summaryrefslogtreecommitdiffstats
path: root/ipc/syscall.c
blob: 52429489cde0070ab9398648ca326592e824a2a7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/*
 * sys_ipc() is the old de-multiplexer for the SysV IPC calls.
 *
 * This is really horribly ugly, and new architectures should just wire up
 * the individual syscalls instead.
 */
#include <linux/unistd.h>

#ifdef __ARCH_WANT_SYS_IPC
#include <linux/errno.h>
#include <linux/ipc.h>
#include <linux/shm.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>

SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
		unsigned long, third, void __user *, ptr, long, fifth)
{
	int version, ret;

	version = call >> 16; /* hack for backward compatibility */
	call &= 0xffff;

	switch (call) {
	case SEMOP:
		return sys_semtimedop(first, (struct sembuf __user *)ptr,
				      second, NULL);
	case SEMTIMEDOP:
		return sys_semtimedop(first, (struct sembuf __user *)ptr,
				      second,
				      (const struct timespec __user *)fifth);

	case SEMGET:
		return sys_semget(first, second, third);
	case SEMCTL: {
		unsigned long arg;
		if (!ptr)
			return -EINVAL;
		if (get_user(arg, (unsigned long __user *) ptr))
			return -EFAULT;
		return sys_semctl(first, second, third, arg);
	}

	case MSGSND:
		return sys_msgsnd(first, (struct msgbuf __user *) ptr,
				  second, third);
	case MSGRCV:
		switch (version) {
		case 0: {
			struct ipc_kludge tmp;
			if (!ptr)
				return -EINVAL;

			if (copy_from_user(&tmp,
					   (struct ipc_kludge __user *) ptr,
					   sizeof(tmp)))
				return -EFAULT;
			return sys_msgrcv(first, tmp.msgp, second,
					   tmp.msgtyp, third);
		}
		default:
			return sys_msgrcv(first,
					   (struct msgbuf __user *) ptr,
					   second, fifth, third);
		}
	case MSGGET:
		return sys_msgget((key_t) first, second);
	case MSGCTL:
		return sys_msgctl(first, second, (struct msqid_ds __user *)ptr);

	case SHMAT:
		switch (version) {
		default: {
			unsigned long raddr;
			ret = do_shmat(first, (char __user *)ptr,
				       second, &raddr, SHMLBA);
			if (ret)
				return ret;
			return put_user(raddr, (unsigned long __user *) third);
		}
		case 1:
			/*
			 * This was the entry point for kernel-originating calls
			 * from iBCS2 in 2.2 days.
			 */
			return -EINVAL;
		}
	case SHMDT:
		return sys_shmdt((char __user *)ptr);
	case SHMGET:
		return sys_shmget(first, second, third);
	case SHMCTL:
		return sys_shmctl(first, second,
				   (struct shmid_ds __user *) ptr);
	default:
		return -ENOSYS;
	}
}
#endif
ss='add' style='width: 0.0%;'/> -rw-r--r--Documentation/DocBook/kgdb.tmpl6
-rw-r--r--Documentation/DocBook/media/dvb/dvbapi.xml2
-rw-r--r--Documentation/DocBook/media/dvb/dvbproperty.xml180
-rw-r--r--Documentation/DocBook/media/dvb/frontend.xml2
-rw-r--r--Documentation/DocBook/media/v4l/common.xml2
-rw-r--r--Documentation/DocBook/media/v4l/compat.xml16
-rw-r--r--Documentation/DocBook/media/v4l/controls.xml23
-rw-r--r--Documentation/DocBook/media/v4l/io.xml59
-rw-r--r--Documentation/DocBook/media/v4l/pixfmt-nv12m.xml2
-rw-r--r--Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml34
-rw-r--r--Documentation/DocBook/media/v4l/pixfmt-uv8.xml62
-rw-r--r--Documentation/DocBook/media/v4l/pixfmt.xml2
-rw-r--r--Documentation/DocBook/media/v4l/subdev-formats.xml926
-rw-r--r--Documentation/DocBook/media/v4l/v4l2.xml12
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-dqevent.xml6
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-expbuf.xml28
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml8
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml57
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-querycap.xml2
-rw-r--r--Documentation/DocBook/media_api.tmpl1
-rw-r--r--Documentation/DocBook/uio-howto.tmpl2
-rw-r--r--Documentation/DocBook/writing-an-alsa-driver.tmpl58
-rw-r--r--Documentation/PCI/MSI-HOWTO.txt37
-rw-r--r--Documentation/acpi/enumeration.txt4
-rw-r--r--Documentation/acpi/scan_handlers.txt77
-rw-r--r--Documentation/arm64/memory.txt2
-rw-r--r--Documentation/atomic_ops.txt2
-rw-r--r--Documentation/backlight/lp855x-driver.txt4
-rw-r--r--Documentation/cgroups/00-INDEX2
-rw-r--r--Documentation/cgroups/memcg_test.txt3
-rw-r--r--Documentation/cpu-freq/cpu-drivers.txt6
-rw-r--r--Documentation/cpu-freq/user-guide.txt8
-rw-r--r--Documentation/devicetree/bindings/arm/altera/socfpga-system.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/arch_timer.txt7
-rw-r--r--Documentation/devicetree/bindings/arm/atmel-aic.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/gic.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/kirkwood.txt27
-rw-r--r--Documentation/devicetree/bindings/arm/omap/omap.txt6
-rw-r--r--Documentation/devicetree/bindings/arm/psci.txt55
-rw-r--r--Documentation/devicetree/bindings/arm/sirf.txt10
-rw-r--r--Documentation/devicetree/bindings/arm/ste-nomadik.txt27
-rw-r--r--Documentation/devicetree/bindings/arm/tegra.txt32
-rw-r--r--Documentation/devicetree/bindings/arm/vt8500.txt8
-rw-r--r--Documentation/devicetree/bindings/bus/ti-gpmc.txt84
-rw-r--r--Documentation/devicetree/bindings/clock/imx31-clock.txt91
-rw-r--r--Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt2
-rw-r--r--Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt205
-rw-r--r--Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt262
-rw-r--r--Documentation/devicetree/bindings/clock/prima2-clock.txt73
-rw-r--r--Documentation/devicetree/bindings/crypto/fsl-sec4.txt12
-rw-r--r--Documentation/devicetree/bindings/drm/exynos/g2d.txt22
-rw-r--r--Documentation/devicetree/bindings/i2c/ina209.txt18
-rw-r--r--Documentation/devicetree/bindings/i2c/max6697.txt64
-rw-r--r--Documentation/devicetree/bindings/input/imx-keypad.txt53
-rw-r--r--Documentation/devicetree/bindings/input/lpc32xx-key.txt9
-rw-r--r--Documentation/devicetree/bindings/input/matrix-keymap.txt8
-rw-r--r--Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt22
-rw-r--r--Documentation/devicetree/bindings/input/omap-keypad.txt13
-rw-r--r--Documentation/devicetree/bindings/input/tca8418_keypad.txt6
-rw-r--r--Documentation/devicetree/bindings/leds/leds-ns2.txt (renamed from Documentation/devicetree/bindings/gpio/leds-ns2.txt)0
-rw-r--r--Documentation/devicetree/bindings/media/gpio-ir-receiver.txt16
-rw-r--r--Documentation/devicetree/bindings/mfd/max8925.txt64
-rwxr-xr-xDocumentation/devicetree/bindings/mfd/tps6507x.txt91
-rw-r--r--Documentation/devicetree/bindings/mips/cavium/dma-engine.txt2
-rw-r--r--Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt8
-rw-r--r--Documentation/devicetree/bindings/mmc/samsung-sdhci.txt2
-rw-r--r--Documentation/devicetree/bindings/mtd/fsmc-nand.txt2
-rw-r--r--Documentation/devicetree/bindings/mtd/gpmc-nand.txt80
-rw-r--r--Documentation/devicetree/bindings/mtd/gpmc-onenand.txt43
-rw-r--r--Documentation/devicetree/bindings/net/cpsw.txt2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt60
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.txt120
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt12
-rw-r--r--Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt140
-rw-r--r--Documentation/devicetree/bindings/power_supply/max8925_batter.txt18
-rw-r--r--Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt13
-rw-r--r--Documentation/devicetree/bindings/power_supply/restart-poweroff.txt8
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/guts.txt13
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/pamu.txt140
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/srio.txt4
-rw-r--r--Documentation/devicetree/bindings/regulator/anatop-regulator.txt8
-rw-r--r--Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt152
-rw-r--r--Documentation/devicetree/bindings/regulator/tps51632-regulator.txt27
-rw-r--r--Documentation/devicetree/bindings/regulator/tps62360-regulator.txt4
-rw-r--r--Documentation/devicetree/bindings/regulator/tps65090.txt122
-rw-r--r--Documentation/devicetree/bindings/rtc/s3c-rtc.txt2
-rw-r--r--Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt24
-rw-r--r--Documentation/devicetree/bindings/sound/ak4642.txt17
-rw-r--r--Documentation/devicetree/bindings/sound/cs4271.txt12
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt51
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/omap-twl4030.txt46
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,fsi.txt26
-rw-r--r--Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt14
-rw-r--r--Documentation/devicetree/bindings/sound/samsung-i2s.txt63
-rw-r--r--Documentation/devicetree/bindings/sound/tlv320aic3x.txt6
-rw-r--r--Documentation/devicetree/bindings/sound/wm8962.txt16
-rw-r--r--Documentation/devicetree/bindings/spi/sh-msiof.txt12
-rw-r--r--Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt6
-rw-r--r--Documentation/devicetree/bindings/tty/serial/arc-uart.txt26
-rw-r--r--Documentation/devicetree/bindings/tty/serial/efm32-uart.txt6
-rw-r--r--Documentation/devicetree/bindings/usb/dwc3.txt22
-rw-r--r--Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt3
-rw-r--r--Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt17
-rw-r--r--Documentation/devicetree/bindings/usb/omap-usb.txt34
-rw-r--r--Documentation/devicetree/bindings/usb/samsung-usbphy.txt55
-rw-r--r--Documentation/devicetree/bindings/usb/usb-phy.txt35
-rw-r--r--Documentation/devicetree/bindings/usb/usb3503.txt20
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt4
-rw-r--r--Documentation/devicetree/bindings/video/backlight/max8925-backlight.txt10
-rw-r--r--Documentation/devicetree/bindings/watchdog/samsung-wdt.txt2
-rw-r--r--Documentation/devicetree/booting-without-of.txt2
-rw-r--r--Documentation/driver-model/devres.txt7
-rwxr-xr-xDocumentation/dvb/get_dvb_firmware17
-rw-r--r--Documentation/dynamic-debug-howto.txt15
-rw-r--r--Documentation/hwmon/coretemp9
-rw-r--r--Documentation/hwmon/ina20993
-rw-r--r--Documentation/hwmon/it8716
-rw-r--r--Documentation/hwmon/jc423
-rw-r--r--Documentation/hwmon/lm7390
-rw-r--r--Documentation/hwmon/max3444016
-rw-r--r--Documentation/hwmon/max669758
-rw-r--r--Documentation/hwmon/sysfs-interface8
-rw-r--r--Documentation/hwmon/zl610026
-rw-r--r--Documentation/intel_txt.txt2
-rw-r--r--Documentation/ioctl/ioctl-number.txt2
-rw-r--r--Documentation/kbuild/makefiles.txt23
-rw-r--r--Documentation/kernel-parameters.txt55
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt2
-rw-r--r--Documentation/lockstat.txt2
-rw-r--r--Documentation/magic-number.txt2
-rw-r--r--Documentation/media-framework.txt2
-rw-r--r--Documentation/memory-barriers.txt1
-rw-r--r--Documentation/namespaces/resource-control.txt14
-rw-r--r--Documentation/networking/00-INDEX6
-rw-r--r--Documentation/networking/DLINK.txt203
-rw-r--r--Documentation/networking/LICENSE.qlcnic2
-rw-r--r--Documentation/networking/cs89x0.txt79
-rw-r--r--Documentation/networking/depca.txt92
-rw-r--r--Documentation/networking/ewrk3.txt46
-rw-r--r--Documentation/networking/filter.txt11
-rw-r--r--Documentation/networking/ip-sysctl.txt19
-rw-r--r--Documentation/networking/multicast.txt63
-rw-r--r--Documentation/networking/netconsole.txt7
-rw-r--r--Documentation/networking/nf_conntrack-sysctl.txt176
-rw-r--r--Documentation/networking/operstates.txt4
-rw-r--r--Documentation/networking/phy.txt11
-rw-r--r--Documentation/nfc/nfc-hci.txt129
-rw-r--r--Documentation/nfc/nfc-pn544.txt84
-rw-r--r--Documentation/pinctrl.txt18
-rw-r--r--Documentation/power/freezing-of-tasks.txt5
-rw-r--r--Documentation/power/runtime_pm.txt4
-rw-r--r--Documentation/powerpc/cpu_features.txt10
-rw-r--r--Documentation/powerpc/transactional_memory.txt175
-rw-r--r--Documentation/printk-formats.txt14
-rw-r--r--Documentation/serial/driver44
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt5
-rw-r--r--Documentation/sound/alsa/HD-Audio-Models.txt2
-rw-r--r--Documentation/sound/alsa/HD-Audio.txt126
-rw-r--r--Documentation/sound/alsa/compress_offload.txt46
-rw-r--r--Documentation/trace/events-power.txt27
-rw-r--r--Documentation/trace/ftrace.txt83
-rw-r--r--Documentation/video4linux/CARDLIST.au08282
-rw-r--r--Documentation/video4linux/CARDLIST.cx238852
-rw-r--r--Documentation/video4linux/CARDLIST.em28xx3
-rw-r--r--Documentation/video4linux/CARDLIST.saa71341
-rw-r--r--Documentation/video4linux/et61x251.txt315
-rwxr-xr-x[-rw-r--r--]Documentation/video4linux/extract_xc3028.pl0
-rw-r--r--Documentation/video4linux/fimc.txt2
-rw-r--r--Documentation/video4linux/ibmcam.txt323
-rw-r--r--Documentation/video4linux/m5602.txt12
-rw-r--r--Documentation/video4linux/ov511.txt288
-rw-r--r--Documentation/video4linux/se401.txt54
-rw-r--r--Documentation/video4linux/si470x.txt7
-rw-r--r--Documentation/video4linux/soc-camera.txt146
-rw-r--r--Documentation/video4linux/stv680.txt53
-rw-r--r--Documentation/video4linux/v4l2-controls.txt22
-rw-r--r--Documentation/video4linux/v4l2-framework.txt3
-rw-r--r--Documentation/video4linux/w9968cf.txt458
-rw-r--r--Documentation/video4linux/zc0301.txt270
-rw-r--r--Documentation/virtual/kvm/api.txt245
-rw-r--r--Documentation/virtual/kvm/mmu.txt7
-rw-r--r--Documentation/vm/ksm.txt15
-rw-r--r--Documentation/w1/slaves/w1_therm13
-rw-r--r--Documentation/x86/boot.txt39
-rw-r--r--Documentation/x86/early-microcode.txt43
-rw-r--r--Documentation/x86/x86_64/boot-options.txt4
-rw-r--r--Documentation/zh_CN/CodingStyle7
-rw-r--r--Documentation/zh_CN/magic-number.txt2
-rw-r--r--MAINTAINERS397
-rw-r--r--Makefile9
-rw-r--r--arch/Kconfig41
-rw-r--r--arch/alpha/Kconfig9
-rw-r--r--arch/alpha/include/asm/signal.h11
-rw-r--r--arch/alpha/include/asm/unistd.h1
-rw-r--r--arch/alpha/include/uapi/asm/socket.h3
-rw-r--r--arch/alpha/kernel/osf_sys.c26
-rw-r--r--arch/alpha/kernel/process.c1
-rw-r--r--arch/alpha/kernel/signal.c121
-rw-r--r--arch/alpha/kernel/srmcons.c18
-rw-r--r--arch/alpha/kernel/traps.c2
-rw-r--r--arch/arm/Kconfig101
-rw-r--r--arch/arm/Kconfig.debug121
-rw-r--r--arch/arm/Makefile6
-rw-r--r--arch/arm/boot/compressed/decompress.c2
-rw-r--r--arch/arm/boot/dts/Makefile15
-rw-r--r--arch/arm/boot/dts/animeo_ip.dts4
-rw-r--r--arch/arm/boot/dts/armada-370-xp.dtsi6
-rw-r--r--arch/arm/boot/dts/at91rm9200.dtsi158
-rw-r--r--arch/arm/boot/dts/at91rm9200ek.dts5
-rw-r--r--arch/arm/boot/dts/at91sam9n12.dtsi11
-rw-r--r--arch/arm/boot/dts/at91sam9n12ek.dts5
-rw-r--r--arch/arm/boot/dts/at91sam9x5.dtsi14
-rw-r--r--arch/arm/boot/dts/at91sam9x5cm.dtsi5
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b.dts16
-rw-r--r--arch/arm/boot/dts/bcm2835.dtsi44
-rw-r--r--arch/arm/boot/dts/da850-evm.dts20
-rw-r--r--arch/arm/boot/dts/da850.dtsi70
-rw-r--r--arch/arm/boot/dts/dbx5x0.dtsi10
-rw-r--r--arch/arm/boot/dts/dove.dtsi2
-rw-r--r--arch/arm/boot/dts/emev2-kzm9d.dts2
-rw-r--r--arch/arm/boot/dts/emev2.dtsi7
-rw-r--r--arch/arm/boot/dts/exynos4210.dtsi6
-rw-r--r--arch/arm/boot/dts/exynos4x12-pinctrl.dtsi2
-rw-r--r--arch/arm/boot/dts/exynos4x12.dtsi8
-rw-r--r--arch/arm/boot/dts/exynos5250-smdk5250.dts26
-rw-r--r--arch/arm/boot/dts/exynos5250.dtsi44
-rw-r--r--arch/arm/boot/dts/exynos5440.dtsi4
-rw-r--r--arch/arm/boot/dts/highbank.dts10
-rw-r--r--arch/arm/boot/dts/imx23.dtsi2
-rw-r--r--arch/arm/boot/dts/imx28-cfa10037.dts77
-rw-r--r--arch/arm/boot/dts/imx28-cfa10049.dts214
-rw-r--r--arch/arm/boot/dts/imx28-m28evk.dts1
-rw-r--r--arch/arm/boot/dts/imx28.dtsi10
-rw-r--r--arch/arm/boot/dts/imx31.dtsi17
-rw-r--r--arch/arm/boot/dts/imx6q.dtsi2
-rw-r--r--arch/arm/boot/dts/marco-evb.dts54
-rw-r--r--arch/arm/boot/dts/marco.dtsi756
-rw-r--r--arch/arm/boot/dts/mmp2-brownstone.dts158
-rw-r--r--arch/arm/boot/dts/mmp2.dtsi4
-rw-r--r--arch/arm/boot/dts/prima2.dtsi31
-rw-r--r--arch/arm/boot/dts/r8a7740-armadillo800eva.dts6
-rw-r--r--arch/arm/boot/dts/sh7372-mackerel.dts6
-rw-r--r--arch/arm/boot/dts/sh73a0-kzm9g.dts6
-rw-r--r--arch/arm/boot/dts/sh73a0-reference.dtsi24
-rw-r--r--arch/arm/boot/dts/sh73a0.dtsi100
-rw-r--r--arch/arm/boot/dts/socfpga.dtsi22
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5.dts34
-rw-r--r--arch/arm/boot/dts/socfpga_vt.dts64
-rw-r--r--arch/arm/boot/dts/ste-nomadik-s8815.dts30
-rw-r--r--arch/arm/boot/dts/ste-nomadik-stn8815.dtsi256
-rw-r--r--arch/arm/boot/dts/sun4i-a10-hackberry.dts30
-rw-r--r--arch/arm/boot/dts/sun4i-a10.dtsi30
-rw-r--r--arch/arm/boot/dts/sun5i-a13-olinuxino.dts2
-rw-r--r--arch/arm/boot/dts/sun5i-a13.dtsi23
-rw-r--r--arch/arm/boot/dts/tegra114-dalmore.dts21
-rw-r--r--arch/arm/boot/dts/tegra114-pluto.dts21
-rw-r--r--arch/arm/boot/dts/tegra114.dtsi153
-rw-r--r--arch/arm/boot/dts/tegra20-colibri-512.dtsi491
-rw-r--r--arch/arm/boot/dts/tegra20-harmony.dts124
-rw-r--r--arch/arm/boot/dts/tegra20-iris-512.dts89
-rw-r--r--arch/arm/boot/dts/tegra20-paz00.dts28
-rw-r--r--arch/arm/boot/dts/tegra20-seaboard.dts162
-rw-r--r--arch/arm/boot/dts/tegra20-tamonten.dtsi1
-rw-r--r--arch/arm/boot/dts/tegra20-trimslice.dts15
-rw-r--r--arch/arm/boot/dts/tegra20-ventana.dts27
-rw-r--r--arch/arm/boot/dts/tegra20-whistler.dts15
-rw-r--r--arch/arm/boot/dts/tegra20.dtsi163
-rw-r--r--arch/arm/boot/dts/tegra30-beaver.dts373
-rw-r--r--arch/arm/boot/dts/tegra30-cardhu.dtsi15
-rw-r--r--arch/arm/boot/dts/tegra30.dtsi152
-rw-r--r--arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts2
-rw-r--r--arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts2
-rw-r--r--arch/arm/boot/dts/vt8500.dtsi40
-rw-r--r--arch/arm/boot/dts/wm8505.dtsi60
-rw-r--r--arch/arm/boot/dts/wm8650.dtsi20
-rw-r--r--arch/arm/boot/dts/wm8850-w70v2.dts47
-rw-r--r--arch/arm/boot/dts/wm8850.dtsi224
-rw-r--r--arch/arm/boot/dts/zynq-7000.dtsi4
-rw-r--r--arch/arm/common/Kconfig23
-rw-r--r--arch/arm/common/Makefile2
-rw-r--r--arch/arm/configs/armadillo800eva_defconfig10
-rw-r--r--arch/arm/configs/at91sam9263_defconfig1
-rw-r--r--arch/arm/configs/bcm2835_defconfig43
-rw-r--r--arch/arm/configs/da8xx_omapl_defconfig4
-rw-r--r--arch/arm/configs/davinci_all_defconfig3
-rw-r--r--arch/arm/configs/imx_v4_v5_defconfig3
-rw-r--r--arch/arm/configs/imx_v6_v7_defconfig10
-rw-r--r--arch/arm/configs/kirkwood_defconfig1
-rw-r--r--arch/arm/configs/kota2_defconfig2
-rw-r--r--arch/arm/configs/kzm9d_defconfig4
-rw-r--r--arch/arm/configs/kzm9g_defconfig4
-rw-r--r--arch/arm/configs/mackerel_defconfig3
-rw-r--r--arch/arm/configs/marzen_defconfig1
-rw-r--r--arch/arm/configs/multi_v7_defconfig2
-rw-r--r--arch/arm/configs/mvebu_defconfig2
-rw-r--r--arch/arm/configs/mxs_defconfig64
-rw-r--r--arch/arm/configs/omap2plus_defconfig31
-rw-r--r--arch/arm/configs/prima2_defconfig3
-rw-r--r--arch/arm/configs/pxa910_defconfig8
-rw-r--r--arch/arm/configs/shark_defconfig1
-rw-r--r--arch/arm/configs/tegra_defconfig6
-rw-r--r--arch/arm/configs/u8500_defconfig6
-rw-r--r--arch/arm/crypto/aes-armv4.S64
-rw-r--r--arch/arm/crypto/sha1-armv4-large.S24
-rw-r--r--arch/arm/include/asm/arch_timer.h109
-rw-r--r--arch/arm/include/asm/assembler.h10
-rw-r--r--arch/arm/include/asm/cputype.h33
-rw-r--r--arch/arm/include/asm/cti.h10
-rw-r--r--arch/arm/include/asm/dma.h2
-rw-r--r--arch/arm/include/asm/hardware/coresight.h6
-rw-r--r--arch/arm/include/asm/hw_breakpoint.h3
-rw-r--r--arch/arm/include/asm/idmap.h1
-rw-r--r--arch/arm/include/asm/kvm_arch_timer.h85
-rw-r--r--arch/arm/include/asm/kvm_arm.h214
-rw-r--r--arch/arm/include/asm/kvm_asm.h83
-rw-r--r--arch/arm/include/asm/kvm_coproc.h47
-rw-r--r--arch/arm/include/asm/kvm_emulate.h72
-rw-r--r--arch/arm/include/asm/kvm_host.h184
-rw-r--r--arch/arm/include/asm/kvm_mmio.h56
-rw-r--r--arch/arm/include/asm/kvm_mmu.h50
-rw-r--r--arch/arm/include/asm/kvm_psci.h (renamed from include/clocksource/arm_generic.h)12
-rw-r--r--arch/arm/include/asm/kvm_vgic.h221
-rw-r--r--arch/arm/include/asm/mach/arch.h3
-rw-r--r--arch/arm/include/asm/mach/irq.h1
-rw-r--r--arch/arm/include/asm/mach/pci.h1
-rw-r--r--arch/arm/include/asm/mach/time.h30
-rw-r--r--arch/arm/include/asm/memory.h12
-rw-r--r--arch/arm/include/asm/opcodes-sec.h24
-rw-r--r--arch/arm/include/asm/opcodes.h1
-rw-r--r--arch/arm/include/asm/outercache.h1
-rw-r--r--arch/arm/include/asm/pgtable-3level-hwdef.h5
-rw-r--r--arch/arm/include/asm/pgtable-3level.h18
-rw-r--r--arch/arm/include/asm/pgtable.h7
-rw-r--r--arch/arm/include/asm/psci.h36
-rw-r--r--arch/arm/include/asm/signal.h18
-rw-r--r--arch/arm/include/asm/smp_scu.h25
-rw-r--r--arch/arm/include/asm/spinlock.h16
-rw-r--r--arch/arm/include/asm/unistd.h2
-rw-r--r--arch/arm/include/asm/virt.h4
-rw-r--r--arch/arm/include/asm/xen/events.h22
-rw-r--r--arch/arm/include/asm/xen/page.h4
-rw-r--r--arch/arm/include/debug/imx-uart.h88
-rw-r--r--arch/arm/include/debug/imx.S29
-rw-r--r--arch/arm/include/debug/omap2plus.S (renamed from arch/arm/mach-omap2/include/mach/debug-macro.S)137
-rw-r--r--arch/arm/include/debug/vt8500.S (renamed from arch/arm/mach-vt8500/include/mach/debug-macro.S)24
-rw-r--r--arch/arm/include/uapi/asm/kvm.h180
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/arch_timer.c505
-rw-r--r--arch/arm/kernel/asm-offsets.c43
-rw-r--r--arch/arm/kernel/bios32.c9
-rw-r--r--arch/arm/kernel/calls.S2
-rw-r--r--arch/arm/kernel/entry-common.S5
-rw-r--r--arch/arm/kernel/hw_breakpoint.c61
-rw-r--r--arch/arm/kernel/irq.c10
-rw-r--r--arch/arm/kernel/perf_event.c16
-rw-r--r--arch/arm/kernel/perf_event_cpu.c51
-rw-r--r--arch/arm/kernel/perf_event_v6.c4
-rw-r--r--arch/arm/kernel/perf_event_v7.c18
-rw-r--r--arch/arm/kernel/perf_event_xscale.c2
-rw-r--r--arch/arm/kernel/process.c13
-rw-r--r--arch/arm/kernel/psci.c211
-rw-r--r--arch/arm/kernel/sched_clock.c4
-rw-r--r--arch/arm/kernel/signal.c160
-rw-r--r--arch/arm/kernel/smp.c47
-rw-r--r--arch/arm/kernel/smp_scu.c2
-rw-r--r--arch/arm/kernel/smp_twd.c54
-rw-r--r--arch/arm/kernel/time.c53
-rw-r--r--arch/arm/kernel/traps.c2
-rw-r--r--arch/arm/kernel/vmlinux.lds.S6
-rw-r--r--arch/arm/kvm/Kconfig72
-rw-r--r--arch/arm/kvm/Makefile23
-rw-r--r--arch/arm/kvm/arch_timer.c271
-rw-r--r--arch/arm/kvm/arm.c1169
-rw-r--r--arch/arm/kvm/coproc.c1050
-rw-r--r--arch/arm/kvm/coproc.h153
-rw-r--r--arch/arm/kvm/coproc_a15.c162
-rw-r--r--arch/arm/kvm/emulate.c373
-rw-r--r--arch/arm/kvm/guest.c222
-rw-r--r--arch/arm/kvm/init.S114
-rw-r--r--arch/arm/kvm/interrupts.S484
-rw-r--r--arch/arm/kvm/interrupts_head.S605
-rw-r--r--arch/arm/kvm/mmio.c156
-rw-r--r--arch/arm/kvm/mmu.c782
-rw-r--r--arch/arm/kvm/psci.c108
-rw-r--r--arch/arm/kvm/reset.c74
-rw-r--r--arch/arm/kvm/trace.h235
-rw-r--r--arch/arm/kvm/vgic.c1506
-rw-r--r--arch/arm/mach-at91/Kconfig6
-rw-r--r--arch/arm/mach-at91/Makefile1
-rw-r--r--arch/arm/mach-at91/at91rm9200.c2
-rw-r--r--arch/arm/mach-at91/at91rm9200_time.c12
-rw-r--r--arch/arm/mach-at91/at91sam926x_time.c53
-rw-r--r--arch/arm/mach-at91/at91x40_time.c13
-rw-r--r--arch/arm/mach-at91/board-1arm.c2
-rw-r--r--arch/arm/mach-at91/board-afeb-9260v1.c2
-rw-r--r--arch/arm/mach-at91/board-cam60.c2
-rw-r--r--arch/arm/mach-at91/board-carmeva.c2
-rw-r--r--arch/arm/mach-at91/board-cpu9krea.c2
-rw-r--r--arch/arm/mach-at91/board-cpuat91.c2
-rw-r--r--arch/arm/mach-at91/board-csb337.c2
-rw-r--r--arch/arm/mach-at91/board-csb637.c2
-rw-r--r--arch/arm/mach-at91/board-dt.c2
-rw-r--r--arch/arm/mach-at91/board-eb01.c2
-rw-r--r--arch/arm/mach-at91/board-eb9200.c2
-rw-r--r--arch/arm/mach-at91/board-ecbat91.c2
-rw-r--r--arch/arm/mach-at91/board-eco920.c2
-rw-r--r--arch/arm/mach-at91/board-flexibity.c2
-rw-r--r--arch/arm/mach-at91/board-foxg20.c2
-rw-r--r--arch/arm/mach-at91/board-gsia18s.c2
-rw-r--r--arch/arm/mach-at91/board-kafa.c2
-rw-r--r--arch/arm/mach-at91/board-kb9202.c2
-rw-r--r--arch/arm/mach-at91/board-neocore926.c387
-rw-r--r--arch/arm/mach-at91/board-pcontrol-g20.c2
-rw-r--r--arch/arm/mach-at91/board-picotux200.c2
-rw-r--r--arch/arm/mach-at91/board-qil-a9260.c2
-rw-r--r--arch/arm/mach-at91/board-rm9200-dt.c2
-rw-r--r--arch/arm/mach-at91/board-rm9200dk.c2
-rw-r--r--arch/arm/mach-at91/board-rm9200ek.c2
-rw-r--r--arch/arm/mach-at91/board-rsi-ews.c2
-rw-r--r--arch/arm/mach-at91/board-sam9-l9260.c2
-rw-r--r--arch/arm/mach-at91/board-sam9260ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9261ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9263ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9g20ek.c4
-rw-r--r--arch/arm/mach-at91/board-sam9m10g45ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9rlek.c2
-rw-r--r--arch/arm/mach-at91/board-snapper9260.c2
-rw-r--r--arch/arm/mach-at91/board-stamp9g20.c4
-rw-r--r--arch/arm/mach-at91/board-usb-a926x.c6
-rw-r--r--arch/arm/mach-at91/board-yl-9200.c2
-rw-r--r--arch/arm/mach-at91/generic.h7
-rw-r--r--arch/arm/mach-at91/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-bcm/Kconfig1
-rw-r--r--arch/arm/mach-bcm/board_bcm.c22
-rw-r--r--arch/arm/mach-bcm2835/bcm2835.c32
-rw-r--r--arch/arm/mach-bcm2835/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-clps711x/board-autcpu12.c2
-rw-r--r--arch/arm/mach-clps711x/board-cdb89712.c2
-rw-r--r--arch/arm/mach-clps711x/board-clep7312.c2
-rw-r--r--arch/arm/mach-clps711x/board-edb7211.c2
-rw-r--r--arch/arm/mach-clps711x/board-fortunet.c2
-rw-r--r--arch/arm/mach-clps711x/board-p720t.c2
-rw-r--r--arch/arm/mach-clps711x/common.c6
-rw-r--r--arch/arm/mach-clps711x/common.h4
-rw-r--r--arch/arm/mach-clps711x/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-cns3xxx/cns3420vb.c4
-rw-r--r--arch/arm/mach-cns3xxx/core.c21
-rw-r--r--arch/arm/mach-cns3xxx/core.h2
-rw-r--r--arch/arm/mach-cns3xxx/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-davinci/Kconfig1
-rw-r--r--arch/arm/mach-davinci/board-da830-evm.c11
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c126
-rw-r--r--arch/arm/mach-davinci/board-dm355-evm.c2
-rw-r--r--arch/arm/mach-davinci/board-dm355-leopard.c2
-rw-r--r--arch/arm/mach-davinci/board-dm365-evm.c2
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c10
-rw-r--r--arch/arm/mach-davinci/board-dm646x-evm.c4
-rw-r--r--arch/arm/mach-davinci/board-mityomapl138.c11
-rw-r--r--arch/arm/mach-davinci/board-neuros-osd2.c2
-rw-r--r--arch/arm/mach-davinci/board-omapl138-hawk.c32
-rw-r--r--arch/arm/mach-davinci/board-sffsdr.c2
-rw-r--r--arch/arm/mach-davinci/board-tnetv107x-evm.c2
-rw-r--r--arch/arm/mach-davinci/clock.c39
-rw-r--r--arch/arm/mach-davinci/clock.h3
-rw-r--r--arch/arm/mach-davinci/cpuidle.c84
-rw-r--r--arch/arm/mach-davinci/da850.c17
-rw-r--r--arch/arm/mach-davinci/da8xx-dt.c11
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c28
-rw-r--r--arch/arm/mach-davinci/dm644x.c10
-rw-r--r--arch/arm/mach-davinci/include/mach/clock.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/common.h4
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h5
-rw-r--r--arch/arm/mach-davinci/include/mach/psc.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-davinci/psc.c29
-rw-r--r--arch/arm/mach-davinci/time.c7
-rw-r--r--arch/arm/mach-dove/cm-a510.c2
-rw-r--r--arch/arm/mach-dove/common.c37
-rw-r--r--arch/arm/mach-dove/common.h2
-rw-r--r--arch/arm/mach-dove/dove-db-setup.c2
-rw-r--r--arch/arm/mach-dove/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-ebsa110/core.c15
-rw-r--r--arch/arm/mach-ebsa110/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-ep93xx/adssphere.c4
-rw-r--r--arch/arm/mach-ep93xx/core.c38
-rw-r--r--arch/arm/mach-ep93xx/edb93xx.c25
-rw-r--r--arch/arm/mach-ep93xx/gesbc9312.c4
-rw-r--r--arch/arm/mach-ep93xx/include/mach/platform.h2
-rw-r--r--arch/arm/mach-ep93xx/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-ep93xx/micro9.c13
-rw-r--r--arch/arm/mach-ep93xx/simone.c4
-rw-r--r--arch/arm/mach-ep93xx/snappercl15.c4
-rw-r--r--arch/arm/mach-ep93xx/ts72xx.c4
-rw-r--r--arch/arm/mach-ep93xx/vision_ep9307.c4
-rw-r--r--arch/arm/mach-exynos/Kconfig2
-rw-r--r--arch/arm/mach-exynos/common.c233
-rw-r--r--arch/arm/mach-exynos/common.h25
-rw-r--r--arch/arm/mach-exynos/cpuidle.c3
-rw-r--r--arch/arm/mach-exynos/dev-audio.c3
-rw-r--r--arch/arm/mach-exynos/include/mach/pmu.h34
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-audss.h18
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-irq.h2
-rw-r--r--arch/arm/mach-exynos/mach-armlex4210.c4
-rw-r--r--arch/arm/mach-exynos/mach-exynos4-dt.c4
-rw-r--r--arch/arm/mach-exynos/mach-exynos5-dt.c10
-rw-r--r--arch/arm/mach-exynos/mach-nuri.c12
-rw-r--r--arch/arm/mach-exynos/mach-origen.c4
-rw-r--r--arch/arm/mach-exynos/mach-smdk4x12.c7
-rw-r--r--arch/arm/mach-exynos/mach-smdkv310.c7
-rw-r--r--arch/arm/mach-exynos/mach-universal_c210.c12
-rw-r--r--arch/arm/mach-exynos/mct.c25
-rw-r--r--arch/arm/mach-exynos/platsmp.c6
-rw-r--r--arch/arm/mach-exynos/pm.c9
-rw-r--r--arch/arm/mach-exynos/pmu.c3
-rw-r--r--arch/arm/mach-footbridge/cats-hw.c2
-rw-r--r--arch/arm/mach-footbridge/common.h4
-rw-r--r--arch/arm/mach-footbridge/dc21285-timer.c12
-rw-r--r--arch/arm/mach-footbridge/ebsa285.c2
-rw-r--r--arch/arm/mach-footbridge/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-footbridge/isa-timer.c6
-rw-r--r--arch/arm/mach-footbridge/netwinder-hw.c2
-rw-r--r--arch/arm/mach-footbridge/personal.c2
-rw-r--r--arch/arm/mach-gemini/board-nas4220b.c6
-rw-r--r--arch/arm/mach-gemini/board-rut1xx.c6
-rw-r--r--arch/arm/mach-gemini/board-wbd111.c6
-rw-r--r--arch/arm/mach-gemini/board-wbd222.c6
-rw-r--r--arch/arm/mach-gemini/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-h720x/common.c6
-rw-r--r--arch/arm/mach-h720x/common.h6
-rw-r--r--arch/arm/mach-h720x/cpu-h7201.c9
-rw-r--r--arch/arm/mach-h720x/cpu-h7202.c9
-rw-r--r--arch/arm/mach-h720x/h7201-eval.c2
-rw-r--r--arch/arm/mach-h720x/h7202-eval.c2
-rw-r--r--arch/arm/mach-h720x/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-highbank/Kconfig4
-rw-r--r--arch/arm/mach-highbank/core.h1
-rw-r--r--arch/arm/mach-highbank/highbank.c23
-rw-r--r--arch/arm/mach-highbank/platsmp.c6
-rw-r--r--arch/arm/mach-highbank/sysregs.h4
-rw-r--r--arch/arm/mach-imx/Kconfig38
-rw-r--r--arch/arm/mach-imx/Makefile9
-rw-r--r--arch/arm/mach-imx/Makefile.boot4
-rw-r--r--arch/arm/mach-imx/clk-imx25.c3
-rw-r--r--arch/arm/mach-imx/clk-imx27.c16
-rw-r--r--arch/arm/mach-imx/clk-imx31.c15
-rw-r--r--arch/arm/mach-imx/clk-imx35.c4
-rw-r--r--arch/arm/mach-imx/clk-imx6q.c12
-rw-r--r--arch/arm/mach-imx/common.h15
-rw-r--r--arch/arm/mach-imx/cpu-imx5.c39
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6q.c95
-rw-r--r--arch/arm/mach-imx/cpuidle.h5
-rw-r--r--arch/arm/mach-imx/devices-imx50.h33
-rw-r--r--arch/arm/mach-imx/devices/Kconfig2
-rw-r--r--arch/arm/mach-imx/devices/platform-fec.c6
-rw-r--r--arch/arm/mach-imx/devices/platform-imx-i2c.c10
-rw-r--r--arch/arm/mach-imx/devices/platform-imx-uart.c12
-rw-r--r--arch/arm/mach-imx/epit.c15
-rw-r--r--arch/arm/mach-imx/gpc.c7
-rw-r--r--arch/arm/mach-imx/hardware.h6
-rw-r--r--arch/arm/mach-imx/headsmp.S47
-rw-r--r--arch/arm/mach-imx/imx25-dt.c11
-rw-r--r--arch/arm/mach-imx/imx27-dt.c16
-rw-r--r--arch/arm/mach-imx/imx31-dt.c33
-rw-r--r--arch/arm/mach-imx/imx51-dt.c16
-rw-r--r--arch/arm/mach-imx/iomux-mx50.h977
-rw-r--r--arch/arm/mach-imx/lluart.c47
-rw-r--r--arch/arm/mach-imx/mach-apf9328.c6
-rw-r--r--arch/arm/mach-imx/mach-armadillo5x0.c6
-rw-r--r--arch/arm/mach-imx/mach-bug.c6
-rw-r--r--arch/arm/mach-imx/mach-cpuimx27.c6
-rw-r--r--arch/arm/mach-imx/mach-cpuimx35.c6
-rw-r--r--arch/arm/mach-imx/mach-cpuimx51sd.c6
-rw-r--r--arch/arm/mach-imx/mach-eukrea_cpuimx25.c6
-rw-r--r--arch/arm/mach-imx/mach-imx27_visstrim_m10.c6
-rw-r--r--arch/arm/mach-imx/mach-imx27ipcam.c6
-rw-r--r--arch/arm/mach-imx/mach-imx27lite.c6
-rw-r--r--arch/arm/mach-imx/mach-imx53.c16
-rw-r--r--arch/arm/mach-imx/mach-imx6q.c37
-rw-r--r--arch/arm/mach-imx/mach-kzm_arm11_01.c6
-rw-r--r--arch/arm/mach-imx/mach-mx1ads.c8
-rw-r--r--arch/arm/mach-imx/mach-mx21ads.c6
-rw-r--r--arch/arm/mach-imx/mach-mx25_3ds.c6
-rw-r--r--arch/arm/mach-imx/mach-mx27_3ds.c6
-rw-r--r--arch/arm/mach-imx/mach-mx27ads.c6
-rw-r--r--arch/arm/mach-imx/mach-mx31_3ds.c6
-rw-r--r--arch/arm/mach-imx/mach-mx31ads.c6
-rw-r--r--arch/arm/mach-imx/mach-mx31lilly.c6
-rw-r--r--arch/arm/mach-imx/mach-mx31lite.c6
-rw-r--r--arch/arm/mach-imx/mach-mx31moboard.c6
-rw-r--r--arch/arm/mach-imx/mach-mx35_3ds.c6
-rw-r--r--arch/arm/mach-imx/mach-mx50_rdp.c225
-rw-r--r--arch/arm/mach-imx/mach-mx51_3ds.c178
-rw-r--r--arch/arm/mach-imx/mach-mx51_babbage.c6
-rw-r--r--arch/arm/mach-imx/mach-mxt_td60.c6
-rw-r--r--arch/arm/mach-imx/mach-pca100.c6
-rw-r--r--arch/arm/mach-imx/mach-pcm037.c6
-rw-r--r--arch/arm/mach-imx/mach-pcm038.c6
-rw-r--r--arch/arm/mach-imx/mach-pcm043.c6
-rw-r--r--arch/arm/mach-imx/mach-qong.c6
-rw-r--r--arch/arm/mach-imx/mach-scb9328.c6
-rw-r--r--arch/arm/mach-imx/mach-vpr200.c6
-rw-r--r--arch/arm/mach-imx/mm-imx5.c48
-rw-r--r--arch/arm/mach-imx/mx50.h290
-rw-r--r--arch/arm/mach-imx/mxc.h13
-rw-r--r--arch/arm/mach-imx/platsmp.c14
-rw-r--r--arch/arm/mach-imx/pm-imx5.c7
-rw-r--r--arch/arm/mach-imx/time.c18
-rw-r--r--arch/arm/mach-integrator/common.h5
-rw-r--r--arch/arm/mach-integrator/core.c2
-rw-r--r--arch/arm/mach-integrator/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c20
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c18
-rw-r--r--arch/arm/mach-iop13xx/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-iop13xx/iq81340mc.c6
-rw-r--r--arch/arm/mach-iop13xx/iq81340sc.c6
-rw-r--r--arch/arm/mach-iop32x/em7210.c6
-rw-r--r--arch/arm/mach-iop32x/glantank.c6
-rw-r--r--arch/arm/mach-iop32x/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-iop32x/iq31244.c8
-rw-r--r--arch/arm/mach-iop32x/iq80321.c6
-rw-r--r--arch/arm/mach-iop32x/n2100.c6
-rw-r--r--arch/arm/mach-iop33x/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-iop33x/iq80331.c6
-rw-r--r--arch/arm/mach-iop33x/iq80332.c6
-rw-r--r--arch/arm/mach-ixp4xx/avila-setup.c4
-rw-r--r--arch/arm/mach-ixp4xx/common.c15
-rw-r--r--arch/arm/mach-ixp4xx/coyote-setup.c4
-rw-r--r--arch/arm/mach-ixp4xx/dsmg600-setup.c6
-rw-r--r--arch/arm/mach-ixp4xx/fsg-setup.c2
-rw-r--r--arch/arm/mach-ixp4xx/gateway7001-setup.c2
-rw-r--r--arch/arm/mach-ixp4xx/goramo_mlr.c2
-rw-r--r--arch/arm/mach-ixp4xx/gtwx5715-setup.c2
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/platform.h3
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-ixp4xx/ixdp425-setup.c8
-rw-r--r--arch/arm/mach-ixp4xx/nas100d-setup.c2
-rw-r--r--arch/arm/mach-ixp4xx/nslu2-setup.c6
-rw-r--r--arch/arm/mach-ixp4xx/omixp-setup.c6
-rw-r--r--arch/arm/mach-ixp4xx/vulcan-setup.c2
-rw-r--r--arch/arm/mach-ixp4xx/wg302v2-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/Makefile1
-rw-r--r--arch/arm/mach-kirkwood/board-dt.c4
-rw-r--r--arch/arm/mach-kirkwood/board-ib62x0.c1
-rw-r--r--arch/arm/mach-kirkwood/board-mplcec4.c1
-rw-r--r--arch/arm/mach-kirkwood/board-nsa310.c10
-rw-r--r--arch/arm/mach-kirkwood/common.c29
-rw-r--r--arch/arm/mach-kirkwood/common.h3
-rw-r--r--arch/arm/mach-kirkwood/d2net_v2-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/db88f6281-bp-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/dockstar-setup.c3
-rw-r--r--arch/arm/mach-kirkwood/guruplug-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/include/mach/kirkwood.h3
-rw-r--r--arch/arm/mach-kirkwood/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/netspace_v2-setup.c6
-rw-r--r--arch/arm/mach-kirkwood/netxbig_v2-setup.c4
-rw-r--r--arch/arm/mach-kirkwood/openrd-setup.c6
-rw-r--r--arch/arm/mach-kirkwood/pcie.c10
-rw-r--r--arch/arm/mach-kirkwood/rd88f6192-nas-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/rd88f6281-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/sheevaplug-setup.c4
-rw-r--r--arch/arm/mach-kirkwood/t5325-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/ts219-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/ts41x-setup.c2
-rw-r--r--arch/arm/mach-ks8695/board-acs5k.c2
-rw-r--r--arch/arm/mach-ks8695/board-dsm320.c2
-rw-r--r--arch/arm/mach-ks8695/board-micrel.c2
-rw-r--r--arch/arm/mach-ks8695/board-og.c10
-rw-r--r--arch/arm/mach-ks8695/board-sg.c6
-rw-r--r--arch/arm/mach-ks8695/generic.h2
-rw-r--r--arch/arm/mach-ks8695/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-ks8695/time.c6
-rw-r--r--arch/arm/mach-lpc32xx/common.h2
-rw-r--r--arch/arm/mach-lpc32xx/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-lpc32xx/phy3250.c2
-rw-r--r--arch/arm/mach-lpc32xx/timer.c16
-rw-r--r--arch/arm/mach-mmp/aspenite.c4
-rw-r--r--arch/arm/mach-mmp/avengers_lite.c2
-rw-r--r--arch/arm/mach-mmp/brownstone.c2
-rw-r--r--arch/arm/mach-mmp/common.h2
-rw-r--r--arch/arm/mach-mmp/flint.c2
-rw-r--r--arch/arm/mach-mmp/gplugd.c2
-rw-r--r--arch/arm/mach-mmp/include/mach/mmp2.h4
-rw-r--r--arch/arm/mach-mmp/include/mach/pxa168.h4
-rw-r--r--arch/arm/mach-mmp/include/mach/pxa910.h9
-rw-r--r--arch/arm/mach-mmp/include/mach/uncompress.h6
-rw-r--r--arch/arm/mach-mmp/jasper.c2
-rw-r--r--arch/arm/mach-mmp/mmp-dt.c8
-rw-r--r--arch/arm/mach-mmp/mmp2-dt.c6
-rw-r--r--arch/arm/mach-mmp/mmp2.c6
-rw-r--r--arch/arm/mach-mmp/pxa168.c6
-rw-r--r--arch/arm/mach-mmp/pxa910.c9
-rw-r--r--arch/arm/mach-mmp/tavorevb.c2
-rw-r--r--arch/arm/mach-mmp/teton_bga.c2
-rw-r--r--arch/arm/mach-mmp/time.c7
-rw-r--r--arch/arm/mach-mmp/ttc_dkb.c94
-rw-r--r--arch/arm/mach-msm/board-dt-8660.c18
-rw-r--r--arch/arm/mach-msm/board-dt-8960.c18
-rw-r--r--arch/arm/mach-msm/board-halibut.c2
-rw-r--r--arch/arm/mach-msm/board-mahimahi.c4
-rw-r--r--arch/arm/mach-msm/board-msm7x30.c6
-rw-r--r--arch/arm/mach-msm/board-qsd8x50.c4
-rw-r--r--arch/arm/mach-msm/board-sapphire.c4
-rw-r--r--arch/arm/mach-msm/board-trout.c2
-rw-r--r--arch/arm/mach-msm/common.h8
-rw-r--r--arch/arm/mach-msm/include/mach/uncompress.h4
-rw-r--r--arch/arm/mach-msm/platsmp.c6
-rw-r--r--arch/arm/mach-msm/proc_comm.h2
-rw-r--r--arch/arm/mach-msm/timer.c31
-rw-r--r--arch/arm/mach-mv78xx0/buffalo-wxl-setup.c2
-rw-r--r--arch/arm/mach-mv78xx0/common.c6
-rw-r--r--arch/arm/mach-mv78xx0/common.h2
-rw-r--r--arch/arm/mach-mv78xx0/db78x00-bp-setup.c2
-rw-r--r--arch/arm/mach-mv78xx0/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-mv78xx0/rd78x00-masa-setup.c2
-rw-r--r--arch/arm/mach-mvebu/Makefile5
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.c6
-rw-r--r--arch/arm/mach-mxs/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-mxs/mach-mxs.c42
-rw-r--r--arch/arm/mach-mxs/timer.c34
-rw-r--r--arch/arm/mach-netx/generic.c2
-rw-r--r--arch/arm/mach-netx/generic.h3
-rw-r--r--arch/arm/mach-netx/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-netx/nxdb500.c4
-rw-r--r--arch/arm/mach-netx/nxdkn.c4
-rw-r--r--arch/arm/mach-netx/nxeb500hmi.c4
-rw-r--r--arch/arm/mach-netx/time.c16
-rw-r--r--arch/arm/mach-nomadik/Kconfig10
-rw-r--r--arch/arm/mach-nomadik/Makefile6
-rw-r--r--arch/arm/mach-nomadik/board-nhk8815.c359
-rw-r--r--arch/arm/mach-nomadik/cpu-8815.c358
-rw-r--r--arch/arm/mach-nomadik/cpu-8815.h4
-rw-r--r--arch/arm/mach-nomadik/i2c-8815nhk.c88
-rw-r--r--arch/arm/mach-nomadik/include/mach/hardware.h90
-rw-r--r--arch/arm/mach-nomadik/include/mach/irqs.h2
-rw-r--r--arch/arm/mach-nomadik/include/mach/uncompress.h3
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c2
-rw-r--r--arch/arm/mach-omap1/board-fsample.c2
-rw-r--r--arch/arm/mach-omap1/board-generic.c2
-rw-r--r--arch/arm/mach-omap1/board-h2.c2
-rw-r--r--arch/arm/mach-omap1/board-h3.c2
-rw-r--r--arch/arm/mach-omap1/board-htcherald.c2
-rw-r--r--arch/arm/mach-omap1/board-innovator.c2
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c45
-rw-r--r--arch/arm/mach-omap1/board-osk.c2
-rw-r--r--arch/arm/mach-omap1/board-palmte.c2
-rw-r--r--arch/arm/mach-omap1/board-palmtt.c2
-rw-r--r--arch/arm/mach-omap1/board-palmz71.c2
-rw-r--r--arch/arm/mach-omap1/board-perseus2.c2
-rw-r--r--arch/arm/mach-omap1/board-sx1.c2
-rw-r--r--arch/arm/mach-omap1/board-voiceblue.c2
-rw-r--r--arch/arm/mach-omap1/common.h2
-rw-r--r--arch/arm/mach-omap1/dma.c18
-rw-r--r--arch/arm/mach-omap1/i2c.c6
-rw-r--r--arch/arm/mach-omap1/include/mach/uncompress.h5
-rw-r--r--arch/arm/mach-omap1/time.c17
-rw-r--r--arch/arm/mach-omap1/timer32k.c12
-rw-r--r--arch/arm/mach-omap2/Kconfig33
-rw-r--r--arch/arm/mach-omap2/Makefile4
-rw-r--r--arch/arm/mach-omap2/am35xx-emac.c2
-rw-r--r--arch/arm/mach-omap2/board-2430sdp.c4
-rw-r--r--arch/arm/mach-omap2/board-3430sdp.c26
-rw-r--r--arch/arm/mach-omap2/board-3630sdp.c4
-rw-r--r--arch/arm/mach-omap2/board-4430sdp.c37
-rw-r--r--arch/arm/mach-omap2/board-am3517crane.c63
-rw-r--r--arch/arm/mach-omap2/board-am3517evm.c4
-rw-r--r--arch/arm/mach-omap2/board-apollon.c342
-rw-r--r--arch/arm/mach-omap2/board-cm-t35.c10
-rw-r--r--arch/arm/mach-omap2/board-cm-t3517.c31
-rw-r--r--arch/arm/mach-omap2/board-devkit8000.c8
-rw-r--r--arch/arm/mach-omap2/board-generic.c17
-rw-r--r--arch/arm/mach-omap2/board-h4.c2
-rw-r--r--arch/arm/mach-omap2/board-igep0020.c28
-rw-r--r--arch/arm/mach-omap2/board-ldp.c4
-rw-r--r--arch/arm/mach-omap2/board-n8x0.c6
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c49
-rw-r--r--arch/arm/mach-omap2/board-omap3evm.c18
-rw-r--r--arch/arm/mach-omap2/board-omap3logic.c6
-rw-r--r--arch/arm/mach-omap2/board-omap3pandora.c6
-rw-r--r--arch/arm/mach-omap2/board-omap3stalker.c6
-rw-r--r--arch/arm/mach-omap2/board-omap3touchbook.c6
-rw-r--r--arch/arm/mach-omap2/board-omap4panda.c9
-rw-r--r--arch/arm/mach-omap2/board-overo.c8
-rw-r--r--arch/arm/mach-omap2/board-rm680.c6
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c22
-rw-r--r--arch/arm/mach-omap2/board-rx51-video.c3
-rw-r--r--arch/arm/mach-omap2/board-rx51.c2
-rw-r--r--arch/arm/mach-omap2/board-ti8168evm.c4
-rw-r--r--arch/arm/mach-omap2/board-zoom-display.c14
-rw-r--r--arch/arm/mach-omap2/board-zoom-peripherals.c41
-rw-r--r--arch/arm/mach-omap2/board-zoom.c6
-rw-r--r--arch/arm/mach-omap2/cclock2420_data.c16
-rw-r--r--arch/arm/mach-omap2/cclock2430_data.c16
-rw-r--r--arch/arm/mach-omap2/cclock44xx_data.c578
-rw-r--r--arch/arm/mach-omap2/clock2xxx.c2
-rw-r--r--arch/arm/mach-omap2/clock3xxx.c2
-rw-r--r--arch/arm/mach-omap2/clockdomain.c569
-rw-r--r--arch/arm/mach-omap2/clockdomain.h17
-rw-r--r--arch/arm/mach-omap2/cm2xxx.c33
-rw-r--r--arch/arm/mach-omap2/cm3xxx.c14
-rw-r--r--arch/arm/mach-omap2/cminst44xx.c2
-rw-r--r--arch/arm/mach-omap2/common.h14
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c79
-rw-r--r--arch/arm/mach-omap2/devices.c76
-rw-r--r--arch/arm/mach-omap2/display.c2
-rw-r--r--arch/arm/mach-omap2/dma.c25
-rw-r--r--arch/arm/mach-omap2/drm.c5
-rw-r--r--arch/arm/mach-omap2/emu.c2
-rw-r--r--arch/arm/mach-omap2/fb.c4
-rw-r--r--arch/arm/mach-omap2/gpio.c8
-rw-r--r--arch/arm/mach-omap2/gpmc-nand.c15
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.c2
-rw-r--r--arch/arm/mach-omap2/gpmc.c249
-rw-r--r--arch/arm/mach-omap2/hdq1w.c5
-rw-r--r--arch/arm/mach-omap2/hsmmc.c2
-rw-r--r--arch/arm/mach-omap2/hwspinlock.c6
-rw-r--r--arch/arm/mach-omap2/i2c.c8
-rw-r--r--arch/arm/mach-omap2/include/mach/serial.h37
-rw-r--r--arch/arm/mach-omap2/include/mach/uncompress.h176
-rw-r--r--arch/arm/mach-omap2/mcbsp.c5
-rw-r--r--arch/arm/mach-omap2/msdi.c2
-rw-r--r--arch/arm/mach-omap2/omap-iommu.c6
-rw-r--r--arch/arm/mach-omap2/omap-mpuss-lowpower.c44
-rw-r--r--arch/arm/mach-omap2/omap-smp.c8
-rw-r--r--arch/arm/mach-omap2/omap-wakeupgen.c17
-rw-r--r--arch/arm/mach-omap2/omap2-restart.c3
-rw-r--r--arch/arm/mach-omap2/omap4-common.c15
-rw-r--r--arch/arm/mach-omap2/omap44xx.h1
-rw-r--r--arch/arm/mach-omap2/omap_device.c542
-rw-r--r--arch/arm/mach-omap2/omap_device.h79
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c10
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.h9
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2420_data.c7
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c112
-rw-r--r--arch/arm/mach-omap2/omap_phy_internal.c2
-rw-r--r--arch/arm/mach-omap2/opp3xxx_data.c2
-rw-r--r--arch/arm/mach-omap2/opp4xxx_data.c2
-rw-r--r--arch/arm/mach-omap2/pm-debug.c8
-rw-r--r--arch/arm/mach-omap2/pm.c71
-rw-r--r--arch/arm/mach-omap2/pm.h1
-rw-r--r--arch/arm/mach-omap2/pm24xx.c43
-rw-r--r--arch/arm/mach-omap2/pm34xx.c2
-rw-r--r--arch/arm/mach-omap2/pmu.c5
-rw-r--r--arch/arm/mach-omap2/powerdomain.c232
-rw-r--r--arch/arm/mach-omap2/powerdomain.h52
-rw-r--r--arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c4
-rw-r--r--arch/arm/mach-omap2/powerdomains2xxx_data.c9
-rw-r--r--arch/arm/mach-omap2/powerdomains3xxx_data.c44
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.c3
-rw-r--r--arch/arm/mach-omap2/prm3xxx.c2
-rw-r--r--arch/arm/mach-omap2/prm44xx.c2
-rw-r--r--arch/arm/mach-omap2/serial.c5
-rw-r--r--arch/arm/mach-omap2/smartreflex-class3.c3
-rw-r--r--arch/arm/mach-omap2/soc.h29
-rw-r--r--arch/arm/mach-omap2/sr_device.c3
-rw-r--r--arch/arm/mach-omap2/timer.c42
-rw-r--r--arch/arm/mach-omap2/twl-common.c20
-rw-r--r--arch/arm/mach-omap2/twl-common.h3
-rw-r--r--arch/arm/mach-omap2/usb-host.c41
-rw-r--r--arch/arm/mach-omap2/usb-musb.c5
-rw-r--r--arch/arm/mach-omap2/usb.h20
-rw-r--r--arch/arm/mach-omap2/wd_timer.c5
-rw-r--r--arch/arm/mach-orion5x/board-dt.c2
-rw-r--r--arch/arm/mach-orion5x/common.c6
-rw-r--r--arch/arm/mach-orion5x/common.h2
-rw-r--r--arch/arm/mach-orion5x/d2net-setup.c4
-rw-r--r--arch/arm/mach-orion5x/db88f5281-setup.c2
-rw-r--r--arch/arm/mach-orion5x/dns323-setup.c2
-rw-r--r--arch/arm/mach-orion5x/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-orion5x/kurobox_pro-setup.c4
-rw-r--r--arch/arm/mach-orion5x/ls-chl-setup.c2
-rw-r--r--arch/arm/mach-orion5x/ls_hgl-setup.c2
-rw-r--r--arch/arm/mach-orion5x/lsmini-setup.c2
-rw-r--r--arch/arm/mach-orion5x/mss2-setup.c2
-rw-r--r--arch/arm/mach-orion5x/mv2120-setup.c2
-rw-r--r--arch/arm/mach-orion5x/net2big-setup.c2
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c2
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-ge-setup.c2
-rw-r--r--arch/arm/mach-orion5x/rd88f5182-setup.c2
-rw-r--r--arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c2
-rw-r--r--arch/arm/mach-orion5x/terastation_pro2-setup.c2
-rw-r--r--arch/arm/mach-orion5x/ts209-setup.c2
-rw-r--r--arch/arm/mach-orion5x/ts409-setup.c2
-rw-r--r--arch/arm/mach-orion5x/ts78xx-setup.c2
-rw-r--r--arch/arm/mach-orion5x/wnr854t-setup.c2
-rw-r--r--arch/arm/mach-orion5x/wrt350n-v2-setup.c2
-rw-r--r--arch/arm/mach-picoxcell/Kconfig1
-rw-r--r--arch/arm/mach-picoxcell/common.c17
-rw-r--r--arch/arm/mach-picoxcell/common.h2
-rw-r--r--arch/arm/mach-prima2/Kconfig10
-rw-r--r--arch/arm/mach-prima2/Makefile5
-rw-r--r--arch/arm/mach-prima2/common.c33
-rw-r--r--arch/arm/mach-prima2/common.h15
-rw-r--r--arch/arm/mach-prima2/headsmp.S40
-rw-r--r--arch/arm/mach-prima2/hotplug.c41
-rw-r--r--arch/arm/mach-prima2/include/mach/irqs.h4
-rw-r--r--arch/arm/mach-prima2/include/mach/uart.h6
-rw-r--r--arch/arm/mach-prima2/include/mach/uncompress.h5
-rw-r--r--arch/arm/mach-prima2/irq.c16
-rw-r--r--arch/arm/mach-prima2/l2x0.c29
-rw-r--r--arch/arm/mach-prima2/platsmp.c157
-rw-r--r--arch/arm/mach-prima2/rstc.c45
-rw-r--r--arch/arm/mach-prima2/rtciobrg.c1
-rw-r--r--arch/arm/mach-prima2/timer-marco.c316
-rw-r--r--arch/arm/mach-prima2/timer-prima2.c (renamed from arch/arm/mach-prima2/timer.c)18
-rw-r--r--arch/arm/mach-pxa/balloon3.c2
-rw-r--r--arch/arm/mach-pxa/capc7117.c2
-rw-r--r--arch/arm/mach-pxa/cm-x2xx.c2
-rw-r--r--arch/arm/mach-pxa/cm-x300.c2
-rw-r--r--arch/arm/mach-pxa/colibri-pxa270.c4
-rw-r--r--arch/arm/mach-pxa/colibri-pxa300.c2
-rw-r--r--arch/arm/mach-pxa/colibri-pxa320.c2
-rw-r--r--arch/arm/mach-pxa/corgi.c6
-rw-r--r--arch/arm/mach-pxa/csb726.c2
-rw-r--r--arch/arm/mach-pxa/em-x270.c4
-rw-r--r--arch/arm/mach-pxa/eseries.c12
-rw-r--r--arch/arm/mach-pxa/ezx.c12
-rw-r--r--arch/arm/mach-pxa/generic.h3
-rw-r--r--arch/arm/mach-pxa/gumstix.c2
-rw-r--r--arch/arm/mach-pxa/h5000.c2
-rw-r--r--arch/arm/mach-pxa/himalaya.c2
-rw-r--r--arch/arm/mach-pxa/hx4700.c2
-rw-r--r--arch/arm/mach-pxa/icontrol.c2
-rw-r--r--arch/arm/mach-pxa/idp.c2
-rw-r--r--arch/arm/mach-pxa/include/mach/palmtreo.h5
-rw-r--r--arch/arm/mach-pxa/include/mach/smemc.h1
-rw-r--r--arch/arm/mach-pxa/include/mach/uncompress.h5
-rw-r--r--arch/arm/mach-pxa/littleton.c2
-rw-r--r--arch/arm/mach-pxa/lpd270.c2
-rw-r--r--arch/arm/mach-pxa/lubbock.c2
-rw-r--r--arch/arm/mach-pxa/magician.c2
-rw-r--r--arch/arm/mach-pxa/mainstone.c2
-rw-r--r--arch/arm/mach-pxa/mioa701.c2
-rw-r--r--arch/arm/mach-pxa/mp900.c2
-rw-r--r--arch/arm/mach-pxa/palmld.c2
-rw-r--r--arch/arm/mach-pxa/palmt5.c2
-rw-r--r--arch/arm/mach-pxa/palmtc.c2
-rw-r--r--arch/arm/mach-pxa/palmte2.c2
-rw-r--r--arch/arm/mach-pxa/palmtreo.c105
-rw-r--r--arch/arm/mach-pxa/palmtx.c2
-rw-r--r--arch/arm/mach-pxa/palmz72.c2
-rw-r--r--arch/arm/mach-pxa/pcm027.c2
-rw-r--r--arch/arm/mach-pxa/poodle.c2
-rw-r--r--arch/arm/mach-pxa/pxa-dt.c2
-rw-r--r--arch/arm/mach-pxa/pxa27x.c21
-rw-r--r--arch/arm/mach-pxa/raumfeld.c6
-rw-r--r--arch/arm/mach-pxa/saar.c2
-rw-r--r--arch/arm/mach-pxa/smemc.c15
-rw-r--r--arch/arm/mach-pxa/spitz.c10
-rw-r--r--arch/arm/mach-pxa/stargate2.c4
-rw-r--r--arch/arm/mach-pxa/tavorevb.c2
-rw-r--r--arch/arm/mach-pxa/time.c76
-rw-r--r--arch/arm/mach-pxa/tosa.c2
-rw-r--r--arch/arm/mach-pxa/trizeps4.c4
-rw-r--r--arch/arm/mach-pxa/viper.c2
-rw-r--r--arch/arm/mach-pxa/vpac270.c2
-rw-r--r--arch/arm/mach-pxa/xcep.c2
-rw-r--r--arch/arm/mach-pxa/z2.c2
-rw-r--r--arch/arm/mach-pxa/zeus.c2
-rw-r--r--arch/arm/mach-pxa/zylonite.c2
-rw-r--r--arch/arm/mach-realview/core.c1
-rw-r--r--arch/arm/mach-realview/include/mach/irqs-eb.h2
-rw-r--r--arch/arm/mach-realview/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-realview/platsmp.c3
-rw-r--r--arch/arm/mach-realview/realview_eb.c9
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c9
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c9
-rw-r--r--arch/arm/mach-realview/realview_pba8.c9
-rw-r--r--arch/arm/mach-realview/realview_pbx.c9
-rw-r--r--arch/arm/mach-rpc/include/mach/uncompress.h5
-rw-r--r--arch/arm/mach-rpc/riscpc.c4
-rw-r--r--arch/arm/mach-rpc/time.c13
-rw-r--r--arch/arm/mach-s3c2410/Kconfig20
-rw-r--r--arch/arm/mach-s3c2410/Makefile14
-rw-r--r--arch/arm/mach-s3c2412/Kconfig13
-rw-r--r--arch/arm/mach-s3c2412/Makefile12
-rw-r--r--arch/arm/mach-s3c2412/gpio.c62
-rw-r--r--arch/arm/mach-s3c2440/Kconfig37
-rw-r--r--arch/arm/mach-s3c2440/Makefile17
-rw-r--r--arch/arm/mach-s3c2440/dsc.c54
-rw-r--r--arch/arm/mach-s3c24xx/Kconfig166
-rw-r--r--arch/arm/mach-s3c24xx/Makefile24
-rw-r--r--arch/arm/mach-s3c24xx/anubis.h53
-rw-r--r--arch/arm/mach-s3c24xx/bast-ide.c18
-rw-r--r--arch/arm/mach-s3c24xx/bast-irq.c19
-rw-r--r--arch/arm/mach-s3c24xx/bast.h197
-rw-r--r--arch/arm/mach-s3c24xx/clock-dclk.c (renamed from arch/arm/plat-s3c24xx/clock-dclk.c)3
-rw-r--r--arch/arm/mach-s3c24xx/clock-s3c2410.c (renamed from arch/arm/plat-s3c24xx/s3c2410-clock.c)3
-rw-r--r--arch/arm/mach-s3c24xx/common-s3c2443.c2
-rw-r--r--arch/arm/mach-s3c24xx/common.c2
-rw-r--r--arch/arm/mach-s3c24xx/common.h2
-rw-r--r--arch/arm/mach-s3c24xx/cpufreq-debugfs.c (renamed from arch/arm/plat-s3c24xx/cpu-freq-debugfs.c)3
-rw-r--r--arch/arm/mach-s3c24xx/cpufreq-s3c2410.c (renamed from arch/arm/mach-s3c2410/cpu-freq.c)7
-rw-r--r--arch/arm/mach-s3c24xx/cpufreq-s3c2412.c (renamed from arch/arm/mach-s3c2412/cpu-freq.c)9
-rw-r--r--arch/arm/mach-s3c24xx/cpufreq-s3c2440.c (renamed from arch/arm/mach-s3c2440/s3c2440-cpufreq.c)4
-rw-r--r--arch/arm/mach-s3c24xx/cpufreq-utils.c (renamed from arch/arm/plat-s3c24xx/s3c2410-cpufreq-utils.c)6
-rw-r--r--arch/arm/mach-s3c24xx/cpufreq.c (renamed from arch/arm/plat-s3c24xx/cpu-freq.c)3
-rw-r--r--arch/arm/mach-s3c24xx/dma-s3c2410.c1
-rw-r--r--arch/arm/mach-s3c24xx/dma-s3c2412.c1
-rw-r--r--arch/arm/mach-s3c24xx/dma-s3c2440.c1
-rw-r--r--arch/arm/mach-s3c24xx/dma-s3c2443.c1
-rw-r--r--arch/arm/mach-s3c24xx/dma.c (renamed from arch/arm/plat-s3c24xx/dma.c)3
-rw-r--r--arch/arm/mach-s3c24xx/gta02.h (renamed from arch/arm/mach-s3c24xx/include/mach/gta02.h)14
-rw-r--r--arch/arm/mach-s3c24xx/h1940-bluetooth.c6
-rw-r--r--arch/arm/mach-s3c24xx/h1940.h (renamed from arch/arm/mach-s3c24xx/include/mach/h1940-latch.h)22
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/anubis-cpld.h25
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/anubis-irq.h21
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/anubis-map.h38
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/bast-cpld.h53
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/bast-irq.h29
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/bast-map.h146
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/debug-macro.S12
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/entry-macro.S4
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/gpio-fns.h1
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/gpio-nrs.h97
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/gpio-track.h33
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/gpio.h87
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/h1940.h24
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/hardware.h6
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/idle.h24
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/osiris-cpld.h30
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/regs-gpio.h2
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/regs-mem.h202
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/regs-power.h40
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/regs-s3c2412-mem.h48
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/regs-s3c2412.h23
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/regs-s3c2416-mem.h30
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/regs-s3c2416.h24
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/vr1000-cpld.h18
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/vr1000-irq.h26
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/vr1000-map.h110
-rw-r--r--arch/arm/mach-s3c24xx/iotiming-s3c2410.c (renamed from arch/arm/plat-s3c24xx/s3c2410-iotiming.c)6
-rw-r--r--arch/arm/mach-s3c24xx/iotiming-s3c2412.c (renamed from arch/arm/plat-s3c24xx/s3c2412-iotiming.c)7
-rw-r--r--arch/arm/mach-s3c24xx/irq-pm.c41
-rw-r--r--arch/arm/mach-s3c24xx/irq-s3c2412.c3
-rw-r--r--arch/arm/mach-s3c24xx/irq-s3c2416.c348
-rw-r--r--arch/arm/mach-s3c24xx/irq-s3c2443.c281
-rw-r--r--arch/arm/mach-s3c24xx/irq.c822
-rw-r--r--arch/arm/mach-s3c24xx/mach-amlm5900.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-anubis.c16
-rw-r--r--arch/arm/mach-s3c24xx/mach-at2440evb.c4
-rw-r--r--arch/arm/mach-s3c24xx/mach-bast.c53
-rw-r--r--arch/arm/mach-s3c24xx/mach-gta02.c60
-rw-r--r--arch/arm/mach-s3c24xx/mach-h1940.c39
-rw-r--r--arch/arm/mach-s3c24xx/mach-jive.c6
-rw-r--r--arch/arm/mach-s3c24xx/mach-mini2440.c3
-rw-r--r--arch/arm/mach-s3c24xx/mach-n30.c4
-rw-r--r--arch/arm/mach-s3c24xx/mach-nexcoder.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-osiris.c30
-rw-r--r--arch/arm/mach-s3c24xx/mach-otom.c22
-rw-r--r--arch/arm/mach-s3c24xx/mach-qt2410.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-rx1950.c33
-rw-r--r--arch/arm/mach-s3c24xx/mach-rx3715.c18
-rw-r--r--arch/arm/mach-s3c24xx/mach-smdk2410.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-smdk2413.c7
-rw-r--r--arch/arm/mach-s3c24xx/mach-smdk2416.c5
-rw-r--r--arch/arm/mach-s3c24xx/mach-smdk2440.c3
-rw-r--r--arch/arm/mach-s3c24xx/mach-smdk2443.c5
-rw-r--r--arch/arm/mach-s3c24xx/mach-tct_hammer.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-vr1000.c39
-rw-r--r--arch/arm/mach-s3c24xx/mach-vstms.c3
-rw-r--r--arch/arm/mach-s3c24xx/osiris.h (renamed from arch/arm/mach-s3c24xx/include/mach/osiris-map.h)23
-rw-r--r--arch/arm/mach-s3c24xx/otom.h (renamed from arch/arm/mach-s3c24xx/include/mach/otom-map.h)20
-rw-r--r--arch/arm/mach-s3c24xx/pll-s3c2410.c (renamed from arch/arm/mach-s3c2410/pll.c)5
-rw-r--r--arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c (renamed from arch/arm/mach-s3c2440/s3c2440-pll-12000000.c)5
-rw-r--r--arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c (renamed from arch/arm/mach-s3c2440/s3c2440-pll-16934400.c)5
-rw-r--r--arch/arm/mach-s3c24xx/pm-h1940.S2
-rw-r--r--arch/arm/mach-s3c24xx/pm-s3c2410.c6
-rw-r--r--arch/arm/mach-s3c24xx/pm-s3c2412.c11
-rw-r--r--arch/arm/mach-s3c24xx/pm-s3c2416.c6
-rw-r--r--arch/arm/mach-s3c24xx/pm.c3
-rw-r--r--arch/arm/mach-s3c24xx/regs-dsc.h (renamed from arch/arm/mach-s3c24xx/include/mach/regs-dsc.h)0
-rw-r--r--arch/arm/mach-s3c24xx/regs-mem.h54
-rw-r--r--arch/arm/mach-s3c24xx/s3c2410.c4
-rw-r--r--arch/arm/mach-s3c24xx/s3c2412-power.h37
-rw-r--r--arch/arm/mach-s3c24xx/s3c2412.c32
-rw-r--r--arch/arm/mach-s3c24xx/s3c2412.h26
-rw-r--r--arch/arm/mach-s3c24xx/s3c2416.c4
-rw-r--r--arch/arm/mach-s3c24xx/s3c2440.c4
-rw-r--r--arch/arm/mach-s3c24xx/s3c2442.c4
-rw-r--r--arch/arm/mach-s3c24xx/s3c244x.c3
-rw-r--r--arch/arm/mach-s3c24xx/simtec-audio.c5
-rw-r--r--arch/arm/mach-s3c24xx/simtec-nor.c3
-rw-r--r--arch/arm/mach-s3c24xx/simtec-pm.c3
-rw-r--r--arch/arm/mach-s3c24xx/simtec-usb.c8
-rw-r--r--arch/arm/mach-s3c24xx/sleep-s3c2410.S15
-rw-r--r--arch/arm/mach-s3c24xx/sleep-s3c2412.S12
-rw-r--r--arch/arm/mach-s3c24xx/sleep.S1
-rw-r--r--arch/arm/mach-s3c24xx/vr1000.h118
-rw-r--r--arch/arm/mach-s3c64xx/clock.c3
-rw-r--r--arch/arm/mach-s3c64xx/common.c2
-rw-r--r--arch/arm/mach-s3c64xx/cpuidle.c4
-rw-r--r--arch/arm/mach-s3c64xx/crag6410.h (renamed from arch/arm/mach-s3c64xx/include/mach/crag6410.h)0
-rw-r--r--arch/arm/mach-s3c64xx/dma.c4
-rw-r--r--arch/arm/mach-s3c64xx/include/mach/regs-irq.h1
-rw-r--r--arch/arm/mach-s3c64xx/include/mach/regs-sys.h31
-rw-r--r--arch/arm/mach-s3c64xx/include/mach/tick.h2
-rw-r--r--arch/arm/mach-s3c64xx/mach-anw6410.c6
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410-module.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410.c13
-rw-r--r--arch/arm/mach-s3c64xx/mach-hmt.c4
-rw-r--r--arch/arm/mach-s3c64xx/mach-mini6410.c8
-rw-r--r--arch/arm/mach-s3c64xx/mach-ncp.c4
-rw-r--r--arch/arm/mach-s3c64xx/mach-real6410.c8
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq5.c4
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq7.c4
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6400.c4
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6410.c10
-rw-r--r--arch/arm/mach-s3c64xx/pm.c12
-rw-r--r--arch/arm/mach-s3c64xx/regs-gpio-memport.h (renamed from arch/arm/mach-s3c64xx/include/mach/regs-gpio-memport.h)9
-rw-r--r--arch/arm/mach-s3c64xx/regs-modem.h (renamed from arch/arm/mach-s3c64xx/include/mach/regs-modem.h)11
-rw-r--r--arch/arm/mach-s3c64xx/regs-srom.h (renamed from arch/arm/mach-s3c64xx/include/mach/regs-srom.h)11
-rw-r--r--arch/arm/mach-s3c64xx/regs-sys.h30
-rw-r--r--arch/arm/mach-s3c64xx/regs-syscon-power.h (renamed from arch/arm/mach-s3c64xx/include/mach/regs-syscon-power.h)9
-rw-r--r--arch/arm/mach-s3c64xx/setup-usb-phy.c3
-rw-r--r--arch/arm/mach-s5p64x0/clock-s5p6440.c2
-rw-r--r--arch/arm/mach-s5p64x0/clock-s5p6450.c2
-rw-r--r--arch/arm/mach-s5p64x0/clock.h (renamed from arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h)9
-rw-r--r--arch/arm/mach-s5p64x0/gpiolib.c508
-rw-r--r--arch/arm/mach-s5p64x0/i2c.h (renamed from arch/arm/mach-s5p64x0/include/mach/i2c.h)3
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/regs-irq.h1
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/tick.h29
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/uncompress.h28
-rw-r--r--arch/arm/mach-s5p64x0/mach-smdk6440.c6
-rw-r--r--arch/arm/mach-s5p64x0/mach-smdk6450.c6
-rw-r--r--arch/arm/mach-s5p64x0/pm.c4
-rw-r--r--arch/arm/mach-s5p64x0/setup-i2c0.c2
-rw-r--r--arch/arm/mach-s5p64x0/setup-i2c1.c2
-rw-r--r--arch/arm/mach-s5pc100/include/mach/regs-irq.h1
-rw-r--r--arch/arm/mach-s5pc100/include/mach/tick.h2
-rw-r--r--arch/arm/mach-s5pc100/mach-smdkc100.c4
-rw-r--r--arch/arm/mach-s5pv210/dev-audio.c3
-rw-r--r--arch/arm/mach-s5pv210/include/mach/regs-audss.h18
-rw-r--r--arch/arm/mach-s5pv210/include/mach/regs-irq.h1
-rw-r--r--arch/arm/mach-s5pv210/include/mach/regs-sys.h15
-rw-r--r--arch/arm/mach-s5pv210/include/mach/tick.h26
-rw-r--r--arch/arm/mach-s5pv210/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-s5pv210/mach-aquila.c4
-rw-r--r--arch/arm/mach-s5pv210/mach-goni.c10
-rw-r--r--arch/arm/mach-s5pv210/mach-smdkc110.c4
-rw-r--r--arch/arm/mach-s5pv210/mach-smdkv210.c4
-rw-r--r--arch/arm/mach-s5pv210/mach-torbreck.c4
-rw-r--r--arch/arm/mach-s5pv210/pm.c4
-rw-r--r--arch/arm/mach-s5pv210/setup-usb-phy.c7
-rw-r--r--arch/arm/mach-sa1100/assabet.c3
-rw-r--r--arch/arm/mach-sa1100/badge4.c2
-rw-r--r--arch/arm/mach-sa1100/cerf.c2
-rw-r--r--arch/arm/mach-sa1100/collie.c2
-rw-r--r--arch/arm/mach-sa1100/generic.h4
-rw-r--r--arch/arm/mach-sa1100/h3100.c2
-rw-r--r--arch/arm/mach-sa1100/h3600.c2
-rw-r--r--arch/arm/mach-sa1100/hackkit.c2
-rw-r--r--arch/arm/mach-sa1100/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-sa1100/jornada720.c2
-rw-r--r--arch/arm/mach-sa1100/lart.c5
-rw-r--r--arch/arm/mach-sa1100/nanoengine.c2
-rw-r--r--arch/arm/mach-sa1100/pleb.c2
-rw-r--r--arch/arm/mach-sa1100/shannon.c2
-rw-r--r--arch/arm/mach-sa1100/simpad.c2
-rw-r--r--arch/arm/mach-sa1100/time.c72
-rw-r--r--arch/arm/mach-shark/core.c6
-rw-r--r--arch/arm/mach-shark/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-shmobile/Makefile11
-rw-r--r--arch/arm/mach-shmobile/board-ag5evm.c27
-rw-r--r--arch/arm/mach-shmobile/board-ap4evb.c81
-rw-r--r--arch/arm/mach-shmobile/board-armadillo800eva.c106
-rw-r--r--arch/arm/mach-shmobile/board-bonito.c12
-rw-r--r--arch/arm/mach-shmobile/board-kota2.c14
-rw-r--r--arch/arm/mach-shmobile/board-kzm9d.c4
-rw-r--r--arch/arm/mach-shmobile/board-kzm9g.c47
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c64
-rw-r--r--arch/arm/mach-shmobile/board-marzen.c4
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7740.c6
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7779.c1
-rw-r--r--arch/arm/mach-shmobile/clock-sh7372.c9
-rw-r--r--arch/arm/mach-shmobile/clock-sh73a0.c35
-rw-r--r--arch/arm/mach-shmobile/headsmp-sh73a0.S50
-rw-r--r--arch/arm/mach-shmobile/headsmp.S48
-rw-r--r--arch/arm/mach-shmobile/hotplug.c6
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h14
-rw-r--r--arch/arm/mach-shmobile/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-shmobile/intc-r8a7779.c2
-rw-r--r--arch/arm/mach-shmobile/intc-sh73a0.c18
-rw-r--r--arch/arm/mach-shmobile/platsmp.c3
-rw-r--r--arch/arm/mach-shmobile/pm-r8a7740.c22
-rw-r--r--arch/arm/mach-shmobile/pm-sh73a0.c32
-rw-r--r--arch/arm/mach-shmobile/setup-emev2.c19
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7740.c132
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7779.c48
-rw-r--r--arch/arm/mach-shmobile/setup-sh7372.c33
-rw-r--r--arch/arm/mach-shmobile/setup-sh73a0.c90
-rw-r--r--arch/arm/mach-shmobile/sleep-sh7372.S12
-rw-r--r--arch/arm/mach-shmobile/smp-emev2.c4
-rw-r--r--arch/arm/mach-shmobile/smp-r8a7779.c2
-rw-r--r--arch/arm/mach-shmobile/smp-sh73a0.c70
-rw-r--r--arch/arm/mach-shmobile/timer.c9
-rw-r--r--arch/arm/mach-socfpga/core.h4
-rw-r--r--arch/arm/mach-socfpga/headsmp.S16
-rw-r--r--arch/arm/mach-socfpga/platsmp.c21
-rw-r--r--arch/arm/mach-socfpga/socfpga.c23
-rw-r--r--arch/arm/mach-spear13xx/include/mach/generic.h3
-rw-r--r--arch/arm/mach-spear13xx/platsmp.c4
-rw-r--r--arch/arm/mach-spear13xx/spear1310.c7
-rw-r--r--arch/arm/mach-spear13xx/spear1340.c7
-rw-r--r--arch/arm/mach-spear13xx/spear13xx.c19
-rw-r--r--arch/arm/mach-spear3xx/include/mach/generic.h3
-rw-r--r--arch/arm/mach-spear3xx/spear300.c7
-rw-r--r--arch/arm/mach-spear3xx/spear310.c7
-rw-r--r--arch/arm/mach-spear3xx/spear320.c7
-rw-r--r--arch/arm/mach-spear3xx/spear3xx.c22
-rw-r--r--arch/arm/mach-spear6xx/spear6xx.c24
-rw-r--r--arch/arm/mach-sunxi/Kconfig1
-rw-r--r--arch/arm/mach-sunxi/sunxi.c23
-rw-r--r--arch/arm/mach-tegra/Kconfig19
-rw-r--r--arch/arm/mach-tegra/Makefile15
-rw-r--r--arch/arm/mach-tegra/apbio.c2
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra114.c46
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra20.c76
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra30.c67
-rw-r--r--arch/arm/mach-tegra/board.h3
-rw-r--r--arch/arm/mach-tegra/clock.c166
-rw-r--r--arch/arm/mach-tegra/clock.h153
-rw-r--r--arch/arm/mach-tegra/common.c80
-rw-r--r--arch/arm/mach-tegra/common.h1
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c43
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra114.c61
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra20.c197
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra30.c8
-rw-r--r--arch/arm/mach-tegra/cpuidle.c3
-rw-r--r--arch/arm/mach-tegra/cpuidle.h6
-rw-r--r--arch/arm/mach-tegra/flowctrl.c42
-rw-r--r--arch/arm/mach-tegra/flowctrl.h4
-rw-r--r--arch/arm/mach-tegra/fuse.c8
-rw-r--r--arch/arm/mach-tegra/fuse.h1
-rw-r--r--arch/arm/mach-tegra/headsmp.S264
-rw-r--r--arch/arm/mach-tegra/hotplug.c23
-rw-r--r--arch/arm/mach-tegra/include/mach/clk.h44
-rw-r--r--arch/arm/mach-tegra/include/mach/uncompress.h4
-rw-r--r--arch/arm/mach-tegra/iomap.h9
-rw-r--r--arch/arm/mach-tegra/irq.c18
-rw-r--r--arch/arm/mach-tegra/irq.h22
-rw-r--r--arch/arm/mach-tegra/pcie.c2
-rw-r--r--arch/arm/mach-tegra/platsmp.c72
-rw-r--r--arch/arm/mach-tegra/pm.c9
-rw-r--r--arch/arm/mach-tegra/powergate.c2
-rw-r--r--arch/arm/mach-tegra/reset-handler.S239
-rw-r--r--arch/arm/mach-tegra/reset.c2
-rw-r--r--arch/arm/mach-tegra/sleep-tegra20.S203
-rw-r--r--arch/arm/mach-tegra/sleep-tegra30.S3
-rw-r--r--arch/arm/mach-tegra/sleep.S23
-rw-r--r--arch/arm/mach-tegra/sleep.h27
-rw-r--r--arch/arm/mach-tegra/tegra20_clocks.c1623
-rw-r--r--arch/arm/mach-tegra/tegra20_clocks.h42
-rw-r--r--arch/arm/mach-tegra/tegra20_clocks_data.c1143
-rw-r--r--arch/arm/mach-tegra/tegra2_emc.c8
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks.c2506
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks.h54
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks_data.c1425
-rw-r--r--arch/arm/mach-u300/core.c1092
-rw-r--r--arch/arm/mach-u300/dma_channels.h60
-rw-r--r--arch/arm/mach-u300/include/mach/coh901318.h267
-rw-r--r--arch/arm/mach-u300/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-u300/spi.c3
-rw-r--r--arch/arm/mach-u300/timer.c10
-rw-r--r--arch/arm/mach-u300/timer.h2
-rw-r--r--arch/arm/mach-ux500/Kconfig6
-rw-r--r--arch/arm/mach-ux500/board-mop500-uib.c1
-rw-r--r--arch/arm/mach-ux500/board-mop500.c38
-rw-r--r--arch/arm/mach-ux500/cache-l2x0.c3
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c15
-rw-r--r--arch/arm/mach-ux500/cpu.c17
-rw-r--r--arch/arm/mach-ux500/cpuidle.c4
-rw-r--r--arch/arm/mach-ux500/devices-db8500.c44
-rw-r--r--arch/arm/mach-ux500/devices-db8500.h5
-rw-r--r--arch/arm/mach-ux500/id.c2
-rw-r--r--arch/arm/mach-ux500/id.h (renamed from arch/arm/mach-ux500/include/mach/id.h)21
-rw-r--r--arch/arm/mach-ux500/include/mach/hardware.h1
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-board-mop500.h10
-rw-r--r--arch/arm/mach-ux500/include/mach/setup.h3
-rw-r--r--arch/arm/mach-ux500/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-ux500/platsmp.c9
-rw-r--r--arch/arm/mach-ux500/timer.c15
-rw-r--r--arch/arm/mach-versatile/Kconfig5
-rw-r--r--arch/arm/mach-versatile/core.c26
-rw-r--r--arch/arm/mach-versatile/core.h2
-rw-r--r--arch/arm/mach-versatile/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-versatile/pci.c11
-rw-r--r--arch/arm/mach-versatile/versatile_ab.c4
-rw-r--r--arch/arm/mach-versatile/versatile_dt.c4
-rw-r--r--arch/arm/mach-versatile/versatile_pb.c4
-rw-r--r--arch/arm/mach-vexpress/ct-ca9x4.c4
-rw-r--r--arch/arm/mach-vexpress/platsmp.c3
-rw-r--r--arch/arm/mach-vexpress/v2m.c28
-rw-r--r--arch/arm/mach-virt/Kconfig10
-rw-r--r--arch/arm/mach-virt/Makefile6
-rw-r--r--arch/arm/mach-virt/platsmp.c58
-rw-r--r--arch/arm/mach-virt/virt.c54
-rw-r--r--arch/arm/mach-vt8500/Kconfig30
-rw-r--r--arch/arm/mach-vt8500/Makefile2
-rw-r--r--arch/arm/mach-vt8500/common.h1
-rw-r--r--arch/arm/mach-vt8500/include/mach/timex.h26
-rw-r--r--arch/arm/mach-vt8500/include/mach/uncompress.h37
-rw-r--r--arch/arm/mach-vt8500/vt8500.c9
-rw-r--r--arch/arm/mach-w90x900/include/mach/entry-macro.S4
-rw-r--r--arch/arm/mach-w90x900/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-w90x900/mach-nuc910evb.c2
-rw-r--r--arch/arm/mach-w90x900/mach-nuc950evb.c2
-rw-r--r--arch/arm/mach-w90x900/mach-nuc960evb.c2
-rw-r--r--arch/arm/mach-w90x900/nuc9xx.h3
-rw-r--r--arch/arm/mach-w90x900/time.c16
-rw-r--r--arch/arm/mach-zynq/common.c29
-rw-r--r--arch/arm/mach-zynq/common.h2
-rw-r--r--arch/arm/mach-zynq/timer.c150
-rw-r--r--arch/arm/mm/Kconfig10
-rw-r--r--arch/arm/mm/Makefile2
-rw-r--r--arch/arm/mm/cache-v7.S46
-rw-r--r--arch/arm/mm/context.c3
-rw-r--r--arch/arm/mm/dma-mapping.c2
-rw-r--r--arch/arm/mm/idmap.c55
-rw-r--r--arch/arm/mm/ioremap.c135
-rw-r--r--arch/arm/mm/mm.h12
-rw-r--r--arch/arm/mm/mmu.c58
-rw-r--r--arch/arm/mm/proc-macros.S5
-rw-r--r--arch/arm/mm/proc-v6.S2
-rw-r--r--arch/arm/mm/proc-v7-2level.S2
-rw-r--r--arch/arm/mm/proc-v7-3level.S2
-rw-r--r--arch/arm/mm/vmregion.c205
-rw-r--r--arch/arm/mm/vmregion.h31
-rw-r--r--arch/arm/net/bpf_jit_32.c15
-rw-r--r--arch/arm/plat-iop/time.c9
-rw-r--r--arch/arm/plat-omap/Kconfig32
-rw-r--r--arch/arm/plat-omap/Makefile2
-rw-r--r--arch/arm/plat-omap/dma.c2
-rw-r--r--arch/arm/plat-omap/dmtimer.c8
-rw-r--r--arch/arm/plat-omap/i2c.c3
-rw-r--r--arch/arm/plat-omap/include/plat/i2c.h6
-rw-r--r--arch/arm/plat-orion/mpp.c2
-rw-r--r--arch/arm/plat-orion/time.c6
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig116
-rw-r--r--arch/arm/plat-s3c24xx/Makefile27
-rw-r--r--arch/arm/plat-s3c24xx/irq.c676
-rw-r--r--arch/arm/plat-samsung/adc.c8
-rw-r--r--arch/arm/plat-samsung/dma-ops.c10
-rw-r--r--arch/arm/plat-samsung/include/plat/adc.h1
-rw-r--r--arch/arm/plat-samsung/include/plat/cpu.h3
-rw-r--r--arch/arm/plat-samsung/include/plat/debug-macro.S18
-rw-r--r--arch/arm/plat-samsung/include/plat/dma-ops.h3
-rw-r--r--arch/arm/plat-samsung/include/plat/fimc-core.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/gpio-core.h13
-rw-r--r--arch/arm/plat-samsung/include/plat/gpio-fns.h1
-rw-r--r--arch/arm/plat-samsung/include/plat/pm.h6
-rw-r--r--arch/arm/plat-samsung/include/plat/s3c2416.h1
-rw-r--r--arch/arm/plat-samsung/include/plat/s3c2443.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/s5p-time.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/sdhci.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/uncompress.h28
-rw-r--r--arch/arm/plat-samsung/pm.c7
-rw-r--r--arch/arm/plat-samsung/s3c-dma-ops.c3
-rw-r--r--arch/arm/plat-samsung/s5p-irq-eint.c3
-rw-r--r--arch/arm/plat-samsung/s5p-irq.c3
-rw-r--r--arch/arm/plat-samsung/s5p-time.c15
-rw-r--r--arch/arm/plat-samsung/time.c20
-rw-r--r--arch/arm/plat-spear/Kconfig1
-rw-r--r--arch/arm/plat-spear/include/plat/uncompress.h1
-rw-r--r--arch/arm/plat-spear/restart.c2
-rw-r--r--arch/arm/plat-spear/time.c8
-rw-r--r--arch/arm/plat-versatile/platsmp.c4
-rw-r--r--arch/arm/xen/enlighten.c8
-rw-r--r--arch/arm64/Kconfig5
-rw-r--r--arch/arm64/Kconfig.debug17
-rw-r--r--arch/arm64/include/asm/Kbuild2
-rw-r--r--arch/arm64/include/asm/arch_timer.h133
-rw-r--r--arch/arm64/include/asm/arm_generic.h100
-rw-r--r--arch/arm64/include/asm/atomic.h132
-rw-r--r--arch/arm64/include/asm/cmpxchg.h74
-rw-r--r--arch/arm64/include/asm/futex.h2
-rw-r--r--arch/arm64/include/asm/io.h3
-rw-r--r--arch/arm64/include/asm/memory.h1
-rw-r--r--arch/arm64/include/asm/mmu.h1
-rw-r--r--arch/arm64/include/asm/mmu_context.h15
-rw-r--r--arch/arm64/include/asm/perf_event.h7
-rw-r--r--arch/arm64/include/asm/psci.h38
-rw-r--r--arch/arm64/include/asm/ptrace.h10
-rw-r--r--arch/arm64/include/asm/smp.h11
-rw-r--r--arch/arm64/include/asm/spinlock.h78
-rw-r--r--arch/arm64/include/asm/syscalls.h2
-rw-r--r--arch/arm64/include/asm/unistd.h2
-rw-r--r--arch/arm64/include/asm/unistd32.h4
-rw-r--r--arch/arm64/include/uapi/asm/Kbuild3
-rw-r--r--arch/arm64/kernel/Makefile5
-rw-r--r--arch/arm64/kernel/early_printk.c118
-rw-r--r--arch/arm64/kernel/entry.S5
-rw-r--r--arch/arm64/kernel/head.S12
-rw-r--r--arch/arm64/kernel/perf_event.c37
-rw-r--r--arch/arm64/kernel/process.c17
-rw-r--r--arch/arm64/kernel/psci.c211
-rw-r--r--arch/arm64/kernel/setup.c11
-rw-r--r--arch/arm64/kernel/signal.c17
-rw-r--r--arch/arm64/kernel/signal32.c224
-rw-r--r--arch/arm64/kernel/smp.c69
-rw-r--r--arch/arm64/kernel/smp_psci.c52
-rw-r--r--arch/arm64/kernel/smp_spin_table.c66
-rw-r--r--arch/arm64/kernel/sys.c1
-rw-r--r--arch/arm64/kernel/sys32.S5
-rw-r--r--arch/arm64/kernel/time.c29
-rw-r--r--arch/arm64/kernel/traps.c2
-rw-r--r--arch/arm64/mm/mmu.c45
-rw-r--r--arch/avr32/include/asm/signal.h11
-rw-r--r--arch/avr32/include/asm/unistd.h2
-rw-r--r--arch/avr32/include/uapi/asm/socket.h4
-rw-r--r--arch/avr32/kernel/signal.c15
-rw-r--r--arch/avr32/kernel/syscall-stubs.S6
-rw-r--r--arch/avr32/kernel/syscall_table.S2
-rw-r--r--arch/avr32/kernel/traps.c2
-rw-r--r--arch/blackfin/Kconfig8
-rw-r--r--arch/blackfin/include/asm/mem_init.h2
-rw-r--r--arch/blackfin/include/asm/uaccess.h1
-rw-r--r--arch/blackfin/include/asm/unistd.h2
-rw-r--r--arch/blackfin/kernel/dma-mapping.c23
-rw-r--r--arch/blackfin/kernel/process.c7
-rw-r--r--arch/blackfin/kernel/signal.c12
-rw-r--r--arch/blackfin/kernel/time-ts.c6
-rw-r--r--arch/blackfin/kernel/time.c6
-rw-r--r--arch/blackfin/mach-common/ints-priority.c4
-rw-r--r--arch/c6x/kernel/entry.S12
-rw-r--r--arch/cris/Kconfig2
-rw-r--r--arch/cris/arch-v10/kernel/signal.c65
-rw-r--r--arch/cris/arch-v10/kernel/time.c10
-rw-r--r--arch/cris/arch-v32/drivers/Kconfig4
-rw-r--r--arch/cris/arch-v32/kernel/signal.c68
-rw-r--r--arch/cris/include/asm/signal.h19
-rw-r--r--arch/cris/include/asm/unistd.h2
-rw-r--r--arch/cris/include/uapi/asm/posix_types.h5
-rw-r--r--arch/cris/include/uapi/asm/socket.h4
-rw-r--r--arch/cris/kernel/process.c11
-rw-r--r--arch/cris/kernel/time.c11
-rw-r--r--arch/frv/Kconfig3
-rw-r--r--arch/frv/include/asm/signal.h7
-rw-r--r--arch/frv/include/asm/unistd.h2
-rw-r--r--arch/frv/include/uapi/asm/socket.h4
-rw-r--r--arch/frv/kernel/signal.c55
-rw-r--r--arch/h8300/Kconfig2
-rw-r--r--arch/h8300/README2
-rw-r--r--arch/h8300/include/asm/signal.h18
-rw-r--r--arch/h8300/include/asm/unistd.h2
-rw-r--r--arch/h8300/include/uapi/asm/socket.h4
-rw-r--r--arch/h8300/kernel/signal.c72
-rw-r--r--arch/h8300/kernel/syscalls.S15
-rw-r--r--arch/hexagon/Kconfig2
-rw-r--r--arch/hexagon/kernel/signal.c16
-rw-r--r--arch/hexagon/kernel/traps.c2
-rw-r--r--arch/ia64/Kconfig10
-rw-r--r--arch/ia64/hp/common/aml_nfw.c2
-rw-r--r--arch/ia64/hp/sim/Kconfig1
-rw-r--r--arch/ia64/hp/sim/simserial.c21
-rw-r--r--arch/ia64/include/asm/acpi.h4
-rw-r--r--arch/ia64/include/asm/cputime.h92
-rw-r--r--arch/ia64/include/asm/kvm_host.h4
-rw-r--r--arch/ia64/include/asm/signal.h10
-rw-r--r--arch/ia64/include/asm/thread_info.h4
-rw-r--r--arch/ia64/include/asm/unistd.h8
-rw-r--r--arch/ia64/include/asm/xen/minstate.h2
-rw-r--r--arch/ia64/include/uapi/asm/socket.h4
-rw-r--r--arch/ia64/kernel/asm-offsets.c2
-rw-r--r--arch/ia64/kernel/entry.S16
-rw-r--r--arch/ia64/kernel/fsys.S4
-rw-r--r--arch/ia64/kernel/head.S4
-rw-r--r--arch/ia64/kernel/ivt.S8
-rw-r--r--arch/ia64/kernel/minstate.h2
-rw-r--r--arch/ia64/kernel/process.c3
-rw-r--r--arch/ia64/kernel/setup.c1
-rw-r--r--arch/ia64/kernel/signal.c19
-rw-r--r--arch/ia64/kernel/sys_ia64.c37
-rw-r--r--arch/ia64/kernel/time.c5
-rw-r--r--arch/ia64/kernel/traps.c2
-rw-r--r--arch/ia64/kvm/Kconfig2
-rw-r--r--arch/ia64/kvm/kvm-ia64.c8
-rw-r--r--arch/ia64/kvm/lapic.h6
-rw-r--r--arch/ia64/mm/contig.c2
-rw-r--r--arch/ia64/mm/discontig.c6
-rw-r--r--arch/ia64/mm/hugetlbpage.c20
-rw-r--r--arch/ia64/mm/init.c18
-rw-r--r--arch/ia64/xen/Kconfig2
-rw-r--r--arch/m32r/include/asm/signal.h11
-rw-r--r--arch/m32r/include/asm/unistd.h2
-rw-r--r--arch/m32r/include/uapi/asm/socket.h4
-rw-r--r--arch/m32r/kernel/process.c51
-rw-r--r--arch/m32r/kernel/signal.c16
-rw-r--r--arch/m32r/kernel/time.c4
-rw-r--r--arch/m68k/Kconfig2
-rw-r--r--arch/m68k/Kconfig.devices2
-rw-r--r--arch/m68k/amiga/config.c10
-rw-r--r--arch/m68k/apollo/config.c9
-rw-r--r--arch/m68k/atari/config.c4
-rw-r--r--arch/m68k/atari/time.c6
-rw-r--r--arch/m68k/bvme6000/config.c10
-rw-r--r--arch/m68k/hp300/config.c2
-rw-r--r--arch/m68k/hp300/time.c4
-rw-r--r--arch/m68k/hp300/time.h2
-rw-r--r--arch/m68k/include/asm/dma-mapping.h5
-rw-r--r--arch/m68k/include/asm/machdep.h2
-rw-r--r--arch/m68k/include/asm/processor.h1
-rw-r--r--arch/m68k/include/asm/signal.h19
-rw-r--r--arch/m68k/include/asm/unistd.h2
-rw-r--r--arch/m68k/kernel/Makefile4
-rw-r--r--arch/m68k/kernel/setup_mm.c1
-rw-r--r--arch/m68k/kernel/signal.c59
-rw-r--r--arch/m68k/kernel/time.c15
-rw-r--r--arch/m68k/kernel/traps.c2
-rw-r--r--arch/m68k/mac/config.c4
-rw-r--r--arch/m68k/mac/via.c4
-rw-r--r--arch/m68k/mvme147/config.c8
-rw-r--r--arch/m68k/mvme16x/config.c8
-rw-r--r--arch/m68k/q40/config.c8
-rw-r--r--arch/m68k/sun3/config.c4
-rw-r--r--arch/m68k/sun3/intersil.c4
-rw-r--r--arch/m68k/sun3x/config.c2
-rw-r--r--arch/m68k/sun3x/time.c2
-rw-r--r--arch/m68k/sun3x/time.h2
-rw-r--r--arch/microblaze/include/asm/unistd.h2
-rw-r--r--arch/microblaze/kernel/entry-nommu.S21
-rw-r--r--arch/microblaze/kernel/entry.S62
-rw-r--r--arch/microblaze/kernel/process.c3
-rw-r--r--arch/microblaze/kernel/ptrace.c23
-rw-r--r--arch/microblaze/kernel/signal.c26
-rw-r--r--arch/microblaze/platform/Kconfig.platform2
-rw-r--r--arch/mips/Kconfig30
-rw-r--r--arch/mips/bcm47xx/serial.c2
-rw-r--r--arch/mips/cavium-octeon/dma-octeon.c3
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-util.c4
-rw-r--r--arch/mips/include/asm/compat.h8
-rw-r--r--arch/mips/include/asm/octeon/cvmx-helper-util.h4
-rw-r--r--arch/mips/include/asm/signal.h2
-rw-r--r--arch/mips/include/asm/sim.h24
-rw-r--r--arch/mips/include/asm/unistd.h3
-rw-r--r--arch/mips/include/uapi/asm/signal.h6
-rw-r--r--arch/mips/include/uapi/asm/socket.h5
-rw-r--r--arch/mips/jazz/Kconfig6
-rw-r--r--arch/mips/kernel/linux32.c44
-rw-r--r--arch/mips/kernel/process.c3
-rw-r--r--arch/mips/kernel/scall32-o32.S4
-rw-r--r--arch/mips/kernel/scall64-64.S4
-rw-r--r--arch/mips/kernel/scall64-n32.S20
-rw-r--r--arch/mips/kernel/scall64-o32.S22
-rw-r--r--arch/mips/kernel/signal.c48
-rw-r--r--arch/mips/kernel/signal32.c237
-rw-r--r--arch/mips/kernel/signal_n32.c59
-rw-r--r--arch/mips/kernel/syscall.c73
-rw-r--r--arch/mips/kernel/traps.c2
-rw-r--r--arch/mips/lantiq/xway/dma.c5
-rw-r--r--arch/mips/lantiq/xway/gptu.c8
-rw-r--r--arch/mips/pci/pci-lantiq.c12
-rw-r--r--arch/mips/sgi-ip27/Kconfig1
-rw-r--r--arch/mips/sni/a20r.c2
-rw-r--r--arch/mn10300/Kconfig2
-rw-r--r--arch/mn10300/include/asm/signal.h19
-rw-r--r--arch/mn10300/include/asm/unistd.h2
-rw-r--r--arch/mn10300/include/uapi/asm/socket.h4
-rw-r--r--arch/mn10300/kernel/mn10300-serial.c20
-rw-r--r--arch/mn10300/kernel/process.c7
-rw-r--r--arch/mn10300/kernel/signal.c60
-rw-r--r--arch/mn10300/unit-asb2305/pci-irq.c2
-rw-r--r--arch/openrisc/kernel/entry.S4
-rw-r--r--arch/openrisc/kernel/idle.c5
-rw-r--r--arch/openrisc/kernel/signal.c15
-rw-r--r--arch/parisc/Kconfig32
-rw-r--r--arch/parisc/Makefile13
-rw-r--r--arch/parisc/hpux/fs.c3
-rw-r--r--arch/parisc/include/asm/cacheflush.h2
-rw-r--r--arch/parisc/include/asm/compat.h61
-rw-r--r--arch/parisc/include/asm/compat_rt_sigframe.h50
-rw-r--r--arch/parisc/include/asm/elf.h2
-rw-r--r--arch/parisc/include/asm/floppy.h4
-rw-r--r--arch/parisc/include/asm/mmzone.h7
-rw-r--r--arch/parisc/include/asm/page.h20
-rw-r--r--arch/parisc/include/asm/pgtable.h13
-rw-r--r--arch/parisc/include/asm/signal.h10
-rw-r--r--arch/parisc/include/asm/unistd.h5
-rw-r--r--arch/parisc/include/uapi/asm/socket.h3
-rw-r--r--arch/parisc/include/uapi/asm/unistd.h6
-rw-r--r--arch/parisc/kernel/cache.c221
-rw-r--r--arch/parisc/kernel/entry.S42
-rw-r--r--arch/parisc/kernel/inventory.c2
-rw-r--r--arch/parisc/kernel/irq.c4
-rw-r--r--arch/parisc/kernel/pacache.S335
-rw-r--r--arch/parisc/kernel/parisc_ksyms.c5
-rw-r--r--arch/parisc/kernel/pdc_cons.c10
-rw-r--r--arch/parisc/kernel/signal.c21
-rw-r--r--arch/parisc/kernel/signal32.c142
-rw-r--r--arch/parisc/kernel/signal32.h23
-rw-r--r--arch/parisc/kernel/sys32.h12
-rw-r--r--arch/parisc/kernel/sys_parisc.c16
-rw-r--r--arch/parisc/kernel/sys_parisc32.c122
-rw-r--r--arch/parisc/kernel/syscall.S5
-rw-r--r--arch/parisc/kernel/syscall_table.S35
-rw-r--r--arch/parisc/kernel/traps.c2
-rw-r--r--arch/parisc/mm/fault.c30
-rw-r--r--arch/powerpc/Kconfig32
-rw-r--r--arch/powerpc/Makefile22
-rw-r--r--arch/powerpc/boot/dts/a3m071.dts6
-rw-r--r--arch/powerpc/boot/dts/a4m072.dts27
-rw-r--r--arch/powerpc/boot/dts/bluestone.dts8
-rw-r--r--arch/powerpc/boot/dts/bsc9131rdb.dtsi2
-rw-r--r--arch/powerpc/boot/dts/cm5200.dts6
-rw-r--r--arch/powerpc/boot/dts/digsy_mtc.dts14
-rw-r--r--arch/powerpc/boot/dts/fsl/p1010si-post.dtsi4
-rw-r--r--arch/powerpc/boot/dts/fsl/p1022si-post.dtsi6
-rw-r--r--arch/powerpc/boot/dts/fsl/p2041si-post.dtsi87
-rw-r--r--arch/powerpc/boot/dts/fsl/p3041si-post.dtsi87
-rw-r--r--arch/powerpc/boot/dts/fsl/p4080si-post.dtsi74
-rw-r--r--arch/powerpc/boot/dts/fsl/p5020si-post.dtsi92
-rw-r--r--arch/powerpc/boot/dts/fsl/p5040si-post.dtsi92
-rw-r--r--arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi1
-rw-r--r--arch/powerpc/boot/dts/lite5200b.dts23
-rw-r--r--arch/powerpc/boot/dts/media5200.dts6
-rw-r--r--arch/powerpc/boot/dts/motionpro.dts26
-rw-r--r--arch/powerpc/boot/dts/mpc5121.dtsi410
-rw-r--r--arch/powerpc/boot/dts/mpc5121ads.dts319
-rw-r--r--arch/powerpc/boot/dts/mpc5200b.dtsi25
-rw-r--r--arch/powerpc/boot/dts/mucmc52.dts48
-rw-r--r--arch/powerpc/boot/dts/o2d.dtsi27
-rw-r--r--arch/powerpc/boot/dts/pcm030.dts48
-rw-r--r--arch/powerpc/boot/dts/pcm032.dts45
-rw-r--r--arch/powerpc/boot/dts/pdm360ng.dts273
-rw-r--r--arch/powerpc/boot/dts/ppa8548.dts166
-rw-r--r--arch/powerpc/boot/dts/sbc8548-altflash.dts115
-rw-r--r--arch/powerpc/boot/dts/sbc8548-post.dtsi295
-rw-r--r--arch/powerpc/boot/dts/sbc8548-pre.dtsi52
-rw-r--r--arch/powerpc/boot/dts/sbc8548.dts356
-rw-r--r--arch/powerpc/boot/dts/uc101.dts52
-rw-r--r--arch/powerpc/boot/dts/virtex440-ml507.dts6
-rw-r--r--arch/powerpc/configs/83xx/kmeter1_defconfig6
-rw-r--r--arch/powerpc/configs/85xx/ge_imp3a_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/ppa8548_defconfig65
-rw-r--r--arch/powerpc/configs/85xx/sbc8548_defconfig19
-rw-r--r--arch/powerpc/configs/86xx/gef_ppc9a_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc310_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc610_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/sbc8641d_defconfig1
-rw-r--r--arch/powerpc/configs/chroma_defconfig2
-rw-r--r--arch/powerpc/configs/corenet32_smp_defconfig1
-rw-r--r--arch/powerpc/configs/corenet64_smp_defconfig3
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig1
-rw-r--r--arch/powerpc/configs/pasemi_defconfig31
-rw-r--r--arch/powerpc/configs/ppc64_defconfig147
-rw-r--r--arch/powerpc/configs/ppc64e_defconfig107
-rw-r--r--arch/powerpc/configs/ps3_defconfig15
-rw-r--r--arch/powerpc/configs/pseries_defconfig91
-rw-r--r--arch/powerpc/crypto/Makefile9
-rw-r--r--arch/powerpc/crypto/sha1-powerpc-asm.S179
-rw-r--r--arch/powerpc/crypto/sha1.c157
-rw-r--r--arch/powerpc/include/asm/cputable.h126
-rw-r--r--arch/powerpc/include/asm/cputime.h6
-rw-r--r--arch/powerpc/include/asm/dbell.h30
-rw-r--r--arch/powerpc/include/asm/debug.h15
-rw-r--r--arch/powerpc/include/asm/eeh.h3
-rw-r--r--arch/powerpc/include/asm/exception-64s.h138
-rw-r--r--arch/powerpc/include/asm/firmware.h3
-rw-r--r--arch/powerpc/include/asm/hvcall.h9
-rw-r--r--arch/powerpc/include/asm/hw_breakpoint.h35
-rw-r--r--arch/powerpc/include/asm/kvm_book3s_asm.h3
-rw-r--r--arch/powerpc/include/asm/kvm_host.h9
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h12
-rw-r--r--arch/powerpc/include/asm/lppaca.h2
-rw-r--r--arch/powerpc/include/asm/machdep.h4
-rw-r--r--arch/powerpc/include/asm/mpc5121.h17
-rw-r--r--arch/powerpc/include/asm/paca.h10
-rw-r--r--arch/powerpc/include/asm/perf_event_server.h36
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h13
-rw-r--r--arch/powerpc/include/asm/ppc4xx_ocm.h45
-rw-r--r--arch/powerpc/include/asm/ppc_asm.h114
-rw-r--r--arch/powerpc/include/asm/processor.h48
-rw-r--r--arch/powerpc/include/asm/ps3.h2
-rw-r--r--arch/powerpc/include/asm/reg.h45
-rw-r--r--arch/powerpc/include/asm/reg_booke.h1
-rw-r--r--arch/powerpc/include/asm/sections.h3
-rw-r--r--arch/powerpc/include/asm/signal.h1
-rw-r--r--arch/powerpc/include/asm/spinlock.h2
-rw-r--r--arch/powerpc/include/asm/syscalls.h15
-rw-r--r--arch/powerpc/include/asm/systbl.h63
-rw-r--r--arch/powerpc/include/asm/tm.h20
-rw-r--r--arch/powerpc/include/asm/unistd.h4
-rw-r--r--arch/powerpc/include/uapi/asm/kvm.h6
-rw-r--r--arch/powerpc/include/uapi/asm/ptrace.h29
-rw-r--r--arch/powerpc/include/uapi/asm/signal.h6
-rw-r--r--arch/powerpc/include/uapi/asm/socket.h4
-rw-r--r--arch/powerpc/kernel/Makefile10
-rw-r--r--arch/powerpc/kernel/asm-offsets.c36
-rw-r--r--arch/powerpc/kernel/cpu_setup_power.S7
-rw-r--r--arch/powerpc/kernel/dbell.c4
-rw-r--r--arch/powerpc/kernel/entry_64.S47
-rw-r--r--arch/powerpc/kernel/exceptions-64e.S3
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S351
-rw-r--r--arch/powerpc/kernel/fpu.S66
-rw-r--r--arch/powerpc/kernel/head_40x.S47
-rw-r--r--arch/powerpc/kernel/head_64.S34
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c84
-rw-r--r--arch/powerpc/kernel/iommu.c7
-rw-r--r--arch/powerpc/kernel/irq.c11
-rw-r--r--arch/powerpc/kernel/kgdb.c10
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c5
-rw-r--r--arch/powerpc/kernel/module_64.c30
-rw-r--r--arch/powerpc/kernel/of_platform.c7
-rw-r--r--arch/powerpc/kernel/paca.c2
-rw-r--r--arch/powerpc/kernel/pci-common.c7
-rw-r--r--arch/powerpc/kernel/ppc32.h26
-rw-r--r--arch/powerpc/kernel/process.c241
-rw-r--r--arch/powerpc/kernel/prom_init.c626
-rw-r--r--arch/powerpc/kernel/prom_init_check.sh2
-rw-r--r--arch/powerpc/kernel/ptrace.c89
-rw-r--r--arch/powerpc/kernel/ptrace32.c8
-rw-r--r--arch/powerpc/kernel/setup_64.c18
-rw-r--r--arch/powerpc/kernel/signal.c12
-rw-r--r--arch/powerpc/kernel/signal.h8
-rw-r--r--arch/powerpc/kernel/signal_32.c729
-rw-r--r--arch/powerpc/kernel/signal_64.c348
-rw-r--r--arch/powerpc/kernel/smp.c2
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c301
-rw-r--r--arch/powerpc/kernel/time.c7
-rw-r--r--arch/powerpc/kernel/tm.S388
-rw-r--r--arch/powerpc/kernel/traps.c152
-rw-r--r--arch/powerpc/kernel/vector.S51
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S5
-rw-r--r--arch/powerpc/kvm/Kconfig10
-rw-r--r--arch/powerpc/kvm/Makefile9
-rw-r--r--arch/powerpc/kvm/book3s_emulate.c30
-rw-r--r--arch/powerpc/kvm/book3s_hv.c2
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S9
-rw-r--r--arch/powerpc/kvm/book3s_pr.c24
-rw-r--r--arch/powerpc/kvm/booke.c70
-rw-r--r--arch/powerpc/kvm/booke.h1
-rw-r--r--arch/powerpc/kvm/booke_emulate.c3
-rw-r--r--arch/powerpc/kvm/booke_interrupts.S49
-rw-r--r--arch/powerpc/kvm/e500.c16
-rw-r--r--arch/powerpc/kvm/e500.h1
-rw-r--r--arch/powerpc/kvm/e500_mmu.c (renamed from arch/powerpc/kvm/e500_tlb.c)659
-rw-r--r--arch/powerpc/kvm/e500_mmu_host.c699
-rw-r--r--arch/powerpc/kvm/e500_mmu_host.h18
-rw-r--r--arch/powerpc/kvm/emulate.c5
-rw-r--r--arch/powerpc/kvm/powerpc.c17
-rw-r--r--arch/powerpc/lib/Makefile6
-rw-r--r--arch/powerpc/mm/Makefile2
-rw-r--r--arch/powerpc/mm/fault.c4
-rw-r--r--arch/powerpc/mm/hash_utils_64.c16
-rw-r--r--arch/powerpc/mm/init_64.c5
-rw-r--r--arch/powerpc/mm/mem.c23
-rw-r--r--arch/powerpc/oprofile/Makefile2
-rw-r--r--arch/powerpc/perf/core-book3s.c105
-rw-r--r--arch/powerpc/perf/e500-pmu.c2
-rw-r--r--arch/powerpc/perf/power7-pmu.c80
-rw-r--r--arch/powerpc/platforms/44x/Kconfig8
-rw-r--r--arch/powerpc/platforms/512x/clock.c34
-rw-r--r--arch/powerpc/platforms/512x/mpc512x_shared.c37
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c6
-rw-r--r--arch/powerpc/platforms/82xx/km82xx.c6
-rw-r--r--arch/powerpc/platforms/82xx/pq2.c4
-rw-r--r--arch/powerpc/platforms/83xx/km83xx.c161
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig16
-rw-r--r--arch/powerpc/platforms/85xx/Makefile2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c4
-rw-r--r--arch/powerpc/platforms/85xx/p1022_ds.c48
-rw-r--r--arch/powerpc/platforms/85xx/p1022_rdk.c12
-rw-r--r--arch/powerpc/platforms/85xx/ppa8548.c98
-rw-r--r--arch/powerpc/platforms/85xx/qemu_e500.c7
-rw-r--r--arch/powerpc/platforms/85xx/sgy_cts1000.c176
-rw-r--r--arch/powerpc/platforms/86xx/mpc8610_hpcd.c4
-rw-r--r--arch/powerpc/platforms/Kconfig2
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype6
-rw-r--r--arch/powerpc/platforms/cell/Kconfig2
-rw-r--r--arch/powerpc/platforms/cell/celleb_scc_sio.c5
-rw-r--r--arch/powerpc/platforms/cell/spu_callbacks.c13
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c1
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig2
-rw-r--r--arch/powerpc/platforms/ps3/htab.c14
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig1
-rw-r--r--arch/powerpc/platforms/pseries/Makefile2
-rw-r--r--arch/powerpc/platforms/pseries/dtl.c6
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c24
-rw-r--r--arch/powerpc/platforms/pseries/firmware.c21
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c8
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c104
-rw-r--r--arch/powerpc/platforms/pseries/pci.c3
-rw-r--r--arch/powerpc/platforms/pseries/plpar_wrappers.h18
-rw-r--r--arch/powerpc/platforms/pseries/pseries_energy.c37
-rw-r--r--arch/powerpc/platforms/pseries/setup.c26
-rw-r--r--arch/powerpc/platforms/pseries/smp.c33
-rw-r--r--arch/powerpc/platforms/wsp/Makefile2
-rw-r--r--arch/powerpc/sysdev/Makefile4
-rw-r--r--arch/powerpc/sysdev/fsl_85xx_l2ctlr.c1
-rw-r--r--arch/powerpc/sysdev/fsl_ifc.c2
-rw-r--r--arch/powerpc/sysdev/fsl_lbc.c6
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c4
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c24
-rw-r--r--arch/powerpc/sysdev/fsl_pci.h2
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c4
-rw-r--r--arch/powerpc/sysdev/mpc5xxx_clocks.c4
-rw-r--r--arch/powerpc/sysdev/mpic.c28
-rw-r--r--arch/powerpc/sysdev/ppc4xx_ocm.c415
-rw-r--r--arch/powerpc/sysdev/xics/ics-rtas.c2
-rw-r--r--arch/powerpc/xmon/Makefile2
-rw-r--r--arch/powerpc/xmon/xmon.c21
-rw-r--r--arch/s390/Kconfig121
-rw-r--r--arch/s390/appldata/appldata_mem.c2
-rw-r--r--arch/s390/appldata/appldata_net_sum.c2
-rw-r--r--arch/s390/appldata/appldata_os.c2
-rw-r--r--arch/s390/hypfs/hypfs_vm.c2
-rw-r--r--arch/s390/include/asm/barrier.h9
-rw-r--r--arch/s390/include/asm/clp.h2
-rw-r--r--arch/s390/include/asm/cpu_mf.h4
-rw-r--r--arch/s390/include/asm/dma-mapping.h8
-rw-r--r--arch/s390/include/asm/irq.h1
-rw-r--r--arch/s390/include/asm/kvm_host.h15
-rw-r--r--arch/s390/include/asm/mman.h4
-rw-r--r--arch/s390/include/asm/page.h22
-rw-r--r--arch/s390/include/asm/pci.h11
-rw-r--r--arch/s390/include/asm/pgtable.h132
-rw-r--r--arch/s390/include/asm/sclp.h1
-rw-r--r--arch/s390/include/asm/setup.h22
-rw-r--r--arch/s390/include/asm/signal.h19
-rw-r--r--arch/s390/include/asm/timex.h18
-rw-r--r--arch/s390/include/asm/unistd.h3
-rw-r--r--arch/s390/include/uapi/asm/socket.h4
-rw-r--r--arch/s390/kernel/compat_linux.c80
-rw-r--r--arch/s390/kernel/compat_linux.h34
-rw-r--r--arch/s390/kernel/compat_signal.c134
-rw-r--r--arch/s390/kernel/compat_wrapper.S144
-rw-r--r--arch/s390/kernel/debug.c2
-rw-r--r--arch/s390/kernel/dis.c1
-rw-r--r--arch/s390/kernel/early.c8
-rw-r--r--arch/s390/kernel/entry.h4
-rw-r--r--arch/s390/kernel/entry64.S10
-rw-r--r--arch/s390/kernel/ipl.c16
-rw-r--r--arch/s390/kernel/irq.c1
-rw-r--r--arch/s390/kernel/module.c143
-rw-r--r--arch/s390/kernel/nmi.c2
-rw-r--r--arch/s390/kernel/perf_cpum_cf.c13
-rw-r--r--arch/s390/kernel/signal.c56
-rw-r--r--arch/s390/kernel/smp.c10
-rw-r--r--arch/s390/kernel/syscalls.S46
-rw-r--r--arch/s390/kernel/time.c29
-rw-r--r--arch/s390/kernel/traps.c2
-rw-r--r--arch/s390/kernel/vmlinux.lds.S4
-rw-r--r--arch/s390/kernel/vtime.c8
-rw-r--r--arch/s390/kvm/Kconfig2
-rw-r--r--arch/s390/kvm/intercept.c45
-rw-r--r--arch/s390/kvm/interrupt.c270
-rw-r--r--arch/s390/kvm/kvm-s390.c52
-rw-r--r--arch/s390/kvm/kvm-s390.h46
-rw-r--r--arch/s390/kvm/priv.c316
-rw-r--r--arch/s390/kvm/sigp.c10
-rw-r--r--arch/s390/kvm/trace-s390.h26
-rw-r--r--arch/s390/lib/delay.c16
-rw-r--r--arch/s390/lib/uaccess_pt.c2
-rw-r--r--arch/s390/mm/init.c12
-rw-r--r--arch/s390/mm/mmap.c9
-rw-r--r--arch/s390/mm/pageattr.c2
-rw-r--r--arch/s390/mm/vmem.c28
-rw-r--r--arch/s390/net/bpf_jit_comp.c21
-rw-r--r--arch/s390/pci/pci.c35
-rw-r--r--arch/s390/pci/pci_clp.c14
-rw-r--r--arch/score/include/asm/syscalls.h1
-rw-r--r--arch/score/kernel/entry.S5
-rw-r--r--arch/score/kernel/signal.c21
-rw-r--r--arch/sh/Kconfig31
-rw-r--r--arch/sh/Kconfig.cpu3
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c27
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c29
-rw-r--r--arch/sh/include/asm/gpio.h2
-rw-r--r--arch/sh/include/asm/syscalls_32.h6
-rw-r--r--arch/sh/include/asm/unistd.h2
-rw-r--r--arch/sh/include/cpu-common/cpu/pfc.h (renamed from include/linux/clk/sunxi.h)20
-rw-r--r--arch/sh/include/cpu-sh4/cpu/sh7723.h2
-rw-r--r--arch/sh/include/cpu-sh4/cpu/sh7786.h8
-rw-r--r--arch/sh/include/uapi/asm/signal.h2
-rw-r--r--arch/sh/kernel/cpu/Makefile2
-rw-r--r--arch/sh/kernel/cpu/pfc.c33
-rw-r--r--arch/sh/kernel/cpu/sh2a/pinmux-sh7203.c1582
-rw-r--r--arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c2121
-rw-r--r--arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c2823
-rw-r--r--arch/sh/kernel/cpu/sh3/pinmux-sh7720.c1226
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-sh7722.c1778
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-sh7723.c1893
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-sh7724.c2210
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c2470
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c2267
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-sh7785.c1294
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-sh7786.c822
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-shx3.c573
-rw-r--r--arch/sh/kernel/idle.c12
-rw-r--r--arch/sh/kernel/signal_32.c63
-rw-r--r--arch/sh/kernel/signal_64.c62
-rw-r--r--arch/sh/kernel/traps.c2
-rw-r--r--arch/sh/mm/Kconfig4
-rw-r--r--arch/sh/mm/init.c17
-rw-r--r--arch/sparc/Kconfig6
-rw-r--r--arch/sparc/include/asm/compat_signal.h6
-rw-r--r--arch/sparc/include/asm/hugetlb.h1
-rw-r--r--arch/sparc/include/asm/page_64.h4
-rw-r--r--arch/sparc/include/asm/pgtable_64.h14
-rw-r--r--arch/sparc/include/asm/processor_32.h1
-rw-r--r--arch/sparc/include/asm/signal.h6
-rw-r--r--arch/sparc/include/asm/tsb.h28
-rw-r--r--arch/sparc/include/asm/unistd.h3
-rw-r--r--arch/sparc/include/uapi/asm/signal.h2
-rw-r--r--arch/sparc/include/uapi/asm/socket.h3
-rw-r--r--arch/sparc/kernel/apc.c3
-rw-r--r--arch/sparc/kernel/entry.S8
-rw-r--r--arch/sparc/kernel/kernel.h12
-rw-r--r--arch/sparc/kernel/kgdb_32.c1
-rw-r--r--arch/sparc/kernel/leon_pmc.c5
-rw-r--r--arch/sparc/kernel/leon_smp.c33
-rw-r--r--arch/sparc/kernel/pmc.c3
-rw-r--r--arch/sparc/kernel/process_32.c7
-rw-r--r--arch/sparc/kernel/prom_common.c4
-rw-r--r--arch/sparc/kernel/sbus.c6
-rw-r--r--arch/sparc/kernel/setup_64.c2
-rw-r--r--arch/sparc/kernel/signal32.c202
-rw-r--r--arch/sparc/kernel/signal_32.c175
-rw-r--r--arch/sparc/kernel/signal_64.c142
-rw-r--r--arch/sparc/kernel/smp_32.c86
-rw-r--r--arch/sparc/kernel/sun4d_smp.c29
-rw-r--r--arch/sparc/kernel/sun4m_smp.c33
-rw-r--r--arch/sparc/kernel/sys32.S86
-rw-r--r--arch/sparc/kernel/sys_sparc32.c185
-rw-r--r--arch/sparc/kernel/sys_sparc_32.c48
-rw-r--r--arch/sparc/kernel/syscalls.S6
-rw-r--r--arch/sparc/kernel/systbls.h4
-rw-r--r--arch/sparc/kernel/systbls_32.S2
-rw-r--r--arch/sparc/kernel/systbls_64.S84
-rw-r--r--arch/sparc/kernel/trampoline_32.S17
-rw-r--r--arch/sparc/kernel/traps_32.c2
-rw-r--r--arch/sparc/kernel/traps_64.c2
-rw-r--r--arch/sparc/kernel/tsb.S39
-rw-r--r--arch/sparc/mm/fault_64.c9
-rw-r--r--arch/sparc/mm/gup.c59
-rw-r--r--arch/sparc/mm/init_32.c2
-rw-r--r--arch/sparc/mm/init_64.c91
-rw-r--r--arch/sparc/mm/tlb.c11
-rw-r--r--arch/sparc/mm/tsb.c2
-rw-r--r--arch/tile/Kconfig9
-rw-r--r--arch/tile/include/asm/compat.h8
-rw-r--r--arch/tile/include/asm/io.h6
-rw-r--r--arch/tile/include/asm/irqflags.h32
-rw-r--r--arch/tile/include/asm/syscalls.h2
-rw-r--r--arch/tile/include/asm/unistd.h1
-rw-r--r--arch/tile/include/uapi/arch/interrupts_32.h394
-rw-r--r--arch/tile/include/uapi/arch/interrupts_64.h346
-rw-r--r--arch/tile/kernel/compat_signal.c112
-rw-r--r--arch/tile/kernel/intvec_64.S4
-rw-r--r--arch/tile/kernel/process.c2
-rw-r--r--arch/tile/kernel/reboot.c2
-rw-r--r--arch/tile/kernel/setup.c5
-rw-r--r--arch/tile/kernel/signal.c15
-rw-r--r--arch/tile/kernel/stack.c3
-rw-r--r--arch/tile/kvm/Kconfig2
-rw-r--r--arch/tile/lib/cacheflush.c2
-rw-r--r--arch/tile/lib/cpumask.c2
-rw-r--r--arch/tile/lib/exports.c2
-rw-r--r--arch/tile/mm/elf.c1
-rw-r--r--arch/tile/mm/homecache.c1
-rw-r--r--arch/tile/mm/init.c8
-rw-r--r--arch/tile/mm/pgtable.c2
-rw-r--r--arch/um/Kconfig.common1
-rw-r--r--arch/um/Kconfig.net2
-rw-r--r--arch/um/Kconfig.um8
-rw-r--r--arch/um/drivers/chan.h3
-rw-r--r--arch/um/drivers/chan_kern.c25
-rw-r--r--arch/um/drivers/line.c7
-rw-r--r--arch/um/drivers/net_kern.c26
-rw-r--r--arch/um/include/shared/net_kern.h1
-rw-r--r--arch/um/kernel/signal.c10
-rw-r--r--arch/unicore32/kernel/entry.S5
-rw-r--r--arch/unicore32/kernel/process.c5
-rw-r--r--arch/unicore32/kernel/signal.c12
-rw-r--r--arch/unicore32/kernel/traps.c2
-rw-r--r--arch/x86/Kconfig91
-rw-r--r--arch/x86/Makefile4
-rw-r--r--arch/x86/boot/boot.h18
-rw-r--r--arch/x86/boot/cmdline.c12
-rw-r--r--arch/x86/boot/compressed/cmdline.c12
-rw-r--r--arch/x86/boot/compressed/head_64.S48
-rw-r--r--arch/x86/boot/compressed/misc.c2
-rw-r--r--arch/x86/boot/compressed/misc.h1
-rw-r--r--arch/x86/boot/header.S10
-rw-r--r--arch/x86/configs/i386_defconfig1
-rw-r--r--arch/x86/crypto/Makefile2
-rw-r--r--arch/x86/crypto/aes-i586-asm_32.S15
-rw-r--r--arch/x86/crypto/aes-x86_64-asm_64.S30
-rw-r--r--arch/x86/crypto/aesni-intel_asm.S23
-rw-r--r--arch/x86/crypto/aesni-intel_glue.c37
-rw-r--r--arch/x86/crypto/blowfish-x86_64-asm_64.S39
-rw-r--r--arch/x86/crypto/camellia-aesni-avx-asm_64.S38
-rw-r--r--arch/x86/crypto/camellia-x86_64-asm_64.S50
-rw-r--r--arch/x86/crypto/cast5-avx-x86_64-asm_64.S48
-rw-r--r--arch/x86/crypto/cast6-avx-x86_64-asm_64.S35
-rw-r--r--arch/x86/crypto/crc32-pclmul_asm.S246
-rw-r--r--arch/x86/crypto/crc32-pclmul_glue.c201
-rw-r--r--arch/x86/crypto/crc32c-pcl-intel-asm_64.S8
-rw-r--r--arch/x86/crypto/ghash-clmulni-intel_asm.S4
-rw-r--r--arch/x86/crypto/salsa20-i586-asm_32.S28
-rw-r--r--arch/x86/crypto/salsa20-x86_64-asm_64.S28
-rw-r--r--arch/x86/crypto/salsa20_glue.c5
-rw-r--r--arch/x86/crypto/serpent-avx-x86_64-asm_64.S35
-rw-r--r--arch/x86/crypto/serpent-sse2-i586-asm_32.S20
-rw-r--r--arch/x86/crypto/serpent-sse2-x86_64-asm_64.S20
-rw-r--r--arch/x86/crypto/sha1_ssse3_asm.S10
-rw-r--r--arch/x86/crypto/twofish-avx-x86_64-asm_64.S35
-rw-r--r--arch/x86/crypto/twofish-i586-asm_32.S11
-rw-r--r--arch/x86/crypto/twofish-x86_64-asm_64-3way.S20
-rw-r--r--arch/x86/crypto/twofish-x86_64-asm_64.S11
-rw-r--r--arch/x86/ia32/ia32_signal.c50
-rw-r--r--arch/x86/ia32/ia32entry.S12
-rw-r--r--arch/x86/ia32/sys_ia32.c171
-rw-r--r--arch/x86/include/asm/acpi.h4
-rw-r--r--arch/x86/include/asm/amd_nb.h17
-rw-r--r--arch/x86/include/asm/bootparam_utils.h38
-rw-r--r--arch/x86/include/asm/cpufeature.h2
-rw-r--r--arch/x86/include/asm/fpu-internal.h5
-rw-r--r--arch/x86/include/asm/ftrace.h1
-rw-r--r--arch/x86/include/asm/hpet.h5
-rw-r--r--arch/x86/include/asm/hw_irq.h13
-rw-r--r--arch/x86/include/asm/hypervisor.h13
-rw-r--r--arch/x86/include/asm/ia32.h15
-rw-r--r--arch/x86/include/asm/init.h28
-rw-r--r--arch/x86/include/asm/io_apic.h28
-rw-r--r--arch/x86/include/asm/irq_remapping.h40
-rw-r--r--arch/x86/include/asm/irq_vectors.h4
-rw-r--r--arch/x86/include/asm/kexec.h6
-rw-r--r--arch/x86/include/asm/kvm_host.h26
-rw-r--r--arch/x86/include/asm/kvm_para.h10
-rw-r--r--arch/x86/include/asm/linkage.h18
-rw-r--r--arch/x86/include/asm/mce.h84
-rw-r--r--arch/x86/include/asm/microcode.h14
-rw-r--r--arch/x86/include/asm/microcode_intel.h85
-rw-r--r--arch/x86/include/asm/mmzone_32.h6
-rw-r--r--arch/x86/include/asm/mshyperv.h4
-rw-r--r--arch/x86/include/asm/mwait.h3
-rw-r--r--arch/x86/include/asm/numa.h6
-rw-r--r--arch/x86/include/asm/numa_64.h6
-rw-r--r--arch/x86/include/asm/page.h7
-rw-r--r--arch/x86/include/asm/page_32.h1
-rw-r--r--arch/x86/include/asm/page_64.h36
-rw-r--r--arch/x86/include/asm/page_64_types.h22
-rw-r--r--arch/x86/include/asm/page_types.h2
-rw-r--r--arch/x86/include/asm/pci.h3
-rw-r--r--arch/x86/include/asm/perf_event.h13
-rw-r--r--arch/x86/include/asm/pgtable.h34
-rw-r--r--arch/x86/include/asm/pgtable_32.h7
-rw-r--r--arch/x86/include/asm/pgtable_64.h8
-rw-r--r--arch/x86/include/asm/pgtable_64_types.h4
-rw-r--r--arch/x86/include/asm/pgtable_types.h5
-rw-r--r--arch/x86/include/asm/processor.h29
-rw-r--r--arch/x86/include/asm/proto.h2
-rw-r--r--arch/x86/include/asm/realmode.h3
-rw-r--r--arch/x86/include/asm/required-features.h8
-rw-r--r--arch/x86/include/asm/signal.h22
-rw-r--r--arch/x86/include/asm/sys_ia32.h16
-rw-r--r--arch/x86/include/asm/syscalls.h13
-rw-r--r--arch/x86/include/asm/tlbflush.h18
-rw-r--r--arch/x86/include/asm/uaccess.h55
-rw-r--r--arch/x86/include/asm/unistd.h2
-rw-r--r--arch/x86/include/asm/uv/uv_hub.h44
-rw-r--r--arch/x86/include/asm/uv/uv_mmrs.h1496
-rw-r--r--arch/x86/include/asm/vmx.h18
-rw-r--r--arch/x86/include/asm/x86_init.h39
-rw-r--r--arch/x86/include/asm/xen/events.h3
-rw-r--r--arch/x86/include/asm/xen/page.h2
-rw-r--r--arch/x86/include/asm/xor.h491
-rw-r--r--arch/x86/include/asm/xor_32.h309
-rw-r--r--arch/x86/include/asm/xor_64.h305
-rw-r--r--arch/x86/include/uapi/asm/mce.h87
-rw-r--r--arch/x86/include/uapi/asm/msr-index.h6
-rw-r--r--arch/x86/include/uapi/asm/signal.h8
-rw-r--r--arch/x86/include/uapi/asm/vmx.h9
-rw-r--r--arch/x86/kernel/Makefile6
-rw-r--r--arch/x86/kernel/acpi/boot.c5
-rw-r--r--arch/x86/kernel/acpi/sleep.c2
-rw-r--r--arch/x86/kernel/amd_gart_64.c5
-rw-r--r--arch/x86/kernel/apb_timer.c10
-rw-r--r--arch/x86/kernel/apic/apic.c28
-rw-r--r--arch/x86/kernel/apic/apic_numachip.c1
-rw-r--r--arch/x86/kernel/apic/io_apic.c457
-rw-r--r--arch/x86/kernel/apic/ipi.c2
-rw-r--r--arch/x86/kernel/apic/x2apic_phys.c21
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c206
-rw-r--r--arch/x86/kernel/apm_32.c68
-rw-r--r--arch/x86/kernel/cpu/amd.c68
-rw-r--r--arch/x86/kernel/cpu/bugs.c27
-rw-r--r--arch/x86/kernel/cpu/common.c17
-rw-r--r--arch/x86/kernel/cpu/hypervisor.c7
-rw-r--r--arch/x86/kernel/cpu/intel.c3
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c2
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c16
-rw-r--r--arch/x86/kernel/cpu/mcheck/p5.c2
-rw-r--r--arch/x86/kernel/cpu/mcheck/winchip.c2
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c54
-rw-r--r--arch/x86/kernel/cpu/mtrr/generic.c2
-rw-r--r--arch/x86/kernel/cpu/perf_event.c15
-rw-r--r--arch/x86/kernel/cpu/perf_event.h25
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd.c322
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd_ibs.c2
-rw-r--r--arch/x86/kernel/cpu/proc.c2
-rw-r--r--arch/x86/kernel/cpu/vmware.c13
-rw-r--r--arch/x86/kernel/dumpstack.c2
-rw-r--r--arch/x86/kernel/e820.c16
-rw-r--r--arch/x86/kernel/entry_32.S54
-rw-r--r--arch/x86/kernel/entry_64.S41
-rw-r--r--arch/x86/kernel/ftrace.c4
-rw-r--r--arch/x86/kernel/head32.c21
-rw-r--r--arch/x86/kernel/head64.c146
-rw-r--r--arch/x86/kernel/head_32.S104
-rw-r--r--arch/x86/kernel/head_64.S212
-rw-r--r--arch/x86/kernel/hpet.c2
-rw-r--r--arch/x86/kernel/i386_ksyms_32.c1
-rw-r--r--arch/x86/kernel/ioport.c3
-rw-r--r--arch/x86/kernel/kprobes/Makefile7
-rw-r--r--arch/x86/kernel/kprobes/common.h (renamed from arch/x86/kernel/kprobes-common.h)11
-rw-r--r--arch/x86/kernel/kprobes/core.c (renamed from arch/x86/kernel/kprobes.c)76
-rw-r--r--arch/x86/kernel/kprobes/ftrace.c93
-rw-r--r--arch/x86/kernel/kprobes/opt.c (renamed from arch/x86/kernel/kprobes-opt.c)2
-rw-r--r--arch/x86/kernel/kvm.c12
-rw-r--r--arch/x86/kernel/kvmclock.c15
-rw-r--r--arch/x86/kernel/machine_kexec_64.c171
-rw-r--r--arch/x86/kernel/microcode_core.c7
-rw-r--r--arch/x86/kernel/microcode_core_early.c76
-rw-r--r--arch/x86/kernel/microcode_intel.c198
-rw-r--r--arch/x86/kernel/microcode_intel_early.c796
-rw-r--r--arch/x86/kernel/microcode_intel_lib.c174
-rw-r--r--arch/x86/kernel/process.c122
-rw-r--r--arch/x86/kernel/process_64.c2
-rw-r--r--arch/x86/kernel/ptrace.c2
-rw-r--r--arch/x86/kernel/rtc.c1
-rw-r--r--arch/x86/kernel/setup.c273
-rw-r--r--arch/x86/kernel/signal.c184
-rw-r--r--arch/x86/kernel/smpboot.c2
-rw-r--r--arch/x86/kernel/sys_x86_64.c2
-rw-r--r--arch/x86/kernel/traps.c9
-rw-r--r--arch/x86/kernel/tsc.c3
-rw-r--r--arch/x86/kernel/uprobes.c4
-rw-r--r--arch/x86/kernel/vm86_32.c8
-rw-r--r--arch/x86/kernel/x8664_ksyms_64.c3
-rw-r--r--arch/x86/kernel/x86_init.c28
-rw-r--r--arch/x86/kvm/emulate.c673
-rw-r--r--arch/x86/kvm/i8254.c1
-rw-r--r--arch/x86/kvm/i8259.c2
-rw-r--r--arch/x86/kvm/irq.c74
-rw-r--r--arch/x86/kvm/lapic.c140
-rw-r--r--arch/x86/kvm/lapic.h34
-rw-r--r--arch/x86/kvm/mmu.c168
-rw-r--r--arch/x86/kvm/mmutrace.h6
-rw-r--r--arch/x86/kvm/paging_tmpl.h106
-rw-r--r--arch/x86/kvm/svm.c24
-rw-r--r--arch/x86/kvm/vmx.c714
-rw-r--r--arch/x86/kvm/x86.c184
-rw-r--r--arch/x86/lguest/Kconfig1
-rw-r--r--arch/x86/lguest/boot.c3
-rw-r--r--arch/x86/lib/getuser.S43
-rw-r--r--arch/x86/mm/fault.c8
-rw-r--r--arch/x86/mm/init.c469
-rw-r--r--arch/x86/mm/init_32.c118
-rw-r--r--arch/x86/mm/init_64.c659
-rw-r--r--arch/x86/mm/memtest.c10
-rw-r--r--arch/x86/mm/mm_internal.h19
-rw-r--r--arch/x86/mm/numa.c43
-rw-r--r--arch/x86/mm/numa_32.c161
-rw-r--r--arch/x86/mm/numa_64.c13
-rw-r--r--arch/x86/mm/numa_internal.h6
-rw-r--r--arch/x86/mm/pageattr.c113
-rw-r--r--arch/x86/mm/pat.c4
-rw-r--r--arch/x86/mm/pgtable.c7
-rw-r--r--arch/x86/mm/physaddr.c60
-rw-r--r--arch/x86/mm/srat.c152
-rw-r--r--arch/x86/mm/tlb.c2
-rw-r--r--arch/x86/net/bpf_jit_comp.c40
-rw-r--r--arch/x86/pci/mmconfig-shared.c3
-rw-r--r--arch/x86/platform/Makefile2
-rw-r--r--arch/x86/platform/efi/efi-bgrt.c7
-rw-r--r--arch/x86/platform/efi/efi.c13
-rw-r--r--arch/x86/platform/goldfish/Makefile1
-rw-r--r--arch/x86/platform/goldfish/goldfish.c51
-rw-r--r--arch/x86/platform/olpc/olpc-xo15-sci.c2
-rw-r--r--arch/x86/platform/sfi/sfi.c2
-rw-r--r--arch/x86/platform/ts5500/Makefile1
-rw-r--r--arch/x86/platform/ts5500/ts5500.c339
-rw-r--r--arch/x86/platform/uv/tlb_uv.c4
-rw-r--r--arch/x86/platform/uv/uv_time.c13
-rw-r--r--arch/x86/power/hibernate_32.c2
-rw-r--r--arch/x86/power/hibernate_64.c66
-rw-r--r--arch/x86/realmode/init.c49
-rw-r--r--arch/x86/syscalls/syscall_32.tbl22
-rw-r--r--arch/x86/syscalls/syscall_64.tbl6
-rw-r--r--arch/x86/um/Kconfig6
-rw-r--r--arch/x86/um/Makefile4
-rw-r--r--arch/x86/um/fault.c2
-rw-r--r--arch/x86/um/shared/sysdep/syscalls_32.h5
-rw-r--r--arch/x86/um/signal.c15
-rw-r--r--arch/x86/um/sys_call_table_32.c4
-rw-r--r--arch/x86/um/syscalls_32.c38
-rw-r--r--arch/x86/vdso/vclock_gettime.c2
-rw-r--r--arch/x86/xen/enlighten.c78
-rw-r--r--arch/x86/xen/mmu.c72
-rw-r--r--arch/x86/xen/setup.c5
-rw-r--r--arch/x86/xen/smp.c42
-rw-r--r--arch/x86/xen/spinlock.c1
-rw-r--r--arch/x86/xen/suspend.c2
-rw-r--r--arch/x86/xen/xen-asm_32.S14
-rw-r--r--arch/x86/xen/xen-ops.h2
-rw-r--r--arch/xtensa/Kconfig3
-rw-r--r--arch/xtensa/include/asm/signal.h11
-rw-r--r--arch/xtensa/include/asm/syscall.h7
-rw-r--r--arch/xtensa/include/asm/unistd.h2
-rw-r--r--arch/xtensa/include/uapi/asm/socket.h4
-rw-r--r--arch/xtensa/include/uapi/asm/unistd.h2
-rw-r--r--arch/xtensa/kernel/signal.c18
-rw-r--r--arch/xtensa/kernel/traps.c2
-rw-r--r--arch/xtensa/platforms/iss/console.c10
-rw-r--r--block/blk-core.c8
-rw-r--r--block/blk-exec.c1
-rw-r--r--block/blk-integrity.c4
-rw-r--r--block/elevator.c35
-rw-r--r--block/genhd.c52
-rw-r--r--crypto/Kconfig43
-rw-r--r--crypto/Makefile1
-rw-r--r--crypto/ablkcipher.c12
-rw-r--r--crypto/aead.c15
-rw-r--r--crypto/ahash.c2
-rw-r--r--crypto/algapi.c4
-rw-r--r--crypto/authenc.c3
-rw-r--r--crypto/authencesn.c3
-rw-r--r--crypto/blkcipher.c12
-rw-r--r--crypto/ccm.c23
-rw-r--r--crypto/chainiv.c3
-rw-r--r--crypto/crc32.c158
-rw-r--r--crypto/crypto_user.c38
-rw-r--r--crypto/ctr.c173
-rw-r--r--crypto/cts.c3
-rw-r--r--crypto/gcm.c29
-rw-r--r--crypto/pcompress.c3
-rw-r--r--crypto/rng.c2
-rw-r--r--crypto/seqiv.c3
-rw-r--r--crypto/shash.c3
-rw-r--r--crypto/tcrypt.c4
-rw-r--r--crypto/tcrypt.h1
-rw-r--r--crypto/testmgr.c15
-rw-r--r--drivers/Kconfig4
-rw-r--r--drivers/Makefile4
-rw-r--r--drivers/acpi/Kconfig9
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/ac.c4
-rw-r--r--drivers/acpi/acpi_memhotplug.c90
-rw-r--r--drivers/acpi/acpi_pad.c3
-rw-r--r--drivers/acpi/acpi_platform.c72
-rw-r--r--drivers/acpi/acpica/Makefile8
-rw-r--r--drivers/acpi/acpica/accommon.h3
-rw-r--r--drivers/acpi/acpica/acdebug.h19
-rw-r--r--drivers/acpi/acpica/acdispat.h2
-rw-r--r--drivers/acpi/acpica/acevents.h23
-rw-r--r--drivers/acpi/acpica/acglobal.h43
-rw-r--r--drivers/acpi/acpica/achware.h2
-rw-r--r--drivers/acpi/acpica/acinterp.h4
-rw-r--r--drivers/acpi/acpica/aclocal.h47
-rw-r--r--drivers/acpi/acpica/acmacros.h173
-rw-r--r--drivers/acpi/acpica/acnamesp.h16
-rw-r--r--drivers/acpi/acpica/acobject.h4
-rw-r--r--drivers/acpi/acpica/acopcode.h2
-rw-r--r--drivers/acpi/acpica/acparser.h27
-rw-r--r--drivers/acpi/acpica/acpredef.h31
-rw-r--r--drivers/acpi/acpica/acresrc.h8
-rw-r--r--drivers/acpi/acpica/acstruct.h2
-rw-r--r--drivers/acpi/acpica/actables.h2
-rw-r--r--drivers/acpi/acpica/acutils.h59
-rw-r--r--drivers/acpi/acpica/amlcode.h2
-rw-r--r--drivers/acpi/acpica/amlresrc.h8
-rw-r--r--drivers/acpi/acpica/dsargs.c2
-rw-r--r--drivers/acpi/acpica/dscontrol.c2
-rw-r--r--drivers/acpi/acpica/dsfield.c2
-rw-r--r--drivers/acpi/acpica/dsinit.c2
-rw-r--r--drivers/acpi/acpica/dsmethod.c8
-rw-r--r--drivers/acpi/acpica/dsmthdat.c2
-rw-r--r--drivers/acpi/acpica/dsobject.c20
-rw-r--r--drivers/acpi/acpica/dsopcode.c16
-rw-r--r--drivers/acpi/acpica/dsutils.c12
-rw-r--r--drivers/acpi/acpica/dswexec.c6
-rw-r--r--drivers/acpi/acpica/dswload.c7
-rw-r--r--drivers/acpi/acpica/dswload2.c4
-rw-r--r--drivers/acpi/acpica/dswscope.c2
-rw-r--r--drivers/acpi/acpica/dswstate.c2
-rw-r--r--drivers/acpi/acpica/evevent.c2
-rw-r--r--drivers/acpi/acpica/evglock.c2
-rw-r--r--drivers/acpi/acpica/evgpe.c14
-rw-r--r--drivers/acpi/acpica/evgpeblk.c24
-rw-r--r--drivers/acpi/acpica/evgpeinit.c5
-rw-r--r--drivers/acpi/acpica/evgpeutil.c2
-rw-r--r--drivers/acpi/acpica/evhandler.c529
-rw-r--r--drivers/acpi/acpica/evmisc.c2
-rw-r--r--drivers/acpi/acpica/evregion.c584
-rw-r--r--drivers/acpi/acpica/evrgnini.c2
-rw-r--r--drivers/acpi/acpica/evsci.c6
-rw-r--r--drivers/acpi/acpica/evxface.c36
-rw-r--r--drivers/acpi/acpica/evxfevnt.c7
-rw-r--r--drivers/acpi/acpica/evxfgpe.c11
-rw-r--r--drivers/acpi/acpica/evxfregn.c2
-rw-r--r--drivers/acpi/acpica/exconfig.c22
-rw-r--r--drivers/acpi/acpica/exconvrt.c4
-rw-r--r--drivers/acpi/acpica/excreate.c2
-rw-r--r--drivers/acpi/acpica/exdebug.c2
-rw-r--r--drivers/acpi/acpica/exdump.c21
-rw-r--r--drivers/acpi/acpica/exfield.c2
-rw-r--r--drivers/acpi/acpica/exfldio.c3
-rw-r--r--drivers/acpi/acpica/exmisc.c2
-rw-r--r--drivers/acpi/acpica/exmutex.c5
-rw-r--r--drivers/acpi/acpica/exnames.c2
-rw-r--r--drivers/acpi/acpica/exoparg1.c10
-rw-r--r--drivers/acpi/acpica/exoparg2.c2
-rw-r--r--drivers/acpi/acpica/exoparg3.c2
-rw-r--r--drivers/acpi/acpica/exoparg6.c2
-rw-r--r--drivers/acpi/acpica/exprep.c6
-rw-r--r--drivers/acpi/acpica/exregion.c25
-rw-r--r--drivers/acpi/acpica/exresnte.c2
-rw-r--r--drivers/acpi/acpica/exresolv.c2
-rw-r--r--drivers/acpi/acpica/exresop.c2
-rw-r--r--drivers/acpi/acpica/exstore.c31
-rw-r--r--drivers/acpi/acpica/exstoren.c4
-rw-r--r--drivers/acpi/acpica/exstorob.c2
-rw-r--r--drivers/acpi/acpica/exsystem.c2
-rw-r--r--drivers/acpi/acpica/exutils.c24
-rw-r--r--drivers/acpi/acpica/hwacpi.c13
-rw-r--r--drivers/acpi/acpica/hwesleep.c3
-rw-r--r--drivers/acpi/acpica/hwgpe.c10
-rw-r--r--drivers/acpi/acpica/hwpci.c2
-rw-r--r--drivers/acpi/acpica/hwregs.c8
-rw-r--r--drivers/acpi/acpica/hwsleep.c8
-rw-r--r--drivers/acpi/acpica/hwtimer.c9
-rw-r--r--drivers/acpi/acpica/hwvalid.c20
-rw-r--r--drivers/acpi/acpica/hwxface.c137
-rw-r--r--drivers/acpi/acpica/hwxfsleep.c13
-rw-r--r--drivers/acpi/acpica/nsaccess.c2
-rw-r--r--drivers/acpi/acpica/nsalloc.c2
-rw-r--r--drivers/acpi/acpica/nsdump.c14
-rw-r--r--drivers/acpi/acpica/nsdumpdv.c3
-rw-r--r--drivers/acpi/acpica/nseval.c2
-rw-r--r--drivers/acpi/acpica/nsinit.c29
-rw-r--r--drivers/acpi/acpica/nsload.c2
-rw-r--r--drivers/acpi/acpica/nsnames.c5
-rw-r--r--drivers/acpi/acpica/nsobject.c2
-rw-r--r--drivers/acpi/acpica/nsparse.c2
-rw-r--r--drivers/acpi/acpica/nspredef.c586
-rw-r--r--drivers/acpi/acpica/nsprepkg.c621
-rw-r--r--drivers/acpi/acpica/nsrepair.c2
-rw-r--r--drivers/acpi/acpica/nsrepair2.c5
-rw-r--r--drivers/acpi/acpica/nssearch.c7
-rw-r--r--drivers/acpi/acpica/nsutils.c88
-rw-r--r--drivers/acpi/acpica/nswalk.c6
-rw-r--r--drivers/acpi/acpica/nsxfeval.c19
-rw-r--r--drivers/acpi/acpica/nsxfname.c20
-rw-r--r--drivers/acpi/acpica/nsxfobj.c2
-rw-r--r--drivers/acpi/acpica/psargs.c9
-rw-r--r--drivers/acpi/acpica/psloop.c623
-rw-r--r--drivers/acpi/acpica/psobject.c647
-rw-r--r--drivers/acpi/acpica/psopcode.c174
-rw-r--r--drivers/acpi/acpica/psopinfo.c223
-rw-r--r--drivers/acpi/acpica/psparse.c2
-rw-r--r--drivers/acpi/acpica/psscope.c2
-rw-r--r--drivers/acpi/acpica/pstree.c2
-rw-r--r--drivers/acpi/acpica/psutils.c10
-rw-r--r--drivers/acpi/acpica/pswalk.c2
-rw-r--r--drivers/acpi/acpica/psxface.c2
-rw-r--r--drivers/acpi/acpica/rsaddr.c2
-rw-r--r--drivers/acpi/acpica/rscalc.c8
-rw-r--r--drivers/acpi/acpica/rscreate.c9
-rw-r--r--drivers/acpi/acpica/rsdump.c424
-rw-r--r--drivers/acpi/acpica/rsdumpinfo.c454
-rw-r--r--drivers/acpi/acpica/rsinfo.c2
-rw-r--r--drivers/acpi/acpica/rsio.c2
-rw-r--r--drivers/acpi/acpica/rsirq.c40
-rw-r--r--drivers/acpi/acpica/rslist.c9
-rw-r--r--drivers/acpi/acpica/rsmemory.c8
-rw-r--r--drivers/acpi/acpica/rsmisc.c76
-rw-r--r--drivers/acpi/acpica/rsserial.c10
-rw-r--r--drivers/acpi/acpica/rsutils.c14
-rw-r--r--drivers/acpi/acpica/rsxface.c107
-rw-r--r--drivers/acpi/acpica/tbfadt.c7
-rw-r--r--drivers/acpi/acpica/tbfind.c2
-rw-r--r--drivers/acpi/acpica/tbinstal.c2
-rw-r--r--drivers/acpi/acpica/tbutils.c4
-rw-r--r--drivers/acpi/acpica/tbxface.c7
-rw-r--r--drivers/acpi/acpica/tbxfload.c4
-rw-r--r--drivers/acpi/acpica/tbxfroot.c2
-rw-r--r--drivers/acpi/acpica/utaddress.c6
-rw-r--r--drivers/acpi/acpica/utalloc.c2
-rw-r--r--drivers/acpi/acpica/utcache.c2
-rw-r--r--drivers/acpi/acpica/utcopy.c6
-rw-r--r--drivers/acpi/acpica/utdebug.c120
-rw-r--r--drivers/acpi/acpica/utdecode.c2
-rw-r--r--drivers/acpi/acpica/utdelete.c70
-rw-r--r--drivers/acpi/acpica/uteval.c4
-rw-r--r--drivers/acpi/acpica/utexcep.c2
-rw-r--r--drivers/acpi/acpica/utglobal.c11
-rw-r--r--drivers/acpi/acpica/utids.c2
-rw-r--r--drivers/acpi/acpica/utinit.c2
-rw-r--r--drivers/acpi/acpica/utlock.c16
-rw-r--r--drivers/acpi/acpica/utmath.c2
-rw-r--r--drivers/acpi/acpica/utmisc.c830
-rw-r--r--drivers/acpi/acpica/utmutex.c2
-rw-r--r--drivers/acpi/acpica/utobject.c4
-rw-r--r--drivers/acpi/acpica/utosi.c2
-rw-r--r--drivers/acpi/acpica/utownerid.c218
-rw-r--r--drivers/acpi/acpica/utresrc.c83
-rw-r--r--drivers/acpi/acpica/utstate.c42
-rw-r--r--drivers/acpi/acpica/utstring.c574
-rw-r--r--drivers/acpi/acpica/uttrack.c18
-rw-r--r--drivers/acpi/acpica/utxface.c6
-rw-r--r--drivers/acpi/acpica/utxferror.c6
-rw-r--r--drivers/acpi/acpica/utxfinit.c2
-rw-r--r--drivers/acpi/acpica/utxfmutex.c2
-rw-r--r--drivers/acpi/apei/cper.c19
-rw-r--r--drivers/acpi/battery.c2
-rw-r--r--drivers/acpi/bus.c270
-rw-r--r--drivers/acpi/button.c4
-rw-r--r--drivers/acpi/container.c211
-rw-r--r--drivers/acpi/csrt.c159
-rw-r--r--drivers/acpi/custom_method.c4
-rw-r--r--drivers/acpi/device_pm.c359
-rw-r--r--drivers/acpi/dock.c44
-rw-r--r--drivers/acpi/ec.c2
-rw-r--r--drivers/acpi/fan.c4
-rw-r--r--drivers/acpi/glue.c85
-rw-r--r--drivers/acpi/hed.c2
-rw-r--r--drivers/acpi/internal.h31
-rw-r--r--drivers/acpi/numa.c31
-rw-r--r--drivers/acpi/osl.c4
-rw-r--r--drivers/acpi/pci_bind.c122
-rw-r--r--drivers/acpi/pci_link.c47
-rw-r--r--drivers/acpi/pci_root.c101
-rw-r--r--drivers/acpi/pci_slot.c7
-rw-r--r--drivers/acpi/power.c730
-rw-r--r--drivers/acpi/proc.c9
-rw-r--r--drivers/acpi/processor_driver.c64
-rw-r--r--drivers/acpi/processor_idle.c48
-rw-r--r--drivers/acpi/sbs.c6
-rw-r--r--drivers/acpi/sbshc.c4
-rw-r--r--drivers/acpi/scan.c976
-rw-r--r--drivers/acpi/sleep.c97
-rw-r--r--drivers/acpi/sleep.h2
-rw-r--r--drivers/acpi/sysfs.c2
-rw-r--r--drivers/acpi/tables.c6
-rw-r--r--drivers/acpi/thermal.c10
-rw-r--r--drivers/acpi/video.c8
-rw-r--r--drivers/amba/tegra-ahb.c7
-rw-r--r--drivers/ata/Kconfig47
-rw-r--r--drivers/ata/Makefile2
-rw-r--r--drivers/ata/ahci.c117
-rw-r--r--drivers/ata/ahci.h6
-rw-r--r--drivers/ata/ata_piix.c17
-rw-r--r--drivers/ata/libahci.c118
-rw-r--r--drivers/ata/libata-acpi.c195
-rw-r--r--drivers/ata/libata-core.c66
-rw-r--r--drivers/ata/libata-eh.c27
-rw-r--r--drivers/ata/libata-scsi.c20
-rw-r--r--drivers/ata/libata-zpodd.c299
-rw-r--r--drivers/ata/libata.h27
-rw-r--r--drivers/ata/pata_ep93xx.c7
-rw-r--r--drivers/ata/pata_mpc52xx.c6
-rw-r--r--drivers/ata/pata_samsung_cf.c4
-rw-r--r--drivers/ata/sata_rcar.c910
-rw-r--r--drivers/atm/iphase.h146
-rw-r--r--drivers/base/Kconfig11
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/bus.c6
-rw-r--r--drivers/base/class.c4
-rw-r--r--drivers/base/core.c8
-rw-r--r--drivers/base/dd.c9
-rw-r--r--drivers/base/dma-buf.c9
-rw-r--r--drivers/base/firmware_class.c550
-rw-r--r--drivers/base/memory.c10
-rw-r--r--drivers/base/pinctrl.c69
-rw-r--r--drivers/base/power/domain.c3
-rw-r--r--drivers/base/power/opp.c19
-rw-r--r--drivers/base/power/qos.c1
-rw-r--r--drivers/base/power/runtime.c89
-rw-r--r--drivers/base/power/wakeup.c6
-rw-r--r--drivers/base/regmap/Makefile2
-rw-r--r--drivers/base/regmap/internal.h22
-rw-r--r--drivers/base/regmap/regcache-flat.c72
-rw-r--r--drivers/base/regmap/regcache.c1
-rw-r--r--drivers/base/regmap/regmap-debugfs.c52
-rw-r--r--drivers/base/regmap/regmap-irq.c125
-rw-r--r--drivers/base/regmap/regmap-mmio.c79
-rw-r--r--drivers/base/regmap/regmap-spi.c54
-rw-r--r--drivers/base/regmap/regmap.c351
-rw-r--r--drivers/bcma/bcma_private.h8
-rw-r--r--drivers/bcma/driver_chipcommon.c2
-rw-r--r--drivers/bcma/driver_chipcommon_nflash.c6
-rw-r--r--drivers/bcma/driver_chipcommon_pmu.c3
-rw-r--r--drivers/bcma/driver_chipcommon_sflash.c4
-rw-r--r--drivers/bcma/driver_gpio.c16
-rw-r--r--drivers/bcma/driver_mips.c195
-rw-r--r--drivers/bcma/driver_pci_host.c62
-rw-r--r--drivers/bcma/main.c19
-rw-r--r--drivers/block/drbd/drbd_req.c2
-rw-r--r--drivers/block/drbd/drbd_req.h1
-rw-r--r--drivers/block/drbd/drbd_state.c7
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c24
-rw-r--r--drivers/block/paride/Kconfig4
-rw-r--r--drivers/block/sunvdc.c2
-rw-r--r--drivers/block/swim.c1
-rw-r--r--drivers/block/xen-blkback/blkback.c18
-rw-r--r--drivers/block/xen-blkfront.c10
-rw-r--r--drivers/bluetooth/Kconfig1
-rw-r--r--drivers/bluetooth/ath3k.c2
-rw-r--r--drivers/char/Kconfig7
-rw-r--r--drivers/char/hpet.c2
-rw-r--r--drivers/char/hw_random/exynos-rng.c11
-rw-r--r--drivers/char/hw_random/omap-rng.c6
-rw-r--r--drivers/char/hw_random/tx4939-rng.c7
-rw-r--r--drivers/char/mem.c10
-rw-r--r--drivers/char/pcmcia/Kconfig4
-rw-r--r--drivers/char/pcmcia/synclink_cs.c707
-rw-r--r--drivers/char/random.c6
-rw-r--r--drivers/char/sonypi.c2
-rw-r--r--drivers/char/tpm/Kconfig12
-rw-r--r--drivers/char/tpm/Makefile1
-rw-r--r--drivers/char/tpm/tpm.c114
-rw-r--r--drivers/char/tpm/tpm.h52
-rw-r--r--drivers/char/tpm/tpm_acpi.c8
-rw-r--r--drivers/char/tpm/tpm_atmel.c7
-rw-r--r--drivers/char/tpm/tpm_i2c_infineon.c7
-rw-r--r--drivers/char/tpm/tpm_i2c_stm_st33.c887
-rw-r--r--drivers/char/tpm/tpm_i2c_stm_st33.h61
-rw-r--r--drivers/char/tpm/tpm_ibmvtpm.c15
-rw-r--r--drivers/char/tpm/tpm_nsc.c7
-rw-r--r--drivers/char/tpm/tpm_tis.c64
-rw-r--r--drivers/char/virtio_console.c3
-rw-r--r--drivers/clk/Makefile13
-rw-r--r--drivers/clk/clk-bcm2835.c9
-rw-r--r--drivers/clk/clk-divider.c6
-rw-r--r--drivers/clk/clk-fixed-factor.c5
-rw-r--r--drivers/clk/clk-fixed-rate.c3
-rw-r--r--drivers/clk/clk-highbank.c20
-rw-r--r--drivers/clk/clk-max77686.c37
-rw-r--r--drivers/clk/clk-prima2.c205
-rw-r--r--drivers/clk/clk-sunxi.c30
-rw-r--r--drivers/clk/clk-vt8500.c143
-rw-r--r--drivers/clk/clk-zynq.c14
-rw-r--r--drivers/clk/clk.c169
-rw-r--r--drivers/clk/mvebu/clk-gating-ctrl.c1
-rw-r--r--drivers/clk/mxs/clk-imx23.c2
-rw-r--r--drivers/clk/mxs/clk-imx28.c4
-rw-r--r--drivers/clk/tegra/Makefile11
-rw-r--r--drivers/clk/tegra/clk-audio-sync.c87
-rw-r--r--drivers/clk/tegra/clk-divider.c187
-rw-r--r--drivers/clk/tegra/clk-periph-gate.c179
-rw-r--r--drivers/clk/tegra/clk-periph.c218
-rw-r--r--drivers/clk/tegra/clk-pll-out.c123
-rw-r--r--drivers/clk/tegra/clk-pll.c648
-rw-r--r--drivers/clk/tegra/clk-super.c166
-rw-r--r--drivers/clk/tegra/clk-tegra20.c1355
-rw-r--r--drivers/clk/tegra/clk-tegra30.c1994
-rw-r--r--drivers/clk/tegra/clk.c85
-rw-r--r--drivers/clk/tegra/clk.h502
-rw-r--r--drivers/clk/versatile/clk-vexpress-osc.c1
-rw-r--r--drivers/clk/versatile/clk-vexpress.c11
-rw-r--r--drivers/clk/x86/Makefile2
-rw-r--r--drivers/clk/x86/clk-lpss.c99
-rw-r--r--drivers/clk/x86/clk-lpss.h36
-rw-r--r--drivers/clk/x86/clk-lpt.c86
-rw-r--r--drivers/clocksource/Kconfig12
-rw-r--r--drivers/clocksource/Makefile5
-rw-r--r--drivers/clocksource/arm_arch_timer.c391
-rw-r--r--drivers/clocksource/arm_generic.c232
-rw-r--r--drivers/clocksource/bcm2835_timer.c9
-rw-r--r--drivers/clocksource/clksrc-of.c35
-rw-r--r--drivers/clocksource/cs5535-clockevt.c11
-rw-r--r--drivers/clocksource/dw_apb_timer_of.c6
-rw-r--r--drivers/clocksource/nomadik-mtu.c44
-rw-r--r--drivers/clocksource/sunxi_timer.c21
-rw-r--r--drivers/clocksource/tcb_clksrc.c7
-rw-r--r--drivers/clocksource/tegra20_timer.c (renamed from arch/arm/mach-tegra/timer.c)21
-rw-r--r--drivers/clocksource/vt8500_timer.c (renamed from arch/arm/mach-vt8500/timer.c)12
-rw-r--r--drivers/connector/connector.c4
-rw-r--r--drivers/cpufreq/Kconfig2
-rw-r--r--drivers/cpufreq/Kconfig.arm34
-rw-r--r--drivers/cpufreq/Kconfig.x8619
-rw-r--r--drivers/cpufreq/Makefile13
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c8
-rw-r--r--drivers/cpufreq/cpufreq-cpu0.c42
-rw-r--r--drivers/cpufreq/cpufreq.c460
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c19
-rw-r--r--drivers/cpufreq/cpufreq_governor.c131
-rw-r--r--drivers/cpufreq/cpufreq_governor.h6
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c70
-rw-r--r--drivers/cpufreq/cpufreq_stats.c49
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c2
-rw-r--r--drivers/cpufreq/dbx500-cpufreq.c (renamed from drivers/cpufreq/db8500-cpufreq.c)109
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c192
-rw-r--r--drivers/cpufreq/exynos-cpufreq.h (renamed from arch/arm/mach-exynos/include/mach/cpufreq.h)22
-rw-r--r--drivers/cpufreq/exynos4210-cpufreq.c153
-rw-r--r--drivers/cpufreq/exynos4x12-cpufreq.c389
-rw-r--r--drivers/cpufreq/exynos5250-cpufreq.c179
-rw-r--r--drivers/cpufreq/freq_table.c15
-rw-r--r--drivers/cpufreq/highbank-cpufreq.c120
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c336
-rw-r--r--drivers/cpufreq/intel_pstate.c823
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c259
-rw-r--r--drivers/cpufreq/maple-cpufreq.c2
-rw-r--r--drivers/cpufreq/omap-cpufreq.c4
-rw-r--r--drivers/cpufreq/powernow-k8.c46
-rw-r--r--drivers/cpufreq/spear-cpufreq.c12
-rw-r--r--drivers/cpuidle/Kconfig6
-rw-r--r--drivers/cpuidle/Makefile1
-rw-r--r--drivers/cpuidle/cpuidle-kirkwood.c (renamed from arch/arm/mach-kirkwood/cpuidle.c)45
-rw-r--r--drivers/cpuidle/cpuidle.c2
-rw-r--r--drivers/crypto/atmel-aes.c2
-rw-r--r--drivers/crypto/bfin_crc.c6
-rw-r--r--drivers/crypto/omap-aes.c658
-rw-r--r--drivers/crypto/omap-sham.c915
-rw-r--r--drivers/crypto/s5p-sss.c4
-rw-r--r--drivers/devfreq/exynos4_bus.c2
-rw-r--r--drivers/dma/Kconfig2
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/bestcomm/Kconfig (renamed from arch/powerpc/sysdev/bestcomm/Kconfig)0
-rw-r--r--drivers/dma/bestcomm/Makefile (renamed from arch/powerpc/sysdev/bestcomm/Makefile)0
-rw-r--r--drivers/dma/bestcomm/ata.c (renamed from arch/powerpc/sysdev/bestcomm/ata.c)6
-rw-r--r--drivers/dma/bestcomm/bcom_ata_task.c (renamed from arch/powerpc/sysdev/bestcomm/bcom_ata_task.c)0
-rw-r--r--drivers/dma/bestcomm/bcom_fec_rx_task.c (renamed from arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c)0
-rw-r--r--drivers/dma/bestcomm/bcom_fec_tx_task.c (renamed from arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c)0
-rw-r--r--drivers/dma/bestcomm/bcom_gen_bd_rx_task.c (renamed from arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c)0
-rw-r--r--drivers/dma/bestcomm/bcom_gen_bd_tx_task.c (renamed from arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c)0
-rw-r--r--drivers/dma/bestcomm/bestcomm.c (renamed from arch/powerpc/sysdev/bestcomm/bestcomm.c)8
-rw-r--r--drivers/dma/bestcomm/fec.c (renamed from arch/powerpc/sysdev/bestcomm/fec.c)6
-rw-r--r--drivers/dma/bestcomm/gen_bd.c (renamed from arch/powerpc/sysdev/bestcomm/gen_bd.c)6
-rw-r--r--drivers/dma/bestcomm/sram.c (renamed from arch/powerpc/sysdev/bestcomm/sram.c)2
-rw-r--r--drivers/dma/coh901318.c1302
-rw-r--r--drivers/dma/coh901318.h (renamed from drivers/dma/coh901318_lli.h)35
-rw-r--r--drivers/dma/coh901318_lli.c4
-rw-r--r--drivers/dma/dw_dmac.c7
-rw-r--r--drivers/dma/imx-dma.c7
-rw-r--r--drivers/dma/mmp_pdma.c7
-rw-r--r--drivers/dma/mmp_tdma.c7
-rw-r--r--drivers/dma/omap-dma.c20
-rw-r--r--drivers/dma/tegra20-apb-dma.c12
-rw-r--r--drivers/edac/Kconfig4
-rw-r--r--drivers/edac/amd64_edac.c214
-rw-r--r--drivers/edac/amd64_edac.h12
-rw-r--r--drivers/edac/mce_amd.c166
-rw-r--r--drivers/edac/mce_amd.h13
-rw-r--r--drivers/edac/mpc85xx_edac.c4
-rw-r--r--drivers/extcon/Kconfig4
-rw-r--r--drivers/extcon/extcon-adc-jack.c3
-rw-r--r--drivers/extcon/extcon-arizona.c810
-rw-r--r--drivers/extcon/extcon-gpio.c2
-rw-r--r--drivers/extcon/extcon-max77693.c981
-rw-r--r--drivers/extcon/extcon-max8997.c734
-rw-r--r--drivers/firewire/net.c14
-rw-r--r--drivers/firewire/ohci.c2
-rw-r--r--drivers/firmware/efivars.c180
-rw-r--r--drivers/firmware/memmap.c196
-rw-r--r--drivers/gpio/Kconfig15
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/gpio-ab8500.c520
-rw-r--r--drivers/gpio/gpio-mvebu.c18
-rw-r--r--drivers/gpio/gpio-mxs.c9
-rw-r--r--drivers/gpio/gpio-palmas.c184
-rw-r--r--drivers/gpio/gpio-samsung.c7
-rw-r--r--drivers/gpio/gpio-spear-spics.c8
-rw-r--r--drivers/gpio/gpio-stp-xway.c9
-rw-r--r--drivers/gpio/gpio-tegra.c9
-rw-r--r--drivers/gpio/gpiolib-of.c37
-rw-r--r--drivers/gpio/gpiolib.c2
-rw-r--r--drivers/gpu/drm/ast/Kconfig2
-rw-r--r--drivers/gpu/drm/cirrus/Kconfig2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c8
-rw-r--r--drivers/gpu/drm/gma500/Kconfig2
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_dp.c1
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c2
-rw-r--r--drivers/gpu/drm/mgag200/Kconfig2
-rw-r--r--drivers/gpu/drm/nouveau/core/core/falcon.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/core/subdev.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/object.h7
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/base.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c3
-rw-r--r--drivers/gpu/drm/omapdrm/Kconfig2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_connector.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c5
-rw-r--r--drivers/gpu/drm/omapdrm/omap_dmm_tiler.c13
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_encoder.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fb.c1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.c10
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.c4
-rw-r--r--drivers/gpu/drm/radeon/evergreen_cs.c100
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c38
-rw-r--r--drivers/gpu/drm/tegra/dc.c11
-rw-r--r--drivers/gpu/drm/tegra/drm.c1
-rw-r--r--drivers/gpu/drm/tegra/hdmi.c9
-rw-r--r--drivers/gpu/drm/tegra/host1x.c6
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c13
-rw-r--r--drivers/gpu/drm/udl/Kconfig2
-rw-r--r--drivers/hid/Kconfig20
-rw-r--r--drivers/hid/Makefile2
-rw-r--r--drivers/hid/hid-a4tech.c13
-rw-r--r--drivers/hid/hid-apple.c19
-rw-r--r--drivers/hid/hid-aureal.c13
-rw-r--r--drivers/hid/hid-axff.c14
-rw-r--r--drivers/hid/hid-belkin.c13
-rw-r--r--drivers/hid/hid-cherry.c13
-rw-r--r--drivers/hid/hid-chicony.c13
-rw-r--r--drivers/hid/hid-core.c18
-rw-r--r--drivers/hid/hid-cypress.c13
-rw-r--r--drivers/hid/hid-dr.c13
-rw-r--r--drivers/hid/hid-elecom.c13
-rw-r--r--drivers/hid/hid-emsff.c13
-rw-r--r--drivers/hid/hid-ezkey.c13
-rw-r--r--drivers/hid/hid-gaff.c13
-rw-r--r--drivers/hid/hid-generic.c14
-rw-r--r--drivers/hid/hid-gyration.c13
-rw-r--r--drivers/hid/hid-holtek-kbd.c13
-rw-r--r--drivers/hid/hid-holtekff.c15
-rw-r--r--drivers/hid/hid-hyperv.c3
-rw-r--r--drivers/hid/hid-icade.c19
-rw-r--r--drivers/hid/hid-ids.h24
-rw-r--r--drivers/hid/hid-kensington.c13
-rw-r--r--drivers/hid/hid-keytouch.c13
-rw-r--r--drivers/hid/hid-kye.c13
-rw-r--r--drivers/hid/hid-lcpower.c13
-rw-r--r--drivers/hid/hid-lenovo-tpkbd.c14
-rw-r--r--drivers/hid/hid-lg.c212
-rw-r--r--drivers/hid/hid-lg4ff.c17
-rw-r--r--drivers/hid/hid-magicmouse.c19
-rw-r--r--drivers/hid/hid-microsoft.c13
-rw-r--r--drivers/hid/hid-monterey.c13
-rw-r--r--drivers/hid/hid-multitouch.c163
-rw-r--r--drivers/hid/hid-ntrig.c81
-rw-r--r--drivers/hid/hid-ortek.c13
-rw-r--r--drivers/hid/hid-petalynx.c13
-rw-r--r--drivers/hid/hid-picolcd_core.c13
-rw-r--r--drivers/hid/hid-pl.c26
-rw-r--r--drivers/hid/hid-primax.c13
-rw-r--r--drivers/hid/hid-prodikeys.c19
-rw-r--r--drivers/hid/hid-ps3remote.c13
-rw-r--r--drivers/hid/hid-roccat-lua.c14
-rw-r--r--drivers/hid/hid-saitek.c13
-rw-r--r--drivers/hid/hid-samsung.c13
-rw-r--r--drivers/hid/hid-sensor-hub.c22
-rw-r--r--drivers/hid/hid-sjoy.c13
-rw-r--r--drivers/hid/hid-sony.c59
-rw-r--r--drivers/hid/hid-speedlink.c13
-rw-r--r--drivers/hid/hid-steelseries.c393
-rw-r--r--drivers/hid/hid-sunplus.c13
-rw-r--r--drivers/hid/hid-thingm.c272
-rw-r--r--drivers/hid/hid-tivo.c13
-rw-r--r--drivers/hid/hid-tmff.c13
-rw-r--r--drivers/hid/hid-topseed.c13
-rw-r--r--drivers/hid/hid-twinhan.c13
-rw-r--r--drivers/hid/hid-uclogic.c13
-rw-r--r--drivers/hid/hid-wacom.c18
-rw-r--r--drivers/hid/hid-waltop.c13
-rw-r--r--drivers/hid/hid-wiimote-core.c19
-rw-r--r--drivers/hid/hid-wiimote-debug.c2
-rw-r--r--drivers/hid/hid-wiimote-ext.c8
-rw-r--r--drivers/hid/hid-zpff.c13
-rw-r--r--drivers/hid/hid-zydacron.c13
-rw-r--r--drivers/hid/hidraw.c1
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c87
-rw-r--r--drivers/hid/uhid.c95
-rw-r--r--drivers/hv/Kconfig2
-rw-r--r--drivers/hv/channel.c33
-rw-r--r--drivers/hv/channel_mgmt.c93
-rw-r--r--drivers/hv/connection.c232
-rw-r--r--drivers/hv/hv.c72
-rw-r--r--drivers/hv/hv_balloon.c63
-rw-r--r--drivers/hv/hv_util.c46
-rw-r--r--drivers/hv/hyperv_vmbus.h65
-rw-r--r--drivers/hv/ring_buffer.c130
-rw-r--r--drivers/hv/vmbus_drv.c54
-rw-r--r--drivers/hwmon/Kconfig32
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/acpi_power_meter.c2
-rw-r--r--drivers/hwmon/ad7414.c2
-rw-r--r--drivers/hwmon/adm1021.c4
-rw-r--r--drivers/hwmon/adm1026.c16
-rw-r--r--drivers/hwmon/adm1031.c12
-rw-r--r--drivers/hwmon/adm9240.c6
-rw-r--r--drivers/hwmon/ads7828.c6
-rw-r--r--drivers/hwmon/adt7410.c28
-rw-r--r--drivers/hwmon/adt7462.c20
-rw-r--r--drivers/hwmon/adt7470.c20
-rw-r--r--drivers/hwmon/adt7475.c18
-rw-r--r--drivers/hwmon/amc6821.c32
-rw-r--r--drivers/hwmon/asb100.c10
-rw-r--r--drivers/hwmon/asc7621.c26
-rw-r--r--drivers/hwmon/asus_atk0110.c4
-rw-r--r--drivers/hwmon/coretemp.c5
-rw-r--r--drivers/hwmon/dme1737.c15
-rw-r--r--drivers/hwmon/emc2103.c2
-rw-r--r--drivers/hwmon/emc6w201.c6
-rw-r--r--drivers/hwmon/f71882fg.c25
-rw-r--r--drivers/hwmon/f75375s.c12
-rw-r--r--drivers/hwmon/fschmd.c4
-rw-r--r--drivers/hwmon/g760a.c2
-rw-r--r--drivers/hwmon/gl518sm.c10
-rw-r--r--drivers/hwmon/gl520sm.c9
-rw-r--r--drivers/hwmon/gpio-fan.c4
-rw-r--r--drivers/hwmon/ina209.c636
-rw-r--r--drivers/hwmon/it87.c52
-rw-r--r--drivers/hwmon/jc42.c10
-rw-r--r--drivers/hwmon/lm63.c8
-rw-r--r--drivers/hwmon/lm73.c136
-rw-r--r--drivers/hwmon/lm75.h2
-rw-r--r--drivers/hwmon/lm77.c2
-rw-r--r--drivers/hwmon/lm78.c6
-rw-r--r--drivers/hwmon/lm80.c8
-rw-r--r--drivers/hwmon/lm85.c10
-rw-r--r--drivers/hwmon/lm90.c2
-rw-r--r--drivers/hwmon/lm93.c28
-rw-r--r--drivers/hwmon/lm95245.c4
-rw-r--r--drivers/hwmon/max16065.c2
-rw-r--r--drivers/hwmon/max1668.c4
-rw-r--r--drivers/hwmon/max6639.c4
-rw-r--r--drivers/hwmon/max6642.c2
-rw-r--r--drivers/hwmon/max6650.c4
-rw-r--r--drivers/hwmon/max6697.c726
-rw-r--r--drivers/hwmon/ntc_thermistor.c4
-rw-r--r--drivers/hwmon/pmbus/Kconfig2
-rw-r--r--drivers/hwmon/pmbus/max34440.c75
-rw-r--r--drivers/hwmon/pmbus/pmbus.h11
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c840
-rw-r--r--drivers/hwmon/pmbus/zl6100.c176
-rw-r--r--drivers/hwmon/sht15.c157
-rw-r--r--drivers/hwmon/sis5595.c6
-rw-r--r--drivers/hwmon/smsc47m1.c2
-rw-r--r--drivers/hwmon/smsc47m192.c4
-rw-r--r--drivers/hwmon/thmc50.c6
-rw-r--r--drivers/hwmon/tmp102.c2
-rw-r--r--drivers/hwmon/tmp401.c14
-rw-r--r--drivers/hwmon/via686a.c17
-rw-r--r--drivers/hwmon/vt1211.c10
-rw-r--r--drivers/hwmon/vt8231.c22
-rw-r--r--drivers/hwmon/w83627ehf.c17
-rw-r--r--drivers/hwmon/w83627hf.c23
-rw-r--r--drivers/hwmon/w83781d.c17
-rw-r--r--drivers/hwmon/w83791d.c10
-rw-r--r--drivers/hwmon/w83792d.c25
-rw-r--r--drivers/hwmon/w83793.c18
-rw-r--r--drivers/hwmon/w83795.c28
-rw-r--r--drivers/hwmon/w83l786ng.c17
-rw-r--r--drivers/i2c/Kconfig2
-rw-r--r--drivers/i2c/busses/Kconfig17
-rw-r--r--drivers/i2c/busses/i2c-at91.c6
-rw-r--r--drivers/i2c/busses/i2c-imx.c6
-rw-r--r--drivers/i2c/busses/i2c-ocores.c7
-rw-r--r--drivers/i2c/busses/i2c-omap.c8
-rw-r--r--drivers/i2c/busses/i2c-rcar.c8
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c7
-rw-r--r--drivers/i2c/busses/i2c-scmi.c2
-rw-r--r--drivers/i2c/busses/i2c-sirf.c7
-rw-r--r--drivers/i2c/busses/i2c-stu300.c6
-rw-r--r--drivers/i2c/busses/i2c-tegra.c11
-rw-r--r--drivers/i2c/busses/i2c-xlr.c9
-rw-r--r--drivers/i2c/muxes/Kconfig2
-rw-r--r--drivers/ide/Kconfig13
-rw-r--r--drivers/idle/Kconfig1
-rw-r--r--drivers/idle/i7300_idle.c8
-rw-r--r--drivers/idle/intel_idle.c278
-rw-r--r--drivers/iio/accel/Kconfig38
-rw-r--r--drivers/iio/accel/Makefile9
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c3
-rw-r--r--drivers/iio/accel/kxsd9.c (renamed from drivers/staging/iio/accel/kxsd9.c)16
-rw-r--r--drivers/iio/accel/st_accel.h47
-rw-r--r--drivers/iio/accel/st_accel_buffer.c114
-rw-r--r--drivers/iio/accel/st_accel_core.c500
-rw-r--r--drivers/iio/accel/st_accel_i2c.c86
-rw-r--r--drivers/iio/accel/st_accel_spi.c85
-rw-r--r--drivers/iio/adc/Kconfig4
-rw-r--r--drivers/iio/adc/at91_adc.c6
-rw-r--r--drivers/iio/adc/lp8788_adc.c18
-rw-r--r--drivers/iio/adc/max1363.c167
-rw-r--r--drivers/iio/buffer_cb.c4
-rw-r--r--drivers/iio/common/Kconfig1
-rw-r--r--drivers/iio/common/Makefile1
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-attributes.c11
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-attributes.h57
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c5
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.h2
-rw-r--r--drivers/iio/common/st_sensors/Kconfig14
-rw-r--r--drivers/iio/common/st_sensors/Makefile10
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_buffer.c116
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c446
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_i2c.c81
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_spi.c128
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_trigger.c77
-rw-r--r--drivers/iio/dac/ad5360.c7
-rw-r--r--drivers/iio/dac/ad5421.c7
-rw-r--r--drivers/iio/dac/ad5504.c6
-rw-r--r--drivers/iio/dac/ad5686.c7
-rw-r--r--drivers/iio/dac/ad5755.c7
-rw-r--r--drivers/iio/dac/ad5764.c7
-rw-r--r--drivers/iio/dac/ad5791.c6
-rw-r--r--drivers/iio/frequency/ad9523.c14
-rw-r--r--drivers/iio/gyro/Kconfig55
-rw-r--r--drivers/iio/gyro/Makefile14
-rw-r--r--drivers/iio/gyro/adis16080.c (renamed from drivers/staging/iio/gyro/adis16080_core.c)154
-rw-r--r--drivers/iio/gyro/adxrs450.c (renamed from drivers/staging/iio/gyro/adxrs450_core.c)202
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c3
-rw-r--r--drivers/iio/gyro/itg3200_buffer.c156
-rw-r--r--drivers/iio/gyro/itg3200_core.c401
-rw-r--r--drivers/iio/gyro/st_gyro.h45
-rw-r--r--drivers/iio/gyro/st_gyro_buffer.c114
-rw-r--r--drivers/iio/gyro/st_gyro_core.c368
-rw-r--r--drivers/iio/gyro/st_gyro_i2c.c84
-rw-r--r--drivers/iio/gyro/st_gyro_spi.c83
-rw-r--r--drivers/iio/imu/Kconfig13
-rw-r--r--drivers/iio/imu/Makefile5
-rw-r--r--drivers/iio/imu/adis16400.h (renamed from drivers/staging/iio/imu/adis16400.h)141
-rw-r--r--drivers/iio/imu/adis16400_buffer.c96
-rw-r--r--drivers/iio/imu/adis16400_core.c965
-rw-r--r--drivers/iio/imu/inv_mpu6050/Kconfig13
-rw-r--r--drivers/iio/imu/inv_mpu6050/Makefile6
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c795
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h246
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c196
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c155
-rw-r--r--drivers/iio/industrialio-trigger.c12
-rw-r--r--drivers/iio/inkern.c53
-rw-r--r--drivers/iio/kfifo_buf.c1
-rw-r--r--drivers/iio/light/Kconfig10
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/hid-sensor-als.c3
-rw-r--r--drivers/iio/light/tsl2563.c (renamed from drivers/staging/iio/light/tsl2563.c)96
-rw-r--r--drivers/iio/magnetometer/Kconfig30
-rw-r--r--drivers/iio/magnetometer/Makefile7
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c3
-rw-r--r--drivers/iio/magnetometer/st_magn.h45
-rw-r--r--drivers/iio/magnetometer/st_magn_buffer.c98
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c400
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c80
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c79
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c2
-rw-r--r--drivers/infiniband/hw/nes/nes.c8
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c13
-rw-r--r--drivers/infiniband/hw/qib/qib_qp.c11
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c6
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ethtool.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c6
-rw-r--r--drivers/input/Kconfig2
-rw-r--r--drivers/input/input-mt.c1
-rw-r--r--drivers/input/input.c16
-rw-r--r--drivers/input/joystick/analog.c2
-rw-r--r--drivers/input/joystick/walkera0701.c82
-rw-r--r--drivers/input/keyboard/Kconfig16
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/atkbd.c74
-rw-r--r--drivers/input/keyboard/goldfish_events.c194
-rw-r--r--drivers/input/keyboard/imx_keypad.c43
-rw-r--r--drivers/input/keyboard/lm8323.c2
-rw-r--r--drivers/input/keyboard/matrix_keypad.c8
-rw-r--r--drivers/input/keyboard/qt2160.c141
-rw-r--r--drivers/input/keyboard/spear-keyboard.c8
-rw-r--r--drivers/input/keyboard/tegra-kbc.c480
-rw-r--r--drivers/input/misc/adxl34x.c7
-rw-r--r--drivers/input/misc/atlas_btns.c2
-rw-r--r--drivers/input/misc/bma150.c14
-rw-r--r--drivers/input/misc/max8925_onkey.c3
-rw-r--r--drivers/input/misc/twl4030-vibra.c45
-rw-r--r--drivers/input/misc/twl6040-vibra.c100
-rw-r--r--drivers/input/misc/wm831x-on.c4
-rw-r--r--drivers/input/mouse/Kconfig22
-rw-r--r--drivers/input/mouse/Makefile2
-rw-r--r--drivers/input/mouse/alps.c773
-rw-r--r--drivers/input/mouse/alps.h145
-rw-r--r--drivers/input/mouse/cyapa.c973
-rw-r--r--drivers/input/mouse/cypress_ps2.c725
-rw-r--r--drivers/input/mouse/cypress_ps2.h191
-rw-r--r--drivers/input/mouse/psmouse-base.c32
-rw-r--r--drivers/input/mouse/psmouse.h1
-rw-r--r--drivers/input/mouse/synaptics.c32
-rw-r--r--drivers/input/serio/Kconfig2
-rw-r--r--drivers/input/serio/arc_ps2.c7
-rw-r--r--drivers/input/tablet/wacom_sys.c6
-rw-r--r--drivers/input/tablet/wacom_wac.c192
-rw-r--r--drivers/input/tablet/wacom_wac.h2
-rw-r--r--drivers/input/touchscreen/Kconfig2
-rw-r--r--drivers/input/touchscreen/cyttsp_spi.c1
-rw-r--r--drivers/input/touchscreen/mms114.c54
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c2
-rw-r--r--drivers/input/touchscreen/tsc2005.c1
-rw-r--r--drivers/input/touchscreen/wm831x-ts.c4
-rw-r--r--drivers/iommu/Kconfig8
-rw-r--r--drivers/iommu/amd_iommu.c8
-rw-r--r--drivers/iommu/dmar.c2
-rw-r--r--drivers/iommu/intel-iommu.c2
-rw-r--r--drivers/iommu/intel_irq_remapping.c48
-rw-r--r--drivers/iommu/irq_remapping.c231
-rw-r--r--drivers/iommu/irq_remapping.h1
-rw-r--r--drivers/iommu/tegra-smmu.c7
-rw-r--r--drivers/ipack/devices/Kconfig2
-rw-r--r--drivers/ipack/devices/ipoctal.c130
-rw-r--r--drivers/irqchip/Kconfig27
-rw-r--r--drivers/irqchip/Makefile7
-rw-r--r--drivers/irqchip/exynos-combiner.c230
-rw-r--r--drivers/irqchip/irq-gic.c (renamed from arch/arm/common/gic.c)84
-rw-r--r--drivers/irqchip/irq-vic.c (renamed from arch/arm/common/vic.c)95
-rw-r--r--drivers/irqchip/irqchip.c30
-rw-r--r--drivers/irqchip/irqchip.h29
-rw-r--r--drivers/irqchip/spear-shirq.c5
-rw-r--r--drivers/isdn/Kconfig1
-rw-r--r--drivers/isdn/capi/Kconfig1
-rw-r--r--drivers/isdn/divert/divert_init.c33
-rw-r--r--drivers/isdn/divert/isdn_divert.c423
-rw-r--r--drivers/isdn/divert/isdn_divert.h28
-rw-r--r--drivers/isdn/gigaset/Kconfig1
-rw-r--r--drivers/isdn/gigaset/common.c31
-rw-r--r--drivers/isdn/gigaset/ev-layer.c124
-rw-r--r--drivers/isdn/gigaset/gigaset.h9
-rw-r--r--drivers/isdn/gigaset/interface.c60
-rw-r--r--drivers/isdn/hardware/eicon/divacapi.h6
-rw-r--r--drivers/isdn/hardware/eicon/pc.h4
-rw-r--r--drivers/isdn/hardware/mISDN/Kconfig1
-rw-r--r--drivers/isdn/hisax/Kconfig15
-rw-r--r--drivers/isdn/i4l/isdn_common.c14
-rw-r--r--drivers/isdn/i4l/isdn_common.h2
-rw-r--r--drivers/isdn/i4l/isdn_tty.c59
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.h1
-rw-r--r--drivers/isdn/mISDN/core.c4
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c2
-rw-r--r--drivers/isdn/mISDN/stack.c7
-rw-r--r--drivers/leds/Kconfig2
-rw-r--r--drivers/lguest/Kconfig2
-rw-r--r--drivers/macintosh/Kconfig2
-rw-r--r--drivers/macintosh/windfarm_pm112.c2
-rw-r--r--drivers/macintosh/windfarm_pm72.c2
-rw-r--r--drivers/macintosh/windfarm_rm31.c2
-rw-r--r--drivers/mailbox/Kconfig19
-rw-r--r--drivers/mailbox/Makefile1
-rw-r--r--drivers/mailbox/pl320-ipc.c199
-rw-r--r--drivers/md/persistent-data/dm-transaction-manager.c14
-rw-r--r--drivers/media/Kconfig26
-rw-r--r--drivers/media/common/Kconfig11
-rw-r--r--drivers/media/common/Makefile3
-rw-r--r--drivers/media/common/btcx-risc.c (renamed from drivers/media/i2c/btcx-risc.c)0
-rw-r--r--drivers/media/common/btcx-risc.h (renamed from drivers/media/i2c/btcx-risc.h)0
-rw-r--r--drivers/media/common/cx2341x.c (renamed from drivers/media/i2c/cx2341x.c)0
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c5
-rw-r--r--drivers/media/common/tveeprom.c (renamed from drivers/media/i2c/tveeprom.c)290
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h6
-rw-r--r--drivers/media/dvb-core/dvb_ca_en50221.c16
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c65
-rw-r--r--drivers/media/dvb-core/dvb_frontend.h10
-rw-r--r--drivers/media/dvb-core/dvb_net.c71
-rw-r--r--drivers/media/dvb-core/dvb_net.h1
-rw-r--r--drivers/media/dvb-core/dvbdev.c2
-rw-r--r--drivers/media/dvb-frontends/Kconfig7
-rw-r--r--drivers/media/dvb-frontends/Makefile1
-rw-r--r--drivers/media/dvb-frontends/af9033.c18
-rw-r--r--drivers/media/dvb-frontends/af9033.h1
-rw-r--r--drivers/media/dvb-frontends/af9033_priv.h132
-rw-r--r--drivers/media/dvb-frontends/bcm3510.h2
-rw-r--r--drivers/media/dvb-frontends/cx22700.h2
-rw-r--r--drivers/media/dvb-frontends/cx24110.h2
-rw-r--r--drivers/media/dvb-frontends/cx24116.c2
-rw-r--r--drivers/media/dvb-frontends/dib0070.h2
-rw-r--r--drivers/media/dvb-frontends/dib0090.h2
-rw-r--r--drivers/media/dvb-frontends/dib3000.h2
-rw-r--r--drivers/media/dvb-frontends/dib8000.h2
-rw-r--r--drivers/media/dvb-frontends/dib9000.h2
-rw-r--r--drivers/media/dvb-frontends/drxd_hard.c9
-rw-r--r--drivers/media/dvb-frontends/ds3000.c261
-rw-r--r--drivers/media/dvb-frontends/ds3000.h10
-rw-r--r--drivers/media/dvb-frontends/dvb-pll.h2
-rw-r--r--drivers/media/dvb-frontends/isl6405.h2
-rw-r--r--drivers/media/dvb-frontends/isl6421.h2
-rw-r--r--drivers/media/dvb-frontends/isl6423.h2
-rw-r--r--drivers/media/dvb-frontends/itd1000.h2
-rw-r--r--drivers/media/dvb-frontends/ix2505v.c2
-rw-r--r--drivers/media/dvb-frontends/l64781.h2
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.h2
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.c422
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.h6
-rw-r--r--drivers/media/dvb-frontends/mb86a16.h2
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.c1790
-rw-r--r--drivers/media/dvb-frontends/mt312.h2
-rw-r--r--drivers/media/dvb-frontends/mt352.h2
-rw-r--r--drivers/media/dvb-frontends/nxt200x.h2
-rw-r--r--drivers/media/dvb-frontends/nxt6000.h2
-rw-r--r--drivers/media/dvb-frontends/or51132.h2
-rw-r--r--drivers/media/dvb-frontends/or51211.c99
-rw-r--r--drivers/media/dvb-frontends/or51211.h2
-rw-r--r--drivers/media/dvb-frontends/s5h1420.h2
-rw-r--r--drivers/media/dvb-frontends/sp8870.h2
-rw-r--r--drivers/media/dvb-frontends/sp887x.h2
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.h2
-rw-r--r--drivers/media/dvb-frontends/stb6100.h2
-rw-r--r--drivers/media/dvb-frontends/stv0297.h2
-rw-r--r--drivers/media/dvb-frontends/stv0299.c2
-rw-r--r--drivers/media/dvb-frontends/stv0299.h2
-rw-r--r--drivers/media/dvb-frontends/stv0900_core.c40
-rw-r--r--drivers/media/dvb-frontends/stv0900_reg.h3
-rw-r--r--drivers/media/dvb-frontends/stv0900_sw.c7
-rw-r--r--drivers/media/dvb-frontends/stv090x.c141
-rw-r--r--drivers/media/dvb-frontends/stv090x.h2
-rw-r--r--drivers/media/dvb-frontends/stv6110x.h2
-rw-r--r--drivers/media/dvb-frontends/tda1002x.h5
-rw-r--r--drivers/media/dvb-frontends/tda1004x.h2
-rw-r--r--drivers/media/dvb-frontends/tda10071.c22
-rw-r--r--drivers/media/dvb-frontends/tda10071.h8
-rw-r--r--drivers/media/dvb-frontends/tda10086.h2
-rw-r--r--drivers/media/dvb-frontends/tda665x.h2
-rw-r--r--drivers/media/dvb-frontends/tda8083.h2
-rw-r--r--drivers/media/dvb-frontends/tda8261.h2
-rw-r--r--drivers/media/dvb-frontends/tda8261_cfg.h2
-rw-r--r--drivers/media/dvb-frontends/tda826x.h2
-rw-r--r--drivers/media/dvb-frontends/ts2020.c373
-rw-r--r--drivers/media/dvb-frontends/ts2020.h50
-rw-r--r--drivers/media/dvb-frontends/tua6100.h2
-rw-r--r--drivers/media/dvb-frontends/ves1820.h2
-rw-r--r--drivers/media/dvb-frontends/ves1x93.h2
-rw-r--r--drivers/media/dvb-frontends/zl10353.h2
-rw-r--r--drivers/media/i2c/Kconfig42
-rw-r--r--drivers/media/i2c/Makefile5
-rw-r--r--drivers/media/i2c/adv7180.c3
-rw-r--r--drivers/media/i2c/adv7343.c45
-rw-r--r--drivers/media/i2c/cx25840/cx25840-ir.c6
-rw-r--r--drivers/media/i2c/mt9v011.c223
-rw-r--r--drivers/media/i2c/noon010pc30.c7
-rw-r--r--drivers/media/i2c/ov7670.c589
-rw-r--r--drivers/media/i2c/ov9650.c1562
-rw-r--r--drivers/media/i2c/s5c73m3/Makefile2
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c1704
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c563
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-spi.c156
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3.h459
-rw-r--r--drivers/media/i2c/s5k6aa.c7
-rw-r--r--drivers/media/i2c/soc_camera/imx074.c27
-rw-r--r--drivers/media/i2c/soc_camera/mt9m001.c52
-rw-r--r--drivers/media/i2c/soc_camera/mt9m111.c36
-rw-r--r--drivers/media/i2c/soc_camera/mt9t031.c36
-rw-r--r--drivers/media/i2c/soc_camera/mt9t112.c45
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c45
-rw-r--r--drivers/media/i2c/soc_camera/ov2640.c29
-rw-r--r--drivers/media/i2c/soc_camera/ov5642.c31
-rw-r--r--drivers/media/i2c/soc_camera/ov6650.c30
-rw-r--r--drivers/media/i2c/soc_camera/ov772x.c36
-rw-r--r--drivers/media/i2c/soc_camera/ov9640.c27
-rw-r--r--drivers/media/i2c/soc_camera/ov9740.c29
-rw-r--r--drivers/media/i2c/soc_camera/rj54n1cb0c.c39
-rw-r--r--drivers/media/i2c/soc_camera/tw9910.c30
-rw-r--r--drivers/media/i2c/ths7303.c3
-rw-r--r--drivers/media/i2c/tvaudio.c238
-rw-r--r--drivers/media/i2c/tvp514x.c4
-rw-r--r--drivers/media/i2c/tvp5150.c7
-rw-r--r--drivers/media/i2c/tvp7002.c18
-rw-r--r--drivers/media/parport/Kconfig1
-rw-r--r--drivers/media/parport/bw-qcam.c165
-rw-r--r--drivers/media/pci/bt8xx/Makefile1
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c6
-rw-r--r--drivers/media/pci/bt8xx/bttv-i2c.c5
-rw-r--r--drivers/media/pci/bt8xx/dst_ca.c4
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-main.c2
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-pcm.h2
-rw-r--r--drivers/media/pci/cx18/cx18-i2c.c9
-rw-r--r--drivers/media/pci/cx18/cx18-vbi.c2
-rw-r--r--drivers/media/pci/cx23885/Kconfig3
-rw-r--r--drivers/media/pci/cx23885/Makefile1
-rw-r--r--drivers/media/pci/cx23885/cx23885-cards.c114
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c66
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.c9
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c20
-rw-r--r--drivers/media/pci/cx23885/cx23885.h2
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.c6
-rw-r--r--drivers/media/pci/cx25821/Kconfig2
-rw-r--r--drivers/media/pci/cx25821/Makefile1
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.c2
-rw-r--r--drivers/media/pci/cx88/Kconfig2
-rw-r--r--drivers/media/pci/cx88/Makefile1
-rw-r--r--drivers/media/pci/cx88/cx88-cards.c2
-rw-r--r--drivers/media/pci/cx88/cx88-core.c2
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c15
-rw-r--r--drivers/media/pci/cx88/cx88-i2c.c3
-rw-r--r--drivers/media/pci/cx88/cx88-vp3054-i2c.c3
-rw-r--r--drivers/media/pci/cx88/cx88-vp3054-i2c.h2
-rw-r--r--drivers/media/pci/cx88/cx88.h10
-rw-r--r--drivers/media/pci/dm1105/Kconfig1
-rw-r--r--drivers/media/pci/dm1105/dm1105.c11
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-main.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-pcm.h2
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-i2c.c14
-rw-r--r--drivers/media/pci/ivtv/ivtv-vbi.c4
-rw-r--r--drivers/media/pci/mantis/mantis_ca.c5
-rw-r--r--drivers/media/pci/meye/meye.c286
-rw-r--r--drivers/media/pci/meye/meye.h2
-rw-r--r--drivers/media/pci/ngene/ngene-cards.c9
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c17
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-dvb.c3
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c13
-rw-r--r--drivers/media/pci/saa7134/saa7134.h7
-rw-r--r--drivers/media/pci/saa7164/saa7164-encoder.c2
-rw-r--r--drivers/media/pci/sta2x11/Kconfig2
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c1073
-rw-r--r--drivers/media/pci/ttpci/Kconfig5
-rw-r--r--drivers/media/pci/ttpci/av7110.c12
-rw-r--r--drivers/media/pci/ttpci/av7110.h2
-rw-r--r--drivers/media/pci/ttpci/av7110_av.c8
-rw-r--r--drivers/media/pci/ttpci/av7110_ca.c24
-rw-r--r--drivers/media/pci/zoran/zoran_card.c3
-rw-r--r--drivers/media/pci/zoran/zoran_device.c4
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c2
-rw-r--r--drivers/media/platform/Kconfig19
-rw-r--r--drivers/media/platform/Makefile2
-rw-r--r--drivers/media/platform/blackfin/Kconfig7
-rw-r--r--drivers/media/platform/blackfin/Makefile4
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c189
-rw-r--r--drivers/media/platform/blackfin/ppi.c90
-rw-r--r--drivers/media/platform/coda.c32
-rw-r--r--drivers/media/platform/davinci/Kconfig22
-rw-r--r--drivers/media/platform/davinci/Makefile4
-rw-r--r--drivers/media/platform/davinci/dm355_ccdc.c2
-rw-r--r--drivers/media/platform/davinci/vpbe.c12
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c9
-rw-r--r--drivers/media/platform/davinci/vpbe_osd.c35
-rw-r--r--drivers/media/platform/davinci/vpbe_venc.c65
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c5
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c2
-rw-r--r--drivers/media/platform/davinci/vpif_display.c6
-rw-r--r--drivers/media/platform/davinci/vpss.c71
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c56
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.h5
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c34
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-regs.c6
-rw-r--r--drivers/media/platform/fsl-viu.c2
-rw-r--r--drivers/media/platform/m2m-deinterlace.c6
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c84
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.h17
-rw-r--r--drivers/media/platform/mx2_emmaprp.c6
-rw-r--r--drivers/media/platform/omap/Kconfig2
-rw-r--r--drivers/media/platform/omap/omap_vout.c36
-rw-r--r--drivers/media/platform/omap24xxcam.c2
-rw-r--r--drivers/media/platform/omap3isp/isp.c74
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c8
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.c13
-rw-r--r--drivers/media/platform/omap3isp/isph3a_aewb.c28
-rw-r--r--drivers/media/platform/omap3isp/isph3a_af.c28
-rw-r--r--drivers/media/platform/omap3isp/isphist.c21
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c40
-rw-r--r--drivers/media/platform/omap3isp/ispqueue.c5
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.c9
-rw-r--r--drivers/media/platform/s5p-fimc/Kconfig1
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-capture.c190
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-core.c173
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-core.h17
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite-reg.c16
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite-reg.h4
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite.c200
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite.h9
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-m2m.c136
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-mdevice.c400
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-mdevice.h14
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-reg.c82
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-reg.h10
-rw-r--r--drivers/media/platform/s5p-fimc/mipi-csis.c109
-rw-r--r--drivers/media/platform/s5p-g2d/g2d-hw.c16
-rw-r--r--drivers/media/platform/s5p-g2d/g2d-regs.h7
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c43
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.h17
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c8
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.h2
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c173
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_common.h31
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c149
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h3
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c15
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c2
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.c30
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.h5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c197
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c148
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_pm.c2
-rw-r--r--drivers/media/platform/s5p-tv/Kconfig3
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c18
-rw-r--r--drivers/media/platform/s5p-tv/hdmiphy_drv.c2
-rw-r--r--drivers/media/platform/s5p-tv/mixer.h1
-rw-r--r--drivers/media/platform/s5p-tv/mixer_drv.c14
-rw-r--r--drivers/media/platform/s5p-tv/mixer_reg.c6
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c19
-rw-r--r--drivers/media/platform/s5p-tv/sdo_drv.c29
-rw-r--r--drivers/media/platform/s5p-tv/sii9234_drv.c6
-rw-r--r--drivers/media/platform/sh_veu.c1266
-rw-r--r--drivers/media/platform/sh_vou.c123
-rw-r--r--drivers/media/platform/soc_camera/Kconfig7
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c6
-rw-r--r--drivers/media/platform/soc_camera/mx1_camera.c5
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c543
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c6
-rw-r--r--drivers/media/platform/soc_camera/omap1_camera.c6
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c73
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c44
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_csi2.c23
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c172
-rw-r--r--drivers/media/platform/soc_camera/soc_camera_platform.c6
-rw-r--r--drivers/media/platform/soc_camera/soc_mediabus.c6
-rw-r--r--drivers/media/platform/timblogiw.c2
-rw-r--r--drivers/media/platform/via-camera.c60
-rw-r--r--drivers/media/platform/vino.c11
-rw-r--r--drivers/media/platform/vivi.c224
-rw-r--r--drivers/media/radio/Kconfig14
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/radio-ma901.c460
-rw-r--r--drivers/media/radio/radio-miropcm20.c173
-rw-r--r--drivers/media/radio/radio-wl1273.c3
-rw-r--r--drivers/media/radio/si470x/radio-si470x.h4
-rw-r--r--drivers/media/radio/wl128x/Kconfig2
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c3
-rw-r--r--drivers/media/rc/Kconfig2
-rw-r--r--drivers/media/rc/ati_remote.c27
-rw-r--r--drivers/media/rc/ene_ir.c28
-rw-r--r--drivers/media/rc/fintek-cir.c24
-rw-r--r--drivers/media/rc/gpio-ir-recv.c55
-rw-r--r--drivers/media/rc/iguanair.c26
-rw-r--r--drivers/media/rc/imon.c4
-rw-r--r--drivers/media/rc/ir-raw.c17
-rw-r--r--drivers/media/rc/ite-cir.c26
-rw-r--r--drivers/media/rc/keymaps/Makefile1
-rw-r--r--drivers/media/rc/keymaps/rc-total-media-in-hand-02.c86
-rw-r--r--drivers/media/rc/mceusb.c37
-rw-r--r--drivers/media/rc/nuvoton-cir.c41
-rw-r--r--drivers/media/rc/rc-core-priv.h16
-rw-r--r--drivers/media/rc/rc-main.c7
-rw-r--r--drivers/media/rc/redrat3.c18
-rw-r--r--drivers/media/rc/ttusbir.c10
-rw-r--r--drivers/media/rc/winbond-cir.c41
-rw-r--r--drivers/media/tuners/fc0011.c19
-rw-r--r--drivers/media/tuners/fc0012-priv.h13
-rw-r--r--drivers/media/tuners/fc0012.c113
-rw-r--r--drivers/media/tuners/fc0012.h32
-rw-r--r--drivers/media/tuners/mt2060.h2
-rw-r--r--drivers/media/tuners/mt2063.h2
-rw-r--r--drivers/media/tuners/mt20xx.h2
-rw-r--r--drivers/media/tuners/mt2131.h2
-rw-r--r--drivers/media/tuners/mt2266.h2
-rw-r--r--drivers/media/tuners/mxl5007t.h2
-rw-r--r--drivers/media/tuners/qt1010.h2
-rw-r--r--drivers/media/tuners/tda18212.c6
-rw-r--r--drivers/media/tuners/tda18218.c6
-rw-r--r--drivers/media/tuners/tda18271-fe.c2
-rw-r--r--drivers/media/tuners/tda18271-maps.c6
-rw-r--r--drivers/media/tuners/tda18271.h2
-rw-r--r--drivers/media/tuners/tda827x.h2
-rw-r--r--drivers/media/tuners/tda8290.h2
-rw-r--r--drivers/media/tuners/tda9887.h2
-rw-r--r--drivers/media/tuners/tea5761.h2
-rw-r--r--drivers/media/tuners/tea5767.h2
-rw-r--r--drivers/media/tuners/tuner-simple.h2
-rw-r--r--drivers/media/tuners/tuner-xc2028.c2
-rw-r--r--drivers/media/tuners/tuner-xc2028.h2
-rw-r--r--drivers/media/tuners/xc4000.c2
-rw-r--r--drivers/media/tuners/xc4000.h2
-rw-r--r--drivers/media/tuners/xc5000.c1
-rw-r--r--drivers/media/usb/Kconfig2
-rw-r--r--drivers/media/usb/au0828/Kconfig17
-rw-r--r--drivers/media/usb/au0828/Makefile6
-rw-r--r--drivers/media/usb/au0828/au0828-cards.c24
-rw-r--r--drivers/media/usb/au0828/au0828-core.c13
-rw-r--r--drivers/media/usb/au0828/au0828-i2c.c13
-rw-r--r--drivers/media/usb/au0828/au0828-video.c4
-rw-r--r--drivers/media/usb/au0828/au0828.h2
-rw-r--r--drivers/media/usb/cpia2/cpia2_usb.c2
-rw-r--r--drivers/media/usb/cpia2/cpia2_v4l.c5
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c4
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c31
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c6
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h1
-rw-r--r--drivers/media/usb/dvb-usb-v2/Kconfig6
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c289
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.h3
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/az6007.c26
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb.h3
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c15
-rw-r--r--drivers/media/usb/dvb-usb-v2/it913x.c54
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c38
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c30
-rw-r--r--drivers/media/usb/dvb-usb/Kconfig8
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_core.c5
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-init.c60
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c179
-rw-r--r--drivers/media/usb/dvb-usb/friio-fe.c5
-rw-r--r--drivers/media/usb/dvb-usb/m920x.c277
-rw-r--r--drivers/media/usb/dvb-usb/ttusb2.c8
-rw-r--r--drivers/media/usb/em28xx/Kconfig8
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c270
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c296
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c96
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c293
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c359
-rw-r--r--drivers/media/usb/em28xx/em28xx-reg.h5
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c123
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c1689
-rw-r--r--drivers/media/usb/em28xx/em28xx.h149
-rw-r--r--drivers/media/usb/gspca/cpia1.c6
-rw-r--r--drivers/media/usb/gspca/gspca.c10
-rw-r--r--drivers/media/usb/gspca/gspca.h6
-rw-r--r--drivers/media/usb/gspca/jl2005bcd.c18
-rw-r--r--drivers/media/usb/gspca/konica.c6
-rw-r--r--drivers/media/usb/gspca/ov519.c6
-rw-r--r--drivers/media/usb/gspca/pac207.c36
-rw-r--r--drivers/media/usb/gspca/pac7302.c4
-rw-r--r--drivers/media/usb/gspca/pac7311.c4
-rw-r--r--drivers/media/usb/gspca/se401.c4
-rw-r--r--drivers/media/usb/gspca/sn9c20x.c4
-rw-r--r--drivers/media/usb/gspca/sonixb.c6
-rw-r--r--drivers/media/usb/gspca/sonixj.c4
-rw-r--r--drivers/media/usb/gspca/spca561.c6
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx.c4
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c17
-rw-r--r--drivers/media/usb/gspca/t613.c8
-rw-r--r--drivers/media/usb/gspca/xirlink_cit.c8
-rw-r--r--drivers/media/usb/gspca/zc3xx.c4
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-core.c6
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-i2c.c5
-rw-r--r--drivers/media/usb/pvrusb2/Kconfig8
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-encoder.c3
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c4
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c2
-rw-r--r--drivers/media/usb/pwc/pwc-if.c5
-rw-r--r--drivers/media/usb/pwc/pwc-v4l.c7
-rw-r--r--drivers/media/usb/s2255/s2255drv.c6
-rw-r--r--drivers/media/usb/sn9c102/sn9c102_core.c9
-rw-r--r--drivers/media/usb/stk1160/stk1160-video.c4
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c59
-rw-r--r--drivers/media/usb/tlg2300/pd-video.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-core.c9
-rw-r--r--drivers/media/usb/tm6000/tm6000-dvb.c4
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c542
-rw-r--r--drivers/media/usb/tm6000/tm6000.h10
-rw-r--r--drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c7
-rw-r--r--drivers/media/usb/usbvision/usbvision-core.c2
-rw-r--r--drivers/media/usb/usbvision/usbvision-i2c.c3
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c5
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c2
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c16
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c8
-rw-r--r--drivers/media/usb/zr364xx/zr364xx.c6
-rw-r--r--drivers/media/v4l2-core/Kconfig11
-rw-r--r--drivers/media/v4l2-core/Makefile3
-rw-r--r--drivers/media/v4l2-core/tuner-core.c17
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c14
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c179
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c14
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c32
-rw-r--r--drivers/media/v4l2-core/v4l2-event.c7
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c4
-rw-r--r--drivers/media/v4l2-core/videobuf-core.c2
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c15
-rw-r--r--drivers/memory/emif.c8
-rw-r--r--drivers/memory/tegra20-mc.c7
-rw-r--r--drivers/memory/tegra30-mc.c7
-rw-r--r--drivers/memstick/Kconfig2
-rw-r--r--drivers/memstick/host/Kconfig12
-rw-r--r--drivers/memstick/host/rtsx_pci_ms.c7
-rw-r--r--drivers/mfd/88pm800.c10
-rw-r--r--drivers/mfd/88pm805.c4
-rw-r--r--drivers/mfd/88pm80x.c22
-rw-r--r--drivers/mfd/Kconfig72
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/ab8500-core.c75
-rw-r--r--drivers/mfd/ab8500-debugfs.c1248
-rw-r--r--drivers/mfd/ab8500-gpadc.c90
-rw-r--r--drivers/mfd/ab8500-sysctrl.c92
-rw-r--r--drivers/mfd/abx500-core.c16
-rw-r--r--drivers/mfd/arizona-core.c55
-rw-r--r--drivers/mfd/da9052-i2c.c3
-rw-r--r--drivers/mfd/db8500-prcmu.c160
-rw-r--r--drivers/mfd/intel_msic.c9
-rw-r--r--drivers/mfd/lpc_ich.c144
-rw-r--r--drivers/mfd/lpc_sch.c147
-rw-r--r--drivers/mfd/max8925-core.c89
-rw-r--r--drivers/mfd/max8925-i2c.c36
-rw-r--r--drivers/mfd/omap-usb-host.c558
-rw-r--r--drivers/mfd/omap-usb-tll.c243
-rw-r--r--drivers/mfd/palmas.c14
-rw-r--r--drivers/mfd/rtl8411.c16
-rw-r--r--drivers/mfd/rts5209.c8
-rw-r--r--drivers/mfd/rts5227.c234
-rw-r--r--drivers/mfd/rts5229.c8
-rw-r--r--drivers/mfd/rtsx_pcr.c98
-rw-r--r--drivers/mfd/rtsx_pcr.h4
-rw-r--r--drivers/mfd/sec-core.c75
-rw-r--r--drivers/mfd/syscon.c1
-rw-r--r--drivers/mfd/tps6507x.c9
-rw-r--r--drivers/mfd/tps65090.c47
-rw-r--r--drivers/mfd/twl-core.c370
-rw-r--r--drivers/mfd/vexpress-sysreg.c85
-rw-r--r--drivers/mfd/wm5102-tables.c141
-rw-r--r--drivers/mfd/wm5110-tables.c1
-rw-r--r--drivers/mfd/wm8994-core.c7
-rw-r--r--drivers/misc/Kconfig16
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/atmel-ssc.c10
-rw-r--r--drivers/misc/cb710/Kconfig2
-rw-r--r--drivers/misc/lattice-ecp3-config.c243
-rw-r--r--drivers/misc/mei/Kconfig15
-rw-r--r--drivers/misc/mei/Makefile6
-rw-r--r--drivers/misc/mei/amthif.c164
-rw-r--r--drivers/misc/mei/client.c729
-rw-r--r--drivers/misc/mei/client.h102
-rw-r--r--drivers/misc/mei/hbm.c669
-rw-r--r--drivers/misc/mei/hbm.h39
-rw-r--r--drivers/misc/mei/hw-me-regs.h167
-rw-r--r--drivers/misc/mei/hw-me.c576
-rw-r--r--drivers/misc/mei/hw-me.h48
-rw-r--r--drivers/misc/mei/hw.h125
-rw-r--r--drivers/misc/mei/init.c572
-rw-r--r--drivers/misc/mei/interface.c388
-rw-r--r--drivers/misc/mei/interface.h81
-rw-r--r--drivers/misc/mei/interrupt.c656
-rw-r--r--drivers/misc/mei/iorw.c366
-rw-r--r--drivers/misc/mei/main.c536
-rw-r--r--drivers/misc/mei/mei_dev.h350
-rw-r--r--drivers/misc/mei/pci-me.c396
-rw-r--r--drivers/misc/mei/wd.c77
-rw-r--r--drivers/misc/sgi-gru/grufile.c2
-rw-r--r--drivers/misc/ti-st/Kconfig2
-rw-r--r--drivers/misc/ti-st/st_core.c3
-rw-r--r--drivers/misc/vmw_vmci/Kconfig16
-rw-r--r--drivers/misc/vmw_vmci/Makefile4
-rw-r--r--drivers/misc/vmw_vmci/vmci_context.c1214
-rw-r--r--drivers/misc/vmw_vmci/vmci_context.h182
-rw-r--r--drivers/misc/vmw_vmci/vmci_datagram.c500
-rw-r--r--drivers/misc/vmw_vmci/vmci_datagram.h52
-rw-r--r--drivers/misc/vmw_vmci/vmci_doorbell.c604
-rw-r--r--drivers/misc/vmw_vmci/vmci_doorbell.h51
-rw-r--r--drivers/misc/vmw_vmci/vmci_driver.c117
-rw-r--r--drivers/misc/vmw_vmci/vmci_driver.h50
-rw-r--r--drivers/misc/vmw_vmci/vmci_event.c224
-rw-r--r--drivers/misc/vmw_vmci/vmci_event.h25
-rw-r--r--drivers/misc/vmw_vmci/vmci_guest.c759
-rw-r--r--drivers/misc/vmw_vmci/vmci_handle_array.c142
-rw-r--r--drivers/misc/vmw_vmci/vmci_handle_array.h52
-rw-r--r--drivers/misc/vmw_vmci/vmci_host.c1043
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.c3425
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.h191
-rw-r--r--drivers/misc/vmw_vmci/vmci_resource.c229
-rw-r--r--drivers/misc/vmw_vmci/vmci_resource.h59
-rw-r--r--drivers/misc/vmw_vmci/vmci_route.c226
-rw-r--r--drivers/misc/vmw_vmci/vmci_route.h30
-rw-r--r--drivers/mmc/card/Kconfig1
-rw-r--r--drivers/mmc/card/sdio_uart.c13
-rw-r--r--drivers/mmc/core/Kconfig3
-rw-r--r--drivers/mmc/host/Kconfig22
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c7
-rw-r--r--drivers/mmc/host/mmci.c306
-rw-r--r--drivers/mmc/host/mmci.h3
-rw-r--r--drivers/mmc/host/mxs-mmc.c6
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c18
-rw-r--r--drivers/mmc/host/sdhci-s3c.c7
-rw-r--r--drivers/mtd/Kconfig2
-rw-r--r--drivers/mtd/chips/Kconfig2
-rw-r--r--drivers/mtd/devices/Kconfig4
-rw-r--r--drivers/mtd/devices/spear_smi.c7
-rw-r--r--drivers/mtd/maps/autcpu12-nvram.c9
-rw-r--r--drivers/mtd/maps/lantiq-flash.c8
-rw-r--r--drivers/mtd/nand/Kconfig7
-rw-r--r--drivers/mtd/nand/fsmc_nand.c34
-rw-r--r--drivers/mtd/nand/lpc32xx_mlc.c9
-rw-r--r--drivers/mtd/nand/lpc32xx_slc.c8
-rw-r--r--drivers/mtd/nand/mxc_nand.c12
-rw-r--r--drivers/mtd/nand/omap2.c4
-rw-r--r--drivers/mtd/nand/s3c2410.c7
-rw-r--r--drivers/mtd/nand/txx9ndfmc.c7
-rw-r--r--drivers/mtd/onenand/omap2.c4
-rw-r--r--drivers/net/Kconfig13
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/Space.c106
-rw-r--r--drivers/net/bonding/bond_3ad.c45
-rw-r--r--drivers/net/bonding/bond_alb.c6
-rw-r--r--drivers/net/bonding/bond_main.c285
-rw-r--r--drivers/net/bonding/bond_sysfs.c1
-rw-r--r--drivers/net/bonding/bonding.h15
-rw-r--r--drivers/net/caif/Kconfig2
-rw-r--r--drivers/net/caif/caif_serial.c2
-rw-r--r--drivers/net/caif/caif_shmcore.c6
-rw-r--r--drivers/net/can/Kconfig38
-rw-r--r--drivers/net/can/Makefile2
-rw-r--r--drivers/net/can/at91_can.c10
-rw-r--r--drivers/net/can/c_can/Kconfig2
-rw-r--r--drivers/net/can/c_can/c_can.c16
-rw-r--r--drivers/net/can/cc770/Kconfig2
-rw-r--r--drivers/net/can/dev.c26
-rw-r--r--drivers/net/can/flexcan.c11
-rw-r--r--drivers/net/can/led.c124
-rw-r--r--drivers/net/can/mcp251x.c23
-rw-r--r--drivers/net/can/mscan/Kconfig2
-rw-r--r--drivers/net/can/sja1000/Kconfig14
-rw-r--r--drivers/net/can/sja1000/ems_pci.c1
-rw-r--r--drivers/net/can/sja1000/peak_pci.c8
-rw-r--r--drivers/net/can/sja1000/peak_pcmcia.c1
-rw-r--r--drivers/net/can/sja1000/plx_pci.c1
-rw-r--r--drivers/net/can/sja1000/sja1000.c17
-rw-r--r--drivers/net/can/slcan.c8
-rw-r--r--drivers/net/can/softing/Kconfig2
-rw-r--r--drivers/net/can/ti_hecc.c10
-rw-r--r--drivers/net/can/usb/Kconfig8
-rw-r--r--drivers/net/can/usb/Makefile1
-rw-r--r--drivers/net/can/usb/ems_usb.c8
-rw-r--r--drivers/net/can/usb/kvaser_usb.c2
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c5
-rw-r--r--drivers/net/can/usb/usb_8dev.c1031
-rw-r--r--drivers/net/cris/eth_v10.c8
-rw-r--r--drivers/net/dsa/mv88e6060.c54
-rw-r--r--drivers/net/dsa/mv88e6123_61_65.c125
-rw-r--r--drivers/net/dsa/mv88e6131.c114
-rw-r--r--drivers/net/dsa/mv88e6xxx.c141
-rw-r--r--drivers/net/dsa/mv88e6xxx.h11
-rw-r--r--drivers/net/dummy.c10
-rw-r--r--drivers/net/ethernet/3com/3c501.c896
-rw-r--r--drivers/net/ethernet/3com/3c501.h91
-rw-r--r--drivers/net/ethernet/3com/3c509.c4
-rw-r--r--drivers/net/ethernet/3com/3c515.c7
-rw-r--r--drivers/net/ethernet/3com/3c59x.c1
-rw-r--r--drivers/net/ethernet/3com/Kconfig20
-rw-r--r--drivers/net/ethernet/3com/Makefile1
-rw-r--r--drivers/net/ethernet/8390/3c503.c777
-rw-r--r--drivers/net/ethernet/8390/3c503.h91
-rw-r--r--drivers/net/ethernet/8390/Kconfig120
-rw-r--r--drivers/net/ethernet/8390/Makefile10
-rw-r--r--drivers/net/ethernet/8390/ac3200.c431
-rw-r--r--drivers/net/ethernet/8390/ax88796.c8
-rw-r--r--drivers/net/ethernet/8390/e2100.c489
-rw-r--r--drivers/net/ethernet/8390/es3210.c445
-rw-r--r--drivers/net/ethernet/8390/hp-plus.c505
-rw-r--r--drivers/net/ethernet/8390/hp.c438
-rw-r--r--drivers/net/ethernet/8390/lne390.c433
-rw-r--r--drivers/net/ethernet/8390/ne2k-pci.c1
-rw-r--r--drivers/net/ethernet/8390/ne3210.c346
-rw-r--r--drivers/net/ethernet/8390/smc-ultra32.c463
-rw-r--r--drivers/net/ethernet/Kconfig1
-rw-r--r--drivers/net/ethernet/Makefile1
-rw-r--r--drivers/net/ethernet/adi/bfin_mac.c13
-rw-r--r--drivers/net/ethernet/aeroflex/greth.c13
-rw-r--r--drivers/net/ethernet/amd/Kconfig15
-rw-r--r--drivers/net/ethernet/amd/Makefile1
-rw-r--r--drivers/net/ethernet/amd/au1000_eth.c12
-rw-r--r--drivers/net/ethernet/amd/depca.c1910
-rw-r--r--drivers/net/ethernet/amd/depca.h183
-rw-r--r--drivers/net/ethernet/amd/pcnet32.c50
-rw-r--r--drivers/net/ethernet/amd/sunlance.c4
-rw-r--r--drivers/net/ethernet/atheros/Kconfig8
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c79
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c3
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c2
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl2.c7
-rw-r--r--drivers/net/ethernet/atheros/atlx/atlx.c1
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig18
-rw-r--r--drivers/net/ethernet/broadcom/Makefile1
-rw-r--r--drivers/net/ethernet/broadcom/b44.c9
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.c17
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.c1461
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.h453
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/Makefile3
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h174
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c995
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h123
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c7
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h3274
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c456
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h8
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h32
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h8
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c22
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c1667
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h58
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c203
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h30
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c3198
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h809
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c134
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h13
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c1651
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h360
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c10
-rw-r--r--drivers/net/ethernet/broadcom/cnic_if.h1
-rw-r--r--drivers/net/ethernet/broadcom/sb1250-mac.c2
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c1099
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h65
-rw-r--r--drivers/net/ethernet/cadence/Kconfig1
-rw-r--r--drivers/net/ethernet/cadence/macb.c7
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/cxgb2.c28
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/sge.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c42
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c92
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/t3_hw.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c5
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/adapter.h1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c23
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/sge.c6
-rw-r--r--drivers/net/ethernet/cirrus/ep93xx_eth.c4
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_main.c13
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c7
-rw-r--r--drivers/net/ethernet/dec/Kconfig16
-rw-r--r--drivers/net/ethernet/dec/Makefile1
-rw-r--r--drivers/net/ethernet/dec/ewrk3.c1961
-rw-r--r--drivers/net/ethernet/dec/ewrk3.h322
-rw-r--r--drivers/net/ethernet/dec/tulip/Kconfig4
-rw-r--r--drivers/net/ethernet/dlink/Kconfig32
-rw-r--r--drivers/net/ethernet/dlink/Makefile2
-rw-r--r--drivers/net/ethernet/dlink/de600.c529
-rw-r--r--drivers/net/ethernet/dlink/de600.h168
-rw-r--r--drivers/net/ethernet/dlink/de620.c987
-rw-r--r--drivers/net/ethernet/dlink/de620.h117
-rw-r--r--drivers/net/ethernet/dlink/dl2k.c7
-rw-r--r--drivers/net/ethernet/dlink/sundance.c1
-rw-r--r--drivers/net/ethernet/dnet.c4
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h10
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c46
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h20
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c12
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c166
-rw-r--r--drivers/net/ethernet/ethoc.c63
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c9
-rw-r--r--drivers/net/ethernet/faraday/ftmac100.c6
-rw-r--r--drivers/net/ethernet/freescale/Kconfig9
-rw-r--r--drivers/net/ethernet/freescale/Makefile3
-rw-r--r--drivers/net/ethernet/freescale/fec.c356
-rw-r--r--drivers/net/ethernet/freescale/fec.h23
-rw-r--r--drivers/net/ethernet/freescale/fec_mpc52xx.c66
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c4
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c4
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c252
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h210
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c35
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth_ethtool.c8
-rw-r--r--drivers/net/ethernet/fujitsu/Kconfig25
-rw-r--r--drivers/net/ethernet/fujitsu/Makefile2
-rw-r--r--drivers/net/ethernet/fujitsu/at1700.c791
-rw-r--r--drivers/net/ethernet/fujitsu/eth16i.c1483
-rw-r--r--drivers/net/ethernet/i825xx/3c505.c1671
-rw-r--r--drivers/net/ethernet/i825xx/3c505.h292
-rw-r--r--drivers/net/ethernet/i825xx/3c507.c938
-rw-r--r--drivers/net/ethernet/i825xx/82596.c94
-rw-r--r--drivers/net/ethernet/i825xx/Kconfig94
-rw-r--r--drivers/net/ethernet/i825xx/Makefile8
-rw-r--r--drivers/net/ethernet/i825xx/eepro.c1822
-rw-r--r--drivers/net/ethernet/i825xx/eexpress.c1661
-rw-r--r--drivers/net/ethernet/i825xx/eexpress.h179
-rw-r--r--drivers/net/ethernet/i825xx/lp486e.c1337
-rw-r--r--drivers/net/ethernet/i825xx/ni52.c1346
-rw-r--r--drivers/net/ethernet/i825xx/ni52.h310
-rw-r--r--drivers/net/ethernet/i825xx/znet.c928
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c12
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_qmr.c19
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c9
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.c7
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c6
-rw-r--r--drivers/net/ethernet/icplus/Kconfig2
-rw-r--r--drivers/net/ethernet/intel/Kconfig19
-rw-r--r--drivers/net/ethernet/intel/e100.c3
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000.h65
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_ethtool.c140
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.c558
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c339
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_param.c29
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.c117
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.h95
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.c57
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.h58
-rw-r--r--drivers/net/ethernet/intel/e1000e/Makefile4
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h195
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h282
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c254
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h366
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c426
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.h268
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.c164
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.h74
-rw-r--r--drivers/net/ethernet/intel/e1000e/manage.c15
-rw-r--r--drivers/net/ethernet/intel/e1000e/manage.h72
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c745
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.c28
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.h47
-rw-r--r--drivers/net/ethernet/intel/e1000e/param.c8
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c354
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.h242
-rw-r--r--drivers/net/ethernet/intel/e1000e/ptp.c277
-rw-r--r--drivers/net/ethernet/intel/e1000e/regs.h252
-rw-r--r--drivers/net/ethernet/intel/igb/Makefile4
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c630
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.h19
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_defines.h15
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_hw.h22
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.c2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.c2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mbx.c2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mbx.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_nvm.c2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_nvm.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.c2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_regs.h18
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h69
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c15
-rw-r--r--drivers/net/ethernet/intel/igb/igb_hwmon.c242
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c865
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ptp.c65
-rw-r--r--drivers/net/ethernet/intel/igbvf/igbvf.h2
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c87
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_main.c13
-rw-r--r--drivers/net/ethernet/intel/ixgbe/Makefile2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h82
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c59
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c57
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c65
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c320
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c13
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c23
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c411
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c56
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h12
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c219
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c203
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h16
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h8
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c10
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ethtool.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c56
-rw-r--r--drivers/net/ethernet/korina.c6
-rw-r--r--drivers/net/ethernet/lantiq_etop.c12
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c10
-rw-r--r--drivers/net/ethernet/marvell/mvmdio.c1
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c1
-rw-r--r--drivers/net/ethernet/marvell/pxa168_eth.c11
-rw-r--r--drivers/net/ethernet/marvell/skge.c6
-rw-r--r--drivers/net/ethernet/marvell/sky2.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c174
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c28
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c869
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c59
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_selftest.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c24
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c34
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mcg.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h19
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h38
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/port.c193
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c2
-rw-r--r--drivers/net/ethernet/micrel/ks8842.c1
-rw-r--r--drivers/net/ethernet/micrel/ks8851.c44
-rw-r--r--drivers/net/ethernet/micrel/ks8851_mll.c1
-rw-r--r--drivers/net/ethernet/microchip/Kconfig4
-rw-r--r--drivers/net/ethernet/microchip/enc28j60.c1
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/myri10ge.c5
-rw-r--r--drivers/net/ethernet/natsemi/Kconfig3
-rw-r--r--drivers/net/ethernet/natsemi/ibmlana.c1075
-rw-r--r--drivers/net/ethernet/natsemi/ibmlana.h278
-rw-r--r--drivers/net/ethernet/natsemi/natsemi.c3
-rw-r--r--drivers/net/ethernet/neterion/s2io.c1
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-ethtool.c6
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-main.c1
-rw-r--r--drivers/net/ethernet/nuvoton/w90p910_ether.c4
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c4
-rw-r--r--drivers/net/ethernet/nxp/lpc_eth.c9
-rw-r--r--drivers/net/ethernet/octeon/octeon_mgmt.c14
-rw-r--r--drivers/net/ethernet/packetengines/Kconfig4
-rw-r--r--drivers/net/ethernet/packetengines/hamachi.c7
-rw-r--r--drivers/net/ethernet/packetengines/yellowfin.c7
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c5
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c18
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c28
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c8
-rw-r--r--drivers/net/ethernet/qlogic/qla3xxx.c11
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/Makefile4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h544
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c3011
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h438
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c2054
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c225
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c727
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c550
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h108
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c245
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h194
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c97
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c823
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c1217
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c650
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c271
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c24
-rw-r--r--drivers/net/ethernet/racal/Kconfig33
-rw-r--r--drivers/net/ethernet/racal/Makefile5
-rw-r--r--drivers/net/ethernet/racal/ni5010.c771
-rw-r--r--drivers/net/ethernet/racal/ni5010.h144
-rw-r--r--drivers/net/ethernet/rdc/r6040.c14
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c1
-rw-r--r--drivers/net/ethernet/realtek/8139too.c1
-rw-r--r--drivers/net/ethernet/realtek/Kconfig4
-rw-r--r--drivers/net/ethernet/realtek/r8169.c100
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c12
-rw-r--r--drivers/net/ethernet/s6gmac.c2
-rw-r--r--drivers/net/ethernet/seeq/Kconfig12
-rw-r--r--drivers/net/ethernet/seeq/Makefile1
-rw-r--r--drivers/net/ethernet/seeq/seeq8005.c749
-rw-r--r--drivers/net/ethernet/seeq/seeq8005.h156
-rw-r--r--drivers/net/ethernet/sfc/ptp.c2
-rw-r--r--drivers/net/ethernet/sgi/ioc3-eth.c6
-rw-r--r--drivers/net/ethernet/silan/Kconfig6
-rw-r--r--drivers/net/ethernet/silan/sc92031.c12
-rw-r--r--drivers/net/ethernet/sis/sis900.c22
-rw-r--r--drivers/net/ethernet/smsc/smc911x.c9
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c7
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c6
-rw-r--r--drivers/net/ethernet/smsc/smsc9420.c11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c18
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c1
-rw-r--r--drivers/net/ethernet/sun/Kconfig8
-rw-r--r--drivers/net/ethernet/sun/niu.c48
-rw-r--r--drivers/net/ethernet/sun/sunbmac.c4
-rw-r--r--drivers/net/ethernet/sun/sunqe.c7
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c6
-rw-r--r--drivers/net/ethernet/tehuti/tehuti.c8
-rw-r--r--drivers/net/ethernet/ti/Kconfig4
-rw-r--r--drivers/net/ethernet/ti/cpmac.c11
-rw-r--r--drivers/net/ethernet/ti/cpsw.c530
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c107
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.h24
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.c77
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.h12
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c26
-rw-r--r--drivers/net/ethernet/ti/davinci_mdio.c4
-rw-r--r--drivers/net/ethernet/tile/tilepro.c1
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.c4
-rw-r--r--drivers/net/ethernet/toshiba/spider_net_ethtool.c12
-rw-r--r--drivers/net/ethernet/toshiba/tc35815.c13
-rw-r--r--drivers/net/ethernet/via/via-rhine.c56
-rw-r--r--drivers/net/ethernet/wiznet/w5100.c1
-rw-r--r--drivers/net/ethernet/wiznet/w5300.c1
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c37
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c5
-rw-r--r--drivers/net/ethernet/xircom/xirc2ps_cs.c3
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c7
-rw-r--r--drivers/net/hamradio/Kconfig4
-rw-r--r--drivers/net/hamradio/bpqether.c5
-rw-r--r--drivers/net/hamradio/dmascc.c7
-rw-r--r--drivers/net/hamradio/scc.c4
-rw-r--r--drivers/net/hamradio/yam.c4
-rw-r--r--drivers/net/hippi/Kconfig8
-rw-r--r--drivers/net/hyperv/netvsc_drv.c9
-rw-r--r--drivers/net/ieee802154/at86rf230.c12
-rw-r--r--drivers/net/ieee802154/fakehard.c1
-rw-r--r--drivers/net/ifb.c2
-rw-r--r--drivers/net/irda/Kconfig38
-rw-r--r--drivers/net/irda/ali-ircc.c2
-rw-r--r--drivers/net/irda/irtty-sir.c2
-rw-r--r--drivers/net/macvlan.c51
-rw-r--r--drivers/net/macvtap.c1
-rw-r--r--drivers/net/netconsole.c44
-rw-r--r--drivers/net/ntb_netdev.c408
-rw-r--r--drivers/net/phy/Kconfig1
-rw-r--r--drivers/net/phy/mdio-mux-gpio.c4
-rw-r--r--drivers/net/phy/mdio_bus.c2
-rw-r--r--drivers/net/phy/micrel.c64
-rw-r--r--drivers/net/phy/phy_device.c15
-rw-r--r--drivers/net/phy/realtek.c50
-rw-r--r--drivers/net/phy/spi_ks8995.c4
-rw-r--r--drivers/net/ppp/Kconfig23
-rw-r--r--drivers/net/ppp/ppp_generic.c11
-rw-r--r--drivers/net/ppp/pppoe.c4
-rw-r--r--drivers/net/rionet.c8
-rw-r--r--drivers/net/slip/Kconfig1
-rw-r--r--drivers/net/team/Kconfig3
-rw-r--r--drivers/net/team/team.c261
-rw-r--r--drivers/net/team/team_mode_activebackup.c13
-rw-r--r--drivers/net/tun.c39
-rw-r--r--drivers/net/usb/Kconfig20
-rw-r--r--drivers/net/usb/asix.h18
-rw-r--r--drivers/net/usb/asix_common.c94
-rw-r--r--drivers/net/usb/asix_devices.c51
-rw-r--r--drivers/net/usb/ax88172a.c19
-rw-r--r--drivers/net/usb/catc.c6
-rw-r--r--drivers/net/usb/cdc_ether.c7
-rw-r--r--drivers/net/usb/cdc_ncm.c20
-rw-r--r--drivers/net/usb/dm9601.c4
-rw-r--r--drivers/net/usb/hso.c57
-rw-r--r--drivers/net/usb/kalmia.c1
-rw-r--r--drivers/net/usb/pegasus.c19
-rw-r--r--drivers/net/usb/qmi_wwan.c21
-rw-r--r--drivers/net/usb/rndis_host.c1
-rw-r--r--drivers/net/usb/rtl8150.c6
-rw-r--r--drivers/net/usb/sierra_net.c14
-rw-r--r--drivers/net/usb/smsc75xx.c6
-rw-r--r--drivers/net/usb/smsc95xx.c441
-rw-r--r--drivers/net/usb/usbnet.c40
-rw-r--r--drivers/net/veth.c177
-rw-r--r--drivers/net/virtio_net.c115
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c234
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c15
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h3
-rw-r--r--drivers/net/vxlan.c18
-rw-r--r--drivers/net/wan/Kconfig60
-rw-r--r--drivers/net/wan/Makefile5
-rw-r--r--drivers/net/wan/cosa.c9
-rw-r--r--drivers/net/wan/cycx_drv.c569
-rw-r--r--drivers/net/wan/cycx_main.c346
-rw-r--r--drivers/net/wan/cycx_x25.c1602
-rw-r--r--drivers/net/wan/farsync.c6
-rw-r--r--drivers/net/wan/hdlc.c9
-rw-r--r--drivers/net/wan/x25_asy.c1
-rw-r--r--drivers/net/wimax/i2400m/fw.c1
-rw-r--r--drivers/net/wimax/i2400m/netdev.c41
-rw-r--r--drivers/net/wimax/i2400m/rx.c17
-rw-r--r--drivers/net/wimax/i2400m/usb-notif.c1
-rw-r--r--drivers/net/wimax/i2400m/usb.c6
-rw-r--r--drivers/net/wireless/Kconfig10
-rw-r--r--drivers/net/wireless/airo_cs.c5
-rw-r--r--drivers/net/wireless/at76c50x-usb.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c5
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/Kconfig1
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c133
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.h2
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h2
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_pipe.c26
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c36
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c6
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c30
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig1
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c33
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_initvals.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c50
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9001_initvals.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c23
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.c66
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h180
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c143
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c128
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c69
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c95
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9340_initvals.h100
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9485_initvals.h146
-rw-r--r--drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h132
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h76
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h166
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c115
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c304
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c11
-rw-r--r--drivers/net/wireless/ath/ath9k/hw-ops.h16
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c55
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h58
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c123
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c149
-rw-r--r--drivers/net/wireless/ath/ath9k/mci.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c39
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c151
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c150
-rw-r--r--drivers/net/wireless/ath/carl9170/Kconfig2
-rw-r--r--drivers/net/wireless/ath/carl9170/carl9170.h19
-rw-r--r--drivers/net/wireless/ath/carl9170/fw.c37
-rw-r--r--drivers/net/wireless/ath/carl9170/fwcmd.h8
-rw-r--r--drivers/net/wireless/ath/carl9170/hw.h2
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c115
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c133
-rw-r--r--drivers/net/wireless/ath/carl9170/version.h6
-rw-r--r--drivers/net/wireless/ath/regd.c37
-rw-r--r--drivers/net/wireless/ath/regd.h10
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c11
-rw-r--r--drivers/net/wireless/ath/wil6210/dbg_hexdump.h18
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c55
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c63
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c31
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c109
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h22
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c119
-rw-r--r--drivers/net/wireless/atmel_cs.c5
-rw-r--r--drivers/net/wireless/b43/Kconfig12
-rw-r--r--drivers/net/wireless/b43/dma.h2
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c30
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/Makefile3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h96
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h38
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c56
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h35
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c395
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c54
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.c11
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil.c7
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h66
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c2277
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.h183
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c43
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c1463
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h113
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/ampdu.c7
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/channel.c16
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c47
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h3
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c114
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pub.h3
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/scb.h1
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c2
-rw-r--r--drivers/net/wireless/ipw2x00/Kconfig2
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c40
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.h3
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c14
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c96
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c105
-rw-r--r--drivers/net/wireless/iwlegacy/4965-rs.c3
-rw-r--r--drivers/net/wireless/iwlegacy/4965.c3
-rw-r--r--drivers/net/wireless/iwlegacy/commands.h3
-rw-r--r--drivers/net/wireless/iwlegacy/common.c68
-rw-r--r--drivers/net/wireless/iwlegacy/common.h2
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig14
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile3
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/agn.h6
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/calib.c4
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/calib.h4
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/commands.h31
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/debugfs.c6
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/dev.h2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/devices.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/led.c4
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/led.h2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/lib.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c183
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/main.c55
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/power.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/power.h2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rs.c19
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rs.h2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rx.c4
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rxon.c7
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/scan.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/sta.c42
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/testmode.c4
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tt.c10
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tt.h2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tx.c117
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/ucode.c98
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-read.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-read.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h22
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c229
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-modparams.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-notif-wait.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-notif-wait.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c346
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.h80
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-op-mode.h16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-phy-db.c514
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-phy-db.h82
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-test.c56
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-test.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-testmode.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h164
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/Makefile10
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/binding.c197
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c955
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c378
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h282
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h369
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-power.h140
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h312
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h561
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h380
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h580
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h952
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c640
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/led.c134
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c992
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c1314
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h500
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c311
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c682
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c292
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/power.c207
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/quota.c197
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c3080
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.h393
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c356
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c442
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c1241
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.h374
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c519
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.h214
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c916
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c472
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/1000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/2000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/5000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/6000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/7000.c111
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/cfg.h6
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c10
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h17
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c57
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c361
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c89
-rw-r--r--drivers/net/wireless/libertas/cfg.c45
-rw-r--r--drivers/net/wireless/libertas/cfg.h3
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c178
-rw-r--r--drivers/net/wireless/mwifiex/11ac.c261
-rw-r--r--drivers/net/wireless/mwifiex/11ac.h26
-rw-r--r--drivers/net/wireless/mwifiex/11n.c55
-rw-r--r--drivers/net/wireless/mwifiex/11n.h6
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c6
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c5
-rw-r--r--drivers/net/wireless/mwifiex/Kconfig4
-rw-r--r--drivers/net/wireless/mwifiex/Makefile1
-rw-r--r--drivers/net/wireless/mwifiex/README1
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c192
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c159
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c30
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c2
-rw-r--r--drivers/net/wireless/mwifiex/decl.h18
-rw-r--r--drivers/net/wireless/mwifiex/fw.h141
-rw-r--r--drivers/net/wireless/mwifiex/init.c12
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h8
-rw-r--r--drivers/net/wireless/mwifiex/join.c44
-rw-r--r--drivers/net/wireless/mwifiex/main.h30
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c1262
-rw-r--r--drivers/net/wireless/mwifiex/pcie.h228
-rw-r--r--drivers/net/wireless/mwifiex/scan.c101
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c30
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c12
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c6
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c27
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c6
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c44
-rw-r--r--drivers/net/wireless/mwifiex/usb.c34
-rw-r--r--drivers/net/wireless/mwifiex/util.c2
-rw-r--r--drivers/net/wireless/mwifiex/util.h8
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c15
-rw-r--r--drivers/net/wireless/mwl8k.c358
-rw-r--r--drivers/net/wireless/orinoco/main.c17
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c11
-rw-r--r--drivers/net/wireless/orinoco/scan.c4
-rw-r--r--drivers/net/wireless/p54/Kconfig2
-rw-r--r--drivers/net/wireless/p54/p54pci.c7
-rw-r--r--drivers/net/wireless/p54/p54usb.c12
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c1
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.c14
-rw-r--r--drivers/net/wireless/ray_cs.c19
-rw-r--r--drivers/net/wireless/rndis_wlan.c9
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig5
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c7
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c816
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h8
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c36
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c53
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h30
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c108
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c78
-rw-r--r--drivers/net/wireless/rtl818x/Kconfig2
-rw-r--r--drivers/net/wireless/rtlwifi/Kconfig50
-rw-r--r--drivers/net/wireless/rtlwifi/base.c14
-rw-r--r--drivers/net/wireless/rtlwifi/core.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rc.c13
-rw-r--r--drivers/net/wireless/rtlwifi/regd.c37
-rw-r--r--drivers/net/wireless/rtlwifi/regd.h6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.c6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.c5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/mac.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c11
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/dm.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/hw.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/trx.c5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/hw.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/trx.c5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/fw.c8
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hw.c11
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/phy.c20
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/trx.c7
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c57
-rw-r--r--drivers/net/wireless/rtlwifi/usb.h3
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h2
-rw-r--r--drivers/net/wireless/ti/Kconfig9
-rw-r--r--drivers/net/wireless/ti/Makefile4
-rw-r--r--drivers/net/wireless/ti/wilink_platform_data.c (renamed from drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c)0
-rw-r--r--drivers/net/wireless/ti/wl1251/Kconfig2
-rw-r--r--drivers/net/wireless/ti/wl1251/event.c6
-rw-r--r--drivers/net/wireless/ti/wl1251/main.c24
-rw-r--r--drivers/net/wireless/ti/wl1251/ps.c3
-rw-r--r--drivers/net/wireless/ti/wl12xx/Makefile2
-rw-r--r--drivers/net/wireless/ti/wl12xx/cmd.c37
-rw-r--r--drivers/net/wireless/ti/wl12xx/cmd.h20
-rw-r--r--drivers/net/wireless/ti/wl12xx/event.c116
-rw-r--r--drivers/net/wireless/ti/wl12xx/event.h111
-rw-r--r--drivers/net/wireless/ti/wl12xx/main.c195
-rw-r--r--drivers/net/wireless/ti/wl12xx/scan.c501
-rw-r--r--drivers/net/wireless/ti/wl12xx/scan.h140
-rw-r--r--drivers/net/wireless/ti/wl12xx/wl12xx.h40
-rw-r--r--drivers/net/wireless/ti/wl18xx/Makefile2
-rw-r--r--drivers/net/wireless/ti/wl18xx/acx.c87
-rw-r--r--drivers/net/wireless/ti/wl18xx/acx.h55
-rw-r--r--drivers/net/wireless/ti/wl18xx/cmd.c80
-rw-r--r--drivers/net/wireless/ti/wl18xx/cmd.h52
-rw-r--r--drivers/net/wireless/ti/wl18xx/conf.h22
-rw-r--r--drivers/net/wireless/ti/wl18xx/event.c111
-rw-r--r--drivers/net/wireless/ti/wl18xx/event.h77
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c272
-rw-r--r--drivers/net/wireless/ti/wl18xx/scan.c326
-rw-r--r--drivers/net/wireless/ti/wl18xx/scan.h127
-rw-r--r--drivers/net/wireless/ti/wl18xx/tx.c54
-rw-r--r--drivers/net/wireless/ti/wl18xx/wl18xx.h50
-rw-r--r--drivers/net/wireless/ti/wlcore/Kconfig5
-rw-r--r--drivers/net/wireless/ti/wlcore/Makefile3
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.c15
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.h1
-rw-r--r--drivers/net/wireless/ti/wlcore/boot.c77
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.c423
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.h81
-rw-r--r--drivers/net/wireless/ti/wlcore/conf.h110
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.c10
-rw-r--r--drivers/net/wireless/ti/wlcore/event.c326
-rw-r--r--drivers/net/wireless/ti/wlcore/event.h99
-rw-r--r--drivers/net/wireless/ti/wlcore/hw_ops.h41
-rw-r--r--drivers/net/wireless/ti/wlcore/init.c19
-rw-r--r--drivers/net/wireless/ti/wlcore/io.h12
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c1596
-rw-r--r--drivers/net/wireless/ti/wlcore/ps.c11
-rw-r--r--drivers/net/wireless/ti/wlcore/rx.c33
-rw-r--r--drivers/net/wireless/ti/wlcore/rx.h3
-rw-r--r--drivers/net/wireless/ti/wlcore/scan.c696
-rw-r--r--drivers/net/wireless/ti/wlcore/scan.h144
-rw-r--r--drivers/net/wireless/ti/wlcore/sdio.c34
-rw-r--r--drivers/net/wireless/ti/wlcore/spi.c31
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c298
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.h35
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h119
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore_i.h58
-rw-r--r--drivers/net/wireless/zd1211rw/Kconfig2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c1
-rw-r--r--drivers/net/xen-netback/common.h3
-rw-r--r--drivers/net/xen-netback/interface.c28
-rw-r--r--drivers/net/xen-netback/netback.c123
-rw-r--r--drivers/nfc/Kconfig16
-rw-r--r--drivers/nfc/Makefile3
-rw-r--r--drivers/nfc/microread/Kconfig35
-rw-r--r--drivers/nfc/microread/Makefile10
-rw-r--r--drivers/nfc/microread/i2c.c340
-rw-r--r--drivers/nfc/microread/mei.c246
-rw-r--r--drivers/nfc/microread/microread.c728
-rw-r--r--drivers/nfc/microread/microread.h33
-rw-r--r--drivers/nfc/nfcwilink.c10
-rw-r--r--drivers/nfc/pn533.c1593
-rw-r--r--drivers/nfc/pn544/Kconfig23
-rw-r--r--drivers/nfc/pn544/Makefile5
-rw-r--r--drivers/nfc/pn544/i2c.c44
-rw-r--r--drivers/nfc/pn544/pn544.c65
-rw-r--r--drivers/ntb/Kconfig13
-rw-r--r--drivers/ntb/Makefile3
-rw-r--r--drivers/ntb/ntb_hw.c1141
-rw-r--r--drivers/ntb/ntb_hw.h181
-rw-r--r--drivers/ntb/ntb_regs.h139
-rw-r--r--drivers/ntb/ntb_transport.c1441
-rw-r--r--drivers/of/address.c2
-rw-r--r--drivers/of/base.c303
-rw-r--r--drivers/of/device.c13
-rw-r--r--drivers/of/of_mdio.c4
-rw-r--r--drivers/of/of_private.h36
-rw-r--r--drivers/of/platform.c1
-rw-r--r--drivers/of/selftest.c54
-rw-r--r--drivers/parisc/Kconfig1
-rw-r--r--drivers/parisc/dino.c13
-rw-r--r--drivers/parisc/hppb.c6
-rw-r--r--drivers/parisc/pdc_stable.c6
-rw-r--r--drivers/parisc/superio.c2
-rw-r--r--drivers/parport/Kconfig2
-rw-r--r--drivers/parport/parport_serial.c21
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c56
-rw-r--r--drivers/pci/hotplug/s390_pci_hpc.c60
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c15
-rw-r--r--drivers/pci/msi.c26
-rw-r--r--drivers/pci/pci-acpi.c56
-rw-r--r--drivers/pci/pci.c26
-rw-r--r--drivers/pci/pci.h5
-rw-r--r--drivers/pci/pcie/aer/aerdrv_errprint.c63
-rw-r--r--drivers/pci/probe.c1
-rw-r--r--drivers/pci/remove.c2
-rw-r--r--drivers/pcmcia/Kconfig4
-rw-r--r--drivers/pcmcia/cs.c37
-rw-r--r--drivers/pcmcia/i82092.c8
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c6
-rw-r--r--drivers/pcmcia/vrc4171_card.c1
-rw-r--r--drivers/pinctrl/Kconfig38
-rw-r--r--drivers/pinctrl/Makefile11
-rw-r--r--drivers/pinctrl/core.c118
-rw-r--r--drivers/pinctrl/core.h29
-rw-r--r--drivers/pinctrl/devicetree.c5
-rw-r--r--drivers/pinctrl/pinconf-generic.c4
-rw-r--r--drivers/pinctrl/pinconf.c207
-rw-r--r--drivers/pinctrl/pinctrl-ab8500.c484
-rw-r--r--drivers/pinctrl/pinctrl-ab8505.c380
-rw-r--r--drivers/pinctrl/pinctrl-ab8540.c407
-rw-r--r--drivers/pinctrl/pinctrl-ab9540.c485
-rw-r--r--drivers/pinctrl/pinctrl-abx500.c1012
-rw-r--r--drivers/pinctrl/pinctrl-abx500.h234
-rw-r--r--drivers/pinctrl/pinctrl-at91.c7
-rw-r--r--drivers/pinctrl/pinctrl-bcm2835.c6
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c8
-rw-r--r--drivers/pinctrl/pinctrl-exynos5440.c8
-rw-r--r--drivers/pinctrl/pinctrl-falcon.c51
-rw-r--r--drivers/pinctrl/pinctrl-imx.c6
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.c56
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.h1
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c396
-rw-r--r--drivers/pinctrl/pinctrl-pxa3xx.c7
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c13
-rw-r--r--drivers/pinctrl/pinctrl-sirf.c18
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.c1505
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.h478
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c14
-rw-r--r--drivers/pinctrl/pinctrl-tegra.h16
-rw-r--r--drivers/pinctrl/pinctrl-tegra114.c2769
-rw-r--r--drivers/pinctrl/pinctrl-tegra20.c6
-rw-r--r--drivers/pinctrl/pinctrl-tegra30.c4
-rw-r--r--drivers/pinctrl/pinctrl-u300.c6
-rw-r--r--drivers/pinctrl/pinctrl-xway.c69
-rw-r--r--drivers/pinctrl/sh-pfc/Kconfig116
-rw-r--r--drivers/pinctrl/sh-pfc/Makefile21
-rw-r--r--drivers/pinctrl/sh-pfc/core.c (renamed from drivers/sh/pfc/core.c)355
-rw-r--r--drivers/pinctrl/sh-pfc/core.h72
-rw-r--r--drivers/pinctrl/sh-pfc/gpio.c (renamed from drivers/sh/pfc/gpio.c)114
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7740.c (renamed from arch/arm/mach-shmobile/pfc-r8a7740.c)11
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7779.c (renamed from arch/arm/mach-shmobile/pfc-r8a7779.c)29
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7203.c1592
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7264.c2131
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7269.c2834
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7372.c (renamed from arch/arm/mach-shmobile/pfc-sh7372.c)11
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh73a0.c (renamed from arch/arm/mach-shmobile/pfc-sh73a0.c)11
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7720.c1236
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7722.c1779
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7723.c1903
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7724.c2225
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7734.c2475
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7757.c2282
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7785.c1304
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7786.c837
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-shx3.c582
-rw-r--r--drivers/pinctrl/sh-pfc/pinctrl.c (renamed from drivers/sh/pfc/pinctrl.c)164
-rw-r--r--drivers/pinctrl/sh-pfc/sh_pfc.h (renamed from include/linux/sh_pfc.h)43
-rw-r--r--drivers/pinctrl/spear/pinctrl-plgpio.c8
-rw-r--r--drivers/platform/Kconfig4
-rw-r--r--drivers/platform/Makefile1
-rw-r--r--drivers/platform/goldfish/Kconfig5
-rw-r--r--drivers/platform/goldfish/Makefile5
-rw-r--r--drivers/platform/goldfish/goldfish_pipe.c612
-rw-r--r--drivers/platform/goldfish/pdev_bus.c240
-rw-r--r--drivers/platform/x86/Kconfig6
-rw-r--r--drivers/platform/x86/asus-laptop.c2
-rw-r--r--drivers/platform/x86/classmate-laptop.c10
-rw-r--r--drivers/platform/x86/eeepc-laptop.c4
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c4
-rw-r--r--drivers/platform/x86/fujitsu-tablet.c2
-rw-r--r--drivers/platform/x86/hp_accel.c2
-rw-r--r--drivers/platform/x86/ideapad-laptop.c2
-rw-r--r--drivers/platform/x86/intel_menlow.c2
-rw-r--r--drivers/platform/x86/panasonic-laptop.c4
-rw-r--r--drivers/platform/x86/sony-laptop.c4
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c3
-rw-r--r--drivers/platform/x86/topstar-laptop.c2
-rw-r--r--drivers/platform/x86/toshiba_acpi.c4
-rw-r--r--drivers/platform/x86/toshiba_bluetooth.c4
-rw-r--r--drivers/platform/x86/wmi.c4
-rw-r--r--drivers/platform/x86/xo15-ebook.c2
-rw-r--r--drivers/pnp/pnpacpi/core.c10
-rw-r--r--drivers/pnp/pnpbios/Kconfig4
-rw-r--r--drivers/power/88pm860x_battery.c13
-rw-r--r--drivers/power/Kconfig14
-rw-r--r--drivers/power/Makefile4
-rw-r--r--drivers/power/ab8500_bmdata.c524
-rw-r--r--drivers/power/ab8500_btemp.c192
-rw-r--r--drivers/power/ab8500_charger.c1067
-rw-r--r--drivers/power/ab8500_fg.c447
-rw-r--r--drivers/power/abx500_chargalg.c204
-rw-r--r--drivers/power/bq2415x_charger.c54
-rw-r--r--drivers/power/bq27x00_battery.c12
-rw-r--r--drivers/power/charger-manager.c310
-rw-r--r--drivers/power/da9030_battery.c1
-rw-r--r--drivers/power/da9052-battery.c2
-rw-r--r--drivers/power/ds2782_battery.c69
-rw-r--r--drivers/power/generic-adc-battery.c20
-rw-r--r--drivers/power/goldfish_battery.c236
-rw-r--r--drivers/power/jz4740-battery.c7
-rw-r--r--drivers/power/lp8727_charger.c8
-rw-r--r--drivers/power/lp8788-charger.c25
-rw-r--r--drivers/power/max17040_battery.c4
-rw-r--r--drivers/power/pm2301_charger.c1088
-rw-r--r--drivers/power/pm2301_charger.h513
-rw-r--r--drivers/power/power_supply_core.c4
-rw-r--r--drivers/power/power_supply_sysfs.c3
-rw-r--r--drivers/power/reset/Kconfig17
-rw-r--r--drivers/power/reset/Makefile2
-rw-r--r--drivers/power/reset/qnap-poweroff.c116
-rw-r--r--drivers/power/reset/restart-poweroff.c65
-rw-r--r--drivers/pps/clients/Kconfig2
-rw-r--r--drivers/pps/clients/pps-ldisc.c30
-rw-r--r--drivers/pps/pps.c47
-rw-r--r--drivers/pwm/pwm-imx.c6
-rw-r--r--drivers/pwm/pwm-lpc32xx.c6
-rw-r--r--drivers/pwm/pwm-mxs.c6
-rw-r--r--drivers/pwm/pwm-puv3.c6
-rw-r--r--drivers/pwm/pwm-pxa.c6
-rw-r--r--drivers/pwm/pwm-spear.c6
-rw-r--r--drivers/pwm/pwm-tegra.c6
-rw-r--r--drivers/pwm/pwm-tiecap.c6
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c6
-rw-r--r--drivers/pwm/pwm-tipwmss.c6
-rw-r--r--drivers/pwm/pwm-vt8500.c6
-rw-r--r--drivers/regulator/88pm8607.c40
-rw-r--r--drivers/regulator/Kconfig10
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/anatop-regulator.c41
-rw-r--r--drivers/regulator/arizona-micsupp.c78
-rw-r--r--drivers/regulator/as3711-regulator.c2
-rw-r--r--drivers/regulator/core.c43
-rw-r--r--drivers/regulator/da9052-regulator.c46
-rw-r--r--drivers/regulator/da9055-regulator.c3
-rw-r--r--drivers/regulator/gpio-regulator.c7
-rw-r--r--drivers/regulator/lp3971.c22
-rw-r--r--drivers/regulator/lp3972.c22
-rw-r--r--drivers/regulator/lp872x.c36
-rw-r--r--drivers/regulator/lp8755.c566
-rw-r--r--drivers/regulator/lp8788-buck.c41
-rw-r--r--drivers/regulator/lp8788-ldo.c133
-rw-r--r--drivers/regulator/max77686.c29
-rw-r--r--drivers/regulator/max8907-regulator.c10
-rw-r--r--drivers/regulator/max8925-regulator.c3
-rw-r--r--drivers/regulator/max8997.c128
-rw-r--r--drivers/regulator/max8998.c16
-rw-r--r--drivers/regulator/mc13892-regulator.c111
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c25
-rw-r--r--drivers/regulator/mc13xxx.h4
-rw-r--r--drivers/regulator/of_regulator.c6
-rw-r--r--drivers/regulator/palmas-regulator.c7
-rw-r--r--drivers/regulator/s2mps11.c4
-rw-r--r--drivers/regulator/s5m8767.c268
-rw-r--r--drivers/regulator/tps51632-regulator.c152
-rw-r--r--drivers/regulator/tps6507x-regulator.c92
-rw-r--r--drivers/regulator/tps65090-regulator.c106
-rw-r--r--drivers/regulator/tps65217-regulator.c4
-rw-r--r--drivers/regulator/tps6586x-regulator.c54
-rw-r--r--drivers/regulator/tps65910-regulator.c8
-rw-r--r--drivers/remoteproc/Kconfig7
-rw-r--r--drivers/rpmsg/Kconfig3
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c2
-rw-r--r--drivers/rtc/Kconfig82
-rw-r--r--drivers/rtc/Makefile8
-rw-r--r--drivers/rtc/class.c11
-rw-r--r--drivers/rtc/interface.c6
-rw-r--r--drivers/rtc/rtc-at91rm9200.c17
-rw-r--r--drivers/rtc/rtc-cmos.c15
-rw-r--r--drivers/rtc/rtc-coh901331.c7
-rw-r--r--drivers/rtc/rtc-da9052.c18
-rw-r--r--drivers/rtc/rtc-davinci.c28
-rw-r--r--drivers/rtc/rtc-dev.c11
-rw-r--r--drivers/rtc/rtc-ds1305.c8
-rw-r--r--drivers/rtc/rtc-ds1307.c11
-rw-r--r--drivers/rtc/rtc-ds2404.c18
-rw-r--r--drivers/rtc/rtc-efi.c10
-rw-r--r--drivers/rtc/rtc-fm3130.c33
-rw-r--r--drivers/rtc/rtc-hid-sensor-time.c292
-rw-r--r--drivers/rtc/rtc-imxdi.c4
-rw-r--r--drivers/rtc/rtc-isl12022.c2
-rw-r--r--drivers/rtc/rtc-lp8788.c338
-rw-r--r--drivers/rtc/rtc-max77686.c641
-rw-r--r--drivers/rtc/rtc-max8907.c6
-rw-r--r--drivers/rtc/rtc-max8997.c552
-rw-r--r--drivers/rtc/rtc-mpc5121.c5
-rw-r--r--drivers/rtc/rtc-palmas.c339
-rw-r--r--drivers/rtc/rtc-pcf8523.c31
-rw-r--r--drivers/rtc/rtc-pcf8563.c2
-rw-r--r--drivers/rtc/rtc-pcf8583.c4
-rw-r--r--drivers/rtc/rtc-pl031.c6
-rw-r--r--drivers/rtc/rtc-pxa.c23
-rw-r--r--drivers/rtc/rtc-rs5c313.c5
-rw-r--r--drivers/rtc/rtc-rs5c372.c10
-rw-r--r--drivers/rtc/rtc-rx4581.c314
-rw-r--r--drivers/rtc/rtc-s3c.c26
-rw-r--r--drivers/rtc/rtc-sa1100.c15
-rw-r--r--drivers/rtc/rtc-snvs.c8
-rw-r--r--drivers/rtc/rtc-spear.c8
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c3
-rw-r--r--drivers/rtc/rtc-sun4v.c10
-rw-r--r--drivers/rtc/rtc-tegra.c8
-rw-r--r--drivers/rtc/rtc-tps6586x.c4
-rw-r--r--drivers/rtc/rtc-tps65910.c44
-rw-r--r--drivers/rtc/rtc-tps80031.c349
-rw-r--r--drivers/rtc/rtc-twl.c6
-rw-r--r--drivers/rtc/rtc-vr41xx.c2
-rw-r--r--drivers/rtc/rtc-vt8500.c28
-rw-r--r--drivers/rtc/rtc-wm831x.c9
-rw-r--r--drivers/rtc/systohc.c44
-rw-r--r--drivers/s390/block/dasd.c23
-rw-r--r--drivers/s390/block/dasd_3990_erp.c8
-rw-r--r--drivers/s390/block/dasd_alias.c4
-rw-r--r--drivers/s390/block/dasd_diag.c10
-rw-r--r--drivers/s390/block/dasd_eckd.c30
-rw-r--r--drivers/s390/block/dasd_eer.c2
-rw-r--r--drivers/s390/block/dasd_erp.c4
-rw-r--r--drivers/s390/block/dasd_fba.c2
-rw-r--r--drivers/s390/block/scm_blk.h41
-rw-r--r--drivers/s390/char/Kconfig8
-rw-r--r--drivers/s390/char/con3215.c12
-rw-r--r--drivers/s390/char/fs3270.c29
-rw-r--r--drivers/s390/char/keyboard.h16
-rw-r--r--drivers/s390/char/raw3270.c611
-rw-r--r--drivers/s390/char/raw3270.h12
-rw-r--r--drivers/s390/char/sclp.c4
-rw-r--r--drivers/s390/char/sclp_cmd.c10
-rw-r--r--drivers/s390/char/sclp_tty.c14
-rw-r--r--drivers/s390/char/sclp_vt220.c12
-rw-r--r--drivers/s390/char/tty3270.c191
-rw-r--r--drivers/s390/char/zcore.c64
-rw-r--r--drivers/s390/cio/chsc.c68
-rw-r--r--drivers/s390/cio/chsc.h2
-rw-r--r--drivers/s390/cio/cio.c4
-rw-r--r--drivers/s390/cio/cmf.c6
-rw-r--r--drivers/s390/cio/css.c2
-rw-r--r--drivers/s390/cio/device.c10
-rw-r--r--drivers/s390/cio/device_fsm.c2
-rw-r--r--drivers/s390/cio/device_pgid.c123
-rw-r--r--drivers/s390/cio/io_sch.h5
-rw-r--r--drivers/s390/cio/qdio_main.c12
-rw-r--r--drivers/s390/kvm/Makefile2
-rw-r--r--drivers/s390/kvm/kvm_virtio.c38
-rw-r--r--drivers/s390/kvm/virtio_ccw.c926
-rw-r--r--drivers/s390/net/Kconfig4
-rw-r--r--drivers/s390/net/qeth_core.h10
-rw-r--r--drivers/s390/net/qeth_core_main.c256
-rw-r--r--drivers/s390/net/qeth_core_mpc.c1
-rw-r--r--drivers/s390/net/qeth_core_mpc.h5
-rw-r--r--drivers/s390/net/qeth_core_sys.c3
-rw-r--r--drivers/s390/net/qeth_l2_main.c16
-rw-r--r--drivers/s390/net/qeth_l3_main.c35
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c2
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c2
-rw-r--r--drivers/sbus/char/Kconfig7
-rw-r--r--drivers/scsi/Kconfig20
-rw-r--r--drivers/scsi/arm/Kconfig10
-rw-r--r--drivers/scsi/device_handler/Kconfig4
-rw-r--r--drivers/scsi/hosts.c4
-rw-r--r--drivers/scsi/osd/osd_uld.c26
-rw-r--r--drivers/scsi/scsi_lib.c14
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c4
-rw-r--r--drivers/scsi/sr.c46
-rw-r--r--drivers/scsi/storvsc_drv.c12
-rw-r--r--drivers/sh/Kconfig1
-rw-r--r--drivers/sh/Makefile1
-rw-r--r--drivers/sh/pfc/Kconfig26
-rw-r--r--drivers/sh/pfc/Makefile3
-rw-r--r--drivers/spi/Kconfig32
-rw-r--r--drivers/spi/Makefile5
-rw-r--r--drivers/spi/spi-altera.c2
-rw-r--r--drivers/spi/spi-ath79.c115
-rw-r--r--drivers/spi/spi-atmel.c2
-rw-r--r--drivers/spi/spi-au1550.c8
-rw-r--r--drivers/spi/spi-bcm63xx.c179
-rw-r--r--drivers/spi/spi-bfin-sport.c3
-rw-r--r--drivers/spi/spi-bfin5xx.c5
-rw-r--r--drivers/spi/spi-bitbang.c33
-rw-r--r--drivers/spi/spi-clps711x.c2
-rw-r--r--drivers/spi/spi-coldfire-qspi.c3
-rw-r--r--drivers/spi/spi-davinci.c119
-rw-r--r--drivers/spi/spi-ep93xx.c9
-rw-r--r--drivers/spi/spi-falcon.c3
-rw-r--r--drivers/spi/spi-fsl-spi.c4
-rw-r--r--drivers/spi/spi-gpio.c23
-rw-r--r--drivers/spi/spi-imx.c1
-rw-r--r--drivers/spi/spi-mpc512x-psc.c17
-rw-r--r--drivers/spi/spi-mxs.c11
-rw-r--r--drivers/spi/spi-oc-tiny.c8
-rw-r--r--drivers/spi/spi-omap-100k.c6
-rw-r--r--drivers/spi/spi-omap-uwire.c6
-rw-r--r--drivers/spi/spi-omap2-mcspi.c49
-rw-r--r--drivers/spi/spi-orion.c21
-rw-r--r--drivers/spi/spi-ppc4xx.c10
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c392
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c133
-rw-r--r--drivers/spi/spi-pxa2xx-pxadma.c490
-rw-r--r--drivers/spi/spi-pxa2xx.c1103
-rw-r--r--drivers/spi/spi-pxa2xx.h221
-rw-r--r--drivers/spi/spi-s3c64xx.c160
-rw-r--r--drivers/spi/spi-sh-msiof.c56
-rw-r--r--drivers/spi/spi-sirf.c17
-rw-r--r--drivers/spi/spi-tegra20-sflash.c26
-rw-r--r--drivers/spi/spi-tegra20-slink.c27
-rw-r--r--drivers/spi/spi-txx9.c12
-rw-r--r--drivers/spi/spi.c26
-rw-r--r--drivers/ssb/Kconfig5
-rw-r--r--drivers/ssb/Makefile1
-rw-r--r--drivers/ssb/driver_chipcommon_sflash.c140
-rw-r--r--drivers/ssb/driver_gpio.c34
-rw-r--r--drivers/ssb/driver_mipscore.c51
-rw-r--r--drivers/ssb/main.c17
-rw-r--r--drivers/ssb/ssb_private.h20
-rw-r--r--drivers/staging/Kconfig8
-rw-r--r--drivers/staging/Makefile4
-rw-r--r--drivers/staging/android/Kconfig29
-rw-r--r--drivers/staging/android/alarm-dev.c277
-rw-r--r--drivers/staging/android/android_alarm.h19
-rw-r--r--drivers/staging/android/binder.c6
-rw-r--r--drivers/staging/android/binder.h6
-rw-r--r--drivers/staging/asus_oled/asus_oled.c15
-rw-r--r--drivers/staging/bcm/Adapter.h20
-rw-r--r--drivers/staging/bcm/Bcmchar.c14
-rw-r--r--drivers/staging/bcm/Bcmnet.c4
-rw-r--r--drivers/staging/bcm/CmHost.c6
-rw-r--r--drivers/staging/bcm/CmHost.h12
-rw-r--r--drivers/staging/bcm/Debug.h356
-rw-r--r--drivers/staging/bcm/IPv6Protocol.c34
-rw-r--r--drivers/staging/bcm/IPv6ProtocolHdr.h149
-rw-r--r--drivers/staging/bcm/InterfaceDld.c6
-rw-r--r--drivers/staging/bcm/InterfaceInit.c14
-rw-r--r--drivers/staging/bcm/Ioctl.h6
-rw-r--r--drivers/staging/bcm/Macros.h25
-rw-r--r--drivers/staging/bcm/Misc.c10
-rw-r--r--drivers/staging/bcm/PHSDefines.h200
-rw-r--r--drivers/staging/bcm/PHSModule.c160
-rw-r--r--drivers/staging/bcm/PHSModule.h14
-rw-r--r--drivers/staging/bcm/Protocol.h177
-rw-r--r--drivers/staging/bcm/Prototypes.h6
-rw-r--r--drivers/staging/bcm/Qos.c46
-rw-r--r--drivers/staging/bcm/hostmibs.c12
-rw-r--r--drivers/staging/bcm/led_control.c8
-rw-r--r--drivers/staging/bcm/led_control.h138
-rw-r--r--drivers/staging/bcm/nvm.c87
-rw-r--r--drivers/staging/bcm/nvm.h665
-rw-r--r--drivers/staging/bcm/target_params.h128
-rw-r--r--drivers/staging/bcm/vendorspecificextn.c2
-rw-r--r--drivers/staging/bcm/vendorspecificextn.h2
-rw-r--r--drivers/staging/ccg/Kconfig2
-rw-r--r--drivers/staging/ccg/u_ether.c10
-rw-r--r--drivers/staging/ccg/u_serial.c13
-rw-r--r--drivers/staging/ced1401/ced_ioc.c18
-rw-r--r--drivers/staging/ced1401/usb1401.c14
-rw-r--r--drivers/staging/ced1401/usb1401.h2
-rw-r--r--drivers/staging/comedi/Kconfig46
-rw-r--r--drivers/staging/comedi/Makefile19
-rw-r--r--drivers/staging/comedi/comedi.h12
-rw-r--r--drivers/staging/comedi/comedi_buf.c415
-rw-r--r--drivers/staging/comedi/comedi_compat32.c4
-rw-r--r--drivers/staging/comedi/comedi_fops.c1007
-rw-r--r--drivers/staging/comedi/comedi_internal.h33
-rw-r--r--drivers/staging/comedi/comedi_pci.c140
-rw-r--r--drivers/staging/comedi/comedi_pcmcia.c160
-rw-r--r--drivers/staging/comedi/comedi_usb.c108
-rw-r--r--drivers/staging/comedi/comedidev.h370
-rw-r--r--drivers/staging/comedi/drivers.c859
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c9
-rw-r--r--drivers/staging/comedi/drivers/Makefile4
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c26
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c807
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c263
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c589
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_035.c9
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c10
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1500.c9
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1516.c114
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1564.c9
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_16xx.c257
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1710.c9
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2032.c282
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2200.c187
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c9
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3200.c9
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c482
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c9
-rw-r--r--drivers/staging/comedi/drivers/addi_watchdog.c172
-rw-r--r--drivers/staging/comedi/drivers/addi_watchdog.h10
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c9
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7x3x.c17
-rw-r--r--drivers/staging/comedi/drivers/adl_pci8164.c39
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c12
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c13
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c8
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c9
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c12
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c20
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c8
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c9
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c8
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c12
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c132
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c11
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c12
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c9
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c12
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c9
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c5
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c75
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c9
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c14
-rw-r--r--drivers/staging/comedi/drivers/das08.c358
-rw-r--r--drivers/staging/comedi/drivers/das08.h2
-rw-r--r--drivers/staging/comedi/drivers/das08_cs.c152
-rw-r--r--drivers/staging/comedi/drivers/das08_isa.c217
-rw-r--r--drivers/staging/comedi/drivers/das08_pci.c121
-rw-r--r--drivers/staging/comedi/drivers/das16.c2
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c11
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c30
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c11
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c11
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c13
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c15
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c9
-rw-r--r--drivers/staging/comedi/drivers/me4000.c14
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c9
-rw-r--r--drivers/staging/comedi/drivers/mite.c5
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c9
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c10
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c10
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c9
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c119
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c303
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c55
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_cs.c257
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c4
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c399
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c9
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c11
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c1
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c19
-rw-r--r--drivers/staging/comedi/drivers/pcm_common.c63
-rw-r--r--drivers/staging/comedi/drivers/pcm_common.h8
-rw-r--r--drivers/staging/comedi/drivers/pcmda12.c3
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c62
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c72
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c589
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c10
-rw-r--r--drivers/staging/comedi/drivers/s626.c8
-rw-r--r--drivers/staging/comedi/drivers/skel.c12
-rw-r--r--drivers/staging/comedi/drivers/unioxx5.c6
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c29
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c8
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c33
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c1272
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c8
-rw-r--r--drivers/staging/comedi/proc.c9
-rw-r--r--drivers/staging/cptm1217/clearpad_tm1217.c5
-rw-r--r--drivers/staging/csr/bh.c2
-rw-r--r--drivers/staging/csr/drv.c6
-rw-r--r--drivers/staging/csr/sme_sys.c41
-rw-r--r--drivers/staging/csr/unifi_sme.c3
-rw-r--r--drivers/staging/cxt1e1/linux.c4
-rw-r--r--drivers/staging/dgrp/Kconfig2
-rw-r--r--drivers/staging/dgrp/dgrp_net_ops.c13
-rw-r--r--drivers/staging/dgrp/dgrp_specproc.c81
-rw-r--r--drivers/staging/dgrp/dgrp_tty.c1
-rw-r--r--drivers/staging/echo/echo.c42
-rw-r--r--drivers/staging/et131x/README4
-rw-r--r--drivers/staging/et131x/et131x.c801
-rw-r--r--drivers/staging/et131x/et131x.h96
-rw-r--r--drivers/staging/frontier/alphatrack.c51
-rw-r--r--drivers/staging/frontier/tranzport.c26
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000.h33
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c30
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c10
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_debug.c153
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_download.c110
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_hw.c166
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_proc.c6
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_usb.c39
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_usb.h84
-rw-r--r--drivers/staging/ft1000/ft1000.h35
-rw-r--r--drivers/staging/fwserial/Kconfig2
-rw-r--r--drivers/staging/fwserial/TODO15
-rw-r--r--drivers/staging/fwserial/fwserial.c412
-rw-r--r--drivers/staging/fwserial/fwserial.h25
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.c8
-rw-r--r--drivers/staging/gdm72xx/sdio_boot.c9
-rw-r--r--drivers/staging/gdm72xx/usb_boot.c8
-rw-r--r--drivers/staging/goldfish/Kconfig13
-rw-r--r--drivers/staging/goldfish/Makefile6
-rw-r--r--drivers/staging/goldfish/README12
-rw-r--r--drivers/staging/goldfish/goldfish_audio.c363
-rw-r--r--drivers/staging/goldfish/goldfish_nand.c444
-rw-r--r--drivers/staging/goldfish/goldfish_nand_reg.h72
-rw-r--r--drivers/staging/iio/Kconfig14
-rw-r--r--drivers/staging/iio/Makefile3
-rw-r--r--drivers/staging/iio/accel/Kconfig30
-rw-r--r--drivers/staging/iio/accel/Makefile2
-rw-r--r--drivers/staging/iio/accel/lis3l02dq.h8
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c18
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c12
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c13
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c6
-rw-r--r--drivers/staging/iio/adc/Kconfig4
-rw-r--r--drivers/staging/iio/adc/ad7280a.c6
-rw-r--r--drivers/staging/iio/adc/mxs-lradc.c532
-rw-r--r--drivers/staging/iio/frequency/ad5930.c5
-rw-r--r--drivers/staging/iio/frequency/ad9850.c5
-rw-r--r--drivers/staging/iio/frequency/ad9852.c5
-rw-r--r--drivers/staging/iio/gyro/Kconfig17
-rw-r--r--drivers/staging/iio/gyro/Makefile9
-rw-r--r--drivers/staging/iio/gyro/adxrs450.h62
-rw-r--r--drivers/staging/iio/iio_hwmon.c83
-rw-r--r--drivers/staging/iio/iio_simple_dummy.c4
-rw-r--r--drivers/staging/iio/iio_simple_dummy_buffer.c2
-rw-r--r--drivers/staging/iio/impedance-analyzer/Kconfig2
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c8
-rw-r--r--drivers/staging/iio/imu/Kconfig17
-rw-r--r--drivers/staging/iio/imu/Makefile7
-rw-r--r--drivers/staging/iio/imu/adis16400_core.c1320
-rw-r--r--drivers/staging/iio/imu/adis16400_ring.c204
-rw-r--r--drivers/staging/iio/imu/adis16400_trigger.c74
-rw-r--r--drivers/staging/iio/light/Kconfig10
-rw-r--r--drivers/staging/iio/light/Makefile1
-rw-r--r--drivers/staging/iio/light/tsl2x7x_core.c78
-rw-r--r--drivers/staging/iio/meter/Kconfig2
-rw-r--r--drivers/staging/iio/meter/ade7753.c6
-rw-r--r--drivers/staging/iio/meter/ade7754.c5
-rw-r--r--drivers/staging/iio/meter/ade7758_core.c28
-rw-r--r--drivers/staging/iio/meter/ade7758_ring.c12
-rw-r--r--drivers/staging/iio/meter/ade7759.c5
-rw-r--r--drivers/staging/iio/meter/ade7854-spi.c44
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c5
-rw-r--r--drivers/staging/iio/ring_sw.c366
-rw-r--r--drivers/staging/iio/ring_sw.h30
-rw-r--r--drivers/staging/iio/trigger/Kconfig1
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-common.c3
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-di.c2
-rw-r--r--drivers/staging/keucr/usb.c188
-rw-r--r--drivers/staging/line6/Kconfig10
-rw-r--r--drivers/staging/line6/capture.c10
-rw-r--r--drivers/staging/line6/driver.c86
-rw-r--r--drivers/staging/line6/driver.h13
-rw-r--r--drivers/staging/line6/midi.c2
-rw-r--r--drivers/staging/line6/midi.h4
-rw-r--r--drivers/staging/line6/midibuf.c25
-rw-r--r--drivers/staging/line6/midibuf.h22
-rw-r--r--drivers/staging/line6/pcm.c36
-rw-r--r--drivers/staging/line6/playback.c9
-rw-r--r--drivers/staging/line6/pod.c105
-rw-r--r--drivers/staging/line6/toneport.c6
-rw-r--r--drivers/staging/line6/variax.c14
-rw-r--r--drivers/staging/media/Kconfig2
-rw-r--r--drivers/staging/media/Makefile1
-rw-r--r--drivers/staging/media/as102/as102_usb_drv.c4
-rw-r--r--drivers/staging/media/as102/as10x_cmd_cfg.c2
-rw-r--r--drivers/staging/media/cxd2099/cxd2099.c29
-rw-r--r--drivers/staging/media/cxd2099/cxd2099.h2
-rw-r--r--drivers/staging/media/davinci_vpfe/Kconfig9
-rw-r--r--drivers/staging/media/davinci_vpfe/Makefile3
-rw-r--r--drivers/staging/media/davinci_vpfe/TODO37
-rw-r--r--drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt154
-rw-r--r--drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h1290
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c1863
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.h179
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c1048
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h559
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif.c1071
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif.h233
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h93
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.c2104
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.h203
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif_regs.h294
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.c1999
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.h244
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe.h86
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c740
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h97
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c1620
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.h155
-rw-r--r--drivers/staging/media/dt3155v4l/dt3155v4l.c2
-rw-r--r--drivers/staging/media/go7007/go7007-driver.c15
-rw-r--r--drivers/staging/media/go7007/go7007-fw.c24
-rw-r--r--drivers/staging/media/go7007/go7007-i2c.c10
-rw-r--r--drivers/staging/media/go7007/go7007-usb.c5
-rw-r--r--drivers/staging/media/go7007/go7007-v4l2.c11
-rw-r--r--drivers/staging/media/go7007/s2250-board.c32
-rw-r--r--drivers/staging/media/go7007/s2250-loader.c38
-rw-r--r--drivers/staging/media/go7007/wis-saa7113.c2
-rw-r--r--drivers/staging/media/go7007/wis-sony-tuner.c86
-rw-r--r--drivers/staging/media/go7007/wis-tw2804.c24
-rw-r--r--drivers/staging/media/go7007/wis-tw9903.c12
-rw-r--r--drivers/staging/media/go7007/wis-uda1342.c7
-rw-r--r--drivers/staging/media/lirc/lirc_bt829.c15
-rw-r--r--drivers/staging/media/lirc/lirc_igorplugusb.c12
-rw-r--r--drivers/staging/media/lirc/lirc_imon.c31
-rw-r--r--drivers/staging/media/lirc/lirc_parallel.c49
-rw-r--r--drivers/staging/media/lirc/lirc_sasem.c73
-rw-r--r--drivers/staging/media/lirc/lirc_serial.c70
-rw-r--r--drivers/staging/media/lirc/lirc_sir.c36
-rw-r--r--drivers/staging/media/solo6x10/p2m.c8
-rw-r--r--drivers/staging/media/solo6x10/v4l2-enc.c4
-rw-r--r--drivers/staging/media/solo6x10/v4l2.c5
-rw-r--r--drivers/staging/nvec/TODO4
-rw-r--r--drivers/staging/nvec/nvec.c95
-rw-r--r--drivers/staging/nvec/nvec.h5
-rw-r--r--drivers/staging/nvec/nvec_kbd.c42
-rw-r--r--drivers/staging/nvec/nvec_power.c8
-rw-r--r--drivers/staging/nvec/nvec_ps2.c37
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c6
-rw-r--r--drivers/staging/octeon/ethernet.c8
-rw-r--r--drivers/staging/omap-thermal/omap-bandgap.c13
-rw-r--r--drivers/staging/omap-thermal/omap-thermal-common.c4
-rw-r--r--drivers/staging/ozwpan/TODO3
-rw-r--r--drivers/staging/ozwpan/ozcdev.c52
-rw-r--r--drivers/staging/ozwpan/ozcdev.h1
-rw-r--r--drivers/staging/ozwpan/ozeltbuf.c18
-rw-r--r--drivers/staging/ozwpan/ozevent.c8
-rw-r--r--drivers/staging/ozwpan/ozhcd.c152
-rw-r--r--drivers/staging/ozwpan/ozmain.c2
-rw-r--r--drivers/staging/ozwpan/ozpd.c88
-rw-r--r--drivers/staging/ozwpan/ozpd.h4
-rw-r--r--drivers/staging/ozwpan/ozproto.c84
-rw-r--r--drivers/staging/ozwpan/ozproto.h2
-rw-r--r--drivers/staging/ozwpan/ozusbif.h8
-rw-r--r--drivers/staging/ozwpan/ozusbsvc.c22
-rw-r--r--drivers/staging/ozwpan/ozusbsvc1.c26
-rw-r--r--drivers/staging/panel/panel.c31
-rw-r--r--drivers/staging/quickstart/quickstart.c2
-rw-r--r--drivers/staging/ramster/Kconfig31
-rw-r--r--drivers/staging/ramster/Makefile6
-rw-r--r--drivers/staging/ramster/tmem.c894
-rw-r--r--drivers/staging/ramster/tmem.h259
-rw-r--r--drivers/staging/ramster/zcache-main.c1820
-rw-r--r--drivers/staging/rtl8187se/ieee80211/dot11d.c71
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_module.c4
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c6
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c408
-rw-r--r--drivers/staging/rtl8187se/r8185b_init.c301
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c6
-rw-r--r--drivers/staging/rtl8192u/changes1
-rw-r--r--drivers/staging/rtl8192u/ieee80211/Makefile1
-rw-r--r--drivers/staging/rtl8192u/ieee80211/aes.c3
-rw-r--r--drivers/staging/rtl8192u/ieee80211/arc4.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/crypto_compat.h2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/dot11d.c1
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h102
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_module.c8
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c394
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c280
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c31
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c54
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/internal.h1
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BA.h6
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c63
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h13
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c124
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_Qos.h83
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h3
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c18
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl_crypto.h93
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.c2
-rw-r--r--drivers/staging/rtl8192u/r8180_pm.h2
-rw-r--r--drivers/staging/rtl8192u/r8190_rtl8256.c13
-rw-r--r--drivers/staging/rtl8192u/r8192U.h299
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c589
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c197
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.h24
-rw-r--r--drivers/staging/rtl8192u/r8192U_hw.h16
-rw-r--r--drivers/staging/rtl8192u/r8192U_wx.c37
-rw-r--r--drivers/staging/rtl8192u/r819xU_HTGen.h1
-rw-r--r--drivers/staging/rtl8192u/r819xU_HTType.h9
-rw-r--r--drivers/staging/rtl8192u/r819xU_cmdpkt.c38
-rw-r--r--drivers/staging/rtl8192u/r819xU_cmdpkt.h44
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.c109
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.h1
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c127
-rw-r--r--drivers/staging/rtl8192u/r819xU_phyreg.h1044
-rw-r--r--drivers/staging/rtl8712/ethernet.h7
-rw-r--r--drivers/staging/rtl8712/hal_init.c17
-rw-r--r--drivers/staging/rtl8712/ieee80211.h2
-rw-r--r--drivers/staging/rtl8712/mlme_linux.c2
-rw-r--r--drivers/staging/rtl8712/os_intfs.c3
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c14
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.c1
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c66
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_rtl.c181
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c9
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp.h56
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.c393
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.h6
-rw-r--r--drivers/staging/rtl8712/sta_info.h2
-rw-r--r--drivers/staging/rtl8712/usb_intf.c33
-rw-r--r--drivers/staging/rtl8712/usb_ops_linux.c15
-rw-r--r--drivers/staging/rtl8712/wifi.h171
-rw-r--r--drivers/staging/rtl8712/xmit_linux.c3
-rw-r--r--drivers/staging/sb105x/Kconfig3
-rw-r--r--drivers/staging/sb105x/sb_mp_register.h2
-rw-r--r--drivers/staging/sb105x/sb_pci_mp.c18
-rw-r--r--drivers/staging/sbe-2t3e3/dc.c9
-rw-r--r--drivers/staging/sbe-2t3e3/module.c7
-rw-r--r--drivers/staging/sep/sep_crypto.c10
-rw-r--r--drivers/staging/sep/sep_main.c44
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c41
-rw-r--r--drivers/staging/slicoss/slic.h504
-rw-r--r--drivers/staging/slicoss/slichw.h6
-rw-r--r--drivers/staging/slicoss/slicoss.c35
-rw-r--r--drivers/staging/speakup/Kconfig2
-rw-r--r--drivers/staging/speakup/buffers.c14
-rw-r--r--drivers/staging/speakup/fakekey.c2
-rw-r--r--drivers/staging/speakup/i18n.c12
-rw-r--r--drivers/staging/speakup/i18n.h12
-rw-r--r--drivers/staging/speakup/keyhelp.c39
-rw-r--r--drivers/staging/speakup/kobjects.c84
-rw-r--r--drivers/staging/speakup/main.c370
-rw-r--r--drivers/staging/speakup/selection.c16
-rw-r--r--drivers/staging/speakup/serialio.c6
-rw-r--r--drivers/staging/speakup/speakup.h72
-rw-r--r--drivers/staging/speakup/speakup_acntpc.c6
-rw-r--r--drivers/staging/speakup/speakup_acntsa.c2
-rw-r--r--drivers/staging/speakup/speakup_apollo.c8
-rw-r--r--drivers/staging/speakup/speakup_audptr.c2
-rw-r--r--drivers/staging/speakup/speakup_bns.c2
-rw-r--r--drivers/staging/speakup/speakup_decext.c6
-rw-r--r--drivers/staging/speakup/speakup_decpc.c4
-rw-r--r--drivers/staging/speakup/speakup_dectlk.c6
-rw-r--r--drivers/staging/speakup/speakup_dtlk.c4
-rw-r--r--drivers/staging/speakup/speakup_dummy.c2
-rw-r--r--drivers/staging/speakup/speakup_keypc.c6
-rw-r--r--drivers/staging/speakup/speakup_ltlk.c2
-rw-r--r--drivers/staging/speakup/speakup_spkout.c2
-rw-r--r--drivers/staging/speakup/speakup_txprt.c2
-rw-r--r--drivers/staging/speakup/spk_priv.h8
-rw-r--r--drivers/staging/speakup/synth.c38
-rw-r--r--drivers/staging/speakup/thread.c4
-rw-r--r--drivers/staging/speakup/varhandlers.c66
-rw-r--r--drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c18
-rw-r--r--drivers/staging/tidspbridge/Kconfig2
-rw-r--r--drivers/staging/tidspbridge/core/msg_sm.c3
-rw-r--r--drivers/staging/tidspbridge/core/tiomap3430.c34
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/proc.h2
-rw-r--r--drivers/staging/tidspbridge/pmgr/cod.c2
-rw-r--r--drivers/staging/tidspbridge/pmgr/dbll.c2
-rw-r--r--drivers/staging/tidspbridge/pmgr/dspapi.c11
-rw-r--r--drivers/staging/tidspbridge/rmgr/dbdcd.c3
-rw-r--r--drivers/staging/tidspbridge/rmgr/drv_interface.c1
-rw-r--r--drivers/staging/tidspbridge/rmgr/nldr.c6
-rw-r--r--drivers/staging/tidspbridge/rmgr/node.c12
-rw-r--r--drivers/staging/tidspbridge/rmgr/proc.c23
-rw-r--r--drivers/staging/usbip/Kconfig2
-rw-r--r--drivers/staging/usbip/stub_dev.c42
-rw-r--r--drivers/staging/usbip/stub_rx.c5
-rw-r--r--drivers/staging/usbip/stub_tx.c1
-rw-r--r--drivers/staging/usbip/usbip_common.c3
-rw-r--r--drivers/staging/usbip/usbip_event.c6
-rw-r--r--drivers/staging/usbip/userspace/.gitignore28
-rw-r--r--drivers/staging/usbip/userspace/Makefile.am2
-rw-r--r--drivers/staging/usbip/userspace/README2
-rw-r--r--drivers/staging/usbip/userspace/configure.ac20
-rw-r--r--drivers/staging/usbip/userspace/src/Makefile.am4
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_attach.c15
-rw-r--r--drivers/staging/usbip/userspace/src/usbipd.c96
-rw-r--r--drivers/staging/usbip/vhci_hcd.c80
-rw-r--r--drivers/staging/usbip/vhci_rx.c10
-rw-r--r--drivers/staging/usbip/vhci_tx.c14
-rw-r--r--drivers/staging/vme/devices/Kconfig2
-rw-r--r--drivers/staging/vme/devices/vme_pio2_core.c1
-rw-r--r--drivers/staging/vme/devices/vme_pio2_gpio.c4
-rw-r--r--drivers/staging/vme/devices/vme_user.c2
-rw-r--r--drivers/staging/vt6655/channel.c11
-rw-r--r--drivers/staging/vt6655/device.h24
-rw-r--r--drivers/staging/vt6655/rxtx.c6
-rw-r--r--drivers/staging/vt6655/wcmd.c2
-rw-r--r--drivers/staging/vt6655/wmgr.c2
-rw-r--r--drivers/staging/vt6656/80211mgr.c36
-rw-r--r--drivers/staging/vt6656/80211mgr.h169
-rw-r--r--drivers/staging/vt6656/aes_ccmp.c10
-rw-r--r--drivers/staging/vt6656/aes_ccmp.h2
-rw-r--r--drivers/staging/vt6656/baseband.c91
-rw-r--r--drivers/staging/vt6656/baseband.h70
-rw-r--r--drivers/staging/vt6656/bssdb.c435
-rw-r--r--drivers/staging/vt6656/bssdb.h172
-rw-r--r--drivers/staging/vt6656/card.c366
-rw-r--r--drivers/staging/vt6656/card.h47
-rw-r--r--drivers/staging/vt6656/channel.c157
-rw-r--r--drivers/staging/vt6656/channel.h9
-rw-r--r--drivers/staging/vt6656/control.c55
-rw-r--r--drivers/staging/vt6656/control.h26
-rw-r--r--drivers/staging/vt6656/datarate.c109
-rw-r--r--drivers/staging/vt6656/datarate.h43
-rw-r--r--drivers/staging/vt6656/desc.h195
-rw-r--r--drivers/staging/vt6656/device.h879
-rw-r--r--drivers/staging/vt6656/device_cfg.h12
-rw-r--r--drivers/staging/vt6656/dpc.c470
-rw-r--r--drivers/staging/vt6656/dpc.h16
-rw-r--r--drivers/staging/vt6656/firmware.c33
-rw-r--r--drivers/staging/vt6656/firmware.h17
-rw-r--r--drivers/staging/vt6656/hostap.c147
-rw-r--r--drivers/staging/vt6656/hostap.h4
-rw-r--r--drivers/staging/vt6656/int.c22
-rw-r--r--drivers/staging/vt6656/int.h7
-rw-r--r--drivers/staging/vt6656/iocmd.h22
-rw-r--r--drivers/staging/vt6656/iwctl.c184
-rw-r--r--drivers/staging/vt6656/key.c364
-rw-r--r--drivers/staging/vt6656/key.h104
-rw-r--r--drivers/staging/vt6656/mac.c92
-rw-r--r--drivers/staging/vt6656/mac.h35
-rw-r--r--drivers/staging/vt6656/main_usb.c530
-rw-r--r--drivers/staging/vt6656/power.c104
-rw-r--r--drivers/staging/vt6656/power.h16
-rw-r--r--drivers/staging/vt6656/rf.c178
-rw-r--r--drivers/staging/vt6656/rf.h26
-rw-r--r--drivers/staging/vt6656/rxtx.c965
-rw-r--r--drivers/staging/vt6656/rxtx.h31
-rw-r--r--drivers/staging/vt6656/tether.c8
-rw-r--r--drivers/staging/vt6656/tether.h2
-rw-r--r--drivers/staging/vt6656/ttype.h23
-rw-r--r--drivers/staging/vt6656/usbpipe.c216
-rw-r--r--drivers/staging/vt6656/usbpipe.h40
-rw-r--r--drivers/staging/vt6656/wcmd.c323
-rw-r--r--drivers/staging/vt6656/wcmd.h18
-rw-r--r--drivers/staging/vt6656/wctl.c50
-rw-r--r--drivers/staging/vt6656/wctl.h10
-rw-r--r--drivers/staging/vt6656/wmgr.c1406
-rw-r--r--drivers/staging/vt6656/wmgr.h394
-rw-r--r--drivers/staging/vt6656/wpa.c30
-rw-r--r--drivers/staging/vt6656/wpa.h4
-rw-r--r--drivers/staging/vt6656/wpa2.c41
-rw-r--r--drivers/staging/vt6656/wpactl.c34
-rw-r--r--drivers/staging/vt6656/wpactl.h2
-rw-r--r--drivers/staging/winbond/Kconfig2
-rw-r--r--drivers/staging/wlags49_h2/ap_h2.c8
-rw-r--r--drivers/staging/wlags49_h2/ap_h25.c78
-rw-r--r--drivers/staging/wlags49_h2/sta_h2.c80
-rw-r--r--drivers/staging/wlags49_h2/wl_enc.c128
-rw-r--r--drivers/staging/wlags49_h2/wl_netdev.c14
-rw-r--r--drivers/staging/wlags49_h2/wl_netdev.h94
-rw-r--r--drivers/staging/wlags49_h2/wl_priv.c1113
-rw-r--r--drivers/staging/wlags49_h2/wl_priv.h58
-rw-r--r--drivers/staging/wlags49_h2/wl_profile.h12
-rw-r--r--drivers/staging/wlags49_h2/wl_util.h38
-rw-r--r--drivers/staging/wlags49_h2/wl_wext.c2
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c2
-rw-r--r--drivers/staging/wlan-ng/hfa384x.h31
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c2
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.c40
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c84
-rw-r--r--drivers/staging/xgifb/XGIfb.h2
-rw-r--r--drivers/staging/xgifb/vb_init.c119
-rw-r--r--drivers/staging/xgifb/vb_init.h1
-rw-r--r--drivers/staging/xgifb/vb_setmode.c684
-rw-r--r--drivers/staging/xgifb/vb_struct.h5
-rw-r--r--drivers/staging/xgifb/vb_table.h168
-rw-r--r--drivers/staging/zcache/Kconfig34
-rw-r--r--drivers/staging/zcache/Makefile5
-rw-r--r--drivers/staging/zcache/TODO69
-rw-r--r--drivers/staging/zcache/ramster.h (renamed from drivers/staging/ramster/ramster.h)0
-rw-r--r--drivers/staging/zcache/ramster/heartbeat.c (renamed from drivers/staging/ramster/ramster/heartbeat.c)0
-rw-r--r--drivers/staging/zcache/ramster/heartbeat.h (renamed from drivers/staging/ramster/ramster/heartbeat.h)0
-rw-r--r--drivers/staging/zcache/ramster/masklog.c (renamed from drivers/staging/ramster/ramster/masklog.c)0
-rw-r--r--drivers/staging/zcache/ramster/masklog.h (renamed from drivers/staging/ramster/ramster/masklog.h)0
-rw-r--r--drivers/staging/zcache/ramster/nodemanager.c (renamed from drivers/staging/ramster/ramster/nodemanager.c)0
-rw-r--r--drivers/staging/zcache/ramster/nodemanager.h (renamed from drivers/staging/ramster/ramster/nodemanager.h)0
-rw-r--r--drivers/staging/zcache/ramster/r2net.c (renamed from drivers/staging/ramster/ramster/r2net.c)0
-rw-r--r--drivers/staging/zcache/ramster/ramster.c (renamed from drivers/staging/ramster/ramster/ramster.c)34
-rw-r--r--drivers/staging/zcache/ramster/ramster.h (renamed from drivers/staging/ramster/ramster/ramster.h)0
-rw-r--r--drivers/staging/zcache/ramster/ramster_nodemanager.h (renamed from drivers/staging/ramster/ramster/ramster_nodemanager.h)0
-rw-r--r--drivers/staging/zcache/ramster/tcp.c (renamed from drivers/staging/ramster/ramster/tcp.c)0
-rw-r--r--drivers/staging/zcache/ramster/tcp.h (renamed from drivers/staging/ramster/ramster/tcp.h)0
-rw-r--r--drivers/staging/zcache/ramster/tcp_internal.h (renamed from drivers/staging/ramster/ramster/tcp_internal.h)0
-rw-r--r--drivers/staging/zcache/tmem.c327
-rw-r--r--drivers/staging/zcache/tmem.h83
-rw-r--r--drivers/staging/zcache/zbud.c (renamed from drivers/staging/ramster/zbud.c)43
-rw-r--r--drivers/staging/zcache/zbud.h (renamed from drivers/staging/ramster/zbud.h)0
-rw-r--r--drivers/staging/zcache/zcache-main.c2558
-rw-r--r--drivers/staging/zcache/zcache.h (renamed from drivers/staging/ramster/zcache.h)0
-rw-r--r--drivers/staging/zram/Kconfig2
-rw-r--r--drivers/staging/zram/zram.txt27
-rw-r--r--drivers/staging/zram/zram_drv.c294
-rw-r--r--drivers/staging/zram/zram_drv.h17
-rw-r--r--drivers/staging/zram/zram_sysfs.c16
-rw-r--r--drivers/staging/zsmalloc/zsmalloc-main.c31
-rw-r--r--drivers/staging/zsmalloc/zsmalloc.h2
-rw-r--r--drivers/target/sbp/sbp_target.c2
-rw-r--r--drivers/thermal/exynos_thermal.c8
-rw-r--r--drivers/tty/Kconfig32
-rw-r--r--drivers/tty/Makefile4
-rw-r--r--drivers/tty/amiserial.c18
-rw-r--r--drivers/tty/bfin_jtag_comm.c22
-rw-r--r--drivers/tty/cyclades.c297
-rw-r--r--drivers/tty/ehv_bytechan.c13
-rw-r--r--drivers/tty/goldfish.c328
-rw-r--r--drivers/tty/hvc/Kconfig3
-rw-r--r--drivers/tty/hvc/hvc_console.c6
-rw-r--r--drivers/tty/hvc/hvc_xen.c2
-rw-r--r--drivers/tty/hvc/hvcs.c6
-rw-r--r--drivers/tty/hvc/hvsi.c32
-rw-r--r--drivers/tty/ipwireless/hardware.c4
-rw-r--r--drivers/tty/ipwireless/tty.c12
-rw-r--r--drivers/tty/isicom.c12
-rw-r--r--drivers/tty/metag_da.c677
-rw-r--r--drivers/tty/moxa.c10
-rw-r--r--drivers/tty/mxser.c50
-rw-r--r--drivers/tty/n_gsm.c120
-rw-r--r--drivers/tty/n_tty.c59
-rw-r--r--drivers/tty/nozomi.c37
-rw-r--r--drivers/tty/pty.c28
-rw-r--r--drivers/tty/rocket.c60
-rw-r--r--drivers/tty/serial/21285.c3
-rw-r--r--drivers/tty/serial/68328serial.c19
-rw-r--r--drivers/tty/serial/8250/8250.c132
-rw-r--r--drivers/tty/serial/8250/8250.h50
-rw-r--r--drivers/tty/serial/8250/8250_dma.c216
-rw-r--r--drivers/tty/serial/8250/8250_dw.c257
-rw-r--r--drivers/tty/serial/8250/8250_early.c2
-rw-r--r--drivers/tty/serial/8250/8250_pci.c342
-rw-r--r--drivers/tty/serial/8250/Kconfig27
-rw-r--r--drivers/tty/serial/8250/Makefile1
-rw-r--r--drivers/tty/serial/Kconfig41
-rw-r--r--drivers/tty/serial/Makefile2
-rw-r--r--drivers/tty/serial/altera_jtaguart.c8
-rw-r--r--drivers/tty/serial/altera_uart.c8
-rw-r--r--drivers/tty/serial/amba-pl010.c3
-rw-r--r--drivers/tty/serial/amba-pl011.c11
-rw-r--r--drivers/tty/serial/apbuart.c3
-rw-r--r--drivers/tty/serial/ar933x_uart.c15
-rw-r--r--drivers/tty/serial/arc_uart.c104
-rw-r--r--drivers/tty/serial/atmel_serial.c9
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c9
-rw-r--r--drivers/tty/serial/bfin_sport_uart.c12
-rw-r--r--drivers/tty/serial/bfin_uart.c10
-rw-r--r--drivers/tty/serial/clps711x.c8
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c10
-rw-r--r--drivers/tty/serial/crisv10.c35
-rw-r--r--drivers/tty/serial/dz.c4
-rw-r--r--drivers/tty/serial/efm32-uart.c52
-rw-r--r--drivers/tty/serial/icom.c10
-rw-r--r--drivers/tty/serial/ifx6x60.c11
-rw-r--r--drivers/tty/serial/imx.c282
-rw-r--r--drivers/tty/serial/ioc3_serial.c11
-rw-r--r--drivers/tty/serial/ioc4_serial.c13
-rw-r--r--drivers/tty/serial/ip22zilog.c30
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c18
-rw-r--r--drivers/tty/serial/kgdb_nmi.c13
-rw-r--r--drivers/tty/serial/lantiq.c20
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c30
-rw-r--r--drivers/tty/serial/m32r_sio.c8
-rw-r--r--drivers/tty/serial/max3100.c13
-rw-r--r--drivers/tty/serial/max310x.c8
-rw-r--r--drivers/tty/serial/mcf.c73
-rw-r--r--drivers/tty/serial/mfd.c15
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c8
-rw-r--r--drivers/tty/serial/mpsc.c15
-rw-r--r--drivers/tty/serial/mrst_max3110.c19
-rw-r--r--drivers/tty/serial/msm_serial.c16
-rw-r--r--drivers/tty/serial/msm_serial_hs.c19
-rw-r--r--drivers/tty/serial/msm_smd_tty.c4
-rw-r--r--drivers/tty/serial/mux.c9
-rw-r--r--drivers/tty/serial/mxs-auart.c11
-rw-r--r--drivers/tty/serial/netx-serial.c4
-rw-r--r--drivers/tty/serial/nwpserial.c6
-rw-r--r--drivers/tty/serial/of_serial.c7
-rw-r--r--drivers/tty/serial/omap-serial.c51
-rw-r--r--drivers/tty/serial/pch_uart.c90
-rw-r--r--drivers/tty/serial/pmac_zilog.c36
-rw-r--r--drivers/tty/serial/pnx8xxx_uart.c3
-rw-r--r--drivers/tty/serial/pxa.c17
-rw-r--r--drivers/tty/serial/rp2.c885
-rw-r--r--drivers/tty/serial/sa1100.c3
-rw-r--r--drivers/tty/serial/samsung.c15
-rw-r--r--drivers/tty/serial/sb1250-duart.c2
-rw-r--r--drivers/tty/serial/sc26xx.c29
-rw-r--r--drivers/tty/serial/sccnxp.c179
-rw-r--r--drivers/tty/serial/serial-tegra.c1401
-rw-r--r--drivers/tty/serial/serial_core.c94
-rw-r--r--drivers/tty/serial/serial_ks8695.c3
-rw-r--r--drivers/tty/serial/serial_txx9.c3
-rw-r--r--drivers/tty/serial/sh-sci.c52
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c55
-rw-r--r--drivers/tty/serial/sirfsoc_uart.h3
-rw-r--r--drivers/tty/serial/sn_console.c16
-rw-r--r--drivers/tty/serial/sunhv.c33
-rw-r--r--drivers/tty/serial/sunsab.c28
-rw-r--r--drivers/tty/serial/sunsu.c18
-rw-r--r--drivers/tty/serial/sunzilog.c39
-rw-r--r--drivers/tty/serial/timbuart.c6
-rw-r--r--drivers/tty/serial/uartlite.c119
-rw-r--r--drivers/tty/serial/ucc_uart.c10
-rw-r--r--drivers/tty/serial/vr41xx_siu.c4
-rw-r--r--drivers/tty/serial/vt8500_serial.c52
-rw-r--r--drivers/tty/serial/xilinx_uartps.c50
-rw-r--r--drivers/tty/serial/zs.c2
-rw-r--r--drivers/tty/synclink.c50
-rw-r--r--drivers/tty/synclink_gt.c61
-rw-r--r--drivers/tty/synclinkmp.c103
-rw-r--r--drivers/tty/sysrq.c277
-rw-r--r--drivers/tty/tty_buffer.c131
-rw-r--r--drivers/tty/tty_io.c15
-rw-r--r--drivers/tty/tty_ioctl.c12
-rw-r--r--drivers/tty/tty_ldisc.c14
-rw-r--r--drivers/tty/vt/Makefile4
-rw-r--r--drivers/tty/vt/keyboard.c25
-rw-r--r--drivers/tty/vt/vt.c18
-rw-r--r--drivers/uio/Kconfig1
-rw-r--r--drivers/usb/c67x00/c67x00-ll-hpi.c2
-rw-r--r--drivers/usb/chipidea/ci13xxx_imx.h2
-rw-r--r--drivers/usb/chipidea/core.c2
-rw-r--r--drivers/usb/chipidea/debug.c2
-rw-r--r--drivers/usb/chipidea/usbmisc_imx6q.c6
-rw-r--r--drivers/usb/class/Kconfig2
-rw-r--r--drivers/usb/class/cdc-acm.c13
-rw-r--r--drivers/usb/core/Makefile1
-rw-r--r--drivers/usb/core/devices.c13
-rw-r--r--drivers/usb/core/devio.c3
-rw-r--r--drivers/usb/core/generic.c2
-rw-r--r--drivers/usb/core/hcd.c5
-rw-r--r--drivers/usb/core/hub.c629
-rw-r--r--drivers/usb/core/hub.h122
-rw-r--r--drivers/usb/core/message.c2
-rw-r--r--drivers/usb/core/port.c202
-rw-r--r--drivers/usb/core/sysfs.c31
-rw-r--r--drivers/usb/core/usb.h12
-rw-r--r--drivers/usb/dwc3/Kconfig31
-rw-r--r--drivers/usb/dwc3/Makefile10
-rw-r--r--drivers/usb/dwc3/core.c31
-rw-r--r--drivers/usb/dwc3/core.h24
-rw-r--r--drivers/usb/dwc3/debugfs.c38
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c57
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c152
-rw-r--r--drivers/usb/dwc3/gadget.c292
-rw-r--r--drivers/usb/dwc3/host.c2
-rw-r--r--drivers/usb/gadget/Kconfig30
-rw-r--r--drivers/usb/gadget/Makefile8
-rw-r--r--drivers/usb/gadget/acm_ms.c42
-rw-r--r--drivers/usb/gadget/amd5536udc.c59
-rw-r--r--drivers/usb/gadget/amd5536udc.h2
-rw-r--r--drivers/usb/gadget/at91_udc.c17
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c12
-rw-r--r--drivers/usb/gadget/bcm63xx_udc.c13
-rw-r--r--drivers/usb/gadget/cdc2.c36
-rw-r--r--drivers/usb/gadget/composite.c326
-rw-r--r--drivers/usb/gadget/dbgp.c14
-rw-r--r--drivers/usb/gadget/f_acm.c153
-rw-r--r--drivers/usb/gadget/f_fs.c5
-rw-r--r--drivers/usb/gadget/f_loopback.c103
-rw-r--r--drivers/usb/gadget/f_mass_storage.c37
-rw-r--r--drivers/usb/gadget/f_ncm.c18
-rw-r--r--drivers/usb/gadget/f_obex.c4
-rw-r--r--drivers/usb/gadget/f_serial.c4
-rw-r--r--drivers/usb/gadget/f_sourcesink.c200
-rw-r--r--drivers/usb/gadget/f_uac2.c9
-rw-r--r--drivers/usb/gadget/f_uvc.c3
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c2
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c60
-rw-r--r--drivers/usb/gadget/functions.c116
-rw-r--r--drivers/usb/gadget/fusb300_udc.c80
-rw-r--r--drivers/usb/gadget/fusb300_udc.h2
-rw-r--r--drivers/usb/gadget/g_zero.h35
-rw-r--r--drivers/usb/gadget/gmidi.c2
-rw-r--r--drivers/usb/gadget/goku_udc.c70
-rw-r--r--drivers/usb/gadget/goku_udc.h1
-rw-r--r--drivers/usb/gadget/imx_udc.c12
-rw-r--r--drivers/usb/gadget/lpc32xx_udc.c12
-rw-r--r--drivers/usb/gadget/m66592-udc.c84
-rw-r--r--drivers/usb/gadget/m66592-udc.h1
-rw-r--r--drivers/usb/gadget/multi.c71
-rw-r--r--drivers/usb/gadget/mv_udc_core.c246
-rw-r--r--drivers/usb/gadget/net2280.c15
-rw-r--r--drivers/usb/gadget/nokia.c43
-rw-r--r--drivers/usb/gadget/omap_udc.c51
-rw-r--r--drivers/usb/gadget/pch_udc.c67
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c77
-rw-r--r--drivers/usb/gadget/pxa25x_udc.h1
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c61
-rw-r--r--drivers/usb/gadget/pxa27x_udc.h1
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c17
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c51
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c20
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c65
-rw-r--r--drivers/usb/gadget/s3c2410_udc.h1
-rw-r--r--drivers/usb/gadget/serial.c118
-rw-r--r--drivers/usb/gadget/storage_common.c61
-rw-r--r--drivers/usb/gadget/u_ether.c10
-rw-r--r--drivers/usb/gadget/u_serial.c328
-rw-r--r--drivers/usb/gadget/u_serial.h13
-rw-r--r--drivers/usb/gadget/udc-core.c157
-rw-r--r--drivers/usb/gadget/webcam.c2
-rw-r--r--drivers/usb/gadget/zero.c233
-rw-r--r--drivers/usb/host/Kconfig2
-rw-r--r--drivers/usb/host/ehci-atmel.c7
-rw-r--r--drivers/usb/host/ehci-grlib.c9
-rw-r--r--drivers/usb/host/ehci-mv.c1
-rw-r--r--drivers/usb/host/ehci-mxc.c27
-rw-r--r--drivers/usb/host/ehci-omap.c16
-rw-r--r--drivers/usb/host/ehci-platform.c7
-rw-r--r--drivers/usb/host/ehci-ppc-of.c8
-rw-r--r--drivers/usb/host/ehci-s5p.c83
-rw-r--r--drivers/usb/host/ehci-sead3.c8
-rw-r--r--drivers/usb/host/ehci-sh.c7
-rw-r--r--drivers/usb/host/ehci-tegra.c97
-rw-r--r--drivers/usb/host/ehci-vt8500.c8
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c8
-rw-r--r--drivers/usb/host/isp1760-hcd.c4
-rw-r--r--drivers/usb/host/ohci-exynos.c87
-rw-r--r--drivers/usb/host/ohci-nxp.c7
-rw-r--r--drivers/usb/host/ohci-platform.c7
-rw-r--r--drivers/usb/host/ohci-q.c1
-rw-r--r--drivers/usb/host/ohci-s3c2410.c7
-rw-r--r--drivers/usb/host/uhci-debug.c178
-rw-r--r--drivers/usb/host/uhci-hcd.c31
-rw-r--r--drivers/usb/host/uhci-hcd.h4
-rw-r--r--drivers/usb/host/uhci-hub.c4
-rw-r--r--drivers/usb/host/uhci-q.c2
-rw-r--r--drivers/usb/host/xhci-ring.c2
-rw-r--r--drivers/usb/misc/Kconfig6
-rw-r--r--drivers/usb/misc/Makefile1
-rw-r--r--drivers/usb/misc/usb3503.c325
-rw-r--r--drivers/usb/misc/usbtest.c13
-rw-r--r--drivers/usb/musb/Kconfig2
-rw-r--r--drivers/usb/musb/am35x.c2
-rw-r--r--drivers/usb/musb/blackfin.c2
-rw-r--r--drivers/usb/musb/da8xx.c7
-rw-r--r--drivers/usb/musb/davinci.c7
-rw-r--r--drivers/usb/musb/musb_core.c1
-rw-r--r--drivers/usb/musb/musb_dsps.c10
-rw-r--r--drivers/usb/musb/musb_gadget.c22
-rw-r--r--drivers/usb/musb/musb_host.c44
-rw-r--r--drivers/usb/musb/omap2430.c91
-rw-r--r--drivers/usb/musb/omap2430.h9
-rw-r--r--drivers/usb/musb/tusb6010.c2
-rw-r--r--drivers/usb/musb/ux500.c12
-rw-r--r--drivers/usb/otg/gpio_vbus.c12
-rw-r--r--drivers/usb/otg/msm_otg.c13
-rw-r--r--drivers/usb/otg/mv_otg.c84
-rw-r--r--drivers/usb/otg/mxs-phy.c26
-rw-r--r--drivers/usb/otg/otg.c235
-rw-r--r--drivers/usb/otg/twl4030-usb.c3
-rw-r--r--drivers/usb/phy/Kconfig28
-rw-r--r--drivers/usb/phy/Makefile3
-rw-r--r--drivers/usb/phy/mv_u3d_phy.c8
-rw-r--r--drivers/usb/phy/omap-control-usb.c295
-rw-r--r--drivers/usb/phy/omap-usb2.c72
-rw-r--r--drivers/usb/phy/omap-usb3.c355
-rw-r--r--drivers/usb/phy/samsung-usbphy.c930
-rw-r--r--drivers/usb/phy/tegra_usb_phy.c132
-rw-r--r--drivers/usb/renesas_usbhs/Kconfig2
-rw-r--r--drivers/usb/renesas_usbhs/common.c9
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c2
-rw-r--r--drivers/usb/serial/Kconfig14
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/aircable.c17
-rw-r--r--drivers/usb/serial/ark3116.c12
-rw-r--r--drivers/usb/serial/belkin_sa.c12
-rw-r--r--drivers/usb/serial/cyberjack.c11
-rw-r--r--drivers/usb/serial/cypress_m8.c6
-rw-r--r--drivers/usb/serial/digi_acceleport.c14
-rw-r--r--drivers/usb/serial/f81232.c15
-rw-r--r--drivers/usb/serial/ftdi_sio.c41
-rw-r--r--drivers/usb/serial/garmin_gps.c9
-rw-r--r--drivers/usb/serial/generic.c12
-rw-r--r--drivers/usb/serial/io_edgeport.c39
-rw-r--r--drivers/usb/serial/io_ti.c121
-rw-r--r--drivers/usb/serial/ir-usb.c9
-rw-r--r--drivers/usb/serial/iuu_phoenix.c9
-rw-r--r--drivers/usb/serial/keyspan.c64
-rw-r--r--drivers/usb/serial/keyspan_pda.c9
-rw-r--r--drivers/usb/serial/kl5kusb105.c10
-rw-r--r--drivers/usb/serial/kobil_sct.c9
-rw-r--r--drivers/usb/serial/mct_u232.c33
-rw-r--r--drivers/usb/serial/metro-usb.c9
-rw-r--r--drivers/usb/serial/mos7720.c9
-rw-r--r--drivers/usb/serial/mos7840.c10
-rw-r--r--drivers/usb/serial/navman.c9
-rw-r--r--drivers/usb/serial/omninet.c10
-rw-r--r--drivers/usb/serial/opticon.c11
-rw-r--r--drivers/usb/serial/option.c16
-rw-r--r--drivers/usb/serial/oti6858.c9
-rw-r--r--drivers/usb/serial/pl2303.c15
-rw-r--r--drivers/usb/serial/quatech2.c47
-rw-r--r--drivers/usb/serial/safe_serial.c15
-rw-r--r--drivers/usb/serial/sierra.c25
-rw-r--r--drivers/usb/serial/spcp8x5.c24
-rw-r--r--drivers/usb/serial/ssu100.c50
-rw-r--r--drivers/usb/serial/symbolserial.c9
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c44
-rw-r--r--drivers/usb/serial/usb-serial.c28
-rw-r--r--drivers/usb/serial/usb_wwan.c25
-rw-r--r--drivers/usb/serial/xsens_mt.c86
-rw-r--r--drivers/usb/storage/initializers.c4
-rw-r--r--drivers/usb/storage/uas.c124
-rw-r--r--drivers/usb/storage/unusual_cypress.h2
-rw-r--r--drivers/usb/storage/usb.c3
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c6
-rw-r--r--drivers/uwb/lc-rc.c21
-rw-r--r--drivers/vhost/Kconfig4
-rw-r--r--drivers/vhost/Kconfig.tcm4
-rw-r--r--drivers/vhost/net.c41
-rw-r--r--drivers/vhost/vhost.c18
-rw-r--r--drivers/vhost/vhost.h2
-rw-r--r--drivers/video/Kconfig41
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/auo_k190x.c1
-rw-r--r--drivers/video/backlight/88pm860x_bl.c5
-rw-r--r--drivers/video/backlight/Kconfig24
-rw-r--r--drivers/video/backlight/Makefile89
-rw-r--r--drivers/video/backlight/aat2870_bl.c2
-rw-r--r--drivers/video/backlight/adp8860_bl.c2
-rw-r--r--drivers/video/backlight/adp8870_bl.c2
-rw-r--r--drivers/video/backlight/ams369fg06.c104
-rw-r--r--drivers/video/backlight/apple_bl.c2
-rw-r--r--drivers/video/backlight/as3711_bl.c380
-rw-r--r--drivers/video/backlight/backlight.c2
-rw-r--r--drivers/video/backlight/corgi_lcd.c18
-rw-r--r--drivers/video/backlight/hx8357.c497
-rw-r--r--drivers/video/backlight/l4f00242t03.c36
-rw-r--r--drivers/video/backlight/ld9040.c109
-rw-r--r--drivers/video/backlight/lm3630_bl.c4
-rw-r--r--drivers/video/backlight/lm3639_bl.c5
-rw-r--r--drivers/video/backlight/lms283gf05.c4
-rw-r--r--drivers/video/backlight/lms501kf03.c441
-rw-r--r--drivers/video/backlight/lp855x_bl.c169
-rw-r--r--drivers/video/backlight/ltv350qv.c10
-rw-r--r--drivers/video/backlight/max8925_bl.c31
-rw-r--r--drivers/video/backlight/omap1_bl.c10
-rw-r--r--drivers/video/backlight/ot200_bl.c1
-rw-r--r--drivers/video/backlight/pwm_bl.c8
-rw-r--r--drivers/video/backlight/s6e63m0.c153
-rw-r--r--drivers/video/backlight/tdo24m.c10
-rw-r--r--drivers/video/backlight/tosa_bl.c2
-rw-r--r--drivers/video/backlight/tosa_lcd.c12
-rw-r--r--drivers/video/backlight/vgg2432a4.c9
-rw-r--r--drivers/video/clps711xfb.c1
-rw-r--r--drivers/video/console/Kconfig2
-rw-r--r--drivers/video/console/fbcon.c10
-rw-r--r--drivers/video/exynos/exynos_dp_core.c37
-rw-r--r--drivers/video/exynos/exynos_mipi_dsi.c70
-rw-r--r--drivers/video/exynos/exynos_mipi_dsi_common.c1
-rw-r--r--drivers/video/exynos/exynos_mipi_dsi_lowlevel.c1
-rw-r--r--drivers/video/exynos/s6e8ax0.c14
-rw-r--r--drivers/video/fsl-diu-fb.c64
-rw-r--r--drivers/video/geode/Kconfig14
-rw-r--r--drivers/video/goldfishfb.c318
-rw-r--r--drivers/video/jz4740_fb.c6
-rw-r--r--drivers/video/mmp/Kconfig11
-rw-r--r--drivers/video/mmp/Makefile1
-rw-r--r--drivers/video/mmp/core.c258
-rw-r--r--drivers/video/mmp/fb/Kconfig13
-rw-r--r--drivers/video/mmp/fb/Makefile1
-rw-r--r--drivers/video/mmp/fb/mmpfb.c685
-rw-r--r--drivers/video/mmp/fb/mmpfb.h54
-rw-r--r--drivers/video/mmp/hw/Kconfig20
-rw-r--r--drivers/video/mmp/hw/Makefile2
-rw-r--r--drivers/video/mmp/hw/mmp_ctrl.c591
-rw-r--r--drivers/video/mmp/hw/mmp_ctrl.h1974
-rw-r--r--drivers/video/mmp/hw/mmp_spi.c180
-rw-r--r--drivers/video/mmp/panel/Kconfig6
-rw-r--r--drivers/video/mmp/panel/Makefile1
-rw-r--r--drivers/video/mmp/panel/tpo_tj032md01bw.c186
-rw-r--r--drivers/video/mx3fb.c2
-rw-r--r--drivers/video/omap/Kconfig2
-rw-r--r--drivers/video/omap2/displays/panel-generic-dpi.c24
-rw-r--r--drivers/video/omap2/dss/dss_features.c1
-rw-r--r--drivers/video/omap2/dss/hdmi.c8
-rw-r--r--drivers/video/omap2/vrfb.c9
-rw-r--r--drivers/video/s3c-fb.c7
-rw-r--r--drivers/virtio/Kconfig8
-rw-r--r--drivers/vlynq/Kconfig2
-rw-r--r--drivers/vme/vme.c1
-rw-r--r--drivers/w1/masters/ds1wm.c52
-rw-r--r--drivers/w1/masters/ds2482.c51
-rw-r--r--drivers/w1/masters/mxc_w1.c49
-rw-r--r--drivers/w1/masters/omap_hdq.c8
-rw-r--r--drivers/w1/masters/w1-gpio.c2
-rw-r--r--drivers/w1/slaves/w1_therm.c36
-rw-r--r--drivers/watchdog/Kconfig12
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/ar7_wdt.c8
-rw-r--r--drivers/watchdog/at32ap700x_wdt.c12
-rw-r--r--drivers/watchdog/at91sam9_wdt.c13
-rw-r--r--drivers/watchdog/coh901327_wdt.c12
-rw-r--r--drivers/watchdog/dw_wdt.c6
-rw-r--r--drivers/watchdog/imx2_wdt.c20
-rw-r--r--drivers/watchdog/jz4740_wdt.c6
-rw-r--r--drivers/watchdog/lantiq_wdt.c8
-rw-r--r--drivers/watchdog/max63xx_wdt.c7
-rw-r--r--drivers/watchdog/pnx4008_wdt.c6
-rw-r--r--drivers/watchdog/txx9wdt.c19
-rw-r--r--drivers/watchdog/ux500_wdt.c171
-rw-r--r--drivers/xen/Kconfig34
-rw-r--r--drivers/xen/Makefile3
-rw-r--r--drivers/xen/events.c126
-rw-r--r--drivers/xen/evtchn.c14
-rw-r--r--drivers/xen/grant-table.c2
-rw-r--r--drivers/xen/pcpu.c38
-rw-r--r--drivers/xen/swiotlb-xen.c4
-rw-r--r--drivers/xen/tmem.c2
-rw-r--r--drivers/xen/xen-acpi-cpuhotplug.c471
-rw-r--r--drivers/xen/xen-acpi-memhotplug.c483
-rw-r--r--drivers/xen/xen-acpi-pad.c3
-rw-r--r--drivers/xen/xen-pciback/pciback_ops.c14
-rw-r--r--drivers/xen/xen-stub.c101
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c2
-rw-r--r--fs/9p/Kconfig3
-rw-r--r--fs/9p/fid.c17
-rw-r--r--fs/9p/v9fs.c34
-rw-r--r--fs/9p/v9fs.h10
-rw-r--r--fs/9p/vfs_dir.c92
-rw-r--r--fs/9p/vfs_file.c5
-rw-r--r--fs/9p/vfs_inode.c9
-rw-r--r--fs/9p/vfs_inode_dotl.c21
-rw-r--r--fs/adfs/Kconfig4
-rw-r--r--fs/affs/Kconfig4
-rw-r--r--fs/afs/Kconfig7
-rw-r--r--fs/afs/afs.h11
-rw-r--r--fs/afs/fsclient.c14
-rw-r--r--fs/afs/inode.c6
-rw-r--r--fs/afs/super.c6
-rw-r--r--fs/aio.c7
-rw-r--r--fs/befs/Kconfig4
-rw-r--r--fs/bfs/Kconfig4
-rw-r--r--fs/binfmt_elf.c14
-rw-r--r--fs/binfmt_elf_fdpic.c7
-rw-r--r--fs/block_dev.c1
-rw-r--r--fs/btrfs/Kconfig3
-rw-r--r--fs/btrfs/extent-tree.c28
-rw-r--r--fs/btrfs/extent_map.c3
-rw-r--r--fs/btrfs/file.c25
-rw-r--r--fs/btrfs/ioctl.c5
-rw-r--r--fs/btrfs/ordered-data.c13
-rw-r--r--fs/btrfs/relocation.c4
-rw-r--r--fs/btrfs/scrub.c25
-rw-r--r--fs/btrfs/transaction.c28
-rw-r--r--fs/btrfs/volumes.c3
-rw-r--r--fs/buffer.c6
-rw-r--r--fs/ceph/Kconfig4
-rw-r--r--fs/ceph/caps.c17
-rw-r--r--fs/ceph/inode.c23
-rw-r--r--fs/ceph/mds_client.c4
-rw-r--r--fs/ceph/mds_client.h4
-rw-r--r--fs/ceph/super.h4
-rw-r--r--fs/cifs/Kconfig8
-rw-r--r--fs/cifs/cifs_fs_sb.h8
-rw-r--r--fs/cifs/cifs_spnego.c6
-rw-r--r--fs/cifs/cifsacl.c47
-rw-r--r--fs/cifs/cifsfs.c14
-rw-r--r--fs/cifs/cifsglob.h22
-rw-r--r--fs/cifs/cifspdu.h1
-rw-r--r--fs/cifs/cifsproto.h9
-rw-r--r--fs/cifs/cifssmb.c10
-rw-r--r--fs/cifs/connect.c66
-rw-r--r--fs/cifs/dir.c18
-rw-r--r--fs/cifs/file.c8
-rw-r--r--fs/cifs/inode.c50
-rw-r--r--fs/cifs/link.c2
-rw-r--r--fs/cifs/misc.c2
-rw-r--r--fs/coda/cache.c4
-rw-r--r--fs/coda/coda_fs_i.h2
-rw-r--r--fs/coda/coda_linux.c8
-rw-r--r--fs/coda/inode.c6
-rw-r--r--fs/coda/psdev.c7
-rw-r--r--fs/coda/upcall.c10
-rw-r--r--fs/compat.c52
-rw-r--r--fs/configfs/dir.c5
-rw-r--r--fs/debugfs/inode.c1
-rw-r--r--fs/devpts/inode.c18
-rw-r--r--fs/dlm/dlm_internal.h3
-rw-r--r--fs/dlm/lock.c15
-rw-r--r--fs/ecryptfs/Kconfig4
-rw-r--r--fs/efs/Kconfig4
-rw-r--r--fs/ext3/super.c1
-rw-r--r--fs/ext4/inode.c2
-rw-r--r--fs/file.c2
-rw-r--r--fs/fuse/cuse.c10
-rw-r--r--fs/fuse/dev.c128
-rw-r--r--fs/fuse/dir.c259
-rw-r--r--fs/fuse/file.c238
-rw-r--r--fs/fuse/fuse_i.h74
-rw-r--r--fs/fuse/inode.c16
-rw-r--r--fs/gfs2/acl.c2
-rw-r--r--fs/gfs2/aops.c17
-rw-r--r--fs/gfs2/bmap.c32
-rw-r--r--fs/gfs2/dir.c32
-rw-r--r--fs/gfs2/file.c6
-rw-r--r--fs/gfs2/glock.c116
-rw-r--r--fs/gfs2/glops.c4
-rw-r--r--fs/gfs2/incore.h11
-rw-r--r--fs/gfs2/inode.c40
-rw-r--r--fs/gfs2/log.c76
-rw-r--r--fs/gfs2/log.h12
-rw-r--r--fs/gfs2/lops.c83
-rw-r--r--fs/gfs2/lops.h14
-rw-r--r--fs/gfs2/meta_io.c35
-rw-r--r--fs/gfs2/meta_io.h3
-rw-r--r--fs/gfs2/ops_fstype.c4
-rw-r--r--fs/gfs2/quota.c142
-rw-r--r--fs/gfs2/quota.h15
-rw-r--r--fs/gfs2/rgrp.c18
-rw-r--r--fs/gfs2/super.c76
-rw-r--r--fs/gfs2/super.h3
-rw-r--r--fs/gfs2/sys.c62
-rw-r--r--fs/gfs2/trans.c124
-rw-r--r--fs/gfs2/trans.h3
-rw-r--r--fs/gfs2/util.c3
-rw-r--r--fs/gfs2/xattr.c40
-rw-r--r--fs/hfs/Kconfig4
-rw-r--r--fs/hpfs/inode.c2
-rw-r--r--fs/jffs2/Kconfig10
-rw-r--r--fs/jfs/super.c2
-rw-r--r--fs/lockd/clntproc.c3
-rw-r--r--fs/logfs/Kconfig4
-rw-r--r--fs/namespace.c29
-rw-r--r--fs/ncpfs/inode.c55
-rw-r--r--fs/ncpfs/ioctl.c25
-rw-r--r--fs/ncpfs/ncp_fs_sb.h6
-rw-r--r--fs/nfs/blocklayout/blocklayout.c1
-rw-r--r--fs/nfs/callback_proc.c61
-rw-r--r--fs/nfs/delegation.c154
-rw-r--r--fs/nfs/delegation.h1
-rw-r--r--fs/nfs/getroot.c3
-rw-r--r--fs/nfs/idmap.c53
-rw-r--r--fs/nfs/inode.c17
-rw-r--r--fs/nfs/internal.h1
-rw-r--r--fs/nfs/nfs2xdr.c19
-rw-r--r--fs/nfs/nfs3xdr.c18
-rw-r--r--fs/nfs/nfs4_fs.h4
-rw-r--r--fs/nfs/nfs4proc.c133
-rw-r--r--fs/nfs/nfs4state.c11
-rw-r--r--fs/nfs/nfs4xdr.c16
-rw-r--r--fs/nfs/objlayout/objio_osd.c1
-rw-r--r--fs/nfs/pnfs.c150
-rw-r--r--fs/nfs/pnfs.h7
-rw-r--r--fs/nfs/super.c49
-rw-r--r--fs/nfs/unlink.c5
-rw-r--r--fs/nfs_common/nfsacl.c41
-rw-r--r--fs/nfsd/Kconfig4
-rw-r--r--fs/nfsd/acl.h2
-rw-r--r--fs/nfsd/auth.c12
-rw-r--r--fs/nfsd/auth.h6
-rw-r--r--fs/nfsd/export.c22
-rw-r--r--fs/nfsd/idmap.h8
-rw-r--r--fs/nfsd/nfs3xdr.c14
-rw-r--r--fs/nfsd/nfs4acl.c63
-rw-r--r--fs/nfsd/nfs4idmap.c38
-rw-r--r--fs/nfsd/nfs4recover.c4
-rw-r--r--fs/nfsd/nfs4state.c12
-rw-r--r--fs/nfsd/nfs4xdr.c54
-rw-r--r--fs/nfsd/nfsd.h6
-rw-r--r--fs/nfsd/nfssvc.c6
-rw-r--r--fs/nfsd/nfsxdr.c14
-rw-r--r--fs/nfsd/state.h4
-rw-r--r--fs/nfsd/vfs.c8
-rw-r--r--fs/nilfs2/Kconfig3
-rw-r--r--fs/nilfs2/file.c2
-rw-r--r--fs/notify/inotify/inotify_user.c4
-rw-r--r--fs/ocfs2/acl.c31
-rw-r--r--fs/ocfs2/alloc.c3
-rw-r--r--fs/ocfs2/aops.c1
-rw-r--r--fs/ocfs2/cluster/heartbeat.c6
-rw-r--r--fs/ocfs2/cluster/tcp.c8
-rw-r--r--fs/ocfs2/dlm/dlmdomain.c4
-rw-r--r--fs/ocfs2/dlmglue.c13
-rw-r--r--fs/ocfs2/extent_map.c3
-rw-r--r--fs/ocfs2/file.c11
-rw-r--r--fs/ocfs2/inode.c12
-rw-r--r--fs/ocfs2/journal.c10
-rw-r--r--fs/ocfs2/localalloc.c8
-rw-r--r--fs/ocfs2/namei.c4
-rw-r--r--fs/ocfs2/refcounttree.c2
-rw-r--r--fs/ocfs2/stack_o2cb.c2
-rw-r--r--fs/ocfs2/super.c6
-rw-r--r--fs/ocfs2/sysfile.c3
-rw-r--r--fs/proc/Makefile3
-rw-r--r--fs/proc/array.c4
-rw-r--r--fs/proc/meminfo.c6
-rw-r--r--fs/proc/proc_net.c14
-rw-r--r--fs/pstore/inode.c18
-rw-r--r--fs/pstore/platform.c35
-rw-r--r--fs/pstore/ram.c10
-rw-r--r--fs/qnx6/inode.c2
-rw-r--r--fs/ramfs/inode.c1
-rw-r--r--fs/select.c1
-rw-r--r--fs/sysfs/group.c42
-rw-r--r--fs/sysfs/mount.c2
-rw-r--r--fs/sysfs/symlink.c45
-rw-r--r--fs/sysfs/sysfs.h2
-rw-r--r--fs/timerfd.c85
-rw-r--r--fs/ubifs/file.c1
-rw-r--r--fs/ufs/Kconfig2
-rw-r--r--fs/xfs/Kconfig4
-rw-r--r--fs/xfs/xfs_alloc.c2
-rw-r--r--fs/xfs/xfs_attr.c9
-rw-r--r--fs/xfs/xfs_bmap.c118
-rw-r--r--fs/xfs/xfs_buf.c2
-rw-r--r--fs/xfs/xfs_buf_item.c118
-rw-r--r--fs/xfs/xfs_buf_item.h14
-rw-r--r--fs/xfs/xfs_dquot.c12
-rw-r--r--fs/xfs/xfs_fsops.c4
-rw-r--r--fs/xfs/xfs_ialloc.c4
-rw-r--r--fs/xfs/xfs_inode.c6
-rw-r--r--fs/xfs/xfs_inode.h1
-rw-r--r--fs/xfs/xfs_inode_item.c16
-rw-r--r--fs/xfs/xfs_inode_item.h4
-rw-r--r--fs/xfs/xfs_iomap.c77
-rw-r--r--fs/xfs/xfs_log.c10
-rw-r--r--fs/xfs/xfs_mount.c12
-rw-r--r--fs/xfs/xfs_mount.h9
-rw-r--r--fs/xfs/xfs_qm.c7
-rw-r--r--fs/xfs/xfs_qm_bhv.c2
-rw-r--r--fs/xfs/xfs_qm_syscalls.c28
-rw-r--r--fs/xfs/xfs_super.c29
-rw-r--r--fs/xfs/xfs_trans.c376
-rw-r--r--fs/xfs/xfs_trans.h18
-rw-r--r--fs/xfs/xfs_trans_ail.c14
-rw-r--r--fs/xfs/xfs_trans_dquot.c10
-rw-r--r--fs/xfs/xfs_trans_inode.c41
-rw-r--r--fs/xfs/xfs_types.h1
-rw-r--r--fs/xfs/xfs_vnodeops.c12
-rw-r--r--include/acpi/acbuffer.h2
-rw-r--r--include/acpi/acconfig.h27
-rw-r--r--include/acpi/acexcep.h2
-rw-r--r--include/acpi/acnames.h2
-rw-r--r--include/acpi/acoutput.h159
-rw-r--r--include/acpi/acpi.h2
-rw-r--r--include/acpi/acpi_bus.h100
-rw-r--r--include/acpi/acpiosxf.h13
-rw-r--r--include/acpi/acpixf.h68
-rw-r--r--include/acpi/acrestyp.h17
-rw-r--r--include/acpi/actbl.h9
-rw-r--r--include/acpi/actbl1.h8
-rw-r--r--include/acpi/actbl2.h25
-rw-r--r--include/acpi/actbl3.h34
-rw-r--r--include/acpi/actypes.h38
-rw-r--r--include/acpi/container.h12
-rw-r--r--include/acpi/platform/acenv.h319
-rw-r--r--include/acpi/platform/acgcc.h6
-rw-r--r--include/acpi/platform/aclinux.h3
-rw-r--r--include/asm-generic/cmpxchg-local.h8
-rw-r--r--include/asm-generic/cputime.h66
-rw-r--r--include/asm-generic/cputime_jiffies.h72
-rw-r--r--include/asm-generic/cputime_nsecs.h104
-rw-r--r--include/asm-generic/io.h20
-rw-r--r--include/asm-generic/pgtable.h10
-rw-r--r--include/asm-generic/syscalls.h16
-rw-r--r--include/asm-generic/unistd.h3
-rw-r--r--include/asm-generic/vmlinux.lds.h32
-rw-r--r--include/clocksource/arm_arch_timer.h63
-rw-r--r--include/linux/acpi.h33
-rw-r--r--include/linux/aer.h4
-rw-r--r--include/linux/amba/sp810.h (renamed from arch/arm/include/asm/hardware/sp810.h)0
-rw-r--r--include/linux/async.h10
-rw-r--r--include/linux/backing-dev.h6
-rw-r--r--include/linux/bcm2835_timer.h22
-rw-r--r--include/linux/bcma/bcma_driver_chipcommon.h4
-rw-r--r--include/linux/bcma/bcma_driver_mips.h11
-rw-r--r--include/linux/bcma/bcma_driver_pci.h2
-rw-r--r--include/linux/bma150.h16
-rw-r--r--include/linux/bootmem.h6
-rw-r--r--include/linux/bug.h47
-rw-r--r--include/linux/can/dev.h11
-rw-r--r--include/linux/can/led.h51
-rw-r--r--include/linux/can/skb.h45
-rw-r--r--include/linux/cgroup.h3
-rw-r--r--include/linux/clk-provider.h6
-rw-r--r--include/linux/clk/tegra.h (renamed from arch/arm/mach-tegra/tegra_cpu_car.h)13
-rw-r--r--include/linux/clockchips.h9
-rw-r--r--include/linux/clocksource.h11
-rw-r--r--include/linux/coda_psdev.h2
-rw-r--r--include/linux/compaction.h5
-rw-r--r--include/linux/compat.h50
-rw-r--r--include/linux/compiler-gcc.h3
-rw-r--r--include/linux/compiler-gcc3.h8
-rw-r--r--include/linux/compiler-gcc4.h36
-rw-r--r--include/linux/compiler.h32
-rw-r--r--include/linux/console.h5
-rw-r--r--include/linux/context_tracking.h28
-rw-r--r--include/linux/cpufreq.h34
-rw-r--r--include/linux/cpuidle.h22
-rw-r--r--include/linux/cyclomx.h77
-rw-r--r--include/linux/cycx_drv.h64
-rw-r--r--include/linux/debugfs.h2
-rw-r--r--include/linux/device.h12
-rw-r--r--include/linux/dma-buf.h2
-rw-r--r--include/linux/dw_apb_timer.h2
-rw-r--r--include/linux/dynamic_debug.h11
-rw-r--r--include/linux/efi.h3
-rw-r--r--include/linux/elevator.h5
-rw-r--r--include/linux/etherdevice.h4
-rw-r--r--include/linux/extcon/extcon-gpio.h (renamed from include/linux/extcon/extcon_gpio.h)0
-rw-r--r--include/linux/firmware-map.h6
-rw-r--r--include/linux/freezer.h5
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/fsl/bestcomm/ata.h (renamed from arch/powerpc/sysdev/bestcomm/ata.h)0
-rw-r--r--include/linux/fsl/bestcomm/bestcomm.h (renamed from arch/powerpc/sysdev/bestcomm/bestcomm.h)0
-rw-r--r--include/linux/fsl/bestcomm/bestcomm_priv.h (renamed from arch/powerpc/sysdev/bestcomm/bestcomm_priv.h)0
-rw-r--r--include/linux/fsl/bestcomm/fec.h (renamed from arch/powerpc/sysdev/bestcomm/fec.h)0
-rw-r--r--include/linux/fsl/bestcomm/gen_bd.h (renamed from arch/powerpc/sysdev/bestcomm/gen_bd.h)0
-rw-r--r--include/linux/fsl/bestcomm/sram.h (renamed from arch/powerpc/sysdev/bestcomm/sram.h)0
-rw-r--r--include/linux/ftrace.h6
-rw-r--r--include/linux/ftrace_event.h6
-rw-r--r--include/linux/genhd.h10
-rw-r--r--include/linux/hardirq.h8
-rw-r--r--include/linux/hid-sensor-hub.h38
-rw-r--r--include/linux/hid-sensor-ids.h9
-rw-r--r--include/linux/hid.h17
-rw-r--r--include/linux/highmem.h6
-rw-r--r--include/linux/huge_mm.h2
-rw-r--r--include/linux/hugetlb.h6
-rw-r--r--include/linux/hwmon.h12
-rw-r--r--include/linux/hyperv.h248
-rw-r--r--include/linux/i2c/twl.h84
-rw-r--r--include/linux/idr.h2
-rw-r--r--include/linux/ieee80211.h155
-rw-r--r--include/linux/if_macvlan.h6
-rw-r--r--include/linux/if_team.h1
-rw-r--r--include/linux/iio/buffer.h13
-rw-r--r--include/linux/iio/common/st_sensors.h280
-rw-r--r--include/linux/iio/common/st_sensors_i2c.h20
-rw-r--r--include/linux/iio/common/st_sensors_spi.h20
-rw-r--r--include/linux/iio/consumer.h14
-rw-r--r--include/linux/iio/driver.h9
-rw-r--r--include/linux/iio/gyro/itg3200.h154
-rw-r--r--include/linux/iio/trigger.h5
-rw-r--r--include/linux/in6.h13
-rw-r--r--include/linux/inetdevice.h6
-rw-r--r--include/linux/init.h1
-rw-r--r--include/linux/init_task.h12
-rw-r--r--include/linux/input/adxl34x.h2
-rw-r--r--include/linux/input/tegra_kbc.h62
-rw-r--r--include/linux/ipv6.h10
-rw-r--r--include/linux/irq.h8
-rw-r--r--include/linux/irq_work.h22
-rw-r--r--include/linux/irqchip.h16
-rw-r--r--include/linux/irqchip/arm-gic.h (renamed from arch/arm/include/asm/hardware/gic.h)44
-rw-r--r--include/linux/irqchip/arm-vic.h (renamed from arch/arm/include/asm/hardware/vic.h)25
-rw-r--r--include/linux/kernel.h6
-rw-r--r--include/linux/kernel_stat.h2
-rw-r--r--include/linux/kexec.h3
-rw-r--r--include/linux/kgdb.h1
-rw-r--r--include/linux/kprobes.h12
-rw-r--r--include/linux/ksm.h18
-rw-r--r--include/linux/kvm_host.h85
-rw-r--r--include/linux/libata.h3
-rw-r--r--include/linux/libps2.h2
-rw-r--r--include/linux/llist.h25
-rw-r--r--include/linux/lockdep.h6
-rw-r--r--include/linux/mailbox.h17
-rw-r--r--include/linux/memblock.h3
-rw-r--r--include/linux/memcontrol.h7
-rw-r--r--include/linux/memory_hotplug.h20
-rw-r--r--include/linux/mfd/88pm80x.h2
-rw-r--r--include/linux/mfd/abx500.h17
-rw-r--r--include/linux/mfd/abx500/ab8500-bm.h37
-rw-r--r--include/linux/mfd/abx500/ab8500-gpio.h16
-rw-r--r--include/linux/mfd/abx500/ab8500-sysctrl.h5
-rw-r--r--include/linux/mfd/abx500/ab8500.h291
-rw-r--r--include/linux/mfd/abx500/ux500_chargalg.h5
-rw-r--r--include/linux/mfd/arizona/core.h4
-rw-r--r--include/linux/mfd/arizona/pdata.h42
-rw-r--r--include/linux/mfd/arizona/registers.h72
-rw-r--r--include/linux/mfd/db8500-prcmu.h20
-rw-r--r--include/linux/mfd/dbx500-prcmu.h139
-rw-r--r--include/linux/mfd/max77693-private.h86
-rw-r--r--include/linux/mfd/max77693.h9
-rw-r--r--include/linux/mfd/max8925.h3
-rw-r--r--include/linux/mfd/max8997-private.h64
-rw-r--r--include/linux/mfd/max8997.h25
-rw-r--r--include/linux/mfd/palmas.h52
-rw-r--r--include/linux/mfd/rtsx_pci.h9
-rw-r--r--include/linux/mfd/samsung/core.h11
-rw-r--r--include/linux/micrel_phy.h9
-rw-r--r--include/linux/migrate.h14
-rw-r--r--include/linux/mlx4/device.h8
-rw-r--r--include/linux/mm.h179
-rw-r--r--include/linux/mm_types.h9
-rw-r--r--include/linux/mman.h4
-rw-r--r--include/linux/mmzone.h58
-rw-r--r--include/linux/module.h4
-rw-r--r--include/linux/mroute.h2
-rw-r--r--include/linux/mroute6.h2
-rw-r--r--include/linux/netdev_features.h3
-rw-r--r--include/linux/netdevice.h113
-rw-r--r--include/linux/netfilter/nf_conntrack_sip.h3
-rw-r--r--include/linux/netfilter/nfnetlink.h4
-rw-r--r--include/linux/netpoll.h28
-rw-r--r--include/linux/nfs4.h6
-rw-r--r--include/linux/nfs_idmap.h9
-rw-r--r--include/linux/nfs_xdr.h4
-rw-r--r--include/linux/nfsd/export.h4
-rw-r--r--include/linux/ntb.h83
-rw-r--r--include/linux/of.h13
-rw-r--r--include/linux/of_gpio.h40
-rw-r--r--include/linux/of_serial.h17
-rw-r--r--include/linux/page-flags-layout.h88
-rw-r--r--include/linux/page-flags.h8
-rw-r--r--include/linux/page-isolation.h19
-rw-r--r--include/linux/pagemap.h1
-rw-r--r--include/linux/pci.h7
-rw-r--r--include/linux/pci_ids.h26
-rw-r--r--include/linux/percpu_counter.h2
-rw-r--r--include/linux/perf_event.h20
-rw-r--r--include/linux/phy.h6
-rw-r--r--include/linux/pinctrl/devinfo.h45
-rw-r--r--include/linux/pinctrl/pinconf-generic.h16
-rw-r--r--include/linux/pinctrl/pinctrl.h1
-rw-r--r--include/linux/platform_data/cpsw.h4
-rw-r--r--include/linux/platform_data/dma-coh901318.h72
-rw-r--r--include/linux/platform_data/i2c-s3c2410.h2
-rw-r--r--include/linux/platform_data/invensense_mpu6050.h31
-rw-r--r--include/linux/platform_data/lp855x.h19
-rw-r--r--include/linux/platform_data/lp8755.h71
-rw-r--r--include/linux/platform_data/max6697.h36
-rw-r--r--include/linux/platform_data/microread.h35
-rw-r--r--include/linux/platform_data/mtd-nand-omap2.h4
-rw-r--r--include/linux/platform_data/mtd-onenand-omap2.h3
-rw-r--r--include/linux/platform_data/s3c-hsotg.h2
-rw-r--r--include/linux/platform_data/samsung-usbphy.h27
-rw-r--r--include/linux/platform_data/serial-sccnxp.h (renamed from include/linux/platform_data/sccnxp.h)6
-rw-r--r--include/linux/platform_data/spi-omap2-mcspi.h3
-rw-r--r--include/linux/platform_data/tsl2563.h (renamed from drivers/staging/iio/light/tsl2563.h)1
-rw-r--r--include/linux/platform_data/usb-omap.h9
-rw-r--r--include/linux/platform_data/usb3503.h19
-rw-r--r--include/linux/platform_data/ux500_wdt.h19
-rw-r--r--include/linux/platform_device.h18
-rw-r--r--include/linux/pm.h2
-rw-r--r--include/linux/pm2301_charger.h61
-rw-r--r--include/linux/pm_runtime.h10
-rw-r--r--include/linux/power/bq2415x_charger.h3
-rw-r--r--include/linux/power_supply.h4
-rw-r--r--include/linux/pps_kernel.h17
-rw-r--r--include/linux/printk.h38
-rw-r--r--include/linux/proc_fs.h20
-rw-r--r--include/linux/profile.h13
-rw-r--r--include/linux/pstore.h6
-rw-r--r--include/linux/pxa2xx_ssp.h18
-rw-r--r--include/linux/random.h6
-rw-r--r--include/linux/rcupdate.h15
-rw-r--r--include/linux/regmap.h97
-rw-r--r--include/linux/regulator/driver.h6
-rw-r--r--include/linux/ring_buffer.h1
-rw-r--r--include/linux/rmap.h2
-rw-r--r--include/linux/rtc.h3
-rw-r--r--include/linux/sched.h222
-rw-r--r--include/linux/sched/rt.h64
-rw-r--r--include/linux/sched/sysctl.h104
-rw-r--r--include/linux/seqlock.h193
-rw-r--r--include/linux/serial_8250.h4
-rw-r--r--include/linux/serial_core.h26
-rw-r--r--include/linux/signal.h52
-rw-r--r--include/linux/skbuff.h61
-rw-r--r--include/linux/smp.h3
-rw-r--r--include/linux/smpboot.h5
-rw-r--r--include/linux/socket.h4
-rw-r--r--include/linux/spi/pxa2xx_spi.h108
-rw-r--r--include/linux/spi/spi.h49
-rw-r--r--include/linux/spi/spi_gpio.h4
-rw-r--r--include/linux/srcu.h26
-rw-r--r--include/linux/ssb/ssb_driver_gige.h23
-rw-r--r--include/linux/ssb/ssb_driver_mips.h5
-rw-r--r--include/linux/sunrpc/auth.h7
-rw-r--r--include/linux/sunrpc/sched.h1
-rw-r--r--include/linux/sunrpc/svcauth.h4
-rw-r--r--include/linux/sunrpc/xprt.h6
-rw-r--r--include/linux/sunserialcore.h4
-rw-r--r--include/linux/sunxi_timer.h2
-rw-r--r--include/linux/suspend.h6
-rw-r--r--include/linux/swap.h49
-rw-r--r--include/linux/swiotlb.h2
-rw-r--r--include/linux/syscalls.h25
-rw-r--r--include/linux/sysfs.h16
-rw-r--r--include/linux/tcp.h4
-rw-r--r--include/linux/tegra-soc.h22
-rw-r--r--include/linux/tick.h17
-rw-r--r--include/linux/time.h17
-rw-r--r--include/linux/tsacct_kern.h3
-rw-r--r--include/linux/tty.h50
-rw-r--r--include/linux/tty_driver.h1
-rw-r--r--include/linux/tty_flip.h28
-rw-r--r--include/linux/tty_ldisc.h11
-rw-r--r--include/linux/uprobes.h23
-rw-r--r--include/linux/usb/composite.h75
-rw-r--r--include/linux/usb/dwc3-omap.h30
-rw-r--r--include/linux/usb/gadget.h13
-rw-r--r--include/linux/usb/musb.h2
-rw-r--r--include/linux/usb/omap_control_usb.h92
-rw-r--r--include/linux/usb/omap_usb.h27
-rw-r--r--include/linux/usb/phy.h43
-rw-r--r--include/linux/usb/samsung_usb_phy.h16
-rw-r--r--include/linux/usb/tegra_usb_phy.h16
-rw-r--r--include/linux/usb/usbnet.h4
-rw-r--r--include/linux/user_namespace.h10
-rw-r--r--include/linux/vexpress.h8
-rw-r--r--include/linux/vm_event_item.h1
-rw-r--r--include/linux/vmstat.h2
-rw-r--r--include/linux/vmw_vmci_api.h82
-rw-r--r--include/linux/vmw_vmci_defs.h880
-rw-r--r--include/linux/vtime.h59
-rw-r--r--include/linux/wanrouter.h127
-rw-r--r--include/linux/wl12xx.h16
-rw-r--r--include/linux/workqueue.h35
-rw-r--r--include/media/adv7343.h52
-rw-r--r--include/media/blackfin/bfin_capture.h5
-rw-r--r--include/media/blackfin/ppi.h36
-rw-r--r--include/media/davinci/vpbe_osd.h5
-rw-r--r--include/media/davinci/vpbe_venc.h5
-rw-r--r--include/media/davinci/vpss.h16
-rw-r--r--include/media/ov7670.h2
-rw-r--r--include/media/ov9650.h27
-rw-r--r--include/media/rc-map.h1
-rw-r--r--include/media/s5c73m3.h55
-rw-r--r--include/media/s5p_fimc.h49
-rw-r--r--include/media/soc_camera.h107
-rw-r--r--include/media/soc_camera_platform.h10
-rw-r--r--include/media/tvp514x.h7
-rw-r--r--include/media/v4l2-common.h2
-rw-r--r--include/media/v4l2-ctrls.h53
-rw-r--r--include/media/v4l2-event.h4
-rw-r--r--include/media/v4l2-image-sizes.h34
-rw-r--r--include/media/v4l2-mem2mem.h2
-rw-r--r--include/net/9p/9p.h14
-rw-r--r--include/net/9p/client.h12
-rw-r--r--include/net/act_api.h27
-rw-r--r--include/net/addrconf.h63
-rw-r--r--include/net/bluetooth/a2mp.h4
-rw-r--r--include/net/bluetooth/bluetooth.h23
-rw-r--r--include/net/bluetooth/hci.h18
-rw-r--r--include/net/bluetooth/hci_core.h5
-rw-r--r--include/net/bluetooth/l2cap.h1
-rw-r--r--include/net/cfg80211.h480
-rw-r--r--include/net/dn_route.h2
-rw-r--r--include/net/dsfield.h6
-rw-r--r--include/net/dst.h9
-rw-r--r--include/net/gro_cells.h4
-rw-r--r--include/net/inet6_hashtables.h5
-rw-r--r--include/net/inet_frag.h84
-rw-r--r--include/net/inet_hashtables.h13
-rw-r--r--include/net/ip6_checksum.h62
-rw-r--r--include/net/ip6_fib.h41
-rw-r--r--include/net/ip6_route.h9
-rw-r--r--include/net/ipv6.h140
-rw-r--r--include/net/irda/irlmp.h2
-rw-r--r--include/net/irda/irttp.h2
-rw-r--r--include/net/mac80211.h313
-rw-r--r--include/net/mrp.h143
-rw-r--r--include/net/ndisc.h32
-rw-r--r--include/net/neighbour.h3
-rw-r--r--include/net/netevent.h3
-rw-r--r--include/net/netfilter/nf_conntrack_acct.h6
-rw-r--r--include/net/netfilter/nf_conntrack_core.h15
-rw-r--r--include/net/netfilter/nf_conntrack_ecache.h19
-rw-r--r--include/net/netfilter/nf_conntrack_expect.h7
-rw-r--r--include/net/netfilter/nf_conntrack_extend.h4
-rw-r--r--include/net/netfilter/nf_conntrack_helper.h11
-rw-r--r--include/net/netfilter/nf_conntrack_l3proto.h11
-rw-r--r--include/net/netfilter/nf_conntrack_l4proto.h10
-rw-r--r--include/net/netfilter/nf_conntrack_labels.h58
-rw-r--r--include/net/netfilter/nf_conntrack_timeout.h8
-rw-r--r--include/net/netfilter/nf_conntrack_timestamp.h21
-rw-r--r--include/net/netfilter/nf_tproxy_core.h2
-rw-r--r--include/net/netns/conntrack.h4
-rw-r--r--include/net/netns/ipv4.h3
-rw-r--r--include/net/netns/ipv6.h1
-rw-r--r--include/net/nfc/hci.h22
-rw-r--r--include/net/nfc/nci_core.h1
-rw-r--r--include/net/nfc/nfc.h8
-rw-r--r--include/net/pkt_cls.h7
-rw-r--r--include/net/pkt_sched.h10
-rw-r--r--include/net/regulatory.h4
-rw-r--r--include/net/sch_generic.h21
-rw-r--r--include/net/sctp/constants.h2
-rw-r--r--include/net/sctp/structs.h5
-rw-r--r--include/net/sock.h10
-rw-r--r--include/net/tcp.h10
-rw-r--r--include/net/transp_v6.h22
-rw-r--r--include/net/xfrm.h40
-rw-r--r--include/scsi/scsi_device.h5
-rw-r--r--include/sound/compress_driver.h8
-rw-r--r--include/sound/core.h12
-rw-r--r--include/sound/cs4271.h15
-rw-r--r--include/sound/da7213.h52
-rwxr-xr-xinclude/sound/max98090.h29
-rw-r--r--include/sound/memalloc.h2
-rw-r--r--include/sound/saif.h16
-rw-r--r--include/sound/sh_fsi.h70
-rw-r--r--include/sound/simple_card.h12
-rw-r--r--include/sound/soc-dai.h8
-rw-r--r--include/sound/soc.h6
-rw-r--r--include/sound/tlv320aic3x.h10
-rw-r--r--include/sound/wm2000.h3
-rw-r--r--include/sound/wm2200.h22
-rw-r--r--include/trace/events/kvm.h2
-rw-r--r--include/trace/events/power.h92
-rw-r--r--include/trace/events/ras.h77
-rw-r--r--include/trace/events/rcu.h31
-rw-r--r--include/trace/events/workqueue.h10
-rw-r--r--include/uapi/asm-generic/signal.h10
-rw-r--r--include/uapi/asm-generic/socket.h5
-rw-r--r--include/uapi/asm-generic/unistd.h4
-rw-r--r--include/uapi/linux/auto_fs.h25
-rw-r--r--include/uapi/linux/can/gw.h2
-rw-r--r--include/uapi/linux/cdrom.h34
-rw-r--r--include/uapi/linux/dvb/frontend.h79
-rw-r--r--include/uapi/linux/dvb/version.h2
-rw-r--r--include/uapi/linux/elf.h12
-rw-r--r--include/uapi/linux/fs.h3
-rw-r--r--include/uapi/linux/fuse.h60
-rw-r--r--include/uapi/linux/if_bridge.h11
-rw-r--r--include/uapi/linux/if_ether.h1
-rw-r--r--include/uapi/linux/if_link.h1
-rw-r--r--include/uapi/linux/if_vlan.h1
-rw-r--r--include/uapi/linux/in6.h20
-rw-r--r--include/uapi/linux/ipv6.h2
-rw-r--r--include/uapi/linux/kvm.h44
-rw-r--r--include/uapi/linux/meye.h8
-rw-r--r--include/uapi/linux/mroute.h3
-rw-r--r--include/uapi/linux/mroute6.h3
-rw-r--r--include/uapi/linux/neighbour.h1
-rw-r--r--include/uapi/linux/netfilter/Kbuild2
-rw-r--r--include/uapi/linux/netfilter/nf_conntrack_common.h1
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_conntrack.h2
-rw-r--r--include/uapi/linux/netfilter/xt_CT.h6
-rw-r--r--include/uapi/linux/netfilter/xt_bpf.h17
-rw-r--r--include/uapi/linux/netfilter/xt_connlabel.h12
-rw-r--r--include/uapi/linux/netfilter/xt_conntrack.h1
-rw-r--r--include/uapi/linux/nfc.h37
-rw-r--r--include/uapi/linux/nl80211.h395
-rw-r--r--include/uapi/linux/perf_event.h3
-rw-r--r--include/uapi/linux/rtnetlink.h1
-rw-r--r--include/uapi/linux/serial_core.h5
-rw-r--r--include/uapi/linux/snmp.h1
-rw-r--r--include/uapi/linux/tcp.h1
-rw-r--r--include/uapi/linux/uhid.h2
-rw-r--r--include/uapi/linux/usb/audio.h6
-rw-r--r--include/uapi/linux/v4l2-controls.h33
-rw-r--r--include/uapi/linux/v4l2-mediabus.h11
-rw-r--r--include/uapi/linux/videodev2.h35
-rw-r--r--include/uapi/linux/virtio_net.h8
-rw-r--r--include/uapi/linux/vm_sockets.h163
-rw-r--r--include/uapi/linux/wanrouter.h443
-rw-r--r--include/uapi/sound/compress_offload.h31
-rw-r--r--include/video/exynos_mipi_dsim.h1
-rw-r--r--include/video/mmp_disp.h352
-rw-r--r--include/video/samsung_fimd.h205
-rw-r--r--include/xen/acpi.h35
-rw-r--r--include/xen/interface/memory.h6
-rw-r--r--include/xen/interface/platform.h21
-rw-r--r--include/xen/interface/xen.h8
-rw-r--r--init/Kconfig143
-rw-r--r--init/do_mounts.c4
-rw-r--r--init/do_mounts_initrd.c3
-rw-r--r--init/init_task.c2
-rw-r--r--init/initramfs.c8
-rw-r--r--init/main.c16
-rw-r--r--ipc/mqueue.c1
-rw-r--r--ipc/shm.c12
-rw-r--r--kernel/Makefile22
-rw-r--r--kernel/acct.c6
-rw-r--r--kernel/async.c167
-rw-r--r--kernel/cgroup.c288
-rw-r--r--kernel/compat.c74
-rw-r--r--kernel/context_tracking.c114
-rw-r--r--kernel/cpu.c6
-rw-r--r--kernel/cpuset.c884
-rw-r--r--kernel/debug/debug_core.c1
-rw-r--r--kernel/debug/gdbstub.c1
-rw-r--r--kernel/delayacct.c7
-rw-r--r--kernel/events/core.c5
-rw-r--r--kernel/events/hw_breakpoint.c2
-rw-r--r--kernel/events/uprobes.c466
-rw-r--r--kernel/exit.c10
-rw-r--r--kernel/fork.c6
-rw-r--r--kernel/futex.c3
-rw-r--r--kernel/futex_compat.c21
-rw-r--r--kernel/gcov/Kconfig2
-rw-r--r--kernel/hrtimer.c38
-rw-r--r--kernel/irq/chip.c30
-rw-r--r--kernel/irq/manage.c3
-rw-r--r--kernel/irq/spurious.c7
-rw-r--r--kernel/irq_work.c150
-rw-r--r--kernel/kexec.c34
-rw-r--r--kernel/kmod.c9
-rw-r--r--kernel/kprobes.c31
-rw-r--r--kernel/lockdep.c15
-rw-r--r--kernel/module.c140
-rw-r--r--kernel/mutex.c1
-rw-r--r--kernel/nsproxy.c3
-rw-r--r--kernel/panic.c34
-rw-r--r--kernel/pid.c2
-rw-r--r--kernel/posix-cpu-timers.c51
-rw-r--r--kernel/posix-timers.c2
-rw-r--r--kernel/power/autosleep.c2
-rw-r--r--kernel/power/main.c29
-rw-r--r--kernel/power/process.c4
-rw-r--r--kernel/power/qos.c9
-rw-r--r--kernel/power/suspend.c69
-rw-r--r--kernel/power/suspend_test.c11
-rw-r--r--kernel/printk.c36
-rw-r--r--kernel/profile.c24
-rw-r--r--kernel/ptrace.c6
-rw-r--r--kernel/rcu.h7
-rw-r--r--kernel/rcupdate.c60
-rw-r--r--kernel/rcutiny.c8
-rw-r--r--kernel/rcutiny_plugin.h56
-rw-r--r--kernel/rcutorture.c66
-rw-r--r--kernel/rcutree.c260
-rw-r--r--kernel/rcutree.h11
-rw-r--r--kernel/rtmutex-debug.c1
-rw-r--r--kernel/rtmutex-tester.c1
-rw-r--r--kernel/rtmutex.c1
-rw-r--r--kernel/sched/auto_group.c3
-rw-r--r--kernel/sched/core.c128
-rw-r--r--kernel/sched/cpupri.c2
-rw-r--r--kernel/sched/cputime.c314
-rw-r--r--kernel/sched/debug.c7
-rw-r--r--kernel/sched/fair.c27
-rw-r--r--kernel/sched/rt.c26
-rw-r--r--kernel/sched/sched.h2
-rw-r--r--kernel/signal.c344
-rw-r--r--kernel/smp.c183
-rw-r--r--kernel/smpboot.c5
-rw-r--r--kernel/softirq.c23
-rw-r--r--kernel/srcu.c37
-rw-r--r--kernel/stop_machine.c156
-rw-r--r--kernel/sys.c293
-rw-r--r--kernel/sysctl.c20
-rw-r--r--kernel/sysctl_binary.c1
-rw-r--r--kernel/time.c12
-rw-r--r--kernel/time/Kconfig9
-rw-r--r--kernel/time/clockevents.c1
-rw-r--r--kernel/time/ntp.c48
-rw-r--r--kernel/time/tick-broadcast.c38
-rw-r--r--kernel/time/tick-sched.c12
-rw-r--r--kernel/time/timekeeping.c71
-rw-r--r--kernel/timeconst.pl6
-rw-r--r--kernel/timer.c2
-rw-r--r--kernel/trace/Kconfig33
-rw-r--r--kernel/trace/blktrace.c2
-rw-r--r--kernel/trace/ftrace.c88
-rw-r--r--kernel/trace/power-traces.c3
-rw-r--r--kernel/trace/ring_buffer.c108
-rw-r--r--kernel/trace/trace.c253
-rw-r--r--kernel/trace/trace.h134
-rw-r--r--kernel/trace/trace_clock.c5
-rw-r--r--kernel/trace/trace_events.c1
-rw-r--r--kernel/trace/trace_functions.c61
-rw-r--r--kernel/trace/trace_functions_graph.c68
-rw-r--r--kernel/trace/trace_probe.h1
-rw-r--r--kernel/trace/trace_sched_wakeup.c2
-rw-r--r--kernel/trace/trace_selftest.c21
-rw-r--r--kernel/trace/trace_syscalls.c18
-rw-r--r--kernel/trace/trace_uprobe.c217
-rw-r--r--kernel/tsacct.c44
-rw-r--r--kernel/user.c4
-rw-r--r--kernel/user_namespace.c62
-rw-r--r--kernel/watchdog.c11
-rw-r--r--kernel/workqueue.c1530
-rw-r--r--kernel/workqueue_internal.h65
-rw-r--r--kernel/workqueue_sched.h9
-rw-r--r--lib/Kconfig2
-rw-r--r--lib/Kconfig.debug122
-rw-r--r--lib/Kconfig.kgdb3
-rw-r--r--lib/bug.c3
-rw-r--r--lib/devres.c58
-rw-r--r--lib/digsig.c41
-rw-r--r--lib/dynamic_debug.c165
-rw-r--r--lib/hexdump.c4
-rw-r--r--lib/locking-selftest.c34
-rw-r--r--lib/mpi/mpi-internal.h4
-rw-r--r--lib/mpi/mpicoder.c8
-rw-r--r--lib/parser.c6
-rw-r--r--lib/rwsem-spinlock.c69
-rw-r--r--lib/rwsem.c75
-rw-r--r--lib/swiotlb.c47
-rw-r--r--lib/vsprintf.c7
-rw-r--r--lib/xz/Kconfig34
-rw-r--r--mm/Kconfig25
-rw-r--r--mm/backing-dev.c11
-rw-r--r--mm/bootmem.c8
-rw-r--r--mm/bounce.c48
-rw-r--r--mm/compaction.c35
-rw-r--r--mm/fadvise.c18
-rw-r--r--mm/filemap.c5
-rw-r--r--mm/fremap.c51
-rw-r--r--mm/huge_memory.c95
-rw-r--r--mm/hugetlb.c34
-rw-r--r--mm/internal.h4
-rw-r--r--mm/kmemleak.c5
-rw-r--r--mm/ksm.c657
-rw-r--r--mm/madvise.c105
-rw-r--r--mm/memblock.c67
-rw-r--r--mm/memcontrol.c477
-rw-r--r--mm/memory-failure.c202
-rw-r--r--mm/memory.c127
-rw-r--r--mm/memory_hotplug.c553
-rw-r--r--mm/mempolicy.c59
-rw-r--r--mm/migrate.c164
-rw-r--r--mm/mincore.c5
-rw-r--r--mm/mlock.c103
-rw-r--r--mm/mm_init.c31
-rw-r--r--mm/mmap.c84
-rw-r--r--mm/mmu_notifier.c84
-rw-r--r--mm/mmzone.c20
-rw-r--r--mm/mremap.c28
-rw-r--r--mm/nobootmem.c23
-rw-r--r--mm/nommu.c29
-rw-r--r--mm/oom_kill.c6
-rw-r--r--mm/page-writeback.c28
-rw-r--r--mm/page_alloc.c461
-rw-r--r--mm/rmap.c30
-rw-r--r--mm/shmem.c50
-rw-r--r--mm/slab.c2
-rw-r--r--mm/slob.c2
-rw-r--r--mm/slub.c4
-rw-r--r--mm/sparse.c12
-rw-r--r--mm/swap.c9
-rw-r--r--mm/swap_state.c58
-rw-r--r--mm/swapfile.c174
-rw-r--r--mm/util.c26
-rw-r--r--mm/vmalloc.c33
-rw-r--r--mm/vmscan.c397
-rw-r--r--mm/vmstat.c7
-rw-r--r--net/802/Kconfig3
-rw-r--r--net/802/Makefile1
-rw-r--r--net/802/mrp.c895
-rw-r--r--net/8021q/Kconfig11
-rw-r--r--net/8021q/Makefile1
-rw-r--r--net/8021q/vlan.c42
-rw-r--r--net/8021q/vlan.h16
-rw-r--r--net/8021q/vlan_core.c25
-rw-r--r--net/8021q/vlan_dev.c20
-rw-r--r--net/8021q/vlan_mvrp.c72
-rw-r--r--net/8021q/vlan_netlink.c2
-rw-r--r--net/8021q/vlanproc.c2
-rw-r--r--net/9p/Kconfig2
-rw-r--r--net/9p/client.c43
-rw-r--r--net/9p/protocol.c49
-rw-r--r--net/9p/trans_virtio.c2
-rw-r--r--net/Kconfig9
-rw-r--r--net/Makefile2
-rw-r--r--net/atm/proc.c2
-rw-r--r--net/ax25/af_ax25.c13
-rw-r--r--net/batman-adv/bat_algo.h2
-rw-r--r--net/batman-adv/bat_iv_ogm.c14
-rw-r--r--net/batman-adv/bitarray.c2
-rw-r--r--net/batman-adv/bitarray.h2
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c135
-rw-r--r--net/batman-adv/bridge_loop_avoidance.h2
-rw-r--r--net/batman-adv/debugfs.c23
-rw-r--r--net/batman-adv/debugfs.h2
-rw-r--r--net/batman-adv/distributed-arp-table.c4
-rw-r--r--net/batman-adv/distributed-arp-table.h2
-rw-r--r--net/batman-adv/gateway_client.c2
-rw-r--r--net/batman-adv/gateway_client.h2
-rw-r--r--net/batman-adv/gateway_common.c2
-rw-r--r--net/batman-adv/gateway_common.h2
-rw-r--r--net/batman-adv/hard-interface.c26
-rw-r--r--net/batman-adv/hard-interface.h2
-rw-r--r--net/batman-adv/hash.c2
-rw-r--r--net/batman-adv/hash.h4
-rw-r--r--net/batman-adv/icmp_socket.c2
-rw-r--r--net/batman-adv/icmp_socket.h2
-rw-r--r--net/batman-adv/main.c2
-rw-r--r--net/batman-adv/main.h12
-rw-r--r--net/batman-adv/originator.c28
-rw-r--r--net/batman-adv/originator.h2
-rw-r--r--net/batman-adv/packet.h2
-rw-r--r--net/batman-adv/ring_buffer.c2
-rw-r--r--net/batman-adv/ring_buffer.h2
-rw-r--r--net/batman-adv/routing.c6
-rw-r--r--net/batman-adv/routing.h2
-rw-r--r--net/batman-adv/send.c9
-rw-r--r--net/batman-adv/send.h2
-rw-r--r--net/batman-adv/soft-interface.c50
-rw-r--r--net/batman-adv/soft-interface.h2
-rw-r--r--net/batman-adv/sysfs.c2
-rw-r--r--net/batman-adv/sysfs.h2
-rw-r--r--net/batman-adv/translation-table.c89
-rw-r--r--net/batman-adv/translation-table.h2
-rw-r--r--net/batman-adv/types.h571
-rw-r--r--net/batman-adv/unicast.c4
-rw-r--r--net/batman-adv/unicast.h2
-rw-r--r--net/batman-adv/vis.c40
-rw-r--r--net/batman-adv/vis.h2
-rw-r--r--net/bluetooth/a2mp.c42
-rw-r--r--net/bluetooth/af_bluetooth.c4
-rw-r--r--net/bluetooth/amp.c25
-rw-r--r--net/bluetooth/bnep/core.c1
-rw-r--r--net/bluetooth/hci_conn.c6
-rw-r--r--net/bluetooth/hci_core.c32
-rw-r--r--net/bluetooth/hci_event.c64
-rw-r--r--net/bluetooth/hci_sysfs.c22
-rw-r--r--net/bluetooth/l2cap_core.c5
-rw-r--r--net/bluetooth/mgmt.c489
-rw-r--r--net/bluetooth/rfcomm/Kconfig1
-rw-r--r--net/bluetooth/rfcomm/core.c4
-rw-r--r--net/bluetooth/rfcomm/tty.c21
-rw-r--r--net/bluetooth/sco.c18
-rw-r--r--net/bluetooth/smp.c13
-rw-r--r--net/bridge/Kconfig14
-rw-r--r--net/bridge/Makefile2
-rw-r--r--net/bridge/br_device.c19
-rw-r--r--net/bridge/br_fdb.c258
-rw-r--r--net/bridge/br_forward.c9
-rw-r--r--net/bridge/br_if.c16
-rw-r--r--net/bridge/br_input.c28
-rw-r--r--net/bridge/br_mdb.c3
-rw-r--r--net/bridge/br_multicast.c69
-rw-r--r--net/bridge/br_netlink.c247
-rw-r--r--net/bridge/br_notify.c2
-rw-r--r--net/bridge/br_private.h178
-rw-r--r--net/bridge/br_stp_bpdu.c2
-rw-r--r--net/bridge/br_stp_if.c4
-rw-r--r--net/bridge/br_sysfs_br.c21
-rw-r--r--net/bridge/br_vlan.c415
-rw-r--r--net/bridge/netfilter/ebt_ulog.c6
-rw-r--r--net/bridge/netfilter/ebtables.c24
-rw-r--r--net/caif/cfcnfg.c2
-rw-r--r--net/can/Kconfig13
-rw-r--r--net/can/bcm.c14
-rw-r--r--net/can/gw.c72
-rw-r--r--net/can/proc.c2
-rw-r--r--net/can/raw.c8
-rw-r--r--net/ceph/Kconfig4
-rw-r--r--net/ceph/ceph_common.c5
-rw-r--r--net/core/Makefile3
-rw-r--r--net/core/datagram.c2
-rw-r--r--net/core/dev.c1720
-rw-r--r--net/core/dev_addr_lists.c74
-rw-r--r--net/core/dev_ioctl.c576
-rw-r--r--net/core/dst.c1
-rw-r--r--net/core/ethtool.c46
-rw-r--r--net/core/filter.c13
-rw-r--r--net/core/flow.c2
-rw-r--r--net/core/flow_dissector.c173
-rw-r--r--net/core/neighbour.c20
-rw-r--r--net/core/net-procfs.c412
-rw-r--r--net/core/net-sysfs.c180
-rw-r--r--net/core/netpoll.c721
-rw-r--r--net/core/netprio_cgroup.c4
-rw-r--r--net/core/pktgen.c205
-rw-r--r--net/core/rtnetlink.c214
-rw-r--r--net/core/skbuff.c113
-rw-r--r--net/core/sock.c24
-rw-r--r--net/core/sysctl_net_core.c14
-rw-r--r--net/dccp/Kconfig4
-rw-r--r--net/dccp/ccids/Kconfig5
-rw-r--r--net/dccp/probe.c6
-rw-r--r--net/decnet/Kconfig4
-rw-r--r--net/decnet/af_decnet.c10
-rw-r--r--net/decnet/dn_dev.c4
-rw-r--r--net/decnet/dn_neigh.c7
-rw-r--r--net/decnet/dn_nsp_out.c2
-rw-r--r--net/decnet/dn_route.c7
-rw-r--r--net/decnet/netfilter/Kconfig2
-rw-r--r--net/dsa/dsa.c6
-rw-r--r--net/dsa/slave.c14
-rw-r--r--net/ethernet/eth.c43
-rw-r--r--net/ieee802154/6lowpan.c94
-rw-r--r--net/ieee802154/Kconfig3
-rw-r--r--net/ieee802154/wpan-class.c5
-rw-r--r--net/ipv4/Kconfig11
-rw-r--r--net/ipv4/af_inet.c25
-rw-r--r--net/ipv4/ah4.c3
-rw-r--r--net/ipv4/arp.c25
-rw-r--r--net/ipv4/devinet.c215
-rw-r--r--net/ipv4/fib_frontend.c2
-rw-r--r--net/ipv4/fib_trie.c18
-rw-r--r--net/ipv4/gre.c118
-rw-r--r--net/ipv4/igmp.c11
-rw-r--r--net/ipv4/inet_connection_sock.c45
-rw-r--r--net/ipv4/inet_fragment.c39
-rw-r--r--net/ipv4/inet_hashtables.c28
-rw-r--r--net/ipv4/ip_fragment.c52
-rw-r--r--net/ipv4/ip_gre.c91
-rw-r--r--net/ipv4/ip_input.c7
-rw-r--r--net/ipv4/ip_output.c1
-rw-r--r--net/ipv4/ipcomp.c1
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/ipip.c4
-rw-r--r--net/ipv4/ipmr.c130
-rw-r--r--net/ipv4/netfilter/Kconfig4
-rw-r--r--net/ipv4/netfilter/arp_tables.c10
-rw-r--r--net/ipv4/netfilter/ip_tables.c10
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c12
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c92
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c14
-rw-r--r--net/ipv4/ping.c4
-rw-r--r--net/ipv4/proc.c17
-rw-r--r--net/ipv4/protocol.c6
-rw-r--r--net/ipv4/raw.c4
-rw-r--r--net/ipv4/route.c13
-rw-r--r--net/ipv4/syncookies.c7
-rw-r--r--net/ipv4/sysctl_net_ipv4.c38
-rw-r--r--net/ipv4/tcp.c16
-rw-r--r--net/ipv4/tcp_cong.c42
-rw-r--r--net/ipv4/tcp_input.c33
-rw-r--r--net/ipv4/tcp_ipv4.c27
-rw-r--r--net/ipv4/tcp_minisocks.c4
-rw-r--r--net/ipv4/tcp_output.c8
-rw-r--r--net/ipv4/tcp_probe.c6
-rw-r--r--net/ipv4/udp.c68
-rw-r--r--net/ipv4/xfrm4_input.c2
-rw-r--r--net/ipv4/xfrm4_mode_tunnel.c4
-rw-r--r--net/ipv4/xfrm4_policy.c58
-rw-r--r--net/ipv6/Kconfig26
-rw-r--r--net/ipv6/Makefile2
-rw-r--r--net/ipv6/addrconf.c28
-rw-r--r--net/ipv6/af_inet6.c3
-rw-r--r--net/ipv6/ah6.c3
-rw-r--r--net/ipv6/anycast.c20
-rw-r--r--net/ipv6/datagram.c35
-rw-r--r--net/ipv6/exthdrs.c3
-rw-r--r--net/ipv6/inet6_connection_sock.c19
-rw-r--r--net/ipv6/inet6_hashtables.c19
-rw-r--r--net/ipv6/ip6_checksum.c97
-rw-r--r--net/ipv6/ip6_flowlabel.c171
-rw-r--r--net/ipv6/ip6_gre.c8
-rw-r--r--net/ipv6/ip6_input.c35
-rw-r--r--net/ipv6/ip6_offload.c1
-rw-r--r--net/ipv6/ip6_output.c77
-rw-r--r--net/ipv6/ip6_tunnel.c4
-rw-r--r--net/ipv6/ip6mr.c136
-rw-r--r--net/ipv6/ipv6_sockglue.c6
-rw-r--r--net/ipv6/mcast.c91
-rw-r--r--net/ipv6/ndisc.c362
-rw-r--r--net/ipv6/netfilter/ip6_tables.c10
-rw-r--r--net/ipv6/netfilter/ip6t_NPT.c18
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c2
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c5
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c94
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c19
-rw-r--r--net/ipv6/proc.c16
-rw-r--r--net/ipv6/raw.c10
-rw-r--r--net/ipv6/reassembly.c28
-rw-r--r--net/ipv6/route.c201
-rw-r--r--net/ipv6/sit.c61
-rw-r--r--net/ipv6/syncookies.c2
-rw-r--r--net/ipv6/tcp_ipv6.c40
-rw-r--r--net/ipv6/udp.c70
-rw-r--r--net/ipv6/udp_offload.c3
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c4
-rw-r--r--net/ipv6/xfrm6_policy.c53
-rw-r--r--net/ipv6/xfrm6_tunnel.c6
-rw-r--r--net/irda/af_irda.c3
-rw-r--r--net/irda/ircomm/Kconfig2
-rw-r--r--net/irda/ircomm/ircomm_tty.c8
-rw-r--r--net/irda/irnet/irnet_ppp.c117
-rw-r--r--net/irda/timer.c2
-rw-r--r--net/iucv/iucv.c5
-rw-r--r--net/key/af_key.c52
-rw-r--r--net/l2tp/Kconfig4
-rw-r--r--net/l2tp/l2tp_core.c223
-rw-r--r--net/l2tp/l2tp_core.h7
-rw-r--r--net/l2tp/l2tp_ip.c16
-rw-r--r--net/l2tp/l2tp_ip6.c10
-rw-r--r--net/l2tp/l2tp_netlink.c1
-rw-r--r--net/l2tp/l2tp_ppp.c11
-rw-r--r--net/lapb/Kconfig3
-rw-r--r--net/mac80211/Kconfig13
-rw-r--r--net/mac80211/Makefile3
-rw-r--r--net/mac80211/agg-rx.c14
-rw-r--r--net/mac80211/agg-tx.c300
-rw-r--r--net/mac80211/cfg.c273
-rw-r--r--net/mac80211/chan.c158
-rw-r--r--net/mac80211/debug.h10
-rw-r--r--net/mac80211/debugfs.c6
-rw-r--r--net/mac80211/debugfs_netdev.c5
-rw-r--r--net/mac80211/debugfs_sta.c5
-rw-r--r--net/mac80211/driver-ops.h99
-rw-r--r--net/mac80211/ht.c115
-rw-r--r--net/mac80211/ibss.c110
-rw-r--r--net/mac80211/ieee80211_i.h222
-rw-r--r--net/mac80211/iface.c181
-rw-r--r--net/mac80211/key.c5
-rw-r--r--net/mac80211/main.c173
-rw-r--r--net/mac80211/mesh.c405
-rw-r--r--net/mac80211/mesh.h143
-rw-r--r--net/mac80211/mesh_hwmp.c120
-rw-r--r--net/mac80211/mesh_pathtbl.c95
-rw-r--r--net/mac80211/mesh_plink.c410
-rw-r--r--net/mac80211/mesh_ps.c598
-rw-r--r--net/mac80211/mesh_sync.c47
-rw-r--r--net/mac80211/mlme.c1192
-rw-r--r--net/mac80211/offchannel.c50
-rw-r--r--net/mac80211/pm.c76
-rw-r--r--net/mac80211/rate.h2
-rw-r--r--net/mac80211/rc80211_minstrel.c29
-rw-r--r--net/mac80211/rc80211_minstrel.h2
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c181
-rw-r--r--net/mac80211/rc80211_minstrel_ht.h5
-rw-r--r--net/mac80211/rc80211_minstrel_ht_debugfs.c112
-rw-r--r--net/mac80211/rx.c178
-rw-r--r--net/mac80211/scan.c75
-rw-r--r--net/mac80211/sta_info.c91
-rw-r--r--net/mac80211/sta_info.h64
-rw-r--r--net/mac80211/status.c25
-rw-r--r--net/mac80211/tkip.c10
-rw-r--r--net/mac80211/trace.h104
-rw-r--r--net/mac80211/tx.c180
-rw-r--r--net/mac80211/util.c107
-rw-r--r--net/mac80211/vht.c172
-rw-r--r--net/mac80211/wme.c13
-rw-r--r--net/mac80211/wpa.c5
-rw-r--r--net/mac802154/Kconfig2
-rw-r--r--net/mac802154/wpan.c9
-rw-r--r--net/netfilter/Kconfig52
-rw-r--r--net/netfilter/Makefile3
-rw-r--r--net/netfilter/ipset/ip_set_core.c26
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c4
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c4
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_netiface.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_app.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c11
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c14
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c35
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c2
-rw-r--r--net/netfilter/nf_conntrack_acct.c36
-rw-r--r--net/netfilter/nf_conntrack_amanda.c5
-rw-r--r--net/netfilter/nf_conntrack_core.c191
-rw-r--r--net/netfilter/nf_conntrack_ecache.c37
-rw-r--r--net/netfilter/nf_conntrack_expect.c58
-rw-r--r--net/netfilter/nf_conntrack_ftp.c10
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c6
-rw-r--r--net/netfilter/nf_conntrack_helper.c76
-rw-r--r--net/netfilter/nf_conntrack_irc.c7
-rw-r--r--net/netfilter/nf_conntrack_labels.c112
-rw-r--r--net/netfilter/nf_conntrack_netlink.c103
-rw-r--r--net/netfilter/nf_conntrack_pptp.c2
-rw-r--r--net/netfilter/nf_conntrack_proto.c92
-rw-r--r--net/netfilter/nf_conntrack_proto_dccp.c43
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c23
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c43
-rw-r--r--net/netfilter/nf_conntrack_proto_udplite.c40
-rw-r--r--net/netfilter/nf_conntrack_sane.c5
-rw-r--r--net/netfilter/nf_conntrack_sip.c90
-rw-r--r--net/netfilter/nf_conntrack_snmp.c1
-rw-r--r--net/netfilter/nf_conntrack_standalone.c69
-rw-r--r--net/netfilter/nf_conntrack_tftp.c8
-rw-r--r--net/netfilter/nf_conntrack_timeout.c23
-rw-r--r--net/netfilter/nf_conntrack_timestamp.c39
-rw-r--r--net/netfilter/nf_nat_amanda.c8
-rw-r--r--net/netfilter/nf_nat_ftp.c5
-rw-r--r--net/netfilter/nf_nat_irc.c8
-rw-r--r--net/netfilter/nf_nat_sip.c72
-rw-r--r--net/netfilter/nf_nat_tftp.c4
-rw-r--r--net/netfilter/nfnetlink.c52
-rw-r--r--net/netfilter/x_tables.c10
-rw-r--r--net/netfilter/xt_CT.c177
-rw-r--r--net/netfilter/xt_bpf.c73
-rw-r--r--net/netfilter/xt_connlabel.c99
-rw-r--r--net/netfilter/xt_hashlimit.c6
-rw-r--r--net/netfilter/xt_recent.c2
-rw-r--r--net/netlink/af_netlink.c7
-rw-r--r--net/netrom/af_netrom.c12
-rw-r--r--net/nfc/core.c54
-rw-r--r--net/nfc/hci/command.c7
-rw-r--r--net/nfc/hci/core.c57
-rw-r--r--net/nfc/hci/hcp.c7
-rw-r--r--net/nfc/llcp/commands.c2
-rw-r--r--net/nfc/llcp/llcp.c49
-rw-r--r--net/nfc/llcp/llcp.h1
-rw-r--r--net/nfc/llcp/sock.c22
-rw-r--r--net/nfc/nci/core.c2
-rw-r--r--net/nfc/netlink.c1
-rw-r--r--net/openvswitch/datapath.c5
-rw-r--r--net/openvswitch/vport-internal_dev.c3
-rw-r--r--net/openvswitch/vport-netdev.c16
-rw-r--r--net/packet/af_packet.c14
-rw-r--r--net/phonet/pn_dev.c8
-rw-r--r--net/rds/Kconfig4
-rw-r--r--net/rfkill/input.c8
-rw-r--r--net/rose/af_rose.c19
-rw-r--r--net/rxrpc/Kconfig2
-rw-r--r--net/rxrpc/af_rxrpc.c13
-rw-r--r--net/sched/act_api.c18
-rw-r--r--net/sched/act_csum.c2
-rw-r--r--net/sched/act_gact.c5
-rw-r--r--net/sched/act_ipt.c8
-rw-r--r--net/sched/act_mirred.c7
-rw-r--r--net/sched/act_nat.c2
-rw-r--r--net/sched/act_pedit.c8
-rw-r--r--net/sched/act_police.c105
-rw-r--r--net/sched/act_simple.c5
-rw-r--r--net/sched/act_skbedit.c5
-rw-r--r--net/sched/cls_api.c11
-rw-r--r--net/sched/cls_basic.c13
-rw-r--r--net/sched/cls_cgroup.c5
-rw-r--r--net/sched/cls_flow.c4
-rw-r--r--net/sched/cls_fw.c10
-rw-r--r--net/sched/cls_route.c15
-rw-r--r--net/sched/cls_rsvp.h4
-rw-r--r--net/sched/cls_tcindex.c14
-rw-r--r--net/sched/cls_u32.c13
-rw-r--r--net/sched/sch_api.c10
-rw-r--r--net/sched/sch_generic.c37
-rw-r--r--net/sched/sch_htb.c80
-rw-r--r--net/sched/sch_netem.c12
-rw-r--r--net/sched/sch_tbf.c76
-rw-r--r--net/sctp/Kconfig4
-rw-r--r--net/sctp/associola.c5
-rw-r--r--net/sctp/auth.c31
-rw-r--r--net/sctp/endpointola.c6
-rw-r--r--net/sctp/input.c3
-rw-r--r--net/sctp/ipv6.c5
-rw-r--r--net/sctp/outqueue.c4
-rw-r--r--net/sctp/probe.c27
-rw-r--r--net/sctp/protocol.c2
-rw-r--r--net/sctp/sm_make_chunk.c33
-rw-r--r--net/sctp/sm_sideeffect.c6
-rw-r--r--net/sctp/socket.c2
-rw-r--r--net/sctp/transport.c20
-rw-r--r--net/socket.c19
-rw-r--r--net/sunrpc/Kconfig2
-rw-r--r--net/sunrpc/auth.c6
-rw-r--r--net/sunrpc/auth_generic.c16
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c50
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c4
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c18
-rw-r--r--net/sunrpc/auth_unix.c36
-rw-r--r--net/sunrpc/clnt.c16
-rw-r--r--net/sunrpc/svcauth_unix.c43
-rw-r--r--net/sunrpc/svcsock.c2
-rw-r--r--net/sunrpc/xprt.c21
-rw-r--r--net/sunrpc/xprtrdma/rpc_rdma.c4
-rw-r--r--net/sunrpc/xprtrdma/transport.c7
-rw-r--r--net/sunrpc/xprtrdma/xprt_rdma.h6
-rw-r--r--net/sunrpc/xprtsock.c16
-rw-r--r--net/tipc/Kconfig4
-rw-r--r--net/tipc/bcast.c1
-rw-r--r--net/tipc/socket.c103
-rw-r--r--net/unix/af_unix.c7
-rw-r--r--net/vmw_vsock/Kconfig28
-rw-r--r--net/vmw_vsock/Makefile7
-rw-r--r--net/vmw_vsock/af_vsock.c2012
-rw-r--r--net/vmw_vsock/af_vsock.h175
-rw-r--r--net/vmw_vsock/vmci_transport.c2155
-rw-r--r--net/vmw_vsock/vmci_transport.h139
-rw-r--r--net/vmw_vsock/vmci_transport_notify.c680
-rw-r--r--net/vmw_vsock/vmci_transport_notify.h83
-rw-r--r--net/vmw_vsock/vmci_transport_notify_qstate.c438
-rw-r--r--net/vmw_vsock/vsock_addr.c86
-rw-r--r--net/vmw_vsock/vsock_addr.h32
-rw-r--r--net/wanrouter/Kconfig27
-rw-r--r--net/wanrouter/Makefile7
-rw-r--r--net/wanrouter/patchlevel1
-rw-r--r--net/wanrouter/wanmain.c782
-rw-r--r--net/wanrouter/wanproc.c380
-rw-r--r--net/wireless/ap.c62
-rw-r--r--net/wireless/chan.c146
-rw-r--r--net/wireless/core.c39
-rw-r--r--net/wireless/core.h60
-rw-r--r--net/wireless/ethtool.c4
-rw-r--r--net/wireless/ibss.c4
-rw-r--r--net/wireless/mesh.c8
-rw-r--r--net/wireless/mlme.c162
-rw-r--r--net/wireless/nl80211.c1148
-rw-r--r--net/wireless/nl80211.h7
-rw-r--r--net/wireless/rdev-ops.h12
-rw-r--r--net/wireless/reg.c1142
-rw-r--r--net/wireless/reg.h7
-rw-r--r--net/wireless/scan.c632
-rw-r--r--net/wireless/sme.c25
-rw-r--r--net/wireless/sysfs.c2
-rw-r--r--net/wireless/trace.h98
-rw-r--r--net/wireless/util.c42
-rw-r--r--net/wireless/wext-proc.c5
-rw-r--r--net/x25/Kconfig3
-rw-r--r--net/xfrm/Kconfig16
-rw-r--r--net/xfrm/xfrm_algo.c68
-rw-r--r--net/xfrm/xfrm_output.c6
-rw-r--r--net/xfrm/xfrm_policy.c271
-rw-r--r--net/xfrm/xfrm_proc.c7
-rw-r--r--net/xfrm/xfrm_state.c165
-rw-r--r--net/xfrm/xfrm_user.c2
-rw-r--r--samples/Kconfig6
-rw-r--r--samples/Makefile2
-rw-r--r--samples/tracepoints/Makefile6
-rw-r--r--samples/tracepoints/tp-samples-trace.h11
-rw-r--r--samples/tracepoints/tracepoint-probe-sample.c57
-rw-r--r--samples/tracepoints/tracepoint-probe-sample2.c44
-rw-r--r--samples/tracepoints/tracepoint-sample.c57
-rw-r--r--scripts/Makefile.lib14
-rw-r--r--scripts/basic/fixdep.c2
-rwxr-xr-xscripts/checkpatch.pl26
-rw-r--r--scripts/coccinelle/api/devm_ioremap_resource.cocci90
-rwxr-xr-xscripts/get_maintainer.pl2
-rw-r--r--scripts/mod/modpost.c2
-rwxr-xr-xscripts/sign-file134
-rw-r--r--scripts/sortextable.h2
-rwxr-xr-xscripts/tags.sh24
-rw-r--r--security/device_cgroup.c21
-rw-r--r--security/integrity/Kconfig12
-rw-r--r--security/integrity/Makefile1
-rw-r--r--security/integrity/digsig.c11
-rw-r--r--security/integrity/digsig_asymmetric.c115
-rw-r--r--security/integrity/evm/Kconfig13
-rw-r--r--security/integrity/evm/evm.h2
-rw-r--r--security/integrity/evm/evm_crypto.c3
-rw-r--r--security/integrity/evm/evm_main.c10
-rw-r--r--security/integrity/evm/evm_secfs.c6
-rw-r--r--security/integrity/iint.c10
-rw-r--r--security/integrity/ima/ima.h21
-rw-r--r--security/integrity/ima/ima_api.c27
-rw-r--r--security/integrity/ima/ima_appraise.c92
-rw-r--r--security/integrity/ima/ima_crypto.c81
-rw-r--r--security/integrity/ima/ima_init.c3
-rw-r--r--security/integrity/ima/ima_main.c139
-rw-r--r--security/integrity/ima/ima_policy.c139
-rw-r--r--security/integrity/integrity.h62
-rw-r--r--security/keys/process_keys.c2
-rw-r--r--sound/arm/pxa2xx-ac97-lib.c8
-rw-r--r--sound/core/compress_offload.c114
-rw-r--r--sound/drivers/aloop.c5
-rw-r--r--sound/drivers/vx/vx_core.c3
-rw-r--r--sound/pci/Kconfig1
-rw-r--r--sound/pci/ali5451/ali5451.c2
-rw-r--r--sound/pci/atiixp.c5
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c23
-rw-r--r--sound/pci/hda/Kconfig25
-rw-r--r--sound/pci/hda/ca0132_regs.h409
-rw-r--r--sound/pci/hda/hda_auto_parser.c129
-rw-r--r--sound/pci/hda/hda_auto_parser.h81
-rw-r--r--sound/pci/hda/hda_codec.c664
-rw-r--r--sound/pci/hda/hda_codec.h93
-rw-r--r--sound/pci/hda/hda_eld.c52
-rw-r--r--sound/pci/hda/hda_generic.c5290
-rw-r--r--sound/pci/hda/hda_generic.h303
-rw-r--r--sound/pci/hda/hda_hwdep.c87
-rw-r--r--sound/pci/hda/hda_intel.c154
-rw-r--r--sound/pci/hda/hda_jack.c9
-rw-r--r--sound/pci/hda/hda_local.h118
-rw-r--r--sound/pci/hda/hda_proc.c35
-rw-r--r--sound/pci/hda/patch_analog.c1418
-rw-r--r--sound/pci/hda/patch_ca0110.c490
-rw-r--r--sound/pci/hda/patch_ca0132.c4374
-rw-r--r--sound/pci/hda/patch_cirrus.c1292
-rw-r--r--sound/pci/hda/patch_cmedia.c166
-rw-r--r--sound/pci/hda/patch_conexant.c1378
-rw-r--r--sound/pci/hda/patch_hdmi.c227
-rw-r--r--sound/pci/hda/patch_realtek.c4349
-rw-r--r--sound/pci/hda/patch_sigmatel.c7429
-rw-r--r--sound/pci/hda/patch_via.c2630
-rw-r--r--sound/pci/ice1712/wm8766.c2
-rw-r--r--sound/pci/intel8x0.c10
-rw-r--r--sound/pci/maestro3.c10
-rw-r--r--sound/pci/nm256/nm256.c3
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c3
-rw-r--r--sound/pci/rme32.c2
-rw-r--r--sound/pci/rme9652/hdsp.c462
-rw-r--r--sound/pci/via82xx.c2
-rw-r--r--sound/soc/atmel/Kconfig6
-rw-r--r--sound/soc/atmel/atmel-pcm-pdc.c4
-rw-r--r--sound/soc/atmel/atmel-pcm.c2
-rw-r--r--sound/soc/atmel/atmel-pcm.h6
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c14
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c6
-rw-r--r--sound/soc/cirrus/ep93xx-ac97.c7
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c6
-rw-r--r--sound/soc/codecs/Kconfig9
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ab8500-codec.c2
-rw-r--r--sound/soc/codecs/ak4642.c33
-rw-r--r--sound/soc/codecs/arizona.c264
-rw-r--r--sound/soc/codecs/arizona.h8
-rw-r--r--sound/soc/codecs/cs4271.c34
-rw-r--r--sound/soc/codecs/cs42l52.c4
-rw-r--r--sound/soc/codecs/da7213.c1599
-rw-r--r--sound/soc/codecs/da7213.h523
-rw-r--r--sound/soc/codecs/jz4740.c6
-rwxr-xr-x[-rw-r--r--]sound/soc/codecs/max98090.c2685
-rwxr-xr-xsound/soc/codecs/max98090.h1549
-rw-r--r--sound/soc/codecs/tlv320aic3x.c87
-rw-r--r--sound/soc/codecs/tlv320aic3x.h4
-rw-r--r--sound/soc/codecs/tlv320dac33.c16
-rw-r--r--sound/soc/codecs/twl4030.c85
-rw-r--r--sound/soc/codecs/twl6040.c62
-rw-r--r--sound/soc/codecs/wm2000.c66
-rw-r--r--sound/soc/codecs/wm2000.h3
-rw-r--r--sound/soc/codecs/wm2200.c62
-rw-r--r--sound/soc/codecs/wm5100.c13
-rw-r--r--sound/soc/codecs/wm5102.c163
-rw-r--r--sound/soc/codecs/wm5110.c98
-rw-r--r--sound/soc/codecs/wm8350.c10
-rw-r--r--sound/soc/codecs/wm8804.c3
-rw-r--r--sound/soc/codecs/wm8962.c37
-rw-r--r--sound/soc/codecs/wm8974.c6
-rw-r--r--sound/soc/codecs/wm8978.c6
-rw-r--r--sound/soc/codecs/wm8983.c47
-rw-r--r--sound/soc/codecs/wm8985.c49
-rw-r--r--sound/soc/codecs/wm8994.c10
-rw-r--r--sound/soc/codecs/wm_adsp.c525
-rw-r--r--sound/soc/codecs/wm_adsp.h18
-rw-r--r--sound/soc/codecs/wmfw.h15
-rw-r--r--sound/soc/davinci/davinci-evm.c6
-rw-r--r--sound/soc/davinci/davinci-mcasp.c2
-rw-r--r--sound/soc/dwc/designware_i2s.c4
-rw-r--r--sound/soc/fsl/Kconfig9
-rw-r--r--sound/soc/fsl/Makefile5
-rw-r--r--sound/soc/fsl/imx-audmux.c8
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c21
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c22
-rw-r--r--sound/soc/fsl/imx-pcm.c35
-rw-r--r--sound/soc/fsl/imx-pcm.h18
-rw-r--r--sound/soc/fsl/imx-ssi.c7
-rw-r--r--sound/soc/fsl/mpc5200_dma.c4
-rw-r--r--sound/soc/generic/simple-card.c63
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c8
-rw-r--r--sound/soc/mxs/mxs-saif.c57
-rw-r--r--sound/soc/omap/Kconfig19
-rw-r--r--sound/soc/omap/Makefile4
-rw-r--r--sound/soc/omap/n810.c4
-rw-r--r--sound/soc/omap/omap-hdmi.c2
-rw-r--r--sound/soc/omap/omap-mcpdm.c4
-rw-r--r--sound/soc/omap/omap-pcm.c14
-rw-r--r--sound/soc/omap/omap-twl4030.c204
-rw-r--r--sound/soc/omap/omap3pandora.c8
-rw-r--r--sound/soc/omap/rx51.c8
-rw-r--r--sound/soc/omap/sdp3430.c278
-rw-r--r--sound/soc/omap/zoom2.c207
-rw-r--r--sound/soc/pxa/mmp-sspa.c6
-rw-r--r--sound/soc/pxa/palm27x.c38
-rw-r--r--sound/soc/samsung/Kconfig6
-rw-r--r--sound/soc/samsung/dma.c3
-rw-r--r--sound/soc/samsung/dma.h1
-rw-r--r--sound/soc/samsung/h1940_uda1380.c13
-rw-r--r--sound/soc/samsung/i2s.c267
-rw-r--r--sound/soc/samsung/i2s.h7
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c8
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c2
-rw-r--r--sound/soc/samsung/smdk_wm8580.c7
-rw-r--r--sound/soc/samsung/smdk_wm8994.c30
-rw-r--r--sound/soc/sh/fsi.c242
-rw-r--r--sound/soc/soc-compress.c123
-rw-r--r--sound/soc/soc-core.c137
-rw-r--r--sound/soc/soc-dapm.c6
-rw-r--r--sound/soc/soc-pcm.c19
-rw-r--r--sound/soc/tegra/Kconfig19
-rw-r--r--sound/soc/tegra/Makefile4
-rw-r--r--sound/soc/tegra/tegra20_ac97.c480
-rw-r--r--sound/soc/tegra/tegra20_ac97.h95
-rw-r--r--sound/soc/tegra/tegra20_das.c13
-rw-r--r--sound/soc/tegra/tegra30_ahub.c20
-rw-r--r--sound/soc/tegra/tegra30_i2s.c4
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c53
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h1
-rw-r--r--sound/soc/tegra/tegra_wm9712.c176
-rw-r--r--sound/soc/ux500/mop500.c2
-rw-r--r--sound/usb/caiaq/device.c8
-rw-r--r--sound/usb/card.c2
-rw-r--r--sound/usb/mixer.c1
-rw-r--r--sound/usb/mixer_maps.c4
-rw-r--r--sound/usb/mixer_quirks.c72
-rw-r--r--sound/usb/pcm.c26
-rw-r--r--sound/usb/quirks-table.h73
-rw-r--r--sound/usb/quirks.c13
-rw-r--r--tools/Makefile21
-rw-r--r--tools/cgroup/.gitignore1
-rw-r--r--tools/cgroup/Makefile11
-rw-r--r--tools/cgroup/cgroup_event_listener.c (renamed from Documentation/cgroups/cgroup_event_listener.c)72
-rw-r--r--tools/hv/hv_kvp_daemon.c79
-rwxr-xr-xtools/hv/hv_set_ifconfig.sh24
-rw-r--r--tools/lguest/lguest.txt8
-rw-r--r--tools/lib/traceevent/event-parse.c49
-rw-r--r--tools/lib/traceevent/event-parse.h3
-rw-r--r--tools/lib/traceevent/event-utils.h3
-rw-r--r--tools/lib/traceevent/parse-filter.c3
-rw-r--r--tools/lib/traceevent/parse-utils.c19
-rw-r--r--tools/lib/traceevent/trace-seq.c3
-rw-r--r--tools/perf/Documentation/Makefile4
-rw-r--r--tools/perf/Documentation/perf-annotate.txt7
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt7
-rw-r--r--tools/perf/Documentation/perf-diff.txt4
-rw-r--r--tools/perf/Documentation/perf-evlist.txt4
-rw-r--r--tools/perf/Documentation/perf-report.txt41
-rw-r--r--tools/perf/Documentation/perf-script-python.txt2
-rw-r--r--tools/perf/Documentation/perf-stat.txt11
-rw-r--r--tools/perf/Documentation/perf-test.txt4
-rw-r--r--tools/perf/Documentation/perf-top.txt2
-rw-r--r--tools/perf/Makefile104
-rw-r--r--tools/perf/arch/common.c1
-rw-r--r--tools/perf/bench/bench.h1
-rw-r--r--tools/perf/bench/numa.c1731
-rw-r--r--tools/perf/builtin-annotate.c30
-rw-r--r--tools/perf/builtin-bench.c19
-rw-r--r--tools/perf/builtin-buildid-cache.c96
-rw-r--r--tools/perf/builtin-buildid-list.c21
-rw-r--r--tools/perf/builtin-diff.c205
-rw-r--r--tools/perf/builtin-evlist.c88
-rw-r--r--tools/perf/builtin-kmem.c16
-rw-r--r--tools/perf/builtin-kvm.c3
-rw-r--r--tools/perf/builtin-record.c168
-rw-r--r--tools/perf/builtin-report.c93
-rw-r--r--tools/perf/builtin-sched.c6
-rw-r--r--tools/perf/builtin-script.c17
-rw-r--r--tools/perf/builtin-stat.c328
-rw-r--r--tools/perf/builtin-top.c372
-rw-r--r--tools/perf/builtin-trace.c2
-rw-r--r--tools/perf/config/feature-tests.mak11
-rw-r--r--tools/perf/config/utilities.mak6
-rw-r--r--tools/perf/perf.c32
-rw-r--r--tools/perf/perf.h32
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report3
-rw-r--r--tools/perf/scripts/perl/rwtop.pl6
-rw-r--r--tools/perf/scripts/perl/workqueue-stats.pl129
-rw-r--r--tools/perf/tests/attr.c9
-rw-r--r--tools/perf/tests/attr.py27
-rw-r--r--tools/perf/tests/attr/base-record2
-rw-r--r--tools/perf/tests/attr/test-record-group2
-rw-r--r--tools/perf/tests/attr/test-record-group14
-rw-r--r--tools/perf/tests/builtin-test.c40
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c4
-rw-r--r--tools/perf/tests/hists_link.c500
-rw-r--r--tools/perf/tests/mmap-basic.c40
-rw-r--r--tools/perf/tests/open-syscall-all-cpus.c19
-rw-r--r--tools/perf/tests/open-syscall.c17
-rw-r--r--tools/perf/tests/parse-events.c324
-rw-r--r--tools/perf/tests/perf-record.c20
-rw-r--r--tools/perf/tests/pmu.c11
-rw-r--r--tools/perf/tests/python-use.c23
-rw-r--r--tools/perf/tests/tests.h11
-rw-r--r--tools/perf/tests/util.c30
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c7
-rw-r--r--tools/perf/ui/browser.c6
-rw-r--r--tools/perf/ui/browsers/annotate.c33
-rw-r--r--tools/perf/ui/browsers/hists.c341
-rw-r--r--tools/perf/ui/gtk/annotate.c229
-rw-r--r--tools/perf/ui/gtk/browser.c235
-rw-r--r--tools/perf/ui/gtk/gtk.h10
-rw-r--r--tools/perf/ui/gtk/helpline.c23
-rw-r--r--tools/perf/ui/gtk/hists.c312
-rw-r--r--tools/perf/ui/helpline.c12
-rw-r--r--tools/perf/ui/helpline.h22
-rw-r--r--tools/perf/ui/hist.c481
-rw-r--r--tools/perf/ui/keysyms.h1
-rw-r--r--tools/perf/ui/setup.c3
-rw-r--r--tools/perf/ui/stdio/hist.c25
-rw-r--r--tools/perf/ui/tui/helpline.c29
-rw-r--r--tools/perf/ui/util.c1
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN4
-rw-r--r--tools/perf/util/annotate.c2
-rw-r--r--tools/perf/util/annotate.h24
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h5
-rw-r--r--tools/perf/util/cpumap.c54
-rw-r--r--tools/perf/util/cpumap.h9
-rw-r--r--tools/perf/util/debug.c28
-rw-r--r--tools/perf/util/debug.h34
-rw-r--r--tools/perf/util/dso.c6
-rw-r--r--tools/perf/util/dso.h2
-rw-r--r--tools/perf/util/event.c4
-rw-r--r--tools/perf/util/evlist.c31
-rw-r--r--tools/perf/util/evlist.h34
-rw-r--r--tools/perf/util/evsel.c370
-rw-r--r--tools/perf/util/evsel.h50
-rw-r--r--tools/perf/util/header.c266
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/hist.c142
-rw-r--r--tools/perf/util/hist.h26
-rw-r--r--tools/perf/util/include/linux/bitops.h1
-rw-r--r--tools/perf/util/intlist.c36
-rw-r--r--tools/perf/util/intlist.h2
-rw-r--r--tools/perf/util/machine.c784
-rw-r--r--tools/perf/util/machine.h41
-rw-r--r--tools/perf/util/map.c121
-rw-r--r--tools/perf/util/map.h24
-rw-r--r--tools/perf/util/parse-events.c96
-rw-r--r--tools/perf/util/parse-events.h22
-rw-r--r--tools/perf/util/parse-events.y75
-rw-r--r--tools/perf/util/pmu.c46
-rw-r--r--tools/perf/util/pmu.h15
-rw-r--r--tools/perf/util/pmu.y1
-rw-r--r--tools/perf/util/probe-finder.c10
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/python.c9
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c1
-rw-r--r--tools/perf/util/session.c325
-rw-r--r--tools/perf/util/session.h35
-rw-r--r--tools/perf/util/sort.c245
-rw-r--r--tools/perf/util/sort.h15
-rw-r--r--tools/perf/util/string.c18
-rw-r--r--tools/perf/util/strlist.c54
-rw-r--r--tools/perf/util/strlist.h42
-rw-r--r--tools/perf/util/symbol-elf.c14
-rw-r--r--tools/perf/util/symbol-minimal.c1
-rw-r--r--tools/perf/util/symbol.c536
-rw-r--r--tools/perf/util/symbol.h9
-rw-r--r--tools/perf/util/sysfs.c2
-rw-r--r--tools/perf/util/thread.c20
-rw-r--r--tools/perf/util/thread.h1
-rw-r--r--tools/perf/util/top.c22
-rw-r--r--tools/perf/util/top.h10
-rw-r--r--tools/perf/util/util.c24
-rw-r--r--tools/perf/util/util.h4
-rw-r--r--tools/power/acpi/Makefile2
-rw-r--r--tools/power/x86/turbostat/turbostat.836
-rw-r--r--tools/power/x86/turbostat/turbostat.c48
-rw-r--r--tools/testing/ktest/examples/include/patchcheck.conf37
-rwxr-xr-xtools/testing/ktest/ktest.pl190
-rw-r--r--tools/testing/ktest/sample.conf44
-rw-r--r--tools/usb/testusb.c31
-rw-r--r--virt/kvm/ioapic.c48
-rw-r--r--virt/kvm/ioapic.h4
-rw-r--r--virt/kvm/iommu.c4
-rw-r--r--virt/kvm/irq_comm.c25
-rw-r--r--virt/kvm/kvm_main.c201
7400 files changed, 380908 insertions, 220393 deletions
diff --git a/CREDITS b/CREDITS
index 2346b09ca8bb..948e0fb9a70e 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1572,12 +1572,12 @@ S: Wantage, New Jersey 07461
S: USA
N: Harald Hoyer
-E: harald.hoyer@parzelle.de
-W: http://parzelle.de/
+E: harald@redhat.com
+W: http://www.harald-hoyer.de
D: ip_masq_quake
D: md boot support
-S: Hohe Strasse 30
-S: D-70176 Stuttgart
+S: Am Strand 5
+S: D-19063 Schwerin
S: Germany
N: Jan Hubicka
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 8afe64fb2009..0f3e8bbab8d7 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -2,7 +2,7 @@
This is a brief list of all the files in ./linux/Documentation and what
they contain. If you add a documentation file, please list it here in
alphabetical order as well, or risk being hunted down like a rabid dog.
-Please try and keep the descriptions small enough to fit on one line.
+Please keep the descriptions small enough to fit on one line.
Thanks -- Paul G.
Following translations are available on the WWW:
@@ -20,24 +20,33 @@ BUG-HUNTING
Changes
- list of changes that break older software packages.
CodingStyle
- - how the boss likes the C code in the kernel to look.
-development-process/
- - An extended tutorial on how to work with the kernel development
- process.
+ - how the maintainers expect the C code in the kernel to look.
DMA-API.txt
- DMA API, pci_ API & extensions for non-consistent memory machines.
+DMA-API-HOWTO.txt
+ - Dynamic DMA mapping Guide
DMA-ISA-LPC.txt
- How to do DMA with ISA (and LPC) devices.
+DMA-attributes.txt
+ - listing of the various possible attributes a DMA region can have
DocBook/
- directory with DocBook templates etc. for kernel documentation.
+EDID/
+ - directory with info on customizing EDID for broken gfx/displays.
HOWTO
- the process and procedures of how to do Linux kernel development.
IPMI.txt
- info on Linux Intelligent Platform Management Interface (IPMI) Driver.
IRQ-affinity.txt
- how to select which CPU(s) handle which interrupt events on SMP.
+IRQ-domain.txt
+ - info on inerrupt numbering and setting up IRQ domains.
IRQ.txt
- description of what an IRQ is.
+Intel-IOMMU.txt
+ - basic info on the Intel IOMMU virtualization support.
+Makefile
+ - some files in Documentation dir are actually sample code to build
ManagementStyle
- how to (attempt to) manage kernel hackers.
RCU/
@@ -66,10 +75,16 @@ applying-patches.txt
- description of various trees and how to apply their patches.
arm/
- directory with info about Linux on the ARM architecture.
+arm64/
+ - directory with info about Linux on the 64 bit ARM architecture.
atomic_ops.txt
- semantics and behavior of atomic and bitmask operations.
auxdisplay/
- misc. LCD driver documentation (cfag12864b, ks0108).
+backlight/
+ - directory with info on controlling backlights in flat panel displays
+bad_memory.txt
+ - how to use kernel parameters to exclude bad RAM regions.
basic_profiling.txt
- basic instructions for those who wants to profile Linux kernel.
binfmt_misc.txt
@@ -80,8 +95,14 @@ block/
- info on the Block I/O (BIO) layer.
blockdev/
- info on block devices & drivers
+braille-console.txt
+ - info on how to use serial devices for Braille support.
+bt8xxgpio.txt
+ - info on how to modify a bt8xx video card for GPIO usage.
btmrvl.txt
- info on Marvell Bluetooth driver usage.
+bus-devices/
+ - directory with info on TI GPMC (General Purpose Memory Controller)
bus-virt-phys-mapping.txt
- how to access I/O mapped memory from within device drivers.
cachetlb.txt
@@ -90,6 +111,12 @@ cdrom/
- directory with information on the CD-ROM drivers that Linux has.
cgroups/
- cgroups features, including cpusets and memory controller.
+circular-buffers.txt
+ - how to make use of the existing circular buffer infrastructure
+clk.txt
+ - info on the common clock framework
+coccinelle.txt
+ - info on how to get and use the Coccinelle code checking tool.
connector/
- docs on the netlink based userspace<->kernel space communication mod.
console/
@@ -114,24 +141,42 @@ dcdbas.txt
- information on the Dell Systems Management Base Driver.
debugging-modules.txt
- some notes on debugging modules after Linux 2.6.3.
+debugging-via-ohci1394.txt
+ - how to use firewire like a hardware debugger memory reader.
dell_rbu.txt
- document demonstrating the use of the Dell Remote BIOS Update driver.
+development-process/
+ - how to work with the mainline kernel development process.
device-mapper/
- directory with info on Device Mapper.
devices.txt
- plain ASCII listing of all the nodes in /dev/ with major minor #'s.
+devicetree/
+ - directory with info on device tree files used by OF/PowerPC/ARM
+digsig.txt
+ -info on the Digital Signature Verification API
+dma-buf-sharing.txt
+ - the DMA Buffer Sharing API Guide
+dmaengine.txt
+ -the DMA Engine API Guide
dontdiff
- file containing a list of files that should never be diff'ed.
driver-model/
- directory with info about Linux driver model.
dvb/
- info on Linux Digital Video Broadcast (DVB) subsystem.
+dynamic-debug-howto.txt
+ - how to use the dynamic debug (dyndbg) feature.
early-userspace/
- info about initramfs, klibc, and userspace early during boot.
edac.txt
- information on EDAC - Error Detection And Correction
eisa.txt
- info on EISA bus support.
+email-clients.txt
+ - info on how to use e-mail to send un-mangled (git) patches.
+extcon/
+ - directory with porting guide for Android kernel switch driver.
fault-injection/
- dir with docs about the fault injection capabilities infrastructure.
fb/
@@ -140,12 +185,22 @@ filesystems/
- info on the vfs and the various filesystems that Linux supports.
firmware_class/
- request_firmware() hotplug interface info.
+flexible-arrays.txt
+ - how to make use of flexible sized arrays in linux
frv/
- Fujitsu FR-V Linux documentation.
+futex-requeue-pi.txt
+ - info on requeueing of tasks from a non-PI futex to a PI futex
+gcov.txt
+ - use of GCC's coverage testing tool "gcov" with the Linux kernel
gpio.txt
- overview of GPIO (General Purpose Input/Output) access conventions.
+hid/
+ - directory with information on human interface devices
highuid.txt
- notes on the change from 16 bit to 32 bit user/group IDs.
+hwspinlock.txt
+ - hardware spinlock provides hardware assistance for synchronization
timers/
- info on the timer related topics
hw_random.txt
@@ -162,10 +217,14 @@ ia64/
- directory with info about Linux on Intel 64 bit architecture.
infiniband/
- directory with documents concerning Linux InfiniBand support.
+init.txt
+ - what to do when the kernel can't find the 1st process to run.
initrd.txt
- how to use the RAM disk as an initial/temporary root filesystem.
input/
- info on Linux input device support.
+intel_txt.txt
+ - info on intel Trusted Execution Technology (intel TXT).
io-mapping.txt
- description of io_mapping functions in linux/io-mapping.h
io_ordering.txt
@@ -182,6 +241,8 @@ isdn/
- directory with info on the Linux ISDN support, and supported cards.
java.txt
- info on the in-kernel binary support for Java(tm).
+ja_JP/
+ - directory with Japanese translations of various documents
kbuild/
- directory with info about the kernel build process.
kdump/
@@ -192,6 +253,12 @@ kernel-docs.txt
- listing of various WWW + books that document kernel internals.
kernel-parameters.txt
- summary listing of command line / boot prompt args for the kernel.
+kmemcheck.txt
+ - info on dynamic checker that detects uses of uninitialized memory.
+kmemleak.txt
+ - info on how to make use of the kernel memory leak detection system
+ko_KR/
+ - directory with Korean translations of various documents
kobject.txt
- info of the kobject infrastructure of the Linux kernel.
kprobes.txt
@@ -208,6 +275,8 @@ local_ops.txt
- semantics and behavior of local atomic operations.
lockdep-design.txt
- documentation on the runtime locking correctness validator.
+lockstat.txt
+ - info on collecting statistics on locks (and contention).
lockup-watchdogs.txt
- info on soft and hard lockup detectors (aka nmi_watchdog).
logo.gif
@@ -220,16 +289,26 @@ magic-number.txt
- list of magic numbers used to mark/protect kernel data structures.
md.txt
- info on boot arguments for the multiple devices driver.
+media-framework.txt
+ - info on media framework, its data structures, functions and usage.
memory-barriers.txt
- info on Linux kernel memory barriers.
+memory-devices/
+ - directory with info on parts like the Texas Instruments EMIF driver
memory-hotplug.txt
- Hotpluggable memory support, how to use and current status.
memory.txt
- info on typical Linux memory problems.
mips/
- directory with info about Linux on MIPS architecture.
+misc-devices/
+ - directory with info about devices using the misc dev subsystem
mmc/
- directory with info about the MMC subsystem
+mn10300/
+ - directory with info about the mn10300 architecture port
+mtd/
+ - directory with info about memory technology devices (flash)
mono.txt
- how to execute Mono-based .NET binaries with the help of BINFMT_MISC.
mutex-design.txt
@@ -240,6 +319,8 @@ netlabel/
- directory with information on the NetLabel subsystem.
networking/
- directory with info on various aspects of networking with Linux.
+nfc/
+ - directory relating info about Near Field Communications support.
nommu-mmap.txt
- documentation about no-mmu memory mapping support.
numastat.txt
@@ -256,26 +337,46 @@ parport-lowlevel.txt
- description and usage of the low level parallel port functions.
pcmcia/
- info on the Linux PCMCIA driver.
+percpu-rw-semaphore.txt
+ - RCU based read-write semaphore optimized for locking for reading
pi-futex.txt
- - documentation on lightweight PI-futexes.
+ - documentation on lightweight priority inheritance futexes.
+pinctrl.txt
+ - info on pinctrl subsystem and the PINMUX/PINCONF and drivers
pnp.txt
- Linux Plug and Play documentation.
power/
- directory with info on Linux PCI power management.
powerpc/
- directory with info on using Linux with the PowerPC.
+prctl/
+ - directory with info on the priveledge control subsystem
preempt-locking.txt
- info on locking under a preemptive kernel.
printk-formats.txt
- how to get printk format specifiers right
+pps/
+ - directory with information on the pulse-per-second support
+ptp/
+ - directory with info on support for IEEE 1588 PTP clocks in Linux.
+pwm.txt
+ - info on the pulse width modulation driver subsystem
ramoops.txt
- documentation of the ramoops oops/panic logging module.
+rapidio/
+ - directory with info on RapidIO packet-based fabric interconnect
rbtree.txt
- info on what red-black trees are and what they are for.
+remoteproc.txt
+ - info on how to handle remote processor (e.g. AMP) offloads/usage.
+rfkill.txt
+ - info on the radio frequency kill switch subsystem/support.
robust-futex-ABI.txt
- documentation of the robust futex ABI.
robust-futexes.txt
- a description of what robust futexes are.
+rpmsg.txt
+ - info on the Remote Processor Messaging (rpmsg) Framework
rt-mutex-design.txt
- description of the RealTime mutex implementation design.
rt-mutex.txt
@@ -300,10 +401,10 @@ sgi-visws.txt
- short blurb on the SGI Visual Workstations.
sh/
- directory with info on porting Linux to a new architecture.
+smsc_ece1099.txt
+ -info on the smsc Keyboard Scan Expansion/GPIO Expansion device.
sound/
- directory with info on sound card support.
-sparc/
- - directory with info on using Linux on Sparc architecture.
sparse.txt
- info on how to obtain and use the sparse tool for typechecking.
spi/
@@ -314,6 +415,8 @@ stable_api_nonsense.txt
- info on why the kernel does not have a stable in-kernel api or abi.
stable_kernel_rules.txt
- rules and procedures for the -stable kernel releases.
+static-keys.txt
+ - info on how static keys allow debug code in hotpaths via patching
svga.txt
- short guide on selecting video modes at boot via VGA BIOS.
sysfs-rules.txt
@@ -322,27 +425,53 @@ sysctl/
- directory with info on the /proc/sys/* files.
sysrq.txt
- info on the magic SysRq key.
-telephony/
- - directory with info on telephony (e.g. voice over IP) support.
+target/
+ - directory with info on generating TCM v4 fabric .ko modules
+thermal/
+ - directory with information on managing thermal issues (CPU/temp)
+trace/
+ - directory with info on tracing technologies within linux
+unaligned-memory-access.txt
+ - info on how to avoid arch breaking unaligned memory access in code.
unicode.txt
- info on the Unicode character/font mapping used in Linux.
unshare.txt
- description of the Linux unshare system call.
usb/
- directory with info regarding the Universal Serial Bus.
+vDSO/
+ - directory with info regarding virtual dynamic shared objects
+vfio.txt
+ - info on Virtual Function I/O used in guest/hypervisor instances.
+vgaarbiter.txt
+ - info on enable/disable the legacy decoding on different VGA devices
video-output.txt
- sysfs class driver interface to enable/disable a video output device.
video4linux/
- directory with info regarding video/TV/radio cards and linux.
+virtual/
+ - directory with information on the various linux virtualizations.
vm/
- directory with info on the Linux vm code.
+vme_api.txt
+ - file relating info on the VME bus API in linux
volatile-considered-harmful.txt
- Why the "volatile" type class should not be used
w1/
- directory with documents regarding the 1-wire (w1) subsystem.
watchdog/
- how to auto-reboot Linux if it has "fallen and can't get up". ;-)
+wimax/
+ - directory with info about Intel Wireless Wimax Connections
+workqueue.txt
+ - information on the Concurrency Managed Workqueue implementation
x86/x86_64/
- directory with info on Linux support for AMD x86-64 (Hammer) machines.
+xtensa/
+ - directory with documents relating to arch/xtensa port/implementation
+xz.txt
+ - how to make use of the XZ data compression within linux kernel
+zh_CN/
+ - directory with Chinese translations of various documents
zorro.txt
- info on writing drivers for Zorro bus devices found on Amigas.
diff --git a/Documentation/ABI/stable/sysfs-class-tpm b/Documentation/ABI/stable/sysfs-class-tpm
new file mode 100644
index 000000000000..a60b45e2493b
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-class-tpm
@@ -0,0 +1,185 @@
+What: /sys/class/misc/tpmX/device/
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: tpmdd-devel@lists.sf.net
+Description: The device/ directory under a specific TPM instance exposes
+ the properties of that TPM chip
+
+
+What: /sys/class/misc/tpmX/device/active
+Date: April 2006
+KernelVersion: 2.6.17
+Contact: tpmdd-devel@lists.sf.net
+Description: The "active" property prints a '1' if the TPM chip is accepting
+ commands. An inactive TPM chip still contains all the state of
+ an active chip (Storage Root Key, NVRAM, etc), and can be
+ visible to the OS, but will only accept a restricted set of
+ commands. See the TPM Main Specification part 2, Structures,
+ section 17 for more information on which commands are
+ available.
+
+What: /sys/class/misc/tpmX/device/cancel
+Date: June 2005
+KernelVersion: 2.6.13
+Contact: tpmdd-devel@lists.sf.net
+Description: The "cancel" property allows you to cancel the currently
+ pending TPM command. Writing any value to cancel will call the
+ TPM vendor specific cancel operation.
+
+What: /sys/class/misc/tpmX/device/caps
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: tpmdd-devel@lists.sf.net
+Description: The "caps" property contains TPM manufacturer and version info.
+
+ Example output:
+
+ Manufacturer: 0x53544d20
+ TCG version: 1.2
+ Firmware version: 8.16
+
+ Manufacturer is a hex dump of the 4 byte manufacturer info
+ space in a TPM. TCG version shows the TCG TPM spec level that
+ the chip supports. Firmware version is that of the chip and
+ is manufacturer specific.
+
+What: /sys/class/misc/tpmX/device/durations
+Date: March 2011
+KernelVersion: 3.1
+Contact: tpmdd-devel@lists.sf.net
+Description: The "durations" property shows the 3 vendor-specific values
+ used to wait for a short, medium and long TPM command. All
+ TPM commands are categorized as short, medium or long in
+ execution time, so that the driver doesn't have to wait
+ any longer than necessary before starting to poll for a
+ result.
+
+ Example output:
+
+ 3015000 4508000 180995000 [original]
+
+ Here the short, medium and long durations are displayed in
+ usecs. "[original]" indicates that the values are displayed
+ unmodified from when they were queried from the chip.
+ Durations can be modified in the case where a buggy chip
+ reports them in msec instead of usec and they need to be
+ scaled to be displayed in usecs. In this case "[adjusted]"
+ will be displayed in place of "[original]".
+
+What: /sys/class/misc/tpmX/device/enabled
+Date: April 2006
+KernelVersion: 2.6.17
+Contact: tpmdd-devel@lists.sf.net
+Description: The "enabled" property prints a '1' if the TPM chip is enabled,
+ meaning that it should be visible to the OS. This property
+ may be visible but produce a '0' after some operation that
+ disables the TPM.
+
+What: /sys/class/misc/tpmX/device/owned
+Date: April 2006
+KernelVersion: 2.6.17
+Contact: tpmdd-devel@lists.sf.net
+Description: The "owned" property produces a '1' if the TPM_TakeOwnership
+ ordinal has been executed successfully in the chip. A '0'
+ indicates that ownership hasn't been taken.
+
+What: /sys/class/misc/tpmX/device/pcrs
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: tpmdd-devel@lists.sf.net
+Description: The "pcrs" property will dump the current value of all Platform
+ Configuration Registers in the TPM. Note that since these
+ values may be constantly changing, the output is only valid
+ for a snapshot in time.
+
+ Example output:
+
+ PCR-00: 3A 3F 78 0F 11 A4 B4 99 69 FC AA 80 CD 6E 39 57 C3 3B 22 75
+ PCR-01: 3A 3F 78 0F 11 A4 B4 99 69 FC AA 80 CD 6E 39 57 C3 3B 22 75
+ PCR-02: 3A 3F 78 0F 11 A4 B4 99 69 FC AA 80 CD 6E 39 57 C3 3B 22 75
+ PCR-03: 3A 3F 78 0F 11 A4 B4 99 69 FC AA 80 CD 6E 39 57 C3 3B 22 75
+ PCR-04: 3A 3F 78 0F 11 A4 B4 99 69 FC AA 80 CD 6E 39 57 C3 3B 22 75
+ ...
+
+ The number of PCRs and hex bytes needed to represent a PCR
+ value will vary depending on TPM chip version. For TPM 1.1 and
+ 1.2 chips, PCRs represent SHA-1 hashes, which are 20 bytes
+ long. Use the "caps" property to determine TPM version.
+
+What: /sys/class/misc/tpmX/device/pubek
+Date: April 2005
+KernelVersion: 2.6.12
+Contact: tpmdd-devel@lists.sf.net
+Description: The "pubek" property will return the TPM's public endorsement
+ key if possible. If the TPM has had ownership established and
+ is version 1.2, the pubek will not be available without the
+ owner's authorization. Since the TPM driver doesn't store any
+ secrets, it can't authorize its own request for the pubek,
+ making it unaccessible. The public endorsement key is gener-
+ ated at TPM menufacture time and exists for the life of the
+ chip.
+
+ Example output:
+
+ Algorithm: 00 00 00 01
+ Encscheme: 00 03
+ Sigscheme: 00 01
+ Parameters: 00 00 08 00 00 00 00 02 00 00 00 00
+ Modulus length: 256
+ Modulus:
+ B4 76 41 82 C9 20 2C 10 18 40 BC 8B E5 44 4C 6C
+ 3A B2 92 0C A4 9B 2A 83 EB 5C 12 85 04 48 A0 B6
+ 1E E4 81 84 CE B2 F2 45 1C F0 85 99 61 02 4D EB
+ 86 C4 F7 F3 29 60 52 93 6B B2 E5 AB 8B A9 09 E3
+ D7 0E 7D CA 41 BF 43 07 65 86 3C 8C 13 7A D0 8B
+ 82 5E 96 0B F8 1F 5F 34 06 DA A2 52 C1 A9 D5 26
+ 0F F4 04 4B D9 3F 2D F2 AC 2F 74 64 1F 8B CD 3E
+ 1E 30 38 6C 70 63 69 AB E2 50 DF 49 05 2E E1 8D
+ 6F 78 44 DA 57 43 69 EE 76 6C 38 8A E9 8E A3 F0
+ A7 1F 3C A8 D0 12 15 3E CA 0E BD FA 24 CD 33 C6
+ 47 AE A4 18 83 8E 22 39 75 93 86 E6 FD 66 48 B6
+ 10 AD 94 14 65 F9 6A 17 78 BD 16 53 84 30 BF 70
+ E0 DC 65 FD 3C C6 B0 1E BF B9 C1 B5 6C EF B1 3A
+ F8 28 05 83 62 26 11 DC B4 6B 5A 97 FF 32 26 B6
+ F7 02 71 CF 15 AE 16 DD D1 C1 8E A8 CF 9B 50 7B
+ C3 91 FF 44 1E CF 7C 39 FE 17 77 21 20 BD CE 9B
+
+ Possible values:
+
+ Algorithm: TPM_ALG_RSA (1)
+ Encscheme: TPM_ES_RSAESPKCSv15 (2)
+ TPM_ES_RSAESOAEP_SHA1_MGF1 (3)
+ Sigscheme: TPM_SS_NONE (1)
+ Parameters, a byte string of 3 u32 values:
+ Key Length (bits): 00 00 08 00 (2048)
+ Num primes: 00 00 00 02 (2)
+ Exponent Size: 00 00 00 00 (0 means the
+ default exp)
+ Modulus Length: 256 (bytes)
+ Modulus: The 256 byte Endorsement Key modulus
+
+What: /sys/class/misc/tpmX/device/temp_deactivated
+Date: April 2006
+KernelVersion: 2.6.17
+Contact: tpmdd-devel@lists.sf.net
+Description: The "temp_deactivated" property returns a '1' if the chip has
+ been temporarily dectivated, usually until the next power
+ cycle. Whether a warm boot (reboot) will clear a TPM chip
+ from a temp_deactivated state is platform specific.
+
+What: /sys/class/misc/tpmX/device/timeouts
+Date: March 2011
+KernelVersion: 3.1
+Contact: tpmdd-devel@lists.sf.net
+Description: The "timeouts" property shows the 4 vendor-specific values
+ for the TPM's interface spec timeouts. The use of these
+ timeouts is defined by the TPM interface spec that the chip
+ conforms to.
+
+ Example output:
+
+ 750000 750000 750000 750000 [original]
+
+ The four timeout values are shown in usecs, with a trailing
+ "[original]" or "[adjusted]" depending on whether the values
+ were scaled by the driver to be reported in usec from msecs.
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index ec0a38ef3145..f1c5cc9d17a8 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -18,17 +18,21 @@ Description:
rule format: action [condition ...]
action: measure | dont_measure | appraise | dont_appraise | audit
- condition:= base | lsm
- base: [[func=] [mask=] [fsmagic=] [uid=] [fowner]]
+ condition:= base | lsm [option]
+ base: [[func=] [mask=] [fsmagic=] [fsuuid=] [uid=]
+ [fowner]]
lsm: [[subj_user=] [subj_role=] [subj_type=]
[obj_user=] [obj_role=] [obj_type=]]
+ option: [[appraise_type=]]
- base: func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK][MODULE_CHECK]
+ base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
fsmagic:= hex value
+ fsuuid:= file system UUID (e.g 8bcbe394-4f13-4144-be8e-5aa9ea2ce2f6)
uid:= decimal value
fowner:=decimal value
lsm: are LSM specific
+ option: appraise_type:= [imasig]
default policy:
# PROC_SUPER_MAGIC
diff --git a/Documentation/ABI/testing/pstore b/Documentation/ABI/testing/pstore
index ff1df4e3b059..5fca9f5e10a3 100644
--- a/Documentation/ABI/testing/pstore
+++ b/Documentation/ABI/testing/pstore
@@ -1,4 +1,4 @@
-Where: /dev/pstore/...
+Where: /sys/fs/pstore/... (or /dev/pstore/...)
Date: March 2011
Kernel Version: 2.6.39
Contact: tony.luck@intel.com
@@ -11,9 +11,9 @@ Description: Generic interface to platform dependent persistent storage.
of the console log is captured, but other interesting
data can also be saved.
- # mount -t pstore -o kmsg_bytes=8000 - /dev/pstore
+ # mount -t pstore -o kmsg_bytes=8000 - /sys/fs/pstore
- $ ls -l /dev/pstore
+ $ ls -l /sys/fs/pstore/
total 0
-r--r--r-- 1 root root 7896 Nov 30 15:38 dmesg-erst-1
@@ -27,9 +27,9 @@ Description: Generic interface to platform dependent persistent storage.
the file will signal to the underlying persistent storage
device that it can reclaim the space for later re-use.
- $ rm /dev/pstore/dmesg-erst-1
+ $ rm /sys/fs/pstore/dmesg-erst-1
- The expectation is that all files in /dev/pstore
+ The expectation is that all files in /sys/fs/pstore/
will be saved elsewhere and erased from persistent store
soon after boot to free up space ready for the next
catastrophe.
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events
new file mode 100644
index 000000000000..0adeb524c0d4
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events
@@ -0,0 +1,62 @@
+What: /sys/devices/cpu/events/
+ /sys/devices/cpu/events/branch-misses
+ /sys/devices/cpu/events/cache-references
+ /sys/devices/cpu/events/cache-misses
+ /sys/devices/cpu/events/stalled-cycles-frontend
+ /sys/devices/cpu/events/branch-instructions
+ /sys/devices/cpu/events/stalled-cycles-backend
+ /sys/devices/cpu/events/instructions
+ /sys/devices/cpu/events/cpu-cycles
+
+Date: 2013/01/08
+
+Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org>
+
+Description: Generic performance monitoring events
+
+ A collection of performance monitoring events that may be
+ supported by many/most CPUs. These events can be monitored
+ using the 'perf(1)' tool.
+
+ The contents of each file would look like:
+
+ event=0xNNNN
+
+ where 'N' is a hex digit and the number '0xNNNN' shows the
+ "raw code" for the perf event identified by the file's
+ "basename".
+
+
+What: /sys/devices/cpu/events/PM_LD_MISS_L1
+ /sys/devices/cpu/events/PM_LD_REF_L1
+ /sys/devices/cpu/events/PM_CYC
+ /sys/devices/cpu/events/PM_BRU_FIN
+ /sys/devices/cpu/events/PM_GCT_NOSLOT_CYC
+ /sys/devices/cpu/events/PM_BRU_MPRED
+ /sys/devices/cpu/events/PM_INST_CMPL
+ /sys/devices/cpu/events/PM_CMPLU_STALL
+
+Date: 2013/01/08
+
+Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org>
+ Linux Powerpc mailing list <linuxppc-dev@ozlabs.org>
+
+Description: POWER-systems specific performance monitoring events
+
+ A collection of performance monitoring events that may be
+ supported by the POWER CPU. These events can be monitored
+ using the 'perf(1)' tool.
+
+ These events may not be supported by other CPUs.
+
+ The contents of each file would look like:
+
+ event=0xNNNN
+
+ where 'N' is a hex digit and the number '0xNNNN' shows the
+ "raw code" for the perf event identified by the file's
+ "basename".
+
+ Further, multiple terms like 'event=0xNNNN' can be specified
+ and separated with comma. All available terms are defined in
+ the /sys/bus/event_source/devices/<dev>/format file.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-mpu6050 b/Documentation/ABI/testing/sysfs-bus-iio-mpu6050
new file mode 100644
index 000000000000..cb53737aacbf
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-mpu6050
@@ -0,0 +1,13 @@
+What: /sys/bus/iio/devices/iio:deviceX/in_gyro_matrix
+What: /sys/bus/iio/devices/iio:deviceX/in_accel_matrix
+What: /sys/bus/iio/devices/iio:deviceX/in_magn_matrix
+KernelVersion: 3.4.0
+Contact: linux-iio@vger.kernel.org
+Description:
+ This is mounting matrix for motion sensors. Mounting matrix
+ is a 3x3 unitary matrix. A typical mounting matrix would look like
+ [0, 1, 0; 1, 0, 0; 0, 0, -1]. Using this information, it would be
+ easy to tell the relative positions among sensors as well as their
+ positions relative to the board that holds these sensors. Identity matrix
+ [1, 0, 0; 0, 1, 0; 0, 0, 1] means sensor chip and device are perfectly
+ aligned with each other. All axes are exactly the same.
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index b6fbe514a869..c8baaf53594a 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -227,3 +227,12 @@ Contact: Lan Tianyu <tianyu.lan@intel.com>
Description:
The /sys/bus/usb/devices/.../(hub interface)/portX
is usb port device's sysfs directory.
+
+What: /sys/bus/usb/devices/.../(hub interface)/portX/connect_type
+Date: January 2013
+Contact: Lan Tianyu <tianyu.lan@intel.com>
+Description:
+ Some platforms provide usb port connect types through ACPI.
+ This attribute is to expose these information to user space.
+ The file will read "hotplug", "wired" and "not used" if the
+ information is available, and "unknown" otherwise.
diff --git a/Documentation/ABI/testing/sysfs-class-bdi b/Documentation/ABI/testing/sysfs-class-bdi
index 5f500977b42f..d773d5697cf5 100644
--- a/Documentation/ABI/testing/sysfs-class-bdi
+++ b/Documentation/ABI/testing/sysfs-class-bdi
@@ -48,3 +48,8 @@ max_ratio (read-write)
most of the write-back cache. For example in case of an NFS
mount that is prone to get stuck, or a FUSE mount which cannot
be trusted to play fair.
+
+stable_pages_required (read-only)
+
+ If set, the backing device requires that all pages comprising a write
+ request must not be changed until writeout is complete.
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D0 b/Documentation/ABI/testing/sysfs-devices-power_resources_D0
new file mode 100644
index 000000000000..73b77a6be196
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D0
@@ -0,0 +1,13 @@
+What: /sys/devices/.../power_resources_D0/
+Date: January 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../power_resources_D0/ directory is only
+ present for device objects representing ACPI device nodes that
+ use ACPI power resources for power management.
+
+ If present, it contains symbolic links to device directories
+ representing ACPI power resources that need to be turned on for
+ the given device node to be in ACPI power state D0. The names
+ of the links are the same as the names of the directories they
+ point to.
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D1 b/Documentation/ABI/testing/sysfs-devices-power_resources_D1
new file mode 100644
index 000000000000..30c20703fb8c
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D1
@@ -0,0 +1,14 @@
+What: /sys/devices/.../power_resources_D1/
+Date: January 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../power_resources_D1/ directory is only
+ present for device objects representing ACPI device nodes that
+ use ACPI power resources for power management and support ACPI
+ power state D1.
+
+ If present, it contains symbolic links to device directories
+ representing ACPI power resources that need to be turned on for
+ the given device node to be in ACPI power state D1. The names
+ of the links are the same as the names of the directories they
+ point to.
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D2 b/Documentation/ABI/testing/sysfs-devices-power_resources_D2
new file mode 100644
index 000000000000..fd9d84b421e1
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D2
@@ -0,0 +1,14 @@
+What: /sys/devices/.../power_resources_D2/
+Date: January 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../power_resources_D2/ directory is only
+ present for device objects representing ACPI device nodes that
+ use ACPI power resources for power management and support ACPI
+ power state D2.
+
+ If present, it contains symbolic links to device directories
+ representing ACPI power resources that need to be turned on for
+ the given device node to be in ACPI power state D2. The names
+ of the links are the same as the names of the directories they
+ point to.
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_D3hot b/Documentation/ABI/testing/sysfs-devices-power_resources_D3hot
new file mode 100644
index 000000000000..3df32c20addf
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-power_resources_D3hot
@@ -0,0 +1,14 @@
+What: /sys/devices/.../power_resources_D3hot/
+Date: January 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../power_resources_D3hot/ directory is only
+ present for device objects representing ACPI device nodes that
+ use ACPI power resources for power management and support ACPI
+ power state D3hot.
+
+ If present, it contains symbolic links to device directories
+ representing ACPI power resources that need to be turned on for
+ the given device node to be in ACPI power state D3hot. The
+ names of the links are the same as the names of the directories
+ they point to.
diff --git a/Documentation/ABI/testing/sysfs-devices-power_state b/Documentation/ABI/testing/sysfs-devices-power_state
new file mode 100644
index 000000000000..7ad9546748f0
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-power_state
@@ -0,0 +1,20 @@
+What: /sys/devices/.../power_state
+Date: January 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../power_state attribute is only present for
+ device objects representing ACPI device nodes that provide power
+ management methods.
+
+ If present, it contains a string representing the current ACPI
+ power state of the given device node. Its possible values,
+ "D0", "D1", "D2", "D3hot", and "D3cold", reflect the power state
+ names defined by the ACPI specification (ACPI 4 and above).
+
+ If the device node uses shared ACPI power resources, this state
+ determines a list of power resources required not to be turned
+ off. However, some power resources needed by the device node in
+ higher-power (lower-number) states may also be ON because of
+ some other devices using them at the moment.
+
+ This attribute is read-only.
diff --git a/Documentation/ABI/testing/sysfs-devices-real_power_state b/Documentation/ABI/testing/sysfs-devices-real_power_state
new file mode 100644
index 000000000000..8b3527c82a7d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-real_power_state
@@ -0,0 +1,23 @@
+What: /sys/devices/.../real_power_state
+Date: January 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../real_power_state attribute is only present
+ for device objects representing ACPI device nodes that provide
+ power management methods and use ACPI power resources for power
+ management.
+
+ If present, it contains a string representing the real ACPI
+ power state of the given device node as returned by the _PSC
+ control method or inferred from the configuration of power
+ resources. Its possible values, "D0", "D1", "D2", "D3hot", and
+ "D3cold", reflect the power state names defined by the ACPI
+ specification (ACPI 4 and above).
+
+ In some situations the value of this attribute may be different
+ from the value of the /sys/devices/.../power_state attribute for
+ the same device object. If that happens, some shared power
+ resources used by the device node are only ON because of some
+ other devices using them at the moment.
+
+ This attribute is read-only.
diff --git a/Documentation/ABI/testing/sysfs-devices-resource_in_use b/Documentation/ABI/testing/sysfs-devices-resource_in_use
new file mode 100644
index 000000000000..b4a3bc5922a3
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-resource_in_use
@@ -0,0 +1,12 @@
+What: /sys/devices/.../resource_in_use
+Date: January 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../resource_in_use attribute is only present
+ for device objects representing ACPI power resources.
+
+ If present, it contains a number (0 or 1) representing the
+ current status of the given power resource (0 means that the
+ resource is not in use and therefore it has been turned off).
+
+ This attribute is read-only.
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index 6943133afcb8..9c978dcae07d 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -67,20 +67,6 @@ Description: Discover NUMA node a CPU belongs to
/sys/devices/system/cpu/cpu42/node2 -> ../../node/node2
-What: /sys/devices/system/cpu/cpu#/node
-Date: October 2009
-Contact: Linux memory management mailing list <linux-mm@kvack.org>
-Description: Discover NUMA node a CPU belongs to
-
- When CONFIG_NUMA is enabled, a symbolic link that points
- to the corresponding NUMA node directory.
-
- For example, the following symlink is created for cpu42
- in NUMA node 2:
-
- /sys/devices/system/cpu/cpu42/node2 -> ../../node/node2
-
-
What: /sys/devices/system/cpu/cpu#/topology/core_id
/sys/devices/system/cpu/cpu#/topology/core_siblings
/sys/devices/system/cpu/cpu#/topology/core_siblings_list
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-srws1 b/Documentation/ABI/testing/sysfs-driver-hid-srws1
new file mode 100644
index 000000000000..d0eba70c7d40
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-srws1
@@ -0,0 +1,21 @@
+What: /sys/class/leds/SRWS1::<serial>::RPM1
+What: /sys/class/leds/SRWS1::<serial>::RPM2
+What: /sys/class/leds/SRWS1::<serial>::RPM3
+What: /sys/class/leds/SRWS1::<serial>::RPM4
+What: /sys/class/leds/SRWS1::<serial>::RPM5
+What: /sys/class/leds/SRWS1::<serial>::RPM6
+What: /sys/class/leds/SRWS1::<serial>::RPM7
+What: /sys/class/leds/SRWS1::<serial>::RPM8
+What: /sys/class/leds/SRWS1::<serial>::RPM9
+What: /sys/class/leds/SRWS1::<serial>::RPM10
+What: /sys/class/leds/SRWS1::<serial>::RPM11
+What: /sys/class/leds/SRWS1::<serial>::RPM12
+What: /sys/class/leds/SRWS1::<serial>::RPM13
+What: /sys/class/leds/SRWS1::<serial>::RPM14
+What: /sys/class/leds/SRWS1::<serial>::RPM15
+What: /sys/class/leds/SRWS1::<serial>::RPMALL
+Date: Jan 2013
+KernelVersion: 3.9
+Contact: Simon Wood <simon@mungewell.org>
+Description: Provides a control for turning on/off the LEDs which form
+ an RPM meter on the front of the controller
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-thingm b/Documentation/ABI/testing/sysfs-driver-hid-thingm
new file mode 100644
index 000000000000..abcffeedd20a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-thingm
@@ -0,0 +1,23 @@
+What: /sys/class/leds/blink1::<serial>/rgb
+Date: January 2013
+Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+Description: The ThingM blink1 is an USB RGB LED. The color notation is
+ 3-byte hexadecimal. Read this attribute to get the last set
+ color. Write the 24-bit hexadecimal color to change the current
+ LED color. The default color is full white (0xFFFFFF).
+ For instance, set the color to green with: echo 00FF00 > rgb
+
+What: /sys/class/leds/blink1::<serial>/fade
+Date: January 2013
+Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+Description: This attribute allows to set a fade time in milliseconds for
+ the next color change. Read the attribute to know the current
+ fade time. The default value is set to 0 (no fade time). For
+ instance, set a fade time of 2 seconds with: echo 2000 > fade
+
+What: /sys/class/leds/blink1::<serial>/play
+Date: January 2013
+Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+Description: This attribute is used to play/pause the light patterns. Write 1
+ to start playing, 0 to stop. Reading this attribute returns the
+ current playing status.
diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-ksm b/Documentation/ABI/testing/sysfs-kernel-mm-ksm
new file mode 100644
index 000000000000..73e653ee2481
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-kernel-mm-ksm
@@ -0,0 +1,52 @@
+What: /sys/kernel/mm/ksm
+Date: September 2009
+KernelVersion: 2.6.32
+Contact: Linux memory management mailing list <linux-mm@kvack.org>
+Description: Interface for Kernel Samepage Merging (KSM)
+
+What: /sys/kernel/mm/ksm/full_scans
+What: /sys/kernel/mm/ksm/pages_shared
+What: /sys/kernel/mm/ksm/pages_sharing
+What: /sys/kernel/mm/ksm/pages_to_scan
+What: /sys/kernel/mm/ksm/pages_unshared
+What: /sys/kernel/mm/ksm/pages_volatile
+What: /sys/kernel/mm/ksm/run
+What: /sys/kernel/mm/ksm/sleep_millisecs
+Date: September 2009
+Contact: Linux memory management mailing list <linux-mm@kvack.org>
+Description: Kernel Samepage Merging daemon sysfs interface
+
+ full_scans: how many times all mergeable areas have been
+ scanned.
+
+ pages_shared: how many shared pages are being used.
+
+ pages_sharing: how many more sites are sharing them i.e. how
+ much saved.
+
+ pages_to_scan: how many present pages to scan before ksmd goes
+ to sleep.
+
+ pages_unshared: how many pages unique but repeatedly checked
+ for merging.
+
+ pages_volatile: how many pages changing too fast to be placed
+ in a tree.
+
+ run: write 0 to disable ksm, read 0 while ksm is disabled.
+ write 1 to run ksm, read 1 while ksm is running.
+ write 2 to disable ksm and unmerge all its pages.
+
+ sleep_millisecs: how many milliseconds ksm should sleep between
+ scans.
+
+ See Documentation/vm/ksm.txt for more information.
+
+What: /sys/kernel/mm/ksm/merge_across_nodes
+Date: January 2013
+KernelVersion: 3.9
+Contact: Linux memory management mailing list <linux-mm@kvack.org>
+Description: Control merging pages across different NUMA nodes.
+
+ When it is set to 0 only pages from the same node are merged,
+ otherwise pages from all nodes can be merged together (default).
diff --git a/Documentation/ABI/testing/sysfs-platform-ts5500 b/Documentation/ABI/testing/sysfs-platform-ts5500
new file mode 100644
index 000000000000..c88375a537a1
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-ts5500
@@ -0,0 +1,47 @@
+What: /sys/devices/platform/ts5500/adc
+Date: January 2013
+KernelVersion: 3.7
+Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+ Indicates the presence of an A/D Converter. If it is present,
+ it will display "1", otherwise "0".
+
+What: /sys/devices/platform/ts5500/ereset
+Date: January 2013
+KernelVersion: 3.7
+Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+ Indicates the presence of an external reset. If it is present,
+ it will display "1", otherwise "0".
+
+What: /sys/devices/platform/ts5500/id
+Date: January 2013
+KernelVersion: 3.7
+Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+ Product ID of the TS board. TS-5500 ID is 0x60.
+
+What: /sys/devices/platform/ts5500/jumpers
+Date: January 2013
+KernelVersion: 3.7
+Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+ Bitfield showing the jumpers' state. If a jumper is present,
+ the corresponding bit is set. For instance, 0x0e means jumpers
+ 2, 3 and 4 are set.
+
+What: /sys/devices/platform/ts5500/rs485
+Date: January 2013
+KernelVersion: 3.7
+Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+ Indicates the presence of the RS485 option. If it is present,
+ it will display "1", otherwise "0".
+
+What: /sys/devices/platform/ts5500/sram
+Date: January 2013
+KernelVersion: 3.7
+Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+ Indicates the presence of the SRAM option. If it is present,
+ it will display "1", otherwise "0".
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index 495e5ba1634c..e00b8f0dde52 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -546,15 +546,7 @@ config AUDIT
logging of avc messages output). Does not do system-call
auditing without CONFIG_AUDITSYSCALL.
-Features that might still be considered unstable should be defined as
-dependent on "EXPERIMENTAL":
-
-config SLUB
- depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT
- bool "SLUB (Unqueued Allocator)"
- ...
-
-while seriously dangerous features (such as write support for certain
+Seriously dangerous features (such as write support for certain
filesystems) should advertise this prominently in their prompt string:
config ADFS_FS_RW
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
index 42e7f030cb16..284ced7a228f 100644
--- a/Documentation/DocBook/80211.tmpl
+++ b/Documentation/DocBook/80211.tmpl
@@ -107,8 +107,8 @@
!Finclude/net/cfg80211.h key_params
!Finclude/net/cfg80211.h survey_info_flags
!Finclude/net/cfg80211.h survey_info
-!Finclude/net/cfg80211.h beacon_parameters
-!Finclude/net/cfg80211.h plink_actions
+!Finclude/net/cfg80211.h cfg80211_beacon_data
+!Finclude/net/cfg80211.h cfg80211_ap_settings
!Finclude/net/cfg80211.h station_parameters
!Finclude/net/cfg80211.h station_info_flags
!Finclude/net/cfg80211.h rate_info_flags
diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
index eee71426ecb8..d0758b241b23 100644
--- a/Documentation/DocBook/kernel-hacking.tmpl
+++ b/Documentation/DocBook/kernel-hacking.tmpl
@@ -945,7 +945,7 @@ printk(KERN_INFO "my ip: %pI4\n", &amp;ipaddress);
<sect1 id="sym-exportsymbols">
<title><function>EXPORT_SYMBOL()</function>
- <filename class="headerfile">include/linux/module.h</filename></title>
+ <filename class="headerfile">include/linux/export.h</filename></title>
<para>
This is the classic method of exporting a symbol: dynamically
@@ -955,7 +955,7 @@ printk(KERN_INFO "my ip: %pI4\n", &amp;ipaddress);
<sect1 id="sym-exportsymbols-gpl">
<title><function>EXPORT_SYMBOL_GPL()</function>
- <filename class="headerfile">include/linux/module.h</filename></title>
+ <filename class="headerfile">include/linux/export.h</filename></title>
<para>
Similar to <function>EXPORT_SYMBOL()</function> except that the
@@ -1185,13 +1185,6 @@ static struct block_device_operations opt_fops = {
</para>
<para>
- You may well want to make your CONFIG option only visible if
- <symbol>CONFIG_EXPERIMENTAL</symbol> is enabled: this serves as a
- warning to users. There many other fancy things you can do: see
- the various <filename>Kconfig</filename> files for ideas.
- </para>
-
- <para>
In your description of the option, make sure you address both the
expert user and the user who knows nothing about your feature. Mention
incompatibilities and issues here. <emphasis> Definitely
diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl
index 4ee4ba3509fc..f77358f96930 100644
--- a/Documentation/DocBook/kgdb.tmpl
+++ b/Documentation/DocBook/kgdb.tmpl
@@ -94,10 +94,8 @@
<sect1 id="CompileKGDB">
<title>Kernel config options for kgdb</title>
<para>
- To enable <symbol>CONFIG_KGDB</symbol> you should first turn on
- "Prompt for development and/or incomplete code/drivers"
- (CONFIG_EXPERIMENTAL) in "General setup", then under the
- "Kernel debugging" select "KGDB: kernel debugger".
+ To enable <symbol>CONFIG_KGDB</symbol> you should look under
+ "Kernel debugging" and select "KGDB: kernel debugger".
</para>
<para>
While it is not a hard requirement that you have symbols in your
diff --git a/Documentation/DocBook/media/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml
index 757488b24f4f..0197bcc7842d 100644
--- a/Documentation/DocBook/media/dvb/dvbapi.xml
+++ b/Documentation/DocBook/media/dvb/dvbapi.xml
@@ -84,7 +84,7 @@ Added ISDB-T test originally written by Patrick Boettcher
<title>LINUX DVB API</title>
-<subtitle>Version 5.8</subtitle>
+<subtitle>Version 5.10</subtitle>
<!-- ADD THE CHAPTERS HERE -->
<chapter id="dvb_introdution">
&sub-intro;
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index 957e3acaae8e..4a5eaeed0b9e 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -7,14 +7,41 @@ the capability ioctls weren't implemented yet via the new way.</para>
<para>The typical usage for the <constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant>
API is to replace the ioctl's were the <link linkend="dvb-frontend-parameters">
struct <constant>dvb_frontend_parameters</constant></link> were used.</para>
+<section id="dtv-stats">
+<title>DTV stats type</title>
+<programlisting>
+struct dtv_stats {
+ __u8 scale; /* enum fecap_scale_params type */
+ union {
+ __u64 uvalue; /* for counters and relative scales */
+ __s64 svalue; /* for 1/1000 dB measures */
+ };
+} __packed;
+</programlisting>
+</section>
+<section id="dtv-fe-stats">
+<title>DTV stats type</title>
+<programlisting>
+#define MAX_DTV_STATS 4
+
+struct dtv_fe_stats {
+ __u8 len;
+ struct dtv_stats stat[MAX_DTV_STATS];
+} __packed;
+</programlisting>
+</section>
+
<section id="dtv-property">
<title>DTV property type</title>
<programlisting>
/* Reserved fields should be set to 0 */
+
struct dtv_property {
__u32 cmd;
+ __u32 reserved[3];
union {
__u32 data;
+ struct dtv_fe_stats st;
struct {
__u8 data[32];
__u32 len;
@@ -440,7 +467,7 @@ typedef enum fe_delivery_system {
<title><constant>DTV-ISDBT-LAYER*</constant> parameters</title>
<para>ISDB-T channels can be coded hierarchically. As opposed to DVB-T in
ISDB-T hierarchical layers can be decoded simultaneously. For that
- reason a ISDB-T demodulator has 3 viterbi and 3 reed-solomon-decoders.</para>
+ reason a ISDB-T demodulator has 3 Viterbi and 3 Reed-Solomon decoders.</para>
<para>ISDB-T has 3 hierarchical layers which each can use a part of the
available segments. The total number of segments over all layers has
to 13 in ISDB-T.</para>
@@ -850,6 +877,147 @@ enum fe_interleaving {
<para>use the special macro LNA_AUTO to set LNA auto</para>
</section>
</section>
+
+ <section id="frontend-stat-properties">
+ <title>Frontend statistics indicators</title>
+ <para>The values are returned via <constant>dtv_property.stat</constant>.
+ If the property is supported, <constant>dtv_property.stat.len</constant> is bigger than zero.</para>
+ <para>For most delivery systems, <constant>dtv_property.stat.len</constant>
+ will be 1 if the stats is supported, and the properties will
+ return a single value for each parameter.</para>
+ <para>It should be noticed, however, that new OFDM delivery systems
+ like ISDB can use different modulation types for each group of
+ carriers. On such standards, up to 3 groups of statistics can be
+ provided, and <constant>dtv_property.stat.len</constant> is updated
+ to reflect the "global" metrics, plus one metric per each carrier
+ group (called "layer" on ISDB).</para>
+ <para>So, in order to be consistent with other delivery systems, the first
+ value at <link linkend="dtv-stats"><constant>dtv_property.stat.dtv_stats</constant></link>
+ array refers to the global metric. The other elements of the array
+ represent each layer, starting from layer A(index 1),
+ layer B (index 2) and so on.</para>
+ <para>The number of filled elements are stored at <constant>dtv_property.stat.len</constant>.</para>
+ <para>Each element of the <constant>dtv_property.stat.dtv_stats</constant> array consists on two elements:</para>
+ <itemizedlist mark='opencircle'>
+ <listitem><para><constant>svalue</constant> or <constant>uvalue</constant>, where
+ <constant>svalue</constant> is for signed values of the measure (dB measures)
+ and <constant>uvalue</constant> is for unsigned values (counters, relative scale)</para></listitem>
+ <listitem><para><constant>scale</constant> - Scale for the value. It can be:</para>
+ <section id = "fecap-scale-params">
+ <itemizedlist mark='bullet'>
+ <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - The parameter is supported by the frontend, but it was not possible to collect it (could be a transitory or permanent condition)</para></listitem>
+ <listitem><para><constant>FE_SCALE_DECIBEL</constant> - parameter is a signed value, measured in 1/1000 dB</para></listitem>
+ <listitem><para><constant>FE_SCALE_RELATIVE</constant> - parameter is a unsigned value, where 0 means 0% and 65535 means 100%.</para></listitem>
+ <listitem><para><constant>FE_SCALE_COUNTER</constant> - parameter is a unsigned value that counts the occurrence of an event, like bit error, block error, or lapsed time.</para></listitem>
+ </itemizedlist>
+ </section>
+ </listitem>
+ </itemizedlist>
+ <section id="DTV-STAT-SIGNAL-STRENGTH">
+ <title><constant>DTV_STAT_SIGNAL_STRENGTH</constant></title>
+ <para>Indicates the signal strength level at the analog part of the tuner or of the demod.</para>
+ <para>Possible scales for this metric are:</para>
+ <itemizedlist mark='bullet'>
+ <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
+ <listitem><constant>FE_SCALE_DECIBEL</constant> - signal strength is in 0.0001 dBm units, power measured in miliwatts. This value is generally negative.</listitem>
+ <listitem><constant>FE_SCALE_RELATIVE</constant> - The frontend provides a 0% to 100% measurement for power (actually, 0 to 65535).</listitem>
+ </itemizedlist>
+ </section>
+ <section id="DTV-STAT-CNR">
+ <title><constant>DTV_STAT_CNR</constant></title>
+ <para>Indicates the Signal to Noise ratio for the main carrier.</para>
+ <para>Possible scales for this metric are:</para>
+ <itemizedlist mark='bullet'>
+ <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
+ <listitem><constant>FE_SCALE_DECIBEL</constant> - Signal/Noise ratio is in 0.0001 dB units.</listitem>
+ <listitem><constant>FE_SCALE_RELATIVE</constant> - The frontend provides a 0% to 100% measurement for Signal/Noise (actually, 0 to 65535).</listitem>
+ </itemizedlist>
+ </section>
+ <section id="DTV-STAT-PRE-ERROR-BIT-COUNT">
+ <title><constant>DTV_STAT_PRE_ERROR_BIT_COUNT</constant></title>
+ <para>Measures the number of bit errors before the forward error correction (FEC) on the inner coding block (before Viterbi, LDPC or other inner code).</para>
+ <para>This measure is taken during the same interval as <constant>DTV_STAT_PRE_TOTAL_BIT_COUNT</constant>.</para>
+ <para>In order to get the BER (Bit Error Rate) measurement, it should be divided by
+ <link linkend="DTV-STAT-PRE-TOTAL-BIT-COUNT"><constant>DTV_STAT_PRE_TOTAL_BIT_COUNT</constant></link>.</para>
+ <para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
+ The frontend may reset it when a channel/transponder is tuned.</para>
+ <para>Possible scales for this metric are:</para>
+ <itemizedlist mark='bullet'>
+ <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
+ <listitem><constant>FE_SCALE_COUNTER</constant> - Number of error bits counted before the inner coding.</listitem>
+ </itemizedlist>
+ </section>
+ <section id="DTV-STAT-PRE-TOTAL-BIT-COUNT">
+ <title><constant>DTV_STAT_PRE_TOTAL_BIT_COUNT</constant></title>
+ <para>Measures the amount of bits received before the inner code block, during the same period as
+ <link linkend="DTV-STAT-PRE-ERROR-BIT-COUNT"><constant>DTV_STAT_PRE_ERROR_BIT_COUNT</constant></link> measurement was taken.</para>
+ <para>It should be noticed that this measurement can be smaller than the total amount of bits on the transport stream,
+ as the frontend may need to manually restart the measurement, loosing some data between each measurement interval.</para>
+ <para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
+ The frontend may reset it when a channel/transponder is tuned.</para>
+ <para>Possible scales for this metric are:</para>
+ <itemizedlist mark='bullet'>
+ <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
+ <listitem><constant>FE_SCALE_COUNTER</constant> - Number of bits counted while measuring
+ <link linkend="DTV-STAT-PRE-ERROR-BIT-COUNT"><constant>DTV_STAT_PRE_ERROR_BIT_COUNT</constant></link>.</listitem>
+ </itemizedlist>
+ </section>
+ <section id="DTV-STAT-POST-ERROR-BIT-COUNT">
+ <title><constant>DTV_STAT_POST_ERROR_BIT_COUNT</constant></title>
+ <para>Measures the number of bit errors after the forward error correction (FEC) done by inner code block (after Viterbi, LDPC or other inner code).</para>
+ <para>This measure is taken during the same interval as <constant>DTV_STAT_POST_TOTAL_BIT_COUNT</constant>.</para>
+ <para>In order to get the BER (Bit Error Rate) measurement, it should be divided by
+ <link linkend="DTV-STAT-POST-TOTAL-BIT-COUNT"><constant>DTV_STAT_POST_TOTAL_BIT_COUNT</constant></link>.</para>
+ <para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
+ The frontend may reset it when a channel/transponder is tuned.</para>
+ <para>Possible scales for this metric are:</para>
+ <itemizedlist mark='bullet'>
+ <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
+ <listitem><constant>FE_SCALE_COUNTER</constant> - Number of error bits counted after the inner coding.</listitem>
+ </itemizedlist>
+ </section>
+ <section id="DTV-STAT-POST-TOTAL-BIT-COUNT">
+ <title><constant>DTV_STAT_POST_TOTAL_BIT_COUNT</constant></title>
+ <para>Measures the amount of bits received after the inner coding, during the same period as
+ <link linkend="DTV-STAT-POST-ERROR-BIT-COUNT"><constant>DTV_STAT_POST_ERROR_BIT_COUNT</constant></link> measurement was taken.</para>
+ <para>It should be noticed that this measurement can be smaller than the total amount of bits on the transport stream,
+ as the frontend may need to manually restart the measurement, loosing some data between each measurement interval.</para>
+ <para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
+ The frontend may reset it when a channel/transponder is tuned.</para>
+ <para>Possible scales for this metric are:</para>
+ <itemizedlist mark='bullet'>
+ <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
+ <listitem><constant>FE_SCALE_COUNTER</constant> - Number of bits counted while measuring
+ <link linkend="DTV-STAT-POST-ERROR-BIT-COUNT"><constant>DTV_STAT_POST_ERROR_BIT_COUNT</constant></link>.</listitem>
+ </itemizedlist>
+ </section>
+ <section id="DTV-STAT-ERROR-BLOCK-COUNT">
+ <title><constant>DTV_STAT_ERROR_BLOCK_COUNT</constant></title>
+ <para>Measures the number of block errors after the outer forward error correction coding (after Reed-Solomon or other outer code).</para>
+ <para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
+ The frontend may reset it when a channel/transponder is tuned.</para>
+ <para>Possible scales for this metric are:</para>
+ <itemizedlist mark='bullet'>
+ <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
+ <listitem><constant>FE_SCALE_COUNTER</constant> - Number of error blocks counted after the outer coding.</listitem>
+ </itemizedlist>
+ </section>
+ <section id="DTV-STAT-TOTAL-BLOCK-COUNT">
+ <title><constant>DTV-STAT_TOTAL_BLOCK_COUNT</constant></title>
+ <para>Measures the total number of blocks received during the same period as
+ <link linkend="DTV-STAT-ERROR-BLOCK-COUNT"><constant>DTV_STAT_ERROR_BLOCK_COUNT</constant></link> measurement was taken.</para>
+ <para>It can be used to calculate the PER indicator, by dividing
+ <link linkend="DTV-STAT-ERROR-BLOCK-COUNT"><constant>DTV_STAT_ERROR_BLOCK_COUNT</constant></link>
+ by <link linkend="DTV-STAT-TOTAL-BLOCK-COUNT"><constant>DTV-STAT-TOTAL-BLOCK-COUNT</constant></link>.</para>
+ <para>Possible scales for this metric are:</para>
+ <itemizedlist mark='bullet'>
+ <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
+ <listitem><constant>FE_SCALE_COUNTER</constant> - Number of blocks counted while measuring
+ <link linkend="DTV-STAT-ERROR-BLOCK-COUNT"><constant>DTV_STAT_ERROR_BLOCK_COUNT</constant></link>.</listitem>
+ </itemizedlist>
+ </section>
+ </section>
+
<section id="frontend-property-terrestrial-systems">
<title>Properties used on terrestrial delivery systems</title>
<section id="dvbt-params">
@@ -871,6 +1039,7 @@ enum fe_interleaving {
<listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem>
<listitem><para><link linkend="DTV-LNA"><constant>DTV_LNA</constant></link></para></listitem>
</itemizedlist>
+ <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
</section>
<section id="dvbt2-params">
<title>DVB-T2 delivery system</title>
@@ -895,6 +1064,7 @@ enum fe_interleaving {
<listitem><para><link linkend="DTV-STREAM-ID"><constant>DTV_STREAM_ID</constant></link></para></listitem>
<listitem><para><link linkend="DTV-LNA"><constant>DTV_LNA</constant></link></para></listitem>
</itemizedlist>
+ <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
</section>
<section id="isdbt">
<title>ISDB-T delivery system</title>
@@ -948,6 +1118,7 @@ enum fe_interleaving {
<listitem><para><link linkend="DTV-ISDBT-LAYER-SEGMENT-COUNT"><constant>DTV_ISDBT_LAYERC_SEGMENT_COUNT</constant></link></para></listitem>
<listitem><para><link linkend="DTV-ISDBT-LAYER-TIME-INTERLEAVING"><constant>DTV_ISDBT_LAYERC_TIME_INTERLEAVING</constant></link></para></listitem>
</itemizedlist>
+ <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
</section>
<section id="atsc-params">
<title>ATSC delivery system</title>
@@ -961,6 +1132,7 @@ enum fe_interleaving {
<listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
<listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
</itemizedlist>
+ <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
</section>
<section id="atscmh-params">
<title>ATSC-MH delivery system</title>
@@ -988,6 +1160,7 @@ enum fe_interleaving {
<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-C"><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></link></para></listitem>
<listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-D"><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></link></para></listitem>
</itemizedlist>
+ <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
</section>
<section id="dtmb-params">
<title>DTMB delivery system</title>
@@ -1007,6 +1180,7 @@ enum fe_interleaving {
<listitem><para><link linkend="DTV-INTERLEAVING"><constant>DTV_INTERLEAVING</constant></link></para></listitem>
<listitem><para><link linkend="DTV-LNA"><constant>DTV_LNA</constant></link></para></listitem>
</itemizedlist>
+ <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
</section>
</section>
<section id="frontend-property-cable-systems">
@@ -1028,6 +1202,7 @@ enum fe_interleaving {
<listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
<listitem><para><link linkend="DTV-LNA"><constant>DTV_LNA</constant></link></para></listitem>
</itemizedlist>
+ <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
</section>
<section id="dvbc-annex-b-params">
<title>DVB-C Annex B delivery system</title>
@@ -1043,6 +1218,7 @@ enum fe_interleaving {
<listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
<listitem><para><link linkend="DTV-LNA"><constant>DTV_LNA</constant></link></para></listitem>
</itemizedlist>
+ <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
</section>
</section>
<section id="frontend-property-satellital-systems">
@@ -1062,6 +1238,7 @@ enum fe_interleaving {
<listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
<listitem><para><link linkend="DTV-TONE"><constant>DTV_TONE</constant></link></para></listitem>
</itemizedlist>
+ <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
<para>Future implementations might add those two missing parameters:</para>
<itemizedlist mark='opencircle'>
<listitem><para><link linkend="DTV-DISEQC-MASTER"><constant>DTV_DISEQC_MASTER</constant></link></para></listitem>
@@ -1077,6 +1254,7 @@ enum fe_interleaving {
<listitem><para><link linkend="DTV-ROLLOFF"><constant>DTV_ROLLOFF</constant></link></para></listitem>
<listitem><para><link linkend="DTV-STREAM-ID"><constant>DTV_STREAM_ID</constant></link></para></listitem>
</itemizedlist>
+ <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
</section>
<section id="turbo-params">
<title>Turbo code delivery system</title>
diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml
index 426c2526a454..df39ba395df0 100644
--- a/Documentation/DocBook/media/dvb/frontend.xml
+++ b/Documentation/DocBook/media/dvb/frontend.xml
@@ -230,7 +230,7 @@ typedef enum fe_status {
<entry align="char">The frontend has found a DVB signal</entry>
</row><row>
<entry align="char">FE_HAS_VITERBI</entry>
-<entry align="char">The frontend FEC code is stable</entry>
+<entry align="char">The frontend FEC inner coding (Viterbi, LDPC or other inner code) is stable</entry>
</row><row>
<entry align="char">FE_HAS_SYNC</entry>
<entry align="char">Syncronization bytes was found</entry>
diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
index 73c6847436c9..ae06afbbb3a9 100644
--- a/Documentation/DocBook/media/v4l/common.xml
+++ b/Documentation/DocBook/media/v4l/common.xml
@@ -609,7 +609,7 @@ to zero and the <constant>VIDIOC_G_STD</constant>,
<para>Applications can make use of the <xref linkend="input-capabilities" /> and
<xref linkend="output-capabilities"/> flags to determine whether the video standard ioctls
are available for the device.</para>
-&ENOTTY;.
+
<para>See <xref linkend="buffer" /> for a rationale. Probably
even USB cameras follow some well known video standard. It might have
been better to explicitly indicate elsewhere if a device cannot live
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index 3dd9e78815d1..104a1a2b8849 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2477,6 +2477,22 @@ that used it. It was originally scheduled for removal in 2.6.35.
</orderedlist>
</section>
+ <section>
+ <title>V4L2 in Linux 3.9</title>
+ <orderedlist>
+ <listitem>
+ <para>Added timestamp types to
+ <structfield>flags</structfield> field in
+ <structname>v4l2_buffer</structname>. See <xref
+ linkend="buffer-flags" />.</para>
+ </listitem>
+ <listitem>
+ <para>Added <constant>V4L2_EVENT_CTRL_CH_RANGE</constant> control event
+ changes flag. See <xref linkend="changes-flags"/>.</para>
+ </listitem>
+ </orderedlist>
+ </section>
+
<section id="other">
<title>Relation of V4L2 to other Linux multimedia APIs</title>
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 7fe5be1d3bbb..9e8f85498678 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -203,29 +203,6 @@ and should not be used in new drivers and applications.</entry>
<entry>boolean</entry>
<entry>Mirror the picture vertically.</entry>
</row>
- <row>
- <entry><constant>V4L2_CID_HCENTER_DEPRECATED</constant> (formerly <constant>V4L2_CID_HCENTER</constant>)</entry>
- <entry>integer</entry>
- <entry>Horizontal image centering. This control is
-deprecated. New drivers and applications should use the <link
-linkend="camera-controls">Camera class controls</link>
-<constant>V4L2_CID_PAN_ABSOLUTE</constant>,
-<constant>V4L2_CID_PAN_RELATIVE</constant> and
-<constant>V4L2_CID_PAN_RESET</constant> instead.</entry>
- </row>
- <row>
- <entry><constant>V4L2_CID_VCENTER_DEPRECATED</constant>
- (formerly <constant>V4L2_CID_VCENTER</constant>)</entry>
- <entry>integer</entry>
- <entry>Vertical image centering. Centering is intended to
-<emphasis>physically</emphasis> adjust cameras. For image cropping see
-<xref linkend="crop" />, for clipping <xref linkend="overlay" />. This
-control is deprecated. New drivers and applications should use the
-<link linkend="camera-controls">Camera class controls</link>
-<constant>V4L2_CID_TILT_ABSOLUTE</constant>,
-<constant>V4L2_CID_TILT_RELATIVE</constant> and
-<constant>V4L2_CID_TILT_RESET</constant> instead.</entry>
- </row>
<row id="v4l2-power-line-frequency">
<entry><constant>V4L2_CID_POWER_LINE_FREQUENCY</constant></entry>
<entry>enum</entry>
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index 388a34032653..e6c58559ca6b 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -477,7 +477,7 @@ rest should be evident.</para>
<note>
<title>Experimental</title>
- <para>This is an <link linkend="experimental"> experimental </link>
+ <para>This is an <link linkend="experimental">experimental</link>
interface and may change in the future.</para>
</note>
@@ -488,7 +488,7 @@ DMA buffer from userspace using a file descriptor previously exported for a
different or the same device (known as the importer role), or both. This
section describes the DMABUF importer role API in V4L2.</para>
- <para>Refer to <link linked="vidioc-expbuf"> DMABUF exporting </link> for
+ <para>Refer to <link linkend="vidioc-expbuf">DMABUF exporting</link> for
details about exporting V4L2 buffers as DMABUF file descriptors.</para>
<para>Input and output devices support the streaming I/O method when the
@@ -741,17 +741,19 @@ applications when an output stream.</entry>
<entry>struct timeval</entry>
<entry><structfield>timestamp</structfield></entry>
<entry></entry>
- <entry><para>For input streams this is the
-system time (as returned by the <function>gettimeofday()</function>
-function) when the first data byte was captured. For output streams
-the data will not be displayed before this time, secondary to the
-nominal frame rate determined by the current video standard in
-enqueued order. Applications can for example zero this field to
-display frames as soon as possible. The driver stores the time at
-which the first data byte was actually sent out in the
-<structfield>timestamp</structfield> field. This permits
-applications to monitor the drift between the video and system
-clock.</para></entry>
+ <entry><para>For input streams this is time when the first data
+ byte was captured, as returned by the
+ <function>clock_gettime()</function> function for the relevant
+ clock id; see <constant>V4L2_BUF_FLAG_TIMESTAMP_*</constant> in
+ <xref linkend="buffer-flags" />. For output streams the data
+ will not be displayed before this time, secondary to the nominal
+ frame rate determined by the current video standard in enqueued
+ order. Applications can for example zero this field to display
+ frames as soon as possible. The driver stores the time at which
+ the first data byte was actually sent out in the
+ <structfield>timestamp</structfield> field. This permits
+ applications to monitor the drift between the video and system
+ clock.</para></entry>
</row>
<row>
<entry>&v4l2-timecode;</entry>
@@ -903,7 +905,7 @@ should set this to 0.</entry>
</row>
<row>
<entry></entry>
- <entry>__unsigned long</entry>
+ <entry>unsigned long</entry>
<entry><structfield>userptr</structfield></entry>
<entry>When the memory type in the containing &v4l2-buffer; is
<constant>V4L2_MEMORY_USERPTR</constant>, this is a userspace
@@ -1114,6 +1116,35 @@ Typically applications shall use this flag for output buffers if the data
in this buffer has not been created by the CPU but by some DMA-capable unit,
in which case caches have not been used.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_BUF_FLAG_TIMESTAMP_MASK</constant></entry>
+ <entry>0xe000</entry>
+ <entry>Mask for timestamp types below. To test the
+ timestamp type, mask out bits not belonging to timestamp
+ type by performing a logical and operation with buffer
+ flags and timestamp mask.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN</constant></entry>
+ <entry>0x0000</entry>
+ <entry>Unknown timestamp type. This type is used by
+ drivers before Linux 3.9 and may be either monotonic (see
+ below) or realtime (wall clock). Monotonic clock has been
+ favoured in embedded systems whereas most of the drivers
+ use the realtime clock. Either kinds of timestamps are
+ available in user space via
+ <function>clock_gettime(2)</function> using clock IDs
+ <constant>CLOCK_MONOTONIC</constant> and
+ <constant>CLOCK_REALTIME</constant>, respectively.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC</constant></entry>
+ <entry>0x2000</entry>
+ <entry>The buffer timestamp has been taken from the
+ <constant>CLOCK_MONOTONIC</constant> clock. To access the
+ same clock outside V4L2, use
+ <function>clock_gettime(2)</function> .</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml
index a990b34d911a..f3a3d459fcdf 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml
@@ -6,7 +6,7 @@
<refnamediv>
<refname id="V4L2-PIX-FMT-NV12M"><constant>V4L2_PIX_FMT_NV12M</constant></refname>
<refname id="V4L2-PIX-FMT-NV21M"><constant>V4L2_PIX_FMT_NV21M</constant></refname>
- <refname id="V4L2-PIX-FMT-NV12MT_16X16"><constant>V4L2_PIX_FMT_NV12MT_16X16</constant></refname>
+ <refname id="V4L2-PIX-FMT-NV12MT-16X16"><constant>V4L2_PIX_FMT_NV12MT_16X16</constant></refname>
<refpurpose>Variation of <constant>V4L2_PIX_FMT_NV12</constant> and <constant>V4L2_PIX_FMT_NV21</constant> with planes
non contiguous in memory. </refpurpose>
</refnamediv>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml
new file mode 100644
index 000000000000..29acc2098cc2
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml
@@ -0,0 +1,34 @@
+ <refentry>
+ <refmeta>
+ <refentrytitle>
+ V4L2_PIX_FMT_SBGGR10ALAW8 ('aBA8'),
+ V4L2_PIX_FMT_SGBRG10ALAW8 ('aGA8'),
+ V4L2_PIX_FMT_SGRBG10ALAW8 ('agA8'),
+ V4L2_PIX_FMT_SRGGB10ALAW8 ('aRA8'),
+ </refentrytitle>
+ &manvol;
+ </refmeta>
+ <refnamediv>
+ <refname id="V4L2-PIX-FMT-SBGGR10ALAW8">
+ <constant>V4L2_PIX_FMT_SBGGR10ALAW8</constant>
+ </refname>
+ <refname id="V4L2-PIX-FMT-SGBRG10ALAW8">
+ <constant>V4L2_PIX_FMT_SGBRG10ALAW8</constant>
+ </refname>
+ <refname id="V4L2-PIX-FMT-SGRBG10ALAW8">
+ <constant>V4L2_PIX_FMT_SGRBG10ALAW8</constant>
+ </refname>
+ <refname id="V4L2-PIX-FMT-SRGGB10ALAW8">
+ <constant>V4L2_PIX_FMT_SRGGB10ALAW8</constant>
+ </refname>
+ <refpurpose>10-bit Bayer formats compressed to 8 bits</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>Description</title>
+ <para>The following four pixel formats are raw sRGB / Bayer
+ formats with 10 bits per color compressed to 8 bits each,
+ using the A-LAW algorithm. Each color component consumes 8
+ bits of memory. In other respects this format is similar to
+ <xref linkend="V4L2-PIX-FMT-SRGGB8"></xref>.</para>
+ </refsect1>
+ </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-uv8.xml b/Documentation/DocBook/media/v4l/pixfmt-uv8.xml
new file mode 100644
index 000000000000..c507c1f73cd0
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-uv8.xml
@@ -0,0 +1,62 @@
+ <refentry id="V4L2-PIX-FMT-UV8">
+ <refmeta>
+ <refentrytitle>V4L2_PIX_FMT_UV8 ('UV8')</refentrytitle>
+ &manvol;
+ </refmeta>
+ <refnamediv>
+ <refname><constant>V4L2_PIX_FMT_UV8</constant></refname>
+ <refpurpose>UV plane interleaved</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>Description</title>
+ <para>In this format there is no Y plane, Only CbCr plane. ie
+ (UV interleaved)</para>
+ <example>
+ <title>
+ <constant>V4L2_PIX_FMT_UV8</constant>
+ 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>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;4:</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>
+ <row>
+ <entry>start&nbsp;+&nbsp;8:</entry>
+ <entry>Cb<subscript>20</subscript></entry>
+ <entry>Cr<subscript>20</subscript></entry>
+ <entry>Cb<subscript>21</subscript></entry>
+ <entry>Cr<subscript>21</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;12:</entry>
+ <entry>Cb<subscript>30</subscript></entry>
+ <entry>Cr<subscript>30</subscript></entry>
+ <entry>Cb<subscript>31</subscript></entry>
+ <entry>Cr<subscript>31</subscript></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </formalpara>
+ </example>
+ </refsect1>
+ </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
index bf94f417592c..99b8d2ad6e4f 100644
--- a/Documentation/DocBook/media/v4l/pixfmt.xml
+++ b/Documentation/DocBook/media/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-srggb10alaw8;
&sub-srggb10dpcm8;
&sub-srggb12;
</section>
@@ -701,6 +702,7 @@ information.</para>
&sub-y12;
&sub-y10b;
&sub-y16;
+ &sub-uv8;
&sub-yuyv;
&sub-uyvy;
&sub-yvyu;
diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml
index a0a936455fae..cc51372ed5e0 100644
--- a/Documentation/DocBook/media/v4l/subdev-formats.xml
+++ b/Documentation/DocBook/media/v4l/subdev-formats.xml
@@ -353,9 +353,9 @@
<listitem><para>The number of bits per pixel component. All components are
transferred on the same number of bits. Common values are 8, 10 and 12.</para>
</listitem>
- <listitem><para>If the pixel components are DPCM-compressed, a mention of the
- DPCM compression and the number of bits per compressed pixel component.</para>
- </listitem>
+ <listitem><para>The compression (optional). If the pixel components are
+ ALAW- or DPCM-compressed, a mention of the compression scheme and the
+ number of bits per compressed pixel component.</para></listitem>
<listitem><para>The number of bus samples per pixel. Pixels that are wider than
the bus width must be transferred in multiple samples. Common values are
1 and 2.</para></listitem>
@@ -504,6 +504,74 @@
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
+ <row id="V4L2-MBUS-FMT-SBGGR10-ALAW8-1X8">
+ <entry>V4L2_MBUS_FMT_SBGGR10_ALAW8_1X8</entry>
+ <entry>0x3015</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SGBRG10-ALAW8-1X8">
+ <entry>V4L2_MBUS_FMT_SGBRG10_ALAW8_1X8</entry>
+ <entry>0x3016</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>g<subscript>7</subscript></entry>
+ <entry>g<subscript>6</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SGRBG10-ALAW8-1X8">
+ <entry>V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8</entry>
+ <entry>0x3017</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>g<subscript>7</subscript></entry>
+ <entry>g<subscript>6</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-SRGGB10-ALAW8-1X8">
+ <entry>V4L2_MBUS_FMT_SRGGB10_ALAW8_1X8</entry>
+ <entry>0x3018</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>r<subscript>7</subscript></entry>
+ <entry>r<subscript>6</subscript></entry>
+ <entry>r<subscript>5</subscript></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ </row>
<row id="V4L2-MBUS-FMT-SBGGR10-DPCM8-1X8">
<entry>V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8</entry>
<entry>0x300b</entry>
@@ -853,10 +921,16 @@
<title>Packed YUV Formats</title>
<para>Those data formats transfer pixel data as (possibly downsampled) Y, U
- and V components. The format code is made of the following information.
+ and V components. Some formats include dummy bits in some of their samples
+ and are collectively referred to as "YDYC" (Y-Dummy-Y-Chroma) formats.
+ One cannot rely on the values of these dummy bits as those are undefined.
+ </para>
+ <para>The format code is made of the following information.
<itemizedlist>
<listitem><para>The Y, U and V components order code, as transferred on the
- bus. Possible values are YUYV, UYVY, YVYU and VYUY.</para></listitem>
+ bus. Possible values are YUYV, UYVY, YVYU and VYUY for formats with no
+ dummy bit, and YDYUYDYV, YDYVYDYU, YUYDYVYD and YVYDYUYD for YDYC formats.
+ </para></listitem>
<listitem><para>The number of bits per pixel component. All components are
transferred on the same number of bits. Common values are 8, 10 and 12.</para>
</listitem>
@@ -877,7 +951,21 @@
U, Y, V, Y order will be named <constant>V4L2_MBUS_FMT_UYVY8_2X8</constant>.
</para>
- <para>The following table lisst existing packet YUV formats.</para>
+ <para><xref linkend="v4l2-mbus-pixelcode-yuv8"/> list existing packet YUV
+ formats and describes the organization of each pixel data in each sample.
+ When a format pattern is split across multiple samples each of the samples
+ in the pattern is described.</para>
+
+ <para>The role of each bit transferred over the bus is identified by one
+ of the following codes.</para>
+
+ <itemizedlist>
+ <listitem><para>y<subscript>x</subscript> for luma component bit number x</para></listitem>
+ <listitem><para>u<subscript>x</subscript> for blue chroma component bit number x</para></listitem>
+ <listitem><para>v<subscript>x</subscript> for red chroma component bit number x</para></listitem>
+ <listitem><para>- for non-available bits (for positions higher than the bus width)</para></listitem>
+ <listitem><para>d for dummy bits</para></listitem>
+ </itemizedlist>
<table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-yuv8">
<title>YUV Formats</title>
@@ -885,27 +973,37 @@
<colspec colname="id" align="left" />
<colspec colname="code" align="center"/>
<colspec colname="bit" />
- <colspec colnum="4" colname="b19" align="center" />
- <colspec colnum="5" colname="b18" align="center" />
- <colspec colnum="6" colname="b17" align="center" />
- <colspec colnum="7" colname="b16" align="center" />
- <colspec colnum="8" colname="b15" align="center" />
- <colspec colnum="9" colname="b14" align="center" />
- <colspec colnum="10" colname="b13" align="center" />
- <colspec colnum="11" colname="b12" align="center" />
- <colspec colnum="12" colname="b11" align="center" />
- <colspec colnum="13" colname="b10" align="center" />
- <colspec colnum="14" colname="b09" align="center" />
- <colspec colnum="15" colname="b08" align="center" />
- <colspec colnum="16" colname="b07" align="center" />
- <colspec colnum="17" colname="b06" align="center" />
- <colspec colnum="18" colname="b05" align="center" />
- <colspec colnum="19" colname="b04" align="center" />
- <colspec colnum="20" colname="b03" align="center" />
- <colspec colnum="21" colname="b02" align="center" />
- <colspec colnum="22" colname="b01" align="center" />
- <colspec colnum="23" colname="b00" align="center" />
- <spanspec namest="b19" nameend="b00" spanname="b0" />
+ <colspec colnum="4" colname="b29" align="center" />
+ <colspec colnum="5" colname="b28" align="center" />
+ <colspec colnum="6" colname="b27" align="center" />
+ <colspec colnum="7" colname="b26" align="center" />
+ <colspec colnum="8" colname="b25" align="center" />
+ <colspec colnum="9" colname="b24" align="center" />
+ <colspec colnum="10" colname="b23" align="center" />
+ <colspec colnum="11" colname="b22" align="center" />
+ <colspec colnum="12" colname="b21" align="center" />
+ <colspec colnum="13" colname="b20" align="center" />
+ <colspec colnum="14" colname="b19" align="center" />
+ <colspec colnum="15" colname="b18" align="center" />
+ <colspec colnum="16" colname="b17" align="center" />
+ <colspec colnum="17" colname="b16" align="center" />
+ <colspec colnum="18" colname="b15" align="center" />
+ <colspec colnum="19" colname="b14" align="center" />
+ <colspec colnum="20" colname="b13" align="center" />
+ <colspec colnum="21" colname="b12" align="center" />
+ <colspec colnum="22" colname="b11" align="center" />
+ <colspec colnum="23" colname="b10" align="center" />
+ <colspec colnum="24" colname="b09" align="center" />
+ <colspec colnum="25" colname="b08" align="center" />
+ <colspec colnum="26" colname="b07" align="center" />
+ <colspec colnum="27" colname="b06" align="center" />
+ <colspec colnum="28" colname="b05" align="center" />
+ <colspec colnum="29" colname="b04" align="center" />
+ <colspec colnum="30" colname="b03" align="center" />
+ <colspec colnum="31" colname="b02" align="center" />
+ <colspec colnum="32" colname="b01" align="center" />
+ <colspec colnum="33" colname="b00" align="center" />
+ <spanspec namest="b29" nameend="b00" spanname="b0" />
<thead>
<row>
<entry>Identifier</entry>
@@ -917,6 +1015,16 @@
<entry></entry>
<entry></entry>
<entry>Bit</entry>
+ <entry>29</entry>
+ <entry>28</entry>
+ <entry>27</entry>
+ <entry>26</entry>
+ <entry>25</entry>
+ <entry>24</entry>
+ <entry>23</entry>
+ <entry>22</entry>
+ <entry>21</entry>
+ <entry>10</entry>
<entry>19</entry>
<entry>18</entry>
<entry>17</entry>
@@ -944,16 +1052,8 @@
<entry>V4L2_MBUS_FMT_Y8_1X8</entry>
<entry>0x2001</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -965,9 +1065,9 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-UYVY8-1_5X8">
- <entry>V4L2_MBUS_FMT_UYVY8_1_5X8</entry>
- <entry>0x2002</entry>
+ <row id="V4L2-MBUS-FMT-UV8-1X8">
+ <entry>V4L2_MBUS_FMT_UV8_1X8</entry>
+ <entry>0x2015</entry>
<entry></entry>
<entry>-</entry>
<entry>-</entry>
@@ -1006,6 +1106,40 @@
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-UYVY8-1_5X8">
+ <entry>V4L2_MBUS_FMT_UYVY8_1_5X8</entry>
+ <entry>0x2002</entry>
+ <entry></entry>
+ &dash-ent-10;
+ &dash-ent-10;
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ &dash-ent-10;
+ &dash-ent-10;
+ <entry>-</entry>
+ <entry>-</entry>
<entry>y<subscript>7</subscript></entry>
<entry>y<subscript>6</subscript></entry>
<entry>y<subscript>5</subscript></entry>
@@ -1019,16 +1153,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1044,16 +1170,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>v<subscript>7</subscript></entry>
@@ -1069,16 +1187,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1094,16 +1204,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1119,16 +1221,8 @@
<entry>V4L2_MBUS_FMT_VYUY8_1_5X8</entry>
<entry>0x2003</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>v<subscript>7</subscript></entry>
@@ -1144,16 +1238,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1169,16 +1255,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1194,16 +1272,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>u<subscript>7</subscript></entry>
@@ -1219,16 +1289,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1244,16 +1306,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1269,16 +1323,8 @@
<entry>V4L2_MBUS_FMT_YUYV8_1_5X8</entry>
<entry>0x2004</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1294,16 +1340,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1319,16 +1357,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>u<subscript>7</subscript></entry>
@@ -1344,16 +1374,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1369,16 +1391,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1394,16 +1408,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>v<subscript>7</subscript></entry>
@@ -1419,16 +1425,8 @@
<entry>V4L2_MBUS_FMT_YVYU8_1_5X8</entry>
<entry>0x2005</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1444,16 +1442,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1469,16 +1459,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>v<subscript>7</subscript></entry>
@@ -1494,16 +1476,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1519,16 +1493,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1544,16 +1510,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>u<subscript>7</subscript></entry>
@@ -1569,16 +1527,8 @@
<entry>V4L2_MBUS_FMT_UYVY8_2X8</entry>
<entry>0x2006</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>u<subscript>7</subscript></entry>
@@ -1594,16 +1544,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1619,16 +1561,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>v<subscript>7</subscript></entry>
@@ -1644,16 +1578,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1669,16 +1595,8 @@
<entry>V4L2_MBUS_FMT_VYUY8_2X8</entry>
<entry>0x2007</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>v<subscript>7</subscript></entry>
@@ -1694,16 +1612,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1719,16 +1629,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>u<subscript>7</subscript></entry>
@@ -1744,16 +1646,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1769,16 +1663,8 @@
<entry>V4L2_MBUS_FMT_YUYV8_2X8</entry>
<entry>0x2008</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1794,16 +1680,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>u<subscript>7</subscript></entry>
@@ -1819,16 +1697,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1844,16 +1714,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>v<subscript>7</subscript></entry>
@@ -1869,16 +1731,8 @@
<entry>V4L2_MBUS_FMT_YVYU8_2X8</entry>
<entry>0x2009</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1894,16 +1748,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>v<subscript>7</subscript></entry>
@@ -1919,16 +1765,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>y<subscript>7</subscript></entry>
@@ -1944,16 +1782,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>u<subscript>7</subscript></entry>
@@ -1969,16 +1799,8 @@
<entry>V4L2_MBUS_FMT_Y10_1X10</entry>
<entry>0x200a</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>y<subscript>9</subscript></entry>
<entry>y<subscript>8</subscript></entry>
<entry>y<subscript>7</subscript></entry>
@@ -1994,16 +1816,8 @@
<entry>V4L2_MBUS_FMT_YUYV10_2X10</entry>
<entry>0x200b</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>y<subscript>9</subscript></entry>
<entry>y<subscript>8</subscript></entry>
<entry>y<subscript>7</subscript></entry>
@@ -2019,16 +1833,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>u<subscript>9</subscript></entry>
<entry>u<subscript>8</subscript></entry>
<entry>u<subscript>7</subscript></entry>
@@ -2044,16 +1850,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>y<subscript>9</subscript></entry>
<entry>y<subscript>8</subscript></entry>
<entry>y<subscript>7</subscript></entry>
@@ -2069,16 +1867,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>v<subscript>9</subscript></entry>
<entry>v<subscript>8</subscript></entry>
<entry>v<subscript>7</subscript></entry>
@@ -2094,16 +1884,8 @@
<entry>V4L2_MBUS_FMT_YVYU10_2X10</entry>
<entry>0x200c</entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>y<subscript>9</subscript></entry>
<entry>y<subscript>8</subscript></entry>
<entry>y<subscript>7</subscript></entry>
@@ -2119,16 +1901,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>v<subscript>9</subscript></entry>
<entry>v<subscript>8</subscript></entry>
<entry>v<subscript>7</subscript></entry>
@@ -2144,16 +1918,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>y<subscript>9</subscript></entry>
<entry>y<subscript>8</subscript></entry>
<entry>y<subscript>7</subscript></entry>
@@ -2169,16 +1935,8 @@
<entry></entry>
<entry></entry>
<entry></entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ &dash-ent-10;
+ &dash-ent-10;
<entry>u<subscript>9</subscript></entry>
<entry>u<subscript>8</subscript></entry>
<entry>u<subscript>7</subscript></entry>
@@ -2194,6 +1952,7 @@
<entry>V4L2_MBUS_FMT_Y12_1X12</entry>
<entry>0x2013</entry>
<entry></entry>
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
@@ -2219,6 +1978,7 @@
<entry>V4L2_MBUS_FMT_UYVY8_1X16</entry>
<entry>0x200f</entry>
<entry></entry>
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
@@ -2244,6 +2004,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
@@ -2269,6 +2030,7 @@
<entry>V4L2_MBUS_FMT_VYUY8_1X16</entry>
<entry>0x2010</entry>
<entry></entry>
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
@@ -2294,6 +2056,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
@@ -2319,6 +2082,7 @@
<entry>V4L2_MBUS_FMT_YUYV8_1X16</entry>
<entry>0x2011</entry>
<entry></entry>
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
@@ -2344,6 +2108,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
@@ -2369,6 +2134,7 @@
<entry>V4L2_MBUS_FMT_YVYU8_1X16</entry>
<entry>0x2012</entry>
<entry></entry>
+ &dash-ent-10;
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
@@ -2394,6 +2160,57 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-10;
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-YDYUYDYV8-1X16">
+ <entry>V4L2_MBUS_FMT_YDYUYDYV8_1X16</entry>
+ <entry>0x2014</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
<entry>-</entry>
<entry>-</entry>
<entry>-</entry>
@@ -2415,10 +2232,61 @@
<entry>u<subscript>1</subscript></entry>
<entry>u<subscript>0</subscript></entry>
</row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ <entry>d</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
<row id="V4L2-MBUS-FMT-YUYV10-1X20">
<entry>V4L2_MBUS_FMT_YUYV10_1X20</entry>
<entry>0x200d</entry>
<entry></entry>
+ &dash-ent-10;
<entry>y<subscript>9</subscript></entry>
<entry>y<subscript>8</subscript></entry>
<entry>y<subscript>7</subscript></entry>
@@ -2444,6 +2312,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-10;
<entry>y<subscript>9</subscript></entry>
<entry>y<subscript>8</subscript></entry>
<entry>y<subscript>7</subscript></entry>
@@ -2469,6 +2338,7 @@
<entry>V4L2_MBUS_FMT_YVYU10_1X20</entry>
<entry>0x200e</entry>
<entry></entry>
+ &dash-ent-10;
<entry>y<subscript>9</subscript></entry>
<entry>y<subscript>8</subscript></entry>
<entry>y<subscript>7</subscript></entry>
@@ -2494,6 +2364,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-10;
<entry>y<subscript>9</subscript></entry>
<entry>y<subscript>8</subscript></entry>
<entry>y<subscript>7</subscript></entry>
@@ -2515,6 +2386,41 @@
<entry>u<subscript>1</subscript></entry>
<entry>u<subscript>0</subscript></entry>
</row>
+ <row id="V4L2-MBUS-FMT-YUV10-1X30">
+ <entry>V4L2_MBUS_FMT_YUV10_1X30</entry>
+ <entry>0x2014</entry>
+ <entry></entry>
+ <entry>y<subscript>9</subscript></entry>
+ <entry>y<subscript>8</subscript></entry>
+ <entry>y<subscript>7</subscript></entry>
+ <entry>y<subscript>6</subscript></entry>
+ <entry>y<subscript>5</subscript></entry>
+ <entry>y<subscript>4</subscript></entry>
+ <entry>y<subscript>3</subscript></entry>
+ <entry>y<subscript>2</subscript></entry>
+ <entry>y<subscript>1</subscript></entry>
+ <entry>y<subscript>0</subscript></entry>
+ <entry>u<subscript>9</subscript></entry>
+ <entry>u<subscript>8</subscript></entry>
+ <entry>u<subscript>7</subscript></entry>
+ <entry>u<subscript>6</subscript></entry>
+ <entry>u<subscript>5</subscript></entry>
+ <entry>u<subscript>4</subscript></entry>
+ <entry>u<subscript>3</subscript></entry>
+ <entry>u<subscript>2</subscript></entry>
+ <entry>u<subscript>1</subscript></entry>
+ <entry>u<subscript>0</subscript></entry>
+ <entry>v<subscript>9</subscript></entry>
+ <entry>v<subscript>8</subscript></entry>
+ <entry>v<subscript>7</subscript></entry>
+ <entry>v<subscript>6</subscript></entry>
+ <entry>v<subscript>5</subscript></entry>
+ <entry>v<subscript>4</subscript></entry>
+ <entry>v<subscript>3</subscript></entry>
+ <entry>v<subscript>2</subscript></entry>
+ <entry>v<subscript>1</subscript></entry>
+ <entry>v<subscript>0</subscript></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index 4d110b1ad3e9..a3cce18384e9 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -140,6 +140,16 @@ structs, ioctls) must be noted in more detail in the history chapter
applications. -->
<revision>
+ <revnumber>3.9</revnumber>
+ <date>2012-12-03</date>
+ <authorinitials>sa, sn</authorinitials>
+ <revremark>Added timestamp types to v4l2_buffer.
+ Added <constant>V4L2_EVENT_CTRL_CH_RANGE</constant> control
+ event changes flag, see <xref linkend="changes-flags"/>.
+ </revremark>
+ </revision>
+
+ <revision>
<revnumber>3.6</revnumber>
<date>2012-07-02</date>
<authorinitials>hv</authorinitials>
@@ -472,7 +482,7 @@ and discussions on the V4L mailing list.</revremark>
</partinfo>
<title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.6</subtitle>
+ <subtitle>Revision 3.9</subtitle>
<chapter id="common">
&sub-common;
diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
index 98a856f9ec30..89891adb928a 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
@@ -261,6 +261,12 @@
<entry>This control event was triggered because the control flags
changed.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_EVENT_CTRL_CH_RANGE</constant></entry>
+ <entry>0x0004</entry>
+ <entry>This control event was triggered because the minimum,
+ maximum, step or the default value of the control changed.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml
index 72dfbd20a802..e287c8fc803b 100644
--- a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml
@@ -83,15 +83,14 @@ descriptor. The application may pass it to other DMABUF-aware devices. Refer to
<link linkend="dmabuf">DMABUF importing</link> for details about importing
DMABUF files into V4L2 nodes. It is recommended to close a DMABUF file when it
is no longer used to allow the associated memory to be reclaimed. </para>
-
</refsect1>
+
<refsect1>
- <section>
- <title>Examples</title>
+ <title>Examples</title>
- <example>
- <title>Exporting a buffer.</title>
- <programlisting>
+ <example>
+ <title>Exporting a buffer.</title>
+ <programlisting>
int buffer_export(int v4lfd, &v4l2-buf-type; bt, int index, int *dmafd)
{
&v4l2-exportbuffer; expbuf;
@@ -108,12 +107,12 @@ int buffer_export(int v4lfd, &v4l2-buf-type; bt, int index, int *dmafd)
return 0;
}
- </programlisting>
- </example>
+ </programlisting>
+ </example>
- <example>
- <title>Exporting a buffer using the multi-planar API.</title>
- <programlisting>
+ <example>
+ <title>Exporting a buffer using the multi-planar API.</title>
+ <programlisting>
int buffer_export_mp(int v4lfd, &v4l2-buf-type; bt, int index,
int dmafd[], int n_planes)
{
@@ -137,12 +136,9 @@ int buffer_export_mp(int v4lfd, &v4l2-buf-type; bt, int index,
return 0;
}
- </programlisting>
- </example>
- </section>
- </refsect1>
+ </programlisting>
+ </example>
- <refsect1>
<table pgwide="1" frame="none" id="v4l2-exportbuffer">
<title>struct <structname>v4l2_exportbuffer</structname></title>
<tgroup cols="3">
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml b/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml
index 12b1d0503e26..ee2820d6ca66 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml
@@ -64,7 +64,9 @@ return an &EINVAL;. When the <structfield>value</structfield> is out
of bounds drivers can choose to take the closest valid value or return
an &ERANGE;, whatever seems more appropriate. However,
<constant>VIDIOC_S_CTRL</constant> is a write-only ioctl, it does not
-return the actual new value.</para>
+return the actual new value. If the <structfield>value</structfield>
+is inappropriate for the control (e.g. if it refers to an unsupported
+menu index of a menu control), then &EINVAL; is returned as well.</para>
<para>These ioctls work only with user controls. For other
control classes the &VIDIOC-G-EXT-CTRLS;, &VIDIOC-S-EXT-CTRLS; or
@@ -99,7 +101,9 @@ application.</entry>
<term><errorcode>EINVAL</errorcode></term>
<listitem>
<para>The &v4l2-control; <structfield>id</structfield> is
-invalid.</para>
+invalid or the <structfield>value</structfield> is inappropriate for
+the given control (i.e. if a menu item is selected that is not supported
+by the driver according to &VIDIOC-QUERYMENU;).</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
index 0a4b90fcf2da..4e16112df992 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -106,7 +106,9 @@ value or if an error is returned.</para>
&EINVAL;. When the value is out of bounds drivers can choose to take
the closest valid value or return an &ERANGE;, whatever seems more
appropriate. In the first case the new value is set in
-&v4l2-ext-control;.</para>
+&v4l2-ext-control;. If the new control value is inappropriate (e.g. the
+given menu index is not supported by the menu control), then this will
+also result in an &EINVAL; error.</para>
<para>The driver will only set/get these controls if all control
values are correct. This prevents the situation where only some of the
@@ -199,13 +201,46 @@ also be zero.</entry>
<row>
<entry>__u32</entry>
<entry><structfield>error_idx</structfield></entry>
- <entry>Set by the driver in case of an error. If it is equal
-to <structfield>count</structfield>, then no actual changes were made to
-controls. In other words, the error was not associated with setting a particular
-control. If it is another value, then only the controls up to <structfield>error_idx-1</structfield>
-were modified and control <structfield>error_idx</structfield> is the one that
-caused the error. The <structfield>error_idx</structfield> value is undefined
-if the ioctl returned 0 (success).</entry>
+ <entry><para>Set by the driver in case of an error. If the error is
+associated with a particular control, then <structfield>error_idx</structfield>
+is set to the index of that control. If the error is not related to a specific
+control, or the validation step failed (see below), then
+<structfield>error_idx</structfield> is set to <structfield>count</structfield>.
+The value is undefined if the ioctl returned 0 (success).</para>
+
+<para>Before controls are read from/written to hardware a validation step
+takes place: this checks if all controls in the list are valid controls,
+if no attempt is made to write to a read-only control or read from a write-only
+control, and any other up-front checks that can be done without accessing the
+hardware. The exact validations done during this step are driver dependent
+since some checks might require hardware access for some devices, thus making
+it impossible to do those checks up-front. However, drivers should make a
+best-effort to do as many up-front checks as possible.</para>
+
+<para>This check is done to avoid leaving the hardware in an inconsistent state due
+to easy-to-avoid problems. But it leads to another problem: the application needs to
+know whether an error came from the validation step (meaning that the hardware
+was not touched) or from an error during the actual reading from/writing to hardware.</para>
+
+<para>The, in hindsight quite poor, solution for that is to set <structfield>error_idx</structfield>
+to <structfield>count</structfield> if the validation failed. This has the
+unfortunate side-effect that it is not possible to see which control failed the
+validation. If the validation was successful and the error happened while
+accessing the hardware, then <structfield>error_idx</structfield> is less than
+<structfield>count</structfield> and only the controls up to
+<structfield>error_idx-1</structfield> were read or written correctly, and the
+state of the remaining controls is undefined.</para>
+
+<para>Since <constant>VIDIOC_TRY_EXT_CTRLS</constant> does not access hardware
+there is also no need to handle the validation step in this special way,
+so <structfield>error_idx</structfield> will just be set to the control that
+failed the validation step instead of to <structfield>count</structfield>.
+This means that if <constant>VIDIOC_S_EXT_CTRLS</constant> fails with
+<structfield>error_idx</structfield> set to <structfield>count</structfield>,
+then you can call <constant>VIDIOC_TRY_EXT_CTRLS</constant> to try to discover
+the actual control that failed the validation step. Unfortunately, there
+is no <constant>TRY</constant> equivalent for <constant>VIDIOC_G_EXT_CTRLS</constant>.
+</para></entry>
</row>
<row>
<entry>__u32</entry>
@@ -298,8 +333,10 @@ These controls are described in <xref
<term><errorcode>EINVAL</errorcode></term>
<listitem>
<para>The &v4l2-ext-control; <structfield>id</structfield>
-is invalid or the &v4l2-ext-controls;
-<structfield>ctrl_class</structfield> is invalid. This error code is
+is invalid, the &v4l2-ext-controls;
+<structfield>ctrl_class</structfield> is invalid, or the &v4l2-ext-control;
+<structfield>value</structfield> was inappropriate (e.g. the given menu
+index is not supported by the driver). This error code is
also returned by the <constant>VIDIOC_S_EXT_CTRLS</constant> and
<constant>VIDIOC_TRY_EXT_CTRLS</constant> ioctls if two or more
control values are in conflict.</para>
diff --git a/Documentation/DocBook/media/v4l/vidioc-querycap.xml b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
index 4c70215ae03f..d5a3c97b206a 100644
--- a/Documentation/DocBook/media/v4l/vidioc-querycap.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
@@ -76,7 +76,7 @@ make sure the strings are properly NUL-terminated.</para></entry>
<row>
<entry>__u8</entry>
<entry><structfield>card</structfield>[32]</entry>
- <entry>Name of the device, a NUL-terminated ASCII string.
+ <entry>Name of the device, a NUL-terminated UTF-8 string.
For example: "Yoyodyne TV/FM". One driver may support different brands
or models of video hardware. This information is intended for users,
for example in a menu of available devices. Since multiple TV cards of
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl
index f2413acfe241..1f6593deb995 100644
--- a/Documentation/DocBook/media_api.tmpl
+++ b/Documentation/DocBook/media_api.tmpl
@@ -22,6 +22,7 @@
<!-- LinuxTV v4l-dvb repository. -->
<!ENTITY v4l-dvb "<ulink url='http://linuxtv.org/repo/'>http://linuxtv.org/repo/</ulink>">
+<!ENTITY dash-ent-10 "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
]>
<book id="media_api">
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl
index ddb05e98af0d..95618159e29b 100644
--- a/Documentation/DocBook/uio-howto.tmpl
+++ b/Documentation/DocBook/uio-howto.tmpl
@@ -984,7 +984,7 @@ int main()
return errno;
}
configfd = open(&quot;/sys/class/uio/uio0/device/config&quot;, O_RDWR);
- if (uiofd &lt; 0) {
+ if (configfd &lt; 0) {
perror(&quot;config open:&quot;);
return errno;
}
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl
index fb32aead5a0b..bd6fee22c4dd 100644
--- a/Documentation/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl
@@ -871,9 +871,8 @@
<para>
This function itself doesn't allocate the data space. The data
must be allocated manually beforehand, and its pointer is passed
- as the argument. This pointer is used as the
- (<parameter>chip</parameter> identifier in the above example)
- for the instance.
+ as the argument. This pointer (<parameter>chip</parameter> in the
+ above example) is used as the identifier for the instance.
</para>
<para>
@@ -2304,7 +2303,7 @@ struct _snd_pcm_runtime {
<constant>SNDRV_PCM_INFO_XXX</constant>. Here, at least, you
have to specify whether the mmap is supported and which
interleaved format is supported.
- When the is supported, add the
+ When the hardware supports mmap, add the
<constant>SNDRV_PCM_INFO_MMAP</constant> flag here. When the
hardware supports the interleaved or the non-interleaved
formats, <constant>SNDRV_PCM_INFO_INTERLEAVED</constant> or
@@ -2898,7 +2897,7 @@ struct _snd_pcm_runtime {
<para>
When the pcm supports the pause operation (given in the info
- field of the hardware table), the <constant>PAUSE_PUSE</constant>
+ field of the hardware table), the <constant>PAUSE_PUSH</constant>
and <constant>PAUSE_RELEASE</constant> commands must be
handled here, too. The former is the command to pause the pcm,
and the latter to restart the pcm again.
@@ -3085,7 +3084,7 @@ struct _snd_pcm_runtime {
<section id="pcm-interface-interrupt-handler-timer">
<title>High frequency timer interrupts</title>
<para>
- This happense when the hardware doesn't generate interrupts
+ This happens when the hardware doesn't generate interrupts
at the period boundary but issues timer interrupts at a fixed
timer rate (e.g. es1968 or ymfpci drivers).
In this case, you need to check the current hardware
@@ -3251,18 +3250,19 @@ struct _snd_pcm_runtime {
<title>Example of Hardware Constraints for Channels</title>
<programlisting>
<![CDATA[
- static int hw_rule_format_by_channels(struct snd_pcm_hw_params *params,
+ static int hw_rule_channels_by_format(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval *c = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
+ SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- struct snd_mask fmt;
+ struct snd_interval ch;
- snd_mask_any(&fmt); /* Init the struct */
- if (c->min < 2) {
- fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE;
- return snd_mask_refine(f, &fmt);
+ snd_interval_any(&ch);
+ if (f->bits[0] == SNDRV_PCM_FMTBIT_S16_LE) {
+ ch.min = ch.max = 1;
+ ch.integer = 1;
+ return snd_interval_refine(c, &ch);
}
return 0;
}
@@ -3278,35 +3278,35 @@ struct _snd_pcm_runtime {
<programlisting>
<![CDATA[
snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- hw_rule_channels_by_format, 0, SNDRV_PCM_HW_PARAM_FORMAT,
- -1);
+ hw_rule_channels_by_format, NULL,
+ SNDRV_PCM_HW_PARAM_FORMAT, -1);
]]>
</programlisting>
</informalexample>
</para>
<para>
- The rule function is called when an application sets the number of
- channels. But an application can set the format before the number of
- channels. Thus you also need to define the inverse rule:
+ The rule function is called when an application sets the PCM
+ format, and it refines the number of channels accordingly.
+ But an application may set the number of channels before
+ setting the format. Thus you also need to define the inverse rule:
<example>
- <title>Example of Hardware Constraints for Channels</title>
+ <title>Example of Hardware Constraints for Formats</title>
<programlisting>
<![CDATA[
- static int hw_rule_channels_by_format(struct snd_pcm_hw_params *params,
+ static int hw_rule_format_by_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval *c = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
+ SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- struct snd_interval ch;
+ struct snd_mask fmt;
- snd_interval_any(&ch);
- if (f->bits[0] == SNDRV_PCM_FMTBIT_S16_LE) {
- ch.min = ch.max = 1;
- ch.integer = 1;
- return snd_interval_refine(c, &ch);
+ snd_mask_any(&fmt); /* Init the struct */
+ if (c->min < 2) {
+ fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE;
+ return snd_mask_refine(f, &fmt);
}
return 0;
}
@@ -3321,8 +3321,8 @@ struct _snd_pcm_runtime {
<programlisting>
<![CDATA[
snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
- hw_rule_format_by_channels, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- -1);
+ hw_rule_format_by_channels, NULL,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
]]>
</programlisting>
</informalexample>
diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt
index 53e6fca146d7..a09178086c30 100644
--- a/Documentation/PCI/MSI-HOWTO.txt
+++ b/Documentation/PCI/MSI-HOWTO.txt
@@ -127,15 +127,42 @@ on the number of vectors that can be allocated; pci_enable_msi_block()
returns as soon as it finds any constraint that doesn't allow the
call to succeed.
-4.2.3 pci_disable_msi
+4.2.3 pci_enable_msi_block_auto
+
+int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *count)
+
+This variation on pci_enable_msi() call allows a device driver to request
+the maximum possible number of MSIs. The MSI specification only allows
+interrupts to be allocated in powers of two, up to a maximum of 2^5 (32).
+
+If this function returns a positive number, it indicates that it has
+succeeded and the returned value is the number of allocated interrupts. In
+this case, the function enables MSI on this device and updates dev->irq to
+be the lowest of the new interrupts assigned to it. The other interrupts
+assigned to the device are in the range dev->irq to dev->irq + returned
+value - 1.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to request any more MSI interrupts for
+this device.
+
+If the device driver needs to know the number of interrupts the device
+supports it can pass the pointer count where that number is stored. The
+device driver must decide what action to take if pci_enable_msi_block_auto()
+succeeds, but returns a value less than the number of interrupts supported.
+If the device driver does not need to know the number of interrupts
+supported, it can set the pointer count to NULL.
+
+4.2.4 pci_disable_msi
void pci_disable_msi(struct pci_dev *dev)
This function should be used to undo the effect of pci_enable_msi() or
-pci_enable_msi_block(). Calling it restores dev->irq to the pin-based
-interrupt number and frees the previously allocated message signaled
-interrupt(s). The interrupt may subsequently be assigned to another
-device, so drivers should not cache the value of dev->irq.
+pci_enable_msi_block() or pci_enable_msi_block_auto(). Calling it restores
+dev->irq to the pin-based interrupt number and frees the previously
+allocated message signaled interrupt(s). The interrupt may subsequently be
+assigned to another device, so drivers should not cache the value of
+dev->irq.
Before calling this function, a device driver must always call free_irq()
on any interrupt for which it previously called request_irq().
diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt
index 54469bc81b1c..94a656131885 100644
--- a/Documentation/acpi/enumeration.txt
+++ b/Documentation/acpi/enumeration.txt
@@ -63,8 +63,8 @@ from ACPI tables.
Currently the kernel is not able to automatically determine from which ACPI
device it should make the corresponding platform device so we need to add
the ACPI device explicitly to acpi_platform_device_ids list defined in
-drivers/acpi/scan.c. This limitation is only for the platform devices, SPI
-and I2C devices are created automatically as described below.
+drivers/acpi/acpi_platform.c. This limitation is only for the platform
+devices, SPI and I2C devices are created automatically as described below.
SPI serial bus support
~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/acpi/scan_handlers.txt b/Documentation/acpi/scan_handlers.txt
new file mode 100644
index 000000000000..3246ccf15992
--- /dev/null
+++ b/Documentation/acpi/scan_handlers.txt
@@ -0,0 +1,77 @@
+ACPI Scan Handlers
+
+Copyright (C) 2012, Intel Corporation
+Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+During system initialization and ACPI-based device hot-add, the ACPI namespace
+is scanned in search of device objects that generally represent various pieces
+of hardware. This causes a struct acpi_device object to be created and
+registered with the driver core for every device object in the ACPI namespace
+and the hierarchy of those struct acpi_device objects reflects the namespace
+layout (i.e. parent device objects in the namespace are represented by parent
+struct acpi_device objects and analogously for their children). Those struct
+acpi_device objects are referred to as "device nodes" in what follows, but they
+should not be confused with struct device_node objects used by the Device Trees
+parsing code (although their role is analogous to the role of those objects).
+
+During ACPI-based device hot-remove device nodes representing pieces of hardware
+being removed are unregistered and deleted.
+
+The core ACPI namespace scanning code in drivers/acpi/scan.c carries out basic
+initialization of device nodes, such as retrieving common configuration
+information from the device objects represented by them and populating them with
+appropriate data, but some of them require additional handling after they have
+been registered. For example, if the given device node represents a PCI host
+bridge, its registration should cause the PCI bus under that bridge to be
+enumerated and PCI devices on that bus to be registered with the driver core.
+Similarly, if the device node represents a PCI interrupt link, it is necessary
+to configure that link so that the kernel can use it.
+
+Those additional configuration tasks usually depend on the type of the hardware
+component represented by the given device node which can be determined on the
+basis of the device node's hardware ID (HID). They are performed by objects
+called ACPI scan handlers represented by the following structure:
+
+struct acpi_scan_handler {
+ const struct acpi_device_id *ids;
+ struct list_head list_node;
+ int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
+ void (*detach)(struct acpi_device *dev);
+};
+
+where ids is the list of IDs of device nodes the given handler is supposed to
+take care of, list_node is the hook to the global list of ACPI scan handlers
+maintained by the ACPI core and the .attach() and .detach() callbacks are
+executed, respectively, after registration of new device nodes and before
+unregistration of device nodes the handler attached to previously.
+
+The namespace scanning function, acpi_bus_scan(), first registers all of the
+device nodes in the given namespace scope with the driver core. Then, it tries
+to match a scan handler against each of them using the ids arrays of the
+available scan handlers. If a matching scan handler is found, its .attach()
+callback is executed for the given device node. If that callback returns 1,
+that means that the handler has claimed the device node and is now responsible
+for carrying out any additional configuration tasks related to it. It also will
+be responsible for preparing the device node for unregistration in that case.
+The device node's handler field is then populated with the address of the scan
+handler that has claimed it.
+
+If the .attach() callback returns 0, it means that the device node is not
+interesting to the given scan handler and may be matched against the next scan
+handler in the list. If it returns a (negative) error code, that means that
+the namespace scan should be terminated due to a serious error. The error code
+returned should then reflect the type of the error.
+
+The namespace trimming function, acpi_bus_trim(), first executes .detach()
+callbacks from the scan handlers of all device nodes in the given namespace
+scope (if they have scan handlers). Next, it unregisters all of the device
+nodes in that scope.
+
+ACPI scan handlers can be added to the list maintained by the ACPI core with the
+help of the acpi_scan_add_handler() function taking a pointer to the new scan
+handler as an argument. The order in which scan handlers are added to the list
+is the order in which they are matched against device nodes during namespace
+scans.
+
+All scan handles must be added to the list before acpi_bus_scan() is run for the
+first time and they cannot be removed from it.
diff --git a/Documentation/arm64/memory.txt b/Documentation/arm64/memory.txt
index d758702fc03c..5f583af0a6e1 100644
--- a/Documentation/arm64/memory.txt
+++ b/Documentation/arm64/memory.txt
@@ -35,6 +35,8 @@ ffffffbc00000000 ffffffbdffffffff 8GB vmemmap
ffffffbe00000000 ffffffbffbbfffff ~8GB [guard, future vmmemap]
+ffffffbffbc00000 ffffffbffbdfffff 2MB earlyprintk device
+
ffffffbffbe00000 ffffffbffbe0ffff 64KB PCI I/O space
ffffffbbffff0000 ffffffbcffffffff ~2MB [guard]
diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt
index 27f2b21a9d5c..d9ca5be9b471 100644
--- a/Documentation/atomic_ops.txt
+++ b/Documentation/atomic_ops.txt
@@ -253,6 +253,8 @@ This performs an atomic exchange operation on the atomic variable v, setting
the given new value. It returns the old value that the atomic variable v had
just before the operation.
+atomic_xchg requires explicit memory barriers around the operation.
+
int atomic_cmpxchg(atomic_t *v, int old, int new);
This performs an atomic compare exchange operation on the atomic value v,
diff --git a/Documentation/backlight/lp855x-driver.txt b/Documentation/backlight/lp855x-driver.txt
index 1529394cfe8b..18b06ca038ea 100644
--- a/Documentation/backlight/lp855x-driver.txt
+++ b/Documentation/backlight/lp855x-driver.txt
@@ -4,7 +4,7 @@ Kernel driver lp855x
Backlight driver for LP855x ICs
Supported chips:
- Texas Instruments LP8550, LP8551, LP8552, LP8553 and LP8556
+ Texas Instruments LP8550, LP8551, LP8552, LP8553, LP8556 and LP8557
Author: Milo(Woogyom) Kim <milo.kim@ti.com>
@@ -24,7 +24,7 @@ Value : pwm based or register based
2) chip_id
The lp855x chip id.
-Value : lp8550/lp8551/lp8552/lp8553/lp8556
+Value : lp8550/lp8551/lp8552/lp8553/lp8556/lp8557
Platform data for lp855x
------------------------
diff --git a/Documentation/cgroups/00-INDEX b/Documentation/cgroups/00-INDEX
index f78b90a35ad0..f5635a09c3f6 100644
--- a/Documentation/cgroups/00-INDEX
+++ b/Documentation/cgroups/00-INDEX
@@ -4,8 +4,6 @@ blkio-controller.txt
- Description for Block IO Controller, implementation and usage details.
cgroups.txt
- Control Groups definition, implementation details, examples and API.
-cgroup_event_listener.c
- - A user program for cgroup listener.
cpuacct.txt
- CPU Accounting Controller; account CPU usage for groups of tasks.
cpusets.txt
diff --git a/Documentation/cgroups/memcg_test.txt b/Documentation/cgroups/memcg_test.txt
index fc8fa97a09ac..ce94a83a7d9a 100644
--- a/Documentation/cgroups/memcg_test.txt
+++ b/Documentation/cgroups/memcg_test.txt
@@ -399,8 +399,7 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
9.10 Memory thresholds
Memory controller implements memory thresholds using cgroups notification
- API. You can use Documentation/cgroups/cgroup_event_listener.c to test
- it.
+ API. You can use tools/cgroup/cgroup_event_listener.c to test it.
(Shell-A) Create cgroup and run event listener
# mkdir /cgroup/A
diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt
index c436096351f8..72f70b16d299 100644
--- a/Documentation/cpu-freq/cpu-drivers.txt
+++ b/Documentation/cpu-freq/cpu-drivers.txt
@@ -111,6 +111,12 @@ policy->governor must contain the "default policy" for
For setting some of these values, the frequency table helpers might be
helpful. See the section 2 for more information on them.
+SMP systems normally have same clock source for a group of cpus. For these the
+.init() would be called only once for the first online cpu. Here the .init()
+routine must initialize policy->cpus with mask of all possible cpus (Online +
+Offline) that share the clock. Then the core would copy this mask onto
+policy->related_cpus and will reset policy->cpus to carry only online cpus.
+
1.3 verify
------------
diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt
index 04f6b32993e6..ff2f28332cc4 100644
--- a/Documentation/cpu-freq/user-guide.txt
+++ b/Documentation/cpu-freq/user-guide.txt
@@ -190,11 +190,11 @@ scaling_max_freq show the current "policy limits" (in
first set scaling_max_freq, then
scaling_min_freq.
-affected_cpus : List of CPUs that require software coordination
- of frequency.
+affected_cpus : List of Online CPUs that require software
+ coordination of frequency.
-related_cpus : List of CPUs that need some sort of frequency
- coordination, whether software or hardware.
+related_cpus : List of Online + Offline CPUs that need software
+ coordination of frequency.
scaling_driver : Hardware driver for cpufreq.
diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt
index 07c65e3cdcbe..f4d04a067282 100644
--- a/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt
+++ b/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt
@@ -3,9 +3,11 @@ Altera SOCFPGA System Manager
Required properties:
- compatible : "altr,sys-mgr"
- reg : Should contain 1 register ranges(address and length)
+- cpu1-start-addr : CPU1 start address in hex.
Example:
sysmgr@ffd08000 {
compatible = "altr,sys-mgr";
reg = <0xffd08000 0x1000>;
+ cpu1-start-addr = <0xffd080c4>;
};
diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
index 52478c83d0cc..20746e5abe6f 100644
--- a/Documentation/devicetree/bindings/arm/arch_timer.txt
+++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
@@ -1,13 +1,14 @@
* ARM architected timer
-ARM Cortex-A7 and Cortex-A15 have a per-core architected timer, which
-provides per-cpu timers.
+ARM cores may have a per-core architected timer, which provides per-cpu timers.
The timer is attached to a GIC to deliver its per-processor interrupts.
** Timer node properties:
-- compatible : Should at least contain "arm,armv7-timer".
+- compatible : Should at least contain one of
+ "arm,armv7-timer"
+ "arm,armv8-timer"
- interrupts : Interrupt list for secure, non-secure, virtual and
hypervisor timers, in that order.
diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt
index 19078bf5cca8..ad031211b5b8 100644
--- a/Documentation/devicetree/bindings/arm/atmel-aic.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-aic.txt
@@ -4,7 +4,7 @@ Required properties:
- compatible: Should be "atmel,<chip>-aic"
- interrupt-controller: Identifies the node as an interrupt controller.
- interrupt-parent: For single AIC system, it is an empty property.
-- #interrupt-cells: The number of cells to define the interrupts. It sould be 3.
+- #interrupt-cells: The number of cells to define the interrupts. It should be 3.
The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet).
The second cell is used to specify flags:
bits[3:0] trigger type and level flags:
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
index 62eb8df1e08d..3dfb0c0384f5 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -42,7 +42,7 @@ Main node required properties:
Optional
- interrupts : Interrupt source of the parent interrupt controller on
- secondary GICs, or VGIC maintainance interrupt on primary GIC (see
+ secondary GICs, or VGIC maintenance interrupt on primary GIC (see
below).
- cpu-offset : per-cpu offset within the distributor and cpu interface
@@ -74,7 +74,7 @@ Required properties:
virtual interface control register base and size. The 2nd additional
region is the GIC virtual cpu interface register base and size.
-- interrupts : VGIC maintainance interrupt.
+- interrupts : VGIC maintenance interrupt.
Example:
diff --git a/Documentation/devicetree/bindings/arm/kirkwood.txt b/Documentation/devicetree/bindings/arm/kirkwood.txt
new file mode 100644
index 000000000000..98cce9a653eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/kirkwood.txt
@@ -0,0 +1,27 @@
+Marvell Kirkwood Platforms Device Tree Bindings
+-----------------------------------------------
+
+Boards with a SoC of the Marvell Kirkwood
+shall have the following property:
+
+Required root node property:
+
+compatible: must contain "marvell,kirkwood";
+
+In order to support the kirkwood cpufreq driver, there must be a node
+cpus/cpu@0 with three clocks, "cpu_clk", "ddrclk" and "powersave",
+where the "powersave" clock is a gating clock used to switch the CPU
+between the "cpu_clk" and the "ddrclk".
+
+Example:
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "marvell,sheeva-88SV131";
+ clocks = <&core_clk 1>, <&core_clk 3>, <&gate_clk 11>;
+ clock-names = "cpu_clk", "ddrclk", "powersave";
+ };
diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
index d0051a750587..f8288ea1b530 100644
--- a/Documentation/devicetree/bindings/arm/omap/omap.txt
+++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -39,16 +39,16 @@ Boards:
- OMAP3 Tobi with Overo : Commercial expansion board with daughter board
compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3"
-- OMAP4 SDP : Software Developement Board
+- OMAP4 SDP : Software Development Board
compatible = "ti,omap4-sdp", "ti,omap4430"
- OMAP4 PandaBoard : Low cost community board
compatible = "ti,omap4-panda", "ti,omap4430"
-- OMAP3 EVM : Software Developement Board for OMAP35x, AM/DM37x
+- OMAP3 EVM : Software Development Board for OMAP35x, AM/DM37x
compatible = "ti,omap3-evm", "ti,omap3"
-- AM335X EVM : Software Developement Board for AM335x
+- AM335X EVM : Software Development Board for AM335x
compatible = "ti,am335x-evm", "ti,am33xx", "ti,omap3"
- AM335X Bone : Low cost community board
diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt
new file mode 100644
index 000000000000..433afe9cb590
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/psci.txt
@@ -0,0 +1,55 @@
+* Power State Coordination Interface (PSCI)
+
+Firmware implementing the PSCI functions described in ARM document number
+ARM DEN 0022A ("Power State Coordination Interface System Software on ARM
+processors") can be used by Linux to initiate various CPU-centric power
+operations.
+
+Issue A of the specification describes functions for CPU suspend, hotplug
+and migration of secure software.
+
+Functions are invoked by trapping to the privilege level of the PSCI
+firmware (specified as part of the binding below) and passing arguments
+in a manner similar to that specified by AAPCS:
+
+ r0 => 32-bit Function ID / return value
+ {r1 - r3} => Parameters
+
+Note that the immediate field of the trapping instruction must be set
+to #0.
+
+
+Main node required properties:
+
+ - compatible : Must be "arm,psci"
+
+ - method : The method of calling the PSCI firmware. Permitted
+ values are:
+
+ "smc" : SMC #0, with the register assignments specified
+ in this binding.
+
+ "hvc" : HVC #0, with the register assignments specified
+ in this binding.
+
+Main node optional properties:
+
+ - cpu_suspend : Function ID for CPU_SUSPEND operation
+
+ - cpu_off : Function ID for CPU_OFF operation
+
+ - cpu_on : Function ID for CPU_ON operation
+
+ - migrate : Function ID for MIGRATE operation
+
+
+Example:
+
+ psci {
+ compatible = "arm,psci";
+ method = "smc";
+ cpu_suspend = <0x95c10000>;
+ cpu_off = <0x95c10001>;
+ cpu_on = <0x95c10002>;
+ migrate = <0x95c10003>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/sirf.txt b/Documentation/devicetree/bindings/arm/sirf.txt
index 1881e1c6dda5..c6ba6d3c747f 100644
--- a/Documentation/devicetree/bindings/arm/sirf.txt
+++ b/Documentation/devicetree/bindings/arm/sirf.txt
@@ -1,3 +1,9 @@
-prima2 "cb" evaluation board
+CSR SiRFprimaII and SiRFmarco device tree bindings.
+========================================
+
Required root node properties:
- - compatible = "sirf,prima2-cb", "sirf,prima2";
+ - compatible:
+ - "sirf,prima2-cb" : prima2 "cb" evaluation board
+ - "sirf,marco-cb" : marco "cb" evaluation board
+ - "sirf,prima2" : prima2 device based board
+ - "sirf,marco" : marco device based board
diff --git a/Documentation/devicetree/bindings/arm/ste-nomadik.txt b/Documentation/devicetree/bindings/arm/ste-nomadik.txt
new file mode 100644
index 000000000000..19bca04b81c9
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/ste-nomadik.txt
@@ -0,0 +1,27 @@
+ST-Ericsson Nomadik Device Tree Bindings
+
+For various board the "board" node may contain specific properties
+that pertain to this particular board, such as board-specific GPIOs.
+
+Boards with the Nomadik SoC include:
+
+S8815 "MiniKit" manufactured by Calao Systems:
+
+Required root node property:
+
+compatible="calaosystems,usb-s8815";
+
+Required node: usb-s8815
+
+Example:
+
+usb-s8815 {
+ ethernet-gpio {
+ gpios = <&gpio3 19 0x1>;
+ interrupts = <19 0x1>;
+ interrupt-parent = <&gpio3>;
+ };
+ mmcsd-gpio {
+ gpios = <&gpio3 16 0x1>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/arm/tegra.txt b/Documentation/devicetree/bindings/arm/tegra.txt
index 6e69d2e5e766..ed9c85334436 100644
--- a/Documentation/devicetree/bindings/arm/tegra.txt
+++ b/Documentation/devicetree/bindings/arm/tegra.txt
@@ -1,14 +1,34 @@
NVIDIA Tegra device tree bindings
-------------------------------------------
-Boards with the tegra20 SoC shall have the following properties:
+SoCs
+-------------------------------------------
-Required root node property:
+Each device tree must specify which Tegra SoC it uses, using one of the
+following compatible values:
-compatible = "nvidia,tegra20";
+ nvidia,tegra20
+ nvidia,tegra30
-Boards with the tegra30 SoC shall have the following properties:
+Boards
+-------------------------------------------
-Required root node property:
+Each device tree must specify which one or more of the following
+board-specific compatible values:
-compatible = "nvidia,tegra30";
+ ad,medcom-wide
+ ad,plutux
+ ad,tamonten
+ ad,tec
+ compal,paz00
+ compulab,trimslice
+ nvidia,beaver
+ nvidia,cardhu
+ nvidia,cardhu-a02
+ nvidia,cardhu-a04
+ nvidia,harmony
+ nvidia,seaboard
+ nvidia,ventana
+ nvidia,whistler
+ toradex,colibri_t20-512
+ toradex,iris
diff --git a/Documentation/devicetree/bindings/arm/vt8500.txt b/Documentation/devicetree/bindings/arm/vt8500.txt
index d657832c6819..87dc1ddf4770 100644
--- a/Documentation/devicetree/bindings/arm/vt8500.txt
+++ b/Documentation/devicetree/bindings/arm/vt8500.txt
@@ -12,3 +12,11 @@ compatible = "wm,wm8505";
Boards with the Wondermedia WM8650 SoC shall have the following properties:
Required root node property:
compatible = "wm,wm8650";
+
+Boards with the Wondermedia WM8750 SoC shall have the following properties:
+Required root node property:
+compatible = "wm,wm8750";
+
+Boards with the Wondermedia WM8850 SoC shall have the following properties:
+Required root node property:
+compatible = "wm,wm8850";
diff --git a/Documentation/devicetree/bindings/bus/ti-gpmc.txt b/Documentation/devicetree/bindings/bus/ti-gpmc.txt
new file mode 100644
index 000000000000..5ddb2e9efaaa
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/ti-gpmc.txt
@@ -0,0 +1,84 @@
+Device tree bindings for OMAP general purpose memory controllers (GPMC)
+
+The actual devices are instantiated from the child nodes of a GPMC node.
+
+Required properties:
+
+ - compatible: Should be set to one of the following:
+
+ ti,omap2420-gpmc (omap2420)
+ ti,omap2430-gpmc (omap2430)
+ ti,omap3430-gpmc (omap3430 & omap3630)
+ ti,omap4430-gpmc (omap4430 & omap4460 & omap543x)
+ ti,am3352-gpmc (am335x devices)
+
+ - reg: A resource specifier for the register space
+ (see the example below)
+ - ti,hwmods: Should be set to "ti,gpmc" until the DT transition is
+ completed.
+ - #address-cells: Must be set to 2 to allow memory address translation
+ - #size-cells: Must be set to 1 to allow CS address passing
+ - gpmc,num-cs: The maximum number of chip-select lines that controller
+ can support.
+ - gpmc,num-waitpins: The maximum number of wait pins that controller can
+ support.
+ - ranges: Must be set up to reflect the memory layout with four
+ integer values for each chip-select line in use:
+
+ <cs-number> 0 <physical address of mapping> <size>
+
+ Currently, calculated values derived from the contents
+ of the per-CS register GPMC_CONFIG7 (as set up by the
+ bootloader) are used for the physical address decoding.
+ As this will change in the future, filling correct
+ values here is a requirement.
+
+Timing properties for child nodes. All are optional and default to 0.
+
+ - gpmc,sync-clk: Minimum clock period for synchronous mode, in picoseconds
+
+ Chip-select signal timings corresponding to GPMC_CONFIG2:
+ - gpmc,cs-on: Assertion time
+ - gpmc,cs-rd-off: Read deassertion time
+ - gpmc,cs-wr-off: Write deassertion time
+
+ ADV signal timings corresponding to GPMC_CONFIG3:
+ - gpmc,adv-on: Assertion time
+ - gpmc,adv-rd-off: Read deassertion time
+ - gpmc,adv-wr-off: Write deassertion time
+
+ WE signals timings corresponding to GPMC_CONFIG4:
+ - gpmc,we-on: Assertion time
+ - gpmc,we-off: Deassertion time
+
+ OE signals timings corresponding to GPMC_CONFIG4:
+ - gpmc,oe-on: Assertion time
+ - gpmc,oe-off: Deassertion time
+
+ Access time and cycle time timings corresponding to GPMC_CONFIG5:
+ - gpmc,page-burst-access: Multiple access word delay
+ - gpmc,access: Start-cycle to first data valid delay
+ - gpmc,rd-cycle: Total read cycle time
+ - gpmc,wr-cycle: Total write cycle time
+
+The following are only applicable to OMAP3+ and AM335x:
+ - gpmc,wr-access
+ - gpmc,wr-data-mux-bus
+
+
+Example for an AM33xx board:
+
+ gpmc: gpmc@50000000 {
+ compatible = "ti,am3352-gpmc";
+ ti,hwmods = "gpmc";
+ reg = <0x50000000 0x2000>;
+ interrupts = <100>;
+
+ gpmc,num-cs = <8>;
+ gpmc,num-waitpins = <2>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */
+
+ /* child nodes go here */
+ };
diff --git a/Documentation/devicetree/bindings/clock/imx31-clock.txt b/Documentation/devicetree/bindings/clock/imx31-clock.txt
new file mode 100644
index 000000000000..19df842c694f
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/imx31-clock.txt
@@ -0,0 +1,91 @@
+* Clock bindings for Freescale i.MX31
+
+Required properties:
+- compatible: Should be "fsl,imx31-ccm"
+- reg: Address and length of the register set
+- interrupts: Should contain CCM interrupt
+- #clock-cells: Should be <1>
+
+The clock consumer should specify the desired clock by having the clock
+ID in its "clocks" phandle cell. The following is a full list of i.MX31
+clocks and IDs.
+
+ Clock ID
+ -----------------------
+ dummy 0
+ ckih 1
+ ckil 2
+ mpll 3
+ spll 4
+ upll 5
+ mcu_main 6
+ hsp 7
+ ahb 8
+ nfc 9
+ ipg 10
+ per_div 11
+ per 12
+ csi_sel 13
+ fir_sel 14
+ csi_div 15
+ usb_div_pre 16
+ usb_div_post 17
+ fir_div_pre 18
+ fir_div_post 19
+ sdhc1_gate 20
+ sdhc2_gate 21
+ gpt_gate 22
+ epit1_gate 23
+ epit2_gate 24
+ iim_gate 25
+ ata_gate 26
+ sdma_gate 27
+ cspi3_gate 28
+ rng_gate 29
+ uart1_gate 30
+ uart2_gate 31
+ ssi1_gate 32
+ i2c1_gate 33
+ i2c2_gate 34
+ i2c3_gate 35
+ hantro_gate 36
+ mstick1_gate 37
+ mstick2_gate 38
+ csi_gate 39
+ rtc_gate 40
+ wdog_gate 41
+ pwm_gate 42
+ sim_gate 43
+ ect_gate 44
+ usb_gate 45
+ kpp_gate 46
+ ipu_gate 47
+ uart3_gate 48
+ uart4_gate 49
+ uart5_gate 50
+ owire_gate 51
+ ssi2_gate 52
+ cspi1_gate 53
+ cspi2_gate 54
+ gacc_gate 55
+ emi_gate 56
+ rtic_gate 57
+ firi_gate 58
+
+Examples:
+
+clks: ccm@53f80000{
+ compatible = "fsl,imx31-ccm";
+ reg = <0x53f80000 0x4000>;
+ interrupts = <0 31 0x04 0 53 0x04>;
+ #clock-cells = <1>;
+};
+
+uart1: serial@43f90000 {
+ compatible = "fsl,imx31-uart", "fsl,imx21-uart";
+ reg = <0x43f90000 0x4000>;
+ interrupts = <45>;
+ clocks = <&clks 10>, <&clks 30>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
index 7337005ef5e1..cffc93d97f54 100644
--- a/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
+++ b/Documentation/devicetree/bindings/clock/mvebu-gated-clock.txt
@@ -89,7 +89,7 @@ ID Clock Peripheral
16 xor1 XOR DMA 1
17 crypto CESA engine
18 pex1 PCIe Cntrl 1
-19 ge1 Gigabit Ethernet 0
+19 ge1 Gigabit Ethernet 1
20 tdm Time Division Mplx
Required properties:
diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt
new file mode 100644
index 000000000000..0921fac73528
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt
@@ -0,0 +1,205 @@
+NVIDIA Tegra20 Clock And Reset Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The CAR (Clock And Reset) Controller on Tegra is the HW module responsible
+for muxing and gating Tegra's clocks, and setting their rates.
+
+Required properties :
+- compatible : Should be "nvidia,tegra20-car"
+- reg : Should contain CAR registers location and length
+- clocks : Should contain phandle and clock specifiers for two clocks:
+ the 32 KHz "32k_in", and the board-specific oscillator "osc".
+- #clock-cells : Should be 1.
+ In clock consumers, this cell represents the clock ID exposed by the CAR.
+
+ The first 96 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB
+ registers. These IDs often match those in the CAR's RST_DEVICES registers,
+ but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In
+ this case, those clocks are assigned IDs above 95 in order to highlight
+ this issue. Implementations that interpret these clock IDs as bit values
+ within the CLK_OUT_ENB or RST_DEVICES registers should be careful to
+ explicitly handle these special cases.
+
+ The balance of the clocks controlled by the CAR are assigned IDs of 96 and
+ above.
+
+ 0 cpu
+ 1 unassigned
+ 2 unassigned
+ 3 ac97
+ 4 rtc
+ 5 tmr
+ 6 uart1
+ 7 unassigned (register bit affects uart2 and vfir)
+ 8 gpio
+ 9 sdmmc2
+ 10 unassigned (register bit affects spdif_in and spdif_out)
+ 11 i2s1
+ 12 i2c1
+ 13 ndflash
+ 14 sdmmc1
+ 15 sdmmc4
+ 16 twc
+ 17 pwm
+ 18 i2s2
+ 19 epp
+ 20 unassigned (register bit affects vi and vi_sensor)
+ 21 2d
+ 22 usbd
+ 23 isp
+ 24 3d
+ 25 ide
+ 26 disp2
+ 27 disp1
+ 28 host1x
+ 29 vcp
+ 30 unassigned
+ 31 cache2
+
+ 32 mem
+ 33 ahbdma
+ 34 apbdma
+ 35 unassigned
+ 36 kbc
+ 37 stat_mon
+ 38 pmc
+ 39 fuse
+ 40 kfuse
+ 41 sbc1
+ 42 snor
+ 43 spi1
+ 44 sbc2
+ 45 xio
+ 46 sbc3
+ 47 dvc
+ 48 dsi
+ 49 unassigned (register bit affects tvo and cve)
+ 50 mipi
+ 51 hdmi
+ 52 csi
+ 53 tvdac
+ 54 i2c2
+ 55 uart3
+ 56 unassigned
+ 57 emc
+ 58 usb2
+ 59 usb3
+ 60 mpe
+ 61 vde
+ 62 bsea
+ 63 bsev
+
+ 64 speedo
+ 65 uart4
+ 66 uart5
+ 67 i2c3
+ 68 sbc4
+ 69 sdmmc3
+ 70 pcie
+ 71 owr
+ 72 afi
+ 73 csite
+ 74 unassigned
+ 75 avpucq
+ 76 la
+ 77 unassigned
+ 78 unassigned
+ 79 unassigned
+ 80 unassigned
+ 81 unassigned
+ 82 unassigned
+ 83 unassigned
+ 84 irama
+ 85 iramb
+ 86 iramc
+ 87 iramd
+ 88 cram2
+ 89 audio_2x a/k/a audio_2x_sync_clk
+ 90 clk_d
+ 91 unassigned
+ 92 sus
+ 93 cdev1
+ 94 cdev2
+ 95 unassigned
+
+ 96 uart2
+ 97 vfir
+ 98 spdif_in
+ 99 spdif_out
+ 100 vi
+ 101 vi_sensor
+ 102 tvo
+ 103 cve
+ 104 osc
+ 105 clk_32k a/k/a clk_s
+ 106 clk_m
+ 107 sclk
+ 108 cclk
+ 109 hclk
+ 110 pclk
+ 111 blink
+ 112 pll_a
+ 113 pll_a_out0
+ 114 pll_c
+ 115 pll_c_out1
+ 116 pll_d
+ 117 pll_d_out0
+ 118 pll_e
+ 119 pll_m
+ 120 pll_m_out1
+ 121 pll_p
+ 122 pll_p_out1
+ 123 pll_p_out2
+ 124 pll_p_out3
+ 125 pll_p_out4
+ 126 pll_s
+ 127 pll_u
+ 128 pll_x
+ 129 cop a/k/a avp
+ 130 audio a/k/a audio_sync_clk
+ 131 pll_ref
+ 132 twd
+
+Example SoC include file:
+
+/ {
+ tegra_car: clock {
+ compatible = "nvidia,tegra20-car";
+ reg = <0x60006000 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ usb@c5004000 {
+ clocks = <&tegra_car 58>; /* usb2 */
+ };
+};
+
+Example board file:
+
+/ {
+ clocks {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ osc: clock@0 {
+ compatible = "fixed-clock";
+ reg = <0>;
+ #clock-cells = <0>;
+ clock-frequency = <12000000>;
+ };
+
+ clk_32k: clock@1 {
+ compatible = "fixed-clock";
+ reg = <1>;
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+ };
+
+ &tegra_car {
+ clocks = <&clk_32k> <&osc>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt
new file mode 100644
index 000000000000..f3da3be5fcad
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt
@@ -0,0 +1,262 @@
+NVIDIA Tegra30 Clock And Reset Controller
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+The CAR (Clock And Reset) Controller on Tegra is the HW module responsible
+for muxing and gating Tegra's clocks, and setting their rates.
+
+Required properties :
+- compatible : Should be "nvidia,tegra30-car"
+- reg : Should contain CAR registers location and length
+- clocks : Should contain phandle and clock specifiers for two clocks:
+ the 32 KHz "32k_in", and the board-specific oscillator "osc".
+- #clock-cells : Should be 1.
+ In clock consumers, this cell represents the clock ID exposed by the CAR.
+
+ The first 130 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB
+ registers. These IDs often match those in the CAR's RST_DEVICES registers,
+ but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In
+ this case, those clocks are assigned IDs above 160 in order to highlight
+ this issue. Implementations that interpret these clock IDs as bit values
+ within the CLK_OUT_ENB or RST_DEVICES registers should be careful to
+ explicitly handle these special cases.
+
+ The balance of the clocks controlled by the CAR are assigned IDs of 160 and
+ above.
+
+ 0 cpu
+ 1 unassigned
+ 2 unassigned
+ 3 unassigned
+ 4 rtc
+ 5 timer
+ 6 uarta
+ 7 unassigned (register bit affects uartb and vfir)
+ 8 gpio
+ 9 sdmmc2
+ 10 unassigned (register bit affects spdif_in and spdif_out)
+ 11 i2s1
+ 12 i2c1
+ 13 ndflash
+ 14 sdmmc1
+ 15 sdmmc4
+ 16 unassigned
+ 17 pwm
+ 18 i2s2
+ 19 epp
+ 20 unassigned (register bit affects vi and vi_sensor)
+ 21 2d
+ 22 usbd
+ 23 isp
+ 24 3d
+ 25 unassigned
+ 26 disp2
+ 27 disp1
+ 28 host1x
+ 29 vcp
+ 30 i2s0
+ 31 cop_cache
+
+ 32 mc
+ 33 ahbdma
+ 34 apbdma
+ 35 unassigned
+ 36 kbc
+ 37 statmon
+ 38 pmc
+ 39 unassigned (register bit affects fuse and fuse_burn)
+ 40 kfuse
+ 41 sbc1
+ 42 nor
+ 43 unassigned
+ 44 sbc2
+ 45 unassigned
+ 46 sbc3
+ 47 i2c5
+ 48 dsia
+ 49 unassigned (register bit affects cve and tvo)
+ 50 mipi
+ 51 hdmi
+ 52 csi
+ 53 tvdac
+ 54 i2c2
+ 55 uartc
+ 56 unassigned
+ 57 emc
+ 58 usb2
+ 59 usb3
+ 60 mpe
+ 61 vde
+ 62 bsea
+ 63 bsev
+
+ 64 speedo
+ 65 uartd
+ 66 uarte
+ 67 i2c3
+ 68 sbc4
+ 69 sdmmc3
+ 70 pcie
+ 71 owr
+ 72 afi
+ 73 csite
+ 74 pciex
+ 75 avpucq
+ 76 la
+ 77 unassigned
+ 78 unassigned
+ 79 dtv
+ 80 ndspeed
+ 81 i2cslow
+ 82 dsib
+ 83 unassigned
+ 84 irama
+ 85 iramb
+ 86 iramc
+ 87 iramd
+ 88 cram2
+ 89 unassigned
+ 90 audio_2x a/k/a audio_2x_sync_clk
+ 91 unassigned
+ 92 csus
+ 93 cdev2
+ 94 cdev1
+ 95 unassigned
+
+ 96 cpu_g
+ 97 cpu_lp
+ 98 3d2
+ 99 mselect
+ 100 tsensor
+ 101 i2s3
+ 102 i2s4
+ 103 i2c4
+ 104 sbc5
+ 105 sbc6
+ 106 d_audio
+ 107 apbif
+ 108 dam0
+ 109 dam1
+ 110 dam2
+ 111 hda2codec_2x
+ 112 atomics
+ 113 audio0_2x
+ 114 audio1_2x
+ 115 audio2_2x
+ 116 audio3_2x
+ 117 audio4_2x
+ 118 audio5_2x
+ 119 actmon
+ 120 extern1
+ 121 extern2
+ 122 extern3
+ 123 sata_oob
+ 124 sata
+ 125 hda
+ 127 se
+ 128 hda2hdmi
+ 129 sata_cold
+
+ 160 uartb
+ 161 vfir
+ 162 spdif_in
+ 163 spdif_out
+ 164 vi
+ 165 vi_sensor
+ 166 fuse
+ 167 fuse_burn
+ 168 cve
+ 169 tvo
+
+ 170 clk_32k
+ 171 clk_m
+ 172 clk_m_div2
+ 173 clk_m_div4
+ 174 pll_ref
+ 175 pll_c
+ 176 pll_c_out1
+ 177 pll_m
+ 178 pll_m_out1
+ 179 pll_p
+ 180 pll_p_out1
+ 181 pll_p_out2
+ 182 pll_p_out3
+ 183 pll_p_out4
+ 184 pll_a
+ 185 pll_a_out0
+ 186 pll_d
+ 187 pll_d_out0
+ 188 pll_d2
+ 189 pll_d2_out0
+ 190 pll_u
+ 191 pll_x
+ 192 pll_x_out0
+ 193 pll_e
+ 194 spdif_in_sync
+ 195 i2s0_sync
+ 196 i2s1_sync
+ 197 i2s2_sync
+ 198 i2s3_sync
+ 199 i2s4_sync
+ 200 vimclk
+ 201 audio0
+ 202 audio1
+ 203 audio2
+ 204 audio3
+ 205 audio4
+ 206 audio5
+ 207 clk_out_1 (extern1)
+ 208 clk_out_2 (extern2)
+ 209 clk_out_3 (extern3)
+ 210 sclk
+ 211 blink
+ 212 cclk_g
+ 213 cclk_lp
+ 214 twd
+ 215 cml0
+ 216 cml1
+ 217 hclk
+ 218 pclk
+
+Example SoC include file:
+
+/ {
+ tegra_car: clock {
+ compatible = "nvidia,tegra30-car";
+ reg = <0x60006000 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ usb@c5004000 {
+ clocks = <&tegra_car 58>; /* usb2 */
+ };
+};
+
+Example board file:
+
+/ {
+ clocks {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ osc: clock@0 {
+ compatible = "fixed-clock";
+ reg = <0>;
+ #clock-cells = <0>;
+ clock-frequency = <12000000>;
+ };
+
+ clk_32k: clock@1 {
+ compatible = "fixed-clock";
+ reg = <1>;
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+ };
+
+ &tegra_car {
+ clocks = <&clk_32k> <&osc>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/clock/prima2-clock.txt b/Documentation/devicetree/bindings/clock/prima2-clock.txt
new file mode 100644
index 000000000000..5016979c0f78
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/prima2-clock.txt
@@ -0,0 +1,73 @@
+* Clock bindings for CSR SiRFprimaII
+
+Required properties:
+- compatible: Should be "sirf,prima2-clkc"
+- reg: Address and length of the register set
+- interrupts: Should contain clock controller interrupt
+- #clock-cells: Should be <1>
+
+The clock consumer should specify the desired clock by having the clock
+ID in its "clocks" phandle cell. The following is a full list of prima2
+clocks and IDs.
+
+ Clock ID
+ ---------------------------
+ rtc 0
+ osc 1
+ pll1 2
+ pll2 3
+ pll3 4
+ mem 5
+ sys 6
+ security 7
+ dsp 8
+ gps 9
+ mf 10
+ io 11
+ cpu 12
+ uart0 13
+ uart1 14
+ uart2 15
+ tsc 16
+ i2c0 17
+ i2c1 18
+ spi0 19
+ spi1 20
+ pwmc 21
+ efuse 22
+ pulse 23
+ dmac0 24
+ dmac1 25
+ nand 26
+ audio 27
+ usp0 28
+ usp1 29
+ usp2 30
+ vip 31
+ gfx 32
+ mm 33
+ lcd 34
+ vpp 35
+ mmc01 36
+ mmc23 37
+ mmc45 38
+ usbpll 39
+ usb0 40
+ usb1 41
+
+Examples:
+
+clks: clock-controller@88000000 {
+ compatible = "sirf,prima2-clkc";
+ reg = <0x88000000 0x1000>;
+ interrupts = <3>;
+ #clock-cells = <1>;
+};
+
+i2c0: i2c@b00e0000 {
+ cell-index = <0>;
+ compatible = "sirf,prima2-i2c";
+ reg = <0xb00e0000 0x10000>;
+ interrupts = <24>;
+ clocks = <&clks 17>;
+};
diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt
index fc9ce6f1688c..e4022776ac6e 100644
--- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt
+++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt
@@ -54,8 +54,13 @@ PROPERTIES
- compatible
Usage: required
Value type: <string>
- Definition: Must include "fsl,sec-v4.0". Also includes SEC
- ERA versions (optional) with which the device is compatible.
+ Definition: Must include "fsl,sec-v4.0"
+
+ - fsl,sec-era
+ Usage: optional
+ Value type: <u32>
+ Definition: A standard property. Define the 'ERA' of the SEC
+ device.
- #address-cells
Usage: required
@@ -107,7 +112,8 @@ PROPERTIES
EXAMPLE
crypto@300000 {
- compatible = "fsl,sec-v4.0", "fsl,sec-era-v2.0";
+ compatible = "fsl,sec-v4.0";
+ fsl,sec-era = <2>;
#address-cells = <1>;
#size-cells = <1>;
reg = <0x300000 0x10000>;
diff --git a/Documentation/devicetree/bindings/drm/exynos/g2d.txt b/Documentation/devicetree/bindings/drm/exynos/g2d.txt
new file mode 100644
index 000000000000..1eb124d35a99
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/exynos/g2d.txt
@@ -0,0 +1,22 @@
+Samsung 2D Graphic Accelerator using DRM frame work
+
+Samsung FIMG2D is a graphics 2D accelerator which supports Bit Block Transfer.
+We set the drawing-context registers for configuring rendering parameters and
+then start rendering.
+This driver is for SOCs which contain G2D IPs with version 4.1.
+
+Required properties:
+ -compatible:
+ should be "samsung,exynos-g2d-41".
+ -reg:
+ physical base address of the controller and length
+ of memory mapped region.
+ -interrupts:
+ interrupt combiner values.
+
+Example:
+ g2d {
+ compatible = "samsung,exynos-g2d-41";
+ reg = <0x10850000 0x1000>;
+ interrupts = <0 91 0>;
+ };
diff --git a/Documentation/devicetree/bindings/i2c/ina209.txt b/Documentation/devicetree/bindings/i2c/ina209.txt
new file mode 100644
index 000000000000..9dd2bee80840
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/ina209.txt
@@ -0,0 +1,18 @@
+ina209 properties
+
+Required properties:
+- compatible: Must be "ti,ina209"
+- reg: I2C address
+
+Optional properties:
+
+- shunt-resistor
+ Shunt resistor value in micro-Ohm
+
+Example:
+
+temp-sensor@4c {
+ compatible = "ti,ina209";
+ reg = <0x4c>;
+ shunt-resistor = <5000>;
+};
diff --git a/Documentation/devicetree/bindings/i2c/max6697.txt b/Documentation/devicetree/bindings/i2c/max6697.txt
new file mode 100644
index 000000000000..5f793998e4a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/max6697.txt
@@ -0,0 +1,64 @@
+max6697 properties
+
+Required properties:
+- compatible:
+ Should be one of
+ maxim,max6581
+ maxim,max6602
+ maxim,max6622
+ maxim,max6636
+ maxim,max6689
+ maxim,max6693
+ maxim,max6694
+ maxim,max6697
+ maxim,max6698
+ maxim,max6699
+- reg: I2C address
+
+Optional properties:
+
+- smbus-timeout-disable
+ Set to disable SMBus timeout. If not specified, SMBus timeout will be
+ enabled.
+- extended-range-enable
+ Only valid for MAX6581. Set to enable extended temperature range.
+ Extended temperature will be disabled if not specified.
+- beta-compensation-enable
+ Only valid for MAX6693 and MX6694. Set to enable beta compensation on
+ remote temperature channel 1.
+ Beta compensation will be disabled if not specified.
+- alert-mask
+ Alert bit mask. Alert disabled for bits set.
+ Select bit 0 for local temperature, bit 1..7 for remote temperatures.
+ If not specified, alert will be enabled for all channels.
+- over-temperature-mask
+ Over-temperature bit mask. Over-temperature reporting disabled for
+ bits set.
+ Select bit 0 for local temperature, bit 1..7 for remote temperatures.
+ If not specified, over-temperature reporting will be enabled for all
+ channels.
+- resistance-cancellation
+ Boolean for all chips other than MAX6581. Set to enable resistance
+ cancellation on remote temperature channel 1.
+ For MAX6581, resistance cancellation enabled for all channels if
+ specified as boolean, otherwise as per bit mask specified.
+ Only supported for remote temperatures (bit 1..7).
+ If not specified, resistance cancellation will be disabled for all
+ channels.
+- transistor-ideality
+ For MAX6581 only. Two values; first is bit mask, second is ideality
+ select value as per MAX6581 data sheet. Select bit 1..7 for remote
+ channels.
+ Transistor ideality will be initialized to default (1.008) if not
+ specified.
+
+Example:
+
+temp-sensor@1a {
+ compatible = "maxim,max6697";
+ reg = <0x1a>;
+ smbus-timeout-disable;
+ resistance-cancellation;
+ alert-mask = <0x72>;
+ over-temperature-mask = <0x7f>;
+};
diff --git a/Documentation/devicetree/bindings/input/imx-keypad.txt b/Documentation/devicetree/bindings/input/imx-keypad.txt
new file mode 100644
index 000000000000..2ebaf7d26843
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/imx-keypad.txt
@@ -0,0 +1,53 @@
+* Freescale i.MX Keypad Port(KPP) device tree bindings
+
+The KPP is designed to interface with a keypad matrix with 2-point contact
+or 3-point contact keys. The KPP is designed to simplify the software task
+of scanning a keypad matrix. The KPP is capable of detecting, debouncing,
+and decoding one or multiple keys pressed simultaneously on a keypad.
+
+Required SoC Specific Properties:
+- compatible: Should be "fsl,<soc>-kpp".
+
+- reg: Physical base address of the KPP and length of memory mapped
+ region.
+
+- interrupts: The KPP interrupt number to the CPU(s).
+
+- clocks: The clock provided by the SoC to the KPP. Some SoCs use dummy
+clock(The clock for the KPP is provided by the SoCs automatically).
+
+Required Board Specific Properties:
+- pinctrl-names: The definition can be found at
+pinctrl/pinctrl-bindings.txt.
+
+- pinctrl-0: The definition can be found at
+pinctrl/pinctrl-bindings.txt.
+
+- linux,keymap: The definition can be found at
+bindings/input/matrix-keymap.txt.
+
+Example:
+kpp: kpp@73f94000 {
+ compatible = "fsl,imx51-kpp", "fsl,imx21-kpp";
+ reg = <0x73f94000 0x4000>;
+ interrupts = <60>;
+ clocks = <&clks 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_kpp_1>;
+ linux,keymap = <0x00000067 /* KEY_UP */
+ 0x0001006c /* KEY_DOWN */
+ 0x00020072 /* KEY_VOLUMEDOWN */
+ 0x00030066 /* KEY_HOME */
+ 0x0100006a /* KEY_RIGHT */
+ 0x01010069 /* KEY_LEFT */
+ 0x0102001c /* KEY_ENTER */
+ 0x01030073 /* KEY_VOLUMEUP */
+ 0x02000040 /* KEY_F6 */
+ 0x02010042 /* KEY_F8 */
+ 0x02020043 /* KEY_F9 */
+ 0x02030044 /* KEY_F10 */
+ 0x0300003b /* KEY_F1 */
+ 0x0301003c /* KEY_F2 */
+ 0x0302003d /* KEY_F3 */
+ 0x03030074>; /* KEY_POWER */
+};
diff --git a/Documentation/devicetree/bindings/input/lpc32xx-key.txt b/Documentation/devicetree/bindings/input/lpc32xx-key.txt
index 31afd5014c48..bcf62f856358 100644
--- a/Documentation/devicetree/bindings/input/lpc32xx-key.txt
+++ b/Documentation/devicetree/bindings/input/lpc32xx-key.txt
@@ -1,19 +1,22 @@
NXP LPC32xx Key Scan Interface
+This binding is based on the matrix-keymap binding with the following
+changes:
+
Required Properties:
- compatible: Should be "nxp,lpc3220-key"
- reg: Physical base address of the controller and length of memory mapped
region.
- interrupts: The interrupt number to the cpu.
-- keypad,num-rows: Number of rows and columns, e.g. 1: 1x1, 6: 6x6
-- keypad,num-columns: Must be equal to keypad,num-rows since LPC32xx only
- supports square matrices
- nxp,debounce-delay-ms: Debounce delay in ms
- nxp,scan-delay-ms: Repeated scan period in ms
- linux,keymap: the key-code to be reported when the key is pressed
and released, see also
Documentation/devicetree/bindings/input/matrix-keymap.txt
+Note: keypad,num-rows and keypad,num-columns are required, and must be equal
+since LPC32xx only supports square matrices
+
Example:
key@40050000 {
diff --git a/Documentation/devicetree/bindings/input/matrix-keymap.txt b/Documentation/devicetree/bindings/input/matrix-keymap.txt
index 3cd8b98ccd2d..c54919fad17e 100644
--- a/Documentation/devicetree/bindings/input/matrix-keymap.txt
+++ b/Documentation/devicetree/bindings/input/matrix-keymap.txt
@@ -9,6 +9,12 @@ Required properties:
row << 24 | column << 16 | key-code
Optional properties:
+Properties for the number of rows and columns are optional because some
+drivers will use fixed values for these.
+- keypad,num-rows: Number of row lines connected to the keypad controller.
+- keypad,num-columns: Number of column lines connected to the keypad
+ controller.
+
Some users of this binding might choose to specify secondary keymaps for
cases where there is a modifier key such as a Fn key. Proposed names
for said properties are "linux,fn-keymap" or with another descriptive
@@ -17,3 +23,5 @@ word for the modifier other from "Fn".
Example:
linux,keymap = < 0x00030012
0x0102003a >;
+ keypad,num-rows = <2>;
+ keypad,num-columns = <8>;
diff --git a/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt b/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
index 72683be6de35..2995fae7ee47 100644
--- a/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
+++ b/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
@@ -1,7 +1,18 @@
* Tegra keyboard controller
+The key controller has maximum 24 pins to make matrix keypad. Any pin
+can be configured as row or column. The maximum column pin can be 8
+and maximum row pins can be 16 for Tegra20/Tegra30.
Required properties:
- compatible: "nvidia,tegra20-kbc"
+- reg: Register base address of KBC.
+- interrupts: Interrupt number for the KBC.
+- nvidia,kbc-row-pins: The KBC pins which are configured as row. This is an
+ array of pin numbers which is used as rows.
+- nvidia,kbc-col-pins: The KBC pins which are configured as column. This is an
+ array of pin numbers which is used as column.
+- linux,keymap: The keymap for keys as described in the binding document
+ devicetree/bindings/input/matrix-keymap.txt.
Optional properties, in addition to those specified by the shared
matrix-keyboard bindings:
@@ -19,5 +30,16 @@ Example:
keyboard: keyboard {
compatible = "nvidia,tegra20-kbc";
reg = <0x7000e200 0x100>;
+ interrupts = <0 85 0x04>;
nvidia,ghost-filter;
+ nvidia,debounce-delay-ms = <640>;
+ nvidia,kbc-row-pins = <0 1 2>; /* pin 0, 1, 2 as rows */
+ nvidia,kbc-col-pins = <11 12 13>; /* pin 11, 12, 13 as columns */
+ linux,keymap = <0x00000074
+ 0x00010067
+ 0x00020066
+ 0x01010068
+ 0x02000069
+ 0x02010070
+ 0x02020071>;
};
diff --git a/Documentation/devicetree/bindings/input/omap-keypad.txt b/Documentation/devicetree/bindings/input/omap-keypad.txt
index f2fa5e10493d..34ed1c60ff95 100644
--- a/Documentation/devicetree/bindings/input/omap-keypad.txt
+++ b/Documentation/devicetree/bindings/input/omap-keypad.txt
@@ -6,19 +6,16 @@ A key can be placed at each intersection of a unique row and a unique column.
The keypad controller can sense a key-press and key-release and report the
event using a interrupt to the cpu.
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
+
Required SoC Specific Properties:
- compatible: should be one of the following
- "ti,omap4-keypad": For controllers compatible with omap4 keypad
controller.
-Required Board Specific Properties, in addition to those specified by
-the shared matrix-keyboard bindings:
-- keypad,num-rows: Number of row lines connected to the keypad
- controller.
-
-- keypad,num-columns: Number of column lines connected to the
- keypad controller.
-
Optional Properties specific to linux:
- linux,keypad-no-autorepeat: do no enable autorepeat feature.
diff --git a/Documentation/devicetree/bindings/input/tca8418_keypad.txt b/Documentation/devicetree/bindings/input/tca8418_keypad.txt
index 2a1538f0053f..255185009167 100644
--- a/Documentation/devicetree/bindings/input/tca8418_keypad.txt
+++ b/Documentation/devicetree/bindings/input/tca8418_keypad.txt
@@ -1,8 +1,10 @@
+This binding is based on the matrix-keymap binding with the following
+changes:
+
+keypad,num-rows and keypad,num-columns are required.
Required properties:
- compatible: "ti,tca8418"
- reg: the I2C address
- interrupts: IRQ line number, should trigger on falling edge
-- keypad,num-rows: The number of rows
-- keypad,num-columns: The number of columns
- linux,keymap: Keys definitions, see keypad-matrix.
diff --git a/Documentation/devicetree/bindings/gpio/leds-ns2.txt b/Documentation/devicetree/bindings/leds/leds-ns2.txt
index aef3aca34d2d..aef3aca34d2d 100644
--- a/Documentation/devicetree/bindings/gpio/leds-ns2.txt
+++ b/Documentation/devicetree/bindings/leds/leds-ns2.txt
diff --git a/Documentation/devicetree/bindings/media/gpio-ir-receiver.txt b/Documentation/devicetree/bindings/media/gpio-ir-receiver.txt
new file mode 100644
index 000000000000..56e726ef4bf2
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/gpio-ir-receiver.txt
@@ -0,0 +1,16 @@
+Device-Tree bindings for GPIO IR receiver
+
+Required properties:
+ - compatible: should be "gpio-ir-receiver".
+ - gpios: specifies GPIO used for IR signal reception.
+
+Optional properties:
+ - linux,rc-map-name: Linux specific remote control map name.
+
+Example node:
+
+ ir: ir-receiver {
+ compatible = "gpio-ir-receiver";
+ gpios = <&gpio0 19 1>;
+ linux,rc-map-name = "rc-rc6-mce";
+ };
diff --git a/Documentation/devicetree/bindings/mfd/max8925.txt b/Documentation/devicetree/bindings/mfd/max8925.txt
new file mode 100644
index 000000000000..4f0dc6638e5e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/max8925.txt
@@ -0,0 +1,64 @@
+* Maxim max8925 Power Management IC
+
+Required parent device properties:
+- compatible : "maxim,max8925"
+- reg : the I2C slave address for the max8925 chip
+- interrupts : IRQ line for the max8925 chip
+- interrupt-controller: describes the max8925 as an interrupt
+ controller (has its own domain)
+- #interrupt-cells : should be 1.
+ - The cell is the max8925 local IRQ number
+
+Optional parent device properties:
+- maxim,tsc-irq: there are 2 IRQ lines for max8925, one is indicated in
+ interrupts property, the other is indicated here.
+
+max8925 consists of a large and varied group of sub-devices:
+
+Device Supply Names Description
+------ ------------ -----------
+max8925-onkey : : On key
+max8925-rtc : : RTC
+max8925-regulator : : Regulators
+max8925-backlight : : Backlight
+max8925-touch : : Touchscreen
+max8925-power : : Charger
+
+Example:
+
+ pmic: max8925@3c {
+ compatible = "maxim,max8925";
+ reg = <0x3c>;
+ interrupts = <1>;
+ interrupt-parent = <&intcmux4>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ maxim,tsc-irq = <0>;
+
+ regulators {
+ SDV1 {
+ regulator-min-microvolt = <637500>;
+ regulator-max-microvolt = <1425000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ LDO1 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ };
+ backlight {
+ maxim,max8925-dual-string = <0>;
+ };
+ charger {
+ batt-detect = <0>;
+ topoff-threshold = <1>;
+ fast-charge = <7>;
+ no-temp-support = <0>;
+ no-insert-detect = <0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/tps6507x.txt b/Documentation/devicetree/bindings/mfd/tps6507x.txt
new file mode 100755
index 000000000000..8fffa3c5ed40
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/tps6507x.txt
@@ -0,0 +1,91 @@
+TPS6507x Power Management Integrated Circuit
+
+Required properties:
+- compatible: "ti,tps6507x"
+- reg: I2C slave address
+- regulators: This is the list of child nodes that specify the regulator
+ initialization data for defined regulators. Not all regulators for the
+ given device need to be present. The definition for each of these nodes
+ is defined using the standard binding for regulators found at
+ Documentation/devicetree/bindings/regulator/regulator.txt.
+ The regulator is matched with the regulator-compatible.
+
+ The valid regulator-compatible values are:
+ tps6507x: vdcdc1, vdcdc2, vdcdc3, vldo1, vldo2
+- xxx-supply: Input voltage supply regulator.
+ These entries are required if regulators are enabled for a device.
+ Missing of these properties can cause the regulator registration
+ fails.
+ If some of input supply is powered through battery or always-on
+ supply then also it is require to have these parameters with proper
+ node handle of always on power supply.
+ tps6507x:
+ vindcdc1_2-supply: VDCDC1 and VDCDC2 input.
+ vindcdc3-supply : VDCDC3 input.
+ vldo1_2-supply : VLDO1 and VLDO2 input.
+
+Regulator Optional properties:
+- defdcdc_default: It's property of DCDC2 and DCDC3 regulators.
+ 0: If defdcdc pin of DCDC2/DCDC3 is pulled to GND.
+ 1: If defdcdc pin of DCDC2/DCDC3 is driven HIGH.
+ If this property is not defined, it defaults to 0 (not enabled).
+
+Example:
+
+ pmu: tps6507x@48 {
+ compatible = "ti,tps6507x";
+ reg = <0x48>;
+
+ vindcdc1_2-supply = <&vbat>;
+ vindcdc3-supply = <...>;
+ vinldo1_2-supply = <...>;
+
+ regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vdcdc1_reg: regulator@0 {
+ regulator-compatible = "VDCDC1";
+ reg = <0>;
+ regulator-min-microvolt = <3150000>;
+ regulator-max-microvolt = <3450000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ vdcdc2_reg: regulator@1 {
+ regulator-compatible = "VDCDC2";
+ reg = <1>;
+ regulator-min-microvolt = <1710000>;
+ regulator-max-microvolt = <3450000>;
+ regulator-always-on;
+ regulator-boot-on;
+ defdcdc_default = <1>;
+ };
+ vdcdc3_reg: regulator@2 {
+ regulator-compatible = "VDCDC3";
+ reg = <2>;
+ regulator-min-microvolt = <950000>
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ defdcdc_default = <1>;
+ };
+ ldo1_reg: regulator@3 {
+ regulator-compatible = "LDO1";
+ reg = <3>;
+ regulator-min-microvolt = <1710000>;
+ regulator-max-microvolt = <1890000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ ldo2_reg: regulator@4 {
+ regulator-compatible = "LDO2";
+ reg = <4>;
+ regulator-min-microvolt = <1140000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+
+ };
diff --git a/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt b/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt
index cb4291e3b1d1..a5bdff400002 100644
--- a/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt
+++ b/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt
@@ -1,7 +1,7 @@
* DMA Engine.
The Octeon DMA Engine transfers between the Boot Bus and main memory.
-The DMA Engine will be refered to by phandle by any device that is
+The DMA Engine will be referred to by phandle by any device that is
connected to it.
Properties:
diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
index 792768953330..6d1c0988cfc7 100644
--- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
@@ -4,18 +4,18 @@
The Synopsis designware mobile storage host controller is used to interface
a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
differences between the core Synopsis dw mshc controller properties described
-by synposis-dw-mshc.txt and the properties used by the Samsung Exynos specific
+by synopsis-dw-mshc.txt and the properties used by the Samsung Exynos specific
extensions to the Synopsis Designware Mobile Storage Host Controller.
Required Properties:
* compatible: should be
- "samsung,exynos4210-dw-mshc": for controllers with Samsung Exynos4210
- specific extentions.
+ specific extensions.
- "samsung,exynos4412-dw-mshc": for controllers with Samsung Exynos4412
- specific extentions.
+ specific extensions.
- "samsung,exynos5250-dw-mshc": for controllers with Samsung Exynos5250
- specific extentions.
+ specific extensions.
* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
diff --git a/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt
index 97e9e315400d..3b3a1ee055ff 100644
--- a/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt
+++ b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt
@@ -55,5 +55,5 @@ Example:
};
Note: This example shows both SoC specific and board specific properties
- in a single device node. The properties can be actually be seperated
+ in a single device node. The properties can be actually be separated
into SoC specific node and board specific node.
diff --git a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt
index e3ea32e7de3e..2240ac09f6ba 100644
--- a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt
@@ -1,7 +1,7 @@
* FSMC NAND
Required properties:
-- compatible : "st,spear600-fsmc-nand"
+- compatible : "st,spear600-fsmc-nand", "stericsson,fsmc-nand"
- reg : Address range of the mtd chip
- reg-names: Should contain the reg names "fsmc_regs", "nand_data", "nand_addr" and "nand_cmd"
diff --git a/Documentation/devicetree/bindings/mtd/gpmc-nand.txt b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
new file mode 100644
index 000000000000..e7f8d7ed47eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/gpmc-nand.txt
@@ -0,0 +1,80 @@
+Device tree bindings for GPMC connected NANDs
+
+GPMC connected NAND (found on OMAP boards) are represented as child nodes of
+the GPMC controller with a name of "nand".
+
+All timing relevant properties as well as generic gpmc child properties are
+explained in a separate documents - please refer to
+Documentation/devicetree/bindings/bus/ti-gpmc.txt
+
+For NAND specific properties such as ECC modes or bus width, please refer to
+Documentation/devicetree/bindings/mtd/nand.txt
+
+
+Required properties:
+
+ - reg: The CS line the peripheral is connected to
+
+Optional properties:
+
+ - nand-bus-width: Set this numeric value to 16 if the hardware
+ is wired that way. If not specified, a bus
+ width of 8 is assumed.
+
+ - ti,nand-ecc-opt: A string setting the ECC layout to use. One of:
+
+ "sw" Software method (default)
+ "hw" Hardware method
+ "hw-romcode" gpmc hamming mode method & romcode layout
+ "bch4" 4-bit BCH ecc code
+ "bch8" 8-bit BCH ecc code
+
+ - elm_id: Specifies elm device node. This is required to support BCH
+ error correction using ELM module.
+
+For inline partiton table parsing (optional):
+
+ - #address-cells: should be set to 1
+ - #size-cells: should be set to 1
+
+Example for an AM33xx board:
+
+ gpmc: gpmc@50000000 {
+ compatible = "ti,am3352-gpmc";
+ ti,hwmods = "gpmc";
+ reg = <0x50000000 0x1000000>;
+ interrupts = <100>;
+ gpmc,num-cs = <8>;
+ gpmc,num-waitpins = <2>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <0 0 0x08000000 0x2000>; /* CS0: NAND */
+ elm_id = <&elm>;
+
+ nand@0,0 {
+ reg = <0 0 0>; /* CS0, offset 0 */
+ nand-bus-width = <16>;
+ ti,nand-ecc-opt = "bch8";
+
+ gpmc,sync-clk = <0>;
+ gpmc,cs-on = <0>;
+ gpmc,cs-rd-off = <44>;
+ gpmc,cs-wr-off = <44>;
+ gpmc,adv-on = <6>;
+ gpmc,adv-rd-off = <34>;
+ gpmc,adv-wr-off = <44>;
+ gpmc,we-off = <40>;
+ gpmc,oe-off = <54>;
+ gpmc,access = <64>;
+ gpmc,rd-cycle = <82>;
+ gpmc,wr-cycle = <82>;
+ gpmc,wr-access = <40>;
+ gpmc,wr-data-mux-bus = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* partitions go here */
+ };
+ };
+
diff --git a/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
new file mode 100644
index 000000000000..deec9da224a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/gpmc-onenand.txt
@@ -0,0 +1,43 @@
+Device tree bindings for GPMC connected OneNANDs
+
+GPMC connected OneNAND (found on OMAP boards) are represented as child nodes of
+the GPMC controller with a name of "onenand".
+
+All timing relevant properties as well as generic gpmc child properties are
+explained in a separate documents - please refer to
+Documentation/devicetree/bindings/bus/ti-gpmc.txt
+
+Required properties:
+
+ - reg: The CS line the peripheral is connected to
+
+Optional properties:
+
+ - dma-channel: DMA Channel index
+
+For inline partiton table parsing (optional):
+
+ - #address-cells: should be set to 1
+ - #size-cells: should be set to 1
+
+Example for an OMAP3430 board:
+
+ gpmc: gpmc@6e000000 {
+ compatible = "ti,omap3430-gpmc";
+ ti,hwmods = "gpmc";
+ reg = <0x6e000000 0x1000000>;
+ interrupts = <20>;
+ gpmc,num-cs = <8>;
+ gpmc,num-waitpins = <4>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ onenand@0 {
+ reg = <0 0 0>; /* CS0, offset 0 */
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* partitions go here */
+ };
+ };
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index 6ddd0286a9b7..ecfdf756d10f 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -24,6 +24,8 @@ Required properties:
Optional properties:
- ti,hwmods : Must be "cpgmac0"
- no_bd_ram : Must be 0 or 1
+- dual_emac : Specifies Switch to act as Dual EMAC
+- dual_emac_res_vlan : Specifies VID to be used to segregate the ports
Note: "ti,hwmods" field is used to fetch the base address and irq
resources from TI, omap hwmod data base during device registration.
diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
new file mode 100644
index 000000000000..dff0e5f995e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
@@ -0,0 +1,60 @@
+* Allwinner A1X Pin Controller
+
+The pins controlled by sunXi pin controller are organized in banks,
+each bank has 32 pins. Each pin has 7 multiplexing functions, with
+the first two functions being GPIO in and out. The configuration on
+the pins includes drive strength and pull-up.
+
+Required properties:
+- compatible: "allwinner,<soc>-pinctrl". Supported SoCs for now are:
+ sun5i-a13.
+- reg: Should contain the register physical address and length for the
+ pin controller.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices.
+
+A pinctrl node should contain at least one subnodes representing the
+pinctrl groups available on the machine. Each subnode will list the
+pins it needs, and how they should be configured, with regard to muxer
+configuration, drive strength and pullups. If one of these options is
+not set, its actual value will be unspecified.
+
+Required subnode-properties:
+
+- allwinner,pins: List of strings containing the pin name.
+- allwinner,function: Function to mux the pins listed above to.
+
+Optional subnode-properties:
+- allwinner,drive: Integer. Represents the current sent to the pin
+ 0: 10 mA
+ 1: 20 mA
+ 2: 30 mA
+ 3: 40 mA
+- allwinner,pull: Integer.
+ 0: No resistor
+ 1: Pull-up resistor
+ 2: Pull-down resistor
+
+Examples:
+
+pinctrl@01c20800 {
+ compatible = "allwinner,sun5i-a13-pinctrl";
+ reg = <0x01c20800 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ uart1_pins_a: uart1@0 {
+ allwinner,pins = "PE10", "PE11";
+ allwinner,function = "uart1";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ uart1_pins_b: uart1@1 {
+ allwinner,pins = "PG3", "PG4";
+ allwinner,function = "uart1";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.txt
new file mode 100644
index 000000000000..e204d009f16c
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra114-pinmux.txt
@@ -0,0 +1,120 @@
+NVIDIA Tegra114 pinmux controller
+
+The Tegra114 pinctrl binding is very similar to the Tegra20 and Tegra30
+pinctrl binding, as described in nvidia,tegra20-pinmux.txt and
+nvidia,tegra30-pinmux.txt. In fact, this document assumes that binding as
+a baseline, and only documents the differences between the two bindings.
+
+Required properties:
+- compatible: "nvidia,tegra114-pinmux"
+- reg: Should contain the register physical address and length for each of
+ the pad control and mux registers. The first bank of address must be the
+ driver strength pad control register address and second bank address must
+ be pinmux register address.
+
+Tegra114 adds the following optional properties for pin configuration subnodes:
+- nvidia,enable-input: Integer. Enable the pin's input path. 0: no, 1: yes.
+- nvidia,open-drain: Integer. Enable open drain mode. 0: no, 1: yes.
+- nvidia,lock: Integer. Lock the pin configuration against further changes
+ until reset. 0: no, 1: yes.
+- nvidia,io-reset: Integer. Reset the IO path. 0: no, 1: yes.
+- nvidia,rcv-sel: Integer. Select VIL/VIH receivers. 0: normal, 1: high.
+- nvidia,drive-type: Integer. Valid range 0...3.
+
+As with Tegra20 and Terga30, see the Tegra TRM for complete details regarding
+which groups support which functionality.
+
+Valid values for pin and group names are:
+
+ per-pin mux groups:
+
+ These all support nvidia,function, nvidia,tristate, nvidia,pull,
+ nvidia,enable-input, nvidia,lock. Some support nvidia,open-drain,
+ nvidia,io-reset and nvidia,rcv-sel.
+
+ ulpi_data0_po1, ulpi_data1_po2, ulpi_data2_po3, ulpi_data3_po4,
+ ulpi_data4_po5, ulpi_data5_po6, ulpi_data6_po7, ulpi_data7_po0,
+ ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3, dap3_fs_pp0,
+ dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3, pv0, pv1, sdmmc1_clk_pz0,
+ sdmmc1_cmd_pz1, sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6,
+ sdmmc1_dat0_py7, clk2_out_pw5, clk2_req_pcc5, hdmi_int_pn7, ddc_scl_pv4,
+ ddc_sda_pv5, uart2_rxd_pc3, uart2_txd_pc2, uart2_rts_n_pj6,
+ uart2_cts_n_pj5, uart3_txd_pw6, uart3_rxd_pw7, uart3_cts_n_pa1,
+ uart3_rts_n_pc0, pu0, pu1, pu2, pu3, pu4, pu5, pu6, gen1_i2c_sda_pc5,
+ gen1_i2c_scl_pc4, dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6, dap4_sclk_pp7,
+ clk3_out_pee0, clk3_req_pee1, gmi_wp_n_pc7, gmi_iordy_pi5, gmi_wait_pi7,
+ gmi_adv_n_pk0, gmi_clk_pk1, gmi_cs0_n_pj0, gmi_cs1_n_pj2, gmi_cs2_n_pk3,
+ gmi_cs3_n_pk4, gmi_cs4_n_pk2, gmi_cs6_n_pi3, gmi_cs7_n_pi6, gmi_ad0_pg0,
+ gmi_ad1_pg1, gmi_ad2_pg2, gmi_ad3_pg3, gmi_ad4_pg4, gmi_ad5_pg5,
+ gmi_ad6_pg6, gmi_ad7_pg7, gmi_ad8_ph0, gmi_ad9_ph1, gmi_ad10_ph2,
+ gmi_ad11_ph3, gmi_ad12_ph4, gmi_ad13_ph5, gmi_ad14_ph6, gmi_ad15_ph7,
+ gmi_a16_pj7, gmi_a17_pb0, gmi_a18_pb1, gmi_a19_pk7, gmi_wr_n_pi0,
+ gmi_oe_n_pi1, gmi_dqs_p_pj3, gmi_rst_n_pi4, gen2_i2c_scl_pt5,
+ gen2_i2c_sda_pt6, sdmmc4_clk_pcc4, sdmmc4_cmd_pt7, sdmmc4_dat0_paa0,
+ sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, sdmmc4_dat3_paa3, sdmmc4_dat4_paa4,
+ sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, sdmmc4_dat7_paa7, cam_mclk_pcc0,
+ pcc1, pbb0, cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6,
+ pbb7, pcc2, pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, kb_row0_pr0, kb_row1_pr1,
+ kb_row2_pr2, kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6,
+ kb_row7_pr7, kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_col0_pq0,
+ kb_col1_pq1, kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5,
+ kb_col6_pq6, kb_col7_pq7, clk_32k_out_pa0, sys_clk_req_pz5, core_pwr_req,
+ cpu_pwr_req, pwr_int_n, owr, dap1_fs_pn0, dap1_din_pn1, dap1_dout_pn2,
+ dap1_sclk_pn3, clk1_req_pee2, clk1_out_pw4, spdif_in_pk6, spdif_out_pk5,
+ dap2_fs_pa2, dap2_din_pa4, dap2_dout_pa5, dap2_sclk_pa3, dvfs_pwm_px0,
+ gpio_x1_aud_px1, gpio_x3_aud_px3, dvfs_clk_px2, gpio_x4_aud_px4,
+ gpio_x5_aud_px5, gpio_x6_aud_px6, gpio_x7_aud_px7, sdmmc3_clk_pa6,
+ sdmmc3_cmd_pa7, sdmmc3_dat0_pb7, sdmmc3_dat1_pb6, sdmmc3_dat2_pb5,
+ sdmmc3_dat3_pb4, hdmi_cec_pee3, sdmmc1_wp_n_pv3, sdmmc3_cd_n_pv2,
+ gpio_w2_aud_pw2, gpio_w3_aud_pw3, usb_vbus_en0_pn4, usb_vbus_en1_pn5,
+ sdmmc3_clk_lb_in_pee5, sdmmc3_clk_lb_out_pee4, reset_out_n.
+
+ drive groups:
+
+ These all support nvidia,pull-down-strength, nvidia,pull-up-strength,
+ nvidia,slew-rate-rising, nvidia,slew-rate-falling. Most but not all
+ support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode
+ and nvidia,drive-type.
+
+ ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, dap1, dap2, dap3, dap4,
+ dbg, sdio3, spi, uaa, uab, uart2, uart3, sdio1, ddc, gma, gme, gmf, gmg,
+ gmh, owr, uda.
+
+Example:
+
+ pinmux: pinmux {
+ compatible = "nvidia,tegra114-pinmux";
+ reg = <0x70000868 0x148 /* Pad control registers */
+ 0x70003000 0x40c>; /* PinMux registers */
+ };
+
+Example board file extract:
+
+ pinctrl {
+ sdmmc4_default: pinmux {
+ sdmmc4_clk_pcc4 {
+ nvidia,pins = "sdmmc4_clk_pcc4",
+ nvidia,function = "sdmmc4";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ sdmmc4_dat0_paa0 {
+ nvidia,pins = "sdmmc4_dat0_paa0",
+ "sdmmc4_dat1_paa1",
+ "sdmmc4_dat2_paa2",
+ "sdmmc4_dat3_paa3",
+ "sdmmc4_dat4_paa4",
+ "sdmmc4_dat5_paa5",
+ "sdmmc4_dat6_paa6",
+ "sdmmc4_dat7_paa7";
+ nvidia,function = "sdmmc4";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ };
+ };
+
+ sdhci@78000400 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc4_default>;
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
index e97a27856b21..4598a47aa0cd 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
@@ -7,9 +7,9 @@ on-chip controllers onto these pads.
Required Properties:
- compatible: should be one of the following.
- - "samsung,pinctrl-exynos4210": for Exynos4210 compatible pin-controller.
- - "samsung,pinctrl-exynos4x12": for Exynos4x12 compatible pin-controller.
- - "samsung,pinctrl-exynos5250": for Exynos5250 compatible pin-controller.
+ - "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller.
+ - "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
+ - "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
- reg: Base address of the pin controller hardware module and length of
the address space it occupies.
@@ -142,7 +142,7 @@ the following format 'pinctrl{n}' where n is a unique number for the alias.
Example: A pin-controller node with pin banks:
pinctrl_0: pinctrl@11400000 {
- compatible = "samsung,pinctrl-exynos4210";
+ compatible = "samsung,exynos4210-pinctrl";
reg = <0x11400000 0x1000>;
interrupts = <0 47 0>;
@@ -185,7 +185,7 @@ Example: A pin-controller node with pin banks:
Example 1: A pin-controller node with pin groups.
pinctrl_0: pinctrl@11400000 {
- compatible = "samsung,pinctrl-exynos4210";
+ compatible = "samsung,exynos4210-pinctrl";
reg = <0x11400000 0x1000>;
interrupts = <0 47 0>;
@@ -230,7 +230,7 @@ Example 1: A pin-controller node with pin groups.
Example 2: A pin-controller node with external wakeup interrupt controller node.
pinctrl_1: pinctrl@11000000 {
- compatible = "samsung,pinctrl-exynos4210";
+ compatible = "samsung,exynos4210-pinctrl";
reg = <0x11000000 0x1000>;
interrupts = <0 46 0>
diff --git a/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt b/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt
new file mode 100644
index 000000000000..9a2f3f420526
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt
@@ -0,0 +1,140 @@
+ST Ericsson Nomadik pinmux controller
+
+Required properties:
+- compatible: "stericsson,nmk-pinctrl", "stericsson,nmk-pinctrl-db8540",
+ "stericsson,nmk-pinctrl-stn8815"
+- reg: Should contain the register physical address and length of the PRCMU.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+ST Ericsson's pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as input, output, pull up, pull down...
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Required subnode-properties:
+- ste,pins : An array of strings. Each string contains the name of a pin or
+ group.
+
+Optional subnode-properties:
+- ste,function: A string containing the name of the function to mux to the
+ pin or group.
+
+- ste,config: Handle of pin configuration node (e.g. ste,config = <&slpm_in_wkup_pdis>)
+
+- ste,input : <0/1/2>
+ 0: input with no pull
+ 1: input with pull up,
+ 2: input with pull down,
+
+- ste,output: <0/1/2>
+ 0: output low,
+ 1: output high,
+ 2: output (value is not specified).
+
+- ste,sleep: <0/1>
+ 0: sleep mode disable,
+ 1: sleep mode enable.
+
+- ste,sleep-input: <0/1/2/3>
+ 0: sleep input with no pull,
+ 1: sleep input with pull up,
+ 2: sleep input with pull down.
+ 3: sleep input and keep last input configuration (no pull, pull up or pull down).
+
+- ste,sleep-output: <0/1/2>
+ 0: sleep output low,
+ 1: sleep output high,
+ 2: sleep output (value is not specified).
+
+- ste,sleep-gpio: <0/1>
+ 0: disable sleep gpio mode,
+ 1: enable sleep gpio mode.
+
+- ste,sleep-wakeup: <0/1>
+ 0: wake-up detection enabled,
+ 1: wake-up detection disabled.
+
+- ste,sleep-pull-disable: <0/1>
+ 0: GPIO pull-up or pull-down resistor is enabled, when pin is an input,
+ 1: GPIO pull-up and pull-down resistor are disabled.
+
+Example board file extract:
+
+ pinctrl@80157000 {
+ compatible = "stericsson,nmk-pinctrl";
+ reg = <0x80157000 0x2000>;
+
+ pinctrl-names = "default";
+
+ slpm_in_wkup_pdis: slpm_in_wkup_pdis {
+ ste,sleep = <1>;
+ ste,sleep-input = <3>;
+ ste,sleep-wakeup = <1>;
+ ste,sleep-pull-disable = <0>;
+ };
+
+ slpm_out_hi_wkup_pdis: slpm_out_hi_wkup_pdis {
+ ste,sleep = <1>;
+ ste,sleep-output = <1>;
+ ste,sleep-wakeup = <1>;
+ ste,sleep-pull-disable = <0>;
+ };
+
+ slpm_out_wkup_pdis: slpm_out_wkup_pdis {
+ ste,sleep = <1>;
+ ste,sleep-output = <2>;
+ ste,sleep-wakeup = <1>;
+ ste,sleep-pull-disable = <0>;
+ };
+
+ uart0 {
+ uart0_default_mux: uart0_mux {
+ u0_default_mux {
+ ste,function = "u0";
+ ste,pins = "u0_a_1";
+ };
+ };
+ uart0_default_mode: uart0_default {
+ uart0_default_cfg1 {
+ ste,pins = "GPIO0", "GPIO2";
+ ste,input = <1>;
+ };
+
+ uart0_default_cfg2 {
+ ste,pins = "GPIO1", "GPIO3";
+ ste,output = <1>;
+ };
+ };
+ uart0_sleep_mode: uart0_sleep {
+ uart0_sleep_cfg1 {
+ ste,pins = "GPIO0", "GPIO2";
+ ste,config = <&slpm_in_wkup_pdis>;
+ };
+ uart0_sleep_cfg2 {
+ ste,pins = "GPIO1";
+ ste,config = <&slpm_out_hi_wkup_pdis>;
+ };
+ uart0_sleep_cfg3 {
+ ste,pins = "GPIO3";
+ ste,config = <&slpm_out_wkup_pdis>;
+ };
+ };
+ };
+ };
+
+ uart@80120000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x80120000 0x1000>;
+ interrupts = <0 11 0x4>;
+
+ pinctrl-names = "default","sleep";
+ pinctrl-0 = <&uart0_default_mux>, <&uart0_default_mode>;
+ pinctrl-1 = <&uart0_sleep_mode>;
+ };
diff --git a/Documentation/devicetree/bindings/power_supply/max8925_batter.txt b/Documentation/devicetree/bindings/power_supply/max8925_batter.txt
new file mode 100644
index 000000000000..d7e3e0c0f71d
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/max8925_batter.txt
@@ -0,0 +1,18 @@
+max8925-battery bindings
+~~~~~~~~~~~~~~~~
+
+Optional properties :
+ - batt-detect: whether support battery detect
+ - topoff-threshold: set charging current in topoff mode
+ - fast-charge: set charging current in fast mode
+ - no-temp-support: whether support temperature protection detect
+ - no-insert-detect: whether support insert detect
+
+Example:
+ charger {
+ batt-detect = <0>;
+ topoff-threshold = <1>;
+ fast-charge = <7>;
+ no-temp-support = <0>;
+ no-insert-detect = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt b/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt
new file mode 100644
index 000000000000..9a599d27bd75
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt
@@ -0,0 +1,13 @@
+* QNAP Power Off
+
+QNAP NAS devices have a microcontroller controlling the main power
+supply. This microcontroller is connected to UART1 of the Kirkwood and
+Orion5x SoCs. Sending the charactor 'A', at 19200 baud, tells the
+microcontroller to turn the power off. This driver adds a handler to
+pm_power_off which is called to turn the power off.
+
+Required Properties:
+- compatible: Should be "qnap,power-off"
+
+- reg: Address and length of the register set for UART1
+- clocks: tclk clock
diff --git a/Documentation/devicetree/bindings/power_supply/restart-poweroff.txt b/Documentation/devicetree/bindings/power_supply/restart-poweroff.txt
new file mode 100644
index 000000000000..5776e684afda
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/restart-poweroff.txt
@@ -0,0 +1,8 @@
+* Restart Power Off
+
+Buffalo Linkstation LS-XHL and LS-CHLv2, and other devices power off
+by restarting and letting u-boot keep hold of the machine until the
+user presses a button.
+
+Required Properties:
+- compatible: Should be "restart-poweroff"
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/guts.txt b/Documentation/devicetree/bindings/powerpc/fsl/guts.txt
index 9e7a2417dac5..7f150b5012cc 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/guts.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/guts.txt
@@ -17,9 +17,20 @@ Recommended properties:
contains a functioning "reset control register" (i.e. the board
is wired to reset upon setting the HRESET_REQ bit in this register).
-Example:
+ - fsl,liodn-bits : Indicates the number of defined bits in the LIODN
+ registers, for those SOCs that have a PAMU device.
+
+Examples:
global-utilities@e0000 { /* global utilities block */
compatible = "fsl,mpc8548-guts";
reg = <e0000 1000>;
fsl,has-rstcr;
};
+
+ guts: global-utilities@e0000 {
+ compatible = "fsl,qoriq-device-config-1.0";
+ reg = <0xe0000 0xe00>;
+ fsl,has-rstcr;
+ #sleep-cells = <1>;
+ fsl,liodn-bits = <12>;
+ };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/pamu.txt b/Documentation/devicetree/bindings/powerpc/fsl/pamu.txt
new file mode 100644
index 000000000000..1f5e329f756c
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/pamu.txt
@@ -0,0 +1,140 @@
+Freescale Peripheral Management Access Unit (PAMU) Device Tree Binding
+
+DESCRIPTION
+
+The PAMU is an I/O MMU that provides device-to-memory access control and
+address translation capabilities.
+
+Required properties:
+
+- compatible : <string>
+ First entry is a version-specific string, such as
+ "fsl,pamu-v1.0". The second is "fsl,pamu".
+- ranges : <prop-encoded-array>
+ A standard property. Utilized to describe the memory mapped
+ I/O space utilized by the controller. The size should
+ be set to the total size of the register space of all
+ physically present PAMU controllers. For example, for
+ PAMU v1.0, on an SOC that has five PAMU devices, the size
+ is 0x5000.
+- interrupts : <prop-encoded-array>
+ Interrupt mappings. The first tuple is the normal PAMU
+ interrupt, used for reporting access violations. The second
+ is for PAMU hardware errors, such as PAMU operation errors
+ and ECC errors.
+- #address-cells: <u32>
+ A standard property.
+- #size-cells : <u32>
+ A standard property.
+
+Optional properties:
+- reg : <prop-encoded-array>
+ A standard property. It represents the CCSR registers of
+ all child PAMUs combined. Include it to provide support
+ for legacy drivers.
+- interrupt-parent : <phandle>
+ Phandle to interrupt controller
+
+Child nodes:
+
+Each child node represents one PAMU controller. Each SOC device that is
+connected to a specific PAMU device should have a "fsl,pamu-phandle" property
+that links to the corresponding specific child PAMU controller.
+
+- reg : <prop-encoded-array>
+ A standard property. Specifies the physical address and
+ length (relative to the parent 'ranges' property) of this
+ PAMU controller's configuration registers. The size should
+ be set to the size of this PAMU controllers's register space.
+ For PAMU v1.0, this size is 0x1000.
+- fsl,primary-cache-geometry
+ : <prop-encoded-array>
+ Two cells that specify the geometry of the primary PAMU
+ cache. The first is the number of cache lines, and the
+ second is the number of "ways". For direct-mapped caches,
+ specify a value of 1.
+- fsl,secondary-cache-geometry
+ : <prop-encoded-array>
+ Two cells that specify the geometry of the secondary PAMU
+ cache. The first is the number of cache lines, and the
+ second is the number of "ways". For direct-mapped caches,
+ specify a value of 1.
+
+Device nodes:
+
+Devices that have LIODNs need to specify links to the parent PAMU controller
+(the actual PAMU controller that this device is connected to) and a pointer to
+the LIODN register, if applicable.
+
+- fsl,iommu-parent
+ : <phandle>
+ Phandle to the single, specific PAMU controller node to which
+ this device is connect. The PAMU topology is represented in
+ the device tree to assist code that dynamically determines the
+ best LIODN values to minimize PAMU cache thrashing.
+
+- fsl,liodn-reg : <prop-encoded-array>
+ Two cells that specify the location of the LIODN register
+ for this device. Required for devices that have a single
+ LIODN. The first cell is a phandle to a node that contains
+ the registers where the LIODN is to be set. The second is
+ the offset from the first "reg" resource of the node where
+ the specific LIODN register is located.
+
+
+Example:
+
+ iommu@20000 {
+ compatible = "fsl,pamu-v1.0", "fsl,pamu";
+ reg = <0x20000 0x5000>;
+ ranges = <0 0x20000 0x5000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupts = <
+ 24 2 0 0
+ 16 2 1 30>;
+
+ pamu0: pamu@0 {
+ reg = <0 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu1: pamu@1000 {
+ reg = <0x1000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu2: pamu@2000 {
+ reg = <0x2000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu3: pamu@3000 {
+ reg = <0x3000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu4: pamu@4000 {
+ reg = <0x4000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+ };
+
+ guts: global-utilities@e0000 {
+ compatible = "fsl,qoriq-device-config-1.0";
+ reg = <0xe0000 0xe00>;
+ fsl,has-rstcr;
+ #sleep-cells = <1>;
+ fsl,liodn-bits = <12>;
+ };
+
+/include/ "qoriq-dma-0.dtsi"
+ dma@100300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x584>; /* DMA2LIODNR */
+ };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/srio.txt b/Documentation/devicetree/bindings/powerpc/fsl/srio.txt
index b039bcbee134..07abf0f2f440 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/srio.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/srio.txt
@@ -8,9 +8,9 @@ Properties:
Definition: Must include "fsl,srio" for IP blocks with IP Block
Revision Register (SRIO IPBRR1) Major ID equal to 0x01c0.
- Optionally, a compatiable string of "fsl,srio-vX.Y" where X is Major
+ Optionally, a compatible string of "fsl,srio-vX.Y" where X is Major
version in IP Block Revision Register and Y is Minor version. If this
- compatiable is provided it should be ordered before "fsl,srio".
+ compatible is provided it should be ordered before "fsl,srio".
- reg
Usage: required
diff --git a/Documentation/devicetree/bindings/regulator/anatop-regulator.txt b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
index 357758cb6e92..758eae24082a 100644
--- a/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt
@@ -9,6 +9,11 @@ Required properties:
- anatop-min-voltage: Minimum voltage of this regulator
- anatop-max-voltage: Maximum voltage of this regulator
+Optional properties:
+- anatop-delay-reg-offset: Anatop MFD step time register offset
+- anatop-delay-bit-shift: Bit shift for the step time register
+- anatop-delay-bit-width: Number of bits used in the step time register
+
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
@@ -23,6 +28,9 @@ Example:
anatop-reg-offset = <0x140>;
anatop-vol-bit-shift = <9>;
anatop-vol-bit-width = <5>;
+ anatop-delay-reg-offset = <0x170>;
+ anatop-delay-bit-shift = <24>;
+ anatop-delay-bit-width = <2>;
anatop-min-bit-val = <1>;
anatop-min-voltage = <725000>;
anatop-max-voltage = <1300000>;
diff --git a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
new file mode 100644
index 000000000000..a35ff99003a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
@@ -0,0 +1,152 @@
+* Samsung S5M8767 Voltage and Current Regulator
+
+The Samsung S5M8767 is a multi-function device which includes volatage and
+current regulators, rtc, charger controller and other sub-blocks. It is
+interfaced to the host controller using a i2c interface. Each sub-block is
+addressed by the host system using different i2c slave address. This document
+describes the bindings for 'pmic' sub-block of s5m8767.
+
+Required properties:
+- compatible: Should be "samsung,s5m8767-pmic".
+- reg: Specifies the i2c slave address of the pmic block. It should be 0x66.
+
+- s5m8767,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+ units for buck2 when changing voltage using gpio dvs. Refer to [1] below
+ for additional information.
+
+- s5m8767,pmic-buck3-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+ units for buck3 when changing voltage using gpio dvs. Refer to [1] below
+ for additional information.
+
+- s5m8767,pmic-buck4-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
+ units for buck4 when changing voltage using gpio dvs. Refer to [1] below
+ for additional information.
+
+- s5m8767,pmic-buck-ds-gpios: GPIO specifiers for three host gpio's used
+ for selecting GPIO DVS lines. It is one-to-one mapped to dvs gpio lines.
+
+[1] If none of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
+ property is specified, the 's5m8767,pmic-buck[2/3/4]-dvs-voltage'
+ property should specify atleast one voltage level (which would be a
+ safe operating voltage).
+
+ If either of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
+ property is specified, then all the eight voltage values for the
+ 's5m8767,pmic-buck[2/3/4]-dvs-voltage' should be specified.
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+ the interrupts from s5m8767 are delivered to.
+- interrupts: Interrupt specifiers for two interrupt sources.
+ - First interrupt specifier is for 'irq1' interrupt.
+ - Second interrupt specifier is for 'alert' interrupt.
+- s5m8767,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs.
+- s5m8767,pmic-buck3-uses-gpio-dvs: 'buck3' can be controlled by gpio dvs.
+- s5m8767,pmic-buck4-uses-gpio-dvs: 'buck4' can be controlled by gpio dvs.
+
+Additional properties required if either of the optional properties are used:
+
+- s5m8767,pmic-buck234-default-dvs-idx: Default voltage setting selected from
+ the possible 8 options selectable by the dvs gpios. The value of this
+ property should be between 0 and 7. If not specified or if out of range, the
+ default value of this property is set to 0.
+
+- s5m8767,pmic-buck-dvs-gpios: GPIO specifiers for three host gpio's used
+ for dvs. The format of the gpio specifier depends in the gpio controller.
+
+Regulators: The regulators of s5m8767 that have to be instantiated should be
+included in a sub-node named 'regulators'. Regulator nodes included in this
+sub-node should be of the format as listed below.
+
+ regulator_name {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ALIVE_1.0V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+ };
+The above regulator entries are defined in regulator bindings documentation
+except op_mode description.
+ - op_mode: describes the different operating modes of the LDO's with
+ power mode change in SOC. The different possible values are,
+ 0 - always off mode
+ 1 - on in normal mode
+ 2 - low power mode
+ 3 - suspend mode
+
+The following are the names of the regulators that the s5m8767 pmic block
+supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
+as per the datasheet of s5m8767.
+
+ - LDOn
+ - valid values for n are 1 to 28
+ - Example: LDO0, LD01, LDO28
+ - BUCKn
+ - valid values for n are 1 to 9.
+ - Example: BUCK1, BUCK2, BUCK9
+
+The bindings inside the regulator nodes use the standard regulator bindings
+which are documented elsewhere.
+
+Example:
+
+ s5m8767_pmic@66 {
+ compatible = "samsung,s5m8767-pmic";
+ reg = <0x66>;
+
+ s5m8767,pmic-buck2-uses-gpio-dvs;
+ s5m8767,pmic-buck3-uses-gpio-dvs;
+ s5m8767,pmic-buck4-uses-gpio-dvs;
+
+ s5m8767,pmic-buck-default-dvs-idx = <0>;
+
+ s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 1 0 0>, /* DVS1 */
+ <&gpx0 1 1 0 0>, /* DVS2 */
+ <&gpx0 2 1 0 0>; /* DVS3 */
+
+ s5m8767,pmic-buck-ds-gpios = <&gpx2 3 1 0 0>, /* SET1 */
+ <&gpx2 4 1 0 0>, /* SET2 */
+ <&gpx2 5 1 0 0>; /* SET3 */
+
+ s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>,
+ <1250000>, <1200000>,
+ <1150000>, <1100000>,
+ <1000000>, <950000>;
+
+ s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>,
+ <1100000>, <1100000>,
+ <1000000>, <1000000>,
+ <1000000>, <1000000>;
+
+ s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>;
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ABB_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "VDD_ALIVE_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "VDD_MIF_1.2V";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/regulator/tps51632-regulator.txt b/Documentation/devicetree/bindings/regulator/tps51632-regulator.txt
new file mode 100644
index 000000000000..2f7e44a96414
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/tps51632-regulator.txt
@@ -0,0 +1,27 @@
+TPS51632 Voltage regulators
+
+Required properties:
+- compatible: Must be "ti,tps51632"
+- reg: I2C slave address
+
+Optional properties:
+- ti,enable-pwm-dvfs: Enable the DVFS voltage control through the PWM interface.
+- ti,dvfs-step-20mV: The 20mV step voltage when PWM DVFS enabled. Missing this
+ will set 10mV step voltage in PWM DVFS mode. In normal mode, the voltage
+ step is 10mV as per datasheet.
+
+Any property defined as part of the core regulator binding, defined in
+regulator.txt, can also be used.
+
+Example:
+
+ tps51632 {
+ compatible = "ti,tps51632";
+ reg = <0x43>;
+ regulator-name = "tps51632-vout";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-boot-on;
+ ti,enable-pwm-dvfs;
+ ti,dvfs-step-20mV;
+ };
diff --git a/Documentation/devicetree/bindings/regulator/tps62360-regulator.txt b/Documentation/devicetree/bindings/regulator/tps62360-regulator.txt
index c8ca6b8f6582..1b20c3dbcdb8 100644
--- a/Documentation/devicetree/bindings/regulator/tps62360-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/tps62360-regulator.txt
@@ -17,9 +17,9 @@ Optional properties:
- ti,vsel1-gpio: Gpio for controlling VSEL1 line.
If this property is missing, then assume that there is no GPIO
for vsel1 control.
-- ti,vsel0-state-high: Inital state of vsel0 input is high.
+- ti,vsel0-state-high: Initial state of vsel0 input is high.
If this property is missing, then assume the state as low (0).
-- ti,vsel1-state-high: Inital state of vsel1 input is high.
+- ti,vsel1-state-high: Initial state of vsel1 input is high.
If this property is missing, then assume the state as low (0).
Any property defined as part of the core regulator binding, defined in
diff --git a/Documentation/devicetree/bindings/regulator/tps65090.txt b/Documentation/devicetree/bindings/regulator/tps65090.txt
new file mode 100644
index 000000000000..313a60ba61d8
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/tps65090.txt
@@ -0,0 +1,122 @@
+TPS65090 regulators
+
+Required properties:
+- compatible: "ti,tps65090"
+- reg: I2C slave address
+- interrupts: the interrupt outputs of the controller
+- regulators: A node that houses a sub-node for each regulator within the
+ device. Each sub-node is identified using the node's name, with valid
+ values listed below. The content of each sub-node is defined by the
+ standard binding for regulators; see regulator.txt.
+ dcdc[1-3], fet[1-7] and ldo[1-2] respectively.
+- vsys[1-3]-supply: The input supply for DCDC[1-3] respectively.
+- infet[1-7]-supply: The input supply for FET[1-7] respectively.
+- vsys-l[1-2]-supply: The input supply for LDO[1-2] respectively.
+
+Optional properties:
+- ti,enable-ext-control: This is applicable for DCDC1, DCDC2 and DCDC3.
+ If DCDCs are externally controlled then this property should be there.
+- "dcdc-ext-control-gpios: This is applicable for DCDC1, DCDC2 and DCDC3.
+ If DCDCs are externally controlled and if it is from GPIO then GPIO
+ number should be provided. If it is externally controlled and no GPIO
+ entry then driver will just configure this rails as external control
+ and will not provide any enable/disable APIs.
+
+Each regulator is defined using the standard binding for regulators.
+
+Example:
+
+ tps65090@48 {
+ compatible = "ti,tps65090";
+ reg = <0x48>;
+ interrupts = <0 88 0x4>;
+
+ vsys1-supply = <&some_reg>;
+ vsys2-supply = <&some_reg>;
+ vsys3-supply = <&some_reg>;
+ infet1-supply = <&some_reg>;
+ infet2-supply = <&some_reg>;
+ infet3-supply = <&some_reg>;
+ infet4-supply = <&some_reg>;
+ infet5-supply = <&some_reg>;
+ infet6-supply = <&some_reg>;
+ infet7-supply = <&some_reg>;
+ vsys_l1-supply = <&some_reg>;
+ vsys_l2-supply = <&some_reg>;
+
+ regulators {
+ dcdc1 {
+ regulator-name = "dcdc1";
+ regulator-boot-on;
+ regulator-always-on;
+ ti,enable-ext-control;
+ dcdc-ext-control-gpios = <&gpio 10 0>;
+ };
+
+ dcdc2 {
+ regulator-name = "dcdc2";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ dcdc3 {
+ regulator-name = "dcdc3";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ fet1 {
+ regulator-name = "fet1";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ fet2 {
+ regulator-name = "fet2";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ fet3 {
+ regulator-name = "fet3";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ fet4 {
+ regulator-name = "fet4";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ fet5 {
+ regulator-name = "fet5";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ fet6 {
+ regulator-name = "fet6";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ fet7 {
+ regulator-name = "fet7";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1 {
+ regulator-name = "ldo1";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo2 {
+ regulator-name = "ldo2";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.txt b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt
index 90ec45fd33ec..7ac7259fe9ea 100644
--- a/Documentation/devicetree/bindings/rtc/s3c-rtc.txt
+++ b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt
@@ -7,7 +7,7 @@ Required properties:
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: Two interrupt numbers to the cpu should be specified. First
- interrupt number is the rtc alarm interupt and second interrupt number
+ interrupt number is the rtc alarm interrupt and second interrupt number
is the rtc tick interrupt. The number of cells representing a interrupt
depends on the parent interrupt controller.
diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt
new file mode 100644
index 000000000000..392a4493eebd
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt
@@ -0,0 +1,24 @@
+NVIDIA Tegra20/Tegra30 high speed (DMA based) UART controller driver.
+
+Required properties:
+- compatible : should be "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart".
+- reg: Should contain UART controller registers location and length.
+- interrupts: Should contain UART controller interrupts.
+- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
+ request selector for this UART controller.
+
+Optional properties:
+- nvidia,enable-modem-interrupt: Enable modem interrupts. Should be enable
+ only if all 8 lines of UART controller are pinmuxed.
+
+Example:
+
+serial@70006000 {
+ compatible = "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart";
+ reg = <0x70006000 0x40>;
+ reg-shift = <2>;
+ interrupts = <0 36 0x04>;
+ nvidia,dma-request-selector = <&apbdma 8>;
+ nvidia,enable-modem-interrupt;
+ status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/sound/ak4642.txt b/Documentation/devicetree/bindings/sound/ak4642.txt
new file mode 100644
index 000000000000..623d4e70ae11
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ak4642.txt
@@ -0,0 +1,17 @@
+AK4642 I2C transmitter
+
+This device supports I2C mode only.
+
+Required properties:
+
+ - compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648"
+ - reg : The chip select number on the I2C bus
+
+Example:
+
+&i2c {
+ ak4648: ak4648@0x12 {
+ compatible = "asahi-kasei,ak4642";
+ reg = <0x12>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/cs4271.txt b/Documentation/devicetree/bindings/sound/cs4271.txt
index a850fb9c88ea..e2cd1d7539e5 100644
--- a/Documentation/devicetree/bindings/sound/cs4271.txt
+++ b/Documentation/devicetree/bindings/sound/cs4271.txt
@@ -20,6 +20,18 @@ Optional properties:
!RESET pin
- cirrus,amuteb-eq-bmutec: When given, the Codec's AMUTEB=BMUTEC flag
is enabled.
+ - cirrus,enable-soft-reset:
+ The CS4271 requires its LRCLK and MCLK to be stable before its RESET
+ line is de-asserted. That also means that clocks cannot be changed
+ without putting the chip back into hardware reset, which also requires
+ a complete re-initialization of all registers.
+
+ One (undocumented) workaround is to assert and de-assert the PDN bit
+ in the MODE2 register. This workaround can be enabled with this DT
+ property.
+
+ Note that this is not needed in case the clocks are stable
+ throughout the entire runtime of the codec.
Examples:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt
new file mode 100644
index 000000000000..be35d34e8b26
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt
@@ -0,0 +1,51 @@
+NVIDIA Tegra audio complex
+
+Required properties:
+- compatible : "nvidia,tegra-audio-wm9712"
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source. Valid names for sources and
+ sinks are the WM9712's pins, and the jacks on the board:
+
+ WM9712 pins:
+
+ * MONOOUT
+ * HPOUTL
+ * HPOUTR
+ * LOUT2
+ * ROUT2
+ * OUT3
+ * LINEINL
+ * LINEINR
+ * PHONE
+ * PCBEEP
+ * MIC1
+ * MIC2
+ * Mic Bias
+
+ Board connectors:
+
+ * Headphone
+ * LineIn
+ * Mic
+
+- nvidia,ac97-controller : The phandle of the Tegra AC97 controller
+
+
+Example:
+
+sound {
+ compatible = "nvidia,tegra-audio-wm9712-colibri_t20",
+ "nvidia,tegra-audio-wm9712";
+ nvidia,model = "Toradex Colibri T20";
+
+ nvidia,audio-routing =
+ "Headphone", "HPOUTL",
+ "Headphone", "HPOUTR",
+ "LineIn", "LINEINL",
+ "LineIn", "LINEINR",
+ "Mic", "MIC1";
+
+ nvidia,ac97-controller = <&ac97>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt
new file mode 100644
index 000000000000..c1454979c1ef
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt
@@ -0,0 +1,22 @@
+NVIDIA Tegra 20 AC97 controller
+
+Required properties:
+- compatible : "nvidia,tegra20-ac97"
+- reg : Should contain AC97 controller registers location and length
+- interrupts : Should contain AC97 interrupt
+- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
+ request selector for the AC97 controller
+- nvidia,codec-reset-gpio : The Tegra GPIO controller's phandle and the number
+ of the GPIO used to reset the external AC97 codec
+- nvidia,codec-sync-gpio : The Tegra GPIO controller's phandle and the number
+ of the GPIO corresponding with the AC97 DAP _FS line
+Example:
+
+ac97@70002000 {
+ compatible = "nvidia,tegra20-ac97";
+ reg = <0x70002000 0x200>;
+ interrupts = <0 81 0x04>;
+ nvidia,dma-request-selector = <&apbdma 12>;
+ nvidia,codec-reset-gpio = <&gpio 170 0>;
+ nvidia,codec-sync-gpio = <&gpio 120 0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/omap-twl4030.txt b/Documentation/devicetree/bindings/sound/omap-twl4030.txt
index 6fae51c7f766..1ab6bc8404d5 100644
--- a/Documentation/devicetree/bindings/sound/omap-twl4030.txt
+++ b/Documentation/devicetree/bindings/sound/omap-twl4030.txt
@@ -6,6 +6,52 @@ Required properties:
- ti,mcbsp: phandle for the McBSP node
- ti,codec: phandle for the twl4030 audio node
+Optional properties:
+- ti,mcbsp-voice: phandle for the McBSP node connected to the voice port of twl
+- ti, jack-det-gpio: Jack detect GPIO
+- ti,audio-routing: List of connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source.
+ If the routing is not provided all possible connection will be available
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headset Stereophone
+ * Earpiece Spk
+ * Handsfree Spk
+ * Ext Spk
+ * Main Mic
+ * Sub Mic
+ * Headset Mic
+ * Carkit Mic
+ * Digital0 Mic
+ * Digital1 Mic
+ * Line In
+
+twl4030 pins:
+ * HSOL
+ * HSOR
+ * EARPIECE
+ * HFL
+ * HFR
+ * PREDRIVEL
+ * PREDRIVER
+ * CARKITL
+ * CARKITR
+ * MAINMIC
+ * SUBMIC
+ * HSMIC
+ * DIGIMIC0
+ * DIGIMIC1
+ * CARKITMIC
+ * AUXL
+ * AUXR
+
+ * Headset Mic Bias
+ * Mic Bias 1 /* Used for Main Mic or Digimic0 */
+ * Mic Bias 2 /* Used for Sub Mic or Digimic1 */
+
Example:
sound {
diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/Documentation/devicetree/bindings/sound/renesas,fsi.txt
new file mode 100644
index 000000000000..c5be003f413e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/renesas,fsi.txt
@@ -0,0 +1,26 @@
+Renesas FSI
+
+Required properties:
+- compatible : "renesas,sh_fsi2" or "renesas,sh_fsi"
+- reg : Should contain the register physical address and length
+- interrupts : Should contain FSI interrupt
+
+- fsia,spdif-connection : FSI is connected by S/PDFI
+- fsia,stream-mode-support : FSI supports 16bit stream mode.
+- fsia,use-internal-clock : FSI uses internal clock when master mode.
+
+- fsib,spdif-connection : same as fsia
+- fsib,stream-mode-support : same as fsia
+- fsib,use-internal-clock : same as fsia
+
+Example:
+
+sh_fsi2: sh_fsi2@0xec230000 {
+ compatible = "renesas,sh_fsi2";
+ reg = <0xec230000 0x400>;
+ interrupts = <0 146 0x4>;
+
+ fsia,spdif-connection;
+ fsia,stream-mode-support;
+ fsia,use-internal-clock;
+};
diff --git a/Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt b/Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt
new file mode 100644
index 000000000000..4686646fb122
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/samsung,smdk-wm8994.txt
@@ -0,0 +1,14 @@
+Samsung SMDK audio complex
+
+Required properties:
+- compatible : "samsung,smdk-wm8994"
+- samsung,i2s-controller: The phandle of the Samsung I2S0 controller
+- samsung,audio-codec: The phandle of the WM8994 audio codec
+Example:
+
+sound {
+ compatible = "samsung,smdk-wm8994";
+
+ samsung,i2s-controller = <&i2s0>;
+ samsung,audio-codec = <&wm8994>;
+};
diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
new file mode 100644
index 000000000000..3070046da2e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
@@ -0,0 +1,63 @@
+* Samsung I2S controller
+
+Required SoC Specific Properties:
+
+- compatible : "samsung,i2s-v5"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- dmas: list of DMA controller phandle and DMA request line ordered pairs.
+- dma-names: identifier string for each DMA request line in the dmas property.
+ These strings correspond 1:1 with the ordered pairs in dmas.
+
+Optional SoC Specific Properties:
+
+- samsung,supports-6ch: If the I2S Primary sound source has 5.1 Channel
+ support, this flag is enabled.
+- samsung,supports-rstclr: This flag should be set if I2S software reset bit
+ control is required. When this flag is set I2S software reset bit will be
+ enabled or disabled based on need.
+- samsung,supports-secdai:If I2S block has a secondary FIFO and internal DMA,
+ then this flag is enabled.
+- samsung,idma-addr: Internal DMA register base address of the audio
+ sub system(used in secondary sound source).
+
+Required Board Specific Properties:
+
+- gpios: The gpio specifier for data out,data in, LRCLK, CDCLK and SCLK
+ interface lines. The format of the gpio specifier depends on the gpio
+ controller.
+ The syntax of samsung gpio specifier is
+ <[phandle of the gpio controller node]
+ [pin number within the gpio controller]
+ [mux function]
+ [flags and pull up/down]
+ [drive strength]>
+
+Example:
+
+- SoC Specific Portion:
+
+i2s@03830000 {
+ compatible = "samsung,i2s-v5";
+ reg = <0x03830000 0x100>;
+ dmas = <&pdma0 10
+ &pdma0 9
+ &pdma0 8>;
+ dma-names = "tx", "rx", "tx-sec";
+ samsung,supports-6ch;
+ samsung,supports-rstclr;
+ samsung,supports-secdai;
+ samsung,idma-addr = <0x03000000>;
+};
+
+- Board Specific Portion:
+
+i2s@03830000 {
+ gpios = <&gpz 0 2 0 0>, /* I2S_0_SCLK */
+ <&gpz 1 2 0 0>, /* I2S_0_CDCLK */
+ <&gpz 2 2 0 0>, /* I2S_0_LRCK */
+ <&gpz 3 2 0 0>, /* I2S_0_SDI */
+ <&gpz 4 2 0 0>, /* I2S_0_SDO[1] */
+ <&gpz 5 2 0 0>, /* I2S_0_SDO[2] */
+ <&gpz 6 2 0 0>; /* I2S_0_SDO[3] */
+};
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
index e7b98f41fa5f..f47c3f589fd0 100644
--- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
+++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
@@ -11,6 +11,12 @@ Optional properties:
- gpio-reset - gpio pin number used for codec reset
- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
+- ai3x-micbias-vg - MicBias Voltage required.
+ 1 - MICBIAS output is powered to 2.0V,
+ 2 - MICBIAS output is powered to 2.5V,
+ 3 - MICBIAS output is connected to AVDD,
+ If this node is not mentioned or if the value is incorrect, then MicBias
+ is powered down.
Example:
diff --git a/Documentation/devicetree/bindings/sound/wm8962.txt b/Documentation/devicetree/bindings/sound/wm8962.txt
new file mode 100644
index 000000000000..dceb3b1c2bb7
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wm8962.txt
@@ -0,0 +1,16 @@
+WM8962 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+ - compatible : "wlf,wm8962"
+
+ - reg : the I2C address of the device.
+
+Example:
+
+codec: wm8962@1a {
+ compatible = "wlf,wm8962";
+ reg = <0x1a>;
+};
diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt
new file mode 100644
index 000000000000..e6222106ca36
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt
@@ -0,0 +1,12 @@
+Renesas MSIOF spi controller
+
+Required properties:
+- compatible : "renesas,sh-msiof" for SuperH or
+ "renesas,sh-mobile-msiof" for SH Mobile series
+- reg : Offset and length of the register set for the device
+- interrupts : interrupt line used by MSIOF
+
+Optional properties:
+- num-cs : total number of chip-selects
+- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
+- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
index 801d58cb6d4d..46882058b59b 100644
--- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
+++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
@@ -5,6 +5,12 @@ Required properties:
- reg: Address and length of the register set for the device
- interrupts: Should contain the LRADC interrupts
+Optional properties:
+- fsl,lradc-touchscreen-wires: Number of wires used to connect the touchscreen
+ to LRADC. Valid value is either 4 or 5. If this
+ property is not present, then the touchscreen is
+ disabled.
+
Examples:
lradc@80050000 {
diff --git a/Documentation/devicetree/bindings/tty/serial/arc-uart.txt b/Documentation/devicetree/bindings/tty/serial/arc-uart.txt
new file mode 100644
index 000000000000..5cae2eb686f8
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/arc-uart.txt
@@ -0,0 +1,26 @@
+* Synopsys ARC UART : Non standard UART used in some of the ARC FPGA boards
+
+Required properties:
+- compatible : "snps,arc-uart"
+- reg : offset and length of the register set for the device.
+- interrupts : device interrupt
+- clock-frequency : the input clock frequency for the UART
+- current-speed : baud rate for UART
+
+e.g.
+
+arcuart0: serial@c0fc1000 {
+ compatible = "snps,arc-uart";
+ reg = <0xc0fc1000 0x100>;
+ interrupts = <5>;
+ clock-frequency = <80000000>;
+ current-speed = <115200>;
+ status = "okay";
+};
+
+Note: Each port should have an alias correctly numbered in "aliases" node.
+
+e.g.
+aliases {
+ serial0 = &arcuart0;
+};
diff --git a/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt b/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt
index 6588b6950a7f..8e080b893b49 100644
--- a/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt
+++ b/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt
@@ -5,10 +5,16 @@ Required properties:
- reg : Address and length of the register set
- interrupts : Should contain uart interrupt
+Optional properties:
+- location : Decides the location of the USART I/O pins.
+ Allowed range : [0 .. 5]
+ Default: 0
+
Example:
uart@0x4000c400 {
compatible = "efm32,uart";
reg = <0x4000c400 0x400>;
interrupts = <15>;
+ location = <0>;
};
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
new file mode 100644
index 000000000000..7a95c651ceb3
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -0,0 +1,22 @@
+synopsys DWC3 CORE
+
+DWC3- USB3 CONTROLLER
+
+Required properties:
+ - compatible: must be "synopsys,dwc3"
+ - reg : Address and length of the register set for the device
+ - interrupts: Interrupts used by the dwc3 controller.
+ - usb-phy : array of phandle for the PHY device
+
+Optional properties:
+ - tx-fifo-resize: determines if the FIFO *has* to be reallocated.
+
+This is usually a subnode to DWC3 glue to which it is connected.
+
+dwc3@4a030000 {
+ compatible = "synopsys,dwc3";
+ reg = <0x4a030000 0xcfff>;
+ interrupts = <0 92 4>
+ usb-phy = <&usb2_phy>, <&usb3,phy>;
+ tx-fifo-resize;
+};
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt
index e9b005dc7625..34c952883276 100644
--- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt
@@ -11,6 +11,7 @@ Required properties :
- phy_type : Should be one of "ulpi" or "utmi".
- nvidia,vbus-gpio : If present, specifies a gpio that needs to be
activated for the bus to be powered.
+ - nvidia,phy : phandle of the PHY instance, the controller is connected to.
Required properties for phy_type == ulpi:
- nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
@@ -27,3 +28,5 @@ Optional properties:
registers are accessed through the APB_MISC base address instead of
the USB controller. Since this is a legacy issue it probably does not
warrant a compatible string of its own.
+ - nvidia,needs-double-reset : boolean is to be set for some of the Tegra2
+ USB ports, which need reset twice due to hardware issues.
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt
new file mode 100644
index 000000000000..6bdaba2f0aa1
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt
@@ -0,0 +1,17 @@
+Tegra SOC USB PHY
+
+The device node for Tegra SOC USB PHY:
+
+Required properties :
+ - compatible : Should be "nvidia,tegra20-usb-phy".
+ - reg : Address and length of the register set for the USB PHY interface.
+ - phy_type : Should be one of "ulpi" or "utmi".
+
+Required properties for phy_type == ulpi:
+ - nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
+
+Optional properties:
+ - nvidia,has-legacy-mode : boolean indicates whether this controller can
+ operate in legacy mode (as APX 2500 / 2600). In legacy mode some
+ registers are accessed through the APB_MISC base address instead of
+ the USB controller. \ No newline at end of file
diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
index 29a043ecda52..1ef0ce71f8fa 100644
--- a/Documentation/devicetree/bindings/usb/omap-usb.txt
+++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
@@ -1,8 +1,11 @@
-OMAP GLUE
+OMAP GLUE AND OTHER OMAP SPECIFIC COMPONENTS
OMAP MUSB GLUE
- compatible : Should be "ti,omap4-musb" or "ti,omap3-musb"
- ti,hwmods : must be "usb_otg_hs"
+ - ti,has-mailbox : to specify that omap uses an external mailbox
+ (in control module) to communicate with the musb core during device connect
+ and disconnect.
- multipoint : Should be "1" indicating the musb controller supports
multipoint. This is a MUSB configuration-specific setting.
- num_eps : Specifies the number of endpoints. This is also a
@@ -16,13 +19,19 @@ OMAP MUSB GLUE
- power : Should be "50". This signifies the controller can supply upto
100mA when operating in host mode.
+Optional properties:
+ - ctrl-module : phandle of the control module this glue uses to write to
+ mailbox
+
SOC specific device node entry
usb_otg_hs: usb_otg_hs@4a0ab000 {
compatible = "ti,omap4-musb";
ti,hwmods = "usb_otg_hs";
+ ti,has-mailbox;
multipoint = <1>;
num_eps = <16>;
ram_bits = <12>;
+ ctrl-module = <&omap_control_usb>;
};
Board specific device node entry
@@ -31,3 +40,26 @@ Board specific device node entry
mode = <3>;
power = <50>;
};
+
+OMAP CONTROL USB
+
+Required properties:
+ - compatible: Should be "ti,omap-control-usb"
+ - reg : Address and length of the register set for the device. It contains
+ the address of "control_dev_conf" and "otghs_control" or "phy_power_usb"
+ depending upon omap4 or omap5.
+ - reg-names: The names of the register addresses corresponding to the registers
+ filled in "reg".
+ - ti,type: This is used to differentiate whether the control module has
+ usb mailbox or usb3 phy power. omap4 has usb mailbox in control module to
+ notify events to the musb core and omap5 has usb3 phy power register to
+ power on usb3 phy. Should be "1" if it has mailbox and "2" if it has usb3
+ phy power.
+
+omap_control_usb: omap-control-usb@4a002300 {
+ compatible = "ti,omap-control-usb";
+ reg = <0x4a002300 0x4>,
+ <0x4a00233c 0x4>;
+ reg-names = "control_dev_conf", "otghs_control";
+ ti,type = <1>;
+};
diff --git a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt
new file mode 100644
index 000000000000..033194934f64
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt
@@ -0,0 +1,55 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb phy for
+s3c-hsotg as well as ehci-s5p and ohci-exynos usb controllers
+across Samsung SOCs.
+TODO: Adding the PHY binding with controller(s) according to the under
+developement generic PHY driver.
+
+Required properties:
+
+Exynos4210:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+ region.
+
+Exynos5250:
+- compatible : should be "samsung,exynos5250-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+ region.
+
+Optional properties:
+- #address-cells: should be '1' when usbphy node has a child node with 'reg'
+ property.
+- #size-cells: should be '1' when usbphy node has a child node with 'reg'
+ property.
+- ranges: allows valid translation between child's address space and parent's
+ address space.
+
+- The child node 'usbphy-sys' to the node 'usbphy' is for the system controller
+ interface for usb-phy. It should provide the following information required by
+ usb-phy controller to control phy.
+ - reg : base physical address of PHY_CONTROL registers.
+ The size of this register is the total sum of size of all PHY_CONTROL
+ registers that the SoC has. For example, the size will be
+ '0x4' in case we have only one PHY_CONTROL register (e.g.
+ OTHERS register in S3C64XX or USB_PHY_CONTROL register in S5PV210)
+ and, '0x8' in case we have two PHY_CONTROL registers (e.g.
+ USBDEVICE_PHY_CONTROL and USBHOST_PHY_CONTROL registers in exynos4x).
+ and so on.
+
+Example:
+ - Exynos4210
+
+ usbphy@125B0000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "samsung,exynos4210-usbphy";
+ reg = <0x125B0000 0x100>;
+ ranges;
+
+ usbphy-sys {
+ /* USB device and host PHY_CONTROL registers */
+ reg = <0x10020704 0x8>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
index 80d4148cb661..61496f5cb095 100644
--- a/Documentation/devicetree/bindings/usb/usb-phy.txt
+++ b/Documentation/devicetree/bindings/usb/usb-phy.txt
@@ -4,14 +4,39 @@ OMAP USB2 PHY
Required properties:
- compatible: Should be "ti,omap-usb2"
- - reg : Address and length of the register set for the device. Also
-add the address of control module dev conf register until a driver for
-control module is added
+ - reg : Address and length of the register set for the device.
+
+Optional properties:
+ - ctrl-module : phandle of the control module used by PHY driver to power on
+ the PHY.
This is usually a subnode of ocp2scp to which it is connected.
usb2phy@4a0ad080 {
compatible = "ti,omap-usb2";
- reg = <0x4a0ad080 0x58>,
- <0x4a002300 0x4>;
+ reg = <0x4a0ad080 0x58>;
+ ctrl-module = <&omap_control_usb>;
+};
+
+OMAP USB3 PHY
+
+Required properties:
+ - compatible: Should be "ti,omap-usb3"
+ - reg : Address and length of the register set for the device.
+ - reg-names: The names of the register addresses corresponding to the registers
+ filled in "reg".
+
+Optional properties:
+ - ctrl-module : phandle of the control module used by PHY driver to power on
+ the PHY.
+
+This is usually a subnode of ocp2scp to which it is connected.
+
+usb3phy@4a084400 {
+ compatible = "ti,omap-usb3";
+ reg = <0x4a084400 0x80>,
+ <0x4a084800 0x64>,
+ <0x4a084c00 0x40>;
+ reg-names = "phy_rx", "phy_tx", "pll_ctrl";
+ ctrl-module = <&omap_control_usb>;
};
diff --git a/Documentation/devicetree/bindings/usb/usb3503.txt b/Documentation/devicetree/bindings/usb/usb3503.txt
new file mode 100644
index 000000000000..6813a715fc7d
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usb3503.txt
@@ -0,0 +1,20 @@
+SMSC USB3503 High-Speed Hub Controller
+
+Required properties:
+- compatible: Should be "smsc,usb3503".
+- reg: Specifies the i2c slave address, it should be 0x08.
+- connect-gpios: Should specify GPIO for connect.
+- intn-gpios: Should specify GPIO for interrupt.
+- reset-gpios: Should specify GPIO for reset.
+- initial-mode: Should specify initial mode.
+ (1 for HUB mode, 2 for STANDBY mode)
+
+Examples:
+ usb3503@08 {
+ compatible = "smsc,usb3503";
+ reg = <0x08>;
+ connect-gpios = <&gpx3 0 1>;
+ intn-gpios = <&gpx3 4 1>;
+ reset-gpios = <&gpx3 5 1>;
+ initial-mode = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 902b1b1f568e..19e1ef73ab0d 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -14,6 +14,7 @@ bosch Bosch Sensortec GmbH
brcm Broadcom Corporation
cavium Cavium, Inc.
chrp Common Hardware Reference Platform
+cirrus Cirrus Logic, Inc.
cortina Cortina Systems, Inc.
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
denx Denx Software Engineering
@@ -42,6 +43,7 @@ powervr PowerVR (deprecated, use img)
qcom Qualcomm, Inc.
ramtron Ramtron International
realtek Realtek Semiconductor Corp.
+renesas Renesas Electronics Corporation
samsung Samsung Semiconductor
sbs Smart Battery System
schindler Schindler
@@ -50,8 +52,10 @@ simtek
sirf SiRF Technology, Inc.
snps Synopsys, Inc.
st STMicroelectronics
+ste ST-Ericsson
stericsson ST-Ericsson
ti Texas Instruments
+toshiba Toshiba Corporation
via VIA Technologies, Inc.
wlf Wolfson Microelectronics
wm Wondermedia Technologies, Inc.
diff --git a/Documentation/devicetree/bindings/video/backlight/max8925-backlight.txt b/Documentation/devicetree/bindings/video/backlight/max8925-backlight.txt
new file mode 100644
index 000000000000..b4cffdaa4137
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/backlight/max8925-backlight.txt
@@ -0,0 +1,10 @@
+88pm860x-backlight bindings
+
+Optional properties:
+ - maxim,max8925-dual-string: whether support dual string
+
+Example:
+
+ backlights {
+ maxim,max8925-dual-string = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
index 79ead8263ae4..ce0d8e78ed8f 100644
--- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
@@ -2,7 +2,7 @@
The Samsung's Watchdog controller is used for resuming system operation
after a preset amount of time during which the WDT reset event has not
-occured.
+occurred.
Required properties:
- compatible : should be "samsung,s3c2410-wdt"
diff --git a/Documentation/devicetree/booting-without-of.txt b/Documentation/devicetree/booting-without-of.txt
index d4d66757354e..b2fb2f5e1922 100644
--- a/Documentation/devicetree/booting-without-of.txt
+++ b/Documentation/devicetree/booting-without-of.txt
@@ -1228,7 +1228,7 @@ hierarchy and routing of interrupts in the hardware.
The interrupt tree model is fully described in the
document "Open Firmware Recommended Practice: Interrupt
Mapping Version 0.9". The document is available at:
-<http://playground.sun.com/1275/practice>.
+<http://www.openfirmware.org/ofwg/practice/>
1) interrupts property
----------------------
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 43cff70465ab..b4671459857f 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -266,7 +266,8 @@ IOMAP
devm_ioremap()
devm_ioremap_nocache()
devm_iounmap()
- devm_request_and_ioremap() : checks resource, requests region, ioremaps
+ devm_ioremap_resource() : checks resource, requests memory region, ioremaps
+ devm_request_and_ioremap() : obsoleted by devm_ioremap_resource()
pcim_iomap()
pcim_iounmap()
pcim_iomap_table() : array of mapped addresses indexed by BAR
@@ -288,3 +289,7 @@ PINCTRL
PWM
devm_pwm_get()
devm_pwm_put()
+
+PHY
+ devm_usb_get_phy()
+ devm_usb_put_phy()
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 32bc56b13b1c..5d5ee4c13fa6 100755
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -23,7 +23,7 @@ use IO::Handle;
@components = ( "sp8870", "sp887x", "tda10045", "tda10046",
"tda10046lifeview", "av7110", "dec2000t", "dec2540t",
- "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
+ "dec3000s", "vp7041", "vp7049", "dibusb", "nxt2002", "nxt2004",
"or51211", "or51132_qam", "or51132_vsb", "bluebird",
"opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
"af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
@@ -289,6 +289,19 @@ sub vp7041 {
$outfile;
}
+sub vp7049 {
+ my $fwfile = "dvb-usb-vp7049-0.95.fw";
+ my $url = "http://ao2.it/sites/default/files/blog/2012/11/06/linux-support-digicom-digitune-s-vp7049-udtt7049/$fwfile";
+ my $hash = "5609fd295168aea88b25ff43a6f79c36";
+
+ checkstandard();
+
+ wgetfile($fwfile, $url);
+ verify($fwfile, $hash);
+
+ $fwfile;
+}
+
sub dibusb {
my $url = "http://www.linuxtv.org/downloads/firmware/dvb-usb-dibusb-5.0.0.11.fw";
my $outfile = "dvb-dibusb-5.0.0.11.fw";
@@ -677,7 +690,7 @@ sub drxk_terratec_h5 {
}
sub drxk_terratec_htc_stick {
- my $url = "http://ftp.terratec.de/Receiver/Cinergy_HTC_Stick/Updates/";
+ my $url = "http://ftp.terratec.de/Receiver/Cinergy_HTC_Stick/Updates/History/";
my $zipfile = "Cinergy_HTC_Stick_Drv_5.09.1202.00_XP_Vista_7.exe";
my $hash = "6722a2442a05423b781721fbc069ed5e";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt
index 6e1684981da2..72322c6d7352 100644
--- a/Documentation/dynamic-debug-howto.txt
+++ b/Documentation/dynamic-debug-howto.txt
@@ -6,8 +6,16 @@ This document describes how to use the dynamic debug (dyndbg) feature.
Dynamic debug is designed to allow you to dynamically enable/disable
kernel code to obtain additional kernel information. Currently, if
-CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_dbg() calls can
-be dynamically enabled per-callsite.
+CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_dbg() and
+print_hex_dump_debug()/print_hex_dump_bytes() calls can be dynamically
+enabled per-callsite.
+
+If CONFIG_DYNAMIC_DEBUG is not set, print_hex_dump_debug() is just
+shortcut for print_hex_dump(KERN_DEBUG).
+
+For print_hex_dump_debug()/print_hex_dump_bytes(), format string is
+its 'prefix_str' argument, if it is constant string; or "hexdump"
+in case 'prefix_str' is build dynamically.
Dynamic debug has even more useful features:
@@ -202,6 +210,9 @@ The flags are:
t Include thread ID in messages not generated from interrupt context
_ No flags are set. (Or'd with others on input)
+For print_hex_dump_debug() and print_hex_dump_bytes(), only 'p' flag
+have meaning, other flags ignored.
+
For display, the flags are preceded by '='
(mnemonic: what the flags are currently equal to).
diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
index 3374c085678d..fec5a9bf755f 100644
--- a/Documentation/hwmon/coretemp
+++ b/Documentation/hwmon/coretemp
@@ -66,6 +66,7 @@ Process Processor TjMax(C)
i5 3470T 91
32nm Core i3/i5/i7 Processors
+ i7 2600 98
i7 660UM/640/620, 640LM/620, 620M, 610E 105
i5 540UM/520/430, 540M/520/450/430 105
i3 330E, 370M/350/330 90 rPGA, 105 BGA
@@ -79,7 +80,10 @@ Process Processor TjMax(C)
P4505/P4500 90
32nm Atom Processors
+ S1260/1220 95
+ S1240 102
Z2460 90
+ Z2760 90
D2700/2550/2500 100
N2850/2800/2650/2600 100
@@ -98,6 +102,7 @@ Process Processor TjMax(C)
45nm Atom Processors
D525/510/425/410 100
+ K525/510/425/410 100
Z670/650 90
Z560/550/540/530P/530/520PT/520/515/510PT/510P 90
Z510/500 90
@@ -107,7 +112,11 @@ Process Processor TjMax(C)
330/230 125
E680/660/640/620 90
E680T/660T/640T/620T 110
+ E665C/645C 90
+ E665CT/645CT 110
CE4170/4150/4110 110
+ CE4200 series unknown
+ CE5300 series unknown
45nm Core2 Processors
Solo ULV SU3500/3300 100
diff --git a/Documentation/hwmon/ina209 b/Documentation/hwmon/ina209
new file mode 100644
index 000000000000..672501de4509
--- /dev/null
+++ b/Documentation/hwmon/ina209
@@ -0,0 +1,93 @@
+Kernel driver ina209
+=====================
+
+Supported chips:
+ * Burr-Brown / Texas Instruments INA209
+ Prefix: 'ina209'
+ Addresses scanned: -
+ Datasheet:
+ http://www.ti.com/lit/gpn/ina209
+
+Author: Paul Hays <Paul.Hays@cattail.ca>
+Author: Ira W. Snyder <iws@ovro.caltech.edu>
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+The TI / Burr-Brown INA209 monitors voltage, current, and power on the high side
+of a D.C. power supply. It can perform measurements and calculations in the
+background to supply readings at any time. It includes a programmable
+calibration multiplier to scale the displayed current and power values.
+
+
+Sysfs entries
+-------------
+
+The INA209 chip is highly configurable both via hardwiring and via
+the I2C bus. See the datasheet for details.
+
+This tries to expose most monitoring features of the hardware via
+sysfs. It does not support every feature of this chip.
+
+
+in0_input shunt voltage (mV)
+in0_input_highest shunt voltage historical maximum reading (mV)
+in0_input_lowest shunt voltage historical minimum reading (mV)
+in0_reset_history reset shunt voltage history
+in0_max shunt voltage max alarm limit (mV)
+in0_min shunt voltage min alarm limit (mV)
+in0_crit_max shunt voltage crit max alarm limit (mV)
+in0_crit_min shunt voltage crit min alarm limit (mV)
+in0_max_alarm shunt voltage max alarm limit exceeded
+in0_min_alarm shunt voltage min alarm limit exceeded
+in0_crit_max_alarm shunt voltage crit max alarm limit exceeded
+in0_crit_min_alarm shunt voltage crit min alarm limit exceeded
+
+in1_input bus voltage (mV)
+in1_input_highest bus voltage historical maximum reading (mV)
+in1_input_lowest bus voltage historical minimum reading (mV)
+in1_reset_history reset bus voltage history
+in1_max bus voltage max alarm limit (mV)
+in1_min bus voltage min alarm limit (mV)
+in1_crit_max bus voltage crit max alarm limit (mV)
+in1_crit_min bus voltage crit min alarm limit (mV)
+in1_max_alarm bus voltage max alarm limit exceeded
+in1_min_alarm bus voltage min alarm limit exceeded
+in1_crit_max_alarm bus voltage crit max alarm limit exceeded
+in1_crit_min_alarm bus voltage crit min alarm limit exceeded
+
+power1_input power measurement (uW)
+power1_input_highest power historical maximum reading (uW)
+power1_reset_history reset power history
+power1_max power max alarm limit (uW)
+power1_crit power crit alarm limit (uW)
+power1_max_alarm power max alarm limit exceeded
+power1_crit_alarm power crit alarm limit exceeded
+
+curr1_input current measurement (mA)
+
+update_interval data conversion time; affects number of samples used
+ to average results for shunt and bus voltages.
+
+General Remarks
+---------------
+
+The power and current registers in this chip require that the calibration
+register is programmed correctly before they are used. Normally this is expected
+to be done in the BIOS. In the absence of BIOS programming, the shunt resistor
+voltage can be provided using platform data. The driver uses platform data from
+the ina2xx driver for this purpose. If calibration register data is not provided
+via platform data, the driver checks if the calibration register has been
+programmed (ie has a value not equal to zero). If so, this value is retained.
+Otherwise, a default value reflecting a shunt resistor value of 10 mOhm is
+programmed into the calibration register.
+
+
+Output Pins
+-----------
+
+Output pin programming is a board feature which depends on the BIOS. It is
+outside the scope of a hardware monitoring driver to enable or disable output
+pins.
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
index 8386aadc0a82..c263740f0cba 100644
--- a/Documentation/hwmon/it87
+++ b/Documentation/hwmon/it87
@@ -30,6 +30,14 @@ Supported chips:
Prefix: 'it8728'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Not publicly available
+ * IT8771E
+ Prefix: 'it8771'
+ Addresses scanned: from Super I/O config space (8 I/O ports)
+ Datasheet: Not publicly available
+ * IT8772E
+ Prefix: 'it8772'
+ Addresses scanned: from Super I/O config space (8 I/O ports)
+ Datasheet: Not publicly available
* IT8782F
Prefix: 'it8782'
Addresses scanned: from Super I/O config space (8 I/O ports)
@@ -83,8 +91,8 @@ Description
-----------
This driver implements support for the IT8705F, IT8712F, IT8716F,
-IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8781F, IT8782F,
-IT8783E/F, and SiS950 chips.
+IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, IT8772E,
+IT8782F, IT8783E/F, and SiS950 chips.
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
joysticks and other miscellaneous stuff. For hardware monitoring, they
@@ -118,8 +126,8 @@ The IT8726F is just bit enhanced IT8716F with additional hardware
for AMD power sequencing. Therefore the chip will appear as IT8716F
to userspace applications.
-The IT8728F is considered compatible with the IT8721F, until a datasheet
-becomes available (hopefully.)
+The IT8728F, IT8771E, and IT8772E are considered compatible with the IT8721F,
+until a datasheet becomes available (hopefully.)
Temperatures are measured in degrees Celsius. An alarm is triggered once
when the Overtemperature Shutdown limit is crossed.
diff --git a/Documentation/hwmon/jc42 b/Documentation/hwmon/jc42
index 66ecb9fc8246..165077121238 100644
--- a/Documentation/hwmon/jc42
+++ b/Documentation/hwmon/jc42
@@ -17,12 +17,13 @@ Supported chips:
* Maxim MAX6604
Datasheets:
http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf
- * Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP9843
+ * Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP98244, MCP9843
Datasheets:
http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf
+ http://ww1.microchip.com/downloads/en/DeviceDoc/22327A.pdf
* NXP Semiconductors SE97, SE97B, SE98, SE98A
Datasheets:
http://www.nxp.com/documents/data_sheet/SE97.pdf
diff --git a/Documentation/hwmon/lm73 b/Documentation/hwmon/lm73
new file mode 100644
index 000000000000..8af059dcb642
--- /dev/null
+++ b/Documentation/hwmon/lm73
@@ -0,0 +1,90 @@
+Kernel driver lm73
+==================
+
+Supported chips:
+ * Texas Instruments LM73
+ Prefix: 'lm73'
+ Addresses scanned: I2C 0x48, 0x49, 0x4a, 0x4c, 0x4d, and 0x4e
+ Datasheet: Publicly available at the Texas Instruments website
+ http://www.ti.com/product/lm73
+
+Author: Guillaume Ligneul <guillaume.ligneul@gmail.com>
+Documentation: Chris Verges <kg4ysn@gmail.com>
+
+
+Description
+-----------
+
+The LM73 is a digital temperature sensor. All temperature values are
+given in degrees Celsius.
+
+Measurement Resolution Support
+------------------------------
+
+The LM73 supports four resolutions, defined in terms of degrees C per
+LSB: 0.25, 0.125, 0.0625, and 0.3125. Changing the resolution mode
+affects the conversion time of the LM73's analog-to-digital converter.
+From userspace, the desired resolution can be specified as a function of
+conversion time via the 'update_interval' sysfs attribute for the
+device. This attribute will normalize ranges of input values to the
+maximum times defined for the resolution in the datasheet.
+
+ Resolution Conv. Time Input Range
+ (C/LSB) (msec) (msec)
+ --------------------------------------
+ 0.25 14 0..14
+ 0.125 28 15..28
+ 0.0625 56 29..56
+ 0.03125 112 57..infinity
+ --------------------------------------
+
+The following examples show how the 'update_interval' attribute can be
+used to change the conversion time:
+
+ $ echo 0 > update_interval
+ $ cat update_interval
+ 14
+ $ cat temp1_input
+ 24250
+
+ $ echo 22 > update_interval
+ $ cat update_interval
+ 28
+ $ cat temp1_input
+ 24125
+
+ $ echo 56 > update_interval
+ $ cat update_interval
+ 56
+ $ cat temp1_input
+ 24062
+
+ $ echo 85 > update_interval
+ $ cat update_interval
+ 112
+ $ cat temp1_input
+ 24031
+
+As shown here, the lm73 driver automatically adjusts any user input for
+'update_interval' via a step function. Reading back the
+'update_interval' value after a write operation will confirm the
+conversion time actively in use.
+
+Mathematically, the resolution can be derived from the conversion time
+via the following function:
+
+ g(x) = 0.250 * [log(x/14) / log(2)]
+
+where 'x' is the output from 'update_interval' and 'g(x)' is the
+resolution in degrees C per LSB.
+
+Alarm Support
+-------------
+
+The LM73 features a simple over-temperature alarm mechanism. This
+feature is exposed via the sysfs attributes.
+
+The attributes 'temp1_max_alarm' and 'temp1_min_alarm' are flags
+provided by the LM73 that indicate whether the measured temperature has
+passed the 'temp1_max' and 'temp1_min' thresholds, respectively. These
+values _must_ be read to clear the registers on the LM73.
diff --git a/Documentation/hwmon/max34440 b/Documentation/hwmon/max34440
index 04482226db20..47651ff341ae 100644
--- a/Documentation/hwmon/max34440
+++ b/Documentation/hwmon/max34440
@@ -16,6 +16,16 @@ Supported chips:
Prefixes: 'max34446'
Addresses scanned: -
Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34446.pdf
+ * Maxim MAX34460
+ PMBus 12-Channel Voltage Monitor & Sequencer
+ Prefix: 'max34460'
+ Addresses scanned: -
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX34460.pdf
+ * Maxim MAX34461
+ PMBus 16-Channel Voltage Monitor & Sequencer
+ Prefix: 'max34461'
+ Addresses scanned: -
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX34461.pdf
Author: Guenter Roeck <guenter.roeck@ericsson.com>
@@ -26,6 +36,9 @@ Description
This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel
Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply Manager
and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data Logger.
+It also supports the MAX34460 and MAX34461 PMBus Voltage Monitor & Sequencers.
+The MAX34460 supports 12 voltage channels, and the MAX34461 supports 16 voltage
+channels.
The driver is a client driver to the core PMBus driver. Please see
Documentation/hwmon/pmbus for details on PMBus client drivers.
@@ -109,3 +122,6 @@ temp[1-8]_reset_history Write any value to reset history.
temp7 and temp8 attributes only exist for MAX34440.
MAX34446 only supports temp[1-3].
+
+MAX34460 supports attribute groups in[1-12] and temp[1-5].
+MAX34461 supports attribute groups in[1-16] and temp[1-5].
diff --git a/Documentation/hwmon/max6697 b/Documentation/hwmon/max6697
new file mode 100644
index 000000000000..6594177ededa
--- /dev/null
+++ b/Documentation/hwmon/max6697
@@ -0,0 +1,58 @@
+Kernel driver max6697
+=====================
+
+Supported chips:
+ * Maxim MAX6581
+ Prefix: 'max6581'
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6581.pdf
+ * Maxim MAX6602
+ Prefix: 'max6602'
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6602.pdf
+ * Maxim MAX6622
+ Prefix: 'max6622'
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6622.pdf
+ * Maxim MAX6636
+ Prefix: 'max6636'
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6636.pdf
+ * Maxim MAX6689
+ Prefix: 'max6689'
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6689.pdf
+ * Maxim MAX6693
+ Prefix: 'max6693'
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6693.pdf
+ * Maxim MAX6694
+ Prefix: 'max6694'
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6694.pdf
+ * Maxim MAX6697
+ Prefix: 'max6697'
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6697.pdf
+ * Maxim MAX6698
+ Prefix: 'max6698'
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6698.pdf
+ * Maxim MAX6699
+ Prefix: 'max6699'
+ Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6699.pdf
+
+Author:
+ Guenter Roeck <linux@roeck-us.net>
+
+Description
+-----------
+
+This driver implements support for several MAX6697 compatible temperature sensor
+chips. The chips support one local temperature sensor plus four, six, or seven
+remote temperature sensors. Remote temperature sensors are diode-connected
+thermal transitors, except for MAX6698 which supports three diode-connected
+thermal transistors plus three thermistors in addition to the local temperature
+sensor.
+
+The driver provides the following sysfs attributes. temp1 is the local (chip)
+temperature, temp[2..n] are remote temperatures. The actually supported
+per-channel attributes are chip type and channel dependent.
+
+tempX_input RO temperature
+tempX_max RW temperature maximum threshold
+tempX_max_alarm RO temperature maximum threshold alarm
+tempX_crit RW temperature critical threshold
+tempX_crit_alarm RO temperature critical threshold alarm
+tempX_fault RO temperature diode fault (remote sensors only)
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index 1f4dd855a299..79f8257dd790 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -722,14 +722,14 @@ add/subtract if it has been divided before the add/subtract.
What to do if a value is found to be invalid, depends on the type of the
sysfs attribute that is being set. If it is a continuous setting like a
tempX_max or inX_max attribute, then the value should be clamped to its
-limits using SENSORS_LIMIT(value, min_limit, max_limit). If it is not
-continuous like for example a tempX_type, then when an invalid value is
-written, -EINVAL should be returned.
+limits using clamp_val(value, min_limit, max_limit). If it is not continuous
+like for example a tempX_type, then when an invalid value is written,
+-EINVAL should be returned.
Example1, temp1_max, register is a signed 8 bit value (-128 - 127 degrees):
long v = simple_strtol(buf, NULL, 10) / 1000;
- v = SENSORS_LIMIT(v, -128, 127);
+ v = clamp_val(v, -128, 127);
/* write v to register */
Example2, fan divider setting, valid values 2, 4 and 8:
diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100
index a995b41724fd..3d924b6b59e9 100644
--- a/Documentation/hwmon/zl6100
+++ b/Documentation/hwmon/zl6100
@@ -121,12 +121,26 @@ in1_max_alarm Input voltage high alarm.
in1_lcrit_alarm Input voltage critical low alarm.
in1_crit_alarm Input voltage critical high alarm.
-in2_label "vout1"
-in2_input Measured output voltage.
-in2_lcrit Critical minimum output Voltage.
-in2_crit Critical maximum output voltage.
-in2_lcrit_alarm Critical output voltage critical low alarm.
-in2_crit_alarm Critical output voltage critical high alarm.
+in2_label "vmon"
+in2_input Measured voltage on VMON (ZL2004) or VDRV (ZL9101M,
+ ZL9117M) pin. Reported voltage is 16x the voltage on the
+ pin (adjusted internally by the chip).
+in2_lcrit Critical minumum VMON/VDRV Voltage.
+in2_crit Critical maximum VMON/VDRV voltage.
+in2_lcrit_alarm VMON/VDRV voltage critical low alarm.
+in2_crit_alarm VMON/VDRV voltage critical high alarm.
+
+ vmon attributes are supported on ZL2004, ZL9101M,
+ and ZL9117M only.
+
+inX_label "vout1"
+inX_input Measured output voltage.
+inX_lcrit Critical minimum output Voltage.
+inX_crit Critical maximum output voltage.
+inX_lcrit_alarm Critical output voltage critical low alarm.
+inX_crit_alarm Critical output voltage critical high alarm.
+
+ X is 3 for ZL2004, ZL9101M, and ZL9117M, 2 otherwise.
curr1_label "iout1"
curr1_input Measured output current.
diff --git a/Documentation/intel_txt.txt b/Documentation/intel_txt.txt
index 849de1a78e77..91d89c540709 100644
--- a/Documentation/intel_txt.txt
+++ b/Documentation/intel_txt.txt
@@ -192,7 +192,7 @@ grub.conf needs to be modified as follows:
The kernel option for enabling Intel TXT support is found under the
Security top-level menu and is called "Enable Intel(R) Trusted
-Execution Technology (TXT)". It is marked as EXPERIMENTAL and
+Execution Technology (TXT)". It is considered EXPERIMENTAL and
depends on the generic x86 support (to allow maximum flexibility in
kernel build options), since the tboot code will detect whether the
platform actually supports Intel TXT and thus whether any of the
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 2152b0e7237d..3210540f8bd3 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -179,7 +179,7 @@ Code Seq#(hex) Include File Comments
'V' C0 media/davinci/vpfe_capture.h conflict!
'V' C0 media/si4713.h conflict!
'W' 00-1F linux/watchdog.h conflict!
-'W' 00-1F linux/wanrouter.h conflict!
+'W' 00-1F linux/wanrouter.h conflict! (pre 3.9)
'W' 00-3F sound/asound.h conflict!
'X' all fs/xfs/xfs_fs.h conflict!
and fs/xfs/linux-2.6/xfs_ioctl32.h
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 14c3f4f1b617..5198b742fde1 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -1186,6 +1186,29 @@ When kbuild executes, the following steps are followed (roughly):
clean-files += *.dtb
DTC_FLAGS ?= -p 1024
+ dtc_cpp
+ This is just like dtc as describe above, except that the C pre-
+ processor is invoked upon the .dtsp file before compiling the result
+ with dtc.
+
+ In order for build dependencies to work, all files compiled using
+ dtc_cpp must use the C pre-processor's #include functionality and not
+ dtc's /include/ functionality.
+
+ Using the C pre-processor allows use of #define to create named
+ constants. In turn, the #defines will typically appear in a header
+ file, which may be shared with regular C code. Since the dtc language
+ represents a data structure rather than code in C syntax, similar
+ restrictions are placed on a header file included by a device tree
+ file as for a header file included by an assembly language file.
+ In particular, the C pre-processor is passed -x assembler-with-cpp,
+ which sets macro __ASSEMBLY__. __DTS__ is also set. These allow header
+ files to restrict their content to that compatible with device tree
+ source.
+
+ A central rule exists to create $(obj)/%.dtb from $(src)/%.dtsp;
+ architecture Makefiles do no need to explicitly write out that rule.
+
--- 6.8 Custom kbuild commands
When kbuild is executing with KBUILD_VERBOSE=0, then only a shorthand
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 6c723811c0a0..766087781ecd 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -594,6 +594,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
is selected automatically. Check
Documentation/kdump/kdump.txt for further details.
+ crashkernel_low=size[KMG]
+ [KNL, x86] parts under 4G.
+
crashkernel=range1:size1[,range2:size2,...][@offset]
[KNL] Same as above, but depends on the memory
in the running system. The syntax of range is
@@ -1039,16 +1042,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Claim all unknown PCI IDE storage controllers.
idle= [X86]
- Format: idle=poll, idle=mwait, idle=halt, idle=nomwait
+ Format: idle=poll, idle=halt, idle=nomwait
Poll forces a polling idle loop that can slightly
improve the performance of waking up a idle CPU, but
will use a lot of power and make the system run hot.
Not recommended.
- idle=mwait: On systems which support MONITOR/MWAIT but
- the kernel chose to not use it because it doesn't save
- as much power as a normal idle loop, use the
- MONITOR/MWAIT idle loop anyways. Performance should be
- the same as idle=poll.
idle=halt: Halt is forced to be used for CPU idle.
In such case C2/C3 won't be used again.
idle=nomwait: Disable mwait for CPU C-states
@@ -1131,6 +1129,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
0 disables intel_idle and fall back on acpi_idle.
1 to 6 specify maximum depth of C-state.
+ intel_pstate= [X86]
+ disable
+ Do not enable intel_pstate as the default
+ scaling driver for the supported processors
+
intremap= [X86-64, Intel-IOMMU]
on enable Interrupt Remapping (default)
off disable Interrupt Remapping
@@ -1637,6 +1640,42 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
that the amount of memory usable for all allocations
is not too small.
+ movablemem_map=acpi
+ [KNL,X86,IA-64,PPC] This parameter is similar to
+ memmap except it specifies the memory map of
+ ZONE_MOVABLE.
+ This option inform the kernel to use Hot Pluggable bit
+ in flags from SRAT from ACPI BIOS to determine which
+ memory devices could be hotplugged. The corresponding
+ memory ranges will be set as ZONE_MOVABLE.
+ NOTE: Whatever node the kernel resides in will always
+ be un-hotpluggable.
+
+ movablemem_map=nn[KMG]@ss[KMG]
+ [KNL,X86,IA-64,PPC] This parameter is similar to
+ memmap except it specifies the memory map of
+ ZONE_MOVABLE.
+ If user specifies memory ranges, the info in SRAT will
+ be ingored. And it works like the following:
+ - If more ranges are all within one node, then from
+ lowest ss to the end of the node will be ZONE_MOVABLE.
+ - If a range is within a node, then from ss to the end
+ of the node will be ZONE_MOVABLE.
+ - If a range covers two or more nodes, then from ss to
+ the end of the 1st node will be ZONE_MOVABLE, and all
+ the rest nodes will only have ZONE_MOVABLE.
+ If memmap is specified at the same time, the
+ movablemem_map will be limited within the memmap
+ areas. If kernelcore or movablecore is also specified,
+ movablemem_map will have higher priority to be
+ satisfied. So the administrator should be careful that
+ the amount of movablemem_map areas are not too large.
+ Otherwise kernel won't have enough memory to start.
+ NOTE: We don't stop users specifying the node the
+ kernel resides in as hotpluggable so that this
+ option can be used as a workaround of firmware
+ bugs.
+
MTD_Partition= [MTD]
Format: <name>,<region-number>,<size>,<offset>
@@ -1886,10 +1925,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
wfi(ARM) instruction doesn't work correctly and not to
use it. This is also useful when using JTAG debugger.
- no-hlt [BUGS=X86-32] Tells the kernel that the hlt
- instruction doesn't work correctly and not to
- use it.
-
no_file_caps Tells the kernel not to honor file capabilities. The
only way then for a file to be executed with privilege
is to be setuid root or executed by root.
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index 9d666828915a..cf7bc6cb9719 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -1398,7 +1398,7 @@ Sysfs notes:
EXPERIMENTAL: UWB
-----------------
-This feature is marked EXPERIMENTAL because it has not been extensively
+This feature is considered EXPERIMENTAL because it has not been extensively
tested and validated in various ThinkPad models yet. The feature may not
work as expected. USE WITH CAUTION! To use this feature, you need to supply
the experimental=1 parameter when loading the module.
diff --git a/Documentation/lockstat.txt b/Documentation/lockstat.txt
index cef00d42ed5b..dd2f7b26ca30 100644
--- a/Documentation/lockstat.txt
+++ b/Documentation/lockstat.txt
@@ -65,7 +65,7 @@ that had to wait on lock acquisition.
- CONFIGURATION
-Lock statistics are enabled via CONFIG_LOCK_STATS.
+Lock statistics are enabled via CONFIG_LOCK_STAT.
- USAGE
diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt
index 82761a31d64d..76d80a64bbe1 100644
--- a/Documentation/magic-number.txt
+++ b/Documentation/magic-number.txt
@@ -122,7 +122,7 @@ SLAB_C_MAGIC 0x4f17a36d kmem_cache mm/slab.c
COW_MAGIC 0x4f4f4f4d cow_header_v1 arch/um/drivers/ubd_user.c
I810_CARD_MAGIC 0x5072696E i810_card sound/oss/i810_audio.c
TRIDENT_CARD_MAGIC 0x5072696E trident_card sound/oss/trident.c
-ROUTER_MAGIC 0x524d4157 wan_device include/linux/wanrouter.h
+ROUTER_MAGIC 0x524d4157 wan_device [in wanrouter.h pre 3.9]
SCC_MAGIC 0x52696368 gs_port drivers/char/scc.h
SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c
GDA_MAGIC 0x58464552 gda arch/mips/include/asm/sn/gda.h
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 802875413873..77bd0a42f19d 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -336,7 +336,7 @@ Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must
be identical for all nested calls to the function.
media_entity_pipeline_start() may return an error. In that case, it will
-clean up any the changes it did by itself.
+clean up any of the changes it did by itself.
When stopping the stream, drivers must notify the entities with
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index 3c4e1b3b80a1..fa5d8a9ae205 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -1685,6 +1685,7 @@ explicit lock operations, described later). These include:
xchg();
cmpxchg();
+ atomic_xchg();
atomic_cmpxchg();
atomic_inc_return();
atomic_dec_return();
diff --git a/Documentation/namespaces/resource-control.txt b/Documentation/namespaces/resource-control.txt
new file mode 100644
index 000000000000..abc13c394738
--- /dev/null
+++ b/Documentation/namespaces/resource-control.txt
@@ -0,0 +1,14 @@
+There are a lot of kinds of objects in the kernel that don't have
+individual limits or that have limits that are ineffective when a set
+of processes is allowed to switch user ids. With user namespaces
+enabled in a kernel for people who don't trust their users or their
+users programs to play nice this problems becomes more acute.
+
+Therefore it is recommended that memory control groups be enabled in
+kernels that enable user namespaces, and it is further recommended
+that userspace configure memory control groups to limit how much
+memory user's they don't trust to play nice can use.
+
+Memory control groups can be configured by installing the libcgroup
+package present on most distros editing /etc/cgrules.conf,
+/etc/cgconfig.conf and setting up libpam-cgroup.
diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
index 2cc3c7733a2f..258d9b92c36f 100644
--- a/Documentation/networking/00-INDEX
+++ b/Documentation/networking/00-INDEX
@@ -52,8 +52,6 @@ de4x5.txt
- the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver
decnet.txt
- info on using the DECnet networking layer in Linux.
-depca.txt
- - the Digital DEPCA/EtherWORKS DE1?? and DE2?? LANCE Ethernet driver
dl2k.txt
- README for D-Link DL2000-based Gigabit Ethernet Adapters (dl2k.ko).
dm9000.txt
@@ -72,8 +70,6 @@ e1000e.txt
- README for the Intel Gigabit Ethernet Driver (e1000e).
eql.txt
- serial IP load balancing
-ewrk3.txt
- - the Digital EtherWORKS 3 DE203/4/5 Ethernet driver
fib_trie.txt
- Level Compressed Trie (LC-trie) notes: a structure for routing.
filter.txt
@@ -126,8 +122,6 @@ ltpc.txt
- the Apple or Farallon LocalTalk PC card driver
mac80211-injection.txt
- HOWTO use packet injection with mac80211
-multicast.txt
- - Behaviour of cards under Multicast
multiqueue.txt
- HOWTO for multiqueue network device support.
netconsole.txt
diff --git a/Documentation/networking/DLINK.txt b/Documentation/networking/DLINK.txt
deleted file mode 100644
index 55d24433d151..000000000000
--- a/Documentation/networking/DLINK.txt
+++ /dev/null
@@ -1,203 +0,0 @@
-Released 1994-06-13
-
-
- CONTENTS:
-
- 1. Introduction.
- 2. License.
- 3. Files in this release.
- 4. Installation.
- 5. Problems and tuning.
- 6. Using the drivers with earlier releases.
- 7. Acknowledgments.
-
-
- 1. INTRODUCTION.
-
- This is a set of Ethernet drivers for the D-Link DE-600/DE-620
- pocket adapters, for the parallel port on a Linux based machine.
- Some adapter "clones" will also work. Xircom is _not_ a clone...
- These drivers _can_ be used as loadable modules,
- and were developed for use on Linux 1.1.13 and above.
- For use on Linux 1.0.X, or earlier releases, see below.
-
- I have used these drivers for NFS, ftp, telnet and X-clients on
- remote machines. Transmissions with ftp seems to work as
- good as can be expected (i.e. > 80k bytes/sec) from a
- parallel port...:-) Receive speeds will be about 60-80% of this.
- Depending on your machine, somewhat higher speeds can be achieved.
-
- All comments/fixes to Bjorn Ekwall (bj0rn@blox.se).
-
-
- 2. LICENSE.
-
- This program is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 2, or (at your option) any later version.
-
- This program is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied
- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
- 02139, USA.
-
-
- 3. FILES IN THIS RELEASE.
-
- README.DLINK This file.
- de600.c The Source (may it be with You :-) for the DE-600
- de620.c ditto for the DE-620
- de620.h Macros for de620.c
-
- If you are upgrading from the d-link tar release, there will
- also be a "dlink-patches" file that will patch Linux 1.1.18:
- linux/drivers/net/Makefile
- linux/drivers/net/CONFIG
- linux/drivers/net/MODULES
- linux/drivers/net/Space.c
- linux/config.in
- Apply the patch by:
- "cd /usr/src; patch -p0 < linux/drivers/net/dlink-patches"
- The old source, "linux/drivers/net/d_link.c", can be removed.
-
-
- 4. INSTALLATION.
-
- o Get the latest net binaries, according to current net.wisdom.
-
- o Read the NET-2 and Ethernet HOWTOs and modify your setup.
-
- o If your parallel port has a strange address or irq,
- modify "linux/drivers/net/CONFIG" accordingly, or adjust
- the parameters in the "tuning" section in the sources.
-
- If you are going to use the drivers as loadable modules, do _not_
- enable them while doing "make config", but instead make sure that
- the drivers are included in "linux/drivers/net/MODULES".
-
- If you are _not_ going to use the driver(s) as loadable modules,
- but instead have them included in the kernel, remember to enable
- the drivers while doing "make config".
-
- o To include networking and DE600/DE620 support in your kernel:
- # cd /linux
- (as modules:)
- # make config (answer yes on CONFIG_NET and CONFIG_INET)
- (else included in the kernel:)
- # make config (answer yes on CONFIG _NET, _INET and _DE600 or _DE620)
- # make clean
- # make zImage (or whatever magic you usually do)
-
- o I use lilo to boot multiple kernels, so that I at least
- can have one working kernel :-). If you do too, append
- these lines to /etc/lilo/config:
-
- image = /linux/zImage
- label = newlinux
- root = /dev/hda2 (or whatever YOU have...)
-
- # /etc/lilo/install
-
- o Do "sync" and reboot the new kernel with a D-Link
- DE-600/DE-620 pocket adapter connected.
-
- o The adapter can be configured with ifconfig eth?
- where the actual number is decided by the kernel
- when the drivers are initialized.
-
-
- 5. "PROBLEMS" AND TUNING,
-
- o If you see error messages from the driver, and if the traffic
- stops on the adapter, try to do "ifconfig" and "route" once
- more, just as in "rc.inet1". This should take care of most
- problems, including effects from power loss, or adapters that
- aren't connected to the printer port in some way or another.
- You can somewhat change the behaviour by enabling/disabling
- the macro SHUTDOWN_WHEN_LOST in the "tuning" section.
- For the DE-600 there is another macro, CHECK_LOST_DE600,
- that you might want to read about in the "tuning" section.
-
- o Some machines have trouble handling the parallel port and
- the adapter at high speed. If you experience problems:
-
- DE-600:
- - The adapter is not recognized at boot, i.e. an Ethernet
- address of 00:80:c8:... is not shown, try to add another
- "; SLOW_DOWN_IO"
- at DE600_SLOW_DOWN in the "tuning" section. As a last resort,
- uncomment: "#define REALLY_SLOW_IO" (see <asm/io.h> for hints).
-
- - You experience "timeout" messages: first try to add another
- "; SLOW_DOWN_IO"
- at DE600_SLOW_DOWN in the "tuning" section, _then_ try to
- increase the value (original value: 5) at
- "if (tickssofar < 5)" near line 422.
-
- DE-620:
- - Your parallel port might be "sluggish". To cater for
- this, there are the macros LOWSPEED and READ_DELAY/WRITE_DELAY
- in the "tuning" section. Your first step should be to enable
- LOWSPEED, and after that you can "tune" the XXX_DELAY values.
-
- o If the adapter _is_ recognized at boot but you get messages
- about "Network Unreachable", then the problem is probably
- _not_ with the driver. Check your net configuration instead
- (ifconfig and route) in "rc.inet1".
-
- o There is some rudimentary support for debugging, look at
- the source. Use "-DDE600_DEBUG=3" or "-DDE620_DEBUG=3"
- when compiling, or include it in "linux/drivers/net/CONFIG".
- IF YOU HAVE PROBLEMS YOU CAN'T SOLVE: PLEASE COMPILE THE DRIVER
- WITH DEBUGGING ENABLED, AND SEND ME THE RESULTING OUTPUT!
-
-
- 6. USING THE DRIVERS WITH EARLIER RELEASES.
-
- The later 1.1.X releases of the Linux kernel include some
- changes in the networking layer (a.k.a. NET3). This affects
- these drivers in a few places. The hints that follow are
- _not_ tested by me, since I don't have the disk space to keep
- all releases on-line.
- Known needed changes to date:
- - release patchfile: some patches will fail, but they should
- be easy to apply "by hand", since they are trivial.
- (Space.c: d_link_init() is now called de600_probe())
- - de600.c: change "mark_bh(NET_BH)" to "mark_bh(INET_BH)".
- - de620.c: (maybe) change the code around "netif_rx(skb);" to be
- similar to the code around "dev_rint(...)" in de600.c
-
-
- 7. ACKNOWLEDGMENTS.
-
- These drivers wouldn't have been done without the base
- (and support) from Ross Biro, and D-Link Systems Inc.
- The driver relies upon GPL-ed source from D-Link Systems Inc.
- and from Russel Nelson at Crynwr Software <nelson@crynwr.com>.
-
- Additional input also from:
- Donald Becker <becker@super.org>, Alan Cox <A.Cox@swansea.ac.uk>
- and Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
-
- DE-600 alpha release primary victim^H^H^H^H^H^Htester:
- - Erik Proper <erikp@cs.kun.nl>.
- Good input also from several users, most notably
- - Mark Burton <markb@ordern.demon.co.uk>.
-
- DE-620 alpha release victims^H^H^H^H^H^H^Htesters:
- - J. Joshua Kopper <kopper@rtsg.mot.com>
- - Olav Kvittem <Olav.Kvittem@uninett.no>
- - Germano Caronni <caronni@nessie.cs.id.ethz.ch>
- - Jeremy Fitzhardinge <jeremy@suite.sw.oz.au>
-
-
- Happy hacking!
-
- Bjorn Ekwall == bj0rn@blox.se
diff --git a/Documentation/networking/LICENSE.qlcnic b/Documentation/networking/LICENSE.qlcnic
index e7fb2c6023bc..2ae3b64983ab 100644
--- a/Documentation/networking/LICENSE.qlcnic
+++ b/Documentation/networking/LICENSE.qlcnic
@@ -1,4 +1,4 @@
-Copyright (c) 2009-2011 QLogic Corporation
+Copyright (c) 2009-2013 QLogic Corporation
QLogic Linux qlcnic NIC Driver
You may modify and redistribute the device driver code under the
diff --git a/Documentation/networking/cs89x0.txt b/Documentation/networking/cs89x0.txt
index c725d33b316f..0e190180eec8 100644
--- a/Documentation/networking/cs89x0.txt
+++ b/Documentation/networking/cs89x0.txt
@@ -36,7 +36,6 @@ TABLE OF CONTENTS
4.1 Compiling the Driver as a Loadable Module
4.2 Compiling the driver to support memory mode
4.3 Compiling the driver to support Rx DMA
- 4.4 Compiling the Driver into the Kernel
5.0 TESTING AND TROUBLESHOOTING
5.1 Known Defects and Limitations
@@ -364,84 +363,6 @@ The compile-time optionality for DMA was removed in the 2.3 kernel
series. DMA support is now unconditionally part of the driver. It is
enabled by the 'use_dma=1' module option.
-4.4 COMPILING THE DRIVER INTO THE KERNEL
-
-If your Linux distribution already has support for the cs89x0 driver
-then simply copy the source file to the /usr/src/linux/drivers/net
-directory to replace the original ones and run the make utility to
-rebuild the kernel. See Step 3 for rebuilding the kernel.
-
-If your Linux does not include the cs89x0 driver, you need to edit three
-configuration files, copy the source file to the /usr/src/linux/drivers/net
-directory, and then run the make utility to rebuild the kernel.
-
-1. Edit the following configuration files by adding the statements as
-indicated. (When possible, try to locate the added text to the section of the
-file containing similar statements).
-
-
-a.) In /usr/src/linux/drivers/net/Config.in, add:
-
-tristate 'CS89x0 support' CONFIG_CS89x0
-
-Example:
-
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
- fi
-
- tristate 'CS89x0 support' CONFIG_CS89x0
-
- tristate 'NE2000/NE1000 support' CONFIG_NE2000
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'NI5210 support' CONFIG_NI52
-
-
-b.) In /usr/src/linux/drivers/net/Makefile, add the following lines:
-
-ifeq ($(CONFIG_CS89x0),y)
-L_OBJS += cs89x0.o
-else
- ifeq ($(CONFIG_CS89x0),m)
- M_OBJS += cs89x0.o
- endif
-endif
-
-
-c.) In /linux/drivers/net/Space.c file, add the line:
-
-extern int cs89x0_probe(struct device *dev);
-
-
-Example:
-
- extern int ultra_probe(struct device *dev);
- extern int wd_probe(struct device *dev);
- extern int el2_probe(struct device *dev);
-
- extern int cs89x0_probe(struct device *dev);
-
- extern int ne_probe(struct device *dev);
- extern int hp_probe(struct device *dev);
- extern int hp_plus_probe(struct device *dev);
-
-
-Also add:
-
- #ifdef CONFIG_CS89x0
- { cs89x0_probe,0 },
- #endif
-
-
-2.) Copy the driver source files (cs89x0.c and cs89x0.h)
-into the /usr/src/linux/drivers/net directory.
-
-
-3.) Go to /usr/src/linux directory and run 'make config' followed by 'make'
-(or make bzImage) to rebuild the kernel.
-
-4.) Use the DOS 'setup' utility to disable plug and play on the NIC.
-
5.0 TESTING AND TROUBLESHOOTING
===============================================================================
diff --git a/Documentation/networking/depca.txt b/Documentation/networking/depca.txt
deleted file mode 100644
index 24c6b26e5658..000000000000
--- a/Documentation/networking/depca.txt
+++ /dev/null
@@ -1,92 +0,0 @@
-
-DE10x
-=====
-
-Memory Addresses:
-
- SW1 SW2 SW3 SW4
-64K on on on on d0000 dbfff
- off on on on c0000 cbfff
- off off on on e0000 ebfff
-
-32K on on off on d8000 dbfff
- off on off on c8000 cbfff
- off off off on e8000 ebfff
-
-DBR ROM on on dc000 dffff
- off on cc000 cffff
- off off ec000 effff
-
-Note that the 2K mode is set by SW3/SW4 on/off or off/off. Address
-assignment is through the RBSA register.
-
-I/O Address:
- SW5
-0x300 on
-0x200 off
-
-Remote Boot:
- SW6
-Disable on
-Enable off
-
-Remote Boot Timeout:
- SW7
-2.5min on
-30s off
-
-IRQ:
- SW8 SW9 SW10 SW11 SW12
-2 on off off off off
-3 off on off off off
-4 off off on off off
-5 off off off on off
-7 off off off off on
-
-DE20x
-=====
-
-Memory Size:
-
- SW3 SW4
-64K on on
-32K off on
-2K on off
-2K off off
-
-Start Addresses:
-
- SW1 SW2 SW3 SW4
-64K on on on on c0000 cffff
- on off on on d0000 dffff
- off on on on e0000 effff
-
-32K on on off off c8000 cffff
- on off off off d8000 dffff
- off on off off e8000 effff
-
-Illegal off off - - - -
-
-I/O Address:
- SW5
-0x300 on
-0x200 off
-
-Remote Boot:
- SW6
-Disable on
-Enable off
-
-Remote Boot Timeout:
- SW7
-2.5min on
-30s off
-
-IRQ:
- SW8 SW9 SW10 SW11 SW12
-5 on off off off off
-9 off on off off off
-10 off off on off off
-11 off off off on off
-15 off off off off on
-
diff --git a/Documentation/networking/ewrk3.txt b/Documentation/networking/ewrk3.txt
deleted file mode 100644
index 90e9e5f16e6b..000000000000
--- a/Documentation/networking/ewrk3.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-The EtherWORKS 3 driver in this distribution is designed to work with all
-kernels > 1.1.33 (approx) and includes tools in the 'ewrk3tools'
-subdirectory to allow set up of the card, similar to the MSDOS
-'NICSETUP.EXE' tools provided on the DOS drivers disk (type 'make' in that
-subdirectory to make the tools).
-
-The supported cards are DE203, DE204 and DE205. All other cards are NOT
-supported - refer to 'depca.c' for running the LANCE based network cards and
-'de4x5.c' for the DIGITAL Semiconductor PCI chip based adapters from
-Digital.
-
-The ability to load this driver as a loadable module has been included and
-used extensively during the driver development (to save those long reboot
-sequences). To utilise this ability, you have to do 8 things:
-
- 0) have a copy of the loadable modules code installed on your system.
- 1) copy ewrk3.c from the /linux/drivers/net directory to your favourite
- temporary directory.
- 2) edit the source code near line 1898 to reflect the I/O address and
- IRQ you're using.
- 3) compile ewrk3.c, but include -DMODULE in the command line to ensure
- that the correct bits are compiled (see end of source code).
- 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
- kernel with the ewrk3 configuration turned off and reboot.
- 5) insmod ewrk3.o
- [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
- [Adam Kropelin: Multiple cards now supported by irq=x1,x2 io=y1,y2]
- 6) run the net startup bits for your new eth?? interface manually
- (usually /etc/rc.inet[12] at boot time).
- 7) enjoy!
-
- Note that autoprobing is not allowed in loadable modules - the system is
- already up and running and you're messing with interrupts.
-
- To unload a module, turn off the associated interface
- 'ifconfig eth?? down' then 'rmmod ewrk3'.
-
-The performance we've achieved so far has been measured through the 'ttcp'
-tool at 975kB/s. This measures the total TCP stack performance which
-includes the card, so don't expect to get much nearer the 1.25MB/s
-theoretical Ethernet rate.
-
-
-Enjoy!
-
-Dave
diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt
index bbf2005270b5..cdb3e40b9d14 100644
--- a/Documentation/networking/filter.txt
+++ b/Documentation/networking/filter.txt
@@ -17,12 +17,12 @@ creating filters.
LSF is much simpler than BPF. One does not have to worry about
devices or anything like that. You simply create your filter
-code, send it to the kernel via the SO_ATTACH_FILTER ioctl and
+code, send it to the kernel via the SO_ATTACH_FILTER option and
if your filter code passes the kernel check on it, you then
immediately begin filtering data on that socket.
You can also detach filters from your socket via the
-SO_DETACH_FILTER ioctl. This will probably not be used much
+SO_DETACH_FILTER option. This will probably not be used much
since when you close a socket that has a filter on it the
filter is automagically removed. The other less common case
may be adding a different filter on the same socket where you had another
@@ -31,12 +31,19 @@ the old one and placing your new one in its place, assuming your
filter has passed the checks, otherwise if it fails the old filter
will remain on that socket.
+SO_LOCK_FILTER option allows to lock the filter attached to a
+socket. Once set, a filter cannot be removed or changed. This allows
+one process to setup a socket, attach a filter, lock it then drop
+privileges and be assured that the filter will be kept until the
+socket is closed.
+
Examples
========
Ioctls-
setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter));
setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, &value, sizeof(value));
+setsockopt(sockfd, SOL_SOCKET, SO_LOCK_FILTER, &value, sizeof(value));
See the BSD bpf.4 manpage and the BSD Packet Filter paper written by
Steven McCanne and Van Jacobson of Lawrence Berkeley Laboratory.
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index dbca66182089..dc2dc87d2557 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -26,6 +26,11 @@ route/max_size - INTEGER
Maximum number of routes allowed in the kernel. Increase
this when using large numbers of interfaces and/or routes.
+neigh/default/gc_thresh1 - INTEGER
+ Minimum number of entries to keep. Garbage collector will not
+ purge entries if there are fewer than this number.
+ Default: 256
+
neigh/default/gc_thresh3 - INTEGER
Maximum number of neighbor entries allowed. Increase this
when using large numbers of interfaces and when communicating
@@ -125,17 +130,6 @@ somaxconn - INTEGER
Defaults to 128. See also tcp_max_syn_backlog for additional tuning
for TCP sockets.
-tcp_abc - INTEGER
- Controls Appropriate Byte Count (ABC) defined in RFC3465.
- ABC is a way of increasing congestion window (cwnd) more slowly
- in response to partial acknowledgments.
- Possible values are:
- 0 increase cwnd once per acknowledgment (no ABC)
- 1 increase cwnd once per acknowledgment of full sized segment
- 2 allow increase cwnd by two if acknowledgment is
- of two segments to compensate for delayed acknowledgments.
- Default: 0 (off)
-
tcp_abort_on_overflow - BOOLEAN
If listening service is too slow to accept new connections,
reset them. Default state is FALSE. It means that if overflow
@@ -214,7 +208,8 @@ tcp_ecn - INTEGER
congestion before having to drop packets.
Possible values are:
0 Disable ECN. Neither initiate nor accept ECN.
- 1 Always request ECN on outgoing connection attempts.
+ 1 Enable ECN when requested by incoming connections and
+ also request ECN on outgoing connection attempts.
2 Enable ECN when requested by incoming connections
but do not request ECN on outgoing connections.
Default: 2
diff --git a/Documentation/networking/multicast.txt b/Documentation/networking/multicast.txt
deleted file mode 100644
index b06c8c69266f..000000000000
--- a/Documentation/networking/multicast.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-Behaviour of Cards Under Multicast
-==================================
-
-This is how they currently behave, not what the hardware can do--for example,
-the Lance driver doesn't use its filter, even though the code for loading
-it is in the DEC Lance-based driver.
-
-The following are requirements for multicasting
------------------------------------------------
-AppleTalk Multicast hardware filtering not important but
- avoid cards only doing promisc
-IP-Multicast Multicast hardware filters really help
-IP-MRoute AllMulti hardware filters are of no help
-
-
-Board Multicast AllMulti Promisc Filter
-------------------------------------------------------------------------
-3c501 YES YES YES Software
-3c503 YES YES YES Hardware
-3c505 YES NO YES Hardware
-3c507 NO NO NO N/A
-3c509 YES YES YES Software
-3c59x YES YES YES Software
-ac3200 YES YES YES Hardware
-apricot YES PROMISC YES Hardware
-arcnet NO NO NO N/A
-at1700 PROMISC PROMISC YES Software
-atp PROMISC PROMISC YES Software
-cs89x0 YES YES YES Software
-de4x5 YES YES YES Hardware
-de600 NO NO NO N/A
-de620 PROMISC PROMISC YES Software
-depca YES PROMISC YES Hardware
-dmfe YES YES YES Software(*)
-e2100 YES YES YES Hardware
-eepro YES PROMISC YES Hardware
-eexpress NO NO NO N/A
-ewrk3 YES PROMISC YES Hardware
-hp-plus YES YES YES Hardware
-hp YES YES YES Hardware
-hp100 YES YES YES Hardware
-ibmtr NO NO NO N/A
-ioc3-eth YES YES YES Hardware
-lance YES YES YES Software(#)
-ne YES YES YES Hardware
-ni52 <------------------ Buggy ------------------>
-ni65 YES YES YES Software(#)
-seeq NO NO NO N/A
-sgiseek <------------------ Buggy ------------------>
-smc-ultra YES YES YES Hardware
-sunlance YES YES YES Hardware
-tulip YES YES YES Hardware
-wavelan YES PROMISC YES Hardware
-wd YES YES YES Hardware
-xirc2ps_cs YES YES YES Hardware
-znet YES YES YES Software
-
-
-PROMISC = This multicast mode is in fact promiscuous mode. Avoid using
-cards who go PROMISC on any multicast in a multicast kernel.
-
-(#) = Hardware multicast support is not used yet.
-(*) = Hardware support for Davicom 9132 chipset only.
diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt
index 2e9e0ae2cd45..a5d574a9ae09 100644
--- a/Documentation/networking/netconsole.txt
+++ b/Documentation/networking/netconsole.txt
@@ -1,9 +1,10 @@
started by Ingo Molnar <mingo@redhat.com>, 2001.09.17
2.6 port and netpoll api by Matt Mackall <mpm@selenic.com>, Sep 9 2003
+IPv6 support by Cong Wang <xiyou.wangcong@gmail.com>, Jan 1 2013
Please send bug reports to Matt Mackall <mpm@selenic.com>
-and Satyam Sharma <satyam.sharma@gmail.com>
+Satyam Sharma <satyam.sharma@gmail.com>, and Cong Wang <xiyou.wangcong@gmail.com>
Introduction:
=============
@@ -41,6 +42,10 @@ Examples:
insmod netconsole netconsole=@/,@10.0.0.2/
+ or using IPv6
+
+ insmod netconsole netconsole=@/,@fd00:1:2:3::1/
+
It also supports logging to multiple remote agents by specifying
parameters for the multiple agents separated by semicolons and the
complete string enclosed in "quotes", thusly:
diff --git a/Documentation/networking/nf_conntrack-sysctl.txt b/Documentation/networking/nf_conntrack-sysctl.txt
new file mode 100644
index 000000000000..70da5086153d
--- /dev/null
+++ b/Documentation/networking/nf_conntrack-sysctl.txt
@@ -0,0 +1,176 @@
+/proc/sys/net/netfilter/nf_conntrack_* Variables:
+
+nf_conntrack_acct - BOOLEAN
+ 0 - disabled (default)
+ not 0 - enabled
+
+ Enable connection tracking flow accounting. 64-bit byte and packet
+ counters per flow are added.
+
+nf_conntrack_buckets - INTEGER (read-only)
+ Size of hash table. If not specified as parameter during module
+ loading, the default size is calculated by dividing total memory
+ by 16384 to determine the number of buckets but the hash table will
+ never have fewer than 32 or more than 16384 buckets.
+
+nf_conntrack_checksum - BOOLEAN
+ 0 - disabled
+ not 0 - enabled (default)
+
+ Verify checksum of incoming packets. Packets with bad checksums are
+ in INVALID state. If this is enabled, such packets will not be
+ considered for connection tracking.
+
+nf_conntrack_count - INTEGER (read-only)
+ Number of currently allocated flow entries.
+
+nf_conntrack_events - BOOLEAN
+ 0 - disabled
+ not 0 - enabled (default)
+
+ If this option is enabled, the connection tracking code will
+ provide userspace with connection tracking events via ctnetlink.
+
+nf_conntrack_events_retry_timeout - INTEGER (seconds)
+ default 15
+
+ This option is only relevant when "reliable connection tracking
+ events" are used. Normally, ctnetlink is "lossy", that is,
+ events are normally dropped when userspace listeners can't keep up.
+
+ Userspace can request "reliable event mode". When this mode is
+ active, the conntrack will only be destroyed after the event was
+ delivered. If event delivery fails, the kernel periodically
+ re-tries to send the event to userspace.
+
+ This is the maximum interval the kernel should use when re-trying
+ to deliver the destroy event.
+
+ A higher number means there will be fewer delivery retries and it
+ will take longer for a backlog to be processed.
+
+nf_conntrack_expect_max - INTEGER
+ Maximum size of expectation table. Default value is
+ nf_conntrack_buckets / 256. Minimum is 1.
+
+nf_conntrack_frag6_high_thresh - INTEGER
+ default 262144
+
+ Maximum memory used to reassemble IPv6 fragments. When
+ nf_conntrack_frag6_high_thresh bytes of memory is allocated for this
+ purpose, the fragment handler will toss packets until
+ nf_conntrack_frag6_low_thresh is reached.
+
+nf_conntrack_frag6_low_thresh - INTEGER
+ default 196608
+
+ See nf_conntrack_frag6_low_thresh
+
+nf_conntrack_frag6_timeout - INTEGER (seconds)
+ default 60
+
+ Time to keep an IPv6 fragment in memory.
+
+nf_conntrack_generic_timeout - INTEGER (seconds)
+ default 600
+
+ Default for generic timeout. This refers to layer 4 unknown/unsupported
+ protocols.
+
+nf_conntrack_helper - BOOLEAN
+ 0 - disabled
+ not 0 - enabled (default)
+
+ Enable automatic conntrack helper assignment.
+
+nf_conntrack_icmp_timeout - INTEGER (seconds)
+ default 30
+
+ Default for ICMP timeout.
+
+nf_conntrack_icmpv6_timeout - INTEGER (seconds)
+ default 30
+
+ Default for ICMP6 timeout.
+
+nf_conntrack_log_invalid - INTEGER
+ 0 - disable (default)
+ 1 - log ICMP packets
+ 6 - log TCP packets
+ 17 - log UDP packets
+ 33 - log DCCP packets
+ 41 - log ICMPv6 packets
+ 136 - log UDPLITE packets
+ 255 - log packets of any protocol
+
+ Log invalid packets of a type specified by value.
+
+nf_conntrack_max - INTEGER
+ Size of connection tracking table. Default value is
+ nf_conntrack_buckets value * 4.
+
+nf_conntrack_tcp_be_liberal - BOOLEAN
+ 0 - disabled (default)
+ not 0 - enabled
+
+ Be conservative in what you do, be liberal in what you accept from others.
+ If it's non-zero, we mark only out of window RST segments as INVALID.
+
+nf_conntrack_tcp_loose - BOOLEAN
+ 0 - disabled
+ not 0 - enabled (default)
+
+ If it is set to zero, we disable picking up already established
+ connections.
+
+nf_conntrack_tcp_max_retrans - INTEGER
+ default 3
+
+ Maximum number of packets that can be retransmitted without
+ received an (acceptable) ACK from the destination. If this number
+ is reached, a shorter timer will be started.
+
+nf_conntrack_tcp_timeout_close - INTEGER (seconds)
+ default 10
+
+nf_conntrack_tcp_timeout_close_wait - INTEGER (seconds)
+ default 60
+
+nf_conntrack_tcp_timeout_established - INTEGER (seconds)
+ default 432000 (5 days)
+
+nf_conntrack_tcp_timeout_fin_wait - INTEGER (seconds)
+ default 120
+
+nf_conntrack_tcp_timeout_last_ack - INTEGER (seconds)
+ default 30
+
+nf_conntrack_tcp_timeout_max_retrans - INTEGER (seconds)
+ default 300
+
+nf_conntrack_tcp_timeout_syn_recv - INTEGER (seconds)
+ default 60
+
+nf_conntrack_tcp_timeout_syn_sent - INTEGER (seconds)
+ default 120
+
+nf_conntrack_tcp_timeout_time_wait - INTEGER (seconds)
+ default 120
+
+nf_conntrack_tcp_timeout_unacknowledged - INTEGER (seconds)
+ default 300
+
+nf_conntrack_timestamp - BOOLEAN
+ 0 - disabled (default)
+ not 0 - enabled
+
+ Enable connection tracking flow timestamping.
+
+nf_conntrack_udp_timeout - INTEGER (seconds)
+ default 30
+
+nf_conntrack_udp_timeout_stream2 - INTEGER (seconds)
+ default 180
+
+ This extended timeout will be used in case there is an UDP stream
+ detected.
diff --git a/Documentation/networking/operstates.txt b/Documentation/networking/operstates.txt
index 1a77a3cfae54..97694572338b 100644
--- a/Documentation/networking/operstates.txt
+++ b/Documentation/networking/operstates.txt
@@ -88,6 +88,10 @@ set this flag. On netif_carrier_off(), the scheduler stops sending
packets. The name 'carrier' and the inversion are historical, think of
it as lower layer.
+Note that for certain kind of soft-devices, which are not managing any
+real hardware, there is possible to set this bit from userpsace.
+One should use TVL IFLA_CARRIER to do so.
+
netif_carrier_ok() can be used to query that bit.
__LINK_STATE_DORMANT, maps to IFF_DORMANT:
diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt
index 95e5f5985a2a..d5b1a3935245 100644
--- a/Documentation/networking/phy.txt
+++ b/Documentation/networking/phy.txt
@@ -103,7 +103,7 @@ Letting the PHY Abstraction Layer do Everything
Now, to connect, just call this function:
- phydev = phy_connect(dev, phy_name, &adjust_link, flags, interface);
+ phydev = phy_connect(dev, phy_name, &adjust_link, interface);
phydev is a pointer to the phy_device structure which represents the PHY. If
phy_connect is successful, it will return the pointer. dev, here, is the
@@ -113,7 +113,9 @@ Letting the PHY Abstraction Layer do Everything
current state, though the PHY will not yet be truly operational at this
point.
- flags is a u32 which can optionally contain phy-specific flags.
+ PHY-specific flags should be set in phydev->dev_flags prior to the call
+ to phy_connect() such that the underlying PHY driver can check for flags
+ and perform specific operations based on them.
This is useful if the system has put hardware restrictions on
the PHY/controller, of which the PHY needs to be aware.
@@ -185,11 +187,10 @@ Doing it all yourself
start, or disables then frees them for stop.
struct phy_device * phy_attach(struct net_device *dev, const char *phy_id,
- u32 flags, phy_interface_t interface);
+ phy_interface_t interface);
Attaches a network device to a particular PHY, binding the PHY to a generic
- driver if none was found during bus initialization. Passes in
- any phy-specific flags as needed.
+ driver if none was found during bus initialization.
int phy_start_aneg(struct phy_device *phydev);
diff --git a/Documentation/nfc/nfc-hci.txt b/Documentation/nfc/nfc-hci.txt
index 89a339c9b079..0686c9e211c2 100644
--- a/Documentation/nfc/nfc-hci.txt
+++ b/Documentation/nfc/nfc-hci.txt
@@ -17,10 +17,12 @@ HCI
HCI registers as an nfc device with NFC Core. Requests coming from userspace are
routed through netlink sockets to NFC Core and then to HCI. From this point,
they are translated in a sequence of HCI commands sent to the HCI layer in the
-host controller (the chip). The sending context blocks while waiting for the
-response to arrive.
+host controller (the chip). Commands can be executed synchronously (the sending
+context blocks waiting for response) or asynchronously (the response is returned
+from HCI Rx context).
HCI events can also be received from the host controller. They will be handled
-and a translation will be forwarded to NFC Core as needed.
+and a translation will be forwarded to NFC Core as needed. There are hooks to
+let the HCI driver handle proprietary events or override standard behavior.
HCI uses 2 execution contexts:
- one for executing commands : nfc_hci_msg_tx_work(). Only one command
can be executing at any given moment.
@@ -33,6 +35,8 @@ The Session initialization is an HCI standard which must unfortunately
support proprietary gates. This is the reason why the driver will pass a list
of proprietary gates that must be part of the session. HCI will ensure all
those gates have pipes connected when the hci device is set up.
+In case the chip supports pre-opened gates and pseudo-static pipes, the driver
+can pass that information to HCI core.
HCI Gates and Pipes
-------------------
@@ -46,6 +50,13 @@ without knowing the pipe connected to it.
Driver interface
----------------
+A driver is generally written in two parts : the physical link management and
+the HCI management. This makes it easier to maintain a driver for a chip that
+can be connected using various phy (i2c, spi, ...)
+
+HCI Management
+--------------
+
A driver would normally register itself with HCI and provide the following
entry points:
@@ -53,58 +64,113 @@ struct nfc_hci_ops {
int (*open)(struct nfc_hci_dev *hdev);
void (*close)(struct nfc_hci_dev *hdev);
int (*hci_ready) (struct nfc_hci_dev *hdev);
- int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
- int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols);
- int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate,
- struct nfc_target *target);
+ int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
+ int (*start_poll) (struct nfc_hci_dev *hdev,
+ u32 im_protocols, u32 tm_protocols);
+ int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target,
+ u8 comm_mode, u8 *gb, size_t gb_len);
+ int (*dep_link_down)(struct nfc_hci_dev *hdev);
+ int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
+ struct nfc_target *target);
int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
- int (*data_exchange) (struct nfc_hci_dev *hdev,
- struct nfc_target *target,
- struct sk_buff *skb, struct sk_buff **res_skb);
+ int (*im_transceive) (struct nfc_hci_dev *hdev,
+ struct nfc_target *target, struct sk_buff *skb,
+ data_exchange_cb_t cb, void *cb_context);
+ int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*check_presence)(struct nfc_hci_dev *hdev,
struct nfc_target *target);
+ int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
+ struct sk_buff *skb);
};
- open() and close() shall turn the hardware on and off.
- hci_ready() is an optional entry point that is called right after the hci
session has been set up. The driver can use it to do additional initialization
that must be performed using HCI commands.
-- xmit() shall simply write a frame to the chip.
+- xmit() shall simply write a frame to the physical link.
- start_poll() is an optional entrypoint that shall set the hardware in polling
mode. This must be implemented only if the hardware uses proprietary gates or a
mechanism slightly different from the HCI standard.
+- dep_link_up() is called after a p2p target has been detected, to finish
+the p2p connection setup with hardware parameters that need to be passed back
+to nfc core.
+- dep_link_down() is called to bring the p2p link down.
- target_from_gate() is an optional entrypoint to return the nfc protocols
corresponding to a proprietary gate.
- complete_target_discovered() is an optional entry point to let the driver
perform additional proprietary processing necessary to auto activate the
discovered target.
-- data_exchange() must be implemented by the driver if proprietary HCI commands
+- im_transceive() must be implemented by the driver if proprietary HCI commands
are required to send data to the tag. Some tag types will require custom
commands, others can be written to using the standard HCI commands. The driver
can check the tag type and either do proprietary processing, or return 1 to ask
-for standard processing.
+for standard processing. The data exchange command itself must be sent
+asynchronously.
+- tm_send() is called to send data in the case of a p2p connection
- check_presence() is an optional entry point that will be called regularly
by the core to check that an activated tag is still in the field. If this is
not implemented, the core will not be able to push tag_lost events to the user
space
+- event_received() is called to handle an event coming from the chip. Driver
+can handle the event or return 1 to let HCI attempt standard processing.
On the rx path, the driver is responsible to push incoming HCP frames to HCI
using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling
This must be done from a context that can sleep.
-SHDLC
------
+PHY Management
+--------------
+
+The physical link (i2c, ...) management is defined by the following struture:
+
+struct nfc_phy_ops {
+ int (*write)(void *dev_id, struct sk_buff *skb);
+ int (*enable)(void *dev_id);
+ void (*disable)(void *dev_id);
+};
+
+enable(): turn the phy on (power on), make it ready to transfer data
+disable(): turn the phy off
+write(): Send a data frame to the chip. Note that to enable higher
+layers such as an llc to store the frame for re-emission, this function must
+not alter the skb. It must also not return a positive result (return 0 for
+success, negative for failure).
+
+Data coming from the chip shall be sent directly to nfc_hci_recv_frame().
+
+LLC
+---
+
+Communication between the CPU and the chip often requires some link layer
+protocol. Those are isolated as modules managed by the HCI layer. There are
+currently two modules : nop (raw transfert) and shdlc.
+A new llc must implement the following functions:
+
+struct nfc_llc_ops {
+ void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv,
+ rcv_to_hci_t rcv_to_hci, int tx_headroom,
+ int tx_tailroom, int *rx_headroom, int *rx_tailroom,
+ llc_failure_t llc_failure);
+ void (*deinit) (struct nfc_llc *llc);
+ int (*start) (struct nfc_llc *llc);
+ int (*stop) (struct nfc_llc *llc);
+ void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb);
+ int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb);
+};
+
+- init() : allocate and init your private storage
+- deinit() : cleanup
+- start() : establish the logical connection
+- stop () : terminate the logical connection
+- rcv_from_drv() : handle data coming from the chip, going to HCI
+- xmit_from_hci() : handle data sent by HCI, going to the chip
-Most chips use shdlc to ensure integrity and delivery ordering of the HCP
-frames between the host controller (the chip) and hosts (entities connected
-to the chip, like the cpu). In order to simplify writing the driver, an shdlc
-layer is available for use by the driver.
-When used, the driver actually registers with shdlc, and shdlc will register
-with HCI. HCI sees shdlc as the driver and thus send its HCP frames
-through shdlc->xmit.
-SHDLC adds a new execution context (nfc_shdlc_sm_work()) to run its state
-machine and handle both its rx and tx path.
+The llc must be registered with nfc before it can be used. Do that by
+calling nfc_llc_register(const char *name, struct nfc_llc_ops *ops);
+
+Again, note that the llc does not handle the physical link. It is thus very
+easy to mix any physical link with any llc for a given chip driver.
Included Drivers
----------------
@@ -117,10 +183,12 @@ Execution Contexts
The execution contexts are the following:
- IRQ handler (IRQH):
-fast, cannot sleep. stores incoming frames into an shdlc rx queue
+fast, cannot sleep. sends incoming frames to HCI where they are passed to
+the current llc. In case of shdlc, the frame is queued in shdlc rx queue.
- SHDLC State Machine worker (SMW)
-handles shdlc rx & tx queues. Dispatches HCI cmd responses.
+Only when llc_shdlc is used: handles shdlc rx & tx queues.
+Dispatches HCI cmd responses.
- HCI Tx Cmd worker (MSGTXWQ)
Serializes execution of HCI commands. Completes execution in case of response
@@ -166,6 +234,15 @@ waiting command execution. Response processing involves invoking the completion
callback that was provided by nfc_hci_msg_tx_work() when it sent the command.
The completion callback will then wake the syscall context.
+It is also possible to execute the command asynchronously using this API:
+
+static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
+ const u8 *param, size_t param_len,
+ data_exchange_cb_t cb, void *cb_context)
+
+The workflow is the same, except that the API call returns immediately, and
+the callback will be called with the result from the SMW context.
+
Workflow receiving an HCI event or command
------------------------------------------
diff --git a/Documentation/nfc/nfc-pn544.txt b/Documentation/nfc/nfc-pn544.txt
index 2fcac9f5996e..b36ca14ca2d6 100644
--- a/Documentation/nfc/nfc-pn544.txt
+++ b/Documentation/nfc/nfc-pn544.txt
@@ -1,32 +1,15 @@
Kernel driver for the NXP Semiconductors PN544 Near Field
Communication chip
-Author: Jari Vanhala
-Contact: Matti Aaltonen (matti.j.aaltonen at nokia.com)
-
General
-------
The PN544 is an integrated transmission module for contactless
communication. The driver goes under drives/nfc/ and is compiled as a
-module named "pn544". It registers a misc device and creates a device
-file named "/dev/pn544".
+module named "pn544".
Host Interfaces: I2C, SPI and HSU, this driver supports currently only I2C.
-The Interface
--------------
-
-The driver offers a sysfs interface for a hardware test and an IOCTL
-interface for selecting between two operating modes. There are read,
-write and poll functions for transferring messages. The two operating
-modes are the normal (HCI) mode and the firmware update mode.
-
-PN544 is controlled by sending messages from the userspace to the
-chip. The main function of the driver is just to pass those messages
-without caring about the message content.
-
-
Protocols
---------
@@ -47,68 +30,3 @@ and third (LSB) bytes of the message. The maximum FW message length is
For the ETSI HCI specification see
http://www.etsi.org/WebSite/Technologies/ProtocolSpecification.aspx
-
-The Hardware Test
------------------
-
-The idea of the test is that it can performed by reading from the
-corresponding sysfs file. The test is implemented in the board file
-and it should test that PN544 can be put into the firmware update
-mode. If the test is not implemented the sysfs file does not get
-created.
-
-Example:
-> cat /sys/module/pn544/drivers/i2c\:pn544/3-002b/nfc_test
-1
-
-Normal Operation
-----------------
-
-PN544 is powered up when the device file is opened, otherwise it's
-turned off. Only one instance can use the device at a time.
-
-Userspace applications control PN544 with HCI messages. The hardware
-sends an interrupt when data is available for reading. Data is
-physically read when the read function is called by a userspace
-application. Poll() checks the read interrupt state. Configuration and
-self testing are also done from the userspace using read and write.
-
-Example platform data:
-
-static int rx71_pn544_nfc_request_resources(struct i2c_client *client)
-{
- /* Get and setup the HW resources for the device */
-}
-
-static void rx71_pn544_nfc_free_resources(void)
-{
- /* Release the HW resources */
-}
-
-static void rx71_pn544_nfc_enable(int fw)
-{
- /* Turn the device on */
-}
-
-static int rx71_pn544_nfc_test(void)
-{
- /*
- * Put the device into the FW update mode
- * and then back to the normal mode.
- * Check the behavior and return one on success,
- * zero on failure.
- */
-}
-
-static void rx71_pn544_nfc_disable(void)
-{
- /* turn the power off */
-}
-
-static struct pn544_nfc_platform_data rx71_nfc_data = {
- .request_resources = rx71_pn544_nfc_request_resources,
- .free_resources = rx71_pn544_nfc_free_resources,
- .enable = rx71_pn544_nfc_enable,
- .test = rx71_pn544_nfc_test,
- .disable = rx71_pn544_nfc_disable,
-};
diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
index da40efbef6ec..a2b57e0a1db0 100644
--- a/Documentation/pinctrl.txt
+++ b/Documentation/pinctrl.txt
@@ -972,6 +972,18 @@ pinmux core.
Pin control requests from drivers
=================================
+When a device driver is about to probe the device core will automatically
+attempt to issue pinctrl_get_select_default() on these devices.
+This way driver writers do not need to add any of the boilerplate code
+of the type found below. However when doing fine-grained state selection
+and not using the "default" state, you may have to do some device driver
+handling of the pinctrl handles and states.
+
+So if you just want to put the pins for a certain device into the default
+state and be done with it, there is nothing you need to do besides
+providing the proper mapping table. The device core will take care of
+the rest.
+
Generally it is discouraged to let individual drivers get and enable pin
control. So if possible, handle the pin control in platform code or some other
place where you have access to all the affected struct device * pointers. In
@@ -1097,9 +1109,9 @@ situations that can be electrically unpleasant, you will certainly want to
mux in and bias pins in a certain way before the GPIO subsystems starts to
deal with them.
-The above can be hidden: using pinctrl hogs, the pin control driver may be
-setting up the config and muxing for the pins when it is probing,
-nevertheless orthogonal to the GPIO subsystem.
+The above can be hidden: using the device core, the pinctrl core may be
+setting up the config and muxing for the pins right before the device is
+probing, nevertheless orthogonal to the GPIO subsystem.
But there are also situations where it makes sense for the GPIO subsystem
to communicate directly with with the pinctrl subsystem, using the latter
diff --git a/Documentation/power/freezing-of-tasks.txt b/Documentation/power/freezing-of-tasks.txt
index 6ec291ea1c78..85894d83b352 100644
--- a/Documentation/power/freezing-of-tasks.txt
+++ b/Documentation/power/freezing-of-tasks.txt
@@ -223,3 +223,8 @@ since they ask the freezer to skip freezing this task, since it is anyway
only after the entire suspend/hibernation sequence is complete.
So, to summarize, use [un]lock_system_sleep() instead of directly using
mutex_[un]lock(&pm_mutex). That would prevent freezing failures.
+
+V. Miscellaneous
+/sys/power/pm_freeze_timeout controls how long it will cost at most to freeze
+all user space processes or all freezable kernel threads, in unit of millisecond.
+The default value is 20000, with range of unsigned integer.
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 03591a750f99..6c9f5d9aa115 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -426,6 +426,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
'power.runtime_error' is set or 'power.disable_depth' is greater than
zero)
+ bool pm_runtime_active(struct device *dev);
+ - return true if the device's runtime PM status is 'active' or its
+ 'power.disable_depth' field is not equal to zero, or false otherwise
+
bool pm_runtime_suspended(struct device *dev);
- return true if the device's runtime PM status is 'suspended' and its
'power.disable_depth' field is equal to zero, or false otherwise
diff --git a/Documentation/powerpc/cpu_features.txt b/Documentation/powerpc/cpu_features.txt
index ffa4183fdb8b..ae09df8722c8 100644
--- a/Documentation/powerpc/cpu_features.txt
+++ b/Documentation/powerpc/cpu_features.txt
@@ -11,10 +11,10 @@ split instruction and data caches, and if the CPU supports the DOZE and NAP
sleep modes.
Detection of the feature set is simple. A list of processors can be found in
-arch/ppc/kernel/cputable.c. The PVR register is masked and compared with each
-value in the list. If a match is found, the cpu_features of cur_cpu_spec is
-assigned to the feature bitmask for this processor and a __setup_cpu function
-is called.
+arch/powerpc/kernel/cputable.c. The PVR register is masked and compared with
+each value in the list. If a match is found, the cpu_features of cur_cpu_spec
+is assigned to the feature bitmask for this processor and a __setup_cpu
+function is called.
C code may test 'cur_cpu_spec[smp_processor_id()]->cpu_features' for a
particular feature bit. This is done in quite a few places, for example
@@ -51,6 +51,6 @@ should be used in the majority of cases.
The END_FTR_SECTION macros are implemented by storing information about this
code in the '__ftr_fixup' ELF section. When do_cpu_ftr_fixups
-(arch/ppc/kernel/misc.S) is invoked, it will iterate over the records in
+(arch/powerpc/kernel/misc.S) is invoked, it will iterate over the records in
__ftr_fixup, and if the required feature is not present it will loop writing
nop's from each BEGIN_FTR_SECTION to END_FTR_SECTION.
diff --git a/Documentation/powerpc/transactional_memory.txt b/Documentation/powerpc/transactional_memory.txt
new file mode 100644
index 000000000000..c907be41d60f
--- /dev/null
+++ b/Documentation/powerpc/transactional_memory.txt
@@ -0,0 +1,175 @@
+Transactional Memory support
+============================
+
+POWER kernel support for this feature is currently limited to supporting
+its use by user programs. It is not currently used by the kernel itself.
+
+This file aims to sum up how it is supported by Linux and what behaviour you
+can expect from your user programs.
+
+
+Basic overview
+==============
+
+Hardware Transactional Memory is supported on POWER8 processors, and is a
+feature that enables a different form of atomic memory access. Several new
+instructions are presented to delimit transactions; transactions are
+guaranteed to either complete atomically or roll back and undo any partial
+changes.
+
+A simple transaction looks like this:
+
+begin_move_money:
+ tbegin
+ beq abort_handler
+
+ ld r4, SAVINGS_ACCT(r3)
+ ld r5, CURRENT_ACCT(r3)
+ subi r5, r5, 1
+ addi r4, r4, 1
+ std r4, SAVINGS_ACCT(r3)
+ std r5, CURRENT_ACCT(r3)
+
+ tend
+
+ b continue
+
+abort_handler:
+ ... test for odd failures ...
+
+ /* Retry the transaction if it failed because it conflicted with
+ * someone else: */
+ b begin_move_money
+
+
+The 'tbegin' instruction denotes the start point, and 'tend' the end point.
+Between these points the processor is in 'Transactional' state; any memory
+references will complete in one go if there are no conflicts with other
+transactional or non-transactional accesses within the system. In this
+example, the transaction completes as though it were normal straight-line code
+IF no other processor has touched SAVINGS_ACCT(r3) or CURRENT_ACCT(r3); an
+atomic move of money from the current account to the savings account has been
+performed. Even though the normal ld/std instructions are used (note no
+lwarx/stwcx), either *both* SAVINGS_ACCT(r3) and CURRENT_ACCT(r3) will be
+updated, or neither will be updated.
+
+If, in the meantime, there is a conflict with the locations accessed by the
+transaction, the transaction will be aborted by the CPU. Register and memory
+state will roll back to that at the 'tbegin', and control will continue from
+'tbegin+4'. The branch to abort_handler will be taken this second time; the
+abort handler can check the cause of the failure, and retry.
+
+Checkpointed registers include all GPRs, FPRs, VRs/VSRs, LR, CCR/CR, CTR, FPCSR
+and a few other status/flag regs; see the ISA for details.
+
+Causes of transaction aborts
+============================
+
+- Conflicts with cache lines used by other processors
+- Signals
+- Context switches
+- See the ISA for full documentation of everything that will abort transactions.
+
+
+Syscalls
+========
+
+Performing syscalls from within transaction is not recommended, and can lead
+to unpredictable results.
+
+Syscalls do not by design abort transactions, but beware: The kernel code will
+not be running in transactional state. The effect of syscalls will always
+remain visible, but depending on the call they may abort your transaction as a
+side-effect, read soon-to-be-aborted transactional data that should not remain
+invisible, etc. If you constantly retry a transaction that constantly aborts
+itself by calling a syscall, you'll have a livelock & make no progress.
+
+Simple syscalls (e.g. sigprocmask()) "could" be OK. Even things like write()
+from, say, printf() should be OK as long as the kernel does not access any
+memory that was accessed transactionally.
+
+Consider any syscalls that happen to work as debug-only -- not recommended for
+production use. Best to queue them up till after the transaction is over.
+
+
+Signals
+=======
+
+Delivery of signals (both sync and async) during transactions provides a second
+thread state (ucontext/mcontext) to represent the second transactional register
+state. Signal delivery 'treclaim's to capture both register states, so signals
+abort transactions. The usual ucontext_t passed to the signal handler
+represents the checkpointed/original register state; the signal appears to have
+arisen at 'tbegin+4'.
+
+If the sighandler ucontext has uc_link set, a second ucontext has been
+delivered. For future compatibility the MSR.TS field should be checked to
+determine the transactional state -- if so, the second ucontext in uc->uc_link
+represents the active transactional registers at the point of the signal.
+
+For 64-bit processes, uc->uc_mcontext.regs->msr is a full 64-bit MSR and its TS
+field shows the transactional mode.
+
+For 32-bit processes, the mcontext's MSR register is only 32 bits; the top 32
+bits are stored in the MSR of the second ucontext, i.e. in
+uc->uc_link->uc_mcontext.regs->msr. The top word contains the transactional
+state TS.
+
+However, basic signal handlers don't need to be aware of transactions
+and simply returning from the handler will deal with things correctly:
+
+Transaction-aware signal handlers can read the transactional register state
+from the second ucontext. This will be necessary for crash handlers to
+determine, for example, the address of the instruction causing the SIGSEGV.
+
+Example signal handler:
+
+ void crash_handler(int sig, siginfo_t *si, void *uc)
+ {
+ ucontext_t *ucp = uc;
+ ucontext_t *transactional_ucp = ucp->uc_link;
+
+ if (ucp_link) {
+ u64 msr = ucp->uc_mcontext.regs->msr;
+ /* May have transactional ucontext! */
+#ifndef __powerpc64__
+ msr |= ((u64)transactional_ucp->uc_mcontext.regs->msr) << 32;
+#endif
+ if (MSR_TM_ACTIVE(msr)) {
+ /* Yes, we crashed during a transaction. Oops. */
+ fprintf(stderr, "Transaction to be restarted at 0x%llx, but "
+ "crashy instruction was at 0x%llx\n",
+ ucp->uc_mcontext.regs->nip,
+ transactional_ucp->uc_mcontext.regs->nip);
+ }
+ }
+
+ fix_the_problem(ucp->dar);
+ }
+
+
+Failure cause codes used by kernel
+==================================
+
+These are defined in <asm/reg.h>, and distinguish different reasons why the
+kernel aborted a transaction:
+
+ TM_CAUSE_RESCHED Thread was rescheduled.
+ TM_CAUSE_FAC_UNAV FP/VEC/VSX unavailable trap.
+ TM_CAUSE_SYSCALL Currently unused; future syscalls that must abort
+ transactions for consistency will use this.
+ TM_CAUSE_SIGNAL Signal delivered.
+ TM_CAUSE_MISC Currently unused.
+
+These can be checked by the user program's abort handler as TEXASR[0:7].
+
+
+GDB
+===
+
+GDB and ptrace are not currently TM-aware. If one stops during a transaction,
+it looks like the transaction has just started (the checkpointed state is
+presented). The transaction cannot then be continued and will take the failure
+handler route. Furthermore, the transactional 2nd register state will be
+inaccessible. GDB can currently be used on programs using TM, but not sensibly
+in parts within transactions.
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index 8ffb274367c7..e8a6aa473bab 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -53,6 +53,14 @@ Struct Resources:
For printing struct resources. The 'R' and 'r' specifiers result in a
printed resource with ('R') or without ('r') a decoded flags member.
+Physical addresses:
+
+ %pa 0x01234567 or 0x0123456789abcdef
+
+ For printing a phys_addr_t type (and its derivatives, such as
+ resource_size_t) which can vary based on build options, regardless of
+ the width of the CPU data path. Passed by reference.
+
Raw buffer as a hex string:
%*ph 00 01 02 ... 3f
%*phC 00:01:02: ... :3f
@@ -150,9 +158,9 @@ s64 SHOULD be printed with %lld/%llx, (long long):
printk("%lld", (long long)s64_var);
If <type> is dependent on a config option for its size (e.g., sector_t,
-blkcnt_t, phys_addr_t, resource_size_t) or is architecture-dependent
-for its size (e.g., tcflag_t), use a format specifier of its largest
-possible type and explicitly cast to it. Example:
+blkcnt_t) or is architecture-dependent for its size (e.g., tcflag_t), use a
+format specifier of its largest possible type and explicitly cast to it.
+Example:
printk("test: sector number/total blocks: %llu/%llu\n",
(unsigned long long)sector, (unsigned long long)blockcount);
diff --git a/Documentation/serial/driver b/Documentation/serial/driver
index 0a25a9191864..067c47d46917 100644
--- a/Documentation/serial/driver
+++ b/Documentation/serial/driver
@@ -133,6 +133,16 @@ hardware.
Interrupts: locally disabled.
This call must not sleep
+ send_xchar(port,ch)
+ Transmit a high priority character, even if the port is stopped.
+ This is used to implement XON/XOFF flow control and tcflow(). If
+ the serial driver does not implement this function, the tty core
+ will append the character to the circular buffer and then call
+ start_tx() / stop_tx() to flush the data out.
+
+ Locking: none.
+ Interrupts: caller dependent.
+
stop_rx(port)
Stop receiving characters; the port is in the process of
being closed.
@@ -242,9 +252,8 @@ hardware.
pm(port,state,oldstate)
Perform any power management related activities on the specified
- port. State indicates the new state (defined by ACPI D0-D3),
- oldstate indicates the previous state. Essentially, D0 means
- fully on, D3 means powered down.
+ port. State indicates the new state (defined by
+ enum uart_pm_state), oldstate indicates the previous state.
This function should not be used to grab any resources.
@@ -255,6 +264,10 @@ hardware.
Locking: none.
Interrupts: caller dependent.
+ set_wake(port,state)
+ Enable/disable power management wakeup on serial activity. Not
+ currently implemented.
+
type(port)
Return a pointer to a string constant describing the specified
port, or return NULL, in which case the string 'unknown' is
@@ -307,6 +320,31 @@ hardware.
Locking: none.
Interrupts: caller dependent.
+ poll_init(port)
+ Called by kgdb to perform the minimal hardware initialization needed
+ to support poll_put_char() and poll_get_char(). Unlike ->startup()
+ this should not request interrupts.
+
+ Locking: tty_mutex and tty_port->mutex taken.
+ Interrupts: n/a.
+
+ poll_put_char(port,ch)
+ Called by kgdb to write a single character directly to the serial
+ port. It can and should block until there is space in the TX FIFO.
+
+ Locking: none.
+ Interrupts: caller dependent.
+ This call must not sleep
+
+ poll_get_char(port)
+ Called by kgdb to read a single character directly from the serial
+ port. If data is available, it should be returned; otherwise
+ the function should return NO_POLL_CHAR immediately.
+
+ Locking: none.
+ Interrupts: caller dependent.
+ This call must not sleep
+
Other functions
---------------
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index b9cfd339a6fa..ce6581c8ca26 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -890,8 +890,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
enable_msi - Enable Message Signaled Interrupt (MSI) (default = off)
power_save - Automatic power-saving timeout (in second, 0 =
disable)
- power_save_controller - Reset HD-audio controller in power-saving mode
- (default = on)
+ power_save_controller - Support runtime D3 of HD-audio controller
+ (-1 = on for supported chip (default), false = off,
+ true = force to on even for unsupported hardware)
align_buffer_size - Force rounding of buffer/period sizes to multiples
of 128 bytes. This is more efficient in terms of memory
access but isn't required by the HDA spec and prevents
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 16dfe57f1731..bb8b0dc532b8 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -53,7 +53,7 @@ ALC882/883/885/888/889
acer-aspire-8930g Acer Aspire 8330G/6935G
acer-aspire Acer Aspire others
inv-dmic Inverted internal mic workaround
- no-primary-hp VAIO Z workaround (for fixed speaker DAC)
+ no-primary-hp VAIO Z/VGC-LN51JGB workaround (for fixed speaker DAC)
ALC861/660
==========
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt
index 7813c06a5c71..d4faa63ff352 100644
--- a/Documentation/sound/alsa/HD-Audio.txt
+++ b/Documentation/sound/alsa/HD-Audio.txt
@@ -176,14 +176,14 @@ support the automatic probing (yet as of 2.6.28). And, BIOS is often,
yes, pretty often broken. It sets up wrong values and screws up the
driver.
-The preset model is provided basically to overcome such a situation.
-When the matching preset model is found in the white-list, the driver
-assumes the static configuration of that preset and builds the mixer
-elements and PCM streams based on the static information. Thus, if
-you have a newer machine with a slightly different PCI SSID from the
-existing one, you may have a good chance to re-use the same model.
-You can pass the `model` option to specify the preset model instead of
-PCI SSID look-up.
+The preset model (or recently called as "fix-up") is provided
+basically to overcome such a situation. When the matching preset
+model is found in the white-list, the driver assumes the static
+configuration of that preset with the correct pin setup, etc.
+Thus, if you have a newer machine with a slightly different PCI SSID
+(or codec SSID) from the existing one, you may have a good chance to
+re-use the same model. You can pass the `model` option to specify the
+preset model instead of PCI (and codec-) SSID look-up.
What `model` option values are available depends on the codec chip.
Check your codec chip from the codec proc file (see "Codec Proc-File"
@@ -199,17 +199,12 @@ non-working HD-audio hardware is to check HD-audio codec and several
different `model` option values. If you have any luck, some of them
might suit with your device well.
-Some codecs such as ALC880 have a special model option `model=test`.
-This configures the driver to provide as many mixer controls as
-possible for every single pin feature except for the unsolicited
-events (and maybe some other specials). Adjust each mixer element and
-try the I/O in the way of trial-and-error until figuring out the whole
-I/O pin mappings.
+There are a few special model option values:
+- when 'nofixup' is passed, the device-specific fixups in the codec
+ parser are skipped.
+- when `generic` is passed, the codec-specific parser is skipped and
+ only the generic parser is used.
-Note that `model=generic` has a special meaning. It means to use the
-generic parser regardless of the codec. Usually the codec-specific
-parser is much better than the generic parser (as now). Thus this
-option is more about the debugging purpose.
Speaker and Headphone Output
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -387,9 +382,8 @@ init_verbs::
(separated with a space).
hints::
Shows / stores hint strings for codec parsers for any use.
- Its format is `key = value`. For example, passing `hp_detect = yes`
- to IDT/STAC codec parser will result in the disablement of the
- headphone detection.
+ Its format is `key = value`. For example, passing `jack_detect = no`
+ will disable the jack detection of the machine completely.
init_pin_configs::
Shows the initial pin default config values set by BIOS.
driver_pin_configs::
@@ -421,6 +415,61 @@ re-configure based on that state, run like below:
------------------------------------------------------------------------
+Hint Strings
+~~~~~~~~~~~~
+The codec parser have several switches and adjustment knobs for
+matching better with the actual codec or device behavior. Many of
+them can be adjusted dynamically via "hints" strings as mentioned in
+the section above. For example, by passing `jack_detect = no` string
+via sysfs or a patch file, you can disable the jack detection, thus
+the codec parser will skip the features like auto-mute or mic
+auto-switch. As a boolean value, either `yes`, `no`, `true`, `false`,
+`1` or `0` can be passed.
+
+The generic parser supports the following hints:
+
+- jack_detect (bool): specify whether the jack detection is available
+ at all on this machine; default true
+- inv_jack_detect (bool): indicates that the jack detection logic is
+ inverted
+- trigger_sense (bool): indicates that the jack detection needs the
+ explicit call of AC_VERB_SET_PIN_SENSE verb
+- inv_eapd (bool): indicates that the EAPD is implemented in the
+ inverted logic
+- pcm_format_first (bool): sets the PCM format before the stream tag
+ and channel ID
+- sticky_stream (bool): keep the PCM format, stream tag and ID as long
+ as possible; default true
+- spdif_status_reset (bool): reset the SPDIF status bits at each time
+ the SPDIF stream is set up
+- pin_amp_workaround (bool): the output pin may have multiple amp
+ values
+- single_adc_amp (bool): ADCs can have only single input amps
+- auto_mute (bool): enable/disable the headphone auto-mute feature;
+ default true
+- auto_mic (bool): enable/disable the mic auto-switch feature; default
+ true
+- line_in_auto_switch (bool): enable/disable the line-in auto-switch
+ feature; default false
+- need_dac_fix (bool): limits the DACs depending on the channel count
+- primary_hp (bool): probe headphone jacks as the primary outputs;
+ default true
+- multi_cap_vol (bool): provide multiple capture volumes
+- inv_dmic_split (bool): provide split internal mic volume/switch for
+ phase-inverted digital mics
+- indep_hp (bool): provide the independent headphone PCM stream and
+ the corresponding mixer control, if available
+- add_stereo_mix_input (bool): add the stereo mix (analog-loopback
+ mix) to the input mux if available
+- add_out_jack_modes (bool): add "xxx Jack Mode" enum controls to each
+ output jack for allowing to change the headphone amp capability
+- add_in_jack_modes (bool): add "xxx Jack Mode" enum controls to each
+ input jack for allowing to change the mic bias vref
+- power_down_unused (bool): power down the unused widgets
+- mixer_nid (int): specifies the widget NID of the analog-loopback
+ mixer
+
+
Early Patching
~~~~~~~~~~~~~~
When CONFIG_SND_HDA_PATCH_LOADER=y is set, you can pass a "patch" as a
@@ -445,7 +494,7 @@ A patch file is a plain text file which looks like below:
0x20 0x400 0xff
[hint]
- hp_detect = yes
+ jack_detect = no
------------------------------------------------------------------------
The file needs to have a line `[codec]`. The next line should contain
@@ -531,6 +580,13 @@ cable is unplugged. Thus, if you hear noises, suspect first the
power-saving. See /sys/module/snd_hda_intel/parameters/power_save to
check the current value. If it's non-zero, the feature is turned on.
+The recent kernel supports the runtime PM for the HD-audio controller
+chip, too. It means that the HD-audio controller is also powered up /
+down dynamically. The feature is enabled only for certain controller
+chips like Intel LynxPoint. You can enable/disable this feature
+forcibly by setting `power_save_controller` option, which is also
+available at /sys/module/snd_hda_intel/parameters directory.
+
Tracepoints
~~~~~~~~~~~
@@ -587,8 +643,9 @@ The latest development codes for HD-audio are found on sound git tree:
- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
The master branch or for-next branches can be used as the main
-development branches in general while the HD-audio specific patches
-are committed in topic/hda branch.
+development branches in general while the development for the current
+and next kernels are found in for-linus and for-next branches,
+respectively.
If you are using the latest Linus tree, it'd be better to pull the
above GIT tree onto it. If you are using the older kernels, an easy
@@ -699,7 +756,11 @@ won't be always updated. For example, the volume values are usually
cached in the driver, and thus changing the widget amp value directly
via hda-verb won't change the mixer value.
-The hda-verb program is found in the ftp directory:
+The hda-verb program is included now in alsa-tools:
+
+- git://git.alsa-project.org/alsa-tools.git
+
+Also, the old stand-alone package is found in the ftp directory:
- ftp://ftp.suse.com/pub/people/tiwai/misc/
@@ -777,3 +838,18 @@ A git repository is available:
See README file in the tarball for more details about hda-emu
program.
+
+
+hda-jack-retask
+~~~~~~~~~~~~~~~
+hda-jack-retask is a user-friendly GUI program to manipulate the
+HD-audio pin control for jack retasking. If you have a problem about
+the jack assignment, try this program and check whether you can get
+useful results. Once when you figure out the proper pin assignment,
+it can be fixed either in the driver code statically or via passing a
+firmware patch file (see "Early Patching" section).
+
+The program is included in alsa-tools now:
+
+- git://git.alsa-project.org/alsa-tools.git
+
diff --git a/Documentation/sound/alsa/compress_offload.txt b/Documentation/sound/alsa/compress_offload.txt
index 90e9b3a11abc..0bcc55155911 100644
--- a/Documentation/sound/alsa/compress_offload.txt
+++ b/Documentation/sound/alsa/compress_offload.txt
@@ -145,6 +145,52 @@ Modifications include:
- Addition of encoding options when required (derived from OpenMAX IL)
- Addition of rateControlSupported (missing in OpenMAX AL)
+Gapless Playback
+================
+When playing thru an album, the decoders have the ability to skip the encoder
+delay and padding and directly move from one track content to another. The end
+user can perceive this as gapless playback as we dont have silence while
+switching from one track to another
+
+Also, there might be low-intensity noises due to encoding. Perfect gapless is
+difficult to reach with all types of compressed data, but works fine with most
+music content. The decoder needs to know the encoder delay and encoder padding.
+So we need to pass this to DSP. This metadata is extracted from ID3/MP4 headers
+and are not present by default in the bitstream, hence the need for a new
+interface to pass this information to the DSP. Also DSP and userspace needs to
+switch from one track to another and start using data for second track.
+
+The main additions are:
+
+- set_metadata
+This routine sets the encoder delay and encoder padding. This can be used by
+decoder to strip the silence. This needs to be set before the data in the track
+is written.
+
+- set_next_track
+This routine tells DSP that metadata and write operation sent after this would
+correspond to subsequent track
+
+- partial drain
+This is called when end of file is reached. The userspace can inform DSP that
+EOF is reached and now DSP can start skipping padding delay. Also next write
+data would belong to next track
+
+Sequence flow for gapless would be:
+- Open
+- Get caps / codec caps
+- Set params
+- Set metadata of the first track
+- Fill data of the first track
+- Trigger start
+- User-space finished sending all,
+- Indicaite next track data by sending set_next_track
+- Set metadata of the next track
+- then call partial_drain to flush most of buffer in DSP
+- Fill data of the next track
+- DSP switches to second track
+(note: order for partial_drain and write for next track can be reversed as well)
+
Not supported:
- Support for VoIP/circuit-switched calls is not the target of this
diff --git a/Documentation/trace/events-power.txt b/Documentation/trace/events-power.txt
index cf794af22855..e1498ff8cf94 100644
--- a/Documentation/trace/events-power.txt
+++ b/Documentation/trace/events-power.txt
@@ -17,7 +17,7 @@ Cf. include/trace/events/power.h for the events definitions.
1. Power state switch events
============================
-1.1 New trace API
+1.1 Trace API
-----------------
A 'cpu' event class gathers the CPU-related events: cpuidle and
@@ -41,31 +41,6 @@ The event which has 'state=4294967295' in the trace is very important to the use
space tools which are using it to detect the end of the current state, and so to
correctly draw the states diagrams and to calculate accurate statistics etc.
-1.2 DEPRECATED trace API
-------------------------
-
-A new Kconfig option CONFIG_EVENT_POWER_TRACING_DEPRECATED with the default value of
-'y' has been created. This allows the legacy trace power API to be used conjointly
-with the new trace API.
-The Kconfig option, the old trace API (in include/trace/events/power.h) and the
-old trace points will disappear in a future release (namely 2.6.41).
-
-power_start "type=%lu state=%lu cpu_id=%lu"
-power_frequency "type=%lu state=%lu cpu_id=%lu"
-power_end "cpu_id=%lu"
-
-The 'type' parameter takes one of those macros:
- . POWER_NONE = 0,
- . POWER_CSTATE = 1, /* C-State */
- . POWER_PSTATE = 2, /* Frequency change or DVFS */
-
-The 'state' parameter is set depending on the type:
- . Target C-state for type=POWER_CSTATE,
- . Target frequency for type=POWER_PSTATE,
-
-power_end is used to indicate the exit of a state, corresponding to the latest
-power_start event.
-
2. Clocks events
================
The clock events are used for clock enable/disable and for
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
index 6f51fed45f2d..53d6a3c51d87 100644
--- a/Documentation/trace/ftrace.txt
+++ b/Documentation/trace/ftrace.txt
@@ -1842,6 +1842,89 @@ an error.
# cat buffer_size_kb
85
+Snapshot
+--------
+CONFIG_TRACER_SNAPSHOT makes a generic snapshot feature
+available to all non latency tracers. (Latency tracers which
+record max latency, such as "irqsoff" or "wakeup", can't use
+this feature, since those are already using the snapshot
+mechanism internally.)
+
+Snapshot preserves a current trace buffer at a particular point
+in time without stopping tracing. Ftrace swaps the current
+buffer with a spare buffer, and tracing continues in the new
+current (=previous spare) buffer.
+
+The following debugfs files in "tracing" are related to this
+feature:
+
+ snapshot:
+
+ This is used to take a snapshot and to read the output
+ of the snapshot. Echo 1 into this file to allocate a
+ spare buffer and to take a snapshot (swap), then read
+ the snapshot from this file in the same format as
+ "trace" (described above in the section "The File
+ System"). Both reads snapshot and tracing are executable
+ in parallel. When the spare buffer is allocated, echoing
+ 0 frees it, and echoing else (positive) values clear the
+ snapshot contents.
+ More details are shown in the table below.
+
+ status\input | 0 | 1 | else |
+ --------------+------------+------------+------------+
+ not allocated |(do nothing)| alloc+swap | EINVAL |
+ --------------+------------+------------+------------+
+ allocated | free | swap | clear |
+ --------------+------------+------------+------------+
+
+Here is an example of using the snapshot feature.
+
+ # echo 1 > events/sched/enable
+ # echo 1 > snapshot
+ # cat snapshot
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 71/71 #P:8
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ <idle>-0 [005] d... 2440.603828: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2242 next_prio=120
+ sleep-2242 [005] d... 2440.603846: sched_switch: prev_comm=snapshot-test-2 prev_pid=2242 prev_prio=120 prev_state=R ==> next_comm=kworker/5:1 next_pid=60 next_prio=120
+[...]
+ <idle>-0 [002] d... 2440.707230: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2229 next_prio=120
+
+ # cat trace
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 77/77 #P:8
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ <idle>-0 [007] d... 2440.707395: sched_switch: prev_comm=swapper/7 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2243 next_prio=120
+ snapshot-test-2-2229 [002] d... 2440.707438: sched_switch: prev_comm=snapshot-test-2 prev_pid=2229 prev_prio=120 prev_state=S ==> next_comm=swapper/2 next_pid=0 next_prio=120
+[...]
+
+
+If you try to use this snapshot feature when current tracer is
+one of the latency tracers, you will get the following results.
+
+ # echo wakeup > current_tracer
+ # echo 1 > snapshot
+bash: echo: write error: Device or resource busy
+ # cat snapshot
+cat: snapshot: Device or resource busy
+
-----------
More details can be found in the source code, in the
diff --git a/Documentation/video4linux/CARDLIST.au0828 b/Documentation/video4linux/CARDLIST.au0828
index a8a65753e544..55a21deab7db 100644
--- a/Documentation/video4linux/CARDLIST.au0828
+++ b/Documentation/video4linux/CARDLIST.au0828
@@ -1,5 +1,5 @@
0 -> Unknown board (au0828)
- 1 -> Hauppauge HVR950Q (au0828) [2040:7200,2040:7210,2040:7217,2040:721b,2040:721e,2040:721f,2040:7280,0fd9:0008,2040:7260,2040:7213]
+ 1 -> Hauppauge HVR950Q (au0828) [2040:7200,2040:7210,2040:7217,2040:721b,2040:721e,2040:721f,2040:7280,0fd9:0008,2040:7260,2040:7213,2040:7270]
2 -> Hauppauge HVR850 (au0828) [2040:7240]
3 -> DViCO FusionHDTV USB (au0828) [0fe9:d620]
4 -> Hauppauge HVR950Q rev xxF8 (au0828) [2040:7201,2040:7211,2040:7281]
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index 1299b5e82d7f..9f056d512e35 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -36,3 +36,5 @@
35 -> TeVii S471 [d471:9022]
36 -> Hauppauge WinTV-HVR1255 [0070:2259]
37 -> Prof Revolution DVB-S2 8000 [8000:3034]
+ 38 -> Hauppauge WinTV-HVR4400 [0070:c108,0070:c138,0070:c12a,0070:c1f8]
+ 39 -> AVerTV Hybrid Express Slim HC81R [1461:d939]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index d99262dda533..3f12865b2a88 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -76,7 +76,7 @@
76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340]
77 -> EM2874 Leadership ISDBT (em2874)
78 -> PCTV nanoStick T2 290e (em28174)
- 79 -> Terratec Cinergy H5 (em2884) [0ccd:008e,0ccd:00ac,0ccd:10a2,0ccd:10ad]
+ 79 -> Terratec Cinergy H5 (em2884) [0ccd:10a2,0ccd:10ad]
80 -> PCTV DVB-S2 Stick (460e) (em28174)
81 -> Hauppauge WinTV HVR 930C (em2884) [2040:1605]
82 -> Terratec Cinergy HTC Stick (em2884) [0ccd:00b2]
@@ -84,3 +84,4 @@
84 -> MaxMedia UB425-TC (em2874) [1b80:e425]
85 -> PCTV QuatroStick (510e) (em2884) [2304:0242]
86 -> PCTV QuatroStick nano (520e) (em2884) [2013:0251]
+ 87 -> Terratec Cinergy HTC USB XS (em2884) [0ccd:008e,0ccd:00ac]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 94d9025aa82d..b3ad68309109 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -189,3 +189,4 @@
188 -> Sensoray 811/911 [6000:0811,6000:0911]
189 -> Kworld PC150-U [17de:a134]
190 -> Asus My Cinema PS3-100 [1043:48cd]
+191 -> Hawell HW-9004V1
diff --git a/Documentation/video4linux/et61x251.txt b/Documentation/video4linux/et61x251.txt
deleted file mode 100644
index e0cdae491858..000000000000
--- a/Documentation/video4linux/et61x251.txt
+++ /dev/null
@@ -1,315 +0,0 @@
-
- ET61X[12]51 PC Camera Controllers
- Driver for Linux
- =================================
-
- - Documentation -
-
-
-Index
-=====
-1. Copyright
-2. Disclaimer
-3. License
-4. Overview and features
-5. Module dependencies
-6. Module loading
-7. Module parameters
-8. Optional device control through "sysfs"
-9. Supported devices
-10. Notes for V4L2 application developers
-11. Contact information
-
-
-1. Copyright
-============
-Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>
-
-
-2. Disclaimer
-=============
-Etoms is a trademark of Etoms Electronics Corp.
-This software is not developed or sponsored by Etoms Electronics.
-
-
-3. License
-==========
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You 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.
-
-
-4. Overview and features
-========================
-This driver supports the video interface of the devices mounting the ET61X151
-or ET61X251 PC Camera Controllers.
-
-It's worth to note that Etoms Electronics has never collaborated with the
-author during the development of this project; despite several requests,
-Etoms Electronics also refused to release enough detailed specifications of
-the video compression engine.
-
-The driver relies on the Video4Linux2 and USB core modules. It has been
-designed to run properly on SMP systems as well.
-
-The latest version of the ET61X[12]51 driver can be found at the following URL:
-http://www.linux-projects.org/
-
-Some of the features of the driver are:
-
-- full compliance with the Video4Linux2 API (see also "Notes for V4L2
- application developers" paragraph);
-- available mmap or read/poll methods for video streaming through isochronous
- data transfers;
-- automatic detection of image sensor;
-- support for any window resolutions and optional panning within the maximum
- pixel area of image sensor;
-- image downscaling with arbitrary scaling factors from 1 and 2 in both
- directions (see "Notes for V4L2 application developers" paragraph);
-- two different video formats for uncompressed or compressed data in low or
- high compression quality (see also "Notes for V4L2 application developers"
- paragraph);
-- full support for the capabilities of every possible image sensors that can
- be connected to the ET61X[12]51 bridges, including, for instance, red, green,
- blue and global gain adjustments and exposure control (see "Supported
- devices" paragraph for details);
-- use of default color settings for sunlight conditions;
-- dynamic I/O interface for both ET61X[12]51 and image sensor control (see
- "Optional device control through 'sysfs'" paragraph);
-- dynamic driver control thanks to various module parameters (see "Module
- parameters" paragraph);
-- up to 64 cameras can be handled at the same time; they can be connected and
- disconnected from the host many times without turning off the computer, if
- the system supports hotplugging;
-- no known bugs.
-
-
-5. Module dependencies
-======================
-For it to work properly, the driver needs kernel support for Video4Linux and
-USB.
-
-The following options of the kernel configuration file must be enabled and
-corresponding modules must be compiled:
-
- # Multimedia devices
- #
- CONFIG_VIDEO_DEV=m
-
-To enable advanced debugging functionality on the device through /sysfs:
-
- # Multimedia devices
- #
- CONFIG_VIDEO_ADV_DEBUG=y
-
- # USB support
- #
- CONFIG_USB=m
-
-In addition, depending on the hardware being used, the modules below are
-necessary:
-
- # USB Host Controller Drivers
- #
- CONFIG_USB_EHCI_HCD=m
- CONFIG_USB_UHCI_HCD=m
- CONFIG_USB_OHCI_HCD=m
-
-And finally:
-
- # USB Multimedia devices
- #
- CONFIG_USB_ET61X251=m
-
-
-6. Module loading
-=================
-To use the driver, it is necessary to load the "et61x251" module into memory
-after every other module required: "videodev", "v4l2_common", "compat_ioctl32",
-"usbcore" and, depending on the USB host controller you have, "ehci-hcd",
-"uhci-hcd" or "ohci-hcd".
-
-Loading can be done as shown below:
-
- [root@localhost home]# modprobe et61x251
-
-At this point the devices should be recognized. You can invoke "dmesg" to
-analyze kernel messages and verify that the loading process has gone well:
-
- [user@localhost home]$ dmesg
-
-
-7. Module parameters
-====================
-Module parameters are listed below:
--------------------------------------------------------------------------------
-Name: video_nr
-Type: short array (min = 0, max = 64)
-Syntax: <-1|n[,...]>
-Description: Specify V4L2 minor mode number:
- -1 = use next available
- n = use minor number n
- You can specify up to 64 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- registered camera and use auto for the first one and for every
- other camera.
-Default: -1
--------------------------------------------------------------------------------
-Name: force_munmap
-Type: bool array (min = 0, max = 64)
-Syntax: <0|1[,...]>
-Description: Force the application to unmap previously mapped buffer memory
- before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
- all the applications support this feature. This parameter is
- specific for each detected camera.
- 0 = do not force memory unmapping
- 1 = force memory unmapping (save memory)
-Default: 0
--------------------------------------------------------------------------------
-Name: frame_timeout
-Type: uint array (min = 0, max = 64)
-Syntax: <n[,...]>
-Description: Timeout for a video frame in seconds. This parameter is
- specific for each detected camera. This parameter can be
- changed at runtime thanks to the /sys filesystem interface.
-Default: 2
--------------------------------------------------------------------------------
-Name: debug
-Type: ushort
-Syntax: <n>
-Description: Debugging information level, from 0 to 3:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant information
- 3 = more verbose messages
- Level 3 is useful for testing only, when only one device
- is used at the same time. It also shows some more information
- about the hardware being detected. This module parameter can be
- changed at runtime thanks to the /sys filesystem interface.
-Default: 2
--------------------------------------------------------------------------------
-
-
-8. Optional device control through "sysfs"
-==========================================
-If the kernel has been compiled with the CONFIG_VIDEO_ADV_DEBUG option enabled,
-it is possible to read and write both the ET61X[12]51 and the image sensor
-registers by using the "sysfs" filesystem interface.
-
-There are four files in the /sys/class/video4linux/videoX directory for each
-registered camera: "reg", "val", "i2c_reg" and "i2c_val". The first two files
-control the ET61X[12]51 bridge, while the other two control the sensor chip.
-"reg" and "i2c_reg" hold the values of the current register index where the
-following reading/writing operations are addressed at through "val" and
-"i2c_val". Their use is not intended for end-users, unless you know what you
-are doing. Remember that you must be logged in as root before writing to them.
-
-As an example, suppose we were to want to read the value contained in the
-register number 1 of the sensor register table - which is usually the product
-identifier - of the camera registered as "/dev/video0":
-
- [root@localhost #] cd /sys/class/video4linux/video0
- [root@localhost #] echo 1 > i2c_reg
- [root@localhost #] cat i2c_val
-
-Note that if the sensor registers cannot be read, "cat" will fail.
-To avoid race conditions, all the I/O accesses to the files are serialized.
-
-
-9. Supported devices
-====================
-None of the names of the companies as well as their products will be mentioned
-here. They have never collaborated with the author, so no advertising.
-
-From the point of view of a driver, what unambiguously identify a device are
-its vendor and product USB identifiers. Below is a list of known identifiers of
-devices mounting the ET61X[12]51 PC camera controllers:
-
-Vendor ID Product ID
---------- ----------
-0x102c 0x6151
-0x102c 0x6251
-0x102c 0x6253
-0x102c 0x6254
-0x102c 0x6255
-0x102c 0x6256
-0x102c 0x6257
-0x102c 0x6258
-0x102c 0x6259
-0x102c 0x625a
-0x102c 0x625b
-0x102c 0x625c
-0x102c 0x625d
-0x102c 0x625e
-0x102c 0x625f
-0x102c 0x6260
-0x102c 0x6261
-0x102c 0x6262
-0x102c 0x6263
-0x102c 0x6264
-0x102c 0x6265
-0x102c 0x6266
-0x102c 0x6267
-0x102c 0x6268
-0x102c 0x6269
-
-The following image sensors are supported:
-
-Model Manufacturer
------ ------------
-TAS5130D1B Taiwan Advanced Sensor Corporation
-
-All the available control settings of each image sensor are supported through
-the V4L2 interface.
-
-
-10. Notes for V4L2 application developers
-=========================================
-This driver follows the V4L2 API specifications. In particular, it enforces two
-rules:
-
-- exactly one I/O method, either "mmap" or "read", is associated with each
-file descriptor. Once it is selected, the application must close and reopen the
-device to switch to the other I/O method;
-
-- although it is not mandatory, previously mapped buffer memory should always
-be unmapped before calling any "VIDIOC_S_CROP" or "VIDIOC_S_FMT" ioctl's.
-The same number of buffers as before will be allocated again to match the size
-of the new video frames, so you have to map the buffers again before any I/O
-attempts on them.
-
-Consistently with the hardware limits, this driver also supports image
-downscaling with arbitrary scaling factors from 1 and 2 in both directions.
-However, the V4L2 API specifications don't correctly define how the scaling
-factor can be chosen arbitrarily by the "negotiation" of the "source" and
-"target" rectangles. To work around this flaw, we have added the convention
-that, during the negotiation, whenever the "VIDIOC_S_CROP" ioctl is issued, the
-scaling factor is restored to 1.
-
-This driver supports two different video formats: the first one is the "8-bit
-Sequential Bayer" format and can be used to obtain uncompressed video data
-from the device through the current I/O method, while the second one provides
-"raw" compressed video data (without frame headers not related to the
-compressed data). The current compression quality may vary from 0 to 1 and can
-be selected or queried thanks to the VIDIOC_S_JPEGCOMP and VIDIOC_G_JPEGCOMP
-V4L2 ioctl's.
-
-
-11. Contact information
-=======================
-The author may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
-
-GPG/PGP encrypted e-mail's are accepted. The GPG key ID of the author is
-'FCE635A4'; the public 1024-bit key should be available at any keyserver;
-the fingerprint is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'.
diff --git a/Documentation/video4linux/extract_xc3028.pl b/Documentation/video4linux/extract_xc3028.pl
index 47877deae6d7..47877deae6d7 100644..100755
--- a/Documentation/video4linux/extract_xc3028.pl
+++ b/Documentation/video4linux/extract_xc3028.pl
diff --git a/Documentation/video4linux/fimc.txt b/Documentation/video4linux/fimc.txt
index fd02d9a4930a..25f4d3402722 100644
--- a/Documentation/video4linux/fimc.txt
+++ b/Documentation/video4linux/fimc.txt
@@ -58,7 +58,7 @@ Not currently supported:
4.1. Media device interface
The driver supports Media Controller API as defined at
-http://http://linuxtv.org/downloads/v4l-dvb-apis/media_common.html
+http://linuxtv.org/downloads/v4l-dvb-apis/media_common.html
The media device driver name is "SAMSUNG S5P FIMC".
The purpose of this interface is to allow changing assignment of FIMC instances
diff --git a/Documentation/video4linux/ibmcam.txt b/Documentation/video4linux/ibmcam.txt
deleted file mode 100644
index a51055211e62..000000000000
--- a/Documentation/video4linux/ibmcam.txt
+++ /dev/null
@@ -1,323 +0,0 @@
-README for Linux device driver for the IBM "C-It" USB video camera
-
-INTRODUCTION:
-
-This driver does not use all features known to exist in
-the IBM camera. However most of needed features work well.
-
-This driver was developed using logs of observed USB traffic
-which was produced by standard Windows driver (c-it98.sys).
-I did not have data sheets from Xirlink.
-
-Video formats:
- 128x96 [model 1]
- 176x144
- 320x240 [model 2]
- 352x240 [model 2]
- 352x288
-Frame rate: 3 - 30 frames per second (FPS)
-External interface: USB
-Internal interface: Video For Linux (V4L)
-Supported controls:
-- by V4L: Contrast, Brightness, Color, Hue
-- by driver options: frame rate, lighting conditions, video format,
- default picture settings, sharpness.
-
-SUPPORTED CAMERAS:
-
-Xirlink "C-It" camera, also known as "IBM PC Camera".
-The device uses proprietary ASIC (and compression method);
-it is manufactured by Xirlink. See http://xirlinkwebcam.sourceforge.net,
-http://www.ibmpccamera.com, or http://www.c-itnow.com/ for details and pictures.
-
-This very chipset ("X Chip", as marked at the factory)
-is used in several other cameras, and they are supported
-as well:
-
-- IBM NetCamera
-- Veo Stingray
-
-The Linux driver was developed with camera with following
-model number (or FCC ID): KSX-XVP510. This camera has three
-interfaces, each with one endpoint (control, iso, iso). This
-type of cameras is referred to as "model 1". These cameras are
-no longer manufactured.
-
-Xirlink now manufactures new cameras which are somewhat different.
-In particular, following models [FCC ID] belong to that category:
-
-XVP300 [KSX-X9903]
-XVP600 [KSX-X9902]
-XVP610 [KSX-X9902]
-
-(see http://www.xirlink.com/ibmpccamera/ for updates, they refer
-to these new cameras by Windows driver dated 12-27-99, v3005 BETA)
-These cameras have two interfaces, one endpoint in each (iso, bulk).
-Such type of cameras is referred to as "model 2". They are supported
-(with exception of 352x288 native mode).
-
-Some IBM NetCameras (Model 4) are made to generate only compressed
-video streams. This is great for performance, but unfortunately
-nobody knows how to decompress the stream :-( Therefore, these
-cameras are *unsupported* and if you try to use one of those, all
-you get is random colored horizontal streaks, not the image!
-If you have one of those cameras, you probably should return it
-to the store and get something that is supported.
-
-Tell me more about all that "model" business
---------------------------------------------
-
-I just invented model numbers to uniquely identify flavors of the
-hardware/firmware that were sold. It was very confusing to use
-brand names or some other internal numbering schemes. So I found
-by experimentation that all Xirlink chipsets fall into four big
-classes, and I called them "models". Each model is programmed in
-its own way, and each model sends back the video in its own way.
-
-Quirks of Model 2 cameras:
--------------------------
-
-Model 2 does not have hardware contrast control. Corresponding V4L
-control is implemented in software, which is not very nice to your
-CPU, but at least it works.
-
-This driver provides 352x288 mode by switching the camera into
-quasi-352x288 RGB mode (800 Kbits per frame) essentially limiting
-this mode to 10 frames per second or less, in ideal conditions on
-the bus (USB is shared, after all). The frame rate
-has to be programmed very conservatively. Additional concern is that
-frame rate depends on brightness setting; therefore the picture can
-be good at one brightness and broken at another! I did not want to fix
-the frame rate at slowest setting, but I had to move it pretty much down
-the scale (so that framerate option barely matters). I also noticed that
-camera after first powering up produces frames slightly faster than during
-consecutive uses. All this means that if you use 352x288 (which is
-default), be warned - you may encounter broken picture on first connect;
-try to adjust brightness - brighter image is slower, so USB will be able
-to send all data. However if you regularly use Model 2 cameras you may
-prefer 176x144 which makes perfectly good I420, with no scaling and
-lesser demands on USB (300 Kbits per second, or 26 frames per second).
-
-Another strange effect of 352x288 mode is the fine vertical grid visible
-on some colored surfaces. I am sure it is caused by me not understanding
-what the camera is trying to say. Blame trade secrets for that.
-
-The camera that I had also has a hardware quirk: if disconnected,
-it needs few minutes to "relax" before it can be plugged in again
-(poorly designed USB processor reset circuit?)
-
-[Veo Stingray with Product ID 0x800C is also Model 2, but I haven't
-observed this particular flaw in it.]
-
-Model 2 camera can be programmed for very high sensitivity (even starlight
-may be enough), this makes it convenient for tinkering with. The driver
-code has enough comments to help a programmer to tweak the camera
-as s/he feels necessary.
-
-WHAT YOU NEED:
-
-- A supported IBM PC (C-it) camera (model 1 or 2)
-
-- A Linux box with USB support (2.3/2.4; 2.2 w/backport may work)
-
-- A Video4Linux compatible frame grabber program such as xawtv.
-
-HOW TO COMPILE THE DRIVER:
-
-You need to compile the driver only if you are a developer
-or if you want to make changes to the code. Most distributions
-precompile all modules, so you can go directly to the next
-section "HOW TO USE THE DRIVER".
-
-The ibmcam driver uses usbvideo helper library (module),
-so if you are studying the ibmcam code you will be led there.
-
-The driver itself consists of only one file in usb/ directory:
-ibmcam.c. This file is included into the Linux kernel build
-process if you configure the kernel for CONFIG_USB_IBMCAM.
-Run "make xconfig" and in USB section you will find the IBM
-camera driver. Select it, save the configuration and recompile.
-
-HOW TO USE THE DRIVER:
-
-I recommend to compile driver as a module. This gives you an
-easier access to its configuration. The camera has many more
-settings than V4L can operate, so some settings are done using
-module options.
-
-To begin with, on most modern Linux distributions the driver
-will be automatically loaded whenever you plug the supported
-camera in. Therefore, you don't need to do anything. However
-if you want to experiment with some module parameters then
-you can load and unload the driver manually, with camera
-plugged in or unplugged.
-
-Typically module is installed with command 'modprobe', like this:
-
-# modprobe ibmcam framerate=1
-
-Alternatively you can use 'insmod' in similar fashion:
-
-# insmod /lib/modules/2.x.y/usb/ibmcam.o framerate=1
-
-Module can be inserted with camera connected or disconnected.
-
-The driver can have options, though some defaults are provided.
-
-Driver options: (* indicates that option is model-dependent)
-
-Name Type Range [default] Example
--------------- -------------- -------------- ------------------
-debug Integer 0-9 [0] debug=1
-flags Integer 0-0xFF [0] flags=0x0d
-framerate Integer 0-6 [2] framerate=1
-hue_correction Integer 0-255 [128] hue_correction=115
-init_brightness Integer 0-255 [128] init_brightness=100
-init_contrast Integer 0-255 [192] init_contrast=200
-init_color Integer 0-255 [128] init_color=130
-init_hue Integer 0-255 [128] init_hue=115
-lighting Integer 0-2* [1] lighting=2
-sharpness Integer 0-6* [4] sharpness=3
-size Integer 0-2* [2] size=1
-
-Options for Model 2 only:
-
-Name Type Range [default] Example
--------------- -------------- -------------- ------------------
-init_model2_rg Integer 0..255 [0x70] init_model2_rg=128
-init_model2_rg2 Integer 0..255 [0x2f] init_model2_rg2=50
-init_model2_sat Integer 0..255 [0x34] init_model2_sat=65
-init_model2_yb Integer 0..255 [0xa0] init_model2_yb=200
-
-debug You don't need this option unless you are a developer.
- If you are a developer then you will see in the code
- what values do what. 0=off.
-
-flags This is a bit mask, and you can combine any number of
- bits to produce what you want. Usually you don't want
- any of extra features this option provides:
-
- FLAGS_RETRY_VIDIOCSYNC 1 This bit allows to retry failed
- VIDIOCSYNC ioctls without failing.
- Will work with xawtv, will not
- with xrealproducer. Default is
- not set.
- FLAGS_MONOCHROME 2 Activates monochrome (b/w) mode.
- FLAGS_DISPLAY_HINTS 4 Shows colored pixels which have
- magic meaning to developers.
- FLAGS_OVERLAY_STATS 8 Shows tiny numbers on screen,
- useful only for debugging.
- FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
- FLAGS_SEPARATE_FRAMES 32 Shows each frame separately, as
- it was received from the camera.
- Default (not set) is to mix the
- preceding frame in to compensate
- for occasional loss of Isoc data
- on high frame rates.
- FLAGS_CLEAN_FRAMES 64 Forces "cleanup" of each frame
- prior to use; relevant only if
- FLAGS_SEPARATE_FRAMES is set.
- Default is not to clean frames,
- this is a little faster but may
- produce flicker if frame rate is
- too high and Isoc data gets lost.
- FLAGS_NO_DECODING 128 This flag turns the video stream
- decoder off, and dumps the raw
- Isoc data from the camera into
- the reading process. Useful to
- developers, but not to users.
-
-framerate This setting controls frame rate of the camera. This is
- an approximate setting (in terms of "worst" ... "best")
- because camera changes frame rate depending on amount
- of light available. Setting 0 is slowest, 6 is fastest.
- Beware - fast settings are very demanding and may not
- work well with all video sizes. Be conservative.
-
-hue_correction This highly optional setting allows to adjust the
- hue of the image in a way slightly different from
- what usual "hue" control does. Both controls affect
- YUV colorspace: regular "hue" control adjusts only
- U component, and this "hue_correction" option similarly
- adjusts only V component. However usually it is enough
- to tweak only U or V to compensate for colored light or
- color temperature; this option simply allows more
- complicated correction when and if it is necessary.
-
-init_brightness These settings specify _initial_ values which will be
-init_contrast used to set up the camera. If your V4L application has
-init_color its own controls to adjust the picture then these
-init_hue controls will be used too. These options allow you to
- preconfigure the camera when it gets connected, before
- any V4L application connects to it. Good for webcams.
-
-init_model2_rg These initial settings alter color balance of the
-init_model2_rg2 camera on hardware level. All four settings may be used
-init_model2_sat to tune the camera to specific lighting conditions. These
-init_model2_yb settings only apply to Model 2 cameras.
-
-lighting This option selects one of three hardware-defined
- photosensitivity settings of the camera. 0=bright light,
- 1=Medium (default), 2=Low light. This setting affects
- frame rate: the dimmer the lighting the lower the frame
- rate (because longer exposition time is needed). The
- Model 2 cameras allow values more than 2 for this option,
- thus enabling extremely high sensitivity at cost of frame
- rate, color saturation and imaging sensor noise.
-
-sharpness This option controls smoothing (noise reduction)
- made by camera. Setting 0 is most smooth, setting 6
- is most sharp. Be aware that CMOS sensor used in the
- camera is pretty noisy, so if you choose 6 you will
- be greeted with "snowy" image. Default is 4. Model 2
- cameras do not support this feature.
-
-size This setting chooses one of several image sizes that are
- supported by this driver. Cameras may support more, but
- it's difficult to reverse-engineer all formats.
- Following video sizes are supported:
-
- size=0 128x96 (Model 1 only)
- size=1 160x120
- size=2 176x144
- size=3 320x240 (Model 2 only)
- size=4 352x240 (Model 2 only)
- size=5 352x288
- size=6 640x480 (Model 3 only)
-
- The 352x288 is the native size of the Model 1 sensor
- array, so it's the best resolution the camera can
- yield. The best resolution of Model 2 is 176x144, and
- larger images are produced by stretching the bitmap.
- Model 3 has sensor with 640x480 grid, and it works too,
- but the frame rate will be exceptionally low (1-2 FPS);
- it may be still OK for some applications, like security.
- Choose the image size you need. The smaller image can
- support faster frame rate. Default is 352x288.
-
-For more information and the Troubleshooting FAQ visit this URL:
-
- http://www.linux-usb.org/ibmcam/
-
-WHAT NEEDS TO BE DONE:
-
-- The button on the camera is not used. I don't know how to get to it.
- I know now how to read button on Model 2, but what to do with it?
-
-- Camera reports its status back to the driver; however I don't know
- what returned data means. If camera fails at some initialization
- stage then something should be done, and I don't do that because
- I don't even know that some command failed. This is mostly Model 1
- concern because Model 2 uses different commands which do not return
- status (and seem to complete successfully every time).
-
-- Some flavors of Model 4 NetCameras produce only compressed video
- streams, and I don't know how to decode them.
-
-CREDITS:
-
-The code is based in no small part on the CPiA driver by Johannes Erdfelt,
-Randy Dunlap, and others. Big thanks to them for their pioneering work on that
-and the USB stack.
-
-I also thank John Lightsey for his donation of the Veo Stingray camera.
diff --git a/Documentation/video4linux/m5602.txt b/Documentation/video4linux/m5602.txt
deleted file mode 100644
index 4450ab13f37b..000000000000
--- a/Documentation/video4linux/m5602.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-This document describes the ALi m5602 bridge connected
-to the following supported sensors:
-OmniVision OV9650,
-Samsung s5k83a,
-Samsung s5k4aa,
-Micron mt9m111,
-Pixel plus PO1030
-
-This driver mimics the windows drivers, which have a braindead implementation sending bayer-encoded frames at VGA resolution.
-In a perfect world we should be able to reprogram the m5602 and the connected sensor in hardware instead, supporting a range of resolutions and pixelformats
-
-Anyway, have fun and please report any bugs to m560x-driver-devel@lists.sourceforge.net
diff --git a/Documentation/video4linux/ov511.txt b/Documentation/video4linux/ov511.txt
deleted file mode 100644
index b3326b167ada..000000000000
--- a/Documentation/video4linux/ov511.txt
+++ /dev/null
@@ -1,288 +0,0 @@
--------------------------------------------------------------------------------
-Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC
--------------------------------------------------------------------------------
-
-Author: Mark McClelland
-Homepage: http://alpha.dyndns.org/ov511
-
-INTRODUCTION:
-
-This is a driver for the OV511, a USB-only chip used in many "webcam" devices.
-Any camera using the OV511/OV511+ and the OV6620/OV7610/20/20AE should work.
-Video capture devices that use the Philips SAA7111A decoder also work. It
-supports streaming and capture of color or monochrome video via the Video4Linux
-API. Most V4L apps are compatible with it. Most resolutions with a width and
-height that are a multiple of 8 are supported.
-
-If you need more information, please visit the OV511 homepage at the above URL.
-
-WHAT YOU NEED:
-
-- If you want to help with the development, get the chip's specification docs at
- http://www.ovt.com/omniusbp.html
-
-- A Video4Linux compatible frame grabber program (I recommend vidcat and xawtv)
- vidcat is part of the w3cam package: http://mpx.freeshell.net/
- xawtv is available at: http://linux.bytesex.org/xawtv/
-
-HOW TO USE IT:
-
-Note: These are simplified instructions. For complete instructions see:
- http://alpha.dyndns.org/ov511/install.html
-
-You must have first compiled USB support, support for your specific USB host
-controller (UHCI or OHCI), and Video4Linux support for your kernel (I recommend
-making them modules.) Make sure "Enforce bandwidth allocation" is NOT enabled.
-
-Next, (as root):
-
- modprobe usbcore
- modprobe usb-uhci <OR> modprobe usb-ohci
- modprobe videodev
- modprobe ov511
-
-If it is not already there (it usually is), create the video device:
-
- mknod /dev/video0 c 81 0
-
-Optionally, symlink /dev/video to /dev/video0
-
-You will have to set permissions on this device to allow you to read/write
-from it:
-
- chmod 666 /dev/video
- chmod 666 /dev/video0 (if necessary)
-
-Now you are ready to run a video app! Both vidcat and xawtv work well for me
-at 640x480.
-
-[Using vidcat:]
-
- vidcat -s 640x480 -p c > test.jpg
- xview test.jpg
-
-[Using xawtv:]
-
-From the main xawtv directory:
-
- make clean
- ./configure
- make
- make install
-
-Now you should be able to run xawtv. Right click for the options dialog.
-
-MODULE PARAMETERS:
-
- You can set these with: insmod ov511 NAME=VALUE
- There is currently no way to set these on a per-camera basis.
-
- NAME: autobright
- TYPE: integer (Boolean)
- DEFAULT: 1
- DESC: Brightness is normally under automatic control and can't be set
- manually by the video app. Set to 0 for manual control.
-
- NAME: autogain
- TYPE: integer (Boolean)
- DEFAULT: 1
- DESC: Auto Gain Control enable. This feature is not yet implemented.
-
- NAME: autoexp
- TYPE: integer (Boolean)
- DEFAULT: 1
- DESC: Auto Exposure Control enable. This feature is not yet implemented.
-
- NAME: debug
- TYPE: integer (0-6)
- DEFAULT: 3
- DESC: Sets the threshold for printing debug messages. The higher the value,
- the more is printed. The levels are cumulative, and are as follows:
- 0=no debug messages
- 1=init/detection/unload and other significant messages
- 2=some warning messages
- 3=config/control function calls
- 4=most function calls and data parsing messages
- 5=highly repetitive mesgs
-
- NAME: snapshot
- TYPE: integer (Boolean)
- DEFAULT: 0
- DESC: Set to 1 to enable snapshot mode. read()/VIDIOCSYNC will block until
- the snapshot button is pressed. Note: enabling this mode disables
- /proc/video/ov511/<minor#>/button
-
- NAME: cams
- TYPE: integer (1-4 for OV511, 1-31 for OV511+)
- DEFAULT: 1
- DESC: Number of cameras allowed to stream simultaneously on a single bus.
- Values higher than 1 reduce the data rate of each camera, allowing two
- or more to be used at once. If you have a complicated setup involving
- both OV511 and OV511+ cameras, trial-and-error may be necessary for
- finding the optimum setting.
-
- NAME: compress
- TYPE: integer (Boolean)
- DEFAULT: 0
- DESC: Set this to 1 to turn on the camera's compression engine. This can
- potentially increase the frame rate at the expense of quality, if you
- have a fast CPU. You must load the proper compression module for your
- camera before starting your application (ov511_decomp or ov518_decomp).
-
- NAME: testpat
- TYPE: integer (Boolean)
- DEFAULT: 0
- DESC: This configures the camera's sensor to transmit a colored test-pattern
- instead of an image. This does not work correctly yet.
-
- NAME: dumppix
- TYPE: integer (0-2)
- DEFAULT: 0
- DESC: Dumps raw pixel data and skips post-processing and format conversion.
- It is for debugging purposes only. Options are:
- 0: Disable (default)
- 1: Dump raw data from camera, excluding headers and trailers
- 2: Dumps data exactly as received from camera
-
- NAME: led
- TYPE: integer (0-2)
- DEFAULT: 1 (Always on)
- DESC: Controls whether the LED (the little light) on the front of the camera
- is always off (0), always on (1), or only on when driver is open (2).
- This is not supported with the OV511, and might only work with certain
- cameras (ones that actually have the LED wired to the control pin, and
- not just hard-wired to be on all the time).
-
- NAME: dump_bridge
- TYPE: integer (Boolean)
- DEFAULT: 0
- DESC: Dumps the bridge (OV511[+] or OV518[+]) register values to the system
- log. Only useful for serious debugging/development purposes.
-
- NAME: dump_sensor
- TYPE: integer (Boolean)
- DEFAULT: 0
- DESC: Dumps the sensor register values to the system log. Only useful for
- serious debugging/development purposes.
-
- NAME: printph
- TYPE: integer (Boolean)
- DEFAULT: 0
- DESC: Setting this to 1 will dump the first 12 bytes of each isoc frame. This
- is only useful if you are trying to debug problems with the isoc data
- stream (i.e.: camera initializes, but vidcat hangs until Ctrl-C). Be
- warned that this dumps a large number of messages to your kernel log.
-
- NAME: phy, phuv, pvy, pvuv, qhy, qhuv, qvy, qvuv
- TYPE: integer (0-63 for phy and phuv, 0-255 for rest)
- DEFAULT: OV511 default values
- DESC: These are registers 70h - 77h of the OV511, which control the
- prediction ranges and quantization thresholds of the compressor, for
- the Y and UV channels in the horizontal and vertical directions. See
- the OV511 or OV511+ data sheet for more detailed descriptions. These
- normally do not need to be changed.
-
- NAME: lightfreq
- TYPE: integer (0, 50, or 60)
- DEFAULT: 0 (use sensor default)
- DESC: Sets the sensor to match your lighting frequency. This can reduce the
- appearance of "banding", i.e. horizontal lines or waves of light and
- dark that are often caused by artificial lighting. Valid values are:
- 0 - Use default (depends on sensor, most likely 60 Hz)
- 50 - For European and Asian 50 Hz power
- 60 - For American 60 Hz power
-
- NAME: bandingfilter
- TYPE: integer (Boolean)
- DEFAULT: 0 (off)
- DESC: Enables the sensor´s banding filter exposure algorithm. This reduces
- or stabilizes the "banding" caused by some artificial light sources
- (especially fluorescent). You might have to set lightfreq correctly for
- this to work right. As an added bonus, this sometimes makes it
- possible to capture your monitor´s output.
-
- NAME: fastset
- TYPE: integer (Boolean)
- DEFAULT: 0 (off)
- DESC: Allows picture settings (brightness, contrast, color, and hue) to take
- effect immediately, even in the middle of a frame. This reduces the
- time to change settings, but can ruin frames during the change. Only
- affects OmniVision sensors.
-
- NAME: force_palette
- TYPE: integer (Boolean)
- DEFAULT: 0 (off)
- DESC: Forces the palette (color format) to a specific value. If an
- application requests a different palette, it will be rejected, thereby
- forcing it to try others until it succeeds. This is useful for forcing
- greyscale mode with a color camera, for example. Supported modes are:
- 0 (Allows all the following formats)
- 1 VIDEO_PALETTE_GREY (Linear greyscale)
- 10 VIDEO_PALETTE_YUV420 (YUV 4:2:0 Planar)
- 15 VIDEO_PALETTE_YUV420P (YUV 4:2:0 Planar, same as 10)
-
- NAME: backlight
- TYPE: integer (Boolean)
- DEFAULT: 0 (off)
- DESC: Setting this flag changes the exposure algorithm for OmniVision sensors
- such that objects in the camera's view (i.e. your head) can be clearly
- seen when they are illuminated from behind. It reduces or eliminates
- the sensor's auto-exposure function, so it should only be used when
- needed. Additionally, it is only supported with the OV6620 and OV7620.
-
- NAME: unit_video
- TYPE: Up to 16 comma-separated integers
- DEFAULT: 0,0,0... (automatically assign the next available minor(s))
- DESC: You can specify up to 16 minor numbers to be assigned to ov511 devices.
- For example, "unit_video=1,3" will make the driver use /dev/video1 and
- /dev/video3 for the first two devices it detects. Additional devices
- will be assigned automatically starting at the first available device
- node (/dev/video0 in this case). Note that you cannot specify 0 as a
- minor number. This feature requires kernel version 2.4.5 or higher.
-
- NAME: remove_zeros
- TYPE: integer (Boolean)
- DEFAULT: 0 (do not skip any incoming data)
- DESC: Setting this to 1 will remove zero-padding from incoming data. This
- will compensate for the blocks of corruption that can appear when the
- camera cannot keep up with the speed of the USB bus (eg. at low frame
- resolutions). This feature is always enabled when compression is on.
-
- NAME: mirror
- TYPE: integer (Boolean)
- DEFAULT: 0 (off)
- DESC: Setting this to 1 will reverse ("mirror") the image horizontally. This
- might be necessary if your camera has a custom lens assembly. This has
- no effect with video capture devices.
-
- NAME: ov518_color
- TYPE: integer (Boolean)
- DEFAULT: 0 (off)
- DESC: Enable OV518 color support. This is off by default since it doesn't
- work most of the time. If you want to try it, you must also load
- ov518_decomp with the "nouv=0" parameter. If you get improper colors or
- diagonal lines through the image, restart your video app and try again.
- Repeat as necessary.
-
-WORKING FEATURES:
- o Color streaming/capture at most widths and heights that are multiples of 8.
- o Monochrome (use force_palette=1 to enable)
- o Setting/getting of saturation, contrast, brightness, and hue (only some of
- them work the OV7620 and OV7620AE)
- o /proc status reporting
- o SAA7111A video capture support at 320x240 and 640x480
- o Compression support
- o SMP compatibility
-
-HOW TO CONTACT ME:
-
-You can email me at mark@alpha.dyndns.org . Please prefix the subject line
-with "OV511: " so that I am certain to notice your message.
-
-CREDITS:
-
-The code is based in no small part on the CPiA driver by Johannes Erdfelt,
-Randy Dunlap, and others. Big thanks to them for their pioneering work on that
-and the USB stack. Thanks to Bret Wallach for getting camera reg IO, ISOC, and
-image capture working. Thanks to Orion Sky Lawlor, Kevin Moore, and Claudio
-Matsuoka for their work as well.
diff --git a/Documentation/video4linux/se401.txt b/Documentation/video4linux/se401.txt
deleted file mode 100644
index bd6526ec8dd7..000000000000
--- a/Documentation/video4linux/se401.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-Linux driver for SE401 based USB cameras
-
-Copyright, 2001, Jeroen Vreeken
-
-
-INTRODUCTION:
-
-The SE401 chip is the used in low-cost usb webcams.
-It is produced by Endpoints Inc. (www.endpoints.com).
-It interfaces directly to a cmos image sensor and USB. The only other major
-part in a se401 based camera is a dram chip.
-
-The following cameras are known to work with this driver:
-
-Aox se401 (non-branded) cameras
-Philips PVCV665 USB VGA webcam 'Vesta Fun'
-Kensington VideoCAM PC Camera Model 67014
-Kensington VideoCAM PC Camera Model 67015
-Kensington VideoCAM PC Camera Model 67016
-Kensington VideoCAM PC Camera Model 67017
-
-
-WHAT YOU NEED:
-
-- USB support
-- VIDEO4LINUX support
-
-More information about USB support for linux can be found at:
-http://www.linux-usb.org
-
-
-MODULE OPTIONS:
-
-When the driver is compiled as a module you can also use the 'flickerless'
-option. With it exposure is limited to values that do not interfere with the
-net frequency. Valid options for this option are 0, 50 and 60. (0=disable,
-50=50hz, 60=60hz)
-
-
-KNOWN PROBLEMS:
-
-The driver works fine with the usb-ohci and uhci host controller drivers,
-the default settings also work with usb-uhci. But sending more than one bulk
-transfer at a time with usb-uhci doesn't work yet.
-Users of usb-ohci and uhci can safely enlarge SE401_NUMSBUF in se401.h in
-order to increase the throughput (and thus framerate).
-
-
-HELP:
-
-The latest info on this driver can be found at:
-http://members.chello.nl/~j.vreeken/se401/
-And questions to me can be send to:
-pe1rxq@amsat.org
diff --git a/Documentation/video4linux/si470x.txt b/Documentation/video4linux/si470x.txt
index 3a7823e01b4d..98c32925eb39 100644
--- a/Documentation/video4linux/si470x.txt
+++ b/Documentation/video4linux/si470x.txt
@@ -53,6 +53,9 @@ Testing is usually done with most application under Debian/testing:
- kradio - Comfortable Radio Application for KDE
- radio - ncurses-based radio application
- mplayer - The Ultimate Movie Player For Linux
+- v4l2-ctl - Collection of command line video4linux utilities
+For example, you can use:
+v4l2-ctl -d /dev/radio0 --set-ctrl=volume=10,mute=0 --set-freq=95.21 --all
There is also a library libv4l, which can be used. It's going to have a function
for frequency seeking, either by using hardware functionality as in radio-si470x
@@ -75,8 +78,10 @@ commands. Please adjust the audio devices to your needs (/dev/dsp* and hw:x,x).
If you just want to test audio (very poor quality):
cat /dev/dsp1 > /dev/dsp
-If you use OSS try:
+If you use sox + OSS try:
sox -2 --endian little -r 96000 -t oss /dev/dsp1 -t oss /dev/dsp
+or using sox + alsa:
+sox --endian little -c 2 -S -r 96000 -t alsa hw:1 -t alsa -r 96000 hw:0
If you use arts try:
arecord -D hw:1,0 -r96000 -c2 -f S16_LE | artsdsp aplay -B -
diff --git a/Documentation/video4linux/soc-camera.txt b/Documentation/video4linux/soc-camera.txt
index 3f87c7da4ca2..f62fcdbc8b9f 100644
--- a/Documentation/video4linux/soc-camera.txt
+++ b/Documentation/video4linux/soc-camera.txt
@@ -9,32 +9,36 @@ The following terms are used in this document:
of connecting to a variety of systems and interfaces, typically uses i2c for
control and configuration, and a parallel or a serial bus for data.
- camera host - an interface, to which a camera is connected. Typically a
- specialised interface, present on many SoCs, e.g., PXA27x and PXA3xx, SuperH,
+ specialised interface, present on many SoCs, e.g. PXA27x and PXA3xx, SuperH,
AVR32, i.MX27, i.MX31.
- camera host bus - a connection between a camera host and a camera. Can be
- parallel or serial, consists of data and control lines, e.g., clock, vertical
+ parallel or serial, consists of data and control lines, e.g. clock, vertical
and horizontal synchronization signals.
Purpose of the soc-camera subsystem
-----------------------------------
-The soc-camera subsystem provides a unified API between camera host drivers and
-camera sensor drivers. It implements a V4L2 interface to the user, currently
-only the mmap method is supported.
+The soc-camera subsystem initially provided a unified API between camera host
+drivers and camera sensor drivers. Later the soc-camera sensor API has been
+replaced with the V4L2 standard subdev API. This also made camera driver re-use
+with non-soc-camera hosts possible. The camera host API to the soc-camera core
+has been preserved.
-This subsystem has been written to connect drivers for System-on-Chip (SoC)
-video capture interfaces with drivers for CMOS camera sensor chips to enable
-the reuse of sensor drivers with various hosts. The subsystem has been designed
-to support multiple camera host interfaces and multiple cameras per interface,
-although most applications have only one camera sensor.
+Soc-camera implements a V4L2 interface to the user, currently only the "mmap"
+method is supported by host drivers. However, the soc-camera core also provides
+support for the "read" method.
+
+The subsystem has been designed to support multiple camera host interfaces and
+multiple cameras per interface, although most applications have only one camera
+sensor.
Existing drivers
----------------
-As of 2.6.27-rc4 there are two host drivers in the mainline: pxa_camera.c for
-PXA27x SoCs and sh_mobile_ceu_camera.c for SuperH SoCs, and four sensor drivers:
-mt9m001.c, mt9m111.c, mt9v022.c and a generic soc_camera_platform.c driver. This
-list is not supposed to be updated, look for more examples in your tree.
+As of 3.7 there are seven host drivers in the mainline: atmel-isi.c,
+mx1_camera.c (broken, scheduled for removal), mx2_camera.c, mx3_camera.c,
+omap1_camera.c, pxa_camera.c, sh_mobile_ceu_camera.c, and multiple sensor
+drivers under drivers/media/i2c/soc_camera/.
Camera host API
---------------
@@ -45,38 +49,37 @@ soc_camera_host_register(struct soc_camera_host *);
function. The host object can be initialized as follows:
-static struct soc_camera_host pxa_soc_camera_host = {
- .drv_name = PXA_CAM_DRV_NAME,
- .ops = &pxa_soc_camera_host_ops,
-};
+ struct soc_camera_host *ici;
+ ici->drv_name = DRV_NAME;
+ ici->ops = &camera_host_ops;
+ ici->priv = pcdev;
+ ici->v4l2_dev.dev = &pdev->dev;
+ ici->nr = pdev->id;
All camera host methods are passed in a struct soc_camera_host_ops:
-static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
+static struct soc_camera_host_ops camera_host_ops = {
.owner = THIS_MODULE,
- .add = pxa_camera_add_device,
- .remove = pxa_camera_remove_device,
- .suspend = pxa_camera_suspend,
- .resume = pxa_camera_resume,
- .set_fmt_cap = pxa_camera_set_fmt_cap,
- .try_fmt_cap = pxa_camera_try_fmt_cap,
- .init_videobuf = pxa_camera_init_videobuf,
- .reqbufs = pxa_camera_reqbufs,
- .poll = pxa_camera_poll,
- .querycap = pxa_camera_querycap,
- .try_bus_param = pxa_camera_try_bus_param,
- .set_bus_param = pxa_camera_set_bus_param,
+ .add = camera_add_device,
+ .remove = camera_remove_device,
+ .set_fmt = camera_set_fmt_cap,
+ .try_fmt = camera_try_fmt_cap,
+ .init_videobuf2 = camera_init_videobuf2,
+ .poll = camera_poll,
+ .querycap = camera_querycap,
+ .set_bus_param = camera_set_bus_param,
+ /* The rest of host operations are optional */
};
.add and .remove methods are called when a sensor is attached to or detached
-from the host, apart from performing host-internal tasks they shall also call
-sensor driver's .init and .release methods respectively. .suspend and .resume
-methods implement host's power-management functionality and its their
-responsibility to call respective sensor's methods. .try_bus_param and
-.set_bus_param are used to negotiate physical connection parameters between the
-host and the sensor. .init_videobuf is called by soc-camera core when a
-video-device is opened, further video-buffer management is implemented completely
-by the specific camera host driver. The rest of the methods are called from
+from the host. .set_bus_param is used to configure physical connection
+parameters between the host and the sensor. .init_videobuf2 is called by
+soc-camera core when a video-device is opened, the host driver would typically
+call vb2_queue_init() in this method. Further video-buffer management is
+implemented completely by the specific camera host driver. If the host driver
+supports non-standard pixel format conversion, it should implement a
+.get_formats and, possibly, a .put_formats operations. See below for more
+details about format conversion. The rest of the methods are called from
respective V4L2 operations.
Camera API
@@ -84,37 +87,21 @@ Camera API
Sensor drivers can use struct soc_camera_link, typically provided by the
platform, and used to specify to which camera host bus the sensor is connected,
-and arbitrarily provide platform .power and .reset methods for the camera.
-soc_camera_device_register() and soc_camera_device_unregister() functions are
-used to add a sensor driver to or remove one from the system. The registration
-function takes a pointer to struct soc_camera_device as the only parameter.
-This struct can be initialized as follows:
-
- /* link to driver operations */
- icd->ops = &mt9m001_ops;
- /* link to the underlying physical (e.g., i2c) device */
- icd->control = &client->dev;
- /* window geometry */
- icd->x_min = 20;
- icd->y_min = 12;
- icd->x_current = 20;
- icd->y_current = 12;
- icd->width_min = 48;
- icd->width_max = 1280;
- icd->height_min = 32;
- icd->height_max = 1024;
- icd->y_skip_top = 1;
- /* camera bus ID, typically obtained from platform data */
- icd->iface = icl->bus_id;
-
-struct soc_camera_ops provides .probe and .remove methods, which are called by
-the soc-camera core, when a camera is matched against or removed from a camera
-host bus, .init, .release, .suspend, and .resume are called from the camera host
-driver as discussed above. Other members of this struct provide respective V4L2
-functionality.
-
-struct soc_camera_device also links to an array of struct soc_camera_data_format,
-listing pixel formats, supported by the camera.
+and optionally provide platform .power and .reset methods for the camera. This
+struct is provided to the camera driver via the I2C client device platform data
+and can be obtained, using the soc_camera_i2c_to_link() macro. Care should be
+taken, when using soc_camera_vdev_to_subdev() and when accessing struct
+soc_camera_device, using v4l2_get_subdev_hostdata(): both only work, when
+running on an soc-camera host. The actual camera driver operation is implemented
+using the V4L2 subdev API. Additionally soc-camera camera drivers can use
+auxiliary soc-camera helper functions like soc_camera_power_on() and
+soc_camera_power_off(), which switch regulators, provided by the platform and call
+board-specific power switching methods. soc_camera_apply_board_flags() takes
+camera bus configuration capability flags and applies any board transformations,
+e.g. signal polarity inversion. soc_mbus_get_fmtdesc() can be used to obtain a
+pixel format descriptor, corresponding to a certain media-bus pixel format code.
+soc_camera_limit_side() can be used to restrict beginning and length of a frame
+side, based on camera capabilities.
VIDIOC_S_CROP and VIDIOC_S_FMT behaviour
----------------------------------------
@@ -153,8 +140,25 @@ implemented.
User window geometry is kept in .user_width and .user_height fields in struct
soc_camera_device and used by the soc-camera core and host drivers. The core
updates these fields upon successful completion of a .s_fmt() call, but if these
-fields change elsewhere, e.g., during .s_crop() processing, the host driver is
+fields change elsewhere, e.g. during .s_crop() processing, the host driver is
responsible for updating them.
+Format conversion
+-----------------
+
+V4L2 distinguishes between pixel formats, as they are stored in memory, and as
+they are transferred over a media bus. Soc-camera provides support to
+conveniently manage these formats. A table of standard transformations is
+maintained by soc-camera core, which describes, what FOURCC pixel format will
+be obtained, if a media-bus pixel format is stored in memory according to
+certain rules. E.g. if V4L2_MBUS_FMT_YUYV8_2X8 data is sampled with 8 bits per
+sample and stored in memory in the little-endian order with no gaps between
+bytes, data in memory will represent the V4L2_PIX_FMT_YUYV FOURCC format. These
+standard transformations will be used by soc-camera or by camera host drivers to
+configure camera drivers to produce the FOURCC format, requested by the user,
+using the VIDIOC_S_FMT ioctl(). Apart from those standard format conversions,
+host drivers can also provide their own conversion rules by implementing a
+.get_formats and, if required, a .put_formats methods.
+
--
Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
diff --git a/Documentation/video4linux/stv680.txt b/Documentation/video4linux/stv680.txt
deleted file mode 100644
index e3de33645308..000000000000
--- a/Documentation/video4linux/stv680.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-Linux driver for STV0680 based USB cameras
-
-Copyright, 2001, Kevin Sisson
-
-
-INTRODUCTION:
-
-STMicroelectronics produces the STV0680B chip, which comes in two
-types, -001 and -003. The -003 version allows the recording and downloading
-of sound clips from the camera, and allows a flash attachment. Otherwise,
-it uses the same commands as the -001 version. Both versions support a
-variety of SDRAM sizes and sensors, allowing for a maximum of 26 VGA or 20
-CIF pictures. The STV0680 supports either a serial or a usb interface, and
-video is possible through the usb interface.
-
-The following cameras are known to work with this driver, although any
-camera with Vendor/Product codes of 0553/0202 should work:
-
-Aiptek Pencam (various models)
-Nisis QuickPix 2
-Radio Shack 'Kid's digital camera' (#60-1207)
-At least one Trust Spycam model
-Several other European brand models
-
-WHAT YOU NEED:
-
-- USB support
-- VIDEO4LINUX support
-
-More information about USB support for linux can be found at:
-http://www.linux-usb.org
-
-
-MODULE OPTIONS:
-
-When the driver is compiled as a module, you can set a "swapRGB=1"
-option, if necessary, for those applications that require it
-(such as xawtv). However, the driver should detect and set this
-automatically, so this option should not normally be used.
-
-
-KNOWN PROBLEMS:
-
-The driver seems to work better with the usb-ohci than the usb-uhci host
-controller driver.
-
-HELP:
-
-The latest info on this driver can be found at:
-http://personal.clt.bellsouth.net/~kjsisson or at
-http://stv0680-usb.sourceforge.net
-
-Any questions to me can be send to: kjsisson@bellsouth.net
diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
index cfe52c798d74..676f87366025 100644
--- a/Documentation/video4linux/v4l2-controls.txt
+++ b/Documentation/video4linux/v4l2-controls.txt
@@ -715,14 +715,20 @@ a control of this type whenever the first control belonging to a new control
class is added.
-Proposals for Extensions
-========================
+Adding Notify Callbacks
+=======================
+
+Sometimes the platform or bridge driver needs to be notified when a control
+from a sub-device driver changes. You can set a notify callback by calling
+this function:
-Some ideas for future extensions to the spec:
+void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl,
+ void (*notify)(struct v4l2_ctrl *ctrl, void *priv), void *priv);
-1) Add a V4L2_CTRL_FLAG_HEX to have values shown as hexadecimal instead of
-decimal. Useful for e.g. video_mute_yuv.
+Whenever the give control changes value the notify callback will be called
+with a pointer to the control and the priv pointer that was passed with
+v4l2_ctrl_notify. Note that the control's handler lock is held when the
+notify function is called.
-2) It is possible to mark in the controls array which controls have been
-successfully written and which failed by for example adding a bit to the
-control ID. Not sure if it is worth the effort, though.
+There can be only one notify function per control handler. Any attempt
+to set another notify function will cause a WARN_ON.
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index b89567ad04b7..a300b283a1a0 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -68,8 +68,7 @@ Structure of the framework
The framework closely resembles the driver structure: it has a v4l2_device
struct for the device instance data, a v4l2_subdev struct to refer to
sub-device instances, the video_device struct stores V4L2 device node data
-and in the future a v4l2_fh struct will keep track of filehandle instances
-(this is not yet implemented).
+and the v4l2_fh struct keeps track of filehandle instances.
The V4L2 framework also optionally integrates with the media framework. If a
driver sets the struct v4l2_device mdev field, sub-devices and video nodes
diff --git a/Documentation/video4linux/w9968cf.txt b/Documentation/video4linux/w9968cf.txt
deleted file mode 100644
index 9649450f3b90..000000000000
--- a/Documentation/video4linux/w9968cf.txt
+++ /dev/null
@@ -1,458 +0,0 @@
-
- W996[87]CF JPEG USB Dual Mode Camera Chip
- Driver for Linux 2.6 (basic version)
- =========================================
-
- - Documentation -
-
-
-Index
-=====
-1. Copyright
-2. Disclaimer
-3. License
-4. Overview
-5. Supported devices
-6. Module dependencies
-7. Module loading
-8. Module parameters
-9. Contact information
-10. Credits
-
-
-1. Copyright
-============
-Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>
-
-
-2. Disclaimer
-=============
-Winbond is a trademark of Winbond Electronics Corporation.
-This software is not sponsored or developed by Winbond.
-
-
-3. License
-==========
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You 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.
-
-
-4. Overview
-===========
-This driver supports the video streaming capabilities of the devices mounting
-Winbond W9967CF and Winbond W9968CF JPEG USB Dual Mode Camera Chips. OV681
-based cameras should be supported as well.
-
-The driver is divided into two modules: the basic one, "w9968cf", is needed for
-the supported devices to work; the second one, "w9968cf-vpp", is an optional
-module, which provides some useful video post-processing functions like video
-decoding, up-scaling and colour conversions.
-
-Note that the official kernels do neither include nor support the second
-module for performance purposes. Therefore, it is always recommended to
-download and install the latest and complete release of the driver,
-replacing the existing one, if present.
-
-The latest and full-featured version of the W996[87]CF driver can be found at:
-http://www.linux-projects.org. Please refer to the documentation included in
-that package, if you are going to use it.
-
-Up to 32 cameras can be handled at the same time. They can be connected and
-disconnected from the host many times without turning off the computer, if
-your system supports the hotplug facility.
-
-To change the default settings for each camera, many parameters can be passed
-through command line when the module is loaded into memory.
-
-The driver relies on the Video4Linux, USB and I2C core modules. It has been
-designed to run properly on SMP systems as well. An additional module,
-"ovcamchip", is mandatory; it provides support for some OmniVision image
-sensors connected to the W996[87]CF chips; if found in the system, the module
-will be automatically loaded by default (provided that the kernel has been
-compiled with the automatic module loading option).
-
-
-5. Supported devices
-====================
-At the moment, known W996[87]CF and OV681 based devices are:
-- Aroma Digi Pen VGA Dual Mode ADG-5000 (unknown image sensor)
-- AVerMedia AVerTV USB (SAA7111A, Philips FI1216Mk2 tuner, PT2313L audio chip)
-- Creative Labs Video Blaster WebCam Go (OmniVision OV7610 sensor)
-- Creative Labs Video Blaster WebCam Go Plus (OmniVision OV7620 sensor)
-- Lebon LDC-035A (unknown image sensor)
-- Ezonics EZ-802 EZMega Cam (OmniVision OV8610C sensor)
-- OmniVision OV8610-EDE (OmniVision OV8610 sensor)
-- OPCOM Digi Pen VGA Dual Mode Pen Camera (unknown image sensor)
-- Pretec Digi Pen-II (OmniVision OV7620 sensor)
-- Pretec DigiPen-480 (OmniVision OV8610 sensor)
-
-If you know any other W996[87]CF or OV681 based cameras, please contact me.
-
-The list above does not imply that all those devices work with this driver: up
-until now only webcams that have an image sensor supported by the "ovcamchip"
-module work. Kernel messages will always tell you whether this is case.
-
-Possible external microcontrollers of those webcams are not supported: this
-means that still images cannot be downloaded from the device memory.
-
-Furthermore, it's worth to note that I was only able to run tests on my
-"Creative Labs Video Blaster WebCam Go". Donations of other models, for
-additional testing and full support, would be much appreciated.
-
-
-6. Module dependencies
-======================
-For it to work properly, the driver needs kernel support for Video4Linux, USB
-and I2C, and the "ovcamchip" module for the image sensor. Make sure you are not
-actually using any external "ovcamchip" module, given that the W996[87]CF
-driver depends on the version of the module present in the official kernels.
-
-The following options of the kernel configuration file must be enabled and
-corresponding modules must be compiled:
-
- # Multimedia devices
- #
- CONFIG_VIDEO_DEV=m
-
- # I2C support
- #
- CONFIG_I2C=m
-
-The I2C core module can be compiled statically in the kernel as well.
-
- # OmniVision Camera Chip support
- #
- CONFIG_VIDEO_OVCAMCHIP=m
-
- # USB support
- #
- CONFIG_USB=m
-
-In addition, depending on the hardware being used, only one of the modules
-below is necessary:
-
- # USB Host Controller Drivers
- #
- CONFIG_USB_EHCI_HCD=m
- CONFIG_USB_UHCI_HCD=m
- CONFIG_USB_OHCI_HCD=m
-
-And finally:
-
- # USB Multimedia devices
- #
- CONFIG_USB_W9968CF=m
-
-
-7. Module loading
-=================
-To use the driver, it is necessary to load the "w9968cf" module into memory
-after every other module required.
-
-Loading can be done this way, from root:
-
- [root@localhost home]# modprobe usbcore
- [root@localhost home]# modprobe i2c-core
- [root@localhost home]# modprobe videodev
- [root@localhost home]# modprobe w9968cf
-
-At this point the pertinent devices should be recognized: "dmesg" can be used
-to analyze kernel messages:
-
- [user@localhost home]$ dmesg
-
-There are a lot of parameters the module can use to change the default
-settings for each device. To list every possible parameter with a brief
-explanation about them and which syntax to use, it is recommended to run the
-"modinfo" command:
-
- [root@locahost home]# modinfo w9968cf
-
-
-8. Module parameters
-====================
-Module parameters are listed below:
--------------------------------------------------------------------------------
-Name: ovmod_load
-Type: bool
-Syntax: <0|1>
-Description: Automatic 'ovcamchip' module loading: 0 disabled, 1 enabled.
- If enabled, 'insmod' searches for the required 'ovcamchip'
- module in the system, according to its configuration, and
- loads that module automatically. This action is performed as
- once soon as the 'w9968cf' module is loaded into memory.
-Default: 1
--------------------------------------------------------------------------------
-Name: simcams
-Type: int
-Syntax: <n>
-Description: Number of cameras allowed to stream simultaneously.
- n may vary from 0 to 32.
-Default: 32
--------------------------------------------------------------------------------
-Name: video_nr
-Type: int array (min = 0, max = 32)
-Syntax: <-1|n[,...]>
-Description: Specify V4L minor mode number.
- -1 = use next available
- n = use minor number n
- You can specify up to 32 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- recognized camera and use auto for the first one and for every
- other camera.
-Default: -1
--------------------------------------------------------------------------------
-Name: packet_size
-Type: int array (min = 0, max = 32)
-Syntax: <n[,...]>
-Description: Specify the maximum data payload size in bytes for alternate
- settings, for each device. n is scaled between 63 and 1023.
-Default: 1023
--------------------------------------------------------------------------------
-Name: max_buffers
-Type: int array (min = 0, max = 32)
-Syntax: <n[,...]>
-Description: For advanced users.
- Specify the maximum number of video frame buffers to allocate
- for each device, from 2 to 32.
-Default: 2
--------------------------------------------------------------------------------
-Name: double_buffer
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: Hardware double buffering: 0 disabled, 1 enabled.
- It should be enabled if you want smooth video output: if you
- obtain out of sync. video, disable it, or try to
- decrease the 'clockdiv' module parameter value.
-Default: 1 for every device.
--------------------------------------------------------------------------------
-Name: clamping
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: Video data clamping: 0 disabled, 1 enabled.
-Default: 0 for every device.
--------------------------------------------------------------------------------
-Name: filter_type
-Type: int array (min = 0, max = 32)
-Syntax: <0|1|2[,...]>
-Description: Video filter type.
- 0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
- The filter is used to reduce noise and aliasing artifacts
- produced by the CCD or CMOS image sensor.
-Default: 0 for every device.
--------------------------------------------------------------------------------
-Name: largeview
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: Large view: 0 disabled, 1 enabled.
-Default: 1 for every device.
--------------------------------------------------------------------------------
-Name: upscaling
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: Software scaling (for non-compressed video only):
- 0 disabled, 1 enabled.
- Disable it if you have a slow CPU or you don't have enough
- memory.
-Default: 0 for every device.
-Note: If 'w9968cf-vpp' is not present, this parameter is set to 0.
--------------------------------------------------------------------------------
-Name: decompression
-Type: int array (min = 0, max = 32)
-Syntax: <0|1|2[,...]>
-Description: Software video decompression:
- 0 = disables decompression
- (doesn't allow formats needing decompression).
- 1 = forces decompression
- (allows formats needing decompression only).
- 2 = allows any permitted formats.
- Formats supporting (de)compressed video are YUV422P and
- YUV420P/YUV420 in any resolutions where width and height are
- multiples of 16.
-Default: 2 for every device.
-Note: If 'w9968cf-vpp' is not present, forcing decompression is not
- allowed; in this case this parameter is set to 2.
--------------------------------------------------------------------------------
-Name: force_palette
-Type: int array (min = 0, max = 32)
-Syntax: <0|9|10|13|15|8|7|1|6|3|4|5[,...]>
-Description: Force picture palette.
- In order:
- 0 = Off - allows any of the following formats:
- 9 = UYVY 16 bpp - Original video, compression disabled
- 10 = YUV420 12 bpp - Original video, compression enabled
- 13 = YUV422P 16 bpp - Original video, compression enabled
- 15 = YUV420P 12 bpp - Original video, compression enabled
- 8 = YUVY 16 bpp - Software conversion from UYVY
- 7 = YUV422 16 bpp - Software conversion from UYVY
- 1 = GREY 8 bpp - Software conversion from UYVY
- 6 = RGB555 16 bpp - Software conversion from UYVY
- 3 = RGB565 16 bpp - Software conversion from UYVY
- 4 = RGB24 24 bpp - Software conversion from UYVY
- 5 = RGB32 32 bpp - Software conversion from UYVY
- When not 0, this parameter will override 'decompression'.
-Default: 0 for every device. Initial palette is 9 (UYVY).
-Note: If 'w9968cf-vpp' is not present, this parameter is set to 9.
--------------------------------------------------------------------------------
-Name: force_rgb
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: Read RGB video data instead of BGR:
- 1 = use RGB component ordering.
- 0 = use BGR component ordering.
- This parameter has effect when using RGBX palettes only.
-Default: 0 for every device.
--------------------------------------------------------------------------------
-Name: autobright
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: Image sensor automatically changes brightness:
- 0 = no, 1 = yes
-Default: 0 for every device.
--------------------------------------------------------------------------------
-Name: autoexp
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: Image sensor automatically changes exposure:
- 0 = no, 1 = yes
-Default: 1 for every device.
--------------------------------------------------------------------------------
-Name: lightfreq
-Type: int array (min = 0, max = 32)
-Syntax: <50|60[,...]>
-Description: Light frequency in Hz:
- 50 for European and Asian lighting, 60 for American lighting.
-Default: 50 for every device.
--------------------------------------------------------------------------------
-Name: bandingfilter
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: Banding filter to reduce effects of fluorescent
- lighting:
- 0 disabled, 1 enabled.
- This filter tries to reduce the pattern of horizontal
- light/dark bands caused by some (usually fluorescent) lighting.
-Default: 0 for every device.
--------------------------------------------------------------------------------
-Name: clockdiv
-Type: int array (min = 0, max = 32)
-Syntax: <-1|n[,...]>
-Description: Force pixel clock divisor to a specific value (for experts):
- n may vary from 0 to 127.
- -1 for automatic value.
- See also the 'double_buffer' module parameter.
-Default: -1 for every device.
--------------------------------------------------------------------------------
-Name: backlight
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: Objects are lit from behind:
- 0 = no, 1 = yes
-Default: 0 for every device.
--------------------------------------------------------------------------------
-Name: mirror
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: Reverse image horizontally:
- 0 = no, 1 = yes
-Default: 0 for every device.
--------------------------------------------------------------------------------
-Name: monochrome
-Type: bool array (min = 0, max = 32)
-Syntax: <0|1[,...]>
-Description: The image sensor is monochrome:
- 0 = no, 1 = yes
-Default: 0 for every device.
--------------------------------------------------------------------------------
-Name: brightness
-Type: long array (min = 0, max = 32)
-Syntax: <n[,...]>
-Description: Set picture brightness (0-65535).
- This parameter has no effect if 'autobright' is enabled.
-Default: 31000 for every device.
--------------------------------------------------------------------------------
-Name: hue
-Type: long array (min = 0, max = 32)
-Syntax: <n[,...]>
-Description: Set picture hue (0-65535).
-Default: 32768 for every device.
--------------------------------------------------------------------------------
-Name: colour
-Type: long array (min = 0, max = 32)
-Syntax: <n[,...]>
-Description: Set picture saturation (0-65535).
-Default: 32768 for every device.
--------------------------------------------------------------------------------
-Name: contrast
-Type: long array (min = 0, max = 32)
-Syntax: <n[,...]>
-Description: Set picture contrast (0-65535).
-Default: 50000 for every device.
--------------------------------------------------------------------------------
-Name: whiteness
-Type: long array (min = 0, max = 32)
-Syntax: <n[,...]>
-Description: Set picture whiteness (0-65535).
-Default: 32768 for every device.
--------------------------------------------------------------------------------
-Name: debug
-Type: int
-Syntax: <n>
-Description: Debugging information level, from 0 to 6:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant information
- 3 = configuration or general messages
- 4 = warnings
- 5 = called functions
- 6 = function internals
- Level 5 and 6 are useful for testing only, when only one
- device is used.
-Default: 2
--------------------------------------------------------------------------------
-Name: specific_debug
-Type: bool
-Syntax: <0|1>
-Description: Enable or disable specific debugging messages:
- 0 = print messages concerning every level <= 'debug' level.
- 1 = print messages concerning the level indicated by 'debug'.
-Default: 0
--------------------------------------------------------------------------------
-
-
-9. Contact information
-======================
-I may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
-
-I can accept GPG/PGP encrypted e-mail. My GPG key ID is 'FCE635A4'.
-My public 1024-bit key should be available at your keyserver; the fingerprint
-is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'.
-
-
-10. Credits
-==========
-The development would not have proceed much further without having looked at
-the source code of other drivers and without the help of several persons; in
-particular:
-
-- the I2C interface to kernel and high-level image sensor control routines have
- been taken from the OV511 driver by Mark McClelland;
-
-- memory management code has been copied from the bttv driver by Ralph Metzler,
- Marcus Metzler and Gerd Knorr;
-
-- the low-level I2C read function has been written by Frederic Jouault;
-
-- the low-level I2C fast write function has been written by Piotr Czerczak.
diff --git a/Documentation/video4linux/zc0301.txt b/Documentation/video4linux/zc0301.txt
deleted file mode 100644
index b41c83cf09f4..000000000000
--- a/Documentation/video4linux/zc0301.txt
+++ /dev/null
@@ -1,270 +0,0 @@
-
- ZC0301 and ZC0301P Image Processor and Control Chip
- Driver for Linux
- ===================================================
-
- - Documentation -
-
-
-Index
-=====
-1. Copyright
-2. Disclaimer
-3. License
-4. Overview and features
-5. Module dependencies
-6. Module loading
-7. Module parameters
-8. Supported devices
-9. Notes for V4L2 application developers
-10. Contact information
-11. Credits
-
-
-1. Copyright
-============
-Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>
-
-
-2. Disclaimer
-=============
-This software is not developed or sponsored by Z-Star Microelectronics Corp.
-Trademarks are property of their respective owner.
-
-
-3. License
-==========
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You 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.
-
-
-4. Overview and features
-========================
-This driver supports the video interface of the devices mounting the ZC0301 or
-ZC0301P Image Processors and Control Chips.
-
-The driver relies on the Video4Linux2 and USB core modules. It has been
-designed to run properly on SMP systems as well.
-
-The latest version of the ZC0301[P] driver can be found at the following URL:
-http://www.linux-projects.org/
-
-Some of the features of the driver are:
-
-- full compliance with the Video4Linux2 API (see also "Notes for V4L2
- application developers" paragraph);
-- available mmap or read/poll methods for video streaming through isochronous
- data transfers;
-- automatic detection of image sensor;
-- video format is standard JPEG;
-- dynamic driver control thanks to various module parameters (see "Module
- parameters" paragraph);
-- up to 64 cameras can be handled at the same time; they can be connected and
- disconnected from the host many times without turning off the computer, if
- the system supports hotplugging;
-
-
-5. Module dependencies
-======================
-For it to work properly, the driver needs kernel support for Video4Linux and
-USB.
-
-The following options of the kernel configuration file must be enabled and
-corresponding modules must be compiled:
-
- # Multimedia devices
- #
- CONFIG_VIDEO_DEV=m
-
- # USB support
- #
- CONFIG_USB=m
-
-In addition, depending on the hardware being used, the modules below are
-necessary:
-
- # USB Host Controller Drivers
- #
- CONFIG_USB_EHCI_HCD=m
- CONFIG_USB_UHCI_HCD=m
- CONFIG_USB_OHCI_HCD=m
-
-The ZC0301 controller also provides a built-in microphone interface. It is
-supported by the USB Audio driver thanks to the ALSA API:
-
- # Sound
- #
- CONFIG_SOUND=y
-
- # Advanced Linux Sound Architecture
- #
- CONFIG_SND=m
-
- # USB devices
- #
- CONFIG_SND_USB_AUDIO=m
-
-And finally:
-
- # V4L USB devices
- #
- CONFIG_USB_ZC0301=m
-
-
-6. Module loading
-=================
-To use the driver, it is necessary to load the "zc0301" module into memory
-after every other module required: "videodev", "v4l2_common", "compat_ioctl32",
-"usbcore" and, depending on the USB host controller you have, "ehci-hcd",
-"uhci-hcd" or "ohci-hcd".
-
-Loading can be done as shown below:
-
- [root@localhost home]# modprobe zc0301
-
-At this point the devices should be recognized. You can invoke "dmesg" to
-analyze kernel messages and verify that the loading process has gone well:
-
- [user@localhost home]$ dmesg
-
-
-7. Module parameters
-====================
-Module parameters are listed below:
--------------------------------------------------------------------------------
-Name: video_nr
-Type: short array (min = 0, max = 64)
-Syntax: <-1|n[,...]>
-Description: Specify V4L2 minor mode number:
- -1 = use next available
- n = use minor number n
- You can specify up to 64 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- registered camera and use auto for the first one and for every
- other camera.
-Default: -1
--------------------------------------------------------------------------------
-Name: force_munmap
-Type: bool array (min = 0, max = 64)
-Syntax: <0|1[,...]>
-Description: Force the application to unmap previously mapped buffer memory
- before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
- all the applications support this feature. This parameter is
- specific for each detected camera.
- 0 = do not force memory unmapping
- 1 = force memory unmapping (save memory)
-Default: 0
--------------------------------------------------------------------------------
-Name: frame_timeout
-Type: uint array (min = 0, max = 64)
-Syntax: <n[,...]>
-Description: Timeout for a video frame in seconds. This parameter is
- specific for each detected camera. This parameter can be
- changed at runtime thanks to the /sys filesystem interface.
-Default: 2
--------------------------------------------------------------------------------
-Name: debug
-Type: ushort
-Syntax: <n>
-Description: Debugging information level, from 0 to 3:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant information
- 3 = more verbose messages
- Level 3 is useful for testing only, when only one device
- is used at the same time. It also shows some information
- about the hardware being detected. This module parameter can be
- changed at runtime thanks to the /sys filesystem interface.
-Default: 2
--------------------------------------------------------------------------------
-
-
-8. Supported devices
-====================
-None of the names of the companies as well as their products will be mentioned
-here. They have never collaborated with the author, so no advertising.
-
-From the point of view of a driver, what unambiguously identify a device are
-its vendor and product USB identifiers. Below is a list of known identifiers of
-devices mounting the ZC0301 Image Processor and Control Chips:
-
-Vendor ID Product ID
---------- ----------
-0x041e 0x4017
-0x041e 0x401c
-0x041e 0x401e
-0x041e 0x401f
-0x041e 0x4022
-0x041e 0x4034
-0x041e 0x4035
-0x041e 0x4036
-0x041e 0x403a
-0x0458 0x7007
-0x0458 0x700c
-0x0458 0x700f
-0x046d 0x08ae
-0x055f 0xd003
-0x055f 0xd004
-0x0ac8 0x0301
-0x0ac8 0x301b
-0x0ac8 0x303b
-0x10fd 0x0128
-0x10fd 0x8050
-0x10fd 0x804e
-
-The list above does not imply that all those devices work with this driver: up
-until now only the ones that mount the following image sensors are supported;
-kernel messages will always tell you whether this is the case:
-
-Model Manufacturer
------ ------------
-PAS202BCB PixArt Imaging, Inc.
-PB-0330 Photobit Corporation
-
-
-9. Notes for V4L2 application developers
-========================================
-This driver follows the V4L2 API specifications. In particular, it enforces two
-rules:
-
-- exactly one I/O method, either "mmap" or "read", is associated with each
-file descriptor. Once it is selected, the application must close and reopen the
-device to switch to the other I/O method;
-
-- although it is not mandatory, previously mapped buffer memory should always
-be unmapped before calling any "VIDIOC_S_CROP" or "VIDIOC_S_FMT" ioctl's.
-The same number of buffers as before will be allocated again to match the size
-of the new video frames, so you have to map the buffers again before any I/O
-attempts on them.
-
-
-10. Contact information
-=======================
-The author may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
-
-GPG/PGP encrypted e-mail's are accepted. The GPG key ID of the author is
-'FCE635A4'; the public 1024-bit key should be available at any keyserver;
-the fingerprint is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'.
-
-
-11. Credits
-===========
-- Information about the chip internals needed to enable the I2C protocol have
- been taken from the documentation of the ZC030x Video4Linux1 driver written
- by Andrew Birkett <andy@nobugs.org>;
-- The initialization values of the ZC0301 controller connected to the PAS202BCB
- and PB-0330 image sensors have been taken from the SPCA5XX driver maintained
- by Michel Xhaard <mxhaard@magic.fr>;
-- Stanislav Lechev donated one camera.
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index a4df5535996b..119358dfb742 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -219,19 +219,6 @@ allocation of vcpu ids. For example, if userspace wants
single-threaded guest vcpus, it should make all vcpu ids be a multiple
of the number of vcpus per vcore.
-On powerpc using book3s_hv mode, the vcpus are mapped onto virtual
-threads in one or more virtual CPU cores. (This is because the
-hardware requires all the hardware threads in a CPU core to be in the
-same partition.) The KVM_CAP_PPC_SMT capability indicates the number
-of vcpus per virtual core (vcore). The vcore id is obtained by
-dividing the vcpu id by the number of vcpus per vcore. The vcpus in a
-given vcore will always be in the same physical core as each other
-(though that might be a different physical core from time to time).
-Userspace can control the threading (SMT) mode of the guest by its
-allocation of vcpu ids. For example, if userspace wants
-single-threaded guest vcpus, it should make all vcpu ids be a multiple
-of the number of vcpus per vcore.
-
For virtual cpus that have been created with S390 user controlled virtual
machines, the resulting vcpu fd can be memory mapped at page offset
KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of the virtual
@@ -293,7 +280,7 @@ kvm_run' (see below).
4.11 KVM_GET_REGS
Capability: basic
-Architectures: all
+Architectures: all except ARM
Type: vcpu ioctl
Parameters: struct kvm_regs (out)
Returns: 0 on success, -1 on error
@@ -314,7 +301,7 @@ struct kvm_regs {
4.12 KVM_SET_REGS
Capability: basic
-Architectures: all
+Architectures: all except ARM
Type: vcpu ioctl
Parameters: struct kvm_regs (in)
Returns: 0 on success, -1 on error
@@ -345,7 +332,7 @@ struct kvm_sregs {
__u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
};
-/* ppc -- see arch/powerpc/include/asm/kvm.h */
+/* ppc -- see arch/powerpc/include/uapi/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
@@ -600,7 +587,7 @@ struct kvm_fpu {
4.24 KVM_CREATE_IRQCHIP
Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64
+Architectures: x86, ia64, ARM
Type: vm ioctl
Parameters: none
Returns: 0 on success, -1 on error
@@ -608,21 +595,39 @@ Returns: 0 on success, -1 on error
Creates an interrupt controller model in the kernel. On x86, creates a virtual
ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a
local APIC. IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23
-only go to the IOAPIC. On ia64, a IOSAPIC is created.
+only go to the IOAPIC. On ia64, a IOSAPIC is created. On ARM, a GIC is
+created.
4.25 KVM_IRQ_LINE
Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64
+Architectures: x86, ia64, arm
Type: vm ioctl
Parameters: struct kvm_irq_level
Returns: 0 on success, -1 on error
Sets the level of a GSI input to the interrupt controller model in the kernel.
-Requires that an interrupt controller model has been previously created with
-KVM_CREATE_IRQCHIP. Note that edge-triggered interrupts require the level
-to be set to 1 and then back to 0.
+On some architectures it is required that an interrupt controller model has
+been previously created with KVM_CREATE_IRQCHIP. Note that edge-triggered
+interrupts require the level to be set to 1 and then back to 0.
+
+ARM can signal an interrupt either at the CPU level, or at the in-kernel irqchip
+(GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for
+specific cpus. The irq field is interpreted like this:
+
+  bits: | 31 ... 24 | 23 ... 16 | 15 ... 0 |
+ field: | irq_type | vcpu_index | irq_id |
+
+The irq_type field has the following values:
+- irq_type[0]: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
+- irq_type[1]: in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.)
+ (the vcpu_index field is ignored)
+- irq_type[2]: in-kernel GIC: PPI, irq_id between 16 and 31 (incl.)
+
+(The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
+
+In both cases, level is used to raise/lower the line.
struct kvm_irq_level {
union {
@@ -874,12 +879,12 @@ It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr
be identical. This allows large pages in the guest to be backed by large
pages in the host.
-The flags field supports two flag, KVM_MEM_LOG_DIRTY_PAGES, which instructs
-kvm to keep track of writes to memory within the slot. See KVM_GET_DIRTY_LOG
-ioctl. The KVM_CAP_READONLY_MEM capability indicates the availability of the
-KVM_MEM_READONLY flag. When this flag is set for a memory region, KVM only
-allows read accesses. Writes will be posted to userspace as KVM_EXIT_MMIO
-exits.
+The flags field supports two flags: KVM_MEM_LOG_DIRTY_PAGES and
+KVM_MEM_READONLY. The former can be set to instruct KVM to keep track of
+writes to memory within the slot. See KVM_GET_DIRTY_LOG ioctl to know how to
+use it. The latter can be set, if KVM_CAP_READONLY_MEM capability allows it,
+to make a new slot read-only. In this case, writes to this memory will be
+posted to userspace as KVM_EXIT_MMIO exits.
When the KVM_CAP_SYNC_MMU capability is available, changes in the backing of
the memory region are automatically reflected into the guest. For example, an
@@ -913,7 +918,7 @@ documentation when it pops into existence).
4.37 KVM_ENABLE_CAP
Capability: KVM_CAP_ENABLE_CAP
-Architectures: ppc
+Architectures: ppc, s390
Type: vcpu ioctl
Parameters: struct kvm_enable_cap (in)
Returns: 0 on success; -1 on error
@@ -1774,6 +1779,28 @@ registers, find a list below:
PPC | KVM_REG_PPC_VPA_SLB | 128
PPC | KVM_REG_PPC_VPA_DTL | 128
PPC | KVM_REG_PPC_EPCR | 32
+ PPC | KVM_REG_PPC_EPR | 32
+
+ARM registers are mapped using the lower 32 bits. The upper 16 of that
+is the register group type, or coprocessor number:
+
+ARM core registers have the following id bit patterns:
+ 0x4002 0000 0010 <index into the kvm_regs struct:16>
+
+ARM 32-bit CP15 registers have the following id bit patterns:
+ 0x4002 0000 000F <zero:1> <crn:4> <crm:4> <opc1:4> <opc2:3>
+
+ARM 64-bit CP15 registers have the following id bit patterns:
+ 0x4003 0000 000F <zero:1> <zero:4> <crm:4> <opc1:4> <zero:3>
+
+ARM CCSIDR registers are demultiplexed by CSSELR value:
+ 0x4002 0000 0011 00 <csselr:8>
+
+ARM 32-bit VFP control registers have the following id bit patterns:
+ 0x4002 0000 0012 1 <regno:12>
+
+ARM 64-bit FP registers have the following id bit patterns:
+ 0x4002 0000 0012 0 <regno:12>
4.69 KVM_GET_ONE_REG
@@ -2069,6 +2096,14 @@ KVM_S390_INT_VIRTIO (vm) - virtio external interrupt; external interrupt
KVM_S390_INT_SERVICE (vm) - sclp external interrupt; sclp parameter in parm
KVM_S390_INT_EMERGENCY (vcpu) - sigp emergency; source cpu in parm
KVM_S390_INT_EXTERNAL_CALL (vcpu) - sigp external call; source cpu in parm
+KVM_S390_INT_IO(ai,cssid,ssid,schid) (vm) - compound value to indicate an
+ I/O interrupt (ai - adapter interrupt; cssid,ssid,schid - subchannel);
+ I/O interruption parameters in parm (subchannel) and parm64 (intparm,
+ interruption subclass)
+KVM_S390_MCHK (vm, vcpu) - machine check interrupt; cr 14 bits in parm,
+ machine check interrupt code in parm64 (note that
+ machine checks needing further payload are not
+ supported by this ioctl)
Note that the vcpu ioctl is asynchronous to vcpu execution.
@@ -2127,6 +2162,88 @@ written, then `n_invalid' invalid entries, invalidating any previously
valid entries found.
+4.77 KVM_ARM_VCPU_INIT
+
+Capability: basic
+Architectures: arm
+Type: vcpu ioctl
+Parameters: struct struct kvm_vcpu_init (in)
+Returns: 0 on success; -1 on error
+Errors:
+  EINVAL:    the target is unknown, or the combination of features is invalid.
+  ENOENT:    a features bit specified is unknown.
+
+This tells KVM what type of CPU to present to the guest, and what
+optional features it should have.  This will cause a reset of the cpu
+registers to their initial values.  If this is not called, KVM_RUN will
+return ENOEXEC for that vcpu.
+
+Note that because some registers reflect machine topology, all vcpus
+should be created before this ioctl is invoked.
+
+Possible features:
+ - KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state.
+ Depends on KVM_CAP_ARM_PSCI.
+
+
+4.78 KVM_GET_REG_LIST
+
+Capability: basic
+Architectures: arm
+Type: vcpu ioctl
+Parameters: struct kvm_reg_list (in/out)
+Returns: 0 on success; -1 on error
+Errors:
+  E2BIG:     the reg index list is too big to fit in the array specified by
+             the user (the number required will be written into n).
+
+struct kvm_reg_list {
+ __u64 n; /* number of registers in reg[] */
+ __u64 reg[0];
+};
+
+This ioctl returns the guest registers that are supported for the
+KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
+
+
+4.80 KVM_ARM_SET_DEVICE_ADDR
+
+Capability: KVM_CAP_ARM_SET_DEVICE_ADDR
+Architectures: arm
+Type: vm ioctl
+Parameters: struct kvm_arm_device_address (in)
+Returns: 0 on success, -1 on error
+Errors:
+ ENODEV: The device id is unknown
+ ENXIO: Device not supported on current system
+ EEXIST: Address already set
+ E2BIG: Address outside guest physical address space
+ EBUSY: Address overlaps with other device range
+
+struct kvm_arm_device_addr {
+ __u64 id;
+ __u64 addr;
+};
+
+Specify a device address in the guest's physical address space where guests
+can access emulated or directly exposed devices, which the host kernel needs
+to know about. The id field is an architecture specific identifier for a
+specific device.
+
+ARM divides the id field into two parts, a device id and an address type id
+specific to the individual device.
+
+  bits: | 63 ... 32 | 31 ... 16 | 15 ... 0 |
+ field: | 0x00000000 | device id | addr type id |
+
+ARM currently only require this when using the in-kernel GIC support for the
+hardware VGIC features, using KVM_ARM_DEVICE_VGIC_V2 as the device id. When
+setting the base address for the guest's mapping of the VGIC virtual CPU
+and distributor interface, the ioctl must be called after calling
+KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. Calling
+this ioctl twice for any of the base addresses will return -EEXIST.
+
+
5. The kvm_run structure
------------------------
@@ -2238,8 +2355,8 @@ executed a memory-mapped I/O instruction which could not be satisfied
by kvm. The 'data' member contains the written data if 'is_write' is
true, and should be filled by application code otherwise.
-NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_DCR
- and KVM_EXIT_PAPR the corresponding
+NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_DCR,
+ KVM_EXIT_PAPR and KVM_EXIT_EPR the corresponding
operations are complete (and guest state is consistent) only after userspace
has re-entered the kernel with KVM_RUN. The kernel side will first finish
incomplete operations and then check for pending signals. Userspace
@@ -2342,6 +2459,41 @@ The possible hypercalls are defined in the Power Architecture Platform
Requirements (PAPR) document available from www.power.org (free
developer registration required to access it).
+ /* KVM_EXIT_S390_TSCH */
+ struct {
+ __u16 subchannel_id;
+ __u16 subchannel_nr;
+ __u32 io_int_parm;
+ __u32 io_int_word;
+ __u32 ipb;
+ __u8 dequeued;
+ } s390_tsch;
+
+s390 specific. This exit occurs when KVM_CAP_S390_CSS_SUPPORT has been enabled
+and TEST SUBCHANNEL was intercepted. If dequeued is set, a pending I/O
+interrupt for the target subchannel has been dequeued and subchannel_id,
+subchannel_nr, io_int_parm and io_int_word contain the parameters for that
+interrupt. ipb is needed for instruction parameter decoding.
+
+ /* KVM_EXIT_EPR */
+ struct {
+ __u32 epr;
+ } epr;
+
+On FSL BookE PowerPC chips, the interrupt controller has a fast patch
+interrupt acknowledge path to the core. When the core successfully
+delivers an interrupt, it automatically populates the EPR register with
+the interrupt vector number and acknowledges the interrupt inside
+the interrupt controller.
+
+In case the interrupt controller lives in user space, we need to do
+the interrupt acknowledge cycle through it to fetch the next to be
+delivered interrupt vector using this exit.
+
+It gets triggered whenever both KVM_CAP_PPC_EPR are enabled and an
+external interrupt has just been delivered into the guest. User space
+should put the acknowledged interrupt vector into the 'epr' field.
+
/* Fix the size of the union. */
char padding[256];
};
@@ -2463,3 +2615,34 @@ For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
where "num_sets" is the tlb_sizes[] value divided by the tlb_ways[] value.
- The tsize field of mas1 shall be set to 4K on TLB0, even though the
hardware ignores this value for TLB0.
+
+6.4 KVM_CAP_S390_CSS_SUPPORT
+
+Architectures: s390
+Parameters: none
+Returns: 0 on success; -1 on error
+
+This capability enables support for handling of channel I/O instructions.
+
+TEST PENDING INTERRUPTION and the interrupt portion of TEST SUBCHANNEL are
+handled in-kernel, while the other I/O instructions are passed to userspace.
+
+When this capability is enabled, KVM_EXIT_S390_TSCH will occur on TEST
+SUBCHANNEL intercepts.
+
+6.5 KVM_CAP_PPC_EPR
+
+Architectures: ppc
+Parameters: args[0] defines whether the proxy facility is active
+Returns: 0 on success; -1 on error
+
+This capability enables or disables the delivery of interrupts through the
+external proxy facility.
+
+When enabled (args[0] != 0), every time the guest gets an external interrupt
+delivered, it automatically exits into user space with a KVM_EXIT_EPR exit
+to receive the topmost interrupt vector.
+
+When disabled (args[0] == 0), behavior is as if this facility is unsupported.
+
+When this capability is enabled, KVM_EXIT_EPR can occur.
diff --git a/Documentation/virtual/kvm/mmu.txt b/Documentation/virtual/kvm/mmu.txt
index fa5f1dbc6b23..43fcb761ed16 100644
--- a/Documentation/virtual/kvm/mmu.txt
+++ b/Documentation/virtual/kvm/mmu.txt
@@ -187,13 +187,6 @@ Shadow pages contain the following information:
perform a reverse map from a pte to a gfn. When role.direct is set, any
element of this array can be calculated from the gfn field when used, in
this case, the array of gfns is not allocated. See role.direct and gfn.
- slot_bitmap:
- A bitmap containing one bit per memory slot. If the page contains a pte
- mapping a page from memory slot n, then bit n of slot_bitmap will be set
- (if a page is aliased among several slots, then it is not guaranteed that
- all slots will be marked).
- Used during dirty logging to avoid scanning a shadow page if none if its
- pages need tracking.
root_count:
A counter keeping track of how many hardware registers (guest cr3 or
pdptrs) are now pointing at the page. While this counter is nonzero, the
diff --git a/Documentation/vm/ksm.txt b/Documentation/vm/ksm.txt
index b392e496f816..f34a8ee6f860 100644
--- a/Documentation/vm/ksm.txt
+++ b/Documentation/vm/ksm.txt
@@ -58,6 +58,21 @@ sleep_millisecs - how many milliseconds ksmd should sleep before next scan
e.g. "echo 20 > /sys/kernel/mm/ksm/sleep_millisecs"
Default: 20 (chosen for demonstration purposes)
+merge_across_nodes - specifies if pages from different numa nodes can be merged.
+ When set to 0, ksm merges only pages which physically
+ reside in the memory area of same NUMA node. That brings
+ lower latency to access of shared pages. Systems with more
+ nodes, at significant NUMA distances, are likely to benefit
+ from the lower latency of setting 0. Smaller systems, which
+ need to minimize memory usage, are likely to benefit from
+ the greater sharing of setting 1 (default). You may wish to
+ compare how your system performs under each setting, before
+ deciding on which to use. merge_across_nodes setting can be
+ changed only when there are no ksm shared pages in system:
+ set run 2 to unmerge pages first, then to 1 after changing
+ merge_across_nodes, to remerge according to the new setting.
+ Default: 1 (merging across nodes as in earlier releases)
+
run - set 0 to stop ksmd from running but keep merged pages,
set 1 to run ksmd e.g. "echo 1 > /sys/kernel/mm/ksm/run",
set 2 to stop ksmd and unmerge all pages currently merged,
diff --git a/Documentation/w1/slaves/w1_therm b/Documentation/w1/slaves/w1_therm
index 874a8ca93feb..cc62a95e4776 100644
--- a/Documentation/w1/slaves/w1_therm
+++ b/Documentation/w1/slaves/w1_therm
@@ -34,9 +34,16 @@ currently supported. The driver also doesn't support reduced
precision (which would also reduce the conversion time).
The module parameter strong_pullup can be set to 0 to disable the
-strong pullup or 1 to enable. If enabled the 5V strong pullup will be
-enabled when the conversion is taking place provided the master driver
-must support the strong pullup (or it falls back to a pullup
+strong pullup, 1 to enable autodetection or 2 to force strong pullup.
+In case of autodetection, the driver will use the "READ POWER SUPPLY"
+command to check if there are pariste powered devices on the bus.
+If so, it will activate the master's strong pullup.
+In case the detection of parasite devices using this command fails
+(seems to be the case with some DS18S20) the strong pullup can
+be force-enabled.
+If the strong pullup is enabled, the master's strong pullup will be
+driven when the conversion is taking place, provided the master driver
+does support the strong pullup (or it falls back to a pullup
resistor). The DS18b20 temperature sensor specification lists a
maximum current draw of 1.5mA and that a 5k pullup resistor is not
sufficient. The strong pullup is designed to provide the additional
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt
index e540fd67f767..3840b6f28afb 100644
--- a/Documentation/x86/boot.txt
+++ b/Documentation/x86/boot.txt
@@ -390,6 +390,7 @@ Protocol: 2.00+
F Special (0xFF = undefined)
10 Reserved
11 Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de>
+ 12 OVMF UEFI virtualization stack
Please contact <hpa@zytor.com> if you need a bootloader ID
value assigned.
@@ -1054,6 +1055,44 @@ must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
must be __BOOT_DS; interrupt must be disabled; %esi must hold the base
address of the struct boot_params; %ebp, %edi and %ebx must be zero.
+**** 64-bit BOOT PROTOCOL
+
+For machine with 64bit cpus and 64bit kernel, we could use 64bit bootloader
+and we need a 64-bit boot protocol.
+
+In 64-bit boot protocol, the first step in loading a Linux kernel
+should be to setup the boot parameters (struct boot_params,
+traditionally known as "zero page"). The memory for struct boot_params
+could be allocated anywhere (even above 4G) and initialized to all zero.
+Then, the setup header at offset 0x01f1 of kernel image on should be
+loaded into struct boot_params and examined. The end of setup header
+can be calculated as follows:
+
+ 0x0202 + byte value at offset 0x0201
+
+In addition to read/modify/write the setup header of the struct
+boot_params as that of 16-bit boot protocol, the boot loader should
+also fill the additional fields of the struct boot_params as described
+in zero-page.txt.
+
+After setting up the struct boot_params, the boot loader can load
+64-bit kernel in the same way as that of 16-bit boot protocol, but
+kernel could be loaded above 4G.
+
+In 64-bit boot protocol, the kernel is started by jumping to the
+64-bit kernel entry point, which is the start address of loaded
+64-bit kernel plus 0x200.
+
+At entry, the CPU must be in 64-bit mode with paging enabled.
+The range with setup_header.init_size from start address of loaded
+kernel and zero page and command line buffer get ident mapping;
+a GDT must be loaded with the descriptors for selectors
+__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat
+segment; __BOOT_CS must have execute/read permission, and __BOOT_DS
+must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
+must be __BOOT_DS; interrupt must be disabled; %rsi must hold the base
+address of the struct boot_params.
+
**** EFI HANDOVER PROTOCOL
This protocol allows boot loaders to defer initialisation to the EFI
diff --git a/Documentation/x86/early-microcode.txt b/Documentation/x86/early-microcode.txt
new file mode 100644
index 000000000000..4aaf0dfb0cb8
--- /dev/null
+++ b/Documentation/x86/early-microcode.txt
@@ -0,0 +1,43 @@
+Early load microcode
+====================
+By Fenghua Yu <fenghua.yu@intel.com>
+
+Kernel can update microcode in early phase of boot time. Loading microcode early
+can fix CPU issues before they are observed during kernel boot time.
+
+Microcode is stored in an initrd file. The microcode is read from the initrd
+file and loaded to CPUs during boot time.
+
+The format of the combined initrd image is microcode in cpio format followed by
+the initrd image (maybe compressed). Kernel parses the combined initrd image
+during boot time. The microcode file in cpio name space is:
+kernel/x86/microcode/GenuineIntel.bin
+
+During BSP boot (before SMP starts), if the kernel finds the microcode file in
+the initrd file, it parses the microcode and saves matching microcode in memory.
+If matching microcode is found, it will be uploaded in BSP and later on in all
+APs.
+
+The cached microcode patch is applied when CPUs resume from a sleep state.
+
+There are two legacy user space interfaces to load microcode, either through
+/dev/cpu/microcode or through /sys/devices/system/cpu/microcode/reload file
+in sysfs.
+
+In addition to these two legacy methods, the early loading method described
+here is the third method with which microcode can be uploaded to a system's
+CPUs.
+
+The following example script shows how to generate a new combined initrd file in
+/boot/initrd-3.5.0.ucode.img with original microcode microcode.bin and
+original initrd image /boot/initrd-3.5.0.img.
+
+mkdir initrd
+cd initrd
+mkdir kernel
+mkdir kernel/x86
+mkdir kernel/x86/microcode
+cp ../microcode.bin kernel/x86/microcode/GenuineIntel.bin
+find .|cpio -oc >../ucode.cpio
+cd ..
+cat ucode.cpio /boot/initrd-3.5.0.img >/boot/initrd-3.5.0.ucode.img
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
index de38429beb71..e015a83c3996 100644
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -112,10 +112,6 @@ Timing
This can be used to work around timing problems on multiprocessor systems
with not properly synchronized CPUs.
- report_lost_ticks
- Report when timer interrupts are lost because some code turned off
- interrupts for too long.
-
nohpet
Don't use the HPET timer.
diff --git a/Documentation/zh_CN/CodingStyle b/Documentation/zh_CN/CodingStyle
index ecd9307a641f..654afd72eb24 100644
--- a/Documentation/zh_CN/CodingStyle
+++ b/Documentation/zh_CN/CodingStyle
@@ -462,13 +462,6 @@ config AUDIT
logging of avc messages output). Does not do system-call
auditing without CONFIG_AUDITSYSCALL.
-仍然被认为不够稳定的功能应该被定义为依赖于“EXPERIMENTAL”:
-
-config SLUB
- depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT
- bool "SLUB (Unqueued Allocator)"
- ...
-
而那些危险的功能(比如某些文件系统的写支持)应该在它们的提示字符串里显著的声明这
一点:
diff --git a/Documentation/zh_CN/magic-number.txt b/Documentation/zh_CN/magic-number.txt
index 4263022f5002..2ebe539f5450 100644
--- a/Documentation/zh_CN/magic-number.txt
+++ b/Documentation/zh_CN/magic-number.txt
@@ -122,7 +122,7 @@ SLAB_C_MAGIC 0x4f17a36d kmem_cache mm/slab.c
COW_MAGIC 0x4f4f4f4d cow_header_v1 arch/um/drivers/ubd_user.c
I810_CARD_MAGIC 0x5072696E i810_card sound/oss/i810_audio.c
TRIDENT_CARD_MAGIC 0x5072696E trident_card sound/oss/trident.c
-ROUTER_MAGIC 0x524d4157 wan_device include/linux/wanrouter.h
+ROUTER_MAGIC 0x524d4157 wan_device [in wanrouter.h pre 3.9]
SCC_MAGIC 0x52696368 gs_port drivers/char/scc.h
SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c
GDA_MAGIC 0x58464552 gda arch/mips/include/asm/sn/gda.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 35a56bcd5e75..870ba56207d7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -465,6 +465,14 @@ S: Maintained
F: drivers/scsi/aic7xxx/
F: drivers/scsi/aic7xxx_old/
+AIMSLAB FM RADIO RECEIVER DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/radio/radio-aimslab*
+
AIO
M: Benjamin LaHaise <bcrl@kvack.org>
L: linux-aio@kvack.org
@@ -559,6 +567,18 @@ L: linux-rdma@vger.kernel.org
S: Maintained
F: drivers/infiniband/hw/amso1100/
+ANALOG DEVICES INC AD9389B DRIVER
+M: Hans Verkuil <hans.verkuil@cisco.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/i2c/ad9389b*
+
+ANALOG DEVICES INC ADV7604 DRIVER
+M: Hans Verkuil <hans.verkuil@cisco.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/i2c/adv7604*
+
ANALOG DEVICES INC ASOC CODEC DRIVERS
M: Lars-Peter Clausen <lars@metafoo.de>
L: device-drivers-devel@blackfin.uclinux.org
@@ -670,8 +690,16 @@ F: drivers/input/serio/ambakmi.*
F: include/linux/amba/kmi.h
ARM PRIMECELL MMCI PL180/1 DRIVER
-S: Orphan
+M: Russell King <linux@arm.linux.org.uk>
+S: Maintained
F: drivers/mmc/host/mmci.*
+F: include/linux/amba/mmci.h
+
+ARM PRIMECELL UART PL010 AND PL011 DRIVERS
+M: Russell King <linux@arm.linux.org.uk>
+S: Maintained
+F: drivers/tty/serial/amba-pl01*.c
+F: include/linux/amba/serial.h
ARM PRIMECELL BUS SUPPORT
M: Russell King <linux@arm.linux.org.uk>
@@ -1118,6 +1146,14 @@ F: arch/arm/mach-s5pv210/mach-goni.c
F: arch/arm/mach-exynos/mach-universal_c210.c
F: arch/arm/mach-exynos/mach-nuri.c
+ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT
+M: Kyungmin Park <kyungmin.park@samsung.com>
+M: Kamil Debski <k.debski@samsung.com>
+L: linux-arm-kernel@lists.infradead.org
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/platform/s5p-g2d/
+
ARM/SAMSUNG S5P SERIES FIMC SUPPORT
M: Kyungmin Park <kyungmin.park@samsung.com>
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
@@ -1248,12 +1284,17 @@ M: Tony Prisk <linux@prisktech.co.nz>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-vt8500/
+F: drivers/clocksource/vt8500_timer.c
+F: drivers/gpio/gpio-vt8500.c
+F: drivers/mmc/host/wmt-sdmmc.c
+F: drivers/pwm/pwm-vt8500.c
+F: drivers/rtc/rtc-vt8500.c
+F: drivers/tty/serial/vt8500_serial.c
+F: drivers/usb/host/ehci-vt8500.c
+F: drivers/usb/host/uhci-platform.c
F: drivers/video/vt8500lcdfb.*
F: drivers/video/wm8505fb*
F: drivers/video/wmt_ge_rops.*
-F: drivers/tty/serial/vt8500_serial.c
-F: drivers/rtc/rtc-vt8500.c
-F: drivers/mmc/host/wmt-sdmmc.c
ARM/ZIPIT Z2 SUPPORT
M: Marek Vasut <marek.vasut@gmail.com>
@@ -1262,6 +1303,14 @@ S: Maintained
F: arch/arm/mach-pxa/z2.c
F: arch/arm/mach-pxa/include/mach/z2.h
+ARM/ZYNQ ARCHITECTURE
+M: Michal Simek <michal.simek@xilinx.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+W: http://wiki.xilinx.com
+T: git git://git.xilinx.com/linux-xlnx.git
+S: Supported
+F: arch/arm/mach-zynq/
+
ARM64 PORT (AARCH64 ARCHITECTURE)
M: Catalin Marinas <catalin.marinas@arm.com>
M: Will Deacon <will.deacon@arm.com>
@@ -1270,6 +1319,14 @@ S: Maintained
F: arch/arm64/
F: Documentation/arm64/
+AS3645A LED FLASH CONTROLLER DRIVER
+M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/as3645a.c
+F: include/media/as3645a.h
+
ASC7621 HARDWARE MONITOR DRIVER
M: George Joseph <george.joseph@fairview5.com>
L: lm-sensors@lm-sensors.org
@@ -1303,7 +1360,7 @@ F: include/linux/dmaengine.h
F: include/linux/async_tx.h
AT24 EEPROM DRIVER
-M: Wolfram Sang <w.sang@pengutronix.de>
+M: Wolfram Sang <wsa@the-dreams.de>
L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/misc/eeprom/at24.c
@@ -1517,6 +1574,14 @@ T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/usb/dvb-usb-v2/az6007.c
+AZTECH FM RADIO RECEIVER DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/radio/radio-aztech*
+
B43 WIRELESS DRIVER
M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org
@@ -1616,6 +1681,15 @@ W: http://blackfin.uclinux.org/
S: Supported
F: drivers/i2c/busses/i2c-bfin-twi.c
+BLACKFIN MEDIA DRIVER
+M: Scott Jiang <scott.jiang.linux@gmail.com>
+L: uclinux-dist-devel@blackfin.uclinux.org
+W: http://blackfin.uclinux.org/
+S: Supported
+F: drivers/media/platform/blackfin/
+F: drivers/media/i2c/adv7183*
+F: drivers/media/i2c/vs6624*
+
BLINKM RGB LED DRIVER
M: Jan-Simon Moeller <jansimon.moeller@gmx.de>
S: Maintained
@@ -1799,6 +1873,14 @@ S: Supported
F: Documentation/filesystems/caching/cachefiles.txt
F: fs/cachefiles/
+CADET FM/AM RADIO RECEIVER DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/radio/radio-cadet*
+
CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER
M: Jonathan Corbet <corbet@lwn.net>
L: linux-media@vger.kernel.org
@@ -1935,7 +2017,8 @@ F: drivers/misc/*
CHECKPATCH
M: Andy Whitcroft <apw@canonical.com>
-S: Supported
+M: Joe Perches <joe@perches.com>
+S: Maintained
F: scripts/checkpatch.pl
CHINESE DOCUMENTATION
@@ -2140,10 +2223,10 @@ S: Maintained
F: tools/power/cpupower
CPUSETS
-M: Paul Menage <paul@paulmenage.org>
+M: Li Zefan <lizefan@huawei.com>
W: http://www.bullopensource.org/cpuset/
W: http://oss.sgi.com/projects/cpusets/
-S: Supported
+S: Maintained
F: Documentation/cgroups/cpusets.txt
F: include/linux/cpuset.h
F: kernel/cpuset.c
@@ -2199,6 +2282,15 @@ F: Documentation/video4linux/cx18.txt
F: drivers/media/pci/cx18/
F: include/uapi/linux/ivtv*
+CX2341X MPEG ENCODER HELPER MODULE
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/i2c/cx2341x*
+F: include/media/cx2341x*
+
CX88 VIDEO4LINUX DRIVER
M: Mauro Carvalho Chehab <mchehab@redhat.com>
L: linux-media@vger.kernel.org
@@ -2576,6 +2668,13 @@ S: Maintained
F: drivers/gpu/drm/tegra/
F: Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
+DSBR100 USB FM RADIO DRIVER
+M: Alexey Klimov <klimov.linux@gmail.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/radio/dsbr100.c
+
DSCC4 DRIVER
M: Francois Romieu <romieu@fr.zoreil.com>
L: netdev@vger.kernel.org
@@ -2974,11 +3073,6 @@ S: Maintained
F: include/linux/netfilter_bridge/
F: net/bridge/
-ETHERTEAM 16I DRIVER
-M: Mika Kuoppala <miku@iki.fi>
-S: Maintained
-F: drivers/net/ethernet/fujitsu/eth16i.c
-
EXT2 FILE SYSTEM
M: Jan Kara <jack@suse.cz>
L: linux-ext4@vger.kernel.org
@@ -3347,6 +3441,14 @@ W: http://www.icp-vortex.com/
S: Supported
F: drivers/scsi/gdt*
+GEMTEK FM RADIO RECEIVER DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/radio/radio-gemtek*
+
GENERIC GPIO I2C DRIVER
M: Haavard Skinnemoen <hskinnemoen@gmail.com>
S: Supported
@@ -3757,12 +3859,11 @@ S: Maintained
F: drivers/i2c/i2c-stub.c
I2C SUBSYSTEM
-M: Wolfram Sang <w.sang@pengutronix.de>
+M: Wolfram Sang <wsa@the-dreams.de>
M: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>
L: linux-i2c@vger.kernel.org
W: http://i2c.wiki.kernel.org/
-T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
-T: git git://git.pengutronix.de/git/wsa/linux.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
S: Maintained
F: Documentation/i2c/
F: drivers/i2c/
@@ -4216,6 +4317,7 @@ M: Thomas Gleixner <tglx@linutronix.de>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
F: kernel/irq/
+F: drivers/irqchip/
IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
@@ -4233,6 +4335,14 @@ F: Documentation/isapnp.txt
F: drivers/pnp/isapnp/
F: include/linux/isapnp.h
+ISA RADIO MODULE
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/radio/radio-isa*
+
iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER
M: Peter Jones <pjones@redhat.com>
M: Konrad Rzeszutek Wilk <konrad@kernel.org>
@@ -4391,6 +4501,14 @@ W: http://lse.sourceforge.net/kdump/
S: Maintained
F: Documentation/kdump/
+KEENE FM RADIO TRANSMITTER DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/radio/radio-keene*
+
KERNEL AUTOMOUNTER v4 (AUTOFS4)
M: Ian Kent <raven@themaw.net>
L: autofs@vger.kernel.org
@@ -4481,6 +4599,15 @@ F: arch/s390/include/asm/kvm*
F: arch/s390/kvm/
F: drivers/s390/kvm/
+KERNEL VIRTUAL MACHINE (KVM) FOR ARM
+M: Christoffer Dall <cdall@cs.columbia.edu>
+L: kvmarm@lists.cs.columbia.edu
+W: http://systems.cs.columbia.edu/projects/kvm-arm
+S: Maintained
+F: arch/arm/include/uapi/asm/kvm*
+F: arch/arm/include/asm/kvm*
+F: arch/arm/kvm/
+
KEXEC
M: Eric Biederman <ebiederm@xmission.com>
W: http://kernel.org/pub/linux/utils/kernel/kexec/
@@ -4869,6 +4996,13 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/
S: Maintained
F: drivers/media/dvb-frontends/m88rs2000*
+MA901 MASTERKIT USB FM RADIO DRIVER
+M: Alexey Klimov <klimov.linux@gmail.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/radio/radio-ma901.c
+
MAC80211
M: Johannes Berg <johannes@sipsolutions.net>
L: linux-wireless@vger.kernel.org
@@ -4966,6 +5100,14 @@ S: Maintained
F: Documentation/hwmon/max6650
F: drivers/hwmon/max6650.c
+MAXIRADIO FM RADIO RECEIVER DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/radio/radio-maxiradio*
+
MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
M: Mauro Carvalho Chehab <mchehab@redhat.com>
P: LinuxTV.org Project
@@ -4988,6 +5130,14 @@ F: include/uapi/linux/meye.h
F: include/uapi/linux/ivtv*
F: include/uapi/linux/uvcvideo.h
+MEDIAVISION PRO MOVIE STUDIO DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/parport/pms*
+
MEGARAID SCSI DRIVERS
M: Neela Syam Kolli <megaraidlinux@lsi.com>
L: linux-scsi@vger.kernel.org
@@ -5010,6 +5160,10 @@ L: linux-mm@kvack.org
W: http://www.linux-mm.org
S: Maintained
F: include/linux/mm.h
+F: include/linux/gfp.h
+F: include/linux/mmzone.h
+F: include/linux/memory_hotplug.h
+F: include/linux/vmalloc.h
F: mm/
MEMORY RESOURCE CONTROLLER
@@ -5057,6 +5211,14 @@ S: Supported
F: Documentation/mips/
F: arch/mips/
+MIROSOUND PCM20 FM RADIO RECEIVER DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/radio/radio-miropcm20*
+
MODULE SUPPORT
M: Rusty Russell <rusty@rustcorp.com.au>
S: Maintained
@@ -5095,6 +5257,38 @@ L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/msi-wmi.c
+MT9M032 SENSOR DRIVER
+M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/mt9m032.c
+F: include/media/mt9m032.h
+
+MT9P031 SENSOR DRIVER
+M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/mt9p031.c
+F: include/media/mt9p031.h
+
+MT9T001 SENSOR DRIVER
+M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/mt9t001.c
+F: include/media/mt9t001.h
+
+MT9V032 SENSOR DRIVER
+M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/mt9v032.c
+F: include/media/mt9v032.h
+
MULTIFUNCTION DEVICES (MFD)
M: Samuel Ortiz <sameo@linux.intel.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git
@@ -5369,13 +5563,6 @@ F: include/linux/sunrpc/
F: include/uapi/linux/nfs*
F: include/uapi/linux/sunrpc/
-NI5010 NETWORK DRIVER
-M: Jan-Pascal van Best <janpascal@vanbest.org>
-M: Andreas Mohr <andi@lisas.de>
-L: netdev@vger.kernel.org
-S: Maintained
-F: drivers/net/ethernet/racal/ni5010.*
-
NILFS2 FILESYSTEM
M: KONISHI Ryusuke <konishi.ryusuke@lab.ntt.co.jp>
L: linux-nilfs@vger.kernel.org
@@ -5401,6 +5588,13 @@ S: Maintained
F: Documentation/scsi/NinjaSCSI.txt
F: drivers/scsi/nsp32*
+NTB DRIVER
+M: Jon Mason <jon.mason@intel.com>
+S: Supported
+F: drivers/ntb/
+F: drivers/net/ntb_netdev.c
+F: include/linux/ntb.h
+
NTFS FILESYSTEM
M: Anton Altaparmakov <anton@tuxera.com>
L: linux-ntfs-dev@lists.sourceforge.net
@@ -5778,15 +5972,6 @@ L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/muxes/i2c-mux-pca9541.c
-PCA9564/PCA9665 I2C BUS DRIVER
-M: Wolfram Sang <w.sang@pengutronix.de>
-L: linux-i2c@vger.kernel.org
-S: Maintained
-F: drivers/i2c/algos/i2c-algo-pca.c
-F: drivers/i2c/busses/i2c-pca-*
-F: include/linux/i2c-algo-pca.h
-F: include/linux/i2c-pca-platform.h
-
PCDP - PRIMARY CONSOLE AND DEBUG PORT
M: Khalid Aziz <khalid@gonehiking.org>
S: Maintained
@@ -6255,6 +6440,14 @@ L: linux-hexagon@vger.kernel.org
S: Supported
F: arch/hexagon/
+QUICKCAM PARALLEL PORT WEBCAMS
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/parport/*-qcam*
+
RADOS BLOCK DEVICE (RBD)
M: Yehuda Sadeh <yehuda@inktank.com>
M: Sage Weil <sage@inktank.com>
@@ -6498,7 +6691,7 @@ S: Supported
F: drivers/s390/net/
S390 ZCRYPT DRIVER
-M: Holger Dengler <hd@linux.vnet.ibm.com>
+M: Ingo Tuchscherer <ingo.tuchscherer@de.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
@@ -6529,6 +6722,14 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Supported
F: drivers/mmc/host/s3cmci.*
+SAA6588 RDS RECEIVER DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/i2c/saa6588*
+
SAA7134 VIDEO4LINUX DRIVER
M: Mauro Carvalho Chehab <mchehab@redhat.com>
L: linux-media@vger.kernel.org
@@ -6539,10 +6740,9 @@ F: Documentation/video4linux/saa7134/
F: drivers/media/pci/saa7134/
SAA7146 VIDEO4LINUX-2 DRIVER
-M: Michael Hunold <michael@mihu.de>
+M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://www.mihu.de/linux/saa7146
S: Maintained
F: drivers/media/common/saa7146/
F: drivers/media/pci/saa7146/
@@ -6584,6 +6784,13 @@ S: Maintained
F: drivers/media/platform/s3c-camif/
F: include/media/s3c_camif.h
+SAMSUNG S5C73M3 CAMERA DRIVER
+M: Kyungmin Park <kyungmin.park@samsung.com>
+M: Andrzej Hajda <a.hajda@samsung.com>
+L: linux-media@vger.kernel.org
+S: Supported
+F: drivers/media/i2c/s5c73m3/*
+
SERIAL DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
L: linux-serial@vger.kernel.org
@@ -6598,7 +6805,7 @@ F: drivers/dma/dw_dmac_regs.h
F: drivers/dma/dw_dmac.c
TIMEKEEPING, NTP
-M: John Stultz <johnstul@us.ibm.com>
+M: John Stultz <john.stultz@linaro.org>
M: Thomas Gleixner <tglx@linutronix.de>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
S: Supported
@@ -6820,7 +7027,8 @@ S: Supported
F: drivers/net/ethernet/sfc/
SGI GRU DRIVER
-M: Jack Steiner <steiner@sgi.com>
+M: Dimitri Sivanich <sivanich@sgi.com>
+M: Robin Holt <holt@sgi.com>
S: Maintained
F: drivers/misc/sgi-gru/
@@ -6844,6 +7052,38 @@ M: Robin Holt <holt@sgi.com>
S: Maintained
F: drivers/misc/sgi-xp/
+SI470X FM RADIO RECEIVER I2C DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/radio/si470x/radio-si470x-i2c.c
+
+SI470X FM RADIO RECEIVER USB DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/radio/si470x/radio-si470x-common.c
+F: drivers/media/radio/si470x/radio-si470x.h
+F: drivers/media/radio/si470x/radio-si470x-usb.c
+
+SH_VEU V4L2 MEM2MEM DRIVER
+M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/platform/sh_veu.c
+F: include/media/sh_veu.h
+
+SH_VOU V4L2 OUTPUT DRIVER
+M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/platform/sh_vou.c
+F: include/media/sh_vou.h
+
SIMPLE FIRMWARE INTERFACE (SFI)
M: Len Brown <lenb@kernel.org>
L: sfi-devel@simplefirmware.org
@@ -7015,14 +7255,6 @@ L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/video/smscufx.c
-SN-IA64 (Itanium) SUB-PLATFORM
-M: Jes Sorensen <jes@sgi.com>
-L: linux-altix@sgi.com
-L: linux-ia64@vger.kernel.org
-W: http://www.sgi.com/altix
-S: Maintained
-F: arch/ia64/sn/
-
SOC-CAMERA V4L2 SUBSYSTEM
M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
L: linux-media@vger.kernel.org
@@ -7178,6 +7410,7 @@ F: drivers/clk/spear/
SPI SUBSYSTEM
M: Grant Likely <grant.likely@secretlab.ca>
+M: Mark Brown <broonie@opensource.wolfsonmicro.com>
L: spi-devel-general@lists.sourceforge.net
Q: http://patchwork.kernel.org/project/spi-devel-general/list/
T: git git://git.secretlab.ca/git/linux-2.6.git
@@ -7303,8 +7536,7 @@ S: Odd Fixes
F: drivers/staging/olpc_dcon/
STAGING - OZMO DEVICES USB OVER WIFI DRIVER
-M: Rupesh Gujare <rgujare@ozmodevices.com>
-M: Chris Kelly <ckelly@ozmodevices.com>
+M: Rupesh Gujare <rupesh.gujare@atmel.com>
S: Maintained
F: drivers/staging/ozwpan/
@@ -7519,6 +7751,14 @@ T: git git://linuxtv.org/mkrufky/tuners.git
S: Maintained
F: drivers/media/tuners/tda8290.*
+TDA9840 MEDIA DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/i2c/tda9840*
+
TEA5761 TUNER DRIVER
M: Mauro Carvalho Chehab <mchehab@redhat.com>
L: linux-media@vger.kernel.org
@@ -7535,14 +7775,35 @@ T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/tuners/tea5767.*
+TEA6415C MEDIA DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/i2c/tea6415c*
+
+TEA6420 MEDIA DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/i2c/tea6420*
+
TEAM DRIVER
-M: Jiri Pirko <jpirko@redhat.com>
+M: Jiri Pirko <jiri@resnulli.us>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/team/
F: include/linux/if_team.h
F: include/uapi/linux/if_team.h
+TECHNOLOGIC SYSTEMS TS-5500 PLATFORM SUPPORT
+M: Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>
+S: Maintained
+F: arch/x86/platform/ts5500/
+
TECHNOTREND USB IR RECEIVER
M: Sean Young <sean@mess.org>
L: linux-media@vger.kernel.org
@@ -7585,6 +7846,11 @@ S: Supported
F: drivers/thermal/
F: include/linux/thermal.h
+THINGM BLINK(1) USB RGB LED DRIVER
+M: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+S: Maintained
+F: drivers/hid/hid-thingm.c
+
THINKPAD ACPI EXTRAS DRIVER
M: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
L: ibm-acpi-devel@lists.sourceforge.net
@@ -7617,6 +7883,22 @@ F: Documentation/backlight/lp855x-driver.txt
F: drivers/video/backlight/lp855x_bl.c
F: include/linux/platform_data/lp855x.h
+TI LP8727 CHARGER DRIVER
+M: Milo Kim <milo.kim@ti.com>
+S: Maintained
+F: drivers/power/lp8727_charger.c
+F: include/linux/platform_data/lp8727.h
+
+TI LP8788 MFD DRIVER
+M: Milo Kim <milo.kim@ti.com>
+S: Maintained
+F: drivers/iio/adc/lp8788_adc.c
+F: drivers/leds/leds-lp8788.c
+F: drivers/mfd/lp8788*.c
+F: drivers/power/lp8788-charger.c
+F: drivers/regulator/lp8788-*.c
+F: include/linux/mfd/lp8788*.h
+
TI TWL4030 SERIES SOC CODEC DRIVER
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -7911,9 +8193,10 @@ F: drivers/net/wireless/ath/ar5523/
USB ATTACHED SCSI
M: Matthew Wilcox <willy@linux.intel.com>
M: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+M: Gerd Hoffmann <kraxel@redhat.com>
L: linux-usb@vger.kernel.org
L: linux-scsi@vger.kernel.org
-S: Supported
+S: Maintained
F: drivers/usb/storage/uas.c
USB CDC ETHERNET DRIVER
@@ -8157,6 +8440,14 @@ S: Maintained
F: drivers/media/usb/uvc/
F: include/uapi/linux/uvcvideo.h
+USB VISION DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/usb/usbvision/
+
USB WEBCAM GADGET
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-usb@vger.kernel.org
@@ -8306,6 +8597,14 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/via/via-velocity.*
+VIVI VIRTUAL VIDEO DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Maintained
+F: drivers/media/platform/vivi*
+
VLAN (802.1Q)
M: Patrick McHardy <kaber@trash.net>
L: netdev@vger.kernel.org
diff --git a/Makefile b/Makefile
index 54dfde5e9f9e..2309b435c07f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 8
SUBLEVEL = 0
-EXTRAVERSION = -rc6
+EXTRAVERSION =
NAME = Unicycling Gorilla
# *DOCUMENTATION*
@@ -165,7 +165,8 @@ export srctree objtree VPATH
# then ARCH is assigned, getting whatever value it gets normally, and
# SUBARCH is subsequently ignored.
-SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
+ -e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
@@ -719,11 +720,11 @@ endif # INSTALL_MOD_STRIP
export mod_strip_cmd
-ifeq ($(CONFIG_MODULE_SIG),y)
+ifdef CONFIG_MODULE_SIG_ALL
MODSECKEY = ./signing_key.priv
MODPUBKEY = ./signing_key.x509
export MODPUBKEY
-mod_sign_cmd = perl $(srctree)/scripts/sign-file $(MODSECKEY) $(MODPUBKEY)
+mod_sign_cmd = perl $(srctree)/scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(MODSECKEY) $(MODPUBKEY)
else
mod_sign_cmd = true
endif
diff --git a/arch/Kconfig b/arch/Kconfig
index 7f8f281f2585..40e2b12c7916 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -76,6 +76,15 @@ config OPTPROBES
depends on KPROBES && HAVE_OPTPROBES
depends on !PREEMPT
+config KPROBES_ON_FTRACE
+ def_bool y
+ depends on KPROBES && HAVE_KPROBES_ON_FTRACE
+ depends on DYNAMIC_FTRACE_WITH_REGS
+ help
+ If function tracer is enabled and the arch supports full
+ passing of pt_regs to function tracing, then kprobes can
+ optimize on top of function tracing.
+
config UPROBES
bool "Transparent user-space probes (EXPERIMENTAL)"
depends on UPROBE_EVENT && PERF_EVENTS
@@ -158,6 +167,9 @@ config HAVE_KRETPROBES
config HAVE_OPTPROBES
bool
+config HAVE_KPROBES_ON_FTRACE
+ bool
+
config HAVE_NMI_WATCHDOG
bool
#
@@ -356,9 +368,6 @@ config MODULES_USE_ELF_REL
Modules only use ELF REL relocations. Modules with ELF RELA
relocations will give an error.
-config GENERIC_SIGALTSTACK
- bool
-
#
# ABI hall of shame
#
@@ -373,4 +382,30 @@ config CLONE_BACKWARDS2
help
Architecture has the first two arguments of clone(2) swapped.
+config ODD_RT_SIGACTION
+ bool
+ help
+ Architecture has unusual rt_sigaction(2) arguments
+
+config OLD_SIGSUSPEND
+ bool
+ help
+ Architecture has old sigsuspend(2) syscall, of one-argument variety
+
+config OLD_SIGSUSPEND3
+ bool
+ help
+ Even weirder antique ABI - three-argument sigsuspend(2)
+
+config OLD_SIGACTION
+ bool
+ help
+ Architecture has old sigaction(2) syscall. Nope, not the same
+ as OLD_SIGSUSPEND | OLD_SIGSUSPEND3 - alpha has sigsuspend(2),
+ but fairly different variant of sigaction(2), thanks to OSF/1
+ compatibility...
+
+config COMPAT_OLD_SIGACTION
+ bool
+
source "kernel/gcov/Kconfig"
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 9d5904cc7712..1ecbf7a1b677 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -5,7 +5,6 @@ config ALPHA
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_SYSCALL_WRAPPERS
- select HAVE_IRQ_WORK
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
select HAVE_DMA_ATTRS
@@ -22,7 +21,8 @@ config ALPHA
select GENERIC_STRNLEN_USER
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
- select GENERIC_SIGALTSTACK
+ select ODD_RT_SIGACTION
+ select OLD_SIGSUSPEND
help
The Alpha is a 64-bit general-purpose processor designed and
marketed by the Digital Equipment Corporation of blessed memory,
@@ -125,6 +125,7 @@ choice
config ALPHA_GENERIC
bool "Generic"
+ depends on TTY
help
A generic kernel will run on all supported Alpha hardware.
@@ -491,6 +492,7 @@ config VGA_HOSE
config ALPHA_SRM
bool "Use SRM as bootloader" if ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_NAUTILUS || ALPHA_NONAME
+ depends on TTY
default y if ALPHA_JENSEN || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_LYNX || ALPHA_NORITAKE || ALPHA_DP264 || ALPHA_RAWHIDE || ALPHA_EIGER || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_MARVEL
---help---
There are two different types of booting firmware on Alphas: SRM,
@@ -556,8 +558,7 @@ config NR_CPUS
with working support have a maximum of 4 CPUs.
config ARCH_DISCONTIGMEM_ENABLE
- bool "Discontiguous Memory Support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "Discontiguous Memory Support"
help
Say Y to support efficient handling of discontiguous physical memory,
for architectures which are either NUMA (Non-Uniform Memory Access)
diff --git a/arch/alpha/include/asm/signal.h b/arch/alpha/include/asm/signal.h
index 8a1ac28cd562..963f0494dca7 100644
--- a/arch/alpha/include/asm/signal.h
+++ b/arch/alpha/include/asm/signal.h
@@ -22,15 +22,6 @@ struct osf_sigaction {
int sa_flags;
};
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
- __sigrestore_t ka_restorer;
-};
+#define __ARCH_HAS_KA_RESTORER
#include <asm/sigcontext.h>
#endif
diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h
index b3396ee039b7..6d6fe7ab5473 100644
--- a/arch/alpha/include/asm/unistd.h
+++ b/arch/alpha/include/asm/unistd.h
@@ -14,7 +14,6 @@
#define __ARCH_WANT_SYS_OLD_GETRLIMIT
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index 097c1577735a..c5195524d1ef 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -19,7 +19,7 @@
#define SO_BROADCAST 0x0020
#define SO_LINGER 0x0080
#define SO_OOBINLINE 0x0100
-/* To add :#define SO_REUSEPORT 0x0200 */
+#define SO_REUSEPORT 0x0200
#define SO_TYPE 0x1008
#define SO_ERROR 0x1007
@@ -77,5 +77,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 14db93e4c8a8..b9e37ad6fa19 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -1139,6 +1139,7 @@ struct rusage32 {
SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru)
{
struct rusage32 r;
+ cputime_t utime, stime;
if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
return -EINVAL;
@@ -1146,8 +1147,9 @@ SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru)
memset(&r, 0, sizeof(r));
switch (who) {
case RUSAGE_SELF:
- jiffies_to_timeval32(current->utime, &r.ru_utime);
- jiffies_to_timeval32(current->stime, &r.ru_stime);
+ task_cputime(current, &utime, &stime);
+ jiffies_to_timeval32(utime, &r.ru_utime);
+ jiffies_to_timeval32(stime, &r.ru_stime);
r.ru_minflt = current->min_flt;
r.ru_majflt = current->maj_flt;
break;
@@ -1298,17 +1300,15 @@ static unsigned long
arch_get_unmapped_area_1(unsigned long addr, unsigned long len,
unsigned long limit)
{
- struct vm_area_struct *vma = find_vma(current->mm, addr);
-
- while (1) {
- /* At this point: (!vma || addr < vma->vm_end). */
- if (limit - len < addr)
- return -ENOMEM;
- if (!vma || addr + len <= vma->vm_start)
- return addr;
- addr = vma->vm_end;
- vma = vma->vm_next;
- }
+ struct vm_unmapped_area_info info;
+
+ info.flags = 0;
+ info.length = len;
+ info.low_limit = addr;
+ info.high_limit = limit;
+ info.align_mask = 0;
+ info.align_offset = 0;
+ return vm_unmapped_area(&info);
}
unsigned long
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index b5d0d0923699..63d27fb9b023 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -250,7 +250,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
struct pt_regs *childregs = task_pt_regs(p);
struct pt_regs *regs = current_pt_regs();
struct switch_stack *childstack, *stack;
- unsigned long settls;
childstack = ((struct switch_stack *) childregs) - 1;
childti->pcb.ksp = (unsigned long) childstack;
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 02d02c047f17..6cec2881acbf 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -113,16 +113,6 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act,
}
/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-/*
* Do a signal return; undo the signal stack.
*/
@@ -282,12 +272,9 @@ give_sigsegv:
*/
static inline void __user *
-get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+get_sigframe(struct ksignal *ksig, unsigned long sp, size_t frame_size)
{
- if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
- sp = current->sas_ss_sp + current->sas_ss_size;
-
- return (void __user *)((sp - frame_size) & -32ul);
+ return (void __user *)((sigsp(sp, ksig) - frame_size) & -32ul);
}
static long
@@ -348,14 +335,13 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
}
static int
-setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
- struct pt_regs *regs)
+setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
{
unsigned long oldsp, r26, err = 0;
struct sigframe __user *frame;
oldsp = rdusp();
- frame = get_sigframe(ka, oldsp, sizeof(*frame));
+ frame = get_sigframe(ksig, oldsp, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;
@@ -365,9 +351,8 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
- if (ka->ka_restorer) {
- r26 = (unsigned long) ka->ka_restorer;
- } else {
+ r26 = (unsigned long) ksig->ka.ka_restorer;
+ if (!r26) {
err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
err |= __put_user(INSN_CALLSYS, frame->retcode+2);
@@ -381,8 +366,8 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
/* "Return" to the handler */
regs->r26 = r26;
- regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
- regs->r16 = sig; /* a0: signal number */
+ regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
+ regs->r16 = ksig->sig; /* a0: signal number */
regs->r17 = 0; /* a1: exception code */
regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */
wrusp((unsigned long) frame);
@@ -395,18 +380,17 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
}
static int
-setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
{
unsigned long oldsp, r26, err = 0;
struct rt_sigframe __user *frame;
oldsp = rdusp();
- frame = get_sigframe(ka, oldsp, sizeof(*frame));
+ frame = get_sigframe(ksig, oldsp, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;
- err |= copy_siginfo_to_user(&frame->info, info);
+ err |= copy_siginfo_to_user(&frame->info, &ksig->info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
@@ -421,9 +405,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
- if (ka->ka_restorer) {
- r26 = (unsigned long) ka->ka_restorer;
- } else {
+ r26 = (unsigned long) ksig->ka.ka_restorer;
+ if (!r26) {
err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn,
frame->retcode+1);
@@ -437,8 +420,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* "Return" to the handler */
regs->r26 = r26;
- regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
- regs->r16 = sig; /* a0: signal number */
+ regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
+ regs->r16 = ksig->sig; /* a0: signal number */
regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */
regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */
wrusp((unsigned long) frame);
@@ -456,22 +439,17 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
* OK, we're invoking a handler.
*/
static inline void
-handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
- struct pt_regs * regs)
+handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
sigset_t *oldset = sigmask_to_save();
int ret;
- if (ka->sa.sa_flags & SA_SIGINFO)
- ret = setup_rt_frame(sig, ka, info, oldset, regs);
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+ ret = setup_rt_frame(ksig, oldset, regs);
else
- ret = setup_frame(sig, ka, oldset, regs);
+ ret = setup_frame(ksig, oldset, regs);
- if (ret) {
- force_sigsegv(sig, current);
- return;
- }
- signal_delivered(sig, info, ka, regs, 0);
+ signal_setup_done(ret, ksig, 0);
}
static inline void
@@ -514,47 +492,38 @@ syscall_restart(unsigned long r0, unsigned long r19,
static void
do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
{
- siginfo_t info;
- int signr;
unsigned long single_stepping = ptrace_cancel_bpt(current);
- struct k_sigaction ka;
+ struct ksignal ksig;
/* This lets the debugger run, ... */
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-
- /* ... so re-check the single stepping. */
- single_stepping |= ptrace_cancel_bpt(current);
-
- if (signr > 0) {
+ if (get_signal(&ksig)) {
+ /* ... so re-check the single stepping. */
+ single_stepping |= ptrace_cancel_bpt(current);
/* Whee! Actually deliver the signal. */
if (r0)
- syscall_restart(r0, r19, regs, &ka);
- handle_signal(signr, &ka, &info, regs);
- if (single_stepping)
- ptrace_set_bpt(current); /* re-set bpt */
- return;
- }
-
- if (r0) {
- switch (regs->r0) {
- case ERESTARTNOHAND:
- case ERESTARTSYS:
- case ERESTARTNOINTR:
- /* Reset v0 and a3 and replay syscall. */
- regs->r0 = r0;
- regs->r19 = r19;
- regs->pc -= 4;
- break;
- case ERESTART_RESTARTBLOCK:
- /* Force v0 to the restart syscall and reply. */
- regs->r0 = __NR_restart_syscall;
- regs->pc -= 4;
- break;
+ syscall_restart(r0, r19, regs, &ksig.ka);
+ handle_signal(&ksig, regs);
+ } else {
+ single_stepping |= ptrace_cancel_bpt(current);
+ if (r0) {
+ switch (regs->r0) {
+ case ERESTARTNOHAND:
+ case ERESTARTSYS:
+ case ERESTARTNOINTR:
+ /* Reset v0 and a3 and replay syscall. */
+ regs->r0 = r0;
+ regs->r19 = r19;
+ regs->pc -= 4;
+ break;
+ case ERESTART_RESTARTBLOCK:
+ /* Set v0 to the restart_syscall and replay */
+ regs->r0 = __NR_restart_syscall;
+ regs->pc -= 4;
+ break;
+ }
}
+ restore_saved_sigmask();
}
-
- /* If there's no signal to deliver, we just restore the saved mask. */
- restore_saved_sigmask();
if (single_stepping)
ptrace_set_bpt(current); /* re-set breakpoint */
}
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index 59b7bbad8394..6f01d9ad7b81 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -44,7 +44,7 @@ typedef union _srmcons_result {
/* called with callback_lock held */
static int
-srmcons_do_receive_chars(struct tty_struct *tty)
+srmcons_do_receive_chars(struct tty_port *port)
{
srmcons_result result;
int count = 0, loops = 0;
@@ -52,13 +52,13 @@ srmcons_do_receive_chars(struct tty_struct *tty)
do {
result.as_long = callback_getc(0);
if (result.bits.status < 2) {
- tty_insert_flip_char(tty, (char)result.bits.c, 0);
+ tty_insert_flip_char(port, (char)result.bits.c, 0);
count++;
}
} while((result.bits.status & 1) && (++loops < 10));
if (count)
- tty_schedule_flip(tty);
+ tty_schedule_flip(port);
return count;
}
@@ -73,7 +73,7 @@ srmcons_receive_chars(unsigned long data)
local_irq_save(flags);
if (spin_trylock(&srmcons_callback_lock)) {
- if (!srmcons_do_receive_chars(port->tty))
+ if (!srmcons_do_receive_chars(port))
incr = 100;
spin_unlock(&srmcons_callback_lock);
}
@@ -88,7 +88,7 @@ srmcons_receive_chars(unsigned long data)
/* called with callback_lock held */
static int
-srmcons_do_write(struct tty_struct *tty, const char *buf, int count)
+srmcons_do_write(struct tty_port *port, const char *buf, int count)
{
static char str_cr[1] = "\r";
long c, remaining = count;
@@ -113,10 +113,10 @@ srmcons_do_write(struct tty_struct *tty, const char *buf, int count)
cur += result.bits.c;
/*
- * Check for pending input iff a tty was provided
+ * Check for pending input iff a tty port was provided
*/
- if (tty)
- srmcons_do_receive_chars(tty);
+ if (port)
+ srmcons_do_receive_chars(port);
}
while (need_cr) {
@@ -135,7 +135,7 @@ srmcons_write(struct tty_struct *tty,
unsigned long flags;
spin_lock_irqsave(&srmcons_callback_lock, flags);
- srmcons_do_write(tty, (const char *) buf, count);
+ srmcons_do_write(tty->port, (const char *) buf, count);
spin_unlock_irqrestore(&srmcons_callback_lock, flags);
return count;
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 272666d006df..4037461a6493 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -186,7 +186,7 @@ die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15)
#endif
printk("%s(%d): %s %ld\n", current->comm, task_pid_nr(current), str, err);
dik_show_regs(regs, r9_15);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
dik_show_trace((unsigned long *)(regs+1));
dik_show_code((unsigned int *)regs->pc);
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 67874b82a4ed..a955d89ed836 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -4,6 +4,7 @@ config ARM
select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAVE_CUSTOM_GPIO_H
+ select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_WANT_IPC_PARSE_VERSION
select BUILDTIME_EXTABLE_SORT if MMU
select CPU_PM if (SUSPEND || CPU_IDLE)
@@ -36,7 +37,6 @@ config ARM
select HAVE_GENERIC_HARDIRQS
select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
select HAVE_IDE if PCI || ISA || PCMCIA
- select HAVE_IRQ_WORK
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
@@ -56,6 +56,8 @@ config ARM
select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
select MODULES_USE_ELF_REL
select CLONE_BACKWARDS
+ select OLD_SIGSUSPEND3
+ select OLD_SIGACTION
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
@@ -261,7 +263,8 @@ config MMU
#
choice
prompt "ARM system type"
- default ARCH_MULTIPLATFORM
+ default ARCH_VERSATILE if !MMU
+ default ARCH_MULTIPLATFORM if MMU
config ARCH_MULTIPLATFORM
bool "Allow multiple platforms to be selected"
@@ -344,10 +347,10 @@ config ARCH_BCM2835
select ARM_ERRATA_411920
select ARM_TIMER_SP804
select CLKDEV_LOOKUP
+ select CLKSRC_OF
select COMMON_CLK
select CPU_V6
select GENERIC_CLOCKEVENTS
- select GENERIC_GPIO
select MULTI_IRQ_HANDLER
select PINCTRL
select PINCTRL_BCM2835
@@ -393,6 +396,7 @@ config ARCH_GEMINI
config ARCH_SIRF
bool "CSR SiRF"
select ARCH_REQUIRE_GPIOLIB
+ select AUTO_ZRELADDR
select COMMON_CLK
select GENERIC_CLOCKEVENTS
select GENERIC_IRQ_CHIP
@@ -640,11 +644,12 @@ config ARCH_LPC32XX
config ARCH_TEGRA
bool "NVIDIA Tegra"
select ARCH_HAS_CPUFREQ
+ select ARCH_REQUIRE_GPIOLIB
select CLKDEV_LOOKUP
select CLKSRC_MMIO
+ select CLKSRC_OF
select COMMON_CLK
select GENERIC_CLOCKEVENTS
- select GENERIC_GPIO
select HAVE_CLK
select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
@@ -698,6 +703,7 @@ config ARCH_SHMOBILE
select MULTI_IRQ_HANDLER
select NEED_MACH_MEMORY_H
select NO_IOPORT
+ select PINCTRL
select PM_GENERIC_DOMAINS if PM
select SPARSE_IRQ
help
@@ -744,7 +750,6 @@ config ARCH_S3C24XX
select ARCH_HAS_CPUFREQ
select ARCH_USES_GETTIMEOFFSET
select CLKDEV_LOOKUP
- select GENERIC_GPIO
select HAVE_CLK
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C2410_WATCHDOG if WATCHDOG
@@ -787,7 +792,6 @@ config ARCH_S5P64X0
select CLKSRC_MMIO
select CPU_V6
select GENERIC_CLOCKEVENTS
- select GENERIC_GPIO
select HAVE_CLK
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C2410_WATCHDOG if WATCHDOG
@@ -802,7 +806,6 @@ config ARCH_S5PC100
select ARCH_USES_GETTIMEOFFSET
select CLKDEV_LOOKUP
select CPU_V7
- select GENERIC_GPIO
select HAVE_CLK
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C2410_WATCHDOG if WATCHDOG
@@ -820,7 +823,6 @@ config ARCH_S5PV210
select CLKSRC_MMIO
select CPU_V7
select GENERIC_CLOCKEVENTS
- select GENERIC_GPIO
select HAVE_CLK
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C2410_WATCHDOG if WATCHDOG
@@ -838,7 +840,6 @@ config ARCH_EXYNOS
select CLKDEV_LOOKUP
select CPU_V7
select GENERIC_CLOCKEVENTS
- select GENERIC_GPIO
select HAVE_CLK
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C2410_WATCHDOG if WATCHDOG
@@ -873,7 +874,6 @@ config ARCH_U300
select COMMON_CLK
select CPU_ARM926T
select GENERIC_CLOCKEVENTS
- select GENERIC_GPIO
select HAVE_TCM
select SPARSE_IRQ
help
@@ -899,10 +899,12 @@ config ARCH_NOMADIK
select ARCH_REQUIRE_GPIOLIB
select ARM_AMBA
select ARM_VIC
+ select CLKSRC_NOMADIK_MTU
select COMMON_CLK
select CPU_ARM926T
select GENERIC_CLOCKEVENTS
select MIGHT_HAVE_CACHE_L2X0
+ select USE_OF
select PINCTRL
select PINCTRL_STN8815
select SPARSE_IRQ
@@ -937,33 +939,24 @@ config ARCH_DAVINCI
help
Support for TI's DaVinci platform.
-config ARCH_OMAP
- bool "TI OMAP"
+config ARCH_OMAP1
+ bool "TI OMAP1"
depends on MMU
select ARCH_HAS_CPUFREQ
select ARCH_HAS_HOLES_MEMORYMODEL
- select ARCH_REQUIRE_GPIOLIB
- select CLKSRC_MMIO
- select GENERIC_CLOCKEVENTS
- select HAVE_CLK
- help
- Support for TI's OMAP platform (OMAP1/2/3/4).
-
-config ARCH_VT8500_SINGLE
- bool "VIA/WonderMedia 85xx"
- select ARCH_HAS_CPUFREQ
+ select ARCH_OMAP
select ARCH_REQUIRE_GPIOLIB
select CLKDEV_LOOKUP
- select COMMON_CLK
- select CPU_ARM926T
+ select CLKSRC_MMIO
select GENERIC_CLOCKEVENTS
- select GENERIC_GPIO
+ select GENERIC_IRQ_CHIP
select HAVE_CLK
- select MULTI_IRQ_HANDLER
- select SPARSE_IRQ
- select USE_OF
+ select HAVE_IDE
+ select IRQ_DOMAIN
+ select NEED_MACH_IO_H if PCCARD
+ select NEED_MACH_MEMORY_H
help
- Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip.
+ Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
endchoice
@@ -1086,17 +1079,12 @@ source "arch/arm/mach-realview/Kconfig"
source "arch/arm/mach-sa1100/Kconfig"
source "arch/arm/plat-samsung/Kconfig"
-source "arch/arm/plat-s3c24xx/Kconfig"
source "arch/arm/mach-socfpga/Kconfig"
source "arch/arm/plat-spear/Kconfig"
source "arch/arm/mach-s3c24xx/Kconfig"
-if ARCH_S3C24XX
-source "arch/arm/mach-s3c2412/Kconfig"
-source "arch/arm/mach-s3c2440/Kconfig"
-endif
if ARCH_S3C64XX
source "arch/arm/mach-s3c64xx/Kconfig"
@@ -1127,6 +1115,8 @@ source "arch/arm/mach-versatile/Kconfig"
source "arch/arm/mach-vexpress/Kconfig"
source "arch/arm/plat-versatile/Kconfig"
+source "arch/arm/mach-virt/Kconfig"
+
source "arch/arm/mach-vt8500/Kconfig"
source "arch/arm/mach-w90x900/Kconfig"
@@ -1450,6 +1440,10 @@ config ISA_DMA
bool
select ISA_DMA_API
+config ARCH_NO_VIRT_TO_BUS
+ def_bool y
+ depends on !ARCH_RPC && !ARCH_NETWINDER && !ARCH_SHARK
+
# Select ISA DMA interface
config ISA_DMA_API
bool
@@ -1531,7 +1525,6 @@ config SMP
config SMP_ON_UP
bool "Allow booting SMP kernel on uniprocessor systems (EXPERIMENTAL)"
- depends on EXPERIMENTAL
depends on SMP && !XIP_KERNEL
default y
help
@@ -1572,9 +1565,10 @@ config HAVE_ARM_SCU
help
This option enables support for the ARM system coherency unit
-config ARM_ARCH_TIMER
+config HAVE_ARM_ARCH_TIMER
bool "Architected timer support"
depends on CPU_V7
+ select ARM_ARCH_TIMER
help
This option enables support for the ARM architected timer
@@ -1620,6 +1614,16 @@ config HOTPLUG_CPU
Say Y here to experiment with turning CPUs off and on. CPUs
can be controlled through /sys/devices/system/cpu.
+config ARM_PSCI
+ bool "Support for the ARM Power State Coordination Interface (PSCI)"
+ depends on CPU_V7
+ help
+ Say Y here if you want Linux to communicate with system firmware
+ implementing the PSCI specification for CPU-centric power
+ management operations described in ARM document number ARM DEN
+ 0022A ("Power State Coordination Interface System Software on
+ ARM processors").
+
config LOCAL_TIMERS
bool "Use local timer interrupts"
depends on SMP
@@ -1637,7 +1641,7 @@ config ARCH_NR_GPIO
default 355 if ARCH_U8500
default 264 if MACH_H4700
default 512 if SOC_OMAP5
- default 288 if ARCH_VT8500
+ default 288 if ARCH_VT8500 || ARCH_SUNXI
default 0
help
Maximum number of GPIOs in the system.
@@ -1655,6 +1659,9 @@ config HZ
default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE
default 100
+config SCHED_HRTICK
+ def_bool HIGH_RES_TIMERS
+
config THUMB2_KERNEL
bool "Compile the kernel in Thumb-2 mode"
depends on CPU_V7 && !CPU_V6 && !CPU_V6K
@@ -1719,7 +1726,7 @@ config AEABI
config OABI_COMPAT
bool "Allow old ABI binaries to run with this kernel (EXPERIMENTAL)"
- depends on AEABI && EXPERIMENTAL && !THUMB2_KERNEL
+ depends on AEABI && !THUMB2_KERNEL
default y
help
This option preserves the old syscall interface along with the
@@ -1843,7 +1850,6 @@ config SECCOMP
config CC_STACKPROTECTOR
bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
- depends on EXPERIMENTAL
help
This option turns on the -fstack-protector GCC feature. This
feature puts, at the beginning of functions, a canary value on
@@ -1860,7 +1866,7 @@ config XEN_DOM0
config XEN
bool "Xen guest support on ARM (EXPERIMENTAL)"
- depends on EXPERIMENTAL && ARM && OF
+ depends on ARM && OF
depends on CPU_V7 && !CPU_V6
help
Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
@@ -1929,7 +1935,7 @@ config ZBOOT_ROM
choice
prompt "Include SD/MMC loader in zImage (EXPERIMENTAL)"
- depends on ZBOOT_ROM && ARCH_SH7372 && EXPERIMENTAL
+ depends on ZBOOT_ROM && ARCH_SH7372
default ZBOOT_ROM_NONE
help
Include experimental SD/MMC loading code in the ROM-able zImage.
@@ -1958,7 +1964,7 @@ endchoice
config ARM_APPENDED_DTB
bool "Use appended device tree blob to zImage (EXPERIMENTAL)"
- depends on OF && !ZBOOT_ROM && EXPERIMENTAL
+ depends on OF && !ZBOOT_ROM
help
With this option, the boot code will look for a device tree binary
(DTB) appended to zImage
@@ -2076,7 +2082,7 @@ config XIP_PHYS_ADDR
config KEXEC
bool "Kexec system call (EXPERIMENTAL)"
- depends on EXPERIMENTAL && (!SMP || HOTPLUG_CPU)
+ depends on (!SMP || HOTPLUG_CPU)
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
@@ -2098,7 +2104,6 @@ config ATAGS_PROC
config CRASH_DUMP
bool "Build kdump crash kernel (EXPERIMENTAL)"
- depends on EXPERIMENTAL
help
Generate crash dump after being started by kexec. This should
be normally only set in special crash dump kernels which are
@@ -2165,7 +2170,7 @@ config CPU_FREQ_S3C
config CPU_FREQ_S3C24XX
bool "CPUfreq driver for Samsung S3C24XX series CPUs (EXPERIMENTAL)"
- depends on ARCH_S3C24XX && CPU_FREQ && EXPERIMENTAL
+ depends on ARCH_S3C24XX && CPU_FREQ
select CPU_FREQ_S3C
help
This enables the CPUfreq driver for the Samsung S3C24XX family
@@ -2177,7 +2182,7 @@ config CPU_FREQ_S3C24XX
config CPU_FREQ_S3C24XX_PLL
bool "Support CPUfreq changing of PLL frequency (EXPERIMENTAL)"
- depends on CPU_FREQ_S3C24XX && EXPERIMENTAL
+ depends on CPU_FREQ_S3C24XX
help
Compile in support for changing the PLL frequency from the
S3C24XX series CPUfreq driver. The PLL takes time to settle
@@ -2240,7 +2245,7 @@ config FPE_NWFPE_XP
config FPE_FASTFPE
bool "FastFPE math emulation (EXPERIMENTAL)"
- depends on (!AEABI || OABI_COMPAT) && !CPU_32v3 && EXPERIMENTAL
+ depends on (!AEABI || OABI_COMPAT) && !CPU_32v3
---help---
Say Y here to include the FAST floating point emulator in the kernel.
This is an experimental much faster emulator which now also has full
@@ -2322,3 +2327,5 @@ source "security/Kconfig"
source "crypto/Kconfig"
source "lib/Kconfig"
+
+source "arch/arm/kvm/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 661030d6bc6c..acddddac7ee4 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -32,7 +32,7 @@ config FRAME_POINTER
config ARM_UNWIND
bool "Enable stack unwinding support (EXPERIMENTAL)"
- depends on AEABI && EXPERIMENTAL
+ depends on AEABI
default y
help
This option enables stack unwinding support in the kernel
@@ -205,12 +205,19 @@ choice
Say Y here if you want kernel low-level debugging support
on i.MX28.
- config DEBUG_IMX31_IMX35_UART
- bool "i.MX31 and i.MX35 Debug UART"
- depends on SOC_IMX31 || SOC_IMX35
+ config DEBUG_IMX31_UART
+ bool "i.MX31 Debug UART"
+ depends on SOC_IMX31
help
Say Y here if you want kernel low-level debugging support
- on i.MX31 or i.MX35.
+ on i.MX31.
+
+ config DEBUG_IMX35_UART
+ bool "i.MX35 Debug UART"
+ depends on SOC_IMX35
+ help
+ Say Y here if you want kernel low-level debugging support
+ on i.MX35.
config DEBUG_IMX51_UART
bool "i.MX51 Debug UART"
@@ -219,12 +226,12 @@ choice
Say Y here if you want kernel low-level debugging support
on i.MX51.
- config DEBUG_IMX50_IMX53_UART
- bool "i.MX50 and i.MX53 Debug UART"
- depends on SOC_IMX50 || SOC_IMX53
+ config DEBUG_IMX53_UART
+ bool "i.MX53 Debug UART"
+ depends on SOC_IMX53
help
Say Y here if you want kernel low-level debugging support
- on i.MX50 or i.MX53.
+ on i.MX53.
config DEBUG_IMX6Q_UART
bool "i.MX6Q Debug UART"
@@ -291,6 +298,13 @@ choice
Say Y here if you want kernel low-level debugging support
on MVEBU based platforms.
+ config DEBUG_OMAP2PLUS_UART
+ bool "Kernel low-level debugging messages via OMAP2PLUS UART"
+ depends on ARCH_OMAP2PLUS
+ help
+ Say Y here if you want kernel low-level debugging support
+ on OMAP2PLUS based platforms.
+
config DEBUG_PICOXCELL_UART
depends on ARCH_PICOXCELL
bool "Use PicoXcell UART for low-level debug"
@@ -386,6 +400,20 @@ choice
Say Y here if you want kernel low-level debugging support
on Tegra based platforms.
+ config DEBUG_SIRFPRIMA2_UART1
+ bool "Kernel low-level debugging messages via SiRFprimaII UART1"
+ depends on ARCH_PRIMA2
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the uart1 port on SiRFprimaII devices.
+
+ config DEBUG_SIRFMARCO_UART1
+ bool "Kernel low-level debugging messages via SiRFmarco UART1"
+ depends on ARCH_MARCO
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the uart1 port on SiRFmarco devices.
+
config DEBUG_VEXPRESS_UART0_DETECT
bool "Autodetect UART0 on Versatile Express Cortex-A core tiles"
depends on ARCH_VEXPRESS && CPU_CP15_MMU
@@ -412,6 +440,13 @@ choice
of the tiles using the RS1 memory map, including all new A-class
core tiles, FPGA-based SMMs and software models.
+ config DEBUG_VT8500_UART0
+ bool "Use UART0 on VIA/Wondermedia SoCs"
+ depends on ARCH_VT8500
+ help
+ This option selects UART0 on VIA/Wondermedia System-on-a-chip
+ devices, including VT8500, WM8505, WM8650 and WM8850.
+
config DEBUG_LL_UART_NONE
bool "No low-level debugging UART"
depends on !ARCH_MULTIPLATFORM
@@ -450,17 +485,70 @@ choice
endchoice
-config DEBUG_IMX6Q_UART_PORT
- int "i.MX6Q Debug UART Port (1-5)" if DEBUG_IMX6Q_UART
- range 1 5
+config DEBUG_IMX_UART_PORT
+ int "i.MX Debug UART Port Selection" if DEBUG_IMX1_UART || \
+ DEBUG_IMX25_UART || \
+ DEBUG_IMX21_IMX27_UART || \
+ DEBUG_IMX31_UART || \
+ DEBUG_IMX35_UART || \
+ DEBUG_IMX51_UART || \
+ DEBUG_IMX50_IMX53_UART || \
+ DEBUG_IMX6Q_UART
default 1
- depends on SOC_IMX6Q
help
Choose UART port on which kernel low-level debug messages
should be output.
choice
prompt "Low-level debug console UART"
+ depends on DEBUG_OMAP2PLUS_UART
+
+ config DEBUG_OMAP2UART1
+ bool "OMAP2/3/4 UART1 (omap2/3 sdp boards and some omap3 boards)"
+ help
+ This covers at least h4, 2430sdp, 3430sdp, 3630sdp,
+ omap3 torpedo and 3530 lv som.
+
+ config DEBUG_OMAP2UART2
+ bool "OMAP2/3/4 UART2"
+
+ config DEBUG_OMAP2UART3
+ bool "OMAP2 UART3 (n8x0)"
+
+ config DEBUG_OMAP3UART3
+ bool "OMAP3 UART3 (most omap3 boards)"
+ help
+ This covers at least cm_t3x, beagle, crane, devkit8000,
+ igep00x0, ldp, n900, n9(50), pandora, overo, touchbook,
+ and 3517evm.
+
+ config DEBUG_OMAP4UART3
+ bool "OMAP4/5 UART3 (omap4 blaze, panda, omap5 sevm)"
+
+ config DEBUG_OMAP3UART4
+ bool "OMAP36XX UART4"
+
+ config DEBUG_OMAP4UART4
+ bool "OMAP4/5 UART4"
+
+ config DEBUG_TI81XXUART1
+ bool "TI81XX UART1 (ti8148evm)"
+
+ config DEBUG_TI81XXUART2
+ bool "TI81XX UART2"
+
+ config DEBUG_TI81XXUART3
+ bool "TI81XX UART3 (ti8168evm)"
+
+ config DEBUG_AM33XXUART1
+ bool "AM33XX UART1"
+
+ config DEBUG_ZOOM_UART
+ bool "Zoom2/3 UART"
+endchoice
+
+choice
+ prompt "Low-level debug console UART"
depends on DEBUG_LL && DEBUG_TEGRA_UART
config TEGRA_DEBUG_UART_AUTO_ODMDATA
@@ -495,17 +583,20 @@ config DEBUG_LL_INCLUDE
default "debug/imx.S" if DEBUG_IMX1_UART || \
DEBUG_IMX25_UART || \
DEBUG_IMX21_IMX27_UART || \
- DEBUG_IMX31_IMX35_UART || \
+ DEBUG_IMX31_UART || \
+ DEBUG_IMX35_UART || \
DEBUG_IMX51_UART || \
- DEBUG_IMX50_IMX53_UART ||\
+ DEBUG_IMX53_UART ||\
DEBUG_IMX6Q_UART
default "debug/highbank.S" if DEBUG_HIGHBANK_UART
default "debug/mvebu.S" if DEBUG_MVEBU_UART
+ default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART
default "debug/picoxcell.S" if DEBUG_PICOXCELL_UART
default "debug/socfpga.S" if DEBUG_SOCFPGA_UART
default "debug/sunxi.S" if DEBUG_SUNXI_UART0 || DEBUG_SUNXI_UART1
default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT || \
DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1
+ default "debug/vt8500.S" if DEBUG_VT8500_UART0
default "debug/tegra.S" if DEBUG_TEGRA_UART
default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
default "mach/debug-macro.S"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 30c443c406f3..ee4605f400b0 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -173,7 +173,7 @@ machine-$(CONFIG_ARCH_PRIMA2) += prima2
machine-$(CONFIG_ARCH_PXA) += pxa
machine-$(CONFIG_ARCH_REALVIEW) += realview
machine-$(CONFIG_ARCH_RPC) += rpc
-machine-$(CONFIG_ARCH_S3C24XX) += s3c24xx s3c2412 s3c2440
+machine-$(CONFIG_ARCH_S3C24XX) += s3c24xx
machine-$(CONFIG_ARCH_S3C64XX) += s3c64xx
machine-$(CONFIG_ARCH_S5P64X0) += s5p64x0
machine-$(CONFIG_ARCH_S5PC100) += s5pc100
@@ -194,6 +194,7 @@ machine-$(CONFIG_ARCH_SOCFPGA) += socfpga
machine-$(CONFIG_ARCH_SPEAR13XX) += spear13xx
machine-$(CONFIG_ARCH_SPEAR3XX) += spear3xx
machine-$(CONFIG_MACH_SPEAR600) += spear6xx
+machine-$(CONFIG_ARCH_VIRT) += virt
machine-$(CONFIG_ARCH_ZYNQ) += zynq
machine-$(CONFIG_ARCH_SUNXI) += sunxi
@@ -204,7 +205,7 @@ plat-$(CONFIG_ARCH_S3C64XX) += samsung
plat-$(CONFIG_PLAT_IOP) += iop
plat-$(CONFIG_PLAT_ORION) += orion
plat-$(CONFIG_PLAT_PXA) += pxa
-plat-$(CONFIG_PLAT_S3C24XX) += s3c24xx samsung
+plat-$(CONFIG_PLAT_S3C24XX) += samsung
plat-$(CONFIG_PLAT_S5P) += samsung
plat-$(CONFIG_PLAT_SPEAR) += spear
plat-$(CONFIG_PLAT_VERSATILE) += versatile
@@ -252,6 +253,7 @@ core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
core-$(CONFIG_VFP) += arch/arm/vfp/
core-$(CONFIG_XEN) += arch/arm/xen/
+core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/
# If we have a machine-specific directory, then include it in the build.
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c
index 9deb56a702ce..24b0475cb8bf 100644
--- a/arch/arm/boot/compressed/decompress.c
+++ b/arch/arm/boot/compressed/decompress.c
@@ -13,8 +13,6 @@ extern void error(char *);
#define STATIC static
#define STATIC_RW_DATA /* non-static please */
-#define ARCH_HAS_DECOMP_WDOG
-
/* Diagnostic functions */
#ifdef DEBUG
# define Assert(cond,msg) {if(!(cond)) error(msg);}
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 5ebb44fe826a..411ab1614a0e 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -73,6 +73,7 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-dns320.dtb \
kirkwood-ts219-6281.dtb \
kirkwood-ts219-6282.dtb \
kirkwood-openblocks_a6.dtb
+dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb
dtb-$(CONFIG_ARCH_MSM) += msm8660-surf.dtb \
msm8960-cdp.dtb
dtb-$(CONFIG_ARCH_MVEBU) += armada-370-db.dtb \
@@ -95,11 +96,13 @@ dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \
imx28-apf28dev.dtb \
imx28-apx4devkit.dtb \
imx28-cfa10036.dtb \
+ imx28-cfa10037.dtb \
imx28-cfa10049.dtb \
imx28-evk.dtb \
imx28-m28evk.dtb \
imx28-sps1.dtb \
imx28-tx28.dtb
+dtb-$(CONFIG_ARCH_NOMADIK) += ste-nomadik-s8815.dtb
dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
omap3-beagle.dtb \
omap3-beagle-xm.dtb \
@@ -124,6 +127,8 @@ dtb-$(CONFIG_ARCH_SHMOBILE) += emev2-kzm9d.dtb \
r8a7740-armadillo800eva.dtb \
sh73a0-kzm9g.dtb \
sh7372-mackerel.dtb
+dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_cyclone5.dtb \
+ socfpga_vt.dtb
dtb-$(CONFIG_ARCH_SPEAR13XX) += spear1310-evb.dtb \
spear1340-evb.dtb
dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \
@@ -132,8 +137,10 @@ dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \
spear320-hmi.dtb
dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb
dtb-$(CONFIG_ARCH_SUNXI) += sun4i-a10-cubieboard.dtb \
+ sun4i-a10-hackberry.dtb \
sun5i-a13-olinuxino.dtb
dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
+ tegra20-iris-512.dtb \
tegra20-medcom-wide.dtb \
tegra20-paz00.dtb \
tegra20-plutux.dtb \
@@ -142,8 +149,11 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
tegra20-trimslice.dtb \
tegra20-ventana.dtb \
tegra20-whistler.dtb \
+ tegra30-beaver.dtb \
tegra30-cardhu-a02.dtb \
- tegra30-cardhu-a04.dtb
+ tegra30-cardhu-a04.dtb \
+ tegra114-dalmore.dtb \
+ tegra114-pluto.dtb
dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
vexpress-v2p-ca9.dtb \
vexpress-v2p-ca15-tc1.dtb \
@@ -151,7 +161,8 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
xenvm-4.2.dtb
dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \
wm8505-ref.dtb \
- wm8650-mid.dtb
+ wm8650-mid.dtb \
+ wm8850-w70v2.dtb
dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb
targets += dtbs
diff --git a/arch/arm/boot/dts/animeo_ip.dts b/arch/arm/boot/dts/animeo_ip.dts
index 74d92cd29d87..5160210f74da 100644
--- a/arch/arm/boot/dts/animeo_ip.dts
+++ b/arch/arm/boot/dts/animeo_ip.dts
@@ -78,6 +78,10 @@
bus-width = <4>;
};
};
+
+ watchdog@fffffd40 {
+ status = "okay";
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index 4c0abe85405f..5b2922599f0e 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -131,6 +131,12 @@
clocks = <&coreclk 0>;
status = "disabled";
};
+
+ rtc@10300 {
+ compatible = "marvell,orion-rtc";
+ reg = <0xd0010300 0x20>;
+ interrupts = <50>;
+ };
};
};
diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi
index 222047f1ece9..b0268a5f4b4e 100644
--- a/arch/arm/boot/dts/at91rm9200.dtsi
+++ b/arch/arm/boot/dts/at91rm9200.dtsi
@@ -29,6 +29,9 @@
gpio3 = &pioD;
tcb0 = &tcb0;
tcb1 = &tcb1;
+ ssc0 = &ssc0;
+ ssc1 = &ssc1;
+ ssc2 = &ssc2;
};
cpus {
cpu@0 {
@@ -88,6 +91,52 @@
interrupts = <20 4 0 21 4 0 22 4 0>;
};
+ mmc0: mmc@fffb4000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfffb4000 0x4000>;
+ interrupts = <10 4 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ ssc0: ssc@fffd0000 {
+ compatible = "atmel,at91rm9200-ssc";
+ reg = <0xfffd0000 0x4000>;
+ interrupts = <14 4 5>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
+ status = "disable";
+ };
+
+ ssc1: ssc@fffd4000 {
+ compatible = "atmel,at91rm9200-ssc";
+ reg = <0xfffd4000 0x4000>;
+ interrupts = <15 4 5>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>;
+ status = "disable";
+ };
+
+ ssc2: ssc@fffd8000 {
+ compatible = "atmel,at91rm9200-ssc";
+ reg = <0xfffd8000 0x4000>;
+ interrupts = <16 4 5>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ssc2_tx &pinctrl_ssc2_rx>;
+ status = "disable";
+ };
+
+ macb0: ethernet@fffbc000 {
+ compatible = "cdns,at91rm9200-emac", "cdns,emac";
+ reg = <0xfffbc000 0x4000>;
+ interrupts = <24 4 3>;
+ phy-mode = "rmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_macb_rmii>;
+ status = "disabled";
+ };
+
pinctrl@fffff400 {
#address-cells = <1>;
#size-cells = <1>;
@@ -207,6 +256,115 @@
};
};
+ macb {
+ pinctrl_macb_rmii: macb_rmii-0 {
+ atmel,pins =
+ <0 7 0x1 0x0 /* PA7 periph A */
+ 0 8 0x1 0x0 /* PA8 periph A */
+ 0 9 0x1 0x0 /* PA9 periph A */
+ 0 10 0x1 0x0 /* PA10 periph A */
+ 0 11 0x1 0x0 /* PA11 periph A */
+ 0 12 0x1 0x0 /* PA12 periph A */
+ 0 13 0x1 0x0 /* PA13 periph A */
+ 0 14 0x1 0x0 /* PA14 periph A */
+ 0 15 0x1 0x0 /* PA15 periph A */
+ 0 16 0x1 0x0>; /* PA16 periph A */
+ };
+
+ pinctrl_macb_rmii_mii: macb_rmii_mii-0 {
+ atmel,pins =
+ <1 12 0x2 0x0 /* PB12 periph B */
+ 1 13 0x2 0x0 /* PB13 periph B */
+ 1 14 0x2 0x0 /* PB14 periph B */
+ 1 15 0x2 0x0 /* PB15 periph B */
+ 1 16 0x2 0x0 /* PB16 periph B */
+ 1 17 0x2 0x0 /* PB17 periph B */
+ 1 18 0x2 0x0 /* PB18 periph B */
+ 1 19 0x2 0x0>; /* PB19 periph B */
+ };
+ };
+
+ mmc0 {
+ pinctrl_mmc0_clk: mmc0_clk-0 {
+ atmel,pins =
+ <0 27 0x1 0x0>; /* PA27 periph A */
+ };
+
+ pinctrl_mmc0_slot0_cmd_dat0: mmc0_slot0_cmd_dat0-0 {
+ atmel,pins =
+ <0 28 0x1 0x1 /* PA28 periph A with pullup */
+ 0 29 0x1 0x1>; /* PA29 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot0_dat1_3: mmc0_slot0_dat1_3-0 {
+ atmel,pins =
+ <1 3 0x2 0x1 /* PB3 periph B with pullup */
+ 1 4 0x2 0x1 /* PB4 periph B with pullup */
+ 1 5 0x2 0x1>; /* PB5 periph B with pullup */
+ };
+
+ pinctrl_mmc0_slot1_cmd_dat0: mmc0_slot1_cmd_dat0-0 {
+ atmel,pins =
+ <0 8 0x2 0x1 /* PA8 periph B with pullup */
+ 0 9 0x2 0x1>; /* PA9 periph B with pullup */
+ };
+
+ pinctrl_mmc0_slot1_dat1_3: mmc0_slot1_dat1_3-0 {
+ atmel,pins =
+ <0 10 0x2 0x1 /* PA10 periph B with pullup */
+ 0 11 0x2 0x1 /* PA11 periph B with pullup */
+ 0 12 0x2 0x1>; /* PA12 periph B with pullup */
+ };
+ };
+
+ ssc0 {
+ pinctrl_ssc0_tx: ssc0_tx-0 {
+ atmel,pins =
+ <1 0 0x1 0x0 /* PB0 periph A */
+ 1 1 0x1 0x0 /* PB1 periph A */
+ 1 2 0x1 0x0>; /* PB2 periph A */
+ };
+
+ pinctrl_ssc0_rx: ssc0_rx-0 {
+ atmel,pins =
+ <1 3 0x1 0x0 /* PB3 periph A */
+ 1 4 0x1 0x0 /* PB4 periph A */
+ 1 5 0x1 0x0>; /* PB5 periph A */
+ };
+ };
+
+ ssc1 {
+ pinctrl_ssc1_tx: ssc1_tx-0 {
+ atmel,pins =
+ <1 6 0x1 0x0 /* PB6 periph A */
+ 1 7 0x1 0x0 /* PB7 periph A */
+ 1 8 0x1 0x0>; /* PB8 periph A */
+ };
+
+ pinctrl_ssc1_rx: ssc1_rx-0 {
+ atmel,pins =
+ <1 9 0x1 0x0 /* PB9 periph A */
+ 1 10 0x1 0x0 /* PB10 periph A */
+ 1 11 0x1 0x0>; /* PB11 periph A */
+ };
+ };
+
+ ssc2 {
+ pinctrl_ssc2_tx: ssc2_tx-0 {
+ atmel,pins =
+ <1 12 0x1 0x0 /* PB12 periph A */
+ 1 13 0x1 0x0 /* PB13 periph A */
+ 1 14 0x1 0x0>; /* PB14 periph A */
+ };
+
+ pinctrl_ssc2_rx: ssc2_rx-0 {
+ atmel,pins =
+ <1 15 0x1 0x0 /* PB15 periph A */
+ 1 16 0x1 0x0 /* PB16 periph A */
+ 1 17 0x1 0x0>; /* PB17 periph A */
+ };
+ };
+
pioA: gpio@fffff400 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff400 0x200>;
diff --git a/arch/arm/boot/dts/at91rm9200ek.dts b/arch/arm/boot/dts/at91rm9200ek.dts
index 8aa48931e0a2..e586d85f8e23 100644
--- a/arch/arm/boot/dts/at91rm9200ek.dts
+++ b/arch/arm/boot/dts/at91rm9200ek.dts
@@ -44,6 +44,11 @@
status = "okay";
};
+ macb0: ethernet@fffbc000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
usb1: gadget@fffb0000 {
atmel,vbus-gpio = <&pioD 4 0>;
status = "okay";
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index 80e29c605d4e..7750f98dd764 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -324,8 +324,6 @@
compatible = "atmel,at91sam9260-usart";
reg = <0xf801c000 0x4000>;
interrupts = <5 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart0>;
status = "disabled";
@@ -335,8 +333,6 @@
compatible = "atmel,at91sam9260-usart";
reg = <0xf8020000 0x4000>;
interrupts = <6 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart1>;
status = "disabled";
@@ -346,8 +342,6 @@
compatible = "atmel,at91sam9260-usart";
reg = <0xf8024000 0x4000>;
interrupts = <7 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart2>;
status = "disabled";
@@ -357,8 +351,6 @@
compatible = "atmel,at91sam9260-usart";
reg = <0xf8028000 0x4000>;
interrupts = <8 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart3>;
status = "disabled";
@@ -390,8 +382,9 @@
reg = < 0x40000000 0x10000000
0xffffe000 0x00000600
0xffffe600 0x00000200
- 0x00100000 0x00100000
+ 0x00108000 0x00018000
>;
+ atmel,pmecc-lookup-table-offset = <0x0 0x8000>;
atmel,nand-addr-offset = <21>;
atmel,nand-cmd-offset = <22>;
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
index 0376bf4fd66b..d400f8de4387 100644
--- a/arch/arm/boot/dts/at91sam9n12ek.dts
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -71,7 +71,10 @@
nand0: nand@40000000 {
nand-bus-width = <8>;
- nand-ecc-mode = "soft";
+ nand-ecc-mode = "hw";
+ atmel,has-pmecc;
+ atmel,pmecc-cap = <2>;
+ atmel,pmecc-sector-size = <512>;
nand-on-flash-bbt;
status = "okay";
};
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index 8ecca6948d81..aa98e641931f 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -197,9 +197,9 @@
};
usart3 {
- pinctrl_uart3: usart3-0 {
+ pinctrl_usart3: usart3-0 {
atmel,pins =
- <2 23 0x2 0x1 /* PC22 periph B with pullup */
+ <2 22 0x2 0x1 /* PC22 periph B with pullup */
2 23 0x2 0x0>; /* PC23 periph B */
};
@@ -402,8 +402,6 @@
compatible = "atmel,at91sam9260-usart";
reg = <0xf801c000 0x200>;
interrupts = <5 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart0>;
status = "disabled";
@@ -413,8 +411,6 @@
compatible = "atmel,at91sam9260-usart";
reg = <0xf8020000 0x200>;
interrupts = <6 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart1>;
status = "disabled";
@@ -424,8 +420,6 @@
compatible = "atmel,at91sam9260-usart";
reg = <0xf8024000 0x200>;
interrupts = <7 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart2>;
status = "disabled";
@@ -518,7 +512,11 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0x40000000 0x10000000
+ 0xffffe000 0x600 /* PMECC Registers */
+ 0xffffe600 0x200 /* PMECC Error Location Registers */
+ 0x00108000 0x18000 /* PMECC looup table in ROM code */
>;
+ atmel,pmecc-lookup-table-offset = <0x0 0x8000>;
atmel,nand-addr-offset = <21>;
atmel,nand-cmd-offset = <22>;
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi
index 31e7be23703d..4027ac7e4502 100644
--- a/arch/arm/boot/dts/at91sam9x5cm.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi
@@ -26,7 +26,10 @@
ahb {
nand0: nand@40000000 {
nand-bus-width = <8>;
- nand-ecc-mode = "soft";
+ nand-ecc-mode = "hw";
+ atmel,has-pmecc; /* Enable PMECC */
+ atmel,pmecc-cap = <2>;
+ atmel,pmecc-sector-size = <512>;
nand-on-flash-bbt;
status = "okay";
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
index 9b72054a0bc0..aafda174a605 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -1,5 +1,4 @@
/dts-v1/;
-/memreserve/ 0x0c000000 0x04000000;
/include/ "bcm2835.dtsi"
/ {
@@ -25,3 +24,18 @@
brcm,function = <7>; /* alt3 */
};
};
+
+&i2c0 {
+ status = "okay";
+ clock-frequency = <100000>;
+};
+
+&i2c1 {
+ status = "okay";
+ clock-frequency = <100000>;
+};
+
+&sdhci {
+ status = "okay";
+ bus-width = <4>;
+};
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index 8917550fd1bb..4bf2a8774aa7 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -63,5 +63,49 @@
interrupt-controller;
#interrupt-cells = <2>;
};
+
+ i2c0: i2c@20205000 {
+ compatible = "brcm,bcm2835-i2c";
+ reg = <0x7e205000 0x1000>;
+ interrupts = <2 21>;
+ clocks = <&clk_i2c>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@20804000 {
+ compatible = "brcm,bcm2835-i2c";
+ reg = <0x7e804000 0x1000>;
+ interrupts = <2 21>;
+ clocks = <&clk_i2c>;
+ status = "disabled";
+ };
+
+ sdhci: sdhci {
+ compatible = "brcm,bcm2835-sdhci";
+ reg = <0x7e300000 0x100>;
+ interrupts = <2 30>;
+ clocks = <&clk_mmc>;
+ status = "disabled";
+ };
+ };
+
+ clocks {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ clk_mmc: mmc {
+ compatible = "fixed-clock";
+ reg = <0>;
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ };
+
+ clk_i2c: i2c {
+ compatible = "fixed-clock";
+ reg = <1>;
+ #clock-cells = <0>;
+ clock-frequency = <150000000>;
+ };
};
};
diff --git a/arch/arm/boot/dts/da850-evm.dts b/arch/arm/boot/dts/da850-evm.dts
index 37dc5a3243b8..f712fb607a42 100644
--- a/arch/arm/boot/dts/da850-evm.dts
+++ b/arch/arm/boot/dts/da850-evm.dts
@@ -15,6 +15,9 @@
model = "DA850/AM1808/OMAP-L138 EVM";
soc {
+ pmx_core: pinmux@1c14120 {
+ status = "okay";
+ };
serial0: serial@1c42000 {
status = "okay";
};
@@ -24,5 +27,22 @@
serial2: serial@1d0d000 {
status = "okay";
};
+ rtc0: rtc@1c23000 {
+ status = "okay";
+ };
+ i2c0: i2c@1c22000 {
+ status = "okay";
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ };
+ wdt: wdt@1c21000 {
+ status = "okay";
+ };
+ };
+ nand_cs3@62000000 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_cs3_pins>;
};
};
diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
index 640ab75c20db..3ec1bda64356 100644
--- a/arch/arm/boot/dts/da850.dtsi
+++ b/arch/arm/boot/dts/da850.dtsi
@@ -28,14 +28,47 @@
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x01c00000 0x400000>;
+ interrupt-parent = <&intc>;
+ pmx_core: pinmux@1c14120 {
+ compatible = "pinctrl-single";
+ reg = <0x14120 0x50>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-single,bit-per-mux;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <0xffffffff>;
+ status = "disabled";
+
+ nand_cs3_pins: pinmux_nand_pins {
+ pinctrl-single,bits = <
+ /* EMA_OE, EMA_WE */
+ 0x1c 0x00110000 0x00ff0000
+ /* EMA_CS[4],EMA_CS[3]*/
+ 0x1c 0x00000110 0x00000ff0
+ /*
+ * EMA_D[0], EMA_D[1], EMA_D[2],
+ * EMA_D[3], EMA_D[4], EMA_D[5],
+ * EMA_D[6], EMA_D[7]
+ */
+ 0x24 0x11111111 0xffffffff
+ /* EMA_A[1], EMA_A[2] */
+ 0x30 0x01100000 0x0ff00000
+ >;
+ };
+ i2c0_pins: pinmux_i2c0_pins {
+ pinctrl-single,bits = <
+ /* I2C0_SDA,I2C0_SCL */
+ 0x10 0x00002200 0x0000ff00
+ >;
+ };
+ };
serial0: serial@1c42000 {
compatible = "ns16550a";
reg = <0x42000 0x100>;
clock-frequency = <150000000>;
reg-shift = <2>;
interrupts = <25>;
- interrupt-parent = <&intc>;
status = "disabled";
};
serial1: serial@1d0c000 {
@@ -44,7 +77,6 @@
clock-frequency = <150000000>;
reg-shift = <2>;
interrupts = <53>;
- interrupt-parent = <&intc>;
status = "disabled";
};
serial2: serial@1d0d000 {
@@ -53,8 +85,40 @@
clock-frequency = <150000000>;
reg-shift = <2>;
interrupts = <61>;
- interrupt-parent = <&intc>;
status = "disabled";
};
+ rtc0: rtc@1c23000 {
+ compatible = "ti,da830-rtc";
+ reg = <0x23000 0x1000>;
+ interrupts = <19
+ 19>;
+ status = "disabled";
+ };
+ i2c0: i2c@1c22000 {
+ compatible = "ti,davinci-i2c";
+ reg = <0x22000 0x1000>;
+ interrupts = <15>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ wdt: wdt@1c21000 {
+ compatible = "ti,davinci-wdt";
+ reg = <0x21000 0x1000>;
+ status = "disabled";
+ };
+ };
+ nand_cs3@62000000 {
+ compatible = "ti,davinci-nand";
+ reg = <0x62000000 0x807ff
+ 0x68000000 0x8000>;
+ ti,davinci-chipselect = <1>;
+ ti,davinci-mask-ale = <0>;
+ ti,davinci-mask-cle = <0>;
+ ti,davinci-mask-chipsel = <0>;
+ ti,davinci-ecc-mode = "hw";
+ ti,davinci-ecc-bits = <4>;
+ ti,davinci-nand-use-bbt;
+ status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index 63f2fbcfe819..69140ba99f46 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -170,10 +170,9 @@
gpio-bank = <8>;
};
- pinctrl@80157000 {
- // This is actually the PRCMU base address
- reg = <0x80157000 0x2000>;
- compatible = "stericsson,nmk_pinctrl";
+ pinctrl {
+ compatible = "stericsson,nmk-pinctrl";
+ prcm = <&prcmu>;
};
usb@a03e0000 {
@@ -190,9 +189,10 @@
interrupts = <0 25 0x4>;
};
- prcmu@80157000 {
+ prcmu: prcmu@80157000 {
compatible = "stericsson,db8500-prcmu";
reg = <0x80157000 0x1000>;
+ reg-names = "prcmu";
interrupts = <0 47 0x4>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index 42eac1ff3cc8..740630f9cd65 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -93,6 +93,7 @@
reg = <0xd0400 0x20>;
ngpios = <32>;
interrupt-controller;
+ #interrupt-cells = <2>;
interrupts = <12>, <13>, <14>, <60>;
};
@@ -103,6 +104,7 @@
reg = <0xd0420 0x20>;
ngpios = <32>;
interrupt-controller;
+ #interrupt-cells = <2>;
interrupts = <61>;
};
diff --git a/arch/arm/boot/dts/emev2-kzm9d.dts b/arch/arm/boot/dts/emev2-kzm9d.dts
index 297e3baba71c..b9b3241f173b 100644
--- a/arch/arm/boot/dts/emev2-kzm9d.dts
+++ b/arch/arm/boot/dts/emev2-kzm9d.dts
@@ -21,6 +21,6 @@
};
chosen {
- bootargs = "console=ttyS1,115200n81";
+ bootargs = "console=tty0 console=ttyS1,115200n81 earlyprintk=serial8250-em.1,115200n81 mem=128M@0x40000000 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096";
};
};
diff --git a/arch/arm/boot/dts/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi
index eb504a6c0f4a..c8a8c08b48dd 100644
--- a/arch/arm/boot/dts/emev2.dtsi
+++ b/arch/arm/boot/dts/emev2.dtsi
@@ -15,11 +15,18 @@
interrupt-parent = <&gic>;
cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
cpu@0 {
+ device_type = "cpu";
compatible = "arm,cortex-a9";
+ reg = <0>;
};
cpu@1 {
+ device_type = "cpu";
compatible = "arm,cortex-a9";
+ reg = <1>;
};
};
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index e31bfc4a6f09..2feffc70814c 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -48,13 +48,13 @@
};
pinctrl_0: pinctrl@11400000 {
- compatible = "samsung,pinctrl-exynos4210";
+ compatible = "samsung,exynos4210-pinctrl";
reg = <0x11400000 0x1000>;
interrupts = <0 47 0>;
};
pinctrl_1: pinctrl@11000000 {
- compatible = "samsung,pinctrl-exynos4210";
+ compatible = "samsung,exynos4210-pinctrl";
reg = <0x11000000 0x1000>;
interrupts = <0 46 0>;
@@ -66,7 +66,7 @@
};
pinctrl_2: pinctrl@03860000 {
- compatible = "samsung,pinctrl-exynos4210";
+ compatible = "samsung,exynos4210-pinctrl";
reg = <0x03860000 0x1000>;
};
diff --git a/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi b/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
index 8e6115adcd97..099cec79e2ae 100644
--- a/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
@@ -661,7 +661,7 @@
sd4_bus8: sd4-bus-width8 {
samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6";
- samsung,pin-function = <3>;
+ samsung,pin-function = <4>;
samsung,pin-pud = <4>;
samsung,pin-drv = <3>;
};
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index 179a62e46c9d..9a8780694909 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -37,13 +37,13 @@
};
pinctrl_0: pinctrl@11400000 {
- compatible = "samsung,pinctrl-exynos4x12";
+ compatible = "samsung,exynos4x12-pinctrl";
reg = <0x11400000 0x1000>;
interrupts = <0 47 0>;
};
pinctrl_1: pinctrl@11000000 {
- compatible = "samsung,pinctrl-exynos4x12";
+ compatible = "samsung,exynos4x12-pinctrl";
reg = <0x11000000 0x1000>;
interrupts = <0 46 0>;
@@ -55,14 +55,14 @@
};
pinctrl_2: pinctrl@03860000 {
- compatible = "samsung,pinctrl-exynos4x12";
+ compatible = "samsung,exynos4x12-pinctrl";
reg = <0x03860000 0x1000>;
interrupt-parent = <&combiner>;
interrupts = <10 0>;
};
pinctrl_3: pinctrl@106E0000 {
- compatible = "samsung,pinctrl-exynos4x12";
+ compatible = "samsung,exynos4x12-pinctrl";
reg = <0x106E0000 0x1000>;
interrupts = <0 72 0>;
};
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index e05b18f3c33d..4db9db0a8443 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -49,6 +49,11 @@
compatible = "samsung,s524ad0xd1";
reg = <0x51>;
};
+
+ wm8994: wm8994@1a {
+ compatible = "wlf,wm8994";
+ reg = <0x1a>;
+ };
};
i2c@121D0000 {
@@ -204,4 +209,25 @@
samsung,mfc-r = <0x43000000 0x800000>;
samsung,mfc-l = <0x51000000 0x800000>;
};
+
+ i2s0: i2s@03830000 {
+ gpios = <&gpz 0 2 0 0>, <&gpz 1 2 0 0>, <&gpz 2 2 0 0>,
+ <&gpz 3 2 0 0>, <&gpz 4 2 0 0>, <&gpz 5 2 0 0>,
+ <&gpz 6 2 0 0>;
+ };
+
+ i2s1: i2s@12D60000 {
+ status = "disabled";
+ };
+
+ i2s2: i2s@12D70000 {
+ status = "disabled";
+ };
+
+ sound {
+ compatible = "samsung,smdk-wm8994";
+
+ samsung,i2s-controller = <&i2s0>;
+ samsung,audio-codec = <&wm8994>;
+ };
};
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 3acf594ea60b..f50b4e854355 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -211,8 +211,9 @@
compatible = "samsung,exynos4210-spi";
reg = <0x12d20000 0x100>;
interrupts = <0 66 0>;
- tx-dma-channel = <&pdma0 5>; /* preliminary */
- rx-dma-channel = <&pdma0 4>; /* preliminary */
+ dmas = <&pdma0 5
+ &pdma0 4>;
+ dma-names = "tx", "rx";
#address-cells = <1>;
#size-cells = <0>;
};
@@ -221,8 +222,9 @@
compatible = "samsung,exynos4210-spi";
reg = <0x12d30000 0x100>;
interrupts = <0 67 0>;
- tx-dma-channel = <&pdma1 5>; /* preliminary */
- rx-dma-channel = <&pdma1 4>; /* preliminary */
+ dmas = <&pdma1 5
+ &pdma1 4>;
+ dma-names = "tx", "rx";
#address-cells = <1>;
#size-cells = <0>;
};
@@ -231,8 +233,9 @@
compatible = "samsung,exynos4210-spi";
reg = <0x12d40000 0x100>;
interrupts = <0 68 0>;
- tx-dma-channel = <&pdma0 7>; /* preliminary */
- rx-dma-channel = <&pdma0 6>; /* preliminary */
+ dmas = <&pdma0 7
+ &pdma0 6>;
+ dma-names = "tx", "rx";
#address-cells = <1>;
#size-cells = <0>;
};
@@ -269,6 +272,35 @@
#size-cells = <0>;
};
+ i2s0: i2s@03830000 {
+ compatible = "samsung,i2s-v5";
+ reg = <0x03830000 0x100>;
+ dmas = <&pdma0 10
+ &pdma0 9
+ &pdma0 8>;
+ dma-names = "tx", "rx", "tx-sec";
+ samsung,supports-6ch;
+ samsung,supports-rstclr;
+ samsung,supports-secdai;
+ samsung,idma-addr = <0x03000000>;
+ };
+
+ i2s1: i2s@12D60000 {
+ compatible = "samsung,i2s-v5";
+ reg = <0x12D60000 0x100>;
+ dmas = <&pdma1 12
+ &pdma1 11>;
+ dma-names = "tx", "rx";
+ };
+
+ i2s2: i2s@12D70000 {
+ compatible = "samsung,i2s-v5";
+ reg = <0x12D70000 0x100>;
+ dmas = <&pdma0 12
+ &pdma0 11>;
+ dma-names = "tx", "rx";
+ };
+
amba {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi
index 024269de8ee5..5f3562ad6746 100644
--- a/arch/arm/boot/dts/exynos5440.dtsi
+++ b/arch/arm/boot/dts/exynos5440.dtsi
@@ -86,7 +86,7 @@
};
pinctrl {
- compatible = "samsung,pinctrl-exynos5440";
+ compatible = "samsung,exynos5440-pinctrl";
reg = <0xE0000 0x1000>;
interrupt-controller;
#interrupt-cells = <2>;
@@ -154,6 +154,6 @@
rtc {
compatible = "samsung,s3c6410-rtc";
reg = <0x130000 0x1000>;
- interrupts = <0 16 0>, <0 17 0>;
+ interrupts = <0 17 0>, <0 16 0>;
};
};
diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 5927a8df5625..6aad34ad9517 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -37,6 +37,16 @@
next-level-cache = <&L2>;
clocks = <&a9pll>;
clock-names = "cpu";
+ operating-points = <
+ /* kHz ignored */
+ 1300000 1000000
+ 1200000 1000000
+ 1100000 1000000
+ 800000 1000000
+ 400000 1000000
+ 200000 1000000
+ >;
+ clock-latency = <100000>;
};
cpu@901 {
diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi
index 65415c598a5e..56afcf41aae0 100644
--- a/arch/arm/boot/dts/imx23.dtsi
+++ b/arch/arm/boot/dts/imx23.dtsi
@@ -391,7 +391,9 @@
};
lradc@80050000 {
+ compatible = "fsl,imx23-lradc";
reg = <0x80050000 0x2000>;
+ interrupts = <36 37 38 39 40 41 42 43 44>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/imx28-cfa10037.dts b/arch/arm/boot/dts/imx28-cfa10037.dts
new file mode 100644
index 000000000000..c2ef3a3d655e
--- /dev/null
+++ b/arch/arm/boot/dts/imx28-cfa10037.dts
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2012 Free Electrons
+ *
+ * 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
+ */
+
+/*
+ * The CFA-10049 is an expansion board for the CFA-10036 module, thus we
+ * need to include the CFA-10036 DTS.
+ */
+/include/ "imx28-cfa10036.dts"
+
+/ {
+ model = "Crystalfontz CFA-10037 Board";
+ compatible = "crystalfontz,cfa10037", "crystalfontz,cfa10036", "fsl,imx28";
+
+ apb@80000000 {
+ apbh@80000000 {
+ pinctrl@80018000 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&hog_pins_cfa10037>;
+
+ hog_pins_cfa10037: hog-10037@0 {
+ reg = <0>;
+ fsl,pinmux-ids = <
+ 0x0073 /* MX28_PAD_GPMI_D7__GPIO_0_7 */
+ 0x2153 /* MX28_PAD_SSP2_D5__GPIO_2_21 */
+ >;
+ fsl,drive-strength = <0>;
+ fsl,voltage = <1>;
+ fsl,pull-up = <0>;
+ };
+ };
+ };
+
+ apbx@80040000 {
+ usbphy1: usbphy@8007e000 {
+ status = "okay";
+ };
+ };
+ };
+
+ ahb@80080000 {
+ usb1: usb@80090000 {
+ vbus-supply = <&reg_usb1_vbus>;
+ pinctrl-0 = <&usbphy1_pins_a>;
+ pinctrl-names = "default";
+ status = "okay";
+ };
+
+ mac0: ethernet@800f0000 {
+ phy-mode = "rmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mac0_pins_a>;
+ phy-reset-gpios = <&gpio2 21 0>;
+ phy-reset-duration = <100>;
+ status = "okay";
+ };
+ };
+
+ regulators {
+ compatible = "simple-bus";
+
+ reg_usb1_vbus: usb1_vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio0 7 1>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/imx28-cfa10049.dts b/arch/arm/boot/dts/imx28-cfa10049.dts
index bdc80a4453dd..a0d3e9f1738e 100644
--- a/arch/arm/boot/dts/imx28-cfa10049.dts
+++ b/arch/arm/boot/dts/imx28-cfa10049.dts
@@ -23,69 +23,120 @@
apbh@80000000 {
pinctrl@80018000 {
pinctrl-names = "default", "default";
- pinctrl-1 = <&hog_pins_cfa10049>;
+ pinctrl-1 = <&hog_pins_cfa10049
+ &hog_pins_cfa10049_pullup>;
hog_pins_cfa10049: hog-10049@0 {
reg = <0>;
fsl,pinmux-ids = <
0x0073 /* MX28_PAD_GPMI_D7__GPIO_0_7 */
+ 0x1153 /* MX28_PAD_LCD_D22__GPIO_1_21 */
0x1163 /* MX28_PAD_LCD_D22__GPIO_1_22 */
0x1173 /* MX28_PAD_LCD_D22__GPIO_1_23 */
0x2153 /* MX28_PAD_SSP2_D5__GPIO_2_21 */
+ 0x3173 /* MX28_PAD_LCD_RESET__GPIO_3_23 */
>;
fsl,drive-strength = <0>;
fsl,voltage = <1>;
fsl,pull-up = <0>;
};
- spi3_pins_cfa10049: spi3-cfa10049@0 {
+ hog_pins_cfa10049_pullup: hog-10049-pullup@0 {
reg = <0>;
fsl,pinmux-ids = <
- 0x0181 /* MX28_PAD_GPMI_RDN__SSP3_SCK */
- 0x01c1 /* MX28_PAD_GPMI_RESETN__SSP3_CMD */
- 0x0111 /* MX28_PAD_GPMI_CE1N__SSP3_D3 */
- 0x01a2 /* MX28_PAD_GPMI_ALE__SSP3_D4 */
- 0x01b2 /* MX28_PAD_GPMI_CLE__SSP3_D5 */
+ 0x2133 /* MX28_PAD_SSP2_D3__GPIO_2_19 */
+ 0x3183 /* MX28_PAD_I2C0_SCL__GPIO_3_24 */
+ 0x3193 /* MX28_PAD_I2C0_SDA__GPIO_3_25 */
+ 0x31a3 /* MX28_PAD_SAIF_SDATA0__GPIO_3_26 */
+ 0x31e3 /* MX28_PAD_LCD_RESET__GPIO_3_30 */
>;
- fsl,drive-strength = <1>;
+ fsl,drive-strength = <0>;
fsl,voltage = <1>;
fsl,pull-up = <1>;
};
- };
- ssp3: ssp@80016000 {
- compatible = "fsl,imx28-spi";
- pinctrl-names = "default";
- pinctrl-0 = <&spi3_pins_cfa10049>;
- status = "okay";
+ spi2_pins_cfa10049: spi2-cfa10049@0 {
+ reg = <0>;
+ fsl,pinmux-ids = <
+ 0x2103 /* MX28_PAD_SSP2_SCK__GPIO_2_16 */
+ 0x2113 /* MX28_PAD_SSP2_CMD__GPIO_2_17 */
+ 0x2123 /* MX28_PAD_SSP2_D0__GPIO_2_18 */
+ >;
+ fsl,drive-strength = <1>;
+ fsl,voltage = <1>;
+ fsl,pull-up = <1>;
+ };
- gpio5: gpio5@0 {
- compatible = "fairchild,74hc595";
- gpio-controller;
- #gpio-cells = <2>;
+ spi3_pins_cfa10049: spi3-cfa10049@0 {
reg = <0>;
- registers-number = <2>;
- spi-max-frequency = <100000>;
+ fsl,pinmux-ids = <
+ 0x0183 /* MX28_PAD_GPMI_RDN__GPIO_0_24 */
+ 0x01c3 /* MX28_PAD_GPMI_RESETN__GPIO_0_28 */
+ 0x0113 /* MX28_PAD_GPMI_CE1N__GPIO_0_17 */
+ 0x01a3 /* MX28_PAD_GPMI_ALE__GPIO_0_26 */
+ 0x01b3 /* MX28_PAD_GPMI_CLE__GPIO_0_27 */
+ >;
+ fsl,drive-strength = <1>;
+ fsl,voltage = <1>;
+ fsl,pull-up = <1>;
};
- gpio6: gpio6@1 {
- compatible = "fairchild,74hc595";
- gpio-controller;
- #gpio-cells = <2>;
- reg = <1>;
- registers-number = <4>;
- spi-max-frequency = <100000>;
+ lcdif_18bit_pins_cfa10049: lcdif-18bit@0 {
+ reg = <0>;
+ fsl,pinmux-ids = <
+ 0x1000 /* MX28_PAD_LCD_D00__LCD_D0 */
+ 0x1010 /* MX28_PAD_LCD_D01__LCD_D1 */
+ 0x1020 /* MX28_PAD_LCD_D02__LCD_D2 */
+ 0x1030 /* MX28_PAD_LCD_D03__LCD_D3 */
+ 0x1040 /* MX28_PAD_LCD_D04__LCD_D4 */
+ 0x1050 /* MX28_PAD_LCD_D05__LCD_D5 */
+ 0x1060 /* MX28_PAD_LCD_D06__LCD_D6 */
+ 0x1070 /* MX28_PAD_LCD_D07__LCD_D7 */
+ 0x1080 /* MX28_PAD_LCD_D08__LCD_D8 */
+ 0x1090 /* MX28_PAD_LCD_D09__LCD_D9 */
+ 0x10a0 /* MX28_PAD_LCD_D10__LCD_D10 */
+ 0x10b0 /* MX28_PAD_LCD_D11__LCD_D11 */
+ 0x10c0 /* MX28_PAD_LCD_D12__LCD_D12 */
+ 0x10d0 /* MX28_PAD_LCD_D13__LCD_D13 */
+ 0x10e0 /* MX28_PAD_LCD_D14__LCD_D14 */
+ 0x10f0 /* MX28_PAD_LCD_D15__LCD_D15 */
+ 0x1100 /* MX28_PAD_LCD_D16__LCD_D16 */
+ 0x1110 /* MX28_PAD_LCD_D17__LCD_D17 */
+ >;
+ fsl,drive-strength = <0>;
+ fsl,voltage = <1>;
+ fsl,pull-up = <0>;
};
- dac0: dh2228@2 {
- compatible = "rohm,dh2228fv";
- reg = <2>;
- spi-max-frequency = <100000>;
+ lcdif_pins_cfa10049: lcdif-evk@0 {
+ reg = <0>;
+ fsl,pinmux-ids = <
+ 0x1181 /* MX28_PAD_LCD_RD_E__LCD_VSYNC */
+ 0x1191 /* MX28_PAD_LCD_WR_RWN__LCD_HSYNC */
+ 0x11a1 /* MX28_PAD_LCD_RS__LCD_DOTCLK */
+ 0x11b1 /* MX28_PAD_LCD_CS__LCD_ENABLE */
+ >;
+ fsl,drive-strength = <0>;
+ fsl,voltage = <1>;
+ fsl,pull-up = <0>;
};
};
+
+ lcdif@80030000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcdif_18bit_pins_cfa10049
+ &lcdif_pins_cfa10049>;
+ status = "okay";
+ };
};
apbx@80040000 {
+ pwm: pwm@80064000 {
+ pinctrl-names = "default", "default";
+ pinctrl-1 = <&pwm3_pins_b>;
+ status = "okay";
+ };
+
i2c1: i2c@8005a000 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins_a>;
@@ -113,6 +164,19 @@
i2c@3 {
reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pca9555: pca9555@20 {
+ compatible = "nxp,pca9555";
+ interrupt-parent = <&gpio2>;
+ interrupts = <19 0x2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x20>;
+ };
};
};
@@ -153,4 +217,92 @@
status = "okay";
};
};
+
+ spi2 {
+ compatible = "spi-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi2_pins_cfa10049>;
+ status = "okay";
+ gpio-sck = <&gpio2 16 0>;
+ gpio-mosi = <&gpio2 17 0>;
+ gpio-miso = <&gpio2 18 0>;
+ cs-gpios = <&gpio3 23 0>;
+ num-chipselects = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hx8357: hx8357@0 {
+ compatible = "himax,hx8357b", "himax,hx8357";
+ reg = <0>;
+ spi-max-frequency = <100000>;
+ spi-cpol;
+ spi-cpha;
+ gpios-reset = <&gpio3 30 0>;
+ im-gpios = <&gpio5 4 0 &gpio5 5 0 &gpio5 6 0>;
+ };
+ };
+
+ spi3 {
+ compatible = "spi-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi3_pins_cfa10049>;
+ status = "okay";
+ gpio-sck = <&gpio0 24 0>;
+ gpio-mosi = <&gpio0 28 0>;
+ cs-gpios = <&gpio0 17 0 &gpio0 26 0 &gpio0 27 0>;
+ num-chipselects = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio5: gpio5@0 {
+ compatible = "fairchild,74hc595";
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0>;
+ registers-number = <2>;
+ spi-max-frequency = <100000>;
+ };
+
+ gpio6: gpio6@1 {
+ compatible = "fairchild,74hc595";
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <1>;
+ registers-number = <4>;
+ spi-max-frequency = <100000>;
+ };
+
+ dac0: dh2228@2 {
+ compatible = "rohm,dh2228fv";
+ reg = <2>;
+ spi-max-frequency = <100000>;
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rotary_button {
+ label = "rotary_button";
+ gpios = <&gpio3 26 1>;
+ debounce-interval = <10>;
+ linux,code = <28>;
+ };
+ };
+
+ rotary {
+ compatible = "rotary-encoder";
+ gpios = <&gpio3 24 1>, <&gpio3 25 1>;
+ linux,axis = <1>; /* REL_Y */
+ rotary-encoder,relative-axis;
+ };
+
+ backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm 3 5000000>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <6>;
+ };
};
diff --git a/arch/arm/boot/dts/imx28-m28evk.dts b/arch/arm/boot/dts/imx28-m28evk.dts
index 3bab6b00c52d..6ce3d17c3a29 100644
--- a/arch/arm/boot/dts/imx28-m28evk.dts
+++ b/arch/arm/boot/dts/imx28-m28evk.dts
@@ -177,6 +177,7 @@
lradc@80050000 {
status = "okay";
+ fsl,lradc-touchscreen-wires = <4>;
};
duart: serial@80074000 {
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index 13b7053d799e..7ba49662b9bc 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -502,6 +502,16 @@
fsl,pull-up = <0>;
};
+ pwm3_pins_b: pwm3@1 {
+ reg = <1>;
+ fsl,pinmux-ids = <
+ 0x3141 /* MX28_PAD_SAIF0_MCLK__PWM3 */
+ >;
+ fsl,drive-strength = <0>;
+ fsl,voltage = <1>;
+ fsl,pull-up = <0>;
+ };
+
pwm4_pins_a: pwm4@0 {
reg = <0>;
fsl,pinmux-ids = <
diff --git a/arch/arm/boot/dts/imx31.dtsi b/arch/arm/boot/dts/imx31.dtsi
index eef7099f3e3c..454c2d175402 100644
--- a/arch/arm/boot/dts/imx31.dtsi
+++ b/arch/arm/boot/dts/imx31.dtsi
@@ -45,6 +45,8 @@
compatible = "fsl,imx31-uart", "fsl,imx21-uart";
reg = <0x43f90000 0x4000>;
interrupts = <45>;
+ clocks = <&clks 10>, <&clks 30>;
+ clock-names = "ipg", "per";
status = "disabled";
};
@@ -52,12 +54,16 @@
compatible = "fsl,imx31-uart", "fsl,imx21-uart";
reg = <0x43f94000 0x4000>;
interrupts = <32>;
+ clocks = <&clks 10>, <&clks 31>;
+ clock-names = "ipg", "per";
status = "disabled";
};
uart4: serial@43fb0000 {
compatible = "fsl,imx31-uart", "fsl,imx21-uart";
reg = <0x43fb0000 0x4000>;
+ clocks = <&clks 10>, <&clks 49>;
+ clock-names = "ipg", "per";
interrupts = <46>;
status = "disabled";
};
@@ -66,6 +72,8 @@
compatible = "fsl,imx31-uart", "fsl,imx21-uart";
reg = <0x43fb4000 0x4000>;
interrupts = <47>;
+ clocks = <&clks 10>, <&clks 50>;
+ clock-names = "ipg", "per";
status = "disabled";
};
};
@@ -81,8 +89,17 @@
compatible = "fsl,imx31-uart", "fsl,imx21-uart";
reg = <0x5000c000 0x4000>;
interrupts = <18>;
+ clocks = <&clks 10>, <&clks 48>;
+ clock-names = "ipg", "per";
status = "disabled";
};
+
+ clks: ccm@53f80000{
+ compatible = "fsl,imx31-ccm";
+ reg = <0x53f80000 0x4000>;
+ interrupts = <0 31 0x04 0 53 0x04>;
+ #clock-cells = <1>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index d6265ca97119..ff1205ea5719 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -866,7 +866,7 @@
compatible = "fsl,imx6q-fec";
reg = <0x02188000 0x4000>;
interrupts = <0 118 0x04 0 119 0x04>;
- clocks = <&clks 117>, <&clks 117>, <&clks 177>;
+ clocks = <&clks 117>, <&clks 117>, <&clks 190>;
clock-names = "ipg", "ahb", "ptp";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/marco-evb.dts b/arch/arm/boot/dts/marco-evb.dts
new file mode 100644
index 000000000000..5130aeacfca5
--- /dev/null
+++ b/arch/arm/boot/dts/marco-evb.dts
@@ -0,0 +1,54 @@
+/*
+ * DTS file for CSR SiRFmarco Evaluation Board
+ *
+ * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/dts-v1/;
+
+/include/ "marco.dtsi"
+
+/ {
+ model = "CSR SiRFmarco Evaluation Board";
+ compatible = "sirf,marco-cb", "sirf,marco";
+
+ memory {
+ reg = <0x40000000 0x60000000>;
+ };
+
+ axi {
+ peri-iobg {
+ uart1: uart@cc060000 {
+ status = "okay";
+ };
+ uart2: uart@cc070000 {
+ status = "okay";
+ };
+ i2c0: i2c@cc0e0000 {
+ status = "okay";
+ fpga-cpld@4d {
+ compatible = "sirf,fpga-cpld";
+ reg = <0x4d>;
+ };
+ };
+ spi1: spi@cc170000 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_pins_a>;
+ spi@0 {
+ compatible = "spidev";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+ };
+ pci-iobg {
+ sd0: sdhci@cd000000 {
+ bus-width = <8>;
+ status = "okay";
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/marco.dtsi b/arch/arm/boot/dts/marco.dtsi
new file mode 100644
index 000000000000..1579c3491ccd
--- /dev/null
+++ b/arch/arm/boot/dts/marco.dtsi
@@ -0,0 +1,756 @@
+/*
+ * DTS file for CSR SiRFmarco SoC
+ *
+ * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+/ {
+ compatible = "sirf,marco";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ };
+ };
+
+ axi {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x40000000 0x40000000 0xa0000000>;
+
+ l2-cache-controller@c0030000 {
+ compatible = "sirf,marco-pl310-cache", "arm,pl310-cache";
+ reg = <0xc0030000 0x1000>;
+ interrupts = <0 59 0>;
+ arm,tag-latency = <1 1 1>;
+ arm,data-latency = <1 1 1>;
+ arm,filter-ranges = <0x40000000 0x80000000>;
+ };
+
+ gic: interrupt-controller@c0011000 {
+ compatible = "arm,cortex-a9-gic";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0xc0011000 0x1000>,
+ <0xc0010100 0x0100>;
+ };
+
+ rstc-iobg {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xc2000000 0xc2000000 0x1000000>;
+
+ reset-controller@c2000000 {
+ compatible = "sirf,marco-rstc";
+ reg = <0xc2000000 0x10000>;
+ };
+ };
+
+ sys-iobg {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xc3000000 0xc3000000 0x1000000>;
+
+ clock-controller@c3000000 {
+ compatible = "sirf,marco-clkc";
+ reg = <0xc3000000 0x1000>;
+ interrupts = <0 3 0>;
+ };
+
+ rsc-controller@c3010000 {
+ compatible = "sirf,marco-rsc";
+ reg = <0xc3010000 0x1000>;
+ };
+ };
+
+ mem-iobg {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xc4000000 0xc4000000 0x1000000>;
+
+ memory-controller@c4000000 {
+ compatible = "sirf,marco-memc";
+ reg = <0xc4000000 0x10000>;
+ interrupts = <0 27 0>;
+ };
+ };
+
+ disp-iobg0 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xc5000000 0xc5000000 0x1000000>;
+
+ display0@c5000000 {
+ compatible = "sirf,marco-lcd";
+ reg = <0xc5000000 0x10000>;
+ interrupts = <0 30 0>;
+ };
+
+ vpp0@c5010000 {
+ compatible = "sirf,marco-vpp";
+ reg = <0xc5010000 0x10000>;
+ interrupts = <0 31 0>;
+ };
+ };
+
+ disp-iobg1 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xc6000000 0xc6000000 0x1000000>;
+
+ display1@c6000000 {
+ compatible = "sirf,marco-lcd";
+ reg = <0xc6000000 0x10000>;
+ interrupts = <0 62 0>;
+ };
+
+ vpp1@c6010000 {
+ compatible = "sirf,marco-vpp";
+ reg = <0xc6010000 0x10000>;
+ interrupts = <0 63 0>;
+ };
+ };
+
+ graphics-iobg {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xc8000000 0xc8000000 0x1000000>;
+
+ graphics@c8000000 {
+ compatible = "powervr,sgx540";
+ reg = <0xc8000000 0x1000000>;
+ interrupts = <0 6 0>;
+ };
+ };
+
+ multimedia-iobg {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xc9000000 0xc9000000 0x1000000>;
+
+ multimedia@a0000000 {
+ compatible = "sirf,marco-video-codec";
+ reg = <0xc9000000 0x1000000>;
+ interrupts = <0 5 0>;
+ };
+ };
+
+ dsp-iobg {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xca000000 0xca000000 0x2000000>;
+
+ dspif@ca000000 {
+ compatible = "sirf,marco-dspif";
+ reg = <0xca000000 0x10000>;
+ interrupts = <0 9 0>;
+ };
+
+ gps@ca010000 {
+ compatible = "sirf,marco-gps";
+ reg = <0xca010000 0x10000>;
+ interrupts = <0 7 0>;
+ };
+
+ dsp@cb000000 {
+ compatible = "sirf,marco-dsp";
+ reg = <0xcb000000 0x1000000>;
+ interrupts = <0 8 0>;
+ };
+ };
+
+ peri-iobg {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xcc000000 0xcc000000 0x2000000>;
+
+ timer@cc020000 {
+ compatible = "sirf,marco-tick";
+ reg = <0xcc020000 0x1000>;
+ interrupts = <0 0 0>,
+ <0 1 0>,
+ <0 2 0>,
+ <0 49 0>,
+ <0 50 0>,
+ <0 51 0>;
+ };
+
+ nand@cc030000 {
+ compatible = "sirf,marco-nand";
+ reg = <0xcc030000 0x10000>;
+ interrupts = <0 41 0>;
+ };
+
+ audio@cc040000 {
+ compatible = "sirf,marco-audio";
+ reg = <0xcc040000 0x10000>;
+ interrupts = <0 35 0>;
+ };
+
+ uart0: uart@cc050000 {
+ cell-index = <0>;
+ compatible = "sirf,marco-uart";
+ reg = <0xcc050000 0x1000>;
+ interrupts = <0 17 0>;
+ fifosize = <128>;
+ status = "disabled";
+ };
+
+ uart1: uart@cc060000 {
+ cell-index = <1>;
+ compatible = "sirf,marco-uart";
+ reg = <0xcc060000 0x1000>;
+ interrupts = <0 18 0>;
+ fifosize = <32>;
+ status = "disabled";
+ };
+
+ uart2: uart@cc070000 {
+ cell-index = <2>;
+ compatible = "sirf,marco-uart";
+ reg = <0xcc070000 0x1000>;
+ interrupts = <0 19 0>;
+ fifosize = <128>;
+ status = "disabled";
+ };
+
+ uart3: uart@cc190000 {
+ cell-index = <3>;
+ compatible = "sirf,marco-uart";
+ reg = <0xcc190000 0x1000>;
+ interrupts = <0 66 0>;
+ fifosize = <128>;
+ status = "disabled";
+ };
+
+ uart4: uart@cc1a0000 {
+ cell-index = <4>;
+ compatible = "sirf,marco-uart";
+ reg = <0xcc1a0000 0x1000>;
+ interrupts = <0 69 0>;
+ fifosize = <128>;
+ status = "disabled";
+ };
+
+ usp0: usp@cc080000 {
+ cell-index = <0>;
+ compatible = "sirf,marco-usp";
+ reg = <0xcc080000 0x10000>;
+ interrupts = <0 20 0>;
+ status = "disabled";
+ };
+
+ usp1: usp@cc090000 {
+ cell-index = <1>;
+ compatible = "sirf,marco-usp";
+ reg = <0xcc090000 0x10000>;
+ interrupts = <0 21 0>;
+ status = "disabled";
+ };
+
+ usp2: usp@cc0a0000 {
+ cell-index = <2>;
+ compatible = "sirf,marco-usp";
+ reg = <0xcc0a0000 0x10000>;
+ interrupts = <0 22 0>;
+ status = "disabled";
+ };
+
+ dmac0: dma-controller@cc0b0000 {
+ cell-index = <0>;
+ compatible = "sirf,marco-dmac";
+ reg = <0xcc0b0000 0x10000>;
+ interrupts = <0 12 0>;
+ };
+
+ dmac1: dma-controller@cc160000 {
+ cell-index = <1>;
+ compatible = "sirf,marco-dmac";
+ reg = <0xcc160000 0x10000>;
+ interrupts = <0 13 0>;
+ };
+
+ vip@cc0c0000 {
+ compatible = "sirf,marco-vip";
+ reg = <0xcc0c0000 0x10000>;
+ };
+
+ spi0: spi@cc0d0000 {
+ cell-index = <0>;
+ compatible = "sirf,marco-spi";
+ reg = <0xcc0d0000 0x10000>;
+ interrupts = <0 15 0>;
+ sirf,spi-num-chipselects = <1>;
+ cs-gpios = <&gpio 0 0>;
+ sirf,spi-dma-rx-channel = <25>;
+ sirf,spi-dma-tx-channel = <20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi1: spi@cc170000 {
+ cell-index = <1>;
+ compatible = "sirf,marco-spi";
+ reg = <0xcc170000 0x10000>;
+ interrupts = <0 16 0>;
+ sirf,spi-num-chipselects = <1>;
+ cs-gpios = <&gpio 0 0>;
+ sirf,spi-dma-rx-channel = <12>;
+ sirf,spi-dma-tx-channel = <13>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@cc0e0000 {
+ cell-index = <0>;
+ compatible = "sirf,marco-i2c";
+ reg = <0xcc0e0000 0x10000>;
+ interrupts = <0 24 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@cc0f0000 {
+ cell-index = <1>;
+ compatible = "sirf,marco-i2c";
+ reg = <0xcc0f0000 0x10000>;
+ interrupts = <0 25 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ tsc@cc110000 {
+ compatible = "sirf,marco-tsc";
+ reg = <0xcc110000 0x10000>;
+ interrupts = <0 33 0>;
+ };
+
+ gpio: pinctrl@cc120000 {
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ compatible = "sirf,marco-pinctrl";
+ reg = <0xcc120000 0x10000>;
+ interrupts = <0 43 0>,
+ <0 44 0>,
+ <0 45 0>,
+ <0 46 0>,
+ <0 47 0>;
+ gpio-controller;
+ interrupt-controller;
+
+ lcd_16pins_a: lcd0_0 {
+ lcd {
+ sirf,pins = "lcd_16bitsgrp";
+ sirf,function = "lcd_16bits";
+ };
+ };
+ lcd_18pins_a: lcd0_1 {
+ lcd {
+ sirf,pins = "lcd_18bitsgrp";
+ sirf,function = "lcd_18bits";
+ };
+ };
+ lcd_24pins_a: lcd0_2 {
+ lcd {
+ sirf,pins = "lcd_24bitsgrp";
+ sirf,function = "lcd_24bits";
+ };
+ };
+ lcdrom_pins_a: lcdrom0_0 {
+ lcd {
+ sirf,pins = "lcdromgrp";
+ sirf,function = "lcdrom";
+ };
+ };
+ uart0_pins_a: uart0_0 {
+ uart {
+ sirf,pins = "uart0grp";
+ sirf,function = "uart0";
+ };
+ };
+ uart1_pins_a: uart1_0 {
+ uart {
+ sirf,pins = "uart1grp";
+ sirf,function = "uart1";
+ };
+ };
+ uart2_pins_a: uart2_0 {
+ uart {
+ sirf,pins = "uart2grp";
+ sirf,function = "uart2";
+ };
+ };
+ uart2_noflow_pins_a: uart2_1 {
+ uart {
+ sirf,pins = "uart2_nostreamctrlgrp";
+ sirf,function = "uart2_nostreamctrl";
+ };
+ };
+ spi0_pins_a: spi0_0 {
+ spi {
+ sirf,pins = "spi0grp";
+ sirf,function = "spi0";
+ };
+ };
+ spi1_pins_a: spi1_0 {
+ spi {
+ sirf,pins = "spi1grp";
+ sirf,function = "spi1";
+ };
+ };
+ i2c0_pins_a: i2c0_0 {
+ i2c {
+ sirf,pins = "i2c0grp";
+ sirf,function = "i2c0";
+ };
+ };
+ i2c1_pins_a: i2c1_0 {
+ i2c {
+ sirf,pins = "i2c1grp";
+ sirf,function = "i2c1";
+ };
+ };
+ pwm0_pins_a: pwm0_0 {
+ pwm {
+ sirf,pins = "pwm0grp";
+ sirf,function = "pwm0";
+ };
+ };
+ pwm1_pins_a: pwm1_0 {
+ pwm {
+ sirf,pins = "pwm1grp";
+ sirf,function = "pwm1";
+ };
+ };
+ pwm2_pins_a: pwm2_0 {
+ pwm {
+ sirf,pins = "pwm2grp";
+ sirf,function = "pwm2";
+ };
+ };
+ pwm3_pins_a: pwm3_0 {
+ pwm {
+ sirf,pins = "pwm3grp";
+ sirf,function = "pwm3";
+ };
+ };
+ gps_pins_a: gps_0 {
+ gps {
+ sirf,pins = "gpsgrp";
+ sirf,function = "gps";
+ };
+ };
+ vip_pins_a: vip_0 {
+ vip {
+ sirf,pins = "vipgrp";
+ sirf,function = "vip";
+ };
+ };
+ sdmmc0_pins_a: sdmmc0_0 {
+ sdmmc0 {
+ sirf,pins = "sdmmc0grp";
+ sirf,function = "sdmmc0";
+ };
+ };
+ sdmmc1_pins_a: sdmmc1_0 {
+ sdmmc1 {
+ sirf,pins = "sdmmc1grp";
+ sirf,function = "sdmmc1";
+ };
+ };
+ sdmmc2_pins_a: sdmmc2_0 {
+ sdmmc2 {
+ sirf,pins = "sdmmc2grp";
+ sirf,function = "sdmmc2";
+ };
+ };
+ sdmmc3_pins_a: sdmmc3_0 {
+ sdmmc3 {
+ sirf,pins = "sdmmc3grp";
+ sirf,function = "sdmmc3";
+ };
+ };
+ sdmmc4_pins_a: sdmmc4_0 {
+ sdmmc4 {
+ sirf,pins = "sdmmc4grp";
+ sirf,function = "sdmmc4";
+ };
+ };
+ sdmmc5_pins_a: sdmmc5_0 {
+ sdmmc5 {
+ sirf,pins = "sdmmc5grp";
+ sirf,function = "sdmmc5";
+ };
+ };
+ i2s_pins_a: i2s_0 {
+ i2s {
+ sirf,pins = "i2sgrp";
+ sirf,function = "i2s";
+ };
+ };
+ ac97_pins_a: ac97_0 {
+ ac97 {
+ sirf,pins = "ac97grp";
+ sirf,function = "ac97";
+ };
+ };
+ nand_pins_a: nand_0 {
+ nand {
+ sirf,pins = "nandgrp";
+ sirf,function = "nand";
+ };
+ };
+ usp0_pins_a: usp0_0 {
+ usp0 {
+ sirf,pins = "usp0grp";
+ sirf,function = "usp0";
+ };
+ };
+ usp1_pins_a: usp1_0 {
+ usp1 {
+ sirf,pins = "usp1grp";
+ sirf,function = "usp1";
+ };
+ };
+ usp2_pins_a: usp2_0 {
+ usp2 {
+ sirf,pins = "usp2grp";
+ sirf,function = "usp2";
+ };
+ };
+ usb0_utmi_drvbus_pins_a: usb0_utmi_drvbus_0 {
+ usb0_utmi_drvbus {
+ sirf,pins = "usb0_utmi_drvbusgrp";
+ sirf,function = "usb0_utmi_drvbus";
+ };
+ };
+ usb1_utmi_drvbus_pins_a: usb1_utmi_drvbus_0 {
+ usb1_utmi_drvbus {
+ sirf,pins = "usb1_utmi_drvbusgrp";
+ sirf,function = "usb1_utmi_drvbus";
+ };
+ };
+ warm_rst_pins_a: warm_rst_0 {
+ warm_rst {
+ sirf,pins = "warm_rstgrp";
+ sirf,function = "warm_rst";
+ };
+ };
+ pulse_count_pins_a: pulse_count_0 {
+ pulse_count {
+ sirf,pins = "pulse_countgrp";
+ sirf,function = "pulse_count";
+ };
+ };
+ cko0_rst_pins_a: cko0_rst_0 {
+ cko0_rst {
+ sirf,pins = "cko0_rstgrp";
+ sirf,function = "cko0_rst";
+ };
+ };
+ cko1_rst_pins_a: cko1_rst_0 {
+ cko1_rst {
+ sirf,pins = "cko1_rstgrp";
+ sirf,function = "cko1_rst";
+ };
+ };
+ };
+
+ pwm@cc130000 {
+ compatible = "sirf,marco-pwm";
+ reg = <0xcc130000 0x10000>;
+ };
+
+ efusesys@cc140000 {
+ compatible = "sirf,marco-efuse";
+ reg = <0xcc140000 0x10000>;
+ };
+
+ pulsec@cc150000 {
+ compatible = "sirf,marco-pulsec";
+ reg = <0xcc150000 0x10000>;
+ interrupts = <0 48 0>;
+ };
+
+ pci-iobg {
+ compatible = "sirf,marco-pciiobg", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xcd000000 0xcd000000 0x1000000>;
+
+ sd0: sdhci@cd000000 {
+ cell-index = <0>;
+ compatible = "sirf,marco-sdhc";
+ reg = <0xcd000000 0x100000>;
+ interrupts = <0 38 0>;
+ status = "disabled";
+ };
+
+ sd1: sdhci@cd100000 {
+ cell-index = <1>;
+ compatible = "sirf,marco-sdhc";
+ reg = <0xcd100000 0x100000>;
+ interrupts = <0 38 0>;
+ status = "disabled";
+ };
+
+ sd2: sdhci@cd200000 {
+ cell-index = <2>;
+ compatible = "sirf,marco-sdhc";
+ reg = <0xcd200000 0x100000>;
+ interrupts = <0 23 0>;
+ status = "disabled";
+ };
+
+ sd3: sdhci@cd300000 {
+ cell-index = <3>;
+ compatible = "sirf,marco-sdhc";
+ reg = <0xcd300000 0x100000>;
+ interrupts = <0 23 0>;
+ status = "disabled";
+ };
+
+ sd4: sdhci@cd400000 {
+ cell-index = <4>;
+ compatible = "sirf,marco-sdhc";
+ reg = <0xcd400000 0x100000>;
+ interrupts = <0 39 0>;
+ status = "disabled";
+ };
+
+ sd5: sdhci@cd500000 {
+ cell-index = <5>;
+ compatible = "sirf,marco-sdhc";
+ reg = <0xcd500000 0x100000>;
+ interrupts = <0 39 0>;
+ status = "disabled";
+ };
+
+ pci-copy@cd900000 {
+ compatible = "sirf,marco-pcicp";
+ reg = <0xcd900000 0x100000>;
+ interrupts = <0 40 0>;
+ };
+
+ rom-interface@cda00000 {
+ compatible = "sirf,marco-romif";
+ reg = <0xcda00000 0x100000>;
+ };
+ };
+ };
+
+ rtc-iobg {
+ compatible = "sirf,marco-rtciobg", "sirf-marco-rtciobg-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xc1000000 0x10000>;
+
+ gpsrtc@1000 {
+ compatible = "sirf,marco-gpsrtc";
+ reg = <0x1000 0x1000>;
+ interrupts = <0 55 0>,
+ <0 56 0>,
+ <0 57 0>;
+ };
+
+ sysrtc@2000 {
+ compatible = "sirf,marco-sysrtc";
+ reg = <0x2000 0x1000>;
+ interrupts = <0 52 0>,
+ <0 53 0>,
+ <0 54 0>;
+ };
+
+ pwrc@3000 {
+ compatible = "sirf,marco-pwrc";
+ reg = <0x3000 0x1000>;
+ interrupts = <0 32 0>;
+ };
+ };
+
+ uus-iobg {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xce000000 0xce000000 0x1000000>;
+
+ usb0: usb@ce000000 {
+ compatible = "chipidea,ci13611a-marco";
+ reg = <0xce000000 0x10000>;
+ interrupts = <0 10 0>;
+ };
+
+ usb1: usb@ce010000 {
+ compatible = "chipidea,ci13611a-marco";
+ reg = <0xce010000 0x10000>;
+ interrupts = <0 11 0>;
+ };
+
+ security@ce020000 {
+ compatible = "sirf,marco-security";
+ reg = <0xce020000 0x10000>;
+ interrupts = <0 42 0>;
+ };
+ };
+
+ can-iobg {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xd0000000 0xd0000000 0x1000000>;
+
+ can0: can@d0000000 {
+ compatible = "sirf,marco-can";
+ reg = <0xd0000000 0x10000>;
+ };
+
+ can1: can@d0010000 {
+ compatible = "sirf,marco-can";
+ reg = <0xd0010000 0x10000>;
+ };
+ };
+
+ lvds-iobg {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xd1000000 0xd1000000 0x1000000>;
+
+ lvds@d1000000 {
+ compatible = "sirf,marco-lvds";
+ reg = <0xd1000000 0x10000>;
+ interrupts = <0 64 0>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
index c9b4f27d191e..7f70a39459f6 100644
--- a/arch/arm/boot/dts/mmp2-brownstone.dts
+++ b/arch/arm/boot/dts/mmp2-brownstone.dts
@@ -29,6 +29,164 @@
};
twsi1: i2c@d4011000 {
status = "okay";
+ pmic: max8925@3c {
+ compatible = "maxium,max8925";
+ reg = <0x3c>;
+ interrupts = <1>;
+ interrupt-parent = <&intcmux4>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ maxim,tsc-irq = <0>;
+
+ regulators {
+ SDV1 {
+ regulator-min-microvolt = <637500>;
+ regulator-max-microvolt = <1425000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ SDV2 {
+ regulator-min-microvolt = <650000>;
+ regulator-max-microvolt = <2225000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ SDV3 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO1 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO2 {
+ regulator-min-microvolt = <650000>;
+ regulator-max-microvolt = <2250000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO3 {
+ regulator-min-microvolt = <650000>;
+ regulator-max-microvolt = <2250000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO4 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO5 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO6 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO7 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO8 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO9 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO10 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ };
+ LDO11 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO12 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO13 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO14 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO15 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO16 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO17 {
+ regulator-min-microvolt = <650000>;
+ regulator-max-microvolt = <2250000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO18 {
+ regulator-min-microvolt = <650000>;
+ regulator-max-microvolt = <2250000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO19 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ LDO20 {
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3900000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ backlight {
+ maxim,max8925-dual-string = <0>;
+ };
+ charger {
+ batt-detect = <0>;
+ topoff-threshold = <1>;
+ fast-charge = <7>;
+ no-temp-support = <0>;
+ no-insert-detect = <0>;
+ };
+ };
};
rtc: rtc@d4010000 {
status = "okay";
diff --git a/arch/arm/boot/dts/mmp2.dtsi b/arch/arm/boot/dts/mmp2.dtsi
index 0514fb41627e..1429ac05b36d 100644
--- a/arch/arm/boot/dts/mmp2.dtsi
+++ b/arch/arm/boot/dts/mmp2.dtsi
@@ -46,7 +46,7 @@
mrvl,intc-nr-irqs = <64>;
};
- intcmux4@d4282150 {
+ intcmux4: interrupt-controller@d4282150 {
compatible = "mrvl,mmp2-mux-intc";
interrupts = <4>;
interrupt-controller;
@@ -201,6 +201,8 @@
compatible = "mrvl,mmp-twsi";
reg = <0xd4011000 0x1000>;
interrupts = <7>;
+ #address-cells = <1>;
+ #size-cells = <0>;
mrvl,i2c-fast-mode;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi
index 055fca542120..3329719a9412 100644
--- a/arch/arm/boot/dts/prima2.dtsi
+++ b/arch/arm/boot/dts/prima2.dtsi
@@ -58,10 +58,11 @@
#size-cells = <1>;
ranges = <0x88000000 0x88000000 0x40000>;
- clock-controller@88000000 {
+ clks: clock-controller@88000000 {
compatible = "sirf,prima2-clkc";
reg = <0x88000000 0x1000>;
interrupts = <3>;
+ #clock-cells = <1>;
};
reset-controller@88010000 {
@@ -85,6 +86,7 @@
compatible = "sirf,prima2-memc";
reg = <0x90000000 0x10000>;
interrupts = <27>;
+ clocks = <&clks 5>;
};
};
@@ -104,6 +106,7 @@
compatible = "sirf,prima2-vpp";
reg = <0x90020000 0x10000>;
interrupts = <31>;
+ clocks = <&clks 35>;
};
};
@@ -117,6 +120,7 @@
compatible = "powervr,sgx531";
reg = <0x98000000 0x8000000>;
interrupts = <6>;
+ clocks = <&clks 32>;
};
};
@@ -130,6 +134,7 @@
compatible = "sirf,prima2-video-codec";
reg = <0xa0000000 0x8000000>;
interrupts = <5>;
+ clocks = <&clks 33>;
};
};
@@ -149,12 +154,14 @@
compatible = "sirf,prima2-gps";
reg = <0xa8010000 0x10000>;
interrupts = <7>;
+ clocks = <&clks 9>;
};
dsp@a9000000 {
compatible = "sirf,prima2-dsp";
reg = <0xa9000000 0x1000000>;
interrupts = <8>;
+ clocks = <&clks 8>;
};
};
@@ -174,12 +181,14 @@
compatible = "sirf,prima2-nand";
reg = <0xb0030000 0x10000>;
interrupts = <41>;
+ clocks = <&clks 26>;
};
audio@b0040000 {
compatible = "sirf,prima2-audio";
reg = <0xb0040000 0x10000>;
interrupts = <35>;
+ clocks = <&clks 27>;
};
uart0: uart@b0050000 {
@@ -187,6 +196,7 @@
compatible = "sirf,prima2-uart";
reg = <0xb0050000 0x10000>;
interrupts = <17>;
+ clocks = <&clks 13>;
};
uart1: uart@b0060000 {
@@ -194,6 +204,7 @@
compatible = "sirf,prima2-uart";
reg = <0xb0060000 0x10000>;
interrupts = <18>;
+ clocks = <&clks 14>;
};
uart2: uart@b0070000 {
@@ -201,6 +212,7 @@
compatible = "sirf,prima2-uart";
reg = <0xb0070000 0x10000>;
interrupts = <19>;
+ clocks = <&clks 15>;
};
usp0: usp@b0080000 {
@@ -208,6 +220,7 @@
compatible = "sirf,prima2-usp";
reg = <0xb0080000 0x10000>;
interrupts = <20>;
+ clocks = <&clks 28>;
};
usp1: usp@b0090000 {
@@ -215,6 +228,7 @@
compatible = "sirf,prima2-usp";
reg = <0xb0090000 0x10000>;
interrupts = <21>;
+ clocks = <&clks 29>;
};
usp2: usp@b00a0000 {
@@ -222,6 +236,7 @@
compatible = "sirf,prima2-usp";
reg = <0xb00a0000 0x10000>;
interrupts = <22>;
+ clocks = <&clks 30>;
};
dmac0: dma-controller@b00b0000 {
@@ -229,6 +244,7 @@
compatible = "sirf,prima2-dmac";
reg = <0xb00b0000 0x10000>;
interrupts = <12>;
+ clocks = <&clks 24>;
};
dmac1: dma-controller@b0160000 {
@@ -236,11 +252,13 @@
compatible = "sirf,prima2-dmac";
reg = <0xb0160000 0x10000>;
interrupts = <13>;
+ clocks = <&clks 25>;
};
vip@b00C0000 {
compatible = "sirf,prima2-vip";
reg = <0xb00C0000 0x10000>;
+ clocks = <&clks 31>;
};
spi0: spi@b00d0000 {
@@ -248,6 +266,7 @@
compatible = "sirf,prima2-spi";
reg = <0xb00d0000 0x10000>;
interrupts = <15>;
+ clocks = <&clks 19>;
};
spi1: spi@b0170000 {
@@ -255,6 +274,7 @@
compatible = "sirf,prima2-spi";
reg = <0xb0170000 0x10000>;
interrupts = <16>;
+ clocks = <&clks 20>;
};
i2c0: i2c@b00e0000 {
@@ -262,6 +282,7 @@
compatible = "sirf,prima2-i2c";
reg = <0xb00e0000 0x10000>;
interrupts = <24>;
+ clocks = <&clks 17>;
};
i2c1: i2c@b00f0000 {
@@ -269,12 +290,14 @@
compatible = "sirf,prima2-i2c";
reg = <0xb00f0000 0x10000>;
interrupts = <25>;
+ clocks = <&clks 18>;
};
tsc@b0110000 {
compatible = "sirf,prima2-tsc";
reg = <0xb0110000 0x10000>;
interrupts = <33>;
+ clocks = <&clks 16>;
};
gpio: pinctrl@b0120000 {
@@ -507,17 +530,20 @@
pwm@b0130000 {
compatible = "sirf,prima2-pwm";
reg = <0xb0130000 0x10000>;
+ clocks = <&clks 21>;
};
efusesys@b0140000 {
compatible = "sirf,prima2-efuse";
reg = <0xb0140000 0x10000>;
+ clocks = <&clks 22>;
};
pulsec@b0150000 {
compatible = "sirf,prima2-pulsec";
reg = <0xb0150000 0x10000>;
interrupts = <48>;
+ clocks = <&clks 23>;
};
pci-iobg {
@@ -616,12 +642,14 @@
compatible = "chipidea,ci13611a-prima2";
reg = <0xb8000000 0x10000>;
interrupts = <10>;
+ clocks = <&clks 40>;
};
usb1: usb@b00f0000 {
compatible = "chipidea,ci13611a-prima2";
reg = <0xb8010000 0x10000>;
interrupts = <11>;
+ clocks = <&clks 41>;
};
sata@b00f0000 {
@@ -634,6 +662,7 @@
compatible = "sirf,prima2-security";
reg = <0xb8030000 0x10000>;
interrupts = <42>;
+ clocks = <&clks 7>;
};
};
};
diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
index a7505a95a3b7..93da655b2598 100644
--- a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
+++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
@@ -9,12 +9,16 @@
*/
/dts-v1/;
-/include/ "skeleton.dtsi"
+/include/ "r8a7740.dtsi"
/ {
model = "armadillo 800 eva";
compatible = "renesas,armadillo800eva";
+ chosen {
+ bootargs = "console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096 rw";
+ };
+
memory {
device_type = "memory";
reg = <0x40000000 0x20000000>;
diff --git a/arch/arm/boot/dts/sh7372-mackerel.dts b/arch/arm/boot/dts/sh7372-mackerel.dts
index 286f0caef013..8acf51e0cdae 100644
--- a/arch/arm/boot/dts/sh7372-mackerel.dts
+++ b/arch/arm/boot/dts/sh7372-mackerel.dts
@@ -9,12 +9,16 @@
*/
/dts-v1/;
-/include/ "skeleton.dtsi"
+/include/ "sh7372.dtsi"
/ {
model = "Mackerel (AP4 EVM 2nd)";
compatible = "renesas,mackerel";
+ chosen {
+ bootargs = "console=tty0, console=ttySC0,115200 earlyprintk=sh-sci.0,115200 root=/dev/nfs nfsroot=,tcp,v3 ip=dhcp mem=240m rw";
+ };
+
memory {
device_type = "memory";
reg = <0x40000000 0x10000000>;
diff --git a/arch/arm/boot/dts/sh73a0-kzm9g.dts b/arch/arm/boot/dts/sh73a0-kzm9g.dts
index bcb911951978..7c4071e7790c 100644
--- a/arch/arm/boot/dts/sh73a0-kzm9g.dts
+++ b/arch/arm/boot/dts/sh73a0-kzm9g.dts
@@ -9,12 +9,16 @@
*/
/dts-v1/;
-/include/ "skeleton.dtsi"
+/include/ "sh73a0.dtsi"
/ {
model = "KZM-A9-GT";
compatible = "renesas,kzm9g", "renesas,sh73a0";
+ chosen {
+ bootargs = "console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel earlyprintk=sh-sci.4,115200";
+ };
+
memory {
device_type = "memory";
reg = <0x41000000 0x1e800000>;
diff --git a/arch/arm/boot/dts/sh73a0-reference.dtsi b/arch/arm/boot/dts/sh73a0-reference.dtsi
new file mode 100644
index 000000000000..d4bb0125b2b2
--- /dev/null
+++ b/arch/arm/boot/dts/sh73a0-reference.dtsi
@@ -0,0 +1,24 @@
+/*
+ * Device Tree Source for the SH73A0 SoC
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * 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/ "sh73a0.dtsi"
+
+/ {
+ compatible = "renesas,sh73a0";
+
+ mmcif: mmcif@0x10010000 {
+ compatible = "renesas,sh-mmcif";
+ reg = <0xe6bd0000 0x100>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 140 0x4
+ 0 141 0x4>;
+ reg-io-width = <4>;
+ };
+};
diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi
new file mode 100644
index 000000000000..8a59465d0231
--- /dev/null
+++ b/arch/arm/boot/dts/sh73a0.dtsi
@@ -0,0 +1,100 @@
+/*
+ * Device Tree Source for the SH73A0 SoC
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * 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/ "skeleton.dtsi"
+
+/ {
+ compatible = "renesas,sh73a0";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ };
+ };
+
+ gic: interrupt-controller@f0001000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0xf0001000 0x1000>,
+ <0xf0000100 0x100>;
+ };
+
+ i2c0: i2c@0xe6820000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,rmobile-iic";
+ reg = <0xe6820000 0x425>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 167 0x4
+ 0 168 0x4
+ 0 169 0x4
+ 0 170 0x4>;
+ };
+
+ i2c1: i2c@0xe6822000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,rmobile-iic";
+ reg = <0xe6822000 0x425>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 51 0x4
+ 0 52 0x4
+ 0 53 0x4
+ 0 54 0x4>;
+ };
+
+ i2c2: i2c@0xe6824000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,rmobile-iic";
+ reg = <0xe6824000 0x425>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 171 0x4
+ 0 172 0x4
+ 0 173 0x4
+ 0 174 0x4>;
+ };
+
+ i2c3: i2c@0xe6826000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,rmobile-iic";
+ reg = <0xe6826000 0x425>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 183 0x4
+ 0 184 0x4
+ 0 185 0x4
+ 0 186 0x4>;
+ };
+
+ i2c4: i2c@0xe6828000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,rmobile-iic";
+ reg = <0xe6828000 0x425>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 187 0x4
+ 0 188 0x4
+ 0 189 0x4
+ 0 190 0x4>;
+ };
+};
diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index 19aec421bb26..936d2306e7e1 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -25,6 +25,10 @@
ethernet0 = &gmac0;
serial0 = &uart0;
serial1 = &uart1;
+ timer0 = &timer0;
+ timer1 = &timer1;
+ timer2 = &timer2;
+ timer3 = &timer3;
};
cpus {
@@ -98,47 +102,41 @@
interrupts = <1 13 0xf04>;
};
- timer0: timer@ffc08000 {
+ timer0: timer0@ffc08000 {
compatible = "snps,dw-apb-timer-sp";
interrupts = <0 167 4>;
- clock-frequency = <200000000>;
reg = <0xffc08000 0x1000>;
};
- timer1: timer@ffc09000 {
+ timer1: timer1@ffc09000 {
compatible = "snps,dw-apb-timer-sp";
interrupts = <0 168 4>;
- clock-frequency = <200000000>;
reg = <0xffc09000 0x1000>;
};
- timer2: timer@ffd00000 {
+ timer2: timer2@ffd00000 {
compatible = "snps,dw-apb-timer-osc";
interrupts = <0 169 4>;
- clock-frequency = <200000000>;
reg = <0xffd00000 0x1000>;
};
- timer3: timer@ffd01000 {
+ timer3: timer3@ffd01000 {
compatible = "snps,dw-apb-timer-osc";
interrupts = <0 170 4>;
- clock-frequency = <200000000>;
reg = <0xffd01000 0x1000>;
};
- uart0: uart@ffc02000 {
+ uart0: serial0@ffc02000 {
compatible = "snps,dw-apb-uart";
reg = <0xffc02000 0x1000>;
- clock-frequency = <7372800>;
interrupts = <0 162 4>;
reg-shift = <2>;
reg-io-width = <4>;
};
- uart1: uart@ffc03000 {
+ uart1: serial1@ffc03000 {
compatible = "snps,dw-apb-uart";
reg = <0xffc03000 0x1000>;
- clock-frequency = <7372800>;
interrupts = <0 163 4>;
reg-shift = <2>;
reg-io-width = <4>;
diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dts b/arch/arm/boot/dts/socfpga_cyclone5.dts
index ab7e4a94299f..3ae8a83a0875 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5.dts
@@ -20,7 +20,7 @@
/ {
model = "Altera SOCFPGA Cyclone V";
- compatible = "altr,socfpga-cyclone5";
+ compatible = "altr,socfpga-cyclone5", "altr,socfpga";
chosen {
bootargs = "console=ttyS0,57600";
@@ -29,6 +29,36 @@
memory {
name = "memory";
device_type = "memory";
- reg = <0x0 0x10000000>; /* 256MB */
+ reg = <0x0 0x40000000>; /* 1GB */
+ };
+
+ soc {
+ timer0@ffc08000 {
+ clock-frequency = <100000000>;
+ };
+
+ timer1@ffc09000 {
+ clock-frequency = <100000000>;
+ };
+
+ timer2@ffd00000 {
+ clock-frequency = <25000000>;
+ };
+
+ timer3@ffd01000 {
+ clock-frequency = <25000000>;
+ };
+
+ serial0@ffc02000 {
+ clock-frequency = <100000000>;
+ };
+
+ serial1@ffc03000 {
+ clock-frequency = <100000000>;
+ };
+
+ sysmgr@ffd08000 {
+ cpu1-start-addr = <0xffd080c4>;
+ };
};
};
diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts
new file mode 100644
index 000000000000..1036eba40bbf
--- /dev/null
+++ b/arch/arm/boot/dts/socfpga_vt.dts
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 Altera Corporation <www.altera.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/>.
+ */
+
+/dts-v1/;
+/include/ "socfpga.dtsi"
+
+/ {
+ model = "Altera SOCFPGA VT";
+ compatible = "altr,socfpga-vt", "altr,socfpga";
+
+ chosen {
+ bootargs = "console=ttyS0,57600";
+ };
+
+ memory {
+ name = "memory";
+ device_type = "memory";
+ reg = <0x0 0x40000000>; /* 1 GB */
+ };
+
+ soc {
+ timer0@ffc08000 {
+ clock-frequency = <7000000>;
+ };
+
+ timer1@ffc09000 {
+ clock-frequency = <7000000>;
+ };
+
+ timer2@ffd00000 {
+ clock-frequency = <7000000>;
+ };
+
+ timer3@ffd01000 {
+ clock-frequency = <7000000>;
+ };
+
+ serial0@ffc02000 {
+ clock-frequency = <7372800>;
+ };
+
+ serial1@ffc03000 {
+ clock-frequency = <7372800>;
+ };
+
+ sysmgr@ffd08000 {
+ cpu1-start-addr = <0xffd08010>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/ste-nomadik-s8815.dts b/arch/arm/boot/dts/ste-nomadik-s8815.dts
new file mode 100644
index 000000000000..b28fbf3408e3
--- /dev/null
+++ b/arch/arm/boot/dts/ste-nomadik-s8815.dts
@@ -0,0 +1,30 @@
+/*
+ * Device Tree for the ST-Ericsson Nomadik S8815 board
+ * Produced by Calao Systems
+ */
+
+/dts-v1/;
+/include/ "ste-nomadik-stn8815.dtsi"
+
+/ {
+ model = "Calao Systems USB-S8815";
+ compatible = "calaosystems,usb-s8815";
+
+ chosen {
+ bootargs = "root=/dev/ram0 console=ttyAMA1,115200n8 earlyprintk";
+ };
+
+ /* Custom board node with GPIO pins to active etc */
+ usb-s8815 {
+ /* The S8815 is using this very GPIO pin for the SMSC91x IRQs */
+ ethernet-gpio {
+ gpios = <&gpio3 19 0x1>;
+ interrupts = <19 0x1>;
+ interrupt-parent = <&gpio3>;
+ };
+ /* This will bias the MMC/SD card detect line */
+ mmcsd-gpio {
+ gpios = <&gpio3 16 0x1>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
new file mode 100644
index 000000000000..4a4aab395141
--- /dev/null
+++ b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
@@ -0,0 +1,256 @@
+/*
+ * Device Tree for the ST-Ericsson Nomadik 8815 STn8815 SoC
+ */
+/include/ "skeleton.dtsi"
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ memory {
+ reg = <0x00000000 0x04000000>,
+ <0x08000000 0x04000000>;
+ };
+
+ L2: l2-cache {
+ compatible = "arm,l210-cache";
+ reg = <0x10210000 0x1000>;
+ interrupt-parent = <&vica>;
+ interrupts = <30>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
+ mtu0 {
+ /* Nomadik system timer */
+ reg = <0x101e2000 0x1000>;
+ interrupt-parent = <&vica>;
+ interrupts = <4>;
+ };
+
+ mtu1 {
+ /* Secondary timer */
+ reg = <0x101e3000 0x1000>;
+ interrupt-parent = <&vica>;
+ interrupts = <5>;
+ };
+
+ gpio0: gpio@101e4000 {
+ compatible = "st,nomadik-gpio";
+ reg = <0x101e4000 0x80>;
+ interrupt-parent = <&vica>;
+ interrupts = <6>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <0>;
+ };
+
+ gpio1: gpio@101e5000 {
+ compatible = "st,nomadik-gpio";
+ reg = <0x101e5000 0x80>;
+ interrupt-parent = <&vica>;
+ interrupts = <7>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <1>;
+ };
+
+ gpio2: gpio@101e6000 {
+ compatible = "st,nomadik-gpio";
+ reg = <0x101e6000 0x80>;
+ interrupt-parent = <&vica>;
+ interrupts = <8>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <2>;
+ };
+
+ gpio3: gpio@101e7000 {
+ compatible = "st,nomadik-gpio";
+ reg = <0x101e7000 0x80>;
+ interrupt-parent = <&vica>;
+ interrupts = <9>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <3>;
+ };
+
+ pinctrl {
+ compatible = "stericsson,nmk-pinctrl-stn8815";
+ };
+
+ /* A NAND flash of 128 MiB */
+ fsmc: flash@40000000 {
+ compatible = "stericsson,fsmc-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x10100000 0x1000>, /* FSMC Register*/
+ <0x40000000 0x2000>, /* NAND Base DATA */
+ <0x41000000 0x2000>, /* NAND Base ADDR */
+ <0x40800000 0x2000>; /* NAND Base CMD */
+ reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
+ status = "okay";
+
+ partition@0 {
+ label = "X-Loader(NAND)";
+ reg = <0x0 0x40000>;
+ };
+ partition@40000 {
+ label = "MemInit(NAND)";
+ reg = <0x40000 0x40000>;
+ };
+ partition@80000 {
+ label = "BootLoader(NAND)";
+ reg = <0x80000 0x200000>;
+ };
+ partition@280000 {
+ label = "Kernel zImage(NAND)";
+ reg = <0x280000 0x300000>;
+ };
+ partition@580000 {
+ label = "Root Filesystem(NAND)";
+ reg = <0x580000 0x1600000>;
+ };
+ partition@1b80000 {
+ label = "User Filesystem(NAND)";
+ reg = <0x1b80000 0x6480000>;
+ };
+ };
+
+ external-bus@34000000 {
+ compatible = "simple-bus";
+ reg = <0x34000000 0x1000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x34000000 0x1000000>;
+ ethernet@300 {
+ compatible = "smsc,lan91c111";
+ reg = <0x300 0x0fd00>;
+ };
+ };
+
+ /* I2C0 connected to the STw4811 power management chip */
+ i2c0 {
+ compatible = "i2c-gpio";
+ gpios = <&gpio1 31 0>, /* sda */
+ <&gpio1 30 0>; /* scl */
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ stw4811@2d {
+ compatible = "st,stw4811";
+ reg = <0x2d>;
+ };
+ };
+
+ /* I2C1 connected to various sensors */
+ i2c1 {
+ compatible = "i2c-gpio";
+ gpios = <&gpio1 22 0>, /* sda */
+ <&gpio1 21 0>; /* scl */
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ camera@2d {
+ compatible = "st,camera";
+ reg = <0x10>;
+ };
+ stw5095@1a {
+ compatible = "st,stw5095";
+ reg = <0x1a>;
+ };
+ lis3lv02dl@1d {
+ compatible = "st,lis3lv02dl";
+ reg = <0x1d>;
+ };
+ };
+
+ /* I2C2 connected to the USB portions of the STw4811 only */
+ i2c2 {
+ compatible = "i2c-gpio";
+ gpios = <&gpio2 10 0>, /* sda */
+ <&gpio2 9 0>; /* scl */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ stw4811@2d {
+ compatible = "st,stw4811-usb";
+ reg = <0x2d>;
+ };
+ };
+
+ amba {
+ compatible = "arm,amba-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ vica: intc@0x10140000 {
+ compatible = "arm,versatile-vic";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x10140000 0x20>;
+ };
+
+ vicb: intc@0x10140020 {
+ compatible = "arm,versatile-vic";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x10140020 0x20>;
+ };
+
+ uart0: uart@101fd000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x101fd000 0x1000>;
+ interrupt-parent = <&vica>;
+ interrupts = <12>;
+ };
+
+ uart1: uart@101fb000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x101fb000 0x1000>;
+ interrupt-parent = <&vica>;
+ interrupts = <17>;
+ };
+
+ uart2: uart@101f2000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x101f2000 0x1000>;
+ interrupt-parent = <&vica>;
+ interrupts = <28>;
+ status = "disabled";
+ };
+
+ rng: rng@101b0000 {
+ compatible = "arm,primecell";
+ reg = <0x101b0000 0x1000>;
+ };
+
+ rtc: rtc@101e8000 {
+ compatible = "arm,pl031", "arm,primecell";
+ reg = <0x101e8000 0x1000>;
+ interrupt-parent = <&vica>;
+ interrupts = <10>;
+ };
+
+ mmcsd: sdi@101f6000 {
+ compatible = "arm,pl18x", "arm,primecell";
+ reg = <0x101f6000 0x1000>;
+ interrupt-parent = <&vica>;
+ interrupts = <22>;
+ max-frequency = <48000000>;
+ bus-width = <4>;
+ mmc-cap-mmc-highspeed;
+ mmc-cap-sd-highspeed;
+ cd-gpios = <&gpio3 15 0x1>;
+ cd-inverted;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
new file mode 100644
index 000000000000..f84549ad791e
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * 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
+ */
+
+/dts-v1/;
+/include/ "sun4i-a10.dtsi"
+
+/ {
+ model = "Miniand Hackberry";
+ compatible = "miniand,hackberry", "allwinner,sun4i-a10";
+
+ chosen {
+ bootargs = "earlyprintk console=ttyS0,115200";
+ };
+
+ soc {
+ uart0: uart@01c28000 {
+ status = "okay";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index e61fdd47bd01..f99f60dadf5d 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -16,4 +16,34 @@
memory {
reg = <0x40000000 0x80000000>;
};
+
+ soc {
+ pinctrl@01c20800 {
+ compatible = "allwinner,sun4i-a10-pinctrl";
+ reg = <0x01c20800 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ uart0_pins_a: uart0@0 {
+ allwinner,pins = "PB22", "PB23";
+ allwinner,function = "uart0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ uart0_pins_b: uart0@1 {
+ allwinner,pins = "PF2", "PF4";
+ allwinner,function = "uart0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ uart1_pins_a: uart1@0 {
+ allwinner,pins = "PA10", "PA11";
+ allwinner,function = "uart1";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ };
+ };
};
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
index 498a091a4ea2..4a1e45d4aace 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
@@ -24,6 +24,8 @@
soc {
uart1: uart@01c28400 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_b>;
status = "okay";
};
};
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 59a2d265a98e..e1121890fb29 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -17,4 +17,27 @@
memory {
reg = <0x40000000 0x20000000>;
};
+
+ soc {
+ pinctrl@01c20800 {
+ compatible = "allwinner,sun5i-a13-pinctrl";
+ reg = <0x01c20800 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ uart1_pins_a: uart1@0 {
+ allwinner,pins = "PE10", "PE11";
+ allwinner,function = "uart1";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ uart1_pins_b: uart1@1 {
+ allwinner,pins = "PG3", "PG4";
+ allwinner,function = "uart1";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ };
+ };
};
diff --git a/arch/arm/boot/dts/tegra114-dalmore.dts b/arch/arm/boot/dts/tegra114-dalmore.dts
new file mode 100644
index 000000000000..a30aca62658a
--- /dev/null
+++ b/arch/arm/boot/dts/tegra114-dalmore.dts
@@ -0,0 +1,21 @@
+/dts-v1/;
+
+/include/ "tegra114.dtsi"
+
+/ {
+ model = "NVIDIA Tegra114 Dalmore evaluation board";
+ compatible = "nvidia,dalmore", "nvidia,tegra114";
+
+ memory {
+ reg = <0x80000000 0x40000000>;
+ };
+
+ serial@70006300 {
+ status = "okay";
+ clock-frequency = <408000000>;
+ };
+
+ pmc {
+ nvidia,invert-interrupt;
+ };
+};
diff --git a/arch/arm/boot/dts/tegra114-pluto.dts b/arch/arm/boot/dts/tegra114-pluto.dts
new file mode 100644
index 000000000000..9bea8f57aa47
--- /dev/null
+++ b/arch/arm/boot/dts/tegra114-pluto.dts
@@ -0,0 +1,21 @@
+/dts-v1/;
+
+/include/ "tegra114.dtsi"
+
+/ {
+ model = "NVIDIA Tegra114 Pluto evaluation board";
+ compatible = "nvidia,pluto", "nvidia,tegra114";
+
+ memory {
+ reg = <0x80000000 0x40000000>;
+ };
+
+ serial@70006300 {
+ status = "okay";
+ clock-frequency = <408000000>;
+ };
+
+ pmc {
+ nvidia,invert-interrupt;
+ };
+};
diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
new file mode 100644
index 000000000000..1dfaf2874c57
--- /dev/null
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -0,0 +1,153 @@
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "nvidia,tegra114";
+ interrupt-parent = <&gic>;
+
+ gic: interrupt-controller {
+ compatible = "arm,cortex-a15-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x50041000 0x1000>,
+ <0x50042000 0x1000>,
+ <0x50044000 0x2000>,
+ <0x50046000 0x2000>;
+ interrupts = <1 9 0xf04>;
+ };
+
+ timer@60005000 {
+ compatible = "nvidia,tegra114-timer", "nvidia,tegra20-timer";
+ reg = <0x60005000 0x400>;
+ interrupts = <0 0 0x04
+ 0 1 0x04
+ 0 41 0x04
+ 0 42 0x04
+ 0 121 0x04
+ 0 122 0x04>;
+ };
+
+ tegra_car: clock {
+ compatible = "nvidia,tegra114-car, nvidia,tegra30-car";
+ reg = <0x60006000 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ ahb: ahb {
+ compatible = "nvidia,tegra114-ahb", "nvidia,tegra30-ahb";
+ reg = <0x6000c004 0x14c>;
+ };
+
+ gpio: gpio {
+ compatible = "nvidia,tegra114-gpio", "nvidia,tegra30-gpio";
+ reg = <0x6000d000 0x1000>;
+ interrupts = <0 32 0x04
+ 0 33 0x04
+ 0 34 0x04
+ 0 35 0x04
+ 0 55 0x04
+ 0 87 0x04
+ 0 89 0x04
+ 0 125 0x04>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ };
+
+ pinmux: pinmux {
+ compatible = "nvidia,tegra114-pinmux";
+ reg = <0x70000868 0x148 /* Pad control registers */
+ 0x70003000 0x40c>; /* Mux registers */
+ };
+
+ serial@70006000 {
+ compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart";
+ reg = <0x70006000 0x40>;
+ reg-shift = <2>;
+ interrupts = <0 36 0x04>;
+ status = "disabled";
+ };
+
+ serial@70006040 {
+ compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart";
+ reg = <0x70006040 0x40>;
+ reg-shift = <2>;
+ interrupts = <0 37 0x04>;
+ status = "disabled";
+ };
+
+ serial@70006200 {
+ compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart";
+ reg = <0x70006200 0x100>;
+ reg-shift = <2>;
+ interrupts = <0 46 0x04>;
+ status = "disabled";
+ };
+
+ serial@70006300 {
+ compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart";
+ reg = <0x70006300 0x100>;
+ reg-shift = <2>;
+ interrupts = <0 90 0x04>;
+ status = "disabled";
+ };
+
+ rtc {
+ compatible = "nvidia,tegra114-rtc", "nvidia,tegra20-rtc";
+ reg = <0x7000e000 0x100>;
+ interrupts = <0 2 0x04>;
+ };
+
+ pmc {
+ compatible = "nvidia,tegra114-pmc", "nvidia,tegra30-pmc";
+ reg = <0x7000e400 0x400>;
+ };
+
+ iommu {
+ compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu";
+ reg = <0x7000f010 0x02c
+ 0x7000f1f0 0x010
+ 0x7000f228 0x074>;
+ nvidia,#asids = <4>;
+ dma-window = <0 0x40000000>;
+ nvidia,swgroups = <0x18659fe>;
+ nvidia,ahb = <&ahb>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <1>;
+ };
+
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <2>;
+ };
+
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <3>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 13 0xf08>,
+ <1 14 0xf08>,
+ <1 11 0xf08>,
+ <1 10 0xf08>;
+ };
+};
diff --git a/arch/arm/boot/dts/tegra20-colibri-512.dtsi b/arch/arm/boot/dts/tegra20-colibri-512.dtsi
new file mode 100644
index 000000000000..444162090042
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-colibri-512.dtsi
@@ -0,0 +1,491 @@
+/include/ "tegra20.dtsi"
+
+/ {
+ model = "Toradex Colibri T20 512MB";
+ compatible = "toradex,colibri_t20-512", "nvidia,tegra20";
+
+ memory {
+ reg = <0x00000000 0x20000000>;
+ };
+
+ host1x {
+ hdmi {
+ vdd-supply = <&hdmi_vdd_reg>;
+ pll-supply = <&hdmi_pll_reg>;
+
+ nvidia,ddc-i2c-bus = <&i2c_ddc>;
+ nvidia,hpd-gpio = <&gpio 111 0>; /* PN7 */
+ };
+ };
+
+ pinmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ audio_refclk {
+ nvidia,pins = "cdev1";
+ nvidia,function = "plla_out";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ crt {
+ nvidia,pins = "crtp";
+ nvidia,function = "crt";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ dap3 {
+ nvidia,pins = "dap3";
+ nvidia,function = "dap3";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ displaya {
+ nvidia,pins = "ld0", "ld1", "ld2", "ld3",
+ "ld4", "ld5", "ld6", "ld7", "ld8",
+ "ld9", "ld10", "ld11", "ld12", "ld13",
+ "ld14", "ld15", "ld16", "ld17",
+ "lhs", "lpw0", "lpw2", "lsc0",
+ "lsc1", "lsck", "lsda", "lspi", "lvs";
+ nvidia,function = "displaya";
+ nvidia,tristate = <1>;
+ };
+ gpio_dte {
+ nvidia,pins = "dte";
+ nvidia,function = "rsvd1";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ gpio_gmi {
+ nvidia,pins = "ata", "atc", "atd", "ate",
+ "dap1", "dap2", "dap4", "gpu", "irrx",
+ "irtx", "spia", "spib", "spic";
+ nvidia,function = "gmi";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ gpio_pta {
+ nvidia,pins = "pta";
+ nvidia,function = "rsvd4";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ gpio_uac {
+ nvidia,pins = "uac";
+ nvidia,function = "rsvd2";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ hdint {
+ nvidia,pins = "hdint";
+ nvidia,function = "hdmi";
+ nvidia,tristate = <1>;
+ };
+ i2c1 {
+ nvidia,pins = "rm";
+ nvidia,function = "i2c1";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ i2c3 {
+ nvidia,pins = "dtf";
+ nvidia,function = "i2c3";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ i2cddc {
+ nvidia,pins = "ddc";
+ nvidia,function = "i2c2";
+ nvidia,pull = <2>;
+ nvidia,tristate = <1>;
+ };
+ i2cp {
+ nvidia,pins = "i2cp";
+ nvidia,function = "i2cp";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ irda {
+ nvidia,pins = "uad";
+ nvidia,function = "irda";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ nand {
+ nvidia,pins = "kbca", "kbcc", "kbcd",
+ "kbce", "kbcf";
+ nvidia,function = "nand";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ owc {
+ nvidia,pins = "owc";
+ nvidia,function = "owr";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ pmc {
+ nvidia,pins = "pmc";
+ nvidia,function = "pwr_on";
+ nvidia,tristate = <0>;
+ };
+ pwm {
+ nvidia,pins = "sdb", "sdc", "sdd";
+ nvidia,function = "pwm";
+ nvidia,tristate = <1>;
+ };
+ sdio4 {
+ nvidia,pins = "atb", "gma", "gme";
+ nvidia,function = "sdio4";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ spi1 {
+ nvidia,pins = "spid", "spie", "spif";
+ nvidia,function = "spi1";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ spi4 {
+ nvidia,pins = "slxa", "slxc", "slxd", "slxk";
+ nvidia,function = "spi4";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ uarta {
+ nvidia,pins = "sdio1";
+ nvidia,function = "uarta";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ uartd {
+ nvidia,pins = "gmc";
+ nvidia,function = "uartd";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ ulpi {
+ nvidia,pins = "uaa", "uab", "uda";
+ nvidia,function = "ulpi";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ ulpi_refclk {
+ nvidia,pins = "cdev2";
+ nvidia,function = "pllp_out4";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ usb_gpio {
+ nvidia,pins = "spig", "spih";
+ nvidia,function = "spi2_alt";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ vi {
+ nvidia,pins = "dta", "dtb", "dtc", "dtd";
+ nvidia,function = "vi";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ vi_sc {
+ nvidia,pins = "csus";
+ nvidia,function = "vi_sensor_clk";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ };
+ };
+
+ i2c@7000c000 {
+ clock-frequency = <400000>;
+ };
+
+ i2c_ddc: i2c@7000c400 {
+ clock-frequency = <100000>;
+ };
+
+ i2c@7000c500 {
+ clock-frequency = <400000>;
+ };
+
+ i2c@7000d000 {
+ status = "okay";
+ clock-frequency = <400000>;
+
+ pmic: tps6586x@34 {
+ compatible = "ti,tps6586x";
+ reg = <0x34>;
+ interrupts = <0 86 0x4>;
+
+ ti,system-power-controller;
+
+ #gpio-cells = <2>;
+ gpio-controller;
+
+ sys-supply = <&vdd_5v0_reg>;
+ vin-sm0-supply = <&sys_reg>;
+ vin-sm1-supply = <&sys_reg>;
+ vin-sm2-supply = <&sys_reg>;
+ vinldo01-supply = <&sm2_reg>;
+ vinldo23-supply = <&sm2_reg>;
+ vinldo4-supply = <&sm2_reg>;
+ vinldo678-supply = <&sm2_reg>;
+ vinldo9-supply = <&sm2_reg>;
+
+ regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sys_reg: regulator@0 {
+ reg = <0>;
+ regulator-compatible = "sys";
+ regulator-name = "vdd_sys";
+ regulator-always-on;
+ };
+
+ regulator@1 {
+ reg = <1>;
+ regulator-compatible = "sm0";
+ regulator-name = "vdd_sm0,vdd_core";
+ regulator-min-microvolt = <1275000>;
+ regulator-max-microvolt = <1275000>;
+ regulator-always-on;
+ };
+
+ regulator@2 {
+ reg = <2>;
+ regulator-compatible = "sm1";
+ regulator-name = "vdd_sm1,vdd_cpu";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ sm2_reg: regulator@3 {
+ reg = <3>;
+ regulator-compatible = "sm2";
+ regulator-name = "vdd_sm2,vin_ldo*";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+ regulator-always-on;
+ };
+
+ /* LDO0 is not connected to anything */
+
+ regulator@5 {
+ reg = <5>;
+ regulator-compatible = "ldo1";
+ regulator-name = "vdd_ldo1,avdd_pll*";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ regulator@6 {
+ reg = <6>;
+ regulator-compatible = "ldo2";
+ regulator-name = "vdd_ldo2,vdd_rtc";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ /* LDO3 is not connected to anything */
+
+ regulator@8 {
+ reg = <8>;
+ regulator-compatible = "ldo4";
+ regulator-name = "vdd_ldo4,avdd_osc,vddio_sys";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo5_reg: regulator@9 {
+ reg = <9>;
+ regulator-compatible = "ldo5";
+ regulator-name = "vdd_ldo5,vdd_fuse";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ regulator@10 {
+ reg = <10>;
+ regulator-compatible = "ldo6";
+ regulator-name = "vdd_ldo6,avdd_vdac,vddio_vi,vddio_cam";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ hdmi_vdd_reg: regulator@11 {
+ reg = <11>;
+ regulator-compatible = "ldo7";
+ regulator-name = "vdd_ldo7,avdd_hdmi";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ hdmi_pll_reg: regulator@12 {
+ reg = <12>;
+ regulator-compatible = "ldo8";
+ regulator-name = "vdd_ldo8,avdd_hdmi_pll";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ regulator@13 {
+ reg = <13>;
+ regulator-compatible = "ldo9";
+ regulator-name = "vdd_ldo9,avdd_2v85,vdd_ddr_rx";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ regulator-always-on;
+ };
+
+ regulator@14 {
+ reg = <14>;
+ regulator-compatible = "ldo_rtc";
+ regulator-name = "vdd_rtc_out,vdd_cell";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+ };
+
+ temperature-sensor@4c {
+ compatible = "national,lm95245";
+ reg = <0x4c>;
+ };
+ };
+
+ memory-controller@7000f400 {
+ emc-table@83250 {
+ reg = <83250>;
+ compatible = "nvidia,tegra20-emc-table";
+ clock-frequency = <83250>;
+ nvidia,emc-registers = <0x00000005 0x00000011
+ 0x00000004 0x00000002 0x00000004 0x00000004
+ 0x00000001 0x0000000a 0x00000002 0x00000002
+ 0x00000001 0x00000001 0x00000003 0x00000004
+ 0x00000003 0x00000009 0x0000000c 0x0000025f
+ 0x00000000 0x00000003 0x00000003 0x00000002
+ 0x00000002 0x00000001 0x00000008 0x000000c8
+ 0x00000003 0x00000005 0x00000003 0x0000000c
+ 0x00000002 0x00000000 0x00000000 0x00000002
+ 0x00000000 0x00000000 0x00000083 0x00520006
+ 0x00000010 0x00000008 0x00000000 0x00000000
+ 0x00000000 0x00000000 0x00000000 0x00000000>;
+ };
+ emc-table@133200 {
+ reg = <133200>;
+ compatible = "nvidia,tegra20-emc-table";
+ clock-frequency = <133200>;
+ nvidia,emc-registers = <0x00000008 0x00000019
+ 0x00000006 0x00000002 0x00000004 0x00000004
+ 0x00000001 0x0000000a 0x00000002 0x00000002
+ 0x00000002 0x00000001 0x00000003 0x00000004
+ 0x00000003 0x00000009 0x0000000c 0x0000039f
+ 0x00000000 0x00000003 0x00000003 0x00000002
+ 0x00000002 0x00000001 0x00000008 0x000000c8
+ 0x00000003 0x00000007 0x00000003 0x0000000c
+ 0x00000002 0x00000000 0x00000000 0x00000002
+ 0x00000000 0x00000000 0x00000083 0x00510006
+ 0x00000010 0x00000008 0x00000000 0x00000000
+ 0x00000000 0x00000000 0x00000000 0x00000000>;
+ };
+ emc-table@166500 {
+ reg = <166500>;
+ compatible = "nvidia,tegra20-emc-table";
+ clock-frequency = <166500>;
+ nvidia,emc-registers = <0x0000000a 0x00000021
+ 0x00000008 0x00000003 0x00000004 0x00000004
+ 0x00000002 0x0000000a 0x00000003 0x00000003
+ 0x00000002 0x00000001 0x00000003 0x00000004
+ 0x00000003 0x00000009 0x0000000c 0x000004df
+ 0x00000000 0x00000003 0x00000003 0x00000003
+ 0x00000003 0x00000001 0x00000009 0x000000c8
+ 0x00000003 0x00000009 0x00000004 0x0000000c
+ 0x00000002 0x00000000 0x00000000 0x00000002
+ 0x00000000 0x00000000 0x00000083 0x004f0006
+ 0x00000010 0x00000008 0x00000000 0x00000000
+ 0x00000000 0x00000000 0x00000000 0x00000000>;
+ };
+ emc-table@333000 {
+ reg = <333000>;
+ compatible = "nvidia,tegra20-emc-table";
+ clock-frequency = <333000>;
+ nvidia,emc-registers = <0x00000014 0x00000041
+ 0x0000000f 0x00000005 0x00000004 0x00000005
+ 0x00000003 0x0000000a 0x00000005 0x00000005
+ 0x00000004 0x00000001 0x00000003 0x00000004
+ 0x00000003 0x00000009 0x0000000c 0x000009ff
+ 0x00000000 0x00000003 0x00000003 0x00000005
+ 0x00000005 0x00000001 0x0000000e 0x000000c8
+ 0x00000003 0x00000011 0x00000006 0x0000000c
+ 0x00000002 0x00000000 0x00000000 0x00000002
+ 0x00000000 0x00000000 0x00000083 0x00380006
+ 0x00000010 0x00000008 0x00000000 0x00000000
+ 0x00000000 0x00000000 0x00000000 0x00000000>;
+ };
+ };
+
+ ac97: ac97 {
+ status = "okay";
+ nvidia,codec-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
+ nvidia,codec-sync-gpio = <&gpio 120 0>; /* gpio PP0 */
+ };
+
+ usb@c5004000 {
+ status = "okay";
+ nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ };
+
+ sdhci@c8000600 {
+ cd-gpios = <&gpio 23 0>; /* gpio PC7 */
+ };
+
+ sound {
+ compatible = "nvidia,tegra-audio-wm9712-colibri_t20",
+ "nvidia,tegra-audio-wm9712";
+ nvidia,model = "Colibri T20 AC97 Audio";
+
+ nvidia,audio-routing =
+ "Headphone", "HPOUTL",
+ "Headphone", "HPOUTR",
+ "LineIn", "LINEINL",
+ "LineIn", "LINEINR",
+ "Mic", "MIC1";
+
+ nvidia,ac97-controller = <&ac97>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vdd_5v0_reg: regulator@100 {
+ compatible = "regulator-fixed";
+ reg = <100>;
+ regulator-name = "vdd_5v0";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+
+ regulator@101 {
+ compatible = "regulator-fixed";
+ reg = <101>;
+ regulator-name = "internal_usb";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ regulator-boot-on;
+ regulator-always-on;
+ gpio = <&gpio 217 0>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts
index 43eb72af8948..61d027f03617 100644
--- a/arch/arm/boot/dts/tegra20-harmony.dts
+++ b/arch/arm/boot/dts/tegra20-harmony.dts
@@ -3,7 +3,7 @@
/include/ "tegra20.dtsi"
/ {
- model = "NVIDIA Tegra2 Harmony evaluation board";
+ model = "NVIDIA Tegra20 Harmony evaluation board";
compatible = "nvidia,harmony", "nvidia,tegra20";
memory {
@@ -252,7 +252,6 @@
serial@70006300 {
status = "okay";
- clock-frequency = <216000000>;
};
i2c@7000c000 {
@@ -432,6 +431,10 @@
status = "okay";
};
+ usb-phy@c5004400 {
+ nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ };
+
sdhci@c8000200 {
status = "okay";
cd-gpios = <&gpio 69 0>; /* gpio PI5 */
@@ -448,6 +451,123 @@
bus-width = <8>;
};
+ kbc {
+ status = "okay";
+ nvidia,debounce-delay-ms = <2>;
+ nvidia,repeat-delay-ms = <160>;
+ nvidia,kbc-row-pins = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>;
+ nvidia,kbc-col-pins = <16 17 18 19 20 21 22 23>;
+ linux,keymap = <0x00020011 /* KEY_W */
+ 0x0003001F /* KEY_S */
+ 0x0004001E /* KEY_A */
+ 0x0005002C /* KEY_Z */
+ 0x000701D0 /* KEY_FN */
+ 0x0107008B /* KEY_MENU */
+ 0x02060038 /* KEY_LEFTALT */
+ 0x02070064 /* KEY_RIGHTALT */
+ 0x03000006 /* KEY_5 */
+ 0x03010005 /* KEY_4 */
+ 0x03020013 /* KEY_R */
+ 0x03030012 /* KEY_E */
+ 0x03040021 /* KEY_F */
+ 0x03050020 /* KEY_D */
+ 0x0306002D /* KEY_X */
+ 0x04000008 /* KEY_7 */
+ 0x04010007 /* KEY_6 */
+ 0x04020014 /* KEY_T */
+ 0x04030023 /* KEY_H */
+ 0x04040022 /* KEY_G */
+ 0x0405002F /* KEY_V */
+ 0x0406002E /* KEY_C */
+ 0x04070039 /* KEY_SPACE */
+ 0x0500000A /* KEY_9 */
+ 0x05010009 /* KEY_8 */
+ 0x05020016 /* KEY_U */
+ 0x05030015 /* KEY_Y */
+ 0x05040024 /* KEY_J */
+ 0x05050031 /* KEY_N */
+ 0x05060030 /* KEY_B */
+ 0x0507002B /* KEY_BACKSLASH */
+ 0x0600000C /* KEY_MINUS */
+ 0x0601000B /* KEY_0 */
+ 0x06020018 /* KEY_O */
+ 0x06030017 /* KEY_I */
+ 0x06040026 /* KEY_L */
+ 0x06050025 /* KEY_K */
+ 0x06060033 /* KEY_COMMA */
+ 0x06070032 /* KEY_M */
+ 0x0701000D /* KEY_EQUAL */
+ 0x0702001B /* KEY_RIGHTBRACE */
+ 0x0703001C /* KEY_ENTER */
+ 0x0707008B /* KEY_MENU */
+ 0x0804002A /* KEY_LEFTSHIFT */
+ 0x08050036 /* KEY_RIGHTSHIFT */
+ 0x0905001D /* KEY_LEFTCTRL */
+ 0x09070061 /* KEY_RIGHTCTRL */
+ 0x0B00001A /* KEY_LEFTBRACE */
+ 0x0B010019 /* KEY_P */
+ 0x0B020028 /* KEY_APOSTROPHE */
+ 0x0B030027 /* KEY_SEMICOLON */
+ 0x0B040035 /* KEY_SLASH */
+ 0x0B050034 /* KEY_DOT */
+ 0x0C000044 /* KEY_F10 */
+ 0x0C010043 /* KEY_F9 */
+ 0x0C02000E /* KEY_BACKSPACE */
+ 0x0C030004 /* KEY_3 */
+ 0x0C040003 /* KEY_2 */
+ 0x0C050067 /* KEY_UP */
+ 0x0C0600D2 /* KEY_PRINT */
+ 0x0C070077 /* KEY_PAUSE */
+ 0x0D00006E /* KEY_INSERT */
+ 0x0D01006F /* KEY_DELETE */
+ 0x0D030068 /* KEY_PAGEUP */
+ 0x0D04006D /* KEY_PAGEDOWN */
+ 0x0D05006A /* KEY_RIGHT */
+ 0x0D06006C /* KEY_DOWN */
+ 0x0D070069 /* KEY_LEFT */
+ 0x0E000057 /* KEY_F11 */
+ 0x0E010058 /* KEY_F12 */
+ 0x0E020042 /* KEY_F8 */
+ 0x0E030010 /* KEY_Q */
+ 0x0E04003E /* KEY_F4 */
+ 0x0E05003D /* KEY_F3 */
+ 0x0E060002 /* KEY_1 */
+ 0x0E070041 /* KEY_F7 */
+ 0x0F000001 /* KEY_ESC */
+ 0x0F010029 /* KEY_GRAVE */
+ 0x0F02003F /* KEY_F5 */
+ 0x0F03000F /* KEY_TAB */
+ 0x0F04003B /* KEY_F1 */
+ 0x0F05003C /* KEY_F2 */
+ 0x0F06003A /* KEY_CAPSLOCK */
+ 0x0F070040 /* KEY_F6 */
+ 0x14000047 /* KEY_KP7 */
+ 0x15000049 /* KEY_KP9 */
+ 0x15010048 /* KEY_KP8 */
+ 0x1502004B /* KEY_KP4 */
+ 0x1504004F /* KEY_KP1 */
+ 0x1601004E /* KEY_KPSLASH */
+ 0x1602004D /* KEY_KP6 */
+ 0x1603004C /* KEY_KP5 */
+ 0x16040051 /* KEY_KP3 */
+ 0x16050050 /* KEY_KP2 */
+ 0x16070052 /* KEY_KP0 */
+ 0x1B010037 /* KEY_KPASTERISK */
+ 0x1B03004A /* KEY_KPMINUS */
+ 0x1B04004E /* KEY_KPPLUS */
+ 0x1B050053 /* KEY_KPDOT */
+ 0x1C050073 /* KEY_VOLUMEUP */
+ 0x1D030066 /* KEY_HOME */
+ 0x1D04006B /* KEY_END */
+ 0x1D0500E1 /* KEY_BRIGHTNESSUP */
+ 0x1D060072 /* KEY_VOLUMEDOWN */
+ 0x1D0700E0 /* KEY_BRIGHTNESSDOWN */
+ 0x1E000045 /* KEY_NUMLOCK */
+ 0x1E010046 /* KEY_SCROLLLOCK */
+ 0x1E020071 /* KEY_MUTE */
+ 0x1F0400D6>; /* KEY_QUESTION */
+ };
+
regulators {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/tegra20-iris-512.dts b/arch/arm/boot/dts/tegra20-iris-512.dts
new file mode 100644
index 000000000000..52f1103907d7
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-iris-512.dts
@@ -0,0 +1,89 @@
+/dts-v1/;
+
+/include/ "tegra20-colibri-512.dtsi"
+
+/ {
+ model = "Toradex Colibri T20 512MB on Iris";
+ compatible = "toradex,iris", "toradex,colibri_t20-512", "nvidia,tegra20";
+
+ host1x {
+ hdmi {
+ status = "okay";
+ };
+ };
+
+ pinmux {
+ state_default: pinmux {
+ hdint {
+ nvidia,tristate = <0>;
+ };
+
+ i2cddc {
+ nvidia,tristate = <0>;
+ };
+
+ sdio4 {
+ nvidia,tristate = <0>;
+ };
+
+ uarta {
+ nvidia,tristate = <0>;
+ };
+
+ uartd {
+ nvidia,tristate = <0>;
+ };
+ };
+ };
+
+ usb@c5000000 {
+ status = "okay";
+ dr_mode = "otg";
+ };
+
+ usb@c5008000 {
+ status = "okay";
+ };
+
+ serial@70006000 {
+ status = "okay";
+ };
+
+ serial@70006300 {
+ status = "okay";
+ };
+
+ i2c_ddc: i2c@7000c400 {
+ status = "okay";
+ };
+
+ sdhci@c8000600 {
+ status = "okay";
+ bus-width = <4>;
+ vmmc-supply = <&vcc_sd_reg>;
+ vqmmc-supply = <&vcc_sd_reg>;
+ };
+
+ regulators {
+ regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "usb_host_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ gpio = <&gpio 178 0>;
+ };
+
+ vcc_sd_reg: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "vcc_sd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts
index 6a93d1404c76..54d6fce00a59 100644
--- a/arch/arm/boot/dts/tegra20-paz00.dts
+++ b/arch/arm/boot/dts/tegra20-paz00.dts
@@ -10,6 +10,18 @@
reg = <0x00000000 0x20000000>;
};
+ host1x {
+ hdmi {
+ status = "okay";
+
+ vdd-supply = <&hdmi_vdd_reg>;
+ pll-supply = <&hdmi_pll_reg>;
+
+ nvidia,ddc-i2c-bus = <&hdmi_ddc>;
+ nvidia,hpd-gpio = <&gpio 111 0>; /* PN7 */
+ };
+ };
+
pinmux {
pinctrl-names = "default";
pinctrl-0 = <&state_default>;
@@ -232,12 +244,10 @@
serial@70006000 {
status = "okay";
- clock-frequency = <216000000>;
};
serial@70006200 {
status = "okay";
- clock-frequency = <216000000>;
};
i2c@7000c000 {
@@ -252,9 +262,9 @@
};
};
- i2c@7000c400 {
+ hdmi_ddc: i2c@7000c400 {
status = "okay";
- clock-frequency = <400000>;
+ clock-frequency = <100000>;
};
nvec {
@@ -266,6 +276,8 @@
clock-frequency = <80000>;
request-gpios = <&gpio 170 0>; /* gpio PV2 */
slave-addr = <138>;
+ clocks = <&tegra_car 67>, <&tegra_car 124>;
+ clock-names = "div-clk", "fast-clk";
};
i2c@7000d000 {
@@ -367,13 +379,13 @@
regulator-max-microvolt = <1800000>;
};
- ldo7 {
+ hdmi_vdd_reg: ldo7 {
regulator-name = "+3.3vs_ldo7,avdd_hdmi";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
- ldo8 {
+ hdmi_pll_reg: ldo8 {
regulator-name = "+1.8vs_ldo8,avdd_hdmi_pll";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -418,6 +430,10 @@
status = "okay";
};
+ usb-phy@c5004400 {
+ nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
+ };
+
sdhci@c8000000 {
status = "okay";
cd-gpios = <&gpio 173 0>; /* gpio PV5 */
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index 420459825b46..37b3a57ec0f1 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -10,6 +10,18 @@
reg = <0x00000000 0x40000000>;
};
+ host1x {
+ hdmi {
+ status = "okay";
+
+ vdd-supply = <&hdmi_vdd_reg>;
+ pll-supply = <&hdmi_pll_reg>;
+
+ nvidia,ddc-i2c-bus = <&hdmi_ddc>;
+ nvidia,hpd-gpio = <&gpio 111 0>; /* PN7 */
+ };
+ };
+
pinmux {
pinctrl-names = "default";
pinctrl-0 = <&state_default>;
@@ -291,7 +303,6 @@
serial@70006300 {
status = "okay";
- clock-frequency = <216000000>;
};
i2c@7000c000 {
@@ -345,7 +356,7 @@
pinctrl-1 = <&state_i2cmux_pta>;
pinctrl-2 = <&state_i2cmux_idle>;
- i2c@0 {
+ hdmi_ddc: i2c@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
@@ -463,13 +474,13 @@
regulator-max-microvolt = <1800000>;
};
- ldo7 {
+ hdmi_vdd_reg: ldo7 {
regulator-name = "vdd_ldo7,avdd_hdmi,vdd_fuse";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
- ldo8 {
+ hdmi_pll_reg: ldo8 {
regulator-name = "vdd_ldo8,avdd_hdmi_pll";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -561,6 +572,10 @@
status = "okay";
};
+ usb-phy@c5004400 {
+ nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ };
+
sdhci@c8000000 {
status = "okay";
power-gpios = <&gpio 86 0>; /* gpio PK6 */
@@ -600,6 +615,145 @@
};
};
+ kbc {
+ status = "okay";
+ nvidia,debounce-delay-ms = <32>;
+ nvidia,repeat-delay-ms = <160>;
+ nvidia,ghost-filter;
+ nvidia,kbc-row-pins = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>;
+ nvidia,kbc-col-pins = <16 17 18 19 20 21 22 23>;
+ linux,keymap = <0x00020011 /* KEY_W */
+ 0x0003001F /* KEY_S */
+ 0x0004001E /* KEY_A */
+ 0x0005002C /* KEY_Z */
+ 0x000701d0 /* KEY_FN */
+
+ 0x0107007D /* KEY_LEFTMETA */
+ 0x02060064 /* KEY_RIGHTALT */
+ 0x02070038 /* KEY_LEFTALT */
+
+ 0x03000006 /* KEY_5 */
+ 0x03010005 /* KEY_4 */
+ 0x03020013 /* KEY_R */
+ 0x03030012 /* KEY_E */
+ 0x03040021 /* KEY_F */
+ 0x03050020 /* KEY_D */
+ 0x0306002D /* KEY_X */
+
+ 0x04000008 /* KEY_7 */
+ 0x04010007 /* KEY_6 */
+ 0x04020014 /* KEY_T */
+ 0x04030023 /* KEY_H */
+ 0x04040022 /* KEY_G */
+ 0x0405002F /* KEY_V */
+ 0x0406002E /* KEY_C */
+ 0x04070039 /* KEY_SPACE */
+
+ 0x0500000A /* KEY_9 */
+ 0x05010009 /* KEY_8 */
+ 0x05020016 /* KEY_U */
+ 0x05030015 /* KEY_Y */
+ 0x05040024 /* KEY_J */
+ 0x05050031 /* KEY_N */
+ 0x05060030 /* KEY_B */
+ 0x0507002B /* KEY_BACKSLASH */
+
+ 0x0600000C /* KEY_MINUS */
+ 0x0601000B /* KEY_0 */
+ 0x06020018 /* KEY_O */
+ 0x06030017 /* KEY_I */
+ 0x06040026 /* KEY_L */
+ 0x06050025 /* KEY_K */
+ 0x06060033 /* KEY_COMMA */
+ 0x06070032 /* KEY_M */
+
+ 0x0701000D /* KEY_EQUAL */
+ 0x0702001B /* KEY_RIGHTBRACE */
+ 0x0703001C /* KEY_ENTER */
+ 0x0707008B /* KEY_MENU */
+
+ 0x08040036 /* KEY_RIGHTSHIFT */
+ 0x0805002A /* KEY_LEFTSHIFT */
+
+ 0x09050061 /* KEY_RIGHTCTRL */
+ 0x0907001D /* KEY_LEFTCTRL */
+
+ 0x0B00001A /* KEY_LEFTBRACE */
+ 0x0B010019 /* KEY_P */
+ 0x0B020028 /* KEY_APOSTROPHE */
+ 0x0B030027 /* KEY_SEMICOLON */
+ 0x0B040035 /* KEY_SLASH */
+ 0x0B050034 /* KEY_DOT */
+
+ 0x0C000044 /* KEY_F10 */
+ 0x0C010043 /* KEY_F9 */
+ 0x0C02000E /* KEY_BACKSPACE */
+ 0x0C030004 /* KEY_3 */
+ 0x0C040003 /* KEY_2 */
+ 0x0C050067 /* KEY_UP */
+ 0x0C0600D2 /* KEY_PRINT */
+ 0x0C070077 /* KEY_PAUSE */
+
+ 0x0D00006E /* KEY_INSERT */
+ 0x0D01006F /* KEY_DELETE */
+ 0x0D030068 /* KEY_PAGEUP */
+ 0x0D04006D /* KEY_PAGEDOWN */
+ 0x0D05006A /* KEY_RIGHT */
+ 0x0D06006C /* KEY_DOWN */
+ 0x0D070069 /* KEY_LEFT */
+
+ 0x0E000057 /* KEY_F11 */
+ 0x0E010058 /* KEY_F12 */
+ 0x0E020042 /* KEY_F8 */
+ 0x0E030010 /* KEY_Q */
+ 0x0E04003E /* KEY_F4 */
+ 0x0E05003D /* KEY_F3 */
+ 0x0E060002 /* KEY_1 */
+ 0x0E070041 /* KEY_F7 */
+
+ 0x0F000001 /* KEY_ESC */
+ 0x0F010029 /* KEY_GRAVE */
+ 0x0F02003F /* KEY_F5 */
+ 0x0F03000F /* KEY_TAB */
+ 0x0F04003B /* KEY_F1 */
+ 0x0F05003C /* KEY_F2 */
+ 0x0F06003A /* KEY_CAPSLOCK */
+ 0x0F070040 /* KEY_F6 */
+
+ /* Software Handled Function Keys */
+ 0x14000047 /* KEY_KP7 */
+
+ 0x15000049 /* KEY_KP9 */
+ 0x15010048 /* KEY_KP8 */
+ 0x1502004B /* KEY_KP4 */
+ 0x1504004F /* KEY_KP1 */
+
+ 0x1601004E /* KEY_KPSLASH */
+ 0x1602004D /* KEY_KP6 */
+ 0x1603004C /* KEY_KP5 */
+ 0x16040051 /* KEY_KP3 */
+ 0x16050050 /* KEY_KP2 */
+ 0x16070052 /* KEY_KP0 */
+
+ 0x1B010037 /* KEY_KPASTERISK */
+ 0x1B03004A /* KEY_KPMINUS */
+ 0x1B04004E /* KEY_KPPLUS */
+ 0x1B050053 /* KEY_KPDOT */
+
+ 0x1C050073 /* KEY_VOLUMEUP */
+
+ 0x1D030066 /* KEY_HOME */
+ 0x1D04006B /* KEY_END */
+ 0x1D0500E0 /* KEY_BRIGHTNESSDOWN */
+ 0x1D060072 /* KEY_VOLUMEDOWN */
+ 0x1D0700E1 /* KEY_BRIGHTNESSUP */
+
+ 0x1E000045 /* KEY_NUMLOCK */
+ 0x1E010046 /* KEY_SCROLLLOCK */
+ 0x1E020071 /* KEY_MUTE */
+
+ 0x1F04008A>; /* KEY_HELP */
+ };
regulators {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi
index a239ccdfaa52..4766abae7a72 100644
--- a/arch/arm/boot/dts/tegra20-tamonten.dtsi
+++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi
@@ -276,7 +276,6 @@
};
serial@70006300 {
- clock-frequency = <216000000>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts
index b70b4cb754c8..5d79e4fc49a6 100644
--- a/arch/arm/boot/dts/tegra20-trimslice.dts
+++ b/arch/arm/boot/dts/tegra20-trimslice.dts
@@ -249,6 +249,11 @@
"ld23_22";
nvidia,pull = <1>;
};
+ conf_spif {
+ nvidia,pins = "spif";
+ nvidia,pull = <1>;
+ nvidia,tristate = <0>;
+ };
};
};
@@ -258,7 +263,6 @@
serial@70006000 {
status = "okay";
- clock-frequency = <216000000>;
};
dvi_ddc: i2c@7000c000 {
@@ -310,6 +314,10 @@
status = "okay";
};
+ usb-phy@c5004400 {
+ nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
+ };
+
sdhci@c8000000 {
status = "okay";
bus-width = <4>;
@@ -322,6 +330,11 @@
bus-width = <4>;
};
+ poweroff {
+ compatible = "gpio-poweroff";
+ gpios = <&gpio 191 1>; /* gpio PX7, active low */
+ };
+
regulators {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
index adc47547eaae..425c89000c20 100644
--- a/arch/arm/boot/dts/tegra20-ventana.dts
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -3,13 +3,25 @@
/include/ "tegra20.dtsi"
/ {
- model = "NVIDIA Tegra2 Ventana evaluation board";
+ model = "NVIDIA Tegra20 Ventana evaluation board";
compatible = "nvidia,ventana", "nvidia,tegra20";
memory {
reg = <0x00000000 0x40000000>;
};
+ host1x {
+ hdmi {
+ status = "okay";
+
+ vdd-supply = <&hdmi_vdd_reg>;
+ pll-supply = <&hdmi_pll_reg>;
+
+ nvidia,ddc-i2c-bus = <&hdmi_ddc>;
+ nvidia,hpd-gpio = <&gpio 111 0>; /* PN7 */
+ };
+ };
+
pinmux {
pinctrl-names = "default";
pinctrl-0 = <&state_default>;
@@ -288,7 +300,6 @@
serial@70006300 {
status = "okay";
- clock-frequency = <216000000>;
};
i2c@7000c000 {
@@ -320,7 +331,7 @@
i2c@7000c400 {
status = "okay";
- clock-frequency = <400000>;
+ clock-frequency = <100000>;
};
i2cmux {
@@ -335,7 +346,7 @@
pinctrl-1 = <&state_i2cmux_pta>;
pinctrl-2 = <&state_i2cmux_idle>;
- i2c@0 {
+ hdmi_ddc: i2c@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
@@ -446,13 +457,13 @@
regulator-max-microvolt = <1800000>;
};
- ldo7 {
+ hdmi_vdd_reg: ldo7 {
regulator-name = "vdd_ldo7,avdd_hdmi,vdd_fuse";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
- ldo8 {
+ hdmi_pll_reg: ldo8 {
regulator-name = "vdd_ldo8,avdd_hdmi_pll";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -497,6 +508,10 @@
status = "okay";
};
+ usb-phy@c5004400 {
+ nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+ };
+
sdhci@c8000000 {
status = "okay";
power-gpios = <&gpio 86 0>; /* gpio PK6 */
diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts
index 20d576ecd555..ea57c0f6dcce 100644
--- a/arch/arm/boot/dts/tegra20-whistler.dts
+++ b/arch/arm/boot/dts/tegra20-whistler.dts
@@ -3,7 +3,7 @@
/include/ "tegra20.dtsi"
/ {
- model = "NVIDIA Tegra2 Whistler evaluation board";
+ model = "NVIDIA Tegra20 Whistler evaluation board";
compatible = "nvidia,whistler", "nvidia,tegra20";
memory {
@@ -255,7 +255,6 @@
serial@70006000 {
status = "okay";
- clock-frequency = <216000000>;
};
hdmi_ddc: i2c@7000c400 {
@@ -520,6 +519,18 @@
bus-width = <8>;
};
+ kbc {
+ status = "okay";
+ nvidia,debounce-delay-ms = <20>;
+ nvidia,repeat-delay-ms = <160>;
+ nvidia,kbc-row-pins = <0 1 2>;
+ nvidia,kbc-col-pins = <16 17>;
+ linux,keymap = <0x00000074 /* KEY_POWER */
+ 0x01000066 /* KEY_HOME */
+ 0x0101009E /* KEY_BACK */
+ 0x0201008B>; /* KEY_MENU */
+ };
+
regulators {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index b8effa1cbda7..9a428931d042 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -4,11 +4,20 @@
compatible = "nvidia,tegra20";
interrupt-parent = <&intc>;
+ aliases {
+ serial0 = &uarta;
+ serial1 = &uartb;
+ serial2 = &uartc;
+ serial3 = &uartd;
+ serial4 = &uarte;
+ };
+
host1x {
compatible = "nvidia,tegra20-host1x", "simple-bus";
reg = <0x50000000 0x00024000>;
interrupts = <0 65 0x04 /* mpcore syncpt */
0 67 0x04>; /* mpcore general */
+ clocks = <&tegra_car 28>;
#address-cells = <1>;
#size-cells = <1>;
@@ -19,41 +28,49 @@
compatible = "nvidia,tegra20-mpe";
reg = <0x54040000 0x00040000>;
interrupts = <0 68 0x04>;
+ clocks = <&tegra_car 60>;
};
vi {
compatible = "nvidia,tegra20-vi";
reg = <0x54080000 0x00040000>;
interrupts = <0 69 0x04>;
+ clocks = <&tegra_car 100>;
};
epp {
compatible = "nvidia,tegra20-epp";
reg = <0x540c0000 0x00040000>;
interrupts = <0 70 0x04>;
+ clocks = <&tegra_car 19>;
};
isp {
compatible = "nvidia,tegra20-isp";
reg = <0x54100000 0x00040000>;
interrupts = <0 71 0x04>;
+ clocks = <&tegra_car 23>;
};
gr2d {
compatible = "nvidia,tegra20-gr2d";
reg = <0x54140000 0x00040000>;
interrupts = <0 72 0x04>;
+ clocks = <&tegra_car 21>;
};
gr3d {
compatible = "nvidia,tegra20-gr3d";
reg = <0x54180000 0x00040000>;
+ clocks = <&tegra_car 24>;
};
dc@54200000 {
compatible = "nvidia,tegra20-dc";
reg = <0x54200000 0x00040000>;
interrupts = <0 73 0x04>;
+ clocks = <&tegra_car 27>, <&tegra_car 121>;
+ clock-names = "disp1", "parent";
rgb {
status = "disabled";
@@ -64,6 +81,8 @@
compatible = "nvidia,tegra20-dc";
reg = <0x54240000 0x00040000>;
interrupts = <0 74 0x04>;
+ clocks = <&tegra_car 26>, <&tegra_car 121>;
+ clock-names = "disp2", "parent";
rgb {
status = "disabled";
@@ -74,6 +93,8 @@
compatible = "nvidia,tegra20-hdmi";
reg = <0x54280000 0x00040000>;
interrupts = <0 75 0x04>;
+ clocks = <&tegra_car 51>, <&tegra_car 117>;
+ clock-names = "hdmi", "parent";
status = "disabled";
};
@@ -81,12 +102,14 @@
compatible = "nvidia,tegra20-tvo";
reg = <0x542c0000 0x00040000>;
interrupts = <0 76 0x04>;
+ clocks = <&tegra_car 102>;
status = "disabled";
};
dsi {
compatible = "nvidia,tegra20-dsi";
reg = <0x54300000 0x00040000>;
+ clocks = <&tegra_car 48>;
status = "disabled";
};
};
@@ -97,15 +120,6 @@
interrupts = <1 13 0x304>;
};
- cache-controller@50043000 {
- compatible = "arm,pl310-cache";
- reg = <0x50043000 0x1000>;
- arm,data-latency = <5 5 2>;
- arm,tag-latency = <4 4 2>;
- cache-unified;
- cache-level = <2>;
- };
-
intc: interrupt-controller {
compatible = "arm,cortex-a9-gic";
reg = <0x50041000 0x1000
@@ -114,6 +128,15 @@
#interrupt-cells = <3>;
};
+ cache-controller {
+ compatible = "arm,pl310-cache";
+ reg = <0x50043000 0x1000>;
+ arm,data-latency = <5 5 2>;
+ arm,tag-latency = <4 4 2>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
timer@60005000 {
compatible = "nvidia,tegra20-timer";
reg = <0x60005000 0x60>;
@@ -123,6 +146,12 @@
0 42 0x04>;
};
+ tegra_car: clock {
+ compatible = "nvidia,tegra20-car";
+ reg = <0x60006000 0x1000>;
+ #clock-cells = <1>;
+ };
+
apbdma: dma {
compatible = "nvidia,tegra20-apbdma";
reg = <0x6000a000 0x1200>;
@@ -142,6 +171,7 @@
0 117 0x04
0 118 0x04
0 119 0x04>;
+ clocks = <&tegra_car 34>;
};
ahb {
@@ -177,12 +207,22 @@
compatible = "nvidia,tegra20-das";
reg = <0x70000c00 0x80>;
};
+
+ tegra_ac97: ac97 {
+ compatible = "nvidia,tegra20-ac97";
+ reg = <0x70002000 0x200>;
+ interrupts = <0 81 0x04>;
+ nvidia,dma-request-selector = <&apbdma 12>;
+ clocks = <&tegra_car 3>;
+ status = "disabled";
+ };
tegra_i2s1: i2s@70002800 {
compatible = "nvidia,tegra20-i2s";
reg = <0x70002800 0x200>;
interrupts = <0 13 0x04>;
nvidia,dma-request-selector = <&apbdma 2>;
+ clocks = <&tegra_car 11>;
status = "disabled";
};
@@ -191,46 +231,64 @@
reg = <0x70002a00 0x200>;
interrupts = <0 3 0x04>;
nvidia,dma-request-selector = <&apbdma 1>;
+ clocks = <&tegra_car 18>;
status = "disabled";
};
- serial@70006000 {
+ /*
+ * There are two serial driver i.e. 8250 based simple serial
+ * driver and APB DMA based serial driver for higher baudrate
+ * and performace. To enable the 8250 based driver, the compatible
+ * is "nvidia,tegra20-uart" and to enable the APB DMA based serial
+ * driver, the comptible is "nvidia,tegra20-hsuart".
+ */
+ uarta: serial@70006000 {
compatible = "nvidia,tegra20-uart";
reg = <0x70006000 0x40>;
reg-shift = <2>;
interrupts = <0 36 0x04>;
+ nvidia,dma-request-selector = <&apbdma 8>;
+ clocks = <&tegra_car 6>;
status = "disabled";
};
- serial@70006040 {
+ uartb: serial@70006040 {
compatible = "nvidia,tegra20-uart";
reg = <0x70006040 0x40>;
reg-shift = <2>;
interrupts = <0 37 0x04>;
+ nvidia,dma-request-selector = <&apbdma 9>;
+ clocks = <&tegra_car 96>;
status = "disabled";
};
- serial@70006200 {
+ uartc: serial@70006200 {
compatible = "nvidia,tegra20-uart";
reg = <0x70006200 0x100>;
reg-shift = <2>;
interrupts = <0 46 0x04>;
+ nvidia,dma-request-selector = <&apbdma 10>;
+ clocks = <&tegra_car 55>;
status = "disabled";
};
- serial@70006300 {
+ uartd: serial@70006300 {
compatible = "nvidia,tegra20-uart";
reg = <0x70006300 0x100>;
reg-shift = <2>;
interrupts = <0 90 0x04>;
+ nvidia,dma-request-selector = <&apbdma 19>;
+ clocks = <&tegra_car 65>;
status = "disabled";
};
- serial@70006400 {
+ uarte: serial@70006400 {
compatible = "nvidia,tegra20-uart";
reg = <0x70006400 0x100>;
reg-shift = <2>;
interrupts = <0 91 0x04>;
+ nvidia,dma-request-selector = <&apbdma 20>;
+ clocks = <&tegra_car 66>;
status = "disabled";
};
@@ -238,6 +296,7 @@
compatible = "nvidia,tegra20-pwm";
reg = <0x7000a000 0x100>;
#pwm-cells = <2>;
+ clocks = <&tegra_car 17>;
};
rtc {
@@ -252,6 +311,8 @@
interrupts = <0 38 0x04>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 12>, <&tegra_car 124>;
+ clock-names = "div-clk", "fast-clk";
status = "disabled";
};
@@ -262,6 +323,7 @@
nvidia,dma-request-selector = <&apbdma 11>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 43>;
status = "disabled";
};
@@ -271,6 +333,8 @@
interrupts = <0 84 0x04>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 54>, <&tegra_car 124>;
+ clock-names = "div-clk", "fast-clk";
status = "disabled";
};
@@ -280,6 +344,8 @@
interrupts = <0 92 0x04>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 67>, <&tegra_car 124>;
+ clock-names = "div-clk", "fast-clk";
status = "disabled";
};
@@ -289,6 +355,8 @@
interrupts = <0 53 0x04>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 47>, <&tegra_car 124>;
+ clock-names = "div-clk", "fast-clk";
status = "disabled";
};
@@ -299,6 +367,7 @@
nvidia,dma-request-selector = <&apbdma 15>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 41>;
status = "disabled";
};
@@ -309,6 +378,7 @@
nvidia,dma-request-selector = <&apbdma 16>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 44>;
status = "disabled";
};
@@ -319,6 +389,7 @@
nvidia,dma-request-selector = <&apbdma 17>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 46>;
status = "disabled";
};
@@ -329,6 +400,15 @@
nvidia,dma-request-selector = <&apbdma 18>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 68>;
+ status = "disabled";
+ };
+
+ kbc {
+ compatible = "nvidia,tegra20-kbc";
+ reg = <0x7000e200 0x100>;
+ interrupts = <0 85 0x04>;
+ clocks = <&tegra_car 36>;
status = "disabled";
};
@@ -344,7 +424,7 @@
interrupts = <0 77 0x04>;
};
- gart {
+ iommu {
compatible = "nvidia,tegra20-gart";
reg = <0x7000f024 0x00000018 /* controller registers */
0x58000000 0x02000000>; /* GART aperture */
@@ -357,12 +437,40 @@
#size-cells = <0>;
};
+ phy1: usb-phy@c5000400 {
+ compatible = "nvidia,tegra20-usb-phy";
+ reg = <0xc5000400 0x3c00>;
+ phy_type = "utmi";
+ nvidia,has-legacy-mode;
+ clocks = <&tegra_car 22>, <&tegra_car 127>;
+ clock-names = "phy", "pll_u";
+ };
+
+ phy2: usb-phy@c5004400 {
+ compatible = "nvidia,tegra20-usb-phy";
+ reg = <0xc5004400 0x3c00>;
+ phy_type = "ulpi";
+ clocks = <&tegra_car 94>, <&tegra_car 127>;
+ clock-names = "phy", "pll_u";
+ };
+
+ phy3: usb-phy@c5008400 {
+ compatible = "nvidia,tegra20-usb-phy";
+ reg = <0xc5008400 0x3C00>;
+ phy_type = "utmi";
+ clocks = <&tegra_car 22>, <&tegra_car 127>;
+ clock-names = "phy", "pll_u";
+ };
+
usb@c5000000 {
compatible = "nvidia,tegra20-ehci", "usb-ehci";
reg = <0xc5000000 0x4000>;
interrupts = <0 20 0x04>;
phy_type = "utmi";
nvidia,has-legacy-mode;
+ clocks = <&tegra_car 22>;
+ nvidia,needs-double-reset;
+ nvidia,phy = <&phy1>;
status = "disabled";
};
@@ -371,6 +479,8 @@
reg = <0xc5004000 0x4000>;
interrupts = <0 21 0x04>;
phy_type = "ulpi";
+ clocks = <&tegra_car 58>;
+ nvidia,phy = <&phy2>;
status = "disabled";
};
@@ -379,6 +489,8 @@
reg = <0xc5008000 0x4000>;
interrupts = <0 97 0x04>;
phy_type = "utmi";
+ clocks = <&tegra_car 59>;
+ nvidia,phy = <&phy3>;
status = "disabled";
};
@@ -386,6 +498,7 @@
compatible = "nvidia,tegra20-sdhci";
reg = <0xc8000000 0x200>;
interrupts = <0 14 0x04>;
+ clocks = <&tegra_car 14>;
status = "disabled";
};
@@ -393,6 +506,7 @@
compatible = "nvidia,tegra20-sdhci";
reg = <0xc8000200 0x200>;
interrupts = <0 15 0x04>;
+ clocks = <&tegra_car 9>;
status = "disabled";
};
@@ -400,6 +514,7 @@
compatible = "nvidia,tegra20-sdhci";
reg = <0xc8000400 0x200>;
interrupts = <0 19 0x04>;
+ clocks = <&tegra_car 69>;
status = "disabled";
};
@@ -407,9 +522,27 @@
compatible = "nvidia,tegra20-sdhci";
reg = <0xc8000600 0x200>;
interrupts = <0 31 0x04>;
+ clocks = <&tegra_car 15>;
status = "disabled";
};
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ };
+ };
+
pmu {
compatible = "arm,cortex-a9-pmu";
interrupts = <0 56 0x04
diff --git a/arch/arm/boot/dts/tegra30-beaver.dts b/arch/arm/boot/dts/tegra30-beaver.dts
new file mode 100644
index 000000000000..8ff2ff20e4a3
--- /dev/null
+++ b/arch/arm/boot/dts/tegra30-beaver.dts
@@ -0,0 +1,373 @@
+/dts-v1/;
+
+/include/ "tegra30.dtsi"
+
+/ {
+ model = "NVIDIA Tegra30 Beaver evaluation board";
+ compatible = "nvidia,beaver", "nvidia,tegra30";
+
+ memory {
+ reg = <0x80000000 0x80000000>;
+ };
+
+ pinmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ sdmmc1_clk_pz0 {
+ nvidia,pins = "sdmmc1_clk_pz0";
+ nvidia,function = "sdmmc1";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ sdmmc1_cmd_pz1 {
+ nvidia,pins = "sdmmc1_cmd_pz1",
+ "sdmmc1_dat0_py7",
+ "sdmmc1_dat1_py6",
+ "sdmmc1_dat2_py5",
+ "sdmmc1_dat3_py4";
+ nvidia,function = "sdmmc1";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ sdmmc3_clk_pa6 {
+ nvidia,pins = "sdmmc3_clk_pa6";
+ nvidia,function = "sdmmc3";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ sdmmc3_cmd_pa7 {
+ nvidia,pins = "sdmmc3_cmd_pa7",
+ "sdmmc3_dat0_pb7",
+ "sdmmc3_dat1_pb6",
+ "sdmmc3_dat2_pb5",
+ "sdmmc3_dat3_pb4";
+ nvidia,function = "sdmmc3";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ sdmmc4_clk_pcc4 {
+ nvidia,pins = "sdmmc4_clk_pcc4",
+ "sdmmc4_rst_n_pcc3";
+ nvidia,function = "sdmmc4";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ sdmmc4_dat0_paa0 {
+ nvidia,pins = "sdmmc4_dat0_paa0",
+ "sdmmc4_dat1_paa1",
+ "sdmmc4_dat2_paa2",
+ "sdmmc4_dat3_paa3",
+ "sdmmc4_dat4_paa4",
+ "sdmmc4_dat5_paa5",
+ "sdmmc4_dat6_paa6",
+ "sdmmc4_dat7_paa7";
+ nvidia,function = "sdmmc4";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ dap2_fs_pa2 {
+ nvidia,pins = "dap2_fs_pa2",
+ "dap2_sclk_pa3",
+ "dap2_din_pa4",
+ "dap2_dout_pa5";
+ nvidia,function = "i2s1";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ sdio3 {
+ nvidia,pins = "drive_sdio3";
+ nvidia,high-speed-mode = <0>;
+ nvidia,schmitt = <0>;
+ nvidia,pull-down-strength = <46>;
+ nvidia,pull-up-strength = <42>;
+ nvidia,slew-rate-rising = <1>;
+ nvidia,slew-rate-falling = <1>;
+ };
+ };
+ };
+
+ serial@70006000 {
+ status = "okay";
+ };
+
+ i2c@7000c000 {
+ status = "okay";
+ clock-frequency = <100000>;
+ };
+
+ i2c@7000c400 {
+ status = "okay";
+ clock-frequency = <100000>;
+ };
+
+ i2c@7000c500 {
+ status = "okay";
+ clock-frequency = <100000>;
+ };
+
+ i2c@7000c700 {
+ status = "okay";
+ clock-frequency = <100000>;
+ };
+
+ i2c@7000d000 {
+ status = "okay";
+ clock-frequency = <100000>;
+
+ tps62361 {
+ compatible = "ti,tps62361";
+ reg = <0x60>;
+
+ regulator-name = "tps62361-vout";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-boot-on;
+ regulator-always-on;
+ ti,vsel0-state-high;
+ ti,vsel1-state-high;
+ };
+
+ pmic: tps65911@2d {
+ compatible = "ti,tps65911";
+ reg = <0x2d>;
+
+ interrupts = <0 86 0x4>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+
+ ti,system-power-controller;
+
+ #gpio-cells = <2>;
+ gpio-controller;
+
+ vcc1-supply = <&vdd_5v_in_reg>;
+ vcc2-supply = <&vdd_5v_in_reg>;
+ vcc3-supply = <&vio_reg>;
+ vcc4-supply = <&vdd_5v_in_reg>;
+ vcc5-supply = <&vdd_5v_in_reg>;
+ vcc6-supply = <&vdd2_reg>;
+ vcc7-supply = <&vdd_5v_in_reg>;
+ vccio-supply = <&vdd_5v_in_reg>;
+
+ regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vdd1_reg: vdd1 {
+ regulator-name = "vddio_ddr_1v2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ vdd2_reg: vdd2 {
+ regulator-name = "vdd_1v5_gen";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ };
+
+ vddctrl_reg: vddctrl {
+ regulator-name = "vdd_cpu,vdd_sys";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ vio_reg: vio {
+ regulator-name = "vdd_1v8_gen";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo1_reg: ldo1 {
+ regulator-name = "vdd_pexa,vdd_pexb";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ ldo2_reg: ldo2 {
+ regulator-name = "vdd_sata,avdd_plle";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ };
+
+ /* LDO3 is not connected to anything */
+
+ ldo4_reg: ldo4 {
+ regulator-name = "vdd_rtc";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ ldo5_reg: ldo5 {
+ regulator-name = "vddio_sdmmc,avdd_vdac";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ ldo6_reg: ldo6 {
+ regulator-name = "avdd_dsi_csi,pwrdet_mipi";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ ldo7_reg: ldo7 {
+ regulator-name = "vdd_pllm,x,u,a_p_c_s";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ ldo8_reg: ldo8 {
+ regulator-name = "vdd_ddr_hs";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+ };
+ };
+ };
+
+ spi@7000da00 {
+ status = "okay";
+ spi-max-frequency = <25000000>;
+ spi-flash@1 {
+ compatible = "winbond,w25q32";
+ reg = <1>;
+ spi-max-frequency = <20000000>;
+ };
+ };
+
+ ahub {
+ i2s@70080400 {
+ status = "okay";
+ };
+ };
+
+ pmc {
+ status = "okay";
+ nvidia,invert-interrupt;
+ };
+
+ sdhci@78000000 {
+ status = "okay";
+ cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+ wp-gpios = <&gpio 155 0>; /* gpio PT3 */
+ power-gpios = <&gpio 31 0>; /* gpio PD7 */
+ bus-width = <4>;
+ };
+
+ sdhci@78000600 {
+ status = "okay";
+ bus-width = <8>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vdd_5v_in_reg: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "vdd_5v_in";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+
+ chargepump_5v_reg: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "chargepump_5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ enable-active-high;
+ gpio = <&pmic 0 0>; /* PMIC TPS65911 GPIO0 */
+ };
+
+ ddr_reg: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "vdd_ddr";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ enable-active-high;
+ gpio = <&pmic 7 0>; /* PMIC TPS65911 GPIO7 */
+ vin-supply = <&vdd_5v_in_reg>;
+ };
+
+ vdd_5v_sata_reg: regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ regulator-name = "vdd_5v_sata";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ enable-active-high;
+ gpio = <&gpio 30 0>; /* gpio PD6 */
+ vin-supply = <&vdd_5v_in_reg>;
+ };
+
+ usb1_vbus_reg: regulator@4 {
+ compatible = "regulator-fixed";
+ reg = <4>;
+ regulator-name = "usb1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ gpio = <&gpio 68 0>; /* GPIO PI4 */
+ gpio-open-drain;
+ vin-supply = <&vdd_5v_in_reg>;
+ };
+
+ usb3_vbus_reg: regulator@5 {
+ compatible = "regulator-fixed";
+ reg = <5>;
+ regulator-name = "usb3_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ gpio = <&gpio 63 0>; /* GPIO PH7 */
+ gpio-open-drain;
+ vin-supply = <&vdd_5v_in_reg>;
+ };
+
+ sys_3v3_reg: regulator@6 {
+ compatible = "regulator-fixed";
+ reg = <6>;
+ regulator-name = "sys_3v3,vdd_3v3_alw";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ enable-active-high;
+ gpio = <&pmic 6 0>; /* PMIC TPS65911 GPIO6 */
+ vin-supply = <&vdd_5v_in_reg>;
+ };
+
+ sys_3v3_pexs_reg: regulator@7 {
+ compatible = "regulator-fixed";
+ reg = <7>;
+ regulator-name = "sys_3v3_pexs";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ enable-active-high;
+ gpio = <&gpio 95 0>; /* gpio PL7 */
+ vin-supply = <&sys_3v3_reg>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi
index bdb2a660f376..17499272a4ef 100644
--- a/arch/arm/boot/dts/tegra30-cardhu.dtsi
+++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi
@@ -106,12 +106,25 @@
nvidia,slew-rate-rising = <1>;
nvidia,slew-rate-falling = <1>;
};
+ uart3_txd_pw6 {
+ nvidia,pins = "uart3_txd_pw6",
+ "uart3_cts_n_pa1",
+ "uart3_rts_n_pc0",
+ "uart3_rxd_pw7";
+ nvidia,function = "uartc";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
};
};
serial@70006000 {
status = "okay";
- clock-frequency = <408000000>;
+ };
+
+ serial@70006200 {
+ compatible = "nvidia,tegra30-hsuart";
+ status = "okay";
};
i2c@7000c000 {
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index 529fdb82dfdb..767803e1fd55 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -4,11 +4,20 @@
compatible = "nvidia,tegra30";
interrupt-parent = <&intc>;
+ aliases {
+ serial0 = &uarta;
+ serial1 = &uartb;
+ serial2 = &uartc;
+ serial3 = &uartd;
+ serial4 = &uarte;
+ };
+
host1x {
compatible = "nvidia,tegra30-host1x", "simple-bus";
reg = <0x50000000 0x00024000>;
interrupts = <0 65 0x04 /* mpcore syncpt */
0 67 0x04>; /* mpcore general */
+ clocks = <&tegra_car 28>;
#address-cells = <1>;
#size-cells = <1>;
@@ -19,41 +28,50 @@
compatible = "nvidia,tegra30-mpe";
reg = <0x54040000 0x00040000>;
interrupts = <0 68 0x04>;
+ clocks = <&tegra_car 60>;
};
vi {
compatible = "nvidia,tegra30-vi";
reg = <0x54080000 0x00040000>;
interrupts = <0 69 0x04>;
+ clocks = <&tegra_car 164>;
};
epp {
compatible = "nvidia,tegra30-epp";
reg = <0x540c0000 0x00040000>;
interrupts = <0 70 0x04>;
+ clocks = <&tegra_car 19>;
};
isp {
compatible = "nvidia,tegra30-isp";
reg = <0x54100000 0x00040000>;
interrupts = <0 71 0x04>;
+ clocks = <&tegra_car 23>;
};
gr2d {
compatible = "nvidia,tegra30-gr2d";
reg = <0x54140000 0x00040000>;
interrupts = <0 72 0x04>;
+ clocks = <&tegra_car 21>;
};
gr3d {
compatible = "nvidia,tegra30-gr3d";
reg = <0x54180000 0x00040000>;
+ clocks = <&tegra_car 24 &tegra_car 98>;
+ clock-names = "3d", "3d2";
};
dc@54200000 {
compatible = "nvidia,tegra30-dc";
reg = <0x54200000 0x00040000>;
interrupts = <0 73 0x04>;
+ clocks = <&tegra_car 27>, <&tegra_car 179>;
+ clock-names = "disp1", "parent";
rgb {
status = "disabled";
@@ -64,6 +82,8 @@
compatible = "nvidia,tegra30-dc";
reg = <0x54240000 0x00040000>;
interrupts = <0 74 0x04>;
+ clocks = <&tegra_car 26>, <&tegra_car 179>;
+ clock-names = "disp2", "parent";
rgb {
status = "disabled";
@@ -74,6 +94,8 @@
compatible = "nvidia,tegra30-hdmi";
reg = <0x54280000 0x00040000>;
interrupts = <0 75 0x04>;
+ clocks = <&tegra_car 51>, <&tegra_car 189>;
+ clock-names = "hdmi", "parent";
status = "disabled";
};
@@ -81,12 +103,14 @@
compatible = "nvidia,tegra30-tvo";
reg = <0x542c0000 0x00040000>;
interrupts = <0 76 0x04>;
+ clocks = <&tegra_car 169>;
status = "disabled";
};
dsi {
compatible = "nvidia,tegra30-dsi";
reg = <0x54300000 0x00040000>;
+ clocks = <&tegra_car 48>;
status = "disabled";
};
};
@@ -97,15 +121,6 @@
interrupts = <1 13 0xf04>;
};
- cache-controller@50043000 {
- compatible = "arm,pl310-cache";
- reg = <0x50043000 0x1000>;
- arm,data-latency = <6 6 2>;
- arm,tag-latency = <5 5 2>;
- cache-unified;
- cache-level = <2>;
- };
-
intc: interrupt-controller {
compatible = "arm,cortex-a9-gic";
reg = <0x50041000 0x1000
@@ -114,6 +129,15 @@
#interrupt-cells = <3>;
};
+ cache-controller {
+ compatible = "arm,pl310-cache";
+ reg = <0x50043000 0x1000>;
+ arm,data-latency = <6 6 2>;
+ arm,tag-latency = <5 5 2>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
timer@60005000 {
compatible = "nvidia,tegra30-timer", "nvidia,tegra20-timer";
reg = <0x60005000 0x400>;
@@ -125,6 +149,12 @@
0 122 0x04>;
};
+ tegra_car: clock {
+ compatible = "nvidia,tegra30-car";
+ reg = <0x60006000 0x1000>;
+ #clock-cells = <1>;
+ };
+
apbdma: dma {
compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma";
reg = <0x6000a000 0x1400>;
@@ -160,6 +190,7 @@
0 141 0x04
0 142 0x04
0 143 0x04>;
+ clocks = <&tegra_car 34>;
};
ahb: ahb {
@@ -168,7 +199,7 @@
};
gpio: gpio {
- compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio";
+ compatible = "nvidia,tegra30-gpio";
reg = <0x6000d000 0x1000>;
interrupts = <0 32 0x04
0 33 0x04
@@ -190,43 +221,61 @@
0x70003000 0x3e4>; /* Mux registers */
};
- serial@70006000 {
+ /*
+ * There are two serial driver i.e. 8250 based simple serial
+ * driver and APB DMA based serial driver for higher baudrate
+ * and performace. To enable the 8250 based driver, the compatible
+ * is "nvidia,tegra30-uart", "nvidia,tegra20-uart" and to enable
+ * the APB DMA based serial driver, the comptible is
+ * "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart".
+ */
+ uarta: serial@70006000 {
compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart";
reg = <0x70006000 0x40>;
reg-shift = <2>;
interrupts = <0 36 0x04>;
+ nvidia,dma-request-selector = <&apbdma 8>;
+ clocks = <&tegra_car 6>;
status = "disabled";
};
- serial@70006040 {
+ uartb: serial@70006040 {
compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart";
reg = <0x70006040 0x40>;
reg-shift = <2>;
interrupts = <0 37 0x04>;
+ nvidia,dma-request-selector = <&apbdma 9>;
+ clocks = <&tegra_car 160>;
status = "disabled";
};
- serial@70006200 {
+ uartc: serial@70006200 {
compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart";
reg = <0x70006200 0x100>;
reg-shift = <2>;
interrupts = <0 46 0x04>;
+ nvidia,dma-request-selector = <&apbdma 10>;
+ clocks = <&tegra_car 55>;
status = "disabled";
};
- serial@70006300 {
+ uartd: serial@70006300 {
compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart";
reg = <0x70006300 0x100>;
reg-shift = <2>;
interrupts = <0 90 0x04>;
+ nvidia,dma-request-selector = <&apbdma 19>;
+ clocks = <&tegra_car 65>;
status = "disabled";
};
- serial@70006400 {
+ uarte: serial@70006400 {
compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart";
reg = <0x70006400 0x100>;
reg-shift = <2>;
interrupts = <0 91 0x04>;
+ nvidia,dma-request-selector = <&apbdma 20>;
+ clocks = <&tegra_car 66>;
status = "disabled";
};
@@ -234,6 +283,7 @@
compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";
reg = <0x7000a000 0x100>;
#pwm-cells = <2>;
+ clocks = <&tegra_car 17>;
};
rtc {
@@ -248,6 +298,8 @@
interrupts = <0 38 0x04>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 12>, <&tegra_car 182>;
+ clock-names = "div-clk", "fast-clk";
status = "disabled";
};
@@ -257,6 +309,8 @@
interrupts = <0 84 0x04>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 54>, <&tegra_car 182>;
+ clock-names = "div-clk", "fast-clk";
status = "disabled";
};
@@ -266,6 +320,8 @@
interrupts = <0 92 0x04>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 67>, <&tegra_car 182>;
+ clock-names = "div-clk", "fast-clk";
status = "disabled";
};
@@ -275,6 +331,8 @@
interrupts = <0 120 0x04>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 103>, <&tegra_car 182>;
+ clock-names = "div-clk", "fast-clk";
status = "disabled";
};
@@ -284,6 +342,8 @@
interrupts = <0 53 0x04>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 47>, <&tegra_car 182>;
+ clock-names = "div-clk", "fast-clk";
status = "disabled";
};
@@ -294,6 +354,7 @@
nvidia,dma-request-selector = <&apbdma 15>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 41>;
status = "disabled";
};
@@ -304,6 +365,7 @@
nvidia,dma-request-selector = <&apbdma 16>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 44>;
status = "disabled";
};
@@ -314,6 +376,7 @@
nvidia,dma-request-selector = <&apbdma 17>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 46>;
status = "disabled";
};
@@ -324,6 +387,7 @@
nvidia,dma-request-selector = <&apbdma 18>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 68>;
status = "disabled";
};
@@ -334,6 +398,7 @@
nvidia,dma-request-selector = <&apbdma 27>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 104>;
status = "disabled";
};
@@ -344,6 +409,15 @@
nvidia,dma-request-selector = <&apbdma 28>;
#address-cells = <1>;
#size-cells = <0>;
+ clocks = <&tegra_car 105>;
+ status = "disabled";
+ };
+
+ kbc {
+ compatible = "nvidia,tegra30-kbc", "nvidia,tegra20-kbc";
+ reg = <0x7000e200 0x100>;
+ interrupts = <0 85 0x04>;
+ clocks = <&tegra_car 36>;
status = "disabled";
};
@@ -361,7 +435,7 @@
interrupts = <0 77 0x04>;
};
- smmu {
+ iommu {
compatible = "nvidia,tegra30-smmu";
reg = <0x7000f010 0x02c
0x7000f1f0 0x010
@@ -377,7 +451,13 @@
0x70080200 0x100>;
interrupts = <0 103 0x04>;
nvidia,dma-request-selector = <&apbdma 1>;
-
+ clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>,
+ <&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>,
+ <&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>,
+ <&tegra_car 110>, <&tegra_car 162>;
+ clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2",
+ "i2s3", "i2s4", "dam0", "dam1", "dam2",
+ "spdif_in";
ranges;
#address-cells = <1>;
#size-cells = <1>;
@@ -386,6 +466,7 @@
compatible = "nvidia,tegra30-i2s";
reg = <0x70080300 0x100>;
nvidia,ahub-cif-ids = <4 4>;
+ clocks = <&tegra_car 30>;
status = "disabled";
};
@@ -393,6 +474,7 @@
compatible = "nvidia,tegra30-i2s";
reg = <0x70080400 0x100>;
nvidia,ahub-cif-ids = <5 5>;
+ clocks = <&tegra_car 11>;
status = "disabled";
};
@@ -400,6 +482,7 @@
compatible = "nvidia,tegra30-i2s";
reg = <0x70080500 0x100>;
nvidia,ahub-cif-ids = <6 6>;
+ clocks = <&tegra_car 18>;
status = "disabled";
};
@@ -407,6 +490,7 @@
compatible = "nvidia,tegra30-i2s";
reg = <0x70080600 0x100>;
nvidia,ahub-cif-ids = <7 7>;
+ clocks = <&tegra_car 101>;
status = "disabled";
};
@@ -414,6 +498,7 @@
compatible = "nvidia,tegra30-i2s";
reg = <0x70080700 0x100>;
nvidia,ahub-cif-ids = <8 8>;
+ clocks = <&tegra_car 102>;
status = "disabled";
};
};
@@ -422,6 +507,7 @@
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
reg = <0x78000000 0x200>;
interrupts = <0 14 0x04>;
+ clocks = <&tegra_car 14>;
status = "disabled";
};
@@ -429,6 +515,7 @@
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
reg = <0x78000200 0x200>;
interrupts = <0 15 0x04>;
+ clocks = <&tegra_car 9>;
status = "disabled";
};
@@ -436,6 +523,7 @@
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
reg = <0x78000400 0x200>;
interrupts = <0 19 0x04>;
+ clocks = <&tegra_car 69>;
status = "disabled";
};
@@ -443,9 +531,39 @@
compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
reg = <0x78000600 0x200>;
interrupts = <0 31 0x04>;
+ clocks = <&tegra_car 15>;
status = "disabled";
};
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ };
+
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <2>;
+ };
+
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <3>;
+ };
+ };
+
pmu {
compatible = "arm,cortex-a9-pmu";
interrupts = <0 144 0x04
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
index a3d37ec2655d..73187173117c 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
@@ -70,7 +70,7 @@
compatible = "arm,sp805", "arm,primecell";
status = "disabled";
reg = <0 0x2b060000 0 0x1000>;
- interrupts = <98>;
+ interrupts = <0 98 4>;
clocks = <&oscclk7>;
clock-names = "apb_pclk";
};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
index cf8071ad22d5..dfe371ec2749 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
@@ -72,7 +72,7 @@
wdt@2a490000 {
compatible = "arm,sp805", "arm,primecell";
reg = <0 0x2a490000 0 0x1000>;
- interrupts = <98>;
+ interrupts = <0 98 4>;
clocks = <&oscclk6a>, <&oscclk6a>;
clock-names = "wdogclk", "apb_pclk";
};
diff --git a/arch/arm/boot/dts/vt8500.dtsi b/arch/arm/boot/dts/vt8500.dtsi
index d8645e990b21..cf31ced46602 100644
--- a/arch/arm/boot/dts/vt8500.dtsi
+++ b/arch/arm/boot/dts/vt8500.dtsi
@@ -45,6 +45,38 @@
compatible = "fixed-clock";
clock-frequency = <24000000>;
};
+
+ clkuart0: uart0 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <1>;
+ };
+
+ clkuart1: uart1 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <2>;
+ };
+
+ clkuart2: uart2 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <3>;
+ };
+
+ clkuart3: uart3 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <4>;
+ };
};
};
@@ -83,28 +115,28 @@
compatible = "via,vt8500-uart";
reg = <0xd8200000 0x1040>;
interrupts = <32>;
- clocks = <&ref24>;
+ clocks = <&clkuart0>;
};
uart@d82b0000 {
compatible = "via,vt8500-uart";
reg = <0xd82b0000 0x1040>;
interrupts = <33>;
- clocks = <&ref24>;
+ clocks = <&clkuart1>;
};
uart@d8210000 {
compatible = "via,vt8500-uart";
reg = <0xd8210000 0x1040>;
interrupts = <47>;
- clocks = <&ref24>;
+ clocks = <&clkuart2>;
};
uart@d82c0000 {
compatible = "via,vt8500-uart";
reg = <0xd82c0000 0x1040>;
interrupts = <50>;
- clocks = <&ref24>;
+ clocks = <&clkuart3>;
};
rtc@d8100000 {
diff --git a/arch/arm/boot/dts/wm8505.dtsi b/arch/arm/boot/dts/wm8505.dtsi
index 330f833ac3b0..e74a1c0fb9a2 100644
--- a/arch/arm/boot/dts/wm8505.dtsi
+++ b/arch/arm/boot/dts/wm8505.dtsi
@@ -59,6 +59,54 @@
compatible = "fixed-clock";
clock-frequency = <24000000>;
};
+
+ clkuart0: uart0 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <1>;
+ };
+
+ clkuart1: uart1 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <2>;
+ };
+
+ clkuart2: uart2 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <3>;
+ };
+
+ clkuart3: uart3 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <4>;
+ };
+
+ clkuart4: uart4 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <22>;
+ };
+
+ clkuart5: uart5 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <23>;
+ };
};
};
@@ -96,42 +144,42 @@
compatible = "via,vt8500-uart";
reg = <0xd8200000 0x1040>;
interrupts = <32>;
- clocks = <&ref24>;
+ clocks = <&clkuart0>;
};
uart@d82b0000 {
compatible = "via,vt8500-uart";
reg = <0xd82b0000 0x1040>;
interrupts = <33>;
- clocks = <&ref24>;
+ clocks = <&clkuart1>;
};
uart@d8210000 {
compatible = "via,vt8500-uart";
reg = <0xd8210000 0x1040>;
interrupts = <47>;
- clocks = <&ref24>;
+ clocks = <&clkuart2>;
};
uart@d82c0000 {
compatible = "via,vt8500-uart";
reg = <0xd82c0000 0x1040>;
interrupts = <50>;
- clocks = <&ref24>;
+ clocks = <&clkuart3>;
};
uart@d8370000 {
compatible = "via,vt8500-uart";
reg = <0xd8370000 0x1040>;
interrupts = <31>;
- clocks = <&ref24>;
+ clocks = <&clkuart4>;
};
uart@d8380000 {
compatible = "via,vt8500-uart";
reg = <0xd8380000 0x1040>;
interrupts = <30>;
- clocks = <&ref24>;
+ clocks = <&clkuart5>;
};
rtc@d8100000 {
diff --git a/arch/arm/boot/dts/wm8650.dtsi b/arch/arm/boot/dts/wm8650.dtsi
index 83b9467559bb..db3c0a12e052 100644
--- a/arch/arm/boot/dts/wm8650.dtsi
+++ b/arch/arm/boot/dts/wm8650.dtsi
@@ -75,6 +75,22 @@
reg = <0x204>;
};
+ clkuart0: uart0 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <1>;
+ };
+
+ clkuart1: uart1 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x250>;
+ enable-bit = <2>;
+ };
+
arm: arm {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
@@ -128,14 +144,14 @@
compatible = "via,vt8500-uart";
reg = <0xd8200000 0x1040>;
interrupts = <32>;
- clocks = <&ref24>;
+ clocks = <&clkuart0>;
};
uart@d82b0000 {
compatible = "via,vt8500-uart";
reg = <0xd82b0000 0x1040>;
interrupts = <33>;
- clocks = <&ref24>;
+ clocks = <&clkuart1>;
};
rtc@d8100000 {
diff --git a/arch/arm/boot/dts/wm8850-w70v2.dts b/arch/arm/boot/dts/wm8850-w70v2.dts
new file mode 100644
index 000000000000..fcc660c89540
--- /dev/null
+++ b/arch/arm/boot/dts/wm8850-w70v2.dts
@@ -0,0 +1,47 @@
+/*
+ * wm8850-w70v2.dts
+ * - Device tree file for Wondermedia WM8850 Tablet
+ * - 'W70-V2' mainboard
+ * - HongLianYing 'HLY070ML268-21A' 7" LCD panel
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * Licensed under GPLv2 or later
+ */
+
+/dts-v1/;
+/include/ "wm8850.dtsi"
+
+/ {
+ model = "Wondermedia WM8850-W70v2 Tablet";
+
+ /*
+ * Display node is based on Sascha Hauer's patch on dri-devel.
+ * Added a bpp property to calculate the size of the framebuffer
+ * until the binding is formalized.
+ */
+ display: display@0 {
+ modes {
+ mode0: mode@0 {
+ hactive = <800>;
+ vactive = <480>;
+ hback-porch = <88>;
+ hfront-porch = <40>;
+ hsync-len = <0>;
+ vback-porch = <32>;
+ vfront-porch = <11>;
+ vsync-len = <1>;
+ clock = <0>; /* unused but required */
+ bpp = <16>; /* non-standard but required */
+ };
+ };
+ };
+
+ backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm 0 50000 1>; /* duty inverted */
+
+ brightness-levels = <0 40 60 80 100 130 190 255>;
+ default-brightness-level = <5>;
+ };
+};
diff --git a/arch/arm/boot/dts/wm8850.dtsi b/arch/arm/boot/dts/wm8850.dtsi
new file mode 100644
index 000000000000..e8cbfdc87bba
--- /dev/null
+++ b/arch/arm/boot/dts/wm8850.dtsi
@@ -0,0 +1,224 @@
+/*
+ * wm8850.dtsi - Device tree file for Wondermedia WM8850 SoC
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * Licensed under GPLv2 or later
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "wm,wm8850";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges;
+ interrupt-parent = <&intc0>;
+
+ intc0: interrupt-controller@d8140000 {
+ compatible = "via,vt8500-intc";
+ interrupt-controller;
+ reg = <0xd8140000 0x10000>;
+ #interrupt-cells = <1>;
+ };
+
+ /* Secondary IC cascaded to intc0 */
+ intc1: interrupt-controller@d8150000 {
+ compatible = "via,vt8500-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xD8150000 0x10000>;
+ interrupts = <56 57 58 59 60 61 62 63>;
+ };
+
+ gpio: gpio-controller@d8110000 {
+ compatible = "wm,wm8650-gpio";
+ gpio-controller;
+ reg = <0xd8110000 0x10000>;
+ #gpio-cells = <3>;
+ };
+
+ pmc@d8130000 {
+ compatible = "via,vt8500-pmc";
+ reg = <0xd8130000 0x1000>;
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ref25: ref25M {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <25000000>;
+ };
+
+ ref24: ref24M {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ };
+
+ plla: plla {
+ #clock-cells = <0>;
+ compatible = "wm,wm8750-pll-clock";
+ clocks = <&ref25>;
+ reg = <0x200>;
+ };
+
+ pllb: pllb {
+ #clock-cells = <0>;
+ compatible = "wm,wm8750-pll-clock";
+ clocks = <&ref25>;
+ reg = <0x204>;
+ };
+
+ clkuart0: uart0 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x254>;
+ enable-bit = <24>;
+ };
+
+ clkuart1: uart1 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x254>;
+ enable-bit = <25>;
+ };
+
+ clkuart2: uart2 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x254>;
+ enable-bit = <26>;
+ };
+
+ clkuart3: uart3 {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&ref24>;
+ enable-reg = <0x254>;
+ enable-bit = <27>;
+ };
+
+ clkpwm: pwm {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&pllb>;
+ divisor-reg = <0x350>;
+ enable-reg = <0x250>;
+ enable-bit = <17>;
+ };
+
+ clksdhc: sdhc {
+ #clock-cells = <0>;
+ compatible = "via,vt8500-device-clock";
+ clocks = <&pllb>;
+ divisor-reg = <0x330>;
+ divisor-mask = <0x3f>;
+ enable-reg = <0x250>;
+ enable-bit = <0>;
+ };
+ };
+ };
+
+ fb@d8051700 {
+ compatible = "wm,wm8505-fb";
+ reg = <0xd8051700 0x200>;
+ display = <&display>;
+ default-mode = <&mode0>;
+ };
+
+ ge_rops@d8050400 {
+ compatible = "wm,prizm-ge-rops";
+ reg = <0xd8050400 0x100>;
+ };
+
+ pwm: pwm@d8220000 {
+ #pwm-cells = <3>;
+ compatible = "via,vt8500-pwm";
+ reg = <0xd8220000 0x100>;
+ clocks = <&clkpwm>;
+ };
+
+ timer@d8130100 {
+ compatible = "via,vt8500-timer";
+ reg = <0xd8130100 0x28>;
+ interrupts = <36>;
+ };
+
+ ehci@d8007900 {
+ compatible = "via,vt8500-ehci";
+ reg = <0xd8007900 0x200>;
+ interrupts = <26>;
+ };
+
+ uhci@d8007b00 {
+ compatible = "platform-uhci";
+ reg = <0xd8007b00 0x200>;
+ interrupts = <26>;
+ };
+
+ uhci@d8008d00 {
+ compatible = "platform-uhci";
+ reg = <0xd8008d00 0x200>;
+ interrupts = <26>;
+ };
+
+ uart0: uart@d8200000 {
+ compatible = "via,vt8500-uart";
+ reg = <0xd8200000 0x1040>;
+ interrupts = <32>;
+ clocks = <&clkuart0>;
+ };
+
+ uart1: uart@d82b0000 {
+ compatible = "via,vt8500-uart";
+ reg = <0xd82b0000 0x1040>;
+ interrupts = <33>;
+ clocks = <&clkuart1>;
+ };
+
+ uart2: uart@d8210000 {
+ compatible = "via,vt8500-uart";
+ reg = <0xd8210000 0x1040>;
+ interrupts = <47>;
+ clocks = <&clkuart2>;
+ };
+
+ uart3: uart@d82c0000 {
+ compatible = "via,vt8500-uart";
+ reg = <0xd82c0000 0x1040>;
+ interrupts = <50>;
+ clocks = <&clkuart3>;
+ };
+
+ rtc@d8100000 {
+ compatible = "via,vt8500-rtc";
+ reg = <0xd8100000 0x10000>;
+ interrupts = <48>;
+ };
+
+ sdhc@d800a000 {
+ compatible = "wm,wm8505-sdhc";
+ reg = <0xd800a000 0x1000>;
+ interrupts = <20 21>;
+ clocks = <&clksdhc>;
+ bus-width = <4>;
+ sdon-inverted;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
index 401c1262d4ed..5914b5654591 100644
--- a/arch/arm/boot/dts/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/zynq-7000.dtsi
@@ -44,14 +44,14 @@
compatible = "xlnx,xuartps";
reg = <0xE0000000 0x1000>;
interrupts = <0 27 4>;
- clock = <50000000>;
+ clocks = <&uart_clk 0>;
};
uart1: uart@e0001000 {
compatible = "xlnx,xuartps";
reg = <0xE0001000 0x1000>;
interrupts = <0 50 4>;
- clock = <50000000>;
+ clocks = <&uart_clk 1>;
};
slcr: slcr@f8000000 {
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index 45ceeb0e93e0..9353184d730d 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -1,26 +1,3 @@
-config ARM_GIC
- bool
- select IRQ_DOMAIN
- select MULTI_IRQ_HANDLER
-
-config GIC_NON_BANKED
- bool
-
-config ARM_VIC
- bool
- select IRQ_DOMAIN
- select MULTI_IRQ_HANDLER
-
-config ARM_VIC_NR
- int
- default 4 if ARCH_S5PV210
- default 3 if ARCH_S5PC100
- default 2
- depends on ARM_VIC
- help
- The maximum number of VICs available in the system, for
- power management.
-
config ICST
bool
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index e8a4e58f1b82..dc8dd0de5c0f 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -2,8 +2,6 @@
# Makefile for the linux kernel.
#
-obj-$(CONFIG_ARM_GIC) += gic.o
-obj-$(CONFIG_ARM_VIC) += vic.o
obj-$(CONFIG_ICST) += icst.o
obj-$(CONFIG_SA1111) += sa1111.o
obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o
diff --git a/arch/arm/configs/armadillo800eva_defconfig b/arch/arm/configs/armadillo800eva_defconfig
index 2e1a82577207..0b98100d2ae7 100644
--- a/arch/arm/configs/armadillo800eva_defconfig
+++ b/arch/arm/configs/armadillo800eva_defconfig
@@ -34,12 +34,11 @@ CONFIG_AEABI=y
CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096 rw"
-CONFIG_CMDLINE_FORCE=y
+CONFIG_ARM_APPENDED_DTB=y
CONFIG_KEXEC=y
CONFIG_VFP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_SUSPEND is not set
+CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -91,14 +90,11 @@ CONFIG_I2C_SH_MOBILE=y
# CONFIG_HWMON is not set
CONFIG_MEDIA_SUPPORT=y
CONFIG_VIDEO_DEV=y
-# CONFIG_RC_CORE is not set
-# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
-# CONFIG_V4L_USB_DRIVERS is not set
+CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_MT9T112=y
CONFIG_VIDEO_SH_MOBILE_CEU=y
-# CONFIG_RADIO_ADAPTERS is not set
CONFIG_FB=y
CONFIG_FB_SH_MOBILE_LCDC=y
CONFIG_FB_SH_MOBILE_HDMI=y
diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig
index c5212f43eee6..36fed66bd4b5 100644
--- a/arch/arm/configs/at91sam9263_defconfig
+++ b/arch/arm/configs/at91sam9263_defconfig
@@ -18,7 +18,6 @@ CONFIG_ARCH_AT91=y
CONFIG_ARCH_AT91SAM9263=y
CONFIG_MACH_AT91SAM9263EK=y
CONFIG_MACH_USB_A9263=y
-CONFIG_MACH_NEOCORE926=y
CONFIG_MTD_AT91_DATAFLASH_CARD=y
# CONFIG_ARM_THUMB is not set
CONFIG_AEABI=y
diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig
index 74e27f0ff6ad..af472e4ed451 100644
--- a/arch/arm/configs/bcm2835_defconfig
+++ b/arch/arm/configs/bcm2835_defconfig
@@ -1,11 +1,10 @@
-CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_FHANDLE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
@@ -30,13 +29,10 @@ CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_JUMP_LABEL=y
-# CONFIG_BLOCK is not set
CONFIG_ARCH_BCM2835=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_AEABI=y
-CONFIG_COMPACTION=y
CONFIG_KSM=y
-CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
CONFIG_CLEANCACHE=y
CONFIG_SECCOMP=y
CONFIG_CC_STACKPROTECTOR=y
@@ -45,6 +41,11 @@ CONFIG_CRASH_DUMP=y
CONFIG_VFP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_NETWORK_SECMARK=y
+# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
@@ -53,20 +54,42 @@ CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
-# CONFIG_UNIX98_PTYS is not set
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_TTY_PRINTK=y
# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_BCM2835=y
+CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_BCM2835=y
# CONFIG_IOMMU_SUPPORT is not set
-# CONFIG_FILE_LOCKING is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_INOTIFY_USER is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_FANOTIFY=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
CONFIG_PRINTK_TIME=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
diff --git a/arch/arm/configs/da8xx_omapl_defconfig b/arch/arm/configs/da8xx_omapl_defconfig
index f29223954af8..9aaad36a1728 100644
--- a/arch/arm/configs/da8xx_omapl_defconfig
+++ b/arch/arm/configs/da8xx_omapl_defconfig
@@ -36,6 +36,7 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=m
CONFIG_CPU_FREQ_GOV_POWERSAVE=m
CONFIG_CPU_FREQ_GOV_ONDEMAND=m
CONFIG_CPU_IDLE=y
+CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -45,6 +46,8 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_LRO is not set
CONFIG_NETFILTER=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_FW_LOADER is not set
CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_RAM=y
@@ -81,6 +84,7 @@ CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_DAVINCI=y
+CONFIG_PINCTRL_SINGLE=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_REGULATOR=y
diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index 4ea7c95719d2..3edc78a40b66 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -33,6 +33,7 @@ CONFIG_AEABI=y
CONFIG_LEDS=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -42,6 +43,8 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_LRO is not set
CONFIG_NETFILTER=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_FW_LOADER is not set
CONFIG_MTD=m
CONFIG_MTD_PARTITIONS=y
diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig
index ebbfb27e0e74..02c657af4005 100644
--- a/arch/arm/configs/imx_v4_v5_defconfig
+++ b/arch/arm/configs/imx_v4_v5_defconfig
@@ -61,6 +61,7 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -127,6 +128,8 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_OV2640=y
CONFIG_VIDEO_MX2=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_CODA=y
CONFIG_FB=y
CONFIG_FB_IMX=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 69667133321f..e36b01025321 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -19,6 +19,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_ARCH_MXC=y
CONFIG_ARCH_MULTI_V6=y
CONFIG_ARCH_MULTI_V7=y
+CONFIG_MACH_IMX31_DT=y
CONFIG_MACH_MX31LILLY=y
CONFIG_MACH_MX31LITE=y
CONFIG_MACH_PCM037=y
@@ -32,7 +33,6 @@ CONFIG_MACH_PCM043=y
CONFIG_MACH_MX35_3DS=y
CONFIG_MACH_VPR200=y
CONFIG_MACH_IMX51_DT=y
-CONFIG_MACH_MX51_3DS=y
CONFIG_MACH_EUKREA_CPUIMX51SD=y
CONFIG_SOC_IMX53=y
CONFIG_SOC_IMX6Q=y
@@ -59,6 +59,7 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
+CONFIG_NETFILTER=y
# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -151,6 +152,7 @@ CONFIG_MFD_MC13XXX_I2C=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_DA9052=y
+CONFIG_REGULATOR_ANATOP=y
CONFIG_REGULATOR_MC13783=y
CONFIG_REGULATOR_MC13892=y
CONFIG_MEDIA_SUPPORT=y
@@ -159,6 +161,7 @@ CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_OV2640=y
+CONFIG_DRM=y
CONFIG_VIDEO_MX3=y
CONFIG_FB=y
CONFIG_LCD_PLATFORM=y
@@ -197,9 +200,14 @@ CONFIG_RTC_CLASS=y
CONFIG_RTC_INTF_DEV_UIE_EMUL=y
CONFIG_RTC_DRV_MC13XXX=y
CONFIG_RTC_DRV_MXC=y
+CONFIG_RTC_DRV_SNVS=y
CONFIG_DMADEVICES=y
CONFIG_IMX_SDMA=y
CONFIG_MXS_DMA=y
+CONFIG_STAGING=y
+CONFIG_DRM_IMX=y
+CONFIG_DRM_IMX_IPUV3_CORE=y
+CONFIG_DRM_IMX_IPUV3=y
CONFIG_COMMON_CLK_DEBUG=y
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig
index 93f3794ba5cb..13482ea58b09 100644
--- a/arch/arm/configs/kirkwood_defconfig
+++ b/arch/arm/configs/kirkwood_defconfig
@@ -56,6 +56,7 @@ CONFIG_AEABI=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_KIRKWOOD=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm/configs/kota2_defconfig b/arch/arm/configs/kota2_defconfig
index fa83db1ef0eb..57ad3d47de70 100644
--- a/arch/arm/configs/kota2_defconfig
+++ b/arch/arm/configs/kota2_defconfig
@@ -21,7 +21,7 @@ CONFIG_ARCH_SHMOBILE=y
CONFIG_KEYBOARD_GPIO_POLLED=y
CONFIG_ARCH_SH73A0=y
CONFIG_MACH_KOTA2=y
-CONFIG_MEMORY_SIZE=0x1e0000000
+CONFIG_MEMORY_SIZE=0x1e000000
# CONFIG_SH_TIMER_TMU is not set
# CONFIG_SWP_EMULATE is not set
CONFIG_CPU_BPREDICT_DISABLE=y
diff --git a/arch/arm/configs/kzm9d_defconfig b/arch/arm/configs/kzm9d_defconfig
index 8c49df66cac3..6c37f4a98eb8 100644
--- a/arch/arm/configs/kzm9d_defconfig
+++ b/arch/arm/configs/kzm9d_defconfig
@@ -32,11 +32,9 @@ CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ARM_APPENDED_DTB=y
-CONFIG_CMDLINE="console=tty0 console=ttyS1,115200n81 earlyprintk=serial8250-em.1,115200n81 mem=128M@0x40000000 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096"
-CONFIG_CMDLINE_FORCE=y
CONFIG_VFP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_SUSPEND is not set
+CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm/configs/kzm9g_defconfig b/arch/arm/configs/kzm9g_defconfig
index afbae287436b..670c3b60f936 100644
--- a/arch/arm/configs/kzm9g_defconfig
+++ b/arch/arm/configs/kzm9g_defconfig
@@ -39,7 +39,7 @@ CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel earlyprintk=sh-sci.4,115200"
+CONFIG_ARM_APPENDED_DTB=y
CONFIG_KEXEC=y
CONFIG_VFP=y
CONFIG_NEON=y
@@ -85,6 +85,8 @@ CONFIG_I2C_CHARDEV=y
CONFIG_I2C_SH_MOBILE=y
CONFIG_GPIO_PCF857X=y
# CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DUMMY=y
CONFIG_FB=y
CONFIG_FB_SH_MOBILE_LCDC=y
CONFIG_FRAMEBUFFER_CONSOLE=y
diff --git a/arch/arm/configs/mackerel_defconfig b/arch/arm/configs/mackerel_defconfig
index 2098ce155542..7594b3aff259 100644
--- a/arch/arm/configs/mackerel_defconfig
+++ b/arch/arm/configs/mackerel_defconfig
@@ -23,8 +23,9 @@ CONFIG_AEABI=y
CONFIG_FORCE_MAX_ZONEORDER=15
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=tty0, console=ttySC0,115200 earlyprintk=sh-sci.0,115200 root=/dev/nfs nfsroot=,tcp,v3 ip=dhcp memchunk.vpu=64m memchunk.veu0=8m memchunk.spu0=2m mem=240m"
+CONFIG_ARM_APPENDED_DTB=y
CONFIG_KEXEC=y
+CONFIG_VFP=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_PM=y
CONFIG_PM_RUNTIME=y
diff --git a/arch/arm/configs/marzen_defconfig b/arch/arm/configs/marzen_defconfig
index 728a43c446f8..afb17d630d44 100644
--- a/arch/arm/configs/marzen_defconfig
+++ b/arch/arm/configs/marzen_defconfig
@@ -83,7 +83,6 @@ CONFIG_USB=y
CONFIG_USB_RCAR_PHY=y
CONFIG_MMC=y
CONFIG_MMC_SDHI=y
-CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 2eeff1e64b6e..e31d442343c8 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -8,6 +8,7 @@ CONFIG_ARCH_HIGHBANK=y
CONFIG_ARCH_SOCFPGA=y
CONFIG_ARCH_SUNXI=y
# CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set
+CONFIG_ARCH_ZYNQ=y
CONFIG_ARM_ERRATA_754322=y
CONFIG_SMP=y
CONFIG_ARM_ARCH_TIMER=y
@@ -39,7 +40,6 @@ CONFIG_I2C=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
-CONFIG_GPIOLIB=y
CONFIG_FB=y
CONFIG_FB_ARMCLCD=y
CONFIG_FRAMEBUFFER_CONSOLE=y
diff --git a/arch/arm/configs/mvebu_defconfig b/arch/arm/configs/mvebu_defconfig
index b5bc96cb65a7..cbd91bce1ca9 100644
--- a/arch/arm/configs/mvebu_defconfig
+++ b/arch/arm/configs/mvebu_defconfig
@@ -33,6 +33,8 @@ CONFIG_MVNETA=y
CONFIG_MARVELL_PHY=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_I2C=y
+CONFIG_I2C_MV64XXX=y
CONFIG_SERIAL_8250_DW=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig
index 7bf535104e26..fbbc5bb022d5 100644
--- a/arch/arm/configs/mxs_defconfig
+++ b/arch/arm/configs/mxs_defconfig
@@ -1,5 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
@@ -8,7 +10,6 @@ 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
@@ -24,8 +25,6 @@ CONFIG_BLK_DEV_INTEGRITY=y
CONFIG_ARCH_MXS=y
CONFIG_MACH_MXS_DT=y
# CONFIG_ARM_THUMB is not set
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_AEABI=y
CONFIG_AUTO_ZRELADDR=y
@@ -46,25 +45,34 @@ CONFIG_SYN_COOKIES=y
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_DEVTMPFS_MOUNT=y
# CONFIG_FIRMWARE_IN_KERNEL is not set
-# CONFIG_BLK_DEV is not set
CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_M25P80
+CONFIG_MTD_M25P80=y
+# CONFIG_M25PXX_USE_FAST_READ is not set
+CONFIG_MTD_SST25L=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_GPMI_NAND=y
+CONFIG_MTD_UBI=y
+# CONFIG_BLK_DEV is not set
+CONFIG_EEPROM_AT24=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
CONFIG_ENC28J60=y
CONFIG_USB_USBNET=y
CONFIG_USB_NET_SMSC95XX=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_SMSC_PHY=y
+CONFIG_ICPLUS_PHY=y
+CONFIG_REALTEK_PHY=y
+CONFIG_MICREL_PHY=y
# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_EVDEV=m
@@ -91,21 +99,6 @@ CONFIG_SPI_MXS=y
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_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_TIMER=y
-CONFIG_SND_PCM=y
-CONFIG_SND_JACK=y
-CONFIG_SND_DRIVERS=y
-CONFIG_SND_ARM=y
-CONFIG_SND_SOC=y
-CONFIG_SND_MXS_SOC=y
-CONFIG_SND_SOC_MXS_SGTL5000=y
-CONFIG_SND_SOC_I2C_AND_SPI=y
-CONFIG_SND_SOC_SGTL5000=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_FB=y
@@ -117,13 +110,16 @@ CONFIG_BACKLIGHT_PWM=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FONTS=y
CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_MXS_SOC=y
+CONFIG_SND_SOC_MXS_SGTL5000=y
CONFIG_USB=y
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_USB_STORAGE=y
CONFIG_USB_MXS_PHY=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
CONFIG_MMC=y
CONFIG_MMC_MXS=y
CONFIG_NEW_LEDS=y
@@ -147,16 +143,23 @@ CONFIG_COMMON_CLK_DEBUG=y
CONFIG_IIO=y
CONFIG_PWM=y
CONFIG_PWM_MXS=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
+CONFIG_EXT4_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_JFFS2_FS=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
@@ -170,17 +173,12 @@ 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
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 82ce8d738fa1..b16bae2c9a60 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -20,9 +20,10 @@ CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_OMAP=y
+CONFIG_ARCH_OMAP2PLUS=y
CONFIG_OMAP_RESET_CLOCKS=y
CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_ARCH_VEXPRESS_CA9X4=y
CONFIG_ARM_THUMBEE=y
CONFIG_ARM_ERRATA_411920=y
CONFIG_NO_HZ=y
@@ -52,6 +53,11 @@ CONFIG_IP_PNP_RARP=y
# CONFIG_INET_LRO is not set
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+CONFIG_CAN_C_CAN=m
+CONFIG_CAN_C_CAN_PLATFORM=m
CONFIG_BT=m
CONFIG_BT_HCIUART=m
CONFIG_BT_HCIUART_H4=y
@@ -64,6 +70,7 @@ CONFIG_MAC80211=m
CONFIG_MAC80211_RC_PID=y
CONFIG_MAC80211_RC_DEFAULT_PID=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_CMA=y
CONFIG_CONNECTOR=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -83,6 +90,9 @@ CONFIG_MTD_UBI=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_SENSORS_LIS3LV02D=m
+CONFIG_SENSORS_TSL2550=m
+CONFIG_SENSORS_LIS3_I2C=m
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_MULTI_LUN=y
@@ -108,6 +118,7 @@ CONFIG_USB_KC2190=y
CONFIG_INPUT_JOYDEV=y
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_MATRIX=m
CONFIG_KEYBOARD_TWL4030=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=y
@@ -121,6 +132,8 @@ CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
CONFIG_SERIAL_8250_DETECT_IRQ=y
CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_I2C_CHARDEV=y
CONFIG_SPI=y
@@ -131,14 +144,17 @@ CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_TWL4030=y
CONFIG_W1=y
CONFIG_POWER_SUPPLY=y
+CONFIG_SENSORS_LM75=m
CONFIG_WATCHDOG=y
CONFIG_OMAP_WATCHDOG=y
CONFIG_TWL4030_WATCHDOG=y
CONFIG_MFD_TPS65217=y
+CONFIG_MFD_TPS65910=y
CONFIG_REGULATOR_TWL4030=y
CONFIG_REGULATOR_TPS65023=y
CONFIG_REGULATOR_TPS6507X=y
CONFIG_REGULATOR_TPS65217=y
+CONFIG_REGULATOR_TPS65910=y
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_MODE_HELPERS=y
@@ -150,6 +166,7 @@ CONFIG_OMAP2_DSS_SDI=y
CONFIG_OMAP2_DSS_DSI=y
CONFIG_FB_OMAP2=m
CONFIG_PANEL_GENERIC_DPI=m
+CONFIG_PANEL_TFP410=m
CONFIG_PANEL_SHARP_LS037V7DW01=m
CONFIG_PANEL_NEC_NL8048HL11_01B=m
CONFIG_PANEL_TAAL=m
@@ -194,11 +211,23 @@ CONFIG_USB_ZERO=m
CONFIG_MMC=y
CONFIG_MMC_UNSAFE_RESUME=y
CONFIG_SDIO_UART=y
+CONFIG_MMC_ARMMMCI=y
CONFIG_MMC_OMAP=y
CONFIG_MMC_OMAP_HS=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_TWL92330=y
CONFIG_RTC_DRV_TWL4030=y
+CONFIG_RTC_DRV_OMAP=y
CONFIG_DMADEVICES=y
CONFIG_DMA_OMAP=y
CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/prima2_defconfig b/arch/arm/configs/prima2_defconfig
index 6a936c7c078a..002a1ceadceb 100644
--- a/arch/arm/configs/prima2_defconfig
+++ b/arch/arm/configs/prima2_defconfig
@@ -11,6 +11,9 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_BSD_DISKLABEL=y
CONFIG_SOLARIS_X86_PARTITION=y
CONFIG_ARCH_SIRF=y
+# CONFIG_SWP_EMULATE is not set
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_KEXEC=y
diff --git a/arch/arm/configs/pxa910_defconfig b/arch/arm/configs/pxa910_defconfig
index 191118caa5c0..3bb7771d3c19 100644
--- a/arch/arm/configs/pxa910_defconfig
+++ b/arch/arm/configs/pxa910_defconfig
@@ -42,6 +42,14 @@ CONFIG_SMC91X=y
# CONFIG_SERIO is not set
CONFIG_SERIAL_PXA=y
CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SPI=y
+CONFIG_FB=y
+CONFIG_MMP_DISP=y
+CONFIG_MMP_DISP_CONTROLLER=y
+CONFIG_MMP_SPI=y
+CONFIG_MMP_PANEL_TPOHVGA=y
+CONFIG_MMP_FB=y
+CONFIG_LOGO=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
diff --git a/arch/arm/configs/shark_defconfig b/arch/arm/configs/shark_defconfig
index caa07db90cf5..e319b2c56f11 100644
--- a/arch/arm/configs/shark_defconfig
+++ b/arch/arm/configs/shark_defconfig
@@ -73,7 +73,6 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_CODEPAGE_850=m
CONFIG_NLS_ISO8859_1=m
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index a7827fd0616f..aba4881d20e5 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -38,6 +38,7 @@ CONFIG_HIGHMEM=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_AUTO_ZRELADDR=y
+CONFIG_KEXEC=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_IDLE=y
@@ -106,12 +107,14 @@ CONFIG_BRCMFMAC=m
CONFIG_RT2X00=y
CONFIG_RT2800USB=m
CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_TEGRA=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_MPU3050=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_TEGRA=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
@@ -127,6 +130,8 @@ CONFIG_GPIO_TPS6586X=y
CONFIG_GPIO_TPS65910=y
CONFIG_POWER_SUPPLY=y
CONFIG_BATTERY_SBS=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
CONFIG_SENSORS_LM90=y
CONFIG_MFD_TPS6586X=y
CONFIG_MFD_TPS65910=y
@@ -186,6 +191,7 @@ CONFIG_RTC_INTF_SYSFS=y
CONFIG_RTC_INTF_PROC=y
CONFIG_RTC_INTF_DEV=y
CONFIG_RTC_DRV_MAX8907=y
+CONFIG_RTC_DRV_TPS6586X=y
CONFIG_RTC_DRV_TPS65910=y
CONFIG_RTC_DRV_EM3027=y
CONFIG_RTC_DRV_TEGRA=y
diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
index 231dca604737..426270fe080d 100644
--- a/arch/arm/configs/u8500_defconfig
+++ b/arch/arm/configs/u8500_defconfig
@@ -66,9 +66,9 @@ CONFIG_SPI=y
CONFIG_SPI_PL022=y
CONFIG_GPIO_STMPE=y
CONFIG_GPIO_TC3589X=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_AB8500_BM=y
-CONFIG_AB8500_BATTERY_THERM_ON_BATCTRL=y
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_AB8500_BM is not set
+# CONFIG_AB8500_BATTERY_THERM_ON_BATCTRL is not set
CONFIG_THERMAL=y
CONFIG_CPU_THERMAL=y
CONFIG_MFD_STMPE=y
diff --git a/arch/arm/crypto/aes-armv4.S b/arch/arm/crypto/aes-armv4.S
index e59b1d505d6c..19d6cd6f29f9 100644
--- a/arch/arm/crypto/aes-armv4.S
+++ b/arch/arm/crypto/aes-armv4.S
@@ -34,8 +34,9 @@
@ A little glue here to select the correct code below for the ARM CPU
@ that is being targetted.
+#include <linux/linkage.h>
+
.text
-.code 32
.type AES_Te,%object
.align 5
@@ -145,10 +146,8 @@ AES_Te:
@ void AES_encrypt(const unsigned char *in, unsigned char *out,
@ const AES_KEY *key) {
-.global AES_encrypt
-.type AES_encrypt,%function
.align 5
-AES_encrypt:
+ENTRY(AES_encrypt)
sub r3,pc,#8 @ AES_encrypt
stmdb sp!,{r1,r4-r12,lr}
mov r12,r0 @ inp
@@ -239,15 +238,8 @@ AES_encrypt:
strb r6,[r12,#14]
strb r3,[r12,#15]
#endif
-#if __ARM_ARCH__>=5
ldmia sp!,{r4-r12,pc}
-#else
- ldmia sp!,{r4-r12,lr}
- tst lr,#1
- moveq pc,lr @ be binary compatible with V4, yet
- .word 0xe12fff1e @ interoperable with Thumb ISA:-)
-#endif
-.size AES_encrypt,.-AES_encrypt
+ENDPROC(AES_encrypt)
.type _armv4_AES_encrypt,%function
.align 2
@@ -386,10 +378,8 @@ _armv4_AES_encrypt:
ldr pc,[sp],#4 @ pop and return
.size _armv4_AES_encrypt,.-_armv4_AES_encrypt
-.global private_AES_set_encrypt_key
-.type private_AES_set_encrypt_key,%function
.align 5
-private_AES_set_encrypt_key:
+ENTRY(private_AES_set_encrypt_key)
_armv4_AES_set_encrypt_key:
sub r3,pc,#8 @ AES_set_encrypt_key
teq r0,#0
@@ -658,15 +648,11 @@ _armv4_AES_set_encrypt_key:
.Ldone: mov r0,#0
ldmia sp!,{r4-r12,lr}
-.Labrt: tst lr,#1
- moveq pc,lr @ be binary compatible with V4, yet
- .word 0xe12fff1e @ interoperable with Thumb ISA:-)
-.size private_AES_set_encrypt_key,.-private_AES_set_encrypt_key
+.Labrt: mov pc,lr
+ENDPROC(private_AES_set_encrypt_key)
-.global private_AES_set_decrypt_key
-.type private_AES_set_decrypt_key,%function
.align 5
-private_AES_set_decrypt_key:
+ENTRY(private_AES_set_decrypt_key)
str lr,[sp,#-4]! @ push lr
#if 0
@ kernel does both of these in setkey so optimise this bit out by
@@ -748,15 +734,8 @@ private_AES_set_decrypt_key:
bne .Lmix
mov r0,#0
-#if __ARM_ARCH__>=5
ldmia sp!,{r4-r12,pc}
-#else
- ldmia sp!,{r4-r12,lr}
- tst lr,#1
- moveq pc,lr @ be binary compatible with V4, yet
- .word 0xe12fff1e @ interoperable with Thumb ISA:-)
-#endif
-.size private_AES_set_decrypt_key,.-private_AES_set_decrypt_key
+ENDPROC(private_AES_set_decrypt_key)
.type AES_Td,%object
.align 5
@@ -862,10 +841,8 @@ AES_Td:
@ void AES_decrypt(const unsigned char *in, unsigned char *out,
@ const AES_KEY *key) {
-.global AES_decrypt
-.type AES_decrypt,%function
.align 5
-AES_decrypt:
+ENTRY(AES_decrypt)
sub r3,pc,#8 @ AES_decrypt
stmdb sp!,{r1,r4-r12,lr}
mov r12,r0 @ inp
@@ -956,15 +933,8 @@ AES_decrypt:
strb r6,[r12,#14]
strb r3,[r12,#15]
#endif
-#if __ARM_ARCH__>=5
ldmia sp!,{r4-r12,pc}
-#else
- ldmia sp!,{r4-r12,lr}
- tst lr,#1
- moveq pc,lr @ be binary compatible with V4, yet
- .word 0xe12fff1e @ interoperable with Thumb ISA:-)
-#endif
-.size AES_decrypt,.-AES_decrypt
+ENDPROC(AES_decrypt)
.type _armv4_AES_decrypt,%function
.align 2
@@ -1064,7 +1034,9 @@ _armv4_AES_decrypt:
and r9,lr,r1,lsr#8
ldrb r7,[r10,r7] @ Td4[s1>>0]
- ldrb r1,[r10,r1,lsr#24] @ Td4[s1>>24]
+ ARM( ldrb r1,[r10,r1,lsr#24] ) @ Td4[s1>>24]
+ THUMB( add r1,r10,r1,lsr#24 ) @ Td4[s1>>24]
+ THUMB( ldrb r1,[r1] )
ldrb r8,[r10,r8] @ Td4[s1>>16]
eor r0,r7,r0,lsl#24
ldrb r9,[r10,r9] @ Td4[s1>>8]
@@ -1077,7 +1049,9 @@ _armv4_AES_decrypt:
ldrb r8,[r10,r8] @ Td4[s2>>0]
and r9,lr,r2,lsr#16
- ldrb r2,[r10,r2,lsr#24] @ Td4[s2>>24]
+ ARM( ldrb r2,[r10,r2,lsr#24] ) @ Td4[s2>>24]
+ THUMB( add r2,r10,r2,lsr#24 ) @ Td4[s2>>24]
+ THUMB( ldrb r2,[r2] )
eor r0,r0,r7,lsl#8
ldrb r9,[r10,r9] @ Td4[s2>>16]
eor r1,r8,r1,lsl#16
@@ -1090,7 +1064,9 @@ _armv4_AES_decrypt:
and r9,lr,r3 @ i2
ldrb r9,[r10,r9] @ Td4[s3>>0]
- ldrb r3,[r10,r3,lsr#24] @ Td4[s3>>24]
+ ARM( ldrb r3,[r10,r3,lsr#24] ) @ Td4[s3>>24]
+ THUMB( add r3,r10,r3,lsr#24 ) @ Td4[s3>>24]
+ THUMB( ldrb r3,[r3] )
eor r0,r0,r7,lsl#16
ldr r7,[r11,#0]
eor r1,r1,r8,lsl#8
diff --git a/arch/arm/crypto/sha1-armv4-large.S b/arch/arm/crypto/sha1-armv4-large.S
index 7050ab133b9d..92c6eed7aac9 100644
--- a/arch/arm/crypto/sha1-armv4-large.S
+++ b/arch/arm/crypto/sha1-armv4-large.S
@@ -51,13 +51,12 @@
@ Profiler-assisted and platform-specific optimization resulted in 10%
@ improvement on Cortex A8 core and 12.2 cycles per byte.
-.text
+#include <linux/linkage.h>
-.global sha1_block_data_order
-.type sha1_block_data_order,%function
+.text
.align 2
-sha1_block_data_order:
+ENTRY(sha1_block_data_order)
stmdb sp!,{r4-r12,lr}
add r2,r1,r2,lsl#6 @ r2 to point at the end of r1
ldmia r0,{r3,r4,r5,r6,r7}
@@ -194,7 +193,7 @@ sha1_block_data_order:
eor r10,r10,r7,ror#2 @ F_00_19(B,C,D)
str r9,[r14,#-4]!
add r3,r3,r10 @ E+=F_00_19(B,C,D)
- teq r14,sp
+ cmp r14,sp
bne .L_00_15 @ [((11+4)*5+2)*3]
#if __ARM_ARCH__<7
ldrb r10,[r1,#2]
@@ -374,7 +373,9 @@ sha1_block_data_order:
@ F_xx_xx
add r3,r3,r9 @ E+=X[i]
add r3,r3,r10 @ E+=F_20_39(B,C,D)
- teq r14,sp @ preserve carry
+ ARM( teq r14,sp ) @ preserve carry
+ THUMB( mov r11,sp )
+ THUMB( teq r14,r11 ) @ preserve carry
bne .L_20_39_or_60_79 @ [+((12+3)*5+2)*4]
bcs .L_done @ [+((12+3)*5+2)*4], spare 300 bytes
@@ -466,7 +467,7 @@ sha1_block_data_order:
add r3,r3,r9 @ E+=X[i]
add r3,r3,r10 @ E+=F_40_59(B,C,D)
add r3,r3,r11,ror#2
- teq r14,sp
+ cmp r14,sp
bne .L_40_59 @ [+((12+5)*5+2)*4]
ldr r8,.LK_60_79
@@ -485,19 +486,12 @@ sha1_block_data_order:
teq r1,r2
bne .Lloop @ [+18], total 1307
-#if __ARM_ARCH__>=5
ldmia sp!,{r4-r12,pc}
-#else
- ldmia sp!,{r4-r12,lr}
- tst lr,#1
- moveq pc,lr @ be binary compatible with V4, yet
- .word 0xe12fff1e @ interoperable with Thumb ISA:-)
-#endif
.align 2
.LK_00_19: .word 0x5a827999
.LK_20_39: .word 0x6ed9eba1
.LK_40_59: .word 0x8f1bbcdc
.LK_60_79: .word 0xca62c1d6
-.size sha1_block_data_order,.-sha1_block_data_order
+ENDPROC(sha1_block_data_order)
.asciz "SHA1 block transform for ARMv4, CRYPTOGAMS by <appro@openssl.org>"
.align 2
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index d40229d9a1c9..7ade91d8cc6f 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -1,13 +1,115 @@
#ifndef __ASMARM_ARCH_TIMER_H
#define __ASMARM_ARCH_TIMER_H
+#include <asm/barrier.h>
#include <asm/errno.h>
#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <clocksource/arm_arch_timer.h>
#ifdef CONFIG_ARM_ARCH_TIMER
int arch_timer_of_register(void);
int arch_timer_sched_clock_init(void);
-struct timecounter *arch_timer_get_timecounter(void);
+
+/*
+ * These register accessors are marked inline so the compiler can
+ * nicely work out which register we want, and chuck away the rest of
+ * the code. At least it does so with a recent GCC (4.6.3).
+ */
+static inline void arch_timer_reg_write(const int access, const int reg, u32 val)
+{
+ if (access == ARCH_TIMER_PHYS_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
+ break;
+ }
+ }
+
+ if (access == ARCH_TIMER_VIRT_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mcr p15, 0, %0, c14, c3, 0" : : "r" (val));
+ break;
+ }
+ }
+
+ isb();
+}
+
+static inline u32 arch_timer_reg_read(const int access, const int reg)
+{
+ u32 val = 0;
+
+ if (access == ARCH_TIMER_PHYS_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
+ break;
+ }
+ }
+
+ if (access == ARCH_TIMER_VIRT_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mrc p15, 0, %0, c14, c3, 0" : "=r" (val));
+ break;
+ }
+ }
+
+ return val;
+}
+
+static inline u32 arch_timer_get_cntfrq(void)
+{
+ u32 val;
+ asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
+ return val;
+}
+
+static inline u64 arch_counter_get_cntpct(void)
+{
+ u64 cval;
+
+ isb();
+ asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
+ return cval;
+}
+
+static inline u64 arch_counter_get_cntvct(void)
+{
+ u64 cval;
+
+ isb();
+ asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
+ return cval;
+}
+
+static inline void __cpuinit arch_counter_set_user_access(void)
+{
+ u32 cntkctl;
+
+ asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl));
+
+ /* disable user access to everything */
+ cntkctl &= ~((3 << 8) | (7 << 0));
+
+ asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl));
+}
#else
static inline int arch_timer_of_register(void)
{
@@ -18,11 +120,6 @@ static inline int arch_timer_sched_clock_init(void)
{
return -ENXIO;
}
-
-static inline struct timecounter *arch_timer_get_timecounter(void)
-{
- return NULL;
-}
#endif
#endif
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index eb87200aa4b5..05ee9eebad6b 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -246,18 +246,14 @@
*
* This macro is intended for forcing the CPU into SVC mode at boot time.
* you cannot return to the original mode.
- *
- * Beware, it also clobers LR.
*/
.macro safe_svcmode_maskall reg:req
#if __LINUX_ARM_ARCH__ >= 6
mrs \reg , cpsr
- mov lr , \reg
- and lr , lr , #MODE_MASK
- cmp lr , #HYP_MODE
- orr \reg , \reg , #PSR_I_BIT | PSR_F_BIT
+ eor \reg, \reg, #HYP_MODE
+ tst \reg, #MODE_MASK
bic \reg , \reg , #MODE_MASK
- orr \reg , \reg , #SVC_MODE
+ orr \reg , \reg , #PSR_I_BIT | PSR_F_BIT | SVC_MODE
THUMB( orr \reg , \reg , #PSR_T_BIT )
bne 1f
orr \reg, \reg, #PSR_A_BIT
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index a59dcb5ab5fc..ad41ec2471e8 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -64,6 +64,24 @@ extern unsigned int processor_id;
#define read_cpuid_ext(reg) 0
#endif
+#define ARM_CPU_IMP_ARM 0x41
+#define ARM_CPU_IMP_INTEL 0x69
+
+#define ARM_CPU_PART_ARM1136 0xB360
+#define ARM_CPU_PART_ARM1156 0xB560
+#define ARM_CPU_PART_ARM1176 0xB760
+#define ARM_CPU_PART_ARM11MPCORE 0xB020
+#define ARM_CPU_PART_CORTEX_A8 0xC080
+#define ARM_CPU_PART_CORTEX_A9 0xC090
+#define ARM_CPU_PART_CORTEX_A5 0xC050
+#define ARM_CPU_PART_CORTEX_A15 0xC0F0
+#define ARM_CPU_PART_CORTEX_A7 0xC070
+
+#define ARM_CPU_XSCALE_ARCH_MASK 0xe000
+#define ARM_CPU_XSCALE_ARCH_V1 0x2000
+#define ARM_CPU_XSCALE_ARCH_V2 0x4000
+#define ARM_CPU_XSCALE_ARCH_V3 0x6000
+
/*
* The CPU ID never changes at run time, so we might as well tell the
* compiler that it's constant. Use this function to read the CPU ID
@@ -74,6 +92,21 @@ static inline unsigned int __attribute_const__ read_cpuid_id(void)
return read_cpuid(CPUID_ID);
}
+static inline unsigned int __attribute_const__ read_cpuid_implementor(void)
+{
+ return (read_cpuid_id() & 0xFF000000) >> 24;
+}
+
+static inline unsigned int __attribute_const__ read_cpuid_part_number(void)
+{
+ return read_cpuid_id() & 0xFFF0;
+}
+
+static inline unsigned int __attribute_const__ xscale_cpu_arch_version(void)
+{
+ return read_cpuid_part_number() & ARM_CPU_XSCALE_ARCH_MASK;
+}
+
static inline unsigned int __attribute_const__ read_cpuid_cachetype(void)
{
return read_cpuid(CPUID_CACHETYPE);
diff --git a/arch/arm/include/asm/cti.h b/arch/arm/include/asm/cti.h
index f2e5cad3f306..2381199acb7d 100644
--- a/arch/arm/include/asm/cti.h
+++ b/arch/arm/include/asm/cti.h
@@ -2,6 +2,7 @@
#define __ASMARM_CTI_H
#include <asm/io.h>
+#include <asm/hardware/coresight.h>
/* The registers' definition is from section 3.2 of
* Embedded Cross Trigger Revision: r0p0
@@ -35,11 +36,6 @@
#define LOCKACCESS 0xFB0
#define LOCKSTATUS 0xFB4
-/* write this value to LOCKACCESS will unlock the module, and
- * other value will lock the module
- */
-#define LOCKCODE 0xC5ACCE55
-
/**
* struct cti - cross trigger interface struct
* @base: mapped virtual address for the cti base
@@ -146,7 +142,7 @@ static inline void cti_irq_ack(struct cti *cti)
*/
static inline void cti_unlock(struct cti *cti)
{
- __raw_writel(LOCKCODE, cti->base + LOCKACCESS);
+ __raw_writel(CS_LAR_KEY, cti->base + LOCKACCESS);
}
/**
@@ -158,6 +154,6 @@ static inline void cti_unlock(struct cti *cti)
*/
static inline void cti_lock(struct cti *cti)
{
- __raw_writel(~LOCKCODE, cti->base + LOCKACCESS);
+ __raw_writel(~CS_LAR_KEY, cti->base + LOCKACCESS);
}
#endif
diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h
index 5694a0d6576b..58b8c6a0ab1f 100644
--- a/arch/arm/include/asm/dma.h
+++ b/arch/arm/include/asm/dma.h
@@ -105,7 +105,7 @@ extern void set_dma_sg(unsigned int chan, struct scatterlist *sg, int nr_sg);
*/
extern void __set_dma_addr(unsigned int chan, void *addr);
#define set_dma_addr(chan, addr) \
- __set_dma_addr(chan, bus_to_virt(addr))
+ __set_dma_addr(chan, (void *)__bus_to_virt(addr))
/* Set the DMA byte count for this channel
*
diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h
index 7ecd793b8f5a..0cf7a6b842ff 100644
--- a/arch/arm/include/asm/hardware/coresight.h
+++ b/arch/arm/include/asm/hardware/coresight.h
@@ -36,7 +36,7 @@
/* CoreSight Component Registers */
#define CSCR_CLASS 0xff4
-#define UNLOCK_MAGIC 0xc5acce55
+#define CS_LAR_KEY 0xc5acce55
/* ETM control register, "ETM Architecture", 3.3.1 */
#define ETMR_CTRL 0
@@ -147,11 +147,11 @@
#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0)
#define etm_unlock(t) \
- do { etm_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
+ do { etm_writel((t), CS_LAR_KEY, CSMR_LOCKACCESS); } while (0)
#define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0)
#define etb_unlock(t) \
- do { etb_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
+ do { etb_writel((t), CS_LAR_KEY, CSMR_LOCKACCESS); } while (0)
#endif /* __ASM_HARDWARE_CORESIGHT_H */
diff --git a/arch/arm/include/asm/hw_breakpoint.h b/arch/arm/include/asm/hw_breakpoint.h
index 01169dd723f1..eef55ea9ef00 100644
--- a/arch/arm/include/asm/hw_breakpoint.h
+++ b/arch/arm/include/asm/hw_breakpoint.h
@@ -85,6 +85,9 @@ static inline void decode_ctrl_reg(u32 reg,
#define ARM_DSCR_HDBGEN (1 << 14)
#define ARM_DSCR_MDBGEN (1 << 15)
+/* OSLSR os lock model bits */
+#define ARM_OSLSR_OSLM0 (1 << 0)
+
/* opcode2 numbers for the co-processor instructions. */
#define ARM_OP2_BVR 4
#define ARM_OP2_BCR 5
diff --git a/arch/arm/include/asm/idmap.h b/arch/arm/include/asm/idmap.h
index bf863edb517d..1a66f907e5cc 100644
--- a/arch/arm/include/asm/idmap.h
+++ b/arch/arm/include/asm/idmap.h
@@ -8,6 +8,7 @@
#define __idmap __section(.idmap.text) noinline notrace
extern pgd_t *idmap_pgd;
+extern pgd_t *hyp_pgd;
void setup_mm_for_reboot(void);
diff --git a/arch/arm/include/asm/kvm_arch_timer.h b/arch/arm/include/asm/kvm_arch_timer.h
new file mode 100644
index 000000000000..68cb9e1dfb81
--- /dev/null
+++ b/arch/arm/include/asm/kvm_arch_timer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_ARM_KVM_ARCH_TIMER_H
+#define __ASM_ARM_KVM_ARCH_TIMER_H
+
+#include <linux/clocksource.h>
+#include <linux/hrtimer.h>
+#include <linux/workqueue.h>
+
+struct arch_timer_kvm {
+#ifdef CONFIG_KVM_ARM_TIMER
+ /* Is the timer enabled */
+ bool enabled;
+
+ /* Virtual offset */
+ cycle_t cntvoff;
+#endif
+};
+
+struct arch_timer_cpu {
+#ifdef CONFIG_KVM_ARM_TIMER
+ /* Registers: control register, timer value */
+ u32 cntv_ctl; /* Saved/restored */
+ cycle_t cntv_cval; /* Saved/restored */
+
+ /*
+ * Anything that is not used directly from assembly code goes
+ * here.
+ */
+
+ /* Background timer used when the guest is not running */
+ struct hrtimer timer;
+
+ /* Work queued with the above timer expires */
+ struct work_struct expired;
+
+ /* Background timer active */
+ bool armed;
+
+ /* Timer IRQ */
+ const struct kvm_irq_level *irq;
+#endif
+};
+
+#ifdef CONFIG_KVM_ARM_TIMER
+int kvm_timer_hyp_init(void);
+int kvm_timer_init(struct kvm *kvm);
+void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
+void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu);
+void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu);
+void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu);
+#else
+static inline int kvm_timer_hyp_init(void)
+{
+ return 0;
+};
+
+static inline int kvm_timer_init(struct kvm *kvm)
+{
+ return 0;
+}
+
+static inline void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) {}
+static inline void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) {}
+static inline void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) {}
+static inline void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu) {}
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
new file mode 100644
index 000000000000..7c3d813e15df
--- /dev/null
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_ARM_H__
+#define __ARM_KVM_ARM_H__
+
+#include <linux/types.h>
+
+/* Hyp Configuration Register (HCR) bits */
+#define HCR_TGE (1 << 27)
+#define HCR_TVM (1 << 26)
+#define HCR_TTLB (1 << 25)
+#define HCR_TPU (1 << 24)
+#define HCR_TPC (1 << 23)
+#define HCR_TSW (1 << 22)
+#define HCR_TAC (1 << 21)
+#define HCR_TIDCP (1 << 20)
+#define HCR_TSC (1 << 19)
+#define HCR_TID3 (1 << 18)
+#define HCR_TID2 (1 << 17)
+#define HCR_TID1 (1 << 16)
+#define HCR_TID0 (1 << 15)
+#define HCR_TWE (1 << 14)
+#define HCR_TWI (1 << 13)
+#define HCR_DC (1 << 12)
+#define HCR_BSU (3 << 10)
+#define HCR_BSU_IS (1 << 10)
+#define HCR_FB (1 << 9)
+#define HCR_VA (1 << 8)
+#define HCR_VI (1 << 7)
+#define HCR_VF (1 << 6)
+#define HCR_AMO (1 << 5)
+#define HCR_IMO (1 << 4)
+#define HCR_FMO (1 << 3)
+#define HCR_PTW (1 << 2)
+#define HCR_SWIO (1 << 1)
+#define HCR_VM 1
+
+/*
+ * The bits we set in HCR:
+ * TAC: Trap ACTLR
+ * TSC: Trap SMC
+ * TSW: Trap cache operations by set/way
+ * TWI: Trap WFI
+ * TIDCP: Trap L2CTLR/L2ECTLR
+ * BSU_IS: Upgrade barriers to the inner shareable domain
+ * FB: Force broadcast of all maintainance operations
+ * AMO: Override CPSR.A and enable signaling with VA
+ * IMO: Override CPSR.I and enable signaling with VI
+ * FMO: Override CPSR.F and enable signaling with VF
+ * SWIO: Turn set/way invalidates into set/way clean+invalidate
+ */
+#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
+ HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
+ HCR_SWIO | HCR_TIDCP)
+#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
+
+/* System Control Register (SCTLR) bits */
+#define SCTLR_TE (1 << 30)
+#define SCTLR_EE (1 << 25)
+#define SCTLR_V (1 << 13)
+
+/* Hyp System Control Register (HSCTLR) bits */
+#define HSCTLR_TE (1 << 30)
+#define HSCTLR_EE (1 << 25)
+#define HSCTLR_FI (1 << 21)
+#define HSCTLR_WXN (1 << 19)
+#define HSCTLR_I (1 << 12)
+#define HSCTLR_C (1 << 2)
+#define HSCTLR_A (1 << 1)
+#define HSCTLR_M 1
+#define HSCTLR_MASK (HSCTLR_M | HSCTLR_A | HSCTLR_C | HSCTLR_I | \
+ HSCTLR_WXN | HSCTLR_FI | HSCTLR_EE | HSCTLR_TE)
+
+/* TTBCR and HTCR Registers bits */
+#define TTBCR_EAE (1 << 31)
+#define TTBCR_IMP (1 << 30)
+#define TTBCR_SH1 (3 << 28)
+#define TTBCR_ORGN1 (3 << 26)
+#define TTBCR_IRGN1 (3 << 24)
+#define TTBCR_EPD1 (1 << 23)
+#define TTBCR_A1 (1 << 22)
+#define TTBCR_T1SZ (3 << 16)
+#define TTBCR_SH0 (3 << 12)
+#define TTBCR_ORGN0 (3 << 10)
+#define TTBCR_IRGN0 (3 << 8)
+#define TTBCR_EPD0 (1 << 7)
+#define TTBCR_T0SZ 3
+#define HTCR_MASK (TTBCR_T0SZ | TTBCR_IRGN0 | TTBCR_ORGN0 | TTBCR_SH0)
+
+/* Hyp System Trap Register */
+#define HSTR_T(x) (1 << x)
+#define HSTR_TTEE (1 << 16)
+#define HSTR_TJDBX (1 << 17)
+
+/* Hyp Coprocessor Trap Register */
+#define HCPTR_TCP(x) (1 << x)
+#define HCPTR_TCP_MASK (0x3fff)
+#define HCPTR_TASE (1 << 15)
+#define HCPTR_TTA (1 << 20)
+#define HCPTR_TCPAC (1 << 31)
+
+/* Hyp Debug Configuration Register bits */
+#define HDCR_TDRA (1 << 11)
+#define HDCR_TDOSA (1 << 10)
+#define HDCR_TDA (1 << 9)
+#define HDCR_TDE (1 << 8)
+#define HDCR_HPME (1 << 7)
+#define HDCR_TPM (1 << 6)
+#define HDCR_TPMCR (1 << 5)
+#define HDCR_HPMN_MASK (0x1F)
+
+/*
+ * The architecture supports 40-bit IPA as input to the 2nd stage translations
+ * and PTRS_PER_S2_PGD becomes 1024, because each entry covers 1GB of address
+ * space.
+ */
+#define KVM_PHYS_SHIFT (40)
+#define KVM_PHYS_SIZE (1ULL << KVM_PHYS_SHIFT)
+#define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1ULL)
+#define PTRS_PER_S2_PGD (1ULL << (KVM_PHYS_SHIFT - 30))
+#define S2_PGD_ORDER get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
+#define S2_PGD_SIZE (1 << S2_PGD_ORDER)
+
+/* Virtualization Translation Control Register (VTCR) bits */
+#define VTCR_SH0 (3 << 12)
+#define VTCR_ORGN0 (3 << 10)
+#define VTCR_IRGN0 (3 << 8)
+#define VTCR_SL0 (3 << 6)
+#define VTCR_S (1 << 4)
+#define VTCR_T0SZ (0xf)
+#define VTCR_MASK (VTCR_SH0 | VTCR_ORGN0 | VTCR_IRGN0 | VTCR_SL0 | \
+ VTCR_S | VTCR_T0SZ)
+#define VTCR_HTCR_SH (VTCR_SH0 | VTCR_ORGN0 | VTCR_IRGN0)
+#define VTCR_SL_L2 (0 << 6) /* Starting-level: 2 */
+#define VTCR_SL_L1 (1 << 6) /* Starting-level: 1 */
+#define KVM_VTCR_SL0 VTCR_SL_L1
+/* stage-2 input address range defined as 2^(32-T0SZ) */
+#define KVM_T0SZ (32 - KVM_PHYS_SHIFT)
+#define KVM_VTCR_T0SZ (KVM_T0SZ & VTCR_T0SZ)
+#define KVM_VTCR_S ((KVM_VTCR_T0SZ << 1) & VTCR_S)
+
+/* Virtualization Translation Table Base Register (VTTBR) bits */
+#if KVM_VTCR_SL0 == VTCR_SL_L2 /* see ARM DDI 0406C: B4-1720 */
+#define VTTBR_X (14 - KVM_T0SZ)
+#else
+#define VTTBR_X (5 - KVM_T0SZ)
+#endif
+#define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
+#define VTTBR_BADDR_MASK (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
+#define VTTBR_VMID_SHIFT (48LLU)
+#define VTTBR_VMID_MASK (0xffLLU << VTTBR_VMID_SHIFT)
+
+/* Hyp Syndrome Register (HSR) bits */
+#define HSR_EC_SHIFT (26)
+#define HSR_EC (0x3fU << HSR_EC_SHIFT)
+#define HSR_IL (1U << 25)
+#define HSR_ISS (HSR_IL - 1)
+#define HSR_ISV_SHIFT (24)
+#define HSR_ISV (1U << HSR_ISV_SHIFT)
+#define HSR_SRT_SHIFT (16)
+#define HSR_SRT_MASK (0xf << HSR_SRT_SHIFT)
+#define HSR_FSC (0x3f)
+#define HSR_FSC_TYPE (0x3c)
+#define HSR_SSE (1 << 21)
+#define HSR_WNR (1 << 6)
+#define HSR_CV_SHIFT (24)
+#define HSR_CV (1U << HSR_CV_SHIFT)
+#define HSR_COND_SHIFT (20)
+#define HSR_COND (0xfU << HSR_COND_SHIFT)
+
+#define FSC_FAULT (0x04)
+#define FSC_PERM (0x0c)
+
+/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
+#define HPFAR_MASK (~0xf)
+
+#define HSR_EC_UNKNOWN (0x00)
+#define HSR_EC_WFI (0x01)
+#define HSR_EC_CP15_32 (0x03)
+#define HSR_EC_CP15_64 (0x04)
+#define HSR_EC_CP14_MR (0x05)
+#define HSR_EC_CP14_LS (0x06)
+#define HSR_EC_CP_0_13 (0x07)
+#define HSR_EC_CP10_ID (0x08)
+#define HSR_EC_JAZELLE (0x09)
+#define HSR_EC_BXJ (0x0A)
+#define HSR_EC_CP14_64 (0x0C)
+#define HSR_EC_SVC_HYP (0x11)
+#define HSR_EC_HVC (0x12)
+#define HSR_EC_SMC (0x13)
+#define HSR_EC_IABT (0x20)
+#define HSR_EC_IABT_HYP (0x21)
+#define HSR_EC_DABT (0x24)
+#define HSR_EC_DABT_HYP (0x25)
+
+#define HSR_HVC_IMM_MASK ((1UL << 16) - 1)
+
+#endif /* __ARM_KVM_ARM_H__ */
diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
new file mode 100644
index 000000000000..e4956f4e23e1
--- /dev/null
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_ASM_H__
+#define __ARM_KVM_ASM_H__
+
+/* 0 is reserved as an invalid value. */
+#define c0_MPIDR 1 /* MultiProcessor ID Register */
+#define c0_CSSELR 2 /* Cache Size Selection Register */
+#define c1_SCTLR 3 /* System Control Register */
+#define c1_ACTLR 4 /* Auxilliary Control Register */
+#define c1_CPACR 5 /* Coprocessor Access Control */
+#define c2_TTBR0 6 /* Translation Table Base Register 0 */
+#define c2_TTBR0_high 7 /* TTBR0 top 32 bits */
+#define c2_TTBR1 8 /* Translation Table Base Register 1 */
+#define c2_TTBR1_high 9 /* TTBR1 top 32 bits */
+#define c2_TTBCR 10 /* Translation Table Base Control R. */
+#define c3_DACR 11 /* Domain Access Control Register */
+#define c5_DFSR 12 /* Data Fault Status Register */
+#define c5_IFSR 13 /* Instruction Fault Status Register */
+#define c5_ADFSR 14 /* Auxilary Data Fault Status R */
+#define c5_AIFSR 15 /* Auxilary Instrunction Fault Status R */
+#define c6_DFAR 16 /* Data Fault Address Register */
+#define c6_IFAR 17 /* Instruction Fault Address Register */
+#define c9_L2CTLR 18 /* Cortex A15 L2 Control Register */
+#define c10_PRRR 19 /* Primary Region Remap Register */
+#define c10_NMRR 20 /* Normal Memory Remap Register */
+#define c12_VBAR 21 /* Vector Base Address Register */
+#define c13_CID 22 /* Context ID Register */
+#define c13_TID_URW 23 /* Thread ID, User R/W */
+#define c13_TID_URO 24 /* Thread ID, User R/O */
+#define c13_TID_PRIV 25 /* Thread ID, Privileged */
+#define c14_CNTKCTL 26 /* Timer Control Register (PL1) */
+#define NR_CP15_REGS 27 /* Number of regs (incl. invalid) */
+
+#define ARM_EXCEPTION_RESET 0
+#define ARM_EXCEPTION_UNDEFINED 1
+#define ARM_EXCEPTION_SOFTWARE 2
+#define ARM_EXCEPTION_PREF_ABORT 3
+#define ARM_EXCEPTION_DATA_ABORT 4
+#define ARM_EXCEPTION_IRQ 5
+#define ARM_EXCEPTION_FIQ 6
+#define ARM_EXCEPTION_HVC 7
+
+#ifndef __ASSEMBLY__
+struct kvm;
+struct kvm_vcpu;
+
+extern char __kvm_hyp_init[];
+extern char __kvm_hyp_init_end[];
+
+extern char __kvm_hyp_exit[];
+extern char __kvm_hyp_exit_end[];
+
+extern char __kvm_hyp_vector[];
+
+extern char __kvm_hyp_code_start[];
+extern char __kvm_hyp_code_end[];
+
+extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
+
+extern void __kvm_flush_vm_context(void);
+extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
+
+extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+#endif
+
+#endif /* __ARM_KVM_ASM_H__ */
diff --git a/arch/arm/include/asm/kvm_coproc.h b/arch/arm/include/asm/kvm_coproc.h
new file mode 100644
index 000000000000..4917c2f7e459
--- /dev/null
+++ b/arch/arm/include/asm/kvm_coproc.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 Rusty Russell IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_COPROC_H__
+#define __ARM_KVM_COPROC_H__
+#include <linux/kvm_host.h>
+
+void kvm_reset_coprocs(struct kvm_vcpu *vcpu);
+
+struct kvm_coproc_target_table {
+ unsigned target;
+ const struct coproc_reg *table;
+ size_t num;
+};
+void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table);
+
+int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
+
+unsigned long kvm_arm_num_guest_msrs(struct kvm_vcpu *vcpu);
+int kvm_arm_copy_msrindices(struct kvm_vcpu *vcpu, u64 __user *uindices);
+void kvm_coproc_table_init(void);
+
+struct kvm_one_reg;
+int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
+int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
+int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
+unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu);
+#endif /* __ARM_KVM_COPROC_H__ */
diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
new file mode 100644
index 000000000000..fd611996bfb5
--- /dev/null
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_EMULATE_H__
+#define __ARM_KVM_EMULATE_H__
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmio.h>
+
+u32 *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num);
+u32 *vcpu_spsr(struct kvm_vcpu *vcpu);
+
+int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run);
+void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr);
+void kvm_inject_undefined(struct kvm_vcpu *vcpu);
+void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
+void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
+
+static inline bool vcpu_mode_is_32bit(struct kvm_vcpu *vcpu)
+{
+ return 1;
+}
+
+static inline u32 *vcpu_pc(struct kvm_vcpu *vcpu)
+{
+ return (u32 *)&vcpu->arch.regs.usr_regs.ARM_pc;
+}
+
+static inline u32 *vcpu_cpsr(struct kvm_vcpu *vcpu)
+{
+ return (u32 *)&vcpu->arch.regs.usr_regs.ARM_cpsr;
+}
+
+static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
+{
+ *vcpu_cpsr(vcpu) |= PSR_T_BIT;
+}
+
+static inline bool mode_has_spsr(struct kvm_vcpu *vcpu)
+{
+ unsigned long cpsr_mode = vcpu->arch.regs.usr_regs.ARM_cpsr & MODE_MASK;
+ return (cpsr_mode > USR_MODE && cpsr_mode < SYSTEM_MODE);
+}
+
+static inline bool vcpu_mode_priv(struct kvm_vcpu *vcpu)
+{
+ unsigned long cpsr_mode = vcpu->arch.regs.usr_regs.ARM_cpsr & MODE_MASK;
+ return cpsr_mode > USR_MODE;;
+}
+
+static inline bool kvm_vcpu_reg_is_pc(struct kvm_vcpu *vcpu, int reg)
+{
+ return reg == 15;
+}
+
+#endif /* __ARM_KVM_EMULATE_H__ */
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
new file mode 100644
index 000000000000..d1736a53b12d
--- /dev/null
+++ b/arch/arm/include/asm/kvm_host.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_HOST_H__
+#define __ARM_KVM_HOST_H__
+
+#include <asm/kvm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmio.h>
+#include <asm/fpstate.h>
+#include <asm/kvm_arch_timer.h>
+
+#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
+#define KVM_USER_MEM_SLOTS 32
+#define KVM_PRIVATE_MEM_SLOTS 4
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+#define KVM_HAVE_ONE_REG
+
+#define KVM_VCPU_MAX_FEATURES 1
+
+/* We don't currently support large pages. */
+#define KVM_HPAGE_GFN_SHIFT(x) 0
+#define KVM_NR_PAGE_SIZES 1
+#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
+
+#include <asm/kvm_vgic.h>
+
+struct kvm_vcpu;
+u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
+int kvm_target_cpu(void);
+int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
+void kvm_reset_coprocs(struct kvm_vcpu *vcpu);
+
+struct kvm_arch {
+ /* VTTBR value associated with below pgd and vmid */
+ u64 vttbr;
+
+ /* Timer */
+ struct arch_timer_kvm timer;
+
+ /*
+ * Anything that is not used directly from assembly code goes
+ * here.
+ */
+
+ /* The VMID generation used for the virt. memory system */
+ u64 vmid_gen;
+ u32 vmid;
+
+ /* Stage-2 page table */
+ pgd_t *pgd;
+
+ /* Interrupt controller */
+ struct vgic_dist vgic;
+};
+
+#define KVM_NR_MEM_OBJS 40
+
+/*
+ * We don't want allocation failures within the mmu code, so we preallocate
+ * enough memory for a single page fault in a cache.
+ */
+struct kvm_mmu_memory_cache {
+ int nobjs;
+ void *objects[KVM_NR_MEM_OBJS];
+};
+
+struct kvm_vcpu_arch {
+ struct kvm_regs regs;
+
+ int target; /* Processor target */
+ DECLARE_BITMAP(features, KVM_VCPU_MAX_FEATURES);
+
+ /* System control coprocessor (cp15) */
+ u32 cp15[NR_CP15_REGS];
+
+ /* The CPU type we expose to the VM */
+ u32 midr;
+
+ /* Exception Information */
+ u32 hsr; /* Hyp Syndrome Register */
+ u32 hxfar; /* Hyp Data/Inst Fault Address Register */
+ u32 hpfar; /* Hyp IPA Fault Address Register */
+
+ /* Floating point registers (VFP and Advanced SIMD/NEON) */
+ struct vfp_hard_struct vfp_guest;
+ struct vfp_hard_struct *vfp_host;
+
+ /* VGIC state */
+ struct vgic_cpu vgic_cpu;
+ struct arch_timer_cpu timer_cpu;
+
+ /*
+ * Anything that is not used directly from assembly code goes
+ * here.
+ */
+ /* dcache set/way operation pending */
+ int last_pcpu;
+ cpumask_t require_dcache_flush;
+
+ /* Don't run the guest on this vcpu */
+ bool pause;
+
+ /* IO related fields */
+ struct kvm_decode mmio_decode;
+
+ /* Interrupt related fields */
+ u32 irq_lines; /* IRQ and FIQ levels */
+
+ /* Hyp exception information */
+ u32 hyp_pc; /* PC when exception was taken from Hyp mode */
+
+ /* Cache some mmu pages needed inside spinlock regions */
+ struct kvm_mmu_memory_cache mmu_page_cache;
+
+ /* Detect first run of a vcpu */
+ bool has_run_once;
+};
+
+struct kvm_vm_stat {
+ u32 remote_tlb_flush;
+};
+
+struct kvm_vcpu_stat {
+ u32 halt_wakeup;
+};
+
+struct kvm_vcpu_init;
+int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
+ const struct kvm_vcpu_init *init);
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
+int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
+struct kvm_one_reg;
+int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+u64 kvm_call_hyp(void *hypfn, ...);
+void force_vm_exit(const cpumask_t *mask);
+
+#define KVM_ARCH_WANT_MMU_NOTIFIER
+struct kvm;
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+int kvm_unmap_hva_range(struct kvm *kvm,
+ unsigned long start, unsigned long end);
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
+
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
+int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
+
+/* We do not have shadow page tables, hence the empty hooks */
+static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+ return 0;
+}
+
+static inline int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+ return 0;
+}
+
+struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
+struct kvm_vcpu __percpu **kvm_get_running_vcpus(void);
+
+int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
+unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu);
+struct kvm_one_reg;
+int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
+int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
+
+#endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm/include/asm/kvm_mmio.h b/arch/arm/include/asm/kvm_mmio.h
new file mode 100644
index 000000000000..adcc0d7d3175
--- /dev/null
+++ b/arch/arm/include/asm/kvm_mmio.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_MMIO_H__
+#define __ARM_KVM_MMIO_H__
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+
+struct kvm_decode {
+ unsigned long rt;
+ bool sign_extend;
+};
+
+/*
+ * The in-kernel MMIO emulation code wants to use a copy of run->mmio,
+ * which is an anonymous type. Use our own type instead.
+ */
+struct kvm_exit_mmio {
+ phys_addr_t phys_addr;
+ u8 data[8];
+ u32 len;
+ bool is_write;
+};
+
+static inline void kvm_prepare_mmio(struct kvm_run *run,
+ struct kvm_exit_mmio *mmio)
+{
+ run->mmio.phys_addr = mmio->phys_addr;
+ run->mmio.len = mmio->len;
+ run->mmio.is_write = mmio->is_write;
+ memcpy(run->mmio.data, mmio->data, mmio->len);
+ run->exit_reason = KVM_EXIT_MMIO;
+}
+
+int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ phys_addr_t fault_ipa);
+
+#endif /* __ARM_KVM_MMIO_H__ */
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
new file mode 100644
index 000000000000..421a20b34874
--- /dev/null
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_MMU_H__
+#define __ARM_KVM_MMU_H__
+
+int create_hyp_mappings(void *from, void *to);
+int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
+void free_hyp_pmds(void);
+
+int kvm_alloc_stage2_pgd(struct kvm *kvm);
+void kvm_free_stage2_pgd(struct kvm *kvm);
+int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
+ phys_addr_t pa, unsigned long size);
+
+int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
+
+void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
+
+phys_addr_t kvm_mmu_get_httbr(void);
+int kvm_mmu_init(void);
+void kvm_clear_hyp_idmap(void);
+
+static inline bool kvm_is_write_fault(unsigned long hsr)
+{
+ unsigned long hsr_ec = hsr >> HSR_EC_SHIFT;
+ if (hsr_ec == HSR_EC_IABT)
+ return false;
+ else if ((hsr & HSR_ISV) && !(hsr & HSR_WNR))
+ return false;
+ else
+ return true;
+}
+
+#endif /* __ARM_KVM_MMU_H__ */
diff --git a/include/clocksource/arm_generic.h b/arch/arm/include/asm/kvm_psci.h
index 5b41b0d27f0f..9a83d98bf170 100644
--- a/include/clocksource/arm_generic.h
+++ b/arch/arm/include/asm/kvm_psci.h
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2012 ARM Ltd.
+ * Copyright (C) 2012 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.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
@@ -13,9 +14,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __CLKSOURCE_ARM_GENERIC_H
-#define __CLKSOURCE_ARM_GENERIC_H
-extern int arm_generic_timer_init(void);
+#ifndef __ARM_KVM_PSCI_H__
+#define __ARM_KVM_PSCI_H__
-#endif
+bool kvm_psci_call(struct kvm_vcpu *vcpu);
+
+#endif /* __ARM_KVM_PSCI_H__ */
diff --git a/arch/arm/include/asm/kvm_vgic.h b/arch/arm/include/asm/kvm_vgic.h
new file mode 100644
index 000000000000..ab97207d9cd3
--- /dev/null
+++ b/arch/arm/include/asm/kvm_vgic.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_ARM_KVM_VGIC_H
+#define __ASM_ARM_KVM_VGIC_H
+
+#include <linux/kernel.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/irqreturn.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/irqchip/arm-gic.h>
+
+#define VGIC_NR_IRQS 128
+#define VGIC_NR_SGIS 16
+#define VGIC_NR_PPIS 16
+#define VGIC_NR_PRIVATE_IRQS (VGIC_NR_SGIS + VGIC_NR_PPIS)
+#define VGIC_NR_SHARED_IRQS (VGIC_NR_IRQS - VGIC_NR_PRIVATE_IRQS)
+#define VGIC_MAX_CPUS KVM_MAX_VCPUS
+#define VGIC_MAX_LRS (1 << 6)
+
+/* Sanity checks... */
+#if (VGIC_MAX_CPUS > 8)
+#error Invalid number of CPU interfaces
+#endif
+
+#if (VGIC_NR_IRQS & 31)
+#error "VGIC_NR_IRQS must be a multiple of 32"
+#endif
+
+#if (VGIC_NR_IRQS > 1024)
+#error "VGIC_NR_IRQS must be <= 1024"
+#endif
+
+/*
+ * The GIC distributor registers describing interrupts have two parts:
+ * - 32 per-CPU interrupts (SGI + PPI)
+ * - a bunch of shared interrupts (SPI)
+ */
+struct vgic_bitmap {
+ union {
+ u32 reg[VGIC_NR_PRIVATE_IRQS / 32];
+ DECLARE_BITMAP(reg_ul, VGIC_NR_PRIVATE_IRQS);
+ } percpu[VGIC_MAX_CPUS];
+ union {
+ u32 reg[VGIC_NR_SHARED_IRQS / 32];
+ DECLARE_BITMAP(reg_ul, VGIC_NR_SHARED_IRQS);
+ } shared;
+};
+
+struct vgic_bytemap {
+ u32 percpu[VGIC_MAX_CPUS][VGIC_NR_PRIVATE_IRQS / 4];
+ u32 shared[VGIC_NR_SHARED_IRQS / 4];
+};
+
+struct vgic_dist {
+#ifdef CONFIG_KVM_ARM_VGIC
+ spinlock_t lock;
+ bool ready;
+
+ /* Virtual control interface mapping */
+ void __iomem *vctrl_base;
+
+ /* Distributor and vcpu interface mapping in the guest */
+ phys_addr_t vgic_dist_base;
+ phys_addr_t vgic_cpu_base;
+
+ /* Distributor enabled */
+ u32 enabled;
+
+ /* Interrupt enabled (one bit per IRQ) */
+ struct vgic_bitmap irq_enabled;
+
+ /* Interrupt 'pin' level */
+ struct vgic_bitmap irq_state;
+
+ /* Level-triggered interrupt in progress */
+ struct vgic_bitmap irq_active;
+
+ /* Interrupt priority. Not used yet. */
+ struct vgic_bytemap irq_priority;
+
+ /* Level/edge triggered */
+ struct vgic_bitmap irq_cfg;
+
+ /* Source CPU per SGI and target CPU */
+ u8 irq_sgi_sources[VGIC_MAX_CPUS][VGIC_NR_SGIS];
+
+ /* Target CPU for each IRQ */
+ u8 irq_spi_cpu[VGIC_NR_SHARED_IRQS];
+ struct vgic_bitmap irq_spi_target[VGIC_MAX_CPUS];
+
+ /* Bitmap indicating which CPU has something pending */
+ unsigned long irq_pending_on_cpu;
+#endif
+};
+
+struct vgic_cpu {
+#ifdef CONFIG_KVM_ARM_VGIC
+ /* per IRQ to LR mapping */
+ u8 vgic_irq_lr_map[VGIC_NR_IRQS];
+
+ /* Pending interrupts on this VCPU */
+ DECLARE_BITMAP( pending_percpu, VGIC_NR_PRIVATE_IRQS);
+ DECLARE_BITMAP( pending_shared, VGIC_NR_SHARED_IRQS);
+
+ /* Bitmap of used/free list registers */
+ DECLARE_BITMAP( lr_used, VGIC_MAX_LRS);
+
+ /* Number of list registers on this CPU */
+ int nr_lr;
+
+ /* CPU vif control registers for world switch */
+ u32 vgic_hcr;
+ u32 vgic_vmcr;
+ u32 vgic_misr; /* Saved only */
+ u32 vgic_eisr[2]; /* Saved only */
+ u32 vgic_elrsr[2]; /* Saved only */
+ u32 vgic_apr;
+ u32 vgic_lr[VGIC_MAX_LRS];
+#endif
+};
+
+#define LR_EMPTY 0xff
+
+struct kvm;
+struct kvm_vcpu;
+struct kvm_run;
+struct kvm_exit_mmio;
+
+#ifdef CONFIG_KVM_ARM_VGIC
+int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr);
+int kvm_vgic_hyp_init(void);
+int kvm_vgic_init(struct kvm *kvm);
+int kvm_vgic_create(struct kvm *kvm);
+int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
+ bool level);
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
+bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ struct kvm_exit_mmio *mmio);
+
+#define irqchip_in_kernel(k) (!!((k)->arch.vgic.vctrl_base))
+#define vgic_initialized(k) ((k)->arch.vgic.ready)
+
+#else
+static inline int kvm_vgic_hyp_init(void)
+{
+ return 0;
+}
+
+static inline int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr)
+{
+ return 0;
+}
+
+static inline int kvm_vgic_init(struct kvm *kvm)
+{
+ return 0;
+}
+
+static inline int kvm_vgic_create(struct kvm *kvm)
+{
+ return 0;
+}
+
+static inline int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+static inline void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu) {}
+static inline void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) {}
+
+static inline int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid,
+ unsigned int irq_num, bool level)
+{
+ return 0;
+}
+
+static inline int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+static inline bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ struct kvm_exit_mmio *mmio)
+{
+ return false;
+}
+
+static inline int irqchip_in_kernel(struct kvm *kvm)
+{
+ return 0;
+}
+
+static inline bool vgic_initialized(struct kvm *kvm)
+{
+ return true;
+}
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
index 917d4fcfd9b4..308ad7d6f98b 100644
--- a/arch/arm/include/asm/mach/arch.h
+++ b/arch/arm/include/asm/mach/arch.h
@@ -12,7 +12,6 @@
struct tag;
struct meminfo;
-struct sys_timer;
struct pt_regs;
struct smp_operations;
#ifdef CONFIG_SMP
@@ -48,7 +47,7 @@ struct machine_desc {
void (*map_io)(void);/* IO mapping function */
void (*init_early)(void);
void (*init_irq)(void);
- struct sys_timer *timer; /* system tick timer */
+ void (*init_time)(void);
void (*init_machine)(void);
void (*init_late)(void);
#ifdef CONFIG_MULTI_IRQ_HANDLER
diff --git a/arch/arm/include/asm/mach/irq.h b/arch/arm/include/asm/mach/irq.h
index 15cb035309f7..18c883023339 100644
--- a/arch/arm/include/asm/mach/irq.h
+++ b/arch/arm/include/asm/mach/irq.h
@@ -22,6 +22,7 @@ extern int show_fiq_list(struct seq_file *, int);
#ifdef CONFIG_MULTI_IRQ_HANDLER
extern void (*handle_arch_irq)(struct pt_regs *);
+extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
#endif
/*
diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
index db9fedb57f2c..5cf2e979b4be 100644
--- a/arch/arm/include/asm/mach/pci.h
+++ b/arch/arm/include/asm/mach/pci.h
@@ -23,6 +23,7 @@ struct hw_pci {
#endif
struct pci_ops *ops;
int nr_controllers;
+ void **private_data;
int (*setup)(int nr, struct pci_sys_data *);
struct pci_bus *(*scan)(int nr, struct pci_sys_data *);
void (*preinit)(void);
diff --git a/arch/arm/include/asm/mach/time.h b/arch/arm/include/asm/mach/time.h
index 6ca945f534ab..90c12e1e695c 100644
--- a/arch/arm/include/asm/mach/time.h
+++ b/arch/arm/include/asm/mach/time.h
@@ -10,36 +10,6 @@
#ifndef __ASM_ARM_MACH_TIME_H
#define __ASM_ARM_MACH_TIME_H
-/*
- * This is our kernel timer structure.
- *
- * - init
- * Initialise the kernels jiffy timer source, claim interrupt
- * using setup_irq. This is called early on during initialisation
- * while interrupts are still disabled on the local CPU.
- * - suspend
- * Suspend the kernel jiffy timer source, if necessary. This
- * is called with interrupts disabled, after all normal devices
- * have been suspended. If no action is required, set this to
- * NULL.
- * - resume
- * Resume the kernel jiffy timer source, if necessary. This
- * is called with interrupts disabled before any normal devices
- * are resumed. If no action is required, set this to NULL.
- * - offset
- * Return the timer offset in microseconds since the last timer
- * interrupt. Note: this must take account of any unprocessed
- * timer interrupt which may be pending.
- */
-struct sys_timer {
- void (*init)(void);
- void (*suspend)(void);
- void (*resume)(void);
-#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
- unsigned long (*offset)(void);
-#endif
-};
-
extern void timer_tick(void);
struct timespec;
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 73cf03aa981e..57870ab313c5 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -36,23 +36,23 @@
* TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
*/
#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET)
-#define TASK_SIZE (UL(CONFIG_PAGE_OFFSET) - UL(0x01000000))
-#define TASK_UNMAPPED_BASE (UL(CONFIG_PAGE_OFFSET) / 3)
+#define TASK_SIZE (UL(CONFIG_PAGE_OFFSET) - UL(SZ_16M))
+#define TASK_UNMAPPED_BASE ALIGN(TASK_SIZE / 3, SZ_16M)
/*
* The maximum size of a 26-bit user space task.
*/
-#define TASK_SIZE_26 UL(0x04000000)
+#define TASK_SIZE_26 (UL(1) << 26)
/*
* The module space lives between the addresses given by TASK_SIZE
* and PAGE_OFFSET - it must be within 32MB of the kernel text.
*/
#ifndef CONFIG_THUMB2_KERNEL
-#define MODULES_VADDR (PAGE_OFFSET - 16*1024*1024)
+#define MODULES_VADDR (PAGE_OFFSET - SZ_16M)
#else
/* smaller range for Thumb-2 symbols relocation (2^24)*/
-#define MODULES_VADDR (PAGE_OFFSET - 8*1024*1024)
+#define MODULES_VADDR (PAGE_OFFSET - SZ_8M)
#endif
#if TASK_SIZE > MODULES_VADDR
@@ -245,6 +245,7 @@ static inline void *phys_to_virt(phys_addr_t x)
#define __bus_to_pfn(x) __phys_to_pfn(x)
#endif
+#ifdef CONFIG_VIRT_TO_BUS
static inline __deprecated unsigned long virt_to_bus(void *x)
{
return __virt_to_bus((unsigned long)x);
@@ -254,6 +255,7 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
{
return (void *)__bus_to_virt(x);
}
+#endif
/*
* Conversion between a struct page and a physical address.
diff --git a/arch/arm/include/asm/opcodes-sec.h b/arch/arm/include/asm/opcodes-sec.h
new file mode 100644
index 000000000000..bc3a9174417c
--- /dev/null
+++ b/arch/arm/include/asm/opcodes-sec.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2012 ARM Limited
+ */
+
+#ifndef __ASM_ARM_OPCODES_SEC_H
+#define __ASM_ARM_OPCODES_SEC_H
+
+#include <asm/opcodes.h>
+
+#define __SMC(imm4) __inst_arm_thumb32( \
+ 0xE1600070 | (((imm4) & 0xF) << 0), \
+ 0xF7F08000 | (((imm4) & 0xF) << 16) \
+)
+
+#endif /* __ASM_ARM_OPCODES_SEC_H */
diff --git a/arch/arm/include/asm/opcodes.h b/arch/arm/include/asm/opcodes.h
index 74e211a6fb24..e796c598513b 100644
--- a/arch/arm/include/asm/opcodes.h
+++ b/arch/arm/include/asm/opcodes.h
@@ -10,6 +10,7 @@
#define __ASM_ARM_OPCODES_H
#ifndef __ASSEMBLY__
+#include <linux/linkage.h>
extern asmlinkage unsigned int arm_check_condition(u32 opcode, u32 psr);
#endif
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index 53426c66352a..12f71a190422 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -92,6 +92,7 @@ static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)
static inline void outer_flush_all(void) { }
static inline void outer_inv_all(void) { }
static inline void outer_disable(void) { }
+static inline void outer_resume(void) { }
#endif
diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h
index d7952824c5c4..18f5cef82ad5 100644
--- a/arch/arm/include/asm/pgtable-3level-hwdef.h
+++ b/arch/arm/include/asm/pgtable-3level-hwdef.h
@@ -32,6 +32,9 @@
#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0)
#define PMD_BIT4 (_AT(pmdval_t, 0))
#define PMD_DOMAIN(x) (_AT(pmdval_t, 0))
+#define PMD_APTABLE_SHIFT (61)
+#define PMD_APTABLE (_AT(pgdval_t, 3) << PGD_APTABLE_SHIFT)
+#define PMD_PXNTABLE (_AT(pgdval_t, 1) << 59)
/*
* - section
@@ -41,9 +44,11 @@
#define PMD_SECT_S (_AT(pmdval_t, 3) << 8)
#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10)
#define PMD_SECT_nG (_AT(pmdval_t, 1) << 11)
+#define PMD_SECT_PXN (_AT(pmdval_t, 1) << 53)
#define PMD_SECT_XN (_AT(pmdval_t, 1) << 54)
#define PMD_SECT_AP_WRITE (_AT(pmdval_t, 0))
#define PMD_SECT_AP_READ (_AT(pmdval_t, 0))
+#define PMD_SECT_AP1 (_AT(pmdval_t, 1) << 6)
#define PMD_SECT_TEX(x) (_AT(pmdval_t, 0))
/*
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index a3f37929940a..6ef8afd1b64c 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -104,11 +104,29 @@
*/
#define L_PGD_SWAPPER (_AT(pgdval_t, 1) << 55) /* swapper_pg_dir entry */
+/*
+ * 2nd stage PTE definitions for LPAE.
+ */
+#define L_PTE_S2_MT_UNCACHED (_AT(pteval_t, 0x5) << 2) /* MemAttr[3:0] */
+#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* MemAttr[3:0] */
+#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* MemAttr[3:0] */
+#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */
+#define L_PTE_S2_RDWR (_AT(pteval_t, 2) << 6) /* HAP[2:1] */
+
+/*
+ * Hyp-mode PL2 PTE definitions for LPAE.
+ */
+#define L_PTE_HYP L_PTE_USER
+
#ifndef __ASSEMBLY__
#define pud_none(pud) (!pud_val(pud))
#define pud_bad(pud) (!(pud_val(pud) & 2))
#define pud_present(pud) (pud_val(pud))
+#define pmd_table(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \
+ PMD_TYPE_TABLE)
+#define pmd_sect(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \
+ PMD_TYPE_SECT)
#define pud_clear(pudp) \
do { \
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 9c82f988c0e3..f30ac3b55ba9 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -70,6 +70,9 @@ extern void __pgd_error(const char *file, int line, pgd_t);
extern pgprot_t pgprot_user;
extern pgprot_t pgprot_kernel;
+extern pgprot_t pgprot_hyp_device;
+extern pgprot_t pgprot_s2;
+extern pgprot_t pgprot_s2_device;
#define _MOD_PROT(p, b) __pgprot(pgprot_val(p) | (b))
@@ -82,6 +85,10 @@ extern pgprot_t pgprot_kernel;
#define PAGE_READONLY_EXEC _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY)
#define PAGE_KERNEL _MOD_PROT(pgprot_kernel, L_PTE_XN)
#define PAGE_KERNEL_EXEC pgprot_kernel
+#define PAGE_HYP _MOD_PROT(pgprot_kernel, L_PTE_HYP)
+#define PAGE_HYP_DEVICE _MOD_PROT(pgprot_hyp_device, L_PTE_HYP)
+#define PAGE_S2 _MOD_PROT(pgprot_s2, L_PTE_S2_RDONLY)
+#define PAGE_S2_DEVICE _MOD_PROT(pgprot_s2_device, L_PTE_USER | L_PTE_S2_RDONLY)
#define __PAGE_NONE __pgprot(_L_PTE_DEFAULT | L_PTE_RDONLY | L_PTE_XN | L_PTE_NONE)
#define __PAGE_SHARED __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_XN)
diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
new file mode 100644
index 000000000000..ce0dbe7c1625
--- /dev/null
+++ b/arch/arm/include/asm/psci.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2012 ARM Limited
+ */
+
+#ifndef __ASM_ARM_PSCI_H
+#define __ASM_ARM_PSCI_H
+
+#define PSCI_POWER_STATE_TYPE_STANDBY 0
+#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1
+
+struct psci_power_state {
+ u16 id;
+ u8 type;
+ u8 affinity_level;
+};
+
+struct psci_operations {
+ int (*cpu_suspend)(struct psci_power_state state,
+ unsigned long entry_point);
+ int (*cpu_off)(struct psci_power_state state);
+ int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
+ int (*migrate)(unsigned long cpuid);
+};
+
+extern struct psci_operations psci_ops;
+
+#endif /* __ASM_ARM_PSCI_H */
diff --git a/arch/arm/include/asm/signal.h b/arch/arm/include/asm/signal.h
index 9a0ea6ab988f..c0eb412aff04 100644
--- a/arch/arm/include/asm/signal.h
+++ b/arch/arm/include/asm/signal.h
@@ -16,23 +16,7 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
-};
-
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#define __ARCH_HAS_SA_RESTORER
#include <asm/sigcontext.h>
#endif
diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h
index 4eb6d005ffaa..18d169373612 100644
--- a/arch/arm/include/asm/smp_scu.h
+++ b/arch/arm/include/asm/smp_scu.h
@@ -6,9 +6,32 @@
#define SCU_PM_POWEROFF 3
#ifndef __ASSEMBLER__
+
+#include <asm/cputype.h>
+
+static inline bool scu_a9_has_base(void)
+{
+ return read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9;
+}
+
+static inline unsigned long scu_a9_get_base(void)
+{
+ unsigned long pa;
+
+ asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (pa));
+
+ return pa;
+}
+
unsigned int scu_get_core_count(void __iomem *);
-void scu_enable(void __iomem *);
int scu_power_mode(void __iomem *, unsigned int);
+
+#ifdef CONFIG_SMP
+void scu_enable(void __iomem *scu_base);
+#else
+static inline void scu_enable(void __iomem *scu_base) {}
+#endif
+
#endif
#endif
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index b4ca707d0a69..6220e9fdf4c7 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -119,22 +119,8 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
- unsigned long tmp;
- u32 slock;
-
smp_mb();
-
- __asm__ __volatile__(
-" mov %1, #1\n"
-"1: ldrex %0, [%2]\n"
-" uadd16 %0, %0, %1\n"
-" strex %1, %0, [%2]\n"
-" teq %1, #0\n"
-" bne 1b"
- : "=&r" (slock), "=&r" (tmp)
- : "r" (&lock->slock)
- : "cc");
-
+ lock->tickets.owner++;
dsb_sev();
}
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
index 21a2700d2957..e4ddfb39ca34 100644
--- a/arch/arm/include/asm/unistd.h
+++ b/arch/arm/include/asm/unistd.h
@@ -26,8 +26,6 @@
#define __ARCH_WANT_SYS_NICE
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_OLD_MMAP
#define __ARCH_WANT_SYS_OLD_SELECT
diff --git a/arch/arm/include/asm/virt.h b/arch/arm/include/asm/virt.h
index 86164df86cb4..50af92bac737 100644
--- a/arch/arm/include/asm/virt.h
+++ b/arch/arm/include/asm/virt.h
@@ -24,9 +24,9 @@
/*
* Flag indicating that the kernel was not entered in the same mode on every
* CPU. The zImage loader stashes this value in an SPSR, so we need an
- * architecturally defined flag bit here (the N flag, as it happens)
+ * architecturally defined flag bit here.
*/
-#define BOOT_CPU_MODE_MISMATCH (1<<31)
+#define BOOT_CPU_MODE_MISMATCH PSR_N_BIT
#ifndef __ASSEMBLY__
diff --git a/arch/arm/include/asm/xen/events.h b/arch/arm/include/asm/xen/events.h
index 94b4e9020b02..5c27696de14f 100644
--- a/arch/arm/include/asm/xen/events.h
+++ b/arch/arm/include/asm/xen/events.h
@@ -15,4 +15,26 @@ static inline int xen_irqs_disabled(struct pt_regs *regs)
return raw_irqs_disabled_flags(regs->ARM_cpsr);
}
+/*
+ * We cannot use xchg because it does not support 8-byte
+ * values. However it is safe to use {ldr,dtd}exd directly because all
+ * platforms which Xen can run on support those instructions.
+ */
+static inline xen_ulong_t xchg_xen_ulong(xen_ulong_t *ptr, xen_ulong_t val)
+{
+ xen_ulong_t oldval;
+ unsigned int tmp;
+
+ wmb();
+ asm volatile("@ xchg_xen_ulong\n"
+ "1: ldrexd %0, %H0, [%3]\n"
+ " strexd %1, %2, %H2, [%3]\n"
+ " teq %1, #0\n"
+ " bne 1b"
+ : "=&r" (oldval), "=&r" (tmp)
+ : "r" (val), "r" (ptr)
+ : "memory", "cc");
+ return oldval;
+}
+
#endif /* _ASM_ARM_XEN_EVENTS_H */
diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
index c6b9096cef95..30cdacb675af 100644
--- a/arch/arm/include/asm/xen/page.h
+++ b/arch/arm/include/asm/xen/page.h
@@ -1,6 +1,7 @@
#ifndef _ASM_ARM_XEN_PAGE_H
#define _ASM_ARM_XEN_PAGE_H
+#include <asm/mach/map.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -86,4 +87,7 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
{
return __set_phys_to_machine(pfn, mfn);
}
+
+#define xen_remap(cookie, size) __arm_ioremap((cookie), (size), MT_MEMORY);
+
#endif /* _ASM_ARM_XEN_PAGE_H */
diff --git a/arch/arm/include/debug/imx-uart.h b/arch/arm/include/debug/imx-uart.h
new file mode 100644
index 000000000000..91d38e38a0b4
--- /dev/null
+++ b/arch/arm/include/debug/imx-uart.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef __DEBUG_IMX_UART_H
+#define __DEBUG_IMX_UART_H
+
+#define IMX1_UART1_BASE_ADDR 0x00206000
+#define IMX1_UART2_BASE_ADDR 0x00207000
+#define IMX1_UART_BASE_ADDR(n) IMX1_UART##n##_BASE_ADDR
+#define IMX1_UART_BASE(n) IMX1_UART_BASE_ADDR(n)
+
+#define IMX21_UART1_BASE_ADDR 0x1000a000
+#define IMX21_UART2_BASE_ADDR 0x1000b000
+#define IMX21_UART3_BASE_ADDR 0x1000c000
+#define IMX21_UART4_BASE_ADDR 0x1000d000
+#define IMX21_UART_BASE_ADDR(n) IMX21_UART##n##_BASE_ADDR
+#define IMX21_UART_BASE(n) IMX21_UART_BASE_ADDR(n)
+
+#define IMX25_UART1_BASE_ADDR 0x43f90000
+#define IMX25_UART2_BASE_ADDR 0x43f94000
+#define IMX25_UART3_BASE_ADDR 0x5000c000
+#define IMX25_UART4_BASE_ADDR 0x50008000
+#define IMX25_UART5_BASE_ADDR 0x5002c000
+#define IMX25_UART_BASE_ADDR(n) IMX25_UART##n##_BASE_ADDR
+#define IMX25_UART_BASE(n) IMX25_UART_BASE_ADDR(n)
+
+#define IMX31_UART1_BASE_ADDR 0x43f90000
+#define IMX31_UART2_BASE_ADDR 0x43f94000
+#define IMX31_UART3_BASE_ADDR 0x5000c000
+#define IMX31_UART4_BASE_ADDR 0x43fb0000
+#define IMX31_UART5_BASE_ADDR 0x43fb4000
+#define IMX31_UART_BASE_ADDR(n) IMX31_UART##n##_BASE_ADDR
+#define IMX31_UART_BASE(n) IMX31_UART_BASE_ADDR(n)
+
+#define IMX35_UART1_BASE_ADDR 0x43f90000
+#define IMX35_UART2_BASE_ADDR 0x43f94000
+#define IMX35_UART3_BASE_ADDR 0x5000c000
+#define IMX35_UART_BASE_ADDR(n) IMX35_UART##n##_BASE_ADDR
+#define IMX35_UART_BASE(n) IMX35_UART_BASE_ADDR(n)
+
+#define IMX51_UART1_BASE_ADDR 0x73fbc000
+#define IMX51_UART2_BASE_ADDR 0x73fc0000
+#define IMX51_UART3_BASE_ADDR 0x7000c000
+#define IMX51_UART_BASE_ADDR(n) IMX51_UART##n##_BASE_ADDR
+#define IMX51_UART_BASE(n) IMX51_UART_BASE_ADDR(n)
+
+#define IMX53_UART1_BASE_ADDR 0x53fbc000
+#define IMX53_UART2_BASE_ADDR 0x53fc0000
+#define IMX53_UART3_BASE_ADDR 0x5000c000
+#define IMX53_UART4_BASE_ADDR 0x53ff0000
+#define IMX53_UART5_BASE_ADDR 0x63f90000
+#define IMX53_UART_BASE_ADDR(n) IMX53_UART##n##_BASE_ADDR
+#define IMX53_UART_BASE(n) IMX53_UART_BASE_ADDR(n)
+
+#define IMX6Q_UART1_BASE_ADDR 0x02020000
+#define IMX6Q_UART2_BASE_ADDR 0x021e8000
+#define IMX6Q_UART3_BASE_ADDR 0x021ec000
+#define IMX6Q_UART4_BASE_ADDR 0x021f0000
+#define IMX6Q_UART5_BASE_ADDR 0x021f4000
+#define IMX6Q_UART_BASE_ADDR(n) IMX6Q_UART##n##_BASE_ADDR
+#define IMX6Q_UART_BASE(n) IMX6Q_UART_BASE_ADDR(n)
+
+#define IMX_DEBUG_UART_BASE(soc) soc##_UART_BASE(CONFIG_DEBUG_IMX_UART_PORT)
+
+#ifdef CONFIG_DEBUG_IMX1_UART
+#define UART_PADDR IMX_DEBUG_UART_BASE(IMX1)
+#elif defined(CONFIG_DEBUG_IMX21_IMX27_UART)
+#define UART_PADDR IMX_DEBUG_UART_BASE(IMX21)
+#elif defined(CONFIG_DEBUG_IMX25_UART)
+#define UART_PADDR IMX_DEBUG_UART_BASE(IMX25)
+#elif defined(CONFIG_DEBUG_IMX31_UART)
+#define UART_PADDR IMX_DEBUG_UART_BASE(IMX31)
+#elif defined(CONFIG_DEBUG_IMX35_UART)
+#define UART_PADDR IMX_DEBUG_UART_BASE(IMX35)
+#elif defined(CONFIG_DEBUG_IMX51_UART)
+#define UART_PADDR IMX_DEBUG_UART_BASE(IMX51)
+#elif defined(CONFIG_DEBUG_IMX53_UART)
+#define UART_PADDR IMX_DEBUG_UART_BASE(IMX53)
+#elif defined(CONFIG_DEBUG_IMX6Q_UART)
+#define UART_PADDR IMX_DEBUG_UART_BASE(IMX6Q)
+#endif
+
+#endif /* __DEBUG_IMX_UART_H */
diff --git a/arch/arm/include/debug/imx.S b/arch/arm/include/debug/imx.S
index 0c4e17d4d359..619d8cc1ac12 100644
--- a/arch/arm/include/debug/imx.S
+++ b/arch/arm/include/debug/imx.S
@@ -10,35 +10,8 @@
* published by the Free Software Foundation.
*
*/
-#define IMX6Q_UART1_BASE_ADDR 0x02020000
-#define IMX6Q_UART2_BASE_ADDR 0x021e8000
-#define IMX6Q_UART3_BASE_ADDR 0x021ec000
-#define IMX6Q_UART4_BASE_ADDR 0x021f0000
-#define IMX6Q_UART5_BASE_ADDR 0x021f4000
-/*
- * IMX6Q_UART_BASE_ADDR is put in the middle to force the expansion
- * of IMX6Q_UART##n##_BASE_ADDR.
- */
-#define IMX6Q_UART_BASE_ADDR(n) IMX6Q_UART##n##_BASE_ADDR
-#define IMX6Q_UART_BASE(n) IMX6Q_UART_BASE_ADDR(n)
-#define IMX6Q_DEBUG_UART_BASE IMX6Q_UART_BASE(CONFIG_DEBUG_IMX6Q_UART_PORT)
-
-#ifdef CONFIG_DEBUG_IMX1_UART
-#define UART_PADDR 0x00206000
-#elif defined (CONFIG_DEBUG_IMX25_UART)
-#define UART_PADDR 0x43f90000
-#elif defined (CONFIG_DEBUG_IMX21_IMX27_UART)
-#define UART_PADDR 0x1000a000
-#elif defined (CONFIG_DEBUG_IMX31_IMX35_UART)
-#define UART_PADDR 0x43f90000
-#elif defined (CONFIG_DEBUG_IMX51_UART)
-#define UART_PADDR 0x73fbc000
-#elif defined (CONFIG_DEBUG_IMX50_IMX53_UART)
-#define UART_PADDR 0x53fbc000
-#elif defined (CONFIG_DEBUG_IMX6Q_UART)
-#define UART_PADDR IMX6Q_DEBUG_UART_BASE
-#endif
+#include "imx-uart.h"
/*
* FIXME: This is a copy of IMX_IO_P2V in hardware.h, and needs to
diff --git a/arch/arm/mach-omap2/include/mach/debug-macro.S b/arch/arm/include/debug/omap2plus.S
index cfaed13d0040..6d867aef18eb 100644
--- a/arch/arm/mach-omap2/include/mach/debug-macro.S
+++ b/arch/arm/include/debug/omap2plus.S
@@ -1,5 +1,4 @@
-/* arch/arm/mach-omap2/include/mach/debug-macro.S
- *
+/*
* Debugging macro include header
*
* Copyright (C) 1994-1999 Russell King
@@ -13,7 +12,49 @@
#include <linux/serial_reg.h>
-#include <mach/serial.h>
+/* OMAP2 serial ports */
+#define OMAP2_UART1_BASE 0x4806a000
+#define OMAP2_UART2_BASE 0x4806c000
+#define OMAP2_UART3_BASE 0x4806e000
+
+/* OMAP3 serial ports */
+#define OMAP3_UART1_BASE OMAP2_UART1_BASE
+#define OMAP3_UART2_BASE OMAP2_UART2_BASE
+#define OMAP3_UART3_BASE 0x49020000
+#define OMAP3_UART4_BASE 0x49042000 /* Only on 36xx */
+#define OMAP3_UART4_AM35XX_BASE 0x4809E000 /* Only on AM35xx */
+
+/* OMAP4 serial ports */
+#define OMAP4_UART1_BASE OMAP2_UART1_BASE
+#define OMAP4_UART2_BASE OMAP2_UART2_BASE
+#define OMAP4_UART3_BASE 0x48020000
+#define OMAP4_UART4_BASE 0x4806e000
+
+/* TI81XX serial ports */
+#define TI81XX_UART1_BASE 0x48020000
+#define TI81XX_UART2_BASE 0x48022000
+#define TI81XX_UART3_BASE 0x48024000
+
+/* AM3505/3517 UART4 */
+#define AM35XX_UART4_BASE 0x4809E000 /* Only on AM3505/3517 */
+
+/* AM33XX serial port */
+#define AM33XX_UART1_BASE 0x44E09000
+
+/* OMAP5 serial ports */
+#define OMAP5_UART1_BASE OMAP2_UART1_BASE
+#define OMAP5_UART2_BASE OMAP2_UART2_BASE
+#define OMAP5_UART3_BASE OMAP4_UART3_BASE
+#define OMAP5_UART4_BASE OMAP4_UART4_BASE
+#define OMAP5_UART5_BASE 0x48066000
+#define OMAP5_UART6_BASE 0x48068000
+
+/* External port on Zoom2/3 */
+#define ZOOM_UART_BASE 0x10000000
+#define ZOOM_UART_VIRT 0xfa400000
+
+#define OMAP_PORT_SHIFT 2
+#define ZOOM_PORT_SHIFT 1
#define UART_OFFSET(addr) ((addr) & 0x00ffffff)
@@ -23,12 +64,6 @@ omap_uart_virt: .word 0
omap_uart_lsr: .word 0
.popsection
- /*
- * Note that this code won't work if the bootloader passes
- * a wrong machine ID number in r1. To debug, just hardcode
- * the desired UART phys and virt addresses temporarily into
- * the omap_uart_phys and omap_uart_virt above.
- */
.macro addruart, rp, rv, tmp
/* Use omap_uart_phys/virt if already configured */
@@ -43,74 +78,64 @@ omap_uart_lsr: .word 0
cmpne \rv, #0
bne 100f @ already configured
- /* Check the debug UART configuration set in uncompress.h */
- mov \rp, pc
- ldr \rv, =OMAP_UART_INFO_OFS
- and \rp, \rp, #0xff000000
- ldr \rp, [\rp, \rv]
-
- /* Select the UART to use based on the UART1 scratchpad value */
- cmp \rp, #0 @ no port configured?
- beq 21f @ if none, try to use UART1
- cmp \rp, #OMAP2UART1 @ OMAP2/3/4UART1
- beq 21f @ configure OMAP2/3/4UART1
- cmp \rp, #OMAP2UART2 @ OMAP2/3/4UART2
- beq 22f @ configure OMAP2/3/4UART2
- cmp \rp, #OMAP2UART3 @ only on 24xx
- beq 23f @ configure OMAP2UART3
- cmp \rp, #OMAP3UART3 @ only on 34xx
- beq 33f @ configure OMAP3UART3
- cmp \rp, #OMAP4UART3 @ only on 44xx/54xx
- beq 43f @ configure OMAP4/5UART3
- cmp \rp, #OMAP3UART4 @ only on 36xx
- beq 34f @ configure OMAP3UART4
- cmp \rp, #OMAP4UART4 @ only on 44xx/54xx
- beq 44f @ configure OMAP4/5UART4
- cmp \rp, #TI81XXUART1 @ ti81Xx UART offsets different
- beq 81f @ configure UART1
- cmp \rp, #TI81XXUART2 @ ti81Xx UART offsets different
- beq 82f @ configure UART2
- cmp \rp, #TI81XXUART3 @ ti81Xx UART offsets different
- beq 83f @ configure UART3
- cmp \rp, #AM33XXUART1 @ AM33XX UART offsets different
- beq 84f @ configure UART1
- cmp \rp, #ZOOM_UART @ only on zoom2/3
- beq 95f @ configure ZOOM_UART
-
/* Configure the UART offset from the phys/virt base */
-21: mov \rp, #UART_OFFSET(OMAP2_UART1_BASE) @ omap2/3/4
+#ifdef CONFIG_DEBUG_OMAP2UART1
+ mov \rp, #UART_OFFSET(OMAP2_UART1_BASE) @ omap2/3/4
b 98f
-22: mov \rp, #UART_OFFSET(OMAP2_UART2_BASE) @ omap2/3/4
+#endif
+#ifdef CONFIG_DEBUG_OMAP2UART2
+ mov \rp, #UART_OFFSET(OMAP2_UART2_BASE) @ omap2/3/4
b 98f
-23: mov \rp, #UART_OFFSET(OMAP2_UART3_BASE)
+#endif
+#ifdef CONFIG_DEBUG_OMAP2UART3
+ mov \rp, #UART_OFFSET(OMAP2_UART3_BASE)
b 98f
-33: mov \rp, #UART_OFFSET(OMAP3_UART1_BASE)
+#endif
+#ifdef CONFIG_DEBUG_OMAP3UART3
+ mov \rp, #UART_OFFSET(OMAP3_UART1_BASE)
add \rp, \rp, #0x00fb0000
add \rp, \rp, #0x00006000 @ OMAP3_UART3_BASE
b 98f
-34: mov \rp, #UART_OFFSET(OMAP3_UART1_BASE)
+#endif
+#ifdef CONFIG_DEBUG_OMAP4UART3
+ mov \rp, #UART_OFFSET(OMAP4_UART3_BASE)
+ b 98f
+#endif
+#ifdef CONFIG_DEBUG_OMAP3UART4
+ mov \rp, #UART_OFFSET(OMAP3_UART1_BASE)
add \rp, \rp, #0x00fb0000
add \rp, \rp, #0x00028000 @ OMAP3_UART4_BASE
b 98f
-43: mov \rp, #UART_OFFSET(OMAP4_UART3_BASE)
- b 98f
-44: mov \rp, #UART_OFFSET(OMAP4_UART4_BASE)
+#endif
+#ifdef CONFIG_DEBUG_OMAP4UART4
+ mov \rp, #UART_OFFSET(OMAP4_UART4_BASE)
b 98f
-81: mov \rp, #UART_OFFSET(TI81XX_UART1_BASE)
+#endif
+#ifdef CONFIG_DEBUG_TI81XXUART1
+ mov \rp, #UART_OFFSET(TI81XX_UART1_BASE)
b 98f
-82: mov \rp, #UART_OFFSET(TI81XX_UART2_BASE)
+#endif
+#ifdef CONFIG_DEBUG_TI81XXUART2
+ mov \rp, #UART_OFFSET(TI81XX_UART2_BASE)
b 98f
-83: mov \rp, #UART_OFFSET(TI81XX_UART3_BASE)
+#endif
+#ifdef CONFIG_DEBUG_TI81XXUART3
+ mov \rp, #UART_OFFSET(TI81XX_UART3_BASE)
b 98f
-84: ldr \rp, =AM33XX_UART1_BASE
+#endif
+#ifdef CONFIG_DEBUG_AM33XXUART1
+ ldr \rp, =AM33XX_UART1_BASE
and \rp, \rp, #0x00ffffff
b 97f
-95: ldr \rp, =ZOOM_UART_BASE
+#endif
+#ifdef CONFIG_DEBUG_ZOOM_UART
+ ldr \rp, =ZOOM_UART_BASE
str \rp, [\tmp, #0] @ omap_uart_phys
ldr \rp, =ZOOM_UART_VIRT
str \rp, [\tmp, #4] @ omap_uart_virt
mov \rp, #(UART_LSR << ZOOM_PORT_SHIFT)
str \rp, [\tmp, #8] @ omap_uart_lsr
+#endif
b 10b
/* AM33XX: Store both phys and virt address for the uart */
diff --git a/arch/arm/mach-vt8500/include/mach/debug-macro.S b/arch/arm/include/debug/vt8500.S
index ca292f29d4a3..0e0ca0869da7 100644
--- a/arch/arm/mach-vt8500/include/mach/debug-macro.S
+++ b/arch/arm/include/debug/vt8500.S
@@ -1,20 +1,24 @@
-/*
- * arch/arm/mach-vt8500/include/mach/debug-macro.S
+/*
+ * Debugging macro include header
*
* Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * Debugging macro include header
+ * Moved from arch/arm/mach-vt8500/include/mach/debug-macro.S
+ * Minor changes for readability.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
-*/
+ */
+
+#define DEBUG_LL_PHYS_BASE 0xD8000000
+#define DEBUG_LL_VIRT_BASE 0xF8000000
+#define DEBUG_LL_UART_OFFSET 0x00200000
+#if defined(CONFIG_DEBUG_VT8500_UART0)
.macro addruart, rp, rv, tmp
- mov \rp, #0x00200000
- orr \rv, \rp, #0xf8000000
- orr \rp, \rp, #0xd8000000
+ mov \rp, #DEBUG_LL_UART_OFFSET
+ orr \rv, \rp, #DEBUG_LL_VIRT_BASE
+ orr \rp, \rp, #DEBUG_LL_PHYS_BASE
.endm
.macro senduart,rd,rx
@@ -29,3 +33,5 @@
.macro waituart,rd,rx
.endm
+
+#endif
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
new file mode 100644
index 000000000000..023bfeb367bf
--- /dev/null
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_H__
+#define __ARM_KVM_H__
+
+#include <linux/types.h>
+#include <asm/ptrace.h>
+
+#define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_IRQ_LINE
+
+#define KVM_REG_SIZE(id) \
+ (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
+
+/* Valid for svc_regs, abt_regs, und_regs, irq_regs in struct kvm_regs */
+#define KVM_ARM_SVC_sp svc_regs[0]
+#define KVM_ARM_SVC_lr svc_regs[1]
+#define KVM_ARM_SVC_spsr svc_regs[2]
+#define KVM_ARM_ABT_sp abt_regs[0]
+#define KVM_ARM_ABT_lr abt_regs[1]
+#define KVM_ARM_ABT_spsr abt_regs[2]
+#define KVM_ARM_UND_sp und_regs[0]
+#define KVM_ARM_UND_lr und_regs[1]
+#define KVM_ARM_UND_spsr und_regs[2]
+#define KVM_ARM_IRQ_sp irq_regs[0]
+#define KVM_ARM_IRQ_lr irq_regs[1]
+#define KVM_ARM_IRQ_spsr irq_regs[2]
+
+/* Valid only for fiq_regs in struct kvm_regs */
+#define KVM_ARM_FIQ_r8 fiq_regs[0]
+#define KVM_ARM_FIQ_r9 fiq_regs[1]
+#define KVM_ARM_FIQ_r10 fiq_regs[2]
+#define KVM_ARM_FIQ_fp fiq_regs[3]
+#define KVM_ARM_FIQ_ip fiq_regs[4]
+#define KVM_ARM_FIQ_sp fiq_regs[5]
+#define KVM_ARM_FIQ_lr fiq_regs[6]
+#define KVM_ARM_FIQ_spsr fiq_regs[7]
+
+struct kvm_regs {
+ struct pt_regs usr_regs;/* R0_usr - R14_usr, PC, CPSR */
+ __u32 svc_regs[3]; /* SP_svc, LR_svc, SPSR_svc */
+ __u32 abt_regs[3]; /* SP_abt, LR_abt, SPSR_abt */
+ __u32 und_regs[3]; /* SP_und, LR_und, SPSR_und */
+ __u32 irq_regs[3]; /* SP_irq, LR_irq, SPSR_irq */
+ __u32 fiq_regs[8]; /* R8_fiq - R14_fiq, SPSR_fiq */
+};
+
+/* Supported Processor Types */
+#define KVM_ARM_TARGET_CORTEX_A15 0
+#define KVM_ARM_NUM_TARGETS 1
+
+/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
+#define KVM_ARM_DEVICE_TYPE_SHIFT 0
+#define KVM_ARM_DEVICE_TYPE_MASK (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT)
+#define KVM_ARM_DEVICE_ID_SHIFT 16
+#define KVM_ARM_DEVICE_ID_MASK (0xffff << KVM_ARM_DEVICE_ID_SHIFT)
+
+/* Supported device IDs */
+#define KVM_ARM_DEVICE_VGIC_V2 0
+
+/* Supported VGIC address types */
+#define KVM_VGIC_V2_ADDR_TYPE_DIST 0
+#define KVM_VGIC_V2_ADDR_TYPE_CPU 1
+
+#define KVM_VGIC_V2_DIST_SIZE 0x1000
+#define KVM_VGIC_V2_CPU_SIZE 0x2000
+
+#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
+
+struct kvm_vcpu_init {
+ __u32 target;
+ __u32 features[7];
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+};
+
+struct kvm_guest_debug_arch {
+};
+
+struct kvm_debug_exit_arch {
+};
+
+struct kvm_sync_regs {
+};
+
+struct kvm_arch_memory_slot {
+};
+
+/* If you need to interpret the index values, here is the key: */
+#define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
+#define KVM_REG_ARM_COPROC_SHIFT 16
+#define KVM_REG_ARM_32_OPC2_MASK 0x0000000000000007
+#define KVM_REG_ARM_32_OPC2_SHIFT 0
+#define KVM_REG_ARM_OPC1_MASK 0x0000000000000078
+#define KVM_REG_ARM_OPC1_SHIFT 3
+#define KVM_REG_ARM_CRM_MASK 0x0000000000000780
+#define KVM_REG_ARM_CRM_SHIFT 7
+#define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800
+#define KVM_REG_ARM_32_CRN_SHIFT 11
+
+/* Normal registers are mapped as coprocessor 16. */
+#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4)
+
+/* Some registers need more space to represent values. */
+#define KVM_REG_ARM_DEMUX (0x0011 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_DEMUX_ID_MASK 0x000000000000FF00
+#define KVM_REG_ARM_DEMUX_ID_SHIFT 8
+#define KVM_REG_ARM_DEMUX_ID_CCSIDR (0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT)
+#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF
+#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0
+
+/* VFP registers: we could overload CP10 like ARM does, but that's ugly. */
+#define KVM_REG_ARM_VFP (0x0012 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_VFP_MASK 0x000000000000FFFF
+#define KVM_REG_ARM_VFP_BASE_REG 0x0
+#define KVM_REG_ARM_VFP_FPSID 0x1000
+#define KVM_REG_ARM_VFP_FPSCR 0x1001
+#define KVM_REG_ARM_VFP_MVFR1 0x1006
+#define KVM_REG_ARM_VFP_MVFR0 0x1007
+#define KVM_REG_ARM_VFP_FPEXC 0x1008
+#define KVM_REG_ARM_VFP_FPINST 0x1009
+#define KVM_REG_ARM_VFP_FPINST2 0x100A
+
+
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_TYPE_SHIFT 24
+#define KVM_ARM_IRQ_TYPE_MASK 0xff
+#define KVM_ARM_IRQ_VCPU_SHIFT 16
+#define KVM_ARM_IRQ_VCPU_MASK 0xff
+#define KVM_ARM_IRQ_NUM_SHIFT 0
+#define KVM_ARM_IRQ_NUM_MASK 0xffff
+
+/* irq_type field */
+#define KVM_ARM_IRQ_TYPE_CPU 0
+#define KVM_ARM_IRQ_TYPE_SPI 1
+#define KVM_ARM_IRQ_TYPE_PPI 2
+
+/* out-of-kernel GIC cpu interrupt injection irq_number field */
+#define KVM_ARM_IRQ_CPU_IRQ 0
+#define KVM_ARM_IRQ_CPU_FIQ 1
+
+/* Highest supported SPI, from VGIC_NR_IRQS */
+#define KVM_ARM_IRQ_GIC_MAX 127
+
+/* PSCI interface */
+#define KVM_PSCI_FN_BASE 0x95c1ba5e
+#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
+
+#define KVM_PSCI_FN_CPU_SUSPEND KVM_PSCI_FN(0)
+#define KVM_PSCI_FN_CPU_OFF KVM_PSCI_FN(1)
+#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2)
+#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
+
+#define KVM_PSCI_RET_SUCCESS 0
+#define KVM_PSCI_RET_NI ((unsigned long)-1)
+#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
+#define KVM_PSCI_RET_DENIED ((unsigned long)-3)
+
+#endif /* __ARM_KVM_H__ */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 5bbec7b8183e..5f3338eacad2 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -82,5 +82,6 @@ obj-$(CONFIG_DEBUG_LL) += debug.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o
+obj-$(CONFIG_ARM_PSCI) += psci.o
extra-y := $(head-y) vmlinux.lds
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index c8ef20747ee7..d957a51435d8 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -9,516 +9,53 @@
* published by the Free Software Foundation.
*/
#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/smp.h>
-#include <linux/cpu.h>
-#include <linux/jiffies.h>
-#include <linux/clockchips.h>
-#include <linux/interrupt.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/errno.h>
-#include <asm/cputype.h>
#include <asm/delay.h>
-#include <asm/localtimer.h>
-#include <asm/arch_timer.h>
-#include <asm/system_info.h>
#include <asm/sched_clock.h>
-static unsigned long arch_timer_rate;
+#include <clocksource/arm_arch_timer.h>
-enum ppi_nr {
- PHYS_SECURE_PPI,
- PHYS_NONSECURE_PPI,
- VIRT_PPI,
- HYP_PPI,
- MAX_TIMER_PPI
-};
-
-static int arch_timer_ppi[MAX_TIMER_PPI];
-
-static struct clock_event_device __percpu **arch_timer_evt;
-static struct delay_timer arch_delay_timer;
-
-static bool arch_timer_use_virtual = true;
-
-/*
- * Architected system timer support.
- */
-
-#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
-#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
-#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
-
-#define ARCH_TIMER_REG_CTRL 0
-#define ARCH_TIMER_REG_FREQ 1
-#define ARCH_TIMER_REG_TVAL 2
-
-#define ARCH_TIMER_PHYS_ACCESS 0
-#define ARCH_TIMER_VIRT_ACCESS 1
-
-/*
- * These register accessors are marked inline so the compiler can
- * nicely work out which register we want, and chuck away the rest of
- * the code. At least it does so with a recent GCC (4.6.3).
- */
-static inline void arch_timer_reg_write(const int access, const int reg, u32 val)
-{
- if (access == ARCH_TIMER_PHYS_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
- break;
- }
- }
-
- if (access == ARCH_TIMER_VIRT_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mcr p15, 0, %0, c14, c3, 0" : : "r" (val));
- break;
- }
- }
-
- isb();
-}
-
-static inline u32 arch_timer_reg_read(const int access, const int reg)
-{
- u32 val = 0;
-
- if (access == ARCH_TIMER_PHYS_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
- break;
- case ARCH_TIMER_REG_FREQ:
- asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
- break;
- }
- }
-
- if (access == ARCH_TIMER_VIRT_ACCESS) {
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mrc p15, 0, %0, c14, c3, 0" : "=r" (val));
- break;
- }
- }
-
- return val;
-}
-
-static inline cycle_t arch_timer_counter_read(const int access)
-{
- cycle_t cval = 0;
-
- if (access == ARCH_TIMER_PHYS_ACCESS)
- asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
-
- if (access == ARCH_TIMER_VIRT_ACCESS)
- asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cval));
-
- return cval;
-}
-
-static inline cycle_t arch_counter_get_cntpct(void)
-{
- return arch_timer_counter_read(ARCH_TIMER_PHYS_ACCESS);
-}
-
-static inline cycle_t arch_counter_get_cntvct(void)
-{
- return arch_timer_counter_read(ARCH_TIMER_VIRT_ACCESS);
-}
-
-static irqreturn_t inline timer_handler(const int access,
- struct clock_event_device *evt)
-{
- unsigned long ctrl;
- ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
- if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
- ctrl |= ARCH_TIMER_CTRL_IT_MASK;
- arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
- evt->event_handler(evt);
- return IRQ_HANDLED;
- }
-
- return IRQ_NONE;
-}
-
-static irqreturn_t arch_timer_handler_virt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
-
- return timer_handler(ARCH_TIMER_VIRT_ACCESS, evt);
-}
-
-static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id)
-{
- struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
-
- return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt);
-}
-
-static inline void timer_set_mode(const int access, int mode)
-{
- unsigned long ctrl;
- switch (mode) {
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
- ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
- arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
- break;
- default:
- break;
- }
-}
-
-static void arch_timer_set_mode_virt(enum clock_event_mode mode,
- struct clock_event_device *clk)
-{
- timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode);
-}
-
-static void arch_timer_set_mode_phys(enum clock_event_mode mode,
- struct clock_event_device *clk)
-{
- timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode);
-}
-
-static inline void set_next_event(const int access, unsigned long evt)
-{
- unsigned long ctrl;
- ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
- ctrl |= ARCH_TIMER_CTRL_ENABLE;
- ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
- arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt);
- arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
-}
-
-static int arch_timer_set_next_event_virt(unsigned long evt,
- struct clock_event_device *unused)
-{
- set_next_event(ARCH_TIMER_VIRT_ACCESS, evt);
- return 0;
-}
-
-static int arch_timer_set_next_event_phys(unsigned long evt,
- struct clock_event_device *unused)
-{
- set_next_event(ARCH_TIMER_PHYS_ACCESS, evt);
- return 0;
-}
-
-static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
-{
- clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
- clk->name = "arch_sys_timer";
- clk->rating = 450;
- if (arch_timer_use_virtual) {
- clk->irq = arch_timer_ppi[VIRT_PPI];
- clk->set_mode = arch_timer_set_mode_virt;
- clk->set_next_event = arch_timer_set_next_event_virt;
- } else {
- clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
- clk->set_mode = arch_timer_set_mode_phys;
- clk->set_next_event = arch_timer_set_next_event_phys;
- }
-
- clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL);
-
- clockevents_config_and_register(clk, arch_timer_rate,
- 0xf, 0x7fffffff);
-
- *__this_cpu_ptr(arch_timer_evt) = clk;
-
- if (arch_timer_use_virtual)
- enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0);
- else {
- enable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], 0);
- if (arch_timer_ppi[PHYS_NONSECURE_PPI])
- enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
- }
-
- return 0;
-}
-
-/* Is the optional system timer available? */
-static int local_timer_is_architected(void)
-{
- return (cpu_architecture() >= CPU_ARCH_ARMv7) &&
- ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1;
-}
-
-static int arch_timer_available(void)
-{
- unsigned long freq;
-
- if (!local_timer_is_architected())
- return -ENXIO;
-
- if (arch_timer_rate == 0) {
- freq = arch_timer_reg_read(ARCH_TIMER_PHYS_ACCESS,
- ARCH_TIMER_REG_FREQ);
-
- /* Check the timer frequency. */
- if (freq == 0) {
- pr_warn("Architected timer frequency not available\n");
- return -EINVAL;
- }
-
- arch_timer_rate = freq;
- }
-
- pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n",
- arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100,
- arch_timer_use_virtual ? "virt" : "phys");
- return 0;
-}
-
-static u32 notrace arch_counter_get_cntpct32(void)
-{
- cycle_t cnt = arch_counter_get_cntpct();
-
- /*
- * The sched_clock infrastructure only knows about counters
- * with at most 32bits. Forget about the upper 24 bits for the
- * time being...
- */
- return (u32)cnt;
-}
-
-static u32 notrace arch_counter_get_cntvct32(void)
-{
- cycle_t cnt = arch_counter_get_cntvct();
-
- /*
- * The sched_clock infrastructure only knows about counters
- * with at most 32bits. Forget about the upper 24 bits for the
- * time being...
- */
- return (u32)cnt;
-}
-
-static cycle_t arch_counter_read(struct clocksource *cs)
-{
- /*
- * Always use the physical counter for the clocksource.
- * CNTHCTL.PL1PCTEN must be set to 1.
- */
- return arch_counter_get_cntpct();
-}
-
-static unsigned long arch_timer_read_current_timer(void)
+static unsigned long arch_timer_read_counter_long(void)
{
- return arch_counter_get_cntpct();
+ return arch_timer_read_counter();
}
-static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
+static u32 arch_timer_read_counter_u32(void)
{
- /*
- * Always use the physical counter for the clocksource.
- * CNTHCTL.PL1PCTEN must be set to 1.
- */
- return arch_counter_get_cntpct();
+ return arch_timer_read_counter();
}
-static struct clocksource clocksource_counter = {
- .name = "arch_sys_counter",
- .rating = 400,
- .read = arch_counter_read,
- .mask = CLOCKSOURCE_MASK(56),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static struct cyclecounter cyclecounter = {
- .read = arch_counter_read_cc,
- .mask = CLOCKSOURCE_MASK(56),
-};
-
-static struct timecounter timecounter;
-
-struct timecounter *arch_timer_get_timecounter(void)
-{
- return &timecounter;
-}
-
-static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
-{
- pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
- clk->irq, smp_processor_id());
-
- if (arch_timer_use_virtual)
- disable_percpu_irq(arch_timer_ppi[VIRT_PPI]);
- else {
- disable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI]);
- if (arch_timer_ppi[PHYS_NONSECURE_PPI])
- disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
- }
-
- clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk);
-}
-
-static struct local_timer_ops arch_timer_ops __cpuinitdata = {
- .setup = arch_timer_setup,
- .stop = arch_timer_stop,
-};
-
-static struct clock_event_device arch_timer_global_evt;
+static struct delay_timer arch_delay_timer;
-static int __init arch_timer_register(void)
+static void __init arch_timer_delay_timer_register(void)
{
- int err;
- int ppi;
-
- err = arch_timer_available();
- if (err)
- goto out;
-
- arch_timer_evt = alloc_percpu(struct clock_event_device *);
- if (!arch_timer_evt) {
- err = -ENOMEM;
- goto out;
- }
-
- clocksource_register_hz(&clocksource_counter, arch_timer_rate);
- cyclecounter.mult = clocksource_counter.mult;
- cyclecounter.shift = clocksource_counter.shift;
- timecounter_init(&timecounter, &cyclecounter,
- arch_counter_get_cntpct());
-
- if (arch_timer_use_virtual) {
- ppi = arch_timer_ppi[VIRT_PPI];
- err = request_percpu_irq(ppi, arch_timer_handler_virt,
- "arch_timer", arch_timer_evt);
- } else {
- ppi = arch_timer_ppi[PHYS_SECURE_PPI];
- err = request_percpu_irq(ppi, arch_timer_handler_phys,
- "arch_timer", arch_timer_evt);
- if (!err && arch_timer_ppi[PHYS_NONSECURE_PPI]) {
- ppi = arch_timer_ppi[PHYS_NONSECURE_PPI];
- err = request_percpu_irq(ppi, arch_timer_handler_phys,
- "arch_timer", arch_timer_evt);
- if (err)
- free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
- arch_timer_evt);
- }
- }
-
- if (err) {
- pr_err("arch_timer: can't register interrupt %d (%d)\n",
- ppi, err);
- goto out_free;
- }
-
- err = local_timer_register(&arch_timer_ops);
- if (err) {
- /*
- * We couldn't register as a local timer (could be
- * because we're on a UP platform, or because some
- * other local timer is already present...). Try as a
- * global timer instead.
- */
- arch_timer_global_evt.cpumask = cpumask_of(0);
- err = arch_timer_setup(&arch_timer_global_evt);
- }
- if (err)
- goto out_free_irq;
-
/* Use the architected timer for the delay loop. */
- arch_delay_timer.read_current_timer = &arch_timer_read_current_timer;
- arch_delay_timer.freq = arch_timer_rate;
+ arch_delay_timer.read_current_timer = arch_timer_read_counter_long;
+ arch_delay_timer.freq = arch_timer_get_rate();
register_current_timer_delay(&arch_delay_timer);
- return 0;
-
-out_free_irq:
- if (arch_timer_use_virtual)
- free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt);
- else {
- free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
- arch_timer_evt);
- if (arch_timer_ppi[PHYS_NONSECURE_PPI])
- free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
- arch_timer_evt);
- }
-
-out_free:
- free_percpu(arch_timer_evt);
-out:
- return err;
}
-static const struct of_device_id arch_timer_of_match[] __initconst = {
- { .compatible = "arm,armv7-timer", },
- {},
-};
-
int __init arch_timer_of_register(void)
{
- struct device_node *np;
- u32 freq;
- int i;
-
- np = of_find_matching_node(NULL, arch_timer_of_match);
- if (!np) {
- pr_err("arch_timer: can't find DT node\n");
- return -ENODEV;
- }
-
- /* Try to determine the frequency from the device tree or CNTFRQ */
- if (!of_property_read_u32(np, "clock-frequency", &freq))
- arch_timer_rate = freq;
-
- for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
- arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+ int ret;
- /*
- * If no interrupt provided for virtual timer, we'll have to
- * stick to the physical timer. It'd better be accessible...
- */
- if (!arch_timer_ppi[VIRT_PPI]) {
- arch_timer_use_virtual = false;
+ ret = arch_timer_init();
+ if (ret)
+ return ret;
- if (!arch_timer_ppi[PHYS_SECURE_PPI] ||
- !arch_timer_ppi[PHYS_NONSECURE_PPI]) {
- pr_warn("arch_timer: No interrupt available, giving up\n");
- return -EINVAL;
- }
- }
+ arch_timer_delay_timer_register();
- return arch_timer_register();
+ return 0;
}
int __init arch_timer_sched_clock_init(void)
{
- u32 (*cnt32)(void);
- int err;
-
- err = arch_timer_available();
- if (err)
- return err;
-
- if (arch_timer_use_virtual)
- cnt32 = arch_counter_get_cntvct32;
- else
- cnt32 = arch_counter_get_cntpct32;
+ if (arch_timer_get_rate() == 0)
+ return -ENXIO;
- setup_sched_clock(cnt32, 32, arch_timer_rate);
+ setup_sched_clock(arch_timer_read_counter_u32,
+ 32, arch_timer_get_rate());
return 0;
}
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index c985b481192c..5ce738b43508 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -13,6 +13,9 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
+#ifdef CONFIG_KVM_ARM_HOST
+#include <linux/kvm_host.h>
+#endif
#include <asm/cacheflush.h>
#include <asm/glue-df.h>
#include <asm/glue-pf.h>
@@ -146,5 +149,45 @@ int main(void)
DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL);
DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE);
DEFINE(DMA_FROM_DEVICE, DMA_FROM_DEVICE);
+#ifdef CONFIG_KVM_ARM_HOST
+ DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm));
+ DEFINE(VCPU_MIDR, offsetof(struct kvm_vcpu, arch.midr));
+ DEFINE(VCPU_CP15, offsetof(struct kvm_vcpu, arch.cp15));
+ DEFINE(VCPU_VFP_GUEST, offsetof(struct kvm_vcpu, arch.vfp_guest));
+ DEFINE(VCPU_VFP_HOST, offsetof(struct kvm_vcpu, arch.vfp_host));
+ DEFINE(VCPU_REGS, offsetof(struct kvm_vcpu, arch.regs));
+ DEFINE(VCPU_USR_REGS, offsetof(struct kvm_vcpu, arch.regs.usr_regs));
+ DEFINE(VCPU_SVC_REGS, offsetof(struct kvm_vcpu, arch.regs.svc_regs));
+ DEFINE(VCPU_ABT_REGS, offsetof(struct kvm_vcpu, arch.regs.abt_regs));
+ DEFINE(VCPU_UND_REGS, offsetof(struct kvm_vcpu, arch.regs.und_regs));
+ DEFINE(VCPU_IRQ_REGS, offsetof(struct kvm_vcpu, arch.regs.irq_regs));
+ DEFINE(VCPU_FIQ_REGS, offsetof(struct kvm_vcpu, arch.regs.fiq_regs));
+ DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_pc));
+ DEFINE(VCPU_CPSR, offsetof(struct kvm_vcpu, arch.regs.usr_regs.ARM_cpsr));
+ DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines));
+ DEFINE(VCPU_HSR, offsetof(struct kvm_vcpu, arch.hsr));
+ DEFINE(VCPU_HxFAR, offsetof(struct kvm_vcpu, arch.hxfar));
+ DEFINE(VCPU_HPFAR, offsetof(struct kvm_vcpu, arch.hpfar));
+ DEFINE(VCPU_HYP_PC, offsetof(struct kvm_vcpu, arch.hyp_pc));
+#ifdef CONFIG_KVM_ARM_VGIC
+ DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
+ DEFINE(VGIC_CPU_HCR, offsetof(struct vgic_cpu, vgic_hcr));
+ DEFINE(VGIC_CPU_VMCR, offsetof(struct vgic_cpu, vgic_vmcr));
+ DEFINE(VGIC_CPU_MISR, offsetof(struct vgic_cpu, vgic_misr));
+ DEFINE(VGIC_CPU_EISR, offsetof(struct vgic_cpu, vgic_eisr));
+ DEFINE(VGIC_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_elrsr));
+ DEFINE(VGIC_CPU_APR, offsetof(struct vgic_cpu, vgic_apr));
+ DEFINE(VGIC_CPU_LR, offsetof(struct vgic_cpu, vgic_lr));
+ DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
+#ifdef CONFIG_KVM_ARM_TIMER
+ DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
+ DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_cval));
+ DEFINE(KVM_TIMER_CNTVOFF, offsetof(struct kvm, arch.timer.cntvoff));
+ DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled));
+#endif
+ DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base));
+#endif
+ DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
+#endif
return 0;
}
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 379cf3292390..a1f73b502ef0 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -413,7 +413,7 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return irq;
}
-static int __init pcibios_init_resources(int busnr, struct pci_sys_data *sys)
+static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
{
int ret;
struct pci_host_bridge_window *window;
@@ -445,7 +445,7 @@ static int __init pcibios_init_resources(int busnr, struct pci_sys_data *sys)
return 0;
}
-static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
+static void pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
{
struct pci_sys_data *sys = NULL;
int ret;
@@ -464,6 +464,9 @@ static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
sys->map_irq = hw->map_irq;
INIT_LIST_HEAD(&sys->resources);
+ if (hw->private_data)
+ sys->private_data = hw->private_data[nr];
+
ret = hw->setup(nr, sys);
if (ret > 0) {
@@ -493,7 +496,7 @@ static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
}
}
-void __init pci_common_init(struct hw_pci *hw)
+void pci_common_init(struct hw_pci *hw)
{
struct pci_sys_data *sys;
LIST_HEAD(head);
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index a4fda4e7a372..0cc57611fc4f 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -195,7 +195,7 @@
CALL(sys_getcwd)
CALL(sys_capget)
/* 185 */ CALL(sys_capset)
- CALL(sys_sigaltstack_wrapper)
+ CALL(sys_sigaltstack)
CALL(sys_sendfile)
CALL(sys_ni_syscall) /* getpmsg */
CALL(sys_ni_syscall) /* putpmsg */
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index a6c301e90a3b..3248cde504ed 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -514,11 +514,6 @@ sys_rt_sigreturn_wrapper:
b sys_rt_sigreturn
ENDPROC(sys_rt_sigreturn_wrapper)
-sys_sigaltstack_wrapper:
- ldr r2, [sp, #S_OFF + S_SP]
- b do_sigaltstack
-ENDPROC(sys_sigaltstack_wrapper)
-
sys_statfs64_wrapper:
teq r1, #88
moveq r1, #84
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index 5ff2e77782b1..5eae53e7a2e1 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -28,6 +28,7 @@
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <linux/smp.h>
+#include <linux/cpu_pm.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
@@ -35,6 +36,7 @@
#include <asm/hw_breakpoint.h>
#include <asm/kdebug.h>
#include <asm/traps.h>
+#include <asm/hardware/coresight.h>
/* Breakpoint currently in use for each BRP. */
static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
@@ -49,6 +51,9 @@ static int core_num_wrps;
/* Debug architecture version. */
static u8 debug_arch;
+/* Does debug architecture support OS Save and Restore? */
+static bool has_ossr;
+
/* Maximum supported watchpoint length. */
static u8 max_watchpoint_len;
@@ -903,6 +908,23 @@ static struct undef_hook debug_reg_hook = {
.fn = debug_reg_trap,
};
+/* Does this core support OS Save and Restore? */
+static bool core_has_os_save_restore(void)
+{
+ u32 oslsr;
+
+ switch (get_debug_arch()) {
+ case ARM_DEBUG_ARCH_V7_1:
+ return true;
+ case ARM_DEBUG_ARCH_V7_ECP14:
+ ARM_DBG_READ(c1, c1, 4, oslsr);
+ if (oslsr & ARM_OSLSR_OSLM0)
+ return true;
+ default:
+ return false;
+ }
+}
+
static void reset_ctrl_regs(void *unused)
{
int i, raw_num_brps, err = 0, cpu = smp_processor_id();
@@ -930,11 +952,7 @@ static void reset_ctrl_regs(void *unused)
if ((val & 0x1) == 0)
err = -EPERM;
- /*
- * Check whether we implement OS save and restore.
- */
- ARM_DBG_READ(c1, c1, 4, val);
- if ((val & 0x9) == 0)
+ if (!has_ossr)
goto clear_vcr;
break;
case ARM_DEBUG_ARCH_V7_1:
@@ -955,9 +973,9 @@ static void reset_ctrl_regs(void *unused)
/*
* Unconditionally clear the OS lock by writing a value
- * other than 0xC5ACCE55 to the access register.
+ * other than CS_LAR_KEY to the access register.
*/
- ARM_DBG_WRITE(c1, c0, 4, 0);
+ ARM_DBG_WRITE(c1, c0, 4, ~CS_LAR_KEY);
isb();
/*
@@ -1015,6 +1033,30 @@ static struct notifier_block __cpuinitdata dbg_reset_nb = {
.notifier_call = dbg_reset_notify,
};
+#ifdef CONFIG_CPU_PM
+static int dbg_cpu_pm_notify(struct notifier_block *self, unsigned long action,
+ void *v)
+{
+ if (action == CPU_PM_EXIT)
+ reset_ctrl_regs(NULL);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata dbg_cpu_pm_nb = {
+ .notifier_call = dbg_cpu_pm_notify,
+};
+
+static void __init pm_init(void)
+{
+ cpu_pm_register_notifier(&dbg_cpu_pm_nb);
+}
+#else
+static inline void pm_init(void)
+{
+}
+#endif
+
static int __init arch_hw_breakpoint_init(void)
{
debug_arch = get_debug_arch();
@@ -1024,6 +1066,8 @@ static int __init arch_hw_breakpoint_init(void)
return 0;
}
+ has_ossr = core_has_os_save_restore();
+
/* Determine how many BRPs/WRPs are available. */
core_num_brps = get_num_brps();
core_num_wrps = get_num_wrps();
@@ -1062,8 +1106,9 @@ static int __init arch_hw_breakpoint_init(void)
hook_ifault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP,
TRAP_HWBKPT, "breakpoint debug exception");
- /* Register hotplug notifier. */
+ /* Register hotplug and PM notifiers. */
register_cpu_notifier(&dbg_reset_nb);
+ pm_init();
return 0;
}
arch_initcall(arch_hw_breakpoint_init);
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 896165096d6a..8e4ef4c83a74 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -117,6 +117,16 @@ void __init init_IRQ(void)
machine_desc->init_irq();
}
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
+{
+ if (handle_arch_irq)
+ return;
+
+ handle_arch_irq = handle_irq;
+}
+#endif
+
#ifdef CONFIG_SPARSE_IRQ
int __init arch_probe_nr_irqs(void)
{
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index f9e8657dd241..31e0eb353cd8 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -149,12 +149,6 @@ again:
static void
armpmu_read(struct perf_event *event)
{
- struct hw_perf_event *hwc = &event->hw;
-
- /* Don't read disabled counters! */
- if (hwc->idx < 0)
- return;
-
armpmu_event_update(event);
}
@@ -207,8 +201,6 @@ armpmu_del(struct perf_event *event, int flags)
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
- WARN_ON(idx < 0);
-
armpmu_stop(event, PERF_EF_UPDATE);
hw_events->events[idx] = NULL;
clear_bit(idx, hw_events->used_mask);
@@ -358,7 +350,7 @@ __hw_perf_event_init(struct perf_event *event)
{
struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
- int mapping, err;
+ int mapping;
mapping = armpmu->map_event(event);
@@ -407,14 +399,12 @@ __hw_perf_event_init(struct perf_event *event)
local64_set(&hwc->period_left, hwc->sample_period);
}
- err = 0;
if (event->group_leader != event) {
- err = validate_group(event);
- if (err)
+ if (validate_group(event) != 0);
return -EINVAL;
}
- return err;
+ return 0;
}
static int armpmu_event_init(struct perf_event *event)
diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c
index 5f6620684e25..1f2740e3dbc0 100644
--- a/arch/arm/kernel/perf_event_cpu.c
+++ b/arch/arm/kernel/perf_event_cpu.c
@@ -147,7 +147,7 @@ static void cpu_pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->free_irq = cpu_pmu_free_irq;
/* Ensure the PMU has sane values out of reset. */
- if (cpu_pmu && cpu_pmu->reset)
+ if (cpu_pmu->reset)
on_each_cpu(cpu_pmu->reset, cpu_pmu, 1);
}
@@ -201,48 +201,46 @@ static struct platform_device_id cpu_pmu_plat_device_ids[] = {
static int probe_current_pmu(struct arm_pmu *pmu)
{
int cpu = get_cpu();
- unsigned long cpuid = read_cpuid_id();
- unsigned long implementor = (cpuid & 0xFF000000) >> 24;
- unsigned long part_number = (cpuid & 0xFFF0);
+ unsigned long implementor = read_cpuid_implementor();
+ unsigned long part_number = read_cpuid_part_number();
int ret = -ENODEV;
pr_info("probing PMU on CPU %d\n", cpu);
/* ARM Ltd CPUs. */
- if (0x41 == implementor) {
+ if (implementor == ARM_CPU_IMP_ARM) {
switch (part_number) {
- case 0xB360: /* ARM1136 */
- case 0xB560: /* ARM1156 */
- case 0xB760: /* ARM1176 */
+ case ARM_CPU_PART_ARM1136:
+ case ARM_CPU_PART_ARM1156:
+ case ARM_CPU_PART_ARM1176:
ret = armv6pmu_init(pmu);
break;
- case 0xB020: /* ARM11mpcore */
+ case ARM_CPU_PART_ARM11MPCORE:
ret = armv6mpcore_pmu_init(pmu);
break;
- case 0xC080: /* Cortex-A8 */
+ case ARM_CPU_PART_CORTEX_A8:
ret = armv7_a8_pmu_init(pmu);
break;
- case 0xC090: /* Cortex-A9 */
+ case ARM_CPU_PART_CORTEX_A9:
ret = armv7_a9_pmu_init(pmu);
break;
- case 0xC050: /* Cortex-A5 */
+ case ARM_CPU_PART_CORTEX_A5:
ret = armv7_a5_pmu_init(pmu);
break;
- case 0xC0F0: /* Cortex-A15 */
+ case ARM_CPU_PART_CORTEX_A15:
ret = armv7_a15_pmu_init(pmu);
break;
- case 0xC070: /* Cortex-A7 */
+ case ARM_CPU_PART_CORTEX_A7:
ret = armv7_a7_pmu_init(pmu);
break;
}
/* Intel CPUs [xscale]. */
- } else if (0x69 == implementor) {
- part_number = (cpuid >> 13) & 0x7;
- switch (part_number) {
- case 1:
+ } else if (implementor == ARM_CPU_IMP_INTEL) {
+ switch (xscale_cpu_arch_version()) {
+ case ARM_CPU_XSCALE_ARCH_V1:
ret = xscale1pmu_init(pmu);
break;
- case 2:
+ case ARM_CPU_XSCALE_ARCH_V2:
ret = xscale2pmu_init(pmu);
break;
}
@@ -279,17 +277,22 @@ static int cpu_pmu_device_probe(struct platform_device *pdev)
}
if (ret) {
- pr_info("failed to register PMU devices!");
- kfree(pmu);
- return ret;
+ pr_info("failed to probe PMU!");
+ goto out_free;
}
cpu_pmu = pmu;
cpu_pmu->plat_device = pdev;
cpu_pmu_init(cpu_pmu);
- armpmu_register(cpu_pmu, PERF_TYPE_RAW);
+ ret = armpmu_register(cpu_pmu, PERF_TYPE_RAW);
- return 0;
+ if (!ret)
+ return 0;
+
+out_free:
+ pr_info("failed to register PMU devices!");
+ kfree(pmu);
+ return ret;
}
static struct platform_driver cpu_pmu_driver = {
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index 041d0526a288..03664b0e8fa4 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -106,7 +106,7 @@ static const unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
- [C(RESULT_MISS)] = ARMV6_PERFCTR_ICACHE_MISS,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
@@ -259,7 +259,7 @@ static const unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
- [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ICACHE_MISS,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 4fbc757d9cff..8c79a9e70b83 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -157,8 +157,8 @@ static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
},
[C(OP_WRITE)] = {
- [C(RESULT_ACCESS)] = ARMV7_A8_PERFCTR_L1_ICACHE_ACCESS,
- [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
@@ -282,7 +282,7 @@ static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
- [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
@@ -399,8 +399,8 @@ static const unsigned armv7_a5_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
},
[C(OP_WRITE)] = {
- [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
- [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
/*
* The prefetch counters don't differentiate between the I
@@ -527,8 +527,8 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
},
[C(OP_WRITE)] = {
- [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
- [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
@@ -651,8 +651,8 @@ static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
},
[C(OP_WRITE)] = {
- [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
- [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL,
+ [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 2b0fe30ec12e..63990c42fac9 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -83,7 +83,7 @@ static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
},
[C(OP_WRITE)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
- [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS,
+ [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index c6dec5fc20aa..047d3e40e470 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -172,14 +172,9 @@ static void default_idle(void)
local_irq_enable();
}
-void (*pm_idle)(void) = default_idle;
-EXPORT_SYMBOL(pm_idle);
-
/*
- * The idle thread, has rather strange semantics for calling pm_idle,
- * but this is what x86 does and we need to do the same, so that
- * things like cpuidle get called in the same way. The only difference
- * is that we always respect 'hlt_counter' to prevent low power idle.
+ * The idle thread.
+ * We always respect 'hlt_counter' to prevent low power idle.
*/
void cpu_idle(void)
{
@@ -210,10 +205,10 @@ void cpu_idle(void)
} else if (!need_resched()) {
stop_critical_timings();
if (cpuidle_idle_call())
- pm_idle();
+ default_idle();
start_critical_timings();
/*
- * pm_idle functions must always
+ * default_idle functions must always
* return with IRQs enabled.
*/
WARN_ON(irqs_disabled());
diff --git a/arch/arm/kernel/psci.c b/arch/arm/kernel/psci.c
new file mode 100644
index 000000000000..36531643cc2c
--- /dev/null
+++ b/arch/arm/kernel/psci.c
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#define pr_fmt(fmt) "psci: " fmt
+
+#include <linux/init.h>
+#include <linux/of.h>
+
+#include <asm/compiler.h>
+#include <asm/errno.h>
+#include <asm/opcodes-sec.h>
+#include <asm/opcodes-virt.h>
+#include <asm/psci.h>
+
+struct psci_operations psci_ops;
+
+static int (*invoke_psci_fn)(u32, u32, u32, u32);
+
+enum psci_function {
+ PSCI_FN_CPU_SUSPEND,
+ PSCI_FN_CPU_ON,
+ PSCI_FN_CPU_OFF,
+ PSCI_FN_MIGRATE,
+ PSCI_FN_MAX,
+};
+
+static u32 psci_function_id[PSCI_FN_MAX];
+
+#define PSCI_RET_SUCCESS 0
+#define PSCI_RET_EOPNOTSUPP -1
+#define PSCI_RET_EINVAL -2
+#define PSCI_RET_EPERM -3
+
+static int psci_to_linux_errno(int errno)
+{
+ switch (errno) {
+ case PSCI_RET_SUCCESS:
+ return 0;
+ case PSCI_RET_EOPNOTSUPP:
+ return -EOPNOTSUPP;
+ case PSCI_RET_EINVAL:
+ return -EINVAL;
+ case PSCI_RET_EPERM:
+ return -EPERM;
+ };
+
+ return -EINVAL;
+}
+
+#define PSCI_POWER_STATE_ID_MASK 0xffff
+#define PSCI_POWER_STATE_ID_SHIFT 0
+#define PSCI_POWER_STATE_TYPE_MASK 0x1
+#define PSCI_POWER_STATE_TYPE_SHIFT 16
+#define PSCI_POWER_STATE_AFFL_MASK 0x3
+#define PSCI_POWER_STATE_AFFL_SHIFT 24
+
+static u32 psci_power_state_pack(struct psci_power_state state)
+{
+ return ((state.id & PSCI_POWER_STATE_ID_MASK)
+ << PSCI_POWER_STATE_ID_SHIFT) |
+ ((state.type & PSCI_POWER_STATE_TYPE_MASK)
+ << PSCI_POWER_STATE_TYPE_SHIFT) |
+ ((state.affinity_level & PSCI_POWER_STATE_AFFL_MASK)
+ << PSCI_POWER_STATE_AFFL_SHIFT);
+}
+
+/*
+ * The following two functions are invoked via the invoke_psci_fn pointer
+ * and will not be inlined, allowing us to piggyback on the AAPCS.
+ */
+static noinline int __invoke_psci_fn_hvc(u32 function_id, u32 arg0, u32 arg1,
+ u32 arg2)
+{
+ asm volatile(
+ __asmeq("%0", "r0")
+ __asmeq("%1", "r1")
+ __asmeq("%2", "r2")
+ __asmeq("%3", "r3")
+ __HVC(0)
+ : "+r" (function_id)
+ : "r" (arg0), "r" (arg1), "r" (arg2));
+
+ return function_id;
+}
+
+static noinline int __invoke_psci_fn_smc(u32 function_id, u32 arg0, u32 arg1,
+ u32 arg2)
+{
+ asm volatile(
+ __asmeq("%0", "r0")
+ __asmeq("%1", "r1")
+ __asmeq("%2", "r2")
+ __asmeq("%3", "r3")
+ __SMC(0)
+ : "+r" (function_id)
+ : "r" (arg0), "r" (arg1), "r" (arg2));
+
+ return function_id;
+}
+
+static int psci_cpu_suspend(struct psci_power_state state,
+ unsigned long entry_point)
+{
+ int err;
+ u32 fn, power_state;
+
+ fn = psci_function_id[PSCI_FN_CPU_SUSPEND];
+ power_state = psci_power_state_pack(state);
+ err = invoke_psci_fn(fn, power_state, entry_point, 0);
+ return psci_to_linux_errno(err);
+}
+
+static int psci_cpu_off(struct psci_power_state state)
+{
+ int err;
+ u32 fn, power_state;
+
+ fn = psci_function_id[PSCI_FN_CPU_OFF];
+ power_state = psci_power_state_pack(state);
+ err = invoke_psci_fn(fn, power_state, 0, 0);
+ return psci_to_linux_errno(err);
+}
+
+static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point)
+{
+ int err;
+ u32 fn;
+
+ fn = psci_function_id[PSCI_FN_CPU_ON];
+ err = invoke_psci_fn(fn, cpuid, entry_point, 0);
+ return psci_to_linux_errno(err);
+}
+
+static int psci_migrate(unsigned long cpuid)
+{
+ int err;
+ u32 fn;
+
+ fn = psci_function_id[PSCI_FN_MIGRATE];
+ err = invoke_psci_fn(fn, cpuid, 0, 0);
+ return psci_to_linux_errno(err);
+}
+
+static const struct of_device_id psci_of_match[] __initconst = {
+ { .compatible = "arm,psci", },
+ {},
+};
+
+static int __init psci_init(void)
+{
+ struct device_node *np;
+ const char *method;
+ u32 id;
+
+ np = of_find_matching_node(NULL, psci_of_match);
+ if (!np)
+ return 0;
+
+ pr_info("probing function IDs from device-tree\n");
+
+ if (of_property_read_string(np, "method", &method)) {
+ pr_warning("missing \"method\" property\n");
+ goto out_put_node;
+ }
+
+ if (!strcmp("hvc", method)) {
+ invoke_psci_fn = __invoke_psci_fn_hvc;
+ } else if (!strcmp("smc", method)) {
+ invoke_psci_fn = __invoke_psci_fn_smc;
+ } else {
+ pr_warning("invalid \"method\" property: %s\n", method);
+ goto out_put_node;
+ }
+
+ if (!of_property_read_u32(np, "cpu_suspend", &id)) {
+ psci_function_id[PSCI_FN_CPU_SUSPEND] = id;
+ psci_ops.cpu_suspend = psci_cpu_suspend;
+ }
+
+ if (!of_property_read_u32(np, "cpu_off", &id)) {
+ psci_function_id[PSCI_FN_CPU_OFF] = id;
+ psci_ops.cpu_off = psci_cpu_off;
+ }
+
+ if (!of_property_read_u32(np, "cpu_on", &id)) {
+ psci_function_id[PSCI_FN_CPU_ON] = id;
+ psci_ops.cpu_on = psci_cpu_on;
+ }
+
+ if (!of_property_read_u32(np, "migrate", &id)) {
+ psci_function_id[PSCI_FN_MIGRATE] = id;
+ psci_ops.migrate = psci_migrate;
+ }
+
+out_put_node:
+ of_node_put(np);
+ return 0;
+}
+early_initcall(psci_init);
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index fc6692e2b603..bd6f56b9ec21 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -93,11 +93,11 @@ static void notrace update_sched_clock(void)
* detectable in cyc_to_fixed_sched_clock().
*/
raw_local_irq_save(flags);
- cd.epoch_cyc = cyc;
+ cd.epoch_cyc_copy = cyc;
smp_wmb();
cd.epoch_ns = ns;
smp_wmb();
- cd.epoch_cyc_copy = cyc;
+ cd.epoch_cyc = cyc;
raw_local_irq_restore(flags);
}
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 56f72d257ebd..296786bdbb73 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -45,48 +45,6 @@ const unsigned long sigreturn_codes[7] = {
MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
};
-/*
- * atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction __user *act,
- struct old_sigaction __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
#ifdef CONFIG_CRUNCH
static int preserve_crunch_context(struct crunch_sigframe __user *frame)
{
@@ -300,7 +258,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigframe(regs, &frame->sig))
goto badframe;
- if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
+ if (restore_altstack(&frame->sig.uc.uc_stack))
goto badframe;
return regs->ARM_r0;
@@ -360,18 +318,12 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
}
static inline void __user *
-get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
+get_sigframe(struct ksignal *ksig, struct pt_regs *regs, int framesize)
{
- unsigned long sp = regs->ARM_sp;
+ unsigned long sp = sigsp(regs->ARM_sp, ksig);
void __user *frame;
/*
- * This is the X/Open sanctioned signal stack switching.
- */
- if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
- sp = current->sas_ss_sp + current->sas_ss_size;
-
- /*
* ATPCS B01 mandates 8-byte alignment
*/
frame = (void __user *)((sp - framesize) & ~7);
@@ -385,11 +337,22 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
return frame;
}
+/*
+ * translate the signal
+ */
+static inline int map_sig(int sig)
+{
+ struct thread_info *thread = current_thread_info();
+ if (sig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
+ sig = thread->exec_domain->signal_invmap[sig];
+ return sig;
+}
+
static int
-setup_return(struct pt_regs *regs, struct k_sigaction *ka,
- unsigned long __user *rc, void __user *frame, int usig)
+setup_return(struct pt_regs *regs, struct ksignal *ksig,
+ unsigned long __user *rc, void __user *frame)
{
- unsigned long handler = (unsigned long)ka->sa.sa_handler;
+ unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler;
unsigned long retcode;
int thumb = 0;
unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT);
@@ -399,7 +362,7 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
/*
* Maybe we need to deliver a 32-bit signal to a 26-bit task.
*/
- if (ka->sa.sa_flags & SA_THIRTYTWO)
+ if (ksig->ka.sa.sa_flags & SA_THIRTYTWO)
cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
#ifdef CONFIG_ARM_THUMB
@@ -421,12 +384,12 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
}
#endif
- if (ka->sa.sa_flags & SA_RESTORER) {
- retcode = (unsigned long)ka->sa.sa_restorer;
+ if (ksig->ka.sa.sa_flags & SA_RESTORER) {
+ retcode = (unsigned long)ksig->ka.sa.sa_restorer;
} else {
unsigned int idx = thumb << 1;
- if (ka->sa.sa_flags & SA_SIGINFO)
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
idx += 3;
if (__put_user(sigreturn_codes[idx], rc) ||
@@ -451,7 +414,7 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
}
}
- regs->ARM_r0 = usig;
+ regs->ARM_r0 = map_sig(ksig->sig);
regs->ARM_sp = (unsigned long)frame;
regs->ARM_lr = retcode;
regs->ARM_pc = handler;
@@ -461,9 +424,9 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
}
static int
-setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs)
+setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
{
- struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame));
+ struct sigframe __user *frame = get_sigframe(ksig, regs, sizeof(*frame));
int err = 0;
if (!frame)
@@ -476,36 +439,29 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg
err |= setup_sigframe(frame, regs, set);
if (err == 0)
- err = setup_return(regs, ka, frame->retcode, frame, usig);
+ err = setup_return(regs, ksig, frame->retcode, frame);
return err;
}
static int
-setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
+setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
{
- struct rt_sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame));
- stack_t stack;
+ struct rt_sigframe __user *frame = get_sigframe(ksig, regs, sizeof(*frame));
int err = 0;
if (!frame)
return 1;
- err |= copy_siginfo_to_user(&frame->info, info);
+ err |= copy_siginfo_to_user(&frame->info, &ksig->info);
__put_user_error(0, &frame->sig.uc.uc_flags, err);
__put_user_error(NULL, &frame->sig.uc.uc_link, err);
- memset(&stack, 0, sizeof(stack));
- stack.ss_sp = (void __user *)current->sas_ss_sp;
- stack.ss_flags = sas_ss_flags(regs->ARM_sp);
- stack.ss_size = current->sas_ss_size;
- err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack));
-
+ err |= __save_altstack(&frame->sig.uc.uc_stack, regs->ARM_sp);
err |= setup_sigframe(&frame->sig, regs, set);
if (err == 0)
- err = setup_return(regs, ka, frame->sig.retcode, frame, usig);
+ err = setup_return(regs, ksig, frame->sig.retcode, frame);
if (err == 0) {
/*
@@ -523,40 +479,25 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
/*
* OK, we're invoking a handler
*/
-static void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
- siginfo_t *info, struct pt_regs *regs)
+static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
- struct thread_info *thread = current_thread_info();
- struct task_struct *tsk = current;
sigset_t *oldset = sigmask_to_save();
- int usig = sig;
int ret;
/*
- * translate the signal
- */
- if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
- usig = thread->exec_domain->signal_invmap[usig];
-
- /*
* Set up the stack frame
*/
- if (ka->sa.sa_flags & SA_SIGINFO)
- ret = setup_rt_frame(usig, ka, info, oldset, regs);
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+ ret = setup_rt_frame(ksig, oldset, regs);
else
- ret = setup_frame(usig, ka, oldset, regs);
+ ret = setup_frame(ksig, oldset, regs);
/*
* Check that the resulting registers are actually sane.
*/
ret |= !valid_user_regs(regs);
- if (ret != 0) {
- force_sigsegv(sig, tsk);
- return;
- }
- signal_delivered(sig, info, ka, regs, 0);
+ signal_setup_done(ret, ksig, 0);
}
/*
@@ -571,9 +512,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
static int do_signal(struct pt_regs *regs, int syscall)
{
unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
- struct k_sigaction ka;
- siginfo_t info;
- int signr;
+ struct ksignal ksig;
int restart = 0;
/*
@@ -605,33 +544,32 @@ static int do_signal(struct pt_regs *regs, int syscall)
* Get the signal to deliver. When running under ptrace, at this
* point the debugger may change all our registers ...
*/
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
/*
* Depending on the signal settings we may need to revert the
* decision to restart the system call. But skip this if a
* debugger has chosen to restart at a different PC.
*/
- if (regs->ARM_pc != restart_addr)
- restart = 0;
- if (signr > 0) {
- if (unlikely(restart)) {
+ if (get_signal(&ksig)) {
+ /* handler */
+ if (unlikely(restart) && regs->ARM_pc == restart_addr) {
if (retval == -ERESTARTNOHAND ||
retval == -ERESTART_RESTARTBLOCK
|| (retval == -ERESTARTSYS
- && !(ka.sa.sa_flags & SA_RESTART))) {
+ && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
regs->ARM_r0 = -EINTR;
regs->ARM_pc = continue_addr;
}
}
-
- handle_signal(signr, &ka, &info, regs);
- return 0;
+ handle_signal(&ksig, regs);
+ } else {
+ /* no handler */
+ restore_saved_sigmask();
+ if (unlikely(restart) && regs->ARM_pc == restart_addr) {
+ regs->ARM_pc = continue_addr;
+ return restart;
+ }
}
-
- restore_saved_sigmask();
- if (unlikely(restart))
- regs->ARM_pc = continue_addr;
- return restart;
+ return 0;
}
asmlinkage int
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 84f4cbf652e5..5f73f7018f50 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -125,18 +125,6 @@ void __init smp_init_cpus(void)
smp_ops.smp_init_cpus();
}
-static void __init platform_smp_prepare_cpus(unsigned int max_cpus)
-{
- if (smp_ops.smp_prepare_cpus)
- smp_ops.smp_prepare_cpus(max_cpus);
-}
-
-static void __cpuinit platform_secondary_init(unsigned int cpu)
-{
- if (smp_ops.smp_secondary_init)
- smp_ops.smp_secondary_init(cpu);
-}
-
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
if (smp_ops.smp_boot_secondary)
@@ -154,12 +142,6 @@ static int platform_cpu_kill(unsigned int cpu)
return 1;
}
-static void platform_cpu_die(unsigned int cpu)
-{
- if (smp_ops.cpu_die)
- smp_ops.cpu_die(cpu);
-}
-
static int platform_cpu_disable(unsigned int cpu)
{
if (smp_ops.cpu_disable)
@@ -257,7 +239,8 @@ void __ref cpu_die(void)
* actual CPU shutdown procedure is at least platform (if not
* CPU) specific.
*/
- platform_cpu_die(cpu);
+ if (smp_ops.cpu_die)
+ smp_ops.cpu_die(cpu);
/*
* Do not return to the idle loop - jump back to the secondary
@@ -324,7 +307,8 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
/*
* Give the platform a chance to do its own initialisation.
*/
- platform_secondary_init(cpu);
+ if (smp_ops.smp_secondary_init)
+ smp_ops.smp_secondary_init(cpu);
notify_cpu_starting(cpu);
@@ -399,8 +383,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
/*
* Initialise the present map, which describes the set of CPUs
* actually populated at the present time. A platform should
- * re-initialize the map in platform_smp_prepare_cpus() if
- * present != possible (e.g. physical hotplug).
+ * re-initialize the map in the platforms smp_prepare_cpus()
+ * if present != possible (e.g. physical hotplug).
*/
init_cpu_present(cpu_possible_mask);
@@ -408,7 +392,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
* Initialise the SCU if there are more than one CPU
* and let them know where to start.
*/
- platform_smp_prepare_cpus(max_cpus);
+ if (smp_ops.smp_prepare_cpus)
+ smp_ops.smp_prepare_cpus(max_cpus);
}
}
@@ -416,7 +401,8 @@ 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;
+ if (!smp_cross_call)
+ smp_cross_call = fn;
}
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
@@ -475,14 +461,8 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
*/
static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
-static void ipi_timer(void)
-{
- struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
- evt->event_handler(evt);
-}
-
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
-static void smp_timer_broadcast(const struct cpumask *mask)
+void tick_broadcast(const struct cpumask *mask)
{
smp_cross_call(mask, IPI_TIMER);
}
@@ -530,7 +510,6 @@ static void __cpuinit percpu_timer_setup(void)
struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
evt->cpumask = cpumask_of(cpu);
- evt->broadcast = smp_timer_broadcast;
if (!lt_ops || lt_ops->setup(evt))
broadcast_timer_setup(evt);
@@ -596,11 +575,13 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
case IPI_WAKEUP:
break;
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
case IPI_TIMER:
irq_enter();
- ipi_timer();
+ tick_receive_broadcast();
irq_exit();
break;
+#endif
case IPI_RESCHEDULE:
scheduler_ipi();
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index b9f015e843d8..45eac87ed66a 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -75,7 +75,7 @@ void scu_enable(void __iomem *scu_base)
int scu_power_mode(void __iomem *scu_base, unsigned int mode)
{
unsigned int val;
- int cpu = cpu_logical_map(smp_processor_id());
+ int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0);
if (mode > 3 || mode == 1 || cpu > 3)
return -EINVAL;
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 49f335d301ba..c092115d903a 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -24,14 +24,12 @@
#include <asm/smp_twd.h>
#include <asm/localtimer.h>
-#include <asm/hardware/gic.h>
/* set up by the platform code */
static void __iomem *twd_base;
static struct clk *twd_clk;
static unsigned long twd_timer_rate;
-static bool common_setup_called;
static DEFINE_PER_CPU(bool, percpu_setup_called);
static struct clock_event_device __percpu **twd_evt;
@@ -239,25 +237,28 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
return IRQ_NONE;
}
-static struct clk *twd_get_clock(void)
+static void twd_get_clock(struct device_node *np)
{
- struct clk *clk;
int err;
- clk = clk_get_sys("smp_twd", NULL);
- if (IS_ERR(clk)) {
- pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
- return clk;
+ if (np)
+ twd_clk = of_clk_get(np, 0);
+ else
+ twd_clk = clk_get_sys("smp_twd", NULL);
+
+ if (IS_ERR(twd_clk)) {
+ pr_err("smp_twd: clock not found %d\n", (int) PTR_ERR(twd_clk));
+ return;
}
- err = clk_prepare_enable(clk);
+ err = clk_prepare_enable(twd_clk);
if (err) {
pr_err("smp_twd: clock failed to prepare+enable: %d\n", err);
- clk_put(clk);
- return ERR_PTR(err);
+ clk_put(twd_clk);
+ return;
}
- return clk;
+ twd_timer_rate = clk_get_rate(twd_clk);
}
/*
@@ -280,26 +281,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
}
per_cpu(percpu_setup_called, cpu) = true;
- /*
- * This stuff only need to be done once for the entire TWD cluster
- * during the runtime of the system.
- */
- if (!common_setup_called) {
- twd_clk = twd_get_clock();
-
- /*
- * We use IS_ERR_OR_NULL() here, because if the clock stubs
- * are active we will get a valid clk reference which is
- * however NULL and will return the rate 0. In that case we
- * need to calibrate the rate instead.
- */
- if (!IS_ERR_OR_NULL(twd_clk))
- twd_timer_rate = clk_get_rate(twd_clk);
- else
- twd_calibrate_rate();
-
- common_setup_called = true;
- }
+ twd_calibrate_rate();
/*
* The following is done once per CPU the first time .setup() is
@@ -330,7 +312,7 @@ static struct local_timer_ops twd_lt_ops __cpuinitdata = {
.stop = twd_timer_stop,
};
-static int __init twd_local_timer_common_register(void)
+static int __init twd_local_timer_common_register(struct device_node *np)
{
int err;
@@ -350,6 +332,8 @@ static int __init twd_local_timer_common_register(void)
if (err)
goto out_irq;
+ twd_get_clock(np);
+
return 0;
out_irq:
@@ -373,7 +357,7 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
if (!twd_base)
return -ENOMEM;
- return twd_local_timer_common_register();
+ return twd_local_timer_common_register(NULL);
}
#ifdef CONFIG_OF
@@ -405,7 +389,7 @@ void __init twd_local_timer_of_register(void)
goto out;
}
- err = twd_local_timer_common_register();
+ err = twd_local_timer_common_register(np);
out:
WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 09be0c3c9069..955d92d265e5 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -21,7 +21,6 @@
#include <linux/timex.h>
#include <linux/errno.h>
#include <linux/profile.h>
-#include <linux/syscore_ops.h>
#include <linux/timer.h>
#include <linux/irq.h>
@@ -31,11 +30,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
-/*
- * Our system timer.
- */
-static struct sys_timer *system_timer;
-
#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || \
defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE)
/* this needs a better home */
@@ -69,16 +63,6 @@ unsigned long profile_pc(struct pt_regs *regs)
EXPORT_SYMBOL(profile_pc);
#endif
-#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
-u32 arch_gettimeoffset(void)
-{
- if (system_timer->offset != NULL)
- return system_timer->offset() * 1000;
-
- return 0;
-}
-#endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */
-
#ifndef CONFIG_GENERIC_CLOCKEVENTS
/*
* Kernel system timer support.
@@ -129,43 +113,8 @@ int __init register_persistent_clock(clock_access_fn read_boot,
return -EINVAL;
}
-#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
-static int timer_suspend(void)
-{
- if (system_timer->suspend)
- system_timer->suspend();
-
- return 0;
-}
-
-static void timer_resume(void)
-{
- if (system_timer->resume)
- system_timer->resume();
-}
-#else
-#define timer_suspend NULL
-#define timer_resume NULL
-#endif
-
-static struct syscore_ops timer_syscore_ops = {
- .suspend = timer_suspend,
- .resume = timer_resume,
-};
-
-static int __init timer_init_syscore_ops(void)
-{
- register_syscore_ops(&timer_syscore_ops);
-
- return 0;
-}
-
-device_initcall(timer_init_syscore_ops);
-
void __init time_init(void)
{
- system_timer = machine_desc->timer;
- system_timer->init();
+ machine_desc->init_time();
sched_clock_postinit();
}
-
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index b0179b89a04c..1c089119b2d7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -296,7 +296,7 @@ static void oops_end(unsigned long flags, struct pt_regs *regs, int signr)
bust_spinlocks(0);
die_owner = -1;
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
die_nest_count--;
if (!die_nest_count)
/* Nest count reaches zero, release the lock. */
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 11c1785bf63e..b571484e9f03 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -19,7 +19,11 @@
ALIGN_FUNCTION(); \
VMLINUX_SYMBOL(__idmap_text_start) = .; \
*(.idmap.text) \
- VMLINUX_SYMBOL(__idmap_text_end) = .;
+ VMLINUX_SYMBOL(__idmap_text_end) = .; \
+ ALIGN_FUNCTION(); \
+ VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \
+ *(.hyp.idmap.text) \
+ VMLINUX_SYMBOL(__hyp_idmap_text_end) = .;
#ifdef CONFIG_HOTPLUG_CPU
#define ARM_CPU_DISCARD(x)
diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
new file mode 100644
index 000000000000..49dd64e579c2
--- /dev/null
+++ b/arch/arm/kvm/Kconfig
@@ -0,0 +1,72 @@
+#
+# KVM configuration
+#
+
+source "virt/kvm/Kconfig"
+
+menuconfig VIRTUALIZATION
+ bool "Virtualization"
+ ---help---
+ Say Y here to get to see options for using your Linux host to run
+ other operating systems inside virtual machines (guests).
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and
+ disabled.
+
+if VIRTUALIZATION
+
+config KVM
+ bool "Kernel-based Virtual Machine (KVM) support"
+ select PREEMPT_NOTIFIERS
+ select ANON_INODES
+ select KVM_MMIO
+ select KVM_ARM_HOST
+ depends on ARM_VIRT_EXT && ARM_LPAE
+ ---help---
+ Support hosting virtualized guest machines. You will also
+ need to select one or more of the processor modules below.
+
+ This module provides access to the hardware capabilities through
+ a character device node named /dev/kvm.
+
+ If unsure, say N.
+
+config KVM_ARM_HOST
+ bool "KVM host support for ARM cpus."
+ depends on KVM
+ depends on MMU
+ select MMU_NOTIFIER
+ ---help---
+ Provides host support for ARM processors.
+
+config KVM_ARM_MAX_VCPUS
+ int "Number maximum supported virtual CPUs per VM"
+ depends on KVM_ARM_HOST
+ default 4
+ help
+ Static number of max supported virtual CPUs per VM.
+
+ If you choose a high number, the vcpu structures will be quite
+ large, so only choose a reasonable number that you expect to
+ actually use.
+
+config KVM_ARM_VGIC
+ bool "KVM support for Virtual GIC"
+ depends on KVM_ARM_HOST && OF
+ select HAVE_KVM_IRQCHIP
+ default y
+ ---help---
+ Adds support for a hardware assisted, in-kernel GIC emulation.
+
+config KVM_ARM_TIMER
+ bool "KVM support for Architected Timers"
+ depends on KVM_ARM_VGIC && ARM_ARCH_TIMER
+ select HAVE_KVM_IRQCHIP
+ default y
+ ---help---
+ Adds support for the Architected Timers in virtual machines
+
+source drivers/virtio/Kconfig
+
+endif # VIRTUALIZATION
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
new file mode 100644
index 000000000000..fc96ce6f2357
--- /dev/null
+++ b/arch/arm/kvm/Makefile
@@ -0,0 +1,23 @@
+#
+# Makefile for Kernel-based Virtual Machine module
+#
+
+plus_virt := $(call as-instr,.arch_extension virt,+virt)
+ifeq ($(plus_virt),+virt)
+ plus_virt_def := -DREQUIRES_VIRT=1
+endif
+
+ccflags-y += -Ivirt/kvm -Iarch/arm/kvm
+CFLAGS_arm.o := -I. $(plus_virt_def)
+CFLAGS_mmu.o := -I.
+
+AFLAGS_init.o := -Wa,-march=armv7-a$(plus_virt)
+AFLAGS_interrupts.o := -Wa,-march=armv7-a$(plus_virt)
+
+kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
+
+obj-y += kvm-arm.o init.o interrupts.o
+obj-y += arm.o guest.o mmu.o emulate.o reset.o
+obj-y += coproc.o coproc_a15.o mmio.o psci.o
+obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o
+obj-$(CONFIG_KVM_ARM_TIMER) += arch_timer.o
diff --git a/arch/arm/kvm/arch_timer.c b/arch/arm/kvm/arch_timer.c
new file mode 100644
index 000000000000..6ac938d46297
--- /dev/null
+++ b/arch/arm/kvm/arch_timer.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/cpu.h>
+#include <linux/of_irq.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/interrupt.h>
+
+#include <asm/arch_timer.h>
+
+#include <asm/kvm_vgic.h>
+#include <asm/kvm_arch_timer.h>
+
+static struct timecounter *timecounter;
+static struct workqueue_struct *wqueue;
+static struct kvm_irq_level timer_irq = {
+ .level = 1,
+};
+
+static cycle_t kvm_phys_timer_read(void)
+{
+ return timecounter->cc->read(timecounter->cc);
+}
+
+static bool timer_is_armed(struct arch_timer_cpu *timer)
+{
+ return timer->armed;
+}
+
+/* timer_arm: as in "arm the timer", not as in ARM the company */
+static void timer_arm(struct arch_timer_cpu *timer, u64 ns)
+{
+ timer->armed = true;
+ hrtimer_start(&timer->timer, ktime_add_ns(ktime_get(), ns),
+ HRTIMER_MODE_ABS);
+}
+
+static void timer_disarm(struct arch_timer_cpu *timer)
+{
+ if (timer_is_armed(timer)) {
+ hrtimer_cancel(&timer->timer);
+ cancel_work_sync(&timer->expired);
+ timer->armed = false;
+ }
+}
+
+static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+ timer->cntv_ctl |= 1 << 1; /* Mask the interrupt in the guest */
+ kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
+ vcpu->arch.timer_cpu.irq->irq,
+ vcpu->arch.timer_cpu.irq->level);
+}
+
+static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
+{
+ struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
+
+ /*
+ * We disable the timer in the world switch and let it be
+ * handled by kvm_timer_sync_hwstate(). Getting a timer
+ * interrupt at this point is a sure sign of some major
+ * breakage.
+ */
+ pr_warn("Unexpected interrupt %d on vcpu %p\n", irq, vcpu);
+ return IRQ_HANDLED;
+}
+
+static void kvm_timer_inject_irq_work(struct work_struct *work)
+{
+ struct kvm_vcpu *vcpu;
+
+ vcpu = container_of(work, struct kvm_vcpu, arch.timer_cpu.expired);
+ vcpu->arch.timer_cpu.armed = false;
+ kvm_timer_inject_irq(vcpu);
+}
+
+static enum hrtimer_restart kvm_timer_expire(struct hrtimer *hrt)
+{
+ struct arch_timer_cpu *timer;
+ timer = container_of(hrt, struct arch_timer_cpu, timer);
+ queue_work(wqueue, &timer->expired);
+ return HRTIMER_NORESTART;
+}
+
+/**
+ * kvm_timer_flush_hwstate - prepare to move the virt timer to the cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Disarm any pending soft timers, since the world-switch code will write the
+ * virtual timer state back to the physical CPU.
+ */
+void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+ /*
+ * We're about to run this vcpu again, so there is no need to
+ * keep the background timer running, as we're about to
+ * populate the CPU timer again.
+ */
+ timer_disarm(timer);
+}
+
+/**
+ * kvm_timer_sync_hwstate - sync timer state from cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Check if the virtual timer was armed and either schedule a corresponding
+ * soft timer or inject directly if already expired.
+ */
+void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+ cycle_t cval, now;
+ u64 ns;
+
+ /* Check if the timer is enabled and unmasked first */
+ if ((timer->cntv_ctl & 3) != 1)
+ return;
+
+ cval = timer->cntv_cval;
+ now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
+
+ BUG_ON(timer_is_armed(timer));
+
+ if (cval <= now) {
+ /*
+ * Timer has already expired while we were not
+ * looking. Inject the interrupt and carry on.
+ */
+ kvm_timer_inject_irq(vcpu);
+ return;
+ }
+
+ ns = cyclecounter_cyc2ns(timecounter->cc, cval - now);
+ timer_arm(timer, ns);
+}
+
+void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+ INIT_WORK(&timer->expired, kvm_timer_inject_irq_work);
+ hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ timer->timer.function = kvm_timer_expire;
+ timer->irq = &timer_irq;
+}
+
+static void kvm_timer_init_interrupt(void *info)
+{
+ enable_percpu_irq(timer_irq.irq, 0);
+}
+
+
+static int kvm_timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *cpu)
+{
+ switch (action) {
+ case CPU_STARTING:
+ case CPU_STARTING_FROZEN:
+ kvm_timer_init_interrupt(NULL);
+ break;
+ case CPU_DYING:
+ case CPU_DYING_FROZEN:
+ disable_percpu_irq(timer_irq.irq);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block kvm_timer_cpu_nb = {
+ .notifier_call = kvm_timer_cpu_notify,
+};
+
+static const struct of_device_id arch_timer_of_match[] = {
+ { .compatible = "arm,armv7-timer", },
+ {},
+};
+
+int kvm_timer_hyp_init(void)
+{
+ struct device_node *np;
+ unsigned int ppi;
+ int err;
+
+ timecounter = arch_timer_get_timecounter();
+ if (!timecounter)
+ return -ENODEV;
+
+ np = of_find_matching_node(NULL, arch_timer_of_match);
+ if (!np) {
+ kvm_err("kvm_arch_timer: can't find DT node\n");
+ return -ENODEV;
+ }
+
+ ppi = irq_of_parse_and_map(np, 2);
+ if (!ppi) {
+ kvm_err("kvm_arch_timer: no virtual timer interrupt\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = request_percpu_irq(ppi, kvm_arch_timer_handler,
+ "kvm guest timer", kvm_get_running_vcpus());
+ if (err) {
+ kvm_err("kvm_arch_timer: can't request interrupt %d (%d)\n",
+ ppi, err);
+ goto out;
+ }
+
+ timer_irq.irq = ppi;
+
+ err = register_cpu_notifier(&kvm_timer_cpu_nb);
+ if (err) {
+ kvm_err("Cannot register timer CPU notifier\n");
+ goto out_free;
+ }
+
+ wqueue = create_singlethread_workqueue("kvm_arch_timer");
+ if (!wqueue) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ kvm_info("%s IRQ%d\n", np->name, ppi);
+ on_each_cpu(kvm_timer_init_interrupt, NULL, 1);
+
+ goto out;
+out_free:
+ free_percpu_irq(ppi, kvm_get_running_vcpus());
+out:
+ of_node_put(np);
+ return err;
+}
+
+void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+ timer_disarm(timer);
+}
+
+int kvm_timer_init(struct kvm *kvm)
+{
+ if (timecounter && wqueue) {
+ kvm->arch.timer.cntvoff = kvm_phys_timer_read();
+ kvm->arch.timer.enabled = 1;
+ }
+
+ return 0;
+}
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
new file mode 100644
index 000000000000..5a936988eb24
--- /dev/null
+++ b/arch/arm/kvm/arm.c
@@ -0,0 +1,1169 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/mman.h>
+#include <linux/sched.h>
+#include <linux/kvm.h>
+#include <trace/events/kvm.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#include <asm/unified.h>
+#include <asm/uaccess.h>
+#include <asm/ptrace.h>
+#include <asm/mman.h>
+#include <asm/cputype.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/virt.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmu.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+#include <asm/kvm_psci.h>
+#include <asm/opcodes.h>
+
+#ifdef REQUIRES_VIRT
+__asm__(".arch_extension virt");
+#endif
+
+static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
+static struct vfp_hard_struct __percpu *kvm_host_vfp_state;
+static unsigned long hyp_default_vectors;
+
+/* Per-CPU variable containing the currently running vcpu. */
+static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu);
+
+/* The VMID used in the VTTBR */
+static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
+static u8 kvm_next_vmid;
+static DEFINE_SPINLOCK(kvm_vmid_lock);
+
+static bool vgic_present;
+
+static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
+{
+ BUG_ON(preemptible());
+ __get_cpu_var(kvm_arm_running_vcpu) = vcpu;
+}
+
+/**
+ * kvm_arm_get_running_vcpu - get the vcpu running on the current CPU.
+ * Must be called from non-preemptible context
+ */
+struct kvm_vcpu *kvm_arm_get_running_vcpu(void)
+{
+ BUG_ON(preemptible());
+ return __get_cpu_var(kvm_arm_running_vcpu);
+}
+
+/**
+ * kvm_arm_get_running_vcpus - get the per-CPU array of currently running vcpus.
+ */
+struct kvm_vcpu __percpu **kvm_get_running_vcpus(void)
+{
+ return &kvm_arm_running_vcpu;
+}
+
+int kvm_arch_hardware_enable(void *garbage)
+{
+ return 0;
+}
+
+int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
+}
+
+void kvm_arch_hardware_disable(void *garbage)
+{
+}
+
+int kvm_arch_hardware_setup(void)
+{
+ return 0;
+}
+
+void kvm_arch_hardware_unsetup(void)
+{
+}
+
+void kvm_arch_check_processor_compat(void *rtn)
+{
+ *(int *)rtn = 0;
+}
+
+void kvm_arch_sync_events(struct kvm *kvm)
+{
+}
+
+/**
+ * kvm_arch_init_vm - initializes a VM data structure
+ * @kvm: pointer to the KVM struct
+ */
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
+{
+ int ret = 0;
+
+ if (type)
+ return -EINVAL;
+
+ ret = kvm_alloc_stage2_pgd(kvm);
+ if (ret)
+ goto out_fail_alloc;
+
+ ret = create_hyp_mappings(kvm, kvm + 1);
+ if (ret)
+ goto out_free_stage2_pgd;
+
+ /* Mark the initial VMID generation invalid */
+ kvm->arch.vmid_gen = 0;
+
+ return ret;
+out_free_stage2_pgd:
+ kvm_free_stage2_pgd(kvm);
+out_fail_alloc:
+ return ret;
+}
+
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+ return VM_FAULT_SIGBUS;
+}
+
+void kvm_arch_free_memslot(struct kvm_memory_slot *free,
+ struct kvm_memory_slot *dont)
+{
+}
+
+int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
+{
+ return 0;
+}
+
+/**
+ * kvm_arch_destroy_vm - destroy the VM data structure
+ * @kvm: pointer to the KVM struct
+ */
+void kvm_arch_destroy_vm(struct kvm *kvm)
+{
+ int i;
+
+ kvm_free_stage2_pgd(kvm);
+
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ if (kvm->vcpus[i]) {
+ kvm_arch_vcpu_free(kvm->vcpus[i]);
+ kvm->vcpus[i] = NULL;
+ }
+ }
+}
+
+int kvm_dev_ioctl_check_extension(long ext)
+{
+ int r;
+ switch (ext) {
+ case KVM_CAP_IRQCHIP:
+ r = vgic_present;
+ break;
+ case KVM_CAP_USER_MEMORY:
+ case KVM_CAP_SYNC_MMU:
+ case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
+ case KVM_CAP_ONE_REG:
+ case KVM_CAP_ARM_PSCI:
+ r = 1;
+ break;
+ case KVM_CAP_COALESCED_MMIO:
+ r = KVM_COALESCED_MMIO_PAGE_OFFSET;
+ break;
+ case KVM_CAP_ARM_SET_DEVICE_ADDR:
+ r = 1;
+ case KVM_CAP_NR_VCPUS:
+ r = num_online_cpus();
+ break;
+ case KVM_CAP_MAX_VCPUS:
+ r = KVM_MAX_VCPUS;
+ break;
+ default:
+ r = 0;
+ break;
+ }
+ return r;
+}
+
+long kvm_arch_dev_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_set_memory_region(struct kvm *kvm,
+ struct kvm_userspace_memory_region *mem,
+ struct kvm_memory_slot old,
+ int user_alloc)
+{
+ return 0;
+}
+
+int kvm_arch_prepare_memory_region(struct kvm *kvm,
+ struct kvm_memory_slot *memslot,
+ struct kvm_memory_slot old,
+ struct kvm_userspace_memory_region *mem,
+ bool user_alloc)
+{
+ return 0;
+}
+
+void kvm_arch_commit_memory_region(struct kvm *kvm,
+ struct kvm_userspace_memory_region *mem,
+ struct kvm_memory_slot old,
+ bool user_alloc)
+{
+}
+
+void kvm_arch_flush_shadow_all(struct kvm *kvm)
+{
+}
+
+void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
+ struct kvm_memory_slot *slot)
+{
+}
+
+struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
+{
+ int err;
+ struct kvm_vcpu *vcpu;
+
+ vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+ if (!vcpu) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = kvm_vcpu_init(vcpu, kvm, id);
+ if (err)
+ goto free_vcpu;
+
+ err = create_hyp_mappings(vcpu, vcpu + 1);
+ if (err)
+ goto vcpu_uninit;
+
+ return vcpu;
+vcpu_uninit:
+ kvm_vcpu_uninit(vcpu);
+free_vcpu:
+ kmem_cache_free(kvm_vcpu_cache, vcpu);
+out:
+ return ERR_PTR(err);
+}
+
+int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
+{
+ kvm_mmu_free_memory_caches(vcpu);
+ kvm_timer_vcpu_terminate(vcpu);
+ kmem_cache_free(kvm_vcpu_cache, vcpu);
+}
+
+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+ kvm_arch_vcpu_free(vcpu);
+}
+
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+int __attribute_const__ kvm_target_cpu(void)
+{
+ unsigned long implementor = read_cpuid_implementor();
+ unsigned long part_number = read_cpuid_part_number();
+
+ if (implementor != ARM_CPU_IMP_ARM)
+ return -EINVAL;
+
+ switch (part_number) {
+ case ARM_CPU_PART_CORTEX_A15:
+ return KVM_ARM_TARGET_CORTEX_A15;
+ default:
+ return -EINVAL;
+ }
+}
+
+int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ int ret;
+
+ /* Force users to call KVM_ARM_VCPU_INIT */
+ vcpu->arch.target = -1;
+
+ /* Set up VGIC */
+ ret = kvm_vgic_vcpu_init(vcpu);
+ if (ret)
+ return ret;
+
+ /* Set up the timer */
+ kvm_timer_vcpu_init(vcpu);
+
+ return 0;
+}
+
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+ vcpu->cpu = cpu;
+ vcpu->arch.vfp_host = this_cpu_ptr(kvm_host_vfp_state);
+
+ /*
+ * Check whether this vcpu requires the cache to be flushed on
+ * this physical CPU. This is a consequence of doing dcache
+ * operations by set/way on this vcpu. We do it here to be in
+ * a non-preemptible section.
+ */
+ if (cpumask_test_and_clear_cpu(cpu, &vcpu->arch.require_dcache_flush))
+ flush_cache_all(); /* We'd really want v7_flush_dcache_all() */
+
+ kvm_arm_set_running_vcpu(vcpu);
+}
+
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+{
+ kvm_arm_set_running_vcpu(NULL);
+}
+
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug *dbg)
+{
+ return -EINVAL;
+}
+
+
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ return -EINVAL;
+}
+
+/**
+ * kvm_arch_vcpu_runnable - determine if the vcpu can be scheduled
+ * @v: The VCPU pointer
+ *
+ * If the guest CPU is not waiting for interrupts or an interrupt line is
+ * asserted, the CPU is by definition runnable.
+ */
+int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
+{
+ return !!v->arch.irq_lines || kvm_vgic_vcpu_pending_irq(v);
+}
+
+/* Just ensure a guest exit from a particular CPU */
+static void exit_vm_noop(void *info)
+{
+}
+
+void force_vm_exit(const cpumask_t *mask)
+{
+ smp_call_function_many(mask, exit_vm_noop, NULL, true);
+}
+
+/**
+ * need_new_vmid_gen - check that the VMID is still valid
+ * @kvm: The VM's VMID to checkt
+ *
+ * return true if there is a new generation of VMIDs being used
+ *
+ * The hardware supports only 256 values with the value zero reserved for the
+ * host, so we check if an assigned value belongs to a previous generation,
+ * which which requires us to assign a new value. If we're the first to use a
+ * VMID for the new generation, we must flush necessary caches and TLBs on all
+ * CPUs.
+ */
+static bool need_new_vmid_gen(struct kvm *kvm)
+{
+ return unlikely(kvm->arch.vmid_gen != atomic64_read(&kvm_vmid_gen));
+}
+
+/**
+ * update_vttbr - Update the VTTBR with a valid VMID before the guest runs
+ * @kvm The guest that we are about to run
+ *
+ * Called from kvm_arch_vcpu_ioctl_run before entering the guest to ensure the
+ * VM has a valid VMID, otherwise assigns a new one and flushes corresponding
+ * caches and TLBs.
+ */
+static void update_vttbr(struct kvm *kvm)
+{
+ phys_addr_t pgd_phys;
+ u64 vmid;
+
+ if (!need_new_vmid_gen(kvm))
+ return;
+
+ spin_lock(&kvm_vmid_lock);
+
+ /*
+ * We need to re-check the vmid_gen here to ensure that if another vcpu
+ * already allocated a valid vmid for this vm, then this vcpu should
+ * use the same vmid.
+ */
+ if (!need_new_vmid_gen(kvm)) {
+ spin_unlock(&kvm_vmid_lock);
+ return;
+ }
+
+ /* First user of a new VMID generation? */
+ if (unlikely(kvm_next_vmid == 0)) {
+ atomic64_inc(&kvm_vmid_gen);
+ kvm_next_vmid = 1;
+
+ /*
+ * On SMP we know no other CPUs can use this CPU's or each
+ * other's VMID after force_vm_exit returns since the
+ * kvm_vmid_lock blocks them from reentry to the guest.
+ */
+ force_vm_exit(cpu_all_mask);
+ /*
+ * Now broadcast TLB + ICACHE invalidation over the inner
+ * shareable domain to make sure all data structures are
+ * clean.
+ */
+ kvm_call_hyp(__kvm_flush_vm_context);
+ }
+
+ kvm->arch.vmid_gen = atomic64_read(&kvm_vmid_gen);
+ kvm->arch.vmid = kvm_next_vmid;
+ kvm_next_vmid++;
+
+ /* update vttbr to be used with the new vmid */
+ pgd_phys = virt_to_phys(kvm->arch.pgd);
+ vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK;
+ kvm->arch.vttbr = pgd_phys & VTTBR_BADDR_MASK;
+ kvm->arch.vttbr |= vmid;
+
+ spin_unlock(&kvm_vmid_lock);
+}
+
+static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ /* SVC called from Hyp mode should never get here */
+ kvm_debug("SVC called from Hyp mode shouldn't go here\n");
+ BUG();
+ return -EINVAL; /* Squash warning */
+}
+
+static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
+ vcpu->arch.hsr & HSR_HVC_IMM_MASK);
+
+ if (kvm_psci_call(vcpu))
+ return 1;
+
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ if (kvm_psci_call(vcpu))
+ return 1;
+
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+static int handle_pabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ /* The hypervisor should never cause aborts */
+ kvm_err("Prefetch Abort taken from Hyp mode at %#08x (HSR: %#08x)\n",
+ vcpu->arch.hxfar, vcpu->arch.hsr);
+ return -EFAULT;
+}
+
+static int handle_dabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ /* This is either an error in the ws. code or an external abort */
+ kvm_err("Data Abort taken from Hyp mode at %#08x (HSR: %#08x)\n",
+ vcpu->arch.hxfar, vcpu->arch.hsr);
+ return -EFAULT;
+}
+
+typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
+static exit_handle_fn arm_exit_handlers[] = {
+ [HSR_EC_WFI] = kvm_handle_wfi,
+ [HSR_EC_CP15_32] = kvm_handle_cp15_32,
+ [HSR_EC_CP15_64] = kvm_handle_cp15_64,
+ [HSR_EC_CP14_MR] = kvm_handle_cp14_access,
+ [HSR_EC_CP14_LS] = kvm_handle_cp14_load_store,
+ [HSR_EC_CP14_64] = kvm_handle_cp14_access,
+ [HSR_EC_CP_0_13] = kvm_handle_cp_0_13_access,
+ [HSR_EC_CP10_ID] = kvm_handle_cp10_id,
+ [HSR_EC_SVC_HYP] = handle_svc_hyp,
+ [HSR_EC_HVC] = handle_hvc,
+ [HSR_EC_SMC] = handle_smc,
+ [HSR_EC_IABT] = kvm_handle_guest_abort,
+ [HSR_EC_IABT_HYP] = handle_pabt_hyp,
+ [HSR_EC_DABT] = kvm_handle_guest_abort,
+ [HSR_EC_DABT_HYP] = handle_dabt_hyp,
+};
+
+/*
+ * A conditional instruction is allowed to trap, even though it
+ * wouldn't be executed. So let's re-implement the hardware, in
+ * software!
+ */
+static bool kvm_condition_valid(struct kvm_vcpu *vcpu)
+{
+ unsigned long cpsr, cond, insn;
+
+ /*
+ * Exception Code 0 can only happen if we set HCR.TGE to 1, to
+ * catch undefined instructions, and then we won't get past
+ * the arm_exit_handlers test anyway.
+ */
+ BUG_ON(((vcpu->arch.hsr & HSR_EC) >> HSR_EC_SHIFT) == 0);
+
+ /* Top two bits non-zero? Unconditional. */
+ if (vcpu->arch.hsr >> 30)
+ return true;
+
+ cpsr = *vcpu_cpsr(vcpu);
+
+ /* Is condition field valid? */
+ if ((vcpu->arch.hsr & HSR_CV) >> HSR_CV_SHIFT)
+ cond = (vcpu->arch.hsr & HSR_COND) >> HSR_COND_SHIFT;
+ else {
+ /* This can happen in Thumb mode: examine IT state. */
+ unsigned long it;
+
+ it = ((cpsr >> 8) & 0xFC) | ((cpsr >> 25) & 0x3);
+
+ /* it == 0 => unconditional. */
+ if (it == 0)
+ return true;
+
+ /* The cond for this insn works out as the top 4 bits. */
+ cond = (it >> 4);
+ }
+
+ /* Shift makes it look like an ARM-mode instruction */
+ insn = cond << 28;
+ return arm_check_condition(insn, cpsr) != ARM_OPCODE_CONDTEST_FAIL;
+}
+
+/*
+ * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
+ * proper exit to QEMU.
+ */
+static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ int exception_index)
+{
+ unsigned long hsr_ec;
+
+ switch (exception_index) {
+ case ARM_EXCEPTION_IRQ:
+ return 1;
+ case ARM_EXCEPTION_UNDEFINED:
+ kvm_err("Undefined exception in Hyp mode at: %#08x\n",
+ vcpu->arch.hyp_pc);
+ BUG();
+ panic("KVM: Hypervisor undefined exception!\n");
+ case ARM_EXCEPTION_DATA_ABORT:
+ case ARM_EXCEPTION_PREF_ABORT:
+ case ARM_EXCEPTION_HVC:
+ hsr_ec = (vcpu->arch.hsr & HSR_EC) >> HSR_EC_SHIFT;
+
+ if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers)
+ || !arm_exit_handlers[hsr_ec]) {
+ kvm_err("Unkown exception class: %#08lx, "
+ "hsr: %#08x\n", hsr_ec,
+ (unsigned int)vcpu->arch.hsr);
+ BUG();
+ }
+
+ /*
+ * See ARM ARM B1.14.1: "Hyp traps on instructions
+ * that fail their condition code check"
+ */
+ if (!kvm_condition_valid(vcpu)) {
+ bool is_wide = vcpu->arch.hsr & HSR_IL;
+ kvm_skip_instr(vcpu, is_wide);
+ return 1;
+ }
+
+ return arm_exit_handlers[hsr_ec](vcpu, run);
+ default:
+ kvm_pr_unimpl("Unsupported exception type: %d",
+ exception_index);
+ run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+ return 0;
+ }
+}
+
+static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
+{
+ if (likely(vcpu->arch.has_run_once))
+ return 0;
+
+ vcpu->arch.has_run_once = true;
+
+ /*
+ * Initialize the VGIC before running a vcpu the first time on
+ * this VM.
+ */
+ if (irqchip_in_kernel(vcpu->kvm) &&
+ unlikely(!vgic_initialized(vcpu->kvm))) {
+ int ret = kvm_vgic_init(vcpu->kvm);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Handle the "start in power-off" case by calling into the
+ * PSCI code.
+ */
+ if (test_and_clear_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features)) {
+ *vcpu_reg(vcpu, 0) = KVM_PSCI_FN_CPU_OFF;
+ kvm_psci_call(vcpu);
+ }
+
+ return 0;
+}
+
+static void vcpu_pause(struct kvm_vcpu *vcpu)
+{
+ wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu);
+
+ wait_event_interruptible(*wq, !vcpu->arch.pause);
+}
+
+/**
+ * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
+ * @vcpu: The VCPU pointer
+ * @run: The kvm_run structure pointer used for userspace state exchange
+ *
+ * This function is called through the VCPU_RUN ioctl called from user space. It
+ * will execute VM code in a loop until the time slice for the process is used
+ * or some emulation is needed from user space in which case the function will
+ * return with return value 0 and with the kvm_run structure filled in with the
+ * required data for the requested emulation.
+ */
+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ int ret;
+ sigset_t sigsaved;
+
+ /* Make sure they initialize the vcpu with KVM_ARM_VCPU_INIT */
+ if (unlikely(vcpu->arch.target < 0))
+ return -ENOEXEC;
+
+ ret = kvm_vcpu_first_run_init(vcpu);
+ if (ret)
+ return ret;
+
+ if (run->exit_reason == KVM_EXIT_MMIO) {
+ ret = kvm_handle_mmio_return(vcpu, vcpu->run);
+ if (ret)
+ return ret;
+ }
+
+ if (vcpu->sigset_active)
+ sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
+
+ ret = 1;
+ run->exit_reason = KVM_EXIT_UNKNOWN;
+ while (ret > 0) {
+ /*
+ * Check conditions before entering the guest
+ */
+ cond_resched();
+
+ update_vttbr(vcpu->kvm);
+
+ if (vcpu->arch.pause)
+ vcpu_pause(vcpu);
+
+ kvm_vgic_flush_hwstate(vcpu);
+ kvm_timer_flush_hwstate(vcpu);
+
+ local_irq_disable();
+
+ /*
+ * Re-check atomic conditions
+ */
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ run->exit_reason = KVM_EXIT_INTR;
+ }
+
+ if (ret <= 0 || need_new_vmid_gen(vcpu->kvm)) {
+ local_irq_enable();
+ kvm_timer_sync_hwstate(vcpu);
+ kvm_vgic_sync_hwstate(vcpu);
+ continue;
+ }
+
+ /**************************************************************
+ * Enter the guest
+ */
+ trace_kvm_entry(*vcpu_pc(vcpu));
+ kvm_guest_enter();
+ vcpu->mode = IN_GUEST_MODE;
+
+ ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
+
+ vcpu->mode = OUTSIDE_GUEST_MODE;
+ vcpu->arch.last_pcpu = smp_processor_id();
+ kvm_guest_exit();
+ trace_kvm_exit(*vcpu_pc(vcpu));
+ /*
+ * We may have taken a host interrupt in HYP mode (ie
+ * while executing the guest). This interrupt is still
+ * pending, as we haven't serviced it yet!
+ *
+ * We're now back in SVC mode, with interrupts
+ * disabled. Enabling the interrupts now will have
+ * the effect of taking the interrupt again, in SVC
+ * mode this time.
+ */
+ local_irq_enable();
+
+ /*
+ * Back from guest
+ *************************************************************/
+
+ kvm_timer_sync_hwstate(vcpu);
+ kvm_vgic_sync_hwstate(vcpu);
+
+ ret = handle_exit(vcpu, run, ret);
+ }
+
+ if (vcpu->sigset_active)
+ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+ return ret;
+}
+
+static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level)
+{
+ int bit_index;
+ bool set;
+ unsigned long *ptr;
+
+ if (number == KVM_ARM_IRQ_CPU_IRQ)
+ bit_index = __ffs(HCR_VI);
+ else /* KVM_ARM_IRQ_CPU_FIQ */
+ bit_index = __ffs(HCR_VF);
+
+ ptr = (unsigned long *)&vcpu->arch.irq_lines;
+ if (level)
+ set = test_and_set_bit(bit_index, ptr);
+ else
+ set = test_and_clear_bit(bit_index, ptr);
+
+ /*
+ * If we didn't change anything, no need to wake up or kick other CPUs
+ */
+ if (set == level)
+ return 0;
+
+ /*
+ * The vcpu irq_lines field was updated, wake up sleeping VCPUs and
+ * trigger a world-switch round on the running physical CPU to set the
+ * virtual IRQ/FIQ fields in the HCR appropriately.
+ */
+ kvm_vcpu_kick(vcpu);
+
+ return 0;
+}
+
+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level)
+{
+ u32 irq = irq_level->irq;
+ unsigned int irq_type, vcpu_idx, irq_num;
+ int nrcpus = atomic_read(&kvm->online_vcpus);
+ struct kvm_vcpu *vcpu = NULL;
+ bool level = irq_level->level;
+
+ irq_type = (irq >> KVM_ARM_IRQ_TYPE_SHIFT) & KVM_ARM_IRQ_TYPE_MASK;
+ vcpu_idx = (irq >> KVM_ARM_IRQ_VCPU_SHIFT) & KVM_ARM_IRQ_VCPU_MASK;
+ irq_num = (irq >> KVM_ARM_IRQ_NUM_SHIFT) & KVM_ARM_IRQ_NUM_MASK;
+
+ trace_kvm_irq_line(irq_type, vcpu_idx, irq_num, irq_level->level);
+
+ switch (irq_type) {
+ case KVM_ARM_IRQ_TYPE_CPU:
+ if (irqchip_in_kernel(kvm))
+ return -ENXIO;
+
+ if (vcpu_idx >= nrcpus)
+ return -EINVAL;
+
+ vcpu = kvm_get_vcpu(kvm, vcpu_idx);
+ if (!vcpu)
+ return -EINVAL;
+
+ if (irq_num > KVM_ARM_IRQ_CPU_FIQ)
+ return -EINVAL;
+
+ return vcpu_interrupt_line(vcpu, irq_num, level);
+ case KVM_ARM_IRQ_TYPE_PPI:
+ if (!irqchip_in_kernel(kvm))
+ return -ENXIO;
+
+ if (vcpu_idx >= nrcpus)
+ return -EINVAL;
+
+ vcpu = kvm_get_vcpu(kvm, vcpu_idx);
+ if (!vcpu)
+ return -EINVAL;
+
+ if (irq_num < VGIC_NR_SGIS || irq_num >= VGIC_NR_PRIVATE_IRQS)
+ return -EINVAL;
+
+ return kvm_vgic_inject_irq(kvm, vcpu->vcpu_id, irq_num, level);
+ case KVM_ARM_IRQ_TYPE_SPI:
+ if (!irqchip_in_kernel(kvm))
+ return -ENXIO;
+
+ if (irq_num < VGIC_NR_PRIVATE_IRQS ||
+ irq_num > KVM_ARM_IRQ_GIC_MAX)
+ return -EINVAL;
+
+ return kvm_vgic_inject_irq(kvm, 0, irq_num, level);
+ }
+
+ return -EINVAL;
+}
+
+long kvm_arch_vcpu_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm_vcpu *vcpu = filp->private_data;
+ void __user *argp = (void __user *)arg;
+
+ switch (ioctl) {
+ case KVM_ARM_VCPU_INIT: {
+ struct kvm_vcpu_init init;
+
+ if (copy_from_user(&init, argp, sizeof(init)))
+ return -EFAULT;
+
+ return kvm_vcpu_set_target(vcpu, &init);
+
+ }
+ case KVM_SET_ONE_REG:
+ case KVM_GET_ONE_REG: {
+ struct kvm_one_reg reg;
+ if (copy_from_user(&reg, argp, sizeof(reg)))
+ return -EFAULT;
+ if (ioctl == KVM_SET_ONE_REG)
+ return kvm_arm_set_reg(vcpu, &reg);
+ else
+ return kvm_arm_get_reg(vcpu, &reg);
+ }
+ case KVM_GET_REG_LIST: {
+ struct kvm_reg_list __user *user_list = argp;
+ struct kvm_reg_list reg_list;
+ unsigned n;
+
+ if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
+ return -EFAULT;
+ n = reg_list.n;
+ reg_list.n = kvm_arm_num_regs(vcpu);
+ if (copy_to_user(user_list, &reg_list, sizeof(reg_list)))
+ return -EFAULT;
+ if (n < reg_list.n)
+ return -E2BIG;
+ return kvm_arm_copy_reg_indices(vcpu, user_list->reg);
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+ return -EINVAL;
+}
+
+static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
+ struct kvm_arm_device_addr *dev_addr)
+{
+ unsigned long dev_id, type;
+
+ dev_id = (dev_addr->id & KVM_ARM_DEVICE_ID_MASK) >>
+ KVM_ARM_DEVICE_ID_SHIFT;
+ type = (dev_addr->id & KVM_ARM_DEVICE_TYPE_MASK) >>
+ KVM_ARM_DEVICE_TYPE_SHIFT;
+
+ switch (dev_id) {
+ case KVM_ARM_DEVICE_VGIC_V2:
+ if (!vgic_present)
+ return -ENXIO;
+ return kvm_vgic_set_addr(kvm, type, dev_addr->addr);
+ default:
+ return -ENODEV;
+ }
+}
+
+long kvm_arch_vm_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm *kvm = filp->private_data;
+ void __user *argp = (void __user *)arg;
+
+ switch (ioctl) {
+ case KVM_CREATE_IRQCHIP: {
+ if (vgic_present)
+ return kvm_vgic_create(kvm);
+ else
+ return -ENXIO;
+ }
+ case KVM_ARM_SET_DEVICE_ADDR: {
+ struct kvm_arm_device_addr dev_addr;
+
+ if (copy_from_user(&dev_addr, argp, sizeof(dev_addr)))
+ return -EFAULT;
+ return kvm_vm_ioctl_set_device_addr(kvm, &dev_addr);
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static void cpu_init_hyp_mode(void *vector)
+{
+ unsigned long long pgd_ptr;
+ unsigned long pgd_low, pgd_high;
+ unsigned long hyp_stack_ptr;
+ unsigned long stack_page;
+ unsigned long vector_ptr;
+
+ /* Switch from the HYP stub to our own HYP init vector */
+ __hyp_set_vectors((unsigned long)vector);
+
+ pgd_ptr = (unsigned long long)kvm_mmu_get_httbr();
+ pgd_low = (pgd_ptr & ((1ULL << 32) - 1));
+ pgd_high = (pgd_ptr >> 32ULL);
+ stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
+ hyp_stack_ptr = stack_page + PAGE_SIZE;
+ vector_ptr = (unsigned long)__kvm_hyp_vector;
+
+ /*
+ * Call initialization code, and switch to the full blown
+ * HYP code. The init code doesn't need to preserve these registers as
+ * r1-r3 and r12 are already callee save according to the AAPCS.
+ * Note that we slightly misuse the prototype by casing the pgd_low to
+ * a void *.
+ */
+ kvm_call_hyp((void *)pgd_low, pgd_high, hyp_stack_ptr, vector_ptr);
+}
+
+/**
+ * Inits Hyp-mode on all online CPUs
+ */
+static int init_hyp_mode(void)
+{
+ phys_addr_t init_phys_addr;
+ int cpu;
+ int err = 0;
+
+ /*
+ * Allocate Hyp PGD and setup Hyp identity mapping
+ */
+ err = kvm_mmu_init();
+ if (err)
+ goto out_err;
+
+ /*
+ * It is probably enough to obtain the default on one
+ * CPU. It's unlikely to be different on the others.
+ */
+ hyp_default_vectors = __hyp_get_vectors();
+
+ /*
+ * Allocate stack pages for Hypervisor-mode
+ */
+ for_each_possible_cpu(cpu) {
+ unsigned long stack_page;
+
+ stack_page = __get_free_page(GFP_KERNEL);
+ if (!stack_page) {
+ err = -ENOMEM;
+ goto out_free_stack_pages;
+ }
+
+ per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page;
+ }
+
+ /*
+ * Execute the init code on each CPU.
+ *
+ * Note: The stack is not mapped yet, so don't do anything else than
+ * initializing the hypervisor mode on each CPU using a local stack
+ * space for temporary storage.
+ */
+ init_phys_addr = virt_to_phys(__kvm_hyp_init);
+ for_each_online_cpu(cpu) {
+ smp_call_function_single(cpu, cpu_init_hyp_mode,
+ (void *)(long)init_phys_addr, 1);
+ }
+
+ /*
+ * Unmap the identity mapping
+ */
+ kvm_clear_hyp_idmap();
+
+ /*
+ * Map the Hyp-code called directly from the host
+ */
+ err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end);
+ if (err) {
+ kvm_err("Cannot map world-switch code\n");
+ goto out_free_mappings;
+ }
+
+ /*
+ * Map the Hyp stack pages
+ */
+ for_each_possible_cpu(cpu) {
+ char *stack_page = (char *)per_cpu(kvm_arm_hyp_stack_page, cpu);
+ err = create_hyp_mappings(stack_page, stack_page + PAGE_SIZE);
+
+ if (err) {
+ kvm_err("Cannot map hyp stack\n");
+ goto out_free_mappings;
+ }
+ }
+
+ /*
+ * Map the host VFP structures
+ */
+ kvm_host_vfp_state = alloc_percpu(struct vfp_hard_struct);
+ if (!kvm_host_vfp_state) {
+ err = -ENOMEM;
+ kvm_err("Cannot allocate host VFP state\n");
+ goto out_free_mappings;
+ }
+
+ for_each_possible_cpu(cpu) {
+ struct vfp_hard_struct *vfp;
+
+ vfp = per_cpu_ptr(kvm_host_vfp_state, cpu);
+ err = create_hyp_mappings(vfp, vfp + 1);
+
+ if (err) {
+ kvm_err("Cannot map host VFP state: %d\n", err);
+ goto out_free_vfp;
+ }
+ }
+
+ /*
+ * Init HYP view of VGIC
+ */
+ err = kvm_vgic_hyp_init();
+ if (err)
+ goto out_free_vfp;
+
+#ifdef CONFIG_KVM_ARM_VGIC
+ vgic_present = true;
+#endif
+
+ /*
+ * Init HYP architected timer support
+ */
+ err = kvm_timer_hyp_init();
+ if (err)
+ goto out_free_mappings;
+
+ kvm_info("Hyp mode initialized successfully\n");
+ return 0;
+out_free_vfp:
+ free_percpu(kvm_host_vfp_state);
+out_free_mappings:
+ free_hyp_pmds();
+out_free_stack_pages:
+ for_each_possible_cpu(cpu)
+ free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
+out_err:
+ kvm_err("error initializing Hyp mode: %d\n", err);
+ return err;
+}
+
+/**
+ * Initialize Hyp-mode and memory mappings on all CPUs.
+ */
+int kvm_arch_init(void *opaque)
+{
+ int err;
+
+ if (!is_hyp_mode_available()) {
+ kvm_err("HYP mode not available\n");
+ return -ENODEV;
+ }
+
+ if (kvm_target_cpu() < 0) {
+ kvm_err("Target CPU not supported!\n");
+ return -ENODEV;
+ }
+
+ err = init_hyp_mode();
+ if (err)
+ goto out_err;
+
+ kvm_coproc_table_init();
+ return 0;
+out_err:
+ return err;
+}
+
+/* NOP: Compiling as a module not supported */
+void kvm_arch_exit(void)
+{
+}
+
+static int arm_init(void)
+{
+ int rc = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
+ return rc;
+}
+
+module_init(arm_init);
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
new file mode 100644
index 000000000000..4ea9a982269c
--- /dev/null
+++ b/arch/arm/kvm/coproc.c
@@ -0,0 +1,1050 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Authors: Rusty Russell <rusty@rustcorp.com.au>
+ * Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <linux/mm.h>
+#include <linux/kvm_host.h>
+#include <linux/uaccess.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <trace/events/kvm.h>
+#include <asm/vfp.h>
+#include "../vfp/vfpinstr.h"
+
+#include "trace.h"
+#include "coproc.h"
+
+
+/******************************************************************************
+ * Co-processor emulation
+ *****************************************************************************/
+
+/* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
+static u32 cache_levels;
+
+/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */
+#define CSSELR_MAX 12
+
+int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ /*
+ * We can get here, if the host has been built without VFPv3 support,
+ * but the guest attempted a floating point operation.
+ */
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+/* See note at ARM ARM B1.14.4 */
+static bool access_dcsw(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r)
+{
+ u32 val;
+ int cpu;
+
+ cpu = get_cpu();
+
+ if (!p->is_write)
+ return read_from_write_only(vcpu, p);
+
+ cpumask_setall(&vcpu->arch.require_dcache_flush);
+ cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush);
+
+ /* If we were already preempted, take the long way around */
+ if (cpu != vcpu->arch.last_pcpu) {
+ flush_cache_all();
+ goto done;
+ }
+
+ val = *vcpu_reg(vcpu, p->Rt1);
+
+ switch (p->CRm) {
+ case 6: /* Upgrade DCISW to DCCISW, as per HCR.SWIO */
+ case 14: /* DCCISW */
+ asm volatile("mcr p15, 0, %0, c7, c14, 2" : : "r" (val));
+ break;
+
+ case 10: /* DCCSW */
+ asm volatile("mcr p15, 0, %0, c7, c10, 2" : : "r" (val));
+ break;
+ }
+
+done:
+ put_cpu();
+
+ return true;
+}
+
+/*
+ * We could trap ID_DFR0 and tell the guest we don't support performance
+ * monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
+ * NAKed, so it will read the PMCR anyway.
+ *
+ * Therefore we tell the guest we have 0 counters. Unfortunately, we
+ * must always support PMCCNTR (the cycle counter): we just RAZ/WI for
+ * all PM registers, which doesn't crash the guest kernel at least.
+ */
+static bool pm_fake(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r)
+{
+ if (p->is_write)
+ return ignore_write(vcpu, p);
+ else
+ return read_zero(vcpu, p);
+}
+
+#define access_pmcr pm_fake
+#define access_pmcntenset pm_fake
+#define access_pmcntenclr pm_fake
+#define access_pmovsr pm_fake
+#define access_pmselr pm_fake
+#define access_pmceid0 pm_fake
+#define access_pmceid1 pm_fake
+#define access_pmccntr pm_fake
+#define access_pmxevtyper pm_fake
+#define access_pmxevcntr pm_fake
+#define access_pmuserenr pm_fake
+#define access_pmintenset pm_fake
+#define access_pmintenclr pm_fake
+
+/* Architected CP15 registers.
+ * Important: Must be sorted ascending by CRn, CRM, Op1, Op2
+ */
+static const struct coproc_reg cp15_regs[] = {
+ /* CSSELR: swapped by interrupt.S. */
+ { CRn( 0), CRm( 0), Op1( 2), Op2( 0), is32,
+ NULL, reset_unknown, c0_CSSELR },
+
+ /* TTBR0/TTBR1: swapped by interrupt.S. */
+ { CRm( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
+ { CRm( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
+
+ /* TTBCR: swapped by interrupt.S. */
+ { CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32,
+ NULL, reset_val, c2_TTBCR, 0x00000000 },
+
+ /* DACR: swapped by interrupt.S. */
+ { CRn( 3), CRm( 0), Op1( 0), Op2( 0), is32,
+ NULL, reset_unknown, c3_DACR },
+
+ /* DFSR/IFSR/ADFSR/AIFSR: swapped by interrupt.S. */
+ { CRn( 5), CRm( 0), Op1( 0), Op2( 0), is32,
+ NULL, reset_unknown, c5_DFSR },
+ { CRn( 5), CRm( 0), Op1( 0), Op2( 1), is32,
+ NULL, reset_unknown, c5_IFSR },
+ { CRn( 5), CRm( 1), Op1( 0), Op2( 0), is32,
+ NULL, reset_unknown, c5_ADFSR },
+ { CRn( 5), CRm( 1), Op1( 0), Op2( 1), is32,
+ NULL, reset_unknown, c5_AIFSR },
+
+ /* DFAR/IFAR: swapped by interrupt.S. */
+ { CRn( 6), CRm( 0), Op1( 0), Op2( 0), is32,
+ NULL, reset_unknown, c6_DFAR },
+ { CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32,
+ NULL, reset_unknown, c6_IFAR },
+ /*
+ * DC{C,I,CI}SW operations:
+ */
+ { CRn( 7), CRm( 6), Op1( 0), Op2( 2), is32, access_dcsw},
+ { CRn( 7), CRm(10), Op1( 0), Op2( 2), is32, access_dcsw},
+ { CRn( 7), CRm(14), Op1( 0), Op2( 2), is32, access_dcsw},
+ /*
+ * Dummy performance monitor implementation.
+ */
+ { CRn( 9), CRm(12), Op1( 0), Op2( 0), is32, access_pmcr},
+ { CRn( 9), CRm(12), Op1( 0), Op2( 1), is32, access_pmcntenset},
+ { CRn( 9), CRm(12), Op1( 0), Op2( 2), is32, access_pmcntenclr},
+ { CRn( 9), CRm(12), Op1( 0), Op2( 3), is32, access_pmovsr},
+ { CRn( 9), CRm(12), Op1( 0), Op2( 5), is32, access_pmselr},
+ { CRn( 9), CRm(12), Op1( 0), Op2( 6), is32, access_pmceid0},
+ { CRn( 9), CRm(12), Op1( 0), Op2( 7), is32, access_pmceid1},
+ { CRn( 9), CRm(13), Op1( 0), Op2( 0), is32, access_pmccntr},
+ { CRn( 9), CRm(13), Op1( 0), Op2( 1), is32, access_pmxevtyper},
+ { CRn( 9), CRm(13), Op1( 0), Op2( 2), is32, access_pmxevcntr},
+ { CRn( 9), CRm(14), Op1( 0), Op2( 0), is32, access_pmuserenr},
+ { CRn( 9), CRm(14), Op1( 0), Op2( 1), is32, access_pmintenset},
+ { CRn( 9), CRm(14), Op1( 0), Op2( 2), is32, access_pmintenclr},
+
+ /* PRRR/NMRR (aka MAIR0/MAIR1): swapped by interrupt.S. */
+ { CRn(10), CRm( 2), Op1( 0), Op2( 0), is32,
+ NULL, reset_unknown, c10_PRRR},
+ { CRn(10), CRm( 2), Op1( 0), Op2( 1), is32,
+ NULL, reset_unknown, c10_NMRR},
+
+ /* VBAR: swapped by interrupt.S. */
+ { CRn(12), CRm( 0), Op1( 0), Op2( 0), is32,
+ NULL, reset_val, c12_VBAR, 0x00000000 },
+
+ /* CONTEXTIDR/TPIDRURW/TPIDRURO/TPIDRPRW: swapped by interrupt.S. */
+ { CRn(13), CRm( 0), Op1( 0), Op2( 1), is32,
+ NULL, reset_val, c13_CID, 0x00000000 },
+ { CRn(13), CRm( 0), Op1( 0), Op2( 2), is32,
+ NULL, reset_unknown, c13_TID_URW },
+ { CRn(13), CRm( 0), Op1( 0), Op2( 3), is32,
+ NULL, reset_unknown, c13_TID_URO },
+ { CRn(13), CRm( 0), Op1( 0), Op2( 4), is32,
+ NULL, reset_unknown, c13_TID_PRIV },
+
+ /* CNTKCTL: swapped by interrupt.S. */
+ { CRn(14), CRm( 1), Op1( 0), Op2( 0), is32,
+ NULL, reset_val, c14_CNTKCTL, 0x00000000 },
+};
+
+/* Target specific emulation tables */
+static struct kvm_coproc_target_table *target_tables[KVM_ARM_NUM_TARGETS];
+
+void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table)
+{
+ target_tables[table->target] = table;
+}
+
+/* Get specific register table for this target. */
+static const struct coproc_reg *get_target_table(unsigned target, size_t *num)
+{
+ struct kvm_coproc_target_table *table;
+
+ table = target_tables[target];
+ *num = table->num;
+ return table->table;
+}
+
+static const struct coproc_reg *find_reg(const struct coproc_params *params,
+ const struct coproc_reg table[],
+ unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++) {
+ const struct coproc_reg *r = &table[i];
+
+ if (params->is_64bit != r->is_64)
+ continue;
+ if (params->CRn != r->CRn)
+ continue;
+ if (params->CRm != r->CRm)
+ continue;
+ if (params->Op1 != r->Op1)
+ continue;
+ if (params->Op2 != r->Op2)
+ continue;
+
+ return r;
+ }
+ return NULL;
+}
+
+static int emulate_cp15(struct kvm_vcpu *vcpu,
+ const struct coproc_params *params)
+{
+ size_t num;
+ const struct coproc_reg *table, *r;
+
+ trace_kvm_emulate_cp15_imp(params->Op1, params->Rt1, params->CRn,
+ params->CRm, params->Op2, params->is_write);
+
+ table = get_target_table(vcpu->arch.target, &num);
+
+ /* Search target-specific then generic table. */
+ r = find_reg(params, table, num);
+ if (!r)
+ r = find_reg(params, cp15_regs, ARRAY_SIZE(cp15_regs));
+
+ if (likely(r)) {
+ /* If we don't have an accessor, we should never get here! */
+ BUG_ON(!r->access);
+
+ if (likely(r->access(vcpu, params, r))) {
+ /* Skip instruction, since it was emulated */
+ kvm_skip_instr(vcpu, (vcpu->arch.hsr >> 25) & 1);
+ return 1;
+ }
+ /* If access function fails, it should complain. */
+ } else {
+ kvm_err("Unsupported guest CP15 access at: %08x\n",
+ *vcpu_pc(vcpu));
+ print_cp_instr(params);
+ }
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+/**
+ * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access
+ * @vcpu: The VCPU pointer
+ * @run: The kvm_run struct
+ */
+int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ struct coproc_params params;
+
+ params.CRm = (vcpu->arch.hsr >> 1) & 0xf;
+ params.Rt1 = (vcpu->arch.hsr >> 5) & 0xf;
+ params.is_write = ((vcpu->arch.hsr & 1) == 0);
+ params.is_64bit = true;
+
+ params.Op1 = (vcpu->arch.hsr >> 16) & 0xf;
+ params.Op2 = 0;
+ params.Rt2 = (vcpu->arch.hsr >> 10) & 0xf;
+ params.CRn = 0;
+
+ return emulate_cp15(vcpu, &params);
+}
+
+static void reset_coproc_regs(struct kvm_vcpu *vcpu,
+ const struct coproc_reg *table, size_t num)
+{
+ unsigned long i;
+
+ for (i = 0; i < num; i++)
+ if (table[i].reset)
+ table[i].reset(vcpu, &table[i]);
+}
+
+/**
+ * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access
+ * @vcpu: The VCPU pointer
+ * @run: The kvm_run struct
+ */
+int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ struct coproc_params params;
+
+ params.CRm = (vcpu->arch.hsr >> 1) & 0xf;
+ params.Rt1 = (vcpu->arch.hsr >> 5) & 0xf;
+ params.is_write = ((vcpu->arch.hsr & 1) == 0);
+ params.is_64bit = false;
+
+ params.CRn = (vcpu->arch.hsr >> 10) & 0xf;
+ params.Op1 = (vcpu->arch.hsr >> 14) & 0x7;
+ params.Op2 = (vcpu->arch.hsr >> 17) & 0x7;
+ params.Rt2 = 0;
+
+ return emulate_cp15(vcpu, &params);
+}
+
+/******************************************************************************
+ * Userspace API
+ *****************************************************************************/
+
+static bool index_to_params(u64 id, struct coproc_params *params)
+{
+ switch (id & KVM_REG_SIZE_MASK) {
+ case KVM_REG_SIZE_U32:
+ /* Any unused index bits means it's not valid. */
+ if (id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK
+ | KVM_REG_ARM_COPROC_MASK
+ | KVM_REG_ARM_32_CRN_MASK
+ | KVM_REG_ARM_CRM_MASK
+ | KVM_REG_ARM_OPC1_MASK
+ | KVM_REG_ARM_32_OPC2_MASK))
+ return false;
+
+ params->is_64bit = false;
+ params->CRn = ((id & KVM_REG_ARM_32_CRN_MASK)
+ >> KVM_REG_ARM_32_CRN_SHIFT);
+ params->CRm = ((id & KVM_REG_ARM_CRM_MASK)
+ >> KVM_REG_ARM_CRM_SHIFT);
+ params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK)
+ >> KVM_REG_ARM_OPC1_SHIFT);
+ params->Op2 = ((id & KVM_REG_ARM_32_OPC2_MASK)
+ >> KVM_REG_ARM_32_OPC2_SHIFT);
+ return true;
+ case KVM_REG_SIZE_U64:
+ /* Any unused index bits means it's not valid. */
+ if (id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK
+ | KVM_REG_ARM_COPROC_MASK
+ | KVM_REG_ARM_CRM_MASK
+ | KVM_REG_ARM_OPC1_MASK))
+ return false;
+ params->is_64bit = true;
+ params->CRm = ((id & KVM_REG_ARM_CRM_MASK)
+ >> KVM_REG_ARM_CRM_SHIFT);
+ params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK)
+ >> KVM_REG_ARM_OPC1_SHIFT);
+ params->Op2 = 0;
+ params->CRn = 0;
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Decode an index value, and find the cp15 coproc_reg entry. */
+static const struct coproc_reg *index_to_coproc_reg(struct kvm_vcpu *vcpu,
+ u64 id)
+{
+ size_t num;
+ const struct coproc_reg *table, *r;
+ struct coproc_params params;
+
+ /* We only do cp15 for now. */
+ if ((id & KVM_REG_ARM_COPROC_MASK) >> KVM_REG_ARM_COPROC_SHIFT != 15)
+ return NULL;
+
+ if (!index_to_params(id, &params))
+ return NULL;
+
+ table = get_target_table(vcpu->arch.target, &num);
+ r = find_reg(&params, table, num);
+ if (!r)
+ r = find_reg(&params, cp15_regs, ARRAY_SIZE(cp15_regs));
+
+ /* Not saved in the cp15 array? */
+ if (r && !r->reg)
+ r = NULL;
+
+ return r;
+}
+
+/*
+ * These are the invariant cp15 registers: we let the guest see the host
+ * versions of these, so they're part of the guest state.
+ *
+ * A future CPU may provide a mechanism to present different values to
+ * the guest, or a future kvm may trap them.
+ */
+/* Unfortunately, there's no register-argument for mrc, so generate. */
+#define FUNCTION_FOR32(crn, crm, op1, op2, name) \
+ static void get_##name(struct kvm_vcpu *v, \
+ const struct coproc_reg *r) \
+ { \
+ u32 val; \
+ \
+ asm volatile("mrc p15, " __stringify(op1) \
+ ", %0, c" __stringify(crn) \
+ ", c" __stringify(crm) \
+ ", " __stringify(op2) "\n" : "=r" (val)); \
+ ((struct coproc_reg *)r)->val = val; \
+ }
+
+FUNCTION_FOR32(0, 0, 0, 0, MIDR)
+FUNCTION_FOR32(0, 0, 0, 1, CTR)
+FUNCTION_FOR32(0, 0, 0, 2, TCMTR)
+FUNCTION_FOR32(0, 0, 0, 3, TLBTR)
+FUNCTION_FOR32(0, 0, 0, 6, REVIDR)
+FUNCTION_FOR32(0, 1, 0, 0, ID_PFR0)
+FUNCTION_FOR32(0, 1, 0, 1, ID_PFR1)
+FUNCTION_FOR32(0, 1, 0, 2, ID_DFR0)
+FUNCTION_FOR32(0, 1, 0, 3, ID_AFR0)
+FUNCTION_FOR32(0, 1, 0, 4, ID_MMFR0)
+FUNCTION_FOR32(0, 1, 0, 5, ID_MMFR1)
+FUNCTION_FOR32(0, 1, 0, 6, ID_MMFR2)
+FUNCTION_FOR32(0, 1, 0, 7, ID_MMFR3)
+FUNCTION_FOR32(0, 2, 0, 0, ID_ISAR0)
+FUNCTION_FOR32(0, 2, 0, 1, ID_ISAR1)
+FUNCTION_FOR32(0, 2, 0, 2, ID_ISAR2)
+FUNCTION_FOR32(0, 2, 0, 3, ID_ISAR3)
+FUNCTION_FOR32(0, 2, 0, 4, ID_ISAR4)
+FUNCTION_FOR32(0, 2, 0, 5, ID_ISAR5)
+FUNCTION_FOR32(0, 0, 1, 1, CLIDR)
+FUNCTION_FOR32(0, 0, 1, 7, AIDR)
+
+/* ->val is filled in by kvm_invariant_coproc_table_init() */
+static struct coproc_reg invariant_cp15[] = {
+ { CRn( 0), CRm( 0), Op1( 0), Op2( 0), is32, NULL, get_MIDR },
+ { CRn( 0), CRm( 0), Op1( 0), Op2( 1), is32, NULL, get_CTR },
+ { CRn( 0), CRm( 0), Op1( 0), Op2( 2), is32, NULL, get_TCMTR },
+ { CRn( 0), CRm( 0), Op1( 0), Op2( 3), is32, NULL, get_TLBTR },
+ { CRn( 0), CRm( 0), Op1( 0), Op2( 6), is32, NULL, get_REVIDR },
+
+ { CRn( 0), CRm( 1), Op1( 0), Op2( 0), is32, NULL, get_ID_PFR0 },
+ { CRn( 0), CRm( 1), Op1( 0), Op2( 1), is32, NULL, get_ID_PFR1 },
+ { CRn( 0), CRm( 1), Op1( 0), Op2( 2), is32, NULL, get_ID_DFR0 },
+ { CRn( 0), CRm( 1), Op1( 0), Op2( 3), is32, NULL, get_ID_AFR0 },
+ { CRn( 0), CRm( 1), Op1( 0), Op2( 4), is32, NULL, get_ID_MMFR0 },
+ { CRn( 0), CRm( 1), Op1( 0), Op2( 5), is32, NULL, get_ID_MMFR1 },
+ { CRn( 0), CRm( 1), Op1( 0), Op2( 6), is32, NULL, get_ID_MMFR2 },
+ { CRn( 0), CRm( 1), Op1( 0), Op2( 7), is32, NULL, get_ID_MMFR3 },
+
+ { CRn( 0), CRm( 2), Op1( 0), Op2( 0), is32, NULL, get_ID_ISAR0 },
+ { CRn( 0), CRm( 2), Op1( 0), Op2( 1), is32, NULL, get_ID_ISAR1 },
+ { CRn( 0), CRm( 2), Op1( 0), Op2( 2), is32, NULL, get_ID_ISAR2 },
+ { CRn( 0), CRm( 2), Op1( 0), Op2( 3), is32, NULL, get_ID_ISAR3 },
+ { CRn( 0), CRm( 2), Op1( 0), Op2( 4), is32, NULL, get_ID_ISAR4 },
+ { CRn( 0), CRm( 2), Op1( 0), Op2( 5), is32, NULL, get_ID_ISAR5 },
+
+ { CRn( 0), CRm( 0), Op1( 1), Op2( 1), is32, NULL, get_CLIDR },
+ { CRn( 0), CRm( 0), Op1( 1), Op2( 7), is32, NULL, get_AIDR },
+};
+
+static int reg_from_user(void *val, const void __user *uaddr, u64 id)
+{
+ /* This Just Works because we are little endian. */
+ if (copy_from_user(val, uaddr, KVM_REG_SIZE(id)) != 0)
+ return -EFAULT;
+ return 0;
+}
+
+static int reg_to_user(void __user *uaddr, const void *val, u64 id)
+{
+ /* This Just Works because we are little endian. */
+ if (copy_to_user(uaddr, val, KVM_REG_SIZE(id)) != 0)
+ return -EFAULT;
+ return 0;
+}
+
+static int get_invariant_cp15(u64 id, void __user *uaddr)
+{
+ struct coproc_params params;
+ const struct coproc_reg *r;
+
+ if (!index_to_params(id, &params))
+ return -ENOENT;
+
+ r = find_reg(&params, invariant_cp15, ARRAY_SIZE(invariant_cp15));
+ if (!r)
+ return -ENOENT;
+
+ return reg_to_user(uaddr, &r->val, id);
+}
+
+static int set_invariant_cp15(u64 id, void __user *uaddr)
+{
+ struct coproc_params params;
+ const struct coproc_reg *r;
+ int err;
+ u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
+
+ if (!index_to_params(id, &params))
+ return -ENOENT;
+ r = find_reg(&params, invariant_cp15, ARRAY_SIZE(invariant_cp15));
+ if (!r)
+ return -ENOENT;
+
+ err = reg_from_user(&val, uaddr, id);
+ if (err)
+ return err;
+
+ /* This is what we mean by invariant: you can't change it. */
+ if (r->val != val)
+ return -EINVAL;
+
+ return 0;
+}
+
+static bool is_valid_cache(u32 val)
+{
+ u32 level, ctype;
+
+ if (val >= CSSELR_MAX)
+ return -ENOENT;
+
+ /* Bottom bit is Instruction or Data bit. Next 3 bits are level. */
+ level = (val >> 1);
+ ctype = (cache_levels >> (level * 3)) & 7;
+
+ switch (ctype) {
+ case 0: /* No cache */
+ return false;
+ case 1: /* Instruction cache only */
+ return (val & 1);
+ case 2: /* Data cache only */
+ case 4: /* Unified cache */
+ return !(val & 1);
+ case 3: /* Separate instruction and data caches */
+ return true;
+ default: /* Reserved: we can't know instruction or data. */
+ return false;
+ }
+}
+
+/* Which cache CCSIDR represents depends on CSSELR value. */
+static u32 get_ccsidr(u32 csselr)
+{
+ u32 ccsidr;
+
+ /* Make sure noone else changes CSSELR during this! */
+ local_irq_disable();
+ /* Put value into CSSELR */
+ asm volatile("mcr p15, 2, %0, c0, c0, 0" : : "r" (csselr));
+ isb();
+ /* Read result out of CCSIDR */
+ asm volatile("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr));
+ local_irq_enable();
+
+ return ccsidr;
+}
+
+static int demux_c15_get(u64 id, void __user *uaddr)
+{
+ u32 val;
+ u32 __user *uval = uaddr;
+
+ /* Fail if we have unknown bits set. */
+ if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK
+ | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1)))
+ return -ENOENT;
+
+ switch (id & KVM_REG_ARM_DEMUX_ID_MASK) {
+ case KVM_REG_ARM_DEMUX_ID_CCSIDR:
+ if (KVM_REG_SIZE(id) != 4)
+ return -ENOENT;
+ val = (id & KVM_REG_ARM_DEMUX_VAL_MASK)
+ >> KVM_REG_ARM_DEMUX_VAL_SHIFT;
+ if (!is_valid_cache(val))
+ return -ENOENT;
+
+ return put_user(get_ccsidr(val), uval);
+ default:
+ return -ENOENT;
+ }
+}
+
+static int demux_c15_set(u64 id, void __user *uaddr)
+{
+ u32 val, newval;
+ u32 __user *uval = uaddr;
+
+ /* Fail if we have unknown bits set. */
+ if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK
+ | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1)))
+ return -ENOENT;
+
+ switch (id & KVM_REG_ARM_DEMUX_ID_MASK) {
+ case KVM_REG_ARM_DEMUX_ID_CCSIDR:
+ if (KVM_REG_SIZE(id) != 4)
+ return -ENOENT;
+ val = (id & KVM_REG_ARM_DEMUX_VAL_MASK)
+ >> KVM_REG_ARM_DEMUX_VAL_SHIFT;
+ if (!is_valid_cache(val))
+ return -ENOENT;
+
+ if (get_user(newval, uval))
+ return -EFAULT;
+
+ /* This is also invariant: you can't change it. */
+ if (newval != get_ccsidr(val))
+ return -EINVAL;
+ return 0;
+ default:
+ return -ENOENT;
+ }
+}
+
+#ifdef CONFIG_VFPv3
+static const int vfp_sysregs[] = { KVM_REG_ARM_VFP_FPEXC,
+ KVM_REG_ARM_VFP_FPSCR,
+ KVM_REG_ARM_VFP_FPINST,
+ KVM_REG_ARM_VFP_FPINST2,
+ KVM_REG_ARM_VFP_MVFR0,
+ KVM_REG_ARM_VFP_MVFR1,
+ KVM_REG_ARM_VFP_FPSID };
+
+static unsigned int num_fp_regs(void)
+{
+ if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK) >> MVFR0_A_SIMD_BIT) == 2)
+ return 32;
+ else
+ return 16;
+}
+
+static unsigned int num_vfp_regs(void)
+{
+ /* Normal FP regs + control regs. */
+ return num_fp_regs() + ARRAY_SIZE(vfp_sysregs);
+}
+
+static int copy_vfp_regids(u64 __user *uindices)
+{
+ unsigned int i;
+ const u64 u32reg = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP;
+ const u64 u64reg = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
+
+ for (i = 0; i < num_fp_regs(); i++) {
+ if (put_user((u64reg | KVM_REG_ARM_VFP_BASE_REG) + i,
+ uindices))
+ return -EFAULT;
+ uindices++;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(vfp_sysregs); i++) {
+ if (put_user(u32reg | vfp_sysregs[i], uindices))
+ return -EFAULT;
+ uindices++;
+ }
+
+ return num_vfp_regs();
+}
+
+static int vfp_get_reg(const struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
+{
+ u32 vfpid = (id & KVM_REG_ARM_VFP_MASK);
+ u32 val;
+
+ /* Fail if we have unknown bits set. */
+ if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK
+ | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1)))
+ return -ENOENT;
+
+ if (vfpid < num_fp_regs()) {
+ if (KVM_REG_SIZE(id) != 8)
+ return -ENOENT;
+ return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpregs[vfpid],
+ id);
+ }
+
+ /* FP control registers are all 32 bit. */
+ if (KVM_REG_SIZE(id) != 4)
+ return -ENOENT;
+
+ switch (vfpid) {
+ case KVM_REG_ARM_VFP_FPEXC:
+ return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpexc, id);
+ case KVM_REG_ARM_VFP_FPSCR:
+ return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpscr, id);
+ case KVM_REG_ARM_VFP_FPINST:
+ return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpinst, id);
+ case KVM_REG_ARM_VFP_FPINST2:
+ return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpinst2, id);
+ case KVM_REG_ARM_VFP_MVFR0:
+ val = fmrx(MVFR0);
+ return reg_to_user(uaddr, &val, id);
+ case KVM_REG_ARM_VFP_MVFR1:
+ val = fmrx(MVFR1);
+ return reg_to_user(uaddr, &val, id);
+ case KVM_REG_ARM_VFP_FPSID:
+ val = fmrx(FPSID);
+ return reg_to_user(uaddr, &val, id);
+ default:
+ return -ENOENT;
+ }
+}
+
+static int vfp_set_reg(struct kvm_vcpu *vcpu, u64 id, const void __user *uaddr)
+{
+ u32 vfpid = (id & KVM_REG_ARM_VFP_MASK);
+ u32 val;
+
+ /* Fail if we have unknown bits set. */
+ if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK
+ | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1)))
+ return -ENOENT;
+
+ if (vfpid < num_fp_regs()) {
+ if (KVM_REG_SIZE(id) != 8)
+ return -ENOENT;
+ return reg_from_user(&vcpu->arch.vfp_guest.fpregs[vfpid],
+ uaddr, id);
+ }
+
+ /* FP control registers are all 32 bit. */
+ if (KVM_REG_SIZE(id) != 4)
+ return -ENOENT;
+
+ switch (vfpid) {
+ case KVM_REG_ARM_VFP_FPEXC:
+ return reg_from_user(&vcpu->arch.vfp_guest.fpexc, uaddr, id);
+ case KVM_REG_ARM_VFP_FPSCR:
+ return reg_from_user(&vcpu->arch.vfp_guest.fpscr, uaddr, id);
+ case KVM_REG_ARM_VFP_FPINST:
+ return reg_from_user(&vcpu->arch.vfp_guest.fpinst, uaddr, id);
+ case KVM_REG_ARM_VFP_FPINST2:
+ return reg_from_user(&vcpu->arch.vfp_guest.fpinst2, uaddr, id);
+ /* These are invariant. */
+ case KVM_REG_ARM_VFP_MVFR0:
+ if (reg_from_user(&val, uaddr, id))
+ return -EFAULT;
+ if (val != fmrx(MVFR0))
+ return -EINVAL;
+ return 0;
+ case KVM_REG_ARM_VFP_MVFR1:
+ if (reg_from_user(&val, uaddr, id))
+ return -EFAULT;
+ if (val != fmrx(MVFR1))
+ return -EINVAL;
+ return 0;
+ case KVM_REG_ARM_VFP_FPSID:
+ if (reg_from_user(&val, uaddr, id))
+ return -EFAULT;
+ if (val != fmrx(FPSID))
+ return -EINVAL;
+ return 0;
+ default:
+ return -ENOENT;
+ }
+}
+#else /* !CONFIG_VFPv3 */
+static unsigned int num_vfp_regs(void)
+{
+ return 0;
+}
+
+static int copy_vfp_regids(u64 __user *uindices)
+{
+ return 0;
+}
+
+static int vfp_get_reg(const struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
+{
+ return -ENOENT;
+}
+
+static int vfp_set_reg(struct kvm_vcpu *vcpu, u64 id, const void __user *uaddr)
+{
+ return -ENOENT;
+}
+#endif /* !CONFIG_VFPv3 */
+
+int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ const struct coproc_reg *r;
+ void __user *uaddr = (void __user *)(long)reg->addr;
+
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
+ return demux_c15_get(reg->id, uaddr);
+
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_VFP)
+ return vfp_get_reg(vcpu, reg->id, uaddr);
+
+ r = index_to_coproc_reg(vcpu, reg->id);
+ if (!r)
+ return get_invariant_cp15(reg->id, uaddr);
+
+ /* Note: copies two regs if size is 64 bit. */
+ return reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id);
+}
+
+int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ const struct coproc_reg *r;
+ void __user *uaddr = (void __user *)(long)reg->addr;
+
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
+ return demux_c15_set(reg->id, uaddr);
+
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_VFP)
+ return vfp_set_reg(vcpu, reg->id, uaddr);
+
+ r = index_to_coproc_reg(vcpu, reg->id);
+ if (!r)
+ return set_invariant_cp15(reg->id, uaddr);
+
+ /* Note: copies two regs if size is 64 bit */
+ return reg_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id);
+}
+
+static unsigned int num_demux_regs(void)
+{
+ unsigned int i, count = 0;
+
+ for (i = 0; i < CSSELR_MAX; i++)
+ if (is_valid_cache(i))
+ count++;
+
+ return count;
+}
+
+static int write_demux_regids(u64 __user *uindices)
+{
+ u64 val = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_DEMUX;
+ unsigned int i;
+
+ val |= KVM_REG_ARM_DEMUX_ID_CCSIDR;
+ for (i = 0; i < CSSELR_MAX; i++) {
+ if (!is_valid_cache(i))
+ continue;
+ if (put_user(val | i, uindices))
+ return -EFAULT;
+ uindices++;
+ }
+ return 0;
+}
+
+static u64 cp15_to_index(const struct coproc_reg *reg)
+{
+ u64 val = KVM_REG_ARM | (15 << KVM_REG_ARM_COPROC_SHIFT);
+ if (reg->is_64) {
+ val |= KVM_REG_SIZE_U64;
+ val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT);
+ val |= (reg->CRm << KVM_REG_ARM_CRM_SHIFT);
+ } else {
+ val |= KVM_REG_SIZE_U32;
+ val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT);
+ val |= (reg->Op2 << KVM_REG_ARM_32_OPC2_SHIFT);
+ val |= (reg->CRm << KVM_REG_ARM_CRM_SHIFT);
+ val |= (reg->CRn << KVM_REG_ARM_32_CRN_SHIFT);
+ }
+ return val;
+}
+
+static bool copy_reg_to_user(const struct coproc_reg *reg, u64 __user **uind)
+{
+ if (!*uind)
+ return true;
+
+ if (put_user(cp15_to_index(reg), *uind))
+ return false;
+
+ (*uind)++;
+ return true;
+}
+
+/* Assumed ordered tables, see kvm_coproc_table_init. */
+static int walk_cp15(struct kvm_vcpu *vcpu, u64 __user *uind)
+{
+ const struct coproc_reg *i1, *i2, *end1, *end2;
+ unsigned int total = 0;
+ size_t num;
+
+ /* We check for duplicates here, to allow arch-specific overrides. */
+ i1 = get_target_table(vcpu->arch.target, &num);
+ end1 = i1 + num;
+ i2 = cp15_regs;
+ end2 = cp15_regs + ARRAY_SIZE(cp15_regs);
+
+ BUG_ON(i1 == end1 || i2 == end2);
+
+ /* Walk carefully, as both tables may refer to the same register. */
+ while (i1 || i2) {
+ int cmp = cmp_reg(i1, i2);
+ /* target-specific overrides generic entry. */
+ if (cmp <= 0) {
+ /* Ignore registers we trap but don't save. */
+ if (i1->reg) {
+ if (!copy_reg_to_user(i1, &uind))
+ return -EFAULT;
+ total++;
+ }
+ } else {
+ /* Ignore registers we trap but don't save. */
+ if (i2->reg) {
+ if (!copy_reg_to_user(i2, &uind))
+ return -EFAULT;
+ total++;
+ }
+ }
+
+ if (cmp <= 0 && ++i1 == end1)
+ i1 = NULL;
+ if (cmp >= 0 && ++i2 == end2)
+ i2 = NULL;
+ }
+ return total;
+}
+
+unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu)
+{
+ return ARRAY_SIZE(invariant_cp15)
+ + num_demux_regs()
+ + num_vfp_regs()
+ + walk_cp15(vcpu, (u64 __user *)NULL);
+}
+
+int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+ unsigned int i;
+ int err;
+
+ /* Then give them all the invariant registers' indices. */
+ for (i = 0; i < ARRAY_SIZE(invariant_cp15); i++) {
+ if (put_user(cp15_to_index(&invariant_cp15[i]), uindices))
+ return -EFAULT;
+ uindices++;
+ }
+
+ err = walk_cp15(vcpu, uindices);
+ if (err < 0)
+ return err;
+ uindices += err;
+
+ err = copy_vfp_regids(uindices);
+ if (err < 0)
+ return err;
+ uindices += err;
+
+ return write_demux_regids(uindices);
+}
+
+void kvm_coproc_table_init(void)
+{
+ unsigned int i;
+
+ /* Make sure tables are unique and in order. */
+ for (i = 1; i < ARRAY_SIZE(cp15_regs); i++)
+ BUG_ON(cmp_reg(&cp15_regs[i-1], &cp15_regs[i]) >= 0);
+
+ /* We abuse the reset function to overwrite the table itself. */
+ for (i = 0; i < ARRAY_SIZE(invariant_cp15); i++)
+ invariant_cp15[i].reset(NULL, &invariant_cp15[i]);
+
+ /*
+ * CLIDR format is awkward, so clean it up. See ARM B4.1.20:
+ *
+ * If software reads the Cache Type fields from Ctype1
+ * upwards, once it has seen a value of 0b000, no caches
+ * exist at further-out levels of the hierarchy. So, for
+ * example, if Ctype3 is the first Cache Type field with a
+ * value of 0b000, the values of Ctype4 to Ctype7 must be
+ * ignored.
+ */
+ asm volatile("mrc p15, 1, %0, c0, c0, 1" : "=r" (cache_levels));
+ for (i = 0; i < 7; i++)
+ if (((cache_levels >> (i*3)) & 7) == 0)
+ break;
+ /* Clear all higher bits. */
+ cache_levels &= (1 << (i*3))-1;
+}
+
+/**
+ * kvm_reset_coprocs - sets cp15 registers to reset value
+ * @vcpu: The VCPU pointer
+ *
+ * This function finds the right table above and sets the registers on the
+ * virtual CPU struct to their architecturally defined reset values.
+ */
+void kvm_reset_coprocs(struct kvm_vcpu *vcpu)
+{
+ size_t num;
+ const struct coproc_reg *table;
+
+ /* Catch someone adding a register without putting in reset entry. */
+ memset(vcpu->arch.cp15, 0x42, sizeof(vcpu->arch.cp15));
+
+ /* Generic chip reset first (so target could override). */
+ reset_coproc_regs(vcpu, cp15_regs, ARRAY_SIZE(cp15_regs));
+
+ table = get_target_table(vcpu->arch.target, &num);
+ reset_coproc_regs(vcpu, table, num);
+
+ for (num = 1; num < NR_CP15_REGS; num++)
+ if (vcpu->arch.cp15[num] == 0x42424242)
+ panic("Didn't reset vcpu->arch.cp15[%zi]", num);
+}
diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h
new file mode 100644
index 000000000000..992adfafa2ff
--- /dev/null
+++ b/arch/arm/kvm/coproc.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Authors: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ARM_KVM_COPROC_LOCAL_H__
+#define __ARM_KVM_COPROC_LOCAL_H__
+
+struct coproc_params {
+ unsigned long CRn;
+ unsigned long CRm;
+ unsigned long Op1;
+ unsigned long Op2;
+ unsigned long Rt1;
+ unsigned long Rt2;
+ bool is_64bit;
+ bool is_write;
+};
+
+struct coproc_reg {
+ /* MRC/MCR/MRRC/MCRR instruction which accesses it. */
+ unsigned long CRn;
+ unsigned long CRm;
+ unsigned long Op1;
+ unsigned long Op2;
+
+ bool is_64;
+
+ /* Trapped access from guest, if non-NULL. */
+ bool (*access)(struct kvm_vcpu *,
+ const struct coproc_params *,
+ const struct coproc_reg *);
+
+ /* Initialization for vcpu. */
+ void (*reset)(struct kvm_vcpu *, const struct coproc_reg *);
+
+ /* Index into vcpu->arch.cp15[], or 0 if we don't need to save it. */
+ unsigned long reg;
+
+ /* Value (usually reset value) */
+ u64 val;
+};
+
+static inline void print_cp_instr(const struct coproc_params *p)
+{
+ /* Look, we even formatted it for you to paste into the table! */
+ if (p->is_64bit) {
+ kvm_pr_unimpl(" { CRm(%2lu), Op1(%2lu), is64, func_%s },\n",
+ p->CRm, p->Op1, p->is_write ? "write" : "read");
+ } else {
+ kvm_pr_unimpl(" { CRn(%2lu), CRm(%2lu), Op1(%2lu), Op2(%2lu), is32,"
+ " func_%s },\n",
+ p->CRn, p->CRm, p->Op1, p->Op2,
+ p->is_write ? "write" : "read");
+ }
+}
+
+static inline bool ignore_write(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p)
+{
+ return true;
+}
+
+static inline bool read_zero(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p)
+{
+ *vcpu_reg(vcpu, p->Rt1) = 0;
+ return true;
+}
+
+static inline bool write_to_read_only(struct kvm_vcpu *vcpu,
+ const struct coproc_params *params)
+{
+ kvm_debug("CP15 write to read-only register at: %08x\n",
+ *vcpu_pc(vcpu));
+ print_cp_instr(params);
+ return false;
+}
+
+static inline bool read_from_write_only(struct kvm_vcpu *vcpu,
+ const struct coproc_params *params)
+{
+ kvm_debug("CP15 read to write-only register at: %08x\n",
+ *vcpu_pc(vcpu));
+ print_cp_instr(params);
+ return false;
+}
+
+/* Reset functions */
+static inline void reset_unknown(struct kvm_vcpu *vcpu,
+ const struct coproc_reg *r)
+{
+ BUG_ON(!r->reg);
+ BUG_ON(r->reg >= ARRAY_SIZE(vcpu->arch.cp15));
+ vcpu->arch.cp15[r->reg] = 0xdecafbad;
+}
+
+static inline void reset_val(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
+{
+ BUG_ON(!r->reg);
+ BUG_ON(r->reg >= ARRAY_SIZE(vcpu->arch.cp15));
+ vcpu->arch.cp15[r->reg] = r->val;
+}
+
+static inline void reset_unknown64(struct kvm_vcpu *vcpu,
+ const struct coproc_reg *r)
+{
+ BUG_ON(!r->reg);
+ BUG_ON(r->reg + 1 >= ARRAY_SIZE(vcpu->arch.cp15));
+
+ vcpu->arch.cp15[r->reg] = 0xdecafbad;
+ vcpu->arch.cp15[r->reg+1] = 0xd0c0ffee;
+}
+
+static inline int cmp_reg(const struct coproc_reg *i1,
+ const struct coproc_reg *i2)
+{
+ BUG_ON(i1 == i2);
+ if (!i1)
+ return 1;
+ else if (!i2)
+ return -1;
+ if (i1->CRn != i2->CRn)
+ return i1->CRn - i2->CRn;
+ if (i1->CRm != i2->CRm)
+ return i1->CRm - i2->CRm;
+ if (i1->Op1 != i2->Op1)
+ return i1->Op1 - i2->Op1;
+ return i1->Op2 - i2->Op2;
+}
+
+
+#define CRn(_x) .CRn = _x
+#define CRm(_x) .CRm = _x
+#define Op1(_x) .Op1 = _x
+#define Op2(_x) .Op2 = _x
+#define is64 .is_64 = true
+#define is32 .is_64 = false
+
+#endif /* __ARM_KVM_COPROC_LOCAL_H__ */
diff --git a/arch/arm/kvm/coproc_a15.c b/arch/arm/kvm/coproc_a15.c
new file mode 100644
index 000000000000..685063a6d0cf
--- /dev/null
+++ b/arch/arm/kvm/coproc_a15.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Authors: Rusty Russell <rusty@rustcorp.au>
+ * Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <linux/kvm_host.h>
+#include <asm/cputype.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+#include <linux/init.h>
+
+static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
+{
+ /*
+ * Compute guest MPIDR:
+ * (Even if we present only one VCPU to the guest on an SMP
+ * host we don't set the U bit in the MPIDR, or vice versa, as
+ * revealing the underlying hardware properties is likely to
+ * be the best choice).
+ */
+ vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr() & ~MPIDR_LEVEL_MASK)
+ | (vcpu->vcpu_id & MPIDR_LEVEL_MASK);
+}
+
+#include "coproc.h"
+
+/* A15 TRM 4.3.28: RO WI */
+static bool access_actlr(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r)
+{
+ if (p->is_write)
+ return ignore_write(vcpu, p);
+
+ *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c1_ACTLR];
+ return true;
+}
+
+/* A15 TRM 4.3.60: R/O. */
+static bool access_cbar(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r)
+{
+ if (p->is_write)
+ return write_to_read_only(vcpu, p);
+ return read_zero(vcpu, p);
+}
+
+/* A15 TRM 4.3.48: R/O WI. */
+static bool access_l2ctlr(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r)
+{
+ if (p->is_write)
+ return ignore_write(vcpu, p);
+
+ *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c9_L2CTLR];
+ return true;
+}
+
+static void reset_l2ctlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
+{
+ u32 l2ctlr, ncores;
+
+ asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
+ l2ctlr &= ~(3 << 24);
+ ncores = atomic_read(&vcpu->kvm->online_vcpus) - 1;
+ l2ctlr |= (ncores & 3) << 24;
+
+ vcpu->arch.cp15[c9_L2CTLR] = l2ctlr;
+}
+
+static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
+{
+ u32 actlr;
+
+ /* ACTLR contains SMP bit: make sure you create all cpus first! */
+ asm volatile("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr));
+ /* Make the SMP bit consistent with the guest configuration */
+ if (atomic_read(&vcpu->kvm->online_vcpus) > 1)
+ actlr |= 1U << 6;
+ else
+ actlr &= ~(1U << 6);
+
+ vcpu->arch.cp15[c1_ACTLR] = actlr;
+}
+
+/* A15 TRM 4.3.49: R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored). */
+static bool access_l2ectlr(struct kvm_vcpu *vcpu,
+ const struct coproc_params *p,
+ const struct coproc_reg *r)
+{
+ if (p->is_write)
+ return ignore_write(vcpu, p);
+
+ *vcpu_reg(vcpu, p->Rt1) = 0;
+ return true;
+}
+
+/*
+ * A15-specific CP15 registers.
+ * Important: Must be sorted ascending by CRn, CRM, Op1, Op2
+ */
+static const struct coproc_reg a15_regs[] = {
+ /* MPIDR: we use VMPIDR for guest access. */
+ { CRn( 0), CRm( 0), Op1( 0), Op2( 5), is32,
+ NULL, reset_mpidr, c0_MPIDR },
+
+ /* SCTLR: swapped by interrupt.S. */
+ { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
+ NULL, reset_val, c1_SCTLR, 0x00C50078 },
+ /* ACTLR: trapped by HCR.TAC bit. */
+ { CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32,
+ access_actlr, reset_actlr, c1_ACTLR },
+ /* CPACR: swapped by interrupt.S. */
+ { CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32,
+ NULL, reset_val, c1_CPACR, 0x00000000 },
+
+ /*
+ * L2CTLR access (guest wants to know #CPUs).
+ */
+ { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32,
+ access_l2ctlr, reset_l2ctlr, c9_L2CTLR },
+ { CRn( 9), CRm( 0), Op1( 1), Op2( 3), is32, access_l2ectlr},
+
+ /* The Configuration Base Address Register. */
+ { CRn(15), CRm( 0), Op1( 4), Op2( 0), is32, access_cbar},
+};
+
+static struct kvm_coproc_target_table a15_target_table = {
+ .target = KVM_ARM_TARGET_CORTEX_A15,
+ .table = a15_regs,
+ .num = ARRAY_SIZE(a15_regs),
+};
+
+static int __init coproc_a15_init(void)
+{
+ unsigned int i;
+
+ for (i = 1; i < ARRAY_SIZE(a15_regs); i++)
+ BUG_ON(cmp_reg(&a15_regs[i-1],
+ &a15_regs[i]) >= 0);
+
+ kvm_register_target_coproc_table(&a15_target_table);
+ return 0;
+}
+late_initcall(coproc_a15_init);
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
new file mode 100644
index 000000000000..d61450ac6665
--- /dev/null
+++ b/arch/arm/kvm/emulate.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/mm.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_emulate.h>
+#include <trace/events/kvm.h>
+
+#include "trace.h"
+
+#define VCPU_NR_MODES 6
+#define VCPU_REG_OFFSET_USR 0
+#define VCPU_REG_OFFSET_FIQ 1
+#define VCPU_REG_OFFSET_IRQ 2
+#define VCPU_REG_OFFSET_SVC 3
+#define VCPU_REG_OFFSET_ABT 4
+#define VCPU_REG_OFFSET_UND 5
+#define REG_OFFSET(_reg) \
+ (offsetof(struct kvm_regs, _reg) / sizeof(u32))
+
+#define USR_REG_OFFSET(_num) REG_OFFSET(usr_regs.uregs[_num])
+
+static const unsigned long vcpu_reg_offsets[VCPU_NR_MODES][15] = {
+ /* USR/SYS Registers */
+ [VCPU_REG_OFFSET_USR] = {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12), USR_REG_OFFSET(13), USR_REG_OFFSET(14),
+ },
+
+ /* FIQ Registers */
+ [VCPU_REG_OFFSET_FIQ] = {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7),
+ REG_OFFSET(fiq_regs[0]), /* r8 */
+ REG_OFFSET(fiq_regs[1]), /* r9 */
+ REG_OFFSET(fiq_regs[2]), /* r10 */
+ REG_OFFSET(fiq_regs[3]), /* r11 */
+ REG_OFFSET(fiq_regs[4]), /* r12 */
+ REG_OFFSET(fiq_regs[5]), /* r13 */
+ REG_OFFSET(fiq_regs[6]), /* r14 */
+ },
+
+ /* IRQ Registers */
+ [VCPU_REG_OFFSET_IRQ] = {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ REG_OFFSET(irq_regs[0]), /* r13 */
+ REG_OFFSET(irq_regs[1]), /* r14 */
+ },
+
+ /* SVC Registers */
+ [VCPU_REG_OFFSET_SVC] = {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ REG_OFFSET(svc_regs[0]), /* r13 */
+ REG_OFFSET(svc_regs[1]), /* r14 */
+ },
+
+ /* ABT Registers */
+ [VCPU_REG_OFFSET_ABT] = {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ REG_OFFSET(abt_regs[0]), /* r13 */
+ REG_OFFSET(abt_regs[1]), /* r14 */
+ },
+
+ /* UND Registers */
+ [VCPU_REG_OFFSET_UND] = {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ REG_OFFSET(und_regs[0]), /* r13 */
+ REG_OFFSET(und_regs[1]), /* r14 */
+ },
+};
+
+/*
+ * Return a pointer to the register number valid in the current mode of
+ * the virtual CPU.
+ */
+u32 *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num)
+{
+ u32 *reg_array = (u32 *)&vcpu->arch.regs;
+ u32 mode = *vcpu_cpsr(vcpu) & MODE_MASK;
+
+ switch (mode) {
+ case USR_MODE...SVC_MODE:
+ mode &= ~MODE32_BIT; /* 0 ... 3 */
+ break;
+
+ case ABT_MODE:
+ mode = VCPU_REG_OFFSET_ABT;
+ break;
+
+ case UND_MODE:
+ mode = VCPU_REG_OFFSET_UND;
+ break;
+
+ case SYSTEM_MODE:
+ mode = VCPU_REG_OFFSET_USR;
+ break;
+
+ default:
+ BUG();
+ }
+
+ return reg_array + vcpu_reg_offsets[mode][reg_num];
+}
+
+/*
+ * Return the SPSR for the current mode of the virtual CPU.
+ */
+u32 *vcpu_spsr(struct kvm_vcpu *vcpu)
+{
+ u32 mode = *vcpu_cpsr(vcpu) & MODE_MASK;
+ switch (mode) {
+ case SVC_MODE:
+ return &vcpu->arch.regs.KVM_ARM_SVC_spsr;
+ case ABT_MODE:
+ return &vcpu->arch.regs.KVM_ARM_ABT_spsr;
+ case UND_MODE:
+ return &vcpu->arch.regs.KVM_ARM_UND_spsr;
+ case IRQ_MODE:
+ return &vcpu->arch.regs.KVM_ARM_IRQ_spsr;
+ case FIQ_MODE:
+ return &vcpu->arch.regs.KVM_ARM_FIQ_spsr;
+ default:
+ BUG();
+ }
+}
+
+/**
+ * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
+ * @vcpu: the vcpu pointer
+ * @run: the kvm_run structure pointer
+ *
+ * Simply sets the wait_for_interrupts flag on the vcpu structure, which will
+ * halt execution of world-switches and schedule other host processes until
+ * there is an incoming IRQ or FIQ to the VM.
+ */
+int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ trace_kvm_wfi(*vcpu_pc(vcpu));
+ kvm_vcpu_block(vcpu);
+ return 1;
+}
+
+/**
+ * adjust_itstate - adjust ITSTATE when emulating instructions in IT-block
+ * @vcpu: The VCPU pointer
+ *
+ * When exceptions occur while instructions are executed in Thumb IF-THEN
+ * blocks, the ITSTATE field of the CPSR is not advanved (updated), so we have
+ * to do this little bit of work manually. The fields map like this:
+ *
+ * IT[7:0] -> CPSR[26:25],CPSR[15:10]
+ */
+static void kvm_adjust_itstate(struct kvm_vcpu *vcpu)
+{
+ unsigned long itbits, cond;
+ unsigned long cpsr = *vcpu_cpsr(vcpu);
+ bool is_arm = !(cpsr & PSR_T_BIT);
+
+ BUG_ON(is_arm && (cpsr & PSR_IT_MASK));
+
+ if (!(cpsr & PSR_IT_MASK))
+ return;
+
+ cond = (cpsr & 0xe000) >> 13;
+ itbits = (cpsr & 0x1c00) >> (10 - 2);
+ itbits |= (cpsr & (0x3 << 25)) >> 25;
+
+ /* Perform ITAdvance (see page A-52 in ARM DDI 0406C) */
+ if ((itbits & 0x7) == 0)
+ itbits = cond = 0;
+ else
+ itbits = (itbits << 1) & 0x1f;
+
+ cpsr &= ~PSR_IT_MASK;
+ cpsr |= cond << 13;
+ cpsr |= (itbits & 0x1c) << (10 - 2);
+ cpsr |= (itbits & 0x3) << 25;
+ *vcpu_cpsr(vcpu) = cpsr;
+}
+
+/**
+ * kvm_skip_instr - skip a trapped instruction and proceed to the next
+ * @vcpu: The vcpu pointer
+ */
+void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
+{
+ bool is_thumb;
+
+ is_thumb = !!(*vcpu_cpsr(vcpu) & PSR_T_BIT);
+ if (is_thumb && !is_wide_instr)
+ *vcpu_pc(vcpu) += 2;
+ else
+ *vcpu_pc(vcpu) += 4;
+ kvm_adjust_itstate(vcpu);
+}
+
+
+/******************************************************************************
+ * Inject exceptions into the guest
+ */
+
+static u32 exc_vector_base(struct kvm_vcpu *vcpu)
+{
+ u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
+ u32 vbar = vcpu->arch.cp15[c12_VBAR];
+
+ if (sctlr & SCTLR_V)
+ return 0xffff0000;
+ else /* always have security exceptions */
+ return vbar;
+}
+
+/**
+ * kvm_inject_undefined - inject an undefined exception into the guest
+ * @vcpu: The VCPU to receive the undefined exception
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ *
+ * Modelled after TakeUndefInstrException() pseudocode.
+ */
+void kvm_inject_undefined(struct kvm_vcpu *vcpu)
+{
+ u32 new_lr_value;
+ u32 new_spsr_value;
+ u32 cpsr = *vcpu_cpsr(vcpu);
+ u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
+ bool is_thumb = (cpsr & PSR_T_BIT);
+ u32 vect_offset = 4;
+ u32 return_offset = (is_thumb) ? 2 : 4;
+
+ new_spsr_value = cpsr;
+ new_lr_value = *vcpu_pc(vcpu) - return_offset;
+
+ *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | UND_MODE;
+ *vcpu_cpsr(vcpu) |= PSR_I_BIT;
+ *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
+
+ if (sctlr & SCTLR_TE)
+ *vcpu_cpsr(vcpu) |= PSR_T_BIT;
+ if (sctlr & SCTLR_EE)
+ *vcpu_cpsr(vcpu) |= PSR_E_BIT;
+
+ /* Note: These now point to UND banked copies */
+ *vcpu_spsr(vcpu) = cpsr;
+ *vcpu_reg(vcpu, 14) = new_lr_value;
+
+ /* Branch to exception vector */
+ *vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset;
+}
+
+/*
+ * Modelled after TakeDataAbortException() and TakePrefetchAbortException
+ * pseudocode.
+ */
+static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr)
+{
+ u32 new_lr_value;
+ u32 new_spsr_value;
+ u32 cpsr = *vcpu_cpsr(vcpu);
+ u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
+ bool is_thumb = (cpsr & PSR_T_BIT);
+ u32 vect_offset;
+ u32 return_offset = (is_thumb) ? 4 : 0;
+ bool is_lpae;
+
+ new_spsr_value = cpsr;
+ new_lr_value = *vcpu_pc(vcpu) + return_offset;
+
+ *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | ABT_MODE;
+ *vcpu_cpsr(vcpu) |= PSR_I_BIT | PSR_A_BIT;
+ *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
+
+ if (sctlr & SCTLR_TE)
+ *vcpu_cpsr(vcpu) |= PSR_T_BIT;
+ if (sctlr & SCTLR_EE)
+ *vcpu_cpsr(vcpu) |= PSR_E_BIT;
+
+ /* Note: These now point to ABT banked copies */
+ *vcpu_spsr(vcpu) = cpsr;
+ *vcpu_reg(vcpu, 14) = new_lr_value;
+
+ if (is_pabt)
+ vect_offset = 12;
+ else
+ vect_offset = 16;
+
+ /* Branch to exception vector */
+ *vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset;
+
+ if (is_pabt) {
+ /* Set DFAR and DFSR */
+ vcpu->arch.cp15[c6_IFAR] = addr;
+ is_lpae = (vcpu->arch.cp15[c2_TTBCR] >> 31);
+ /* Always give debug fault for now - should give guest a clue */
+ if (is_lpae)
+ vcpu->arch.cp15[c5_IFSR] = 1 << 9 | 0x22;
+ else
+ vcpu->arch.cp15[c5_IFSR] = 2;
+ } else { /* !iabt */
+ /* Set DFAR and DFSR */
+ vcpu->arch.cp15[c6_DFAR] = addr;
+ is_lpae = (vcpu->arch.cp15[c2_TTBCR] >> 31);
+ /* Always give debug fault for now - should give guest a clue */
+ if (is_lpae)
+ vcpu->arch.cp15[c5_DFSR] = 1 << 9 | 0x22;
+ else
+ vcpu->arch.cp15[c5_DFSR] = 2;
+ }
+
+}
+
+/**
+ * kvm_inject_dabt - inject a data abort into the guest
+ * @vcpu: The VCPU to receive the undefined exception
+ * @addr: The address to report in the DFAR
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
+{
+ inject_abt(vcpu, false, addr);
+}
+
+/**
+ * kvm_inject_pabt - inject a prefetch abort into the guest
+ * @vcpu: The VCPU to receive the undefined exception
+ * @addr: The address to report in the DFAR
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
+{
+ inject_abt(vcpu, true, addr);
+}
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
new file mode 100644
index 000000000000..2339d9609d36
--- /dev/null
+++ b/arch/arm/kvm/guest.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/kvm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+
+#define VM_STAT(x) { #x, offsetof(struct kvm, stat.x), KVM_STAT_VM }
+#define VCPU_STAT(x) { #x, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU }
+
+struct kvm_stats_debugfs_item debugfs_entries[] = {
+ { NULL }
+};
+
+int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+
+static u64 core_reg_offset_from_id(u64 id)
+{
+ return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
+}
+
+static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ u32 __user *uaddr = (u32 __user *)(long)reg->addr;
+ struct kvm_regs *regs = &vcpu->arch.regs;
+ u64 off;
+
+ if (KVM_REG_SIZE(reg->id) != 4)
+ return -ENOENT;
+
+ /* Our ID is an index into the kvm_regs struct. */
+ off = core_reg_offset_from_id(reg->id);
+ if (off >= sizeof(*regs) / KVM_REG_SIZE(reg->id))
+ return -ENOENT;
+
+ return put_user(((u32 *)regs)[off], uaddr);
+}
+
+static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ u32 __user *uaddr = (u32 __user *)(long)reg->addr;
+ struct kvm_regs *regs = &vcpu->arch.regs;
+ u64 off, val;
+
+ if (KVM_REG_SIZE(reg->id) != 4)
+ return -ENOENT;
+
+ /* Our ID is an index into the kvm_regs struct. */
+ off = core_reg_offset_from_id(reg->id);
+ if (off >= sizeof(*regs) / KVM_REG_SIZE(reg->id))
+ return -ENOENT;
+
+ if (get_user(val, uaddr) != 0)
+ return -EFAULT;
+
+ if (off == KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr)) {
+ unsigned long mode = val & MODE_MASK;
+ switch (mode) {
+ case USR_MODE:
+ case FIQ_MODE:
+ case IRQ_MODE:
+ case SVC_MODE:
+ case ABT_MODE:
+ case UND_MODE:
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ ((u32 *)regs)[off] = val;
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ return -EINVAL;
+}
+
+static unsigned long num_core_regs(void)
+{
+ return sizeof(struct kvm_regs) / sizeof(u32);
+}
+
+/**
+ * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
+ *
+ * This is for all registers.
+ */
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
+{
+ return num_core_regs() + kvm_arm_num_coproc_regs(vcpu);
+}
+
+/**
+ * kvm_arm_copy_reg_indices - get indices of all registers.
+ *
+ * We do core registers right here, then we apppend coproc regs.
+ */
+int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+ unsigned int i;
+ const u64 core_reg = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_CORE;
+
+ for (i = 0; i < sizeof(struct kvm_regs)/sizeof(u32); i++) {
+ if (put_user(core_reg | i, uindices))
+ return -EFAULT;
+ uindices++;
+ }
+
+ return kvm_arm_copy_coproc_indices(vcpu, uindices);
+}
+
+int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ /* We currently use nothing arch-specific in upper 32 bits */
+ if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM >> 32)
+ return -EINVAL;
+
+ /* Register group 16 means we want a core register. */
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
+ return get_core_reg(vcpu, reg);
+
+ return kvm_arm_coproc_get_reg(vcpu, reg);
+}
+
+int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ /* We currently use nothing arch-specific in upper 32 bits */
+ if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM >> 32)
+ return -EINVAL;
+
+ /* Register group 16 means we set a core register. */
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
+ return set_core_reg(vcpu, reg);
+
+ return kvm_arm_coproc_set_reg(vcpu, reg);
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -EINVAL;
+}
+
+int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
+ const struct kvm_vcpu_init *init)
+{
+ unsigned int i;
+
+ /* We can only do a cortex A15 for now. */
+ if (init->target != kvm_target_cpu())
+ return -EINVAL;
+
+ vcpu->arch.target = init->target;
+ bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES);
+
+ /* -ENOENT for unknown features, -EINVAL for invalid combinations. */
+ for (i = 0; i < sizeof(init->features) * 8; i++) {
+ if (test_bit(i, (void *)init->features)) {
+ if (i >= KVM_VCPU_MAX_FEATURES)
+ return -ENOENT;
+ set_bit(i, vcpu->arch.features);
+ }
+ }
+
+ /* Now we know what it is, we can reset it. */
+ return kvm_reset_vcpu(vcpu);
+}
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+ struct kvm_translation *tr)
+{
+ return -EINVAL;
+}
diff --git a/arch/arm/kvm/init.S b/arch/arm/kvm/init.S
new file mode 100644
index 000000000000..9f37a79b880b
--- /dev/null
+++ b/arch/arm/kvm/init.S
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/linkage.h>
+#include <asm/unified.h>
+#include <asm/asm-offsets.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+
+/********************************************************************
+ * Hypervisor initialization
+ * - should be called with:
+ * r0,r1 = Hypervisor pgd pointer
+ * r2 = top of Hyp stack (kernel VA)
+ * r3 = pointer to hyp vectors
+ */
+
+ .text
+ .pushsection .hyp.idmap.text,"ax"
+ .align 5
+__kvm_hyp_init:
+ .globl __kvm_hyp_init
+
+ @ Hyp-mode exception vector
+ W(b) .
+ W(b) .
+ W(b) .
+ W(b) .
+ W(b) .
+ W(b) __do_hyp_init
+ W(b) .
+ W(b) .
+
+__do_hyp_init:
+ @ Set the HTTBR to point to the hypervisor PGD pointer passed
+ mcrr p15, 4, r0, r1, c2
+
+ @ Set the HTCR and VTCR to the same shareability and cacheability
+ @ settings as the non-secure TTBCR and with T0SZ == 0.
+ mrc p15, 4, r0, c2, c0, 2 @ HTCR
+ ldr r12, =HTCR_MASK
+ bic r0, r0, r12
+ mrc p15, 0, r1, c2, c0, 2 @ TTBCR
+ and r1, r1, #(HTCR_MASK & ~TTBCR_T0SZ)
+ orr r0, r0, r1
+ mcr p15, 4, r0, c2, c0, 2 @ HTCR
+
+ mrc p15, 4, r1, c2, c1, 2 @ VTCR
+ ldr r12, =VTCR_MASK
+ bic r1, r1, r12
+ bic r0, r0, #(~VTCR_HTCR_SH) @ clear non-reusable HTCR bits
+ orr r1, r0, r1
+ orr r1, r1, #(KVM_VTCR_SL0 | KVM_VTCR_T0SZ | KVM_VTCR_S)
+ mcr p15, 4, r1, c2, c1, 2 @ VTCR
+
+ @ Use the same memory attributes for hyp. accesses as the kernel
+ @ (copy MAIRx ro HMAIRx).
+ mrc p15, 0, r0, c10, c2, 0
+ mcr p15, 4, r0, c10, c2, 0
+ mrc p15, 0, r0, c10, c2, 1
+ mcr p15, 4, r0, c10, c2, 1
+
+ @ Set the HSCTLR to:
+ @ - ARM/THUMB exceptions: Kernel config (Thumb-2 kernel)
+ @ - Endianness: Kernel config
+ @ - Fast Interrupt Features: Kernel config
+ @ - Write permission implies XN: disabled
+ @ - Instruction cache: enabled
+ @ - Data/Unified cache: enabled
+ @ - Memory alignment checks: enabled
+ @ - MMU: enabled (this code must be run from an identity mapping)
+ mrc p15, 4, r0, c1, c0, 0 @ HSCR
+ ldr r12, =HSCTLR_MASK
+ bic r0, r0, r12
+ mrc p15, 0, r1, c1, c0, 0 @ SCTLR
+ ldr r12, =(HSCTLR_EE | HSCTLR_FI | HSCTLR_I | HSCTLR_C)
+ and r1, r1, r12
+ ARM( ldr r12, =(HSCTLR_M | HSCTLR_A) )
+ THUMB( ldr r12, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE) )
+ orr r1, r1, r12
+ orr r0, r0, r1
+ isb
+ mcr p15, 4, r0, c1, c0, 0 @ HSCR
+ isb
+
+ @ Set stack pointer and return to the kernel
+ mov sp, r2
+
+ @ Set HVBAR to point to the HYP vectors
+ mcr p15, 4, r3, c12, c0, 0 @ HVBAR
+
+ eret
+
+ .ltorg
+
+ .globl __kvm_hyp_init_end
+__kvm_hyp_init_end:
+
+ .popsection
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
new file mode 100644
index 000000000000..8ca87ab0919d
--- /dev/null
+++ b/arch/arm/kvm/interrupts.S
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/unified.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/asm-offsets.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+#include <asm/vfpmacros.h>
+#include "interrupts_head.S"
+
+ .text
+
+__kvm_hyp_code_start:
+ .globl __kvm_hyp_code_start
+
+/********************************************************************
+ * Flush per-VMID TLBs
+ *
+ * void __kvm_tlb_flush_vmid(struct kvm *kvm);
+ *
+ * We rely on the hardware to broadcast the TLB invalidation to all CPUs
+ * inside the inner-shareable domain (which is the case for all v7
+ * implementations). If we come across a non-IS SMP implementation, we'll
+ * have to use an IPI based mechanism. Until then, we stick to the simple
+ * hardware assisted version.
+ */
+ENTRY(__kvm_tlb_flush_vmid)
+ push {r2, r3}
+
+ add r0, r0, #KVM_VTTBR
+ ldrd r2, r3, [r0]
+ mcrr p15, 6, r2, r3, c2 @ Write VTTBR
+ isb
+ mcr p15, 0, r0, c8, c3, 0 @ TLBIALLIS (rt ignored)
+ dsb
+ isb
+ mov r2, #0
+ mov r3, #0
+ mcrr p15, 6, r2, r3, c2 @ Back to VMID #0
+ isb @ Not necessary if followed by eret
+
+ pop {r2, r3}
+ bx lr
+ENDPROC(__kvm_tlb_flush_vmid)
+
+/********************************************************************
+ * Flush TLBs and instruction caches of all CPUs inside the inner-shareable
+ * domain, for all VMIDs
+ *
+ * void __kvm_flush_vm_context(void);
+ */
+ENTRY(__kvm_flush_vm_context)
+ mov r0, #0 @ rn parameter for c15 flushes is SBZ
+
+ /* Invalidate NS Non-Hyp TLB Inner Shareable (TLBIALLNSNHIS) */
+ mcr p15, 4, r0, c8, c3, 4
+ /* Invalidate instruction caches Inner Shareable (ICIALLUIS) */
+ mcr p15, 0, r0, c7, c1, 0
+ dsb
+ isb @ Not necessary if followed by eret
+
+ bx lr
+ENDPROC(__kvm_flush_vm_context)
+
+
+/********************************************************************
+ * Hypervisor world-switch code
+ *
+ *
+ * int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+ */
+ENTRY(__kvm_vcpu_run)
+ @ Save the vcpu pointer
+ mcr p15, 4, vcpu, c13, c0, 2 @ HTPIDR
+
+ save_host_regs
+
+ restore_vgic_state
+ restore_timer_state
+
+ @ Store hardware CP15 state and load guest state
+ read_cp15_state store_to_vcpu = 0
+ write_cp15_state read_from_vcpu = 1
+
+ @ If the host kernel has not been configured with VFPv3 support,
+ @ then it is safer if we deny guests from using it as well.
+#ifdef CONFIG_VFPv3
+ @ Set FPEXC_EN so the guest doesn't trap floating point instructions
+ VFPFMRX r2, FPEXC @ VMRS
+ push {r2}
+ orr r2, r2, #FPEXC_EN
+ VFPFMXR FPEXC, r2 @ VMSR
+#endif
+
+ @ Configure Hyp-role
+ configure_hyp_role vmentry
+
+ @ Trap coprocessor CRx accesses
+ set_hstr vmentry
+ set_hcptr vmentry, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11))
+ set_hdcr vmentry
+
+ @ Write configured ID register into MIDR alias
+ ldr r1, [vcpu, #VCPU_MIDR]
+ mcr p15, 4, r1, c0, c0, 0
+
+ @ Write guest view of MPIDR into VMPIDR
+ ldr r1, [vcpu, #CP15_OFFSET(c0_MPIDR)]
+ mcr p15, 4, r1, c0, c0, 5
+
+ @ Set up guest memory translation
+ ldr r1, [vcpu, #VCPU_KVM]
+ add r1, r1, #KVM_VTTBR
+ ldrd r2, r3, [r1]
+ mcrr p15, 6, r2, r3, c2 @ Write VTTBR
+
+ @ We're all done, just restore the GPRs and go to the guest
+ restore_guest_regs
+ clrex @ Clear exclusive monitor
+ eret
+
+__kvm_vcpu_return:
+ /*
+ * return convention:
+ * guest r0, r1, r2 saved on the stack
+ * r0: vcpu pointer
+ * r1: exception code
+ */
+ save_guest_regs
+
+ @ Set VMID == 0
+ mov r2, #0
+ mov r3, #0
+ mcrr p15, 6, r2, r3, c2 @ Write VTTBR
+
+ @ Don't trap coprocessor accesses for host kernel
+ set_hstr vmexit
+ set_hdcr vmexit
+ set_hcptr vmexit, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11))
+
+#ifdef CONFIG_VFPv3
+ @ Save floating point registers we if let guest use them.
+ tst r2, #(HCPTR_TCP(10) | HCPTR_TCP(11))
+ bne after_vfp_restore
+
+ @ Switch VFP/NEON hardware state to the host's
+ add r7, vcpu, #VCPU_VFP_GUEST
+ store_vfp_state r7
+ add r7, vcpu, #VCPU_VFP_HOST
+ ldr r7, [r7]
+ restore_vfp_state r7
+
+after_vfp_restore:
+ @ Restore FPEXC_EN which we clobbered on entry
+ pop {r2}
+ VFPFMXR FPEXC, r2
+#endif
+
+ @ Reset Hyp-role
+ configure_hyp_role vmexit
+
+ @ Let host read hardware MIDR
+ mrc p15, 0, r2, c0, c0, 0
+ mcr p15, 4, r2, c0, c0, 0
+
+ @ Back to hardware MPIDR
+ mrc p15, 0, r2, c0, c0, 5
+ mcr p15, 4, r2, c0, c0, 5
+
+ @ Store guest CP15 state and restore host state
+ read_cp15_state store_to_vcpu = 1
+ write_cp15_state read_from_vcpu = 0
+
+ save_timer_state
+ save_vgic_state
+
+ restore_host_regs
+ clrex @ Clear exclusive monitor
+ mov r0, r1 @ Return the return code
+ mov r1, #0 @ Clear upper bits in return value
+ bx lr @ return to IOCTL
+
+/********************************************************************
+ * Call function in Hyp mode
+ *
+ *
+ * u64 kvm_call_hyp(void *hypfn, ...);
+ *
+ * This is not really a variadic function in the classic C-way and care must
+ * be taken when calling this to ensure parameters are passed in registers
+ * only, since the stack will change between the caller and the callee.
+ *
+ * Call the function with the first argument containing a pointer to the
+ * function you wish to call in Hyp mode, and subsequent arguments will be
+ * passed as r0, r1, and r2 (a maximum of 3 arguments in addition to the
+ * function pointer can be passed). The function being called must be mapped
+ * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
+ * passed in r0 and r1.
+ *
+ * The calling convention follows the standard AAPCS:
+ * r0 - r3: caller save
+ * r12: caller save
+ * rest: callee save
+ */
+ENTRY(kvm_call_hyp)
+ hvc #0
+ bx lr
+
+/********************************************************************
+ * Hypervisor exception vector and handlers
+ *
+ *
+ * The KVM/ARM Hypervisor ABI is defined as follows:
+ *
+ * Entry to Hyp mode from the host kernel will happen _only_ when an HVC
+ * instruction is issued since all traps are disabled when running the host
+ * kernel as per the Hyp-mode initialization at boot time.
+ *
+ * HVC instructions cause a trap to the vector page + offset 0x18 (see hyp_hvc
+ * below) when the HVC instruction is called from SVC mode (i.e. a guest or the
+ * host kernel) and they cause a trap to the vector page + offset 0xc when HVC
+ * instructions are called from within Hyp-mode.
+ *
+ * Hyp-ABI: Calling HYP-mode functions from host (in SVC mode):
+ * Switching to Hyp mode is done through a simple HVC #0 instruction. The
+ * exception vector code will check that the HVC comes from VMID==0 and if
+ * so will push the necessary state (SPSR, lr_usr) on the Hyp stack.
+ * - r0 contains a pointer to a HYP function
+ * - r1, r2, and r3 contain arguments to the above function.
+ * - The HYP function will be called with its arguments in r0, r1 and r2.
+ * On HYP function return, we return directly to SVC.
+ *
+ * Note that the above is used to execute code in Hyp-mode from a host-kernel
+ * point of view, and is a different concept from performing a world-switch and
+ * executing guest code SVC mode (with a VMID != 0).
+ */
+
+/* Handle undef, svc, pabt, or dabt by crashing with a user notice */
+.macro bad_exception exception_code, panic_str
+ push {r0-r2}
+ mrrc p15, 6, r0, r1, c2 @ Read VTTBR
+ lsr r1, r1, #16
+ ands r1, r1, #0xff
+ beq 99f
+
+ load_vcpu @ Load VCPU pointer
+ .if \exception_code == ARM_EXCEPTION_DATA_ABORT
+ mrc p15, 4, r2, c5, c2, 0 @ HSR
+ mrc p15, 4, r1, c6, c0, 0 @ HDFAR
+ str r2, [vcpu, #VCPU_HSR]
+ str r1, [vcpu, #VCPU_HxFAR]
+ .endif
+ .if \exception_code == ARM_EXCEPTION_PREF_ABORT
+ mrc p15, 4, r2, c5, c2, 0 @ HSR
+ mrc p15, 4, r1, c6, c0, 2 @ HIFAR
+ str r2, [vcpu, #VCPU_HSR]
+ str r1, [vcpu, #VCPU_HxFAR]
+ .endif
+ mov r1, #\exception_code
+ b __kvm_vcpu_return
+
+ @ We were in the host already. Let's craft a panic-ing return to SVC.
+99: mrs r2, cpsr
+ bic r2, r2, #MODE_MASK
+ orr r2, r2, #SVC_MODE
+THUMB( orr r2, r2, #PSR_T_BIT )
+ msr spsr_cxsf, r2
+ mrs r1, ELR_hyp
+ ldr r2, =BSYM(panic)
+ msr ELR_hyp, r2
+ ldr r0, =\panic_str
+ eret
+.endm
+
+ .text
+
+ .align 5
+__kvm_hyp_vector:
+ .globl __kvm_hyp_vector
+
+ @ Hyp-mode exception vector
+ W(b) hyp_reset
+ W(b) hyp_undef
+ W(b) hyp_svc
+ W(b) hyp_pabt
+ W(b) hyp_dabt
+ W(b) hyp_hvc
+ W(b) hyp_irq
+ W(b) hyp_fiq
+
+ .align
+hyp_reset:
+ b hyp_reset
+
+ .align
+hyp_undef:
+ bad_exception ARM_EXCEPTION_UNDEFINED, und_die_str
+
+ .align
+hyp_svc:
+ bad_exception ARM_EXCEPTION_HVC, svc_die_str
+
+ .align
+hyp_pabt:
+ bad_exception ARM_EXCEPTION_PREF_ABORT, pabt_die_str
+
+ .align
+hyp_dabt:
+ bad_exception ARM_EXCEPTION_DATA_ABORT, dabt_die_str
+
+ .align
+hyp_hvc:
+ /*
+ * Getting here is either becuase of a trap from a guest or from calling
+ * HVC from the host kernel, which means "switch to Hyp mode".
+ */
+ push {r0, r1, r2}
+
+ @ Check syndrome register
+ mrc p15, 4, r1, c5, c2, 0 @ HSR
+ lsr r0, r1, #HSR_EC_SHIFT
+#ifdef CONFIG_VFPv3
+ cmp r0, #HSR_EC_CP_0_13
+ beq switch_to_guest_vfp
+#endif
+ cmp r0, #HSR_EC_HVC
+ bne guest_trap @ Not HVC instr.
+
+ /*
+ * Let's check if the HVC came from VMID 0 and allow simple
+ * switch to Hyp mode
+ */
+ mrrc p15, 6, r0, r2, c2
+ lsr r2, r2, #16
+ and r2, r2, #0xff
+ cmp r2, #0
+ bne guest_trap @ Guest called HVC
+
+host_switch_to_hyp:
+ pop {r0, r1, r2}
+
+ push {lr}
+ mrs lr, SPSR
+ push {lr}
+
+ mov lr, r0
+ mov r0, r1
+ mov r1, r2
+ mov r2, r3
+
+THUMB( orr lr, #1)
+ blx lr @ Call the HYP function
+
+ pop {lr}
+ msr SPSR_csxf, lr
+ pop {lr}
+ eret
+
+guest_trap:
+ load_vcpu @ Load VCPU pointer to r0
+ str r1, [vcpu, #VCPU_HSR]
+
+ @ Check if we need the fault information
+ lsr r1, r1, #HSR_EC_SHIFT
+ cmp r1, #HSR_EC_IABT
+ mrceq p15, 4, r2, c6, c0, 2 @ HIFAR
+ beq 2f
+ cmp r1, #HSR_EC_DABT
+ bne 1f
+ mrc p15, 4, r2, c6, c0, 0 @ HDFAR
+
+2: str r2, [vcpu, #VCPU_HxFAR]
+
+ /*
+ * B3.13.5 Reporting exceptions taken to the Non-secure PL2 mode:
+ *
+ * Abort on the stage 2 translation for a memory access from a
+ * Non-secure PL1 or PL0 mode:
+ *
+ * For any Access flag fault or Translation fault, and also for any
+ * Permission fault on the stage 2 translation of a memory access
+ * made as part of a translation table walk for a stage 1 translation,
+ * the HPFAR holds the IPA that caused the fault. Otherwise, the HPFAR
+ * is UNKNOWN.
+ */
+
+ /* Check for permission fault, and S1PTW */
+ mrc p15, 4, r1, c5, c2, 0 @ HSR
+ and r0, r1, #HSR_FSC_TYPE
+ cmp r0, #FSC_PERM
+ tsteq r1, #(1 << 7) @ S1PTW
+ mrcne p15, 4, r2, c6, c0, 4 @ HPFAR
+ bne 3f
+
+ /* Resolve IPA using the xFAR */
+ mcr p15, 0, r2, c7, c8, 0 @ ATS1CPR
+ isb
+ mrrc p15, 0, r0, r1, c7 @ PAR
+ tst r0, #1
+ bne 4f @ Failed translation
+ ubfx r2, r0, #12, #20
+ lsl r2, r2, #4
+ orr r2, r2, r1, lsl #24
+
+3: load_vcpu @ Load VCPU pointer to r0
+ str r2, [r0, #VCPU_HPFAR]
+
+1: mov r1, #ARM_EXCEPTION_HVC
+ b __kvm_vcpu_return
+
+4: pop {r0, r1, r2} @ Failed translation, return to guest
+ eret
+
+/*
+ * If VFPv3 support is not available, then we will not switch the VFP
+ * registers; however cp10 and cp11 accesses will still trap and fallback
+ * to the regular coprocessor emulation code, which currently will
+ * inject an undefined exception to the guest.
+ */
+#ifdef CONFIG_VFPv3
+switch_to_guest_vfp:
+ load_vcpu @ Load VCPU pointer to r0
+ push {r3-r7}
+
+ @ NEON/VFP used. Turn on VFP access.
+ set_hcptr vmexit, (HCPTR_TCP(10) | HCPTR_TCP(11))
+
+ @ Switch VFP/NEON hardware state to the guest's
+ add r7, r0, #VCPU_VFP_HOST
+ ldr r7, [r7]
+ store_vfp_state r7
+ add r7, r0, #VCPU_VFP_GUEST
+ restore_vfp_state r7
+
+ pop {r3-r7}
+ pop {r0-r2}
+ eret
+#endif
+
+ .align
+hyp_irq:
+ push {r0, r1, r2}
+ mov r1, #ARM_EXCEPTION_IRQ
+ load_vcpu @ Load VCPU pointer to r0
+ b __kvm_vcpu_return
+
+ .align
+hyp_fiq:
+ b hyp_fiq
+
+ .ltorg
+
+__kvm_hyp_code_end:
+ .globl __kvm_hyp_code_end
+
+ .section ".rodata"
+
+und_die_str:
+ .ascii "unexpected undefined exception in Hyp mode at: %#08x"
+pabt_die_str:
+ .ascii "unexpected prefetch abort in Hyp mode at: %#08x"
+dabt_die_str:
+ .ascii "unexpected data abort in Hyp mode at: %#08x"
+svc_die_str:
+ .ascii "unexpected HVC/SVC trap in Hyp mode at: %#08x"
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
new file mode 100644
index 000000000000..3c8f2f0b4c5e
--- /dev/null
+++ b/arch/arm/kvm/interrupts_head.S
@@ -0,0 +1,605 @@
+#include <linux/irqchip/arm-gic.h>
+
+#define VCPU_USR_REG(_reg_nr) (VCPU_USR_REGS + (_reg_nr * 4))
+#define VCPU_USR_SP (VCPU_USR_REG(13))
+#define VCPU_USR_LR (VCPU_USR_REG(14))
+#define CP15_OFFSET(_cp15_reg_idx) (VCPU_CP15 + (_cp15_reg_idx * 4))
+
+/*
+ * Many of these macros need to access the VCPU structure, which is always
+ * held in r0. These macros should never clobber r1, as it is used to hold the
+ * exception code on the return path (except of course the macro that switches
+ * all the registers before the final jump to the VM).
+ */
+vcpu .req r0 @ vcpu pointer always in r0
+
+/* Clobbers {r2-r6} */
+.macro store_vfp_state vfp_base
+ @ The VFPFMRX and VFPFMXR macros are the VMRS and VMSR instructions
+ VFPFMRX r2, FPEXC
+ @ Make sure VFP is enabled so we can touch the registers.
+ orr r6, r2, #FPEXC_EN
+ VFPFMXR FPEXC, r6
+
+ VFPFMRX r3, FPSCR
+ tst r2, #FPEXC_EX @ Check for VFP Subarchitecture
+ beq 1f
+ @ If FPEXC_EX is 0, then FPINST/FPINST2 reads are upredictable, so
+ @ we only need to save them if FPEXC_EX is set.
+ VFPFMRX r4, FPINST
+ tst r2, #FPEXC_FP2V
+ VFPFMRX r5, FPINST2, ne @ vmrsne
+ bic r6, r2, #FPEXC_EX @ FPEXC_EX disable
+ VFPFMXR FPEXC, r6
+1:
+ VFPFSTMIA \vfp_base, r6 @ Save VFP registers
+ stm \vfp_base, {r2-r5} @ Save FPEXC, FPSCR, FPINST, FPINST2
+.endm
+
+/* Assume FPEXC_EN is on and FPEXC_EX is off, clobbers {r2-r6} */
+.macro restore_vfp_state vfp_base
+ VFPFLDMIA \vfp_base, r6 @ Load VFP registers
+ ldm \vfp_base, {r2-r5} @ Load FPEXC, FPSCR, FPINST, FPINST2
+
+ VFPFMXR FPSCR, r3
+ tst r2, #FPEXC_EX @ Check for VFP Subarchitecture
+ beq 1f
+ VFPFMXR FPINST, r4
+ tst r2, #FPEXC_FP2V
+ VFPFMXR FPINST2, r5, ne
+1:
+ VFPFMXR FPEXC, r2 @ FPEXC (last, in case !EN)
+.endm
+
+/* These are simply for the macros to work - value don't have meaning */
+.equ usr, 0
+.equ svc, 1
+.equ abt, 2
+.equ und, 3
+.equ irq, 4
+.equ fiq, 5
+
+.macro push_host_regs_mode mode
+ mrs r2, SP_\mode
+ mrs r3, LR_\mode
+ mrs r4, SPSR_\mode
+ push {r2, r3, r4}
+.endm
+
+/*
+ * Store all host persistent registers on the stack.
+ * Clobbers all registers, in all modes, except r0 and r1.
+ */
+.macro save_host_regs
+ /* Hyp regs. Only ELR_hyp (SPSR_hyp already saved) */
+ mrs r2, ELR_hyp
+ push {r2}
+
+ /* usr regs */
+ push {r4-r12} @ r0-r3 are always clobbered
+ mrs r2, SP_usr
+ mov r3, lr
+ push {r2, r3}
+
+ push_host_regs_mode svc
+ push_host_regs_mode abt
+ push_host_regs_mode und
+ push_host_regs_mode irq
+
+ /* fiq regs */
+ mrs r2, r8_fiq
+ mrs r3, r9_fiq
+ mrs r4, r10_fiq
+ mrs r5, r11_fiq
+ mrs r6, r12_fiq
+ mrs r7, SP_fiq
+ mrs r8, LR_fiq
+ mrs r9, SPSR_fiq
+ push {r2-r9}
+.endm
+
+.macro pop_host_regs_mode mode
+ pop {r2, r3, r4}
+ msr SP_\mode, r2
+ msr LR_\mode, r3
+ msr SPSR_\mode, r4
+.endm
+
+/*
+ * Restore all host registers from the stack.
+ * Clobbers all registers, in all modes, except r0 and r1.
+ */
+.macro restore_host_regs
+ pop {r2-r9}
+ msr r8_fiq, r2
+ msr r9_fiq, r3
+ msr r10_fiq, r4
+ msr r11_fiq, r5
+ msr r12_fiq, r6
+ msr SP_fiq, r7
+ msr LR_fiq, r8
+ msr SPSR_fiq, r9
+
+ pop_host_regs_mode irq
+ pop_host_regs_mode und
+ pop_host_regs_mode abt
+ pop_host_regs_mode svc
+
+ pop {r2, r3}
+ msr SP_usr, r2
+ mov lr, r3
+ pop {r4-r12}
+
+ pop {r2}
+ msr ELR_hyp, r2
+.endm
+
+/*
+ * Restore SP, LR and SPSR for a given mode. offset is the offset of
+ * this mode's registers from the VCPU base.
+ *
+ * Assumes vcpu pointer in vcpu reg
+ *
+ * Clobbers r1, r2, r3, r4.
+ */
+.macro restore_guest_regs_mode mode, offset
+ add r1, vcpu, \offset
+ ldm r1, {r2, r3, r4}
+ msr SP_\mode, r2
+ msr LR_\mode, r3
+ msr SPSR_\mode, r4
+.endm
+
+/*
+ * Restore all guest registers from the vcpu struct.
+ *
+ * Assumes vcpu pointer in vcpu reg
+ *
+ * Clobbers *all* registers.
+ */
+.macro restore_guest_regs
+ restore_guest_regs_mode svc, #VCPU_SVC_REGS
+ restore_guest_regs_mode abt, #VCPU_ABT_REGS
+ restore_guest_regs_mode und, #VCPU_UND_REGS
+ restore_guest_regs_mode irq, #VCPU_IRQ_REGS
+
+ add r1, vcpu, #VCPU_FIQ_REGS
+ ldm r1, {r2-r9}
+ msr r8_fiq, r2
+ msr r9_fiq, r3
+ msr r10_fiq, r4
+ msr r11_fiq, r5
+ msr r12_fiq, r6
+ msr SP_fiq, r7
+ msr LR_fiq, r8
+ msr SPSR_fiq, r9
+
+ @ Load return state
+ ldr r2, [vcpu, #VCPU_PC]
+ ldr r3, [vcpu, #VCPU_CPSR]
+ msr ELR_hyp, r2
+ msr SPSR_cxsf, r3
+
+ @ Load user registers
+ ldr r2, [vcpu, #VCPU_USR_SP]
+ ldr r3, [vcpu, #VCPU_USR_LR]
+ msr SP_usr, r2
+ mov lr, r3
+ add vcpu, vcpu, #(VCPU_USR_REGS)
+ ldm vcpu, {r0-r12}
+.endm
+
+/*
+ * Save SP, LR and SPSR for a given mode. offset is the offset of
+ * this mode's registers from the VCPU base.
+ *
+ * Assumes vcpu pointer in vcpu reg
+ *
+ * Clobbers r2, r3, r4, r5.
+ */
+.macro save_guest_regs_mode mode, offset
+ add r2, vcpu, \offset
+ mrs r3, SP_\mode
+ mrs r4, LR_\mode
+ mrs r5, SPSR_\mode
+ stm r2, {r3, r4, r5}
+.endm
+
+/*
+ * Save all guest registers to the vcpu struct
+ * Expects guest's r0, r1, r2 on the stack.
+ *
+ * Assumes vcpu pointer in vcpu reg
+ *
+ * Clobbers r2, r3, r4, r5.
+ */
+.macro save_guest_regs
+ @ Store usr registers
+ add r2, vcpu, #VCPU_USR_REG(3)
+ stm r2, {r3-r12}
+ add r2, vcpu, #VCPU_USR_REG(0)
+ pop {r3, r4, r5} @ r0, r1, r2
+ stm r2, {r3, r4, r5}
+ mrs r2, SP_usr
+ mov r3, lr
+ str r2, [vcpu, #VCPU_USR_SP]
+ str r3, [vcpu, #VCPU_USR_LR]
+
+ @ Store return state
+ mrs r2, ELR_hyp
+ mrs r3, spsr
+ str r2, [vcpu, #VCPU_PC]
+ str r3, [vcpu, #VCPU_CPSR]
+
+ @ Store other guest registers
+ save_guest_regs_mode svc, #VCPU_SVC_REGS
+ save_guest_regs_mode abt, #VCPU_ABT_REGS
+ save_guest_regs_mode und, #VCPU_UND_REGS
+ save_guest_regs_mode irq, #VCPU_IRQ_REGS
+.endm
+
+/* Reads cp15 registers from hardware and stores them in memory
+ * @store_to_vcpu: If 0, registers are written in-order to the stack,
+ * otherwise to the VCPU struct pointed to by vcpup
+ *
+ * Assumes vcpu pointer in vcpu reg
+ *
+ * Clobbers r2 - r12
+ */
+.macro read_cp15_state store_to_vcpu
+ mrc p15, 0, r2, c1, c0, 0 @ SCTLR
+ mrc p15, 0, r3, c1, c0, 2 @ CPACR
+ mrc p15, 0, r4, c2, c0, 2 @ TTBCR
+ mrc p15, 0, r5, c3, c0, 0 @ DACR
+ mrrc p15, 0, r6, r7, c2 @ TTBR 0
+ mrrc p15, 1, r8, r9, c2 @ TTBR 1
+ mrc p15, 0, r10, c10, c2, 0 @ PRRR
+ mrc p15, 0, r11, c10, c2, 1 @ NMRR
+ mrc p15, 2, r12, c0, c0, 0 @ CSSELR
+
+ .if \store_to_vcpu == 0
+ push {r2-r12} @ Push CP15 registers
+ .else
+ str r2, [vcpu, #CP15_OFFSET(c1_SCTLR)]
+ str r3, [vcpu, #CP15_OFFSET(c1_CPACR)]
+ str r4, [vcpu, #CP15_OFFSET(c2_TTBCR)]
+ str r5, [vcpu, #CP15_OFFSET(c3_DACR)]
+ add r2, vcpu, #CP15_OFFSET(c2_TTBR0)
+ strd r6, r7, [r2]
+ add r2, vcpu, #CP15_OFFSET(c2_TTBR1)
+ strd r8, r9, [r2]
+ str r10, [vcpu, #CP15_OFFSET(c10_PRRR)]
+ str r11, [vcpu, #CP15_OFFSET(c10_NMRR)]
+ str r12, [vcpu, #CP15_OFFSET(c0_CSSELR)]
+ .endif
+
+ mrc p15, 0, r2, c13, c0, 1 @ CID
+ mrc p15, 0, r3, c13, c0, 2 @ TID_URW
+ mrc p15, 0, r4, c13, c0, 3 @ TID_URO
+ mrc p15, 0, r5, c13, c0, 4 @ TID_PRIV
+ mrc p15, 0, r6, c5, c0, 0 @ DFSR
+ mrc p15, 0, r7, c5, c0, 1 @ IFSR
+ mrc p15, 0, r8, c5, c1, 0 @ ADFSR
+ mrc p15, 0, r9, c5, c1, 1 @ AIFSR
+ mrc p15, 0, r10, c6, c0, 0 @ DFAR
+ mrc p15, 0, r11, c6, c0, 2 @ IFAR
+ mrc p15, 0, r12, c12, c0, 0 @ VBAR
+
+ .if \store_to_vcpu == 0
+ push {r2-r12} @ Push CP15 registers
+ .else
+ str r2, [vcpu, #CP15_OFFSET(c13_CID)]
+ str r3, [vcpu, #CP15_OFFSET(c13_TID_URW)]
+ str r4, [vcpu, #CP15_OFFSET(c13_TID_URO)]
+ str r5, [vcpu, #CP15_OFFSET(c13_TID_PRIV)]
+ str r6, [vcpu, #CP15_OFFSET(c5_DFSR)]
+ str r7, [vcpu, #CP15_OFFSET(c5_IFSR)]
+ str r8, [vcpu, #CP15_OFFSET(c5_ADFSR)]
+ str r9, [vcpu, #CP15_OFFSET(c5_AIFSR)]
+ str r10, [vcpu, #CP15_OFFSET(c6_DFAR)]
+ str r11, [vcpu, #CP15_OFFSET(c6_IFAR)]
+ str r12, [vcpu, #CP15_OFFSET(c12_VBAR)]
+ .endif
+
+ mrc p15, 0, r2, c14, c1, 0 @ CNTKCTL
+
+ .if \store_to_vcpu == 0
+ push {r2}
+ .else
+ str r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
+ .endif
+.endm
+
+/*
+ * Reads cp15 registers from memory and writes them to hardware
+ * @read_from_vcpu: If 0, registers are read in-order from the stack,
+ * otherwise from the VCPU struct pointed to by vcpup
+ *
+ * Assumes vcpu pointer in vcpu reg
+ */
+.macro write_cp15_state read_from_vcpu
+ .if \read_from_vcpu == 0
+ pop {r2}
+ .else
+ ldr r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
+ .endif
+
+ mcr p15, 0, r2, c14, c1, 0 @ CNTKCTL
+
+ .if \read_from_vcpu == 0
+ pop {r2-r12}
+ .else
+ ldr r2, [vcpu, #CP15_OFFSET(c13_CID)]
+ ldr r3, [vcpu, #CP15_OFFSET(c13_TID_URW)]
+ ldr r4, [vcpu, #CP15_OFFSET(c13_TID_URO)]
+ ldr r5, [vcpu, #CP15_OFFSET(c13_TID_PRIV)]
+ ldr r6, [vcpu, #CP15_OFFSET(c5_DFSR)]
+ ldr r7, [vcpu, #CP15_OFFSET(c5_IFSR)]
+ ldr r8, [vcpu, #CP15_OFFSET(c5_ADFSR)]
+ ldr r9, [vcpu, #CP15_OFFSET(c5_AIFSR)]
+ ldr r10, [vcpu, #CP15_OFFSET(c6_DFAR)]
+ ldr r11, [vcpu, #CP15_OFFSET(c6_IFAR)]
+ ldr r12, [vcpu, #CP15_OFFSET(c12_VBAR)]
+ .endif
+
+ mcr p15, 0, r2, c13, c0, 1 @ CID
+ mcr p15, 0, r3, c13, c0, 2 @ TID_URW
+ mcr p15, 0, r4, c13, c0, 3 @ TID_URO
+ mcr p15, 0, r5, c13, c0, 4 @ TID_PRIV
+ mcr p15, 0, r6, c5, c0, 0 @ DFSR
+ mcr p15, 0, r7, c5, c0, 1 @ IFSR
+ mcr p15, 0, r8, c5, c1, 0 @ ADFSR
+ mcr p15, 0, r9, c5, c1, 1 @ AIFSR
+ mcr p15, 0, r10, c6, c0, 0 @ DFAR
+ mcr p15, 0, r11, c6, c0, 2 @ IFAR
+ mcr p15, 0, r12, c12, c0, 0 @ VBAR
+
+ .if \read_from_vcpu == 0
+ pop {r2-r12}
+ .else
+ ldr r2, [vcpu, #CP15_OFFSET(c1_SCTLR)]
+ ldr r3, [vcpu, #CP15_OFFSET(c1_CPACR)]
+ ldr r4, [vcpu, #CP15_OFFSET(c2_TTBCR)]
+ ldr r5, [vcpu, #CP15_OFFSET(c3_DACR)]
+ add r12, vcpu, #CP15_OFFSET(c2_TTBR0)
+ ldrd r6, r7, [r12]
+ add r12, vcpu, #CP15_OFFSET(c2_TTBR1)
+ ldrd r8, r9, [r12]
+ ldr r10, [vcpu, #CP15_OFFSET(c10_PRRR)]
+ ldr r11, [vcpu, #CP15_OFFSET(c10_NMRR)]
+ ldr r12, [vcpu, #CP15_OFFSET(c0_CSSELR)]
+ .endif
+
+ mcr p15, 0, r2, c1, c0, 0 @ SCTLR
+ mcr p15, 0, r3, c1, c0, 2 @ CPACR
+ mcr p15, 0, r4, c2, c0, 2 @ TTBCR
+ mcr p15, 0, r5, c3, c0, 0 @ DACR
+ mcrr p15, 0, r6, r7, c2 @ TTBR 0
+ mcrr p15, 1, r8, r9, c2 @ TTBR 1
+ mcr p15, 0, r10, c10, c2, 0 @ PRRR
+ mcr p15, 0, r11, c10, c2, 1 @ NMRR
+ mcr p15, 2, r12, c0, c0, 0 @ CSSELR
+.endm
+
+/*
+ * Save the VGIC CPU state into memory
+ *
+ * Assumes vcpu pointer in vcpu reg
+ */
+.macro save_vgic_state
+#ifdef CONFIG_KVM_ARM_VGIC
+ /* Get VGIC VCTRL base into r2 */
+ ldr r2, [vcpu, #VCPU_KVM]
+ ldr r2, [r2, #KVM_VGIC_VCTRL]
+ cmp r2, #0
+ beq 2f
+
+ /* Compute the address of struct vgic_cpu */
+ add r11, vcpu, #VCPU_VGIC_CPU
+
+ /* Save all interesting registers */
+ ldr r3, [r2, #GICH_HCR]
+ ldr r4, [r2, #GICH_VMCR]
+ ldr r5, [r2, #GICH_MISR]
+ ldr r6, [r2, #GICH_EISR0]
+ ldr r7, [r2, #GICH_EISR1]
+ ldr r8, [r2, #GICH_ELRSR0]
+ ldr r9, [r2, #GICH_ELRSR1]
+ ldr r10, [r2, #GICH_APR]
+
+ str r3, [r11, #VGIC_CPU_HCR]
+ str r4, [r11, #VGIC_CPU_VMCR]
+ str r5, [r11, #VGIC_CPU_MISR]
+ str r6, [r11, #VGIC_CPU_EISR]
+ str r7, [r11, #(VGIC_CPU_EISR + 4)]
+ str r8, [r11, #VGIC_CPU_ELRSR]
+ str r9, [r11, #(VGIC_CPU_ELRSR + 4)]
+ str r10, [r11, #VGIC_CPU_APR]
+
+ /* Clear GICH_HCR */
+ mov r5, #0
+ str r5, [r2, #GICH_HCR]
+
+ /* Save list registers */
+ add r2, r2, #GICH_LR0
+ add r3, r11, #VGIC_CPU_LR
+ ldr r4, [r11, #VGIC_CPU_NR_LR]
+1: ldr r6, [r2], #4
+ str r6, [r3], #4
+ subs r4, r4, #1
+ bne 1b
+2:
+#endif
+.endm
+
+/*
+ * Restore the VGIC CPU state from memory
+ *
+ * Assumes vcpu pointer in vcpu reg
+ */
+.macro restore_vgic_state
+#ifdef CONFIG_KVM_ARM_VGIC
+ /* Get VGIC VCTRL base into r2 */
+ ldr r2, [vcpu, #VCPU_KVM]
+ ldr r2, [r2, #KVM_VGIC_VCTRL]
+ cmp r2, #0
+ beq 2f
+
+ /* Compute the address of struct vgic_cpu */
+ add r11, vcpu, #VCPU_VGIC_CPU
+
+ /* We only restore a minimal set of registers */
+ ldr r3, [r11, #VGIC_CPU_HCR]
+ ldr r4, [r11, #VGIC_CPU_VMCR]
+ ldr r8, [r11, #VGIC_CPU_APR]
+
+ str r3, [r2, #GICH_HCR]
+ str r4, [r2, #GICH_VMCR]
+ str r8, [r2, #GICH_APR]
+
+ /* Restore list registers */
+ add r2, r2, #GICH_LR0
+ add r3, r11, #VGIC_CPU_LR
+ ldr r4, [r11, #VGIC_CPU_NR_LR]
+1: ldr r6, [r3], #4
+ str r6, [r2], #4
+ subs r4, r4, #1
+ bne 1b
+2:
+#endif
+.endm
+
+#define CNTHCTL_PL1PCTEN (1 << 0)
+#define CNTHCTL_PL1PCEN (1 << 1)
+
+/*
+ * Save the timer state onto the VCPU and allow physical timer/counter access
+ * for the host.
+ *
+ * Assumes vcpu pointer in vcpu reg
+ * Clobbers r2-r5
+ */
+.macro save_timer_state
+#ifdef CONFIG_KVM_ARM_TIMER
+ ldr r4, [vcpu, #VCPU_KVM]
+ ldr r2, [r4, #KVM_TIMER_ENABLED]
+ cmp r2, #0
+ beq 1f
+
+ mrc p15, 0, r2, c14, c3, 1 @ CNTV_CTL
+ str r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
+ bic r2, #1 @ Clear ENABLE
+ mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
+ isb
+
+ mrrc p15, 3, r2, r3, c14 @ CNTV_CVAL
+ ldr r4, =VCPU_TIMER_CNTV_CVAL
+ add r5, vcpu, r4
+ strd r2, r3, [r5]
+
+1:
+#endif
+ @ Allow physical timer/counter access for the host
+ mrc p15, 4, r2, c14, c1, 0 @ CNTHCTL
+ orr r2, r2, #(CNTHCTL_PL1PCEN | CNTHCTL_PL1PCTEN)
+ mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
+.endm
+
+/*
+ * Load the timer state from the VCPU and deny physical timer/counter access
+ * for the host.
+ *
+ * Assumes vcpu pointer in vcpu reg
+ * Clobbers r2-r5
+ */
+.macro restore_timer_state
+ @ Disallow physical timer access for the guest
+ @ Physical counter access is allowed
+ mrc p15, 4, r2, c14, c1, 0 @ CNTHCTL
+ orr r2, r2, #CNTHCTL_PL1PCTEN
+ bic r2, r2, #CNTHCTL_PL1PCEN
+ mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
+
+#ifdef CONFIG_KVM_ARM_TIMER
+ ldr r4, [vcpu, #VCPU_KVM]
+ ldr r2, [r4, #KVM_TIMER_ENABLED]
+ cmp r2, #0
+ beq 1f
+
+ ldr r2, [r4, #KVM_TIMER_CNTVOFF]
+ ldr r3, [r4, #(KVM_TIMER_CNTVOFF + 4)]
+ mcrr p15, 4, r2, r3, c14 @ CNTVOFF
+
+ ldr r4, =VCPU_TIMER_CNTV_CVAL
+ add r5, vcpu, r4
+ ldrd r2, r3, [r5]
+ mcrr p15, 3, r2, r3, c14 @ CNTV_CVAL
+ isb
+
+ ldr r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
+ and r2, r2, #3
+ mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
+1:
+#endif
+.endm
+
+.equ vmentry, 0
+.equ vmexit, 1
+
+/* Configures the HSTR (Hyp System Trap Register) on entry/return
+ * (hardware reset value is 0) */
+.macro set_hstr operation
+ mrc p15, 4, r2, c1, c1, 3
+ ldr r3, =HSTR_T(15)
+ .if \operation == vmentry
+ orr r2, r2, r3 @ Trap CR{15}
+ .else
+ bic r2, r2, r3 @ Don't trap any CRx accesses
+ .endif
+ mcr p15, 4, r2, c1, c1, 3
+.endm
+
+/* Configures the HCPTR (Hyp Coprocessor Trap Register) on entry/return
+ * (hardware reset value is 0). Keep previous value in r2. */
+.macro set_hcptr operation, mask
+ mrc p15, 4, r2, c1, c1, 2
+ ldr r3, =\mask
+ .if \operation == vmentry
+ orr r3, r2, r3 @ Trap coproc-accesses defined in mask
+ .else
+ bic r3, r2, r3 @ Don't trap defined coproc-accesses
+ .endif
+ mcr p15, 4, r3, c1, c1, 2
+.endm
+
+/* Configures the HDCR (Hyp Debug Configuration Register) on entry/return
+ * (hardware reset value is 0) */
+.macro set_hdcr operation
+ mrc p15, 4, r2, c1, c1, 1
+ ldr r3, =(HDCR_TPM|HDCR_TPMCR)
+ .if \operation == vmentry
+ orr r2, r2, r3 @ Trap some perfmon accesses
+ .else
+ bic r2, r2, r3 @ Don't trap any perfmon accesses
+ .endif
+ mcr p15, 4, r2, c1, c1, 1
+.endm
+
+/* Enable/Disable: stage-2 trans., trap interrupts, trap wfi, trap smc */
+.macro configure_hyp_role operation
+ mrc p15, 4, r2, c1, c1, 0 @ HCR
+ bic r2, r2, #HCR_VIRT_EXCP_MASK
+ ldr r3, =HCR_GUEST_MASK
+ .if \operation == vmentry
+ orr r2, r2, r3
+ ldr r3, [vcpu, #VCPU_IRQ_LINES]
+ orr r2, r2, r3
+ .else
+ bic r2, r2, r3
+ .endif
+ mcr p15, 4, r2, c1, c1, 0
+.endm
+
+.macro load_vcpu
+ mrc p15, 4, vcpu, c13, c0, 2 @ HTPIDR
+.endm
diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
new file mode 100644
index 000000000000..98a870ff1a5c
--- /dev/null
+++ b/arch/arm/kvm/mmio.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_mmio.h>
+#include <asm/kvm_emulate.h>
+#include <trace/events/kvm.h>
+
+#include "trace.h"
+
+/**
+ * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
+ * @vcpu: The VCPU pointer
+ * @run: The VCPU run struct containing the mmio data
+ *
+ * This should only be called after returning from userspace for MMIO load
+ * emulation.
+ */
+int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ __u32 *dest;
+ unsigned int len;
+ int mask;
+
+ if (!run->mmio.is_write) {
+ dest = vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt);
+ memset(dest, 0, sizeof(int));
+
+ len = run->mmio.len;
+ if (len > 4)
+ return -EINVAL;
+
+ memcpy(dest, run->mmio.data, len);
+
+ trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
+ *((u64 *)run->mmio.data));
+
+ if (vcpu->arch.mmio_decode.sign_extend && len < 4) {
+ mask = 1U << ((len * 8) - 1);
+ *dest = (*dest ^ mask) - mask;
+ }
+ }
+
+ return 0;
+}
+
+static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+ struct kvm_exit_mmio *mmio)
+{
+ unsigned long rt, len;
+ bool is_write, sign_extend;
+
+ if ((vcpu->arch.hsr >> 8) & 1) {
+ /* cache operation on I/O addr, tell guest unsupported */
+ kvm_inject_dabt(vcpu, vcpu->arch.hxfar);
+ return 1;
+ }
+
+ if ((vcpu->arch.hsr >> 7) & 1) {
+ /* page table accesses IO mem: tell guest to fix its TTBR */
+ kvm_inject_dabt(vcpu, vcpu->arch.hxfar);
+ return 1;
+ }
+
+ switch ((vcpu->arch.hsr >> 22) & 0x3) {
+ case 0:
+ len = 1;
+ break;
+ case 1:
+ len = 2;
+ break;
+ case 2:
+ len = 4;
+ break;
+ default:
+ kvm_err("Hardware is weird: SAS 0b11 is reserved\n");
+ return -EFAULT;
+ }
+
+ is_write = vcpu->arch.hsr & HSR_WNR;
+ sign_extend = vcpu->arch.hsr & HSR_SSE;
+ rt = (vcpu->arch.hsr & HSR_SRT_MASK) >> HSR_SRT_SHIFT;
+
+ if (kvm_vcpu_reg_is_pc(vcpu, rt)) {
+ /* IO memory trying to read/write pc */
+ kvm_inject_pabt(vcpu, vcpu->arch.hxfar);
+ return 1;
+ }
+
+ mmio->is_write = is_write;
+ mmio->phys_addr = fault_ipa;
+ mmio->len = len;
+ vcpu->arch.mmio_decode.sign_extend = sign_extend;
+ vcpu->arch.mmio_decode.rt = rt;
+
+ /*
+ * The MMIO instruction is emulated and should not be re-executed
+ * in the guest.
+ */
+ kvm_skip_instr(vcpu, (vcpu->arch.hsr >> 25) & 1);
+ return 0;
+}
+
+int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ phys_addr_t fault_ipa)
+{
+ struct kvm_exit_mmio mmio;
+ unsigned long rt;
+ int ret;
+
+ /*
+ * Prepare MMIO operation. First stash it in a private
+ * structure that we can use for in-kernel emulation. If the
+ * kernel can't handle it, copy it into run->mmio and let user
+ * space do its magic.
+ */
+
+ if (vcpu->arch.hsr & HSR_ISV) {
+ ret = decode_hsr(vcpu, fault_ipa, &mmio);
+ if (ret)
+ return ret;
+ } else {
+ kvm_err("load/store instruction decoding not implemented\n");
+ return -ENOSYS;
+ }
+
+ rt = vcpu->arch.mmio_decode.rt;
+ trace_kvm_mmio((mmio.is_write) ? KVM_TRACE_MMIO_WRITE :
+ KVM_TRACE_MMIO_READ_UNSATISFIED,
+ mmio.len, fault_ipa,
+ (mmio.is_write) ? *vcpu_reg(vcpu, rt) : 0);
+
+ if (mmio.is_write)
+ memcpy(mmio.data, vcpu_reg(vcpu, rt), mmio.len);
+
+ if (vgic_handle_mmio(vcpu, run, &mmio))
+ return 1;
+
+ kvm_prepare_mmio(run, &mmio);
+ return 0;
+}
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
new file mode 100644
index 000000000000..99e07c7dd745
--- /dev/null
+++ b/arch/arm/kvm/mmu.c
@@ -0,0 +1,782 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/mman.h>
+#include <linux/kvm_host.h>
+#include <linux/io.h>
+#include <trace/events/kvm.h>
+#include <asm/idmap.h>
+#include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+#include <asm/kvm_mmio.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_emulate.h>
+#include <asm/mach/map.h>
+#include <trace/events/kvm.h>
+
+#include "trace.h"
+
+extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[];
+
+static DEFINE_MUTEX(kvm_hyp_pgd_mutex);
+
+static void kvm_tlb_flush_vmid(struct kvm *kvm)
+{
+ kvm_call_hyp(__kvm_tlb_flush_vmid, kvm);
+}
+
+static void kvm_set_pte(pte_t *pte, pte_t new_pte)
+{
+ pte_val(*pte) = new_pte;
+ /*
+ * flush_pmd_entry just takes a void pointer and cleans the necessary
+ * cache entries, so we can reuse the function for ptes.
+ */
+ flush_pmd_entry(pte);
+}
+
+static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
+ int min, int max)
+{
+ void *page;
+
+ BUG_ON(max > KVM_NR_MEM_OBJS);
+ if (cache->nobjs >= min)
+ return 0;
+ while (cache->nobjs < max) {
+ page = (void *)__get_free_page(PGALLOC_GFP);
+ if (!page)
+ return -ENOMEM;
+ cache->objects[cache->nobjs++] = page;
+ }
+ return 0;
+}
+
+static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
+{
+ while (mc->nobjs)
+ free_page((unsigned long)mc->objects[--mc->nobjs]);
+}
+
+static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc)
+{
+ void *p;
+
+ BUG_ON(!mc || !mc->nobjs);
+ p = mc->objects[--mc->nobjs];
+ return p;
+}
+
+static void free_ptes(pmd_t *pmd, unsigned long addr)
+{
+ pte_t *pte;
+ unsigned int i;
+
+ for (i = 0; i < PTRS_PER_PMD; i++, addr += PMD_SIZE) {
+ if (!pmd_none(*pmd) && pmd_table(*pmd)) {
+ pte = pte_offset_kernel(pmd, addr);
+ pte_free_kernel(NULL, pte);
+ }
+ pmd++;
+ }
+}
+
+/**
+ * free_hyp_pmds - free a Hyp-mode level-2 tables and child level-3 tables
+ *
+ * Assumes this is a page table used strictly in Hyp-mode and therefore contains
+ * only mappings in the kernel memory area, which is above PAGE_OFFSET.
+ */
+void free_hyp_pmds(void)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ unsigned long addr;
+
+ mutex_lock(&kvm_hyp_pgd_mutex);
+ for (addr = PAGE_OFFSET; addr != 0; addr += PGDIR_SIZE) {
+ pgd = hyp_pgd + pgd_index(addr);
+ pud = pud_offset(pgd, addr);
+
+ if (pud_none(*pud))
+ continue;
+ BUG_ON(pud_bad(*pud));
+
+ pmd = pmd_offset(pud, addr);
+ free_ptes(pmd, addr);
+ pmd_free(NULL, pmd);
+ pud_clear(pud);
+ }
+ mutex_unlock(&kvm_hyp_pgd_mutex);
+}
+
+static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long start,
+ unsigned long end)
+{
+ pte_t *pte;
+ unsigned long addr;
+ struct page *page;
+
+ for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
+ pte = pte_offset_kernel(pmd, addr);
+ BUG_ON(!virt_addr_valid(addr));
+ page = virt_to_page(addr);
+ kvm_set_pte(pte, mk_pte(page, PAGE_HYP));
+ }
+}
+
+static void create_hyp_io_pte_mappings(pmd_t *pmd, unsigned long start,
+ unsigned long end,
+ unsigned long *pfn_base)
+{
+ pte_t *pte;
+ unsigned long addr;
+
+ for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
+ pte = pte_offset_kernel(pmd, addr);
+ BUG_ON(pfn_valid(*pfn_base));
+ kvm_set_pte(pte, pfn_pte(*pfn_base, PAGE_HYP_DEVICE));
+ (*pfn_base)++;
+ }
+}
+
+static int create_hyp_pmd_mappings(pud_t *pud, unsigned long start,
+ unsigned long end, unsigned long *pfn_base)
+{
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long addr, next;
+
+ for (addr = start; addr < end; addr = next) {
+ pmd = pmd_offset(pud, addr);
+
+ BUG_ON(pmd_sect(*pmd));
+
+ if (pmd_none(*pmd)) {
+ pte = pte_alloc_one_kernel(NULL, addr);
+ if (!pte) {
+ kvm_err("Cannot allocate Hyp pte\n");
+ return -ENOMEM;
+ }
+ pmd_populate_kernel(NULL, pmd, pte);
+ }
+
+ next = pmd_addr_end(addr, end);
+
+ /*
+ * If pfn_base is NULL, we map kernel pages into HYP with the
+ * virtual address. Otherwise, this is considered an I/O
+ * mapping and we map the physical region starting at
+ * *pfn_base to [start, end[.
+ */
+ if (!pfn_base)
+ create_hyp_pte_mappings(pmd, addr, next);
+ else
+ create_hyp_io_pte_mappings(pmd, addr, next, pfn_base);
+ }
+
+ return 0;
+}
+
+static int __create_hyp_mappings(void *from, void *to, unsigned long *pfn_base)
+{
+ unsigned long start = (unsigned long)from;
+ unsigned long end = (unsigned long)to;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ unsigned long addr, next;
+ int err = 0;
+
+ BUG_ON(start > end);
+ if (start < PAGE_OFFSET)
+ return -EINVAL;
+
+ mutex_lock(&kvm_hyp_pgd_mutex);
+ for (addr = start; addr < end; addr = next) {
+ pgd = hyp_pgd + pgd_index(addr);
+ pud = pud_offset(pgd, addr);
+
+ if (pud_none_or_clear_bad(pud)) {
+ pmd = pmd_alloc_one(NULL, addr);
+ if (!pmd) {
+ kvm_err("Cannot allocate Hyp pmd\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ pud_populate(NULL, pud, pmd);
+ }
+
+ next = pgd_addr_end(addr, end);
+ err = create_hyp_pmd_mappings(pud, addr, next, pfn_base);
+ if (err)
+ goto out;
+ }
+out:
+ mutex_unlock(&kvm_hyp_pgd_mutex);
+ return err;
+}
+
+/**
+ * create_hyp_mappings - map a kernel virtual address range in Hyp mode
+ * @from: The virtual kernel start address of the range
+ * @to: The virtual kernel end address of the range (exclusive)
+ *
+ * The same virtual address as the kernel virtual address is also used in
+ * Hyp-mode mapping to the same underlying physical pages.
+ *
+ * Note: Wrapping around zero in the "to" address is not supported.
+ */
+int create_hyp_mappings(void *from, void *to)
+{
+ return __create_hyp_mappings(from, to, NULL);
+}
+
+/**
+ * create_hyp_io_mappings - map a physical IO range in Hyp mode
+ * @from: The virtual HYP start address of the range
+ * @to: The virtual HYP end address of the range (exclusive)
+ * @addr: The physical start address which gets mapped
+ */
+int create_hyp_io_mappings(void *from, void *to, phys_addr_t addr)
+{
+ unsigned long pfn = __phys_to_pfn(addr);
+ return __create_hyp_mappings(from, to, &pfn);
+}
+
+/**
+ * kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
+ * @kvm: The KVM struct pointer for the VM.
+ *
+ * Allocates the 1st level table only of size defined by S2_PGD_ORDER (can
+ * support either full 40-bit input addresses or limited to 32-bit input
+ * addresses). Clears the allocated pages.
+ *
+ * Note we don't need locking here as this is only called when the VM is
+ * created, which can only be done once.
+ */
+int kvm_alloc_stage2_pgd(struct kvm *kvm)
+{
+ pgd_t *pgd;
+
+ if (kvm->arch.pgd != NULL) {
+ kvm_err("kvm_arch already initialized?\n");
+ return -EINVAL;
+ }
+
+ pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, S2_PGD_ORDER);
+ if (!pgd)
+ return -ENOMEM;
+
+ /* stage-2 pgd must be aligned to its size */
+ VM_BUG_ON((unsigned long)pgd & (S2_PGD_SIZE - 1));
+
+ memset(pgd, 0, PTRS_PER_S2_PGD * sizeof(pgd_t));
+ clean_dcache_area(pgd, PTRS_PER_S2_PGD * sizeof(pgd_t));
+ kvm->arch.pgd = pgd;
+
+ return 0;
+}
+
+static void clear_pud_entry(pud_t *pud)
+{
+ pmd_t *pmd_table = pmd_offset(pud, 0);
+ pud_clear(pud);
+ pmd_free(NULL, pmd_table);
+ put_page(virt_to_page(pud));
+}
+
+static void clear_pmd_entry(pmd_t *pmd)
+{
+ pte_t *pte_table = pte_offset_kernel(pmd, 0);
+ pmd_clear(pmd);
+ pte_free_kernel(NULL, pte_table);
+ put_page(virt_to_page(pmd));
+}
+
+static bool pmd_empty(pmd_t *pmd)
+{
+ struct page *pmd_page = virt_to_page(pmd);
+ return page_count(pmd_page) == 1;
+}
+
+static void clear_pte_entry(pte_t *pte)
+{
+ if (pte_present(*pte)) {
+ kvm_set_pte(pte, __pte(0));
+ put_page(virt_to_page(pte));
+ }
+}
+
+static bool pte_empty(pte_t *pte)
+{
+ struct page *pte_page = virt_to_page(pte);
+ return page_count(pte_page) == 1;
+}
+
+/**
+ * unmap_stage2_range -- Clear stage2 page table entries to unmap a range
+ * @kvm: The VM pointer
+ * @start: The intermediate physical base address of the range to unmap
+ * @size: The size of the area to unmap
+ *
+ * Clear a range of stage-2 mappings, lowering the various ref-counts. Must
+ * be called while holding mmu_lock (unless for freeing the stage2 pgd before
+ * destroying the VM), otherwise another faulting VCPU may come in and mess
+ * with things behind our backs.
+ */
+static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ phys_addr_t addr = start, end = start + size;
+ u64 range;
+
+ while (addr < end) {
+ pgd = kvm->arch.pgd + pgd_index(addr);
+ pud = pud_offset(pgd, addr);
+ if (pud_none(*pud)) {
+ addr += PUD_SIZE;
+ continue;
+ }
+
+ pmd = pmd_offset(pud, addr);
+ if (pmd_none(*pmd)) {
+ addr += PMD_SIZE;
+ continue;
+ }
+
+ pte = pte_offset_kernel(pmd, addr);
+ clear_pte_entry(pte);
+ range = PAGE_SIZE;
+
+ /* If we emptied the pte, walk back up the ladder */
+ if (pte_empty(pte)) {
+ clear_pmd_entry(pmd);
+ range = PMD_SIZE;
+ if (pmd_empty(pmd)) {
+ clear_pud_entry(pud);
+ range = PUD_SIZE;
+ }
+ }
+
+ addr += range;
+ }
+}
+
+/**
+ * kvm_free_stage2_pgd - free all stage-2 tables
+ * @kvm: The KVM struct pointer for the VM.
+ *
+ * Walks the level-1 page table pointed to by kvm->arch.pgd and frees all
+ * underlying level-2 and level-3 tables before freeing the actual level-1 table
+ * and setting the struct pointer to NULL.
+ *
+ * Note we don't need locking here as this is only called when the VM is
+ * destroyed, which can only be done once.
+ */
+void kvm_free_stage2_pgd(struct kvm *kvm)
+{
+ if (kvm->arch.pgd == NULL)
+ return;
+
+ unmap_stage2_range(kvm, 0, KVM_PHYS_SIZE);
+ free_pages((unsigned long)kvm->arch.pgd, S2_PGD_ORDER);
+ kvm->arch.pgd = NULL;
+}
+
+
+static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
+ phys_addr_t addr, const pte_t *new_pte, bool iomap)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte, old_pte;
+
+ /* Create 2nd stage page table mapping - Level 1 */
+ pgd = kvm->arch.pgd + pgd_index(addr);
+ pud = pud_offset(pgd, addr);
+ if (pud_none(*pud)) {
+ if (!cache)
+ return 0; /* ignore calls from kvm_set_spte_hva */
+ pmd = mmu_memory_cache_alloc(cache);
+ pud_populate(NULL, pud, pmd);
+ pmd += pmd_index(addr);
+ get_page(virt_to_page(pud));
+ } else
+ pmd = pmd_offset(pud, addr);
+
+ /* Create 2nd stage page table mapping - Level 2 */
+ if (pmd_none(*pmd)) {
+ if (!cache)
+ return 0; /* ignore calls from kvm_set_spte_hva */
+ pte = mmu_memory_cache_alloc(cache);
+ clean_pte_table(pte);
+ pmd_populate_kernel(NULL, pmd, pte);
+ pte += pte_index(addr);
+ get_page(virt_to_page(pmd));
+ } else
+ pte = pte_offset_kernel(pmd, addr);
+
+ if (iomap && pte_present(*pte))
+ return -EFAULT;
+
+ /* Create 2nd stage page table mapping - Level 3 */
+ old_pte = *pte;
+ kvm_set_pte(pte, *new_pte);
+ if (pte_present(old_pte))
+ kvm_tlb_flush_vmid(kvm);
+ else
+ get_page(virt_to_page(pte));
+
+ return 0;
+}
+
+/**
+ * kvm_phys_addr_ioremap - map a device range to guest IPA
+ *
+ * @kvm: The KVM pointer
+ * @guest_ipa: The IPA at which to insert the mapping
+ * @pa: The physical address of the device
+ * @size: The size of the mapping
+ */
+int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
+ phys_addr_t pa, unsigned long size)
+{
+ phys_addr_t addr, end;
+ int ret = 0;
+ unsigned long pfn;
+ struct kvm_mmu_memory_cache cache = { 0, };
+
+ end = (guest_ipa + size + PAGE_SIZE - 1) & PAGE_MASK;
+ pfn = __phys_to_pfn(pa);
+
+ for (addr = guest_ipa; addr < end; addr += PAGE_SIZE) {
+ pte_t pte = pfn_pte(pfn, PAGE_S2_DEVICE | L_PTE_S2_RDWR);
+
+ ret = mmu_topup_memory_cache(&cache, 2, 2);
+ if (ret)
+ goto out;
+ spin_lock(&kvm->mmu_lock);
+ ret = stage2_set_pte(kvm, &cache, addr, &pte, true);
+ spin_unlock(&kvm->mmu_lock);
+ if (ret)
+ goto out;
+
+ pfn++;
+ }
+
+out:
+ mmu_free_memory_cache(&cache);
+ return ret;
+}
+
+static void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn)
+{
+ /*
+ * If we are going to insert an instruction page and the icache is
+ * either VIPT or PIPT, there is a potential problem where the host
+ * (or another VM) may have used the same page as this guest, and we
+ * read incorrect data from the icache. If we're using a PIPT cache,
+ * we can invalidate just that page, but if we are using a VIPT cache
+ * we need to invalidate the entire icache - damn shame - as written
+ * in the ARM ARM (DDI 0406C.b - Page B3-1393).
+ *
+ * VIVT caches are tagged using both the ASID and the VMID and doesn't
+ * need any kind of flushing (DDI 0406C.b - Page B3-1392).
+ */
+ if (icache_is_pipt()) {
+ unsigned long hva = gfn_to_hva(kvm, gfn);
+ __cpuc_coherent_user_range(hva, hva + PAGE_SIZE);
+ } else if (!icache_is_vivt_asid_tagged()) {
+ /* any kind of VIPT cache */
+ __flush_icache_all();
+ }
+}
+
+static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+ gfn_t gfn, struct kvm_memory_slot *memslot,
+ unsigned long fault_status)
+{
+ pte_t new_pte;
+ pfn_t pfn;
+ int ret;
+ bool write_fault, writable;
+ unsigned long mmu_seq;
+ struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache;
+
+ write_fault = kvm_is_write_fault(vcpu->arch.hsr);
+ if (fault_status == FSC_PERM && !write_fault) {
+ kvm_err("Unexpected L2 read permission error\n");
+ return -EFAULT;
+ }
+
+ /* We need minimum second+third level pages */
+ ret = mmu_topup_memory_cache(memcache, 2, KVM_NR_MEM_OBJS);
+ if (ret)
+ return ret;
+
+ mmu_seq = vcpu->kvm->mmu_notifier_seq;
+ /*
+ * Ensure the read of mmu_notifier_seq happens before we call
+ * gfn_to_pfn_prot (which calls get_user_pages), so that we don't risk
+ * the page we just got a reference to gets unmapped before we have a
+ * chance to grab the mmu_lock, which ensure that if the page gets
+ * unmapped afterwards, the call to kvm_unmap_hva will take it away
+ * from us again properly. This smp_rmb() interacts with the smp_wmb()
+ * in kvm_mmu_notifier_invalidate_<page|range_end>.
+ */
+ smp_rmb();
+
+ pfn = gfn_to_pfn_prot(vcpu->kvm, gfn, write_fault, &writable);
+ if (is_error_pfn(pfn))
+ return -EFAULT;
+
+ new_pte = pfn_pte(pfn, PAGE_S2);
+ coherent_icache_guest_page(vcpu->kvm, gfn);
+
+ spin_lock(&vcpu->kvm->mmu_lock);
+ if (mmu_notifier_retry(vcpu->kvm, mmu_seq))
+ goto out_unlock;
+ if (writable) {
+ pte_val(new_pte) |= L_PTE_S2_RDWR;
+ kvm_set_pfn_dirty(pfn);
+ }
+ stage2_set_pte(vcpu->kvm, memcache, fault_ipa, &new_pte, false);
+
+out_unlock:
+ spin_unlock(&vcpu->kvm->mmu_lock);
+ kvm_release_pfn_clean(pfn);
+ return 0;
+}
+
+/**
+ * kvm_handle_guest_abort - handles all 2nd stage aborts
+ * @vcpu: the VCPU pointer
+ * @run: the kvm_run structure
+ *
+ * Any abort that gets to the host is almost guaranteed to be caused by a
+ * missing second stage translation table entry, which can mean that either the
+ * guest simply needs more memory and we must allocate an appropriate page or it
+ * can mean that the guest tried to access I/O memory, which is emulated by user
+ * space. The distinction is based on the IPA causing the fault and whether this
+ * memory region has been registered as standard RAM by user space.
+ */
+int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ unsigned long hsr_ec;
+ unsigned long fault_status;
+ phys_addr_t fault_ipa;
+ struct kvm_memory_slot *memslot;
+ bool is_iabt;
+ gfn_t gfn;
+ int ret, idx;
+
+ hsr_ec = vcpu->arch.hsr >> HSR_EC_SHIFT;
+ is_iabt = (hsr_ec == HSR_EC_IABT);
+ fault_ipa = ((phys_addr_t)vcpu->arch.hpfar & HPFAR_MASK) << 8;
+
+ trace_kvm_guest_fault(*vcpu_pc(vcpu), vcpu->arch.hsr,
+ vcpu->arch.hxfar, fault_ipa);
+
+ /* Check the stage-2 fault is trans. fault or write fault */
+ fault_status = (vcpu->arch.hsr & HSR_FSC_TYPE);
+ if (fault_status != FSC_FAULT && fault_status != FSC_PERM) {
+ kvm_err("Unsupported fault status: EC=%#lx DFCS=%#lx\n",
+ hsr_ec, fault_status);
+ return -EFAULT;
+ }
+
+ idx = srcu_read_lock(&vcpu->kvm->srcu);
+
+ gfn = fault_ipa >> PAGE_SHIFT;
+ if (!kvm_is_visible_gfn(vcpu->kvm, gfn)) {
+ if (is_iabt) {
+ /* Prefetch Abort on I/O address */
+ kvm_inject_pabt(vcpu, vcpu->arch.hxfar);
+ ret = 1;
+ goto out_unlock;
+ }
+
+ if (fault_status != FSC_FAULT) {
+ kvm_err("Unsupported fault status on io memory: %#lx\n",
+ fault_status);
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+ /* Adjust page offset */
+ fault_ipa |= vcpu->arch.hxfar & ~PAGE_MASK;
+ ret = io_mem_abort(vcpu, run, fault_ipa);
+ goto out_unlock;
+ }
+
+ memslot = gfn_to_memslot(vcpu->kvm, gfn);
+
+ ret = user_mem_abort(vcpu, fault_ipa, gfn, memslot, fault_status);
+ if (ret == 0)
+ ret = 1;
+out_unlock:
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
+ return ret;
+}
+
+static void handle_hva_to_gpa(struct kvm *kvm,
+ unsigned long start,
+ unsigned long end,
+ void (*handler)(struct kvm *kvm,
+ gpa_t gpa, void *data),
+ void *data)
+{
+ struct kvm_memslots *slots;
+ struct kvm_memory_slot *memslot;
+
+ slots = kvm_memslots(kvm);
+
+ /* we only care about the pages that the guest sees */
+ kvm_for_each_memslot(memslot, slots) {
+ unsigned long hva_start, hva_end;
+ gfn_t gfn, gfn_end;
+
+ hva_start = max(start, memslot->userspace_addr);
+ hva_end = min(end, memslot->userspace_addr +
+ (memslot->npages << PAGE_SHIFT));
+ if (hva_start >= hva_end)
+ continue;
+
+ /*
+ * {gfn(page) | page intersects with [hva_start, hva_end)} =
+ * {gfn_start, gfn_start+1, ..., gfn_end-1}.
+ */
+ gfn = hva_to_gfn_memslot(hva_start, memslot);
+ gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot);
+
+ for (; gfn < gfn_end; ++gfn) {
+ gpa_t gpa = gfn << PAGE_SHIFT;
+ handler(kvm, gpa, data);
+ }
+ }
+}
+
+static void kvm_unmap_hva_handler(struct kvm *kvm, gpa_t gpa, void *data)
+{
+ unmap_stage2_range(kvm, gpa, PAGE_SIZE);
+ kvm_tlb_flush_vmid(kvm);
+}
+
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
+{
+ unsigned long end = hva + PAGE_SIZE;
+
+ if (!kvm->arch.pgd)
+ return 0;
+
+ trace_kvm_unmap_hva(hva);
+ handle_hva_to_gpa(kvm, hva, end, &kvm_unmap_hva_handler, NULL);
+ return 0;
+}
+
+int kvm_unmap_hva_range(struct kvm *kvm,
+ unsigned long start, unsigned long end)
+{
+ if (!kvm->arch.pgd)
+ return 0;
+
+ trace_kvm_unmap_hva_range(start, end);
+ handle_hva_to_gpa(kvm, start, end, &kvm_unmap_hva_handler, NULL);
+ return 0;
+}
+
+static void kvm_set_spte_handler(struct kvm *kvm, gpa_t gpa, void *data)
+{
+ pte_t *pte = (pte_t *)data;
+
+ stage2_set_pte(kvm, NULL, gpa, pte, false);
+}
+
+
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
+{
+ unsigned long end = hva + PAGE_SIZE;
+ pte_t stage2_pte;
+
+ if (!kvm->arch.pgd)
+ return;
+
+ trace_kvm_set_spte_hva(hva);
+ stage2_pte = pfn_pte(pte_pfn(pte), PAGE_S2);
+ handle_hva_to_gpa(kvm, hva, end, &kvm_set_spte_handler, &stage2_pte);
+}
+
+void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu)
+{
+ mmu_free_memory_cache(&vcpu->arch.mmu_page_cache);
+}
+
+phys_addr_t kvm_mmu_get_httbr(void)
+{
+ VM_BUG_ON(!virt_addr_valid(hyp_pgd));
+ return virt_to_phys(hyp_pgd);
+}
+
+int kvm_mmu_init(void)
+{
+ if (!hyp_pgd) {
+ kvm_err("Hyp mode PGD not allocated\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * kvm_clear_idmap - remove all idmaps from the hyp pgd
+ *
+ * Free the underlying pmds for all pgds in range and clear the pgds (but
+ * don't free them) afterwards.
+ */
+void kvm_clear_hyp_idmap(void)
+{
+ unsigned long addr, end;
+ unsigned long next;
+ pgd_t *pgd = hyp_pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+
+ addr = virt_to_phys(__hyp_idmap_text_start);
+ end = virt_to_phys(__hyp_idmap_text_end);
+
+ pgd += pgd_index(addr);
+ do {
+ next = pgd_addr_end(addr, end);
+ if (pgd_none_or_clear_bad(pgd))
+ continue;
+ pud = pud_offset(pgd, addr);
+ pmd = pmd_offset(pud, addr);
+
+ pud_clear(pud);
+ clean_pmd_entry(pmd);
+ pmd_free(NULL, (pmd_t *)((unsigned long)pmd & PAGE_MASK));
+ } while (pgd++, addr = next, addr < end);
+}
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
new file mode 100644
index 000000000000..7ee5bb7a3667
--- /dev/null
+++ b/arch/arm/kvm/psci.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/wait.h>
+
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_psci.h>
+
+/*
+ * This is an implementation of the Power State Coordination Interface
+ * as described in ARM document number ARM DEN 0022A.
+ */
+
+static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.pause = true;
+}
+
+static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
+{
+ struct kvm *kvm = source_vcpu->kvm;
+ struct kvm_vcpu *vcpu;
+ wait_queue_head_t *wq;
+ unsigned long cpu_id;
+ phys_addr_t target_pc;
+
+ cpu_id = *vcpu_reg(source_vcpu, 1);
+ if (vcpu_mode_is_32bit(source_vcpu))
+ cpu_id &= ~((u32) 0);
+
+ if (cpu_id >= atomic_read(&kvm->online_vcpus))
+ return KVM_PSCI_RET_INVAL;
+
+ target_pc = *vcpu_reg(source_vcpu, 2);
+
+ vcpu = kvm_get_vcpu(kvm, cpu_id);
+
+ wq = kvm_arch_vcpu_wq(vcpu);
+ if (!waitqueue_active(wq))
+ return KVM_PSCI_RET_INVAL;
+
+ kvm_reset_vcpu(vcpu);
+
+ /* Gracefully handle Thumb2 entry point */
+ if (vcpu_mode_is_32bit(vcpu) && (target_pc & 1)) {
+ target_pc &= ~((phys_addr_t) 1);
+ vcpu_set_thumb(vcpu);
+ }
+
+ *vcpu_pc(vcpu) = target_pc;
+ vcpu->arch.pause = false;
+ smp_mb(); /* Make sure the above is visible */
+
+ wake_up_interruptible(wq);
+
+ return KVM_PSCI_RET_SUCCESS;
+}
+
+/**
+ * kvm_psci_call - handle PSCI call if r0 value is in range
+ * @vcpu: Pointer to the VCPU struct
+ *
+ * Handle PSCI calls from guests through traps from HVC or SMC instructions.
+ * The calling convention is similar to SMC calls to the secure world where
+ * the function number is placed in r0 and this function returns true if the
+ * function number specified in r0 is withing the PSCI range, and false
+ * otherwise.
+ */
+bool kvm_psci_call(struct kvm_vcpu *vcpu)
+{
+ unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
+ unsigned long val;
+
+ switch (psci_fn) {
+ case KVM_PSCI_FN_CPU_OFF:
+ kvm_psci_vcpu_off(vcpu);
+ val = KVM_PSCI_RET_SUCCESS;
+ break;
+ case KVM_PSCI_FN_CPU_ON:
+ val = kvm_psci_vcpu_on(vcpu);
+ break;
+ case KVM_PSCI_FN_CPU_SUSPEND:
+ case KVM_PSCI_FN_MIGRATE:
+ val = KVM_PSCI_RET_NI;
+ break;
+
+ default:
+ return false;
+ }
+
+ *vcpu_reg(vcpu, 0) = val;
+ return true;
+}
diff --git a/arch/arm/kvm/reset.c b/arch/arm/kvm/reset.c
new file mode 100644
index 000000000000..b80256b554cd
--- /dev/null
+++ b/arch/arm/kvm/reset.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+
+#include <asm/unified.h>
+#include <asm/ptrace.h>
+#include <asm/cputype.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_coproc.h>
+
+/******************************************************************************
+ * Cortex-A15 Reset Values
+ */
+
+static const int a15_max_cpu_idx = 3;
+
+static struct kvm_regs a15_regs_reset = {
+ .usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT,
+};
+
+
+/*******************************************************************************
+ * Exported reset function
+ */
+
+/**
+ * kvm_reset_vcpu - sets core registers and cp15 registers to reset value
+ * @vcpu: The VCPU pointer
+ *
+ * This function finds the right table above and sets the registers on the
+ * virtual CPU struct to their architectually defined reset values.
+ */
+int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
+{
+ struct kvm_regs *cpu_reset;
+
+ switch (vcpu->arch.target) {
+ case KVM_ARM_TARGET_CORTEX_A15:
+ if (vcpu->vcpu_id > a15_max_cpu_idx)
+ return -EINVAL;
+ cpu_reset = &a15_regs_reset;
+ vcpu->arch.midr = read_cpuid_id();
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ /* Reset core registers */
+ memcpy(&vcpu->arch.regs, cpu_reset, sizeof(vcpu->arch.regs));
+
+ /* Reset CP15 registers */
+ kvm_reset_coprocs(vcpu);
+
+ return 0;
+}
diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h
new file mode 100644
index 000000000000..a8e73ed5ad5b
--- /dev/null
+++ b/arch/arm/kvm/trace.h
@@ -0,0 +1,235 @@
+#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVM_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+
+/*
+ * Tracepoints for entry/exit to guest
+ */
+TRACE_EVENT(kvm_entry,
+ TP_PROTO(unsigned long vcpu_pc),
+ TP_ARGS(vcpu_pc),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, vcpu_pc )
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_pc = vcpu_pc;
+ ),
+
+ TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
+);
+
+TRACE_EVENT(kvm_exit,
+ TP_PROTO(unsigned long vcpu_pc),
+ TP_ARGS(vcpu_pc),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, vcpu_pc )
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_pc = vcpu_pc;
+ ),
+
+ TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
+);
+
+TRACE_EVENT(kvm_guest_fault,
+ TP_PROTO(unsigned long vcpu_pc, unsigned long hsr,
+ unsigned long hxfar,
+ unsigned long long ipa),
+ TP_ARGS(vcpu_pc, hsr, hxfar, ipa),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, vcpu_pc )
+ __field( unsigned long, hsr )
+ __field( unsigned long, hxfar )
+ __field( unsigned long long, ipa )
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_pc = vcpu_pc;
+ __entry->hsr = hsr;
+ __entry->hxfar = hxfar;
+ __entry->ipa = ipa;
+ ),
+
+ TP_printk("guest fault at PC %#08lx (hxfar %#08lx, "
+ "ipa %#16llx, hsr %#08lx",
+ __entry->vcpu_pc, __entry->hxfar,
+ __entry->ipa, __entry->hsr)
+);
+
+TRACE_EVENT(kvm_irq_line,
+ TP_PROTO(unsigned int type, int vcpu_idx, int irq_num, int level),
+ TP_ARGS(type, vcpu_idx, irq_num, level),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, type )
+ __field( int, vcpu_idx )
+ __field( int, irq_num )
+ __field( int, level )
+ ),
+
+ TP_fast_assign(
+ __entry->type = type;
+ __entry->vcpu_idx = vcpu_idx;
+ __entry->irq_num = irq_num;
+ __entry->level = level;
+ ),
+
+ TP_printk("Inject %s interrupt (%d), vcpu->idx: %d, num: %d, level: %d",
+ (__entry->type == KVM_ARM_IRQ_TYPE_CPU) ? "CPU" :
+ (__entry->type == KVM_ARM_IRQ_TYPE_PPI) ? "VGIC PPI" :
+ (__entry->type == KVM_ARM_IRQ_TYPE_SPI) ? "VGIC SPI" : "UNKNOWN",
+ __entry->type, __entry->vcpu_idx, __entry->irq_num, __entry->level)
+);
+
+TRACE_EVENT(kvm_mmio_emulate,
+ TP_PROTO(unsigned long vcpu_pc, unsigned long instr,
+ unsigned long cpsr),
+ TP_ARGS(vcpu_pc, instr, cpsr),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, vcpu_pc )
+ __field( unsigned long, instr )
+ __field( unsigned long, cpsr )
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_pc = vcpu_pc;
+ __entry->instr = instr;
+ __entry->cpsr = cpsr;
+ ),
+
+ TP_printk("Emulate MMIO at: 0x%08lx (instr: %08lx, cpsr: %08lx)",
+ __entry->vcpu_pc, __entry->instr, __entry->cpsr)
+);
+
+/* Architecturally implementation defined CP15 register access */
+TRACE_EVENT(kvm_emulate_cp15_imp,
+ TP_PROTO(unsigned long Op1, unsigned long Rt1, unsigned long CRn,
+ unsigned long CRm, unsigned long Op2, bool is_write),
+ TP_ARGS(Op1, Rt1, CRn, CRm, Op2, is_write),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, Op1 )
+ __field( unsigned int, Rt1 )
+ __field( unsigned int, CRn )
+ __field( unsigned int, CRm )
+ __field( unsigned int, Op2 )
+ __field( bool, is_write )
+ ),
+
+ TP_fast_assign(
+ __entry->is_write = is_write;
+ __entry->Op1 = Op1;
+ __entry->Rt1 = Rt1;
+ __entry->CRn = CRn;
+ __entry->CRm = CRm;
+ __entry->Op2 = Op2;
+ ),
+
+ TP_printk("Implementation defined CP15: %s\tp15, %u, r%u, c%u, c%u, %u",
+ (__entry->is_write) ? "mcr" : "mrc",
+ __entry->Op1, __entry->Rt1, __entry->CRn,
+ __entry->CRm, __entry->Op2)
+);
+
+TRACE_EVENT(kvm_wfi,
+ TP_PROTO(unsigned long vcpu_pc),
+ TP_ARGS(vcpu_pc),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, vcpu_pc )
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_pc = vcpu_pc;
+ ),
+
+ TP_printk("guest executed wfi at: 0x%08lx", __entry->vcpu_pc)
+);
+
+TRACE_EVENT(kvm_unmap_hva,
+ TP_PROTO(unsigned long hva),
+ TP_ARGS(hva),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, hva )
+ ),
+
+ TP_fast_assign(
+ __entry->hva = hva;
+ ),
+
+ TP_printk("mmu notifier unmap hva: %#08lx", __entry->hva)
+);
+
+TRACE_EVENT(kvm_unmap_hva_range,
+ TP_PROTO(unsigned long start, unsigned long end),
+ TP_ARGS(start, end),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, start )
+ __field( unsigned long, end )
+ ),
+
+ TP_fast_assign(
+ __entry->start = start;
+ __entry->end = end;
+ ),
+
+ TP_printk("mmu notifier unmap range: %#08lx -- %#08lx",
+ __entry->start, __entry->end)
+);
+
+TRACE_EVENT(kvm_set_spte_hva,
+ TP_PROTO(unsigned long hva),
+ TP_ARGS(hva),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, hva )
+ ),
+
+ TP_fast_assign(
+ __entry->hva = hva;
+ ),
+
+ TP_printk("mmu notifier set pte hva: %#08lx", __entry->hva)
+);
+
+TRACE_EVENT(kvm_hvc,
+ TP_PROTO(unsigned long vcpu_pc, unsigned long r0, unsigned long imm),
+ TP_ARGS(vcpu_pc, r0, imm),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, vcpu_pc )
+ __field( unsigned long, r0 )
+ __field( unsigned long, imm )
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_pc = vcpu_pc;
+ __entry->r0 = r0;
+ __entry->imm = imm;
+ ),
+
+ TP_printk("HVC at 0x%08lx (r0: 0x%08lx, imm: 0x%lx",
+ __entry->vcpu_pc, __entry->r0, __entry->imm)
+);
+
+#endif /* _TRACE_KVM_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH arch/arm/kvm
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
new file mode 100644
index 000000000000..c9a17316e9fe
--- /dev/null
+++ b/arch/arm/kvm/vgic.c
@@ -0,0 +1,1506 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/cpu.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <linux/irqchip/arm-gic.h>
+
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+
+/*
+ * How the whole thing works (courtesy of Christoffer Dall):
+ *
+ * - At any time, the dist->irq_pending_on_cpu is the oracle that knows if
+ * something is pending
+ * - VGIC pending interrupts are stored on the vgic.irq_state vgic
+ * bitmap (this bitmap is updated by both user land ioctls and guest
+ * mmio ops, and other in-kernel peripherals such as the
+ * arch. timers) and indicate the 'wire' state.
+ * - Every time the bitmap changes, the irq_pending_on_cpu oracle is
+ * recalculated
+ * - To calculate the oracle, we need info for each cpu from
+ * compute_pending_for_cpu, which considers:
+ * - PPI: dist->irq_state & dist->irq_enable
+ * - SPI: dist->irq_state & dist->irq_enable & dist->irq_spi_target
+ * - irq_spi_target is a 'formatted' version of the GICD_ICFGR
+ * registers, stored on each vcpu. We only keep one bit of
+ * information per interrupt, making sure that only one vcpu can
+ * accept the interrupt.
+ * - The same is true when injecting an interrupt, except that we only
+ * consider a single interrupt at a time. The irq_spi_cpu array
+ * contains the target CPU for each SPI.
+ *
+ * The handling of level interrupts adds some extra complexity. We
+ * need to track when the interrupt has been EOIed, so we can sample
+ * the 'line' again. This is achieved as such:
+ *
+ * - When a level interrupt is moved onto a vcpu, the corresponding
+ * bit in irq_active is set. As long as this bit is set, the line
+ * will be ignored for further interrupts. The interrupt is injected
+ * into the vcpu with the GICH_LR_EOI bit set (generate a
+ * maintenance interrupt on EOI).
+ * - When the interrupt is EOIed, the maintenance interrupt fires,
+ * and clears the corresponding bit in irq_active. This allow the
+ * interrupt line to be sampled again.
+ */
+
+#define VGIC_ADDR_UNDEF (-1)
+#define IS_VGIC_ADDR_UNDEF(_x) ((_x) == VGIC_ADDR_UNDEF)
+
+/* Physical address of vgic virtual cpu interface */
+static phys_addr_t vgic_vcpu_base;
+
+/* Virtual control interface base address */
+static void __iomem *vgic_vctrl_base;
+
+static struct device_node *vgic_node;
+
+#define ACCESS_READ_VALUE (1 << 0)
+#define ACCESS_READ_RAZ (0 << 0)
+#define ACCESS_READ_MASK(x) ((x) & (1 << 0))
+#define ACCESS_WRITE_IGNORED (0 << 1)
+#define ACCESS_WRITE_SETBIT (1 << 1)
+#define ACCESS_WRITE_CLEARBIT (2 << 1)
+#define ACCESS_WRITE_VALUE (3 << 1)
+#define ACCESS_WRITE_MASK(x) ((x) & (3 << 1))
+
+static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu);
+static void vgic_update_state(struct kvm *kvm);
+static void vgic_kick_vcpus(struct kvm *kvm);
+static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg);
+static u32 vgic_nr_lr;
+
+static unsigned int vgic_maint_irq;
+
+static u32 *vgic_bitmap_get_reg(struct vgic_bitmap *x,
+ int cpuid, u32 offset)
+{
+ offset >>= 2;
+ if (!offset)
+ return x->percpu[cpuid].reg;
+ else
+ return x->shared.reg + offset - 1;
+}
+
+static int vgic_bitmap_get_irq_val(struct vgic_bitmap *x,
+ int cpuid, int irq)
+{
+ if (irq < VGIC_NR_PRIVATE_IRQS)
+ return test_bit(irq, x->percpu[cpuid].reg_ul);
+
+ return test_bit(irq - VGIC_NR_PRIVATE_IRQS, x->shared.reg_ul);
+}
+
+static void vgic_bitmap_set_irq_val(struct vgic_bitmap *x, int cpuid,
+ int irq, int val)
+{
+ unsigned long *reg;
+
+ if (irq < VGIC_NR_PRIVATE_IRQS) {
+ reg = x->percpu[cpuid].reg_ul;
+ } else {
+ reg = x->shared.reg_ul;
+ irq -= VGIC_NR_PRIVATE_IRQS;
+ }
+
+ if (val)
+ set_bit(irq, reg);
+ else
+ clear_bit(irq, reg);
+}
+
+static unsigned long *vgic_bitmap_get_cpu_map(struct vgic_bitmap *x, int cpuid)
+{
+ if (unlikely(cpuid >= VGIC_MAX_CPUS))
+ return NULL;
+ return x->percpu[cpuid].reg_ul;
+}
+
+static unsigned long *vgic_bitmap_get_shared_map(struct vgic_bitmap *x)
+{
+ return x->shared.reg_ul;
+}
+
+static u32 *vgic_bytemap_get_reg(struct vgic_bytemap *x, int cpuid, u32 offset)
+{
+ offset >>= 2;
+ BUG_ON(offset > (VGIC_NR_IRQS / 4));
+ if (offset < 4)
+ return x->percpu[cpuid] + offset;
+ else
+ return x->shared + offset - 8;
+}
+
+#define VGIC_CFG_LEVEL 0
+#define VGIC_CFG_EDGE 1
+
+static bool vgic_irq_is_edge(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ int irq_val;
+
+ irq_val = vgic_bitmap_get_irq_val(&dist->irq_cfg, vcpu->vcpu_id, irq);
+ return irq_val == VGIC_CFG_EDGE;
+}
+
+static int vgic_irq_is_enabled(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+ return vgic_bitmap_get_irq_val(&dist->irq_enabled, vcpu->vcpu_id, irq);
+}
+
+static int vgic_irq_is_active(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+ return vgic_bitmap_get_irq_val(&dist->irq_active, vcpu->vcpu_id, irq);
+}
+
+static void vgic_irq_set_active(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+ vgic_bitmap_set_irq_val(&dist->irq_active, vcpu->vcpu_id, irq, 1);
+}
+
+static void vgic_irq_clear_active(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+ vgic_bitmap_set_irq_val(&dist->irq_active, vcpu->vcpu_id, irq, 0);
+}
+
+static int vgic_dist_irq_is_pending(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+ return vgic_bitmap_get_irq_val(&dist->irq_state, vcpu->vcpu_id, irq);
+}
+
+static void vgic_dist_irq_set(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+ vgic_bitmap_set_irq_val(&dist->irq_state, vcpu->vcpu_id, irq, 1);
+}
+
+static void vgic_dist_irq_clear(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+ vgic_bitmap_set_irq_val(&dist->irq_state, vcpu->vcpu_id, irq, 0);
+}
+
+static void vgic_cpu_irq_set(struct kvm_vcpu *vcpu, int irq)
+{
+ if (irq < VGIC_NR_PRIVATE_IRQS)
+ set_bit(irq, vcpu->arch.vgic_cpu.pending_percpu);
+ else
+ set_bit(irq - VGIC_NR_PRIVATE_IRQS,
+ vcpu->arch.vgic_cpu.pending_shared);
+}
+
+static void vgic_cpu_irq_clear(struct kvm_vcpu *vcpu, int irq)
+{
+ if (irq < VGIC_NR_PRIVATE_IRQS)
+ clear_bit(irq, vcpu->arch.vgic_cpu.pending_percpu);
+ else
+ clear_bit(irq - VGIC_NR_PRIVATE_IRQS,
+ vcpu->arch.vgic_cpu.pending_shared);
+}
+
+static u32 mmio_data_read(struct kvm_exit_mmio *mmio, u32 mask)
+{
+ return *((u32 *)mmio->data) & mask;
+}
+
+static void mmio_data_write(struct kvm_exit_mmio *mmio, u32 mask, u32 value)
+{
+ *((u32 *)mmio->data) = value & mask;
+}
+
+/**
+ * vgic_reg_access - access vgic register
+ * @mmio: pointer to the data describing the mmio access
+ * @reg: pointer to the virtual backing of vgic distributor data
+ * @offset: least significant 2 bits used for word offset
+ * @mode: ACCESS_ mode (see defines above)
+ *
+ * Helper to make vgic register access easier using one of the access
+ * modes defined for vgic register access
+ * (read,raz,write-ignored,setbit,clearbit,write)
+ */
+static void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
+ phys_addr_t offset, int mode)
+{
+ int word_offset = (offset & 3) * 8;
+ u32 mask = (1UL << (mmio->len * 8)) - 1;
+ u32 regval;
+
+ /*
+ * Any alignment fault should have been delivered to the guest
+ * directly (ARM ARM B3.12.7 "Prioritization of aborts").
+ */
+
+ if (reg) {
+ regval = *reg;
+ } else {
+ BUG_ON(mode != (ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED));
+ regval = 0;
+ }
+
+ if (mmio->is_write) {
+ u32 data = mmio_data_read(mmio, mask) << word_offset;
+ switch (ACCESS_WRITE_MASK(mode)) {
+ case ACCESS_WRITE_IGNORED:
+ return;
+
+ case ACCESS_WRITE_SETBIT:
+ regval |= data;
+ break;
+
+ case ACCESS_WRITE_CLEARBIT:
+ regval &= ~data;
+ break;
+
+ case ACCESS_WRITE_VALUE:
+ regval = (regval & ~(mask << word_offset)) | data;
+ break;
+ }
+ *reg = regval;
+ } else {
+ switch (ACCESS_READ_MASK(mode)) {
+ case ACCESS_READ_RAZ:
+ regval = 0;
+ /* fall through */
+
+ case ACCESS_READ_VALUE:
+ mmio_data_write(mmio, mask, regval >> word_offset);
+ }
+ }
+}
+
+static bool handle_mmio_misc(struct kvm_vcpu *vcpu,
+ struct kvm_exit_mmio *mmio, phys_addr_t offset)
+{
+ u32 reg;
+ u32 word_offset = offset & 3;
+
+ switch (offset & ~3) {
+ case 0: /* CTLR */
+ reg = vcpu->kvm->arch.vgic.enabled;
+ vgic_reg_access(mmio, &reg, word_offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
+ if (mmio->is_write) {
+ vcpu->kvm->arch.vgic.enabled = reg & 1;
+ vgic_update_state(vcpu->kvm);
+ return true;
+ }
+ break;
+
+ case 4: /* TYPER */
+ reg = (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
+ reg |= (VGIC_NR_IRQS >> 5) - 1;
+ vgic_reg_access(mmio, &reg, word_offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
+ break;
+
+ case 8: /* IIDR */
+ reg = 0x4B00043B;
+ vgic_reg_access(mmio, &reg, word_offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
+ break;
+ }
+
+ return false;
+}
+
+static bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu,
+ struct kvm_exit_mmio *mmio, phys_addr_t offset)
+{
+ vgic_reg_access(mmio, NULL, offset,
+ ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
+ return false;
+}
+
+static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu,
+ struct kvm_exit_mmio *mmio,
+ phys_addr_t offset)
+{
+ u32 *reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_enabled,
+ vcpu->vcpu_id, offset);
+ vgic_reg_access(mmio, reg, offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT);
+ if (mmio->is_write) {
+ vgic_update_state(vcpu->kvm);
+ return true;
+ }
+
+ return false;
+}
+
+static bool handle_mmio_clear_enable_reg(struct kvm_vcpu *vcpu,
+ struct kvm_exit_mmio *mmio,
+ phys_addr_t offset)
+{
+ u32 *reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_enabled,
+ vcpu->vcpu_id, offset);
+ vgic_reg_access(mmio, reg, offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT);
+ if (mmio->is_write) {
+ if (offset < 4) /* Force SGI enabled */
+ *reg |= 0xffff;
+ vgic_retire_disabled_irqs(vcpu);
+ vgic_update_state(vcpu->kvm);
+ return true;
+ }
+
+ return false;
+}
+
+static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu,
+ struct kvm_exit_mmio *mmio,
+ phys_addr_t offset)
+{
+ u32 *reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_state,
+ vcpu->vcpu_id, offset);
+ vgic_reg_access(mmio, reg, offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT);
+ if (mmio->is_write) {
+ vgic_update_state(vcpu->kvm);
+ return true;
+ }
+
+ return false;
+}
+
+static bool handle_mmio_clear_pending_reg(struct kvm_vcpu *vcpu,
+ struct kvm_exit_mmio *mmio,
+ phys_addr_t offset)
+{
+ u32 *reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_state,
+ vcpu->vcpu_id, offset);
+ vgic_reg_access(mmio, reg, offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT);
+ if (mmio->is_write) {
+ vgic_update_state(vcpu->kvm);
+ return true;
+ }
+
+ return false;
+}
+
+static bool handle_mmio_priority_reg(struct kvm_vcpu *vcpu,
+ struct kvm_exit_mmio *mmio,
+ phys_addr_t offset)
+{
+ u32 *reg = vgic_bytemap_get_reg(&vcpu->kvm->arch.vgic.irq_priority,
+ vcpu->vcpu_id, offset);
+ vgic_reg_access(mmio, reg, offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
+ return false;
+}
+
+#define GICD_ITARGETSR_SIZE 32
+#define GICD_CPUTARGETS_BITS 8
+#define GICD_IRQS_PER_ITARGETSR (GICD_ITARGETSR_SIZE / GICD_CPUTARGETS_BITS)
+static u32 vgic_get_target_reg(struct kvm *kvm, int irq)
+{
+ struct vgic_dist *dist = &kvm->arch.vgic;
+ struct kvm_vcpu *vcpu;
+ int i, c;
+ unsigned long *bmap;
+ u32 val = 0;
+
+ irq -= VGIC_NR_PRIVATE_IRQS;
+
+ kvm_for_each_vcpu(c, vcpu, kvm) {
+ bmap = vgic_bitmap_get_shared_map(&dist->irq_spi_target[c]);
+ for (i = 0; i < GICD_IRQS_PER_ITARGETSR; i++)
+ if (test_bit(irq + i, bmap))
+ val |= 1 << (c + i * 8);
+ }
+
+ return val;
+}
+
+static void vgic_set_target_reg(struct kvm *kvm, u32 val, int irq)
+{
+ struct vgic_dist *dist = &kvm->arch.vgic;
+ struct kvm_vcpu *vcpu;
+ int i, c;
+ unsigned long *bmap;
+ u32 target;
+
+ irq -= VGIC_NR_PRIVATE_IRQS;
+
+ /*
+ * Pick the LSB in each byte. This ensures we target exactly
+ * one vcpu per IRQ. If the byte is null, assume we target
+ * CPU0.
+ */
+ for (i = 0; i < GICD_IRQS_PER_ITARGETSR; i++) {
+ int shift = i * GICD_CPUTARGETS_BITS;
+ target = ffs((val >> shift) & 0xffU);
+ target = target ? (target - 1) : 0;
+ dist->irq_spi_cpu[irq + i] = target;
+ kvm_for_each_vcpu(c, vcpu, kvm) {
+ bmap = vgic_bitmap_get_shared_map(&dist->irq_spi_target[c]);
+ if (c == target)
+ set_bit(irq + i, bmap);
+ else
+ clear_bit(irq + i, bmap);
+ }
+ }
+}
+
+static bool handle_mmio_target_reg(struct kvm_vcpu *vcpu,
+ struct kvm_exit_mmio *mmio,
+ phys_addr_t offset)
+{
+ u32 reg;
+
+ /* We treat the banked interrupts targets as read-only */
+ if (offset < 32) {
+ u32 roreg = 1 << vcpu->vcpu_id;
+ roreg |= roreg << 8;
+ roreg |= roreg << 16;
+
+ vgic_reg_access(mmio, &roreg, offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
+ return false;
+ }
+
+ reg = vgic_get_target_reg(vcpu->kvm, offset & ~3U);
+ vgic_reg_access(mmio, &reg, offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
+ if (mmio->is_write) {
+ vgic_set_target_reg(vcpu->kvm, reg, offset & ~3U);
+ vgic_update_state(vcpu->kvm);
+ return true;
+ }
+
+ return false;
+}
+
+static u32 vgic_cfg_expand(u16 val)
+{
+ u32 res = 0;
+ int i;
+
+ /*
+ * Turn a 16bit value like abcd...mnop into a 32bit word
+ * a0b0c0d0...m0n0o0p0, which is what the HW cfg register is.
+ */
+ for (i = 0; i < 16; i++)
+ res |= ((val >> i) & VGIC_CFG_EDGE) << (2 * i + 1);
+
+ return res;
+}
+
+static u16 vgic_cfg_compress(u32 val)
+{
+ u16 res = 0;
+ int i;
+
+ /*
+ * Turn a 32bit word a0b0c0d0...m0n0o0p0 into 16bit value like
+ * abcd...mnop which is what we really care about.
+ */
+ for (i = 0; i < 16; i++)
+ res |= ((val >> (i * 2 + 1)) & VGIC_CFG_EDGE) << i;
+
+ return res;
+}
+
+/*
+ * The distributor uses 2 bits per IRQ for the CFG register, but the
+ * LSB is always 0. As such, we only keep the upper bit, and use the
+ * two above functions to compress/expand the bits
+ */
+static bool handle_mmio_cfg_reg(struct kvm_vcpu *vcpu,
+ struct kvm_exit_mmio *mmio, phys_addr_t offset)
+{
+ u32 val;
+ u32 *reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_cfg,
+ vcpu->vcpu_id, offset >> 1);
+ if (offset & 2)
+ val = *reg >> 16;
+ else
+ val = *reg & 0xffff;
+
+ val = vgic_cfg_expand(val);
+ vgic_reg_access(mmio, &val, offset,
+ ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
+ if (mmio->is_write) {
+ if (offset < 4) {
+ *reg = ~0U; /* Force PPIs/SGIs to 1 */
+ return false;
+ }
+
+ val = vgic_cfg_compress(val);
+ if (offset & 2) {
+ *reg &= 0xffff;
+ *reg |= val << 16;
+ } else {
+ *reg &= 0xffff << 16;
+ *reg |= val;
+ }
+ }
+
+ return false;
+}
+
+static bool handle_mmio_sgi_reg(struct kvm_vcpu *vcpu,
+ struct kvm_exit_mmio *mmio, phys_addr_t offset)
+{
+ u32 reg;
+ vgic_reg_access(mmio, &reg, offset,
+ ACCESS_READ_RAZ | ACCESS_WRITE_VALUE);
+ if (mmio->is_write) {
+ vgic_dispatch_sgi(vcpu, reg);
+ vgic_update_state(vcpu->kvm);
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * I would have liked to use the kvm_bus_io_*() API instead, but it
+ * cannot cope with banked registers (only the VM pointer is passed
+ * around, and we need the vcpu). One of these days, someone please
+ * fix it!
+ */
+struct mmio_range {
+ phys_addr_t base;
+ unsigned long len;
+ bool (*handle_mmio)(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
+ phys_addr_t offset);
+};
+
+static const struct mmio_range vgic_ranges[] = {
+ {
+ .base = GIC_DIST_CTRL,
+ .len = 12,
+ .handle_mmio = handle_mmio_misc,
+ },
+ {
+ .base = GIC_DIST_IGROUP,
+ .len = VGIC_NR_IRQS / 8,
+ .handle_mmio = handle_mmio_raz_wi,
+ },
+ {
+ .base = GIC_DIST_ENABLE_SET,
+ .len = VGIC_NR_IRQS / 8,
+ .handle_mmio = handle_mmio_set_enable_reg,
+ },
+ {
+ .base = GIC_DIST_ENABLE_CLEAR,
+ .len = VGIC_NR_IRQS / 8,
+ .handle_mmio = handle_mmio_clear_enable_reg,
+ },
+ {
+ .base = GIC_DIST_PENDING_SET,
+ .len = VGIC_NR_IRQS / 8,
+ .handle_mmio = handle_mmio_set_pending_reg,
+ },
+ {
+ .base = GIC_DIST_PENDING_CLEAR,
+ .len = VGIC_NR_IRQS / 8,
+ .handle_mmio = handle_mmio_clear_pending_reg,
+ },
+ {
+ .base = GIC_DIST_ACTIVE_SET,
+ .len = VGIC_NR_IRQS / 8,
+ .handle_mmio = handle_mmio_raz_wi,
+ },
+ {
+ .base = GIC_DIST_ACTIVE_CLEAR,
+ .len = VGIC_NR_IRQS / 8,
+ .handle_mmio = handle_mmio_raz_wi,
+ },
+ {
+ .base = GIC_DIST_PRI,
+ .len = VGIC_NR_IRQS,
+ .handle_mmio = handle_mmio_priority_reg,
+ },
+ {
+ .base = GIC_DIST_TARGET,
+ .len = VGIC_NR_IRQS,
+ .handle_mmio = handle_mmio_target_reg,
+ },
+ {
+ .base = GIC_DIST_CONFIG,
+ .len = VGIC_NR_IRQS / 4,
+ .handle_mmio = handle_mmio_cfg_reg,
+ },
+ {
+ .base = GIC_DIST_SOFTINT,
+ .len = 4,
+ .handle_mmio = handle_mmio_sgi_reg,
+ },
+ {}
+};
+
+static const
+struct mmio_range *find_matching_range(const struct mmio_range *ranges,
+ struct kvm_exit_mmio *mmio,
+ phys_addr_t base)
+{
+ const struct mmio_range *r = ranges;
+ phys_addr_t addr = mmio->phys_addr - base;
+
+ while (r->len) {
+ if (addr >= r->base &&
+ (addr + mmio->len) <= (r->base + r->len))
+ return r;
+ r++;
+ }
+
+ return NULL;
+}
+
+/**
+ * vgic_handle_mmio - handle an in-kernel MMIO access
+ * @vcpu: pointer to the vcpu performing the access
+ * @run: pointer to the kvm_run structure
+ * @mmio: pointer to the data describing the access
+ *
+ * returns true if the MMIO access has been performed in kernel space,
+ * and false if it needs to be emulated in user space.
+ */
+bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ struct kvm_exit_mmio *mmio)
+{
+ const struct mmio_range *range;
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ unsigned long base = dist->vgic_dist_base;
+ bool updated_state;
+ unsigned long offset;
+
+ if (!irqchip_in_kernel(vcpu->kvm) ||
+ mmio->phys_addr < base ||
+ (mmio->phys_addr + mmio->len) > (base + KVM_VGIC_V2_DIST_SIZE))
+ return false;
+
+ /* We don't support ldrd / strd or ldm / stm to the emulated vgic */
+ if (mmio->len > 4) {
+ kvm_inject_dabt(vcpu, mmio->phys_addr);
+ return true;
+ }
+
+ range = find_matching_range(vgic_ranges, mmio, base);
+ if (unlikely(!range || !range->handle_mmio)) {
+ pr_warn("Unhandled access %d %08llx %d\n",
+ mmio->is_write, mmio->phys_addr, mmio->len);
+ return false;
+ }
+
+ spin_lock(&vcpu->kvm->arch.vgic.lock);
+ offset = mmio->phys_addr - range->base - base;
+ updated_state = range->handle_mmio(vcpu, mmio, offset);
+ spin_unlock(&vcpu->kvm->arch.vgic.lock);
+ kvm_prepare_mmio(run, mmio);
+ kvm_handle_mmio_return(vcpu, run);
+
+ if (updated_state)
+ vgic_kick_vcpus(vcpu->kvm);
+
+ return true;
+}
+
+static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg)
+{
+ struct kvm *kvm = vcpu->kvm;
+ struct vgic_dist *dist = &kvm->arch.vgic;
+ int nrcpus = atomic_read(&kvm->online_vcpus);
+ u8 target_cpus;
+ int sgi, mode, c, vcpu_id;
+
+ vcpu_id = vcpu->vcpu_id;
+
+ sgi = reg & 0xf;
+ target_cpus = (reg >> 16) & 0xff;
+ mode = (reg >> 24) & 3;
+
+ switch (mode) {
+ case 0:
+ if (!target_cpus)
+ return;
+
+ case 1:
+ target_cpus = ((1 << nrcpus) - 1) & ~(1 << vcpu_id) & 0xff;
+ break;
+
+ case 2:
+ target_cpus = 1 << vcpu_id;
+ break;
+ }
+
+ kvm_for_each_vcpu(c, vcpu, kvm) {
+ if (target_cpus & 1) {
+ /* Flag the SGI as pending */
+ vgic_dist_irq_set(vcpu, sgi);
+ dist->irq_sgi_sources[c][sgi] |= 1 << vcpu_id;
+ kvm_debug("SGI%d from CPU%d to CPU%d\n", sgi, vcpu_id, c);
+ }
+
+ target_cpus >>= 1;
+ }
+}
+
+static int compute_pending_for_cpu(struct kvm_vcpu *vcpu)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ unsigned long *pending, *enabled, *pend_percpu, *pend_shared;
+ unsigned long pending_private, pending_shared;
+ int vcpu_id;
+
+ vcpu_id = vcpu->vcpu_id;
+ pend_percpu = vcpu->arch.vgic_cpu.pending_percpu;
+ pend_shared = vcpu->arch.vgic_cpu.pending_shared;
+
+ pending = vgic_bitmap_get_cpu_map(&dist->irq_state, vcpu_id);
+ enabled = vgic_bitmap_get_cpu_map(&dist->irq_enabled, vcpu_id);
+ bitmap_and(pend_percpu, pending, enabled, VGIC_NR_PRIVATE_IRQS);
+
+ pending = vgic_bitmap_get_shared_map(&dist->irq_state);
+ enabled = vgic_bitmap_get_shared_map(&dist->irq_enabled);
+ bitmap_and(pend_shared, pending, enabled, VGIC_NR_SHARED_IRQS);
+ bitmap_and(pend_shared, pend_shared,
+ vgic_bitmap_get_shared_map(&dist->irq_spi_target[vcpu_id]),
+ VGIC_NR_SHARED_IRQS);
+
+ pending_private = find_first_bit(pend_percpu, VGIC_NR_PRIVATE_IRQS);
+ pending_shared = find_first_bit(pend_shared, VGIC_NR_SHARED_IRQS);
+ return (pending_private < VGIC_NR_PRIVATE_IRQS ||
+ pending_shared < VGIC_NR_SHARED_IRQS);
+}
+
+/*
+ * Update the interrupt state and determine which CPUs have pending
+ * interrupts. Must be called with distributor lock held.
+ */
+static void vgic_update_state(struct kvm *kvm)
+{
+ struct vgic_dist *dist = &kvm->arch.vgic;
+ struct kvm_vcpu *vcpu;
+ int c;
+
+ if (!dist->enabled) {
+ set_bit(0, &dist->irq_pending_on_cpu);
+ return;
+ }
+
+ kvm_for_each_vcpu(c, vcpu, kvm) {
+ if (compute_pending_for_cpu(vcpu)) {
+ pr_debug("CPU%d has pending interrupts\n", c);
+ set_bit(c, &dist->irq_pending_on_cpu);
+ }
+ }
+}
+
+#define LR_CPUID(lr) \
+ (((lr) & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT)
+#define MK_LR_PEND(src, irq) \
+ (GICH_LR_PENDING_BIT | ((src) << GICH_LR_PHYSID_CPUID_SHIFT) | (irq))
+
+/*
+ * An interrupt may have been disabled after being made pending on the
+ * CPU interface (the classic case is a timer running while we're
+ * rebooting the guest - the interrupt would kick as soon as the CPU
+ * interface gets enabled, with deadly consequences).
+ *
+ * The solution is to examine already active LRs, and check the
+ * interrupt is still enabled. If not, just retire it.
+ */
+static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+ int lr;
+
+ for_each_set_bit(lr, vgic_cpu->lr_used, vgic_cpu->nr_lr) {
+ int irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID;
+
+ if (!vgic_irq_is_enabled(vcpu, irq)) {
+ vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
+ clear_bit(lr, vgic_cpu->lr_used);
+ vgic_cpu->vgic_lr[lr] &= ~GICH_LR_STATE;
+ if (vgic_irq_is_active(vcpu, irq))
+ vgic_irq_clear_active(vcpu, irq);
+ }
+ }
+}
+
+/*
+ * Queue an interrupt to a CPU virtual interface. Return true on success,
+ * or false if it wasn't possible to queue it.
+ */
+static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+ int lr;
+
+ /* Sanitize the input... */
+ BUG_ON(sgi_source_id & ~7);
+ BUG_ON(sgi_source_id && irq >= VGIC_NR_SGIS);
+ BUG_ON(irq >= VGIC_NR_IRQS);
+
+ kvm_debug("Queue IRQ%d\n", irq);
+
+ lr = vgic_cpu->vgic_irq_lr_map[irq];
+
+ /* Do we have an active interrupt for the same CPUID? */
+ if (lr != LR_EMPTY &&
+ (LR_CPUID(vgic_cpu->vgic_lr[lr]) == sgi_source_id)) {
+ kvm_debug("LR%d piggyback for IRQ%d %x\n",
+ lr, irq, vgic_cpu->vgic_lr[lr]);
+ BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
+ vgic_cpu->vgic_lr[lr] |= GICH_LR_PENDING_BIT;
+
+ goto out;
+ }
+
+ /* Try to use another LR for this interrupt */
+ lr = find_first_zero_bit((unsigned long *)vgic_cpu->lr_used,
+ vgic_cpu->nr_lr);
+ if (lr >= vgic_cpu->nr_lr)
+ return false;
+
+ kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id);
+ vgic_cpu->vgic_lr[lr] = MK_LR_PEND(sgi_source_id, irq);
+ vgic_cpu->vgic_irq_lr_map[irq] = lr;
+ set_bit(lr, vgic_cpu->lr_used);
+
+out:
+ if (!vgic_irq_is_edge(vcpu, irq))
+ vgic_cpu->vgic_lr[lr] |= GICH_LR_EOI;
+
+ return true;
+}
+
+static bool vgic_queue_sgi(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ unsigned long sources;
+ int vcpu_id = vcpu->vcpu_id;
+ int c;
+
+ sources = dist->irq_sgi_sources[vcpu_id][irq];
+
+ for_each_set_bit(c, &sources, VGIC_MAX_CPUS) {
+ if (vgic_queue_irq(vcpu, c, irq))
+ clear_bit(c, &sources);
+ }
+
+ dist->irq_sgi_sources[vcpu_id][irq] = sources;
+
+ /*
+ * If the sources bitmap has been cleared it means that we
+ * could queue all the SGIs onto link registers (see the
+ * clear_bit above), and therefore we are done with them in
+ * our emulated gic and can get rid of them.
+ */
+ if (!sources) {
+ vgic_dist_irq_clear(vcpu, irq);
+ vgic_cpu_irq_clear(vcpu, irq);
+ return true;
+ }
+
+ return false;
+}
+
+static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq)
+{
+ if (vgic_irq_is_active(vcpu, irq))
+ return true; /* level interrupt, already queued */
+
+ if (vgic_queue_irq(vcpu, 0, irq)) {
+ if (vgic_irq_is_edge(vcpu, irq)) {
+ vgic_dist_irq_clear(vcpu, irq);
+ vgic_cpu_irq_clear(vcpu, irq);
+ } else {
+ vgic_irq_set_active(vcpu, irq);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Fill the list registers with pending interrupts before running the
+ * guest.
+ */
+static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ int i, vcpu_id;
+ int overflow = 0;
+
+ vcpu_id = vcpu->vcpu_id;
+
+ /*
+ * We may not have any pending interrupt, or the interrupts
+ * may have been serviced from another vcpu. In all cases,
+ * move along.
+ */
+ if (!kvm_vgic_vcpu_pending_irq(vcpu)) {
+ pr_debug("CPU%d has no pending interrupt\n", vcpu_id);
+ goto epilog;
+ }
+
+ /* SGIs */
+ for_each_set_bit(i, vgic_cpu->pending_percpu, VGIC_NR_SGIS) {
+ if (!vgic_queue_sgi(vcpu, i))
+ overflow = 1;
+ }
+
+ /* PPIs */
+ for_each_set_bit_from(i, vgic_cpu->pending_percpu, VGIC_NR_PRIVATE_IRQS) {
+ if (!vgic_queue_hwirq(vcpu, i))
+ overflow = 1;
+ }
+
+ /* SPIs */
+ for_each_set_bit(i, vgic_cpu->pending_shared, VGIC_NR_SHARED_IRQS) {
+ if (!vgic_queue_hwirq(vcpu, i + VGIC_NR_PRIVATE_IRQS))
+ overflow = 1;
+ }
+
+epilog:
+ if (overflow) {
+ vgic_cpu->vgic_hcr |= GICH_HCR_UIE;
+ } else {
+ vgic_cpu->vgic_hcr &= ~GICH_HCR_UIE;
+ /*
+ * We're about to run this VCPU, and we've consumed
+ * everything the distributor had in store for
+ * us. Claim we don't have anything pending. We'll
+ * adjust that if needed while exiting.
+ */
+ clear_bit(vcpu_id, &dist->irq_pending_on_cpu);
+ }
+}
+
+static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+ bool level_pending = false;
+
+ kvm_debug("MISR = %08x\n", vgic_cpu->vgic_misr);
+
+ /*
+ * We do not need to take the distributor lock here, since the only
+ * action we perform is clearing the irq_active_bit for an EOIed
+ * level interrupt. There is a potential race with
+ * the queuing of an interrupt in __kvm_vgic_flush_hwstate(), where we
+ * check if the interrupt is already active. Two possibilities:
+ *
+ * - The queuing is occurring on the same vcpu: cannot happen,
+ * as we're already in the context of this vcpu, and
+ * executing the handler
+ * - The interrupt has been migrated to another vcpu, and we
+ * ignore this interrupt for this run. Big deal. It is still
+ * pending though, and will get considered when this vcpu
+ * exits.
+ */
+ if (vgic_cpu->vgic_misr & GICH_MISR_EOI) {
+ /*
+ * Some level interrupts have been EOIed. Clear their
+ * active bit.
+ */
+ int lr, irq;
+
+ for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_eisr,
+ vgic_cpu->nr_lr) {
+ irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID;
+
+ vgic_irq_clear_active(vcpu, irq);
+ vgic_cpu->vgic_lr[lr] &= ~GICH_LR_EOI;
+
+ /* Any additional pending interrupt? */
+ if (vgic_dist_irq_is_pending(vcpu, irq)) {
+ vgic_cpu_irq_set(vcpu, irq);
+ level_pending = true;
+ } else {
+ vgic_cpu_irq_clear(vcpu, irq);
+ }
+ }
+ }
+
+ if (vgic_cpu->vgic_misr & GICH_MISR_U)
+ vgic_cpu->vgic_hcr &= ~GICH_HCR_UIE;
+
+ return level_pending;
+}
+
+/*
+ * Sync back the VGIC state after a guest run. We do not really touch
+ * the distributor here (the irq_pending_on_cpu bit is safe to set),
+ * so there is no need for taking its lock.
+ */
+static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ int lr, pending;
+ bool level_pending;
+
+ level_pending = vgic_process_maintenance(vcpu);
+
+ /* Clear mappings for empty LRs */
+ for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_elrsr,
+ vgic_cpu->nr_lr) {
+ int irq;
+
+ if (!test_and_clear_bit(lr, vgic_cpu->lr_used))
+ continue;
+
+ irq = vgic_cpu->vgic_lr[lr] & GICH_LR_VIRTUALID;
+
+ BUG_ON(irq >= VGIC_NR_IRQS);
+ vgic_cpu->vgic_irq_lr_map[irq] = LR_EMPTY;
+ }
+
+ /* Check if we still have something up our sleeve... */
+ pending = find_first_zero_bit((unsigned long *)vgic_cpu->vgic_elrsr,
+ vgic_cpu->nr_lr);
+ if (level_pending || pending < vgic_cpu->nr_lr)
+ set_bit(vcpu->vcpu_id, &dist->irq_pending_on_cpu);
+}
+
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+ if (!irqchip_in_kernel(vcpu->kvm))
+ return;
+
+ spin_lock(&dist->lock);
+ __kvm_vgic_flush_hwstate(vcpu);
+ spin_unlock(&dist->lock);
+}
+
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
+{
+ if (!irqchip_in_kernel(vcpu->kvm))
+ return;
+
+ __kvm_vgic_sync_hwstate(vcpu);
+}
+
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+ if (!irqchip_in_kernel(vcpu->kvm))
+ return 0;
+
+ return test_bit(vcpu->vcpu_id, &dist->irq_pending_on_cpu);
+}
+
+static void vgic_kick_vcpus(struct kvm *kvm)
+{
+ struct kvm_vcpu *vcpu;
+ int c;
+
+ /*
+ * We've injected an interrupt, time to find out who deserves
+ * a good kick...
+ */
+ kvm_for_each_vcpu(c, vcpu, kvm) {
+ if (kvm_vgic_vcpu_pending_irq(vcpu))
+ kvm_vcpu_kick(vcpu);
+ }
+}
+
+static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level)
+{
+ int is_edge = vgic_irq_is_edge(vcpu, irq);
+ int state = vgic_dist_irq_is_pending(vcpu, irq);
+
+ /*
+ * Only inject an interrupt if:
+ * - edge triggered and we have a rising edge
+ * - level triggered and we change level
+ */
+ if (is_edge)
+ return level > state;
+ else
+ return level != state;
+}
+
+static bool vgic_update_irq_state(struct kvm *kvm, int cpuid,
+ unsigned int irq_num, bool level)
+{
+ struct vgic_dist *dist = &kvm->arch.vgic;
+ struct kvm_vcpu *vcpu;
+ int is_edge, is_level;
+ int enabled;
+ bool ret = true;
+
+ spin_lock(&dist->lock);
+
+ vcpu = kvm_get_vcpu(kvm, cpuid);
+ is_edge = vgic_irq_is_edge(vcpu, irq_num);
+ is_level = !is_edge;
+
+ if (!vgic_validate_injection(vcpu, irq_num, level)) {
+ ret = false;
+ goto out;
+ }
+
+ if (irq_num >= VGIC_NR_PRIVATE_IRQS) {
+ cpuid = dist->irq_spi_cpu[irq_num - VGIC_NR_PRIVATE_IRQS];
+ vcpu = kvm_get_vcpu(kvm, cpuid);
+ }
+
+ kvm_debug("Inject IRQ%d level %d CPU%d\n", irq_num, level, cpuid);
+
+ if (level)
+ vgic_dist_irq_set(vcpu, irq_num);
+ else
+ vgic_dist_irq_clear(vcpu, irq_num);
+
+ enabled = vgic_irq_is_enabled(vcpu, irq_num);
+
+ if (!enabled) {
+ ret = false;
+ goto out;
+ }
+
+ if (is_level && vgic_irq_is_active(vcpu, irq_num)) {
+ /*
+ * Level interrupt in progress, will be picked up
+ * when EOId.
+ */
+ ret = false;
+ goto out;
+ }
+
+ if (level) {
+ vgic_cpu_irq_set(vcpu, irq_num);
+ set_bit(cpuid, &dist->irq_pending_on_cpu);
+ }
+
+out:
+ spin_unlock(&dist->lock);
+
+ return ret;
+}
+
+/**
+ * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
+ * @kvm: The VM structure pointer
+ * @cpuid: The CPU for PPIs
+ * @irq_num: The IRQ number that is assigned to the device
+ * @level: Edge-triggered: true: to trigger the interrupt
+ * false: to ignore the call
+ * Level-sensitive true: activates an interrupt
+ * false: deactivates an interrupt
+ *
+ * The GIC is not concerned with devices being active-LOW or active-HIGH for
+ * level-sensitive interrupts. You can think of the level parameter as 1
+ * being HIGH and 0 being LOW and all devices being active-HIGH.
+ */
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
+ bool level)
+{
+ if (vgic_update_irq_state(kvm, cpuid, irq_num, level))
+ vgic_kick_vcpus(kvm);
+
+ return 0;
+}
+
+static irqreturn_t vgic_maintenance_handler(int irq, void *data)
+{
+ /*
+ * We cannot rely on the vgic maintenance interrupt to be
+ * delivered synchronously. This means we can only use it to
+ * exit the VM, and we perform the handling of EOIed
+ * interrupts on the exit path (see vgic_process_maintenance).
+ */
+ return IRQ_HANDLED;
+}
+
+int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+ int i;
+
+ if (!irqchip_in_kernel(vcpu->kvm))
+ return 0;
+
+ if (vcpu->vcpu_id >= VGIC_MAX_CPUS)
+ return -EBUSY;
+
+ for (i = 0; i < VGIC_NR_IRQS; i++) {
+ if (i < VGIC_NR_PPIS)
+ vgic_bitmap_set_irq_val(&dist->irq_enabled,
+ vcpu->vcpu_id, i, 1);
+ if (i < VGIC_NR_PRIVATE_IRQS)
+ vgic_bitmap_set_irq_val(&dist->irq_cfg,
+ vcpu->vcpu_id, i, VGIC_CFG_EDGE);
+
+ vgic_cpu->vgic_irq_lr_map[i] = LR_EMPTY;
+ }
+
+ /*
+ * By forcing VMCR to zero, the GIC will restore the binary
+ * points to their reset values. Anything else resets to zero
+ * anyway.
+ */
+ vgic_cpu->vgic_vmcr = 0;
+
+ vgic_cpu->nr_lr = vgic_nr_lr;
+ vgic_cpu->vgic_hcr = GICH_HCR_EN; /* Get the show on the road... */
+
+ return 0;
+}
+
+static void vgic_init_maintenance_interrupt(void *info)
+{
+ enable_percpu_irq(vgic_maint_irq, 0);
+}
+
+static int vgic_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *cpu)
+{
+ switch (action) {
+ case CPU_STARTING:
+ case CPU_STARTING_FROZEN:
+ vgic_init_maintenance_interrupt(NULL);
+ break;
+ case CPU_DYING:
+ case CPU_DYING_FROZEN:
+ disable_percpu_irq(vgic_maint_irq);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vgic_cpu_nb = {
+ .notifier_call = vgic_cpu_notify,
+};
+
+int kvm_vgic_hyp_init(void)
+{
+ int ret;
+ struct resource vctrl_res;
+ struct resource vcpu_res;
+
+ vgic_node = of_find_compatible_node(NULL, NULL, "arm,cortex-a15-gic");
+ if (!vgic_node) {
+ kvm_err("error: no compatible vgic node in DT\n");
+ return -ENODEV;
+ }
+
+ vgic_maint_irq = irq_of_parse_and_map(vgic_node, 0);
+ if (!vgic_maint_irq) {
+ kvm_err("error getting vgic maintenance irq from DT\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ ret = request_percpu_irq(vgic_maint_irq, vgic_maintenance_handler,
+ "vgic", kvm_get_running_vcpus());
+ if (ret) {
+ kvm_err("Cannot register interrupt %d\n", vgic_maint_irq);
+ goto out;
+ }
+
+ ret = register_cpu_notifier(&vgic_cpu_nb);
+ if (ret) {
+ kvm_err("Cannot register vgic CPU notifier\n");
+ goto out_free_irq;
+ }
+
+ ret = of_address_to_resource(vgic_node, 2, &vctrl_res);
+ if (ret) {
+ kvm_err("Cannot obtain VCTRL resource\n");
+ goto out_free_irq;
+ }
+
+ vgic_vctrl_base = of_iomap(vgic_node, 2);
+ if (!vgic_vctrl_base) {
+ kvm_err("Cannot ioremap VCTRL\n");
+ ret = -ENOMEM;
+ goto out_free_irq;
+ }
+
+ vgic_nr_lr = readl_relaxed(vgic_vctrl_base + GICH_VTR);
+ vgic_nr_lr = (vgic_nr_lr & 0x3f) + 1;
+
+ ret = create_hyp_io_mappings(vgic_vctrl_base,
+ vgic_vctrl_base + resource_size(&vctrl_res),
+ vctrl_res.start);
+ if (ret) {
+ kvm_err("Cannot map VCTRL into hyp\n");
+ goto out_unmap;
+ }
+
+ kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
+ vctrl_res.start, vgic_maint_irq);
+ on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
+
+ if (of_address_to_resource(vgic_node, 3, &vcpu_res)) {
+ kvm_err("Cannot obtain VCPU resource\n");
+ ret = -ENXIO;
+ goto out_unmap;
+ }
+ vgic_vcpu_base = vcpu_res.start;
+
+ goto out;
+
+out_unmap:
+ iounmap(vgic_vctrl_base);
+out_free_irq:
+ free_percpu_irq(vgic_maint_irq, kvm_get_running_vcpus());
+out:
+ of_node_put(vgic_node);
+ return ret;
+}
+
+int kvm_vgic_init(struct kvm *kvm)
+{
+ int ret = 0, i;
+
+ mutex_lock(&kvm->lock);
+
+ if (vgic_initialized(kvm))
+ goto out;
+
+ if (IS_VGIC_ADDR_UNDEF(kvm->arch.vgic.vgic_dist_base) ||
+ IS_VGIC_ADDR_UNDEF(kvm->arch.vgic.vgic_cpu_base)) {
+ kvm_err("Need to set vgic cpu and dist addresses first\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ ret = kvm_phys_addr_ioremap(kvm, kvm->arch.vgic.vgic_cpu_base,
+ vgic_vcpu_base, KVM_VGIC_V2_CPU_SIZE);
+ if (ret) {
+ kvm_err("Unable to remap VGIC CPU to VCPU\n");
+ goto out;
+ }
+
+ for (i = VGIC_NR_PRIVATE_IRQS; i < VGIC_NR_IRQS; i += 4)
+ vgic_set_target_reg(kvm, 0, i);
+
+ kvm_timer_init(kvm);
+ kvm->arch.vgic.ready = true;
+out:
+ mutex_unlock(&kvm->lock);
+ return ret;
+}
+
+int kvm_vgic_create(struct kvm *kvm)
+{
+ int ret = 0;
+
+ mutex_lock(&kvm->lock);
+
+ if (atomic_read(&kvm->online_vcpus) || kvm->arch.vgic.vctrl_base) {
+ ret = -EEXIST;
+ goto out;
+ }
+
+ spin_lock_init(&kvm->arch.vgic.lock);
+ kvm->arch.vgic.vctrl_base = vgic_vctrl_base;
+ kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
+ kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
+
+out:
+ mutex_unlock(&kvm->lock);
+ return ret;
+}
+
+static bool vgic_ioaddr_overlap(struct kvm *kvm)
+{
+ phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
+ phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
+
+ if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
+ return 0;
+ if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
+ (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
+ return -EBUSY;
+ return 0;
+}
+
+static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
+ phys_addr_t addr, phys_addr_t size)
+{
+ int ret;
+
+ if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
+ return -EEXIST;
+ if (addr + size < addr)
+ return -EINVAL;
+
+ ret = vgic_ioaddr_overlap(kvm);
+ if (ret)
+ return ret;
+ *ioaddr = addr;
+ return ret;
+}
+
+int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr)
+{
+ int r = 0;
+ struct vgic_dist *vgic = &kvm->arch.vgic;
+
+ if (addr & ~KVM_PHYS_MASK)
+ return -E2BIG;
+
+ if (addr & ~PAGE_MASK)
+ return -EINVAL;
+
+ mutex_lock(&kvm->lock);
+ switch (type) {
+ case KVM_VGIC_V2_ADDR_TYPE_DIST:
+ r = vgic_ioaddr_assign(kvm, &vgic->vgic_dist_base,
+ addr, KVM_VGIC_V2_DIST_SIZE);
+ break;
+ case KVM_VGIC_V2_ADDR_TYPE_CPU:
+ r = vgic_ioaddr_assign(kvm, &vgic->vgic_cpu_base,
+ addr, KVM_VGIC_V2_CPU_SIZE);
+ break;
+ default:
+ r = -ENODEV;
+ }
+
+ mutex_unlock(&kvm->lock);
+ return r;
+}
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 958358c91afd..6071f4c3d654 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -352,12 +352,6 @@ config MACH_USB_A9263
Select this if you are using a Calao Systems USB-A9263.
<http://www.calao-systems.com>
-config MACH_NEOCORE926
- bool "Adeneo NEOCORE926"
- select HAVE_AT91_DATAFLASH_CARD
- help
- Select this if you are using the Adeneo Neocore 926 board.
-
endif
# ----------------------------------------------------------
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index b38a1dcb79b8..39218ca6d8e8 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -66,7 +66,6 @@ obj-$(CONFIG_MACH_AT91SAM9G10EK) += board-sam9261ek.o
# AT91SAM9263 board-specific support
obj-$(CONFIG_MACH_AT91SAM9263EK) += board-sam9263ek.o
obj-$(CONFIG_MACH_USB_A9263) += board-usb-a926x.o
-obj-$(CONFIG_MACH_NEOCORE926) += board-neocore926.o
# AT91SAM9RL board-specific support
obj-$(CONFIG_MACH_AT91SAM9RLEK) += board-sam9rlek.o
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 7aeb473ee539..9706c000f294 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -210,6 +210,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "fffa4000.timer", &tc3_clk),
CLKDEV_CON_DEV_ID("t1_clk", "fffa4000.timer", &tc4_clk),
CLKDEV_CON_DEV_ID("t2_clk", "fffa4000.timer", &tc5_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fffb4000.mmc", &mmc_clk),
+ CLKDEV_CON_DEV_ID("emac_clk", "fffbc000.ethernet", &ether_clk),
CLKDEV_CON_DEV_ID("hclk", "300000.ohci", &ohci_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c
index cafe98836c8a..2acdff4c1dfe 100644
--- a/arch/arm/mach-at91/at91rm9200_time.c
+++ b/arch/arm/mach-at91/at91rm9200_time.c
@@ -174,7 +174,6 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev)
static struct clock_event_device clkevt = {
.name = "at91_tick",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.rating = 150,
.set_next_event = clkevt32k_next_event,
.set_mode = clkevt32k_mode,
@@ -265,17 +264,10 @@ void __init at91rm9200_timer_init(void)
at91_st_write(AT91_ST_RTMR, 1);
/* Setup timer clockevent, with minimum of two ticks (important!!) */
- clkevt.mult = div_sc(AT91_SLOW_CLOCK, NSEC_PER_SEC, clkevt.shift);
- clkevt.max_delta_ns = clockevent_delta2ns(AT91_ST_ALMV, &clkevt);
- clkevt.min_delta_ns = clockevent_delta2ns(2, &clkevt) + 1;
clkevt.cpumask = cpumask_of(0);
- clockevents_register_device(&clkevt);
+ clockevents_config_and_register(&clkevt, AT91_SLOW_CLOCK,
+ 2, AT91_ST_ALMV);
/* register clocksource */
clocksource_register_hz(&clk32k, AT91_SLOW_CLOCK);
}
-
-struct sys_timer at91rm9200_timer = {
- .init = at91rm9200_timer_init,
-};
-
diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
index 358412f1f5f8..3a4bc2e1a65e 100644
--- a/arch/arm/mach-at91/at91sam926x_time.c
+++ b/arch/arm/mach-at91/at91sam926x_time.c
@@ -104,12 +104,38 @@ pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
}
}
+static void at91sam926x_pit_suspend(struct clock_event_device *cedev)
+{
+ /* Disable timer */
+ pit_write(AT91_PIT_MR, 0);
+}
+
+static void at91sam926x_pit_reset(void)
+{
+ /* Disable timer and irqs */
+ pit_write(AT91_PIT_MR, 0);
+
+ /* Clear any pending interrupts, wait for PIT to stop counting */
+ while (PIT_CPIV(pit_read(AT91_PIT_PIVR)) != 0)
+ cpu_relax();
+
+ /* Start PIT but don't enable IRQ */
+ pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
+}
+
+static void at91sam926x_pit_resume(struct clock_event_device *cedev)
+{
+ at91sam926x_pit_reset();
+}
+
static struct clock_event_device pit_clkevt = {
.name = "pit",
.features = CLOCK_EVT_FEAT_PERIODIC,
.shift = 32,
.rating = 100,
.set_mode = pit_clkevt_mode,
+ .suspend = at91sam926x_pit_suspend,
+ .resume = at91sam926x_pit_resume,
};
@@ -150,19 +176,6 @@ static struct irqaction at91sam926x_pit_irq = {
.irq = NR_IRQS_LEGACY + AT91_ID_SYS,
};
-static void at91sam926x_pit_reset(void)
-{
- /* Disable timer and irqs */
- pit_write(AT91_PIT_MR, 0);
-
- /* Clear any pending interrupts, wait for PIT to stop counting */
- while (PIT_CPIV(pit_read(AT91_PIT_PIVR)) != 0)
- cpu_relax();
-
- /* Start PIT but don't enable IRQ */
- pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
-}
-
#ifdef CONFIG_OF
static struct of_device_id pit_timer_ids[] = {
{ .compatible = "atmel,at91sam9260-pit" },
@@ -211,7 +224,7 @@ static int __init of_at91sam926x_pit_init(void)
/*
* Set up both clocksource and clockevent support.
*/
-static void __init at91sam926x_pit_init(void)
+void __init at91sam926x_pit_init(void)
{
unsigned long pit_rate;
unsigned bits;
@@ -250,12 +263,6 @@ static void __init at91sam926x_pit_init(void)
clockevents_register_device(&pit_clkevt);
}
-static void at91sam926x_pit_suspend(void)
-{
- /* Disable timer */
- pit_write(AT91_PIT_MR, 0);
-}
-
void __init at91sam926x_ioremap_pit(u32 addr)
{
#if defined(CONFIG_OF)
@@ -272,9 +279,3 @@ void __init at91sam926x_ioremap_pit(u32 addr)
if (!pit_base_addr)
panic("Impossible to ioremap PIT\n");
}
-
-struct sys_timer at91sam926x_timer = {
- .init = at91sam926x_pit_init,
- .suspend = at91sam926x_pit_suspend,
- .resume = at91sam926x_pit_reset,
-};
diff --git a/arch/arm/mach-at91/at91x40_time.c b/arch/arm/mach-at91/at91x40_time.c
index 0e57e440c061..0c07a4459cb2 100644
--- a/arch/arm/mach-at91/at91x40_time.c
+++ b/arch/arm/mach-at91/at91x40_time.c
@@ -42,9 +42,10 @@
#define AT91_TC_CLK1BASE 0x40
#define AT91_TC_CLK2BASE 0x80
-static unsigned long at91x40_gettimeoffset(void)
+static u32 at91x40_gettimeoffset(void)
{
- return (at91_tc_read(AT91_TC_CLK1BASE + AT91_TC_CV) * 1000000 / (AT91X40_MASTER_CLOCK / 128));
+ return (at91_tc_read(AT91_TC_CLK1BASE + AT91_TC_CV) * 1000000 /
+ (AT91X40_MASTER_CLOCK / 128)) * 1000;
}
static irqreturn_t at91x40_timer_interrupt(int irq, void *dev_id)
@@ -64,6 +65,8 @@ void __init at91x40_timer_init(void)
{
unsigned int v;
+ arch_gettimeoffset = at91x40_gettimeoffset;
+
at91_tc_write(AT91_TC_BCR, 0);
v = at91_tc_read(AT91_TC_BMR);
v = (v & ~AT91_TC_TC1XC1S) | AT91_TC_TC1XC1S_NONE;
@@ -79,9 +82,3 @@ void __init at91x40_timer_init(void)
at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_CCR, (AT91_TC_SWTRG | AT91_TC_CLKEN));
}
-
-struct sys_timer at91x40_timer = {
- .init = at91x40_timer_init,
- .offset = at91x40_gettimeoffset,
-};
-
diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c
index b99b5752cc10..35ab632bbf68 100644
--- a/arch/arm/mach-at91/board-1arm.c
+++ b/arch/arm/mach-at91/board-1arm.c
@@ -90,7 +90,7 @@ static void __init onearm_board_init(void)
MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = onearm_init_early,
diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
index 854b97974287..f95e31cda4b3 100644
--- a/arch/arm/mach-at91/board-afeb-9260v1.c
+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
@@ -210,7 +210,7 @@ static void __init afeb9260_board_init(void)
MACHINE_START(AFEB9260, "Custom afeb9260 board")
/* Maintainer: Sergey Lapin <slapin@ossfans.org> */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = afeb9260_init_early,
diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
index 28a18ce6d914..ade948b82662 100644
--- a/arch/arm/mach-at91/board-cam60.c
+++ b/arch/arm/mach-at91/board-cam60.c
@@ -187,7 +187,7 @@ static void __init cam60_board_init(void)
MACHINE_START(CAM60, "KwikByte CAM60")
/* Maintainer: KwikByte */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = cam60_init_early,
diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
index c17bb533a949..92983050a9bd 100644
--- a/arch/arm/mach-at91/board-carmeva.c
+++ b/arch/arm/mach-at91/board-carmeva.c
@@ -157,7 +157,7 @@ static void __init carmeva_board_init(void)
MACHINE_START(CARMEVA, "Carmeva")
/* Maintainer: Conitec Datasystems */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = carmeva_init_early,
diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
index 847432441ecc..008527efdbcf 100644
--- a/arch/arm/mach-at91/board-cpu9krea.c
+++ b/arch/arm/mach-at91/board-cpu9krea.c
@@ -374,7 +374,7 @@ MACHINE_START(CPUAT9260, "Eukrea CPU9260")
MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
#endif
/* Maintainer: Eric Benard - EUKREA Electromatique */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = cpu9krea_init_early,
diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
index 2a7af7868747..42f1353a4baf 100644
--- a/arch/arm/mach-at91/board-cpuat91.c
+++ b/arch/arm/mach-at91/board-cpuat91.c
@@ -178,7 +178,7 @@ static void __init cpuat91_board_init(void)
MACHINE_START(CPUAT91, "Eukrea")
/* Maintainer: Eric Benard - EUKREA Electromatique */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = cpuat91_init_early,
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index 48a531e05be3..e5fde215225b 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -251,7 +251,7 @@ static void __init csb337_board_init(void)
MACHINE_START(CSB337, "Cogent CSB337")
/* Maintainer: Bill Gatliff */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = csb337_init_early,
diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
index ec0f3abd504b..fdf11061c577 100644
--- a/arch/arm/mach-at91/board-csb637.c
+++ b/arch/arm/mach-at91/board-csb637.c
@@ -132,7 +132,7 @@ static void __init csb637_board_init(void)
MACHINE_START(CSB637, "Cogent CSB637")
/* Maintainer: Bill Gatliff */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = csb637_init_early,
diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
index 881170ce61dd..8db30132abed 100644
--- a/arch/arm/mach-at91/board-dt.c
+++ b/arch/arm/mach-at91/board-dt.c
@@ -49,7 +49,7 @@ static const char *at91_dt_board_compat[] __initdata = {
DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)")
/* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = at91_dt_initialize,
diff --git a/arch/arm/mach-at91/board-eb01.c b/arch/arm/mach-at91/board-eb01.c
index b489388a6f84..becf0a6a289e 100644
--- a/arch/arm/mach-at91/board-eb01.c
+++ b/arch/arm/mach-at91/board-eb01.c
@@ -44,7 +44,7 @@ static void __init at91eb01_init_early(void)
MACHINE_START(AT91EB01, "Atmel AT91 EB01")
/* Maintainer: Greg Ungerer <gerg@snapgear.com> */
- .timer = &at91x40_timer,
+ .init_time = at91x40_timer_init,
.handle_irq = at91_aic_handle_irq,
.init_early = at91eb01_init_early,
.init_irq = at91eb01_init_irq,
diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
index 9f5e71c95f05..f9be8161bbfa 100644
--- a/arch/arm/mach-at91/board-eb9200.c
+++ b/arch/arm/mach-at91/board-eb9200.c
@@ -116,7 +116,7 @@ static void __init eb9200_board_init(void)
}
MACHINE_START(ATEB9200, "Embest ATEB9200")
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = eb9200_init_early,
diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
index ef69e0ebe949..b2fcd71262ba 100644
--- a/arch/arm/mach-at91/board-ecbat91.c
+++ b/arch/arm/mach-at91/board-ecbat91.c
@@ -181,7 +181,7 @@ static void __init ecb_at91board_init(void)
MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
/* Maintainer: emQbit.com */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ecb_at91init_early,
diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
index 50f3d3795c05..77de410efc90 100644
--- a/arch/arm/mach-at91/board-eco920.c
+++ b/arch/arm/mach-at91/board-eco920.c
@@ -149,7 +149,7 @@ static void __init eco920_board_init(void)
MACHINE_START(ECO920, "eco920")
/* Maintainer: Sascha Hauer */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = eco920_init_early,
diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
index 5d44eba0f20f..737c08563628 100644
--- a/arch/arm/mach-at91/board-flexibity.c
+++ b/arch/arm/mach-at91/board-flexibity.c
@@ -159,7 +159,7 @@ static void __init flexibity_board_init(void)
MACHINE_START(FLEXIBITY, "Flexibity Connect")
/* Maintainer: Maxim Osipov */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = flexibity_init_early,
diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
index 191d37c16bab..2ea7059b840b 100644
--- a/arch/arm/mach-at91/board-foxg20.c
+++ b/arch/arm/mach-at91/board-foxg20.c
@@ -261,7 +261,7 @@ static void __init foxg20_board_init(void)
MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
/* Maintainer: Sergio Tanzilli */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = foxg20_init_early,
diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c
index 23a2fa17ab29..c1d61d247790 100644
--- a/arch/arm/mach-at91/board-gsia18s.c
+++ b/arch/arm/mach-at91/board-gsia18s.c
@@ -574,7 +574,7 @@ static void __init gsia18s_board_init(void)
}
MACHINE_START(GSIA18S, "GS_IA18_S")
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = gsia18s_init_early,
diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
index 9a43d1e1a037..88e2f5d2d16d 100644
--- a/arch/arm/mach-at91/board-kafa.c
+++ b/arch/arm/mach-at91/board-kafa.c
@@ -103,7 +103,7 @@ static void __init kafa_board_init(void)
MACHINE_START(KAFA, "Sperry-Sun KAFA")
/* Maintainer: Sergei Sharonov */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = kafa_init_early,
diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
index f168bec2369f..0c519d9ebffc 100644
--- a/arch/arm/mach-at91/board-kb9202.c
+++ b/arch/arm/mach-at91/board-kb9202.c
@@ -149,7 +149,7 @@ static void __init kb9202_board_init(void)
MACHINE_START(KB9200, "KB920x")
/* Maintainer: KwikByte, Inc. */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = kb9202_init_early,
diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
deleted file mode 100644
index bc7a1c4a1f6a..000000000000
--- a/arch/arm/mach-at91/board-neocore926.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-neocore926.c
- *
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2007 Atmel Corporation
- * Copyright (C) 2008 ADENEO.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
-#include <linux/fb.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-
-#include <video/atmel_lcdc.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-#include <asm/sizes.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/at91sam9_smc.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-
-
-static void __init neocore926_init_early(void)
-{
- /* Initialize processor: 20 MHz crystal */
- at91_initialize(20000000);
-}
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata neocore926_usbh_data = {
- .ports = 2,
- .vbus_pin = { AT91_PIN_PA24, AT91_PIN_PA21 },
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata neocore926_udc_data = {
- .vbus_pin = AT91_PIN_PA25,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-
-/*
- * ADS7846 Touchscreen
- */
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-static int ads7843_pendown_state(void)
-{
- return !at91_get_gpio_value(AT91_PIN_PA15); /* Touchscreen PENIRQ */
-}
-
-static struct ads7846_platform_data ads_info = {
- .model = 7843,
- .x_min = 150,
- .x_max = 3830,
- .y_min = 190,
- .y_max = 3830,
- .vref_delay_usecs = 100,
- .x_plate_ohms = 450,
- .y_plate_ohms = 250,
- .pressure_max = 15000,
- .debounce_max = 1,
- .debounce_rep = 0,
- .debounce_tol = (~0),
- .get_pendown_state = ads7843_pendown_state,
-};
-
-static void __init neocore926_add_device_ts(void)
-{
- at91_set_B_periph(AT91_PIN_PA15, 1); /* External IRQ1, with pullup */
- at91_set_gpio_input(AT91_PIN_PC13, 1); /* Touchscreen BUSY signal */
-}
-#else
-static void __init neocore926_add_device_ts(void) {}
-#endif
-
-/*
- * SPI devices.
- */
-static struct spi_board_info neocore926_spi_devices[] = {
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
- { /* DataFlash card */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-#endif
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
- {
- .modalias = "ads7846",
- .chip_select = 1,
- .max_speed_hz = 125000 * 16,
- .bus_num = 0,
- .platform_data = &ads_info,
- .irq = NR_IRQS_LEGACY + AT91SAM9263_ID_IRQ1,
- },
-#endif
-};
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct mci_platform_data __initdata neocore926_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PE18,
- .wp_pin = AT91_PIN_PE19,
- },
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata neocore926_macb_data = {
- .phy_irq_pin = AT91_PIN_PE31,
- .is_rmii = 1,
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata neocore926_nand_partition[] = {
- {
- .name = "Linux Kernel", /* "Partition 1", */
- .offset = 0,
- .size = SZ_8M,
- },
- {
- .name = "Filesystem", /* "Partition 2", */
- .offset = MTDPART_OFS_NXTBLK,
- .size = SZ_32M,
- },
- {
- .name = "Free", /* "Partition 3", */
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct atmel_nand_data __initdata neocore926_nand_data = {
- .ale = 21,
- .cle = 22,
- .rdy_pin = AT91_PIN_PB19,
- .rdy_pin_active_low = 1,
- .enable_pin = AT91_PIN_PD15,
- .ecc_mode = NAND_ECC_SOFT,
- .parts = neocore926_nand_partition,
- .num_parts = ARRAY_SIZE(neocore926_nand_partition),
- .det_pin = -EINVAL,
-};
-
-static struct sam9_smc_config __initdata neocore926_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 1,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 4,
- .nrd_pulse = 4,
- .ncs_write_pulse = 4,
- .nwe_pulse = 4,
-
- .read_cycle = 6,
- .write_cycle = 6,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
- .tdf_cycles = 2,
-};
-
-static void __init neocore926_add_device_nand(void)
-{
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(0, 3, &neocore926_nand_smc_config);
-
- at91_add_device_nand(&neocore926_nand_data);
-}
-
-
-/*
- * LCD Controller
- */
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static struct fb_videomode at91_tft_vga_modes[] = {
- {
- .name = "TX09D50VM1CCA @ 60",
- .refresh = 60,
- .xres = 240, .yres = 320,
- .pixclock = KHZ2PICOS(5000),
-
- .left_margin = 1, .right_margin = 33,
- .upper_margin = 1, .lower_margin = 0,
- .hsync_len = 5, .vsync_len = 1,
-
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- .vmode = FB_VMODE_NONINTERLACED,
- },
-};
-
-static struct fb_monspecs at91fb_default_monspecs = {
- .manufacturer = "HIT",
- .monitor = "TX09D70VM1CCA",
-
- .modedb = at91_tft_vga_modes,
- .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
- .hfmin = 15000,
- .hfmax = 64000,
- .vfmin = 50,
- .vfmax = 150,
-};
-
-#define AT91SAM9263_DEFAULT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \
- | ATMEL_LCDC_DISTYPE_TFT \
- | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
-
-static void at91_lcdc_power_control(int on)
-{
- at91_set_gpio_value(AT91_PIN_PA30, on);
-}
-
-/* Driver datas */
-static struct atmel_lcdfb_info __initdata neocore926_lcdc_data = {
- .lcdcon_is_backlight = true,
- .default_bpp = 16,
- .default_dmacon = ATMEL_LCDC_DMAEN,
- .default_lcdcon2 = AT91SAM9263_DEFAULT_LCDCON2,
- .default_monspecs = &at91fb_default_monspecs,
- .atmel_lcdfb_power_control = at91_lcdc_power_control,
- .guard_time = 1,
- .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB555,
-};
-
-#else
-static struct atmel_lcdfb_info __initdata neocore926_lcdc_data;
-#endif
-
-
-/*
- * GPIO Buttons
- */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button neocore926_buttons[] = {
- { /* BP1, "leftclic" */
- .code = BTN_LEFT,
- .gpio = AT91_PIN_PC5,
- .active_low = 1,
- .desc = "left_click",
- .wakeup = 1,
- },
- { /* BP2, "rightclic" */
- .code = BTN_RIGHT,
- .gpio = AT91_PIN_PC4,
- .active_low = 1,
- .desc = "right_click",
- .wakeup = 1,
- },
-};
-
-static struct gpio_keys_platform_data neocore926_button_data = {
- .buttons = neocore926_buttons,
- .nbuttons = ARRAY_SIZE(neocore926_buttons),
-};
-
-static struct platform_device neocore926_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &neocore926_button_data,
- }
-};
-
-static void __init neocore926_add_device_buttons(void)
-{
- at91_set_GPIO_periph(AT91_PIN_PC5, 0); /* left button */
- at91_set_deglitch(AT91_PIN_PC5, 1);
- at91_set_GPIO_periph(AT91_PIN_PC4, 0); /* right button */
- at91_set_deglitch(AT91_PIN_PC4, 1);
-
- platform_device_register(&neocore926_button_device);
-}
-#else
-static void __init neocore926_add_device_buttons(void) {}
-#endif
-
-
-/*
- * AC97
- */
-static struct ac97c_platform_data neocore926_ac97_data = {
- .reset_pin = AT91_PIN_PA13,
-};
-
-
-static void __init neocore926_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_add_device_serial();
-
- /* USB Host */
- at91_add_device_usbh(&neocore926_usbh_data);
-
- /* USB Device */
- at91_add_device_udc(&neocore926_udc_data);
-
- /* SPI */
- at91_set_gpio_output(AT91_PIN_PE20, 1); /* select spi0 clock */
- at91_add_device_spi(neocore926_spi_devices, ARRAY_SIZE(neocore926_spi_devices));
-
- /* Touchscreen */
- neocore926_add_device_ts();
-
- /* MMC */
- at91_add_device_mci(0, &neocore926_mci0_data);
-
- /* Ethernet */
- at91_add_device_eth(&neocore926_macb_data);
-
- /* NAND */
- neocore926_add_device_nand();
-
- /* I2C */
- at91_add_device_i2c(NULL, 0);
-
- /* LCD Controller */
- at91_add_device_lcdc(&neocore926_lcdc_data);
-
- /* Push Buttons */
- neocore926_add_device_buttons();
-
- /* AC97 */
- at91_add_device_ac97(&neocore926_ac97_data);
-}
-
-MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
- /* Maintainer: ADENEO */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = neocore926_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = neocore926_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
index 0299554495dd..65c0d6b5ecba 100644
--- a/arch/arm/mach-at91/board-pcontrol-g20.c
+++ b/arch/arm/mach-at91/board-pcontrol-g20.c
@@ -217,7 +217,7 @@ static void __init pcontrol_g20_board_init(void)
MACHINE_START(PCONTROL_G20, "PControl G20")
/* Maintainer: pgsellmann@portner-elektronik.at */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = pcontrol_g20_init_early,
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
index 4938f1cd5e13..ab2b2ec36c14 100644
--- a/arch/arm/mach-at91/board-picotux200.c
+++ b/arch/arm/mach-at91/board-picotux200.c
@@ -119,7 +119,7 @@ static void __init picotux200_board_init(void)
MACHINE_START(PICOTUX2XX, "picotux 200")
/* Maintainer: Kleinhenz Elektronik GmbH */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = picotux200_init_early,
diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
index 33b1628467ea..aa3bc9b0f150 100644
--- a/arch/arm/mach-at91/board-qil-a9260.c
+++ b/arch/arm/mach-at91/board-qil-a9260.c
@@ -257,7 +257,7 @@ static void __init ek_board_init(void)
MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
/* Maintainer: calao-systems */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
diff --git a/arch/arm/mach-at91/board-rm9200-dt.c b/arch/arm/mach-at91/board-rm9200-dt.c
index 5f9ce3da3fde..3fcb6623a33e 100644
--- a/arch/arm/mach-at91/board-rm9200-dt.c
+++ b/arch/arm/mach-at91/board-rm9200-dt.c
@@ -47,7 +47,7 @@ static const char *at91rm9200_dt_board_compat[] __initdata = {
};
DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200 (Device Tree)")
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = at91rm9200_dt_initialize,
diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
index 9e5061bef0d0..690541b18cbc 100644
--- a/arch/arm/mach-at91/board-rm9200dk.c
+++ b/arch/arm/mach-at91/board-rm9200dk.c
@@ -219,7 +219,7 @@ static void __init dk_board_init(void)
MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
/* Maintainer: SAN People/Atmel */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = dk_init_early,
diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
index 58277dbc718f..8b17dadc1aba 100644
--- a/arch/arm/mach-at91/board-rm9200ek.c
+++ b/arch/arm/mach-at91/board-rm9200ek.c
@@ -186,7 +186,7 @@ static void __init ek_board_init(void)
MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
/* Maintainer: SAN People/Atmel */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
index 2e8b8339a206..f6d7f1958c7e 100644
--- a/arch/arm/mach-at91/board-rsi-ews.c
+++ b/arch/arm/mach-at91/board-rsi-ews.c
@@ -222,7 +222,7 @@ static void __init rsi_ews_board_init(void)
MACHINE_START(RSI_EWS, "RSI EWS")
/* Maintainer: Josef Holzmayr <holzmayr@rsi-elektrotechnik.de> */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = rsi_ews_init_early,
diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
index b75fbf6003a1..43ee4dc43b50 100644
--- a/arch/arm/mach-at91/board-sam9-l9260.c
+++ b/arch/arm/mach-at91/board-sam9-l9260.c
@@ -218,7 +218,7 @@ static void __init ek_board_init(void)
MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
/* Maintainer: Olimex */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index f0135cd1d858..0b153c87521d 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -343,7 +343,7 @@ static void __init ek_board_init(void)
MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
/* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 13ebaa8e4100..b446645c7727 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -612,7 +612,7 @@ MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK")
MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
#endif
/* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 89b9608742a7..3284df05df14 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -443,7 +443,7 @@ static void __init ek_board_init(void)
MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
/* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 1b7dd9f688d3..f9cd1f2c7146 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -409,7 +409,7 @@ static void __init ek_board_init(void)
MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
/* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
@@ -419,7 +419,7 @@ MACHINE_END
MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
/* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index e4cc375e3a32..2a94896a1375 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -502,7 +502,7 @@ static void __init ek_board_init(void)
MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
/* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
index 377a1097afa7..aa265dcf2128 100644
--- a/arch/arm/mach-at91/board-sam9rlek.c
+++ b/arch/arm/mach-at91/board-sam9rlek.c
@@ -320,7 +320,7 @@ static void __init ek_board_init(void)
MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
/* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
index 98771500ddb9..3aaa9784cf0e 100644
--- a/arch/arm/mach-at91/board-snapper9260.c
+++ b/arch/arm/mach-at91/board-snapper9260.c
@@ -177,7 +177,7 @@ static void __init snapper9260_board_init(void)
}
MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = snapper9260_init_early,
diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
index 48a962b61fa3..a033b8df9fb2 100644
--- a/arch/arm/mach-at91/board-stamp9g20.c
+++ b/arch/arm/mach-at91/board-stamp9g20.c
@@ -272,7 +272,7 @@ static void __init stamp9g20evb_board_init(void)
MACHINE_START(PORTUXG20, "taskit PortuxG20")
/* Maintainer: taskit GmbH */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = stamp9g20_init_early,
@@ -282,7 +282,7 @@ MACHINE_END
MACHINE_START(STAMP9G20, "taskit Stamp9G20")
/* Maintainer: taskit GmbH */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = stamp9g20_init_early,
diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
index c1060f96e589..2487d944a1bc 100644
--- a/arch/arm/mach-at91/board-usb-a926x.c
+++ b/arch/arm/mach-at91/board-usb-a926x.c
@@ -355,7 +355,7 @@ static void __init ek_board_init(void)
MACHINE_START(USB_A9263, "CALAO USB_A9263")
/* Maintainer: calao-systems */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
@@ -365,7 +365,7 @@ MACHINE_END
MACHINE_START(USB_A9260, "CALAO USB_A9260")
/* Maintainer: calao-systems */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
@@ -375,7 +375,7 @@ MACHINE_END
MACHINE_START(USB_A9G20, "CALAO USB_A92G0")
/* Maintainer: Jean-Christophe PLAGNIOL-VILLARD */
- .timer = &at91sam926x_timer,
+ .init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = ek_init_early,
diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
index 8673aebcb85d..be083771df2e 100644
--- a/arch/arm/mach-at91/board-yl-9200.c
+++ b/arch/arm/mach-at91/board-yl-9200.c
@@ -587,7 +587,7 @@ static void __init yl9200_board_init(void)
MACHINE_START(YL9200, "uCdragon YL-9200")
/* Maintainer: S.Birtles */
- .timer = &at91rm9200_timer,
+ .init_time = at91rm9200_timer_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = yl9200_init_early,
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index fc593d615e7d..78ab06548658 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -36,12 +36,11 @@ extern int __init at91_aic5_of_init(struct device_node *node,
/* Timer */
-struct sys_timer;
extern void at91rm9200_ioremap_st(u32 addr);
-extern struct sys_timer at91rm9200_timer;
+extern void at91rm9200_timer_init(void);
extern void at91sam926x_ioremap_pit(u32 addr);
-extern struct sys_timer at91sam926x_timer;
-extern struct sys_timer at91x40_timer;
+extern void at91sam926x_pit_init(void);
+extern void at91x40_timer_init(void);
/* Clocks */
#ifdef CONFIG_AT91_PMC_UNIT
diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h
index 97ad68a826f8..5659f7c72120 100644
--- a/arch/arm/mach-at91/include/mach/uncompress.h
+++ b/arch/arm/mach-at91/include/mach/uncompress.h
@@ -196,6 +196,4 @@ static inline void flush(void)
barrier();
}
-#define arch_decomp_wdog()
-
#endif
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index 48705c10a0fe..bf02471d7e7c 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -7,7 +7,6 @@ config ARCH_BCM
select ARM_GIC
select CPU_V7
select GENERIC_CLOCKEVENTS
- select GENERIC_GPIO
select GENERIC_TIME
select GPIO_BCM
select SPARSE_IRQ
diff --git a/arch/arm/mach-bcm/board_bcm.c b/arch/arm/mach-bcm/board_bcm.c
index 3a62f1b1cabc..f0f9abafad29 100644
--- a/arch/arm/mach-bcm/board_bcm.c
+++ b/arch/arm/mach-bcm/board_bcm.c
@@ -11,34 +11,19 @@
* GNU General Public License for more details.
*/
-#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/irqchip.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
-
#include <asm/mach/time.h>
-static const struct of_device_id irq_match[] = {
- {.compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- {}
-};
-
static void timer_init(void)
{
}
-static struct sys_timer timer = {
- .init = timer_init,
-};
-
-static void __init init_irq(void)
-{
- of_irq_init(irq_match);
-}
static void __init board_init(void)
{
@@ -49,9 +34,8 @@ static void __init board_init(void)
static const char * const bcm11351_dt_compat[] = { "bcm,bcm11351", NULL, };
DT_MACHINE_START(BCM11351_DT, "Broadcom Application Processor")
- .init_irq = init_irq,
- .timer = &timer,
+ .init_irq = irqchip_init,
+ .init_time = timer_init,
.init_machine = board_init,
.dt_compat = bcm11351_dt_compat,
- .handle_irq = gic_handle_irq,
MACHINE_END
diff --git a/arch/arm/mach-bcm2835/bcm2835.c b/arch/arm/mach-bcm2835/bcm2835.c
index f0d739f4b7a3..6f5785985dd1 100644
--- a/arch/arm/mach-bcm2835/bcm2835.c
+++ b/arch/arm/mach-bcm2835/bcm2835.c
@@ -17,8 +17,8 @@
#include <linux/irqchip/bcm2835.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
-#include <linux/bcm2835_timer.h>
#include <linux/clk/bcm2835.h>
+#include <linux/clocksource.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -26,11 +26,13 @@
#include <mach/bcm2835_soc.h>
#define PM_RSTC 0x1c
+#define PM_RSTS 0x20
#define PM_WDOG 0x24
#define PM_PASSWORD 0x5a000000
#define PM_RSTC_WRCFG_MASK 0x00000030
#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
+#define PM_RSTS_HADWRH_SET 0x00000040
static void __iomem *wdt_regs;
@@ -67,6 +69,29 @@ static void bcm2835_restart(char mode, const char *cmd)
mdelay(1);
}
+/*
+ * We can't really power off, but if we do the normal reset scheme, and
+ * indicate to bootcode.bin not to reboot, then most of the chip will be
+ * powered off.
+ */
+static void bcm2835_power_off(void)
+{
+ u32 val;
+
+ /*
+ * We set the watchdog hard reset bit here to distinguish this reset
+ * from the normal (full) reset. bootcode.bin will not reboot after a
+ * hard reset.
+ */
+ val = readl_relaxed(wdt_regs + PM_RSTS);
+ val &= ~PM_RSTC_WRCFG_MASK;
+ val |= PM_PASSWORD | PM_RSTS_HADWRH_SET;
+ writel_relaxed(val, wdt_regs + PM_RSTS);
+
+ /* Continue with normal reset mechanism */
+ bcm2835_restart(0, "");
+}
+
static struct map_desc io_map __initdata = {
.virtual = BCM2835_PERIPH_VIRT,
.pfn = __phys_to_pfn(BCM2835_PERIPH_PHYS),
@@ -84,6 +109,9 @@ static void __init bcm2835_init(void)
int ret;
bcm2835_setup_restart();
+ if (wdt_regs)
+ pm_power_off = bcm2835_power_off;
+
bcm2835_init_clocks();
ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
@@ -104,7 +132,7 @@ DT_MACHINE_START(BCM2835, "BCM2835")
.init_irq = bcm2835_init_irq,
.handle_irq = bcm2835_handle_irq,
.init_machine = bcm2835_init,
- .timer = &bcm2835_timer,
+ .init_time = clocksource_of_init,
.restart = bcm2835_restart,
.dt_compat = bcm2835_compat
MACHINE_END
diff --git a/arch/arm/mach-bcm2835/include/mach/uncompress.h b/arch/arm/mach-bcm2835/include/mach/uncompress.h
index cc46dcc72377..bf86dca3bf71 100644
--- a/arch/arm/mach-bcm2835/include/mach/uncompress.h
+++ b/arch/arm/mach-bcm2835/include/mach/uncompress.h
@@ -42,4 +42,3 @@ static inline void flush(void)
}
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-clps711x/board-autcpu12.c b/arch/arm/mach-clps711x/board-autcpu12.c
index 3fbf43f72589..f38584709df7 100644
--- a/arch/arm/mach-clps711x/board-autcpu12.c
+++ b/arch/arm/mach-clps711x/board-autcpu12.c
@@ -170,7 +170,7 @@ MACHINE_START(AUTCPU12, "autronix autcpu12")
.nr_irqs = CLPS711X_NR_IRQS,
.map_io = clps711x_map_io,
.init_irq = clps711x_init_irq,
- .timer = &clps711x_timer,
+ .init_time = clps711x_timer_init,
.init_machine = autcpu12_init,
.init_late = autcpu12_init_late,
.handle_irq = clps711x_handle_irq,
diff --git a/arch/arm/mach-clps711x/board-cdb89712.c b/arch/arm/mach-clps711x/board-cdb89712.c
index 60900ddf97c9..baab7da33c9b 100644
--- a/arch/arm/mach-clps711x/board-cdb89712.c
+++ b/arch/arm/mach-clps711x/board-cdb89712.c
@@ -140,7 +140,7 @@ MACHINE_START(CDB89712, "Cirrus-CDB89712")
.nr_irqs = CLPS711X_NR_IRQS,
.map_io = clps711x_map_io,
.init_irq = clps711x_init_irq,
- .timer = &clps711x_timer,
+ .init_time = clps711x_timer_init,
.init_machine = cdb89712_init,
.handle_irq = clps711x_handle_irq,
.restart = clps711x_restart,
diff --git a/arch/arm/mach-clps711x/board-clep7312.c b/arch/arm/mach-clps711x/board-clep7312.c
index 0b32a487183b..014aa3c19a03 100644
--- a/arch/arm/mach-clps711x/board-clep7312.c
+++ b/arch/arm/mach-clps711x/board-clep7312.c
@@ -40,7 +40,7 @@ MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312")
.fixup = fixup_clep7312,
.map_io = clps711x_map_io,
.init_irq = clps711x_init_irq,
- .timer = &clps711x_timer,
+ .init_time = clps711x_timer_init,
.handle_irq = clps711x_handle_irq,
.restart = clps711x_restart,
MACHINE_END
diff --git a/arch/arm/mach-clps711x/board-edb7211.c b/arch/arm/mach-clps711x/board-edb7211.c
index 71aa5cf2c0d3..5f928e9ed2ef 100644
--- a/arch/arm/mach-clps711x/board-edb7211.c
+++ b/arch/arm/mach-clps711x/board-edb7211.c
@@ -173,7 +173,7 @@ MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)")
.reserve = edb7211_reserve,
.map_io = edb7211_map_io,
.init_irq = clps711x_init_irq,
- .timer = &clps711x_timer,
+ .init_time = clps711x_timer_init,
.init_machine = edb7211_init,
.handle_irq = clps711x_handle_irq,
.restart = clps711x_restart,
diff --git a/arch/arm/mach-clps711x/board-fortunet.c b/arch/arm/mach-clps711x/board-fortunet.c
index 7d0125580366..c5675efc8c6a 100644
--- a/arch/arm/mach-clps711x/board-fortunet.c
+++ b/arch/arm/mach-clps711x/board-fortunet.c
@@ -78,7 +78,7 @@ MACHINE_START(FORTUNET, "ARM-FortuNet")
.fixup = fortunet_fixup,
.map_io = clps711x_map_io,
.init_irq = clps711x_init_irq,
- .timer = &clps711x_timer,
+ .init_time = clps711x_timer_init,
.handle_irq = clps711x_handle_irq,
.restart = clps711x_restart,
MACHINE_END
diff --git a/arch/arm/mach-clps711x/board-p720t.c b/arch/arm/mach-clps711x/board-p720t.c
index 1518fc83babd..8d3ee6771135 100644
--- a/arch/arm/mach-clps711x/board-p720t.c
+++ b/arch/arm/mach-clps711x/board-p720t.c
@@ -224,7 +224,7 @@ MACHINE_START(P720T, "ARM-Prospector720T")
.map_io = p720t_map_io,
.init_early = p720t_init_early,
.init_irq = clps711x_init_irq,
- .timer = &clps711x_timer,
+ .init_time = clps711x_timer_init,
.init_machine = p720t_init,
.init_late = p720t_init_late,
.handle_irq = clps711x_handle_irq,
diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c
index e046439573ee..20ff50f3ccf0 100644
--- a/arch/arm/mach-clps711x/common.c
+++ b/arch/arm/mach-clps711x/common.c
@@ -282,7 +282,7 @@ static void add_fixed_clk(struct clk *clk, const char *name, int rate)
clk_register_clkdev(clk, name, NULL);
}
-static void __init clps711x_timer_init(void)
+void __init clps711x_timer_init(void)
{
int osc, ext, pll, cpu, bus, timl, timh, uart, spi;
u32 tmp;
@@ -345,10 +345,6 @@ static void __init clps711x_timer_init(void)
setup_irq(IRQ_TC2OI, &clps711x_timer_irq);
}
-struct sys_timer clps711x_timer = {
- .init = clps711x_timer_init,
-};
-
void clps711x_restart(char mode, const char *cmd)
{
soft_restart(0);
diff --git a/arch/arm/mach-clps711x/common.h b/arch/arm/mach-clps711x/common.h
index b7c0c75c90c0..f84a7292c70e 100644
--- a/arch/arm/mach-clps711x/common.h
+++ b/arch/arm/mach-clps711x/common.h
@@ -8,10 +8,8 @@
#define CLPS711X_NR_GPIO (4 * 8 + 3)
#define CLPS711X_GPIO(prt, bit) ((prt) * 8 + (bit))
-struct sys_timer;
-
extern void clps711x_map_io(void);
extern void clps711x_init_irq(void);
+extern void clps711x_timer_init(void);
extern void clps711x_handle_irq(struct pt_regs *regs);
extern void clps711x_restart(char mode, const char *cmd);
-extern struct sys_timer clps711x_timer;
diff --git a/arch/arm/mach-clps711x/include/mach/uncompress.h b/arch/arm/mach-clps711x/include/mach/uncompress.h
index 7b28d6a47690..5f02d06dc655 100644
--- a/arch/arm/mach-clps711x/include/mach/uncompress.h
+++ b/arch/arm/mach-clps711x/include/mach/uncompress.h
@@ -53,5 +53,3 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-cns3xxx/cns3420vb.c b/arch/arm/mach-cns3xxx/cns3420vb.c
index ae305397003c..a71867e1d8d6 100644
--- a/arch/arm/mach-cns3xxx/cns3420vb.c
+++ b/arch/arm/mach-cns3xxx/cns3420vb.c
@@ -28,7 +28,6 @@
#include <linux/usb/ohci_pdriver.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
@@ -250,8 +249,7 @@ MACHINE_START(CNS3420VB, "Cavium Networks CNS3420 Validation Board")
.atag_offset = 0x100,
.map_io = cns3420_map_io,
.init_irq = cns3xxx_init_irq,
- .timer = &cns3xxx_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = cns3xxx_timer_init,
.init_machine = cns3420_init,
.restart = cns3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c
index 031805b1428d..e698f26cc0cb 100644
--- a/arch/arm/mach-cns3xxx/core.c
+++ b/arch/arm/mach-cns3xxx/core.c
@@ -12,10 +12,10 @@
#include <linux/interrupt.h>
#include <linux/clockchips.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include <mach/cns3xxx.h>
#include "core.h"
@@ -134,7 +134,6 @@ static int cns3xxx_timer_set_next_event(unsigned long evt,
static struct clock_event_device cns3xxx_tmr1_clockevent = {
.name = "cns3xxx timer1",
- .shift = 8,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = cns3xxx_timer_set_mode,
.set_next_event = cns3xxx_timer_set_next_event,
@@ -145,15 +144,9 @@ static struct clock_event_device cns3xxx_tmr1_clockevent = {
static void __init cns3xxx_clockevents_init(unsigned int timer_irq)
{
cns3xxx_tmr1_clockevent.irq = timer_irq;
- cns3xxx_tmr1_clockevent.mult =
- div_sc((cns3xxx_cpu_clock() >> 3) * 1000000, NSEC_PER_SEC,
- cns3xxx_tmr1_clockevent.shift);
- cns3xxx_tmr1_clockevent.max_delta_ns =
- clockevent_delta2ns(0xffffffff, &cns3xxx_tmr1_clockevent);
- cns3xxx_tmr1_clockevent.min_delta_ns =
- clockevent_delta2ns(0xf, &cns3xxx_tmr1_clockevent);
-
- clockevents_register_device(&cns3xxx_tmr1_clockevent);
+ clockevents_config_and_register(&cns3xxx_tmr1_clockevent,
+ (cns3xxx_cpu_clock() >> 3) * 1000000,
+ 0xf, 0xffffffff);
}
/*
@@ -235,17 +228,13 @@ static void __init __cns3xxx_timer_init(unsigned int timer_irq)
cns3xxx_clockevents_init(timer_irq);
}
-static void __init cns3xxx_timer_init(void)
+void __init cns3xxx_timer_init(void)
{
cns3xxx_tmr1 = IOMEM(CNS3XXX_TIMER1_2_3_BASE_VIRT);
__cns3xxx_timer_init(IRQ_CNS3XXX_TIMER0);
}
-struct sys_timer cns3xxx_timer = {
- .init = cns3xxx_timer_init,
-};
-
#ifdef CONFIG_CACHE_L2X0
void __init cns3xxx_l2x0_init(void)
diff --git a/arch/arm/mach-cns3xxx/core.h b/arch/arm/mach-cns3xxx/core.h
index 4894b8c17151..b23b17b4da10 100644
--- a/arch/arm/mach-cns3xxx/core.h
+++ b/arch/arm/mach-cns3xxx/core.h
@@ -11,7 +11,7 @@
#ifndef __CNS3XXX_CORE_H
#define __CNS3XXX_CORE_H
-extern struct sys_timer cns3xxx_timer;
+extern void cns3xxx_timer_init(void);
#ifdef CONFIG_CACHE_L2X0
void __init cns3xxx_l2x0_init(void);
diff --git a/arch/arm/mach-cns3xxx/include/mach/uncompress.h b/arch/arm/mach-cns3xxx/include/mach/uncompress.h
index a91b6058ab4f..7a030b99df84 100644
--- a/arch/arm/mach-cns3xxx/include/mach/uncompress.h
+++ b/arch/arm/mach-cns3xxx/include/mach/uncompress.h
@@ -51,4 +51,3 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index 0153950f6068..a075b3e0c5c7 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -62,6 +62,7 @@ config MACH_DA8XX_DT
bool "Support DA8XX platforms using device tree"
default y
depends on ARCH_DAVINCI_DA8XX
+ select PINCTRL
help
Say y here to include support for TI DaVinci DA850 based using
Flattened Device Tree. More information at Documentation/devicetree
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 95b5e102ceb1..6da25eebf911 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -652,8 +652,13 @@ static __init void da830_evm_init(void)
if (ret)
pr_warning("da830_evm_init: rtc setup failed: %d\n", ret);
- ret = da8xx_register_spi(0, da830evm_spi_info,
- ARRAY_SIZE(da830evm_spi_info));
+ ret = spi_register_board_info(da830evm_spi_info,
+ ARRAY_SIZE(da830evm_spi_info));
+ if (ret)
+ pr_warn("%s: spi info registration failed: %d\n", __func__,
+ ret);
+
+ ret = da8xx_register_spi_bus(0, ARRAY_SIZE(da830evm_spi_info));
if (ret)
pr_warning("da830_evm_init: spi 0 registration failed: %d\n",
ret);
@@ -679,7 +684,7 @@ MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137/AM17x EVM")
.atag_offset = 0x100,
.map_io = da830_evm_map_io,
.init_irq = cp_intc_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = da830_evm_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 0299915575a8..c2dfe06563df 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -349,13 +349,13 @@ static inline void da850_evm_setup_nor_nand(void)
if (!HAS_MMC) {
ret = davinci_cfg_reg_list(da850_evm_nand_pins);
if (ret)
- pr_warning("da850_evm_init: nand mux setup failed: "
- "%d\n", ret);
+ pr_warn("%s: NAND mux setup failed: %d\n",
+ __func__, ret);
ret = davinci_cfg_reg_list(da850_evm_nor_pins);
if (ret)
- pr_warning("da850_evm_init: nor mux setup failed: %d\n",
- ret);
+ pr_warn("%s: NOR mux setup failed: %d\n",
+ __func__, ret);
da850_evm_init_nor();
@@ -477,19 +477,19 @@ static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio,
ret = gpio_request(sel_a, da850_evm_ui_exp[DA850_EVM_UI_EXP_SEL_A]);
if (ret) {
- pr_warning("Cannot open UI expander pin %d\n", sel_a);
+ pr_warn("Cannot open UI expander pin %d\n", sel_a);
goto exp_setup_sela_fail;
}
ret = gpio_request(sel_b, da850_evm_ui_exp[DA850_EVM_UI_EXP_SEL_B]);
if (ret) {
- pr_warning("Cannot open UI expander pin %d\n", sel_b);
+ pr_warn("Cannot open UI expander pin %d\n", sel_b);
goto exp_setup_selb_fail;
}
ret = gpio_request(sel_c, da850_evm_ui_exp[DA850_EVM_UI_EXP_SEL_C]);
if (ret) {
- pr_warning("Cannot open UI expander pin %d\n", sel_c);
+ pr_warn("Cannot open UI expander pin %d\n", sel_c);
goto exp_setup_selc_fail;
}
@@ -501,7 +501,7 @@ static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio,
da850_evm_ui_keys_init(gpio);
ret = platform_device_register(&da850_evm_ui_keys_device);
if (ret) {
- pr_warning("Could not register UI GPIO expander push-buttons");
+ pr_warn("Could not register UI GPIO expander push-buttons");
goto exp_setup_keys_fail;
}
@@ -690,14 +690,14 @@ static int da850_evm_bb_expander_setup(struct i2c_client *client,
da850_evm_bb_keys_init(gpio);
ret = platform_device_register(&da850_evm_bb_keys_device);
if (ret) {
- pr_warning("Could not register baseboard GPIO expander keys");
+ pr_warn("Could not register baseboard GPIO expander keys");
goto io_exp_setup_sw_fail;
}
da850_evm_bb_leds_init(gpio);
ret = platform_device_register(&da850_evm_bb_leds_device);
if (ret) {
- pr_warning("Could not register baseboard GPIO expander LEDS");
+ pr_warn("Could not register baseboard GPIO expander LEDs");
goto io_exp_setup_leds_fail;
}
@@ -1065,21 +1065,19 @@ static int __init da850_evm_config_emac(void)
}
if (ret)
- pr_warning("da850_evm_init: cpgmac/rmii mux setup failed: %d\n",
- ret);
+ pr_warn("%s: CPGMAC/RMII mux setup failed: %d\n",
+ __func__, ret);
/* configure the CFGCHIP3 register for RMII or MII */
__raw_writel(val, cfg_chip3_base);
ret = davinci_cfg_reg(DA850_GPIO2_6);
if (ret)
- pr_warning("da850_evm_init:GPIO(2,6) mux setup "
- "failed\n");
+ pr_warn("%s:GPIO(2,6) mux setup failed\n", __func__);
ret = gpio_request(DA850_MII_MDIO_CLKEN_PIN, "mdio_clk_en");
if (ret) {
- pr_warning("Cannot open GPIO %d\n",
- DA850_MII_MDIO_CLKEN_PIN);
+ pr_warn("Cannot open GPIO %d\n", DA850_MII_MDIO_CLKEN_PIN);
return ret;
}
@@ -1090,8 +1088,7 @@ static int __init da850_evm_config_emac(void)
ret = da8xx_register_emac();
if (ret)
- pr_warning("da850_evm_init: emac registration failed: %d\n",
- ret);
+ pr_warn("%s: EMAC registration failed: %d\n", __func__, ret);
return 0;
}
@@ -1256,11 +1253,24 @@ static struct vpif_capture_config da850_vpif_capture_config = {
};
/* VPIF display configuration */
+
+static struct adv7343_platform_data adv7343_pdata = {
+ .mode_config = {
+ .dac_3 = 1,
+ .dac_2 = 1,
+ .dac_1 = 1,
+ },
+ .sd_config = {
+ .sd_dac_out1 = 1,
+ },
+};
+
static struct vpif_subdev_info da850_vpif_subdev[] = {
{
.name = "adv7343",
.board_info = {
I2C_BOARD_INFO("adv7343", 0x2a),
+ .platform_data = &adv7343_pdata,
},
},
};
@@ -1443,57 +1453,53 @@ static __init void da850_evm_init(void)
ret = pmic_tps65070_init();
if (ret)
- pr_warning("da850_evm_init: TPS65070 PMIC init failed: %d\n",
- ret);
+ pr_warn("%s: TPS65070 PMIC init failed: %d\n", __func__, ret);
ret = da850_register_edma(da850_edma_rsv);
if (ret)
- pr_warning("da850_evm_init: edma registration failed: %d\n",
- ret);
+ pr_warn("%s: EDMA registration failed: %d\n", __func__, ret);
ret = davinci_cfg_reg_list(da850_i2c0_pins);
if (ret)
- pr_warning("da850_evm_init: i2c0 mux setup failed: %d\n",
- ret);
+ pr_warn("%s: I2C0 mux setup failed: %d\n", __func__, ret);
ret = da8xx_register_i2c(0, &da850_evm_i2c_0_pdata);
if (ret)
- pr_warning("da850_evm_init: i2c0 registration failed: %d\n",
- ret);
+ pr_warn("%s: I2C0 registration failed: %d\n", __func__, ret);
ret = da8xx_register_watchdog();
if (ret)
- pr_warning("da830_evm_init: watchdog registration failed: %d\n",
- ret);
+ pr_warn("%s: watchdog registration failed: %d\n",
+ __func__, ret);
if (HAS_MMC) {
ret = davinci_cfg_reg_list(da850_evm_mmcsd0_pins);
if (ret)
- pr_warning("da850_evm_init: mmcsd0 mux setup failed:"
- " %d\n", ret);
+ pr_warn("%s: MMCSD0 mux setup failed: %d\n",
+ __func__, ret);
ret = gpio_request(DA850_MMCSD_CD_PIN, "MMC CD\n");
if (ret)
- pr_warning("da850_evm_init: can not open GPIO %d\n",
- DA850_MMCSD_CD_PIN);
+ pr_warn("%s: can not open GPIO %d\n",
+ __func__, DA850_MMCSD_CD_PIN);
gpio_direction_input(DA850_MMCSD_CD_PIN);
ret = gpio_request(DA850_MMCSD_WP_PIN, "MMC WP\n");
if (ret)
- pr_warning("da850_evm_init: can not open GPIO %d\n",
- DA850_MMCSD_WP_PIN);
+ pr_warn("%s: can not open GPIO %d\n",
+ __func__, DA850_MMCSD_WP_PIN);
gpio_direction_input(DA850_MMCSD_WP_PIN);
ret = da8xx_register_mmcsd0(&da850_mmc_config);
if (ret)
- pr_warning("da850_evm_init: mmcsd0 registration failed:"
- " %d\n", ret);
+ pr_warn("%s: MMCSD0 registration failed: %d\n",
+ __func__, ret);
ret = da850_wl12xx_init();
if (ret)
- pr_warning("da850_evm_init: wl12xx initialization"
- " failed: %d\n", ret);
+ pr_warn("%s: WL12xx initialization failed: %d\n",
+ __func__, ret);
}
davinci_serial_init(&da850_evm_uart_config);
@@ -1511,16 +1517,14 @@ static __init void da850_evm_init(void)
ret = davinci_cfg_reg_list(da850_evm_mcasp_pins);
if (ret)
- pr_warning("da850_evm_init: mcasp mux setup failed: %d\n",
- ret);
+ pr_warn("%s: McASP mux setup failed: %d\n", __func__, ret);
da850_evm_snd_data.sram_pool = sram_get_gen_pool();
da8xx_register_mcasp(0, &da850_evm_snd_data);
ret = davinci_cfg_reg_list(da850_lcdcntl_pins);
if (ret)
- pr_warning("da850_evm_init: lcdcntl mux setup failed: %d\n",
- ret);
+ pr_warn("%s: LCDC mux setup failed: %d\n", __func__, ret);
ret = da8xx_register_uio_pruss();
if (ret)
@@ -1530,51 +1534,49 @@ static __init void da850_evm_init(void)
/* Handle board specific muxing for LCD here */
ret = davinci_cfg_reg_list(da850_evm_lcdc_pins);
if (ret)
- pr_warning("da850_evm_init: evm specific lcd mux setup "
- "failed: %d\n", ret);
+ pr_warn("%s: EVM specific LCD mux setup failed: %d\n",
+ __func__, ret);
ret = da850_lcd_hw_init();
if (ret)
- pr_warning("da850_evm_init: lcd initialization failed: %d\n",
- ret);
+ pr_warn("%s: LCD initialization failed: %d\n", __func__, ret);
sharp_lk043t1dg01_pdata.panel_power_ctrl = da850_panel_power_ctrl,
ret = da8xx_register_lcdc(&sharp_lk043t1dg01_pdata);
if (ret)
- pr_warning("da850_evm_init: lcdc registration failed: %d\n",
- ret);
+ pr_warn("%s: LCDC registration failed: %d\n", __func__, ret);
ret = da8xx_register_rtc();
if (ret)
- pr_warning("da850_evm_init: rtc setup failed: %d\n", ret);
+ pr_warn("%s: RTC setup failed: %d\n", __func__, ret);
ret = da850_evm_init_cpufreq();
if (ret)
- pr_warning("da850_evm_init: cpufreq registration failed: %d\n",
- ret);
+ pr_warn("%s: cpufreq registration failed: %d\n", __func__, ret);
ret = da8xx_register_cpuidle();
if (ret)
- pr_warning("da850_evm_init: cpuidle registration failed: %d\n",
- ret);
+ pr_warn("%s: cpuidle registration failed: %d\n", __func__, ret);
ret = da850_register_pm(&da850_pm_device);
if (ret)
- pr_warning("da850_evm_init: suspend registration failed: %d\n",
- ret);
+ pr_warn("%s: suspend registration failed: %d\n", __func__, ret);
da850_vpif_init();
- ret = da8xx_register_spi(1, da850evm_spi_info,
- ARRAY_SIZE(da850evm_spi_info));
+ ret = spi_register_board_info(da850evm_spi_info,
+ ARRAY_SIZE(da850evm_spi_info));
if (ret)
- pr_warning("da850_evm_init: spi 1 registration failed: %d\n",
- ret);
+ pr_warn("%s: spi info registration failed: %d\n", __func__,
+ ret);
+
+ ret = da8xx_register_spi_bus(1, ARRAY_SIZE(da850evm_spi_info));
+ if (ret)
+ pr_warn("%s: SPI 1 registration failed: %d\n", __func__, ret);
ret = da850_register_sata(DA850EVM_SATA_REFCLKPN_RATE);
if (ret)
- pr_warning("da850_evm_init: sata registration failed: %d\n",
- ret);
+ pr_warn("%s: SATA registration failed: %d\n", __func__, ret);
da850_evm_setup_mac_addr();
}
@@ -1599,7 +1601,7 @@ MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138/AM18x EVM")
.atag_offset = 0x100,
.map_io = da850_evm_map_io,
.init_irq = cp_intc_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = da850_evm_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index cdf8d0746e79..147b8e1a4407 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -355,7 +355,7 @@ MACHINE_START(DAVINCI_DM355_EVM, "DaVinci DM355 EVM")
.atag_offset = 0x100,
.map_io = dm355_evm_map_io,
.init_irq = davinci_irq_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = dm355_evm_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c
index d41954507fc2..dff4ddc5ef81 100644
--- a/arch/arm/mach-davinci/board-dm355-leopard.c
+++ b/arch/arm/mach-davinci/board-dm355-leopard.c
@@ -274,7 +274,7 @@ MACHINE_START(DM355_LEOPARD, "DaVinci DM355 leopard")
.atag_offset = 0x100,
.map_io = dm355_leopard_map_io,
.init_irq = davinci_irq_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = dm355_leopard_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index 5d49c75388ca..c2d4958a0cb6 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -616,7 +616,7 @@ MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM365 EVM")
.atag_offset = 0x100,
.map_io = dm365_evm_map_io,
.init_irq = davinci_irq_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = dm365_evm_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index f5e018de7fa5..71735e7797cc 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -690,7 +690,7 @@ static struct vpbe_output dm644xevm_vpbe_outputs[] = {
.std = VENC_STD_ALL,
.capabilities = V4L2_OUT_CAP_STD,
},
- .subdev_name = VPBE_VENC_SUBDEV_NAME,
+ .subdev_name = DM644X_VPBE_VENC_SUBDEV_NAME,
.default_mode = "ntsc",
.num_modes = ARRAY_SIZE(dm644xevm_enc_std_timing),
.modes = dm644xevm_enc_std_timing,
@@ -702,7 +702,7 @@ static struct vpbe_output dm644xevm_vpbe_outputs[] = {
.type = V4L2_OUTPUT_TYPE_ANALOG,
.capabilities = V4L2_OUT_CAP_DV_TIMINGS,
},
- .subdev_name = VPBE_VENC_SUBDEV_NAME,
+ .subdev_name = DM644X_VPBE_VENC_SUBDEV_NAME,
.default_mode = "480p59_94",
.num_modes = ARRAY_SIZE(dm644xevm_enc_preset_timing),
.modes = dm644xevm_enc_preset_timing,
@@ -713,10 +713,10 @@ static struct vpbe_config dm644xevm_display_cfg = {
.module_name = "dm644x-vpbe-display",
.i2c_adapter_id = 1,
.osd = {
- .module_name = VPBE_OSD_SUBDEV_NAME,
+ .module_name = DM644X_VPBE_OSD_SUBDEV_NAME,
},
.venc = {
- .module_name = VPBE_VENC_SUBDEV_NAME,
+ .module_name = DM644X_VPBE_VENC_SUBDEV_NAME,
},
.num_outputs = ARRAY_SIZE(dm644xevm_vpbe_outputs),
.outputs = dm644xevm_vpbe_outputs,
@@ -825,7 +825,7 @@ MACHINE_START(DAVINCI_EVM, "DaVinci DM644x EVM")
.atag_offset = 0x100,
.map_io = davinci_evm_map_io,
.init_irq = davinci_irq_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = davinci_evm_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index 6e2f1631df5b..de7adff324dc 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -818,7 +818,7 @@ MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
.atag_offset = 0x100,
.map_io = davinci_map_io,
.init_irq = davinci_irq_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = evm_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
@@ -829,7 +829,7 @@ MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM")
.atag_offset = 0x100,
.map_io = davinci_map_io,
.init_irq = davinci_irq_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = evm_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c
index 43e4a0d663fa..9549d53aa63f 100644
--- a/arch/arm/mach-davinci/board-mityomapl138.c
+++ b/arch/arm/mach-davinci/board-mityomapl138.c
@@ -529,8 +529,13 @@ static void __init mityomapl138_init(void)
mityomapl138_setup_nand();
- ret = da8xx_register_spi(1, mityomapl138_spi_flash_info,
- ARRAY_SIZE(mityomapl138_spi_flash_info));
+ ret = spi_register_board_info(mityomapl138_spi_flash_info,
+ ARRAY_SIZE(mityomapl138_spi_flash_info));
+ if (ret)
+ pr_warn("spi info registration failed: %d\n", ret);
+
+ ret = da8xx_register_spi_bus(1,
+ ARRAY_SIZE(mityomapl138_spi_flash_info));
if (ret)
pr_warning("spi 1 registration failed: %d\n", ret);
@@ -570,7 +575,7 @@ MACHINE_START(MITYOMAPL138, "MityDSP-L138/MityARM-1808")
.atag_offset = 0x100,
.map_io = mityomapl138_map_io,
.init_irq = cp_intc_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = mityomapl138_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c
index 3e3e3afebf88..1c98107527fa 100644
--- a/arch/arm/mach-davinci/board-neuros-osd2.c
+++ b/arch/arm/mach-davinci/board-neuros-osd2.c
@@ -237,7 +237,7 @@ MACHINE_START(NEUROS_OSD2, "Neuros OSD2")
.atag_offset = 0x100,
.map_io = davinci_ntosd2_map_io,
.init_irq = davinci_irq_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = davinci_ntosd2_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index dc1208e9e664..5a2bd44da54d 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -48,8 +48,7 @@ static __init void omapl138_hawk_config_emac(void)
val &= ~BIT(8);
ret = davinci_cfg_reg_list(omapl138_hawk_mii_pins);
if (ret) {
- pr_warning("%s: cpgmac/mii mux setup failed: %d\n",
- __func__, ret);
+ pr_warn("%s: CPGMAC/MII mux setup failed: %d\n", __func__, ret);
return;
}
@@ -61,8 +60,7 @@ static __init void omapl138_hawk_config_emac(void)
ret = da8xx_register_emac();
if (ret)
- pr_warning("%s: emac registration failed: %d\n",
- __func__, ret);
+ pr_warn("%s: EMAC registration failed: %d\n", __func__, ret);
}
/*
@@ -147,15 +145,14 @@ static __init void omapl138_hawk_mmc_init(void)
ret = davinci_cfg_reg_list(hawk_mmcsd0_pins);
if (ret) {
- pr_warning("%s: MMC/SD0 mux setup failed: %d\n",
- __func__, ret);
+ pr_warn("%s: MMC/SD0 mux setup failed: %d\n", __func__, ret);
return;
}
ret = gpio_request_one(DA850_HAWK_MMCSD_CD_PIN,
GPIOF_DIR_IN, "MMC CD");
if (ret < 0) {
- pr_warning("%s: can not open GPIO %d\n",
+ pr_warn("%s: can not open GPIO %d\n",
__func__, DA850_HAWK_MMCSD_CD_PIN);
return;
}
@@ -163,15 +160,14 @@ static __init void omapl138_hawk_mmc_init(void)
ret = gpio_request_one(DA850_HAWK_MMCSD_WP_PIN,
GPIOF_DIR_IN, "MMC WP");
if (ret < 0) {
- pr_warning("%s: can not open GPIO %d\n",
+ pr_warn("%s: can not open GPIO %d\n",
__func__, DA850_HAWK_MMCSD_WP_PIN);
goto mmc_setup_wp_fail;
}
ret = da8xx_register_mmcsd0(&da850_mmc_config);
if (ret) {
- pr_warning("%s: MMC/SD0 registration failed: %d\n",
- __func__, ret);
+ pr_warn("%s: MMC/SD0 registration failed: %d\n", __func__, ret);
goto mmc_setup_mmcsd_fail;
}
@@ -250,8 +246,7 @@ static __init void omapl138_hawk_usb_init(void)
ret = davinci_cfg_reg_list(da850_hawk_usb11_pins);
if (ret) {
- pr_warning("%s: USB 1.1 PinMux setup failed: %d\n",
- __func__, ret);
+ pr_warn("%s: USB 1.1 PinMux setup failed: %d\n", __func__, ret);
return;
}
@@ -280,8 +275,7 @@ static __init void omapl138_hawk_usb_init(void)
ret = da8xx_register_usb11(&omapl138_hawk_usb11_pdata);
if (ret) {
- pr_warning("%s: USB 1.1 registration failed: %d\n",
- __func__, ret);
+ pr_warn("%s: USB 1.1 registration failed: %d\n", __func__, ret);
goto usb11_setup_fail;
}
@@ -307,8 +301,7 @@ static __init void omapl138_hawk_init(void)
ret = da850_register_edma(da850_edma_rsv);
if (ret)
- pr_warning("%s: EDMA registration failed: %d\n",
- __func__, ret);
+ pr_warn("%s: EDMA registration failed: %d\n", __func__, ret);
omapl138_hawk_mmc_init();
@@ -316,9 +309,8 @@ static __init void omapl138_hawk_init(void)
ret = da8xx_register_watchdog();
if (ret)
- pr_warning("omapl138_hawk_init: "
- "watchdog registration failed: %d\n",
- ret);
+ pr_warn("%s: watchdog registration failed: %d\n",
+ __func__, ret);
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
@@ -341,7 +333,7 @@ MACHINE_START(OMAPL138_HAWKBOARD, "AM18x/OMAP-L138 Hawkboard")
.atag_offset = 0x100,
.map_io = omapl138_hawk_map_io,
.init_irq = cp_intc_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = omapl138_hawk_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c
index 6957787fa7f3..739be7e738fe 100644
--- a/arch/arm/mach-davinci/board-sffsdr.c
+++ b/arch/arm/mach-davinci/board-sffsdr.c
@@ -155,7 +155,7 @@ MACHINE_START(SFFSDR, "Lyrtech SFFSDR")
.atag_offset = 0x100,
.map_io = davinci_sffsdr_map_io,
.init_irq = davinci_irq_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = davinci_sffsdr_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index be3099733b1f..4f416023d4e2 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -280,7 +280,7 @@ MACHINE_START(TNETV107X, "TNETV107X EVM")
.atag_offset = 0x100,
.map_io = tnetv107x_init,
.init_irq = cp_intc_init,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = tnetv107x_evm_board_init,
.init_late = davinci_init_late,
.dma_zone_size = SZ_128M,
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 34668ead53c7..d458558ee84a 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -52,6 +52,40 @@ static void __clk_disable(struct clk *clk)
__clk_disable(clk->parent);
}
+int davinci_clk_reset(struct clk *clk, bool reset)
+{
+ unsigned long flags;
+
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+ if (clk->flags & CLK_PSC)
+ davinci_psc_reset(clk->gpsc, clk->lpsc, reset);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(davinci_clk_reset);
+
+int davinci_clk_reset_assert(struct clk *clk)
+{
+ if (clk == NULL || IS_ERR(clk) || !clk->reset)
+ return -EINVAL;
+
+ return clk->reset(clk, true);
+}
+EXPORT_SYMBOL(davinci_clk_reset_assert);
+
+int davinci_clk_reset_deassert(struct clk *clk)
+{
+ if (clk == NULL || IS_ERR(clk) || !clk->reset)
+ return -EINVAL;
+
+ return clk->reset(clk, false);
+}
+EXPORT_SYMBOL(davinci_clk_reset_deassert);
+
int clk_enable(struct clk *clk)
{
unsigned long flags;
@@ -535,7 +569,7 @@ int davinci_set_refclk_rate(unsigned long rate)
}
int __init davinci_clk_init(struct clk_lookup *clocks)
- {
+{
struct clk_lookup *c;
struct clk *clk;
size_t num_clocks = 0;
@@ -576,6 +610,9 @@ int __init davinci_clk_init(struct clk_lookup *clocks)
if (clk->lpsc)
clk->flags |= CLK_PSC;
+ if (clk->flags & PSC_LRST)
+ clk->reset = davinci_clk_reset;
+
clk_register(clk);
num_clocks++;
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
index 46f0f1bf1a4c..8694b395fc92 100644
--- a/arch/arm/mach-davinci/clock.h
+++ b/arch/arm/mach-davinci/clock.h
@@ -103,6 +103,7 @@ struct clk {
unsigned long (*recalc) (struct clk *);
int (*set_rate) (struct clk *clk, unsigned long rate);
int (*round_rate) (struct clk *clk, unsigned long rate);
+ int (*reset) (struct clk *clk, bool reset);
};
/* Clock flags: SoC-specific flags start at BIT(16) */
@@ -112,6 +113,7 @@ struct clk {
#define PRE_PLL BIT(4) /* source is before PLL mult/div */
#define PSC_SWRSTDISABLE BIT(5) /* Disable state is SwRstDisable */
#define PSC_FORCE BIT(6) /* Force module state transtition */
+#define PSC_LRST BIT(8) /* Use local reset on enable/disable */
#define CLK(dev, con, ck) \
{ \
@@ -126,6 +128,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate);
int davinci_set_refclk_rate(unsigned long rate);
int davinci_simple_set_rate(struct clk *clk, unsigned long rate);
+int davinci_clk_reset(struct clk *clk, bool reset);
extern struct platform_device davinci_wdt_device;
extern void davinci_watchdog_reset(struct platform_device *);
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index 9107691adbdb..5ac9e9384b15 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -25,35 +25,44 @@
#define DAVINCI_CPUIDLE_MAX_STATES 2
-struct davinci_ops {
- void (*enter) (u32 flags);
- void (*exit) (u32 flags);
- u32 flags;
-};
+static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device);
+static void __iomem *ddr2_reg_base;
+static bool ddr2_pdown;
+
+static void davinci_save_ddr_power(int enter, bool pdown)
+{
+ u32 val;
+
+ val = __raw_readl(ddr2_reg_base + DDR2_SDRCR_OFFSET);
+
+ if (enter) {
+ if (pdown)
+ val |= DDR2_SRPD_BIT;
+ else
+ val &= ~DDR2_SRPD_BIT;
+ val |= DDR2_LPMODEN_BIT;
+ } else {
+ val &= ~(DDR2_SRPD_BIT | DDR2_LPMODEN_BIT);
+ }
+
+ __raw_writel(val, ddr2_reg_base + DDR2_SDRCR_OFFSET);
+}
/* Actual code that puts the SoC in different idle states */
static int davinci_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
- struct davinci_ops *ops = cpuidle_get_statedata(state_usage);
-
- if (ops && ops->enter)
- ops->enter(ops->flags);
+ davinci_save_ddr_power(1, ddr2_pdown);
index = cpuidle_wrap_enter(dev, drv, index,
arm_cpuidle_simple_enter);
- if (ops && ops->exit)
- ops->exit(ops->flags);
+ davinci_save_ddr_power(0, ddr2_pdown);
return index;
}
-/* fields in davinci_ops.flags */
-#define DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN BIT(0)
-
static struct cpuidle_driver davinci_idle_driver = {
.name = "cpuidle-davinci",
.owner = THIS_MODULE,
@@ -70,45 +79,6 @@ static struct cpuidle_driver davinci_idle_driver = {
.state_count = DAVINCI_CPUIDLE_MAX_STATES,
};
-static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device);
-static void __iomem *ddr2_reg_base;
-
-static void davinci_save_ddr_power(int enter, bool pdown)
-{
- u32 val;
-
- val = __raw_readl(ddr2_reg_base + DDR2_SDRCR_OFFSET);
-
- if (enter) {
- if (pdown)
- val |= DDR2_SRPD_BIT;
- else
- val &= ~DDR2_SRPD_BIT;
- val |= DDR2_LPMODEN_BIT;
- } else {
- val &= ~(DDR2_SRPD_BIT | DDR2_LPMODEN_BIT);
- }
-
- __raw_writel(val, ddr2_reg_base + DDR2_SDRCR_OFFSET);
-}
-
-static void davinci_c2state_enter(u32 flags)
-{
- davinci_save_ddr_power(1, !!(flags & DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN));
-}
-
-static void davinci_c2state_exit(u32 flags)
-{
- davinci_save_ddr_power(0, !!(flags & DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN));
-}
-
-static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
- [1] = {
- .enter = davinci_c2state_enter,
- .exit = davinci_c2state_exit,
- },
-};
-
static int __init davinci_cpuidle_probe(struct platform_device *pdev)
{
int ret;
@@ -124,11 +94,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
ddr2_reg_base = pdata->ddr2_ctlr_base;
- if (pdata->ddr2_pdown)
- davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
- cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]);
-
- device->state_count = DAVINCI_CPUIDLE_MAX_STATES;
+ ddr2_pdown = pdata->ddr2_pdown;
ret = cpuidle_register_driver(&davinci_idle_driver);
if (ret) {
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 6b9154e9f908..0c4a26ddebba 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -76,6 +76,13 @@ static struct clk pll0_aux_clk = {
.flags = CLK_PLL | PRE_PLL,
};
+static struct clk pll0_sysclk1 = {
+ .name = "pll0_sysclk1",
+ .parent = &pll0_clk,
+ .flags = CLK_PLL,
+ .div_reg = PLLDIV1,
+};
+
static struct clk pll0_sysclk2 = {
.name = "pll0_sysclk2",
.parent = &pll0_clk,
@@ -368,10 +375,19 @@ static struct clk sata_clk = {
.flags = PSC_FORCE,
};
+static struct clk dsp_clk = {
+ .name = "dsp",
+ .parent = &pll0_sysclk1,
+ .domain = DAVINCI_GPSC_DSPDOMAIN,
+ .lpsc = DA8XX_LPSC0_GEM,
+ .flags = PSC_LRST | PSC_FORCE,
+};
+
static struct clk_lookup da850_clks[] = {
CLK(NULL, "ref", &ref_clk),
CLK(NULL, "pll0", &pll0_clk),
CLK(NULL, "pll0_aux", &pll0_aux_clk),
+ CLK(NULL, "pll0_sysclk1", &pll0_sysclk1),
CLK(NULL, "pll0_sysclk2", &pll0_sysclk2),
CLK(NULL, "pll0_sysclk3", &pll0_sysclk3),
CLK(NULL, "pll0_sysclk4", &pll0_sysclk4),
@@ -413,6 +429,7 @@ static struct clk_lookup da850_clks[] = {
CLK("spi_davinci.1", NULL, &spi1_clk),
CLK("vpif", NULL, &vpif_clk),
CLK("ahci", NULL, &sata_clk),
+ CLK("davinci-rproc.0", NULL, &dsp_clk),
CLK(NULL, NULL, NULL),
};
diff --git a/arch/arm/mach-davinci/da8xx-dt.c b/arch/arm/mach-davinci/da8xx-dt.c
index 37c27af18fa0..6b7a0a27fbd1 100644
--- a/arch/arm/mach-davinci/da8xx-dt.c
+++ b/arch/arm/mach-davinci/da8xx-dt.c
@@ -37,11 +37,18 @@ static void __init da8xx_init_irq(void)
of_irq_init(da8xx_irq_match);
}
+struct of_dev_auxdata da850_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("ti,davinci-i2c", 0x01c22000, "i2c_davinci.1", NULL),
+ OF_DEV_AUXDATA("ti,davinci-wdt", 0x01c21000, "watchdog", NULL),
+ {}
+};
+
#ifdef CONFIG_ARCH_DAVINCI_DA850
static void __init da850_init_machine(void)
{
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ of_platform_populate(NULL, of_default_bus_match_table,
+ da850_auxdata_lookup, NULL);
da8xx_uart_clk_enable();
}
@@ -56,7 +63,7 @@ static const char *da850_boards_compat[] __initdata = {
DT_MACHINE_START(DA850_DT, "Generic DA850/OMAP-L138/AM18x")
.map_io = da850_init,
.init_irq = da8xx_init_irq,
- .timer = &davinci_timer,
+ .init_time = davinci_timer_init,
.init_machine = da850_init_machine,
.dt_compat = da850_boards_compat,
.init_late = davinci_init_late,
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 2d5502d84a22..fc50243b1481 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -359,7 +359,7 @@ static struct resource da8xx_watchdog_resources[] = {
},
};
-struct platform_device da8xx_wdt_device = {
+static struct platform_device da8xx_wdt_device = {
.name = "watchdog",
.id = -1,
.num_resources = ARRAY_SIZE(da8xx_watchdog_resources),
@@ -368,7 +368,15 @@ struct platform_device da8xx_wdt_device = {
void da8xx_restart(char mode, const char *cmd)
{
- davinci_watchdog_reset(&da8xx_wdt_device);
+ struct device *dev;
+
+ dev = bus_find_device_by_name(&platform_bus_type, NULL, "watchdog");
+ if (!dev) {
+ pr_err("%s: failed to find watchdog device\n", __func__);
+ return;
+ }
+
+ davinci_watchdog_reset(to_platform_device(dev));
}
int __init da8xx_register_watchdog(void)
@@ -751,7 +759,7 @@ void __iomem * __init da8xx_get_mem_ctlr(void)
da8xx_ddr2_ctlr_base = ioremap(DA8XX_DDR2_CTL_BASE, SZ_32K);
if (!da8xx_ddr2_ctlr_base)
- pr_warning("%s: Unable to map DDR2 controller", __func__);
+ pr_warn("%s: Unable to map DDR2 controller", __func__);
return da8xx_ddr2_ctlr_base;
}
@@ -832,7 +840,7 @@ static struct resource da8xx_spi1_resources[] = {
},
};
-struct davinci_spi_platform_data da8xx_spi_pdata[] = {
+static struct davinci_spi_platform_data da8xx_spi_pdata[] = {
[0] = {
.version = SPI_VERSION_2,
.intr_line = 1,
@@ -866,20 +874,12 @@ static struct platform_device da8xx_spi_device[] = {
},
};
-int __init da8xx_register_spi(int instance, const struct spi_board_info *info,
- unsigned len)
+int __init da8xx_register_spi_bus(int instance, unsigned num_chipselect)
{
- int ret;
-
if (instance < 0 || instance > 1)
return -EINVAL;
- ret = spi_register_board_info(info, len);
- if (ret)
- pr_warning("%s: failed to register board info for spi %d :"
- " %d\n", __func__, instance, ret);
-
- da8xx_spi_pdata[instance].num_chipselect = len;
+ da8xx_spi_pdata[instance].num_chipselect = num_chipselect;
if (instance == 1 && cpu_is_davinci_da850()) {
da8xx_spi1_resources[0].start = DA850_SPI1_BASE;
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index 11c79a3362ef..db1dd92e00af 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -669,19 +669,14 @@ static struct resource dm644x_osd_resources[] = {
},
};
-static struct osd_platform_data dm644x_osd_data = {
- .vpbe_type = VPBE_VERSION_1,
-};
-
static struct platform_device dm644x_osd_dev = {
- .name = VPBE_OSD_SUBDEV_NAME,
+ .name = DM644X_VPBE_OSD_SUBDEV_NAME,
.id = -1,
.num_resources = ARRAY_SIZE(dm644x_osd_resources),
.resource = dm644x_osd_resources,
.dev = {
.dma_mask = &dm644x_video_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &dm644x_osd_data,
},
};
@@ -751,12 +746,11 @@ static struct platform_device dm644x_vpbe_display = {
};
static struct venc_platform_data dm644x_venc_pdata = {
- .venc_type = VPBE_VERSION_1,
.setup_clock = dm644x_venc_setup_clock,
};
static struct platform_device dm644x_venc_dev = {
- .name = VPBE_VENC_SUBDEV_NAME,
+ .name = DM644X_VPBE_VENC_SUBDEV_NAME,
.id = -1,
.num_resources = ARRAY_SIZE(dm644x_venc_resources),
.resource = dm644x_venc_resources,
diff --git a/arch/arm/mach-davinci/include/mach/clock.h b/arch/arm/mach-davinci/include/mach/clock.h
index a3b040219876..3e8af6a0b64c 100644
--- a/arch/arm/mach-davinci/include/mach/clock.h
+++ b/arch/arm/mach-davinci/include/mach/clock.h
@@ -18,4 +18,7 @@ struct clk;
extern int clk_register(struct clk *clk);
extern void clk_unregister(struct clk *clk);
+int davinci_clk_reset_assert(struct clk *c);
+int davinci_clk_reset_deassert(struct clk *c);
+
#endif
diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h
index 046c7238a3d6..b124b77c90c5 100644
--- a/arch/arm/mach-davinci/include/mach/common.h
+++ b/arch/arm/mach-davinci/include/mach/common.h
@@ -15,9 +15,7 @@
#include <linux/compiler.h>
#include <linux/types.h>
-struct sys_timer;
-
-extern struct sys_timer davinci_timer;
+extern void davinci_timer_init(void);
extern void davinci_irq_init(void);
extern void __iomem *davinci_intc_base;
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 700d311c6854..de439b7b9af1 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -82,8 +82,7 @@ void __init da850_init(void);
int da830_register_edma(struct edma_rsv_info *rsv);
int da850_register_edma(struct edma_rsv_info *rsv[2]);
int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata);
-int da8xx_register_spi(int instance,
- const struct spi_board_info *info, unsigned len);
+int da8xx_register_spi_bus(int instance, unsigned num_chipselect);
int da8xx_register_watchdog(void);
int da8xx_register_usb20(unsigned mA, unsigned potpgt);
int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
@@ -110,9 +109,7 @@ extern struct platform_device da8xx_serial_device;
extern struct emac_platform_data da8xx_emac_pdata;
extern struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata;
extern struct da8xx_lcdc_platform_data sharp_lk043t1dg01_pdata;
-extern struct davinci_spi_platform_data da8xx_spi_pdata[];
-extern struct platform_device da8xx_wdt_device;
extern const short da830_emif25_pins[];
extern const short da830_spi0_pins[];
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h
index 40a0027838e8..0a22710493fd 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/include/mach/psc.h
@@ -246,6 +246,7 @@
#define MDSTAT_STATE_MASK 0x3f
#define PDSTAT_STATE_MASK 0x1f
+#define MDCTL_LRST BIT(8)
#define MDCTL_FORCE BIT(31)
#define PDCTL_NEXT BIT(0)
#define PDCTL_EPCGOOD BIT(8)
@@ -253,6 +254,8 @@
#ifndef __ASSEMBLER__
extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id);
+extern void davinci_psc_reset(unsigned int ctlr, unsigned int id,
+ bool reset);
extern void davinci_psc_config(unsigned int domain, unsigned int ctlr,
unsigned int id, bool enable, u32 flags);
diff --git a/arch/arm/mach-davinci/include/mach/uncompress.h b/arch/arm/mach-davinci/include/mach/uncompress.h
index 3a0ff905a69b..f49c2916aa3a 100644
--- a/arch/arm/mach-davinci/include/mach/uncompress.h
+++ b/arch/arm/mach-davinci/include/mach/uncompress.h
@@ -101,4 +101,3 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
}
#define arch_decomp_setup() __arch_decomp_setup(arch_id)
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
index d7e210f4b55c..82fdc69d5728 100644
--- a/arch/arm/mach-davinci/psc.c
+++ b/arch/arm/mach-davinci/psc.c
@@ -35,7 +35,7 @@ int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id)
struct davinci_soc_info *soc_info = &davinci_soc_info;
if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) {
- pr_warning("PSC: Bad psc data: 0x%x[%d]\n",
+ pr_warn("PSC: Bad psc data: 0x%x[%d]\n",
(int)soc_info->psc_bases, ctlr);
return 0;
}
@@ -48,6 +48,31 @@ int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id)
return mdstat & BIT(12);
}
+/* Control "reset" line associated with PSC domain */
+void davinci_psc_reset(unsigned int ctlr, unsigned int id, bool reset)
+{
+ u32 mdctl;
+ void __iomem *psc_base;
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+ if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) {
+ pr_warn("PSC: Bad psc data: 0x%x[%d]\n",
+ (int)soc_info->psc_bases, ctlr);
+ return;
+ }
+
+ psc_base = ioremap(soc_info->psc_bases[ctlr], SZ_4K);
+
+ mdctl = readl(psc_base + MDCTL + 4 * id);
+ if (reset)
+ mdctl &= ~MDCTL_LRST;
+ else
+ mdctl |= MDCTL_LRST;
+ writel(mdctl, psc_base + MDCTL + 4 * id);
+
+ iounmap(psc_base);
+}
+
/* Enable or disable a PSC domain */
void davinci_psc_config(unsigned int domain, unsigned int ctlr,
unsigned int id, bool enable, u32 flags)
@@ -58,7 +83,7 @@ void davinci_psc_config(unsigned int domain, unsigned int ctlr,
u32 next_state = PSC_STATE_ENABLE;
if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) {
- pr_warning("PSC: Bad psc data: 0x%x[%d]\n",
+ pr_warn("PSC: Bad psc data: 0x%x[%d]\n",
(int)soc_info->psc_bases, ctlr);
return;
}
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 9847938785ca..bad361ec1666 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -337,7 +337,7 @@ static struct clock_event_device clockevent_davinci = {
};
-static void __init davinci_timer_init(void)
+void __init davinci_timer_init(void)
{
struct clk *timer_clk;
struct davinci_soc_info *soc_info = &davinci_soc_info;
@@ -410,11 +410,6 @@ static void __init davinci_timer_init(void)
timer32_config(&timers[i]);
}
-struct sys_timer davinci_timer = {
- .init = davinci_timer_init,
-};
-
-
/* reset board using watchdog timer */
void davinci_watchdog_reset(struct platform_device *pdev)
{
diff --git a/arch/arm/mach-dove/cm-a510.c b/arch/arm/mach-dove/cm-a510.c
index 792b4e2e24f1..0dc39cf30fdd 100644
--- a/arch/arm/mach-dove/cm-a510.c
+++ b/arch/arm/mach-dove/cm-a510.c
@@ -92,6 +92,6 @@ MACHINE_START(CM_A510, "Compulab CM-A510 Board")
.map_io = dove_map_io,
.init_early = dove_init_early,
.init_irq = dove_init_irq,
- .timer = &dove_timer,
+ .init_time = dove_timer_init,
.restart = dove_restart,
MACHINE_END
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index 89f4f993cd03..ea84c535a110 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -8,35 +8,24 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/pci.h>
#include <linux/clk-provider.h>
#include <linux/clk/mvebu.h>
-#include <linux/ata_platform.h>
-#include <linux/gpio.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <asm/page.h>
-#include <asm/setup.h>
-#include <asm/timex.h>
+#include <linux/platform_data/dma-mv_xor.h>
+#include <linux/platform_data/usb-ehci-orion.h>
+#include <linux/platform_device.h>
#include <asm/hardware/cache-tauros2.h>
+#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <asm/mach/pci.h>
-#include <mach/dove.h>
-#include <mach/pm.h>
#include <mach/bridge-regs.h>
-#include <asm/mach/arch.h>
-#include <linux/irq.h>
-#include <plat/time.h>
-#include <linux/platform_data/usb-ehci-orion.h>
-#include <linux/platform_data/dma-mv_xor.h>
-#include <plat/irq.h>
+#include <mach/pm.h>
#include <plat/common.h>
-#include <plat/addr-map.h>
+#include <plat/irq.h>
+#include <plat/time.h>
#include "common.h"
/*****************************************************************************
@@ -242,17 +231,13 @@ static int __init dove_find_tclk(void)
return 166666667;
}
-static void __init dove_timer_init(void)
+void __init dove_timer_init(void)
{
dove_tclk = dove_find_tclk();
orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
IRQ_DOVE_BRIDGE, dove_tclk);
}
-struct sys_timer dove_timer = {
- .init = dove_timer_init,
-};
-
/*****************************************************************************
* Cryptographic Engines and Security Accelerator (CESA)
****************************************************************************/
@@ -454,7 +439,7 @@ DT_MACHINE_START(DOVE_DT, "Marvell Dove (Flattened Device Tree)")
.map_io = dove_map_io,
.init_early = dove_init_early,
.init_irq = orion_dt_init_irq,
- .timer = &dove_timer,
+ .init_time = dove_timer_init,
.init_machine = dove_dt_init,
.restart = dove_restart,
.dt_compat = dove_dt_board_compat,
diff --git a/arch/arm/mach-dove/common.h b/arch/arm/mach-dove/common.h
index 1a233404b735..ee59fba4c6d1 100644
--- a/arch/arm/mach-dove/common.h
+++ b/arch/arm/mach-dove/common.h
@@ -14,7 +14,7 @@
struct mv643xx_eth_platform_data;
struct mv_sata_platform_data;
-extern struct sys_timer dove_timer;
+extern void dove_timer_init(void);
/*
* Basic Dove init functions used early by machine-setup.
diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c
index bc2867f11346..76e26f949c27 100644
--- a/arch/arm/mach-dove/dove-db-setup.c
+++ b/arch/arm/mach-dove/dove-db-setup.c
@@ -98,6 +98,6 @@ MACHINE_START(DOVE_DB, "Marvell DB-MV88AP510-BP Development Board")
.map_io = dove_map_io,
.init_early = dove_init_early,
.init_irq = dove_init_irq,
- .timer = &dove_timer,
+ .init_time = dove_timer_init,
.restart = dove_restart,
MACHINE_END
diff --git a/arch/arm/mach-dove/include/mach/uncompress.h b/arch/arm/mach-dove/include/mach/uncompress.h
index 2c5cdd7a3eed..5c8ae9b9d39a 100644
--- a/arch/arm/mach-dove/include/mach/uncompress.h
+++ b/arch/arm/mach-dove/include/mach/uncompress.h
@@ -34,4 +34,3 @@ static void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index f0fe6b5350e2..b13cc74114db 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -158,7 +158,7 @@ static void __init ebsa110_init_early(void)
* interrupt, then the PIT counter will roll over (ie, be negative).
* This actually works out to be convenient.
*/
-static unsigned long ebsa110_gettimeoffset(void)
+static u32 ebsa110_gettimeoffset(void)
{
unsigned long offset, count;
@@ -181,7 +181,7 @@ static unsigned long ebsa110_gettimeoffset(void)
*/
offset = offset * (1000000 / HZ) / COUNT;
- return offset;
+ return offset * 1000;
}
static irqreturn_t
@@ -213,8 +213,10 @@ static struct irqaction ebsa110_timer_irq = {
/*
* Set up timer interrupt.
*/
-static void __init ebsa110_timer_init(void)
+void __init ebsa110_timer_init(void)
{
+ arch_gettimeoffset = ebsa110_gettimeoffset;
+
/*
* Timer 1, mode 2, LSB/MSB
*/
@@ -225,11 +227,6 @@ static void __init ebsa110_timer_init(void)
setup_irq(IRQ_EBSA110_TIMER0, &ebsa110_timer_irq);
}
-static struct sys_timer ebsa110_timer = {
- .init = ebsa110_timer_init,
- .offset = ebsa110_gettimeoffset,
-};
-
static struct plat_serial8250_port serial_platform_data[] = {
{
.iobase = 0x3f8,
@@ -328,6 +325,6 @@ MACHINE_START(EBSA110, "EBSA110")
.map_io = ebsa110_map_io,
.init_early = ebsa110_init_early,
.init_irq = ebsa110_init_irq,
- .timer = &ebsa110_timer,
+ .init_time = ebsa110_timer_init,
.restart = ebsa110_restart,
MACHINE_END
diff --git a/arch/arm/mach-ebsa110/include/mach/uncompress.h b/arch/arm/mach-ebsa110/include/mach/uncompress.h
index 32041509fbf8..ab64bea69c72 100644
--- a/arch/arm/mach-ebsa110/include/mach/uncompress.h
+++ b/arch/arm/mach-ebsa110/include/mach/uncompress.h
@@ -42,4 +42,3 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-ep93xx/adssphere.c b/arch/arm/mach-ep93xx/adssphere.c
index 41383bf03d4b..bda6c3a5c923 100644
--- a/arch/arm/mach-ep93xx/adssphere.c
+++ b/arch/arm/mach-ep93xx/adssphere.c
@@ -17,7 +17,6 @@
#include <mach/hardware.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -39,8 +38,7 @@ MACHINE_START(ADSSPHERE, "ADS Sphere board")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = adssphere_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index e85bf17f2d2a..c49ed3dc1aea 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -34,6 +34,7 @@
#include <linux/i2c-gpio.h>
#include <linux/spi/spi.h>
#include <linux/export.h>
+#include <linux/irqchip/arm-vic.h>
#include <mach/hardware.h>
#include <linux/platform_data/video-ep93xx.h>
@@ -44,8 +45,6 @@
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <asm/hardware/vic.h>
-
#include "soc.h"
/*************************************************************************
@@ -140,11 +139,29 @@ static struct irqaction ep93xx_timer_irq = {
.handler = ep93xx_timer_interrupt,
};
-static void __init ep93xx_timer_init(void)
+static u32 ep93xx_gettimeoffset(void)
+{
+ int offset;
+
+ offset = __raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time;
+
+ /*
+ * Timer 4 is based on a 983.04 kHz reference clock,
+ * so dividing by 983040 gives the fraction of a second,
+ * so dividing by 0.983040 converts to uS.
+ * Refactor the calculation to avoid overflow.
+ * Finally, multiply by 1000 to give nS.
+ */
+ return (offset + (53 * offset / 3072)) * 1000;
+}
+
+void __init ep93xx_timer_init(void)
{
u32 tmode = EP93XX_TIMER123_CONTROL_MODE |
EP93XX_TIMER123_CONTROL_CLKSEL;
+ arch_gettimeoffset = ep93xx_gettimeoffset;
+
/* Enable periodic HZ timer. */
__raw_writel(tmode, EP93XX_TIMER1_CONTROL);
__raw_writel(TIMER1_RELOAD, EP93XX_TIMER1_LOAD);
@@ -158,21 +175,6 @@ static void __init ep93xx_timer_init(void)
setup_irq(IRQ_EP93XX_TIMER1, &ep93xx_timer_irq);
}
-static unsigned long ep93xx_gettimeoffset(void)
-{
- int offset;
-
- offset = __raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time;
-
- /* Calculate (1000000 / 983040) * offset. */
- return offset + (53 * offset / 3072);
-}
-
-struct sys_timer ep93xx_timer = {
- .init = ep93xx_timer_init,
- .offset = ep93xx_gettimeoffset,
-};
-
/*************************************************************************
* EP93xx IRQ handling
diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
index b8f53d57a299..27b14ae92c7e 100644
--- a/arch/arm/mach-ep93xx/edb93xx.c
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -39,7 +39,6 @@
#include <linux/platform_data/spi-ep93xx.h>
#include <mach/gpio-ep93xx.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -276,8 +275,7 @@ MACHINE_START(EDB9301, "Cirrus Logic EDB9301 Evaluation Board")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = edb93xx_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
@@ -290,8 +288,7 @@ MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = edb93xx_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
@@ -304,8 +301,7 @@ MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = edb93xx_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
@@ -318,8 +314,7 @@ MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = edb93xx_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
@@ -332,8 +327,7 @@ MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = edb93xx_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
@@ -346,8 +340,7 @@ MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = edb93xx_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
@@ -360,8 +353,7 @@ MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = edb93xx_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
@@ -374,8 +366,7 @@ MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = edb93xx_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
diff --git a/arch/arm/mach-ep93xx/gesbc9312.c b/arch/arm/mach-ep93xx/gesbc9312.c
index 7fd705b5efe4..0cca5b183309 100644
--- a/arch/arm/mach-ep93xx/gesbc9312.c
+++ b/arch/arm/mach-ep93xx/gesbc9312.c
@@ -17,7 +17,6 @@
#include <mach/hardware.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -39,8 +38,7 @@ MACHINE_START(GESBC9312, "Glomation GESBC-9312-sx")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = gesbc9312_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index 33a5122c6dc8..a14e1b37beff 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -53,7 +53,7 @@ int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
void ep93xx_ide_release_gpio(struct platform_device *pdev);
void ep93xx_init_devices(void);
-extern struct sys_timer ep93xx_timer;
+extern void ep93xx_timer_init(void);
void ep93xx_restart(char, const char *);
void ep93xx_init_late(void);
diff --git a/arch/arm/mach-ep93xx/include/mach/uncompress.h b/arch/arm/mach-ep93xx/include/mach/uncompress.h
index d64274fc5760..d2afb4dd82ab 100644
--- a/arch/arm/mach-ep93xx/include/mach/uncompress.h
+++ b/arch/arm/mach-ep93xx/include/mach/uncompress.h
@@ -86,5 +86,3 @@ static void arch_decomp_setup(void)
{
ethernet_reset();
}
-
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-ep93xx/micro9.c b/arch/arm/mach-ep93xx/micro9.c
index 3d7cdab725b2..373583c29825 100644
--- a/arch/arm/mach-ep93xx/micro9.c
+++ b/arch/arm/mach-ep93xx/micro9.c
@@ -18,7 +18,6 @@
#include <mach/hardware.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -82,8 +81,7 @@ MACHINE_START(MICRO9, "Contec Micro9-High")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = micro9_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
@@ -96,8 +94,7 @@ MACHINE_START(MICRO9M, "Contec Micro9-Mid")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = micro9_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
@@ -110,8 +107,7 @@ MACHINE_START(MICRO9L, "Contec Micro9-Lite")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = micro9_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
@@ -124,8 +120,7 @@ MACHINE_START(MICRO9S, "Contec Micro9-Slim")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = micro9_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c
index 0eb3f17a6fa2..36f22c1a31fe 100644
--- a/arch/arm/mach-ep93xx/simone.c
+++ b/arch/arm/mach-ep93xx/simone.c
@@ -25,7 +25,6 @@
#include <linux/platform_data/video-ep93xx.h>
#include <mach/gpio-ep93xx.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -83,8 +82,7 @@ MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = simone_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c
index 50043eef1cf2..aa86f86638dd 100644
--- a/arch/arm/mach-ep93xx/snappercl15.c
+++ b/arch/arm/mach-ep93xx/snappercl15.c
@@ -31,7 +31,6 @@
#include <linux/platform_data/video-ep93xx.h>
#include <mach/gpio-ep93xx.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -176,8 +175,7 @@ MACHINE_START(SNAPPER_CL15, "Bluewater Systems Snapper CL15")
.atag_offset = 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = snappercl15_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index 3c4c233391dc..61f4b5dc4d7d 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -22,7 +22,6 @@
#include <mach/hardware.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
@@ -246,8 +245,7 @@ MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC")
.atag_offset = 0x100,
.map_io = ts72xx_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = ts72xx_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c
index ba92e25e3016..605956fd07a2 100644
--- a/arch/arm/mach-ep93xx/vision_ep9307.c
+++ b/arch/arm/mach-ep93xx/vision_ep9307.c
@@ -34,7 +34,6 @@
#include <linux/platform_data/spi-ep93xx.h>
#include <mach/gpio-ep93xx.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
@@ -364,8 +363,7 @@ MACHINE_START(VISION_EP9307, "Vision Engraving Systems EP9307")
.atag_offset = 0x100,
.map_io = vision_map_io,
.init_irq = ep93xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &ep93xx_timer,
+ .init_time = ep93xx_timer_init,
.init_machine = vision_init_machine,
.init_late = ep93xx_init_late,
.restart = ep93xx_restart,
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index e103c290bc9e..85afb031b676 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -414,7 +414,7 @@ config MACH_EXYNOS4_DT
select CPU_EXYNOS4210
select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD
select PINCTRL
- select PINCTRL_EXYNOS4
+ select PINCTRL_EXYNOS
select USE_OF
help
Machine support for Samsung Exynos4 machine with device tree enabled.
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 1a89824a5f78..d63d399c7bae 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/gpio.h>
@@ -22,12 +23,13 @@
#include <linux/of_irq.h>
#include <linux/export.h>
#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
#include <linux/of_address.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/proc-fns.h>
#include <asm/exception.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <asm/cacheflush.h>
@@ -35,7 +37,6 @@
#include <mach/regs-irq.h>
#include <mach/regs-pmu.h>
#include <mach/regs-gpio.h>
-#include <mach/pmu.h>
#include <plat/cpu.h>
#include <plat/clock.h>
@@ -299,6 +300,7 @@ void exynos4_restart(char mode, const char *cmd)
void exynos5_restart(char mode, const char *cmd)
{
+ struct device_node *np;
u32 val;
void __iomem *addr;
@@ -306,8 +308,9 @@ void exynos5_restart(char mode, const char *cmd)
val = 0x1;
addr = EXYNOS_SWRESET;
} else if (of_machine_is_compatible("samsung,exynos5440")) {
- val = (0x10 << 20) | (0x1 << 16);
- addr = EXYNOS5440_SWRESET;
+ np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock");
+ addr = of_iomap(np, 0) + 0xcc;
+ val = (0xfff << 20) | (0x1 << 16);
} else {
pr_err("%s: cannot support non-DT\n", __func__);
return;
@@ -438,220 +441,6 @@ static void __init exynos5_init_clocks(int xtal)
#endif
}
-#define COMBINER_ENABLE_SET 0x0
-#define COMBINER_ENABLE_CLEAR 0x4
-#define COMBINER_INT_STATUS 0xC
-
-static DEFINE_SPINLOCK(irq_controller_lock);
-
-struct combiner_chip_data {
- unsigned int irq_offset;
- unsigned int irq_mask;
- void __iomem *base;
-};
-
-static struct irq_domain *combiner_irq_domain;
-static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
-
-static inline void __iomem *combiner_base(struct irq_data *data)
-{
- struct combiner_chip_data *combiner_data =
- irq_data_get_irq_chip_data(data);
-
- return combiner_data->base;
-}
-
-static void combiner_mask_irq(struct irq_data *data)
-{
- u32 mask = 1 << (data->hwirq % 32);
-
- __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
-}
-
-static void combiner_unmask_irq(struct irq_data *data)
-{
- u32 mask = 1 << (data->hwirq % 32);
-
- __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
-}
-
-static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
-{
- struct combiner_chip_data *chip_data = irq_get_handler_data(irq);
- struct irq_chip *chip = irq_get_chip(irq);
- unsigned int cascade_irq, combiner_irq;
- unsigned long status;
-
- chained_irq_enter(chip, desc);
-
- spin_lock(&irq_controller_lock);
- status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
- spin_unlock(&irq_controller_lock);
- status &= chip_data->irq_mask;
-
- if (status == 0)
- goto out;
-
- combiner_irq = __ffs(status);
-
- cascade_irq = combiner_irq + (chip_data->irq_offset & ~31);
- if (unlikely(cascade_irq >= NR_IRQS))
- do_bad_IRQ(cascade_irq, desc);
- else
- generic_handle_irq(cascade_irq);
-
- out:
- chained_irq_exit(chip, desc);
-}
-
-static struct irq_chip combiner_chip = {
- .name = "COMBINER",
- .irq_mask = combiner_mask_irq,
- .irq_unmask = combiner_unmask_irq,
-};
-
-static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
-{
- unsigned int max_nr;
-
- if (soc_is_exynos5250())
- max_nr = EXYNOS5_MAX_COMBINER_NR;
- else
- max_nr = EXYNOS4_MAX_COMBINER_NR;
-
- if (combiner_nr >= max_nr)
- BUG();
- if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
- BUG();
- irq_set_chained_handler(irq, combiner_handle_cascade_irq);
-}
-
-static void __init combiner_init_one(unsigned int combiner_nr,
- void __iomem *base)
-{
- combiner_data[combiner_nr].base = base;
- combiner_data[combiner_nr].irq_offset = irq_find_mapping(
- combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
- combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
-
- /* Disable all interrupts */
- __raw_writel(combiner_data[combiner_nr].irq_mask,
- base + COMBINER_ENABLE_CLEAR);
-}
-
-#ifdef CONFIG_OF
-static int combiner_irq_domain_xlate(struct irq_domain *d,
- struct device_node *controller,
- const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq,
- unsigned int *out_type)
-{
- if (d->of_node != controller)
- return -EINVAL;
-
- if (intsize < 2)
- return -EINVAL;
-
- *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
- *out_type = 0;
-
- return 0;
-}
-#else
-static int combiner_irq_domain_xlate(struct irq_domain *d,
- struct device_node *controller,
- const u32 *intspec, unsigned int intsize,
- unsigned long *out_hwirq,
- unsigned int *out_type)
-{
- return -EINVAL;
-}
-#endif
-
-static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hw)
-{
- irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
- irq_set_chip_data(irq, &combiner_data[hw >> 3]);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-
- return 0;
-}
-
-static struct irq_domain_ops combiner_irq_domain_ops = {
- .xlate = combiner_irq_domain_xlate,
- .map = combiner_irq_domain_map,
-};
-
-static void __init combiner_init(void __iomem *combiner_base,
- struct device_node *np)
-{
- int i, irq, irq_base;
- unsigned int max_nr, nr_irq;
-
- if (np) {
- if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
- pr_warning("%s: number of combiners not specified, "
- "setting default as %d.\n",
- __func__, EXYNOS4_MAX_COMBINER_NR);
- max_nr = EXYNOS4_MAX_COMBINER_NR;
- }
- } else {
- max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
- EXYNOS4_MAX_COMBINER_NR;
- }
- nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
-
- irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
- if (IS_ERR_VALUE(irq_base)) {
- irq_base = COMBINER_IRQ(0, 0);
- pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base);
- }
-
- combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
- &combiner_irq_domain_ops, &combiner_data);
- if (WARN_ON(!combiner_irq_domain)) {
- pr_warning("%s: irq domain init failed\n", __func__);
- return;
- }
-
- for (i = 0; i < max_nr; i++) {
- combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
- irq = IRQ_SPI(i);
-#ifdef CONFIG_OF
- if (np)
- irq = irq_of_parse_and_map(np, i);
-#endif
- combiner_cascade_irq(i, irq);
- }
-}
-
-#ifdef CONFIG_OF
-static int __init combiner_of_init(struct device_node *np,
- struct device_node *parent)
-{
- void __iomem *combiner_base;
-
- combiner_base = of_iomap(np, 0);
- if (!combiner_base) {
- pr_err("%s: failed to map combiner registers\n", __func__);
- return -ENXIO;
- }
-
- combiner_init(combiner_base, np);
-
- return 0;
-}
-
-static const struct of_device_id exynos_dt_irq_match[] = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- { .compatible = "arm,cortex-a15-gic", .data = gic_of_init, },
- { .compatible = "samsung,exynos4210-combiner",
- .data = combiner_of_init, },
- {},
-};
-#endif
-
void __init exynos4_init_irq(void)
{
unsigned int gic_bank_offset;
@@ -662,7 +451,7 @@ void __init exynos4_init_irq(void)
gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL);
#ifdef CONFIG_OF
else
- of_irq_init(exynos_dt_irq_match);
+ irqchip_init();
#endif
if (!of_have_populated_dt())
@@ -679,7 +468,7 @@ void __init exynos4_init_irq(void)
void __init exynos5_init_irq(void)
{
#ifdef CONFIG_OF
- of_irq_init(exynos_dt_irq_match);
+ irqchip_init();
#endif
/*
* The parameters of s5p_init_irq() are for VIC init.
@@ -1031,8 +820,8 @@ static int __init exynos_init_irq_eint(void)
* interrupt support code here can be completely removed.
*/
static const struct of_device_id exynos_pinctrl_ids[] = {
- { .compatible = "samsung,pinctrl-exynos4210", },
- { .compatible = "samsung,pinctrl-exynos4x12", },
+ { .compatible = "samsung,exynos4210-pinctrl", },
+ { .compatible = "samsung,exynos4x12-pinctrl", },
};
struct device_node *pctrl_np, *wkup_np;
const char *wkup_compat = "samsung,exynos4210-wakeup-eint";
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 04744f9c120f..9339bb8954be 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -12,7 +12,7 @@
#ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
#define __ARCH_ARM_MACH_EXYNOS_COMMON_H
-extern struct sys_timer exynos4_timer;
+extern void exynos4_timer_init(void);
struct map_desc;
void exynos_init_io(struct map_desc *mach_desc, int size);
@@ -60,8 +60,31 @@ void exynos4212_register_clocks(void);
#define exynos4212_register_clocks()
#endif
+struct device_node;
+void combiner_init(void __iomem *combiner_base, struct device_node *np);
+
extern struct smp_operations exynos_smp_ops;
extern void exynos_cpu_die(unsigned int cpu);
+/* PMU(Power Management Unit) support */
+
+#define PMU_TABLE_END NULL
+
+enum sys_powerdown {
+ SYS_AFTR,
+ SYS_LPA,
+ SYS_SLEEP,
+ NUM_SYS_POWERDOWN,
+};
+
+extern unsigned long l2x0_regs_phys;
+struct exynos_pmu_conf {
+ void __iomem *reg;
+ unsigned int val[NUM_SYS_POWERDOWN];
+};
+
+extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
+extern void s3c_cpu_resume(void);
+
#endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c
index 050924152776..fcfe0251aa3e 100644
--- a/arch/arm/mach-exynos/cpuidle.c
+++ b/arch/arm/mach-exynos/cpuidle.c
@@ -23,10 +23,11 @@
#include <asm/cpuidle.h>
#include <mach/regs-clock.h>
#include <mach/regs-pmu.h>
-#include <mach/pmu.h>
#include <plat/cpu.h>
+#include "common.h"
+
#define REG_DIRECTGO_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \
S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
(S5P_VA_SYSRAM + 0x24) : S5P_INFORM0))
diff --git a/arch/arm/mach-exynos/dev-audio.c b/arch/arm/mach-exynos/dev-audio.c
index 9d1a60951d7b..c662c89794b2 100644
--- a/arch/arm/mach-exynos/dev-audio.c
+++ b/arch/arm/mach-exynos/dev-audio.c
@@ -21,7 +21,8 @@
#include <mach/map.h>
#include <mach/dma.h>
#include <mach/irqs.h>
-#include <mach/regs-audss.h>
+
+#define EXYNOS4_AUDSS_INT_MEM (0x03000000)
static int exynos4_cfg_i2s(struct platform_device *pdev)
{
diff --git a/arch/arm/mach-exynos/include/mach/pmu.h b/arch/arm/mach-exynos/include/mach/pmu.h
deleted file mode 100644
index 7c27c2d4bf44..000000000000
--- a/arch/arm/mach-exynos/include/mach/pmu.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* linux/arch/arm/mach-exynos4/include/mach/pmu.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * EXYNOS4210 - PMU(Power Management Unit) 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.
-*/
-
-#ifndef __ASM_ARCH_PMU_H
-#define __ASM_ARCH_PMU_H __FILE__
-
-#define PMU_TABLE_END NULL
-
-enum sys_powerdown {
- SYS_AFTR,
- SYS_LPA,
- SYS_SLEEP,
- NUM_SYS_POWERDOWN,
-};
-
-extern unsigned long l2x0_regs_phys;
-struct exynos_pmu_conf {
- void __iomem *reg;
- unsigned int val[NUM_SYS_POWERDOWN];
-};
-
-extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
-extern void s3c_cpu_resume(void);
-
-#endif /* __ASM_ARCH_PMU_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-audss.h b/arch/arm/mach-exynos/include/mach/regs-audss.h
deleted file mode 100644
index ca5a8b64218a..000000000000
--- a/arch/arm/mach-exynos/include/mach/regs-audss.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* arch/arm/mach-exynos4/include/mach/regs-audss.h
- *
- * Copyright (c) 2011 Samsung Electronics
- * http://www.samsung.com
- *
- * Exynos4 Audio SubSystem clock register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __PLAT_REGS_AUDSS_H
-#define __PLAT_REGS_AUDSS_H __FILE__
-
-#define EXYNOS4_AUDSS_INT_MEM (0x03000000)
-
-#endif /* _PLAT_REGS_AUDSS_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-irq.h b/arch/arm/mach-exynos/include/mach/regs-irq.h
index 9c7b4bfd546f..f2b50506b9f6 100644
--- a/arch/arm/mach-exynos/include/mach/regs-irq.h
+++ b/arch/arm/mach-exynos/include/mach/regs-irq.h
@@ -13,7 +13,7 @@
#ifndef __ASM_ARCH_REGS_IRQ_H
#define __ASM_ARCH_REGS_IRQ_H __FILE__
-#include <asm/hardware/gic.h>
+#include <linux/irqchip/arm-gic.h>
#include <mach/map.h>
#endif /* __ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-exynos/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c
index b938f9fc1dd1..685f29173afa 100644
--- a/arch/arm/mach-exynos/mach-armlex4210.c
+++ b/arch/arm/mach-exynos/mach-armlex4210.c
@@ -16,7 +16,6 @@
#include <linux/smsc911x.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <plat/cpu.h>
@@ -201,9 +200,8 @@ MACHINE_START(ARMLEX4210, "ARMLEX4210")
.smp = smp_ops(exynos_smp_ops),
.init_irq = exynos4_init_irq,
.map_io = armlex4210_map_io,
- .handle_irq = gic_handle_irq,
.init_machine = armlex4210_machine_init,
.init_late = exynos_init_late,
- .timer = &exynos4_timer,
+ .init_time = exynos4_timer_init,
.restart = exynos4_restart,
MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c
index 92757ff817ae..112d10e53d20 100644
--- a/arch/arm/mach-exynos/mach-exynos4-dt.c
+++ b/arch/arm/mach-exynos/mach-exynos4-dt.c
@@ -15,7 +15,6 @@
#include <linux/serial_core.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <mach/map.h>
#include <plat/cpu.h>
@@ -107,10 +106,9 @@ DT_MACHINE_START(EXYNOS4210_DT, "Samsung Exynos4 (Flattened Device Tree)")
.smp = smp_ops(exynos_smp_ops),
.init_irq = exynos4_init_irq,
.map_io = exynos4_dt_map_io,
- .handle_irq = gic_handle_irq,
.init_machine = exynos4_dt_machine_init,
.init_late = exynos_init_late,
- .timer = &exynos4_timer,
+ .init_time = exynos4_timer_init,
.dt_compat = exynos4_dt_compat,
.restart = exynos4_restart,
MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c
index e99d3d8f2bcf..973a06637572 100644
--- a/arch/arm/mach-exynos/mach-exynos5-dt.c
+++ b/arch/arm/mach-exynos/mach-exynos5-dt.c
@@ -16,7 +16,6 @@
#include <linux/io.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <mach/map.h>
#include <mach/regs-pmu.h>
@@ -104,6 +103,12 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("samsung,mfc-v6", 0x11000000, "s5p-mfc-v6", NULL),
OF_DEV_AUXDATA("samsung,exynos5250-tmu", 0x10060000,
"exynos-tmu", NULL),
+ OF_DEV_AUXDATA("samsung,i2s-v5", 0x03830000,
+ "samsung-i2s.0", NULL),
+ OF_DEV_AUXDATA("samsung,i2s-v5", 0x12D60000,
+ "samsung-i2s.1", NULL),
+ OF_DEV_AUXDATA("samsung,i2s-v5", 0x12D70000,
+ "samsung-i2s.2", NULL),
{},
};
@@ -179,10 +184,9 @@ DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)")
.init_irq = exynos5_init_irq,
.smp = smp_ops(exynos_smp_ops),
.map_io = exynos5_dt_map_io,
- .handle_irq = gic_handle_irq,
.init_machine = exynos5_dt_machine_init,
.init_late = exynos_init_late,
- .timer = &exynos4_timer,
+ .init_time = exynos4_timer_init,
.dt_compat = exynos5_dt_compat,
.restart = exynos5_restart,
.reserve = exynos5_reserve,
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index 27d4ed8b116e..1ea79730187f 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -39,7 +39,6 @@
#include <media/v4l2-mediabus.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <plat/adc.h>
@@ -1209,25 +1208,25 @@ static struct i2c_board_info m5mols_board_info = {
.platform_data = &m5mols_platdata,
};
-static struct s5p_fimc_isp_info nuri_camera_sensors[] = {
+static struct fimc_source_info nuri_camera_sensors[] = {
{
.flags = V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_VSYNC_ACTIVE_LOW,
- .bus_type = FIMC_ITU_601,
+ .fimc_bus_type = FIMC_BUS_TYPE_ITU_601,
.board_info = &s5k6aa_board_info,
.clk_frequency = 24000000UL,
.i2c_bus_num = 6,
}, {
.flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_VSYNC_ACTIVE_LOW,
- .bus_type = FIMC_MIPI_CSI2,
+ .fimc_bus_type = FIMC_BUS_TYPE_MIPI_CSI2,
.board_info = &m5mols_board_info,
.clk_frequency = 24000000UL,
},
};
static struct s5p_platform_fimc fimc_md_platdata = {
- .isp_info = nuri_camera_sensors,
+ .source_info = nuri_camera_sensors,
.num_clients = ARRAY_SIZE(nuri_camera_sensors),
};
@@ -1379,10 +1378,9 @@ MACHINE_START(NURI, "NURI")
.smp = smp_ops(exynos_smp_ops),
.init_irq = exynos4_init_irq,
.map_io = nuri_map_io,
- .handle_irq = gic_handle_irq,
.init_machine = nuri_machine_init,
.init_late = exynos_init_late,
- .timer = &exynos4_timer,
+ .init_time = exynos4_timer_init,
.reserve = &nuri_reserve,
.restart = exynos4_restart,
MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 5e34b9c16196..579d2d171daa 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -29,7 +29,6 @@
#include <linux/platform_data/usb-exynos.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <video/platform_lcd.h>
@@ -814,10 +813,9 @@ MACHINE_START(ORIGEN, "ORIGEN")
.smp = smp_ops(exynos_smp_ops),
.init_irq = exynos4_init_irq,
.map_io = origen_map_io,
- .handle_irq = gic_handle_irq,
.init_machine = origen_machine_init,
.init_late = exynos_init_late,
- .timer = &exynos4_timer,
+ .init_time = exynos4_timer_init,
.reserve = &origen_reserve,
.restart = exynos4_restart,
MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c
index ae6da40c2aa9..fe6149624b84 100644
--- a/arch/arm/mach-exynos/mach-smdk4x12.c
+++ b/arch/arm/mach-exynos/mach-smdk4x12.c
@@ -25,7 +25,6 @@
#include <linux/platform_data/s3c-hsotg.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <video/samsung_fimd.h>
@@ -376,9 +375,8 @@ MACHINE_START(SMDK4212, "SMDK4212")
.smp = smp_ops(exynos_smp_ops),
.init_irq = exynos4_init_irq,
.map_io = smdk4x12_map_io,
- .handle_irq = gic_handle_irq,
.init_machine = smdk4x12_machine_init,
- .timer = &exynos4_timer,
+ .init_time = exynos4_timer_init,
.restart = exynos4_restart,
.reserve = &smdk4x12_reserve,
MACHINE_END
@@ -390,10 +388,9 @@ MACHINE_START(SMDK4412, "SMDK4412")
.smp = smp_ops(exynos_smp_ops),
.init_irq = exynos4_init_irq,
.map_io = smdk4x12_map_io,
- .handle_irq = gic_handle_irq,
.init_machine = smdk4x12_machine_init,
.init_late = exynos_init_late,
- .timer = &exynos4_timer,
+ .init_time = exynos4_timer_init,
.restart = exynos4_restart,
.reserve = &smdk4x12_reserve,
MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index 35548e3c097d..d71672922b19 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -26,7 +26,6 @@
#include <linux/platform_data/usb-exynos.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <video/platform_lcd.h>
@@ -423,9 +422,8 @@ MACHINE_START(SMDKV310, "SMDKV310")
.smp = smp_ops(exynos_smp_ops),
.init_irq = exynos4_init_irq,
.map_io = smdkv310_map_io,
- .handle_irq = gic_handle_irq,
.init_machine = smdkv310_machine_init,
- .timer = &exynos4_timer,
+ .init_time = exynos4_timer_init,
.reserve = &smdkv310_reserve,
.restart = exynos4_restart,
MACHINE_END
@@ -436,10 +434,9 @@ MACHINE_START(SMDKC210, "SMDKC210")
.smp = smp_ops(exynos_smp_ops),
.init_irq = exynos4_init_irq,
.map_io = smdkv310_map_io,
- .handle_irq = gic_handle_irq,
.init_machine = smdkv310_machine_init,
.init_late = exynos_init_late,
- .timer = &exynos4_timer,
+ .init_time = exynos4_timer_init,
.reserve = &smdkv310_reserve,
.restart = exynos4_restart,
MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index 9e3340f18950..497fcb793dc1 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -29,7 +29,6 @@
#include <drm/exynos_drm.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <video/samsung_fimd.h>
@@ -988,12 +987,12 @@ static struct i2c_board_info m5mols_board_info = {
.platform_data = &m5mols_platdata,
};
-static struct s5p_fimc_isp_info universal_camera_sensors[] = {
+static struct fimc_source_info universal_camera_sensors[] = {
{
.mux_id = 0,
.flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_VSYNC_ACTIVE_LOW,
- .bus_type = FIMC_ITU_601,
+ .fimc_bus_type = FIMC_BUS_TYPE_ITU_601,
.board_info = &s5k6aa_board_info,
.i2c_bus_num = 0,
.clk_frequency = 24000000UL,
@@ -1001,7 +1000,7 @@ static struct s5p_fimc_isp_info universal_camera_sensors[] = {
.mux_id = 0,
.flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_VSYNC_ACTIVE_LOW,
- .bus_type = FIMC_MIPI_CSI2,
+ .fimc_bus_type = FIMC_BUS_TYPE_MIPI_CSI2,
.board_info = &m5mols_board_info,
.i2c_bus_num = 0,
.clk_frequency = 24000000UL,
@@ -1009,7 +1008,7 @@ static struct s5p_fimc_isp_info universal_camera_sensors[] = {
};
static struct s5p_platform_fimc fimc_md_platdata = {
- .isp_info = universal_camera_sensors,
+ .source_info = universal_camera_sensors,
.num_clients = ARRAY_SIZE(universal_camera_sensors),
};
@@ -1151,10 +1150,9 @@ MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210")
.smp = smp_ops(exynos_smp_ops),
.init_irq = exynos4_init_irq,
.map_io = universal_map_io,
- .handle_irq = gic_handle_irq,
.init_machine = universal_machine_init,
.init_late = exynos_init_late,
- .timer = &s5p_timer,
+ .init_time = s5p_timer_init,
.reserve = &universal_reserve,
.restart = exynos4_restart,
MACHINE_END
diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
index 57668eb68e75..c9d6650f9b5d 100644
--- a/arch/arm/mach-exynos/mct.c
+++ b/arch/arm/mach-exynos/mct.c
@@ -22,7 +22,6 @@
#include <linux/of.h>
#include <asm/arch_timer.h>
-#include <asm/hardware/gic.h>
#include <asm/localtimer.h>
#include <plat/cpu.h>
@@ -255,13 +254,9 @@ static struct irqaction mct_comp_event_irq = {
static void exynos4_clockevent_init(void)
{
- clockevents_calc_mult_shift(&mct_comp_device, clk_rate, 5);
- mct_comp_device.max_delta_ns =
- clockevent_delta2ns(0xffffffff, &mct_comp_device);
- mct_comp_device.min_delta_ns =
- clockevent_delta2ns(0xf, &mct_comp_device);
mct_comp_device.cpumask = cpumask_of(0);
- clockevents_register_device(&mct_comp_device);
+ clockevents_config_and_register(&mct_comp_device, clk_rate,
+ 0xf, 0xffffffff);
if (soc_is_exynos5250())
setup_irq(EXYNOS5_IRQ_MCT_G0, &mct_comp_event_irq);
@@ -404,14 +399,8 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
evt->set_mode = exynos4_tick_set_mode;
evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
evt->rating = 450;
-
- clockevents_calc_mult_shift(evt, clk_rate / (TICK_BASE_CNT + 1), 5);
- evt->max_delta_ns =
- clockevent_delta2ns(0x7fffffff, evt);
- evt->min_delta_ns =
- clockevent_delta2ns(0xf, evt);
-
- clockevents_register_device(evt);
+ clockevents_config_and_register(evt, clk_rate / (TICK_BASE_CNT + 1),
+ 0xf, 0x7fffffff);
exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
@@ -478,7 +467,7 @@ static void __init exynos4_timer_resources(void)
#endif /* CONFIG_LOCAL_TIMERS */
}
-static void __init exynos_timer_init(void)
+void __init exynos4_timer_init(void)
{
if (soc_is_exynos5440()) {
arch_timer_of_register();
@@ -494,7 +483,3 @@ static void __init exynos_timer_init(void)
exynos4_clocksource_init();
exynos4_clockevent_init();
}
-
-struct sys_timer exynos4_timer = {
- .init = exynos_timer_init,
-};
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index c5c840e947b8..60f7c5be057d 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -20,9 +20,9 @@
#include <linux/jiffies.h>
#include <linux/smp.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/cacheflush.h>
-#include <asm/hardware/gic.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
@@ -149,7 +149,7 @@ static int __cpuinit exynos_boot_secondary(unsigned int cpu, struct task_struct
__raw_writel(virt_to_phys(exynos4_secondary_startup),
cpu_boot_reg(phys_cpu));
- gic_raise_softirq(cpumask_of(cpu), 0);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
if (pen_release == -1)
break;
@@ -190,8 +190,6 @@ static void __init exynos_smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index b9b539cac81e..e3faaa812016 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -34,7 +34,8 @@
#include <mach/regs-clock.h>
#include <mach/regs-pmu.h>
#include <mach/pm-core.h>
-#include <mach/pmu.h>
+
+#include "common.h"
static struct sleep_save exynos4_set_clksrc[] = {
{ .reg = EXYNOS4_CLKSRC_MASK_TOP , .val = 0x00000001, },
@@ -91,8 +92,8 @@ static int exynos_cpu_suspend(unsigned long arg)
/* issue the standby signal into the pm unit. */
cpu_do_idle();
- /* we should never get past here */
- panic("sleep resumed to originator?");
+ pr_info("Failed to suspend the system\n");
+ return 1; /* Aborting suspend */
}
static void exynos_pm_prepare(void)
@@ -282,6 +283,8 @@ static void exynos_pm_resume(void)
if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) {
tmp |= S5P_CENTRAL_LOWPWR_CFG;
__raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+ /* clear the wakeup state register */
+ __raw_writel(0x0, S5P_WAKEUP_STAT);
/* No need to perform below restore code */
goto early_wakeup;
}
diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c
index 3a48c852be6c..daebc1abc966 100644
--- a/arch/arm/mach-exynos/pmu.c
+++ b/arch/arm/mach-exynos/pmu.c
@@ -14,7 +14,8 @@
#include <linux/bug.h>
#include <mach/regs-clock.h>
-#include <mach/pmu.h>
+
+#include "common.h"
static struct exynos_pmu_conf *exynos_pmu_config;
diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c
index 25b453601acc..6987a09ec219 100644
--- a/arch/arm/mach-footbridge/cats-hw.c
+++ b/arch/arm/mach-footbridge/cats-hw.c
@@ -90,6 +90,6 @@ MACHINE_START(CATS, "Chalice-CATS")
.fixup = fixup_cats,
.map_io = footbridge_map_io,
.init_irq = footbridge_init_irq,
- .timer = &isa_timer,
+ .init_time = isa_timer_init,
.restart = footbridge_restart,
MACHINE_END
diff --git a/arch/arm/mach-footbridge/common.h b/arch/arm/mach-footbridge/common.h
index c9767b892cb2..a846e50a07b8 100644
--- a/arch/arm/mach-footbridge/common.h
+++ b/arch/arm/mach-footbridge/common.h
@@ -1,6 +1,6 @@
-extern struct sys_timer footbridge_timer;
-extern struct sys_timer isa_timer;
+extern void footbridge_timer_init(void);
+extern void isa_timer_init(void);
extern void isa_rtc_init(void);
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
index 3b54196447c7..9ee78f7b4990 100644
--- a/arch/arm/mach-footbridge/dc21285-timer.c
+++ b/arch/arm/mach-footbridge/dc21285-timer.c
@@ -93,7 +93,7 @@ static struct irqaction footbridge_timer_irq = {
/*
* Set up timer interrupt.
*/
-static void __init footbridge_timer_init(void)
+void __init footbridge_timer_init(void)
{
struct clock_event_device *ce = &ckevt_dc21285;
@@ -101,14 +101,6 @@ static void __init footbridge_timer_init(void)
setup_irq(ce->irq, &footbridge_timer_irq);
- clockevents_calc_mult_shift(ce, mem_fclk_21285, 5);
- ce->max_delta_ns = clockevent_delta2ns(0xffffff, ce);
- ce->min_delta_ns = clockevent_delta2ns(0x000004, ce);
ce->cpumask = cpumask_of(smp_processor_id());
-
- clockevents_register_device(ce);
+ clockevents_config_and_register(ce, mem_fclk_21285, 0x4, 0xffffff);
}
-
-struct sys_timer footbridge_timer = {
- .init = footbridge_timer_init,
-};
diff --git a/arch/arm/mach-footbridge/ebsa285.c b/arch/arm/mach-footbridge/ebsa285.c
index b09551ef89ca..b08243500e2e 100644
--- a/arch/arm/mach-footbridge/ebsa285.c
+++ b/arch/arm/mach-footbridge/ebsa285.c
@@ -101,7 +101,7 @@ MACHINE_START(EBSA285, "EBSA285")
.video_end = 0x000bffff,
.map_io = footbridge_map_io,
.init_irq = footbridge_init_irq,
- .timer = &footbridge_timer,
+ .init_time = footbridge_timer_init,
.restart = footbridge_restart,
MACHINE_END
diff --git a/arch/arm/mach-footbridge/include/mach/uncompress.h b/arch/arm/mach-footbridge/include/mach/uncompress.h
index 5dfa44287346..a69398c05a52 100644
--- a/arch/arm/mach-footbridge/include/mach/uncompress.h
+++ b/arch/arm/mach-footbridge/include/mach/uncompress.h
@@ -35,4 +35,3 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
index c40bb415f4b5..d9301dd56354 100644
--- a/arch/arm/mach-footbridge/isa-timer.c
+++ b/arch/arm/mach-footbridge/isa-timer.c
@@ -31,14 +31,10 @@ static struct irqaction pit_timer_irq = {
.dev_id = &i8253_clockevent,
};
-static void __init isa_timer_init(void)
+void __init isa_timer_init(void)
{
clocksource_i8253_init();
setup_irq(i8253_clockevent.irq, &pit_timer_irq);
clockevent_i8253_init(false);
}
-
-struct sys_timer isa_timer = {
- .init = isa_timer_init,
-};
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index d2d14339c6c4..90ea23fdce4c 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -766,6 +766,6 @@ MACHINE_START(NETWINDER, "Rebel-NetWinder")
.fixup = fixup_netwinder,
.map_io = footbridge_map_io,
.init_irq = footbridge_init_irq,
- .timer = &isa_timer,
+ .init_time = isa_timer_init,
.restart = netwinder_restart,
MACHINE_END
diff --git a/arch/arm/mach-footbridge/personal.c b/arch/arm/mach-footbridge/personal.c
index e1e9990fa957..7bdeabdcd4d8 100644
--- a/arch/arm/mach-footbridge/personal.c
+++ b/arch/arm/mach-footbridge/personal.c
@@ -18,7 +18,7 @@ MACHINE_START(PERSONAL_SERVER, "Compaq-PersonalServer")
.atag_offset = 0x100,
.map_io = footbridge_map_io,
.init_irq = footbridge_init_irq,
- .timer = &footbridge_timer,
+ .init_time = footbridge_timer_init,
.restart = footbridge_restart,
MACHINE_END
diff --git a/arch/arm/mach-gemini/board-nas4220b.c b/arch/arm/mach-gemini/board-nas4220b.c
index 5927d3c253aa..08bd650c42f3 100644
--- a/arch/arm/mach-gemini/board-nas4220b.c
+++ b/arch/arm/mach-gemini/board-nas4220b.c
@@ -31,10 +31,6 @@
#include "common.h"
-static struct sys_timer ib4220b_timer = {
- .init = gemini_timer_init,
-};
-
static struct gpio_led ib4220b_leds[] = {
{
.name = "nas4220b:orange:hdd",
@@ -105,6 +101,6 @@ MACHINE_START(NAS4220B, "Raidsonic NAS IB-4220-B")
.atag_offset = 0x100,
.map_io = gemini_map_io,
.init_irq = gemini_init_irq,
- .timer = &ib4220b_timer,
+ .init_time = gemini_timer_init,
.init_machine = ib4220b_init,
MACHINE_END
diff --git a/arch/arm/mach-gemini/board-rut1xx.c b/arch/arm/mach-gemini/board-rut1xx.c
index cd7437a1cea0..fa0a36337f4d 100644
--- a/arch/arm/mach-gemini/board-rut1xx.c
+++ b/arch/arm/mach-gemini/board-rut1xx.c
@@ -71,10 +71,6 @@ static struct platform_device rut1xx_leds = {
},
};
-static struct sys_timer rut1xx_timer = {
- .init = gemini_timer_init,
-};
-
static void __init rut1xx_init(void)
{
gemini_gpio_init();
@@ -89,6 +85,6 @@ MACHINE_START(RUT100, "Teltonika RUT100")
.atag_offset = 0x100,
.map_io = gemini_map_io,
.init_irq = gemini_init_irq,
- .timer = &rut1xx_timer,
+ .init_time = gemini_timer_init,
.init_machine = rut1xx_init,
MACHINE_END
diff --git a/arch/arm/mach-gemini/board-wbd111.c b/arch/arm/mach-gemini/board-wbd111.c
index a367880368f1..3321cd6cc1f3 100644
--- a/arch/arm/mach-gemini/board-wbd111.c
+++ b/arch/arm/mach-gemini/board-wbd111.c
@@ -80,10 +80,6 @@ static struct platform_device wbd111_leds_device = {
},
};
-static struct sys_timer wbd111_timer = {
- .init = gemini_timer_init,
-};
-
static struct mtd_partition wbd111_partitions[] = {
{
.name = "RedBoot",
@@ -132,6 +128,6 @@ MACHINE_START(WBD111, "Wiliboard WBD-111")
.atag_offset = 0x100,
.map_io = gemini_map_io,
.init_irq = gemini_init_irq,
- .timer = &wbd111_timer,
+ .init_time = gemini_timer_init,
.init_machine = wbd111_init,
MACHINE_END
diff --git a/arch/arm/mach-gemini/board-wbd222.c b/arch/arm/mach-gemini/board-wbd222.c
index f382811c1319..fe33c825fdaf 100644
--- a/arch/arm/mach-gemini/board-wbd222.c
+++ b/arch/arm/mach-gemini/board-wbd222.c
@@ -80,10 +80,6 @@ static struct platform_device wbd222_leds_device = {
},
};
-static struct sys_timer wbd222_timer = {
- .init = gemini_timer_init,
-};
-
static struct mtd_partition wbd222_partitions[] = {
{
.name = "RedBoot",
@@ -132,6 +128,6 @@ MACHINE_START(WBD222, "Wiliboard WBD-222")
.atag_offset = 0x100,
.map_io = gemini_map_io,
.init_irq = gemini_init_irq,
- .timer = &wbd222_timer,
+ .init_time = gemini_timer_init,
.init_machine = wbd222_init,
MACHINE_END
diff --git a/arch/arm/mach-gemini/include/mach/uncompress.h b/arch/arm/mach-gemini/include/mach/uncompress.h
index 0efa26247235..02e225673acb 100644
--- a/arch/arm/mach-gemini/include/mach/uncompress.h
+++ b/arch/arm/mach-gemini/include/mach/uncompress.h
@@ -39,6 +39,4 @@ static inline void flush(void)
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
-
#endif /* __MACH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c
index aa1331e86bcf..17ef91fa3d56 100644
--- a/arch/arm/mach-h720x/common.c
+++ b/arch/arm/mach-h720x/common.c
@@ -42,12 +42,12 @@ void __init arch_dma_init(dma_t *dma)
}
/*
- * Return usecs since last timer reload
+ * Return nsecs since last timer reload
* (timercount * (usecs perjiffie)) / (ticks per jiffie)
*/
-unsigned long h720x_gettimeoffset(void)
+u32 h720x_gettimeoffset(void)
{
- return (CPU_REG (TIMER_VIRT, TM0_COUNT) * tick_usec) / LATCH;
+ return ((CPU_REG(TIMER_VIRT, TM0_COUNT) * tick_usec) / LATCH) * 1000;
}
/*
diff --git a/arch/arm/mach-h720x/common.h b/arch/arm/mach-h720x/common.h
index 2489537d33dd..7e738410ca93 100644
--- a/arch/arm/mach-h720x/common.h
+++ b/arch/arm/mach-h720x/common.h
@@ -13,18 +13,18 @@
*
*/
-extern unsigned long h720x_gettimeoffset(void);
+extern u32 h720x_gettimeoffset(void);
extern void __init h720x_init_irq(void);
extern void __init h720x_map_io(void);
extern void h720x_restart(char, const char *);
#ifdef CONFIG_ARCH_H7202
-extern struct sys_timer h7202_timer;
+extern void h7202_timer_init(void);
extern void __init init_hw_h7202(void);
extern void __init h7202_init_irq(void);
extern void __init h7202_init_time(void);
#endif
#ifdef CONFIG_ARCH_H7201
-extern struct sys_timer h7201_timer;
+extern void h7201_timer_init(void);
#endif
diff --git a/arch/arm/mach-h720x/cpu-h7201.c b/arch/arm/mach-h720x/cpu-h7201.c
index 24df2a349a98..13c741215387 100644
--- a/arch/arm/mach-h720x/cpu-h7201.c
+++ b/arch/arm/mach-h720x/cpu-h7201.c
@@ -44,8 +44,10 @@ static struct irqaction h7201_timer_irq = {
/*
* Setup TIMER0 as system timer
*/
-void __init h7201_init_time(void)
+void __init h7201_timer_init(void)
{
+ arch_gettimeoffset = h720x_gettimeoffset;
+
CPU_REG (TIMER_VIRT, TM0_PERIOD) = LATCH;
CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_RESET;
CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_REPEAT | TM_START;
@@ -53,8 +55,3 @@ void __init h7201_init_time(void)
setup_irq(IRQ_TIMER0, &h7201_timer_irq);
}
-
-struct sys_timer h7201_timer = {
- .init = h7201_init_time,
- .offset = h720x_gettimeoffset,
-};
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
index c37d570b852d..e2ae7e898f9d 100644
--- a/arch/arm/mach-h720x/cpu-h7202.c
+++ b/arch/arm/mach-h720x/cpu-h7202.c
@@ -178,8 +178,10 @@ static struct irqaction h7202_timer_irq = {
/*
* Setup TIMER0 as system timer
*/
-void __init h7202_init_time(void)
+void __init h7202_timer_init(void)
{
+ arch_gettimeoffset = h720x_gettimeoffset;
+
CPU_REG (TIMER_VIRT, TM0_PERIOD) = LATCH;
CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_RESET;
CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_REPEAT | TM_START;
@@ -188,11 +190,6 @@ void __init h7202_init_time(void)
setup_irq(IRQ_TIMER0, &h7202_timer_irq);
}
-struct sys_timer h7202_timer = {
- .init = h7202_init_time,
- .offset = h720x_gettimeoffset,
-};
-
void __init h7202_init_irq (void)
{
int irq;
diff --git a/arch/arm/mach-h720x/h7201-eval.c b/arch/arm/mach-h720x/h7201-eval.c
index 5fdb20c855e2..4fdeb686c0a9 100644
--- a/arch/arm/mach-h720x/h7201-eval.c
+++ b/arch/arm/mach-h720x/h7201-eval.c
@@ -32,7 +32,7 @@ MACHINE_START(H7201, "Hynix GMS30C7201")
.atag_offset = 0x1000,
.map_io = h720x_map_io,
.init_irq = h720x_init_irq,
- .timer = &h7201_timer,
+ .init_time = h7201_timer_init,
.dma_zone_size = SZ_256M,
.restart = h720x_restart,
MACHINE_END
diff --git a/arch/arm/mach-h720x/h7202-eval.c b/arch/arm/mach-h720x/h7202-eval.c
index 169673036c59..f68e967a2062 100644
--- a/arch/arm/mach-h720x/h7202-eval.c
+++ b/arch/arm/mach-h720x/h7202-eval.c
@@ -74,7 +74,7 @@ MACHINE_START(H7202, "Hynix HMS30C7202")
.atag_offset = 0x100,
.map_io = h720x_map_io,
.init_irq = h7202_init_irq,
- .timer = &h7202_timer,
+ .init_time = h7202_timer_init,
.init_machine = init_eval_h7202,
.dma_zone_size = SZ_256M,
.restart = h720x_restart,
diff --git a/arch/arm/mach-h720x/include/mach/uncompress.h b/arch/arm/mach-h720x/include/mach/uncompress.h
index d6623234f61e..43e343c4b50a 100644
--- a/arch/arm/mach-h720x/include/mach/uncompress.h
+++ b/arch/arm/mach-h720x/include/mach/uncompress.h
@@ -32,6 +32,5 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
#endif
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 551c97e87a78..44b12f9c1584 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,7 @@
config ARCH_HIGHBANK
bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7
+ select ARCH_HAS_CPUFREQ
+ select ARCH_HAS_OPP
select ARCH_WANT_OPTIONAL_GPIOLIB
select ARM_AMBA
select ARM_GIC
@@ -11,5 +13,7 @@ config ARCH_HIGHBANK
select GENERIC_CLOCKEVENTS
select HAVE_ARM_SCU
select HAVE_SMP
+ select MAILBOX
+ select PL320_MBOX
select SPARSE_IRQ
select USE_OF
diff --git a/arch/arm/mach-highbank/core.h b/arch/arm/mach-highbank/core.h
index 80235b46cb58..3f65206a9b92 100644
--- a/arch/arm/mach-highbank/core.h
+++ b/arch/arm/mach-highbank/core.h
@@ -2,7 +2,6 @@
#define __HIGHBANK_CORE_H
extern void highbank_set_cpu_jump(int cpu, void *jump_addr);
-extern void highbank_clocks_init(void);
extern void highbank_restart(char, const char *);
extern void __iomem *scu_base_addr;
diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c
index 981dc1e1da51..a4f9f50247d4 100644
--- a/arch/arm/mach-highbank/highbank.c
+++ b/arch/arm/mach-highbank/highbank.c
@@ -18,6 +18,7 @@
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -25,14 +26,15 @@
#include <linux/of_address.h>
#include <linux/smp.h>
#include <linux/amba/bus.h>
+#include <linux/clk-provider.h>
#include <asm/arch_timer.h>
#include <asm/cacheflush.h>
+#include <asm/cputype.h>
#include <asm/smp_plat.h>
#include <asm/smp_twd.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/timer-sp.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -59,19 +61,13 @@ static void __init highbank_scu_map_io(void)
void highbank_set_cpu_jump(int cpu, void *jump_addr)
{
- cpu = cpu_logical_map(cpu);
+ cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 0);
writel(virt_to_phys(jump_addr), HB_JUMP_TABLE_VIRT(cpu));
__cpuc_flush_dcache_area(HB_JUMP_TABLE_VIRT(cpu), 16);
outer_clean_range(HB_JUMP_TABLE_PHYS(cpu),
HB_JUMP_TABLE_PHYS(cpu) + 15);
}
-const static struct of_device_id irq_match[] = {
- { .compatible = "arm,cortex-a15-gic", .data = gic_of_init, },
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- {}
-};
-
#ifdef CONFIG_CACHE_L2X0
static void highbank_l2x0_disable(void)
{
@@ -82,7 +78,7 @@ static void highbank_l2x0_disable(void)
static void __init highbank_init_irq(void)
{
- of_irq_init(irq_match);
+ irqchip_init();
if (of_find_compatible_node(NULL, NULL, "arm,cortex-a9"))
highbank_scu_map_io();
@@ -116,7 +112,7 @@ static void __init highbank_timer_init(void)
WARN_ON(!timer_base);
irq = irq_of_parse_and_map(np, 0);
- highbank_clocks_init();
+ of_clk_init(NULL);
lookup.clk = of_clk_get(np, 0);
clkdev_add(&lookup);
@@ -129,10 +125,6 @@ static void __init highbank_timer_init(void)
arch_timer_sched_clock_init();
}
-static struct sys_timer highbank_timer = {
- .init = highbank_timer_init,
-};
-
static void highbank_power_off(void)
{
highbank_set_pwr_shutdown();
@@ -209,8 +201,7 @@ DT_MACHINE_START(HIGHBANK, "Highbank")
.smp = smp_ops(highbank_smp_ops),
.map_io = debug_ll_io_init,
.init_irq = highbank_init_irq,
- .timer = &highbank_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = highbank_timer_init,
.init_machine = highbank_init,
.dt_compat = highbank_match,
.restart = highbank_restart,
diff --git a/arch/arm/mach-highbank/platsmp.c b/arch/arm/mach-highbank/platsmp.c
index 4ecc864ac8b9..8797a7001720 100644
--- a/arch/arm/mach-highbank/platsmp.c
+++ b/arch/arm/mach-highbank/platsmp.c
@@ -17,9 +17,9 @@
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/smp_scu.h>
-#include <asm/hardware/gic.h>
#include "core.h"
@@ -33,7 +33,7 @@ static void __cpuinit highbank_secondary_init(unsigned int cpu)
static int __cpuinit highbank_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
highbank_set_cpu_jump(cpu, secondary_startup);
- gic_raise_softirq(cpumask_of(cpu), 0);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
return 0;
}
@@ -56,8 +56,6 @@ static void __init highbank_smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
static void __init highbank_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-highbank/sysregs.h b/arch/arm/mach-highbank/sysregs.h
index 70af9d13fcef..5995df7f2622 100644
--- a/arch/arm/mach-highbank/sysregs.h
+++ b/arch/arm/mach-highbank/sysregs.h
@@ -37,7 +37,7 @@ extern void __iomem *sregs_base;
static inline void highbank_set_core_pwr(void)
{
- int cpu = cpu_logical_map(smp_processor_id());
+ int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0);
if (scu_base_addr)
scu_power_mode(scu_base_addr, SCU_PM_POWEROFF);
else
@@ -46,7 +46,7 @@ static inline void highbank_set_core_pwr(void)
static inline void highbank_clear_core_pwr(void)
{
- int cpu = cpu_logical_map(smp_processor_id());
+ int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0);
if (scu_base_addr)
scu_power_mode(scu_base_addr, SCU_PM_NORMAL);
else
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 0a2349dc7018..4c9c6f9d2c55 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -95,9 +95,6 @@ config MACH_MX27
config ARCH_MX5
bool
-config ARCH_MX50
- bool
-
config ARCH_MX51
bool
@@ -164,11 +161,6 @@ config SOC_IMX5
select CPU_V7
select MXC_TZIC
-config SOC_IMX50
- bool
- select ARCH_MX50
- select SOC_IMX5
-
config SOC_IMX51
bool
select ARCH_MX5
@@ -488,7 +480,7 @@ 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
+ depends on REGULATOR_WM8350 = y
select MFD_WM8350_CONFIG_MODE_0
select MFD_WM8352_CONFIG_MODE_0
help
@@ -738,25 +730,10 @@ endif
if ARCH_MULTI_V7
-comment "i.MX5 platforms:"
-
-config MACH_MX50_RDP
- bool "Support MX50 reference design platform"
- depends on BROKEN
- 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 SOC_IMX50
- help
- Include support for MX50 reference design platform (RDP) board. This
- includes specific configurations for the board and its peripherals.
-
comment "i.MX51 machines:"
config MACH_IMX51_DT
bool "Support i.MX51 platforms from device tree"
- select MACH_MX51_BABBAGE
select SOC_IMX51
help
Include support for Freescale i.MX51 based platforms
@@ -777,19 +754,6 @@ config MACH_MX51_BABBAGE
u-boot. This includes specific configurations for the board and its
peripherals.
-config MACH_MX51_3DS
- bool "Support MX51PDK (3DS)"
- select IMX_HAVE_PLATFORM_IMX2_WDT
- select IMX_HAVE_PLATFORM_IMX_KEYPAD
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
- select IMX_HAVE_PLATFORM_SPI_IMX
- select MXC_DEBUG_BOARD
- select SOC_IMX51
- help
- Include support for MX51PDK (3DS) platform. This includes specific
- configurations for the board and its peripherals.
-
config MACH_EUKREA_CPUIMX51SD
bool "Support Eukrea CPUIMX51SD module"
select IMX_HAVE_PLATFORM_FSL_USB2_UDC
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 0634b3152c24..c4ce0906d76a 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -28,7 +28,11 @@ obj-$(CONFIG_MXC_ULPI) += ulpi.o
obj-$(CONFIG_MXC_USE_EPIT) += epit.o
obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o
-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+
+ifeq ($(CONFIG_CPU_IDLE),y)
+obj-y += cpuidle.o
+obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
+endif
ifdef CONFIG_SND_IMX_SOC
obj-y += ssi-fiq.o
@@ -88,7 +92,6 @@ obj-$(CONFIG_MACH_EUKREA_CPUIMX35SD) += mach-cpuimx35.o
obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o
obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o
-obj-$(CONFIG_DEBUG_LL) += lluart.o
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
obj-$(CONFIG_HAVE_IMX_SRC) += src.o
@@ -103,10 +106,8 @@ endif
# i.MX5 based machines
obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o
-obj-$(CONFIG_MACH_MX51_3DS) += mach-mx51_3ds.o
obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += mach-cpuimx51sd.o
obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd51-baseboard.o
-obj-$(CONFIG_MACH_MX50_RDP) += mach-mx50_rdp.o
obj-$(CONFIG_MACH_IMX51_DT) += imx51-dt.o
obj-$(CONFIG_SOC_IMX53) += mach-imx53.o
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
index b27815de8473..41ba1bb0437b 100644
--- a/arch/arm/mach-imx/Makefile.boot
+++ b/arch/arm/mach-imx/Makefile.boot
@@ -22,10 +22,6 @@ zreladdr-$(CONFIG_SOC_IMX35) += 0x80008000
params_phys-$(CONFIG_SOC_IMX35) := 0x80000100
initrd_phys-$(CONFIG_SOC_IMX35) := 0x80800000
-zreladdr-$(CONFIG_SOC_IMX50) += 0x70008000
-params_phys-$(CONFIG_SOC_IMX50) := 0x70000100
-initrd_phys-$(CONFIG_SOC_IMX50) := 0x70800000
-
zreladdr-$(CONFIG_SOC_IMX51) += 0x90008000
params_phys-$(CONFIG_SOC_IMX51) := 0x90000100
initrd_phys-$(CONFIG_SOC_IMX51) := 0x90800000
diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c
index 2c570cdaae7b..69858c78f40d 100644
--- a/arch/arm/mach-imx/clk-imx25.c
+++ b/arch/arm/mach-imx/clk-imx25.c
@@ -224,6 +224,9 @@ static int __init __mx25_clocks_init(unsigned long osc_rate)
clk_prepare_enable(clk[emi_ahb]);
+ /* Clock source for gpt must be derived from AHB */
+ clk_set_parent(clk[per5_sel], clk[ahb]);
+
clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0");
clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0");
diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c
index 1ffe3b534e51..30b3242a7d49 100644
--- a/arch/arm/mach-imx/clk-imx27.c
+++ b/arch/arm/mach-imx/clk-imx27.c
@@ -62,7 +62,7 @@ static const char *clko_sel_clks[] = {
"32k", "usb_div", "dptc",
};
-static const char *ssi_sel_clks[] = { "spll", "mpll", };
+static const char *ssi_sel_clks[] = { "spll_gate", "mpll", };
enum mx27_clks {
dummy, ckih, ckil, mpll, spll, mpll_main2, ahb, ipg, nfc_div, per1_div,
@@ -82,7 +82,7 @@ enum mx27_clks {
csi_ahb_gate, brom_ahb_gate, ata_ahb_gate, wdog_ipg_gate, usb_ipg_gate,
uart6_ipg_gate, uart5_ipg_gate, uart4_ipg_gate, uart3_ipg_gate,
uart2_ipg_gate, uart1_ipg_gate, ckih_div1p5, fpm, mpll_osc_sel,
- mpll_sel, clk_max
+ mpll_sel, spll_gate, clk_max
};
static struct clk *clk[clk_max];
@@ -104,6 +104,7 @@ int __init mx27_clocks_init(unsigned long fref)
ARRAY_SIZE(mpll_sel_clks));
clk[mpll] = imx_clk_pllv1("mpll", "mpll_sel", CCM_MPCTL0);
clk[spll] = imx_clk_pllv1("spll", "ckih", CCM_SPCTL0);
+ clk[spll_gate] = imx_clk_gate("spll_gate", "spll", CCM_CSCR, 1);
clk[mpll_main2] = imx_clk_fixed_factor("mpll_main2", "mpll", 2, 3);
if (mx27_revision() >= IMX_CHIP_REVISION_2_0) {
@@ -121,7 +122,7 @@ int __init mx27_clocks_init(unsigned long fref)
clk[per4_div] = imx_clk_divider("per4_div", "mpll_main2", CCM_PCDR1, 24, 6);
clk[vpu_sel] = imx_clk_mux("vpu_sel", CCM_CSCR, 21, 1, vpu_sel_clks, ARRAY_SIZE(vpu_sel_clks));
clk[vpu_div] = imx_clk_divider("vpu_div", "vpu_sel", CCM_PCDR0, 10, 6);
- clk[usb_div] = imx_clk_divider("usb_div", "spll", CCM_CSCR, 28, 3);
+ clk[usb_div] = imx_clk_divider("usb_div", "spll_gate", CCM_CSCR, 28, 3);
clk[cpu_sel] = imx_clk_mux("cpu_sel", CCM_CSCR, 15, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks));
clk[clko_sel] = imx_clk_mux("clko_sel", CCM_CCSR, 0, 5, clko_sel_clks, ARRAY_SIZE(clko_sel_clks));
if (mx27_revision() >= IMX_CHIP_REVISION_2_0)
@@ -228,9 +229,12 @@ int __init mx27_clocks_init(unsigned long fref)
clk_register_clkdev(clk[sdhc2_ipg_gate], "ipg", "imx21-mmc.1");
clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.2");
clk_register_clkdev(clk[sdhc2_ipg_gate], "ipg", "imx21-mmc.2");
- clk_register_clkdev(clk[cspi1_ipg_gate], NULL, "imx27-cspi.0");
- clk_register_clkdev(clk[cspi2_ipg_gate], NULL, "imx27-cspi.1");
- clk_register_clkdev(clk[cspi3_ipg_gate], NULL, "imx27-cspi.2");
+ clk_register_clkdev(clk[per2_gate], "per", "imx27-cspi.0");
+ clk_register_clkdev(clk[cspi1_ipg_gate], "ipg", "imx27-cspi.0");
+ clk_register_clkdev(clk[per2_gate], "per", "imx27-cspi.1");
+ clk_register_clkdev(clk[cspi2_ipg_gate], "ipg", "imx27-cspi.1");
+ clk_register_clkdev(clk[per2_gate], "per", "imx27-cspi.2");
+ clk_register_clkdev(clk[cspi3_ipg_gate], "ipg", "imx27-cspi.2");
clk_register_clkdev(clk[per3_gate], "per", "imx21-fb.0");
clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx21-fb.0");
clk_register_clkdev(clk[lcdc_ahb_gate], "ahb", "imx21-fb.0");
diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c
index 16ccbd41dea9..b5b65f3efaf1 100644
--- a/arch/arm/mach-imx/clk-imx31.c
+++ b/arch/arm/mach-imx/clk-imx31.c
@@ -34,8 +34,8 @@ static const char *csi_sel[] = { "upll", "spll", };
static const char *fir_sel[] = { "mcu_main", "upll", "spll" };
enum mx31_clks {
- ckih, ckil, mpll, spll, upll, mcu_main, hsp, ahb, nfc, ipg, per_div,
- per, csi, fir, csi_div, usb_div_pre, usb_div_post, fir_div_pre,
+ dummy, ckih, ckil, mpll, spll, upll, mcu_main, hsp, ahb, nfc, ipg,
+ per_div, per, csi, fir, csi_div, usb_div_pre, usb_div_post, fir_div_pre,
fir_div_post, sdhc1_gate, sdhc2_gate, gpt_gate, epit1_gate, epit2_gate,
iim_gate, ata_gate, sdma_gate, cspi3_gate, rng_gate, uart1_gate,
uart2_gate, ssi1_gate, i2c1_gate, i2c2_gate, i2c3_gate, hantro_gate,
@@ -46,12 +46,15 @@ enum mx31_clks {
};
static struct clk *clk[clk_max];
+static struct clk_onecell_data clk_data;
int __init mx31_clocks_init(unsigned long fref)
{
void __iomem *base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR);
int i;
+ struct device_node *np;
+ clk[dummy] = imx_clk_fixed("dummy", 0);
clk[ckih] = imx_clk_fixed("ckih", fref);
clk[ckil] = imx_clk_fixed("ckil", 32768);
clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MXC_CCM_MPCTL);
@@ -116,6 +119,14 @@ int __init mx31_clocks_init(unsigned long fref)
pr_err("imx31 clk %d: register failed with %ld\n",
i, PTR_ERR(clk[i]));
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx31-ccm");
+
+ if (np) {
+ clk_data.clks = clk;
+ clk_data.clk_num = ARRAY_SIZE(clk);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ }
+
clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0");
clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0");
clk_register_clkdev(clk[cspi1_gate], NULL, "imx31-cspi.0");
diff --git a/arch/arm/mach-imx/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c
index f0727e80815d..74e3a34d78b8 100644
--- a/arch/arm/mach-imx/clk-imx35.c
+++ b/arch/arm/mach-imx/clk-imx35.c
@@ -67,13 +67,13 @@ enum mx35_clks {
static struct clk *clk[clk_max];
-int __init mx35_clocks_init()
+int __init mx35_clocks_init(void)
{
void __iomem *base = MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR);
u32 pdr0, consumer_sel, hsp_sel;
struct arm_ahb_div *aad;
unsigned char *hsp_div;
- int i;
+ u32 i;
pdr0 = __raw_readl(base + MXC_CCM_PDR0);
consumer_sel = (pdr0 >> 16) & 0xf;
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index c0c4e723b7f5..540138c4606c 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -54,9 +54,18 @@
#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26)
#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27)
+#define CGPR 0x64
+#define BM_CGPR_CHICKEN_BIT (0x1 << 17)
+
static void __iomem *ccm_base;
-void __init imx6q_clock_map_io(void) { }
+void imx6q_set_chicken_bit(void)
+{
+ u32 val = readl_relaxed(ccm_base + CGPR);
+
+ val |= BM_CGPR_CHICKEN_BIT;
+ writel_relaxed(val, ccm_base + CGPR);
+}
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
{
@@ -68,6 +77,7 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
break;
case WAIT_UNCLOCKED:
val |= 0x1 << BP_CLPCR_LPM;
+ val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM;
break;
case STOP_POWER_ON:
val |= 0x2 << BP_CLPCR_LPM;
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index fa36fb84ab19..5a800bfcec5b 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -21,7 +21,6 @@ extern void mx25_map_io(void);
extern void mx27_map_io(void);
extern void mx31_map_io(void);
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 imx1_init_early(void);
@@ -30,7 +29,6 @@ extern void imx25_init_early(void);
extern void imx27_init_early(void);
extern void imx31_init_early(void);
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 mxc_init_irq(void __iomem *);
@@ -41,7 +39,6 @@ extern void mx25_init_irq(void);
extern void mx27_init_irq(void);
extern void mx31_init_irq(void);
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 imx1_soc_init(void);
@@ -50,7 +47,6 @@ extern void imx25_soc_init(void);
extern void imx27_soc_init(void);
extern void imx31_soc_init(void);
extern void imx35_soc_init(void);
-extern void imx50_soc_init(void);
extern void imx51_soc_init(void);
extern void imx51_init_late(void);
extern void imx53_init_late(void);
@@ -109,27 +105,22 @@ void tzic_handle_irq(struct pt_regs *);
#define imx27_handle_irq avic_handle_irq
#define imx31_handle_irq avic_handle_irq
#define imx35_handle_irq avic_handle_irq
-#define imx50_handle_irq tzic_handle_irq
#define imx51_handle_irq tzic_handle_irq
#define imx53_handle_irq tzic_handle_irq
-#define imx6q_handle_irq gic_handle_irq
extern void imx_enable_cpu(int cpu, bool enable);
extern void imx_set_cpu_jump(int cpu, void *jump_addr);
-#ifdef CONFIG_DEBUG_LL
-extern void imx_lluart_map_io(void);
-#else
-static inline void imx_lluart_map_io(void) {}
-#endif
extern void v7_cpu_resume(void);
extern u32 *pl310_get_save_ptr(void);
#ifdef CONFIG_SMP
extern void v7_secondary_startup(void);
extern void imx_scu_map_io(void);
extern void imx_smp_prepare(void);
+extern void imx_scu_standby_enable(void);
#else
static inline void imx_scu_map_io(void) {}
static inline void imx_smp_prepare(void) {}
+static inline void imx_scu_standby_enable(void) {}
#endif
extern void imx_enable_cpu(int cpu, bool enable);
extern void imx_set_cpu_jump(int cpu, void *jump_addr);
@@ -139,7 +130,7 @@ extern void imx_gpc_init(void);
extern void imx_gpc_pre_suspend(void);
extern void imx_gpc_post_resume(void);
extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
-extern void imx6q_clock_map_io(void);
+extern void imx6q_set_chicken_bit(void);
extern void imx_cpu_die(unsigned int cpu);
extern int imx_cpu_kill(unsigned int cpu);
diff --git a/arch/arm/mach-imx/cpu-imx5.c b/arch/arm/mach-imx/cpu-imx5.c
index d88760014ff9..d7ce72252a4e 100644
--- a/arch/arm/mach-imx/cpu-imx5.c
+++ b/arch/arm/mach-imx/cpu-imx5.c
@@ -22,7 +22,6 @@
static int mx5_cpu_rev = -1;
#define IIM_SREV 0x24
-#define MX50_HW_ADADIG_DIGPROG 0xB0
static int get_mx51_srev(void)
{
@@ -108,41 +107,3 @@ int mx53_revision(void)
return mx5_cpu_rev;
}
EXPORT_SYMBOL(mx53_revision);
-
-static int get_mx50_srev(void)
-{
- void __iomem *anatop = ioremap(MX50_ANATOP_BASE_ADDR, SZ_8K);
- u32 rev;
-
- if (!anatop) {
- mx5_cpu_rev = -EINVAL;
- return 0;
- }
-
- rev = readl(anatop + MX50_HW_ADADIG_DIGPROG);
- rev &= 0xff;
-
- iounmap(anatop);
- if (rev == 0x0)
- return IMX_CHIP_REVISION_1_0;
- else if (rev == 0x1)
- return IMX_CHIP_REVISION_1_1;
- return 0;
-}
-
-/*
- * Returns:
- * the silicon revision of the cpu
- * -EINVAL - not a mx50
- */
-int mx50_revision(void)
-{
- if (!cpu_is_mx50())
- return -EINVAL;
-
- if (mx5_cpu_rev == -1)
- mx5_cpu_rev = get_mx50_srev();
-
- return mx5_cpu_rev;
-}
-EXPORT_SYMBOL(mx50_revision);
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
new file mode 100644
index 000000000000..d533e2695f0e
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 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 <linux/clockchips.h>
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+
+#include "common.h"
+#include "cpuidle.h"
+
+static atomic_t master = ATOMIC_INIT(0);
+static DEFINE_SPINLOCK(master_lock);
+
+static int imx6q_enter_wait(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ int cpu = dev->cpu;
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+
+ if (atomic_inc_return(&master) == num_online_cpus()) {
+ /*
+ * With this lock, we prevent other cpu to exit and enter
+ * this function again and become the master.
+ */
+ if (!spin_trylock(&master_lock))
+ goto idle;
+ imx6q_set_lpm(WAIT_UNCLOCKED);
+ cpu_do_idle();
+ imx6q_set_lpm(WAIT_CLOCKED);
+ spin_unlock(&master_lock);
+ goto done;
+ }
+
+idle:
+ cpu_do_idle();
+done:
+ atomic_dec(&master);
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+
+ return index;
+}
+
+/*
+ * For each cpu, setup the broadcast timer because local timer
+ * stops for the states other than WFI.
+ */
+static void imx6q_setup_broadcast_timer(void *arg)
+{
+ int cpu = smp_processor_id();
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
+}
+
+static struct cpuidle_driver imx6q_cpuidle_driver = {
+ .name = "imx6q_cpuidle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
+ .states = {
+ /* WFI */
+ ARM_CPUIDLE_WFI_STATE,
+ /* WAIT */
+ {
+ .exit_latency = 50,
+ .target_residency = 75,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .enter = imx6q_enter_wait,
+ .name = "WAIT",
+ .desc = "Clock off",
+ },
+ },
+ .state_count = 2,
+ .safe_state_index = 0,
+};
+
+int __init imx6q_cpuidle_init(void)
+{
+ /* Need to enable SCU standby for entering WAIT modes */
+ imx_scu_standby_enable();
+
+ /* Set chicken bit to get a reliable WAIT mode support */
+ imx6q_set_chicken_bit();
+
+ /* Configure the broadcast timer on each cpu */
+ on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1);
+
+ return imx_cpuidle_init(&imx6q_cpuidle_driver);
+}
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h
index bc932d1af372..e092d1359d94 100644
--- a/arch/arm/mach-imx/cpuidle.h
+++ b/arch/arm/mach-imx/cpuidle.h
@@ -14,9 +14,14 @@
#ifdef CONFIG_CPU_IDLE
extern int imx_cpuidle_init(struct cpuidle_driver *drv);
+extern int imx6q_cpuidle_init(void);
#else
static inline int imx_cpuidle_init(struct cpuidle_driver *drv)
{
return -ENODEV;
}
+static inline int imx6q_cpuidle_init(void)
+{
+ return -ENODEV;
+}
#endif
diff --git a/arch/arm/mach-imx/devices-imx50.h b/arch/arm/mach-imx/devices-imx50.h
deleted file mode 100644
index 2c290391f298..000000000000
--- a/arch/arm/mach-imx/devices-imx50.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "devices/devices-common.h"
-
-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;
-#define imx50_add_fec(pdata) \
- imx_add_fec(&imx50_fec_data, pdata)
-
-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-imx/devices/Kconfig b/arch/arm/mach-imx/devices/Kconfig
index 9a8f1ca7bcb1..9b9ba1f4ffe1 100644
--- a/arch/arm/mach-imx/devices/Kconfig
+++ b/arch/arm/mach-imx/devices/Kconfig
@@ -1,6 +1,6 @@
config IMX_HAVE_PLATFORM_FEC
bool
- default y if ARCH_MX25 || SOC_IMX27 || SOC_IMX35 || SOC_IMX50 || SOC_IMX51 || SOC_IMX53
+ default y if ARCH_MX25 || SOC_IMX27 || SOC_IMX35 || SOC_IMX51 || SOC_IMX53
config IMX_HAVE_PLATFORM_FLEXCAN
bool
diff --git a/arch/arm/mach-imx/devices/platform-fec.c b/arch/arm/mach-imx/devices/platform-fec.c
index 2cb188ad9a0a..63eba08f87b1 100644
--- a/arch/arm/mach-imx/devices/platform-fec.c
+++ b/arch/arm/mach-imx/devices/platform-fec.c
@@ -35,12 +35,6 @@ const struct imx_fec_data imx35_fec_data __initconst =
imx_fec_data_entry_single(MX35, "imx27-fec");
#endif
-#ifdef CONFIG_SOC_IMX50
-/* i.mx50 has the i.mx25 type fec */
-const struct imx_fec_data imx50_fec_data __initconst =
- imx_fec_data_entry_single(MX50, "imx25-fec");
-#endif
-
#ifdef CONFIG_SOC_IMX51
/* i.mx51 has the i.mx27 type fec */
const struct imx_fec_data imx51_fec_data __initconst =
diff --git a/arch/arm/mach-imx/devices/platform-imx-i2c.c b/arch/arm/mach-imx/devices/platform-imx-i2c.c
index 8e30e5703cd2..57d342e85c2f 100644
--- a/arch/arm/mach-imx/devices/platform-imx-i2c.c
+++ b/arch/arm/mach-imx/devices/platform-imx-i2c.c
@@ -70,16 +70,6 @@ const struct imx_imx_i2c_data imx35_imx_i2c_data[] __initconst = {
};
#endif /* ifdef CONFIG_SOC_IMX35 */
-#ifdef CONFIG_SOC_IMX50
-const struct imx_imx_i2c_data imx50_imx_i2c_data[] __initconst = {
-#define imx50_imx_i2c_data_entry(_id, _hwid) \
- imx_imx_i2c_data_entry(MX50, "imx21-i2c", _id, _hwid, SZ_4K)
- imx50_imx_i2c_data_entry(0, 1),
- imx50_imx_i2c_data_entry(1, 2),
- imx50_imx_i2c_data_entry(2, 3),
-};
-#endif /* ifdef CONFIG_SOC_IMX51 */
-
#ifdef CONFIG_SOC_IMX51
const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst = {
#define imx51_imx_i2c_data_entry(_id, _hwid) \
diff --git a/arch/arm/mach-imx/devices/platform-imx-uart.c b/arch/arm/mach-imx/devices/platform-imx-uart.c
index 67bf866a2cb6..faac4aa6ca6d 100644
--- a/arch/arm/mach-imx/devices/platform-imx-uart.c
+++ b/arch/arm/mach-imx/devices/platform-imx-uart.c
@@ -94,18 +94,6 @@ const struct imx_imx_uart_1irq_data imx35_imx_uart_data[] __initconst = {
};
#endif /* ifdef CONFIG_SOC_IMX35 */
-#ifdef CONFIG_SOC_IMX50
-const struct imx_imx_uart_1irq_data imx50_imx_uart_data[] __initconst = {
-#define imx50_imx_uart_data_entry(_id, _hwid) \
- imx_imx_uart_1irq_data_entry(MX50, _id, _hwid, SZ_4K)
- imx50_imx_uart_data_entry(0, 1),
- imx50_imx_uart_data_entry(1, 2),
- imx50_imx_uart_data_entry(2, 3),
- imx50_imx_uart_data_entry(3, 4),
- imx50_imx_uart_data_entry(4, 5),
-};
-#endif /* ifdef CONFIG_SOC_IMX50 */
-
#ifdef CONFIG_SOC_IMX51
const struct imx_imx_uart_1irq_data imx51_imx_uart_data[] __initconst = {
#define imx51_imx_uart_data_entry(_id, _hwid) \
diff --git a/arch/arm/mach-imx/epit.c b/arch/arm/mach-imx/epit.c
index 04a5961beeac..e02de188ae83 100644
--- a/arch/arm/mach-imx/epit.c
+++ b/arch/arm/mach-imx/epit.c
@@ -178,7 +178,6 @@ static struct irqaction epit_timer_irq = {
static struct clock_event_device clockevent_epit = {
.name = "epit",
.features = CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.set_mode = epit_set_mode,
.set_next_event = epit_set_next_event,
.rating = 200,
@@ -186,18 +185,10 @@ static struct clock_event_device clockevent_epit = {
static int __init epit_clockevent_init(struct clk *timer_clk)
{
- unsigned int c = clk_get_rate(timer_clk);
-
- clockevent_epit.mult = div_sc(c, NSEC_PER_SEC,
- clockevent_epit.shift);
- clockevent_epit.max_delta_ns =
- clockevent_delta2ns(0xfffffffe, &clockevent_epit);
- clockevent_epit.min_delta_ns =
- clockevent_delta2ns(0x800, &clockevent_epit);
-
clockevent_epit.cpumask = cpumask_of(0);
-
- clockevents_register_device(&clockevent_epit);
+ clockevents_config_and_register(&clockevent_epit,
+ clk_get_rate(timer_clk),
+ 0x800, 0xfffffffe);
return 0;
}
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index e1537f9e45b8..a96ccc7f5012 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -15,7 +15,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <asm/hardware/gic.h>
+#include <linux/irqchip/arm-gic.h>
#define GPC_IMR1 0x008
#define GPC_PGC_CPU_PDN 0x2a0
@@ -101,11 +101,16 @@ static void imx_gpc_irq_mask(struct irq_data *d)
void __init imx_gpc_init(void)
{
struct device_node *np;
+ int i;
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
gpc_base = of_iomap(np, 0);
WARN_ON(!gpc_base);
+ /* Initially mask all interrupts */
+ for (i = 0; i < IMR_NUM; i++)
+ writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4);
+
/* Register GPC as the secondary interrupt controller behind GIC */
gic_arch_extn.irq_mask = imx_gpc_irq_mask;
gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h
index 3ce7fa3bd43f..911e9b31b03f 100644
--- a/arch/arm/mach-imx/hardware.h
+++ b/arch/arm/mach-imx/hardware.h
@@ -72,11 +72,6 @@
* AVIC 0x68000000+0x100000 -> 0xf5800000+0x100000
* X_MEMC 0xb8000000+0x010000 -> 0xf5c00000+0x010000
* SPBA0 0x50000000+0x100000 -> 0xf5400000+0x100000
- * mx50:
- * TZIC 0x0fffc000+0x004000 -> 0xf4bfc000+0x004000
- * AIPS1 0x53f00000+0x100000 -> 0xf5700000+0x100000
- * SPBA0 0x50000000+0x100000 -> 0xf5400000+0x100000
- * AIPS2 0x63f00000+0x100000 -> 0xf5300000+0x100000
* mx51:
* TZIC 0x0fffc000+0x004000 -> 0xf4bfc000+0x004000
* IRAM 0x1ffe0000+0x020000 -> 0xf4fe0000+0x020000
@@ -108,7 +103,6 @@
#include "mxc.h"
#include "mx6q.h"
-#include "mx50.h"
#include "mx51.h"
#include "mx53.h"
#include "mx3x.h"
diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S
index 7e49deb128a4..921fc1555854 100644
--- a/arch/arm/mach-imx/headsmp.S
+++ b/arch/arm/mach-imx/headsmp.S
@@ -17,53 +17,6 @@
.section ".text.head", "ax"
-/*
- * The secondary kernel init calls v7_flush_dcache_all before it enables
- * the L1; however, the L1 comes out of reset in an undefined state, so
- * the clean + invalidate performed by v7_flush_dcache_all causes a bunch
- * of cache lines with uninitialized data and uninitialized tags to get
- * written out to memory, which does really unpleasant things to the main
- * processor. We fix this by performing an invalidate, rather than a
- * clean + invalidate, before jumping into the kernel.
- *
- * This funciton is cloned from arch/arm/mach-tegra/headsmp.S, and needs
- * to be called for both secondary cores startup and primary core resume
- * procedures. Ideally, it should be moved into arch/arm/mm/cache-v7.S.
- */
-ENTRY(v7_invalidate_l1)
- mov r0, #0
- mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
- mcr p15, 2, r0, c0, c0, 0
- mrc p15, 1, r0, c0, c0, 0
-
- ldr r1, =0x7fff
- and r2, r1, r0, lsr #13
-
- ldr r1, =0x3ff
-
- and r3, r1, r0, lsr #3 @ NumWays - 1
- add r2, r2, #1 @ NumSets
-
- and r0, r0, #0x7
- add r0, r0, #4 @ SetShift
-
- clz r1, r3 @ WayShift
- add r4, r3, #1 @ NumWays
-1: sub r2, r2, #1 @ NumSets--
- mov r3, r4 @ Temp = NumWays
-2: subs r3, r3, #1 @ Temp--
- mov r5, r3, lsl r1
- mov r6, r2, lsl r0
- orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
- mcr p15, 0, r5, c7, c6, 2
- bgt 2b
- cmp r2, #0
- bgt 1b
- dsb
- isb
- mov pc, lr
-ENDPROC(v7_invalidate_l1)
-
#ifdef CONFIG_SMP
ENTRY(v7_secondary_startup)
bl v7_invalidate_l1
diff --git a/arch/arm/mach-imx/imx25-dt.c b/arch/arm/mach-imx/imx25-dt.c
index e17dfbc42192..03b65e5ea541 100644
--- a/arch/arm/mach-imx/imx25-dt.c
+++ b/arch/arm/mach-imx/imx25-dt.c
@@ -22,15 +22,6 @@ static void __init imx25_dt_init(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
-static void __init imx25_timer_init(void)
-{
- mx25_clocks_init_dt();
-}
-
-static struct sys_timer imx25_timer = {
- .init = imx25_timer_init,
-};
-
static const char * const imx25_dt_board_compat[] __initconst = {
"fsl,imx25",
NULL
@@ -41,7 +32,7 @@ DT_MACHINE_START(IMX25_DT, "Freescale i.MX25 (Device Tree Support)")
.init_early = imx25_init_early,
.init_irq = mx25_init_irq,
.handle_irq = imx25_handle_irq,
- .timer = &imx25_timer,
+ .init_time = imx25_timer_init,
.init_machine = imx25_dt_init,
.dt_compat = imx25_dt_board_compat,
.restart = mxc_restart,
diff --git a/arch/arm/mach-imx/imx27-dt.c b/arch/arm/mach-imx/imx27-dt.c
index ebfae96543c4..c915a490a11c 100644
--- a/arch/arm/mach-imx/imx27-dt.c
+++ b/arch/arm/mach-imx/imx27-dt.c
@@ -39,26 +39,22 @@ static void __init imx27_dt_init(void)
imx27_auxdata_lookup, NULL);
}
-static void __init imx27_timer_init(void)
-{
- mx27_clocks_init_dt();
-}
-
-static struct sys_timer imx27_timer = {
- .init = imx27_timer_init,
-};
-
static const char * const imx27_dt_board_compat[] __initconst = {
"fsl,imx27",
NULL
};
+static void __init imx27_timer_init(void)
+{
+ mx27_clocks_init_dt();
+}
+
DT_MACHINE_START(IMX27_DT, "Freescale i.MX27 (Device Tree Support)")
.map_io = mx27_map_io,
.init_early = imx27_init_early,
.init_irq = mx27_init_irq,
.handle_irq = imx27_handle_irq,
- .timer = &imx27_timer,
+ .init_time = imx27_timer_init,
.init_machine = imx27_dt_init,
.dt_compat = imx27_dt_board_compat,
.restart = mxc_restart,
diff --git a/arch/arm/mach-imx/imx31-dt.c b/arch/arm/mach-imx/imx31-dt.c
index af476de2570e..67de611e29ab 100644
--- a/arch/arm/mach-imx/imx31-dt.c
+++ b/arch/arm/mach-imx/imx31-dt.c
@@ -18,46 +18,27 @@
#include "common.h"
#include "mx31.h"
-static const struct of_dev_auxdata imx31_auxdata_lookup[] __initconst = {
- OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART1_BASE_ADDR,
- "imx21-uart.0", NULL),
- OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART2_BASE_ADDR,
- "imx21-uart.1", NULL),
- OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART3_BASE_ADDR,
- "imx21-uart.2", NULL),
- OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART4_BASE_ADDR,
- "imx21-uart.3", NULL),
- OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART5_BASE_ADDR,
- "imx21-uart.4", NULL),
- { /* sentinel */ }
-};
-
static void __init imx31_dt_init(void)
{
- of_platform_populate(NULL, of_default_bus_match_table,
- imx31_auxdata_lookup, NULL);
-}
-
-static void __init imx31_timer_init(void)
-{
- mx31_clocks_init_dt();
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
-static struct sys_timer imx31_timer = {
- .init = imx31_timer_init,
-};
-
static const char *imx31_dt_board_compat[] __initdata = {
"fsl,imx31",
NULL
};
+static void __init imx31_dt_timer_init(void)
+{
+ mx31_clocks_init_dt();
+}
+
DT_MACHINE_START(IMX31_DT, "Freescale i.MX31 (Device Tree Support)")
.map_io = mx31_map_io,
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &imx31_timer,
+ .init_time = imx31_dt_timer_init,
.init_machine = imx31_dt_init,
.dt_compat = imx31_dt_board_compat,
.restart = mxc_restart,
diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c
index 5ffa40c673f8..e2926a8863f8 100644
--- a/arch/arm/mach-imx/imx51-dt.c
+++ b/arch/arm/mach-imx/imx51-dt.c
@@ -24,26 +24,22 @@ static void __init imx51_dt_init(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
-static void __init imx51_timer_init(void)
-{
- mx51_clocks_init_dt();
-}
-
-static struct sys_timer imx51_timer = {
- .init = imx51_timer_init,
-};
-
static const char *imx51_dt_board_compat[] __initdata = {
"fsl,imx51",
NULL
};
+static void __init imx51_timer_init(void)
+{
+ mx51_clocks_init_dt();
+}
+
DT_MACHINE_START(IMX51_DT, "Freescale i.MX51 (Device Tree Support)")
.map_io = mx51_map_io,
.init_early = imx51_init_early,
.init_irq = mx51_init_irq,
.handle_irq = imx51_handle_irq,
- .timer = &imx51_timer,
+ .init_time = imx51_timer_init,
.init_machine = imx51_dt_init,
.init_late = imx51_init_late,
.dt_compat = imx51_dt_board_compat,
diff --git a/arch/arm/mach-imx/iomux-mx50.h b/arch/arm/mach-imx/iomux-mx50.h
deleted file mode 100644
index 00f56e0e8009..000000000000
--- a/arch/arm/mach-imx/iomux-mx50.h
+++ /dev/null
@@ -1,977 +0,0 @@
-/*
- * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef __MACH_IOMUX_MX50_H__
-#define __MACH_IOMUX_MX50_H__
-
-#include "iomux-v3.h"
-
-#define MX50_ELCDIF_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_DSE_HIGH)
-
-#define MX50_SD_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | \
- PAD_CTL_PUS_47K_UP | PAD_CTL_DSE_HIGH)
-
-#define MX50_UART_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PKE)
-
-#define MX50_I2C_PAD_CTRL (PAD_CTL_ODE | PAD_CTL_DSE_HIGH | \
- PAD_CTL_PUS_100K_UP | PAD_CTL_HYS)
-
-#define MX50_USB_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \
- PAD_CTL_DSE_HIGH | PAD_CTL_PUS_47K_UP)
-
-#define MX50_FEC_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | \
- PAD_CTL_PUS_22K_UP | PAD_CTL_ODE | \
- PAD_CTL_DSE_HIGH)
-
-#define MX50_OWIRE_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | \
- PAD_CTL_PUS_100K_UP | PAD_CTL_ODE | \
- PAD_CTL_DSE_HIGH | PAD_CTL_SRE_FAST)
-
-#define MX50_KEYPAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | \
- PAD_CTL_PUS_100K_UP | PAD_CTL_DSE_HIGH)
-
-#define MX50_CSPI_SS_PAD (PAD_CTL_PKE | PAD_CTL_PUE | \
- PAD_CTL_PUS_22K_UP | PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_KEY_COL0__KEY_COL0 IOMUX_PAD(0x2CC, 0x20, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_COL0__GPIO_4_0 IOMUX_PAD(0x2CC, 0x20, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_COL0__NANDF_CLE IOMUX_PAD(0x2CC, 0x20, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_KEY_ROW0__KEY_ROW0 IOMUX_PAD(0x2D0, 0x24, 0, 0x0, 0, MX50_KEYPAD_CTRL)
-#define MX50_PAD_KEY_ROW0__GPIO_4_1 IOMUX_PAD(0x2D0, 0x24, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_ROW0__NANDF_ALE IOMUX_PAD(0x2D0, 0x24, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_KEY_COL1__KEY_COL1 IOMUX_PAD(0x2D4, 0x28, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_COL1__GPIO_4_2 IOMUX_PAD(0x2D4, 0x28, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_COL1__NANDF_CE0 IOMUX_PAD(0x2D4, 0x28, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_KEY_ROW1__KEY_ROW1 IOMUX_PAD(0x2D8, 0x2C, 0, 0x0, 0, MX50_KEYPAD_CTRL)
-#define MX50_PAD_KEY_ROW1__GPIO_4_3 IOMUX_PAD(0x2D8, 0x2C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_ROW1__NANDF_CE1 IOMUX_PAD(0x2D8, 0x2C, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_KEY_COL2__KEY_COL2 IOMUX_PAD(0x2DC, 0x30, 0, 0x0, 0, MX50_KEYPAD_CTRL)
-#define MX50_PAD_KEY_COL2__GPIO_4_4 IOMUX_PAD(0x2DC, 0x30, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_COL2__NANDF_CE2 IOMUX_PAD(0x2DC, 0x30, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_KEY_ROW2__KEY_ROW2 IOMUX_PAD(0x2E0, 0x34, 0, 0x0, 0, MX50_KEYPAD_CTRL)
-#define MX50_PAD_KEY_ROW2__GPIO_4_5 IOMUX_PAD(0x2E0, 0x34, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_ROW2__NANDF_CE3 IOMUX_PAD(0x2E0, 0x34, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_KEY_COL3__KEY_COL3 IOMUX_PAD(0x2E4, 0x38, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_COL3__GPIO_4_6 IOMUX_PAD(0x2E4, 0x38, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_COL3__NANDF_READY IOMUX_PAD(0x2E4, 0x38, 2, 0x7b4, 0, PAD_CTL_PKE | \
- PAD_CTL_PUE | PAD_CTL_PUS_100K_UP)
-#define MX50_PAD_KEY_COL3__SDMA_EXT0 IOMUX_PAD(0x2E4, 0x38, 6, 0x7b8, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_KEY_ROW3__KEY_ROW3 IOMUX_PAD(0x2E8, 0x3C, 0, 0x0, 0, MX50_KEYPAD_CTRL)
-#define MX50_PAD_KEY_ROW3__GPIO_4_7 IOMUX_PAD(0x2E8, 0x3C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_KEY_ROW3__NANDF_DQS IOMUX_PAD(0x2E8, 0x3C, 2, 0x7b0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_KEY_ROW3__SDMA_EXT1 IOMUX_PAD(0x2E8, 0x3C, 6, 0x7bc, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_I2C1_SCL__I2C1_SCL IOMUX_PAD(0x2EC, 0x40, IOMUX_CONFIG_SION, 0x0, 0, \
- MX50_I2C_PAD_CTRL)
-#define MX50_PAD_I2C1_SCL__GPIO_6_18 IOMUX_PAD(0x2EC, 0x40, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C1_SCL__UART2_TXD IOMUX_PAD(0x2EC, 0x40, 2, 0x0, 0, MX50_UART_PAD_CTRL)
-
-#define MX50_PAD_I2C1_SDA__I2C1_SDA IOMUX_PAD(0x2F0, 0x44, IOMUX_CONFIG_SION, 0x0, 0, \
- MX50_I2C_PAD_CTRL)
-#define MX50_PAD_I2C1_SDA__GPIO_6_19 IOMUX_PAD(0x2F0, 0x44, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C1_SDA__UART2_RXD IOMUX_PAD(0x2F0, 0x44, 2, 0x7cc, 1, MX50_UART_PAD_CTRL)
-
-#define MX50_PAD_I2C2_SCL__I2C2_SCL IOMUX_PAD(0x2F4, 0x48, IOMUX_CONFIG_SION, 0x0, 0, \
- MX50_I2C_PAD_CTRL)
-#define MX50_PAD_I2C2_SCL__GPIO_6_20 IOMUX_PAD(0x2F4, 0x48, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C2_SCL__UART2_CTS IOMUX_PAD(0x2F4, 0x48, 2, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_I2C2_SCL__DCDC_OK IOMUX_PAD(0x2F4, 0x48, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_I2C2_SDA__I2C2_SDA IOMUX_PAD(0x2F8, 0x4C, IOMUX_CONFIG_SION, 0x0, 0, \
- MX50_I2C_PAD_CTRL)
-#define MX50_PAD_I2C2_SDA__GPIO_6_21 IOMUX_PAD(0x2F8, 0x4C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C2_SDA__UART2_RTS IOMUX_PAD(0x2F8, 0x4C, 2, 0x7c8, 1, MX50_UART_PAD_CTRL)
-#define MX50_PAD_I2C2_SDA__PWRSTABLE IOMUX_PAD(0x2F8, 0x4C, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_I2C3_SCL__I2C3_SCL IOMUX_PAD(0x2FC, 0x50, IOMUX_CONFIG_SION, 0x0, 0, \
- MX50_I2C_PAD_CTRL)
-#define MX50_PAD_I2C3_SCL__GPIO_6_22 IOMUX_PAD(0x2FC, 0x50, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C3_SCL__FEC_MDC IOMUX_PAD(0x2FC, 0x50, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_I2C3_SCL__PMIC_RDY IOMUX_PAD(0x2FC, 0x50, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C3_SCL__GPT_CAPIN1 IOMUX_PAD(0x2FC, 0x50, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C3_SCL__USBOTG_OC IOMUX_PAD(0x2FC, 0x50, 7, 0x7E8, 0, MX50_USB_PAD_CTRL)
-
-#define MX50_PAD_I2C3_SDA__I2C3_SDA IOMUX_PAD(0x300, 0x54, IOMUX_CONFIG_SION, 0x0, 0, \
- MX50_I2C_PAD_CTRL)
-#define MX50_PAD_I2C3_SDA__GPIO_6_23 IOMUX_PAD(0x300, 0x54, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C3_SDA__FEC_MDIO IOMUX_PAD(0x300, 0x54, 2, 0x774, 0, MX50_FEC_PAD_CTRL)
-#define MX50_PAD_I2C3_SDA__PWRFAIL_INT IOMUX_PAD(0x300, 0x54, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C3_SDA__ALARM_DEB IOMUX_PAD(0x300, 0x54, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C3_SDA__GPT_CAPIN1 IOMUX_PAD(0x300, 0x54, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C3_SDA__USBOTG_PWR IOMUX_PAD(0x300, 0x54, 7, 0x0, 0, \
- PAD_CTL_PKE | PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_PWM1__PWM1_PWMO IOMUX_PAD(0x304, 0x58, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_PWM1__GPIO_6_24 IOMUX_PAD(0x304, 0x58, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_PWM1__USBOTG_OC IOMUX_PAD(0x304, 0x58, 2, 0x7E8, 1, MX50_USB_PAD_CTRL)
-#define MX50_PAD_PWM1__GPT_CMPOUT1 IOMUX_PAD(0x304, 0x58, 5, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PWM2__PWM2_PWMO IOMUX_PAD(0x308, 0x5C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_PWM2__GPIO_6_25 IOMUX_PAD(0x308, 0x5C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_PWM2__USBOTG_PWR IOMUX_PAD(0x308, 0x5C, 2, 0x0, 0, \
- PAD_CTL_PKE | PAD_CTL_DSE_HIGH)
-#define MX50_PAD_PWM2__DCDC_PWM IOMUX_PAD(0x308, 0x5C, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_PWM2__GPT_CMPOUT2 IOMUX_PAD(0x308, 0x5C, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_PWM2__ANY_PU_RST IOMUX_PAD(0x308, 0x5C, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_OWIRE__OWIRE IOMUX_PAD(0x30C, 0x60, 0, 0x0, 0, MX50_OWIRE_PAD_CTRL)
-#define MX50_PAD_OWIRE__GPIO_6_26 IOMUX_PAD(0x30C, 0x60, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_OWIRE__USBH1_OC IOMUX_PAD(0x30C, 0x60, 2, 0x0, 0, MX50_USB_PAD_CTRL)
-#define MX50_PAD_OWIRE__SSI_EXT1_CLK IOMUX_PAD(0x30C, 0x60, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_OWIRE__EPDC_PWRIRQ IOMUX_PAD(0x30C, 0x60, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_OWIRE__GPT_CMPOUT3 IOMUX_PAD(0x30C, 0x60, 5, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPITO__EPITO IOMUX_PAD(0x310, 0x64, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPITO__GPIO_6_27 IOMUX_PAD(0x310, 0x64, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPITO__USBH1_PWR IOMUX_PAD(0x310, 0x64, 2, 0x0, 0, \
- PAD_CTL_PKE | PAD_CTL_DSE_HIGH)
-#define MX50_PAD_EPITO__SSI_EXT2_CLK IOMUX_PAD(0x310, 0x64, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPITO__TOG_EN IOMUX_PAD(0x310, 0x64, 4, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPITO__GPT_CLKIN IOMUX_PAD(0x310, 0x64, 5, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_WDOG__WDOG IOMUX_PAD(0x314, 0x68, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_WDOG__GPIO_6_28 IOMUX_PAD(0x314, 0x68, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_WDOG__WDOG_RST IOMUX_PAD(0x314, 0x68, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_WDOG__XTAL32K IOMUX_PAD(0x314, 0x68, 6, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SSI_TXFS__SSI_TXFS IOMUX_PAD(0x318, 0x6C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_TXFS__GPIO_6_0 IOMUX_PAD(0x318, 0x6C, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SSI_TXC__SSI_TXC IOMUX_PAD(0x31C, 0x70, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_TXC__GPIO_6_1 IOMUX_PAD(0x31C, 0x70, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SSI_TXD__SSI_TXD IOMUX_PAD(0x320, 0x74, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_TXD__GPIO_6_2 IOMUX_PAD(0x320, 0x74, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_TXD__CSPI_RDY IOMUX_PAD(0x320, 0x74, 4, 0x6e8, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SSI_RXD__SSI_RXD IOMUX_PAD(0x324, 0x78, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_RXD__GPIO_6_3 IOMUX_PAD(0x324, 0x78, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_RXD__CSPI_SS3 IOMUX_PAD(0x324, 0x78, 4, 0x6f4, 0, MX50_CSPI_SS_PAD)
-
-#define MX50_PAD_SSI_RXFS__AUD3_RXFS IOMUX_PAD(0x328, 0x7C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_RXFS__GPIO_6_4 IOMUX_PAD(0x328, 0x7C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_RXFS__UART5_TXD IOMUX_PAD(0x328, 0x7C, 2, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_SSI_RXFS__WEIM_D6 IOMUX_PAD(0x328, 0x7C, 3, 0x804, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_RXFS__CSPI_SS2 IOMUX_PAD(0x328, 0x7C, 4, 0x6f0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_SSI_RXFS__FEC_COL IOMUX_PAD(0x328, 0x7C, 5, 0x770, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SSI_RXFS__FEC_MDC IOMUX_PAD(0x328, 0x7C, 6, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_SSI_RXC__AUD3_RXC IOMUX_PAD(0x32C, 0x80, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_RXC__GPIO_6_5 IOMUX_PAD(0x32C, 0x80, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_RXC__UART5_RXD IOMUX_PAD(0x32C, 0x80, 2, 0x7e4, 1, MX50_UART_PAD_CTRL)
-#define MX50_PAD_SSI_RXC__WEIM_D7 IOMUX_PAD(0x32C, 0x80, 3, 0x808, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_RXC__CSPI_SS1 IOMUX_PAD(0x32C, 0x80, 4, 0x6ec, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_SSI_RXC__FEC_RX_CLK IOMUX_PAD(0x32C, 0x80, 5, 0x780, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_RXC__FEC_MDIO IOMUX_PAD(0x32C, 0x80, 6, 0x774, 1, MX50_FEC_PAD_CTRL)
-
-#define MX50_PAD_UART1_TXD__UART1_TXD IOMUX_PAD(0x330, 0x84, 0, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART1_TXD__GPIO_6_6 IOMUX_PAD(0x330, 0x84, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_UART1_RXD__UART1_RXD IOMUX_PAD(0x334, 0x88, 0, 0x7c4, 1, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART1_RXD__GPIO_6_7 IOMUX_PAD(0x334, 0x88, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_UART1_CTS__UART1_CTS IOMUX_PAD(0x338, 0x8C, 0, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART1_CTS__GPIO_6_8 IOMUX_PAD(0x338, 0x8C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART1_CTS__UART5_TXD IOMUX_PAD(0x338, 0x8C, 2, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART1_CTS__SD4_D4 IOMUX_PAD(0x338, 0x8C, 4, 0x760, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART1_CTS__SD4_CMD IOMUX_PAD(0x338, 0x8C, 5, 0x74c, 0, MX50_SD_PAD_CTRL)
-
-#define MX50_PAD_UART1_RTS__UART1_RTS IOMUX_PAD(0x33C, 0x90, 0, 0x7c0, 1, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART1_RTS__GPIO_6_9 IOMUX_PAD(0x33C, 0x90, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART1_RTS__UART5_RXD IOMUX_PAD(0x33C, 0x90, 2, 0x7e4, 3, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART1_RTS__SD4_D5 IOMUX_PAD(0x33C, 0x90, 4, 0x764, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART1_RTS__SD4_CLK IOMUX_PAD(0x33C, 0x90, 5, 0x748, 0, MX50_SD_PAD_CTRL)
-
-#define MX50_PAD_UART2_TXD__UART2_TXD IOMUX_PAD(0x340, 0x94, 0, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART2_TXD__GPIO_6_10 IOMUX_PAD(0x340, 0x94, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART2_TXD__SD4_D6 IOMUX_PAD(0x340, 0x94, 4, 0x768, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART2_TXD__SD4_D4 IOMUX_PAD(0x340, 0x94, 5, 0x760, 1, MX50_SD_PAD_CTRL)
-
-#define MX50_PAD_UART2_RXD__UART2_RXD IOMUX_PAD(0x344, 0x98, 0, 0x7cc, 3, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART2_RXD__GPIO_6_11 IOMUX_PAD(0x344, 0x98, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART2_RXD__SD4_D7 IOMUX_PAD(0x344, 0x98, 4, 0x76c, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART2_RXD__SD4_D5 IOMUX_PAD(0x344, 0x98, 5, 0x764, 1, MX50_SD_PAD_CTRL)
-
-#define MX50_PAD_UART2_CTS__UART2_CTS IOMUX_PAD(0x348, 0x9C, 0, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART2_CTS__GPIO_6_12 IOMUX_PAD(0x348, 0x9C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART2_CTS__SD4_CMD IOMUX_PAD(0x348, 0x9C, 4, 0x74c, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART2_CTS__SD4_D6 IOMUX_PAD(0x348, 0x9C, 5, 0x768, 1, MX50_SD_PAD_CTRL)
-
-#define MX50_PAD_UART2_RTS__UART2_RTS IOMUX_PAD(0x34C, 0xA0, 0, 0x7c8, 3, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART2_RTS__GPIO_6_13 IOMUX_PAD(0x34C, 0xA0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART2_RTS__SD4_CLK IOMUX_PAD(0x34C, 0xA0, 4, 0x748, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART2_RTS__SD4_D7 IOMUX_PAD(0x34C, 0xA0, 5, 0x76c, 1, MX50_SD_PAD_CTRL)
-
-#define MX50_PAD_UART3_TXD__UART3_TXD IOMUX_PAD(0x350, 0xA4, 0, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART3_TXD__GPIO_6_14 IOMUX_PAD(0x350, 0xA4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART3_TXD__SD1_D4 IOMUX_PAD(0x350, 0xA4, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART3_TXD__SD4_D0 IOMUX_PAD(0x350, 0xA4, 4, 0x750, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART3_TXD__SD2_WP IOMUX_PAD(0x350, 0xA4, 5, 0x744, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART3_TXD__WEIM_D12 IOMUX_PAD(0x350, 0xA4, 6, 0x81c, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_UART3_RXD__UART3_RXD IOMUX_PAD(0x354, 0xA8, 0, 0x7d4, 1, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART3_RXD__GPIO_6_15 IOMUX_PAD(0x354, 0xA8, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART3_RXD__SD1_D5 IOMUX_PAD(0x354, 0xA8, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART3_RXD__SD4_D1 IOMUX_PAD(0x354, 0xA8, 4, 0x754, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART3_RXD__SD2_CD IOMUX_PAD(0x354, 0xA8, 5, 0x740, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART3_RXD__WEIM_D13 IOMUX_PAD(0x354, 0xA8, 6, 0x820, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_UART4_TXD__UART4_TXD IOMUX_PAD(0x358, 0xAC, 0, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART4_TXD__GPIO_6_16 IOMUX_PAD(0x358, 0xAC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART4_TXD__UART3_CTS IOMUX_PAD(0x358, 0xAC, 2, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART4_TXD__SD1_D6 IOMUX_PAD(0x358, 0xAC, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART4_TXD__SD4_D2 IOMUX_PAD(0x358, 0xAC, 4, 0x758, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART4_TXD__SD2_LCTL IOMUX_PAD(0x358, 0xAC, 5, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART4_TXD__WEIM_D14 IOMUX_PAD(0x358, 0xAC, 6, 0x824, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_UART4_RXD__UART4_RXD IOMUX_PAD(0x35C, 0xB0, 0, 0x7dc, 1, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART4_RXD__GPIO_6_17 IOMUX_PAD(0x35C, 0xB0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART4_RXD__UART3_RTS IOMUX_PAD(0x35C, 0xB0, 2, 0x7d0, 1, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART4_RXD__SD1_D7 IOMUX_PAD(0x35C, 0xB0, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART4_RXD__SD4_D3 IOMUX_PAD(0x35C, 0xB0, 4, 0x75c, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART4_RXD__SD1_LCTL IOMUX_PAD(0x35C, 0xB0, 5, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART4_RXD__WEIM_D15 IOMUX_PAD(0x35C, 0xB0, 6, 0x828, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_CSPI_SCLK__CSPI_SCLK IOMUX_PAD(0x360, 0xB4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_CSPI_SCLK__GPIO_4_8 IOMUX_PAD(0x360, 0xB4, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_CSPI_MOSI__CSPI_MOSI IOMUX_PAD(0x364, 0xB8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_CSPI_MOSI__GPIO_4_9 IOMUX_PAD(0x364, 0xB8, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_CSPI_MISO__CSPI_MISO IOMUX_PAD(0x368, 0xBC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_CSPI_MISO__GPIO_4_10 IOMUX_PAD(0x368, 0xBC, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_CSPI_SS0__CSPI_SS0 IOMUX_PAD(0x36C, 0xC0, 0, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_CSPI_SS0__GPIO_4_11 IOMUX_PAD(0x36C, 0xC0, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_ECSPI1_SCLK__ECSPI1_SCLK IOMUX_PAD(0x370, 0xC4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_SCLK__GPIO_4_12 IOMUX_PAD(0x370, 0xC4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_SCLK__CSPI_RDY IOMUX_PAD(0x370, 0xC4, 2, 0x6e8, 1, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_SCLK__ECSPI2_RDY IOMUX_PAD(0x370, 0xC4, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_SCLK__UART3_RTS IOMUX_PAD(0x370, 0xC4, 4, 0x7d0, 2, MX50_UART_PAD_CTRL)
-#define MX50_PAD_ECSPI1_SCLK__EPDC_SDCE6 IOMUX_PAD(0x370, 0xC4, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_SCLK__WEIM_D8 IOMUX_PAD(0x370, 0xC4, 7, 0x80c, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_ECSPI1_MOSI__ECSPI1_MOSI IOMUX_PAD(0x374, 0xC8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_MOSI__GPIO_4_13 IOMUX_PAD(0x374, 0xC8, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_MOSI__CSPI_SS1 IOMUX_PAD(0x374, 0xC8, 2, 0x6ec, 1, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI1_MOSI__ECSPI2_SS1 IOMUX_PAD(0x374, 0xC8, 3, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI1_MOSI__UART3_CTS IOMUX_PAD(0x374, 0xC8, 4, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_ECSPI1_MOSI__EPDC_SDCE7 IOMUX_PAD(0x374, 0xC8, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_MOSI__WEIM_D9 IOMUX_PAD(0x374, 0xC8, 7, 0x810, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_ECSPI1_MISO__ECSPI1_MISO IOMUX_PAD(0x378, 0xCC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_MISO__GPIO_4_14 IOMUX_PAD(0x378, 0xCC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_MISO__CSPI_SS2 IOMUX_PAD(0x378, 0xCC, 2, 0x6f0, 1, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI1_MISO__ECSPI2_SS2 IOMUX_PAD(0x378, 0xCC, 3, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI1_MISO__UART4_RTS IOMUX_PAD(0x378, 0xCC, 4, 0x7d8, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_ECSPI1_MISO__EPDC_SDCE8 IOMUX_PAD(0x378, 0xCC, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_MISO__WEIM_D10 IOMUX_PAD(0x378, 0xCC, 7, 0x814, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_ECSPI1_SS0__ECSPI1_SS0 IOMUX_PAD(0x37C, 0xD0, 0, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI1_SS0__GPIO_4_15 IOMUX_PAD(0x37C, 0xD0, 1, 0x0, 0, PAD_CTL_PUS_100K_UP)
-#define MX50_PAD_ECSPI1_SS0__CSPI_SS3 IOMUX_PAD(0x37C, 0xD0, 2, 0x6f4, 1, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI1_SS0__ECSPI2_SS3 IOMUX_PAD(0x37C, 0xD0, 3, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI1_SS0__UART4_CTS IOMUX_PAD(0x37C, 0xD0, 4, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_ECSPI1_SS0__EPDC_SDCE9 IOMUX_PAD(0x37C, 0xD0, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI1_SS0__WEIM_D11 IOMUX_PAD(0x37C, 0xD0, 7, 0x818, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_ECSPI2_SCLK__ECSPI2_SCLK IOMUX_PAD(0x380, 0xD4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SCLK__GPIO_4_16 IOMUX_PAD(0x380, 0xD4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SCLK__ELCDIF_WR IOMUX_PAD(0x380, 0xD4, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SCLK__ECSPI1_RDY IOMUX_PAD(0x380, 0xD4, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SCLK__UART5_RTS IOMUX_PAD(0x380, 0xD4, 4, 0x7e0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SCLK__ELCDIF_DOTCLK IOMUX_PAD(0x380, 0xD4, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SCLK__NANDF_CEN4 IOMUX_PAD(0x380, 0xD4, 6, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SCLK__WEIM_D8 IOMUX_PAD(0x380, 0xD4, 7, 0x80c, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_ECSPI2_MOSI__ECSPI2_MOSI IOMUX_PAD(0x384, 0xD8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MOSI__GPIO_4_17 IOMUX_PAD(0x384, 0xD8, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MOSI__ELCDIF_RD IOMUX_PAD(0x384, 0xD8, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MOSI__ECSPI1_SS1 IOMUX_PAD(0x384, 0xD8, 3, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI2_MOSI__UART5_CTS IOMUX_PAD(0x384, 0xD8, 4, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MOSI__ELCDIF_EN IOMUX_PAD(0x384, 0xD8, 5, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MOSI__NANDF_CEN5 IOMUX_PAD(0x384, 0xD8, 6, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MOSI__WEIM_D9 IOMUX_PAD(0x384, 0xD8, 7, 0x810, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_ECSPI2_MISO__ECSPI2_MISO IOMUX_PAD(0x388, 0xDC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MISO__GPIO_4_18 IOMUX_PAD(0x388, 0xDC, 1, 0x0, 0, PAD_CTL_PUS_100K_UP)
-#define MX50_PAD_ECSPI2_MISO__ELCDIF_RS IOMUX_PAD(0x388, 0xDC, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MISO__ECSPI1_SS2 IOMUX_PAD(0x388, 0xDC, 3, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI2_MISO__UART5_TXD IOMUX_PAD(0x388, 0xDC, 4, 0x0, 0, MX50_UART_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MISO__ELCDIF_VSYNC IOMUX_PAD(0x388, 0xDC, 5, 0x73c, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MISO__NANDF_CEN6 IOMUX_PAD(0x388, 0xDC, 6, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MISO__WEIM_D10 IOMUX_PAD(0x388, 0xDC, 7, 0x814, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_ECSPI2_SS0__ECSPI2_SS0 IOMUX_PAD(0x38C, 0xE0, 0, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI2_SS0__GPIO_4_19 IOMUX_PAD(0x38C, 0xE0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SS0__ELCDIF_CS IOMUX_PAD(0x38C, 0xE0, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SS0__ECSPI1_SS3 IOMUX_PAD(0x38C, 0xE0, 3, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI2_SS0__UART5_RXD IOMUX_PAD(0x38C, 0xE0, 4, 0x7e4, 5, MX50_UART_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SS0__ELCDIF_HSYNC IOMUX_PAD(0x38C, 0xE0, 5, 0x6f8, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SS0__NANDF_CEN7 IOMUX_PAD(0x38C, 0xE0, 6, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_SS0__WEIM_D11 IOMUX_PAD(0x38C, 0xE0, 7, 0x818, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_SD1_CLK__SD1_CLK IOMUX_PAD(0x390, 0xE4, IOMUX_CONFIG_SION, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD1_CLK__GPIO_5_0 IOMUX_PAD(0x390, 0xE4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD1_CLK__CLKO IOMUX_PAD(0x390, 0xE4, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD1_CMD__SD1_CMD IOMUX_PAD(0x394, 0xE8, IOMUX_CONFIG_SION, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD1_CMD__GPIO_5_1 IOMUX_PAD(0x394, 0xE8, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD1_CMD__CLKO2 IOMUX_PAD(0x394, 0xE8, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD1_D0__SD1_D0 IOMUX_PAD(0x398, 0xEC, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD1_D0__GPIO_5_2 IOMUX_PAD(0x398, 0xEC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD1_D0__PLL1_BYP IOMUX_PAD(0x398, 0xEC, 7, 0x6dc, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD1_D1__SD1_D1 IOMUX_PAD(0x39C, 0xF0, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD1_D1__GPIO_5_3 IOMUX_PAD(0x39C, 0xF0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD1_D1__PLL2_BYP IOMUX_PAD(0x39C, 0xF0, 7, 0x6e0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD1_D2__SD1_D2 IOMUX_PAD(0x3A0, 0xF4, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD1_D2__GPIO_5_4 IOMUX_PAD(0x3A0, 0xF4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD1_D2__PLL3_BYP IOMUX_PAD(0x3A0, 0xF4, 7, 0x6e4, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD1_D3__SD1_D3 IOMUX_PAD(0x3A4, 0xF8, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD1_D3__GPIO_5_5 IOMUX_PAD(0x3A4, 0xF8, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD2_CLK__SD2_CLK IOMUX_PAD(0x3A8, 0xFC, IOMUX_CONFIG_SION, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_CLK__GPIO_5_6 IOMUX_PAD(0x3A8, 0xFC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_CLK__MSHC_SCLK IOMUX_PAD(0x3A8, 0xFC, 2, 0x0, 0, MX50_SD_PAD_CTRL)
-
-#define MX50_PAD_SD2_CMD__SD2_CMD IOMUX_PAD(0x3AC, 0x100, IOMUX_CONFIG_SION, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_CMD__GPIO_5_7 IOMUX_PAD(0x3AC, 0x100, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_CMD__MSHC_BS IOMUX_PAD(0x3AC, 0x100, 2, 0x0, 0, MX50_SD_PAD_CTRL)
-
-#define MX50_PAD_SD2_D0__SD2_D0 IOMUX_PAD(0x3B0, 0x104, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D0__GPIO_5_8 IOMUX_PAD(0x3B0, 0x104, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D0__MSHC_D0 IOMUX_PAD(0x3B0, 0x104, 2, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D0__KEY_COL4 IOMUX_PAD(0x3B0, 0x104, 3, 0x790, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD2_D1__SD2_D1 IOMUX_PAD(0x3B4, 0x108, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D1__GPIO_5_9 IOMUX_PAD(0x3B4, 0x108, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D1__MSHC_D1 IOMUX_PAD(0x3B4, 0x108, 2, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D1__KEY_ROW4 IOMUX_PAD(0x3B4, 0x108, 3, 0x7a0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD2_D2__SD2_D2 IOMUX_PAD(0x3B8, 0x10C, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D2__GPIO_5_10 IOMUX_PAD(0x3B8, 0x10C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D2__MSHC_D2 IOMUX_PAD(0x3B8, 0x10C, 2, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D2__KEY_COL5 IOMUX_PAD(0x3B8, 0x10C, 3, 0x794, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD2_D3__SD2_D3 IOMUX_PAD(0x3BC, 0x110, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D3__GPIO_5_11 IOMUX_PAD(0x3BC, 0x110, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D3__MSHC_D3 IOMUX_PAD(0x3BC, 0x110, 2, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D3__KEY_ROW5 IOMUX_PAD(0x3BC, 0x110, 3, 0x7a4, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD2_D4__SD2_D4 IOMUX_PAD(0x3C0, 0x114, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D4__GPIO_5_12 IOMUX_PAD(0x3C0, 0x114, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D4__AUD4_RXFS IOMUX_PAD(0x3C0, 0x114, 2, 0x6d0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D4__KEY_COL6 IOMUX_PAD(0x3C0, 0x114, 3, 0x798, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D4__WEIM_D0 IOMUX_PAD(0x3C0, 0x114, 4, 0x7ec, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D4__CCM_OUT0 IOMUX_PAD(0x3C0, 0x114, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD2_D5__SD2_D5 IOMUX_PAD(0x3C4, 0x118, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D5__GPIO_5_13 IOMUX_PAD(0x3C4, 0x118, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D5__AUD4_RXC IOMUX_PAD(0x3C4, 0x118, 2, 0x6cc, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D5__KEY_ROW6 IOMUX_PAD(0x3C4, 0x118, 3, 0x7a8, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D5__WEIM_D1 IOMUX_PAD(0x3C4, 0x118, 4, 0x7f0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D5__CCM_OUT1 IOMUX_PAD(0x3C4, 0x118, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD2_D6__SD2_D6 IOMUX_PAD(0x3C8, 0x11C, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D6__GPIO_5_14 IOMUX_PAD(0x3C8, 0x11C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D6__AUD4_RXD IOMUX_PAD(0x3C8, 0x11C, 2, 0x6c4, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D6__KEY_COL7 IOMUX_PAD(0x3C8, 0x11C, 3, 0x79c, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D6__WEIM_D2 IOMUX_PAD(0x3C8, 0x11C, 4, 0x7f4, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D6__CCM_OUT2 IOMUX_PAD(0x3C8, 0x11C, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD2_D7__SD2_D7 IOMUX_PAD(0x3CC, 0x120, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_D7__GPIO_5_15 IOMUX_PAD(0x3CC, 0x120, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D7__AUD4_TXFS IOMUX_PAD(0x3CC, 0x120, 2, 0x6d8, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D7__KEY_ROW7 IOMUX_PAD(0x3CC, 0x120, 3, 0x7ac, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D7__WEIM_D3 IOMUX_PAD(0x3CC, 0x120, 4, 0x7f8, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_D7__CCM_STOP IOMUX_PAD(0x3CC, 0x120, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD2_WP__SD2_WP IOMUX_PAD(0x3D0, 0x124, 0, 0x744, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_WP__GPIO_5_16 IOMUX_PAD(0x3D0, 0x124, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_WP__AUD4_TXD IOMUX_PAD(0x3D0, 0x124, 2, 0x6c8, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_WP__WEIM_D4 IOMUX_PAD(0x3D0, 0x124, 4, 0x7fc, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_WP__CCM_WAIT IOMUX_PAD(0x3D0, 0x124, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD2_CD__SD2_CD IOMUX_PAD(0x3D4, 0x128, 0, 0x740, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD2_CD__GPIO_5_17 IOMUX_PAD(0x3D4, 0x128, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_CD__AUD4_TXC IOMUX_PAD(0x3D4, 0x128, 2, 0x6d4, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_CD__WEIM_D5 IOMUX_PAD(0x3D4, 0x128, 4, 0x800, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD2_CD__CCM_REF_EN IOMUX_PAD(0x3D4, 0x128, 7, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_ON_REQ__PMIC_ON_REQ IOMUX_PAD(0x3D8, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_STBY_REQ__PMIC_STBY_REQ IOMUX_PAD(0x3DC, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_PORT_B__PMIC_PORT_B IOMUX_PAD(0x3E0, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_BOOT_MODE1__PMIC_BOOT_MODE1 IOMUX_PAD(0x3E4, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_RESET_IN_B__PMIC_RESET_IN_B IOMUX_PAD(0x3E8, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_BOOT_MODE0__PMIC_BOOT_MODE0 IOMUX_PAD(0x3EC, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_TEST_MODE__PMIC_TEST_MODE IOMUX_PAD(0x3F0, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_JTAG_TMS__PMIC_JTAG_TMS IOMUX_PAD(0x3F4, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_JTAG_MOD__PMIC_JTAG_MOD IOMUX_PAD(0x3F8, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_JTAG_TRSTB__PMIC_JTAG_TRSTB IOMUX_PAD(0x3FC, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_JTAG_TDI__PMIC_JTAG_TDI IOMUX_PAD(0x400, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_JTAG_TCK__PMIC_JTAG_TCK IOMUX_PAD(0x404, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_PMIC_JTAG_TDO__PMIC_JTAG_TDO IOMUX_PAD(0x408, 0, 0, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D0__DISP_D0 IOMUX_PAD(0x40C, 0x12C, 0, 0x6fc, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D0__GPIO_2_0 IOMUX_PAD(0x40C, 0x12C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D0__FEC_TXCLK IOMUX_PAD(0x40C, 0x12C, 2, 0x78c, 0, PAD_CTL_HYS | PAD_CTL_PKE)
-
-#define MX50_PAD_DISP_D1__DISP_D1 IOMUX_PAD(0x410, 0x130, 0, 0x700, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D1__GPIO_2_1 IOMUX_PAD(0x410, 0x130, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D1__FEC_RX_ER IOMUX_PAD(0x410, 0x130, 2, 0x788, 0, PAD_CTL_HYS | PAD_CTL_PKE)
-#define MX50_PAD_DISP_D1__WEIM_A17 IOMUX_PAD(0x410, 0x130, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D2__DISP_D2 IOMUX_PAD(0x414, 0x134, 0, 0x704, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D2__GPIO_2_2 IOMUX_PAD(0x414, 0x134, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D2__FEC_RX_DV IOMUX_PAD(0x414, 0x134, 2, 0x784, 0, PAD_CTL_HYS | PAD_CTL_PKE)
-#define MX50_PAD_DISP_D2__WEIM_A18 IOMUX_PAD(0x414, 0x134, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D3__DISP_D3 IOMUX_PAD(0x418, 0x138, 0, 0x708, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D3__GPIO_2_3 IOMUX_PAD(0x418, 0x138, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D3__FEC_RXD1 IOMUX_PAD(0x418, 0x138, 2, 0x77C, 0, PAD_CTL_HYS | PAD_CTL_PKE)
-#define MX50_PAD_DISP_D3__WEIM_A19 IOMUX_PAD(0x418, 0x138, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D3__FEC_COL IOMUX_PAD(0x418, 0x138, 4, 0x770, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D4__DISP_D4 IOMUX_PAD(0x41C, 0x13C, 0, 0x70c, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D4__GPIO_2_4 IOMUX_PAD(0x41C, 0x13C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D4__FEC_RXD0 IOMUX_PAD(0x41C, 0x13C, 2, 0x778, 0, PAD_CTL_HYS | PAD_CTL_PKE)
-#define MX50_PAD_DISP_D4__WEIM_A20 IOMUX_PAD(0x41C, 0x13C, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D5__DISP_D5 IOMUX_PAD(0x420, 0x140, 0, 0x710, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D5__GPIO_2_5 IOMUX_PAD(0x420, 0x140, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D5__FEC_TX_EN IOMUX_PAD(0x420, 0x140, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_DISP_D5__WEIM_A21 IOMUX_PAD(0x420, 0x140, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D6__DISP_D6 IOMUX_PAD(0x424, 0x144, 0, 0x714, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D6__GPIO_2_6 IOMUX_PAD(0x424, 0x144, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D6__FEC_TXD1 IOMUX_PAD(0x424, 0x144, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_DISP_D6__WEIM_A22 IOMUX_PAD(0x424, 0x144, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D6__FEC_RX_CLK IOMUX_PAD(0x424, 0x144, 4, 0x780, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D7__DISP_D7 IOMUX_PAD(0x428, 0x148, 0, 0x718, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D7__GPIO_2_7 IOMUX_PAD(0x428, 0x148, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D7__FEC_TXD0 IOMUX_PAD(0x428, 0x148, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_DISP_D7__WEIM_A23 IOMUX_PAD(0x428, 0x148, 3, 0x0, 0, NO_PAD_CTRL)
-
-
-#define MX50_PAD_DISP_WR__ELCDIF_WR IOMUX_PAD(0x42C, 0x14C, 0, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_WR__GPIO_2_16 IOMUX_PAD(0x42C, 0x14C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_WR__ELCDIF_PIXCLK IOMUX_PAD(0x42C, 0x14C, 2, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_WR__WEIM_A24 IOMUX_PAD(0x42C, 0x14C, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_RD__ELCDIF_RD IOMUX_PAD(0x430, 0x150, 0, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_RD__GPIO_2_19 IOMUX_PAD(0x430, 0x150, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_RD__ELCDIF_EN IOMUX_PAD(0x430, 0x150, 2, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_RD__WEIM_A25 IOMUX_PAD(0x430, 0x150, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_RS__ELCDIF_RS IOMUX_PAD(0x434, 0x154, 0, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_RS__GPIO_2_17 IOMUX_PAD(0x434, 0x154, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_RS__ELCDIF_VSYNC IOMUX_PAD(0x434, 0x154, 2, 0x73c, 1, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_RS__WEIM_A26 IOMUX_PAD(0x434, 0x154, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_CS__ELCDIF_CS IOMUX_PAD(0x438, 0x158, 0, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_CS__GPIO_2_21 IOMUX_PAD(0x438, 0x158, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_CS__ELCDIF_HSYNC IOMUX_PAD(0x438, 0x158, 2, 0x6f8, 1, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_CS__WEIM_A27 IOMUX_PAD(0x438, 0x158, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_CS__WEIM_CS3 IOMUX_PAD(0x438, 0x158, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_BUSY__ELCDIF_HSYNC IOMUX_PAD(0x43C, 0x15C, 0, 0x6f8, 2, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_BUSY__GPIO_2_18 IOMUX_PAD(0x43C, 0x15C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_BUSY__WEIM_CS3 IOMUX_PAD(0x43C, 0x15C, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_RESET__ELCDIF_RST IOMUX_PAD(0x440, 0x160, 0, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_RESET__GPIO_2_20 IOMUX_PAD(0x440, 0x160, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_RESET__WEIM_CS3 IOMUX_PAD(0x440, 0x160, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_CMD__SD3_CMD IOMUX_PAD(0x444, 0x164, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_CMD__GPIO_5_18 IOMUX_PAD(0x444, 0x164, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_CMD__NANDF_WRN IOMUX_PAD(0x444, 0x164, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_CMD__SSP_CMD IOMUX_PAD(0x444, 0x164, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_CLK__SD3_CLK IOMUX_PAD(0x448, 0x168, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_CLK__GPIO_5_19 IOMUX_PAD(0x448, 0x168, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_CLK__NANDF_RDN IOMUX_PAD(0x448, 0x168, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_CLK__SSP_CLK IOMUX_PAD(0x448, 0x168, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_D0__SD3_D0 IOMUX_PAD(0x44C, 0x16C, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_D0__GPIO_5_20 IOMUX_PAD(0x44C, 0x16C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_D0__NANDF_D4 IOMUX_PAD(0x44C, 0x16C, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_D0__SSP_D0 IOMUX_PAD(0x44C, 0x16C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD3_D0__PLL1_BYP IOMUX_PAD(0x44C, 0x16C, 7, 0x6dc, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_D1__SD3_D1 IOMUX_PAD(0x450, 0x170, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_D1__GPIO_5_21 IOMUX_PAD(0x450, 0x170, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_D1__NANDF_D5 IOMUX_PAD(0x450, 0x170, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_D1__PLL2_BYP IOMUX_PAD(0x450, 0x170, 7, 0x6e0, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_D2__SD3_D2 IOMUX_PAD(0x454, 0x174, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_D2__GPIO_5_22 IOMUX_PAD(0x454, 0x174, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_D2__NANDF_D6 IOMUX_PAD(0x454, 0x174, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_D2__SSP_D2 IOMUX_PAD(0x454, 0x174, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD3_D2__PLL3_BYP IOMUX_PAD(0x454, 0x174, 7, 0x6e4, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_D3__SD3_D3 IOMUX_PAD(0x458, 0x178, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_D3__GPIO_5_23 IOMUX_PAD(0x458, 0x178, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_D3__NANDF_D7 IOMUX_PAD(0x458, 0x178, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_D3__SSP_D3 IOMUX_PAD(0x458, 0x178, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_D4__SD3_D4 IOMUX_PAD(0x45C, 0x17C, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_D4__GPIO_5_24 IOMUX_PAD(0x45C, 0x17C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_D4__NANDF_D0 IOMUX_PAD(0x45C, 0x17C, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_D4__SSP_D4 IOMUX_PAD(0x45C, 0x17C, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_D5__SD3_D5 IOMUX_PAD(0x460, 0x180, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_D5__GPIO_5_25 IOMUX_PAD(0x460, 0x180, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_D5__NANDF_D1 IOMUX_PAD(0x460, 0x180, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_D5__SSP_D5 IOMUX_PAD(0x460, 0x180, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_D6__SD3_D6 IOMUX_PAD(0x464, 0x184, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_D6__GPIO_5_26 IOMUX_PAD(0x464, 0x184, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_D6__NANDF_D2 IOMUX_PAD(0x464, 0x184, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_D6__SSP_D6 IOMUX_PAD(0x464, 0x184, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_D7__SD3_D7 IOMUX_PAD(0x468, 0x188, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_D7__GPIO_5_27 IOMUX_PAD(0x468, 0x188, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_D7__NANDF_D3 IOMUX_PAD(0x468, 0x188, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_D7__SSP_D7 IOMUX_PAD(0x468, 0x188, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_SD3_WP__SD3_WP IOMUX_PAD(0x46C, 0x18C, 0, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_WP__GPIO_5_28 IOMUX_PAD(0x46C, 0x18C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_SD3_WP__NANDF_RESETN IOMUX_PAD(0x46C, 0x18C, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_SD3_WP__SSP_CD IOMUX_PAD(0x46C, 0x18C, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SD3_WP__SD4_LCTL IOMUX_PAD(0x46C, 0x18C, 4, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_SD3_WP__WEIM_CS3 IOMUX_PAD(0x46C, 0x18C, 5, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D8__DISP_D8 IOMUX_PAD(0x470, 0x190, 0, 0x71c, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D8__GPIO_2_8 IOMUX_PAD(0x470, 0x190, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D8__NANDF_CLE IOMUX_PAD(0x470, 0x190, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D8__SD1_LCTL IOMUX_PAD(0x470, 0x190, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D8__SD4_CMD IOMUX_PAD(0x470, 0x190, 4, 0x74c, 2, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D8__KEY_COL4 IOMUX_PAD(0x470, 0x190, 5, 0x790, 1, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D8__FEC_TX_CLK IOMUX_PAD(0x470, 0x190, 6, 0x78c, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D9__DISP_D9 IOMUX_PAD(0x474, 0x194, 0, 0x720, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D9__GPIO_2_9 IOMUX_PAD(0x474, 0x194, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D9__NANDF_ALE IOMUX_PAD(0x474, 0x194, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D9__SD2_LCTL IOMUX_PAD(0x474, 0x194, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D9__SD4_CLK IOMUX_PAD(0x474, 0x194, 4, 0x748, 2, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D9__KEY_ROW4 IOMUX_PAD(0x474, 0x194, 5, 0x7a0, 1, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D9__FEC_RX_ER IOMUX_PAD(0x474, 0x194, 6, 0x788, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D10__DISP_D10 IOMUX_PAD(0x478, 0x198, 0, 0x724, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D10__GPIO_2_10 IOMUX_PAD(0x478, 0x198, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D10__NANDF_CEN0 IOMUX_PAD(0x478, 0x198, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D10__SD3_LCTL IOMUX_PAD(0x478, 0x198, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D10__SD4_D0 IOMUX_PAD(0x478, 0x198, 4, 0x750, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D10__KEY_COL5 IOMUX_PAD(0x478, 0x198, 5, 0x794, 1, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D10__FEC_RX_DV IOMUX_PAD(0x478, 0x198, 6, 0x784, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D11__DISP_D11 IOMUX_PAD(0x47C, 0x19C, 0, 0x728, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D11__GPIO_2_11 IOMUX_PAD(0x47C, 0x19C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D11__NANDF_CEN1 IOMUX_PAD(0x47C, 0x19C, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D11__SD4_D1 IOMUX_PAD(0x47C, 0x19C, 4, 0x754, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D11__KEY_ROW5 IOMUX_PAD(0x47C, 0x19C, 5, 0x7a4, 1, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D11__FEC_RDAT1 IOMUX_PAD(0x47C, 0x19C, 6, 0x77c, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D12__DISP_D12 IOMUX_PAD(0x480, 0x1A0, 0, 0x72c, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D12__GPIO_2_12 IOMUX_PAD(0x480, 0x1A0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D12__NANDF_CEN2 IOMUX_PAD(0x480, 0x1A0, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D12__SD1_CD IOMUX_PAD(0x480, 0x1A0, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D12__SD4_D2 IOMUX_PAD(0x480, 0x1A0, 4, 0x758, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D12__KEY_COL6 IOMUX_PAD(0x480, 0x1A0, 5, 0x798, 1, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D12__FEC_RDAT0 IOMUX_PAD(0x480, 0x1A0, 6, 0x778, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D13__DISP_D13 IOMUX_PAD(0x484, 0x1A4, 0, 0x730, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D13__GPIO_2_13 IOMUX_PAD(0x484, 0x1A4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D13__NANDF_CEN3 IOMUX_PAD(0x484, 0x1A4, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D13__SD3_CD IOMUX_PAD(0x484, 0x1A4, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D13__SD4_D3 IOMUX_PAD(0x484, 0x1A4, 4, 0x75c, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D13__KEY_ROW6 IOMUX_PAD(0x484, 0x1A4, 5, 0x7a8, 1, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D13__FEC_TX_EN IOMUX_PAD(0x484, 0x1A4, 6, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D14__DISP_D14 IOMUX_PAD(0x488, 0x1A8, 0, 0x734, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D14__GPIO_2_14 IOMUX_PAD(0x488, 0x1A8, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D14__NANDF_RDY0 IOMUX_PAD(0x488, 0x1A8, 2, 0x7b4, 1, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D14__SD1_WP IOMUX_PAD(0x488, 0x1A8, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D14__SD4_WP IOMUX_PAD(0x488, 0x1A8, 4, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D14__KEY_COL7 IOMUX_PAD(0x488, 0x1A8, 5, 0x79c, 1, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D14__FEC_TDAT1 IOMUX_PAD(0x488, 0x1A8, 6, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_DISP_D15__DISP_D15 IOMUX_PAD(0x48C, 0x1AC, 0, 0x738, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_DISP_D15__GPIO_2_15 IOMUX_PAD(0x48C, 0x1AC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D15__NANDF_DQS IOMUX_PAD(0x48C, 0x1AC, 2, 0x7b0, 1, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D15__SD3_RST IOMUX_PAD(0x48C, 0x1AC, 3, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D15__SD4_CD IOMUX_PAD(0x48C, 0x1AC, 4, 0x0, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_DISP_D15__KEY_ROW7 IOMUX_PAD(0x48C, 0x1AC, 5, 0x7ac, 1, NO_PAD_CTRL)
-#define MX50_PAD_DISP_D15__FEC_TDAT0 IOMUX_PAD(0x48C, 0x1AC, 6, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D0__EPDC_D0 IOMUX_PAD(0x54C, 0x1B0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D0__GPIO_3_0 IOMUX_PAD(0x54C, 0x1B0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D0__WEIM_D0 IOMUX_PAD(0x54C, 0x1B0, 2, 0x7ec, 1, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D0__ELCDIF_RS IOMUX_PAD(0x54C, 0x1B0, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_D0__ELCDIF_PIXCLK IOMUX_PAD(0x54C, 0x1B0, 4, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D1__EPDC_D1 IOMUX_PAD(0x550, 0x1B4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D1__GPIO_3_1 IOMUX_PAD(0x550, 0x1B4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D1__WEIM_D1 IOMUX_PAD(0x550, 0x1B4, 2, 0x7f0, 1, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D1__ELCDIF_CS IOMUX_PAD(0x550, 0x1B4, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_D1__ELCDIF_EN IOMUX_PAD(0x550, 0x1B4, 4, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D2__EPDC_D2 IOMUX_PAD(0x554, 0x1B8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D2__GPIO_3_2 IOMUX_PAD(0x554, 0x1B8, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D2__WEIM_D2 IOMUX_PAD(0x554, 0x1B8, 2, 0x7f4, 1, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D2__ELCDIF_WR IOMUX_PAD(0x554, 0x1B8, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_D2__ELCDIF_VSYNC IOMUX_PAD(0x554, 0x1B8, 4, 0x73c, 2, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D3__EPDC_D3 IOMUX_PAD(0x558, 0x1BC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D3__GPIO_3_3 IOMUX_PAD(0x558, 0x1BC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D3__WEIM_D3 IOMUX_PAD(0x558, 0x1BC, 2, 0x7f8, 1, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D3__ELCDIF_RD IOMUX_PAD(0x558, 0x1BC, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_D3__ELCDIF_HSYNC IOMUX_PAD(0x558, 0x1BC, 4, 0x6f8, 3, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D4__EPDC_D4 IOMUX_PAD(0x55C, 0x1C0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D4__GPIO_3_4 IOMUX_PAD(0x55C, 0x1C0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D4__WEIM_D4 IOMUX_PAD(0x55C, 0x1C0, 2, 0x7fc, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D5__EPDC_D5 IOMUX_PAD(0x560, 0x1C4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D5__GPIO_3_5 IOMUX_PAD(0x560, 0x1C4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D5__WEIM_D5 IOMUX_PAD(0x560, 0x1C4, 2, 0x800, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D6__EPDC_D6 IOMUX_PAD(0x564, 0x1C8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D6__GPIO_3_6 IOMUX_PAD(0x564, 0x1C8, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D6__WEIM_D6 IOMUX_PAD(0x564, 0x1C8, 2, 0x804, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D7__EPDC_D7 IOMUX_PAD(0x568, 0x1CC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D7__GPIO_3_7 IOMUX_PAD(0x568, 0x1CC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D7__WEIM_D7 IOMUX_PAD(0x568, 0x1CC, 2, 0x808, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D8__EPDC_D8 IOMUX_PAD(0x56C, 0x1D0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D8__GPIO_3_8 IOMUX_PAD(0x56C, 0x1D0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D8__WEIM_D8 IOMUX_PAD(0x56C, 0x1D0, 2, 0x80c, 2, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D8__ELCDIF_D24 IOMUX_PAD(0x56C, 0x1D0, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D9__EPDC_D9 IOMUX_PAD(0x570, 0x1D4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D9__GPIO_3_9 IOMUX_PAD(0x570, 0x1D4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D9__WEIM_D9 IOMUX_PAD(0x570, 0x1D4, 2, 0x810, 2, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D9__ELCDIF_D25 IOMUX_PAD(0x570, 0x1D4, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D10__EPDC_D10 IOMUX_PAD(0x574, 0x1D8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D10__GPIO_3_10 IOMUX_PAD(0x574, 0x1D8, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D10__WEIM_D10 IOMUX_PAD(0x574, 0x1D8, 2, 0x814, 2, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D10__ELCDIF_D26 IOMUX_PAD(0x574, 0x1D8, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D11__EPDC_D11 IOMUX_PAD(0x578, 0x1DC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D11__GPIO_3_11 IOMUX_PAD(0x578, 0x1DC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D11__WEIM_D11 IOMUX_PAD(0x578, 0x1DC, 2, 0x818, 2, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D11__ELCDIF_D27 IOMUX_PAD(0x578, 0x1DC, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D12__EPDC_D12 IOMUX_PAD(0x57C, 0x1E0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D12__GPIO_3_12 IOMUX_PAD(0x57C, 0x1E0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D12__WEIM_D12 IOMUX_PAD(0x57C, 0x1E0, 2, 0x81c, 1, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D12__ELCDIF_D28 IOMUX_PAD(0x57C, 0x1E0, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D13__EPDC_D13 IOMUX_PAD(0x580, 0x1E4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D13__GPIO_3_13 IOMUX_PAD(0x580, 0x1E4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D13__WEIM_D13 IOMUX_PAD(0x580, 0x1E4, 2, 0x820, 1, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D13__ELCDIF_D29 IOMUX_PAD(0x580, 0x1E4, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D14__EPDC_D14 IOMUX_PAD(0x584, 0x1E8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D14__GPIO_3_14 IOMUX_PAD(0x584, 0x1E8, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D14__WEIM_D14 IOMUX_PAD(0x584, 0x1E8, 2, 0x824, 1, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D14__ELCDIF_D30 IOMUX_PAD(0x584, 0x1E8, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_D14__AUD6_TXD IOMUX_PAD(0x584, 0x1E8, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_D15__EPDC_D15 IOMUX_PAD(0x588, 0x1EC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D15__GPIO_3_15 IOMUX_PAD(0x588, 0x1EC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D15__WEIM_D15 IOMUX_PAD(0x588, 0x1EC, 2, 0x828, 1, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D15__ELCDIF_D31 IOMUX_PAD(0x588, 0x1EC, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_D15__AUD6_TXC IOMUX_PAD(0x588, 0x1EC, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_GDCLK__EPDC_GDCLK IOMUX_PAD(0x58C, 0x1F0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDCLK__GPIO_3_16 IOMUX_PAD(0x58C, 0x1F0, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDCLK__WEIM_D16 IOMUX_PAD(0x58C, 0x1F0, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDCLK__ELCDIF_D16 IOMUX_PAD(0x58C, 0x1F0, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_GDCLK__AUD6_TXFS IOMUX_PAD(0x58C, 0x1F0, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_GDSP__EPDC_GDSP IOMUX_PAD(0x590, 0x1F4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDSP__GPIO_3_17 IOMUX_PAD(0x590, 0x1F4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDSP__WEIM_D17 IOMUX_PAD(0x590, 0x1F4, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDSP__ELCDIF_D17 IOMUX_PAD(0x590, 0x1F4, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_GDSP__AUD6_RXD IOMUX_PAD(0x590, 0x1F4, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_GDOE__EPDC_GDOE IOMUX_PAD(0x594, 0x1F8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDOE__GPIO_3_18 IOMUX_PAD(0x594, 0x1F8, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDOE__WEIM_D18 IOMUX_PAD(0x594, 0x1F8, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDOE__ELCDIF_D18 IOMUX_PAD(0x594, 0x1F8, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_GDOE__AUD6_RXC IOMUX_PAD(0x594, 0x1F8, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_GDRL__EPDC_GDRL IOMUX_PAD(0x598, 0x1FC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDRL__GPIO_3_19 IOMUX_PAD(0x598, 0x1FC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDRL__WEIM_D19 IOMUX_PAD(0x598, 0x1FC, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_GDRL__ELCDIF_D19 IOMUX_PAD(0x598, 0x1FC, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_GDRL__AUD6_RXFS IOMUX_PAD(0x598, 0x1FC, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDCLK__EPDC_SDCLK IOMUX_PAD(0x59C, 0x200, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCLK__GPIO_3_20 IOMUX_PAD(0x59C, 0x200, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCLK__WEIM_D20 IOMUX_PAD(0x59C, 0x200, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCLK__ELCDIF_D20 IOMUX_PAD(0x59C, 0x200, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCLK__AUD5_TXD IOMUX_PAD(0x59C, 0x200, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDOEZ__EPDC_SDOEZ IOMUX_PAD(0x5A0, 0x204, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOEZ__GPIO_3_21 IOMUX_PAD(0x5A0, 0x204, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOEZ__WEIM_D21 IOMUX_PAD(0x5A0, 0x204, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOEZ__ELCDIF_D21 IOMUX_PAD(0x5A0, 0x204, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOEZ__AUD5_TXC IOMUX_PAD(0x5A0, 0x204, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDOED__EPDC_SDOED IOMUX_PAD(0x5A4, 0x208, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOED__GPIO_3_22 IOMUX_PAD(0x5A4, 0x208, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOED__WEIM_D22 IOMUX_PAD(0x5A4, 0x208, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOED__ELCDIF_D22 IOMUX_PAD(0x5A4, 0x208, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOED__AUD5_TXFS IOMUX_PAD(0x5A4, 0x208, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDOE__EPDC_SDOE IOMUX_PAD(0x5A8, 0x20C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOE__GPIO_3_23 IOMUX_PAD(0x5A8, 0x20C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOE__WEIM_D23 IOMUX_PAD(0x5A8, 0x20C, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOE__ELCDIF_D23 IOMUX_PAD(0x5A8, 0x20C, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_SDOE__AUD5_RXD IOMUX_PAD(0x5A8, 0x20C, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDLE__EPDC_SDLE IOMUX_PAD(0x5AC, 0x210, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDLE__GPIO_3_24 IOMUX_PAD(0x5AC, 0x210, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDLE__WEIM_D24 IOMUX_PAD(0x5AC, 0x210, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDLE__ELCDIF_D8 IOMUX_PAD(0x5AC, 0x210, 3, 0x71c, 1, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_SDLE__AUD5_RXC IOMUX_PAD(0x5AC, 0x210, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDCLKN__EPDC_SDCLKN IOMUX_PAD(0x5B0, 0x214, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCLKN__GPIO_3_25 IOMUX_PAD(0x5B0, 0x214, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCLKN__WEIM_D25 IOMUX_PAD(0x5B0, 0x214, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCLKN__ELCDIF_D9 IOMUX_PAD(0x5B0, 0x214, 3, 0x720, 1, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCLKN__AUD5_RXFS IOMUX_PAD(0x5B0, 0x214, 4, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDSHR__EPDC_SDSHR IOMUX_PAD(0x5B4, 0x218, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDSHR__GPIO_3_26 IOMUX_PAD(0x5B4, 0x218, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDSHR__WEIM_D26 IOMUX_PAD(0x5B4, 0x218, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDSHR__ELCDIF_D10 IOMUX_PAD(0x5B4, 0x218, 3, 0x724, 1, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_SDSHR__AUD4_TXD IOMUX_PAD(0x5B4, 0x218, 4, 0x6c8, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_PWRCOM__EPDC_PWRCOM IOMUX_PAD(0x5B8, 0x21C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCOM__GPIO_3_27 IOMUX_PAD(0x5B8, 0x21C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCOM__WEIM_D27 IOMUX_PAD(0x5B8, 0x21C, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCOM__ELCDIF_D11 IOMUX_PAD(0x5B8, 0x21C, 3, 0x728, 1, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCOM__AUD4_TXC IOMUX_PAD(0x5B8, 0x21C, 4, 0x6d4, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_PWRSTAT__EPDC_PWRSTAT IOMUX_PAD(0x5BC, 0x220, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRSTAT__GPIO_3_28 IOMUX_PAD(0x5BC, 0x220, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRSTAT__WEIM_D28 IOMUX_PAD(0x5BC, 0x220, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRSTAT__ELCDIF_D12 IOMUX_PAD(0x5BC, 0x220, 3, 0x72c, 1, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRSTAT__AUD4_TXFS IOMUX_PAD(0x5BC, 0x220, 4, 0x6d8, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_PWRCTRL0__EPDC_PWRCTRL0 IOMUX_PAD(0x5C0, 0x224, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL0__GPIO_3_29 IOMUX_PAD(0x5C0, 0x224, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL0__WEIM_D29 IOMUX_PAD(0x5C0, 0x224, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL0__ELCDIF_D13 IOMUX_PAD(0x5C0, 0x224, 3, 0x730, 1, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL0__AUD4_RXD IOMUX_PAD(0x5C0, 0x224, 4, 0x6c4, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_PWRCTRL1__EPDC_PWRCTRL1 IOMUX_PAD(0x5C4, 0x228, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL1__GPIO_3_30 IOMUX_PAD(0x5C4, 0x228, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL1__WEIM_D30 IOMUX_PAD(0x5C4, 0x228, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL1__ELCDIF_D14 IOMUX_PAD(0x5C4, 0x228, 3, 0x734, 1, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL1__AUD4_RXC IOMUX_PAD(0x5C4, 0x228, 4, 0x6cc, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_PWRCTRL2__EPDC_PWRCTRL2 IOMUX_PAD(0x5C8, 0x22C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL2__GPIO_3_31 IOMUX_PAD(0x5C8, 0x22C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL2__WEIM_D31 IOMUX_PAD(0x5C8, 0x22C, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL2__ELCDIF_D15 IOMUX_PAD(0x5C8, 0x22C, 3, 0x738, 1, MX50_ELCDIF_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL2__AUD4_RXFS IOMUX_PAD(0x5C8, 0x22C, 4, 0x6d0, 1, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL2__SDMA_EXT0 IOMUX_PAD(0x5C8, 0x22C, 6, 0x7b8, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_PWRCTRL3__PWRCTRL3 IOMUX_PAD(0x5CC, 0x230, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL3__GPIO_4_20 IOMUX_PAD(0x5CC, 0x230, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL3__WEIM_EB2 IOMUX_PAD(0x5CC, 0x230, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_PWRCTRL3__SDMA_EXT1 IOMUX_PAD(0x5CC, 0x230, 6, 0x7bc, 1, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_VCOM0__EPDC_VCOM0 IOMUX_PAD(0x5D0, 0x234, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_VCOM0__GPIO_4_21 IOMUX_PAD(0x5D0, 0x234, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_VCOM0__WEIM_EB3 IOMUX_PAD(0x5D0, 0x234, 2, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_VCOM1__EPDC_VCOM1 IOMUX_PAD(0x5D4, 0x238, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_VCOM1__GPIO_4_22 IOMUX_PAD(0x5D4, 0x238, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_VCOM1__WEIM_CS3 IOMUX_PAD(0x5D4, 0x238, 2, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EPDC_BDR0__EPDC_BDR0 IOMUX_PAD(0x5D8, 0x23C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_BDR0__GPIO_4_23 IOMUX_PAD(0x5D8, 0x23C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_BDR0__ELCDIF_D7 IOMUX_PAD(0x5D8, 0x23C, 3, 0x718, 1, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_BDR1__EPDC_BDR1 IOMUX_PAD(0x5DC, 0x240, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_BDR1__GPIO_4_24 IOMUX_PAD(0x5DC, 0x240, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_BDR1__ELCDIF_D6 IOMUX_PAD(0x5DC, 0x240, 3, 0x714, 1, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDCE0__EPDC_SDCE0 IOMUX_PAD(0x5E0, 0x244, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE0__GPIO_4_25 IOMUX_PAD(0x5E0, 0x244, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE0__ELCDIF_D5 IOMUX_PAD(0x5E0, 0x244, 3, 0x710, 1, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDCE1__EPDC_SDCE1 IOMUX_PAD(0x5E4, 0x248, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE1__GPIO_4_26 IOMUX_PAD(0x5E4, 0x248, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE1__ELCDIF_D4 IOMUX_PAD(0x5E4, 0x248, 2, 0x70c, 1, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDCE2__EPDC_SDCE2 IOMUX_PAD(0x5E8, 0x24C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE2__GPIO_4_27 IOMUX_PAD(0x5E8, 0x24C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE2__ELCDIF_DAT3 IOMUX_PAD(0x5E8, 0x24C, 3, 0x708, 1, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDCE3__EPDC_SDCE3 IOMUX_PAD(0x5EC, 0x250, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE3__GPIO_4_28 IOMUX_PAD(0x5EC, 0x250, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE3__ELCDIF_D2 IOMUX_PAD(0x5EC, 0x250, 3, 0x704, 1, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDCE4__EPDC_SDCE4 IOMUX_PAD(0x5F0, 0x254, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE4__GPIO_4_29 IOMUX_PAD(0x5F0, 0x254, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE4__ELCDIF_D1 IOMUX_PAD(0x5F0, 0x254, 3, 0x700, 1, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EPDC_SDCE5__EPDC_SDCE5 IOMUX_PAD(0x5F4, 0x258, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE5__GPIO_4_30 IOMUX_PAD(0x5F4, 0x258, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_SDCE5__ELCDIF_D0 IOMUX_PAD(0x5F4, 0x258, 3, 0x6fc, 1, MX50_ELCDIF_PAD_CTRL)
-
-#define MX50_PAD_EIM_DA0__WEIM_A0 IOMUX_PAD(0x5F8, 0x25C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA0__GPIO_1_0 IOMUX_PAD(0x5F8, 0x25C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA0__KEY_COL4 IOMUX_PAD(0x5f8, 0x25C, 3, 0x790, 2, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_DA1__WEIM_A1 IOMUX_PAD(0x5FC, 0x260, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA1__GPIO_1_1 IOMUX_PAD(0x5FC, 0x260, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA1__KEY_ROW4 IOMUX_PAD(0x5fc, 0x260, 3, 0x7a0, 2, MX50_KEYPAD_CTRL)
-
-#define MX50_PAD_EIM_DA2__WEIM_A2 IOMUX_PAD(0x600, 0x264, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA2__GPIO_1_2 IOMUX_PAD(0x600, 0x264, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA2__KEY_COL5 IOMUX_PAD(0x600, 0x264, 3, 0x794, 2, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_DA3__WEIM_A3 IOMUX_PAD(0x604, 0x268, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA3__GPIO_1_3 IOMUX_PAD(0x604, 0x268, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA3__KEY_ROW5 IOMUX_PAD(0x604, 0x268, 3, 0x7a4, 2, MX50_KEYPAD_CTRL)
-
-#define MX50_PAD_EIM_DA4__WEIM_A4 IOMUX_PAD(0x608, 0x26C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA4__GPIO_1_4 IOMUX_PAD(0x608, 0x26C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA4__KEY_COL6 IOMUX_PAD(0x608, 0x26C, 3, 0x798, 2, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_DA5__WEIM_A5 IOMUX_PAD(0x60C, 0x270, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA5__GPIO_1_5 IOMUX_PAD(0x60C, 0x270, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA5__KEY_ROW6 IOMUX_PAD(0x60C, 0x270, 3, 0x7a8, 2, MX50_KEYPAD_CTRL)
-
-#define MX50_PAD_EIM_DA6__WEIM_A6 IOMUX_PAD(0x610, 0x274, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA6__GPIO_1_6 IOMUX_PAD(0x610, 0x274, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA6__KEY_COL7 IOMUX_PAD(0x610, 0x274, 3, 0x79c, 2, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_DA7__WEIM_A7 IOMUX_PAD(0x614, 0x278, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA7__GPIO_1_7 IOMUX_PAD(0x614, 0x278, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA7__KEY_ROW7 IOMUX_PAD(0x614, 0x278, 3, 0x7ac, 2, MX50_KEYPAD_CTRL)
-
-#define MX50_PAD_EIM_DA8__WEIM_A8 IOMUX_PAD(0x618, 0x27C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA8__GPIO_1_8 IOMUX_PAD(0x618, 0x27C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_EIM_DA8__NANDF_CLE IOMUX_PAD(0x618, 0x27C, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_EIM_DA9__WEIM_A9 IOMUX_PAD(0x61C, 0x280, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA9__GPIO_1_9 IOMUX_PAD(0x61C, 0x280, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_EIM_DA9__NANDF_ALE IOMUX_PAD(0x61C, 0x280, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_EIM_DA10__WEIM_A10 IOMUX_PAD(0x620, 0x284, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA10__GPIO_1_10 IOMUX_PAD(0x620, 0x284, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_EIM_DA10__NANDF_CE0 IOMUX_PAD(0x620, 0x284, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_EIM_DA11__WEIM_A11 IOMUX_PAD(0x624, 0x288, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA11__GPIO_1_11 IOMUX_PAD(0x624, 0x288, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_EIM_DA11__NANDF_CE1 IOMUX_PAD(0x624, 0x288, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-
-#define MX50_PAD_EIM_DA12__WEIM_A12 IOMUX_PAD(0x628, 0x28C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA12__GPIO_1_12 IOMUX_PAD(0x628, 0x28C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_EIM_DA12__NANDF_CE2 IOMUX_PAD(0x628, 0x28C, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_EIM_DA12__EPDC_SDCE6 IOMUX_PAD(0x628, 0x28C, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_DA13__WEIM_A13 IOMUX_PAD(0x62C, 0x290, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA13__GPIO_1_13 IOMUX_PAD(0x62C, 0x290, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_EIM_DA13__NANDF_CE3 IOMUX_PAD(0x62C, 0x290, 2, 0x0, 0, PAD_CTL_DSE_HIGH)
-#define MX50_PIN_EIM_DA13__EPDC_SDCE7 IOMUX_PAD(0x62C, 0x290, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_DA14__WEIM_A14 IOMUX_PAD(0x630, 0x294, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA14__GPIO_1_14 IOMUX_PAD(0x630, 0x294, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA14__NANDF_READY IOMUX_PAD(0x630, 0x294, 2, 0x7B4, 2, PAD_CTL_PKE | \
- PAD_CTL_PUE | PAD_CTL_PUS_100K_UP)
-#define MX50_PAD_EIM_DA14__EPDC_SDCE8 IOMUX_PAD(0x630, 0x294, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_DA15__WEIM_A15 IOMUX_PAD(0x634, 0x298, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_DA15__GPIO_1_15 IOMUX_PAD(0x634, 0x298, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PIN_EIM_DA15__NANDF_DQS IOMUX_PAD(0x634, 0x298, 2, 0x7B0, 2, PAD_CTL_DSE_HIGH)
-#define MX50_PAD_EIM_DA15__EPDC_SDCE9 IOMUX_PAD(0x634, 0x298, 3, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_CS2__WEIM_CS2 IOMUX_PAD(0x638, 0x29C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_CS2__GPIO_1_16 IOMUX_PAD(0x638, 0x29C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_CS2__WEIM_A27 IOMUX_PAD(0x638, 0x29C, 2, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_CS1__WEIM_CS1 IOMUX_PAD(0x63C, 0x2A0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_CS1__GPIO_1_17 IOMUX_PAD(0x63C, 0x2A0, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_CS0__WEIM_CS0 IOMUX_PAD(0x640, 0x2A4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_CS0__GPIO_1_18 IOMUX_PAD(0x640, 0x2A4, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_EB0__WEIM_EB0 IOMUX_PAD(0x644, 0x2A8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_EB0__GPIO_1_19 IOMUX_PAD(0x644, 0x2A8, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_EB1__WEIM_EB1 IOMUX_PAD(0x648, 0x2AC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_EB1__GPIO_1_20 IOMUX_PAD(0x648, 0x2AC, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_WAIT__WEIM_WAIT IOMUX_PAD(0x64C, 0x2B0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_WAIT__GPIO_1_21 IOMUX_PAD(0x64C, 0x2B0, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_BCLK__WEIM_BCLK IOMUX_PAD(0x650, 0x2B4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_BCLK__GPIO_1_22 IOMUX_PAD(0x650, 0x2B4, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_RDY__WEIM_RDY IOMUX_PAD(0x654, 0x2B8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_RDY__GPIO_1_23 IOMUX_PAD(0x654, 0x2B8, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_OE__WEIM_OE IOMUX_PAD(0x658, 0x2BC, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_OE__GPIO_1_24 IOMUX_PAD(0x658, 0x2BC, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_RW__WEIM_RW IOMUX_PAD(0x65C, 0x2C0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_RW__GPIO_1_25 IOMUX_PAD(0x65C, 0x2C0, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_LBA__WEIM_LBA IOMUX_PAD(0x660, 0x2C4, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_LBA__GPIO_1_26 IOMUX_PAD(0x660, 0x2C4, 1, 0x0, 0, NO_PAD_CTRL)
-
-#define MX50_PAD_EIM_CRE__WEIM_CRE IOMUX_PAD(0x664, 0x2C8, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EIM_CRE__GPIO_1_27 IOMUX_PAD(0x664, 0x2C8, 1, 0x0, 0, NO_PAD_CTRL)
-
-#endif /* __MACH_IOMUX_MX50_H__ */
diff --git a/arch/arm/mach-imx/lluart.c b/arch/arm/mach-imx/lluart.c
deleted file mode 100644
index 2fdc9bf2fb5e..000000000000
--- a/arch/arm/mach-imx/lluart.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2011 Freescale Semiconductor, Inc.
- * Copyright 2011 Linaro Ltd.
- *
- * 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 <asm/page.h>
-#include <asm/sizes.h>
-#include <asm/mach/map.h>
-
-#include "hardware.h"
-
-#define IMX6Q_UART1_BASE_ADDR 0x02020000
-#define IMX6Q_UART2_BASE_ADDR 0x021e8000
-#define IMX6Q_UART3_BASE_ADDR 0x021ec000
-#define IMX6Q_UART4_BASE_ADDR 0x021f0000
-#define IMX6Q_UART5_BASE_ADDR 0x021f4000
-
-/*
- * IMX6Q_UART_BASE_ADDR is put in the middle to force the expansion
- * of IMX6Q_UART##n##_BASE_ADDR.
- */
-#define IMX6Q_UART_BASE_ADDR(n) IMX6Q_UART##n##_BASE_ADDR
-#define IMX6Q_UART_BASE(n) IMX6Q_UART_BASE_ADDR(n)
-#define IMX6Q_DEBUG_UART_BASE IMX6Q_UART_BASE(CONFIG_DEBUG_IMX6Q_UART_PORT)
-
-static struct map_desc imx_lluart_desc = {
-#ifdef CONFIG_DEBUG_IMX6Q_UART
- .virtual = IMX_IO_P2V(IMX6Q_DEBUG_UART_BASE),
- .pfn = __phys_to_pfn(IMX6Q_DEBUG_UART_BASE),
- .length = 0x4000,
- .type = MT_DEVICE,
-#endif
-};
-
-void __init imx_lluart_map_io(void)
-{
- if (imx_lluart_desc.virtual)
- iotable_init(&imx_lluart_desc, 1);
-}
diff --git a/arch/arm/mach-imx/mach-apf9328.c b/arch/arm/mach-imx/mach-apf9328.c
index 5c9bd2c66e6d..067580b2969b 100644
--- a/arch/arm/mach-imx/mach-apf9328.c
+++ b/arch/arm/mach-imx/mach-apf9328.c
@@ -137,17 +137,13 @@ 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,
.handle_irq = imx1_handle_irq,
- .timer = &apf9328_timer,
+ .init_time = apf9328_timer_init,
.init_machine = apf9328_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-armadillo5x0.c b/arch/arm/mach-imx/mach-armadillo5x0.c
index 59bd6b06a6b5..368a6e3f5926 100644
--- a/arch/arm/mach-imx/mach-armadillo5x0.c
+++ b/arch/arm/mach-imx/mach-armadillo5x0.c
@@ -557,10 +557,6 @@ static void __init armadillo5x0_timer_init(void)
mx31_clocks_init(26000000);
}
-static struct sys_timer armadillo5x0_timer = {
- .init = armadillo5x0_timer_init,
-};
-
MACHINE_START(ARMADILLO5X0, "Armadillo-500")
/* Maintainer: Alberto Panizzo */
.atag_offset = 0x100,
@@ -568,7 +564,7 @@ MACHINE_START(ARMADILLO5X0, "Armadillo-500")
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &armadillo5x0_timer,
+ .init_time = armadillo5x0_timer_init,
.init_machine = armadillo5x0_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-bug.c b/arch/arm/mach-imx/mach-bug.c
index 3a39d5aec07a..2d00476f7d2c 100644
--- a/arch/arm/mach-imx/mach-bug.c
+++ b/arch/arm/mach-imx/mach-bug.c
@@ -53,16 +53,12 @@ static void __init bug_timer_init(void)
mx31_clocks_init(26000000);
}
-static struct sys_timer bug_timer = {
- .init = bug_timer_init,
-};
-
MACHINE_START(BUG, "BugLabs BUGBase")
.map_io = mx31_map_io,
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &bug_timer,
+ .init_time = bug_timer_init,
.init_machine = bug_board_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c
index 12a370646b45..146559311bd2 100644
--- a/arch/arm/mach-imx/mach-cpuimx27.c
+++ b/arch/arm/mach-imx/mach-cpuimx27.c
@@ -309,17 +309,13 @@ static void __init eukrea_cpuimx27_timer_init(void)
mx27_clocks_init(26000000);
}
-static struct sys_timer eukrea_cpuimx27_timer = {
- .init = eukrea_cpuimx27_timer_init,
-};
-
MACHINE_START(EUKREA_CPUIMX27, "EUKREA CPUIMX27")
.atag_offset = 0x100,
.map_io = mx27_map_io,
.init_early = imx27_init_early,
.init_irq = mx27_init_irq,
.handle_irq = imx27_handle_irq,
- .timer = &eukrea_cpuimx27_timer,
+ .init_time = eukrea_cpuimx27_timer_init,
.init_machine = eukrea_cpuimx27_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c
index 5a31bf8c8f4c..771362d1fbee 100644
--- a/arch/arm/mach-imx/mach-cpuimx35.c
+++ b/arch/arm/mach-imx/mach-cpuimx35.c
@@ -193,10 +193,6 @@ static void __init eukrea_cpuimx35_timer_init(void)
mx35_clocks_init();
}
-static struct sys_timer eukrea_cpuimx35_timer = {
- .init = eukrea_cpuimx35_timer_init,
-};
-
MACHINE_START(EUKREA_CPUIMX35SD, "Eukrea CPUIMX35")
/* Maintainer: Eukrea Electromatique */
.atag_offset = 0x100,
@@ -204,7 +200,7 @@ MACHINE_START(EUKREA_CPUIMX35SD, "Eukrea CPUIMX35")
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.handle_irq = imx35_handle_irq,
- .timer = &eukrea_cpuimx35_timer,
+ .init_time = eukrea_cpuimx35_timer_init,
.init_machine = eukrea_cpuimx35_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-cpuimx51sd.c b/arch/arm/mach-imx/mach-cpuimx51sd.c
index b727de029c8f..9b7393234f6f 100644
--- a/arch/arm/mach-imx/mach-cpuimx51sd.c
+++ b/arch/arm/mach-imx/mach-cpuimx51sd.c
@@ -355,10 +355,6 @@ static void __init eukrea_cpuimx51sd_timer_init(void)
mx51_clocks_init(32768, 24000000, 22579200, 0);
}
-static struct sys_timer mxc_timer = {
- .init = eukrea_cpuimx51sd_timer_init,
-};
-
MACHINE_START(EUKREA_CPUIMX51SD, "Eukrea CPUIMX51SD")
/* Maintainer: Eric Bénard <eric@eukrea.com> */
.atag_offset = 0x100,
@@ -366,7 +362,7 @@ MACHINE_START(EUKREA_CPUIMX51SD, "Eukrea CPUIMX51SD")
.init_early = imx51_init_early,
.init_irq = mx51_init_irq,
.handle_irq = imx51_handle_irq,
- .timer = &mxc_timer,
+ .init_time = eukrea_cpuimx51sd_timer_init,
.init_machine = eukrea_cpuimx51sd_init,
.init_late = imx51_init_late,
.restart = mxc_restart,
diff --git a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
index 75027a5ad8b7..4bf454424249 100644
--- a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
+++ b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
@@ -159,10 +159,6 @@ static void __init eukrea_cpuimx25_timer_init(void)
mx25_clocks_init();
}
-static struct sys_timer eukrea_cpuimx25_timer = {
- .init = eukrea_cpuimx25_timer_init,
-};
-
MACHINE_START(EUKREA_CPUIMX25SD, "Eukrea CPUIMX25")
/* Maintainer: Eukrea Electromatique */
.atag_offset = 0x100,
@@ -170,7 +166,7 @@ MACHINE_START(EUKREA_CPUIMX25SD, "Eukrea CPUIMX25")
.init_early = imx25_init_early,
.init_irq = mx25_init_irq,
.handle_irq = imx25_handle_irq,
- .timer = &eukrea_cpuimx25_timer,
+ .init_time = eukrea_cpuimx25_timer_init,
.init_machine = eukrea_cpuimx25_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
index 318bd8df7fcc..29ac8ee651d2 100644
--- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
+++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
@@ -598,10 +598,6 @@ static void __init visstrim_m10_timer_init(void)
mx27_clocks_init((unsigned long)25000000);
}
-static struct sys_timer visstrim_m10_timer = {
- .init = visstrim_m10_timer_init,
-};
-
MACHINE_START(IMX27_VISSTRIM_M10, "Vista Silicon Visstrim_M10")
.atag_offset = 0x100,
.reserve = visstrim_reserve,
@@ -609,7 +605,7 @@ MACHINE_START(IMX27_VISSTRIM_M10, "Vista Silicon Visstrim_M10")
.init_early = imx27_init_early,
.init_irq = mx27_init_irq,
.handle_irq = imx27_handle_irq,
- .timer = &visstrim_m10_timer,
+ .init_time = visstrim_m10_timer_init,
.init_machine = visstrim_m10_board_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx27ipcam.c b/arch/arm/mach-imx/mach-imx27ipcam.c
index 53a860112938..1a851aea6832 100644
--- a/arch/arm/mach-imx/mach-imx27ipcam.c
+++ b/arch/arm/mach-imx/mach-imx27ipcam.c
@@ -65,10 +65,6 @@ static void __init mx27ipcam_timer_init(void)
mx27_clocks_init(25000000);
}
-static struct sys_timer mx27ipcam_timer = {
- .init = mx27ipcam_timer_init,
-};
-
MACHINE_START(IMX27IPCAM, "Freescale IMX27IPCAM")
/* maintainer: Freescale Semiconductor, Inc. */
.atag_offset = 0x100,
@@ -76,7 +72,7 @@ MACHINE_START(IMX27IPCAM, "Freescale IMX27IPCAM")
.init_early = imx27_init_early,
.init_irq = mx27_init_irq,
.handle_irq = imx27_handle_irq,
- .timer = &mx27ipcam_timer,
+ .init_time = mx27ipcam_timer_init,
.init_machine = mx27ipcam_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx27lite.c b/arch/arm/mach-imx/mach-imx27lite.c
index fc8dce931378..3da2e3e44ce9 100644
--- a/arch/arm/mach-imx/mach-imx27lite.c
+++ b/arch/arm/mach-imx/mach-imx27lite.c
@@ -72,17 +72,13 @@ static void __init mx27lite_timer_init(void)
mx27_clocks_init(26000000);
}
-static struct sys_timer mx27lite_timer = {
- .init = mx27lite_timer_init,
-};
-
MACHINE_START(IMX27LITE, "LogicPD i.MX27LITE")
.atag_offset = 0x100,
.map_io = mx27_map_io,
.init_early = imx27_init_early,
.init_irq = mx27_init_irq,
.handle_irq = imx27_handle_irq,
- .timer = &mx27lite_timer,
+ .init_time = mx27lite_timer_init,
.init_machine = mx27lite_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx53.c b/arch/arm/mach-imx/mach-imx53.c
index 860284dea0e7..f579c616feed 100644
--- a/arch/arm/mach-imx/mach-imx53.c
+++ b/arch/arm/mach-imx/mach-imx53.c
@@ -44,26 +44,22 @@ static void __init imx53_dt_init(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
-static void __init imx53_timer_init(void)
-{
- mx53_clocks_init_dt();
-}
-
-static struct sys_timer imx53_timer = {
- .init = imx53_timer_init,
-};
-
static const char *imx53_dt_board_compat[] __initdata = {
"fsl,imx53",
NULL
};
+static void __init imx53_timer_init(void)
+{
+ mx53_clocks_init_dt();
+}
+
DT_MACHINE_START(IMX53_DT, "Freescale i.MX53 (Device Tree Support)")
.map_io = mx53_map_io,
.init_early = imx53_init_early,
.init_irq = mx53_init_irq,
.handle_irq = imx53_handle_irq,
- .timer = &imx53_timer,
+ .init_time = imx53_timer_init,
.init_machine = imx53_dt_init,
.init_late = imx53_init_late,
.dt_compat = imx53_dt_board_compat,
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 4eb1b3ac794c..1786b2d1257e 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -12,12 +12,12 @@
#include <linux/clk.h>
#include <linux/clkdev.h>
-#include <linux/cpuidle.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -26,11 +26,10 @@
#include <linux/regmap.h>
#include <linux/micrel_phy.h>
#include <linux/mfd/syscon.h>
-#include <asm/cpuidle.h>
#include <asm/smp_twd.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <asm/system_misc.h>
@@ -201,37 +200,28 @@ static void __init imx6q_init_machine(void)
imx6q_1588_init();
}
-static struct cpuidle_driver imx6q_cpuidle_driver = {
- .name = "imx6q_cpuidle",
- .owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
- .states[0] = ARM_CPUIDLE_WFI_STATE,
- .state_count = 1,
-};
-
static void __init imx6q_init_late(void)
{
- imx_cpuidle_init(&imx6q_cpuidle_driver);
+ /*
+ * WAIT mode is broken on TO 1.0 and 1.1, so there is no point
+ * to run cpuidle on them.
+ */
+ if (imx6q_revision() > IMX_CHIP_REVISION_1_1)
+ imx6q_cpuidle_init();
}
static void __init imx6q_map_io(void)
{
- imx_lluart_map_io();
+ debug_ll_io_init();
imx_scu_map_io();
- imx6q_clock_map_io();
}
-static const struct of_device_id imx6q_irq_match[] __initconst = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- { /* sentinel */ }
-};
-
static void __init imx6q_init_irq(void)
{
l2x0_of_init(0, ~0UL);
imx_src_init();
imx_gpc_init();
- of_irq_init(imx6q_irq_match);
+ irqchip_init();
}
static void __init imx6q_timer_init(void)
@@ -241,10 +231,6 @@ static void __init imx6q_timer_init(void)
imx_print_silicon_rev("i.MX6Q", imx6q_revision());
}
-static struct sys_timer imx6q_timer = {
- .init = imx6q_timer_init,
-};
-
static const char *imx6q_dt_compat[] __initdata = {
"fsl,imx6q",
NULL,
@@ -254,8 +240,7 @@ DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)")
.smp = smp_ops(imx_smp_ops),
.map_io = imx6q_map_io,
.init_irq = imx6q_init_irq,
- .handle_irq = imx6q_handle_irq,
- .timer = &imx6q_timer,
+ .init_time = imx6q_timer_init,
.init_machine = imx6q_init_machine,
.init_late = imx6q_init_late,
.dt_compat = imx6q_dt_compat,
diff --git a/arch/arm/mach-imx/mach-kzm_arm11_01.c b/arch/arm/mach-imx/mach-kzm_arm11_01.c
index 2e536ea53444..c7bc41d6b468 100644
--- a/arch/arm/mach-imx/mach-kzm_arm11_01.c
+++ b/arch/arm/mach-imx/mach-kzm_arm11_01.c
@@ -284,17 +284,13 @@ static void __init kzm_timer_init(void)
mx31_clocks_init(26000000);
}
-static struct sys_timer kzm_timer = {
- .init = kzm_timer_init,
-};
-
MACHINE_START(KZM_ARM11_01, "Kyoto Microcomputer Co., Ltd. KZM-ARM11-01")
.atag_offset = 0x100,
.map_io = kzm_map_io,
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &kzm_timer,
+ .init_time = kzm_timer_init,
.init_machine = kzm_board_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx1ads.c b/arch/arm/mach-imx/mach-mx1ads.c
index 06b483783e68..9f883e4d6fc9 100644
--- a/arch/arm/mach-imx/mach-mx1ads.c
+++ b/arch/arm/mach-imx/mach-mx1ads.c
@@ -132,10 +132,6 @@ static void __init mx1ads_timer_init(void)
mx1_clocks_init(32000);
}
-static struct sys_timer mx1ads_timer = {
- .init = mx1ads_timer_init,
-};
-
MACHINE_START(MX1ADS, "Freescale MX1ADS")
/* Maintainer: Sascha Hauer, Pengutronix */
.atag_offset = 0x100,
@@ -143,7 +139,7 @@ MACHINE_START(MX1ADS, "Freescale MX1ADS")
.init_early = imx1_init_early,
.init_irq = mx1_init_irq,
.handle_irq = imx1_handle_irq,
- .timer = &mx1ads_timer,
+ .init_time = mx1ads_timer_init,
.init_machine = mx1ads_init,
.restart = mxc_restart,
MACHINE_END
@@ -154,7 +150,7 @@ MACHINE_START(MXLADS, "Freescale MXLADS")
.init_early = imx1_init_early,
.init_irq = mx1_init_irq,
.handle_irq = imx1_handle_irq,
- .timer = &mx1ads_timer,
+ .init_time = mx1ads_timer_init,
.init_machine = mx1ads_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c
index 6adb3136bb08..a06aa4dc37fc 100644
--- a/arch/arm/mach-imx/mach-mx21ads.c
+++ b/arch/arm/mach-imx/mach-mx21ads.c
@@ -318,10 +318,6 @@ static void __init mx21ads_timer_init(void)
mx21_clocks_init(32768, 26000000);
}
-static struct sys_timer mx21ads_timer = {
- .init = mx21ads_timer_init,
-};
-
MACHINE_START(MX21ADS, "Freescale i.MX21ADS")
/* maintainer: Freescale Semiconductor, Inc. */
.atag_offset = 0x100,
@@ -329,7 +325,7 @@ MACHINE_START(MX21ADS, "Freescale i.MX21ADS")
.init_early = imx21_init_early,
.init_irq = mx21_init_irq,
.handle_irq = imx21_handle_irq,
- .timer = &mx21ads_timer,
+ .init_time = mx21ads_timer_init,
.init_machine = mx21ads_board_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx25_3ds.c b/arch/arm/mach-imx/mach-mx25_3ds.c
index b1b03aa55bb8..8bcda688a006 100644
--- a/arch/arm/mach-imx/mach-mx25_3ds.c
+++ b/arch/arm/mach-imx/mach-mx25_3ds.c
@@ -257,10 +257,6 @@ static void __init mx25pdk_timer_init(void)
mx25_clocks_init();
}
-static struct sys_timer mx25pdk_timer = {
- .init = mx25pdk_timer_init,
-};
-
MACHINE_START(MX25_3DS, "Freescale MX25PDK (3DS)")
/* Maintainer: Freescale Semiconductor, Inc. */
.atag_offset = 0x100,
@@ -268,7 +264,7 @@ MACHINE_START(MX25_3DS, "Freescale MX25PDK (3DS)")
.init_early = imx25_init_early,
.init_irq = mx25_init_irq,
.handle_irq = imx25_handle_irq,
- .timer = &mx25pdk_timer,
+ .init_time = mx25pdk_timer_init,
.init_machine = mx25pdk_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c
index d0e547fa925f..25b3e4c9bc0a 100644
--- a/arch/arm/mach-imx/mach-mx27_3ds.c
+++ b/arch/arm/mach-imx/mach-mx27_3ds.c
@@ -538,10 +538,6 @@ static void __init mx27pdk_timer_init(void)
mx27_clocks_init(26000000);
}
-static struct sys_timer mx27pdk_timer = {
- .init = mx27pdk_timer_init,
-};
-
MACHINE_START(MX27_3DS, "Freescale MX27PDK")
/* maintainer: Freescale Semiconductor, Inc. */
.atag_offset = 0x100,
@@ -549,7 +545,7 @@ MACHINE_START(MX27_3DS, "Freescale MX27PDK")
.init_early = imx27_init_early,
.init_irq = mx27_init_irq,
.handle_irq = imx27_handle_irq,
- .timer = &mx27pdk_timer,
+ .init_time = mx27pdk_timer_init,
.init_machine = mx27pdk_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx27ads.c b/arch/arm/mach-imx/mach-mx27ads.c
index 3d036f57f0e6..9821b824dcaf 100644
--- a/arch/arm/mach-imx/mach-mx27ads.c
+++ b/arch/arm/mach-imx/mach-mx27ads.c
@@ -323,10 +323,6 @@ static void __init mx27ads_timer_init(void)
mx27_clocks_init(fref);
}
-static struct sys_timer mx27ads_timer = {
- .init = mx27ads_timer_init,
-};
-
static struct map_desc mx27ads_io_desc[] __initdata = {
{
.virtual = PBC_BASE_ADDRESS,
@@ -349,7 +345,7 @@ MACHINE_START(MX27ADS, "Freescale i.MX27ADS")
.init_early = imx27_init_early,
.init_irq = mx27_init_irq,
.handle_irq = imx27_handle_irq,
- .timer = &mx27ads_timer,
+ .init_time = mx27ads_timer_init,
.init_machine = mx27ads_board_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c
index bc301befdd06..1ed916175d41 100644
--- a/arch/arm/mach-imx/mach-mx31_3ds.c
+++ b/arch/arm/mach-imx/mach-mx31_3ds.c
@@ -762,10 +762,6 @@ static void __init mx31_3ds_timer_init(void)
mx31_clocks_init(26000000);
}
-static struct sys_timer mx31_3ds_timer = {
- .init = mx31_3ds_timer_init,
-};
-
static void __init mx31_3ds_reserve(void)
{
/* reserve MX31_3DS_CAMERA_BUF_SIZE bytes for mx3-camera */
@@ -780,7 +776,7 @@ MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)")
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &mx31_3ds_timer,
+ .init_time = mx31_3ds_timer_init,
.init_machine = mx31_3ds_init,
.reserve = mx31_3ds_reserve,
.restart = mxc_restart,
diff --git a/arch/arm/mach-imx/mach-mx31ads.c b/arch/arm/mach-imx/mach-mx31ads.c
index 8b56f8883f32..daf8889125cc 100644
--- a/arch/arm/mach-imx/mach-mx31ads.c
+++ b/arch/arm/mach-imx/mach-mx31ads.c
@@ -576,10 +576,6 @@ static void __init mx31ads_timer_init(void)
mx31_clocks_init(26000000);
}
-static struct sys_timer mx31ads_timer = {
- .init = mx31ads_timer_init,
-};
-
MACHINE_START(MX31ADS, "Freescale MX31ADS")
/* Maintainer: Freescale Semiconductor, Inc. */
.atag_offset = 0x100,
@@ -587,7 +583,7 @@ MACHINE_START(MX31ADS, "Freescale MX31ADS")
.init_early = imx31_init_early,
.init_irq = mx31ads_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &mx31ads_timer,
+ .init_time = mx31ads_timer_init,
.init_machine = mx31ads_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx31lilly.c b/arch/arm/mach-imx/mach-mx31lilly.c
index 08b9965c8b36..832b1e2f964e 100644
--- a/arch/arm/mach-imx/mach-mx31lilly.c
+++ b/arch/arm/mach-imx/mach-mx31lilly.c
@@ -303,17 +303,13 @@ static void __init mx31lilly_timer_init(void)
mx31_clocks_init(26000000);
}
-static struct sys_timer mx31lilly_timer = {
- .init = mx31lilly_timer_init,
-};
-
MACHINE_START(LILLY1131, "INCO startec LILLY-1131")
.atag_offset = 0x100,
.map_io = mx31_map_io,
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &mx31lilly_timer,
+ .init_time = mx31lilly_timer_init,
.init_machine = mx31lilly_board_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx31lite.c b/arch/arm/mach-imx/mach-mx31lite.c
index bdcd92e59518..bea07299b61a 100644
--- a/arch/arm/mach-imx/mach-mx31lite.c
+++ b/arch/arm/mach-imx/mach-mx31lite.c
@@ -285,10 +285,6 @@ static void __init mx31lite_timer_init(void)
mx31_clocks_init(26000000);
}
-static struct sys_timer mx31lite_timer = {
- .init = mx31lite_timer_init,
-};
-
MACHINE_START(MX31LITE, "LogicPD i.MX31 SOM")
/* Maintainer: Freescale Semiconductor, Inc. */
.atag_offset = 0x100,
@@ -296,7 +292,7 @@ MACHINE_START(MX31LITE, "LogicPD i.MX31 SOM")
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &mx31lite_timer,
+ .init_time = mx31lite_timer_init,
.init_machine = mx31lite_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index 2517cfa9f26b..dae4cd7be040 100644
--- a/arch/arm/mach-imx/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -596,10 +596,6 @@ static void __init mx31moboard_timer_init(void)
mx31_clocks_init(26000000);
}
-static struct sys_timer mx31moboard_timer = {
- .init = mx31moboard_timer_init,
-};
-
static void __init mx31moboard_reserve(void)
{
/* reserve 4 MiB for mx3-camera */
@@ -615,7 +611,7 @@ MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &mx31moboard_timer,
+ .init_time = mx31moboard_timer_init,
.init_machine = mx31moboard_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx35_3ds.c b/arch/arm/mach-imx/mach-mx35_3ds.c
index 5277da45d60c..a42f4f07051f 100644
--- a/arch/arm/mach-imx/mach-mx35_3ds.c
+++ b/arch/arm/mach-imx/mach-mx35_3ds.c
@@ -602,10 +602,6 @@ static void __init mx35pdk_timer_init(void)
mx35_clocks_init();
}
-static struct sys_timer mx35pdk_timer = {
- .init = mx35pdk_timer_init,
-};
-
static void __init mx35_3ds_reserve(void)
{
/* reserve MX35_3DS_CAMERA_BUF_SIZE bytes for mx3-camera */
@@ -620,7 +616,7 @@ MACHINE_START(MX35_3DS, "Freescale MX35PDK")
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.handle_irq = imx35_handle_irq,
- .timer = &mx35pdk_timer,
+ .init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
diff --git a/arch/arm/mach-imx/mach-mx50_rdp.c b/arch/arm/mach-imx/mach-mx50_rdp.c
deleted file mode 100644
index 0c1f88a80bdc..000000000000
--- a/arch/arm/mach-imx/mach-mx50_rdp.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-
-#include "common.h"
-#include "devices-imx50.h"
-#include "hardware.h"
-#include "iomux-mx50.h"
-
-#define FEC_EN IMX_GPIO_NR(6, 23)
-#define FEC_RESET_B IMX_GPIO_NR(4, 12)
-
-static iomux_v3_cfg_t mx50_rdp_pads[] __initdata = {
- /* SD1 */
- MX50_PAD_ECSPI2_SS0__GPIO_4_19,
- MX50_PAD_EIM_CRE__GPIO_1_27,
- MX50_PAD_SD1_CMD__SD1_CMD,
-
- MX50_PAD_SD1_CLK__SD1_CLK,
- MX50_PAD_SD1_D0__SD1_D0,
- MX50_PAD_SD1_D1__SD1_D1,
- MX50_PAD_SD1_D2__SD1_D2,
- MX50_PAD_SD1_D3__SD1_D3,
-
- /* SD2 */
- MX50_PAD_SD2_CD__GPIO_5_17,
- MX50_PAD_SD2_WP__GPIO_5_16,
- MX50_PAD_SD2_CMD__SD2_CMD,
- MX50_PAD_SD2_CLK__SD2_CLK,
- MX50_PAD_SD2_D0__SD2_D0,
- MX50_PAD_SD2_D1__SD2_D1,
- MX50_PAD_SD2_D2__SD2_D2,
- MX50_PAD_SD2_D3__SD2_D3,
- MX50_PAD_SD2_D4__SD2_D4,
- MX50_PAD_SD2_D5__SD2_D5,
- MX50_PAD_SD2_D6__SD2_D6,
- MX50_PAD_SD2_D7__SD2_D7,
-
- /* SD3 */
- MX50_PAD_SD3_CMD__SD3_CMD,
- MX50_PAD_SD3_CLK__SD3_CLK,
- MX50_PAD_SD3_D0__SD3_D0,
- MX50_PAD_SD3_D1__SD3_D1,
- MX50_PAD_SD3_D2__SD3_D2,
- MX50_PAD_SD3_D3__SD3_D3,
- MX50_PAD_SD3_D4__SD3_D4,
- MX50_PAD_SD3_D5__SD3_D5,
- MX50_PAD_SD3_D6__SD3_D6,
- MX50_PAD_SD3_D7__SD3_D7,
-
- /* PWR_INT */
- MX50_PAD_ECSPI2_MISO__GPIO_4_18,
-
- /* UART pad setting */
- MX50_PAD_UART1_TXD__UART1_TXD,
- MX50_PAD_UART1_RXD__UART1_RXD,
- MX50_PAD_UART1_RTS__UART1_RTS,
- MX50_PAD_UART2_TXD__UART2_TXD,
- MX50_PAD_UART2_RXD__UART2_RXD,
- MX50_PAD_UART2_CTS__UART2_CTS,
- MX50_PAD_UART2_RTS__UART2_RTS,
-
- MX50_PAD_I2C1_SCL__I2C1_SCL,
- MX50_PAD_I2C1_SDA__I2C1_SDA,
- MX50_PAD_I2C2_SCL__I2C2_SCL,
- MX50_PAD_I2C2_SDA__I2C2_SDA,
-
- MX50_PAD_EPITO__USBH1_PWR,
- /* Need to comment below line if
- * one needs to debug owire.
- */
- MX50_PAD_OWIRE__USBH1_OC,
- /* using gpio to control otg pwr */
- MX50_PAD_PWM2__GPIO_6_25,
- MX50_PAD_I2C3_SCL__USBOTG_OC,
-
- MX50_PAD_SSI_RXC__FEC_MDIO,
- MX50_PAD_SSI_RXFS__FEC_MDC,
- MX50_PAD_DISP_D0__FEC_TXCLK,
- MX50_PAD_DISP_D1__FEC_RX_ER,
- MX50_PAD_DISP_D2__FEC_RX_DV,
- MX50_PAD_DISP_D3__FEC_RXD1,
- MX50_PAD_DISP_D4__FEC_RXD0,
- MX50_PAD_DISP_D5__FEC_TX_EN,
- MX50_PAD_DISP_D6__FEC_TXD1,
- MX50_PAD_DISP_D7__FEC_TXD0,
- MX50_PAD_I2C3_SDA__GPIO_6_23,
- MX50_PAD_ECSPI1_SCLK__GPIO_4_12,
-
- MX50_PAD_CSPI_SS0__CSPI_SS0,
- MX50_PAD_ECSPI1_MOSI__CSPI_SS1,
- MX50_PAD_CSPI_MOSI__CSPI_MOSI,
- MX50_PAD_CSPI_MISO__CSPI_MISO,
-
- /* SGTL500_OSC_EN */
- MX50_PAD_UART1_CTS__GPIO_6_8,
-
- /* SGTL_AMP_SHDN */
- MX50_PAD_UART3_RXD__GPIO_6_15,
-
- /* Keypad */
- MX50_PAD_KEY_COL0__KEY_COL0,
- MX50_PAD_KEY_ROW0__KEY_ROW0,
- MX50_PAD_KEY_COL1__KEY_COL1,
- MX50_PAD_KEY_ROW1__KEY_ROW1,
- MX50_PAD_KEY_COL2__KEY_COL2,
- MX50_PAD_KEY_ROW2__KEY_ROW2,
- MX50_PAD_KEY_COL3__KEY_COL3,
- MX50_PAD_KEY_ROW3__KEY_ROW3,
- MX50_PAD_EIM_DA0__KEY_COL4,
- MX50_PAD_EIM_DA1__KEY_ROW4,
- MX50_PAD_EIM_DA2__KEY_COL5,
- MX50_PAD_EIM_DA3__KEY_ROW5,
- MX50_PAD_EIM_DA4__KEY_COL6,
- MX50_PAD_EIM_DA5__KEY_ROW6,
- MX50_PAD_EIM_DA6__KEY_COL7,
- MX50_PAD_EIM_DA7__KEY_ROW7,
- /*EIM pads */
- MX50_PAD_EIM_DA8__GPIO_1_8,
- MX50_PAD_EIM_DA9__GPIO_1_9,
- MX50_PAD_EIM_DA10__GPIO_1_10,
- MX50_PAD_EIM_DA11__GPIO_1_11,
- MX50_PAD_EIM_DA12__GPIO_1_12,
- MX50_PAD_EIM_DA13__GPIO_1_13,
- MX50_PAD_EIM_DA14__GPIO_1_14,
- MX50_PAD_EIM_DA15__GPIO_1_15,
- MX50_PAD_EIM_CS2__GPIO_1_16,
- MX50_PAD_EIM_CS1__GPIO_1_17,
- MX50_PAD_EIM_CS0__GPIO_1_18,
- MX50_PAD_EIM_EB0__GPIO_1_19,
- MX50_PAD_EIM_EB1__GPIO_1_20,
- MX50_PAD_EIM_WAIT__GPIO_1_21,
- MX50_PAD_EIM_BCLK__GPIO_1_22,
- MX50_PAD_EIM_RDY__GPIO_1_23,
- MX50_PAD_EIM_OE__GPIO_1_24,
-};
-
-/* Serial ports */
-static const struct imxuart_platform_data uart_pdata __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static const struct fec_platform_data fec_data __initconst = {
- .phy = PHY_INTERFACE_MODE_RMII,
-};
-
-static inline void mx50_rdp_fec_reset(void)
-{
- gpio_request(FEC_EN, "fec-en");
- gpio_direction_output(FEC_EN, 0);
- gpio_request(FEC_RESET_B, "fec-reset_b");
- gpio_direction_output(FEC_RESET_B, 0);
- msleep(1);
- gpio_set_value(FEC_RESET_B, 1);
-}
-
-static const struct imxi2c_platform_data i2c_data __initconst = {
- .bitrate = 100000,
-};
-
-/*
- * Board specific initialization.
- */
-static void __init mx50_rdp_board_init(void)
-{
- imx50_soc_init();
-
- mxc_iomux_v3_setup_multiple_pads(mx50_rdp_pads,
- ARRAY_SIZE(mx50_rdp_pads));
-
- imx50_add_imx_uart(0, &uart_pdata);
- imx50_add_imx_uart(1, &uart_pdata);
- mx50_rdp_fec_reset();
- imx50_add_fec(&fec_data);
- imx50_add_imx_i2c(0, &i2c_data);
- imx50_add_imx_i2c(1, &i2c_data);
- imx50_add_imx_i2c(2, &i2c_data);
-}
-
-static void __init mx50_rdp_timer_init(void)
-{
- mx50_clocks_init(32768, 24000000, 22579200);
-}
-
-static struct sys_timer mx50_rdp_timer = {
- .init = mx50_rdp_timer_init,
-};
-
-MACHINE_START(MX50_RDP, "Freescale MX50 Reference Design Platform")
- .map_io = mx50_map_io,
- .init_early = imx50_init_early,
- .init_irq = mx50_init_irq,
- .handle_irq = imx50_handle_irq,
- .timer = &mx50_rdp_timer,
- .init_machine = mx50_rdp_board_init,
- .restart = mxc_restart,
-MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx51_3ds.c b/arch/arm/mach-imx/mach-mx51_3ds.c
deleted file mode 100644
index abc25bd1107b..000000000000
--- a/arch/arm/mach-imx/mach-mx51_3ds.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2010 Jason Wang <jason77.wang@gmail.com>
- *
- * 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/irq.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-
-#include "3ds_debugboard.h"
-#include "common.h"
-#include "devices-imx51.h"
-#include "hardware.h"
-#include "iomux-mx51.h"
-
-#define MX51_3DS_ECSPI2_CS (GPIO_PORTC + 28)
-
-static iomux_v3_cfg_t mx51_3ds_pads[] = {
- /* UART1 */
- MX51_PAD_UART1_RXD__UART1_RXD,
- MX51_PAD_UART1_TXD__UART1_TXD,
- MX51_PAD_UART1_RTS__UART1_RTS,
- MX51_PAD_UART1_CTS__UART1_CTS,
-
- /* UART2 */
- MX51_PAD_UART2_RXD__UART2_RXD,
- MX51_PAD_UART2_TXD__UART2_TXD,
- MX51_PAD_EIM_D25__UART2_CTS,
- MX51_PAD_EIM_D26__UART2_RTS,
-
- /* UART3 */
- MX51_PAD_UART3_RXD__UART3_RXD,
- MX51_PAD_UART3_TXD__UART3_TXD,
- MX51_PAD_EIM_D24__UART3_CTS,
- MX51_PAD_EIM_D27__UART3_RTS,
-
- /* CPLD PARENT IRQ PIN */
- MX51_PAD_GPIO1_6__GPIO1_6,
-
- /* KPP */
- MX51_PAD_KEY_ROW0__KEY_ROW0,
- MX51_PAD_KEY_ROW1__KEY_ROW1,
- MX51_PAD_KEY_ROW2__KEY_ROW2,
- MX51_PAD_KEY_ROW3__KEY_ROW3,
- MX51_PAD_KEY_COL0__KEY_COL0,
- MX51_PAD_KEY_COL1__KEY_COL1,
- MX51_PAD_KEY_COL2__KEY_COL2,
- MX51_PAD_KEY_COL3__KEY_COL3,
- MX51_PAD_KEY_COL4__KEY_COL4,
- MX51_PAD_KEY_COL5__KEY_COL5,
-
- /* eCSPI2 */
- MX51_PAD_NANDF_RB2__ECSPI2_SCLK,
- MX51_PAD_NANDF_RB3__ECSPI2_MISO,
- MX51_PAD_NANDF_D15__ECSPI2_MOSI,
- MX51_PAD_NANDF_D12__GPIO3_28,
-};
-
-/* Serial ports */
-static const struct imxuart_platform_data uart_pdata __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static int mx51_3ds_board_keymap[] = {
- KEY(0, 0, KEY_1),
- KEY(0, 1, KEY_2),
- KEY(0, 2, KEY_3),
- KEY(0, 3, KEY_F1),
- KEY(0, 4, KEY_UP),
- KEY(0, 5, KEY_F2),
-
- KEY(1, 0, KEY_4),
- KEY(1, 1, KEY_5),
- KEY(1, 2, KEY_6),
- KEY(1, 3, KEY_LEFT),
- KEY(1, 4, KEY_SELECT),
- KEY(1, 5, KEY_RIGHT),
-
- KEY(2, 0, KEY_7),
- KEY(2, 1, KEY_8),
- KEY(2, 2, KEY_9),
- KEY(2, 3, KEY_F3),
- KEY(2, 4, KEY_DOWN),
- KEY(2, 5, KEY_F4),
-
- KEY(3, 0, KEY_0),
- KEY(3, 1, KEY_OK),
- KEY(3, 2, KEY_ESC),
- KEY(3, 3, KEY_ENTER),
- KEY(3, 4, KEY_MENU),
- KEY(3, 5, KEY_BACK)
-};
-
-static const struct matrix_keymap_data mx51_3ds_map_data __initconst = {
- .keymap = mx51_3ds_board_keymap,
- .keymap_size = ARRAY_SIZE(mx51_3ds_board_keymap),
-};
-
-static int mx51_3ds_spi2_cs[] = {
- MXC_SPI_CS(0),
- MX51_3DS_ECSPI2_CS,
-};
-
-static const struct spi_imx_master mx51_3ds_ecspi2_pdata __initconst = {
- .chipselect = mx51_3ds_spi2_cs,
- .num_chipselect = ARRAY_SIZE(mx51_3ds_spi2_cs),
-};
-
-static struct spi_board_info mx51_3ds_spi_nor_device[] = {
- {
- .modalias = "m25p80",
- .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
- .bus_num = 1,
- .chip_select = 1,
- .mode = SPI_MODE_0,
- .platform_data = NULL,},
-};
-
-/*
- * Board specific initialization.
- */
-static void __init mx51_3ds_init(void)
-{
- imx51_soc_init();
-
- mxc_iomux_v3_setup_multiple_pads(mx51_3ds_pads,
- ARRAY_SIZE(mx51_3ds_pads));
-
- imx51_add_imx_uart(0, &uart_pdata);
- imx51_add_imx_uart(1, &uart_pdata);
- imx51_add_imx_uart(2, &uart_pdata);
-
- imx51_add_ecspi(1, &mx51_3ds_ecspi2_pdata);
- spi_register_board_info(mx51_3ds_spi_nor_device,
- ARRAY_SIZE(mx51_3ds_spi_nor_device));
-
- if (mxc_expio_init(MX51_CS5_BASE_ADDR, IMX_GPIO_NR(1, 6)))
- printk(KERN_WARNING "Init of the debugboard failed, all "
- "devices on the board are unusable.\n");
-
- imx51_add_sdhci_esdhc_imx(0, NULL);
- imx51_add_imx_keypad(&mx51_3ds_map_data);
- imx51_add_imx2_wdt(0);
-}
-
-static void __init mx51_3ds_timer_init(void)
-{
- mx51_clocks_init(32768, 24000000, 22579200, 0);
-}
-
-static struct sys_timer mx51_3ds_timer = {
- .init = mx51_3ds_timer_init,
-};
-
-MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board")
- /* Maintainer: Freescale Semiconductor, Inc. */
- .atag_offset = 0x100,
- .map_io = mx51_map_io,
- .init_early = imx51_init_early,
- .init_irq = mx51_init_irq,
- .handle_irq = imx51_handle_irq,
- .timer = &mx51_3ds_timer,
- .init_machine = mx51_3ds_init,
- .init_late = imx51_init_late,
- .restart = mxc_restart,
-MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx51_babbage.c b/arch/arm/mach-imx/mach-mx51_babbage.c
index d9a84ca2199a..6c4d7feb4520 100644
--- a/arch/arm/mach-imx/mach-mx51_babbage.c
+++ b/arch/arm/mach-imx/mach-mx51_babbage.c
@@ -418,10 +418,6 @@ static void __init mx51_babbage_timer_init(void)
mx51_clocks_init(32768, 24000000, 22579200, 0);
}
-static struct sys_timer mx51_babbage_timer = {
- .init = mx51_babbage_timer_init,
-};
-
MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board")
/* Maintainer: Amit Kucheria <amit.kucheria@canonical.com> */
.atag_offset = 0x100,
@@ -429,7 +425,7 @@ MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board")
.init_early = imx51_init_early,
.init_irq = mx51_init_irq,
.handle_irq = imx51_handle_irq,
- .timer = &mx51_babbage_timer,
+ .init_time = mx51_babbage_timer_init,
.init_machine = mx51_babbage_init,
.init_late = imx51_init_late,
.restart = mxc_restart,
diff --git a/arch/arm/mach-imx/mach-mxt_td60.c b/arch/arm/mach-imx/mach-mxt_td60.c
index f4a8c7e108e1..a27faaba98ec 100644
--- a/arch/arm/mach-imx/mach-mxt_td60.c
+++ b/arch/arm/mach-imx/mach-mxt_td60.c
@@ -261,10 +261,6 @@ static void __init mxt_td60_timer_init(void)
mx27_clocks_init(26000000);
}
-static struct sys_timer mxt_td60_timer = {
- .init = mxt_td60_timer_init,
-};
-
MACHINE_START(MXT_TD60, "Maxtrack i-MXT TD60")
/* maintainer: Maxtrack Industrial */
.atag_offset = 0x100,
@@ -272,7 +268,7 @@ MACHINE_START(MXT_TD60, "Maxtrack i-MXT TD60")
.init_early = imx27_init_early,
.init_irq = mx27_init_irq,
.handle_irq = imx27_handle_irq,
- .timer = &mxt_td60_timer,
+ .init_time = mxt_td60_timer_init,
.init_machine = mxt_td60_board_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c
index eee369fa94a2..b8b15bb1ffdf 100644
--- a/arch/arm/mach-imx/mach-pca100.c
+++ b/arch/arm/mach-imx/mach-pca100.c
@@ -416,10 +416,6 @@ static void __init pca100_timer_init(void)
mx27_clocks_init(26000000);
}
-static struct sys_timer pca100_timer = {
- .init = pca100_timer_init,
-};
-
MACHINE_START(PCA100, "phyCARD-i.MX27")
.atag_offset = 0x100,
.map_io = mx27_map_io,
@@ -427,6 +423,6 @@ MACHINE_START(PCA100, "phyCARD-i.MX27")
.init_irq = mx27_init_irq,
.handle_irq = imx27_handle_irq,
.init_machine = pca100_init,
- .timer = &pca100_timer,
+ .init_time = pca100_timer_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c
index 547fef133f65..bc0261e99d39 100644
--- a/arch/arm/mach-imx/mach-pcm037.c
+++ b/arch/arm/mach-imx/mach-pcm037.c
@@ -685,10 +685,6 @@ static void __init pcm037_timer_init(void)
mx31_clocks_init(26000000);
}
-static struct sys_timer pcm037_timer = {
- .init = pcm037_timer_init,
-};
-
static void __init pcm037_reserve(void)
{
/* reserve 4 MiB for mx3-camera */
@@ -709,7 +705,7 @@ MACHINE_START(PCM037, "Phytec Phycore pcm037")
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &pcm037_timer,
+ .init_time = pcm037_timer_init,
.init_machine = pcm037_init,
.init_late = pcm037_init_late,
.restart = mxc_restart,
diff --git a/arch/arm/mach-imx/mach-pcm038.c b/arch/arm/mach-imx/mach-pcm038.c
index 4aa0d0798605..e805ac273e9c 100644
--- a/arch/arm/mach-imx/mach-pcm038.c
+++ b/arch/arm/mach-imx/mach-pcm038.c
@@ -346,17 +346,13 @@ static void __init pcm038_timer_init(void)
mx27_clocks_init(26000000);
}
-static struct sys_timer pcm038_timer = {
- .init = pcm038_timer_init,
-};
-
MACHINE_START(PCM038, "phyCORE-i.MX27")
.atag_offset = 0x100,
.map_io = mx27_map_io,
.init_early = imx27_init_early,
.init_irq = mx27_init_irq,
.handle_irq = imx27_handle_irq,
- .timer = &pcm038_timer,
+ .init_time = pcm038_timer_init,
.init_machine = pcm038_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c
index 92445440221e..8ed533f0f8ca 100644
--- a/arch/arm/mach-imx/mach-pcm043.c
+++ b/arch/arm/mach-imx/mach-pcm043.c
@@ -394,10 +394,6 @@ static void __init pcm043_timer_init(void)
mx35_clocks_init();
}
-static struct sys_timer pcm043_timer = {
- .init = pcm043_timer_init,
-};
-
MACHINE_START(PCM043, "Phytec Phycore pcm043")
/* Maintainer: Pengutronix */
.atag_offset = 0x100,
@@ -405,7 +401,7 @@ MACHINE_START(PCM043, "Phytec Phycore pcm043")
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.handle_irq = imx35_handle_irq,
- .timer = &pcm043_timer,
+ .init_time = pcm043_timer_init,
.init_machine = pcm043_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-qong.c b/arch/arm/mach-imx/mach-qong.c
index 96d9a91f8a3b..22af27ed457e 100644
--- a/arch/arm/mach-imx/mach-qong.c
+++ b/arch/arm/mach-imx/mach-qong.c
@@ -260,10 +260,6 @@ static void __init qong_timer_init(void)
mx31_clocks_init(26000000);
}
-static struct sys_timer qong_timer = {
- .init = qong_timer_init,
-};
-
MACHINE_START(QONG, "Dave/DENX QongEVB-LITE")
/* Maintainer: DENX Software Engineering GmbH */
.atag_offset = 0x100,
@@ -271,7 +267,7 @@ MACHINE_START(QONG, "Dave/DENX QongEVB-LITE")
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.handle_irq = imx31_handle_irq,
- .timer = &qong_timer,
+ .init_time = qong_timer_init,
.init_machine = qong_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-scb9328.c b/arch/arm/mach-imx/mach-scb9328.c
index fc970409dbaf..b0fa10dd79fe 100644
--- a/arch/arm/mach-imx/mach-scb9328.c
+++ b/arch/arm/mach-imx/mach-scb9328.c
@@ -131,10 +131,6 @@ static void __init scb9328_timer_init(void)
mx1_clocks_init(32000);
}
-static struct sys_timer scb9328_timer = {
- .init = scb9328_timer_init,
-};
-
MACHINE_START(SCB9328, "Synertronixx scb9328")
/* Sascha Hauer */
.atag_offset = 100,
@@ -142,7 +138,7 @@ MACHINE_START(SCB9328, "Synertronixx scb9328")
.init_early = imx1_init_early,
.init_irq = mx1_init_irq,
.handle_irq = imx1_handle_irq,
- .timer = &scb9328_timer,
+ .init_time = scb9328_timer_init,
.init_machine = scb9328_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-vpr200.c b/arch/arm/mach-imx/mach-vpr200.c
index 3aecf91e4289..0910761e8280 100644
--- a/arch/arm/mach-imx/mach-vpr200.c
+++ b/arch/arm/mach-imx/mach-vpr200.c
@@ -305,17 +305,13 @@ static void __init vpr200_timer_init(void)
mx35_clocks_init();
}
-static struct sys_timer vpr200_timer = {
- .init = vpr200_timer_init,
-};
-
MACHINE_START(VPR200, "VPR200")
/* Maintainer: Creative Product Design */
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.handle_irq = imx35_handle_irq,
- .timer = &vpr200_timer,
+ .init_time = vpr200_timer_init,
.init_machine = vpr200_board_init,
.restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c
index 79d71cf23a1d..cf34994cfe28 100644
--- a/arch/arm/mach-imx/mm-imx5.c
+++ b/arch/arm/mach-imx/mm-imx5.c
@@ -24,16 +24,6 @@
#include "iomux-v3.h"
/*
- * Define the MX50 memory map.
- */
-static struct map_desc mx50_io_desc[] __initdata = {
- imx_map_entry(MX50, TZIC, MT_DEVICE),
- imx_map_entry(MX50, SPBA0, MT_DEVICE),
- imx_map_entry(MX50, AIPS1, MT_DEVICE),
- imx_map_entry(MX50, AIPS2, MT_DEVICE),
-};
-
-/*
* Define the MX51 memory map.
*/
static struct map_desc mx51_io_desc[] __initdata = {
@@ -59,11 +49,6 @@ static struct map_desc mx53_io_desc[] __initdata = {
* system startup to create static physical to virtual memory mappings
* for the IO modules.
*/
-void __init mx50_map_io(void)
-{
- iotable_init(mx50_io_desc, ARRAY_SIZE(mx50_io_desc));
-}
-
void __init mx51_map_io(void)
{
iotable_init(mx51_io_desc, ARRAY_SIZE(mx51_io_desc));
@@ -74,13 +59,6 @@ void __init mx53_map_io(void)
iotable_init(mx53_io_desc, ARRAY_SIZE(mx53_io_desc));
}
-void __init imx50_init_early(void)
-{
- mxc_set_cpu_type(MXC_CPU_MX50);
- mxc_iomux_v3_init(MX50_IO_ADDRESS(MX50_IOMUXC_BASE_ADDR));
- mxc_arch_reset_init(MX50_IO_ADDRESS(MX50_WDOG_BASE_ADDR));
-}
-
/*
* The MIPI HSC unit has been removed from the i.MX51 Reference Manual by
* the Freescale marketing division. However this did not remove the
@@ -115,11 +93,6 @@ void __init imx53_init_early(void)
mxc_arch_reset_init(MX53_IO_ADDRESS(MX53_WDOG1_BASE_ADDR));
}
-void __init mx50_init_irq(void)
-{
- tzic_init_irq(MX50_IO_ADDRESS(MX50_TZIC_BASE_ADDR));
-}
-
void __init mx51_init_irq(void)
{
tzic_init_irq(MX51_IO_ADDRESS(MX51_TZIC_BASE_ADDR));
@@ -148,31 +121,10 @@ static struct sdma_platform_data imx51_sdma_pdata __initdata = {
.script_addrs = &imx51_sdma_script,
};
-static const struct resource imx50_audmux_res[] __initconst = {
- DEFINE_RES_MEM(MX50_AUDMUX_BASE_ADDR, SZ_16K),
-};
-
static const struct resource imx51_audmux_res[] __initconst = {
DEFINE_RES_MEM(MX51_AUDMUX_BASE_ADDR, SZ_16K),
};
-void __init imx50_soc_init(void)
-{
- mxc_device_init();
-
- /* i.mx50 has the i.mx35 type gpio */
- mxc_register_gpio("imx35-gpio", 0, MX50_GPIO1_BASE_ADDR, SZ_16K, MX50_INT_GPIO1_LOW, MX50_INT_GPIO1_HIGH);
- mxc_register_gpio("imx35-gpio", 1, MX50_GPIO2_BASE_ADDR, SZ_16K, MX50_INT_GPIO2_LOW, MX50_INT_GPIO2_HIGH);
- mxc_register_gpio("imx35-gpio", 2, MX50_GPIO3_BASE_ADDR, SZ_16K, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH);
- mxc_register_gpio("imx35-gpio", 3, MX50_GPIO4_BASE_ADDR, SZ_16K, MX50_INT_GPIO4_LOW, MX50_INT_GPIO4_HIGH);
- mxc_register_gpio("imx35-gpio", 4, MX50_GPIO5_BASE_ADDR, SZ_16K, MX50_INT_GPIO5_LOW, MX50_INT_GPIO5_HIGH);
- mxc_register_gpio("imx35-gpio", 5, MX50_GPIO6_BASE_ADDR, SZ_16K, MX50_INT_GPIO6_LOW, MX50_INT_GPIO6_HIGH);
-
- /* i.mx50 has the i.mx31 type audmux */
- platform_device_register_simple("imx31-audmux", 0, imx50_audmux_res,
- ARRAY_SIZE(imx50_audmux_res));
-}
-
void __init imx51_soc_init(void)
{
mxc_device_init();
diff --git a/arch/arm/mach-imx/mx50.h b/arch/arm/mach-imx/mx50.h
deleted file mode 100644
index 09ac19c1570c..000000000000
--- a/arch/arm/mach-imx/mx50.h
+++ /dev/null
@@ -1,290 +0,0 @@
-#ifndef __MACH_MX50_H__
-#define __MACH_MX50_H__
-
-/*
- * IROM
- */
-#define MX50_IROM_BASE_ADDR 0x0
-#define MX50_IROM_SIZE SZ_64K
-
-/* TZIC */
-#define MX50_TZIC_BASE_ADDR 0x0fffc000
-#define MX50_TZIC_SIZE SZ_16K
-
-/*
- * IRAM
- */
-#define MX50_IRAM_BASE_ADDR 0xf8000000 /* internal ram */
-#define MX50_IRAM_PARTITIONS 16
-#define MX50_IRAM_SIZE (MX50_IRAM_PARTITIONS * SZ_8K) /* 128KB */
-
-/*
- * Databahn
- */
-#define MX50_DATABAHN_BASE_ADDR 0x14000000
-
-/*
- * Graphics Memory of GPU
- */
-#define MX50_GPU2D_BASE_ADDR 0x20000000
-
-#define MX50_DEBUG_BASE_ADDR 0x40000000
-#define MX50_DEBUG_SIZE SZ_1M
-#define MX50_ETB_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x00001000)
-#define MX50_ETM_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x00002000)
-#define MX50_TPIU_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x00003000)
-#define MX50_CTI0_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x00004000)
-#define MX50_CTI1_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x00005000)
-#define MX50_CTI2_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x00006000)
-#define MX50_CTI3_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x00007000)
-#define MX50_CORTEX_DBG_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x00008000)
-
-#define MX50_APBHDMA_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x01000000)
-#define MX50_OCOTP_CTRL_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x01002000)
-#define MX50_DIGCTL_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x01004000)
-#define MX50_GPMI_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x01006000)
-#define MX50_BCH_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x01008000)
-#define MX50_ELCDIF_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x0100a000)
-#define MX50_EPXP_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x0100c000)
-#define MX50_DCP_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x0100e000)
-#define MX50_EPDC_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x01010000)
-#define MX50_QOSC_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x01012000)
-#define MX50_PERFMON_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x01014000)
-#define MX50_SSP_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x01016000)
-#define MX50_ANATOP_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x01018000)
-#define MX50_NIC_BASE_ADDR (MX50_DEBUG_BASE_ADDR + 0x08000000)
-
-/*
- * SPBA global module enabled #0
- */
-#define MX50_SPBA0_BASE_ADDR 0x50000000
-#define MX50_SPBA0_SIZE SZ_1M
-
-#define MX50_MMC_SDHC1_BASE_ADDR (MX50_SPBA0_BASE_ADDR + 0x00004000)
-#define MX50_MMC_SDHC2_BASE_ADDR (MX50_SPBA0_BASE_ADDR + 0x00008000)
-#define MX50_UART3_BASE_ADDR (MX50_SPBA0_BASE_ADDR + 0x0000c000)
-#define MX50_CSPI1_BASE_ADDR (MX50_SPBA0_BASE_ADDR + 0x00010000)
-#define MX50_SSI2_BASE_ADDR (MX50_SPBA0_BASE_ADDR + 0x00014000)
-#define MX50_MMC_SDHC3_BASE_ADDR (MX50_SPBA0_BASE_ADDR + 0x00020000)
-#define MX50_MMC_SDHC4_BASE_ADDR (MX50_SPBA0_BASE_ADDR + 0x00024000)
-
-/*
- * AIPS 1
- */
-#define MX50_AIPS1_BASE_ADDR 0x53f00000
-#define MX50_AIPS1_SIZE SZ_1M
-
-#define MX50_OTG_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x00080000)
-#define MX50_GPIO1_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x00084000)
-#define MX50_GPIO2_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x00088000)
-#define MX50_GPIO3_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x0008c000)
-#define MX50_GPIO4_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x00090000)
-#define MX50_KPP_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x00094000)
-#define MX50_WDOG_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x00098000)
-#define MX50_GPT1_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000a0000)
-#define MX50_SRTC_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000a4000)
-#define MX50_IOMUXC_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000a8000)
-#define MX50_EPIT1_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000ac000)
-#define MX50_PWM1_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000b4000)
-#define MX50_PWM2_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000b8000)
-#define MX50_UART1_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000bc000)
-#define MX50_UART2_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000c0000)
-#define MX50_SRC_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000d0000)
-#define MX50_CCM_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000d4000)
-#define MX50_GPC_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000d8000)
-#define MX50_GPIO5_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000dc000)
-#define MX50_GPIO6_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000e0000)
-#define MX50_I2C3_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000ec000)
-#define MX50_UART4_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000f0000)
-
-#define MX50_MSHC_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000f4000)
-#define MX50_RNGB_BASE_ADDR (MX50_AIPS1_BASE_ADDR + 0x000f8000)
-
-/*
- * AIPS 2
- */
-#define MX50_AIPS2_BASE_ADDR 0x63f00000
-#define MX50_AIPS2_SIZE SZ_1M
-
-#define MX50_PLL1_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x00080000)
-#define MX50_PLL2_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x00084000)
-#define MX50_PLL3_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x00088000)
-#define MX50_UART5_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x00090000)
-#define MX50_AHBMAX_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x00094000)
-#define MX50_ARM_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000a0000)
-#define MX50_OWIRE_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000a4000)
-#define MX50_CSPI2_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000ac000)
-#define MX50_SDMA_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000b0000)
-#define MX50_ROMCP_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000b8000)
-#define MX50_CSPI3_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000c0000)
-#define MX50_I2C2_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000c4000)
-#define MX50_I2C1_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000c8000)
-#define MX50_SSI1_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000cc000)
-#define MX50_AUDMUX_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000d0000)
-#define MX50_WEIM_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000d8000)
-#define MX50_FEC_BASE_ADDR (MX50_AIPS2_BASE_ADDR + 0x000ec000)
-
-/*
- * Memory regions and CS
- */
-#define MX50_CSD0_BASE_ADDR 0x70000000
-#define MX50_CSD1_BASE_ADDR 0xb0000000
-#define MX50_CS0_BASE_ADDR 0xf0000000
-
-#define MX50_IO_P2V(x) IMX_IO_P2V(x)
-#define MX50_IO_ADDRESS(x) IOMEM(MX50_IO_P2V(x))
-
-/*
- * defines for SPBA modules
- */
-#define MX50_SPBA_SDHC1 0x04
-#define MX50_SPBA_SDHC2 0x08
-#define MX50_SPBA_UART3 0x0c
-#define MX50_SPBA_CSPI1 0x10
-#define MX50_SPBA_SSI2 0x14
-#define MX50_SPBA_SDHC3 0x20
-#define MX50_SPBA_SDHC4 0x24
-#define MX50_SPBA_SPDIF 0x28
-#define MX50_SPBA_ATA 0x30
-#define MX50_SPBA_SLIM 0x34
-#define MX50_SPBA_HSI2C 0x38
-#define MX50_SPBA_CTRL 0x3c
-
-/*
- * DMA request assignments
- */
-#define MX50_DMA_REQ_GPC 1
-#define MX50_DMA_REQ_ATA_UART4_RX 2
-#define MX50_DMA_REQ_ATA_UART4_TX 3
-#define MX50_DMA_REQ_CSPI1_RX 6
-#define MX50_DMA_REQ_CSPI1_TX 7
-#define MX50_DMA_REQ_CSPI2_RX 8
-#define MX50_DMA_REQ_CSPI2_TX 9
-#define MX50_DMA_REQ_I2C3_SDHC3 10
-#define MX50_DMA_REQ_SDHC4 11
-#define MX50_DMA_REQ_UART2_FIRI_RX 12
-#define MX50_DMA_REQ_UART2_FIRI_TX 13
-#define MX50_DMA_REQ_EXT0 14
-#define MX50_DMA_REQ_EXT1 15
-#define MX50_DMA_REQ_UART5_RX 16
-#define MX50_DMA_REQ_UART5_TX 17
-#define MX50_DMA_REQ_UART1_RX 18
-#define MX50_DMA_REQ_UART1_TX 19
-#define MX50_DMA_REQ_I2C1_SDHC1 20
-#define MX50_DMA_REQ_I2C2_SDHC2 21
-#define MX50_DMA_REQ_SSI2_RX2 22
-#define MX50_DMA_REQ_SSI2_TX2 23
-#define MX50_DMA_REQ_SSI2_RX1 24
-#define MX50_DMA_REQ_SSI2_TX1 25
-#define MX50_DMA_REQ_SSI1_RX2 26
-#define MX50_DMA_REQ_SSI1_TX2 27
-#define MX50_DMA_REQ_SSI1_RX1 28
-#define MX50_DMA_REQ_SSI1_TX1 29
-#define MX50_DMA_REQ_CSPI_RX 38
-#define MX50_DMA_REQ_CSPI_TX 39
-#define MX50_DMA_REQ_UART3_RX 42
-#define MX50_DMA_REQ_UART3_TX 43
-
-/*
- * Interrupt numbers
- */
-#include <asm/irq.h>
-#define MX50_INT_MMC_SDHC1 (NR_IRQS_LEGACY + 1)
-#define MX50_INT_MMC_SDHC2 (NR_IRQS_LEGACY + 2)
-#define MX50_INT_MMC_SDHC3 (NR_IRQS_LEGACY + 3)
-#define MX50_INT_MMC_SDHC4 (NR_IRQS_LEGACY + 4)
-#define MX50_INT_DAP (NR_IRQS_LEGACY + 5)
-#define MX50_INT_SDMA (NR_IRQS_LEGACY + 6)
-#define MX50_INT_IOMUX (NR_IRQS_LEGACY + 7)
-#define MX50_INT_UART4 (NR_IRQS_LEGACY + 13)
-#define MX50_INT_USB_H1 (NR_IRQS_LEGACY + 14)
-#define MX50_INT_USB_OTG (NR_IRQS_LEGACY + 18)
-#define MX50_INT_DATABAHN (NR_IRQS_LEGACY + 19)
-#define MX50_INT_ELCDIF (NR_IRQS_LEGACY + 20)
-#define MX50_INT_EPXP (NR_IRQS_LEGACY + 21)
-#define MX50_INT_SRTC_NTZ (NR_IRQS_LEGACY + 24)
-#define MX50_INT_SRTC_TZ (NR_IRQS_LEGACY + 25)
-#define MX50_INT_EPDC (NR_IRQS_LEGACY + 27)
-#define MX50_INT_NIC (NR_IRQS_LEGACY + 28)
-#define MX50_INT_SSI1 (NR_IRQS_LEGACY + 29)
-#define MX50_INT_SSI2 (NR_IRQS_LEGACY + 30)
-#define MX50_INT_UART1 (NR_IRQS_LEGACY + 31)
-#define MX50_INT_UART2 (NR_IRQS_LEGACY + 32)
-#define MX50_INT_UART3 (NR_IRQS_LEGACY + 33)
-#define MX50_INT_RESV34 (NR_IRQS_LEGACY + 34)
-#define MX50_INT_RESV35 (NR_IRQS_LEGACY + 35)
-#define MX50_INT_CSPI1 (NR_IRQS_LEGACY + 36)
-#define MX50_INT_CSPI2 (NR_IRQS_LEGACY + 37)
-#define MX50_INT_CSPI (NR_IRQS_LEGACY + 38)
-#define MX50_INT_GPT (NR_IRQS_LEGACY + 39)
-#define MX50_INT_EPIT1 (NR_IRQS_LEGACY + 40)
-#define MX50_INT_GPIO1_INT7 (NR_IRQS_LEGACY + 42)
-#define MX50_INT_GPIO1_INT6 (NR_IRQS_LEGACY + 43)
-#define MX50_INT_GPIO1_INT5 (NR_IRQS_LEGACY + 44)
-#define MX50_INT_GPIO1_INT4 (NR_IRQS_LEGACY + 45)
-#define MX50_INT_GPIO1_INT3 (NR_IRQS_LEGACY + 46)
-#define MX50_INT_GPIO1_INT2 (NR_IRQS_LEGACY + 47)
-#define MX50_INT_GPIO1_INT1 (NR_IRQS_LEGACY + 48)
-#define MX50_INT_GPIO1_INT0 (NR_IRQS_LEGACY + 49)
-#define MX50_INT_GPIO1_LOW (NR_IRQS_LEGACY + 50)
-#define MX50_INT_GPIO1_HIGH (NR_IRQS_LEGACY + 51)
-#define MX50_INT_GPIO2_LOW (NR_IRQS_LEGACY + 52)
-#define MX50_INT_GPIO2_HIGH (NR_IRQS_LEGACY + 53)
-#define MX50_INT_GPIO3_LOW (NR_IRQS_LEGACY + 54)
-#define MX50_INT_GPIO3_HIGH (NR_IRQS_LEGACY + 55)
-#define MX50_INT_GPIO4_LOW (NR_IRQS_LEGACY + 56)
-#define MX50_INT_GPIO4_HIGH (NR_IRQS_LEGACY + 57)
-#define MX50_INT_WDOG1 (NR_IRQS_LEGACY + 58)
-#define MX50_INT_KPP (NR_IRQS_LEGACY + 60)
-#define MX50_INT_PWM1 (NR_IRQS_LEGACY + 61)
-#define MX50_INT_I2C1 (NR_IRQS_LEGACY + 62)
-#define MX50_INT_I2C2 (NR_IRQS_LEGACY + 63)
-#define MX50_INT_I2C3 (NR_IRQS_LEGACY + 64)
-#define MX50_INT_RESV65 (NR_IRQS_LEGACY + 65)
-#define MX50_INT_DCDC (NR_IRQS_LEGACY + 66)
-#define MX50_INT_THERMAL_ALARM (NR_IRQS_LEGACY + 67)
-#define MX50_INT_ANA3 (NR_IRQS_LEGACY + 68)
-#define MX50_INT_ANA4 (NR_IRQS_LEGACY + 69)
-#define MX50_INT_CCM1 (NR_IRQS_LEGACY + 71)
-#define MX50_INT_CCM2 (NR_IRQS_LEGACY + 72)
-#define MX50_INT_GPC1 (NR_IRQS_LEGACY + 73)
-#define MX50_INT_GPC2 (NR_IRQS_LEGACY + 74)
-#define MX50_INT_SRC (NR_IRQS_LEGACY + 75)
-#define MX50_INT_NM (NR_IRQS_LEGACY + 76)
-#define MX50_INT_PMU (NR_IRQS_LEGACY + 77)
-#define MX50_INT_CTI_IRQ (NR_IRQS_LEGACY + 78)
-#define MX50_INT_CTI1_TG0 (NR_IRQS_LEGACY + 79)
-#define MX50_INT_CTI1_TG1 (NR_IRQS_LEGACY + 80)
-#define MX50_INT_GPU2_IRQ (NR_IRQS_LEGACY + 84)
-#define MX50_INT_GPU2_BUSY (NR_IRQS_LEGACY + 85)
-#define MX50_INT_UART5 (NR_IRQS_LEGACY + 86)
-#define MX50_INT_FEC (NR_IRQS_LEGACY + 87)
-#define MX50_INT_OWIRE (NR_IRQS_LEGACY + 88)
-#define MX50_INT_CTI1_TG2 (NR_IRQS_LEGACY + 89)
-#define MX50_INT_SJC (NR_IRQS_LEGACY + 90)
-#define MX50_INT_DCP_CHAN1_3 (NR_IRQS_LEGACY + 91)
-#define MX50_INT_DCP_CHAN0 (NR_IRQS_LEGACY + 92)
-#define MX50_INT_PWM2 (NR_IRQS_LEGACY + 94)
-#define MX50_INT_RNGB (NR_IRQS_LEGACY + 97)
-#define MX50_INT_CTI1_TG3 (NR_IRQS_LEGACY + 98)
-#define MX50_INT_RAWNAND_BCH (NR_IRQS_LEGACY + 100)
-#define MX50_INT_RAWNAND_GPMI (NR_IRQS_LEGACY + 102)
-#define MX50_INT_GPIO5_LOW (NR_IRQS_LEGACY + 103)
-#define MX50_INT_GPIO5_HIGH (NR_IRQS_LEGACY + 104)
-#define MX50_INT_GPIO6_LOW (NR_IRQS_LEGACY + 105)
-#define MX50_INT_GPIO6_HIGH (NR_IRQS_LEGACY + 106)
-#define MX50_INT_MSHC (NR_IRQS_LEGACY + 109)
-#define MX50_INT_APBHDMA_CHAN0 (NR_IRQS_LEGACY + 110)
-#define MX50_INT_APBHDMA_CHAN1 (NR_IRQS_LEGACY + 111)
-#define MX50_INT_APBHDMA_CHAN2 (NR_IRQS_LEGACY + 112)
-#define MX50_INT_APBHDMA_CHAN3 (NR_IRQS_LEGACY + 113)
-#define MX50_INT_APBHDMA_CHAN4 (NR_IRQS_LEGACY + 114)
-#define MX50_INT_APBHDMA_CHAN5 (NR_IRQS_LEGACY + 115)
-#define MX50_INT_APBHDMA_CHAN6 (NR_IRQS_LEGACY + 116)
-#define MX50_INT_APBHDMA_CHAN7 (NR_IRQS_LEGACY + 117)
-
-#if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS)
-extern int mx50_revision(void);
-#endif
-
-#endif /* ifndef __MACH_MX50_H__ */
diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h
index d78298366a91..7dce17a9fe6c 100644
--- a/arch/arm/mach-imx/mxc.h
+++ b/arch/arm/mach-imx/mxc.h
@@ -32,7 +32,6 @@
#define MXC_CPU_MX27 27
#define MXC_CPU_MX31 31
#define MXC_CPU_MX35 35
-#define MXC_CPU_MX50 50
#define MXC_CPU_MX51 51
#define MXC_CPU_MX53 53
@@ -126,18 +125,6 @@ extern unsigned int __mxc_cpu_type;
# define cpu_is_mx35() (0)
#endif
-#ifdef CONFIG_SOC_IMX50
-# ifdef mxc_cpu_type
-# undef mxc_cpu_type
-# define mxc_cpu_type __mxc_cpu_type
-# else
-# define mxc_cpu_type MXC_CPU_MX50
-# endif
-# define cpu_is_mx50() (mxc_cpu_type == MXC_CPU_MX50)
-#else
-# define cpu_is_mx50() (0)
-#endif
-
#ifdef CONFIG_SOC_IMX51
# ifdef mxc_cpu_type
# undef mxc_cpu_type
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index 66fae885c842..7c0b03f67b05 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -12,14 +12,16 @@
#include <linux/init.h>
#include <linux/smp.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/page.h>
#include <asm/smp_scu.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
#include "common.h"
#include "hardware.h"
+#define SCU_STANDBY_ENABLE (1 << 5)
+
static void __iomem *scu_base;
static struct map_desc scu_io_desc __initdata = {
@@ -42,6 +44,14 @@ void __init imx_scu_map_io(void)
scu_base = IMX_IO_ADDRESS(base);
}
+void imx_scu_standby_enable(void)
+{
+ u32 val = readl_relaxed(scu_base);
+
+ val |= SCU_STANDBY_ENABLE;
+ writel_relaxed(val, scu_base);
+}
+
static void __cpuinit imx_secondary_init(unsigned int cpu)
{
/*
@@ -71,8 +81,6 @@ static void __init imx_smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
void imx_smp_prepare(void)
diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c
index 2e063c2deb9e..f67fd7ee8127 100644
--- a/arch/arm/mach-imx/pm-imx5.c
+++ b/arch/arm/mach-imx/pm-imx5.c
@@ -34,7 +34,7 @@
/*
* set cpu low power mode before WFI instruction. This function is called
- * mx5 because it can be used for mx50, mx51, and mx53.
+ * mx5 because it can be used for mx51, and mx53.
*/
static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
{
@@ -85,10 +85,7 @@ static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
__raw_writel(plat_lpc, MXC_CORTEXA8_PLAT_LPC);
__raw_writel(ccm_clpcr, MXC_CCM_CLPCR);
__raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR);
-
- /* Enable NEON SRPG for all but MX50TO1.0. */
- if (mx50_revision() != IMX_CHIP_REVISION_1_0)
- __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR);
+ __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR);
if (stop_mode) {
empgc0 |= MXC_SRPGCR_PCR;
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index f017302f6d09..fea91313678b 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -152,7 +152,8 @@ static int v2_set_next_event(unsigned long evt,
__raw_writel(tcmp, timer_base + V2_TCMP);
- return (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
+ return evt < 0x7fffffff &&
+ (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
-ETIME : 0;
}
@@ -256,7 +257,6 @@ static struct irqaction mxc_timer_irq = {
static struct clock_event_device clockevent_mxc = {
.name = "mxc_timer1",
.features = CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.set_mode = mxc_set_mode,
.set_next_event = mx1_2_set_next_event,
.rating = 200,
@@ -264,21 +264,13 @@ static struct clock_event_device clockevent_mxc = {
static int __init mxc_clockevent_init(struct clk *timer_clk)
{
- unsigned int c = clk_get_rate(timer_clk);
-
if (timer_is_v2())
clockevent_mxc.set_next_event = v2_set_next_event;
- clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
- clockevent_mxc.shift);
- clockevent_mxc.max_delta_ns =
- clockevent_delta2ns(0xfffffffe, &clockevent_mxc);
- clockevent_mxc.min_delta_ns =
- clockevent_delta2ns(0xff, &clockevent_mxc);
-
clockevent_mxc.cpumask = cpumask_of(0);
-
- clockevents_register_device(&clockevent_mxc);
+ clockevents_config_and_register(&clockevent_mxc,
+ clk_get_rate(timer_clk),
+ 0xff, 0xfffffffe);
return 0;
}
diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h
index 79197d8b34aa..72516658be1e 100644
--- a/arch/arm/mach-integrator/common.h
+++ b/arch/arm/mach-integrator/common.h
@@ -1,10 +1,5 @@
#include <linux/amba/serial.h>
-#ifdef CONFIG_ARCH_INTEGRATOR_AP
extern struct amba_pl010_data ap_uart_data;
-#else
-/* Not used without Integrator/AP support anyway */
-struct amba_pl010_data ap_uart_data {};
-#endif
void integrator_init_early(void);
int integrator_init(bool is_cp);
void integrator_reserve(void);
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 39c060f75e47..81461d218717 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -71,7 +71,7 @@ int __init integrator_init(bool is_cp)
* hard-code them. The Integator/CP and forward have proper cell IDs.
* Else we leave them undefined to the bus driver can autoprobe them.
*/
- if (!is_cp) {
+ if (!is_cp && IS_ENABLED(CONFIG_ARCH_INTEGRATOR_AP)) {
rtc_device.periphid = 0x00041030;
uart0_device.periphid = 0x00041010;
uart1_device.periphid = 0x00041010;
diff --git a/arch/arm/mach-integrator/include/mach/uncompress.h b/arch/arm/mach-integrator/include/mach/uncompress.h
index 30452f00a164..8f3cc9954c16 100644
--- a/arch/arm/mach-integrator/include/mach/uncompress.h
+++ b/arch/arm/mach-integrator/include/mach/uncompress.h
@@ -46,5 +46,3 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 11e2a4145807..ea961445e0e9 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -94,7 +94,7 @@ void __iomem *ap_syscon_base;
* f1b00000 1b000000 GPIO
*/
-static struct map_desc ap_io_desc[] __initdata = {
+static struct map_desc ap_io_desc[] __initdata __maybe_unused = {
{
.virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE),
.pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE),
@@ -425,7 +425,7 @@ void __init ap_init_early(void)
#ifdef CONFIG_OF
-static void __init ap_init_timer_of(void)
+static void __init ap_of_timer_init(void)
{
struct device_node *node;
const char *path;
@@ -464,10 +464,6 @@ static void __init ap_init_timer_of(void)
integrator_clockevent_init(rate, base, irq);
}
-static struct sys_timer ap_of_timer = {
- .init = ap_init_timer_of,
-};
-
static const struct of_device_id fpga_irq_of_match[] __initconst = {
{ .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, },
{ /* Sentinel */ }
@@ -586,7 +582,7 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
.init_early = ap_init_early,
.init_irq = ap_init_irq_of,
.handle_irq = fpga_handle_irq,
- .timer = &ap_of_timer,
+ .init_time = ap_of_timer_init,
.init_machine = ap_init_of,
.restart = integrator_restart,
.dt_compat = ap_dt_board_compat,
@@ -613,7 +609,6 @@ static struct map_desc ap_io_desc_atag[] __initdata = {
static void __init ap_map_io_atag(void)
{
iotable_init(ap_io_desc_atag, ARRAY_SIZE(ap_io_desc_atag));
- ap_syscon_base = __io_address(INTEGRATOR_SC_BASE);
ap_map_io();
}
@@ -638,7 +633,7 @@ static struct platform_device cfi_flash_device = {
.resource = &cfi_flash_resource,
};
-static void __init ap_init_timer(void)
+static void __init ap_timer_init(void)
{
struct clk *clk;
unsigned long rate;
@@ -657,10 +652,6 @@ static void __init ap_init_timer(void)
IRQ_TIMERINT1);
}
-static struct sys_timer ap_timer = {
- .init = ap_init_timer,
-};
-
#define INTEGRATOR_SC_VALID_INT 0x003fffff
static void __init ap_init_irq(void)
@@ -685,6 +676,7 @@ static void __init ap_init(void)
platform_device_register(&cfi_flash_device);
+ ap_syscon_base = __io_address(INTEGRATOR_SC_BASE);
sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET);
for (i = 0; i < 4; i++) {
struct lm_device *lmdev;
@@ -716,7 +708,7 @@ MACHINE_START(INTEGRATOR, "ARM-Integrator")
.init_early = ap_init_early,
.init_irq = ap_init_irq,
.handle_irq = fpga_handle_irq,
- .timer = &ap_timer,
+ .init_time = ap_timer_init,
.init_machine = ap_init,
.restart = integrator_restart,
MACHINE_END
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 7322838c0447..2b0db82a5381 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -78,7 +78,7 @@ static void __iomem *intcp_con_base;
* fcb00000 cb000000 CP system control
*/
-static struct map_desc intcp_io_desc[] __initdata = {
+static struct map_desc intcp_io_desc[] __initdata __maybe_unused = {
{
.virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE),
.pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE),
@@ -251,7 +251,7 @@ static void __init intcp_init_early(void)
#ifdef CONFIG_OF
-static void __init intcp_timer_init_of(void)
+static void __init cp_of_timer_init(void)
{
struct device_node *node;
const char *path;
@@ -283,10 +283,6 @@ static void __init intcp_timer_init_of(void)
sp804_clockevents_init(base, irq, node->name);
}
-static struct sys_timer cp_of_timer = {
- .init = intcp_timer_init_of,
-};
-
static const struct of_device_id fpga_irq_of_match[] __initconst = {
{ .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, },
{ /* Sentinel */ }
@@ -390,7 +386,7 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
.init_early = intcp_init_early,
.init_irq = intcp_init_irq_of,
.handle_irq = fpga_handle_irq,
- .timer = &cp_of_timer,
+ .init_time = cp_of_timer_init,
.init_machine = intcp_init_of,
.restart = integrator_restart,
.dt_compat = intcp_dt_board_compat,
@@ -512,7 +508,7 @@ static void __init intcp_init_irq(void)
#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE)
#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE)
-static void __init intcp_timer_init(void)
+static void __init cp_timer_init(void)
{
writel(0, TIMER0_VA_BASE + TIMER_CTRL);
writel(0, TIMER1_VA_BASE + TIMER_CTRL);
@@ -522,10 +518,6 @@ static void __init intcp_timer_init(void)
sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1, "timer1");
}
-static struct sys_timer cp_timer = {
- .init = intcp_timer_init,
-};
-
#define INTEGRATOR_CP_MMC_IRQS { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 }
#define INTEGRATOR_CP_AACI_IRQS { IRQ_CP_AACIINT }
@@ -565,7 +557,7 @@ MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
.init_early = intcp_init_early,
.init_irq = intcp_init_irq,
.handle_irq = fpga_handle_irq,
- .timer = &cp_timer,
+ .init_time = cp_timer_init,
.init_machine = intcp_init,
.restart = integrator_restart,
MACHINE_END
diff --git a/arch/arm/mach-iop13xx/include/mach/uncompress.h b/arch/arm/mach-iop13xx/include/mach/uncompress.h
index fa4f80522fad..d3791ece2772 100644
--- a/arch/arm/mach-iop13xx/include/mach/uncompress.h
+++ b/arch/arm/mach-iop13xx/include/mach/uncompress.h
@@ -20,4 +20,3 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-iop13xx/iq81340mc.c b/arch/arm/mach-iop13xx/iq81340mc.c
index e3f3e7daa79e..02a8228ac2d3 100644
--- a/arch/arm/mach-iop13xx/iq81340mc.c
+++ b/arch/arm/mach-iop13xx/iq81340mc.c
@@ -84,17 +84,13 @@ static void __init iq81340mc_timer_init(void)
iop_init_time(bus_freq);
}
-static struct sys_timer iq81340mc_timer = {
- .init = iq81340mc_timer_init,
-};
-
MACHINE_START(IQ81340MC, "Intel IQ81340MC")
/* Maintainer: Dan Williams <dan.j.williams@intel.com> */
.atag_offset = 0x100,
.init_early = iop13xx_init_early,
.map_io = iop13xx_map_io,
.init_irq = iop13xx_init_irq,
- .timer = &iq81340mc_timer,
+ .init_time = iq81340mc_timer_init,
.init_machine = iq81340mc_init,
.restart = iop13xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c
index e94744111634..1b80f10722b3 100644
--- a/arch/arm/mach-iop13xx/iq81340sc.c
+++ b/arch/arm/mach-iop13xx/iq81340sc.c
@@ -86,17 +86,13 @@ static void __init iq81340sc_timer_init(void)
iop_init_time(bus_freq);
}
-static struct sys_timer iq81340sc_timer = {
- .init = iq81340sc_timer_init,
-};
-
MACHINE_START(IQ81340SC, "Intel IQ81340SC")
/* Maintainer: Dan Williams <dan.j.williams@intel.com> */
.atag_offset = 0x100,
.init_early = iop13xx_init_early,
.map_io = iop13xx_map_io,
.init_irq = iop13xx_init_irq,
- .timer = &iq81340sc_timer,
+ .init_time = iq81340sc_timer_init,
.init_machine = iq81340sc_init,
.restart = iop13xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c
index 9f369f09c29d..31fbb6c61b25 100644
--- a/arch/arm/mach-iop32x/em7210.c
+++ b/arch/arm/mach-iop32x/em7210.c
@@ -40,10 +40,6 @@ static void __init em7210_timer_init(void)
iop_init_time(200000000);
}
-static struct sys_timer em7210_timer = {
- .init = em7210_timer_init,
-};
-
/*
* EM7210 RTC
*/
@@ -205,7 +201,7 @@ MACHINE_START(EM7210, "Lanner EM7210")
.atag_offset = 0x100,
.map_io = em7210_map_io,
.init_irq = iop32x_init_irq,
- .timer = &em7210_timer,
+ .init_time = em7210_timer_init,
.init_machine = em7210_init_machine,
.restart = iop3xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c
index 02e20c3912ba..ac304705fe68 100644
--- a/arch/arm/mach-iop32x/glantank.c
+++ b/arch/arm/mach-iop32x/glantank.c
@@ -44,10 +44,6 @@ static void __init glantank_timer_init(void)
iop_init_time(200000000);
}
-static struct sys_timer glantank_timer = {
- .init = glantank_timer_init,
-};
-
/*
* GLAN Tank I/O.
@@ -209,7 +205,7 @@ MACHINE_START(GLANTANK, "GLAN Tank")
.atag_offset = 0x100,
.map_io = glantank_map_io,
.init_irq = iop32x_init_irq,
- .timer = &glantank_timer,
+ .init_time = glantank_timer_init,
.init_machine = glantank_init_machine,
.restart = iop3xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-iop32x/include/mach/uncompress.h b/arch/arm/mach-iop32x/include/mach/uncompress.h
index 4fd715496f45..b3d45fd365e7 100644
--- a/arch/arm/mach-iop32x/include/mach/uncompress.h
+++ b/arch/arm/mach-iop32x/include/mach/uncompress.h
@@ -36,4 +36,3 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
* nothing to do
*/
#define arch_decomp_setup() __arch_decomp_setup(arch_id)
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c
index ddd1c7ecfe57..f2cd2966212d 100644
--- a/arch/arm/mach-iop32x/iq31244.c
+++ b/arch/arm/mach-iop32x/iq31244.c
@@ -75,10 +75,6 @@ static void __init iq31244_timer_init(void)
}
}
-static struct sys_timer iq31244_timer = {
- .init = iq31244_timer_init,
-};
-
/*
* IQ31244 I/O.
@@ -314,7 +310,7 @@ MACHINE_START(IQ31244, "Intel IQ31244")
.atag_offset = 0x100,
.map_io = iq31244_map_io,
.init_irq = iop32x_init_irq,
- .timer = &iq31244_timer,
+ .init_time = iq31244_timer_init,
.init_machine = iq31244_init_machine,
.restart = iop3xx_restart,
MACHINE_END
@@ -329,7 +325,7 @@ MACHINE_START(EP80219, "Intel EP80219")
.atag_offset = 0x100,
.map_io = iq31244_map_io,
.init_irq = iop32x_init_irq,
- .timer = &iq31244_timer,
+ .init_time = iq31244_timer_init,
.init_machine = iq31244_init_machine,
.restart = iop3xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c
index bf155e6a3b45..015435de90dd 100644
--- a/arch/arm/mach-iop32x/iq80321.c
+++ b/arch/arm/mach-iop32x/iq80321.c
@@ -43,10 +43,6 @@ static void __init iq80321_timer_init(void)
iop_init_time(200000000);
}
-static struct sys_timer iq80321_timer = {
- .init = iq80321_timer_init,
-};
-
/*
* IQ80321 I/O.
@@ -188,7 +184,7 @@ MACHINE_START(IQ80321, "Intel IQ80321")
.atag_offset = 0x100,
.map_io = iq80321_map_io,
.init_irq = iop32x_init_irq,
- .timer = &iq80321_timer,
+ .init_time = iq80321_timer_init,
.init_machine = iq80321_init_machine,
.restart = iop3xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c
index 5a7ae91e8849..ea0984a7449e 100644
--- a/arch/arm/mach-iop32x/n2100.c
+++ b/arch/arm/mach-iop32x/n2100.c
@@ -50,10 +50,6 @@ static void __init n2100_timer_init(void)
iop_init_time(198000000);
}
-static struct sys_timer n2100_timer = {
- .init = n2100_timer_init,
-};
-
/*
* N2100 I/O.
@@ -337,7 +333,7 @@ MACHINE_START(N2100, "Thecus N2100")
.atag_offset = 0x100,
.map_io = n2100_map_io,
.init_irq = iop32x_init_irq,
- .timer = &n2100_timer,
+ .init_time = n2100_timer_init,
.init_machine = n2100_init_machine,
.restart = n2100_restart,
MACHINE_END
diff --git a/arch/arm/mach-iop33x/include/mach/uncompress.h b/arch/arm/mach-iop33x/include/mach/uncompress.h
index f99bb848c5a1..ed282e14176d 100644
--- a/arch/arm/mach-iop33x/include/mach/uncompress.h
+++ b/arch/arm/mach-iop33x/include/mach/uncompress.h
@@ -34,4 +34,3 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
* nothing to do
*/
#define arch_decomp_setup() __arch_decomp_setup(arch_id)
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-iop33x/iq80331.c b/arch/arm/mach-iop33x/iq80331.c
index e74a7debe793..c43304a10fa7 100644
--- a/arch/arm/mach-iop33x/iq80331.c
+++ b/arch/arm/mach-iop33x/iq80331.c
@@ -45,10 +45,6 @@ static void __init iq80331_timer_init(void)
iop_init_time(266000000);
}
-static struct sys_timer iq80331_timer = {
- .init = iq80331_timer_init,
-};
-
/*
* IQ80331 PCI.
@@ -143,7 +139,7 @@ MACHINE_START(IQ80331, "Intel IQ80331")
.atag_offset = 0x100,
.map_io = iop3xx_map_io,
.init_irq = iop33x_init_irq,
- .timer = &iq80331_timer,
+ .init_time = iq80331_timer_init,
.init_machine = iq80331_init_machine,
.restart = iop3xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-iop33x/iq80332.c b/arch/arm/mach-iop33x/iq80332.c
index e2f5beece6e8..8192987e78e5 100644
--- a/arch/arm/mach-iop33x/iq80332.c
+++ b/arch/arm/mach-iop33x/iq80332.c
@@ -45,10 +45,6 @@ static void __init iq80332_timer_init(void)
iop_init_time(266000000);
}
-static struct sys_timer iq80332_timer = {
- .init = iq80332_timer_init,
-};
-
/*
* IQ80332 PCI.
@@ -143,7 +139,7 @@ MACHINE_START(IQ80332, "Intel IQ80332")
.atag_offset = 0x100,
.map_io = iop3xx_map_io,
.init_irq = iop33x_init_irq,
- .timer = &iq80332_timer,
+ .init_time = iq80332_timer_init,
.init_machine = iq80332_init_machine,
.restart = iop3xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-ixp4xx/avila-setup.c b/arch/arm/mach-ixp4xx/avila-setup.c
index 90e42e9982cb..6beec150c060 100644
--- a/arch/arm/mach-ixp4xx/avila-setup.c
+++ b/arch/arm/mach-ixp4xx/avila-setup.c
@@ -167,7 +167,7 @@ MACHINE_START(AVILA, "Gateworks Avila Network Platform")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = avila_init,
#if defined(CONFIG_PCI)
@@ -187,7 +187,7 @@ MACHINE_START(LOFT, "Giant Shoulder Inc Loft board")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = avila_init,
#if defined(CONFIG_PCI)
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 8c0c0e2d0727..1dbeb7c99d58 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -307,10 +307,6 @@ void __init ixp4xx_timer_init(void)
ixp4xx_clockevent_init();
}
-struct sys_timer ixp4xx_timer = {
- .init = ixp4xx_timer_init,
-};
-
static struct pxa2xx_udc_mach_info ixp4xx_udc_info;
void __init ixp4xx_set_udc_info(struct pxa2xx_udc_mach_info *info)
@@ -523,22 +519,15 @@ static struct clock_event_device clockevent_ixp4xx = {
.name = "ixp4xx timer1",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.rating = 200,
- .shift = 24,
.set_mode = ixp4xx_set_mode,
.set_next_event = ixp4xx_set_next_event,
};
static void __init ixp4xx_clockevent_init(void)
{
- clockevent_ixp4xx.mult = div_sc(IXP4XX_TIMER_FREQ, NSEC_PER_SEC,
- clockevent_ixp4xx.shift);
- clockevent_ixp4xx.max_delta_ns =
- clockevent_delta2ns(0xfffffffe, &clockevent_ixp4xx);
- clockevent_ixp4xx.min_delta_ns =
- clockevent_delta2ns(0xf, &clockevent_ixp4xx);
clockevent_ixp4xx.cpumask = cpumask_of(0);
-
- clockevents_register_device(&clockevent_ixp4xx);
+ clockevents_config_and_register(&clockevent_ixp4xx, IXP4XX_TIMER_FREQ,
+ 0xf, 0xfffffffe);
}
void ixp4xx_restart(char mode, const char *cmd)
diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c
index 1b83110028d6..820cae8608fc 100644
--- a/arch/arm/mach-ixp4xx/coyote-setup.c
+++ b/arch/arm/mach-ixp4xx/coyote-setup.c
@@ -112,7 +112,7 @@ MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = coyote_init,
#if defined(CONFIG_PCI)
@@ -132,7 +132,7 @@ MACHINE_START(IXDPG425, "Intel IXDPG425")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = coyote_init,
.restart = ixp4xx_restart,
diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c
index 97a0af8f1955..5d413f8c5700 100644
--- a/arch/arm/mach-ixp4xx/dsmg600-setup.c
+++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c
@@ -226,10 +226,6 @@ static void __init dsmg600_timer_init(void)
ixp4xx_timer_init();
}
-static struct sys_timer dsmg600_timer = {
- .init = dsmg600_timer_init,
-};
-
static void __init dsmg600_init(void)
{
ixp4xx_sys_init();
@@ -282,7 +278,7 @@ MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &dsmg600_timer,
+ .init_time = dsmg600_timer_init,
.init_machine = dsmg600_init,
#if defined(CONFIG_PCI)
.dma_zone_size = SZ_64M,
diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c
index 9175a25a7511..429966b756ed 100644
--- a/arch/arm/mach-ixp4xx/fsg-setup.c
+++ b/arch/arm/mach-ixp4xx/fsg-setup.c
@@ -272,7 +272,7 @@ MACHINE_START(FSG, "Freecom FSG-3")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = fsg_init,
#if defined(CONFIG_PCI)
diff --git a/arch/arm/mach-ixp4xx/gateway7001-setup.c b/arch/arm/mach-ixp4xx/gateway7001-setup.c
index 033c71758953..3d24b3fcee87 100644
--- a/arch/arm/mach-ixp4xx/gateway7001-setup.c
+++ b/arch/arm/mach-ixp4xx/gateway7001-setup.c
@@ -99,7 +99,7 @@ MACHINE_START(GATEWAY7001, "Gateway 7001 AP")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = gateway7001_init,
#if defined(CONFIG_PCI)
diff --git a/arch/arm/mach-ixp4xx/goramo_mlr.c b/arch/arm/mach-ixp4xx/goramo_mlr.c
index 53b8348dfcc2..e54ff491c105 100644
--- a/arch/arm/mach-ixp4xx/goramo_mlr.c
+++ b/arch/arm/mach-ixp4xx/goramo_mlr.c
@@ -498,7 +498,7 @@ MACHINE_START(GORAMO_MLR, "MultiLink")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = gmlr_init,
#if defined(CONFIG_PCI)
diff --git a/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
index 18ebc6be7969..16a12994fb53 100644
--- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c
+++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
@@ -167,7 +167,7 @@ MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = gtwx5715_init,
#if defined(CONFIG_PCI)
diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h
index 5bce94aacca9..db5afb69c123 100644
--- a/arch/arm/mach-ixp4xx/include/mach/platform.h
+++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
@@ -89,8 +89,6 @@ struct ixp4xx_pata_data {
void __iomem *cs1;
};
-struct sys_timer;
-
#define IXP4XX_ETH_NPEA 0x00
#define IXP4XX_ETH_NPEB 0x10
#define IXP4XX_ETH_NPEC 0x20
@@ -125,7 +123,6 @@ extern void ixp4xx_init_early(void);
extern void ixp4xx_init_irq(void);
extern void ixp4xx_sys_init(void);
extern void ixp4xx_timer_init(void);
-extern struct sys_timer ixp4xx_timer;
extern void ixp4xx_restart(char, const char *);
extern void ixp4xx_pci_preinit(void);
struct pci_sys_data;
diff --git a/arch/arm/mach-ixp4xx/include/mach/uncompress.h b/arch/arm/mach-ixp4xx/include/mach/uncompress.h
index eb945a926d07..7b25c0225e46 100644
--- a/arch/arm/mach-ixp4xx/include/mach/uncompress.h
+++ b/arch/arm/mach-ixp4xx/include/mach/uncompress.h
@@ -53,6 +53,4 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
*/
#define arch_decomp_setup() __arch_decomp_setup(arch_id)
-#define arch_decomp_wdog()
-
#endif
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index 108a9d3f382d..22d688b7d513 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -252,7 +252,7 @@ MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = ixdp425_init,
#if defined(CONFIG_PCI)
@@ -268,7 +268,7 @@ MACHINE_START(IXDP465, "Intel IXDP465 Development Platform")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = ixdp425_init,
#if defined(CONFIG_PCI)
@@ -283,7 +283,7 @@ MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = ixdp425_init,
#if defined(CONFIG_PCI)
@@ -298,7 +298,7 @@ MACHINE_START(KIXRP435, "Intel KIXRP435 Reference Platform")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = ixdp425_init,
#if defined(CONFIG_PCI)
diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
index 33cb0955b6bf..ed667ce9f576 100644
--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
+++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
@@ -317,7 +317,7 @@ MACHINE_START(NAS100D, "Iomega NAS 100d")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.init_machine = nas100d_init,
#if defined(CONFIG_PCI)
.dma_zone_size = SZ_64M,
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
index e2903faaebb3..7e55236c26ea 100644
--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -232,10 +232,6 @@ static void __init nslu2_timer_init(void)
ixp4xx_timer_init();
}
-static struct sys_timer nslu2_timer = {
- .init = nslu2_timer_init,
-};
-
static void __init nslu2_init(void)
{
uint8_t __iomem *f;
@@ -303,7 +299,7 @@ MACHINE_START(NSLU2, "Linksys NSLU2")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &nslu2_timer,
+ .init_time = nslu2_timer_init,
.init_machine = nslu2_init,
#if defined(CONFIG_PCI)
.dma_zone_size = SZ_64M,
diff --git a/arch/arm/mach-ixp4xx/omixp-setup.c b/arch/arm/mach-ixp4xx/omixp-setup.c
index 158ddb79821d..46a89f5e8269 100644
--- a/arch/arm/mach-ixp4xx/omixp-setup.c
+++ b/arch/arm/mach-ixp4xx/omixp-setup.c
@@ -245,7 +245,7 @@ MACHINE_START(DEVIXP, "Omicron DEVIXP")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.init_machine = omixp_init,
.restart = ixp4xx_restart,
MACHINE_END
@@ -257,7 +257,7 @@ MACHINE_START(MICCPT, "Omicron MICCPT")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.init_machine = omixp_init,
#if defined(CONFIG_PCI)
.dma_zone_size = SZ_64M,
@@ -272,7 +272,7 @@ MACHINE_START(MIC256, "Omicron MIC256")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.init_machine = omixp_init,
.restart = ixp4xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-ixp4xx/vulcan-setup.c b/arch/arm/mach-ixp4xx/vulcan-setup.c
index 2798f435aaf4..d42730a1d4ab 100644
--- a/arch/arm/mach-ixp4xx/vulcan-setup.c
+++ b/arch/arm/mach-ixp4xx/vulcan-setup.c
@@ -239,7 +239,7 @@ MACHINE_START(ARCOM_VULCAN, "Arcom/Eurotech Vulcan")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = vulcan_init,
#if defined(CONFIG_PCI)
diff --git a/arch/arm/mach-ixp4xx/wg302v2-setup.c b/arch/arm/mach-ixp4xx/wg302v2-setup.c
index a785175b115b..8f9ea2f3a9a5 100644
--- a/arch/arm/mach-ixp4xx/wg302v2-setup.c
+++ b/arch/arm/mach-ixp4xx/wg302v2-setup.c
@@ -100,7 +100,7 @@ MACHINE_START(WG302V2, "Netgear WG302 v2 / WAG302 v2")
.map_io = ixp4xx_map_io,
.init_early = ixp4xx_init_early,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .init_time = ixp4xx_timer_init,
.atag_offset = 0x100,
.init_machine = wg302v2_init,
#if defined(CONFIG_PCI)
diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile
index 8d2e5a96247c..d6653095a1eb 100644
--- a/arch/arm/mach-kirkwood/Makefile
+++ b/arch/arm/mach-kirkwood/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_MACH_NET2BIG_V2) += netxbig_v2-setup.o lacie_v2-common.o
obj-$(CONFIG_MACH_NET5BIG_V2) += netxbig_v2-setup.o lacie_v2-common.o
obj-$(CONFIG_MACH_T5325) += t5325-setup.o
-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_ARCH_KIRKWOOD_DT) += board-dt.o
obj-$(CONFIG_MACH_DREAMPLUG_DT) += board-dreamplug.o
obj-$(CONFIG_MACH_ICONNECT_DT) += board-iconnect.o
diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c
index de4fd2bb1e27..95cc04d14b65 100644
--- a/arch/arm/mach-kirkwood/board-dt.c
+++ b/arch/arm/mach-kirkwood/board-dt.c
@@ -98,6 +98,8 @@ static void __init kirkwood_dt_init(void)
/* Setup root of clk tree */
kirkwood_of_clk_init();
+ kirkwood_cpuidle_init();
+
#ifdef CONFIG_KEXEC
kexec_reinit = kirkwood_enable_pcie;
#endif
@@ -183,7 +185,7 @@ DT_MACHINE_START(KIRKWOOD_DT, "Marvell Kirkwood (Flattened Device Tree)")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = orion_dt_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.init_machine = kirkwood_dt_init,
.restart = kirkwood_restart,
.dt_compat = kirkwood_dt_board_compat,
diff --git a/arch/arm/mach-kirkwood/board-ib62x0.c b/arch/arm/mach-kirkwood/board-ib62x0.c
index 9f6f496380d8..9a857ae83984 100644
--- a/arch/arm/mach-kirkwood/board-ib62x0.c
+++ b/arch/arm/mach-kirkwood/board-ib62x0.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mv643xx_eth.h>
-#include <linux/input.h>
#include "common.h"
static struct mv643xx_eth_platform_data ib62x0_ge00_data = {
diff --git a/arch/arm/mach-kirkwood/board-mplcec4.c b/arch/arm/mach-kirkwood/board-mplcec4.c
index 56bfe5a1605a..3264925b8318 100644
--- a/arch/arm/mach-kirkwood/board-mplcec4.c
+++ b/arch/arm/mach-kirkwood/board-mplcec4.c
@@ -14,7 +14,6 @@
#include <linux/mv643xx_eth.h>
#include <linux/platform_data/mmc-mvsdio.h>
#include "common.h"
-#include "mpp.h"
static struct mv643xx_eth_platform_data mplcec4_ge00_data = {
.phy_addr = MV643XX_ETH_PHY_ADDR(1),
diff --git a/arch/arm/mach-kirkwood/board-nsa310.c b/arch/arm/mach-kirkwood/board-nsa310.c
index f58d2e1a4042..970174ad4a70 100644
--- a/arch/arm/mach-kirkwood/board-nsa310.c
+++ b/arch/arm/mach-kirkwood/board-nsa310.c
@@ -10,12 +10,10 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/i2c.h>
#include <linux/gpio.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
+#include <linux/i2c.h>
#include <mach/kirkwood.h>
+#include <linux/of.h>
#include "common.h"
#include "mpp.h"
@@ -79,14 +77,10 @@ static void __init nsa310_gpio_init(void)
void __init nsa310_init(void)
{
- u32 dev, rev;
-
kirkwood_mpp_conf(nsa310_mpp_config);
nsa310_gpio_init();
- kirkwood_pcie_id(&dev, &rev);
-
i2c_register_board_info(0, ARRAY_AND_SIZE(nsa310_i2c_info));
}
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index bac21a554c91..49792a0cd2d3 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -499,6 +499,28 @@ void __init kirkwood_wdt_init(void)
orion_wdt_init();
}
+/*****************************************************************************
+ * CPU idle
+ ****************************************************************************/
+static struct resource kirkwood_cpuidle_resource[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ .start = DDR_OPERATION_BASE,
+ .end = DDR_OPERATION_BASE + 3,
+ },
+};
+
+static struct platform_device kirkwood_cpuidle = {
+ .name = "kirkwood_cpuidle",
+ .id = -1,
+ .resource = kirkwood_cpuidle_resource,
+ .num_resources = 1,
+};
+
+void __init kirkwood_cpuidle_init(void)
+{
+ platform_device_register(&kirkwood_cpuidle);
+}
/*****************************************************************************
* Time handling
@@ -530,7 +552,7 @@ static int __init kirkwood_find_tclk(void)
return 166666667;
}
-static void __init kirkwood_timer_init(void)
+void __init kirkwood_timer_init(void)
{
kirkwood_tclk = kirkwood_find_tclk();
@@ -538,10 +560,6 @@ static void __init kirkwood_timer_init(void)
IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
}
-struct sys_timer kirkwood_timer = {
- .init = kirkwood_timer_init,
-};
-
/*****************************************************************************
* Audio
****************************************************************************/
@@ -671,6 +689,7 @@ void __init kirkwood_init(void)
kirkwood_xor1_init();
kirkwood_crypto_init();
+ kirkwood_cpuidle_init();
#ifdef CONFIG_KEXEC
kexec_reinit = kirkwood_enable_pcie;
#endif
diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
index 5ffa57f08c80..e956d0277dd1 100644
--- a/arch/arm/mach-kirkwood/common.h
+++ b/arch/arm/mach-kirkwood/common.h
@@ -50,6 +50,7 @@ void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
void kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts,
int (*dev_ready)(struct mtd_info *));
void kirkwood_audio_init(void);
+void kirkwood_cpuidle_init(void);
void kirkwood_restart(char, const char *);
void kirkwood_clk_init(void);
@@ -156,7 +157,7 @@ void kirkwood_xor1_init(void);
void kirkwood_crypto_init(void);
extern int kirkwood_tclk;
-extern struct sys_timer kirkwood_timer;
+extern void kirkwood_timer_init(void);
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
diff --git a/arch/arm/mach-kirkwood/d2net_v2-setup.c b/arch/arm/mach-kirkwood/d2net_v2-setup.c
index 2c1a453df201..453418063c1e 100644
--- a/arch/arm/mach-kirkwood/d2net_v2-setup.c
+++ b/arch/arm/mach-kirkwood/d2net_v2-setup.c
@@ -226,6 +226,6 @@ MACHINE_START(D2NET_V2, "LaCie d2 Network v2")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
index c49b177c1523..5a369fe74754 100644
--- a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
+++ b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
@@ -103,6 +103,6 @@ MACHINE_START(DB88F6281_BP, "Marvell DB-88F6281-BP Development Board")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/dockstar-setup.c b/arch/arm/mach-kirkwood/dockstar-setup.c
index 791a98fafa29..060ccf9cb63f 100644
--- a/arch/arm/mach-kirkwood/dockstar-setup.c
+++ b/arch/arm/mach-kirkwood/dockstar-setup.c
@@ -19,7 +19,6 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/kirkwood.h>
-#include <linux/platform_data/mmc-mvsdio.h>
#include "common.h"
#include "mpp.h"
@@ -107,6 +106,6 @@ MACHINE_START(DOCKSTAR, "Seagate FreeAgent DockStar")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/guruplug-setup.c b/arch/arm/mach-kirkwood/guruplug-setup.c
index 7cb55f982243..1c6e736cbbf8 100644
--- a/arch/arm/mach-kirkwood/guruplug-setup.c
+++ b/arch/arm/mach-kirkwood/guruplug-setup.c
@@ -126,6 +126,6 @@ MACHINE_START(GURUPLUG, "Marvell GuruPlug Reference Board")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
index 041653a04a9c..a05563a31c95 100644
--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
@@ -60,8 +60,9 @@
* Register Map
*/
#define DDR_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE + 0x00000)
+#define DDR_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE + 0x00000)
#define DDR_WINDOW_CPU_BASE (DDR_VIRT_BASE + 0x1500)
-#define DDR_OPERATION_BASE (DDR_VIRT_BASE + 0x1418)
+#define DDR_OPERATION_BASE (DDR_PHYS_BASE + 0x1418)
#define DEV_BUS_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE + 0x10000)
#define DEV_BUS_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE + 0x10000)
diff --git a/arch/arm/mach-kirkwood/include/mach/uncompress.h b/arch/arm/mach-kirkwood/include/mach/uncompress.h
index 75d5497df3a8..5bca5534021f 100644
--- a/arch/arm/mach-kirkwood/include/mach/uncompress.h
+++ b/arch/arm/mach-kirkwood/include/mach/uncompress.h
@@ -44,4 +44,3 @@ static void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
index 6d8364a97810..ba384b992bef 100644
--- a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
+++ b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
@@ -167,6 +167,6 @@ MACHINE_START(MV88F6281GTW_GE, "Marvell 88F6281 GTW GE Board")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/netspace_v2-setup.c b/arch/arm/mach-kirkwood/netspace_v2-setup.c
index 728e86d33f0c..3b706611da8e 100644
--- a/arch/arm/mach-kirkwood/netspace_v2-setup.c
+++ b/arch/arm/mach-kirkwood/netspace_v2-setup.c
@@ -263,7 +263,7 @@ MACHINE_START(NETSPACE_V2, "LaCie Network Space v2")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
#endif
@@ -275,7 +275,7 @@ MACHINE_START(INETSPACE_V2, "LaCie Internet Space v2")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
#endif
@@ -287,7 +287,7 @@ MACHINE_START(NETSPACE_MAX_V2, "LaCie Network Space Max v2")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
#endif
diff --git a/arch/arm/mach-kirkwood/netxbig_v2-setup.c b/arch/arm/mach-kirkwood/netxbig_v2-setup.c
index a3b091470b8a..913d032cdb19 100644
--- a/arch/arm/mach-kirkwood/netxbig_v2-setup.c
+++ b/arch/arm/mach-kirkwood/netxbig_v2-setup.c
@@ -404,7 +404,7 @@ MACHINE_START(NET2BIG_V2, "LaCie 2Big Network v2")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
#endif
@@ -416,7 +416,7 @@ MACHINE_START(NET5BIG_V2, "LaCie 5Big Network v2")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
#endif
diff --git a/arch/arm/mach-kirkwood/openrd-setup.c b/arch/arm/mach-kirkwood/openrd-setup.c
index 7e81e9b586bf..8ddd69fdc937 100644
--- a/arch/arm/mach-kirkwood/openrd-setup.c
+++ b/arch/arm/mach-kirkwood/openrd-setup.c
@@ -221,7 +221,7 @@ MACHINE_START(OPENRD_BASE, "Marvell OpenRD Base Board")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
#endif
@@ -234,7 +234,7 @@ MACHINE_START(OPENRD_CLIENT, "Marvell OpenRD Client Board")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
#endif
@@ -247,7 +247,7 @@ MACHINE_START(OPENRD_ULTIMATE, "Marvell OpenRD Ultimate Board")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
#endif
diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c
index a1c3ab6fc809..d96ad4c09972 100644
--- a/arch/arm/mach-kirkwood/pcie.c
+++ b/arch/arm/mach-kirkwood/pcie.c
@@ -247,13 +247,9 @@ static struct hw_pci kirkwood_pci __initdata = {
static void __init add_pcie_port(int index, void __iomem *base)
{
- pr_info("Kirkwood PCIe port %d: ", index);
-
- if (orion_pcie_link_up(base)) {
- pr_info("link up\n");
- pcie_port_map[num_pcie_ports++] = index;
- } else
- pr_info("link down, ignoring\n");
+ pcie_port_map[num_pcie_ports++] = index;
+ pr_info("Kirkwood PCIe port %d: link %s\n", index,
+ orion_pcie_link_up(base) ? "up" : "down");
}
void __init kirkwood_pcie_init(unsigned int portmask)
diff --git a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
index 19072c84008f..e4fd3129d36f 100644
--- a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
@@ -84,6 +84,6 @@ MACHINE_START(RD88F6192_NAS, "Marvell RD-88F6192-NAS Development Board")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/rd88f6281-setup.c b/arch/arm/mach-kirkwood/rd88f6281-setup.c
index 9717101a7437..c7d93b48926b 100644
--- a/arch/arm/mach-kirkwood/rd88f6281-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c
@@ -120,6 +120,6 @@ MACHINE_START(RD88F6281, "Marvell RD-88F6281 Reference Board")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/sheevaplug-setup.c b/arch/arm/mach-kirkwood/sheevaplug-setup.c
index 8a175948b28d..55b68fa39f45 100644
--- a/arch/arm/mach-kirkwood/sheevaplug-setup.c
+++ b/arch/arm/mach-kirkwood/sheevaplug-setup.c
@@ -143,7 +143,7 @@ MACHINE_START(SHEEVAPLUG, "Marvell SheevaPlug Reference Board")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
#endif
@@ -155,7 +155,7 @@ MACHINE_START(ESATA_SHEEVAPLUG, "Marvell eSATA SheevaPlug Reference Board")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
#endif
diff --git a/arch/arm/mach-kirkwood/t5325-setup.c b/arch/arm/mach-kirkwood/t5325-setup.c
index f2daf711e72e..8736f8c97518 100644
--- a/arch/arm/mach-kirkwood/t5325-setup.c
+++ b/arch/arm/mach-kirkwood/t5325-setup.c
@@ -211,6 +211,6 @@ MACHINE_START(T5325, "HP t5325 Thin Client")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/ts219-setup.c b/arch/arm/mach-kirkwood/ts219-setup.c
index 73e2b6ca9564..283abff90228 100644
--- a/arch/arm/mach-kirkwood/ts219-setup.c
+++ b/arch/arm/mach-kirkwood/ts219-setup.c
@@ -137,6 +137,6 @@ MACHINE_START(TS219, "QNAP TS-119/TS-219")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/ts41x-setup.c b/arch/arm/mach-kirkwood/ts41x-setup.c
index e4c61279ea86..81d585806b2f 100644
--- a/arch/arm/mach-kirkwood/ts41x-setup.c
+++ b/arch/arm/mach-kirkwood/ts41x-setup.c
@@ -181,6 +181,6 @@ MACHINE_START(TS41X, "QNAP TS-41x")
.map_io = kirkwood_map_io,
.init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
- .timer = &kirkwood_timer,
+ .init_time = kirkwood_timer_init,
.restart = kirkwood_restart,
MACHINE_END
diff --git a/arch/arm/mach-ks8695/board-acs5k.c b/arch/arm/mach-ks8695/board-acs5k.c
index b0c306ccbc6e..456d6386edf8 100644
--- a/arch/arm/mach-ks8695/board-acs5k.c
+++ b/arch/arm/mach-ks8695/board-acs5k.c
@@ -227,6 +227,6 @@ MACHINE_START(ACS5K, "Brivo Systems LLC ACS-5000 Master board")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = acs5k_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
diff --git a/arch/arm/mach-ks8695/board-dsm320.c b/arch/arm/mach-ks8695/board-dsm320.c
index e0d36cef2c56..d37c218c3584 100644
--- a/arch/arm/mach-ks8695/board-dsm320.c
+++ b/arch/arm/mach-ks8695/board-dsm320.c
@@ -125,6 +125,6 @@ MACHINE_START(DSM320, "D-Link DSM-320 Wireless Media Player")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = dsm320_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
diff --git a/arch/arm/mach-ks8695/board-micrel.c b/arch/arm/mach-ks8695/board-micrel.c
index a8270725b76d..3acbdfd31391 100644
--- a/arch/arm/mach-ks8695/board-micrel.c
+++ b/arch/arm/mach-ks8695/board-micrel.c
@@ -57,6 +57,6 @@ MACHINE_START(KS8695, "KS8695 Centaur Development Board")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = micrel_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
diff --git a/arch/arm/mach-ks8695/board-og.c b/arch/arm/mach-ks8695/board-og.c
index 1623ba461e47..002bc619bb68 100644
--- a/arch/arm/mach-ks8695/board-og.c
+++ b/arch/arm/mach-ks8695/board-og.c
@@ -145,7 +145,7 @@ MACHINE_START(CM4002, "OpenGear/CM4002")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = og_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
#endif
@@ -157,7 +157,7 @@ MACHINE_START(CM4008, "OpenGear/CM4008")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = og_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
#endif
@@ -169,7 +169,7 @@ MACHINE_START(CM41XX, "OpenGear/CM41xx")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = og_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
#endif
@@ -181,7 +181,7 @@ MACHINE_START(IM4004, "OpenGear/IM4004")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = og_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
#endif
@@ -193,7 +193,7 @@ MACHINE_START(IM42XX, "OpenGear/IM42xx")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = og_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
#endif
diff --git a/arch/arm/mach-ks8695/board-sg.c b/arch/arm/mach-ks8695/board-sg.c
index f35b98b5bf37..fdf2352d2cf8 100644
--- a/arch/arm/mach-ks8695/board-sg.c
+++ b/arch/arm/mach-ks8695/board-sg.c
@@ -91,7 +91,7 @@ MACHINE_START(LITE300, "SecureComputing/SG300")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = sg_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
#endif
@@ -103,7 +103,7 @@ MACHINE_START(SG310, "McAfee/SG310")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = sg_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
#endif
@@ -115,7 +115,7 @@ MACHINE_START(SE4200, "SecureComputing/SE4200")
.map_io = ks8695_map_io,
.init_irq = ks8695_init_irq,
.init_machine = sg_init,
- .timer = &ks8695_timer,
+ .init_time = ks8695_timer_init,
.restart = ks8695_restart,
MACHINE_END
#endif
diff --git a/arch/arm/mach-ks8695/generic.h b/arch/arm/mach-ks8695/generic.h
index f8bdb11a9c33..6e97ce462d73 100644
--- a/arch/arm/mach-ks8695/generic.h
+++ b/arch/arm/mach-ks8695/generic.h
@@ -13,4 +13,4 @@
extern __init void ks8695_map_io(void);
extern __init void ks8695_init_irq(void);
extern void ks8695_restart(char, const char *);
-extern struct sys_timer ks8695_timer;
+extern void ks8695_timer_init(void);
diff --git a/arch/arm/mach-ks8695/include/mach/uncompress.h b/arch/arm/mach-ks8695/include/mach/uncompress.h
index 8879d610308a..c089a1aea674 100644
--- a/arch/arm/mach-ks8695/include/mach/uncompress.h
+++ b/arch/arm/mach-ks8695/include/mach/uncompress.h
@@ -32,6 +32,5 @@ static inline void flush(void)
}
#define arch_decomp_setup()
-#define arch_decomp_wdog()
#endif
diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c
index 46c84bc7792c..c272a3863d5f 100644
--- a/arch/arm/mach-ks8695/time.c
+++ b/arch/arm/mach-ks8695/time.c
@@ -146,7 +146,7 @@ static void ks8695_timer_setup(void)
0xFFFFFFFFU);
}
-static void __init ks8695_timer_init (void)
+void __init ks8695_timer_init(void)
{
ks8695_timer_setup();
@@ -154,10 +154,6 @@ static void __init ks8695_timer_init (void)
setup_irq(KS8695_IRQ_TIMER1, &ks8695_timer_irq);
}
-struct sys_timer ks8695_timer = {
- .init = ks8695_timer_init,
-};
-
void ks8695_restart(char mode, const char *cmd)
{
unsigned int reg;
diff --git a/arch/arm/mach-lpc32xx/common.h b/arch/arm/mach-lpc32xx/common.h
index afeac3b1fae6..e0b26062a272 100644
--- a/arch/arm/mach-lpc32xx/common.h
+++ b/arch/arm/mach-lpc32xx/common.h
@@ -25,7 +25,7 @@
/*
* Other arch specific structures and functions
*/
-extern struct sys_timer lpc32xx_timer;
+extern void lpc32xx_timer_init(void);
extern void __init lpc32xx_init_irq(void);
extern void __init lpc32xx_map_io(void);
extern void __init lpc32xx_serial_init(void);
diff --git a/arch/arm/mach-lpc32xx/include/mach/uncompress.h b/arch/arm/mach-lpc32xx/include/mach/uncompress.h
index c142487d299a..1198a89183cd 100644
--- a/arch/arm/mach-lpc32xx/include/mach/uncompress.h
+++ b/arch/arm/mach-lpc32xx/include/mach/uncompress.h
@@ -55,6 +55,5 @@ static inline void flush(void)
/* NULL functions; we don't presently need them */
#define arch_decomp_setup()
-#define arch_decomp_wdog()
#endif
diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c
index e8ff4c3f0566..c1cd5a943ab1 100644
--- a/arch/arm/mach-lpc32xx/phy3250.c
+++ b/arch/arm/mach-lpc32xx/phy3250.c
@@ -263,7 +263,7 @@ DT_MACHINE_START(LPC32XX_DT, "LPC32XX SoC (Flattened Device Tree)")
.atag_offset = 0x100,
.map_io = lpc32xx_map_io,
.init_irq = lpc32xx_init_irq,
- .timer = &lpc32xx_timer,
+ .init_time = lpc32xx_timer_init,
.init_machine = lpc3250_machine_init,
.dt_compat = lpc32xx_dt_compat,
.restart = lpc23xx_restart,
diff --git a/arch/arm/mach-lpc32xx/timer.c b/arch/arm/mach-lpc32xx/timer.c
index c40667c33161..20eab63d10ba 100644
--- a/arch/arm/mach-lpc32xx/timer.c
+++ b/arch/arm/mach-lpc32xx/timer.c
@@ -70,7 +70,6 @@ static void lpc32xx_clkevt_mode(enum clock_event_mode mode,
static struct clock_event_device lpc32xx_clkevt = {
.name = "lpc32xx_clkevt",
.features = CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.rating = 300,
.set_next_event = lpc32xx_clkevt_next_event,
.set_mode = lpc32xx_clkevt_mode,
@@ -100,7 +99,7 @@ static struct irqaction lpc32xx_timer_irq = {
* clocks need to be enabled here manually and then tagged as used in
* the clock driver initialization
*/
-static void __init lpc32xx_timer_init(void)
+void __init lpc32xx_timer_init(void)
{
u32 clkrate, pllreg;
@@ -141,14 +140,8 @@ static void __init lpc32xx_timer_init(void)
setup_irq(IRQ_LPC32XX_TIMER0, &lpc32xx_timer_irq);
/* Setup the clockevent structure. */
- lpc32xx_clkevt.mult = div_sc(clkrate, NSEC_PER_SEC,
- lpc32xx_clkevt.shift);
- lpc32xx_clkevt.max_delta_ns = clockevent_delta2ns(-1,
- &lpc32xx_clkevt);
- lpc32xx_clkevt.min_delta_ns = clockevent_delta2ns(1,
- &lpc32xx_clkevt) + 1;
lpc32xx_clkevt.cpumask = cpumask_of(0);
- clockevents_register_device(&lpc32xx_clkevt);
+ clockevents_config_and_register(&lpc32xx_clkevt, clkrate, 1, -1);
/* Use timer1 as clock source. */
__raw_writel(LPC32XX_TIMER_CNTR_TCR_RESET,
@@ -161,8 +154,3 @@ static void __init lpc32xx_timer_init(void)
clocksource_mmio_init(LPC32XX_TIMER_TC(LPC32XX_TIMER1_BASE),
"lpc32xx_clksrc", clkrate, 300, 32, clocksource_mmio_readl_up);
}
-
-struct sys_timer lpc32xx_timer = {
- .init = &lpc32xx_timer_init,
-};
-
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index e5dba9c5dc54..9f64d5632e07 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -262,7 +262,7 @@ MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform")
.map_io = mmp_map_io,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa168_init_irq,
- .timer = &pxa168_timer,
+ .init_time = pxa168_timer_init,
.init_machine = common_init,
.restart = pxa168_restart,
MACHINE_END
@@ -271,7 +271,7 @@ MACHINE_START(ZYLONITE2, "PXA168-based Zylonite2 Development Platform")
.map_io = mmp_map_io,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa168_init_irq,
- .timer = &pxa168_timer,
+ .init_time = pxa168_timer_init,
.init_machine = common_init,
.restart = pxa168_restart,
MACHINE_END
diff --git a/arch/arm/mach-mmp/avengers_lite.c b/arch/arm/mach-mmp/avengers_lite.c
index 603542ae6fbd..1f94957b56ae 100644
--- a/arch/arm/mach-mmp/avengers_lite.c
+++ b/arch/arm/mach-mmp/avengers_lite.c
@@ -45,7 +45,7 @@ MACHINE_START(AVENGERS_LITE, "PXA168 Avengers lite Development Platform")
.map_io = mmp_map_io,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa168_init_irq,
- .timer = &pxa168_timer,
+ .init_time = pxa168_timer_init,
.init_machine = avengers_lite_init,
.restart = pxa168_restart,
MACHINE_END
diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c
index 5cb769cd26d9..2358011c7d8e 100644
--- a/arch/arm/mach-mmp/brownstone.c
+++ b/arch/arm/mach-mmp/brownstone.c
@@ -218,7 +218,7 @@ MACHINE_START(BROWNSTONE, "Brownstone Development Platform")
.map_io = mmp_map_io,
.nr_irqs = BROWNSTONE_NR_IRQS,
.init_irq = mmp2_init_irq,
- .timer = &mmp2_timer,
+ .init_time = mmp2_timer_init,
.init_machine = brownstone_init,
.restart = mmp_restart,
MACHINE_END
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index bd453274fca2..0bdc50b134ce 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -1,7 +1,5 @@
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
-struct sys_timer;
-
extern void timer_init(int irq);
extern void __init icu_init_irq(void);
diff --git a/arch/arm/mach-mmp/flint.c b/arch/arm/mach-mmp/flint.c
index 8059cc0905c6..754c352dd02b 100644
--- a/arch/arm/mach-mmp/flint.c
+++ b/arch/arm/mach-mmp/flint.c
@@ -121,7 +121,7 @@ MACHINE_START(FLINT, "Flint Development Platform")
.map_io = mmp_map_io,
.nr_irqs = FLINT_NR_IRQS,
.init_irq = mmp2_init_irq,
- .timer = &mmp2_timer,
+ .init_time = mmp2_timer_init,
.init_machine = flint_init,
.restart = mmp_restart,
MACHINE_END
diff --git a/arch/arm/mach-mmp/gplugd.c b/arch/arm/mach-mmp/gplugd.c
index 5c3d61ee729a..d1e2d595e79c 100644
--- a/arch/arm/mach-mmp/gplugd.c
+++ b/arch/arm/mach-mmp/gplugd.c
@@ -194,7 +194,7 @@ MACHINE_START(GPLUGD, "PXA168-based GuruPlug Display (gplugD) Platform")
.map_io = mmp_map_io,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa168_init_irq,
- .timer = &pxa168_timer,
+ .init_time = pxa168_timer_init,
.init_machine = gplugd_init,
.restart = pxa168_restart,
MACHINE_END
diff --git a/arch/arm/mach-mmp/include/mach/mmp2.h b/arch/arm/mach-mmp/include/mach/mmp2.h
index c4ca4d17194a..0764f4ecec82 100644
--- a/arch/arm/mach-mmp/include/mach/mmp2.h
+++ b/arch/arm/mach-mmp/include/mach/mmp2.h
@@ -3,9 +3,7 @@
#include <linux/platform_data/pxa_sdhci.h>
-struct sys_timer;
-
-extern struct sys_timer mmp2_timer;
+extern void mmp2_timer_init(void);
extern void __init mmp2_init_icu(void);
extern void __init mmp2_init_irq(void);
extern void mmp2_clear_pmic_int(void);
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h
index 37632d964d50..7ed1df21ea1c 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/pxa168.h
@@ -1,9 +1,7 @@
#ifndef __ASM_MACH_PXA168_H
#define __ASM_MACH_PXA168_H
-struct sys_timer;
-
-extern struct sys_timer pxa168_timer;
+extern void pxa168_timer_init(void);
extern void __init pxa168_init_irq(void);
extern void pxa168_restart(char, const char *);
extern void pxa168_clear_keypad_wakeup(void);
diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h
index 3b58a3b2d7df..b914afa1fcdc 100644
--- a/arch/arm/mach-mmp/include/mach/pxa910.h
+++ b/arch/arm/mach-mmp/include/mach/pxa910.h
@@ -1,15 +1,14 @@
#ifndef __ASM_MACH_PXA910_H
#define __ASM_MACH_PXA910_H
-struct sys_timer;
-
-extern struct sys_timer pxa910_timer;
+extern void pxa910_timer_init(void);
extern void __init pxa910_init_irq(void);
#include <linux/i2c.h>
#include <linux/i2c/pxa-i2c.h>
#include <mach/devices.h>
#include <linux/platform_data/mtd-nand-pxa3xx.h>
+#include <video/mmp_disp.h>
extern struct pxa_device_desc pxa910_device_uart1;
extern struct pxa_device_desc pxa910_device_uart2;
@@ -23,7 +22,9 @@ extern struct pxa_device_desc pxa910_device_nand;
extern struct platform_device pxa168_device_u2o;
extern struct platform_device pxa168_device_u2ootg;
extern struct platform_device pxa168_device_u2oehci;
-
+extern struct pxa_device_desc pxa910_device_disp;
+extern struct pxa_device_desc pxa910_device_fb;
+extern struct pxa_device_desc pxa910_device_panel;
extern struct platform_device pxa910_device_gpio;
extern struct platform_device pxa910_device_rtc;
diff --git a/arch/arm/mach-mmp/include/mach/uncompress.h b/arch/arm/mach-mmp/include/mach/uncompress.h
index d6daeb7e4ef1..8890fa8fa771 100644
--- a/arch/arm/mach-mmp/include/mach/uncompress.h
+++ b/arch/arm/mach-mmp/include/mach/uncompress.h
@@ -43,9 +43,3 @@ static inline void arch_decomp_setup(void)
if (machine_is_avengers_lite())
UART = (unsigned long *)UART3_BASE;
}
-
-/*
- * nothing to do
- */
-
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-mmp/jasper.c b/arch/arm/mach-mmp/jasper.c
index ff73249884d0..66634fd0ecb0 100644
--- a/arch/arm/mach-mmp/jasper.c
+++ b/arch/arm/mach-mmp/jasper.c
@@ -174,7 +174,7 @@ MACHINE_START(MARVELL_JASPER, "Jasper Development Platform")
.map_io = mmp_map_io,
.nr_irqs = JASPER_NR_IRQS,
.init_irq = mmp2_init_irq,
- .timer = &mmp2_timer,
+ .init_time = mmp2_timer_init,
.init_machine = jasper_init,
.restart = mmp_restart,
MACHINE_END
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
index 033cc31b3c72..d063efa0a4f1 100644
--- a/arch/arm/mach-mmp/mmp-dt.c
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -22,10 +22,6 @@
extern void __init mmp_dt_irq_init(void);
extern void __init mmp_dt_init_timer(void);
-static struct sys_timer mmp_dt_timer = {
- .init = mmp_dt_init_timer,
-};
-
static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
@@ -69,7 +65,7 @@ static const char *mmp_dt_board_compat[] __initdata = {
DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
.map_io = mmp_map_io,
.init_irq = mmp_dt_irq_init,
- .timer = &mmp_dt_timer,
+ .init_time = mmp_dt_init_timer,
.init_machine = pxa168_dt_init,
.dt_compat = mmp_dt_board_compat,
MACHINE_END
@@ -77,7 +73,7 @@ MACHINE_END
DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)")
.map_io = mmp_map_io,
.init_irq = mmp_dt_irq_init,
- .timer = &mmp_dt_timer,
+ .init_time = mmp_dt_init_timer,
.init_machine = pxa910_dt_init,
.dt_compat = mmp_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-mmp/mmp2-dt.c b/arch/arm/mach-mmp/mmp2-dt.c
index 535a5ed5977b..fad431aa6e09 100644
--- a/arch/arm/mach-mmp/mmp2-dt.c
+++ b/arch/arm/mach-mmp/mmp2-dt.c
@@ -24,10 +24,6 @@
extern void __init mmp_dt_irq_init(void);
extern void __init mmp_dt_init_timer(void);
-static struct sys_timer mmp_dt_timer = {
- .init = mmp_dt_init_timer,
-};
-
static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4030000, "pxa2xx-uart.0", NULL),
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.1", NULL),
@@ -54,7 +50,7 @@ static const char *mmp2_dt_board_compat[] __initdata = {
DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
.map_io = mmp_map_io,
.init_irq = mmp_dt_irq_init,
- .timer = &mmp_dt_timer,
+ .init_time = mmp_dt_init_timer,
.init_machine = mmp2_dt_init,
.dt_compat = mmp2_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index 3a3768c7a191..d94d114eef7b 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -114,7 +114,7 @@ postcore_initcall(mmp2_init);
#define APBC_TIMERS APBC_REG(0x024)
-static void __init mmp2_timer_init(void)
+void __init mmp2_timer_init(void)
{
unsigned long clk_rst;
@@ -130,10 +130,6 @@ static void __init mmp2_timer_init(void)
timer_init(IRQ_MMP2_TIMER1);
}
-struct sys_timer mmp2_timer = {
- .init = mmp2_timer_init,
-};
-
/* on-chip devices */
MMP2_DEVICE(uart1, "pxa2xx-uart", 0, UART1, 0xd4030000, 0x30, 4, 5);
MMP2_DEVICE(uart2, "pxa2xx-uart", 1, UART2, 0xd4017000, 0x30, 20, 21);
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index b7f074f15498..9bc7b86a86a7 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -67,7 +67,7 @@ postcore_initcall(pxa168_init);
#define TIMER_CLK_RST (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3))
#define APBC_TIMERS APBC_REG(0x34)
-static void __init pxa168_timer_init(void)
+void __init pxa168_timer_init(void)
{
/* this is early, we have to initialize the CCU registers by
* ourselves instead of using clk_* API. Clock rate is defined
@@ -81,10 +81,6 @@ static void __init pxa168_timer_init(void)
timer_init(IRQ_PXA168_TIMER1);
}
-struct sys_timer pxa168_timer = {
- .init = pxa168_timer_init,
-};
-
void pxa168_clear_keypad_wakeup(void)
{
uint32_t val;
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 8b1e16fbb7a5..36cb321a3d70 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -101,7 +101,7 @@ postcore_initcall(pxa910_init);
#define TIMER_CLK_RST (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3))
#define APBC_TIMERS APBC_REG(0x34)
-static void __init pxa910_timer_init(void)
+void __init pxa910_timer_init(void)
{
/* reset and configure */
__raw_writel(APBC_APBCLK | APBC_RST, APBC_TIMERS);
@@ -110,10 +110,6 @@ static void __init pxa910_timer_init(void)
timer_init(IRQ_PXA910_AP1_TIMER1);
}
-struct sys_timer pxa910_timer = {
- .init = pxa910_timer_init,
-};
-
/* on-chip devices */
/* NOTE: there are totally 3 UARTs on PXA910:
@@ -138,6 +134,9 @@ PXA910_DEVICE(pwm2, "pxa910-pwm", 1, NONE, 0xd401a400, 0x10);
PXA910_DEVICE(pwm3, "pxa910-pwm", 2, NONE, 0xd401a800, 0x10);
PXA910_DEVICE(pwm4, "pxa910-pwm", 3, NONE, 0xd401ac00, 0x10);
PXA910_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99);
+PXA910_DEVICE(disp, "mmp-disp", 0, LCD, 0xd420b000, 0x1ec);
+PXA910_DEVICE(fb, "mmp-fb", -1, NONE, 0, 0);
+PXA910_DEVICE(panel, "tpo-hvga", -1, NONE, 0, 0);
struct resource pxa910_resource_gpio[] = {
{
diff --git a/arch/arm/mach-mmp/tavorevb.c b/arch/arm/mach-mmp/tavorevb.c
index b28f9084dfff..4c127d23955d 100644
--- a/arch/arm/mach-mmp/tavorevb.c
+++ b/arch/arm/mach-mmp/tavorevb.c
@@ -103,7 +103,7 @@ MACHINE_START(TAVOREVB, "PXA910 Evaluation Board (aka TavorEVB)")
.map_io = mmp_map_io,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa910_init_irq,
- .timer = &pxa910_timer,
+ .init_time = pxa910_timer_init,
.init_machine = tavorevb_init,
.restart = mmp_restart,
MACHINE_END
diff --git a/arch/arm/mach-mmp/teton_bga.c b/arch/arm/mach-mmp/teton_bga.c
index dd30ea74785c..8609967975ed 100644
--- a/arch/arm/mach-mmp/teton_bga.c
+++ b/arch/arm/mach-mmp/teton_bga.c
@@ -86,7 +86,7 @@ MACHINE_START(TETON_BGA, "PXA168-based Teton BGA Development Platform")
.map_io = mmp_map_io,
.nr_irqs = MMP_NR_IRQS,
.init_irq = pxa168_init_irq,
- .timer = &pxa168_timer,
+ .init_time = pxa168_timer_init,
.init_machine = teton_bga_init,
.restart = pxa168_restart,
MACHINE_END
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index 936447c70977..86a18b3d252e 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -141,7 +141,6 @@ static void timer_set_mode(enum clock_event_mode mode,
static struct clock_event_device ckevt = {
.name = "clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.rating = 200,
.set_next_event = timer_set_next_event,
.set_mode = timer_set_mode,
@@ -198,15 +197,13 @@ void __init timer_init(int irq)
setup_sched_clock(mmp_read_sched_clock, 32, CLOCK_TICK_RATE);
- ckevt.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt.shift);
- ckevt.max_delta_ns = clockevent_delta2ns(MAX_DELTA, &ckevt);
- ckevt.min_delta_ns = clockevent_delta2ns(MIN_DELTA, &ckevt);
ckevt.cpumask = cpumask_of(0);
setup_irq(irq, &timer_irq);
clocksource_register_hz(&cksrc, CLOCK_TICK_RATE);
- clockevents_register_device(&ckevt);
+ clockevents_config_and_register(&ckevt, CLOCK_TICK_RATE,
+ MIN_DELTA, MAX_DELTA);
}
#ifdef CONFIG_OF
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index ce55fd8821c4..22a9058f9f4d 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -19,6 +19,8 @@
#include <linux/gpio.h>
#include <linux/mfd/88pm860x.h>
#include <linux/platform_data/mv_usb.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -184,6 +186,92 @@ static struct pxa3xx_nand_platform_data dkb_nand_info = {
};
#endif
+#ifdef CONFIG_MMP_DISP
+/* path config */
+#define CFG_IOPADMODE(iopad) (iopad) /* 0x0 ~ 0xd */
+#define SCLK_SOURCE_SELECT(x) (x << 30) /* 0x0 ~ 0x3 */
+/* link config */
+#define CFG_DUMBMODE(mode) (mode << 28) /* 0x0 ~ 0x6*/
+#define CFG_GRA_SWAPRB(x) (x << 0) /* 1: rbswap enabled */
+static struct mmp_mach_path_config dkb_disp_config[] = {
+ [0] = {
+ .name = "mmp-parallel",
+ .overlay_num = 2,
+ .output_type = PATH_OUT_PARALLEL,
+ .path_config = CFG_IOPADMODE(0x1)
+ | SCLK_SOURCE_SELECT(0x1),
+ .link_config = CFG_DUMBMODE(0x2)
+ | CFG_GRA_SWAPRB(0x1),
+ },
+};
+
+static struct mmp_mach_plat_info dkb_disp_info = {
+ .name = "mmp-disp",
+ .clk_name = "disp0",
+ .path_num = 1,
+ .paths = dkb_disp_config,
+};
+
+static struct mmp_buffer_driver_mach_info dkb_fb_info = {
+ .name = "mmp-fb",
+ .path_name = "mmp-parallel",
+ .overlay_id = 0,
+ .dmafetch_id = 1,
+ .default_pixfmt = PIXFMT_RGB565,
+};
+
+static void dkb_tpo_panel_power(int on)
+{
+ int err;
+ u32 spi_reset = mfp_to_gpio(MFP_PIN_GPIO106);
+
+ if (on) {
+ err = gpio_request(spi_reset, "TPO_LCD_SPI_RESET");
+ if (err) {
+ pr_err("failed to request GPIO for TPO LCD RESET\n");
+ return;
+ }
+ gpio_direction_output(spi_reset, 0);
+ udelay(100);
+ gpio_set_value(spi_reset, 1);
+ gpio_free(spi_reset);
+ } else {
+ err = gpio_request(spi_reset, "TPO_LCD_SPI_RESET");
+ if (err) {
+ pr_err("failed to request LCD RESET gpio\n");
+ return;
+ }
+ gpio_set_value(spi_reset, 0);
+ gpio_free(spi_reset);
+ }
+}
+
+static struct mmp_mach_panel_info dkb_tpo_panel_info = {
+ .name = "tpo-hvga",
+ .plat_path_name = "mmp-parallel",
+ .plat_set_onoff = dkb_tpo_panel_power,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+ {
+ .modalias = "tpo-hvga",
+ .platform_data = &dkb_tpo_panel_info,
+ .bus_num = 5,
+ }
+};
+
+static void __init add_disp(void)
+{
+ pxa_register_device(&pxa910_device_disp,
+ &dkb_disp_info, sizeof(dkb_disp_info));
+ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+ pxa_register_device(&pxa910_device_fb,
+ &dkb_fb_info, sizeof(dkb_fb_info));
+ pxa_register_device(&pxa910_device_panel,
+ &dkb_tpo_panel_info, sizeof(dkb_tpo_panel_info));
+}
+#endif
+
static void __init ttc_dkb_init(void)
{
mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
@@ -212,13 +300,17 @@ static void __init ttc_dkb_init(void)
pxa168_device_u2ootg.dev.platform_data = &ttc_usb_pdata;
platform_device_register(&pxa168_device_u2ootg);
#endif
+
+#ifdef CONFIG_MMP_DISP
+ add_disp();
+#endif
}
MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
.map_io = mmp_map_io,
.nr_irqs = TTCDKB_NR_IRQS,
.init_irq = pxa910_init_irq,
- .timer = &pxa910_timer,
+ .init_time = pxa910_timer_init,
.init_machine = ttc_dkb_init,
.restart = mmp_restart,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-dt-8660.c b/arch/arm/mach-msm/board-dt-8660.c
index b5b4de2cdf9e..7dcfc5300bbd 100644
--- a/arch/arm/mach-msm/board-dt-8660.c
+++ b/arch/arm/mach-msm/board-dt-8660.c
@@ -11,26 +11,15 @@
*/
#include <linux/init.h>
+#include <linux/irqchip.h>
#include <linux/of.h>
-#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <mach/board.h>
#include "common.h"
-static const struct of_device_id msm_dt_gic_match[] __initconst = {
- { .compatible = "qcom,msm-8660-qgic", .data = gic_of_init },
- {}
-};
-
-static void __init msm8x60_init_irq(void)
-{
- of_irq_init(msm_dt_gic_match);
-}
-
static void __init msm8x60_init_late(void)
{
smd_debugfs_init();
@@ -55,10 +44,9 @@ static const char *msm8x60_fluid_match[] __initdata = {
DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
.smp = smp_ops(msm_smp_ops),
.map_io = msm_map_msm8x60_io,
- .init_irq = msm8x60_init_irq,
- .handle_irq = gic_handle_irq,
+ .init_irq = irqchip_init,
.init_machine = msm8x60_dt_init,
.init_late = msm8x60_init_late,
- .timer = &msm_dt_timer,
+ .init_time = msm_dt_timer_init,
.dt_compat = msm8x60_fluid_match,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-dt-8960.c b/arch/arm/mach-msm/board-dt-8960.c
index 4490edb71c17..73019363ffa4 100644
--- a/arch/arm/mach-msm/board-dt-8960.c
+++ b/arch/arm/mach-msm/board-dt-8960.c
@@ -11,24 +11,13 @@
*/
#include <linux/init.h>
-#include <linux/of_irq.h>
+#include <linux/irqchip.h>
#include <linux/of_platform.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>
#include "common.h"
-static const struct of_device_id msm_dt_gic_match[] __initconst = {
- { .compatible = "qcom,msm-qgic2", .data = gic_of_init },
- { }
-};
-
-static void __init msm_dt_init_irq(void)
-{
- of_irq_init(msm_dt_gic_match);
-}
-
static void __init msm_dt_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
@@ -42,9 +31,8 @@ static const char * const msm8960_dt_match[] __initconst = {
DT_MACHINE_START(MSM8960_DT, "Qualcomm MSM (Flattened Device Tree)")
.smp = smp_ops(msm_smp_ops),
.map_io = msm_map_msm8960_io,
- .init_irq = msm_dt_init_irq,
- .timer = &msm_dt_timer,
+ .init_irq = irqchip_init,
+ .init_time = msm_dt_timer_init,
.init_machine = msm_dt_init,
.dt_compat = msm8960_dt_match,
- .handle_irq = gic_handle_irq,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
index 6ce542e2e21c..84d720af34ab 100644
--- a/arch/arm/mach-msm/board-halibut.c
+++ b/arch/arm/mach-msm/board-halibut.c
@@ -106,5 +106,5 @@ MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)")
.init_irq = halibut_init_irq,
.init_machine = halibut_init,
.init_late = halibut_init_late,
- .timer = &msm7x01_timer,
+ .init_time = msm7x01_timer_init,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-mahimahi.c b/arch/arm/mach-msm/board-mahimahi.c
index df00bc03ce74..30c3496db593 100644
--- a/arch/arm/mach-msm/board-mahimahi.c
+++ b/arch/arm/mach-msm/board-mahimahi.c
@@ -75,7 +75,7 @@ static void __init mahimahi_init_late(void)
smd_debugfs_init();
}
-extern struct sys_timer msm_timer;
+void msm_timer_init(void);
MACHINE_START(MAHIMAHI, "mahimahi")
.atag_offset = 0x100,
@@ -84,5 +84,5 @@ MACHINE_START(MAHIMAHI, "mahimahi")
.init_irq = msm_init_irq,
.init_machine = mahimahi_init,
.init_late = mahimahi_init_late,
- .timer = &msm_timer,
+ .init_time = msm_timer_init,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index effa6f4336c7..7bc3f82e3ec9 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -131,7 +131,7 @@ MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF")
.init_irq = msm7x30_init_irq,
.init_machine = msm7x30_init,
.init_late = msm7x30_init_late,
- .timer = &msm7x30_timer,
+ .init_time = msm7x30_timer_init,
MACHINE_END
MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA")
@@ -142,7 +142,7 @@ MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA")
.init_irq = msm7x30_init_irq,
.init_machine = msm7x30_init,
.init_late = msm7x30_init_late,
- .timer = &msm7x30_timer,
+ .init_time = msm7x30_timer_init,
MACHINE_END
MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID")
@@ -153,5 +153,5 @@ MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID")
.init_irq = msm7x30_init_irq,
.init_machine = msm7x30_init,
.init_late = msm7x30_init_late,
- .timer = &msm7x30_timer,
+ .init_time = msm7x30_timer_init,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 2448fcf09eb1..686e7949a73a 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -200,7 +200,7 @@ MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF")
.init_irq = qsd8x50_init_irq,
.init_machine = qsd8x50_init,
.init_late = qsd8x50_init_late,
- .timer = &qsd8x50_timer,
+ .init_time = qsd8x50_timer_init,
MACHINE_END
MACHINE_START(QSD8X50A_ST1_5, "QCT QSD8X50A ST1.5")
@@ -209,5 +209,5 @@ MACHINE_START(QSD8X50A_ST1_5, "QCT QSD8X50A ST1.5")
.init_irq = qsd8x50_init_irq,
.init_machine = qsd8x50_init,
.init_late = qsd8x50_init_late,
- .timer = &qsd8x50_timer,
+ .init_time = qsd8x50_timer_init,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c
index b7b0fc7e3278..70730111b37c 100644
--- a/arch/arm/mach-msm/board-sapphire.c
+++ b/arch/arm/mach-msm/board-sapphire.c
@@ -53,7 +53,7 @@ static struct platform_device *devices[] __initdata = {
&msm_device_uart3,
};
-extern struct sys_timer msm_timer;
+void msm_timer_init(void);
static void __init sapphire_init_irq(void)
{
@@ -113,5 +113,5 @@ MACHINE_START(SAPPHIRE, "sapphire")
.init_irq = sapphire_init_irq,
.init_machine = sapphire_init,
.init_late = sapphire_init_late,
- .timer = &msm_timer,
+ .init_time = msm_timer_init,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c
index 4ba0800e243e..919bfa32871a 100644
--- a/arch/arm/mach-msm/board-trout.c
+++ b/arch/arm/mach-msm/board-trout.c
@@ -110,5 +110,5 @@ MACHINE_START(TROUT, "HTC Dream")
.init_irq = trout_init_irq,
.init_machine = trout_init,
.init_late = trout_init_late,
- .timer = &msm7x01_timer,
+ .init_time = msm7x01_timer_init,
MACHINE_END
diff --git a/arch/arm/mach-msm/common.h b/arch/arm/mach-msm/common.h
index 633a7159d5ff..ce8215a269e5 100644
--- a/arch/arm/mach-msm/common.h
+++ b/arch/arm/mach-msm/common.h
@@ -12,10 +12,10 @@
#ifndef __MACH_COMMON_H
#define __MACH_COMMON_H
-extern struct sys_timer msm7x01_timer;
-extern struct sys_timer msm7x30_timer;
-extern struct sys_timer msm_dt_timer;
-extern struct sys_timer qsd8x50_timer;
+extern void msm7x01_timer_init(void);
+extern void msm7x30_timer_init(void);
+extern void msm_dt_timer_init(void);
+extern void qsd8x50_timer_init(void);
extern void msm_map_common_io(void);
extern void msm_map_msm7x30_io(void);
diff --git a/arch/arm/mach-msm/include/mach/uncompress.h b/arch/arm/mach-msm/include/mach/uncompress.h
index c14011fe832d..fa97a10d8695 100644
--- a/arch/arm/mach-msm/include/mach/uncompress.h
+++ b/arch/arm/mach-msm/include/mach/uncompress.h
@@ -60,8 +60,4 @@ static inline void arch_decomp_setup(void)
{
}
-static inline void arch_decomp_wdog(void)
-{
-}
-
#endif
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 7ed69b69c87c..42932865416a 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -15,8 +15,8 @@
#include <linux/jiffies.h>
#include <linux/smp.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
-#include <asm/hardware/gic.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include <asm/mach-types.h>
@@ -115,7 +115,7 @@ static int __cpuinit msm_boot_secondary(unsigned int cpu, struct task_struct *id
* the boot monitor to read the system wide flags register,
* and branch to the address found there.
*/
- gic_raise_softirq(cpumask_of(cpu), 0);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
@@ -153,8 +153,6 @@ static void __init msm_smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
static void __init msm_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h
index 12da4cacd4a8..e8d043a0e990 100644
--- a/arch/arm/mach-msm/proc_comm.h
+++ b/arch/arm/mach-msm/proc_comm.h
@@ -253,6 +253,6 @@ enum {
(((drvstr) & 0xF) << 17))
int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2);
-void __init proc_comm_boot_wait(void);
+void proc_comm_boot_wait(void);
#endif
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 476549a8a709..2969027f02fa 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -25,7 +25,6 @@
#include <linux/of_irq.h>
#include <asm/mach/time.h>
-#include <asm/hardware/gic.h>
#include <asm/localtimer.h>
#include <asm/sched_clock.h>
@@ -144,13 +143,9 @@ static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt)
evt->rating = msm_clockevent.rating;
evt->set_mode = msm_timer_set_mode;
evt->set_next_event = msm_timer_set_next_event;
- evt->shift = msm_clockevent.shift;
- evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift);
- evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt);
- evt->min_delta_ns = clockevent_delta2ns(4, evt);
*__this_cpu_ptr(msm_evt.percpu_evt) = evt;
- clockevents_register_device(evt);
+ clockevents_config_and_register(evt, GPT_HZ, 4, 0xf0000000);
enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING);
return 0;
}
@@ -229,7 +224,7 @@ static const struct of_device_id msm_gpt_match[] __initconst = {
{ },
};
-static void __init msm_dt_timer_init(void)
+void __init msm_dt_timer_init(void)
{
struct device_node *np;
u32 freq;
@@ -296,10 +291,6 @@ static void __init msm_dt_timer_init(void)
msm_timer_init(freq, 32, irq, !!percpu_offset);
}
-
-struct sys_timer msm_dt_timer = {
- .init = msm_dt_timer_init
-};
#endif
static int __init msm_timer_map(phys_addr_t event, phys_addr_t source)
@@ -317,7 +308,7 @@ static int __init msm_timer_map(phys_addr_t event, phys_addr_t source)
return 0;
}
-static void __init msm7x01_timer_init(void)
+void __init msm7x01_timer_init(void)
{
struct clocksource *cs = &msm_clocksource;
@@ -330,28 +321,16 @@ static void __init msm7x01_timer_init(void)
false);
}
-struct sys_timer msm7x01_timer = {
- .init = msm7x01_timer_init
-};
-
-static void __init msm7x30_timer_init(void)
+void __init msm7x30_timer_init(void)
{
if (msm_timer_map(0xc0100004, 0xc0100024))
return;
msm_timer_init(24576000 / 4, 32, 1, false);
}
-struct sys_timer msm7x30_timer = {
- .init = msm7x30_timer_init
-};
-
-static void __init qsd8x50_timer_init(void)
+void __init qsd8x50_timer_init(void)
{
if (msm_timer_map(0xAC100000, 0xAC100010))
return;
msm_timer_init(19200000 / 4, 32, 7, false);
}
-
-struct sys_timer qsd8x50_timer = {
- .init = qsd8x50_timer_init
-};
diff --git a/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c b/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
index ee74ec97c141..1f2ef98b37c6 100644
--- a/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
+++ b/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
@@ -150,6 +150,6 @@ MACHINE_START(TERASTATION_WXL, "Buffalo Nas WXL")
.map_io = mv78xx0_map_io,
.init_early = mv78xx0_init_early,
.init_irq = mv78xx0_init_irq,
- .timer = &mv78xx0_timer,
+ .init_time = mv78xx0_timer_init,
.restart = mv78xx0_restart,
MACHINE_END
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
index d0cb4857b4b3..0efa14498ebc 100644
--- a/arch/arm/mach-mv78xx0/common.c
+++ b/arch/arm/mach-mv78xx0/common.c
@@ -336,16 +336,12 @@ void __init mv78xx0_init_early(void)
orion_time_set_base(TIMER_VIRT_BASE);
}
-static void __init_refok mv78xx0_timer_init(void)
+void __init_refok mv78xx0_timer_init(void)
{
orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
IRQ_MV78XX0_TIMER_1, get_tclk());
}
-struct sys_timer mv78xx0_timer = {
- .init = mv78xx0_timer_init,
-};
-
/*****************************************************************************
* General
diff --git a/arch/arm/mach-mv78xx0/common.h b/arch/arm/mach-mv78xx0/common.h
index 507c767d49e0..5e9485bad0ac 100644
--- a/arch/arm/mach-mv78xx0/common.h
+++ b/arch/arm/mach-mv78xx0/common.h
@@ -47,7 +47,7 @@ void mv78xx0_uart3_init(void);
void mv78xx0_i2c_init(void);
void mv78xx0_restart(char, const char *);
-extern struct sys_timer mv78xx0_timer;
+extern void mv78xx0_timer_init(void);
#endif
diff --git a/arch/arm/mach-mv78xx0/db78x00-bp-setup.c b/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
index 4d6d48bf51ef..4e0f22b30bc8 100644
--- a/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
+++ b/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
@@ -98,6 +98,6 @@ MACHINE_START(DB78X00_BP, "Marvell DB-78x00-BP Development Board")
.map_io = mv78xx0_map_io,
.init_early = mv78xx0_init_early,
.init_irq = mv78xx0_init_irq,
- .timer = &mv78xx0_timer,
+ .init_time = mv78xx0_timer_init,
.restart = mv78xx0_restart,
MACHINE_END
diff --git a/arch/arm/mach-mv78xx0/include/mach/uncompress.h b/arch/arm/mach-mv78xx0/include/mach/uncompress.h
index 365264298e79..6a761c44a296 100644
--- a/arch/arm/mach-mv78xx0/include/mach/uncompress.h
+++ b/arch/arm/mach-mv78xx0/include/mach/uncompress.h
@@ -44,4 +44,3 @@ static void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c b/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
index 9a882706e138..d2d06f3957f3 100644
--- a/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
+++ b/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
@@ -83,6 +83,6 @@ MACHINE_START(RD78X00_MASA, "Marvell RD-78x00-MASA Development Board")
.map_io = mv78xx0_map_io,
.init_early = mv78xx0_init_early,
.init_irq = mv78xx0_init_irq,
- .timer = &mv78xx0_timer,
+ .init_time = mv78xx0_timer_init,
.restart = mv78xx0_restart,
MACHINE_END
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 99df4df680fd..da93bcbc74c1 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -3,7 +3,8 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
AFLAGS_coherency_ll.o := -Wa,-march=armv7-a
-obj-y += system-controller.o
-obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o coherency.o coherency_ll.o pmsu.o
+obj-y += system-controller.o
+obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o
+obj-$(CONFIG_ARCH_MVEBU) += addr-map.o coherency.o coherency_ll.o pmsu.o irq-armada-370-xp.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c
index 7434b5e36197..a5ea616d6d12 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.c
+++ b/arch/arm/mach-mvebu/armada-370-xp.c
@@ -56,10 +56,6 @@ void __init armada_370_xp_init_early(void)
init_dma_coherent_pool_size(SZ_1M);
}
-struct sys_timer armada_370_xp_timer = {
- .init = armada_370_xp_timer_and_clk_init,
-};
-
static void __init armada_370_xp_dt_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
@@ -78,7 +74,7 @@ DT_MACHINE_START(ARMADA_XP_DT, "Marvell Armada 370/XP (Device Tree)")
.init_early = armada_370_xp_init_early,
.init_irq = armada_370_xp_init_irq,
.handle_irq = armada_370_xp_handle_irq,
- .timer = &armada_370_xp_timer,
+ .init_time = armada_370_xp_timer_and_clk_init,
.restart = mvebu_restart,
.dt_compat = armada_370_xp_dt_compat,
MACHINE_END
diff --git a/arch/arm/mach-mxs/include/mach/uncompress.h b/arch/arm/mach-mxs/include/mach/uncompress.h
index ef2811495446..533f5186e200 100644
--- a/arch/arm/mach-mxs/include/mach/uncompress.h
+++ b/arch/arm/mach-mxs/include/mach/uncompress.h
@@ -72,6 +72,5 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
}
#define arch_decomp_setup() __arch_decomp_setup(arch_id)
-#define arch_decomp_wdog()
#endif /* __MACH_MXS_UNCOMPRESS_H__ */
diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c
index c66129b5dd18..052186713347 100644
--- a/arch/arm/mach-mxs/mach-mxs.c
+++ b/arch/arm/mach-mxs/mach-mxs.c
@@ -119,6 +119,23 @@ static struct fb_videomode apf28dev_video_modes[] = {
},
};
+static struct fb_videomode cfa10049_video_modes[] = {
+ {
+ .name = "Himax HX8357-B",
+ .refresh = 60,
+ .xres = 320,
+ .yres = 480,
+ .pixclock = 108506, /* picosecond (9.216 MHz) */
+ .left_margin = 2,
+ .right_margin = 2,
+ .upper_margin = 2,
+ .lower_margin = 2,
+ .hsync_len = 15,
+ .vsync_len = 15,
+ .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT
+ },
+};
+
static struct mxsfb_platform_data mxsfb_pdata __initdata;
/*
@@ -163,19 +180,11 @@ static void __init imx23_timer_init(void)
mx23_clocks_init();
}
-static struct sys_timer imx23_timer = {
- .init = imx23_timer_init,
-};
-
static void __init imx28_timer_init(void)
{
mx28_clocks_init();
}
-static struct sys_timer imx28_timer = {
- .init = imx28_timer_init,
-};
-
enum mac_oui {
OUI_FSL,
OUI_DENX,
@@ -395,6 +404,17 @@ static void __init cfa10049_init(void)
update_fec_mac_prop(OUI_CRYSTALFONTZ);
}
+static void __init cfa10037_init(void)
+{
+ enable_clk_enet_out();
+ update_fec_mac_prop(OUI_CRYSTALFONTZ);
+
+ mxsfb_pdata.mode_list = cfa10049_video_modes;
+ mxsfb_pdata.mode_count = ARRAY_SIZE(cfa10049_video_modes);
+ mxsfb_pdata.default_bpp = 32;
+ mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT;
+}
+
static void __init apf28_init(void)
{
enable_clk_enet_out();
@@ -415,6 +435,8 @@ static void __init mxs_machine_init(void)
m28evk_init();
else if (of_machine_is_compatible("bluegiga,apx4devkit"))
apx4devkit_init();
+ else if (of_machine_is_compatible("crystalfontz,cfa10037"))
+ cfa10037_init();
else if (of_machine_is_compatible("crystalfontz,cfa10049"))
cfa10049_init();
else if (of_machine_is_compatible("armadeus,imx28-apf28"))
@@ -446,7 +468,7 @@ DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)")
.map_io = mx23_map_io,
.init_irq = icoll_init_irq,
.handle_irq = icoll_handle_irq,
- .timer = &imx23_timer,
+ .init_time = imx23_timer_init,
.init_machine = mxs_machine_init,
.dt_compat = imx23_dt_compat,
.restart = mxs_restart,
@@ -456,7 +478,7 @@ DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)")
.map_io = mx28_map_io,
.init_irq = icoll_init_irq,
.handle_irq = icoll_handle_irq,
- .timer = &imx28_timer,
+ .init_time = imx28_timer_init,
.init_machine = mxs_machine_init,
.dt_compat = imx28_dt_compat,
.restart = mxs_restart,
diff --git a/arch/arm/mach-mxs/timer.c b/arch/arm/mach-mxs/timer.c
index 856f4c796061..421020498a1b 100644
--- a/arch/arm/mach-mxs/timer.c
+++ b/arch/arm/mach-mxs/timer.c
@@ -72,8 +72,9 @@
#define BM_TIMROT_TIMCTRLn_IRQ_EN (1 << 14)
#define BM_TIMROT_TIMCTRLn_IRQ (1 << 15)
#define BP_TIMROT_TIMCTRLn_SELECT 0
-#define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL 0x8
-#define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL 0xb
+#define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL 0x8
+#define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL 0xb
+#define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS 0xf
static struct clock_event_device mxs_clockevent_device;
static enum clock_event_mode mxs_clockevent_mode = CLOCK_EVT_MODE_UNUSED;
@@ -195,7 +196,6 @@ static void mxs_set_mode(enum clock_event_mode mode,
static struct clock_event_device mxs_clockevent_device = {
.name = "mxs_timrot",
.features = CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.set_mode = mxs_set_mode,
.set_next_event = timrotv2_set_next_event,
.rating = 200,
@@ -203,25 +203,13 @@ static struct clock_event_device mxs_clockevent_device = {
static int __init mxs_clockevent_init(struct clk *timer_clk)
{
- unsigned int c = clk_get_rate(timer_clk);
-
- mxs_clockevent_device.mult =
- div_sc(c, NSEC_PER_SEC, mxs_clockevent_device.shift);
- mxs_clockevent_device.cpumask = cpumask_of(0);
- if (timrot_is_v1()) {
+ if (timrot_is_v1())
mxs_clockevent_device.set_next_event = timrotv1_set_next_event;
- mxs_clockevent_device.max_delta_ns =
- clockevent_delta2ns(0xfffe, &mxs_clockevent_device);
- mxs_clockevent_device.min_delta_ns =
- clockevent_delta2ns(0xf, &mxs_clockevent_device);
- } else {
- mxs_clockevent_device.max_delta_ns =
- clockevent_delta2ns(0xfffffffe, &mxs_clockevent_device);
- mxs_clockevent_device.min_delta_ns =
- clockevent_delta2ns(0xf, &mxs_clockevent_device);
- }
-
- clockevents_register_device(&mxs_clockevent_device);
+ mxs_clockevent_device.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&mxs_clockevent_device,
+ clk_get_rate(timer_clk),
+ timrot_is_v1() ? 0xf : 0x2,
+ timrot_is_v1() ? 0xfffe : 0xfffffffe);
return 0;
}
@@ -288,7 +276,7 @@ void __init mxs_timer_init(void)
/* one for clock_event */
__raw_writel((timrot_is_v1() ?
BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
- BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL) |
+ BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
BM_TIMROT_TIMCTRLn_UPDATE |
BM_TIMROT_TIMCTRLn_IRQ_EN,
mxs_timrot_base + HW_TIMROT_TIMCTRLn(0));
@@ -296,7 +284,7 @@ void __init mxs_timer_init(void)
/* another for clocksource */
__raw_writel((timrot_is_v1() ?
BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
- BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL) |
+ BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
BM_TIMROT_TIMCTRLn_RELOAD,
mxs_timrot_base + HW_TIMROT_TIMCTRLn(1));
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index aa627465d914..27c2cb7ab813 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -23,9 +23,9 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-vic.h>
#include <mach/hardware.h>
#include <asm/mach/map.h>
-#include <asm/hardware/vic.h>
#include <mach/netx-regs.h>
#include <asm/mach/irq.h>
diff --git a/arch/arm/mach-netx/generic.h b/arch/arm/mach-netx/generic.h
index 9b915119b8d6..768b26bbb42b 100644
--- a/arch/arm/mach-netx/generic.h
+++ b/arch/arm/mach-netx/generic.h
@@ -21,5 +21,4 @@ extern void __init netx_map_io(void);
extern void __init netx_init_irq(void);
extern void netx_restart(char, const char *);
-struct sys_timer;
-extern struct sys_timer netx_timer;
+extern void netx_timer_init(void);
diff --git a/arch/arm/mach-netx/include/mach/uncompress.h b/arch/arm/mach-netx/include/mach/uncompress.h
index 84f91284f612..5cb1051b5831 100644
--- a/arch/arm/mach-netx/include/mach/uncompress.h
+++ b/arch/arm/mach-netx/include/mach/uncompress.h
@@ -73,4 +73,3 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-netx/nxdb500.c b/arch/arm/mach-netx/nxdb500.c
index 8b781ff7c9e9..9b558eb3070f 100644
--- a/arch/arm/mach-netx/nxdb500.c
+++ b/arch/arm/mach-netx/nxdb500.c
@@ -28,7 +28,6 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/vic.h>
#include <mach/netx-regs.h>
#include <linux/platform_data/eth-netx.h>
@@ -204,8 +203,7 @@ MACHINE_START(NXDB500, "Hilscher nxdb500")
.atag_offset = 0x100,
.map_io = netx_map_io,
.init_irq = netx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &netx_timer,
+ .init_time = netx_timer_init,
.init_machine = nxdb500_init,
.restart = netx_restart,
MACHINE_END
diff --git a/arch/arm/mach-netx/nxdkn.c b/arch/arm/mach-netx/nxdkn.c
index b26dbce334f2..a5e86cd365e7 100644
--- a/arch/arm/mach-netx/nxdkn.c
+++ b/arch/arm/mach-netx/nxdkn.c
@@ -28,7 +28,6 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/vic.h>
#include <mach/netx-regs.h>
#include <linux/platform_data/eth-netx.h>
@@ -97,8 +96,7 @@ MACHINE_START(NXDKN, "Hilscher nxdkn")
.atag_offset = 0x100,
.map_io = netx_map_io,
.init_irq = netx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &netx_timer,
+ .init_time = netx_timer_init,
.init_machine = nxdkn_init,
.restart = netx_restart,
MACHINE_END
diff --git a/arch/arm/mach-netx/nxeb500hmi.c b/arch/arm/mach-netx/nxeb500hmi.c
index 257382efafa0..ad17885d0159 100644
--- a/arch/arm/mach-netx/nxeb500hmi.c
+++ b/arch/arm/mach-netx/nxeb500hmi.c
@@ -28,7 +28,6 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/vic.h>
#include <mach/netx-regs.h>
#include <linux/platform_data/eth-netx.h>
@@ -181,8 +180,7 @@ MACHINE_START(NXEB500HMI, "Hilscher nxeb500hmi")
.atag_offset = 0x100,
.map_io = netx_map_io,
.init_irq = netx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &netx_timer,
+ .init_time = netx_timer_init,
.init_machine = nxeb500hmi_init,
.restart = netx_restart,
MACHINE_END
diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c
index e24c141ba489..6df42e643031 100644
--- a/arch/arm/mach-netx/time.c
+++ b/arch/arm/mach-netx/time.c
@@ -76,7 +76,6 @@ static int netx_set_next_event(unsigned long evt,
static struct clock_event_device netx_clockevent = {
.name = "netx-timer" __stringify(TIMER_CLOCKEVENT),
- .shift = 32,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = netx_set_next_event,
.set_mode = netx_set_mode,
@@ -107,7 +106,7 @@ static struct irqaction netx_timer_irq = {
/*
* Set up timer interrupt
*/
-static void __init netx_timer_init(void)
+void __init netx_timer_init(void)
{
/* disable timer initially */
writel(0, NETX_GPIO_COUNTER_CTRL(0));
@@ -140,18 +139,9 @@ static void __init netx_timer_init(void)
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);
- netx_clockevent.max_delta_ns =
- clockevent_delta2ns(0xfffffffe, &netx_clockevent);
/* with max_delta_ns >= delta2ns(0x800) the system currently runs fine.
* Adding some safety ... */
- netx_clockevent.min_delta_ns =
- clockevent_delta2ns(0xa00, &netx_clockevent);
netx_clockevent.cpumask = cpumask_of(0);
- clockevents_register_device(&netx_clockevent);
+ clockevents_config_and_register(&netx_clockevent, CLOCK_TICK_RATE,
+ 0xa00, 0xfffffffe);
}
-
-struct sys_timer netx_timer = {
- .init = netx_timer_init,
-};
diff --git a/arch/arm/mach-nomadik/Kconfig b/arch/arm/mach-nomadik/Kconfig
index 706dc5727bbe..82226a5d60ef 100644
--- a/arch/arm/mach-nomadik/Kconfig
+++ b/arch/arm/mach-nomadik/Kconfig
@@ -4,19 +4,13 @@ menu "Nomadik boards"
config MACH_NOMADIK_8815NHK
bool "ST 8815 Nomadik Hardware Kit (evaluation board)"
- select CLKSRC_NOMADIK_MTU
select NOMADIK_8815
+ select I2C
+ select I2C_ALGOBIT
endmenu
config NOMADIK_8815
bool
-config I2C_BITBANG_8815NHK
- tristate "Driver for bit-bang busses found on the 8815 NHK"
- depends on I2C && MACH_NOMADIK_8815NHK
- depends on PINCTRL_NOMADIK
- default y
- select I2C_ALGOBIT
-
endif
diff --git a/arch/arm/mach-nomadik/Makefile b/arch/arm/mach-nomadik/Makefile
index a42c9a33d3bf..1071c3b04d1a 100644
--- a/arch/arm/mach-nomadik/Makefile
+++ b/arch/arm/mach-nomadik/Makefile
@@ -9,9 +9,3 @@
# Cpu revision
obj-$(CONFIG_NOMADIK_8815) += cpu-8815.o
-
-# Specific board support
-obj-$(CONFIG_MACH_NOMADIK_8815NHK) += board-nhk8815.o
-
-# Nomadik extra devices
-obj-$(CONFIG_I2C_BITBANG_8815NHK) += i2c-8815nhk.o
diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
deleted file mode 100644
index 9f19069248da..000000000000
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * linux/arch/arm/mach-nomadik/board-8815nhk.c
- *
- * Copyright (C) STMicroelectronics
- *
- * 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.
- *
- * NHK15 board specifc driver definition
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/mmci.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/fsmc.h>
-#include <linux/mtd/onenand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/i2c.h>
-#include <linux/io.h>
-#include <linux/pinctrl/machine.h>
-#include <linux/platform_data/pinctrl-nomadik.h>
-#include <linux/platform_data/clocksource-nomadik-mtu.h>
-#include <asm/hardware/vic.h>
-#include <asm/sizes.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-#include <asm/mach/time.h>
-#include <mach/irqs.h>
-
-#include "cpu-8815.h"
-
-/* Initial value for SRC control register: all timers use MXTAL/8 source */
-#define SRC_CR_INIT_MASK 0x00007fff
-#define SRC_CR_INIT_VAL 0x2aaa8000
-
-#define ALE_OFF 0x1000000
-#define CLE_OFF 0x800000
-
-/* These addresses span 16MB, so use three individual pages */
-static struct resource nhk8815_nand_resources[] = {
- {
- .name = "nand_data",
- .start = 0x40000000,
- .end = 0x40000000 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "nand_addr",
- .start = 0x40000000 + ALE_OFF,
- .end = 0x40000000 +ALE_OFF + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "nand_cmd",
- .start = 0x40000000 + CLE_OFF,
- .end = 0x40000000 + CLE_OFF + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "fsmc_regs",
- .start = NOMADIK_FSMC_BASE,
- .end = NOMADIK_FSMC_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-/*
- * These partitions are the same as those used in the 2.6.20 release
- * shipped by the vendor; the first two partitions are mandated
- * by the boot ROM, and the bootloader area is somehow oversized...
- */
-static struct mtd_partition nhk8815_partitions[] = {
- {
- .name = "X-Loader(NAND)",
- .offset = 0,
- .size = SZ_256K,
- }, {
- .name = "MemInit(NAND)",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_256K,
- }, {
- .name = "BootLoader(NAND)",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_2M,
- }, {
- .name = "Kernel zImage(NAND)",
- .offset = MTDPART_OFS_APPEND,
- .size = 3 * SZ_1M,
- }, {
- .name = "Root Filesystem(NAND)",
- .offset = MTDPART_OFS_APPEND,
- .size = 22 * SZ_1M,
- }, {
- .name = "User Filesystem(NAND)",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- }
-};
-
-static struct fsmc_nand_timings nhk8815_nand_timings = {
- .thiz = 0,
- .thold = 0x10,
- .twait = 0x0A,
- .tset = 0,
-};
-
-static struct fsmc_nand_platform_data nhk8815_nand_platform_data = {
- .nand_timings = &nhk8815_nand_timings,
- .partitions = nhk8815_partitions,
- .nr_partitions = ARRAY_SIZE(nhk8815_partitions),
- .width = FSMC_NAND_BW8,
-};
-
-static struct platform_device nhk8815_nand_device = {
- .name = "fsmc-nand",
- .id = -1,
- .resource = nhk8815_nand_resources,
- .num_resources = ARRAY_SIZE(nhk8815_nand_resources),
- .dev = {
- .platform_data = &nhk8815_nand_platform_data,
- },
-};
-
-/* These are the partitions for the OneNand device, different from above */
-static struct mtd_partition nhk8815_onenand_partitions[] = {
- {
- .name = "X-Loader(OneNAND)",
- .offset = 0,
- .size = SZ_256K,
- }, {
- .name = "MemInit(OneNAND)",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_256K,
- }, {
- .name = "BootLoader(OneNAND)",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_2M-SZ_256K,
- }, {
- .name = "SysImage(OneNAND)",
- .offset = MTDPART_OFS_APPEND,
- .size = 4 * SZ_1M,
- }, {
- .name = "Root Filesystem(OneNAND)",
- .offset = MTDPART_OFS_APPEND,
- .size = 22 * SZ_1M,
- }, {
- .name = "User Filesystem(OneNAND)",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- }
-};
-
-static struct onenand_platform_data nhk8815_onenand_data = {
- .parts = nhk8815_onenand_partitions,
- .nr_parts = ARRAY_SIZE(nhk8815_onenand_partitions),
-};
-
-static struct resource nhk8815_onenand_resource[] = {
- {
- .start = 0x30000000,
- .end = 0x30000000 + SZ_128K - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device nhk8815_onenand_device = {
- .name = "onenand-flash",
- .id = -1,
- .dev = {
- .platform_data = &nhk8815_onenand_data,
- },
- .resource = nhk8815_onenand_resource,
- .num_resources = ARRAY_SIZE(nhk8815_onenand_resource),
-};
-
-/* bus control reg. and bus timing reg. for CS0..CS3 */
-#define FSMC_BCR(x) (NOMADIK_FSMC_VA + (x << 3))
-#define FSMC_BTR(x) (NOMADIK_FSMC_VA + (x << 3) + 0x04)
-
-static void __init nhk8815_onenand_init(void)
-{
-#ifdef CONFIG_MTD_ONENAND
- /* Set up SMCS0 for OneNand */
- writel(0x000030db, FSMC_BCR(0));
- writel(0x02100551, FSMC_BTR(0));
-#endif
-}
-
-static struct mmci_platform_data mmcsd_plat_data = {
- .ocr_mask = MMC_VDD_29_30,
- .f_max = 48000000,
- .gpio_wp = -1,
- .gpio_cd = 111,
- .cd_invert = true,
- .capabilities = MMC_CAP_MMC_HIGHSPEED |
- MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA,
-};
-
-static int __init nhk8815_mmcsd_init(void)
-{
- int ret;
-
- ret = gpio_request(112, "card detect bias");
- if (ret)
- return ret;
- gpio_direction_output(112, 0);
- amba_apb_device_add(NULL, "mmci", NOMADIK_SDI_BASE, SZ_4K, IRQ_SDMMC, 0, &mmcsd_plat_data, 0x10180180);
- return 0;
-}
-module_init(nhk8815_mmcsd_init);
-
-static struct resource nhk8815_eth_resources[] = {
- {
- .name = "smc91x-regs",
- .start = 0x34000000 + 0x300,
- .end = 0x34000000 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = NOMADIK_GPIO_TO_IRQ(115),
- .end = NOMADIK_GPIO_TO_IRQ(115),
- .flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
- }
-};
-
-static struct platform_device nhk8815_eth_device = {
- .name = "smc91x",
- .resource = nhk8815_eth_resources,
- .num_resources = ARRAY_SIZE(nhk8815_eth_resources),
-};
-
-static int __init nhk8815_eth_init(void)
-{
- int gpio_nr = 115; /* hardwired in the board */
- int err;
-
- err = gpio_request(gpio_nr, "eth_irq");
- if (!err) err = nmk_gpio_set_mode(gpio_nr, NMK_GPIO_ALT_GPIO);
- if (!err) err = gpio_direction_input(gpio_nr);
- if (err)
- pr_err("Error %i in %s\n", err, __func__);
- return err;
-}
-device_initcall(nhk8815_eth_init);
-
-static struct platform_device *nhk8815_platform_devices[] __initdata = {
- &nhk8815_nand_device,
- &nhk8815_onenand_device,
- &nhk8815_eth_device,
- /* will add more devices */
-};
-
-static void __init nomadik_timer_init(void)
-{
- u32 src_cr;
-
- /* Configure timer sources in "system reset controller" ctrl reg */
- src_cr = readl(io_p2v(NOMADIK_SRC_BASE));
- src_cr &= SRC_CR_INIT_MASK;
- src_cr |= SRC_CR_INIT_VAL;
- writel(src_cr, io_p2v(NOMADIK_SRC_BASE));
-
- nmdk_timer_init(io_p2v(NOMADIK_MTU0_BASE), IRQ_MTU0);
-}
-
-static struct sys_timer nomadik_timer = {
- .init = nomadik_timer_init,
-};
-
-static struct i2c_board_info __initdata nhk8815_i2c0_devices[] = {
- {
- I2C_BOARD_INFO("stw4811", 0x2d),
- },
-};
-
-static struct i2c_board_info __initdata nhk8815_i2c1_devices[] = {
- {
- I2C_BOARD_INFO("camera", 0x10),
- },
- {
- I2C_BOARD_INFO("stw5095", 0x1a),
- },
- {
- I2C_BOARD_INFO("lis3lv02dl", 0x1d),
- },
-};
-
-static struct i2c_board_info __initdata nhk8815_i2c2_devices[] = {
- {
- I2C_BOARD_INFO("stw4811-usb", 0x2d),
- },
-};
-
-static unsigned long out_low[] = { PIN_OUTPUT_LOW };
-static unsigned long out_high[] = { PIN_OUTPUT_HIGH };
-static unsigned long in_nopull[] = { PIN_INPUT_NOPULL };
-static unsigned long in_pullup[] = { PIN_INPUT_PULLUP };
-
-static struct pinctrl_map __initdata nhk8815_pinmap[] = {
- PIN_MAP_MUX_GROUP_DEFAULT("uart0", "pinctrl-stn8815", "u0_a_1", "u0"),
- PIN_MAP_MUX_GROUP_DEFAULT("uart1", "pinctrl-stn8815", "u1_a_1", "u1"),
- /* Hog in MMC/SD card mux */
- PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-stn8815", "mmcsd_a_1", "mmcsd"),
- /* MCCLK */
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO8_B10", out_low),
- /* MCCMD */
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO9_A10", in_pullup),
- /* MCCMDDIR */
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO10_C11", out_high),
- /* MCDAT3-0 */
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO11_B11", in_pullup),
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO12_A11", in_pullup),
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO13_C12", in_pullup),
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO14_B12", in_pullup),
- /* MCDAT0DIR */
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO15_A12", out_high),
- /* MCDAT31DIR */
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO16_C13", out_high),
- /* MCMSFBCLK */
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO24_C15", in_pullup),
- /* CD input GPIO */
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO111_H21", in_nopull),
- /* CD bias drive */
- PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO112_J21", out_low),
-};
-
-static void __init nhk8815_platform_init(void)
-{
- pinctrl_register_mappings(nhk8815_pinmap, ARRAY_SIZE(nhk8815_pinmap));
- cpu8815_platform_init();
- nhk8815_onenand_init();
- platform_add_devices(nhk8815_platform_devices,
- ARRAY_SIZE(nhk8815_platform_devices));
-
- amba_apb_device_add(NULL, "uart0", NOMADIK_UART0_BASE, SZ_4K, IRQ_UART0, 0, NULL, 0);
- amba_apb_device_add(NULL, "uart1", NOMADIK_UART1_BASE, SZ_4K, IRQ_UART1, 0, NULL, 0);
-
- i2c_register_board_info(0, nhk8815_i2c0_devices,
- ARRAY_SIZE(nhk8815_i2c0_devices));
- i2c_register_board_info(1, nhk8815_i2c1_devices,
- ARRAY_SIZE(nhk8815_i2c1_devices));
- i2c_register_board_info(2, nhk8815_i2c2_devices,
- ARRAY_SIZE(nhk8815_i2c2_devices));
-}
-
-MACHINE_START(NOMADIK, "NHK8815")
- /* Maintainer: ST MicroElectronics */
- .atag_offset = 0x100,
- .map_io = cpu8815_map_io,
- .init_irq = cpu8815_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &nomadik_timer,
- .init_machine = nhk8815_platform_init,
- .restart = cpu8815_restart,
-MACHINE_END
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
index 1273931303fb..21c1aa512640 100644
--- a/arch/arm/mach-nomadik/cpu-8815.c
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -25,138 +25,308 @@
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/dma-mapping.h>
+#include <linux/irqchip.h>
#include <linux/platform_data/clk-nomadik.h>
#include <linux/platform_data/pinctrl-nomadik.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/platform_data/clocksource-nomadik-mtu.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/mtd/fsmc.h>
+#include <linux/gpio.h>
+#include <linux/amba/mmci.h>
-#include <mach/hardware.h>
#include <mach/irqs.h>
+#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <asm/hardware/vic.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
#include <asm/cacheflush.h>
#include <asm/hardware/cache-l2x0.h>
-#include "cpu-8815.h"
+/*
+ * These are the only hard-coded address offsets we still have to use.
+ */
+#define NOMADIK_FSMC_BASE 0x10100000 /* FSMC registers */
+#define NOMADIK_SDRAMC_BASE 0x10110000 /* SDRAM Controller */
+#define NOMADIK_CLCDC_BASE 0x10120000 /* CLCD Controller */
+#define NOMADIK_MDIF_BASE 0x10120000 /* MDIF */
+#define NOMADIK_DMA0_BASE 0x10130000 /* DMA0 Controller */
+#define NOMADIK_IC_BASE 0x10140000 /* Vectored Irq Controller */
+#define NOMADIK_DMA1_BASE 0x10150000 /* DMA1 Controller */
+#define NOMADIK_USB_BASE 0x10170000 /* USB-OTG conf reg base */
+#define NOMADIK_CRYP_BASE 0x10180000 /* Crypto processor */
+#define NOMADIK_SHA1_BASE 0x10190000 /* SHA-1 Processor */
+#define NOMADIK_XTI_BASE 0x101A0000 /* XTI */
+#define NOMADIK_RNG_BASE 0x101B0000 /* Random number generator */
+#define NOMADIK_SRC_BASE 0x101E0000 /* SRC base */
+#define NOMADIK_WDOG_BASE 0x101E1000 /* Watchdog */
+#define NOMADIK_MTU0_BASE 0x101E2000 /* Multiple Timer 0 */
+#define NOMADIK_MTU1_BASE 0x101E3000 /* Multiple Timer 1 */
+#define NOMADIK_GPIO0_BASE 0x101E4000 /* GPIO0 */
+#define NOMADIK_GPIO1_BASE 0x101E5000 /* GPIO1 */
+#define NOMADIK_GPIO2_BASE 0x101E6000 /* GPIO2 */
+#define NOMADIK_GPIO3_BASE 0x101E7000 /* GPIO3 */
+#define NOMADIK_RTC_BASE 0x101E8000 /* Real Time Clock base */
+#define NOMADIK_PMU_BASE 0x101E9000 /* Power Management Unit */
+#define NOMADIK_OWM_BASE 0x101EA000 /* One wire master */
+#define NOMADIK_SCR_BASE 0x101EF000 /* Secure Control registers */
+#define NOMADIK_MSP2_BASE 0x101F0000 /* MSP 2 interface */
+#define NOMADIK_MSP1_BASE 0x101F1000 /* MSP 1 interface */
+#define NOMADIK_UART2_BASE 0x101F2000 /* UART 2 interface */
+#define NOMADIK_SSIRx_BASE 0x101F3000 /* SSI 8-ch rx interface */
+#define NOMADIK_SSITx_BASE 0x101F4000 /* SSI 8-ch tx interface */
+#define NOMADIK_MSHC_BASE 0x101F5000 /* Memory Stick(Pro) Host */
+#define NOMADIK_SDI_BASE 0x101F6000 /* SD-card/MM-Card */
+#define NOMADIK_I2C1_BASE 0x101F7000 /* I2C1 interface */
+#define NOMADIK_I2C0_BASE 0x101F8000 /* I2C0 interface */
+#define NOMADIK_MSP0_BASE 0x101F9000 /* MSP 0 interface */
+#define NOMADIK_FIRDA_BASE 0x101FA000 /* FIrDA interface */
+#define NOMADIK_UART1_BASE 0x101FB000 /* UART 1 interface */
+#define NOMADIK_SSP_BASE 0x101FC000 /* SSP interface */
+#define NOMADIK_UART0_BASE 0x101FD000 /* UART 0 interface */
+#define NOMADIK_SGA_BASE 0x101FE000 /* SGA interface */
+#define NOMADIK_L2CC_BASE 0x10210000 /* L2 Cache controller */
+#define NOMADIK_UART1_VBASE 0xF01FB000
-/* The 8815 has 4 GPIO blocks, let's register them immediately */
-static resource_size_t __initdata cpu8815_gpio_base[] = {
- NOMADIK_GPIO0_BASE,
- NOMADIK_GPIO1_BASE,
- NOMADIK_GPIO2_BASE,
- NOMADIK_GPIO3_BASE,
+static unsigned long out_low[] = { PIN_OUTPUT_LOW };
+static unsigned long out_high[] = { PIN_OUTPUT_HIGH };
+static unsigned long in_nopull[] = { PIN_INPUT_NOPULL };
+static unsigned long in_pullup[] = { PIN_INPUT_PULLUP };
+
+static struct pinctrl_map __initdata nhk8815_pinmap[] = {
+ PIN_MAP_MUX_GROUP_DEFAULT("uart0", "pinctrl-stn8815", "u0_a_1", "u0"),
+ PIN_MAP_MUX_GROUP_DEFAULT("uart1", "pinctrl-stn8815", "u1_a_1", "u1"),
+ /* Hog in MMC/SD card mux */
+ PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-stn8815", "mmcsd_a_1", "mmcsd"),
+ /* MCCLK */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO8_B10", out_low),
+ /* MCCMD */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO9_A10", in_pullup),
+ /* MCCMDDIR */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO10_C11", out_high),
+ /* MCDAT3-0 */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO11_B11", in_pullup),
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO12_A11", in_pullup),
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO13_C12", in_pullup),
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO14_B12", in_pullup),
+ /* MCDAT0DIR */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO15_A12", out_high),
+ /* MCDAT31DIR */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO16_C13", out_high),
+ /* MCMSFBCLK */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO24_C15", in_pullup),
+ /* CD input GPIO */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO111_H21", in_nopull),
+ /* CD bias drive */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO112_J21", out_low),
+ /* I2C0 */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO62_D3", in_pullup),
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO63_D2", in_pullup),
+ /* I2C1 */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO53_L4", in_pullup),
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO54_L3", in_pullup),
+ /* I2C2 */
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO73_C21", in_pullup),
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO74_C20", in_pullup),
};
-static struct platform_device *
-cpu8815_add_gpio(int id, resource_size_t addr, int irq,
- struct nmk_gpio_platform_data *pdata)
+/* This is needed for LL-debug/earlyprintk/debug-macro.S */
+static struct map_desc cpu8815_io_desc[] __initdata = {
+ {
+ .virtual = NOMADIK_UART1_VBASE,
+ .pfn = __phys_to_pfn(NOMADIK_UART1_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ },
+};
+
+static void __init cpu8815_map_io(void)
{
- struct resource resources[] = {
- {
- .start = addr,
- .end = addr + 127,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = irq,
- .end = irq,
- .flags = IORESOURCE_IRQ,
- }
- };
-
- return platform_device_register_resndata(NULL, "gpio", id,
- resources, ARRAY_SIZE(resources),
- pdata, sizeof(*pdata));
+ iotable_init(cpu8815_io_desc, ARRAY_SIZE(cpu8815_io_desc));
}
-void cpu8815_add_gpios(resource_size_t *base, int num, int irq,
- struct nmk_gpio_platform_data *pdata)
+static void cpu8815_restart(char mode, const char *cmd)
{
- int first = 0;
- int i;
+ void __iomem *srcbase = ioremap(NOMADIK_SRC_BASE, SZ_4K);
- for (i = 0; i < num; i++, first += 32, irq++) {
- pdata->first_gpio = first;
- pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first);
- pdata->num_gpio = 32;
+ /* FIXME: use egpio when implemented */
- cpu8815_add_gpio(i, base[i], irq, pdata);
- }
+ /* Write anything to Reset status register */
+ writel(1, srcbase + 0x18);
}
-static inline void
-cpu8815_add_pinctrl(struct device *parent, const char *name)
+/* Initial value for SRC control register: all timers use MXTAL/8 source */
+#define SRC_CR_INIT_MASK 0x00007fff
+#define SRC_CR_INIT_VAL 0x2aaa8000
+
+static void __init cpu8815_timer_init_of(void)
{
- struct platform_device_info pdevinfo = {
- .parent = parent,
- .name = name,
- .id = -1,
- };
+ struct device_node *mtu;
+ void __iomem *base;
+ int irq;
+ u32 src_cr;
+
+ /* We need this to be up now */
+ nomadik_clk_init();
+
+ mtu = of_find_node_by_path("/mtu0");
+ if (!mtu)
+ return;
+ base = of_iomap(mtu, 0);
+ if (WARN_ON(!base))
+ return;
+ irq = irq_of_parse_and_map(mtu, 0);
- platform_device_register_full(&pdevinfo);
+ pr_info("Remapped MTU @ %p, irq: %d\n", base, irq);
+
+ /* Configure timer sources in "system reset controller" ctrl reg */
+ src_cr = readl(base);
+ src_cr &= SRC_CR_INIT_MASK;
+ src_cr |= SRC_CR_INIT_VAL;
+ writel(src_cr, base);
+
+ nmdk_timer_init(base, irq);
}
-static int __init cpu8815_init(void)
+static struct fsmc_nand_timings cpu8815_nand_timings = {
+ .thiz = 0,
+ .thold = 0x10,
+ .twait = 0x0A,
+ .tset = 0,
+};
+
+static struct fsmc_nand_platform_data cpu8815_nand_data = {
+ .nand_timings = &cpu8815_nand_timings,
+};
+
+/*
+ * The SMSC911x IRQ is connected to a GPIO pin, but the driver expects
+ * to simply request an IRQ passed as a resource. So the GPIO pin needs
+ * to be requested by this hog and set as input.
+ */
+static int __init cpu8815_eth_init(void)
{
- struct nmk_gpio_platform_data pdata = {
- /* No custom data yet */
- };
-
- cpu8815_add_gpios(cpu8815_gpio_base, ARRAY_SIZE(cpu8815_gpio_base),
- IRQ_GPIO0, &pdata);
- cpu8815_add_pinctrl(NULL, "pinctrl-stn8815");
- amba_apb_device_add(NULL, "rng", NOMADIK_RNG_BASE, SZ_4K, 0, 0, NULL, 0);
- amba_apb_device_add(NULL, "rtc-pl031", NOMADIK_RTC_BASE, SZ_4K, IRQ_RTC_RTT, 0, NULL, 0);
+ struct device_node *eth;
+ int gpio, irq, err;
+
+ eth = of_find_node_by_path("/usb-s8815/ethernet-gpio");
+ if (!eth) {
+ pr_info("could not find any ethernet GPIO\n");
+ return 0;
+ }
+ gpio = of_get_gpio(eth, 0);
+ err = gpio_request(gpio, "eth_irq");
+ if (err) {
+ pr_info("failed to request ethernet GPIO\n");
+ return -ENODEV;
+ }
+ err = gpio_direction_input(gpio);
+ if (err) {
+ pr_info("failed to set ethernet GPIO as input\n");
+ return -ENODEV;
+ }
+ irq = gpio_to_irq(gpio);
+ pr_info("enabled USB-S8815 ethernet GPIO %d, IRQ %d\n", gpio, irq);
return 0;
}
-arch_initcall(cpu8815_init);
+device_initcall(cpu8815_eth_init);
-/* All SoC devices live in the same area (see hardware.h) */
-static struct map_desc nomadik_io_desc[] __initdata = {
- {
- .virtual = NOMADIK_IO_VIRTUAL,
- .pfn = __phys_to_pfn(NOMADIK_IO_PHYSICAL),
- .length = NOMADIK_IO_SIZE,
- .type = MT_DEVICE,
- }
- /* static ram and secured ram may be added later */
+/*
+ * TODO:
+ * cannot be set from device tree, convert to a proper DT
+ * binding.
+ */
+static struct mmci_platform_data mmcsd_plat_data = {
+ .ocr_mask = MMC_VDD_29_30,
};
-void __init cpu8815_map_io(void)
+/*
+ * This GPIO pin turns on a line that is used to detect card insertion
+ * on this board.
+ */
+static int __init cpu8815_mmcsd_init(void)
{
- iotable_init(nomadik_io_desc, ARRAY_SIZE(nomadik_io_desc));
-}
+ struct device_node *cdbias;
+ int gpio, err;
-void __init cpu8815_init_irq(void)
-{
- /* This modified VIC cell has two register blocks, at 0 and 0x20 */
- vic_init(io_p2v(NOMADIK_IC_BASE + 0x00), IRQ_VIC_START + 0, ~0, 0);
- vic_init(io_p2v(NOMADIK_IC_BASE + 0x20), IRQ_VIC_START + 32, ~0, 0);
-
- /*
- * Init clocks here so that they are available for system timer
- * initialization.
- */
- nomadik_clk_init();
+ cdbias = of_find_node_by_path("/usb-s8815/mmcsd-gpio");
+ if (!cdbias) {
+ pr_info("could not find MMC/SD card detect bias node\n");
+ return 0;
+ }
+ gpio = of_get_gpio(cdbias, 0);
+ if (gpio < 0) {
+ pr_info("could not obtain MMC/SD card detect bias GPIO\n");
+ return 0;
+ }
+ err = gpio_request(gpio, "card detect bias");
+ if (err) {
+ pr_info("failed to request card detect bias GPIO %d\n", gpio);
+ return -ENODEV;
+ }
+ err = gpio_direction_output(gpio, 0);
+ if (err){
+ pr_info("failed to set GPIO %d as output, low\n", gpio);
+ return err;
+ }
+ pr_info("enabled USB-S8815 CD bias GPIO %d, low\n", gpio);
+ return 0;
}
+device_initcall(cpu8815_mmcsd_init);
-/*
- * This function is called from the board init ("init_machine").
- */
- void __init cpu8815_platform_init(void)
+
+/* These are mostly to get the right device names for the clock lookups */
+static struct of_dev_auxdata cpu8815_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("st,nomadik-gpio", NOMADIK_GPIO0_BASE,
+ "gpio.0", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", NOMADIK_GPIO1_BASE,
+ "gpio.1", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", NOMADIK_GPIO2_BASE,
+ "gpio.2", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", NOMADIK_GPIO3_BASE,
+ "gpio.3", NULL),
+ OF_DEV_AUXDATA("stericsson,nmk-pinctrl-stn8815", 0,
+ "pinctrl-stn8815", NULL),
+ OF_DEV_AUXDATA("arm,primecell", NOMADIK_UART0_BASE,
+ "uart0", NULL),
+ OF_DEV_AUXDATA("arm,primecell", NOMADIK_UART1_BASE,
+ "uart1", NULL),
+ OF_DEV_AUXDATA("arm,primecell", NOMADIK_RNG_BASE,
+ "rng", NULL),
+ OF_DEV_AUXDATA("arm,primecell", NOMADIK_RTC_BASE,
+ "rtc-pl031", NULL),
+ OF_DEV_AUXDATA("stericsson,fsmc-nand", NOMADIK_FSMC_BASE,
+ "fsmc-nand", &cpu8815_nand_data),
+ OF_DEV_AUXDATA("arm,primecell", NOMADIK_SDI_BASE,
+ "mmci", &mmcsd_plat_data),
+ { /* sentinel */ },
+};
+
+static void __init cpu8815_init_of(void)
{
#ifdef CONFIG_CACHE_L2X0
/* At full speed latency must be >=2, so 0x249 in low bits */
- l2x0_init(io_p2v(NOMADIK_L2CC_BASE), 0x00730249, 0xfe000fff);
+ l2x0_of_init(0x00730249, 0xfe000fff);
#endif
- return;
+ pinctrl_register_mappings(nhk8815_pinmap, ARRAY_SIZE(nhk8815_pinmap));
+ of_platform_populate(NULL, of_default_bus_match_table,
+ cpu8815_auxdata_lookup, NULL);
}
-void cpu8815_restart(char mode, const char *cmd)
-{
- void __iomem *src_rstsr = io_p2v(NOMADIK_SRC_BASE + 0x18);
-
- /* FIXME: use egpio when implemented */
+static const char * cpu8815_board_compat[] = {
+ "calaosystems,usb-s8815",
+ NULL,
+};
- /* Write anything to Reset status register */
- writel(1, src_rstsr);
-}
+DT_MACHINE_START(NOMADIK_DT, "Nomadik STn8815")
+ .map_io = cpu8815_map_io,
+ .init_irq = irqchip_init,
+ .init_time = cpu8815_timer_init_of,
+ .init_machine = cpu8815_init_of,
+ .restart = cpu8815_restart,
+ .dt_compat = cpu8815_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-nomadik/cpu-8815.h b/arch/arm/mach-nomadik/cpu-8815.h
deleted file mode 100644
index 71c21e8a11dc..000000000000
--- a/arch/arm/mach-nomadik/cpu-8815.h
+++ /dev/null
@@ -1,4 +0,0 @@
-extern void cpu8815_map_io(void);
-extern void cpu8815_platform_init(void);
-extern void cpu8815_init_irq(void);
-extern void cpu8815_restart(char, const char *);
diff --git a/arch/arm/mach-nomadik/i2c-8815nhk.c b/arch/arm/mach-nomadik/i2c-8815nhk.c
deleted file mode 100644
index 0c2f6628299a..000000000000
--- a/arch/arm/mach-nomadik/i2c-8815nhk.c
+++ /dev/null
@@ -1,88 +0,0 @@
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/i2c-gpio.h>
-#include <linux/platform_device.h>
-#include <linux/platform_data/pinctrl-nomadik.h>
-
-/*
- * There are two busses in the 8815NHK.
- * They could, in theory, be driven by the hardware component, but we
- * use bit-bang through GPIO by now, to keep things simple
- */
-
-/* I2C0 connected to the STw4811 power management chip */
-static struct i2c_gpio_platform_data nhk8815_i2c_data0 = {
- /* keep defaults for timeouts; pins are push-pull bidirectional */
- .scl_pin = 62,
- .sda_pin = 63,
-};
-
-/* I2C1 connected to various sensors */
-static struct i2c_gpio_platform_data nhk8815_i2c_data1 = {
- /* keep defaults for timeouts; pins are push-pull bidirectional */
- .scl_pin = 53,
- .sda_pin = 54,
-};
-
-/* I2C2 connected to the USB portions of the STw4811 only */
-static struct i2c_gpio_platform_data nhk8815_i2c_data2 = {
- /* keep defaults for timeouts; pins are push-pull bidirectional */
- .scl_pin = 73,
- .sda_pin = 74,
-};
-
-static struct platform_device nhk8815_i2c_dev0 = {
- .name = "i2c-gpio",
- .id = 0,
- .dev = {
- .platform_data = &nhk8815_i2c_data0,
- },
-};
-
-static struct platform_device nhk8815_i2c_dev1 = {
- .name = "i2c-gpio",
- .id = 1,
- .dev = {
- .platform_data = &nhk8815_i2c_data1,
- },
-};
-
-static struct platform_device nhk8815_i2c_dev2 = {
- .name = "i2c-gpio",
- .id = 2,
- .dev = {
- .platform_data = &nhk8815_i2c_data2,
- },
-};
-
-static pin_cfg_t cpu8815_pins_i2c[] = {
- PIN_CFG_INPUT(62, GPIO, PULLUP),
- PIN_CFG_INPUT(63, GPIO, PULLUP),
- PIN_CFG_INPUT(53, GPIO, PULLUP),
- PIN_CFG_INPUT(54, GPIO, PULLUP),
- PIN_CFG_INPUT(73, GPIO, PULLUP),
- PIN_CFG_INPUT(74, GPIO, PULLUP),
-};
-
-static int __init nhk8815_i2c_init(void)
-{
- nmk_config_pins(cpu8815_pins_i2c, ARRAY_SIZE(cpu8815_pins_i2c));
- platform_device_register(&nhk8815_i2c_dev0);
- platform_device_register(&nhk8815_i2c_dev1);
- platform_device_register(&nhk8815_i2c_dev2);
-
- return 0;
-}
-
-static void __exit nhk8815_i2c_exit(void)
-{
- platform_device_unregister(&nhk8815_i2c_dev0);
- platform_device_unregister(&nhk8815_i2c_dev1);
- platform_device_unregister(&nhk8815_i2c_dev2);
- return;
-}
-
-module_init(nhk8815_i2c_init);
-module_exit(nhk8815_i2c_exit);
diff --git a/arch/arm/mach-nomadik/include/mach/hardware.h b/arch/arm/mach-nomadik/include/mach/hardware.h
deleted file mode 100644
index 02035e459f50..000000000000
--- a/arch/arm/mach-nomadik/include/mach/hardware.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * This file contains the hardware definitions of the Nomadik.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * YOU should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/* Nomadik registers live from 0x1000.0000 to 0x1023.0000 -- currently */
-#define NOMADIK_IO_VIRTUAL 0xF0000000 /* VA of IO */
-#define NOMADIK_IO_PHYSICAL 0x10000000 /* PA of IO */
-#define NOMADIK_IO_SIZE 0x00300000 /* 3MB for all regs */
-
-/* used in C code, so cast to proper type */
-#define io_p2v(x) ((void __iomem *)(x) \
- - NOMADIK_IO_PHYSICAL + NOMADIK_IO_VIRTUAL)
-#define io_v2p(x) ((unsigned long)(x) \
- - NOMADIK_IO_VIRTUAL + NOMADIK_IO_PHYSICAL)
-
-/* used in asm code, so no casts */
-#define IO_ADDRESS(x) IOMEM((x) - NOMADIK_IO_PHYSICAL + NOMADIK_IO_VIRTUAL)
-
-/*
- * Base address defination for Nomadik Onchip Logic Block
- */
-#define NOMADIK_FSMC_BASE 0x10100000 /* FSMC registers */
-#define NOMADIK_SDRAMC_BASE 0x10110000 /* SDRAM Controller */
-#define NOMADIK_CLCDC_BASE 0x10120000 /* CLCD Controller */
-#define NOMADIK_MDIF_BASE 0x10120000 /* MDIF */
-#define NOMADIK_DMA0_BASE 0x10130000 /* DMA0 Controller */
-#define NOMADIK_IC_BASE 0x10140000 /* Vectored Irq Controller */
-#define NOMADIK_DMA1_BASE 0x10150000 /* DMA1 Controller */
-#define NOMADIK_USB_BASE 0x10170000 /* USB-OTG conf reg base */
-#define NOMADIK_CRYP_BASE 0x10180000 /* Crypto processor */
-#define NOMADIK_SHA1_BASE 0x10190000 /* SHA-1 Processor */
-#define NOMADIK_XTI_BASE 0x101A0000 /* XTI */
-#define NOMADIK_RNG_BASE 0x101B0000 /* Random number generator */
-#define NOMADIK_SRC_BASE 0x101E0000 /* SRC base */
-#define NOMADIK_WDOG_BASE 0x101E1000 /* Watchdog */
-#define NOMADIK_MTU0_BASE 0x101E2000 /* Multiple Timer 0 */
-#define NOMADIK_MTU1_BASE 0x101E3000 /* Multiple Timer 1 */
-#define NOMADIK_GPIO0_BASE 0x101E4000 /* GPIO0 */
-#define NOMADIK_GPIO1_BASE 0x101E5000 /* GPIO1 */
-#define NOMADIK_GPIO2_BASE 0x101E6000 /* GPIO2 */
-#define NOMADIK_GPIO3_BASE 0x101E7000 /* GPIO3 */
-#define NOMADIK_RTC_BASE 0x101E8000 /* Real Time Clock base */
-#define NOMADIK_PMU_BASE 0x101E9000 /* Power Management Unit */
-#define NOMADIK_OWM_BASE 0x101EA000 /* One wire master */
-#define NOMADIK_SCR_BASE 0x101EF000 /* Secure Control registers */
-#define NOMADIK_MSP2_BASE 0x101F0000 /* MSP 2 interface */
-#define NOMADIK_MSP1_BASE 0x101F1000 /* MSP 1 interface */
-#define NOMADIK_UART2_BASE 0x101F2000 /* UART 2 interface */
-#define NOMADIK_SSIRx_BASE 0x101F3000 /* SSI 8-ch rx interface */
-#define NOMADIK_SSITx_BASE 0x101F4000 /* SSI 8-ch tx interface */
-#define NOMADIK_MSHC_BASE 0x101F5000 /* Memory Stick(Pro) Host */
-#define NOMADIK_SDI_BASE 0x101F6000 /* SD-card/MM-Card */
-#define NOMADIK_I2C1_BASE 0x101F7000 /* I2C1 interface */
-#define NOMADIK_I2C0_BASE 0x101F8000 /* I2C0 interface */
-#define NOMADIK_MSP0_BASE 0x101F9000 /* MSP 0 interface */
-#define NOMADIK_FIRDA_BASE 0x101FA000 /* FIrDA interface */
-#define NOMADIK_UART1_BASE 0x101FB000 /* UART 1 interface */
-#define NOMADIK_SSP_BASE 0x101FC000 /* SSP interface */
-#define NOMADIK_UART0_BASE 0x101FD000 /* UART 0 interface */
-#define NOMADIK_SGA_BASE 0x101FE000 /* SGA interface */
-#define NOMADIK_L2CC_BASE 0x10210000 /* L2 Cache controller */
-
-/* Other ranges, not for p2v/v2p */
-#define NOMADIK_BACKUP_RAM 0x80010000
-#define NOMADIK_EBROM 0x80000000 /* Embedded boot ROM */
-#define NOMADIK_HAMACV_DMEM_BASE 0xA0100000 /* HAMACV Data Memory Start */
-#define NOMADIK_HAMACV_DMEM_END 0xA01FFFFF /* HAMACV Data Memory End */
-#define NOMADIK_HAMACA_DMEM 0xA0200000 /* HAMACA Data Memory Space */
-
-#define NOMADIK_FSMC_VA IO_ADDRESS(NOMADIK_FSMC_BASE)
-#define NOMADIK_MTU0_VA IO_ADDRESS(NOMADIK_MTU0_BASE)
-#define NOMADIK_MTU1_VA IO_ADDRESS(NOMADIK_MTU1_BASE)
-
-#endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-nomadik/include/mach/irqs.h b/arch/arm/mach-nomadik/include/mach/irqs.h
index 215f8cdb4004..90ac965a92fe 100644
--- a/arch/arm/mach-nomadik/include/mach/irqs.h
+++ b/arch/arm/mach-nomadik/include/mach/irqs.h
@@ -20,8 +20,6 @@
#ifndef __ASM_ARCH_IRQS_H
#define __ASM_ARCH_IRQS_H
-#include <mach/hardware.h>
-
#define IRQ_VIC_START 32 /* first VIC interrupt is 1 */
/*
diff --git a/arch/arm/mach-nomadik/include/mach/uncompress.h b/arch/arm/mach-nomadik/include/mach/uncompress.h
index 7d4687e9cbdf..106fccca2021 100644
--- a/arch/arm/mach-nomadik/include/mach/uncompress.h
+++ b/arch/arm/mach-nomadik/include/mach/uncompress.h
@@ -21,7 +21,6 @@
#include <asm/setup.h>
#include <asm/io.h>
-#include <mach/hardware.h>
/* we need the constants in amba/serial.h, but it refers to amba_device */
struct amba_device;
@@ -58,6 +57,4 @@ static inline void arch_decomp_setup(void)
{
}
-#define arch_decomp_wdog() /* nothing to do here */
-
#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index 2e98a3ac7c5e..2aab761ee68d 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -628,6 +628,6 @@ MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)")
.init_irq = omap1_init_irq,
.init_machine = ams_delta_init,
.init_late = ams_delta_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 560a7dcf0a56..702d58039cc1 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -364,6 +364,6 @@ MACHINE_START(OMAP_FSAMPLE, "OMAP730 F-Sample")
.init_irq = omap1_init_irq,
.init_machine = omap_fsample_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c
index 608e7d2a2778..e1d9171774bc 100644
--- a/arch/arm/mach-omap1/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -84,6 +84,6 @@ MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
.init_irq = omap1_init_irq,
.init_machine = omap_generic_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 2274bd677efc..0dac3d239e32 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -461,6 +461,6 @@ MACHINE_START(OMAP_H2, "TI-H2")
.init_irq = omap1_init_irq,
.init_machine = h2_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 1051935f0aac..816ecd13f81e 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -454,6 +454,6 @@ MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
.init_irq = omap1_init_irq,
.init_machine = h3_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c
index 356f816c84a6..35a2379b986f 100644
--- a/arch/arm/mach-omap1/board-htcherald.c
+++ b/arch/arm/mach-omap1/board-htcherald.c
@@ -603,6 +603,6 @@ MACHINE_START(HERALD, "HTC Herald")
.init_irq = omap1_init_irq,
.init_machine = htcherald_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index f8033fab0f82..bd5f02e9c354 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -458,6 +458,6 @@ MACHINE_START(OMAP_INNOVATOR, "TI-Innovator")
.init_irq = omap1_init_irq,
.init_machine = innovator_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index 24d2f2df11a0..62a15e289c79 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -7,6 +7,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -23,6 +24,8 @@
#include <linux/platform_data/keypad-omap.h>
#include <linux/platform_data/lcd-mipid.h>
+#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/i2c-cbus-gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -212,6 +215,45 @@ static inline void nokia770_mmc_init(void)
}
#endif
+#if defined(CONFIG_I2C_CBUS_GPIO) || defined(CONFIG_I2C_CBUS_GPIO_MODULE)
+static struct i2c_cbus_platform_data nokia770_cbus_data = {
+ .clk_gpio = OMAP_MPUIO(9),
+ .dat_gpio = OMAP_MPUIO(10),
+ .sel_gpio = OMAP_MPUIO(11),
+};
+
+static struct platform_device nokia770_cbus_device = {
+ .name = "i2c-cbus-gpio",
+ .id = 2,
+ .dev = {
+ .platform_data = &nokia770_cbus_data,
+ },
+};
+
+static struct i2c_board_info nokia770_i2c_board_info_2[] __initdata = {
+ {
+ I2C_BOARD_INFO("retu-mfd", 0x01),
+ },
+};
+
+static void __init nokia770_cbus_init(void)
+{
+ const int retu_irq_gpio = 62;
+
+ if (gpio_request_one(retu_irq_gpio, GPIOF_IN, "Retu IRQ"))
+ return;
+ irq_set_irq_type(gpio_to_irq(retu_irq_gpio), IRQ_TYPE_EDGE_RISING);
+ nokia770_i2c_board_info_2[0].irq = gpio_to_irq(retu_irq_gpio);
+ i2c_register_board_info(2, nokia770_i2c_board_info_2,
+ ARRAY_SIZE(nokia770_i2c_board_info_2));
+ platform_device_register(&nokia770_cbus_device);
+}
+#else /* CONFIG_I2C_CBUS_GPIO */
+static void __init nokia770_cbus_init(void)
+{
+}
+#endif /* CONFIG_I2C_CBUS_GPIO */
+
static void __init omap_nokia770_init(void)
{
/* On Nokia 770, the SleepX signal is masked with an
@@ -233,6 +275,7 @@ static void __init omap_nokia770_init(void)
mipid_dev_init();
omap1_usb_init(&nokia770_usb_config);
nokia770_mmc_init();
+ nokia770_cbus_init();
}
MACHINE_START(NOKIA770, "Nokia 770")
@@ -242,6 +285,6 @@ MACHINE_START(NOKIA770, "Nokia 770")
.init_irq = omap1_init_irq,
.init_machine = omap_nokia770_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 872ea47cd28a..a7ce69286688 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -609,6 +609,6 @@ MACHINE_START(OMAP_OSK, "TI-OSK")
.init_irq = omap1_init_irq,
.init_machine = osk_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index c33dceb46607..845a1a7aef95 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -268,6 +268,6 @@ MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
.init_irq = omap1_init_irq,
.init_machine = omap_palmte_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
index 2948b0ee4be8..65a4a3e357f2 100644
--- a/arch/arm/mach-omap1/board-palmtt.c
+++ b/arch/arm/mach-omap1/board-palmtt.c
@@ -314,6 +314,6 @@ MACHINE_START(OMAP_PALMTT, "OMAP1510 based Palm Tungsten|T")
.init_irq = omap1_init_irq,
.init_machine = omap_palmtt_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index 7a05895c0be3..01c970071fd8 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -330,6 +330,6 @@ MACHINE_START(OMAP_PALMZ71, "OMAP310 based Palm Zire71")
.init_irq = omap1_init_irq,
.init_machine = omap_palmz71_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 27f8d12ec222..8b2f7127f716 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -326,6 +326,6 @@ MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
.init_irq = omap1_init_irq,
.init_machine = omap_perseus2_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c
index 20ed52ae1714..9732a98f3e06 100644
--- a/arch/arm/mach-omap1/board-sx1.c
+++ b/arch/arm/mach-omap1/board-sx1.c
@@ -407,6 +407,6 @@ MACHINE_START(SX1, "OMAP310 based Siemens SX1")
.init_irq = omap1_init_irq,
.init_machine = omap_sx1_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = omap1_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index abf705f49b19..6c116e1a4b01 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -289,6 +289,6 @@ MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
.init_irq = omap1_init_irq,
.init_machine = voiceblue_init,
.init_late = omap1_init_late,
- .timer = &omap1_timer,
+ .init_time = omap1_timer_init,
.restart = voiceblue_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h
index b53e0854422f..fb18831e88aa 100644
--- a/arch/arm/mach-omap1/common.h
+++ b/arch/arm/mach-omap1/common.h
@@ -75,7 +75,7 @@ extern void __init omap_check_revision(void);
extern void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
unsigned int ctrl);
-extern struct sys_timer omap1_timer;
+extern void omap1_timer_init(void);
#ifdef CONFIG_OMAP_32K_TIMER
extern int omap_32k_timer_init(void);
#else
diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c
index e190611e4b46..1a4e887f028d 100644
--- a/arch/arm/mach-omap1/dma.c
+++ b/arch/arm/mach-omap1/dma.c
@@ -24,7 +24,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/io.h>
-
+#include <linux/dma-mapping.h>
#include <linux/omap-dma.h>
#include <mach/tc.h>
@@ -270,11 +270,17 @@ static u32 configure_dma_errata(void)
return errata;
}
+static const struct platform_device_info omap_dma_dev_info = {
+ .name = "omap-dma-engine",
+ .id = -1,
+ .dma_mask = DMA_BIT_MASK(32),
+};
+
static int __init omap1_system_dma_init(void)
{
struct omap_system_dma_plat_info *p;
struct omap_dma_dev_attr *d;
- struct platform_device *pdev;
+ struct platform_device *pdev, *dma_pdev;
int ret;
pdev = platform_device_alloc("omap_dma_system", 0);
@@ -380,8 +386,16 @@ static int __init omap1_system_dma_init(void)
dma_common_ch_start = CPC;
dma_common_ch_end = COLOR;
+ dma_pdev = platform_device_register_full(&omap_dma_dev_info);
+ if (IS_ERR(dma_pdev)) {
+ ret = PTR_ERR(dma_pdev);
+ goto exit_release_pdev;
+ }
+
return ret;
+exit_release_pdev:
+ platform_device_del(pdev);
exit_release_chan:
kfree(d->chan);
exit_release_d:
diff --git a/arch/arm/mach-omap1/i2c.c b/arch/arm/mach-omap1/i2c.c
index faca808cb3d9..7f5761cffd2e 100644
--- a/arch/arm/mach-omap1/i2c.c
+++ b/arch/arm/mach-omap1/i2c.c
@@ -91,3 +91,9 @@ int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *pdata,
return platform_device_register(pdev);
}
+
+static int __init omap_i2c_cmdline(void)
+{
+ return omap_register_i2c_bus_cmdline();
+}
+subsys_initcall(omap_i2c_cmdline);
diff --git a/arch/arm/mach-omap1/include/mach/uncompress.h b/arch/arm/mach-omap1/include/mach/uncompress.h
index ad6fbe7d83f2..4869633de8cd 100644
--- a/arch/arm/mach-omap1/include/mach/uncompress.h
+++ b/arch/arm/mach-omap1/include/mach/uncompress.h
@@ -115,8 +115,3 @@ static inline void arch_decomp_setup(void)
DEBUG_LL_OMAP1(3, sx1);
} while (0);
}
-
-/*
- * nothing to do
- */
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 4d4816fd6fc9..726ec23d29c7 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -145,7 +145,6 @@ static void omap_mpu_set_mode(enum clock_event_mode mode,
static struct clock_event_device clockevent_mpu_timer1 = {
.name = "mpu_timer1",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.set_next_event = omap_mpu_set_next_event,
.set_mode = omap_mpu_set_mode,
};
@@ -170,15 +169,9 @@ static __init void omap_init_mpu_timer(unsigned long rate)
setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
- clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC,
- clockevent_mpu_timer1.shift);
- clockevent_mpu_timer1.max_delta_ns =
- clockevent_delta2ns(-1, &clockevent_mpu_timer1);
- clockevent_mpu_timer1.min_delta_ns =
- clockevent_delta2ns(1, &clockevent_mpu_timer1);
-
clockevent_mpu_timer1.cpumask = cpumask_of(0);
- clockevents_register_device(&clockevent_mpu_timer1);
+ clockevents_config_and_register(&clockevent_mpu_timer1, rate,
+ 1, -1);
}
@@ -236,12 +229,8 @@ static inline void omap_mpu_timer_init(void)
* Timer initialization
* ---------------------------------------------------------------------------
*/
-static void __init omap1_timer_init(void)
+void __init omap1_timer_init(void)
{
if (omap_32k_timer_init() != 0)
omap_mpu_timer_init();
}
-
-struct sys_timer omap1_timer = {
- .init = omap1_timer_init,
-};
diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c
index 41152fadd4c0..0b74246ba62c 100644
--- a/arch/arm/mach-omap1/timer32k.c
+++ b/arch/arm/mach-omap1/timer32k.c
@@ -140,7 +140,6 @@ static void omap_32k_timer_set_mode(enum clock_event_mode mode,
static struct clock_event_device clockevent_32k_timer = {
.name = "32k-timer",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.set_next_event = omap_32k_timer_set_next_event,
.set_mode = omap_32k_timer_set_mode,
};
@@ -165,16 +164,9 @@ static __init void omap_init_32k_timer(void)
{
setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
- clockevent_32k_timer.mult = div_sc(OMAP_32K_TICKS_PER_SEC,
- NSEC_PER_SEC,
- clockevent_32k_timer.shift);
- clockevent_32k_timer.max_delta_ns =
- clockevent_delta2ns(0xfffffffe, &clockevent_32k_timer);
- clockevent_32k_timer.min_delta_ns =
- clockevent_delta2ns(1, &clockevent_32k_timer);
-
clockevent_32k_timer.cpumask = cpumask_of(0);
- clockevents_register_device(&clockevent_32k_timer);
+ clockevents_config_and_register(&clockevent_32k_timer,
+ OMAP_32K_TICKS_PER_SEC, 1, 0xfffffffe);
}
/*
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 41b581fd0213..49ac3dfebef9 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -1,3 +1,26 @@
+config ARCH_OMAP
+ bool
+
+config ARCH_OMAP2PLUS
+ bool "TI OMAP2/3/4/5 SoCs with device tree support" if (ARCH_MULTI_V6 || ARCH_MULTI_V7)
+ select ARCH_HAS_CPUFREQ
+ select ARCH_HAS_HOLES_MEMORYMODEL
+ select ARCH_OMAP
+ select ARCH_REQUIRE_GPIOLIB
+ select CLKDEV_LOOKUP
+ select CLKSRC_MMIO
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_IRQ_CHIP
+ select HAVE_CLK
+ select OMAP_DM_TIMER
+ select PINCTRL
+ select PROC_DEVICETREE if PROC_FS
+ select SPARSE_IRQ
+ select USE_OF
+ help
+ Systems based on OMAP2, OMAP3, OMAP4 or OMAP5
+
+
if ARCH_OMAP2PLUS
menu "TI OMAP2/3/4 Specific Features"
@@ -76,12 +99,12 @@ config ARCH_OMAP4
config SOC_OMAP5
bool "TI OMAP5"
- select ARM_ARCH_TIMER
select ARM_CPU_SUSPEND if PM
select ARM_GIC
select CPU_V7
select HAVE_SMP
select COMMON_CLK
+ select HAVE_ARM_ARCH_TIMER
comment "OMAP Core Type"
depends on ARCH_OMAP2
@@ -165,12 +188,6 @@ config MACH_OMAP_H4
select OMAP_DEBUG_DEVICES
select OMAP_PACKAGE_ZAF
-config MACH_OMAP_APOLLON
- bool "OMAP 2420 Apollon board"
- depends on SOC_OMAP2420
- default y
- select OMAP_PACKAGE_ZAC
-
config MACH_OMAP_2430SDP
bool "OMAP 2430 SDP board"
depends on SOC_OMAP2430
@@ -397,7 +414,7 @@ config OMAP3_SDRC_AC_TIMING
config OMAP4_ERRATA_I688
bool "OMAP4 errata: Async Bridge Corruption"
- depends on ARCH_OMAP4
+ depends on ARCH_OMAP4 && !ARCH_MULTIPLATFORM
select ARCH_HAS_BARRIERS
help
If a data is stalled inside asynchronous bridge because of back
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 947cafe65aef..ff528df70119 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -2,6 +2,9 @@
# Makefile for the linux kernel.
#
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
+ -I$(srctree)/arch/arm/plat-omap/include
+
# Common support
obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
@@ -220,7 +223,6 @@ endif
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o
obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o
-obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o
obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o
obj-$(CONFIG_MACH_DEVKIT8000) += board-devkit8000.o
obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o
diff --git a/arch/arm/mach-omap2/am35xx-emac.c b/arch/arm/mach-omap2/am35xx-emac.c
index af11dcdb7e2c..a00d39107a21 100644
--- a/arch/arm/mach-omap2/am35xx-emac.c
+++ b/arch/arm/mach-omap2/am35xx-emac.c
@@ -63,7 +63,7 @@ static int __init omap_davinci_emac_dev_init(struct omap_hwmod *oh,
struct platform_device *pdev;
pdev = omap_device_build(oh->class->name, 0, oh, pdata, pdata_len,
- NULL, 0, false);
+ false);
if (IS_ERR(pdev)) {
WARN(1, "Can't build omap_device for %s:%s.\n",
oh->class->name, oh->name);
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 4815ea6f8f5d..a3e0aaa4886b 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -27,6 +27,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/usb/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -263,6 +264,7 @@ static void __init omap_2430sdp_init(void)
omap_hsmmc_init(mmc);
omap_mux_init_signal("usb0hs_stp", OMAP_PULL_ENA | OMAP_PULL_UP);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
board_smc91x_init();
@@ -284,6 +286,6 @@ MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board")
.handle_irq = omap2_intc_handle_irq,
.init_machine = omap_2430sdp_init,
.init_late = omap2430_init_late,
- .timer = &omap2_timer,
+ .init_time = omap2_sync32k_timer_init,
.restart = omap2xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index bb73afc9ac17..ce812decfaca 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -25,6 +25,8 @@
#include <linux/gpio.h>
#include <linux/mmc/host.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
+#include <linux/platform_data/omap-twl4030.h>
+#include <linux/usb/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -209,6 +211,19 @@ static struct omap2_hsmmc_info mmc[] = {
{} /* Terminator */
};
+static struct omap_tw4030_pdata omap_twl4030_audio_data = {
+ .voice_connected = true,
+ .custom_routing = true,
+
+ .has_hs = OMAP_TWL4030_LEFT | OMAP_TWL4030_RIGHT,
+ .has_hf = OMAP_TWL4030_LEFT | OMAP_TWL4030_RIGHT,
+
+ .has_mainmic = true,
+ .has_submic = true,
+ .has_hsmic = true,
+ .has_linein = OMAP_TWL4030_LEFT | OMAP_TWL4030_RIGHT,
+};
+
static int sdp3430_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
@@ -225,6 +240,9 @@ static int sdp3430_twl_gpio_setup(struct device *dev,
/* gpio + 15 is "sub_lcd_nRST" (output) */
gpio_request_one(gpio + 15, GPIOF_OUT_INIT_LOW, "sub_lcd_nRST");
+ omap_twl4030_audio_data.jack_detect = gpio + 2;
+ omap_twl4030_audio_init("SDP3430", &omap_twl4030_audio_data);
+
return 0;
}
@@ -382,6 +400,9 @@ static int __init omap3430_i2c_init(void)
sdp3430_twldata.vpll2->constraints.apply_uV = true;
sdp3430_twldata.vpll2->constraints.name = "VDVI";
+ sdp3430_twldata.audio->codec->hs_extmute = 1;
+ sdp3430_twldata.audio->codec->hs_extmute_gpio = -EINVAL;
+
omap3_pmic_init("twl4030", &sdp3430_twldata);
/* i2c2 on camera connector (for sensor control) and optional isp1301 */
@@ -424,7 +445,7 @@ static void enable_board_wakeup_source(void)
OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP);
}
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
@@ -579,6 +600,7 @@ static void __init omap_3430sdp_init(void)
omap_ads7846_init(1, gpio_pendown, 310, NULL);
omap_serial_init();
omap_sdrc_init(hyb18m512160af6_sdrc_params, NULL);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
board_smc91x_init();
board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);
@@ -597,6 +619,6 @@ MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_3430sdp_init,
.init_late = omap3430_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c
index 050aaa771254..67447bd4564f 100644
--- a/arch/arm/mach-omap2/board-3630sdp.c
+++ b/arch/arm/mach-omap2/board-3630sdp.c
@@ -53,7 +53,7 @@ static void enable_board_wakeup_source(void)
OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP);
}
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
@@ -211,6 +211,6 @@ MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_sdp_init,
.init_late = omap3630_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 1cc6696594fd..35f3ad0cb7c7 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -24,12 +24,15 @@
#include <linux/gpio_keys.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
+#include <linux/pwm.h>
#include <linux/leds.h>
#include <linux/leds_pwm.h>
+#include <linux/pwm_backlight.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/omap4-keypad.h>
#include <linux/usb/musb.h>
+#include <linux/usb/phy.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -256,10 +259,20 @@ static struct gpio_led_platform_data sdp4430_led_data = {
.num_leds = ARRAY_SIZE(sdp4430_gpio_leds),
};
+static struct pwm_lookup sdp4430_pwm_lookup[] = {
+ PWM_LOOKUP("twl-pwm", 0, "leds_pwm", "omap4::keypad"),
+ PWM_LOOKUP("twl-pwm", 1, "pwm-backlight", NULL),
+ PWM_LOOKUP("twl-pwmled", 0, "leds_pwm", "omap4:green:chrg"),
+};
+
static struct led_pwm sdp4430_pwm_leds[] = {
{
+ .name = "omap4::keypad",
+ .max_brightness = 127,
+ .pwm_period_ns = 7812500,
+ },
+ {
.name = "omap4:green:chrg",
- .pwm_id = 1,
.max_brightness = 255,
.pwm_period_ns = 7812500,
},
@@ -278,6 +291,20 @@ static struct platform_device sdp4430_leds_pwm = {
},
};
+static struct platform_pwm_backlight_data sdp4430_backlight_data = {
+ .max_brightness = 127,
+ .dft_brightness = 127,
+ .pwm_period_ns = 7812500,
+};
+
+static struct platform_device sdp4430_backlight_pwm = {
+ .name = "pwm-backlight",
+ .id = -1,
+ .dev = {
+ .platform_data = &sdp4430_backlight_data,
+ },
+};
+
static int omap_prox_activate(struct device *dev)
{
gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1);
@@ -412,6 +439,7 @@ static struct platform_device *sdp4430_devices[] __initdata = {
&sdp4430_gpio_keys_device,
&sdp4430_leds_gpio,
&sdp4430_leds_pwm,
+ &sdp4430_backlight_pwm,
&sdp4430_vbat,
&sdp4430_dmic_codec,
&sdp4430_abe_audio,
@@ -696,6 +724,7 @@ static void __init omap_4430sdp_init(void)
omap4_sdp4430_wifi_init();
omap4_twl6030_hsmmc_init(mmc);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "omap-usb2.1.auto");
usb_musb_init(&musb_board_data);
status = omap_ethernet_init();
@@ -707,6 +736,7 @@ static void __init omap_4430sdp_init(void)
ARRAY_SIZE(sdp4430_spi_board_info));
}
+ pwm_add_table(sdp4430_pwm_lookup, ARRAY_SIZE(sdp4430_pwm_lookup));
status = omap4_keyboard_init(&sdp4430_keypad_data, &keypad_data);
if (status)
pr_err("Keypad initialization failed: %d\n", status);
@@ -722,9 +752,8 @@ MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board")
.map_io = omap4_map_io,
.init_early = omap4430_init_early,
.init_irq = gic_init_irq,
- .handle_irq = gic_handle_irq,
.init_machine = omap_4430sdp_init,
.init_late = omap4430_init_late,
- .timer = &omap4_timer,
+ .init_time = omap4_local_timer_init,
.restart = omap44xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c
index 51b96a1206d1..7d3358b2e593 100644
--- a/arch/arm/mach-omap2/board-am3517crane.c
+++ b/arch/arm/mach-omap2/board-am3517crane.c
@@ -20,12 +20,18 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
+#include <linux/mfd/tps65910.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "common.h"
+#include "common-board-devices.h"
+#include "board-flash.h"
#include "am35xx-emac.h"
#include "mux.h"
@@ -36,11 +42,12 @@
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
+ OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
#endif
-static struct usbhs_omap_board_data usbhs_bdata __initdata = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -51,6 +58,54 @@ static struct usbhs_omap_board_data usbhs_bdata __initdata = {
.reset_gpio_port[2] = -EINVAL
};
+static struct mtd_partition crane_nand_partitions[] = {
+ {
+ .name = "X-Loader",
+ .offset = 0,
+ .size = 4 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ {
+ .name = "U-Boot",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 14 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ {
+ .name = "U-Boot Env",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 2 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "Kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 40 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "File System",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct tps65910_board tps65910_pdata = {
+ .irq = 7 + OMAP_INTC_START,
+ .en_ck32k_xtal = true,
+};
+
+static struct i2c_board_info __initdata tps65910_board_info[] = {
+ {
+ I2C_BOARD_INFO("tps65910", 0x2d),
+ .platform_data = &tps65910_pdata,
+ },
+};
+
+static void __init am3517_crane_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 2600, tps65910_board_info,
+ ARRAY_SIZE(tps65910_board_info));
+}
+
static void __init am3517_crane_init(void)
{
int ret;
@@ -58,6 +113,10 @@ static void __init am3517_crane_init(void)
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
omap_serial_init();
omap_sdrc_init(NULL, NULL);
+ board_nand_init(crane_nand_partitions,
+ ARRAY_SIZE(crane_nand_partitions), 0,
+ NAND_BUSWIDTH_16, NULL);
+ am3517_crane_i2c_init();
/* Configure GPIO for EHCI port */
if (omap_mux_init_gpio(GPIO_USB_NRESET, OMAP_PIN_OUTPUT)) {
@@ -92,6 +151,6 @@ MACHINE_START(CRANEBOARD, "AM3517/05 CRANEBOARD")
.handle_irq = omap3_intc_handle_irq,
.init_machine = am3517_crane_init,
.init_late = am35xx_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
index f81a303b87ff..9fb85908a61e 100644
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ b/arch/arm/mach-omap2/board-am3517evm.c
@@ -274,7 +274,7 @@ static __init void am3517_evm_mcbsp1_init(void)
omap_ctrl_writel(devconf0, OMAP2_CONTROL_DEVCONF0);
}
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
#if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \
defined(CONFIG_PANEL_SHARP_LQ043T1DG01_MODULE)
@@ -393,6 +393,6 @@ MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
.handle_irq = omap3_intc_handle_irq,
.init_machine = am3517_evm_init,
.init_late = am35xx_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
deleted file mode 100644
index 5d0a61f54165..000000000000
--- a/arch/arm/mach-omap2/board-apollon.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/board-apollon.c
- *
- * Copyright (C) 2005,2006 Samsung Electronics
- * Author: Kyungmin Park <kyungmin.park@samsung.com>
- *
- * Modified from mach-omap/omap2/board-h4.c
- *
- * Code for apollon OMAP2 board. Should work on many OMAP2 systems where
- * the bootloader passes the board-specific data to the kernel.
- * Do not put any board specific code to this file; create a new machine
- * type if you need custom low-level initializations.
- *
- * 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/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/onenand.h>
-#include <linux/delay.h>
-#include <linux/leds.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/smc91x.h>
-#include <linux/gpio.h>
-#include <linux/platform_data/leds-omap.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-
-#include "common.h"
-#include "gpmc.h"
-
-#include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
-
-#include "mux.h"
-#include "control.h"
-
-/* LED & Switch macros */
-#define LED0_GPIO13 13
-#define LED1_GPIO14 14
-#define LED2_GPIO15 15
-#define SW_ENTER_GPIO16 16
-#define SW_UP_GPIO17 17
-#define SW_DOWN_GPIO58 58
-
-#define APOLLON_FLASH_CS 0
-#define APOLLON_ETH_CS 1
-#define APOLLON_ETHR_GPIO_IRQ 74
-
-static struct mtd_partition apollon_partitions[] = {
- {
- .name = "X-Loader + U-Boot",
- .offset = 0,
- .size = SZ_128K,
- .mask_flags = MTD_WRITEABLE,
- },
- {
- .name = "params",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_128K,
- },
- {
- .name = "kernel",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_2M,
- },
- {
- .name = "rootfs",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_16M,
- },
- {
- .name = "filesystem00",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_32M,
- },
- {
- .name = "filesystem01",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct onenand_platform_data apollon_flash_data = {
- .parts = apollon_partitions,
- .nr_parts = ARRAY_SIZE(apollon_partitions),
-};
-
-static struct resource apollon_flash_resource[] = {
- [0] = {
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device apollon_onenand_device = {
- .name = "onenand-flash",
- .id = -1,
- .dev = {
- .platform_data = &apollon_flash_data,
- },
- .num_resources = ARRAY_SIZE(apollon_flash_resource),
- .resource = apollon_flash_resource,
-};
-
-static void __init apollon_flash_init(void)
-{
- unsigned long base;
-
- if (gpmc_cs_request(APOLLON_FLASH_CS, SZ_128K, &base) < 0) {
- printk(KERN_ERR "Cannot request OneNAND GPMC CS\n");
- return;
- }
- apollon_flash_resource[0].start = base;
- apollon_flash_resource[0].end = base + SZ_128K - 1;
-}
-
-static struct smc91x_platdata appolon_smc91x_info = {
- .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
- .leda = RPC_LED_100_10,
- .ledb = RPC_LED_TX_RX,
-};
-
-static struct resource apollon_smc91x_resources[] = {
- [0] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
- },
-};
-
-static struct platform_device apollon_smc91x_device = {
- .name = "smc91x",
- .id = -1,
- .dev = {
- .platform_data = &appolon_smc91x_info,
- },
- .num_resources = ARRAY_SIZE(apollon_smc91x_resources),
- .resource = apollon_smc91x_resources,
-};
-
-static struct omap_led_config apollon_led_config[] = {
- {
- .cdev = {
- .name = "apollon:led0",
- },
- .gpio = LED0_GPIO13,
- },
- {
- .cdev = {
- .name = "apollon:led1",
- },
- .gpio = LED1_GPIO14,
- },
- {
- .cdev = {
- .name = "apollon:led2",
- },
- .gpio = LED2_GPIO15,
- },
-};
-
-static struct omap_led_platform_data apollon_led_data = {
- .nr_leds = ARRAY_SIZE(apollon_led_config),
- .leds = apollon_led_config,
-};
-
-static struct platform_device apollon_led_device = {
- .name = "omap-led",
- .id = -1,
- .dev = {
- .platform_data = &apollon_led_data,
- },
-};
-
-static struct platform_device *apollon_devices[] __initdata = {
- &apollon_onenand_device,
- &apollon_smc91x_device,
- &apollon_led_device,
-};
-
-static inline void __init apollon_init_smc91x(void)
-{
- unsigned long base;
-
- 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)) {
- WARN_ON(1);
- return;
- }
-
- clk_prepare_enable(gpmc_fck);
- rate = clk_get_rate(gpmc_fck);
-
- eth_cs = APOLLON_ETH_CS;
-
- /* Make sure CS1 timings are correct */
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200);
-
- if (rate >= 160000000) {
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
- } else if (rate >= 130000000) {
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
- } else {/* rate = 100000000 */
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
- gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
- }
-
- if (gpmc_cs_request(APOLLON_ETH_CS, SZ_16M, &base) < 0) {
- printk(KERN_ERR "Failed to request GPMC CS for smc91x\n");
- goto out;
- }
- apollon_smc91x_resources[0].start = base + 0x300;
- apollon_smc91x_resources[0].end = base + 0x30f;
- udelay(100);
-
- 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);
- }
-out:
- clk_disable_unprepare(gpmc_fck);
- clk_put(gpmc_fck);
-}
-
-static struct panel_generic_dpi_data apollon_panel_data = {
- .name = "apollon",
-};
-
-static struct omap_dss_device apollon_lcd_device = {
- .name = "lcd",
- .driver_name = "generic_dpi_panel",
- .type = OMAP_DISPLAY_TYPE_DPI,
- .phy.dpi.data_lines = 18,
- .data = &apollon_panel_data,
-};
-
-static struct omap_dss_device *apollon_dss_devices[] = {
- &apollon_lcd_device,
-};
-
-static struct omap_dss_board_info apollon_dss_data = {
- .num_devices = ARRAY_SIZE(apollon_dss_devices),
- .devices = apollon_dss_devices,
- .default_device = &apollon_lcd_device,
-};
-
-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)
-{
- omap_mux_init_signal("vlynq_clk.gpio_13", 0);
- omap_mux_init_signal("vlynq_rx1.gpio_14", 0);
- omap_mux_init_signal("vlynq_rx0.gpio_15", 0);
-
- gpio_request_array(apollon_gpio_leds, ARRAY_SIZE(apollon_gpio_leds));
-}
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
- { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#endif
-
-static void __init omap_apollon_init(void)
-{
- u32 v;
-
- omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAC);
-
- apollon_init_smc91x();
- apollon_led_init();
- apollon_flash_init();
-
- /* REVISIT: where's the correct place */
- omap_mux_init_signal("sys_nirq", OMAP_PULL_ENA | OMAP_PULL_UP);
-
- /* LCD PWR_EN */
- omap_mux_init_signal("mcbsp2_dr.gpio_11", OMAP_PULL_ENA | OMAP_PULL_UP);
-
- /* Use Internal loop-back in MMC/SDIO Module Input Clock selection */
- v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
- v |= (1 << 24);
- omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
-
- /*
- * Make sure the serial ports are muxed on at this point.
- * You have to mux them off in device drivers later on
- * if not needed.
- */
- apollon_smc91x_resources[1].start = gpio_to_irq(APOLLON_ETHR_GPIO_IRQ);
- apollon_smc91x_resources[1].end = gpio_to_irq(APOLLON_ETHR_GPIO_IRQ);
- platform_add_devices(apollon_devices, ARRAY_SIZE(apollon_devices));
- omap_serial_init();
- omap_sdrc_init(NULL, NULL);
- omap_display_init(&apollon_dss_data);
-}
-
-MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon")
- /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
- .atag_offset = 0x100,
- .reserve = omap_reserve,
- .map_io = omap242x_map_io,
- .init_early = omap2420_init_early,
- .init_irq = omap2_init_irq,
- .handle_irq = omap2_intc_handle_irq,
- .init_machine = omap_apollon_init,
- .init_late = omap2420_init_late,
- .timer = &omap2_timer,
- .restart = omap2xxx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index b3102c2f4a3c..af2bb219e214 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -30,6 +30,7 @@
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
#include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
#include <linux/spi/spi.h>
#include <linux/spi/tdo24m.h>
@@ -418,7 +419,7 @@ static struct omap2_hsmmc_info mmc[] = {
{} /* Terminator */
};
-static struct usbhs_omap_board_data usbhs_bdata __initdata = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -722,8 +723,9 @@ static void __init cm_t3x_common_init(void)
cm_t35_init_ethernet();
cm_t35_init_led();
cm_t35_init_display();
- omap_twl4030_audio_init("cm-t3x");
+ omap_twl4030_audio_init("cm-t3x", NULL);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
cm_t35_init_usbh();
cm_t35_init_camera();
@@ -751,7 +753,7 @@ MACHINE_START(CM_T35, "Compulab CM-T35")
.handle_irq = omap3_intc_handle_irq,
.init_machine = cm_t35_init,
.init_late = omap35xx_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
@@ -764,6 +766,6 @@ MACHINE_START(CM_T3730, "Compulab CM-T3730")
.handle_irq = omap3_intc_handle_irq,
.init_machine = cm_t3730_init,
.init_late = omap3630_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c
index ebbc2adb499e..a66da808cc4a 100644
--- a/arch/arm/mach-omap2/board-cm-t3517.c
+++ b/arch/arm/mach-omap2/board-cm-t3517.c
@@ -32,6 +32,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/mmc/host.h>
#include <linux/can/platform/ti_hecc.h>
#include <asm/mach-types.h>
@@ -46,6 +47,7 @@
#include "mux.h"
#include "control.h"
+#include "hsmmc.h"
#include "common-board-devices.h"
#include "am35xx-emac.h"
#include "gpmc-nand.h"
@@ -121,6 +123,26 @@ static void cm_t3517_init_hecc(void)
static inline void cm_t3517_init_hecc(void) {}
#endif
+#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
+static struct omap2_hsmmc_info cm_t3517_mmc[] = {
+ {
+ .mmc = 1,
+ .caps = MMC_CAP_4_BIT_DATA,
+ .gpio_cd = 144,
+ .gpio_wp = 59,
+ },
+ {
+ .mmc = 2,
+ .caps = MMC_CAP_4_BIT_DATA,
+ .gpio_cd = -EINVAL,
+ .gpio_wp = -EINVAL,
+ },
+ {} /* Terminator */
+};
+#else
+#define cm_t3517_mmc NULL
+#endif
+
#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
#define RTC_IO_GPIO (153)
#define RTC_WR_GPIO (154)
@@ -166,7 +188,7 @@ static inline void cm_t3517_init_rtc(void) {}
#define HSUSB2_RESET_GPIO (147)
#define USB_HUB_RESET_GPIO (152)
-static struct usbhs_omap_board_data cm_t3517_ehci_pdata __initdata = {
+static struct usbhs_omap_platform_data cm_t3517_ehci_pdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -271,6 +293,10 @@ static struct omap_board_mux board_mux[] __initdata = {
/* CM-T3517 USB HUB nRESET */
OMAP3_MUX(MCBSP4_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+ /* CD - GPIO144 and WP - GPIO59 for MMC1 - SB-T35 */
+ OMAP3_MUX(UART2_CTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(GPMC_CLK, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
+
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
#endif
@@ -286,6 +312,7 @@ static void __init cm_t3517_init(void)
cm_t3517_init_usbh();
cm_t3517_init_hecc();
am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1);
+ omap_hsmmc_init(cm_t3517_mmc);
}
MACHINE_START(CM_T3517, "Compulab CM-T3517")
@@ -297,6 +324,6 @@ MACHINE_START(CM_T3517, "Compulab CM-T3517")
.handle_irq = omap3_intc_handle_irq,
.init_machine = cm_t3517_init,
.init_late = am35xx_init_late,
- .timer = &omap3_gp_timer,
+ .init_time = omap3_gp_gptimer_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 12865af25d3a..53056c3b0836 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -29,6 +29,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
@@ -435,7 +436,7 @@ static struct platform_device *devkit8000_devices[] __initdata = {
&omap_dm9000_dev,
};
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -622,12 +623,13 @@ static void __init devkit8000_init(void)
omap_ads7846_init(2, OMAP3_DEVKIT_TS_GPIO, 0, NULL);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
board_nand_init(devkit8000_nand_partitions,
ARRAY_SIZE(devkit8000_nand_partitions), NAND_CS,
NAND_BUSWIDTH_16, NULL);
- omap_twl4030_audio_init("omap3beagle");
+ omap_twl4030_audio_init("omap3beagle", NULL);
/* Ensure SDRC pins are mux'd for self-refresh */
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
@@ -643,6 +645,6 @@ MACHINE_START(DEVKIT8000, "OMAP3 Devkit8000")
.handle_irq = omap3_intc_handle_irq,
.init_machine = devkit8000_init,
.init_late = omap35xx_init_late,
- .timer = &omap3_secure_timer,
+ .init_time = omap3_secure_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index 53cb380b7877..2590463e4b57 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -16,7 +16,6 @@
#include <linux/of_platform.h>
#include <linux/irqdomain.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>
#include "common.h"
@@ -65,7 +64,7 @@ DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)")
.init_irq = omap_intc_of_init,
.handle_irq = omap2_intc_handle_irq,
.init_machine = omap_generic_init,
- .timer = &omap2_timer,
+ .init_time = omap2_sync32k_timer_init,
.dt_compat = omap242x_boards_compat,
.restart = omap2xxx_restart,
MACHINE_END
@@ -84,7 +83,7 @@ DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)")
.init_irq = omap_intc_of_init,
.handle_irq = omap2_intc_handle_irq,
.init_machine = omap_generic_init,
- .timer = &omap2_timer,
+ .init_time = omap2_sync32k_timer_init,
.dt_compat = omap243x_boards_compat,
.restart = omap2xxx_restart,
MACHINE_END
@@ -103,7 +102,7 @@ DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
.init_irq = omap_intc_of_init,
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_generic_init,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.dt_compat = omap3_boards_compat,
.restart = omap3xxx_restart,
MACHINE_END
@@ -120,7 +119,7 @@ DT_MACHINE_START(OMAP3_GP_DT, "Generic OMAP3-GP (Flattened Device Tree)")
.init_irq = omap_intc_of_init,
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_generic_init,
- .timer = &omap3_secure_timer,
+ .init_time = omap3_secure_sync32k_timer_init,
.dt_compat = omap3_gp_boards_compat,
.restart = omap3xxx_restart,
MACHINE_END
@@ -139,7 +138,7 @@ DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
.init_irq = omap_intc_of_init,
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_generic_init,
- .timer = &omap3_am33xx_timer,
+ .init_time = omap3_am33xx_gptimer_timer_init,
.dt_compat = am33xx_boards_compat,
MACHINE_END
#endif
@@ -156,10 +155,9 @@ DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)")
.map_io = omap4_map_io,
.init_early = omap4430_init_early,
.init_irq = omap_gic_of_init,
- .handle_irq = gic_handle_irq,
.init_machine = omap_generic_init,
.init_late = omap4430_init_late,
- .timer = &omap4_timer,
+ .init_time = omap4_local_timer_init,
.dt_compat = omap4_boards_compat,
.restart = omap44xx_restart,
MACHINE_END
@@ -177,9 +175,8 @@ DT_MACHINE_START(OMAP5_DT, "Generic OMAP5 (Flattened Device Tree)")
.map_io = omap5_map_io,
.init_early = omap5_init_early,
.init_irq = omap_gic_of_init,
- .handle_irq = gic_handle_irq,
.init_machine = omap_generic_init,
- .timer = &omap5_timer,
+ .init_time = omap5_realtime_timer_init,
.dt_compat = omap5_boards_compat,
.restart = omap44xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 3be1311f9e33..812c829fa46f 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -342,6 +342,6 @@ MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
.handle_irq = omap2_intc_handle_irq,
.init_machine = omap_h4_init,
.init_late = omap2420_init_late,
- .timer = &omap2_timer,
+ .init_time = omap2_sync32k_timer_init,
.restart = omap2xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index 0f24cb84ba5a..bf92678a01d0 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -18,6 +18,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/input.h>
+#include <linux/usb/phy.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
@@ -300,20 +301,20 @@ static struct omap2_hsmmc_info mmc[] = {
static struct gpio_led igep_gpio_leds[] = {
[0] = {
- .name = "gpio-led:red:d0",
- .default_trigger = "default-off"
+ .name = "omap3:red:user0",
+ .default_state = 0,
},
[1] = {
- .name = "gpio-led:green:d0",
- .default_trigger = "default-off",
+ .name = "omap3:green:boot",
+ .default_state = 1,
},
[2] = {
- .name = "gpio-led:red:d1",
- .default_trigger = "default-off",
+ .name = "omap3:red:user1",
+ .default_state = 0,
},
[3] = {
- .name = "gpio-led:green:d1",
- .default_trigger = "heartbeat",
+ .name = "omap3:green:user1",
+ .default_state = 0,
.gpio = -EINVAL, /* gets replaced */
.active_low = 1,
},
@@ -526,7 +527,7 @@ static void __init igep_i2c_init(void)
omap3_pmic_init("twl4030", &igep_twldata);
}
-static const struct usbhs_omap_board_data igep2_usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data igep2_usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -537,7 +538,7 @@ static const struct usbhs_omap_board_data igep2_usbhs_bdata __initconst = {
.reset_gpio_port[2] = -EINVAL,
};
-static const struct usbhs_omap_board_data igep3_usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data igep3_usbhs_bdata __initdata = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -625,11 +626,12 @@ static void __init igep_init(void)
omap_serial_init();
omap_sdrc_init(m65kxxxxam_sdrc_params,
m65kxxxxam_sdrc_params);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
igep_flash_init();
igep_leds_init();
- omap_twl4030_audio_init("igep2");
+ omap_twl4030_audio_init("igep2", NULL);
/*
* WLAN-BT combo module from MuRata which has a Marvell WLAN
@@ -655,7 +657,7 @@ MACHINE_START(IGEP0020, "IGEP v2 board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = igep_init,
.init_late = omap35xx_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
@@ -668,6 +670,6 @@ MACHINE_START(IGEP0030, "IGEP OMAP3 module")
.handle_irq = omap3_intc_handle_irq,
.init_machine = igep_init,
.init_late = omap35xx_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index 0869f4f3d3e1..b12fe966a7b9 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -28,6 +28,7 @@
#include <linux/io.h>
#include <linux/smsc911x.h>
#include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <asm/mach-types.h>
@@ -418,6 +419,7 @@ static void __init omap_ldp_init(void)
omap_ads7846_init(1, 54, 310, NULL);
omap_serial_init();
omap_sdrc_init(NULL, NULL);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
board_nand_init(ldp_nand_partitions, ARRAY_SIZE(ldp_nand_partitions),
ZOOM_NAND_CS, 0, nand_default_timings);
@@ -435,6 +437,6 @@ MACHINE_START(OMAP_LDP, "OMAP LDP board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_ldp_init,
.init_late = omap3430_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index 0abb30fe399c..f6eeb87e4e95 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -731,7 +731,7 @@ MACHINE_START(NOKIA_N800, "Nokia N800")
.handle_irq = omap2_intc_handle_irq,
.init_machine = n8x0_init_machine,
.init_late = omap2420_init_late,
- .timer = &omap2_timer,
+ .init_time = omap2_sync32k_timer_init,
.restart = omap2xxx_restart,
MACHINE_END
@@ -744,7 +744,7 @@ MACHINE_START(NOKIA_N810, "Nokia N810")
.handle_irq = omap2_intc_handle_irq,
.init_machine = n8x0_init_machine,
.init_late = omap2420_init_late,
- .timer = &omap2_timer,
+ .init_time = omap2_sync32k_timer_init,
.restart = omap2xxx_restart,
MACHINE_END
@@ -757,6 +757,6 @@ MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX")
.handle_irq = omap2_intc_handle_irq,
.init_machine = n8x0_init_machine,
.init_late = omap2420_init_late,
- .timer = &omap2_timer,
+ .init_time = omap2_sync32k_timer_init,
.restart = omap2xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 22c483d5dfa8..c3558f93d42c 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -20,6 +20,8 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/leds.h>
+#include <linux/pwm.h>
+#include <linux/leds_pwm.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
@@ -30,6 +32,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
@@ -55,6 +58,32 @@
#define NAND_CS 0
+static struct pwm_lookup pwm_lookup[] = {
+ /* LEDB -> PMU_STAT */
+ PWM_LOOKUP("twl-pwmled", 1, "leds_pwm", "beagleboard::pmu_stat"),
+};
+
+static struct led_pwm pwm_leds[] = {
+ {
+ .name = "beagleboard::pmu_stat",
+ .max_brightness = 127,
+ .pwm_period_ns = 7812500,
+ },
+};
+
+static struct led_pwm_platform_data pwm_data = {
+ .num_leds = ARRAY_SIZE(pwm_leds),
+ .leds = pwm_leds,
+};
+
+static struct platform_device leds_pwm = {
+ .name = "leds_pwm",
+ .id = -1,
+ .dev = {
+ .platform_data = &pwm_data,
+ },
+};
+
/*
* OMAP3 Beagle revision
* Run time detection of Beagle revision is done by reading GPIO.
@@ -292,9 +321,6 @@ static int beagle_twl_gpio_setup(struct device *dev,
gpio_request_one(gpio + TWL4030_GPIO_MAX, beagle_config.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;
}
@@ -376,11 +402,6 @@ static struct gpio_led gpio_leds[] = {
.default_trigger = "mmc0",
.gpio = 149,
},
- {
- .name = "beagleboard::pmu_stat",
- .gpio = -EINVAL, /* gets replaced */
- .active_low = true,
- },
};
static struct gpio_led_platform_data gpio_led_info = {
@@ -428,9 +449,10 @@ static struct platform_device *omap3_beagle_devices[] __initdata = {
&leds_gpio,
&keys_gpio,
&madc_hwmon,
+ &leds_pwm,
};
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
@@ -494,7 +516,7 @@ static int __init beagle_opp_init(void)
}
return 0;
}
-device_initcall(beagle_opp_init);
+omap_device_initcall(beagle_opp_init);
static void __init omap3_beagle_init(void)
{
@@ -519,12 +541,13 @@ static void __init omap3_beagle_init(void)
omap_sdrc_init(mt46h32m32lf6_sdrc_params,
mt46h32m32lf6_sdrc_params);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
board_nand_init(omap3beagle_nand_partitions,
ARRAY_SIZE(omap3beagle_nand_partitions), NAND_CS,
NAND_BUSWIDTH_16, NULL);
- omap_twl4030_audio_init("omap3beagle");
+ omap_twl4030_audio_init("omap3beagle", NULL);
/* Ensure msecure is mux'd to be able to set the RTC. */
omap_mux_init_signal("sys_drm_msecure", OMAP_PIN_OFF_OUTPUT_HIGH);
@@ -532,6 +555,8 @@ static void __init omap3_beagle_init(void)
/* Ensure SDRC pins are mux'd for self-refresh */
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
+
+ pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup));
}
MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
@@ -544,6 +569,6 @@ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap3_beagle_init,
.init_late = omap3_init_late,
- .timer = &omap3_secure_timer,
+ .init_time = omap3_secure_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 3985f35aee06..48789e0bb915 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -41,6 +41,7 @@
#include <linux/regulator/machine.h>
#include <linux/mmc/host.h>
#include <linux/export.h>
+#include <linux/usb/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -309,7 +310,7 @@ static struct omap2_hsmmc_info mmc[] = {
.gpio_wp = 63,
.deferred = true,
},
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
{
.name = "wl1271",
.mmc = 2,
@@ -450,7 +451,7 @@ static struct regulator_init_data omap3evm_vio = {
.consumer_supplies = omap3evm_vio_supply,
};
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
#define OMAP3EVM_WLAN_PMENA_GPIO (150)
#define OMAP3EVM_WLAN_IRQ_GPIO (149)
@@ -538,7 +539,7 @@ static int __init omap3_evm_i2c_init(void)
return 0;
}
-static struct usbhs_omap_board_data usbhs_bdata __initdata = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
@@ -563,7 +564,7 @@ static struct omap_board_mux omap35x_board_mux[] __initdata = {
OMAP_PIN_OFF_NONE),
OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP |
OMAP_PIN_OFF_NONE),
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
/* WLAN IRQ - GPIO 149 */
OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
@@ -601,7 +602,7 @@ static struct omap_board_mux omap36x_board_mux[] __initdata = {
OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
/* WLAN IRQ - GPIO 149 */
OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
@@ -637,7 +638,7 @@ static struct gpio omap3_evm_ehci_gpios[] __initdata = {
static void __init omap3_evm_wl12xx_init(void)
{
-#ifdef CONFIG_WL12XX_PLATFORM_DATA
+#ifdef CONFIG_WILINK_PLATFORM_DATA
int ret;
/* WL12xx WLAN Init */
@@ -734,6 +735,7 @@ static void __init omap3_evm_init(void)
omap_mux_init_gpio(135, OMAP_PIN_OUTPUT);
usbhs_bdata.reset_gpio_port[1] = 135;
}
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(&musb_board_data);
usbhs_init(&usbhs_bdata);
board_nand_init(omap3evm_nand_partitions,
@@ -744,7 +746,7 @@ static void __init omap3_evm_init(void)
omap3evm_init_smsc911x();
omap3_evm_display_init();
omap3_evm_wl12xx_init();
- omap_twl4030_audio_init("omap3evm");
+ omap_twl4030_audio_init("omap3evm", NULL);
}
MACHINE_START(OMAP3EVM, "OMAP3 EVM")
@@ -757,6 +759,6 @@ MACHINE_START(OMAP3EVM, "OMAP3 EVM")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap3_evm_init,
.init_late = omap35xx_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c
index 2a065ba6eb58..bab51e64c4b5 100644
--- a/arch/arm/mach-omap2/board-omap3logic.c
+++ b/arch/arm/mach-omap2/board-omap3logic.c
@@ -29,6 +29,7 @@
#include <linux/i2c/twl.h>
#include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -215,6 +216,7 @@ static void __init omap3logic_init(void)
board_mmc_init();
board_smsc911x_init();
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
/* Ensure SDRC pins are mux'd for self-refresh */
@@ -231,7 +233,7 @@ MACHINE_START(OMAP3_TORPEDO, "Logic OMAP3 Torpedo board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap3logic_init,
.init_late = omap35xx_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
@@ -244,6 +246,6 @@ MACHINE_START(OMAP3530_LV_SOM, "OMAP Logic 3530 LV SOM board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap3logic_init,
.init_late = omap35xx_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index a53a6683c1b8..2bba362148a0 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -35,6 +35,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/regulator/fixed.h>
+#include <linux/usb/phy.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <asm/mach-types.h>
@@ -567,7 +568,7 @@ static struct platform_device *omap3pandora_devices[] __initdata = {
&pandora_backlight,
};
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
@@ -601,6 +602,7 @@ static void __init omap3pandora_init(void)
ARRAY_SIZE(omap3pandora_spi_board_info));
omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 0, NULL);
usbhs_init(&usbhs_bdata);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
gpmc_nand_init(&pandora_nand_data, NULL);
@@ -618,6 +620,6 @@ MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap3pandora_init,
.init_late = omap35xx_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index 53a6cbcf9747..95c10b3aa678 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -33,6 +33,7 @@
#include <linux/interrupt.h>
#include <linux/smsc911x.h>
#include <linux/i2c/at24.h>
+#include <linux/usb/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -361,7 +362,7 @@ static struct platform_device *omap3_stalker_devices[] __initdata = {
&keys_gpio,
};
-static struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -404,6 +405,7 @@ static void __init omap3_stalker_init(void)
omap_serial_init();
omap_sdrc_init(mt46h32m32lf6_sdrc_params, NULL);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
omap_ads7846_init(1, OMAP3_STALKER_TS_GPIO, 310, NULL);
@@ -427,6 +429,6 @@ MACHINE_START(SBC3530, "OMAP3 STALKER")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap3_stalker_init,
.init_late = omap35xx_init_late,
- .timer = &omap3_secure_timer,
+ .init_time = omap3_secure_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index 263cb9cfbf37..bcd44fbcd877 100644
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -28,6 +28,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/spi/spi.h>
@@ -309,7 +310,7 @@ static struct platform_device *omap3_touchbook_devices[] __initdata = {
&keys_gpio,
};
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
@@ -365,6 +366,7 @@ static void __init omap3_touchbook_init(void)
/* Touchscreen and accelerometer */
omap_ads7846_init(4, OMAP3_TS_GPIO, 310, &ads7846_pdata);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
board_nand_init(omap3touchbook_nand_partitions,
@@ -386,6 +388,6 @@ MACHINE_START(TOUCHBOOK, "OMAP3 touchbook Board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap3_touchbook_init,
.init_late = omap3430_init_late,
- .timer = &omap3_secure_timer,
+ .init_time = omap3_secure_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 769c1feee1c4..b02c2f00609b 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -30,10 +30,11 @@
#include <linux/regulator/fixed.h>
#include <linux/ti_wilink_st.h>
#include <linux/usb/musb.h>
+#include <linux/usb/phy.h>
#include <linux/wl12xx.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/omap-abe-twl6040.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -139,7 +140,7 @@ static struct platform_device *panda_devices[] __initdata = {
&btwilink_device,
};
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -447,6 +448,7 @@ static void __init omap4_panda_init(void)
omap_sdrc_init(NULL, NULL);
omap4_twl6030_hsmmc_init(mmc);
omap4_ehci_init();
+ usb_bind_phy("musb-hdrc.0.auto", 0, "omap-usb2.1.auto");
usb_musb_init(&musb_board_data);
omap4_panda_display_init();
}
@@ -459,9 +461,8 @@ MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board")
.map_io = omap4_map_io,
.init_early = omap4430_init_early,
.init_irq = gic_init_irq,
- .handle_irq = gic_handle_irq,
.init_machine = omap4_panda_init,
.init_late = omap4430_init_late,
- .timer = &omap4_timer,
+ .init_time = omap4_local_timer_init,
.restart = omap44xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index c8fde3e56441..86bab51154ee 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -36,6 +36,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mmc/host.h>
+#include <linux/usb/phy.h>
#include <linux/platform_data/mtd-nand-omap2.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
@@ -457,7 +458,7 @@ static int __init overo_spi_init(void)
return 0;
}
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -499,6 +500,7 @@ static void __init overo_init(void)
mt46h32m32lf6_sdrc_params);
board_nand_init(overo_nand_partitions,
ARRAY_SIZE(overo_nand_partitions), NAND_CS, 0, NULL);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
overo_spi_init();
@@ -506,7 +508,7 @@ static void __init overo_init(void)
overo_display_init();
overo_init_led();
overo_init_keys();
- omap_twl4030_audio_init("overo");
+ omap_twl4030_audio_init("overo", NULL);
/* Ensure SDRC pins are mux'd for self-refresh */
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
@@ -551,6 +553,6 @@ MACHINE_START(OVERO, "Gumstix Overo")
.handle_irq = omap3_intc_handle_irq,
.init_machine = overo_init,
.init_late = omap35xx_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-rm680.c b/arch/arm/mach-omap2/board-rm680.c
index 0c777b75e484..345e8c4b8731 100644
--- a/arch/arm/mach-omap2/board-rm680.c
+++ b/arch/arm/mach-omap2/board-rm680.c
@@ -18,6 +18,7 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_data/mtd-onenand-omap2.h>
+#include <linux/usb/phy.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
@@ -134,6 +135,7 @@ static void __init rm680_init(void)
sdrc_params = nokia_get_sdram_timings();
omap_sdrc_init(sdrc_params, sdrc_params);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
rm680_peripherals_init();
}
@@ -147,7 +149,7 @@ MACHINE_START(NOKIA_RM680, "Nokia RM-680 board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = rm680_init,
.init_late = omap3630_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
@@ -160,6 +162,6 @@ MACHINE_START(NOKIA_RM696, "Nokia RM-696 board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = rm680_init,
.init_late = omap3630_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index cf07e289b4ea..c26d441ca4fb 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -42,7 +42,7 @@
#include <media/si4713.h>
#include <linux/leds-lp5523.h>
-#include <../drivers/staging/iio/light/tsl2563.h>
+#include <linux/platform_data/tsl2563.h>
#include <linux/lis3lv02d.h>
#if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
@@ -162,30 +162,39 @@ static struct tsl2563_platform_data rx51_tsl2563_platform_data = {
#if defined(CONFIG_LEDS_LP5523) || defined(CONFIG_LEDS_LP5523_MODULE)
static struct lp5523_led_config rx51_lp5523_led_config[] = {
{
+ .name = "lp5523:kb1",
.chan_nr = 0,
.led_current = 50,
}, {
+ .name = "lp5523:kb2",
.chan_nr = 1,
.led_current = 50,
}, {
+ .name = "lp5523:kb3",
.chan_nr = 2,
.led_current = 50,
}, {
+ .name = "lp5523:kb4",
.chan_nr = 3,
.led_current = 50,
}, {
+ .name = "lp5523:b",
.chan_nr = 4,
.led_current = 50,
}, {
+ .name = "lp5523:g",
.chan_nr = 5,
.led_current = 50,
}, {
+ .name = "lp5523:r",
.chan_nr = 6,
.led_current = 50,
}, {
+ .name = "lp5523:kb5",
.chan_nr = 7,
.led_current = 50,
}, {
+ .name = "lp5523:kb6",
.chan_nr = 8,
.led_current = 50,
}
@@ -1253,6 +1262,16 @@ static void __init rx51_init_lirc(void)
}
#endif
+static struct platform_device madc_hwmon = {
+ .name = "twl4030_madc_hwmon",
+ .id = -1,
+};
+
+static void __init rx51_init_twl4030_hwmon(void)
+{
+ platform_device_register(&madc_hwmon);
+}
+
void __init rx51_peripherals_init(void)
{
rx51_i2c_init();
@@ -1272,5 +1291,6 @@ void __init rx51_peripherals_init(void)
omap_hsmmc_init(mmc);
rx51_charger_init();
+ rx51_init_twl4030_hwmon();
}
diff --git a/arch/arm/mach-omap2/board-rx51-video.c b/arch/arm/mach-omap2/board-rx51-video.c
index 46f4fc982766..eb667261df08 100644
--- a/arch/arm/mach-omap2/board-rx51-video.c
+++ b/arch/arm/mach-omap2/board-rx51-video.c
@@ -18,6 +18,7 @@
#include <video/omapdss.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
+#include "soc.h"
#include "board-rx51.h"
#include "mux.h"
@@ -85,5 +86,5 @@ static int __init rx51_video_init(void)
return 0;
}
-subsys_initcall(rx51_video_init);
+omap_subsys_initcall(rx51_video_init);
#endif /* defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE) */
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
index d0374ea2dfb0..f7c4616cbb60 100644
--- a/arch/arm/mach-omap2/board-rx51.c
+++ b/arch/arm/mach-omap2/board-rx51.c
@@ -123,6 +123,6 @@ MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = rx51_init,
.init_late = omap3430_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-ti8168evm.c b/arch/arm/mach-omap2/board-ti8168evm.c
index 1a3e056d63a7..6273c286e1d8 100644
--- a/arch/arm/mach-omap2/board-ti8168evm.c
+++ b/arch/arm/mach-omap2/board-ti8168evm.c
@@ -43,7 +43,7 @@ MACHINE_START(TI8168EVM, "ti8168evm")
.map_io = ti81xx_map_io,
.init_early = ti81xx_init_early,
.init_irq = ti81xx_init_irq,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.init_machine = ti81xx_evm_init,
.init_late = ti81xx_init_late,
.restart = omap44xx_restart,
@@ -55,7 +55,7 @@ MACHINE_START(TI8148EVM, "ti8148evm")
.map_io = ti81xx_map_io,
.init_early = ti81xx_init_early,
.init_irq = ti81xx_init_irq,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.init_machine = ti81xx_evm_init,
.init_late = ti81xx_init_late,
.restart = omap44xx_restart,
diff --git a/arch/arm/mach-omap2/board-zoom-display.c b/arch/arm/mach-omap2/board-zoom-display.c
index 1c7c834a5b5f..8cef477d6b00 100644
--- a/arch/arm/mach-omap2/board-zoom-display.c
+++ b/arch/arm/mach-omap2/board-zoom-display.c
@@ -49,13 +49,13 @@ static void zoom_panel_disable_lcd(struct omap_dss_device *dssdev)
{
}
-/*
- * PWMA/B register offsets (TWL4030_MODULE_PWMA)
- */
+/* Register offsets in TWL4030_MODULE_INTBR */
#define TWL_INTBR_PMBR1 0xD
#define TWL_INTBR_GPBR1 0xC
-#define TWL_LED_PWMON 0x0
-#define TWL_LED_PWMOFF 0x1
+
+/* Register offsets in TWL_MODULE_PWM */
+#define TWL_LED_PWMON 0x3
+#define TWL_LED_PWMOFF 0x4
static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
{
@@ -93,8 +93,8 @@ static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
}
c = ((50 * (100 - level)) / 100) + 1;
- twl_i2c_write_u8(TWL4030_MODULE_PWM1, 0x7F, TWL_LED_PWMOFF);
- twl_i2c_write_u8(TWL4030_MODULE_PWM1, c, TWL_LED_PWMON);
+ twl_i2c_write_u8(TWL_MODULE_PWM, 0x7F, TWL_LED_PWMOFF);
+ twl_i2c_write_u8(TWL_MODULE_PWM, c, TWL_LED_PWMON);
#else
pr_warn("Backlight not enabled\n");
#endif
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index 26e07addc9d7..cdc0c1021863 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -20,6 +20,8 @@
#include <linux/wl12xx.h>
#include <linux/mmc/host.h>
#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/omap-twl4030.h>
+#include <linux/usb/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -34,11 +36,9 @@
#include "common-board-devices.h"
#define OMAP_ZOOM_WLAN_PMENA_GPIO (101)
-#define ZOOM2_HEADSET_EXTMUTE_GPIO (153)
+#define OMAP_ZOOM_TSC2004_IRQ_GPIO (153)
#define OMAP_ZOOM_WLAN_IRQ_GPIO (162)
-#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES)
-
/* Zoom2 has Qwerty keyboard*/
static uint32_t board_keymap[] = {
KEY(0, 0, KEY_E),
@@ -226,22 +226,31 @@ static struct omap2_hsmmc_info mmc[] = {
{} /* Terminator */
};
+static struct omap_tw4030_pdata omap_twl4030_audio_data = {
+ .voice_connected = true,
+ .custom_routing = true,
+
+ .has_hs = OMAP_TWL4030_LEFT | OMAP_TWL4030_RIGHT,
+ .has_hf = OMAP_TWL4030_LEFT | OMAP_TWL4030_RIGHT,
+
+ .has_mainmic = true,
+ .has_submic = true,
+ .has_hsmic = true,
+ .has_linein = OMAP_TWL4030_LEFT | OMAP_TWL4030_RIGHT,
+};
+
static int zoom_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;
omap_hsmmc_late_init(mmc);
- 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);
+ /* Audio setup */
+ omap_twl4030_audio_data.jack_detect = gpio + 2;
+ omap_twl4030_audio_init("Zoom2", &omap_twl4030_audio_data);
- return ret;
+ return 0;
}
static struct twl4030_gpio_platform_data zoom_gpio_data = {
@@ -264,14 +273,9 @@ static int __init omap_i2c_init(void)
TWL_COMMON_PDATA_MADC | TWL_COMMON_PDATA_AUDIO,
TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2);
- if (machine_is_omap_zoom2()) {
- struct twl4030_codec_data *codec_data;
- codec_data = zoom_twldata.audio->codec;
+ if (machine_is_omap_zoom2())
+ zoom_twldata.audio->codec->ramp_delay_value = 3; /* 161 ms */
- codec_data->ramp_delay_value = 3; /* 161 ms */
- codec_data->hs_extmute = 1;
- codec_data->hs_extmute_gpio = ZOOM2_HEADSET_EXTMUTE_GPIO;
- }
omap_pmic_init(1, 2400, "twl5030", 7 + OMAP_INTC_START, &zoom_twldata);
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, NULL, 0);
@@ -298,6 +302,7 @@ void __init zoom_peripherals_init(void)
omap_hsmmc_init(mmc);
omap_i2c_init();
platform_device_register(&omap_vwlan_device);
+ usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
enable_board_wakeup_source();
omap_serial_init();
diff --git a/arch/arm/mach-omap2/board-zoom.c b/arch/arm/mach-omap2/board-zoom.c
index d7fa31e67238..5e4d4c9fe61a 100644
--- a/arch/arm/mach-omap2/board-zoom.c
+++ b/arch/arm/mach-omap2/board-zoom.c
@@ -92,7 +92,7 @@ static struct mtd_partition zoom_nand_partitions[] = {
},
};
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -137,7 +137,7 @@ MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_zoom_init,
.init_late = omap3430_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
@@ -150,6 +150,6 @@ MACHINE_START(OMAP_ZOOM3, "OMAP Zoom3 board")
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_zoom_init,
.init_late = omap3630_init_late,
- .timer = &omap3_timer,
+ .init_time = omap3_sync32k_timer_init,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/cclock2420_data.c b/arch/arm/mach-omap2/cclock2420_data.c
index ab7e952d2070..0f0a97c1fcc0 100644
--- a/arch/arm/mach-omap2/cclock2420_data.c
+++ b/arch/arm/mach-omap2/cclock2420_data.c
@@ -622,15 +622,10 @@ static struct clk_hw_omap gpios_fck_hw = {
DEFINE_STRUCT_CLK(gpios_fck, gpios_fck_parent_names, aes_ick_ops);
-static struct clk wu_l4_ick;
-
-DEFINE_STRUCT_CLK_HW_OMAP(wu_l4_ick, "wkup_clkdm");
-DEFINE_STRUCT_CLK(wu_l4_ick, dpll_ck_parent_names, core_ck_ops);
-
static struct clk gpios_ick;
static const char *gpios_ick_parent_names[] = {
- "wu_l4_ick",
+ "sys_ck",
};
static struct clk_hw_omap gpios_ick_hw = {
@@ -1682,13 +1677,6 @@ static struct clk_hw_omap wdt1_ick_hw = {
DEFINE_STRUCT_CLK(wdt1_ick, gpios_ick_parent_names, aes_ick_ops);
-static struct clk wdt1_osc_ck;
-
-static const struct clk_ops wdt1_osc_ck_ops = {};
-
-DEFINE_STRUCT_CLK_HW_OMAP(wdt1_osc_ck, NULL);
-DEFINE_STRUCT_CLK(wdt1_osc_ck, sys_ck_parent_names, wdt1_osc_ck_ops);
-
static struct clk wdt3_fck;
static struct clk_hw_omap wdt3_fck_hw = {
@@ -1767,7 +1755,6 @@ static struct omap_clk omap2420_clks[] = {
CLK(NULL, "func_96m_ck", &func_96m_ck, CK_242X),
CLK(NULL, "func_48m_ck", &func_48m_ck, CK_242X),
CLK(NULL, "func_12m_ck", &func_12m_ck, CK_242X),
- CLK(NULL, "ck_wdt1_osc", &wdt1_osc_ck, CK_242X),
CLK(NULL, "sys_clkout_src", &sys_clkout_src, CK_242X),
CLK(NULL, "sys_clkout", &sys_clkout, CK_242X),
CLK(NULL, "sys_clkout2_src", &sys_clkout2_src, CK_242X),
@@ -1797,7 +1784,6 @@ static struct omap_clk omap2420_clks[] = {
/* L4 domain clocks */
CLK(NULL, "l4_ck", &l4_ck, CK_242X),
CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_242X),
- CLK(NULL, "wu_l4_ick", &wu_l4_ick, CK_242X),
/* virtual meta-group clock */
CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_242X),
/* general l4 interface ck, multi-parent functional clk */
diff --git a/arch/arm/mach-omap2/cclock2430_data.c b/arch/arm/mach-omap2/cclock2430_data.c
index eb3dab68d536..aed8f74ca076 100644
--- a/arch/arm/mach-omap2/cclock2430_data.c
+++ b/arch/arm/mach-omap2/cclock2430_data.c
@@ -601,15 +601,10 @@ static struct clk_hw_omap gpios_fck_hw = {
DEFINE_STRUCT_CLK(gpios_fck, gpio5_fck_parent_names, aes_ick_ops);
-static struct clk wu_l4_ick;
-
-DEFINE_STRUCT_CLK_HW_OMAP(wu_l4_ick, "wkup_clkdm");
-DEFINE_STRUCT_CLK(wu_l4_ick, dpll_ck_parent_names, core_ck_ops);
-
static struct clk gpios_ick;
static const char *gpios_ick_parent_names[] = {
- "wu_l4_ick",
+ "sys_ck",
};
static struct clk_hw_omap gpios_ick_hw = {
@@ -1811,13 +1806,6 @@ static struct clk_hw_omap wdt1_ick_hw = {
DEFINE_STRUCT_CLK(wdt1_ick, gpios_ick_parent_names, aes_ick_ops);
-static struct clk wdt1_osc_ck;
-
-static const struct clk_ops wdt1_osc_ck_ops = {};
-
-DEFINE_STRUCT_CLK_HW_OMAP(wdt1_osc_ck, NULL);
-DEFINE_STRUCT_CLK(wdt1_osc_ck, sys_ck_parent_names, wdt1_osc_ck_ops);
-
static struct clk wdt4_fck;
static struct clk_hw_omap wdt4_fck_hw = {
@@ -1869,7 +1857,6 @@ static struct omap_clk omap2430_clks[] = {
CLK(NULL, "func_96m_ck", &func_96m_ck, CK_243X),
CLK(NULL, "func_48m_ck", &func_48m_ck, CK_243X),
CLK(NULL, "func_12m_ck", &func_12m_ck, CK_243X),
- CLK(NULL, "ck_wdt1_osc", &wdt1_osc_ck, CK_243X),
CLK(NULL, "sys_clkout_src", &sys_clkout_src, CK_243X),
CLK(NULL, "sys_clkout", &sys_clkout, CK_243X),
CLK(NULL, "emul_ck", &emul_ck, CK_243X),
@@ -1898,7 +1885,6 @@ static struct omap_clk omap2430_clks[] = {
/* L4 domain clocks */
CLK(NULL, "l4_ck", &l4_ck, CK_243X),
CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_243X),
- CLK(NULL, "wu_l4_ick", &wu_l4_ick, CK_243X),
/* virtual meta-group clock */
CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_243X),
/* general l4 interface ck, multi-parent functional clk */
diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c
index a2cc046b47f4..cebe2b31943e 100644
--- a/arch/arm/mach-omap2/cclock44xx_data.c
+++ b/arch/arm/mach-omap2/cclock44xx_data.c
@@ -16,6 +16,10 @@
* XXX Some of the ES1 clocks have been removed/changed; once support
* is added for discriminating clocks by ES level, these should be added back
* in.
+ *
+ * XXX All of the remaining MODULEMODE clock nodes should be removed
+ * once the drivers are updated to use pm_runtime or to use the appropriate
+ * upstream clock node for rate/parent selection.
*/
#include <linux/kernel.h>
@@ -315,7 +319,7 @@ DEFINE_CLK_DIVIDER(dpll_abe_m2_ck, "dpll_abe_ck", &dpll_abe_ck, 0x0,
OMAP4430_CM_DIV_M2_DPLL_ABE, OMAP4430_DPLL_CLKOUT_DIV_SHIFT,
OMAP4430_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL);
-static const struct clk_ops dmic_fck_ops = {
+static const struct clk_ops dpll_hsd_ops = {
.enable = &omap2_dflt_clk_enable,
.disable = &omap2_dflt_clk_disable,
.is_enabled = &omap2_dflt_clk_is_enabled,
@@ -325,6 +329,12 @@ static const struct clk_ops dmic_fck_ops = {
.init = &omap2_init_clk_clkdm,
};
+static const struct clk_ops func_dmic_abe_gfclk_ops = {
+ .recalc_rate = &omap2_clksel_recalc,
+ .get_parent = &omap2_clksel_find_parent_index,
+ .set_parent = &omap2_clksel_set_parent,
+};
+
static const char *dpll_core_m3x2_ck_parents[] = {
"dpll_core_x2_ck",
};
@@ -340,7 +350,7 @@ DEFINE_CLK_OMAP_MUX_GATE(dpll_core_m3x2_ck, NULL, dpll_core_m3x2_div,
OMAP4430_DPLL_CLKOUTHIF_DIV_MASK,
OMAP4430_CM_DIV_M3_DPLL_CORE,
OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL,
- dpll_core_m3x2_ck_parents, dmic_fck_ops);
+ dpll_core_m3x2_ck_parents, dpll_hsd_ops);
DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m7x2_ck, "dpll_core_x2_ck",
&dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M7_DPLL_CORE,
@@ -547,7 +557,7 @@ DEFINE_CLK_OMAP_MUX_GATE(dpll_per_m3x2_ck, NULL, dpll_per_m3x2_div,
OMAP4430_DPLL_CLKOUTHIF_DIV_MASK,
OMAP4430_CM_DIV_M3_DPLL_PER,
OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL,
- dpll_per_m3x2_ck_parents, dmic_fck_ops);
+ dpll_per_m3x2_ck_parents, dpll_hsd_ops);
DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m4x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck,
0x0, OMAP4430_CM_DIV_M4_DPLL_PER,
@@ -749,10 +759,6 @@ DEFINE_CLK_GATE(aes2_fck, "l3_div_ck", &l3_div_ck, 0x0,
OMAP4430_CM_L4SEC_AES2_CLKCTRL,
OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-DEFINE_CLK_GATE(aess_fck, "aess_fclk", &aess_fclk, 0x0,
- OMAP4430_CM1_ABE_AESS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT,
- 0x0, NULL);
-
DEFINE_CLK_GATE(bandgap_fclk, "sys_32k_ck", &sys_32k_ck, 0x0,
OMAP4430_CM_WKUP_BANDGAP_CLKCTRL,
OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT, 0x0, NULL);
@@ -774,11 +780,6 @@ DEFINE_CLK_GATE(bandgap_ts_fclk, "div_ts_ck", &div_ts_ck, 0x0,
OMAP4460_OPTFCLKEN_TS_FCLK_SHIFT,
0x0, NULL);
-DEFINE_CLK_GATE(des3des_fck, "l4_div_ck", &l4_div_ck, 0x0,
- OMAP4430_CM_L4SEC_DES3DES_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT,
- 0x0, NULL);
-
static const char *dmic_sync_mux_ck_parents[] = {
"abe_24m_fclk", "syc_clk_div_ck", "func_24m_clk",
};
@@ -795,23 +796,13 @@ static const struct clksel func_dmic_abe_gfclk_sel[] = {
{ .parent = NULL },
};
-static const char *dmic_fck_parents[] = {
+static const char *func_dmic_abe_gfclk_parents[] = {
"dmic_sync_mux_ck", "pad_clks_ck", "slimbus_clk",
};
-/* Merged func_dmic_abe_gfclk into dmic */
-static struct clk dmic_fck;
-
-DEFINE_CLK_OMAP_MUX_GATE(dmic_fck, "abe_clkdm", func_dmic_abe_gfclk_sel,
- OMAP4430_CM1_ABE_DMIC_CLKCTRL,
- OMAP4430_CLKSEL_SOURCE_MASK,
- OMAP4430_CM1_ABE_DMIC_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- dmic_fck_parents, dmic_fck_ops);
-
-DEFINE_CLK_GATE(dsp_fck, "dpll_iva_m4x2_ck", &dpll_iva_m4x2_ck, 0x0,
- OMAP4430_CM_TESLA_TESLA_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
+DEFINE_CLK_OMAP_MUX(func_dmic_abe_gfclk, "abe_clkdm", func_dmic_abe_gfclk_sel,
+ OMAP4430_CM1_ABE_DMIC_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK,
+ func_dmic_abe_gfclk_parents, func_dmic_abe_gfclk_ops);
DEFINE_CLK_GATE(dss_sys_clk, "syc_clk_div_ck", &syc_clk_div_ck, 0x0,
OMAP4430_CM_DSS_DSS_CLKCTRL,
@@ -833,177 +824,57 @@ DEFINE_CLK_GATE(dss_fck, "l3_div_ck", &l3_div_ck, 0x0,
OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT,
0x0, NULL);
-DEFINE_CLK_GATE(efuse_ctrl_cust_fck, "sys_clkin_ck", &sys_clkin_ck, 0x0,
- OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(emif1_fck, "ddrphy_ck", &ddrphy_ck, 0x0,
- OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(emif2_fck, "ddrphy_ck", &ddrphy_ck, 0x0,
- OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
DEFINE_CLK_DIVIDER(fdif_fck, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, 0x0,
OMAP4430_CM_CAM_FDIF_CLKCTRL, OMAP4430_CLKSEL_FCLK_SHIFT,
OMAP4430_CLKSEL_FCLK_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL);
-DEFINE_CLK_GATE(fpka_fck, "l4_div_ck", &l4_div_ck, 0x0,
- OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
DEFINE_CLK_GATE(gpio1_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
OMAP4430_CM_WKUP_GPIO1_CLKCTRL,
OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL);
-DEFINE_CLK_GATE(gpio1_ick, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, 0x0,
- OMAP4430_CM_WKUP_GPIO1_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
DEFINE_CLK_GATE(gpio2_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
OMAP4430_CM_L4PER_GPIO2_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
0x0, NULL);
-DEFINE_CLK_GATE(gpio2_ick, "l4_div_ck", &l4_div_ck, 0x0,
- OMAP4430_CM_L4PER_GPIO2_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
DEFINE_CLK_GATE(gpio3_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
OMAP4430_CM_L4PER_GPIO3_CLKCTRL,
OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL);
-DEFINE_CLK_GATE(gpio3_ick, "l4_div_ck", &l4_div_ck, 0x0,
- OMAP4430_CM_L4PER_GPIO3_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
DEFINE_CLK_GATE(gpio4_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
OMAP4430_CM_L4PER_GPIO4_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
0x0, NULL);
-DEFINE_CLK_GATE(gpio4_ick, "l4_div_ck", &l4_div_ck, 0x0,
- OMAP4430_CM_L4PER_GPIO4_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
DEFINE_CLK_GATE(gpio5_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
OMAP4430_CM_L4PER_GPIO5_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
0x0, NULL);
-DEFINE_CLK_GATE(gpio5_ick, "l4_div_ck", &l4_div_ck, 0x0,
- OMAP4430_CM_L4PER_GPIO5_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
DEFINE_CLK_GATE(gpio6_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
OMAP4430_CM_L4PER_GPIO6_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
0x0, NULL);
-DEFINE_CLK_GATE(gpio6_ick, "l4_div_ck", &l4_div_ck, 0x0,
- OMAP4430_CM_L4PER_GPIO6_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(gpmc_ick, "l3_div_ck", &l3_div_ck, 0x0,
- OMAP4430_CM_L3_2_GPMC_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT,
- 0x0, NULL);
-
static const struct clksel sgx_clk_mux_sel[] = {
{ .parent = &dpll_core_m7x2_ck, .rates = div_1_0_rates },
{ .parent = &dpll_per_m7x2_ck, .rates = div_1_1_rates },
{ .parent = NULL },
};
-static const char *gpu_fck_parents[] = {
+static const char *sgx_clk_mux_parents[] = {
"dpll_core_m7x2_ck", "dpll_per_m7x2_ck",
};
-/* Merged sgx_clk_mux into gpu */
-DEFINE_CLK_OMAP_MUX_GATE(gpu_fck, "l3_gfx_clkdm", sgx_clk_mux_sel,
- OMAP4430_CM_GFX_GFX_CLKCTRL,
- OMAP4430_CLKSEL_SGX_FCLK_MASK,
- OMAP4430_CM_GFX_GFX_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- gpu_fck_parents, dmic_fck_ops);
-
-DEFINE_CLK_GATE(hdq1w_fck, "func_12m_fclk", &func_12m_fclk, 0x0,
- OMAP4430_CM_L4PER_HDQ1W_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
+DEFINE_CLK_OMAP_MUX(sgx_clk_mux, "l3_gfx_clkdm", sgx_clk_mux_sel,
+ OMAP4430_CM_GFX_GFX_CLKCTRL, OMAP4430_CLKSEL_SGX_FCLK_MASK,
+ sgx_clk_mux_parents, func_dmic_abe_gfclk_ops);
DEFINE_CLK_DIVIDER(hsi_fck, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, 0x0,
OMAP4430_CM_L3INIT_HSI_CLKCTRL, OMAP4430_CLKSEL_24_25_SHIFT,
OMAP4430_CLKSEL_24_25_WIDTH, CLK_DIVIDER_POWER_OF_TWO,
NULL);
-DEFINE_CLK_GATE(i2c1_fck, "func_96m_fclk", &func_96m_fclk, 0x0,
- OMAP4430_CM_L4PER_I2C1_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(i2c2_fck, "func_96m_fclk", &func_96m_fclk, 0x0,
- OMAP4430_CM_L4PER_I2C2_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(i2c3_fck, "func_96m_fclk", &func_96m_fclk, 0x0,
- OMAP4430_CM_L4PER_I2C3_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(i2c4_fck, "func_96m_fclk", &func_96m_fclk, 0x0,
- OMAP4430_CM_L4PER_I2C4_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(ipu_fck, "ducati_clk_mux_ck", &ducati_clk_mux_ck, 0x0,
- OMAP4430_CM_DUCATI_DUCATI_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
DEFINE_CLK_GATE(iss_ctrlclk, "func_96m_fclk", &func_96m_fclk, 0x0,
OMAP4430_CM_CAM_ISS_CLKCTRL, OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT,
0x0, NULL);
-DEFINE_CLK_GATE(iss_fck, "ducati_clk_mux_ck", &ducati_clk_mux_ck, 0x0,
- OMAP4430_CM_CAM_ISS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT,
- 0x0, NULL);
-
-DEFINE_CLK_GATE(iva_fck, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck, 0x0,
- OMAP4430_CM_IVAHD_IVAHD_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(kbd_fck, "sys_32k_ck", &sys_32k_ck, 0x0,
- OMAP4430_CM_WKUP_KEYBOARD_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-static struct clk l3_instr_ick;
-
-static const char *l3_instr_ick_parent_names[] = {
- "l3_div_ck",
-};
-
-static const struct clk_ops l3_instr_ick_ops = {
- .enable = &omap2_dflt_clk_enable,
- .disable = &omap2_dflt_clk_disable,
- .is_enabled = &omap2_dflt_clk_is_enabled,
- .init = &omap2_init_clk_clkdm,
-};
-
-static struct clk_hw_omap l3_instr_ick_hw = {
- .hw = {
- .clk = &l3_instr_ick,
- },
- .enable_reg = OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_HWCTRL_SHIFT,
- .clkdm_name = "l3_instr_clkdm",
-};
-
-DEFINE_STRUCT_CLK(l3_instr_ick, l3_instr_ick_parent_names, l3_instr_ick_ops);
-
-static struct clk l3_main_3_ick;
-static struct clk_hw_omap l3_main_3_ick_hw = {
- .hw = {
- .clk = &l3_main_3_ick,
- },
- .enable_reg = OMAP4430_CM_L3INSTR_L3_3_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_HWCTRL_SHIFT,
- .clkdm_name = "l3_instr_clkdm",
-};
-
-DEFINE_STRUCT_CLK(l3_main_3_ick, l3_instr_ick_parent_names, l3_instr_ick_ops);
-
DEFINE_CLK_MUX(mcasp_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0,
OMAP4430_CM1_ABE_MCASP_CLKCTRL,
OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT,
@@ -1016,17 +887,13 @@ static const struct clksel func_mcasp_abe_gfclk_sel[] = {
{ .parent = NULL },
};
-static const char *mcasp_fck_parents[] = {
+static const char *func_mcasp_abe_gfclk_parents[] = {
"mcasp_sync_mux_ck", "pad_clks_ck", "slimbus_clk",
};
-/* Merged func_mcasp_abe_gfclk into mcasp */
-DEFINE_CLK_OMAP_MUX_GATE(mcasp_fck, "abe_clkdm", func_mcasp_abe_gfclk_sel,
- OMAP4430_CM1_ABE_MCASP_CLKCTRL,
- OMAP4430_CLKSEL_SOURCE_MASK,
- OMAP4430_CM1_ABE_MCASP_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- mcasp_fck_parents, dmic_fck_ops);
+DEFINE_CLK_OMAP_MUX(func_mcasp_abe_gfclk, "abe_clkdm", func_mcasp_abe_gfclk_sel,
+ OMAP4430_CM1_ABE_MCASP_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK,
+ func_mcasp_abe_gfclk_parents, func_dmic_abe_gfclk_ops);
DEFINE_CLK_MUX(mcbsp1_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0,
OMAP4430_CM1_ABE_MCBSP1_CLKCTRL,
@@ -1040,17 +907,14 @@ static const struct clksel func_mcbsp1_gfclk_sel[] = {
{ .parent = NULL },
};
-static const char *mcbsp1_fck_parents[] = {
+static const char *func_mcbsp1_gfclk_parents[] = {
"mcbsp1_sync_mux_ck", "pad_clks_ck", "slimbus_clk",
};
-/* Merged func_mcbsp1_gfclk into mcbsp1 */
-DEFINE_CLK_OMAP_MUX_GATE(mcbsp1_fck, "abe_clkdm", func_mcbsp1_gfclk_sel,
- OMAP4430_CM1_ABE_MCBSP1_CLKCTRL,
- OMAP4430_CLKSEL_SOURCE_MASK,
- OMAP4430_CM1_ABE_MCBSP1_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- mcbsp1_fck_parents, dmic_fck_ops);
+DEFINE_CLK_OMAP_MUX(func_mcbsp1_gfclk, "abe_clkdm", func_mcbsp1_gfclk_sel,
+ OMAP4430_CM1_ABE_MCBSP1_CLKCTRL,
+ OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp1_gfclk_parents,
+ func_dmic_abe_gfclk_ops);
DEFINE_CLK_MUX(mcbsp2_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0,
OMAP4430_CM1_ABE_MCBSP2_CLKCTRL,
@@ -1064,17 +928,14 @@ static const struct clksel func_mcbsp2_gfclk_sel[] = {
{ .parent = NULL },
};
-static const char *mcbsp2_fck_parents[] = {
+static const char *func_mcbsp2_gfclk_parents[] = {
"mcbsp2_sync_mux_ck", "pad_clks_ck", "slimbus_clk",
};
-/* Merged func_mcbsp2_gfclk into mcbsp2 */
-DEFINE_CLK_OMAP_MUX_GATE(mcbsp2_fck, "abe_clkdm", func_mcbsp2_gfclk_sel,
- OMAP4430_CM1_ABE_MCBSP2_CLKCTRL,
- OMAP4430_CLKSEL_SOURCE_MASK,
- OMAP4430_CM1_ABE_MCBSP2_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- mcbsp2_fck_parents, dmic_fck_ops);
+DEFINE_CLK_OMAP_MUX(func_mcbsp2_gfclk, "abe_clkdm", func_mcbsp2_gfclk_sel,
+ OMAP4430_CM1_ABE_MCBSP2_CLKCTRL,
+ OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp2_gfclk_parents,
+ func_dmic_abe_gfclk_ops);
DEFINE_CLK_MUX(mcbsp3_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0,
OMAP4430_CM1_ABE_MCBSP3_CLKCTRL,
@@ -1088,17 +949,14 @@ static const struct clksel func_mcbsp3_gfclk_sel[] = {
{ .parent = NULL },
};
-static const char *mcbsp3_fck_parents[] = {
+static const char *func_mcbsp3_gfclk_parents[] = {
"mcbsp3_sync_mux_ck", "pad_clks_ck", "slimbus_clk",
};
-/* Merged func_mcbsp3_gfclk into mcbsp3 */
-DEFINE_CLK_OMAP_MUX_GATE(mcbsp3_fck, "abe_clkdm", func_mcbsp3_gfclk_sel,
- OMAP4430_CM1_ABE_MCBSP3_CLKCTRL,
- OMAP4430_CLKSEL_SOURCE_MASK,
- OMAP4430_CM1_ABE_MCBSP3_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- mcbsp3_fck_parents, dmic_fck_ops);
+DEFINE_CLK_OMAP_MUX(func_mcbsp3_gfclk, "abe_clkdm", func_mcbsp3_gfclk_sel,
+ OMAP4430_CM1_ABE_MCBSP3_CLKCTRL,
+ OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp3_gfclk_parents,
+ func_dmic_abe_gfclk_ops);
static const char *mcbsp4_sync_mux_ck_parents[] = {
"func_96m_fclk", "per_abe_nc_fclk",
@@ -1115,37 +973,14 @@ static const struct clksel per_mcbsp4_gfclk_sel[] = {
{ .parent = NULL },
};
-static const char *mcbsp4_fck_parents[] = {
+static const char *per_mcbsp4_gfclk_parents[] = {
"mcbsp4_sync_mux_ck", "pad_clks_ck",
};
-/* Merged per_mcbsp4_gfclk into mcbsp4 */
-DEFINE_CLK_OMAP_MUX_GATE(mcbsp4_fck, "l4_per_clkdm", per_mcbsp4_gfclk_sel,
- OMAP4430_CM_L4PER_MCBSP4_CLKCTRL,
- OMAP4430_CLKSEL_SOURCE_24_24_MASK,
- OMAP4430_CM_L4PER_MCBSP4_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- mcbsp4_fck_parents, dmic_fck_ops);
-
-DEFINE_CLK_GATE(mcpdm_fck, "pad_clks_ck", &pad_clks_ck, 0x0,
- OMAP4430_CM1_ABE_PDM_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT,
- 0x0, NULL);
-
-DEFINE_CLK_GATE(mcspi1_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_MCSPI1_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(mcspi2_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_MCSPI2_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(mcspi3_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_MCSPI3_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(mcspi4_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_MCSPI4_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
+DEFINE_CLK_OMAP_MUX(per_mcbsp4_gfclk, "l4_per_clkdm", per_mcbsp4_gfclk_sel,
+ OMAP4430_CM_L4PER_MCBSP4_CLKCTRL,
+ OMAP4430_CLKSEL_SOURCE_24_24_MASK, per_mcbsp4_gfclk_parents,
+ func_dmic_abe_gfclk_ops);
static const struct clksel hsmmc1_fclk_sel[] = {
{ .parent = &func_64m_fclk, .rates = div_1_0_rates },
@@ -1153,69 +988,22 @@ static const struct clksel hsmmc1_fclk_sel[] = {
{ .parent = NULL },
};
-static const char *mmc1_fck_parents[] = {
+static const char *hsmmc1_fclk_parents[] = {
"func_64m_fclk", "func_96m_fclk",
};
-/* Merged hsmmc1_fclk into mmc1 */
-DEFINE_CLK_OMAP_MUX_GATE(mmc1_fck, "l3_init_clkdm", hsmmc1_fclk_sel,
- OMAP4430_CM_L3INIT_MMC1_CLKCTRL, OMAP4430_CLKSEL_MASK,
- OMAP4430_CM_L3INIT_MMC1_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- mmc1_fck_parents, dmic_fck_ops);
-
-/* Merged hsmmc2_fclk into mmc2 */
-DEFINE_CLK_OMAP_MUX_GATE(mmc2_fck, "l3_init_clkdm", hsmmc1_fclk_sel,
- OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK,
- OMAP4430_CM_L3INIT_MMC2_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- mmc1_fck_parents, dmic_fck_ops);
-
-DEFINE_CLK_GATE(mmc3_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_MMCSD3_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(mmc4_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_MMCSD4_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(mmc5_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_MMCSD5_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(ocp2scp_usb_phy_phy_48m, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
- OMAP4430_OPTFCLKEN_PHY_48M_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(ocp2scp_usb_phy_ick, "l4_div_ck", &l4_div_ck, 0x0,
- OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
- OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
-static struct clk ocp_wp_noc_ick;
-
-static struct clk_hw_omap ocp_wp_noc_ick_hw = {
- .hw = {
- .clk = &ocp_wp_noc_ick,
- },
- .enable_reg = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL,
- .enable_bit = OMAP4430_MODULEMODE_HWCTRL_SHIFT,
- .clkdm_name = "l3_instr_clkdm",
-};
-
-DEFINE_STRUCT_CLK(ocp_wp_noc_ick, l3_instr_ick_parent_names, l3_instr_ick_ops);
+DEFINE_CLK_OMAP_MUX(hsmmc1_fclk, "l3_init_clkdm", hsmmc1_fclk_sel,
+ OMAP4430_CM_L3INIT_MMC1_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops);
-DEFINE_CLK_GATE(rng_ick, "l4_div_ck", &l4_div_ck, 0x0,
- OMAP4430_CM_L4SEC_RNG_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT,
- 0x0, NULL);
+DEFINE_CLK_OMAP_MUX(hsmmc2_fclk, "l3_init_clkdm", hsmmc1_fclk_sel,
+ OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops);
DEFINE_CLK_GATE(sha2md5_fck, "l3_div_ck", &l3_div_ck, 0x0,
OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL,
OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-DEFINE_CLK_GATE(sl2if_ick, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck, 0x0,
- OMAP4430_CM_IVAHD_SL2_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT,
- 0x0, NULL);
-
DEFINE_CLK_GATE(slimbus1_fclk_1, "func_24m_clk", &func_24m_clk, 0x0,
OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
OMAP4430_OPTFCLKEN_FCLK1_SHIFT, 0x0, NULL);
@@ -1232,10 +1020,6 @@ DEFINE_CLK_GATE(slimbus1_slimbus_clk, "slimbus_clk", &slimbus_clk, 0x0,
OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT, 0x0, NULL);
-DEFINE_CLK_GATE(slimbus1_fck, "ocp_abe_iclk", &ocp_abe_iclk, 0x0,
- OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
DEFINE_CLK_GATE(slimbus2_fclk_1, "per_abe_24m_fclk", &per_abe_24m_fclk, 0x0,
OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT, 0x0, NULL);
@@ -1249,10 +1033,6 @@ DEFINE_CLK_GATE(slimbus2_slimbus_clk, "pad_slimbus_core_clks_ck",
OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT, 0x0, NULL);
-DEFINE_CLK_GATE(slimbus2_fck, "l4_div_ck", &l4_div_ck, 0x0,
- OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
DEFINE_CLK_GATE(smartreflex_core_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck,
0x0, OMAP4430_CM_ALWON_SR_CORE_CLKCTRL,
OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
@@ -1271,52 +1051,35 @@ static const struct clksel dmt1_clk_mux_sel[] = {
{ .parent = NULL },
};
-/* Merged dmt1_clk_mux into timer1 */
-DEFINE_CLK_OMAP_MUX_GATE(timer1_fck, "l4_wkup_clkdm", dmt1_clk_mux_sel,
- OMAP4430_CM_WKUP_TIMER1_CLKCTRL, OMAP4430_CLKSEL_MASK,
- OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops);
-
-/* Merged cm2_dm10_mux into timer10 */
-DEFINE_CLK_OMAP_MUX_GATE(timer10_fck, "l4_per_clkdm", dmt1_clk_mux_sel,
- OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
- OMAP4430_CLKSEL_MASK,
- OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops);
-
-/* Merged cm2_dm11_mux into timer11 */
-DEFINE_CLK_OMAP_MUX_GATE(timer11_fck, "l4_per_clkdm", dmt1_clk_mux_sel,
- OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
- OMAP4430_CLKSEL_MASK,
- OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops);
-
-/* Merged cm2_dm2_mux into timer2 */
-DEFINE_CLK_OMAP_MUX_GATE(timer2_fck, "l4_per_clkdm", dmt1_clk_mux_sel,
- OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
- OMAP4430_CLKSEL_MASK,
- OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops);
-
-/* Merged cm2_dm3_mux into timer3 */
-DEFINE_CLK_OMAP_MUX_GATE(timer3_fck, "l4_per_clkdm", dmt1_clk_mux_sel,
- OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
- OMAP4430_CLKSEL_MASK,
- OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops);
-
-/* Merged cm2_dm4_mux into timer4 */
-DEFINE_CLK_OMAP_MUX_GATE(timer4_fck, "l4_per_clkdm", dmt1_clk_mux_sel,
- OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
- OMAP4430_CLKSEL_MASK,
- OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops);
+DEFINE_CLK_OMAP_MUX(dmt1_clk_mux, "l4_wkup_clkdm", dmt1_clk_mux_sel,
+ OMAP4430_CM_WKUP_TIMER1_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ abe_dpll_bypass_clk_mux_ck_parents,
+ func_dmic_abe_gfclk_ops);
+
+DEFINE_CLK_OMAP_MUX(cm2_dm10_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
+ OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ abe_dpll_bypass_clk_mux_ck_parents,
+ func_dmic_abe_gfclk_ops);
+
+DEFINE_CLK_OMAP_MUX(cm2_dm11_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
+ OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ abe_dpll_bypass_clk_mux_ck_parents,
+ func_dmic_abe_gfclk_ops);
+
+DEFINE_CLK_OMAP_MUX(cm2_dm2_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
+ OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ abe_dpll_bypass_clk_mux_ck_parents,
+ func_dmic_abe_gfclk_ops);
+
+DEFINE_CLK_OMAP_MUX(cm2_dm3_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
+ OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ abe_dpll_bypass_clk_mux_ck_parents,
+ func_dmic_abe_gfclk_ops);
+
+DEFINE_CLK_OMAP_MUX(cm2_dm4_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
+ OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ abe_dpll_bypass_clk_mux_ck_parents,
+ func_dmic_abe_gfclk_ops);
static const struct clksel timer5_sync_mux_sel[] = {
{ .parent = &syc_clk_div_ck, .rates = div_1_0_rates },
@@ -1324,61 +1087,30 @@ static const struct clksel timer5_sync_mux_sel[] = {
{ .parent = NULL },
};
-static const char *timer5_fck_parents[] = {
+static const char *timer5_sync_mux_parents[] = {
"syc_clk_div_ck", "sys_32k_ck",
};
-/* Merged timer5_sync_mux into timer5 */
-DEFINE_CLK_OMAP_MUX_GATE(timer5_fck, "abe_clkdm", timer5_sync_mux_sel,
- OMAP4430_CM1_ABE_TIMER5_CLKCTRL, OMAP4430_CLKSEL_MASK,
- OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- timer5_fck_parents, dmic_fck_ops);
-
-/* Merged timer6_sync_mux into timer6 */
-DEFINE_CLK_OMAP_MUX_GATE(timer6_fck, "abe_clkdm", timer5_sync_mux_sel,
- OMAP4430_CM1_ABE_TIMER6_CLKCTRL, OMAP4430_CLKSEL_MASK,
- OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- timer5_fck_parents, dmic_fck_ops);
-
-/* Merged timer7_sync_mux into timer7 */
-DEFINE_CLK_OMAP_MUX_GATE(timer7_fck, "abe_clkdm", timer5_sync_mux_sel,
- OMAP4430_CM1_ABE_TIMER7_CLKCTRL, OMAP4430_CLKSEL_MASK,
- OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- timer5_fck_parents, dmic_fck_ops);
-
-/* Merged timer8_sync_mux into timer8 */
-DEFINE_CLK_OMAP_MUX_GATE(timer8_fck, "abe_clkdm", timer5_sync_mux_sel,
- OMAP4430_CM1_ABE_TIMER8_CLKCTRL, OMAP4430_CLKSEL_MASK,
- OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- timer5_fck_parents, dmic_fck_ops);
-
-/* Merged cm2_dm9_mux into timer9 */
-DEFINE_CLK_OMAP_MUX_GATE(timer9_fck, "l4_per_clkdm", dmt1_clk_mux_sel,
- OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
- OMAP4430_CLKSEL_MASK,
- OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, NULL,
- abe_dpll_bypass_clk_mux_ck_parents, dmic_fck_ops);
-
-DEFINE_CLK_GATE(uart1_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_UART1_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
+DEFINE_CLK_OMAP_MUX(timer5_sync_mux, "abe_clkdm", timer5_sync_mux_sel,
+ OMAP4430_CM1_ABE_TIMER5_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ timer5_sync_mux_parents, func_dmic_abe_gfclk_ops);
-DEFINE_CLK_GATE(uart2_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_UART2_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
+DEFINE_CLK_OMAP_MUX(timer6_sync_mux, "abe_clkdm", timer5_sync_mux_sel,
+ OMAP4430_CM1_ABE_TIMER6_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ timer5_sync_mux_parents, func_dmic_abe_gfclk_ops);
-DEFINE_CLK_GATE(uart3_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_UART3_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
+DEFINE_CLK_OMAP_MUX(timer7_sync_mux, "abe_clkdm", timer5_sync_mux_sel,
+ OMAP4430_CM1_ABE_TIMER7_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ timer5_sync_mux_parents, func_dmic_abe_gfclk_ops);
-DEFINE_CLK_GATE(uart4_fck, "func_48m_fclk", &func_48m_fclk, 0x0,
- OMAP4430_CM_L4PER_UART4_CLKCTRL,
- OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
+DEFINE_CLK_OMAP_MUX(timer8_sync_mux, "abe_clkdm", timer5_sync_mux_sel,
+ OMAP4430_CM1_ABE_TIMER8_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ timer5_sync_mux_parents, func_dmic_abe_gfclk_ops);
+
+DEFINE_CLK_OMAP_MUX(cm2_dm9_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
+ OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, OMAP4430_CLKSEL_MASK,
+ abe_dpll_bypass_clk_mux_ck_parents,
+ func_dmic_abe_gfclk_ops);
static struct clk usb_host_fs_fck;
@@ -1512,18 +1244,6 @@ DEFINE_CLK_GATE(usim_fclk, "usim_ck", &usim_ck, 0x0,
OMAP4430_CM_WKUP_USIM_CLKCTRL, OMAP4430_OPTFCLKEN_FCLK_SHIFT,
0x0, NULL);
-DEFINE_CLK_GATE(usim_fck, "sys_32k_ck", &sys_32k_ck, 0x0,
- OMAP4430_CM_WKUP_USIM_CLKCTRL, OMAP4430_MODULEMODE_HWCTRL_SHIFT,
- 0x0, NULL);
-
-DEFINE_CLK_GATE(wd_timer2_fck, "sys_32k_ck", &sys_32k_ck, 0x0,
- OMAP4430_CM_WKUP_WDT2_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT,
- 0x0, NULL);
-
-DEFINE_CLK_GATE(wd_timer3_fck, "sys_32k_ck", &sys_32k_ck, 0x0,
- OMAP4430_CM1_ABE_WDT3_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT,
- 0x0, NULL);
-
/* Remaining optional clocks */
static const char *pmd_stm_clock_mux_ck_parents[] = {
"sys_clkin_ck", "dpll_core_m6x2_ck", "tie_low_clock_ck",
@@ -1774,106 +1494,61 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "syc_clk_div_ck", &syc_clk_div_ck, CK_443X),
CLK(NULL, "aes1_fck", &aes1_fck, CK_443X),
CLK(NULL, "aes2_fck", &aes2_fck, CK_443X),
- CLK(NULL, "aess_fck", &aess_fck, CK_443X),
CLK(NULL, "bandgap_fclk", &bandgap_fclk, CK_443X),
CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X),
CLK(NULL, "bandgap_ts_fclk", &bandgap_ts_fclk, CK_446X),
- CLK(NULL, "des3des_fck", &des3des_fck, CK_443X),
CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X),
- CLK(NULL, "dmic_fck", &dmic_fck, CK_443X),
- CLK(NULL, "dsp_fck", &dsp_fck, CK_443X),
+ CLK(NULL, "func_dmic_abe_gfclk", &func_dmic_abe_gfclk, CK_443X),
CLK(NULL, "dss_sys_clk", &dss_sys_clk, CK_443X),
CLK(NULL, "dss_tv_clk", &dss_tv_clk, CK_443X),
CLK(NULL, "dss_dss_clk", &dss_dss_clk, CK_443X),
CLK(NULL, "dss_48mhz_clk", &dss_48mhz_clk, CK_443X),
CLK(NULL, "dss_fck", &dss_fck, CK_443X),
CLK("omapdss_dss", "ick", &dss_fck, CK_443X),
- CLK(NULL, "efuse_ctrl_cust_fck", &efuse_ctrl_cust_fck, CK_443X),
- CLK(NULL, "emif1_fck", &emif1_fck, CK_443X),
- CLK(NULL, "emif2_fck", &emif2_fck, CK_443X),
CLK(NULL, "fdif_fck", &fdif_fck, CK_443X),
- CLK(NULL, "fpka_fck", &fpka_fck, CK_443X),
CLK(NULL, "gpio1_dbclk", &gpio1_dbclk, CK_443X),
- CLK(NULL, "gpio1_ick", &gpio1_ick, CK_443X),
CLK(NULL, "gpio2_dbclk", &gpio2_dbclk, CK_443X),
- CLK(NULL, "gpio2_ick", &gpio2_ick, CK_443X),
CLK(NULL, "gpio3_dbclk", &gpio3_dbclk, CK_443X),
- CLK(NULL, "gpio3_ick", &gpio3_ick, CK_443X),
CLK(NULL, "gpio4_dbclk", &gpio4_dbclk, CK_443X),
- CLK(NULL, "gpio4_ick", &gpio4_ick, CK_443X),
CLK(NULL, "gpio5_dbclk", &gpio5_dbclk, CK_443X),
- CLK(NULL, "gpio5_ick", &gpio5_ick, CK_443X),
CLK(NULL, "gpio6_dbclk", &gpio6_dbclk, CK_443X),
- CLK(NULL, "gpio6_ick", &gpio6_ick, CK_443X),
- CLK(NULL, "gpmc_ick", &gpmc_ick, CK_443X),
- CLK(NULL, "gpu_fck", &gpu_fck, CK_443X),
- CLK(NULL, "hdq1w_fck", &hdq1w_fck, CK_443X),
+ CLK(NULL, "sgx_clk_mux", &sgx_clk_mux, CK_443X),
CLK(NULL, "hsi_fck", &hsi_fck, CK_443X),
- CLK(NULL, "i2c1_fck", &i2c1_fck, CK_443X),
- CLK(NULL, "i2c2_fck", &i2c2_fck, CK_443X),
- CLK(NULL, "i2c3_fck", &i2c3_fck, CK_443X),
- CLK(NULL, "i2c4_fck", &i2c4_fck, CK_443X),
- CLK(NULL, "ipu_fck", &ipu_fck, CK_443X),
CLK(NULL, "iss_ctrlclk", &iss_ctrlclk, CK_443X),
- CLK(NULL, "iss_fck", &iss_fck, CK_443X),
- CLK(NULL, "iva_fck", &iva_fck, CK_443X),
- CLK(NULL, "kbd_fck", &kbd_fck, CK_443X),
- CLK(NULL, "l3_instr_ick", &l3_instr_ick, CK_443X),
- CLK(NULL, "l3_main_3_ick", &l3_main_3_ick, CK_443X),
CLK(NULL, "mcasp_sync_mux_ck", &mcasp_sync_mux_ck, CK_443X),
- CLK(NULL, "mcasp_fck", &mcasp_fck, CK_443X),
+ CLK(NULL, "func_mcasp_abe_gfclk", &func_mcasp_abe_gfclk, CK_443X),
CLK(NULL, "mcbsp1_sync_mux_ck", &mcbsp1_sync_mux_ck, CK_443X),
- CLK(NULL, "mcbsp1_fck", &mcbsp1_fck, CK_443X),
+ CLK(NULL, "func_mcbsp1_gfclk", &func_mcbsp1_gfclk, CK_443X),
CLK(NULL, "mcbsp2_sync_mux_ck", &mcbsp2_sync_mux_ck, CK_443X),
- CLK(NULL, "mcbsp2_fck", &mcbsp2_fck, CK_443X),
+ CLK(NULL, "func_mcbsp2_gfclk", &func_mcbsp2_gfclk, CK_443X),
CLK(NULL, "mcbsp3_sync_mux_ck", &mcbsp3_sync_mux_ck, CK_443X),
- CLK(NULL, "mcbsp3_fck", &mcbsp3_fck, CK_443X),
+ CLK(NULL, "func_mcbsp3_gfclk", &func_mcbsp3_gfclk, CK_443X),
CLK(NULL, "mcbsp4_sync_mux_ck", &mcbsp4_sync_mux_ck, CK_443X),
- CLK(NULL, "mcbsp4_fck", &mcbsp4_fck, CK_443X),
- CLK(NULL, "mcpdm_fck", &mcpdm_fck, CK_443X),
- CLK(NULL, "mcspi1_fck", &mcspi1_fck, CK_443X),
- CLK(NULL, "mcspi2_fck", &mcspi2_fck, CK_443X),
- CLK(NULL, "mcspi3_fck", &mcspi3_fck, CK_443X),
- CLK(NULL, "mcspi4_fck", &mcspi4_fck, CK_443X),
- CLK(NULL, "mmc1_fck", &mmc1_fck, CK_443X),
- CLK(NULL, "mmc2_fck", &mmc2_fck, CK_443X),
- CLK(NULL, "mmc3_fck", &mmc3_fck, CK_443X),
- CLK(NULL, "mmc4_fck", &mmc4_fck, CK_443X),
- CLK(NULL, "mmc5_fck", &mmc5_fck, CK_443X),
- CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m, CK_443X),
- CLK(NULL, "ocp2scp_usb_phy_ick", &ocp2scp_usb_phy_ick, CK_443X),
- CLK(NULL, "ocp_wp_noc_ick", &ocp_wp_noc_ick, CK_443X),
- CLK(NULL, "rng_ick", &rng_ick, CK_443X),
- CLK("omap_rng", "ick", &rng_ick, CK_443X),
+ CLK(NULL, "per_mcbsp4_gfclk", &per_mcbsp4_gfclk, CK_443X),
+ CLK(NULL, "hsmmc1_fclk", &hsmmc1_fclk, CK_443X),
+ CLK(NULL, "hsmmc2_fclk", &hsmmc2_fclk, CK_443X),
CLK(NULL, "sha2md5_fck", &sha2md5_fck, CK_443X),
- CLK(NULL, "sl2if_ick", &sl2if_ick, CK_443X),
CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1, CK_443X),
CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0, CK_443X),
CLK(NULL, "slimbus1_fclk_2", &slimbus1_fclk_2, CK_443X),
CLK(NULL, "slimbus1_slimbus_clk", &slimbus1_slimbus_clk, CK_443X),
- CLK(NULL, "slimbus1_fck", &slimbus1_fck, CK_443X),
CLK(NULL, "slimbus2_fclk_1", &slimbus2_fclk_1, CK_443X),
CLK(NULL, "slimbus2_fclk_0", &slimbus2_fclk_0, CK_443X),
CLK(NULL, "slimbus2_slimbus_clk", &slimbus2_slimbus_clk, CK_443X),
- CLK(NULL, "slimbus2_fck", &slimbus2_fck, CK_443X),
CLK(NULL, "smartreflex_core_fck", &smartreflex_core_fck, CK_443X),
CLK(NULL, "smartreflex_iva_fck", &smartreflex_iva_fck, CK_443X),
CLK(NULL, "smartreflex_mpu_fck", &smartreflex_mpu_fck, CK_443X),
- CLK(NULL, "timer1_fck", &timer1_fck, CK_443X),
- CLK(NULL, "timer10_fck", &timer10_fck, CK_443X),
- CLK(NULL, "timer11_fck", &timer11_fck, CK_443X),
- CLK(NULL, "timer2_fck", &timer2_fck, CK_443X),
- CLK(NULL, "timer3_fck", &timer3_fck, CK_443X),
- CLK(NULL, "timer4_fck", &timer4_fck, CK_443X),
- CLK(NULL, "timer5_fck", &timer5_fck, CK_443X),
- CLK(NULL, "timer6_fck", &timer6_fck, CK_443X),
- CLK(NULL, "timer7_fck", &timer7_fck, CK_443X),
- CLK(NULL, "timer8_fck", &timer8_fck, CK_443X),
- CLK(NULL, "timer9_fck", &timer9_fck, CK_443X),
- CLK(NULL, "uart1_fck", &uart1_fck, CK_443X),
- CLK(NULL, "uart2_fck", &uart2_fck, CK_443X),
- CLK(NULL, "uart3_fck", &uart3_fck, CK_443X),
- CLK(NULL, "uart4_fck", &uart4_fck, CK_443X),
+ CLK(NULL, "dmt1_clk_mux", &dmt1_clk_mux, CK_443X),
+ CLK(NULL, "cm2_dm10_mux", &cm2_dm10_mux, CK_443X),
+ CLK(NULL, "cm2_dm11_mux", &cm2_dm11_mux, CK_443X),
+ CLK(NULL, "cm2_dm2_mux", &cm2_dm2_mux, CK_443X),
+ CLK(NULL, "cm2_dm3_mux", &cm2_dm3_mux, CK_443X),
+ CLK(NULL, "cm2_dm4_mux", &cm2_dm4_mux, CK_443X),
+ CLK(NULL, "timer5_sync_mux", &timer5_sync_mux, CK_443X),
+ CLK(NULL, "timer6_sync_mux", &timer6_sync_mux, CK_443X),
+ CLK(NULL, "timer7_sync_mux", &timer7_sync_mux, CK_443X),
+ CLK(NULL, "timer8_sync_mux", &timer8_sync_mux, CK_443X),
+ CLK(NULL, "cm2_dm9_mux", &cm2_dm9_mux, CK_443X),
CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck, CK_443X),
CLK("usbhs_omap", "fs_fck", &usb_host_fs_fck, CK_443X),
CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_443X),
@@ -1901,9 +1576,6 @@ static struct omap_clk omap44xx_clks[] = {
CLK("usbhs_tll", "usbtll_ick", &usb_tll_hs_ick, CK_443X),
CLK(NULL, "usim_ck", &usim_ck, CK_443X),
CLK(NULL, "usim_fclk", &usim_fclk, CK_443X),
- CLK(NULL, "usim_fck", &usim_fck, CK_443X),
- CLK(NULL, "wd_timer2_fck", &wd_timer2_fck, CK_443X),
- CLK(NULL, "wd_timer3_fck", &wd_timer3_fck, CK_443X),
CLK(NULL, "pmd_stm_clock_mux_ck", &pmd_stm_clock_mux_ck, CK_443X),
CLK(NULL, "pmd_trace_clk_mux_ck", &pmd_trace_clk_mux_ck, CK_443X),
CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck, CK_443X),
@@ -1980,15 +1652,6 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "cpufreq_ck", &dpll_mpu_ck, CK_443X),
};
-static const char *enable_init_clks[] = {
- "emif1_fck",
- "emif2_fck",
- "gpmc_ick",
- "l3_instr_ick",
- "l3_main_3_ick",
- "ocp_wp_noc_ick",
-};
-
int __init omap4xxx_clk_init(void)
{
u32 cpu_clkflg;
@@ -2019,9 +1682,6 @@ int __init omap4xxx_clk_init(void)
omap2_clk_disable_autoidle_all();
- omap2_clk_enable_init_clocks(enable_init_clks,
- ARRAY_SIZE(enable_init_clks));
-
/*
* On OMAP4460 the ABE DPLL fails to turn on if in idle low-power
* state when turning the ABE clock domain. Workaround this by
diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c
index 1ff646908627..b870f6a9e283 100644
--- a/arch/arm/mach-omap2/clock2xxx.c
+++ b/arch/arm/mach-omap2/clock2xxx.c
@@ -52,6 +52,6 @@ static int __init omap2xxx_clk_arch_init(void)
return ret;
}
-arch_initcall(omap2xxx_clk_arch_init);
+omap_arch_initcall(omap2xxx_clk_arch_init);
diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c
index 4eacab8f1176..0b02b4161d71 100644
--- a/arch/arm/mach-omap2/clock3xxx.c
+++ b/arch/arm/mach-omap2/clock3xxx.c
@@ -94,6 +94,6 @@ static int __init omap3xxx_clk_arch_init(void)
return ret;
}
-arch_initcall(omap3xxx_clk_arch_init);
+omap_arch_initcall(omap3xxx_clk_arch_init);
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 7faf82d4e85c..2da3b5ec010c 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -92,8 +92,6 @@ static int _clkdm_register(struct clockdomain *clkdm)
pwrdm_add_clkdm(pwrdm, clkdm);
- spin_lock_init(&clkdm->lock);
-
pr_debug("clockdomain: registered %s\n", clkdm->name);
return 0;
@@ -122,7 +120,7 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
return cd;
}
-/*
+/**
* _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store
* @autodep: struct clkdm_autodep * to resolve
*
@@ -154,88 +152,206 @@ static void _autodep_lookup(struct clkdm_autodep *autodep)
autodep->clkdm.ptr = clkdm;
}
-/*
- * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
- * @clkdm: struct clockdomain *
+/**
+ * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms
+ * @clkdm: clockdomain that we are resolving dependencies for
+ * @clkdm_deps: ptr to array of struct clkdm_deps to resolve
*
- * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
- * in hardware-supervised mode. Meant to be called from clock framework
- * when a clock inside clockdomain 'clkdm' is enabled. No return value.
+ * Iterates through @clkdm_deps, looking up the struct clockdomain named by
+ * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep.
+ * No return value.
+ */
+static void _resolve_clkdm_deps(struct clockdomain *clkdm,
+ struct clkdm_dep *clkdm_deps)
+{
+ struct clkdm_dep *cd;
+
+ for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
+ if (cd->clkdm)
+ continue;
+ cd->clkdm = _clkdm_lookup(cd->clkdm_name);
+
+ WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
+ clkdm->name, cd->clkdm_name);
+ }
+}
+
+/**
+ * _clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1 (lockless)
+ * @clkdm1: wake this struct clockdomain * up (dependent)
+ * @clkdm2: when this struct clockdomain * wakes up (source)
*
- * XXX autodeps are deprecated and should be removed at the earliest
- * opportunity
+ * When the clockdomain represented by @clkdm2 wakes up, wake up
+ * @clkdm1. Implemented in hardware on the OMAP, this feature is
+ * designed to reduce wakeup latency of the dependent clockdomain @clkdm1.
+ * Returns -EINVAL if presented with invalid clockdomain pointers,
+ * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon
+ * success.
*/
-void _clkdm_add_autodeps(struct clockdomain *clkdm)
+static int _clkdm_add_wkdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
{
- struct clkdm_autodep *autodep;
+ struct clkdm_dep *cd;
+ int ret = 0;
- if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
- return;
+ if (!clkdm1 || !clkdm2)
+ return -EINVAL;
- for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
- if (IS_ERR(autodep->clkdm.ptr))
- continue;
+ cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
- pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n",
- clkdm->name, autodep->clkdm.ptr->name);
+ if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
+ ret = -EINVAL;
+
+ if (ret) {
+ pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
+ clkdm1->name, clkdm2->name);
+ return ret;
+ }
+
+ cd->wkdep_usecount++;
+ if (cd->wkdep_usecount == 1) {
+ pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n",
+ clkdm1->name, clkdm2->name);
- clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr);
- clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
+ ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
}
+
+ return ret;
}
-/*
- * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm
- * @clkdm: struct clockdomain *
+/**
+ * _clkdm_del_wkdep - remove a wakeup dep from clkdm2 to clkdm1 (lockless)
+ * @clkdm1: wake this struct clockdomain * up (dependent)
+ * @clkdm2: when this struct clockdomain * wakes up (source)
*
- * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
- * in hardware-supervised mode. Meant to be called from clock framework
- * when a clock inside clockdomain 'clkdm' is disabled. No return value.
+ * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2
+ * wakes up. Returns -EINVAL if presented with invalid clockdomain
+ * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or
+ * 0 upon success.
+ */
+static int _clkdm_del_wkdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ struct clkdm_dep *cd;
+ int ret = 0;
+
+ if (!clkdm1 || !clkdm2)
+ return -EINVAL;
+
+ cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
+ ret = -EINVAL;
+
+ if (ret) {
+ pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
+ clkdm1->name, clkdm2->name);
+ return ret;
+ }
+
+ cd->wkdep_usecount--;
+ if (cd->wkdep_usecount == 0) {
+ pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n",
+ clkdm1->name, clkdm2->name);
+
+ ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
+ }
+
+ return ret;
+}
+
+/**
+ * _clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 (lockless)
+ * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
+ * @clkdm2: when this struct clockdomain * is active (source)
*
- * XXX autodeps are deprecated and should be removed at the earliest
- * opportunity
+ * Prevent @clkdm1 from automatically going inactive (and then to
+ * retention or off) if @clkdm2 is active. Returns -EINVAL if
+ * presented with invalid clockdomain pointers or called on a machine
+ * that does not support software-configurable hardware sleep
+ * dependencies, -ENOENT if the specified dependency cannot be set in
+ * hardware, or 0 upon success.
*/
-void _clkdm_del_autodeps(struct clockdomain *clkdm)
+static int _clkdm_add_sleepdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
{
- struct clkdm_autodep *autodep;
+ struct clkdm_dep *cd;
+ int ret = 0;
- if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
- return;
+ if (!clkdm1 || !clkdm2)
+ return -EINVAL;
- for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
- if (IS_ERR(autodep->clkdm.ptr))
- continue;
+ cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
- pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n",
- clkdm->name, autodep->clkdm.ptr->name);
+ if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
+ ret = -EINVAL;
- clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr);
- clkdm_del_wkdep(clkdm, autodep->clkdm.ptr);
+ if (ret) {
+ pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
+ clkdm1->name, clkdm2->name);
+ return ret;
+ }
+
+ cd->sleepdep_usecount++;
+ if (cd->sleepdep_usecount == 1) {
+ pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n",
+ clkdm1->name, clkdm2->name);
+
+ ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
}
+
+ return ret;
}
/**
- * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms
- * @clkdm: clockdomain that we are resolving dependencies for
- * @clkdm_deps: ptr to array of struct clkdm_deps to resolve
+ * _clkdm_del_sleepdep - remove a sleep dep from clkdm2 to clkdm1 (lockless)
+ * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
+ * @clkdm2: when this struct clockdomain * is active (source)
*
- * Iterates through @clkdm_deps, looking up the struct clockdomain named by
- * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep.
- * No return value.
+ * Allow @clkdm1 to automatically go inactive (and then to retention or
+ * off), independent of the activity state of @clkdm2. Returns -EINVAL
+ * if presented with invalid clockdomain pointers or called on a machine
+ * that does not support software-configurable hardware sleep dependencies,
+ * -ENOENT if the specified dependency cannot be cleared in hardware, or
+ * 0 upon success.
*/
-static void _resolve_clkdm_deps(struct clockdomain *clkdm,
- struct clkdm_dep *clkdm_deps)
+static int _clkdm_del_sleepdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
+ int ret = 0;
- for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
- if (cd->clkdm)
- continue;
- cd->clkdm = _clkdm_lookup(cd->clkdm_name);
+ if (!clkdm1 || !clkdm2)
+ return -EINVAL;
- WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
- clkdm->name, cd->clkdm_name);
+ cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
+ ret = -EINVAL;
+
+ if (ret) {
+ pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
+ clkdm1->name, clkdm2->name);
+ return ret;
}
+
+ cd->sleepdep_usecount--;
+ if (cd->sleepdep_usecount == 0) {
+ pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n",
+ clkdm1->name, clkdm2->name);
+
+ ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
+ }
+
+ return ret;
}
/* Public functions */
@@ -456,30 +572,18 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
- int ret = 0;
+ int ret;
if (!clkdm1 || !clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
if (IS_ERR(cd))
- ret = PTR_ERR(cd);
+ return PTR_ERR(cd);
- if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
- ret = -EINVAL;
-
- if (ret) {
- pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
- clkdm1->name, clkdm2->name);
- return ret;
- }
-
- if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
- pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n",
- clkdm1->name, clkdm2->name);
-
- ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
- }
+ pwrdm_lock(cd->clkdm->pwrdm.ptr);
+ ret = _clkdm_add_wkdep(clkdm1, clkdm2);
+ pwrdm_unlock(cd->clkdm->pwrdm.ptr);
return ret;
}
@@ -497,30 +601,18 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
- int ret = 0;
+ int ret;
if (!clkdm1 || !clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
if (IS_ERR(cd))
- ret = PTR_ERR(cd);
+ return PTR_ERR(cd);
- if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
- ret = -EINVAL;
-
- if (ret) {
- pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
- clkdm1->name, clkdm2->name);
- return ret;
- }
-
- if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
- pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n",
- clkdm1->name, clkdm2->name);
-
- ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
- }
+ pwrdm_lock(cd->clkdm->pwrdm.ptr);
+ ret = _clkdm_del_wkdep(clkdm1, clkdm2);
+ pwrdm_unlock(cd->clkdm->pwrdm.ptr);
return ret;
}
@@ -560,7 +652,7 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
return ret;
}
- /* XXX It's faster to return the atomic wkdep_usecount */
+ /* XXX It's faster to return the wkdep_usecount */
return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2);
}
@@ -600,30 +692,18 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
- int ret = 0;
+ int ret;
if (!clkdm1 || !clkdm2)
return -EINVAL;
- cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
+ cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
if (IS_ERR(cd))
- ret = PTR_ERR(cd);
+ return PTR_ERR(cd);
- if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
- ret = -EINVAL;
-
- if (ret) {
- pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
- clkdm1->name, clkdm2->name);
- return ret;
- }
-
- if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
- pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n",
- clkdm1->name, clkdm2->name);
-
- ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
- }
+ pwrdm_lock(cd->clkdm->pwrdm.ptr);
+ ret = _clkdm_add_sleepdep(clkdm1, clkdm2);
+ pwrdm_unlock(cd->clkdm->pwrdm.ptr);
return ret;
}
@@ -643,30 +723,18 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
- int ret = 0;
+ int ret;
if (!clkdm1 || !clkdm2)
return -EINVAL;
- cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
+ cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
if (IS_ERR(cd))
- ret = PTR_ERR(cd);
+ return PTR_ERR(cd);
- if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
- ret = -EINVAL;
-
- if (ret) {
- pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
- clkdm1->name, clkdm2->name);
- return ret;
- }
-
- if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
- pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n",
- clkdm1->name, clkdm2->name);
-
- ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
- }
+ pwrdm_lock(cd->clkdm->pwrdm.ptr);
+ ret = _clkdm_del_sleepdep(clkdm1, clkdm2);
+ pwrdm_unlock(cd->clkdm->pwrdm.ptr);
return ret;
}
@@ -708,7 +776,7 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
return ret;
}
- /* XXX It's faster to return the atomic sleepdep_usecount */
+ /* XXX It's faster to return the sleepdep_usecount */
return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2);
}
@@ -734,18 +802,17 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
}
/**
- * clkdm_sleep - force clockdomain sleep transition
+ * clkdm_sleep_nolock - force clockdomain sleep transition (lockless)
* @clkdm: struct clockdomain *
*
* Instruct the CM to force a sleep transition on the specified
- * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if
- * clockdomain does not support software-initiated sleep; 0 upon
- * success.
+ * clockdomain @clkdm. Only for use by the powerdomain code. Returns
+ * -EINVAL if @clkdm is NULL or if clockdomain does not support
+ * software-initiated sleep; 0 upon success.
*/
-int clkdm_sleep(struct clockdomain *clkdm)
+int clkdm_sleep_nolock(struct clockdomain *clkdm)
{
int ret;
- unsigned long flags;
if (!clkdm)
return -EINVAL;
@@ -761,26 +828,45 @@ int clkdm_sleep(struct clockdomain *clkdm)
pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
- spin_lock_irqsave(&clkdm->lock, flags);
clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
ret = arch_clkdm->clkdm_sleep(clkdm);
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
+
return ret;
}
/**
- * clkdm_wakeup - force clockdomain wakeup transition
+ * clkdm_sleep - force clockdomain sleep transition
* @clkdm: struct clockdomain *
*
- * Instruct the CM to force a wakeup transition on the specified
- * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the
- * clockdomain does not support software-controlled wakeup; 0 upon
+ * Instruct the CM to force a sleep transition on the specified
+ * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if
+ * clockdomain does not support software-initiated sleep; 0 upon
* success.
*/
-int clkdm_wakeup(struct clockdomain *clkdm)
+int clkdm_sleep(struct clockdomain *clkdm)
+{
+ int ret;
+
+ pwrdm_lock(clkdm->pwrdm.ptr);
+ ret = clkdm_sleep_nolock(clkdm);
+ pwrdm_unlock(clkdm->pwrdm.ptr);
+
+ return ret;
+}
+
+/**
+ * clkdm_wakeup_nolock - force clockdomain wakeup transition (lockless)
+ * @clkdm: struct clockdomain *
+ *
+ * Instruct the CM to force a wakeup transition on the specified
+ * clockdomain @clkdm. Only for use by the powerdomain code. Returns
+ * -EINVAL if @clkdm is NULL or if the clockdomain does not support
+ * software-controlled wakeup; 0 upon success.
+ */
+int clkdm_wakeup_nolock(struct clockdomain *clkdm)
{
int ret;
- unsigned long flags;
if (!clkdm)
return -EINVAL;
@@ -796,28 +882,46 @@ int clkdm_wakeup(struct clockdomain *clkdm)
pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
- spin_lock_irqsave(&clkdm->lock, flags);
clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
ret = arch_clkdm->clkdm_wakeup(clkdm);
- ret |= pwrdm_state_switch(clkdm->pwrdm.ptr);
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
+
return ret;
}
/**
- * clkdm_allow_idle - enable hwsup idle transitions for clkdm
+ * clkdm_wakeup - force clockdomain wakeup transition
* @clkdm: struct clockdomain *
*
- * Allow the hardware to automatically switch the clockdomain @clkdm into
- * active or idle states, as needed by downstream clocks. If the
+ * Instruct the CM to force a wakeup transition on the specified
+ * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the
+ * clockdomain does not support software-controlled wakeup; 0 upon
+ * success.
+ */
+int clkdm_wakeup(struct clockdomain *clkdm)
+{
+ int ret;
+
+ pwrdm_lock(clkdm->pwrdm.ptr);
+ ret = clkdm_wakeup_nolock(clkdm);
+ pwrdm_unlock(clkdm->pwrdm.ptr);
+
+ return ret;
+}
+
+/**
+ * clkdm_allow_idle_nolock - enable hwsup idle transitions for clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Allow the hardware to automatically switch the clockdomain @clkdm
+ * into active or idle states, as needed by downstream clocks. If the
* clockdomain has any downstream clocks enabled in the clock
* framework, wkdep/sleepdep autodependencies are added; this is so
- * device drivers can read and write to the device. No return value.
+ * device drivers can read and write to the device. Only for use by
+ * the powerdomain code. No return value.
*/
-void clkdm_allow_idle(struct clockdomain *clkdm)
+void clkdm_allow_idle_nolock(struct clockdomain *clkdm)
{
- unsigned long flags;
-
if (!clkdm)
return;
@@ -833,11 +937,26 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
clkdm->name);
- spin_lock_irqsave(&clkdm->lock, flags);
clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED;
arch_clkdm->clkdm_allow_idle(clkdm);
- pwrdm_state_switch(clkdm->pwrdm.ptr);
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
+}
+
+/**
+ * clkdm_allow_idle - enable hwsup idle transitions for clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Allow the hardware to automatically switch the clockdomain @clkdm into
+ * active or idle states, as needed by downstream clocks. If the
+ * clockdomain has any downstream clocks enabled in the clock
+ * framework, wkdep/sleepdep autodependencies are added; this is so
+ * device drivers can read and write to the device. No return value.
+ */
+void clkdm_allow_idle(struct clockdomain *clkdm)
+{
+ pwrdm_lock(clkdm->pwrdm.ptr);
+ clkdm_allow_idle_nolock(clkdm);
+ pwrdm_unlock(clkdm->pwrdm.ptr);
}
/**
@@ -847,12 +966,11 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
* Prevent the hardware from automatically switching the clockdomain
* @clkdm into inactive or idle states. If the clockdomain has
* downstream clocks enabled in the clock framework, wkdep/sleepdep
- * autodependencies are removed. No return value.
+ * autodependencies are removed. Only for use by the powerdomain
+ * code. No return value.
*/
-void clkdm_deny_idle(struct clockdomain *clkdm)
+void clkdm_deny_idle_nolock(struct clockdomain *clkdm)
{
- unsigned long flags;
-
if (!clkdm)
return;
@@ -868,11 +986,25 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
clkdm->name);
- spin_lock_irqsave(&clkdm->lock, flags);
clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
arch_clkdm->clkdm_deny_idle(clkdm);
- pwrdm_state_switch(clkdm->pwrdm.ptr);
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
+}
+
+/**
+ * clkdm_deny_idle - disable hwsup idle transitions for clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Prevent the hardware from automatically switching the clockdomain
+ * @clkdm into inactive or idle states. If the clockdomain has
+ * downstream clocks enabled in the clock framework, wkdep/sleepdep
+ * autodependencies are removed. No return value.
+ */
+void clkdm_deny_idle(struct clockdomain *clkdm)
+{
+ pwrdm_lock(clkdm->pwrdm.ptr);
+ clkdm_deny_idle_nolock(clkdm);
+ pwrdm_unlock(clkdm->pwrdm.ptr);
}
/**
@@ -889,14 +1021,11 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
bool clkdm_in_hwsup(struct clockdomain *clkdm)
{
bool ret;
- unsigned long flags;
if (!clkdm)
return false;
- spin_lock_irqsave(&clkdm->lock, flags);
ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
- spin_unlock_irqrestore(&clkdm->lock, flags);
return ret;
}
@@ -918,30 +1047,91 @@ bool clkdm_missing_idle_reporting(struct clockdomain *clkdm)
return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false;
}
+/* Public autodep handling functions (deprecated) */
+
+/**
+ * clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
+ * @clkdm: struct clockdomain *
+ *
+ * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
+ * in hardware-supervised mode. Meant to be called from clock framework
+ * when a clock inside clockdomain 'clkdm' is enabled. No return value.
+ *
+ * XXX autodeps are deprecated and should be removed at the earliest
+ * opportunity
+ */
+void clkdm_add_autodeps(struct clockdomain *clkdm)
+{
+ struct clkdm_autodep *autodep;
+
+ if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
+ return;
+
+ for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
+ if (IS_ERR(autodep->clkdm.ptr))
+ continue;
+
+ pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n",
+ clkdm->name, autodep->clkdm.ptr->name);
+
+ _clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr);
+ _clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
+ }
+}
+
+/**
+ * clkdm_del_autodeps - remove auto sleepdeps/wkdeps from clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
+ * in hardware-supervised mode. Meant to be called from clock framework
+ * when a clock inside clockdomain 'clkdm' is disabled. No return value.
+ *
+ * XXX autodeps are deprecated and should be removed at the earliest
+ * opportunity
+ */
+void clkdm_del_autodeps(struct clockdomain *clkdm)
+{
+ struct clkdm_autodep *autodep;
+
+ if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
+ return;
+
+ for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
+ if (IS_ERR(autodep->clkdm.ptr))
+ continue;
+
+ pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n",
+ clkdm->name, autodep->clkdm.ptr->name);
+
+ _clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr);
+ _clkdm_del_wkdep(clkdm, autodep->clkdm.ptr);
+ }
+}
+
/* Clockdomain-to-clock/hwmod framework interface code */
static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
{
- unsigned long flags;
-
if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
return -EINVAL;
- spin_lock_irqsave(&clkdm->lock, flags);
+ pwrdm_lock(clkdm->pwrdm.ptr);
/*
* For arch's with no autodeps, clkcm_clk_enable
* should be called for every clock instance or hwmod that is
* enabled, so the clkdm can be force woken up.
*/
- if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) {
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ clkdm->usecount++;
+ if (clkdm->usecount > 1 && autodeps) {
+ pwrdm_unlock(clkdm->pwrdm.ptr);
return 0;
}
arch_clkdm->clkdm_clk_enable(clkdm);
- pwrdm_state_switch(clkdm->pwrdm.ptr);
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
+ pwrdm_unlock(clkdm->pwrdm.ptr);
pr_debug("clockdomain: %s: enabled\n", clkdm->name);
@@ -990,36 +1180,34 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
*/
int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
{
- unsigned long flags;
-
if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
return -EINVAL;
- spin_lock_irqsave(&clkdm->lock, flags);
+ pwrdm_lock(clkdm->pwrdm.ptr);
/* corner case: disabling unused clocks */
- if ((__clk_get_enable_count(clk) == 0) &&
- (atomic_read(&clkdm->usecount) == 0))
+ if ((__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0)
goto ccd_exit;
- if (atomic_read(&clkdm->usecount) == 0) {
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ if (clkdm->usecount == 0) {
+ pwrdm_unlock(clkdm->pwrdm.ptr);
WARN_ON(1); /* underflow */
return -ERANGE;
}
- if (atomic_dec_return(&clkdm->usecount) > 0) {
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ clkdm->usecount--;
+ if (clkdm->usecount > 0) {
+ pwrdm_unlock(clkdm->pwrdm.ptr);
return 0;
}
arch_clkdm->clkdm_clk_disable(clkdm);
- pwrdm_state_switch(clkdm->pwrdm.ptr);
+ pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
pr_debug("clockdomain: %s: disabled\n", clkdm->name);
ccd_exit:
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ pwrdm_unlock(clkdm->pwrdm.ptr);
return 0;
}
@@ -1072,8 +1260,6 @@ int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)
*/
int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
{
- unsigned long flags;
-
/* The clkdm attribute does not exist yet prior OMAP4 */
if (cpu_is_omap24xx() || cpu_is_omap34xx())
return 0;
@@ -1086,22 +1272,23 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
return -EINVAL;
- spin_lock_irqsave(&clkdm->lock, flags);
+ pwrdm_lock(clkdm->pwrdm.ptr);
- if (atomic_read(&clkdm->usecount) == 0) {
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ if (clkdm->usecount == 0) {
+ pwrdm_unlock(clkdm->pwrdm.ptr);
WARN_ON(1); /* underflow */
return -ERANGE;
}
- if (atomic_dec_return(&clkdm->usecount) > 0) {
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ clkdm->usecount--;
+ if (clkdm->usecount > 0) {
+ pwrdm_unlock(clkdm->pwrdm.ptr);
return 0;
}
arch_clkdm->clkdm_clk_disable(clkdm);
- pwrdm_state_switch(clkdm->pwrdm.ptr);
- spin_unlock_irqrestore(&clkdm->lock, flags);
+ pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
+ pwrdm_unlock(clkdm->pwrdm.ptr);
pr_debug("clockdomain: %s: disabled\n", clkdm->name);
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h
index bc42446e23ab..2da37656a693 100644
--- a/arch/arm/mach-omap2/clockdomain.h
+++ b/arch/arm/mach-omap2/clockdomain.h
@@ -15,7 +15,6 @@
#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H
#include <linux/init.h>
-#include <linux/spinlock.h>
#include "powerdomain.h"
#include "clock.h"
@@ -92,8 +91,8 @@ struct clkdm_autodep {
struct clkdm_dep {
const char *clkdm_name;
struct clockdomain *clkdm;
- atomic_t wkdep_usecount;
- atomic_t sleepdep_usecount;
+ s16 wkdep_usecount;
+ s16 sleepdep_usecount;
};
/* Possible flags for struct clockdomain._flags */
@@ -137,9 +136,8 @@ struct clockdomain {
const u16 clkdm_offs;
struct clkdm_dep *wkdep_srcs;
struct clkdm_dep *sleepdep_srcs;
- atomic_t usecount;
+ int usecount;
struct list_head node;
- spinlock_t lock;
};
/**
@@ -196,12 +194,16 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm);
+void clkdm_allow_idle_nolock(struct clockdomain *clkdm);
void clkdm_allow_idle(struct clockdomain *clkdm);
+void clkdm_deny_idle_nolock(struct clockdomain *clkdm);
void clkdm_deny_idle(struct clockdomain *clkdm);
bool clkdm_in_hwsup(struct clockdomain *clkdm);
bool clkdm_missing_idle_reporting(struct clockdomain *clkdm);
+int clkdm_wakeup_nolock(struct clockdomain *clkdm);
int clkdm_wakeup(struct clockdomain *clkdm);
+int clkdm_sleep_nolock(struct clockdomain *clkdm);
int clkdm_sleep(struct clockdomain *clkdm);
int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
@@ -214,8 +216,9 @@ extern void __init omap243x_clockdomains_init(void);
extern void __init omap3xxx_clockdomains_init(void);
extern void __init am33xx_clockdomains_init(void);
extern void __init omap44xx_clockdomains_init(void);
-extern void _clkdm_add_autodeps(struct clockdomain *clkdm);
-extern void _clkdm_del_autodeps(struct clockdomain *clkdm);
+
+extern void clkdm_add_autodeps(struct clockdomain *clkdm);
+extern void clkdm_del_autodeps(struct clockdomain *clkdm);
extern struct clkdm_ops omap2_clkdm_operations;
extern struct clkdm_ops omap3_clkdm_operations;
diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c
index db650690e9d0..6774a53a3874 100644
--- a/arch/arm/mach-omap2/cm2xxx.c
+++ b/arch/arm/mach-omap2/cm2xxx.c
@@ -273,9 +273,6 @@ int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
static void omap2xxx_clkdm_allow_idle(struct clockdomain *clkdm)
{
- if (atomic_read(&clkdm->usecount) > 0)
- _clkdm_add_autodeps(clkdm);
-
omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
}
@@ -284,9 +281,6 @@ static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm)
{
omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
-
- if (atomic_read(&clkdm->usecount) > 0)
- _clkdm_del_autodeps(clkdm);
}
static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)
@@ -298,18 +292,8 @@ static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)
hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
-
- if (hwsup) {
- /* Disable HW transitions when we are changing deps */
- omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
- _clkdm_add_autodeps(clkdm);
- omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
- } else {
- if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
- omap2xxx_clkdm_wakeup(clkdm);
- }
+ if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
+ omap2xxx_clkdm_wakeup(clkdm);
return 0;
}
@@ -324,17 +308,8 @@ static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm)
hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
- if (hwsup) {
- /* Disable HW transitions when we are changing deps */
- omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
- _clkdm_del_autodeps(clkdm);
- omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
- } else {
- if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
- omap2xxx_clkdm_sleep(clkdm);
- }
+ if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
+ omap2xxx_clkdm_sleep(clkdm);
return 0;
}
diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c
index c2086f2e86b6..9061c307d915 100644
--- a/arch/arm/mach-omap2/cm3xxx.c
+++ b/arch/arm/mach-omap2/cm3xxx.c
@@ -186,7 +186,7 @@ static int omap3xxx_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
continue; /* only happens if data is erroneous */
mask |= 1 << cd->clkdm->dep_bit;
- atomic_set(&cd->sleepdep_usecount, 0);
+ cd->sleepdep_usecount = 0;
}
omap2_cm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
OMAP3430_CM_SLEEPDEP);
@@ -209,8 +209,8 @@ static int omap3xxx_clkdm_wakeup(struct clockdomain *clkdm)
static void omap3xxx_clkdm_allow_idle(struct clockdomain *clkdm)
{
- if (atomic_read(&clkdm->usecount) > 0)
- _clkdm_add_autodeps(clkdm);
+ if (clkdm->usecount > 0)
+ clkdm_add_autodeps(clkdm);
omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
@@ -221,8 +221,8 @@ static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm)
omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
- if (atomic_read(&clkdm->usecount) > 0)
- _clkdm_del_autodeps(clkdm);
+ if (clkdm->usecount > 0)
+ clkdm_del_autodeps(clkdm);
}
static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
@@ -250,7 +250,7 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
/* Disable HW transitions when we are changing deps */
omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
- _clkdm_add_autodeps(clkdm);
+ clkdm_add_autodeps(clkdm);
omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
} else {
@@ -287,7 +287,7 @@ static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
/* Disable HW transitions when we are changing deps */
omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
- _clkdm_del_autodeps(clkdm);
+ clkdm_del_autodeps(clkdm);
omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
clkdm->clktrctrl_mask);
} else {
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c
index 7f9a464f01e9..f0290f5566fe 100644
--- a/arch/arm/mach-omap2/cminst44xx.c
+++ b/arch/arm/mach-omap2/cminst44xx.c
@@ -393,7 +393,7 @@ static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
continue; /* only happens if data is erroneous */
mask |= 1 << cd->clkdm->dep_bit;
- atomic_set(&cd->wkdep_usecount, 0);
+ cd->wkdep_usecount = 0;
}
omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition,
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 948bcaa82eb6..b4350274361b 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -79,13 +79,13 @@ static inline int omap_mux_late_init(void)
extern void omap2_init_common_infrastructure(void);
-extern struct sys_timer omap2_timer;
-extern struct sys_timer omap3_timer;
-extern struct sys_timer omap3_secure_timer;
-extern struct sys_timer omap3_gp_timer;
-extern struct sys_timer omap3_am33xx_timer;
-extern struct sys_timer omap4_timer;
-extern struct sys_timer omap5_timer;
+extern void omap2_sync32k_timer_init(void);
+extern void omap3_sync32k_timer_init(void);
+extern void omap3_secure_sync32k_timer_init(void);
+extern void omap3_gp_gptimer_timer_init(void);
+extern void omap3_am33xx_gptimer_timer_init(void);
+extern void omap4_local_timer_init(void);
+extern void omap5_realtime_timer_init(void);
void omap2420_init_early(void);
void omap2430_init_early(void);
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 22590dbe8f14..80392fca86c6 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -36,40 +36,66 @@
/* Mach specific information to be recorded in the C-state driver_data */
struct omap3_idle_statedata {
- u32 mpu_state;
- u32 core_state;
+ u8 mpu_state;
+ u8 core_state;
+ u8 per_min_state;
+ u8 flags;
};
static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
+/*
+ * Possible flag bits for struct omap3_idle_statedata.flags:
+ *
+ * OMAP_CPUIDLE_CX_NO_CLKDM_IDLE: don't allow the MPU clockdomain to go
+ * inactive. This in turn prevents the MPU DPLL from entering autoidle
+ * mode, so wakeup latency is greatly reduced, at the cost of additional
+ * energy consumption. This also prevents the CORE clockdomain from
+ * entering idle.
+ */
+#define OMAP_CPUIDLE_CX_NO_CLKDM_IDLE BIT(0)
+
+/*
+ * Prevent PER OFF if CORE is not in RETention or OFF as this would
+ * disable PER wakeups completely.
+ */
static struct omap3_idle_statedata omap3_idle_data[] = {
{
.mpu_state = PWRDM_POWER_ON,
.core_state = PWRDM_POWER_ON,
+ /* In C1 do not allow PER state lower than CORE state */
+ .per_min_state = PWRDM_POWER_ON,
+ .flags = OMAP_CPUIDLE_CX_NO_CLKDM_IDLE,
},
{
.mpu_state = PWRDM_POWER_ON,
.core_state = PWRDM_POWER_ON,
+ .per_min_state = PWRDM_POWER_RET,
},
{
.mpu_state = PWRDM_POWER_RET,
.core_state = PWRDM_POWER_ON,
+ .per_min_state = PWRDM_POWER_RET,
},
{
.mpu_state = PWRDM_POWER_OFF,
.core_state = PWRDM_POWER_ON,
+ .per_min_state = PWRDM_POWER_RET,
},
{
.mpu_state = PWRDM_POWER_RET,
.core_state = PWRDM_POWER_RET,
+ .per_min_state = PWRDM_POWER_OFF,
},
{
.mpu_state = PWRDM_POWER_OFF,
.core_state = PWRDM_POWER_RET,
+ .per_min_state = PWRDM_POWER_OFF,
},
{
.mpu_state = PWRDM_POWER_OFF,
.core_state = PWRDM_POWER_OFF,
+ .per_min_state = PWRDM_POWER_OFF,
},
};
@@ -80,27 +106,25 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
int index)
{
struct omap3_idle_statedata *cx = &omap3_idle_data[index];
- u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
local_fiq_disable();
- pwrdm_set_next_pwrst(mpu_pd, mpu_state);
- pwrdm_set_next_pwrst(core_pd, core_state);
-
if (omap_irq_pending() || need_resched())
goto return_sleep_time;
/* Deny idle for C1 */
- if (index == 0) {
+ if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) {
clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]);
- clkdm_deny_idle(core_pd->pwrdm_clkdms[0]);
+ } else {
+ pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state);
+ pwrdm_set_next_pwrst(core_pd, cx->core_state);
}
/*
* Call idle CPU PM enter notifier chain so that
* VFP context is saved.
*/
- if (mpu_state == PWRDM_POWER_OFF)
+ if (cx->mpu_state == PWRDM_POWER_OFF)
cpu_pm_enter();
/* Execute ARM wfi */
@@ -110,17 +134,15 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
* Call idle CPU PM enter notifier chain to restore
* VFP context.
*/
- if (pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF)
+ if (cx->mpu_state == PWRDM_POWER_OFF &&
+ pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF)
cpu_pm_exit();
/* Re-allow idle for C1 */
- if (index == 0) {
+ if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE)
clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]);
- clkdm_allow_idle(core_pd->pwrdm_clkdms[0]);
- }
return_sleep_time:
-
local_fiq_enable();
return index;
@@ -185,7 +207,7 @@ static int next_valid_state(struct cpuidle_device *dev,
* Start search from the next (lower) state.
*/
for (idx = index - 1; idx >= 0; idx--) {
- cx = &omap3_idle_data[idx];
+ cx = &omap3_idle_data[idx];
if ((cx->mpu_state >= mpu_deepest_state) &&
(cx->core_state >= core_deepest_state)) {
next_index = idx;
@@ -209,10 +231,9 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- int new_state_idx;
- u32 core_next_state, per_next_state = 0, per_saved_state = 0;
+ int new_state_idx, ret;
+ u8 per_next_state, per_saved_state;
struct omap3_idle_statedata *cx;
- int ret;
/*
* Use only C1 if CAM is active.
@@ -233,25 +254,13 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
/* Program PER state */
cx = &omap3_idle_data[new_state_idx];
- core_next_state = cx->core_state;
- per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
- if (new_state_idx == 0) {
- /* In C1 do not allow PER state lower than CORE state */
- if (per_next_state < core_next_state)
- per_next_state = core_next_state;
- } else {
- /*
- * Prevent PER OFF if CORE is not in RETention or OFF as this
- * would disable PER wakeups completely.
- */
- if ((per_next_state == PWRDM_POWER_OFF) &&
- (core_next_state > PWRDM_POWER_RET))
- per_next_state = PWRDM_POWER_RET;
- }
- /* Are we changing PER target state? */
- if (per_next_state != per_saved_state)
+ per_next_state = pwrdm_read_next_pwrst(per_pd);
+ per_saved_state = per_next_state;
+ if (per_next_state < cx->per_min_state) {
+ per_next_state = cx->per_min_state;
pwrdm_set_next_pwrst(per_pd, per_next_state);
+ }
ret = omap3_enter_idle(dev, drv, new_state_idx);
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 626f3ea3142f..142d9c616f1b 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -20,6 +20,7 @@
#include <linux/pinctrl/machine.h>
#include <linux/platform_data/omap4-keypad.h>
#include <linux/platform_data/omap_ocp2scp.h>
+#include <linux/usb/omap_control_usb.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
@@ -61,14 +62,13 @@ static int __init omap3_l3_init(void)
if (!oh)
pr_err("could not look up %s\n", oh_name);
- pdev = omap_device_build("omap_l3_smx", 0, oh, NULL, 0,
- NULL, 0, 0);
+ pdev = omap_device_build("omap_l3_smx", 0, oh, NULL, 0);
WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
}
-postcore_initcall(omap3_l3_init);
+omap_postcore_initcall(omap3_l3_init);
static int __init omap4_l3_init(void)
{
@@ -96,14 +96,13 @@ static int __init omap4_l3_init(void)
pr_err("could not look up %s\n", oh_name);
}
- pdev = omap_device_build_ss("omap_l3_noc", 0, oh, 3, NULL,
- 0, NULL, 0, 0);
+ pdev = omap_device_build_ss("omap_l3_noc", 0, oh, 3, NULL, 0);
WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
}
-postcore_initcall(omap4_l3_init);
+omap_postcore_initcall(omap4_l3_init);
#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
@@ -254,6 +253,49 @@ static inline void omap_init_camera(void)
#endif
}
+#if IS_ENABLED(CONFIG_OMAP_CONTROL_USB)
+static struct omap_control_usb_platform_data omap4_control_usb_pdata = {
+ .type = 1,
+};
+
+struct resource omap4_control_usb_res[] = {
+ {
+ .name = "control_dev_conf",
+ .start = 0x4a002300,
+ .end = 0x4a002303,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "otghs_control",
+ .start = 0x4a00233c,
+ .end = 0x4a00233f,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device omap4_control_usb = {
+ .name = "omap-control-usb",
+ .id = -1,
+ .dev = {
+ .platform_data = &omap4_control_usb_pdata,
+ },
+ .num_resources = 2,
+ .resource = omap4_control_usb_res,
+};
+
+static inline void __init omap_init_control_usb(void)
+{
+ if (!cpu_is_omap44xx())
+ return;
+
+ if (platform_device_register(&omap4_control_usb))
+ pr_err("Error registering omap_control_usb device\n");
+}
+
+#else
+static inline void omap_init_control_usb(void) { }
+#endif /* CONFIG_OMAP_CONTROL_USB */
+
int __init omap4_keyboard_init(struct omap4_keypad_platform_data
*sdp4430_keypad_data, struct omap_board_data *bdata)
{
@@ -273,7 +315,7 @@ int __init omap4_keyboard_init(struct omap4_keypad_platform_data
keypad_data = sdp4430_keypad_data;
pdev = omap_device_build(name, id, oh, keypad_data,
- sizeof(struct omap4_keypad_platform_data), NULL, 0, 0);
+ sizeof(struct omap4_keypad_platform_data));
if (IS_ERR(pdev)) {
WARN(1, "Can't build omap_device for %s:%s.\n",
@@ -297,7 +339,7 @@ static inline void __init omap_init_mbox(void)
return;
}
- pdev = omap_device_build("omap-mailbox", -1, oh, NULL, 0, NULL, 0, 0);
+ pdev = omap_device_build("omap-mailbox", -1, oh, NULL, 0);
WARN(IS_ERR(pdev), "%s: could not build device, err %ld\n",
__func__, PTR_ERR(pdev));
}
@@ -337,7 +379,7 @@ static void __init omap_init_mcpdm(void)
return;
}
- pdev = omap_device_build("omap-mcpdm", -1, oh, NULL, 0, NULL, 0, 0);
+ pdev = omap_device_build("omap-mcpdm", -1, oh, NULL, 0);
WARN(IS_ERR(pdev), "Can't build omap_device for omap-mcpdm.\n");
}
#else
@@ -358,7 +400,7 @@ static void __init omap_init_dmic(void)
return;
}
- pdev = omap_device_build("omap-dmic", -1, oh, NULL, 0, NULL, 0, 0);
+ pdev = omap_device_build("omap-dmic", -1, oh, NULL, 0);
WARN(IS_ERR(pdev), "Can't build omap_device for omap-dmic.\n");
}
#else
@@ -384,8 +426,7 @@ static void __init omap_init_hdmi_audio(void)
return;
}
- pdev = omap_device_build("omap-hdmi-audio-dai",
- -1, oh, NULL, 0, NULL, 0, 0);
+ pdev = omap_device_build("omap-hdmi-audio-dai", -1, oh, NULL, 0, 0);
WARN(IS_ERR(pdev),
"Can't build omap_device for omap-hdmi-audio-dai.\n");
@@ -429,8 +470,7 @@ static int __init omap_mcspi_init(struct omap_hwmod *oh, void *unused)
}
spi_num++;
- pdev = omap_device_build(name, spi_num, oh, pdata,
- sizeof(*pdata), NULL, 0, 0);
+ pdev = omap_device_build(name, spi_num, oh, pdata, sizeof(*pdata));
WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s\n",
name, oh->name);
kfree(pdata);
@@ -460,7 +500,7 @@ static void omap_init_rng(void)
if (!oh)
return;
- pdev = omap_device_build("omap_rng", -1, oh, NULL, 0, NULL, 0, 0);
+ pdev = omap_device_build("omap_rng", -1, oh, NULL, 0);
WARN(IS_ERR(pdev), "Can't build omap_device for omap_rng\n");
}
@@ -689,8 +729,7 @@ static void __init omap_init_ocp2scp(void)
pdata->dev_cnt = dev_cnt;
- pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(*pdata), NULL,
- 0, false);
+ pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(*pdata));
if (IS_ERR(pdev)) {
pr_err("Could not build omap_device for %s %s\n",
name, oh_name);
@@ -721,6 +760,7 @@ static int __init omap2_init_devices(void)
omap_init_mbox();
/* If dtb is there, the devices will be created dynamically */
if (!of_have_populated_dt()) {
+ omap_init_control_usb();
omap_init_dmic();
omap_init_mcpdm();
omap_init_mcspi();
@@ -734,4 +774,4 @@ static int __init omap2_init_devices(void)
return 0;
}
-arch_initcall(omap2_init_devices);
+omap_arch_initcall(omap2_init_devices);
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
index cc75aaf6e764..ff37be1f6f93 100644
--- a/arch/arm/mach-omap2/display.c
+++ b/arch/arm/mach-omap2/display.c
@@ -226,7 +226,7 @@ static struct platform_device *create_dss_pdev(const char *pdev_name,
dev_set_name(&pdev->dev, "%s", pdev->name);
ohs[0] = oh;
- od = omap_device_alloc(pdev, ohs, 1, NULL, 0);
+ od = omap_device_alloc(pdev, ohs, 1);
if (IS_ERR(od)) {
pr_err("Could not alloc omap_device for %s\n", pdev_name);
r = -ENOMEM;
diff --git a/arch/arm/mach-omap2/dma.c b/arch/arm/mach-omap2/dma.c
index 612b98249873..dab9fc014b97 100644
--- a/arch/arm/mach-omap2/dma.c
+++ b/arch/arm/mach-omap2/dma.c
@@ -27,7 +27,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
-
+#include <linux/dma-mapping.h>
#include <linux/omap-dma.h>
#include "soc.h"
@@ -248,7 +248,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
p->errata = configure_dma_errata();
- pdev = omap_device_build(name, 0, oh, p, sizeof(*p), NULL, 0, 0);
+ pdev = omap_device_build(name, 0, oh, p, sizeof(*p));
kfree(p);
if (IS_ERR(pdev)) {
pr_err("%s: Can't build omap_device for %s:%s.\n",
@@ -288,9 +288,26 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
return 0;
}
+static const struct platform_device_info omap_dma_dev_info = {
+ .name = "omap-dma-engine",
+ .id = -1,
+ .dma_mask = DMA_BIT_MASK(32),
+};
+
static int __init omap2_system_dma_init(void)
{
- return omap_hwmod_for_each_by_class("dma",
+ struct platform_device *pdev;
+ int res;
+
+ res = omap_hwmod_for_each_by_class("dma",
omap2_system_dma_init_dev, NULL);
+ if (res)
+ return res;
+
+ pdev = platform_device_register_full(&omap_dma_dev_info);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ return res;
}
-arch_initcall(omap2_system_dma_init);
+omap_arch_initcall(omap2_system_dma_init);
diff --git a/arch/arm/mach-omap2/drm.c b/arch/arm/mach-omap2/drm.c
index 2a2cfa88ddbf..59a4af779f42 100644
--- a/arch/arm/mach-omap2/drm.c
+++ b/arch/arm/mach-omap2/drm.c
@@ -51,8 +51,7 @@ static int __init omap_init_drm(void)
oh = omap_hwmod_lookup("dmm");
if (oh) {
- pdev = omap_device_build(oh->name, -1, oh, NULL, 0, NULL, 0,
- false);
+ pdev = omap_device_build(oh->name, -1, oh, NULL, 0);
WARN(IS_ERR(pdev), "Could not build omap_device for %s\n",
oh->name);
}
@@ -63,6 +62,6 @@ static int __init omap_init_drm(void)
}
-arch_initcall(omap_init_drm);
+omap_arch_initcall(omap_init_drm);
#endif
diff --git a/arch/arm/mach-omap2/emu.c b/arch/arm/mach-omap2/emu.c
index b3566f68a559..cbeaca2d7695 100644
--- a/arch/arm/mach-omap2/emu.c
+++ b/arch/arm/mach-omap2/emu.c
@@ -47,4 +47,4 @@ static int __init emu_init(void)
return 0;
}
-subsys_initcall(emu_init);
+omap_subsys_initcall(emu_init);
diff --git a/arch/arm/mach-omap2/fb.c b/arch/arm/mach-omap2/fb.c
index d9bd965f6d07..190ae493c6ef 100644
--- a/arch/arm/mach-omap2/fb.c
+++ b/arch/arm/mach-omap2/fb.c
@@ -89,7 +89,7 @@ static int __init omap_init_vrfb(void)
return 0;
}
-arch_initcall(omap_init_vrfb);
+omap_arch_initcall(omap_init_vrfb);
#endif
#if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
@@ -113,6 +113,6 @@ static int __init omap_init_fb(void)
return platform_device_register(&omap_fb_device);
}
-arch_initcall(omap_init_fb);
+omap_arch_initcall(omap_init_fb);
#endif
diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c
index 399acabc3d0b..7a577145b68b 100644
--- a/arch/arm/mach-omap2/gpio.c
+++ b/arch/arm/mach-omap2/gpio.c
@@ -23,6 +23,7 @@
#include <linux/of.h>
#include <linux/platform_data/gpio-omap.h>
+#include "soc.h"
#include "omap_hwmod.h"
#include "omap_device.h"
#include "omap-pm.h"
@@ -131,8 +132,7 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
pwrdm = omap_hwmod_get_pwrdm(oh);
pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
- pdev = omap_device_build(name, id - 1, oh, pdata,
- sizeof(*pdata), NULL, 0, false);
+ pdev = omap_device_build(name, id - 1, oh, pdata, sizeof(*pdata));
kfree(pdata);
if (IS_ERR(pdev)) {
@@ -147,7 +147,7 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
/*
* gpio_init needs to be done before
* machine_init functions access gpio APIs.
- * Hence gpio_init is a postcore_initcall.
+ * Hence gpio_init is a omap_postcore_initcall.
*/
static int __init omap2_gpio_init(void)
{
@@ -157,4 +157,4 @@ static int __init omap2_gpio_init(void)
return omap_hwmod_for_each_by_class("gpio", omap2_gpio_dev_init, NULL);
}
-postcore_initcall(omap2_gpio_init);
+omap_postcore_initcall(omap2_gpio_init);
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index db969a5c4998..afc1e8c32d6c 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -89,20 +89,21 @@ static int omap2_nand_gpmc_retime(
return 0;
}
-static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
+static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
{
/* support only OMAP3 class */
- if (!cpu_is_omap34xx()) {
+ if (!cpu_is_omap34xx() && !soc_is_am33xx()) {
pr_err("BCH ecc is not supported on this CPU\n");
return 0;
}
/*
- * For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1.
- * Other chips may be added if confirmed to work.
+ * For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1
+ * and AM33xx derivates. Other chips may be added if confirmed to work.
*/
if ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) &&
- (!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) {
+ (!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0)) &&
+ (!soc_is_am33xx())) {
pr_err("BCH 4-bit mode is not supported on this CPU\n");
return 0;
}
@@ -110,8 +111,8 @@ static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
return 1;
}
-int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
- struct gpmc_timings *gpmc_t)
+int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
+ struct gpmc_timings *gpmc_t)
{
int err = 0;
struct device *dev = &gpmc_nand_device.dev;
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 94a349e4dc96..fadd87435cd0 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -356,7 +356,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
return ret;
}
-void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
+void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
{
int err;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 8033cb747c86..e4b16c8efe8b 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -25,6 +25,10 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_mtd.h>
+#include <linux/of_device.h>
+#include <linux/mtd/nand.h>
#include <linux/platform_data/mtd-nand-omap2.h>
@@ -34,6 +38,8 @@
#include "common.h"
#include "omap_device.h"
#include "gpmc.h"
+#include "gpmc-nand.h"
+#include "gpmc-onenand.h"
#define DEVICE_NAME "omap-gpmc"
@@ -145,7 +151,8 @@ static unsigned gpmc_irq_start;
static struct resource gpmc_mem_root;
static struct resource gpmc_cs_mem[GPMC_CS_NUM];
static DEFINE_SPINLOCK(gpmc_mem_lock);
-static unsigned int gpmc_cs_map; /* flag for cs which are initialized */
+/* Define chip-selects as reserved by default until probe completes */
+static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
static struct device *gpmc_dev;
static int gpmc_irq;
static resource_size_t phys_base, mem_size;
@@ -783,9 +790,6 @@ static int gpmc_mem_init(void)
* even if we didn't boot from ROM.
*/
boot_rom_space = BOOT_ROM_SPACE;
- /* In apollon the CS0 is mapped as 0x0000 0000 */
- if (machine_is_omap_apollon())
- boot_rom_space = 0;
gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space;
gpmc_mem_root.end = GPMC_MEM_END;
@@ -1118,8 +1122,215 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
/* TODO: remove, see function definition */
gpmc_convert_ps_to_ns(gpmc_t);
+ /* Now the GPMC is initialised, unreserve the chip-selects */
+ gpmc_cs_map = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id gpmc_dt_ids[] = {
+ { .compatible = "ti,omap2420-gpmc" },
+ { .compatible = "ti,omap2430-gpmc" },
+ { .compatible = "ti,omap3430-gpmc" }, /* omap3430 & omap3630 */
+ { .compatible = "ti,omap4430-gpmc" }, /* omap4430 & omap4460 & omap543x */
+ { .compatible = "ti,am3352-gpmc" }, /* am335x devices */
+ { }
+};
+MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
+
+static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
+ struct gpmc_timings *gpmc_t)
+{
+ u32 val;
+
+ memset(gpmc_t, 0, sizeof(*gpmc_t));
+
+ /* minimum clock period for syncronous mode */
+ if (!of_property_read_u32(np, "gpmc,sync-clk", &val))
+ gpmc_t->sync_clk = val;
+
+ /* chip select timtings */
+ if (!of_property_read_u32(np, "gpmc,cs-on", &val))
+ gpmc_t->cs_on = val;
+
+ if (!of_property_read_u32(np, "gpmc,cs-rd-off", &val))
+ gpmc_t->cs_rd_off = val;
+
+ if (!of_property_read_u32(np, "gpmc,cs-wr-off", &val))
+ gpmc_t->cs_wr_off = val;
+
+ /* ADV signal timings */
+ if (!of_property_read_u32(np, "gpmc,adv-on", &val))
+ gpmc_t->adv_on = val;
+
+ if (!of_property_read_u32(np, "gpmc,adv-rd-off", &val))
+ gpmc_t->adv_rd_off = val;
+
+ if (!of_property_read_u32(np, "gpmc,adv-wr-off", &val))
+ gpmc_t->adv_wr_off = val;
+
+ /* WE signal timings */
+ if (!of_property_read_u32(np, "gpmc,we-on", &val))
+ gpmc_t->we_on = val;
+
+ if (!of_property_read_u32(np, "gpmc,we-off", &val))
+ gpmc_t->we_off = val;
+
+ /* OE signal timings */
+ if (!of_property_read_u32(np, "gpmc,oe-on", &val))
+ gpmc_t->oe_on = val;
+
+ if (!of_property_read_u32(np, "gpmc,oe-off", &val))
+ gpmc_t->oe_off = val;
+
+ /* access and cycle timings */
+ if (!of_property_read_u32(np, "gpmc,page-burst-access", &val))
+ gpmc_t->page_burst_access = val;
+
+ if (!of_property_read_u32(np, "gpmc,access", &val))
+ gpmc_t->access = val;
+
+ if (!of_property_read_u32(np, "gpmc,rd-cycle", &val))
+ gpmc_t->rd_cycle = val;
+
+ if (!of_property_read_u32(np, "gpmc,wr-cycle", &val))
+ gpmc_t->wr_cycle = val;
+
+ /* only for OMAP3430 */
+ if (!of_property_read_u32(np, "gpmc,wr-access", &val))
+ gpmc_t->wr_access = val;
+
+ if (!of_property_read_u32(np, "gpmc,wr-data-mux-bus", &val))
+ gpmc_t->wr_data_mux_bus = val;
+}
+
+#ifdef CONFIG_MTD_NAND
+
+static const char * const nand_ecc_opts[] = {
+ [OMAP_ECC_HAMMING_CODE_DEFAULT] = "sw",
+ [OMAP_ECC_HAMMING_CODE_HW] = "hw",
+ [OMAP_ECC_HAMMING_CODE_HW_ROMCODE] = "hw-romcode",
+ [OMAP_ECC_BCH4_CODE_HW] = "bch4",
+ [OMAP_ECC_BCH8_CODE_HW] = "bch8",
+};
+
+static int gpmc_probe_nand_child(struct platform_device *pdev,
+ struct device_node *child)
+{
+ u32 val;
+ const char *s;
+ struct gpmc_timings gpmc_t;
+ struct omap_nand_platform_data *gpmc_nand_data;
+
+ if (of_property_read_u32(child, "reg", &val) < 0) {
+ dev_err(&pdev->dev, "%s has no 'reg' property\n",
+ child->full_name);
+ return -ENODEV;
+ }
+
+ gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
+ GFP_KERNEL);
+ if (!gpmc_nand_data)
+ return -ENOMEM;
+
+ gpmc_nand_data->cs = val;
+ gpmc_nand_data->of_node = child;
+
+ if (!of_property_read_string(child, "ti,nand-ecc-opt", &s))
+ for (val = 0; val < ARRAY_SIZE(nand_ecc_opts); val++)
+ if (!strcasecmp(s, nand_ecc_opts[val])) {
+ gpmc_nand_data->ecc_opt = val;
+ break;
+ }
+
+ val = of_get_nand_bus_width(child);
+ if (val == 16)
+ gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
+
+ gpmc_read_timings_dt(child, &gpmc_t);
+ gpmc_nand_init(gpmc_nand_data, &gpmc_t);
+
+ return 0;
+}
+#else
+static int gpmc_probe_nand_child(struct platform_device *pdev,
+ struct device_node *child)
+{
return 0;
}
+#endif
+
+#ifdef CONFIG_MTD_ONENAND
+static int gpmc_probe_onenand_child(struct platform_device *pdev,
+ struct device_node *child)
+{
+ u32 val;
+ struct omap_onenand_platform_data *gpmc_onenand_data;
+
+ if (of_property_read_u32(child, "reg", &val) < 0) {
+ dev_err(&pdev->dev, "%s has no 'reg' property\n",
+ child->full_name);
+ return -ENODEV;
+ }
+
+ gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data),
+ GFP_KERNEL);
+ if (!gpmc_onenand_data)
+ return -ENOMEM;
+
+ gpmc_onenand_data->cs = val;
+ gpmc_onenand_data->of_node = child;
+ gpmc_onenand_data->dma_channel = -1;
+
+ if (!of_property_read_u32(child, "dma-channel", &val))
+ gpmc_onenand_data->dma_channel = val;
+
+ gpmc_onenand_init(gpmc_onenand_data);
+
+ return 0;
+}
+#else
+static int gpmc_probe_onenand_child(struct platform_device *pdev,
+ struct device_node *child)
+{
+ return 0;
+}
+#endif
+
+static int gpmc_probe_dt(struct platform_device *pdev)
+{
+ int ret;
+ struct device_node *child;
+ const struct of_device_id *of_id =
+ of_match_device(gpmc_dt_ids, &pdev->dev);
+
+ if (!of_id)
+ return 0;
+
+ for_each_node_by_name(child, "nand") {
+ ret = gpmc_probe_nand_child(pdev, child);
+ if (ret < 0) {
+ of_node_put(child);
+ return ret;
+ }
+ }
+
+ for_each_node_by_name(child, "onenand") {
+ ret = gpmc_probe_onenand_child(pdev, child);
+ if (ret < 0) {
+ of_node_put(child);
+ return ret;
+ }
+ }
+ return 0;
+}
+#else
+static int gpmc_probe_dt(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
static int gpmc_probe(struct platform_device *pdev)
{
@@ -1134,11 +1345,9 @@ static int gpmc_probe(struct platform_device *pdev)
phys_base = res->start;
mem_size = resource_size(res);
- gpmc_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!gpmc_base) {
- dev_err(&pdev->dev, "error: request memory / ioremap\n");
- return -EADDRNOTAVAIL;
- }
+ gpmc_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gpmc_base))
+ return PTR_ERR(gpmc_base);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL)
@@ -1174,6 +1383,14 @@ static int gpmc_probe(struct platform_device *pdev)
if (IS_ERR_VALUE(gpmc_setup_irq()))
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
+ rc = gpmc_probe_dt(pdev);
+ if (rc < 0) {
+ clk_disable_unprepare(gpmc_l3_clk);
+ clk_put(gpmc_l3_clk);
+ dev_err(gpmc_dev, "failed to probe DT parameters\n");
+ return rc;
+ }
+
return 0;
}
@@ -1191,6 +1408,7 @@ static struct platform_driver gpmc_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(gpmc_dt_ids),
},
};
@@ -1205,7 +1423,7 @@ static __exit void gpmc_exit(void)
}
-postcore_initcall(gpmc_init);
+omap_postcore_initcall(gpmc_init);
module_exit(gpmc_exit);
static int __init omap_gpmc_init(void)
@@ -1214,18 +1432,25 @@ static int __init omap_gpmc_init(void)
struct platform_device *pdev;
char *oh_name = "gpmc";
+ /*
+ * if the board boots up with a populated DT, do not
+ * manually add the device from this initcall
+ */
+ if (of_have_populated_dt())
+ return -ENODEV;
+
oh = omap_hwmod_lookup(oh_name);
if (!oh) {
pr_err("Could not look up %s\n", oh_name);
return -ENODEV;
}
- pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0, NULL, 0, 0);
+ pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0);
WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
}
-postcore_initcall(omap_gpmc_init);
+omap_postcore_initcall(omap_gpmc_init);
static irqreturn_t gpmc_handle_irq(int irq, void *dev)
{
diff --git a/arch/arm/mach-omap2/hdq1w.c b/arch/arm/mach-omap2/hdq1w.c
index ab7bf181a105..cbc8e3c480e0 100644
--- a/arch/arm/mach-omap2/hdq1w.c
+++ b/arch/arm/mach-omap2/hdq1w.c
@@ -27,6 +27,7 @@
#include <linux/err.h>
#include <linux/platform_device.h>
+#include "soc.h"
#include "omap_hwmod.h"
#include "omap_device.h"
#include "hdq1w.h"
@@ -87,10 +88,10 @@ static int __init omap_init_hdq(void)
if (!oh)
return 0;
- pdev = omap_device_build(devname, id, oh, NULL, 0, NULL, 0, 0);
+ pdev = omap_device_build(devname, id, oh, NULL, 0);
WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s.\n",
devname, oh->name);
return 0;
}
-arch_initcall(omap_init_hdq);
+omap_arch_initcall(omap_init_hdq);
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 4a964338992a..2ef1f8714fcf 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -522,7 +522,7 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo,
}
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
- od = omap_device_alloc(pdev, ohs, 1, NULL, 0);
+ od = omap_device_alloc(pdev, ohs, 1);
if (IS_ERR(od)) {
pr_err("Could not allocate od for %s\n", name);
goto put_pdev;
diff --git a/arch/arm/mach-omap2/hwspinlock.c b/arch/arm/mach-omap2/hwspinlock.c
index 1df9b5feda16..ef175acaeaa2 100644
--- a/arch/arm/mach-omap2/hwspinlock.c
+++ b/arch/arm/mach-omap2/hwspinlock.c
@@ -21,6 +21,7 @@
#include <linux/err.h>
#include <linux/hwspinlock.h>
+#include "soc.h"
#include "omap_hwmod.h"
#include "omap_device.h"
@@ -46,8 +47,7 @@ static int __init hwspinlocks_init(void)
return -EINVAL;
pdev = omap_device_build(dev_name, 0, oh, &omap_hwspinlock_pdata,
- sizeof(struct hwspinlock_pdata),
- NULL, 0, false);
+ sizeof(struct hwspinlock_pdata));
if (IS_ERR(pdev)) {
pr_err("Can't build omap_device for %s:%s\n", dev_name,
oh_name);
@@ -57,4 +57,4 @@ static int __init hwspinlocks_init(void)
return retval;
}
/* early board code might need to reserve specific hwspinlock instances */
-postcore_initcall(hwspinlocks_init);
+omap_postcore_initcall(hwspinlocks_init);
diff --git a/arch/arm/mach-omap2/i2c.c b/arch/arm/mach-omap2/i2c.c
index b9074dde3b9c..d940e53dd9f2 100644
--- a/arch/arm/mach-omap2/i2c.c
+++ b/arch/arm/mach-omap2/i2c.c
@@ -178,10 +178,14 @@ int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
if (cpu_is_omap34xx())
pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;
pdev = omap_device_build(name, bus_id, oh, pdata,
- sizeof(struct omap_i2c_bus_platform_data),
- NULL, 0, 0);
+ sizeof(struct omap_i2c_bus_platform_data));
WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", name);
return PTR_RET(pdev);
}
+static int __init omap_i2c_cmdline(void)
+{
+ return omap_register_i2c_bus_cmdline();
+}
+omap_subsys_initcall(omap_i2c_cmdline);
diff --git a/arch/arm/mach-omap2/include/mach/serial.h b/arch/arm/mach-omap2/include/mach/serial.h
index 70eda00db7a4..7ca1fcff453b 100644
--- a/arch/arm/mach-omap2/include/mach/serial.h
+++ b/arch/arm/mach-omap2/include/mach/serial.h
@@ -8,20 +8,6 @@
* GNU General Public License for more details.
*/
-/*
- * Memory entry used for the DEBUG_LL UART configuration, relative to
- * start of RAM. See also uncompress.h and debug-macro.S.
- *
- * Note that using a memory location for storing the UART configuration
- * has at least two limitations:
- *
- * 1. Kernel uncompress code cannot overlap OMAP_UART_INFO as the
- * uncompress code could then partially overwrite itself
- * 2. We assume printascii is called at least once before paging_init,
- * and addruart has a chance to read OMAP_UART_INFO
- */
-#define OMAP_UART_INFO_OFS 0x3ffc
-
/* OMAP2 serial ports */
#define OMAP2_UART1_BASE 0x4806a000
#define OMAP2_UART2_BASE 0x4806c000
@@ -68,29 +54,6 @@
#define OMAP24XX_BASE_BAUD (48000000/16)
-/*
- * DEBUG_LL port encoding stored into the UART1 scratchpad register by
- * decomp_setup in uncompress.h
- */
-#define OMAP2UART1 21
-#define OMAP2UART2 22
-#define OMAP2UART3 23
-#define OMAP3UART1 OMAP2UART1
-#define OMAP3UART2 OMAP2UART2
-#define OMAP3UART3 33
-#define OMAP3UART4 34 /* Only on 36xx */
-#define OMAP4UART1 OMAP2UART1
-#define OMAP4UART2 OMAP2UART2
-#define OMAP4UART3 43
-#define OMAP4UART4 44
-#define TI81XXUART1 81
-#define TI81XXUART2 82
-#define TI81XXUART3 83
-#define AM33XXUART1 84
-#define OMAP5UART3 OMAP4UART3
-#define OMAP5UART4 OMAP4UART4
-#define ZOOM_UART 95 /* Only on zoom2/3 */
-
#ifndef __ASSEMBLER__
struct omap_board_data;
diff --git a/arch/arm/mach-omap2/include/mach/uncompress.h b/arch/arm/mach-omap2/include/mach/uncompress.h
deleted file mode 100644
index 8e3546d3e041..000000000000
--- a/arch/arm/mach-omap2/include/mach/uncompress.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/uncompress.h
- *
- * Serial port stubs for kernel decompress status messages
- *
- * Initially based on:
- * linux-2.4.15-rmk1-dsplinux1.6/arch/arm/plat-omap/include/mach1510/uncompress.h
- * Copyright (C) 2000 RidgeRun, Inc.
- * Author: Greg Lonnon <glonnon@ridgerun.com>
- *
- * Rewritten by:
- * Author: <source@mvista.com>
- * 2004 (c) MontaVista Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/types.h>
-#include <linux/serial_reg.h>
-
-#include <asm/memory.h>
-#include <asm/mach-types.h>
-
-#include <mach/serial.h>
-
-#define MDR1_MODE_MASK 0x07
-
-volatile u8 *uart_base;
-int uart_shift;
-
-/*
- * Store the DEBUG_LL uart number into memory.
- * See also debug-macro.S, and serial.c for related code.
- */
-static void set_omap_uart_info(unsigned char port)
-{
- /*
- * Get address of some.bss variable and round it down
- * a la CONFIG_AUTO_ZRELADDR.
- */
- u32 ram_start = (u32)&uart_shift & 0xf8000000;
- u32 *uart_info = (u32 *)(ram_start + OMAP_UART_INFO_OFS);
- *uart_info = port;
-}
-
-static void putc(int c)
-{
- if (!uart_base)
- return;
-
- /* Check for UART 16x mode */
- if ((uart_base[UART_OMAP_MDR1 << uart_shift] & MDR1_MODE_MASK) != 0)
- return;
-
- while (!(uart_base[UART_LSR << uart_shift] & UART_LSR_THRE))
- barrier();
- uart_base[UART_TX << uart_shift] = c;
-}
-
-static inline void flush(void)
-{
-}
-
-/*
- * Macros to configure UART1 and debug UART
- */
-#define _DEBUG_LL_ENTRY(mach, dbg_uart, dbg_shft, dbg_id) \
- if (machine_is_##mach()) { \
- uart_base = (volatile u8 *)(dbg_uart); \
- uart_shift = (dbg_shft); \
- port = (dbg_id); \
- set_omap_uart_info(port); \
- break; \
- }
-
-#define DEBUG_LL_OMAP2(p, mach) \
- _DEBUG_LL_ENTRY(mach, OMAP2_UART##p##_BASE, OMAP_PORT_SHIFT, \
- OMAP2UART##p)
-
-#define DEBUG_LL_OMAP3(p, mach) \
- _DEBUG_LL_ENTRY(mach, OMAP3_UART##p##_BASE, OMAP_PORT_SHIFT, \
- OMAP3UART##p)
-
-#define DEBUG_LL_OMAP4(p, mach) \
- _DEBUG_LL_ENTRY(mach, OMAP4_UART##p##_BASE, OMAP_PORT_SHIFT, \
- OMAP4UART##p)
-
-#define DEBUG_LL_OMAP5(p, mach) \
- _DEBUG_LL_ENTRY(mach, OMAP5_UART##p##_BASE, OMAP_PORT_SHIFT, \
- OMAP5UART##p)
-/* Zoom2/3 shift is different for UART1 and external port */
-#define DEBUG_LL_ZOOM(mach) \
- _DEBUG_LL_ENTRY(mach, ZOOM_UART_BASE, ZOOM_PORT_SHIFT, ZOOM_UART)
-
-#define DEBUG_LL_TI81XX(p, mach) \
- _DEBUG_LL_ENTRY(mach, TI81XX_UART##p##_BASE, OMAP_PORT_SHIFT, \
- TI81XXUART##p)
-
-#define DEBUG_LL_AM33XX(p, mach) \
- _DEBUG_LL_ENTRY(mach, AM33XX_UART##p##_BASE, OMAP_PORT_SHIFT, \
- AM33XXUART##p)
-
-static inline void arch_decomp_setup(void)
-{
- int port = 0;
-
- /*
- * Initialize the port based on the machine ID from the bootloader.
- * Note that we're using macros here instead of switch statement
- * as machine_is functions are optimized out for the boards that
- * are not selected.
- */
- do {
- /* omap2 based boards using UART1 */
- DEBUG_LL_OMAP2(1, omap_2430sdp);
- DEBUG_LL_OMAP2(1, omap_apollon);
- DEBUG_LL_OMAP2(1, omap_h4);
-
- /* omap2 based boards using UART3 */
- DEBUG_LL_OMAP2(3, nokia_n800);
- DEBUG_LL_OMAP2(3, nokia_n810);
- DEBUG_LL_OMAP2(3, nokia_n810_wimax);
-
- /* omap3 based boards using UART1 */
- DEBUG_LL_OMAP2(1, omap3evm);
- DEBUG_LL_OMAP3(1, omap_3430sdp);
- DEBUG_LL_OMAP3(1, omap_3630sdp);
- DEBUG_LL_OMAP3(1, omap3530_lv_som);
- DEBUG_LL_OMAP3(1, omap3_torpedo);
-
- /* omap3 based boards using UART3 */
- DEBUG_LL_OMAP3(3, cm_t35);
- DEBUG_LL_OMAP3(3, cm_t3517);
- DEBUG_LL_OMAP3(3, cm_t3730);
- DEBUG_LL_OMAP3(3, craneboard);
- DEBUG_LL_OMAP3(3, devkit8000);
- DEBUG_LL_OMAP3(3, igep0020);
- DEBUG_LL_OMAP3(3, igep0030);
- DEBUG_LL_OMAP3(3, nokia_rm680);
- DEBUG_LL_OMAP3(3, nokia_rm696);
- DEBUG_LL_OMAP3(3, nokia_rx51);
- DEBUG_LL_OMAP3(3, omap3517evm);
- DEBUG_LL_OMAP3(3, omap3_beagle);
- DEBUG_LL_OMAP3(3, omap3_pandora);
- DEBUG_LL_OMAP3(3, omap_ldp);
- DEBUG_LL_OMAP3(3, overo);
- DEBUG_LL_OMAP3(3, touchbook);
-
- /* omap4 based boards using UART3 */
- DEBUG_LL_OMAP4(3, omap_4430sdp);
- DEBUG_LL_OMAP4(3, omap4_panda);
-
- /* omap5 based boards using UART3 */
- DEBUG_LL_OMAP5(3, omap5_sevm);
-
- /* zoom2/3 external uart */
- DEBUG_LL_ZOOM(omap_zoom2);
- DEBUG_LL_ZOOM(omap_zoom3);
-
- /* TI8168 base boards using UART3 */
- DEBUG_LL_TI81XX(3, ti8168evm);
-
- /* TI8148 base boards using UART1 */
- DEBUG_LL_TI81XX(1, ti8148evm);
-
- /* AM33XX base boards using UART1 */
- DEBUG_LL_AM33XX(1, am335xevm);
- } while (0);
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index df49f2a49461..5d8768075dd9 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -23,6 +23,7 @@
#include <linux/omap-dma.h>
+#include "soc.h"
#include "omap_device.h"
/*
@@ -101,7 +102,7 @@ static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
count++;
}
pdev = omap_device_build_ss(name, id, oh_device, count, pdata,
- sizeof(*pdata), NULL, 0, false);
+ sizeof(*pdata));
kfree(pdata);
if (IS_ERR(pdev)) {
pr_err("%s: Can't build omap_device for %s:%s.\n", __func__,
@@ -118,4 +119,4 @@ static int __init omap2_mcbsp_init(void)
return 0;
}
-arch_initcall(omap2_mcbsp_init);
+omap_arch_initcall(omap2_mcbsp_init);
diff --git a/arch/arm/mach-omap2/msdi.c b/arch/arm/mach-omap2/msdi.c
index aafdd4ca9f4f..c52d8b4a3e91 100644
--- a/arch/arm/mach-omap2/msdi.c
+++ b/arch/arm/mach-omap2/msdi.c
@@ -150,7 +150,7 @@ void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data)
return;
}
pdev = omap_device_build(dev_name, id, oh, mmc_data[0],
- sizeof(struct omap_mmc_platform_data), NULL, 0, 0);
+ sizeof(struct omap_mmc_platform_data));
if (IS_ERR(pdev))
WARN(1, "Can'd build omap_device for %s:%s.\n",
dev_name, oh->name);
diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c
index 6da4f7ae9d7f..f6daae821ebb 100644
--- a/arch/arm/mach-omap2/omap-iommu.c
+++ b/arch/arm/mach-omap2/omap-iommu.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/platform_data/iommu-omap.h>
+#include "soc.h"
#include "omap_hwmod.h"
#include "omap_device.h"
@@ -41,8 +42,7 @@ static int __init omap_iommu_dev_init(struct omap_hwmod *oh, void *unused)
pdata->deassert_reset = omap_device_deassert_hardreset;
}
- pdev = omap_device_build("omap-iommu", i, oh, pdata, sizeof(*pdata),
- NULL, 0, 0);
+ pdev = omap_device_build("omap-iommu", i, oh, pdata, sizeof(*pdata));
kfree(pdata);
@@ -61,7 +61,7 @@ static int __init omap_iommu_init(void)
return omap_hwmod_for_each_by_class("mmu", omap_iommu_dev_init, NULL);
}
/* must be ready before omap3isp is probed */
-subsys_initcall(omap_iommu_init);
+omap_subsys_initcall(omap_iommu_init);
static void __exit omap_iommu_exit(void)
{
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index aac46bfdbeb2..8bcb64bcdcdb 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -87,37 +87,6 @@ static inline void set_cpu_wakeup_addr(unsigned int cpu_id, u32 addr)
}
/*
- * Set the CPUx powerdomain's previous power state
- */
-static inline void set_cpu_next_pwrst(unsigned int cpu_id,
- unsigned int power_state)
-{
- struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
-
- pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
-}
-
-/*
- * Read CPU's previous power state
- */
-static inline unsigned int read_cpu_prev_pwrst(unsigned int cpu_id)
-{
- struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
-
- return pwrdm_read_prev_pwrst(pm_info->pwrdm);
-}
-
-/*
- * Clear the CPUx powerdomain's previous power state
- */
-static inline void clear_cpu_prev_pwrst(unsigned int cpu_id)
-{
- struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
-
- pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
-}
-
-/*
* Store the SCU power status value to scratchpad memory
*/
static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state)
@@ -230,6 +199,7 @@ static void save_l2x0_context(void)
*/
int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
{
+ struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
unsigned int save_state = 0;
unsigned int wakeup_cpu;
@@ -268,7 +238,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
save_state = 2;
cpu_clear_prev_logic_pwrst(cpu);
- set_cpu_next_pwrst(cpu, power_state);
+ pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume));
scu_pwrst_prepare(cpu, power_state);
l2x0_pwrst_prepare(cpu, save_state);
@@ -286,7 +256,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
* domain transition
*/
wakeup_cpu = smp_processor_id();
- set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
+ pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
pwrdm_post_transition(NULL);
@@ -300,8 +270,8 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
*/
int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
{
- unsigned int cpu_state = 0;
struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
+ unsigned int cpu_state = 0;
if (omap_rev() == OMAP4430_REV_ES1_0)
return -ENXIO;
@@ -309,8 +279,8 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
if (power_state == PWRDM_POWER_OFF)
cpu_state = 1;
- clear_cpu_prev_pwrst(cpu);
- set_cpu_next_pwrst(cpu, power_state);
+ pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
+ pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup));
scu_pwrst_prepare(cpu, power_state);
@@ -321,7 +291,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
*/
omap4_finish_suspend(cpu_state);
- set_cpu_next_pwrst(cpu, PWRDM_POWER_ON);
+ pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
return 0;
}
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index cd42d921940d..d9727218dd0a 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -19,9 +19,9 @@
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/cacheflush.h>
-#include <asm/hardware/gic.h>
#include <asm/smp_scu.h>
#include "omap-secure.h"
@@ -157,7 +157,7 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *
booted = true;
}
- gic_raise_softirq(cpumask_of(cpu), 0);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
/*
* Now the secondary core is starting up let it run its
@@ -215,7 +215,7 @@ static void __init omap4_smp_init_cpus(void)
* Currently we can't call ioremap here because
* SoC detection won't work until after init_early.
*/
- scu_base = OMAP2_L4_IO_ADDRESS(OMAP44XX_SCU_BASE);
+ scu_base = OMAP2_L4_IO_ADDRESS(scu_a9_get_base());
BUG_ON(!scu_base);
ncores = scu_get_core_count(scu_base);
} else if (cpu_id == CPU_CORTEX_A15) {
@@ -231,8 +231,6 @@ static void __init omap4_smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
static void __init omap4_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index 5d3b4f4f81ae..f8bb3b9b6a76 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -24,8 +24,7 @@
#include <linux/cpu.h>
#include <linux/notifier.h>
#include <linux/cpu_pm.h>
-
-#include <asm/hardware/gic.h>
+#include <linux/irqchip/arm-gic.h>
#include "omap-wakeupgen.h"
#include "omap-secure.h"
@@ -46,7 +45,7 @@
static void __iomem *wakeupgen_base;
static void __iomem *sar_base;
-static DEFINE_SPINLOCK(wakeupgen_lock);
+static DEFINE_RAW_SPINLOCK(wakeupgen_lock);
static unsigned int irq_target_cpu[MAX_IRQS];
static unsigned int irq_banks = MAX_NR_REG_BANKS;
static unsigned int max_irqs = MAX_IRQS;
@@ -134,9 +133,9 @@ static void wakeupgen_mask(struct irq_data *d)
{
unsigned long flags;
- spin_lock_irqsave(&wakeupgen_lock, flags);
+ raw_spin_lock_irqsave(&wakeupgen_lock, flags);
_wakeupgen_clear(d->irq, irq_target_cpu[d->irq]);
- spin_unlock_irqrestore(&wakeupgen_lock, flags);
+ raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
}
/*
@@ -146,9 +145,9 @@ static void wakeupgen_unmask(struct irq_data *d)
{
unsigned long flags;
- spin_lock_irqsave(&wakeupgen_lock, flags);
+ raw_spin_lock_irqsave(&wakeupgen_lock, flags);
_wakeupgen_set(d->irq, irq_target_cpu[d->irq]);
- spin_unlock_irqrestore(&wakeupgen_lock, flags);
+ raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
}
#ifdef CONFIG_HOTPLUG_CPU
@@ -189,7 +188,7 @@ static void wakeupgen_irqmask_all(unsigned int cpu, unsigned int set)
{
unsigned long flags;
- spin_lock_irqsave(&wakeupgen_lock, flags);
+ raw_spin_lock_irqsave(&wakeupgen_lock, flags);
if (set) {
_wakeupgen_save_masks(cpu);
_wakeupgen_set_all(cpu, WKG_MASK_ALL);
@@ -197,7 +196,7 @@ static void wakeupgen_irqmask_all(unsigned int cpu, unsigned int set)
_wakeupgen_set_all(cpu, WKG_UNMASK_ALL);
_wakeupgen_restore_masks(cpu);
}
- spin_unlock_irqrestore(&wakeupgen_lock, flags);
+ raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
}
#endif
diff --git a/arch/arm/mach-omap2/omap2-restart.c b/arch/arm/mach-omap2/omap2-restart.c
index be6bc89ab1e8..719b716a4494 100644
--- a/arch/arm/mach-omap2/omap2-restart.c
+++ b/arch/arm/mach-omap2/omap2-restart.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/io.h>
+#include "soc.h"
#include "common.h"
#include "prm2xxx.h"
@@ -62,4 +63,4 @@ static int __init omap2xxx_common_look_up_clks_for_reset(void)
return 0;
}
-core_initcall(omap2xxx_common_look_up_clks_for_reset);
+omap_core_initcall(omap2xxx_common_look_up_clks_for_reset);
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 6897ae21bb82..708bb115a27f 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -15,13 +15,14 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/platform_device.h>
#include <linux/memblock.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/export.h>
+#include <linux/irqchip/arm-gic.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/map.h>
#include <asm/memblock.h>
@@ -225,7 +226,7 @@ static int __init omap_l2_cache_init(void)
return 0;
}
-early_initcall(omap_l2_cache_init);
+omap_early_initcall(omap_l2_cache_init);
#endif
void __iomem *omap4_get_sar_ram_base(void)
@@ -253,18 +254,12 @@ static int __init omap4_sar_ram_init(void)
return 0;
}
-early_initcall(omap4_sar_ram_init);
-
-static struct of_device_id irq_match[] __initdata = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- { .compatible = "arm,cortex-a15-gic", .data = gic_of_init, },
- { }
-};
+omap_early_initcall(omap4_sar_ram_init);
void __init omap_gic_of_init(void)
{
omap_wakeupgen_init();
- of_irq_init(irq_match);
+ irqchip_init();
}
#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
diff --git a/arch/arm/mach-omap2/omap44xx.h b/arch/arm/mach-omap2/omap44xx.h
index 43b927b2e2e8..8a515bb74639 100644
--- a/arch/arm/mach-omap2/omap44xx.h
+++ b/arch/arm/mach-omap2/omap44xx.h
@@ -40,7 +40,6 @@
#define OMAP44XX_GIC_DIST_BASE 0x48241000
#define OMAP44XX_GIC_CPU_BASE 0x48240100
#define OMAP44XX_IRQ_GIC_START 32
-#define OMAP44XX_SCU_BASE 0x48240000
#define OMAP44XX_LOCAL_TWD_BASE 0x48240600
#define OMAP44XX_L2CACHE_BASE 0x48242000
#define OMAP44XX_WKUPGEN_BASE 0x48281000
diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
index e065daa537c0..381be7ac0c17 100644
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -17,68 +17,15 @@
* to control power management and interconnect properties of their
* devices.
*
- * In the medium- to long-term, this code should either be
- * a) implemented via arch-specific pointers in platform_data
- * or
- * b) implemented as a proper omap_bus/omap_device in Linux, no more
- * platform_data func pointers
+ * In the medium- to long-term, this code should be implemented as a
+ * proper omap_bus/omap_device in Linux, no more platform_data func
+ * pointers
*
*
- * Guidelines for usage by driver authors:
- *
- * 1. These functions are intended to be used by device drivers via
- * function pointers in struct platform_data. As an example,
- * omap_device_enable() should be passed to the driver as
- *
- * struct foo_driver_platform_data {
- * ...
- * int (*device_enable)(struct platform_device *pdev);
- * ...
- * }
- *
- * Note that the generic "device_enable" name is used, rather than
- * "omap_device_enable". This is so other architectures can pass in their
- * own enable/disable functions here.
- *
- * This should be populated during device setup:
- *
- * ...
- * pdata->device_enable = omap_device_enable;
- * ...
- *
- * 2. Drivers should first check to ensure the function pointer is not null
- * before calling it, as in:
- *
- * if (pdata->device_enable)
- * pdata->device_enable(pdev);
- *
- * This allows other architectures that don't use similar device_enable()/
- * device_shutdown() functions to execute normally.
- *
- * ...
- *
- * Suggested usage by device drivers:
- *
- * During device initialization:
- * device_enable()
- *
- * During device idle:
- * (save remaining device context if necessary)
- * device_idle();
- *
- * During device resume:
- * device_enable();
- * (restore context if necessary)
- *
- * During device shutdown:
- * device_shutdown()
- * (device must be reinitialized at this point to use it again)
- *
*/
#undef DEBUG
#include <linux/kernel.h>
-#include <linux/export.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/err.h>
@@ -89,158 +36,12 @@
#include <linux/of.h>
#include <linux/notifier.h>
+#include "soc.h"
#include "omap_device.h"
#include "omap_hwmod.h"
-/* These parameters are passed to _omap_device_{de,}activate() */
-#define USE_WAKEUP_LAT 0
-#define IGNORE_WAKEUP_LAT 1
-
-static int omap_early_device_register(struct platform_device *pdev);
-
-static struct omap_device_pm_latency omap_default_latency[] = {
- {
- .deactivate_func = omap_device_idle_hwmods,
- .activate_func = omap_device_enable_hwmods,
- .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
- }
-};
-
/* Private functions */
-/**
- * _omap_device_activate - increase device readiness
- * @od: struct omap_device *
- * @ignore_lat: increase to latency target (0) or full readiness (1)?
- *
- * Increase readiness of omap_device @od (thus decreasing device
- * wakeup latency, but consuming more power). If @ignore_lat is
- * IGNORE_WAKEUP_LAT, make the omap_device fully active. Otherwise,
- * if @ignore_lat is USE_WAKEUP_LAT, and the device's maximum wakeup
- * latency is greater than the requested maximum wakeup latency, step
- * backwards in the omap_device_pm_latency table to ensure the
- * device's maximum wakeup latency is less than or equal to the
- * requested maximum wakeup latency. Returns 0.
- */
-static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
-{
- struct timespec a, b, c;
-
- dev_dbg(&od->pdev->dev, "omap_device: activating\n");
-
- while (od->pm_lat_level > 0) {
- struct omap_device_pm_latency *odpl;
- unsigned long long act_lat = 0;
-
- od->pm_lat_level--;
-
- odpl = od->pm_lats + od->pm_lat_level;
-
- if (!ignore_lat &&
- (od->dev_wakeup_lat <= od->_dev_wakeup_lat_limit))
- break;
-
- read_persistent_clock(&a);
-
- /* XXX check return code */
- odpl->activate_func(od);
-
- read_persistent_clock(&b);
-
- c = timespec_sub(b, a);
- act_lat = timespec_to_ns(&c);
-
- dev_dbg(&od->pdev->dev,
- "omap_device: pm_lat %d: activate: elapsed time %llu nsec\n",
- od->pm_lat_level, act_lat);
-
- if (act_lat > odpl->activate_lat) {
- odpl->activate_lat_worst = act_lat;
- if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
- odpl->activate_lat = act_lat;
- dev_dbg(&od->pdev->dev,
- "new worst case activate latency %d: %llu\n",
- od->pm_lat_level, act_lat);
- } else
- dev_warn(&od->pdev->dev,
- "activate latency %d higher than expected. (%llu > %d)\n",
- od->pm_lat_level, act_lat,
- odpl->activate_lat);
- }
-
- od->dev_wakeup_lat -= odpl->activate_lat;
- }
-
- return 0;
-}
-
-/**
- * _omap_device_deactivate - decrease device readiness
- * @od: struct omap_device *
- * @ignore_lat: decrease to latency target (0) or full inactivity (1)?
- *
- * Decrease readiness of omap_device @od (thus increasing device
- * wakeup latency, but conserving power). If @ignore_lat is
- * IGNORE_WAKEUP_LAT, make the omap_device fully inactive. Otherwise,
- * if @ignore_lat is USE_WAKEUP_LAT, and the device's maximum wakeup
- * latency is less than the requested maximum wakeup latency, step
- * forwards in the omap_device_pm_latency table to ensure the device's
- * maximum wakeup latency is less than or equal to the requested
- * maximum wakeup latency. Returns 0.
- */
-static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
-{
- struct timespec a, b, c;
-
- dev_dbg(&od->pdev->dev, "omap_device: deactivating\n");
-
- while (od->pm_lat_level < od->pm_lats_cnt) {
- struct omap_device_pm_latency *odpl;
- unsigned long long deact_lat = 0;
-
- odpl = od->pm_lats + od->pm_lat_level;
-
- if (!ignore_lat &&
- ((od->dev_wakeup_lat + odpl->activate_lat) >
- od->_dev_wakeup_lat_limit))
- break;
-
- read_persistent_clock(&a);
-
- /* XXX check return code */
- odpl->deactivate_func(od);
-
- read_persistent_clock(&b);
-
- c = timespec_sub(b, a);
- deact_lat = timespec_to_ns(&c);
-
- dev_dbg(&od->pdev->dev,
- "omap_device: pm_lat %d: deactivate: elapsed time %llu nsec\n",
- od->pm_lat_level, deact_lat);
-
- if (deact_lat > odpl->deactivate_lat) {
- odpl->deactivate_lat_worst = deact_lat;
- if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
- odpl->deactivate_lat = deact_lat;
- dev_dbg(&od->pdev->dev,
- "new worst case deactivate latency %d: %llu\n",
- od->pm_lat_level, deact_lat);
- } else
- dev_warn(&od->pdev->dev,
- "deactivate latency %d higher than expected. (%llu > %d)\n",
- od->pm_lat_level, deact_lat,
- odpl->deactivate_lat);
- }
-
- od->dev_wakeup_lat += odpl->activate_lat;
-
- od->pm_lat_level++;
- }
-
- return 0;
-}
-
static void _add_clkdev(struct omap_device *od, const char *clk_alias,
const char *clk_name)
{
@@ -315,9 +116,6 @@ static void _add_hwmod_clocks_clkdev(struct omap_device *od,
* @oh: ptr to the single omap_hwmod that backs this omap_device
* @pdata: platform_data ptr to associate with the platform_device
* @pdata_len: amount of memory pointed to by @pdata
- * @pm_lats: pointer to a omap_device_pm_latency array for this device
- * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats
- * @is_early_device: should the device be registered as an early device or not
*
* Function for building an omap_device already registered from device-tree
*
@@ -356,7 +154,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
hwmods[i] = oh;
}
- od = omap_device_alloc(pdev, hwmods, oh_cnt, NULL, 0);
+ od = omap_device_alloc(pdev, hwmods, oh_cnt);
if (!od) {
dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
oh_name);
@@ -407,6 +205,39 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
return NOTIFY_DONE;
}
+/**
+ * _omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods
+ * @od: struct omap_device *od
+ *
+ * Enable all underlying hwmods. Returns 0.
+ */
+static int _omap_device_enable_hwmods(struct omap_device *od)
+{
+ int i;
+
+ for (i = 0; i < od->hwmods_cnt; i++)
+ omap_hwmod_enable(od->hwmods[i]);
+
+ /* XXX pass along return value here? */
+ return 0;
+}
+
+/**
+ * _omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
+ * @od: struct omap_device *od
+ *
+ * Idle all underlying hwmods. Returns 0.
+ */
+static int _omap_device_idle_hwmods(struct omap_device *od)
+{
+ int i;
+
+ for (i = 0; i < od->hwmods_cnt; i++)
+ omap_hwmod_idle(od->hwmods[i]);
+
+ /* XXX pass along return value here? */
+ return 0;
+}
/* Public functions for use by core code */
@@ -526,18 +357,14 @@ static int _od_fill_dma_resources(struct omap_device *od,
* @oh: ptr to the single omap_hwmod that backs this omap_device
* @pdata: platform_data ptr to associate with the platform_device
* @pdata_len: amount of memory pointed to by @pdata
- * @pm_lats: pointer to a omap_device_pm_latency array for this device
- * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats
*
* Convenience function for allocating an omap_device structure and filling
- * hwmods, resources and pm_latency attributes.
+ * hwmods, and resources.
*
* Returns an struct omap_device pointer or ERR_PTR() on error;
*/
struct omap_device *omap_device_alloc(struct platform_device *pdev,
- struct omap_hwmod **ohs, int oh_cnt,
- struct omap_device_pm_latency *pm_lats,
- int pm_lats_cnt)
+ struct omap_hwmod **ohs, int oh_cnt)
{
int ret = -ENOMEM;
struct omap_device *od;
@@ -626,18 +453,6 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev,
goto oda_exit3;
have_everything:
- if (!pm_lats) {
- pm_lats = omap_default_latency;
- pm_lats_cnt = ARRAY_SIZE(omap_default_latency);
- }
-
- od->pm_lats_cnt = pm_lats_cnt;
- od->pm_lats = kmemdup(pm_lats,
- sizeof(struct omap_device_pm_latency) * pm_lats_cnt,
- GFP_KERNEL);
- if (!od->pm_lats)
- goto oda_exit3;
-
pdev->archdata.od = od;
for (i = 0; i < oh_cnt; i++) {
@@ -663,7 +478,6 @@ void omap_device_delete(struct omap_device *od)
return;
od->pdev->archdata.od = NULL;
- kfree(od->pm_lats);
kfree(od->hwmods);
kfree(od);
}
@@ -675,9 +489,6 @@ void omap_device_delete(struct omap_device *od)
* @oh: ptr to the single omap_hwmod that backs this omap_device
* @pdata: platform_data ptr to associate with the platform_device
* @pdata_len: amount of memory pointed to by @pdata
- * @pm_lats: pointer to a omap_device_pm_latency array for this device
- * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats
- * @is_early_device: should the device be registered as an early device or not
*
* Convenience function for building and registering a single
* omap_device record, which in turn builds and registers a
@@ -685,11 +496,10 @@ void omap_device_delete(struct omap_device *od)
* information. Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise,
* passes along the return value of omap_device_build_ss().
*/
-struct platform_device __init *omap_device_build(const char *pdev_name, int pdev_id,
- struct omap_hwmod *oh, void *pdata,
- int pdata_len,
- struct omap_device_pm_latency *pm_lats,
- int pm_lats_cnt, int is_early_device)
+struct platform_device __init *omap_device_build(const char *pdev_name,
+ int pdev_id,
+ struct omap_hwmod *oh,
+ void *pdata, int pdata_len)
{
struct omap_hwmod *ohs[] = { oh };
@@ -697,8 +507,7 @@ struct platform_device __init *omap_device_build(const char *pdev_name, int pdev
return ERR_PTR(-EINVAL);
return omap_device_build_ss(pdev_name, pdev_id, ohs, 1, pdata,
- pdata_len, pm_lats, pm_lats_cnt,
- is_early_device);
+ pdata_len);
}
/**
@@ -708,9 +517,6 @@ struct platform_device __init *omap_device_build(const char *pdev_name, int pdev
* @oh: ptr to the single omap_hwmod that backs this omap_device
* @pdata: platform_data ptr to associate with the platform_device
* @pdata_len: amount of memory pointed to by @pdata
- * @pm_lats: pointer to a omap_device_pm_latency array for this device
- * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats
- * @is_early_device: should the device be registered as an early device or not
*
* Convenience function for building and registering an omap_device
* subsystem record. Subsystem records consist of multiple
@@ -718,11 +524,11 @@ struct platform_device __init *omap_device_build(const char *pdev_name, int pdev
* platform_device record. Returns an ERR_PTR() on error, or passes
* along the return value of omap_device_register().
*/
-struct platform_device __init *omap_device_build_ss(const char *pdev_name, int pdev_id,
- struct omap_hwmod **ohs, int oh_cnt,
- void *pdata, int pdata_len,
- struct omap_device_pm_latency *pm_lats,
- int pm_lats_cnt, int is_early_device)
+struct platform_device __init *omap_device_build_ss(const char *pdev_name,
+ int pdev_id,
+ struct omap_hwmod **ohs,
+ int oh_cnt, void *pdata,
+ int pdata_len)
{
int ret = -ENOMEM;
struct platform_device *pdev;
@@ -746,7 +552,7 @@ struct platform_device __init *omap_device_build_ss(const char *pdev_name, int p
else
dev_set_name(&pdev->dev, "%s", pdev->name);
- od = omap_device_alloc(pdev, ohs, oh_cnt, pm_lats, pm_lats_cnt);
+ od = omap_device_alloc(pdev, ohs, oh_cnt);
if (IS_ERR(od))
goto odbs_exit1;
@@ -754,10 +560,7 @@ struct platform_device __init *omap_device_build_ss(const char *pdev_name, int p
if (ret)
goto odbs_exit2;
- if (is_early_device)
- ret = omap_early_device_register(pdev);
- else
- ret = omap_device_register(pdev);
+ ret = omap_device_register(pdev);
if (ret)
goto odbs_exit2;
@@ -774,24 +577,6 @@ odbs_exit:
return ERR_PTR(ret);
}
-/**
- * omap_early_device_register - register an omap_device as an early platform
- * device.
- * @od: struct omap_device * to register
- *
- * Register the omap_device structure. This currently just calls
- * platform_early_add_device() on the underlying platform_device.
- * Returns 0 by default.
- */
-static int __init omap_early_device_register(struct platform_device *pdev)
-{
- struct platform_device *devices[1];
-
- devices[0] = pdev;
- early_platform_add_devices(devices, 1);
- return 0;
-}
-
#ifdef CONFIG_PM_RUNTIME
static int _od_runtime_suspend(struct device *dev)
{
@@ -902,10 +687,9 @@ int omap_device_register(struct platform_device *pdev)
* to be accessible and ready to operate. This generally involves
* enabling clocks, setting SYSCONFIG registers; and in the future may
* involve remuxing pins. Device drivers should call this function
- * (through platform_data function pointers) where they would normally
- * enable clocks, etc. Returns -EINVAL if called when the omap_device
- * is already enabled, or passes along the return value of
- * _omap_device_activate().
+ * indirectly via pm_runtime_get*(). Returns -EINVAL if called when
+ * the omap_device is already enabled, or passes along the return
+ * value of _omap_device_enable_hwmods().
*/
int omap_device_enable(struct platform_device *pdev)
{
@@ -921,14 +705,8 @@ int omap_device_enable(struct platform_device *pdev)
return -EINVAL;
}
- /* Enable everything if we're enabling this device from scratch */
- if (od->_state == OMAP_DEVICE_STATE_UNKNOWN)
- od->pm_lat_level = od->pm_lats_cnt;
-
- ret = _omap_device_activate(od, IGNORE_WAKEUP_LAT);
+ ret = _omap_device_enable_hwmods(od);
- od->dev_wakeup_lat = 0;
- od->_dev_wakeup_lat_limit = UINT_MAX;
od->_state = OMAP_DEVICE_STATE_ENABLED;
return ret;
@@ -938,14 +716,10 @@ int omap_device_enable(struct platform_device *pdev)
* omap_device_idle - idle an omap_device
* @od: struct omap_device * to idle
*
- * Idle omap_device @od by calling as many .deactivate_func() entries
- * in the omap_device's pm_lats table as is possible without exceeding
- * the device's maximum wakeup latency limit, pm_lat_limit. Device
- * drivers should call this function (through platform_data function
- * pointers) where they would normally disable clocks after operations
- * complete, etc.. Returns -EINVAL if the omap_device is not
+ * Idle omap_device @od. Device drivers call this function indirectly
+ * via pm_runtime_put*(). Returns -EINVAL if the omap_device is not
* currently enabled, or passes along the return value of
- * _omap_device_deactivate().
+ * _omap_device_idle_hwmods().
*/
int omap_device_idle(struct platform_device *pdev)
{
@@ -961,7 +735,7 @@ int omap_device_idle(struct platform_device *pdev)
return -EINVAL;
}
- ret = _omap_device_deactivate(od, USE_WAKEUP_LAT);
+ ret = _omap_device_idle_hwmods(od);
od->_state = OMAP_DEVICE_STATE_IDLE;
@@ -969,42 +743,6 @@ int omap_device_idle(struct platform_device *pdev)
}
/**
- * omap_device_shutdown - shut down an omap_device
- * @od: struct omap_device * to shut down
- *
- * Shut down omap_device @od by calling all .deactivate_func() entries
- * in the omap_device's pm_lats table and then shutting down all of
- * the underlying omap_hwmods. Used when a device is being "removed"
- * or a device driver is being unloaded. Returns -EINVAL if the
- * omap_device is not currently enabled or idle, or passes along the
- * return value of _omap_device_deactivate().
- */
-int omap_device_shutdown(struct platform_device *pdev)
-{
- int ret, i;
- struct omap_device *od;
-
- od = to_omap_device(pdev);
-
- if (od->_state != OMAP_DEVICE_STATE_ENABLED &&
- od->_state != OMAP_DEVICE_STATE_IDLE) {
- dev_warn(&pdev->dev,
- "omap_device: %s() called from invalid state %d\n",
- __func__, od->_state);
- return -EINVAL;
- }
-
- ret = _omap_device_deactivate(od, IGNORE_WAKEUP_LAT);
-
- for (i = 0; i < od->hwmods_cnt; i++)
- omap_hwmod_shutdown(od->hwmods[i]);
-
- od->_state = OMAP_DEVICE_STATE_SHUTDOWN;
-
- return ret;
-}
-
-/**
* omap_device_assert_hardreset - set a device's hardreset line
* @pdev: struct platform_device * to reset
* @name: const char * name of the reset line
@@ -1060,86 +798,6 @@ int omap_device_deassert_hardreset(struct platform_device *pdev,
}
/**
- * omap_device_align_pm_lat - activate/deactivate device to match wakeup lat lim
- * @od: struct omap_device *
- *
- * When a device's maximum wakeup latency limit changes, call some of
- * the .activate_func or .deactivate_func function pointers in the
- * omap_device's pm_lats array to ensure that the device's maximum
- * wakeup latency is less than or equal to the new latency limit.
- * Intended to be called by OMAP PM code whenever a device's maximum
- * wakeup latency limit changes (e.g., via
- * omap_pm_set_dev_wakeup_lat()). Returns 0 if nothing needs to be
- * done (e.g., if the omap_device is not currently idle, or if the
- * wakeup latency is already current with the new limit) or passes
- * along the return value of _omap_device_deactivate() or
- * _omap_device_activate().
- */
-int omap_device_align_pm_lat(struct platform_device *pdev,
- u32 new_wakeup_lat_limit)
-{
- int ret = -EINVAL;
- struct omap_device *od;
-
- od = to_omap_device(pdev);
-
- if (new_wakeup_lat_limit == od->dev_wakeup_lat)
- return 0;
-
- od->_dev_wakeup_lat_limit = new_wakeup_lat_limit;
-
- if (od->_state != OMAP_DEVICE_STATE_IDLE)
- return 0;
- else if (new_wakeup_lat_limit > od->dev_wakeup_lat)
- ret = _omap_device_deactivate(od, USE_WAKEUP_LAT);
- else if (new_wakeup_lat_limit < od->dev_wakeup_lat)
- ret = _omap_device_activate(od, USE_WAKEUP_LAT);
-
- return ret;
-}
-
-/**
- * omap_device_get_pwrdm - return the powerdomain * associated with @od
- * @od: struct omap_device *
- *
- * Return the powerdomain associated with the first underlying
- * omap_hwmod for this omap_device. Intended for use by core OMAP PM
- * code. Returns NULL on error or a struct powerdomain * upon
- * success.
- */
-struct powerdomain *omap_device_get_pwrdm(struct omap_device *od)
-{
- /*
- * XXX Assumes that all omap_hwmod powerdomains are identical.
- * This may not necessarily be true. There should be a sanity
- * check in here to WARN() if any difference appears.
- */
- if (!od->hwmods_cnt)
- return NULL;
-
- return omap_hwmod_get_pwrdm(od->hwmods[0]);
-}
-
-/**
- * omap_device_get_mpu_rt_va - return the MPU's virtual addr for the hwmod base
- * @od: struct omap_device *
- *
- * Return the MPU's virtual address for the base of the hwmod, from
- * the ioremap() that the hwmod code does. Only valid if there is one
- * hwmod associated with this device. Returns NULL if there are zero
- * or more than one hwmods associated with this omap_device;
- * otherwise, passes along the return value from
- * omap_hwmod_get_mpu_rt_va().
- */
-void __iomem *omap_device_get_rt_va(struct omap_device *od)
-{
- if (od->hwmods_cnt != 1)
- return NULL;
-
- return omap_hwmod_get_mpu_rt_va(od->hwmods[0]);
-}
-
-/**
* omap_device_get_by_hwmod_name() - convert a hwmod name to
* device pointer.
* @oh_name: name of the hwmod device
@@ -1173,82 +831,6 @@ struct device *omap_device_get_by_hwmod_name(const char *oh_name)
return &oh->od->pdev->dev;
}
-EXPORT_SYMBOL(omap_device_get_by_hwmod_name);
-
-/*
- * Public functions intended for use in omap_device_pm_latency
- * .activate_func and .deactivate_func function pointers
- */
-
-/**
- * omap_device_enable_hwmods - call omap_hwmod_enable() on all hwmods
- * @od: struct omap_device *od
- *
- * Enable all underlying hwmods. Returns 0.
- */
-int omap_device_enable_hwmods(struct omap_device *od)
-{
- int i;
-
- for (i = 0; i < od->hwmods_cnt; i++)
- omap_hwmod_enable(od->hwmods[i]);
-
- /* XXX pass along return value here? */
- return 0;
-}
-
-/**
- * omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
- * @od: struct omap_device *od
- *
- * Idle all underlying hwmods. Returns 0.
- */
-int omap_device_idle_hwmods(struct omap_device *od)
-{
- int i;
-
- for (i = 0; i < od->hwmods_cnt; i++)
- omap_hwmod_idle(od->hwmods[i]);
-
- /* XXX pass along return value here? */
- return 0;
-}
-
-/**
- * omap_device_disable_clocks - disable all main and interface clocks
- * @od: struct omap_device *od
- *
- * Disable the main functional clock and interface clock for all of the
- * omap_hwmods associated with the omap_device. Returns 0.
- */
-int omap_device_disable_clocks(struct omap_device *od)
-{
- int i;
-
- for (i = 0; i < od->hwmods_cnt; i++)
- omap_hwmod_disable_clocks(od->hwmods[i]);
-
- /* XXX pass along return value here? */
- return 0;
-}
-
-/**
- * omap_device_enable_clocks - enable all main and interface clocks
- * @od: struct omap_device *od
- *
- * Enable the main functional clock and interface clock for all of the
- * omap_hwmods associated with the omap_device. Returns 0.
- */
-int omap_device_enable_clocks(struct omap_device *od)
-{
- int i;
-
- for (i = 0; i < od->hwmods_cnt; i++)
- omap_hwmod_enable_clocks(od->hwmods[i]);
-
- /* XXX pass along return value here? */
- return 0;
-}
static struct notifier_block platform_nb = {
.notifier_call = _omap_device_notifier_call,
@@ -1259,7 +841,7 @@ static int __init omap_device_init(void)
bus_register_notifier(&platform_bus_type, &platform_nb);
return 0;
}
-core_initcall(omap_device_init);
+omap_core_initcall(omap_device_init);
/**
* omap_device_late_idle - idle devices without drivers
@@ -1297,4 +879,4 @@ static int __init omap_device_late_init(void)
bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle);
return 0;
}
-late_initcall(omap_device_late_init);
+omap_late_initcall(omap_device_late_init);
diff --git a/arch/arm/mach-omap2/omap_device.h b/arch/arm/mach-omap2/omap_device.h
index 0933c599bf89..044c31d50e5b 100644
--- a/arch/arm/mach-omap2/omap_device.h
+++ b/arch/arm/mach-omap2/omap_device.h
@@ -13,20 +13,12 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Eventually this type of functionality should either be
- * a) implemented via arch-specific pointers in platform_device
- * or
- * b) implemented as a proper omap_bus/omap_device in Linux, no more
- * platform_device
+ * This type of functionality should be implemented as a proper
+ * omap_bus/omap_device in Linux.
*
* omap_device differs from omap_hwmod in that it includes external
* (e.g., board- and system-level) integration details. omap_hwmod
* stores hardware data that is invariant for a given OMAP chip.
- *
- * To do:
- * - GPIO integration
- * - regulator integration
- *
*/
#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_DEVICE_H
#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_DEVICE_H
@@ -45,19 +37,14 @@ extern struct dev_pm_domain omap_device_pm_domain;
#define OMAP_DEVICE_STATE_SHUTDOWN 3
/* omap_device.flags values */
-#define OMAP_DEVICE_SUSPENDED BIT(0)
-#define OMAP_DEVICE_NO_IDLE_ON_SUSPEND BIT(1)
+#define OMAP_DEVICE_SUSPENDED BIT(0)
+#define OMAP_DEVICE_NO_IDLE_ON_SUSPEND BIT(1)
/**
* struct omap_device - omap_device wrapper for platform_devices
* @pdev: platform_device
* @hwmods: (one .. many per omap_device)
* @hwmods_cnt: ARRAY_SIZE() of @hwmods
- * @pm_lats: ptr to an omap_device_pm_latency table
- * @pm_lats_cnt: ARRAY_SIZE() of what is passed to @pm_lats
- * @pm_lat_level: array index of the last odpl entry executed - -1 if never
- * @dev_wakeup_lat: dev wakeup latency in nanoseconds
- * @_dev_wakeup_lat_limit: dev wakeup latency limit in nsec - set by OMAP PM
* @_state: one of OMAP_DEVICE_STATE_* (see above)
* @flags: device flags
* @_driver_status: one of BUS_NOTIFY_*_DRIVER from <linux/device.h>
@@ -71,12 +58,7 @@ extern struct dev_pm_domain omap_device_pm_domain;
struct omap_device {
struct platform_device *pdev;
struct omap_hwmod **hwmods;
- struct omap_device_pm_latency *pm_lats;
- u32 dev_wakeup_lat;
- u32 _dev_wakeup_lat_limit;
unsigned long _driver_status;
- u8 pm_lats_cnt;
- s8 pm_lat_level;
u8 hwmods_cnt;
u8 _state;
u8 flags;
@@ -86,36 +68,25 @@ struct omap_device {
int omap_device_enable(struct platform_device *pdev);
int omap_device_idle(struct platform_device *pdev);
-int omap_device_shutdown(struct platform_device *pdev);
/* Core code interface */
struct platform_device *omap_device_build(const char *pdev_name, int pdev_id,
- struct omap_hwmod *oh, void *pdata,
- int pdata_len,
- struct omap_device_pm_latency *pm_lats,
- int pm_lats_cnt, int is_early_device);
+ struct omap_hwmod *oh, void *pdata,
+ int pdata_len);
struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
struct omap_hwmod **oh, int oh_cnt,
- void *pdata, int pdata_len,
- struct omap_device_pm_latency *pm_lats,
- int pm_lats_cnt, int is_early_device);
+ void *pdata, int pdata_len);
struct omap_device *omap_device_alloc(struct platform_device *pdev,
- struct omap_hwmod **ohs, int oh_cnt,
- struct omap_device_pm_latency *pm_lats,
- int pm_lats_cnt);
+ struct omap_hwmod **ohs, int oh_cnt);
void omap_device_delete(struct omap_device *od);
int omap_device_register(struct platform_device *pdev);
-void __iomem *omap_device_get_rt_va(struct omap_device *od);
struct device *omap_device_get_by_hwmod_name(const char *oh_name);
/* OMAP PM interface */
-int omap_device_align_pm_lat(struct platform_device *pdev,
- u32 new_wakeup_lat_limit);
-struct powerdomain *omap_device_get_pwrdm(struct omap_device *od);
int omap_device_get_context_loss_count(struct platform_device *pdev);
/* Other */
@@ -124,40 +95,6 @@ int omap_device_assert_hardreset(struct platform_device *pdev,
const char *name);
int omap_device_deassert_hardreset(struct platform_device *pdev,
const char *name);
-int omap_device_idle_hwmods(struct omap_device *od);
-int omap_device_enable_hwmods(struct omap_device *od);
-
-int omap_device_disable_clocks(struct omap_device *od);
-int omap_device_enable_clocks(struct omap_device *od);
-
-/*
- * Entries should be kept in latency order ascending
- *
- * deact_lat is the maximum number of microseconds required to complete
- * deactivate_func() at the device's slowest OPP.
- *
- * act_lat is the maximum number of microseconds required to complete
- * activate_func() at the device's slowest OPP.
- *
- * This will result in some suboptimal power management decisions at fast
- * OPPs, but avoids having to recompute all device power management decisions
- * if the system shifts from a fast OPP to a slow OPP (in order to meet
- * latency requirements).
- *
- * XXX should deactivate_func/activate_func() take platform_device pointers
- * rather than omap_device pointers?
- */
-struct omap_device_pm_latency {
- u32 deactivate_lat;
- u32 deactivate_lat_worst;
- int (*deactivate_func)(struct omap_device *od);
- u32 activate_lat;
- u32 activate_lat_worst;
- int (*activate_func)(struct omap_device *od);
- u32 flags;
-};
-
-#define OMAP_DEVICE_LATENCY_AUTO_ADJUST BIT(1)
/* Get omap_device pointer from platform_device pointer */
static inline struct omap_device *to_omap_device(struct platform_device *pdev)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 4653efb87a27..a8984989dec8 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -139,6 +139,8 @@
#include <linux/slab.h>
#include <linux/bootmem.h>
+#include <asm/system_misc.h>
+
#include "clock.h"
#include "omap_hwmod.h"
@@ -2134,6 +2136,8 @@ static int _enable(struct omap_hwmod *oh)
_enable_clocks(oh);
if (soc_ops.enable_module)
soc_ops.enable_module(oh);
+ if (oh->flags & HWMOD_BLOCK_WFI)
+ disable_hlt();
if (soc_ops.update_context_lost)
soc_ops.update_context_lost(oh);
@@ -2195,6 +2199,8 @@ static int _idle(struct omap_hwmod *oh)
_idle_sysc(oh);
_del_initiator_dep(oh, mpu_oh);
+ if (oh->flags & HWMOD_BLOCK_WFI)
+ enable_hlt();
if (soc_ops.disable_module)
soc_ops.disable_module(oh);
@@ -2303,6 +2309,8 @@ static int _shutdown(struct omap_hwmod *oh)
if (oh->_state == _HWMOD_STATE_ENABLED) {
_del_initiator_dep(oh, mpu_oh);
/* XXX what about the other system initiators here? dma, dsp */
+ if (oh->flags & HWMOD_BLOCK_WFI)
+ enable_hlt();
if (soc_ops.disable_module)
soc_ops.disable_module(oh);
_disable_clocks(oh);
@@ -3303,7 +3311,7 @@ static int __init omap_hwmod_setup_all(void)
return 0;
}
-core_initcall(omap_hwmod_setup_all);
+omap_core_initcall(omap_hwmod_setup_all);
/**
* omap_hwmod_enable - enable an omap_hwmod
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
index 3ae852a522f9..80c00e706d69 100644
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -451,6 +451,14 @@ struct omap_hwmod_omap4_prcm {
* enabled. This prevents the hwmod code from being able to
* enable and reset the IP block early. XXX Eventually it should
* be possible to query the clock framework for this information.
+ * HWMOD_BLOCK_WFI: Some OMAP peripherals apparently don't work
+ * correctly if the MPU is allowed to go idle while the
+ * peripherals are active. This is apparently true for the I2C on
+ * OMAP2420, and also the EMAC on AM3517/3505. It's unlikely that
+ * this is really true -- we're probably not configuring something
+ * correctly, or this is being abused to deal with some PM latency
+ * issues -- but we're currently suffering from a shortage of
+ * folks who are able to track these issues down properly.
*/
#define HWMOD_SWSUP_SIDLE (1 << 0)
#define HWMOD_SWSUP_MSTANDBY (1 << 1)
@@ -462,6 +470,7 @@ struct omap_hwmod_omap4_prcm {
#define HWMOD_CONTROL_OPT_CLKS_IN_RESET (1 << 7)
#define HWMOD_16BIT_REG (1 << 8)
#define HWMOD_EXT_OPT_MAIN_CLK (1 << 9)
+#define HWMOD_BLOCK_WFI (1 << 10)
/*
* omap_hwmod._int_flags definitions
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index b5efe58c0be0..6a764af6c6d3 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -121,7 +121,12 @@ static struct omap_hwmod omap2420_i2c1_hwmod = {
},
.class = &i2c_class,
.dev_attr = &i2c_dev_attr,
- .flags = HWMOD_16BIT_REG,
+ /*
+ * From mach-omap2/pm24xx.c: "Putting MPU into the WFI state
+ * while a transfer is active seems to cause the I2C block to
+ * timeout. Why? Good question."
+ */
+ .flags = (HWMOD_16BIT_REG | HWMOD_BLOCK_WFI),
};
/* I2C2 */
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 793f54ac7d14..7ec1083ff604 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -616,7 +616,7 @@ static struct omap_hwmod omap44xx_dmic_hwmod = {
.clkdm_name = "abe_clkdm",
.mpu_irqs = omap44xx_dmic_irqs,
.sdma_reqs = omap44xx_dmic_sdma_reqs,
- .main_clk = "dmic_fck",
+ .main_clk = "func_dmic_abe_gfclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_DMIC_CLKCTRL_OFFSET,
@@ -1161,7 +1161,7 @@ static struct omap_hwmod omap44xx_gpio1_hwmod = {
.class = &omap44xx_gpio_hwmod_class,
.clkdm_name = "l4_wkup_clkdm",
.mpu_irqs = omap44xx_gpio1_irqs,
- .main_clk = "gpio1_ick",
+ .main_clk = "l4_wkup_clk_mux_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_WKUP_GPIO1_CLKCTRL_OFFSET,
@@ -1190,7 +1190,7 @@ static struct omap_hwmod omap44xx_gpio2_hwmod = {
.clkdm_name = "l4_per_clkdm",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
.mpu_irqs = omap44xx_gpio2_irqs,
- .main_clk = "gpio2_ick",
+ .main_clk = "l4_div_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_GPIO2_CLKCTRL_OFFSET,
@@ -1219,7 +1219,7 @@ static struct omap_hwmod omap44xx_gpio3_hwmod = {
.clkdm_name = "l4_per_clkdm",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
.mpu_irqs = omap44xx_gpio3_irqs,
- .main_clk = "gpio3_ick",
+ .main_clk = "l4_div_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_GPIO3_CLKCTRL_OFFSET,
@@ -1248,7 +1248,7 @@ static struct omap_hwmod omap44xx_gpio4_hwmod = {
.clkdm_name = "l4_per_clkdm",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
.mpu_irqs = omap44xx_gpio4_irqs,
- .main_clk = "gpio4_ick",
+ .main_clk = "l4_div_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_GPIO4_CLKCTRL_OFFSET,
@@ -1277,7 +1277,7 @@ static struct omap_hwmod omap44xx_gpio5_hwmod = {
.clkdm_name = "l4_per_clkdm",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
.mpu_irqs = omap44xx_gpio5_irqs,
- .main_clk = "gpio5_ick",
+ .main_clk = "l4_div_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_GPIO5_CLKCTRL_OFFSET,
@@ -1306,7 +1306,7 @@ static struct omap_hwmod omap44xx_gpio6_hwmod = {
.clkdm_name = "l4_per_clkdm",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
.mpu_irqs = omap44xx_gpio6_irqs,
- .main_clk = "gpio6_ick",
+ .main_clk = "l4_div_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_GPIO6_CLKCTRL_OFFSET,
@@ -1405,7 +1405,7 @@ static struct omap_hwmod omap44xx_gpu_hwmod = {
.class = &omap44xx_gpu_hwmod_class,
.clkdm_name = "l3_gfx_clkdm",
.mpu_irqs = omap44xx_gpu_irqs,
- .main_clk = "gpu_fck",
+ .main_clk = "sgx_clk_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_GFX_GFX_CLKCTRL_OFFSET,
@@ -1446,7 +1446,7 @@ static struct omap_hwmod omap44xx_hdq1w_hwmod = {
.clkdm_name = "l4_per_clkdm",
.flags = HWMOD_INIT_NO_RESET, /* XXX temporary */
.mpu_irqs = omap44xx_hdq1w_irqs,
- .main_clk = "hdq1w_fck",
+ .main_clk = "func_12m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_HDQ1W_CLKCTRL_OFFSET,
@@ -1550,7 +1550,7 @@ static struct omap_hwmod omap44xx_i2c1_hwmod = {
.flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
.mpu_irqs = omap44xx_i2c1_irqs,
.sdma_reqs = omap44xx_i2c1_sdma_reqs,
- .main_clk = "i2c1_fck",
+ .main_clk = "func_96m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_I2C1_CLKCTRL_OFFSET,
@@ -1580,7 +1580,7 @@ static struct omap_hwmod omap44xx_i2c2_hwmod = {
.flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
.mpu_irqs = omap44xx_i2c2_irqs,
.sdma_reqs = omap44xx_i2c2_sdma_reqs,
- .main_clk = "i2c2_fck",
+ .main_clk = "func_96m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_I2C2_CLKCTRL_OFFSET,
@@ -1610,7 +1610,7 @@ static struct omap_hwmod omap44xx_i2c3_hwmod = {
.flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
.mpu_irqs = omap44xx_i2c3_irqs,
.sdma_reqs = omap44xx_i2c3_sdma_reqs,
- .main_clk = "i2c3_fck",
+ .main_clk = "func_96m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_I2C3_CLKCTRL_OFFSET,
@@ -1640,7 +1640,7 @@ static struct omap_hwmod omap44xx_i2c4_hwmod = {
.flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
.mpu_irqs = omap44xx_i2c4_irqs,
.sdma_reqs = omap44xx_i2c4_sdma_reqs,
- .main_clk = "i2c4_fck",
+ .main_clk = "func_96m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_I2C4_CLKCTRL_OFFSET,
@@ -1743,7 +1743,7 @@ static struct omap_hwmod omap44xx_iss_hwmod = {
.clkdm_name = "iss_clkdm",
.mpu_irqs = omap44xx_iss_irqs,
.sdma_reqs = omap44xx_iss_sdma_reqs,
- .main_clk = "iss_fck",
+ .main_clk = "ducati_clk_mux_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET,
@@ -1785,7 +1785,7 @@ static struct omap_hwmod omap44xx_iva_hwmod = {
.mpu_irqs = omap44xx_iva_irqs,
.rst_lines = omap44xx_iva_resets,
.rst_lines_cnt = ARRAY_SIZE(omap44xx_iva_resets),
- .main_clk = "iva_fck",
+ .main_clk = "dpll_iva_m5x2_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_IVAHD_IVAHD_CLKCTRL_OFFSET,
@@ -1829,7 +1829,7 @@ static struct omap_hwmod omap44xx_kbd_hwmod = {
.class = &omap44xx_kbd_hwmod_class,
.clkdm_name = "l4_wkup_clkdm",
.mpu_irqs = omap44xx_kbd_irqs,
- .main_clk = "kbd_fck",
+ .main_clk = "sys_32k_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_WKUP_KEYBOARD_CLKCTRL_OFFSET,
@@ -1920,7 +1920,7 @@ static struct omap_hwmod omap44xx_mcasp_hwmod = {
.clkdm_name = "abe_clkdm",
.mpu_irqs = omap44xx_mcasp_irqs,
.sdma_reqs = omap44xx_mcasp_sdma_reqs,
- .main_clk = "mcasp_fck",
+ .main_clk = "func_mcasp_abe_gfclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_MCASP_CLKCTRL_OFFSET,
@@ -1972,7 +1972,7 @@ static struct omap_hwmod omap44xx_mcbsp1_hwmod = {
.clkdm_name = "abe_clkdm",
.mpu_irqs = omap44xx_mcbsp1_irqs,
.sdma_reqs = omap44xx_mcbsp1_sdma_reqs,
- .main_clk = "mcbsp1_fck",
+ .main_clk = "func_mcbsp1_gfclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_MCBSP1_CLKCTRL_OFFSET,
@@ -2007,7 +2007,7 @@ static struct omap_hwmod omap44xx_mcbsp2_hwmod = {
.clkdm_name = "abe_clkdm",
.mpu_irqs = omap44xx_mcbsp2_irqs,
.sdma_reqs = omap44xx_mcbsp2_sdma_reqs,
- .main_clk = "mcbsp2_fck",
+ .main_clk = "func_mcbsp2_gfclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_MCBSP2_CLKCTRL_OFFSET,
@@ -2042,7 +2042,7 @@ static struct omap_hwmod omap44xx_mcbsp3_hwmod = {
.clkdm_name = "abe_clkdm",
.mpu_irqs = omap44xx_mcbsp3_irqs,
.sdma_reqs = omap44xx_mcbsp3_sdma_reqs,
- .main_clk = "mcbsp3_fck",
+ .main_clk = "func_mcbsp3_gfclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_MCBSP3_CLKCTRL_OFFSET,
@@ -2077,7 +2077,7 @@ static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_mcbsp4_irqs,
.sdma_reqs = omap44xx_mcbsp4_sdma_reqs,
- .main_clk = "mcbsp4_fck",
+ .main_clk = "per_mcbsp4_gfclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_MCBSP4_CLKCTRL_OFFSET,
@@ -2140,7 +2140,7 @@ static struct omap_hwmod omap44xx_mcpdm_hwmod = {
.flags = HWMOD_EXT_OPT_MAIN_CLK | HWMOD_SWSUP_SIDLE,
.mpu_irqs = omap44xx_mcpdm_irqs,
.sdma_reqs = omap44xx_mcpdm_sdma_reqs,
- .main_clk = "mcpdm_fck",
+ .main_clk = "pad_clks_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_PDM_CLKCTRL_OFFSET,
@@ -2201,7 +2201,7 @@ static struct omap_hwmod omap44xx_mcspi1_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_mcspi1_irqs,
.sdma_reqs = omap44xx_mcspi1_sdma_reqs,
- .main_clk = "mcspi1_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_MCSPI1_CLKCTRL_OFFSET,
@@ -2237,7 +2237,7 @@ static struct omap_hwmod omap44xx_mcspi2_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_mcspi2_irqs,
.sdma_reqs = omap44xx_mcspi2_sdma_reqs,
- .main_clk = "mcspi2_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_MCSPI2_CLKCTRL_OFFSET,
@@ -2273,7 +2273,7 @@ static struct omap_hwmod omap44xx_mcspi3_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_mcspi3_irqs,
.sdma_reqs = omap44xx_mcspi3_sdma_reqs,
- .main_clk = "mcspi3_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_MCSPI3_CLKCTRL_OFFSET,
@@ -2307,7 +2307,7 @@ static struct omap_hwmod omap44xx_mcspi4_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_mcspi4_irqs,
.sdma_reqs = omap44xx_mcspi4_sdma_reqs,
- .main_clk = "mcspi4_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_MCSPI4_CLKCTRL_OFFSET,
@@ -2363,7 +2363,7 @@ static struct omap_hwmod omap44xx_mmc1_hwmod = {
.clkdm_name = "l3_init_clkdm",
.mpu_irqs = omap44xx_mmc1_irqs,
.sdma_reqs = omap44xx_mmc1_sdma_reqs,
- .main_clk = "mmc1_fck",
+ .main_clk = "hsmmc1_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L3INIT_MMC1_CLKCTRL_OFFSET,
@@ -2392,7 +2392,7 @@ static struct omap_hwmod omap44xx_mmc2_hwmod = {
.clkdm_name = "l3_init_clkdm",
.mpu_irqs = omap44xx_mmc2_irqs,
.sdma_reqs = omap44xx_mmc2_sdma_reqs,
- .main_clk = "mmc2_fck",
+ .main_clk = "hsmmc2_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L3INIT_MMC2_CLKCTRL_OFFSET,
@@ -2420,7 +2420,7 @@ static struct omap_hwmod omap44xx_mmc3_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_mmc3_irqs,
.sdma_reqs = omap44xx_mmc3_sdma_reqs,
- .main_clk = "mmc3_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_MMCSD3_CLKCTRL_OFFSET,
@@ -2448,7 +2448,7 @@ static struct omap_hwmod omap44xx_mmc4_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_mmc4_irqs,
.sdma_reqs = omap44xx_mmc4_sdma_reqs,
- .main_clk = "mmc4_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_MMCSD4_CLKCTRL_OFFSET,
@@ -2476,7 +2476,7 @@ static struct omap_hwmod omap44xx_mmc5_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_mmc5_irqs,
.sdma_reqs = omap44xx_mmc5_sdma_reqs,
- .main_clk = "mmc5_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_MMCSD5_CLKCTRL_OFFSET,
@@ -2702,13 +2702,6 @@ static struct resource omap44xx_usb_phy_and_pll_addrs[] = {
.end = 0x4a0ae000,
.flags = IORESOURCE_MEM,
},
- {
- /* XXX: Remove this once control module driver is in place */
- .name = "ctrl_dev",
- .start = 0x4a002300,
- .end = 0x4a002303,
- .flags = IORESOURCE_MEM,
- },
{ }
};
@@ -2725,7 +2718,7 @@ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
.name = "ocp2scp_usb_phy",
.class = &omap44xx_ocp2scp_hwmod_class,
.clkdm_name = "l3_init_clkdm",
- .main_clk = "ocp2scp_usb_phy_phy_48m",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL_OFFSET,
@@ -3162,7 +3155,7 @@ static struct omap_hwmod omap44xx_timer1_hwmod = {
.clkdm_name = "l4_wkup_clkdm",
.flags = HWMOD_SET_DEFAULT_CLOCKACT,
.mpu_irqs = omap44xx_timer1_irqs,
- .main_clk = "timer1_fck",
+ .main_clk = "dmt1_clk_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_WKUP_TIMER1_CLKCTRL_OFFSET,
@@ -3185,7 +3178,7 @@ static struct omap_hwmod omap44xx_timer2_hwmod = {
.clkdm_name = "l4_per_clkdm",
.flags = HWMOD_SET_DEFAULT_CLOCKACT,
.mpu_irqs = omap44xx_timer2_irqs,
- .main_clk = "timer2_fck",
+ .main_clk = "cm2_dm2_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER2_CLKCTRL_OFFSET,
@@ -3206,7 +3199,7 @@ static struct omap_hwmod omap44xx_timer3_hwmod = {
.class = &omap44xx_timer_hwmod_class,
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_timer3_irqs,
- .main_clk = "timer3_fck",
+ .main_clk = "cm2_dm3_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER3_CLKCTRL_OFFSET,
@@ -3227,7 +3220,7 @@ static struct omap_hwmod omap44xx_timer4_hwmod = {
.class = &omap44xx_timer_hwmod_class,
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_timer4_irqs,
- .main_clk = "timer4_fck",
+ .main_clk = "cm2_dm4_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER4_CLKCTRL_OFFSET,
@@ -3248,7 +3241,7 @@ static struct omap_hwmod omap44xx_timer5_hwmod = {
.class = &omap44xx_timer_hwmod_class,
.clkdm_name = "abe_clkdm",
.mpu_irqs = omap44xx_timer5_irqs,
- .main_clk = "timer5_fck",
+ .main_clk = "timer5_sync_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_TIMER5_CLKCTRL_OFFSET,
@@ -3270,8 +3263,7 @@ static struct omap_hwmod omap44xx_timer6_hwmod = {
.class = &omap44xx_timer_hwmod_class,
.clkdm_name = "abe_clkdm",
.mpu_irqs = omap44xx_timer6_irqs,
-
- .main_clk = "timer6_fck",
+ .main_clk = "timer6_sync_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_TIMER6_CLKCTRL_OFFSET,
@@ -3293,7 +3285,7 @@ static struct omap_hwmod omap44xx_timer7_hwmod = {
.class = &omap44xx_timer_hwmod_class,
.clkdm_name = "abe_clkdm",
.mpu_irqs = omap44xx_timer7_irqs,
- .main_clk = "timer7_fck",
+ .main_clk = "timer7_sync_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_TIMER7_CLKCTRL_OFFSET,
@@ -3315,7 +3307,7 @@ static struct omap_hwmod omap44xx_timer8_hwmod = {
.class = &omap44xx_timer_hwmod_class,
.clkdm_name = "abe_clkdm",
.mpu_irqs = omap44xx_timer8_irqs,
- .main_clk = "timer8_fck",
+ .main_clk = "timer8_sync_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_TIMER8_CLKCTRL_OFFSET,
@@ -3337,7 +3329,7 @@ static struct omap_hwmod omap44xx_timer9_hwmod = {
.class = &omap44xx_timer_hwmod_class,
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_timer9_irqs,
- .main_clk = "timer9_fck",
+ .main_clk = "cm2_dm9_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER9_CLKCTRL_OFFSET,
@@ -3360,7 +3352,7 @@ static struct omap_hwmod omap44xx_timer10_hwmod = {
.clkdm_name = "l4_per_clkdm",
.flags = HWMOD_SET_DEFAULT_CLOCKACT,
.mpu_irqs = omap44xx_timer10_irqs,
- .main_clk = "timer10_fck",
+ .main_clk = "cm2_dm10_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER10_CLKCTRL_OFFSET,
@@ -3382,7 +3374,7 @@ static struct omap_hwmod omap44xx_timer11_hwmod = {
.class = &omap44xx_timer_hwmod_class,
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_timer11_irqs,
- .main_clk = "timer11_fck",
+ .main_clk = "cm2_dm11_mux",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_DMTIMER11_CLKCTRL_OFFSET,
@@ -3433,7 +3425,7 @@ static struct omap_hwmod omap44xx_uart1_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_uart1_irqs,
.sdma_reqs = omap44xx_uart1_sdma_reqs,
- .main_clk = "uart1_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_UART1_CLKCTRL_OFFSET,
@@ -3461,7 +3453,7 @@ static struct omap_hwmod omap44xx_uart2_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_uart2_irqs,
.sdma_reqs = omap44xx_uart2_sdma_reqs,
- .main_clk = "uart2_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_UART2_CLKCTRL_OFFSET,
@@ -3490,7 +3482,7 @@ static struct omap_hwmod omap44xx_uart3_hwmod = {
.flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
.mpu_irqs = omap44xx_uart3_irqs,
.sdma_reqs = omap44xx_uart3_sdma_reqs,
- .main_clk = "uart3_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_UART3_CLKCTRL_OFFSET,
@@ -3518,7 +3510,7 @@ static struct omap_hwmod omap44xx_uart4_hwmod = {
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_uart4_irqs,
.sdma_reqs = omap44xx_uart4_sdma_reqs,
- .main_clk = "uart4_fck",
+ .main_clk = "func_48m_fclk",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L4PER_UART4_CLKCTRL_OFFSET,
@@ -3797,7 +3789,7 @@ static struct omap_hwmod omap44xx_wd_timer2_hwmod = {
.class = &omap44xx_wd_timer_hwmod_class,
.clkdm_name = "l4_wkup_clkdm",
.mpu_irqs = omap44xx_wd_timer2_irqs,
- .main_clk = "wd_timer2_fck",
+ .main_clk = "sys_32k_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_WKUP_WDT2_CLKCTRL_OFFSET,
@@ -3818,7 +3810,7 @@ static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
.class = &omap44xx_wd_timer_hwmod_class,
.clkdm_name = "abe_clkdm",
.mpu_irqs = omap44xx_wd_timer3_irqs,
- .main_clk = "wd_timer3_fck",
+ .main_clk = "sys_32k_ck",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET,
@@ -6156,12 +6148,6 @@ static struct omap_hwmod_addr_space omap44xx_usb_otg_hs_addrs[] = {
.pa_end = 0x4a0ab7ff,
.flags = ADDR_TYPE_RT
},
- {
- /* XXX: Remove this once control module driver is in place */
- .pa_start = 0x4a00233c,
- .pa_end = 0x4a00233f,
- .flags = ADDR_TYPE_RT
- },
{ }
};
diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c
index e237602e10ea..eb8a25de67ed 100644
--- a/arch/arm/mach-omap2/omap_phy_internal.c
+++ b/arch/arm/mach-omap2/omap_phy_internal.c
@@ -63,7 +63,7 @@ static int __init omap4430_phy_power_down(void)
return 0;
}
-early_initcall(omap4430_phy_power_down);
+omap_early_initcall(omap4430_phy_power_down);
void am35x_musb_reset(void)
{
diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c
index 62772e0e0d69..fc67add76444 100644
--- a/arch/arm/mach-omap2/opp3xxx_data.c
+++ b/arch/arm/mach-omap2/opp3xxx_data.c
@@ -168,4 +168,4 @@ int __init omap3_opp_init(void)
return r;
}
-device_initcall(omap3_opp_init);
+omap_device_initcall(omap3_opp_init);
diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c
index d470b728e720..1ef7a3e5ce4a 100644
--- a/arch/arm/mach-omap2/opp4xxx_data.c
+++ b/arch/arm/mach-omap2/opp4xxx_data.c
@@ -177,4 +177,4 @@ int __init omap4_opp_init(void)
ARRAY_SIZE(omap446x_opp_def_list));
return r;
}
-device_initcall(omap4_opp_init);
+omap_device_initcall(omap4_opp_init);
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index e2c291f52f92..1edd000a8143 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -83,10 +83,8 @@ static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
strncmp(clkdm->name, "dpll", 4) == 0)
return 0;
- seq_printf(s, "%s->%s (%d)", clkdm->name,
- clkdm->pwrdm.ptr->name,
- atomic_read(&clkdm->usecount));
- seq_printf(s, "\n");
+ seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name,
+ clkdm->usecount);
return 0;
}
@@ -279,6 +277,6 @@ static int __init pm_dbg_init(void)
return 0;
}
-arch_initcall(pm_dbg_init);
+omap_arch_initcall(pm_dbg_init);
#endif
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index f4b3143a8b1d..cd6682df5625 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -32,8 +32,6 @@
#include "pm.h"
#include "twl-common.h"
-static struct omap_device_pm_latency *pm_lats;
-
/*
* omap_pm_suspend: points to a function that does the SoC-specific
* suspend work
@@ -82,7 +80,7 @@ static int __init _init_omap_device(char *name)
__func__, name))
return -ENODEV;
- pdev = omap_device_build(oh->name, 0, oh, NULL, 0, pm_lats, 0, false);
+ pdev = omap_device_build(oh->name, 0, oh, NULL, 0);
if (WARN(IS_ERR(pdev), "%s: could not build omap_device for %s\n",
__func__, name))
return -ENODEV;
@@ -108,80 +106,19 @@ static void __init omap2_init_processor_devices(void)
}
}
-/* Types of sleep_switch used in omap_set_pwrdm_state */
-#define FORCEWAKEUP_SWITCH 0
-#define LOWPOWERSTATE_SWITCH 1
-
int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
{
+ /* XXX The usecount test is racy */
if ((clkdm->flags & CLKDM_CAN_ENABLE_AUTO) &&
!(clkdm->flags & CLKDM_MISSING_IDLE_REPORTING))
clkdm_allow_idle(clkdm);
else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
- atomic_read(&clkdm->usecount) == 0)
+ clkdm->usecount == 0)
clkdm_sleep(clkdm);
return 0;
}
/*
- * This sets pwrdm state (other than mpu & core. Currently only ON &
- * RET are supported.
- */
-int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
-{
- u8 curr_pwrst, next_pwrst;
- int sleep_switch = -1, ret = 0, hwsup = 0;
-
- if (!pwrdm || IS_ERR(pwrdm))
- return -EINVAL;
-
- while (!(pwrdm->pwrsts & (1 << pwrst))) {
- if (pwrst == PWRDM_POWER_OFF)
- return ret;
- pwrst--;
- }
-
- next_pwrst = pwrdm_read_next_pwrst(pwrdm);
- if (next_pwrst == pwrst)
- return ret;
-
- curr_pwrst = pwrdm_read_pwrst(pwrdm);
- if (curr_pwrst < PWRDM_POWER_ON) {
- if ((curr_pwrst > pwrst) &&
- (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
- sleep_switch = LOWPOWERSTATE_SWITCH;
- } else {
- hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
- clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
- sleep_switch = FORCEWAKEUP_SWITCH;
- }
- }
-
- ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
- if (ret)
- pr_err("%s: unable to set power state of powerdomain: %s\n",
- __func__, pwrdm->name);
-
- switch (sleep_switch) {
- case FORCEWAKEUP_SWITCH:
- if (hwsup)
- clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
- else
- clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
- break;
- case LOWPOWERSTATE_SWITCH:
- pwrdm_set_lowpwrstchange(pwrdm);
- pwrdm_wait_transition(pwrdm);
- pwrdm_state_switch(pwrdm);
- break;
- }
-
- return ret;
-}
-
-
-
-/*
* This API is to be called during init to set the various voltage
* domains to the voltage as per the opp table. Typically we boot up
* at the nominal voltage. So this function finds out the rate of
@@ -336,7 +273,7 @@ static int __init omap2_common_pm_init(void)
return 0;
}
-postcore_initcall(omap2_common_pm_init);
+omap_postcore_initcall(omap2_common_pm_init);
int __init omap2_common_pm_late_init(void)
{
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index c22503b17abd..7bdd22afce69 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -33,7 +33,6 @@ static inline int omap4_idle_init(void)
extern void *omap3_secure_ram_storage;
extern void omap3_pm_off_mode_enable(int);
extern void omap_sram_idle(void);
-extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused);
extern int (*omap_pm_suspend)(void);
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index c333fa6dffa8..b2a4df623545 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -90,11 +90,7 @@ static int omap2_enter_full_retention(void)
omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
- /*
- * Set MPU powerdomain's next power state to RETENTION;
- * preserve logic state during retention
- */
- pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+ pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
/* Workaround to kill USB */
@@ -137,15 +133,10 @@ no_sleep:
/* Mask future PRCM-to-MPU interrupts */
omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
- return 0;
-}
-
-static int omap2_i2c_active(void)
-{
- u32 l;
+ pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
+ pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON);
- l = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
- return l & (OMAP2420_EN_I2C2_MASK | OMAP2420_EN_I2C1_MASK);
+ return 0;
}
static int sti_console_enabled;
@@ -172,11 +163,6 @@ static int omap2_allow_mpu_retention(void)
static void omap2_enter_mpu_retention(void)
{
- /* Putting MPU into the WFI state while a transfer is active
- * seems to cause the I2C block to timeout. Why? Good question. */
- if (omap2_i2c_active())
- return;
-
/* The peripherals seem not to be able to wake up the MPU when
* it is in retention mode. */
if (omap2_allow_mpu_retention()) {
@@ -186,17 +172,16 @@ static void omap2_enter_mpu_retention(void)
omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
/* Try to enter MPU retention */
- omap2_prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
- OMAP_LOGICRETSTATE_MASK,
- MPU_MOD, OMAP2_PM_PWSTCTRL);
+ pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
} else {
/* Block MPU retention */
-
- omap2_prm_write_mod_reg(OMAP_LOGICRETSTATE_MASK, MPU_MOD,
- OMAP2_PM_PWSTCTRL);
+ pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
}
omap2_sram_idle();
+
+ pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
}
static int omap2_can_sleep(void)
@@ -251,25 +236,17 @@ static void __init prcm_setup_regs(void)
for (i = 0; i < num_mem_banks; i++)
pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
- /* Set CORE powerdomain's next power state to RETENTION */
- pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
+ pwrdm_set_logic_retst(core_pwrdm, PWRDM_POWER_RET);
- /*
- * Set MPU powerdomain's next power state to RETENTION;
- * preserve logic state during retention
- */
pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
- pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
/* Force-power down DSP, GFX powerdomains */
pwrdm = clkdm_get_pwrdm(dsp_clkdm);
pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
- clkdm_sleep(dsp_clkdm);
pwrdm = clkdm_get_pwrdm(gfx_clkdm);
pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
- clkdm_sleep(gfx_clkdm);
/* Enable hardware-supervised idle for all clkdms */
clkdm_for_each(omap_pm_clkdms_setup, NULL);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 7be3622cfc85..2d93d8b23835 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -351,12 +351,10 @@ static void omap3_pm_idle(void)
if (omap_irq_pending())
goto out;
- trace_power_start(POWER_CSTATE, 1, smp_processor_id());
trace_cpu_idle(1, smp_processor_id());
omap_sram_idle();
- trace_power_end(smp_processor_id());
trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
out:
diff --git a/arch/arm/mach-omap2/pmu.c b/arch/arm/mach-omap2/pmu.c
index eb78ae7a3464..9debf822687c 100644
--- a/arch/arm/mach-omap2/pmu.c
+++ b/arch/arm/mach-omap2/pmu.c
@@ -48,8 +48,7 @@ static int __init omap2_init_pmu(unsigned oh_num, char *oh_names[])
}
}
- omap_pmu_dev = omap_device_build_ss(dev_name, -1, oh, oh_num, NULL, 0,
- NULL, 0, 0);
+ omap_pmu_dev = omap_device_build_ss(dev_name, -1, oh, oh_num, NULL, 0);
WARN(IS_ERR(omap_pmu_dev), "Can't build omap_device for %s.\n",
dev_name);
@@ -89,4 +88,4 @@ static int __init omap_init_pmu(void)
return omap2_init_pmu(oh_num, oh_names);
}
-subsys_initcall(omap_init_pmu);
+omap_subsys_initcall(omap_init_pmu);
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index dea62a9aad07..8e61d80bf6b3 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -19,6 +19,7 @@
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/spinlock.h>
#include <trace/events/power.h>
#include "cm2xxx_3xxx.h"
@@ -42,6 +43,16 @@ enum {
PWRDM_STATE_PREV,
};
+/*
+ * Types of sleep_switch used internally in omap_set_pwrdm_state()
+ * and its associated static functions
+ *
+ * XXX Better documentation is needed here
+ */
+#define ALREADYACTIVE_SWITCH 0
+#define FORCEWAKEUP_SWITCH 1
+#define LOWPOWERSTATE_SWITCH 2
+#define ERROR_SWITCH 3
/* pwrdm_list contains all registered struct powerdomains */
static LIST_HEAD(pwrdm_list);
@@ -101,6 +112,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
pwrdm->voltdm.ptr = voltdm;
INIT_LIST_HEAD(&pwrdm->voltdm_node);
voltdm_add_pwrdm(voltdm, pwrdm);
+ spin_lock_init(&pwrdm->_lock);
list_add(&pwrdm->node, &pwrdm_list);
@@ -112,7 +124,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
for (i = 0; i < pwrdm->banks; i++)
pwrdm->ret_mem_off_counter[i] = 0;
- pwrdm_wait_transition(pwrdm);
+ arch_pwrdm->pwrdm_wait_transition(pwrdm);
pwrdm->state = pwrdm_read_pwrst(pwrdm);
pwrdm->state_counter[pwrdm->state] = 1;
@@ -143,7 +155,7 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm)
static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
{
- int prev, state, trace_state = 0;
+ int prev, next, state, trace_state = 0;
if (pwrdm == NULL)
return -EINVAL;
@@ -164,9 +176,10 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
* If the power domain did not hit the desired state,
* generate a trace event with both the desired and hit states
*/
- if (state != prev) {
+ next = pwrdm_read_next_pwrst(pwrdm);
+ if (next != prev) {
trace_state = (PWRDM_TRACE_STATES_FLAG |
- ((state & OMAP_POWERSTATE_MASK) << 8) |
+ ((next & OMAP_POWERSTATE_MASK) << 8) |
((prev & OMAP_POWERSTATE_MASK) << 0));
trace_power_domain_target(pwrdm->name, trace_state,
smp_processor_id());
@@ -199,6 +212,80 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
return 0;
}
+/**
+ * _pwrdm_save_clkdm_state_and_activate - prepare for power state change
+ * @pwrdm: struct powerdomain * to operate on
+ * @curr_pwrst: current power state of @pwrdm
+ * @pwrst: power state to switch to
+ * @hwsup: ptr to a bool to return whether the clkdm is hardware-supervised
+ *
+ * Determine whether the powerdomain needs to be turned on before
+ * attempting to switch power states. Called by
+ * omap_set_pwrdm_state(). NOTE that if the powerdomain contains
+ * multiple clockdomains, this code assumes that the first clockdomain
+ * supports software-supervised wakeup mode - potentially a problem.
+ * Returns the power state switch mode currently in use (see the
+ * "Types of sleep_switch" comment above).
+ */
+static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm,
+ u8 curr_pwrst, u8 pwrst,
+ bool *hwsup)
+{
+ u8 sleep_switch;
+
+ if (curr_pwrst < 0) {
+ WARN_ON(1);
+ sleep_switch = ERROR_SWITCH;
+ } else if (curr_pwrst < PWRDM_POWER_ON) {
+ if (curr_pwrst > pwrst &&
+ pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
+ arch_pwrdm->pwrdm_set_lowpwrstchange) {
+ sleep_switch = LOWPOWERSTATE_SWITCH;
+ } else {
+ *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
+ clkdm_wakeup_nolock(pwrdm->pwrdm_clkdms[0]);
+ sleep_switch = FORCEWAKEUP_SWITCH;
+ }
+ } else {
+ sleep_switch = ALREADYACTIVE_SWITCH;
+ }
+
+ return sleep_switch;
+}
+
+/**
+ * _pwrdm_restore_clkdm_state - restore the clkdm hwsup state after pwrst change
+ * @pwrdm: struct powerdomain * to operate on
+ * @sleep_switch: return value from _pwrdm_save_clkdm_state_and_activate()
+ * @hwsup: should @pwrdm's first clockdomain be set to hardware-supervised mode?
+ *
+ * Restore the clockdomain state perturbed by
+ * _pwrdm_save_clkdm_state_and_activate(), and call the power state
+ * bookkeeping code. Called by omap_set_pwrdm_state(). NOTE that if
+ * the powerdomain contains multiple clockdomains, this assumes that
+ * the first associated clockdomain supports either
+ * hardware-supervised idle control in the register, or
+ * software-supervised sleep. No return value.
+ */
+static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm,
+ u8 sleep_switch, bool hwsup)
+{
+ switch (sleep_switch) {
+ case FORCEWAKEUP_SWITCH:
+ if (hwsup)
+ clkdm_allow_idle_nolock(pwrdm->pwrdm_clkdms[0]);
+ else
+ clkdm_sleep_nolock(pwrdm->pwrdm_clkdms[0]);
+ break;
+ case LOWPOWERSTATE_SWITCH:
+ if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
+ arch_pwrdm->pwrdm_set_lowpwrstchange)
+ arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
+ pwrdm_state_switch_nolock(pwrdm);
+ break;
+ }
+}
+
/* Public functions */
/**
@@ -275,6 +362,30 @@ int pwrdm_complete_init(void)
}
/**
+ * pwrdm_lock - acquire a Linux spinlock on a powerdomain
+ * @pwrdm: struct powerdomain * to lock
+ *
+ * Acquire the powerdomain spinlock on @pwrdm. No return value.
+ */
+void pwrdm_lock(struct powerdomain *pwrdm)
+ __acquires(&pwrdm->_lock)
+{
+ spin_lock_irqsave(&pwrdm->_lock, pwrdm->_lock_flags);
+}
+
+/**
+ * pwrdm_unlock - release a Linux spinlock on a powerdomain
+ * @pwrdm: struct powerdomain * to unlock
+ *
+ * Release the powerdomain spinlock on @pwrdm. No return value.
+ */
+void pwrdm_unlock(struct powerdomain *pwrdm)
+ __releases(&pwrdm->_lock)
+{
+ spin_unlock_irqrestore(&pwrdm->_lock, pwrdm->_lock_flags);
+}
+
+/**
* pwrdm_lookup - look up a powerdomain by name, return a pointer
* @name: name of powerdomain
*
@@ -920,65 +1031,27 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
}
-/**
- * pwrdm_set_lowpwrstchange - Request a low power state change
- * @pwrdm: struct powerdomain *
- *
- * Allows a powerdomain to transtion to a lower power sleep state
- * from an existing sleep state without waking up the powerdomain.
- * Returns -EINVAL if the powerdomain pointer is null or if the
- * powerdomain does not support LOWPOWERSTATECHANGE, or returns 0
- * upon success.
- */
-int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
-{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return -EINVAL;
-
- if (!(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE))
- return -EINVAL;
-
- pr_debug("powerdomain: %s: setting LOWPOWERSTATECHANGE bit\n",
- pwrdm->name);
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_set_lowpwrstchange)
- ret = arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
-
- return ret;
-}
-
-/**
- * pwrdm_wait_transition - wait for powerdomain power transition to finish
- * @pwrdm: struct powerdomain * to wait for
- *
- * If the powerdomain @pwrdm is in the process of a state transition,
- * spin until it completes the power transition, or until an iteration
- * bailout value is reached. Returns -EINVAL if the powerdomain
- * pointer is null, -EAGAIN if the bailout value was reached, or
- * returns 0 upon success.
- */
-int pwrdm_wait_transition(struct powerdomain *pwrdm)
+int pwrdm_state_switch_nolock(struct powerdomain *pwrdm)
{
- int ret = -EINVAL;
+ int ret;
- if (!pwrdm)
+ if (!pwrdm || !arch_pwrdm)
return -EINVAL;
- if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition)
- ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
+ ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
+ if (!ret)
+ ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
return ret;
}
-int pwrdm_state_switch(struct powerdomain *pwrdm)
+int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm)
{
int ret;
- ret = pwrdm_wait_transition(pwrdm);
- if (!ret)
- ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
+ pwrdm_lock(pwrdm);
+ ret = pwrdm_state_switch_nolock(pwrdm);
+ pwrdm_unlock(pwrdm);
return ret;
}
@@ -1004,6 +1077,61 @@ int pwrdm_post_transition(struct powerdomain *pwrdm)
}
/**
+ * omap_set_pwrdm_state - change a powerdomain's current power state
+ * @pwrdm: struct powerdomain * to change the power state of
+ * @pwrst: power state to change to
+ *
+ * Change the current hardware power state of the powerdomain
+ * represented by @pwrdm to the power state represented by @pwrst.
+ * Returns -EINVAL if @pwrdm is null or invalid or if the
+ * powerdomain's current power state could not be read, or returns 0
+ * upon success or if @pwrdm does not support @pwrst or any
+ * lower-power state. XXX Should not return 0 if the @pwrdm does not
+ * support @pwrst or any lower-power state: this should be an error.
+ */
+int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst)
+{
+ u8 curr_pwrst, next_pwrst, sleep_switch;
+ int ret = 0;
+ bool hwsup = false;
+
+ if (!pwrdm || IS_ERR(pwrdm))
+ return -EINVAL;
+
+ while (!(pwrdm->pwrsts & (1 << pwrst))) {
+ if (pwrst == PWRDM_POWER_OFF)
+ return ret;
+ pwrst--;
+ }
+
+ pwrdm_lock(pwrdm);
+
+ curr_pwrst = pwrdm_read_pwrst(pwrdm);
+ next_pwrst = pwrdm_read_next_pwrst(pwrdm);
+ if (curr_pwrst == pwrst && next_pwrst == pwrst)
+ goto osps_out;
+
+ sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst,
+ pwrst, &hwsup);
+ if (sleep_switch == ERROR_SWITCH) {
+ ret = -EINVAL;
+ goto osps_out;
+ }
+
+ ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+ if (ret)
+ pr_err("%s: unable to set power state of powerdomain: %s\n",
+ __func__, pwrdm->name);
+
+ _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);
+
+osps_out:
+ pwrdm_unlock(pwrdm);
+
+ return ret;
+}
+
+/**
* pwrdm_get_context_loss_count - get powerdomain's context loss count
* @pwrdm: struct powerdomain * to wait for
*
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 5277d56eb37f..140c36074fed 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -19,8 +19,7 @@
#include <linux/types.h>
#include <linux/list.h>
-
-#include <linux/atomic.h>
+#include <linux/spinlock.h>
#include "voltage.h"
@@ -44,18 +43,20 @@
#define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON)
-/* Powerdomain flags */
-#define PWRDM_HAS_HDWR_SAR (1 << 0) /* hardware save-and-restore support */
-#define PWRDM_HAS_MPU_QUIRK (1 << 1) /* MPU pwr domain has MEM bank 0 bits
- * in MEM bank 1 position. This is
- * true for OMAP3430
- */
-#define PWRDM_HAS_LOWPOWERSTATECHANGE (1 << 2) /*
- * support to transition from a
- * sleep state to a lower sleep
- * state without waking up the
- * powerdomain
- */
+/*
+ * Powerdomain flags (struct powerdomain.flags)
+ *
+ * PWRDM_HAS_HDWR_SAR - powerdomain has hardware save-and-restore support
+ *
+ * PWRDM_HAS_MPU_QUIRK - MPU pwr domain has MEM bank 0 bits in MEM
+ * bank 1 position. This is true for OMAP3430
+ *
+ * PWRDM_HAS_LOWPOWERSTATECHANGE - can transition from a sleep state
+ * to a lower sleep state without waking up the powerdomain
+ */
+#define PWRDM_HAS_HDWR_SAR BIT(0)
+#define PWRDM_HAS_MPU_QUIRK BIT(1)
+#define PWRDM_HAS_LOWPOWERSTATECHANGE BIT(2)
/*
* Number of memory banks that are power-controllable. On OMAP4430, the
@@ -103,6 +104,8 @@ struct powerdomain;
* @state_counter:
* @timer:
* @state_timer:
+ * @_lock: spinlock used to serialize powerdomain and some clockdomain ops
+ * @_lock_flags: stored flags when @_lock is taken
*
* @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
*/
@@ -127,7 +130,8 @@ struct powerdomain {
unsigned state_counter[PWRDM_MAX_PWRSTS];
unsigned ret_logic_off_counter;
unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS];
-
+ spinlock_t _lock;
+ unsigned long _lock_flags;
const u8 pwrstctrl_offs;
const u8 pwrstst_offs;
const u32 logicretstate_mask;
@@ -162,6 +166,16 @@ struct powerdomain {
* @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd
* @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep
* @pwrdm_wait_transition: Wait for a pd state transition to complete
+ *
+ * Regarding @pwrdm_set_lowpwrstchange: On the OMAP2 and 3-family
+ * chips, a powerdomain's power state is not allowed to directly
+ * transition from one low-power state (e.g., CSWR) to another
+ * low-power state (e.g., OFF) without first waking up the
+ * powerdomain. This wastes energy. So OMAP4 chips support the
+ * ability to transition a powerdomain power state directly from one
+ * low-power state to another. The function pointed to by
+ * @pwrdm_set_lowpwrstchange is intended to configure the OMAP4
+ * hardware powerdomain state machine to enable this feature.
*/
struct pwrdm_ops {
int (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst);
@@ -225,15 +239,15 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm);
int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm);
bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
-int pwrdm_wait_transition(struct powerdomain *pwrdm);
-
+int pwrdm_state_switch_nolock(struct powerdomain *pwrdm);
int pwrdm_state_switch(struct powerdomain *pwrdm);
int pwrdm_pre_transition(struct powerdomain *pwrdm);
int pwrdm_post_transition(struct powerdomain *pwrdm);
-int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
+extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state);
+
extern void omap242x_powerdomains_init(void);
extern void omap243x_powerdomains_init(void);
extern void omap3xxx_powerdomains_init(void);
@@ -253,5 +267,7 @@ extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank);
extern struct powerdomain wkup_omap2_pwrdm;
extern struct powerdomain gfx_omap2_pwrdm;
+extern void pwrdm_lock(struct powerdomain *pwrdm);
+extern void pwrdm_unlock(struct powerdomain *pwrdm);
#endif
diff --git a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c
index d3a5399091ad..7b946f1005b1 100644
--- a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c
@@ -54,12 +54,12 @@ struct powerdomain gfx_omap2_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
struct powerdomain wkup_omap2_pwrdm = {
.name = "wkup_pwrdm",
.prcm_offs = WKUP_MOD,
.pwrsts = PWRSTS_ON,
- .voltdm = { .name = "wakeup" },
+ .voltdm = { .name = "wakeup" },
};
diff --git a/arch/arm/mach-omap2/powerdomains2xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_data.c
index ba520d4f7c7b..578eef86fcf2 100644
--- a/arch/arm/mach-omap2/powerdomains2xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains2xxx_data.c
@@ -38,7 +38,7 @@ static struct powerdomain dsp_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON,
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain mpu_24xx_pwrdm = {
@@ -53,13 +53,14 @@ static struct powerdomain mpu_24xx_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON,
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain core_24xx_pwrdm = {
.name = "core_pwrdm",
.prcm_offs = CORE_MOD,
.pwrsts = PWRSTS_OFF_RET_ON,
+ .pwrsts_logic_ret = PWRSTS_RET,
.banks = 3,
.pwrsts_mem_ret = {
[0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */
@@ -71,7 +72,7 @@ static struct powerdomain core_24xx_pwrdm = {
[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
[2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
@@ -93,7 +94,7 @@ static struct powerdomain mdm_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
/*
diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index 8b23d234fb55..f0e14e9efe5a 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -50,7 +50,7 @@ static struct powerdomain iva2_pwrdm = {
[2] = PWRSTS_OFF_ON,
[3] = PWRSTS_ON,
},
- .voltdm = { .name = "mpu_iva" },
+ .voltdm = { .name = "mpu_iva" },
};
static struct powerdomain mpu_3xxx_pwrdm = {
@@ -66,7 +66,7 @@ static struct powerdomain mpu_3xxx_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_OFF_ON,
},
- .voltdm = { .name = "mpu_iva" },
+ .voltdm = { .name = "mpu_iva" },
};
static struct powerdomain mpu_am35x_pwrdm = {
@@ -82,7 +82,7 @@ static struct powerdomain mpu_am35x_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON,
},
- .voltdm = { .name = "mpu_iva" },
+ .voltdm = { .name = "mpu_iva" },
};
/*
@@ -109,7 +109,7 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = {
[0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain core_3xxx_es3_1_pwrdm = {
@@ -131,7 +131,7 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = {
[0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain core_am35x_pwrdm = {
@@ -148,7 +148,7 @@ static struct powerdomain core_am35x_pwrdm = {
[0] = PWRSTS_ON, /* MEM1ONSTATE */
[1] = PWRSTS_ON, /* MEM2ONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain dss_pwrdm = {
@@ -163,7 +163,7 @@ static struct powerdomain dss_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain dss_am35x_pwrdm = {
@@ -178,7 +178,7 @@ static struct powerdomain dss_am35x_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
/*
@@ -199,7 +199,7 @@ static struct powerdomain sgx_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain sgx_am35x_pwrdm = {
@@ -214,7 +214,7 @@ static struct powerdomain sgx_am35x_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain cam_pwrdm = {
@@ -229,7 +229,7 @@ static struct powerdomain cam_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain per_pwrdm = {
@@ -244,7 +244,7 @@ static struct powerdomain per_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain per_am35x_pwrdm = {
@@ -259,13 +259,13 @@ static struct powerdomain per_am35x_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain emu_pwrdm = {
.name = "emu_pwrdm",
.prcm_offs = OMAP3430_EMU_MOD,
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain neon_pwrdm = {
@@ -273,7 +273,7 @@ static struct powerdomain neon_pwrdm = {
.prcm_offs = OMAP3430_NEON_MOD,
.pwrsts = PWRSTS_OFF_RET_ON,
.pwrsts_logic_ret = PWRSTS_RET,
- .voltdm = { .name = "mpu_iva" },
+ .voltdm = { .name = "mpu_iva" },
};
static struct powerdomain neon_am35x_pwrdm = {
@@ -281,7 +281,7 @@ static struct powerdomain neon_am35x_pwrdm = {
.prcm_offs = OMAP3430_NEON_MOD,
.pwrsts = PWRSTS_ON,
.pwrsts_logic_ret = PWRSTS_ON,
- .voltdm = { .name = "mpu_iva" },
+ .voltdm = { .name = "mpu_iva" },
};
static struct powerdomain usbhost_pwrdm = {
@@ -303,37 +303,37 @@ static struct powerdomain usbhost_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* MEMONSTATE */
},
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain dpll1_pwrdm = {
.name = "dpll1_pwrdm",
.prcm_offs = MPU_MOD,
- .voltdm = { .name = "mpu_iva" },
+ .voltdm = { .name = "mpu_iva" },
};
static struct powerdomain dpll2_pwrdm = {
.name = "dpll2_pwrdm",
.prcm_offs = OMAP3430_IVA2_MOD,
- .voltdm = { .name = "mpu_iva" },
+ .voltdm = { .name = "mpu_iva" },
};
static struct powerdomain dpll3_pwrdm = {
.name = "dpll3_pwrdm",
.prcm_offs = PLL_MOD,
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain dpll4_pwrdm = {
.name = "dpll4_pwrdm",
.prcm_offs = PLL_MOD,
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
static struct powerdomain dpll5_pwrdm = {
.name = "dpll5_pwrdm",
.prcm_offs = PLL_MOD,
- .voltdm = { .name = "core" },
+ .voltdm = { .name = "core" },
};
/* As powerdomains are added or removed above, this list must also be changed */
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index a3e121f94a86..947f6adfed0c 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -210,6 +210,7 @@ int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
PM_WKDEP, (1 << clkdm2->dep_bit));
}
+/* XXX Caller must hold the clkdm's powerdomain lock */
int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
{
struct clkdm_dep *cd;
@@ -221,7 +222,7 @@ int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
/* PRM accesses are slow, so minimize them */
mask |= 1 << cd->clkdm->dep_bit;
- atomic_set(&cd->wkdep_usecount, 0);
+ cd->wkdep_usecount = 0;
}
omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c
index e648bd55b072..7721990d2006 100644
--- a/arch/arm/mach-omap2/prm3xxx.c
+++ b/arch/arm/mach-omap2/prm3xxx.c
@@ -427,7 +427,7 @@ static int __init omap3xxx_prm_late_init(void)
return ret;
}
-subsys_initcall(omap3xxx_prm_late_init);
+omap_subsys_initcall(omap3xxx_prm_late_init);
static void __exit omap3xxx_prm_exit(void)
{
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index c05a343d465d..d35f98aabf7a 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -665,7 +665,7 @@ static int __init omap44xx_prm_late_init(void)
return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup);
}
-subsys_initcall(omap44xx_prm_late_init);
+omap_subsys_initcall(omap44xx_prm_late_init);
static void __exit omap44xx_prm_exit(void)
{
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 04fdbc4c499b..8396b5b7e912 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -254,7 +254,7 @@ static int __init omap_serial_early_init(void)
return 0;
}
-core_initcall(omap_serial_early_init);
+omap_core_initcall(omap_serial_early_init);
/**
* omap_serial_init_port() - initialize single serial port
@@ -316,8 +316,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
if (WARN_ON(!oh))
return;
- pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size,
- NULL, 0, false);
+ pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size);
if (IS_ERR(pdev)) {
WARN(1, "Could not build omap_device for %s: %s.\n", name,
oh->name);
diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
index 1da8f03c479e..aee3c8940a30 100644
--- a/arch/arm/mach-omap2/smartreflex-class3.c
+++ b/arch/arm/mach-omap2/smartreflex-class3.c
@@ -12,6 +12,7 @@
*/
#include <linux/power/smartreflex.h>
+#include "soc.h"
#include "voltage.h"
static int sr_class3_enable(struct omap_sr *sr)
@@ -58,4 +59,4 @@ static int __init sr_class3_init(void)
pr_info("SmartReflex Class3 initialized\n");
return sr_register_class(&class3_data);
}
-late_initcall(sr_class3_init);
+omap_late_initcall(sr_class3_init);
diff --git a/arch/arm/mach-omap2/soc.h b/arch/arm/mach-omap2/soc.h
index f31d90774de0..092aedd7ed13 100644
--- a/arch/arm/mach-omap2/soc.h
+++ b/arch/arm/mach-omap2/soc.h
@@ -42,6 +42,9 @@
#undef MULTI_OMAP2
#undef OMAP_NAME
+#ifdef CONFIG_ARCH_MULTIPLATFORM
+#define MULTI_OMAP2
+#endif
#ifdef CONFIG_SOC_OMAP2420
# ifdef OMAP_NAME
# undef MULTI_OMAP2
@@ -112,6 +115,11 @@ int omap_type(void);
*/
unsigned int omap_rev(void);
+static inline int soc_is_omap(void)
+{
+ return omap_rev() != 0;
+}
+
/*
* Get the CPU revision for OMAP devices
*/
@@ -465,5 +473,26 @@ static inline unsigned int omap4_has_ ##feat(void) \
OMAP4_HAS_FEATURE(perf_silicon, PERF_SILICON)
+/*
+ * We need to make sure omap initcalls don't run when
+ * multiplatform kernels are booted on other SoCs.
+ */
+#define omap_initcall(level, fn) \
+static int __init __used __##fn(void) \
+{ \
+ if (!soc_is_omap()) \
+ return 0; \
+ return fn(); \
+} \
+level(__##fn);
+
+#define omap_early_initcall(fn) omap_initcall(early_initcall, fn)
+#define omap_core_initcall(fn) omap_initcall(core_initcall, fn)
+#define omap_postcore_initcall(fn) omap_initcall(postcore_initcall, fn)
+#define omap_arch_initcall(fn) omap_initcall(arch_initcall, fn)
+#define omap_subsys_initcall(fn) omap_initcall(subsys_initcall, fn)
+#define omap_device_initcall(fn) omap_initcall(device_initcall, fn)
+#define omap_late_initcall(fn) omap_initcall(late_initcall, fn)
+
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
index b9753fe27232..bb829e065400 100644
--- a/arch/arm/mach-omap2/sr_device.c
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -152,8 +152,7 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
sr_data->enable_on_init = sr_enable_on_init;
- pdev = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data),
- NULL, 0, 0);
+ pdev = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data), 0);
if (IS_ERR(pdev))
pr_warning("%s: Could not build omap_device for %s: %s.\n\n",
__func__, name, oh->name);
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index b8ad6e632bb8..2bdd4cf17a8f 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -131,7 +131,6 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
static struct clock_event_device clockevent_gpt = {
.name = "gp_timer",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.rating = 300,
.set_next_event = omap2_gp_timer_set_next_event,
.set_mode = omap2_gp_timer_set_mode,
@@ -228,7 +227,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
int r = 0;
if (of_have_populated_dt()) {
- np = omap_get_timer_dt(omap_timer_match, NULL);
+ np = omap_get_timer_dt(omap_timer_match, property);
if (!np)
return -ENODEV;
@@ -336,17 +335,11 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
- clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC,
- clockevent_gpt.shift);
- clockevent_gpt.max_delta_ns =
- clockevent_delta2ns(0xffffffff, &clockevent_gpt);
- clockevent_gpt.min_delta_ns =
- clockevent_delta2ns(3, &clockevent_gpt);
- /* Timer internal resynch latency. */
-
clockevent_gpt.cpumask = cpu_possible_mask;
clockevent_gpt.irq = omap_dm_timer_get_irq(&clkev);
- clockevents_register_device(&clockevent_gpt);
+ clockevents_config_and_register(&clockevent_gpt, clkev.rate,
+ 3, /* Timer internal resynch latency */
+ 0xffffffff);
pr_info("OMAP clockevent source: GPTIMER%d at %lu Hz\n",
gptimer_id, clkev.rate);
@@ -552,7 +545,7 @@ static inline void __init realtime_counter_init(void)
#define OMAP_SYS_GP_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \
clksrc_nr, clksrc_src) \
-static void __init omap##name##_gptimer_timer_init(void) \
+void __init omap##name##_gptimer_timer_init(void) \
{ \
omap_dmtimer_init(); \
omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \
@@ -561,7 +554,7 @@ static void __init omap##name##_gptimer_timer_init(void) \
#define OMAP_SYS_32K_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \
clksrc_nr, clksrc_src) \
-static void __init omap##name##_sync32k_timer_init(void) \
+void __init omap##name##_sync32k_timer_init(void) \
{ \
omap_dmtimer_init(); \
omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \
@@ -572,33 +565,23 @@ static void __init omap##name##_sync32k_timer_init(void) \
omap2_sync32k_clocksource_init(); \
}
-#define OMAP_SYS_TIMER(name, clksrc) \
-struct sys_timer omap##name##_timer = { \
- .init = omap##name##_##clksrc##_timer_init, \
-};
-
#ifdef CONFIG_ARCH_OMAP2
OMAP_SYS_32K_TIMER_INIT(2, 1, OMAP2_32K_SOURCE, "ti,timer-alwon",
2, OMAP2_MPU_SOURCE);
-OMAP_SYS_TIMER(2, sync32k);
#endif /* CONFIG_ARCH_OMAP2 */
#ifdef CONFIG_ARCH_OMAP3
OMAP_SYS_32K_TIMER_INIT(3, 1, OMAP3_32K_SOURCE, "ti,timer-alwon",
2, OMAP3_MPU_SOURCE);
-OMAP_SYS_TIMER(3, sync32k);
OMAP_SYS_32K_TIMER_INIT(3_secure, 12, OMAP3_32K_SOURCE, "ti,timer-secure",
2, OMAP3_MPU_SOURCE);
-OMAP_SYS_TIMER(3_secure, sync32k);
OMAP_SYS_GP_TIMER_INIT(3_gp, 1, OMAP3_MPU_SOURCE, "ti,timer-alwon",
2, OMAP3_MPU_SOURCE);
-OMAP_SYS_TIMER(3_gp, gptimer);
#endif /* CONFIG_ARCH_OMAP3 */
#ifdef CONFIG_SOC_AM33XX
OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
2, OMAP4_MPU_SOURCE);
-OMAP_SYS_TIMER(3_am33xx, gptimer);
#endif /* CONFIG_SOC_AM33XX */
#ifdef CONFIG_ARCH_OMAP4
@@ -606,7 +589,7 @@ OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
2, OMAP4_MPU_SOURCE);
#ifdef CONFIG_LOCAL_TIMERS
static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29);
-static void __init omap4_local_timer_init(void)
+void __init omap4_local_timer_init(void)
{
omap4_sync32k_timer_init();
/* Local timers are not supprted on OMAP4430 ES1.0 */
@@ -624,18 +607,17 @@ static void __init omap4_local_timer_init(void)
}
}
#else /* CONFIG_LOCAL_TIMERS */
-static void __init omap4_local_timer_init(void)
+void __init omap4_local_timer_init(void)
{
omap4_sync32k_timer_init();
}
#endif /* CONFIG_LOCAL_TIMERS */
-OMAP_SYS_TIMER(4, local);
#endif /* CONFIG_ARCH_OMAP4 */
#ifdef CONFIG_SOC_OMAP5
OMAP_SYS_32K_TIMER_INIT(5, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
2, OMAP4_MPU_SOURCE);
-static void __init omap5_realtime_timer_init(void)
+void __init omap5_realtime_timer_init(void)
{
int err;
@@ -646,7 +628,6 @@ static void __init omap5_realtime_timer_init(void)
if (err)
pr_err("%s: arch_timer_register failed %d\n", __func__, err);
}
-OMAP_SYS_TIMER(5, realtime);
#endif /* CONFIG_SOC_OMAP5 */
/**
@@ -702,8 +683,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
pdata->timer_errata = omap_dm_timer_get_errata();
pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
- pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
- NULL, 0, 0);
+ pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata));
if (IS_ERR(pdev)) {
pr_err("%s: Can't build omap_device for %s: %s.\n",
@@ -738,7 +718,7 @@ static int __init omap2_dm_timer_init(void)
return 0;
}
-arch_initcall(omap2_dm_timer_init);
+omap_arch_initcall(omap2_dm_timer_init);
/**
* omap2_override_clocksource - clocksource override with user configuration
diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index e49b40b4c90a..51e138cc5398 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -23,6 +23,7 @@
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
#include <linux/gpio.h>
+#include <linux/string.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
@@ -56,7 +57,7 @@ void __init omap_pmic_init(int bus, u32 clkrate,
struct twl4030_platform_data *pmic_data)
{
omap_mux_init_signal("sys_nirq", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE);
- strncpy(pmic_i2c_board_info.type, pmic_type,
+ strlcpy(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;
@@ -528,24 +529,29 @@ void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
defined(CONFIG_SND_OMAP_SOC_OMAP_TWL4030_MODULE)
#include <linux/platform_data/omap-twl4030.h>
+/* Commonly used configuration */
static struct omap_tw4030_pdata omap_twl4030_audio_data;
static struct platform_device audio_device = {
.name = "omap-twl4030",
.id = -1,
- .dev = {
- .platform_data = &omap_twl4030_audio_data,
- },
};
-void __init omap_twl4030_audio_init(char *card_name)
+void omap_twl4030_audio_init(char *card_name,
+ struct omap_tw4030_pdata *pdata)
{
- omap_twl4030_audio_data.card_name = card_name;
+ if (!pdata)
+ pdata = &omap_twl4030_audio_data;
+
+ pdata->card_name = card_name;
+
+ audio_device.dev.platform_data = pdata;
platform_device_register(&audio_device);
}
#else /* SOC_OMAP_TWL4030 */
-void __init omap_twl4030_audio_init(char *card_name)
+void omap_twl4030_audio_init(char *card_name,
+ struct omap_tw4030_pdata *pdata)
{
return;
}
diff --git a/arch/arm/mach-omap2/twl-common.h b/arch/arm/mach-omap2/twl-common.h
index dcfbad5ac471..24b65d081b69 100644
--- a/arch/arm/mach-omap2/twl-common.h
+++ b/arch/arm/mach-omap2/twl-common.h
@@ -32,6 +32,7 @@
struct twl4030_platform_data;
struct twl6040_platform_data;
+struct omap_tw4030_pdata;
struct i2c_board_info;
void omap_pmic_init(int bus, u32 clkrate, const char *pmic_type, int pmic_irq,
@@ -60,6 +61,6 @@ void omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
void omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
u32 pdata_flags, u32 regulators_flags);
-void omap_twl4030_audio_init(char *card_name);
+void omap_twl4030_audio_init(char *card_name, struct omap_tw4030_pdata *pdata);
#endif /* __OMAP_PMIC_COMMON__ */
diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c
index 2e44e8a22884..5706bdccf45e 100644
--- a/arch/arm/mach-omap2/usb-host.c
+++ b/arch/arm/mach-omap2/usb-host.c
@@ -37,19 +37,6 @@
#define USBHS_UHH_HWMODNAME "usb_host_hs"
#define USBHS_TLL_HWMODNAME "usb_tll_hs"
-static struct usbhs_omap_platform_data usbhs_data;
-static struct usbtll_omap_platform_data usbtll_data;
-static struct ehci_hcd_omap_platform_data ehci_data;
-static struct ohci_hcd_omap_platform_data ohci_data;
-
-static struct omap_device_pm_latency omap_uhhtll_latency[] = {
- {
- .deactivate_func = omap_device_idle_hwmods,
- .activate_func = omap_device_enable_hwmods,
- .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
- },
-};
-
/* MUX settings for EHCI pins */
/*
* setup_ehci_io_mux - initialize IO pad mux for USBHOST
@@ -485,32 +472,18 @@ void __init setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
}
}
-void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
+void __init usbhs_init(struct usbhs_omap_platform_data *pdata)
{
struct omap_hwmod *uhh_hwm, *tll_hwm;
struct platform_device *pdev;
int bus_id = -1;
- int i;
-
- for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
- usbhs_data.port_mode[i] = pdata->port_mode[i];
- usbtll_data.port_mode[i] = pdata->port_mode[i];
- ohci_data.port_mode[i] = pdata->port_mode[i];
- ehci_data.port_mode[i] = pdata->port_mode[i];
- ehci_data.reset_gpio_port[i] = pdata->reset_gpio_port[i];
- ehci_data.regulator[i] = pdata->regulator[i];
- }
- ehci_data.phy_reset = pdata->phy_reset;
- ohci_data.es2_compatibility = pdata->es2_compatibility;
- usbhs_data.ehci_data = &ehci_data;
- usbhs_data.ohci_data = &ohci_data;
if (cpu_is_omap34xx()) {
setup_ehci_io_mux(pdata->port_mode);
setup_ohci_io_mux(pdata->port_mode);
if (omap_rev() <= OMAP3430_REV_ES2_1)
- usbhs_data.single_ulpi_bypass = true;
+ pdata->single_ulpi_bypass = true;
} else if (cpu_is_omap44xx()) {
setup_4430ehci_io_mux(pdata->port_mode);
@@ -530,9 +503,7 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
}
pdev = omap_device_build(OMAP_USBTLL_DEVICE, bus_id, tll_hwm,
- &usbtll_data, sizeof(usbtll_data),
- omap_uhhtll_latency,
- ARRAY_SIZE(omap_uhhtll_latency), false);
+ pdata, sizeof(*pdata));
if (IS_ERR(pdev)) {
pr_err("Could not build hwmod device %s\n",
USBHS_TLL_HWMODNAME);
@@ -540,9 +511,7 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
}
pdev = omap_device_build(OMAP_USBHS_DEVICE, bus_id, uhh_hwm,
- &usbhs_data, sizeof(usbhs_data),
- omap_uhhtll_latency,
- ARRAY_SIZE(omap_uhhtll_latency), false);
+ pdata, sizeof(*pdata));
if (IS_ERR(pdev)) {
pr_err("Could not build hwmod devices %s\n",
USBHS_UHH_HWMODNAME);
@@ -552,7 +521,7 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
#else
-void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
+void __init usbhs_init(struct usbhs_omap_platform_data *pdata)
{
}
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 7b33b375fe77..3242a554ad6b 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -85,6 +85,9 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
musb_plat.mode = board_data->mode;
musb_plat.extvbus = board_data->extvbus;
+ if (cpu_is_omap44xx())
+ musb_plat.has_mailbox = true;
+
if (soc_is_am35xx()) {
oh_name = "am35x_otg_hs";
name = "musb-am35x";
@@ -102,7 +105,7 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
return;
pdev = omap_device_build(name, bus_id, oh, &musb_plat,
- sizeof(musb_plat), NULL, 0, false);
+ sizeof(musb_plat));
if (IS_ERR(pdev)) {
pr_err("Could not build omap_device for %s %s\n",
name, oh_name);
diff --git a/arch/arm/mach-omap2/usb.h b/arch/arm/mach-omap2/usb.h
index 9b986ead7c45..3319f5cf47a3 100644
--- a/arch/arm/mach-omap2/usb.h
+++ b/arch/arm/mach-omap2/usb.h
@@ -53,26 +53,8 @@
#define USBPHY_OTGSESSEND_EN (1 << 20)
#define USBPHY_DATA_POLARITY (1 << 23)
-struct usbhs_omap_board_data {
- enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS];
-
- /* have to be valid if phy_reset is true and portx is in phy mode */
- int reset_gpio_port[OMAP3_HS_USB_PORTS];
-
- /* Set this to true for ES2.x silicon */
- unsigned es2_compatibility:1;
-
- unsigned phy_reset:1;
-
- /*
- * Regulators for USB PHYs.
- * Each PHY can have a separate regulator.
- */
- struct regulator *regulator[OMAP3_HS_USB_PORTS];
-};
-
extern void usb_musb_init(struct omap_musb_board_data *board_data);
-extern void usbhs_init(const struct usbhs_omap_board_data *pdata);
+extern void usbhs_init(struct usbhs_omap_platform_data *pdata);
extern void am35x_musb_reset(void);
extern void am35x_musb_phy_power(u8 on);
diff --git a/arch/arm/mach-omap2/wd_timer.c b/arch/arm/mach-omap2/wd_timer.c
index 7c2b4ed38f02..d15c7bbab8e2 100644
--- a/arch/arm/mach-omap2/wd_timer.c
+++ b/arch/arm/mach-omap2/wd_timer.c
@@ -124,10 +124,9 @@ static int __init omap_init_wdt(void)
pdata.read_reset_sources = prm_read_reset_sources;
pdev = omap_device_build(dev_name, id, oh, &pdata,
- sizeof(struct omap_wd_timer_platform_data),
- NULL, 0, 0);
+ sizeof(struct omap_wd_timer_platform_data));
WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s.\n",
dev_name, oh->name);
return 0;
}
-subsys_initcall(omap_init_wdt);
+omap_subsys_initcall(omap_init_wdt);
diff --git a/arch/arm/mach-orion5x/board-dt.c b/arch/arm/mach-orion5x/board-dt.c
index 32e5c211a89b..35a8014529ca 100644
--- a/arch/arm/mach-orion5x/board-dt.c
+++ b/arch/arm/mach-orion5x/board-dt.c
@@ -72,7 +72,7 @@ DT_MACHINE_START(ORION5X_DT, "Marvell Orion5x (Flattened Device Tree)")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion_dt_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.init_machine = orion5x_dt_init,
.restart = orion5x_restart,
.dt_compat = orion5x_dt_compat,
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 550f92320afb..d068f1431c40 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -217,7 +217,7 @@ int __init orion5x_find_tclk(void)
return 166666667;
}
-static void __init orion5x_timer_init(void)
+void __init orion5x_timer_init(void)
{
orion5x_tclk = orion5x_find_tclk();
@@ -225,10 +225,6 @@ static void __init orion5x_timer_init(void)
IRQ_ORION5X_BRIDGE, orion5x_tclk);
}
-struct sys_timer orion5x_timer = {
- .init = orion5x_timer_init,
-};
-
/*****************************************************************************
* General
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index 7db5cdd9c4b7..e60345760283 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -15,7 +15,7 @@ void orion5x_init(void);
void orion5x_id(u32 *dev, u32 *rev, char **dev_name);
void clk_init(void);
extern int orion5x_tclk;
-extern struct sys_timer orion5x_timer;
+extern void orion5x_timer_init(void);
/*
* Enumerations and functions for Orion windows mapping. Used by Orion core
diff --git a/arch/arm/mach-orion5x/d2net-setup.c b/arch/arm/mach-orion5x/d2net-setup.c
index e3629c063df2..57d0af74874d 100644
--- a/arch/arm/mach-orion5x/d2net-setup.c
+++ b/arch/arm/mach-orion5x/d2net-setup.c
@@ -342,7 +342,7 @@ MACHINE_START(D2NET, "LaCie d2 Network")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
@@ -355,7 +355,7 @@ MACHINE_START(BIGDISK, "LaCie Big Disk Network")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c
index 41fe2b1ff47c..76665640087b 100644
--- a/arch/arm/mach-orion5x/db88f5281-setup.c
+++ b/arch/arm/mach-orion5x/db88f5281-setup.c
@@ -362,6 +362,6 @@ MACHINE_START(DB88F5281, "Marvell Orion-2 Development Board")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index e533588880ff..6eb1732757fd 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -714,7 +714,7 @@ MACHINE_START(DNS323, "D-Link DNS-323")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/include/mach/uncompress.h b/arch/arm/mach-orion5x/include/mach/uncompress.h
index 4322dba468a4..abd26b542c3c 100644
--- a/arch/arm/mach-orion5x/include/mach/uncompress.h
+++ b/arch/arm/mach-orion5x/include/mach/uncompress.h
@@ -46,4 +46,3 @@ static void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c
index f1ae10ae5bd4..b98403526218 100644
--- a/arch/arm/mach-orion5x/kurobox_pro-setup.c
+++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c
@@ -383,7 +383,7 @@ MACHINE_START(KUROBOX_PRO, "Buffalo/Revogear Kurobox Pro")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
@@ -397,7 +397,7 @@ MACHINE_START(LINKSTATION_PRO, "Buffalo Linkstation Pro/Live")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/ls-chl-setup.c b/arch/arm/mach-orion5x/ls-chl-setup.c
index 0c9e413b5805..044da5b6a6ae 100644
--- a/arch/arm/mach-orion5x/ls-chl-setup.c
+++ b/arch/arm/mach-orion5x/ls-chl-setup.c
@@ -322,7 +322,7 @@ MACHINE_START(LINKSTATION_LSCHL, "Buffalo Linkstation LiveV3 (LS-CHL)")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/ls_hgl-setup.c b/arch/arm/mach-orion5x/ls_hgl-setup.c
index c1b5d8a58037..d49f93423f52 100644
--- a/arch/arm/mach-orion5x/ls_hgl-setup.c
+++ b/arch/arm/mach-orion5x/ls_hgl-setup.c
@@ -269,7 +269,7 @@ MACHINE_START(LINKSTATION_LS_HGL, "Buffalo Linkstation LS-HGL")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/lsmini-setup.c b/arch/arm/mach-orion5x/lsmini-setup.c
index 949eaa8f12e3..8e3965c6c0fe 100644
--- a/arch/arm/mach-orion5x/lsmini-setup.c
+++ b/arch/arm/mach-orion5x/lsmini-setup.c
@@ -271,7 +271,7 @@ MACHINE_START(LINKSTATION_MINI, "Buffalo Linkstation Mini")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/mss2-setup.c b/arch/arm/mach-orion5x/mss2-setup.c
index 1c16d045333e..0ec94a1f2b16 100644
--- a/arch/arm/mach-orion5x/mss2-setup.c
+++ b/arch/arm/mach-orion5x/mss2-setup.c
@@ -265,7 +265,7 @@ MACHINE_START(MSS2, "Maxtor Shared Storage II")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/mv2120-setup.c b/arch/arm/mach-orion5x/mv2120-setup.c
index c87fde4deeca..18143f2a9093 100644
--- a/arch/arm/mach-orion5x/mv2120-setup.c
+++ b/arch/arm/mach-orion5x/mv2120-setup.c
@@ -233,7 +233,7 @@ MACHINE_START(MV2120, "HP Media Vault mv2120")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/net2big-setup.c b/arch/arm/mach-orion5x/net2big-setup.c
index 3506f16c0bf2..282e503b003e 100644
--- a/arch/arm/mach-orion5x/net2big-setup.c
+++ b/arch/arm/mach-orion5x/net2big-setup.c
@@ -425,7 +425,7 @@ MACHINE_START(NET2BIG, "LaCie 2Big Network")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index 9b1c95310291..d6e72f672afb 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -171,7 +171,7 @@ MACHINE_START(RD88F5181L_FXO, "Marvell Orion-VoIP FXO Reference Design")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index 51ba2b81a10b..c8b7913310e5 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -183,7 +183,7 @@ MACHINE_START(RD88F5181L_GE, "Marvell Orion-VoIP GE Reference Design")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c
index 0a56b9444f1b..f9e156725d7c 100644
--- a/arch/arm/mach-orion5x/rd88f5182-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5182-setup.c
@@ -281,6 +281,6 @@ MACHINE_START(RD88F5182, "Marvell Orion-NAS Reference Design")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
index ed50910b08a4..78a1e6ab1b9d 100644
--- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
@@ -123,7 +123,7 @@ MACHINE_START(RD88F6183AP_GE, "Marvell Orion-1-90 AP GE Reference Design")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/terastation_pro2-setup.c b/arch/arm/mach-orion5x/terastation_pro2-setup.c
index 90e571dc4deb..acc0877ec1c9 100644
--- a/arch/arm/mach-orion5x/terastation_pro2-setup.c
+++ b/arch/arm/mach-orion5x/terastation_pro2-setup.c
@@ -361,7 +361,7 @@ MACHINE_START(TERASTATION_PRO2, "Buffalo Terastation Pro II/Live")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c
index b184f680e0db..9c17f0c2b488 100644
--- a/arch/arm/mach-orion5x/ts209-setup.c
+++ b/arch/arm/mach-orion5x/ts209-setup.c
@@ -326,7 +326,7 @@ MACHINE_START(TS209, "QNAP TS-109/TS-209")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/ts409-setup.c b/arch/arm/mach-orion5x/ts409-setup.c
index a5c2e64c4ece..8cc5ab6c503e 100644
--- a/arch/arm/mach-orion5x/ts409-setup.c
+++ b/arch/arm/mach-orion5x/ts409-setup.c
@@ -315,7 +315,7 @@ MACHINE_START(TS409, "QNAP TS-409")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index b0727dcd1ef9..e960855d32ac 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -619,6 +619,6 @@ MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
.map_io = ts78xx_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c
index 754c12b6abf0..66552ca7e05d 100644
--- a/arch/arm/mach-orion5x/wnr854t-setup.c
+++ b/arch/arm/mach-orion5x/wnr854t-setup.c
@@ -176,7 +176,7 @@ MACHINE_START(WNR854T, "Netgear WNR854T")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
index 45c21251eb1e..2c5408e2e689 100644
--- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c
+++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
@@ -264,7 +264,7 @@ MACHINE_START(WRT350N_V2, "Linksys WRT350N v2")
.map_io = orion5x_map_io,
.init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
- .timer = &orion5x_timer,
+ .init_time = orion5x_timer_init,
.fixup = tag_fixup_mem32,
.restart = orion5x_restart,
MACHINE_END
diff --git a/arch/arm/mach-picoxcell/Kconfig b/arch/arm/mach-picoxcell/Kconfig
index 868796f8085c..13bae78b215a 100644
--- a/arch/arm/mach-picoxcell/Kconfig
+++ b/arch/arm/mach-picoxcell/Kconfig
@@ -7,7 +7,6 @@ config ARCH_PICOXCELL
select DW_APB_TIMER
select DW_APB_TIMER_OF
select GENERIC_CLOCKEVENTS
- select GENERIC_GPIO
select HAVE_TCM
select NO_IOPORT
select SPARSE_IRQ
diff --git a/arch/arm/mach-picoxcell/common.c b/arch/arm/mach-picoxcell/common.c
index f6c0849af5e9..70b441ad1d18 100644
--- a/arch/arm/mach-picoxcell/common.c
+++ b/arch/arm/mach-picoxcell/common.c
@@ -9,6 +9,7 @@
*/
#include <linux/delay.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -17,7 +18,6 @@
#include <linux/dw_apb_timer.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/map.h>
#include "common.h"
@@ -70,16 +70,6 @@ static const char *picoxcell_dt_match[] = {
NULL
};
-static const struct of_device_id vic_of_match[] __initconst = {
- { .compatible = "arm,pl192-vic", .data = vic_of_init, },
- { /* Sentinel */ }
-};
-
-static void __init picoxcell_init_irq(void)
-{
- of_irq_init(vic_of_match);
-}
-
static void picoxcell_wdt_restart(char mode, const char *cmd)
{
/*
@@ -97,9 +87,8 @@ static void picoxcell_wdt_restart(char mode, const char *cmd)
DT_MACHINE_START(PICOXCELL, "Picochip picoXcell")
.map_io = picoxcell_map_io,
.nr_irqs = NR_IRQS_LEGACY,
- .init_irq = picoxcell_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &dw_apb_timer,
+ .init_irq = irqchip_init,
+ .init_time = dw_apb_timer_init,
.init_machine = picoxcell_init_machine,
.dt_compat = picoxcell_dt_match,
.restart = picoxcell_wdt_restart,
diff --git a/arch/arm/mach-picoxcell/common.h b/arch/arm/mach-picoxcell/common.h
index a65cb02f84c8..481b42a4ef15 100644
--- a/arch/arm/mach-picoxcell/common.h
+++ b/arch/arm/mach-picoxcell/common.h
@@ -12,6 +12,6 @@
#include <asm/mach/time.h>
-extern struct sys_timer dw_apb_timer;
+extern void dw_apb_timer_init(void);
#endif /* __PICOXCELL_COMMON_H__ */
diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig
index 558ccfb8d458..4f7379fe01e2 100644
--- a/arch/arm/mach-prima2/Kconfig
+++ b/arch/arm/mach-prima2/Kconfig
@@ -11,6 +11,16 @@ config ARCH_PRIMA2
help
Support for CSR SiRFSoC ARM Cortex A9 Platform
+config ARCH_MARCO
+ bool "CSR SiRFSoC MARCO ARM Cortex A9 Platform"
+ default y
+ select ARM_GIC
+ select CPU_V7
+ select HAVE_SMP
+ select SMP_ON_UP
+ help
+ Support for CSR SiRFSoC ARM Cortex A9 Platform
+
endmenu
config SIRF_IRQ
diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
index fc9ce22e2b5a..bfe360cbd177 100644
--- a/arch/arm/mach-prima2/Makefile
+++ b/arch/arm/mach-prima2/Makefile
@@ -1,4 +1,3 @@
-obj-y := timer.o
obj-y += rstc.o
obj-y += common.o
obj-y += rtciobrg.o
@@ -6,3 +5,7 @@ obj-$(CONFIG_DEBUG_LL) += lluart.o
obj-$(CONFIG_CACHE_L2X0) += l2x0.o
obj-$(CONFIG_SUSPEND) += pm.o sleep.o
obj-$(CONFIG_SIRF_IRQ) += irq.o
+obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o
+obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c
index f25a54194639..2d57aa479a7b 100644
--- a/arch/arm/mach-prima2/common.c
+++ b/arch/arm/mach-prima2/common.c
@@ -8,6 +8,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/irqchip.h>
#include <asm/sizes.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -30,6 +31,12 @@ void __init sirfsoc_init_late(void)
sirfsoc_pm_init();
}
+static __init void sirfsoc_map_io(void)
+{
+ sirfsoc_map_lluart();
+ sirfsoc_map_scu();
+}
+
#ifdef CONFIG_ARCH_PRIMA2
static const char *prima2_dt_match[] __initdata = {
"sirf,prima2",
@@ -38,9 +45,12 @@ static const char *prima2_dt_match[] __initdata = {
DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")
/* Maintainer: Barry Song <baohua.song@csr.com> */
- .map_io = sirfsoc_map_lluart,
+ .map_io = sirfsoc_map_io,
.init_irq = sirfsoc_of_irq_init,
- .timer = &sirfsoc_timer,
+ .init_time = sirfsoc_prima2_timer_init,
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+ .handle_irq = sirfsoc_handle_irq,
+#endif
.dma_zone_size = SZ_256M,
.init_machine = sirfsoc_mach_init,
.init_late = sirfsoc_init_late,
@@ -48,3 +58,22 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")
.restart = sirfsoc_restart,
MACHINE_END
#endif
+
+#ifdef CONFIG_ARCH_MARCO
+static const char *marco_dt_match[] __initdata = {
+ "sirf,marco",
+ NULL
+};
+
+DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)")
+ /* Maintainer: Barry Song <baohua.song@csr.com> */
+ .smp = smp_ops(sirfsoc_smp_ops),
+ .map_io = sirfsoc_map_io,
+ .init_irq = irqchip_init,
+ .init_time = sirfsoc_marco_timer_init,
+ .init_machine = sirfsoc_mach_init,
+ .init_late = sirfsoc_init_late,
+ .dt_compat = marco_dt_match,
+ .restart = sirfsoc_restart,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
index 60d826fc2185..b7c26b62e4a7 100644
--- a/arch/arm/mach-prima2/common.h
+++ b/arch/arm/mach-prima2/common.h
@@ -11,12 +11,19 @@
#include <linux/init.h>
#include <asm/mach/time.h>
+#include <asm/exception.h>
-extern struct sys_timer sirfsoc_timer;
+extern void sirfsoc_prima2_timer_init(void);
+extern void sirfsoc_marco_timer_init(void);
+
+extern struct smp_operations sirfsoc_smp_ops;
+extern void sirfsoc_secondary_startup(void);
+extern void sirfsoc_cpu_die(unsigned int cpu);
extern void __init sirfsoc_of_irq_init(void);
extern void __init sirfsoc_of_clk_init(void);
extern void sirfsoc_restart(char, const char *);
+extern asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs);
#ifndef CONFIG_DEBUG_LL
static inline void sirfsoc_map_lluart(void) {}
@@ -24,6 +31,12 @@ static inline void sirfsoc_map_lluart(void) {}
extern void __init sirfsoc_map_lluart(void);
#endif
+#ifndef CONFIG_SMP
+static inline void sirfsoc_map_scu(void) {}
+#else
+extern void sirfsoc_map_scu(void);
+#endif
+
#ifdef CONFIG_SUSPEND
extern int sirfsoc_pm_init(void);
#else
diff --git a/arch/arm/mach-prima2/headsmp.S b/arch/arm/mach-prima2/headsmp.S
new file mode 100644
index 000000000000..5b8a408d8921
--- /dev/null
+++ b/arch/arm/mach-prima2/headsmp.S
@@ -0,0 +1,40 @@
+/*
+ * Entry of the second core for CSR Marco dual-core SMP SoCs
+ *
+ * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+ __CPUINIT
+
+/*
+ * SIRFSOC specific entry point for secondary CPUs. This provides
+ * a "holding pen" into which all secondary cores are held until we're
+ * ready for them to initialise.
+ */
+ENTRY(sirfsoc_secondary_startup)
+ bl v7_invalidate_l1
+ mrc p15, 0, r0, c0, c0, 5
+ and r0, r0, #15
+ adr r4, 1f
+ ldmia r4, {r5, r6}
+ sub r4, r4, r5
+ add r6, r6, r4
+pen: ldr r7, [r6]
+ cmp r7, r0
+ bne pen
+
+ /*
+ * we've been released from the holding pen: secondary_stack
+ * should now contain the SVC stack for this core
+ */
+ b secondary_startup
+ENDPROC(sirfsoc_secondary_startup)
+
+ .align
+1: .long .
+ .long pen_release
diff --git a/arch/arm/mach-prima2/hotplug.c b/arch/arm/mach-prima2/hotplug.c
new file mode 100644
index 000000000000..f4b17cbababd
--- /dev/null
+++ b/arch/arm/mach-prima2/hotplug.c
@@ -0,0 +1,41 @@
+/*
+ * CPU hotplug support for CSR Marco dual-core SMP SoCs
+ *
+ * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+
+static inline void platform_do_lowpower(unsigned int cpu)
+{
+ flush_cache_all();
+
+ /* we put the platform to just WFI */
+ for (;;) {
+ __asm__ __volatile__("dsb\n\t" "wfi\n\t"
+ : : : "memory");
+ if (pen_release == cpu_logical_map(cpu)) {
+ /*
+ * OK, proper wakeup, we're done
+ */
+ break;
+ }
+ }
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void __ref sirfsoc_cpu_die(unsigned int cpu)
+{
+ platform_do_lowpower(cpu);
+}
diff --git a/arch/arm/mach-prima2/include/mach/irqs.h b/arch/arm/mach-prima2/include/mach/irqs.h
index f6014a07541f..b778a0f248ed 100644
--- a/arch/arm/mach-prima2/include/mach/irqs.h
+++ b/arch/arm/mach-prima2/include/mach/irqs.h
@@ -10,8 +10,8 @@
#define __ASM_ARCH_IRQS_H
#define SIRFSOC_INTENAL_IRQ_START 0
-#define SIRFSOC_INTENAL_IRQ_END 59
+#define SIRFSOC_INTENAL_IRQ_END 127
#define SIRFSOC_GPIO_IRQ_START (SIRFSOC_INTENAL_IRQ_END + 1)
-#define NR_IRQS 220
+#define NR_IRQS 288
#endif
diff --git a/arch/arm/mach-prima2/include/mach/uart.h b/arch/arm/mach-prima2/include/mach/uart.h
index c98b4d5ac24a..c10510d01a44 100644
--- a/arch/arm/mach-prima2/include/mach/uart.h
+++ b/arch/arm/mach-prima2/include/mach/uart.h
@@ -10,7 +10,13 @@
#define __MACH_PRIMA2_SIRFSOC_UART_H
/* UART-1: used as serial debug port */
+#if defined(CONFIG_DEBUG_SIRFPRIMA2_UART1)
#define SIRFSOC_UART1_PA_BASE 0xb0060000
+#elif defined(CONFIG_DEBUG_SIRFMARCO_UART1)
+#define SIRFSOC_UART1_PA_BASE 0xcc060000
+#else
+#define SIRFSOC_UART1_PA_BASE 0
+#endif
#define SIRFSOC_UART1_VA_BASE SIRFSOC_VA(0x060000)
#define SIRFSOC_UART1_SIZE SZ_4K
diff --git a/arch/arm/mach-prima2/include/mach/uncompress.h b/arch/arm/mach-prima2/include/mach/uncompress.h
index 0c898fcf909c..d1513a33709a 100644
--- a/arch/arm/mach-prima2/include/mach/uncompress.h
+++ b/arch/arm/mach-prima2/include/mach/uncompress.h
@@ -17,14 +17,15 @@ void arch_decomp_setup(void)
{
}
-#define arch_decomp_wdog()
-
static __inline__ void putc(char c)
{
/*
* during kernel decompression, all mappings are flat:
* virt_addr == phys_addr
*/
+ if (!SIRFSOC_UART1_PA_BASE)
+ return;
+
while (__raw_readl((void __iomem *)SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_STATUS)
& SIRFSOC_UART1_TXFIFO_FULL)
barrier();
diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c
index 7dee9176e77a..6c0f3e9c43fb 100644
--- a/arch/arm/mach-prima2/irq.c
+++ b/arch/arm/mach-prima2/irq.c
@@ -9,17 +9,19 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <mach/hardware.h>
-#include <asm/mach/irq.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/irqdomain.h>
#include <linux/syscore_ops.h>
+#include <asm/mach/irq.h>
+#include <asm/exception.h>
+#include <mach/hardware.h>
#define SIRFSOC_INT_RISC_MASK0 0x0018
#define SIRFSOC_INT_RISC_MASK1 0x001C
#define SIRFSOC_INT_RISC_LEVEL0 0x0020
#define SIRFSOC_INT_RISC_LEVEL1 0x0024
+#define SIRFSOC_INIT_IRQ_ID 0x0038
void __iomem *sirfsoc_intc_base;
@@ -52,6 +54,16 @@ static __init void sirfsoc_irq_init(void)
writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK1);
}
+asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
+{
+ u32 irqstat, irqnr;
+
+ irqstat = readl_relaxed(sirfsoc_intc_base + SIRFSOC_INIT_IRQ_ID);
+ irqnr = irqstat & 0xff;
+
+ handle_IRQ(irqnr, regs);
+}
+
static struct of_device_id intc_ids[] = {
{ .compatible = "sirf,prima2-intc" },
{},
diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c
index c99837797d76..cbcbe9cb094c 100644
--- a/arch/arm/mach-prima2/l2x0.c
+++ b/arch/arm/mach-prima2/l2x0.c
@@ -11,19 +11,38 @@
#include <linux/of.h>
#include <asm/hardware/cache-l2x0.h>
-static struct of_device_id prima2_l2x0_ids[] = {
- { .compatible = "sirf,prima2-pl310-cache" },
+struct l2x0_aux
+{
+ u32 val;
+ u32 mask;
+};
+
+static struct l2x0_aux prima2_l2x0_aux __initconst = {
+ .val = 2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT,
+ .mask = 0,
+};
+
+static struct l2x0_aux marco_l2x0_aux __initconst = {
+ .val = (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) |
+ (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT),
+ .mask = L2X0_AUX_CTRL_MASK,
+};
+
+static struct of_device_id sirf_l2x0_ids[] __initconst = {
+ { .compatible = "sirf,prima2-pl310-cache", .data = &prima2_l2x0_aux, },
+ { .compatible = "sirf,marco-pl310-cache", .data = &marco_l2x0_aux, },
{},
};
static int __init sirfsoc_l2x0_init(void)
{
struct device_node *np;
+ const struct l2x0_aux *aux;
- np = of_find_matching_node(NULL, prima2_l2x0_ids);
+ np = of_find_matching_node(NULL, sirf_l2x0_ids);
if (np) {
- pr_info("Initializing prima2 L2 cache\n");
- return l2x0_of_init(0x40000, 0);
+ aux = of_match_node(sirf_l2x0_ids, np)->data;
+ return l2x0_of_init(aux->val, aux->mask);
}
return 0;
diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c
new file mode 100644
index 000000000000..4b788310f6a6
--- /dev/null
+++ b/arch/arm/mach-prima2/platsmp.c
@@ -0,0 +1,157 @@
+/*
+ * plat smp support for CSR Marco dual-core SMP SoCs
+ *
+ * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/irqchip/arm-gic.h>
+#include <asm/page.h>
+#include <asm/mach/map.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <mach/map.h>
+
+#include "common.h"
+
+static void __iomem *scu_base;
+static void __iomem *rsc_base;
+
+static DEFINE_SPINLOCK(boot_lock);
+
+static struct map_desc scu_io_desc __initdata = {
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+};
+
+void __init sirfsoc_map_scu(void)
+{
+ unsigned long base;
+
+ /* Get SCU base */
+ asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
+
+ scu_io_desc.virtual = SIRFSOC_VA(base);
+ scu_io_desc.pfn = __phys_to_pfn(base);
+ iotable_init(&scu_io_desc, 1);
+
+ scu_base = (void __iomem *)SIRFSOC_VA(base);
+}
+
+static void __cpuinit sirfsoc_secondary_init(unsigned int cpu)
+{
+ /*
+ * if any interrupts are already enabled for the primary
+ * core (e.g. timer irq), then they will not have been enabled
+ * for us: do so
+ */
+ gic_secondary_init(0);
+
+ /*
+ * let the primary processor know we're out of the
+ * pen, then head off into the C entry point
+ */
+ pen_release = -1;
+ smp_wmb();
+
+ /*
+ * Synchronise with the boot thread.
+ */
+ spin_lock(&boot_lock);
+ spin_unlock(&boot_lock);
+}
+
+static struct of_device_id rsc_ids[] = {
+ { .compatible = "sirf,marco-rsc" },
+ {},
+};
+
+static int __cpuinit sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ unsigned long timeout;
+ struct device_node *np;
+
+ np = of_find_matching_node(NULL, rsc_ids);
+ if (!np)
+ return -ENODEV;
+
+ rsc_base = of_iomap(np, 0);
+ if (!rsc_base)
+ return -ENOMEM;
+
+ /*
+ * write the address of secondary startup into the sram register
+ * at offset 0x2C, then write the magic number 0x3CAF5D62 to the
+ * RSC register at offset 0x28, which is what boot rom code is
+ * waiting for. This would wake up the secondary core from WFE
+ */
+#define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x2C
+ __raw_writel(virt_to_phys(sirfsoc_secondary_startup),
+ rsc_base + SIRFSOC_CPU1_JUMPADDR_OFFSET);
+
+#define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x28
+ __raw_writel(0x3CAF5D62,
+ rsc_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET);
+
+ /* make sure write buffer is drained */
+ mb();
+
+ spin_lock(&boot_lock);
+
+ /*
+ * The secondary processor is waiting to be released from
+ * the holding pen - release it, then wait for it to flag
+ * that it has been released by resetting pen_release.
+ *
+ * Note that "pen_release" is the hardware CPU ID, whereas
+ * "cpu" is Linux's internal ID.
+ */
+ pen_release = cpu_logical_map(cpu);
+ __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+ outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+
+ /*
+ * Send the secondary CPU SEV, thereby causing the boot monitor to read
+ * the JUMPADDR and WAKEMAGIC, and branch to the address found there.
+ */
+ dsb_sev();
+
+ timeout = jiffies + (1 * HZ);
+ while (time_before(jiffies, timeout)) {
+ smp_rmb();
+ if (pen_release == -1)
+ break;
+
+ udelay(10);
+ }
+
+ /*
+ * now the secondary core is starting up let it run its
+ * calibrations, then wait for it to finish
+ */
+ spin_unlock(&boot_lock);
+
+ return pen_release != -1 ? -ENOSYS : 0;
+}
+
+static void __init sirfsoc_smp_prepare_cpus(unsigned int max_cpus)
+{
+ scu_enable(scu_base);
+}
+
+struct smp_operations sirfsoc_smp_ops __initdata = {
+ .smp_prepare_cpus = sirfsoc_smp_prepare_cpus,
+ .smp_secondary_init = sirfsoc_secondary_init,
+ .smp_boot_secondary = sirfsoc_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = sirfsoc_cpu_die,
+#endif
+};
diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c
index 762adb73ab7c..435019ca0a48 100644
--- a/arch/arm/mach-prima2/rstc.c
+++ b/arch/arm/mach-prima2/rstc.c
@@ -19,6 +19,7 @@ static DEFINE_MUTEX(rstc_lock);
static struct of_device_id rstc_ids[] = {
{ .compatible = "sirf,prima2-rstc" },
+ { .compatible = "sirf,marco-rstc" },
{},
};
@@ -42,27 +43,37 @@ early_initcall(sirfsoc_of_rstc_init);
int sirfsoc_reset_device(struct device *dev)
{
- const unsigned int *prop = of_get_property(dev->of_node, "reset-bit", NULL);
- unsigned int reset_bit;
+ u32 reset_bit;
- if (!prop)
- return -ENODEV;
-
- reset_bit = be32_to_cpup(prop);
+ if (of_property_read_u32(dev->of_node, "reset-bit", &reset_bit))
+ return -EINVAL;
mutex_lock(&rstc_lock);
- /*
- * Writing 1 to this bit resets corresponding block. Writing 0 to this
- * bit de-asserts reset signal of the corresponding block.
- * datasheet doesn't require explicit delay between the set and clear
- * of reset bit. it could be shorter if tests pass.
- */
- writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit,
- sirfsoc_rstc_base + (reset_bit / 32) * 4);
- msleep(10);
- writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit,
- sirfsoc_rstc_base + (reset_bit / 32) * 4);
+ if (of_device_is_compatible(dev->of_node, "sirf,prima2-rstc")) {
+ /*
+ * Writing 1 to this bit resets corresponding block. Writing 0 to this
+ * bit de-asserts reset signal of the corresponding block.
+ * datasheet doesn't require explicit delay between the set and clear
+ * of reset bit. it could be shorter if tests pass.
+ */
+ writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit,
+ sirfsoc_rstc_base + (reset_bit / 32) * 4);
+ msleep(10);
+ writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit,
+ sirfsoc_rstc_base + (reset_bit / 32) * 4);
+ } else {
+ /*
+ * For MARCO and POLO
+ * Writing 1 to SET register resets corresponding block. Writing 1 to CLEAR
+ * register de-asserts reset signal of the corresponding block.
+ * datasheet doesn't require explicit delay between the set and clear
+ * of reset bit. it could be shorter if tests pass.
+ */
+ writel(reset_bit, sirfsoc_rstc_base + (reset_bit / 32) * 8);
+ msleep(10);
+ writel(reset_bit, sirfsoc_rstc_base + (reset_bit / 32) * 8 + 4);
+ }
mutex_unlock(&rstc_lock);
diff --git a/arch/arm/mach-prima2/rtciobrg.c b/arch/arm/mach-prima2/rtciobrg.c
index 557353602130..9f2da2eec4dc 100644
--- a/arch/arm/mach-prima2/rtciobrg.c
+++ b/arch/arm/mach-prima2/rtciobrg.c
@@ -104,6 +104,7 @@ EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_writel);
static const struct of_device_id rtciobrg_ids[] = {
{ .compatible = "sirf,prima2-rtciobg" },
+ { .compatible = "sirf,marco-rtciobg" },
{}
};
diff --git a/arch/arm/mach-prima2/timer-marco.c b/arch/arm/mach-prima2/timer-marco.c
new file mode 100644
index 000000000000..f4eea2e97eb0
--- /dev/null
+++ b/arch/arm/mach-prima2/timer-marco.c
@@ -0,0 +1,316 @@
+/*
+ * System timer for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <asm/sched_clock.h>
+#include <asm/localtimer.h>
+#include <asm/mach/time.h>
+
+#include "common.h"
+
+#define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000
+#define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004
+#define SIRFSOC_TIMER_MATCH_0 0x0018
+#define SIRFSOC_TIMER_MATCH_1 0x001c
+#define SIRFSOC_TIMER_COUNTER_0 0x0048
+#define SIRFSOC_TIMER_COUNTER_1 0x004c
+#define SIRFSOC_TIMER_INTR_STATUS 0x0060
+#define SIRFSOC_TIMER_WATCHDOG_EN 0x0064
+#define SIRFSOC_TIMER_64COUNTER_CTRL 0x0068
+#define SIRFSOC_TIMER_64COUNTER_LO 0x006c
+#define SIRFSOC_TIMER_64COUNTER_HI 0x0070
+#define SIRFSOC_TIMER_64COUNTER_LOAD_LO 0x0074
+#define SIRFSOC_TIMER_64COUNTER_LOAD_HI 0x0078
+#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO 0x007c
+#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI 0x0080
+
+#define SIRFSOC_TIMER_REG_CNT 6
+
+static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
+ SIRFSOC_TIMER_WATCHDOG_EN,
+ SIRFSOC_TIMER_32COUNTER_0_CTRL,
+ SIRFSOC_TIMER_32COUNTER_1_CTRL,
+ SIRFSOC_TIMER_64COUNTER_CTRL,
+ SIRFSOC_TIMER_64COUNTER_RLATCHED_LO,
+ SIRFSOC_TIMER_64COUNTER_RLATCHED_HI,
+};
+
+static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
+
+static void __iomem *sirfsoc_timer_base;
+static void __init sirfsoc_of_timer_map(void);
+
+/* disable count and interrupt */
+static inline void sirfsoc_timer_count_disable(int idx)
+{
+ writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7,
+ sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
+}
+
+/* enable count and interrupt */
+static inline void sirfsoc_timer_count_enable(int idx)
+{
+ writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x7,
+ sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
+}
+
+/* timer interrupt handler */
+static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *ce = dev_id;
+ int cpu = smp_processor_id();
+
+ /* clear timer interrupt */
+ writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
+
+ if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
+ sirfsoc_timer_count_disable(cpu);
+
+ ce->event_handler(ce);
+
+ return IRQ_HANDLED;
+}
+
+/* read 64-bit timer counter */
+static cycle_t sirfsoc_timer_read(struct clocksource *cs)
+{
+ u64 cycles;
+
+ writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
+ BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+
+ cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI);
+ cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO);
+
+ return cycles;
+}
+
+static int sirfsoc_timer_set_next_event(unsigned long delta,
+ struct clock_event_device *ce)
+{
+ int cpu = smp_processor_id();
+
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 +
+ 4 * cpu);
+ writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 +
+ 4 * cpu);
+
+ /* enable the tick */
+ sirfsoc_timer_count_enable(cpu);
+
+ return 0;
+}
+
+static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *ce)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* enable in set_next_event */
+ break;
+ default:
+ break;
+ }
+
+ sirfsoc_timer_count_disable(smp_processor_id());
+}
+
+static void sirfsoc_clocksource_suspend(struct clocksource *cs)
+{
+ int i;
+
+ for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
+ sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
+}
+
+static void sirfsoc_clocksource_resume(struct clocksource *cs)
+{
+ int i;
+
+ for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
+ writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
+
+ writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
+ sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
+ writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
+ sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
+
+ writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
+ BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+}
+
+static struct clock_event_device sirfsoc_clockevent = {
+ .name = "sirfsoc_clockevent",
+ .rating = 200,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = sirfsoc_timer_set_mode,
+ .set_next_event = sirfsoc_timer_set_next_event,
+};
+
+static struct clocksource sirfsoc_clocksource = {
+ .name = "sirfsoc_clocksource",
+ .rating = 200,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .read = sirfsoc_timer_read,
+ .suspend = sirfsoc_clocksource_suspend,
+ .resume = sirfsoc_clocksource_resume,
+};
+
+static struct irqaction sirfsoc_timer_irq = {
+ .name = "sirfsoc_timer0",
+ .flags = IRQF_TIMER | IRQF_NOBALANCING,
+ .handler = sirfsoc_timer_interrupt,
+ .dev_id = &sirfsoc_clockevent,
+};
+
+#ifdef CONFIG_LOCAL_TIMERS
+
+static struct irqaction sirfsoc_timer1_irq = {
+ .name = "sirfsoc_timer1",
+ .flags = IRQF_TIMER | IRQF_NOBALANCING,
+ .handler = sirfsoc_timer_interrupt,
+};
+
+static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce)
+{
+ /* Use existing clock_event for cpu 0 */
+ if (!smp_processor_id())
+ return 0;
+
+ ce->irq = sirfsoc_timer1_irq.irq;
+ ce->name = "local_timer";
+ ce->features = sirfsoc_clockevent.features;
+ ce->rating = sirfsoc_clockevent.rating;
+ ce->set_mode = sirfsoc_timer_set_mode;
+ ce->set_next_event = sirfsoc_timer_set_next_event;
+ ce->shift = sirfsoc_clockevent.shift;
+ ce->mult = sirfsoc_clockevent.mult;
+ ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns;
+ ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns;
+
+ sirfsoc_timer1_irq.dev_id = ce;
+ BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq));
+ irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1));
+
+ clockevents_register_device(ce);
+ return 0;
+}
+
+static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
+{
+ sirfsoc_timer_count_disable(1);
+
+ remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
+}
+
+static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = {
+ .setup = sirfsoc_local_timer_setup,
+ .stop = sirfsoc_local_timer_stop,
+};
+#endif /* CONFIG_LOCAL_TIMERS */
+
+static void __init sirfsoc_clockevent_init(void)
+{
+ clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60);
+
+ sirfsoc_clockevent.max_delta_ns =
+ clockevent_delta2ns(-2, &sirfsoc_clockevent);
+ sirfsoc_clockevent.min_delta_ns =
+ clockevent_delta2ns(2, &sirfsoc_clockevent);
+
+ sirfsoc_clockevent.cpumask = cpumask_of(0);
+ clockevents_register_device(&sirfsoc_clockevent);
+#ifdef CONFIG_LOCAL_TIMERS
+ local_timer_register(&sirfsoc_local_timer_ops);
+#endif
+}
+
+/* initialize the kernel jiffy timer source */
+void __init sirfsoc_marco_timer_init(void)
+{
+ unsigned long rate;
+ u32 timer_div;
+ struct clk *clk;
+
+ /* initialize clocking early, we want to set the OS timer */
+ sirfsoc_of_clk_init();
+
+ /* timer's input clock is io clock */
+ clk = clk_get_sys("io", NULL);
+
+ BUG_ON(IS_ERR(clk));
+ rate = clk_get_rate(clk);
+
+ BUG_ON(rate < CLOCK_TICK_RATE);
+ BUG_ON(rate % CLOCK_TICK_RATE);
+
+ sirfsoc_of_timer_map();
+
+ /* Initialize the timer dividers */
+ timer_div = rate / CLOCK_TICK_RATE - 1;
+ writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+ writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
+ writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);
+
+ /* Initialize timer counters to 0 */
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
+ writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
+ BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0);
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1);
+
+ /* Clear all interrupts */
+ writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
+
+ BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
+
+ BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
+
+ sirfsoc_clockevent_init();
+}
+
+static struct of_device_id timer_ids[] = {
+ { .compatible = "sirf,marco-tick" },
+ {},
+};
+
+static void __init sirfsoc_of_timer_map(void)
+{
+ struct device_node *np;
+
+ np = of_find_matching_node(NULL, timer_ids);
+ if (!np)
+ return;
+ sirfsoc_timer_base = of_iomap(np, 0);
+ if (!sirfsoc_timer_base)
+ panic("unable to map timer cpu registers\n");
+
+ sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
+ if (!sirfsoc_timer_irq.irq)
+ panic("No irq passed for timer0 via DT\n");
+
+#ifdef CONFIG_LOCAL_TIMERS
+ sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
+ if (!sirfsoc_timer1_irq.irq)
+ panic("No irq passed for timer1 via DT\n");
+#endif
+
+ of_node_put(np);
+}
diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer-prima2.c
index d95bf252f694..6da584f8a949 100644
--- a/arch/arm/mach-prima2/timer.c
+++ b/arch/arm/mach-prima2/timer-prima2.c
@@ -175,19 +175,13 @@ static u32 notrace sirfsoc_read_sched_clock(void)
static void __init sirfsoc_clockevent_init(void)
{
- clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60);
-
- sirfsoc_clockevent.max_delta_ns =
- clockevent_delta2ns(-2, &sirfsoc_clockevent);
- sirfsoc_clockevent.min_delta_ns =
- clockevent_delta2ns(2, &sirfsoc_clockevent);
-
sirfsoc_clockevent.cpumask = cpumask_of(0);
- clockevents_register_device(&sirfsoc_clockevent);
+ clockevents_config_and_register(&sirfsoc_clockevent, CLOCK_TICK_RATE,
+ 2, -2);
}
/* initialize the kernel jiffy timer source */
-static void __init sirfsoc_timer_init(void)
+void __init sirfsoc_prima2_timer_init(void)
{
unsigned long rate;
struct clk *clk;
@@ -233,7 +227,7 @@ static void __init sirfsoc_of_timer_map(void)
np = of_find_matching_node(NULL, timer_ids);
if (!np)
- panic("unable to find compatible timer node in dtb\n");
+ return;
sirfsoc_timer_base = of_iomap(np, 0);
if (!sirfsoc_timer_base)
panic("unable to map timer cpu registers\n");
@@ -245,7 +239,3 @@ static void __init sirfsoc_of_timer_map(void)
of_node_put(np);
}
-
-struct sys_timer sirfsoc_timer = {
- .init = sirfsoc_timer_init,
-};
diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c
index 208229342514..2f71b3fbd319 100644
--- a/arch/arm/mach-pxa/balloon3.c
+++ b/arch/arm/mach-pxa/balloon3.c
@@ -822,7 +822,7 @@ MACHINE_START(BALLOON3, "Balloon3")
.nr_irqs = BALLOON3_NR_IRQS,
.init_irq = balloon3_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = balloon3_init,
.atag_offset = 0x100,
.restart = pxa_restart,
diff --git a/arch/arm/mach-pxa/capc7117.c b/arch/arm/mach-pxa/capc7117.c
index 9a8760b72913..c092730749b9 100644
--- a/arch/arm/mach-pxa/capc7117.c
+++ b/arch/arm/mach-pxa/capc7117.c
@@ -153,7 +153,7 @@ MACHINE_START(CAPC7117,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = capc7117_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/cm-x2xx.c b/arch/arm/mach-pxa/cm-x2xx.c
index a103c8ffea9f..bb99f59a36d8 100644
--- a/arch/arm/mach-pxa/cm-x2xx.c
+++ b/arch/arm/mach-pxa/cm-x2xx.c
@@ -520,7 +520,7 @@ MACHINE_START(ARMCORE, "Compulab CM-X2XX")
.init_irq = cmx2xx_init_irq,
/* NOTE: pxa25x_handle_irq() works on PXA27x w/o camera support */
.handle_irq = pxa25x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = cmx2xx_init,
#ifdef CONFIG_PCI
.dma_zone_size = SZ_64M,
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index cc2b23afcaaf..8091aac89edf 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -854,7 +854,7 @@ MACHINE_START(CM_X300, "CM-X300 module")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = cm_x300_init,
.fixup = cm_x300_fixup,
.restart = pxa_restart,
diff --git a/arch/arm/mach-pxa/colibri-pxa270.c b/arch/arm/mach-pxa/colibri-pxa270.c
index b2f227d36125..5f9d9303b346 100644
--- a/arch/arm/mach-pxa/colibri-pxa270.c
+++ b/arch/arm/mach-pxa/colibri-pxa270.c
@@ -313,7 +313,7 @@ MACHINE_START(COLIBRI, "Toradex Colibri PXA270")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
@@ -324,7 +324,7 @@ MACHINE_START(INCOME, "Income s.r.o. SH-Dmaster PXA270 SBC")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/colibri-pxa300.c b/arch/arm/mach-pxa/colibri-pxa300.c
index a9c9c163dd95..f1a1ac1fbd85 100644
--- a/arch/arm/mach-pxa/colibri-pxa300.c
+++ b/arch/arm/mach-pxa/colibri-pxa300.c
@@ -189,7 +189,7 @@ MACHINE_START(COLIBRI300, "Toradex Colibri PXA300")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/colibri-pxa320.c b/arch/arm/mach-pxa/colibri-pxa320.c
index 25515cd7e68f..f6cc8b0ab82f 100644
--- a/arch/arm/mach-pxa/colibri-pxa320.c
+++ b/arch/arm/mach-pxa/colibri-pxa320.c
@@ -259,7 +259,7 @@ MACHINE_START(COLIBRI320, "Toradex Colibri PXA320")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 7c83f52c549c..a5b8fead7d61 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -733,7 +733,7 @@ MACHINE_START(CORGI, "SHARP Corgi")
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_machine = corgi_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = corgi_restart,
MACHINE_END
#endif
@@ -746,7 +746,7 @@ MACHINE_START(SHEPHERD, "SHARP Shepherd")
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_machine = corgi_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = corgi_restart,
MACHINE_END
#endif
@@ -759,7 +759,7 @@ MACHINE_START(HUSKY, "SHARP Husky")
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_machine = corgi_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = corgi_restart,
MACHINE_END
#endif
diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c
index 7039f44b3647..fadfff8feaef 100644
--- a/arch/arm/mach-pxa/csb726.c
+++ b/arch/arm/mach-pxa/csb726.c
@@ -278,6 +278,6 @@ MACHINE_START(CSB726, "Cogent CSB726")
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_machine = csb726_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 1b6411439ec8..446563a7d1ad 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -1298,7 +1298,7 @@ MACHINE_START(EM_X270, "Compulab EM-X270")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = em_x270_init,
.restart = pxa_restart,
MACHINE_END
@@ -1309,7 +1309,7 @@ MACHINE_START(EXEDA, "Compulab eXeda")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = em_x270_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c
index be2ee9bf5c6e..8280ebcaab9f 100644
--- a/arch/arm/mach-pxa/eseries.c
+++ b/arch/arm/mach-pxa/eseries.c
@@ -195,7 +195,7 @@ MACHINE_START(E330, "Toshiba e330")
.handle_irq = pxa25x_handle_irq,
.fixup = eseries_fixup,
.init_machine = e330_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
#endif
@@ -246,7 +246,7 @@ MACHINE_START(E350, "Toshiba e350")
.handle_irq = pxa25x_handle_irq,
.fixup = eseries_fixup,
.init_machine = e350_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
#endif
@@ -370,7 +370,7 @@ MACHINE_START(E400, "Toshiba e400")
.handle_irq = pxa25x_handle_irq,
.fixup = eseries_fixup,
.init_machine = e400_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
#endif
@@ -566,7 +566,7 @@ MACHINE_START(E740, "Toshiba e740")
.handle_irq = pxa25x_handle_irq,
.fixup = eseries_fixup,
.init_machine = e740_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
#endif
@@ -765,7 +765,7 @@ MACHINE_START(E750, "Toshiba e750")
.handle_irq = pxa25x_handle_irq,
.fixup = eseries_fixup,
.init_machine = e750_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
#endif
@@ -977,7 +977,7 @@ MACHINE_START(E800, "Toshiba e800")
.handle_irq = pxa25x_handle_irq,
.fixup = eseries_fixup,
.init_machine = e800_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
#endif
diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c
index dc58fa0edb66..dca10709be8f 100644
--- a/arch/arm/mach-pxa/ezx.c
+++ b/arch/arm/mach-pxa/ezx.c
@@ -802,7 +802,7 @@ MACHINE_START(EZX_A780, "Motorola EZX A780")
.nr_irqs = EZX_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = a780_init,
.restart = pxa_restart,
MACHINE_END
@@ -869,7 +869,7 @@ MACHINE_START(EZX_E680, "Motorola EZX E680")
.nr_irqs = EZX_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = e680_init,
.restart = pxa_restart,
MACHINE_END
@@ -936,7 +936,7 @@ MACHINE_START(EZX_A1200, "Motorola EZX A1200")
.nr_irqs = EZX_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = a1200_init,
.restart = pxa_restart,
MACHINE_END
@@ -1128,7 +1128,7 @@ MACHINE_START(EZX_A910, "Motorola EZX A910")
.nr_irqs = EZX_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = a910_init,
.restart = pxa_restart,
MACHINE_END
@@ -1195,7 +1195,7 @@ MACHINE_START(EZX_E6, "Motorola EZX E6")
.nr_irqs = EZX_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = e6_init,
.restart = pxa_restart,
MACHINE_END
@@ -1236,7 +1236,7 @@ MACHINE_START(EZX_E2, "Motorola EZX E2")
.nr_irqs = EZX_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = e2_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index 42d5cca66257..fd7ea39b78c0 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -10,9 +10,8 @@
*/
struct irq_data;
-struct sys_timer;
-extern struct sys_timer pxa_timer;
+extern void pxa_timer_init(void);
extern void __init pxa_map_io(void);
diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c
index 60755a6bb1c6..00b92dad7b81 100644
--- a/arch/arm/mach-pxa/gumstix.c
+++ b/arch/arm/mach-pxa/gumstix.c
@@ -238,7 +238,7 @@ MACHINE_START(GUMSTIX, "Gumstix")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = gumstix_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/h5000.c b/arch/arm/mach-pxa/h5000.c
index e7dec589f014..875ec3351499 100644
--- a/arch/arm/mach-pxa/h5000.c
+++ b/arch/arm/mach-pxa/h5000.c
@@ -208,7 +208,7 @@ MACHINE_START(H5400, "HP iPAQ H5000")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = h5000_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/himalaya.c b/arch/arm/mach-pxa/himalaya.c
index 2962de898da9..7a8d749a07b8 100644
--- a/arch/arm/mach-pxa/himalaya.c
+++ b/arch/arm/mach-pxa/himalaya.c
@@ -164,6 +164,6 @@ MACHINE_START(HIMALAYA, "HTC Himalaya")
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_machine = himalaya_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
index e2c6391863fe..133109ec7332 100644
--- a/arch/arm/mach-pxa/hx4700.c
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -900,6 +900,6 @@ MACHINE_START(H4700, "HP iPAQ HX4700")
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_machine = hx4700_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/icontrol.c b/arch/arm/mach-pxa/icontrol.c
index 1d02eabc9c65..fe31bfcbb8df 100644
--- a/arch/arm/mach-pxa/icontrol.c
+++ b/arch/arm/mach-pxa/icontrol.c
@@ -196,7 +196,7 @@ MACHINE_START(ICONTROL, "iControl/SafeTcam boards using Embedian MXM-8x10 CoM")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = icontrol_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index 64507cdd2e8f..343c4e3a7c5d 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -279,7 +279,7 @@ MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = idp_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/include/mach/palmtreo.h b/arch/arm/mach-pxa/include/mach/palmtreo.h
index 2d3f14e3be29..714b6574393e 100644
--- a/arch/arm/mach-pxa/include/mach/palmtreo.h
+++ b/arch/arm/mach-pxa/include/mach/palmtreo.h
@@ -38,13 +38,14 @@
#define GPIO_NR_TREO_LCD_POWER 25
/* Treo680 specific GPIOs */
-#ifdef CONFIG_MACH_TREO680
#define GPIO_NR_TREO680_SD_READONLY 33
#define GPIO_NR_TREO680_SD_POWER 42
#define GPIO_NR_TREO680_VIBRATE_EN 44
#define GPIO_NR_TREO680_KEYB_BL 24
#define GPIO_NR_TREO680_BT_EN 43
-#endif /* CONFIG_MACH_TREO680 */
+#define GPIO_NR_TREO680_LCD_POWER 77
+#define GPIO_NR_TREO680_LCD_EN 86
+#define GPIO_NR_TREO680_LCD_EN_N 25
/* Centro685 specific GPIOs */
#define GPIO_NR_CENTRO_SD_POWER 21
diff --git a/arch/arm/mach-pxa/include/mach/smemc.h b/arch/arm/mach-pxa/include/mach/smemc.h
index b7de471b273a..b802f285fe00 100644
--- a/arch/arm/mach-pxa/include/mach/smemc.h
+++ b/arch/arm/mach-pxa/include/mach/smemc.h
@@ -37,6 +37,7 @@
#define CSADRCFG1 (SMEMC_VIRT + 0x84) /* Address Configuration Register for CS1 */
#define CSADRCFG2 (SMEMC_VIRT + 0x88) /* Address Configuration Register for CS2 */
#define CSADRCFG3 (SMEMC_VIRT + 0x8C) /* Address Configuration Register for CS3 */
+#define CSMSADRCFG (SMEMC_VIRT + 0xA0) /* Chip Select Configuration Register */
/*
* More handy macros for PCMCIA
diff --git a/arch/arm/mach-pxa/include/mach/uncompress.h b/arch/arm/mach-pxa/include/mach/uncompress.h
index 5519a34b667f..8c27757e68ff 100644
--- a/arch/arm/mach-pxa/include/mach/uncompress.h
+++ b/arch/arm/mach-pxa/include/mach/uncompress.h
@@ -72,8 +72,3 @@ static inline void arch_decomp_setup(void)
uart_is_pxa = 0;
}
}
-
-/*
- * nothing to do
- */
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index 402874f9021f..e848c4607baf 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -443,7 +443,7 @@ MACHINE_START(LITTLETON, "Marvell Form Factor Development Platform (aka Littleto
.nr_irqs = LITTLETON_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = littleton_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index 1a63eaa89867..1255ee00f3d1 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -503,7 +503,7 @@ MACHINE_START(LOGICPD_PXA270, "LogicPD PXA270 Card Engine")
.nr_irqs = LPD270_NR_IRQS,
.init_irq = lpd270_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = lpd270_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 553056d9a3c5..d8a1be619f21 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -650,7 +650,7 @@ MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
.nr_irqs = LUBBOCK_NR_IRQS,
.init_irq = lubbock_init_irq,
.handle_irq = pxa25x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = lubbock_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index f7922404d941..f44532fc648b 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -774,6 +774,6 @@ MACHINE_START(MAGICIAN, "HTC Magician")
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_machine = magician_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index f27a61ee7ac7..7a12c1ba90ff 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -714,7 +714,7 @@ MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
.nr_irqs = MAINSTONE_NR_IRQS,
.init_irq = mainstone_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = mainstone_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index 2831308dba68..f8979b943cbf 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -762,6 +762,6 @@ MACHINE_START(MIOA701, "MIO A701")
.init_irq = &pxa27x_init_irq,
.handle_irq = &pxa27x_handle_irq,
.init_machine = mioa701_machine_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = mioa701_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/mp900.c b/arch/arm/mach-pxa/mp900.c
index 152efbf093f6..854f1f562d6b 100644
--- a/arch/arm/mach-pxa/mp900.c
+++ b/arch/arm/mach-pxa/mp900.c
@@ -93,7 +93,7 @@ static void __init mp900c_init(void)
/* Maintainer - Michael Petchkovsky <mkpetch@internode.on.net> */
MACHINE_START(NEC_MP900, "MobilePro900/C")
.atag_offset = 0x220100,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.map_io = pxa25x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c
index 8bcc96e3b0db..909b713e5789 100644
--- a/arch/arm/mach-pxa/palmld.c
+++ b/arch/arm/mach-pxa/palmld.c
@@ -347,7 +347,7 @@ MACHINE_START(PALMLD, "Palm LifeDrive")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = palmld_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c
index 5ca7b904a30e..5033fd07968f 100644
--- a/arch/arm/mach-pxa/palmt5.c
+++ b/arch/arm/mach-pxa/palmt5.c
@@ -208,7 +208,7 @@ MACHINE_START(PALMT5, "Palm Tungsten|T5")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = palmt5_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c
index ca924cfedfc0..100b176f7e88 100644
--- a/arch/arm/mach-pxa/palmtc.c
+++ b/arch/arm/mach-pxa/palmtc.c
@@ -542,7 +542,7 @@ MACHINE_START(PALMTC, "Palm Tungsten|C")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = palmtc_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c
index 32e0d7998355..0742721ced2d 100644
--- a/arch/arm/mach-pxa/palmte2.c
+++ b/arch/arm/mach-pxa/palmte2.c
@@ -363,7 +363,7 @@ MACHINE_START(PALMTE2, "Palm Tungsten|E2")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = palmte2_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/palmtreo.c b/arch/arm/mach-pxa/palmtreo.c
index 3f3c48f2f7ce..d82a50b4a803 100644
--- a/arch/arm/mach-pxa/palmtreo.c
+++ b/arch/arm/mach-pxa/palmtreo.c
@@ -98,9 +98,6 @@ static unsigned long treo_pin_config[] __initdata = {
GPIO96_KP_MKOUT_6,
GPIO93_KP_DKIN_0 | WAKEUP_ON_LEVEL_HIGH, /* Hotsync button */
- /* LCD */
- GPIOxx_LCD_TFT_16BPP,
-
/* Quick Capture Interface */
GPIO84_CIF_FV,
GPIO85_CIF_LV,
@@ -140,6 +137,12 @@ static unsigned long treo680_pin_config[] __initdata = {
/* MATRIX KEYPAD - different wake up source */
GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
GPIO99_KP_MKIN_5,
+
+ /* LCD... L_BIAS alt fn not configured on Treo680; is GPIO instead */
+ GPIOxx_LCD_16BPP,
+ GPIO74_LCD_FCLK,
+ GPIO75_LCD_LCLK,
+ GPIO76_LCD_PCLK,
};
#endif /* CONFIG_MACH_TREO680 */
@@ -155,13 +158,16 @@ static unsigned long centro685_pin_config[] __initdata = {
/* MATRIX KEYPAD - different wake up source */
GPIO100_KP_MKIN_0,
GPIO99_KP_MKIN_5 | WAKEUP_ON_LEVEL_HIGH,
+
+ /* LCD */
+ GPIOxx_LCD_TFT_16BPP,
};
#endif /* CONFIG_MACH_CENTRO */
/******************************************************************************
* GPIO keyboard
******************************************************************************/
-#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
+#if IS_ENABLED(CONFIG_KEYBOARD_PXA27x)
static unsigned int treo680_matrix_keys[] = {
KEY(0, 0, KEY_F8), /* Red/Off/Power */
KEY(0, 1, KEY_LEFT),
@@ -309,7 +315,7 @@ static inline void palmtreo_kpc_init(void) {}
/******************************************************************************
* USB host
******************************************************************************/
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
static struct pxaohci_platform_data treo680_ohci_info = {
.port_mode = PMM_PERPORT_MODE,
.flags = ENABLE_PORT1 | ENABLE_PORT3,
@@ -328,7 +334,6 @@ static inline void palmtreo_uhc_init(void) {}
/******************************************************************************
* Vibra and LEDs
******************************************************************************/
-#ifdef CONFIG_MACH_TREO680
static struct gpio_led treo680_gpio_leds[] = {
{
.name = "treo680:vibra:vibra",
@@ -379,20 +384,46 @@ static struct gpio_led_platform_data centro_gpio_led_info = {
static struct platform_device palmtreo_leds = {
.name = "leds-gpio",
.id = -1,
- .dev = {
- .platform_data = &treo680_gpio_led_info,
- }
};
static void __init palmtreo_leds_init(void)
{
if (machine_is_centro())
palmtreo_leds.dev.platform_data = &centro_gpio_led_info;
+ else if (machine_is_treo680())
+ palmtreo_leds.dev.platform_data = &treo680_gpio_led_info;
platform_device_register(&palmtreo_leds);
}
+
+/******************************************************************************
+ * diskonchip docg4 flash
+ ******************************************************************************/
+#if defined(CONFIG_MACH_TREO680)
+/* REVISIT: does the centro have this device also? */
+#if IS_ENABLED(CONFIG_MTD_NAND_DOCG4)
+static struct resource docg4_resources[] = {
+ {
+ .start = 0x00000000,
+ .end = 0x00001FFF,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device treo680_docg4_flash = {
+ .name = "docg4",
+ .id = -1,
+ .resource = docg4_resources,
+ .num_resources = ARRAY_SIZE(docg4_resources),
+};
+
+static void __init treo680_docg4_flash_init(void)
+{
+ platform_device_register(&treo680_docg4_flash);
+}
#else
-static inline void palmtreo_leds_init(void) {}
+static inline void treo680_docg4_flash_init(void) {}
+#endif
#endif
/******************************************************************************
@@ -424,12 +455,62 @@ static void __init palmphone_common_init(void)
}
#ifdef CONFIG_MACH_TREO680
+void __init treo680_gpio_init(void)
+{
+ unsigned int gpio;
+
+ /* drive all three lcd gpios high initially */
+ const unsigned long lcd_flags = GPIOF_INIT_HIGH | GPIOF_DIR_OUT;
+
+ /*
+ * LCD GPIO initialization...
+ */
+
+ /*
+ * This is likely the power to the lcd. Toggling it low/high appears to
+ * turn the lcd off/on. Can be toggled after lcd is initialized without
+ * any apparent adverse effects to the lcd operation. Note that this
+ * gpio line is used by the lcd controller as the L_BIAS signal, but
+ * treo680 configures it as gpio.
+ */
+ gpio = GPIO_NR_TREO680_LCD_POWER;
+ if (gpio_request_one(gpio, lcd_flags, "LCD power") < 0)
+ goto fail;
+
+ /*
+ * These two are called "enables", for lack of a better understanding.
+ * If either of these are toggled after the lcd is initialized, the
+ * image becomes degraded. N.B. The IPL shipped with the treo
+ * configures GPIO_NR_TREO680_LCD_EN_N as output and drives it high. If
+ * the IPL is ever reprogrammed, this initialization may be need to be
+ * revisited.
+ */
+ gpio = GPIO_NR_TREO680_LCD_EN;
+ if (gpio_request_one(gpio, lcd_flags, "LCD enable") < 0)
+ goto fail;
+ gpio = GPIO_NR_TREO680_LCD_EN_N;
+ if (gpio_request_one(gpio, lcd_flags, "LCD enable_n") < 0)
+ goto fail;
+
+ /* driving this low turns LCD on */
+ gpio_set_value(GPIO_NR_TREO680_LCD_EN_N, 0);
+
+ return;
+ fail:
+ pr_err("gpio %d initialization failed\n", gpio);
+ gpio_free(GPIO_NR_TREO680_LCD_POWER);
+ gpio_free(GPIO_NR_TREO680_LCD_EN);
+ gpio_free(GPIO_NR_TREO680_LCD_EN_N);
+}
+
static void __init treo680_init(void)
{
pxa2xx_mfp_config(ARRAY_AND_SIZE(treo680_pin_config));
palmphone_common_init();
+ treo680_gpio_init();
palm27x_mmc_init(GPIO_NR_TREO_SD_DETECT_N, GPIO_NR_TREO680_SD_READONLY,
GPIO_NR_TREO680_SD_POWER, 0);
+ treo680_docg4_flash_init();
}
#endif
@@ -451,7 +532,7 @@ MACHINE_START(TREO680, "Palm Treo 680")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = treo680_init,
.restart = pxa_restart,
MACHINE_END
@@ -465,7 +546,7 @@ MACHINE_START(CENTRO, "Palm Centro 685")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = centro_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c
index 8b4366628a12..627c93a7364c 100644
--- a/arch/arm/mach-pxa/palmtx.c
+++ b/arch/arm/mach-pxa/palmtx.c
@@ -366,7 +366,7 @@ MACHINE_START(PALMTX, "Palm T|X")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = palmtx_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c
index 8cdd4f58e253..18b7fcd98592 100644
--- a/arch/arm/mach-pxa/palmz72.c
+++ b/arch/arm/mach-pxa/palmz72.c
@@ -404,7 +404,7 @@ MACHINE_START(PALMZ72, "Palm Zire72")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = palmz72_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/pcm027.c b/arch/arm/mach-pxa/pcm027.c
index fe9054435b6f..69918c7e3f1f 100644
--- a/arch/arm/mach-pxa/pcm027.c
+++ b/arch/arm/mach-pxa/pcm027.c
@@ -263,7 +263,7 @@ MACHINE_START(PCM027, "Phytec Messtechnik GmbH phyCORE-PXA270")
.nr_irqs = PCM027_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = pcm027_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 2910bb935c75..50ccd5f1d560 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -469,7 +469,7 @@ MACHINE_START(POODLE, "SHARP Poodle")
.nr_irqs = POODLE_NR_IRQS, /* 4 for LoCoMo */
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = poodle_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/pxa-dt.c b/arch/arm/mach-pxa/pxa-dt.c
index c9192cea0033..3835979a0dd3 100644
--- a/arch/arm/mach-pxa/pxa-dt.c
+++ b/arch/arm/mach-pxa/pxa-dt.c
@@ -55,7 +55,7 @@ DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)")
.map_io = pxa3xx_map_io,
.init_irq = pxa3xx_dt_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
.init_machine = pxa3xx_dt_init,
.dt_compat = pxa3xx_dt_board_compat,
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 616cb87b6179..3203a9f5b4a2 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -53,17 +53,25 @@ static unsigned long ac97_reset_config[] = {
GPIO95_AC97_nRESET,
};
-void pxa27x_assert_ac97reset(int reset_gpio, int on)
+void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio)
{
+ /*
+ * This helper function is used to work around a bug in the pxa27x's
+ * ac97 controller during a warm reset. The configuration of the
+ * reset_gpio is changed as follows:
+ * to_gpio == true: configured to generic output gpio and driven high
+ * to_gpio == false: configured to ac97 controller alt fn AC97_nRESET
+ */
+
if (reset_gpio == 113)
- pxa2xx_mfp_config(on ? &ac97_reset_config[0] :
- &ac97_reset_config[1], 1);
+ pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[0] :
+ &ac97_reset_config[1], 1);
if (reset_gpio == 95)
- pxa2xx_mfp_config(on ? &ac97_reset_config[2] :
- &ac97_reset_config[3], 1);
+ pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[2] :
+ &ac97_reset_config[3], 1);
}
-EXPORT_SYMBOL_GPL(pxa27x_assert_ac97reset);
+EXPORT_SYMBOL_GPL(pxa27x_configure_ac97reset);
/* Crystal clock: 13MHz */
#define BASE_CLK 13000000
@@ -230,6 +238,7 @@ static struct clk_lookup pxa27x_clkregs[] = {
INIT_CLKREG(&clk_pxa27x_memc, NULL, "MEMCLK"),
INIT_CLKREG(&clk_pxa27x_mem, "pxa2xx-pcmcia", NULL),
INIT_CLKREG(&clk_dummy, "pxa-gpio", NULL),
+ INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL),
};
#ifdef CONFIG_PM
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 25b08bfa997b..af41888acbd6 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -1095,7 +1095,7 @@ MACHINE_START(RAUMFELD_RC, "Raumfeld Controller")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
#endif
@@ -1108,7 +1108,7 @@ MACHINE_START(RAUMFELD_CONNECTOR, "Raumfeld Connector")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
#endif
@@ -1121,7 +1121,7 @@ MACHINE_START(RAUMFELD_SPEAKER, "Raumfeld Speaker")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
#endif
diff --git a/arch/arm/mach-pxa/saar.c b/arch/arm/mach-pxa/saar.c
index 08d87a5d2639..710c493eac89 100644
--- a/arch/arm/mach-pxa/saar.c
+++ b/arch/arm/mach-pxa/saar.c
@@ -601,7 +601,7 @@ MACHINE_START(SAAR, "PXA930 Handheld Platform (aka SAAR)")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = saar_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/smemc.c b/arch/arm/mach-pxa/smemc.c
index 79923058d10f..f38aa890b2c9 100644
--- a/arch/arm/mach-pxa/smemc.c
+++ b/arch/arm/mach-pxa/smemc.c
@@ -40,6 +40,8 @@ static void pxa3xx_smemc_resume(void)
__raw_writel(csadrcfg[1], CSADRCFG1);
__raw_writel(csadrcfg[2], CSADRCFG2);
__raw_writel(csadrcfg[3], CSADRCFG3);
+ /* CSMSADRCFG wakes up in its default state (0), so we need to set it */
+ __raw_writel(0x2, CSMSADRCFG);
}
static struct syscore_ops smemc_syscore_ops = {
@@ -49,8 +51,19 @@ static struct syscore_ops smemc_syscore_ops = {
static int __init smemc_init(void)
{
- if (cpu_is_pxa3xx())
+ if (cpu_is_pxa3xx()) {
+ /*
+ * The only documentation we have on the
+ * Chip Select Configuration Register (CSMSADRCFG) is that
+ * it must be programmed to 0x2.
+ * Moreover, in the bit definitions, the second bit
+ * (CSMSADRCFG[1]) is called "SETALWAYS".
+ * Other bits are reserved in this register.
+ */
+ __raw_writel(0x2, CSMSADRCFG);
+
register_syscore_ops(&smemc_syscore_ops);
+ }
return 0;
}
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 2073f0e6db0d..362726c49c70 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -732,7 +732,7 @@ static inline void spitz_lcd_init(void) {}
#endif
/******************************************************************************
- * Framebuffer
+ * NAND Flash
******************************************************************************/
#if defined(CONFIG_MTD_NAND_SHARPSL) || defined(CONFIG_MTD_NAND_SHARPSL_MODULE)
static struct mtd_partition spitz_nand_partitions[] = {
@@ -858,7 +858,7 @@ static inline void spitz_nor_init(void) {}
#endif
/******************************************************************************
- * GPIO expander
+ * I2C devices
******************************************************************************/
#if defined(CONFIG_I2C_PXA) || defined(CONFIG_I2C_PXA_MODULE)
static struct pca953x_platform_data akita_pca953x_pdata = {
@@ -986,7 +986,7 @@ MACHINE_START(SPITZ, "SHARP Spitz")
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_machine = spitz_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = spitz_restart,
MACHINE_END
#endif
@@ -1000,7 +1000,7 @@ MACHINE_START(BORZOI, "SHARP Borzoi")
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_machine = spitz_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = spitz_restart,
MACHINE_END
#endif
@@ -1014,7 +1014,7 @@ MACHINE_START(AKITA, "SHARP Akita")
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_machine = spitz_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = spitz_restart,
MACHINE_END
#endif
diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c
index 456560b5aad4..88fde43c948c 100644
--- a/arch/arm/mach-pxa/stargate2.c
+++ b/arch/arm/mach-pxa/stargate2.c
@@ -1006,7 +1006,7 @@ MACHINE_START(INTELMOTE2, "IMOTE 2")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = imote2_init,
.atag_offset = 0x100,
.restart = pxa_restart,
@@ -1019,7 +1019,7 @@ MACHINE_START(STARGATE2, "Stargate 2")
.nr_irqs = STARGATE_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = stargate2_init,
.atag_offset = 0x100,
.restart = pxa_restart,
diff --git a/arch/arm/mach-pxa/tavorevb.c b/arch/arm/mach-pxa/tavorevb.c
index 1a25f8a7b0ce..f55979c09a5f 100644
--- a/arch/arm/mach-pxa/tavorevb.c
+++ b/arch/arm/mach-pxa/tavorevb.c
@@ -494,7 +494,7 @@ MACHINE_START(TAVOREVB, "PXA930 Evaluation Board (aka TavorEVB)")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = tavorevb_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 4bc47d63698b..8f1ee92aea30 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -89,48 +89,10 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
}
}
-static struct clock_event_device ckevt_pxa_osmr0 = {
- .name = "osmr0",
- .features = CLOCK_EVT_FEAT_ONESHOT,
- .rating = 200,
- .set_next_event = pxa_osmr0_set_next_event,
- .set_mode = pxa_osmr0_set_mode,
-};
-
-static struct irqaction pxa_ost0_irq = {
- .name = "ost0",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = pxa_ost0_interrupt,
- .dev_id = &ckevt_pxa_osmr0,
-};
-
-static void __init pxa_timer_init(void)
-{
- unsigned long clock_tick_rate = get_clock_tick_rate();
-
- writel_relaxed(0, OIER);
- writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
-
- setup_sched_clock(pxa_read_sched_clock, 32, clock_tick_rate);
-
- clockevents_calc_mult_shift(&ckevt_pxa_osmr0, clock_tick_rate, 4);
- ckevt_pxa_osmr0.max_delta_ns =
- clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0);
- ckevt_pxa_osmr0.min_delta_ns =
- clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_pxa_osmr0) + 1;
- ckevt_pxa_osmr0.cpumask = cpumask_of(0);
-
- setup_irq(IRQ_OST0, &pxa_ost0_irq);
-
- clocksource_mmio_init(OSCR, "oscr0", clock_tick_rate, 200, 32,
- clocksource_mmio_readl_up);
- clockevents_register_device(&ckevt_pxa_osmr0);
-}
-
#ifdef CONFIG_PM
static unsigned long osmr[4], oier, oscr;
-static void pxa_timer_suspend(void)
+static void pxa_timer_suspend(struct clock_event_device *cedev)
{
osmr[0] = readl_relaxed(OSMR0);
osmr[1] = readl_relaxed(OSMR1);
@@ -140,7 +102,7 @@ static void pxa_timer_suspend(void)
oscr = readl_relaxed(OSCR);
}
-static void pxa_timer_resume(void)
+static void pxa_timer_resume(struct clock_event_device *cedev)
{
/*
* Ensure that we have at least MIN_OSCR_DELTA between match
@@ -163,8 +125,38 @@ static void pxa_timer_resume(void)
#define pxa_timer_resume NULL
#endif
-struct sys_timer pxa_timer = {
- .init = pxa_timer_init,
+static struct clock_event_device ckevt_pxa_osmr0 = {
+ .name = "osmr0",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 200,
+ .set_next_event = pxa_osmr0_set_next_event,
+ .set_mode = pxa_osmr0_set_mode,
.suspend = pxa_timer_suspend,
.resume = pxa_timer_resume,
};
+
+static struct irqaction pxa_ost0_irq = {
+ .name = "ost0",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = pxa_ost0_interrupt,
+ .dev_id = &ckevt_pxa_osmr0,
+};
+
+void __init pxa_timer_init(void)
+{
+ unsigned long clock_tick_rate = get_clock_tick_rate();
+
+ writel_relaxed(0, OIER);
+ writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
+
+ setup_sched_clock(pxa_read_sched_clock, 32, clock_tick_rate);
+
+ ckevt_pxa_osmr0.cpumask = cpumask_of(0);
+
+ setup_irq(IRQ_OST0, &pxa_ost0_irq);
+
+ clocksource_mmio_init(OSCR, "oscr0", clock_tick_rate, 200, 32,
+ clocksource_mmio_readl_up);
+ clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate,
+ MIN_OSCR_DELTA * 2, 0x7fffffff);
+}
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 233629edf7ee..9e7998d3635f 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -982,6 +982,6 @@ MACHINE_START(TOSA, "SHARP Tosa")
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
.init_machine = tosa_init,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = tosa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index fbbcbed4d1d4..c58043462acd 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -561,7 +561,7 @@ MACHINE_START(TRIZEPS4, "Keith und Koep Trizeps IV module")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
@@ -573,6 +573,6 @@ MACHINE_START(TRIZEPS4WL, "Keith und Koep Trizeps IV-WL module")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index c773e4dded64..9c363c081d3f 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -997,7 +997,7 @@ MACHINE_START(VIPER, "Arcom/Eurotech VIPER SBC")
.nr_irqs = PXA_NR_IRQS,
.init_irq = viper_init_irq,
.handle_irq = pxa25x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = viper_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c
index 491b6c9a2a9b..aa89488f961e 100644
--- a/arch/arm/mach-pxa/vpac270.c
+++ b/arch/arm/mach-pxa/vpac270.c
@@ -719,7 +719,7 @@ MACHINE_START(VPAC270, "Voipac PXA270")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = vpac270_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/xcep.c b/arch/arm/mach-pxa/xcep.c
index 4275713ccd10..13b1d4586d7d 100644
--- a/arch/arm/mach-pxa/xcep.c
+++ b/arch/arm/mach-pxa/xcep.c
@@ -185,7 +185,7 @@ MACHINE_START(XCEP, "Iskratel XCEP")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c
index 97529face7aa..989903a7e467 100644
--- a/arch/arm/mach-pxa/z2.c
+++ b/arch/arm/mach-pxa/z2.c
@@ -722,7 +722,7 @@ MACHINE_START(ZIPIT2, "Zipit Z2")
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = z2_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c
index abd3aa145083..f5d436434566 100644
--- a/arch/arm/mach-pxa/zeus.c
+++ b/arch/arm/mach-pxa/zeus.c
@@ -910,7 +910,7 @@ MACHINE_START(ARCOM_ZEUS, "Arcom/Eurotech ZEUS")
.nr_irqs = ZEUS_NR_IRQS,
.init_irq = zeus_init_irq,
.handle_irq = pxa27x_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = zeus_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 226279fac9d4..1f00d650ac27 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -428,7 +428,7 @@ MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
.nr_irqs = ZYLONITE_NR_IRQS,
.init_irq = pxa3xx_init_irq,
.handle_irq = pxa3xx_handle_irq,
- .timer = &pxa_timer,
+ .init_time = pxa_timer_init,
.init_machine = zylonite_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 682467480588..1d5ee5c9a1dc 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -42,7 +42,6 @@
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
-#include <asm/hardware/gic.h>
#include <mach/platform.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-realview/include/mach/irqs-eb.h b/arch/arm/mach-realview/include/mach/irqs-eb.h
index d6b5073692d2..44754230fdcc 100644
--- a/arch/arm/mach-realview/include/mach/irqs-eb.h
+++ b/arch/arm/mach-realview/include/mach/irqs-eb.h
@@ -115,7 +115,7 @@
/*
* Only define NR_IRQS if less than NR_IRQS_EB
*/
-#define NR_IRQS_EB (IRQ_EB_GIC_START + 96)
+#define NR_IRQS_EB (IRQ_EB_GIC_START + 128)
#if defined(CONFIG_MACH_REALVIEW_EB) \
&& (!defined(NR_IRQS) || (NR_IRQS < NR_IRQS_EB))
diff --git a/arch/arm/mach-realview/include/mach/uncompress.h b/arch/arm/mach-realview/include/mach/uncompress.h
index 83050378ffd2..cfa30d21783b 100644
--- a/arch/arm/mach-realview/include/mach/uncompress.h
+++ b/arch/arm/mach-realview/include/mach/uncompress.h
@@ -75,4 +75,3 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index 300f7064465d..98e3052b7933 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -14,7 +14,6 @@
#include <linux/io.h>
#include <mach/hardware.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <asm/smp_scu.h>
@@ -59,8 +58,6 @@ static void __init realview_smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 28511d43637a..5b1c8bfe6fa9 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -27,13 +27,13 @@
#include <linux/amba/mmci.h>
#include <linux/amba/pl022.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-realview.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/pgtable.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/smp_twd.h>
@@ -418,10 +418,6 @@ static void __init realview_eb_timer_init(void)
realview_eb_twd_init();
}
-static struct sys_timer realview_eb_timer = {
- .init = realview_eb_timer_init,
-};
-
static void realview_eb_restart(char mode, const char *cmd)
{
void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
@@ -472,8 +468,7 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
.map_io = realview_eb_map_io,
.init_early = realview_init_early,
.init_irq = gic_init_irq,
- .timer = &realview_eb_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = realview_eb_timer_init,
.init_machine = realview_eb_init,
#ifdef CONFIG_ZONE_DMA
.dma_zone_size = SZ_256M,
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index 07d6672ddae7..d5e83a1f6982 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -29,13 +29,13 @@
#include <linux/mtd/physmap.h>
#include <linux/mtd/partitions.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-realview.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/pgtable.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
@@ -329,10 +329,6 @@ static void __init realview_pb1176_timer_init(void)
realview_timer_init(IRQ_DC1176_TIMER0);
}
-static struct sys_timer realview_pb1176_timer = {
- .init = realview_pb1176_timer_init,
-};
-
static void realview_pb1176_restart(char mode, const char *cmd)
{
void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
@@ -384,8 +380,7 @@ MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
.map_io = realview_pb1176_map_io,
.init_early = realview_init_early,
.init_irq = gic_init_irq,
- .timer = &realview_pb1176_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = realview_pb1176_timer_init,
.init_machine = realview_pb1176_init,
#ifdef CONFIG_ZONE_DMA
.dma_zone_size = SZ_256M,
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index 7ed53d75350f..c3cfe213b5e6 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -27,13 +27,13 @@
#include <linux/amba/mmci.h>
#include <linux/amba/pl022.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-realview.h>
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/pgtable.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/smp_twd.h>
@@ -316,10 +316,6 @@ static void __init realview_pb11mp_timer_init(void)
realview_pb11mp_twd_init();
}
-static struct sys_timer realview_pb11mp_timer = {
- .init = realview_pb11mp_timer_init,
-};
-
static void realview_pb11mp_restart(char mode, const char *cmd)
{
void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
@@ -367,8 +363,7 @@ MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
.map_io = realview_pb11mp_map_io,
.init_early = realview_init_early,
.init_irq = gic_init_irq,
- .timer = &realview_pb11mp_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = realview_pb11mp_timer_init,
.init_machine = realview_pb11mp_init,
#ifdef CONFIG_ZONE_DMA
.dma_zone_size = SZ_256M,
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index 9992431b8a15..dde652a59620 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -27,12 +27,12 @@
#include <linux/amba/mmci.h>
#include <linux/amba/pl022.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-realview.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/pgtable.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -264,10 +264,6 @@ static void __init realview_pba8_timer_init(void)
realview_timer_init(IRQ_PBA8_TIMER0_1);
}
-static struct sys_timer realview_pba8_timer = {
- .init = realview_pba8_timer_init,
-};
-
static void realview_pba8_restart(char mode, const char *cmd)
{
void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
@@ -308,8 +304,7 @@ MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
.map_io = realview_pba8_map_io,
.init_early = realview_init_early,
.init_irq = gic_init_irq,
- .timer = &realview_pba8_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = realview_pba8_timer_init,
.init_machine = realview_pba8_init,
#ifdef CONFIG_ZONE_DMA
.dma_zone_size = SZ_256M,
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 4f486f05108a..54f0185b01e3 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -26,13 +26,13 @@
#include <linux/amba/mmci.h>
#include <linux/amba/pl022.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-realview.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/smp_twd.h>
#include <asm/pgtable.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
@@ -324,10 +324,6 @@ static void __init realview_pbx_timer_init(void)
realview_pbx_twd_init();
}
-static struct sys_timer realview_pbx_timer = {
- .init = realview_pbx_timer_init,
-};
-
static void realview_pbx_fixup(struct tag *tags, char **from,
struct meminfo *meminfo)
{
@@ -404,8 +400,7 @@ MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
.map_io = realview_pbx_map_io,
.init_early = realview_init_early,
.init_irq = gic_init_irq,
- .timer = &realview_pbx_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = realview_pbx_timer_init,
.init_machine = realview_pbx_init,
#ifdef CONFIG_ZONE_DMA
.dma_zone_size = SZ_256M,
diff --git a/arch/arm/mach-rpc/include/mach/uncompress.h b/arch/arm/mach-rpc/include/mach/uncompress.h
index 9cd9bcdad6cc..0fd4b0b8ef22 100644
--- a/arch/arm/mach-rpc/include/mach/uncompress.h
+++ b/arch/arm/mach-rpc/include/mach/uncompress.h
@@ -189,8 +189,3 @@ static void arch_decomp_setup(void)
if (nr_pages * page_size < 4096*1024) error("<4M of mem\n");
}
#endif
-
-/*
- * nothing to do
- */
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index f3fa259ce01f..a302cf5e0fc7 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -211,7 +211,7 @@ static void rpc_restart(char mode, const char *cmd)
soft_restart(0);
}
-extern struct sys_timer ioc_timer;
+void ioc_timer_init(void);
MACHINE_START(RISCPC, "Acorn-RiscPC")
/* Maintainer: Russell King */
@@ -220,6 +220,6 @@ MACHINE_START(RISCPC, "Acorn-RiscPC")
.reserve_lp1 = 1,
.map_io = rpc_map_io,
.init_irq = rpc_init_irq,
- .timer = &ioc_timer,
+ .init_time = ioc_timer_init,
.restart = rpc_restart,
MACHINE_END
diff --git a/arch/arm/mach-rpc/time.c b/arch/arm/mach-rpc/time.c
index 581fca934bb3..9a6def14df01 100644
--- a/arch/arm/mach-rpc/time.c
+++ b/arch/arm/mach-rpc/time.c
@@ -24,7 +24,7 @@
#include <asm/mach/time.h>
-unsigned long ioc_timer_gettimeoffset(void)
+static u32 ioc_timer_gettimeoffset(void)
{
unsigned int count1, count2, status;
long offset;
@@ -56,7 +56,7 @@ unsigned long ioc_timer_gettimeoffset(void)
}
offset = (LATCH - offset) * (tick_nsec / 1000);
- return (offset + LATCH/2) / LATCH;
+ return ((offset + LATCH/2) / LATCH) * 1000;
}
void __init ioctime_init(void)
@@ -82,14 +82,9 @@ static struct irqaction ioc_timer_irq = {
/*
* Set up timer interrupt.
*/
-static void __init ioc_timer_init(void)
+void __init ioc_timer_init(void)
{
+ arch_gettimeoffset = ioc_timer_gettimeoffset;
ioctime_init();
setup_irq(IRQ_TIMER0, &ioc_timer_irq);
}
-
-struct sys_timer ioc_timer = {
- .init = ioc_timer_init,
- .offset = ioc_timer_gettimeoffset,
-};
-
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
deleted file mode 100644
index 68d89cb96af0..000000000000
--- a/arch/arm/mach-s3c2410/Kconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-# cpu frequency scaling support
-
-config S3C2410_CPUFREQ
- bool
- depends on CPU_FREQ_S3C24XX && CPU_S3C2410
- select S3C2410_CPUFREQ_UTILS
- help
- CPU Frequency scaling support for S3C2410
-
-config S3C2410_PLLTABLE
- bool
- depends on S3C2410_CPUFREQ && CPU_FREQ_S3C24XX_PLL
- default y
- help
- Select the PLL table for the S3C2410
-
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
deleted file mode 100644
index 6b9a316e0041..000000000000
--- a/arch/arm/mach-s3c2410/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# arch/arm/mach-s3c2410/Makefile
-#
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
-obj-$(CONFIG_S3C2410_CPUFREQ) += cpu-freq.o
-obj-$(CONFIG_S3C2410_PLLTABLE) += pll.o
-
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
deleted file mode 100644
index 495f6928cbaa..000000000000
--- a/arch/arm/mach-s3c2412/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-# Note, the S3C2412 IOtiming support is in plat-s3c24xx
-
-config S3C2412_CPUFREQ
- bool
- depends on CPU_FREQ_S3C24XX && CPU_S3C2412
- default y
- select S3C2412_IOTIMING
- help
- CPU Frequency scaling support for S3C2412 and S3C2413 SoC CPUs.
diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile
deleted file mode 100644
index 41a6c279fb2f..000000000000
--- a/arch/arm/mach-s3c2412/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# arch/arm/mach-s3c2412/Makefile
-#
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
-obj-$(CONFIG_S3C2412_CPUFREQ) += cpu-freq.o
diff --git a/arch/arm/mach-s3c2412/gpio.c b/arch/arm/mach-s3c2412/gpio.c
deleted file mode 100644
index 4526f6ba31a8..000000000000
--- a/arch/arm/mach-s3c2412/gpio.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/gpio.c
- *
- * Copyright (c) 2007 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * http://armlinux.simtec.co.uk/.
- *
- * S3C2412/S3C2413 specific GPIO 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/kernel.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/hardware.h>
-
-#include <plat/gpio-core.h>
-
-int s3c2412_gpio_set_sleepcfg(unsigned int pin, unsigned int state)
-{
- struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
- unsigned long offs = pin - chip->chip.base;
- unsigned long flags;
- unsigned long slpcon;
-
- offs *= 2;
-
- if (pin < S3C2410_GPB(0))
- return -EINVAL;
-
- if (pin >= S3C2410_GPF(0) &&
- pin <= S3C2410_GPG(16))
- return -EINVAL;
-
- if (pin > S3C2410_GPH(16))
- return -EINVAL;
-
- local_irq_save(flags);
-
- slpcon = __raw_readl(chip->base + 0x0C);
-
- slpcon &= ~(3 << offs);
- slpcon |= state << offs;
-
- __raw_writel(slpcon, chip->base + 0x0C);
-
- local_irq_restore(flags);
-
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2412_gpio_set_sleepcfg);
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
deleted file mode 100644
index a4d7fd27bec5..000000000000
--- a/arch/arm/mach-s3c2440/Kconfig
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-config S3C2440_CPUFREQ
- bool "S3C2440/S3C2442 CPU Frequency scaling support"
- depends on CPU_FREQ_S3C24XX && (CPU_S3C2440 || CPU_S3C2442)
- default y
- select S3C2410_CPUFREQ_UTILS
- help
- CPU Frequency scaling support for S3C2440 and S3C2442 SoC CPUs.
-
-config S3C2440_XTAL_12000000
- bool
- help
- Indicate that the build needs to support 12MHz system
- crystal.
-
-config S3C2440_XTAL_16934400
- bool
- help
- Indicate that the build needs to support 16.9344MHz system
- crystal.
-
-config S3C2440_PLL_12000000
- bool
- depends on S3C2440_CPUFREQ && S3C2440_XTAL_12000000
- default y if CPU_FREQ_S3C24XX_PLL
- help
- PLL tables for S3C2440 or S3C2442 CPUs with 12MHz crystals.
-
-config S3C2440_PLL_16934400
- bool
- depends on S3C2440_CPUFREQ && S3C2440_XTAL_16934400
- default y if CPU_FREQ_S3C24XX_PLL
- help
- PLL tables for S3C2440 or S3C2442 CPUs with 16.934MHz crystals.
diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile
deleted file mode 100644
index c46092439814..000000000000
--- a/arch/arm/mach-s3c2440/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# arch/arm/mach-s3c2440/Makefile
-#
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
-obj-$(CONFIG_CPU_S3C2440) += dsc.o
-
-obj-$(CONFIG_S3C2440_CPUFREQ) += s3c2440-cpufreq.o
-
-obj-$(CONFIG_S3C2440_PLL_12000000) += s3c2440-pll-12000000.o
-obj-$(CONFIG_S3C2440_PLL_16934400) += s3c2440-pll-16934400.o
diff --git a/arch/arm/mach-s3c2440/dsc.c b/arch/arm/mach-s3c2440/dsc.c
deleted file mode 100644
index 9ea66e31f626..000000000000
--- a/arch/arm/mach-s3c2440/dsc.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/dsc.c
- *
- * Copyright (c) 2004-2005 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C2440 Drive Strength Control 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/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/regs-dsc.h>
-
-#include <plat/cpu.h>
-#include <plat/s3c244x.h>
-
-int s3c2440_set_dsc(unsigned int pin, unsigned int value)
-{
- void __iomem *base;
- unsigned long val;
- unsigned long flags;
- unsigned long mask;
-
- base = (pin & S3C2440_SELECT_DSC1) ? S3C2440_DSC1 : S3C2440_DSC0;
- mask = 3 << S3C2440_DSC_GETSHIFT(pin);
-
- local_irq_save(flags);
-
- val = __raw_readl(base);
- val &= ~mask;
- val |= value & mask;
- __raw_writel(val, base);
-
- local_irq_restore(flags);
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2440_set_dsc);
diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig
index 25df14a9e268..37f513d1588e 100644
--- a/arch/arm/mach-s3c24xx/Kconfig
+++ b/arch/arm/mach-s3c24xx/Kconfig
@@ -9,6 +9,15 @@
if ARCH_S3C24XX
+config PLAT_S3C24XX
+ def_bool y
+ select ARCH_REQUIRE_GPIOLIB
+ select NO_IOPORT
+ select S3C_DEV_NAND
+ select IRQ_DOMAIN
+ help
+ Base platform code for any Samsung S3C24XX device
+
menu "SAMSUNG S3C24XX SoCs Support"
comment "S3C24XX SoCs"
@@ -83,6 +92,17 @@ config CPU_S3C2443
# common code
+config S3C2410_CLOCK
+ bool
+ help
+ Clock code for the S3C2410, and similar processors which
+ is currently includes the S3C2410, S3C2440, S3C2442.
+
+config S3C24XX_DCLK
+ bool
+ help
+ Clock code for supporting DCLK/CLKOUT on S3C24XX architectures
+
config S3C24XX_SMDK
bool
help
@@ -111,6 +131,22 @@ config S3C24XX_SETUP_TS
help
Compile in platform device definition for Samsung TouchScreen.
+config S3C24XX_DMA
+ bool "S3C2410 DMA support"
+ depends on ARCH_S3C24XX
+ select S3C_DMA
+ help
+ S3C2410 DMA support. This is needed for drivers like sound which
+ use the S3C2410's DMA system to move data to and from the
+ peripheral blocks.
+
+config S3C2410_DMA_DEBUG
+ bool "S3C2410 DMA support debug"
+ depends on ARCH_S3C24XX && S3C2410_DMA
+ help
+ Enable debugging output for the DMA code. This option sends info
+ to the kernel log, at priority KERN_DEBUG.
+
config S3C2410_DMA
bool
depends on S3C24XX_DMA && (CPU_S3C2410 || CPU_S3C2442)
@@ -123,10 +159,92 @@ config S3C2410_PM
help
Power Management code common to S3C2410 and better
+# low-level serial option nodes
+
+config CPU_LLSERIAL_S3C2410_ONLY
+ bool
+ default y if CPU_LLSERIAL_S3C2410 && !CPU_LLSERIAL_S3C2440
+
+config CPU_LLSERIAL_S3C2440_ONLY
+ bool
+ default y if CPU_LLSERIAL_S3C2440 && !CPU_LLSERIAL_S3C2410
+
+config CPU_LLSERIAL_S3C2410
+ bool
+ help
+ Selected if there is an S3C2410 (or register compatible) serial
+ low-level implementation needed
+
+config CPU_LLSERIAL_S3C2440
+ bool
+ help
+ Selected if there is an S3C2440 (or register compatible) serial
+ low-level implementation needed
+
+# gpio configurations
+
+config S3C24XX_GPIO_EXTRA
+ int
+ default 128 if S3C24XX_GPIO_EXTRA128
+ default 64 if S3C24XX_GPIO_EXTRA64
+ default 16 if ARCH_H1940
+ default 0
+
+config S3C24XX_GPIO_EXTRA64
+ bool
+ help
+ Add an extra 64 gpio numbers to the available GPIO pool. This is
+ available for boards that need extra gpios for external devices.
+
+config S3C24XX_GPIO_EXTRA128
+ bool
+ help
+ Add an extra 128 gpio numbers to the available GPIO pool. This is
+ available for boards that need extra gpios for external devices.
+
+# cpu frequency items common between s3c2410 and s3c2440/s3c2442
+
+config S3C2410_IOTIMING
+ bool
+ depends on CPU_FREQ_S3C24XX
+ help
+ Internal node to select io timing code that is common to the s3c2410
+ and s3c2440/s3c2442 cpu frequency support.
+
+config S3C2410_CPUFREQ_UTILS
+ bool
+ depends on CPU_FREQ_S3C24XX
+ help
+ Internal node to select timing code that is common to the s3c2410
+ and s3c2440/s3c244 cpu frequency support.
+
+# cpu frequency support common to s3c2412, s3c2413 and s3c2442
+
+config S3C2412_IOTIMING
+ bool
+ depends on CPU_FREQ_S3C24XX && (CPU_S3C2412 || CPU_S3C2443)
+ help
+ Intel node to select io timing code that is common to the s3c2412
+ and the s3c2443.
+
# cpu-specific sections
if CPU_S3C2410
+config S3C2410_CPUFREQ
+ bool
+ depends on CPU_FREQ_S3C24XX && CPU_S3C2410
+ select S3C2410_CPUFREQ_UTILS
+ help
+ CPU Frequency scaling support for S3C2410
+
+config S3C2410_PLL
+ bool
+ depends on S3C2410_CPUFREQ && CPU_FREQ_S3C24XX_PLL
+ default y
+ help
+ Select the PLL table for the S3C2410
+
config S3C24XX_SIMTEC_NOR
bool
help
@@ -226,6 +344,7 @@ config MACH_QT2410
config ARCH_SMDK2410
bool "SMDK2410/A9M2410"
select S3C24XX_SMDK
+ select S3C_DEV_USB_HOST
help
Say Y here if you are using the SMDK2410 or the derived module A9M2410
<http://www.fsforth.de>
@@ -266,6 +385,14 @@ config CPU_S3C2412_ONLY
!CPU_S3C2443 && CPU_S3C2412
default y
+config S3C2412_CPUFREQ
+ bool
+ depends on CPU_FREQ_S3C24XX && CPU_S3C2412
+ default y
+ select S3C2412_IOTIMING
+ help
+ CPU Frequency scaling support for S3C2412 and S3C2413 SoC CPUs.
+
config S3C2412_DMA
bool
help
@@ -273,6 +400,7 @@ config S3C2412_DMA
config S3C2412_PM
bool
+ select S3C2412_PM_SLEEP
help
Internal config node to apply S3C2412 power management
@@ -291,8 +419,8 @@ config MACH_JIVE
Say Y here if you are using the Logitech Jive.
config MACH_JIVE_SHOW_BOOTLOADER
- bool "Allow access to bootloader partitions in MTD (EXPERIMENTAL)"
- depends on MACH_JIVE && EXPERIMENTAL
+ bool "Allow access to bootloader partitions in MTD"
+ depends on MACH_JIVE
config MACH_S3C2413
bool
@@ -365,11 +493,45 @@ endif # CPU_S3C2416
if CPU_S3C2440
+config S3C2440_CPUFREQ
+ bool "S3C2440/S3C2442 CPU Frequency scaling support"
+ depends on CPU_FREQ_S3C24XX && (CPU_S3C2440 || CPU_S3C2442)
+ default y
+ select S3C2410_CPUFREQ_UTILS
+ help
+ CPU Frequency scaling support for S3C2440 and S3C2442 SoC CPUs.
+
config S3C2440_DMA
bool
help
Support for S3C2440 specific DMA code5A
+config S3C2440_XTAL_12000000
+ bool
+ help
+ Indicate that the build needs to support 12MHz system
+ crystal.
+
+config S3C2440_XTAL_16934400
+ bool
+ help
+ Indicate that the build needs to support 16.9344MHz system
+ crystal.
+
+config S3C2440_PLL_12000000
+ bool
+ depends on S3C2440_CPUFREQ && S3C2440_XTAL_12000000
+ default y if CPU_FREQ_S3C24XX_PLL
+ help
+ PLL tables for S3C2440 or S3C2442 CPUs with 12MHz crystals.
+
+config S3C2440_PLL_16934400
+ bool
+ depends on S3C2440_CPUFREQ && S3C2440_XTAL_16934400
+ default y if CPU_FREQ_S3C24XX_PLL
+ help
+ PLL tables for S3C2440 or S3C2442 CPUs with 16.934MHz crystals.
+
comment "S3C2440 Boards"
#
diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile
index 0ab6ab15da4c..af53d27d5c36 100644
--- a/arch/arm/mach-s3c24xx/Makefile
+++ b/arch/arm/mach-s3c24xx/Makefile
@@ -14,26 +14,32 @@ obj- :=
# core
-obj-y += common.o
+obj-y += common.o irq.o
obj-$(CONFIG_CPU_S3C2410) += s3c2410.o
+obj-$(CONFIG_S3C2410_CPUFREQ) += cpufreq-s3c2410.o
obj-$(CONFIG_S3C2410_DMA) += dma-s3c2410.o
+obj-$(CONFIG_S3C2410_PLL) += pll-s3c2410.o
obj-$(CONFIG_S3C2410_PM) += pm-s3c2410.o sleep-s3c2410.o
obj-$(CONFIG_CPU_S3C2412) += s3c2412.o irq-s3c2412.o clock-s3c2412.o
+obj-$(CONFIG_S3C2412_CPUFREQ) += cpufreq-s3c2412.o
obj-$(CONFIG_S3C2412_DMA) += dma-s3c2412.o
obj-$(CONFIG_S3C2412_PM) += pm-s3c2412.o
obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep-s3c2412.o
-obj-$(CONFIG_CPU_S3C2416) += s3c2416.o irq-s3c2416.o clock-s3c2416.o
+obj-$(CONFIG_CPU_S3C2416) += s3c2416.o clock-s3c2416.o
obj-$(CONFIG_S3C2416_PM) += pm-s3c2416.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440.o irq-s3c2440.o clock-s3c2440.o
obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
obj-$(CONFIG_CPU_S3C244X) += s3c244x.o irq-s3c244x.o clock-s3c244x.o
+obj-$(CONFIG_S3C2440_CPUFREQ) += cpufreq-s3c2440.o
obj-$(CONFIG_S3C2440_DMA) += dma-s3c2440.o
+obj-$(CONFIG_S3C2440_PLL_12000000) += pll-s3c2440-12000000.o
+obj-$(CONFIG_S3C2440_PLL_16934400) += pll-s3c2440-16934400.o
-obj-$(CONFIG_CPU_S3C2443) += s3c2443.o irq-s3c2443.o clock-s3c2443.o
+obj-$(CONFIG_CPU_S3C2443) += s3c2443.o clock-s3c2443.o
# PM
@@ -41,9 +47,21 @@ obj-$(CONFIG_PM) += pm.o irq-pm.o sleep.o
# common code
+obj-$(CONFIG_S3C24XX_DCLK) += clock-dclk.o
+obj-$(CONFIG_S3C24XX_DMA) += dma.o
+
+obj-$(CONFIG_S3C2410_CLOCK) += clock-s3c2410.o
+obj-$(CONFIG_S3C2410_CPUFREQ_UTILS) += cpufreq-utils.o
+
+obj-$(CONFIG_S3C2410_IOTIMING) += iotiming-s3c2410.o
+obj-$(CONFIG_S3C2412_IOTIMING) += iotiming-s3c2412.o
+
obj-$(CONFIG_S3C2443_COMMON) += common-s3c2443.o
obj-$(CONFIG_S3C2443_DMA) += dma-s3c2443.o
+obj-$(CONFIG_CPU_FREQ_S3C24XX) += cpufreq.o
+obj-$(CONFIG_CPU_FREQ_S3C24XX_DEBUGFS) += cpufreq-debugfs.o
+
#
# machine support
# following is ordered alphabetically by option text.
diff --git a/arch/arm/mach-s3c24xx/anubis.h b/arch/arm/mach-s3c24xx/anubis.h
new file mode 100644
index 000000000000..2691665f27d9
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/anubis.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2005 Simtec Electronics
+ * http://www.simtec.co.uk/products/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * ANUBIS - CPLD control constants
+ * ANUBIS - IRQ Number definitions
+ * ANUBIS - Memory map definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __MACH_S3C24XX_ANUBIS_H
+#define __MACH_S3C24XX_ANUBIS_H __FILE__
+
+/* CTRL2 - NAND WP control, IDE Reset assert/check */
+
+#define ANUBIS_CTRL1_NANDSEL (0x3)
+
+/* IDREG - revision */
+
+#define ANUBIS_IDREG_REVMASK (0x7)
+
+/* irq */
+
+#define ANUBIS_IRQ_IDE0 IRQ_EINT2
+#define ANUBIS_IRQ_IDE1 IRQ_EINT3
+#define ANUBIS_IRQ_ASIX IRQ_EINT1
+
+/* map */
+
+/* start peripherals off after the S3C2410 */
+
+#define ANUBIS_IOADDR(x) (S3C2410_ADDR((x) + 0x01800000))
+
+#define ANUBIS_PA_CPLD (S3C2410_CS1 | (1<<26))
+
+/* we put the CPLD registers next, to get them out of the way */
+
+#define ANUBIS_VA_CTRL1 ANUBIS_IOADDR(0x00000000)
+#define ANUBIS_PA_CTRL1 ANUBIS_PA_CPLD
+
+#define ANUBIS_VA_IDREG ANUBIS_IOADDR(0x00300000)
+#define ANUBIS_PA_IDREG (ANUBIS_PA_CPLD + (3 << 23))
+
+#define ANUBIS_IDEPRI ANUBIS_IOADDR(0x01000000)
+#define ANUBIS_IDEPRIAUX ANUBIS_IOADDR(0x01100000)
+#define ANUBIS_IDESEC ANUBIS_IOADDR(0x01200000)
+#define ANUBIS_IDESECAUX ANUBIS_IOADDR(0x01300000)
+
+#endif /* __MACH_S3C24XX_ANUBIS_H */
diff --git a/arch/arm/mach-s3c24xx/bast-ide.c b/arch/arm/mach-s3c24xx/bast-ide.c
index ba02cf8d80a2..3f0288f2f542 100644
--- a/arch/arm/mach-s3c24xx/bast-ide.c
+++ b/arch/arm/mach-s3c24xx/bast-ide.c
@@ -25,8 +25,8 @@
#include <asm/mach/irq.h>
#include <mach/map.h>
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
+
+#include "bast.h"
/* IDE ports */
@@ -34,12 +34,10 @@ static struct pata_platform_info bast_ide_platdata = {
.ioport_shift = 5,
};
-#define IDE_CS S3C2410_CS5
-
static struct resource bast_ide0_resource[] = {
- [0] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDEPRI, 8 * 0x20),
- [1] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDEPRIAUX + (6 * 0x20), 0x20),
- [2] = DEFINE_RES_IRQ(IRQ_IDE0),
+ [0] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDEPRI, 8 * 0x20),
+ [1] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDEPRIAUX + (6 * 0x20), 0x20),
+ [2] = DEFINE_RES_IRQ(BAST_IRQ_IDE0),
};
static struct platform_device bast_device_ide0 = {
@@ -55,9 +53,9 @@ static struct platform_device bast_device_ide0 = {
};
static struct resource bast_ide1_resource[] = {
- [0] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDESEC, 8 * 0x20),
- [1] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDESECAUX + (6 * 0x20), 0x20),
- [2] = DEFINE_RES_IRQ(IRQ_IDE1),
+ [0] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDESEC, 8 * 0x20),
+ [1] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDESECAUX + (6 * 0x20), 0x20),
+ [2] = DEFINE_RES_IRQ(BAST_IRQ_IDE1),
};
static struct platform_device bast_device_ide1 = {
diff --git a/arch/arm/mach-s3c24xx/bast-irq.c b/arch/arm/mach-s3c24xx/bast-irq.c
index ac7b2ad5c405..c0daa9590b4c 100644
--- a/arch/arm/mach-s3c24xx/bast-irq.c
+++ b/arch/arm/mach-s3c24xx/bast-irq.c
@@ -27,27 +27,20 @@
#include <linux/device.h>
#include <linux/io.h>
-#include <asm/mach-types.h>
-
-#include <mach/hardware.h>
#include <asm/irq.h>
-
+#include <asm/mach-types.h>
#include <asm/mach/irq.h>
+#include <mach/hardware.h>
#include <mach/regs-irq.h>
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
#include <plat/irq.h>
-#if 0
-#include <asm/debug-ll.h>
-#endif
+#include "bast.h"
#define irqdbf(x...)
#define irqdbf2(x...)
-
/* handle PC104 ISA interrupts from the system CPLD */
/* table of ISA irq nos to the relevant mask... zero means
@@ -87,7 +80,7 @@ bast_pc104_mask(struct irq_data *data)
static void
bast_pc104_maskack(struct irq_data *data)
{
- struct irq_desc *desc = irq_desc + IRQ_ISA;
+ struct irq_desc *desc = irq_desc + BAST_IRQ_ISA;
bast_pc104_mask(data);
desc->irq_data.chip->irq_ack(&desc->irq_data);
@@ -122,7 +115,7 @@ bast_irq_pc104_demux(unsigned int irq,
if (unlikely(stat == 0)) {
/* ack if we get an irq with nothing (ie, startup) */
- desc = irq_desc + IRQ_ISA;
+ desc = irq_desc + BAST_IRQ_ISA;
desc->irq_data.chip->irq_ack(&desc->irq_data);
} else {
/* handle the IRQ */
@@ -147,7 +140,7 @@ static __init int bast_irq_init(void)
__raw_writeb(0x0, BAST_VA_PC104_IRQMASK);
- irq_set_chained_handler(IRQ_ISA, bast_irq_pc104_demux);
+ irq_set_chained_handler(BAST_IRQ_ISA, bast_irq_pc104_demux);
/* register our IRQs */
diff --git a/arch/arm/mach-s3c24xx/bast.h b/arch/arm/mach-s3c24xx/bast.h
new file mode 100644
index 000000000000..5c7534bae92d
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/bast.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2003-2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * BAST - CPLD control constants
+ * BAST - IRQ Number definitions
+ * BAST - Memory map definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __MACH_S3C24XX_BAST_H
+#define __MACH_S3C24XX_BAST_H __FILE__
+
+/* CTRL1 - Audio LR routing */
+
+#define BAST_CPLD_CTRL1_LRCOFF (0x00)
+#define BAST_CPLD_CTRL1_LRCADC (0x01)
+#define BAST_CPLD_CTRL1_LRCDAC (0x02)
+#define BAST_CPLD_CTRL1_LRCARM (0x03)
+#define BAST_CPLD_CTRL1_LRMASK (0x03)
+
+/* CTRL2 - NAND WP control, IDE Reset assert/check */
+
+#define BAST_CPLD_CTRL2_WNAND (0x04)
+#define BAST_CPLD_CTLR2_IDERST (0x08)
+
+/* CTRL3 - rom write control, CPLD identity */
+
+#define BAST_CPLD_CTRL3_IDMASK (0x0e)
+#define BAST_CPLD_CTRL3_ROMWEN (0x01)
+
+/* CTRL4 - 8bit LCD interface control/status */
+
+#define BAST_CPLD_CTRL4_LLAT (0x01)
+#define BAST_CPLD_CTRL4_LCDRW (0x02)
+#define BAST_CPLD_CTRL4_LCDCMD (0x04)
+#define BAST_CPLD_CTRL4_LCDE2 (0x01)
+
+/* CTRL5 - DMA routing */
+
+#define BAST_CPLD_DMA0_PRIIDE (0)
+#define BAST_CPLD_DMA0_SECIDE (1)
+#define BAST_CPLD_DMA0_ISA15 (2)
+#define BAST_CPLD_DMA0_ISA36 (3)
+
+#define BAST_CPLD_DMA1_PRIIDE (0 << 2)
+#define BAST_CPLD_DMA1_SECIDE (1 << 2)
+#define BAST_CPLD_DMA1_ISA15 (2 << 2)
+#define BAST_CPLD_DMA1_ISA36 (3 << 2)
+
+/* irq numbers to onboard peripherals */
+
+#define BAST_IRQ_USBOC IRQ_EINT18
+#define BAST_IRQ_IDE0 IRQ_EINT16
+#define BAST_IRQ_IDE1 IRQ_EINT17
+#define BAST_IRQ_PCSERIAL1 IRQ_EINT15
+#define BAST_IRQ_PCSERIAL2 IRQ_EINT14
+#define BAST_IRQ_PCPARALLEL IRQ_EINT13
+#define BAST_IRQ_ASIX IRQ_EINT11
+#define BAST_IRQ_DM9000 IRQ_EINT10
+#define BAST_IRQ_ISA IRQ_EINT9
+#define BAST_IRQ_SMALERT IRQ_EINT8
+
+/* map */
+
+/*
+ * ok, we've used up to 0x13000000, now we need to find space for the
+ * peripherals that live in the nGCS[x] areas, which are quite numerous
+ * in their space. We also have the board's CPLD to find register space
+ * for.
+ */
+
+#define BAST_IOADDR(x) (S3C2410_ADDR((x) + 0x01300000))
+
+/* we put the CPLD registers next, to get them out of the way */
+
+#define BAST_VA_CTRL1 BAST_IOADDR(0x00000000)
+#define BAST_PA_CTRL1 (S3C2410_CS5 | 0x7800000)
+
+#define BAST_VA_CTRL2 BAST_IOADDR(0x00100000)
+#define BAST_PA_CTRL2 (S3C2410_CS1 | 0x6000000)
+
+#define BAST_VA_CTRL3 BAST_IOADDR(0x00200000)
+#define BAST_PA_CTRL3 (S3C2410_CS1 | 0x6800000)
+
+#define BAST_VA_CTRL4 BAST_IOADDR(0x00300000)
+#define BAST_PA_CTRL4 (S3C2410_CS1 | 0x7000000)
+
+/* next, we have the PC104 ISA interrupt registers */
+
+#define BAST_PA_PC104_IRQREQ (S3C2410_CS5 | 0x6000000)
+#define BAST_VA_PC104_IRQREQ BAST_IOADDR(0x00400000)
+
+#define BAST_PA_PC104_IRQRAW (S3C2410_CS5 | 0x6800000)
+#define BAST_VA_PC104_IRQRAW BAST_IOADDR(0x00500000)
+
+#define BAST_PA_PC104_IRQMASK (S3C2410_CS5 | 0x7000000)
+#define BAST_VA_PC104_IRQMASK BAST_IOADDR(0x00600000)
+
+#define BAST_PA_LCD_RCMD1 (0x8800000)
+#define BAST_VA_LCD_RCMD1 BAST_IOADDR(0x00700000)
+
+#define BAST_PA_LCD_WCMD1 (0x8000000)
+#define BAST_VA_LCD_WCMD1 BAST_IOADDR(0x00800000)
+
+#define BAST_PA_LCD_RDATA1 (0x9800000)
+#define BAST_VA_LCD_RDATA1 BAST_IOADDR(0x00900000)
+
+#define BAST_PA_LCD_WDATA1 (0x9000000)
+#define BAST_VA_LCD_WDATA1 BAST_IOADDR(0x00A00000)
+
+#define BAST_PA_LCD_RCMD2 (0xA800000)
+#define BAST_VA_LCD_RCMD2 BAST_IOADDR(0x00B00000)
+
+#define BAST_PA_LCD_WCMD2 (0xA000000)
+#define BAST_VA_LCD_WCMD2 BAST_IOADDR(0x00C00000)
+
+#define BAST_PA_LCD_RDATA2 (0xB800000)
+#define BAST_VA_LCD_RDATA2 BAST_IOADDR(0x00D00000)
+
+#define BAST_PA_LCD_WDATA2 (0xB000000)
+#define BAST_VA_LCD_WDATA2 BAST_IOADDR(0x00E00000)
+
+
+/*
+ * 0xE0000000 contains the IO space that is split by speed and
+ * whether the access is for 8 or 16bit IO... this ensures that
+ * the correct access is made
+ *
+ * 0x10000000 of space, partitioned as so:
+ *
+ * 0x00000000 to 0x04000000 8bit, slow
+ * 0x04000000 to 0x08000000 16bit, slow
+ * 0x08000000 to 0x0C000000 16bit, net
+ * 0x0C000000 to 0x10000000 16bit, fast
+ *
+ * each of these spaces has the following in:
+ *
+ * 0x00000000 to 0x01000000 16MB ISA IO space
+ * 0x01000000 to 0x02000000 16MB ISA memory space
+ * 0x02000000 to 0x02100000 1MB IDE primary channel
+ * 0x02100000 to 0x02200000 1MB IDE primary channel aux
+ * 0x02200000 to 0x02400000 1MB IDE secondary channel
+ * 0x02300000 to 0x02400000 1MB IDE secondary channel aux
+ * 0x02400000 to 0x02500000 1MB ASIX ethernet controller
+ * 0x02500000 to 0x02600000 1MB Davicom DM9000 ethernet controller
+ * 0x02600000 to 0x02700000 1MB PC SuperIO controller
+ *
+ * the phyiscal layout of the zones are:
+ * nGCS2 - 8bit, slow
+ * nGCS3 - 16bit, slow
+ * nGCS4 - 16bit, net
+ * nGCS5 - 16bit, fast
+ */
+
+#define BAST_VA_MULTISPACE (0xE0000000)
+
+#define BAST_VA_ISAIO (BAST_VA_MULTISPACE + 0x00000000)
+#define BAST_VA_ISAMEM (BAST_VA_MULTISPACE + 0x01000000)
+#define BAST_VA_IDEPRI (BAST_VA_MULTISPACE + 0x02000000)
+#define BAST_VA_IDEPRIAUX (BAST_VA_MULTISPACE + 0x02100000)
+#define BAST_VA_IDESEC (BAST_VA_MULTISPACE + 0x02200000)
+#define BAST_VA_IDESECAUX (BAST_VA_MULTISPACE + 0x02300000)
+#define BAST_VA_ASIXNET (BAST_VA_MULTISPACE + 0x02400000)
+#define BAST_VA_DM9000 (BAST_VA_MULTISPACE + 0x02500000)
+#define BAST_VA_SUPERIO (BAST_VA_MULTISPACE + 0x02600000)
+
+#define BAST_VAM_CS2 (0x00000000)
+#define BAST_VAM_CS3 (0x04000000)
+#define BAST_VAM_CS4 (0x08000000)
+#define BAST_VAM_CS5 (0x0C000000)
+
+/* physical offset addresses for the peripherals */
+
+#define BAST_PA_ISAIO (0x00000000)
+#define BAST_PA_ASIXNET (0x01000000)
+#define BAST_PA_SUPERIO (0x01800000)
+#define BAST_PA_IDEPRI (0x02000000)
+#define BAST_PA_IDEPRIAUX (0x02800000)
+#define BAST_PA_IDESEC (0x03000000)
+#define BAST_PA_IDESECAUX (0x03800000)
+#define BAST_PA_ISAMEM (0x04000000)
+#define BAST_PA_DM9000 (0x05000000)
+
+/* some configurations for the peripherals */
+
+#define BAST_PCSIO (BAST_VA_SUPERIO + BAST_VAM_CS2)
+
+#define BAST_ASIXNET_CS BAST_VAM_CS5
+#define BAST_DM9000_CS BAST_VAM_CS4
+
+#define BAST_IDE_CS S3C2410_CS5
+
+#endif /* __MACH_S3C24XX_BAST_H */
diff --git a/arch/arm/plat-s3c24xx/clock-dclk.c b/arch/arm/mach-s3c24xx/clock-dclk.c
index f95d3268ae1f..1edd9b2369c5 100644
--- a/arch/arm/plat-s3c24xx/clock-dclk.c
+++ b/arch/arm/mach-s3c24xx/clock-dclk.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-s3c24xx/clock-dclk.c
- *
+/*
* Copyright (c) 2004-2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
diff --git a/arch/arm/plat-s3c24xx/s3c2410-clock.c b/arch/arm/mach-s3c24xx/clock-s3c2410.c
index 25dc4d4397b1..641266f3d152 100644
--- a/arch/arm/plat-s3c24xx/s3c2410-clock.c
+++ b/arch/arm/mach-s3c24xx/clock-s3c2410.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/clock.c
- *
+/*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
diff --git a/arch/arm/mach-s3c24xx/common-s3c2443.c b/arch/arm/mach-s3c24xx/common-s3c2443.c
index aeb4a24ff3ed..f6b9f2ef01bd 100644
--- a/arch/arm/mach-s3c24xx/common-s3c2443.c
+++ b/arch/arm/mach-s3c24xx/common-s3c2443.c
@@ -132,7 +132,7 @@ static struct clk *clk_msysclk_sources[] = {
[3] = &clk_mpllref,
};
-struct clksrc_clk clk_msysclk = {
+static struct clksrc_clk clk_msysclk = {
.clk = {
.name = "msysclk",
.parent = &clk_xtal,
diff --git a/arch/arm/mach-s3c24xx/common.c b/arch/arm/mach-s3c24xx/common.c
index 0c9e9a785ef6..6bcf87f65f9e 100644
--- a/arch/arm/mach-s3c24xx/common.c
+++ b/arch/arm/mach-s3c24xx/common.c
@@ -197,7 +197,7 @@ static unsigned long s3c24xx_read_idcode_v4(void)
static void s3c24xx_default_idle(void)
{
- unsigned long tmp;
+ unsigned long tmp = 0;
int i;
/* idle the system by using the idle mode which will wait for an
diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h
index c2f596e7bc2d..ed6276fcaa3b 100644
--- a/arch/arm/mach-s3c24xx/common.h
+++ b/arch/arm/mach-s3c24xx/common.h
@@ -15,4 +15,6 @@
void s3c2410_restart(char mode, const char *cmd);
void s3c244x_restart(char mode, const char *cmd);
+extern struct syscore_ops s3c24xx_irq_syscore_ops;
+
#endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */
diff --git a/arch/arm/plat-s3c24xx/cpu-freq-debugfs.c b/arch/arm/mach-s3c24xx/cpufreq-debugfs.c
index c7adad0e8de0..9b7b4289d66c 100644
--- a/arch/arm/plat-s3c24xx/cpu-freq-debugfs.c
+++ b/arch/arm/mach-s3c24xx/cpufreq-debugfs.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-s3c24xx/cpu-freq-debugfs.c
- *
+/*
* Copyright (c) 2009 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/cpu-freq.c b/arch/arm/mach-s3c24xx/cpufreq-s3c2410.c
index 5404535da1a5..cfa0dd8723ec 100644
--- a/arch/arm/mach-s3c2410/cpu-freq.c
+++ b/arch/arm/mach-s3c24xx/cpufreq-s3c2410.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/cpu-freq.c
- *
+/*
* Copyright (c) 2006-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -81,7 +80,7 @@ static int s3c2410_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
cfg->divs.p_divisor = pdiv;
cfg->divs.h_divisor = hdiv;
- return 0 ;
+ return 0;
}
static struct s3c_cpufreq_info s3c2410_cpufreq_info = {
@@ -131,7 +130,6 @@ static int __init s3c2410_cpufreq_init(void)
{
return subsys_interface_register(&s3c2410_cpufreq_interface);
}
-
arch_initcall(s3c2410_cpufreq_init);
static int s3c2410a_cpufreq_add(struct device *dev,
@@ -159,5 +157,4 @@ static int __init s3c2410a_cpufreq_init(void)
{
return subsys_interface_register(&s3c2410a_cpufreq_interface);
}
-
arch_initcall(s3c2410a_cpufreq_init);
diff --git a/arch/arm/mach-s3c2412/cpu-freq.c b/arch/arm/mach-s3c24xx/cpufreq-s3c2412.c
index 125be7d5fa60..8bf0f3a77476 100644
--- a/arch/arm/mach-s3c2412/cpu-freq.c
+++ b/arch/arm/mach-s3c24xx/cpufreq-s3c2412.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-s3c2412/cpu-freq.c
- *
+/*
* Copyright 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -26,12 +25,13 @@
#include <asm/mach/map.h>
#include <mach/regs-clock.h>
-#include <mach/regs-s3c2412-mem.h>
#include <plat/cpu.h>
#include <plat/clock.h>
#include <plat/cpu-freq-core.h>
+#include "s3c2412.h"
+
/* our clock resources. */
static struct clk *xtal;
static struct clk *fclk;
@@ -111,7 +111,7 @@ static int s3c2412_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
return 0;
- invalid:
+invalid:
return -EINVAL;
}
@@ -255,5 +255,4 @@ static int s3c2412_cpufreq_init(void)
{
return subsys_interface_register(&s3c2412_cpufreq_interface);
}
-
arch_initcall(s3c2412_cpufreq_init);
diff --git a/arch/arm/mach-s3c2440/s3c2440-cpufreq.c b/arch/arm/mach-s3c24xx/cpufreq-s3c2440.c
index 61776764d9f4..72b2cc8a5a85 100644
--- a/arch/arm/mach-s3c2440/s3c2440-cpufreq.c
+++ b/arch/arm/mach-s3c24xx/cpufreq-s3c2440.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-s3c24xx/s3c2440-cpufreq.c
- *
+/*
* Copyright (c) 2006-2009 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -310,5 +309,4 @@ static int s3c2442_cpufreq_init(void)
{
return subsys_interface_register(&s3c2442_cpufreq_interface);
}
-
subsys_initcall(s3c2442_cpufreq_init);
diff --git a/arch/arm/plat-s3c24xx/s3c2410-cpufreq-utils.c b/arch/arm/mach-s3c24xx/cpufreq-utils.c
index 43ea80190d87..ddd8280e3875 100644
--- a/arch/arm/plat-s3c24xx/s3c2410-cpufreq-utils.c
+++ b/arch/arm/mach-s3c24xx/cpufreq-utils.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-s3c24xx/s3c2410-cpufreq-utils.c
- *
+/*
* Copyright (c) 2009 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -17,11 +16,12 @@
#include <linux/io.h>
#include <mach/map.h>
-#include <mach/regs-mem.h>
#include <mach/regs-clock.h>
#include <plat/cpu-freq-core.h>
+#include "regs-mem.h"
+
/**
* s3c2410_cpufreq_setrefresh - set SDRAM refresh value
* @cfg: The frequency configuration
diff --git a/arch/arm/plat-s3c24xx/cpu-freq.c b/arch/arm/mach-s3c24xx/cpufreq.c
index 468079938884..5f181e733eee 100644
--- a/arch/arm/plat-s3c24xx/cpu-freq.c
+++ b/arch/arm/mach-s3c24xx/cpufreq.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-s3c24xx/cpu-freq.c
- *
+/*
* Copyright (c) 2006-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2410.c b/arch/arm/mach-s3c24xx/dma-s3c2410.c
index 4803338cf56e..25d085adc93c 100644
--- a/arch/arm/mach-s3c24xx/dma-s3c2410.c
+++ b/arch/arm/mach-s3c24xx/dma-s3c2410.c
@@ -27,7 +27,6 @@
#include <mach/regs-gpio.h>
#include <plat/regs-ac97.h>
#include <plat/regs-dma.h>
-#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>
#include <plat/regs-iis.h>
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2412.c b/arch/arm/mach-s3c24xx/dma-s3c2412.c
index 38472ac920ff..d2408ba372cb 100644
--- a/arch/arm/mach-s3c24xx/dma-s3c2412.c
+++ b/arch/arm/mach-s3c24xx/dma-s3c2412.c
@@ -27,7 +27,6 @@
#include <mach/regs-gpio.h>
#include <plat/regs-ac97.h>
#include <plat/regs-dma.h>
-#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>
#include <plat/regs-iis.h>
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2440.c b/arch/arm/mach-s3c24xx/dma-s3c2440.c
index 5f0a0c8ef84f..0b86e74d104f 100644
--- a/arch/arm/mach-s3c24xx/dma-s3c2440.c
+++ b/arch/arm/mach-s3c24xx/dma-s3c2440.c
@@ -27,7 +27,6 @@
#include <mach/regs-gpio.h>
#include <plat/regs-ac97.h>
#include <plat/regs-dma.h>
-#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>
#include <plat/regs-iis.h>
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2443.c b/arch/arm/mach-s3c24xx/dma-s3c2443.c
index 2d94228d2866..05536254a3f8 100644
--- a/arch/arm/mach-s3c24xx/dma-s3c2443.c
+++ b/arch/arm/mach-s3c24xx/dma-s3c2443.c
@@ -27,7 +27,6 @@
#include <mach/regs-gpio.h>
#include <plat/regs-ac97.h>
#include <plat/regs-dma.h>
-#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>
#include <plat/regs-iis.h>
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/mach-s3c24xx/dma.c
index ba3e76c95504..aab64909e9a3 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/mach-s3c24xx/dma.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-s3c24xx/dma.c
- *
+/*
* Copyright 2003-2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
diff --git a/arch/arm/mach-s3c24xx/include/mach/gta02.h b/arch/arm/mach-s3c24xx/gta02.h
index 217393482153..9430a71e9184 100644
--- a/arch/arm/mach-s3c24xx/include/mach/gta02.h
+++ b/arch/arm/mach-s3c24xx/gta02.h
@@ -1,5 +1,13 @@
-#ifndef _GTA02_H
-#define _GTA02_H
+/*
+ * GTA02 header
+ *
+ * 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 __MACH_S3C24XX_GTA02_H
+#define __MACH_S3C24XX_GTA02_H __FILE__
#include <mach/regs-gpio.h>
@@ -12,4 +20,4 @@
#define GTA02_IRQ_PCF50633 IRQ_EINT9
-#endif /* _GTA02_H */
+#endif /* __MACH_S3C24XX_GTA02_H */
diff --git a/arch/arm/mach-s3c24xx/h1940-bluetooth.c b/arch/arm/mach-s3c24xx/h1940-bluetooth.c
index 3f40c61b6e02..5b98bfd1df43 100644
--- a/arch/arm/mach-s3c24xx/h1940-bluetooth.c
+++ b/arch/arm/mach-s3c24xx/h1940-bluetooth.c
@@ -19,10 +19,10 @@
#include <linux/gpio.h>
#include <linux/rfkill.h>
-#include <mach/regs-gpio.h>
#include <mach/hardware.h>
-#include <mach/h1940-latch.h>
-#include <mach/h1940.h>
+#include <mach/regs-gpio.h>
+
+#include "h1940.h"
#define DRV_NAME "h1940-bt"
diff --git a/arch/arm/mach-s3c24xx/include/mach/h1940-latch.h b/arch/arm/mach-s3c24xx/h1940.h
index fc897d3a056c..2950cc466840 100644
--- a/arch/arm/mach-s3c24xx/include/mach/h1940-latch.h
+++ b/arch/arm/mach-s3c24xx/h1940.h
@@ -1,20 +1,30 @@
-/* arch/arm/mach-s3c2410/include/mach/h1940-latch.h
+/*
+ * Copyright 2006 Ben Dooks <ben-linux@fluff.org>
*
* Copyright (c) 2005 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
- * iPAQ H1940 series - latch definitions
+ * iPAQ H1940 series definitions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#ifndef __ASM_ARCH_H1940_LATCH_H
-#define __ASM_ARCH_H1940_LATCH_H
+#ifndef __MACH_S3C24XX_H1940_H
+#define __MACH_S3C24XX_H1940_H __FILE__
-#include <asm/gpio.h>
+#define H1940_SUSPEND_CHECKSUM (0x30003ff8)
+#define H1940_SUSPEND_RESUMEAT (0x30081000)
+#define H1940_SUSPEND_CHECK (0x30080000)
+
+extern void h1940_pm_return(void);
+extern int h1940_led_blink_set(unsigned gpio, int state,
+ unsigned long *delay_on,
+ unsigned long *delay_off);
+
+#include <linux/gpio.h>
#define H1940_LATCH_GPIO(x) (S3C_GPIO_END + (x))
@@ -40,4 +50,4 @@
#define H1940_LATCH_LED_GREEN H1940_LATCH_GPIO(14)
#define H1940_LATCH_LED_FLASH H1940_LATCH_GPIO(15)
-#endif /* __ASM_ARCH_H1940_LATCH_H */
+#endif /* __MACH_S3C24XX_H1940_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/anubis-cpld.h b/arch/arm/mach-s3c24xx/include/mach/anubis-cpld.h
deleted file mode 100644
index 1b614d5a81f3..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/anubis-cpld.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/anubis-cpld.h
- *
- * Copyright (c) 2005 Simtec Electronics
- * http://www.simtec.co.uk/products/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * ANUBIS - CPLD control constants
- *
- * 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_ANUBISCPLD_H
-#define __ASM_ARCH_ANUBISCPLD_H
-
-/* CTRL2 - NAND WP control, IDE Reset assert/check */
-
-#define ANUBIS_CTRL1_NANDSEL (0x3)
-
-/* IDREG - revision */
-
-#define ANUBIS_IDREG_REVMASK (0x7)
-
-#endif /* __ASM_ARCH_ANUBISCPLD_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/anubis-irq.h b/arch/arm/mach-s3c24xx/include/mach/anubis-irq.h
deleted file mode 100644
index a2a328134e34..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/anubis-irq.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/anubis-irq.h
- *
- * Copyright (c) 2005 Simtec Electronics
- * http://www.simtec.co.uk/products/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * ANUBIS - IRQ Number definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_ANUBISIRQ_H
-#define __ASM_ARCH_ANUBISIRQ_H
-
-#define IRQ_IDE0 IRQ_EINT2
-#define IRQ_IDE1 IRQ_EINT3
-#define IRQ_ASIX IRQ_EINT1
-
-#endif /* __ASM_ARCH_ANUBISIRQ_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/anubis-map.h b/arch/arm/mach-s3c24xx/include/mach/anubis-map.h
deleted file mode 100644
index c9deb3a5b2c3..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/anubis-map.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/anubis-map.h
- *
- * Copyright (c) 2005 Simtec Electronics
- * http://www.simtec.co.uk/products/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * ANUBIS - Memory map definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/* needs arch/map.h including with this */
-
-#ifndef __ASM_ARCH_ANUBISMAP_H
-#define __ASM_ARCH_ANUBISMAP_H
-
-/* start peripherals off after the S3C2410 */
-
-#define ANUBIS_IOADDR(x) (S3C2410_ADDR((x) + 0x01800000))
-
-#define ANUBIS_PA_CPLD (S3C2410_CS1 | (1<<26))
-
-/* we put the CPLD registers next, to get them out of the way */
-
-#define ANUBIS_VA_CTRL1 ANUBIS_IOADDR(0x00000000) /* 0x01800000 */
-#define ANUBIS_PA_CTRL1 (ANUBIS_PA_CPLD)
-
-#define ANUBIS_VA_IDREG ANUBIS_IOADDR(0x00300000) /* 0x01B00000 */
-#define ANUBIS_PA_IDREG (ANUBIS_PA_CPLD + (3<<23))
-
-#define ANUBIS_IDEPRI ANUBIS_IOADDR(0x01000000)
-#define ANUBIS_IDEPRIAUX ANUBIS_IOADDR(0x01100000)
-#define ANUBIS_IDESEC ANUBIS_IOADDR(0x01200000)
-#define ANUBIS_IDESECAUX ANUBIS_IOADDR(0x01300000)
-
-#endif /* __ASM_ARCH_ANUBISMAP_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/bast-cpld.h b/arch/arm/mach-s3c24xx/include/mach/bast-cpld.h
deleted file mode 100644
index bee2a7a932a0..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/bast-cpld.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/bast-cpld.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * BAST - CPLD control constants
- *
- * 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_BASTCPLD_H
-#define __ASM_ARCH_BASTCPLD_H
-
-/* CTRL1 - Audio LR routing */
-
-#define BAST_CPLD_CTRL1_LRCOFF (0x00)
-#define BAST_CPLD_CTRL1_LRCADC (0x01)
-#define BAST_CPLD_CTRL1_LRCDAC (0x02)
-#define BAST_CPLD_CTRL1_LRCARM (0x03)
-#define BAST_CPLD_CTRL1_LRMASK (0x03)
-
-/* CTRL2 - NAND WP control, IDE Reset assert/check */
-
-#define BAST_CPLD_CTRL2_WNAND (0x04)
-#define BAST_CPLD_CTLR2_IDERST (0x08)
-
-/* CTRL3 - rom write control, CPLD identity */
-
-#define BAST_CPLD_CTRL3_IDMASK (0x0e)
-#define BAST_CPLD_CTRL3_ROMWEN (0x01)
-
-/* CTRL4 - 8bit LCD interface control/status */
-
-#define BAST_CPLD_CTRL4_LLAT (0x01)
-#define BAST_CPLD_CTRL4_LCDRW (0x02)
-#define BAST_CPLD_CTRL4_LCDCMD (0x04)
-#define BAST_CPLD_CTRL4_LCDE2 (0x01)
-
-/* CTRL5 - DMA routing */
-
-#define BAST_CPLD_DMA0_PRIIDE (0<<0)
-#define BAST_CPLD_DMA0_SECIDE (1<<0)
-#define BAST_CPLD_DMA0_ISA15 (2<<0)
-#define BAST_CPLD_DMA0_ISA36 (3<<0)
-
-#define BAST_CPLD_DMA1_PRIIDE (0<<2)
-#define BAST_CPLD_DMA1_SECIDE (1<<2)
-#define BAST_CPLD_DMA1_ISA15 (2<<2)
-#define BAST_CPLD_DMA1_ISA36 (3<<2)
-
-#endif /* __ASM_ARCH_BASTCPLD_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/bast-irq.h b/arch/arm/mach-s3c24xx/include/mach/bast-irq.h
deleted file mode 100644
index cac428c42e7f..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/bast-irq.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/bast-irq.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * Machine BAST - IRQ Number definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_BASTIRQ_H
-#define __ASM_ARCH_BASTIRQ_H
-
-/* irq numbers to onboard peripherals */
-
-#define IRQ_USBOC IRQ_EINT18
-#define IRQ_IDE0 IRQ_EINT16
-#define IRQ_IDE1 IRQ_EINT17
-#define IRQ_PCSERIAL1 IRQ_EINT15
-#define IRQ_PCSERIAL2 IRQ_EINT14
-#define IRQ_PCPARALLEL IRQ_EINT13
-#define IRQ_ASIX IRQ_EINT11
-#define IRQ_DM9000 IRQ_EINT10
-#define IRQ_ISA IRQ_EINT9
-#define IRQ_SMALERT IRQ_EINT8
-
-#endif /* __ASM_ARCH_BASTIRQ_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/bast-map.h b/arch/arm/mach-s3c24xx/include/mach/bast-map.h
deleted file mode 100644
index eecea2a50f8f..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/bast-map.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/bast-map.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * Machine BAST - Memory map definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/* needs arch/map.h including with this */
-
-/* ok, we've used up to 0x13000000, now we need to find space for the
- * peripherals that live in the nGCS[x] areas, which are quite numerous
- * in their space. We also have the board's CPLD to find register space
- * for.
- */
-
-#ifndef __ASM_ARCH_BASTMAP_H
-#define __ASM_ARCH_BASTMAP_H
-
-#define BAST_IOADDR(x) (S3C2410_ADDR((x) + 0x01300000))
-
-/* we put the CPLD registers next, to get them out of the way */
-
-#define BAST_VA_CTRL1 BAST_IOADDR(0x00000000) /* 0x01300000 */
-#define BAST_PA_CTRL1 (S3C2410_CS5 | 0x7800000)
-
-#define BAST_VA_CTRL2 BAST_IOADDR(0x00100000) /* 0x01400000 */
-#define BAST_PA_CTRL2 (S3C2410_CS1 | 0x6000000)
-
-#define BAST_VA_CTRL3 BAST_IOADDR(0x00200000) /* 0x01500000 */
-#define BAST_PA_CTRL3 (S3C2410_CS1 | 0x6800000)
-
-#define BAST_VA_CTRL4 BAST_IOADDR(0x00300000) /* 0x01600000 */
-#define BAST_PA_CTRL4 (S3C2410_CS1 | 0x7000000)
-
-/* next, we have the PC104 ISA interrupt registers */
-
-#define BAST_PA_PC104_IRQREQ (S3C2410_CS5 | 0x6000000) /* 0x01700000 */
-#define BAST_VA_PC104_IRQREQ BAST_IOADDR(0x00400000)
-
-#define BAST_PA_PC104_IRQRAW (S3C2410_CS5 | 0x6800000) /* 0x01800000 */
-#define BAST_VA_PC104_IRQRAW BAST_IOADDR(0x00500000)
-
-#define BAST_PA_PC104_IRQMASK (S3C2410_CS5 | 0x7000000) /* 0x01900000 */
-#define BAST_VA_PC104_IRQMASK BAST_IOADDR(0x00600000)
-
-#define BAST_PA_LCD_RCMD1 (0x8800000)
-#define BAST_VA_LCD_RCMD1 BAST_IOADDR(0x00700000)
-
-#define BAST_PA_LCD_WCMD1 (0x8000000)
-#define BAST_VA_LCD_WCMD1 BAST_IOADDR(0x00800000)
-
-#define BAST_PA_LCD_RDATA1 (0x9800000)
-#define BAST_VA_LCD_RDATA1 BAST_IOADDR(0x00900000)
-
-#define BAST_PA_LCD_WDATA1 (0x9000000)
-#define BAST_VA_LCD_WDATA1 BAST_IOADDR(0x00A00000)
-
-#define BAST_PA_LCD_RCMD2 (0xA800000)
-#define BAST_VA_LCD_RCMD2 BAST_IOADDR(0x00B00000)
-
-#define BAST_PA_LCD_WCMD2 (0xA000000)
-#define BAST_VA_LCD_WCMD2 BAST_IOADDR(0x00C00000)
-
-#define BAST_PA_LCD_RDATA2 (0xB800000)
-#define BAST_VA_LCD_RDATA2 BAST_IOADDR(0x00D00000)
-
-#define BAST_PA_LCD_WDATA2 (0xB000000)
-#define BAST_VA_LCD_WDATA2 BAST_IOADDR(0x00E00000)
-
-
-/* 0xE0000000 contains the IO space that is split by speed and
- * whether the access is for 8 or 16bit IO... this ensures that
- * the correct access is made
- *
- * 0x10000000 of space, partitioned as so:
- *
- * 0x00000000 to 0x04000000 8bit, slow
- * 0x04000000 to 0x08000000 16bit, slow
- * 0x08000000 to 0x0C000000 16bit, net
- * 0x0C000000 to 0x10000000 16bit, fast
- *
- * each of these spaces has the following in:
- *
- * 0x00000000 to 0x01000000 16MB ISA IO space
- * 0x01000000 to 0x02000000 16MB ISA memory space
- * 0x02000000 to 0x02100000 1MB IDE primary channel
- * 0x02100000 to 0x02200000 1MB IDE primary channel aux
- * 0x02200000 to 0x02400000 1MB IDE secondary channel
- * 0x02300000 to 0x02400000 1MB IDE secondary channel aux
- * 0x02400000 to 0x02500000 1MB ASIX ethernet controller
- * 0x02500000 to 0x02600000 1MB Davicom DM9000 ethernet controller
- * 0x02600000 to 0x02700000 1MB PC SuperIO controller
- *
- * the phyiscal layout of the zones are:
- * nGCS2 - 8bit, slow
- * nGCS3 - 16bit, slow
- * nGCS4 - 16bit, net
- * nGCS5 - 16bit, fast
- */
-
-#define BAST_VA_MULTISPACE (0xE0000000)
-
-#define BAST_VA_ISAIO (BAST_VA_MULTISPACE + 0x00000000)
-#define BAST_VA_ISAMEM (BAST_VA_MULTISPACE + 0x01000000)
-#define BAST_VA_IDEPRI (BAST_VA_MULTISPACE + 0x02000000)
-#define BAST_VA_IDEPRIAUX (BAST_VA_MULTISPACE + 0x02100000)
-#define BAST_VA_IDESEC (BAST_VA_MULTISPACE + 0x02200000)
-#define BAST_VA_IDESECAUX (BAST_VA_MULTISPACE + 0x02300000)
-#define BAST_VA_ASIXNET (BAST_VA_MULTISPACE + 0x02400000)
-#define BAST_VA_DM9000 (BAST_VA_MULTISPACE + 0x02500000)
-#define BAST_VA_SUPERIO (BAST_VA_MULTISPACE + 0x02600000)
-
-#define BAST_VA_MULTISPACE (0xE0000000)
-
-#define BAST_VAM_CS2 (0x00000000)
-#define BAST_VAM_CS3 (0x04000000)
-#define BAST_VAM_CS4 (0x08000000)
-#define BAST_VAM_CS5 (0x0C000000)
-
-/* physical offset addresses for the peripherals */
-
-#define BAST_PA_ISAIO (0x00000000)
-#define BAST_PA_ASIXNET (0x01000000)
-#define BAST_PA_SUPERIO (0x01800000)
-#define BAST_PA_IDEPRI (0x02000000)
-#define BAST_PA_IDEPRIAUX (0x02800000)
-#define BAST_PA_IDESEC (0x03000000)
-#define BAST_PA_IDESECAUX (0x03800000)
-#define BAST_PA_ISAMEM (0x04000000)
-#define BAST_PA_DM9000 (0x05000000)
-
-/* some configurations for the peripherals */
-
-#define BAST_PCSIO (BAST_VA_SUPERIO + BAST_VAM_CS2)
-/* */
-
-#define BAST_ASIXNET_CS BAST_VAM_CS5
-#define BAST_IDE_CS BAST_VAM_CS5
-#define BAST_DM9000_CS BAST_VAM_CS4
-
-#endif /* __ASM_ARCH_BASTMAP_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/debug-macro.S b/arch/arm/mach-s3c24xx/include/mach/debug-macro.S
index 4135de87d1f7..13ed33c69113 100644
--- a/arch/arm/mach-s3c24xx/include/mach/debug-macro.S
+++ b/arch/arm/mach-s3c24xx/include/mach/debug-macro.S
@@ -40,17 +40,17 @@
addeq \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
addne \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART)
bic \rd, \rd, #0xff000
- ldr \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
+ ldr \rd, [\rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0)]
and \rd, \rd, #0x00ff0000
teq \rd, #0x00440000 @ is it 2440?
1004:
- ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ ldr \rd, [\rx, # S3C2410_UFSTAT]
moveq \rd, \rd, lsr #SHIFT_2440TXF
tst \rd, #S3C2410_UFSTAT_TXFULL
.endm
.macro fifo_full_s3c2410 rd, rx
- ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ ldr \rd, [\rx, # S3C2410_UFSTAT]
tst \rd, #S3C2410_UFSTAT_TXFULL
.endm
@@ -68,18 +68,18 @@
addeq \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
addne \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART)
bic \rd, \rd, #0xff000
- ldr \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
+ ldr \rd, [\rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0)]
and \rd, \rd, #0x00ff0000
teq \rd, #0x00440000 @ is it 2440?
10000:
- ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ ldr \rd, [\rx, # S3C2410_UFSTAT]
andne \rd, \rd, #S3C2410_UFSTAT_TXMASK
andeq \rd, \rd, #S3C2440_UFSTAT_TXMASK
.endm
.macro fifo_level_s3c2410 rd, rx
- ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ ldr \rd, [\rx, # S3C2410_UFSTAT]
and \rd, \rd, #S3C2410_UFSTAT_TXMASK
.endm
diff --git a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S
index 7615a14773fa..6a21beeba1da 100644
--- a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S
+++ b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S
@@ -31,10 +31,10 @@
@@ try the interrupt offset register, since it is there
- ldr \irqstat, [ \base, #INTPND ]
+ ldr \irqstat, [\base, #INTPND ]
teq \irqstat, #0
beq 1002f
- ldr \irqnr, [ \base, #INTOFFSET ]
+ ldr \irqnr, [\base, #INTOFFSET ]
mov \tmp, #1
tst \irqstat, \tmp, lsl \irqnr
bne 1001f
diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio-fns.h b/arch/arm/mach-s3c24xx/include/mach/gpio-fns.h
deleted file mode 100644
index c53ad34c6579..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/gpio-fns.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <plat/gpio-fns.h>
diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio-nrs.h b/arch/arm/mach-s3c24xx/include/mach/gpio-nrs.h
deleted file mode 100644
index 3890a05948fb..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/gpio-nrs.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
- *
- * Copyright (c) 2008 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - GPIO bank numbering
- *
- * 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 __MACH_GPIONRS_H
-#define __MACH_GPIONRS_H
-
-#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
-
-#define S3C2410_GPIO_BANKG (32*6)
-#define S3C2410_GPIO_BANKH (32*7)
-
-/* GPIO sizes for various SoCs:
- *
- * 2442
- * 2410 2412 2440 2443 2416
- * ---- ---- ---- ---- ----
- * A 23 22 25 16 25
- * B 11 11 11 11 9
- * C 16 15 16 16 16
- * D 16 16 16 16 16
- * E 16 16 16 16 16
- * F 8 8 8 8 8
- * G 16 16 16 16 8
- * H 11 11 9 15 15
- * J -- -- 13 16 --
- * K -- -- -- -- 16
- * L -- -- -- 15 7
- * M -- -- -- 2 2
- */
-
-/* GPIO bank sizes */
-#define S3C2410_GPIO_A_NR (32)
-#define S3C2410_GPIO_B_NR (32)
-#define S3C2410_GPIO_C_NR (32)
-#define S3C2410_GPIO_D_NR (32)
-#define S3C2410_GPIO_E_NR (32)
-#define S3C2410_GPIO_F_NR (32)
-#define S3C2410_GPIO_G_NR (32)
-#define S3C2410_GPIO_H_NR (32)
-#define S3C2410_GPIO_J_NR (32) /* technically 16. */
-#define S3C2410_GPIO_K_NR (32) /* technically 16. */
-#define S3C2410_GPIO_L_NR (32) /* technically 15. */
-#define S3C2410_GPIO_M_NR (32) /* technically 2. */
-
-#if CONFIG_S3C_GPIO_SPACE != 0
-#error CONFIG_S3C_GPIO_SPACE cannot be nonzero at the moment
-#endif
-
-#define S3C2410_GPIO_NEXT(__gpio) \
- ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)
-
-#ifndef __ASSEMBLY__
-
-enum s3c_gpio_number {
- S3C2410_GPIO_A_START = 0,
- S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
- S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
- S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
- S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
- S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
- S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
- S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
- S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H),
- S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J),
- S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K),
- S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L),
-};
-
-#endif /* __ASSEMBLY__ */
-
-/* S3C2410 GPIO number definitions. */
-
-#define S3C2410_GPA(_nr) (S3C2410_GPIO_A_START + (_nr))
-#define S3C2410_GPB(_nr) (S3C2410_GPIO_B_START + (_nr))
-#define S3C2410_GPC(_nr) (S3C2410_GPIO_C_START + (_nr))
-#define S3C2410_GPD(_nr) (S3C2410_GPIO_D_START + (_nr))
-#define S3C2410_GPE(_nr) (S3C2410_GPIO_E_START + (_nr))
-#define S3C2410_GPF(_nr) (S3C2410_GPIO_F_START + (_nr))
-#define S3C2410_GPG(_nr) (S3C2410_GPIO_G_START + (_nr))
-#define S3C2410_GPH(_nr) (S3C2410_GPIO_H_START + (_nr))
-#define S3C2410_GPJ(_nr) (S3C2410_GPIO_J_START + (_nr))
-#define S3C2410_GPK(_nr) (S3C2410_GPIO_K_START + (_nr))
-#define S3C2410_GPL(_nr) (S3C2410_GPIO_L_START + (_nr))
-#define S3C2410_GPM(_nr) (S3C2410_GPIO_M_START + (_nr))
-
-#endif /* __MACH_GPIONRS_H */
-
diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio-track.h b/arch/arm/mach-s3c24xx/include/mach/gpio-track.h
deleted file mode 100644
index c410a078622c..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/gpio-track.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* arch/arm/mach-s3c24100/include/mach/gpio-core.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- * http://armlinux.simtec.co.uk/
- *
- * S3C2410 - GPIO core 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.
-*/
-
-#ifndef __ASM_ARCH_GPIO_CORE_H
-#define __ASM_ARCH_GPIO_CORE_H __FILE__
-
-#include <mach/regs-gpio.h>
-
-extern struct samsung_gpio_chip s3c24xx_gpios[];
-
-static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int pin)
-{
- struct samsung_gpio_chip *chip;
-
- if (pin > S3C_GPIO_END)
- return NULL;
-
- chip = &s3c24xx_gpios[pin/32];
- return ((pin - chip->chip.base) < chip->chip.ngpio) ? chip : NULL;
-}
-
-#endif /* __ASM_ARCH_GPIO_CORE_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio.h b/arch/arm/mach-s3c24xx/include/mach/gpio.h
index 6fac70f3484e..14591563ca70 100644
--- a/arch/arm/mach-s3c24xx/include/mach/gpio.h
+++ b/arch/arm/mach-s3c24xx/include/mach/gpio.h
@@ -1,5 +1,4 @@
-/* arch/arm/mach-s3c2410/include/mach/gpio.h
- *
+/*
* Copyright (c) 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -15,6 +14,9 @@
* devices that need GPIO.
*/
+#ifndef __MACH_GPIO_H
+#define __MACH_GPIO_H __FILE__
+
#ifdef CONFIG_CPU_S3C244X
#define ARCH_NR_GPIOS (32 * 9 + CONFIG_S3C24XX_GPIO_EXTRA)
#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
@@ -23,8 +25,83 @@
#define ARCH_NR_GPIOS (256 + CONFIG_S3C24XX_GPIO_EXTRA)
#endif
-#include <mach/gpio-nrs.h>
-#include <mach/gpio-fns.h>
+/*
+ * GPIO sizes for various SoCs:
+ *
+ * 2410 2412 2440 2443 2416
+ * 2442
+ * ---- ---- ---- ---- ----
+ * A 23 22 25 16 25
+ * B 11 11 11 11 9
+ * C 16 15 16 16 16
+ * D 16 16 16 16 16
+ * E 16 16 16 16 16
+ * F 8 8 8 8 8
+ * G 16 16 16 16 8
+ * H 11 11 9 15 15
+ * J -- -- 13 16 --
+ * K -- -- -- -- 16
+ * L -- -- -- 15 7
+ * M -- -- -- 2 2
+ */
+
+/* GPIO bank sizes */
+
+#define S3C2410_GPIO_A_NR (32)
+#define S3C2410_GPIO_B_NR (32)
+#define S3C2410_GPIO_C_NR (32)
+#define S3C2410_GPIO_D_NR (32)
+#define S3C2410_GPIO_E_NR (32)
+#define S3C2410_GPIO_F_NR (32)
+#define S3C2410_GPIO_G_NR (32)
+#define S3C2410_GPIO_H_NR (32)
+#define S3C2410_GPIO_J_NR (32) /* technically 16. */
+#define S3C2410_GPIO_K_NR (32) /* technically 16. */
+#define S3C2410_GPIO_L_NR (32) /* technically 15. */
+#define S3C2410_GPIO_M_NR (32) /* technically 2. */
+
+#if CONFIG_S3C_GPIO_SPACE != 0
+#error CONFIG_S3C_GPIO_SPACE cannot be nonzero at the moment
+#endif
+
+#define S3C2410_GPIO_NEXT(__gpio) \
+ ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)
+
+#ifndef __ASSEMBLY__
+
+enum s3c_gpio_number {
+ S3C2410_GPIO_A_START = 0,
+ S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
+ S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
+ S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
+ S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
+ S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
+ S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
+ S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
+ S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H),
+ S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J),
+ S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K),
+ S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L),
+};
+
+#endif /* __ASSEMBLY__ */
+
+/* S3C2410 GPIO number definitions. */
+
+#define S3C2410_GPA(_nr) (S3C2410_GPIO_A_START + (_nr))
+#define S3C2410_GPB(_nr) (S3C2410_GPIO_B_START + (_nr))
+#define S3C2410_GPC(_nr) (S3C2410_GPIO_C_START + (_nr))
+#define S3C2410_GPD(_nr) (S3C2410_GPIO_D_START + (_nr))
+#define S3C2410_GPE(_nr) (S3C2410_GPIO_E_START + (_nr))
+#define S3C2410_GPF(_nr) (S3C2410_GPIO_F_START + (_nr))
+#define S3C2410_GPG(_nr) (S3C2410_GPIO_G_START + (_nr))
+#define S3C2410_GPH(_nr) (S3C2410_GPIO_H_START + (_nr))
+#define S3C2410_GPJ(_nr) (S3C2410_GPIO_J_START + (_nr))
+#define S3C2410_GPK(_nr) (S3C2410_GPIO_K_START + (_nr))
+#define S3C2410_GPL(_nr) (S3C2410_GPIO_L_START + (_nr))
+#define S3C2410_GPM(_nr) (S3C2410_GPIO_M_START + (_nr))
+
+#include <plat/gpio-cfg.h>
#ifdef CONFIG_CPU_S3C244X
#define S3C_GPIO_END (S3C2410_GPJ(0) + 32)
@@ -33,3 +110,5 @@
#else
#define S3C_GPIO_END (S3C2410_GPH(0) + 32)
#endif
+
+#endif /* __MACH_GPIO_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/h1940.h b/arch/arm/mach-s3c24xx/include/mach/h1940.h
deleted file mode 100644
index 2aa683c8d3d6..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/h1940.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/h1940.h
- *
- * Copyright 2006 Ben Dooks <ben-linux@fluff.org>
- *
- * H1940 definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_H1940_H
-#define __ASM_ARCH_H1940_H
-
-#define H1940_SUSPEND_CHECKSUM (0x30003ff8)
-#define H1940_SUSPEND_RESUMEAT (0x30081000)
-#define H1940_SUSPEND_CHECK (0x30080000)
-
-extern void h1940_pm_return(void);
-extern int h1940_led_blink_set(unsigned gpio, int state,
- unsigned long *delay_on, unsigned long *delay_off);
-
-
-#endif /* __ASM_ARCH_H1940_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/hardware.h b/arch/arm/mach-s3c24xx/include/mach/hardware.h
index aef5631eac58..a6cc14a092fc 100644
--- a/arch/arm/mach-s3c24xx/include/mach/hardware.h
+++ b/arch/arm/mach-s3c24xx/include/mach/hardware.h
@@ -23,12 +23,6 @@ extern int s3c2440_set_dsc(unsigned int pin, unsigned int value);
#endif /* CONFIG_CPU_S3C2440 */
-#ifdef CONFIG_CPU_S3C2412
-
-extern int s3c2412_gpio_set_sleepcfg(unsigned int pin, unsigned int state);
-
-#endif /* CONFIG_CPU_S3C2412 */
-
#endif /* __ASSEMBLY__ */
#include <asm/sizes.h>
diff --git a/arch/arm/mach-s3c24xx/include/mach/idle.h b/arch/arm/mach-s3c24xx/include/mach/idle.h
deleted file mode 100644
index e9ddd706b16e..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/idle.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/idle.h
- *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
- * http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2410 CPU Idle controls
-*/
-
-#ifndef __ASM_ARCH_IDLE_H
-#define __ASM_ARCH_IDLE_H __FILE__
-
-/* This allows the over-ride of the default idle code, in case there
- * is any other things to be done over idle (like DVS)
-*/
-
-extern void (*s3c24xx_idle)(void);
-
-extern void s3c24xx_default_idle(void);
-
-#endif /* __ASM_ARCH_IDLE_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/osiris-cpld.h b/arch/arm/mach-s3c24xx/include/mach/osiris-cpld.h
deleted file mode 100644
index e9e36b0abbac..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/osiris-cpld.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/osiris-cpld.h
- *
- * Copyright 2005 Simtec Electronics
- * http://www.simtec.co.uk/products/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * OSIRIS - CPLD control constants
- *
- * 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_OSIRISCPLD_H
-#define __ASM_ARCH_OSIRISCPLD_H
-
-/* CTRL0 - NAND WP control */
-
-#define OSIRIS_CTRL0_NANDSEL (0x3)
-#define OSIRIS_CTRL0_BOOT_INT (1<<3)
-#define OSIRIS_CTRL0_PCMCIA (1<<4)
-#define OSIRIS_CTRL0_FIX8 (1<<5)
-#define OSIRIS_CTRL0_PCMCIA_nWAIT (1<<6)
-#define OSIRIS_CTRL0_PCMCIA_nIOIS16 (1<<7)
-
-#define OSIRIS_CTRL1_FIX8 (1<<0)
-
-#define OSIRIS_ID_REVMASK (0x7)
-
-#endif /* __ASM_ARCH_OSIRISCPLD_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h b/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h
index a11a638bd599..c2ef016032ab 100644
--- a/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h
+++ b/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h
@@ -14,8 +14,6 @@
#ifndef __ASM_ARCH_REGS_GPIO_H
#define __ASM_ARCH_REGS_GPIO_H
-#include <mach/gpio-nrs.h>
-
#define S3C24XX_MISCCR S3C24XX_GPIOREG2(0x80)
/* general configuration options */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-mem.h b/arch/arm/mach-s3c24xx/include/mach/regs-mem.h
deleted file mode 100644
index e0c67b0163d8..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/regs-mem.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-mem.h
- *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
- * http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2410 Memory Control register definitions
-*/
-
-#ifndef __ASM_ARM_MEMREGS_H
-#define __ASM_ARM_MEMREGS_H
-
-#ifndef S3C2410_MEMREG
-#define S3C2410_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
-#endif
-
-/* bus width, and wait state control */
-#define S3C2410_BWSCON S3C2410_MEMREG(0x0000)
-
-/* bank zero config - note, pinstrapped from OM pins! */
-#define S3C2410_BWSCON_DW0_16 (1<<1)
-#define S3C2410_BWSCON_DW0_32 (2<<1)
-
-/* bank one configs */
-#define S3C2410_BWSCON_DW1_8 (0<<4)
-#define S3C2410_BWSCON_DW1_16 (1<<4)
-#define S3C2410_BWSCON_DW1_32 (2<<4)
-#define S3C2410_BWSCON_WS1 (1<<6)
-#define S3C2410_BWSCON_ST1 (1<<7)
-
-/* bank 2 configurations */
-#define S3C2410_BWSCON_DW2_8 (0<<8)
-#define S3C2410_BWSCON_DW2_16 (1<<8)
-#define S3C2410_BWSCON_DW2_32 (2<<8)
-#define S3C2410_BWSCON_WS2 (1<<10)
-#define S3C2410_BWSCON_ST2 (1<<11)
-
-/* bank 3 configurations */
-#define S3C2410_BWSCON_DW3_8 (0<<12)
-#define S3C2410_BWSCON_DW3_16 (1<<12)
-#define S3C2410_BWSCON_DW3_32 (2<<12)
-#define S3C2410_BWSCON_WS3 (1<<14)
-#define S3C2410_BWSCON_ST3 (1<<15)
-
-/* bank 4 configurations */
-#define S3C2410_BWSCON_DW4_8 (0<<16)
-#define S3C2410_BWSCON_DW4_16 (1<<16)
-#define S3C2410_BWSCON_DW4_32 (2<<16)
-#define S3C2410_BWSCON_WS4 (1<<18)
-#define S3C2410_BWSCON_ST4 (1<<19)
-
-/* bank 5 configurations */
-#define S3C2410_BWSCON_DW5_8 (0<<20)
-#define S3C2410_BWSCON_DW5_16 (1<<20)
-#define S3C2410_BWSCON_DW5_32 (2<<20)
-#define S3C2410_BWSCON_WS5 (1<<22)
-#define S3C2410_BWSCON_ST5 (1<<23)
-
-/* bank 6 configurations */
-#define S3C2410_BWSCON_DW6_8 (0<<24)
-#define S3C2410_BWSCON_DW6_16 (1<<24)
-#define S3C2410_BWSCON_DW6_32 (2<<24)
-#define S3C2410_BWSCON_WS6 (1<<26)
-#define S3C2410_BWSCON_ST6 (1<<27)
-
-/* bank 7 configurations */
-#define S3C2410_BWSCON_DW7_8 (0<<28)
-#define S3C2410_BWSCON_DW7_16 (1<<28)
-#define S3C2410_BWSCON_DW7_32 (2<<28)
-#define S3C2410_BWSCON_WS7 (1<<30)
-#define S3C2410_BWSCON_ST7 (1<<31)
-
-/* accesor functions for getting BANK(n) configuration. (n != 0) */
-
-#define S3C2410_BWSCON_GET(_bwscon, _bank) (((_bwscon) >> ((_bank) * 4)) & 0xf)
-
-#define S3C2410_BWSCON_DW8 (0)
-#define S3C2410_BWSCON_DW16 (1)
-#define S3C2410_BWSCON_DW32 (2)
-#define S3C2410_BWSCON_WS (1 << 2)
-#define S3C2410_BWSCON_ST (1 << 3)
-
-/* memory set (rom, ram) */
-#define S3C2410_BANKCON0 S3C2410_MEMREG(0x0004)
-#define S3C2410_BANKCON1 S3C2410_MEMREG(0x0008)
-#define S3C2410_BANKCON2 S3C2410_MEMREG(0x000C)
-#define S3C2410_BANKCON3 S3C2410_MEMREG(0x0010)
-#define S3C2410_BANKCON4 S3C2410_MEMREG(0x0014)
-#define S3C2410_BANKCON5 S3C2410_MEMREG(0x0018)
-#define S3C2410_BANKCON6 S3C2410_MEMREG(0x001C)
-#define S3C2410_BANKCON7 S3C2410_MEMREG(0x0020)
-
-/* bank configuration registers */
-
-#define S3C2410_BANKCON_PMCnorm (0x00)
-#define S3C2410_BANKCON_PMC4 (0x01)
-#define S3C2410_BANKCON_PMC8 (0x02)
-#define S3C2410_BANKCON_PMC16 (0x03)
-
-/* bank configurations for banks 0..7, note banks
- * 6 and 7 have different configurations depending on
- * the memory type bits */
-
-#define S3C2410_BANKCON_Tacp2 (0x0 << 2)
-#define S3C2410_BANKCON_Tacp3 (0x1 << 2)
-#define S3C2410_BANKCON_Tacp4 (0x2 << 2)
-#define S3C2410_BANKCON_Tacp6 (0x3 << 2)
-#define S3C2410_BANKCON_Tacp_SHIFT (2)
-
-#define S3C2410_BANKCON_Tcah0 (0x0 << 4)
-#define S3C2410_BANKCON_Tcah1 (0x1 << 4)
-#define S3C2410_BANKCON_Tcah2 (0x2 << 4)
-#define S3C2410_BANKCON_Tcah4 (0x3 << 4)
-#define S3C2410_BANKCON_Tcah_SHIFT (4)
-
-#define S3C2410_BANKCON_Tcoh0 (0x0 << 6)
-#define S3C2410_BANKCON_Tcoh1 (0x1 << 6)
-#define S3C2410_BANKCON_Tcoh2 (0x2 << 6)
-#define S3C2410_BANKCON_Tcoh4 (0x3 << 6)
-#define S3C2410_BANKCON_Tcoh_SHIFT (6)
-
-#define S3C2410_BANKCON_Tacc1 (0x0 << 8)
-#define S3C2410_BANKCON_Tacc2 (0x1 << 8)
-#define S3C2410_BANKCON_Tacc3 (0x2 << 8)
-#define S3C2410_BANKCON_Tacc4 (0x3 << 8)
-#define S3C2410_BANKCON_Tacc6 (0x4 << 8)
-#define S3C2410_BANKCON_Tacc8 (0x5 << 8)
-#define S3C2410_BANKCON_Tacc10 (0x6 << 8)
-#define S3C2410_BANKCON_Tacc14 (0x7 << 8)
-#define S3C2410_BANKCON_Tacc_SHIFT (8)
-
-#define S3C2410_BANKCON_Tcos0 (0x0 << 11)
-#define S3C2410_BANKCON_Tcos1 (0x1 << 11)
-#define S3C2410_BANKCON_Tcos2 (0x2 << 11)
-#define S3C2410_BANKCON_Tcos4 (0x3 << 11)
-#define S3C2410_BANKCON_Tcos_SHIFT (11)
-
-#define S3C2410_BANKCON_Tacs0 (0x0 << 13)
-#define S3C2410_BANKCON_Tacs1 (0x1 << 13)
-#define S3C2410_BANKCON_Tacs2 (0x2 << 13)
-#define S3C2410_BANKCON_Tacs4 (0x3 << 13)
-#define S3C2410_BANKCON_Tacs_SHIFT (13)
-
-#define S3C2410_BANKCON_SRAM (0x0 << 15)
-#define S3C2410_BANKCON_SDRAM (0x3 << 15)
-
-/* next bits only for SDRAM in 6,7 */
-#define S3C2410_BANKCON_Trcd2 (0x00 << 2)
-#define S3C2410_BANKCON_Trcd3 (0x01 << 2)
-#define S3C2410_BANKCON_Trcd4 (0x02 << 2)
-
-/* control column address select */
-#define S3C2410_BANKCON_SCANb8 (0x00 << 0)
-#define S3C2410_BANKCON_SCANb9 (0x01 << 0)
-#define S3C2410_BANKCON_SCANb10 (0x02 << 0)
-
-#define S3C2410_REFRESH S3C2410_MEMREG(0x0024)
-#define S3C2410_BANKSIZE S3C2410_MEMREG(0x0028)
-#define S3C2410_MRSRB6 S3C2410_MEMREG(0x002C)
-#define S3C2410_MRSRB7 S3C2410_MEMREG(0x0030)
-
-/* refresh control */
-
-#define S3C2410_REFRESH_REFEN (1<<23)
-#define S3C2410_REFRESH_SELF (1<<22)
-#define S3C2410_REFRESH_REFCOUNTER ((1<<11)-1)
-
-#define S3C2410_REFRESH_TRP_MASK (3<<20)
-#define S3C2410_REFRESH_TRP_2clk (0<<20)
-#define S3C2410_REFRESH_TRP_3clk (1<<20)
-#define S3C2410_REFRESH_TRP_4clk (2<<20)
-
-#define S3C2410_REFRESH_TSRC_MASK (3<<18)
-#define S3C2410_REFRESH_TSRC_4clk (0<<18)
-#define S3C2410_REFRESH_TSRC_5clk (1<<18)
-#define S3C2410_REFRESH_TSRC_6clk (2<<18)
-#define S3C2410_REFRESH_TSRC_7clk (3<<18)
-
-
-/* mode select register(s) */
-
-#define S3C2410_MRSRB_CL1 (0x00 << 4)
-#define S3C2410_MRSRB_CL2 (0x02 << 4)
-#define S3C2410_MRSRB_CL3 (0x03 << 4)
-
-/* bank size register */
-#define S3C2410_BANKSIZE_128M (0x2 << 0)
-#define S3C2410_BANKSIZE_64M (0x1 << 0)
-#define S3C2410_BANKSIZE_32M (0x0 << 0)
-#define S3C2410_BANKSIZE_16M (0x7 << 0)
-#define S3C2410_BANKSIZE_8M (0x6 << 0)
-#define S3C2410_BANKSIZE_4M (0x5 << 0)
-#define S3C2410_BANKSIZE_2M (0x4 << 0)
-#define S3C2410_BANKSIZE_MASK (0x7 << 0)
-#define S3C2410_BANKSIZE_SCLK_EN (1<<4)
-#define S3C2410_BANKSIZE_SCKE_EN (1<<5)
-#define S3C2410_BANKSIZE_BURST (1<<7)
-
-#endif /* __ASM_ARM_MEMREGS_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-power.h b/arch/arm/mach-s3c24xx/include/mach/regs-power.h
deleted file mode 100644
index 4932b87bdf3d..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/regs-power.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-power.h
- *
- * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk>
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * S3C24XX power control register definitions
-*/
-
-#ifndef __ASM_ARM_REGS_PWR
-#define __ASM_ARM_REGS_PWR __FILE__
-
-#define S3C24XX_PWRREG(x) ((x) + S3C24XX_VA_CLKPWR)
-
-#define S3C2412_PWRMODECON S3C24XX_PWRREG(0x20)
-#define S3C2412_PWRCFG S3C24XX_PWRREG(0x24)
-
-#define S3C2412_INFORM0 S3C24XX_PWRREG(0x70)
-#define S3C2412_INFORM1 S3C24XX_PWRREG(0x74)
-#define S3C2412_INFORM2 S3C24XX_PWRREG(0x78)
-#define S3C2412_INFORM3 S3C24XX_PWRREG(0x7C)
-
-#define S3C2412_PWRCFG_BATF_IRQ (1<<0)
-#define S3C2412_PWRCFG_BATF_IGNORE (2<<0)
-#define S3C2412_PWRCFG_BATF_SLEEP (3<<0)
-#define S3C2412_PWRCFG_BATF_MASK (3<<0)
-
-#define S3C2412_PWRCFG_STANDBYWFI_IGNORE (0<<6)
-#define S3C2412_PWRCFG_STANDBYWFI_IDLE (1<<6)
-#define S3C2412_PWRCFG_STANDBYWFI_STOP (2<<6)
-#define S3C2412_PWRCFG_STANDBYWFI_SLEEP (3<<6)
-#define S3C2412_PWRCFG_STANDBYWFI_MASK (3<<6)
-
-#define S3C2412_PWRCFG_RTC_MASKIRQ (1<<8)
-#define S3C2412_PWRCFG_NAND_NORST (1<<9)
-
-#endif /* __ASM_ARM_REGS_PWR */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412-mem.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412-mem.h
deleted file mode 100644
index fb6352515090..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412-mem.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-s3c2412-mem.h
- *
- * Copyright (c) 2008 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * S3C2412 memory register definitions
-*/
-
-#ifndef __ASM_ARM_REGS_S3C2412_MEM
-#define __ASM_ARM_REGS_S3C2412_MEM
-
-#define S3C2412_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
-#define S3C2412_EBIREG(x) (S3C2412_VA_EBI + (x))
-
-#define S3C2412_SSMCREG(x) (S3C2412_VA_SSMC + (x))
-#define S3C2412_SSMC(x, o) (S3C2412_SSMCREG((x * 0x20) + (o)))
-
-#define S3C2412_BANKCFG S3C2412_MEMREG(0x00)
-#define S3C2412_BANKCON1 S3C2412_MEMREG(0x04)
-#define S3C2412_BANKCON2 S3C2412_MEMREG(0x08)
-#define S3C2412_BANKCON3 S3C2412_MEMREG(0x0C)
-
-#define S3C2412_REFRESH S3C2412_MEMREG(0x10)
-#define S3C2412_TIMEOUT S3C2412_MEMREG(0x14)
-
-/* EBI control registers */
-
-#define S3C2412_EBI_PR S3C2412_EBIREG(0x00)
-#define S3C2412_EBI_BANKCFG S3C2412_EBIREG(0x04)
-
-/* SSMC control registers */
-
-#define S3C2412_SSMC_BANK(x) S3C2412_SSMC(x, 0x00)
-#define S3C2412_SMIDCYR(x) S3C2412_SSMC(x, 0x00)
-#define S3C2412_SMBWSTRD(x) S3C2412_SSMC(x, 0x04)
-#define S3C2412_SMBWSTWRR(x) S3C2412_SSMC(x, 0x08)
-#define S3C2412_SMBWSTOENR(x) S3C2412_SSMC(x, 0x0C)
-#define S3C2412_SMBWSTWENR(x) S3C2412_SSMC(x, 0x10)
-#define S3C2412_SMBCR(x) S3C2412_SSMC(x, 0x14)
-#define S3C2412_SMBSR(x) S3C2412_SSMC(x, 0x18)
-#define S3C2412_SMBWSTBRDR(x) S3C2412_SSMC(x, 0x1C)
-
-#endif /* __ASM_ARM_REGS_S3C2412_MEM */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412.h
deleted file mode 100644
index aa69dc79bc38..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-s3c2412.h
- *
- * Copyright 2007 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * S3C2412 specific register definitions
-*/
-
-#ifndef __ASM_ARCH_REGS_S3C2412_H
-#define __ASM_ARCH_REGS_S3C2412_H "s3c2412"
-
-#define S3C2412_SWRST (S3C24XX_VA_CLKPWR + 0x30)
-#define S3C2412_SWRST_RESET (0x533C2412)
-
-/* see regs-power.h for the other registers in the power block. */
-
-#endif /* __ASM_ARCH_REGS_S3C2412_H */
-
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416-mem.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416-mem.h
deleted file mode 100644
index 2f31b74974af..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416-mem.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-s3c2416-mem.h
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- * as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- * Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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.
- *
- * S3C2416 memory register definitions
-*/
-
-#ifndef __ASM_ARM_REGS_S3C2416_MEM
-#define __ASM_ARM_REGS_S3C2416_MEM
-
-#ifndef S3C2416_MEMREG
-#define S3C2416_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
-#endif
-
-#define S3C2416_BANKCFG S3C2416_MEMREG(0x00)
-#define S3C2416_BANKCON1 S3C2416_MEMREG(0x04)
-#define S3C2416_BANKCON2 S3C2416_MEMREG(0x08)
-#define S3C2416_BANKCON3 S3C2416_MEMREG(0x0C)
-
-#define S3C2416_REFRESH S3C2416_MEMREG(0x10)
-#define S3C2416_TIMEOUT S3C2416_MEMREG(0x14)
-
-#endif /* __ASM_ARM_REGS_S3C2416_MEM */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416.h
deleted file mode 100644
index e443167efb87..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-s3c2416.h
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- * as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- * Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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.
- *
- * S3C2416 specific register definitions
-*/
-
-#ifndef __ASM_ARCH_REGS_S3C2416_H
-#define __ASM_ARCH_REGS_S3C2416_H "s3c2416"
-
-#define S3C2416_SWRST (S3C24XX_VA_CLKPWR + 0x44)
-#define S3C2416_SWRST_RESET (0x533C2416)
-
-/* see regs-power.h for the other registers in the power block. */
-
-#endif /* __ASM_ARCH_REGS_S3C2416_H */
-
diff --git a/arch/arm/mach-s3c24xx/include/mach/vr1000-cpld.h b/arch/arm/mach-s3c24xx/include/mach/vr1000-cpld.h
deleted file mode 100644
index e4119913d7c5..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/vr1000-cpld.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/vr1000-cpld.h
- *
- * Copyright (c) 2003 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * VR1000 - CPLD control constants
- *
- * 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_VR1000CPLD_H
-#define __ASM_ARCH_VR1000CPLD_H
-
-#define VR1000_CPLD_CTRL2_RAMWEN (0x04) /* SRAM Write Enable */
-
-#endif /* __ASM_ARCH_VR1000CPLD_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/vr1000-irq.h b/arch/arm/mach-s3c24xx/include/mach/vr1000-irq.h
deleted file mode 100644
index 47add133b8ee..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/vr1000-irq.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/vr1000-irq.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * Machine VR1000 - IRQ Number definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_VR1000IRQ_H
-#define __ASM_ARCH_VR1000IRQ_H
-
-/* irq numbers to onboard peripherals */
-
-#define IRQ_USBOC IRQ_EINT19
-#define IRQ_IDE0 IRQ_EINT16
-#define IRQ_IDE1 IRQ_EINT17
-#define IRQ_VR1000_SERIAL IRQ_EINT12
-#define IRQ_VR1000_DM9000A IRQ_EINT10
-#define IRQ_VR1000_DM9000N IRQ_EINT9
-#define IRQ_SMALERT IRQ_EINT8
-
-#endif /* __ASM_ARCH_VR1000IRQ_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/vr1000-map.h b/arch/arm/mach-s3c24xx/include/mach/vr1000-map.h
deleted file mode 100644
index 28376e56dd3b..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/vr1000-map.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/vr1000-map.h
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * Machine VR1000 - Memory map definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/* needs arch/map.h including with this */
-
-/* ok, we've used up to 0x13000000, now we need to find space for the
- * peripherals that live in the nGCS[x] areas, which are quite numerous
- * in their space. We also have the board's CPLD to find register space
- * for.
- */
-
-#ifndef __ASM_ARCH_VR1000MAP_H
-#define __ASM_ARCH_VR1000MAP_H
-
-#include <mach/bast-map.h>
-
-#define VR1000_IOADDR(x) BAST_IOADDR(x)
-
-/* we put the CPLD registers next, to get them out of the way */
-
-#define VR1000_VA_CTRL1 VR1000_IOADDR(0x00000000) /* 0x01300000 */
-#define VR1000_PA_CTRL1 (S3C2410_CS5 | 0x7800000)
-
-#define VR1000_VA_CTRL2 VR1000_IOADDR(0x00100000) /* 0x01400000 */
-#define VR1000_PA_CTRL2 (S3C2410_CS1 | 0x6000000)
-
-#define VR1000_VA_CTRL3 VR1000_IOADDR(0x00200000) /* 0x01500000 */
-#define VR1000_PA_CTRL3 (S3C2410_CS1 | 0x6800000)
-
-#define VR1000_VA_CTRL4 VR1000_IOADDR(0x00300000) /* 0x01600000 */
-#define VR1000_PA_CTRL4 (S3C2410_CS1 | 0x7000000)
-
-/* next, we have the PC104 ISA interrupt registers */
-
-#define VR1000_PA_PC104_IRQREQ (S3C2410_CS5 | 0x6000000) /* 0x01700000 */
-#define VR1000_VA_PC104_IRQREQ VR1000_IOADDR(0x00400000)
-
-#define VR1000_PA_PC104_IRQRAW (S3C2410_CS5 | 0x6800000) /* 0x01800000 */
-#define VR1000_VA_PC104_IRQRAW VR1000_IOADDR(0x00500000)
-
-#define VR1000_PA_PC104_IRQMASK (S3C2410_CS5 | 0x7000000) /* 0x01900000 */
-#define VR1000_VA_PC104_IRQMASK VR1000_IOADDR(0x00600000)
-
-/* 0xE0000000 contains the IO space that is split by speed and
- * whether the access is for 8 or 16bit IO... this ensures that
- * the correct access is made
- *
- * 0x10000000 of space, partitioned as so:
- *
- * 0x00000000 to 0x04000000 8bit, slow
- * 0x04000000 to 0x08000000 16bit, slow
- * 0x08000000 to 0x0C000000 16bit, net
- * 0x0C000000 to 0x10000000 16bit, fast
- *
- * each of these spaces has the following in:
- *
- * 0x02000000 to 0x02100000 1MB IDE primary channel
- * 0x02100000 to 0x02200000 1MB IDE primary channel aux
- * 0x02200000 to 0x02400000 1MB IDE secondary channel
- * 0x02300000 to 0x02400000 1MB IDE secondary channel aux
- * 0x02500000 to 0x02600000 1MB Davicom DM9000 ethernet controllers
- * 0x02600000 to 0x02700000 1MB
- *
- * the phyiscal layout of the zones are:
- * nGCS2 - 8bit, slow
- * nGCS3 - 16bit, slow
- * nGCS4 - 16bit, net
- * nGCS5 - 16bit, fast
- */
-
-#define VR1000_VA_MULTISPACE (0xE0000000)
-
-#define VR1000_VA_ISAIO (VR1000_VA_MULTISPACE + 0x00000000)
-#define VR1000_VA_ISAMEM (VR1000_VA_MULTISPACE + 0x01000000)
-#define VR1000_VA_IDEPRI (VR1000_VA_MULTISPACE + 0x02000000)
-#define VR1000_VA_IDEPRIAUX (VR1000_VA_MULTISPACE + 0x02100000)
-#define VR1000_VA_IDESEC (VR1000_VA_MULTISPACE + 0x02200000)
-#define VR1000_VA_IDESECAUX (VR1000_VA_MULTISPACE + 0x02300000)
-#define VR1000_VA_ASIXNET (VR1000_VA_MULTISPACE + 0x02400000)
-#define VR1000_VA_DM9000 (VR1000_VA_MULTISPACE + 0x02500000)
-#define VR1000_VA_SUPERIO (VR1000_VA_MULTISPACE + 0x02600000)
-
-/* physical offset addresses for the peripherals */
-
-#define VR1000_PA_IDEPRI (0x02000000)
-#define VR1000_PA_IDEPRIAUX (0x02800000)
-#define VR1000_PA_IDESEC (0x03000000)
-#define VR1000_PA_IDESECAUX (0x03800000)
-#define VR1000_PA_DM9000 (0x05000000)
-
-#define VR1000_PA_SERIAL (0x11800000)
-#define VR1000_VA_SERIAL (VR1000_IOADDR(0x00700000))
-
-/* VR1000 ram is in CS1, with A26..A24 = 2_101 */
-#define VR1000_PA_SRAM (S3C2410_CS1 | 0x05000000)
-
-/* some configurations for the peripherals */
-
-#define VR1000_DM9000_CS VR1000_VAM_CS4
-
-#endif /* __ASM_ARCH_VR1000MAP_H */
diff --git a/arch/arm/plat-s3c24xx/s3c2410-iotiming.c b/arch/arm/mach-s3c24xx/iotiming-s3c2410.c
index b1908e56da1b..4cd13ab6496b 100644
--- a/arch/arm/plat-s3c24xx/s3c2410-iotiming.c
+++ b/arch/arm/mach-s3c24xx/iotiming-s3c2410.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-s3c24xx/s3c2410-iotiming.c
- *
+/*
* Copyright (c) 2006-2009 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -20,11 +19,12 @@
#include <linux/slab.h>
#include <mach/map.h>
-#include <mach/regs-mem.h>
#include <mach/regs-clock.h>
#include <plat/cpu-freq-core.h>
+#include "regs-mem.h"
+
#define print_ns(x) ((x) / 10), ((x) % 10)
/**
diff --git a/arch/arm/plat-s3c24xx/s3c2412-iotiming.c b/arch/arm/mach-s3c24xx/iotiming-s3c2412.c
index 48eee39ab369..663436d9db01 100644
--- a/arch/arm/plat-s3c24xx/s3c2412-iotiming.c
+++ b/arch/arm/mach-s3c24xx/iotiming-s3c2412.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-s3c24xx/s3c2412-iotiming.c
- *
+/*
* Copyright (c) 2006-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -28,12 +27,12 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/regs-s3c2412-mem.h>
-
#include <plat/cpu.h>
#include <plat/cpu-freq-core.h>
#include <plat/clock.h>
+#include "s3c2412.h"
+
#define print_ns(x) ((x) / 10), ((x) % 10)
/**
diff --git a/arch/arm/mach-s3c24xx/irq-pm.c b/arch/arm/mach-s3c24xx/irq-pm.c
index 0efb2e2848c8..e1199599873e 100644
--- a/arch/arm/mach-s3c24xx/irq-pm.c
+++ b/arch/arm/mach-s3c24xx/irq-pm.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/syscore_ops.h>
#include <plat/cpu.h>
#include <plat/pm.h>
@@ -29,18 +30,18 @@
* set bit to 1 in allow bitfield to enable the wakeup settings on it
*/
-unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
+unsigned long s3c_irqwake_intallow = 1L << 30 | 0xfL;
unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
int s3c_irq_wake(struct irq_data *data, unsigned int state)
{
- unsigned long irqbit = 1 << (data->irq - IRQ_EINT0);
+ unsigned long irqbit = 1 << data->hwirq;
if (!(s3c_irqwake_intallow & irqbit))
return -ENOENT;
- printk(KERN_INFO "wake %s for irq %d\n",
- state ? "enabled" : "disabled", data->irq);
+ pr_info("wake %s for hwirq %lu\n",
+ state ? "enabled" : "disabled", data->hwirq);
if (!state)
s3c_irqwake_intmask |= irqbit;
@@ -64,7 +65,7 @@ static unsigned long save_extint[3];
static unsigned long save_eintflt[4];
static unsigned long save_eintmask;
-int s3c24xx_irq_suspend(void)
+static int s3c24xx_irq_suspend(void)
{
unsigned int i;
@@ -80,7 +81,7 @@ int s3c24xx_irq_suspend(void)
return 0;
}
-void s3c24xx_irq_resume(void)
+static void s3c24xx_irq_resume(void)
{
unsigned int i;
@@ -93,3 +94,31 @@ void s3c24xx_irq_resume(void)
s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
__raw_writel(save_eintmask, S3C24XX_EINTMASK);
}
+
+struct syscore_ops s3c24xx_irq_syscore_ops = {
+ .suspend = s3c24xx_irq_suspend,
+ .resume = s3c24xx_irq_resume,
+};
+
+#ifdef CONFIG_CPU_S3C2416
+static struct sleep_save s3c2416_irq_save[] = {
+ SAVE_ITEM(S3C2416_INTMSK2),
+};
+
+static int s3c2416_irq_suspend(void)
+{
+ s3c_pm_do_save(s3c2416_irq_save, ARRAY_SIZE(s3c2416_irq_save));
+
+ return 0;
+}
+
+static void s3c2416_irq_resume(void)
+{
+ s3c_pm_do_restore(s3c2416_irq_save, ARRAY_SIZE(s3c2416_irq_save));
+}
+
+struct syscore_ops s3c2416_irq_syscore_ops = {
+ .suspend = s3c2416_irq_suspend,
+ .resume = s3c2416_irq_resume,
+};
+#endif
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2412.c b/arch/arm/mach-s3c24xx/irq-s3c2412.c
index e65619ddbccc..67d763178d3f 100644
--- a/arch/arm/mach-s3c24xx/irq-s3c2412.c
+++ b/arch/arm/mach-s3c24xx/irq-s3c2412.c
@@ -33,12 +33,13 @@
#include <mach/regs-irq.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-power.h>
#include <plat/cpu.h>
#include <plat/irq.h>
#include <plat/pm.h>
+#include "s3c2412-power.h"
+
#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
#define INTMSK_SUB(start, end) (INTMSK(start, end) << ((start - S3C2410_IRQSUB(0))))
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2416.c b/arch/arm/mach-s3c24xx/irq-s3c2416.c
deleted file mode 100644
index ff141b0af26b..000000000000
--- a/arch/arm/mach-s3c24xx/irq-s3c2416.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/irq.c
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- * as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- * Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/syscore_ops.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-
-#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
-
-static inline void s3c2416_irq_demux(unsigned int irq, unsigned int len)
-{
- unsigned int subsrc, submsk;
- unsigned int end;
-
- /* read the current pending interrupts, and the mask
- * for what it is available */
-
- subsrc = __raw_readl(S3C2410_SUBSRCPND);
- submsk = __raw_readl(S3C2410_INTSUBMSK);
-
- subsrc &= ~submsk;
- subsrc >>= (irq - S3C2410_IRQSUB(0));
- subsrc &= (1 << len)-1;
-
- end = len + irq;
-
- for (; irq < end && subsrc; irq++) {
- if (subsrc & 1)
- generic_handle_irq(irq);
-
- subsrc >>= 1;
- }
-}
-
-/* WDT/AC97 sub interrupts */
-
-static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
-{
- s3c2416_irq_demux(IRQ_S3C2443_WDT, 4);
-}
-
-#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
-#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
-
-static void s3c2416_irq_wdtac97_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static void s3c2416_irq_wdtac97_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
-}
-
-static void s3c2416_irq_wdtac97_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static struct irq_chip s3c2416_irq_wdtac97 = {
- .irq_mask = s3c2416_irq_wdtac97_mask,
- .irq_unmask = s3c2416_irq_wdtac97_unmask,
- .irq_ack = s3c2416_irq_wdtac97_ack,
-};
-
-/* LCD sub interrupts */
-
-static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
-{
- s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4);
-}
-
-#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
-#define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
-
-static void s3c2416_irq_lcd_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static void s3c2416_irq_lcd_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_LCD);
-}
-
-static void s3c2416_irq_lcd_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static struct irq_chip s3c2416_irq_lcd = {
- .irq_mask = s3c2416_irq_lcd_mask,
- .irq_unmask = s3c2416_irq_lcd_unmask,
- .irq_ack = s3c2416_irq_lcd_ack,
-};
-
-/* DMA sub interrupts */
-
-static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
-{
- s3c2416_irq_demux(IRQ_S3C2443_DMA0, 6);
-}
-
-#define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
-#define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
-
-
-static void s3c2416_irq_dma_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static void s3c2416_irq_dma_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_DMA);
-}
-
-static void s3c2416_irq_dma_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static struct irq_chip s3c2416_irq_dma = {
- .irq_mask = s3c2416_irq_dma_mask,
- .irq_unmask = s3c2416_irq_dma_unmask,
- .irq_ack = s3c2416_irq_dma_ack,
-};
-
-/* UART3 sub interrupts */
-
-static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
-{
- s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
-}
-
-#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
-static void s3c2416_irq_uart3_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static void s3c2416_irq_uart3_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_UART3);
-}
-
-static void s3c2416_irq_uart3_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static struct irq_chip s3c2416_irq_uart3 = {
- .irq_mask = s3c2416_irq_uart3_mask,
- .irq_unmask = s3c2416_irq_uart3_unmask,
- .irq_ack = s3c2416_irq_uart3_ack,
-};
-
-/* second interrupt register */
-
-static inline void s3c2416_irq_ack_second(struct irq_data *data)
-{
- unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
-
- __raw_writel(bitval, S3C2416_SRCPND2);
- __raw_writel(bitval, S3C2416_INTPND2);
-}
-
-static void s3c2416_irq_mask_second(struct irq_data *data)
-{
- unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
- unsigned long mask;
-
- mask = __raw_readl(S3C2416_INTMSK2);
- mask |= bitval;
- __raw_writel(mask, S3C2416_INTMSK2);
-}
-
-static void s3c2416_irq_unmask_second(struct irq_data *data)
-{
- unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D);
- unsigned long mask;
-
- mask = __raw_readl(S3C2416_INTMSK2);
- mask &= ~bitval;
- __raw_writel(mask, S3C2416_INTMSK2);
-}
-
-struct irq_chip s3c2416_irq_second = {
- .irq_ack = s3c2416_irq_ack_second,
- .irq_mask = s3c2416_irq_mask_second,
- .irq_unmask = s3c2416_irq_unmask_second,
-};
-
-
-/* IRQ initialisation code */
-
-static int s3c2416_add_sub(unsigned int base,
- void (*demux)(unsigned int,
- struct irq_desc *),
- struct irq_chip *chip,
- unsigned int start, unsigned int end)
-{
- unsigned int irqno;
-
- irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
- irq_set_chained_handler(base, demux);
-
- for (irqno = start; irqno <= end; irqno++) {
- irq_set_chip_and_handler(irqno, chip, handle_level_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- return 0;
-}
-
-static void s3c2416_irq_add_second(void)
-{
- unsigned long pend;
- unsigned long last;
- int irqno;
- int i;
-
- /* first, clear all interrupts pending... */
- last = 0;
- for (i = 0; i < 4; i++) {
- pend = __raw_readl(S3C2416_INTPND2);
-
- if (pend == 0 || pend == last)
- break;
-
- __raw_writel(pend, S3C2416_SRCPND2);
- __raw_writel(pend, S3C2416_INTPND2);
- printk(KERN_INFO "irq: clearing pending status %08x\n",
- (int)pend);
- last = pend;
- }
-
- for (irqno = IRQ_S3C2416_2D; irqno <= IRQ_S3C2416_I2S1; irqno++) {
- switch (irqno) {
- case IRQ_S3C2416_RESERVED2:
- case IRQ_S3C2416_RESERVED3:
- /* no IRQ here */
- break;
- default:
- irq_set_chip_and_handler(irqno, &s3c2416_irq_second,
- handle_edge_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
- }
-}
-
-static int s3c2416_irq_add(struct device *dev,
- struct subsys_interface *sif)
-{
- printk(KERN_INFO "S3C2416: IRQ Support\n");
-
- s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd,
- IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4);
-
- s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma,
- &s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
-
- s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3,
- &s3c2416_irq_uart3,
- IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
-
- s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97,
- &s3c2416_irq_wdtac97,
- IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
-
- s3c2416_irq_add_second();
-
- return 0;
-}
-
-static struct subsys_interface s3c2416_irq_interface = {
- .name = "s3c2416_irq",
- .subsys = &s3c2416_subsys,
- .add_dev = s3c2416_irq_add,
-};
-
-static int __init s3c2416_irq_init(void)
-{
- return subsys_interface_register(&s3c2416_irq_interface);
-}
-
-arch_initcall(s3c2416_irq_init);
-
-#ifdef CONFIG_PM
-static struct sleep_save irq_save[] = {
- SAVE_ITEM(S3C2416_INTMSK2),
-};
-
-int s3c2416_irq_suspend(void)
-{
- s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
-
- return 0;
-}
-
-void s3c2416_irq_resume(void)
-{
- s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
-}
-
-struct syscore_ops s3c2416_irq_syscore_ops = {
- .suspend = s3c2416_irq_suspend,
- .resume = s3c2416_irq_resume,
-};
-#endif
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2443.c b/arch/arm/mach-s3c24xx/irq-s3c2443.c
deleted file mode 100644
index 5e69109c0928..000000000000
--- a/arch/arm/mach-s3c24xx/irq-s3c2443.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/irq.c
- *
- * Copyright (c) 2007 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-
-#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
-
-static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len)
-{
- unsigned int subsrc, submsk;
- unsigned int end;
-
- /* read the current pending interrupts, and the mask
- * for what it is available */
-
- subsrc = __raw_readl(S3C2410_SUBSRCPND);
- submsk = __raw_readl(S3C2410_INTSUBMSK);
-
- subsrc &= ~submsk;
- subsrc >>= (irq - S3C2410_IRQSUB(0));
- subsrc &= (1 << len)-1;
-
- end = len + irq;
-
- for (; irq < end && subsrc; irq++) {
- if (subsrc & 1)
- generic_handle_irq(irq);
-
- subsrc >>= 1;
- }
-}
-
-/* WDT/AC97 sub interrupts */
-
-static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
-{
- s3c2443_irq_demux(IRQ_S3C2443_WDT, 4);
-}
-
-#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
-#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
-
-static void s3c2443_irq_wdtac97_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static void s3c2443_irq_wdtac97_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
-}
-
-static void s3c2443_irq_wdtac97_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static struct irq_chip s3c2443_irq_wdtac97 = {
- .irq_mask = s3c2443_irq_wdtac97_mask,
- .irq_unmask = s3c2443_irq_wdtac97_unmask,
- .irq_ack = s3c2443_irq_wdtac97_ack,
-};
-
-/* LCD sub interrupts */
-
-static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
-{
- s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4);
-}
-
-#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
-#define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
-
-static void s3c2443_irq_lcd_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static void s3c2443_irq_lcd_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_LCD);
-}
-
-static void s3c2443_irq_lcd_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static struct irq_chip s3c2443_irq_lcd = {
- .irq_mask = s3c2443_irq_lcd_mask,
- .irq_unmask = s3c2443_irq_lcd_unmask,
- .irq_ack = s3c2443_irq_lcd_ack,
-};
-
-/* DMA sub interrupts */
-
-static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
-{
- s3c2443_irq_demux(IRQ_S3C2443_DMA0, 6);
-}
-
-#define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
-#define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
-
-static void s3c2443_irq_dma_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static void s3c2443_irq_dma_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_DMA);
-}
-
-static void s3c2443_irq_dma_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static struct irq_chip s3c2443_irq_dma = {
- .irq_mask = s3c2443_irq_dma_mask,
- .irq_unmask = s3c2443_irq_dma_unmask,
- .irq_ack = s3c2443_irq_dma_ack,
-};
-
-/* UART3 sub interrupts */
-
-static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
-{
- s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
-}
-
-#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
-static void s3c2443_irq_uart3_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static void s3c2443_irq_uart3_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_UART3);
-}
-
-static void s3c2443_irq_uart3_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static struct irq_chip s3c2443_irq_uart3 = {
- .irq_mask = s3c2443_irq_uart3_mask,
- .irq_unmask = s3c2443_irq_uart3_unmask,
- .irq_ack = s3c2443_irq_uart3_ack,
-};
-
-/* CAM sub interrupts */
-
-static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc)
-{
- s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4);
-}
-
-#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
-#define SUBMSK_CAM INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P)
-
-static void s3c2443_irq_cam_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_CAM, SUBMSK_CAM);
-}
-
-static void s3c2443_irq_cam_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_CAM);
-}
-
-static void s3c2443_irq_cam_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_CAM, SUBMSK_CAM);
-}
-
-static struct irq_chip s3c2443_irq_cam = {
- .irq_mask = s3c2443_irq_cam_mask,
- .irq_unmask = s3c2443_irq_cam_unmask,
- .irq_ack = s3c2443_irq_cam_ack,
-};
-
-/* IRQ initialisation code */
-
-static int s3c2443_add_sub(unsigned int base,
- void (*demux)(unsigned int,
- struct irq_desc *),
- struct irq_chip *chip,
- unsigned int start, unsigned int end)
-{
- unsigned int irqno;
-
- irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
- irq_set_chained_handler(base, demux);
-
- for (irqno = start; irqno <= end; irqno++) {
- irq_set_chip_and_handler(irqno, chip, handle_level_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- return 0;
-}
-
-static int s3c2443_irq_add(struct device *dev,
- struct subsys_interface *sif)
-{
- printk("S3C2443: IRQ Support\n");
-
- s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam,
- IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P);
-
- s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd,
- IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4);
-
- s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma,
- &s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
-
- s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3,
- &s3c2443_irq_uart3,
- IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
-
- s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97,
- &s3c2443_irq_wdtac97,
- IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
-
- return 0;
-}
-
-static struct subsys_interface s3c2443_irq_interface = {
- .name = "s3c2443_irq",
- .subsys = &s3c2443_subsys,
- .add_dev = s3c2443_irq_add,
-};
-
-static int __init s3c2443_irq_init(void)
-{
- return subsys_interface_register(&s3c2443_irq_interface);
-}
-
-arch_initcall(s3c2443_irq_init);
-
diff --git a/arch/arm/mach-s3c24xx/irq.c b/arch/arm/mach-s3c24xx/irq.c
new file mode 100644
index 000000000000..cb9f5e011e73
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/irq.c
@@ -0,0 +1,822 @@
+/*
+ * S3C24XX IRQ handling
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2012 Heiko Stuebner <heiko@sntech.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.
+*/
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/irqdomain.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/cpu.h>
+#include <plat/regs-irqtype.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
+
+#define S3C_IRQTYPE_NONE 0
+#define S3C_IRQTYPE_EINT 1
+#define S3C_IRQTYPE_EDGE 2
+#define S3C_IRQTYPE_LEVEL 3
+
+struct s3c_irq_data {
+ unsigned int type;
+ unsigned long parent_irq;
+
+ /* data gets filled during init */
+ struct s3c_irq_intc *intc;
+ unsigned long sub_bits;
+ struct s3c_irq_intc *sub_intc;
+};
+
+/*
+ * Sructure holding the controller data
+ * @reg_pending register holding pending irqs
+ * @reg_intpnd special register intpnd in main intc
+ * @reg_mask mask register
+ * @domain irq_domain of the controller
+ * @parent parent controller for ext and sub irqs
+ * @irqs irq-data, always s3c_irq_data[32]
+ */
+struct s3c_irq_intc {
+ void __iomem *reg_pending;
+ void __iomem *reg_intpnd;
+ void __iomem *reg_mask;
+ struct irq_domain *domain;
+ struct s3c_irq_intc *parent;
+ struct s3c_irq_data *irqs;
+};
+
+static void s3c_irq_mask(struct irq_data *data)
+{
+ struct s3c_irq_intc *intc = data->domain->host_data;
+ struct s3c_irq_intc *parent_intc = intc->parent;
+ struct s3c_irq_data *irq_data = &intc->irqs[data->hwirq];
+ struct s3c_irq_data *parent_data;
+ unsigned long mask;
+ unsigned int irqno;
+
+ mask = __raw_readl(intc->reg_mask);
+ mask |= (1UL << data->hwirq);
+ __raw_writel(mask, intc->reg_mask);
+
+ if (parent_intc && irq_data->parent_irq) {
+ parent_data = &parent_intc->irqs[irq_data->parent_irq];
+
+ /* check to see if we need to mask the parent IRQ */
+ if ((mask & parent_data->sub_bits) == parent_data->sub_bits) {
+ irqno = irq_find_mapping(parent_intc->domain,
+ irq_data->parent_irq);
+ s3c_irq_mask(irq_get_irq_data(irqno));
+ }
+ }
+}
+
+static void s3c_irq_unmask(struct irq_data *data)
+{
+ struct s3c_irq_intc *intc = data->domain->host_data;
+ struct s3c_irq_intc *parent_intc = intc->parent;
+ struct s3c_irq_data *irq_data = &intc->irqs[data->hwirq];
+ unsigned long mask;
+ unsigned int irqno;
+
+ mask = __raw_readl(intc->reg_mask);
+ mask &= ~(1UL << data->hwirq);
+ __raw_writel(mask, intc->reg_mask);
+
+ if (parent_intc && irq_data->parent_irq) {
+ irqno = irq_find_mapping(parent_intc->domain,
+ irq_data->parent_irq);
+ s3c_irq_unmask(irq_get_irq_data(irqno));
+ }
+}
+
+static inline void s3c_irq_ack(struct irq_data *data)
+{
+ struct s3c_irq_intc *intc = data->domain->host_data;
+ unsigned long bitval = 1UL << data->hwirq;
+
+ __raw_writel(bitval, intc->reg_pending);
+ if (intc->reg_intpnd)
+ __raw_writel(bitval, intc->reg_intpnd);
+}
+
+static int s3c_irqext_type_set(void __iomem *gpcon_reg,
+ void __iomem *extint_reg,
+ unsigned long gpcon_offset,
+ unsigned long extint_offset,
+ unsigned int type)
+{
+ unsigned long newvalue = 0, value;
+
+ /* Set the GPIO to external interrupt mode */
+ value = __raw_readl(gpcon_reg);
+ value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
+ __raw_writel(value, gpcon_reg);
+
+ /* Set the external interrupt to pointed trigger type */
+ switch (type)
+ {
+ case IRQ_TYPE_NONE:
+ pr_warn("No edge setting!\n");
+ break;
+
+ case IRQ_TYPE_EDGE_RISING:
+ newvalue = S3C2410_EXTINT_RISEEDGE;
+ break;
+
+ case IRQ_TYPE_EDGE_FALLING:
+ newvalue = S3C2410_EXTINT_FALLEDGE;
+ break;
+
+ case IRQ_TYPE_EDGE_BOTH:
+ newvalue = S3C2410_EXTINT_BOTHEDGE;
+ break;
+
+ case IRQ_TYPE_LEVEL_LOW:
+ newvalue = S3C2410_EXTINT_LOWLEV;
+ break;
+
+ case IRQ_TYPE_LEVEL_HIGH:
+ newvalue = S3C2410_EXTINT_HILEV;
+ break;
+
+ default:
+ pr_err("No such irq type %d", type);
+ return -EINVAL;
+ }
+
+ value = __raw_readl(extint_reg);
+ value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
+ __raw_writel(value, extint_reg);
+
+ return 0;
+}
+
+/* FIXME: make static when it's out of plat-samsung/irq.h */
+int s3c_irqext_type(struct irq_data *data, unsigned int type)
+{
+ void __iomem *extint_reg;
+ void __iomem *gpcon_reg;
+ unsigned long gpcon_offset, extint_offset;
+
+ if ((data->hwirq >= 4) && (data->hwirq <= 7)) {
+ gpcon_reg = S3C2410_GPFCON;
+ extint_reg = S3C24XX_EXTINT0;
+ gpcon_offset = (data->hwirq) * 2;
+ extint_offset = (data->hwirq) * 4;
+ } else if ((data->hwirq >= 8) && (data->hwirq <= 15)) {
+ gpcon_reg = S3C2410_GPGCON;
+ extint_reg = S3C24XX_EXTINT1;
+ gpcon_offset = (data->hwirq - 8) * 2;
+ extint_offset = (data->hwirq - 8) * 4;
+ } else if ((data->hwirq >= 16) && (data->hwirq <= 23)) {
+ gpcon_reg = S3C2410_GPGCON;
+ extint_reg = S3C24XX_EXTINT2;
+ gpcon_offset = (data->hwirq - 8) * 2;
+ extint_offset = (data->hwirq - 16) * 4;
+ } else {
+ return -EINVAL;
+ }
+
+ return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
+ extint_offset, type);
+}
+
+static int s3c_irqext0_type(struct irq_data *data, unsigned int type)
+{
+ void __iomem *extint_reg;
+ void __iomem *gpcon_reg;
+ unsigned long gpcon_offset, extint_offset;
+
+ if ((data->hwirq >= 0) && (data->hwirq <= 3)) {
+ gpcon_reg = S3C2410_GPFCON;
+ extint_reg = S3C24XX_EXTINT0;
+ gpcon_offset = (data->hwirq) * 2;
+ extint_offset = (data->hwirq) * 4;
+ } else {
+ return -EINVAL;
+ }
+
+ return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
+ extint_offset, type);
+}
+
+struct irq_chip s3c_irq_chip = {
+ .name = "s3c",
+ .irq_ack = s3c_irq_ack,
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_set_wake = s3c_irq_wake
+};
+
+struct irq_chip s3c_irq_level_chip = {
+ .name = "s3c-level",
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_ack = s3c_irq_ack,
+};
+
+static struct irq_chip s3c_irqext_chip = {
+ .name = "s3c-ext",
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_ack = s3c_irq_ack,
+ .irq_set_type = s3c_irqext_type,
+ .irq_set_wake = s3c_irqext_wake
+};
+
+static struct irq_chip s3c_irq_eint0t4 = {
+ .name = "s3c-ext0",
+ .irq_ack = s3c_irq_ack,
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_set_wake = s3c_irq_wake,
+ .irq_set_type = s3c_irqext0_type,
+};
+
+static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct s3c_irq_intc *intc = desc->irq_data.domain->host_data;
+ struct s3c_irq_data *irq_data = &intc->irqs[desc->irq_data.hwirq];
+ struct s3c_irq_intc *sub_intc = irq_data->sub_intc;
+ unsigned long src;
+ unsigned long msk;
+ unsigned int n;
+
+ chained_irq_enter(chip, desc);
+
+ src = __raw_readl(sub_intc->reg_pending);
+ msk = __raw_readl(sub_intc->reg_mask);
+
+ src &= ~msk;
+ src &= irq_data->sub_bits;
+
+ while (src) {
+ n = __ffs(src);
+ src &= ~(1 << n);
+ generic_handle_irq(irq_find_mapping(sub_intc->domain, n));
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+#ifdef CONFIG_FIQ
+/**
+ * s3c24xx_set_fiq - set the FIQ routing
+ * @irq: IRQ number to route to FIQ on processor.
+ * @on: Whether to route @irq to the FIQ, or to remove the FIQ routing.
+ *
+ * Change the state of the IRQ to FIQ routing depending on @irq and @on. If
+ * @on is true, the @irq is checked to see if it can be routed and the
+ * interrupt controller updated to route the IRQ. If @on is false, the FIQ
+ * routing is cleared, regardless of which @irq is specified.
+ */
+int s3c24xx_set_fiq(unsigned int irq, bool on)
+{
+ u32 intmod;
+ unsigned offs;
+
+ if (on) {
+ offs = irq - FIQ_START;
+ if (offs > 31)
+ return -EINVAL;
+
+ intmod = 1 << offs;
+ } else {
+ intmod = 0;
+ }
+
+ __raw_writel(intmod, S3C2410_INTMOD);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c24xx_set_fiq);
+#endif
+
+static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct s3c_irq_intc *intc = h->host_data;
+ struct s3c_irq_data *irq_data = &intc->irqs[hw];
+ struct s3c_irq_intc *parent_intc;
+ struct s3c_irq_data *parent_irq_data;
+ unsigned int irqno;
+
+ if (!intc) {
+ pr_err("irq-s3c24xx: no controller found for hwirq %lu\n", hw);
+ return -EINVAL;
+ }
+
+ if (!irq_data) {
+ pr_err("irq-s3c24xx: no irq data found for hwirq %lu\n", hw);
+ return -EINVAL;
+ }
+
+ /* attach controller pointer to irq_data */
+ irq_data->intc = intc;
+
+ /* set handler and flags */
+ switch (irq_data->type) {
+ case S3C_IRQTYPE_NONE:
+ return 0;
+ case S3C_IRQTYPE_EINT:
+ if (irq_data->parent_irq)
+ irq_set_chip_and_handler(virq, &s3c_irqext_chip,
+ handle_edge_irq);
+ else
+ irq_set_chip_and_handler(virq, &s3c_irq_eint0t4,
+ handle_edge_irq);
+ break;
+ case S3C_IRQTYPE_EDGE:
+ if (irq_data->parent_irq ||
+ intc->reg_pending == S3C2416_SRCPND2)
+ irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
+ handle_edge_irq);
+ else
+ irq_set_chip_and_handler(virq, &s3c_irq_chip,
+ handle_edge_irq);
+ break;
+ case S3C_IRQTYPE_LEVEL:
+ if (irq_data->parent_irq)
+ irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
+ handle_level_irq);
+ else
+ irq_set_chip_and_handler(virq, &s3c_irq_chip,
+ handle_level_irq);
+ break;
+ default:
+ pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type);
+ return -EINVAL;
+ }
+ set_irq_flags(virq, IRQF_VALID);
+
+ if (irq_data->parent_irq) {
+ parent_intc = intc->parent;
+ if (!parent_intc) {
+ pr_err("irq-s3c24xx: no parent controller found for hwirq %lu\n",
+ hw);
+ goto err;
+ }
+
+ parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
+ if (!irq_data) {
+ pr_err("irq-s3c24xx: no irq data found for hwirq %lu\n",
+ hw);
+ goto err;
+ }
+
+ parent_irq_data->sub_intc = intc;
+ parent_irq_data->sub_bits |= (1UL << hw);
+
+ /* attach the demuxer to the parent irq */
+ irqno = irq_find_mapping(parent_intc->domain,
+ irq_data->parent_irq);
+ if (!irqno) {
+ pr_err("irq-s3c24xx: could not find mapping for parent irq %lu\n",
+ irq_data->parent_irq);
+ goto err;
+ }
+ irq_set_chained_handler(irqno, s3c_irq_demux);
+ }
+
+ return 0;
+
+err:
+ set_irq_flags(virq, 0);
+
+ /* the only error can result from bad mapping data*/
+ return -EINVAL;
+}
+
+static struct irq_domain_ops s3c24xx_irq_ops = {
+ .map = s3c24xx_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void s3c24xx_clear_intc(struct s3c_irq_intc *intc)
+{
+ void __iomem *reg_source;
+ unsigned long pend;
+ unsigned long last;
+ int i;
+
+ /* if intpnd is set, read the next pending irq from there */
+ reg_source = intc->reg_intpnd ? intc->reg_intpnd : intc->reg_pending;
+
+ last = 0;
+ for (i = 0; i < 4; i++) {
+ pend = __raw_readl(reg_source);
+
+ if (pend == 0 || pend == last)
+ break;
+
+ __raw_writel(pend, intc->reg_pending);
+ if (intc->reg_intpnd)
+ __raw_writel(pend, intc->reg_intpnd);
+
+ pr_info("irq: clearing pending status %08x\n", (int)pend);
+ last = pend;
+ }
+}
+
+struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np,
+ struct s3c_irq_data *irq_data,
+ struct s3c_irq_intc *parent,
+ unsigned long address)
+{
+ struct s3c_irq_intc *intc;
+ void __iomem *base = (void *)0xf6000000; /* static mapping */
+ int irq_num;
+ int irq_start;
+ int irq_offset;
+ int ret;
+
+ intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
+ if (!intc)
+ return ERR_PTR(-ENOMEM);
+
+ intc->irqs = irq_data;
+
+ if (parent)
+ intc->parent = parent;
+
+ /* select the correct data for the controller.
+ * Need to hard code the irq num start and offset
+ * to preserve the static mapping for now
+ */
+ switch (address) {
+ case 0x4a000000:
+ pr_debug("irq: found main intc\n");
+ intc->reg_pending = base;
+ intc->reg_mask = base + 0x08;
+ intc->reg_intpnd = base + 0x10;
+ irq_num = 32;
+ irq_start = S3C2410_IRQ(0);
+ irq_offset = 0;
+ break;
+ case 0x4a000018:
+ pr_debug("irq: found subintc\n");
+ intc->reg_pending = base + 0x18;
+ intc->reg_mask = base + 0x1c;
+ irq_num = 29;
+ irq_start = S3C2410_IRQSUB(0);
+ irq_offset = 0;
+ break;
+ case 0x4a000040:
+ pr_debug("irq: found intc2\n");
+ intc->reg_pending = base + 0x40;
+ intc->reg_mask = base + 0x48;
+ intc->reg_intpnd = base + 0x50;
+ irq_num = 8;
+ irq_start = S3C2416_IRQ(0);
+ irq_offset = 0;
+ break;
+ case 0x560000a4:
+ pr_debug("irq: found eintc\n");
+ base = (void *)0xfd000000;
+
+ intc->reg_mask = base + 0xa4;
+ intc->reg_pending = base + 0x08;
+ irq_num = 20;
+ irq_start = S3C2410_IRQ(32);
+ irq_offset = 4;
+ break;
+ default:
+ pr_err("irq: unsupported controller address\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* now that all the data is complete, init the irq-domain */
+ s3c24xx_clear_intc(intc);
+ intc->domain = irq_domain_add_legacy(np, irq_num, irq_start,
+ irq_offset, &s3c24xx_irq_ops,
+ intc);
+ if (!intc->domain) {
+ pr_err("irq: could not create irq-domain\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return intc;
+
+err:
+ kfree(intc);
+ return ERR_PTR(ret);
+}
+
+/* s3c24xx_init_irq
+ *
+ * Initialise S3C2410 IRQ system
+*/
+
+static struct s3c_irq_data init_base[32] = {
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+ { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+ { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
+};
+
+static struct s3c_irq_data init_eint[32] = {
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
+};
+
+static struct s3c_irq_data init_subint[32] = {
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+};
+
+void __init s3c24xx_init_irq(void)
+{
+ struct s3c_irq_intc *main_intc;
+
+#ifdef CONFIG_FIQ
+ init_FIQ(FIQ_START);
+#endif
+
+ main_intc = s3c24xx_init_intc(NULL, &init_base[0], NULL, 0x4a000000);
+ if (IS_ERR(main_intc)) {
+ pr_err("irq: could not create main interrupt controller\n");
+ return;
+ }
+
+ s3c24xx_init_intc(NULL, &init_subint[0], main_intc, 0x4a000018);
+ s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4);
+}
+
+#ifdef CONFIG_CPU_S3C2416
+static struct s3c_irq_data init_s3c2416base[32] = {
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* NAND */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+ { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+ { .type = S3C_IRQTYPE_NONE, },
+ { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
+};
+
+static struct s3c_irq_data init_s3c2416subint[32] = {
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
+};
+
+static struct s3c_irq_data init_s3c2416_second[32] = {
+ { .type = S3C_IRQTYPE_EDGE }, /* 2D */
+ { .type = S3C_IRQTYPE_EDGE }, /* IIC1 */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */
+ { .type = S3C_IRQTYPE_EDGE }, /* PCM1 */
+ { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */
+ { .type = S3C_IRQTYPE_EDGE }, /* I2S1 */
+};
+
+void __init s3c2416_init_irq(void)
+{
+ struct s3c_irq_intc *main_intc;
+
+ pr_info("S3C2416: IRQ Support\n");
+
+#ifdef CONFIG_FIQ
+ init_FIQ(FIQ_START);
+#endif
+
+ main_intc = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL, 0x4a000000);
+ if (IS_ERR(main_intc)) {
+ pr_err("irq: could not create main interrupt controller\n");
+ return;
+ }
+
+ s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4);
+ s3c24xx_init_intc(NULL, &init_s3c2416subint[0], main_intc, 0x4a000018);
+
+ s3c24xx_init_intc(NULL, &init_s3c2416_second[0], NULL, 0x4a000040);
+}
+
+#endif
+
+#ifdef CONFIG_CPU_S3C2443
+static struct s3c_irq_data init_s3c2443base[32] = {
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
+ { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* CFON */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* NAND */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+ { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
+};
+
+
+static struct s3c_irq_data init_s3c2443subint[32] = {
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD1 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
+};
+
+void __init s3c2443_init_irq(void)
+{
+ struct s3c_irq_intc *main_intc;
+
+ pr_info("S3C2443: IRQ Support\n");
+
+#ifdef CONFIG_FIQ
+ init_FIQ(FIQ_START);
+#endif
+
+ main_intc = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL, 0x4a000000);
+ if (IS_ERR(main_intc)) {
+ pr_err("irq: could not create main interrupt controller\n");
+ return;
+ }
+
+ s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4);
+ s3c24xx_init_intc(NULL, &init_s3c2443subint[0], main_intc, 0x4a000018);
+}
+#endif
diff --git a/arch/arm/mach-s3c24xx/mach-amlm5900.c b/arch/arm/mach-s3c24xx/mach-amlm5900.c
index f4ad99c1e476..0e0279e79150 100644
--- a/arch/arm/mach-s3c24xx/mach-amlm5900.c
+++ b/arch/arm/mach-s3c24xx/mach-amlm5900.c
@@ -237,6 +237,6 @@ MACHINE_START(AML_M5900, "AML_M5900")
.map_io = amlm5900_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = amlm5900_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2410_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
index 1ee8c4638743..bb595f15ce36 100644
--- a/arch/arm/mach-s3c24xx/mach-anubis.c
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -28,17 +28,12 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/anubis-map.h>
-#include <mach/anubis-irq.h>
-#include <mach/anubis-cpld.h>
-
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <linux/platform_data/mtd-nand-s3c2410.h>
#include <linux/platform_data/i2c-s3c2410.h>
@@ -55,8 +50,9 @@
#include <plat/cpu.h>
#include <linux/platform_data/asoc-s3c24xx_simtec.h>
-#include "simtec.h"
+#include "anubis.h"
#include "common.h"
+#include "simtec.h"
#define COPYRIGHT ", Copyright 2005-2009 Simtec Electronics"
@@ -237,7 +233,7 @@ static struct pata_platform_info anubis_ide_platdata = {
static struct resource anubis_ide0_resource[] = {
[0] = DEFINE_RES_MEM(S3C2410_CS3, 8 * 32),
[2] = DEFINE_RES_MEM(S3C2410_CS3 + (1 << 26) + (6 * 32), 32),
- [3] = DEFINE_RES_IRQ(IRQ_IDE0),
+ [3] = DEFINE_RES_IRQ(ANUBIS_IRQ_IDE0),
};
static struct platform_device anubis_device_ide0 = {
@@ -254,7 +250,7 @@ static struct platform_device anubis_device_ide0 = {
static struct resource anubis_ide1_resource[] = {
[0] = DEFINE_RES_MEM(S3C2410_CS4, 8 * 32),
[1] = DEFINE_RES_MEM(S3C2410_CS4 + (1 << 26) + (6 * 32), 32),
- [2] = DEFINE_RES_IRQ(IRQ_IDE0),
+ [2] = DEFINE_RES_IRQ(ANUBIS_IRQ_IDE0),
};
static struct platform_device anubis_device_ide1 = {
@@ -279,7 +275,7 @@ static struct ax_plat_data anubis_asix_platdata = {
static struct resource anubis_asix_resource[] = {
[0] = DEFINE_RES_MEM(S3C2410_CS5, 0x20 * 0x20),
- [1] = DEFINE_RES_IRQ(IRQ_ASIX),
+ [1] = DEFINE_RES_IRQ(ANUBIS_IRQ_ASIX),
};
static struct platform_device anubis_device_asix = {
@@ -448,6 +444,6 @@ MACHINE_START(ANUBIS, "Simtec-Anubis")
.map_io = anubis_map_io,
.init_machine = anubis_init,
.init_irq = s3c24xx_init_irq,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
index 00381fe5de32..b4bc60c78ebb 100644
--- a/arch/arm/mach-s3c24xx/mach-at2440evb.c
+++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
@@ -34,7 +35,6 @@
#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <linux/platform_data/mtd-nand-s3c2410.h>
#include <linux/platform_data/i2c-s3c2410.h>
@@ -210,6 +210,6 @@ MACHINE_START(AT2440EVB, "AT2440EVB")
.map_io = at2440evb_map_io,
.init_machine = at2440evb_init,
.init_irq = s3c24xx_init_irq,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
index 6a30ce7e4aa7..ca6618081041 100644
--- a/arch/arm/mach-s3c24xx/mach-bast.c
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -24,48 +24,41 @@
#include <linux/ata_platform.h>
#include <linux/i2c.h>
#include <linux/io.h>
+#include <linux/serial_8250.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/platform_data/asoc-s3c24xx_simtec.h>
+#include <linux/platform_data/hwmon-s3c.h>
+#include <linux/platform_data/i2c-s3c2410.h>
+#include <linux/platform_data/mtd-nand-s3c2410.h>
#include <net/ax88796.h>
+#include <asm/irq.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-#include <mach/bast-cpld.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
#include <asm/mach-types.h>
-//#include <asm/debug-ll.h>
-#include <plat/regs-serial.h>
+#include <mach/fb.h>
+#include <mach/hardware.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
-#include <linux/platform_data/hwmon-s3c.h>
-#include <linux/platform_data/mtd-nand-s3c2410.h>
-#include <linux/platform_data/i2c-s3c2410.h>
-#include <mach/fb.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <linux/serial_8250.h>
-
#include <plat/clock.h>
-#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/cpu-freq.h>
+#include <plat/devs.h>
#include <plat/gpio-cfg.h>
-#include <linux/platform_data/asoc-s3c24xx_simtec.h>
+#include <plat/regs-serial.h>
-#include "simtec.h"
+#include "bast.h"
#include "common.h"
+#include "simtec.h"
#define COPYRIGHT ", Copyright 2004-2008 Simtec Electronics"
@@ -312,7 +305,7 @@ static struct s3c2410_platform_nand __initdata bast_nand_info = {
static struct resource bast_dm9k_resource[] = {
[0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_DM9000, 4),
[1] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_DM9000 + 0x40, 0x40),
- [2] = DEFINE_RES_NAMED(IRQ_DM9000 , 1, NULL, IORESOURCE_IRQ \
+ [2] = DEFINE_RES_NAMED(BAST_IRQ_DM9000 , 1, NULL, IORESOURCE_IRQ \
| IORESOURCE_IRQ_HIGHLEVEL),
};
@@ -343,7 +336,7 @@ static struct platform_device bast_device_dm9k = {
static struct plat_serial8250_port bast_sio_data[] = {
[0] = {
.mapbase = SERIAL_BASE + 0x2f8,
- .irq = IRQ_PCSERIAL1,
+ .irq = BAST_IRQ_PCSERIAL1,
.flags = SERIAL_FLAGS,
.iotype = UPIO_MEM,
.regshift = 0,
@@ -351,7 +344,7 @@ static struct plat_serial8250_port bast_sio_data[] = {
},
[1] = {
.mapbase = SERIAL_BASE + 0x3f8,
- .irq = IRQ_PCSERIAL2,
+ .irq = BAST_IRQ_PCSERIAL2,
.flags = SERIAL_FLAGS,
.iotype = UPIO_MEM,
.regshift = 0,
@@ -390,7 +383,7 @@ static struct ax_plat_data bast_asix_platdata = {
static struct resource bast_asix_resource[] = {
[0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET, 0x18 * 0x20),
[1] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20), 1),
- [2] = DEFINE_RES_IRQ(IRQ_ASIX),
+ [2] = DEFINE_RES_IRQ(BAST_IRQ_ASIX),
};
static struct platform_device bast_device_asix = {
@@ -612,6 +605,6 @@ MACHINE_START(BAST, "Simtec-BAST")
.map_io = bast_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = bast_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2410_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
index 973b87ca87f4..a25e8c5a7b4c 100644
--- a/arch/arm/mach-s3c24xx/mach-gta02.c
+++ b/arch/arm/mach-s3c24xx/mach-gta02.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-s3c2442/mach-gta02.c
- *
* S3C2442 Machine Support for Openmoko GTA02 / FreeRunner.
*
* Copyright (C) 2006-2009 by Openmoko, Inc.
@@ -23,7 +21,6 @@
* 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>
@@ -34,62 +31,59 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/s3c24xx.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
#include <linux/mmc/host.h>
+#include <linux/mfd/pcf50633/adc.h>
+#include <linux/mfd/pcf50633/backlight.h>
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/gpio.h>
+#include <linux/mfd/pcf50633/mbc.h>
+#include <linux/mfd/pcf50633/pmic.h>
+
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
#include <linux/regulator/machine.h>
-#include <linux/mfd/pcf50633/core.h>
-#include <linux/mfd/pcf50633/mbc.h>
-#include <linux/mfd/pcf50633/adc.h>
-#include <linux/mfd/pcf50633/gpio.h>
-#include <linux/mfd/pcf50633/pmic.h>
-#include <linux/mfd/pcf50633/backlight.h>
-
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/s3c24xx.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
+#include <linux/platform_data/i2c-s3c2410.h>
+#include <linux/platform_data/mtd-nand-s3c2410.h>
+#include <linux/platform_data/touchscreen-s3c2410.h>
+#include <linux/platform_data/usb-ohci-s3c2410.h>
+#include <linux/platform_data/usb-s3c2410_udc.h>
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
#include <mach/fb.h>
-
-#include <linux/platform_data/usb-ohci-s3c2410.h>
-#include <mach/regs-mem.h>
#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-irq.h>
-#include <mach/gta02.h>
-
-#include <plat/regs-serial.h>
-#include <linux/platform_data/mtd-nand-s3c2410.h>
-#include <plat/devs.h>
#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <linux/platform_data/usb-s3c2410_udc.h>
+#include <plat/devs.h>
#include <plat/gpio-cfg.h>
-#include <linux/platform_data/i2c-s3c2410.h>
-#include <linux/platform_data/touchscreen-s3c2410.h>
+#include <plat/pm.h>
+#include <plat/regs-serial.h>
#include "common.h"
+#include "gta02.h"
static struct pcf50633 *gta02_pcf;
@@ -595,6 +589,6 @@ MACHINE_START(NEO1973_GTA02, "GTA02")
.map_io = gta02_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = gta02_machine_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
index b23dd1b106e8..79bc0830d740 100644
--- a/arch/arm/mach-s3c24xx/mach-h1940.c
+++ b/arch/arm/mach-s3c24xx/mach-h1940.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/mach-h1940.c
- *
+/*
* Copyright (c) 2003-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
@@ -37,40 +36,36 @@
#include <linux/mmc/host.h>
#include <linux/export.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-clock.h>
+#include <linux/platform_data/i2c-s3c2410.h>
+#include <linux/platform_data/mmc-s3cmci.h>
+#include <linux/platform_data/touchscreen-s3c2410.h>
+#include <linux/platform_data/usb-s3c2410_udc.h>
-#include <mach/regs-gpio.h>
-#include <mach/gpio-fns.h>
-#include <mach/gpio-nrs.h>
+#include <sound/uda1380.h>
-#include <mach/h1940.h>
-#include <mach/h1940-latch.h>
#include <mach/fb.h>
-#include <linux/platform_data/usb-s3c2410_udc.h>
-#include <linux/platform_data/i2c-s3c2410.h>
+#include <mach/hardware.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-lcd.h>
-#include <plat/gpio-cfg.h>
#include <plat/clock.h>
-#include <plat/devs.h>
#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/gpio-cfg.h>
#include <plat/pll.h>
#include <plat/pm.h>
-#include <linux/platform_data/mmc-s3cmci.h>
-#include <linux/platform_data/touchscreen-s3c2410.h>
+#include <plat/regs-serial.h>
-#include <sound/uda1380.h>
#include "common.h"
+#include "h1940.h"
#define H1940_LATCH ((void __force __iomem *)0xF8000000)
@@ -746,6 +741,6 @@ MACHINE_START(H1940, "IPAQ-H1940")
.reserve = h1940_reserve,
.init_irq = h1940_init_irq,
.init_machine = h1940_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2410_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
index c9954e26b492..54e83c1f780c 100644
--- a/arch/arm/mach-s3c24xx/mach-jive.c
+++ b/arch/arm/mach-s3c24xx/mach-jive.c
@@ -35,9 +35,7 @@
#include <linux/platform_data/mtd-nand-s3c2410.h>
#include <linux/platform_data/i2c-s3c2410.h>
-#include <mach/regs-power.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/fb.h>
@@ -56,6 +54,8 @@
#include <plat/pm.h>
#include <linux/platform_data/usb-s3c2410_udc.h>
+#include "s3c2412-power.h"
+
static struct map_desc jive_iodesc[] __initdata = {
};
@@ -661,6 +661,6 @@ MACHINE_START(JIVE, "JIVE")
.init_irq = s3c24xx_init_irq,
.map_io = jive_map_io,
.init_machine = jive_machine_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2412_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index a31d5b83e5f7..2865e5919f2c 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -40,7 +40,6 @@
#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>
#include <linux/platform_data/leds-s3c24xx.h>
-#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/irqs.h>
#include <linux/platform_data/mtd-nand-s3c2410.h>
@@ -688,6 +687,6 @@ MACHINE_START(MINI2440, "MINI2440")
.map_io = mini2440_map_io,
.init_machine = mini2440_init,
.init_irq = s3c24xx_init_irq,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-n30.c b/arch/arm/mach-s3c24xx/mach-n30.c
index c53a9bfe1417..d9d04b240295 100644
--- a/arch/arm/mach-s3c24xx/mach-n30.c
+++ b/arch/arm/mach-s3c24xx/mach-n30.c
@@ -589,7 +589,7 @@ MACHINE_START(N30, "Acer-N30")
Ben Dooks <ben-linux@fluff.org>
*/
.atag_offset = 0x100,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.init_machine = n30_init,
.init_irq = s3c24xx_init_irq,
.map_io = n30_map_io,
@@ -600,7 +600,7 @@ MACHINE_START(N35, "Acer-N35")
/* Maintainer: Christer Weinigel <christer@weinigel.se>
*/
.atag_offset = 0x100,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.init_machine = n30_init,
.init_irq = s3c24xx_init_irq,
.map_io = n30_map_io,
diff --git a/arch/arm/mach-s3c24xx/mach-nexcoder.c b/arch/arm/mach-s3c24xx/mach-nexcoder.c
index a2b92b0898e2..a454e2461860 100644
--- a/arch/arm/mach-s3c24xx/mach-nexcoder.c
+++ b/arch/arm/mach-s3c24xx/mach-nexcoder.c
@@ -153,6 +153,6 @@ MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
.map_io = nexcoder_map_io,
.init_machine = nexcoder_init,
.init_irq = s3c24xx_init_irq,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
index bb36d832bd3d..ae2cbdf3e3ca 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-s3c2440/mach-osiris.c
- *
+/*
* Copyright (c) 2005-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -22,25 +21,16 @@
#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
#include <linux/i2c/tps65010.h>
+#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-
-#include <mach/osiris-map.h>
-#include <mach/osiris-cpld.h>
-
-#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <plat/cpu-freq.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
#include <linux/platform_data/mtd-nand-s3c2410.h>
#include <linux/platform_data/i2c-s3c2410.h>
@@ -49,12 +39,20 @@
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
-#include <plat/gpio-cfg.h>
#include <plat/clock.h>
-#include <plat/devs.h>
#include <plat/cpu.h>
+#include <plat/cpu-freq.h>
+#include <plat/devs.h>
+#include <plat/gpio-cfg.h>
+#include <plat/regs-serial.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-lcd.h>
#include "common.h"
+#include "osiris.h"
+#include "regs-mem.h"
/* onboard perihperal map */
@@ -428,6 +426,6 @@ MACHINE_START(OSIRIS, "Simtec-OSIRIS")
.map_io = osiris_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = osiris_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-otom.c b/arch/arm/mach-s3c24xx/mach-otom.c
index bca39f0232b3..40a47d6c6a85 100644
--- a/arch/arm/mach-s3c24xx/mach-otom.c
+++ b/arch/arm/mach-s3c24xx/mach-otom.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/mach-otom.c
+/*
*
* Copyright (c) 2004 Nex Vision
* Guillaume GOURAT <guillaume.gourat@nexvision.fr>
@@ -6,7 +6,6 @@
* 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>
@@ -19,26 +18,25 @@
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/platform_data/i2c-s3c2410.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/otom-map.h>
-
#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>
-#include <plat/s3c2410.h>
#include <plat/clock.h>
-#include <plat/devs.h>
-#include <linux/platform_data/i2c-s3c2410.h>
#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/regs-serial.h>
+#include <plat/s3c2410.h>
#include "common.h"
+#include "otom.h"
static struct map_desc otom11_iodesc[] __initdata = {
/* Device area */
@@ -118,6 +116,6 @@ MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
.map_io = otom11_map_io,
.init_machine = otom11_init,
.init_irq = s3c24xx_init_irq,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2410_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 7b6ba13d7285..56175f0941b1 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -343,6 +343,6 @@ MACHINE_START(QT2410, "QT2410")
.map_io = qt2410_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = qt2410_machine_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2410_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
index 0606f2faaa5c..1f9ba2ae5288 100644
--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-s3c2440/mach-rx1950.c
- *
+/*
* Copyright (c) 2006-2009 Victor Chukhantsev, Denis Grigoriev,
* Copyright (c) 2007-2010 Vasily Khoruzhick
*
@@ -37,31 +36,31 @@
#include <linux/mmc/host.h>
+#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <asm/mach-types.h>
+#include <linux/platform_data/i2c-s3c2410.h>
+#include <linux/platform_data/mmc-s3cmci.h>
+#include <linux/platform_data/mtd-nand-s3c2410.h>
+#include <linux/platform_data/touchscreen-s3c2410.h>
+#include <linux/platform_data/usb-s3c2410_udc.h>
+
+#include <sound/uda1380.h>
+
+#include <mach/fb.h>
#include <mach/regs-gpio.h>
#include <mach/regs-lcd.h>
-#include <mach/h1940.h>
-#include <mach/fb.h>
#include <plat/clock.h>
-#include <plat/regs-serial.h>
-#include <plat/regs-iic.h>
-#include <linux/platform_data/mmc-s3cmci.h>
-#include <linux/platform_data/usb-s3c2410_udc.h>
-#include <linux/platform_data/mtd-nand-s3c2410.h>
-#include <linux/platform_data/i2c-s3c2410.h>
-#include <plat/devs.h>
#include <plat/cpu.h>
+#include <plat/devs.h>
#include <plat/pm.h>
-#include <plat/irq.h>
-#include <linux/platform_data/touchscreen-s3c2410.h>
-
-#include <sound/uda1380.h>
+#include <plat/regs-iic.h>
+#include <plat/regs-serial.h>
#include "common.h"
+#include "h1940.h"
#define LCD_PWM_PERIOD 192960
#define LCD_PWM_DUTY 127353
@@ -814,6 +813,6 @@ MACHINE_START(RX1950, "HP iPAQ RX1950")
.reserve = rx1950_reserve,
.init_irq = s3c24xx_init_irq,
.init_machine = rx1950_init_machine,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c
index dacbb9a2122a..f20418a2fb1b 100644
--- a/arch/arm/mach-s3c24xx/mach-rx3715.c
+++ b/arch/arm/mach-s3c24xx/mach-rx3715.c
@@ -31,27 +31,27 @@
#include <linux/mtd/partitions.h>
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+
+#include <linux/platform_data/mtd-nand-s3c2410.h>
-#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <plat/regs-serial.h>
+#include <mach/fb.h>
+#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <mach/regs-lcd.h>
-#include <mach/h1940.h>
-#include <linux/platform_data/mtd-nand-s3c2410.h>
-#include <mach/fb.h>
-
#include <plat/clock.h>
-#include <plat/devs.h>
#include <plat/cpu.h>
+#include <plat/devs.h>
#include <plat/pm.h>
+#include <plat/regs-serial.h>
#include "common.h"
+#include "h1940.h"
static struct map_desc rx3715_iodesc[] __initdata = {
/* dump ISA space somewhere unused */
@@ -212,6 +212,6 @@ MACHINE_START(RX3715, "IPAQ-RX3715")
.reserve = rx3715_reserve,
.init_irq = rx3715_init_irq,
.init_machine = rx3715_init_machine,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2410.c b/arch/arm/mach-s3c24xx/mach-smdk2410.c
index 82796b97cb04..e184bfa9613a 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2410.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2410.c
@@ -117,6 +117,6 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc
.map_io = smdk2410_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = smdk2410_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2410_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2413.c b/arch/arm/mach-s3c24xx/mach-smdk2413.c
index ce99fd8bbbc5..86d7847c9d45 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2413.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2413.c
@@ -37,7 +37,6 @@
#include <mach/regs-gpio.h>
#include <mach/regs-lcd.h>
-#include <mach/idle.h>
#include <linux/platform_data/usb-s3c2410_udc.h>
#include <linux/platform_data/i2c-s3c2410.h>
#include <mach/fb.h>
@@ -133,7 +132,7 @@ MACHINE_START(S3C2413, "S3C2413")
.init_irq = s3c24xx_init_irq,
.map_io = smdk2413_map_io,
.init_machine = smdk2413_machine_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2412_restart,
MACHINE_END
@@ -145,7 +144,7 @@ MACHINE_START(SMDK2412, "SMDK2412")
.init_irq = s3c24xx_init_irq,
.map_io = smdk2413_map_io,
.init_machine = smdk2413_machine_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2412_restart,
MACHINE_END
@@ -157,6 +156,6 @@ MACHINE_START(SMDK2413, "SMDK2413")
.init_irq = s3c24xx_init_irq,
.map_io = smdk2413_map_io,
.init_machine = smdk2413_machine_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2412_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c
index f30d7fccbfee..ebb2e61f3d07 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2416.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c
@@ -39,7 +39,6 @@
#include <mach/regs-lcd.h>
#include <mach/regs-s3c2443-clock.h>
-#include <mach/idle.h>
#include <linux/platform_data/leds-s3c24xx.h>
#include <linux/platform_data/i2c-s3c2410.h>
@@ -251,9 +250,9 @@ MACHINE_START(SMDK2416, "SMDK2416")
/* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */
.atag_offset = 0x100,
- .init_irq = s3c24xx_init_irq,
+ .init_irq = s3c2416_init_irq,
.map_io = smdk2416_map_io,
.init_machine = smdk2416_machine_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2416_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2440.c b/arch/arm/mach-s3c24xx/mach-smdk2440.c
index b7ff882c6ce6..08cc38c8a4ae 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2440.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2440.c
@@ -35,7 +35,6 @@
#include <mach/regs-gpio.h>
#include <mach/regs-lcd.h>
-#include <mach/idle.h>
#include <mach/fb.h>
#include <linux/platform_data/i2c-s3c2410.h>
@@ -182,6 +181,6 @@ MACHINE_START(S3C2440, "SMDK2440")
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c244x_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2443.c b/arch/arm/mach-s3c24xx/mach-smdk2443.c
index 2568656f046f..fc65d74d3c73 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2443.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2443.c
@@ -35,7 +35,6 @@
#include <mach/regs-gpio.h>
#include <mach/regs-lcd.h>
-#include <mach/idle.h>
#include <mach/fb.h>
#include <linux/platform_data/i2c-s3c2410.h>
@@ -141,9 +140,9 @@ MACHINE_START(SMDK2443, "SMDK2443")
/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
.atag_offset = 0x100,
- .init_irq = s3c24xx_init_irq,
+ .init_irq = s3c2443_init_irq,
.map_io = smdk2443_map_io,
.init_machine = smdk2443_machine_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2443_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-tct_hammer.c b/arch/arm/mach-s3c24xx/mach-tct_hammer.c
index 495bf5cf52e9..24b3d79e7b2c 100644
--- a/arch/arm/mach-s3c24xx/mach-tct_hammer.c
+++ b/arch/arm/mach-s3c24xx/mach-tct_hammer.c
@@ -149,6 +149,6 @@ MACHINE_START(TCT_HAMMER, "TCT_HAMMER")
.map_io = tct_hammer_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = tct_hammer_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2410_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-vr1000.c b/arch/arm/mach-s3c24xx/mach-vr1000.c
index 14d5b12e388c..ec42d1e4e465 100644
--- a/arch/arm/mach-s3c24xx/mach-vr1000.c
+++ b/arch/arm/mach-s3c24xx/mach-vr1000.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/mach-vr1000.c
- *
+/*
* Copyright (c) 2003-2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
@@ -32,27 +31,25 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/bast-map.h>
-#include <mach/vr1000-map.h>
-#include <mach/vr1000-irq.h>
-#include <mach/vr1000-cpld.h>
-
-#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
#include <linux/platform_data/leds-s3c24xx.h>
+#include <linux/platform_data/i2c-s3c2410.h>
+#include <linux/platform_data/asoc-s3c24xx_simtec.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
#include <plat/clock.h>
-#include <plat/devs.h>
#include <plat/cpu.h>
-#include <linux/platform_data/i2c-s3c2410.h>
-#include <linux/platform_data/asoc-s3c24xx_simtec.h>
+#include <plat/devs.h>
+#include <plat/regs-serial.h>
-#include "simtec.h"
+#include "bast.h"
#include "common.h"
+#include "simtec.h"
+#include "vr1000.h"
/* macros for virtual address mods for the io space entries */
#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
@@ -143,7 +140,7 @@ static struct s3c2410_uartcfg vr1000_uartcfgs[] __initdata = {
static struct plat_serial8250_port serial_platform_data[] = {
[0] = {
.mapbase = VR1000_SERIAL_MAPBASE(0),
- .irq = IRQ_VR1000_SERIAL + 0,
+ .irq = VR1000_IRQ_SERIAL + 0,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
.iotype = UPIO_MEM,
.regshift = 0,
@@ -151,7 +148,7 @@ static struct plat_serial8250_port serial_platform_data[] = {
},
[1] = {
.mapbase = VR1000_SERIAL_MAPBASE(1),
- .irq = IRQ_VR1000_SERIAL + 1,
+ .irq = VR1000_IRQ_SERIAL + 1,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
.iotype = UPIO_MEM,
.regshift = 0,
@@ -159,7 +156,7 @@ static struct plat_serial8250_port serial_platform_data[] = {
},
[2] = {
.mapbase = VR1000_SERIAL_MAPBASE(2),
- .irq = IRQ_VR1000_SERIAL + 2,
+ .irq = VR1000_IRQ_SERIAL + 2,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
.iotype = UPIO_MEM,
.regshift = 0,
@@ -167,7 +164,7 @@ static struct plat_serial8250_port serial_platform_data[] = {
},
[3] = {
.mapbase = VR1000_SERIAL_MAPBASE(3),
- .irq = IRQ_VR1000_SERIAL + 3,
+ .irq = VR1000_IRQ_SERIAL + 3,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
.iotype = UPIO_MEM,
.regshift = 0,
@@ -189,14 +186,14 @@ static struct platform_device serial_device = {
static struct resource vr1000_dm9k0_resource[] = {
[0] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000, 4),
[1] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0x40, 0x40),
- [2] = DEFINE_RES_NAMED(IRQ_VR1000_DM9000A, 1, NULL, IORESOURCE_IRQ \
+ [2] = DEFINE_RES_NAMED(VR1000_IRQ_DM9000A, 1, NULL, IORESOURCE_IRQ \
| IORESOURCE_IRQ_HIGHLEVEL),
};
static struct resource vr1000_dm9k1_resource[] = {
[0] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0x80, 4),
[1] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0, 0x40),
- [2] = DEFINE_RES_NAMED(IRQ_VR1000_DM9000N, 1, NULL, IORESOURCE_IRQ \
+ [2] = DEFINE_RES_NAMED(VR1000_IRQ_DM9000N, 1, NULL, IORESOURCE_IRQ \
| IORESOURCE_IRQ_HIGHLEVEL),
};
@@ -357,6 +354,6 @@ MACHINE_START(VR1000, "Thorcom-VR1000")
.map_io = vr1000_map_io,
.init_machine = vr1000_init,
.init_irq = s3c24xx_init_irq,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2410_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c
index f1d44ae11833..3e2bfddc9df1 100644
--- a/arch/arm/mach-s3c24xx/mach-vstms.c
+++ b/arch/arm/mach-s3c24xx/mach-vstms.c
@@ -36,7 +36,6 @@
#include <mach/regs-gpio.h>
#include <mach/regs-lcd.h>
-#include <mach/idle.h>
#include <mach/fb.h>
#include <linux/platform_data/i2c-s3c2410.h>
@@ -161,6 +160,6 @@ MACHINE_START(VSTMS, "VSTMS")
.init_irq = s3c24xx_init_irq,
.init_machine = vstms_init,
.map_io = vstms_map_io,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c2412_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/include/mach/osiris-map.h b/arch/arm/mach-s3c24xx/osiris.h
index 17380f848428..b8d56074abac 100644
--- a/arch/arm/mach-s3c24xx/include/mach/osiris-map.h
+++ b/arch/arm/mach-s3c24xx/osiris.h
@@ -1,9 +1,9 @@
-/* arch/arm/mach-s3c2410/include/mach/osiris-map.h
- *
+/*
* Copyright 2005 Simtec Electronics
* http://www.simtec.co.uk/products/
* Ben Dooks <ben@simtec.co.uk>
*
+ * OSIRIS - CPLD control constants
* OSIRIS - Memory map definitions
*
* This program is free software; you can redistribute it and/or modify
@@ -11,10 +11,21 @@
* published by the Free Software Foundation.
*/
-/* needs arch/map.h including with this */
+#ifndef __MACH_S3C24XX_OSIRIS_H
+#define __MACH_S3C24XX_OSIRIS_H __FILE__
+
+/* CTRL0 - NAND WP control */
+
+#define OSIRIS_CTRL0_NANDSEL (0x3)
+#define OSIRIS_CTRL0_BOOT_INT (1<<3)
+#define OSIRIS_CTRL0_PCMCIA (1<<4)
+#define OSIRIS_CTRL0_FIX8 (1<<5)
+#define OSIRIS_CTRL0_PCMCIA_nWAIT (1<<6)
+#define OSIRIS_CTRL0_PCMCIA_nIOIS16 (1<<7)
+
+#define OSIRIS_CTRL1_FIX8 (1<<0)
-#ifndef __ASM_ARCH_OSIRISMAP_H
-#define __ASM_ARCH_OSIRISMAP_H
+#define OSIRIS_ID_REVMASK (0x7)
/* start peripherals off after the S3C2410 */
@@ -39,4 +50,4 @@
#define OSIRIS_VA_IDREG OSIRIS_IOADDR(0x00700000)
#define OSIRIS_PA_IDREG (OSIRIS_PA_CPLD + (7<<23))
-#endif /* __ASM_ARCH_OSIRISMAP_H */
+#endif /* __MACH_S3C24XX_OSIRIS_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/otom-map.h b/arch/arm/mach-s3c24xx/otom.h
index f9277a52c145..321b7be1c0f7 100644
--- a/arch/arm/mach-s3c24xx/include/mach/otom-map.h
+++ b/arch/arm/mach-s3c24xx/otom.h
@@ -1,5 +1,4 @@
-/* arch/arm/mach-s3c2410/include/mach/otom-map.h
- *
+/*
* (c) 2005 Guillaume GOURAT / NexVision
* guillaume.gourat@nexvision.fr
*
@@ -10,21 +9,20 @@
* published by the Free Software Foundation.
*/
-/* needs arch/map.h including with this */
-
-/* ok, we've used up to 0x01300000, now we need to find space for the
+/*
+ * ok, we've used up to 0x01300000, now we need to find space for the
* peripherals that live in the nGCS[x] areas, which are quite numerous
* in their space.
*/
-#ifndef __ASM_ARCH_OTOMMAP_H
-#define __ASM_ARCH_OTOMMAP_H
+#ifndef __MACH_S3C24XX_OTOM_H
+#define __MACH_S3C24XX_OTOM_H __FILE__
-#define OTOM_PA_CS8900A_BASE (S3C2410_CS3 + 0x01000000) /* nGCS3 +0x01000000 */
-#define OTOM_VA_CS8900A_BASE S3C2410_ADDR(0x04000000) /* 0xF4000000 */
+#define OTOM_PA_CS8900A_BASE (S3C2410_CS3 + 0x01000000) /* nGCS3 +0x01000000 */
+#define OTOM_VA_CS8900A_BASE S3C2410_ADDR(0x04000000) /* 0xF4000000 */
/* physical offset addresses for the peripherals */
-#define OTOM_PA_FLASH0_BASE (S3C2410_CS0) /* Bank 0 */
+#define OTOM_PA_FLASH0_BASE (S3C2410_CS0)
-#endif /* __ASM_ARCH_OTOMMAP_H */
+#endif /* __MACH_S3C24XX_OTOM_H */
diff --git a/arch/arm/mach-s3c2410/pll.c b/arch/arm/mach-s3c24xx/pll-s3c2410.c
index e0b3b347da82..dcf3420a3271 100644
--- a/arch/arm/mach-s3c2410/pll.c
+++ b/arch/arm/mach-s3c24xx/pll-s3c2410.c
@@ -1,5 +1,4 @@
-/* arch/arm/mach-s3c2410/pll.c
- *
+/*
* Copyright (c) 2006-2007 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -82,7 +81,6 @@ static int __init s3c2410_pll_init(void)
return subsys_interface_register(&s3c2410_plls_interface);
}
-
arch_initcall(s3c2410_pll_init);
static struct subsys_interface s3c2410a_plls_interface = {
@@ -95,5 +93,4 @@ static int __init s3c2410a_pll_init(void)
{
return subsys_interface_register(&s3c2410a_plls_interface);
}
-
arch_initcall(s3c2410a_pll_init);
diff --git a/arch/arm/mach-s3c2440/s3c2440-pll-12000000.c b/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c
index 551fb433be87..673781758319 100644
--- a/arch/arm/mach-s3c2440/s3c2440-pll-12000000.c
+++ b/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c
@@ -1,5 +1,4 @@
-/* arch/arm/mach-s3c2440/s3c2440-pll-12000000.c
- *
+/*
* Copyright (c) 2006-2007 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -83,7 +82,6 @@ static int __init s3c2440_pll_12mhz(void)
return subsys_interface_register(&s3c2440_plls12_interface);
}
-
arch_initcall(s3c2440_pll_12mhz);
static struct subsys_interface s3c2442_plls12_interface = {
@@ -97,5 +95,4 @@ static int __init s3c2442_pll_12mhz(void)
return subsys_interface_register(&s3c2442_plls12_interface);
}
-
arch_initcall(s3c2442_pll_12mhz);
diff --git a/arch/arm/mach-s3c2440/s3c2440-pll-16934400.c b/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c
index 3f15bcf64290..debfa106289b 100644
--- a/arch/arm/mach-s3c2440/s3c2440-pll-16934400.c
+++ b/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c
@@ -1,5 +1,4 @@
-/* arch/arm/mach-s3c2440/s3c2440-pll-16934400.c
- *
+/*
* Copyright (c) 2006-2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
@@ -111,7 +110,6 @@ static int __init s3c2440_pll_16934400(void)
{
return subsys_interface_register(&s3c2440_plls169344_interface);
}
-
arch_initcall(s3c2440_pll_16934400);
static struct subsys_interface s3c2442_plls169344_interface = {
@@ -124,5 +122,4 @@ static int __init s3c2442_pll_16934400(void)
{
return subsys_interface_register(&s3c2442_plls169344_interface);
}
-
arch_initcall(s3c2442_pll_16934400);
diff --git a/arch/arm/mach-s3c24xx/pm-h1940.S b/arch/arm/mach-s3c24xx/pm-h1940.S
index c93bf2db9f4d..6183a688012b 100644
--- a/arch/arm/mach-s3c24xx/pm-h1940.S
+++ b/arch/arm/mach-s3c24xx/pm-h1940.S
@@ -30,4 +30,4 @@
h1940_pm_return:
mov r0, #S3C2410_PA_GPIO
- ldr pc, [ r0, #S3C2410_GSTATUS3 - S3C24XX_VA_GPIO ]
+ ldr pc, [r0, #S3C2410_GSTATUS3 - S3C24XX_VA_GPIO]
diff --git a/arch/arm/mach-s3c24xx/pm-s3c2410.c b/arch/arm/mach-s3c24xx/pm-s3c2410.c
index 949ae05e07c5..2d82c4f116cd 100644
--- a/arch/arm/mach-s3c24xx/pm-s3c2410.c
+++ b/arch/arm/mach-s3c24xx/pm-s3c2410.c
@@ -29,16 +29,16 @@
#include <linux/gpio.h>
#include <linux/io.h>
-#include <mach/hardware.h>
-
#include <asm/mach-types.h>
+#include <mach/hardware.h>
#include <mach/regs-gpio.h>
-#include <mach/h1940.h>
#include <plat/cpu.h>
#include <plat/pm.h>
+#include "h1940.h"
+
static void s3c2410_pm_prepare(void)
{
/* ensure at least GSTATUS3 has the resume address */
diff --git a/arch/arm/mach-s3c24xx/pm-s3c2412.c b/arch/arm/mach-s3c24xx/pm-s3c2412.c
index c60f67a75aff..668a78a8b195 100644
--- a/arch/arm/mach-s3c24xx/pm-s3c2412.c
+++ b/arch/arm/mach-s3c24xx/pm-s3c2412.c
@@ -21,19 +21,19 @@
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <mach/hardware.h>
#include <asm/cacheflush.h>
#include <asm/irq.h>
-#include <mach/regs-power.h>
+#include <mach/hardware.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-dsc.h>
#include <plat/cpu.h>
#include <plat/pm.h>
-
#include <plat/s3c2412.h>
+#include "regs-dsc.h"
+#include "s3c2412-power.h"
+
extern void s3c2412_sleep_enter(void);
static int s3c2412_cpu_suspend(unsigned long arg)
@@ -48,7 +48,8 @@ static int s3c2412_cpu_suspend(unsigned long arg)
s3c2412_sleep_enter();
- panic("sleep resumed to originator?");
+ pr_info("Failed to suspend the system\n");
+ return 1; /* Aborting suspend */
}
static void s3c2412_pm_prepare(void)
diff --git a/arch/arm/mach-s3c24xx/pm-s3c2416.c b/arch/arm/mach-s3c24xx/pm-s3c2416.c
index 1bd4817b8eb8..44923895f558 100644
--- a/arch/arm/mach-s3c24xx/pm-s3c2416.c
+++ b/arch/arm/mach-s3c24xx/pm-s3c2416.c
@@ -16,12 +16,13 @@
#include <asm/cacheflush.h>
-#include <mach/regs-power.h>
#include <mach/regs-s3c2443-clock.h>
#include <plat/cpu.h>
#include <plat/pm.h>
+#include "s3c2412-power.h"
+
extern void s3c2412_sleep_enter(void);
static int s3c2416_cpu_suspend(unsigned long arg)
@@ -34,7 +35,8 @@ static int s3c2416_cpu_suspend(unsigned long arg)
s3c2412_sleep_enter();
- panic("sleep resumed to originator?");
+ pr_info("Failed to suspend the system\n");
+ return 1; /* Aborting suspend */
}
static void s3c2416_pm_prepare(void)
diff --git a/arch/arm/mach-s3c24xx/pm.c b/arch/arm/mach-s3c24xx/pm.c
index 724755f0b0f5..caa5b7211380 100644
--- a/arch/arm/mach-s3c24xx/pm.c
+++ b/arch/arm/mach-s3c24xx/pm.c
@@ -38,7 +38,6 @@
#include <plat/regs-serial.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
#include <mach/regs-irq.h>
#include <asm/mach/time.h>
@@ -46,6 +45,8 @@
#include <plat/gpio-cfg.h>
#include <plat/pm.h>
+#include "regs-mem.h"
+
#define PFX "s3c24xx-pm: "
static struct sleep_save core_save[] = {
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-dsc.h b/arch/arm/mach-s3c24xx/regs-dsc.h
index 98fd4a05587c..98fd4a05587c 100644
--- a/arch/arm/mach-s3c24xx/include/mach/regs-dsc.h
+++ b/arch/arm/mach-s3c24xx/regs-dsc.h
diff --git a/arch/arm/mach-s3c24xx/regs-mem.h b/arch/arm/mach-s3c24xx/regs-mem.h
new file mode 100644
index 000000000000..86b1258368c2
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/regs-mem.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 Memory Control register definitions
+ */
+
+#ifndef __ARCH_ARM_MACH_S3C24XX_REGS_MEM_H
+#define __ARCH_ARM_MACH_S3C24XX_REGS_MEM_H __FILE__
+
+#define S3C2410_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
+
+#define S3C2410_BWSCON S3C2410_MEMREG(0x00)
+#define S3C2410_BANKCON0 S3C2410_MEMREG(0x04)
+#define S3C2410_BANKCON1 S3C2410_MEMREG(0x08)
+#define S3C2410_BANKCON2 S3C2410_MEMREG(0x0C)
+#define S3C2410_BANKCON3 S3C2410_MEMREG(0x10)
+#define S3C2410_BANKCON4 S3C2410_MEMREG(0x14)
+#define S3C2410_BANKCON5 S3C2410_MEMREG(0x18)
+#define S3C2410_BANKCON6 S3C2410_MEMREG(0x1C)
+#define S3C2410_BANKCON7 S3C2410_MEMREG(0x20)
+#define S3C2410_REFRESH S3C2410_MEMREG(0x24)
+#define S3C2410_BANKSIZE S3C2410_MEMREG(0x28)
+
+#define S3C2410_BWSCON_ST1 (1 << 7)
+#define S3C2410_BWSCON_ST2 (1 << 11)
+#define S3C2410_BWSCON_ST3 (1 << 15)
+#define S3C2410_BWSCON_ST4 (1 << 19)
+#define S3C2410_BWSCON_ST5 (1 << 23)
+
+#define S3C2410_BWSCON_GET(_bwscon, _bank) (((_bwscon) >> ((_bank) * 4)) & 0xf)
+
+#define S3C2410_BWSCON_WS (1 << 2)
+
+#define S3C2410_BANKCON_PMC16 (0x3)
+
+#define S3C2410_BANKCON_Tacp_SHIFT (2)
+#define S3C2410_BANKCON_Tcah_SHIFT (4)
+#define S3C2410_BANKCON_Tcoh_SHIFT (6)
+#define S3C2410_BANKCON_Tacc_SHIFT (8)
+#define S3C2410_BANKCON_Tcos_SHIFT (11)
+#define S3C2410_BANKCON_Tacs_SHIFT (13)
+
+#define S3C2410_BANKCON_SDRAM (0x3 << 15)
+
+#define S3C2410_REFRESH_SELF (1 << 22)
+
+#define S3C2410_BANKSIZE_MASK (0x7 << 0)
+
+#endif /* __ARCH_ARM_MACH_S3C24XX_REGS_MEM_H */
diff --git a/arch/arm/mach-s3c24xx/s3c2410.c b/arch/arm/mach-s3c24xx/s3c2410.c
index a3c5cb086ee2..9ebef95da721 100644
--- a/arch/arm/mach-s3c24xx/s3c2410.c
+++ b/arch/arm/mach-s3c24xx/s3c2410.c
@@ -49,6 +49,8 @@
#include <plat/gpio-cfg.h>
#include <plat/gpio-cfg-helpers.h>
+#include "common.h"
+
/* Initial IO mappings */
static struct map_desc s3c2410_iodesc[] __initdata = {
@@ -182,8 +184,8 @@ int __init s3c2410_init(void)
#ifdef CONFIG_PM
register_syscore_ops(&s3c2410_pm_syscore_ops);
-#endif
register_syscore_ops(&s3c24xx_irq_syscore_ops);
+#endif
return device_register(&s3c2410_dev);
}
diff --git a/arch/arm/mach-s3c24xx/s3c2412-power.h b/arch/arm/mach-s3c24xx/s3c2412-power.h
new file mode 100644
index 000000000000..1b02c5ddb31b
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/s3c2412-power.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_S3C24XX_S3C2412_POWER_H
+#define __ARCH_ARM_MACH_S3C24XX_S3C2412_POWER_H __FILE__
+
+#define S3C24XX_PWRREG(x) ((x) + S3C24XX_VA_CLKPWR)
+
+#define S3C2412_PWRMODECON S3C24XX_PWRREG(0x20)
+#define S3C2412_PWRCFG S3C24XX_PWRREG(0x24)
+
+#define S3C2412_INFORM0 S3C24XX_PWRREG(0x70)
+#define S3C2412_INFORM1 S3C24XX_PWRREG(0x74)
+#define S3C2412_INFORM2 S3C24XX_PWRREG(0x78)
+#define S3C2412_INFORM3 S3C24XX_PWRREG(0x7C)
+
+#define S3C2412_PWRCFG_BATF_IRQ (1 << 0)
+#define S3C2412_PWRCFG_BATF_IGNORE (2 << 0)
+#define S3C2412_PWRCFG_BATF_SLEEP (3 << 0)
+#define S3C2412_PWRCFG_BATF_MASK (3 << 0)
+
+#define S3C2412_PWRCFG_STANDBYWFI_IGNORE (0 << 6)
+#define S3C2412_PWRCFG_STANDBYWFI_IDLE (1 << 6)
+#define S3C2412_PWRCFG_STANDBYWFI_STOP (2 << 6)
+#define S3C2412_PWRCFG_STANDBYWFI_SLEEP (3 << 6)
+#define S3C2412_PWRCFG_STANDBYWFI_MASK (3 << 6)
+
+#define S3C2412_PWRCFG_RTC_MASKIRQ (1 << 8)
+#define S3C2412_PWRCFG_NAND_NORST (1 << 9)
+
+#endif /* __ARCH_ARM_MACH_S3C24XX_S3C2412_POWER_H */
diff --git a/arch/arm/mach-s3c24xx/s3c2412.c b/arch/arm/mach-s3c24xx/s3c2412.c
index 6c5f4031ff0c..0d592159a5c3 100644
--- a/arch/arm/mach-s3c24xx/s3c2412.c
+++ b/arch/arm/mach-s3c24xx/s3c2412.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-s3c2412/s3c2412.c
- *
+/*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
@@ -28,28 +27,31 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/hardware.h>
#include <asm/proc-fns.h>
#include <asm/irq.h>
#include <asm/system_misc.h>
-#include <plat/cpu-freq.h>
-
+#include <mach/hardware.h>
#include <mach/regs-clock.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-power.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-dsc.h>
-#include <plat/regs-spi.h>
-#include <mach/regs-s3c2412.h>
-#include <plat/s3c2412.h>
+#include <plat/clock.h>
#include <plat/cpu.h>
+#include <plat/cpu-freq.h>
#include <plat/devs.h>
-#include <plat/clock.h>
-#include <plat/pm.h>
-#include <plat/pll.h>
#include <plat/nand-core.h>
+#include <plat/pll.h>
+#include <plat/pm.h>
+#include <plat/regs-serial.h>
+#include <plat/regs-spi.h>
+#include <plat/s3c2412.h>
+
+#include "common.h"
+#include "regs-dsc.h"
+#include "s3c2412-power.h"
+
+#define S3C2412_SWRST (S3C24XX_VA_CLKPWR + 0x30)
+#define S3C2412_SWRST_RESET (0x533C2412)
#ifndef CONFIG_CPU_S3C2412_ONLY
void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
@@ -244,8 +246,8 @@ int __init s3c2412_init(void)
#ifdef CONFIG_PM
register_syscore_ops(&s3c2412_pm_syscore_ops);
-#endif
register_syscore_ops(&s3c24xx_irq_syscore_ops);
+#endif
return device_register(&s3c2412_dev);
}
diff --git a/arch/arm/mach-s3c24xx/s3c2412.h b/arch/arm/mach-s3c24xx/s3c2412.h
new file mode 100644
index 000000000000..548ced42cbb7
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/s3c2412.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_S3C24XX_S3C2412_H
+#define __ARCH_ARM_REGS_S3C24XX_S3C2412_H __FILE__
+
+#define S3C2412_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
+#define S3C2412_EBIREG(x) (S3C2412_VA_EBI + (x))
+
+#define S3C2412_SSMCREG(x) (S3C2412_VA_SSMC + (x))
+#define S3C2412_SSMC(x, o) (S3C2412_SSMCREG((x * 0x20) + (o)))
+
+#define S3C2412_REFRESH S3C2412_MEMREG(0x10)
+
+#define S3C2412_EBI_BANKCFG S3C2412_EBIREG(0x4)
+
+#define S3C2412_SSMC_BANK(x) S3C2412_SSMC(x, 0x0)
+
+#endif /* __ARCH_ARM_MACH_S3C24XX_S3C2412_H */
diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c
index 77ee0b732237..e30476db0295 100644
--- a/arch/arm/mach-s3c24xx/s3c2416.c
+++ b/arch/arm/mach-s3c24xx/s3c2416.c
@@ -63,6 +63,8 @@
#include <plat/rtc-core.h>
#include <plat/spi-core.h>
+#include "common.h"
+
static struct map_desc s3c2416_iodesc[] __initdata = {
IODESC_ENT(WATCHDOG),
IODESC_ENT(CLKPWR),
@@ -105,9 +107,9 @@ int __init s3c2416_init(void)
#ifdef CONFIG_PM
register_syscore_ops(&s3c2416_pm_syscore_ops);
-#endif
register_syscore_ops(&s3c24xx_irq_syscore_ops);
register_syscore_ops(&s3c2416_irq_syscore_ops);
+#endif
return device_register(&s3c2416_dev);
}
diff --git a/arch/arm/mach-s3c24xx/s3c2440.c b/arch/arm/mach-s3c24xx/s3c2440.c
index 2b3dddb49af7..559e394e8989 100644
--- a/arch/arm/mach-s3c24xx/s3c2440.c
+++ b/arch/arm/mach-s3c24xx/s3c2440.c
@@ -40,6 +40,8 @@
#include <plat/gpio-cfg.h>
#include <plat/gpio-cfg-helpers.h>
+#include "common.h"
+
static struct device s3c2440_dev = {
.bus = &s3c2440_subsys,
};
@@ -57,9 +59,9 @@ int __init s3c2440_init(void)
#ifdef CONFIG_PM
register_syscore_ops(&s3c2410_pm_syscore_ops);
+ register_syscore_ops(&s3c24xx_irq_syscore_ops);
#endif
register_syscore_ops(&s3c244x_pm_syscore_ops);
- register_syscore_ops(&s3c24xx_irq_syscore_ops);
/* register our system device for everything else */
diff --git a/arch/arm/mach-s3c24xx/s3c2442.c b/arch/arm/mach-s3c24xx/s3c2442.c
index 22cb7c94a8c8..f732826c2359 100644
--- a/arch/arm/mach-s3c24xx/s3c2442.c
+++ b/arch/arm/mach-s3c24xx/s3c2442.c
@@ -51,6 +51,8 @@
#include <plat/gpio-cfg.h>
#include <plat/gpio-cfg-helpers.h>
+#include "common.h"
+
/* S3C2442 extended clock support */
static unsigned long s3c2442_camif_upll_round(struct clk *clk,
@@ -172,9 +174,9 @@ int __init s3c2442_init(void)
#ifdef CONFIG_PM
register_syscore_ops(&s3c2410_pm_syscore_ops);
+ register_syscore_ops(&s3c24xx_irq_syscore_ops);
#endif
register_syscore_ops(&s3c244x_pm_syscore_ops);
- register_syscore_ops(&s3c24xx_irq_syscore_ops);
return device_register(&s3c2442_dev);
}
diff --git a/arch/arm/mach-s3c24xx/s3c244x.c b/arch/arm/mach-s3c24xx/s3c244x.c
index b0b60a1154d6..ad2671baa910 100644
--- a/arch/arm/mach-s3c24xx/s3c244x.c
+++ b/arch/arm/mach-s3c24xx/s3c244x.c
@@ -36,7 +36,6 @@
#include <mach/regs-clock.h>
#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-dsc.h>
#include <plat/s3c2410.h>
#include <plat/s3c244x.h>
@@ -48,6 +47,8 @@
#include <plat/nand-core.h>
#include <plat/watchdog-reset.h>
+#include "regs-dsc.h"
+
static struct map_desc s3c244x_iodesc[] __initdata = {
IODESC_ENT(CLKPWR),
IODESC_ENT(TIMER),
diff --git a/arch/arm/mach-s3c24xx/simtec-audio.c b/arch/arm/mach-s3c24xx/simtec-audio.c
index fd0ef05763a9..67cb5120dfeb 100644
--- a/arch/arm/mach-s3c24xx/simtec-audio.c
+++ b/arch/arm/mach-s3c24xx/simtec-audio.c
@@ -17,16 +17,13 @@
#include <linux/device.h>
#include <linux/io.h>
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-#include <mach/bast-cpld.h>
-
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <linux/platform_data/asoc-s3c24xx_simtec.h>
#include <plat/devs.h>
+#include "bast.h"
#include "simtec.h"
/* platform ops for audio */
diff --git a/arch/arm/mach-s3c24xx/simtec-nor.c b/arch/arm/mach-s3c24xx/simtec-nor.c
index 029744fcaacb..8884bffa619a 100644
--- a/arch/arm/mach-s3c24xx/simtec-nor.c
+++ b/arch/arm/mach-s3c24xx/simtec-nor.c
@@ -27,9 +27,8 @@
#include <asm/mach/irq.h>
#include <mach/map.h>
-#include <mach/bast-map.h>
-#include <mach/bast-cpld.h>
+#include "bast.h"
#include "simtec.h"
static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
diff --git a/arch/arm/mach-s3c24xx/simtec-pm.c b/arch/arm/mach-s3c24xx/simtec-pm.c
index 699f93171297..38a2f1fdebab 100644
--- a/arch/arm/mach-s3c24xx/simtec-pm.c
+++ b/arch/arm/mach-s3c24xx/simtec-pm.c
@@ -28,12 +28,13 @@
#include <mach/map.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
#include <asm/mach-types.h>
#include <plat/pm.h>
+#include "regs-mem.h"
+
#define COPYRIGHT ", Copyright 2005 Simtec Electronics"
/* pm_simtec_init
diff --git a/arch/arm/mach-s3c24xx/simtec-usb.c b/arch/arm/mach-s3c24xx/simtec-usb.c
index ddf7a3c743ac..2ed2e32430dc 100644
--- a/arch/arm/mach-s3c24xx/simtec-usb.c
+++ b/arch/arm/mach-s3c24xx/simtec-usb.c
@@ -28,15 +28,13 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-
#include <mach/hardware.h>
#include <asm/irq.h>
#include <linux/platform_data/usb-ohci-s3c2410.h>
#include <plat/devs.h>
+#include "bast.h"
#include "simtec.h"
/* control power and monitor over-current events on various Simtec
@@ -79,7 +77,7 @@ static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
int ret;
if (on) {
- ret = request_irq(IRQ_USBOC, usb_simtec_ocirq,
+ ret = request_irq(BAST_IRQ_USBOC, usb_simtec_ocirq,
IRQF_DISABLED | IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING,
"USB Over-current", info);
@@ -87,7 +85,7 @@ static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
printk(KERN_ERR "failed to request usb oc irq\n");
}
} else {
- free_irq(IRQ_USBOC, info);
+ free_irq(BAST_IRQ_USBOC, info);
}
}
diff --git a/arch/arm/mach-s3c24xx/sleep-s3c2410.S b/arch/arm/mach-s3c24xx/sleep-s3c2410.S
index dd5b6388a5a5..dd47c8fa07fa 100644
--- a/arch/arm/mach-s3c24xx/sleep-s3c2410.S
+++ b/arch/arm/mach-s3c24xx/sleep-s3c2410.S
@@ -31,9 +31,10 @@
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
-#include <mach/regs-mem.h>
#include <plat/regs-serial.h>
+#include "regs-mem.h"
+
/* s3c2410_cpu_suspend
*
* put the cpu into sleep mode
@@ -45,9 +46,9 @@ ENTRY(s3c2410_cpu_suspend)
ldr r4, =S3C2410_REFRESH
ldr r5, =S3C24XX_MISCCR
ldr r6, =S3C2410_CLKCON
- ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
- ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
- ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
+ ldr r7, [r4] @ get REFRESH (and ensure in TLB)
+ ldr r8, [r5] @ get MISCCR (and ensure in TLB)
+ ldr r9, [r6] @ get CLKCON (and ensure in TLB)
orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
@@ -61,8 +62,8 @@ ENTRY(s3c2410_cpu_suspend)
@@ align next bit of code to cache line
.align 5
s3c2410_do_sleep:
- streq r7, [ r4 ] @ SDRAM sleep command
- streq r8, [ r5 ] @ SDRAM power-down config
- streq r9, [ r6 ] @ CPU sleep
+ streq r7, [r4] @ SDRAM sleep command
+ streq r8, [r5] @ SDRAM power-down config
+ streq r9, [r6] @ CPU sleep
1: beq 1b
mov pc, r14
diff --git a/arch/arm/mach-s3c24xx/sleep-s3c2412.S b/arch/arm/mach-s3c24xx/sleep-s3c2412.S
index c82418ed714d..5adaceb7da13 100644
--- a/arch/arm/mach-s3c24xx/sleep-s3c2412.S
+++ b/arch/arm/mach-s3c24xx/sleep-s3c2412.S
@@ -57,12 +57,12 @@ s3c2412_sleep_enter1:
* retry, as simply returning causes the system to lock.
*/
- ldrne r9, [ r1 ]
- strne r9, [ r1 ]
- ldrne r9, [ r2 ]
- strne r9, [ r2 ]
- ldrne r9, [ r3 ]
- strne r9, [ r3 ]
+ ldrne r9, [r1]
+ strne r9, [r1]
+ ldrne r9, [r2]
+ strne r9, [r2]
+ ldrne r9, [r3]
+ strne r9, [r3]
bne s3c2412_sleep_enter1
mov pc, r14
diff --git a/arch/arm/mach-s3c24xx/sleep.S b/arch/arm/mach-s3c24xx/sleep.S
index c56612569b40..7f378b662da6 100644
--- a/arch/arm/mach-s3c24xx/sleep.S
+++ b/arch/arm/mach-s3c24xx/sleep.S
@@ -31,7 +31,6 @@
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
-#include <mach/regs-mem.h>
#include <plat/regs-serial.h>
/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
diff --git a/arch/arm/mach-s3c24xx/vr1000.h b/arch/arm/mach-s3c24xx/vr1000.h
new file mode 100644
index 000000000000..7fcd2c2f183c
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/vr1000.h
@@ -0,0 +1,118 @@
+
+/* arch/arm/mach-s3c2410/include/mach/vr1000-cpld.h
+ *
+ * Copyright (c) 2003 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * VR1000 - CPLD control constants
+ * Machine VR1000 - IRQ Number definitions
+ * Machine VR1000 - Memory map definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __MACH_S3C24XX_VR1000_H
+#define __MACH_S3C24XX_VR1000_H __FILE__
+
+#define VR1000_CPLD_CTRL2_RAMWEN (0x04) /* SRAM Write Enable */
+
+/* irq numbers to onboard peripherals */
+
+#define VR1000_IRQ_USBOC IRQ_EINT19
+#define VR1000_IRQ_IDE0 IRQ_EINT16
+#define VR1000_IRQ_IDE1 IRQ_EINT17
+#define VR1000_IRQ_SERIAL IRQ_EINT12
+#define VR1000_IRQ_DM9000A IRQ_EINT10
+#define VR1000_IRQ_DM9000N IRQ_EINT9
+#define VR1000_IRQ_SMALERT IRQ_EINT8
+
+/* map */
+
+#define VR1000_IOADDR(x) (S3C2410_ADDR((x) + 0x01300000))
+
+/* we put the CPLD registers next, to get them out of the way */
+
+#define VR1000_VA_CTRL1 VR1000_IOADDR(0x00000000) /* 0x01300000 */
+#define VR1000_PA_CTRL1 (S3C2410_CS5 | 0x7800000)
+
+#define VR1000_VA_CTRL2 VR1000_IOADDR(0x00100000) /* 0x01400000 */
+#define VR1000_PA_CTRL2 (S3C2410_CS1 | 0x6000000)
+
+#define VR1000_VA_CTRL3 VR1000_IOADDR(0x00200000) /* 0x01500000 */
+#define VR1000_PA_CTRL3 (S3C2410_CS1 | 0x6800000)
+
+#define VR1000_VA_CTRL4 VR1000_IOADDR(0x00300000) /* 0x01600000 */
+#define VR1000_PA_CTRL4 (S3C2410_CS1 | 0x7000000)
+
+/* next, we have the PC104 ISA interrupt registers */
+
+#define VR1000_PA_PC104_IRQREQ (S3C2410_CS5 | 0x6000000) /* 0x01700000 */
+#define VR1000_VA_PC104_IRQREQ VR1000_IOADDR(0x00400000)
+
+#define VR1000_PA_PC104_IRQRAW (S3C2410_CS5 | 0x6800000) /* 0x01800000 */
+#define VR1000_VA_PC104_IRQRAW VR1000_IOADDR(0x00500000)
+
+#define VR1000_PA_PC104_IRQMASK (S3C2410_CS5 | 0x7000000) /* 0x01900000 */
+#define VR1000_VA_PC104_IRQMASK VR1000_IOADDR(0x00600000)
+
+/*
+ * 0xE0000000 contains the IO space that is split by speed and
+ * whether the access is for 8 or 16bit IO... this ensures that
+ * the correct access is made
+ *
+ * 0x10000000 of space, partitioned as so:
+ *
+ * 0x00000000 to 0x04000000 8bit, slow
+ * 0x04000000 to 0x08000000 16bit, slow
+ * 0x08000000 to 0x0C000000 16bit, net
+ * 0x0C000000 to 0x10000000 16bit, fast
+ *
+ * each of these spaces has the following in:
+ *
+ * 0x02000000 to 0x02100000 1MB IDE primary channel
+ * 0x02100000 to 0x02200000 1MB IDE primary channel aux
+ * 0x02200000 to 0x02400000 1MB IDE secondary channel
+ * 0x02300000 to 0x02400000 1MB IDE secondary channel aux
+ * 0x02500000 to 0x02600000 1MB Davicom DM9000 ethernet controllers
+ * 0x02600000 to 0x02700000 1MB
+ *
+ * the phyiscal layout of the zones are:
+ * nGCS2 - 8bit, slow
+ * nGCS3 - 16bit, slow
+ * nGCS4 - 16bit, net
+ * nGCS5 - 16bit, fast
+ */
+
+#define VR1000_VA_MULTISPACE (0xE0000000)
+
+#define VR1000_VA_ISAIO (VR1000_VA_MULTISPACE + 0x00000000)
+#define VR1000_VA_ISAMEM (VR1000_VA_MULTISPACE + 0x01000000)
+#define VR1000_VA_IDEPRI (VR1000_VA_MULTISPACE + 0x02000000)
+#define VR1000_VA_IDEPRIAUX (VR1000_VA_MULTISPACE + 0x02100000)
+#define VR1000_VA_IDESEC (VR1000_VA_MULTISPACE + 0x02200000)
+#define VR1000_VA_IDESECAUX (VR1000_VA_MULTISPACE + 0x02300000)
+#define VR1000_VA_ASIXNET (VR1000_VA_MULTISPACE + 0x02400000)
+#define VR1000_VA_DM9000 (VR1000_VA_MULTISPACE + 0x02500000)
+#define VR1000_VA_SUPERIO (VR1000_VA_MULTISPACE + 0x02600000)
+
+/* physical offset addresses for the peripherals */
+
+#define VR1000_PA_IDEPRI (0x02000000)
+#define VR1000_PA_IDEPRIAUX (0x02800000)
+#define VR1000_PA_IDESEC (0x03000000)
+#define VR1000_PA_IDESECAUX (0x03800000)
+#define VR1000_PA_DM9000 (0x05000000)
+
+#define VR1000_PA_SERIAL (0x11800000)
+#define VR1000_VA_SERIAL (VR1000_IOADDR(0x00700000))
+
+/* VR1000 ram is in CS1, with A26..A24 = 2_101 */
+#define VR1000_PA_SRAM (S3C2410_CS1 | 0x05000000)
+
+/* some configurations for the peripherals */
+
+#define VR1000_DM9000_CS VR1000_VAM_CS4
+
+#endif /* __MACH_S3C24XX_VR1000_H */
diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c
index 803711e283b2..8499415be9cd 100644
--- a/arch/arm/mach-s3c64xx/clock.c
+++ b/arch/arm/mach-s3c64xx/clock.c
@@ -23,7 +23,6 @@
#include <mach/hardware.h>
#include <mach/map.h>
-#include <mach/regs-sys.h>
#include <mach/regs-clock.h>
#include <plat/cpu.h>
@@ -33,6 +32,8 @@
#include <plat/clock-clksrc.h>
#include <plat/pll.h>
+#include "regs-sys.h"
+
/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
* ext_xtal_mux for want of an actual name from the manual.
*/
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index aef303b8997e..0b9c0ba44834 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -25,10 +25,10 @@
#include <linux/dma-mapping.h>
#include <linux/irq.h>
#include <linux/gpio.h>
+#include <linux/irqchip/arm-vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <asm/hardware/vic.h>
#include <asm/system_misc.h>
#include <mach/map.h>
diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c
index acb197ccf3f7..ead5fab0dbb5 100644
--- a/arch/arm/mach-s3c64xx/cpuidle.c
+++ b/arch/arm/mach-s3c64xx/cpuidle.c
@@ -20,8 +20,8 @@
#include <mach/map.h>
-#include <mach/regs-sys.h>
-#include <mach/regs-syscon-power.h>
+#include "regs-sys.h"
+#include "regs-syscon-power.h"
static int s3c64xx_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
diff --git a/arch/arm/mach-s3c64xx/include/mach/crag6410.h b/arch/arm/mach-s3c64xx/crag6410.h
index 4c3c9994fc2c..4c3c9994fc2c 100644
--- a/arch/arm/mach-s3c64xx/include/mach/crag6410.h
+++ b/arch/arm/mach-s3c64xx/crag6410.h
diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c
index f2a7a1725596..ec29b35f25c0 100644
--- a/arch/arm/mach-s3c64xx/dma.c
+++ b/arch/arm/mach-s3c64xx/dma.c
@@ -28,10 +28,10 @@
#include <mach/map.h>
#include <mach/irqs.h>
-#include <mach/regs-sys.h>
-
#include <asm/hardware/pl080.h>
+#include "regs-sys.h"
+
/* dma channel state information */
struct s3c64xx_dmac {
diff --git a/arch/arm/mach-s3c64xx/include/mach/regs-irq.h b/arch/arm/mach-s3c64xx/include/mach/regs-irq.h
index bcce68a0bb75..6a1127891c87 100644
--- a/arch/arm/mach-s3c64xx/include/mach/regs-irq.h
+++ b/arch/arm/mach-s3c64xx/include/mach/regs-irq.h
@@ -15,6 +15,5 @@
#ifndef __ASM_ARCH_REGS_IRQ_H
#define __ASM_ARCH_REGS_IRQ_H __FILE__
-#include <asm/hardware/vic.h>
#endif /* __ASM_ARCH_6400_REGS_IRQ_H */
diff --git a/arch/arm/mach-s3c64xx/include/mach/regs-sys.h b/arch/arm/mach-s3c64xx/include/mach/regs-sys.h
deleted file mode 100644
index b91e02093289..000000000000
--- a/arch/arm/mach-s3c64xx/include/mach/regs-sys.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* arch/arm/plat-s3c64xx/include/plat/regs-sys.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- * http://armlinux.simtec.co.uk/
- *
- * S3C64XX system register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __PLAT_REGS_SYS_H
-#define __PLAT_REGS_SYS_H __FILE__
-
-#define S3C_SYSREG(x) (S3C_VA_SYS + (x))
-
-#define S3C64XX_AHB_CON0 S3C_SYSREG(0x100)
-#define S3C64XX_AHB_CON1 S3C_SYSREG(0x104)
-#define S3C64XX_AHB_CON2 S3C_SYSREG(0x108)
-
-#define S3C64XX_SDMA_SEL S3C_SYSREG(0x110)
-
-#define S3C64XX_OTHERS S3C_SYSREG(0x900)
-
-#define S3C64XX_OTHERS_USBMASK (1 << 16)
-#define S3C64XX_OTHERS_SYNCMUXSEL (1 << 6)
-
-#endif /* _PLAT_REGS_SYS_H */
diff --git a/arch/arm/mach-s3c64xx/include/mach/tick.h b/arch/arm/mach-s3c64xx/include/mach/tick.h
index ebe18a9469b8..db9c1b1d56a4 100644
--- a/arch/arm/mach-s3c64xx/include/mach/tick.h
+++ b/arch/arm/mach-s3c64xx/include/mach/tick.h
@@ -15,6 +15,8 @@
#ifndef __ASM_ARCH_TICK_H
#define __ASM_ARCH_TICK_H __FILE__
+#include <linux/irqchip/arm-vic.h>
+
/* note, the timer interrutps turn up in 2 places, the vic and then
* the timer block. We take the VIC as the base at the moment.
*/
diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c
index 99e82ac81b69..728eef3296b2 100644
--- a/arch/arm/mach-s3c64xx/mach-anw6410.c
+++ b/arch/arm/mach-s3c64xx/mach-anw6410.c
@@ -31,7 +31,6 @@
#include <video/platform_lcd.h>
#include <video/samsung_fimd.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
@@ -50,9 +49,9 @@
#include <plat/devs.h>
#include <plat/cpu.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-modem.h>
#include "common.h"
+#include "regs-modem.h"
/* DM9000 */
#define ANW6410_PA_DM9000 (0x18000000)
@@ -230,10 +229,9 @@ MACHINE_START(ANW6410, "A&W6410")
.atag_offset = 0x100,
.init_irq = s3c6410_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = anw6410_map_io,
.init_machine = anw6410_machine_init,
.init_late = s3c64xx_init_late,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c64xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
index 755c0bb119f4..bf3d1c09b085 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c
@@ -29,7 +29,7 @@
#include <linux/platform_data/spi-s3c64xx.h>
-#include <mach/crag6410.h>
+#include "crag6410.h"
static struct s3c64xx_spi_csinfo wm0010_spi_csinfo = {
.line = S3C64XX_GPC(3),
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index bf6311a28f3d..1acf02bace57 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -42,7 +42,6 @@
#include <sound/wm1250-ev1.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
@@ -50,12 +49,7 @@
#include <mach/hardware.h>
#include <mach/map.h>
-#include <mach/regs-sys.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-modem.h>
-#include <mach/crag6410.h>
-
-#include <mach/regs-gpio-memport.h>
#include <plat/regs-serial.h>
#include <plat/fb.h>
@@ -72,6 +66,10 @@
#include <plat/pm.h>
#include "common.h"
+#include "crag6410.h"
+#include "regs-gpio-memport.h"
+#include "regs-modem.h"
+#include "regs-sys.h"
/* serial port setup */
@@ -867,10 +865,9 @@ MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410")
/* Maintainer: Mark Brown <broonie@opensource.wolfsonmicro.com> */
.atag_offset = 0x100,
.init_irq = s3c6410_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = crag6410_map_io,
.init_machine = crag6410_machine_init,
.init_late = s3c64xx_init_late,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c64xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index 2b144893ddc4..7212eb9cfeb9 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -30,7 +30,6 @@
#include <mach/hardware.h>
#include <mach/map.h>
-#include <asm/hardware/vic.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
@@ -273,10 +272,9 @@ MACHINE_START(HMT, "Airgoo-HMT")
/* Maintainer: Peter Korsgaard <jacmet@sunsite.dk> */
.atag_offset = 0x100,
.init_irq = s3c6410_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = hmt_map_io,
.init_machine = hmt_machine_init,
.init_late = s3c64xx_init_late,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c64xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
index 07c349cca333..4b41fcdaa7b6 100644
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@ -24,15 +24,12 @@
#include <linux/serial_core.h>
#include <linux/types.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-modem.h>
-#include <mach/regs-srom.h>
#include <plat/adc.h>
#include <plat/cpu.h>
@@ -46,6 +43,8 @@
#include <video/samsung_fimd.h>
#include "common.h"
+#include "regs-modem.h"
+#include "regs-srom.h"
#define UCON S3C2410_UCON_DEFAULT
#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
@@ -352,10 +351,9 @@ MACHINE_START(MINI6410, "MINI6410")
/* Maintainer: Darius Augulis <augulis.darius@gmail.com> */
.atag_offset = 0x100,
.init_irq = s3c6410_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = mini6410_map_io,
.init_machine = mini6410_machine_init,
.init_late = s3c64xx_init_late,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c64xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/mach-ncp.c b/arch/arm/mach-s3c64xx/mach-ncp.c
index e5f9a79b535d..8d3cedd995ff 100644
--- a/arch/arm/mach-s3c64xx/mach-ncp.c
+++ b/arch/arm/mach-s3c64xx/mach-ncp.c
@@ -26,7 +26,6 @@
#include <video/platform_lcd.h>
#include <video/samsung_fimd.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
@@ -101,10 +100,9 @@ MACHINE_START(NCP, "NCP")
/* Maintainer: Samsung Electronics */
.atag_offset = 0x100,
.init_irq = s3c6410_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = ncp_map_io,
.init_machine = ncp_machine_init,
.init_late = s3c64xx_init_late,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c64xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index 7476f7c722ab..fa12bd21ad82 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -25,15 +25,12 @@
#include <linux/serial_core.h>
#include <linux/types.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-modem.h>
-#include <mach/regs-srom.h>
#include <plat/adc.h>
#include <plat/cpu.h>
@@ -47,6 +44,8 @@
#include <video/samsung_fimd.h>
#include "common.h"
+#include "regs-modem.h"
+#include "regs-srom.h"
#define UCON S3C2410_UCON_DEFAULT
#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
@@ -331,10 +330,9 @@ MACHINE_START(REAL6410, "REAL6410")
.atag_offset = 0x100,
.init_irq = s3c6410_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = real6410_map_io,
.init_machine = real6410_machine_init,
.init_late = s3c64xx_init_late,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c64xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
index c6d7390939ae..fc3e9b32e26f 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq.c
@@ -25,7 +25,6 @@
#include <mach/map.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-modem.h>
#include <plat/clock.h>
#include <plat/cpu.h>
@@ -41,6 +40,7 @@
#include <video/platform_lcd.h>
#include "common.h"
+#include "regs-modem.h"
#define UCON S3C2410_UCON_DEFAULT
#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE)
diff --git a/arch/arm/mach-s3c64xx/mach-smartq5.c b/arch/arm/mach-s3c64xx/mach-smartq5.c
index 96d6da2b6b5f..ca2afcfce573 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq5.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq5.c
@@ -17,7 +17,6 @@
#include <linux/leds.h>
#include <linux/platform_device.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -153,10 +152,9 @@ MACHINE_START(SMARTQ5, "SmartQ 5")
/* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT com> */
.atag_offset = 0x100,
.init_irq = s3c6410_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = smartq_map_io,
.init_machine = smartq5_machine_init,
.init_late = s3c64xx_init_late,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c64xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/mach-smartq7.c b/arch/arm/mach-s3c64xx/mach-smartq7.c
index 7d1167bdc921..37bb0c632a5e 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq7.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq7.c
@@ -17,7 +17,6 @@
#include <linux/leds.h>
#include <linux/platform_device.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -169,10 +168,9 @@ MACHINE_START(SMARTQ7, "SmartQ 7")
/* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT com> */
.atag_offset = 0x100,
.init_irq = s3c6410_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = smartq_map_io,
.init_machine = smartq7_machine_init,
.init_late = s3c64xx_init_late,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c64xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6400.c b/arch/arm/mach-s3c64xx/mach-smdk6400.c
index a928fae5694e..a392869c8342 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6400.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6400.c
@@ -22,7 +22,6 @@
#include <asm/mach-types.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
@@ -90,10 +89,9 @@ MACHINE_START(SMDK6400, "SMDK6400")
.atag_offset = 0x100,
.init_irq = s3c6400_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = smdk6400_map_io,
.init_machine = smdk6400_machine_init,
.init_late = s3c64xx_init_late,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c64xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index 574a9eef588d..ba7544e2d04d 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -45,7 +45,6 @@
#include <video/platform_lcd.h>
#include <video/samsung_fimd.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
@@ -57,10 +56,7 @@
#include <asm/mach-types.h>
#include <plat/regs-serial.h>
-#include <mach/regs-modem.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-sys.h>
-#include <mach/regs-srom.h>
#include <linux/platform_data/ata-samsung_cf.h>
#include <linux/platform_data/i2c-s3c2410.h>
#include <plat/fb.h>
@@ -75,6 +71,9 @@
#include <plat/backlight.h>
#include "common.h"
+#include "regs-modem.h"
+#include "regs-srom.h"
+#include "regs-sys.h"
#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
@@ -700,10 +699,9 @@ MACHINE_START(SMDK6410, "SMDK6410")
.atag_offset = 0x100,
.init_irq = s3c6410_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = smdk6410_map_io,
.init_machine = smdk6410_machine_init,
.init_late = s3c64xx_init_late,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s3c64xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c
index d2e1a16690bd..6a1f91fea678 100644
--- a/arch/arm/mach-s3c64xx/pm.c
+++ b/arch/arm/mach-s3c64xx/pm.c
@@ -26,12 +26,13 @@
#include <plat/pm.h>
#include <plat/wakeup-mask.h>
-#include <mach/regs-sys.h>
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
-#include <mach/regs-syscon-power.h>
-#include <mach/regs-gpio-memport.h>
-#include <mach/regs-modem.h>
+
+#include "regs-gpio-memport.h"
+#include "regs-modem.h"
+#include "regs-sys.h"
+#include "regs-syscon-power.h"
struct s3c64xx_pm_domain {
char *const name;
@@ -296,7 +297,8 @@ static int s3c64xx_cpu_suspend(unsigned long arg)
/* we should never get past here */
- panic("sleep resumed to originator?");
+ pr_info("Failed to suspend the system\n");
+ return 1; /* Aborting suspend */
}
/* mapping of interrupts to parts of the wakeup mask */
diff --git a/arch/arm/mach-s3c64xx/include/mach/regs-gpio-memport.h b/arch/arm/mach-s3c64xx/regs-gpio-memport.h
index 82342f6fd27d..b927593019f5 100644
--- a/arch/arm/mach-s3c64xx/include/mach/regs-gpio-memport.h
+++ b/arch/arm/mach-s3c64xx/regs-gpio-memport.h
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-s3c64xx/include/mach/regs-gpio-memport.h
- *
+/*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -8,8 +7,8 @@
* S3C64XX - GPIO memory port register definitions
*/
-#ifndef __ASM_PLAT_S3C64XX_REGS_GPIO_MEMPORT_H
-#define __ASM_PLAT_S3C64XX_REGS_GPIO_MEMPORT_H __FILE__
+#ifndef __MACH_S3C64XX_REGS_GPIO_MEMPORT_H
+#define __MACH_S3C64XX_REGS_GPIO_MEMPORT_H __FILE__
#define S3C64XX_MEM0CONSTOP S3C64XX_GPIOREG(0x1B0)
#define S3C64XX_MEM1CONSTOP S3C64XX_GPIOREG(0x1B4)
@@ -21,5 +20,5 @@
#define S3C64XX_MEM0DRVCON S3C64XX_GPIOREG(0x1D0)
#define S3C64XX_MEM1DRVCON S3C64XX_GPIOREG(0x1D4)
-#endif /* __ASM_PLAT_S3C64XX_REGS_GPIO_MEMPORT_H */
+#endif /* __MACH_S3C64XX_REGS_GPIO_MEMPORT_H */
diff --git a/arch/arm/mach-s3c64xx/include/mach/regs-modem.h b/arch/arm/mach-s3c64xx/regs-modem.h
index 49f7759dedfa..073cdd3a03be 100644
--- a/arch/arm/mach-s3c64xx/include/mach/regs-modem.h
+++ b/arch/arm/mach-s3c64xx/regs-modem.h
@@ -1,5 +1,4 @@
-/* arch/arm/plat-s3c64xx/include/plat/regs-modem.h
- *
+/*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
@@ -12,10 +11,10 @@
* published by the Free Software Foundation.
*/
-#ifndef __PLAT_S3C64XX_REGS_MODEM_H
-#define __PLAT_S3C64XX_REGS_MODEM_H __FILE__
+#ifndef __MACH_S3C64XX_REGS_MODEM_H
+#define __MACH_S3C64XX_REGS_MODEM_H __FILE__
-#define S3C64XX_MODEMREG(x) (S3C64XX_VA_MODEM + (x))
+#define S3C64XX_MODEMREG(x) (S3C64XX_VA_MODEM + (x))
#define S3C64XX_MODEM_INT2AP S3C64XX_MODEMREG(0x0)
#define S3C64XX_MODEM_INT2MODEM S3C64XX_MODEMREG(0x4)
@@ -28,4 +27,4 @@
#define MIFPCON_INT2M_LEVEL (1 << 4)
#define MIFPCON_LCD_BYPASS (1 << 3)
-#endif /* __PLAT_S3C64XX_REGS_MODEM_H */
+#endif /* __MACH_S3C64XX_REGS_MODEM_H */
diff --git a/arch/arm/mach-s3c64xx/include/mach/regs-srom.h b/arch/arm/mach-s3c64xx/regs-srom.h
index 756731b36297..d56f3386eb00 100644
--- a/arch/arm/mach-s3c64xx/include/mach/regs-srom.h
+++ b/arch/arm/mach-s3c64xx/regs-srom.h
@@ -1,5 +1,4 @@
-/* arch/arm/plat-s3c64xx/include/plat/regs-srom.h
- *
+/*
* Copyright 2009 Andy Green <andy@warmcat.com>
*
* S3C64XX SROM definitions
@@ -9,8 +8,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __PLAT_REGS_SROM_H
-#define __PLAT_REGS_SROM_H __FILE__
+#ifndef __MACH_S3C64XX_REGS_SROM_H
+#define __MACH_S3C64XX_REGS_SROM_H __FILE__
#define S3C64XX_SROMREG(x) (S3C_VA_MEM + (x))
@@ -29,7 +28,7 @@
#define S3C64XX_SROM_BW__DATAWIDTH__SHIFT 0
#define S3C64XX_SROM_BW__WAITENABLE__SHIFT 2
#define S3C64XX_SROM_BW__BYTEENABLE__SHIFT 3
-#define S3C64XX_SROM_BW__CS_MASK 0xf
+#define S3C64XX_SROM_BW__CS_MASK 0xf
#define S3C64XX_SROM_BW__NCS0__SHIFT 0
#define S3C64XX_SROM_BW__NCS1__SHIFT 4
@@ -56,4 +55,4 @@
#define S3C64XX_SROM_BCX__TACS__SHIFT 28
#define S3C64XX_SROM_BCX__TACS__MASK 0xf
-#endif /* _PLAT_REGS_SROM_H */
+#endif /* __MACH_S3C64XX_REGS_SROM_H */
diff --git a/arch/arm/mach-s3c64xx/regs-sys.h b/arch/arm/mach-s3c64xx/regs-sys.h
new file mode 100644
index 000000000000..8c411fbb0cd9
--- /dev/null
+++ b/arch/arm/mach-s3c64xx/regs-sys.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX system register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __MACH_S3C64XX_REGS_SYS_H
+#define __MACH_S3C64XX_REGS_SYS_H __FILE__
+
+#define S3C_SYSREG(x) (S3C_VA_SYS + (x))
+
+#define S3C64XX_AHB_CON0 S3C_SYSREG(0x100)
+#define S3C64XX_AHB_CON1 S3C_SYSREG(0x104)
+#define S3C64XX_AHB_CON2 S3C_SYSREG(0x108)
+
+#define S3C64XX_SDMA_SEL S3C_SYSREG(0x110)
+
+#define S3C64XX_OTHERS S3C_SYSREG(0x900)
+
+#define S3C64XX_OTHERS_USBMASK (1 << 16)
+#define S3C64XX_OTHERS_SYNCMUXSEL (1 << 6)
+
+#endif /* __MACH_S3C64XX_REGS_SYS_H */
diff --git a/arch/arm/mach-s3c64xx/include/mach/regs-syscon-power.h b/arch/arm/mach-s3c64xx/regs-syscon-power.h
index 270d96ac9705..6e16b3404da9 100644
--- a/arch/arm/mach-s3c64xx/include/mach/regs-syscon-power.h
+++ b/arch/arm/mach-s3c64xx/regs-syscon-power.h
@@ -1,5 +1,4 @@
-/* arch/arm/plat-s3c64xx/include/plat/regs-syscon-power.h
- *
+/*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
@@ -12,8 +11,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __PLAT_S3C64XX_REGS_SYSCON_POWER_H
-#define __PLAT_S3C64XX_REGS_SYSCON_POWER_H __FILE__
+#ifndef __MACH_S3C64XX_REGS_SYSCON_POWER_H
+#define __MACH_S3C64XX_REGS_SYSCON_POWER_H __FILE__
#define S3C64XX_PWR_CFG S3C_SYSREG(0x804)
@@ -113,4 +112,4 @@
#define S3C64XX_INFORM2 S3C_SYSREG(0xA08)
#define S3C64XX_INFORM3 S3C_SYSREG(0xA0C)
-#endif /* __PLAT_S3C64XX_REGS_SYSCON_POWER_H */
+#endif /* __MACH_S3C64XX_REGS_SYSCON_POWER_H */
diff --git a/arch/arm/mach-s3c64xx/setup-usb-phy.c b/arch/arm/mach-s3c64xx/setup-usb-phy.c
index f6757e02d7db..c8174d95339b 100644
--- a/arch/arm/mach-s3c64xx/setup-usb-phy.c
+++ b/arch/arm/mach-s3c64xx/setup-usb-phy.c
@@ -15,11 +15,12 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <mach/map.h>
-#include <mach/regs-sys.h>
#include <plat/cpu.h>
#include <plat/regs-usb-hsotg-phy.h>
#include <plat/usb-phy.h>
+#include "regs-sys.h"
+
static int s3c_usb_otgphy_init(struct platform_device *pdev)
{
struct clk *xusbxti;
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c
index 5112371079d0..3537815247f1 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6440.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c
@@ -23,7 +23,6 @@
#include <mach/hardware.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
-#include <mach/s5p64x0-clock.h>
#include <plat/cpu-freq.h>
#include <plat/clock.h>
@@ -32,6 +31,7 @@
#include <plat/s5p-clock.h>
#include <plat/clock-clksrc.h>
+#include "clock.h"
#include "common.h"
static u32 epll_div[][5] = {
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c
index 154dea702d70..af384ddd2dcf 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6450.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c
@@ -23,7 +23,6 @@
#include <mach/hardware.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
-#include <mach/s5p64x0-clock.h>
#include <plat/cpu-freq.h>
#include <plat/clock.h>
@@ -32,6 +31,7 @@
#include <plat/s5p-clock.h>
#include <plat/clock-clksrc.h>
+#include "clock.h"
#include "common.h"
static struct clksrc_clk clk_mout_dpll = {
diff --git a/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h b/arch/arm/mach-s5p64x0/clock.h
index 0ef47d1b7670..28b8e3c6bd24 100644
--- a/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
+++ b/arch/arm/mach-s5p64x0/clock.h
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
- *
+/*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
@@ -10,8 +9,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __ASM_ARCH_CLOCK_H
-#define __ASM_ARCH_CLOCK_H __FILE__
+#ifndef __MACH_S5P64X0_CLOCK_H
+#define __MACH_S5P64X0_CLOCK_H __FILE__
#include <linux/clk.h>
@@ -36,4 +35,4 @@ extern int s5p64x0_mem_ctrl(struct clk *clk, int enable);
extern int s5p64x0_clk48m_ctrl(struct clk *clk, int enable);
-#endif /* __ASM_ARCH_CLOCK_H */
+#endif /* __MACH_S5P64X0_CLOCK_H */
diff --git a/arch/arm/mach-s5p64x0/gpiolib.c b/arch/arm/mach-s5p64x0/gpiolib.c
deleted file mode 100644
index 700dac6c43f3..000000000000
--- a/arch/arm/mach-s5p64x0/gpiolib.c
+++ /dev/null
@@ -1,508 +0,0 @@
-/* linux/arch/arm/mach-s5p64x0/gpiolib.c
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * S5P64X0 - GPIOlib 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/kernel.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-
-#include <mach/map.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-clock.h>
-
-#include <plat/cpu.h>
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-
-/*
- * S5P6440 GPIO bank summary:
- *
- * Bank GPIOs Style SlpCon ExtInt Group
- * A 6 4Bit Yes 1
- * B 7 4Bit Yes 1
- * C 8 4Bit Yes 2
- * F 2 2Bit Yes 4 [1]
- * G 7 4Bit Yes 5
- * H 10 4Bit[2] Yes 6
- * I 16 2Bit Yes None
- * J 12 2Bit Yes None
- * N 16 2Bit No IRQ_EINT
- * P 8 2Bit Yes 8
- * R 15 4Bit[2] Yes 8
- *
- * S5P6450 GPIO bank summary:
- *
- * Bank GPIOs Style SlpCon ExtInt Group
- * A 6 4Bit Yes 1
- * B 7 4Bit Yes 1
- * C 8 4Bit Yes 2
- * D 8 4Bit Yes None
- * F 2 2Bit Yes None
- * G 14 4Bit[2] Yes 5
- * H 10 4Bit[2] Yes 6
- * I 16 2Bit Yes None
- * J 12 2Bit Yes None
- * K 5 4Bit Yes None
- * N 16 2Bit No IRQ_EINT
- * P 11 2Bit Yes 8
- * Q 14 2Bit Yes None
- * R 15 4Bit[2] Yes None
- * S 8 2Bit Yes None
- *
- * [1] BANKF pins 14,15 do not form part of the external interrupt sources
- * [2] BANK has two control registers, GPxCON0 and GPxCON1
- */
-
-static int s5p64x0_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
- unsigned int offset)
-{
- struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
- void __iomem *base = ourchip->base;
- void __iomem *regcon = base;
- unsigned long con;
- unsigned long flags;
-
- switch (offset) {
- case 6:
- offset += 1;
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- regcon -= 4;
- break;
- default:
- offset -= 7;
- break;
- }
-
- s3c_gpio_lock(ourchip, flags);
-
- con = __raw_readl(regcon);
- con &= ~(0xf << con_4bit_shift(offset));
- __raw_writel(con, regcon);
-
- s3c_gpio_unlock(ourchip, flags);
-
- return 0;
-}
-
-static int s5p64x0_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
- unsigned int offset, int value)
-{
- struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
- void __iomem *base = ourchip->base;
- void __iomem *regcon = base;
- unsigned long con;
- unsigned long dat;
- unsigned long flags;
- unsigned con_offset = offset;
-
- switch (con_offset) {
- case 6:
- con_offset += 1;
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- regcon -= 4;
- break;
- default:
- con_offset -= 7;
- break;
- }
-
- s3c_gpio_lock(ourchip, flags);
-
- con = __raw_readl(regcon);
- con &= ~(0xf << con_4bit_shift(con_offset));
- con |= 0x1 << con_4bit_shift(con_offset);
-
- dat = __raw_readl(base + GPIODAT_OFF);
- if (value)
- dat |= 1 << offset;
- else
- dat &= ~(1 << offset);
-
- __raw_writel(con, regcon);
- __raw_writel(dat, base + GPIODAT_OFF);
-
- s3c_gpio_unlock(ourchip, flags);
-
- return 0;
-}
-
-int s5p64x0_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
- unsigned int off, unsigned int cfg)
-{
- void __iomem *reg = chip->base;
- unsigned int shift;
- u32 con;
-
- switch (off) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- shift = (off & 7) * 4;
- reg -= 4;
- break;
- case 6:
- shift = ((off + 1) & 7) * 4;
- reg -= 4;
- default:
- shift = ((off + 1) & 7) * 4;
- break;
- }
-
- if (s3c_gpio_is_cfg_special(cfg)) {
- cfg &= 0xf;
- cfg <<= shift;
- }
-
- con = __raw_readl(reg);
- con &= ~(0xf << shift);
- con |= cfg;
- __raw_writel(con, reg);
-
- return 0;
-}
-
-static struct s3c_gpio_cfg s5p64x0_gpio_cfgs[] = {
- {
- .cfg_eint = 0,
- }, {
- .cfg_eint = 7,
- }, {
- .cfg_eint = 3,
- .set_config = s5p64x0_gpio_setcfg_4bit_rbank,
- }, {
- .cfg_eint = 0,
- .set_config = s3c_gpio_setcfg_s3c24xx,
- .get_config = s3c_gpio_getcfg_s3c24xx,
- }, {
- .cfg_eint = 2,
- .set_config = s3c_gpio_setcfg_s3c24xx,
- .get_config = s3c_gpio_getcfg_s3c24xx,
- }, {
- .cfg_eint = 3,
- .set_config = s3c_gpio_setcfg_s3c24xx,
- .get_config = s3c_gpio_getcfg_s3c24xx,
- },
-};
-
-static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
- {
- .base = S5P64X0_GPA_BASE,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6440_GPA(0),
- .ngpio = S5P6440_GPIO_A_NR,
- .label = "GPA",
- },
- }, {
- .base = S5P64X0_GPB_BASE,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6440_GPB(0),
- .ngpio = S5P6440_GPIO_B_NR,
- .label = "GPB",
- },
- }, {
- .base = S5P64X0_GPC_BASE,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6440_GPC(0),
- .ngpio = S5P6440_GPIO_C_NR,
- .label = "GPC",
- },
- }, {
- .base = S5P64X0_GPG_BASE,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6440_GPG(0),
- .ngpio = S5P6440_GPIO_G_NR,
- .label = "GPG",
- },
- },
-};
-
-static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
- {
- .base = S5P64X0_GPH_BASE + 0x4,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6440_GPH(0),
- .ngpio = S5P6440_GPIO_H_NR,
- .label = "GPH",
- },
- },
-};
-
-static struct s3c_gpio_chip s5p6440_gpio_rbank_4bit2[] = {
- {
- .base = S5P64X0_GPR_BASE + 0x4,
- .config = &s5p64x0_gpio_cfgs[2],
- .chip = {
- .base = S5P6440_GPR(0),
- .ngpio = S5P6440_GPIO_R_NR,
- .label = "GPR",
- },
- },
-};
-
-static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
- {
- .base = S5P64X0_GPF_BASE,
- .config = &s5p64x0_gpio_cfgs[5],
- .chip = {
- .base = S5P6440_GPF(0),
- .ngpio = S5P6440_GPIO_F_NR,
- .label = "GPF",
- },
- }, {
- .base = S5P64X0_GPI_BASE,
- .config = &s5p64x0_gpio_cfgs[3],
- .chip = {
- .base = S5P6440_GPI(0),
- .ngpio = S5P6440_GPIO_I_NR,
- .label = "GPI",
- },
- }, {
- .base = S5P64X0_GPJ_BASE,
- .config = &s5p64x0_gpio_cfgs[3],
- .chip = {
- .base = S5P6440_GPJ(0),
- .ngpio = S5P6440_GPIO_J_NR,
- .label = "GPJ",
- },
- }, {
- .base = S5P64X0_GPN_BASE,
- .config = &s5p64x0_gpio_cfgs[4],
- .chip = {
- .base = S5P6440_GPN(0),
- .ngpio = S5P6440_GPIO_N_NR,
- .label = "GPN",
- },
- }, {
- .base = S5P64X0_GPP_BASE,
- .config = &s5p64x0_gpio_cfgs[5],
- .chip = {
- .base = S5P6440_GPP(0),
- .ngpio = S5P6440_GPIO_P_NR,
- .label = "GPP",
- },
- },
-};
-
-static struct s3c_gpio_chip s5p6450_gpio_4bit[] = {
- {
- .base = S5P64X0_GPA_BASE,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6450_GPA(0),
- .ngpio = S5P6450_GPIO_A_NR,
- .label = "GPA",
- },
- }, {
- .base = S5P64X0_GPB_BASE,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6450_GPB(0),
- .ngpio = S5P6450_GPIO_B_NR,
- .label = "GPB",
- },
- }, {
- .base = S5P64X0_GPC_BASE,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6450_GPC(0),
- .ngpio = S5P6450_GPIO_C_NR,
- .label = "GPC",
- },
- }, {
- .base = S5P6450_GPD_BASE,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6450_GPD(0),
- .ngpio = S5P6450_GPIO_D_NR,
- .label = "GPD",
- },
- }, {
- .base = S5P6450_GPK_BASE,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6450_GPK(0),
- .ngpio = S5P6450_GPIO_K_NR,
- .label = "GPK",
- },
- },
-};
-
-static struct s3c_gpio_chip s5p6450_gpio_4bit2[] = {
- {
- .base = S5P64X0_GPG_BASE + 0x4,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6450_GPG(0),
- .ngpio = S5P6450_GPIO_G_NR,
- .label = "GPG",
- },
- }, {
- .base = S5P64X0_GPH_BASE + 0x4,
- .config = &s5p64x0_gpio_cfgs[1],
- .chip = {
- .base = S5P6450_GPH(0),
- .ngpio = S5P6450_GPIO_H_NR,
- .label = "GPH",
- },
- },
-};
-
-static struct s3c_gpio_chip s5p6450_gpio_rbank_4bit2[] = {
- {
- .base = S5P64X0_GPR_BASE + 0x4,
- .config = &s5p64x0_gpio_cfgs[2],
- .chip = {
- .base = S5P6450_GPR(0),
- .ngpio = S5P6450_GPIO_R_NR,
- .label = "GPR",
- },
- },
-};
-
-static struct s3c_gpio_chip s5p6450_gpio_2bit[] = {
- {
- .base = S5P64X0_GPF_BASE,
- .config = &s5p64x0_gpio_cfgs[5],
- .chip = {
- .base = S5P6450_GPF(0),
- .ngpio = S5P6450_GPIO_F_NR,
- .label = "GPF",
- },
- }, {
- .base = S5P64X0_GPI_BASE,
- .config = &s5p64x0_gpio_cfgs[3],
- .chip = {
- .base = S5P6450_GPI(0),
- .ngpio = S5P6450_GPIO_I_NR,
- .label = "GPI",
- },
- }, {
- .base = S5P64X0_GPJ_BASE,
- .config = &s5p64x0_gpio_cfgs[3],
- .chip = {
- .base = S5P6450_GPJ(0),
- .ngpio = S5P6450_GPIO_J_NR,
- .label = "GPJ",
- },
- }, {
- .base = S5P64X0_GPN_BASE,
- .config = &s5p64x0_gpio_cfgs[4],
- .chip = {
- .base = S5P6450_GPN(0),
- .ngpio = S5P6450_GPIO_N_NR,
- .label = "GPN",
- },
- }, {
- .base = S5P64X0_GPP_BASE,
- .config = &s5p64x0_gpio_cfgs[5],
- .chip = {
- .base = S5P6450_GPP(0),
- .ngpio = S5P6450_GPIO_P_NR,
- .label = "GPP",
- },
- }, {
- .base = S5P6450_GPQ_BASE,
- .config = &s5p64x0_gpio_cfgs[4],
- .chip = {
- .base = S5P6450_GPQ(0),
- .ngpio = S5P6450_GPIO_Q_NR,
- .label = "GPQ",
- },
- }, {
- .base = S5P6450_GPS_BASE,
- .config = &s5p64x0_gpio_cfgs[5],
- .chip = {
- .base = S5P6450_GPS(0),
- .ngpio = S5P6450_GPIO_S_NR,
- .label = "GPS",
- },
- },
-};
-
-void __init s5p64x0_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
-{
- for (; nr_chips > 0; nr_chips--, chipcfg++) {
- if (!chipcfg->set_config)
- chipcfg->set_config = s3c_gpio_setcfg_s3c64xx_4bit;
- if (!chipcfg->get_config)
- chipcfg->get_config = s3c_gpio_getcfg_s3c64xx_4bit;
- if (!chipcfg->set_pull)
- chipcfg->set_pull = s3c_gpio_setpull_updown;
- if (!chipcfg->get_pull)
- chipcfg->get_pull = s3c_gpio_getpull_updown;
- }
-}
-
-static void __init s5p64x0_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
- int nr_chips)
-{
- for (; nr_chips > 0; nr_chips--, chip++) {
- chip->chip.direction_input = s5p64x0_gpiolib_rbank_4bit2_input;
- chip->chip.direction_output =
- s5p64x0_gpiolib_rbank_4bit2_output;
- s3c_gpiolib_add(chip);
- }
-}
-
-static int __init s5p64x0_gpiolib_init(void)
-{
- s5p64x0_gpiolib_set_cfg(s5p64x0_gpio_cfgs,
- ARRAY_SIZE(s5p64x0_gpio_cfgs));
-
- if (soc_is_s5p6450()) {
- samsung_gpiolib_add_2bit_chips(s5p6450_gpio_2bit,
- ARRAY_SIZE(s5p6450_gpio_2bit));
-
- samsung_gpiolib_add_4bit_chips(s5p6450_gpio_4bit,
- ARRAY_SIZE(s5p6450_gpio_4bit));
-
- samsung_gpiolib_add_4bit2_chips(s5p6450_gpio_4bit2,
- ARRAY_SIZE(s5p6450_gpio_4bit2));
-
- s5p64x0_gpio_add_rbank_4bit2(s5p6450_gpio_rbank_4bit2,
- ARRAY_SIZE(s5p6450_gpio_rbank_4bit2));
- } else {
- samsung_gpiolib_add_2bit_chips(s5p6440_gpio_2bit,
- ARRAY_SIZE(s5p6440_gpio_2bit));
-
- samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
- ARRAY_SIZE(s5p6440_gpio_4bit));
-
- samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
- ARRAY_SIZE(s5p6440_gpio_4bit2));
-
- s5p64x0_gpio_add_rbank_4bit2(s5p6440_gpio_rbank_4bit2,
- ARRAY_SIZE(s5p6440_gpio_rbank_4bit2));
- }
-
- return 0;
-}
-core_initcall(s5p64x0_gpiolib_init);
diff --git a/arch/arm/mach-s5p64x0/include/mach/i2c.h b/arch/arm/mach-s5p64x0/i2c.h
index 887d25209e8e..1e5bb4ea200d 100644
--- a/arch/arm/mach-s5p64x0/include/mach/i2c.h
+++ b/arch/arm/mach-s5p64x0/i2c.h
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/i2c.h
- *
+/*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-irq.h b/arch/arm/mach-s5p64x0/include/mach/regs-irq.h
index 4aaebdace55f..d60397d1ff40 100644
--- a/arch/arm/mach-s5p64x0/include/mach/regs-irq.h
+++ b/arch/arm/mach-s5p64x0/include/mach/regs-irq.h
@@ -13,7 +13,6 @@
#ifndef __ASM_ARCH_REGS_IRQ_H
#define __ASM_ARCH_REGS_IRQ_H __FILE__
-#include <asm/hardware/vic.h>
#include <mach/map.h>
#endif /* __ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-s5p64x0/include/mach/tick.h b/arch/arm/mach-s5p64x0/include/mach/tick.h
deleted file mode 100644
index 00aa7f1d8e51..000000000000
--- a/arch/arm/mach-s5p64x0/include/mach/tick.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/tick.h
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * S5P64X0 - Timer tick support definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_TICK_H
-#define __ASM_ARCH_TICK_H __FILE__
-
-static inline u32 s3c24xx_ostimer_pending(void)
-{
- u32 pend = __raw_readl(VA_VIC0 + VIC_RAW_STATUS);
- return pend & (1 << (IRQ_TIMER4_VIC - S5P_IRQ_VIC0(0)));
-}
-
-#define TICK_MAX (0xffffffff)
-
-#endif /* __ASM_ARCH_TICK_H */
diff --git a/arch/arm/mach-s5p64x0/include/mach/uncompress.h b/arch/arm/mach-s5p64x0/include/mach/uncompress.h
index 1608faf870ff..19e0d64d78c5 100644
--- a/arch/arm/mach-s5p64x0/include/mach/uncompress.h
+++ b/arch/arm/mach-s5p64x0/include/mach/uncompress.h
@@ -116,33 +116,6 @@ static inline void flush(void)
*((volatile unsigned int __force *)(ad)) = (d); \
} while (0)
-/*
- * CONFIG_S3C_BOOT_WATCHDOG
- *
- * Simple boot-time watchdog setup, to reboot the system if there is
- * any problem with the boot process
- */
-
-#ifdef CONFIG_S3C_BOOT_WATCHDOG
-
-#define WDOG_COUNT (0xff00)
-
-static inline void arch_decomp_wdog(void)
-{
- __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
-}
-
-static void arch_decomp_wdog_start(void)
-{
- __raw_writel(WDOG_COUNT, S3C2410_WTDAT);
- __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
- __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x80), S3C2410_WTCON);
-}
-
-#else
-#define arch_decomp_wdog_start()
-#define arch_decomp_wdog()
-#endif
#ifdef CONFIG_S3C_BOOT_ERROR_RESET
@@ -192,7 +165,6 @@ static void arch_decomp_setup(void)
*/
arch_detect_cpu();
- arch_decomp_wdog_start();
/*
* Enable the UART FIFOs if they where not enabled and our
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c
index 1af823558c60..e23723a5a214 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6440.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c
@@ -29,7 +29,6 @@
#include <video/platform_lcd.h>
#include <video/samsung_fimd.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/irq.h>
@@ -38,7 +37,6 @@
#include <mach/hardware.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
-#include <mach/i2c.h>
#include <mach/regs-gpio.h>
#include <plat/regs-serial.h>
@@ -56,6 +54,7 @@
#include <plat/sdhci.h>
#include "common.h"
+#include "i2c.h"
#define SMDK6440_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
S3C2410_UCON_RXILEVEL | \
@@ -272,9 +271,8 @@ MACHINE_START(SMDK6440, "SMDK6440")
.atag_offset = 0x100,
.init_irq = s5p6440_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = smdk6440_map_io,
.init_machine = smdk6440_machine_init,
- .timer = &s5p_timer,
+ .init_time = s5p_timer_init,
.restart = s5p64x0_restart,
MACHINE_END
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c
index 62526ccf6b70..ca10963a959e 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6450.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c
@@ -29,7 +29,6 @@
#include <video/platform_lcd.h>
#include <video/samsung_fimd.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/irq.h>
@@ -38,7 +37,6 @@
#include <mach/hardware.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
-#include <mach/i2c.h>
#include <mach/regs-gpio.h>
#include <plat/regs-serial.h>
@@ -56,6 +54,7 @@
#include <plat/sdhci.h>
#include "common.h"
+#include "i2c.h"
#define SMDK6450_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
S3C2410_UCON_RXILEVEL | \
@@ -291,9 +290,8 @@ MACHINE_START(SMDK6450, "SMDK6450")
.atag_offset = 0x100,
.init_irq = s5p6450_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = smdk6450_map_io,
.init_machine = smdk6450_machine_init,
- .timer = &s5p_timer,
+ .init_time = s5p_timer_init,
.restart = s5p64x0_restart,
MACHINE_END
diff --git a/arch/arm/mach-s5p64x0/pm.c b/arch/arm/mach-s5p64x0/pm.c
index 9cba18bfe47b..97c2a08ad490 100644
--- a/arch/arm/mach-s5p64x0/pm.c
+++ b/arch/arm/mach-s5p64x0/pm.c
@@ -103,8 +103,8 @@ static int s5p64x0_cpu_suspend(unsigned long arg)
"mcr p15, 0, %0, c7, c10, 4\n\t"
"mcr p15, 0, %0, c7, c0, 4" : : "r" (tmp));
- /* we should never get past here */
- panic("sleep resumed to originator?");
+ pr_info("Failed to suspend the system\n");
+ return 1; /* Aborting suspend */
}
/* mapping of interrupts to parts of the wakeup mask */
diff --git a/arch/arm/mach-s5p64x0/setup-i2c0.c b/arch/arm/mach-s5p64x0/setup-i2c0.c
index a32edc545e6c..569b76ac98cb 100644
--- a/arch/arm/mach-s5p64x0/setup-i2c0.c
+++ b/arch/arm/mach-s5p64x0/setup-i2c0.c
@@ -21,7 +21,7 @@ struct platform_device; /* don't need the contents */
#include <plat/gpio-cfg.h>
#include <linux/platform_data/i2c-s3c2410.h>
-#include <mach/i2c.h>
+#include "i2c.h"
void s5p6440_i2c0_cfg_gpio(struct platform_device *dev)
{
diff --git a/arch/arm/mach-s5p64x0/setup-i2c1.c b/arch/arm/mach-s5p64x0/setup-i2c1.c
index ca2c5c7f8aa6..867374e6d0bc 100644
--- a/arch/arm/mach-s5p64x0/setup-i2c1.c
+++ b/arch/arm/mach-s5p64x0/setup-i2c1.c
@@ -21,7 +21,7 @@ struct platform_device; /* don't need the contents */
#include <plat/gpio-cfg.h>
#include <linux/platform_data/i2c-s3c2410.h>
-#include <mach/i2c.h>
+#include "i2c.h"
void s5p6440_i2c1_cfg_gpio(struct platform_device *dev)
{
diff --git a/arch/arm/mach-s5pc100/include/mach/regs-irq.h b/arch/arm/mach-s5pc100/include/mach/regs-irq.h
index 4d9036d0f288..761627897f30 100644
--- a/arch/arm/mach-s5pc100/include/mach/regs-irq.h
+++ b/arch/arm/mach-s5pc100/include/mach/regs-irq.h
@@ -14,6 +14,5 @@
#define __ASM_ARCH_REGS_IRQ_H __FILE__
#include <mach/map.h>
-#include <asm/hardware/vic.h>
#endif /* __ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-s5pc100/include/mach/tick.h b/arch/arm/mach-s5pc100/include/mach/tick.h
index 20f68730ed18..0af8e41230ed 100644
--- a/arch/arm/mach-s5pc100/include/mach/tick.h
+++ b/arch/arm/mach-s5pc100/include/mach/tick.h
@@ -15,6 +15,8 @@
#ifndef __ASM_ARCH_TICK_H
#define __ASM_ARCH_TICK_H __FILE__
+#include <linux/irqchip/arm-vic.h>
+
/* note, the timer interrutps turn up in 2 places, the vic and then
* the timer block. We take the VIC as the base at the moment.
*/
diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c
index 9abe95e806ab..185a19583898 100644
--- a/arch/arm/mach-s5pc100/mach-smdkc100.c
+++ b/arch/arm/mach-s5pc100/mach-smdkc100.c
@@ -25,7 +25,6 @@
#include <linux/input.h>
#include <linux/pwm_backlight.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -254,9 +253,8 @@ MACHINE_START(SMDKC100, "SMDKC100")
/* Maintainer: Byungho Min <bhmin@samsung.com> */
.atag_offset = 0x100,
.init_irq = s5pc100_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = smdkc100_map_io,
.init_machine = smdkc100_machine_init,
- .timer = &s3c24xx_timer,
+ .init_time = s3c24xx_timer_init,
.restart = s5pc100_restart,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/dev-audio.c b/arch/arm/mach-s5pv210/dev-audio.c
index addfb165c13d..2d67361ef431 100644
--- a/arch/arm/mach-s5pv210/dev-audio.c
+++ b/arch/arm/mach-s5pv210/dev-audio.c
@@ -18,7 +18,8 @@
#include <mach/map.h>
#include <mach/dma.h>
#include <mach/irqs.h>
-#include <mach/regs-audss.h>
+
+#define S5PV210_AUDSS_INT_MEM (0xC0000000)
static int s5pv210_cfg_i2s(struct platform_device *pdev)
{
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-audss.h b/arch/arm/mach-s5pv210/include/mach/regs-audss.h
deleted file mode 100644
index eacc1f790807..000000000000
--- a/arch/arm/mach-s5pv210/include/mach/regs-audss.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* arch/arm/mach-s5pv210/include/mach/regs-audss.h
- *
- * Copyright (c) 2011 Samsung Electronics
- * http://www.samsung.com
- *
- * S5PV210 Audio SubSystem clock register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __PLAT_REGS_AUDSS_H
-#define __PLAT_REGS_AUDSS_H __FILE__
-
-#define S5PV210_AUDSS_INT_MEM (0xC0000000)
-
-#endif /* _PLAT_REGS_AUDSS_H */
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-irq.h b/arch/arm/mach-s5pv210/include/mach/regs-irq.h
index 5c3b104a7c86..d8bc1e6c7aaa 100644
--- a/arch/arm/mach-s5pv210/include/mach/regs-irq.h
+++ b/arch/arm/mach-s5pv210/include/mach/regs-irq.h
@@ -13,7 +13,6 @@
#ifndef __ASM_ARCH_REGS_IRQ_H
#define __ASM_ARCH_REGS_IRQ_H __FILE__
-#include <asm/hardware/vic.h>
#include <mach/map.h>
#endif /* __ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-sys.h b/arch/arm/mach-s5pv210/include/mach/regs-sys.h
deleted file mode 100644
index cccb1eddaa38..000000000000
--- a/arch/arm/mach-s5pv210/include/mach/regs-sys.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* arch/arm/mach-s5pv210/include/mach/regs-sys.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * S5PV210 - System registers definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#define S5PV210_USB_PHY_CON (S3C_VA_SYS + 0xE80C)
-#define S5PV210_USB_PHY0_EN (1 << 0)
-#define S5PV210_USB_PHY1_EN (1 << 1)
diff --git a/arch/arm/mach-s5pv210/include/mach/tick.h b/arch/arm/mach-s5pv210/include/mach/tick.h
deleted file mode 100644
index 7993b3603ccf..000000000000
--- a/arch/arm/mach-s5pv210/include/mach/tick.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* linux/arch/arm/mach-s5pv210/include/mach/tick.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * Based on arch/arm/mach-s3c6400/include/mach/tick.h
- *
- * S5PV210 - Timer tick support definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_TICK_H
-#define __ASM_ARCH_TICK_H __FILE__
-
-static inline u32 s3c24xx_ostimer_pending(void)
-{
- u32 pend = __raw_readl(VA_VIC0 + VIC_RAW_STATUS);
- return pend & (1 << (IRQ_TIMER4_VIC - S5P_IRQ_VIC0(0)));
-}
-
-#define TICK_MAX (0xffffffff)
-
-#endif /* __ASM_ARCH_TICK_H */
diff --git a/arch/arm/mach-s5pv210/include/mach/uncompress.h b/arch/arm/mach-s5pv210/include/mach/uncompress.h
index 08ff2fda1fb9..ef977ea8546d 100644
--- a/arch/arm/mach-s5pv210/include/mach/uncompress.h
+++ b/arch/arm/mach-s5pv210/include/mach/uncompress.h
@@ -19,6 +19,8 @@
static void arch_detect_cpu(void)
{
/* we do not need to do any cpu detection here at the moment. */
+ fifo_mask = S5PV210_UFSTAT_TXMASK;
+ fifo_max = 63 << S5PV210_UFSTAT_TXSHIFT;
}
#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c
index ee9fa5c2ef2c..11900a8e88a3 100644
--- a/arch/arm/mach-s5pv210/mach-aquila.c
+++ b/arch/arm/mach-s5pv210/mach-aquila.c
@@ -22,7 +22,6 @@
#include <linux/input.h>
#include <linux/gpio.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/setup.h>
@@ -685,9 +684,8 @@ MACHINE_START(AQUILA, "Aquila")
Kyungmin Park <kyungmin.park@samsung.com> */
.atag_offset = 0x100,
.init_irq = s5pv210_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = aquila_map_io,
.init_machine = aquila_machine_init,
- .timer = &s5p_timer,
+ .init_time = s5p_timer_init,
.restart = s5pv210_restart,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index c72b31078c99..3a38f7b34b94 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -29,7 +29,6 @@
#include <linux/interrupt.h>
#include <linux/platform_data/s3c-hsotg.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/setup.h>
@@ -841,12 +840,12 @@ static struct i2c_board_info noon010pc30_board_info = {
.platform_data = &noon010pc30_pldata,
};
-static struct s5p_fimc_isp_info goni_camera_sensors[] = {
+static struct fimc_source_info goni_camera_sensors[] = {
{
.mux_id = 0,
.flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_VSYNC_ACTIVE_LOW,
- .bus_type = FIMC_ITU_601,
+ .bus_type = FIMC_BUS_TYPE_ITU_601,
.board_info = &noon010pc30_board_info,
.i2c_bus_num = 0,
.clk_frequency = 16000000UL,
@@ -854,7 +853,7 @@ static struct s5p_fimc_isp_info goni_camera_sensors[] = {
};
static struct s5p_platform_fimc goni_fimc_md_platdata __initdata = {
- .isp_info = goni_camera_sensors,
+ .source_info = goni_camera_sensors,
.num_clients = ARRAY_SIZE(goni_camera_sensors),
};
@@ -972,10 +971,9 @@ MACHINE_START(GONI, "GONI")
/* Maintainers: Kyungmin Park <kyungmin.park@samsung.com> */
.atag_offset = 0x100,
.init_irq = s5pv210_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = goni_map_io,
.init_machine = goni_machine_init,
- .timer = &s5p_timer,
+ .init_time = s5p_timer_init,
.reserve = &goni_reserve,
.restart = s5pv210_restart,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/mach-smdkc110.c b/arch/arm/mach-s5pv210/mach-smdkc110.c
index f1f3bd37ecda..28bd0248a3e2 100644
--- a/arch/arm/mach-s5pv210/mach-smdkc110.c
+++ b/arch/arm/mach-s5pv210/mach-smdkc110.c
@@ -15,7 +15,6 @@
#include <linux/i2c.h>
#include <linux/device.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/setup.h>
@@ -152,10 +151,9 @@ MACHINE_START(SMDKC110, "SMDKC110")
/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
.atag_offset = 0x100,
.init_irq = s5pv210_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = smdkc110_map_io,
.init_machine = smdkc110_machine_init,
- .timer = &s5p_timer,
+ .init_time = s5p_timer_init,
.restart = s5pv210_restart,
.reserve = &smdkc110_reserve,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
index 6bc8404bf678..3c73f36869bb 100644
--- a/arch/arm/mach-s5pv210/mach-smdkv210.c
+++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
@@ -21,7 +21,6 @@
#include <linux/pwm_backlight.h>
#include <linux/platform_data/s3c-hsotg.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/setup.h>
@@ -328,10 +327,9 @@ MACHINE_START(SMDKV210, "SMDKV210")
/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
.atag_offset = 0x100,
.init_irq = s5pv210_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = smdkv210_map_io,
.init_machine = smdkv210_machine_init,
- .timer = &s5p_timer,
+ .init_time = s5p_timer_init,
.restart = s5pv210_restart,
.reserve = &smdkv210_reserve,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/mach-torbreck.c b/arch/arm/mach-s5pv210/mach-torbreck.c
index 18785cb5e1ef..2d4c5531819c 100644
--- a/arch/arm/mach-s5pv210/mach-torbreck.c
+++ b/arch/arm/mach-s5pv210/mach-torbreck.c
@@ -14,7 +14,6 @@
#include <linux/init.h>
#include <linux/serial_core.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/setup.h>
@@ -129,9 +128,8 @@ MACHINE_START(TORBRECK, "TORBRECK")
/* Maintainer: Hyunchul Ko <ghcstop@gmail.com> */
.atag_offset = 0x100,
.init_irq = s5pv210_init_irq,
- .handle_irq = vic_handle_irq,
.map_io = torbreck_map_io,
.init_machine = torbreck_machine_init,
- .timer = &s5p_timer,
+ .init_time = s5p_timer_init,
.restart = s5pv210_restart,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c
index 736bfb103cbc..2b68a67b6e95 100644
--- a/arch/arm/mach-s5pv210/pm.c
+++ b/arch/arm/mach-s5pv210/pm.c
@@ -104,8 +104,8 @@ static int s5pv210_cpu_suspend(unsigned long arg)
"mcr p15, 0, %0, c7, c10, 4\n\t"
"wfi" : : "r" (tmp));
- /* we should never get past here */
- panic("sleep resumed to originator?");
+ pr_info("Failed to suspend the system\n");
+ return 1; /* Aborting suspend */
}
static void s5pv210_pm_prepare(void)
diff --git a/arch/arm/mach-s5pv210/setup-usb-phy.c b/arch/arm/mach-s5pv210/setup-usb-phy.c
index be39cf4aa91b..356a0900af03 100644
--- a/arch/arm/mach-s5pv210/setup-usb-phy.c
+++ b/arch/arm/mach-s5pv210/setup-usb-phy.c
@@ -12,12 +12,17 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+
#include <mach/map.h>
-#include <mach/regs-sys.h>
+
#include <plat/cpu.h>
#include <plat/regs-usb-hsotg-phy.h>
#include <plat/usb-phy.h>
+#define S5PV210_USB_PHY_CON (S3C_VA_SYS + 0xE80C)
+#define S5PV210_USB_PHY0_EN (1 << 0)
+#define S5PV210_USB_PHY1_EN (1 << 1)
+
static int s5pv210_usb_otgphy_init(struct platform_device *pdev)
{
struct clk *xusbxti;
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 9a23739f7026..e838ba27e443 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -16,6 +16,7 @@
#include <linux/ioport.h>
#include <linux/platform_data/sa11x0-serial.h>
#include <linux/serial_core.h>
+#include <linux/platform_device.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -621,7 +622,7 @@ MACHINE_START(ASSABET, "Intel-Assabet")
.map_io = assabet_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.init_machine = assabet_init,
.init_late = sa11x0_init_late,
#ifdef CONFIG_SA1111
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index b2dadf3ea3df..63361b6d04e9 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -336,7 +336,7 @@ MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.init_late = sa11x0_init_late,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
#ifdef CONFIG_SA1111
.dma_zone_size = SZ_1M,
#endif
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index 304bca4a07c0..2d25ececb415 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -174,7 +174,7 @@ MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
.map_io = cerf_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = cerf_init_irq,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.init_machine = cerf_init,
.init_late = sa11x0_init_late,
.restart = sa11x0_restart,
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index 45f424f5fca6..612a45689770 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -399,7 +399,7 @@ MACHINE_START(COLLIE, "Sharp-Collie")
.map_io = collie_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.init_machine = collie_init,
.init_late = sa11x0_init_late,
.restart = sa11x0_restart,
diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h
index a5b7c13da3e3..2abc6a1f6e86 100644
--- a/arch/arm/mach-sa1100/generic.h
+++ b/arch/arm/mach-sa1100/generic.h
@@ -4,9 +4,7 @@
* Author: Nicolas Pitre
*/
-struct sys_timer;
-
-extern struct sys_timer sa1100_timer;
+extern void sa1100_timer_init(void);
extern void __init sa1100_map_io(void);
extern void __init sa1100_init_irq(void);
extern void __init sa1100_init_gpio(void);
diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c
index e1571eab08ae..b8f2b151539b 100644
--- a/arch/arm/mach-sa1100/h3100.c
+++ b/arch/arm/mach-sa1100/h3100.c
@@ -108,7 +108,7 @@ MACHINE_START(H3100, "Compaq iPAQ H3100")
.map_io = h3100_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.init_machine = h3100_mach_init,
.init_late = sa11x0_init_late,
.restart = sa11x0_restart,
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index ba7a2901ab88..b8dc5bd22623 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -158,7 +158,7 @@ MACHINE_START(H3600, "Compaq iPAQ H3600")
.map_io = h3600_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.init_machine = h3600_mach_init,
.init_late = sa11x0_init_late,
.restart = sa11x0_restart,
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index d005939c41fc..643d5f2d9af9 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -229,7 +229,7 @@ MACHINE_START(HACKKIT, "HackKit Cpu Board")
.map_io = hackkit_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.init_machine = hackkit_init,
.init_late = sa11x0_init_late,
.restart = sa11x0_restart,
diff --git a/arch/arm/mach-sa1100/include/mach/uncompress.h b/arch/arm/mach-sa1100/include/mach/uncompress.h
index 5cf71da60e42..73093dc89829 100644
--- a/arch/arm/mach-sa1100/include/mach/uncompress.h
+++ b/arch/arm/mach-sa1100/include/mach/uncompress.h
@@ -49,4 +49,3 @@ static inline void flush(void)
* Nothing to do for these
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index 35cfc428b4d4..c0b1f5bafae4 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -346,7 +346,7 @@ MACHINE_START(JORNADA720, "HP Jornada 720")
.map_io = jornada720_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.init_machine = jornada720_mach_init,
.init_late = sa11x0_init_late,
#ifdef CONFIG_SA1111
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index f69f78fc3ddd..51b0eb52c014 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -24,9 +24,6 @@
#include "generic.h"
-
-#warning "include/asm/arch-sa1100/ide.h needs fixing for lart"
-
static struct mcp_plat_data lart_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
@@ -174,6 +171,6 @@ MACHINE_START(LART, "LART")
.init_irq = sa1100_init_irq,
.init_machine = lart_init,
.init_late = sa11x0_init_late,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.restart = sa11x0_restart,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c
index 102e08f7b109..f1cb3784d525 100644
--- a/arch/arm/mach-sa1100/nanoengine.c
+++ b/arch/arm/mach-sa1100/nanoengine.c
@@ -110,7 +110,7 @@ MACHINE_START(NANOENGINE, "BSE nanoEngine")
.map_io = nanoengine_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.init_machine = nanoengine_init,
.init_late = sa11x0_init_late,
.restart = sa11x0_restart,
diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c
index c51bb63f90fb..091261878eff 100644
--- a/arch/arm/mach-sa1100/pleb.c
+++ b/arch/arm/mach-sa1100/pleb.c
@@ -133,7 +133,7 @@ MACHINE_START(PLEB, "PLEB")
.map_io = pleb_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.init_machine = pleb_init,
.init_late = sa11x0_init_late,
.restart = sa11x0_restart,
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index 6460d25fbb88..c8866bce7386 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -102,7 +102,7 @@ MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
.map_io = shannon_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.init_machine = shannon_init,
.init_late = sa11x0_init_late,
.restart = sa11x0_restart,
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index 6d65f65fcb23..bcbc94540e45 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -396,6 +396,6 @@ MACHINE_START(SIMPAD, "Simpad")
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.init_late = sa11x0_init_late,
- .timer = &sa1100_timer,
+ .init_time = sa1100_timer_init,
.restart = sa11x0_restart,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 80702c9ecc77..a59a13a665a6 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -69,46 +69,10 @@ 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,
- .rating = 200,
- .set_next_event = sa1100_osmr0_set_next_event,
- .set_mode = sa1100_osmr0_set_mode,
-};
-
-static struct irqaction sa1100_timer_irq = {
- .name = "ost0",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = sa1100_ost0_interrupt,
- .dev_id = &ckevt_sa1100_osmr0,
-};
-
-static void __init sa1100_timer_init(void)
-{
- writel_relaxed(0, OIER);
- writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
-
- setup_sched_clock(sa1100_read_sched_clock, 32, 3686400);
-
- 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 =
- clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_sa1100_osmr0) + 1;
- ckevt_sa1100_osmr0.cpumask = cpumask_of(0);
-
- setup_irq(IRQ_OST0, &sa1100_timer_irq);
-
- clocksource_mmio_init(OSCR, "oscr", CLOCK_TICK_RATE, 200, 32,
- clocksource_mmio_readl_up);
- clockevents_register_device(&ckevt_sa1100_osmr0);
-}
-
#ifdef CONFIG_PM
unsigned long osmr[4], oier;
-static void sa1100_timer_suspend(void)
+static void sa1100_timer_suspend(struct clock_event_device *cedev)
{
osmr[0] = readl_relaxed(OSMR0);
osmr[1] = readl_relaxed(OSMR1);
@@ -117,7 +81,7 @@ static void sa1100_timer_suspend(void)
oier = readl_relaxed(OIER);
}
-static void sa1100_timer_resume(void)
+static void sa1100_timer_resume(struct clock_event_device *cedev)
{
writel_relaxed(0x0f, OSSR);
writel_relaxed(osmr[0], OSMR0);
@@ -136,8 +100,36 @@ static void sa1100_timer_resume(void)
#define sa1100_timer_resume NULL
#endif
-struct sys_timer sa1100_timer = {
- .init = sa1100_timer_init,
+static struct clock_event_device ckevt_sa1100_osmr0 = {
+ .name = "osmr0",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 200,
+ .set_next_event = sa1100_osmr0_set_next_event,
+ .set_mode = sa1100_osmr0_set_mode,
.suspend = sa1100_timer_suspend,
.resume = sa1100_timer_resume,
};
+
+static struct irqaction sa1100_timer_irq = {
+ .name = "ost0",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = sa1100_ost0_interrupt,
+ .dev_id = &ckevt_sa1100_osmr0,
+};
+
+void __init sa1100_timer_init(void)
+{
+ writel_relaxed(0, OIER);
+ writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
+
+ setup_sched_clock(sa1100_read_sched_clock, 32, 3686400);
+
+ ckevt_sa1100_osmr0.cpumask = cpumask_of(0);
+
+ setup_irq(IRQ_OST0, &sa1100_timer_irq);
+
+ clocksource_mmio_init(OSCR, "oscr", CLOCK_TICK_RATE, 200, 32,
+ clocksource_mmio_readl_up);
+ clockevents_config_and_register(&ckevt_sa1100_osmr0, 3686400,
+ MIN_OSCR_DELTA * 2, 0x7fffffff);
+}
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 9ad2e9737fb5..b63dec848195 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -128,10 +128,6 @@ static void __init shark_timer_init(void)
setup_irq(IRQ_TIMER, &shark_timer_irq);
}
-static struct sys_timer shark_timer = {
- .init = shark_timer_init,
-};
-
static void shark_init_early(void)
{
disable_hlt();
@@ -142,7 +138,7 @@ MACHINE_START(SHARK, "Shark")
.atag_offset = 0x3000,
.init_early = shark_init_early,
.init_irq = shark_init_irq,
- .timer = &shark_timer,
+ .init_time = shark_timer_init,
.dma_zone_size = SZ_4M,
.restart = shark_restart,
MACHINE_END
diff --git a/arch/arm/mach-shark/include/mach/uncompress.h b/arch/arm/mach-shark/include/mach/uncompress.h
index 22ccab4c3c5e..a168435aecc9 100644
--- a/arch/arm/mach-shark/include/mach/uncompress.h
+++ b/arch/arm/mach-shark/include/mach/uncompress.h
@@ -48,4 +48,3 @@ static void putr()
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index 0b7147928aa3..e1fac57514b9 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -15,17 +15,10 @@ obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o clock-emev2.o
# SMP objects
smp-y := platsmp.o headsmp.o
smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o
+smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o headsmp-sh73a0.o
smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o
smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o
-# Pinmux setup
-pfc-y :=
-pfc-$(CONFIG_ARCH_SH7372) += pfc-sh7372.o
-pfc-$(CONFIG_ARCH_SH73A0) += pfc-sh73a0.o
-pfc-$(CONFIG_ARCH_R8A7740) += pfc-r8a7740.o
-pfc-$(CONFIG_ARCH_R8A7779) += pfc-r8a7779.o
-
# IRQ objects
obj-$(CONFIG_ARCH_SH7372) += entry-intc.o
obj-$(CONFIG_ARCH_R8A7740) += entry-intc.o
@@ -37,6 +30,7 @@ obj-$(CONFIG_ARCH_SHMOBILE) += pm-rmobile.o
obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o
obj-$(CONFIG_ARCH_R8A7740) += pm-r8a7740.o
obj-$(CONFIG_ARCH_R8A7779) += pm-r8a7779.o
+obj-$(CONFIG_ARCH_SH73A0) += pm-sh73a0.o
# Board objects
obj-$(CONFIG_MACH_AP4EVB) += board-ap4evb.o
@@ -51,4 +45,3 @@ obj-$(CONFIG_MACH_KZM9G) += board-kzm9g.o
# Framework support
obj-$(CONFIG_SMP) += $(smp-y)
-obj-$(CONFIG_GENERIC_GPIO) += $(pfc-y)
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index 032d10817e79..8ff53a19c48c 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -40,6 +40,7 @@
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mfd/tmio.h>
#include <linux/sh_clk.h>
+#include <linux/irqchip/arm-gic.h>
#include <video/sh_mobile_lcdc.h>
#include <video/sh_mipi_dsi.h>
#include <sound/sh_fsi.h>
@@ -49,7 +50,6 @@
#include <mach/common.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/traps.h>
@@ -479,11 +479,10 @@ static void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state)
static int power_gpio = -EINVAL;
if (power_gpio < 0) {
- int ret = gpio_request(GPIO_PORT114, "sdhi1_power");
- if (!ret) {
+ int ret = gpio_request_one(GPIO_PORT114, GPIOF_OUT_INIT_LOW,
+ "sdhi1_power");
+ if (!ret)
power_gpio = GPIO_PORT114;
- gpio_direction_output(power_gpio, 0);
- }
}
/*
@@ -604,14 +603,11 @@ static void __init ag5evm_init(void)
gpio_request(GPIO_FN_MMCD0_5_PU, NULL);
gpio_request(GPIO_FN_MMCD0_6_PU, NULL);
gpio_request(GPIO_FN_MMCD0_7_PU, NULL);
- gpio_request(GPIO_PORT208, NULL); /* Reset */
- gpio_direction_output(GPIO_PORT208, 1);
+ gpio_request_one(GPIO_PORT208, GPIOF_OUT_INIT_HIGH, NULL); /* Reset */
/* enable SMSC911X */
- gpio_request(GPIO_PORT144, NULL); /* PINTA2 */
- gpio_direction_input(GPIO_PORT144);
- gpio_request(GPIO_PORT145, NULL); /* RESET */
- gpio_direction_output(GPIO_PORT145, 1);
+ gpio_request_one(GPIO_PORT144, GPIOF_IN, NULL); /* PINTA2 */
+ gpio_request_one(GPIO_PORT145, GPIOF_OUT_INIT_HIGH, NULL); /* RESET */
/* FSI A */
gpio_request(GPIO_FN_FSIACK, NULL);
@@ -626,15 +622,13 @@ static void __init ag5evm_init(void)
gpio_request(GPIO_FN_PORT243_IRDA_FIRSEL, NULL);
/* LCD panel */
- gpio_request(GPIO_PORT217, NULL); /* RESET */
- gpio_direction_output(GPIO_PORT217, 0);
+ gpio_request_one(GPIO_PORT217, GPIOF_OUT_INIT_LOW, NULL); /* RESET */
mdelay(1);
gpio_set_value(GPIO_PORT217, 1);
mdelay(100);
/* LCD backlight controller */
- gpio_request(GPIO_PORT235, NULL); /* RESET */
- gpio_direction_output(GPIO_PORT235, 0);
+ gpio_request_one(GPIO_PORT235, GPIOF_OUT_INIT_LOW, NULL); /* RESET */
lcd_backlight_set_brightness(0);
/* enable SDHI0 on CN15 [SD I/F] */
@@ -668,8 +662,7 @@ MACHINE_START(AG5EVM, "ag5evm")
.init_early = sh73a0_add_early_devices,
.nr_irqs = NR_IRQS_LEGACY,
.init_irq = sh73a0_init_irq,
- .handle_irq = gic_handle_irq,
.init_machine = ag5evm_init,
.init_late = shmobile_init_late,
- .timer = &shmobile_timer,
+ .init_time = sh73a0_earlytimer_init,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index 99ef190d0909..38f1259a0daf 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -143,6 +143,10 @@
*
* SW41 : ON : SH-Mobile AP4 Audio Mode
* : OFF : Bluetooth Audio Mode
+ *
+ * it needs amixer settings for playing
+ *
+ * amixer set "Headphone Enable" on
*/
/*
@@ -657,14 +661,8 @@ static struct platform_device lcdc_device = {
/* FSI */
#define IRQ_FSI evt2irq(0x1840)
static struct sh_fsi_platform_info fsi_info = {
- .port_a = {
- .flags = SH_FSI_BRS_INV,
- },
.port_b = {
- .flags = SH_FSI_BRS_INV |
- SH_FSI_BRM_INV |
- SH_FSI_LRS_INV |
- SH_FSI_CLK_CPG |
+ .flags = SH_FSI_CLK_CPG |
SH_FSI_FMT_SPDIF,
},
};
@@ -692,21 +690,21 @@ static struct platform_device fsi_device = {
},
};
-static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
- .fmt = SND_SOC_DAIFMT_LEFT_J,
- .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
- .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
- .sysclk = 11289600,
-};
-
static struct asoc_simple_card_info fsi2_ak4643_info = {
.name = "AK4643",
.card = "FSI2A-AK4643",
- .cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi2",
- .codec_dai = "ak4642-hifi",
- .init = &fsi2_ak4643_init_info,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .cpu_dai = {
+ .name = "fsia-dai",
+ .fmt = SND_SOC_DAIFMT_CBS_CFS,
+ },
+ .codec_dai = {
+ .name = "ak4642-hifi",
+ .fmt = SND_SOC_DAIFMT_CBM_CFM,
+ .sysclk = 11289600,
+ },
};
static struct platform_device fsi_ak4643_device = {
@@ -815,18 +813,18 @@ static struct platform_device lcdc1_device = {
},
};
-static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
- .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM,
-};
-
static struct asoc_simple_card_info fsi2_hdmi_info = {
.name = "HDMI",
.card = "FSI2B-HDMI",
- .cpu_dai = "fsib-dai",
.codec = "sh-mobile-hdmi",
.platform = "sh_fsi2",
- .codec_dai = "sh_mobile_hdmi-hifi",
- .init = &fsi2_hdmi_init_info,
+ .cpu_dai = {
+ .name = "fsib-dai",
+ .fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF,
+ },
+ .codec_dai = {
+ .name = "sh_mobile_hdmi-hifi",
+ },
};
static struct platform_device fsi_hdmi_device = {
@@ -1042,9 +1040,7 @@ static int ts_get_pendown_state(void)
gpio_free(GPIO_TSC_IRQ);
- gpio_request(GPIO_TSC_PORT, NULL);
-
- gpio_direction_input(GPIO_TSC_PORT);
+ gpio_request_one(GPIO_TSC_PORT, GPIOF_IN, NULL);
val = gpio_get_value(GPIO_TSC_PORT);
@@ -1125,18 +1121,10 @@ static void __init ap4evb_init(void)
gpio_request(GPIO_FN_IRQ6_39, NULL);
/* enable Debug switch (S6) */
- gpio_request(GPIO_PORT32, NULL);
- gpio_request(GPIO_PORT33, NULL);
- gpio_request(GPIO_PORT34, NULL);
- gpio_request(GPIO_PORT35, NULL);
- gpio_direction_input(GPIO_PORT32);
- gpio_direction_input(GPIO_PORT33);
- gpio_direction_input(GPIO_PORT34);
- gpio_direction_input(GPIO_PORT35);
- gpio_export(GPIO_PORT32, 0);
- gpio_export(GPIO_PORT33, 0);
- gpio_export(GPIO_PORT34, 0);
- gpio_export(GPIO_PORT35, 0);
+ gpio_request_one(GPIO_PORT32, GPIOF_IN | GPIOF_EXPORT, NULL);
+ gpio_request_one(GPIO_PORT33, GPIOF_IN | GPIOF_EXPORT, NULL);
+ gpio_request_one(GPIO_PORT34, GPIOF_IN | GPIOF_EXPORT, NULL);
+ gpio_request_one(GPIO_PORT35, GPIOF_IN | GPIOF_EXPORT, NULL);
/* SDHI0 */
gpio_request(GPIO_FN_SDHICD0, NULL);
@@ -1184,8 +1172,7 @@ static void __init ap4evb_init(void)
gpio_request(GPIO_FN_FSIAILR, NULL);
gpio_request(GPIO_FN_FSIAISLD, NULL);
gpio_request(GPIO_FN_FSIAOSLD, NULL);
- gpio_request(GPIO_PORT161, NULL);
- gpio_direction_output(GPIO_PORT161, 0); /* slave */
+ gpio_request_one(GPIO_PORT161, GPIOF_OUT_INIT_LOW, NULL); /* slave */
gpio_request(GPIO_PORT9, NULL);
gpio_request(GPIO_PORT10, NULL);
@@ -1193,8 +1180,7 @@ static void __init ap4evb_init(void)
gpio_direction_none(GPIO_PORT10CR); /* FSIAOLR needs no direction */
/* card detect pin for MMC slot (CN7) */
- gpio_request(GPIO_PORT41, NULL);
- gpio_direction_input(GPIO_PORT41);
+ gpio_request_one(GPIO_PORT41, GPIOF_IN, NULL);
/* setup FSI2 port B (HDMI) */
gpio_request(GPIO_FN_FSIBCK, NULL);
@@ -1282,11 +1268,8 @@ static void __init ap4evb_init(void)
gpio_request(GPIO_FN_LCDDISP, NULL);
gpio_request(GPIO_FN_LCDDCK, NULL);
- gpio_request(GPIO_PORT189, NULL); /* backlight */
- gpio_direction_output(GPIO_PORT189, 1);
-
- gpio_request(GPIO_PORT151, NULL); /* LCDDON */
- gpio_direction_output(GPIO_PORT151, 1);
+ gpio_request_one(GPIO_PORT189, GPIOF_OUT_INIT_HIGH, NULL); /* backlight */
+ gpio_request_one(GPIO_PORT151, GPIOF_OUT_INIT_HIGH, NULL); /* LCDDON */
lcdc_info.clock_source = LCDC_CLK_BUS;
lcdc_info.ch[0].interface_type = RGB18;
@@ -1350,5 +1333,5 @@ MACHINE_START(AP4EVB, "ap4evb")
.handle_irq = shmobile_handle_irq_intc,
.init_machine = ap4evb_init,
.init_late = sh7372_pm_init_late,
- .timer = &shmobile_timer,
+ .init_time = sh7372_earlytimer_init,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index 5353adf6b828..f2ec0777cfbe 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -124,6 +124,14 @@
* this command is required when playback.
*
* # amixer set "Headphone" 50
+ *
+ * this command is required when capture.
+ *
+ * # amixer set "Input PGA" 15
+ * # amixer set "Left Input Mixer MicP" on
+ * # amixer set "Left Input Mixer MicN" on
+ * # amixer set "Right Input Mixer MicN" on
+ * # amixer set "Right Input Mixer MicP" on
*/
/*
@@ -700,9 +708,9 @@ static int mt9t111_power(struct device *dev, int mode)
/* video1 (= CON1 camera) expect 24MHz */
clk_set_rate(mclk, clk_round_rate(mclk, 24000000));
clk_enable(mclk);
- gpio_direction_output(GPIO_PORT158, 1);
+ gpio_set_value(GPIO_PORT158, 1);
} else {
- gpio_direction_output(GPIO_PORT158, 0);
+ gpio_set_value(GPIO_PORT158, 0);
clk_disable(mclk);
}
@@ -806,21 +814,21 @@ static struct platform_device fsi_device = {
};
/* FSI-WM8978 */
-static struct asoc_simple_dai_init_info fsi_wm8978_init_info = {
- .fmt = SND_SOC_DAIFMT_I2S,
- .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
- .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
- .sysclk = 12288000,
-};
-
static struct asoc_simple_card_info fsi_wm8978_info = {
.name = "wm8978",
.card = "FSI2A-WM8978",
- .cpu_dai = "fsia-dai",
.codec = "wm8978.0-001a",
.platform = "sh_fsi2",
- .codec_dai = "wm8978-hifi",
- .init = &fsi_wm8978_init_info,
+ .daifmt = SND_SOC_DAIFMT_I2S,
+ .cpu_dai = {
+ .name = "fsia-dai",
+ .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
+ },
+ .codec_dai = {
+ .name = "wm8978-hifi",
+ .fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
+ .sysclk = 12288000,
+ },
};
static struct platform_device fsi_wm8978_device = {
@@ -832,18 +840,18 @@ static struct platform_device fsi_wm8978_device = {
};
/* FSI-HDMI */
-static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
- .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM,
-};
-
static struct asoc_simple_card_info fsi2_hdmi_info = {
.name = "HDMI",
.card = "FSI2B-HDMI",
- .cpu_dai = "fsib-dai",
.codec = "sh-mobile-hdmi",
.platform = "sh_fsi2",
- .codec_dai = "sh_mobile_hdmi-hifi",
- .init = &fsi2_hdmi_init_info,
+ .cpu_dai = {
+ .name = "fsib-dai",
+ .fmt = SND_SOC_DAIFMT_CBM_CFM,
+ },
+ .codec_dai = {
+ .name = "sh_mobile_hdmi-hifi",
+ },
};
static struct platform_device fsi_hdmi_device = {
@@ -992,16 +1000,12 @@ static void __init eva_init(void)
gpio_request(GPIO_FN_LCD0_DISP, NULL);
gpio_request(GPIO_FN_LCD0_LCLK_PORT165, NULL);
- gpio_request(GPIO_PORT61, NULL); /* LCDDON */
- gpio_direction_output(GPIO_PORT61, 1);
-
- gpio_request(GPIO_PORT202, NULL); /* LCD0_LED_CONT */
- gpio_direction_output(GPIO_PORT202, 0);
+ gpio_request_one(GPIO_PORT61, GPIOF_OUT_INIT_HIGH, NULL); /* LCDDON */
+ gpio_request_one(GPIO_PORT202, GPIOF_OUT_INIT_LOW, NULL); /* LCD0_LED_CONT */
/* Touchscreen */
gpio_request(GPIO_FN_IRQ10, NULL); /* TP_INT */
- gpio_request(GPIO_PORT166, NULL); /* TP_RST_B */
- gpio_direction_output(GPIO_PORT166, 1);
+ gpio_request_one(GPIO_PORT166, GPIOF_OUT_INIT_HIGH, NULL); /* TP_RST_B */
/* GETHER */
gpio_request(GPIO_FN_ET_CRS, NULL);
@@ -1024,12 +1028,10 @@ static void __init eva_init(void)
gpio_request(GPIO_FN_ET_RX_DV, NULL);
gpio_request(GPIO_FN_ET_RX_CLK, NULL);
- gpio_request(GPIO_PORT18, NULL); /* PHY_RST */
- gpio_direction_output(GPIO_PORT18, 1);
+ gpio_request_one(GPIO_PORT18, GPIOF_OUT_INIT_HIGH, NULL); /* PHY_RST */
/* USB */
- gpio_request(GPIO_PORT159, NULL); /* USB_DEVICE_MODE */
- gpio_direction_input(GPIO_PORT159);
+ gpio_request_one(GPIO_PORT159, GPIOF_IN, NULL); /* USB_DEVICE_MODE */
if (gpio_get_value(GPIO_PORT159)) {
/* USB Host */
@@ -1043,8 +1045,7 @@ static void __init eva_init(void)
* and select GPIO_PORT209 here
*/
gpio_request(GPIO_FN_IRQ7_PORT209, NULL);
- gpio_request(GPIO_PORT209, NULL);
- gpio_direction_input(GPIO_PORT209);
+ gpio_request_one(GPIO_PORT209, GPIOF_IN, NULL);
platform_device_register(&usbhsf_device);
usb = &usbhsf_device;
@@ -1059,12 +1060,9 @@ static void __init eva_init(void)
gpio_request(GPIO_FN_SDHI0_D3, NULL);
gpio_request(GPIO_FN_SDHI0_WP, NULL);
- gpio_request(GPIO_PORT17, NULL); /* SDHI0_18/33_B */
- gpio_request(GPIO_PORT74, NULL); /* SDHI0_PON */
- gpio_request(GPIO_PORT75, NULL); /* SDSLOT1_PON */
- gpio_direction_output(GPIO_PORT17, 0);
- gpio_direction_output(GPIO_PORT74, 1);
- gpio_direction_output(GPIO_PORT75, 1);
+ gpio_request_one(GPIO_PORT17, GPIOF_OUT_INIT_LOW, NULL); /* SDHI0_18/33_B */
+ gpio_request_one(GPIO_PORT74, GPIOF_OUT_INIT_HIGH, NULL); /* SDHI0_PON */
+ gpio_request_one(GPIO_PORT75, GPIOF_OUT_INIT_HIGH, NULL); /* SDSLOT1_PON */
/* we can use GPIO_FN_IRQ31_PORT167 here for SDHI0 CD irq */
@@ -1101,12 +1099,10 @@ static void __init eva_init(void)
gpio_request(GPIO_FN_VIO_CKO, NULL);
/* CON1/CON15 Camera */
- gpio_request(GPIO_PORT173, NULL); /* STANDBY */
- gpio_request(GPIO_PORT172, NULL); /* RST */
- gpio_request(GPIO_PORT158, NULL); /* CAM_PON */
- gpio_direction_output(GPIO_PORT173, 0);
- gpio_direction_output(GPIO_PORT172, 1);
- gpio_direction_output(GPIO_PORT158, 0); /* see mt9t111_power() */
+ gpio_request_one(GPIO_PORT173, GPIOF_OUT_INIT_LOW, NULL); /* STANDBY */
+ gpio_request_one(GPIO_PORT172, GPIOF_OUT_INIT_HIGH, NULL); /* RST */
+ /* see mt9t111_power() */
+ gpio_request_one(GPIO_PORT158, GPIOF_OUT_INIT_LOW, NULL); /* CAM_PON */
/* FSI-WM8978 */
gpio_request(GPIO_FN_FSIAIBT, NULL);
@@ -1133,15 +1129,13 @@ static void __init eva_init(void)
* DBGMD/LCDC0/FSIA MUX
* DBGMD_SELECT_B should be set after setting PFC Function.
*/
- gpio_request(GPIO_PORT176, NULL);
- gpio_direction_output(GPIO_PORT176, 1);
+ gpio_request_one(GPIO_PORT176, GPIOF_OUT_INIT_HIGH, NULL);
/*
* We can switch CON8/CON14 by SW1.5,
* but it needs after DBGMD_SELECT_B
*/
- gpio_request(GPIO_PORT6, NULL);
- gpio_direction_input(GPIO_PORT6);
+ gpio_request_one(GPIO_PORT6, GPIOF_IN, NULL);
if (gpio_get_value(GPIO_PORT6)) {
/* CON14 enable */
} else {
@@ -1155,8 +1149,8 @@ static void __init eva_init(void)
gpio_request(GPIO_FN_SDHI1_CD, NULL);
gpio_request(GPIO_FN_SDHI1_WP, NULL);
- gpio_request(GPIO_PORT16, NULL); /* SDSLOT2_PON */
- gpio_direction_output(GPIO_PORT16, 1);
+ /* SDSLOT2_PON */
+ gpio_request_one(GPIO_PORT16, GPIOF_OUT_INIT_HIGH, NULL);
platform_device_register(&sdhi1_device);
}
@@ -1175,26 +1169,26 @@ static void __init eva_init(void)
platform_add_devices(eva_devices,
ARRAY_SIZE(eva_devices));
- eva_clock_init();
-
rmobile_add_device_to_domain("A4LC", &lcdc0_device);
rmobile_add_device_to_domain("A4LC", &hdmi_lcdc_device);
if (usb)
rmobile_add_device_to_domain("A3SP", usb);
+
+ r8a7740_pm_init();
}
static void __init eva_earlytimer_init(void)
{
r8a7740_clock_init(MD_CK0 | MD_CK2);
shmobile_earlytimer_init();
+
+ /* the rate of extal1 clock must be set before late_time_init */
+ eva_clock_init();
}
static void __init eva_add_early_devices(void)
{
r8a7740_add_early_devices();
-
- /* override timer setup with board-specific code */
- shmobile_timer.init = eva_earlytimer_init;
}
#define RESCNT2 IOMEM(0xe6188020)
@@ -1216,7 +1210,7 @@ DT_MACHINE_START(ARMADILLO800EVA_DT, "armadillo800eva")
.handle_irq = shmobile_handle_irq_intc,
.init_machine = eva_init,
.init_late = shmobile_init_late,
- .timer = &shmobile_timer,
+ .init_time = eva_earlytimer_init,
.dt_compat = eva_boards_compat_dt,
.restart = eva_restart,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index cb8c994e1430..e50f86691539 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -392,8 +392,7 @@ static void __init bonito_init(void)
/*
* base board settings
*/
- gpio_request(GPIO_PORT176, NULL);
- gpio_direction_input(GPIO_PORT176);
+ gpio_request_one(GPIO_PORT176, GPIOF_IN, NULL);
if (!gpio_get_value(GPIO_PORT176)) {
u16 bsw2;
u16 bsw3;
@@ -462,8 +461,8 @@ static void __init bonito_init(void)
gpio_request(GPIO_FN_LCD0_DISP, NULL);
gpio_request(GPIO_FN_LCD0_LCLK_PORT165, NULL);
- gpio_request(GPIO_PORT61, NULL); /* LCDDON */
- gpio_direction_output(GPIO_PORT61, 1);
+ gpio_request_one(GPIO_PORT61, GPIOF_OUT_INIT_HIGH,
+ NULL); /* LCDDON */
/* backlight on */
bonito_fpga_write(LCDCR, 1);
@@ -499,9 +498,6 @@ static void __init bonito_earlytimer_init(void)
static void __init bonito_add_early_devices(void)
{
r8a7740_add_early_devices();
-
- /* override timer setup with board-specific code */
- shmobile_timer.init = bonito_earlytimer_init;
}
MACHINE_START(BONITO, "bonito")
@@ -511,5 +507,5 @@ MACHINE_START(BONITO, "bonito")
.handle_irq = shmobile_handle_irq_intc,
.init_machine = bonito_init,
.init_late = shmobile_init_late,
- .timer = &shmobile_timer,
+ .init_time = bonito_earlytimer_init,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c
index bf88f9a8b7ac..2ccc860403ef 100644
--- a/arch/arm/mach-shmobile/board-kota2.c
+++ b/arch/arm/mach-shmobile/board-kota2.c
@@ -35,6 +35,7 @@
#include <linux/input/sh_keysc.h>
#include <linux/gpio_keys.h>
#include <linux/leds.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/leds-renesas-tpu.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sh_mmcif.h>
@@ -47,7 +48,6 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/traps.h>
@@ -474,10 +474,8 @@ static void __init kota2_init(void)
gpio_request(GPIO_FN_D15_NAF15, NULL);
gpio_request(GPIO_FN_CS5A_, NULL);
gpio_request(GPIO_FN_WE0__FWE, NULL);
- gpio_request(GPIO_PORT144, NULL); /* PINTA2 */
- gpio_direction_input(GPIO_PORT144);
- gpio_request(GPIO_PORT145, NULL); /* RESET */
- gpio_direction_output(GPIO_PORT145, 1);
+ gpio_request_one(GPIO_PORT144, GPIOF_IN, NULL); /* PINTA2 */
+ gpio_request_one(GPIO_PORT145, GPIOF_OUT_INIT_HIGH, NULL); /* RESET */
/* KEYSC */
gpio_request(GPIO_FN_KEYIN0_PU, NULL);
@@ -509,8 +507,7 @@ static void __init kota2_init(void)
gpio_request(GPIO_FN_MMCD0_6, NULL);
gpio_request(GPIO_FN_MMCD0_7, NULL);
gpio_request(GPIO_FN_MMCCMD0, NULL);
- gpio_request(GPIO_PORT208, NULL); /* Reset */
- gpio_direction_output(GPIO_PORT208, 1);
+ gpio_request_one(GPIO_PORT208, GPIOF_OUT_INIT_HIGH, NULL); /* Reset */
/* SDHI0 (microSD) */
gpio_request(GPIO_FN_SDHICD0_PU, NULL);
@@ -550,8 +547,7 @@ MACHINE_START(KOTA2, "kota2")
.init_early = sh73a0_add_early_devices,
.nr_irqs = NR_IRQS_LEGACY,
.init_irq = sh73a0_init_irq,
- .handle_irq = gic_handle_irq,
.init_machine = kota2_init,
.init_late = shmobile_init_late,
- .timer = &shmobile_timer,
+ .init_time = sh73a0_earlytimer_init,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c
index b52bc0d1273f..c254782aa727 100644
--- a/arch/arm/mach-shmobile/board-kzm9d.c
+++ b/arch/arm/mach-shmobile/board-kzm9d.c
@@ -28,7 +28,6 @@
#include <mach/emev2.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
/* Dummy supplies, where voltage doesn't matter */
static struct regulator_consumer_supply dummy_supplies[] = {
@@ -89,9 +88,8 @@ DT_MACHINE_START(KZM9D_DT, "kzm9d")
.init_early = emev2_add_early_devices,
.nr_irqs = NR_IRQS_LEGACY,
.init_irq = emev2_init_irq,
- .handle_irq = gic_handle_irq,
.init_machine = kzm9d_add_standard_devices,
.init_late = shmobile_init_late,
- .timer = &shmobile_timer,
+ .init_time = shmobile_timer_init,
.dt_compat = kzm9d_boards_compat_dt,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index c02448d6847f..7f3a6b7e7b7c 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -25,6 +25,7 @@
#include <linux/i2c.h>
#include <linux/i2c/pcf857x.h>
#include <linux/input.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sh_mmcif.h>
#include <linux/mmc/sh_mobile_sdhi.h>
@@ -42,7 +43,6 @@
#include <mach/sh73a0.h>
#include <mach/common.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <video/sh_mobile_lcdc.h>
@@ -525,21 +525,21 @@ static struct platform_device fsi_device = {
},
};
-static struct asoc_simple_dai_init_info fsi2_ak4648_init_info = {
- .fmt = SND_SOC_DAIFMT_LEFT_J,
- .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
- .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
- .sysclk = 11289600,
-};
-
static struct asoc_simple_card_info fsi2_ak4648_info = {
.name = "AK4648",
.card = "FSI2A-AK4648",
- .cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi2",
- .codec_dai = "ak4642-hifi",
- .init = &fsi2_ak4648_init_info,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .cpu_dai = {
+ .name = "fsia-dai",
+ .fmt = SND_SOC_DAIFMT_CBS_CFS,
+ },
+ .codec_dai = {
+ .name = "ak4642-hifi",
+ .fmt = SND_SOC_DAIFMT_CBM_CFM,
+ .sysclk = 11289600,
+ },
};
static struct platform_device fsi_ak4648_device = {
@@ -623,7 +623,7 @@ static int __init as3711_enable_lcdc_backlight(void)
0x45, 0xf0,
};
- if (!machine_is_kzm9g())
+ if (!of_machine_is_compatible("renesas,kzm9g"))
return 0;
if (!a)
@@ -672,8 +672,7 @@ static void __init kzm_init(void)
gpio_request(GPIO_FN_CS4_, NULL); /* CS4 */
/* SMSC */
- gpio_request(GPIO_PORT224, NULL); /* IRQ3 */
- gpio_direction_input(GPIO_PORT224);
+ gpio_request_one(GPIO_PORT224, GPIOF_IN, NULL); /* IRQ3 */
/* LCDC */
gpio_request(GPIO_FN_LCDD23, NULL);
@@ -703,14 +702,11 @@ static void __init kzm_init(void)
gpio_request(GPIO_FN_LCDDISP, NULL);
gpio_request(GPIO_FN_LCDDCK, NULL);
- gpio_request(GPIO_PORT222, NULL); /* LCDCDON */
- gpio_request(GPIO_PORT226, NULL); /* SC */
- gpio_direction_output(GPIO_PORT222, 1);
- gpio_direction_output(GPIO_PORT226, 1);
+ gpio_request_one(GPIO_PORT222, GPIOF_OUT_INIT_HIGH, NULL); /* LCDCDON */
+ gpio_request_one(GPIO_PORT226, GPIOF_OUT_INIT_HIGH, NULL); /* SC */
/* Touchscreen */
- gpio_request(GPIO_PORT223, NULL); /* IRQ8 */
- gpio_direction_input(GPIO_PORT223);
+ gpio_request_one(GPIO_PORT223, GPIOF_IN, NULL); /* IRQ8 */
/* enable MMCIF */
gpio_request(GPIO_FN_MMCCLK0, NULL);
@@ -734,8 +730,7 @@ static void __init kzm_init(void)
gpio_request(GPIO_FN_SDHID0_1, NULL);
gpio_request(GPIO_FN_SDHID0_0, NULL);
gpio_request(GPIO_FN_SDHI0_VCCQ_MC0_ON, NULL);
- gpio_request(GPIO_PORT15, NULL);
- gpio_direction_output(GPIO_PORT15, 1); /* power */
+ gpio_request_one(GPIO_PORT15, GPIOF_OUT_INIT_HIGH, NULL); /* power */
/* enable Micro SD */
gpio_request(GPIO_FN_SDHID2_0, NULL);
@@ -744,8 +739,7 @@ static void __init kzm_init(void)
gpio_request(GPIO_FN_SDHID2_3, NULL);
gpio_request(GPIO_FN_SDHICMD2, NULL);
gpio_request(GPIO_FN_SDHICLK2, NULL);
- gpio_request(GPIO_PORT14, NULL);
- gpio_direction_output(GPIO_PORT14, 1); /* power */
+ gpio_request_one(GPIO_PORT14, GPIOF_OUT_INIT_HIGH, NULL); /* power */
/* I2C 3 */
gpio_request(GPIO_FN_PORT27_I2C_SCL3, NULL);
@@ -772,6 +766,8 @@ static void __init kzm_init(void)
sh73a0_add_standard_devices();
platform_add_devices(kzm_devices, ARRAY_SIZE(kzm_devices));
+
+ sh73a0_pm_init();
}
static void kzm9g_restart(char mode, const char *cmd)
@@ -792,10 +788,9 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g")
.init_early = sh73a0_add_early_devices,
.nr_irqs = NR_IRQS_LEGACY,
.init_irq = sh73a0_init_irq,
- .handle_irq = gic_handle_irq,
.init_machine = kzm_init,
.init_late = shmobile_init_late,
- .timer = &shmobile_timer,
+ .init_time = sh73a0_earlytimer_init,
.restart = kzm9g_restart,
.dt_compat = kzm9g_boards_compat_dt,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 2fed62f66045..db968a585ff0 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -202,9 +202,7 @@
*
* it needs amixer settings for playing
*
- * amixer set "Headphone" on
- * amixer set "HPOUTL Mixer DACH" on
- * amixer set "HPOUTR Mixer DACH" on
+ * amixer set "Headphone Enable" on
*/
/* Fixed 3.3V and 1.8V regulators to be used by multiple devices */
@@ -502,18 +500,18 @@ static struct platform_device hdmi_lcdc_device = {
},
};
-static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
- .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM,
-};
-
static struct asoc_simple_card_info fsi2_hdmi_info = {
.name = "HDMI",
.card = "FSI2B-HDMI",
- .cpu_dai = "fsib-dai",
.codec = "sh-mobile-hdmi",
.platform = "sh_fsi2",
- .codec_dai = "sh_mobile_hdmi-hifi",
- .init = &fsi2_hdmi_init_info,
+ .cpu_dai = {
+ .name = "fsib-dai",
+ .fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF,
+ },
+ .codec_dai = {
+ .name = "sh_mobile_hdmi-hifi",
+ },
};
static struct platform_device fsi_hdmi_device = {
@@ -858,16 +856,12 @@ static struct platform_device leds_device = {
#define IRQ_FSI evt2irq(0x1840)
static struct sh_fsi_platform_info fsi_info = {
.port_a = {
- .flags = SH_FSI_BRS_INV,
.tx_id = SHDMA_SLAVE_FSIA_TX,
.rx_id = SHDMA_SLAVE_FSIA_RX,
},
.port_b = {
- .flags = SH_FSI_BRS_INV |
- SH_FSI_BRM_INV |
- SH_FSI_LRS_INV |
- SH_FSI_CLK_CPG |
- SH_FSI_FMT_SPDIF,
+ .flags = SH_FSI_CLK_CPG |
+ SH_FSI_FMT_SPDIF,
}
};
@@ -896,21 +890,21 @@ static struct platform_device fsi_device = {
},
};
-static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
- .fmt = SND_SOC_DAIFMT_LEFT_J,
- .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
- .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
- .sysclk = 11289600,
-};
-
static struct asoc_simple_card_info fsi2_ak4643_info = {
.name = "AK4643",
.card = "FSI2A-AK4643",
- .cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi2",
- .codec_dai = "ak4642-hifi",
- .init = &fsi2_ak4643_init_info,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .cpu_dai = {
+ .name = "fsia-dai",
+ .fmt = SND_SOC_DAIFMT_CBS_CFS,
+ },
+ .codec_dai = {
+ .name = "ak4642-hifi",
+ .fmt = SND_SOC_DAIFMT_CBM_CFM,
+ .sysclk = 11289600,
+ },
};
static struct platform_device fsi_ak4643_device = {
@@ -1408,11 +1402,10 @@ static void __init mackerel_init(void)
gpio_request(GPIO_FN_LCDDISP, NULL);
gpio_request(GPIO_FN_LCDDCK, NULL);
- gpio_request(GPIO_PORT31, NULL); /* backlight */
- gpio_direction_output(GPIO_PORT31, 0); /* off by default */
+ /* backlight, off by default */
+ gpio_request_one(GPIO_PORT31, GPIOF_OUT_INIT_LOW, NULL);
- gpio_request(GPIO_PORT151, NULL); /* LCDDON */
- gpio_direction_output(GPIO_PORT151, 1);
+ gpio_request_one(GPIO_PORT151, GPIOF_OUT_INIT_HIGH, NULL); /* LCDDON */
/* USBHS0 */
gpio_request(GPIO_FN_VBUS0_0, NULL);
@@ -1428,8 +1421,7 @@ static void __init mackerel_init(void)
gpio_request(GPIO_FN_FSIAILR, NULL);
gpio_request(GPIO_FN_FSIAISLD, NULL);
gpio_request(GPIO_FN_FSIAOSLD, NULL);
- gpio_request(GPIO_PORT161, NULL);
- gpio_direction_output(GPIO_PORT161, 0); /* slave */
+ gpio_request_one(GPIO_PORT161, GPIOF_OUT_INIT_LOW, NULL); /* slave */
gpio_request(GPIO_PORT9, NULL);
gpio_request(GPIO_PORT10, NULL);
@@ -1483,8 +1475,7 @@ static void __init mackerel_init(void)
gpio_request(GPIO_FN_SDHID1_0, NULL);
#endif
/* card detect pin for MMC slot (CN7) */
- gpio_request(GPIO_PORT41, NULL);
- gpio_direction_input(GPIO_PORT41);
+ gpio_request_one(GPIO_PORT41, GPIOF_IN, NULL);
/* enable SDHI2 */
gpio_request(GPIO_FN_SDHICMD2, NULL);
@@ -1495,8 +1486,7 @@ static void __init mackerel_init(void)
gpio_request(GPIO_FN_SDHID2_0, NULL);
/* card detect pin for microSD slot (CN23) */
- gpio_request(GPIO_PORT162, NULL);
- gpio_direction_input(GPIO_PORT162);
+ gpio_request_one(GPIO_PORT162, GPIOF_IN, NULL);
/* MMCIF */
gpio_request(GPIO_FN_MMCD0_0, NULL);
@@ -1593,6 +1583,6 @@ DT_MACHINE_START(MACKEREL_DT, "mackerel")
.handle_irq = shmobile_handle_irq_intc,
.init_machine = mackerel_init,
.init_late = sh7372_pm_init_late,
- .timer = &shmobile_timer,
+ .init_time = sh7372_earlytimer_init,
.dt_compat = mackerel_boards_compat_dt,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c
index 449f9289567d..cdcb799e802f 100644
--- a/arch/arm/mach-shmobile/board-marzen.c
+++ b/arch/arm/mach-shmobile/board-marzen.c
@@ -44,7 +44,6 @@
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <asm/traps.h>
/* Fixed 3.3V regulator to be used by SDHI0 */
@@ -382,8 +381,7 @@ MACHINE_START(MARZEN, "marzen")
.init_early = r8a7779_add_early_devices,
.nr_irqs = NR_IRQS_LEGACY,
.init_irq = r8a7779_init_irq,
- .handle_irq = gic_handle_irq,
.init_machine = marzen_init,
.init_late = marzen_init_late,
- .timer = &shmobile_timer,
+ .init_time = r8a7779_earlytimer_init,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c
index eac49d59782f..19ce885a3b43 100644
--- a/arch/arm/mach-shmobile/clock-r8a7740.c
+++ b/arch/arm/mach-shmobile/clock-r8a7740.c
@@ -581,10 +581,14 @@ static struct clk_lookup lookups[] = {
/* MSTP32 clocks */
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]),
- CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP111]),
+ CLKDEV_DEV_ID("sh_tmu.3", &mstp_clks[MSTP111]),
+ CLKDEV_DEV_ID("sh_tmu.4", &mstp_clks[MSTP111]),
+ CLKDEV_DEV_ID("sh_tmu.5", &mstp_clks[MSTP111]),
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]),
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]),
CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP125]),
+ CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP125]),
+ CLKDEV_DEV_ID("sh_tmu.2", &mstp_clks[MSTP125]),
CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]),
CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[MSTP128]),
diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c
index c019609da660..1db36537255c 100644
--- a/arch/arm/mach-shmobile/clock-r8a7779.c
+++ b/arch/arm/mach-shmobile/clock-r8a7779.c
@@ -162,6 +162,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("ohci-platform.0", &mstp_clks[MSTP100]), /* USB OHCI port0/1 */
CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP016]), /* TMU00 */
CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP016]), /* TMU01 */
+ CLKDEV_DEV_ID("sh_tmu.2", &mstp_clks[MSTP016]), /* TMU02 */
CLKDEV_DEV_ID("i2c-rcar.0", &mstp_clks[MSTP030]), /* I2C0 */
CLKDEV_DEV_ID("i2c-rcar.1", &mstp_clks[MSTP029]), /* I2C1 */
CLKDEV_DEV_ID("i2c-rcar.2", &mstp_clks[MSTP028]), /* I2C2 */
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index 3ca6757b129a..45d21fe317f4 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -544,6 +544,7 @@ static struct clk_lookup lookups[] = {
/* MSTP32 clocks */
CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */
+ CLKDEV_DEV_ID("fff30000.i2c", &mstp_clks[MSTP001]), /* IIC2 */
CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[MSTP000]), /* MSIOF0 */
CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */
CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */
@@ -556,6 +557,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("fff20000.i2c", &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 */
@@ -577,18 +579,25 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
+ CLKDEV_DEV_ID("e6c20000.i2c", &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_flctl.0", &mstp_clks[MSTP315]), /* FLCTL */
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
+ CLKDEV_DEV_ID("e6850000.sdhi", &mstp_clks[MSTP314]), /* SDHI0 */
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
+ CLKDEV_DEV_ID("e6860000.sdhi", &mstp_clks[MSTP313]), /* SDHI1 */
CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
+ CLKDEV_DEV_ID("e6bd0000.mmcif", &mstp_clks[MSTP312]), /* MMC */
CLKDEV_DEV_ID("sh-mipi-dsi.1", &mstp_clks[MSTP423]), /* DSITX1 */
CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), /* SDHI2 */
+ CLKDEV_DEV_ID("e6870000.sdhi", &mstp_clks[MSTP415]), /* SDHI2 */
CLKDEV_DEV_ID("sh-mobile-hdmi", &mstp_clks[MSTP413]), /* HDMI */
CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */
+ CLKDEV_DEV_ID("e6d20000.i2c", &mstp_clks[MSTP411]), /* IIC3 */
CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
+ CLKDEV_DEV_ID("e6d30000.i2c", &mstp_clks[MSTP410]), /* IIC4 */
CLKDEV_DEV_ID("sh-dma-engine.4", &mstp_clks[MSTP407]), /* USB-DMAC1 */
CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 516ff7f3e434..afa5423a0f93 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -264,17 +264,17 @@ enum { DIV4_I, DIV4_ZG, DIV4_M3, DIV4_B, DIV4_M1, DIV4_M2,
SH_CLK_DIV4(&pll1_clk, _reg, _bit, _mask, _flags)
static struct clk div4_clks[DIV4_NR] = {
- [DIV4_I] = DIV4(FRQCRA, 20, 0xfff, CLK_ENABLE_ON_INIT),
- [DIV4_ZG] = DIV4(FRQCRA, 16, 0xbff, CLK_ENABLE_ON_INIT),
- [DIV4_M3] = DIV4(FRQCRA, 12, 0xfff, CLK_ENABLE_ON_INIT),
- [DIV4_B] = DIV4(FRQCRA, 8, 0xfff, CLK_ENABLE_ON_INIT),
- [DIV4_M1] = DIV4(FRQCRA, 4, 0xfff, 0),
- [DIV4_M2] = DIV4(FRQCRA, 0, 0xfff, 0),
- [DIV4_Z] = DIV4(FRQCRB, 24, 0xbff, 0),
- [DIV4_ZTR] = DIV4(FRQCRB, 20, 0xfff, 0),
- [DIV4_ZT] = DIV4(FRQCRB, 16, 0xfff, 0),
- [DIV4_ZX] = DIV4(FRQCRB, 12, 0xfff, 0),
- [DIV4_HP] = DIV4(FRQCRB, 4, 0xfff, 0),
+ [DIV4_I] = DIV4(FRQCRA, 20, 0xdff, CLK_ENABLE_ON_INIT),
+ [DIV4_ZG] = DIV4(FRQCRA, 16, 0xd7f, CLK_ENABLE_ON_INIT),
+ [DIV4_M3] = DIV4(FRQCRA, 12, 0x1dff, CLK_ENABLE_ON_INIT),
+ [DIV4_B] = DIV4(FRQCRA, 8, 0xdff, CLK_ENABLE_ON_INIT),
+ [DIV4_M1] = DIV4(FRQCRA, 4, 0x1dff, 0),
+ [DIV4_M2] = DIV4(FRQCRA, 0, 0x1dff, 0),
+ [DIV4_Z] = DIV4(FRQCRB, 24, 0x97f, 0),
+ [DIV4_ZTR] = DIV4(FRQCRB, 20, 0xdff, 0),
+ [DIV4_ZT] = DIV4(FRQCRB, 16, 0xdff, 0),
+ [DIV4_ZX] = DIV4(FRQCRB, 12, 0xdff, 0),
+ [DIV4_HP] = DIV4(FRQCRB, 4, 0xdff, 0),
};
enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_ZB1,
@@ -525,6 +525,13 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
};
+/* The lookups structure below includes duplicate entries for some clocks
+ * with alternate names.
+ * - The traditional name used when a device is initialised with platform data
+ * - The name used when a device is initialised using device tree
+ * The longer-term aim is to remove these duplicates, and indeed the
+ * lookups table entirely, by describing clocks using device tree.
+ */
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("r_clk", &r_clk),
@@ -545,6 +552,7 @@ static struct clk_lookup lookups[] = {
/* MSTP32 clocks */
CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */
+ CLKDEV_DEV_ID("e6824000.i2c", &mstp_clks[MSTP001]), /* I2C2 */
CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[MSTP129]), /* CEU1 */
CLKDEV_DEV_ID("sh-mobile-csi2.1", &mstp_clks[MSTP128]), /* CSI2-RX1 */
CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), /* CEU0 */
@@ -553,6 +561,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP125]), /* TMU01 */
CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* I2C0 */
+ CLKDEV_DEV_ID("e6820000.i2c", &mstp_clks[MSTP116]), /* I2C0 */
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP219]), /* SCIFA7 */
CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), /* SY-DMAC */
@@ -569,17 +578,21 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI */
CLKDEV_DEV_ID("sh_irda.0", &mstp_clks[MSTP325]), /* IrDA */
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* I2C1 */
+ CLKDEV_DEV_ID("e6822000.i2c", &mstp_clks[MSTP323]), /* I2C1 */
CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP322]), /* USB */
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("e6bd0000.mmcif", &mstp_clks[MSTP312]), /* MMCIF0 */
CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), /* SDHI2 */
CLKDEV_DEV_ID("leds-renesas-tpu.12", &mstp_clks[MSTP303]), /* TPU1 */
CLKDEV_DEV_ID("leds-renesas-tpu.21", &mstp_clks[MSTP302]), /* TPU2 */
CLKDEV_DEV_ID("leds-renesas-tpu.30", &mstp_clks[MSTP301]), /* TPU3 */
CLKDEV_DEV_ID("leds-renesas-tpu.41", &mstp_clks[MSTP300]), /* TPU4 */
CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* I2C3 */
+ CLKDEV_DEV_ID("e6826000.i2c", &mstp_clks[MSTP411]), /* I2C3 */
CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* I2C4 */
+ CLKDEV_DEV_ID("e6828000.i2c", &mstp_clks[MSTP410]), /* I2C4 */
CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
};
diff --git a/arch/arm/mach-shmobile/headsmp-sh73a0.S b/arch/arm/mach-shmobile/headsmp-sh73a0.S
new file mode 100644
index 000000000000..bec4c0d9b713
--- /dev/null
+++ b/arch/arm/mach-shmobile/headsmp-sh73a0.S
@@ -0,0 +1,50 @@
+/*
+ * SMP support for SoC sh73a0
+ *
+ * Copyright (C) 2012 Bastian Hecht
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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 <linux/init.h>
+#include <asm/memory.h>
+
+ __CPUINIT
+/*
+ * Reset vector for secondary CPUs.
+ *
+ * First we turn on L1 cache coherency for our CPU. Then we jump to
+ * shmobile_invalidate_start that invalidates the cache and hands over control
+ * to the common ARM startup code.
+ * This function will be mapped to address 0 by the SBAR register.
+ * A normal branch is out of range here so we need a long jump. We jump to
+ * the physical address as the MMU is still turned off.
+ */
+ .align 12
+ENTRY(sh73a0_secondary_vector)
+ mrc p15, 0, r0, c0, c0, 5 @ read MIPDR
+ and r0, r0, #3 @ mask out cpu ID
+ lsl r0, r0, #3 @ we will shift by cpu_id * 8 bits
+ mov r1, #0xf0000000 @ SCU base address
+ ldr r2, [r1, #8] @ SCU Power Status Register
+ mov r3, #3
+ bic r2, r2, r3, lsl r0 @ Clear bits of our CPU (Run Mode)
+ str r2, [r1, #8] @ write back
+
+ ldr pc, 1f
+1: .long shmobile_invalidate_start - PAGE_OFFSET + PLAT_PHYS_OFFSET
+ENDPROC(sh73a0_secondary_vector)
diff --git a/arch/arm/mach-shmobile/headsmp.S b/arch/arm/mach-shmobile/headsmp.S
index b202c1272526..96001fd49b6c 100644
--- a/arch/arm/mach-shmobile/headsmp.S
+++ b/arch/arm/mach-shmobile/headsmp.S
@@ -16,54 +16,6 @@
__CPUINIT
-/* Cache invalidation nicked from arch/arm/mach-imx/head-v7.S, thanks!
- *
- * The secondary kernel init calls v7_flush_dcache_all before it enables
- * the L1; however, the L1 comes out of reset in an undefined state, so
- * the clean + invalidate performed by v7_flush_dcache_all causes a bunch
- * of cache lines with uninitialized data and uninitialized tags to get
- * written out to memory, which does really unpleasant things to the main
- * processor. We fix this by performing an invalidate, rather than a
- * clean + invalidate, before jumping into the kernel.
- *
- * This funciton is cloned from arch/arm/mach-tegra/headsmp.S, and needs
- * to be called for both secondary cores startup and primary core resume
- * procedures. Ideally, it should be moved into arch/arm/mm/cache-v7.S.
- */
-ENTRY(v7_invalidate_l1)
- mov r0, #0
- mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
- mcr p15, 2, r0, c0, c0, 0
- mrc p15, 1, r0, c0, c0, 0
-
- ldr r1, =0x7fff
- and r2, r1, r0, lsr #13
-
- ldr r1, =0x3ff
-
- and r3, r1, r0, lsr #3 @ NumWays - 1
- add r2, r2, #1 @ NumSets
-
- and r0, r0, #0x7
- add r0, r0, #4 @ SetShift
-
- clz r1, r3 @ WayShift
- add r4, r3, #1 @ NumWays
-1: sub r2, r2, #1 @ NumSets--
- mov r3, r4 @ Temp = NumWays
-2: subs r3, r3, #1 @ Temp--
- mov r5, r3, lsl r1
- mov r6, r2, lsl r0
- orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
- mcr p15, 0, r5, c7, c6, 2
- bgt 2b
- cmp r2, #0
- bgt 1b
- dsb
- isb
- mov pc, lr
-ENDPROC(v7_invalidate_l1)
-
ENTRY(shmobile_invalidate_start)
bl v7_invalidate_l1
b secondary_startup
diff --git a/arch/arm/mach-shmobile/hotplug.c b/arch/arm/mach-shmobile/hotplug.c
index b09a0bdbf813..a1524e3367b0 100644
--- a/arch/arm/mach-shmobile/hotplug.c
+++ b/arch/arm/mach-shmobile/hotplug.c
@@ -56,6 +56,12 @@ int shmobile_cpu_disable(unsigned int cpu)
return cpu == 0 ? -EPERM : 0;
}
+int shmobile_cpu_disable_any(unsigned int cpu)
+{
+ cpumask_clear_cpu(cpu, &dead_cpus);
+ return 0;
+}
+
int shmobile_cpu_is_dead(unsigned int cpu)
{
return cpumask_test_cpu(cpu, &dead_cpus);
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index dfeca79e9e96..e48606d8a2be 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -2,7 +2,7 @@
#define __ARCH_MACH_COMMON_H
extern void shmobile_earlytimer_init(void);
-extern struct sys_timer shmobile_timer;
+extern void shmobile_timer_init(void);
extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz,
unsigned int mult, unsigned int div);
struct twd_local_timer;
@@ -20,8 +20,11 @@ extern void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv);
extern void sh7372_init_irq(void);
extern void sh7372_map_io(void);
+extern void sh7372_earlytimer_init(void);
extern void sh7372_add_early_devices(void);
extern void sh7372_add_standard_devices(void);
+extern void sh7372_add_early_devices_dt(void);
+extern void sh7372_add_standard_devices_dt(void);
extern void sh7372_clock_init(void);
extern void sh7372_pinmux_init(void);
extern void sh7372_pm_init(void);
@@ -31,11 +34,17 @@ extern struct clk sh7372_extal1_clk;
extern struct clk sh7372_extal2_clk;
extern void sh73a0_init_irq(void);
+extern void sh73a0_init_irq_dt(void);
extern void sh73a0_map_io(void);
+extern void sh73a0_earlytimer_init(void);
extern void sh73a0_add_early_devices(void);
+extern void sh73a0_add_early_devices_dt(void);
extern void sh73a0_add_standard_devices(void);
+extern void sh73a0_add_standard_devices_dt(void);
extern void sh73a0_clock_init(void);
extern void sh73a0_pinmux_init(void);
+extern void sh73a0_pm_init(void);
+extern void sh73a0_secondary_vector(void);
extern struct clk sh73a0_extal1_clk;
extern struct clk sh73a0_extal2_clk;
extern struct clk sh73a0_extcki_clk;
@@ -47,9 +56,11 @@ extern void r8a7740_add_early_devices(void);
extern void r8a7740_add_standard_devices(void);
extern void r8a7740_clock_init(u8 md_ck);
extern void r8a7740_pinmux_init(void);
+extern void r8a7740_pm_init(void);
extern void r8a7779_init_irq(void);
extern void r8a7779_map_io(void);
+extern void r8a7779_earlytimer_init(void);
extern void r8a7779_add_early_devices(void);
extern void r8a7779_add_standard_devices(void);
extern void r8a7779_clock_init(void);
@@ -73,6 +84,7 @@ static inline int shmobile_cpuidle_init(void) { return 0; }
extern void shmobile_cpu_die(unsigned int cpu);
extern int shmobile_cpu_disable(unsigned int cpu);
+extern int shmobile_cpu_disable_any(unsigned int cpu);
#ifdef CONFIG_HOTPLUG_CPU
extern int shmobile_cpu_is_dead(unsigned int cpu);
diff --git a/arch/arm/mach-shmobile/include/mach/uncompress.h b/arch/arm/mach-shmobile/include/mach/uncompress.h
index 0bd7556b1387..f1aee56781e7 100644
--- a/arch/arm/mach-shmobile/include/mach/uncompress.h
+++ b/arch/arm/mach-shmobile/include/mach/uncompress.h
@@ -16,6 +16,4 @@ static void arch_decomp_setup(void)
{
}
-#define arch_decomp_wdog()
-
#endif /* __ASM_MACH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-shmobile/intc-r8a7779.c b/arch/arm/mach-shmobile/intc-r8a7779.c
index ef66f1a8aa2e..8807c27f71f9 100644
--- a/arch/arm/mach-shmobile/intc-r8a7779.c
+++ b/arch/arm/mach-shmobile/intc-r8a7779.c
@@ -22,10 +22,10 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <mach/common.h>
#include <mach/intc.h>
#include <mach/r8a7779.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c
index f0c5e5190601..91faba666d46 100644
--- a/arch/arm/mach-shmobile/intc-sh73a0.c
+++ b/arch/arm/mach-shmobile/intc-sh73a0.c
@@ -23,10 +23,11 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/sh_intc.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
#include <mach/intc.h>
#include <mach/irqs.h>
#include <mach/sh73a0.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -315,11 +316,6 @@ static int intca_gic_set_type(struct irq_data *data, unsigned int type)
return irq_cbp(irq_set_type, to_intca_reloc_irq(data), type);
}
-static int intca_gic_set_wake(struct irq_data *data, unsigned int on)
-{
- return irq_cbp(irq_set_wake, to_intca_reloc_irq(data), on);
-}
-
#ifdef CONFIG_SMP
static int intca_gic_set_affinity(struct irq_data *data,
const struct cpumask *cpumask,
@@ -339,7 +335,7 @@ struct irq_chip intca_gic_irq_chip = {
.irq_disable = intca_gic_disable,
.irq_shutdown = intca_gic_disable,
.irq_set_type = intca_gic_set_type,
- .irq_set_wake = intca_gic_set_wake,
+ .irq_set_wake = sh73a0_set_wake,
#ifdef CONFIG_SMP
.irq_set_affinity = intca_gic_set_affinity,
#endif
@@ -464,3 +460,11 @@ void __init sh73a0_init_irq(void)
sh73a0_pint1_cascade.handler = sh73a0_pint1_demux;
setup_irq(gic_spi(34), &sh73a0_pint1_cascade);
}
+
+#ifdef CONFIG_OF
+void __init sh73a0_init_irq_dt(void)
+{
+ irqchip_init();
+ gic_arch_extn.irq_set_wake = sh73a0_set_wake;
+}
+#endif
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index ed8d2351915e..1f958d7b0bac 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -12,7 +12,6 @@
*/
#include <linux/init.h>
#include <linux/smp.h>
-#include <asm/hardware/gic.h>
void __init shmobile_smp_init_cpus(unsigned int ncores)
{
@@ -26,6 +25,4 @@ void __init shmobile_smp_init_cpus(unsigned int ncores)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c
index 21e5316d2d88..40b87aa1d448 100644
--- a/arch/arm/mach-shmobile/pm-r8a7740.c
+++ b/arch/arm/mach-shmobile/pm-r8a7740.c
@@ -9,7 +9,9 @@
* for more details.
*/
#include <linux/console.h>
+#include <linux/suspend.h>
#include <mach/pm-rmobile.h>
+#include <mach/common.h>
#ifdef CONFIG_PM
static int r8a7740_pd_a4s_suspend(void)
@@ -58,3 +60,23 @@ void __init r8a7740_init_pm_domains(void)
}
#endif /* CONFIG_PM */
+
+#ifdef CONFIG_SUSPEND
+static int r8a7740_enter_suspend(suspend_state_t suspend_state)
+{
+ cpu_do_idle();
+ return 0;
+}
+
+static void r8a7740_suspend_init(void)
+{
+ shmobile_suspend_ops.enter = r8a7740_enter_suspend;
+}
+#else
+static void r8a7740_suspend_init(void) {}
+#endif
+
+void __init r8a7740_pm_init(void)
+{
+ r8a7740_suspend_init();
+}
diff --git a/arch/arm/mach-shmobile/pm-sh73a0.c b/arch/arm/mach-shmobile/pm-sh73a0.c
new file mode 100644
index 000000000000..99086e98fbbc
--- /dev/null
+++ b/arch/arm/mach-shmobile/pm-sh73a0.c
@@ -0,0 +1,32 @@
+/*
+ * sh73a0 Power management support
+ *
+ * Copyright (C) 2012 Bastian Hecht <hechtb+renesas@gmail.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/suspend.h>
+#include <mach/common.h>
+
+#ifdef CONFIG_SUSPEND
+static int sh73a0_enter_suspend(suspend_state_t suspend_state)
+{
+ cpu_do_idle();
+ return 0;
+}
+
+static void sh73a0_suspend_init(void)
+{
+ shmobile_suspend_ops.enter = sh73a0_enter_suspend;
+}
+#else
+static void sh73a0_suspend_init(void) {}
+#endif
+
+void __init sh73a0_pm_init(void)
+{
+ sh73a0_suspend_init();
+}
diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c
index a47beeb18283..47662a581c0a 100644
--- a/arch/arm/mach-shmobile/setup-emev2.c
+++ b/arch/arm/mach-shmobile/setup-emev2.c
@@ -20,13 +20,14 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/platform_device.h>
#include <linux/platform_data/gpio-em.h>
#include <linux/of_platform.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/io.h>
-#include <linux/of_irq.h>
+#include <linux/irqchip/arm-gic.h>
#include <mach/hardware.h>
#include <mach/common.h>
#include <mach/emev2.h>
@@ -35,7 +36,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <asm/hardware/gic.h>
static struct map_desc emev2_io_desc[] __initdata = {
#ifdef CONFIG_SMP
@@ -445,29 +445,18 @@ void __init emev2_add_standard_devices_dt(void)
emev2_auxdata_lookup, NULL);
}
-static const struct of_device_id emev2_dt_irq_match[] = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- {},
-};
-
static const char *emev2_boards_compat_dt[] __initdata = {
"renesas,emev2",
NULL,
};
-void __init emev2_init_irq_dt(void)
-{
- of_irq_init(emev2_dt_irq_match);
-}
-
DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
.smp = smp_ops(emev2_smp_ops),
.init_early = emev2_init_delay,
.nr_irqs = NR_IRQS_LEGACY,
- .init_irq = emev2_init_irq_dt,
- .handle_irq = gic_handle_irq,
+ .init_irq = irqchip_init,
.init_machine = emev2_add_standard_devices_dt,
- .timer = &shmobile_timer,
+ .init_time = shmobile_timer_init,
.dt_compat = emev2_boards_compat_dt,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index 095222469d03..30ac79c7c687 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -27,7 +27,6 @@
#include <linux/serial_sci.h>
#include <linux/sh_dma.h>
#include <linux/sh_timer.h>
-#include <linux/dma-mapping.h>
#include <mach/dma-register.h>
#include <mach/r8a7740.h>
#include <mach/pm-rmobile.h>
@@ -68,6 +67,32 @@ void __init r8a7740_map_io(void)
iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc));
}
+/* PFC */
+static struct resource r8a7740_pfc_resources[] = {
+ [0] = {
+ .start = 0xe6050000,
+ .end = 0xe6057fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0xe605800c,
+ .end = 0xe605802b,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device r8a7740_pfc_device = {
+ .name = "pfc-r8a7740",
+ .id = -1,
+ .resource = r8a7740_pfc_resources,
+ .num_resources = ARRAY_SIZE(r8a7740_pfc_resources),
+};
+
+void __init r8a7740_pinmux_init(void)
+{
+ platform_device_register(&r8a7740_pfc_device);
+}
+
/* SCIFA0 */
static struct plat_sci_port scif0_platform_data = {
.mapbase = 0xe6c40000,
@@ -262,6 +287,97 @@ static struct platform_device cmt10_device = {
.num_resources = ARRAY_SIZE(cmt10_resources),
};
+/* TMU */
+static struct sh_timer_config tmu00_platform_data = {
+ .name = "TMU00",
+ .channel_offset = 0x4,
+ .timer_bit = 0,
+ .clockevent_rating = 200,
+};
+
+static struct resource tmu00_resources[] = {
+ [0] = {
+ .name = "TMU00",
+ .start = 0xfff80008,
+ .end = 0xfff80014 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = intcs_evt2irq(0xe80),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu00_device = {
+ .name = "sh_tmu",
+ .id = 0,
+ .dev = {
+ .platform_data = &tmu00_platform_data,
+ },
+ .resource = tmu00_resources,
+ .num_resources = ARRAY_SIZE(tmu00_resources),
+};
+
+static struct sh_timer_config tmu01_platform_data = {
+ .name = "TMU01",
+ .channel_offset = 0x10,
+ .timer_bit = 1,
+ .clocksource_rating = 200,
+};
+
+static struct resource tmu01_resources[] = {
+ [0] = {
+ .name = "TMU01",
+ .start = 0xfff80014,
+ .end = 0xfff80020 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = intcs_evt2irq(0xea0),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu01_device = {
+ .name = "sh_tmu",
+ .id = 1,
+ .dev = {
+ .platform_data = &tmu01_platform_data,
+ },
+ .resource = tmu01_resources,
+ .num_resources = ARRAY_SIZE(tmu01_resources),
+};
+
+static struct sh_timer_config tmu02_platform_data = {
+ .name = "TMU02",
+ .channel_offset = 0x1C,
+ .timer_bit = 2,
+ .clocksource_rating = 200,
+};
+
+static struct resource tmu02_resources[] = {
+ [0] = {
+ .name = "TMU02",
+ .start = 0xfff80020,
+ .end = 0xfff8002C - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = intcs_evt2irq(0xec0),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu02_device = {
+ .name = "sh_tmu",
+ .id = 2,
+ .dev = {
+ .platform_data = &tmu02_platform_data,
+ },
+ .resource = tmu02_resources,
+ .num_resources = ARRAY_SIZE(tmu02_resources),
+};
+
static struct platform_device *r8a7740_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
@@ -273,6 +389,9 @@ static struct platform_device *r8a7740_early_devices[] __initdata = {
&scif7_device,
&scifb_device,
&cmt10_device,
+ &tmu00_device,
+ &tmu01_device,
+ &tmu02_device,
};
/* DMA */
@@ -705,12 +824,6 @@ void __init r8a7740_add_standard_devices(void)
rmobile_add_device_to_domain("A3SP", &i2c1_device);
}
-static void __init r8a7740_earlytimer_init(void)
-{
- r8a7740_clock_init(0);
- shmobile_earlytimer_init();
-}
-
void __init r8a7740_add_early_devices(void)
{
early_platform_add_devices(r8a7740_early_devices,
@@ -718,9 +831,6 @@ void __init r8a7740_add_early_devices(void)
/* setup early console here as well */
shmobile_setup_console();
-
- /* override timer setup with soc-specific code */
- shmobile_timer.init = r8a7740_earlytimer_init;
}
#ifdef CONFIG_USE_OF
@@ -763,7 +873,7 @@ DT_MACHINE_START(R8A7740_DT, "Generic R8A7740 (Flattened Device Tree)")
.init_irq = r8a7740_init_irq,
.handle_irq = shmobile_handle_irq_intc,
.init_machine = r8a7740_add_standard_devices_dt,
- .timer = &shmobile_timer,
+ .init_time = shmobile_timer_init,
.dt_compat = r8a7740_boards_compat_dt,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c
index 7a1ad4f38539..c54ff9b29fe5 100644
--- a/arch/arm/mach-shmobile/setup-r8a7779.c
+++ b/arch/arm/mach-shmobile/setup-r8a7779.c
@@ -60,14 +60,38 @@ void __init r8a7779_map_io(void)
iotable_init(r8a7779_io_desc, ARRAY_SIZE(r8a7779_io_desc));
}
+static struct resource r8a7779_pfc_resources[] = {
+ [0] = {
+ .start = 0xfffc0000,
+ .end = 0xfffc023b,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0xffc40000,
+ .end = 0xffc46fff,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device r8a7779_pfc_device = {
+ .name = "pfc-r8a7779",
+ .id = -1,
+ .resource = r8a7779_pfc_resources,
+ .num_resources = ARRAY_SIZE(r8a7779_pfc_resources),
+};
+
+void __init r8a7779_pinmux_init(void)
+{
+ platform_device_register(&r8a7779_pfc_device);
+}
+
static struct plat_sci_port scif0_platform_data = {
.mapbase = 0xffe40000,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { gic_spi(88), gic_spi(88),
- gic_spi(88), gic_spi(88) },
+ .irqs = SCIx_IRQ_MUXED(gic_spi(88)),
};
static struct platform_device scif0_device = {
@@ -84,8 +108,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { gic_spi(89), gic_spi(89),
- gic_spi(89), gic_spi(89) },
+ .irqs = SCIx_IRQ_MUXED(gic_spi(89)),
};
static struct platform_device scif1_device = {
@@ -102,8 +125,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { gic_spi(90), gic_spi(90),
- gic_spi(90), gic_spi(90) },
+ .irqs = SCIx_IRQ_MUXED(gic_spi(90)),
};
static struct platform_device scif2_device = {
@@ -120,8 +142,7 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { gic_spi(91), gic_spi(91),
- gic_spi(91), gic_spi(91) },
+ .irqs = SCIx_IRQ_MUXED(gic_spi(91)),
};
static struct platform_device scif3_device = {
@@ -138,8 +159,7 @@ static struct plat_sci_port scif4_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { gic_spi(92), gic_spi(92),
- gic_spi(92), gic_spi(92) },
+ .irqs = SCIx_IRQ_MUXED(gic_spi(92)),
};
static struct platform_device scif4_device = {
@@ -156,8 +176,7 @@ static struct plat_sci_port scif5_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { gic_spi(93), gic_spi(93),
- gic_spi(93), gic_spi(93) },
+ .irqs = SCIx_IRQ_MUXED(gic_spi(93)),
};
static struct platform_device scif5_device = {
@@ -339,7 +358,7 @@ void __init r8a7779_add_standard_devices(void)
/* do nothing for !CONFIG_SMP or !CONFIG_HAVE_TWD */
void __init __weak r8a7779_register_twd(void) { }
-static void __init r8a7779_earlytimer_init(void)
+void __init r8a7779_earlytimer_init(void)
{
r8a7779_clock_init();
shmobile_earlytimer_init();
@@ -366,7 +385,4 @@ void __init r8a7779_add_early_devices(void)
* As a final step pass earlyprint=sh-sci.2,115200 on the kernel
* command line in case of the marzen board.
*/
-
- /* override timer setup with soc-specific code */
- shmobile_timer.init = r8a7779_earlytimer_init;
}
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index c917882424a7..d2079d5e3334 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -60,6 +60,32 @@ void __init sh7372_map_io(void)
iotable_init(sh7372_io_desc, ARRAY_SIZE(sh7372_io_desc));
}
+/* PFC */
+static struct resource sh7372_pfc_resources[] = {
+ [0] = {
+ .start = 0xe6050000,
+ .end = 0xe6057fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0xe605800c,
+ .end = 0xe6058027,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device sh7372_pfc_device = {
+ .name = "pfc-sh7372",
+ .id = -1,
+ .resource = sh7372_pfc_resources,
+ .num_resources = ARRAY_SIZE(sh7372_pfc_resources),
+};
+
+void __init sh7372_pinmux_init(void)
+{
+ platform_device_register(&sh7372_pfc_device);
+}
+
/* SCIFA0 */
static struct plat_sci_port scif0_platform_data = {
.mapbase = 0xe6c40000,
@@ -1054,7 +1080,7 @@ void __init sh7372_add_standard_devices(void)
ARRAY_SIZE(domain_devices));
}
-static void __init sh7372_earlytimer_init(void)
+void __init sh7372_earlytimer_init(void)
{
sh7372_clock_init();
shmobile_earlytimer_init();
@@ -1067,9 +1093,6 @@ void __init sh7372_add_early_devices(void)
/* setup early console here as well */
shmobile_setup_console();
-
- /* override timer setup with soc-specific code */
- shmobile_timer.init = sh7372_earlytimer_init;
}
#ifdef CONFIG_USE_OF
@@ -1113,7 +1136,7 @@ DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)")
.init_irq = sh7372_init_irq,
.handle_irq = shmobile_handle_irq_intc,
.init_machine = sh7372_add_standard_devices_dt,
- .timer = &shmobile_timer,
+ .init_time = shmobile_timer_init,
.dt_compat = sh7372_boards_compat_dt,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c
index db99a4ade80c..2ecd6681692f 100644
--- a/arch/arm/mach-shmobile/setup-sh73a0.c
+++ b/arch/arm/mach-shmobile/setup-sh73a0.c
@@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
+#include <linux/of_platform.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/io.h>
@@ -57,6 +58,31 @@ void __init sh73a0_map_io(void)
iotable_init(sh73a0_io_desc, ARRAY_SIZE(sh73a0_io_desc));
}
+static struct resource sh73a0_pfc_resources[] = {
+ [0] = {
+ .start = 0xe6050000,
+ .end = 0xe6057fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0xe605801c,
+ .end = 0xe6058027,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device sh73a0_pfc_device = {
+ .name = "pfc-sh73a0",
+ .id = -1,
+ .resource = sh73a0_pfc_resources,
+ .num_resources = ARRAY_SIZE(sh73a0_pfc_resources),
+};
+
+void __init sh73a0_pinmux_init(void)
+{
+ platform_device_register(&sh73a0_pfc_device);
+}
+
static struct plat_sci_port scif0_platform_data = {
.mapbase = 0xe6c40000,
.flags = UPF_BOOT_AUTOCONF,
@@ -754,7 +780,7 @@ static struct platform_device pmu_device = {
.resource = pmu_resources,
};
-static struct platform_device *sh73a0_early_devices[] __initdata = {
+static struct platform_device *sh73a0_early_devices_dt[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
@@ -765,6 +791,9 @@ static struct platform_device *sh73a0_early_devices[] __initdata = {
&scif7_device,
&scif8_device,
&cmt10_device,
+};
+
+static struct platform_device *sh73a0_early_devices[] __initdata = {
&tmu00_device,
&tmu01_device,
};
@@ -787,6 +816,8 @@ 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_dt,
+ ARRAY_SIZE(sh73a0_early_devices_dt));
platform_add_devices(sh73a0_early_devices,
ARRAY_SIZE(sh73a0_early_devices));
platform_add_devices(sh73a0_late_devices,
@@ -796,7 +827,7 @@ void __init sh73a0_add_standard_devices(void)
/* do nothing for !CONFIG_SMP or !CONFIG_HAVE_TWD */
void __init __weak sh73a0_register_twd(void) { }
-static void __init sh73a0_earlytimer_init(void)
+void __init sh73a0_earlytimer_init(void)
{
sh73a0_clock_init();
shmobile_earlytimer_init();
@@ -805,12 +836,63 @@ static void __init sh73a0_earlytimer_init(void)
void __init sh73a0_add_early_devices(void)
{
+ early_platform_add_devices(sh73a0_early_devices_dt,
+ ARRAY_SIZE(sh73a0_early_devices_dt));
early_platform_add_devices(sh73a0_early_devices,
ARRAY_SIZE(sh73a0_early_devices));
/* setup early console here as well */
shmobile_setup_console();
+}
+
+#ifdef CONFIG_USE_OF
+
+/* Please note that the clock initialisation shcheme used in
+ * sh73a0_add_early_devices_dt() and sh73a0_add_standard_devices_dt()
+ * does not work with SMP as there is a yet to be resolved lock-up in
+ * workqueue initialisation.
+ *
+ * CONFIG_SMP should be disabled when using this code.
+ */
+
+void __init sh73a0_add_early_devices_dt(void)
+{
+ shmobile_setup_delay(1196, 44, 46); /* Cortex-A9 @ 1196MHz */
+
+ early_platform_add_devices(sh73a0_early_devices_dt,
+ ARRAY_SIZE(sh73a0_early_devices_dt));
+
+ /* setup early console here as well */
+ shmobile_setup_console();
+}
+
+static const struct of_dev_auxdata sh73a0_auxdata_lookup[] __initconst = {
+ {},
+};
- /* override timer setup with soc-specific code */
- shmobile_timer.init = sh73a0_earlytimer_init;
+void __init sh73a0_add_standard_devices_dt(void)
+{
+ /* clocks are setup late during boot in the case of DT */
+ sh73a0_clock_init();
+
+ platform_add_devices(sh73a0_early_devices_dt,
+ ARRAY_SIZE(sh73a0_early_devices_dt));
+ of_platform_populate(NULL, of_default_bus_match_table,
+ sh73a0_auxdata_lookup, NULL);
}
+
+static const char *sh73a0_boards_compat_dt[] __initdata = {
+ "renesas,sh73a0",
+ NULL,
+};
+
+DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)")
+ .map_io = sh73a0_map_io,
+ .init_early = sh73a0_add_early_devices_dt,
+ .nr_irqs = NR_IRQS_LEGACY,
+ .init_irq = sh73a0_init_irq_dt,
+ .init_machine = sh73a0_add_standard_devices_dt,
+ .init_time = shmobile_timer_init,
+ .dt_compat = sh73a0_boards_compat_dt,
+MACHINE_END
+#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S
index 1d564674451d..a9df53b69ab8 100644
--- a/arch/arm/mach-shmobile/sleep-sh7372.S
+++ b/arch/arm/mach-shmobile/sleep-sh7372.S
@@ -59,17 +59,19 @@ sh7372_do_idle_sysc:
mcr p15, 0, r0, c1, c0, 0
isb
+ /*
+ * Clean and invalidate data cache again.
+ */
+ ldr r1, kernel_flush
+ blx r1
+
/* disable L2 cache in the aux control register */
mrc p15, 0, r10, c1, c0, 1
bic r10, r10, #2
mcr p15, 0, r10, c1, c0, 1
+ isb
/*
- * Invalidate data cache again.
- */
- 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
diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c
index f67456286280..953eb1f9388d 100644
--- a/arch/arm/mach-shmobile/smp-emev2.c
+++ b/arch/arm/mach-shmobile/smp-emev2.c
@@ -23,11 +23,11 @@
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/irqchip/arm-gic.h>
#include <mach/common.h>
#include <mach/emev2.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
-#include <asm/hardware/gic.h>
#include <asm/cacheflush.h>
#define EMEV2_SCU_BASE 0x1e000000
@@ -100,7 +100,7 @@ static int __cpuinit emev2_boot_secondary(unsigned int cpu, struct task_struct *
/* Tell ROM loader about our vector (in headsmp.S) */
emev2_set_boot_vector(__pa(shmobile_secondary_vector));
- gic_raise_softirq(cpumask_of(cpu), 0);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
return 0;
}
diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c
index 2ce6af9a6a37..3a4acf23edcf 100644
--- a/arch/arm/mach-shmobile/smp-r8a7779.c
+++ b/arch/arm/mach-shmobile/smp-r8a7779.c
@@ -23,12 +23,12 @@
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/irqchip/arm-gic.h>
#include <mach/common.h>
#include <mach/r8a7779.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
#include <asm/smp_twd.h>
-#include <asm/hardware/gic.h>
#define AVECR IOMEM(0xfe700040)
diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c
index 624f00f70abf..acb46a94ccdf 100644
--- a/arch/arm/mach-shmobile/smp-sh73a0.c
+++ b/arch/arm/mach-shmobile/smp-sh73a0.c
@@ -23,12 +23,13 @@
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/irqchip/arm-gic.h>
#include <mach/common.h>
+#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
#include <mach/sh73a0.h>
#include <asm/smp_scu.h>
#include <asm/smp_twd.h>
-#include <asm/hardware/gic.h>
#define WUPCR IOMEM(0xe6151010)
#define SRESCR IOMEM(0xe6151018)
@@ -36,14 +37,13 @@
#define SBAR IOMEM(0xe6180020)
#define APARMBAREA IOMEM(0xe6f10020)
+#define PSTR_SHUTDOWN_MODE 3
+
static void __iomem *scu_base_addr(void)
{
return (void __iomem *)0xf0000000;
}
-static DEFINE_SPINLOCK(scu_lock);
-static unsigned long tmp;
-
#ifdef CONFIG_HAVE_ARM_TWD
static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29);
void __init sh73a0_register_twd(void)
@@ -52,20 +52,6 @@ void __init sh73a0_register_twd(void)
}
#endif
-static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
-{
- void __iomem *scu_base = scu_base_addr();
-
- spin_lock(&scu_lock);
- tmp = __raw_readl(scu_base + 8);
- tmp &= ~clr;
- tmp |= set;
- spin_unlock(&scu_lock);
-
- /* disable cache coherency after releasing the lock */
- __raw_writel(tmp, scu_base + 8);
-}
-
static unsigned int __init sh73a0_get_core_count(void)
{
void __iomem *scu_base = scu_base_addr();
@@ -82,9 +68,6 @@ static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct
{
cpu = cpu_logical_map(cpu);
- /* enable cache coherency */
- modify_scu_cpu_psr(0, 3 << (cpu * 8));
-
if (((__raw_readl(PSTR) >> (4 * cpu)) & 3) == 3)
__raw_writel(1 << cpu, WUPCR); /* wake up */
else
@@ -95,16 +78,14 @@ static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct
static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus)
{
- int cpu = cpu_logical_map(0);
-
scu_enable(scu_base_addr());
- /* Map the reset vector (in headsmp.S) */
+ /* Map the reset vector (in headsmp-sh73a0.S) */
__raw_writel(0, APARMBAREA); /* 4k */
- __raw_writel(__pa(shmobile_secondary_vector), SBAR);
+ __raw_writel(__pa(sh73a0_secondary_vector), SBAR);
- /* enable cache coherency on CPU0 */
- modify_scu_cpu_psr(0, 3 << (cpu * 8));
+ /* enable cache coherency on booting CPU */
+ scu_power_mode(scu_base_addr(), SCU_PM_NORMAL);
}
static void __init sh73a0_smp_init_cpus(void)
@@ -114,16 +95,20 @@ static void __init sh73a0_smp_init_cpus(void)
shmobile_smp_init_cpus(ncores);
}
-static int __maybe_unused sh73a0_cpu_kill(unsigned int cpu)
+#ifdef CONFIG_HOTPLUG_CPU
+static int sh73a0_cpu_kill(unsigned int cpu)
{
+
int k;
+ u32 pstr;
- /* this function is running on another CPU than the offline target,
- * here we need wait for shutdown code in platform_cpu_die() to
- * finish before asking SoC-specific code to power off the CPU core.
+ /*
+ * wait until the power status register confirms the shutdown of the
+ * offline target
*/
for (k = 0; k < 1000; k++) {
- if (shmobile_cpu_is_dead(cpu))
+ pstr = (__raw_readl(PSTR) >> (4 * cpu)) & 3;
+ if (pstr == PSTR_SHUTDOWN_MODE)
return 1;
mdelay(1);
@@ -132,6 +117,23 @@ static int __maybe_unused sh73a0_cpu_kill(unsigned int cpu)
return 0;
}
+static void sh73a0_cpu_die(unsigned int cpu)
+{
+ /*
+ * The ARM MPcore does not issue a cache coherency request for the L1
+ * cache when powering off single CPUs. We must take care of this and
+ * further caches.
+ */
+ dsb();
+ flush_cache_all();
+
+ /* Set power off mode. This takes the CPU out of the MP cluster */
+ scu_power_mode(scu_base_addr(), SCU_PM_POWEROFF);
+
+ /* Enter shutdown mode */
+ cpu_do_idle();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
struct smp_operations sh73a0_smp_ops __initdata = {
.smp_init_cpus = sh73a0_smp_init_cpus,
@@ -140,7 +142,7 @@ struct smp_operations sh73a0_smp_ops __initdata = {
.smp_boot_secondary = sh73a0_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_kill = sh73a0_cpu_kill,
- .cpu_die = shmobile_cpu_die,
- .cpu_disable = shmobile_cpu_disable,
+ .cpu_die = sh73a0_cpu_die,
+ .cpu_disable = shmobile_cpu_disable_any,
#endif
};
diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c
index a68919727e24..3d16d4dff01b 100644
--- a/arch/arm/mach-shmobile/timer.c
+++ b/arch/arm/mach-shmobile/timer.c
@@ -20,6 +20,7 @@
*/
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <asm/arch_timer.h>
#include <asm/mach/time.h>
#include <asm/smp_twd.h>
@@ -60,10 +61,8 @@ void __init shmobile_earlytimer_init(void)
late_time_init = shmobile_late_time_init;
}
-static void __init shmobile_timer_init(void)
+void __init shmobile_timer_init(void)
{
+ arch_timer_of_register();
+ arch_timer_sched_clock_init();
}
-
-struct sys_timer shmobile_timer = {
- .init = shmobile_timer_init,
-};
diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h
index 9941caa94931..315edff610f2 100644
--- a/arch/arm/mach-socfpga/core.h
+++ b/arch/arm/mach-socfpga/core.h
@@ -20,7 +20,7 @@
#ifndef __MACH_CORE_H
#define __MACH_CORE_H
-extern void secondary_startup(void);
+extern void socfpga_secondary_startup(void);
extern void __iomem *socfpga_scu_base_addr;
extern void socfpga_init_clocks(void);
@@ -29,6 +29,8 @@ extern void socfpga_sysmgr_init(void);
extern struct smp_operations socfpga_smp_ops;
extern char secondary_trampoline, secondary_trampoline_end;
+extern unsigned long cpu1start_addr;
+
#define SOCFPGA_SCU_VIRT_BASE 0xfffec000
#endif
diff --git a/arch/arm/mach-socfpga/headsmp.S b/arch/arm/mach-socfpga/headsmp.S
index f09b1283ffca..9004bfb1756e 100644
--- a/arch/arm/mach-socfpga/headsmp.S
+++ b/arch/arm/mach-socfpga/headsmp.S
@@ -13,13 +13,21 @@
__CPUINIT
.arch armv7-a
-#define CPU1_START_ADDR 0xffd08010
-
ENTRY(secondary_trampoline)
- movw r0, #:lower16:CPU1_START_ADDR
- movt r0, #:upper16:CPU1_START_ADDR
+ movw r2, #:lower16:cpu1start_addr
+ movt r2, #:upper16:cpu1start_addr
+
+ /* The socfpga VT cannot handle a 0xC0000000 page offset when loading
+ the cpu1start_addr, we bit clear it. Tested on HW and VT. */
+ bic r2, r2, #0x40000000
+ ldr r0, [r2]
ldr r1, [r0]
bx r1
ENTRY(secondary_trampoline_end)
+
+ENTRY(socfpga_secondary_startup)
+ bl v7_invalidate_l1
+ b secondary_startup
+ENDPROC(socfpga_secondary_startup)
diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c
index 68dd1b69512a..84c60fa8daa0 100644
--- a/arch/arm/mach-socfpga/platsmp.c
+++ b/arch/arm/mach-socfpga/platsmp.c
@@ -22,9 +22,9 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/cacheflush.h>
-#include <asm/hardware/gic.h>
#include <asm/smp_scu.h>
#include <asm/smp_plat.h>
@@ -47,16 +47,19 @@ static int __cpuinit socfpga_boot_secondary(unsigned int cpu, struct task_struct
{
int trampoline_size = &secondary_trampoline_end - &secondary_trampoline;
- memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size);
+ if (cpu1start_addr) {
+ memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size);
- __raw_writel(virt_to_phys(secondary_startup), (sys_manager_base_addr+0x10));
+ __raw_writel(virt_to_phys(socfpga_secondary_startup),
+ (sys_manager_base_addr + (cpu1start_addr & 0x000000ff)));
- flush_cache_all();
- smp_wmb();
- outer_clean_range(0, trampoline_size);
+ flush_cache_all();
+ smp_wmb();
+ outer_clean_range(0, trampoline_size);
- /* This will release CPU #1 out of reset.*/
- __raw_writel(0, rst_manager_base_addr + 0x10);
+ /* This will release CPU #1 out of reset.*/
+ __raw_writel(0, rst_manager_base_addr + 0x10);
+ }
return 0;
}
@@ -83,8 +86,6 @@ static void __init socfpga_smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c
index 6732924a5fee..1042c023cf24 100644
--- a/arch/arm/mach-socfpga/socfpga.c
+++ b/arch/arm/mach-socfpga/socfpga.c
@@ -15,12 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/dw_apb_timer.h>
+#include <linux/irqchip.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -29,6 +29,7 @@
void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE));
void __iomem *sys_manager_base_addr;
void __iomem *rst_manager_base_addr;
+unsigned long cpu1start_addr;
static struct map_desc scu_io_desc __initdata = {
.virtual = SOCFPGA_SCU_VIRT_BASE,
@@ -62,25 +63,25 @@ static void __init socfpga_map_io(void)
early_printk("Early printk initialized\n");
}
-const static struct of_device_id irq_match[] = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- {}
-};
-
void __init socfpga_sysmgr_init(void)
{
struct device_node *np;
np = of_find_compatible_node(NULL, NULL, "altr,sys-mgr");
+
+ if (of_property_read_u32(np, "cpu1-start-addr",
+ (u32 *) &cpu1start_addr))
+ pr_err("SMP: Need cpu1-start-addr in device tree.\n");
+
sys_manager_base_addr = of_iomap(np, 0);
np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr");
rst_manager_base_addr = of_iomap(np, 0);
}
-static void __init gic_init_irq(void)
+static void __init socfpga_init_irq(void)
{
- of_irq_init(irq_match);
+ irqchip_init();
socfpga_sysmgr_init();
}
@@ -98,16 +99,14 @@ static void __init socfpga_cyclone5_init(void)
static const char *altera_dt_match[] = {
"altr,socfpga",
- "altr,socfpga-cyclone5",
NULL
};
DT_MACHINE_START(SOCFPGA, "Altera SOCFPGA")
.smp = smp_ops(socfpga_smp_ops),
.map_io = socfpga_map_io,
- .init_irq = gic_init_irq,
- .handle_irq = gic_handle_irq,
- .timer = &dw_apb_timer,
+ .init_irq = socfpga_init_irq,
+ .init_time = dw_apb_timer_init,
.init_machine = socfpga_cyclone5_init,
.restart = socfpga_cyclone5_restart,
.dt_compat = altera_dt_match,
diff --git a/arch/arm/mach-spear13xx/include/mach/generic.h b/arch/arm/mach-spear13xx/include/mach/generic.h
index c33f4d9361bd..633e678e01a3 100644
--- a/arch/arm/mach-spear13xx/include/mach/generic.h
+++ b/arch/arm/mach-spear13xx/include/mach/generic.h
@@ -18,7 +18,7 @@
#include <asm/mach/time.h>
/* Add spear13xx structure declarations here */
-extern struct sys_timer spear13xx_timer;
+extern void spear13xx_timer_init(void);
extern struct pl022_ssp_controller pl022_plat_data;
extern struct dw_dma_platform_data dmac_plat_data;
extern struct dw_dma_slave cf_dma_priv;
@@ -28,7 +28,6 @@ extern struct dw_dma_slave nand_write_dma_priv;
/* Add spear13xx family function declarations here */
void __init spear_setup_of_timer(void);
void __init spear13xx_map_io(void);
-void __init spear13xx_dt_init_irq(void);
void __init spear13xx_l2x0_init(void);
bool dw_dma_filter(struct dma_chan *chan, void *slave);
void spear_restart(char, const char *);
diff --git a/arch/arm/mach-spear13xx/platsmp.c b/arch/arm/mach-spear13xx/platsmp.c
index 2eaa3fa7b432..af4ade61cd95 100644
--- a/arch/arm/mach-spear13xx/platsmp.c
+++ b/arch/arm/mach-spear13xx/platsmp.c
@@ -15,8 +15,8 @@
#include <linux/jiffies.h>
#include <linux/io.h>
#include <linux/smp.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/cacheflush.h>
-#include <asm/hardware/gic.h>
#include <asm/smp_scu.h>
#include <mach/spear.h>
#include <mach/generic.h>
@@ -104,8 +104,6 @@ static void __init spear13xx_smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
static void __init spear13xx_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-spear13xx/spear1310.c b/arch/arm/mach-spear13xx/spear1310.c
index 02f4724bb0d4..56214d1076ef 100644
--- a/arch/arm/mach-spear13xx/spear1310.c
+++ b/arch/arm/mach-spear13xx/spear1310.c
@@ -14,9 +14,9 @@
#define pr_fmt(fmt) "SPEAr1310: " fmt
#include <linux/amba/pl022.h>
+#include <linux/irqchip.h>
#include <linux/of_platform.h>
#include <linux/pata_arasan_cf_data.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/generic.h>
@@ -90,9 +90,8 @@ static void __init spear1310_map_io(void)
DT_MACHINE_START(SPEAR1310_DT, "ST SPEAr1310 SoC with Flattened Device Tree")
.smp = smp_ops(spear13xx_smp_ops),
.map_io = spear1310_map_io,
- .init_irq = spear13xx_dt_init_irq,
- .handle_irq = gic_handle_irq,
- .timer = &spear13xx_timer,
+ .init_irq = irqchip_init,
+ .init_time = spear13xx_timer_init,
.init_machine = spear1310_dt_init,
.restart = spear_restart,
.dt_compat = spear1310_dt_board_compat,
diff --git a/arch/arm/mach-spear13xx/spear1340.c b/arch/arm/mach-spear13xx/spear1340.c
index 081014fb314a..9a28beb2a113 100644
--- a/arch/arm/mach-spear13xx/spear1340.c
+++ b/arch/arm/mach-spear13xx/spear1340.c
@@ -18,7 +18,7 @@
#include <linux/delay.h>
#include <linux/dw_dmac.h>
#include <linux/of_platform.h>
-#include <asm/hardware/gic.h>
+#include <linux/irqchip.h>
#include <asm/mach/arch.h>
#include <mach/dma.h>
#include <mach/generic.h>
@@ -184,9 +184,8 @@ static const char * const spear1340_dt_board_compat[] = {
DT_MACHINE_START(SPEAR1340_DT, "ST SPEAr1340 SoC with Flattened Device Tree")
.smp = smp_ops(spear13xx_smp_ops),
.map_io = spear13xx_map_io,
- .init_irq = spear13xx_dt_init_irq,
- .handle_irq = gic_handle_irq,
- .timer = &spear13xx_timer,
+ .init_irq = irqchip_init,
+ .init_time = spear13xx_timer_init,
.init_machine = spear1340_dt_init,
.restart = spear_restart,
.dt_compat = spear1340_dt_board_compat,
diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c
index c4af775a8451..c7d2b4a8d8cc 100644
--- a/arch/arm/mach-spear13xx/spear13xx.c
+++ b/arch/arm/mach-spear13xx/spear13xx.c
@@ -17,9 +17,8 @@
#include <linux/clk.h>
#include <linux/dw_dmac.h>
#include <linux/err.h>
-#include <linux/of_irq.h>
+#include <linux/of.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
#include <asm/smp_twd.h>
#include <mach/dma.h>
@@ -153,7 +152,7 @@ static void __init spear13xx_clk_init(void)
pr_err("%s: Unknown machine\n", __func__);
}
-static void __init spear13xx_timer_init(void)
+void __init spear13xx_timer_init(void)
{
char pclk_name[] = "osc_24m_clk";
struct clk *gpt_clk, *pclk;
@@ -182,17 +181,3 @@ static void __init spear13xx_timer_init(void)
spear_setup_of_timer();
twd_local_timer_of_register();
}
-
-struct sys_timer spear13xx_timer = {
- .init = spear13xx_timer_init,
-};
-
-static const struct of_device_id gic_of_match[] __initconst = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init },
- { /* Sentinel */ }
-};
-
-void __init spear13xx_dt_init_irq(void)
-{
- of_irq_init(gic_of_match);
-}
diff --git a/arch/arm/mach-spear3xx/include/mach/generic.h b/arch/arm/mach-spear3xx/include/mach/generic.h
index ce19113ca791..df310799e416 100644
--- a/arch/arm/mach-spear3xx/include/mach/generic.h
+++ b/arch/arm/mach-spear3xx/include/mach/generic.h
@@ -22,7 +22,7 @@
#include <asm/mach/map.h>
/* Add spear3xx family device structure declarations here */
-extern struct sys_timer spear3xx_timer;
+extern void spear3xx_timer_init(void);
extern struct pl022_ssp_controller pl022_plat_data;
extern struct pl08x_platform_data pl080_plat_data;
@@ -30,7 +30,6 @@ extern struct pl08x_platform_data pl080_plat_data;
void __init spear_setup_of_timer(void);
void __init spear3xx_clk_init(void);
void __init spear3xx_map_io(void);
-void __init spear3xx_dt_init_irq(void);
void spear_restart(char, const char *);
diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c
index a69cbfdb07ee..bbc9b7e9c62c 100644
--- a/arch/arm/mach-spear3xx/spear300.c
+++ b/arch/arm/mach-spear3xx/spear300.c
@@ -14,8 +14,8 @@
#define pr_fmt(fmt) "SPEAr300: " fmt
#include <linux/amba/pl08x.h>
+#include <linux/irqchip.h>
#include <linux/of_platform.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <mach/generic.h>
#include <mach/spear.h>
@@ -212,9 +212,8 @@ static void __init spear300_map_io(void)
DT_MACHINE_START(SPEAR300_DT, "ST SPEAr300 SoC with Flattened Device Tree")
.map_io = spear300_map_io,
- .init_irq = spear3xx_dt_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &spear3xx_timer,
+ .init_irq = irqchip_init,
+ .init_time = spear3xx_timer_init,
.init_machine = spear300_dt_init,
.restart = spear_restart,
.dt_compat = spear300_dt_board_compat,
diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c
index b963ebb10b56..c13a434a8195 100644
--- a/arch/arm/mach-spear3xx/spear310.c
+++ b/arch/arm/mach-spear3xx/spear310.c
@@ -15,8 +15,8 @@
#include <linux/amba/pl08x.h>
#include <linux/amba/serial.h>
+#include <linux/irqchip.h>
#include <linux/of_platform.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <mach/generic.h>
#include <mach/spear.h>
@@ -254,9 +254,8 @@ static void __init spear310_map_io(void)
DT_MACHINE_START(SPEAR310_DT, "ST SPEAr310 SoC with Flattened Device Tree")
.map_io = spear310_map_io,
- .init_irq = spear3xx_dt_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &spear3xx_timer,
+ .init_irq = irqchip_init,
+ .init_time = spear3xx_timer_init,
.init_machine = spear310_dt_init,
.restart = spear_restart,
.dt_compat = spear310_dt_board_compat,
diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c
index 66e3a0c33e75..e1c77079a3e5 100644
--- a/arch/arm/mach-spear3xx/spear320.c
+++ b/arch/arm/mach-spear3xx/spear320.c
@@ -16,8 +16,8 @@
#include <linux/amba/pl022.h>
#include <linux/amba/pl08x.h>
#include <linux/amba/serial.h>
+#include <linux/irqchip.h>
#include <linux/of_platform.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <mach/generic.h>
#include <mach/spear.h>
@@ -268,9 +268,8 @@ static void __init spear320_map_io(void)
DT_MACHINE_START(SPEAR320_DT, "ST SPEAr320 SoC with Flattened Device Tree")
.map_io = spear320_map_io,
- .init_irq = spear3xx_dt_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &spear3xx_timer,
+ .init_irq = irqchip_init,
+ .init_time = spear3xx_timer_init,
.init_machine = spear320_dt_init,
.restart = spear_restart,
.dt_compat = spear320_dt_board_compat,
diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c
index 38fe95db31a7..b2ba516ca2d4 100644
--- a/arch/arm/mach-spear3xx/spear3xx.c
+++ b/arch/arm/mach-spear3xx/spear3xx.c
@@ -15,11 +15,8 @@
#include <linux/amba/pl022.h>
#include <linux/amba/pl08x.h>
-#include <linux/irqchip/spear-shirq.h>
-#include <linux/of_irq.h>
#include <linux/io.h>
#include <asm/hardware/pl080.h>
-#include <asm/hardware/vic.h>
#include <plat/pl080.h>
#include <mach/generic.h>
#include <mach/spear.h>
@@ -87,7 +84,7 @@ void __init spear3xx_map_io(void)
iotable_init(spear3xx_io_desc, ARRAY_SIZE(spear3xx_io_desc));
}
-static void __init spear3xx_timer_init(void)
+void __init spear3xx_timer_init(void)
{
char pclk_name[] = "pll3_clk";
struct clk *gpt_clk, *pclk;
@@ -115,20 +112,3 @@ static void __init spear3xx_timer_init(void)
spear_setup_of_timer();
}
-
-struct sys_timer spear3xx_timer = {
- .init = spear3xx_timer_init,
-};
-
-static const struct of_device_id vic_of_match[] __initconst = {
- { .compatible = "arm,pl190-vic", .data = vic_of_init, },
- { .compatible = "st,spear300-shirq", .data = spear300_shirq_of_init, },
- { .compatible = "st,spear310-shirq", .data = spear310_shirq_of_init, },
- { .compatible = "st,spear320-shirq", .data = spear320_shirq_of_init, },
- { /* Sentinel */ }
-};
-
-void __init spear3xx_dt_init_irq(void)
-{
- of_irq_init(vic_of_match);
-}
diff --git a/arch/arm/mach-spear6xx/spear6xx.c b/arch/arm/mach-spear6xx/spear6xx.c
index 5a5a52db252b..b8bd33ca88bd 100644
--- a/arch/arm/mach-spear6xx/spear6xx.c
+++ b/arch/arm/mach-spear6xx/spear6xx.c
@@ -16,12 +16,11 @@
#include <linux/amba/pl08x.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/irqchip.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <asm/hardware/pl080.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/mach/map.h>
@@ -374,7 +373,7 @@ void __init spear6xx_map_io(void)
iotable_init(spear6xx_io_desc, ARRAY_SIZE(spear6xx_io_desc));
}
-static void __init spear6xx_timer_init(void)
+void __init spear6xx_timer_init(void)
{
char pclk_name[] = "pll3_clk";
struct clk *gpt_clk, *pclk;
@@ -403,10 +402,6 @@ static void __init spear6xx_timer_init(void)
spear_setup_of_timer();
}
-struct sys_timer spear6xx_timer = {
- .init = spear6xx_timer_init,
-};
-
/* Add auxdata to pass platform data */
struct of_dev_auxdata spear6xx_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("arm,pl080", SPEAR6XX_ICM3_DMA_BASE, NULL,
@@ -425,21 +420,10 @@ static const char *spear600_dt_board_compat[] = {
NULL
};
-static const struct of_device_id vic_of_match[] __initconst = {
- { .compatible = "arm,pl190-vic", .data = vic_of_init, },
- { /* Sentinel */ }
-};
-
-static void __init spear6xx_dt_init_irq(void)
-{
- of_irq_init(vic_of_match);
-}
-
DT_MACHINE_START(SPEAR600_DT, "ST SPEAr600 (Flattened Device Tree)")
.map_io = spear6xx_map_io,
- .init_irq = spear6xx_dt_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &spear6xx_timer,
+ .init_irq = irqchip_init,
+ .init_time = spear6xx_timer_init,
.init_machine = spear600_dt_init,
.restart = spear_restart,
.dt_compat = spear600_dt_board_compat,
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 3fdd0085e306..8709a39bd34c 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -7,3 +7,4 @@ config ARCH_SUNXI
select PINCTRL
select SPARSE_IRQ
select SUNXI_TIMER
+ select PINCTRL_SUNXI \ No newline at end of file
diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
index 1dc8a92e5a5f..23afb732cb40 100644
--- a/arch/arm/mach-sunxi/sunxi.c
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -21,15 +21,16 @@
#include <linux/irqchip/sunxi.h>
-#include <asm/hardware/vic.h>
-
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "sunxi.h"
#define WATCHDOG_CTRL_REG 0x00
+#define WATCHDOG_CTRL_RESTART (1 << 0)
#define WATCHDOG_MODE_REG 0x04
+#define WATCHDOG_MODE_ENABLE (1 << 0)
+#define WATCHDOG_MODE_RESET_ENABLE (1 << 1)
static void __iomem *wdt_base;
@@ -50,11 +51,19 @@ static void sunxi_restart(char mode, const char *cmd)
return;
/* Enable timer and set reset bit in the watchdog */
- writel(3, wdt_base + WATCHDOG_MODE_REG);
- writel(0xa57 << 1 | 1, wdt_base + WATCHDOG_CTRL_REG);
- while(1) {
+ writel(WATCHDOG_MODE_ENABLE | WATCHDOG_MODE_RESET_ENABLE,
+ wdt_base + WATCHDOG_MODE_REG);
+
+ /*
+ * Restart the watchdog. The default (and lowest) interval
+ * value for the watchdog is 0.5s.
+ */
+ writel(WATCHDOG_CTRL_RESTART, wdt_base + WATCHDOG_CTRL_REG);
+
+ while (1) {
mdelay(5);
- writel(3, wdt_base + WATCHDOG_MODE_REG);
+ writel(WATCHDOG_MODE_ENABLE | WATCHDOG_MODE_RESET_ENABLE,
+ wdt_base + WATCHDOG_MODE_REG);
}
}
@@ -91,6 +100,6 @@ DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)")
.init_irq = sunxi_init_irq,
.handle_irq = sunxi_handle_irq,
.restart = sunxi_restart,
- .timer = &sunxi_timer,
+ .init_time = &sunxi_timer_init,
.dt_compat = sunxi_board_dt_compat,
MACHINE_END
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index b442f15fd01a..d1c4893894ce 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -4,11 +4,11 @@ comment "NVIDIA Tegra options"
config ARCH_TEGRA_2x_SOC
bool "Enable support for Tegra20 family"
- select ARCH_REQUIRE_GPIOLIB
+ select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
select ARM_ERRATA_720789
- select ARM_ERRATA_742230
+ select ARM_ERRATA_742230 if SMP
select ARM_ERRATA_751472
- select ARM_ERRATA_754327
+ select ARM_ERRATA_754327 if SMP
select ARM_ERRATA_764369 if SMP
select ARM_GIC
select CPU_FREQ_TABLE if CPU_FREQ
@@ -26,7 +26,6 @@ config ARCH_TEGRA_2x_SOC
config ARCH_TEGRA_3x_SOC
bool "Enable support for Tegra30 family"
- select ARCH_REQUIRE_GPIOLIB
select ARM_ERRATA_743622
select ARM_ERRATA_751472
select ARM_ERRATA_754322
@@ -44,6 +43,18 @@ config ARCH_TEGRA_3x_SOC
Support for NVIDIA Tegra T30 processor family, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
+config ARCH_TEGRA_114_SOC
+ bool "Enable support for Tegra114 family"
+ select ARM_ARCH_TIMER
+ select ARM_GIC
+ select ARM_L1_CACHE_SHIFT_6
+ select CPU_V7
+ select PINCTRL
+ select PINCTRL_TEGRA114
+ help
+ Support for NVIDIA Tegra T114 processor family, based on the
+ ARM CortexA15MP CPU
+
config TEGRA_PCI
bool "PCI Express support"
depends on ARCH_TEGRA_2x_SOC
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 0979e8bba78a..f6b46ae2b7f8 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -1,39 +1,38 @@
obj-y += common.o
obj-y += io.o
obj-y += irq.o
-obj-y += clock.o
-obj-y += timer.o
obj-y += fuse.o
obj-y += pmc.o
obj-y += flowctrl.o
obj-y += powergate.o
obj-y += apbio.o
obj-y += pm.o
+obj-y += reset.o
+obj-y += reset-handler.o
+obj-y += sleep.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
-obj-$(CONFIG_CPU_IDLE) += sleep.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o
ifeq ($(CONFIG_CPU_IDLE),y)
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o
endif
-obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
-obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o
ifeq ($(CONFIG_CPU_IDLE),y)
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o
endif
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
-obj-$(CONFIG_SMP) += reset.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
obj-$(CONFIG_TEGRA_PCI) += pcie.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o
+obj-$(CONFIG_ARCH_TEGRA_114_SOC) += board-dt-tegra114.o
+ifeq ($(CONFIG_CPU_IDLE),y)
+obj-$(CONFIG_ARCH_TEGRA_114_SOC) += cpuidle-tegra114.o
+endif
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-harmony-pcie.o
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
index d091675ba376..d7aa52ea6cfc 100644
--- a/arch/arm/mach-tegra/apbio.c
+++ b/arch/arm/mach-tegra/apbio.c
@@ -38,7 +38,7 @@ static void tegra_apb_writel_direct(u32 value, unsigned long offset);
static struct dma_chan *tegra_apb_dma_chan;
static struct dma_slave_config dma_sconfig;
-bool tegra_apb_dma_init(void)
+static bool tegra_apb_dma_init(void)
{
dma_cap_mask_t mask;
diff --git a/arch/arm/mach-tegra/board-dt-tegra114.c b/arch/arm/mach-tegra/board-dt-tegra114.c
new file mode 100644
index 000000000000..085d63637b62
--- /dev/null
+++ b/arch/arm/mach-tegra/board-dt-tegra114.c
@@ -0,0 +1,46 @@
+/*
+ * NVIDIA Tegra114 device tree board support
+ *
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * 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/of.h>
+#include <linux/of_platform.h>
+#include <linux/clocksource.h>
+
+#include <asm/mach/arch.h>
+
+#include "board.h"
+#include "common.h"
+
+static void __init tegra114_dt_init(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char * const tegra114_dt_board_compat[] = {
+ "nvidia,tegra114",
+ NULL,
+};
+
+DT_MACHINE_START(TEGRA114_DT, "NVIDIA Tegra114 (Flattened Device Tree)")
+ .smp = smp_ops(tegra_smp_ops),
+ .map_io = tegra_map_common_io,
+ .init_early = tegra114_init_early,
+ .init_irq = tegra_dt_init_irq,
+ .init_time = clocksource_of_init,
+ .init_machine = tegra114_dt_init,
+ .init_late = tegra_init_late,
+ .restart = tegra_assert_system_reset,
+ .dt_compat = tegra114_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index 734d9cc87f2e..a0edf2510280 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -15,6 +15,7 @@
*
*/
+#include <linux/clocksource.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
@@ -25,7 +26,6 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
-#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/pda_power.h>
#include <linux/platform_data/tegra_usb.h>
@@ -34,106 +34,51 @@
#include <linux/i2c-tegra.h>
#include <linux/usb/tegra_usb_phy.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/setup.h>
#include "board.h"
-#include "clock.h"
#include "common.h"
#include "iomap.h"
-struct tegra_ehci_platform_data tegra_ehci1_pdata = {
+static struct tegra_ehci_platform_data tegra_ehci1_pdata = {
.operating_mode = TEGRA_USB_OTG,
.power_down_on_bus_suspend = 1,
.vbus_gpio = -1,
};
-struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = {
+static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = {
.reset_gpio = -1,
.clk = "cdev2",
};
-struct tegra_ehci_platform_data tegra_ehci2_pdata = {
+static struct tegra_ehci_platform_data tegra_ehci2_pdata = {
.phy_config = &tegra_ehci2_ulpi_phy_config,
.operating_mode = TEGRA_USB_HOST,
.power_down_on_bus_suspend = 1,
.vbus_gpio = -1,
};
-struct tegra_ehci_platform_data tegra_ehci3_pdata = {
+static struct tegra_ehci_platform_data tegra_ehci3_pdata = {
.operating_mode = TEGRA_USB_HOST,
.power_down_on_bus_suspend = 1,
.vbus_gpio = -1,
};
-struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC4_BASE, "sdhci-tegra.3", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C_BASE, "tegra-i2c.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2c-dvc", TEGRA_DVC_BASE, "tegra-i2c.3", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra20-i2s.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra20-i2s.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra20-das", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0",
+static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5000000, "tegra-ehci.0",
&tegra_ehci1_pdata),
- OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1",
+ OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5004000, "tegra-ehci.1",
&tegra_ehci2_pdata),
- OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2",
+ OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5008000, "tegra-ehci.2",
&tegra_ehci3_pdata),
- OF_DEV_AUXDATA("nvidia,tegra20-apbdma", TEGRA_APB_DMA_BASE, "tegra-apbdma", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-sflash", 0x7000c380, "spi", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D400, "spi_tegra.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D600, "spi_tegra.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D800, "spi_tegra.2", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000DA00, "spi_tegra.3", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-host1x", 0x50000000, "host1x", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54200000, "tegradc.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54240000, "tegradc.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-hdmi", 0x54280000, "hdmi", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-dsi", 0x54300000, "dsi", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-tvo", 0x542c0000, "tvo", NULL),
{}
};
-static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
- /* name parent rate enabled */
- { "uarta", "pll_p", 216000000, true },
- { "uartd", "pll_p", 216000000, true },
- { "usbd", "clk_m", 12000000, false },
- { "usb2", "clk_m", 12000000, false },
- { "usb3", "clk_m", 12000000, false },
- { "pll_a", "pll_p_out1", 56448000, true },
- { "pll_a_out0", "pll_a", 11289600, true },
- { "cdev1", NULL, 0, true },
- { "blink", "clk_32k", 32768, true },
- { "i2s1", "pll_a_out0", 11289600, false},
- { "i2s2", "pll_a_out0", 11289600, false},
- { "sdmmc1", "pll_p", 48000000, false},
- { "sdmmc3", "pll_p", 48000000, false},
- { "sdmmc4", "pll_p", 48000000, false},
- { "spi", "pll_p", 20000000, false },
- { "sbc1", "pll_p", 100000000, false },
- { "sbc2", "pll_p", 100000000, false },
- { "sbc3", "pll_p", 100000000, false },
- { "sbc4", "pll_p", 100000000, false },
- { "host1x", "pll_c", 150000000, false },
- { "disp1", "pll_p", 600000000, false },
- { "disp2", "pll_p", 600000000, false },
- { NULL, NULL, 0, 0},
-};
-
static void __init tegra_dt_init(void)
{
- tegra_clk_init_from_table(tegra_dt_clk_init_table);
-
/*
* Finished with the static registrations now; fill in the missing
* devices
@@ -202,8 +147,7 @@ DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)")
.smp = smp_ops(tegra_smp_ops),
.init_early = tegra20_init_early,
.init_irq = tegra_dt_init_irq,
- .handle_irq = gic_handle_irq,
- .timer = &tegra_sys_timer,
+ .init_time = clocksource_of_init,
.init_machine = tegra_dt_init,
.init_late = tegra_dt_init_late,
.restart = tegra_assert_system_reset,
diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c
index 6497d1236b08..bf68567e549d 100644
--- a/arch/arm/mach-tegra/board-dt-tegra30.c
+++ b/arch/arm/mach-tegra/board-dt-tegra30.c
@@ -23,6 +23,7 @@
*
*/
+#include <linux/clocksource.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -31,75 +32,14 @@
#include <linux/of_platform.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include "board.h"
-#include "clock.h"
#include "common.h"
#include "iomap.h"
-struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000200, "sdhci-tegra.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000400, "sdhci-tegra.2", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000600, "sdhci-tegra.3", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C000, "tegra-i2c.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C400, "tegra-i2c.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D400, "spi_tegra.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D600, "spi_tegra.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D800, "spi_tegra.2", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DA00, "spi_tegra.3", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DC00, "spi_tegra.4", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DE00, "spi_tegra.5", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-host1x", 0x50000000, "host1x", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54200000, "tegradc.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54240000, "tegradc.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-hdmi", 0x54280000, "hdmi", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-dsi", 0x54300000, "dsi", NULL),
- OF_DEV_AUXDATA("nvidia,tegra30-tvo", 0x542c0000, "tvo", NULL),
- {}
-};
-
-static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
- /* name parent rate enabled */
- { "uarta", "pll_p", 408000000, true },
- { "pll_a", "pll_p_out1", 564480000, true },
- { "pll_a_out0", "pll_a", 11289600, true },
- { "extern1", "pll_a_out0", 0, true },
- { "clk_out_1", "extern1", 0, true },
- { "blink", "clk_32k", 32768, true },
- { "i2s0", "pll_a_out0", 11289600, false},
- { "i2s1", "pll_a_out0", 11289600, false},
- { "i2s2", "pll_a_out0", 11289600, false},
- { "i2s3", "pll_a_out0", 11289600, false},
- { "i2s4", "pll_a_out0", 11289600, false},
- { "sdmmc1", "pll_p", 48000000, false},
- { "sdmmc3", "pll_p", 48000000, false},
- { "sdmmc4", "pll_p", 48000000, false},
- { "sbc1", "pll_p", 100000000, false},
- { "sbc2", "pll_p", 100000000, false},
- { "sbc3", "pll_p", 100000000, false},
- { "sbc4", "pll_p", 100000000, false},
- { "sbc5", "pll_p", 100000000, false},
- { "sbc6", "pll_p", 100000000, false},
- { "host1x", "pll_c", 150000000, false},
- { "disp1", "pll_p", 600000000, false},
- { "disp2", "pll_p", 600000000, false},
- { NULL, NULL, 0, 0},
-};
-
static void __init tegra30_dt_init(void)
{
- tegra_clk_init_from_table(tegra_dt_clk_init_table);
-
- of_platform_populate(NULL, of_default_bus_match_table,
- tegra30_auxdata_lookup, NULL);
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
static const char *tegra30_dt_board_compat[] = {
@@ -112,8 +52,7 @@ DT_MACHINE_START(TEGRA30_DT, "NVIDIA Tegra30 (Flattened Device Tree)")
.map_io = tegra_map_common_io,
.init_early = tegra30_init_early,
.init_irq = tegra_dt_init_irq,
- .handle_irq = gic_handle_irq,
- .timer = &tegra_sys_timer,
+ .init_time = clocksource_of_init,
.init_machine = tegra30_dt_init,
.init_late = tegra_init_late,
.restart = tegra_assert_system_reset,
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 91fbe733a21e..86851c81a350 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -1,6 +1,7 @@
/*
* arch/arm/mach-tegra/board.h
*
+ * Copyright (c) 2013 NVIDIA Corporation. All rights reserved.
* Copyright (C) 2010 Google, Inc.
*
* Author:
@@ -27,6 +28,7 @@ void tegra_assert_system_reset(char mode, const char *cmd);
void __init tegra20_init_early(void);
void __init tegra30_init_early(void);
+void __init tegra114_init_early(void);
void __init tegra_map_common_io(void);
void __init tegra_init_irq(void);
void __init tegra_dt_init_irq(void);
@@ -55,5 +57,4 @@ static inline int harmony_pcie_init(void) { return 0; }
void __init tegra_paz00_wifikill_init(void);
-extern struct sys_timer tegra_sys_timer;
#endif
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
deleted file mode 100644
index 867bf8bf5561..000000000000
--- a/arch/arm/mach-tegra/clock.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * Author:
- * Colin Cross <ccross@google.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/kernel.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-
-#include "board.h"
-#include "clock.h"
-#include "tegra_cpu_car.h"
-
-/* Global data of Tegra CPU CAR ops */
-struct tegra_cpu_car_ops *tegra_cpu_car_ops;
-
-/*
- * Locking:
- *
- * An additional mutex, clock_list_lock, is used to protect the list of all
- * clocks.
- *
- */
-static DEFINE_MUTEX(clock_list_lock);
-static LIST_HEAD(clocks);
-
-void tegra_clk_add(struct clk *clk)
-{
- struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk));
-
- mutex_lock(&clock_list_lock);
- list_add(&c->node, &clocks);
- mutex_unlock(&clock_list_lock);
-}
-
-struct clk *tegra_get_clock_by_name(const char *name)
-{
- struct clk_tegra *c;
- struct clk *ret = NULL;
- mutex_lock(&clock_list_lock);
- list_for_each_entry(c, &clocks, node) {
- if (strcmp(__clk_get_name(c->hw.clk), name) == 0) {
- ret = c->hw.clk;
- break;
- }
- }
- mutex_unlock(&clock_list_lock);
- return ret;
-}
-
-static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
-{
- struct clk *c;
- struct clk *p;
- struct clk *parent;
-
- int ret = 0;
-
- c = tegra_get_clock_by_name(table->name);
-
- if (!c) {
- pr_warn("Unable to initialize clock %s\n",
- table->name);
- return -ENODEV;
- }
-
- parent = clk_get_parent(c);
-
- if (table->parent) {
- p = tegra_get_clock_by_name(table->parent);
- if (!p) {
- pr_warn("Unable to find parent %s of clock %s\n",
- table->parent, table->name);
- return -ENODEV;
- }
-
- if (parent != p) {
- ret = clk_set_parent(c, p);
- if (ret) {
- pr_warn("Unable to set parent %s of clock %s: %d\n",
- table->parent, table->name, ret);
- return -EINVAL;
- }
- }
- }
-
- if (table->rate && table->rate != clk_get_rate(c)) {
- ret = clk_set_rate(c, table->rate);
- if (ret) {
- pr_warn("Unable to set clock %s to rate %lu: %d\n",
- table->name, table->rate, ret);
- return -EINVAL;
- }
- }
-
- if (table->enabled) {
- ret = clk_prepare_enable(c);
- if (ret) {
- pr_warn("Unable to enable clock %s: %d\n",
- table->name, ret);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-void tegra_clk_init_from_table(struct tegra_clk_init_table *table)
-{
- for (; table->name; table++)
- tegra_clk_init_one_from_table(table);
-}
-
-void tegra_periph_reset_deassert(struct clk *c)
-{
- struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
- BUG_ON(!clk->reset);
- clk->reset(__clk_get_hw(c), false);
-}
-EXPORT_SYMBOL(tegra_periph_reset_deassert);
-
-void tegra_periph_reset_assert(struct clk *c)
-{
- struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
- BUG_ON(!clk->reset);
- clk->reset(__clk_get_hw(c), true);
-}
-EXPORT_SYMBOL(tegra_periph_reset_assert);
-
-/* Several extended clock configuration bits (e.g., clock routing, clock
- * phase control) are included in PLL and peripheral clock source
- * registers. */
-int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
-{
- int ret = 0;
- struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
-
- if (!clk->clk_cfg_ex) {
- ret = -ENOSYS;
- goto out;
- }
- ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting);
-
-out:
- return ret;
-}
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
deleted file mode 100644
index 2aa37f5c44c0..000000000000
--- a/arch/arm/mach-tegra/clock.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/clock.h
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * Author:
- * Colin Cross <ccross@google.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 __MACH_TEGRA_CLOCK_H
-#define __MACH_TEGRA_CLOCK_H
-
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include <linux/list.h>
-
-#include <mach/clk.h>
-
-#define DIV_BUS (1 << 0)
-#define DIV_U71 (1 << 1)
-#define DIV_U71_FIXED (1 << 2)
-#define DIV_2 (1 << 3)
-#define DIV_U16 (1 << 4)
-#define PLL_FIXED (1 << 5)
-#define PLL_HAS_CPCON (1 << 6)
-#define MUX (1 << 7)
-#define PLLD (1 << 8)
-#define PERIPH_NO_RESET (1 << 9)
-#define PERIPH_NO_ENB (1 << 10)
-#define PERIPH_EMC_ENB (1 << 11)
-#define PERIPH_MANUAL_RESET (1 << 12)
-#define PLL_ALT_MISC_REG (1 << 13)
-#define PLLU (1 << 14)
-#define PLLX (1 << 15)
-#define MUX_PWM (1 << 16)
-#define MUX8 (1 << 17)
-#define DIV_U71_UART (1 << 18)
-#define MUX_CLK_OUT (1 << 19)
-#define PLLM (1 << 20)
-#define DIV_U71_INT (1 << 21)
-#define DIV_U71_IDLE (1 << 22)
-#define ENABLE_ON_INIT (1 << 28)
-#define PERIPH_ON_APB (1 << 29)
-
-struct clk_tegra;
-#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw)
-
-struct clk_mux_sel {
- struct clk *input;
- u32 value;
-};
-
-struct clk_pll_freq_table {
- unsigned long input_rate;
- unsigned long output_rate;
- u16 n;
- u16 m;
- u8 p;
- u8 cpcon;
-};
-
-enum clk_state {
- UNINITIALIZED = 0,
- ON,
- OFF,
-};
-
-struct clk_tegra {
- /* node for master clocks list */
- struct list_head node; /* node for list of all clocks */
- struct clk_lookup lookup;
- struct clk_hw hw;
-
- bool set;
- unsigned long fixed_rate;
- unsigned long max_rate;
- unsigned long min_rate;
- u32 flags;
- const char *name;
-
- enum clk_state state;
- u32 div;
- u32 mul;
-
- u32 reg;
- u32 reg_shift;
-
- struct list_head shared_bus_list;
-
- union {
- struct {
- unsigned int clk_num;
- } periph;
- struct {
- unsigned long input_min;
- unsigned long input_max;
- unsigned long cf_min;
- unsigned long cf_max;
- unsigned long vco_min;
- unsigned long vco_max;
- const struct clk_pll_freq_table *freq_table;
- int lock_delay;
- unsigned long fixed_rate;
- } pll;
- struct {
- u32 sel;
- u32 reg_mask;
- } mux;
- struct {
- struct clk *main;
- struct clk *backup;
- } cpu;
- struct {
- struct list_head node;
- bool enabled;
- unsigned long rate;
- } shared_bus_user;
- } u;
-
- void (*reset)(struct clk_hw *, bool);
- int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32);
-};
-
-struct clk_duplicate {
- const char *name;
- struct clk_lookup lookup;
-};
-
-struct tegra_clk_init_table {
- const char *name;
- const char *parent;
- unsigned long rate;
- bool enabled;
-};
-
-void tegra_clk_add(struct clk *c);
-void tegra2_init_clocks(void);
-void tegra30_init_clocks(void);
-struct clk *tegra_get_clock_by_name(const char *name);
-void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
-
-#endif
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index d54cfc54b9fe..5449a3f2977b 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -1,6 +1,7 @@
/*
* arch/arm/mach-tegra/common.c
*
+ * Copyright (c) 2013 NVIDIA Corporation. All rights reserved.
* Copyright (C) 2010 Google, Inc.
*
* Author:
@@ -21,15 +22,14 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/of_irq.h>
+#include <linux/irqchip.h>
+#include <linux/clk/tegra.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/gic.h>
#include <mach/powergate.h>
#include "board.h"
-#include "clock.h"
#include "common.h"
#include "fuse.h"
#include "iomap.h"
@@ -37,6 +37,7 @@
#include "apbio.h"
#include "sleep.h"
#include "pm.h"
+#include "reset.h"
/*
* Storage for debug-macro.S's state.
@@ -57,15 +58,11 @@ u32 tegra_uart_config[4] = {
};
#ifdef CONFIG_OF
-static const struct of_device_id tegra_dt_irq_match[] __initconst = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init },
- { }
-};
-
void __init tegra_dt_init_irq(void)
{
+ tegra_clocks_init();
tegra_init_irq();
- of_irq_init(tegra_dt_irq_match);
+ irqchip_init();
}
#endif
@@ -79,43 +76,6 @@ void tegra_assert_system_reset(char mode, const char *cmd)
writel_relaxed(reg, reset);
}
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-static __initdata struct tegra_clk_init_table tegra20_clk_init_table[] = {
- /* name parent rate enabled */
- { "clk_m", NULL, 0, true },
- { "pll_p", "clk_m", 216000000, true },
- { "pll_p_out1", "pll_p", 28800000, true },
- { "pll_p_out2", "pll_p", 48000000, true },
- { "pll_p_out3", "pll_p", 72000000, true },
- { "pll_p_out4", "pll_p", 24000000, true },
- { "pll_c", "clk_m", 600000000, true },
- { "pll_c_out1", "pll_c", 120000000, true },
- { "sclk", "pll_c_out1", 120000000, true },
- { "hclk", "sclk", 120000000, true },
- { "pclk", "hclk", 60000000, true },
- { "csite", NULL, 0, true },
- { "emc", NULL, 0, true },
- { "cpu", NULL, 0, true },
- { NULL, NULL, 0, 0},
-};
-#endif
-
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
-static __initdata struct tegra_clk_init_table tegra30_clk_init_table[] = {
- /* name parent rate enabled */
- { "clk_m", NULL, 0, true },
- { "pll_p", "pll_ref", 408000000, true },
- { "pll_p_out1", "pll_p", 9600000, true },
- { "pll_p_out4", "pll_p", 102000000, true },
- { "sclk", "pll_p_out4", 102000000, true },
- { "hclk", "sclk", 102000000, true },
- { "pclk", "hclk", 51000000, true },
- { "csite", NULL, 0, true },
- { NULL, NULL, 0, 0},
-};
-#endif
-
-
static void __init tegra_init_cache(void)
{
#ifdef CONFIG_CACHE_L2X0
@@ -134,33 +94,39 @@ static void __init tegra_init_cache(void)
}
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-void __init tegra20_init_early(void)
+static void __init tegra_init_early(void)
{
+ tegra_cpu_reset_handler_init();
tegra_apb_io_init();
tegra_init_fuse();
- tegra2_init_clocks();
- tegra_clk_init_from_table(tegra20_clk_init_table);
tegra_init_cache();
tegra_pmc_init();
tegra_powergate_init();
+}
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+void __init tegra20_init_early(void)
+{
+ tegra_init_early();
tegra20_hotplug_init();
}
#endif
+
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
void __init tegra30_init_early(void)
{
- tegra_apb_io_init();
- tegra_init_fuse();
- tegra30_init_clocks();
- tegra_clk_init_from_table(tegra30_clk_init_table);
- tegra_init_cache();
- tegra_pmc_init();
- tegra_powergate_init();
+ tegra_init_early();
tegra30_hotplug_init();
}
#endif
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+void __init tegra114_init_early(void)
+{
+ tegra_init_early();
+}
+#endif
+
void __init tegra_init_late(void)
{
tegra_powergate_debugfs_init();
diff --git a/arch/arm/mach-tegra/common.h b/arch/arm/mach-tegra/common.h
index 02f71b4f1e51..32f8eb3fe344 100644
--- a/arch/arm/mach-tegra/common.h
+++ b/arch/arm/mach-tegra/common.h
@@ -1,4 +1,5 @@
extern struct smp_operations tegra_smp_ops;
+extern int tegra_cpu_kill(unsigned int cpu);
extern void tegra_cpu_die(unsigned int cpu);
extern int tegra_cpu_disable(unsigned int cpu);
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index a74d3c7d2e26..e3d6e15ff188 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -214,24 +214,6 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu >= NUM_CPUS)
return -EINVAL;
- cpu_clk = clk_get_sys(NULL, "cpu");
- if (IS_ERR(cpu_clk))
- return PTR_ERR(cpu_clk);
-
- pll_x_clk = clk_get_sys(NULL, "pll_x");
- if (IS_ERR(pll_x_clk))
- return PTR_ERR(pll_x_clk);
-
- pll_p_clk = clk_get_sys(NULL, "pll_p");
- if (IS_ERR(pll_p_clk))
- return PTR_ERR(pll_p_clk);
-
- emc_clk = clk_get_sys("cpu", "emc");
- if (IS_ERR(emc_clk)) {
- clk_put(cpu_clk);
- return PTR_ERR(emc_clk);
- }
-
clk_prepare_enable(emc_clk);
clk_prepare_enable(cpu_clk);
@@ -243,8 +225,7 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
/* FIXME: what's the actual transition time? */
policy->cpuinfo.transition_latency = 300 * 1000;
- policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
- cpumask_copy(policy->related_cpus, cpu_possible_mask);
+ cpumask_copy(policy->cpus, cpu_possible_mask);
if (policy->cpu == 0)
register_pm_notifier(&tegra_cpu_pm_notifier);
@@ -256,8 +237,6 @@ static int tegra_cpu_exit(struct cpufreq_policy *policy)
{
cpufreq_frequency_table_cpuinfo(policy, freq_table);
clk_disable_unprepare(emc_clk);
- clk_put(emc_clk);
- clk_put(cpu_clk);
return 0;
}
@@ -278,12 +257,32 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
static int __init tegra_cpufreq_init(void)
{
+ cpu_clk = clk_get_sys(NULL, "cpu");
+ if (IS_ERR(cpu_clk))
+ return PTR_ERR(cpu_clk);
+
+ pll_x_clk = clk_get_sys(NULL, "pll_x");
+ if (IS_ERR(pll_x_clk))
+ return PTR_ERR(pll_x_clk);
+
+ pll_p_clk = clk_get_sys(NULL, "pll_p_cclk");
+ if (IS_ERR(pll_p_clk))
+ return PTR_ERR(pll_p_clk);
+
+ emc_clk = clk_get_sys("cpu", "emc");
+ if (IS_ERR(emc_clk)) {
+ clk_put(cpu_clk);
+ return PTR_ERR(emc_clk);
+ }
+
return cpufreq_register_driver(&tegra_cpufreq_driver);
}
static void __exit tegra_cpufreq_exit(void)
{
cpufreq_unregister_driver(&tegra_cpufreq_driver);
+ clk_put(emc_clk);
+ clk_put(cpu_clk);
}
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c
new file mode 100644
index 000000000000..0f4e8c483b34
--- /dev/null
+++ b/arch/arm/mach-tegra/cpuidle-tegra114.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cpuidle.h>
+
+#include <asm/cpuidle.h>
+
+static struct cpuidle_driver tegra_idle_driver = {
+ .name = "tegra_idle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
+ .state_count = 1,
+ .states = {
+ [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
+ },
+};
+
+static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
+
+int __init tegra114_cpuidle_init(void)
+{
+ int ret;
+ unsigned int cpu;
+ struct cpuidle_device *dev;
+ struct cpuidle_driver *drv = &tegra_idle_driver;
+
+ ret = cpuidle_register_driver(&tegra_idle_driver);
+ if (ret) {
+ pr_err("CPUidle driver registration failed\n");
+ return ret;
+ }
+
+ for_each_possible_cpu(cpu) {
+ dev = &per_cpu(tegra_idle_device, cpu);
+ dev->cpu = cpu;
+
+ dev->state_count = drv->state_count;
+ ret = cpuidle_register_device(dev);
+ if (ret) {
+ pr_err("CPU%u: CPUidle device registration failed\n",
+ cpu);
+ return ret;
+ }
+ }
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
index d32e8b0dbd4f..825ced4f7a40 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra20.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
@@ -22,21 +22,199 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
+#include <linux/clockchips.h>
+#include <linux/clk/tegra.h>
#include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+#include <asm/suspend.h>
+#include <asm/smp_plat.h>
+
+#include "pm.h"
+#include "sleep.h"
+#include "iomap.h"
+#include "irq.h"
+#include "flowctrl.h"
+
+#ifdef CONFIG_PM_SLEEP
+static bool abort_flag;
+static atomic_t abort_barrier;
+static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index);
+#endif
+
+static struct cpuidle_state tegra_idle_states[] = {
+ [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
+#ifdef CONFIG_PM_SLEEP
+ [1] = {
+ .enter = tegra20_idle_lp2_coupled,
+ .exit_latency = 5000,
+ .target_residency = 10000,
+ .power_usage = 0,
+ .flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_COUPLED,
+ .name = "powered-down",
+ .desc = "CPU power gated",
+ },
+#endif
+};
static struct cpuidle_driver tegra_idle_driver = {
.name = "tegra_idle",
.owner = THIS_MODULE,
.en_core_tk_irqen = 1,
- .state_count = 1,
- .states = {
- [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
- },
};
static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
+#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_SMP
+static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
+
+static int tegra20_reset_sleeping_cpu_1(void)
+{
+ int ret = 0;
+
+ tegra_pen_lock();
+
+ if (readl(pmc + PMC_SCRATCH41) == CPU_RESETTABLE)
+ tegra20_cpu_shutdown(1);
+ else
+ ret = -EINVAL;
+
+ tegra_pen_unlock();
+
+ return ret;
+}
+
+static void tegra20_wake_cpu1_from_reset(void)
+{
+ tegra_pen_lock();
+
+ tegra20_cpu_clear_resettable();
+
+ /* enable cpu clock on cpu */
+ tegra_enable_cpu_clock(1);
+
+ /* take the CPU out of reset */
+ tegra_cpu_out_of_reset(1);
+
+ /* unhalt the cpu */
+ flowctrl_write_cpu_halt(1, 0);
+
+ tegra_pen_unlock();
+}
+
+static int tegra20_reset_cpu_1(void)
+{
+ if (!cpu_online(1) || !tegra20_reset_sleeping_cpu_1())
+ return 0;
+
+ tegra20_wake_cpu1_from_reset();
+ return -EBUSY;
+}
+#else
+static inline void tegra20_wake_cpu1_from_reset(void)
+{
+}
+
+static inline int tegra20_reset_cpu_1(void)
+{
+ return 0;
+}
+#endif
+
+static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ struct cpuidle_state *state = &drv->states[index];
+ u32 cpu_on_time = state->exit_latency;
+ u32 cpu_off_time = state->target_residency - state->exit_latency;
+
+ while (tegra20_cpu_is_resettable_soon())
+ cpu_relax();
+
+ if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready())
+ return false;
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
+
+ tegra_idle_lp2_last(cpu_on_time, cpu_off_time);
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
+
+ if (cpu_online(1))
+ tegra20_wake_cpu1_from_reset();
+
+ return true;
+}
+
+#ifdef CONFIG_SMP
+static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
+
+ cpu_suspend(0, tegra20_sleep_cpu_secondary_finish);
+
+ tegra20_cpu_clear_resettable();
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
+
+ return true;
+}
+#else
+static inline bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ return true;
+}
+#endif
+
+static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu;
+ bool entered_lp2 = false;
+
+ if (tegra_pending_sgi())
+ ACCESS_ONCE(abort_flag) = true;
+
+ cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
+
+ if (abort_flag) {
+ cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
+ abort_flag = false; /* clean flag for next coming */
+ return -EINTR;
+ }
+
+ local_fiq_disable();
+
+ tegra_set_cpu_in_lp2(cpu);
+ cpu_pm_enter();
+
+ if (cpu == 0)
+ entered_lp2 = tegra20_cpu_cluster_power_down(dev, drv, index);
+ else
+ entered_lp2 = tegra20_idle_enter_lp2_cpu_1(dev, drv, index);
+
+ cpu_pm_exit();
+ tegra_clear_cpu_in_lp2(cpu);
+
+ local_fiq_enable();
+
+ smp_rmb();
+
+ return entered_lp2 ? index : 0;
+}
+#endif
+
int __init tegra20_cpuidle_init(void)
{
int ret;
@@ -44,6 +222,14 @@ int __init tegra20_cpuidle_init(void)
struct cpuidle_device *dev;
struct cpuidle_driver *drv = &tegra_idle_driver;
+#ifdef CONFIG_PM_SLEEP
+ tegra_tear_down_cpu = tegra20_tear_down_cpu;
+#endif
+
+ drv->state_count = ARRAY_SIZE(tegra_idle_states);
+ memcpy(drv->states, tegra_idle_states,
+ drv->state_count * sizeof(drv->states[0]));
+
ret = cpuidle_register_driver(&tegra_idle_driver);
if (ret) {
pr_err("CPUidle driver registration failed\n");
@@ -53,6 +239,9 @@ int __init tegra20_cpuidle_init(void)
for_each_possible_cpu(cpu) {
dev = &per_cpu(tegra_idle_device, cpu);
dev->cpu = cpu;
+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+ dev->coupled_cpus = *cpu_possible_mask;
+#endif
dev->state_count = drv->state_count;
ret = cpuidle_register_device(dev);
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
index 5e8cbf5b799f..8b50cf4ddd6f 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra30.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
@@ -24,6 +24,7 @@
#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
#include <linux/clockchips.h>
+#include <linux/clk/tegra.h>
#include <asm/cpuidle.h>
#include <asm/proc-fns.h>
@@ -32,7 +33,6 @@
#include "pm.h"
#include "sleep.h"
-#include "tegra_cpu_car.h"
#ifdef CONFIG_PM_SLEEP
static int tegra30_idle_lp2(struct cpuidle_device *dev,
@@ -121,9 +121,9 @@ static inline bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
}
#endif
-static int __cpuinit tegra30_idle_lp2(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
+static int tegra30_idle_lp2(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
{
u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu;
bool entered_lp2 = false;
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
index d0651397aec7..4b744c4661e2 100644
--- a/arch/arm/mach-tegra/cpuidle.c
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -38,6 +38,9 @@ static int __init tegra_cpuidle_init(void)
case TEGRA30:
ret = tegra30_cpuidle_init();
break;
+ case TEGRA114:
+ ret = tegra114_cpuidle_init();
+ break;
default:
ret = -ENODEV;
break;
diff --git a/arch/arm/mach-tegra/cpuidle.h b/arch/arm/mach-tegra/cpuidle.h
index 496204d34e55..d733f75d0208 100644
--- a/arch/arm/mach-tegra/cpuidle.h
+++ b/arch/arm/mach-tegra/cpuidle.h
@@ -29,4 +29,10 @@ int tegra30_cpuidle_init(void);
static inline int tegra30_cpuidle_init(void) { return -ENODEV; }
#endif
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+int tegra114_cpuidle_init(void);
+#else
+static inline int tegra114_cpuidle_init(void) { return -ENODEV; }
+#endif
+
#endif
diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c
index a2250ddae797..b477ef310dcd 100644
--- a/arch/arm/mach-tegra/flowctrl.c
+++ b/arch/arm/mach-tegra/flowctrl.c
@@ -25,15 +25,16 @@
#include "flowctrl.h"
#include "iomap.h"
+#include "fuse.h"
-u8 flowctrl_offset_halt_cpu[] = {
+static u8 flowctrl_offset_halt_cpu[] = {
FLOW_CTRL_HALT_CPU0_EVENTS,
FLOW_CTRL_HALT_CPU1_EVENTS,
FLOW_CTRL_HALT_CPU1_EVENTS + 8,
FLOW_CTRL_HALT_CPU1_EVENTS + 16,
};
-u8 flowctrl_offset_cpu_csr[] = {
+static u8 flowctrl_offset_cpu_csr[] = {
FLOW_CTRL_CPU0_CSR,
FLOW_CTRL_CPU1_CSR,
FLOW_CTRL_CPU1_CSR + 8,
@@ -75,11 +76,26 @@ void flowctrl_cpu_suspend_enter(unsigned int cpuid)
int i;
reg = flowctrl_read_cpu_csr(cpuid);
- reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP; /* clear wfe bitmap */
- reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP; /* clear wfi bitmap */
+ switch (tegra_chip_id) {
+ case TEGRA20:
+ /* clear wfe bitmap */
+ reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
+ /* clear wfi bitmap */
+ reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
+ /* pwr gating on wfe */
+ reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
+ break;
+ case TEGRA30:
+ /* clear wfe bitmap */
+ reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
+ /* clear wfi bitmap */
+ reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
+ /* pwr gating on wfi */
+ reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
+ break;
+ }
reg |= FLOW_CTRL_CSR_INTR_FLAG; /* clear intr flag */
reg |= FLOW_CTRL_CSR_EVENT_FLAG; /* clear event flag */
- reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid; /* pwr gating on wfi */
reg |= FLOW_CTRL_CSR_ENABLE; /* pwr gating */
flowctrl_write_cpu_csr(cpuid, reg);
@@ -99,8 +115,20 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid)
/* Disable powergating via flow controller for CPU0 */
reg = flowctrl_read_cpu_csr(cpuid);
- reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP; /* clear wfe bitmap */
- reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP; /* clear wfi bitmap */
+ switch (tegra_chip_id) {
+ case TEGRA20:
+ /* clear wfe bitmap */
+ reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP;
+ /* clear wfi bitmap */
+ reg &= ~TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP;
+ break;
+ case TEGRA30:
+ /* clear wfe bitmap */
+ reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
+ /* clear wfi bitmap */
+ reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
+ break;
+ }
reg &= ~FLOW_CTRL_CSR_ENABLE; /* clear enable */
reg |= FLOW_CTRL_CSR_INTR_FLAG; /* clear intr */
reg |= FLOW_CTRL_CSR_EVENT_FLAG; /* clear event */
diff --git a/arch/arm/mach-tegra/flowctrl.h b/arch/arm/mach-tegra/flowctrl.h
index 0798dec1832d..67eab56699bd 100644
--- a/arch/arm/mach-tegra/flowctrl.h
+++ b/arch/arm/mach-tegra/flowctrl.h
@@ -34,6 +34,10 @@
#define FLOW_CTRL_HALT_CPU1_EVENTS 0x14
#define FLOW_CTRL_CPU1_CSR 0x18
+#define TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 (1 << 4)
+#define TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP (3 << 4)
+#define TEGRA20_FLOW_CTRL_CSR_WFI_BITMAP 0
+
#define TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 (1 << 8)
#define TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP (0xF << 4)
#define TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP (0xF << 8)
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index 8121742711fe..f7db0782a6b6 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/export.h>
+#include <linux/tegra-soc.h>
#include "fuse.h"
#include "iomap.h"
@@ -105,6 +106,11 @@ static void tegra_get_process_id(void)
tegra_core_process_id = (reg >> 12) & 3;
}
+u32 tegra_read_chipid(void)
+{
+ return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
+}
+
void tegra_init_fuse(void)
{
u32 id;
@@ -119,7 +125,7 @@ void tegra_init_fuse(void)
reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
- id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
+ id = tegra_read_chipid();
tegra_chip_id = (id >> 8) & 0xff;
switch (tegra_chip_id) {
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index ff1383dd61a7..da78434678c7 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -37,6 +37,7 @@ enum tegra_revision {
#define TEGRA20 0x20
#define TEGRA30 0x30
+#define TEGRA114 0x35
extern int tegra_sku_id;
extern int tegra_cpu_process_id;
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index 4a317fae6860..fd473f2b4c3d 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -1,66 +1,9 @@
#include <linux/linkage.h>
#include <linux/init.h>
-#include <asm/cache.h>
-#include <asm/asm-offsets.h>
-#include <asm/hardware/cache-l2x0.h>
-
-#include "flowctrl.h"
-#include "iomap.h"
-#include "reset.h"
#include "sleep.h"
-#define APB_MISC_GP_HIDREV 0x804
-#define PMC_SCRATCH41 0x140
-
-#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
-
.section ".text.head", "ax"
- __CPUINIT
-
-/*
- * Tegra specific entry point for secondary CPUs.
- * The secondary kernel init calls v7_flush_dcache_all before it enables
- * the L1; however, the L1 comes out of reset in an undefined state, so
- * the clean + invalidate performed by v7_flush_dcache_all causes a bunch
- * of cache lines with uninitialized data and uninitialized tags to get
- * written out to memory, which does really unpleasant things to the main
- * processor. We fix this by performing an invalidate, rather than a
- * clean + invalidate, before jumping into the kernel.
- */
-ENTRY(v7_invalidate_l1)
- mov r0, #0
- mcr p15, 2, r0, c0, c0, 0
- mrc p15, 1, r0, c0, c0, 0
-
- ldr r1, =0x7fff
- and r2, r1, r0, lsr #13
-
- ldr r1, =0x3ff
-
- and r3, r1, r0, lsr #3 @ NumWays - 1
- add r2, r2, #1 @ NumSets
-
- and r0, r0, #0x7
- add r0, r0, #4 @ SetShift
-
- clz r1, r3 @ WayShift
- add r4, r3, #1 @ NumWays
-1: sub r2, r2, #1 @ NumSets--
- mov r3, r4 @ Temp = NumWays
-2: subs r3, r3, #1 @ Temp--
- mov r5, r3, lsl r1
- mov r6, r2, lsl r0
- orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
- mcr p15, 0, r5, c7, c6, 2
- bgt 2b
- cmp r2, #0
- bgt 1b
- dsb
- isb
- mov pc, lr
-ENDPROC(v7_invalidate_l1)
-
ENTRY(tegra_secondary_startup)
bl v7_invalidate_l1
@@ -69,210 +12,3 @@ ENTRY(tegra_secondary_startup)
mcr p14, 0, r0, c7, c12, 6
b secondary_startup
ENDPROC(tegra_secondary_startup)
-
-#ifdef CONFIG_PM_SLEEP
-/*
- * tegra_resume
- *
- * CPU boot vector when restarting the a CPU following
- * an LP2 transition. Also branched to by LP0 and LP1 resume after
- * re-enabling sdram.
- */
-ENTRY(tegra_resume)
- bl v7_invalidate_l1
- /* Enable coresight */
- mov32 r0, 0xC5ACCE55
- mcr p14, 0, r0, c7, c12, 6
-
- cpu_id r0
- cmp r0, #0 @ CPU0?
- bne cpu_resume @ no
-
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
- /* Are we on Tegra20? */
- mov32 r6, TEGRA_APB_MISC_BASE
- ldr r0, [r6, #APB_MISC_GP_HIDREV]
- and r0, r0, #0xff00
- cmp r0, #(0x20 << 8)
- beq 1f @ Yes
- /* Clear the flow controller flags for this CPU. */
- mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR
- ldr r1, [r2]
- /* Clear event & intr flag */
- orr r1, r1, \
- #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
- movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps
- bic r1, r1, r0
- str r1, [r2]
-1:
-#endif
-
-#ifdef CONFIG_HAVE_ARM_SCU
- /* enable SCU */
- mov32 r0, TEGRA_ARM_PERIF_BASE
- ldr r1, [r0]
- orr r1, r1, #1
- str r1, [r0]
-#endif
-
- /* L2 cache resume & re-enable */
- l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr
-
- b cpu_resume
-ENDPROC(tegra_resume)
-#endif
-
-#ifdef CONFIG_CACHE_L2X0
- .globl l2x0_saved_regs_addr
-l2x0_saved_regs_addr:
- .long 0
-#endif
-
- .align L1_CACHE_SHIFT
-ENTRY(__tegra_cpu_reset_handler_start)
-
-/*
- * __tegra_cpu_reset_handler:
- *
- * Common handler for all CPU reset events.
- *
- * Register usage within the reset handler:
- *
- * R7 = CPU present (to the OS) mask
- * R8 = CPU in LP1 state mask
- * R9 = CPU in LP2 state mask
- * R10 = CPU number
- * R11 = CPU mask
- * R12 = pointer to reset handler data
- *
- * NOTE: This code is copied to IRAM. All code and data accesses
- * must be position-independent.
- */
-
- .align L1_CACHE_SHIFT
-ENTRY(__tegra_cpu_reset_handler)
-
- cpsid aif, 0x13 @ SVC mode, interrupts disabled
- mrc p15, 0, r10, c0, c0, 5 @ MPIDR
- and r10, r10, #0x3 @ R10 = CPU number
- mov r11, #1
- mov r11, r11, lsl r10 @ R11 = CPU mask
- adr r12, __tegra_cpu_reset_handler_data
-
-#ifdef CONFIG_SMP
- /* Does the OS know about this CPU? */
- ldr r7, [r12, #RESET_DATA(MASK_PRESENT)]
- tst r7, r11 @ if !present
- bleq __die @ CPU not present (to OS)
-#endif
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- /* Are we on Tegra20? */
- mov32 r6, TEGRA_APB_MISC_BASE
- ldr r0, [r6, #APB_MISC_GP_HIDREV]
- and r0, r0, #0xff00
- cmp r0, #(0x20 << 8)
- bne 1f
- /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
- mov32 r6, TEGRA_PMC_BASE
- mov r0, #0
- cmp r10, #0
- strne r0, [r6, #PMC_SCRATCH41]
-1:
-#endif
-
- /* Waking up from LP2? */
- ldr r9, [r12, #RESET_DATA(MASK_LP2)]
- tst r9, r11 @ if in_lp2
- beq __is_not_lp2
- ldr lr, [r12, #RESET_DATA(STARTUP_LP2)]
- cmp lr, #0
- bleq __die @ no LP2 startup handler
- bx lr
-
-__is_not_lp2:
-
-#ifdef CONFIG_SMP
- /*
- * Can only be secondary boot (initial or hotplug) but CPU 0
- * cannot be here.
- */
- cmp r10, #0
- bleq __die @ CPU0 cannot be here
- ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
- cmp lr, #0
- bleq __die @ no secondary startup handler
- bx lr
-#endif
-
-/*
- * We don't know why the CPU reset. Just kill it.
- * The LR register will contain the address we died at + 4.
- */
-
-__die:
- sub lr, lr, #4
- mov32 r7, TEGRA_PMC_BASE
- str lr, [r7, #PMC_SCRATCH41]
-
- mov32 r7, TEGRA_CLK_RESET_BASE
-
- /* Are we on Tegra20? */
- mov32 r6, TEGRA_APB_MISC_BASE
- ldr r0, [r6, #APB_MISC_GP_HIDREV]
- and r0, r0, #0xff00
- cmp r0, #(0x20 << 8)
- bne 1f
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- mov32 r0, 0x1111
- mov r1, r0, lsl r10
- str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET
-#endif
-1:
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
- mov32 r6, TEGRA_FLOW_CTRL_BASE
-
- cmp r10, #0
- moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS
- moveq r2, #FLOW_CTRL_CPU0_CSR
- movne r1, r10, lsl #3
- addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
- addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
-
- /* Clear CPU "event" and "interrupt" flags and power gate
- it when halting but not before it is in the "WFI" state. */
- ldr r0, [r6, +r2]
- orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
- orr r0, r0, #FLOW_CTRL_CSR_ENABLE
- str r0, [r6, +r2]
-
- /* Unconditionally halt this CPU */
- mov r0, #FLOW_CTRL_WAITEVENT
- str r0, [r6, +r1]
- ldr r0, [r6, +r1] @ memory barrier
-
- dsb
- isb
- wfi @ CPU should be power gated here
-
- /* If the CPU didn't power gate above just kill it's clock. */
-
- mov r0, r11, lsl #8
- str r0, [r7, #348] @ CLK_CPU_CMPLX_SET
-#endif
-
- /* If the CPU still isn't dead, just spin here. */
- b .
-ENDPROC(__tegra_cpu_reset_handler)
-
- .align L1_CACHE_SHIFT
- .type __tegra_cpu_reset_handler_data, %object
- .globl __tegra_cpu_reset_handler_data
-__tegra_cpu_reset_handler_data:
- .rept TEGRA_RESET_DATA_SIZE
- .long 0
- .endr
- .align L1_CACHE_SHIFT
-
-ENTRY(__tegra_cpu_reset_handler_end)
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index dca5141a2c31..a599f6e36dea 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -10,15 +10,26 @@
*/
#include <linux/kernel.h>
#include <linux/smp.h>
+#include <linux/clk/tegra.h>
#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
#include "sleep.h"
-#include "tegra_cpu_car.h"
static void (*tegra_hotplug_shutdown)(void);
+int tegra_cpu_kill(unsigned cpu)
+{
+ cpu = cpu_logical_map(cpu);
+
+ /* Clock gate the CPU */
+ tegra_wait_cpu_in_reset(cpu);
+ tegra_disable_cpu_clock(cpu);
+
+ return 1;
+}
+
/*
* platform-specific code to shutdown a CPU
*
@@ -26,18 +37,12 @@ static void (*tegra_hotplug_shutdown)(void);
*/
void __ref tegra_cpu_die(unsigned int cpu)
{
- cpu = cpu_logical_map(cpu);
-
- /* Flush the L1 data cache. */
- flush_cache_all();
+ /* Clean L1 data cache */
+ tegra_disable_clean_inv_dcache();
/* Shut down the current CPU. */
tegra_hotplug_shutdown();
- /* Clock gate the CPU */
- tegra_wait_cpu_in_reset(cpu);
- tegra_disable_cpu_clock(cpu);
-
/* Should never return here. */
BUG();
}
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
deleted file mode 100644
index 95f3a547c770..000000000000
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/clk.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- * Erik Gilling <konkers@google.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 __MACH_CLK_H
-#define __MACH_CLK_H
-
-struct clk;
-
-enum tegra_clk_ex_param {
- TEGRA_CLK_VI_INP_SEL,
- TEGRA_CLK_DTV_INVERT,
- TEGRA_CLK_NAND_PAD_DIV2_ENB,
- TEGRA_CLK_PLLD_CSI_OUT_ENB,
- TEGRA_CLK_PLLD_DSI_OUT_ENB,
- TEGRA_CLK_PLLD_MIPI_MUX_SEL,
-};
-
-void tegra_periph_reset_deassert(struct clk *c);
-void tegra_periph_reset_assert(struct clk *c);
-
-#ifndef CONFIG_COMMON_CLK
-unsigned long clk_get_rate_all_locked(struct clk *c);
-#endif
-
-void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
-int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h
index 485003f9b636..08386418196f 100644
--- a/arch/arm/mach-tegra/include/mach/uncompress.h
+++ b/arch/arm/mach-tegra/include/mach/uncompress.h
@@ -172,8 +172,4 @@ static inline void arch_decomp_setup(void)
uart[UART_LCR << DEBUG_UART_SHIFT] = 3;
}
-static inline void arch_decomp_wdog(void)
-{
-}
-
#endif
diff --git a/arch/arm/mach-tegra/iomap.h b/arch/arm/mach-tegra/iomap.h
index db8be51cad80..399fbca27102 100644
--- a/arch/arm/mach-tegra/iomap.h
+++ b/arch/arm/mach-tegra/iomap.h
@@ -240,15 +240,6 @@
#define TEGRA_CSITE_BASE 0x70040000
#define TEGRA_CSITE_SIZE SZ_256K
-#define TEGRA_USB_BASE 0xC5000000
-#define TEGRA_USB_SIZE SZ_16K
-
-#define TEGRA_USB2_BASE 0xC5004000
-#define TEGRA_USB2_SIZE SZ_16K
-
-#define TEGRA_USB3_BASE 0xC5008000
-#define TEGRA_USB3_SIZE SZ_16K
-
#define TEGRA_SDMMC1_BASE 0xC8000000
#define TEGRA_SDMMC1_SIZE SZ_512
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index b7886f183511..1952e82797cc 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -22,8 +22,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/of.h>
-
-#include <asm/hardware/gic.h>
+#include <linux/irqchip/arm-gic.h>
#include "board.h"
#include "iomap.h"
@@ -45,6 +44,8 @@
#define FIRST_LEGACY_IRQ 32
+#define SGI_MASK 0xFFFF
+
static int num_ictlrs;
static void __iomem *ictlr_reg_base[] = {
@@ -55,6 +56,19 @@ static void __iomem *ictlr_reg_base[] = {
IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
};
+bool tegra_pending_sgi(void)
+{
+ u32 pending_set;
+ void __iomem *distbase = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE);
+
+ pending_set = readl_relaxed(distbase + GIC_DIST_PENDING_SET);
+
+ if (pending_set & SGI_MASK)
+ return true;
+
+ return false;
+}
+
static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
{
void __iomem *base;
diff --git a/arch/arm/mach-tegra/irq.h b/arch/arm/mach-tegra/irq.h
new file mode 100644
index 000000000000..5142649bba05
--- /dev/null
+++ b/arch/arm/mach-tegra/irq.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TEGRA_IRQ_H
+#define __TEGRA_IRQ_H
+
+bool tegra_pending_sgi(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index bffcd643d7a3..b60165f1ca02 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -33,11 +33,11 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/export.h>
+#include <linux/clk/tegra.h>
#include <asm/sizes.h>
#include <asm/mach/pci.h>
-#include <mach/clk.h>
#include <mach/powergate.h>
#include "board.h"
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 1b926df99c4b..2c6b3d55213b 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -18,25 +18,26 @@
#include <linux/jiffies.h>
#include <linux/smp.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/clk/tegra.h>
#include <asm/cacheflush.h>
-#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <asm/smp_scu.h>
+#include <asm/smp_plat.h>
#include <mach/powergate.h>
#include "fuse.h"
#include "flowctrl.h"
#include "reset.h"
-#include "tegra_cpu_car.h"
#include "common.h"
#include "iomap.h"
extern void tegra_secondary_startup(void);
-static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
+static cpumask_t tegra_cpu_init_mask;
#define EVP_CPU_RESET_VECTOR \
(IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
@@ -50,6 +51,7 @@ static void __cpuinit tegra_secondary_init(unsigned int cpu)
*/
gic_secondary_init(0);
+ cpumask_set_cpu(cpu, &tegra_cpu_init_mask);
}
static int tegra20_power_up_cpu(unsigned int cpu)
@@ -72,14 +74,42 @@ static int tegra30_power_up_cpu(unsigned int cpu)
if (pwrgateid < 0)
return pwrgateid;
- /* If this is the first boot, toggle powergates directly. */
+ /*
+ * The power up sequence of cold boot CPU and warm boot CPU
+ * was different.
+ *
+ * For warm boot CPU that was resumed from CPU hotplug, the
+ * power will be resumed automatically after un-halting the
+ * flow controller of the warm boot CPU. We need to wait for
+ * the confirmaiton that the CPU is powered then removing
+ * the IO clamps.
+ * For cold boot CPU, do not wait. After the cold boot CPU be
+ * booted, it will run to tegra_secondary_init() and set
+ * tegra_cpu_init_mask which influences what tegra30_power_up_cpu()
+ * next time around.
+ */
+ if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) {
+ timeout = jiffies + msecs_to_jiffies(50);
+ do {
+ if (!tegra_powergate_is_powered(pwrgateid))
+ goto remove_clamps;
+ udelay(10);
+ } while (time_before(jiffies, timeout));
+ }
+
+ /*
+ * The power status of the cold boot CPU is power gated as
+ * default. To power up the cold boot CPU, the power should
+ * be un-gated by un-toggling the power gate register
+ * manually.
+ */
if (!tegra_powergate_is_powered(pwrgateid)) {
ret = tegra_powergate_power_on(pwrgateid);
if (ret)
return ret;
/* Wait for the power to come up. */
- timeout = jiffies + 10*HZ;
+ timeout = jiffies + msecs_to_jiffies(100);
while (tegra_powergate_is_powered(pwrgateid)) {
if (time_after(jiffies, timeout))
return -ETIMEDOUT;
@@ -87,6 +117,7 @@ static int tegra30_power_up_cpu(unsigned int cpu)
}
}
+remove_clamps:
/* CPU partition is powered. Enable the CPU clock. */
tegra_enable_cpu_clock(cpu);
udelay(10);
@@ -105,6 +136,8 @@ static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct *
{
int status;
+ cpu = cpu_logical_map(cpu);
+
/*
* Force the CPU into reset. The CPU must remain in reset when the
* flow controller state is cleared (which will cause the flow
@@ -143,38 +176,21 @@ done:
return status;
}
-/*
- * Initialise the CPU possible map early - this describes the CPUs
- * which may be present or become present in the system.
- */
-static void __init tegra_smp_init_cpus(void)
-{
- unsigned int i, ncores = scu_get_core_count(scu_base);
-
- if (ncores > nr_cpu_ids) {
- pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
- ncores, nr_cpu_ids);
- ncores = nr_cpu_ids;
- }
-
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
-}
-
static void __init tegra_smp_prepare_cpus(unsigned int max_cpus)
{
- tegra_cpu_reset_handler_init();
- scu_enable(scu_base);
+ /* Always mark the boot CPU (CPU0) as initialized. */
+ cpumask_set_cpu(0, &tegra_cpu_init_mask);
+
+ if (scu_a9_has_base())
+ scu_enable(IO_ADDRESS(scu_a9_get_base()));
}
struct smp_operations tegra_smp_ops __initdata = {
- .smp_init_cpus = tegra_smp_init_cpus,
.smp_prepare_cpus = tegra_smp_prepare_cpus,
.smp_secondary_init = tegra_secondary_init,
.smp_boot_secondary = tegra_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_kill = tegra_cpu_kill,
.cpu_die = tegra_cpu_die,
.cpu_disable = tegra_cpu_disable,
#endif
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index 1b11707eaca0..523604de666f 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -24,6 +24,7 @@
#include <linux/cpu_pm.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/clk/tegra.h>
#include <asm/smp_plat.h>
#include <asm/cacheflush.h>
@@ -35,8 +36,8 @@
#include "iomap.h"
#include "reset.h"
#include "flowctrl.h"
+#include "fuse.h"
#include "sleep.h"
-#include "tegra_cpu_car.h"
#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
@@ -148,7 +149,7 @@ static void suspend_cpu_complex(void)
save_cpu_arch_register();
}
-void __cpuinit tegra_clear_cpu_in_lp2(int phy_cpu_id)
+void tegra_clear_cpu_in_lp2(int phy_cpu_id)
{
u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
@@ -160,7 +161,7 @@ void __cpuinit tegra_clear_cpu_in_lp2(int phy_cpu_id)
spin_unlock(&tegra_lp2_lock);
}
-bool __cpuinit tegra_set_cpu_in_lp2(int phy_cpu_id)
+bool tegra_set_cpu_in_lp2(int phy_cpu_id)
{
bool last_cpu = false;
cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
@@ -173,6 +174,8 @@ bool __cpuinit tegra_set_cpu_in_lp2(int phy_cpu_id)
if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
last_cpu = true;
+ else if (tegra_chip_id == TEGRA20 && phy_cpu_id == 1)
+ tegra20_cpu_set_resettable_soon();
spin_unlock(&tegra_lp2_lock);
return last_cpu;
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index 2cc1185d902e..c6bc8f85759c 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -26,8 +26,8 @@
#include <linux/io.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
+#include <linux/clk/tegra.h>
-#include <mach/clk.h>
#include <mach/powergate.h>
#include "fuse.h"
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
new file mode 100644
index 000000000000..54382ceade4a
--- /dev/null
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+#include <asm/cache.h>
+#include <asm/asm-offsets.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include "flowctrl.h"
+#include "iomap.h"
+#include "reset.h"
+#include "sleep.h"
+
+#define APB_MISC_GP_HIDREV 0x804
+#define PMC_SCRATCH41 0x140
+
+#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * tegra_resume
+ *
+ * CPU boot vector when restarting the a CPU following
+ * an LP2 transition. Also branched to by LP0 and LP1 resume after
+ * re-enabling sdram.
+ */
+ENTRY(tegra_resume)
+ bl v7_invalidate_l1
+ /* Enable coresight */
+ mov32 r0, 0xC5ACCE55
+ mcr p14, 0, r0, c7, c12, 6
+
+ cpu_id r0
+ cmp r0, #0 @ CPU0?
+ bne cpu_resume @ no
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ /* Are we on Tegra20? */
+ mov32 r6, TEGRA_APB_MISC_BASE
+ ldr r0, [r6, #APB_MISC_GP_HIDREV]
+ and r0, r0, #0xff00
+ cmp r0, #(0x20 << 8)
+ beq 1f @ Yes
+ /* Clear the flow controller flags for this CPU. */
+ mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR
+ ldr r1, [r2]
+ /* Clear event & intr flag */
+ orr r1, r1, \
+ #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+ movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps
+ bic r1, r1, r0
+ str r1, [r2]
+1:
+#endif
+
+#ifdef CONFIG_HAVE_ARM_SCU
+ /* enable SCU */
+ mov32 r0, TEGRA_ARM_PERIF_BASE
+ ldr r1, [r0]
+ orr r1, r1, #1
+ str r1, [r0]
+#endif
+
+ /* L2 cache resume & re-enable */
+ l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr
+
+ b cpu_resume
+ENDPROC(tegra_resume)
+#endif
+
+#ifdef CONFIG_CACHE_L2X0
+ .globl l2x0_saved_regs_addr
+l2x0_saved_regs_addr:
+ .long 0
+#endif
+
+ .align L1_CACHE_SHIFT
+ENTRY(__tegra_cpu_reset_handler_start)
+
+/*
+ * __tegra_cpu_reset_handler:
+ *
+ * Common handler for all CPU reset events.
+ *
+ * Register usage within the reset handler:
+ *
+ * R7 = CPU present (to the OS) mask
+ * R8 = CPU in LP1 state mask
+ * R9 = CPU in LP2 state mask
+ * R10 = CPU number
+ * R11 = CPU mask
+ * R12 = pointer to reset handler data
+ *
+ * NOTE: This code is copied to IRAM. All code and data accesses
+ * must be position-independent.
+ */
+
+ .align L1_CACHE_SHIFT
+ENTRY(__tegra_cpu_reset_handler)
+
+ cpsid aif, 0x13 @ SVC mode, interrupts disabled
+ mrc p15, 0, r10, c0, c0, 5 @ MPIDR
+ and r10, r10, #0x3 @ R10 = CPU number
+ mov r11, #1
+ mov r11, r11, lsl r10 @ R11 = CPU mask
+ adr r12, __tegra_cpu_reset_handler_data
+
+#ifdef CONFIG_SMP
+ /* Does the OS know about this CPU? */
+ ldr r7, [r12, #RESET_DATA(MASK_PRESENT)]
+ tst r7, r11 @ if !present
+ bleq __die @ CPU not present (to OS)
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ /* Are we on Tegra20? */
+ mov32 r6, TEGRA_APB_MISC_BASE
+ ldr r0, [r6, #APB_MISC_GP_HIDREV]
+ and r0, r0, #0xff00
+ cmp r0, #(0x20 << 8)
+ bne 1f
+ /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
+ mov32 r6, TEGRA_PMC_BASE
+ mov r0, #0
+ cmp r10, #0
+ strne r0, [r6, #PMC_SCRATCH41]
+1:
+#endif
+
+ /* Waking up from LP2? */
+ ldr r9, [r12, #RESET_DATA(MASK_LP2)]
+ tst r9, r11 @ if in_lp2
+ beq __is_not_lp2
+ ldr lr, [r12, #RESET_DATA(STARTUP_LP2)]
+ cmp lr, #0
+ bleq __die @ no LP2 startup handler
+ bx lr
+
+__is_not_lp2:
+
+#ifdef CONFIG_SMP
+ /*
+ * Can only be secondary boot (initial or hotplug) but CPU 0
+ * cannot be here.
+ */
+ cmp r10, #0
+ bleq __die @ CPU0 cannot be here
+ ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
+ cmp lr, #0
+ bleq __die @ no secondary startup handler
+ bx lr
+#endif
+
+/*
+ * We don't know why the CPU reset. Just kill it.
+ * The LR register will contain the address we died at + 4.
+ */
+
+__die:
+ sub lr, lr, #4
+ mov32 r7, TEGRA_PMC_BASE
+ str lr, [r7, #PMC_SCRATCH41]
+
+ mov32 r7, TEGRA_CLK_RESET_BASE
+
+ /* Are we on Tegra20? */
+ mov32 r6, TEGRA_APB_MISC_BASE
+ ldr r0, [r6, #APB_MISC_GP_HIDREV]
+ and r0, r0, #0xff00
+ cmp r0, #(0x20 << 8)
+ bne 1f
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ mov32 r0, 0x1111
+ mov r1, r0, lsl r10
+ str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET
+#endif
+1:
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ mov32 r6, TEGRA_FLOW_CTRL_BASE
+
+ cmp r10, #0
+ moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS
+ moveq r2, #FLOW_CTRL_CPU0_CSR
+ movne r1, r10, lsl #3
+ addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
+ addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
+
+ /* Clear CPU "event" and "interrupt" flags and power gate
+ it when halting but not before it is in the "WFI" state. */
+ ldr r0, [r6, +r2]
+ orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+ orr r0, r0, #FLOW_CTRL_CSR_ENABLE
+ str r0, [r6, +r2]
+
+ /* Unconditionally halt this CPU */
+ mov r0, #FLOW_CTRL_WAITEVENT
+ str r0, [r6, +r1]
+ ldr r0, [r6, +r1] @ memory barrier
+
+ dsb
+ isb
+ wfi @ CPU should be power gated here
+
+ /* If the CPU didn't power gate above just kill it's clock. */
+
+ mov r0, r11, lsl #8
+ str r0, [r7, #348] @ CLK_CPU_CMPLX_SET
+#endif
+
+ /* If the CPU still isn't dead, just spin here. */
+ b .
+ENDPROC(__tegra_cpu_reset_handler)
+
+ .align L1_CACHE_SHIFT
+ .type __tegra_cpu_reset_handler_data, %object
+ .globl __tegra_cpu_reset_handler_data
+__tegra_cpu_reset_handler_data:
+ .rept TEGRA_RESET_DATA_SIZE
+ .long 0
+ .endr
+ .align L1_CACHE_SHIFT
+
+ENTRY(__tegra_cpu_reset_handler_end)
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
index 3fd89ecd158e..1ac434e0068f 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -75,7 +75,7 @@ void __init tegra_cpu_reset_handler_init(void)
#ifdef CONFIG_SMP
__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
- *((u32 *)cpu_present_mask);
+ *((u32 *)cpu_possible_mask);
__tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] =
virt_to_phys((void *)tegra_secondary_startup);
#endif
diff --git a/arch/arm/mach-tegra/sleep-tegra20.S b/arch/arm/mach-tegra/sleep-tegra20.S
index 72ce709799da..9f6bfafdd512 100644
--- a/arch/arm/mach-tegra/sleep-tegra20.S
+++ b/arch/arm/mach-tegra/sleep-tegra20.S
@@ -21,6 +21,8 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/proc-fns.h>
+#include <asm/cp15.h>
#include "sleep.h"
#include "flowctrl.h"
@@ -33,9 +35,6 @@
* should never return
*/
ENTRY(tegra20_hotplug_shutdown)
- /* Turn off SMP coherency */
- exit_smp r4, r5
-
/* Put this CPU down */
cpu_id r0
bl tegra20_cpu_shutdown
@@ -58,6 +57,9 @@ ENDPROC(tegra20_hotplug_shutdown)
ENTRY(tegra20_cpu_shutdown)
cmp r0, #0
moveq pc, lr @ must not be called for CPU 0
+ mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
+ mov r12, #CPU_RESETTABLE
+ str r12, [r1]
cpu_to_halt_reg r1, r0
ldr r3, =TEGRA_FLOW_CTRL_VIRT
@@ -78,3 +80,198 @@ ENTRY(tegra20_cpu_shutdown)
mov pc, lr
ENDPROC(tegra20_cpu_shutdown)
#endif
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * tegra_pen_lock
+ *
+ * spinlock implementation with no atomic test-and-set and no coherence
+ * using Peterson's algorithm on strongly-ordered registers
+ * used to synchronize a cpu waking up from wfi with entering lp2 on idle
+ *
+ * The reference link of Peterson's algorithm:
+ * http://en.wikipedia.org/wiki/Peterson's_algorithm
+ *
+ * SCRATCH37 = r1 = !turn (inverted from Peterson's algorithm)
+ * on cpu 0:
+ * r2 = flag[0] (in SCRATCH38)
+ * r3 = flag[1] (in SCRATCH39)
+ * on cpu1:
+ * r2 = flag[1] (in SCRATCH39)
+ * r3 = flag[0] (in SCRATCH38)
+ *
+ * must be called with MMU on
+ * corrupts r0-r3, r12
+ */
+ENTRY(tegra_pen_lock)
+ mov32 r3, TEGRA_PMC_VIRT
+ cpu_id r0
+ add r1, r3, #PMC_SCRATCH37
+ cmp r0, #0
+ addeq r2, r3, #PMC_SCRATCH38
+ addeq r3, r3, #PMC_SCRATCH39
+ addne r2, r3, #PMC_SCRATCH39
+ addne r3, r3, #PMC_SCRATCH38
+
+ mov r12, #1
+ str r12, [r2] @ flag[cpu] = 1
+ dsb
+ str r12, [r1] @ !turn = cpu
+1: dsb
+ ldr r12, [r3]
+ cmp r12, #1 @ flag[!cpu] == 1?
+ ldreq r12, [r1]
+ cmpeq r12, r0 @ !turn == cpu?
+ beq 1b @ while !turn == cpu && flag[!cpu] == 1
+
+ mov pc, lr @ locked
+ENDPROC(tegra_pen_lock)
+
+ENTRY(tegra_pen_unlock)
+ dsb
+ mov32 r3, TEGRA_PMC_VIRT
+ cpu_id r0
+ cmp r0, #0
+ addeq r2, r3, #PMC_SCRATCH38
+ addne r2, r3, #PMC_SCRATCH39
+ mov r12, #0
+ str r12, [r2]
+ mov pc, lr
+ENDPROC(tegra_pen_unlock)
+
+/*
+ * tegra20_cpu_clear_resettable(void)
+ *
+ * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when
+ * it is expected that the secondary CPU will be idle soon.
+ */
+ENTRY(tegra20_cpu_clear_resettable)
+ mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
+ mov r12, #CPU_NOT_RESETTABLE
+ str r12, [r1]
+ mov pc, lr
+ENDPROC(tegra20_cpu_clear_resettable)
+
+/*
+ * tegra20_cpu_set_resettable_soon(void)
+ *
+ * Called to set the "resettable soon" flag in PMC_SCRATCH41 when
+ * it is expected that the secondary CPU will be idle soon.
+ */
+ENTRY(tegra20_cpu_set_resettable_soon)
+ mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
+ mov r12, #CPU_RESETTABLE_SOON
+ str r12, [r1]
+ mov pc, lr
+ENDPROC(tegra20_cpu_set_resettable_soon)
+
+/*
+ * tegra20_cpu_is_resettable_soon(void)
+ *
+ * Returns true if the "resettable soon" flag in PMC_SCRATCH41 has been
+ * set because it is expected that the secondary CPU will be idle soon.
+ */
+ENTRY(tegra20_cpu_is_resettable_soon)
+ mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
+ ldr r12, [r1]
+ cmp r12, #CPU_RESETTABLE_SOON
+ moveq r0, #1
+ movne r0, #0
+ mov pc, lr
+ENDPROC(tegra20_cpu_is_resettable_soon)
+
+/*
+ * tegra20_sleep_cpu_secondary_finish(unsigned long v2p)
+ *
+ * Enters WFI on secondary CPU by exiting coherency.
+ */
+ENTRY(tegra20_sleep_cpu_secondary_finish)
+ stmfd sp!, {r4-r11, lr}
+
+ mrc p15, 0, r11, c1, c0, 1 @ save actlr before exiting coherency
+
+ /* Flush and disable the L1 data cache */
+ bl tegra_disable_clean_inv_dcache
+
+ mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41
+ mov r3, #CPU_RESETTABLE
+ str r3, [r0]
+
+ bl cpu_do_idle
+
+ /*
+ * cpu may be reset while in wfi, which will return through
+ * tegra_resume to cpu_resume
+ * or interrupt may wake wfi, which will return here
+ * cpu state is unchanged - MMU is on, cache is on, coherency
+ * is off, and the data cache is off
+ *
+ * r11 contains the original actlr
+ */
+
+ bl tegra_pen_lock
+
+ mov32 r3, TEGRA_PMC_VIRT
+ add r0, r3, #PMC_SCRATCH41
+ mov r3, #CPU_NOT_RESETTABLE
+ str r3, [r0]
+
+ bl tegra_pen_unlock
+
+ /* Re-enable the data cache */
+ mrc p15, 0, r10, c1, c0, 0
+ orr r10, r10, #CR_C
+ mcr p15, 0, r10, c1, c0, 0
+ isb
+
+ mcr p15, 0, r11, c1, c0, 1 @ reenable coherency
+
+ /* Invalidate the TLBs & BTAC */
+ mov r1, #0
+ mcr p15, 0, r1, c8, c3, 0 @ invalidate shared TLBs
+ mcr p15, 0, r1, c7, c1, 6 @ invalidate shared BTAC
+ dsb
+ isb
+
+ /* the cpu was running with coherency disabled,
+ * caches may be out of date */
+ bl v7_flush_kern_cache_louis
+
+ ldmfd sp!, {r4 - r11, pc}
+ENDPROC(tegra20_sleep_cpu_secondary_finish)
+
+/*
+ * tegra20_tear_down_cpu
+ *
+ * Switches the CPU cluster to PLL-P and enters sleep.
+ */
+ENTRY(tegra20_tear_down_cpu)
+ bl tegra_switch_cpu_to_pllp
+ b tegra20_enter_sleep
+ENDPROC(tegra20_tear_down_cpu)
+
+/*
+ * tegra20_enter_sleep
+ *
+ * uses flow controller to enter sleep state
+ * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1
+ * executes from SDRAM with target state is LP2
+ */
+tegra20_enter_sleep:
+ mov32 r6, TEGRA_FLOW_CTRL_BASE
+
+ mov r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT
+ orr r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ
+ cpu_id r1
+ cpu_to_halt_reg r1, r1
+ str r0, [r6, r1]
+ dsb
+ ldr r0, [r6, r1] /* memory barrier */
+
+halted:
+ dsb
+ wfe /* CPU should be power gated here */
+ isb
+ b halted
+
+#endif
diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S
index 562a8e7e413d..63a15bd9b653 100644
--- a/arch/arm/mach-tegra/sleep-tegra30.S
+++ b/arch/arm/mach-tegra/sleep-tegra30.S
@@ -32,9 +32,6 @@
* Should never return.
*/
ENTRY(tegra30_hotplug_shutdown)
- /* Turn off SMP coherency */
- exit_smp r4, r5
-
/* Powergate this CPU */
mov r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
bl tegra30_cpu_shutdown
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
index 26afa7cbed11..364d84523fba 100644
--- a/arch/arm/mach-tegra/sleep.S
+++ b/arch/arm/mach-tegra/sleep.S
@@ -34,7 +34,10 @@
#include "flowctrl.h"
#include "sleep.h"
-#ifdef CONFIG_PM_SLEEP
+#define CLK_RESET_CCLK_BURST 0x20
+#define CLK_RESET_CCLK_DIVIDER 0x24
+
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
/*
* tegra_disable_clean_inv_dcache
*
@@ -60,7 +63,9 @@ ENTRY(tegra_disable_clean_inv_dcache)
ldmfd sp!, {r0, r4-r5, r7, r9-r11, pc}
ENDPROC(tegra_disable_clean_inv_dcache)
+#endif
+#ifdef CONFIG_PM_SLEEP
/*
* tegra_sleep_cpu_finish(unsigned long v2p)
*
@@ -108,4 +113,20 @@ ENTRY(tegra_shut_off_mmu)
mov pc, r0
ENDPROC(tegra_shut_off_mmu)
.popsection
+
+/*
+ * tegra_switch_cpu_to_pllp
+ *
+ * In LP2 the normal cpu clock pllx will be turned off. Switch the CPU to pllp
+ */
+ENTRY(tegra_switch_cpu_to_pllp)
+ /* in LP2 idle (SDRAM active), set the CPU burst policy to PLLP */
+ mov32 r5, TEGRA_CLK_RESET_BASE
+ mov r0, #(2 << 28) @ burst policy = run mode
+ orr r0, r0, #(4 << 4) @ use PLLP in run mode burst
+ str r0, [r5, #CLK_RESET_CCLK_BURST]
+ mov r0, #0
+ str r0, [r5, #CLK_RESET_CCLK_DIVIDER]
+ mov pc, lr
+ENDPROC(tegra_switch_cpu_to_pllp)
#endif
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index 9821ee725420..4ffae541726e 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -25,6 +25,19 @@
+ IO_PPSB_VIRT)
#define TEGRA_CLK_RESET_VIRT (TEGRA_CLK_RESET_BASE - IO_PPSB_PHYS \
+ IO_PPSB_VIRT)
+#define TEGRA_PMC_VIRT (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT)
+
+/* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock and idle */
+#define PMC_SCRATCH37 0x130
+#define PMC_SCRATCH38 0x134
+#define PMC_SCRATCH39 0x138
+#define PMC_SCRATCH41 0x140
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+#define CPU_RESETTABLE 2
+#define CPU_RESETTABLE_SOON 1
+#define CPU_NOT_RESETTABLE 0
+#endif
#ifdef __ASSEMBLY__
/* returns the offset of the flow controller halt register for a cpu */
@@ -104,8 +117,11 @@ exit_l2_resume:
.endm
#endif /* CONFIG_CACHE_L2X0 */
#else
+void tegra_pen_lock(void);
+void tegra_pen_unlock(void);
void tegra_resume(void);
int tegra_sleep_cpu_finish(unsigned long);
+void tegra_disable_clean_inv_dcache(void);
#ifdef CONFIG_HOTPLUG_CPU
void tegra20_hotplug_init(void);
@@ -115,6 +131,17 @@ static inline void tegra20_hotplug_init(void) {}
static inline void tegra30_hotplug_init(void) {}
#endif
+void tegra20_cpu_shutdown(int cpu);
+int tegra20_cpu_is_resettable_soon(void);
+void tegra20_cpu_clear_resettable(void);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+void tegra20_cpu_set_resettable_soon(void);
+#else
+static inline void tegra20_cpu_set_resettable_soon(void) {}
+#endif
+
+int tegra20_sleep_cpu_secondary_finish(unsigned long);
+void tegra20_tear_down_cpu(void);
int tegra30_sleep_cpu_secondary_finish(unsigned long);
void tegra30_tear_down_cpu(void);
diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c
deleted file mode 100644
index 4eb6bc81a87b..000000000000
--- a/arch/arm/mach-tegra/tegra20_clocks.c
+++ /dev/null
@@ -1,1623 +0,0 @@
-/*
- * arch/arm/mach-tegra/tegra20_clocks.c
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved.
- *
- * Author:
- * Colin Cross <ccross@google.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/kernel.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clkdev.h>
-#include <linux/clk.h>
-
-#include "clock.h"
-#include "fuse.h"
-#include "iomap.h"
-#include "tegra2_emc.h"
-#include "tegra_cpu_car.h"
-
-#define RST_DEVICES 0x004
-#define RST_DEVICES_SET 0x300
-#define RST_DEVICES_CLR 0x304
-#define RST_DEVICES_NUM 3
-
-#define CLK_OUT_ENB 0x010
-#define CLK_OUT_ENB_SET 0x320
-#define CLK_OUT_ENB_CLR 0x324
-#define CLK_OUT_ENB_NUM 3
-
-#define CLK_MASK_ARM 0x44
-#define MISC_CLK_ENB 0x48
-
-#define OSC_CTRL 0x50
-#define OSC_CTRL_OSC_FREQ_MASK (3<<30)
-#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
-#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30)
-#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30)
-#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30)
-#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
-
-#define OSC_FREQ_DET 0x58
-#define OSC_FREQ_DET_TRIG (1<<31)
-
-#define OSC_FREQ_DET_STATUS 0x5C
-#define OSC_FREQ_DET_BUSY (1<<31)
-#define OSC_FREQ_DET_CNT_MASK 0xFFFF
-
-#define PERIPH_CLK_SOURCE_I2S1 0x100
-#define PERIPH_CLK_SOURCE_EMC 0x19c
-#define PERIPH_CLK_SOURCE_OSC 0x1fc
-#define PERIPH_CLK_SOURCE_NUM \
- ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
-
-#define PERIPH_CLK_SOURCE_MASK (3<<30)
-#define PERIPH_CLK_SOURCE_SHIFT 30
-#define PERIPH_CLK_SOURCE_PWM_MASK (7<<28)
-#define PERIPH_CLK_SOURCE_PWM_SHIFT 28
-#define PERIPH_CLK_SOURCE_ENABLE (1<<28)
-#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
-#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
-#define PERIPH_CLK_SOURCE_DIV_SHIFT 0
-
-#define SDMMC_CLK_INT_FB_SEL (1 << 23)
-#define SDMMC_CLK_INT_FB_DLY_SHIFT 16
-#define SDMMC_CLK_INT_FB_DLY_MASK (0xF << SDMMC_CLK_INT_FB_DLY_SHIFT)
-
-#define PLL_BASE 0x0
-#define PLL_BASE_BYPASS (1<<31)
-#define PLL_BASE_ENABLE (1<<30)
-#define PLL_BASE_REF_ENABLE (1<<29)
-#define PLL_BASE_OVERRIDE (1<<28)
-#define PLL_BASE_DIVP_MASK (0x7<<20)
-#define PLL_BASE_DIVP_SHIFT 20
-#define PLL_BASE_DIVN_MASK (0x3FF<<8)
-#define PLL_BASE_DIVN_SHIFT 8
-#define PLL_BASE_DIVM_MASK (0x1F)
-#define PLL_BASE_DIVM_SHIFT 0
-
-#define PLL_OUT_RATIO_MASK (0xFF<<8)
-#define PLL_OUT_RATIO_SHIFT 8
-#define PLL_OUT_OVERRIDE (1<<2)
-#define PLL_OUT_CLKEN (1<<1)
-#define PLL_OUT_RESET_DISABLE (1<<0)
-
-#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
-
-#define PLL_MISC_DCCON_SHIFT 20
-#define PLL_MISC_CPCON_SHIFT 8
-#define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT)
-#define PLL_MISC_LFCON_SHIFT 4
-#define PLL_MISC_LFCON_MASK (0xF<<PLL_MISC_LFCON_SHIFT)
-#define PLL_MISC_VCOCON_SHIFT 0
-#define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT)
-
-#define PLLU_BASE_POST_DIV (1<<20)
-
-#define PLLD_MISC_CLKENABLE (1<<30)
-#define PLLD_MISC_DIV_RST (1<<23)
-#define PLLD_MISC_DCCON_SHIFT 12
-
-#define PLLE_MISC_READY (1 << 15)
-
-#define PERIPH_CLK_TO_ENB_REG(c) ((c->u.periph.clk_num / 32) * 4)
-#define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->u.periph.clk_num / 32) * 8)
-#define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->u.periph.clk_num % 32))
-
-#define SUPER_CLK_MUX 0x00
-#define SUPER_STATE_SHIFT 28
-#define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT)
-#define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT)
-#define SUPER_SOURCE_MASK 0xF
-#define SUPER_FIQ_SOURCE_SHIFT 12
-#define SUPER_IRQ_SOURCE_SHIFT 8
-#define SUPER_RUN_SOURCE_SHIFT 4
-#define SUPER_IDLE_SOURCE_SHIFT 0
-
-#define SUPER_CLK_DIVIDER 0x04
-
-#define BUS_CLK_DISABLE (1<<3)
-#define BUS_CLK_DIV_MASK 0x3
-
-#define PMC_CTRL 0x0
- #define PMC_CTRL_BLINK_ENB (1 << 7)
-
-#define PMC_DPD_PADS_ORIDE 0x1c
- #define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20)
-
-#define PMC_BLINK_TIMER_DATA_ON_SHIFT 0
-#define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff
-#define PMC_BLINK_TIMER_ENB (1 << 15)
-#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
-#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff
-
-/* Tegra CPU clock and reset control regs */
-#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c
-#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340
-#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344
-
-#define CPU_CLOCK(cpu) (0x1 << (8 + cpu))
-#define CPU_RESET(cpu) (0x1111ul << (cpu))
-
-static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
-static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
-/*
- * Some clocks share a register with other clocks. Any clock op that
- * non-atomically modifies a register used by another clock must lock
- * clock_register_lock first.
- */
-static DEFINE_SPINLOCK(clock_register_lock);
-
-/*
- * Some peripheral clocks share an enable bit, so refcount the enable bits
- * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
- */
-static int tegra_periph_clk_enable_refcount[3 * 32];
-
-#define clk_writel(value, reg) \
- __raw_writel(value, reg_clk_base + (reg))
-#define clk_readl(reg) \
- __raw_readl(reg_clk_base + (reg))
-#define pmc_writel(value, reg) \
- __raw_writel(value, reg_pmc_base + (reg))
-#define pmc_readl(reg) \
- __raw_readl(reg_pmc_base + (reg))
-
-static unsigned long clk_measure_input_freq(void)
-{
- u32 clock_autodetect;
- clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
- do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
- clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
- if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
- return 12000000;
- } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
- return 13000000;
- } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
- return 19200000;
- } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
- return 26000000;
- } else {
- pr_err("%s: Unexpected clock autodetect value %d",
- __func__, clock_autodetect);
- BUG();
- return 0;
- }
-}
-
-static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
-{
- s64 divider_u71 = parent_rate * 2;
- divider_u71 += rate - 1;
- do_div(divider_u71, rate);
-
- if (divider_u71 - 2 < 0)
- return 0;
-
- if (divider_u71 - 2 > 255)
- return -EINVAL;
-
- return divider_u71 - 2;
-}
-
-static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
-{
- s64 divider_u16;
-
- divider_u16 = parent_rate;
- divider_u16 += rate - 1;
- do_div(divider_u16, rate);
-
- if (divider_u16 - 1 < 0)
- return 0;
-
- if (divider_u16 - 1 > 0xFFFF)
- return -EINVAL;
-
- return divider_u16 - 1;
-}
-
-static unsigned long tegra_clk_fixed_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- return to_clk_tegra(hw)->fixed_rate;
-}
-
-struct clk_ops tegra_clk_32k_ops = {
- .recalc_rate = tegra_clk_fixed_recalc_rate,
-};
-
-/* clk_m functions */
-static unsigned long tegra20_clk_m_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
-{
- if (!to_clk_tegra(hw)->fixed_rate)
- to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
- return to_clk_tegra(hw)->fixed_rate;
-}
-
-static void tegra20_clk_m_init(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 osc_ctrl = clk_readl(OSC_CTRL);
- u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
-
- switch (c->fixed_rate) {
- case 12000000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
- break;
- case 13000000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
- break;
- case 19200000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
- break;
- case 26000000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
- break;
- default:
- BUG();
- }
- clk_writel(auto_clock_control, OSC_CTRL);
-}
-
-struct clk_ops tegra_clk_m_ops = {
- .init = tegra20_clk_m_init,
- .recalc_rate = tegra20_clk_m_recalc_rate,
-};
-
-/* super clock functions */
-/* "super clocks" on tegra have two-stage muxes and a clock skipping
- * super divider. We will ignore the clock skipping divider, since we
- * can't lower the voltage when using the clock skip, but we can if we
- * lower the PLL frequency.
- */
-static int tegra20_super_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- val = clk_readl(c->reg + SUPER_CLK_MUX);
- BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
- ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
- c->state = ON;
- return c->state;
-}
-
-static int tegra20_super_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
- return 0;
-}
-
-static void tegra20_super_clk_disable(struct clk_hw *hw)
-{
- pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
-
- /* oops - don't disable the CPU clock! */
- BUG();
-}
-
-static u8 tegra20_super_clk_get_parent(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- int val = clk_readl(c->reg + SUPER_CLK_MUX);
- int source;
- int shift;
-
- BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
- ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
- shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
- SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
- source = (val >> shift) & SUPER_SOURCE_MASK;
- return source;
-}
-
-static int tegra20_super_clk_set_parent(struct clk_hw *hw, u8 index)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg + SUPER_CLK_MUX);
- int shift;
-
- BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
- ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
- shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
- SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
- val &= ~(SUPER_SOURCE_MASK << shift);
- val |= index << shift;
-
- clk_writel(val, c->reg);
-
- return 0;
-}
-
-/* FIX ME: Need to switch parents to change the source PLL rate */
-static unsigned long tegra20_super_clk_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
-{
- return prate;
-}
-
-static long tegra20_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- return *prate;
-}
-
-static int tegra20_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- return 0;
-}
-
-struct clk_ops tegra_super_ops = {
- .is_enabled = tegra20_super_clk_is_enabled,
- .enable = tegra20_super_clk_enable,
- .disable = tegra20_super_clk_disable,
- .set_parent = tegra20_super_clk_set_parent,
- .get_parent = tegra20_super_clk_get_parent,
- .set_rate = tegra20_super_clk_set_rate,
- .round_rate = tegra20_super_clk_round_rate,
- .recalc_rate = tegra20_super_clk_recalc_rate,
-};
-
-static unsigned long tegra20_twd_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = parent_rate;
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
-
- return rate;
-}
-
-struct clk_ops tegra_twd_ops = {
- .recalc_rate = tegra20_twd_clk_recalc_rate,
-};
-
-static u8 tegra20_cop_clk_get_parent(struct clk_hw *hw)
-{
- return 0;
-}
-
-struct clk_ops tegra_cop_ops = {
- .get_parent = tegra20_cop_clk_get_parent,
-};
-
-/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
- * reset the COP block (i.e. AVP) */
-void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert)
-{
- unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
-
- pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert");
- clk_writel(1 << 1, reg);
-}
-
-/* bus clock functions */
-static int tegra20_bus_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
-
- c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
- return c->state;
-}
-
-static int tegra20_bus_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long flags;
- u32 val;
-
- spin_lock_irqsave(&clock_register_lock, flags);
-
- val = clk_readl(c->reg);
- val &= ~(BUS_CLK_DISABLE << c->reg_shift);
- clk_writel(val, c->reg);
-
- spin_unlock_irqrestore(&clock_register_lock, flags);
-
- return 0;
-}
-
-static void tegra20_bus_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long flags;
- u32 val;
-
- spin_lock_irqsave(&clock_register_lock, flags);
-
- val = clk_readl(c->reg);
- val |= BUS_CLK_DISABLE << c->reg_shift;
- clk_writel(val, c->reg);
-
- spin_unlock_irqrestore(&clock_register_lock, flags);
-}
-
-static unsigned long tegra20_bus_clk_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
- u64 rate = prate;
-
- c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
- c->mul = 1;
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
- return rate;
-}
-
-static int tegra20_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- int ret = -EINVAL;
- unsigned long flags;
- u32 val;
- int i;
-
- spin_lock_irqsave(&clock_register_lock, flags);
-
- val = clk_readl(c->reg);
- for (i = 1; i <= 4; i++) {
- if (rate == parent_rate / i) {
- val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
- val |= (i - 1) << c->reg_shift;
- clk_writel(val, c->reg);
- c->div = i;
- c->mul = 1;
- ret = 0;
- break;
- }
- }
-
- spin_unlock_irqrestore(&clock_register_lock, flags);
-
- return ret;
-}
-
-static long tegra20_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- unsigned long parent_rate = *prate;
- s64 divider;
-
- if (rate >= parent_rate)
- return rate;
-
- divider = parent_rate;
- divider += rate - 1;
- do_div(divider, rate);
-
- if (divider < 0)
- return divider;
-
- if (divider > 4)
- divider = 4;
- do_div(parent_rate, divider);
-
- return parent_rate;
-}
-
-struct clk_ops tegra_bus_ops = {
- .is_enabled = tegra20_bus_clk_is_enabled,
- .enable = tegra20_bus_clk_enable,
- .disable = tegra20_bus_clk_disable,
- .set_rate = tegra20_bus_clk_set_rate,
- .round_rate = tegra20_bus_clk_round_rate,
- .recalc_rate = tegra20_bus_clk_recalc_rate,
-};
-
-/* Blink output functions */
-static int tegra20_blink_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- val = pmc_readl(PMC_CTRL);
- c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
- return c->state;
-}
-
-static unsigned long tegra20_blink_clk_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = prate;
- u32 val;
-
- c->mul = 1;
- val = pmc_readl(c->reg);
-
- if (val & PMC_BLINK_TIMER_ENB) {
- unsigned int on_off;
-
- on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
- PMC_BLINK_TIMER_DATA_ON_MASK;
- val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
- val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
- on_off += val;
- /* each tick in the blink timer is 4 32KHz clocks */
- c->div = on_off * 4;
- } else {
- c->div = 1;
- }
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
- return rate;
-}
-
-static int tegra20_blink_clk_enable(struct clk_hw *hw)
-{
- u32 val;
-
- val = pmc_readl(PMC_DPD_PADS_ORIDE);
- pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
-
- val = pmc_readl(PMC_CTRL);
- pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
-
- return 0;
-}
-
-static void tegra20_blink_clk_disable(struct clk_hw *hw)
-{
- u32 val;
-
- val = pmc_readl(PMC_CTRL);
- pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
-
- val = pmc_readl(PMC_DPD_PADS_ORIDE);
- pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
-}
-
-static int tegra20_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- if (rate >= parent_rate) {
- c->div = 1;
- pmc_writel(0, c->reg);
- } else {
- unsigned int on_off;
- u32 val;
-
- on_off = DIV_ROUND_UP(parent_rate / 8, rate);
- c->div = on_off * 8;
-
- val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
- PMC_BLINK_TIMER_DATA_ON_SHIFT;
- on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
- on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
- val |= on_off;
- val |= PMC_BLINK_TIMER_ENB;
- pmc_writel(val, c->reg);
- }
-
- return 0;
-}
-
-static long tegra20_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- int div;
- int mul;
- long round_rate = *prate;
-
- mul = 1;
-
- if (rate >= *prate) {
- div = 1;
- } else {
- div = DIV_ROUND_UP(*prate / 8, rate);
- div *= 8;
- }
-
- round_rate *= mul;
- round_rate += div - 1;
- do_div(round_rate, div);
-
- return round_rate;
-}
-
-struct clk_ops tegra_blink_clk_ops = {
- .is_enabled = tegra20_blink_clk_is_enabled,
- .enable = tegra20_blink_clk_enable,
- .disable = tegra20_blink_clk_disable,
- .set_rate = tegra20_blink_clk_set_rate,
- .round_rate = tegra20_blink_clk_round_rate,
- .recalc_rate = tegra20_blink_clk_recalc_rate,
-};
-
-/* PLL Functions */
-static int tegra20_pll_clk_wait_for_lock(struct clk_tegra *c)
-{
- udelay(c->u.pll.lock_delay);
- return 0;
-}
-
-static int tegra20_pll_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg + PLL_BASE);
-
- c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
- return c->state;
-}
-
-static unsigned long tegra20_pll_clk_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg + PLL_BASE);
- u64 rate = prate;
-
- if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
- const struct clk_pll_freq_table *sel;
- for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
- if (sel->input_rate == prate &&
- sel->output_rate == c->u.pll.fixed_rate) {
- c->mul = sel->n;
- c->div = sel->m * sel->p;
- break;
- }
- }
- pr_err("Clock %s has unknown fixed frequency\n",
- __clk_get_name(hw->clk));
- BUG();
- } else if (val & PLL_BASE_BYPASS) {
- c->mul = 1;
- c->div = 1;
- } else {
- c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
- c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
- if (c->flags & PLLU)
- c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
- else
- c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
- }
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
- return rate;
-}
-
-static int tegra20_pll_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
-
- val = clk_readl(c->reg + PLL_BASE);
- val &= ~PLL_BASE_BYPASS;
- val |= PLL_BASE_ENABLE;
- clk_writel(val, c->reg + PLL_BASE);
-
- tegra20_pll_clk_wait_for_lock(c);
-
- return 0;
-}
-
-static void tegra20_pll_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
-
- val = clk_readl(c->reg);
- val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
- clk_writel(val, c->reg);
-}
-
-static int tegra20_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long input_rate = parent_rate;
- const struct clk_pll_freq_table *sel;
- u32 val;
-
- pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
-
- if (c->flags & PLL_FIXED) {
- int ret = 0;
- if (rate != c->u.pll.fixed_rate) {
- pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
- __func__, __clk_get_name(hw->clk),
- c->u.pll.fixed_rate, rate);
- ret = -EINVAL;
- }
- return ret;
- }
-
- for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
- if (sel->input_rate == input_rate && sel->output_rate == rate) {
- c->mul = sel->n;
- c->div = sel->m * sel->p;
-
- val = clk_readl(c->reg + PLL_BASE);
- if (c->flags & PLL_FIXED)
- val |= PLL_BASE_OVERRIDE;
- val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
- PLL_BASE_DIVM_MASK);
- val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
- (sel->n << PLL_BASE_DIVN_SHIFT);
- BUG_ON(sel->p < 1 || sel->p > 2);
- if (c->flags & PLLU) {
- if (sel->p == 1)
- val |= PLLU_BASE_POST_DIV;
- } else {
- if (sel->p == 2)
- val |= 1 << PLL_BASE_DIVP_SHIFT;
- }
- clk_writel(val, c->reg + PLL_BASE);
-
- if (c->flags & PLL_HAS_CPCON) {
- val = clk_readl(c->reg + PLL_MISC(c));
- val &= ~PLL_MISC_CPCON_MASK;
- val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
- clk_writel(val, c->reg + PLL_MISC(c));
- }
-
- if (c->state == ON)
- tegra20_pll_clk_enable(hw);
- return 0;
- }
- }
- return -EINVAL;
-}
-
-static long tegra20_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- const struct clk_pll_freq_table *sel;
- unsigned long input_rate = *prate;
- u64 output_rate = *prate;
- int mul;
- int div;
-
- if (c->flags & PLL_FIXED)
- return c->u.pll.fixed_rate;
-
- for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++)
- if (sel->input_rate == input_rate && sel->output_rate == rate) {
- mul = sel->n;
- div = sel->m * sel->p;
- break;
- }
-
- if (sel->input_rate == 0)
- return -EINVAL;
-
- output_rate *= mul;
- output_rate += div - 1; /* round up */
- do_div(output_rate, div);
-
- return output_rate;
-}
-
-struct clk_ops tegra_pll_ops = {
- .is_enabled = tegra20_pll_clk_is_enabled,
- .enable = tegra20_pll_clk_enable,
- .disable = tegra20_pll_clk_disable,
- .set_rate = tegra20_pll_clk_set_rate,
- .recalc_rate = tegra20_pll_clk_recalc_rate,
- .round_rate = tegra20_pll_clk_round_rate,
-};
-
-static void tegra20_pllx_clk_init(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- if (tegra_sku_id == 7)
- c->max_rate = 750000000;
-}
-
-struct clk_ops tegra_pllx_ops = {
- .init = tegra20_pllx_clk_init,
- .is_enabled = tegra20_pll_clk_is_enabled,
- .enable = tegra20_pll_clk_enable,
- .disable = tegra20_pll_clk_disable,
- .set_rate = tegra20_pll_clk_set_rate,
- .recalc_rate = tegra20_pll_clk_recalc_rate,
- .round_rate = tegra20_pll_clk_round_rate,
-};
-
-static int tegra20_plle_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
-
- mdelay(1);
-
- val = clk_readl(c->reg + PLL_BASE);
- if (!(val & PLLE_MISC_READY))
- return -EBUSY;
-
- val = clk_readl(c->reg + PLL_BASE);
- val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
- clk_writel(val, c->reg + PLL_BASE);
-
- return 0;
-}
-
-struct clk_ops tegra_plle_ops = {
- .is_enabled = tegra20_pll_clk_is_enabled,
- .enable = tegra20_plle_clk_enable,
- .set_rate = tegra20_pll_clk_set_rate,
- .recalc_rate = tegra20_pll_clk_recalc_rate,
- .round_rate = tegra20_pll_clk_round_rate,
-};
-
-/* Clock divider ops */
-static int tegra20_pll_div_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
-
- val >>= c->reg_shift;
- c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
- if (!(val & PLL_OUT_RESET_DISABLE))
- c->state = OFF;
- return c->state;
-}
-
-static unsigned long tegra20_pll_div_clk_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = prate;
- u32 val = clk_readl(c->reg);
- u32 divu71;
-
- val >>= c->reg_shift;
-
- if (c->flags & DIV_U71) {
- divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
- c->div = (divu71 + 2);
- c->mul = 2;
- } else if (c->flags & DIV_2) {
- c->div = 2;
- c->mul = 1;
- } else {
- c->div = 1;
- c->mul = 1;
- }
-
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
-
- return rate;
-}
-
-static int tegra20_pll_div_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long flags;
- u32 new_val;
- u32 val;
-
- pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
-
- if (c->flags & DIV_U71) {
- spin_lock_irqsave(&clock_register_lock, flags);
- val = clk_readl(c->reg);
- new_val = val >> c->reg_shift;
- new_val &= 0xFFFF;
-
- new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
-
- val &= ~(0xFFFF << c->reg_shift);
- val |= new_val << c->reg_shift;
- clk_writel(val, c->reg);
- spin_unlock_irqrestore(&clock_register_lock, flags);
- return 0;
- } else if (c->flags & DIV_2) {
- BUG_ON(!(c->flags & PLLD));
- spin_lock_irqsave(&clock_register_lock, flags);
- val = clk_readl(c->reg);
- val &= ~PLLD_MISC_DIV_RST;
- clk_writel(val, c->reg);
- spin_unlock_irqrestore(&clock_register_lock, flags);
- return 0;
- }
- return -EINVAL;
-}
-
-static void tegra20_pll_div_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long flags;
- u32 new_val;
- u32 val;
-
- pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
-
- if (c->flags & DIV_U71) {
- spin_lock_irqsave(&clock_register_lock, flags);
- val = clk_readl(c->reg);
- new_val = val >> c->reg_shift;
- new_val &= 0xFFFF;
-
- new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
-
- val &= ~(0xFFFF << c->reg_shift);
- val |= new_val << c->reg_shift;
- clk_writel(val, c->reg);
- spin_unlock_irqrestore(&clock_register_lock, flags);
- } else if (c->flags & DIV_2) {
- BUG_ON(!(c->flags & PLLD));
- spin_lock_irqsave(&clock_register_lock, flags);
- val = clk_readl(c->reg);
- val |= PLLD_MISC_DIV_RST;
- clk_writel(val, c->reg);
- spin_unlock_irqrestore(&clock_register_lock, flags);
- }
-}
-
-static int tegra20_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long flags;
- int divider_u71;
- u32 new_val;
- u32 val;
-
- pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
-
- if (c->flags & DIV_U71) {
- divider_u71 = clk_div71_get_divider(parent_rate, rate);
- if (divider_u71 >= 0) {
- spin_lock_irqsave(&clock_register_lock, flags);
- val = clk_readl(c->reg);
- new_val = val >> c->reg_shift;
- new_val &= 0xFFFF;
- if (c->flags & DIV_U71_FIXED)
- new_val |= PLL_OUT_OVERRIDE;
- new_val &= ~PLL_OUT_RATIO_MASK;
- new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
-
- val &= ~(0xFFFF << c->reg_shift);
- val |= new_val << c->reg_shift;
- clk_writel(val, c->reg);
- c->div = divider_u71 + 2;
- c->mul = 2;
- spin_unlock_irqrestore(&clock_register_lock, flags);
- return 0;
- }
- } else if (c->flags & DIV_2) {
- if (parent_rate == rate * 2)
- return 0;
- }
- return -EINVAL;
-}
-
-static long tegra20_pll_div_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long parent_rate = *prate;
- int divider;
-
- pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
-
- if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(parent_rate, rate);
- if (divider < 0)
- return divider;
- return DIV_ROUND_UP(parent_rate * 2, divider + 2);
- } else if (c->flags & DIV_2) {
- return DIV_ROUND_UP(parent_rate, 2);
- }
- return -EINVAL;
-}
-
-struct clk_ops tegra_pll_div_ops = {
- .is_enabled = tegra20_pll_div_clk_is_enabled,
- .enable = tegra20_pll_div_clk_enable,
- .disable = tegra20_pll_div_clk_disable,
- .set_rate = tegra20_pll_div_clk_set_rate,
- .round_rate = tegra20_pll_div_clk_round_rate,
- .recalc_rate = tegra20_pll_div_clk_recalc_rate,
-};
-
-/* Periph clk ops */
-
-static int tegra20_periph_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- c->state = ON;
-
- if (!c->u.periph.clk_num)
- goto out;
-
- if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
- PERIPH_CLK_TO_ENB_BIT(c)))
- c->state = OFF;
-
- if (!(c->flags & PERIPH_NO_RESET))
- if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
- PERIPH_CLK_TO_ENB_BIT(c))
- c->state = OFF;
-
-out:
- return c->state;
-}
-
-static int tegra20_periph_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long flags;
- u32 val;
-
- pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
-
- if (!c->u.periph.clk_num)
- return 0;
-
- tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
- if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
- return 0;
-
- spin_lock_irqsave(&clock_register_lock, flags);
-
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
- if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
- if (c->flags & PERIPH_EMC_ENB) {
- /* The EMC peripheral clock has 2 extra enable bits */
- /* FIXME: Do they need to be disabled? */
- val = clk_readl(c->reg);
- val |= 0x3 << 24;
- clk_writel(val, c->reg);
- }
-
- spin_unlock_irqrestore(&clock_register_lock, flags);
-
- return 0;
-}
-
-static void tegra20_periph_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long flags;
-
- pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
-
- if (!c->u.periph.clk_num)
- return;
-
- tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
-
- if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
- return;
-
- spin_lock_irqsave(&clock_register_lock, flags);
-
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-
- spin_unlock_irqrestore(&clock_register_lock, flags);
-}
-
-void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
-
- pr_debug("%s %s on clock %s\n", __func__,
- assert ? "assert" : "deassert", __clk_get_name(hw->clk));
-
- BUG_ON(!c->u.periph.clk_num);
-
- if (!(c->flags & PERIPH_NO_RESET))
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- base + PERIPH_CLK_TO_ENB_SET_REG(c));
-}
-
-static int tegra20_periph_clk_set_parent(struct clk_hw *hw, u8 index)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- u32 mask;
- u32 shift;
-
- pr_debug("%s: %s %d\n", __func__, __clk_get_name(hw->clk), index);
-
- if (c->flags & MUX_PWM) {
- shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
- mask = PERIPH_CLK_SOURCE_PWM_MASK;
- } else {
- shift = PERIPH_CLK_SOURCE_SHIFT;
- mask = PERIPH_CLK_SOURCE_MASK;
- }
-
- val = clk_readl(c->reg);
- val &= ~mask;
- val |= (index) << shift;
-
- clk_writel(val, c->reg);
-
- return 0;
-}
-
-static u8 tegra20_periph_clk_get_parent(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
- u32 mask;
- u32 shift;
-
- if (c->flags & MUX_PWM) {
- shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
- mask = PERIPH_CLK_SOURCE_PWM_MASK;
- } else {
- shift = PERIPH_CLK_SOURCE_SHIFT;
- mask = PERIPH_CLK_SOURCE_MASK;
- }
-
- if (c->flags & MUX)
- return (val & mask) >> shift;
- else
- return 0;
-}
-
-static unsigned long tegra20_periph_clk_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long rate = prate;
- u32 val = clk_readl(c->reg);
-
- if (c->flags & DIV_U71) {
- u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
- c->div = divu71 + 2;
- c->mul = 2;
- } else if (c->flags & DIV_U16) {
- u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
- c->div = divu16 + 1;
- c->mul = 1;
- } else {
- c->div = 1;
- c->mul = 1;
- return rate;
- }
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
-
- return rate;
-}
-
-static int tegra20_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- int divider;
-
- val = clk_readl(c->reg);
-
- if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(parent_rate, rate);
-
- if (divider >= 0) {
- val = clk_readl(c->reg);
- val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
- val |= divider;
- clk_writel(val, c->reg);
- c->div = divider + 2;
- c->mul = 2;
- return 0;
- }
- } else if (c->flags & DIV_U16) {
- divider = clk_div16_get_divider(parent_rate, rate);
- if (divider >= 0) {
- val = clk_readl(c->reg);
- val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
- val |= divider;
- clk_writel(val, c->reg);
- c->div = divider + 1;
- c->mul = 1;
- return 0;
- }
- } else if (parent_rate <= rate) {
- c->div = 1;
- c->mul = 1;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static long tegra20_periph_clk_round_rate(struct clk_hw *hw,
- unsigned long rate, unsigned long *prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
- int divider;
-
- pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
-
- if (prate)
- parent_rate = *prate;
-
- if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(parent_rate, rate);
- if (divider < 0)
- return divider;
-
- return DIV_ROUND_UP(parent_rate * 2, divider + 2);
- } else if (c->flags & DIV_U16) {
- divider = clk_div16_get_divider(parent_rate, rate);
- if (divider < 0)
- return divider;
- return DIV_ROUND_UP(parent_rate, divider + 1);
- }
- return -EINVAL;
-}
-
-struct clk_ops tegra_periph_clk_ops = {
- .is_enabled = tegra20_periph_clk_is_enabled,
- .enable = tegra20_periph_clk_enable,
- .disable = tegra20_periph_clk_disable,
- .set_parent = tegra20_periph_clk_set_parent,
- .get_parent = tegra20_periph_clk_get_parent,
- .set_rate = tegra20_periph_clk_set_rate,
- .round_rate = tegra20_periph_clk_round_rate,
- .recalc_rate = tegra20_periph_clk_recalc_rate,
-};
-
-/* External memory controller clock ops */
-static void tegra20_emc_clk_init(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- c->max_rate = __clk_get_rate(hw->clk);
-}
-
-static long tegra20_emc_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- long emc_rate;
- long clk_rate;
-
- /*
- * The slowest entry in the EMC clock table that is at least as
- * fast as rate.
- */
- emc_rate = tegra_emc_round_rate(rate);
- if (emc_rate < 0)
- return c->max_rate;
-
- /*
- * The fastest rate the PLL will generate that is at most the
- * requested rate.
- */
- clk_rate = tegra20_periph_clk_round_rate(hw, emc_rate, NULL);
-
- /*
- * If this fails, and emc_rate > clk_rate, it's because the maximum
- * rate in the EMC tables is larger than the maximum rate of the EMC
- * clock. The EMC clock's max rate is the rate it was running when the
- * kernel booted. Such a mismatch is probably due to using the wrong
- * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
- */
- WARN_ONCE(emc_rate != clk_rate,
- "emc_rate %ld != clk_rate %ld",
- emc_rate, clk_rate);
-
- return emc_rate;
-}
-
-static int tegra20_emc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- int ret;
-
- /*
- * The Tegra2 memory controller has an interlock with the clock
- * block that allows memory shadowed registers to be updated,
- * and then transfer them to the main registers at the same
- * time as the clock update without glitches.
- */
- ret = tegra_emc_set_rate(rate);
- if (ret < 0)
- return ret;
-
- ret = tegra20_periph_clk_set_rate(hw, rate, parent_rate);
- udelay(1);
-
- return ret;
-}
-
-struct clk_ops tegra_emc_clk_ops = {
- .init = tegra20_emc_clk_init,
- .is_enabled = tegra20_periph_clk_is_enabled,
- .enable = tegra20_periph_clk_enable,
- .disable = tegra20_periph_clk_disable,
- .set_parent = tegra20_periph_clk_set_parent,
- .get_parent = tegra20_periph_clk_get_parent,
- .set_rate = tegra20_emc_clk_set_rate,
- .round_rate = tegra20_emc_clk_round_rate,
- .recalc_rate = tegra20_periph_clk_recalc_rate,
-};
-
-/* Clock doubler ops */
-static int tegra20_clk_double_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- c->state = ON;
-
- if (!c->u.periph.clk_num)
- goto out;
-
- if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
- PERIPH_CLK_TO_ENB_BIT(c)))
- c->state = OFF;
-
-out:
- return c->state;
-};
-
-static unsigned long tegra20_clk_double_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = prate;
-
- c->mul = 2;
- c->div = 1;
-
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
-
- return rate;
-}
-
-static long tegra20_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- unsigned long output_rate = *prate;
-
- do_div(output_rate, 2);
- return output_rate;
-}
-
-static int tegra20_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- if (rate != 2 * parent_rate)
- return -EINVAL;
- return 0;
-}
-
-struct clk_ops tegra_clk_double_ops = {
- .is_enabled = tegra20_clk_double_is_enabled,
- .enable = tegra20_periph_clk_enable,
- .disable = tegra20_periph_clk_disable,
- .set_rate = tegra20_clk_double_set_rate,
- .recalc_rate = tegra20_clk_double_recalc_rate,
- .round_rate = tegra20_clk_double_round_rate,
-};
-
-/* Audio sync clock ops */
-static int tegra20_audio_sync_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
-
- c->state = (val & (1<<4)) ? OFF : ON;
- return c->state;
-}
-
-static int tegra20_audio_sync_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- clk_writel(0, c->reg);
- return 0;
-}
-
-static void tegra20_audio_sync_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- clk_writel(1, c->reg);
-}
-
-static u8 tegra20_audio_sync_clk_get_parent(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
- int source;
-
- source = val & 0xf;
- return source;
-}
-
-static int tegra20_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- val = clk_readl(c->reg);
- val &= ~0xf;
- val |= index;
-
- clk_writel(val, c->reg);
-
- return 0;
-}
-
-struct clk_ops tegra_audio_sync_clk_ops = {
- .is_enabled = tegra20_audio_sync_clk_is_enabled,
- .enable = tegra20_audio_sync_clk_enable,
- .disable = tegra20_audio_sync_clk_disable,
- .set_parent = tegra20_audio_sync_clk_set_parent,
- .get_parent = tegra20_audio_sync_clk_get_parent,
-};
-
-/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
-
-static int tegra20_cdev_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- /* We could un-tristate the cdev1 or cdev2 pingroup here; this is
- * currently done in the pinmux code. */
- c->state = ON;
-
- BUG_ON(!c->u.periph.clk_num);
-
- if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
- PERIPH_CLK_TO_ENB_BIT(c)))
- c->state = OFF;
- return c->state;
-}
-
-static int tegra20_cdev_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- BUG_ON(!c->u.periph.clk_num);
-
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
- return 0;
-}
-
-static void tegra20_cdev_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- BUG_ON(!c->u.periph.clk_num);
-
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-}
-
-static unsigned long tegra20_cdev_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
-{
- return to_clk_tegra(hw)->fixed_rate;
-}
-
-struct clk_ops tegra_cdev_clk_ops = {
- .is_enabled = tegra20_cdev_clk_is_enabled,
- .enable = tegra20_cdev_clk_enable,
- .disable = tegra20_cdev_clk_disable,
- .recalc_rate = tegra20_cdev_recalc_rate,
-};
-
-/* Tegra20 CPU clock and reset control functions */
-static void tegra20_wait_cpu_in_reset(u32 cpu)
-{
- unsigned int reg;
-
- do {
- reg = readl(reg_clk_base +
- TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
- cpu_relax();
- } while (!(reg & (1 << cpu))); /* check CPU been reset or not */
-
- return;
-}
-
-static void tegra20_put_cpu_in_reset(u32 cpu)
-{
- writel(CPU_RESET(cpu),
- reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
- dmb();
-}
-
-static void tegra20_cpu_out_of_reset(u32 cpu)
-{
- writel(CPU_RESET(cpu),
- reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
- wmb();
-}
-
-static void tegra20_enable_cpu_clock(u32 cpu)
-{
- unsigned int reg;
-
- reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
- writel(reg & ~CPU_CLOCK(cpu),
- reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
- barrier();
- reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-}
-
-static void tegra20_disable_cpu_clock(u32 cpu)
-{
- unsigned int reg;
-
- reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
- writel(reg | CPU_CLOCK(cpu),
- reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-}
-
-static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
- .wait_for_reset = tegra20_wait_cpu_in_reset,
- .put_in_reset = tegra20_put_cpu_in_reset,
- .out_of_reset = tegra20_cpu_out_of_reset,
- .enable_clock = tegra20_enable_cpu_clock,
- .disable_clock = tegra20_disable_cpu_clock,
-};
-
-void __init tegra20_cpu_car_ops_init(void)
-{
- tegra_cpu_car_ops = &tegra20_cpu_car_ops;
-}
diff --git a/arch/arm/mach-tegra/tegra20_clocks.h b/arch/arm/mach-tegra/tegra20_clocks.h
deleted file mode 100644
index 8bfd31bcc490..000000000000
--- a/arch/arm/mach-tegra/tegra20_clocks.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __MACH_TEGRA20_CLOCK_H
-#define __MACH_TEGRA20_CLOCK_H
-
-extern struct clk_ops tegra_clk_32k_ops;
-extern struct clk_ops tegra_pll_ops;
-extern struct clk_ops tegra_clk_m_ops;
-extern struct clk_ops tegra_pll_div_ops;
-extern struct clk_ops tegra_pllx_ops;
-extern struct clk_ops tegra_plle_ops;
-extern struct clk_ops tegra_clk_double_ops;
-extern struct clk_ops tegra_cdev_clk_ops;
-extern struct clk_ops tegra_audio_sync_clk_ops;
-extern struct clk_ops tegra_super_ops;
-extern struct clk_ops tegra_cpu_ops;
-extern struct clk_ops tegra_twd_ops;
-extern struct clk_ops tegra_cop_ops;
-extern struct clk_ops tegra_bus_ops;
-extern struct clk_ops tegra_blink_clk_ops;
-extern struct clk_ops tegra_emc_clk_ops;
-extern struct clk_ops tegra_periph_clk_ops;
-extern struct clk_ops tegra_clk_shared_bus_ops;
-
-void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert);
-void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert);
-
-#endif
diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c
deleted file mode 100644
index a23a0734e352..000000000000
--- a/arch/arm/mach-tegra/tegra20_clocks_data.c
+++ /dev/null
@@ -1,1143 +0,0 @@
-/*
- * arch/arm/mach-tegra/tegra2_clocks.c
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * Author:
- * Colin Cross <ccross@google.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/clk-private.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-
-#include "clock.h"
-#include "fuse.h"
-#include "tegra2_emc.h"
-#include "tegra20_clocks.h"
-#include "tegra_cpu_car.h"
-
-/* Clock definitions */
-
-#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \
- _parent_names, _parents, _parent) \
- static struct clk tegra_##_name = { \
- .hw = &tegra_##_name##_hw.hw, \
- .name = #_name, \
- .rate = _rate, \
- .ops = _ops, \
- .flags = _flags, \
- .parent_names = _parent_names, \
- .parents = _parents, \
- .num_parents = ARRAY_SIZE(_parent_names), \
- .parent = _parent, \
- };
-
-static struct clk tegra_clk_32k;
-static struct clk_tegra tegra_clk_32k_hw = {
- .hw = {
- .clk = &tegra_clk_32k,
- },
- .fixed_rate = 32768,
-};
-
-static struct clk tegra_clk_32k = {
- .name = "clk_32k",
- .rate = 32768,
- .ops = &tegra_clk_32k_ops,
- .hw = &tegra_clk_32k_hw.hw,
- .flags = CLK_IS_ROOT,
-};
-
-static struct clk tegra_clk_m;
-static struct clk_tegra tegra_clk_m_hw = {
- .hw = {
- .clk = &tegra_clk_m,
- },
- .flags = ENABLE_ON_INIT,
- .reg = 0x1fc,
- .reg_shift = 28,
- .max_rate = 26000000,
- .fixed_rate = 0,
-};
-
-static struct clk tegra_clk_m = {
- .name = "clk_m",
- .ops = &tegra_clk_m_ops,
- .hw = &tegra_clk_m_hw.hw,
- .flags = CLK_IS_ROOT,
-};
-
-#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min, \
- _input_max, _cf_min, _cf_max, _vco_min, \
- _vco_max, _freq_table, _lock_delay, _ops, \
- _fixed_rate, _parent) \
- static const char *tegra_##_name##_parent_names[] = { \
- #_parent, \
- }; \
- static struct clk *tegra_##_name##_parents[] = { \
- &tegra_##_parent, \
- }; \
- static struct clk tegra_##_name; \
- static struct clk_tegra tegra_##_name##_hw = { \
- .hw = { \
- .clk = &tegra_##_name, \
- }, \
- .flags = _flags, \
- .reg = _reg, \
- .max_rate = _max_rate, \
- .u.pll = { \
- .input_min = _input_min, \
- .input_max = _input_max, \
- .cf_min = _cf_min, \
- .cf_max = _cf_max, \
- .vco_min = _vco_min, \
- .vco_max = _vco_max, \
- .freq_table = _freq_table, \
- .lock_delay = _lock_delay, \
- .fixed_rate = _fixed_rate, \
- }, \
- }; \
- static struct clk tegra_##_name = { \
- .name = #_name, \
- .ops = &_ops, \
- .hw = &tegra_##_name##_hw.hw, \
- .parent = &tegra_##_parent, \
- .parent_names = tegra_##_name##_parent_names, \
- .parents = tegra_##_name##_parents, \
- .num_parents = 1, \
- };
-
-#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift, \
- _max_rate, _ops, _parent, _clk_flags) \
- static const char *tegra_##_name##_parent_names[] = { \
- #_parent, \
- }; \
- static struct clk *tegra_##_name##_parents[] = { \
- &tegra_##_parent, \
- }; \
- static struct clk tegra_##_name; \
- static struct clk_tegra tegra_##_name##_hw = { \
- .hw = { \
- .clk = &tegra_##_name, \
- }, \
- .flags = _flags, \
- .reg = _reg, \
- .max_rate = _max_rate, \
- .reg_shift = _reg_shift, \
- }; \
- static struct clk tegra_##_name = { \
- .name = #_name, \
- .ops = &tegra_pll_div_ops, \
- .hw = &tegra_##_name##_hw.hw, \
- .parent = &tegra_##_parent, \
- .parent_names = tegra_##_name##_parent_names, \
- .parents = tegra_##_name##_parents, \
- .num_parents = 1, \
- .flags = _clk_flags, \
- };
-
-
-static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
- {32768, 12000000, 366, 1, 1, 0},
- {32768, 13000000, 397, 1, 1, 0},
- {32768, 19200000, 586, 1, 1, 0},
- {32768, 26000000, 793, 1, 1, 0},
- {0, 0, 0, 0, 0, 0},
-};
-
-DEFINE_PLL(pll_s, PLL_ALT_MISC_REG, 0xf0, 26000000, 32768, 32768, 0,
- 0, 12000000, 26000000, tegra_pll_s_freq_table, 300,
- tegra_pll_ops, 0, clk_32k);
-
-static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
- { 12000000, 600000000, 600, 12, 1, 8 },
- { 13000000, 600000000, 600, 13, 1, 8 },
- { 19200000, 600000000, 500, 16, 1, 6 },
- { 26000000, 600000000, 600, 26, 1, 8 },
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 600000000, 2000000, 31000000, 1000000,
- 6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300,
- tegra_pll_ops, 0, clk_m);
-
-DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 600000000,
- tegra_pll_div_ops, pll_c, 0);
-
-static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
- { 12000000, 666000000, 666, 12, 1, 8},
- { 13000000, 666000000, 666, 13, 1, 8},
- { 19200000, 666000000, 555, 16, 1, 8},
- { 26000000, 666000000, 666, 26, 1, 8},
- { 12000000, 600000000, 600, 12, 1, 8},
- { 13000000, 600000000, 600, 13, 1, 8},
- { 19200000, 600000000, 375, 12, 1, 6},
- { 26000000, 600000000, 600, 26, 1, 8},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_m, PLL_HAS_CPCON, 0x90, 800000000, 2000000, 31000000, 1000000,
- 6000000, 20000000, 1200000000, tegra_pll_m_freq_table, 300,
- tegra_pll_ops, 0, clk_m);
-
-DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000,
- tegra_pll_div_ops, pll_m, 0);
-
-static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
- { 12000000, 216000000, 432, 12, 2, 8},
- { 13000000, 216000000, 432, 13, 2, 8},
- { 19200000, 216000000, 90, 4, 2, 1},
- { 26000000, 216000000, 432, 26, 2, 8},
- { 12000000, 432000000, 432, 12, 1, 8},
- { 13000000, 432000000, 432, 13, 1, 8},
- { 19200000, 432000000, 90, 4, 1, 1},
- { 26000000, 432000000, 432, 26, 1, 8},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-
-DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000,
- 2000000, 31000000, 1000000, 6000000, 20000000, 1400000000,
- tegra_pll_p_freq_table, 300, tegra_pll_ops, 216000000, clk_m);
-
-DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 0,
- 432000000, tegra_pll_div_ops, pll_p, 0);
-DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 16,
- 432000000, tegra_pll_div_ops, pll_p, 0);
-DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 0,
- 432000000, tegra_pll_div_ops, pll_p, 0);
-DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 16,
- 432000000, tegra_pll_div_ops, pll_p, 0);
-
-static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
- { 28800000, 56448000, 49, 25, 1, 1},
- { 28800000, 73728000, 64, 25, 1, 1},
- { 28800000, 24000000, 5, 6, 1, 1},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 73728000, 2000000, 31000000, 1000000,
- 6000000, 20000000, 1400000000, tegra_pll_a_freq_table, 300,
- tegra_pll_ops, 0, pll_p_out1);
-
-DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 73728000,
- tegra_pll_div_ops, pll_a, 0);
-
-static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
- { 12000000, 216000000, 216, 12, 1, 4},
- { 13000000, 216000000, 216, 13, 1, 4},
- { 19200000, 216000000, 135, 12, 1, 3},
- { 26000000, 216000000, 216, 26, 1, 4},
-
- { 12000000, 297000000, 99, 4, 1, 4 },
- { 12000000, 339000000, 113, 4, 1, 4 },
-
- { 12000000, 594000000, 594, 12, 1, 8},
- { 13000000, 594000000, 594, 13, 1, 8},
- { 19200000, 594000000, 495, 16, 1, 8},
- { 26000000, 594000000, 594, 26, 1, 8},
-
- { 12000000, 616000000, 616, 12, 1, 8},
-
- { 12000000, 1000000000, 1000, 12, 1, 12},
- { 13000000, 1000000000, 1000, 13, 1, 12},
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 12},
-
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000,
- 1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table,
- 1000, tegra_pll_ops, 0, clk_m);
-
-DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000,
- tegra_pll_div_ops, pll_d, CLK_SET_RATE_PARENT);
-
-static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
- { 12000000, 480000000, 960, 12, 2, 0},
- { 13000000, 480000000, 960, 13, 2, 0},
- { 19200000, 480000000, 200, 4, 2, 0},
- { 26000000, 480000000, 960, 26, 2, 0},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_u, PLLU, 0xc0, 480000000, 2000000, 40000000, 1000000, 6000000,
- 48000000, 960000000, tegra_pll_u_freq_table, 1000,
- tegra_pll_ops, 0, clk_m);
-
-static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
- /* 1 GHz */
- { 12000000, 1000000000, 1000, 12, 1, 12},
- { 13000000, 1000000000, 1000, 13, 1, 12},
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 12},
-
- /* 912 MHz */
- { 12000000, 912000000, 912, 12, 1, 12},
- { 13000000, 912000000, 912, 13, 1, 12},
- { 19200000, 912000000, 760, 16, 1, 8},
- { 26000000, 912000000, 912, 26, 1, 12},
-
- /* 816 MHz */
- { 12000000, 816000000, 816, 12, 1, 12},
- { 13000000, 816000000, 816, 13, 1, 12},
- { 19200000, 816000000, 680, 16, 1, 8},
- { 26000000, 816000000, 816, 26, 1, 12},
-
- /* 760 MHz */
- { 12000000, 760000000, 760, 12, 1, 12},
- { 13000000, 760000000, 760, 13, 1, 12},
- { 19200000, 760000000, 950, 24, 1, 8},
- { 26000000, 760000000, 760, 26, 1, 12},
-
- /* 750 MHz */
- { 12000000, 750000000, 750, 12, 1, 12},
- { 13000000, 750000000, 750, 13, 1, 12},
- { 19200000, 750000000, 625, 16, 1, 8},
- { 26000000, 750000000, 750, 26, 1, 12},
-
- /* 608 MHz */
- { 12000000, 608000000, 608, 12, 1, 12},
- { 13000000, 608000000, 608, 13, 1, 12},
- { 19200000, 608000000, 380, 12, 1, 8},
- { 26000000, 608000000, 608, 26, 1, 12},
-
- /* 456 MHz */
- { 12000000, 456000000, 456, 12, 1, 12},
- { 13000000, 456000000, 456, 13, 1, 12},
- { 19200000, 456000000, 380, 16, 1, 8},
- { 26000000, 456000000, 456, 26, 1, 12},
-
- /* 312 MHz */
- { 12000000, 312000000, 312, 12, 1, 12},
- { 13000000, 312000000, 312, 13, 1, 12},
- { 19200000, 312000000, 260, 16, 1, 8},
- { 26000000, 312000000, 312, 26, 1, 12},
-
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG, 0xe0, 1000000000, 2000000,
- 31000000, 1000000, 6000000, 20000000, 1200000000,
- tegra_pll_x_freq_table, 300, tegra_pllx_ops, 0, clk_m);
-
-static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
- { 12000000, 100000000, 200, 24, 1, 0 },
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 12000000, 12000000, 0, 0,
- 0, 0, tegra_pll_e_freq_table, 0, tegra_plle_ops, 0, clk_m);
-
-static const char *tegra_common_parent_names[] = {
- "clk_m",
-};
-
-static struct clk *tegra_common_parents[] = {
- &tegra_clk_m,
-};
-
-static struct clk tegra_clk_d;
-static struct clk_tegra tegra_clk_d_hw = {
- .hw = {
- .clk = &tegra_clk_d,
- },
- .flags = PERIPH_NO_RESET,
- .reg = 0x34,
- .reg_shift = 12,
- .max_rate = 52000000,
- .u.periph = {
- .clk_num = 90,
- },
-};
-
-static struct clk tegra_clk_d = {
- .name = "clk_d",
- .hw = &tegra_clk_d_hw.hw,
- .ops = &tegra_clk_double_ops,
- .parent = &tegra_clk_m,
- .parent_names = tegra_common_parent_names,
- .parents = tegra_common_parents,
- .num_parents = ARRAY_SIZE(tegra_common_parent_names),
-};
-
-static struct clk tegra_cdev1;
-static struct clk_tegra tegra_cdev1_hw = {
- .hw = {
- .clk = &tegra_cdev1,
- },
- .fixed_rate = 26000000,
- .u.periph = {
- .clk_num = 94,
- },
-};
-static struct clk tegra_cdev1 = {
- .name = "cdev1",
- .hw = &tegra_cdev1_hw.hw,
- .ops = &tegra_cdev_clk_ops,
- .flags = CLK_IS_ROOT,
-};
-
-/* dap_mclk2, belongs to the cdev2 pingroup. */
-static struct clk tegra_cdev2;
-static struct clk_tegra tegra_cdev2_hw = {
- .hw = {
- .clk = &tegra_cdev2,
- },
- .fixed_rate = 26000000,
- .u.periph = {
- .clk_num = 93,
- },
-};
-static struct clk tegra_cdev2 = {
- .name = "cdev2",
- .hw = &tegra_cdev2_hw.hw,
- .ops = &tegra_cdev_clk_ops,
- .flags = CLK_IS_ROOT,
-};
-
-/* initialized before peripheral clocks */
-static struct clk_mux_sel mux_audio_sync_clk[8+1];
-static const struct audio_sources {
- const char *name;
- int value;
-} mux_audio_sync_clk_sources[] = {
- { .name = "spdif_in", .value = 0 },
- { .name = "i2s1", .value = 1 },
- { .name = "i2s2", .value = 2 },
- { .name = "pll_a_out0", .value = 4 },
-#if 0 /* FIXME: not implemented */
- { .name = "ac97", .value = 3 },
- { .name = "ext_audio_clk2", .value = 5 },
- { .name = "ext_audio_clk1", .value = 6 },
- { .name = "ext_vimclk", .value = 7 },
-#endif
- { NULL, 0 }
-};
-
-static const char *audio_parent_names[] = {
- "spdif_in",
- "i2s1",
- "i2s2",
- "dummy",
- "pll_a_out0",
- "dummy",
- "dummy",
- "dummy",
-};
-
-static struct clk *audio_parents[] = {
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
-};
-
-static struct clk tegra_audio;
-static struct clk_tegra tegra_audio_hw = {
- .hw = {
- .clk = &tegra_audio,
- },
- .reg = 0x38,
- .max_rate = 73728000,
-};
-DEFINE_CLK_TEGRA(audio, 0, &tegra_audio_sync_clk_ops, 0, audio_parent_names,
- audio_parents, NULL);
-
-static const char *audio_2x_parent_names[] = {
- "audio",
-};
-
-static struct clk *audio_2x_parents[] = {
- &tegra_audio,
-};
-
-static struct clk tegra_audio_2x;
-static struct clk_tegra tegra_audio_2x_hw = {
- .hw = {
- .clk = &tegra_audio_2x,
- },
- .flags = PERIPH_NO_RESET,
- .max_rate = 48000000,
- .reg = 0x34,
- .reg_shift = 8,
- .u.periph = {
- .clk_num = 89,
- },
-};
-DEFINE_CLK_TEGRA(audio_2x, 0, &tegra_clk_double_ops, 0, audio_2x_parent_names,
- audio_2x_parents, &tegra_audio);
-
-static struct clk_lookup tegra_audio_clk_lookups[] = {
- { .con_id = "audio", .clk = &tegra_audio },
- { .con_id = "audio_2x", .clk = &tegra_audio_2x }
-};
-
-/* This is called after peripheral clocks are initialized, as the
- * audio_sync clock depends on some of the peripheral clocks.
- */
-
-static void init_audio_sync_clock_mux(void)
-{
- int i;
- struct clk_mux_sel *sel = mux_audio_sync_clk;
- const struct audio_sources *src = mux_audio_sync_clk_sources;
- struct clk_lookup *lookup;
-
- for (i = 0; src->name; i++, sel++, src++) {
- sel->input = tegra_get_clock_by_name(src->name);
- if (!sel->input)
- pr_err("%s: could not find clk %s\n", __func__,
- src->name);
- audio_parents[src->value] = sel->input;
- sel->value = src->value;
- }
-
- lookup = tegra_audio_clk_lookups;
- for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
- struct clk *c = lookup->clk;
- struct clk_tegra *clk = to_clk_tegra(c->hw);
- __clk_init(NULL, c);
- INIT_LIST_HEAD(&clk->shared_bus_list);
- clk->lookup.con_id = lookup->con_id;
- clk->lookup.clk = c;
- clkdev_add(&clk->lookup);
- tegra_clk_add(c);
- }
-}
-
-static const char *mux_cclk[] = {
- "clk_m",
- "pll_c",
- "clk_32k",
- "pll_m",
- "pll_p",
- "pll_p_out4",
- "pll_p_out3",
- "clk_d",
- "pll_x",
-};
-
-
-static struct clk *mux_cclk_p[] = {
- &tegra_clk_m,
- &tegra_pll_c,
- &tegra_clk_32k,
- &tegra_pll_m,
- &tegra_pll_p,
- &tegra_pll_p_out4,
- &tegra_pll_p_out3,
- &tegra_clk_d,
- &tegra_pll_x,
-};
-
-static const char *mux_sclk[] = {
- "clk_m",
- "pll_c_out1",
- "pll_p_out4",
- "pllp_p_out3",
- "pll_p_out2",
- "clk_d",
- "clk_32k",
- "pll_m_out1",
-};
-
-static struct clk *mux_sclk_p[] = {
- &tegra_clk_m,
- &tegra_pll_c_out1,
- &tegra_pll_p_out4,
- &tegra_pll_p_out3,
- &tegra_pll_p_out2,
- &tegra_clk_d,
- &tegra_clk_32k,
- &tegra_pll_m_out1,
-};
-
-static struct clk tegra_cclk;
-static struct clk_tegra tegra_cclk_hw = {
- .hw = {
- .clk = &tegra_cclk,
- },
- .reg = 0x20,
- .max_rate = 1000000000,
-};
-DEFINE_CLK_TEGRA(cclk, 0, &tegra_super_ops, 0, mux_cclk,
- mux_cclk_p, NULL);
-
-static const char *mux_twd[] = {
- "cclk",
-};
-
-static struct clk *mux_twd_p[] = {
- &tegra_cclk,
-};
-
-static struct clk tegra_clk_twd;
-static struct clk_tegra tegra_clk_twd_hw = {
- .hw = {
- .clk = &tegra_clk_twd,
- },
- .max_rate = 1000000000,
- .mul = 1,
- .div = 4,
-};
-
-static struct clk tegra_clk_twd = {
- .name = "twd",
- .ops = &tegra_twd_ops,
- .hw = &tegra_clk_twd_hw.hw,
- .parent = &tegra_cclk,
- .parent_names = mux_twd,
- .parents = mux_twd_p,
- .num_parents = ARRAY_SIZE(mux_twd),
-};
-
-static struct clk tegra_sclk;
-static struct clk_tegra tegra_sclk_hw = {
- .hw = {
- .clk = &tegra_sclk,
- },
- .reg = 0x28,
- .max_rate = 240000000,
- .min_rate = 120000000,
-};
-DEFINE_CLK_TEGRA(sclk, 0, &tegra_super_ops, 0, mux_sclk,
- mux_sclk_p, NULL);
-
-static const char *tegra_cop_parent_names[] = {
- "tegra_sclk",
-};
-
-static struct clk *tegra_cop_parents[] = {
- &tegra_sclk,
-};
-
-static struct clk tegra_cop;
-static struct clk_tegra tegra_cop_hw = {
- .hw = {
- .clk = &tegra_cop,
- },
- .max_rate = 240000000,
- .reset = &tegra2_cop_clk_reset,
-};
-DEFINE_CLK_TEGRA(cop, 0, &tegra_cop_ops, CLK_SET_RATE_PARENT,
- tegra_cop_parent_names, tegra_cop_parents, &tegra_sclk);
-
-static const char *tegra_hclk_parent_names[] = {
- "tegra_sclk",
-};
-
-static struct clk *tegra_hclk_parents[] = {
- &tegra_sclk,
-};
-
-static struct clk tegra_hclk;
-static struct clk_tegra tegra_hclk_hw = {
- .hw = {
- .clk = &tegra_hclk,
- },
- .flags = DIV_BUS,
- .reg = 0x30,
- .reg_shift = 4,
- .max_rate = 240000000,
-};
-DEFINE_CLK_TEGRA(hclk, 0, &tegra_bus_ops, 0, tegra_hclk_parent_names,
- tegra_hclk_parents, &tegra_sclk);
-
-static const char *tegra_pclk_parent_names[] = {
- "tegra_hclk",
-};
-
-static struct clk *tegra_pclk_parents[] = {
- &tegra_hclk,
-};
-
-static struct clk tegra_pclk;
-static struct clk_tegra tegra_pclk_hw = {
- .hw = {
- .clk = &tegra_pclk,
- },
- .flags = DIV_BUS,
- .reg = 0x30,
- .reg_shift = 0,
- .max_rate = 120000000,
-};
-DEFINE_CLK_TEGRA(pclk, 0, &tegra_bus_ops, 0, tegra_pclk_parent_names,
- tegra_pclk_parents, &tegra_hclk);
-
-static const char *tegra_blink_parent_names[] = {
- "clk_32k",
-};
-
-static struct clk *tegra_blink_parents[] = {
- &tegra_clk_32k,
-};
-
-static struct clk tegra_blink;
-static struct clk_tegra tegra_blink_hw = {
- .hw = {
- .clk = &tegra_blink,
- },
- .reg = 0x40,
- .max_rate = 32768,
-};
-DEFINE_CLK_TEGRA(blink, 0, &tegra_blink_clk_ops, 0, tegra_blink_parent_names,
- tegra_blink_parents, &tegra_clk_32k);
-
-static const char *mux_pllm_pllc_pllp_plla[] = {
- "pll_m",
- "pll_c",
- "pll_p",
- "pll_a_out0",
-};
-
-static struct clk *mux_pllm_pllc_pllp_plla_p[] = {
- &tegra_pll_m,
- &tegra_pll_c,
- &tegra_pll_p,
- &tegra_pll_a_out0,
-};
-
-static const char *mux_pllm_pllc_pllp_clkm[] = {
- "pll_m",
- "pll_c",
- "pll_p",
- "clk_m",
-};
-
-static struct clk *mux_pllm_pllc_pllp_clkm_p[] = {
- &tegra_pll_m,
- &tegra_pll_c,
- &tegra_pll_p,
- &tegra_clk_m,
-};
-
-static const char *mux_pllp_pllc_pllm_clkm[] = {
- "pll_p",
- "pll_c",
- "pll_m",
- "clk_m",
-};
-
-static struct clk *mux_pllp_pllc_pllm_clkm_p[] = {
- &tegra_pll_p,
- &tegra_pll_c,
- &tegra_pll_m,
- &tegra_clk_m,
-};
-
-static const char *mux_pllaout0_audio2x_pllp_clkm[] = {
- "pll_a_out0",
- "audio_2x",
- "pll_p",
- "clk_m",
-};
-
-static struct clk *mux_pllaout0_audio2x_pllp_clkm_p[] = {
- &tegra_pll_a_out0,
- &tegra_audio_2x,
- &tegra_pll_p,
- &tegra_clk_m,
-};
-
-static const char *mux_pllp_plld_pllc_clkm[] = {
- "pllp",
- "pll_d_out0",
- "pll_c",
- "clk_m",
-};
-
-static struct clk *mux_pllp_plld_pllc_clkm_p[] = {
- &tegra_pll_p,
- &tegra_pll_d_out0,
- &tegra_pll_c,
- &tegra_clk_m,
-};
-
-static const char *mux_pllp_pllc_audio_clkm_clk32[] = {
- "pll_p",
- "pll_c",
- "audio",
- "clk_m",
- "clk_32k",
-};
-
-static struct clk *mux_pllp_pllc_audio_clkm_clk32_p[] = {
- &tegra_pll_p,
- &tegra_pll_c,
- &tegra_audio,
- &tegra_clk_m,
- &tegra_clk_32k,
-};
-
-static const char *mux_pllp_pllc_pllm[] = {
- "pll_p",
- "pll_c",
- "pll_m"
-};
-
-static struct clk *mux_pllp_pllc_pllm_p[] = {
- &tegra_pll_p,
- &tegra_pll_c,
- &tegra_pll_m,
-};
-
-static const char *mux_clk_m[] = {
- "clk_m",
-};
-
-static struct clk *mux_clk_m_p[] = {
- &tegra_clk_m,
-};
-
-static const char *mux_pllp_out3[] = {
- "pll_p_out3",
-};
-
-static struct clk *mux_pllp_out3_p[] = {
- &tegra_pll_p_out3,
-};
-
-static const char *mux_plld[] = {
- "pll_d",
-};
-
-static struct clk *mux_plld_p[] = {
- &tegra_pll_d,
-};
-
-static const char *mux_clk_32k[] = {
- "clk_32k",
-};
-
-static struct clk *mux_clk_32k_p[] = {
- &tegra_clk_32k,
-};
-
-static const char *mux_pclk[] = {
- "pclk",
-};
-
-static struct clk *mux_pclk_p[] = {
- &tegra_pclk,
-};
-
-static struct clk tegra_emc;
-static struct clk_tegra tegra_emc_hw = {
- .hw = {
- .clk = &tegra_emc,
- },
- .reg = 0x19c,
- .max_rate = 800000000,
- .flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
- .reset = &tegra2_periph_clk_reset,
- .u.periph = {
- .clk_num = 57,
- },
-};
-DEFINE_CLK_TEGRA(emc, 0, &tegra_emc_clk_ops, 0, mux_pllm_pllc_pllp_clkm,
- mux_pllm_pllc_pllp_clkm_p, NULL);
-
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, \
- _max, _inputs, _flags) \
- static struct clk tegra_##_name; \
- static struct clk_tegra tegra_##_name##_hw = { \
- .hw = { \
- .clk = &tegra_##_name, \
- }, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- .reg = _reg, \
- .flags = _flags, \
- .max_rate = _max, \
- .u.periph = { \
- .clk_num = _clk_num, \
- }, \
- .reset = tegra2_periph_clk_reset, \
- }; \
- static struct clk tegra_##_name = { \
- .name = #_name, \
- .ops = &tegra_periph_clk_ops, \
- .hw = &tegra_##_name##_hw.hw, \
- .parent_names = _inputs, \
- .parents = _inputs##_p, \
- .num_parents = ARRAY_SIZE(_inputs), \
- };
-
-PERIPH_CLK(apbdma, "tegra-apbdma", NULL, 34, 0, 108000000, mux_pclk, 0);
-PERIPH_CLK(rtc, "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET);
-PERIPH_CLK(timer, "timer", NULL, 5, 0, 26000000, mux_clk_m, 0);
-PERIPH_CLK(i2s1, "tegra20-i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71);
-PERIPH_CLK(i2s2, "tegra20-i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71);
-PERIPH_CLK(spdif_out, "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71);
-PERIPH_CLK(spdif_in, "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71);
-PERIPH_CLK(pwm, "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71 | MUX_PWM);
-PERIPH_CLK(spi, "spi", NULL, 43, 0x114, 40000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(xio, "xio", NULL, 45, 0x120, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(twc, "twc", NULL, 16, 0x12c, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(sbc1, "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(sbc2, "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(sbc3, "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(sbc4, "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(ide, "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */
-PERIPH_CLK(ndflash, "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
-PERIPH_CLK(vfir, "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(sdmmc1, "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
-PERIPH_CLK(sdmmc2, "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
-PERIPH_CLK(sdmmc3, "sdhci-tegra.2", NULL, 69, 0x1bc, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
-PERIPH_CLK(sdmmc4, "sdhci-tegra.3", NULL, 15, 0x164, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
-PERIPH_CLK(vcp, "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0);
-PERIPH_CLK(bsea, "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0);
-PERIPH_CLK(bsev, "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0);
-PERIPH_CLK(vde, "tegra-avp", "vde", 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage and process_id */
-PERIPH_CLK(csite, "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* max rate ??? */
-/* FIXME: what is la? */
-PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(owr, "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(nor, "nor", NULL, 42, 0x1d0, 92000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */
-PERIPH_CLK(mipi, "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
-PERIPH_CLK(i2c1, "tegra-i2c.0", "div-clk", 12, 0x124, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16);
-PERIPH_CLK(i2c2, "tegra-i2c.1", "div-clk", 54, 0x198, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16);
-PERIPH_CLK(i2c3, "tegra-i2c.2", "div-clk", 67, 0x1b8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16);
-PERIPH_CLK(dvc, "tegra-i2c.3", "div-clk", 47, 0x128, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16);
-PERIPH_CLK(uarta, "tegra-uart.0", NULL, 6, 0x178, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
-PERIPH_CLK(uartb, "tegra-uart.1", NULL, 7, 0x17c, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
-PERIPH_CLK(uartc, "tegra-uart.2", NULL, 55, 0x1a0, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
-PERIPH_CLK(uartd, "tegra-uart.3", NULL, 65, 0x1c0, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
-PERIPH_CLK(uarte, "tegra-uart.4", NULL, 66, 0x1c4, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
-PERIPH_CLK(3d, "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET); /* scales with voltage and process_id */
-PERIPH_CLK(2d, "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
-PERIPH_CLK(vi, "tegra_camera", "vi", 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
-PERIPH_CLK(vi_sensor, "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET); /* scales with voltage and process_id */
-PERIPH_CLK(epp, "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
-PERIPH_CLK(mpe, "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
-PERIPH_CLK(host1x, "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
-PERIPH_CLK(cve, "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
-PERIPH_CLK(tvo, "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
-PERIPH_CLK(hdmi, "hdmi", NULL, 51, 0x18c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
-PERIPH_CLK(tvdac, "tvdac", NULL, 53, 0x194, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
-PERIPH_CLK(disp1, "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_plld_pllc_clkm, MUX); /* scales with voltage and process_id */
-PERIPH_CLK(disp2, "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_plld_pllc_clkm, MUX); /* scales with voltage and process_id */
-PERIPH_CLK(usbd, "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
-PERIPH_CLK(usb2, "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
-PERIPH_CLK(usb3, "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
-PERIPH_CLK(dsi, "dsi", NULL, 48, 0, 500000000, mux_plld, 0); /* scales with voltage */
-PERIPH_CLK(csi, "tegra_camera", "csi", 52, 0, 72000000, mux_pllp_out3, 0);
-PERIPH_CLK(isp, "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0); /* same frequency as VI */
-PERIPH_CLK(csus, "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET);
-PERIPH_CLK(pex, NULL, "pex", 70, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET);
-PERIPH_CLK(afi, NULL, "afi", 72, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET);
-PERIPH_CLK(pcie_xclk, NULL, "pcie_xclk", 74, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET);
-
-static struct clk *tegra_list_clks[] = {
- &tegra_apbdma,
- &tegra_rtc,
- &tegra_timer,
- &tegra_i2s1,
- &tegra_i2s2,
- &tegra_spdif_out,
- &tegra_spdif_in,
- &tegra_pwm,
- &tegra_spi,
- &tegra_xio,
- &tegra_twc,
- &tegra_sbc1,
- &tegra_sbc2,
- &tegra_sbc3,
- &tegra_sbc4,
- &tegra_ide,
- &tegra_ndflash,
- &tegra_vfir,
- &tegra_sdmmc1,
- &tegra_sdmmc2,
- &tegra_sdmmc3,
- &tegra_sdmmc4,
- &tegra_vcp,
- &tegra_bsea,
- &tegra_bsev,
- &tegra_vde,
- &tegra_csite,
- &tegra_la,
- &tegra_owr,
- &tegra_nor,
- &tegra_mipi,
- &tegra_i2c1,
- &tegra_i2c2,
- &tegra_i2c3,
- &tegra_dvc,
- &tegra_uarta,
- &tegra_uartb,
- &tegra_uartc,
- &tegra_uartd,
- &tegra_uarte,
- &tegra_3d,
- &tegra_2d,
- &tegra_vi,
- &tegra_vi_sensor,
- &tegra_epp,
- &tegra_mpe,
- &tegra_host1x,
- &tegra_cve,
- &tegra_tvo,
- &tegra_hdmi,
- &tegra_tvdac,
- &tegra_disp1,
- &tegra_disp2,
- &tegra_usbd,
- &tegra_usb2,
- &tegra_usb3,
- &tegra_dsi,
- &tegra_csi,
- &tegra_isp,
- &tegra_csus,
- &tegra_pex,
- &tegra_afi,
- &tegra_pcie_xclk,
-};
-
-#define CLK_DUPLICATE(_name, _dev, _con) \
- { \
- .name = _name, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- }
-
-/* Some clocks may be used by different drivers depending on the board
- * configuration. List those here to register them twice in the clock lookup
- * table under two names.
- */
-static struct clk_duplicate tegra_clk_duplicates[] = {
- CLK_DUPLICATE("uarta", "serial8250.0", NULL),
- CLK_DUPLICATE("uartb", "serial8250.1", NULL),
- CLK_DUPLICATE("uartc", "serial8250.2", NULL),
- CLK_DUPLICATE("uartd", "serial8250.3", NULL),
- CLK_DUPLICATE("uarte", "serial8250.4", NULL),
- CLK_DUPLICATE("usbd", "utmip-pad", NULL),
- CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
- CLK_DUPLICATE("usbd", "tegra-otg", NULL),
- CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
- CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
- CLK_DUPLICATE("epp", "tegra_grhost", "epp"),
- CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"),
- CLK_DUPLICATE("cop", "tegra-avp", "cop"),
- CLK_DUPLICATE("vde", "tegra-aes", "vde"),
- CLK_DUPLICATE("cclk", NULL, "cpu"),
- CLK_DUPLICATE("twd", "smp_twd", NULL),
- CLK_DUPLICATE("pll_p_out3", "tegra-i2c.0", "fast-clk"),
- CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"),
- CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"),
- CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"),
- CLK_DUPLICATE("pll_p", "tegradc.0", "parent"),
- CLK_DUPLICATE("pll_p", "tegradc.1", "parent"),
- CLK_DUPLICATE("pll_d_out0", "hdmi", "parent"),
-};
-
-#define CLK(dev, con, ck) \
- { \
- .dev_id = dev, \
- .con_id = con, \
- .clk = ck, \
- }
-
-static struct clk *tegra_ptr_clks[] = {
- &tegra_clk_32k,
- &tegra_pll_s,
- &tegra_clk_m,
- &tegra_pll_m,
- &tegra_pll_m_out1,
- &tegra_pll_c,
- &tegra_pll_c_out1,
- &tegra_pll_p,
- &tegra_pll_p_out1,
- &tegra_pll_p_out2,
- &tegra_pll_p_out3,
- &tegra_pll_p_out4,
- &tegra_pll_a,
- &tegra_pll_a_out0,
- &tegra_pll_d,
- &tegra_pll_d_out0,
- &tegra_pll_u,
- &tegra_pll_x,
- &tegra_pll_e,
- &tegra_cclk,
- &tegra_clk_twd,
- &tegra_sclk,
- &tegra_hclk,
- &tegra_pclk,
- &tegra_clk_d,
- &tegra_cdev1,
- &tegra_cdev2,
- &tegra_blink,
- &tegra_cop,
- &tegra_emc,
-};
-
-static void tegra2_init_one_clock(struct clk *c)
-{
- struct clk_tegra *clk = to_clk_tegra(c->hw);
- int ret;
-
- ret = __clk_init(NULL, c);
- if (ret)
- pr_err("clk init failed %s\n", __clk_get_name(c));
-
- INIT_LIST_HEAD(&clk->shared_bus_list);
- if (!clk->lookup.dev_id && !clk->lookup.con_id)
- clk->lookup.con_id = c->name;
- clk->lookup.clk = c;
- clkdev_add(&clk->lookup);
- tegra_clk_add(c);
-}
-
-void __init tegra2_init_clocks(void)
-{
- int i;
- struct clk *c;
-
- for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
- tegra2_init_one_clock(tegra_ptr_clks[i]);
-
- for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
- tegra2_init_one_clock(tegra_list_clks[i]);
-
- for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
- c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
- if (!c) {
- pr_err("%s: Unknown duplicate clock %s\n", __func__,
- tegra_clk_duplicates[i].name);
- continue;
- }
-
- tegra_clk_duplicates[i].lookup.clk = c;
- clkdev_add(&tegra_clk_duplicates[i].lookup);
- }
-
- init_audio_sync_clock_mux();
- tegra20_cpu_car_ops_init();
-}
diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c
index e18aa2f83ebf..ce7ce42a1ac9 100644
--- a/arch/arm/mach-tegra/tegra2_emc.c
+++ b/arch/arm/mach-tegra/tegra2_emc.c
@@ -312,11 +312,9 @@ static int tegra_emc_probe(struct platform_device *pdev)
return -ENOMEM;
}
- emc_regbase = devm_request_and_ioremap(&pdev->dev, res);
- if (!emc_regbase) {
- dev_err(&pdev->dev, "failed to remap registers\n");
- return -ENOMEM;
- }
+ emc_regbase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(emc_regbase))
+ return PTR_ERR(emc_regbase);
pdata = pdev->dev.platform_data;
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
deleted file mode 100644
index d7147779f8ea..000000000000
--- a/arch/arm/mach-tegra/tegra30_clocks.c
+++ /dev/null
@@ -1,2506 +0,0 @@
-/*
- * arch/arm/mach-tegra/tegra30_clocks.c
- *
- * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-#include <linux/syscore_ops.h>
-
-#include <asm/clkdev.h>
-
-#include <mach/powergate.h>
-
-#include "clock.h"
-#include "fuse.h"
-#include "iomap.h"
-#include "tegra_cpu_car.h"
-
-#define USE_PLL_LOCK_BITS 0
-
-#define RST_DEVICES_L 0x004
-#define RST_DEVICES_H 0x008
-#define RST_DEVICES_U 0x00C
-#define RST_DEVICES_V 0x358
-#define RST_DEVICES_W 0x35C
-#define RST_DEVICES_SET_L 0x300
-#define RST_DEVICES_CLR_L 0x304
-#define RST_DEVICES_SET_V 0x430
-#define RST_DEVICES_CLR_V 0x434
-#define RST_DEVICES_NUM 5
-
-#define CLK_OUT_ENB_L 0x010
-#define CLK_OUT_ENB_H 0x014
-#define CLK_OUT_ENB_U 0x018
-#define CLK_OUT_ENB_V 0x360
-#define CLK_OUT_ENB_W 0x364
-#define CLK_OUT_ENB_SET_L 0x320
-#define CLK_OUT_ENB_CLR_L 0x324
-#define CLK_OUT_ENB_SET_V 0x440
-#define CLK_OUT_ENB_CLR_V 0x444
-#define CLK_OUT_ENB_NUM 5
-
-#define RST_DEVICES_V_SWR_CPULP_RST_DIS (0x1 << 1)
-#define CLK_OUT_ENB_V_CLK_ENB_CPULP_EN (0x1 << 1)
-
-#define PERIPH_CLK_TO_BIT(c) (1 << (c->u.periph.clk_num % 32))
-#define PERIPH_CLK_TO_RST_REG(c) \
- periph_clk_to_reg((c), RST_DEVICES_L, RST_DEVICES_V, 4)
-#define PERIPH_CLK_TO_RST_SET_REG(c) \
- periph_clk_to_reg((c), RST_DEVICES_SET_L, RST_DEVICES_SET_V, 8)
-#define PERIPH_CLK_TO_RST_CLR_REG(c) \
- periph_clk_to_reg((c), RST_DEVICES_CLR_L, RST_DEVICES_CLR_V, 8)
-
-#define PERIPH_CLK_TO_ENB_REG(c) \
- periph_clk_to_reg((c), CLK_OUT_ENB_L, CLK_OUT_ENB_V, 4)
-#define PERIPH_CLK_TO_ENB_SET_REG(c) \
- periph_clk_to_reg((c), CLK_OUT_ENB_SET_L, CLK_OUT_ENB_SET_V, 8)
-#define PERIPH_CLK_TO_ENB_CLR_REG(c) \
- periph_clk_to_reg((c), CLK_OUT_ENB_CLR_L, CLK_OUT_ENB_CLR_V, 8)
-
-#define CLK_MASK_ARM 0x44
-#define MISC_CLK_ENB 0x48
-
-#define OSC_CTRL 0x50
-#define OSC_CTRL_OSC_FREQ_MASK (0xF<<28)
-#define OSC_CTRL_OSC_FREQ_13MHZ (0x0<<28)
-#define OSC_CTRL_OSC_FREQ_19_2MHZ (0x4<<28)
-#define OSC_CTRL_OSC_FREQ_12MHZ (0x8<<28)
-#define OSC_CTRL_OSC_FREQ_26MHZ (0xC<<28)
-#define OSC_CTRL_OSC_FREQ_16_8MHZ (0x1<<28)
-#define OSC_CTRL_OSC_FREQ_38_4MHZ (0x5<<28)
-#define OSC_CTRL_OSC_FREQ_48MHZ (0x9<<28)
-#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
-
-#define OSC_CTRL_PLL_REF_DIV_MASK (3<<26)
-#define OSC_CTRL_PLL_REF_DIV_1 (0<<26)
-#define OSC_CTRL_PLL_REF_DIV_2 (1<<26)
-#define OSC_CTRL_PLL_REF_DIV_4 (2<<26)
-
-#define OSC_FREQ_DET 0x58
-#define OSC_FREQ_DET_TRIG (1<<31)
-
-#define OSC_FREQ_DET_STATUS 0x5C
-#define OSC_FREQ_DET_BUSY (1<<31)
-#define OSC_FREQ_DET_CNT_MASK 0xFFFF
-
-#define PERIPH_CLK_SOURCE_I2S1 0x100
-#define PERIPH_CLK_SOURCE_EMC 0x19c
-#define PERIPH_CLK_SOURCE_OSC 0x1fc
-#define PERIPH_CLK_SOURCE_NUM1 \
- ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
-
-#define PERIPH_CLK_SOURCE_G3D2 0x3b0
-#define PERIPH_CLK_SOURCE_SE 0x42c
-#define PERIPH_CLK_SOURCE_NUM2 \
- ((PERIPH_CLK_SOURCE_SE - PERIPH_CLK_SOURCE_G3D2) / 4 + 1)
-
-#define AUDIO_DLY_CLK 0x49c
-#define AUDIO_SYNC_CLK_SPDIF 0x4b4
-#define PERIPH_CLK_SOURCE_NUM3 \
- ((AUDIO_SYNC_CLK_SPDIF - AUDIO_DLY_CLK) / 4 + 1)
-
-#define PERIPH_CLK_SOURCE_NUM (PERIPH_CLK_SOURCE_NUM1 + \
- PERIPH_CLK_SOURCE_NUM2 + \
- PERIPH_CLK_SOURCE_NUM3)
-
-#define CPU_SOFTRST_CTRL 0x380
-
-#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
-#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
-#define PERIPH_CLK_SOURCE_DIV_SHIFT 0
-#define PERIPH_CLK_SOURCE_DIVIDLE_SHIFT 8
-#define PERIPH_CLK_SOURCE_DIVIDLE_VAL 50
-#define PERIPH_CLK_UART_DIV_ENB (1<<24)
-#define PERIPH_CLK_VI_SEL_EX_SHIFT 24
-#define PERIPH_CLK_VI_SEL_EX_MASK (0x3<<PERIPH_CLK_VI_SEL_EX_SHIFT)
-#define PERIPH_CLK_NAND_DIV_EX_ENB (1<<8)
-#define PERIPH_CLK_DTV_POLARITY_INV (1<<25)
-
-#define AUDIO_SYNC_SOURCE_MASK 0x0F
-#define AUDIO_SYNC_DISABLE_BIT 0x10
-#define AUDIO_SYNC_TAP_NIBBLE_SHIFT(c) ((c->reg_shift - 24) * 4)
-
-#define PLL_BASE 0x0
-#define PLL_BASE_BYPASS (1<<31)
-#define PLL_BASE_ENABLE (1<<30)
-#define PLL_BASE_REF_ENABLE (1<<29)
-#define PLL_BASE_OVERRIDE (1<<28)
-#define PLL_BASE_LOCK (1<<27)
-#define PLL_BASE_DIVP_MASK (0x7<<20)
-#define PLL_BASE_DIVP_SHIFT 20
-#define PLL_BASE_DIVN_MASK (0x3FF<<8)
-#define PLL_BASE_DIVN_SHIFT 8
-#define PLL_BASE_DIVM_MASK (0x1F)
-#define PLL_BASE_DIVM_SHIFT 0
-
-#define PLL_OUT_RATIO_MASK (0xFF<<8)
-#define PLL_OUT_RATIO_SHIFT 8
-#define PLL_OUT_OVERRIDE (1<<2)
-#define PLL_OUT_CLKEN (1<<1)
-#define PLL_OUT_RESET_DISABLE (1<<0)
-
-#define PLL_MISC(c) \
- (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
-#define PLL_MISC_LOCK_ENABLE(c) \
- (((c)->flags & (PLLU | PLLD)) ? (1<<22) : (1<<18))
-
-#define PLL_MISC_DCCON_SHIFT 20
-#define PLL_MISC_CPCON_SHIFT 8
-#define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT)
-#define PLL_MISC_LFCON_SHIFT 4
-#define PLL_MISC_LFCON_MASK (0xF<<PLL_MISC_LFCON_SHIFT)
-#define PLL_MISC_VCOCON_SHIFT 0
-#define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT)
-#define PLLD_MISC_CLKENABLE (1<<30)
-
-#define PLLU_BASE_POST_DIV (1<<20)
-
-#define PLLD_BASE_DSIB_MUX_SHIFT 25
-#define PLLD_BASE_DSIB_MUX_MASK (1<<PLLD_BASE_DSIB_MUX_SHIFT)
-#define PLLD_BASE_CSI_CLKENABLE (1<<26)
-#define PLLD_MISC_DSI_CLKENABLE (1<<30)
-#define PLLD_MISC_DIV_RST (1<<23)
-#define PLLD_MISC_DCCON_SHIFT 12
-
-#define PLLDU_LFCON_SET_DIVN 600
-
-/* FIXME: OUT_OF_TABLE_CPCON per pll */
-#define OUT_OF_TABLE_CPCON 0x8
-
-#define SUPER_CLK_MUX 0x00
-#define SUPER_STATE_SHIFT 28
-#define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT)
-#define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT)
-#define SUPER_LP_DIV2_BYPASS (0x1 << 16)
-#define SUPER_SOURCE_MASK 0xF
-#define SUPER_FIQ_SOURCE_SHIFT 12
-#define SUPER_IRQ_SOURCE_SHIFT 8
-#define SUPER_RUN_SOURCE_SHIFT 4
-#define SUPER_IDLE_SOURCE_SHIFT 0
-
-#define SUPER_CLK_DIVIDER 0x04
-#define SUPER_CLOCK_DIV_U71_SHIFT 16
-#define SUPER_CLOCK_DIV_U71_MASK (0xff << SUPER_CLOCK_DIV_U71_SHIFT)
-/* guarantees safe cpu backup */
-#define SUPER_CLOCK_DIV_U71_MIN 0x2
-
-#define BUS_CLK_DISABLE (1<<3)
-#define BUS_CLK_DIV_MASK 0x3
-
-#define PMC_CTRL 0x0
- #define PMC_CTRL_BLINK_ENB (1 << 7)
-
-#define PMC_DPD_PADS_ORIDE 0x1c
- #define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20)
-
-#define PMC_BLINK_TIMER_DATA_ON_SHIFT 0
-#define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff
-#define PMC_BLINK_TIMER_ENB (1 << 15)
-#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
-#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff
-
-#define PMC_PLLP_WB0_OVERRIDE 0xf8
-#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE (1 << 12)
-
-#define UTMIP_PLL_CFG2 0x488
-#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
-#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN (1 << 0)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN (1 << 2)
-#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN (1 << 4)
-
-#define UTMIP_PLL_CFG1 0x484
-#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
-#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN (1 << 14)
-#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN (1 << 12)
-#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN (1 << 16)
-
-#define PLLE_BASE_CML_ENABLE (1<<31)
-#define PLLE_BASE_ENABLE (1<<30)
-#define PLLE_BASE_DIVCML_SHIFT 24
-#define PLLE_BASE_DIVCML_MASK (0xf<<PLLE_BASE_DIVCML_SHIFT)
-#define PLLE_BASE_DIVP_SHIFT 16
-#define PLLE_BASE_DIVP_MASK (0x3f<<PLLE_BASE_DIVP_SHIFT)
-#define PLLE_BASE_DIVN_SHIFT 8
-#define PLLE_BASE_DIVN_MASK (0xFF<<PLLE_BASE_DIVN_SHIFT)
-#define PLLE_BASE_DIVM_SHIFT 0
-#define PLLE_BASE_DIVM_MASK (0xFF<<PLLE_BASE_DIVM_SHIFT)
-#define PLLE_BASE_DIV_MASK \
- (PLLE_BASE_DIVCML_MASK | PLLE_BASE_DIVP_MASK | \
- PLLE_BASE_DIVN_MASK | PLLE_BASE_DIVM_MASK)
-#define PLLE_BASE_DIV(m, n, p, cml) \
- (((cml)<<PLLE_BASE_DIVCML_SHIFT) | ((p)<<PLLE_BASE_DIVP_SHIFT) | \
- ((n)<<PLLE_BASE_DIVN_SHIFT) | ((m)<<PLLE_BASE_DIVM_SHIFT))
-
-#define PLLE_MISC_SETUP_BASE_SHIFT 16
-#define PLLE_MISC_SETUP_BASE_MASK (0xFFFF<<PLLE_MISC_SETUP_BASE_SHIFT)
-#define PLLE_MISC_READY (1<<15)
-#define PLLE_MISC_LOCK (1<<11)
-#define PLLE_MISC_LOCK_ENABLE (1<<9)
-#define PLLE_MISC_SETUP_EX_SHIFT 2
-#define PLLE_MISC_SETUP_EX_MASK (0x3<<PLLE_MISC_SETUP_EX_SHIFT)
-#define PLLE_MISC_SETUP_MASK \
- (PLLE_MISC_SETUP_BASE_MASK | PLLE_MISC_SETUP_EX_MASK)
-#define PLLE_MISC_SETUP_VALUE \
- ((0x7<<PLLE_MISC_SETUP_BASE_SHIFT) | (0x0<<PLLE_MISC_SETUP_EX_SHIFT))
-
-#define PLLE_SS_CTRL 0x68
-#define PLLE_SS_INCINTRV_SHIFT 24
-#define PLLE_SS_INCINTRV_MASK (0x3f<<PLLE_SS_INCINTRV_SHIFT)
-#define PLLE_SS_INC_SHIFT 16
-#define PLLE_SS_INC_MASK (0xff<<PLLE_SS_INC_SHIFT)
-#define PLLE_SS_MAX_SHIFT 0
-#define PLLE_SS_MAX_MASK (0x1ff<<PLLE_SS_MAX_SHIFT)
-#define PLLE_SS_COEFFICIENTS_MASK \
- (PLLE_SS_INCINTRV_MASK | PLLE_SS_INC_MASK | PLLE_SS_MAX_MASK)
-#define PLLE_SS_COEFFICIENTS_12MHZ \
- ((0x18<<PLLE_SS_INCINTRV_SHIFT) | (0x1<<PLLE_SS_INC_SHIFT) | \
- (0x24<<PLLE_SS_MAX_SHIFT))
-#define PLLE_SS_DISABLE ((1<<12) | (1<<11) | (1<<10))
-
-#define PLLE_AUX 0x48c
-#define PLLE_AUX_PLLP_SEL (1<<2)
-#define PLLE_AUX_CML_SATA_ENABLE (1<<1)
-#define PLLE_AUX_CML_PCIE_ENABLE (1<<0)
-
-#define PMC_SATA_PWRGT 0x1ac
-#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE (1<<5)
-#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL (1<<4)
-
-#define ROUND_DIVIDER_UP 0
-#define ROUND_DIVIDER_DOWN 1
-
-/* FIXME: recommended safety delay after lock is detected */
-#define PLL_POST_LOCK_DELAY 100
-
-/* Tegra CPU clock and reset control regs */
-#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c
-#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340
-#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344
-#define TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR 0x34c
-#define TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470
-
-#define CPU_CLOCK(cpu) (0x1 << (8 + cpu))
-#define CPU_RESET(cpu) (0x1111ul << (cpu))
-
-#define CLK_RESET_CCLK_BURST 0x20
-#define CLK_RESET_CCLK_DIVIDER 0x24
-#define CLK_RESET_PLLX_BASE 0xe0
-#define CLK_RESET_PLLX_MISC 0xe4
-
-#define CLK_RESET_SOURCE_CSITE 0x1d4
-
-#define CLK_RESET_CCLK_BURST_POLICY_SHIFT 28
-#define CLK_RESET_CCLK_RUN_POLICY_SHIFT 4
-#define CLK_RESET_CCLK_IDLE_POLICY_SHIFT 0
-#define CLK_RESET_CCLK_IDLE_POLICY 1
-#define CLK_RESET_CCLK_RUN_POLICY 2
-#define CLK_RESET_CCLK_BURST_POLICY_PLLX 8
-
-#ifdef CONFIG_PM_SLEEP
-static struct cpu_clk_suspend_context {
- u32 pllx_misc;
- u32 pllx_base;
-
- u32 cpu_burst;
- u32 clk_csite_src;
- u32 cclk_divider;
-} tegra30_cpu_clk_sctx;
-#endif
-
-/**
-* Structure defining the fields for USB UTMI clocks Parameters.
-*/
-struct utmi_clk_param {
- /* Oscillator Frequency in KHz */
- u32 osc_frequency;
- /* UTMIP PLL Enable Delay Count */
- u8 enable_delay_count;
- /* UTMIP PLL Stable count */
- u8 stable_count;
- /* UTMIP PLL Active delay count */
- u8 active_delay_count;
- /* UTMIP PLL Xtal frequency count */
- u8 xtal_freq_count;
-};
-
-static const struct utmi_clk_param utmi_parameters[] = {
- {
- .osc_frequency = 13000000,
- .enable_delay_count = 0x02,
- .stable_count = 0x33,
- .active_delay_count = 0x05,
- .xtal_freq_count = 0x7F
- },
- {
- .osc_frequency = 19200000,
- .enable_delay_count = 0x03,
- .stable_count = 0x4B,
- .active_delay_count = 0x06,
- .xtal_freq_count = 0xBB},
- {
- .osc_frequency = 12000000,
- .enable_delay_count = 0x02,
- .stable_count = 0x2F,
- .active_delay_count = 0x04,
- .xtal_freq_count = 0x76
- },
- {
- .osc_frequency = 26000000,
- .enable_delay_count = 0x04,
- .stable_count = 0x66,
- .active_delay_count = 0x09,
- .xtal_freq_count = 0xFE
- },
- {
- .osc_frequency = 16800000,
- .enable_delay_count = 0x03,
- .stable_count = 0x41,
- .active_delay_count = 0x0A,
- .xtal_freq_count = 0xA4
- },
-};
-
-static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
-static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE);
-
-#define MISC_GP_HIDREV 0x804
-
-/*
- * Some peripheral clocks share an enable bit, so refcount the enable bits
- * in registers CLK_ENABLE_L, ... CLK_ENABLE_W
- */
-static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 32];
-
-#define clk_writel(value, reg) \
- __raw_writel(value, reg_clk_base + (reg))
-#define clk_readl(reg) \
- __raw_readl(reg_clk_base + (reg))
-#define pmc_writel(value, reg) \
- __raw_writel(value, reg_pmc_base + (reg))
-#define pmc_readl(reg) \
- __raw_readl(reg_pmc_base + (reg))
-#define chipid_readl() \
- __raw_readl(misc_gp_hidrev_base + MISC_GP_HIDREV)
-
-#define clk_writel_delay(value, reg) \
- do { \
- __raw_writel((value), reg_clk_base + (reg)); \
- udelay(2); \
- } while (0)
-
-static inline int clk_set_div(struct clk_tegra *c, u32 n)
-{
- struct clk *clk = c->hw.clk;
-
- return clk_set_rate(clk,
- (__clk_get_rate(__clk_get_parent(clk)) + n - 1) / n);
-}
-
-static inline u32 periph_clk_to_reg(
- struct clk_tegra *c, u32 reg_L, u32 reg_V, int offs)
-{
- u32 reg = c->u.periph.clk_num / 32;
- BUG_ON(reg >= RST_DEVICES_NUM);
- if (reg < 3)
- reg = reg_L + (reg * offs);
- else
- reg = reg_V + ((reg - 3) * offs);
- return reg;
-}
-
-static unsigned long clk_measure_input_freq(void)
-{
- u32 clock_autodetect;
- clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
- do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
- clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
- if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
- return 12000000;
- } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
- return 13000000;
- } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
- return 19200000;
- } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
- return 26000000;
- } else if (clock_autodetect >= 1025 - 3 && clock_autodetect <= 1025 + 3) {
- return 16800000;
- } else if (clock_autodetect >= 2344 - 3 && clock_autodetect <= 2344 + 3) {
- return 38400000;
- } else if (clock_autodetect >= 2928 - 3 && clock_autodetect <= 2928 + 3) {
- return 48000000;
- } else {
- pr_err("%s: Unexpected clock autodetect value %d", __func__,
- clock_autodetect);
- BUG();
- return 0;
- }
-}
-
-static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate,
- u32 flags, u32 round_mode)
-{
- s64 divider_u71 = parent_rate;
- if (!rate)
- return -EINVAL;
-
- if (!(flags & DIV_U71_INT))
- divider_u71 *= 2;
- if (round_mode == ROUND_DIVIDER_UP)
- divider_u71 += rate - 1;
- do_div(divider_u71, rate);
- if (flags & DIV_U71_INT)
- divider_u71 *= 2;
-
- if (divider_u71 - 2 < 0)
- return 0;
-
- if (divider_u71 - 2 > 255)
- return -EINVAL;
-
- return divider_u71 - 2;
-}
-
-static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
-{
- s64 divider_u16;
-
- divider_u16 = parent_rate;
- if (!rate)
- return -EINVAL;
- divider_u16 += rate - 1;
- do_div(divider_u16, rate);
-
- if (divider_u16 - 1 < 0)
- return 0;
-
- if (divider_u16 - 1 > 0xFFFF)
- return -EINVAL;
-
- return divider_u16 - 1;
-}
-
-static unsigned long tegra30_clk_fixed_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- return to_clk_tegra(hw)->fixed_rate;
-}
-
-struct clk_ops tegra30_clk_32k_ops = {
- .recalc_rate = tegra30_clk_fixed_recalc_rate,
-};
-
-/* clk_m functions */
-static unsigned long tegra30_clk_m_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- if (!to_clk_tegra(hw)->fixed_rate)
- to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
- return to_clk_tegra(hw)->fixed_rate;
-}
-
-static void tegra30_clk_m_init(struct clk_hw *hw)
-{
- u32 osc_ctrl = clk_readl(OSC_CTRL);
- u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
- u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK;
-
- switch (to_clk_tegra(hw)->fixed_rate) {
- case 12000000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
- BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
- break;
- case 13000000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
- BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
- break;
- case 19200000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
- BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
- break;
- case 26000000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
- BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
- break;
- case 16800000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_16_8MHZ;
- BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
- break;
- case 38400000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_38_4MHZ;
- BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2);
- break;
- case 48000000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_48MHZ;
- BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4);
- break;
- default:
- pr_err("%s: Unexpected clock rate %ld", __func__,
- to_clk_tegra(hw)->fixed_rate);
- BUG();
- }
- clk_writel(auto_clock_control, OSC_CTRL);
-}
-
-struct clk_ops tegra30_clk_m_ops = {
- .init = tegra30_clk_m_init,
- .recalc_rate = tegra30_clk_m_recalc_rate,
-};
-
-static unsigned long tegra30_clk_m_div_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = parent_rate;
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
-
- return rate;
-}
-
-struct clk_ops tegra_clk_m_div_ops = {
- .recalc_rate = tegra30_clk_m_div_recalc_rate,
-};
-
-/* PLL reference divider functions */
-static unsigned long tegra30_pll_ref_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long rate = parent_rate;
- u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK;
-
- switch (pll_ref_div) {
- case OSC_CTRL_PLL_REF_DIV_1:
- c->div = 1;
- break;
- case OSC_CTRL_PLL_REF_DIV_2:
- c->div = 2;
- break;
- case OSC_CTRL_PLL_REF_DIV_4:
- c->div = 4;
- break;
- default:
- pr_err("%s: Invalid pll ref divider %d", __func__, pll_ref_div);
- BUG();
- }
- c->mul = 1;
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
-
- return rate;
-}
-
-struct clk_ops tegra_pll_ref_ops = {
- .recalc_rate = tegra30_pll_ref_recalc_rate,
-};
-
-/* super clock functions */
-/* "super clocks" on tegra30 have two-stage muxes, fractional 7.1 divider and
- * clock skipping super divider. We will ignore the clock skipping divider,
- * since we can't lower the voltage when using the clock skip, but we can if
- * we lower the PLL frequency. We will use 7.1 divider for CPU super-clock
- * only when its parent is a fixed rate PLL, since we can't change PLL rate
- * in this case.
- */
-static void tegra30_super_clk_init(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- struct clk_tegra *p =
- to_clk_tegra(__clk_get_hw(__clk_get_parent(hw->clk)));
-
- c->state = ON;
- if (c->flags & DIV_U71) {
- /* Init safe 7.1 divider value (does not affect PLLX path) */
- clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT,
- c->reg + SUPER_CLK_DIVIDER);
- c->mul = 2;
- c->div = 2;
- if (!(p->flags & PLLX))
- c->div += SUPER_CLOCK_DIV_U71_MIN;
- } else
- clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
-}
-
-static u8 tegra30_super_clk_get_parent(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- int source;
- int shift;
-
- 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) ?
- SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
- source = (val >> shift) & SUPER_SOURCE_MASK;
- if (c->flags & DIV_2)
- source |= val & SUPER_LP_DIV2_BYPASS;
-
- return source;
-}
-
-static int tegra30_super_clk_set_parent(struct clk_hw *hw, u8 index)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- struct clk_tegra *p =
- to_clk_tegra(__clk_get_hw(clk_get_parent(hw->clk)));
- u32 val;
- int shift;
-
- 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) ?
- SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
-
- /* For LP mode super-clock switch between PLLX direct
- and divided-by-2 outputs is allowed only when other
- than PLLX clock source is current parent */
- if ((c->flags & DIV_2) && (p->flags & PLLX) &&
- ((index ^ val) & SUPER_LP_DIV2_BYPASS)) {
- if (p->flags & PLLX)
- return -EINVAL;
- val ^= SUPER_LP_DIV2_BYPASS;
- clk_writel_delay(val, c->reg);
- }
- val &= ~(SUPER_SOURCE_MASK << shift);
- val |= (index & SUPER_SOURCE_MASK) << shift;
-
- /* 7.1 divider for CPU super-clock does not affect
- PLLX path */
- if (c->flags & DIV_U71) {
- u32 div = 0;
- if (!(p->flags & PLLX)) {
- div = clk_readl(c->reg +
- SUPER_CLK_DIVIDER);
- div &= SUPER_CLOCK_DIV_U71_MASK;
- div >>= SUPER_CLOCK_DIV_U71_SHIFT;
- }
- c->div = div + 2;
- c->mul = 2;
- }
- clk_writel_delay(val, c->reg);
-
- return 0;
-}
-
-/*
- * Do not use super clocks "skippers", since dividing using a clock skipper
- * does not allow the voltage to be scaled down. Instead adjust the rate of
- * the parent clock. This requires that the parent of a super clock have no
- * other children, otherwise the rate will change underneath the other
- * children. Special case: if fixed rate PLL is CPU super clock parent the
- * rate of this PLL can't be changed, and it has many other children. In
- * this case use 7.1 fractional divider to adjust the super clock rate.
- */
-static int tegra30_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- struct clk *parent = __clk_get_parent(hw->clk);
- struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent));
-
- if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) {
- int div = clk_div71_get_divider(parent_rate,
- rate, c->flags, ROUND_DIVIDER_DOWN);
- div = max(div, SUPER_CLOCK_DIV_U71_MIN);
-
- clk_writel(div << SUPER_CLOCK_DIV_U71_SHIFT,
- c->reg + SUPER_CLK_DIVIDER);
- c->div = div + 2;
- c->mul = 2;
- return 0;
- }
- return 0;
-}
-
-static unsigned long tegra30_super_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = parent_rate;
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
-
- return rate;
-}
-
-static long tegra30_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- struct clk *parent = __clk_get_parent(hw->clk);
- struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent));
- int mul = 2;
- int div;
-
- if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) {
- div = clk_div71_get_divider(*prate,
- rate, c->flags, ROUND_DIVIDER_DOWN);
- div = max(div, SUPER_CLOCK_DIV_U71_MIN) + 2;
- rate = *prate * mul;
- rate += div - 1; /* round up */
- do_div(rate, c->div);
-
- return rate;
- }
- return *prate;
-}
-
-struct clk_ops tegra30_super_ops = {
- .init = tegra30_super_clk_init,
- .set_parent = tegra30_super_clk_set_parent,
- .get_parent = tegra30_super_clk_get_parent,
- .recalc_rate = tegra30_super_clk_recalc_rate,
- .round_rate = tegra30_super_clk_round_rate,
- .set_rate = tegra30_super_clk_set_rate,
-};
-
-static unsigned long tegra30_twd_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = parent_rate;
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
-
- return rate;
-}
-
-struct clk_ops tegra30_twd_ops = {
- .recalc_rate = tegra30_twd_clk_recalc_rate,
-};
-
-/* bus clock functions */
-static int tegra30_bus_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
-
- c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
- return c->state;
-}
-
-static int tegra30_bus_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- val = clk_readl(c->reg);
- val &= ~(BUS_CLK_DISABLE << c->reg_shift);
- clk_writel(val, c->reg);
-
- return 0;
-}
-
-static void tegra30_bus_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- val = clk_readl(c->reg);
- val |= BUS_CLK_DISABLE << c->reg_shift;
- clk_writel(val, c->reg);
-}
-
-static unsigned long tegra30_bus_clk_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
- u64 rate = prate;
-
- c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
- c->mul = 1;
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
- return rate;
-}
-
-static int tegra30_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- int ret = -EINVAL;
- u32 val;
- int i;
-
- val = clk_readl(c->reg);
- for (i = 1; i <= 4; i++) {
- if (rate == parent_rate / i) {
- val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
- val |= (i - 1) << c->reg_shift;
- clk_writel(val, c->reg);
- c->div = i;
- c->mul = 1;
- ret = 0;
- break;
- }
- }
-
- return ret;
-}
-
-static long tegra30_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- unsigned long parent_rate = *prate;
- s64 divider;
-
- if (rate >= parent_rate)
- return parent_rate;
-
- divider = parent_rate;
- divider += rate - 1;
- do_div(divider, rate);
-
- if (divider < 0)
- return divider;
-
- if (divider > 4)
- divider = 4;
- do_div(parent_rate, divider);
-
- return parent_rate;
-}
-
-struct clk_ops tegra30_bus_ops = {
- .is_enabled = tegra30_bus_clk_is_enabled,
- .enable = tegra30_bus_clk_enable,
- .disable = tegra30_bus_clk_disable,
- .set_rate = tegra30_bus_clk_set_rate,
- .round_rate = tegra30_bus_clk_round_rate,
- .recalc_rate = tegra30_bus_clk_recalc_rate,
-};
-
-/* Blink output functions */
-static int tegra30_blink_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- val = pmc_readl(PMC_CTRL);
- c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
- return c->state;
-}
-
-static int tegra30_blink_clk_enable(struct clk_hw *hw)
-{
- u32 val;
-
- val = pmc_readl(PMC_DPD_PADS_ORIDE);
- pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
-
- val = pmc_readl(PMC_CTRL);
- pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
-
- return 0;
-}
-
-static void tegra30_blink_clk_disable(struct clk_hw *hw)
-{
- u32 val;
-
- val = pmc_readl(PMC_CTRL);
- pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
-
- val = pmc_readl(PMC_DPD_PADS_ORIDE);
- pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
-}
-
-static int tegra30_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- if (rate >= parent_rate) {
- c->div = 1;
- pmc_writel(0, c->reg);
- } else {
- unsigned int on_off;
- u32 val;
-
- on_off = DIV_ROUND_UP(parent_rate / 8, rate);
- c->div = on_off * 8;
-
- val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
- PMC_BLINK_TIMER_DATA_ON_SHIFT;
- on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
- on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
- val |= on_off;
- val |= PMC_BLINK_TIMER_ENB;
- pmc_writel(val, c->reg);
- }
-
- return 0;
-}
-
-static unsigned long tegra30_blink_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = parent_rate;
- u32 val;
- u32 mul;
- u32 div;
- u32 on_off;
-
- mul = 1;
- val = pmc_readl(c->reg);
-
- if (val & PMC_BLINK_TIMER_ENB) {
- on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
- PMC_BLINK_TIMER_DATA_ON_MASK;
- val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
- val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
- on_off += val;
- /* each tick in the blink timer is 4 32KHz clocks */
- div = on_off * 4;
- } else {
- div = 1;
- }
-
- if (mul != 0 && div != 0) {
- rate *= mul;
- rate += div - 1; /* round up */
- do_div(rate, div);
- }
- return rate;
-}
-
-static long tegra30_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- int div;
- int mul;
- long round_rate = *prate;
-
- mul = 1;
-
- if (rate >= *prate) {
- div = 1;
- } else {
- div = DIV_ROUND_UP(*prate / 8, rate);
- div *= 8;
- }
-
- round_rate *= mul;
- round_rate += div - 1;
- do_div(round_rate, div);
-
- return round_rate;
-}
-
-struct clk_ops tegra30_blink_clk_ops = {
- .is_enabled = tegra30_blink_clk_is_enabled,
- .enable = tegra30_blink_clk_enable,
- .disable = tegra30_blink_clk_disable,
- .recalc_rate = tegra30_blink_clk_recalc_rate,
- .round_rate = tegra30_blink_clk_round_rate,
- .set_rate = tegra30_blink_clk_set_rate,
-};
-
-static void tegra30_utmi_param_configure(struct clk_hw *hw)
-{
- unsigned long main_rate =
- __clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk)));
- u32 reg;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
- if (main_rate == utmi_parameters[i].osc_frequency)
- break;
- }
-
- if (i >= ARRAY_SIZE(utmi_parameters)) {
- pr_err("%s: Unexpected main rate %lu\n", __func__, main_rate);
- return;
- }
-
- reg = clk_readl(UTMIP_PLL_CFG2);
-
- /* Program UTMIP PLL stable and active counts */
- /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
- reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
- reg |= UTMIP_PLL_CFG2_STABLE_COUNT(
- utmi_parameters[i].stable_count);
-
- reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
-
- reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
- utmi_parameters[i].active_delay_count);
-
- /* Remove power downs from UTMIP PLL control bits */
- reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
- reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
- reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
-
- clk_writel(reg, UTMIP_PLL_CFG2);
-
- /* Program UTMIP PLL delay and oscillator frequency counts */
- reg = clk_readl(UTMIP_PLL_CFG1);
- reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
-
- reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
- utmi_parameters[i].enable_delay_count);
-
- reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
- reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
- utmi_parameters[i].xtal_freq_count);
-
- /* Remove power downs from UTMIP PLL control bits */
- reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
- reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
- reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
-
- clk_writel(reg, UTMIP_PLL_CFG1);
-}
-
-/* PLL Functions */
-static int tegra30_pll_clk_wait_for_lock(struct clk_tegra *c, u32 lock_reg,
- u32 lock_bit)
-{
- int ret = 0;
-
-#if USE_PLL_LOCK_BITS
- int i;
- for (i = 0; i < c->u.pll.lock_delay; i++) {
- if (clk_readl(lock_reg) & lock_bit) {
- udelay(PLL_POST_LOCK_DELAY);
- return 0;
- }
- udelay(2); /* timeout = 2 * lock time */
- }
- pr_err("Timed out waiting for lock bit on pll %s",
- __clk_get_name(hw->clk));
- ret = -1;
-#else
- udelay(c->u.pll.lock_delay);
-#endif
- return ret;
-}
-
-static int tegra30_pll_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg + PLL_BASE);
-
- c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
- return c->state;
-}
-
-static void tegra30_pll_clk_init(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- if (c->flags & PLLU)
- tegra30_utmi_param_configure(hw);
-}
-
-static int tegra30_pll_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
-
-#if USE_PLL_LOCK_BITS
- val = clk_readl(c->reg + PLL_MISC(c));
- val |= PLL_MISC_LOCK_ENABLE(c);
- clk_writel(val, c->reg + PLL_MISC(c));
-#endif
- val = clk_readl(c->reg + PLL_BASE);
- val &= ~PLL_BASE_BYPASS;
- val |= PLL_BASE_ENABLE;
- clk_writel(val, c->reg + PLL_BASE);
-
- if (c->flags & PLLM) {
- val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
- val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
- pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
- }
-
- tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_BASE, PLL_BASE_LOCK);
-
- return 0;
-}
-
-static void tegra30_pll_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
-
- val = clk_readl(c->reg);
- val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
- clk_writel(val, c->reg);
-
- if (c->flags & PLLM) {
- val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
- val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
- pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
- }
-}
-
-static int tegra30_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val, p_div, old_base;
- unsigned long input_rate;
- const struct clk_pll_freq_table *sel;
- struct clk_pll_freq_table cfg;
-
- if (c->flags & PLL_FIXED) {
- int ret = 0;
- if (rate != c->u.pll.fixed_rate) {
- pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
- __func__, __clk_get_name(hw->clk),
- c->u.pll.fixed_rate, rate);
- ret = -EINVAL;
- }
- return ret;
- }
-
- if (c->flags & PLLM) {
- if (rate != __clk_get_rate(hw->clk)) {
- pr_err("%s: Can not change memory %s rate in flight\n",
- __func__, __clk_get_name(hw->clk));
- return -EINVAL;
- }
- }
-
- p_div = 0;
- input_rate = parent_rate;
-
- /* Check if the target rate is tabulated */
- for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
- if (sel->input_rate == input_rate && sel->output_rate == rate) {
- if (c->flags & PLLU) {
- BUG_ON(sel->p < 1 || sel->p > 2);
- if (sel->p == 1)
- p_div = PLLU_BASE_POST_DIV;
- } else {
- BUG_ON(sel->p < 1);
- for (val = sel->p; val > 1; val >>= 1)
- p_div++;
- p_div <<= PLL_BASE_DIVP_SHIFT;
- }
- break;
- }
- }
-
- /* Configure out-of-table rate */
- if (sel->input_rate == 0) {
- unsigned long cfreq;
- BUG_ON(c->flags & PLLU);
- sel = &cfg;
-
- switch (input_rate) {
- case 12000000:
- case 26000000:
- cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
- break;
- case 13000000:
- cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
- break;
- case 16800000:
- case 19200000:
- cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
- break;
- default:
- pr_err("%s: Unexpected reference rate %lu\n",
- __func__, input_rate);
- BUG();
- }
-
- /* Raise VCO to guarantee 0.5% accuracy */
- for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq;
- cfg.output_rate <<= 1)
- p_div++;
-
- cfg.p = 0x1 << p_div;
- cfg.m = input_rate / cfreq;
- cfg.n = cfg.output_rate / cfreq;
- cfg.cpcon = OUT_OF_TABLE_CPCON;
-
- if ((cfg.m > (PLL_BASE_DIVM_MASK >> PLL_BASE_DIVM_SHIFT)) ||
- (cfg.n > (PLL_BASE_DIVN_MASK >> PLL_BASE_DIVN_SHIFT)) ||
- (p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) ||
- (cfg.output_rate > c->u.pll.vco_max)) {
- pr_err("%s: Failed to set %s out-of-table rate %lu\n",
- __func__, __clk_get_name(hw->clk), rate);
- return -EINVAL;
- }
- p_div <<= PLL_BASE_DIVP_SHIFT;
- }
-
- c->mul = sel->n;
- c->div = sel->m * sel->p;
-
- old_base = val = clk_readl(c->reg + PLL_BASE);
- val &= ~(PLL_BASE_DIVM_MASK | PLL_BASE_DIVN_MASK |
- ((c->flags & PLLU) ? PLLU_BASE_POST_DIV : PLL_BASE_DIVP_MASK));
- val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
- (sel->n << PLL_BASE_DIVN_SHIFT) | p_div;
- if (val == old_base)
- return 0;
-
- if (c->state == ON) {
- tegra30_pll_clk_disable(hw);
- val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
- }
- clk_writel(val, c->reg + PLL_BASE);
-
- if (c->flags & PLL_HAS_CPCON) {
- val = clk_readl(c->reg + PLL_MISC(c));
- val &= ~PLL_MISC_CPCON_MASK;
- val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
- if (c->flags & (PLLU | PLLD)) {
- val &= ~PLL_MISC_LFCON_MASK;
- if (sel->n >= PLLDU_LFCON_SET_DIVN)
- val |= 0x1 << PLL_MISC_LFCON_SHIFT;
- } else if (c->flags & (PLLX | PLLM)) {
- val &= ~(0x1 << PLL_MISC_DCCON_SHIFT);
- if (rate >= (c->u.pll.vco_max >> 1))
- val |= 0x1 << PLL_MISC_DCCON_SHIFT;
- }
- clk_writel(val, c->reg + PLL_MISC(c));
- }
-
- if (c->state == ON)
- tegra30_pll_clk_enable(hw);
-
- c->u.pll.fixed_rate = rate;
-
- return 0;
-}
-
-static long tegra30_pll_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long input_rate = *prate;
- u64 output_rate = *prate;
- const struct clk_pll_freq_table *sel;
- struct clk_pll_freq_table cfg;
- int mul;
- int div;
- u32 p_div;
- u32 val;
-
- if (c->flags & PLL_FIXED)
- return c->u.pll.fixed_rate;
-
- if (c->flags & PLLM)
- return __clk_get_rate(hw->clk);
-
- p_div = 0;
- /* Check if the target rate is tabulated */
- for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
- if (sel->input_rate == input_rate && sel->output_rate == rate) {
- if (c->flags & PLLU) {
- BUG_ON(sel->p < 1 || sel->p > 2);
- if (sel->p == 1)
- p_div = PLLU_BASE_POST_DIV;
- } else {
- BUG_ON(sel->p < 1);
- for (val = sel->p; val > 1; val >>= 1)
- p_div++;
- p_div <<= PLL_BASE_DIVP_SHIFT;
- }
- break;
- }
- }
-
- if (sel->input_rate == 0) {
- unsigned long cfreq;
- BUG_ON(c->flags & PLLU);
- sel = &cfg;
-
- switch (input_rate) {
- case 12000000:
- case 26000000:
- cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
- break;
- case 13000000:
- cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
- break;
- case 16800000:
- case 19200000:
- cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
- break;
- default:
- pr_err("%s: Unexpected reference rate %lu\n",
- __func__, input_rate);
- BUG();
- }
-
- /* Raise VCO to guarantee 0.5% accuracy */
- for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq;
- cfg.output_rate <<= 1)
- p_div++;
-
- cfg.p = 0x1 << p_div;
- cfg.m = input_rate / cfreq;
- cfg.n = cfg.output_rate / cfreq;
- }
-
- mul = sel->n;
- div = sel->m * sel->p;
-
- output_rate *= mul;
- output_rate += div - 1; /* round up */
- do_div(output_rate, div);
-
- return output_rate;
-}
-
-static unsigned long tegra30_pll_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = parent_rate;
- u32 val = clk_readl(c->reg + PLL_BASE);
-
- if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
- const struct clk_pll_freq_table *sel;
- for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
- if (sel->input_rate == parent_rate &&
- sel->output_rate == c->u.pll.fixed_rate) {
- c->mul = sel->n;
- c->div = sel->m * sel->p;
- break;
- }
- }
- pr_err("Clock %s has unknown fixed frequency\n",
- __clk_get_name(hw->clk));
- BUG();
- } else if (val & PLL_BASE_BYPASS) {
- c->mul = 1;
- c->div = 1;
- } else {
- c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
- c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
- if (c->flags & PLLU)
- c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
- else
- c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
- PLL_BASE_DIVP_SHIFT));
- }
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
-
- return rate;
-}
-
-struct clk_ops tegra30_pll_ops = {
- .is_enabled = tegra30_pll_clk_is_enabled,
- .init = tegra30_pll_clk_init,
- .enable = tegra30_pll_clk_enable,
- .disable = tegra30_pll_clk_disable,
- .recalc_rate = tegra30_pll_recalc_rate,
- .round_rate = tegra30_pll_round_rate,
- .set_rate = tegra30_pll_clk_set_rate,
-};
-
-int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
- enum tegra_clk_ex_param p, u32 setting)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val, mask, reg;
-
- switch (p) {
- case TEGRA_CLK_PLLD_CSI_OUT_ENB:
- mask = PLLD_BASE_CSI_CLKENABLE;
- reg = c->reg + PLL_BASE;
- break;
- case TEGRA_CLK_PLLD_DSI_OUT_ENB:
- mask = PLLD_MISC_DSI_CLKENABLE;
- reg = c->reg + PLL_MISC(c);
- break;
- case TEGRA_CLK_PLLD_MIPI_MUX_SEL:
- if (!(c->flags & PLL_ALT_MISC_REG)) {
- mask = PLLD_BASE_DSIB_MUX_MASK;
- reg = c->reg + PLL_BASE;
- break;
- }
- /* fall through - error since PLLD2 does not have MUX_SEL control */
- default:
- return -EINVAL;
- }
-
- val = clk_readl(reg);
- if (setting)
- val |= mask;
- else
- val &= ~mask;
- clk_writel(val, reg);
- return 0;
-}
-
-static int tegra30_plle_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- val = clk_readl(c->reg + PLL_BASE);
- c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF;
- return c->state;
-}
-
-static void tegra30_plle_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- val = clk_readl(c->reg + PLL_BASE);
- val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
- clk_writel(val, c->reg + PLL_BASE);
-}
-
-static void tegra30_plle_training(struct clk_tegra *c)
-{
- u32 val;
-
- /* PLLE is already disabled, and setup cleared;
- * create falling edge on PLLE IDDQ input */
- val = pmc_readl(PMC_SATA_PWRGT);
- val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
- pmc_writel(val, PMC_SATA_PWRGT);
-
- val = pmc_readl(PMC_SATA_PWRGT);
- val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
- pmc_writel(val, PMC_SATA_PWRGT);
-
- val = pmc_readl(PMC_SATA_PWRGT);
- val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
- pmc_writel(val, PMC_SATA_PWRGT);
-
- do {
- val = clk_readl(c->reg + PLL_MISC(c));
- } while (!(val & PLLE_MISC_READY));
-}
-
-static int tegra30_plle_configure(struct clk_hw *hw, bool force_training)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- struct clk *parent = __clk_get_parent(hw->clk);
- const struct clk_pll_freq_table *sel;
- u32 val;
-
- unsigned long rate = c->u.pll.fixed_rate;
- unsigned long input_rate = __clk_get_rate(parent);
-
- for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
- if (sel->input_rate == input_rate && sel->output_rate == rate)
- break;
- }
-
- if (sel->input_rate == 0)
- return -ENOSYS;
-
- /* disable PLLE, clear setup fiels */
- tegra30_plle_clk_disable(hw);
-
- val = clk_readl(c->reg + PLL_MISC(c));
- val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
- clk_writel(val, c->reg + PLL_MISC(c));
-
- /* training */
- val = clk_readl(c->reg + PLL_MISC(c));
- if (force_training || (!(val & PLLE_MISC_READY)))
- tegra30_plle_training(c);
-
- /* configure dividers, setup, disable SS */
- val = clk_readl(c->reg + PLL_BASE);
- val &= ~PLLE_BASE_DIV_MASK;
- val |= PLLE_BASE_DIV(sel->m, sel->n, sel->p, sel->cpcon);
- clk_writel(val, c->reg + PLL_BASE);
- c->mul = sel->n;
- c->div = sel->m * sel->p;
-
- val = clk_readl(c->reg + PLL_MISC(c));
- val |= PLLE_MISC_SETUP_VALUE;
- val |= PLLE_MISC_LOCK_ENABLE;
- clk_writel(val, c->reg + PLL_MISC(c));
-
- val = clk_readl(PLLE_SS_CTRL);
- val |= PLLE_SS_DISABLE;
- clk_writel(val, PLLE_SS_CTRL);
-
- /* enable and lock PLLE*/
- val = clk_readl(c->reg + PLL_BASE);
- val |= (PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
- clk_writel(val, c->reg + PLL_BASE);
-
- tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_MISC(c), PLLE_MISC_LOCK);
-
- return 0;
-}
-
-static int tegra30_plle_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- return tegra30_plle_configure(hw, !c->set);
-}
-
-static unsigned long tegra30_plle_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long rate = parent_rate;
- u32 val;
-
- val = clk_readl(c->reg + PLL_BASE);
- c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
- c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
- c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
- return rate;
-}
-
-struct clk_ops tegra30_plle_ops = {
- .is_enabled = tegra30_plle_clk_is_enabled,
- .enable = tegra30_plle_clk_enable,
- .disable = tegra30_plle_clk_disable,
- .recalc_rate = tegra30_plle_clk_recalc_rate,
-};
-
-/* Clock divider ops */
-static int tegra30_pll_div_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- if (c->flags & DIV_U71) {
- u32 val = clk_readl(c->reg);
- val >>= c->reg_shift;
- c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
- if (!(val & PLL_OUT_RESET_DISABLE))
- c->state = OFF;
- } else {
- c->state = ON;
- }
- return c->state;
-}
-
-static int tegra30_pll_div_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- u32 new_val;
-
- pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
- if (c->flags & DIV_U71) {
- val = clk_readl(c->reg);
- new_val = val >> c->reg_shift;
- new_val &= 0xFFFF;
-
- new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
-
- val &= ~(0xFFFF << c->reg_shift);
- val |= new_val << c->reg_shift;
- clk_writel_delay(val, c->reg);
- return 0;
- } else if (c->flags & DIV_2) {
- return 0;
- }
- return -EINVAL;
-}
-
-static void tegra30_pll_div_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- u32 new_val;
-
- pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
- if (c->flags & DIV_U71) {
- val = clk_readl(c->reg);
- new_val = val >> c->reg_shift;
- new_val &= 0xFFFF;
-
- new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
-
- val &= ~(0xFFFF << c->reg_shift);
- val |= new_val << c->reg_shift;
- clk_writel_delay(val, c->reg);
- }
-}
-
-static int tegra30_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- u32 new_val;
- int divider_u71;
-
- if (c->flags & DIV_U71) {
- divider_u71 = clk_div71_get_divider(
- parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
- if (divider_u71 >= 0) {
- val = clk_readl(c->reg);
- new_val = val >> c->reg_shift;
- new_val &= 0xFFFF;
- if (c->flags & DIV_U71_FIXED)
- new_val |= PLL_OUT_OVERRIDE;
- new_val &= ~PLL_OUT_RATIO_MASK;
- new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
-
- val &= ~(0xFFFF << c->reg_shift);
- val |= new_val << c->reg_shift;
- clk_writel_delay(val, c->reg);
- c->div = divider_u71 + 2;
- c->mul = 2;
- c->fixed_rate = rate;
- return 0;
- }
- } else if (c->flags & DIV_2) {
- c->fixed_rate = rate;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static unsigned long tegra30_pll_div_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = parent_rate;
-
- if (c->flags & DIV_U71) {
- u32 divu71;
- u32 val = clk_readl(c->reg);
- val >>= c->reg_shift;
-
- divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
- c->div = (divu71 + 2);
- c->mul = 2;
- } else if (c->flags & DIV_2) {
- if (c->flags & (PLLD | PLLX)) {
- c->div = 2;
- c->mul = 1;
- } else
- BUG();
- } else {
- c->div = 1;
- c->mul = 1;
- }
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
-
- return rate;
-}
-
-static long tegra30_pll_div_clk_round_rate(struct clk_hw *hw,
- unsigned long rate, unsigned long *prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
- int divider;
-
- if (prate)
- parent_rate = *prate;
-
- if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(
- parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
- if (divider < 0)
- return divider;
- return DIV_ROUND_UP(parent_rate * 2, divider + 2);
- } else if (c->flags & DIV_2) {
- *prate = rate * 2;
- return rate;
- }
-
- return -EINVAL;
-}
-
-struct clk_ops tegra30_pll_div_ops = {
- .is_enabled = tegra30_pll_div_clk_is_enabled,
- .enable = tegra30_pll_div_clk_enable,
- .disable = tegra30_pll_div_clk_disable,
- .set_rate = tegra30_pll_div_clk_set_rate,
- .recalc_rate = tegra30_pll_div_clk_recalc_rate,
- .round_rate = tegra30_pll_div_clk_round_rate,
-};
-
-/* Periph clk ops */
-static inline u32 periph_clk_source_mask(struct clk_tegra *c)
-{
- if (c->flags & MUX8)
- return 7 << 29;
- else if (c->flags & MUX_PWM)
- return 3 << 28;
- else if (c->flags & MUX_CLK_OUT)
- return 3 << (c->u.periph.clk_num + 4);
- else if (c->flags & PLLD)
- return PLLD_BASE_DSIB_MUX_MASK;
- else
- return 3 << 30;
-}
-
-static inline u32 periph_clk_source_shift(struct clk_tegra *c)
-{
- if (c->flags & MUX8)
- return 29;
- else if (c->flags & MUX_PWM)
- return 28;
- else if (c->flags & MUX_CLK_OUT)
- return c->u.periph.clk_num + 4;
- else if (c->flags & PLLD)
- return PLLD_BASE_DSIB_MUX_SHIFT;
- else
- return 30;
-}
-
-static int tegra30_periph_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- c->state = ON;
- if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
- c->state = OFF;
- if (!(c->flags & PERIPH_NO_RESET))
- if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))
- c->state = OFF;
- return c->state;
-}
-
-static int tegra30_periph_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
- if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
- return 0;
-
- clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_SET_REG(c));
- if (!(c->flags & PERIPH_NO_RESET) &&
- !(c->flags & PERIPH_MANUAL_RESET)) {
- if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) &
- PERIPH_CLK_TO_BIT(c)) {
- udelay(5); /* reset propagation delay */
- clk_writel(PERIPH_CLK_TO_BIT(c),
- PERIPH_CLK_TO_RST_CLR_REG(c));
- }
- }
- return 0;
-}
-
-static void tegra30_periph_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long val;
-
- tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
-
- if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
- return;
-
- /* If peripheral is in the APB bus then read the APB bus to
- * flush the write operation in apb bus. This will avoid the
- * peripheral access after disabling clock*/
- if (c->flags & PERIPH_ON_APB)
- val = chipid_readl();
-
- clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
-}
-
-void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long val;
-
- if (!(c->flags & PERIPH_NO_RESET)) {
- if (assert) {
- /* If peripheral is in the APB bus then read the APB
- * bus to flush the write operation in apb bus. This
- * will avoid the peripheral access after disabling
- * clock */
- if (c->flags & PERIPH_ON_APB)
- val = chipid_readl();
-
- clk_writel(PERIPH_CLK_TO_BIT(c),
- PERIPH_CLK_TO_RST_SET_REG(c));
- } else
- clk_writel(PERIPH_CLK_TO_BIT(c),
- PERIPH_CLK_TO_RST_CLR_REG(c));
- }
-}
-
-static int tegra30_periph_clk_set_parent(struct clk_hw *hw, u8 index)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- if (!(c->flags & MUX))
- return (index == 0) ? 0 : (-EINVAL);
-
- val = clk_readl(c->reg);
- val &= ~periph_clk_source_mask(c);
- val |= (index << periph_clk_source_shift(c));
- clk_writel_delay(val, c->reg);
- return 0;
-}
-
-static u8 tegra30_periph_clk_get_parent(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
- int source = (val & periph_clk_source_mask(c)) >>
- periph_clk_source_shift(c);
-
- if (!(c->flags & MUX))
- return 0;
-
- return source;
-}
-
-static int tegra30_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- int divider;
-
- if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(
- parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
- if (divider >= 0) {
- val = clk_readl(c->reg);
- val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
- val |= divider;
- if (c->flags & DIV_U71_UART) {
- if (divider)
- val |= PERIPH_CLK_UART_DIV_ENB;
- else
- val &= ~PERIPH_CLK_UART_DIV_ENB;
- }
- clk_writel_delay(val, c->reg);
- c->div = divider + 2;
- c->mul = 2;
- return 0;
- }
- } else if (c->flags & DIV_U16) {
- divider = clk_div16_get_divider(parent_rate, rate);
- if (divider >= 0) {
- val = clk_readl(c->reg);
- val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
- val |= divider;
- clk_writel_delay(val, c->reg);
- c->div = divider + 1;
- c->mul = 1;
- return 0;
- }
- } else if (parent_rate <= rate) {
- c->div = 1;
- c->mul = 1;
- return 0;
- }
- return -EINVAL;
-}
-
-static long tegra30_periph_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
- int divider;
-
- if (prate)
- parent_rate = *prate;
-
- if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(
- parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
- if (divider < 0)
- return divider;
-
- return DIV_ROUND_UP(parent_rate * 2, divider + 2);
- } else if (c->flags & DIV_U16) {
- divider = clk_div16_get_divider(parent_rate, rate);
- if (divider < 0)
- return divider;
- return DIV_ROUND_UP(parent_rate, divider + 1);
- }
- return -EINVAL;
-}
-
-static unsigned long tegra30_periph_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = parent_rate;
- u32 val = clk_readl(c->reg);
-
- if (c->flags & DIV_U71) {
- u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
- if ((c->flags & DIV_U71_UART) &&
- (!(val & PERIPH_CLK_UART_DIV_ENB))) {
- divu71 = 0;
- }
- if (c->flags & DIV_U71_IDLE) {
- val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
- PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
- val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
- PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
- clk_writel(val, c->reg);
- }
- c->div = divu71 + 2;
- c->mul = 2;
- } else if (c->flags & DIV_U16) {
- u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
- c->div = divu16 + 1;
- c->mul = 1;
- } else {
- c->div = 1;
- c->mul = 1;
- }
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
- return rate;
-}
-
-struct clk_ops tegra30_periph_clk_ops = {
- .is_enabled = tegra30_periph_clk_is_enabled,
- .enable = tegra30_periph_clk_enable,
- .disable = tegra30_periph_clk_disable,
- .set_parent = tegra30_periph_clk_set_parent,
- .get_parent = tegra30_periph_clk_get_parent,
- .set_rate = tegra30_periph_clk_set_rate,
- .round_rate = tegra30_periph_clk_round_rate,
- .recalc_rate = tegra30_periph_clk_recalc_rate,
-};
-
-static int tegra30_dsib_clk_set_parent(struct clk_hw *hw, u8 index)
-{
- struct clk *d = clk_get_sys(NULL, "pll_d");
- /* The DSIB parent selection bit is in PLLD base register */
- tegra_clk_cfg_ex(
- d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, index);
-
- return 0;
-}
-
-struct clk_ops tegra30_dsib_clk_ops = {
- .is_enabled = tegra30_periph_clk_is_enabled,
- .enable = &tegra30_periph_clk_enable,
- .disable = &tegra30_periph_clk_disable,
- .set_parent = &tegra30_dsib_clk_set_parent,
- .get_parent = &tegra30_periph_clk_get_parent,
- .set_rate = &tegra30_periph_clk_set_rate,
- .round_rate = &tegra30_periph_clk_round_rate,
- .recalc_rate = &tegra30_periph_clk_recalc_rate,
-};
-
-/* Periph extended clock configuration ops */
-int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
- enum tegra_clk_ex_param p, u32 setting)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- if (p == TEGRA_CLK_VI_INP_SEL) {
- u32 val = clk_readl(c->reg);
- val &= ~PERIPH_CLK_VI_SEL_EX_MASK;
- val |= (setting << PERIPH_CLK_VI_SEL_EX_SHIFT) &
- PERIPH_CLK_VI_SEL_EX_MASK;
- clk_writel(val, c->reg);
- return 0;
- }
- return -EINVAL;
-}
-
-int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
- enum tegra_clk_ex_param p, u32 setting)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) {
- u32 val = clk_readl(c->reg);
- if (setting)
- val |= PERIPH_CLK_NAND_DIV_EX_ENB;
- else
- val &= ~PERIPH_CLK_NAND_DIV_EX_ENB;
- clk_writel(val, c->reg);
- return 0;
- }
- return -EINVAL;
-}
-
-int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
- enum tegra_clk_ex_param p, u32 setting)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- if (p == TEGRA_CLK_DTV_INVERT) {
- u32 val = clk_readl(c->reg);
- if (setting)
- val |= PERIPH_CLK_DTV_POLARITY_INV;
- else
- val &= ~PERIPH_CLK_DTV_POLARITY_INV;
- clk_writel(val, c->reg);
- return 0;
- }
- return -EINVAL;
-}
-
-/* Output clock ops */
-
-static DEFINE_SPINLOCK(clk_out_lock);
-
-static int tegra30_clk_out_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = pmc_readl(c->reg);
-
- c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF;
- c->mul = 1;
- c->div = 1;
- return c->state;
-}
-
-static int tegra30_clk_out_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- unsigned long flags;
-
- spin_lock_irqsave(&clk_out_lock, flags);
- val = pmc_readl(c->reg);
- val |= (0x1 << c->u.periph.clk_num);
- pmc_writel(val, c->reg);
- spin_unlock_irqrestore(&clk_out_lock, flags);
-
- return 0;
-}
-
-static void tegra30_clk_out_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- unsigned long flags;
-
- spin_lock_irqsave(&clk_out_lock, flags);
- val = pmc_readl(c->reg);
- val &= ~(0x1 << c->u.periph.clk_num);
- pmc_writel(val, c->reg);
- spin_unlock_irqrestore(&clk_out_lock, flags);
-}
-
-static int tegra30_clk_out_set_parent(struct clk_hw *hw, u8 index)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
- unsigned long flags;
-
- spin_lock_irqsave(&clk_out_lock, flags);
- val = pmc_readl(c->reg);
- val &= ~periph_clk_source_mask(c);
- val |= (index << periph_clk_source_shift(c));
- pmc_writel(val, c->reg);
- spin_unlock_irqrestore(&clk_out_lock, flags);
-
- return 0;
-}
-
-static u8 tegra30_clk_out_get_parent(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = pmc_readl(c->reg);
- int source;
-
- source = (val & periph_clk_source_mask(c)) >>
- periph_clk_source_shift(c);
- return source;
-}
-
-struct clk_ops tegra_clk_out_ops = {
- .is_enabled = tegra30_clk_out_is_enabled,
- .enable = tegra30_clk_out_enable,
- .disable = tegra30_clk_out_disable,
- .set_parent = tegra30_clk_out_set_parent,
- .get_parent = tegra30_clk_out_get_parent,
- .recalc_rate = tegra30_clk_fixed_recalc_rate,
-};
-
-/* Clock doubler ops */
-static int tegra30_clk_double_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- c->state = ON;
- if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
- c->state = OFF;
- return c->state;
-};
-
-static int tegra30_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- if (rate == parent_rate) {
- val = clk_readl(c->reg) | (0x1 << c->reg_shift);
- clk_writel(val, c->reg);
- c->mul = 1;
- c->div = 1;
- return 0;
- } else if (rate == 2 * parent_rate) {
- val = clk_readl(c->reg) & (~(0x1 << c->reg_shift));
- clk_writel(val, c->reg);
- c->mul = 2;
- c->div = 1;
- return 0;
- }
- return -EINVAL;
-}
-
-static unsigned long tegra30_clk_double_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u64 rate = parent_rate;
-
- u32 val = clk_readl(c->reg);
- c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
- c->div = 1;
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
-
- return rate;
-}
-
-static long tegra30_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- unsigned long output_rate = *prate;
-
- do_div(output_rate, 2);
- return output_rate;
-}
-
-struct clk_ops tegra30_clk_double_ops = {
- .is_enabled = tegra30_clk_double_is_enabled,
- .enable = tegra30_periph_clk_enable,
- .disable = tegra30_periph_clk_disable,
- .recalc_rate = tegra30_clk_double_recalc_rate,
- .round_rate = tegra30_clk_double_round_rate,
- .set_rate = tegra30_clk_double_set_rate,
-};
-
-/* Audio sync clock ops */
-struct clk_ops tegra_sync_source_ops = {
- .recalc_rate = tegra30_clk_fixed_recalc_rate,
-};
-
-static int tegra30_audio_sync_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
- c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON;
- return c->state;
-}
-
-static int tegra30_audio_sync_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
- clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg);
- return 0;
-}
-
-static void tegra30_audio_sync_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
- clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg);
-}
-
-static int tegra30_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val;
-
- val = clk_readl(c->reg);
- val &= ~AUDIO_SYNC_SOURCE_MASK;
- val |= index;
-
- clk_writel(val, c->reg);
- return 0;
-}
-
-static u8 tegra30_audio_sync_clk_get_parent(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
- int source;
-
- source = val & AUDIO_SYNC_SOURCE_MASK;
- return source;
-}
-
-struct clk_ops tegra30_audio_sync_clk_ops = {
- .is_enabled = tegra30_audio_sync_clk_is_enabled,
- .enable = tegra30_audio_sync_clk_enable,
- .disable = tegra30_audio_sync_clk_disable,
- .set_parent = tegra30_audio_sync_clk_set_parent,
- .get_parent = tegra30_audio_sync_clk_get_parent,
- .recalc_rate = tegra30_clk_fixed_recalc_rate,
-};
-
-/* cml0 (pcie), and cml1 (sata) clock ops */
-static int tegra30_cml_clk_is_enabled(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
- u32 val = clk_readl(c->reg);
- c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF;
- return c->state;
-}
-
-static int tegra30_cml_clk_enable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- u32 val = clk_readl(c->reg);
- val |= (0x1 << c->u.periph.clk_num);
- clk_writel(val, c->reg);
-
- return 0;
-}
-
-static void tegra30_cml_clk_disable(struct clk_hw *hw)
-{
- struct clk_tegra *c = to_clk_tegra(hw);
-
- u32 val = clk_readl(c->reg);
- val &= ~(0x1 << c->u.periph.clk_num);
- clk_writel(val, c->reg);
-}
-
-struct clk_ops tegra_cml_clk_ops = {
- .is_enabled = tegra30_cml_clk_is_enabled,
- .enable = tegra30_cml_clk_enable,
- .disable = tegra30_cml_clk_disable,
- .recalc_rate = tegra30_clk_fixed_recalc_rate,
-};
-
-struct clk_ops tegra_pciex_clk_ops = {
- .recalc_rate = tegra30_clk_fixed_recalc_rate,
-};
-
-/* Tegra30 CPU clock and reset control functions */
-static void tegra30_wait_cpu_in_reset(u32 cpu)
-{
- unsigned int reg;
-
- do {
- reg = readl(reg_clk_base +
- TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
- cpu_relax();
- } while (!(reg & (1 << cpu))); /* check CPU been reset or not */
-
- return;
-}
-
-static void tegra30_put_cpu_in_reset(u32 cpu)
-{
- writel(CPU_RESET(cpu),
- reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
- dmb();
-}
-
-static void tegra30_cpu_out_of_reset(u32 cpu)
-{
- writel(CPU_RESET(cpu),
- reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
- wmb();
-}
-
-static void tegra30_enable_cpu_clock(u32 cpu)
-{
- unsigned int reg;
-
- writel(CPU_CLOCK(cpu),
- reg_clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
- reg = readl(reg_clk_base +
- TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
-}
-
-static void tegra30_disable_cpu_clock(u32 cpu)
-{
-
- unsigned int reg;
-
- reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
- writel(reg | CPU_CLOCK(cpu),
- reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static bool tegra30_cpu_rail_off_ready(void)
-{
- unsigned int cpu_rst_status;
- int cpu_pwr_status;
-
- cpu_rst_status = readl(reg_clk_base +
- TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
- cpu_pwr_status = tegra_powergate_is_powered(TEGRA_POWERGATE_CPU1) ||
- tegra_powergate_is_powered(TEGRA_POWERGATE_CPU2) ||
- tegra_powergate_is_powered(TEGRA_POWERGATE_CPU3);
-
- if (((cpu_rst_status & 0xE) != 0xE) || cpu_pwr_status)
- return false;
-
- return true;
-}
-
-static void tegra30_cpu_clock_suspend(void)
-{
- /* switch coresite to clk_m, save off original source */
- tegra30_cpu_clk_sctx.clk_csite_src =
- readl(reg_clk_base + CLK_RESET_SOURCE_CSITE);
- writel(3<<30, reg_clk_base + CLK_RESET_SOURCE_CSITE);
-
- tegra30_cpu_clk_sctx.cpu_burst =
- readl(reg_clk_base + CLK_RESET_CCLK_BURST);
- tegra30_cpu_clk_sctx.pllx_base =
- readl(reg_clk_base + CLK_RESET_PLLX_BASE);
- tegra30_cpu_clk_sctx.pllx_misc =
- readl(reg_clk_base + CLK_RESET_PLLX_MISC);
- tegra30_cpu_clk_sctx.cclk_divider =
- readl(reg_clk_base + CLK_RESET_CCLK_DIVIDER);
-}
-
-static void tegra30_cpu_clock_resume(void)
-{
- unsigned int reg, policy;
-
- /* Is CPU complex already running on PLLX? */
- reg = readl(reg_clk_base + CLK_RESET_CCLK_BURST);
- policy = (reg >> CLK_RESET_CCLK_BURST_POLICY_SHIFT) & 0xF;
-
- if (policy == CLK_RESET_CCLK_IDLE_POLICY)
- reg = (reg >> CLK_RESET_CCLK_IDLE_POLICY_SHIFT) & 0xF;
- else if (policy == CLK_RESET_CCLK_RUN_POLICY)
- reg = (reg >> CLK_RESET_CCLK_RUN_POLICY_SHIFT) & 0xF;
- else
- BUG();
-
- if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) {
- /* restore PLLX settings if CPU is on different PLL */
- writel(tegra30_cpu_clk_sctx.pllx_misc,
- reg_clk_base + CLK_RESET_PLLX_MISC);
- writel(tegra30_cpu_clk_sctx.pllx_base,
- reg_clk_base + CLK_RESET_PLLX_BASE);
-
- /* wait for PLL stabilization if PLLX was enabled */
- if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30))
- udelay(300);
- }
-
- /*
- * Restore original burst policy setting for calls resulting from CPU
- * LP2 in idle or system suspend.
- */
- writel(tegra30_cpu_clk_sctx.cclk_divider,
- reg_clk_base + CLK_RESET_CCLK_DIVIDER);
- writel(tegra30_cpu_clk_sctx.cpu_burst,
- reg_clk_base + CLK_RESET_CCLK_BURST);
-
- writel(tegra30_cpu_clk_sctx.clk_csite_src,
- reg_clk_base + CLK_RESET_SOURCE_CSITE);
-}
-#endif
-
-static struct tegra_cpu_car_ops tegra30_cpu_car_ops = {
- .wait_for_reset = tegra30_wait_cpu_in_reset,
- .put_in_reset = tegra30_put_cpu_in_reset,
- .out_of_reset = tegra30_cpu_out_of_reset,
- .enable_clock = tegra30_enable_cpu_clock,
- .disable_clock = tegra30_disable_cpu_clock,
-#ifdef CONFIG_PM_SLEEP
- .rail_off_ready = tegra30_cpu_rail_off_ready,
- .suspend = tegra30_cpu_clock_suspend,
- .resume = tegra30_cpu_clock_resume,
-#endif
-};
-
-void __init tegra30_cpu_car_ops_init(void)
-{
- tegra_cpu_car_ops = &tegra30_cpu_car_ops;
-}
diff --git a/arch/arm/mach-tegra/tegra30_clocks.h b/arch/arm/mach-tegra/tegra30_clocks.h
deleted file mode 100644
index 7a34adb2f72d..000000000000
--- a/arch/arm/mach-tegra/tegra30_clocks.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __MACH_TEGRA30_CLOCK_H
-#define __MACH_TEGRA30_CLOCK_H
-
-extern struct clk_ops tegra30_clk_32k_ops;
-extern struct clk_ops tegra30_clk_m_ops;
-extern struct clk_ops tegra_clk_m_div_ops;
-extern struct clk_ops tegra_pll_ref_ops;
-extern struct clk_ops tegra30_pll_ops;
-extern struct clk_ops tegra30_pll_div_ops;
-extern struct clk_ops tegra_plld_ops;
-extern struct clk_ops tegra30_plle_ops;
-extern struct clk_ops tegra_cml_clk_ops;
-extern struct clk_ops tegra_pciex_clk_ops;
-extern struct clk_ops tegra_sync_source_ops;
-extern struct clk_ops tegra30_audio_sync_clk_ops;
-extern struct clk_ops tegra30_clk_double_ops;
-extern struct clk_ops tegra_clk_out_ops;
-extern struct clk_ops tegra30_super_ops;
-extern struct clk_ops tegra30_blink_clk_ops;
-extern struct clk_ops tegra30_twd_ops;
-extern struct clk_ops tegra30_bus_ops;
-extern struct clk_ops tegra30_periph_clk_ops;
-extern struct clk_ops tegra30_dsib_clk_ops;
-extern struct clk_ops tegra_nand_clk_ops;
-extern struct clk_ops tegra_vi_clk_ops;
-extern struct clk_ops tegra_dtv_clk_ops;
-extern struct clk_ops tegra_clk_shared_bus_ops;
-
-int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
- enum tegra_clk_ex_param p, u32 setting);
-void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert);
-int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
- enum tegra_clk_ex_param p, u32 setting);
-int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
- enum tegra_clk_ex_param p, u32 setting);
-int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
- enum tegra_clk_ex_param p, u32 setting);
-#endif
diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c
deleted file mode 100644
index 6942c7add3bb..000000000000
--- a/arch/arm/mach-tegra/tegra30_clocks_data.c
+++ /dev/null
@@ -1,1425 +0,0 @@
-/*
- * arch/arm/mach-tegra/tegra30_clocks.c
- *
- * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include <linux/clk-private.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-
-#include "clock.h"
-#include "fuse.h"
-#include "tegra30_clocks.h"
-#include "tegra_cpu_car.h"
-
-#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \
- _parent_names, _parents, _parent) \
- static struct clk tegra_##_name = { \
- .hw = &tegra_##_name##_hw.hw, \
- .name = #_name, \
- .rate = _rate, \
- .ops = _ops, \
- .flags = _flags, \
- .parent_names = _parent_names, \
- .parents = _parents, \
- .num_parents = ARRAY_SIZE(_parent_names), \
- .parent = _parent, \
- };
-
-static struct clk tegra_clk_32k;
-static struct clk_tegra tegra_clk_32k_hw = {
- .hw = {
- .clk = &tegra_clk_32k,
- },
- .fixed_rate = 32768,
-};
-static struct clk tegra_clk_32k = {
- .name = "clk_32k",
- .hw = &tegra_clk_32k_hw.hw,
- .ops = &tegra30_clk_32k_ops,
- .flags = CLK_IS_ROOT,
-};
-
-static struct clk tegra_clk_m;
-static struct clk_tegra tegra_clk_m_hw = {
- .hw = {
- .clk = &tegra_clk_m,
- },
- .flags = ENABLE_ON_INIT,
- .reg = 0x1fc,
- .reg_shift = 28,
- .max_rate = 48000000,
-};
-static struct clk tegra_clk_m = {
- .name = "clk_m",
- .hw = &tegra_clk_m_hw.hw,
- .ops = &tegra30_clk_m_ops,
- .flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED,
-};
-
-static const char *clk_m_div_parent_names[] = {
- "clk_m",
-};
-
-static struct clk *clk_m_div_parents[] = {
- &tegra_clk_m,
-};
-
-static struct clk tegra_clk_m_div2;
-static struct clk_tegra tegra_clk_m_div2_hw = {
- .hw = {
- .clk = &tegra_clk_m_div2,
- },
- .mul = 1,
- .div = 2,
- .max_rate = 24000000,
-};
-DEFINE_CLK_TEGRA(clk_m_div2, 0, &tegra_clk_m_div_ops, 0,
- clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m);
-
-static struct clk tegra_clk_m_div4;
-static struct clk_tegra tegra_clk_m_div4_hw = {
- .hw = {
- .clk = &tegra_clk_m_div4,
- },
- .mul = 1,
- .div = 4,
- .max_rate = 12000000,
-};
-DEFINE_CLK_TEGRA(clk_m_div4, 0, &tegra_clk_m_div_ops, 0,
- clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m);
-
-static struct clk tegra_pll_ref;
-static struct clk_tegra tegra_pll_ref_hw = {
- .hw = {
- .clk = &tegra_pll_ref,
- },
- .flags = ENABLE_ON_INIT,
- .max_rate = 26000000,
-};
-DEFINE_CLK_TEGRA(pll_ref, 0, &tegra_pll_ref_ops, 0, clk_m_div_parent_names,
- clk_m_div_parents, &tegra_clk_m);
-
-#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min, \
- _input_max, _cf_min, _cf_max, _vco_min, \
- _vco_max, _freq_table, _lock_delay, _ops, \
- _fixed_rate, _clk_cfg_ex, _parent) \
- static struct clk tegra_##_name; \
- static const char *_name##_parent_names[] = { \
- #_parent, \
- }; \
- static struct clk *_name##_parents[] = { \
- &tegra_##_parent, \
- }; \
- static struct clk_tegra tegra_##_name##_hw = { \
- .hw = { \
- .clk = &tegra_##_name, \
- }, \
- .flags = _flags, \
- .reg = _reg, \
- .max_rate = _max_rate, \
- .u.pll = { \
- .input_min = _input_min, \
- .input_max = _input_max, \
- .cf_min = _cf_min, \
- .cf_max = _cf_max, \
- .vco_min = _vco_min, \
- .vco_max = _vco_max, \
- .freq_table = _freq_table, \
- .lock_delay = _lock_delay, \
- .fixed_rate = _fixed_rate, \
- }, \
- .clk_cfg_ex = _clk_cfg_ex, \
- }; \
- DEFINE_CLK_TEGRA(_name, 0, &_ops, CLK_IGNORE_UNUSED, \
- _name##_parent_names, _name##_parents, \
- &tegra_##_parent);
-
-#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift, \
- _max_rate, _ops, _parent, _clk_flags) \
- static const char *_name##_parent_names[] = { \
- #_parent, \
- }; \
- static struct clk *_name##_parents[] = { \
- &tegra_##_parent, \
- }; \
- static struct clk tegra_##_name; \
- static struct clk_tegra tegra_##_name##_hw = { \
- .hw = { \
- .clk = &tegra_##_name, \
- }, \
- .flags = _flags, \
- .reg = _reg, \
- .max_rate = _max_rate, \
- .reg_shift = _reg_shift, \
- }; \
- DEFINE_CLK_TEGRA(_name, 0, &tegra30_pll_div_ops, \
- _clk_flags, _name##_parent_names, \
- _name##_parents, &tegra_##_parent);
-
-static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
- { 12000000, 1040000000, 520, 6, 1, 8},
- { 13000000, 1040000000, 480, 6, 1, 8},
- { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */
- { 19200000, 1040000000, 325, 6, 1, 6},
- { 26000000, 1040000000, 520, 13, 1, 8},
-
- { 12000000, 832000000, 416, 6, 1, 8},
- { 13000000, 832000000, 832, 13, 1, 8},
- { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */
- { 19200000, 832000000, 260, 6, 1, 8},
- { 26000000, 832000000, 416, 13, 1, 8},
-
- { 12000000, 624000000, 624, 12, 1, 8},
- { 13000000, 624000000, 624, 13, 1, 8},
- { 16800000, 600000000, 520, 14, 1, 8},
- { 19200000, 624000000, 520, 16, 1, 8},
- { 26000000, 624000000, 624, 26, 1, 8},
-
- { 12000000, 600000000, 600, 12, 1, 8},
- { 13000000, 600000000, 600, 13, 1, 8},
- { 16800000, 600000000, 500, 14, 1, 8},
- { 19200000, 600000000, 375, 12, 1, 6},
- { 26000000, 600000000, 600, 26, 1, 8},
-
- { 12000000, 520000000, 520, 12, 1, 8},
- { 13000000, 520000000, 520, 13, 1, 8},
- { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */
- { 19200000, 520000000, 325, 12, 1, 6},
- { 26000000, 520000000, 520, 26, 1, 8},
-
- { 12000000, 416000000, 416, 12, 1, 8},
- { 13000000, 416000000, 416, 13, 1, 8},
- { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */
- { 19200000, 416000000, 260, 12, 1, 6},
- { 26000000, 416000000, 416, 26, 1, 8},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 1400000000, 2000000, 31000000, 1000000,
- 6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300,
- tegra30_pll_ops, 0, NULL, pll_ref);
-
-DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 700000000,
- tegra30_pll_div_ops, pll_c, CLK_IGNORE_UNUSED);
-
-static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
- { 12000000, 666000000, 666, 12, 1, 8},
- { 13000000, 666000000, 666, 13, 1, 8},
- { 16800000, 666000000, 555, 14, 1, 8},
- { 19200000, 666000000, 555, 16, 1, 8},
- { 26000000, 666000000, 666, 26, 1, 8},
- { 12000000, 600000000, 600, 12, 1, 8},
- { 13000000, 600000000, 600, 13, 1, 8},
- { 16800000, 600000000, 500, 14, 1, 8},
- { 19200000, 600000000, 375, 12, 1, 6},
- { 26000000, 600000000, 600, 26, 1, 8},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_m, PLL_HAS_CPCON | PLLM, 0x90, 800000000, 2000000, 31000000,
- 1000000, 6000000, 20000000, 1200000000, tegra_pll_m_freq_table,
- 300, tegra30_pll_ops, 0, NULL, pll_ref);
-
-DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000,
- tegra30_pll_div_ops, pll_m, CLK_IGNORE_UNUSED);
-
-static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
- { 12000000, 216000000, 432, 12, 2, 8},
- { 13000000, 216000000, 432, 13, 2, 8},
- { 16800000, 216000000, 360, 14, 2, 8},
- { 19200000, 216000000, 360, 16, 2, 8},
- { 26000000, 216000000, 432, 26, 2, 8},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000,
- 2000000, 31000000, 1000000, 6000000, 20000000, 1400000000,
- tegra_pll_p_freq_table, 300, tegra30_pll_ops, 408000000, NULL,
- pll_ref);
-
-DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4,
- 0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
-DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4,
- 16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
-DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8,
- 0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
-DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8,
- 16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
-
-static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
- { 9600000, 564480000, 294, 5, 1, 4},
- { 9600000, 552960000, 288, 5, 1, 4},
- { 9600000, 24000000, 5, 2, 1, 1},
-
- { 28800000, 56448000, 49, 25, 1, 1},
- { 28800000, 73728000, 64, 25, 1, 1},
- { 28800000, 24000000, 5, 6, 1, 1},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 700000000, 2000000, 31000000, 1000000,
- 6000000, 20000000, 1400000000, tegra_pll_a_freq_table,
- 300, tegra30_pll_ops, 0, NULL, pll_p_out1);
-
-DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 100000000, tegra30_pll_div_ops,
- pll_a, CLK_IGNORE_UNUSED);
-
-static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
- { 12000000, 216000000, 216, 12, 1, 4},
- { 13000000, 216000000, 216, 13, 1, 4},
- { 16800000, 216000000, 180, 14, 1, 4},
- { 19200000, 216000000, 180, 16, 1, 4},
- { 26000000, 216000000, 216, 26, 1, 4},
-
- { 12000000, 594000000, 594, 12, 1, 8},
- { 13000000, 594000000, 594, 13, 1, 8},
- { 16800000, 594000000, 495, 14, 1, 8},
- { 19200000, 594000000, 495, 16, 1, 8},
- { 26000000, 594000000, 594, 26, 1, 8},
-
- { 12000000, 1000000000, 1000, 12, 1, 12},
- { 13000000, 1000000000, 1000, 13, 1, 12},
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 12},
-
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000,
- 1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table,
- 1000, tegra30_pll_ops, 0, tegra30_plld_clk_cfg_ex, pll_ref);
-
-DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops,
- pll_d, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
-
-DEFINE_PLL(pll_d2, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD, 0x4b8, 1000000000,
- 2000000, 40000000, 1000000, 6000000, 40000000, 1000000000,
- tegra_pll_d_freq_table, 1000, tegra30_pll_ops, 0, NULL,
- pll_ref);
-
-DEFINE_PLL_OUT(pll_d2_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops,
- pll_d2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
-
-static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
- { 12000000, 480000000, 960, 12, 2, 12},
- { 13000000, 480000000, 960, 13, 2, 12},
- { 16800000, 480000000, 400, 7, 2, 5},
- { 19200000, 480000000, 200, 4, 2, 3},
- { 26000000, 480000000, 960, 26, 2, 12},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_u, PLL_HAS_CPCON | PLLU, 0xc0, 480000000, 2000000, 40000000,
- 1000000, 6000000, 48000000, 960000000, tegra_pll_u_freq_table,
- 1000, tegra30_pll_ops, 0, NULL, pll_ref);
-
-static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
- /* 1.7 GHz */
- { 12000000, 1700000000, 850, 6, 1, 8},
- { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */
- { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */
- { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */
- { 26000000, 1700000000, 850, 13, 1, 8},
-
- /* 1.6 GHz */
- { 12000000, 1600000000, 800, 6, 1, 8},
- { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */
- { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */
- { 19200000, 1600000000, 500, 6, 1, 8},
- { 26000000, 1600000000, 800, 13, 1, 8},
-
- /* 1.5 GHz */
- { 12000000, 1500000000, 750, 6, 1, 8},
- { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */
- { 16800000, 1500000000, 625, 7, 1, 8},
- { 19200000, 1500000000, 625, 8, 1, 8},
- { 26000000, 1500000000, 750, 13, 1, 8},
-
- /* 1.4 GHz */
- { 12000000, 1400000000, 700, 6, 1, 8},
- { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */
- { 16800000, 1400000000, 1000, 12, 1, 8},
- { 19200000, 1400000000, 875, 12, 1, 8},
- { 26000000, 1400000000, 700, 13, 1, 8},
-
- /* 1.3 GHz */
- { 12000000, 1300000000, 975, 9, 1, 8},
- { 13000000, 1300000000, 1000, 10, 1, 8},
- { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */
- { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */
- { 26000000, 1300000000, 650, 13, 1, 8},
-
- /* 1.2 GHz */
- { 12000000, 1200000000, 1000, 10, 1, 8},
- { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */
- { 16800000, 1200000000, 1000, 14, 1, 8},
- { 19200000, 1200000000, 1000, 16, 1, 8},
- { 26000000, 1200000000, 600, 13, 1, 8},
-
- /* 1.1 GHz */
- { 12000000, 1100000000, 825, 9, 1, 8},
- { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */
- { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */
- { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */
- { 26000000, 1100000000, 550, 13, 1, 8},
-
- /* 1 GHz */
- { 12000000, 1000000000, 1000, 12, 1, 8},
- { 13000000, 1000000000, 1000, 13, 1, 8},
- { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 8},
-
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX, 0xe0, 1700000000,
- 2000000, 31000000, 1000000, 6000000, 20000000, 1700000000,
- tegra_pll_x_freq_table, 300, tegra30_pll_ops, 0, NULL, pll_ref);
-
-DEFINE_PLL_OUT(pll_x_out0, DIV_2 | PLLX, 0, 0, 850000000, tegra30_pll_div_ops,
- pll_x, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
-
-static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
- /* PLLE special case: use cpcon field to store cml divider value */
- { 12000000, 100000000, 150, 1, 18, 11},
- { 216000000, 100000000, 200, 18, 24, 13},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 2000000, 216000000,
- 12000000, 12000000, 1200000000, 2400000000U,
- tegra_pll_e_freq_table, 300, tegra30_plle_ops, 100000000, NULL,
- pll_ref);
-
-static const char *mux_plle[] = {
- "pll_e",
-};
-
-static struct clk *mux_plle_p[] = {
- &tegra_pll_e,
-};
-
-static struct clk tegra_cml0;
-static struct clk_tegra tegra_cml0_hw = {
- .hw = {
- .clk = &tegra_cml0,
- },
- .reg = 0x48c,
- .fixed_rate = 100000000,
- .u.periph = {
- .clk_num = 0,
- },
-};
-DEFINE_CLK_TEGRA(cml0, 0, &tegra_cml_clk_ops, 0, mux_plle,
- mux_plle_p, &tegra_pll_e);
-
-static struct clk tegra_cml1;
-static struct clk_tegra tegra_cml1_hw = {
- .hw = {
- .clk = &tegra_cml1,
- },
- .reg = 0x48c,
- .fixed_rate = 100000000,
- .u.periph = {
- .clk_num = 1,
- },
-};
-DEFINE_CLK_TEGRA(cml1, 0, &tegra_cml_clk_ops, 0, mux_plle,
- mux_plle_p, &tegra_pll_e);
-
-static struct clk tegra_pciex;
-static struct clk_tegra tegra_pciex_hw = {
- .hw = {
- .clk = &tegra_pciex,
- },
- .reg = 0x48c,
- .fixed_rate = 100000000,
- .reset = tegra30_periph_clk_reset,
- .u.periph = {
- .clk_num = 74,
- },
-};
-DEFINE_CLK_TEGRA(pciex, 0, &tegra_pciex_clk_ops, 0, mux_plle,
- mux_plle_p, &tegra_pll_e);
-
-#define SYNC_SOURCE(_name) \
- static struct clk tegra_##_name##_sync; \
- static struct clk_tegra tegra_##_name##_sync_hw = { \
- .hw = { \
- .clk = &tegra_##_name##_sync, \
- }, \
- .max_rate = 24000000, \
- .fixed_rate = 24000000, \
- }; \
- static struct clk tegra_##_name##_sync = { \
- .name = #_name "_sync", \
- .hw = &tegra_##_name##_sync_hw.hw, \
- .ops = &tegra_sync_source_ops, \
- .flags = CLK_IS_ROOT, \
- };
-
-SYNC_SOURCE(spdif_in);
-SYNC_SOURCE(i2s0);
-SYNC_SOURCE(i2s1);
-SYNC_SOURCE(i2s2);
-SYNC_SOURCE(i2s3);
-SYNC_SOURCE(i2s4);
-SYNC_SOURCE(vimclk);
-
-static struct clk *tegra_sync_source_list[] = {
- &tegra_spdif_in_sync,
- &tegra_i2s0_sync,
- &tegra_i2s1_sync,
- &tegra_i2s2_sync,
- &tegra_i2s3_sync,
- &tegra_i2s4_sync,
- &tegra_vimclk_sync,
-};
-
-static const char *mux_audio_sync_clk[] = {
- "spdif_in_sync",
- "i2s0_sync",
- "i2s1_sync",
- "i2s2_sync",
- "i2s3_sync",
- "i2s4_sync",
- "vimclk_sync",
-};
-
-#define AUDIO_SYNC_CLK(_name, _index) \
- static struct clk tegra_##_name; \
- static struct clk_tegra tegra_##_name##_hw = { \
- .hw = { \
- .clk = &tegra_##_name, \
- }, \
- .max_rate = 24000000, \
- .reg = 0x4A0 + (_index) * 4, \
- }; \
- static struct clk tegra_##_name = { \
- .name = #_name, \
- .ops = &tegra30_audio_sync_clk_ops, \
- .hw = &tegra_##_name##_hw.hw, \
- .parent_names = mux_audio_sync_clk, \
- .parents = tegra_sync_source_list, \
- .num_parents = ARRAY_SIZE(mux_audio_sync_clk), \
- };
-
-AUDIO_SYNC_CLK(audio0, 0);
-AUDIO_SYNC_CLK(audio1, 1);
-AUDIO_SYNC_CLK(audio2, 2);
-AUDIO_SYNC_CLK(audio3, 3);
-AUDIO_SYNC_CLK(audio4, 4);
-AUDIO_SYNC_CLK(audio5, 5);
-
-static struct clk *tegra_clk_audio_list[] = {
- &tegra_audio0,
- &tegra_audio1,
- &tegra_audio2,
- &tegra_audio3,
- &tegra_audio4,
- &tegra_audio5, /* SPDIF */
-};
-
-#define AUDIO_SYNC_2X_CLK(_name, _index) \
- static const char *_name##_parent_names[] = { \
- "tegra_" #_name, \
- }; \
- static struct clk *_name##_parents[] = { \
- &tegra_##_name, \
- }; \
- static struct clk tegra_##_name##_2x; \
- static struct clk_tegra tegra_##_name##_2x_hw = { \
- .hw = { \
- .clk = &tegra_##_name##_2x, \
- }, \
- .flags = PERIPH_NO_RESET, \
- .max_rate = 48000000, \
- .reg = 0x49C, \
- .reg_shift = 24 + (_index), \
- .u.periph = { \
- .clk_num = 113 + (_index), \
- }, \
- }; \
- static struct clk tegra_##_name##_2x = { \
- .name = #_name "_2x", \
- .ops = &tegra30_clk_double_ops, \
- .hw = &tegra_##_name##_2x_hw.hw, \
- .parent_names = _name##_parent_names, \
- .parents = _name##_parents, \
- .parent = &tegra_##_name, \
- .num_parents = 1, \
- };
-
-AUDIO_SYNC_2X_CLK(audio0, 0);
-AUDIO_SYNC_2X_CLK(audio1, 1);
-AUDIO_SYNC_2X_CLK(audio2, 2);
-AUDIO_SYNC_2X_CLK(audio3, 3);
-AUDIO_SYNC_2X_CLK(audio4, 4);
-AUDIO_SYNC_2X_CLK(audio5, 5); /* SPDIF */
-
-static struct clk *tegra_clk_audio_2x_list[] = {
- &tegra_audio0_2x,
- &tegra_audio1_2x,
- &tegra_audio2_2x,
- &tegra_audio3_2x,
- &tegra_audio4_2x,
- &tegra_audio5_2x, /* SPDIF */
-};
-
-#define MUX_I2S_SPDIF(_id) \
-static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { \
- "pll_a_out0", \
- #_id "_2x", \
- "pll_p", \
- "clk_m", \
-}; \
-static struct clk *mux_pllaout0_##_id##_2x_pllp_clkm_p[] = { \
- &tegra_pll_a_out0, \
- &tegra_##_id##_2x, \
- &tegra_pll_p, \
- &tegra_clk_m, \
-};
-
-MUX_I2S_SPDIF(audio0);
-MUX_I2S_SPDIF(audio1);
-MUX_I2S_SPDIF(audio2);
-MUX_I2S_SPDIF(audio3);
-MUX_I2S_SPDIF(audio4);
-MUX_I2S_SPDIF(audio5); /* SPDIF */
-
-static struct clk tegra_extern1;
-static struct clk tegra_extern2;
-static struct clk tegra_extern3;
-
-/* External clock outputs (through PMC) */
-#define MUX_EXTERN_OUT(_id) \
-static const char *mux_clkm_clkm2_clkm4_extern##_id[] = { \
- "clk_m", \
- "clk_m_div2", \
- "clk_m_div4", \
- "extern" #_id, \
-}; \
-static struct clk *mux_clkm_clkm2_clkm4_extern##_id##_p[] = { \
- &tegra_clk_m, \
- &tegra_clk_m_div2, \
- &tegra_clk_m_div4, \
- &tegra_extern##_id, \
-};
-
-MUX_EXTERN_OUT(1);
-MUX_EXTERN_OUT(2);
-MUX_EXTERN_OUT(3);
-
-#define CLK_OUT_CLK(_name, _index) \
- static struct clk tegra_##_name; \
- static struct clk_tegra tegra_##_name##_hw = { \
- .hw = { \
- .clk = &tegra_##_name, \
- }, \
- .lookup = { \
- .dev_id = #_name, \
- .con_id = "extern" #_index, \
- }, \
- .flags = MUX_CLK_OUT, \
- .fixed_rate = 216000000, \
- .reg = 0x1a8, \
- .u.periph = { \
- .clk_num = (_index - 1) * 8 + 2, \
- }, \
- }; \
- static struct clk tegra_##_name = { \
- .name = #_name, \
- .ops = &tegra_clk_out_ops, \
- .hw = &tegra_##_name##_hw.hw, \
- .parent_names = mux_clkm_clkm2_clkm4_extern##_index, \
- .parents = mux_clkm_clkm2_clkm4_extern##_index##_p, \
- .num_parents = ARRAY_SIZE(mux_clkm_clkm2_clkm4_extern##_index),\
- };
-
-CLK_OUT_CLK(clk_out_1, 1);
-CLK_OUT_CLK(clk_out_2, 2);
-CLK_OUT_CLK(clk_out_3, 3);
-
-static struct clk *tegra_clk_out_list[] = {
- &tegra_clk_out_1,
- &tegra_clk_out_2,
- &tegra_clk_out_3,
-};
-
-static const char *mux_sclk[] = {
- "clk_m",
- "pll_c_out1",
- "pll_p_out4",
- "pll_p_out3",
- "pll_p_out2",
- "dummy",
- "clk_32k",
- "pll_m_out1",
-};
-
-static struct clk *mux_sclk_p[] = {
- &tegra_clk_m,
- &tegra_pll_c_out1,
- &tegra_pll_p_out4,
- &tegra_pll_p_out3,
- &tegra_pll_p_out2,
- NULL,
- &tegra_clk_32k,
- &tegra_pll_m_out1,
-};
-
-static struct clk tegra_clk_sclk;
-static struct clk_tegra tegra_clk_sclk_hw = {
- .hw = {
- .clk = &tegra_clk_sclk,
- },
- .reg = 0x28,
- .max_rate = 334000000,
- .min_rate = 40000000,
-};
-
-static struct clk tegra_clk_sclk = {
- .name = "sclk",
- .ops = &tegra30_super_ops,
- .hw = &tegra_clk_sclk_hw.hw,
- .parent_names = mux_sclk,
- .parents = mux_sclk_p,
- .num_parents = ARRAY_SIZE(mux_sclk),
-};
-
-static const char *tegra_hclk_parent_names[] = {
- "tegra_sclk",
-};
-
-static struct clk *tegra_hclk_parents[] = {
- &tegra_clk_sclk,
-};
-
-static struct clk tegra_hclk;
-static struct clk_tegra tegra_hclk_hw = {
- .hw = {
- .clk = &tegra_hclk,
- },
- .flags = DIV_BUS,
- .reg = 0x30,
- .reg_shift = 4,
- .max_rate = 378000000,
- .min_rate = 12000000,
-};
-DEFINE_CLK_TEGRA(hclk, 0, &tegra30_bus_ops, 0, tegra_hclk_parent_names,
- tegra_hclk_parents, &tegra_clk_sclk);
-
-static const char *tegra_pclk_parent_names[] = {
- "tegra_hclk",
-};
-
-static struct clk *tegra_pclk_parents[] = {
- &tegra_hclk,
-};
-
-static struct clk tegra_pclk;
-static struct clk_tegra tegra_pclk_hw = {
- .hw = {
- .clk = &tegra_pclk,
- },
- .flags = DIV_BUS,
- .reg = 0x30,
- .reg_shift = 0,
- .max_rate = 167000000,
- .min_rate = 12000000,
-};
-DEFINE_CLK_TEGRA(pclk, 0, &tegra30_bus_ops, 0, tegra_pclk_parent_names,
- tegra_pclk_parents, &tegra_hclk);
-
-static const char *mux_blink[] = {
- "clk_32k",
-};
-
-static struct clk *mux_blink_p[] = {
- &tegra_clk_32k,
-};
-
-static struct clk tegra_clk_blink;
-static struct clk_tegra tegra_clk_blink_hw = {
- .hw = {
- .clk = &tegra_clk_blink,
- },
- .reg = 0x40,
- .max_rate = 32768,
-};
-static struct clk tegra_clk_blink = {
- .name = "blink",
- .ops = &tegra30_blink_clk_ops,
- .hw = &tegra_clk_blink_hw.hw,
- .parent = &tegra_clk_32k,
- .parent_names = mux_blink,
- .parents = mux_blink_p,
- .num_parents = ARRAY_SIZE(mux_blink),
-};
-
-static const char *mux_pllm_pllc_pllp_plla[] = {
- "pll_m",
- "pll_c",
- "pll_p",
- "pll_a_out0",
-};
-
-static const char *mux_pllp_pllc_pllm_clkm[] = {
- "pll_p",
- "pll_c",
- "pll_m",
- "clk_m",
-};
-
-static const char *mux_pllp_clkm[] = {
- "pll_p",
- "dummy",
- "dummy",
- "clk_m",
-};
-
-static const char *mux_pllp_plld_pllc_clkm[] = {
- "pll_p",
- "pll_d_out0",
- "pll_c",
- "clk_m",
-};
-
-static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
- "pll_p",
- "pll_m",
- "pll_d_out0",
- "pll_a_out0",
- "pll_c",
- "pll_d2_out0",
- "clk_m",
-};
-
-static const char *mux_plla_pllc_pllp_clkm[] = {
- "pll_a_out0",
- "dummy",
- "pll_p",
- "clk_m"
-};
-
-static const char *mux_pllp_pllc_clk32_clkm[] = {
- "pll_p",
- "pll_c",
- "clk_32k",
- "clk_m",
-};
-
-static const char *mux_pllp_pllc_clkm_clk32[] = {
- "pll_p",
- "pll_c",
- "clk_m",
- "clk_32k",
-};
-
-static const char *mux_pllp_pllc_pllm[] = {
- "pll_p",
- "pll_c",
- "pll_m",
-};
-
-static const char *mux_clk_m[] = {
- "clk_m",
-};
-
-static const char *mux_pllp_out3[] = {
- "pll_p_out3",
-};
-
-static const char *mux_plld_out0[] = {
- "pll_d_out0",
-};
-
-static const char *mux_plld_out0_plld2_out0[] = {
- "pll_d_out0",
- "pll_d2_out0",
-};
-
-static const char *mux_clk_32k[] = {
- "clk_32k",
-};
-
-static const char *mux_plla_clk32_pllp_clkm_plle[] = {
- "pll_a_out0",
- "clk_32k",
- "pll_p",
- "clk_m",
- "pll_e",
-};
-
-static const char *mux_cclk_g[] = {
- "clk_m",
- "pll_c",
- "clk_32k",
- "pll_m",
- "pll_p",
- "pll_p_out4",
- "pll_p_out3",
- "dummy",
- "pll_x",
-};
-
-static struct clk *mux_pllm_pllc_pllp_plla_p[] = {
- &tegra_pll_m,
- &tegra_pll_c,
- &tegra_pll_p,
- &tegra_pll_a_out0,
-};
-
-static struct clk *mux_pllp_pllc_pllm_clkm_p[] = {
- &tegra_pll_p,
- &tegra_pll_c,
- &tegra_pll_m,
- &tegra_clk_m,
-};
-
-static struct clk *mux_pllp_clkm_p[] = {
- &tegra_pll_p,
- NULL,
- NULL,
- &tegra_clk_m,
-};
-
-static struct clk *mux_pllp_plld_pllc_clkm_p[] = {
- &tegra_pll_p,
- &tegra_pll_d_out0,
- &tegra_pll_c,
- &tegra_clk_m,
-};
-
-static struct clk *mux_pllp_pllm_plld_plla_pllc_plld2_clkm_p[] = {
- &tegra_pll_p,
- &tegra_pll_m,
- &tegra_pll_d_out0,
- &tegra_pll_a_out0,
- &tegra_pll_c,
- &tegra_pll_d2_out0,
- &tegra_clk_m,
-};
-
-static struct clk *mux_plla_pllc_pllp_clkm_p[] = {
- &tegra_pll_a_out0,
- NULL,
- &tegra_pll_p,
- &tegra_clk_m,
-};
-
-static struct clk *mux_pllp_pllc_clk32_clkm_p[] = {
- &tegra_pll_p,
- &tegra_pll_c,
- &tegra_clk_32k,
- &tegra_clk_m,
-};
-
-static struct clk *mux_pllp_pllc_clkm_clk32_p[] = {
- &tegra_pll_p,
- &tegra_pll_c,
- &tegra_clk_m,
- &tegra_clk_32k,
-};
-
-static struct clk *mux_pllp_pllc_pllm_p[] = {
- &tegra_pll_p,
- &tegra_pll_c,
- &tegra_pll_m,
-};
-
-static struct clk *mux_clk_m_p[] = {
- &tegra_clk_m,
-};
-
-static struct clk *mux_pllp_out3_p[] = {
- &tegra_pll_p_out3,
-};
-
-static struct clk *mux_plld_out0_p[] = {
- &tegra_pll_d_out0,
-};
-
-static struct clk *mux_plld_out0_plld2_out0_p[] = {
- &tegra_pll_d_out0,
- &tegra_pll_d2_out0,
-};
-
-static struct clk *mux_clk_32k_p[] = {
- &tegra_clk_32k,
-};
-
-static struct clk *mux_plla_clk32_pllp_clkm_plle_p[] = {
- &tegra_pll_a_out0,
- &tegra_clk_32k,
- &tegra_pll_p,
- &tegra_clk_m,
- &tegra_pll_e,
-};
-
-static struct clk *mux_cclk_g_p[] = {
- &tegra_clk_m,
- &tegra_pll_c,
- &tegra_clk_32k,
- &tegra_pll_m,
- &tegra_pll_p,
- &tegra_pll_p_out4,
- &tegra_pll_p_out3,
- NULL,
- &tegra_pll_x,
-};
-
-static struct clk tegra_clk_cclk_g;
-static struct clk_tegra tegra_clk_cclk_g_hw = {
- .hw = {
- .clk = &tegra_clk_cclk_g,
- },
- .flags = DIV_U71 | DIV_U71_INT,
- .reg = 0x368,
- .max_rate = 1700000000,
-};
-static struct clk tegra_clk_cclk_g = {
- .name = "cclk_g",
- .ops = &tegra30_super_ops,
- .hw = &tegra_clk_cclk_g_hw.hw,
- .parent_names = mux_cclk_g,
- .parents = mux_cclk_g_p,
- .num_parents = ARRAY_SIZE(mux_cclk_g),
-};
-
-static const char *mux_twd[] = {
- "cclk_g",
-};
-
-static struct clk *mux_twd_p[] = {
- &tegra_clk_cclk_g,
-};
-
-static struct clk tegra30_clk_twd;
-static struct clk_tegra tegra30_clk_twd_hw = {
- .hw = {
- .clk = &tegra30_clk_twd,
- },
- .max_rate = 1400000000,
- .mul = 1,
- .div = 2,
-};
-
-static struct clk tegra30_clk_twd = {
- .name = "twd",
- .ops = &tegra30_twd_ops,
- .hw = &tegra30_clk_twd_hw.hw,
- .parent = &tegra_clk_cclk_g,
- .parent_names = mux_twd,
- .parents = mux_twd_p,
- .num_parents = ARRAY_SIZE(mux_twd),
-};
-
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, \
- _max, _inputs, _flags) \
- static struct clk tegra_##_name; \
- static struct clk_tegra tegra_##_name##_hw = { \
- .hw = { \
- .clk = &tegra_##_name, \
- }, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- .reg = _reg, \
- .flags = _flags, \
- .max_rate = _max, \
- .u.periph = { \
- .clk_num = _clk_num, \
- }, \
- .reset = &tegra30_periph_clk_reset, \
- }; \
- static struct clk tegra_##_name = { \
- .name = #_name, \
- .ops = &tegra30_periph_clk_ops, \
- .hw = &tegra_##_name##_hw.hw, \
- .parent_names = _inputs, \
- .parents = _inputs##_p, \
- .num_parents = ARRAY_SIZE(_inputs), \
- };
-
-PERIPH_CLK(apbdma, "tegra-apbdma", NULL, 34, 0, 26000000, mux_clk_m, 0);
-PERIPH_CLK(rtc, "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB);
-PERIPH_CLK(kbc, "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB);
-PERIPH_CLK(timer, "timer", NULL, 5, 0, 26000000, mux_clk_m, 0);
-PERIPH_CLK(kfuse, "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0);
-PERIPH_CLK(fuse, "fuse-tegra", "fuse", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB);
-PERIPH_CLK(fuse_burn, "fuse-tegra", "fuse_burn", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB);
-PERIPH_CLK(apbif, "tegra30-ahub", "apbif", 107, 0, 26000000, mux_clk_m, 0);
-PERIPH_CLK(i2s0, "tegra30-i2s.0", NULL, 30, 0x1d8, 26000000, mux_pllaout0_audio0_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(i2s1, "tegra30-i2s.1", NULL, 11, 0x100, 26000000, mux_pllaout0_audio1_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(i2s2, "tegra30-i2s.2", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(i2s3, "tegra30-i2s.3", NULL, 101, 0x3bc, 26000000, mux_pllaout0_audio3_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(i2s4, "tegra30-i2s.4", NULL, 102, 0x3c0, 26000000, mux_pllaout0_audio4_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(spdif_out, "tegra30-spdif", "spdif_out", 10, 0x108, 100000000, mux_pllaout0_audio5_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(spdif_in, "tegra30-spdif", "spdif_in", 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(pwm, "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_clk32_clkm, MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(d_audio, "tegra30-ahub", "d_audio", 106, 0x3d0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
-PERIPH_CLK(dam0, "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
-PERIPH_CLK(dam1, "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
-PERIPH_CLK(dam2, "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
-PERIPH_CLK(hda, "tegra30-hda", "hda", 125, 0x428, 108000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(hda2codec_2x, "tegra30-hda", "hda2codec", 111, 0x3e4, 48000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(hda2hdmi, "tegra30-hda", "hda2hdmi", 128, 0, 48000000, mux_clk_m, 0);
-PERIPH_CLK(sbc1, "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(sbc2, "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(sbc3, "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(sbc4, "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(sbc5, "spi_tegra.4", NULL, 104, 0x3c8, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(sbc6, "spi_tegra.5", NULL, 105, 0x3cc, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(sata_oob, "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(sata, "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(sata_cold, "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, 0);
-PERIPH_CLK(ndflash, "tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(ndspeed, "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(vfir, "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(sdmmc1, "sdhci-tegra.0", NULL, 14, 0x150, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
-PERIPH_CLK(sdmmc2, "sdhci-tegra.1", NULL, 9, 0x154, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
-PERIPH_CLK(sdmmc3, "sdhci-tegra.2", NULL, 69, 0x1bc, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
-PERIPH_CLK(sdmmc4, "sdhci-tegra.3", NULL, 15, 0x164, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
-PERIPH_CLK(vcp, "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0);
-PERIPH_CLK(bsea, "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0);
-PERIPH_CLK(bsev, "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0);
-PERIPH_CLK(vde, "vde", NULL, 61, 0x1c8, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT);
-PERIPH_CLK(csite, "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* max rate ??? */
-PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
-PERIPH_CLK(owr, "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(nor, "nor", NULL, 42, 0x1d0, 127000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */
-PERIPH_CLK(mipi, "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); /* scales with voltage */
-PERIPH_CLK(i2c1, "tegra-i2c.0", "div-clk", 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB);
-PERIPH_CLK(i2c2, "tegra-i2c.1", "div-clk", 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB);
-PERIPH_CLK(i2c3, "tegra-i2c.2", "div-clk", 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB);
-PERIPH_CLK(i2c4, "tegra-i2c.3", "div-clk", 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB);
-PERIPH_CLK(i2c5, "tegra-i2c.4", "div-clk", 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB);
-PERIPH_CLK(uarta, "tegra-uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
-PERIPH_CLK(uartb, "tegra-uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
-PERIPH_CLK(uartc, "tegra-uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
-PERIPH_CLK(uartd, "tegra-uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
-PERIPH_CLK(uarte, "tegra-uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
-PERIPH_CLK(vi, "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
-PERIPH_CLK(3d, "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET);
-PERIPH_CLK(3d2, "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET);
-PERIPH_CLK(2d, "2d", NULL, 21, 0x15c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE);
-PERIPH_CLK(vi_sensor, "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET);
-PERIPH_CLK(epp, "epp", NULL, 19, 0x16c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
-PERIPH_CLK(mpe, "mpe", NULL, 60, 0x170, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
-PERIPH_CLK(host1x, "host1x", NULL, 28, 0x180, 260000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
-PERIPH_CLK(cve, "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
-PERIPH_CLK(tvo, "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
-PERIPH_CLK(dtv, "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, 0);
-PERIPH_CLK(hdmi, "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8 | DIV_U71);
-PERIPH_CLK(tvdac, "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
-PERIPH_CLK(disp1, "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8);
-PERIPH_CLK(disp2, "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8);
-PERIPH_CLK(usbd, "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
-PERIPH_CLK(usb2, "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
-PERIPH_CLK(usb3, "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
-PERIPH_CLK(dsia, "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0);
-PERIPH_CLK(csi, "tegra_camera", "csi", 52, 0, 102000000, mux_pllp_out3, 0);
-PERIPH_CLK(isp, "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0); /* same frequency as VI */
-PERIPH_CLK(csus, "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET);
-PERIPH_CLK(tsensor, "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71);
-PERIPH_CLK(actmon, "actmon", NULL, 119, 0x3e8, 216000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71);
-PERIPH_CLK(extern1, "extern1", NULL, 120, 0x3ec, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71);
-PERIPH_CLK(extern2, "extern2", NULL, 121, 0x3f0, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71);
-PERIPH_CLK(extern3, "extern3", NULL, 122, 0x3f4, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71);
-PERIPH_CLK(i2cslow, "i2cslow", NULL, 81, 0x3fc, 26000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
-PERIPH_CLK(pcie, "tegra-pcie", "pcie", 70, 0, 250000000, mux_clk_m, 0);
-PERIPH_CLK(afi, "tegra-pcie", "afi", 72, 0, 250000000, mux_clk_m, 0);
-PERIPH_CLK(se, "se", NULL, 127, 0x42c, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT);
-
-static struct clk tegra_dsib;
-static struct clk_tegra tegra_dsib_hw = {
- .hw = {
- .clk = &tegra_dsib,
- },
- .lookup = {
- .dev_id = "tegradc.1",
- .con_id = "dsib",
- },
- .reg = 0xd0,
- .flags = MUX | PLLD,
- .max_rate = 500000000,
- .u.periph = {
- .clk_num = 82,
- },
- .reset = &tegra30_periph_clk_reset,
-};
-static struct clk tegra_dsib = {
- .name = "dsib",
- .ops = &tegra30_dsib_clk_ops,
- .hw = &tegra_dsib_hw.hw,
- .parent_names = mux_plld_out0_plld2_out0,
- .parents = mux_plld_out0_plld2_out0_p,
- .num_parents = ARRAY_SIZE(mux_plld_out0_plld2_out0),
-};
-
-struct clk *tegra_list_clks[] = {
- &tegra_apbdma,
- &tegra_rtc,
- &tegra_kbc,
- &tegra_timer,
- &tegra_kfuse,
- &tegra_fuse,
- &tegra_fuse_burn,
- &tegra_apbif,
- &tegra_i2s0,
- &tegra_i2s1,
- &tegra_i2s2,
- &tegra_i2s3,
- &tegra_i2s4,
- &tegra_spdif_out,
- &tegra_spdif_in,
- &tegra_pwm,
- &tegra_d_audio,
- &tegra_dam0,
- &tegra_dam1,
- &tegra_dam2,
- &tegra_hda,
- &tegra_hda2codec_2x,
- &tegra_hda2hdmi,
- &tegra_sbc1,
- &tegra_sbc2,
- &tegra_sbc3,
- &tegra_sbc4,
- &tegra_sbc5,
- &tegra_sbc6,
- &tegra_sata_oob,
- &tegra_sata,
- &tegra_sata_cold,
- &tegra_ndflash,
- &tegra_ndspeed,
- &tegra_vfir,
- &tegra_sdmmc1,
- &tegra_sdmmc2,
- &tegra_sdmmc3,
- &tegra_sdmmc4,
- &tegra_vcp,
- &tegra_bsea,
- &tegra_bsev,
- &tegra_vde,
- &tegra_csite,
- &tegra_la,
- &tegra_owr,
- &tegra_nor,
- &tegra_mipi,
- &tegra_i2c1,
- &tegra_i2c2,
- &tegra_i2c3,
- &tegra_i2c4,
- &tegra_i2c5,
- &tegra_uarta,
- &tegra_uartb,
- &tegra_uartc,
- &tegra_uartd,
- &tegra_uarte,
- &tegra_vi,
- &tegra_3d,
- &tegra_3d2,
- &tegra_2d,
- &tegra_vi_sensor,
- &tegra_epp,
- &tegra_mpe,
- &tegra_host1x,
- &tegra_cve,
- &tegra_tvo,
- &tegra_dtv,
- &tegra_hdmi,
- &tegra_tvdac,
- &tegra_disp1,
- &tegra_disp2,
- &tegra_usbd,
- &tegra_usb2,
- &tegra_usb3,
- &tegra_dsia,
- &tegra_dsib,
- &tegra_csi,
- &tegra_isp,
- &tegra_csus,
- &tegra_tsensor,
- &tegra_actmon,
- &tegra_extern1,
- &tegra_extern2,
- &tegra_extern3,
- &tegra_i2cslow,
- &tegra_pcie,
- &tegra_afi,
- &tegra_se,
-};
-
-#define CLK_DUPLICATE(_name, _dev, _con) \
- { \
- .name = _name, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- }
-
-/* Some clocks may be used by different drivers depending on the board
- * configuration. List those here to register them twice in the clock lookup
- * table under two names.
- */
-struct clk_duplicate tegra_clk_duplicates[] = {
- CLK_DUPLICATE("uarta", "serial8250.0", NULL),
- CLK_DUPLICATE("uartb", "serial8250.1", NULL),
- CLK_DUPLICATE("uartc", "serial8250.2", NULL),
- CLK_DUPLICATE("uartd", "serial8250.3", NULL),
- CLK_DUPLICATE("uarte", "serial8250.4", NULL),
- CLK_DUPLICATE("usbd", "utmip-pad", NULL),
- CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
- CLK_DUPLICATE("usbd", "tegra-otg", NULL),
- CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
- CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
- CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
- CLK_DUPLICATE("bsev", "nvavp", "bsev"),
- CLK_DUPLICATE("vde", "tegra-aes", "vde"),
- CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
- CLK_DUPLICATE("bsea", "nvavp", "bsea"),
- CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
- CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
- CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
- CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
- CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
- CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
- CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
- CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
- CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
- CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
- CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
- CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
- CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
- CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
- CLK_DUPLICATE("twd", "smp_twd", NULL),
- CLK_DUPLICATE("vcp", "nvavp", "vcp"),
- CLK_DUPLICATE("i2s0", NULL, "i2s0"),
- CLK_DUPLICATE("i2s1", NULL, "i2s1"),
- CLK_DUPLICATE("i2s2", NULL, "i2s2"),
- CLK_DUPLICATE("i2s3", NULL, "i2s3"),
- CLK_DUPLICATE("i2s4", NULL, "i2s4"),
- CLK_DUPLICATE("dam0", NULL, "dam0"),
- CLK_DUPLICATE("dam1", NULL, "dam1"),
- CLK_DUPLICATE("dam2", NULL, "dam2"),
- CLK_DUPLICATE("spdif_in", NULL, "spdif_in"),
- CLK_DUPLICATE("pll_p_out3", "tegra-i2c.0", "fast-clk"),
- CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"),
- CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"),
- CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"),
- CLK_DUPLICATE("pll_p_out3", "tegra-i2c.4", "fast-clk"),
- CLK_DUPLICATE("pll_p", "tegradc.0", "parent"),
- CLK_DUPLICATE("pll_p", "tegradc.1", "parent"),
- CLK_DUPLICATE("pll_d2_out0", "hdmi", "parent"),
-};
-
-struct clk *tegra_ptr_clks[] = {
- &tegra_clk_32k,
- &tegra_clk_m,
- &tegra_clk_m_div2,
- &tegra_clk_m_div4,
- &tegra_pll_ref,
- &tegra_pll_m,
- &tegra_pll_m_out1,
- &tegra_pll_c,
- &tegra_pll_c_out1,
- &tegra_pll_p,
- &tegra_pll_p_out1,
- &tegra_pll_p_out2,
- &tegra_pll_p_out3,
- &tegra_pll_p_out4,
- &tegra_pll_a,
- &tegra_pll_a_out0,
- &tegra_pll_d,
- &tegra_pll_d_out0,
- &tegra_pll_d2,
- &tegra_pll_d2_out0,
- &tegra_pll_u,
- &tegra_pll_x,
- &tegra_pll_x_out0,
- &tegra_pll_e,
- &tegra_clk_cclk_g,
- &tegra_cml0,
- &tegra_cml1,
- &tegra_pciex,
- &tegra_clk_sclk,
- &tegra_hclk,
- &tegra_pclk,
- &tegra_clk_blink,
- &tegra30_clk_twd,
-};
-
-static void tegra30_init_one_clock(struct clk *c)
-{
- struct clk_tegra *clk = to_clk_tegra(c->hw);
- __clk_init(NULL, c);
- INIT_LIST_HEAD(&clk->shared_bus_list);
- if (!clk->lookup.dev_id && !clk->lookup.con_id)
- clk->lookup.con_id = c->name;
- clk->lookup.clk = c;
- clkdev_add(&clk->lookup);
- tegra_clk_add(c);
-}
-
-void __init tegra30_init_clocks(void)
-{
- int i;
- struct clk *c;
-
- for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
- tegra30_init_one_clock(tegra_ptr_clks[i]);
-
- for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
- tegra30_init_one_clock(tegra_list_clks[i]);
-
- for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
- c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
- if (!c) {
- pr_err("%s: Unknown duplicate clock %s\n", __func__,
- tegra_clk_duplicates[i].name);
- continue;
- }
-
- tegra_clk_duplicates[i].lookup.clk = c;
- clkdev_add(&tegra_clk_duplicates[i].lookup);
- }
-
- for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
- tegra30_init_one_clock(tegra_sync_source_list[i]);
- for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
- tegra30_init_one_clock(tegra_clk_audio_list[i]);
- for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
- tegra30_init_one_clock(tegra_clk_audio_2x_list[i]);
-
- for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
- tegra30_init_one_clock(tegra_clk_out_list[i]);
-
- tegra30_cpu_car_ops_init();
-}
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index 4ce77cdc31cc..a683d17b2ce4 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -31,16 +31,16 @@
#include <linux/dma-mapping.h>
#include <linux/platform_data/clk-u300.h>
#include <linux/platform_data/pinctrl-coh901.h>
+#include <linux/platform_data/dma-coh901318.h>
+#include <linux/irqchip/arm-vic.h>
#include <asm/types.h>
#include <asm/setup.h>
#include <asm/memory.h>
-#include <asm/hardware/vic.h>
#include <asm/mach/map.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/coh901318.h>
#include <mach/hardware.h>
#include <mach/syscon.h>
#include <mach/irqs.h>
@@ -49,7 +49,6 @@
#include "spi.h"
#include "i2c.h"
#include "u300-gpio.h"
-#include "dma_channels.h"
/*
* Static I/O mappings that are needed for booting the U300 platforms. The
@@ -327,1089 +326,6 @@ static struct resource dma_resource[] = {
}
};
-/* points out all dma slave channels.
- * Syntax is [A1, B1, A2, B2, .... ,-1,-1]
- * Select all channels from A to B, end of list is marked with -1,-1
- */
-static int dma_slave_channels[] = {
- U300_DMA_MSL_TX_0, U300_DMA_SPI_RX,
- U300_DMA_UART1_TX, U300_DMA_UART1_RX, -1, -1};
-
-/* points out all dma memcpy channels. */
-static int dma_memcpy_channels[] = {
- U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_8, -1, -1};
-
-/** register dma for memory access
- *
- * active 1 means dma intends to access memory
- * 0 means dma wont access memory
- */
-static void coh901318_access_memory_state(struct device *dev, bool active)
-{
-}
-
-#define flags_memcpy_config (COH901318_CX_CFG_CH_DISABLE | \
- COH901318_CX_CFG_RM_MEMORY_TO_MEMORY | \
- COH901318_CX_CFG_LCR_DISABLE | \
- COH901318_CX_CFG_TC_IRQ_ENABLE | \
- COH901318_CX_CFG_BE_IRQ_ENABLE)
-#define flags_memcpy_lli_chained (COH901318_CX_CTRL_TC_ENABLE | \
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \
- COH901318_CX_CTRL_MASTER_MODE_M1RW | \
- COH901318_CX_CTRL_TCP_DISABLE | \
- COH901318_CX_CTRL_TC_IRQ_DISABLE | \
- COH901318_CX_CTRL_HSP_DISABLE | \
- COH901318_CX_CTRL_HSS_DISABLE | \
- COH901318_CX_CTRL_DDMA_LEGACY | \
- COH901318_CX_CTRL_PRDD_SOURCE)
-#define flags_memcpy_lli (COH901318_CX_CTRL_TC_ENABLE | \
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \
- COH901318_CX_CTRL_MASTER_MODE_M1RW | \
- COH901318_CX_CTRL_TCP_DISABLE | \
- COH901318_CX_CTRL_TC_IRQ_DISABLE | \
- COH901318_CX_CTRL_HSP_DISABLE | \
- COH901318_CX_CTRL_HSS_DISABLE | \
- COH901318_CX_CTRL_DDMA_LEGACY | \
- COH901318_CX_CTRL_PRDD_SOURCE)
-#define flags_memcpy_lli_last (COH901318_CX_CTRL_TC_ENABLE | \
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \
- COH901318_CX_CTRL_MASTER_MODE_M1RW | \
- COH901318_CX_CTRL_TCP_DISABLE | \
- COH901318_CX_CTRL_TC_IRQ_ENABLE | \
- COH901318_CX_CTRL_HSP_DISABLE | \
- COH901318_CX_CTRL_HSS_DISABLE | \
- COH901318_CX_CTRL_DDMA_LEGACY | \
- COH901318_CX_CTRL_PRDD_SOURCE)
-
-const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
- {
- .number = U300_DMA_MSL_TX_0,
- .name = "MSL TX 0",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 0 * 0x40 + 0x20,
- },
- {
- .number = U300_DMA_MSL_TX_1,
- .name = "MSL TX 1",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 1 * 0x40 + 0x20,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- },
- {
- .number = U300_DMA_MSL_TX_2,
- .name = "MSL TX 2",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 2 * 0x40 + 0x20,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .desc_nbr_max = 10,
- },
- {
- .number = U300_DMA_MSL_TX_3,
- .name = "MSL TX 3",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 3 * 0x40 + 0x20,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- },
- {
- .number = U300_DMA_MSL_TX_4,
- .name = "MSL TX 4",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 4 * 0x40 + 0x20,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- },
- {
- .number = U300_DMA_MSL_TX_5,
- .name = "MSL TX 5",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 5 * 0x40 + 0x20,
- },
- {
- .number = U300_DMA_MSL_TX_6,
- .name = "MSL TX 6",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 6 * 0x40 + 0x20,
- },
- {
- .number = U300_DMA_MSL_RX_0,
- .name = "MSL RX 0",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 0 * 0x40 + 0x220,
- },
- {
- .number = U300_DMA_MSL_RX_1,
- .name = "MSL RX 1",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 1 * 0x40 + 0x220,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli = 0,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- },
- {
- .number = U300_DMA_MSL_RX_2,
- .name = "MSL RX 2",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 2 * 0x40 + 0x220,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- },
- {
- .number = U300_DMA_MSL_RX_3,
- .name = "MSL RX 3",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 3 * 0x40 + 0x220,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- },
- {
- .number = U300_DMA_MSL_RX_4,
- .name = "MSL RX 4",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 4 * 0x40 + 0x220,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- },
- {
- .number = U300_DMA_MSL_RX_5,
- .name = "MSL RX 5",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 5 * 0x40 + 0x220,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
- COH901318_CX_CTRL_PRDD_DEST,
- },
- {
- .number = U300_DMA_MSL_RX_6,
- .name = "MSL RX 6",
- .priority_high = 0,
- .dev_addr = U300_MSL_BASE + 6 * 0x40 + 0x220,
- },
- /*
- * Don't set up device address, burst count or size of src
- * or dst bus for this peripheral - handled by PrimeCell
- * DMA extension.
- */
- {
- .number = U300_DMA_MMCSD_RX_TX,
- .name = "MMCSD RX TX",
- .priority_high = 0,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
-
- },
- {
- .number = U300_DMA_MSPRO_TX,
- .name = "MSPRO TX",
- .priority_high = 0,
- },
- {
- .number = U300_DMA_MSPRO_RX,
- .name = "MSPRO RX",
- .priority_high = 0,
- },
- /*
- * Don't set up device address, burst count or size of src
- * or dst bus for this peripheral - handled by PrimeCell
- * DMA extension.
- */
- {
- .number = U300_DMA_UART0_TX,
- .name = "UART0 TX",
- .priority_high = 0,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- },
- {
- .number = U300_DMA_UART0_RX,
- .name = "UART0 RX",
- .priority_high = 0,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- },
- {
- .number = U300_DMA_APEX_TX,
- .name = "APEX TX",
- .priority_high = 0,
- },
- {
- .number = U300_DMA_APEX_RX,
- .name = "APEX RX",
- .priority_high = 0,
- },
- {
- .number = U300_DMA_PCM_I2S0_TX,
- .name = "PCM I2S0 TX",
- .priority_high = 1,
- .dev_addr = U300_PCM_I2S0_BASE + 0x14,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- },
- {
- .number = U300_DMA_PCM_I2S0_RX,
- .name = "PCM I2S0 RX",
- .priority_high = 1,
- .dev_addr = U300_PCM_I2S0_BASE + 0x10,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_DEST,
- },
- {
- .number = U300_DMA_PCM_I2S1_TX,
- .name = "PCM I2S1 TX",
- .priority_high = 1,
- .dev_addr = U300_PCM_I2S1_BASE + 0x14,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_SOURCE,
- },
- {
- .number = U300_DMA_PCM_I2S1_RX,
- .name = "PCM I2S1 RX",
- .priority_high = 1,
- .dev_addr = U300_PCM_I2S1_BASE + 0x10,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_DEST,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY |
- COH901318_CX_CTRL_PRDD_DEST,
- },
- {
- .number = U300_DMA_XGAM_CDI,
- .name = "XGAM CDI",
- .priority_high = 0,
- },
- {
- .number = U300_DMA_XGAM_PDI,
- .name = "XGAM PDI",
- .priority_high = 0,
- },
- /*
- * Don't set up device address, burst count or size of src
- * or dst bus for this peripheral - handled by PrimeCell
- * DMA extension.
- */
- {
- .number = U300_DMA_SPI_TX,
- .name = "SPI TX",
- .priority_high = 0,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- },
- {
- .number = U300_DMA_SPI_RX,
- .name = "SPI RX",
- .priority_high = 0,
- .param.config = COH901318_CX_CFG_CH_DISABLE |
- COH901318_CX_CFG_LCR_DISABLE |
- COH901318_CX_CFG_TC_IRQ_ENABLE |
- COH901318_CX_CFG_BE_IRQ_ENABLE,
- .param.ctrl_lli_chained = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_DISABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- .param.ctrl_lli = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
- .param.ctrl_lli_last = 0 |
- COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_MASTER_MODE_M1RW |
- COH901318_CX_CTRL_TCP_DISABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
- COH901318_CX_CTRL_HSP_ENABLE |
- COH901318_CX_CTRL_HSS_DISABLE |
- COH901318_CX_CTRL_DDMA_LEGACY,
-
- },
- {
- .number = U300_DMA_GENERAL_PURPOSE_0,
- .name = "GENERAL 00",
- .priority_high = 0,
-
- .param.config = flags_memcpy_config,
- .param.ctrl_lli_chained = flags_memcpy_lli_chained,
- .param.ctrl_lli = flags_memcpy_lli,
- .param.ctrl_lli_last = flags_memcpy_lli_last,
- },
- {
- .number = U300_DMA_GENERAL_PURPOSE_1,
- .name = "GENERAL 01",
- .priority_high = 0,
-
- .param.config = flags_memcpy_config,
- .param.ctrl_lli_chained = flags_memcpy_lli_chained,
- .param.ctrl_lli = flags_memcpy_lli,
- .param.ctrl_lli_last = flags_memcpy_lli_last,
- },
- {
- .number = U300_DMA_GENERAL_PURPOSE_2,
- .name = "GENERAL 02",
- .priority_high = 0,
-
- .param.config = flags_memcpy_config,
- .param.ctrl_lli_chained = flags_memcpy_lli_chained,
- .param.ctrl_lli = flags_memcpy_lli,
- .param.ctrl_lli_last = flags_memcpy_lli_last,
- },
- {
- .number = U300_DMA_GENERAL_PURPOSE_3,
- .name = "GENERAL 03",
- .priority_high = 0,
-
- .param.config = flags_memcpy_config,
- .param.ctrl_lli_chained = flags_memcpy_lli_chained,
- .param.ctrl_lli = flags_memcpy_lli,
- .param.ctrl_lli_last = flags_memcpy_lli_last,
- },
- {
- .number = U300_DMA_GENERAL_PURPOSE_4,
- .name = "GENERAL 04",
- .priority_high = 0,
-
- .param.config = flags_memcpy_config,
- .param.ctrl_lli_chained = flags_memcpy_lli_chained,
- .param.ctrl_lli = flags_memcpy_lli,
- .param.ctrl_lli_last = flags_memcpy_lli_last,
- },
- {
- .number = U300_DMA_GENERAL_PURPOSE_5,
- .name = "GENERAL 05",
- .priority_high = 0,
-
- .param.config = flags_memcpy_config,
- .param.ctrl_lli_chained = flags_memcpy_lli_chained,
- .param.ctrl_lli = flags_memcpy_lli,
- .param.ctrl_lli_last = flags_memcpy_lli_last,
- },
- {
- .number = U300_DMA_GENERAL_PURPOSE_6,
- .name = "GENERAL 06",
- .priority_high = 0,
-
- .param.config = flags_memcpy_config,
- .param.ctrl_lli_chained = flags_memcpy_lli_chained,
- .param.ctrl_lli = flags_memcpy_lli,
- .param.ctrl_lli_last = flags_memcpy_lli_last,
- },
- {
- .number = U300_DMA_GENERAL_PURPOSE_7,
- .name = "GENERAL 07",
- .priority_high = 0,
-
- .param.config = flags_memcpy_config,
- .param.ctrl_lli_chained = flags_memcpy_lli_chained,
- .param.ctrl_lli = flags_memcpy_lli,
- .param.ctrl_lli_last = flags_memcpy_lli_last,
- },
- {
- .number = U300_DMA_GENERAL_PURPOSE_8,
- .name = "GENERAL 08",
- .priority_high = 0,
-
- .param.config = flags_memcpy_config,
- .param.ctrl_lli_chained = flags_memcpy_lli_chained,
- .param.ctrl_lli = flags_memcpy_lli,
- .param.ctrl_lli_last = flags_memcpy_lli_last,
- },
- {
- .number = U300_DMA_UART1_TX,
- .name = "UART1 TX",
- .priority_high = 0,
- },
- {
- .number = U300_DMA_UART1_RX,
- .name = "UART1 RX",
- .priority_high = 0,
- }
-};
-
-
-static struct coh901318_platform coh901318_platform = {
- .chans_slave = dma_slave_channels,
- .chans_memcpy = dma_memcpy_channels,
- .access_memory_state = coh901318_access_memory_state,
- .chan_conf = chan_config,
- .max_channels = U300_DMA_CHANNELS,
-};
static struct resource pinctrl_resources[] = {
{
@@ -1521,7 +437,6 @@ static struct platform_device dma_device = {
.resource = dma_resource,
.num_resources = ARRAY_SIZE(dma_resource),
.dev = {
- .platform_data = &coh901318_platform,
.coherent_dma_mask = ~0,
},
};
@@ -1779,8 +694,7 @@ MACHINE_START(U300, "Ericsson AB U335 S335/B335 Prototype Board")
.map_io = u300_map_io,
.nr_irqs = 0,
.init_irq = u300_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &u300_timer,
+ .init_time = u300_timer_init,
.init_machine = u300_init_machine,
.restart = u300_restart,
MACHINE_END
diff --git a/arch/arm/mach-u300/dma_channels.h b/arch/arm/mach-u300/dma_channels.h
deleted file mode 100644
index 4e8a88fbca49..000000000000
--- a/arch/arm/mach-u300/dma_channels.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/include/mach/dma_channels.h
- *
- *
- * Copyright (C) 2007-2012 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Map file for the U300 dma driver.
- * Author: Per Friden <per.friden@stericsson.com>
- */
-
-#ifndef DMA_CHANNELS_H
-#define DMA_CHANNELS_H
-
-#define U300_DMA_MSL_TX_0 0
-#define U300_DMA_MSL_TX_1 1
-#define U300_DMA_MSL_TX_2 2
-#define U300_DMA_MSL_TX_3 3
-#define U300_DMA_MSL_TX_4 4
-#define U300_DMA_MSL_TX_5 5
-#define U300_DMA_MSL_TX_6 6
-#define U300_DMA_MSL_RX_0 7
-#define U300_DMA_MSL_RX_1 8
-#define U300_DMA_MSL_RX_2 9
-#define U300_DMA_MSL_RX_3 10
-#define U300_DMA_MSL_RX_4 11
-#define U300_DMA_MSL_RX_5 12
-#define U300_DMA_MSL_RX_6 13
-#define U300_DMA_MMCSD_RX_TX 14
-#define U300_DMA_MSPRO_TX 15
-#define U300_DMA_MSPRO_RX 16
-#define U300_DMA_UART0_TX 17
-#define U300_DMA_UART0_RX 18
-#define U300_DMA_APEX_TX 19
-#define U300_DMA_APEX_RX 20
-#define U300_DMA_PCM_I2S0_TX 21
-#define U300_DMA_PCM_I2S0_RX 22
-#define U300_DMA_PCM_I2S1_TX 23
-#define U300_DMA_PCM_I2S1_RX 24
-#define U300_DMA_XGAM_CDI 25
-#define U300_DMA_XGAM_PDI 26
-#define U300_DMA_SPI_TX 27
-#define U300_DMA_SPI_RX 28
-#define U300_DMA_GENERAL_PURPOSE_0 29
-#define U300_DMA_GENERAL_PURPOSE_1 30
-#define U300_DMA_GENERAL_PURPOSE_2 31
-#define U300_DMA_GENERAL_PURPOSE_3 32
-#define U300_DMA_GENERAL_PURPOSE_4 33
-#define U300_DMA_GENERAL_PURPOSE_5 34
-#define U300_DMA_GENERAL_PURPOSE_6 35
-#define U300_DMA_GENERAL_PURPOSE_7 36
-#define U300_DMA_GENERAL_PURPOSE_8 37
-#define U300_DMA_UART1_TX 38
-#define U300_DMA_UART1_RX 39
-
-#define U300_DMA_DEVICE_CHANNELS 32
-#define U300_DMA_CHANNELS 40
-
-
-#endif /* DMA_CHANNELS_H */
diff --git a/arch/arm/mach-u300/include/mach/coh901318.h b/arch/arm/mach-u300/include/mach/coh901318.h
deleted file mode 100644
index 7c3b2b2d25b6..000000000000
--- a/arch/arm/mach-u300/include/mach/coh901318.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- *
- * include/linux/coh901318.h
- *
- *
- * Copyright (C) 2007-2009 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * DMA driver for COH 901 318
- * Author: Per Friden <per.friden@stericsson.com>
- */
-
-#ifndef COH901318_H
-#define COH901318_H
-
-#include <linux/device.h>
-#include <linux/dmaengine.h>
-
-#define MAX_DMA_PACKET_SIZE_SHIFT 11
-#define MAX_DMA_PACKET_SIZE (1 << MAX_DMA_PACKET_SIZE_SHIFT)
-
-/**
- * struct coh901318_lli - linked list item for DMAC
- * @control: control settings for DMAC
- * @src_addr: transfer source address
- * @dst_addr: transfer destination address
- * @link_addr: physical address to next lli
- * @virt_link_addr: virtual address of next lli (only used by pool_free)
- * @phy_this: physical address of current lli (only used by pool_free)
- */
-struct coh901318_lli {
- u32 control;
- dma_addr_t src_addr;
- dma_addr_t dst_addr;
- dma_addr_t link_addr;
-
- void *virt_link_addr;
- dma_addr_t phy_this;
-};
-/**
- * struct coh901318_params - parameters for DMAC configuration
- * @config: DMA config register
- * @ctrl_lli_last: DMA control register for the last lli in the list
- * @ctrl_lli: DMA control register for an lli
- * @ctrl_lli_chained: DMA control register for a chained lli
- */
-struct coh901318_params {
- u32 config;
- u32 ctrl_lli_last;
- u32 ctrl_lli;
- u32 ctrl_lli_chained;
-};
-/**
- * struct coh_dma_channel - dma channel base
- * @name: ascii name of dma channel
- * @number: channel id number
- * @desc_nbr_max: number of preallocated descriptors
- * @priority_high: prio of channel, 0 low otherwise high.
- * @param: configuration parameters
- * @dev_addr: physical address of periphal connected to channel
- */
-struct coh_dma_channel {
- const char name[32];
- const int number;
- const int desc_nbr_max;
- const int priority_high;
- const struct coh901318_params param;
- const dma_addr_t dev_addr;
-};
-
-/**
- * dma_access_memory_state_t - register dma for memory access
- *
- * @dev: The dma device
- * @active: 1 means dma intends to access memory
- * 0 means dma wont access memory
- */
-typedef void (*dma_access_memory_state_t)(struct device *dev,
- bool active);
-
-/**
- * struct powersave - DMA power save structure
- * @lock: lock protecting data in this struct
- * @started_channels: bit mask indicating active dma channels
- */
-struct powersave {
- spinlock_t lock;
- u64 started_channels;
-};
-/**
- * struct coh901318_platform - platform arch structure
- * @chans_slave: specifying dma slave channels
- * @chans_memcpy: specifying dma memcpy channels
- * @access_memory_state: requesting DMA memory access (on / off)
- * @chan_conf: dma channel configurations
- * @max_channels: max number of dma chanenls
- */
-struct coh901318_platform {
- const int *chans_slave;
- const int *chans_memcpy;
- const dma_access_memory_state_t access_memory_state;
- const struct coh_dma_channel *chan_conf;
- const int max_channels;
-};
-
-#ifdef CONFIG_COH901318
-/**
- * coh901318_filter_id() - DMA channel filter function
- * @chan: dma channel handle
- * @chan_id: id of dma channel to be filter out
- *
- * In dma_request_channel() it specifies what channel id to be requested
- */
-bool coh901318_filter_id(struct dma_chan *chan, void *chan_id);
-#else
-static inline bool coh901318_filter_id(struct dma_chan *chan, void *chan_id)
-{
- return false;
-}
-#endif
-
-/*
- * DMA Controller - this access the static mappings of the coh901318 dma.
- *
- */
-
-#define COH901318_MOD32_MASK (0x1F)
-#define COH901318_WORD_MASK (0xFFFFFFFF)
-/* INT_STATUS - Interrupt Status Registers 32bit (R/-) */
-#define COH901318_INT_STATUS1 (0x0000)
-#define COH901318_INT_STATUS2 (0x0004)
-/* TC_INT_STATUS - Terminal Count Interrupt Status Registers 32bit (R/-) */
-#define COH901318_TC_INT_STATUS1 (0x0008)
-#define COH901318_TC_INT_STATUS2 (0x000C)
-/* TC_INT_CLEAR - Terminal Count Interrupt Clear Registers 32bit (-/W) */
-#define COH901318_TC_INT_CLEAR1 (0x0010)
-#define COH901318_TC_INT_CLEAR2 (0x0014)
-/* RAW_TC_INT_STATUS - Raw Term Count Interrupt Status Registers 32bit (R/-) */
-#define COH901318_RAW_TC_INT_STATUS1 (0x0018)
-#define COH901318_RAW_TC_INT_STATUS2 (0x001C)
-/* BE_INT_STATUS - Bus Error Interrupt Status Registers 32bit (R/-) */
-#define COH901318_BE_INT_STATUS1 (0x0020)
-#define COH901318_BE_INT_STATUS2 (0x0024)
-/* BE_INT_CLEAR - Bus Error Interrupt Clear Registers 32bit (-/W) */
-#define COH901318_BE_INT_CLEAR1 (0x0028)
-#define COH901318_BE_INT_CLEAR2 (0x002C)
-/* RAW_BE_INT_STATUS - Raw Term Count Interrupt Status Registers 32bit (R/-) */
-#define COH901318_RAW_BE_INT_STATUS1 (0x0030)
-#define COH901318_RAW_BE_INT_STATUS2 (0x0034)
-
-/*
- * CX_CFG - Channel Configuration Registers 32bit (R/W)
- */
-#define COH901318_CX_CFG (0x0100)
-#define COH901318_CX_CFG_SPACING (0x04)
-/* Channel enable activates tha dma job */
-#define COH901318_CX_CFG_CH_ENABLE (0x00000001)
-#define COH901318_CX_CFG_CH_DISABLE (0x00000000)
-/* Request Mode */
-#define COH901318_CX_CFG_RM_MASK (0x00000006)
-#define COH901318_CX_CFG_RM_MEMORY_TO_MEMORY (0x0 << 1)
-#define COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY (0x1 << 1)
-#define COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY (0x1 << 1)
-#define COH901318_CX_CFG_RM_PRIMARY_TO_SECONDARY (0x3 << 1)
-#define COH901318_CX_CFG_RM_SECONDARY_TO_PRIMARY (0x3 << 1)
-/* Linked channel request field. RM must == 11 */
-#define COH901318_CX_CFG_LCRF_SHIFT 3
-#define COH901318_CX_CFG_LCRF_MASK (0x000001F8)
-#define COH901318_CX_CFG_LCR_DISABLE (0x00000000)
-/* Terminal Counter Interrupt Request Mask */
-#define COH901318_CX_CFG_TC_IRQ_ENABLE (0x00000200)
-#define COH901318_CX_CFG_TC_IRQ_DISABLE (0x00000000)
-/* Bus Error interrupt Mask */
-#define COH901318_CX_CFG_BE_IRQ_ENABLE (0x00000400)
-#define COH901318_CX_CFG_BE_IRQ_DISABLE (0x00000000)
-
-/*
- * CX_STAT - Channel Status Registers 32bit (R/-)
- */
-#define COH901318_CX_STAT (0x0200)
-#define COH901318_CX_STAT_SPACING (0x04)
-#define COH901318_CX_STAT_RBE_IRQ_IND (0x00000008)
-#define COH901318_CX_STAT_RTC_IRQ_IND (0x00000004)
-#define COH901318_CX_STAT_ACTIVE (0x00000002)
-#define COH901318_CX_STAT_ENABLED (0x00000001)
-
-/*
- * CX_CTRL - Channel Control Registers 32bit (R/W)
- */
-#define COH901318_CX_CTRL (0x0400)
-#define COH901318_CX_CTRL_SPACING (0x10)
-/* Transfer Count Enable */
-#define COH901318_CX_CTRL_TC_ENABLE (0x00001000)
-#define COH901318_CX_CTRL_TC_DISABLE (0x00000000)
-/* Transfer Count Value 0 - 4095 */
-#define COH901318_CX_CTRL_TC_VALUE_MASK (0x00000FFF)
-/* Burst count */
-#define COH901318_CX_CTRL_BURST_COUNT_MASK (0x0000E000)
-#define COH901318_CX_CTRL_BURST_COUNT_64_BYTES (0x7 << 13)
-#define COH901318_CX_CTRL_BURST_COUNT_48_BYTES (0x6 << 13)
-#define COH901318_CX_CTRL_BURST_COUNT_32_BYTES (0x5 << 13)
-#define COH901318_CX_CTRL_BURST_COUNT_16_BYTES (0x4 << 13)
-#define COH901318_CX_CTRL_BURST_COUNT_8_BYTES (0x3 << 13)
-#define COH901318_CX_CTRL_BURST_COUNT_4_BYTES (0x2 << 13)
-#define COH901318_CX_CTRL_BURST_COUNT_2_BYTES (0x1 << 13)
-#define COH901318_CX_CTRL_BURST_COUNT_1_BYTE (0x0 << 13)
-/* Source bus size */
-#define COH901318_CX_CTRL_SRC_BUS_SIZE_MASK (0x00030000)
-#define COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS (0x2 << 16)
-#define COH901318_CX_CTRL_SRC_BUS_SIZE_16_BITS (0x1 << 16)
-#define COH901318_CX_CTRL_SRC_BUS_SIZE_8_BITS (0x0 << 16)
-/* Source address increment */
-#define COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE (0x00040000)
-#define COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE (0x00000000)
-/* Destination Bus Size */
-#define COH901318_CX_CTRL_DST_BUS_SIZE_MASK (0x00180000)
-#define COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS (0x2 << 19)
-#define COH901318_CX_CTRL_DST_BUS_SIZE_16_BITS (0x1 << 19)
-#define COH901318_CX_CTRL_DST_BUS_SIZE_8_BITS (0x0 << 19)
-/* Destination address increment */
-#define COH901318_CX_CTRL_DST_ADDR_INC_ENABLE (0x00200000)
-#define COH901318_CX_CTRL_DST_ADDR_INC_DISABLE (0x00000000)
-/* Master Mode (Master2 is only connected to MSL) */
-#define COH901318_CX_CTRL_MASTER_MODE_MASK (0x00C00000)
-#define COH901318_CX_CTRL_MASTER_MODE_M2R_M1W (0x3 << 22)
-#define COH901318_CX_CTRL_MASTER_MODE_M1R_M2W (0x2 << 22)
-#define COH901318_CX_CTRL_MASTER_MODE_M2RW (0x1 << 22)
-#define COH901318_CX_CTRL_MASTER_MODE_M1RW (0x0 << 22)
-/* Terminal Count flag to PER enable */
-#define COH901318_CX_CTRL_TCP_ENABLE (0x01000000)
-#define COH901318_CX_CTRL_TCP_DISABLE (0x00000000)
-/* Terminal Count flags to CPU enable */
-#define COH901318_CX_CTRL_TC_IRQ_ENABLE (0x02000000)
-#define COH901318_CX_CTRL_TC_IRQ_DISABLE (0x00000000)
-/* Hand shake to peripheral */
-#define COH901318_CX_CTRL_HSP_ENABLE (0x04000000)
-#define COH901318_CX_CTRL_HSP_DISABLE (0x00000000)
-#define COH901318_CX_CTRL_HSS_ENABLE (0x08000000)
-#define COH901318_CX_CTRL_HSS_DISABLE (0x00000000)
-/* DMA mode */
-#define COH901318_CX_CTRL_DDMA_MASK (0x30000000)
-#define COH901318_CX_CTRL_DDMA_LEGACY (0x0 << 28)
-#define COH901318_CX_CTRL_DDMA_DEMAND_DMA1 (0x1 << 28)
-#define COH901318_CX_CTRL_DDMA_DEMAND_DMA2 (0x2 << 28)
-/* Primary Request Data Destination */
-#define COH901318_CX_CTRL_PRDD_MASK (0x40000000)
-#define COH901318_CX_CTRL_PRDD_DEST (0x1 << 30)
-#define COH901318_CX_CTRL_PRDD_SOURCE (0x0 << 30)
-
-/*
- * CX_SRC_ADDR - Channel Source Address Registers 32bit (R/W)
- */
-#define COH901318_CX_SRC_ADDR (0x0404)
-#define COH901318_CX_SRC_ADDR_SPACING (0x10)
-
-/*
- * CX_DST_ADDR - Channel Destination Address Registers 32bit R/W
- */
-#define COH901318_CX_DST_ADDR (0x0408)
-#define COH901318_CX_DST_ADDR_SPACING (0x10)
-
-/*
- * CX_LNK_ADDR - Channel Link Address Registers 32bit (R/W)
- */
-#define COH901318_CX_LNK_ADDR (0x040C)
-#define COH901318_CX_LNK_ADDR_SPACING (0x10)
-#define COH901318_CX_LNK_LINK_IMMEDIATE (0x00000001)
-#endif /* COH901318_H */
diff --git a/arch/arm/mach-u300/include/mach/uncompress.h b/arch/arm/mach-u300/include/mach/uncompress.h
index 29acb718acf7..783e7e60101b 100644
--- a/arch/arm/mach-u300/include/mach/uncompress.h
+++ b/arch/arm/mach-u300/include/mach/uncompress.h
@@ -43,4 +43,3 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c
index 02e6659286d5..910698293d64 100644
--- a/arch/arm/mach-u300/spi.c
+++ b/arch/arm/mach-u300/spi.c
@@ -10,9 +10,8 @@
#include <linux/amba/bus.h>
#include <linux/spi/spi.h>
#include <linux/amba/pl022.h>
+#include <linux/platform_data/dma-coh901318.h>
#include <linux/err.h>
-#include <mach/coh901318.h>
-#include "dma_channels.h"
/*
* The following is for the actual devices on the SSP/SPI bus
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
index 1da10e20e996..d9e73209c9b8 100644
--- a/arch/arm/mach-u300/timer.c
+++ b/arch/arm/mach-u300/timer.c
@@ -349,7 +349,7 @@ static u32 notrace u300_read_sched_clock(void)
/*
* This sets up the system timers, clock source and clock event.
*/
-static void __init u300_timer_init(void)
+void __init u300_timer_init(void)
{
struct clk *clk;
unsigned long rate;
@@ -413,11 +413,3 @@ static void __init u300_timer_init(void)
* used by hrtimers!
*/
}
-
-/*
- * Very simple system timer that only register the clock event and
- * clock source.
- */
-struct sys_timer u300_timer = {
- .init = u300_timer_init,
-};
diff --git a/arch/arm/mach-u300/timer.h b/arch/arm/mach-u300/timer.h
index b5e9791762e0..d34287bc34f5 100644
--- a/arch/arm/mach-u300/timer.h
+++ b/arch/arm/mach-u300/timer.h
@@ -1 +1 @@
-extern struct sys_timer u300_timer;
+extern void u300_timer_init(void);
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 5dea90636d94..3e5bbd0e5b23 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -11,6 +11,7 @@ config UX500_SOC_COMMON
select COMMON_CLK
select PINCTRL
select PINCTRL_NOMADIK
+ select PINCTRL_ABX500
select PL310_ERRATA_753970 if CACHE_PL310
config UX500_SOC_DB8500
@@ -18,6 +19,11 @@ config UX500_SOC_DB8500
select CPU_FREQ_TABLE if CPU_FREQ
select MFD_DB8500_PRCMU
select PINCTRL_DB8500
+ select PINCTRL_DB8540
+ select PINCTRL_AB8500
+ select PINCTRL_AB8505
+ select PINCTRL_AB9540
+ select PINCTRL_AB8540
select REGULATOR
select REGULATOR_DB8500_PRCMU
diff --git a/arch/arm/mach-ux500/board-mop500-uib.c b/arch/arm/mach-ux500/board-mop500-uib.c
index 1f47d962e3a1..7037d3687e9f 100644
--- a/arch/arm/mach-ux500/board-mop500-uib.c
+++ b/arch/arm/mach-ux500/board-mop500-uib.c
@@ -13,6 +13,7 @@
#include <mach/hardware.h>
#include "board-mop500.h"
+#include "id.h"
enum mop500_uib {
STUIB,
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index d453522edb0d..3868aa4ff15e 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -40,7 +40,6 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <mach/setup.h>
@@ -90,26 +89,8 @@ static struct platform_device snowball_gpio_en_3v3_regulator_dev = {
},
};
-static struct ab8500_gpio_platform_data ab8500_gpio_pdata = {
+static struct abx500_gpio_platform_data ab8500_gpio_pdata = {
.gpio_base = MOP500_AB8500_PIN_GPIO(1),
- .irq_base = MOP500_AB8500_VIR_GPIO_IRQ_BASE,
- /* config_reg is the initial configuration of ab8500 pins.
- * The pins can be configured as GPIO or alt functions based
- * on value present in GpioSel1 to GpioSel6 and AlternatFunction
- * register. This is the array of 7 configuration settings.
- * One has to compile time decide these settings. Below is the
- * explanation of these setting
- * GpioSel1 = 0x00 => Pins GPIO1 to GPIO8 are not used as GPIO
- * GpioSel2 = 0x1E => Pins GPIO10 to GPIO13 are configured as GPIO
- * GpioSel3 = 0x80 => Pin GPIO24 is configured as GPIO
- * GpioSel4 = 0x01 => Pin GPIo25 is configured as GPIO
- * GpioSel5 = 0x7A => Pins GPIO34, GPIO36 to GPIO39 are conf as GPIO
- * GpioSel6 = 0x00 => Pins GPIO41 & GPIo42 are not configured as GPIO
- * AlternaFunction = 0x00 => If Pins GPIO10 to 13 are not configured
- * as GPIO then this register selectes the alternate fucntions
- */
- .config_reg = {0x00, 0x1E, 0x80, 0x01,
- 0x7A, 0x00, 0x00},
};
/* ab8500-codec */
@@ -215,7 +196,7 @@ static struct platform_device snowball_sbnet_dev = {
},
};
-static struct ab8500_platform_data ab8500_platdata = {
+struct ab8500_platform_data ab8500_platdata = {
.irq_base = MOP500_AB8500_IRQ_BASE,
.regulator_reg_init = ab8500_regulator_reg_init,
.num_regulator_reg_init = ARRAY_SIZE(ab8500_regulator_reg_init),
@@ -651,6 +632,7 @@ static void __init mop500_init_machine(void)
int i2c0_devs;
int i;
+ platform_device_register(&db8500_prcmu_device);
mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
mop500_pinmaps_init();
@@ -685,6 +667,7 @@ static void __init snowball_init_machine(void)
struct device *parent = NULL;
int i;
+ platform_device_register(&db8500_prcmu_device);
snowball_pinmaps_init();
parent = u8500_init_devices(&ab8500_platdata);
@@ -710,6 +693,7 @@ static void __init hrefv60_init_machine(void)
int i2c0_devs;
int i;
+ platform_device_register(&db8500_prcmu_device);
/*
* The HREFv60 board removed a GPIO expander and routed
* all these GPIO pins to the internal GPIO controller
@@ -751,8 +735,7 @@ MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
.map_io = u8500_map_io,
.init_irq = ux500_init_irq,
/* we re-use nomadik timer here */
- .timer = &ux500_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = ux500_timer_init,
.init_machine = mop500_init_machine,
.init_late = ux500_init_late,
MACHINE_END
@@ -761,8 +744,7 @@ MACHINE_START(U8520, "ST-Ericsson U8520 Platform HREFP520")
.atag_offset = 0x100,
.map_io = u8500_map_io,
.init_irq = ux500_init_irq,
- .timer = &ux500_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = ux500_timer_init,
.init_machine = mop500_init_machine,
.init_late = ux500_init_late,
MACHINE_END
@@ -772,8 +754,7 @@ MACHINE_START(HREFV60, "ST-Ericsson U8500 Platform HREFv60+")
.smp = smp_ops(ux500_smp_ops),
.map_io = u8500_map_io,
.init_irq = ux500_init_irq,
- .timer = &ux500_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = ux500_timer_init,
.init_machine = hrefv60_init_machine,
.init_late = ux500_init_late,
MACHINE_END
@@ -784,8 +765,7 @@ MACHINE_START(SNOWBALL, "Calao Systems Snowball platform")
.map_io = u8500_map_io,
.init_irq = ux500_init_irq,
/* we re-use nomadik timer here */
- .timer = &ux500_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = ux500_timer_init,
.init_machine = snowball_init_machine,
.init_late = NULL,
MACHINE_END
diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index 75d5b512a3d5..1c1609da76ce 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -10,7 +10,8 @@
#include <asm/cacheflush.h>
#include <asm/hardware/cache-l2x0.h>
#include <mach/hardware.h>
-#include <mach/id.h>
+
+#include "id.h"
static void __iomem *l2x0_base;
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 5b286e06474c..19235cf7bbe3 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -27,7 +27,6 @@
#include <asm/pmu.h>
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <mach/setup.h>
@@ -37,7 +36,9 @@
#include "devices-db8500.h"
#include "ste-dma40-db8500.h"
+
#include "board-mop500.h"
+#include "id.h"
/* minimum static i/o mapping required to boot U8500 platforms */
static struct map_desc u8500_uart_io_desc[] __initdata = {
@@ -137,14 +138,9 @@ 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[] = {
@@ -284,8 +280,10 @@ static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("st,nomadik-i2c", 0x80128000, "nmk-i2c.2", NULL),
OF_DEV_AUXDATA("st,nomadik-i2c", 0x80110000, "nmk-i2c.3", NULL),
OF_DEV_AUXDATA("st,nomadik-i2c", 0x8012a000, "nmk-i2c.4", NULL),
+ OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu",
+ &db8500_prcmu_pdata),
/* Requires device name bindings. */
- OF_DEV_AUXDATA("stericsson,nmk_pinctrl", U8500_PRCMU_BASE,
+ OF_DEV_AUXDATA("stericsson,nmk-pinctrl", U8500_PRCMU_BASE,
"pinctrl-db8500", NULL),
/* Requires clock name and DMA bindings. */
OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80123000,
@@ -341,8 +339,7 @@ DT_MACHINE_START(U8500_DT, "ST-Ericsson Ux5x0 platform (Device Tree Support)")
.map_io = u8500_map_io,
.init_irq = ux500_init_irq,
/* we re-use nomadik timer here */
- .timer = &ux500_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = ux500_timer_init,
.init_machine = u8500_init_machine,
.init_late = NULL,
.dt_compat = stericsson_dt_platform_compat,
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index 721e7b4275f3..537870d3fea8 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -17,9 +17,10 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-ux500.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
@@ -27,6 +28,7 @@
#include <mach/devices.h>
#include "board-mop500.h"
+#include "id.h"
void __iomem *_PRCMU_BASE;
@@ -42,11 +44,6 @@ void __iomem *_PRCMU_BASE;
* This feels fragile because it depends on the gpio device getting probed
* _before_ any device uses the gpio interrupts.
*/
-static const struct of_device_id ux500_dt_irq_match[] = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- {},
-};
-
void __init ux500_init_irq(void)
{
void __iomem *dist_base;
@@ -62,7 +59,7 @@ void __init ux500_init_irq(void)
#ifdef CONFIG_OF
if (of_have_populated_dt())
- of_irq_init(ux500_dt_irq_match);
+ irqchip_init();
else
#endif
gic_init(0, 29, dist_base, cpu_base);
@@ -71,13 +68,11 @@ void __init ux500_init_irq(void)
* Init clocks here so that they are available for system timer
* initialization.
*/
- if (cpu_is_u8500_family())
+ if (cpu_is_u8500_family() || cpu_is_u9540())
db8500_prcmu_early_init();
- if (cpu_is_u8500_family())
+ if (cpu_is_u8500_family() || cpu_is_u9540())
u8500_clk_init();
- else if (cpu_is_u9540())
- u9540_clk_init();
else if (cpu_is_u8540())
u8540_clk_init();
}
diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c
index b54884bd2549..ce9149302cc3 100644
--- a/arch/arm/mach-ux500/cpuidle.c
+++ b/arch/arm/mach-ux500/cpuidle.c
@@ -40,8 +40,10 @@ static inline int ux500_enter_idle(struct cpuidle_device *dev,
goto wfi;
/* decouple the gic from the A9 cores */
- if (prcmu_gic_decouple())
+ if (prcmu_gic_decouple()) {
+ spin_unlock(&master_lock);
goto out;
+ }
/* If an error occur, we will have to recouple the gic
* manually */
diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c
index 318d49020894..f3d9419f75d3 100644
--- a/arch/arm/mach-ux500/devices-db8500.c
+++ b/arch/arm/mach-ux500/devices-db8500.c
@@ -13,11 +13,13 @@
#include <linux/amba/bus.h>
#include <linux/amba/pl022.h>
#include <linux/platform_data/dma-ste-dma40.h>
+#include <linux/mfd/dbx500-prcmu.h>
#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/irqs.h>
+#include "devices-db8500.h"
#include "ste-dma40-db8500.h"
static struct resource dma40_resources[] = {
@@ -194,3 +196,45 @@ struct platform_device u8500_ske_keypad_device = {
.num_resources = ARRAY_SIZE(keypad_resources),
.resource = keypad_resources,
};
+
+struct prcmu_pdata db8500_prcmu_pdata = {
+ .ab_platdata = &ab8500_platdata,
+ .version_offset = DB8500_PRCMU_FW_VERSION_OFFSET,
+ .legacy_offset = DB8500_PRCMU_LEGACY_OFFSET,
+};
+
+static struct resource db8500_prcmu_res[] = {
+ {
+ .name = "prcmu",
+ .start = U8500_PRCMU_BASE,
+ .end = U8500_PRCMU_BASE + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "prcmu-tcdm",
+ .start = U8500_PRCMU_TCDM_BASE,
+ .end = U8500_PRCMU_TCDM_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "irq",
+ .start = IRQ_DB8500_PRCMU1,
+ .end = IRQ_DB8500_PRCMU1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "prcmu-tcpm",
+ .start = U8500_PRCMU_TCPM_BASE,
+ .end = U8500_PRCMU_TCPM_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device db8500_prcmu_device = {
+ .name = "db8500-prcmu",
+ .resource = db8500_prcmu_res,
+ .num_resources = ARRAY_SIZE(db8500_prcmu_res),
+ .dev = {
+ .platform_data = &db8500_prcmu_pdata,
+ },
+};
diff --git a/arch/arm/mach-ux500/devices-db8500.h b/arch/arm/mach-ux500/devices-db8500.h
index a5e05f6e256f..dbcb35c48f06 100644
--- a/arch/arm/mach-ux500/devices-db8500.h
+++ b/arch/arm/mach-ux500/devices-db8500.h
@@ -14,6 +14,11 @@
struct ske_keypad_platform_data;
struct pl022_ssp_controller;
+struct platform_device;
+
+extern struct ab8500_platform_data ab8500_platdata;
+extern struct prcmu_pdata db8500_prcmu_pdata;
+extern struct platform_device db8500_prcmu_device;
static inline struct platform_device *
db8500_add_ske_keypad(struct device *parent,
diff --git a/arch/arm/mach-ux500/id.c b/arch/arm/mach-ux500/id.c
index d1579920139f..9f951842e1e5 100644
--- a/arch/arm/mach-ux500/id.c
+++ b/arch/arm/mach-ux500/id.c
@@ -17,6 +17,8 @@
#include <mach/hardware.h>
#include <mach/setup.h>
+#include "id.h"
+
struct dbx500_asic_id dbx500_id;
static unsigned int ux500_read_asicid(phys_addr_t addr)
diff --git a/arch/arm/mach-ux500/include/mach/id.h b/arch/arm/mach-ux500/id.h
index 9c42642ab168..bcc58a8cccbc 100644
--- a/arch/arm/mach-ux500/include/mach/id.h
+++ b/arch/arm/mach-ux500/id.h
@@ -61,9 +61,14 @@ static inline bool __attribute_const__ cpu_is_u8540(void)
return dbx500_partnumber() == 0x8540;
}
+static inline bool __attribute_const__ cpu_is_u8580(void)
+{
+ return dbx500_partnumber() == 0x8580;
+}
+
static inline bool cpu_is_ux540_family(void)
{
- return cpu_is_u9540() || cpu_is_u8540();
+ return cpu_is_u9540() || cpu_is_u8540() || cpu_is_u8580();
}
/*
@@ -115,6 +120,20 @@ static inline bool cpu_is_u8500v20_or_later(void)
return (cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
}
+/*
+ * 8540 revisions
+ */
+
+static inline bool __attribute_const__ cpu_is_u8540v10(void)
+{
+ return cpu_is_u8540() && dbx500_revision() == 0xA0;
+}
+
+static inline bool __attribute_const__ cpu_is_u8580v10(void)
+{
+ return cpu_is_u8580() && dbx500_revision() == 0xA0;
+}
+
static inline bool ux500_is_svp(void)
{
return false;
diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h
index 28d16e744bfd..5201ddace503 100644
--- a/arch/arm/mach-ux500/include/mach/hardware.h
+++ b/arch/arm/mach-ux500/include/mach/hardware.h
@@ -39,7 +39,6 @@
#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/irqs-board-mop500.h b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
index 7d34c52798b5..d526dd8e87d3 100644
--- a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
+++ b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
@@ -38,15 +38,7 @@
#define MOP500_STMPE1601_IRQ_END \
MOP500_STMPE1601_IRQ(STMPE_NR_INTERNAL_IRQS)
-/* AB8500 virtual gpio IRQ */
-#define AB8500_VIR_GPIO_NR_IRQS 16
-
-#define MOP500_AB8500_VIR_GPIO_IRQ_BASE \
- MOP500_STMPE1601_IRQ_END
-#define MOP500_AB8500_VIR_GPIO_IRQ_END \
- (MOP500_AB8500_VIR_GPIO_IRQ_BASE + AB8500_VIR_GPIO_NR_IRQS)
-
-#define MOP500_NR_IRQS MOP500_AB8500_VIR_GPIO_IRQ_END
+#define MOP500_NR_IRQS MOP500_STMPE1601_IRQ_END
#define MOP500_IRQ_END MOP500_NR_IRQS
diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h
index 6be4c4d2ab88..bddce2b49372 100644
--- a/arch/arm/mach-ux500/include/mach/setup.h
+++ b/arch/arm/mach-ux500/include/mach/setup.h
@@ -28,8 +28,7 @@ extern struct device *ux500_soc_device_init(const char *soc_id);
struct amba_device;
extern void __init amba_add_devices(struct amba_device *devs[], int num);
-struct sys_timer;
-extern struct sys_timer ux500_timer;
+extern void ux500_timer_init(void);
#define __IO_DEV_DESC(x, sz) { \
.virtual = IO_ADDRESS(x), \
diff --git a/arch/arm/mach-ux500/include/mach/uncompress.h b/arch/arm/mach-ux500/include/mach/uncompress.h
index d60ecd1753f0..36969d52e53a 100644
--- a/arch/arm/mach-ux500/include/mach/uncompress.h
+++ b/arch/arm/mach-ux500/include/mach/uncompress.h
@@ -54,6 +54,4 @@ static inline void arch_decomp_setup(void)
ux500_uart_base = (void __iomem *)U8500_UART2_BASE;
}
-#define arch_decomp_wdog() /* nothing to do here */
-
#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index 3db7782f3afb..18f7af339dc9 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -16,14 +16,17 @@
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/cacheflush.h>
-#include <asm/hardware/gic.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
+
#include <mach/hardware.h>
#include <mach/setup.h>
+#include "id.h"
+
/* This is called from headsmp.S to wakeup the secondary core */
extern void u8500_secondary_startup(void);
@@ -91,7 +94,7 @@ static int __cpuinit ux500_boot_secondary(unsigned int cpu, struct task_struct *
*/
write_pen_release(cpu_logical_map(cpu));
- smp_send_reschedule(cpu);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
@@ -155,8 +158,6 @@ static void __init ux500_smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
static void __init ux500_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c
index 875309acb022..a6af0b8732ba 100644
--- a/arch/arm/mach-ux500/timer.c
+++ b/arch/arm/mach-ux500/timer.c
@@ -17,6 +17,8 @@
#include <mach/hardware.h>
#include <mach/irqs.h>
+#include "id.h"
+
#ifdef CONFIG_HAVE_ARM_TWD
static DEFINE_TWD_LOCAL_TIMER(u8500_twd_local_timer,
U8500_TWD_BASE, IRQ_LOCALTIMER);
@@ -46,7 +48,7 @@ const static struct of_device_id prcmu_timer_of_match[] __initconst = {
{ },
};
-static void __init ux500_timer_init(void)
+void __init ux500_timer_init(void)
{
void __iomem *mtu_timer_base;
void __iomem *prcmu_timer_base;
@@ -99,14 +101,3 @@ dt_fail:
clksrc_dbx500_prcmu_init(prcmu_timer_base);
ux500_twd_init();
}
-
-static void ux500_timer_reset(void)
-{
- nmdk_clkevt_reset();
- nmdk_clksrc_reset();
-}
-
-struct sys_timer ux500_timer = {
- .init = ux500_timer_init,
- .resume = ux500_timer_reset,
-};
diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig
index 63d8e9f81b99..1dba3688275f 100644
--- a/arch/arm/mach-versatile/Kconfig
+++ b/arch/arm/mach-versatile/Kconfig
@@ -25,4 +25,9 @@ config MACH_VERSATILE_DT
Include support for the ARM(R) Versatile/PB platform,
using the device tree for discovery
+config MACH_VERSATILE_AUTO
+ def_bool y
+ depends on !ARCH_VERSATILE_PB && !MACH_VERSATILE_AB
+ select MACH_VERSATILE_DT
+
endmenu
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 5d5929450366..25160aeaa3b7 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -32,15 +32,16 @@
#include <linux/amba/mmci.h>
#include <linux/amba/pl022.h>
#include <linux/io.h>
+#include <linux/irqchip/arm-vic.h>
#include <linux/irqchip/versatile-fpga.h>
#include <linux/gfp.h>
#include <linux/clkdev.h>
#include <linux/mtd/physmap.h>
+#include <linux/bitops.h>
#include <asm/irq.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -65,16 +66,28 @@
#define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE)
#define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE)
+/* These PIC IRQs are valid in each configuration */
+#define PIC_VALID_ALL BIT(SIC_INT_KMI0) | BIT(SIC_INT_KMI1) | \
+ BIT(SIC_INT_SCI3) | BIT(SIC_INT_UART3) | \
+ BIT(SIC_INT_CLCD) | BIT(SIC_INT_TOUCH) | \
+ BIT(SIC_INT_KEYPAD) | BIT(SIC_INT_DoC) | \
+ BIT(SIC_INT_USB) | BIT(SIC_INT_PCI0) | \
+ BIT(SIC_INT_PCI1) | BIT(SIC_INT_PCI2) | \
+ BIT(SIC_INT_PCI3)
#if 1
#define IRQ_MMCI0A IRQ_VICSOURCE22
#define IRQ_AACI IRQ_VICSOURCE24
#define IRQ_ETH IRQ_VICSOURCE25
#define PIC_MASK 0xFFD00000
+#define PIC_VALID PIC_VALID_ALL
#else
#define IRQ_MMCI0A IRQ_SIC_MMCI0A
#define IRQ_AACI IRQ_SIC_AACI
#define IRQ_ETH IRQ_SIC_ETH
#define PIC_MASK 0
+#define PIC_VALID PIC_VALID_ALL | BIT(SIC_INT_MMCI0A) | \
+ BIT(SIC_INT_MMCI1A) | BIT(SIC_INT_AACI) | \
+ BIT(SIC_INT_ETH)
#endif
/* Lookup table for finding a DT node that represents the vic instance */
@@ -102,7 +115,7 @@ void __init versatile_init_irq(void)
VERSATILE_SIC_BASE);
fpga_irq_init(VA_SIC_BASE, "SIC", IRQ_SIC_START,
- IRQ_VICSOURCE31, ~PIC_MASK, np);
+ IRQ_VICSOURCE31, PIC_VALID, np);
/*
* Interrupts on secondary controller from 0 to 8 are routed to
@@ -114,7 +127,7 @@ void __init versatile_init_irq(void)
writel(PIC_MASK, VA_SIC_BASE + SIC_INT_PIC_ENABLE);
}
-static struct map_desc versatile_io_desc[] __initdata = {
+static struct map_desc versatile_io_desc[] __initdata __maybe_unused = {
{
.virtual = IO_ADDRESS(VERSATILE_SYS_BASE),
.pfn = __phys_to_pfn(VERSATILE_SYS_BASE),
@@ -770,7 +783,7 @@ void __init versatile_init(void)
/*
* Set up timer interrupt, and return the current time in seconds.
*/
-static void __init versatile_timer_init(void)
+void __init versatile_timer_init(void)
{
u32 val;
@@ -797,8 +810,3 @@ static void __init versatile_timer_init(void)
sp804_clocksource_init(TIMER3_VA_BASE, "timer3");
sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1, "timer0");
}
-
-struct sys_timer versatile_timer = {
- .init = versatile_timer_init,
-};
-
diff --git a/arch/arm/mach-versatile/core.h b/arch/arm/mach-versatile/core.h
index 683e60776a85..5c1b87d1da6b 100644
--- a/arch/arm/mach-versatile/core.h
+++ b/arch/arm/mach-versatile/core.h
@@ -29,7 +29,7 @@ extern void __init versatile_init(void);
extern void __init versatile_init_early(void);
extern void __init versatile_init_irq(void);
extern void __init versatile_map_io(void);
-extern struct sys_timer versatile_timer;
+extern void versatile_timer_init(void);
extern void versatile_restart(char, const char *);
extern unsigned int mmc_status(struct device *dev);
#ifdef CONFIG_OF
diff --git a/arch/arm/mach-versatile/include/mach/uncompress.h b/arch/arm/mach-versatile/include/mach/uncompress.h
index 3dd0048afb34..986e3d303f3c 100644
--- a/arch/arm/mach-versatile/include/mach/uncompress.h
+++ b/arch/arm/mach-versatile/include/mach/uncompress.h
@@ -43,4 +43,3 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
index 2f84f4094f13..e92e5e0705bc 100644
--- a/arch/arm/mach-versatile/pci.c
+++ b/arch/arm/mach-versatile/pci.c
@@ -23,6 +23,7 @@
#include <linux/io.h>
#include <mach/hardware.h>
+#include <mach/irqs.h>
#include <asm/irq.h>
#include <asm/mach/pci.h>
@@ -327,12 +328,12 @@ static int __init versatile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
int irq;
/* slot, pin, irq
- * 24 1 27
- * 25 1 28
- * 26 1 29
- * 27 1 30
+ * 24 1 IRQ_SIC_PCI0
+ * 25 1 IRQ_SIC_PCI1
+ * 26 1 IRQ_SIC_PCI2
+ * 27 1 IRQ_SIC_PCI3
*/
- irq = 27 + ((slot - 24 + pin - 1) & 3);
+ irq = IRQ_SIC_PCI0 + ((slot - 24 + pin - 1) & 3);
return irq;
}
diff --git a/arch/arm/mach-versatile/versatile_ab.c b/arch/arm/mach-versatile/versatile_ab.c
index 98f65493177a..1caef1093793 100644
--- a/arch/arm/mach-versatile/versatile_ab.c
+++ b/arch/arm/mach-versatile/versatile_ab.c
@@ -26,7 +26,6 @@
#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -39,8 +38,7 @@ MACHINE_START(VERSATILE_AB, "ARM-Versatile AB")
.map_io = versatile_map_io,
.init_early = versatile_init_early,
.init_irq = versatile_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &versatile_timer,
+ .init_time = versatile_timer_init,
.init_machine = versatile_init,
.restart = versatile_restart,
MACHINE_END
diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c
index ae5ad3c8f3dd..2558f2e957c3 100644
--- a/arch/arm/mach-versatile/versatile_dt.c
+++ b/arch/arm/mach-versatile/versatile_dt.c
@@ -24,7 +24,6 @@
#include <linux/init.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
-#include <asm/hardware/vic.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -46,8 +45,7 @@ DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)")
.map_io = versatile_map_io,
.init_early = versatile_init_early,
.init_irq = versatile_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &versatile_timer,
+ .init_time = versatile_timer_init,
.init_machine = versatile_dt_init,
.dt_compat = versatile_dt_match,
.restart = versatile_restart,
diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c
index 19738331bd3d..611d140c8695 100644
--- a/arch/arm/mach-versatile/versatile_pb.c
+++ b/arch/arm/mach-versatile/versatile_pb.c
@@ -27,7 +27,6 @@
#include <linux/io.h>
#include <mach/hardware.h>
-#include <asm/hardware/vic.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
@@ -107,8 +106,7 @@ MACHINE_START(VERSATILE_PB, "ARM-Versatile PB")
.map_io = versatile_map_io,
.init_early = versatile_init_early,
.init_irq = versatile_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &versatile_timer,
+ .init_time = versatile_timer_init,
.init_machine = versatile_pb_init,
.restart = versatile_restart,
MACHINE_END
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 60838ddb8564..6f34497a4245 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -10,10 +10,10 @@
#include <linux/amba/clcd.h>
#include <linux/clkdev.h>
#include <linux/vexpress.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/gic.h>
#include <asm/smp_scu.h>
#include <asm/smp_twd.h>
@@ -182,8 +182,6 @@ static void __init 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 __init ct_ca9x4_smp_enable(unsigned int max_cpus)
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index c5d70de9bb4e..dc1ace55d557 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -16,7 +16,6 @@
#include <linux/vexpress.h>
#include <asm/smp_scu.h>
-#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
#include <mach/motherboard.h>
@@ -128,8 +127,6 @@ static void __init vexpress_dt_smp_init_cpus(void)
for (i = 0; i < ncores; ++i)
set_cpu_possible(i, true);
-
- set_smp_cross_call(gic_raise_softirq);
}
static void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 011661a6c5cb..915683cb67d6 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -7,6 +7,7 @@
#include <linux/io.h>
#include <linux/smp.h>
#include <linux/init.h>
+#include <linux/irqchip.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
@@ -30,7 +31,6 @@
#include <asm/mach/time.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/timer-sp.h>
#include <mach/ct-ca9x4.h>
@@ -291,10 +291,6 @@ static void __init v2m_timer_init(void)
v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
}
-static struct sys_timer v2m_timer = {
- .init = v2m_timer_init,
-};
-
static void __init v2m_init_early(void)
{
if (ct_desc->init_early)
@@ -376,8 +372,7 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express")
.map_io = v2m_map_io,
.init_early = v2m_init_early,
.init_irq = v2m_init_irq,
- .timer = &v2m_timer,
- .handle_irq = gic_handle_irq,
+ .init_time = v2m_timer_init,
.init_machine = v2m_init,
.restart = vexpress_restart,
MACHINE_END
@@ -434,16 +429,6 @@ void __init v2m_dt_init_early(void)
}
}
-static struct of_device_id vexpress_irq_match[] __initdata = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- {}
-};
-
-static void __init v2m_dt_init_irq(void)
-{
- of_irq_init(vexpress_irq_match);
-}
-
static void __init v2m_dt_timer_init(void)
{
struct device_node *node = NULL;
@@ -468,10 +453,6 @@ static void __init v2m_dt_timer_init(void)
24000000);
}
-static struct sys_timer v2m_dt_timer = {
- .init = v2m_dt_timer_init,
-};
-
static const struct of_device_id v2m_dt_bus_match[] __initconst = {
{ .compatible = "simple-bus", },
{ .compatible = "arm,amba-bus", },
@@ -497,9 +478,8 @@ DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
.smp = smp_ops(vexpress_smp_ops),
.map_io = v2m_dt_map_io,
.init_early = v2m_dt_init_early,
- .init_irq = v2m_dt_init_irq,
- .timer = &v2m_dt_timer,
+ .init_irq = irqchip_init,
+ .init_time = v2m_dt_timer_init,
.init_machine = v2m_dt_init,
- .handle_irq = gic_handle_irq,
.restart = vexpress_restart,
MACHINE_END
diff --git a/arch/arm/mach-virt/Kconfig b/arch/arm/mach-virt/Kconfig
new file mode 100644
index 000000000000..8958f0d896bc
--- /dev/null
+++ b/arch/arm/mach-virt/Kconfig
@@ -0,0 +1,10 @@
+config ARCH_VIRT
+ bool "Dummy Virtual Machine" if ARCH_MULTI_V7
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select ARM_GIC
+ select ARM_ARCH_TIMER
+ select ARM_PSCI
+ select HAVE_SMP
+ select CPU_V7
+ select SPARSE_IRQ
+ select USE_OF
diff --git a/arch/arm/mach-virt/Makefile b/arch/arm/mach-virt/Makefile
new file mode 100644
index 000000000000..042afc1f8c44
--- /dev/null
+++ b/arch/arm/mach-virt/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y := virt.o
+obj-$(CONFIG_SMP) += platsmp.o
diff --git a/arch/arm/mach-virt/platsmp.c b/arch/arm/mach-virt/platsmp.c
new file mode 100644
index 000000000000..8badaabe70a1
--- /dev/null
+++ b/arch/arm/mach-virt/platsmp.c
@@ -0,0 +1,58 @@
+/*
+ * Dummy Virtual Machine - does what it says on the tin.
+ *
+ * Copyright (C) 2012 ARM Ltd
+ * Author: Will Deacon <will.deacon@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/of.h>
+
+#include <linux/irqchip/arm-gic.h>
+
+#include <asm/psci.h>
+#include <asm/smp_plat.h>
+
+extern void secondary_startup(void);
+
+static void __init virt_smp_init_cpus(void)
+{
+}
+
+static void __init virt_smp_prepare_cpus(unsigned int max_cpus)
+{
+}
+
+static int __cpuinit virt_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ if (psci_ops.cpu_on)
+ return psci_ops.cpu_on(cpu_logical_map(cpu),
+ __pa(secondary_startup));
+ return -ENODEV;
+}
+
+static void __cpuinit virt_secondary_init(unsigned int cpu)
+{
+ gic_secondary_init(0);
+}
+
+struct smp_operations __initdata virt_smp_ops = {
+ .smp_init_cpus = virt_smp_init_cpus,
+ .smp_prepare_cpus = virt_smp_prepare_cpus,
+ .smp_secondary_init = virt_secondary_init,
+ .smp_boot_secondary = virt_boot_secondary,
+};
diff --git a/arch/arm/mach-virt/virt.c b/arch/arm/mach-virt/virt.c
new file mode 100644
index 000000000000..31666f6b4373
--- /dev/null
+++ b/arch/arm/mach-virt/virt.c
@@ -0,0 +1,54 @@
+/*
+ * Dummy Virtual Machine - does what it says on the tin.
+ *
+ * Copyright (C) 2012 ARM Ltd
+ * Authors: Will Deacon <will.deacon@arm.com>,
+ * Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/irqchip.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/smp.h>
+
+#include <asm/arch_timer.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+static void __init virt_init(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static void __init virt_timer_init(void)
+{
+ WARN_ON(arch_timer_of_register() != 0);
+ WARN_ON(arch_timer_sched_clock_init() != 0);
+}
+
+static const char *virt_dt_match[] = {
+ "linux,dummy-virt",
+ NULL
+};
+
+extern struct smp_operations virt_smp_ops;
+
+DT_MACHINE_START(VIRT, "Dummy Virtual Machine")
+ .init_irq = irqchip_init,
+ .init_time = virt_timer_init,
+ .init_machine = virt_init,
+ .smp = smp_ops(virt_smp_ops),
+ .dt_compat = virt_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-vt8500/Kconfig b/arch/arm/mach-vt8500/Kconfig
index 2ed0b7d95db6..e3e94b2fa145 100644
--- a/arch/arm/mach-vt8500/Kconfig
+++ b/arch/arm/mach-vt8500/Kconfig
@@ -1,12 +1,34 @@
config ARCH_VT8500
- bool "VIA/WonderMedia 85xx" if ARCH_MULTI_V5
- default ARCH_VT8500_SINGLE
+ bool
select ARCH_HAS_CPUFREQ
select ARCH_REQUIRE_GPIOLIB
select CLKDEV_LOOKUP
- select CPU_ARM926T
+ select CLKSRC_OF
select GENERIC_CLOCKEVENTS
- select GENERIC_GPIO
select HAVE_CLK
+ select VT8500_TIMER
help
Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip.
+
+config ARCH_WM8505
+ bool "VIA/Wondermedia 85xx and WM8650"
+ depends on ARCH_MULTI_V5
+ select ARCH_VT8500
+ select CPU_ARM926T
+ help
+
+config ARCH_WM8750
+ bool "WonderMedia WM8750"
+ depends on ARCH_MULTI_V6
+ select ARCH_VT8500
+ select CPU_V6
+ help
+ Support for WonderMedia WM8750 System-on-Chip.
+
+config ARCH_WM8850
+ bool "WonderMedia WM8850"
+ depends on ARCH_MULTI_V7
+ select ARCH_VT8500
+ select CPU_V7
+ help
+ Support for WonderMedia WM8850 System-on-Chip.
diff --git a/arch/arm/mach-vt8500/Makefile b/arch/arm/mach-vt8500/Makefile
index e035251cda48..92ceb2436b60 100644
--- a/arch/arm/mach-vt8500/Makefile
+++ b/arch/arm/mach-vt8500/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_ARCH_VT8500) += irq.o timer.o vt8500.o
+obj-$(CONFIG_ARCH_VT8500) += irq.o vt8500.o
diff --git a/arch/arm/mach-vt8500/common.h b/arch/arm/mach-vt8500/common.h
index 6f2b843115db..77611a6968d6 100644
--- a/arch/arm/mach-vt8500/common.h
+++ b/arch/arm/mach-vt8500/common.h
@@ -18,7 +18,6 @@
#include <linux/of.h>
-void __init vt8500_timer_init(void);
int __init vt8500_irq_init(struct device_node *node,
struct device_node *parent);
diff --git a/arch/arm/mach-vt8500/include/mach/timex.h b/arch/arm/mach-vt8500/include/mach/timex.h
deleted file mode 100644
index 8487e4c690b7..000000000000
--- a/arch/arm/mach-vt8500/include/mach/timex.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * arch/arm/mach-vt8500/include/mach/timex.h
- *
- * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef MACH_TIMEX_H
-#define MACH_TIMEX_H
-
-#define CLOCK_TICK_RATE (3000000)
-
-#endif /* MACH_TIMEX_H */
diff --git a/arch/arm/mach-vt8500/include/mach/uncompress.h b/arch/arm/mach-vt8500/include/mach/uncompress.h
deleted file mode 100644
index e6e81fdaf109..000000000000
--- a/arch/arm/mach-vt8500/include/mach/uncompress.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* arch/arm/mach-vt8500/include/mach/uncompress.h
- *
- * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * Based on arch/arm/mach-dove/include/mach/uncompress.h
- *
- * 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.
- *
- */
-
-#define UART0_PHYS 0xd8200000
-#define UART0_ADDR(x) *(volatile unsigned char *)(UART0_PHYS + x)
-
-static void putc(const char c)
-{
- while (UART0_ADDR(0x1c) & 0x2)
- /* Tx busy, wait and poll */;
-
- UART0_ADDR(0) = c;
-}
-
-static void flush(void)
-{
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-vt8500/vt8500.c b/arch/arm/mach-vt8500/vt8500.c
index 3c66d48ea082..49e80053d828 100644
--- a/arch/arm/mach-vt8500/vt8500.c
+++ b/arch/arm/mach-vt8500/vt8500.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/clocksource.h>
#include <linux/io.h>
#include <linux/pm.h>
@@ -175,22 +176,20 @@ static void __init vt8500_init_irq(void)
of_irq_init(vt8500_irq_match);
};
-static struct sys_timer vt8500_timer = {
- .init = vt8500_timer_init,
-};
-
static const char * const vt8500_dt_compat[] = {
"via,vt8500",
"wm,wm8650",
"wm,wm8505",
+ "wm,wm8750",
+ "wm,wm8850",
};
DT_MACHINE_START(WMT_DT, "VIA/Wondermedia SoC (Device Tree Support)")
.dt_compat = vt8500_dt_compat,
.map_io = vt8500_map_io,
.init_irq = vt8500_init_irq,
- .timer = &vt8500_timer,
.init_machine = vt8500_init,
+ .init_time = clocksource_of_init,
.restart = vt8500_restart,
.handle_irq = vt8500_handle_irq,
MACHINE_END
diff --git a/arch/arm/mach-w90x900/include/mach/entry-macro.S b/arch/arm/mach-w90x900/include/mach/entry-macro.S
index e286daca6827..0ff612ac95ba 100644
--- a/arch/arm/mach-w90x900/include/mach/entry-macro.S
+++ b/arch/arm/mach-w90x900/include/mach/entry-macro.S
@@ -19,8 +19,8 @@
mov \base, #AIC_BA
- ldr \irqnr, [ \base, #AIC_IPER]
- ldr \irqnr, [ \base, #AIC_ISNR]
+ ldr \irqnr, [\base, #AIC_IPER]
+ ldr \irqnr, [\base, #AIC_ISNR]
cmp \irqnr, #0
.endm
diff --git a/arch/arm/mach-w90x900/include/mach/uncompress.h b/arch/arm/mach-w90x900/include/mach/uncompress.h
index 03130212ace2..4b7c324ff664 100644
--- a/arch/arm/mach-w90x900/include/mach/uncompress.h
+++ b/arch/arm/mach-w90x900/include/mach/uncompress.h
@@ -24,8 +24,6 @@
#include <mach/map.h>
#include <linux/serial_reg.h>
-#define arch_decomp_wdog()
-
#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
static volatile u32 * const uart_base = (u32 *)UART0_PA;
diff --git a/arch/arm/mach-w90x900/mach-nuc910evb.c b/arch/arm/mach-w90x900/mach-nuc910evb.c
index b4243e4f1565..92f1c978f35e 100644
--- a/arch/arm/mach-w90x900/mach-nuc910evb.c
+++ b/arch/arm/mach-w90x900/mach-nuc910evb.c
@@ -37,6 +37,6 @@ MACHINE_START(W90P910EVB, "W90P910EVB")
.map_io = nuc910evb_map_io,
.init_irq = nuc900_init_irq,
.init_machine = nuc910evb_init,
- .timer = &nuc900_timer,
+ .init_time = nuc900_timer_init,
.restart = nuc9xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-w90x900/mach-nuc950evb.c b/arch/arm/mach-w90x900/mach-nuc950evb.c
index 500fe5932ce9..26f7189056e3 100644
--- a/arch/arm/mach-w90x900/mach-nuc950evb.c
+++ b/arch/arm/mach-w90x900/mach-nuc950evb.c
@@ -40,6 +40,6 @@ MACHINE_START(W90P950EVB, "W90P950EVB")
.map_io = nuc950evb_map_io,
.init_irq = nuc900_init_irq,
.init_machine = nuc950evb_init,
- .timer = &nuc900_timer,
+ .init_time = nuc900_timer_init,
.restart = nuc9xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-w90x900/mach-nuc960evb.c b/arch/arm/mach-w90x900/mach-nuc960evb.c
index cbb3adc3db10..9b4e73fe10e5 100644
--- a/arch/arm/mach-w90x900/mach-nuc960evb.c
+++ b/arch/arm/mach-w90x900/mach-nuc960evb.c
@@ -37,6 +37,6 @@ MACHINE_START(W90N960EVB, "W90N960EVB")
.map_io = nuc960evb_map_io,
.init_irq = nuc900_init_irq,
.init_machine = nuc960evb_init,
- .timer = &nuc900_timer,
+ .init_time = nuc900_timer_init,
.restart = nuc9xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-w90x900/nuc9xx.h b/arch/arm/mach-w90x900/nuc9xx.h
index 91acb4047793..88ef4b267089 100644
--- a/arch/arm/mach-w90x900/nuc9xx.h
+++ b/arch/arm/mach-w90x900/nuc9xx.h
@@ -15,10 +15,9 @@
*
*/
struct map_desc;
-struct sys_timer;
/* core initialisation functions */
extern void nuc900_init_irq(void);
-extern struct sys_timer nuc900_timer;
+extern void nuc900_timer_init(void);
extern void nuc9xx_restart(char, const char *);
diff --git a/arch/arm/mach-w90x900/time.c b/arch/arm/mach-w90x900/time.c
index fa27c498ac09..30fbca844575 100644
--- a/arch/arm/mach-w90x900/time.c
+++ b/arch/arm/mach-w90x900/time.c
@@ -91,7 +91,6 @@ static int nuc900_clockevent_setnextevent(unsigned long evt,
static struct clock_event_device nuc900_clockevent_device = {
.name = "nuc900-timer0",
- .shift = 32,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = nuc900_clockevent_setmode,
.set_next_event = nuc900_clockevent_setnextevent,
@@ -133,15 +132,10 @@ static void __init nuc900_clockevents_init(void)
__raw_writel(RESETINT, REG_TISR);
setup_irq(IRQ_TIMER0, &nuc900_timer0_irq);
- nuc900_clockevent_device.mult = div_sc(rate, NSEC_PER_SEC,
- nuc900_clockevent_device.shift);
- nuc900_clockevent_device.max_delta_ns = clockevent_delta2ns(0xffffffff,
- &nuc900_clockevent_device);
- nuc900_clockevent_device.min_delta_ns = clockevent_delta2ns(0xf,
- &nuc900_clockevent_device);
nuc900_clockevent_device.cpumask = cpumask_of(0);
- clockevents_register_device(&nuc900_clockevent_device);
+ clockevents_config_and_register(&nuc900_clockevent_device, rate,
+ 0xf, 0xffffffff);
}
static void __init nuc900_clocksource_init(void)
@@ -167,12 +161,8 @@ static void __init nuc900_clocksource_init(void)
TDR_SHIFT, clocksource_mmio_readl_down);
}
-static void __init nuc900_timer_init(void)
+void __init nuc900_timer_init(void)
{
nuc900_clocksource_init();
nuc900_clockevents_init();
}
-
-struct sys_timer nuc900_timer = {
- .init = nuc900_timer_init,
-};
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c
index e16d4bed0f7a..5c8983218183 100644
--- a/arch/arm/mach-zynq/common.c
+++ b/arch/arm/mach-zynq/common.c
@@ -24,6 +24,7 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/of.h>
+#include <linux/irqchip.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -31,7 +32,6 @@
#include <asm/mach-types.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include "common.h"
@@ -55,19 +55,6 @@ static void __init xilinx_init_machine(void)
of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL);
}
-static struct of_device_id irq_match[] __initdata = {
- { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
- { }
-};
-
-/**
- * xilinx_irq_init() - Interrupt controller initialization for the GIC.
- */
-static void __init xilinx_irq_init(void)
-{
- of_irq_init(irq_match);
-}
-
#define SCU_PERIPH_PHYS 0xF8F00000
#define SCU_PERIPH_SIZE SZ_8K
#define SCU_PERIPH_VIRT (VMALLOC_END - SCU_PERIPH_SIZE)
@@ -90,16 +77,9 @@ static void __init xilinx_zynq_timer_init(void)
xilinx_zynq_clocks_init(slcr);
- xttcpss_timer_init();
+ xttcps_timer_init();
}
-/*
- * Instantiate and initialize the system timer structure
- */
-static struct sys_timer xttcpss_sys_timer = {
- .init = xilinx_zynq_timer_init,
-};
-
/**
* xilinx_map_io() - Create memory mappings needed for early I/O.
*/
@@ -117,9 +97,8 @@ static const char *xilinx_dt_match[] = {
MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
.map_io = xilinx_map_io,
- .init_irq = xilinx_irq_init,
- .handle_irq = gic_handle_irq,
+ .init_irq = irqchip_init,
.init_machine = xilinx_init_machine,
- .timer = &xttcpss_sys_timer,
+ .init_time = xilinx_zynq_timer_init,
.dt_compat = xilinx_dt_match,
MACHINE_END
diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h
index 954b91c13c91..8b4dbbaa01cf 100644
--- a/arch/arm/mach-zynq/common.h
+++ b/arch/arm/mach-zynq/common.h
@@ -17,6 +17,6 @@
#ifndef __MACH_ZYNQ_COMMON_H__
#define __MACH_ZYNQ_COMMON_H__
-void __init xttcpss_timer_init(void);
+void __init xttcps_timer_init(void);
#endif
diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c
index de3df283da74..f9fbc9c1e7a6 100644
--- a/arch/arm/mach-zynq/timer.c
+++ b/arch/arm/mach-zynq/timer.c
@@ -15,39 +15,29 @@
* GNU General Public License for more details.
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/types.h>
-#include <linux/clocksource.h>
#include <linux/clockchips.h>
-#include <linux/io.h>
-#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/clk-provider.h>
-
#include "common.h"
/*
* Timer Register Offset Definitions of Timer 1, Increment base address by 4
* and use same offsets for Timer 2
*/
-#define XTTCPSS_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */
-#define XTTCPSS_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */
-#define XTTCPSS_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */
-#define XTTCPSS_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */
-#define XTTCPSS_MATCH_1_OFFSET 0x30 /* Match 1 Value Reg, RW */
-#define XTTCPSS_MATCH_2_OFFSET 0x3C /* Match 2 Value Reg, RW */
-#define XTTCPSS_MATCH_3_OFFSET 0x48 /* Match 3 Value Reg, RW */
-#define XTTCPSS_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */
-#define XTTCPSS_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */
-
-#define XTTCPSS_CNT_CNTRL_DISABLE_MASK 0x1
-
-/* Setup the timers to use pre-scaling, using a fixed value for now that will
+#define XTTCPS_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */
+#define XTTCPS_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */
+#define XTTCPS_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */
+#define XTTCPS_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */
+#define XTTCPS_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */
+#define XTTCPS_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */
+
+#define XTTCPS_CNT_CNTRL_DISABLE_MASK 0x1
+
+/*
+ * Setup the timers to use pre-scaling, using a fixed value for now that will
* work across most input frequency, but it may need to be more dynamic
*/
#define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */
@@ -57,72 +47,73 @@
#define CNT_CNTRL_RESET (1<<4)
/**
- * struct xttcpss_timer - This definition defines local timer structure
+ * struct xttcps_timer - This definition defines local timer structure
*
* @base_addr: Base address of timer
**/
-struct xttcpss_timer {
+struct xttcps_timer {
void __iomem *base_addr;
};
-struct xttcpss_timer_clocksource {
- struct xttcpss_timer xttc;
+struct xttcps_timer_clocksource {
+ struct xttcps_timer xttc;
struct clocksource cs;
};
-#define to_xttcpss_timer_clksrc(x) \
- container_of(x, struct xttcpss_timer_clocksource, cs)
+#define to_xttcps_timer_clksrc(x) \
+ container_of(x, struct xttcps_timer_clocksource, cs)
-struct xttcpss_timer_clockevent {
- struct xttcpss_timer xttc;
+struct xttcps_timer_clockevent {
+ struct xttcps_timer xttc;
struct clock_event_device ce;
struct clk *clk;
};
-#define to_xttcpss_timer_clkevent(x) \
- container_of(x, struct xttcpss_timer_clockevent, ce)
+#define to_xttcps_timer_clkevent(x) \
+ container_of(x, struct xttcps_timer_clockevent, ce)
/**
- * xttcpss_set_interval - Set the timer interval value
+ * xttcps_set_interval - Set the timer interval value
*
* @timer: Pointer to the timer instance
* @cycles: Timer interval ticks
**/
-static void xttcpss_set_interval(struct xttcpss_timer *timer,
+static void xttcps_set_interval(struct xttcps_timer *timer,
unsigned long cycles)
{
u32 ctrl_reg;
/* Disable the counter, set the counter value and re-enable counter */
- ctrl_reg = __raw_readl(timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
- ctrl_reg |= XTTCPSS_CNT_CNTRL_DISABLE_MASK;
- __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
+ ctrl_reg = __raw_readl(timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
+ ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
+ __raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
- __raw_writel(cycles, timer->base_addr + XTTCPSS_INTR_VAL_OFFSET);
+ __raw_writel(cycles, timer->base_addr + XTTCPS_INTR_VAL_OFFSET);
- /* Reset the counter (0x10) so that it starts from 0, one-shot
- mode makes this needed for timing to be right. */
+ /*
+ * Reset the counter (0x10) so that it starts from 0, one-shot
+ * mode makes this needed for timing to be right.
+ */
ctrl_reg |= CNT_CNTRL_RESET;
- ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK;
- __raw_writel(ctrl_reg, timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
+ ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
+ __raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
}
/**
- * xttcpss_clock_event_interrupt - Clock event timer interrupt handler
+ * xttcps_clock_event_interrupt - Clock event timer interrupt handler
*
* @irq: IRQ number of the Timer
- * @dev_id: void pointer to the xttcpss_timer instance
+ * @dev_id: void pointer to the xttcps_timer instance
*
* returns: Always IRQ_HANDLED - success
**/
-static irqreturn_t xttcpss_clock_event_interrupt(int irq, void *dev_id)
+static irqreturn_t xttcps_clock_event_interrupt(int irq, void *dev_id)
{
- struct xttcpss_timer_clockevent *xttce = dev_id;
- struct xttcpss_timer *timer = &xttce->xttc;
+ struct xttcps_timer_clockevent *xttce = dev_id;
+ struct xttcps_timer *timer = &xttce->xttc;
/* Acknowledge the interrupt and call event handler */
- __raw_writel(__raw_readl(timer->base_addr + XTTCPSS_ISR_OFFSET),
- timer->base_addr + XTTCPSS_ISR_OFFSET);
+ __raw_readl(timer->base_addr + XTTCPS_ISR_OFFSET);
xttce->ce.event_handler(&xttce->ce);
@@ -136,46 +127,46 @@ static irqreturn_t xttcpss_clock_event_interrupt(int irq, void *dev_id)
**/
static cycle_t __xttc_clocksource_read(struct clocksource *cs)
{
- struct xttcpss_timer *timer = &to_xttcpss_timer_clksrc(cs)->xttc;
+ struct xttcps_timer *timer = &to_xttcps_timer_clksrc(cs)->xttc;
return (cycle_t)__raw_readl(timer->base_addr +
- XTTCPSS_COUNT_VAL_OFFSET);
+ XTTCPS_COUNT_VAL_OFFSET);
}
/**
- * xttcpss_set_next_event - Sets the time interval for next event
+ * xttcps_set_next_event - Sets the time interval for next event
*
* @cycles: Timer interval ticks
* @evt: Address of clock event instance
*
* returns: Always 0 - success
**/
-static int xttcpss_set_next_event(unsigned long cycles,
+static int xttcps_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
- struct xttcpss_timer_clockevent *xttce = to_xttcpss_timer_clkevent(evt);
- struct xttcpss_timer *timer = &xttce->xttc;
+ struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
+ struct xttcps_timer *timer = &xttce->xttc;
- xttcpss_set_interval(timer, cycles);
+ xttcps_set_interval(timer, cycles);
return 0;
}
/**
- * xttcpss_set_mode - Sets the mode of timer
+ * xttcps_set_mode - Sets the mode of timer
*
* @mode: Mode to be set
* @evt: Address of clock event instance
**/
-static void xttcpss_set_mode(enum clock_event_mode mode,
+static void xttcps_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
- struct xttcpss_timer_clockevent *xttce = to_xttcpss_timer_clkevent(evt);
- struct xttcpss_timer *timer = &xttce->xttc;
+ struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
+ struct xttcps_timer *timer = &xttce->xttc;
u32 ctrl_reg;
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
- xttcpss_set_interval(timer,
+ xttcps_set_interval(timer,
DIV_ROUND_CLOSEST(clk_get_rate(xttce->clk),
PRESCALE * HZ));
break;
@@ -183,17 +174,17 @@ static void xttcpss_set_mode(enum clock_event_mode mode,
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
ctrl_reg = __raw_readl(timer->base_addr +
- XTTCPSS_CNT_CNTRL_OFFSET);
- ctrl_reg |= XTTCPSS_CNT_CNTRL_DISABLE_MASK;
+ XTTCPS_CNT_CNTRL_OFFSET);
+ ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
__raw_writel(ctrl_reg,
- timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
+ timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
break;
case CLOCK_EVT_MODE_RESUME:
ctrl_reg = __raw_readl(timer->base_addr +
- XTTCPSS_CNT_CNTRL_OFFSET);
- ctrl_reg &= ~XTTCPSS_CNT_CNTRL_DISABLE_MASK;
+ XTTCPS_CNT_CNTRL_OFFSET);
+ ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
__raw_writel(ctrl_reg,
- timer->base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
+ timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
break;
}
}
@@ -201,7 +192,7 @@ static void xttcpss_set_mode(enum clock_event_mode mode,
static void __init zynq_ttc_setup_clocksource(struct device_node *np,
void __iomem *base)
{
- struct xttcpss_timer_clocksource *ttccs;
+ struct xttcps_timer_clocksource *ttccs;
struct clk *clk;
int err;
u32 reg;
@@ -230,11 +221,11 @@ static void __init zynq_ttc_setup_clocksource(struct device_node *np,
ttccs->cs.mask = CLOCKSOURCE_MASK(16);
ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
- __raw_writel(0x0, ttccs->xttc.base_addr + XTTCPSS_IER_OFFSET);
+ __raw_writel(0x0, ttccs->xttc.base_addr + XTTCPS_IER_OFFSET);
__raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
- ttccs->xttc.base_addr + XTTCPSS_CLK_CNTRL_OFFSET);
+ ttccs->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
__raw_writel(CNT_CNTRL_RESET,
- ttccs->xttc.base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
+ ttccs->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
err = clocksource_register_hz(&ttccs->cs, clk_get_rate(clk) / PRESCALE);
if (WARN_ON(err))
@@ -244,7 +235,7 @@ static void __init zynq_ttc_setup_clocksource(struct device_node *np,
static void __init zynq_ttc_setup_clockevent(struct device_node *np,
void __iomem *base)
{
- struct xttcpss_timer_clockevent *ttcce;
+ struct xttcps_timer_clockevent *ttcce;
int err, irq;
u32 reg;
@@ -272,17 +263,18 @@ static void __init zynq_ttc_setup_clockevent(struct device_node *np,
ttcce->ce.name = np->name;
ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
- ttcce->ce.set_next_event = xttcpss_set_next_event;
- ttcce->ce.set_mode = xttcpss_set_mode;
+ ttcce->ce.set_next_event = xttcps_set_next_event;
+ ttcce->ce.set_mode = xttcps_set_mode;
ttcce->ce.rating = 200;
ttcce->ce.irq = irq;
+ ttcce->ce.cpumask = cpu_possible_mask;
- __raw_writel(0x23, ttcce->xttc.base_addr + XTTCPSS_CNT_CNTRL_OFFSET);
+ __raw_writel(0x23, ttcce->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
__raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
- ttcce->xttc.base_addr + XTTCPSS_CLK_CNTRL_OFFSET);
- __raw_writel(0x1, ttcce->xttc.base_addr + XTTCPSS_IER_OFFSET);
+ ttcce->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
+ __raw_writel(0x1, ttcce->xttc.base_addr + XTTCPS_IER_OFFSET);
- err = request_irq(irq, xttcpss_clock_event_interrupt, IRQF_TIMER,
+ err = request_irq(irq, xttcps_clock_event_interrupt, IRQF_TIMER,
np->name, ttcce);
if (WARN_ON(err))
return;
@@ -301,12 +293,12 @@ static const __initconst struct of_device_id zynq_ttc_match[] = {
};
/**
- * xttcpss_timer_init - Initialize the timer
+ * xttcps_timer_init - Initialize the timer
*
* Initializes the timer hardware and register the clock source and clock event
* timers with Linux kernal timer framework
**/
-void __init xttcpss_timer_init(void)
+void __init xttcps_timer_init(void)
{
struct device_node *np;
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 3fd629d5a513..025d17328730 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -629,8 +629,9 @@ config ARM_THUMBEE
make use of it. Say N for code that can run on CPUs without ThumbEE.
config ARM_VIRT_EXT
- bool "Native support for the ARM Virtualization Extensions"
- depends on MMU && CPU_V7
+ bool
+ depends on MMU
+ default y if CPU_V7
help
Enable the kernel to make use of the ARM Virtualization
Extensions to install hypervisors without run-time firmware
@@ -640,11 +641,6 @@ config ARM_VIRT_EXT
use of this feature. Refer to Documentation/arm/Booting for
details.
- It is safe to enable this option even if the kernel may not be
- booted in HYP mode, may not have support for the
- virtualization extensions, or may be booted with a
- non-compliant bootloader.
-
config SWP_EMULATE
bool "Emulate SWP/SWPB instructions"
depends on !CPU_USE_DOMAINS && CPU_V7
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 8a9c4cb50a93..4e333fa2756f 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -6,7 +6,7 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
iomap.o
obj-$(CONFIG_MMU) += fault-armv.o flush.o idmap.o ioremap.o \
- mmap.o pgd.o mmu.o vmregion.o
+ mmap.o pgd.o mmu.o
ifneq ($(CONFIG_MMU),y)
obj-y += nommu.o
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 7539ec275065..15451ee4acc8 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -19,6 +19,52 @@
#include "proc-macros.S"
/*
+ * The secondary kernel init calls v7_flush_dcache_all before it enables
+ * the L1; however, the L1 comes out of reset in an undefined state, so
+ * the clean + invalidate performed by v7_flush_dcache_all causes a bunch
+ * of cache lines with uninitialized data and uninitialized tags to get
+ * written out to memory, which does really unpleasant things to the main
+ * processor. We fix this by performing an invalidate, rather than a
+ * clean + invalidate, before jumping into the kernel.
+ *
+ * This function is cloned from arch/arm/mach-tegra/headsmp.S, and needs
+ * to be called for both secondary cores startup and primary core resume
+ * procedures.
+ */
+ENTRY(v7_invalidate_l1)
+ mov r0, #0
+ mcr p15, 2, r0, c0, c0, 0
+ mrc p15, 1, r0, c0, c0, 0
+
+ ldr r1, =0x7fff
+ and r2, r1, r0, lsr #13
+
+ ldr r1, =0x3ff
+
+ and r3, r1, r0, lsr #3 @ NumWays - 1
+ add r2, r2, #1 @ NumSets
+
+ and r0, r0, #0x7
+ add r0, r0, #4 @ SetShift
+
+ clz r1, r3 @ WayShift
+ add r4, r3, #1 @ NumWays
+1: sub r2, r2, #1 @ NumSets--
+ mov r3, r4 @ Temp = NumWays
+2: subs r3, r3, #1 @ Temp--
+ mov r5, r3, lsl r1
+ mov r6, r2, lsl r0
+ orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
+ mcr p15, 0, r5, c7, c6, 2
+ bgt 2b
+ cmp r2, #0
+ bgt 1b
+ dsb
+ isb
+ mov pc, lr
+ENDPROC(v7_invalidate_l1)
+
+/*
* v7_flush_icache_all()
*
* Flush the whole I-cache.
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index bc4a5e9ebb78..7a0511191f6b 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -34,6 +34,9 @@
* The ASID is used to tag entries in the CPU caches and TLBs.
* The context ID is used by debuggers and trace logic, and
* should be unique within all running processes.
+ *
+ * In big endian operation, the two 32 bit words are swapped if accesed by
+ * non 64-bit operations.
*/
#define ASID_FIRST_VERSION (1ULL << ASID_BITS)
#define NUM_USER_ASIDS (ASID_FIRST_VERSION - 1)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 076c26d43864..dda3904dc64c 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -640,7 +640,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
if (is_coherent || nommu())
addr = __alloc_simple_buffer(dev, size, gfp, &page);
- else if (gfp & GFP_ATOMIC)
+ else if (!(gfp & __GFP_WAIT))
addr = __alloc_from_pool(size, &page);
else if (!IS_ENABLED(CONFIG_CMA))
addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller);
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index 99db769307ec..2dffc010cc41 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -1,4 +1,6 @@
+#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <asm/cputype.h>
#include <asm/idmap.h>
@@ -6,6 +8,7 @@
#include <asm/pgtable.h>
#include <asm/sections.h>
#include <asm/system_info.h>
+#include <asm/virt.h>
pgd_t *idmap_pgd;
@@ -59,11 +62,17 @@ static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
} while (pud++, addr = next, addr != end);
}
-static void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
+static void identity_mapping_add(pgd_t *pgd, const char *text_start,
+ const char *text_end, unsigned long prot)
{
- unsigned long prot, next;
+ unsigned long addr, end;
+ unsigned long next;
+
+ addr = virt_to_phys(text_start);
+ end = virt_to_phys(text_end);
+
+ prot |= PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF;
- prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF;
if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
prot |= PMD_BIT4;
@@ -74,28 +83,52 @@ static void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long e
} while (pgd++, addr = next, addr != end);
}
+#if defined(CONFIG_ARM_VIRT_EXT) && defined(CONFIG_ARM_LPAE)
+pgd_t *hyp_pgd;
+
+extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[];
+
+static int __init init_static_idmap_hyp(void)
+{
+ hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
+ if (!hyp_pgd)
+ return -ENOMEM;
+
+ pr_info("Setting up static HYP identity map for 0x%p - 0x%p\n",
+ __hyp_idmap_text_start, __hyp_idmap_text_end);
+ identity_mapping_add(hyp_pgd, __hyp_idmap_text_start,
+ __hyp_idmap_text_end, PMD_SECT_AP1);
+
+ return 0;
+}
+#else
+static int __init init_static_idmap_hyp(void)
+{
+ return 0;
+}
+#endif
+
extern char __idmap_text_start[], __idmap_text_end[];
static int __init init_static_idmap(void)
{
- phys_addr_t idmap_start, idmap_end;
+ int ret;
idmap_pgd = pgd_alloc(&init_mm);
if (!idmap_pgd)
return -ENOMEM;
- /* Add an identity mapping for the physical address of the section. */
- idmap_start = virt_to_phys((void *)__idmap_text_start);
- idmap_end = virt_to_phys((void *)__idmap_text_end);
+ pr_info("Setting up static identity map for 0x%p - 0x%p\n",
+ __idmap_text_start, __idmap_text_end);
+ identity_mapping_add(idmap_pgd, __idmap_text_start,
+ __idmap_text_end, 0);
- pr_info("Setting up static identity map for 0x%llx - 0x%llx\n",
- (long long)idmap_start, (long long)idmap_end);
- identity_mapping_add(idmap_pgd, idmap_start, idmap_end);
+ ret = init_static_idmap_hyp();
/* Flush L1 for the hardware to see this page table content */
flush_cache_louis();
- return 0;
+ return ret;
}
early_initcall(init_static_idmap);
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 88fd86cf3d9a..04d9006eab1f 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -39,6 +39,70 @@
#include <asm/mach/pci.h>
#include "mm.h"
+
+LIST_HEAD(static_vmlist);
+
+static struct static_vm *find_static_vm_paddr(phys_addr_t paddr,
+ size_t size, unsigned int mtype)
+{
+ struct static_vm *svm;
+ struct vm_struct *vm;
+
+ list_for_each_entry(svm, &static_vmlist, list) {
+ vm = &svm->vm;
+ if (!(vm->flags & VM_ARM_STATIC_MAPPING))
+ continue;
+ if ((vm->flags & VM_ARM_MTYPE_MASK) != VM_ARM_MTYPE(mtype))
+ continue;
+
+ if (vm->phys_addr > paddr ||
+ paddr + size - 1 > vm->phys_addr + vm->size - 1)
+ continue;
+
+ return svm;
+ }
+
+ return NULL;
+}
+
+struct static_vm *find_static_vm_vaddr(void *vaddr)
+{
+ struct static_vm *svm;
+ struct vm_struct *vm;
+
+ list_for_each_entry(svm, &static_vmlist, list) {
+ vm = &svm->vm;
+
+ /* static_vmlist is ascending order */
+ if (vm->addr > vaddr)
+ break;
+
+ if (vm->addr <= vaddr && vm->addr + vm->size > vaddr)
+ return svm;
+ }
+
+ return NULL;
+}
+
+void __init add_static_vm_early(struct static_vm *svm)
+{
+ struct static_vm *curr_svm;
+ struct vm_struct *vm;
+ void *vaddr;
+
+ vm = &svm->vm;
+ vm_area_add_early(vm);
+ vaddr = vm->addr;
+
+ list_for_each_entry(curr_svm, &static_vmlist, list) {
+ vm = &curr_svm->vm;
+
+ if (vm->addr > vaddr)
+ break;
+ }
+ list_add_tail(&svm->list, &curr_svm->list);
+}
+
int ioremap_page(unsigned long virt, unsigned long phys,
const struct mem_type *mtype)
{
@@ -197,13 +261,14 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
const struct mem_type *type;
int err;
unsigned long addr;
- struct vm_struct * area;
+ struct vm_struct *area;
+ phys_addr_t paddr = __pfn_to_phys(pfn);
#ifndef CONFIG_ARM_LPAE
/*
* High mappings must be supersection aligned
*/
- if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK))
+ if (pfn >= 0x100000 && (paddr & ~SUPERSECTION_MASK))
return NULL;
#endif
@@ -219,24 +284,16 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
/*
* Try to reuse one of the static mapping whenever possible.
*/
- read_lock(&vmlist_lock);
- for (area = vmlist; area; area = area->next) {
- if (!size || (sizeof(phys_addr_t) == 4 && pfn >= 0x100000))
- break;
- if (!(area->flags & VM_ARM_STATIC_MAPPING))
- continue;
- if ((area->flags & VM_ARM_MTYPE_MASK) != VM_ARM_MTYPE(mtype))
- continue;
- if (__phys_to_pfn(area->phys_addr) > pfn ||
- __pfn_to_phys(pfn) + size-1 > area->phys_addr + area->size-1)
- continue;
- /* we can drop the lock here as we know *area is static */
- read_unlock(&vmlist_lock);
- addr = (unsigned long)area->addr;
- addr += __pfn_to_phys(pfn) - area->phys_addr;
- return (void __iomem *) (offset + addr);
+ if (size && !(sizeof(phys_addr_t) == 4 && pfn >= 0x100000)) {
+ struct static_vm *svm;
+
+ svm = find_static_vm_paddr(paddr, size, mtype);
+ if (svm) {
+ addr = (unsigned long)svm->vm.addr;
+ addr += paddr - svm->vm.phys_addr;
+ return (void __iomem *) (offset + addr);
+ }
}
- read_unlock(&vmlist_lock);
/*
* Don't allow RAM to be mapped - this causes problems with ARMv6+
@@ -248,21 +305,21 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
if (!area)
return NULL;
addr = (unsigned long)area->addr;
- area->phys_addr = __pfn_to_phys(pfn);
+ area->phys_addr = paddr;
#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE)
if (DOMAIN_IO == 0 &&
(((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
cpu_is_xsc3()) && pfn >= 0x100000 &&
- !((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) {
+ !((paddr | size | addr) & ~SUPERSECTION_MASK)) {
area->flags |= VM_ARM_SECTION_MAPPING;
err = remap_area_supersections(addr, pfn, size, type);
- } else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) {
+ } else if (!((paddr | size | addr) & ~PMD_MASK)) {
area->flags |= VM_ARM_SECTION_MAPPING;
err = remap_area_sections(addr, pfn, size, type);
} else
#endif
- err = ioremap_page_range(addr, addr + size, __pfn_to_phys(pfn),
+ err = ioremap_page_range(addr, addr + size, paddr,
__pgprot(type->prot_pte));
if (err) {
@@ -346,34 +403,28 @@ __arm_ioremap_exec(unsigned long phys_addr, size_t size, bool cached)
void __iounmap(volatile void __iomem *io_addr)
{
void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr);
- struct vm_struct *vm;
+ struct static_vm *svm;
+
+ /* If this is a static mapping, we must leave it alone */
+ svm = find_static_vm_vaddr(addr);
+ if (svm)
+ return;
- read_lock(&vmlist_lock);
- for (vm = vmlist; vm; vm = vm->next) {
- if (vm->addr > addr)
- break;
- if (!(vm->flags & VM_IOREMAP))
- continue;
- /* If this is a static mapping we must leave it alone */
- if ((vm->flags & VM_ARM_STATIC_MAPPING) &&
- (vm->addr <= addr) && (vm->addr + vm->size > addr)) {
- read_unlock(&vmlist_lock);
- return;
- }
#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE)
+ {
+ struct vm_struct *vm;
+
+ vm = find_vm_area(addr);
+
/*
* If this is a section based mapping we need to handle it
* specially as the VM subsystem does not know how to handle
* such a beast.
*/
- if ((vm->addr == addr) &&
- (vm->flags & VM_ARM_SECTION_MAPPING)) {
+ if (vm && (vm->flags & VM_ARM_SECTION_MAPPING))
unmap_area_sections((unsigned long)vm->addr, vm->size);
- break;
- }
-#endif
}
- read_unlock(&vmlist_lock);
+#endif
vunmap(addr);
}
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index a8ee92da3544..d5a4e9ad8f0f 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -1,4 +1,6 @@
#ifdef CONFIG_MMU
+#include <linux/list.h>
+#include <linux/vmalloc.h>
/* the upper-most page table pointer */
extern pmd_t *top_pmd;
@@ -65,6 +67,16 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page
/* consistent regions used by dma_alloc_attrs() */
#define VM_ARM_DMA_CONSISTENT 0x20000000
+
+struct static_vm {
+ struct vm_struct vm;
+ struct list_head list;
+};
+
+extern struct list_head static_vmlist;
+extern struct static_vm *find_static_vm_vaddr(void *vaddr);
+extern __init void add_static_vm_early(struct static_vm *svm);
+
#endif
#ifdef CONFIG_ZONE_DMA
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index ce328c7f5c94..e95a996ab78f 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -57,6 +57,9 @@ static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
static unsigned int ecc_mask __initdata = 0;
pgprot_t pgprot_user;
pgprot_t pgprot_kernel;
+pgprot_t pgprot_hyp_device;
+pgprot_t pgprot_s2;
+pgprot_t pgprot_s2_device;
EXPORT_SYMBOL(pgprot_user);
EXPORT_SYMBOL(pgprot_kernel);
@@ -66,34 +69,46 @@ struct cachepolicy {
unsigned int cr_mask;
pmdval_t pmd;
pteval_t pte;
+ pteval_t pte_s2;
};
+#ifdef CONFIG_ARM_LPAE
+#define s2_policy(policy) policy
+#else
+#define s2_policy(policy) 0
+#endif
+
static struct cachepolicy cache_policies[] __initdata = {
{
.policy = "uncached",
.cr_mask = CR_W|CR_C,
.pmd = PMD_SECT_UNCACHED,
.pte = L_PTE_MT_UNCACHED,
+ .pte_s2 = s2_policy(L_PTE_S2_MT_UNCACHED),
}, {
.policy = "buffered",
.cr_mask = CR_C,
.pmd = PMD_SECT_BUFFERED,
.pte = L_PTE_MT_BUFFERABLE,
+ .pte_s2 = s2_policy(L_PTE_S2_MT_UNCACHED),
}, {
.policy = "writethrough",
.cr_mask = 0,
.pmd = PMD_SECT_WT,
.pte = L_PTE_MT_WRITETHROUGH,
+ .pte_s2 = s2_policy(L_PTE_S2_MT_WRITETHROUGH),
}, {
.policy = "writeback",
.cr_mask = 0,
.pmd = PMD_SECT_WB,
.pte = L_PTE_MT_WRITEBACK,
+ .pte_s2 = s2_policy(L_PTE_S2_MT_WRITEBACK),
}, {
.policy = "writealloc",
.cr_mask = 0,
.pmd = PMD_SECT_WBWA,
.pte = L_PTE_MT_WRITEALLOC,
+ .pte_s2 = s2_policy(L_PTE_S2_MT_WRITEBACK),
}
};
@@ -310,6 +325,7 @@ static void __init build_mem_type_table(void)
struct cachepolicy *cp;
unsigned int cr = get_cr();
pteval_t user_pgprot, kern_pgprot, vecs_pgprot;
+ pteval_t hyp_device_pgprot, s2_pgprot, s2_device_pgprot;
int cpu_arch = cpu_architecture();
int i;
@@ -421,6 +437,8 @@ static void __init build_mem_type_table(void)
*/
cp = &cache_policies[cachepolicy];
vecs_pgprot = kern_pgprot = user_pgprot = cp->pte;
+ s2_pgprot = cp->pte_s2;
+ hyp_device_pgprot = s2_device_pgprot = mem_types[MT_DEVICE].prot_pte;
/*
* ARMv6 and above have extended page tables.
@@ -444,6 +462,7 @@ static void __init build_mem_type_table(void)
user_pgprot |= L_PTE_SHARED;
kern_pgprot |= L_PTE_SHARED;
vecs_pgprot |= L_PTE_SHARED;
+ s2_pgprot |= L_PTE_SHARED;
mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_S;
mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_SHARED;
mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_S;
@@ -498,6 +517,9 @@ static void __init build_mem_type_table(void)
pgprot_user = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | user_pgprot);
pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
L_PTE_DIRTY | kern_pgprot);
+ pgprot_s2 = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | s2_pgprot);
+ pgprot_s2_device = __pgprot(s2_device_pgprot);
+ pgprot_hyp_device = __pgprot(hyp_device_pgprot);
mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask;
mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask;
@@ -757,21 +779,24 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
{
struct map_desc *md;
struct vm_struct *vm;
+ struct static_vm *svm;
if (!nr)
return;
- vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
+ svm = early_alloc_aligned(sizeof(*svm) * nr, __alignof__(*svm));
for (md = io_desc; nr; md++, nr--) {
create_mapping(md);
+
+ vm = &svm->vm;
vm->addr = (void *)(md->virtual & PAGE_MASK);
vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
vm->phys_addr = __pfn_to_phys(md->pfn);
vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
vm->flags |= VM_ARM_MTYPE(md->type);
vm->caller = iotable_init;
- vm_area_add_early(vm++);
+ add_static_vm_early(svm++);
}
}
@@ -779,13 +804,16 @@ void __init vm_reserve_area_early(unsigned long addr, unsigned long size,
void *caller)
{
struct vm_struct *vm;
+ struct static_vm *svm;
+
+ svm = early_alloc_aligned(sizeof(*svm), __alignof__(*svm));
- vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
+ vm = &svm->vm;
vm->addr = (void *)addr;
vm->size = size;
vm->flags = VM_IOREMAP | VM_ARM_EMPTY_MAPPING;
vm->caller = caller;
- vm_area_add_early(vm);
+ add_static_vm_early(svm);
}
#ifndef CONFIG_ARM_LPAE
@@ -810,14 +838,13 @@ static void __init pmd_empty_section_gap(unsigned long addr)
static void __init fill_pmd_gaps(void)
{
+ struct static_vm *svm;
struct vm_struct *vm;
unsigned long addr, next = 0;
pmd_t *pmd;
- /* we're still single threaded hence no lock needed here */
- for (vm = vmlist; vm; vm = vm->next) {
- if (!(vm->flags & (VM_ARM_STATIC_MAPPING | VM_ARM_EMPTY_MAPPING)))
- continue;
+ list_for_each_entry(svm, &static_vmlist, list) {
+ vm = &svm->vm;
addr = (unsigned long)vm->addr;
if (addr < next)
continue;
@@ -857,19 +884,12 @@ static void __init fill_pmd_gaps(void)
#if defined(CONFIG_PCI) && !defined(CONFIG_NEED_MACH_IO_H)
static void __init pci_reserve_io(void)
{
- struct vm_struct *vm;
- unsigned long addr;
+ struct static_vm *svm;
- /* we're still single threaded hence no lock needed here */
- for (vm = vmlist; vm; vm = vm->next) {
- if (!(vm->flags & VM_ARM_STATIC_MAPPING))
- continue;
- addr = (unsigned long)vm->addr;
- addr &= ~(SZ_2M - 1);
- if (addr == PCI_IO_VIRT_BASE)
- return;
+ svm = find_static_vm_vaddr((void *)PCI_IO_VIRT_BASE);
+ if (svm)
+ return;
- }
vm_reserve_area_early(PCI_IO_VIRT_BASE, SZ_2M, pci_reserve_io);
}
#else
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index eb6aa73bc8b7..f9a0aa725ea9 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -38,9 +38,14 @@
/*
* mmid - get context id from mm pointer (mm->context.id)
+ * note, this field is 64bit, so in big-endian the two words are swapped too.
*/
.macro mmid, rd, rn
+#ifdef __ARMEB__
+ ldr \rd, [\rn, #MM_CONTEXT_ID + 4 ]
+#else
ldr \rd, [\rn, #MM_CONTEXT_ID]
+#endif
.endm
/*
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 09c5233f4dfc..bcaaa8de9325 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -101,7 +101,7 @@ ENTRY(cpu_v6_dcache_clean_area)
ENTRY(cpu_v6_switch_mm)
#ifdef CONFIG_MMU
mov r2, #0
- ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
+ mmid r1, r1 @ get mm->context.id
ALT_SMP(orr r0, r0, #TTB_FLAGS_SMP)
ALT_UP(orr r0, r0, #TTB_FLAGS_UP)
mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
index 6d98c13ab827..78f520bc0e99 100644
--- a/arch/arm/mm/proc-v7-2level.S
+++ b/arch/arm/mm/proc-v7-2level.S
@@ -40,7 +40,7 @@
ENTRY(cpu_v7_switch_mm)
#ifdef CONFIG_MMU
mov r2, #0
- ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
+ mmid r1, r1 @ get mm->context.id
ALT_SMP(orr r0, r0, #TTB_FLAGS_SMP)
ALT_UP(orr r0, r0, #TTB_FLAGS_UP)
#ifdef CONFIG_ARM_ERRATA_430973
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
index 7b56386f9496..50bf1dafc9ea 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -47,7 +47,7 @@
*/
ENTRY(cpu_v7_switch_mm)
#ifdef CONFIG_MMU
- ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
+ mmid r1, r1 @ get mm->context.id
and r3, r1, #0xff
mov r3, r3, lsl #(48 - 32) @ ASID
mcrr p15, 0, r0, r3, c2 @ set TTB 0
diff --git a/arch/arm/mm/vmregion.c b/arch/arm/mm/vmregion.c
deleted file mode 100644
index a631016e1f8f..000000000000
--- a/arch/arm/mm/vmregion.c
+++ /dev/null
@@ -1,205 +0,0 @@
-#include <linux/fs.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-
-#include "vmregion.h"
-
-/*
- * VM region handling support.
- *
- * This should become something generic, handling VM region allocations for
- * vmalloc and similar (ioremap, module space, etc).
- *
- * I envisage vmalloc()'s supporting vm_struct becoming:
- *
- * struct vm_struct {
- * struct vmregion region;
- * unsigned long flags;
- * struct page **pages;
- * unsigned int nr_pages;
- * unsigned long phys_addr;
- * };
- *
- * get_vm_area() would then call vmregion_alloc with an appropriate
- * struct vmregion head (eg):
- *
- * struct vmregion vmalloc_head = {
- * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list),
- * .vm_start = VMALLOC_START,
- * .vm_end = VMALLOC_END,
- * };
- *
- * However, vmalloc_head.vm_start is variable (typically, it is dependent on
- * the amount of RAM found at boot time.) I would imagine that get_vm_area()
- * would have to initialise this each time prior to calling vmregion_alloc().
- */
-
-struct arm_vmregion *
-arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
- size_t size, gfp_t gfp, const void *caller)
-{
- unsigned long start = head->vm_start, addr = head->vm_end;
- unsigned long flags;
- struct arm_vmregion *c, *new;
-
- if (head->vm_end - head->vm_start < size) {
- printk(KERN_WARNING "%s: allocation too big (requested %#x)\n",
- __func__, size);
- goto out;
- }
-
- new = kmalloc(sizeof(struct arm_vmregion), gfp);
- if (!new)
- goto out;
-
- new->caller = caller;
-
- spin_lock_irqsave(&head->vm_lock, flags);
-
- addr = rounddown(addr - size, align);
- list_for_each_entry_reverse(c, &head->vm_list, vm_list) {
- if (addr >= c->vm_end)
- goto found;
- addr = rounddown(c->vm_start - size, align);
- if (addr < start)
- goto nospc;
- }
-
- found:
- /*
- * Insert this entry after the one we found.
- */
- list_add(&new->vm_list, &c->vm_list);
- new->vm_start = addr;
- new->vm_end = addr + size;
- new->vm_active = 1;
-
- spin_unlock_irqrestore(&head->vm_lock, flags);
- return new;
-
- nospc:
- spin_unlock_irqrestore(&head->vm_lock, flags);
- kfree(new);
- out:
- return NULL;
-}
-
-static struct arm_vmregion *__arm_vmregion_find(struct arm_vmregion_head *head, unsigned long addr)
-{
- struct arm_vmregion *c;
-
- list_for_each_entry(c, &head->vm_list, vm_list) {
- if (c->vm_active && c->vm_start == addr)
- goto out;
- }
- c = NULL;
- out:
- return c;
-}
-
-struct arm_vmregion *arm_vmregion_find(struct arm_vmregion_head *head, unsigned long addr)
-{
- struct arm_vmregion *c;
- unsigned long flags;
-
- spin_lock_irqsave(&head->vm_lock, flags);
- c = __arm_vmregion_find(head, addr);
- spin_unlock_irqrestore(&head->vm_lock, flags);
- return c;
-}
-
-struct arm_vmregion *arm_vmregion_find_remove(struct arm_vmregion_head *head, unsigned long addr)
-{
- struct arm_vmregion *c;
- unsigned long flags;
-
- spin_lock_irqsave(&head->vm_lock, flags);
- c = __arm_vmregion_find(head, addr);
- if (c)
- c->vm_active = 0;
- spin_unlock_irqrestore(&head->vm_lock, flags);
- return c;
-}
-
-void arm_vmregion_free(struct arm_vmregion_head *head, struct arm_vmregion *c)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&head->vm_lock, flags);
- list_del(&c->vm_list);
- spin_unlock_irqrestore(&head->vm_lock, flags);
-
- kfree(c);
-}
-
-#ifdef CONFIG_PROC_FS
-static int arm_vmregion_show(struct seq_file *m, void *p)
-{
- struct arm_vmregion *c = list_entry(p, struct arm_vmregion, vm_list);
-
- seq_printf(m, "0x%08lx-0x%08lx %7lu", c->vm_start, c->vm_end,
- c->vm_end - c->vm_start);
- if (c->caller)
- seq_printf(m, " %pS", (void *)c->caller);
- seq_putc(m, '\n');
- return 0;
-}
-
-static void *arm_vmregion_start(struct seq_file *m, loff_t *pos)
-{
- struct arm_vmregion_head *h = m->private;
- spin_lock_irq(&h->vm_lock);
- return seq_list_start(&h->vm_list, *pos);
-}
-
-static void *arm_vmregion_next(struct seq_file *m, void *p, loff_t *pos)
-{
- struct arm_vmregion_head *h = m->private;
- return seq_list_next(p, &h->vm_list, pos);
-}
-
-static void arm_vmregion_stop(struct seq_file *m, void *p)
-{
- struct arm_vmregion_head *h = m->private;
- spin_unlock_irq(&h->vm_lock);
-}
-
-static const struct seq_operations arm_vmregion_ops = {
- .start = arm_vmregion_start,
- .stop = arm_vmregion_stop,
- .next = arm_vmregion_next,
- .show = arm_vmregion_show,
-};
-
-static int arm_vmregion_open(struct inode *inode, struct file *file)
-{
- struct arm_vmregion_head *h = PDE(inode)->data;
- int ret = seq_open(file, &arm_vmregion_ops);
- if (!ret) {
- struct seq_file *m = file->private_data;
- m->private = h;
- }
- return ret;
-}
-
-static const struct file_operations arm_vmregion_fops = {
- .open = arm_vmregion_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
-{
- proc_create_data(path, S_IRUSR, NULL, &arm_vmregion_fops, h);
- return 0;
-}
-#else
-int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
-{
- return 0;
-}
-#endif
diff --git a/arch/arm/mm/vmregion.h b/arch/arm/mm/vmregion.h
deleted file mode 100644
index 0f5a5f2a2c7b..000000000000
--- a/arch/arm/mm/vmregion.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef VMREGION_H
-#define VMREGION_H
-
-#include <linux/spinlock.h>
-#include <linux/list.h>
-
-struct page;
-
-struct arm_vmregion_head {
- spinlock_t vm_lock;
- struct list_head vm_list;
- unsigned long vm_start;
- unsigned long vm_end;
-};
-
-struct arm_vmregion {
- struct list_head vm_list;
- unsigned long vm_start;
- unsigned long vm_end;
- int vm_active;
- const void *caller;
-};
-
-struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, size_t, gfp_t, const void *);
-struct arm_vmregion *arm_vmregion_find(struct arm_vmregion_head *, unsigned long);
-struct arm_vmregion *arm_vmregion_find_remove(struct arm_vmregion_head *, unsigned long);
-void arm_vmregion_free(struct arm_vmregion_head *, struct arm_vmregion *);
-
-int arm_vmregion_create_proc(const char *, struct arm_vmregion_head *);
-
-#endif
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index a34f1e214116..6828ef6ce80e 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -341,10 +341,17 @@ static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx)
static inline void emit_swap16(u8 r_dst, u8 r_src, struct jit_ctx *ctx)
{
- emit(ARM_LSL_R(ARM_R1, r_src, 8), ctx);
- emit(ARM_ORR_S(r_dst, ARM_R1, r_src, SRTYPE_LSL, 8), ctx);
- emit(ARM_LSL_I(r_dst, r_dst, 8), ctx);
- emit(ARM_LSL_R(r_dst, r_dst, 8), ctx);
+ /* r_dst = (r_src << 8) | (r_src >> 8) */
+ emit(ARM_LSL_I(ARM_R1, r_src, 8), ctx);
+ emit(ARM_ORR_S(r_dst, ARM_R1, r_src, SRTYPE_LSR, 8), ctx);
+
+ /*
+ * we need to mask out the bits set in r_dst[23:16] due to
+ * the first shift instruction.
+ *
+ * note that 0x8ff is the encoded immediate 0x00ff0000.
+ */
+ emit(ARM_BIC_I(r_dst, r_dst, 0x8ff), ctx);
}
#else /* ARMv6+ */
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
index cbfbbe461788..837a2d52e9db 100644
--- a/arch/arm/plat-iop/time.c
+++ b/arch/arm/plat-iop/time.c
@@ -156,14 +156,9 @@ void __init iop_init_time(unsigned long tick_rate)
write_tmr0(timer_ctl & ~IOP_TMR_EN);
write_tisr(1);
setup_irq(IRQ_IOP_TIMER0, &iop_timer_irq);
- clockevents_calc_mult_shift(&iop_clockevent,
- tick_rate, IOP_MIN_RANGE);
- iop_clockevent.max_delta_ns =
- clockevent_delta2ns(0xfffffffe, &iop_clockevent);
- iop_clockevent.min_delta_ns =
- clockevent_delta2ns(0xf, &iop_clockevent);
iop_clockevent.cpumask = cpumask_of(0);
- clockevents_register_device(&iop_clockevent);
+ clockevents_config_and_register(&iop_clockevent, tick_rate,
+ 0xf, 0xfffffffe);
/*
* Set up free-running clocksource timer 1.
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 665870dce3c8..67c859cf16bc 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -5,36 +5,6 @@ menu "TI OMAP Common Features"
config ARCH_OMAP_OTG
bool
-choice
- prompt "OMAP System Type"
- default ARCH_OMAP2PLUS
-
-config ARCH_OMAP1
- bool "TI OMAP1"
- select CLKDEV_LOOKUP
- select CLKSRC_MMIO
- select GENERIC_IRQ_CHIP
- select HAVE_IDE
- select IRQ_DOMAIN
- select NEED_MACH_IO_H if PCCARD
- select NEED_MACH_MEMORY_H
- 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
- select PINCTRL
- select PROC_DEVICETREE if PROC_FS
- select SPARSE_IRQ
- select USE_OF
- help
- "Systems based on OMAP2, OMAP3, OMAP4 or OMAP5"
-
-endchoice
-
comment "OMAP Feature Selections"
config OMAP_DEBUG_DEVICES
@@ -118,7 +88,7 @@ config OMAP_MUX_WARNINGS
config OMAP_MBOX_FWK
tristate "Mailbox framework support"
- depends on ARCH_OMAP
+ depends on ARCH_OMAP && !ARCH_MULTIPLATFORM
help
Say Y here if you want to use OMAP Mailbox framework support for
DSP, IVA1.0 and IVA2 in OMAP1/2/3.
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index a14a78a2f149..31199417b56a 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -2,6 +2,8 @@
# Makefile for the linux kernel.
#
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-omap/include
+
# Common support
obj-y := sram.o dma.o counter_32k.o
obj-m :=
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 4136b20cba3c..e06c34bdc34a 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -2019,7 +2019,7 @@ static int omap_system_dma_probe(struct platform_device *pdev)
errata = p->errata;
if ((d->dev_caps & RESERVE_CHANNEL) && omap_dma_reserve_channels
- && (omap_dma_reserve_channels <= dma_lch_count))
+ && (omap_dma_reserve_channels < d->lch_count))
d->lch_count = omap_dma_reserve_channels;
dma_lch_count = d->lch_count;
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 7b433f3bddca..a0daa2fb5de6 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -808,11 +808,9 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
return -ENOMEM;
}
- timer->io_base = devm_request_and_ioremap(dev, mem);
- if (!timer->io_base) {
- dev_err(dev, "%s: region already claimed.\n", __func__);
- return -ENOMEM;
- }
+ timer->io_base = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(timer->io_base))
+ return PTR_ERR(timer->io_base);
if (dev->of_node) {
if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index f9df624d108c..58213d9714cd 100644
--- a/arch/arm/plat-omap/i2c.c
+++ b/arch/arm/plat-omap/i2c.c
@@ -68,7 +68,7 @@ __setup("i2c_bus=", omap_i2c_bus_setup);
* Register busses defined in command line but that are not registered with
* omap_register_i2c_bus from board initialization code.
*/
-static int __init omap_register_i2c_bus_cmdline(void)
+int __init omap_register_i2c_bus_cmdline(void)
{
int i, err = 0;
@@ -83,7 +83,6 @@ static int __init omap_register_i2c_bus_cmdline(void)
out:
return err;
}
-subsys_initcall(omap_register_i2c_bus_cmdline);
/**
* omap_register_i2c_bus - register I2C bus with device descriptors
diff --git a/arch/arm/plat-omap/include/plat/i2c.h b/arch/arm/plat-omap/include/plat/i2c.h
index 7a9028cb5a75..810629d79668 100644
--- a/arch/arm/plat-omap/include/plat/i2c.h
+++ b/arch/arm/plat-omap/include/plat/i2c.h
@@ -32,6 +32,7 @@ int omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
struct i2c_board_info const *info,
unsigned len);
+extern int omap_register_i2c_bus_cmdline(void);
#else
static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,
struct i2c_board_info const *info,
@@ -39,6 +40,11 @@ static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,
{
return 0;
}
+
+static inline int omap_register_i2c_bus_cmdline(void)
+{
+ return 0;
+}
#endif
struct omap_hwmod;
diff --git a/arch/arm/plat-orion/mpp.c b/arch/arm/plat-orion/mpp.c
index e686fe76a96b..7310bcfb299f 100644
--- a/arch/arm/plat-orion/mpp.c
+++ b/arch/arm/plat-orion/mpp.c
@@ -49,7 +49,7 @@ void __init orion_mpp_conf(unsigned int *mpp_list, unsigned int variant_mask,
"number (%u)\n", num);
continue;
}
- if (variant_mask & !(*mpp_list & variant_mask)) {
+ if (variant_mask && !(*mpp_list & variant_mask)) {
printk(KERN_WARNING
"orion_mpp_conf: requested MPP%u config "
"unavailable on this hardware\n", num);
diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c
index 0f4fa863dd55..5d5ac0f05422 100644
--- a/arch/arm/plat-orion/time.c
+++ b/arch/arm/plat-orion/time.c
@@ -156,7 +156,6 @@ orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
static struct clock_event_device orion_clkevt = {
.name = "orion_tick",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
- .shift = 32,
.rating = 300,
.set_next_event = orion_clkevt_next_event,
.set_mode = orion_clkevt_mode,
@@ -221,9 +220,6 @@ orion_time_init(void __iomem *_bridge_base, u32 _bridge_timer1_clr_mask,
* Setup clockevent timer (interrupt-driven).
*/
setup_irq(irq, &orion_timer_irq);
- orion_clkevt.mult = div_sc(tclk, NSEC_PER_SEC, orion_clkevt.shift);
- orion_clkevt.max_delta_ns = clockevent_delta2ns(0xfffffffe, &orion_clkevt);
- orion_clkevt.min_delta_ns = clockevent_delta2ns(1, &orion_clkevt);
orion_clkevt.cpumask = cpumask_of(0);
- clockevents_register_device(&orion_clkevt);
+ clockevents_config_and_register(&orion_clkevt, tclk, 1, 0xfffffffe);
}
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
deleted file mode 100644
index eef3b6a2f8a8..000000000000
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ /dev/null
@@ -1,116 +0,0 @@
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-config PLAT_S3C24XX
- bool
- depends on ARCH_S3C24XX
- default y
- select ARCH_REQUIRE_GPIOLIB
- select NO_IOPORT
- select S3C_DEV_NAND
- help
- Base platform code for any Samsung S3C24XX device
-
-if PLAT_S3C24XX
-
-# low-level serial option nodes
-
-config CPU_LLSERIAL_S3C2410_ONLY
- bool
- default y if CPU_LLSERIAL_S3C2410 && !CPU_LLSERIAL_S3C2440
-
-config CPU_LLSERIAL_S3C2440_ONLY
- bool
- default y if CPU_LLSERIAL_S3C2440 && !CPU_LLSERIAL_S3C2410
-
-config CPU_LLSERIAL_S3C2410
- bool
- help
- Selected if there is an S3C2410 (or register compatible) serial
- low-level implementation needed
-
-config CPU_LLSERIAL_S3C2440
- bool
- help
- Selected if there is an S3C2440 (or register compatible) serial
- low-level implementation needed
-
-# code that is shared between a number of the s3c24xx implementations
-
-config S3C2410_CLOCK
- bool
- help
- Clock code for the S3C2410, and similar processors which
- is currently includes the S3C2410, S3C2440, S3C2442.
-
-config S3C24XX_DCLK
- bool
- help
- Clock code for supporting DCLK/CLKOUT on S3C24XX architectures
-
-# gpio configurations
-
-config S3C24XX_GPIO_EXTRA
- int
- default 128 if S3C24XX_GPIO_EXTRA128
- default 64 if S3C24XX_GPIO_EXTRA64
- default 16 if ARCH_H1940
- default 0
-
-config S3C24XX_GPIO_EXTRA64
- bool
- help
- Add an extra 64 gpio numbers to the available GPIO pool. This is
- available for boards that need extra gpios for external devices.
-
-config S3C24XX_GPIO_EXTRA128
- bool
- help
- Add an extra 128 gpio numbers to the available GPIO pool. This is
- available for boards that need extra gpios for external devices.
-
-config S3C24XX_DMA
- bool "S3C2410 DMA support"
- depends on ARCH_S3C24XX
- select S3C_DMA
- help
- S3C2410 DMA support. This is needed for drivers like sound which
- use the S3C2410's DMA system to move data to and from the
- peripheral blocks.
-
-config S3C2410_DMA_DEBUG
- bool "S3C2410 DMA support debug"
- depends on ARCH_S3C24XX && S3C2410_DMA
- help
- Enable debugging output for the DMA code. This option sends info
- to the kernel log, at priority KERN_DEBUG.
-
-# common code for s3c24xx based machines, such as the SMDKs.
-
-# cpu frequency items common between s3c2410 and s3c2440/s3c2442
-
-config S3C2410_IOTIMING
- bool
- depends on CPU_FREQ_S3C24XX
- help
- Internal node to select io timing code that is common to the s3c2410
- and s3c2440/s3c2442 cpu frequency support.
-
-config S3C2410_CPUFREQ_UTILS
- bool
- depends on CPU_FREQ_S3C24XX
- help
- Internal node to select timing code that is common to the s3c2410
- and s3c2440/s3c244 cpu frequency support.
-
-# cpu frequency support common to s3c2412, s3c2413 and s3c2442
-
-config S3C2412_IOTIMING
- bool
- depends on CPU_FREQ_S3C24XX && (CPU_S3C2412 || CPU_S3C2443)
- help
- Intel node to select io timing code that is common to the s3c2412
- and the s3c2443.
-
-endif
diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile
deleted file mode 100644
index 9f60549c8da1..000000000000
--- a/arch/arm/plat-s3c24xx/Makefile
+++ /dev/null
@@ -1,27 +0,0 @@
-# arch/arm/plat-s3c24xx/Makefile
-#
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
-
-# Core files
-
-obj-y += irq.o
-obj-$(CONFIG_S3C24XX_DCLK) += clock-dclk.o
-
-obj-$(CONFIG_CPU_FREQ_S3C24XX) += cpu-freq.o
-obj-$(CONFIG_CPU_FREQ_S3C24XX_DEBUGFS) += cpu-freq-debugfs.o
-
-# Architecture dependent builds
-
-obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
-obj-$(CONFIG_S3C24XX_DMA) += dma.o
-obj-$(CONFIG_S3C2410_IOTIMING) += s3c2410-iotiming.o
-obj-$(CONFIG_S3C2412_IOTIMING) += s3c2412-iotiming.o
-obj-$(CONFIG_S3C2410_CPUFREQ_UTILS) += s3c2410-cpufreq-utils.o
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
deleted file mode 100644
index fe57bbbf166b..000000000000
--- a/arch/arm/plat-s3c24xx/irq.c
+++ /dev/null
@@ -1,676 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/irq.c
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-
-#include <asm/irq.h>
-#include <asm/mach/irq.h>
-
-#include <plat/regs-irqtype.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-
-static void
-s3c_irq_mask(struct irq_data *data)
-{
- unsigned int irqno = data->irq - IRQ_EINT0;
- unsigned long mask;
-
- mask = __raw_readl(S3C2410_INTMSK);
- mask |= 1UL << irqno;
- __raw_writel(mask, S3C2410_INTMSK);
-}
-
-static inline void
-s3c_irq_ack(struct irq_data *data)
-{
- unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
-
- __raw_writel(bitval, S3C2410_SRCPND);
- __raw_writel(bitval, S3C2410_INTPND);
-}
-
-static inline void
-s3c_irq_maskack(struct irq_data *data)
-{
- unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
- unsigned long mask;
-
- mask = __raw_readl(S3C2410_INTMSK);
- __raw_writel(mask|bitval, S3C2410_INTMSK);
-
- __raw_writel(bitval, S3C2410_SRCPND);
- __raw_writel(bitval, S3C2410_INTPND);
-}
-
-
-static void
-s3c_irq_unmask(struct irq_data *data)
-{
- unsigned int irqno = data->irq;
- unsigned long mask;
-
- if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
- irqdbf2("s3c_irq_unmask %d\n", irqno);
-
- irqno -= IRQ_EINT0;
-
- mask = __raw_readl(S3C2410_INTMSK);
- mask &= ~(1UL << irqno);
- __raw_writel(mask, S3C2410_INTMSK);
-}
-
-struct irq_chip s3c_irq_level_chip = {
- .name = "s3c-level",
- .irq_ack = s3c_irq_maskack,
- .irq_mask = s3c_irq_mask,
- .irq_unmask = s3c_irq_unmask,
- .irq_set_wake = s3c_irq_wake
-};
-
-struct irq_chip s3c_irq_chip = {
- .name = "s3c",
- .irq_ack = s3c_irq_ack,
- .irq_mask = s3c_irq_mask,
- .irq_unmask = s3c_irq_unmask,
- .irq_set_wake = s3c_irq_wake
-};
-
-static void
-s3c_irqext_mask(struct irq_data *data)
-{
- unsigned int irqno = data->irq - EXTINT_OFF;
- unsigned long mask;
-
- mask = __raw_readl(S3C24XX_EINTMASK);
- mask |= ( 1UL << irqno);
- __raw_writel(mask, S3C24XX_EINTMASK);
-}
-
-static void
-s3c_irqext_ack(struct irq_data *data)
-{
- unsigned long req;
- unsigned long bit;
- unsigned long mask;
-
- bit = 1UL << (data->irq - EXTINT_OFF);
-
- mask = __raw_readl(S3C24XX_EINTMASK);
-
- __raw_writel(bit, S3C24XX_EINTPEND);
-
- req = __raw_readl(S3C24XX_EINTPEND);
- req &= ~mask;
-
- /* not sure if we should be acking the parent irq... */
-
- if (data->irq <= IRQ_EINT7) {
- if ((req & 0xf0) == 0)
- s3c_irq_ack(irq_get_irq_data(IRQ_EINT4t7));
- } else {
- if ((req >> 8) == 0)
- s3c_irq_ack(irq_get_irq_data(IRQ_EINT8t23));
- }
-}
-
-static void
-s3c_irqext_unmask(struct irq_data *data)
-{
- unsigned int irqno = data->irq - EXTINT_OFF;
- unsigned long mask;
-
- mask = __raw_readl(S3C24XX_EINTMASK);
- mask &= ~(1UL << irqno);
- __raw_writel(mask, S3C24XX_EINTMASK);
-}
-
-int
-s3c_irqext_type(struct irq_data *data, unsigned int type)
-{
- void __iomem *extint_reg;
- void __iomem *gpcon_reg;
- unsigned long gpcon_offset, extint_offset;
- unsigned long newvalue = 0, value;
-
- if ((data->irq >= IRQ_EINT0) && (data->irq <= IRQ_EINT3)) {
- gpcon_reg = S3C2410_GPFCON;
- extint_reg = S3C24XX_EXTINT0;
- gpcon_offset = (data->irq - IRQ_EINT0) * 2;
- extint_offset = (data->irq - IRQ_EINT0) * 4;
- } else if ((data->irq >= IRQ_EINT4) && (data->irq <= IRQ_EINT7)) {
- gpcon_reg = S3C2410_GPFCON;
- extint_reg = S3C24XX_EXTINT0;
- gpcon_offset = (data->irq - (EXTINT_OFF)) * 2;
- extint_offset = (data->irq - (EXTINT_OFF)) * 4;
- } else if ((data->irq >= IRQ_EINT8) && (data->irq <= IRQ_EINT15)) {
- gpcon_reg = S3C2410_GPGCON;
- extint_reg = S3C24XX_EXTINT1;
- gpcon_offset = (data->irq - IRQ_EINT8) * 2;
- extint_offset = (data->irq - IRQ_EINT8) * 4;
- } else if ((data->irq >= IRQ_EINT16) && (data->irq <= IRQ_EINT23)) {
- gpcon_reg = S3C2410_GPGCON;
- extint_reg = S3C24XX_EXTINT2;
- gpcon_offset = (data->irq - IRQ_EINT8) * 2;
- extint_offset = (data->irq - IRQ_EINT16) * 4;
- } else {
- return -1;
- }
-
- /* Set the GPIO to external interrupt mode */
- value = __raw_readl(gpcon_reg);
- value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
- __raw_writel(value, gpcon_reg);
-
- /* Set the external interrupt to pointed trigger type */
- switch (type)
- {
- case IRQ_TYPE_NONE:
- printk(KERN_WARNING "No edge setting!\n");
- break;
-
- case IRQ_TYPE_EDGE_RISING:
- newvalue = S3C2410_EXTINT_RISEEDGE;
- break;
-
- case IRQ_TYPE_EDGE_FALLING:
- newvalue = S3C2410_EXTINT_FALLEDGE;
- break;
-
- case IRQ_TYPE_EDGE_BOTH:
- newvalue = S3C2410_EXTINT_BOTHEDGE;
- break;
-
- case IRQ_TYPE_LEVEL_LOW:
- newvalue = S3C2410_EXTINT_LOWLEV;
- break;
-
- case IRQ_TYPE_LEVEL_HIGH:
- newvalue = S3C2410_EXTINT_HILEV;
- break;
-
- default:
- printk(KERN_ERR "No such irq type %d", type);
- return -1;
- }
-
- value = __raw_readl(extint_reg);
- value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
- __raw_writel(value, extint_reg);
-
- return 0;
-}
-
-static struct irq_chip s3c_irqext_chip = {
- .name = "s3c-ext",
- .irq_mask = s3c_irqext_mask,
- .irq_unmask = s3c_irqext_unmask,
- .irq_ack = s3c_irqext_ack,
- .irq_set_type = s3c_irqext_type,
- .irq_set_wake = s3c_irqext_wake
-};
-
-static struct irq_chip s3c_irq_eint0t4 = {
- .name = "s3c-ext0",
- .irq_ack = s3c_irq_ack,
- .irq_mask = s3c_irq_mask,
- .irq_unmask = s3c_irq_unmask,
- .irq_set_wake = s3c_irq_wake,
- .irq_set_type = s3c_irqext_type,
-};
-
-/* mask values for the parent registers for each of the interrupt types */
-
-#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
-#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
-#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
-#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
-
-
-/* UART0 */
-
-static void
-s3c_irq_uart0_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_UART0, 7);
-}
-
-static void
-s3c_irq_uart0_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_UART0);
-}
-
-static void
-s3c_irq_uart0_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_UART0, 7);
-}
-
-static struct irq_chip s3c_irq_uart0 = {
- .name = "s3c-uart0",
- .irq_mask = s3c_irq_uart0_mask,
- .irq_unmask = s3c_irq_uart0_unmask,
- .irq_ack = s3c_irq_uart0_ack,
-};
-
-/* UART1 */
-
-static void
-s3c_irq_uart1_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_UART1, 7 << 3);
-}
-
-static void
-s3c_irq_uart1_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_UART1);
-}
-
-static void
-s3c_irq_uart1_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_UART1, 7 << 3);
-}
-
-static struct irq_chip s3c_irq_uart1 = {
- .name = "s3c-uart1",
- .irq_mask = s3c_irq_uart1_mask,
- .irq_unmask = s3c_irq_uart1_unmask,
- .irq_ack = s3c_irq_uart1_ack,
-};
-
-/* UART2 */
-
-static void
-s3c_irq_uart2_mask(struct irq_data *data)
-{
- s3c_irqsub_mask(data->irq, INTMSK_UART2, 7 << 6);
-}
-
-static void
-s3c_irq_uart2_unmask(struct irq_data *data)
-{
- s3c_irqsub_unmask(data->irq, INTMSK_UART2);
-}
-
-static void
-s3c_irq_uart2_ack(struct irq_data *data)
-{
- s3c_irqsub_maskack(data->irq, INTMSK_UART2, 7 << 6);
-}
-
-static struct irq_chip s3c_irq_uart2 = {
- .name = "s3c-uart2",
- .irq_mask = s3c_irq_uart2_mask,
- .irq_unmask = s3c_irq_uart2_unmask,
- .irq_ack = s3c_irq_uart2_ack,
-};
-
-/* ADC and Touchscreen */
-
-static void
-s3c_irq_adc_mask(struct irq_data *d)
-{
- s3c_irqsub_mask(d->irq, INTMSK_ADCPARENT, 3 << 9);
-}
-
-static void
-s3c_irq_adc_unmask(struct irq_data *d)
-{
- s3c_irqsub_unmask(d->irq, INTMSK_ADCPARENT);
-}
-
-static void
-s3c_irq_adc_ack(struct irq_data *d)
-{
- s3c_irqsub_ack(d->irq, INTMSK_ADCPARENT, 3 << 9);
-}
-
-static struct irq_chip s3c_irq_adc = {
- .name = "s3c-adc",
- .irq_mask = s3c_irq_adc_mask,
- .irq_unmask = s3c_irq_adc_unmask,
- .irq_ack = s3c_irq_adc_ack,
-};
-
-/* irq demux for adc */
-static void s3c_irq_demux_adc(unsigned int irq,
- struct irq_desc *desc)
-{
- unsigned int subsrc, submsk;
- unsigned int offset = 9;
-
- /* read the current pending interrupts, and the mask
- * for what it is available */
-
- subsrc = __raw_readl(S3C2410_SUBSRCPND);
- submsk = __raw_readl(S3C2410_INTSUBMSK);
-
- subsrc &= ~submsk;
- subsrc >>= offset;
- subsrc &= 3;
-
- if (subsrc != 0) {
- if (subsrc & 1) {
- generic_handle_irq(IRQ_TC);
- }
- if (subsrc & 2) {
- generic_handle_irq(IRQ_ADC);
- }
- }
-}
-
-static void s3c_irq_demux_uart(unsigned int start)
-{
- unsigned int subsrc, submsk;
- unsigned int offset = start - IRQ_S3CUART_RX0;
-
- /* read the current pending interrupts, and the mask
- * for what it is available */
-
- subsrc = __raw_readl(S3C2410_SUBSRCPND);
- submsk = __raw_readl(S3C2410_INTSUBMSK);
-
- irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
- start, offset, subsrc, submsk);
-
- subsrc &= ~submsk;
- subsrc >>= offset;
- subsrc &= 7;
-
- if (subsrc != 0) {
- if (subsrc & 1)
- generic_handle_irq(start);
-
- if (subsrc & 2)
- generic_handle_irq(start+1);
-
- if (subsrc & 4)
- generic_handle_irq(start+2);
- }
-}
-
-/* uart demux entry points */
-
-static void
-s3c_irq_demux_uart0(unsigned int irq,
- struct irq_desc *desc)
-{
- irq = irq;
- s3c_irq_demux_uart(IRQ_S3CUART_RX0);
-}
-
-static void
-s3c_irq_demux_uart1(unsigned int irq,
- struct irq_desc *desc)
-{
- irq = irq;
- s3c_irq_demux_uart(IRQ_S3CUART_RX1);
-}
-
-static void
-s3c_irq_demux_uart2(unsigned int irq,
- struct irq_desc *desc)
-{
- irq = irq;
- s3c_irq_demux_uart(IRQ_S3CUART_RX2);
-}
-
-static void
-s3c_irq_demux_extint8(unsigned int irq,
- struct irq_desc *desc)
-{
- unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
- unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
-
- eintpnd &= ~eintmsk;
- eintpnd &= ~0xff; /* ignore lower irqs */
-
- /* we may as well handle all the pending IRQs here */
-
- while (eintpnd) {
- irq = __ffs(eintpnd);
- eintpnd &= ~(1<<irq);
-
- irq += (IRQ_EINT4 - 4);
- generic_handle_irq(irq);
- }
-
-}
-
-static void
-s3c_irq_demux_extint4t7(unsigned int irq,
- struct irq_desc *desc)
-{
- unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
- unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
-
- eintpnd &= ~eintmsk;
- eintpnd &= 0xff; /* only lower irqs */
-
- /* we may as well handle all the pending IRQs here */
-
- while (eintpnd) {
- irq = __ffs(eintpnd);
- eintpnd &= ~(1<<irq);
-
- irq += (IRQ_EINT4 - 4);
-
- generic_handle_irq(irq);
- }
-}
-
-#ifdef CONFIG_FIQ
-/**
- * s3c24xx_set_fiq - set the FIQ routing
- * @irq: IRQ number to route to FIQ on processor.
- * @on: Whether to route @irq to the FIQ, or to remove the FIQ routing.
- *
- * Change the state of the IRQ to FIQ routing depending on @irq and @on. If
- * @on is true, the @irq is checked to see if it can be routed and the
- * interrupt controller updated to route the IRQ. If @on is false, the FIQ
- * routing is cleared, regardless of which @irq is specified.
- */
-int s3c24xx_set_fiq(unsigned int irq, bool on)
-{
- u32 intmod;
- unsigned offs;
-
- if (on) {
- offs = irq - FIQ_START;
- if (offs > 31)
- return -EINVAL;
-
- intmod = 1 << offs;
- } else {
- intmod = 0;
- }
-
- __raw_writel(intmod, S3C2410_INTMOD);
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(s3c24xx_set_fiq);
-#endif
-
-
-/* s3c24xx_init_irq
- *
- * Initialise S3C2410 IRQ system
-*/
-
-void __init s3c24xx_init_irq(void)
-{
- unsigned long pend;
- unsigned long last;
- int irqno;
- int i;
-
-#ifdef CONFIG_FIQ
- init_FIQ(FIQ_START);
-#endif
-
- irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
-
- /* first, clear all interrupts pending... */
-
- last = 0;
- for (i = 0; i < 4; i++) {
- pend = __raw_readl(S3C24XX_EINTPEND);
-
- if (pend == 0 || pend == last)
- break;
-
- __raw_writel(pend, S3C24XX_EINTPEND);
- printk("irq: clearing pending ext status %08x\n", (int)pend);
- last = pend;
- }
-
- last = 0;
- for (i = 0; i < 4; i++) {
- pend = __raw_readl(S3C2410_INTPND);
-
- if (pend == 0 || pend == last)
- break;
-
- __raw_writel(pend, S3C2410_SRCPND);
- __raw_writel(pend, S3C2410_INTPND);
- printk("irq: clearing pending status %08x\n", (int)pend);
- last = pend;
- }
-
- last = 0;
- for (i = 0; i < 4; i++) {
- pend = __raw_readl(S3C2410_SUBSRCPND);
-
- if (pend == 0 || pend == last)
- break;
-
- printk("irq: clearing subpending status %08x\n", (int)pend);
- __raw_writel(pend, S3C2410_SUBSRCPND);
- last = pend;
- }
-
- /* register the main interrupts */
-
- irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
-
- for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
- /* set all the s3c2410 internal irqs */
-
- switch (irqno) {
- /* deal with the special IRQs (cascaded) */
-
- case IRQ_EINT4t7:
- case IRQ_EINT8t23:
- case IRQ_UART0:
- case IRQ_UART1:
- case IRQ_UART2:
- case IRQ_ADCPARENT:
- irq_set_chip_and_handler(irqno, &s3c_irq_level_chip,
- handle_level_irq);
- break;
-
- case IRQ_RESERVED6:
- case IRQ_RESERVED24:
- /* no IRQ here */
- break;
-
- default:
- //irqdbf("registering irq %d (s3c irq)\n", irqno);
- irq_set_chip_and_handler(irqno, &s3c_irq_chip,
- handle_edge_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
- }
-
- /* setup the cascade irq handlers */
-
- irq_set_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
- irq_set_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
-
- irq_set_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
- irq_set_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
- irq_set_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
- irq_set_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
-
- /* external interrupts */
-
- for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
- irqdbf("registering irq %d (ext int)\n", irqno);
- irq_set_chip_and_handler(irqno, &s3c_irq_eint0t4,
- handle_edge_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
- irqdbf("registering irq %d (extended s3c irq)\n", irqno);
- irq_set_chip_and_handler(irqno, &s3c_irqext_chip,
- handle_edge_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- /* register the uart interrupts */
-
- irqdbf("s3c2410: registering external interrupts\n");
-
- for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
- irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
- irq_set_chip_and_handler(irqno, &s3c_irq_uart0,
- handle_level_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
- irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
- irq_set_chip_and_handler(irqno, &s3c_irq_uart1,
- handle_level_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
- irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
- irq_set_chip_and_handler(irqno, &s3c_irq_uart2,
- handle_level_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
- irqdbf("registering irq %d (s3c adc irq)\n", irqno);
- irq_set_chip_and_handler(irqno, &s3c_irq_adc, handle_edge_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- irqdbf("s3c2410: registered interrupt handlers\n");
-}
-
-struct syscore_ops s3c24xx_irq_syscore_ops = {
- .suspend = s3c24xx_irq_suspend,
- .resume = s3c24xx_irq_resume,
-};
diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index 2d676ab50f73..ca07cb1b155a 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -386,11 +386,9 @@ static int s3c_adc_probe(struct platform_device *pdev)
return -ENXIO;
}
- adc->regs = devm_request_and_ioremap(dev, regs);
- if (!adc->regs) {
- dev_err(dev, "failed to map registers\n");
- return -ENXIO;
- }
+ adc->regs = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(adc->regs))
+ return PTR_ERR(adc->regs);
ret = regulator_enable(adc->vdd);
if (ret)
diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c
index d088afa034e8..71d58ddea9c1 100644
--- a/arch/arm/plat-samsung/dma-ops.c
+++ b/arch/arm/plat-samsung/dma-ops.c
@@ -19,7 +19,8 @@
#include <mach/dma.h>
static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
- struct samsung_dma_req *param)
+ struct samsung_dma_req *param,
+ struct device *dev, char *ch_name)
{
dma_cap_mask_t mask;
void *filter_param;
@@ -33,7 +34,12 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
*/
filter_param = (dma_ch == DMACH_DT_PROP) ?
(void *)param->dt_dmach_prop : (void *)dma_ch;
- return (unsigned)dma_request_channel(mask, pl330_filter, filter_param);
+
+ if (dev->of_node)
+ return (unsigned)dma_request_slave_channel(dev, ch_name);
+ else
+ return (unsigned)dma_request_channel(mask, pl330_filter,
+ filter_param);
}
static int samsung_dmadev_release(unsigned ch, void *param)
diff --git a/arch/arm/plat-samsung/include/plat/adc.h b/arch/arm/plat-samsung/include/plat/adc.h
index b258a08de591..2fc89315553f 100644
--- a/arch/arm/plat-samsung/include/plat/adc.h
+++ b/arch/arm/plat-samsung/include/plat/adc.h
@@ -15,6 +15,7 @@
#define __ASM_PLAT_ADC_H __FILE__
struct s3c_adc_client;
+struct platform_device;
extern int s3c_adc_start(struct s3c_adc_client *client,
unsigned int channel, unsigned int nr_samples);
diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h
index b69e11dc679d..37703ef6dfc7 100644
--- a/arch/arm/plat-samsung/include/plat/cpu.h
+++ b/arch/arm/plat-samsung/include/plat/cpu.h
@@ -194,8 +194,7 @@ extern void s3c24xx_init_uartdevs(char *name,
/* timer for 2410/2440 */
-struct sys_timer;
-extern struct sys_timer s3c24xx_timer;
+extern void s3c24xx_timer_init(void);
extern struct syscore_ops s3c2410_pm_syscore_ops;
extern struct syscore_ops s3c2412_pm_syscore_ops;
diff --git a/arch/arm/plat-samsung/include/plat/debug-macro.S b/arch/arm/plat-samsung/include/plat/debug-macro.S
index 207e275362a8..f3a9cff6d5d4 100644
--- a/arch/arm/plat-samsung/include/plat/debug-macro.S
+++ b/arch/arm/plat-samsung/include/plat/debug-macro.S
@@ -14,12 +14,12 @@
/* The S5PV210/S5PC110 implementations are as belows. */
.macro fifo_level_s5pv210 rd, rx
- ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ ldr \rd, [\rx, # S3C2410_UFSTAT]
and \rd, \rd, #S5PV210_UFSTAT_TXMASK
.endm
.macro fifo_full_s5pv210 rd, rx
- ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ ldr \rd, [\rx, # S3C2410_UFSTAT]
tst \rd, #S5PV210_UFSTAT_TXFULL
.endm
@@ -27,7 +27,7 @@
* most widely re-used */
.macro fifo_level_s3c2440 rd, rx
- ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ ldr \rd, [\rx, # S3C2410_UFSTAT]
and \rd, \rd, #S3C2440_UFSTAT_TXMASK
.endm
@@ -36,7 +36,7 @@
#endif
.macro fifo_full_s3c2440 rd, rx
- ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ ldr \rd, [\rx, # S3C2410_UFSTAT]
tst \rd, #S3C2440_UFSTAT_TXFULL
.endm
@@ -45,11 +45,11 @@
#endif
.macro senduart,rd,rx
- strb \rd, [\rx, # S3C2410_UTXH ]
+ strb \rd, [\rx, # S3C2410_UTXH]
.endm
.macro busyuart, rd, rx
- ldr \rd, [ \rx, # S3C2410_UFCON ]
+ ldr \rd, [\rx, # S3C2410_UFCON]
tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled?
beq 1001f @
@ FIFO enabled...
@@ -60,7 +60,7 @@
1001:
@ busy waiting for non fifo
- ldr \rd, [ \rx, # S3C2410_UTRSTAT ]
+ ldr \rd, [\rx, # S3C2410_UTRSTAT]
tst \rd, #S3C2410_UTRSTAT_TXFE
beq 1001b
@@ -68,7 +68,7 @@
.endm
.macro waituart,rd,rx
- ldr \rd, [ \rx, # S3C2410_UFCON ]
+ ldr \rd, [\rx, # S3C2410_UFCON]
tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled?
beq 1001f @
@ FIFO enabled...
@@ -79,7 +79,7 @@
b 1002f
1001:
@ idle waiting for non fifo
- ldr \rd, [ \rx, # S3C2410_UTRSTAT ]
+ ldr \rd, [\rx, # S3C2410_UTRSTAT]
tst \rd, #S3C2410_UTRSTAT_TXFE
beq 1001b
diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h
index f5144cdd3001..114178268b75 100644
--- a/arch/arm/plat-samsung/include/plat/dma-ops.h
+++ b/arch/arm/plat-samsung/include/plat/dma-ops.h
@@ -39,7 +39,8 @@ struct samsung_dma_config {
};
struct samsung_dma_ops {
- unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param);
+ unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param,
+ struct device *dev, char *ch_name);
int (*release)(unsigned ch, void *param);
int (*config)(unsigned ch, struct samsung_dma_config *param);
int (*prepare)(unsigned ch, struct samsung_dma_prep *param);
diff --git a/arch/arm/plat-samsung/include/plat/fimc-core.h b/arch/arm/plat-samsung/include/plat/fimc-core.h
index 945a99d59563..1d6cb2b8b094 100644
--- a/arch/arm/plat-samsung/include/plat/fimc-core.h
+++ b/arch/arm/plat-samsung/include/plat/fimc-core.h
@@ -43,6 +43,8 @@ static inline void s3c_fimc_setname(int id, char *name)
s5p_device_fimc3.name = name;
break;
#endif
+ default:
+ break;
}
}
diff --git a/arch/arm/plat-samsung/include/plat/gpio-core.h b/arch/arm/plat-samsung/include/plat/gpio-core.h
index f7a3ea2c498a..cf5aae5b0975 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-core.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-core.h
@@ -106,7 +106,18 @@ static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int chi
#else
/* machine specific code should provide samsung_gpiolib_getchip */
-#include <mach/gpio-track.h>
+extern struct samsung_gpio_chip s3c24xx_gpios[];
+
+static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int pin)
+{
+ struct samsung_gpio_chip *chip;
+
+ if (pin > S3C_GPIO_END)
+ return NULL;
+
+ chip = &s3c24xx_gpios[pin/32];
+ return ((pin - chip->chip.base) < chip->chip.ngpio) ? chip : NULL;
+}
static inline void s3c_gpiolib_track(struct samsung_gpio_chip *chip) { }
#endif
diff --git a/arch/arm/plat-samsung/include/plat/gpio-fns.h b/arch/arm/plat-samsung/include/plat/gpio-fns.h
deleted file mode 100644
index d1ecef0e38e0..000000000000
--- a/arch/arm/plat-samsung/include/plat/gpio-fns.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <plat/gpio-cfg.h>
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index 887a0c954379..f6fcadeee969 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -109,17 +109,11 @@ extern void s3c_pm_do_restore_core(struct sleep_save *ptr, int count);
#ifdef CONFIG_PM
extern int s3c_irq_wake(struct irq_data *data, unsigned int state);
extern int s3c_irqext_wake(struct irq_data *data, unsigned int state);
-extern int s3c24xx_irq_suspend(void);
-extern void s3c24xx_irq_resume(void);
#else
#define s3c_irq_wake NULL
#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/s3c2416.h b/arch/arm/plat-samsung/include/plat/s3c2416.h
index 7178e338e25e..f27399a3c68d 100644
--- a/arch/arm/plat-samsung/include/plat/s3c2416.h
+++ b/arch/arm/plat-samsung/include/plat/s3c2416.h
@@ -25,6 +25,7 @@ extern int s3c2416_baseclk_add(void);
extern void s3c2416_restart(char mode, const char *cmd);
+extern void s3c2416_init_irq(void);
extern struct syscore_ops s3c2416_irq_syscore_ops;
#else
diff --git a/arch/arm/plat-samsung/include/plat/s3c2443.h b/arch/arm/plat-samsung/include/plat/s3c2443.h
index a5b794ff838b..71b88ec48956 100644
--- a/arch/arm/plat-samsung/include/plat/s3c2443.h
+++ b/arch/arm/plat-samsung/include/plat/s3c2443.h
@@ -25,6 +25,8 @@ extern void s3c2443_init_clocks(int xtal);
extern int s3c2443_baseclk_add(void);
extern void s3c2443_restart(char mode, const char *cmd);
+
+extern void s3c2443_init_irq(void);
#else
#define s3c2443_init_clocks NULL
#define s3c2443_init_uarts NULL
diff --git a/arch/arm/plat-samsung/include/plat/s5p-time.h b/arch/arm/plat-samsung/include/plat/s5p-time.h
index 3a70aebc9205..9c96f3586ce0 100644
--- a/arch/arm/plat-samsung/include/plat/s5p-time.h
+++ b/arch/arm/plat-samsung/include/plat/s5p-time.h
@@ -36,5 +36,5 @@ struct s5p_timer_source {
extern void __init s5p_set_timer_source(enum s5p_timer_mode event,
enum s5p_timer_mode source);
-extern struct sys_timer s5p_timer;
+extern void s5p_timer_init(void);
#endif /* __ASM_PLAT_S5P_TIME_H */
diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h
index 151cc9195cf6..9b87f38fc4f4 100644
--- a/arch/arm/plat-samsung/include/plat/sdhci.h
+++ b/arch/arm/plat-samsung/include/plat/sdhci.h
@@ -374,6 +374,8 @@ static inline void s3c_sdhci_setname(int id, char *name)
s3c_device_hsmmc3.name = name;
break;
#endif
+ default:
+ break;
}
}
diff --git a/arch/arm/plat-samsung/include/plat/uncompress.h b/arch/arm/plat-samsung/include/plat/uncompress.h
index 7e068d182c3d..438b24846e7f 100644
--- a/arch/arm/plat-samsung/include/plat/uncompress.h
+++ b/arch/arm/plat-samsung/include/plat/uncompress.h
@@ -97,33 +97,6 @@ static inline void flush(void)
*((volatile unsigned int __force *)(ad)) = (d); \
} while (0)
-/* CONFIG_S3C_BOOT_WATCHDOG
- *
- * Simple boot-time watchdog setup, to reboot the system if there is
- * any problem with the boot process
-*/
-
-#ifdef CONFIG_S3C_BOOT_WATCHDOG
-
-#define WDOG_COUNT (0xff00)
-
-static inline void arch_decomp_wdog(void)
-{
- __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
-}
-
-static void arch_decomp_wdog_start(void)
-{
- __raw_writel(WDOG_COUNT, S3C2410_WTDAT);
- __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
- __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x80), S3C2410_WTCON);
-}
-
-#else
-#define arch_decomp_wdog_start()
-#define arch_decomp_wdog()
-#endif
-
#ifdef CONFIG_S3C_BOOT_ERROR_RESET
static void arch_decomp_error(const char *x)
@@ -173,7 +146,6 @@ arch_decomp_setup(void)
*/
arch_detect_cpu();
- arch_decomp_wdog_start();
/* Enable the UART FIFOs if they where not enabled and our
* configuration says we should turn them on.
diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c
index 15070284343e..002b1472293b 100644
--- a/arch/arm/plat-samsung/pm.c
+++ b/arch/arm/plat-samsung/pm.c
@@ -51,7 +51,7 @@ void s3c_pm_dbg(const char *fmt, ...)
char buff[256];
va_start(va, fmt);
- vsprintf(buff, fmt, va);
+ vsnprintf(buff, sizeof(buff), fmt, va);
va_end(va);
printascii(buff);
@@ -243,6 +243,7 @@ int (*pm_cpu_sleep)(unsigned long);
static int s3c_pm_enter(suspend_state_t state)
{
+ int ret;
/* ensure the debug is initialised (if enabled) */
s3c_pm_debug_init();
@@ -300,7 +301,9 @@ static int s3c_pm_enter(suspend_state_t state)
* we resume as it saves its own register state and restores it
* during the resume. */
- cpu_suspend(0, pm_cpu_sleep);
+ ret = cpu_suspend(0, pm_cpu_sleep);
+ if (ret)
+ return ret;
/* restore the system state */
diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c
index f99448c48d30..0cc40aea3f5a 100644
--- a/arch/arm/plat-samsung/s3c-dma-ops.c
+++ b/arch/arm/plat-samsung/s3c-dma-ops.c
@@ -36,7 +36,8 @@ static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param,
}
static unsigned s3c_dma_request(enum dma_ch dma_ch,
- struct samsung_dma_req *param)
+ struct samsung_dma_req *param,
+ struct device *dev, char *ch_name)
{
struct cb_data *data;
diff --git a/arch/arm/plat-samsung/s5p-irq-eint.c b/arch/arm/plat-samsung/s5p-irq-eint.c
index 33bd3f3d20f5..faa651602780 100644
--- a/arch/arm/plat-samsung/s5p-irq-eint.c
+++ b/arch/arm/plat-samsung/s5p-irq-eint.c
@@ -15,8 +15,7 @@
#include <linux/io.h>
#include <linux/device.h>
#include <linux/gpio.h>
-
-#include <asm/hardware/vic.h>
+#include <linux/irqchip/arm-vic.h>
#include <plat/regs-irqtype.h>
diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c
index dfb47d638f03..103e371f5e35 100644
--- a/arch/arm/plat-samsung/s5p-irq.c
+++ b/arch/arm/plat-samsung/s5p-irq.c
@@ -13,8 +13,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
-
-#include <asm/hardware/vic.h>
+#include <linux/irqchip/arm-vic.h>
#include <mach/map.h>
#include <plat/regs-timer.h>
diff --git a/arch/arm/plat-samsung/s5p-time.c b/arch/arm/plat-samsung/s5p-time.c
index 028b6e877eb9..e92510cf82ee 100644
--- a/arch/arm/plat-samsung/s5p-time.c
+++ b/arch/arm/plat-samsung/s5p-time.c
@@ -274,15 +274,8 @@ static void __init s5p_clockevent_init(void)
clock_rate = clk_get_rate(tin_event);
clock_count_per_tick = clock_rate / HZ;
- clockevents_calc_mult_shift(&time_event_device,
- clock_rate, S5PTIMER_MIN_RANGE);
- time_event_device.max_delta_ns =
- clockevent_delta2ns(-1, &time_event_device);
- time_event_device.min_delta_ns =
- clockevent_delta2ns(1, &time_event_device);
-
time_event_device.cpumask = cpumask_of(0);
- clockevents_register_device(&time_event_device);
+ clockevents_config_and_register(&time_event_device, clock_rate, 1, -1);
irq_number = timer_source.event_id + IRQ_TIMER0;
setup_irq(irq_number, &s5p_clock_event_irq);
@@ -393,13 +386,9 @@ static void __init s5p_timer_resources(void)
clk_enable(tin_source);
}
-static void __init s5p_timer_init(void)
+void __init s5p_timer_init(void)
{
s5p_timer_resources();
s5p_clockevent_init();
s5p_clocksource_init();
}
-
-struct sys_timer s5p_timer = {
- .init = s5p_timer_init,
-};
diff --git a/arch/arm/plat-samsung/time.c b/arch/arm/plat-samsung/time.c
index 60552e22f22e..73defd00c3e4 100644
--- a/arch/arm/plat-samsung/time.c
+++ b/arch/arm/plat-samsung/time.c
@@ -27,6 +27,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/syscore_ops.h>
#include <asm/mach-types.h>
@@ -95,7 +96,7 @@ static inline unsigned long timer_ticks_to_usec(unsigned long ticks)
* IRQs are disabled before entering here from do_gettimeofday()
*/
-static unsigned long s3c2410_gettimeoffset (void)
+static u32 s3c2410_gettimeoffset(void)
{
unsigned long tdone;
unsigned long tval;
@@ -120,7 +121,7 @@ static unsigned long s3c2410_gettimeoffset (void)
tdone += timer_startval;
}
- return timer_ticks_to_usec(tdone);
+ return timer_ticks_to_usec(tdone) * 1000;
}
@@ -271,15 +272,16 @@ static void __init s3c2410_timer_resources(void)
clk_enable(tin);
}
-static void __init s3c2410_timer_init(void)
+static struct syscore_ops s3c24xx_syscore_ops = {
+ .resume = s3c2410_timer_setup,
+};
+
+void __init s3c24xx_timer_init(void)
{
+ arch_gettimeoffset = s3c2410_gettimeoffset;
+
s3c2410_timer_resources();
s3c2410_timer_setup();
setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
+ register_syscore_ops(&s3c24xx_syscore_ops);
}
-
-struct sys_timer s3c24xx_timer = {
- .init = s3c2410_timer_init,
- .offset = s3c2410_gettimeoffset,
- .resume = s3c2410_timer_setup
-};
diff --git a/arch/arm/plat-spear/Kconfig b/arch/arm/plat-spear/Kconfig
index 87dbd81bdf51..739d016eb273 100644
--- a/arch/arm/plat-spear/Kconfig
+++ b/arch/arm/plat-spear/Kconfig
@@ -10,6 +10,7 @@ choice
config ARCH_SPEAR13XX
bool "ST SPEAr13xx with Device Tree"
+ select ARCH_HAVE_CPUFREQ
select ARM_GIC
select CPU_V7
select GPIO_SPEAR_SPICS
diff --git a/arch/arm/plat-spear/include/plat/uncompress.h b/arch/arm/plat-spear/include/plat/uncompress.h
index 2ce6cb17a98b..51b2dc93e4da 100644
--- a/arch/arm/plat-spear/include/plat/uncompress.h
+++ b/arch/arm/plat-spear/include/plat/uncompress.h
@@ -38,6 +38,5 @@ static inline void flush(void)
* nothing to do
*/
#define arch_decomp_setup()
-#define arch_decomp_wdog()
#endif /* __PLAT_UNCOMPRESS_H */
diff --git a/arch/arm/plat-spear/restart.c b/arch/arm/plat-spear/restart.c
index 4f990115b1bd..7d4616d5df11 100644
--- a/arch/arm/plat-spear/restart.c
+++ b/arch/arm/plat-spear/restart.c
@@ -11,8 +11,8 @@
* warranty of any kind, whether express or implied.
*/
#include <linux/io.h>
+#include <linux/amba/sp810.h>
#include <asm/system_misc.h>
-#include <asm/hardware/sp810.h>
#include <mach/spear.h>
#include <mach/generic.h>
diff --git a/arch/arm/plat-spear/time.c b/arch/arm/plat-spear/time.c
index 03321af5de9f..bd5c53cd6962 100644
--- a/arch/arm/plat-spear/time.c
+++ b/arch/arm/plat-spear/time.c
@@ -186,15 +186,9 @@ static void __init spear_clockevent_init(int irq)
tick_rate = clk_get_rate(gpt_clk);
tick_rate >>= CTRL_PRESCALER16;
- clockevents_calc_mult_shift(&clkevt, tick_rate, SPEAR_MIN_RANGE);
-
- clkevt.max_delta_ns = clockevent_delta2ns(0xfff0,
- &clkevt);
- clkevt.min_delta_ns = clockevent_delta2ns(3, &clkevt);
-
clkevt.cpumask = cpumask_of(0);
- clockevents_register_device(&clkevt);
+ clockevents_config_and_register(&clkevt, tick_rate, 3, 0xfff0);
setup_irq(irq, &spear_timer_irq);
}
diff --git a/arch/arm/plat-versatile/platsmp.c b/arch/arm/plat-versatile/platsmp.c
index 04ca4937d8ca..f2ac15561778 100644
--- a/arch/arm/plat-versatile/platsmp.c
+++ b/arch/arm/plat-versatile/platsmp.c
@@ -14,10 +14,10 @@
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/smp.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
-#include <asm/hardware/gic.h>
/*
* Write pen_release in a way that is guaranteed to be visible to all
@@ -79,7 +79,7 @@ int __cpuinit versatile_boot_secondary(unsigned int cpu, struct task_struct *idl
* the boot monitor to read the system wide flags register,
* and branch to the address found there.
*/
- gic_raise_softirq(cpumask_of(cpu), 0);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index 7a32976fa2a3..8dc0605a9ce9 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -59,14 +59,16 @@ static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn,
};
xen_ulong_t idx = fgmfn;
xen_pfn_t gpfn = lpfn;
+ int err = 0;
set_xen_guest_handle(xatp.idxs, &idx);
set_xen_guest_handle(xatp.gpfns, &gpfn);
+ set_xen_guest_handle(xatp.errs, &err);
rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
- if (rc) {
- pr_warn("Failed to map pfn to mfn rc:%d pfn:%lx mfn:%lx\n",
- rc, lpfn, fgmfn);
+ if (rc || err) {
+ pr_warn("Failed to map pfn to mfn rc:%d:%d pfn:%lx mfn:%lx\n",
+ rc, err, lpfn, fgmfn);
return 1;
}
return 0;
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index f8f362aafee9..f532ce5f3c5b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2,7 +2,9 @@ config ARM64
def_bool y
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
+ select ARCH_WANT_FRAME_POINTERS
select ARM_AMBA
+ select ARM_ARCH_TIMER
select CLONE_BACKWARDS
select COMMON_CLK
select GENERIC_CLOCKEVENTS
@@ -21,7 +23,6 @@ config ARM64
select HAVE_GENERIC_DMA_COHERENT
select HAVE_GENERIC_HARDIRQS
select HAVE_HW_BREAKPOINT if PERF_EVENTS
- select HAVE_IRQ_WORK
select HAVE_MEMBLOCK
select HAVE_PERF_EVENTS
select IRQ_DOMAIN
@@ -204,6 +205,8 @@ config COMPAT
depends on !ARM64_64K_PAGES
select COMPAT_BINFMT_ELF
select HAVE_UID16
+ select OLD_SIGSUSPEND3
+ select COMPAT_OLD_SIGACTION
help
This option enables support for a 32-bit EL0 running under a 64-bit
kernel at EL1. AArch32-specific components such as system calls,
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index d7553f2bda66..51493430f142 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -24,4 +24,21 @@ config DEBUG_STACK_USAGE
Enables the display of the minimum amount of free stack which each
task has ever had available in the sysrq-T output.
+config EARLY_PRINTK
+ bool "Early printk support"
+ default y
+ help
+ Say Y here if you want to have an early console using the
+ earlyprintk=<name>[,<addr>][,<options>] kernel parameter. It
+ is assumed that the early console device has been initialised
+ by the boot loader prior to starting the Linux kernel.
+
+config PID_IN_CONTEXTIDR
+ bool "Write the current PID to the CONTEXTIDR register"
+ help
+ Enabling this option causes the kernel to write the current PID to
+ the CONTEXTIDR register, at the expense of some additional
+ instructions during context switch. Say Y here only if you are
+ planning to use hardware trace tools with this kernel.
+
endmenu
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 14a9d5a2b85b..e5fe4f99fe10 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -19,6 +19,7 @@ generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
+generic-y += kvm_para.h
generic-y += local.h
generic-y += local64.h
generic-y += mman.h
@@ -48,3 +49,4 @@ generic-y += trace_clock.h
generic-y += types.h
generic-y += unaligned.h
generic-y += user.h
+generic-y += xor.h
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
new file mode 100644
index 000000000000..91e2a6a6fcd4
--- /dev/null
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -0,0 +1,133 @@
+/*
+ * arch/arm64/include/asm/arch_timer.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_ARCH_TIMER_H
+#define __ASM_ARCH_TIMER_H
+
+#include <asm/barrier.h>
+
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <clocksource/arm_arch_timer.h>
+
+static inline void arch_timer_reg_write(int access, int reg, u32 val)
+{
+ if (access == ARCH_TIMER_PHYS_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("msr cntp_ctl_el0, %0" : : "r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("msr cntp_tval_el0, %0" : : "r" (val));
+ break;
+ default:
+ BUILD_BUG();
+ }
+ } else if (access == ARCH_TIMER_VIRT_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("msr cntv_ctl_el0, %0" : : "r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("msr cntv_tval_el0, %0" : : "r" (val));
+ break;
+ default:
+ BUILD_BUG();
+ }
+ } else {
+ BUILD_BUG();
+ }
+
+ isb();
+}
+
+static inline u32 arch_timer_reg_read(int access, int reg)
+{
+ u32 val;
+
+ if (access == ARCH_TIMER_PHYS_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mrs %0, cntp_ctl_el0" : "=r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mrs %0, cntp_tval_el0" : "=r" (val));
+ break;
+ default:
+ BUILD_BUG();
+ }
+ } else if (access == ARCH_TIMER_VIRT_ACCESS) {
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ asm volatile("mrs %0, cntv_ctl_el0" : "=r" (val));
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ asm volatile("mrs %0, cntv_tval_el0" : "=r" (val));
+ break;
+ default:
+ BUILD_BUG();
+ }
+ } else {
+ BUILD_BUG();
+ }
+
+ return val;
+}
+
+static inline u32 arch_timer_get_cntfrq(void)
+{
+ u32 val;
+ asm volatile("mrs %0, cntfrq_el0" : "=r" (val));
+ return val;
+}
+
+static inline void __cpuinit arch_counter_set_user_access(void)
+{
+ u32 cntkctl;
+
+ /* Disable user access to the timers and the physical counter. */
+ asm volatile("mrs %0, cntkctl_el1" : "=r" (cntkctl));
+ cntkctl &= ~((3 << 8) | (1 << 0));
+
+ /* Enable user access to the virtual counter and frequency. */
+ cntkctl |= (1 << 1);
+ asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl));
+}
+
+static inline u64 arch_counter_get_cntpct(void)
+{
+ u64 cval;
+
+ isb();
+ asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
+
+ return cval;
+}
+
+static inline u64 arch_counter_get_cntvct(void)
+{
+ u64 cval;
+
+ isb();
+ asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
+
+ return cval;
+}
+
+#endif
diff --git a/arch/arm64/include/asm/arm_generic.h b/arch/arm64/include/asm/arm_generic.h
deleted file mode 100644
index df2aeb82f74e..000000000000
--- a/arch/arm64/include/asm/arm_generic.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * arch/arm64/include/asm/arm_generic.h
- *
- * Copyright (C) 2012 ARM Ltd.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __ASM_ARM_GENERIC_H
-#define __ASM_ARM_GENERIC_H
-
-#include <linux/clocksource.h>
-
-#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
-#define ARCH_TIMER_CTRL_IMASK (1 << 1)
-#define ARCH_TIMER_CTRL_ISTATUS (1 << 2)
-
-#define ARCH_TIMER_REG_CTRL 0
-#define ARCH_TIMER_REG_FREQ 1
-#define ARCH_TIMER_REG_TVAL 2
-
-static inline void arch_timer_reg_write(int reg, u32 val)
-{
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("msr cntp_ctl_el0, %0" : : "r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("msr cntp_tval_el0, %0" : : "r" (val));
- break;
- default:
- BUILD_BUG();
- }
-
- isb();
-}
-
-static inline u32 arch_timer_reg_read(int reg)
-{
- u32 val;
-
- switch (reg) {
- case ARCH_TIMER_REG_CTRL:
- asm volatile("mrs %0, cntp_ctl_el0" : "=r" (val));
- break;
- case ARCH_TIMER_REG_FREQ:
- asm volatile("mrs %0, cntfrq_el0" : "=r" (val));
- break;
- case ARCH_TIMER_REG_TVAL:
- asm volatile("mrs %0, cntp_tval_el0" : "=r" (val));
- break;
- default:
- BUILD_BUG();
- }
-
- return val;
-}
-
-static inline void __cpuinit arch_counter_enable_user_access(void)
-{
- u32 cntkctl;
-
- /* Disable user access to the timers and the physical counter. */
- asm volatile("mrs %0, cntkctl_el1" : "=r" (cntkctl));
- cntkctl &= ~((3 << 8) | (1 << 0));
-
- /* Enable user access to the virtual counter and frequency. */
- cntkctl |= (1 << 1);
- asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl));
-}
-
-static inline cycle_t arch_counter_get_cntpct(void)
-{
- cycle_t cval;
-
- asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
-
- return cval;
-}
-
-static inline cycle_t arch_counter_get_cntvct(void)
-{
- cycle_t cval;
-
- asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
-
- return cval;
-}
-
-#endif
diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h
index 407717ba060e..836364468571 100644
--- a/arch/arm64/include/asm/atomic.h
+++ b/arch/arm64/include/asm/atomic.h
@@ -49,12 +49,12 @@ static inline void atomic_add(int i, atomic_t *v)
int result;
asm volatile("// atomic_add\n"
-"1: ldxr %w0, [%3]\n"
-" add %w0, %w0, %w4\n"
-" stxr %w1, %w0, [%3]\n"
+"1: ldxr %w0, %2\n"
+" add %w0, %w0, %w3\n"
+" stxr %w1, %w0, %2\n"
" cbnz %w1, 1b"
- : "=&r" (result), "=&r" (tmp), "+o" (v->counter)
- : "r" (&v->counter), "Ir" (i)
+ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+ : "Ir" (i)
: "cc");
}
@@ -64,13 +64,13 @@ static inline int atomic_add_return(int i, atomic_t *v)
int result;
asm volatile("// atomic_add_return\n"
-"1: ldaxr %w0, [%3]\n"
-" add %w0, %w0, %w4\n"
-" stlxr %w1, %w0, [%3]\n"
+"1: ldaxr %w0, %2\n"
+" add %w0, %w0, %w3\n"
+" stlxr %w1, %w0, %2\n"
" cbnz %w1, 1b"
- : "=&r" (result), "=&r" (tmp), "+o" (v->counter)
- : "r" (&v->counter), "Ir" (i)
- : "cc");
+ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+ : "Ir" (i)
+ : "cc", "memory");
return result;
}
@@ -81,12 +81,12 @@ static inline void atomic_sub(int i, atomic_t *v)
int result;
asm volatile("// atomic_sub\n"
-"1: ldxr %w0, [%3]\n"
-" sub %w0, %w0, %w4\n"
-" stxr %w1, %w0, [%3]\n"
+"1: ldxr %w0, %2\n"
+" sub %w0, %w0, %w3\n"
+" stxr %w1, %w0, %2\n"
" cbnz %w1, 1b"
- : "=&r" (result), "=&r" (tmp), "+o" (v->counter)
- : "r" (&v->counter), "Ir" (i)
+ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+ : "Ir" (i)
: "cc");
}
@@ -96,13 +96,13 @@ static inline int atomic_sub_return(int i, atomic_t *v)
int result;
asm volatile("// atomic_sub_return\n"
-"1: ldaxr %w0, [%3]\n"
-" sub %w0, %w0, %w4\n"
-" stlxr %w1, %w0, [%3]\n"
+"1: ldaxr %w0, %2\n"
+" sub %w0, %w0, %w3\n"
+" stlxr %w1, %w0, %2\n"
" cbnz %w1, 1b"
- : "=&r" (result), "=&r" (tmp), "+o" (v->counter)
- : "r" (&v->counter), "Ir" (i)
- : "cc");
+ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+ : "Ir" (i)
+ : "cc", "memory");
return result;
}
@@ -113,15 +113,15 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
int oldval;
asm volatile("// atomic_cmpxchg\n"
-"1: ldaxr %w1, [%3]\n"
-" cmp %w1, %w4\n"
+"1: ldaxr %w1, %2\n"
+" cmp %w1, %w3\n"
" b.ne 2f\n"
-" stlxr %w0, %w5, [%3]\n"
+" stlxr %w0, %w4, %2\n"
" cbnz %w0, 1b\n"
"2:"
- : "=&r" (tmp), "=&r" (oldval), "+o" (ptr->counter)
- : "r" (&ptr->counter), "Ir" (old), "r" (new)
- : "cc");
+ : "=&r" (tmp), "=&r" (oldval), "+Q" (ptr->counter)
+ : "Ir" (old), "r" (new)
+ : "cc", "memory");
return oldval;
}
@@ -131,12 +131,12 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
unsigned long tmp, tmp2;
asm volatile("// atomic_clear_mask\n"
-"1: ldxr %0, [%3]\n"
-" bic %0, %0, %4\n"
-" stxr %w1, %0, [%3]\n"
+"1: ldxr %0, %2\n"
+" bic %0, %0, %3\n"
+" stxr %w1, %0, %2\n"
" cbnz %w1, 1b"
- : "=&r" (tmp), "=&r" (tmp2), "+o" (*addr)
- : "r" (addr), "Ir" (mask)
+ : "=&r" (tmp), "=&r" (tmp2), "+Q" (*addr)
+ : "Ir" (mask)
: "cc");
}
@@ -182,12 +182,12 @@ static inline void atomic64_add(u64 i, atomic64_t *v)
unsigned long tmp;
asm volatile("// atomic64_add\n"
-"1: ldxr %0, [%3]\n"
-" add %0, %0, %4\n"
-" stxr %w1, %0, [%3]\n"
+"1: ldxr %0, %2\n"
+" add %0, %0, %3\n"
+" stxr %w1, %0, %2\n"
" cbnz %w1, 1b"
- : "=&r" (result), "=&r" (tmp), "+o" (v->counter)
- : "r" (&v->counter), "Ir" (i)
+ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+ : "Ir" (i)
: "cc");
}
@@ -197,13 +197,13 @@ static inline long atomic64_add_return(long i, atomic64_t *v)
unsigned long tmp;
asm volatile("// atomic64_add_return\n"
-"1: ldaxr %0, [%3]\n"
-" add %0, %0, %4\n"
-" stlxr %w1, %0, [%3]\n"
+"1: ldaxr %0, %2\n"
+" add %0, %0, %3\n"
+" stlxr %w1, %0, %2\n"
" cbnz %w1, 1b"
- : "=&r" (result), "=&r" (tmp), "+o" (v->counter)
- : "r" (&v->counter), "Ir" (i)
- : "cc");
+ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+ : "Ir" (i)
+ : "cc", "memory");
return result;
}
@@ -214,12 +214,12 @@ static inline void atomic64_sub(u64 i, atomic64_t *v)
unsigned long tmp;
asm volatile("// atomic64_sub\n"
-"1: ldxr %0, [%3]\n"
-" sub %0, %0, %4\n"
-" stxr %w1, %0, [%3]\n"
+"1: ldxr %0, %2\n"
+" sub %0, %0, %3\n"
+" stxr %w1, %0, %2\n"
" cbnz %w1, 1b"
- : "=&r" (result), "=&r" (tmp), "+o" (v->counter)
- : "r" (&v->counter), "Ir" (i)
+ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+ : "Ir" (i)
: "cc");
}
@@ -229,13 +229,13 @@ static inline long atomic64_sub_return(long i, atomic64_t *v)
unsigned long tmp;
asm volatile("// atomic64_sub_return\n"
-"1: ldaxr %0, [%3]\n"
-" sub %0, %0, %4\n"
-" stlxr %w1, %0, [%3]\n"
+"1: ldaxr %0, %2\n"
+" sub %0, %0, %3\n"
+" stlxr %w1, %0, %2\n"
" cbnz %w1, 1b"
- : "=&r" (result), "=&r" (tmp), "+o" (v->counter)
- : "r" (&v->counter), "Ir" (i)
- : "cc");
+ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+ : "Ir" (i)
+ : "cc", "memory");
return result;
}
@@ -246,15 +246,15 @@ static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new)
unsigned long res;
asm volatile("// atomic64_cmpxchg\n"
-"1: ldaxr %1, [%3]\n"
-" cmp %1, %4\n"
+"1: ldaxr %1, %2\n"
+" cmp %1, %3\n"
" b.ne 2f\n"
-" stlxr %w0, %5, [%3]\n"
+" stlxr %w0, %4, %2\n"
" cbnz %w0, 1b\n"
"2:"
- : "=&r" (res), "=&r" (oldval), "+o" (ptr->counter)
- : "r" (&ptr->counter), "Ir" (old), "r" (new)
- : "cc");
+ : "=&r" (res), "=&r" (oldval), "+Q" (ptr->counter)
+ : "Ir" (old), "r" (new)
+ : "cc", "memory");
return oldval;
}
@@ -267,15 +267,15 @@ static inline long atomic64_dec_if_positive(atomic64_t *v)
unsigned long tmp;
asm volatile("// atomic64_dec_if_positive\n"
-"1: ldaxr %0, [%3]\n"
+"1: ldaxr %0, %2\n"
" subs %0, %0, #1\n"
" b.mi 2f\n"
-" stlxr %w1, %0, [%3]\n"
+" stlxr %w1, %0, %2\n"
" cbnz %w1, 1b\n"
"2:"
- : "=&r" (result), "=&r" (tmp), "+o" (v->counter)
- : "r" (&v->counter)
- : "cc");
+ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
+ :
+ : "cc", "memory");
return result;
}
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
index e0e65b069d9e..968b5cbfc260 100644
--- a/arch/arm64/include/asm/cmpxchg.h
+++ b/arch/arm64/include/asm/cmpxchg.h
@@ -29,39 +29,39 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
switch (size) {
case 1:
asm volatile("// __xchg1\n"
- "1: ldaxrb %w0, [%3]\n"
- " stlxrb %w1, %w2, [%3]\n"
+ "1: ldaxrb %w0, %2\n"
+ " stlxrb %w1, %w3, %2\n"
" cbnz %w1, 1b\n"
- : "=&r" (ret), "=&r" (tmp)
- : "r" (x), "r" (ptr)
- : "memory", "cc");
+ : "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr)
+ : "r" (x)
+ : "cc", "memory");
break;
case 2:
asm volatile("// __xchg2\n"
- "1: ldaxrh %w0, [%3]\n"
- " stlxrh %w1, %w2, [%3]\n"
+ "1: ldaxrh %w0, %2\n"
+ " stlxrh %w1, %w3, %2\n"
" cbnz %w1, 1b\n"
- : "=&r" (ret), "=&r" (tmp)
- : "r" (x), "r" (ptr)
- : "memory", "cc");
+ : "=&r" (ret), "=&r" (tmp), "+Q" (*(u16 *)ptr)
+ : "r" (x)
+ : "cc", "memory");
break;
case 4:
asm volatile("// __xchg4\n"
- "1: ldaxr %w0, [%3]\n"
- " stlxr %w1, %w2, [%3]\n"
+ "1: ldaxr %w0, %2\n"
+ " stlxr %w1, %w3, %2\n"
" cbnz %w1, 1b\n"
- : "=&r" (ret), "=&r" (tmp)
- : "r" (x), "r" (ptr)
- : "memory", "cc");
+ : "=&r" (ret), "=&r" (tmp), "+Q" (*(u32 *)ptr)
+ : "r" (x)
+ : "cc", "memory");
break;
case 8:
asm volatile("// __xchg8\n"
- "1: ldaxr %0, [%3]\n"
- " stlxr %w1, %2, [%3]\n"
+ "1: ldaxr %0, %2\n"
+ " stlxr %w1, %3, %2\n"
" cbnz %w1, 1b\n"
- : "=&r" (ret), "=&r" (tmp)
- : "r" (x), "r" (ptr)
- : "memory", "cc");
+ : "=&r" (ret), "=&r" (tmp), "+Q" (*(u64 *)ptr)
+ : "r" (x)
+ : "cc", "memory");
break;
default:
BUILD_BUG();
@@ -82,14 +82,14 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
case 1:
do {
asm volatile("// __cmpxchg1\n"
- " ldxrb %w1, [%2]\n"
+ " ldxrb %w1, %2\n"
" mov %w0, #0\n"
" cmp %w1, %w3\n"
" b.ne 1f\n"
- " stxrb %w0, %w4, [%2]\n"
+ " stxrb %w0, %w4, %2\n"
"1:\n"
- : "=&r" (res), "=&r" (oldval)
- : "r" (ptr), "Ir" (old), "r" (new)
+ : "=&r" (res), "=&r" (oldval), "+Q" (*(u8 *)ptr)
+ : "Ir" (old), "r" (new)
: "cc");
} while (res);
break;
@@ -97,29 +97,29 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
case 2:
do {
asm volatile("// __cmpxchg2\n"
- " ldxrh %w1, [%2]\n"
+ " ldxrh %w1, %2\n"
" mov %w0, #0\n"
" cmp %w1, %w3\n"
" b.ne 1f\n"
- " stxrh %w0, %w4, [%2]\n"
+ " stxrh %w0, %w4, %2\n"
"1:\n"
- : "=&r" (res), "=&r" (oldval)
- : "r" (ptr), "Ir" (old), "r" (new)
- : "memory", "cc");
+ : "=&r" (res), "=&r" (oldval), "+Q" (*(u16 *)ptr)
+ : "Ir" (old), "r" (new)
+ : "cc");
} while (res);
break;
case 4:
do {
asm volatile("// __cmpxchg4\n"
- " ldxr %w1, [%2]\n"
+ " ldxr %w1, %2\n"
" mov %w0, #0\n"
" cmp %w1, %w3\n"
" b.ne 1f\n"
- " stxr %w0, %w4, [%2]\n"
+ " stxr %w0, %w4, %2\n"
"1:\n"
- : "=&r" (res), "=&r" (oldval)
- : "r" (ptr), "Ir" (old), "r" (new)
+ : "=&r" (res), "=&r" (oldval), "+Q" (*(u32 *)ptr)
+ : "Ir" (old), "r" (new)
: "cc");
} while (res);
break;
@@ -127,14 +127,14 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
case 8:
do {
asm volatile("// __cmpxchg8\n"
- " ldxr %1, [%2]\n"
+ " ldxr %1, %2\n"
" mov %w0, #0\n"
" cmp %1, %3\n"
" b.ne 1f\n"
- " stxr %w0, %4, [%2]\n"
+ " stxr %w0, %4, %2\n"
"1:\n"
- : "=&r" (res), "=&r" (oldval)
- : "r" (ptr), "Ir" (old), "r" (new)
+ : "=&r" (res), "=&r" (oldval), "+Q" (*(u64 *)ptr)
+ : "Ir" (old), "r" (new)
: "cc");
} while (res);
break;
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index 3468ae8439fa..c582fa316366 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -39,7 +39,7 @@
" .popsection\n" \
: "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp) \
: "r" (oparg), "Ir" (-EFAULT) \
- : "cc")
+ : "cc", "memory")
static inline int
futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index d2f05a608274..57f12c991de2 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -230,6 +230,9 @@ extern void __iounmap(volatile void __iomem *addr);
#define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
#define iounmap __iounmap
+#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF)
+#define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PTE_PXN | PTE_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
+
#define ARCH_HAS_IOREMAP_WC
#include <asm-generic/iomap.h>
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 1cac16a001cb..381f556b664e 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -43,6 +43,7 @@
#define PAGE_OFFSET UL(0xffffffc000000000)
#define MODULES_END (PAGE_OFFSET)
#define MODULES_VADDR (MODULES_END - SZ_64M)
+#define EARLYCON_IOBASE (MODULES_VADDR - SZ_4M)
#define VA_BITS (39)
#define TASK_SIZE_64 (UL(1) << VA_BITS)
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index d4f7fd5b9e33..2494fc01896a 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -26,5 +26,6 @@ typedef struct {
extern void paging_init(void);
extern void setup_mm_for_reboot(void);
+extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt);
#endif
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index f68465dee026..e2bc385adb6b 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -35,6 +35,21 @@ extern unsigned int cpu_last_asid;
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm);
void __new_context(struct mm_struct *mm);
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+static inline void contextidr_thread_switch(struct task_struct *next)
+{
+ asm(
+ " msr contextidr_el1, %0\n"
+ " isb"
+ :
+ : "r" (task_pid_nr(next)));
+}
+#else
+static inline void contextidr_thread_switch(struct task_struct *next)
+{
+}
+#endif
+
/*
* Set TTBR0 to empty_zero_page. No translations will be possible via TTBR0.
*/
diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h
index a6fffd511c5e..d26d1d53c0d7 100644
--- a/arch/arm64/include/asm/perf_event.h
+++ b/arch/arm64/include/asm/perf_event.h
@@ -17,6 +17,11 @@
#ifndef __ASM_PERF_EVENT_H
#define __ASM_PERF_EVENT_H
-/* It's quiet around here... */
+#ifdef CONFIG_HW_PERF_EVENTS
+struct pt_regs;
+extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
+extern unsigned long perf_misc_flags(struct pt_regs *regs);
+#define perf_misc_flags(regs) perf_misc_flags(regs)
+#endif
#endif
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
new file mode 100644
index 000000000000..0604237ecd99
--- /dev/null
+++ b/arch/arm64/include/asm/psci.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2013 ARM Limited
+ */
+
+#ifndef __ASM_PSCI_H
+#define __ASM_PSCI_H
+
+#define PSCI_POWER_STATE_TYPE_STANDBY 0
+#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1
+
+struct psci_power_state {
+ u16 id;
+ u8 type;
+ u8 affinity_level;
+};
+
+struct psci_operations {
+ int (*cpu_suspend)(struct psci_power_state state,
+ unsigned long entry_point);
+ int (*cpu_off)(struct psci_power_state state);
+ int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
+ int (*migrate)(unsigned long cpuid);
+};
+
+extern struct psci_operations psci_ops;
+
+int psci_init(void);
+
+#endif /* __ASM_PSCI_H */
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 4ce845f8ee1c..41a71ee4c3df 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -42,6 +42,16 @@
#define COMPAT_PSR_MODE_UND 0x0000001b
#define COMPAT_PSR_MODE_SYS 0x0000001f
#define COMPAT_PSR_T_BIT 0x00000020
+#define COMPAT_PSR_F_BIT 0x00000040
+#define COMPAT_PSR_I_BIT 0x00000080
+#define COMPAT_PSR_A_BIT 0x00000100
+#define COMPAT_PSR_E_BIT 0x00000200
+#define COMPAT_PSR_J_BIT 0x01000000
+#define COMPAT_PSR_Q_BIT 0x08000000
+#define COMPAT_PSR_V_BIT 0x10000000
+#define COMPAT_PSR_C_BIT 0x20000000
+#define COMPAT_PSR_Z_BIT 0x40000000
+#define COMPAT_PSR_N_BIT 0x80000000
#define COMPAT_PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */
/*
* These are 'magic' values for PTRACE_PEEKUSR that return info about where a
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 7e34295f78e3..4b8023c5d146 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -66,4 +66,15 @@ extern volatile unsigned long secondary_holding_pen_release;
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+struct device_node;
+
+struct smp_enable_ops {
+ const char *name;
+ int (*init_cpu)(struct device_node *, int);
+ int (*prepare_cpu)(int);
+};
+
+extern const struct smp_enable_ops smp_spin_table_ops;
+extern const struct smp_enable_ops smp_psci_ops;
+
#endif /* ifndef __ASM_SMP_H */
diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h
index 41112fe2f8b1..7065e920149d 100644
--- a/arch/arm64/include/asm/spinlock.h
+++ b/arch/arm64/include/asm/spinlock.h
@@ -45,13 +45,13 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
asm volatile(
" sevl\n"
"1: wfe\n"
- "2: ldaxr %w0, [%1]\n"
+ "2: ldaxr %w0, %1\n"
" cbnz %w0, 1b\n"
- " stxr %w0, %w2, [%1]\n"
+ " stxr %w0, %w2, %1\n"
" cbnz %w0, 2b\n"
- : "=&r" (tmp)
- : "r" (&lock->lock), "r" (1)
- : "memory");
+ : "=&r" (tmp), "+Q" (lock->lock)
+ : "r" (1)
+ : "cc", "memory");
}
static inline int arch_spin_trylock(arch_spinlock_t *lock)
@@ -59,13 +59,13 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
unsigned int tmp;
asm volatile(
- " ldaxr %w0, [%1]\n"
+ " ldaxr %w0, %1\n"
" cbnz %w0, 1f\n"
- " stxr %w0, %w2, [%1]\n"
+ " stxr %w0, %w2, %1\n"
"1:\n"
- : "=&r" (tmp)
- : "r" (&lock->lock), "r" (1)
- : "memory");
+ : "=&r" (tmp), "+Q" (lock->lock)
+ : "r" (1)
+ : "cc", "memory");
return !tmp;
}
@@ -73,8 +73,8 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
asm volatile(
- " stlr %w1, [%0]\n"
- : : "r" (&lock->lock), "r" (0) : "memory");
+ " stlr %w1, %0\n"
+ : "=Q" (lock->lock) : "r" (0) : "memory");
}
/*
@@ -94,13 +94,13 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
asm volatile(
" sevl\n"
"1: wfe\n"
- "2: ldaxr %w0, [%1]\n"
+ "2: ldaxr %w0, %1\n"
" cbnz %w0, 1b\n"
- " stxr %w0, %w2, [%1]\n"
+ " stxr %w0, %w2, %1\n"
" cbnz %w0, 2b\n"
- : "=&r" (tmp)
- : "r" (&rw->lock), "r" (0x80000000)
- : "memory");
+ : "=&r" (tmp), "+Q" (rw->lock)
+ : "r" (0x80000000)
+ : "cc", "memory");
}
static inline int arch_write_trylock(arch_rwlock_t *rw)
@@ -108,13 +108,13 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
unsigned int tmp;
asm volatile(
- " ldaxr %w0, [%1]\n"
+ " ldaxr %w0, %1\n"
" cbnz %w0, 1f\n"
- " stxr %w0, %w2, [%1]\n"
+ " stxr %w0, %w2, %1\n"
"1:\n"
- : "=&r" (tmp)
- : "r" (&rw->lock), "r" (0x80000000)
- : "memory");
+ : "=&r" (tmp), "+Q" (rw->lock)
+ : "r" (0x80000000)
+ : "cc", "memory");
return !tmp;
}
@@ -122,8 +122,8 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
static inline void arch_write_unlock(arch_rwlock_t *rw)
{
asm volatile(
- " stlr %w1, [%0]\n"
- : : "r" (&rw->lock), "r" (0) : "memory");
+ " stlr %w1, %0\n"
+ : "=Q" (rw->lock) : "r" (0) : "memory");
}
/* write_can_lock - would write_trylock() succeed? */
@@ -148,14 +148,14 @@ static inline void arch_read_lock(arch_rwlock_t *rw)
asm volatile(
" sevl\n"
"1: wfe\n"
- "2: ldaxr %w0, [%2]\n"
+ "2: ldaxr %w0, %2\n"
" add %w0, %w0, #1\n"
" tbnz %w0, #31, 1b\n"
- " stxr %w1, %w0, [%2]\n"
+ " stxr %w1, %w0, %2\n"
" cbnz %w1, 2b\n"
- : "=&r" (tmp), "=&r" (tmp2)
- : "r" (&rw->lock)
- : "memory");
+ : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
+ :
+ : "cc", "memory");
}
static inline void arch_read_unlock(arch_rwlock_t *rw)
@@ -163,13 +163,13 @@ static inline void arch_read_unlock(arch_rwlock_t *rw)
unsigned int tmp, tmp2;
asm volatile(
- "1: ldxr %w0, [%2]\n"
+ "1: ldxr %w0, %2\n"
" sub %w0, %w0, #1\n"
- " stlxr %w1, %w0, [%2]\n"
+ " stlxr %w1, %w0, %2\n"
" cbnz %w1, 1b\n"
- : "=&r" (tmp), "=&r" (tmp2)
- : "r" (&rw->lock)
- : "memory");
+ : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock)
+ :
+ : "cc", "memory");
}
static inline int arch_read_trylock(arch_rwlock_t *rw)
@@ -177,14 +177,14 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
unsigned int tmp, tmp2 = 1;
asm volatile(
- " ldaxr %w0, [%2]\n"
+ " ldaxr %w0, %2\n"
" add %w0, %w0, #1\n"
" tbnz %w0, #31, 1f\n"
- " stxr %w1, %w0, [%2]\n"
+ " stxr %w1, %w0, %2\n"
"1:\n"
- : "=&r" (tmp), "+r" (tmp2)
- : "r" (&rw->lock)
- : "memory");
+ : "=&r" (tmp), "+r" (tmp2), "+Q" (rw->lock)
+ :
+ : "cc", "memory");
return !tmp2;
}
diff --git a/arch/arm64/include/asm/syscalls.h b/arch/arm64/include/asm/syscalls.h
index 20d63b290665..48fe7c600e98 100644
--- a/arch/arm64/include/asm/syscalls.h
+++ b/arch/arm64/include/asm/syscalls.h
@@ -24,8 +24,6 @@
* System call wrappers implemented in kernel/entry.S.
*/
asmlinkage long sys_rt_sigreturn_wrapper(void);
-asmlinkage long sys_sigaltstack_wrapper(const stack_t __user *uss,
- stack_t __user *uoss);
#include <asm-generic/syscalls.h>
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 744087fb521c..82ce217e94cf 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -20,10 +20,8 @@
#define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_COMPAT_SYS_SENDFILE
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h
index 5ef47ba3ed45..e60e386178d1 100644
--- a/arch/arm64/include/asm/unistd32.h
+++ b/arch/arm64/include/asm/unistd32.h
@@ -93,7 +93,7 @@ __SYSCALL(68, sys_ni_syscall) /* 68 was sys_sgetmask */
__SYSCALL(69, sys_ni_syscall) /* 69 was sys_ssetmask */
__SYSCALL(70, sys_setreuid16)
__SYSCALL(71, sys_setregid16)
-__SYSCALL(72, compat_sys_sigsuspend)
+__SYSCALL(72, sys_sigsuspend)
__SYSCALL(73, compat_sys_sigpending)
__SYSCALL(74, sys_sethostname)
__SYSCALL(75, compat_sys_setrlimit)
@@ -207,7 +207,7 @@ __SYSCALL(182, sys_chown16)
__SYSCALL(183, sys_getcwd)
__SYSCALL(184, sys_capget)
__SYSCALL(185, sys_capset)
-__SYSCALL(186, compat_sys_sigaltstack_wrapper)
+__SYSCALL(186, compat_sys_sigaltstack)
__SYSCALL(187, compat_sys_sendfile)
__SYSCALL(188, sys_ni_syscall) /* 188 reserved */
__SYSCALL(189, sys_ni_syscall) /* 189 reserved */
diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild
index ca5b65f75c7b..e4b78bdca19e 100644
--- a/arch/arm64/include/uapi/asm/Kbuild
+++ b/arch/arm64/include/uapi/asm/Kbuild
@@ -1,11 +1,14 @@
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
+generic-y += kvm_para.h
+
header-y += auxvec.h
header-y += bitsperlong.h
header-y += byteorder.h
header-y += fcntl.h
header-y += hwcap.h
+header-y += kvm_para.h
header-y += param.h
header-y += ptrace.h
header-y += setup.h
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 74239c31e25a..7b4b564961d4 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -9,14 +9,15 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
sys.o stacktrace.o time.o traps.o io.o vdso.o \
- hyp-stub.o
+ hyp-stub.o psci.o
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
-arm64-obj-$(CONFIG_SMP) += smp.o
+arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o smp_psci.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
+arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/early_printk.c b/arch/arm64/kernel/early_printk.c
new file mode 100644
index 000000000000..7e320a2edb9b
--- /dev/null
+++ b/arch/arm64/kernel/early_printk.c
@@ -0,0 +1,118 @@
+/*
+ * Earlyprintk support.
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Catalin Marinas <catalin.marinas@arm.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+
+#include <linux/amba/serial.h>
+
+static void __iomem *early_base;
+static void (*printch)(char ch);
+
+/*
+ * PL011 single character TX.
+ */
+static void pl011_printch(char ch)
+{
+ while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_TXFF)
+ ;
+ writeb_relaxed(ch, early_base + UART01x_DR);
+ while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_BUSY)
+ ;
+}
+
+struct earlycon_match {
+ const char *name;
+ void (*printch)(char ch);
+};
+
+static const struct earlycon_match earlycon_match[] __initconst = {
+ { .name = "pl011", .printch = pl011_printch, },
+ {}
+};
+
+static void early_write(struct console *con, const char *s, unsigned n)
+{
+ while (n-- > 0) {
+ if (*s == '\n')
+ printch('\r');
+ printch(*s);
+ s++;
+ }
+}
+
+static struct console early_console = {
+ .name = "earlycon",
+ .write = early_write,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .index = -1,
+};
+
+/*
+ * Parse earlyprintk=... parameter in the format:
+ *
+ * <name>[,<addr>][,<options>]
+ *
+ * and register the early console. It is assumed that the UART has been
+ * initialised by the bootloader already.
+ */
+static int __init setup_early_printk(char *buf)
+{
+ const struct earlycon_match *match = earlycon_match;
+ phys_addr_t paddr = 0;
+
+ if (!buf) {
+ pr_warning("No earlyprintk arguments passed.\n");
+ return 0;
+ }
+
+ while (match->name) {
+ size_t len = strlen(match->name);
+ if (!strncmp(buf, match->name, len)) {
+ buf += len;
+ break;
+ }
+ match++;
+ }
+ if (!match->name) {
+ pr_warning("Unknown earlyprintk arguments: %s\n", buf);
+ return 0;
+ }
+
+ /* I/O address */
+ if (!strncmp(buf, ",0x", 3)) {
+ char *e;
+ paddr = simple_strtoul(buf + 1, &e, 16);
+ buf = e;
+ }
+ /* no options parsing yet */
+
+ if (paddr)
+ early_base = early_io_map(paddr, EARLYCON_IOBASE);
+
+ printch = match->printch;
+ register_console(&early_console);
+
+ return 0;
+}
+
+early_param("earlyprintk", setup_early_printk);
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 9c94f404ded6..514d6098dbee 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -677,10 +677,5 @@ ENTRY(sys_rt_sigreturn_wrapper)
b sys_rt_sigreturn
ENDPROC(sys_rt_sigreturn_wrapper)
-ENTRY(sys_sigaltstack_wrapper)
- ldr x2, [sp, #S_SP]
- b sys_sigaltstack
-ENDPROC(sys_sigaltstack_wrapper)
-
ENTRY(handle_arch_irq)
.quad 0
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 368ad1f7c36c..0a0a49756826 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -82,10 +82,8 @@
#ifdef CONFIG_ARM64_64K_PAGES
#define MM_MMUFLAGS PTE_ATTRINDX(MT_NORMAL) | PTE_FLAGS
-#define IO_MMUFLAGS PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_XN | PTE_FLAGS
#else
#define MM_MMUFLAGS PMD_ATTRINDX(MT_NORMAL) | PMD_FLAGS
-#define IO_MMUFLAGS PMD_ATTRINDX(MT_DEVICE_nGnRE) | PMD_SECT_XN | PMD_FLAGS
#endif
/*
@@ -368,6 +366,7 @@ ENDPROC(__calc_phys_offset)
* - identity mapping to enable the MMU (low address, TTBR0)
* - first few MB of the kernel linear mapping to jump to once the MMU has
* been enabled, including the FDT blob (TTBR1)
+ * - UART mapping if CONFIG_EARLY_PRINTK is enabled (TTBR1)
*/
__create_page_tables:
pgtbl x25, x26, x24 // idmap_pg_dir and swapper_pg_dir addresses
@@ -420,6 +419,15 @@ __create_page_tables:
sub x6, x6, #1 // inclusive range
create_block_map x0, x7, x3, x5, x6
1:
+#ifdef CONFIG_EARLY_PRINTK
+ /*
+ * Create the pgd entry for the UART mapping. The full mapping is done
+ * later based earlyprintk kernel parameter.
+ */
+ ldr x5, =EARLYCON_IOBASE // UART virtual address
+ add x0, x26, #2 * PAGE_SIZE // section table address
+ create_pgd_entry x26, x0, x5, x6, x7
+#endif
ret
ENDPROC(__create_page_tables)
.ltorg
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index f7073c7b1ca9..1e49e5eb81e9 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -1331,6 +1331,11 @@ void perf_callchain_user(struct perf_callchain_entry *entry,
{
struct frame_tail __user *tail;
+ if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+ /* We don't support guest os callchain now */
+ return;
+ }
+
tail = (struct frame_tail __user *)regs->regs[29];
while (entry->nr < PERF_MAX_STACK_DEPTH &&
@@ -1355,8 +1360,40 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
{
struct stackframe frame;
+ if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+ /* We don't support guest os callchain now */
+ return;
+ }
+
frame.fp = regs->regs[29];
frame.sp = regs->sp;
frame.pc = regs->pc;
walk_stackframe(&frame, callchain_trace, entry);
}
+
+unsigned long perf_instruction_pointer(struct pt_regs *regs)
+{
+ if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
+ return perf_guest_cbs->get_guest_ip();
+
+ return instruction_pointer(regs);
+}
+
+unsigned long perf_misc_flags(struct pt_regs *regs)
+{
+ int misc = 0;
+
+ if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+ if (perf_guest_cbs->is_user_mode())
+ misc |= PERF_RECORD_MISC_GUEST_USER;
+ else
+ misc |= PERF_RECORD_MISC_GUEST_KERNEL;
+ } else {
+ if (user_mode(regs))
+ misc |= PERF_RECORD_MISC_USER;
+ else
+ misc |= PERF_RECORD_MISC_KERNEL;
+ }
+
+ return misc;
+}
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index cb0956bc96ed..0337cdb0667b 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -45,9 +45,10 @@
#include <asm/compat.h>
#include <asm/cacheflush.h>
+#include <asm/fpsimd.h>
+#include <asm/mmu_context.h>
#include <asm/processor.h>
#include <asm/stacktrace.h>
-#include <asm/fpsimd.h>
static void setup_restart(void)
{
@@ -97,14 +98,9 @@ static void default_idle(void)
local_irq_enable();
}
-void (*pm_idle)(void) = default_idle;
-EXPORT_SYMBOL_GPL(pm_idle);
-
/*
- * The idle thread, has rather strange semantics for calling pm_idle,
- * but this is what x86 does and we need to do the same, so that
- * things like cpuidle get called in the same way. The only difference
- * is that we always respect 'hlt_counter' to prevent low power idle.
+ * The idle thread.
+ * We always respect 'hlt_counter' to prevent low power idle.
*/
void cpu_idle(void)
{
@@ -122,10 +118,10 @@ void cpu_idle(void)
local_irq_disable();
if (!need_resched()) {
stop_critical_timings();
- pm_idle();
+ default_idle();
start_critical_timings();
/*
- * pm_idle functions should always return
+ * default_idle functions should always return
* with IRQs enabled.
*/
WARN_ON(irqs_disabled());
@@ -319,6 +315,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
/* the actual thread switch */
last = cpu_switch_to(prev, next);
+ contextidr_thread_switch(next);
return last;
}
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
new file mode 100644
index 000000000000..14f73c445ff5
--- /dev/null
+++ b/arch/arm64/kernel/psci.c
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2013 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#define pr_fmt(fmt) "psci: " fmt
+
+#include <linux/init.h>
+#include <linux/of.h>
+
+#include <asm/compiler.h>
+#include <asm/errno.h>
+#include <asm/psci.h>
+
+struct psci_operations psci_ops;
+
+static int (*invoke_psci_fn)(u64, u64, u64, u64);
+
+enum psci_function {
+ PSCI_FN_CPU_SUSPEND,
+ PSCI_FN_CPU_ON,
+ PSCI_FN_CPU_OFF,
+ PSCI_FN_MIGRATE,
+ PSCI_FN_MAX,
+};
+
+static u32 psci_function_id[PSCI_FN_MAX];
+
+#define PSCI_RET_SUCCESS 0
+#define PSCI_RET_EOPNOTSUPP -1
+#define PSCI_RET_EINVAL -2
+#define PSCI_RET_EPERM -3
+
+static int psci_to_linux_errno(int errno)
+{
+ switch (errno) {
+ case PSCI_RET_SUCCESS:
+ return 0;
+ case PSCI_RET_EOPNOTSUPP:
+ return -EOPNOTSUPP;
+ case PSCI_RET_EINVAL:
+ return -EINVAL;
+ case PSCI_RET_EPERM:
+ return -EPERM;
+ };
+
+ return -EINVAL;
+}
+
+#define PSCI_POWER_STATE_ID_MASK 0xffff
+#define PSCI_POWER_STATE_ID_SHIFT 0
+#define PSCI_POWER_STATE_TYPE_MASK 0x1
+#define PSCI_POWER_STATE_TYPE_SHIFT 16
+#define PSCI_POWER_STATE_AFFL_MASK 0x3
+#define PSCI_POWER_STATE_AFFL_SHIFT 24
+
+static u32 psci_power_state_pack(struct psci_power_state state)
+{
+ return ((state.id & PSCI_POWER_STATE_ID_MASK)
+ << PSCI_POWER_STATE_ID_SHIFT) |
+ ((state.type & PSCI_POWER_STATE_TYPE_MASK)
+ << PSCI_POWER_STATE_TYPE_SHIFT) |
+ ((state.affinity_level & PSCI_POWER_STATE_AFFL_MASK)
+ << PSCI_POWER_STATE_AFFL_SHIFT);
+}
+
+/*
+ * The following two functions are invoked via the invoke_psci_fn pointer
+ * and will not be inlined, allowing us to piggyback on the AAPCS.
+ */
+static noinline int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1,
+ u64 arg2)
+{
+ asm volatile(
+ __asmeq("%0", "x0")
+ __asmeq("%1", "x1")
+ __asmeq("%2", "x2")
+ __asmeq("%3", "x3")
+ "hvc #0\n"
+ : "+r" (function_id)
+ : "r" (arg0), "r" (arg1), "r" (arg2));
+
+ return function_id;
+}
+
+static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
+ u64 arg2)
+{
+ asm volatile(
+ __asmeq("%0", "x0")
+ __asmeq("%1", "x1")
+ __asmeq("%2", "x2")
+ __asmeq("%3", "x3")
+ "smc #0\n"
+ : "+r" (function_id)
+ : "r" (arg0), "r" (arg1), "r" (arg2));
+
+ return function_id;
+}
+
+static int psci_cpu_suspend(struct psci_power_state state,
+ unsigned long entry_point)
+{
+ int err;
+ u32 fn, power_state;
+
+ fn = psci_function_id[PSCI_FN_CPU_SUSPEND];
+ power_state = psci_power_state_pack(state);
+ err = invoke_psci_fn(fn, power_state, entry_point, 0);
+ return psci_to_linux_errno(err);
+}
+
+static int psci_cpu_off(struct psci_power_state state)
+{
+ int err;
+ u32 fn, power_state;
+
+ fn = psci_function_id[PSCI_FN_CPU_OFF];
+ power_state = psci_power_state_pack(state);
+ err = invoke_psci_fn(fn, power_state, 0, 0);
+ return psci_to_linux_errno(err);
+}
+
+static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point)
+{
+ int err;
+ u32 fn;
+
+ fn = psci_function_id[PSCI_FN_CPU_ON];
+ err = invoke_psci_fn(fn, cpuid, entry_point, 0);
+ return psci_to_linux_errno(err);
+}
+
+static int psci_migrate(unsigned long cpuid)
+{
+ int err;
+ u32 fn;
+
+ fn = psci_function_id[PSCI_FN_MIGRATE];
+ err = invoke_psci_fn(fn, cpuid, 0, 0);
+ return psci_to_linux_errno(err);
+}
+
+static const struct of_device_id psci_of_match[] __initconst = {
+ { .compatible = "arm,psci", },
+ {},
+};
+
+int __init psci_init(void)
+{
+ struct device_node *np;
+ const char *method;
+ u32 id;
+ int err = 0;
+
+ np = of_find_matching_node(NULL, psci_of_match);
+ if (!np)
+ return -ENODEV;
+
+ pr_info("probing function IDs from device-tree\n");
+
+ if (of_property_read_string(np, "method", &method)) {
+ pr_warning("missing \"method\" property\n");
+ err = -ENXIO;
+ goto out_put_node;
+ }
+
+ if (!strcmp("hvc", method)) {
+ invoke_psci_fn = __invoke_psci_fn_hvc;
+ } else if (!strcmp("smc", method)) {
+ invoke_psci_fn = __invoke_psci_fn_smc;
+ } else {
+ pr_warning("invalid \"method\" property: %s\n", method);
+ err = -EINVAL;
+ goto out_put_node;
+ }
+
+ if (!of_property_read_u32(np, "cpu_suspend", &id)) {
+ psci_function_id[PSCI_FN_CPU_SUSPEND] = id;
+ psci_ops.cpu_suspend = psci_cpu_suspend;
+ }
+
+ if (!of_property_read_u32(np, "cpu_off", &id)) {
+ psci_function_id[PSCI_FN_CPU_OFF] = id;
+ psci_ops.cpu_off = psci_cpu_off;
+ }
+
+ if (!of_property_read_u32(np, "cpu_on", &id)) {
+ psci_function_id[PSCI_FN_CPU_ON] = id;
+ psci_ops.cpu_on = psci_cpu_on;
+ }
+
+ if (!of_property_read_u32(np, "migrate", &id)) {
+ psci_function_id[PSCI_FN_MIGRATE] = id;
+ psci_ops.migrate = psci_migrate;
+ }
+
+out_put_node:
+ of_node_put(np);
+ return err;
+}
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 7665a9bfdb1e..113db863f832 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -39,6 +39,7 @@
#include <linux/proc_fs.h>
#include <linux/memblock.h>
#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
#include <asm/cputype.h>
#include <asm/elf.h>
@@ -49,6 +50,7 @@
#include <asm/tlbflush.h>
#include <asm/traps.h>
#include <asm/memblock.h>
+#include <asm/psci.h>
unsigned int processor_id;
EXPORT_SYMBOL(processor_id);
@@ -260,6 +262,8 @@ void __init setup_arch(char **cmdline_p)
unflatten_device_tree();
+ psci_init();
+
#ifdef CONFIG_SMP
smp_init_cpus();
#endif
@@ -289,6 +293,13 @@ static int __init topology_init(void)
}
subsys_initcall(topology_init);
+static int __init arm64_device_probe(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ return 0;
+}
+device_initcall(arm64_device_probe);
+
static const char *hwcap_str[] = {
"fp",
"asimd",
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index abd756315cb5..890a591f75dd 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -149,8 +149,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigframe(regs, frame))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack,
- NULL, regs->sp) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return regs->regs[0];
@@ -164,12 +163,6 @@ badframe:
return 0;
}
-asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
- unsigned long sp)
-{
- return do_sigaltstack(uss, uoss, sp);
-}
-
static int setup_sigframe(struct rt_sigframe __user *sf,
struct pt_regs *regs, sigset_t *set)
{
@@ -250,7 +243,6 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
- stack_t stack;
int err = 0;
frame = get_sigframe(ka, regs);
@@ -260,12 +252,7 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
__put_user_error(0, &frame->uc.uc_flags, err);
__put_user_error(NULL, &frame->uc.uc_link, err);
- memset(&stack, 0, sizeof(stack));
- stack.ss_sp = (void __user *)current->sas_ss_sp;
- stack.ss_flags = sas_ss_flags(regs->sp);
- stack.ss_size = current->sas_ss_size;
- err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack));
-
+ err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
err |= setup_sigframe(frame, regs, set);
if (err == 0) {
setup_return(regs, ka, frame, usig);
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index a4db3d22aac4..7f4f3673f2bc 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -28,26 +28,6 @@
#include <asm/uaccess.h>
#include <asm/unistd32.h>
-struct compat_sigaction {
- compat_uptr_t sa_handler;
- compat_ulong_t sa_flags;
- compat_uptr_t sa_restorer;
- compat_sigset_t sa_mask;
-};
-
-struct compat_old_sigaction {
- compat_uptr_t sa_handler;
- compat_old_sigset_t sa_mask;
- compat_ulong_t sa_flags;
- compat_uptr_t sa_restorer;
-};
-
-typedef struct compat_sigaltstack {
- compat_uptr_t ss_sp;
- int ss_flags;
- compat_size_t ss_size;
-} compat_stack_t;
-
struct compat_sigcontext {
/* We always set these two fields to 0 */
compat_ulong_t trap_no;
@@ -76,7 +56,7 @@ struct compat_sigcontext {
struct compat_ucontext {
compat_ulong_t uc_flags;
- struct compat_ucontext *uc_link;
+ compat_uptr_t uc_link;
compat_stack_t uc_stack;
struct compat_sigcontext uc_mcontext;
compat_sigset_t uc_sigmask;
@@ -339,127 +319,6 @@ static int compat_restore_vfp_context(struct compat_vfp_sigframe __user *frame)
return err ? -EFAULT : 0;
}
-/*
- * atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int compat_sys_sigsuspend(int restart, compat_ulong_t oldmask,
- compat_old_sigset_t mask)
-{
- sigset_t blocked;
-
- siginitset(&current->blocked, mask);
- return sigsuspend(&blocked);
-}
-
-asmlinkage int compat_sys_sigaction(int sig,
- const struct compat_old_sigaction __user *act,
- struct compat_old_sigaction __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
- compat_old_sigset_t mask;
- compat_uptr_t handler, restorer;
-
- if (act) {
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(handler, &act->sa_handler) ||
- __get_user(restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
-
- new_ka.sa.sa_handler = compat_ptr(handler);
- new_ka.sa.sa_restorer = compat_ptr(restorer);
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(ptr_to_compat(old_ka.sa.sa_handler),
- &oact->sa_handler) ||
- __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
- &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
-asmlinkage int compat_sys_rt_sigaction(int sig,
- const struct compat_sigaction __user *act,
- struct compat_sigaction __user *oact,
- compat_size_t sigsetsize)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(compat_sigset_t))
- return -EINVAL;
-
- if (act) {
- compat_uptr_t handler, restorer;
-
- ret = get_user(handler, &act->sa_handler);
- new_ka.sa.sa_handler = compat_ptr(handler);
- ret |= get_user(restorer, &act->sa_restorer);
- new_ka.sa.sa_restorer = compat_ptr(restorer);
- ret |= get_sigset_t(&new_ka.sa.sa_mask, &act->sa_mask);
- ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- if (ret)
- return -EFAULT;
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
- if (!ret && oact) {
- ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
- ret |= put_sigset_t(&oact->sa_mask, &old_ka.sa.sa_mask);
- ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- }
- return ret;
-}
-
-int compat_do_sigaltstack(compat_uptr_t compat_uss, compat_uptr_t compat_uoss,
- compat_ulong_t sp)
-{
- compat_stack_t __user *newstack = compat_ptr(compat_uss);
- compat_stack_t __user *oldstack = compat_ptr(compat_uoss);
- compat_uptr_t ss_sp;
- int ret;
- mm_segment_t old_fs;
- stack_t uss, uoss;
-
- /* Marshall the compat new stack into a stack_t */
- if (newstack) {
- if (get_user(ss_sp, &newstack->ss_sp) ||
- __get_user(uss.ss_flags, &newstack->ss_flags) ||
- __get_user(uss.ss_size, &newstack->ss_size))
- return -EFAULT;
- uss.ss_sp = compat_ptr(ss_sp);
- }
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- /* The __user pointer casts are valid because of the set_fs() */
- ret = do_sigaltstack(
- newstack ? (stack_t __user *) &uss : NULL,
- oldstack ? (stack_t __user *) &uoss : NULL,
- (unsigned long)sp);
- set_fs(old_fs);
-
- /* Convert the old stack_t into a compat stack. */
- if (!ret && oldstack &&
- (put_user(ptr_to_compat(uoss.ss_sp), &oldstack->ss_sp) ||
- __put_user(uoss.ss_flags, &oldstack->ss_flags) ||
- __put_user(uoss.ss_size, &oldstack->ss_size)))
- return -EFAULT;
- return ret;
-}
-
static int compat_restore_sigframe(struct pt_regs *regs,
struct compat_sigframe __user *sf)
{
@@ -562,9 +421,7 @@ asmlinkage int compat_sys_rt_sigreturn(struct pt_regs *regs)
if (compat_restore_sigframe(regs, &frame->sig))
goto badframe;
- if (compat_do_sigaltstack(ptr_to_compat(&frame->sig.uc.uc_stack),
- ptr_to_compat((void __user *)NULL),
- regs->compat_sp) == -EFAULT)
+ if (compat_restore_altstack(&frame->sig.uc.uc_stack))
goto badframe;
return regs->regs[0];
@@ -703,13 +560,9 @@ int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
err |= copy_siginfo_to_user32(&frame->info, info);
__put_user_error(0, &frame->sig.uc.uc_flags, err);
- __put_user_error(NULL, &frame->sig.uc.uc_link, err);
+ __put_user_error(0, &frame->sig.uc.uc_link, err);
- memset(&stack, 0, sizeof(stack));
- stack.ss_sp = (compat_uptr_t)current->sas_ss_sp;
- stack.ss_flags = sas_ss_flags(regs->compat_sp);
- stack.ss_size = current->sas_ss_size;
- err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack));
+ err |= __compat_save_altstack(&frame->sig.uc.uc_stack, regs->compat_sp);
err |= compat_setup_sigframe(&frame->sig, regs, set);
@@ -742,75 +595,6 @@ int compat_setup_frame(int usig, struct k_sigaction *ka, sigset_t *set,
return err;
}
-/*
- * RT signals don't have generic compat wrappers.
- * See arch/powerpc/kernel/signal_32.c
- */
-asmlinkage int compat_sys_rt_sigprocmask(int how, compat_sigset_t __user *set,
- compat_sigset_t __user *oset,
- compat_size_t sigsetsize)
-{
- sigset_t s;
- sigset_t __user *up;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- if (set) {
- if (get_sigset_t(&s, set))
- return -EFAULT;
- }
-
- set_fs(KERNEL_DS);
- /* This is valid because of the set_fs() */
- up = (sigset_t __user *) &s;
- ret = sys_rt_sigprocmask(how, set ? up : NULL, oset ? up : NULL,
- sigsetsize);
- set_fs(old_fs);
- if (ret)
- return ret;
- if (oset) {
- if (put_sigset_t(oset, &s))
- return -EFAULT;
- }
- return 0;
-}
-
-asmlinkage int compat_sys_rt_sigpending(compat_sigset_t __user *set,
- compat_size_t sigsetsize)
-{
- sigset_t s;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- /* The __user pointer cast is valid because of the set_fs() */
- ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
- set_fs(old_fs);
- if (!ret) {
- if (put_sigset_t(set, &s))
- return -EFAULT;
- }
- return ret;
-}
-
-asmlinkage int compat_sys_rt_sigqueueinfo(int pid, int sig,
- compat_siginfo_t __user *uinfo)
-{
- siginfo_t info;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- ret = copy_siginfo_from_user32(&info, uinfo);
- if (unlikely(ret))
- return ret;
-
- set_fs (KERNEL_DS);
- /* The __user pointer cast is valid because of the set_fs() */
- ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
- set_fs (old_fs);
- return ret;
-}
-
void compat_setup_restart_syscall(struct pt_regs *regs)
{
regs->regs[7] = __NR_compat_restart_syscall;
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 538300f2273d..bdd34597254b 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -233,7 +233,28 @@ void __init smp_prepare_boot_cpu(void)
}
static void (*smp_cross_call)(const struct cpumask *, unsigned int);
-static phys_addr_t cpu_release_addr[NR_CPUS];
+
+static const struct smp_enable_ops *enable_ops[] __initconst = {
+ &smp_spin_table_ops,
+ &smp_psci_ops,
+ NULL,
+};
+
+static const struct smp_enable_ops *smp_enable_ops[NR_CPUS];
+
+static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name)
+{
+ const struct smp_enable_ops *ops = enable_ops[0];
+
+ while (ops) {
+ if (!strcmp(name, ops->name))
+ return ops;
+
+ ops++;
+ }
+
+ return NULL;
+}
/*
* Enumerate the possible CPU set from the device tree.
@@ -252,22 +273,22 @@ void __init smp_init_cpus(void)
* We currently support only the "spin-table" enable-method.
*/
enable_method = of_get_property(dn, "enable-method", NULL);
- if (!enable_method || strcmp(enable_method, "spin-table")) {
- pr_err("CPU %d: missing or invalid enable-method property: %s\n",
- cpu, enable_method);
+ if (!enable_method) {
+ pr_err("CPU %d: missing enable-method property\n", cpu);
goto next;
}
- /*
- * Determine the address from which the CPU is polling.
- */
- if (of_property_read_u64(dn, "cpu-release-addr",
- &cpu_release_addr[cpu])) {
- pr_err("CPU %d: missing or invalid cpu-release-addr property\n",
- cpu);
+ smp_enable_ops[cpu] = smp_get_enable_ops(enable_method);
+
+ if (!smp_enable_ops[cpu]) {
+ pr_err("CPU %d: invalid enable-method property: %s\n",
+ cpu, enable_method);
goto next;
}
+ if (smp_enable_ops[cpu]->init_cpu(dn, cpu))
+ goto next;
+
set_cpu_possible(cpu, true);
next:
cpu++;
@@ -281,8 +302,7 @@ next:
void __init smp_prepare_cpus(unsigned int max_cpus)
{
- int cpu;
- void **release_addr;
+ int cpu, err;
unsigned int ncores = num_possible_cpus();
/*
@@ -291,30 +311,35 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
if (max_cpus > ncores)
max_cpus = ncores;
+ /* Don't bother if we're effectively UP */
+ if (max_cpus <= 1)
+ return;
+
/*
* Initialise the present map (which describes the set of CPUs
* actually populated at the present time) and release the
* secondaries from the bootloader.
+ *
+ * Make sure we online at most (max_cpus - 1) additional CPUs.
*/
+ max_cpus--;
for_each_possible_cpu(cpu) {
if (max_cpus == 0)
break;
- if (!cpu_release_addr[cpu])
+ if (cpu == smp_processor_id())
+ continue;
+
+ if (!smp_enable_ops[cpu])
continue;
- release_addr = __va(cpu_release_addr[cpu]);
- release_addr[0] = (void *)__pa(secondary_holding_pen);
- __flush_dcache_area(release_addr, sizeof(release_addr[0]));
+ err = smp_enable_ops[cpu]->prepare_cpu(cpu);
+ if (err)
+ continue;
set_cpu_present(cpu, true);
max_cpus--;
}
-
- /*
- * Send an event to wake up the secondaries.
- */
- sev();
}
diff --git a/arch/arm64/kernel/smp_psci.c b/arch/arm64/kernel/smp_psci.c
new file mode 100644
index 000000000000..112091684c22
--- /dev/null
+++ b/arch/arm64/kernel/smp_psci.c
@@ -0,0 +1,52 @@
+/*
+ * PSCI SMP initialisation
+ *
+ * Copyright (C) 2013 ARM 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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/>.
+ */
+
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/smp.h>
+
+#include <asm/psci.h>
+
+static int __init smp_psci_init_cpu(struct device_node *dn, int cpu)
+{
+ return 0;
+}
+
+static int __init smp_psci_prepare_cpu(int cpu)
+{
+ int err;
+
+ if (!psci_ops.cpu_on) {
+ pr_err("psci: no cpu_on method, not booting CPU%d\n", cpu);
+ return -ENODEV;
+ }
+
+ err = psci_ops.cpu_on(cpu, __pa(secondary_holding_pen));
+ if (err) {
+ pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err);
+ return err;
+ }
+
+ return 0;
+}
+
+const struct smp_enable_ops smp_psci_ops __initconst = {
+ .name = "psci",
+ .init_cpu = smp_psci_init_cpu,
+ .prepare_cpu = smp_psci_prepare_cpu,
+};
diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c
new file mode 100644
index 000000000000..7c35fa682f76
--- /dev/null
+++ b/arch/arm64/kernel/smp_spin_table.c
@@ -0,0 +1,66 @@
+/*
+ * Spin Table SMP initialisation
+ *
+ * Copyright (C) 2013 ARM 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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/>.
+ */
+
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+
+static phys_addr_t cpu_release_addr[NR_CPUS];
+
+static int __init smp_spin_table_init_cpu(struct device_node *dn, int cpu)
+{
+ /*
+ * Determine the address from which the CPU is polling.
+ */
+ if (of_property_read_u64(dn, "cpu-release-addr",
+ &cpu_release_addr[cpu])) {
+ pr_err("CPU %d: missing or invalid cpu-release-addr property\n",
+ cpu);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __init smp_spin_table_prepare_cpu(int cpu)
+{
+ void **release_addr;
+
+ if (!cpu_release_addr[cpu])
+ return -ENODEV;
+
+ release_addr = __va(cpu_release_addr[cpu]);
+ release_addr[0] = (void *)__pa(secondary_holding_pen);
+ __flush_dcache_area(release_addr, sizeof(release_addr[0]));
+
+ /*
+ * Send an event to wake up the secondary CPU.
+ */
+ sev();
+
+ return 0;
+}
+
+const struct smp_enable_ops smp_spin_table_ops __initconst = {
+ .name = "spin-table",
+ .init_cpu = smp_spin_table_init_cpu,
+ .prepare_cpu = smp_spin_table_prepare_cpu,
+};
diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c
index 8292a9b090f8..3fa98ff14f0e 100644
--- a/arch/arm64/kernel/sys.c
+++ b/arch/arm64/kernel/sys.c
@@ -40,7 +40,6 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
* Wrappers to pass the pt_regs argument.
*/
#define sys_rt_sigreturn sys_rt_sigreturn_wrapper
-#define sys_sigaltstack sys_sigaltstack_wrapper
#include <asm/syscalls.h>
diff --git a/arch/arm64/kernel/sys32.S b/arch/arm64/kernel/sys32.S
index 7ef59e9245ef..6abb05721614 100644
--- a/arch/arm64/kernel/sys32.S
+++ b/arch/arm64/kernel/sys32.S
@@ -39,11 +39,6 @@ compat_sys_rt_sigreturn_wrapper:
b compat_sys_rt_sigreturn
ENDPROC(compat_sys_rt_sigreturn_wrapper)
-compat_sys_sigaltstack_wrapper:
- ldr x2, [sp, #S_COMPAT_SP]
- b compat_do_sigaltstack
-ENDPROC(compat_sys_sigaltstack_wrapper)
-
compat_sys_statfs64_wrapper:
mov w3, #84
cmp w1, #88
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
index 3b4b7258f492..b0ef18d14c3b 100644
--- a/arch/arm64/kernel/time.c
+++ b/arch/arm64/kernel/time.c
@@ -31,8 +31,9 @@
#include <linux/syscore_ops.h>
#include <linux/timer.h>
#include <linux/irq.h>
+#include <linux/delay.h>
-#include <clocksource/arm_generic.h>
+#include <clocksource/arm_arch_timer.h>
#include <asm/thread_info.h>
#include <asm/stacktrace.h>
@@ -59,7 +60,31 @@ unsigned long profile_pc(struct pt_regs *regs)
EXPORT_SYMBOL(profile_pc);
#endif
+static u64 sched_clock_mult __read_mostly;
+
+unsigned long long notrace sched_clock(void)
+{
+ return arch_timer_read_counter() * sched_clock_mult;
+}
+
+int read_current_timer(unsigned long *timer_value)
+{
+ *timer_value = arch_timer_read_counter();
+ return 0;
+}
+
void __init time_init(void)
{
- arm_generic_timer_init();
+ u32 arch_timer_rate;
+
+ if (arch_timer_init())
+ panic("Unable to initialise architected timer.\n");
+
+ arch_timer_rate = arch_timer_get_rate();
+
+ /* Cache the sched_clock multiplier to save a divide in the hot path. */
+ sched_clock_mult = NSEC_PER_SEC / arch_timer_rate;
+
+ /* Calibrate the delay loop directly */
+ lpj_fine = arch_timer_rate / HZ;
}
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 3883f842434f..b3c5f628bdb4 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -242,7 +242,7 @@ void die(const char *str, struct pt_regs *regs, int err)
crash_kexec(regs);
bust_spinlocks(0);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
raw_spin_unlock_irq(&die_lock);
oops_exit();
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index a6885d896ab6..224b44ab534e 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -25,6 +25,7 @@
#include <linux/nodemask.h>
#include <linux/memblock.h>
#include <linux/fs.h>
+#include <linux/io.h>
#include <asm/cputype.h>
#include <asm/sections.h>
@@ -251,6 +252,47 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
} while (pgd++, addr = next, addr != end);
}
+#ifdef CONFIG_EARLY_PRINTK
+/*
+ * Create an early I/O mapping using the pgd/pmd entries already populated
+ * in head.S as this function is called too early to allocated any memory. The
+ * mapping size is 2MB with 4KB pages or 64KB or 64KB pages.
+ */
+void __iomem * __init early_io_map(phys_addr_t phys, unsigned long virt)
+{
+ unsigned long size, mask;
+ bool page64k = IS_ENABLED(ARM64_64K_PAGES);
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ /*
+ * No early pte entries with !ARM64_64K_PAGES configuration, so using
+ * sections (pmd).
+ */
+ size = page64k ? PAGE_SIZE : SECTION_SIZE;
+ mask = ~(size - 1);
+
+ pgd = pgd_offset_k(virt);
+ pud = pud_offset(pgd, virt);
+ if (pud_none(*pud))
+ return NULL;
+ pmd = pmd_offset(pud, virt);
+
+ if (page64k) {
+ if (pmd_none(*pmd))
+ return NULL;
+ pte = pte_offset_kernel(pmd, virt);
+ set_pte(pte, __pte((phys & mask) | PROT_DEVICE_nGnRE));
+ } else {
+ set_pmd(pmd, __pmd((phys & mask) | PROT_SECT_DEVICE_nGnRE));
+ }
+
+ return (void __iomem *)((virt & mask) + (phys & ~mask));
+}
+#endif
+
static void __init map_mem(void)
{
struct memblock_region *reg;
@@ -392,4 +434,7 @@ int __meminit vmemmap_populate(struct page *start_page,
return 0;
}
#endif /* CONFIG_ARM64_64K_PAGES */
+void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+{
+}
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
diff --git a/arch/avr32/include/asm/signal.h b/arch/avr32/include/asm/signal.h
index 9326d182e9e5..d875eb6a3f3c 100644
--- a/arch/avr32/include/asm/signal.h
+++ b/arch/avr32/include/asm/signal.h
@@ -23,16 +23,7 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#define __ARCH_HAS_SA_RESTORER
#include <asm/sigcontext.h>
#undef __HAVE_ARCH_SIG_BITOPS
diff --git a/arch/avr32/include/asm/unistd.h b/arch/avr32/include/asm/unistd.h
index 0bdf6371574e..dc4d5a931112 100644
--- a/arch/avr32/include/asm/unistd.h
+++ b/arch/avr32/include/asm/unistd.h
@@ -37,8 +37,6 @@
#define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
diff --git a/arch/avr32/include/uapi/asm/socket.h b/arch/avr32/include/uapi/asm/socket.h
index 486df68abeec..51c6401582ea 100644
--- a/arch/avr32/include/uapi/asm/socket.h
+++ b/arch/avr32/include/uapi/asm/socket.h
@@ -22,7 +22,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT 15
#define SO_PASSCRED 16
#define SO_PEERCRED 17
#define SO_RCVLOWAT 18
@@ -70,4 +70,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
+
#endif /* __ASM_AVR32_SOCKET_H */
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index 5e01c3a40ced..b80c0b3d2bab 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -21,12 +21,6 @@
#include <asm/ucontext.h>
#include <asm/syscalls.h>
-asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
- struct pt_regs *regs)
-{
- return do_sigaltstack(uss, uoss, regs->sp);
-}
-
struct rt_sigframe
{
struct siginfo info;
@@ -91,7 +85,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n",
@@ -175,12 +169,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up the ucontext */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
- err |= __put_user((void __user *)current->sas_ss_sp,
- &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size,
- &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
diff --git a/arch/avr32/kernel/syscall-stubs.S b/arch/avr32/kernel/syscall-stubs.S
index 275aab9731fd..b5fc927cd398 100644
--- a/arch/avr32/kernel/syscall-stubs.S
+++ b/arch/avr32/kernel/syscall-stubs.S
@@ -20,12 +20,6 @@ __sys_rt_sigsuspend:
mov r10, sp
rjmp sys_rt_sigsuspend
- .global __sys_sigaltstack
- .type __sys_sigaltstack,@function
-__sys_sigaltstack:
- mov r10, sp
- rjmp sys_sigaltstack
-
.global __sys_rt_sigreturn
.type __sys_rt_sigreturn,@function
__sys_rt_sigreturn:
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
index f27bb878da6b..017a904180c8 100644
--- a/arch/avr32/kernel/syscall_table.S
+++ b/arch/avr32/kernel/syscall_table.S
@@ -115,7 +115,7 @@ sys_call_table:
.long sys_statfs
.long sys_fstatfs /* 100 */
.long sys_vhangup
- .long __sys_sigaltstack
+ .long sys_sigaltstack
.long sys_syslog
.long sys_setitimer
.long sys_getitimer /* 105 */
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index 3d760c06f024..682b2478691a 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -61,7 +61,7 @@ void die(const char *str, struct pt_regs *regs, long err)
show_regs_log_lvl(regs, KERN_EMERG);
show_stack_log_lvl(current, regs->sp, regs, KERN_EMERG);
bust_spinlocks(0);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
spin_unlock_irq(&die_lock);
if (in_interrupt())
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index b6f3ad5441c5..e98f3248c8aa 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -24,7 +24,6 @@ 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
@@ -38,7 +37,6 @@ config BLACKFIN
select HAVE_GENERIC_HARDIRQS
select GENERIC_ATOMIC64
select GENERIC_IRQ_PROBE
- select IRQ_PER_CPU if SMP
select USE_GENERIC_SMP_HELPERS if SMP
select HAVE_NMI_WATCHDOG if NMI_WATCHDOG
select GENERIC_SMP_IDLE_THREAD
@@ -562,8 +560,7 @@ choice
accurate - This option is therefore marked experimental.
config BFIN_KERNEL_CLOCK_MEMINIT_CALC
- bool "Calculate Timings (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "Calculate Timings"
config BFIN_KERNEL_CLOCK_MEMINIT_SPEC
bool "Provide accurate Timings based on target SCLK"
@@ -1120,7 +1117,7 @@ endchoice
comment "Memory Protection Unit"
config MPU
- bool "Enable the memory protection unit (EXPERIMENTAL)"
+ bool "Enable the memory protection unit"
default n
help
Use the processor's MPU to protect applications from accessing
@@ -1442,7 +1439,6 @@ config BFIN_CPU_FREQ
config CPU_VOLTAGE
bool "CPU Voltage scaling"
- depends on EXPERIMENTAL
depends on CPU_FREQ
default n
help
diff --git a/arch/blackfin/include/asm/mem_init.h b/arch/blackfin/include/asm/mem_init.h
index f019e9bcefe9..9b33e7247864 100644
--- a/arch/blackfin/include/asm/mem_init.h
+++ b/arch/blackfin/include/asm/mem_init.h
@@ -411,7 +411,7 @@ static struct ddr_config ddr_config_table[] __attribute__((section(".data_l1")))
.dmc_ddrcfg = 0x00000422,
.dmc_ddrtr0 = 0x20E0A424,
.dmc_ddrtr1 = 0x3020079E,
- .dmc_ddrtr2 = 0x0032020D,
+ .dmc_ddrtr2 = 0x0032050D,
.dmc_ddrmr = 0x00000842,
.dmc_ddrmr1 = 0x4,
},
diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h
index 461bb542e2e8..57701c3b8a59 100644
--- a/arch/blackfin/include/asm/uaccess.h
+++ b/arch/blackfin/include/asm/uaccess.h
@@ -191,6 +191,7 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
memcpy((void __force *)to, from, n);
else
return n;
+ SSYNC();
return 0;
}
diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h
index e943cb130048..04e83ea8d5cc 100644
--- a/arch/blackfin/include/asm/unistd.h
+++ b/arch/blackfin/include/asm/unistd.h
@@ -18,8 +18,6 @@
#define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_VFORK
/*
diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c
index e7be6532d6a0..df437e52d9df 100644
--- a/arch/blackfin/kernel/dma-mapping.c
+++ b/arch/blackfin/kernel/dma-mapping.c
@@ -13,6 +13,7 @@
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/export.h>
+#include <linux/bitmap.h>
static spinlock_t dma_page_lock;
static unsigned long *dma_page;
@@ -46,24 +47,17 @@ static inline unsigned int get_pages(size_t size)
static unsigned long __alloc_dma_pages(unsigned int pages)
{
unsigned long ret = 0, flags;
- int i, count = 0;
+ unsigned long start;
if (dma_initialized == 0)
dma_alloc_init(_ramend - DMA_UNCACHED_REGION, _ramend);
spin_lock_irqsave(&dma_page_lock, flags);
- for (i = 0; i < dma_pages;) {
- if (test_bit(i++, dma_page) == 0) {
- if (++count == pages) {
- while (count--)
- __set_bit(--i, dma_page);
-
- ret = dma_base + (i << PAGE_SHIFT);
- break;
- }
- } else
- count = 0;
+ start = bitmap_find_next_zero_area(dma_page, dma_pages, 0, pages, 0);
+ if (start < dma_pages) {
+ ret = dma_base + (start << PAGE_SHIFT);
+ bitmap_set(dma_page, start, pages);
}
spin_unlock_irqrestore(&dma_page_lock, flags);
return ret;
@@ -73,7 +67,6 @@ static void __free_dma_pages(unsigned long addr, unsigned int pages)
{
unsigned long page = (addr - dma_base) >> PAGE_SHIFT;
unsigned long flags;
- int i;
if ((page + pages) > dma_pages) {
printk(KERN_ERR "%s: freeing outside range.\n", __func__);
@@ -81,9 +74,7 @@ static void __free_dma_pages(unsigned long addr, unsigned int pages)
}
spin_lock_irqsave(&dma_page_lock, flags);
- for (i = page; i < page + pages; i++)
- __clear_bit(i, dma_page);
-
+ bitmap_clear(dma_page, page, pages);
spin_unlock_irqrestore(&dma_page_lock, flags);
}
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 3e16ad9b0a99..8061426b7df5 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -39,12 +39,6 @@ int nr_l1stack_tasks;
void *l1_stack_base;
unsigned long l1_stack_len;
-/*
- * Powermanagement idle function, if any..
- */
-void (*pm_idle)(void) = NULL;
-EXPORT_SYMBOL(pm_idle);
-
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
@@ -81,7 +75,6 @@ void cpu_idle(void)
{
/* endless idle loop with no priority at all */
while (1) {
- void (*idle)(void) = pm_idle;
#ifdef CONFIG_HOTPLUG_CPU
if (cpu_is_offline(smp_processor_id()))
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index 84b4be05840c..b022af6c48f8 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -37,11 +37,6 @@ struct rt_sigframe {
struct ucontext uc;
};
-asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
- return do_sigaltstack(uss, uoss, rdusp());
-}
-
static inline int
rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *pr0)
{
@@ -100,7 +95,7 @@ asmlinkage int sys_rt_sigreturn(void)
if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->usp) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return r0;
@@ -178,10 +173,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info,
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
- err |=
- __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, rdusp());
err |= rt_setup_sigcontext(&frame->uc.uc_mcontext, regs);
err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c
index f608f02f29a3..cb0a4845339e 100644
--- a/arch/blackfin/kernel/time-ts.c
+++ b/arch/blackfin/kernel/time-ts.c
@@ -329,12 +329,6 @@ void bfin_coretmr_clockevent_init(void)
evt->broadcast = smp_timer_broadcast;
#endif
-
-#ifdef CONFIG_SMP
- evt->broadcast = smp_timer_broadcast;
-#endif
-
-
evt->name = "bfin_core_timer";
evt->rating = 350;
evt->irq = -1;
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
index 2310b249675f..3126b920a4a5 100644
--- a/arch/blackfin/kernel/time.c
+++ b/arch/blackfin/kernel/time.c
@@ -85,7 +85,7 @@ time_sched_init(irqreturn_t(*timer_routine) (int, void *))
/*
* Should return useconds since last timer tick
*/
-u32 arch_gettimeoffset(void)
+static u32 blackfin_gettimeoffset(void)
{
unsigned long offset;
unsigned long clocks_per_jiffy;
@@ -141,6 +141,10 @@ void read_persistent_clock(struct timespec *ts)
void __init time_init(void)
{
+#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
+ arch_gettimeoffset = blackfin_gettimeoffset;
+#endif
+
#ifdef CONFIG_RTC_DRV_BFIN
/* [#2663] hack to filter junk RTC values that would cause
* userspace to have to deal with time values greater than
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
index 83ff311fd6ea..6c0c6816a51a 100644
--- a/arch/blackfin/mach-common/ints-priority.c
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -1195,6 +1195,7 @@ static struct syscore_ops sec_pm_syscore_ops = {
.suspend = sec_suspend,
.resume = sec_resume,
};
+
#endif
#else
# define bfin_gpio_set_wake NULL
@@ -1596,7 +1597,10 @@ int __init init_arch_irq(void)
bfin_write_SEC_SCI(1, SEC_CCTL, SEC_CCTL_EN | SEC_CCTL_NMI_EN);
init_software_driven_irq();
+
+#ifdef CONFIG_PM
register_syscore_ops(&sec_pm_syscore_ops);
+#endif
return 0;
}
diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S
index 5239057de4c4..2721c90b0121 100644
--- a/arch/c6x/kernel/entry.S
+++ b/arch/c6x/kernel/entry.S
@@ -598,18 +598,6 @@ ENTRY(enable_exception)
NOP 5
ENDPROC(enable_exception)
-ENTRY(sys_sigaltstack)
-#ifdef CONFIG_C6X_BIG_KERNEL
- MVKL .S1 do_sigaltstack,A0 ; branch to do_sigaltstack
- MVKH .S1 do_sigaltstack,A0
- B .S2X A0
-#else
- B .S2 do_sigaltstack
-#endif
- LDW .D2T1 *+SP(REGS_SP+8),A6
- NOP 4
-ENDPROC(sys_sigaltstack)
-
;;
;; Special system calls
;; return address is in B3
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index c59a01dd9c0c..0e5c187ac7d2 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -50,6 +50,8 @@ config CRIS
select GENERIC_CMOS_UPDATE
select MODULES_USE_ELF_RELA
select CLONE_BACKWARDS2
+ select OLD_SIGSUSPEND
+ select OLD_SIGACTION
config HZ
int
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
index 0bb477c13a4e..61ce6273a895 100644
--- a/arch/cris/arch-v10/kernel/signal.c
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -42,55 +42,6 @@
void do_signal(int canrestart, struct pt_regs *regs);
/*
- * Atomically swap in the new signal mask, and wait for a signal. Define
- * dummy arguments to be able to reach the regs argument. (Note that this
- * arrangement relies on old_sigset_t occupying one register.)
- */
-int sys_sigsuspend(old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-int sys_sigaction(int sig, const struct old_sigaction __user *act,
- struct old_sigaction *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
-int sys_sigaltstack(const stack_t *uss, stack_t __user *uoss)
-{
- return do_sigaltstack(uss, uoss, rdusp());
-}
-
-
-/*
* Do a signal return; undo the signal stack.
*/
@@ -150,11 +101,9 @@ badframe:
return 1;
}
-/* Define dummy arguments to be able to reach the regs argument. */
-
-asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof,
- long srp, struct pt_regs *regs)
+asmlinkage int sys_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct sigframe __user *frame = (struct sigframe *)rdusp();
sigset_t set;
@@ -188,11 +137,9 @@ badframe:
return 0;
}
-/* Define dummy arguments to be able to reach the regs argument. */
-
-asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
- long mof, long srp, struct pt_regs *regs)
+asmlinkage int sys_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp();
sigset_t set;
@@ -214,7 +161,7 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return regs->r10;
@@ -362,6 +309,8 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ err |= __save_altstack(&frame->uc.uc_stack, rdusp());
+
if (err)
goto give_sigsegv;
diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c
index bcffcb6a9415..fce7c541d70d 100644
--- a/arch/cris/arch-v10/kernel/time.c
+++ b/arch/cris/arch-v10/kernel/time.c
@@ -55,9 +55,9 @@ unsigned long get_ns_in_jiffie(void)
return ns;
}
-unsigned long do_slow_gettimeoffset(void)
+static u32 cris_v10_gettimeoffset(void)
{
- unsigned long count;
+ u32 count;
/* The timer interrupt comes from Etrax timer 0. In order to get
* better precision, we check the current value. It might have
@@ -65,8 +65,8 @@ unsigned long do_slow_gettimeoffset(void)
*/
count = *R_TIMER0_DATA;
- /* Convert timer value to usec */
- return (TIMER0_DIV - count) * ((NSEC_PER_SEC/1000)/HZ)/TIMER0_DIV;
+ /* Convert timer value to nsec */
+ return (TIMER0_DIV - count) * (NSEC_PER_SEC/HZ)/TIMER0_DIV;
}
/* Excerpt from the Etrax100 HSDD about the built-in watchdog:
@@ -191,6 +191,8 @@ static struct irqaction irq2 = {
void __init
time_init(void)
{
+ arch_gettimeoffset = cris_v10_gettimeoffset;
+
/* probe for the RTC and read it if it exists
* Before the RTC can be probed the loops_per_usec variable needs
* to be initialized to make usleep work. A better value for
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig
index de43aadcdbc4..af4a486dadcd 100644
--- a/arch/cris/arch-v32/drivers/Kconfig
+++ b/arch/cris/arch-v32/drivers/Kconfig
@@ -680,7 +680,7 @@ config ETRAX_SPI_MMC_BOARD
config SPI_ETRAX_SSER
tristate
- depends on SPI_MASTER && ETRAX_ARCH_V32 && EXPERIMENTAL
+ depends on SPI_MASTER && ETRAX_ARCH_V32
select SPI_BITBANG
help
This enables using an synchronous serial (sser) port as a
@@ -689,7 +689,7 @@ config SPI_ETRAX_SSER
config SPI_ETRAX_GPIO
tristate
- depends on SPI_MASTER && ETRAX_ARCH_V32 && EXPERIMENTAL
+ depends on SPI_MASTER && ETRAX_ARCH_V32
select SPI_BITBANG
help
This enables using GPIO pins port as a SPI master controller
diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c
index b60d1b65a426..01d1375c9004 100644
--- a/arch/cris/arch-v32/kernel/signal.c
+++ b/arch/cris/arch-v32/kernel/signal.c
@@ -51,59 +51,6 @@ struct rt_signal_frame {
void do_signal(int restart, struct pt_regs *regs);
void keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
struct pt_regs *regs);
-/*
- * Swap in the new signal mask, and wait for a signal. Define some
- * dummy arguments to be able to reach the regs argument.
- */
-int
-sys_sigsuspend(old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-int
-sys_sigaction(int signal, const struct old_sigaction *act,
- struct old_sigaction *oact)
-{
- int retval;
- struct k_sigaction newk;
- struct k_sigaction oldk;
-
- if (act) {
- old_sigset_t mask;
-
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(newk.sa.sa_handler, &act->sa_handler) ||
- __get_user(newk.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(newk.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
-
- siginitset(&newk.sa.sa_mask, mask);
- }
-
- retval = do_sigaction(signal, act ? &newk : NULL, oact ? &oldk : NULL);
-
- if (!retval && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(oldk.sa.sa_handler, &oact->sa_handler) ||
- __put_user(oldk.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(oldk.sa.sa_flags, &oact->sa_flags) ||
- __put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
-
- }
-
- return retval;
-}
-
-int
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
- return do_sigaltstack(uss, uoss, rdusp());
-}
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
@@ -135,11 +82,9 @@ badframe:
return 1;
}
-/* Define some dummy arguments to be able to reach the regs argument. */
-asmlinkage int
-sys_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
- struct pt_regs *regs)
+asmlinkage int sys_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
sigset_t set;
struct signal_frame __user *frame;
unsigned long oldspc = regs->spc;
@@ -178,11 +123,9 @@ badframe:
return 0;
}
-/* Define some dummy variables to be able to reach the regs argument. */
-asmlinkage int
-sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
- struct pt_regs *regs)
+asmlinkage int sys_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
sigset_t set;
struct rt_signal_frame __user *frame;
unsigned long oldspc = regs->spc;
@@ -209,7 +152,7 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
keep_debug_flags(oldccs, oldspc, regs);
@@ -371,6 +314,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ err |= __save_altstack(&frame->uc.uc_stack, rdusp());
if (err)
goto give_sigsegv;
diff --git a/arch/cris/include/asm/signal.h b/arch/cris/include/asm/signal.h
index c0cb1fd4644c..c11b8745cece 100644
--- a/arch/cris/include/asm/signal.h
+++ b/arch/cris/include/asm/signal.h
@@ -16,23 +16,8 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
-};
-
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#define __ARCH_HAS_SA_RESTORER
+
#include <asm/sigcontext.h>
#endif
diff --git a/arch/cris/include/asm/unistd.h b/arch/cris/include/asm/unistd.h
index 6d062bdf92d4..be57a988bfb9 100644
--- a/arch/cris/include/asm/unistd.h
+++ b/arch/cris/include/asm/unistd.h
@@ -30,8 +30,6 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
diff --git a/arch/cris/include/uapi/asm/posix_types.h b/arch/cris/include/uapi/asm/posix_types.h
index ce4e51793151..0f22e6a67ea5 100644
--- a/arch/cris/include/uapi/asm/posix_types.h
+++ b/arch/cris/include/uapi/asm/posix_types.h
@@ -22,11 +22,6 @@ typedef unsigned short __kernel_uid_t;
typedef unsigned short __kernel_gid_t;
#define __kernel_uid_t __kernel_uid_t
-typedef __SIZE_TYPE__ __kernel_size_t;
-typedef long __kernel_ssize_t;
-typedef int __kernel_ptrdiff_t;
-#define __kernel_size_t __kernel_size_t
-
typedef unsigned short __kernel_old_dev_t;
#define __kernel_old_dev_t __kernel_old_dev_t
diff --git a/arch/cris/include/uapi/asm/socket.h b/arch/cris/include/uapi/asm/socket.h
index b681b043f6c8..50692b738c75 100644
--- a/arch/cris/include/uapi/asm/socket.h
+++ b/arch/cris/include/uapi/asm/socket.h
@@ -24,7 +24,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT 15
#define SO_PASSCRED 16
#define SO_PEERCRED 17
#define SO_RCVLOWAT 18
@@ -72,6 +72,8 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
index 7f65be6f7f17..104ff4dd9b98 100644
--- a/arch/cris/kernel/process.c
+++ b/arch/cris/kernel/process.c
@@ -54,11 +54,6 @@ void enable_hlt(void)
EXPORT_SYMBOL(enable_hlt);
-/*
- * The following aren't currently used.
- */
-void (*pm_idle)(void);
-
extern void default_idle(void);
void (*pm_power_off)(void);
@@ -77,16 +72,12 @@ void cpu_idle (void)
while (1) {
rcu_idle_enter();
while (!need_resched()) {
- void (*idle)(void);
/*
* Mark this as an RCU critical section so that
* synchronize_kernel() in the unload path waits
* for our completion.
*/
- idle = pm_idle;
- if (!idle)
- idle = default_idle;
- idle();
+ default_idle();
}
rcu_idle_exit();
schedule_preempt_disabled();
diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c
index 277ffc459e4b..fe6acdabbc8d 100644
--- a/arch/cris/kernel/time.c
+++ b/arch/cris/kernel/time.c
@@ -39,17 +39,6 @@
extern unsigned long loops_per_jiffy; /* init/main.c */
unsigned long loops_per_usec;
-
-#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
-extern unsigned long do_slow_gettimeoffset(void);
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
-
-u32 arch_gettimeoffset(void)
-{
- return do_gettimeoffset() * 1000;
-}
-#endif
-
int set_rtc_mmss(unsigned long nowtime)
{
D(printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime));
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 9d262645f667..2d0509d4cfee 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -3,7 +3,6 @@ config FRV
default y
select HAVE_IDE
select HAVE_ARCH_TRACEHOOK
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select HAVE_UID16
select HAVE_GENERIC_HARDIRQS
@@ -12,6 +11,8 @@ config FRV
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_CPU_DEVICES
select ARCH_WANT_IPC_PARSE_VERSION
+ select OLD_SIGSUSPEND3
+ select OLD_SIGACTION
config ZONE_DMA
bool
diff --git a/arch/frv/include/asm/signal.h b/arch/frv/include/asm/signal.h
index 599500a31025..eca0abcb79d6 100644
--- a/arch/frv/include/asm/signal.h
+++ b/arch/frv/include/asm/signal.h
@@ -3,11 +3,4 @@
#include <uapi/asm/signal.h>
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
-};
-
#endif /* _ASM_SIGNAL_H */
diff --git a/arch/frv/include/asm/unistd.h b/arch/frv/include/asm/unistd.h
index d685da17f5fb..4cfcc7bba25a 100644
--- a/arch/frv/include/asm/unistd.h
+++ b/arch/frv/include/asm/unistd.h
@@ -27,8 +27,6 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
/* #define __ARCH_WANT_SYS_SIGPENDING */
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
diff --git a/arch/frv/include/uapi/asm/socket.h b/arch/frv/include/uapi/asm/socket.h
index 871f89b7fbda..595391f0f98c 100644
--- a/arch/frv/include/uapi/asm/socket.h
+++ b/arch/frv/include/uapi/asm/socket.h
@@ -22,7 +22,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT 15
#define SO_PASSCRED 16
#define SO_PEERCRED 17
#define SO_RCVLOWAT 18
@@ -70,5 +70,7 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 535810a3217a..d822700d4f15 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -33,55 +33,6 @@ struct fdpic_func_descriptor {
};
/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-asmlinkage int sys_sigaction(int sig,
- const struct old_sigaction __user *act,
- struct old_sigaction __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
-asmlinkage
-int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
- return do_sigaltstack(uss, uoss, __frame->sp);
-}
-
-
-/*
* Do a signal return; undo the signal stack.
*/
@@ -173,7 +124,7 @@ asmlinkage int sys_rt_sigreturn(void)
if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, __frame->sp) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return gr8;
@@ -345,9 +296,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
if (__put_user(0, &frame->uc.uc_flags) ||
__put_user(NULL, &frame->uc.uc_link) ||
- __put_user((void __user *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) ||
- __put_user(sas_ss_flags(__frame->sp), &frame->uc.uc_stack.ss_flags) ||
- __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size))
+ __save_altstack(&frame->uc.uc_stack, __frame->sp))
goto give_sigsegv;
if (setup_sigcontext(&frame->uc.uc_mcontext, set->sig[0]))
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 2d2efb653ee0..05b613af223a 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -9,6 +9,8 @@ config H8300
select GENERIC_IRQ_SHOW
select GENERIC_CPU_DEVICES
select MODULES_USE_ELF_RELA
+ select OLD_SIGSUSPEND3
+ select OLD_SIGACTION
config SYMBOL_PREFIX
string
diff --git a/arch/h8300/README b/arch/h8300/README
index 637f5a02f311..efa805fda19b 100644
--- a/arch/h8300/README
+++ b/arch/h8300/README
@@ -11,7 +11,7 @@ H8/300H and H8S
2.AE 3068/AE 3069
more information
MICROTRONIQUE <http://www.microtronique.com/>
- Akizuki Denshi Tsusho Ltd. <http://www.akizuki.ne.jp> (Japanese Only)
+ Akizuki Denshi Tsusho Ltd. <http://akizukidenshi.com/> (Japanese Only)
3.H8MAX
see http://ip-sol.jp/h8max/ (Japanese Only)
diff --git a/arch/h8300/include/asm/signal.h b/arch/h8300/include/asm/signal.h
index 66c81c67e55d..6341e36386f8 100644
--- a/arch/h8300/include/asm/signal.h
+++ b/arch/h8300/include/asm/signal.h
@@ -16,23 +16,7 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
-};
-
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#define __ARCH_HAS_SA_RESTORER
#include <asm/sigcontext.h>
#undef __HAVE_ARCH_SIG_BITOPS
diff --git a/arch/h8300/include/asm/unistd.h b/arch/h8300/include/asm/unistd.h
index aa38105959fb..6721856d841b 100644
--- a/arch/h8300/include/asm/unistd.h
+++ b/arch/h8300/include/asm/unistd.h
@@ -29,8 +29,6 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
diff --git a/arch/h8300/include/uapi/asm/socket.h b/arch/h8300/include/uapi/asm/socket.h
index 90a2e573c7e6..43e32621da7d 100644
--- a/arch/h8300/include/uapi/asm/socket.h
+++ b/arch/h8300/include/uapi/asm/socket.h
@@ -22,7 +22,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT 15
#define SO_PASSCRED 16
#define SO_PEERCRED 17
#define SO_RCVLOWAT 18
@@ -70,4 +70,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index 0e81b96c642f..a65ff3b76326 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -47,56 +47,6 @@
#include <asm/ucontext.h>
/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(int unused1, int unused2, old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction *act,
- struct old_sigaction *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
-asmlinkage int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
-{
- return do_sigaltstack(uss, uoss, rdusp());
-}
-
-
-/*
* Do a signal return; undo the signal stack.
*
* Keep the return code on the stack quadword aligned!
@@ -136,9 +86,9 @@ struct rt_sigframe
} __attribute__((aligned(2),packed));
static inline int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc,
- int *pd0)
+restore_sigcontext(struct sigcontext *usc, int *pd0)
{
+ struct pt_regs *regs = current_pt_regs();
int err = 0;
unsigned int ccr;
unsigned int usp;
@@ -167,9 +117,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc,
return err;
}
-asmlinkage int do_sigreturn(unsigned long __unused,...)
+asmlinkage int sys_sigreturn(void)
{
- struct pt_regs *regs = (struct pt_regs *) (&__unused - 1);
unsigned long usp = rdusp();
struct sigframe *frame = (struct sigframe *)(usp - 4);
sigset_t set;
@@ -185,7 +134,7 @@ asmlinkage int do_sigreturn(unsigned long __unused,...)
set_current_blocked(&set);
- if (restore_sigcontext(regs, &frame->sc, &er0))
+ if (restore_sigcontext(&frame->sc, &er0))
goto badframe;
return er0;
@@ -194,9 +143,8 @@ badframe:
return 0;
}
-asmlinkage int do_rt_sigreturn(unsigned long __unused,...)
+asmlinkage int sys_rt_sigreturn(void)
{
- struct pt_regs *regs = (struct pt_regs *) &__unused;
unsigned long usp = rdusp();
struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
sigset_t set;
@@ -209,10 +157,10 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused,...)
set_current_blocked(&set);
- if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &er0))
+ if (restore_sigcontext(&frame->uc.uc_mcontext, &er0))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return er0;
@@ -358,11 +306,7 @@ static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user((void *)current->sas_ss_sp,
- &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(rdusp()),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, rdusp());
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S
index b74dd0ade58d..5c2168fb9b9e 100644
--- a/arch/h8300/kernel/syscalls.S
+++ b/arch/h8300/kernel/syscalls.S
@@ -334,18 +334,3 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_getcpu)
.long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_pwait */
.long SYMBOL_NAME(sys_setns) /* 320 */
-
- .macro call_sp addr
- mov.l #SYMBOL_NAME(\addr),er6
- bra SYMBOL_NAME(syscall_trampoline):8
- .endm
-
-SYMBOL_NAME_LABEL(sys_sigreturn)
- call_sp do_sigreturn
-
-SYMBOL_NAME_LABEL(sys_rt_sigreturn)
- call_sp do_rt_sigreturn
-
-SYMBOL_NAME_LABEL(syscall_trampoline)
- mov.l sp,er0
- jmp @er6
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig
index 0744f7d7b1fd..e4decc6b8947 100644
--- a/arch/hexagon/Kconfig
+++ b/arch/hexagon/Kconfig
@@ -12,9 +12,7 @@ config HEXAGON
# select ARCH_WANT_OPTIONAL_GPIOLIB
# select ARCH_REQUIRE_GPIOLIB
# select HAVE_CLK
- # select IRQ_PER_CPU
# select GENERIC_PENDING_IRQ if SMP
- select HAVE_IRQ_WORK
select GENERIC_ATOMIC64
select HAVE_PERF_EVENTS
select HAVE_GENERIC_HARDIRQS
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c
index fe0d1373165d..60fa2ca3202b 100644
--- a/arch/hexagon/kernel/signal.c
+++ b/arch/hexagon/kernel/signal.c
@@ -125,6 +125,7 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(0x5400c004, &frame->tramp[1]);
err |= setup_sigcontext(regs, &frame->uc.uc_mcontext);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ err |= __save_altstack(&frame->uc.uc_stack, user_stack_pointer(regs));
if (err)
goto sigsegv;
@@ -247,12 +248,6 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
/*
* Architecture-specific wrappers for signal-related system calls
*/
-asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
- struct pt_regs *regs = current_pt_regs();
-
- return do_sigaltstack(uss, uoss, regs->r29);
-}
asmlinkage int sys_rt_sigreturn(void)
{
@@ -288,14 +283,7 @@ asmlinkage int sys_rt_sigreturn(void)
*/
regs->syscall_nr = __NR_rt_sigreturn;
- /*
- * If we were meticulous, we'd only call this if we knew that
- * we were actually going to use an alternate stack, and we'd
- * consider any error to be fatal. What we do here, in common
- * with many other architectures, is call it blindly and only
- * consider the -EFAULT return case to be proof of a problem.
- */
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, pt_psp(regs)) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return 0;
diff --git a/arch/hexagon/kernel/traps.c b/arch/hexagon/kernel/traps.c
index a41eeb8eeaa1..be5e2dd9c9d3 100644
--- a/arch/hexagon/kernel/traps.c
+++ b/arch/hexagon/kernel/traps.c
@@ -225,7 +225,7 @@ int die(const char *str, struct pt_regs *regs, long err)
do_show_stack(current, &regs->r30, pt_elr(regs));
bust_spinlocks(0);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
spin_unlock_irq(&die.lock);
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 3279646120e3..c90366ef7183 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -29,7 +29,6 @@ config IA64
select ARCH_DISCARD_MEMBLOCK
select GENERIC_IRQ_PROBE
select GENERIC_PENDING_IRQ if SMP
- select IRQ_PER_CPU
select GENERIC_IRQ_SHOW
select ARCH_WANT_OPTIONAL_GPIOLIB
select ARCH_HAVE_NMI_SAFE_CMPXCHG
@@ -40,6 +39,7 @@ config IA64
select ARCH_THREAD_INFO_ALLOCATOR
select ARCH_CLOCKSOURCE_DATA
select GENERIC_TIME_VSYSCALL_OLD
+ select SYSCTL_ARCH_UNALIGN_NO_WARN
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
default y
@@ -375,8 +375,8 @@ config NR_CPUS
performance hit.
config HOTPLUG_CPU
- bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
- depends on SMP && EXPERIMENTAL
+ bool "Support for hot-pluggable CPUs"
+ depends on SMP
select HOTPLUG
default n
---help---
@@ -555,8 +555,8 @@ config IA64_HP_AML_NFW
source "drivers/sn/Kconfig"
config KEXEC
- bool "kexec system call (EXPERIMENTAL)"
- depends on EXPERIMENTAL && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
+ bool "kexec system call"
+ depends on !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/ia64/hp/common/aml_nfw.c b/arch/ia64/hp/common/aml_nfw.c
index 6192f7188654..916ffe770bcf 100644
--- a/arch/ia64/hp/common/aml_nfw.c
+++ b/arch/ia64/hp/common/aml_nfw.c
@@ -191,7 +191,7 @@ static int aml_nfw_add(struct acpi_device *device)
return aml_nfw_add_global_handler();
}
-static int aml_nfw_remove(struct acpi_device *device, int type)
+static int aml_nfw_remove(struct acpi_device *device)
{
return aml_nfw_remove_global_handler();
}
diff --git a/arch/ia64/hp/sim/Kconfig b/arch/ia64/hp/sim/Kconfig
index 8d513a8c5266..d84707d55203 100644
--- a/arch/ia64/hp/sim/Kconfig
+++ b/arch/ia64/hp/sim/Kconfig
@@ -8,6 +8,7 @@ config HP_SIMETH
config HP_SIMSERIAL
bool "Simulated serial driver support"
+ depends on TTY
config HP_SIMSERIAL_CONSOLE
bool "Console for HP simulator"
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index fc3924d18c1f..da2f319fb71d 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -53,7 +53,7 @@ struct tty_driver *hp_simserial_driver;
static struct console *console;
-static void receive_chars(struct tty_struct *tty)
+static void receive_chars(struct tty_port *port)
{
unsigned char ch;
static unsigned char seen_esc = 0;
@@ -81,10 +81,10 @@ static void receive_chars(struct tty_struct *tty)
}
seen_esc = 0;
- if (tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0)
+ if (tty_insert_flip_char(port, ch, TTY_NORMAL) == 0)
break;
}
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(port);
}
/*
@@ -93,18 +93,9 @@ static void receive_chars(struct tty_struct *tty)
static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
{
struct serial_state *info = dev_id;
- struct tty_struct *tty = tty_port_tty_get(&info->port);
- if (!tty) {
- printk(KERN_INFO "%s: tty=0 problem\n", __func__);
- return IRQ_NONE;
- }
- /*
- * pretty simple in our case, because we only get interrupts
- * on inbound traffic
- */
- receive_chars(tty);
- tty_kref_put(tty);
+ receive_chars(&info->port);
+
return IRQ_HANDLED;
}
@@ -435,7 +426,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
struct tty_port *port = &info->port;
tty->driver_data = info;
- tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
/*
* figure out which console to use (should be one already)
diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h
index 359e68a03ca3..faa1bf0da815 100644
--- a/arch/ia64/include/asm/acpi.h
+++ b/arch/ia64/include/asm/acpi.h
@@ -52,10 +52,6 @@
/* Asm macros */
-#define ACPI_ASM_MACROS
-#define BREAKPOINT3
-#define ACPI_DISABLE_IRQS() local_irq_disable()
-#define ACPI_ENABLE_IRQS() local_irq_enable()
#define ACPI_FLUSH_CPU_CACHE()
static inline int
diff --git a/arch/ia64/include/asm/cputime.h b/arch/ia64/include/asm/cputime.h
index 7fcf7f08ab06..e2d3f5baf265 100644
--- a/arch/ia64/include/asm/cputime.h
+++ b/arch/ia64/include/asm/cputime.h
@@ -11,99 +11,19 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * If we have CONFIG_VIRT_CPU_ACCOUNTING, we measure cpu time in nsec.
+ * If we have CONFIG_VIRT_CPU_ACCOUNTING_NATIVE, we measure cpu time in nsec.
* Otherwise we measure cpu time in jiffies using the generic definitions.
*/
#ifndef __IA64_CPUTIME_H
#define __IA64_CPUTIME_H
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
-#include <asm-generic/cputime.h>
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+# include <asm-generic/cputime.h>
#else
-
-#include <linux/time.h>
-#include <linux/jiffies.h>
-#include <asm/processor.h>
-
-typedef u64 __nocast cputime_t;
-typedef u64 __nocast cputime64_t;
-
-#define cputime_one_jiffy jiffies_to_cputime(1)
-
-/*
- * Convert cputime <-> jiffies (HZ)
- */
-#define cputime_to_jiffies(__ct) \
- ((__force u64)(__ct) / (NSEC_PER_SEC / HZ))
-#define jiffies_to_cputime(__jif) \
- (__force cputime_t)((__jif) * (NSEC_PER_SEC / HZ))
-#define cputime64_to_jiffies64(__ct) \
- ((__force u64)(__ct) / (NSEC_PER_SEC / HZ))
-#define jiffies64_to_cputime64(__jif) \
- (__force cputime64_t)((__jif) * (NSEC_PER_SEC / HZ))
-
-/*
- * Convert cputime <-> microseconds
- */
-#define cputime_to_usecs(__ct) \
- ((__force u64)(__ct) / NSEC_PER_USEC)
-#define usecs_to_cputime(__usecs) \
- (__force cputime_t)((__usecs) * NSEC_PER_USEC)
-#define usecs_to_cputime64(__usecs) \
- (__force cputime64_t)((__usecs) * NSEC_PER_USEC)
-
-/*
- * Convert cputime <-> seconds
- */
-#define cputime_to_secs(__ct) \
- ((__force u64)(__ct) / NSEC_PER_SEC)
-#define secs_to_cputime(__secs) \
- (__force cputime_t)((__secs) * NSEC_PER_SEC)
-
-/*
- * Convert cputime <-> timespec (nsec)
- */
-static inline cputime_t timespec_to_cputime(const struct timespec *val)
-{
- u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_nsec;
- return (__force cputime_t) ret;
-}
-static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val)
-{
- val->tv_sec = (__force u64) ct / NSEC_PER_SEC;
- val->tv_nsec = (__force u64) ct % NSEC_PER_SEC;
-}
-
-/*
- * Convert cputime <-> timeval (msec)
- */
-static inline cputime_t timeval_to_cputime(struct timeval *val)
-{
- u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_usec * NSEC_PER_USEC;
- return (__force cputime_t) ret;
-}
-static inline void cputime_to_timeval(const cputime_t ct, struct timeval *val)
-{
- val->tv_sec = (__force u64) ct / NSEC_PER_SEC;
- val->tv_usec = ((__force u64) ct % NSEC_PER_SEC) / NSEC_PER_USEC;
-}
-
-/*
- * Convert cputime <-> clock (USER_HZ)
- */
-#define cputime_to_clock_t(__ct) \
- ((__force u64)(__ct) / (NSEC_PER_SEC / USER_HZ))
-#define clock_t_to_cputime(__x) \
- (__force cputime_t)((__x) * (NSEC_PER_SEC / USER_HZ))
-
-/*
- * Convert cputime64 to clock.
- */
-#define cputime64_to_clock_t(__ct) \
- cputime_to_clock_t((__force cputime_t)__ct)
-
+# include <asm/processor.h>
+# include <asm-generic/cputime_nsecs.h>
extern void arch_vtime_task_switch(struct task_struct *tsk);
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
#endif /* __IA64_CPUTIME_H */
diff --git a/arch/ia64/include/asm/kvm_host.h b/arch/ia64/include/asm/kvm_host.h
index 6d6a5ac48d85..cfa74983c675 100644
--- a/arch/ia64/include/asm/kvm_host.h
+++ b/arch/ia64/include/asm/kvm_host.h
@@ -23,9 +23,7 @@
#ifndef __ASM_KVM_HOST_H
#define __ASM_KVM_HOST_H
-#define KVM_MEMORY_SLOTS 32
-/* memory slots that does not exposed to userspace */
-#define KVM_PRIVATE_MEM_SLOTS 4
+#define KVM_USER_MEM_SLOTS 32
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
diff --git a/arch/ia64/include/asm/signal.h b/arch/ia64/include/asm/signal.h
index 3a1b20e74c5c..c62afa4a0dc2 100644
--- a/arch/ia64/include/asm/signal.h
+++ b/arch/ia64/include/asm/signal.h
@@ -26,16 +26,6 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
-
# include <asm/sigcontext.h>
# endif /* !__ASSEMBLY__ */
diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h
index ff2ae4136584..020d655ed082 100644
--- a/arch/ia64/include/asm/thread_info.h
+++ b/arch/ia64/include/asm/thread_info.h
@@ -31,7 +31,7 @@ struct thread_info {
mm_segment_t addr_limit; /* user-level address space limit */
int preempt_count; /* 0=premptable, <0=BUG; will also serve as bh-counter */
struct restart_block restart_block;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
__u64 ac_stamp;
__u64 ac_leave;
__u64 ac_stime;
@@ -69,7 +69,7 @@ struct thread_info {
#define task_stack_page(tsk) ((void *)(tsk))
#define __HAVE_THREAD_FUNCTIONS
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
#define setup_thread_stack(p, org) \
*task_thread_info(p) = *task_thread_info(org); \
task_thread_info(p)->ac_stime = 0; \
diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h
index c3cc42a15af1..096373800f73 100644
--- a/arch/ia64/include/asm/unistd.h
+++ b/arch/ia64/include/asm/unistd.h
@@ -27,9 +27,6 @@
#define __IGNORE_vfork /* clone() */
#define __IGNORE_umount2 /* umount() */
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-
#if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
#include <linux/types.h>
@@ -47,12 +44,7 @@ asmlinkage unsigned long sys_mmap2(
int prot, int flags,
int fd, long pgoff);
struct pt_regs;
-struct sigaction;
asmlinkage long sys_ia64_pipe(void);
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
/*
* "Conditional" syscalls
diff --git a/arch/ia64/include/asm/xen/minstate.h b/arch/ia64/include/asm/xen/minstate.h
index c57fa910f2c9..00cf03e0cb82 100644
--- a/arch/ia64/include/asm/xen/minstate.h
+++ b/arch/ia64/include/asm/xen/minstate.h
@@ -1,5 +1,5 @@
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
/* read ar.itc in advance, and use it before leaving bank 0 */
#define XEN_ACCOUNT_GET_STAMP \
MOV_FROM_ITC(pUStk, p6, r20, r2);
diff --git a/arch/ia64/include/uapi/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h
index 23d6759bb57b..c567adc8bea5 100644
--- a/arch/ia64/include/uapi/asm/socket.h
+++ b/arch/ia64/include/uapi/asm/socket.h
@@ -31,7 +31,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT 15
#define SO_PASSCRED 16
#define SO_PEERCRED 17
#define SO_RCVLOWAT 18
@@ -79,4 +79,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
+
#endif /* _ASM_IA64_SOCKET_H */
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c
index a48bd9a9927b..46c9e3007315 100644
--- a/arch/ia64/kernel/asm-offsets.c
+++ b/arch/ia64/kernel/asm-offsets.c
@@ -41,7 +41,7 @@ void foo(void)
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
DEFINE(TI_AC_STAMP, offsetof(struct thread_info, ac_stamp));
DEFINE(TI_AC_LEAVE, offsetof(struct thread_info, ac_leave));
DEFINE(TI_AC_STIME, offsetof(struct thread_info, ac_stime));
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 6bfd8429ee0f..7a53530f22c2 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -724,7 +724,7 @@ GLOBAL_ENTRY(__paravirt_leave_syscall)
#endif
.global __paravirt_work_processed_syscall;
__paravirt_work_processed_syscall:
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
adds r2=PT(LOADRS)+16,r12
MOV_FROM_ITC(pUStk, p9, r22, r19) // fetch time at leave
adds r18=TI_FLAGS+IA64_TASK_SIZE,r13
@@ -762,7 +762,7 @@ __paravirt_work_processed_syscall:
ld8 r29=[r2],16 // M0|1 load cr.ipsr
ld8 r28=[r3],16 // M0|1 load cr.iip
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
(pUStk) add r14=TI_AC_LEAVE+IA64_TASK_SIZE,r13
;;
ld8 r30=[r2],16 // M0|1 load cr.ifs
@@ -793,7 +793,7 @@ __paravirt_work_processed_syscall:
ld8.fill r1=[r3],16 // M0|1 load r1
(pUStk) mov r17=1 // A
;;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
(pUStk) st1 [r15]=r17 // M2|3
#else
(pUStk) st1 [r14]=r17 // M2|3
@@ -813,7 +813,7 @@ __paravirt_work_processed_syscall:
shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition
COVER // B add current frame into dirty partition & set cr.ifs
;;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
mov r19=ar.bsp // M2 get new backing store pointer
st8 [r14]=r22 // M save time at leave
mov f10=f0 // F clear f10
@@ -948,7 +948,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel)
adds r16=PT(CR_IPSR)+16,r12
adds r17=PT(CR_IIP)+16,r12
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
.pred.rel.mutex pUStk,pKStk
MOV_FROM_PSR(pKStk, r22, r29) // M2 read PSR now that interrupts are disabled
MOV_FROM_ITC(pUStk, p9, r22, r29) // M fetch time at leave
@@ -981,7 +981,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel)
;;
ld8.fill r12=[r16],16
ld8.fill r13=[r17],16
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
(pUStk) adds r3=TI_AC_LEAVE+IA64_TASK_SIZE,r18
#else
(pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18
@@ -989,7 +989,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel)
;;
ld8 r20=[r16],16 // ar.fpsr
ld8.fill r15=[r17],16
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
(pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18 // deferred
#endif
;;
@@ -997,7 +997,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel)
ld8.fill r2=[r17]
(pUStk) mov r17=1
;;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
// mmi_ : ld8 st1 shr;; mmi_ : st8 st1 shr;;
// mib : mov add br -> mib : ld8 add br
// bbb_ : br nop cover;; mbb_ : mov br cover;;
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index e662f178b990..c4cd45d97749 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -529,7 +529,7 @@ GLOBAL_ENTRY(paravirt_fsys_bubble_down)
nop.i 0
;;
mov ar.rsc=0 // M2 set enforced lazy mode, pl 0, LE, loadrs=0
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
MOV_FROM_ITC(p0, p6, r30, r23) // M get cycle for accounting
#else
nop.m 0
@@ -555,7 +555,7 @@ GLOBAL_ENTRY(paravirt_fsys_bubble_down)
cmp.ne pKStk,pUStk=r0,r0 // A set pKStk <- 0, pUStk <- 1
br.call.sptk.many b7=ia64_syscall_setup // B
;;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
// mov.m r30=ar.itc is called in advance
add r16=TI_AC_STAMP+IA64_TASK_SIZE,r2
add r17=TI_AC_LEAVE+IA64_TASK_SIZE,r2
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
index 4738ff7bd66a..9be4e497f3d3 100644
--- a/arch/ia64/kernel/head.S
+++ b/arch/ia64/kernel/head.S
@@ -1073,7 +1073,7 @@ END(ia64_native_sched_clock)
sched_clock = ia64_native_sched_clock
#endif
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
GLOBAL_ENTRY(cycle_to_cputime)
alloc r16=ar.pfs,1,0,0,0
addl r8=THIS_CPU(ia64_cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0
@@ -1091,7 +1091,7 @@ GLOBAL_ENTRY(cycle_to_cputime)
shrp r8=r9,r8,IA64_NSEC_PER_CYC_SHIFT
br.ret.sptk.many rp
END(cycle_to_cputime)
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
#ifdef CONFIG_IA64_BRL_EMU
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index fa25689fc453..689ffcaa284e 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -784,7 +784,7 @@ ENTRY(break_fault)
(p8) adds r28=16,r28 // A switch cr.iip to next bundle
(p9) adds r8=1,r8 // A increment ei to next slot
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
;;
mov b6=r30 // I0 setup syscall handler branch reg early
#else
@@ -801,7 +801,7 @@ ENTRY(break_fault)
//
///////////////////////////////////////////////////////////////////////
st1 [r16]=r0 // M2|3 clear current->thread.on_ustack flag
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
MOV_FROM_ITC(p0, p14, r30, r18) // M get cycle for accounting
#else
mov b6=r30 // I0 setup syscall handler branch reg early
@@ -817,7 +817,7 @@ ENTRY(break_fault)
cmp.eq p14,p0=r9,r0 // A are syscalls being traced/audited?
br.call.sptk.many b7=ia64_syscall_setup // B
1:
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
// mov.m r30=ar.itc is called in advance, and r13 is current
add r16=TI_AC_STAMP+IA64_TASK_SIZE,r13 // A
add r17=TI_AC_LEAVE+IA64_TASK_SIZE,r13 // A
@@ -1043,7 +1043,7 @@ END(ia64_syscall_setup)
DBG_FAULT(16)
FAULT(16)
-#if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(__IA64_ASM_PARAVIRTUALIZED_NATIVE)
+#if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(__IA64_ASM_PARAVIRTUALIZED_NATIVE)
/*
* There is no particular reason for this code to be here, other than
* that there happens to be space here that would go unused otherwise.
diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h
index d56753a11636..cc82a7d744c9 100644
--- a/arch/ia64/kernel/minstate.h
+++ b/arch/ia64/kernel/minstate.h
@@ -4,7 +4,7 @@
#include "entry.h"
#include "paravirt_inst.h"
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
/* read ar.itc in advance, and use it before leaving bank 0 */
#define ACCOUNT_GET_STAMP \
(pUStk) mov.m r20=ar.itc;
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 31360cbbd5f8..e34f565f595a 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -57,8 +57,6 @@ void (*ia64_mark_idle)(int);
unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE;
EXPORT_SYMBOL(boot_option_idle_override);
-void (*pm_idle) (void);
-EXPORT_SYMBOL(pm_idle);
void (*pm_power_off) (void);
EXPORT_SYMBOL(pm_power_off);
@@ -301,7 +299,6 @@ cpu_idle (void)
if (mark_idle)
(*mark_idle)(1);
- idle = pm_idle;
if (!idle)
idle = default_idle;
(*idle)();
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index aaefd9b94f2f..2029cc0d2fc6 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -1051,7 +1051,6 @@ cpu_init (void)
max_num_phys_stacked = num_phys_stacked;
}
platform_cpu_init();
- pm_idle = default_idle;
}
void __init
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 680b73786be8..3637e03d2282 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -39,14 +39,6 @@
# define GET_SIGSET(k,u) __get_user((k)->sig[0], &(u)->sig[0])
#endif
-asmlinkage long
-sys_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, long arg2,
- long arg3, long arg4, long arg5, long arg6, long arg7,
- struct pt_regs regs)
-{
- return do_sigaltstack(uss, uoss, regs.r12);
-}
-
static long
restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr)
{
@@ -208,11 +200,8 @@ ia64_rt_sigreturn (struct sigscratch *scr)
printk("SIG return (%s:%d): sp=%lx ip=%lx\n",
current->comm, current->pid, scr->pt.r12, scr->pt.cr_iip);
#endif
- /*
- * It is more difficult to avoid calling this function than to
- * call it and ignore errors.
- */
- do_sigaltstack(&sc->sc_stack, NULL, scr->pt.r12);
+ if (restore_altstack(&sc->sc_stack))
+ goto give_sigsegv;
return retval;
give_sigsegv:
@@ -376,9 +365,7 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
err |= copy_siginfo_to_user(&frame->info, info);
- err |= __put_user(current->sas_ss_sp, &frame->sc.sc_stack.ss_sp);
- err |= __put_user(current->sas_ss_size, &frame->sc.sc_stack.ss_size);
- err |= __put_user(sas_ss_flags(scr->pt.r12), &frame->sc.sc_stack.ss_flags);
+ err |= __save_altstack(&frame->sc.sc_stack, scr->pt.r12);
err |= setup_sigcontext(&frame->sc, set, scr);
if (unlikely(err))
diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
index d9439ef2f661..41e33f84c185 100644
--- a/arch/ia64/kernel/sys_ia64.c
+++ b/arch/ia64/kernel/sys_ia64.c
@@ -25,9 +25,9 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len
unsigned long pgoff, unsigned long flags)
{
long map_shared = (flags & MAP_SHARED);
- unsigned long start_addr, align_mask = PAGE_SIZE - 1;
+ unsigned long align_mask = 0;
struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
+ struct vm_unmapped_area_info info;
if (len > RGN_MAP_LIMIT)
return -ENOMEM;
@@ -44,7 +44,7 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len
addr = 0;
#endif
if (!addr)
- addr = mm->free_area_cache;
+ addr = TASK_UNMAPPED_BASE;
if (map_shared && (TASK_SIZE > 0xfffffffful))
/*
@@ -53,28 +53,15 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len
* tasks, we prefer to avoid exhausting the address space too quickly by
* limiting alignment to a single page.
*/
- align_mask = SHMLBA - 1;
-
- full_search:
- start_addr = addr = (addr + align_mask) & ~align_mask;
-
- for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
- /* At this point: (!vma || addr < vma->vm_end). */
- if (TASK_SIZE - len < addr || RGN_MAP_LIMIT - len < REGION_OFFSET(addr)) {
- if (start_addr != TASK_UNMAPPED_BASE) {
- /* Start a new search --- just in case we missed some holes. */
- addr = TASK_UNMAPPED_BASE;
- goto full_search;
- }
- return -ENOMEM;
- }
- if (!vma || addr + len <= vma->vm_start) {
- /* Remember the address where we stopped this search: */
- mm->free_area_cache = addr + len;
- return addr;
- }
- addr = (vma->vm_end + align_mask) & ~align_mask;
- }
+ align_mask = PAGE_MASK & (SHMLBA - 1);
+
+ info.flags = 0;
+ info.length = len;
+ info.low_limit = addr;
+ info.high_limit = TASK_SIZE;
+ info.align_mask = align_mask;
+ info.align_offset = 0;
+ return vm_unmapped_area(&info);
}
asmlinkage long
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 88a794536bc0..fbaac1afb844 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -77,7 +77,7 @@ static struct clocksource clocksource_itc = {
};
static struct clocksource *itc_clocksource;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
#include <linux/kernel_stat.h>
@@ -136,13 +136,14 @@ void vtime_account_system(struct task_struct *tsk)
account_system_time(tsk, 0, delta, delta);
}
+EXPORT_SYMBOL_GPL(vtime_account_system);
void vtime_account_idle(struct task_struct *tsk)
{
account_idle_time(vtime_delta(tsk));
}
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
static irqreturn_t
timer_interrupt (int irq, void *dev_id)
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index bd42b76000d1..f7f9f9c6caf0 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -72,7 +72,7 @@ die (const char *str, struct pt_regs *regs, long err)
bust_spinlocks(0);
die.lock_owner = -1;
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
spin_unlock_irq(&die.lock);
if (!regs)
diff --git a/arch/ia64/kvm/Kconfig b/arch/ia64/kvm/Kconfig
index e7947528aee6..2cd225f8c68d 100644
--- a/arch/ia64/kvm/Kconfig
+++ b/arch/ia64/kvm/Kconfig
@@ -20,7 +20,7 @@ if VIRTUALIZATION
config KVM
tristate "Kernel-based Virtual Machine (KVM) support"
depends on BROKEN
- depends on HAVE_KVM && MODULES && EXPERIMENTAL
+ depends on HAVE_KVM && MODULES
# for device assignment:
depends on PCI
depends on BROKEN
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index bd1c51555038..ad3126a58644 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -955,7 +955,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
kvm_mem.guest_phys_addr;
kvm_userspace_mem.memory_size = kvm_mem.memory_size;
r = kvm_vm_ioctl_set_memory_region(kvm,
- &kvm_userspace_mem, 0);
+ &kvm_userspace_mem, false);
if (r)
goto out;
break;
@@ -1580,7 +1580,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
struct kvm_memory_slot old,
struct kvm_userspace_memory_region *mem,
- int user_alloc)
+ bool user_alloc)
{
unsigned long i;
unsigned long pfn;
@@ -1611,7 +1611,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
void kvm_arch_commit_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
struct kvm_memory_slot old,
- int user_alloc)
+ bool user_alloc)
{
return;
}
@@ -1834,7 +1834,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
mutex_lock(&kvm->slots_lock);
r = -EINVAL;
- if (log->slot >= KVM_MEMORY_SLOTS)
+ if (log->slot >= KVM_USER_MEM_SLOTS)
goto out;
memslot = id_to_memslot(kvm->memslots, log->slot);
diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h
index c5f92a926a9a..c3e2935b6db4 100644
--- a/arch/ia64/kvm/lapic.h
+++ b/arch/ia64/kvm/lapic.h
@@ -27,4 +27,10 @@ int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq);
#define kvm_apic_present(x) (true)
#define kvm_lapic_enabled(x) (true)
+static inline bool kvm_apic_vid_enabled(void)
+{
+ /* IA64 has no apicv supporting, do nothing here */
+ return false;
+}
+
#endif
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index 1516d1dc11fd..80dab509dfb0 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -93,7 +93,7 @@ void show_mem(unsigned int filter)
printk(KERN_INFO "%d pages swap cached\n", total_cached);
printk(KERN_INFO "Total of %ld pages in page table cache\n",
quicklist_total_size());
- printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages());
+ printk(KERN_INFO "%ld free buffer pages\n", nr_free_buffer_pages());
}
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index c641333cd997..c2e955ee79a8 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -666,7 +666,7 @@ void show_mem(unsigned int filter)
printk(KERN_INFO "%d pages swap cached\n", total_cached);
printk(KERN_INFO "Total of %ld pages in page table cache\n",
quicklist_total_size());
- printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages());
+ printk(KERN_INFO "%ld free buffer pages\n", nr_free_buffer_pages());
}
/**
@@ -822,4 +822,8 @@ int __meminit vmemmap_populate(struct page *start_page,
{
return vmemmap_populate_basepages(start_page, size, node);
}
+
+void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+{
+}
#endif
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
index 5ca674b74737..76069c18ee42 100644
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -148,7 +148,7 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb,
unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags)
{
- struct vm_area_struct *vmm;
+ struct vm_unmapped_area_info info;
if (len > RGN_MAP_LIMIT)
return -ENOMEM;
@@ -165,16 +165,14 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, u
/* This code assumes that RGN_HPAGE != 0. */
if ((REGION_NUMBER(addr) != RGN_HPAGE) || (addr & (HPAGE_SIZE - 1)))
addr = HPAGE_REGION_BASE;
- else
- addr = ALIGN(addr, HPAGE_SIZE);
- for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
- /* At this point: (!vmm || addr < vmm->vm_end). */
- if (REGION_OFFSET(addr) + len > RGN_MAP_LIMIT)
- return -ENOMEM;
- if (!vmm || (addr + len) <= vmm->vm_start)
- return addr;
- addr = ALIGN(vmm->vm_end, HPAGE_SIZE);
- }
+
+ info.flags = 0;
+ info.length = len;
+ info.low_limit = addr;
+ info.high_limit = HPAGE_REGION_BASE + RGN_MAP_LIMIT;
+ info.align_mask = PAGE_MASK & (HPAGE_SIZE - 1);
+ info.align_offset = 0;
+ return vm_unmapped_area(&info);
}
static int __init hugetlb_setup_sz(char *str)
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index b755ea92aea7..20bc967c7209 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -688,6 +688,24 @@ int arch_add_memory(int nid, u64 start, u64 size)
return ret;
}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long nr_pages = size >> PAGE_SHIFT;
+ struct zone *zone;
+ int ret;
+
+ zone = page_zone(pfn_to_page(start_pfn));
+ ret = __remove_pages(zone, start_pfn, nr_pages);
+ if (ret)
+ pr_warn("%s: Problem encountered in __remove_pages() as"
+ " ret=%d\n", __func__, ret);
+
+ return ret;
+}
+#endif
#endif
/*
diff --git a/arch/ia64/xen/Kconfig b/arch/ia64/xen/Kconfig
index 515e0826803a..5d8a06b0ddf7 100644
--- a/arch/ia64/xen/Kconfig
+++ b/arch/ia64/xen/Kconfig
@@ -5,7 +5,7 @@
config XEN
bool "Xen hypervisor support"
default y
- depends on PARAVIRT && MCKINLEY && IA64_PAGE_SIZE_16KB && EXPERIMENTAL
+ depends on PARAVIRT && MCKINLEY && IA64_PAGE_SIZE_16KB
select XEN_XENCOMM
select NO_IDLE_HZ
# followings are required to save/restore.
diff --git a/arch/m32r/include/asm/signal.h b/arch/m32r/include/asm/signal.h
index a5ba4a217fb9..ed3ded6601e8 100644
--- a/arch/m32r/include/asm/signal.h
+++ b/arch/m32r/include/asm/signal.h
@@ -16,16 +16,7 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#define __ARCH_HAS_SA_RESTORER
#include <asm/sigcontext.h>
#undef __HAVE_ARCH_SIG_BITOPS
diff --git a/arch/m32r/include/asm/unistd.h b/arch/m32r/include/asm/unistd.h
index 79b063caec85..555629b05267 100644
--- a/arch/m32r/include/asm/unistd.h
+++ b/arch/m32r/include/asm/unistd.h
@@ -20,8 +20,6 @@
#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_OLD_GETRLIMIT /*will be unused*/
#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_CLONE
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
diff --git a/arch/m32r/include/uapi/asm/socket.h b/arch/m32r/include/uapi/asm/socket.h
index 5e7088a26726..519afa2755db 100644
--- a/arch/m32r/include/uapi/asm/socket.h
+++ b/arch/m32r/include/uapi/asm/socket.h
@@ -22,7 +22,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT 15
#define SO_PASSCRED 16
#define SO_PEERCRED 17
#define SO_RCVLOWAT 18
@@ -70,4 +70,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
+
#endif /* _ASM_M32R_SOCKET_H */
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
index 765d0f57c787..bde899e155d3 100644
--- a/arch/m32r/kernel/process.c
+++ b/arch/m32r/kernel/process.c
@@ -44,36 +44,10 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
return tsk->thread.lr;
}
-/*
- * Powermanagement idle function, if any..
- */
-static void (*pm_idle)(void) = NULL;
-
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
/*
- * We use this is we don't have any better
- * idle routine..
- */
-static void default_idle(void)
-{
- /* M32R_FIXME: Please use "cpu_sleep" mode. */
- cpu_relax();
-}
-
-/*
- * On SMP it's slightly faster (but much more power-consuming!)
- * to poll the ->work.need_resched flag instead of waiting for the
- * cross-CPU IPI to arrive. Use this option with caution.
- */
-static void poll_idle (void)
-{
- /* M32R_FIXME */
- cpu_relax();
-}
-
-/*
* The idle thread. There's no useful work to be
* done, so just try to conserve power and have a
* low exit latency (ie sit in a loop waiting for
@@ -84,14 +58,8 @@ void cpu_idle (void)
/* endless idle loop with no priority at all */
while (1) {
rcu_idle_enter();
- while (!need_resched()) {
- void (*idle)(void) = pm_idle;
-
- if (!idle)
- idle = default_idle;
-
- idle();
- }
+ while (!need_resched())
+ cpu_relax();
rcu_idle_exit();
schedule_preempt_disabled();
}
@@ -120,21 +88,6 @@ void machine_power_off(void)
/* M32R_FIXME */
}
-static int __init idle_setup (char *str)
-{
- if (!strncmp(str, "poll", 4)) {
- printk("using poll in idle threads.\n");
- pm_idle = poll_idle;
- } else if (!strncmp(str, "sleep", 4)) {
- printk("using sleep in idle threads.\n");
- pm_idle = default_idle;
- }
-
- return 1;
-}
-
-__setup("idle=", idle_setup);
-
void show_regs(struct pt_regs * regs)
{
printk("\n");
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index 6e3c26a1607c..d503568cb753 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -27,15 +27,6 @@
#define DEBUG_SIG 0
-asmlinkage int
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
- unsigned long r2, unsigned long r3, unsigned long r4,
- unsigned long r5, unsigned long r6, struct pt_regs *regs)
-{
- return do_sigaltstack(uss, uoss, regs->spu);
-}
-
-
/*
* Do a signal return; undo the signal stack.
*/
@@ -113,7 +104,7 @@ sys_rt_sigreturn(unsigned long r0, unsigned long r1,
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &result))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->spu) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return result;
@@ -213,10 +204,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->spu),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->spu);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c
index 84dd04048db9..1a15f81ea1bd 100644
--- a/arch/m32r/kernel/time.c
+++ b/arch/m32r/kernel/time.c
@@ -57,7 +57,7 @@ extern void smp_local_timer_interrupt(void);
static unsigned long latch;
-u32 arch_gettimeoffset(void)
+static u32 m32r_gettimeoffset(void)
{
unsigned long elapsed_time = 0; /* [us] */
@@ -165,6 +165,8 @@ void read_persistent_clock(struct timespec *ts)
void __init time_init(void)
{
+ arch_gettimeoffset = m32r_gettimeoffset;
+
#if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \
|| defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \
|| defined(CONFIG_CHIP_OPSP) || defined(CONFIG_CHIP_M32104)
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 6710084e072a..efb1ce1f14a3 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -18,6 +18,8 @@ config M68K
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_REL
select MODULES_USE_ELF_RELA
+ select OLD_SIGSUSPEND3
+ select OLD_SIGACTION
config RWSEM_GENERIC_SPINLOCK
bool
diff --git a/arch/m68k/Kconfig.devices b/arch/m68k/Kconfig.devices
index c4cdfe444c64..4bc945dfe467 100644
--- a/arch/m68k/Kconfig.devices
+++ b/arch/m68k/Kconfig.devices
@@ -41,7 +41,7 @@ config NFBLOCK
config NFCON
tristate "NatFeat console driver"
- depends on NATFEAT
+ depends on TTY && NATFEAT
help
Say Y to include support for the ARAnyM NatFeat console driver
which allows the console output to be redirected to the stderr
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index ee01b7a38e58..b819390e29cd 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -95,7 +95,7 @@ static void amiga_sched_init(irq_handler_t handler);
static void amiga_get_model(char *model);
static void amiga_get_hardware_list(struct seq_file *m);
/* amiga specific timer functions */
-static unsigned long amiga_gettimeoffset(void);
+static u32 amiga_gettimeoffset(void);
extern void amiga_mksound(unsigned int count, unsigned int ticks);
static void amiga_reset(void);
extern void amiga_init_sound(void);
@@ -377,7 +377,7 @@ void __init config_amiga(void)
mach_init_IRQ = amiga_init_IRQ;
mach_get_model = amiga_get_model;
mach_get_hardware_list = amiga_get_hardware_list;
- mach_gettimeoffset = amiga_gettimeoffset;
+ arch_gettimeoffset = amiga_gettimeoffset;
/*
* default MAX_DMA=0xffffffff on all machines. If we don't do so, the SCSI
@@ -482,10 +482,10 @@ static void __init amiga_sched_init(irq_handler_t timer_routine)
#define TICK_SIZE 10000
/* This is always executed with interrupts disabled. */
-static unsigned long amiga_gettimeoffset(void)
+static u32 amiga_gettimeoffset(void)
{
unsigned short hi, lo, hi2;
- unsigned long ticks, offset = 0;
+ u32 ticks, offset = 0;
/* read CIA B timer A current value */
hi = ciab.tahi;
@@ -507,7 +507,7 @@ static unsigned long amiga_gettimeoffset(void)
ticks = jiffy_ticks - ticks;
ticks = (10000 * ticks) / jiffy_ticks;
- return ticks + offset;
+ return (ticks + offset) * 1000;
}
static void amiga_reset(void) __noreturn;
diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
index f5565d6eeb8e..3ea56b90e718 100644
--- a/arch/m68k/apollo/config.c
+++ b/arch/m68k/apollo/config.c
@@ -26,7 +26,7 @@ u_long apollo_model;
extern void dn_sched_init(irq_handler_t handler);
extern void dn_init_IRQ(void);
-extern unsigned long dn_gettimeoffset(void);
+extern u32 dn_gettimeoffset(void);
extern int dn_dummy_hwclk(int, struct rtc_time *);
extern int dn_dummy_set_clock_mmss(unsigned long);
extern void dn_dummy_reset(void);
@@ -151,7 +151,7 @@ void __init config_apollo(void)
mach_sched_init=dn_sched_init; /* */
mach_init_IRQ=dn_init_IRQ;
- mach_gettimeoffset = dn_gettimeoffset;
+ arch_gettimeoffset = dn_gettimeoffset;
mach_max_dma_address = 0xffffffff;
mach_hwclk = dn_dummy_hwclk; /* */
mach_set_clock_mmss = dn_dummy_set_clock_mmss; /* */
@@ -203,10 +203,9 @@ void dn_sched_init(irq_handler_t timer_routine)
pr_err("Couldn't register timer interrupt\n");
}
-unsigned long dn_gettimeoffset(void) {
-
+u32 dn_gettimeoffset(void)
+{
return 0xdeadbeef;
-
}
int dn_dummy_hwclk(int op, struct rtc_time *t) {
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index d8eb32747ac5..037c11c99331 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -74,7 +74,7 @@ static void atari_heartbeat(int on);
/* atari specific timer functions (in time.c) */
extern void atari_sched_init(irq_handler_t);
-extern unsigned long atari_gettimeoffset (void);
+extern u32 atari_gettimeoffset(void);
extern int atari_mste_hwclk (int, struct rtc_time *);
extern int atari_tt_hwclk (int, struct rtc_time *);
extern int atari_mste_set_clock_mmss (unsigned long);
@@ -204,7 +204,7 @@ void __init config_atari(void)
mach_init_IRQ = atari_init_IRQ;
mach_get_model = atari_get_model;
mach_get_hardware_list = atari_get_hardware_list;
- mach_gettimeoffset = atari_gettimeoffset;
+ arch_gettimeoffset = atari_gettimeoffset;
mach_reset = atari_reset;
mach_max_dma_address = 0xffffff;
#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
index c0cc68a2c829..da8f981c36d6 100644
--- a/arch/m68k/atari/time.c
+++ b/arch/m68k/atari/time.c
@@ -42,9 +42,9 @@ atari_sched_init(irq_handler_t timer_routine)
#define TICK_SIZE 10000
/* This is always executed with interrupts disabled. */
-unsigned long atari_gettimeoffset (void)
+u32 atari_gettimeoffset(void)
{
- unsigned long ticks, offset = 0;
+ u32 ticks, offset = 0;
/* read MFP timer C current value */
ticks = st_mfp.tim_dt_c;
@@ -57,7 +57,7 @@ unsigned long atari_gettimeoffset (void)
ticks = INT_TICKS - ticks;
ticks = ticks * 10000L / INT_TICKS;
- return ticks + offset;
+ return (ticks + offset) * 1000;
}
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 0bf850a20ea2..8943aa4c18e6 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -38,7 +38,7 @@
static void bvme6000_get_model(char *model);
extern void bvme6000_sched_init(irq_handler_t handler);
-extern unsigned long bvme6000_gettimeoffset (void);
+extern u32 bvme6000_gettimeoffset(void);
extern int bvme6000_hwclk (int, struct rtc_time *);
extern int bvme6000_set_clock_mmss (unsigned long);
extern void bvme6000_reset (void);
@@ -110,7 +110,7 @@ void __init config_bvme6000(void)
mach_max_dma_address = 0xffffffff;
mach_sched_init = bvme6000_sched_init;
mach_init_IRQ = bvme6000_init_IRQ;
- mach_gettimeoffset = bvme6000_gettimeoffset;
+ arch_gettimeoffset = bvme6000_gettimeoffset;
mach_hwclk = bvme6000_hwclk;
mach_set_clock_mmss = bvme6000_set_clock_mmss;
mach_reset = bvme6000_reset;
@@ -216,13 +216,13 @@ void bvme6000_sched_init (irq_handler_t timer_routine)
* results...
*/
-unsigned long bvme6000_gettimeoffset (void)
+u32 bvme6000_gettimeoffset(void)
{
volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
unsigned char msr = rtc->msr & 0xc0;
unsigned char t1int, t1op;
- unsigned long v = 800000, ov;
+ u32 v = 800000, ov;
rtc->msr = 0; /* Ensure timer registers accessible */
@@ -246,7 +246,7 @@ unsigned long bvme6000_gettimeoffset (void)
v += 10000; /* Int pending, + 10ms */
rtc->msr = msr;
- return v;
+ return v * 1000;
}
/*
diff --git a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c
index bf16af1edacf..b7609f791522 100644
--- a/arch/m68k/hp300/config.c
+++ b/arch/m68k/hp300/config.c
@@ -251,7 +251,7 @@ void __init config_hp300(void)
mach_sched_init = hp300_sched_init;
mach_init_IRQ = hp300_init_IRQ;
mach_get_model = hp300_get_model;
- mach_gettimeoffset = hp300_gettimeoffset;
+ arch_gettimeoffset = hp300_gettimeoffset;
mach_hwclk = hp300_hwclk;
mach_get_ss = hp300_get_ss;
mach_reset = hp300_reset;
diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c
index 29a71be9fa5b..749543b425a4 100644
--- a/arch/m68k/hp300/time.c
+++ b/arch/m68k/hp300/time.c
@@ -46,7 +46,7 @@ static irqreturn_t hp300_tick(int irq, void *dev_id)
return vector(irq, NULL);
}
-unsigned long hp300_gettimeoffset(void)
+u32 hp300_gettimeoffset(void)
{
/* Read current timer 1 value */
unsigned char lsb, msb1, msb2;
@@ -59,7 +59,7 @@ unsigned long hp300_gettimeoffset(void)
/* A carry happened while we were reading. Read it again */
lsb = in_8(CLOCKBASE + 7);
ticks = INTVAL - ((msb2 << 8) | lsb);
- return (USECS_PER_JIFFY * ticks) / INTVAL;
+ return ((USECS_PER_JIFFY * ticks) / INTVAL) * 1000;
}
void __init hp300_sched_init(irq_handler_t vector)
diff --git a/arch/m68k/hp300/time.h b/arch/m68k/hp300/time.h
index 7b98242960de..f5583ec4033d 100644
--- a/arch/m68k/hp300/time.h
+++ b/arch/m68k/hp300/time.h
@@ -1,2 +1,2 @@
extern void hp300_sched_init(irq_handler_t vector);
-extern unsigned long hp300_gettimeoffset(void);
+extern u32 hp300_gettimeoffset(void);
diff --git a/arch/m68k/include/asm/dma-mapping.h b/arch/m68k/include/asm/dma-mapping.h
index 292805f0762e..05aa53594d49 100644
--- a/arch/m68k/include/asm/dma-mapping.h
+++ b/arch/m68k/include/asm/dma-mapping.h
@@ -5,7 +5,6 @@
struct scatterlist;
-#ifndef CONFIG_MMU_SUN3
static inline int dma_supported(struct device *dev, u64 mask)
{
return 1;
@@ -111,10 +110,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t handle)
return 0;
}
-#else
-#include <asm-generic/dma-mapping-broken.h>
-#endif
-
/* drivers/base/dma-mapping.c */
extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size);
diff --git a/arch/m68k/include/asm/machdep.h b/arch/m68k/include/asm/machdep.h
index 825c1c813196..953ca21da8ee 100644
--- a/arch/m68k/include/asm/machdep.h
+++ b/arch/m68k/include/asm/machdep.h
@@ -3,6 +3,7 @@
#include <linux/seq_file.h>
#include <linux/interrupt.h>
+#include <linux/time.h>
struct pt_regs;
struct mktime;
@@ -16,7 +17,6 @@ extern void (*mach_init_IRQ) (void);
extern void (*mach_get_model) (char *model);
extern void (*mach_get_hardware_list) (struct seq_file *m);
/* machine dependent timer functions */
-extern unsigned long (*mach_gettimeoffset)(void);
extern int (*mach_hwclk)(int, struct rtc_time*);
extern unsigned int (*mach_get_ss)(void);
extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h
index ae700f49e51d..b0768a657920 100644
--- a/arch/m68k/include/asm/processor.h
+++ b/arch/m68k/include/asm/processor.h
@@ -130,7 +130,6 @@ extern int handle_kernel_fault(struct pt_regs *regs);
#define start_thread(_regs, _pc, _usp) \
do { \
(_regs)->pc = (_pc); \
- ((struct switch_stack *)(_regs))[-1].a6 = 0; \
setframeformat(_regs); \
if (current->mm) \
(_regs)->d5 = current->mm->start_data; \
diff --git a/arch/m68k/include/asm/signal.h b/arch/m68k/include/asm/signal.h
index 9c8c46b06b0c..214320b50384 100644
--- a/arch/m68k/include/asm/signal.h
+++ b/arch/m68k/include/asm/signal.h
@@ -16,23 +16,8 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
-};
-
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#define __ARCH_HAS_SA_RESTORER
+
#include <asm/sigcontext.h>
#ifndef CONFIG_CPU_HAS_NO_BITFIELDS
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h
index f9337f614660..6cd92671ca5e 100644
--- a/arch/m68k/include/asm/unistd.h
+++ b/arch/m68k/include/asm/unistd.h
@@ -29,8 +29,6 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 068ad49210d6..655347d80780 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -20,7 +20,5 @@ obj-$(CONFIG_MMU_MOTOROLA) += ints.o vectors.o
obj-$(CONFIG_MMU_SUN3) += ints.o vectors.o
obj-$(CONFIG_PCI) += pcibios.o
-ifndef CONFIG_MMU_SUN3
-obj-y += dma.o
-endif
+obj-$(CONFIG_HAS_DMA) += dma.o
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c
index d872ce4807c9..80cfbe56ea32 100644
--- a/arch/m68k/kernel/setup_mm.c
+++ b/arch/m68k/kernel/setup_mm.c
@@ -84,7 +84,6 @@ void (*mach_init_IRQ) (void) __initdata = NULL;
void (*mach_get_model) (char *model);
void (*mach_get_hardware_list) (struct seq_file *m);
/* machine dependent timer functions */
-unsigned long (*mach_gettimeoffset) (void);
int (*mach_hwclk) (int, struct rtc_time*);
EXPORT_SYMBOL(mach_hwclk);
int (*mach_set_clock_mmss) (unsigned long);
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index 9a396cda3147..2a16df3d9312 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -225,56 +225,6 @@ static inline void push_cache(unsigned long vaddr)
#endif /* CONFIG_MMU */
/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction __user *act,
- struct old_sigaction __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
-asmlinkage int
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
- return do_sigaltstack(uss, uoss, rdusp());
-}
-
-
-/*
* Do a signal return; undo the signal stack.
*
* Keep the return code on the stack quadword aligned!
@@ -765,8 +715,9 @@ rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
err |= __get_user(temp, &uc->uc_formatvec);
err |= rt_restore_fpu_state(uc);
+ err |= restore_altstack(&uc->uc_stack);
- if (err || do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
+ if (err)
goto badframe;
if (mangle_kernel_stack(regs, temp, &uc->uc_extra))
@@ -1014,11 +965,7 @@ static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
- err |= __put_user((void __user *)current->sas_ss_sp,
- &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(rdusp()),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, rdusp());
err |= rt_setup_ucontext(&frame->uc, regs);
err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 5d0bcaad2e55..bea6bcf8f9b8 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -80,18 +80,8 @@ void read_persistent_clock(struct timespec *ts)
}
}
-void __init time_init(void)
-{
- mach_sched_init(timer_interrupt);
-}
-
#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
-u32 arch_gettimeoffset(void)
-{
- return mach_gettimeoffset() * 1000;
-}
-
static int __init rtc_init(void)
{
struct platform_device *pdev;
@@ -106,3 +96,8 @@ static int __init rtc_init(void)
module_init(rtc_init);
#endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */
+
+void __init time_init(void)
+{
+ mach_sched_init(timer_interrupt);
+}
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index cbc624af4494..f32ab22e7ed3 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -1176,7 +1176,7 @@ void die_if_kernel (char *str, struct pt_regs *fp, int nr)
console_verbose();
printk("%s: %08x\n",str,nr);
show_registers(fp);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
do_exit(SIGSEGV);
}
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index d9f62e0f46c0..afb95d5fb26b 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -52,7 +52,7 @@ struct mac_booter_data mac_bi_data;
static unsigned long mac_orig_videoaddr;
/* Mac specific timer functions */
-extern unsigned long mac_gettimeoffset(void);
+extern u32 mac_gettimeoffset(void);
extern int mac_hwclk(int, struct rtc_time *);
extern int mac_set_clock_mmss(unsigned long);
extern void iop_preinit(void);
@@ -177,7 +177,7 @@ void __init config_mac(void)
mach_sched_init = mac_sched_init;
mach_init_IRQ = mac_init_IRQ;
mach_get_model = mac_get_model;
- mach_gettimeoffset = mac_gettimeoffset;
+ arch_gettimeoffset = mac_gettimeoffset;
mach_hwclk = mac_hwclk;
mach_set_clock_mmss = mac_set_clock_mmss;
mach_reset = mac_reset;
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index 2d85662715fb..5d1458bb871b 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -327,7 +327,7 @@ void via_debug_dump(void)
* TBI: get time offset between scheduling timer ticks
*/
-unsigned long mac_gettimeoffset (void)
+u32 mac_gettimeoffset(void)
{
unsigned long ticks, offset = 0;
@@ -341,7 +341,7 @@ unsigned long mac_gettimeoffset (void)
ticks = MAC_CLOCK_TICK - ticks;
ticks = ticks * 10000L / MAC_CLOCK_TICK;
- return ticks + offset;
+ return (ticks + offset) * 1000;
}
/*
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index a41c09149e23..1c6262803b94 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -37,7 +37,7 @@
static void mvme147_get_model(char *model);
extern void mvme147_sched_init(irq_handler_t handler);
-extern unsigned long mvme147_gettimeoffset (void);
+extern u32 mvme147_gettimeoffset(void);
extern int mvme147_hwclk (int, struct rtc_time *);
extern int mvme147_set_clock_mmss (unsigned long);
extern void mvme147_reset (void);
@@ -88,7 +88,7 @@ void __init config_mvme147(void)
mach_max_dma_address = 0x01000000;
mach_sched_init = mvme147_sched_init;
mach_init_IRQ = mvme147_init_IRQ;
- mach_gettimeoffset = mvme147_gettimeoffset;
+ arch_gettimeoffset = mvme147_gettimeoffset;
mach_hwclk = mvme147_hwclk;
mach_set_clock_mmss = mvme147_set_clock_mmss;
mach_reset = mvme147_reset;
@@ -127,7 +127,7 @@ void mvme147_sched_init (irq_handler_t timer_routine)
/* This is always executed with interrupts disabled. */
/* XXX There are race hazards in this code XXX */
-unsigned long mvme147_gettimeoffset (void)
+u32 mvme147_gettimeoffset(void)
{
volatile unsigned short *cp = (volatile unsigned short *)0xfffe1012;
unsigned short n;
@@ -137,7 +137,7 @@ unsigned long mvme147_gettimeoffset (void)
n = *cp;
n -= PCC_TIMER_PRELOAD;
- return (unsigned long)n * 25 / 4;
+ return ((unsigned long)n * 25 / 4) * 1000;
}
static int bcd2int (unsigned char b)
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index b6d7d8a7a3dd..080a342458a1 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -43,7 +43,7 @@ static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
static void mvme16x_get_model(char *model);
extern void mvme16x_sched_init(irq_handler_t handler);
-extern unsigned long mvme16x_gettimeoffset (void);
+extern u32 mvme16x_gettimeoffset(void);
extern int mvme16x_hwclk (int, struct rtc_time *);
extern int mvme16x_set_clock_mmss (unsigned long);
extern void mvme16x_reset (void);
@@ -289,7 +289,7 @@ void __init config_mvme16x(void)
mach_max_dma_address = 0xffffffff;
mach_sched_init = mvme16x_sched_init;
mach_init_IRQ = mvme16x_init_IRQ;
- mach_gettimeoffset = mvme16x_gettimeoffset;
+ arch_gettimeoffset = mvme16x_gettimeoffset;
mach_hwclk = mvme16x_hwclk;
mach_set_clock_mmss = mvme16x_set_clock_mmss;
mach_reset = mvme16x_reset;
@@ -405,9 +405,9 @@ void mvme16x_sched_init (irq_handler_t timer_routine)
/* This is always executed with interrupts disabled. */
-unsigned long mvme16x_gettimeoffset (void)
+u32 mvme16x_gettimeoffset(void)
{
- return (*(volatile unsigned long *)0xfff42008);
+ return (*(volatile u32 *)0xfff42008) * 1000;
}
int bcd2int (unsigned char b)
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 1adb5b7b0d1a..658542b914fc 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -40,7 +40,7 @@ extern void q40_init_IRQ(void);
static void q40_get_model(char *model);
extern void q40_sched_init(irq_handler_t handler);
-static unsigned long q40_gettimeoffset(void);
+static u32 q40_gettimeoffset(void);
static int q40_hwclk(int, struct rtc_time *);
static unsigned int q40_get_ss(void);
static int q40_set_clock_mmss(unsigned long);
@@ -170,7 +170,7 @@ void __init config_q40(void)
mach_sched_init = q40_sched_init;
mach_init_IRQ = q40_init_IRQ;
- mach_gettimeoffset = q40_gettimeoffset;
+ arch_gettimeoffset = q40_gettimeoffset;
mach_hwclk = q40_hwclk;
mach_get_ss = q40_get_ss;
mach_get_rtc_pll = q40_get_rtc_pll;
@@ -204,9 +204,9 @@ int q40_parse_bootinfo(const struct bi_record *rec)
}
-static unsigned long q40_gettimeoffset(void)
+static u32 q40_gettimeoffset(void)
{
- return 5000 * (ql_ticks != 0);
+ return 5000 * (ql_ticks != 0) * 1000;
}
diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
index 2ca25bd01a96..f59ec58083f8 100644
--- a/arch/m68k/sun3/config.c
+++ b/arch/m68k/sun3/config.c
@@ -36,7 +36,7 @@
char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
-extern unsigned long sun3_gettimeoffset(void);
+extern u32 sun3_gettimeoffset(void);
static void sun3_sched_init(irq_handler_t handler);
extern void sun3_get_model (char* model);
extern int sun3_hwclk(int set, struct rtc_time *t);
@@ -141,7 +141,7 @@ void __init config_sun3(void)
mach_sched_init = sun3_sched_init;
mach_init_IRQ = sun3_init_IRQ;
mach_reset = sun3_reboot;
- mach_gettimeoffset = sun3_gettimeoffset;
+ arch_gettimeoffset = sun3_gettimeoffset;
mach_get_model = sun3_get_model;
mach_hwclk = sun3_hwclk;
mach_halt = sun3_halt;
diff --git a/arch/m68k/sun3/intersil.c b/arch/m68k/sun3/intersil.c
index 94fe8016f1f0..889829e11f1d 100644
--- a/arch/m68k/sun3/intersil.c
+++ b/arch/m68k/sun3/intersil.c
@@ -23,9 +23,9 @@
#define START_VAL (INTERSIL_RUN | INTERSIL_INT_ENABLE | INTERSIL_24H_MODE)
/* does this need to be implemented? */
-unsigned long sun3_gettimeoffset(void)
+u32 sun3_gettimeoffset(void)
{
- return 1;
+ return 1000;
}
diff --git a/arch/m68k/sun3x/config.c b/arch/m68k/sun3x/config.c
index dd306c84d36d..0532d64d191e 100644
--- a/arch/m68k/sun3x/config.c
+++ b/arch/m68k/sun3x/config.c
@@ -48,7 +48,7 @@ void __init config_sun3x(void)
mach_sched_init = sun3x_sched_init;
mach_init_IRQ = sun3_init_IRQ;
- mach_gettimeoffset = sun3x_gettimeoffset;
+ arch_gettimeoffset = sun3x_gettimeoffset;
mach_reset = sun3x_reboot;
mach_hwclk = sun3x_hwclk;
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
index 1d0a72480409..c8eb08add6b0 100644
--- a/arch/m68k/sun3x/time.c
+++ b/arch/m68k/sun3x/time.c
@@ -71,7 +71,7 @@ int sun3x_hwclk(int set, struct rtc_time *t)
return 0;
}
/* Not much we can do here */
-unsigned long sun3x_gettimeoffset (void)
+u32 sun3x_gettimeoffset(void)
{
return 0L;
}
diff --git a/arch/m68k/sun3x/time.h b/arch/m68k/sun3x/time.h
index 6909e1297534..a4f9126be7e2 100644
--- a/arch/m68k/sun3x/time.h
+++ b/arch/m68k/sun3x/time.h
@@ -2,7 +2,7 @@
#define SUN3X_TIME_H
extern int sun3x_hwclk(int set, struct rtc_time *t);
-unsigned long sun3x_gettimeoffset (void);
+u32 sun3x_gettimeoffset(void);
void sun3x_sched_init(irq_handler_t vector);
struct mostek_dt {
diff --git a/arch/microblaze/include/asm/unistd.h b/arch/microblaze/include/asm/unistd.h
index 10f8ac186855..b3778391d9cc 100644
--- a/arch/microblaze/include/asm/unistd.h
+++ b/arch/microblaze/include/asm/unistd.h
@@ -33,8 +33,6 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_CLONE
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_FORK
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S
index 70da83a49670..7e394fc2c439 100644
--- a/arch/microblaze/kernel/entry-nommu.S
+++ b/arch/microblaze/kernel/entry-nommu.S
@@ -124,6 +124,7 @@ ret_from_intr:
lwi r11, r1, PT_MODE
bneid r11, no_intr_resched
+3:
lwi r6, r31, TS_THREAD_INFO /* get thread info */
lwi r19, r6, TI_FLAGS /* get flags in thread info */
/* do an extra work if any bits are set */
@@ -132,11 +133,13 @@ ret_from_intr:
beqi r11, 1f
bralid r15, schedule
nop
+ bri 3b
1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
beqid r11, no_intr_resched
addk r5, r1, r0
bralid r15, do_notify_resume
addk r6, r0, r0
+ bri 3b
no_intr_resched:
/* Disable interrupts, we are now committed to the state restore */
@@ -280,6 +283,7 @@ ENTRY(_user_exception)
/* Figure out which function to use for this system call. */
/* Note Microblaze barrel shift is optional, so don't rely on it */
add r12, r12, r12 /* convert num -> ptr */
+ addik r30, r0, 1 /* restarts allowed */
add r12, r12, r12
lwi r12, r12, sys_call_table /* Get function pointer */
addik r15, r0, ret_to_user-8 /* set return address */
@@ -369,6 +373,7 @@ ENTRY(_debug_exception)
bralid r15, send_sig
add r7, r0, r0 /* 3rd param zero */
+ addik r30, r0, 1 /* restarts allowed ??? */
/* Restore r3/r4 to work around how ret_to_user works */
lwi r3, r1, PT_R3
lwi r4, r1, PT_R4
@@ -482,18 +487,26 @@ ENTRY(ret_from_kernel_thread)
addk r3, r0, r0
work_pending:
+ lwi r11, r1, PT_MODE
+ bneid r11, 2f
+3:
enable_irq
-
andi r11, r19, _TIF_NEED_RESCHED
beqi r11, 1f
bralid r15, schedule
nop
+ bri 4f
1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
beqi r11, no_work_pending
- addk r5, r1, r0
+ addk r5, r30, r0
bralid r15, do_notify_resume
addik r6, r0, 1
- bri no_work_pending
+ addk r30, r0, r0 /* no restarts from now on */
+4:
+ disable_irq
+ lwi r6, r31, TS_THREAD_INFO /* get thread info */
+ lwi r19, r6, TI_FLAGS /* get flags in thread info */
+ bri 3b
ENTRY(ret_to_user)
disable_irq
@@ -507,6 +520,7 @@ ENTRY(ret_to_user)
no_work_pending:
disable_irq
+2:
/* save r31 */
swi r31, r0, PER_CPU(CURRENT_SAVE)
/* save mode indicator */
@@ -559,6 +573,7 @@ no_work_pending:
nop
sys_rt_sigreturn_wrapper:
+ addk r30, r0, r0 /* no restarts for this one */
brid sys_rt_sigreturn
addk r5, r1, r0
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
index c217367dfc7b..0536bc021cc6 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -354,6 +354,7 @@ C_ENTRY(_user_exception):
/* Note Microblaze barrel shift is optional, so don't rely on it */
add r12, r12, r12; /* convert num -> ptr */
add r12, r12, r12;
+ addi r30, r0, 1 /* restarts allowed */
#ifdef DEBUG
/* Trac syscalls and stored them to syscall_debug_table */
@@ -401,26 +402,27 @@ C_ENTRY(ret_from_trap):
* trigger rescheduling. */
/* get thread info from current task */
lwi r11, CURRENT_TASK, TS_THREAD_INFO;
- lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_NEED_RESCHED;
+ lwi r19, r11, TI_FLAGS; /* get flags in thread info */
+ andi r11, r19, _TIF_NEED_RESCHED;
beqi r11, 5f;
bralid r15, schedule; /* Call scheduler */
nop; /* delay slot */
+ bri 1b
/* Maybe handle a signal */
-5: /* get thread info from current task*/
- lwi r11, CURRENT_TASK, TS_THREAD_INFO;
- lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
- beqi r11, 1f; /* Signals to handle, handle them */
+5:
+ andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+ beqi r11, 4f; /* Signals to handle, handle them */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
bralid r15, do_notify_resume; /* Handle any signals */
- addi r6, r0, 1; /* Arg 2: int in_syscall */
+ add r6, r30, r0; /* Arg 2: int in_syscall */
+ add r30, r0, r0 /* no more restarts */
+ bri 1b
/* Finally, return to user state. */
-1: set_bip; /* Ints masked for state restore */
+4: set_bip; /* Ints masked for state restore */
swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
VM_OFF;
tophys(r1,r1);
@@ -464,6 +466,7 @@ C_ENTRY(ret_from_kernel_thread):
add r3, r0, r0
C_ENTRY(sys_rt_sigreturn_wrapper):
+ addik r30, r0, 0 /* no restarts */
brid sys_rt_sigreturn /* Do real work */
addik r5, r1, 0; /* add user context as 1st arg */
@@ -571,20 +574,20 @@ C_ENTRY(ret_from_exc):
/* We're returning to user mode, so check for various conditions that
trigger rescheduling. */
+1:
lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
- lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_NEED_RESCHED;
+ lwi r19, r11, TI_FLAGS; /* get flags in thread info */
+ andi r11, r19, _TIF_NEED_RESCHED;
beqi r11, 5f;
/* Call the scheduler before returning from a syscall/trap. */
bralid r15, schedule; /* Call scheduler */
nop; /* delay slot */
+ bri 1b
/* Maybe handle a signal */
-5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
- lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
- beqi r11, 1f; /* Signals to handle, handle them */
+5: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+ beqi r11, 4f; /* Signals to handle, handle them */
/*
* Handle a signal return; Pending signals should be in r18.
@@ -600,9 +603,10 @@ C_ENTRY(ret_from_exc):
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
bralid r15, do_notify_resume; /* Handle any signals */
addi r6, r0, 0; /* Arg 2: int in_syscall */
+ bri 1b
/* Finally, return to user state. */
-1: set_bip; /* Ints masked for state restore */
+4: set_bip; /* Ints masked for state restore */
swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
VM_OFF;
tophys(r1,r1);
@@ -682,22 +686,23 @@ ret_from_irq:
lwi r11, r1, PT_MODE;
bnei r11, 2f;
+1:
lwi r11, CURRENT_TASK, TS_THREAD_INFO;
- lwi r11, r11, TI_FLAGS; /* MS: get flags from thread info */
- andi r11, r11, _TIF_NEED_RESCHED;
+ lwi r19, r11, TI_FLAGS; /* MS: get flags from thread info */
+ andi r11, r19, _TIF_NEED_RESCHED;
beqi r11, 5f
bralid r15, schedule;
nop; /* delay slot */
+ bri 1b
/* Maybe handle a signal */
-5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
- lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+5: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
beqid r11, no_intr_resched
/* Handle a signal return; Pending signals should be in r18. */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
bralid r15, do_notify_resume; /* Handle any signals */
addi r6, r0, 0; /* Arg 2: int in_syscall */
+ bri 1b
/* Finally, return to user state. */
no_intr_resched:
@@ -815,28 +820,29 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
lwi r11, r1, PT_MODE;
bnei r11, 2f;
/* MS: Return to user space - gdb */
+1:
/* Get current task ptr into r11 */
lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
- lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_NEED_RESCHED;
+ lwi r19, r11, TI_FLAGS; /* get flags in thread info */
+ andi r11, r19, _TIF_NEED_RESCHED;
beqi r11, 5f;
/* Call the scheduler before returning from a syscall/trap. */
bralid r15, schedule; /* Call scheduler */
nop; /* delay slot */
+ bri 1b
/* Maybe handle a signal */
-5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
- lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
- beqi r11, 1f; /* Signals to handle, handle them */
+5: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+ beqi r11, 4f; /* Signals to handle, handle them */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
bralid r15, do_notify_resume; /* Handle any signals */
addi r6, r0, 0; /* Arg 2: int in_syscall */
+ bri 1b
/* Finally, return to user state. */
-1: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
+4: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
VM_OFF;
tophys(r1,r1);
/* MS: Restore all regs */
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index a5b74f729e5b..6ff2dcff3410 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -41,7 +41,6 @@ void show_regs(struct pt_regs *regs)
regs->msr, regs->ear, regs->esr, regs->fsr);
}
-void (*pm_idle)(void);
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
@@ -98,8 +97,6 @@ void cpu_idle(void)
/* endless idle loop with no priority at all */
while (1) {
- void (*idle)(void) = pm_idle;
-
if (!idle)
idle = default_idle;
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
index ab1b9db661f3..b050219c42e6 100644
--- a/arch/microblaze/kernel/ptrace.c
+++ b/arch/microblaze/kernel/ptrace.c
@@ -164,29 +164,6 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
tracehook_report_syscall_exit(regs, step);
}
-#if 0
-static asmlinkage void syscall_trace(void)
-{
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
- if (!(current->ptrace & PT_PTRACED))
- 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;
- }
-}
-#endif
-
void ptrace_disable(struct task_struct *child)
{
/* nothing to do */
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index ac3d0a0f4814..9f7a8bde0686 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -41,13 +41,6 @@
#include <asm/cacheflush.h>
#include <asm/syscalls.h>
-asmlinkage long
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
- struct pt_regs *regs)
-{
- return do_sigaltstack(uss, uoss, regs->r1);
-}
-
/*
* Do a signal return; undo the signal stack.
*/
@@ -109,9 +102,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))
goto badframe;
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->r1) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return rval;
@@ -194,11 +185,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
- err |= __put_user((void __user *)current->sas_ss_sp,
- &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->r1),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->r1);
err |= setup_sigcontext(&frame->uc.uc_mcontext,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
@@ -356,15 +343,6 @@ static void do_signal(struct pt_regs *regs, int in_syscall)
asmlinkage void do_notify_resume(struct pt_regs *regs, int in_syscall)
{
- /*
- * We want the common case to go fast, which
- * is why we may in certain cases get here from
- * kernel mode. Just return without doing anything
- * if so.
- */
- if (kernel_mode(regs))
- return;
-
if (test_thread_flag(TIF_SIGPENDING))
do_signal(regs, in_syscall);
diff --git a/arch/microblaze/platform/Kconfig.platform b/arch/microblaze/platform/Kconfig.platform
index 669c7eec293e..b1747211b8b1 100644
--- a/arch/microblaze/platform/Kconfig.platform
+++ b/arch/microblaze/platform/Kconfig.platform
@@ -20,7 +20,7 @@ endchoice
config SELFMOD
bool "Use self modified code for intc/timer"
- depends on EXPERIMENTAL && NO_MMU
+ depends on NO_MMU
default n
help
This choice enables self-modified code for interrupt controller
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 2ac626ab9d43..198641589bb5 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -4,7 +4,6 @@ config MIPS
select HAVE_GENERIC_DMA_COHERENT
select HAVE_IDE
select HAVE_OPROFILE
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
select HAVE_ARCH_KGDB
@@ -41,6 +40,7 @@ config MIPS
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_REL if MODULES
select MODULES_USE_ELF_RELA if MODULES && 64BIT
+ select CLONE_BACKWARDS
menu "Machine selection"
@@ -170,7 +170,7 @@ config MACH_DECSTATION
select SYS_HAS_CPU_R3000
select SYS_HAS_CPU_R4X00
select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+ select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_128HZ
select SYS_SUPPORTS_256HZ
@@ -206,7 +206,7 @@ config MACH_JAZZ
select ISA
select SYS_HAS_CPU_R4X00
select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+ select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_100HZ
help
This a family of machines based on the MIPS R4030 chipset which was
@@ -396,7 +396,6 @@ config PNX8550_STB810
config PMC_MSP
bool "PMC-Sierra MSP chipsets"
- depends on EXPERIMENTAL
select CEVT_R4K
select CSRC_R4K
select DMA_NONCOHERENT
@@ -495,8 +494,7 @@ config SGI_IP27
here.
config SGI_IP28
- bool "SGI IP28 (Indigo2 R10k) (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "SGI IP28 (Indigo2 R10k)"
select FW_ARC
select FW_ARC64
select BOOT_ELF64
@@ -554,7 +552,6 @@ config SGI_IP32
config SIBYTE_CRHINE
bool "Sibyte BCM91120C-CRhine"
- depends on EXPERIMENTAL
select BOOT_ELF32
select DMA_COHERENT
select SIBYTE_BCM1120
@@ -565,7 +562,6 @@ config SIBYTE_CRHINE
config SIBYTE_CARMEL
bool "Sibyte BCM91120x-Carmel"
- depends on EXPERIMENTAL
select BOOT_ELF32
select DMA_COHERENT
select SIBYTE_BCM1120
@@ -576,7 +572,6 @@ config SIBYTE_CARMEL
config SIBYTE_CRHONE
bool "Sibyte BCM91125C-CRhone"
- depends on EXPERIMENTAL
select BOOT_ELF32
select DMA_COHERENT
select SIBYTE_BCM1125
@@ -588,7 +583,6 @@ config SIBYTE_CRHONE
config SIBYTE_RHONE
bool "Sibyte BCM91125E-Rhone"
- depends on EXPERIMENTAL
select BOOT_ELF32
select DMA_COHERENT
select SIBYTE_BCM1125H
@@ -613,7 +607,6 @@ config SIBYTE_SWARM
config SIBYTE_LITTLESUR
bool "Sibyte BCM91250C2-LittleSur"
- depends on EXPERIMENTAL
select BOOT_ELF32
select DMA_COHERENT
select HAVE_PATA_PLATFORM
@@ -627,7 +620,6 @@ config SIBYTE_LITTLESUR
config SIBYTE_SENTOSA
bool "Sibyte BCM91250E-Sentosa"
- depends on EXPERIMENTAL
select BOOT_ELF32
select DMA_COHERENT
select NR_CPUS_DEFAULT_2
@@ -676,7 +668,7 @@ config SNI_RM
select R5000_CPU_SCACHE
select SYS_HAS_EARLY_PRINTK
select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
+ select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_LITTLE_ENDIAN
@@ -780,7 +772,6 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
config NLM_XLR_BOARD
bool "Netlogic XLR/XLS based systems"
- depends on EXPERIMENTAL
select BOOT_ELF32
select NLM_COMMON
select SYS_HAS_CPU_XLR
@@ -809,7 +800,6 @@ config NLM_XLR_BOARD
config NLM_XLP_BOARD
bool "Netlogic XLP based systems"
- depends on EXPERIMENTAL
select BOOT_ELF32
select NLM_COMMON
select SYS_HAS_CPU_XLP
@@ -1375,7 +1365,6 @@ config CPU_R5500
config CPU_R6000
bool "R6000"
- depends on EXPERIMENTAL
depends on SYS_HAS_CPU_R6000
select CPU_SUPPORTS_32BIT_KERNEL
help
@@ -1393,7 +1382,6 @@ config CPU_NEVADA
config CPU_R8000
bool "R8000"
- depends on EXPERIMENTAL
depends on SYS_HAS_CPU_R8000
select CPU_HAS_PREFETCH
select CPU_SUPPORTS_64BIT_KERNEL
@@ -1768,7 +1756,7 @@ config PAGE_SIZE_4KB
config PAGE_SIZE_8KB
bool "8kB"
- depends on (EXPERIMENTAL && CPU_R8000) || CPU_CAVIUM_OCTEON
+ depends on CPU_R8000 || CPU_CAVIUM_OCTEON
help
Using 8kB page size will result in higher performance kernel at
the price of higher memory consumption. This option is available
@@ -1795,7 +1783,7 @@ config PAGE_SIZE_32KB
config PAGE_SIZE_64KB
bool "64kB"
- depends on EXPERIMENTAL && !CPU_R3000 && !CPU_TX39XX
+ depends on !CPU_R3000 && !CPU_TX39XX
help
Using 64kB page size will result in higher performance kernel at
the price of higher memory consumption. This option is available on
@@ -2161,7 +2149,6 @@ source "mm/Kconfig"
config SMP
bool "Multi-Processing support"
depends on SYS_SUPPORTS_SMP
- select IRQ_PER_CPU
select USE_GENERIC_SMP_HELPERS
help
This enables support for systems with more than one CPU. If you have
@@ -2312,8 +2299,7 @@ config HZ
source "kernel/Kconfig.preempt"
config KEXEC
- bool "Kexec system call (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "Kexec system call"
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/mips/bcm47xx/serial.c b/arch/mips/bcm47xx/serial.c
index 57981e4fe2bc..b8ef965705cf 100644
--- a/arch/mips/bcm47xx/serial.c
+++ b/arch/mips/bcm47xx/serial.c
@@ -62,7 +62,7 @@ static int __init uart8250_init_bcma(void)
p->mapbase = (unsigned int) bcma_port->regs;
p->membase = (void *) bcma_port->regs;
- p->irq = bcma_port->irq + 2;
+ p->irq = bcma_port->irq;
p->uartclk = bcma_port->baud_base;
p->regshift = bcma_port->reg_shift;
p->iotype = UPIO_MEM;
diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c
index 41dd00884975..02f244475207 100644
--- a/arch/mips/cavium-octeon/dma-octeon.c
+++ b/arch/mips/cavium-octeon/dma-octeon.c
@@ -317,7 +317,8 @@ void __init plat_swiotlb_setup(void)
octeon_swiotlb = alloc_bootmem_low_pages(swiotlbsize);
- swiotlb_init_with_tbl(octeon_swiotlb, swiotlb_nslabs, 1);
+ if (swiotlb_init_with_tbl(octeon_swiotlb, swiotlb_nslabs, 1) == -ENOMEM)
+ panic("Cannot allocate SWIOTLB buffer");
mips_dma_map_ops = &octeon_linear_dma_map_ops.dma_map_ops;
}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c
index 116dea17acf5..dfdfe8bdc9c5 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c
@@ -175,7 +175,7 @@ int cvmx_helper_dump_packet(cvmx_wqe_t *work)
* Packets will begin slowly dropping when there are less than
* this many packet buffers free in FPA 0.
* @drop_thresh:
- * All incomming packets will be dropped when there are less
+ * All incoming packets will be dropped when there are less
* than this many free packet buffers in FPA 0.
* Returns Zero on success. Negative on failure
*/
@@ -210,7 +210,7 @@ int cvmx_helper_setup_red_queue(int queue, int pass_thresh, int drop_thresh)
* Packets will begin slowly dropping when there are less than
* this many packet buffers free in FPA 0.
* @drop_thresh:
- * All incomming packets will be dropped when there are less
+ * All incoming packets will be dropped when there are less
* than this many free packet buffers in FPA 0.
* Returns Zero on success. Negative on failure
*/
diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h
index 3c5d1464b7bd..ebaae9649f8a 100644
--- a/arch/mips/include/asm/compat.h
+++ b/arch/mips/include/asm/compat.h
@@ -288,6 +288,14 @@ struct compat_shmid64_ds {
compat_ulong_t __unused2;
};
+/* MIPS has unusual order of fields in stack_t */
+typedef struct compat_sigaltstack {
+ compat_uptr_t ss_sp;
+ compat_size_t ss_size;
+ int ss_flags;
+} compat_stack_t;
+#define compat_sigaltstack compat_sigaltstack
+
static inline int is_compat_task(void)
{
return test_thread_flag(TIF_32BIT_ADDR);
diff --git a/arch/mips/include/asm/octeon/cvmx-helper-util.h b/arch/mips/include/asm/octeon/cvmx-helper-util.h
index 6a6e52fc22c1..01c8ddd84ff8 100644
--- a/arch/mips/include/asm/octeon/cvmx-helper-util.h
+++ b/arch/mips/include/asm/octeon/cvmx-helper-util.h
@@ -60,7 +60,7 @@ extern int cvmx_helper_dump_packet(cvmx_wqe_t *work);
* Packets will begin slowly dropping when there are less than
* this many packet buffers free in FPA 0.
* @drop_thresh:
- * All incomming packets will be dropped when there are less
+ * All incoming packets will be dropped when there are less
* than this many free packet buffers in FPA 0.
* Returns Zero on success. Negative on failure
*/
@@ -74,7 +74,7 @@ extern int cvmx_helper_setup_red_queue(int queue, int pass_thresh,
* Packets will begin slowly dropping when there are less than
* this many packet buffers free in FPA 0.
* @drop_thresh:
- * All incomming packets will be dropped when there are less
+ * All incoming packets will be dropped when there are less
* than this many free packet buffers in FPA 0.
* Returns Zero on success. Negative on failure
*/
diff --git a/arch/mips/include/asm/signal.h b/arch/mips/include/asm/signal.h
index cf4a08062d1d..197f6367c201 100644
--- a/arch/mips/include/asm/signal.h
+++ b/arch/mips/include/asm/signal.h
@@ -21,4 +21,6 @@
#include <asm/sigcontext.h>
#include <asm/siginfo.h>
+#define __ARCH_HAS_ODD_SIGACTION
+
#endif /* _ASM_SIGNAL_H */
diff --git a/arch/mips/include/asm/sim.h b/arch/mips/include/asm/sim.h
index 0cd719fabb51..91831800c480 100644
--- a/arch/mips/include/asm/sim.h
+++ b/arch/mips/include/asm/sim.h
@@ -20,10 +20,10 @@
#define save_static_function(symbol) \
__asm__( \
".text\n\t" \
- ".globl\t" #symbol "\n\t" \
+ ".globl\t__" #symbol "\n\t" \
".align\t2\n\t" \
- ".type\t" #symbol ", @function\n\t" \
- ".ent\t" #symbol ", 0\n" \
+ ".type\t__" #symbol ", @function\n\t" \
+ ".ent\t__" #symbol ", 0\n__" \
#symbol":\n\t" \
".frame\t$29, 0, $31\n\t" \
"sw\t$16,"__str(PT_R16)"($29)\t\t\t# save_static_function\n\t" \
@@ -35,9 +35,9 @@ __asm__( \
"sw\t$22,"__str(PT_R22)"($29)\n\t" \
"sw\t$23,"__str(PT_R23)"($29)\n\t" \
"sw\t$30,"__str(PT_R30)"($29)\n\t" \
- "j\t_" #symbol "\n\t" \
- ".end\t" #symbol "\n\t" \
- ".size\t" #symbol",. - " #symbol)
+ "j\t" #symbol "\n\t" \
+ ".end\t__" #symbol "\n\t" \
+ ".size\t__" #symbol",. - __" #symbol)
#define nabi_no_regargs
@@ -48,10 +48,10 @@ __asm__( \
#define save_static_function(symbol) \
__asm__( \
".text\n\t" \
- ".globl\t" #symbol "\n\t" \
+ ".globl\t__" #symbol "\n\t" \
".align\t2\n\t" \
- ".type\t" #symbol ", @function\n\t" \
- ".ent\t" #symbol ", 0\n" \
+ ".type\t__" #symbol ", @function\n\t" \
+ ".ent\t__" #symbol ", 0\n__" \
#symbol":\n\t" \
".frame\t$29, 0, $31\n\t" \
"sd\t$16,"__str(PT_R16)"($29)\t\t\t# save_static_function\n\t" \
@@ -63,9 +63,9 @@ __asm__( \
"sd\t$22,"__str(PT_R22)"($29)\n\t" \
"sd\t$23,"__str(PT_R23)"($29)\n\t" \
"sd\t$30,"__str(PT_R30)"($29)\n\t" \
- "j\t_" #symbol "\n\t" \
- ".end\t" #symbol "\n\t" \
- ".size\t" #symbol",. - " #symbol)
+ "j\t" #symbol "\n\t" \
+ ".end\t__" #symbol "\n\t" \
+ ".size\t__" #symbol",. - __" #symbol)
#define nabi_no_regargs \
unsigned long __dummy0, \
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h
index 9e47cc11aa26..64f661e32879 100644
--- a/arch/mips/include/asm/unistd.h
+++ b/arch/mips/include/asm/unistd.h
@@ -35,7 +35,6 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
# ifdef CONFIG_32BIT
# define __ARCH_WANT_STAT64
# define __ARCH_WANT_SYS_TIME
@@ -43,6 +42,8 @@
# ifdef CONFIG_MIPS32_O32
# define __ARCH_WANT_COMPAT_SYS_TIME
# endif
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_CLONE
/* whitelists for checksyscalls */
#define __IGNORE_select
diff --git a/arch/mips/include/uapi/asm/signal.h b/arch/mips/include/uapi/asm/signal.h
index 770732cb8d03..6783c887a678 100644
--- a/arch/mips/include/uapi/asm/signal.h
+++ b/arch/mips/include/uapi/asm/signal.h
@@ -96,15 +96,13 @@ typedef unsigned long old_sigset_t; /* at least 32 bits */
#include <asm-generic/signal-defs.h>
+#ifndef __KERNEL__
struct sigaction {
unsigned int sa_flags;
__sighandler_t sa_handler;
sigset_t sa_mask;
};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#endif
/* IRIX compatible stack_t */
typedef struct sigaltstack {
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index 17307ab90474..3e68bfbda6bc 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -28,9 +28,7 @@
#define SO_LINGER 0x0080 /* Block on close of a reliable
socket to transmit pending data. */
#define SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band. */
-#if 0
-To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
-#endif
+#define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
#define SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */
#define SO_STYLE SO_TYPE /* Synonym */
@@ -90,5 +88,6 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/mips/jazz/Kconfig b/arch/mips/jazz/Kconfig
index 1f372b0d2559..fb1e072da30b 100644
--- a/arch/mips/jazz/Kconfig
+++ b/arch/mips/jazz/Kconfig
@@ -1,6 +1,6 @@
config ACER_PICA_61
- bool "Support for Acer PICA 1 chipset (EXPERIMENTAL)"
- depends on MACH_JAZZ && EXPERIMENTAL
+ bool "Support for Acer PICA 1 chipset"
+ depends on MACH_JAZZ
select DMA_NONCOHERENT
select SYS_SUPPORTS_LITTLE_ENDIAN
help
@@ -13,7 +13,7 @@ config MIPS_MAGNUM_4000
bool "Support for MIPS Magnum 4000"
depends on MACH_JAZZ
select DMA_NONCOHERENT
- select SYS_SUPPORTS_BIG_ENDIAN if EXPERIMENTAL
+ select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_LITTLE_ENDIAN
help
This is a machine with a R4000 100 MHz CPU. To compile a Linux
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 7adab86c632c..253bd8ad7446 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -119,22 +119,6 @@ SYSCALL_DEFINE6(32_pwrite, unsigned int, fd, const char __user *, buf,
return sys_pwrite64(fd, buf, count, merge_64(a4, a5));
}
-SYSCALL_DEFINE2(32_sched_rr_get_interval, compat_pid_t, pid,
- struct compat_timespec __user *, interval)
-{
- struct timespec t;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
- set_fs(old_fs);
- if (put_user (t.tv_sec, &interval->tv_sec) ||
- __put_user(t.tv_nsec, &interval->tv_nsec))
- return -EFAULT;
- return ret;
-}
-
#ifdef CONFIG_SYSVIPC
SYSCALL_DEFINE6(32_ipc, u32, call, long, first, long, second, long, third,
@@ -295,27 +279,6 @@ asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_a2,
merge_64(len_a4, len_a5));
}
-save_static_function(sys32_clone);
-static int noinline __used
-_sys32_clone(nabi_no_regargs struct pt_regs regs)
-{
- unsigned long clone_flags;
- unsigned long newsp;
- int __user *parent_tidptr, *child_tidptr;
-
- clone_flags = regs.regs[4];
- newsp = regs.regs[5];
- if (!newsp)
- newsp = regs.regs[29];
- parent_tidptr = (int __user *) regs.regs[6];
-
- /* Use __dummy4 instead of getting it off the stack, so that
- syscall() works. */
- child_tidptr = (int __user *) __dummy4;
- return do_fork(clone_flags, newsp, 0,
- parent_tidptr, child_tidptr);
-}
-
asmlinkage long sys32_lookup_dcookie(u32 a0, u32 a1, char __user *buf,
size_t len)
{
@@ -328,10 +291,3 @@ SYSCALL_DEFINE6(32_fanotify_mark, int, fanotify_fd, unsigned int, flags,
return sys_fanotify_mark(fanotify_fd, flags, merge_64(a3, a4),
dfd, pathname);
}
-
-SYSCALL_DEFINE6(32_futex, u32 __user *, uaddr, int, op, u32, val,
- struct compat_timespec __user *, utime, u32 __user *, uaddr2,
- u32, val3)
-{
- return compat_sys_futex(uaddr, op, val, utime, uaddr2, val3);
-}
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index a11c6f9fdd5e..a33d2ef8f273 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -156,7 +156,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
*childregs = *regs;
childregs->regs[7] = 0; /* Clear error flag */
childregs->regs[2] = 0; /* Child gets zero as return value */
- childregs->regs[29] = usp;
+ if (usp)
+ childregs->regs[29] = usp;
ti->addr_limit = USER_DS;
p->thread.reg29 = (unsigned long) childregs;
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index d20a4bc9ed05..80ff9422215f 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -226,7 +226,7 @@ einval: li v0, -ENOSYS
.macro syscalltable
sys sys_syscall 8 /* 4000 */
sys sys_exit 1
- sys sys_fork 0
+ sys __sys_fork 0
sys sys_read 3
sys sys_write 3
sys sys_open 3 /* 4005 */
@@ -344,7 +344,7 @@ einval: li v0, -ENOSYS
sys sys_ipc 6
sys sys_fsync 1
sys sys_sigreturn 0
- sys sys_clone 0 /* 4120 */
+ sys __sys_clone 6 /* 4120 */
sys sys_setdomainname 2
sys sys_newuname 1
sys sys_ni_syscall 0 /* sys_modify_ldt */
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index b64f642da073..9444ad9ea575 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -170,8 +170,8 @@ sys_call_table:
PTR sys_socketpair
PTR sys_setsockopt
PTR sys_getsockopt
- PTR sys_clone /* 5055 */
- PTR sys_fork
+ PTR __sys_clone /* 5055 */
+ PTR __sys_fork
PTR sys_execve
PTR sys_exit
PTR sys_wait4
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index c29ac197f446..3b18a8e29215 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -117,8 +117,8 @@ EXPORT(sysn32_call_table)
PTR sys_mprotect /* 6010 */
PTR sys_munmap
PTR sys_brk
- PTR sys_32_rt_sigaction
- PTR sys_32_rt_sigprocmask
+ PTR compat_sys_rt_sigaction
+ PTR compat_sys_rt_sigprocmask
PTR compat_sys_ioctl /* 6015 */
PTR sys_pread64
PTR sys_pwrite64
@@ -159,8 +159,8 @@ EXPORT(sysn32_call_table)
PTR sys_socketpair
PTR compat_sys_setsockopt
PTR sys_getsockopt
- PTR sys_clone /* 6055 */
- PTR sys_fork
+ PTR __sys_clone /* 6055 */
+ PTR __sys_fork
PTR compat_sys_execve
PTR sys_exit
PTR compat_sys_wait4
@@ -229,11 +229,11 @@ EXPORT(sysn32_call_table)
PTR sys_getsid
PTR sys_capget
PTR sys_capset
- PTR sys_32_rt_sigpending /* 6125 */
+ PTR compat_sys_rt_sigpending /* 6125 */
PTR compat_sys_rt_sigtimedwait
- PTR sys_32_rt_sigqueueinfo
- PTR sysn32_rt_sigsuspend
- PTR sys32_sigaltstack
+ PTR compat_sys_rt_sigqueueinfo
+ PTR compat_sys_rt_sigsuspend
+ PTR compat_sys_sigaltstack
PTR compat_sys_utime /* 6130 */
PTR sys_mknod
PTR sys_32_personality
@@ -249,7 +249,7 @@ EXPORT(sysn32_call_table)
PTR sys_sched_getscheduler
PTR sys_sched_get_priority_max
PTR sys_sched_get_priority_min
- PTR sys_32_sched_rr_get_interval /* 6145 */
+ PTR compat_sys_sched_rr_get_interval /* 6145 */
PTR sys_mlock
PTR sys_munlock
PTR sys_mlockall
@@ -298,7 +298,7 @@ EXPORT(sysn32_call_table)
PTR sys_fremovexattr
PTR sys_tkill
PTR sys_ni_syscall
- PTR sys_32_futex
+ PTR compat_sys_futex
PTR compat_sys_sched_setaffinity /* 6195 */
PTR compat_sys_sched_getaffinity
PTR sys_cacheflush
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index cf3e75e46650..063cd0d6ddd2 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -194,7 +194,7 @@ einval: li v0, -ENOSYS
sys_call_table:
PTR sys32_syscall /* 4000 */
PTR sys_exit
- PTR sys_fork
+ PTR __sys_fork
PTR sys_read
PTR sys_write
PTR compat_sys_open /* 4005 */
@@ -312,7 +312,7 @@ sys_call_table:
PTR sys_32_ipc
PTR sys_fsync
PTR sys32_sigreturn
- PTR sys32_clone /* 4120 */
+ PTR __sys_clone /* 4120 */
PTR sys_setdomainname
PTR sys_newuname
PTR sys_ni_syscall /* sys_modify_ldt */
@@ -357,7 +357,7 @@ sys_call_table:
PTR sys_sched_yield
PTR sys_sched_get_priority_max
PTR sys_sched_get_priority_min
- PTR sys_32_sched_rr_get_interval /* 4165 */
+ PTR compat_sys_sched_rr_get_interval /* 4165 */
PTR compat_sys_nanosleep
PTR sys_mremap
PTR sys_accept
@@ -386,19 +386,19 @@ sys_call_table:
PTR sys_getresgid
PTR sys_prctl
PTR sys32_rt_sigreturn
- PTR sys_32_rt_sigaction
- PTR sys_32_rt_sigprocmask /* 4195 */
- PTR sys_32_rt_sigpending
+ PTR compat_sys_rt_sigaction
+ PTR compat_sys_rt_sigprocmask /* 4195 */
+ PTR compat_sys_rt_sigpending
PTR compat_sys_rt_sigtimedwait
- PTR sys_32_rt_sigqueueinfo
- PTR sys32_rt_sigsuspend
+ PTR compat_sys_rt_sigqueueinfo
+ PTR compat_sys_rt_sigsuspend
PTR sys_32_pread /* 4200 */
PTR sys_32_pwrite
PTR sys_chown
PTR sys_getcwd
PTR sys_capget
PTR sys_capset /* 4205 */
- PTR sys32_sigaltstack
+ PTR compat_sys_sigaltstack
PTR sys_32_sendfile
PTR sys_ni_syscall
PTR sys_ni_syscall
@@ -430,7 +430,7 @@ sys_call_table:
PTR sys_fremovexattr /* 4235 */
PTR sys_tkill
PTR sys_sendfile64
- PTR sys_32_futex
+ PTR compat_sys_futex
PTR compat_sys_sched_setaffinity
PTR compat_sys_sched_getaffinity /* 4240 */
PTR compat_sys_io_setup
@@ -470,7 +470,7 @@ sys_call_table:
PTR compat_sys_mq_notify /* 4275 */
PTR compat_sys_mq_getsetattr
PTR sys_ni_syscall /* sys_vserver */
- PTR sys_32_waitid
+ PTR compat_sys_waitid
PTR sys_ni_syscall /* available, was setaltroot */
PTR sys_add_key /* 4280 */
PTR sys_request_key
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index b6aa77035019..95b019d92f50 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -247,35 +247,12 @@ void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
*/
#ifdef CONFIG_TRAD_SIGNALS
-asmlinkage int sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
+SYSCALL_DEFINE1(sigsuspend, sigset_t __user *, uset)
{
- sigset_t newset;
- sigset_t __user *uset;
-
- uset = (sigset_t __user *) regs.regs[4];
- if (copy_from_user(&newset, uset, sizeof(sigset_t)))
- return -EFAULT;
- return sigsuspend(&newset);
+ return sys_rt_sigsuspend(uset, sizeof(sigset_t));
}
#endif
-asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
-{
- sigset_t newset;
- sigset_t __user *unewset;
- size_t sigsetsize;
-
- /* XXX Don't preclude handling different sized sigset_t's. */
- sigsetsize = regs.regs[5];
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- unewset = (sigset_t __user *) regs.regs[4];
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- return sigsuspend(&newset);
-}
-
#ifdef CONFIG_TRAD_SIGNALS
SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act,
struct sigaction __user *, oact)
@@ -317,15 +294,6 @@ SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act,
}
#endif
-asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs)
-{
- const stack_t __user *uss = (const stack_t __user *) regs.regs[4];
- stack_t __user *uoss = (stack_t __user *) regs.regs[5];
- unsigned long usp = regs.regs[29];
-
- return do_sigaltstack(uss, uoss, usp);
-}
-
#ifdef CONFIG_TRAD_SIGNALS
asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs)
{
@@ -382,9 +350,8 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
else if (sig)
force_sig(sig, current);
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- do_sigaltstack(&frame->rs_uc.uc_stack, NULL, regs.regs[29]);
+ if (restore_altstack(&frame->rs_uc.uc_stack))
+ goto badframe;
/*
* Don't let your children do this ...
@@ -461,12 +428,7 @@ static int setup_rt_frame(void *sig_return, struct k_sigaction *ka,
/* Create the ucontext. */
err |= __put_user(0, &frame->rs_uc.uc_flags);
err |= __put_user(NULL, &frame->rs_uc.uc_link);
- err |= __put_user((void __user *)current->sas_ss_sp,
- &frame->rs_uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->regs[29]),
- &frame->rs_uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size,
- &frame->rs_uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index da1b56a39ac7..ad7c2be0c33d 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -55,23 +55,10 @@ extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user
typedef unsigned int __sighandler32_t;
typedef void (*vfptr_t)(void);
-struct sigaction32 {
- unsigned int sa_flags;
- __sighandler32_t sa_handler;
- compat_sigset_t sa_mask;
-};
-
-/* IRIX compatible stack_t */
-typedef struct sigaltstack32 {
- s32 ss_sp;
- compat_size_t ss_size;
- int ss_flags;
-} stack32_t;
-
struct ucontext32 {
u32 uc_flags;
s32 uc_link;
- stack32_t uc_stack;
+ compat_stack_t uc_stack;
struct sigcontext32 uc_mcontext;
compat_sigset_t uc_sigmask; /* mask last for extensibility */
};
@@ -280,36 +267,13 @@ static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
* Atomically swap in the new signal mask, and wait for a signal.
*/
-asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
+asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset)
{
- compat_sigset_t __user *uset;
- sigset_t newset;
-
- uset = (compat_sigset_t __user *) regs.regs[4];
- if (get_sigset(&newset, uset))
- return -EFAULT;
- return sigsuspend(&newset);
-}
-
-asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
-{
- compat_sigset_t __user *uset;
- sigset_t newset;
- size_t sigsetsize;
-
- /* XXX Don't preclude handling different sized sigset_t's. */
- sigsetsize = regs.regs[5];
- if (sigsetsize != sizeof(compat_sigset_t))
- return -EINVAL;
-
- uset = (compat_sigset_t __user *) regs.regs[4];
- if (get_sigset(&newset, uset))
- return -EFAULT;
- return sigsuspend(&newset);
+ return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t));
}
-SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
- struct sigaction32 __user *, oact)
+SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, act,
+ struct compat_sigaction __user *, oact)
{
struct k_sigaction new_ka, old_ka;
int ret;
@@ -350,45 +314,6 @@ SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
return ret;
}
-asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
-{
- const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4];
- stack32_t __user *uoss = (stack32_t __user *) regs.regs[5];
- unsigned long usp = regs.regs[29];
- stack_t kss, koss;
- int ret, err = 0;
- mm_segment_t old_fs = get_fs();
- s32 sp;
-
- if (uss) {
- if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
- return -EFAULT;
- err |= __get_user(sp, &uss->ss_sp);
- kss.ss_sp = (void __user *) (long) sp;
- err |= __get_user(kss.ss_size, &uss->ss_size);
- err |= __get_user(kss.ss_flags, &uss->ss_flags);
- if (err)
- return -EFAULT;
- }
-
- set_fs(KERNEL_DS);
- ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL,
- uoss ? (stack_t __user *)&koss : NULL, usp);
- set_fs(old_fs);
-
- if (!ret && uoss) {
- if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
- return -EFAULT;
- sp = (int) (unsigned long) koss.ss_sp;
- err |= __put_user(sp, &uoss->ss_sp);
- err |= __put_user(koss.ss_size, &uoss->ss_size);
- err |= __put_user(koss.ss_flags, &uoss->ss_flags);
- if (err)
- return -EFAULT;
- }
- return ret;
-}
-
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
int err;
@@ -490,10 +415,7 @@ badframe:
asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
{
struct rt_sigframe32 __user *frame;
- mm_segment_t old_fs;
sigset_t set;
- stack_t st;
- s32 sp;
int sig;
frame = (struct rt_sigframe32 __user *) regs.regs[29];
@@ -510,22 +432,9 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
else if (sig)
force_sig(sig, current);
- /* The ucontext contains a stack32_t, so we must convert! */
- if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
- goto badframe;
- st.ss_sp = (void __user *)(long) sp;
- if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
- goto badframe;
- if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
+ if (compat_restore_altstack(&frame->rs_uc.uc_stack))
goto badframe;
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
- set_fs(old_fs);
-
/*
* Don't let your children do this ...
*/
@@ -590,7 +499,6 @@ static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
{
struct rt_sigframe32 __user *frame;
int err = 0;
- s32 sp;
frame = get_sigframe(ka, regs, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
@@ -602,13 +510,7 @@ static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
/* Create the ucontext. */
err |= __put_user(0, &frame->rs_uc.uc_flags);
err |= __put_user(0, &frame->rs_uc.uc_link);
- sp = (int) (long) current->sas_ss_sp;
- err |= __put_user(sp,
- &frame->rs_uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->regs[29]),
- &frame->rs_uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size,
- &frame->rs_uc.uc_stack.ss_size);
+ err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
@@ -656,131 +558,6 @@ struct mips_abi mips_abi_32 = {
.restart = __NR_O32_restart_syscall
};
-SYSCALL_DEFINE4(32_rt_sigaction, int, sig,
- const struct sigaction32 __user *, act,
- struct sigaction32 __user *, oact, unsigned int, sigsetsize)
-{
- struct k_sigaction new_sa, old_sa;
- int ret = -EINVAL;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- goto out;
-
- if (act) {
- s32 handler;
- int err = 0;
-
- if (!access_ok(VERIFY_READ, act, sizeof(*act)))
- return -EFAULT;
- err |= __get_user(handler, &act->sa_handler);
- new_sa.sa.sa_handler = (void __user *)(s64)handler;
- err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags);
- err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask);
- if (err)
- return -EFAULT;
- }
-
- ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
-
- if (!ret && oact) {
- int err = 0;
-
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
- return -EFAULT;
-
- err |= __put_user((u32)(u64)old_sa.sa.sa_handler,
- &oact->sa_handler);
- err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags);
- err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask);
- if (err)
- return -EFAULT;
- }
-out:
- return ret;
-}
-
-SYSCALL_DEFINE4(32_rt_sigprocmask, int, how, compat_sigset_t __user *, set,
- compat_sigset_t __user *, oset, unsigned int, sigsetsize)
-{
- sigset_t old_set, new_set;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- if (set && get_sigset(&new_set, set))
- return -EFAULT;
-
- set_fs(KERNEL_DS);
- ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL,
- oset ? (sigset_t __user *)&old_set : NULL,
- sigsetsize);
- set_fs(old_fs);
-
- if (!ret && oset && put_sigset(&old_set, oset))
- return -EFAULT;
-
- return ret;
-}
-
-SYSCALL_DEFINE2(32_rt_sigpending, compat_sigset_t __user *, uset,
- unsigned int, sigsetsize)
-{
- int ret;
- sigset_t set;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize);
- set_fs(old_fs);
-
- if (!ret && put_sigset(&set, uset))
- return -EFAULT;
-
- return ret;
-}
-
-SYSCALL_DEFINE3(32_rt_sigqueueinfo, int, pid, int, sig,
- compat_siginfo_t __user *, uinfo)
-{
- siginfo_t info;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- if (copy_from_user(&info, uinfo, 3*sizeof(int)) ||
- copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
- return -EFAULT;
- set_fs(KERNEL_DS);
- ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
- set_fs(old_fs);
- return ret;
-}
-
-SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid,
- compat_siginfo_t __user *, uinfo, int, options,
- struct compat_rusage __user *, uru)
-{
- siginfo_t info;
- struct rusage ru;
- long ret;
- mm_segment_t old_fs = get_fs();
-
- info.si_signo = 0;
- set_fs(KERNEL_DS);
- ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
- uru ? (struct rusage __user *) &ru : NULL);
- set_fs(old_fs);
-
- if (ret < 0 || info.si_signo == 0)
- return ret;
-
- if (uru && (ret = put_compat_rusage(&ru, uru)))
- return ret;
-
- BUG_ON(info.si_code & __SI_MASK);
- info.si_code |= __SI_CHLD;
- return copy_siginfo_to_user32(uinfo, &info);
-}
-
static int signal32_init(void)
{
if (cpu_has_fpu) {
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index 3574c145511b..5f4ef2ae6199 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -50,18 +50,10 @@
extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *);
extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
-
-/* IRIX compatible stack_t */
-typedef struct sigaltstack32 {
- s32 ss_sp;
- compat_size_t ss_size;
- int ss_flags;
-} stack32_t;
-
struct ucontextn32 {
u32 uc_flags;
s32 uc_link;
- stack32_t uc_stack;
+ compat_stack_t uc_stack;
struct sigcontext uc_mcontext;
compat_sigset_t uc_sigmask; /* mask last for extensibility */
};
@@ -73,34 +65,10 @@ struct rt_sigframe_n32 {
struct ucontextn32 rs_uc;
};
-extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
-
-asmlinkage int sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
-{
- compat_sigset_t __user *unewset;
- compat_sigset_t uset;
- size_t sigsetsize;
- sigset_t newset;
-
- /* XXX Don't preclude handling different sized sigset_t's. */
- sigsetsize = regs.regs[5];
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- unewset = (compat_sigset_t __user *) regs.regs[4];
- if (copy_from_user(&uset, unewset, sizeof(uset)))
- return -EFAULT;
- sigset_from_compat(&newset, &uset);
- return sigsuspend(&newset);
-}
-
asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
{
struct rt_sigframe_n32 __user *frame;
- mm_segment_t old_fs;
sigset_t set;
- stack_t st;
- s32 sp;
int sig;
frame = (struct rt_sigframe_n32 __user *) regs.regs[29];
@@ -117,23 +85,9 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
else if (sig)
force_sig(sig, current);
- /* The ucontext contains a stack32_t, so we must convert! */
- if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
- goto badframe;
- st.ss_sp = (void __user *)(long) sp;
- if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
- goto badframe;
- if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
+ if (compat_restore_altstack(&frame->rs_uc.uc_stack))
goto badframe;
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
- set_fs(old_fs);
-
-
/*
* Don't let your children do this ...
*/
@@ -153,7 +107,6 @@ static int setup_rt_frame_n32(void *sig_return, struct k_sigaction *ka,
{
struct rt_sigframe_n32 __user *frame;
int err = 0;
- s32 sp;
frame = get_sigframe(ka, regs, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
@@ -165,13 +118,7 @@ static int setup_rt_frame_n32(void *sig_return, struct k_sigaction *ka,
/* Create the ucontext. */
err |= __put_user(0, &frame->rs_uc.uc_flags);
err |= __put_user(0, &frame->rs_uc.uc_link);
- sp = (int) (long) current->sas_ss_sp;
- err |= __put_user(sp,
- &frame->rs_uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->regs[29]),
- &frame->rs_uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size,
- &frame->rs_uc.uc_stack.ss_size);
+ err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 201cb76b4df9..b32466a1a1d2 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -46,20 +46,14 @@
* argument. Historically that used to be expensive in Linux. These days
* the performance advantage is negligible.
*/
-asmlinkage int sysm_pipe(nabi_no_regargs volatile struct pt_regs regs)
+asmlinkage int sysm_pipe(void)
{
int fd[2];
- int error, res;
-
- error = do_pipe_flags(fd, 0);
- if (error) {
- res = error;
- goto out;
- }
- regs.regs[3] = fd[1];
- res = fd[0];
-out:
- return res;
+ int error = do_pipe_flags(fd, 0);
+ if (error)
+ return error;
+ current_pt_regs()->regs[3] = fd[1];
+ return fd[0];
}
SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
@@ -89,43 +83,7 @@ SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
}
save_static_function(sys_fork);
-static int __used noinline
-_sys_fork(nabi_no_regargs struct pt_regs regs)
-{
- return do_fork(SIGCHLD, regs.regs[29], 0, NULL, NULL);
-}
-
save_static_function(sys_clone);
-static int __used noinline
-_sys_clone(nabi_no_regargs struct pt_regs regs)
-{
- unsigned long clone_flags;
- unsigned long newsp;
- int __user *parent_tidptr, *child_tidptr;
-
- clone_flags = regs.regs[4];
- newsp = regs.regs[5];
- if (!newsp)
- newsp = regs.regs[29];
- parent_tidptr = (int __user *) regs.regs[6];
-#ifdef CONFIG_32BIT
- /* We need to fetch the fifth argument off the stack. */
- child_tidptr = NULL;
- if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) {
- int __user *__user *usp = (int __user *__user *) regs.regs[29];
- if (regs.regs[2] == __NR_syscall) {
- if (get_user (child_tidptr, &usp[5]))
- return -EFAULT;
- }
- else if (get_user (child_tidptr, &usp[4]))
- return -EFAULT;
- }
-#else
- child_tidptr = (int __user *) regs.regs[8];
-#endif
- return do_fork(clone_flags, newsp, 0,
- parent_tidptr, child_tidptr);
-}
SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
{
@@ -138,10 +96,10 @@ SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
return 0;
}
-static inline int mips_atomic_set(struct pt_regs *regs,
- unsigned long addr, unsigned long new)
+static inline int mips_atomic_set(unsigned long addr, unsigned long new)
{
unsigned long old, tmp;
+ struct pt_regs *regs;
unsigned int err;
if (unlikely(addr & 3))
@@ -222,6 +180,7 @@ static inline int mips_atomic_set(struct pt_regs *regs,
if (unlikely(err))
return err;
+ regs = current_pt_regs();
regs->regs[2] = old;
regs->regs[7] = 0; /* No error */
@@ -235,22 +194,14 @@ static inline int mips_atomic_set(struct pt_regs *regs,
: "r" (regs));
/* unreached. Honestly. */
- while (1);
+ unreachable();
}
-save_static_function(sys_sysmips);
-static int __used noinline
-_sys_sysmips(nabi_no_regargs struct pt_regs regs)
+SYSCALL_DEFINE3(sysmips, long, cmd, long, arg1, long, arg2)
{
- long cmd, arg1, arg2;
-
- cmd = regs.regs[4];
- arg1 = regs.regs[5];
- arg2 = regs.regs[6];
-
switch (cmd) {
case MIPS_ATOMIC_SET:
- return mips_atomic_set(&regs, arg1, arg2);
+ return mips_atomic_set(arg1, arg2);
case MIPS_FIXADE:
if (arg1 & ~3)
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index cf7ac5483f53..9007966d56d4 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -396,7 +396,7 @@ void __noreturn die(const char *str, struct pt_regs *regs)
printk("%s[#%d]:\n", str, ++die_counter);
show_registers(regs);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
raw_spin_unlock_irq(&die_lock);
oops_exit();
diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
index e44a1866653f..08f7ebd9c774 100644
--- a/arch/mips/lantiq/xway/dma.c
+++ b/arch/mips/lantiq/xway/dma.c
@@ -21,6 +21,7 @@
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/clk.h>
+#include <linux/err.h>
#include <lantiq_soc.h>
#include <xway_dma.h>
@@ -223,8 +224,8 @@ ltq_dma_init(struct platform_device *pdev)
panic("Failed to get dma resource");
/* remap dma register range */
- ltq_dma_membase = devm_request_and_ioremap(&pdev->dev, res);
- if (!ltq_dma_membase)
+ ltq_dma_membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ltq_dma_membase))
panic("Failed to remap dma resource");
/* power up and reset the dma engine */
diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c
index e30b1ed1b936..9861c8669fab 100644
--- a/arch/mips/lantiq/xway/gptu.c
+++ b/arch/mips/lantiq/xway/gptu.c
@@ -150,11 +150,9 @@ static int gptu_probe(struct platform_device *pdev)
}
/* remap gptu register range */
- gptu_membase = devm_request_and_ioremap(&pdev->dev, res);
- if (!gptu_membase) {
- dev_err(&pdev->dev, "Failed to remap resource\n");
- return -ENOMEM;
- }
+ gptu_membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gptu_membase))
+ return PTR_ERR(gptu_membase);
/* enable our clock */
clk = clk_get(&pdev->dev, NULL);
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
index 95681789b51e..910fb4c20b9e 100644
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -214,13 +214,13 @@ static int ltq_pci_probe(struct platform_device *pdev)
return -EINVAL;
}
- ltq_pci_membase = devm_request_and_ioremap(&pdev->dev, res_bridge);
- ltq_pci_mapped_cfg = devm_request_and_ioremap(&pdev->dev, res_cfg);
+ ltq_pci_membase = devm_ioremap_resource(&pdev->dev, res_bridge);
+ if (IS_ERR(ltq_pci_membase))
+ return PTR_ERR(ltq_pci_membase);
- if (!ltq_pci_membase || !ltq_pci_mapped_cfg) {
- dev_err(&pdev->dev, "failed to remap resources\n");
- return -ENOMEM;
- }
+ ltq_pci_mapped_cfg = devm_ioremap_resource(&pdev->dev, res_cfg);
+ if (IS_ERR(ltq_pci_mapped_cfg))
+ return PTR_ERR(ltq_pci_mapped_cfg);
ltq_pci_startup(pdev);
diff --git a/arch/mips/sgi-ip27/Kconfig b/arch/mips/sgi-ip27/Kconfig
index 4b2ea282b9c7..4d8705a65e4a 100644
--- a/arch/mips/sgi-ip27/Kconfig
+++ b/arch/mips/sgi-ip27/Kconfig
@@ -13,7 +13,6 @@ config SGI_SN_M_MODE
config SGI_SN_N_MODE
bool "IP27 N-Mode"
- depends on EXPERIMENTAL
help
The nodes of Origin, Onyx, Fuel and Tezro systems can be configured
in either N-Modes which allows for more nodes or M-Mode which allows
diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c
index 9cb9d43a3a0e..e05ad4da44d9 100644
--- a/arch/mips/sni/a20r.c
+++ b/arch/mips/sni/a20r.c
@@ -118,7 +118,7 @@ static struct resource sc26xx_rsrc[] = {
}
};
-#include <linux/platform_data/sccnxp.h>
+#include <linux/platform_data/serial-sccnxp.h>
static struct sccnxp_pdata sccnxp_data = {
.reg_shift = 2,
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index e70001cfa05b..ad0caea0bfea 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -10,6 +10,8 @@ config MN10300
select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
select GENERIC_CLOCKEVENTS
select MODULES_USE_ELF_RELA
+ select OLD_SIGSUSPEND3
+ select OLD_SIGACTION
config AM33_2
def_bool n
diff --git a/arch/mn10300/include/asm/signal.h b/arch/mn10300/include/asm/signal.h
index d280e9780793..214ff5e9fe60 100644
--- a/arch/mn10300/include/asm/signal.h
+++ b/arch/mn10300/include/asm/signal.h
@@ -26,23 +26,8 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
-};
-
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#define __ARCH_HAS_SA_RESTORER
+
#include <asm/sigcontext.h>
#endif /* _ASM_SIGNAL_H */
diff --git a/arch/mn10300/include/asm/unistd.h b/arch/mn10300/include/asm/unistd.h
index e6d2ed4ba68f..7f9d9adfa51e 100644
--- a/arch/mn10300/include/asm/unistd.h
+++ b/arch/mn10300/include/asm/unistd.h
@@ -41,8 +41,6 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
diff --git a/arch/mn10300/include/uapi/asm/socket.h b/arch/mn10300/include/uapi/asm/socket.h
index af5366bbfe62..5c7c7c988544 100644
--- a/arch/mn10300/include/uapi/asm/socket.h
+++ b/arch/mn10300/include/uapi/asm/socket.h
@@ -22,7 +22,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT 15
#define SO_PASSCRED 16
#define SO_PEERCRED 17
#define SO_RCVLOWAT 18
@@ -70,4 +70,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c
index 81d5cb9b6569..bf6e949a2f87 100644
--- a/arch/mn10300/kernel/mn10300-serial.c
+++ b/arch/mn10300/kernel/mn10300-serial.c
@@ -524,7 +524,7 @@ static int mask_test_and_clear(volatile u8 *ptr, u8 mask)
static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port)
{
struct uart_icount *icount = &port->uart.icount;
- struct tty_struct *tty = port->uart.state->port.tty;
+ struct tty_port *tport = &port->uart.state->port;
unsigned ix;
int count;
u8 st, ch, push, status, overrun;
@@ -534,10 +534,10 @@ static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port)
push = 0;
count = CIRC_CNT(port->rx_inp, port->rx_outp, MNSC_BUFFER_SIZE);
- count = tty_buffer_request_room(tty, count);
+ count = tty_buffer_request_room(tport, count);
if (count == 0) {
- if (!tty->low_latency)
- tty_flip_buffer_push(tty);
+ if (!tport->low_latency)
+ tty_flip_buffer_push(tport);
return;
}
@@ -545,8 +545,8 @@ try_again:
/* pull chars out of the hat */
ix = ACCESS_ONCE(port->rx_outp);
if (CIRC_CNT(port->rx_inp, ix, MNSC_BUFFER_SIZE) == 0) {
- if (push && !tty->low_latency)
- tty_flip_buffer_push(tty);
+ if (push && !tport->low_latency)
+ tty_flip_buffer_push(tport);
return;
}
@@ -666,19 +666,19 @@ insert:
else
flag = TTY_NORMAL;
- tty_insert_flip_char(tty, ch, flag);
+ tty_insert_flip_char(tport, ch, flag);
}
/* overrun is special, since it's reported immediately, and doesn't
* affect the current character
*/
if (overrun)
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_insert_flip_char(tport, 0, TTY_OVERRUN);
count--;
if (count <= 0) {
- if (!tty->low_latency)
- tty_flip_buffer_push(tty);
+ if (!tport->low_latency)
+ tty_flip_buffer_push(tport);
return;
}
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index eb09f5a552ff..84f4e97e3074 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -37,12 +37,6 @@
#include "internal.h"
/*
- * power management idle function, if any..
- */
-void (*pm_idle)(void);
-EXPORT_SYMBOL(pm_idle);
-
-/*
* return saved PC of a blocked thread.
*/
unsigned long thread_saved_pc(struct task_struct *tsk)
@@ -113,7 +107,6 @@ void cpu_idle(void)
void (*idle)(void);
smp_rmb();
- idle = pm_idle;
if (!idle) {
#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)
idle = poll_idle;
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c
index f570b3085ef9..9dfac5cd16e6 100644
--- a/arch/mn10300/kernel/signal.c
+++ b/arch/mn10300/kernel/signal.c
@@ -32,59 +32,6 @@
#define DEBUG_SIG 0
/*
- * atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-/*
- * set signal action syscall
- */
-asmlinkage long sys_sigaction(int sig,
- const struct old_sigaction __user *act,
- struct old_sigaction __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
-/*
- * set alternate signal stack syscall
- */
-asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t *uoss)
-{
- return do_sigaltstack(uss, uoss, current_frame()->sp);
-}
-
-/*
* do a signal return; undo the signal stack.
*/
static int restore_sigcontext(struct pt_regs *regs,
@@ -193,8 +140,7 @@ asmlinkage long sys_rt_sigreturn(void)
if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, current_frame()->sp) ==
- -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return d0;
@@ -359,9 +305,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* create the ucontext. */
if (__put_user(0, &frame->uc.uc_flags) ||
__put_user(0, &frame->uc.uc_link) ||
- __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) ||
- __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags) ||
- __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size) ||
+ __save_altstack(&frame->uc.uc_stack, regs->sp) ||
setup_sigcontext(&frame->uc.uc_mcontext,
&frame->fpuctx, regs, set->sig[0]) ||
__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)))
diff --git a/arch/mn10300/unit-asb2305/pci-irq.c b/arch/mn10300/unit-asb2305/pci-irq.c
index 91212ea71e69..77439da04671 100644
--- a/arch/mn10300/unit-asb2305/pci-irq.c
+++ b/arch/mn10300/unit-asb2305/pci-irq.c
@@ -29,7 +29,7 @@ void __init pcibios_fixup_irqs(void)
struct pci_dev *dev = NULL;
u8 line, pin;
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin) {
dev->irq = XIRQ1;
diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S
index 5e5b30601bbf..54afd0a129fe 100644
--- a/arch/openrisc/kernel/entry.S
+++ b/arch/openrisc/kernel/entry.S
@@ -1083,10 +1083,6 @@ ENTRY(__sys_fork)
l.j _fork_save_extra_regs_and_call
l.addi r3,r1,0
-ENTRY(sys_sigaltstack)
- l.j _sys_sigaltstack
- l.addi r5,r1,0
-
ENTRY(sys_rt_sigreturn)
l.j _sys_rt_sigreturn
l.addi r3,r1,0
diff --git a/arch/openrisc/kernel/idle.c b/arch/openrisc/kernel/idle.c
index 7d618feb1b72..5e8a3b6d6bc6 100644
--- a/arch/openrisc/kernel/idle.c
+++ b/arch/openrisc/kernel/idle.c
@@ -39,11 +39,6 @@
void (*powersave) (void) = NULL;
-static inline void pm_idle(void)
-{
- barrier();
-}
-
void cpu_idle(void)
{
set_thread_flag(TIF_POLLING_NRFLAG);
diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c
index ddedc8a77861..ae167f7e081a 100644
--- a/arch/openrisc/kernel/signal.c
+++ b/arch/openrisc/kernel/signal.c
@@ -33,12 +33,6 @@
#define DEBUG_SIG 0
-asmlinkage long
-_sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs)
-{
- return do_sigaltstack(uss, uoss, regs->sp);
-}
-
struct rt_sigframe {
struct siginfo *pinfo;
void *puc;
@@ -103,9 +97,7 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return regs->gpr[11];
@@ -205,10 +197,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
- err |= __put_user((void *)current->sas_ss_sp,
- &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index b77feffbadea..7f9b3c53f74a 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -9,20 +9,19 @@ config PARISC
select RTC_DRV_GENERIC
select INIT_ALL_POSSIBLE
select BUG
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select GENERIC_ATOMIC64 if !64BIT
select HAVE_GENERIC_HARDIRQS
select BROKEN_RODATA
select GENERIC_IRQ_PROBE
select GENERIC_PCI_IOMAP
- select IRQ_PER_CPU
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_SMP_IDLE_THREAD
select GENERIC_STRNCPY_FROM_USER
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
select CLONE_BACKWARDS
+ select TTY # Needed for pdc_cons.c
help
The PA-RISC microprocessor is designed by Hewlett-Packard and used
@@ -161,6 +160,23 @@ config PREFETCH
def_bool y
depends on PA8X00 || PA7200
+config MLONGCALLS
+ bool "Enable the -mlong-calls compiler option for big kernels"
+ def_bool y if (!MODULES)
+ depends on PA8X00
+ help
+ If you configure the kernel to include many drivers built-in instead
+ as modules, the kernel executable may become too big, so that the
+ linker will not be able to resolve some long branches and fails to link
+ your vmlinux kernel. In that case enabling this option will help you
+ to overcome this limit by using the -mlong-calls compiler option.
+
+ Usually you want to say N here, unless you e.g. want to build
+ a kernel which includes all necessary drivers built-in and which can
+ be used for TFTP booting without the need to have an initrd ramdisk.
+
+ Enabling this option will probably slow down your kernel.
+
config 64BIT
bool "64-bit kernel"
depends on PA8X00
@@ -194,12 +210,12 @@ config PARISC_PAGE_SIZE_4KB
If you don't know what to do, choose 4KB.
config PARISC_PAGE_SIZE_16KB
- bool "16KB (EXPERIMENTAL)"
- depends on PA8X00 && EXPERIMENTAL
+ bool "16KB"
+ depends on PA8X00
config PARISC_PAGE_SIZE_64KB
- bool "64KB (EXPERIMENTAL)"
- depends on PA8X00 && EXPERIMENTAL
+ bool "64KB"
+ depends on PA8X00
endchoice
@@ -255,6 +271,10 @@ config COMPAT
def_bool y
depends on 64BIT
+config SYSVIPC_COMPAT
+ def_bool y
+ depends on COMPAT && SYSVIPC
+
config HPUX
bool "Support for HP-UX binaries"
depends on !64BIT
diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
index 5707f1a62341..ed9a14ccd066 100644
--- a/arch/parisc/Makefile
+++ b/arch/parisc/Makefile
@@ -32,11 +32,6 @@ ifdef CONFIG_64BIT
UTS_MACHINE := parisc64
CHECKFLAGS += -D__LP64__=1 -m64
WIDTH := 64
-
-# FIXME: if no default set, should really try to locate dynamically
-ifeq ($(CROSS_COMPILE),)
-CROSS_COMPILE := hppa64-linux-gnu-
-endif
else # 32-bit
WIDTH :=
endif
@@ -44,6 +39,10 @@ endif
# attempt to help out folks who are cross-compiling
ifeq ($(NATIVE),1)
CROSS_COMPILE := hppa$(WIDTH)-linux-
+else
+ ifeq ($(CROSS_COMPILE),)
+ CROSS_COMPILE := hppa$(WIDTH)-linux-gnu-
+ endif
endif
OBJCOPY_FLAGS =-O binary -R .note -R .comment -S
@@ -65,6 +64,10 @@ ifndef CONFIG_FUNCTION_TRACER
cflags-y += -ffunction-sections
endif
+# Use long jumps instead of long branches (needed if your linker fails to
+# link a too big vmlinux executable)
+cflags-$(CONFIG_MLONGCALLS) += -mlong-calls
+
# select which processor to optimise for
cflags-$(CONFIG_PA7100) += -march=1.1 -mschedule=7100
cflags-$(CONFIG_PA7200) += -march=1.1 -mschedule=7200
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index a0760b87fd4e..838b479a42c4 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -43,8 +43,7 @@ int hpux_execve(struct pt_regs *regs)
error = do_execve(filename->name,
(const char __user *const __user *) regs->gr[25],
- (const char __user *const __user *) regs->gr[24],
- regs);
+ (const char __user *const __user *) regs->gr[24]);
putname(filename);
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index 9f21ab0c02e3..79f694f3ad9b 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -115,7 +115,9 @@ flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vma
{
if (PageAnon(page)) {
flush_tlb_page(vma, vmaddr);
+ preempt_disable();
flush_dcache_page_asm(page_to_phys(page), vmaddr);
+ preempt_enable();
}
}
diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h
index db7a662691a8..94710cfc1ce8 100644
--- a/arch/parisc/include/asm/compat.h
+++ b/arch/parisc/include/asm/compat.h
@@ -28,6 +28,7 @@ typedef u16 compat_nlink_t;
typedef u16 compat_ipc_pid_t;
typedef s32 compat_daddr_t;
typedef u32 compat_caddr_t;
+typedef s32 compat_key_t;
typedef s32 compat_timer_t;
typedef s32 compat_int_t;
@@ -188,6 +189,66 @@ typedef struct compat_siginfo {
#define COMPAT_OFF_T_MAX 0x7fffffff
#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL
+struct compat_ipc64_perm {
+ compat_key_t key;
+ __compat_uid_t uid;
+ __compat_gid_t gid;
+ __compat_uid_t cuid;
+ __compat_gid_t cgid;
+ unsigned short int __pad1;
+ compat_mode_t mode;
+ unsigned short int __pad2;
+ unsigned short int seq;
+ unsigned int __pad3;
+ unsigned long __unused1; /* yes they really are 64bit pads */
+ unsigned long __unused2;
+};
+
+struct compat_semid64_ds {
+ struct compat_ipc64_perm sem_perm;
+ compat_time_t sem_otime;
+ unsigned int __unused1;
+ compat_time_t sem_ctime;
+ unsigned int __unused2;
+ compat_ulong_t sem_nsems;
+ compat_ulong_t __unused3;
+ compat_ulong_t __unused4;
+};
+
+struct compat_msqid64_ds {
+ struct compat_ipc64_perm msg_perm;
+ unsigned int __unused1;
+ compat_time_t msg_stime;
+ unsigned int __unused2;
+ compat_time_t msg_rtime;
+ unsigned int __unused3;
+ compat_time_t msg_ctime;
+ compat_ulong_t msg_cbytes;
+ compat_ulong_t msg_qnum;
+ compat_ulong_t msg_qbytes;
+ compat_pid_t msg_lspid;
+ compat_pid_t msg_lrpid;
+ compat_ulong_t __unused4;
+ compat_ulong_t __unused5;
+};
+
+struct compat_shmid64_ds {
+ struct compat_ipc64_perm shm_perm;
+ unsigned int __unused1;
+ compat_time_t shm_atime;
+ unsigned int __unused2;
+ compat_time_t shm_dtime;
+ unsigned int __unused3;
+ compat_time_t shm_ctime;
+ unsigned int __unused4;
+ compat_size_t shm_segsz;
+ compat_pid_t shm_cpid;
+ compat_pid_t shm_lpid;
+ compat_ulong_t shm_nattch;
+ compat_ulong_t __unused5;
+ compat_ulong_t __unused6;
+};
+
/*
* A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them
diff --git a/arch/parisc/include/asm/compat_rt_sigframe.h b/arch/parisc/include/asm/compat_rt_sigframe.h
deleted file mode 100644
index b3f95a7f18b4..000000000000
--- a/arch/parisc/include/asm/compat_rt_sigframe.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <linux/compat.h>
-#include <linux/compat_siginfo.h>
-#include <asm/compat_ucontext.h>
-
-#ifndef _ASM_PARISC_COMPAT_RT_SIGFRAME_H
-#define _ASM_PARISC_COMPAT_RT_SIGFRAME_H
-
-/* In a deft move of uber-hackery, we decide to carry the top half of all
- * 64-bit registers in a non-portable, non-ABI, hidden structure.
- * Userspace can read the hidden structure if it *wants* but is never
- * guaranteed to be in the same place. Infact the uc_sigmask from the
- * ucontext_t structure may push the hidden register file downards
- */
-struct compat_regfile {
- /* Upper half of all the 64-bit registers that were truncated
- on a copy to a 32-bit userspace */
- compat_int_t rf_gr[32];
- compat_int_t rf_iasq[2];
- compat_int_t rf_iaoq[2];
- compat_int_t rf_sar;
-};
-
-#define COMPAT_SIGRETURN_TRAMP 4
-#define COMPAT_SIGRESTARTBLOCK_TRAMP 5
-#define COMPAT_TRAMP_SIZE (COMPAT_SIGRETURN_TRAMP + COMPAT_SIGRESTARTBLOCK_TRAMP)
-
-struct compat_rt_sigframe {
- /* XXX: Must match trampoline size in arch/parisc/kernel/signal.c
- Secondary to that it must protect the ERESTART_RESTARTBLOCK
- trampoline we left on the stack (we were bad and didn't
- change sp so we could run really fast.) */
- compat_uint_t tramp[COMPAT_TRAMP_SIZE];
- compat_siginfo_t info;
- struct compat_ucontext uc;
- /* Hidden location of truncated registers, *must* be last. */
- struct compat_regfile regs;
-};
-
-/*
- * The 32-bit ABI wants at least 48 bytes for a function call frame:
- * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of
- * which Linux/parisc uses is sp-20 for the saved return pointer...)
- * Then, the stack pointer must be rounded to a cache line (64 bytes).
- */
-#define SIGFRAME32 64
-#define FUNCTIONCALLFRAME32 48
-#define PARISC_RT_SIGFRAME_SIZE32 \
- (((sizeof(struct compat_rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32)
-
-#endif
diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h
index 19f6cb1a4a1c..ad2b50397894 100644
--- a/arch/parisc/include/asm/elf.h
+++ b/arch/parisc/include/asm/elf.h
@@ -247,7 +247,7 @@ typedef unsigned long elf_greg_t;
#define ELF_PLATFORM ("PARISC\0")
#define SET_PERSONALITY(ex) \
- current->personality = PER_LINUX; \
+ set_personality((current->personality & ~PER_MASK) | PER_LINUX); \
current->thread.map_base = DEFAULT_MAP_BASE; \
current->thread.task_size = DEFAULT_TASK_SIZE \
diff --git a/arch/parisc/include/asm/floppy.h b/arch/parisc/include/asm/floppy.h
index 4ca69f558fae..f84ff12574b7 100644
--- a/arch/parisc/include/asm/floppy.h
+++ b/arch/parisc/include/asm/floppy.h
@@ -157,10 +157,10 @@ static int fd_request_irq(void)
{
if(can_use_virtual_dma)
return request_irq(FLOPPY_IRQ, floppy_hardint,
- IRQF_DISABLED, "floppy", NULL);
+ 0, "floppy", NULL);
else
return request_irq(FLOPPY_IRQ, floppy_interrupt,
- IRQF_DISABLED, "floppy", NULL);
+ 0, "floppy", NULL);
}
static unsigned long dma_mem_alloc(unsigned long size)
diff --git a/arch/parisc/include/asm/mmzone.h b/arch/parisc/include/asm/mmzone.h
index e67eb9c3d1bf..0e625ab9aaec 100644
--- a/arch/parisc/include/asm/mmzone.h
+++ b/arch/parisc/include/asm/mmzone.h
@@ -1,9 +1,10 @@
#ifndef _PARISC_MMZONE_H
#define _PARISC_MMZONE_H
+#define MAX_PHYSMEM_RANGES 8 /* Fix the size for now (current known max is 3) */
+
#ifdef CONFIG_DISCONTIGMEM
-#define MAX_PHYSMEM_RANGES 8 /* Fix the size for now (current known max is 3) */
extern int npmem_ranges;
struct node_map_data {
@@ -44,7 +45,7 @@ static inline int pfn_to_nid(unsigned long pfn)
return 0;
i = pfn >> PFNNID_SHIFT;
- BUG_ON(i >= sizeof(pfnnid_map) / sizeof(pfnnid_map[0]));
+ BUG_ON(i >= ARRAY_SIZE(pfnnid_map));
r = pfnnid_map[i];
BUG_ON(r == 0xff);
@@ -60,7 +61,5 @@ static inline int pfn_valid(int pfn)
return 0;
}
-#else /* !CONFIG_DISCONTIGMEM */
-#define MAX_PHYSMEM_RANGES 1
#endif
#endif /* _PARISC_MMZONE_H */
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index 4e0e7dbf0f3f..b7adb2ac049c 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -21,15 +21,27 @@
#include <asm/types.h>
#include <asm/cache.h>
-#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
-#define copy_page(to,from) copy_user_page_asm((void *)(to), (void *)(from))
+#define clear_page(page) clear_page_asm((void *)(page))
+#define copy_page(to, from) copy_page_asm((void *)(to), (void *)(from))
struct page;
-void copy_user_page_asm(void *to, void *from);
+void clear_page_asm(void *page);
+void copy_page_asm(void *to, void *from);
+void clear_user_page(void *vto, unsigned long vaddr, struct page *pg);
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
struct page *pg);
-void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
+
+/* #define CONFIG_PARISC_TMPALIAS */
+
+#ifdef CONFIG_PARISC_TMPALIAS
+void clear_user_highpage(struct page *page, unsigned long vaddr);
+#define clear_user_highpage clear_user_highpage
+struct vm_area_struct;
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma);
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
+#endif
/*
* These are used to make use of C type-checking..
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index ee99f2339356..7df49fad29f9 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -12,11 +12,10 @@
#include <linux/bitops.h>
#include <linux/spinlock.h>
+#include <linux/mm_types.h>
#include <asm/processor.h>
#include <asm/cache.h>
-struct vm_area_struct;
-
/*
* kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
* memory. For the return value to be meaningful, ADDR must be >=
@@ -40,7 +39,14 @@ struct vm_area_struct;
do{ \
*(pteptr) = (pteval); \
} while(0)
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
+extern void purge_tlb_entries(struct mm_struct *, unsigned long);
+
+#define set_pte_at(mm, addr, ptep, pteval) \
+ do { \
+ set_pte(ptep, pteval); \
+ purge_tlb_entries(mm, addr); \
+ } while (0)
#endif /* !__ASSEMBLY__ */
@@ -466,6 +472,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
old = pte_val(*ptep);
new = pte_val(pte_wrprotect(__pte (old)));
} while (cmpxchg((unsigned long *) ptep, old, new) != old);
+ purge_tlb_entries(mm, addr);
#else
pte_t old_pte = *ptep;
set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
diff --git a/arch/parisc/include/asm/signal.h b/arch/parisc/include/asm/signal.h
index 0fdb3c835952..81a545773971 100644
--- a/arch/parisc/include/asm/signal.h
+++ b/arch/parisc/include/asm/signal.h
@@ -3,16 +3,12 @@
#include <uapi/asm/signal.h>
-
#define _NSIG 64
/* bits-per-word, where word apparently means 'long' not 'int' */
#define _NSIG_BPW BITS_PER_LONG
#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
# ifndef __ASSEMBLY__
-#ifdef CONFIG_64BIT
-#else
-#endif
/* Most things should be clean enough to redefine this at will, if care
is taken to make libc match. */
@@ -24,15 +20,13 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
+#ifndef __KERNEL__
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
sigset_t sa_mask; /* mask last for extensibility */
};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#endif
#include <asm/sigcontext.h>
diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h
index 3043194547cd..ae9a46cbfd92 100644
--- a/arch/parisc/include/asm/unistd.h
+++ b/arch/parisc/include/asm/unistd.h
@@ -149,6 +149,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
#define __ARCH_WANT_SYS_SIGNAL
#define __ARCH_WANT_SYS_TIME
#define __ARCH_WANT_COMPAT_SYS_TIME
+#define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL
#define __ARCH_WANT_SYS_UTIME
#define __ARCH_WANT_SYS_WAITPID
#define __ARCH_WANT_SYS_SOCKETCALL
@@ -160,12 +161,10 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
+#define __ARCH_WANT_COMPAT_SYS_SENDFILE
#endif /* __ASSEMBLY__ */
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index d9ff4731253b..526e4b9aece0 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -13,7 +13,7 @@
#define SO_BROADCAST 0x0020
#define SO_LINGER 0x0080
#define SO_OOBINLINE 0x0100
-/* To add :#define SO_REUSEPORT 0x0200 */
+#define SO_REUSEPORT 0x0200
#define SO_SNDBUF 0x1001
#define SO_RCVBUF 0x1002
#define SO_SNDBUFFORCE 0x100a
@@ -69,6 +69,7 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 0x4024
+#define SO_LOCK_FILTER 0x4025
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
diff --git a/arch/parisc/include/uapi/asm/unistd.h b/arch/parisc/include/uapi/asm/unistd.h
index e178f30f2ccc..2c8b9bde18eb 100644
--- a/arch/parisc/include/uapi/asm/unistd.h
+++ b/arch/parisc/include/uapi/asm/unistd.h
@@ -822,8 +822,12 @@
#define __NR_syncfs (__NR_Linux + 327)
#define __NR_setns (__NR_Linux + 328)
#define __NR_sendmmsg (__NR_Linux + 329)
+#define __NR_process_vm_readv (__NR_Linux + 330)
+#define __NR_process_vm_writev (__NR_Linux + 331)
+#define __NR_kcmp (__NR_Linux + 332)
+#define __NR_finit_module (__NR_Linux + 333)
-#define __NR_Linux_syscalls (__NR_sendmmsg + 1)
+#define __NR_Linux_syscalls (__NR_finit_module + 1)
#define __IGNORE_select /* newselect */
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 48e16dc20102..4b12890642eb 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -267,9 +267,11 @@ static inline void
__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr,
unsigned long physaddr)
{
+ preempt_disable();
flush_dcache_page_asm(physaddr, vmaddr);
if (vma->vm_flags & VM_EXEC)
flush_icache_page_asm(physaddr, vmaddr);
+ preempt_enable();
}
void flush_dcache_page(struct page *page)
@@ -329,17 +331,6 @@ EXPORT_SYMBOL(flush_kernel_dcache_page_asm);
EXPORT_SYMBOL(flush_data_cache_local);
EXPORT_SYMBOL(flush_kernel_icache_range_asm);
-void clear_user_page_asm(void *page, unsigned long vaddr)
-{
- unsigned long flags;
- /* This function is implemented in assembly in pacache.S */
- extern void __clear_user_page_asm(void *page, unsigned long vaddr);
-
- purge_tlb_start(flags);
- __clear_user_page_asm(page, vaddr);
- purge_tlb_end(flags);
-}
-
#define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
int parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD;
@@ -373,20 +364,9 @@ void __init parisc_setup_cache_timing(void)
printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
}
-extern void purge_kernel_dcache_page(unsigned long);
-extern void clear_user_page_asm(void *page, unsigned long vaddr);
-
-void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
-{
- unsigned long flags;
-
- purge_kernel_dcache_page((unsigned long)page);
- purge_tlb_start(flags);
- pdtlb_kernel(page);
- purge_tlb_end(flags);
- clear_user_page_asm(page, vaddr);
-}
-EXPORT_SYMBOL(clear_user_page);
+extern void purge_kernel_dcache_page_asm(unsigned long);
+extern void clear_user_page_asm(void *, unsigned long);
+extern void copy_user_page_asm(void *, void *, unsigned long);
void flush_kernel_dcache_page_addr(void *addr)
{
@@ -399,11 +379,26 @@ void flush_kernel_dcache_page_addr(void *addr)
}
EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
+void clear_user_page(void *vto, unsigned long vaddr, struct page *page)
+{
+ clear_page_asm(vto);
+ if (!parisc_requires_coherency())
+ flush_kernel_dcache_page_asm(vto);
+}
+EXPORT_SYMBOL(clear_user_page);
+
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
- struct page *pg)
+ struct page *pg)
{
- /* no coherency needed (all in kmap/kunmap) */
- copy_user_page_asm(vto, vfrom);
+ /* Copy using kernel mapping. No coherency is needed
+ (all in kmap/kunmap) on machines that don't support
+ non-equivalent aliasing. However, the `from' page
+ needs to be flushed before it can be accessed through
+ the kernel mapping. */
+ preempt_disable();
+ flush_dcache_page_asm(__pa(vfrom), vaddr);
+ preempt_enable();
+ copy_page_asm(vto, vfrom);
if (!parisc_requires_coherency())
flush_kernel_dcache_page_asm(vto);
}
@@ -419,6 +414,24 @@ void kunmap_parisc(void *addr)
EXPORT_SYMBOL(kunmap_parisc);
#endif
+void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
+{
+ unsigned long flags;
+
+ /* Note: purge_tlb_entries can be called at startup with
+ no context. */
+
+ /* Disable preemption while we play with %sr1. */
+ preempt_disable();
+ mtsp(mm->context, 1);
+ purge_tlb_start(flags);
+ pdtlb(addr);
+ pitlb(addr);
+ purge_tlb_end(flags);
+ preempt_enable();
+}
+EXPORT_SYMBOL(purge_tlb_entries);
+
void __flush_tlb_range(unsigned long sid, unsigned long start,
unsigned long end)
{
@@ -458,8 +471,66 @@ void flush_cache_all(void)
on_each_cpu(cacheflush_h_tmp_function, NULL, 1);
}
+static inline unsigned long mm_total_size(struct mm_struct *mm)
+{
+ struct vm_area_struct *vma;
+ unsigned long usize = 0;
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next)
+ usize += vma->vm_end - vma->vm_start;
+ return usize;
+}
+
+static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr)
+{
+ pte_t *ptep = NULL;
+
+ if (!pgd_none(*pgd)) {
+ pud_t *pud = pud_offset(pgd, addr);
+ if (!pud_none(*pud)) {
+ pmd_t *pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd))
+ ptep = pte_offset_map(pmd, addr);
+ }
+ }
+ return ptep;
+}
+
void flush_cache_mm(struct mm_struct *mm)
{
+ /* Flushing the whole cache on each cpu takes forever on
+ rp3440, etc. So, avoid it if the mm isn't too big. */
+ if (mm_total_size(mm) < parisc_cache_flush_threshold) {
+ struct vm_area_struct *vma;
+
+ if (mm->context == mfsp(3)) {
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ flush_user_dcache_range_asm(vma->vm_start,
+ vma->vm_end);
+ if (vma->vm_flags & VM_EXEC)
+ flush_user_icache_range_asm(
+ vma->vm_start, vma->vm_end);
+ }
+ } else {
+ pgd_t *pgd = mm->pgd;
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ unsigned long addr;
+
+ for (addr = vma->vm_start; addr < vma->vm_end;
+ addr += PAGE_SIZE) {
+ pte_t *ptep = get_ptep(pgd, addr);
+ if (ptep != NULL) {
+ pte_t pte = *ptep;
+ __flush_cache_page(vma, addr,
+ page_to_phys(pte_page(pte)));
+ }
+ }
+ }
+ }
+ return;
+ }
+
#ifdef CONFIG_SMP
flush_cache_all();
#else
@@ -485,20 +556,36 @@ flush_user_icache_range(unsigned long start, unsigned long end)
flush_instruction_cache();
}
-
void flush_cache_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
- int sr3;
-
BUG_ON(!vma->vm_mm->context);
- sr3 = mfsp(3);
- if (vma->vm_mm->context == sr3) {
- flush_user_dcache_range(start,end);
- flush_user_icache_range(start,end);
+ if ((end - start) < parisc_cache_flush_threshold) {
+ if (vma->vm_mm->context == mfsp(3)) {
+ flush_user_dcache_range_asm(start, end);
+ if (vma->vm_flags & VM_EXEC)
+ flush_user_icache_range_asm(start, end);
+ } else {
+ unsigned long addr;
+ pgd_t *pgd = vma->vm_mm->pgd;
+
+ for (addr = start & PAGE_MASK; addr < end;
+ addr += PAGE_SIZE) {
+ pte_t *ptep = get_ptep(pgd, addr);
+ if (ptep != NULL) {
+ pte_t pte = *ptep;
+ flush_cache_page(vma,
+ addr, pte_pfn(pte));
+ }
+ }
+ }
} else {
+#ifdef CONFIG_SMP
flush_cache_all();
+#else
+ flush_cache_all_local();
+#endif
}
}
@@ -511,3 +598,67 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
__flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn)));
}
+
+#ifdef CONFIG_PARISC_TMPALIAS
+
+void clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+ void *vto;
+ unsigned long flags;
+
+ /* Clear using TMPALIAS region. The page doesn't need to
+ be flushed but the kernel mapping needs to be purged. */
+
+ vto = kmap_atomic(page, KM_USER0);
+
+ /* The PA-RISC 2.0 Architecture book states on page F-6:
+ "Before a write-capable translation is enabled, *all*
+ non-equivalently-aliased translations must be removed
+ from the page table and purged from the TLB. (Note
+ that the caches are not required to be flushed at this
+ time.) Before any non-equivalent aliased translation
+ is re-enabled, the virtual address range for the writeable
+ page (the entire page) must be flushed from the cache,
+ and the write-capable translation removed from the page
+ table and purged from the TLB." */
+
+ purge_kernel_dcache_page_asm((unsigned long)vto);
+ purge_tlb_start(flags);
+ pdtlb_kernel(vto);
+ purge_tlb_end(flags);
+ preempt_disable();
+ clear_user_page_asm(vto, vaddr);
+ preempt_enable();
+
+ pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */
+}
+
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma)
+{
+ void *vfrom, *vto;
+ unsigned long flags;
+
+ /* Copy using TMPALIAS region. This has the advantage
+ that the `from' page doesn't need to be flushed. However,
+ the `to' page must be flushed in copy_user_page_asm since
+ it can be used to bring in executable code. */
+
+ vfrom = kmap_atomic(from, KM_USER0);
+ vto = kmap_atomic(to, KM_USER1);
+
+ purge_kernel_dcache_page_asm((unsigned long)vto);
+ purge_tlb_start(flags);
+ pdtlb_kernel(vto);
+ pdtlb_kernel(vfrom);
+ purge_tlb_end(flags);
+ preempt_disable();
+ copy_user_page_asm(vto, vfrom, vaddr);
+ flush_dcache_page_asm(__pa(vto), vaddr);
+ preempt_enable();
+
+ pagefault_enable(); /* kunmap_atomic(addr, KM_USER1); */
+ pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */
+}
+
+#endif /* CONFIG_PARISC_TMPALIAS */
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index eb7850b46c25..f33201bf8977 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -483,7 +483,7 @@
* B <-> _PAGE_DMB (memory break)
*
* Then incredible subtlety: The access rights are
- * _PAGE_GATEWAY _PAGE_EXEC _PAGE_READ
+ * _PAGE_GATEWAY, _PAGE_EXEC and _PAGE_WRITE
* See 3-14 of the parisc 2.0 manual
*
* Finally, _PAGE_READ goes in the top bit of PL1 (so we
@@ -493,7 +493,7 @@
/* PAGE_USER indicates the page can be read with user privileges,
* so deposit X1|11 to PL1|PL2 (remember the upper bit of PL1
- * contains _PAGE_READ */
+ * contains _PAGE_READ) */
extrd,u,*= \pte,_PAGE_USER_BIT+32,1,%r0
depdi 7,11,3,\prot
/* If we're a gateway page, drop PL2 back to zero for promotion
@@ -1748,44 +1748,6 @@ ENTRY(sys_rt_sigreturn_wrapper)
LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */
ENDPROC(sys_rt_sigreturn_wrapper)
-ENTRY(sys_sigaltstack_wrapper)
- /* Get the user stack pointer */
- LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
- ldo TASK_REGS(%r1),%r24 /* get pt regs */
- LDREG TASK_PT_GR30(%r24),%r24
- STREG %r2, -RP_OFFSET(%r30)
-#ifdef CONFIG_64BIT
- ldo FRAME_SIZE(%r30), %r30
- BL do_sigaltstack,%r2
- ldo -16(%r30),%r29 /* Reference param save area */
-#else
- BL do_sigaltstack,%r2
- ldo FRAME_SIZE(%r30), %r30
-#endif
-
- ldo -FRAME_SIZE(%r30), %r30
- LDREG -RP_OFFSET(%r30), %r2
- bv %r0(%r2)
- nop
-ENDPROC(sys_sigaltstack_wrapper)
-
-#ifdef CONFIG_64BIT
-ENTRY(sys32_sigaltstack_wrapper)
- /* Get the user stack pointer */
- LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r24
- LDREG TASK_PT_GR30(%r24),%r24
- STREG %r2, -RP_OFFSET(%r30)
- ldo FRAME_SIZE(%r30), %r30
- BL do_sigaltstack32,%r2
- ldo -16(%r30),%r29 /* Reference param save area */
-
- ldo -FRAME_SIZE(%r30), %r30
- LDREG -RP_OFFSET(%r30), %r2
- bv %r0(%r2)
- nop
-ENDPROC(sys32_sigaltstack_wrapper)
-#endif
-
ENTRY(syscall_exit)
/* NOTE: HP-UX syscalls also come through here
* after hpux_syscall_exit fixes up return
diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c
index 08324aac3544..3295ef4a185d 100644
--- a/arch/parisc/kernel/inventory.c
+++ b/arch/parisc/kernel/inventory.c
@@ -186,12 +186,14 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
if (status != PDC_OK) {
/* no more cell modules or error */
+ kfree(pa_pdc_cell);
return status;
}
temp = pa_pdc_cell->cba;
dev = alloc_pa_dev(PAT_GET_CBA(temp), &(pa_pdc_cell->mod_path));
if (!dev) {
+ kfree(pa_pdc_cell);
return PDC_OK;
}
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index 0299d63cd112..8094d3ed3b64 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -379,14 +379,14 @@ void do_cpu_irq_mask(struct pt_regs *regs)
static struct irqaction timer_action = {
.handler = timer_interrupt,
.name = "timer",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL,
+ .flags = IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL,
};
#ifdef CONFIG_SMP
static struct irqaction ipi_action = {
.handler = ipi_interrupt,
.name = "IPI",
- .flags = IRQF_DISABLED | IRQF_PERCPU,
+ .flags = IRQF_PERCPU,
};
#endif
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
index 5d7218ad885c..312b48422a56 100644
--- a/arch/parisc/kernel/pacache.S
+++ b/arch/parisc/kernel/pacache.S
@@ -199,7 +199,6 @@ ENTRY(flush_instruction_cache_local)
.callinfo NO_CALLS
.entry
- mtsp %r0, %sr1
load32 cache_info, %r1
/* Flush Instruction Cache */
@@ -208,7 +207,8 @@ ENTRY(flush_instruction_cache_local)
LDREG ICACHE_STRIDE(%r1), %arg1
LDREG ICACHE_COUNT(%r1), %arg2
LDREG ICACHE_LOOP(%r1), %arg3
- rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
+ rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
+ mtsp %r0, %sr1
addib,COND(=) -1, %arg3, fioneloop /* Preadjust and test */
movb,<,n %arg3, %r31, fisync /* If loop < 0, do sync */
@@ -220,7 +220,33 @@ fimanyloop: /* Loop if LOOP >= 2 */
addib,COND(<=),n -1, %arg2, fisync /* Outer loop decr */
fioneloop: /* Loop if LOOP = 1 */
- addib,COND(>) -1, %arg2, fioneloop /* Outer loop count decr */
+ /* Some implementations may flush with a single fice instruction */
+ cmpib,COND(>>=),n 15, %arg2, fioneloop2
+
+fioneloop1:
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ addib,COND(>) -16, %arg2, fioneloop1
+ fice,m %arg1(%sr1, %arg0)
+
+ /* Check if done */
+ cmpb,COND(=),n %arg2, %r0, fisync /* Predict branch taken */
+
+fioneloop2:
+ addib,COND(>) -1, %arg2, fioneloop2 /* Outer loop count decr */
fice,m %arg1(%sr1, %arg0) /* Fice for one loop */
fisync:
@@ -240,8 +266,7 @@ ENTRY(flush_data_cache_local)
.callinfo NO_CALLS
.entry
- mtsp %r0, %sr1
- load32 cache_info, %r1
+ load32 cache_info, %r1
/* Flush Data Cache */
@@ -249,7 +274,8 @@ ENTRY(flush_data_cache_local)
LDREG DCACHE_STRIDE(%r1), %arg1
LDREG DCACHE_COUNT(%r1), %arg2
LDREG DCACHE_LOOP(%r1), %arg3
- rsm PSW_SM_I, %r22
+ rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
+ mtsp %r0, %sr1
addib,COND(=) -1, %arg3, fdoneloop /* Preadjust and test */
movb,<,n %arg3, %r31, fdsync /* If loop < 0, do sync */
@@ -261,7 +287,33 @@ fdmanyloop: /* Loop if LOOP >= 2 */
addib,COND(<=),n -1, %arg2, fdsync /* Outer loop decr */
fdoneloop: /* Loop if LOOP = 1 */
- addib,COND(>) -1, %arg2, fdoneloop /* Outer loop count decr */
+ /* Some implementations may flush with a single fdce instruction */
+ cmpib,COND(>>=),n 15, %arg2, fdoneloop2
+
+fdoneloop1:
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ addib,COND(>) -16, %arg2, fdoneloop1
+ fdce,m %arg1(%sr1, %arg0)
+
+ /* Check if done */
+ cmpb,COND(=),n %arg2, %r0, fdsync /* Predict branch taken */
+
+fdoneloop2:
+ addib,COND(>) -1, %arg2, fdoneloop2 /* Outer loop count decr */
fdce,m %arg1(%sr1, %arg0) /* Fdce for one loop */
fdsync:
@@ -277,7 +329,104 @@ ENDPROC(flush_data_cache_local)
.align 16
-ENTRY(copy_user_page_asm)
+/* Macros to serialize TLB purge operations on SMP. */
+
+ .macro tlb_lock la,flags,tmp
+#ifdef CONFIG_SMP
+ ldil L%pa_tlb_lock,%r1
+ ldo R%pa_tlb_lock(%r1),\la
+ rsm PSW_SM_I,\flags
+1: LDCW 0(\la),\tmp
+ cmpib,<>,n 0,\tmp,3f
+2: ldw 0(\la),\tmp
+ cmpb,<> %r0,\tmp,1b
+ nop
+ b,n 2b
+3:
+#endif
+ .endm
+
+ .macro tlb_unlock la,flags,tmp
+#ifdef CONFIG_SMP
+ ldi 1,\tmp
+ stw \tmp,0(\la)
+ mtsm \flags
+#endif
+ .endm
+
+/* Clear page using kernel mapping. */
+
+ENTRY(clear_page_asm)
+ .proc
+ .callinfo NO_CALLS
+ .entry
+
+#ifdef CONFIG_64BIT
+
+ /* Unroll the loop. */
+ ldi (PAGE_SIZE / 128), %r1
+
+1:
+ std %r0, 0(%r26)
+ std %r0, 8(%r26)
+ std %r0, 16(%r26)
+ std %r0, 24(%r26)
+ std %r0, 32(%r26)
+ std %r0, 40(%r26)
+ std %r0, 48(%r26)
+ std %r0, 56(%r26)
+ std %r0, 64(%r26)
+ std %r0, 72(%r26)
+ std %r0, 80(%r26)
+ std %r0, 88(%r26)
+ std %r0, 96(%r26)
+ std %r0, 104(%r26)
+ std %r0, 112(%r26)
+ std %r0, 120(%r26)
+
+ /* Note reverse branch hint for addib is taken. */
+ addib,COND(>),n -1, %r1, 1b
+ ldo 128(%r26), %r26
+
+#else
+
+ /*
+ * Note that until (if) we start saving the full 64-bit register
+ * values on interrupt, we can't use std on a 32 bit kernel.
+ */
+ ldi (PAGE_SIZE / 64), %r1
+
+1:
+ stw %r0, 0(%r26)
+ stw %r0, 4(%r26)
+ stw %r0, 8(%r26)
+ stw %r0, 12(%r26)
+ stw %r0, 16(%r26)
+ stw %r0, 20(%r26)
+ stw %r0, 24(%r26)
+ stw %r0, 28(%r26)
+ stw %r0, 32(%r26)
+ stw %r0, 36(%r26)
+ stw %r0, 40(%r26)
+ stw %r0, 44(%r26)
+ stw %r0, 48(%r26)
+ stw %r0, 52(%r26)
+ stw %r0, 56(%r26)
+ stw %r0, 60(%r26)
+
+ addib,COND(>),n -1, %r1, 1b
+ ldo 64(%r26), %r26
+#endif
+ bv %r0(%r2)
+ nop
+ .exit
+
+ .procend
+ENDPROC(clear_page_asm)
+
+/* Copy page using kernel mapping. */
+
+ENTRY(copy_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -285,18 +434,14 @@ ENTRY(copy_user_page_asm)
#ifdef CONFIG_64BIT
/* PA8x00 CPUs can consume 2 loads or 1 store per cycle.
* Unroll the loop by hand and arrange insn appropriately.
- * GCC probably can do this just as well.
+ * Prefetch doesn't improve performance on rp3440.
+ * GCC probably can do this just as well...
*/
- ldd 0(%r25), %r19
ldi (PAGE_SIZE / 128), %r1
- ldw 64(%r25), %r0 /* prefetch 1 cacheline ahead */
- ldw 128(%r25), %r0 /* prefetch 2 */
-
-1: ldd 8(%r25), %r20
- ldw 192(%r25), %r0 /* prefetch 3 */
- ldw 256(%r25), %r0 /* prefetch 4 */
+1: ldd 0(%r25), %r19
+ ldd 8(%r25), %r20
ldd 16(%r25), %r21
ldd 24(%r25), %r22
@@ -330,20 +475,16 @@ ENTRY(copy_user_page_asm)
ldd 112(%r25), %r21
ldd 120(%r25), %r22
+ ldo 128(%r25), %r25
std %r19, 96(%r26)
std %r20, 104(%r26)
- ldo 128(%r25), %r25
std %r21, 112(%r26)
std %r22, 120(%r26)
- ldo 128(%r26), %r26
- /* conditional branches nullify on forward taken branch, and on
- * non-taken backward branch. Note that .+4 is a backwards branch.
- * The ldd should only get executed if the branch is taken.
- */
- addib,COND(>),n -1, %r1, 1b /* bundle 10 */
- ldd 0(%r25), %r19 /* start next loads */
+ /* Note reverse branch hint for addib is taken. */
+ addib,COND(>),n -1, %r1, 1b
+ ldo 128(%r26), %r26
#else
@@ -399,7 +540,7 @@ ENTRY(copy_user_page_asm)
.exit
.procend
-ENDPROC(copy_user_page_asm)
+ENDPROC(copy_page_asm)
/*
* NOTE: Code in clear_user_page has a hard coded dependency on the
@@ -422,8 +563,6 @@ ENDPROC(copy_user_page_asm)
* %r23 physical page (shifted for tlb insert) of "from" translation
*/
-#if 0
-
/*
* We can't do this since copy_user_page is used to bring in
* file data that might have instructions. Since the data would
@@ -435,6 +574,7 @@ ENDPROC(copy_user_page_asm)
* use it if more information is passed into copy_user_page().
* Have to do some measurements to see if it is worthwhile to
* lobby for such a change.
+ *
*/
ENTRY(copy_user_page_asm)
@@ -442,16 +582,21 @@ ENTRY(copy_user_page_asm)
.callinfo NO_CALLS
.entry
+ /* Convert virtual `to' and `from' addresses to physical addresses.
+ Move `from' physical address to non shadowed register. */
ldil L%(__PAGE_OFFSET), %r1
sub %r26, %r1, %r26
- sub %r25, %r1, %r23 /* move physical addr into non shadowed reg */
+ sub %r25, %r1, %r23
ldil L%(TMPALIAS_MAP_START), %r28
/* FIXME for different page sizes != 4k */
#ifdef CONFIG_64BIT
- extrd,u %r26,56,32, %r26 /* convert phys addr to tlb insert format */
- extrd,u %r23,56,32, %r23 /* convert phys addr to tlb insert format */
- depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */
+#if (TMPALIAS_MAP_START >= 0x80000000)
+ depdi 0, 31,32, %r28 /* clear any sign extension */
+#endif
+ extrd,u %r26,56,32, %r26 /* convert phys addr to tlb insert format */
+ extrd,u %r23,56,32, %r23 /* convert phys addr to tlb insert format */
+ depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */
depdi 0, 63,12, %r28 /* Clear any offset bits */
copy %r28, %r29
depdi 1, 41,1, %r29 /* Form aliased virtual address 'from' */
@@ -466,10 +611,76 @@ ENTRY(copy_user_page_asm)
/* Purge any old translations */
+#ifdef CONFIG_PA20
+ pdtlb,l 0(%r28)
+ pdtlb,l 0(%r29)
+#else
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
pdtlb 0(%r29)
+ tlb_unlock %r20,%r21,%r22
+#endif
+
+#ifdef CONFIG_64BIT
+ /* PA8x00 CPUs can consume 2 loads or 1 store per cycle.
+ * Unroll the loop by hand and arrange insn appropriately.
+ * GCC probably can do this just as well.
+ */
- ldi 64, %r1
+ ldd 0(%r29), %r19
+ ldi (PAGE_SIZE / 128), %r1
+
+1: ldd 8(%r29), %r20
+
+ ldd 16(%r29), %r21
+ ldd 24(%r29), %r22
+ std %r19, 0(%r28)
+ std %r20, 8(%r28)
+
+ ldd 32(%r29), %r19
+ ldd 40(%r29), %r20
+ std %r21, 16(%r28)
+ std %r22, 24(%r28)
+
+ ldd 48(%r29), %r21
+ ldd 56(%r29), %r22
+ std %r19, 32(%r28)
+ std %r20, 40(%r28)
+
+ ldd 64(%r29), %r19
+ ldd 72(%r29), %r20
+ std %r21, 48(%r28)
+ std %r22, 56(%r28)
+
+ ldd 80(%r29), %r21
+ ldd 88(%r29), %r22
+ std %r19, 64(%r28)
+ std %r20, 72(%r28)
+
+ ldd 96(%r29), %r19
+ ldd 104(%r29), %r20
+ std %r21, 80(%r28)
+ std %r22, 88(%r28)
+
+ ldd 112(%r29), %r21
+ ldd 120(%r29), %r22
+ std %r19, 96(%r28)
+ std %r20, 104(%r28)
+
+ ldo 128(%r29), %r29
+ std %r21, 112(%r28)
+ std %r22, 120(%r28)
+ ldo 128(%r28), %r28
+
+ /* conditional branches nullify on forward taken branch, and on
+ * non-taken backward branch. Note that .+4 is a backwards branch.
+ * The ldd should only get executed if the branch is taken.
+ */
+ addib,COND(>),n -1, %r1, 1b /* bundle 10 */
+ ldd 0(%r29), %r19 /* start next loads */
+
+#else
+ ldi (PAGE_SIZE / 64), %r1
/*
* This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
@@ -480,9 +691,7 @@ ENTRY(copy_user_page_asm)
* use ldd/std on a 32 bit kernel.
*/
-
-1:
- ldw 0(%r29), %r19
+1: ldw 0(%r29), %r19
ldw 4(%r29), %r20
ldw 8(%r29), %r21
ldw 12(%r29), %r22
@@ -515,8 +724,10 @@ ENTRY(copy_user_page_asm)
stw %r21, 56(%r28)
stw %r22, 60(%r28)
ldo 64(%r28), %r28
+
addib,COND(>) -1, %r1,1b
ldo 64(%r29), %r29
+#endif
bv %r0(%r2)
nop
@@ -524,9 +735,8 @@ ENTRY(copy_user_page_asm)
.procend
ENDPROC(copy_user_page_asm)
-#endif
-ENTRY(__clear_user_page_asm)
+ENTRY(clear_user_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -550,7 +760,13 @@ ENTRY(__clear_user_page_asm)
/* Purge any old translation */
+#ifdef CONFIG_PA20
+ pdtlb,l 0(%r28)
+#else
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
+ tlb_unlock %r20,%r21,%r22
+#endif
#ifdef CONFIG_64BIT
ldi (PAGE_SIZE / 128), %r1
@@ -580,8 +796,7 @@ ENTRY(__clear_user_page_asm)
#else /* ! CONFIG_64BIT */
ldi (PAGE_SIZE / 64), %r1
-1:
- stw %r0, 0(%r28)
+1: stw %r0, 0(%r28)
stw %r0, 4(%r28)
stw %r0, 8(%r28)
stw %r0, 12(%r28)
@@ -606,7 +821,7 @@ ENTRY(__clear_user_page_asm)
.exit
.procend
-ENDPROC(__clear_user_page_asm)
+ENDPROC(clear_user_page_asm)
ENTRY(flush_dcache_page_asm)
.proc
@@ -630,7 +845,13 @@ ENTRY(flush_dcache_page_asm)
/* Purge any old translation */
+#ifdef CONFIG_PA20
+ pdtlb,l 0(%r28)
+#else
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
+ tlb_unlock %r20,%r21,%r22
+#endif
ldil L%dcache_stride, %r1
ldw R%dcache_stride(%r1), %r1
@@ -663,8 +884,17 @@ ENTRY(flush_dcache_page_asm)
fdc,m %r1(%r28)
sync
+
+#ifdef CONFIG_PA20
+ pdtlb,l 0(%r25)
+#else
+ tlb_lock %r20,%r21,%r22
+ pdtlb 0(%r25)
+ tlb_unlock %r20,%r21,%r22
+#endif
+
bv %r0(%r2)
- pdtlb (%r25)
+ nop
.exit
.procend
@@ -692,7 +922,13 @@ ENTRY(flush_icache_page_asm)
/* Purge any old translation */
- pitlb (%sr4,%r28)
+#ifdef CONFIG_PA20
+ pitlb,l %r0(%sr4,%r28)
+#else
+ tlb_lock %r20,%r21,%r22
+ pitlb (%sr4,%r28)
+ tlb_unlock %r20,%r21,%r22
+#endif
ldil L%icache_stride, %r1
ldw R%icache_stride(%r1), %r1
@@ -727,8 +963,17 @@ ENTRY(flush_icache_page_asm)
fic,m %r1(%sr4,%r28)
sync
+
+#ifdef CONFIG_PA20
+ pitlb,l %r0(%sr4,%r25)
+#else
+ tlb_lock %r20,%r21,%r22
+ pitlb (%sr4,%r25)
+ tlb_unlock %r20,%r21,%r22
+#endif
+
bv %r0(%r2)
- pitlb (%sr4,%r25)
+ nop
.exit
.procend
@@ -777,7 +1022,7 @@ ENTRY(flush_kernel_dcache_page_asm)
.procend
ENDPROC(flush_kernel_dcache_page_asm)
-ENTRY(purge_kernel_dcache_page)
+ENTRY(purge_kernel_dcache_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -817,7 +1062,7 @@ ENTRY(purge_kernel_dcache_page)
.exit
.procend
-ENDPROC(purge_kernel_dcache_page)
+ENDPROC(purge_kernel_dcache_page_asm)
ENTRY(flush_user_dcache_range_asm)
.proc
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index ceec85de6290..6795dc6c995f 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -157,5 +157,6 @@ extern void _mcount(void);
EXPORT_SYMBOL(_mcount);
#endif
-/* from pacache.S -- needed for copy_page */
-EXPORT_SYMBOL(copy_user_page_asm);
+/* from pacache.S -- needed for clear/copy_page */
+EXPORT_SYMBOL(clear_page_asm);
+EXPORT_SYMBOL(copy_page_asm);
diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
index efc5e7d30530..d5cae55195ec 100644
--- a/arch/parisc/kernel/pdc_cons.c
+++ b/arch/parisc/kernel/pdc_cons.c
@@ -138,23 +138,17 @@ static const struct tty_operations pdc_console_tty_ops = {
static void pdc_console_poll(unsigned long unused)
{
int data, count = 0;
- struct tty_struct *tty = tty_port_tty_get(&tty_port);
-
- if (!tty)
- return;
while (1) {
data = pdc_console_poll_key(NULL);
if (data == -1)
break;
- tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
+ tty_insert_flip_char(&tty_port, data & 0xFF, TTY_NORMAL);
count ++;
}
if (count)
- tty_flip_buffer_push(tty);
-
- tty_kref_put(tty);
+ tty_flip_buffer_push(&tty_port);
if (pdc_cons.flags & CON_ENABLED)
mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index fd051705a407..98e9e7126565 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -143,7 +143,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
goto give_sigsegv;
DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n",
usp, &compat_frame->uc.uc_stack);
- if (do_sigaltstack32(&compat_frame->uc.uc_stack, NULL, usp) == -EFAULT)
+ if (compat_restore_altstack(&compat_frame->uc.uc_stack))
goto give_sigsegv;
} else
#endif
@@ -154,7 +154,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
goto give_sigsegv;
DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n",
usp, &frame->uc.uc_stack);
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto give_sigsegv;
}
@@ -262,15 +262,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (is_compat_task()) {
DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
err |= copy_siginfo_to_user32(&compat_frame->info, info);
- DBG(1,"SETUP_RT_FRAME: 1\n");
- compat_val = (compat_int_t)current->sas_ss_sp;
- err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp);
- DBG(1,"SETUP_RT_FRAME: 2\n");
- compat_val = (compat_int_t)current->sas_ss_size;
- err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_size);
- DBG(1,"SETUP_RT_FRAME: 3\n");
- compat_val = sas_ss_flags(regs->gr[30]);
- err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_flags);
+ err |= __compat_save_altstack( &compat_frame->uc.uc_stack, regs->gr[30]);
DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &compat_frame->uc);
DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext);
err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext,
@@ -282,10 +274,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
{
DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &frame->info);
err |= copy_siginfo_to_user(&frame->info, info);
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
- err |= __put_user(sas_ss_flags(regs->gr[30]),
- &frame->uc.uc_stack.ss_flags);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->gr[30]);
DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &frame->uc);
DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &frame->uc.uc_mcontext);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall);
@@ -312,7 +301,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
#if DEBUG_SIG
/* Assert that we're flushing in the correct space... */
{
- int sid;
+ unsigned long sid;
asm ("mfsp %%sr3,%0" : "=r" (sid));
DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n",
sid, frame->tramp);
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c
index 5dede04f2f3e..33eca1b04926 100644
--- a/arch/parisc/kernel/signal32.c
+++ b/arch/parisc/kernel/signal32.c
@@ -60,129 +60,6 @@ sigset_64to32(compat_sigset_t *s32, sigset_t *s64)
s32->sig[1] = (s64->sig[0] >> 32) & 0xffffffffUL;
}
-static int
-put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz)
-{
- compat_sigset_t s;
-
- if (sz != sizeof *set)
- return -EINVAL;
- sigset_64to32(&s, set);
-
- return copy_to_user(up, &s, sizeof s);
-}
-
-static int
-get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz)
-{
- compat_sigset_t s;
- int r;
-
- if (sz != sizeof *set)
- return -EINVAL;
-
- if ((r = copy_from_user(&s, up, sz)) == 0) {
- sigset_32to64(set, &s);
- }
-
- return r;
-}
-
-int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t __user *oset,
- unsigned int sigsetsize)
-{
- sigset_t old_set, new_set;
- int ret;
-
- if (set && get_sigset32(set, &new_set, sigsetsize))
- return -EFAULT;
-
- KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? (sigset_t __user *)&new_set : NULL,
- oset ? (sigset_t __user *)&old_set : NULL, sigsetsize);
-
- if (!ret && oset && put_sigset32(oset, &old_set, sigsetsize))
- return -EFAULT;
-
- return ret;
-}
-
-
-int sys32_rt_sigpending(compat_sigset_t __user *uset, unsigned int sigsetsize)
-{
- int ret;
- sigset_t set;
-
- KERNEL_SYSCALL(ret, sys_rt_sigpending, (sigset_t __user *)&set, sigsetsize);
-
- if (!ret && put_sigset32(uset, &set, sigsetsize))
- return -EFAULT;
-
- return ret;
-}
-
-long
-sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigaction32 __user *oact,
- size_t sigsetsize)
-{
- struct k_sigaction32 new_sa32, old_sa32;
- struct k_sigaction new_sa, old_sa;
- int ret = -EINVAL;
-
- if (act) {
- if (copy_from_user(&new_sa32.sa, act, sizeof new_sa32.sa))
- return -EFAULT;
- new_sa.sa.sa_handler = (__sighandler_t)(unsigned long)new_sa32.sa.sa_handler;
- new_sa.sa.sa_flags = new_sa32.sa.sa_flags;
- sigset_32to64(&new_sa.sa.sa_mask, &new_sa32.sa.sa_mask);
- }
-
- ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
-
- if (!ret && oact) {
- sigset_64to32(&old_sa32.sa.sa_mask, &old_sa.sa.sa_mask);
- old_sa32.sa.sa_flags = old_sa.sa.sa_flags;
- old_sa32.sa.sa_handler = (__sighandler_t32)(unsigned long)old_sa.sa.sa_handler;
- if (copy_to_user(oact, &old_sa32.sa, sizeof old_sa32.sa))
- return -EFAULT;
- }
- return ret;
-}
-
-int
-do_sigaltstack32 (const compat_stack_t __user *uss32, compat_stack_t __user *uoss32, unsigned long sp)
-{
- compat_stack_t ss32, oss32;
- stack_t ss, oss;
- stack_t *ssp = NULL, *ossp = NULL;
- int ret;
-
- if (uss32) {
- if (copy_from_user(&ss32, uss32, sizeof ss32))
- return -EFAULT;
-
- ss.ss_sp = (void __user *)(unsigned long)ss32.ss_sp;
- ss.ss_flags = ss32.ss_flags;
- ss.ss_size = ss32.ss_size;
-
- ssp = &ss;
- }
-
- if (uoss32)
- ossp = &oss;
-
- KERNEL_SYSCALL(ret, do_sigaltstack, (const stack_t __user *)ssp, (stack_t __user *)ossp, sp);
-
- if (!ret && uoss32) {
- oss32.ss_sp = (unsigned int)(unsigned long)oss.ss_sp;
- oss32.ss_flags = oss.ss_flags;
- oss32.ss_size = oss.ss_size;
- if (copy_to_user(uoss32, &oss32, sizeof *uoss32))
- return -EFAULT;
- }
-
- return ret;
-}
-
long
restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
struct pt_regs *regs)
@@ -499,22 +376,3 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from)
}
return err;
}
-
-asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig,
- struct compat_siginfo __user *uinfo)
-{
- siginfo_t info;
-
- if (copy_siginfo_from_user32(&info, uinfo))
- return -EFAULT;
-
- /* Not even root can pretend to send signals from the kernel.
- Nor can they impersonate a kill(), which adds source info. */
- if (info.si_code >= 0)
- return -EPERM;
- info.si_signo = sig;
-
- /* POSIX.1b doesn't mention process groups. */
- return kill_proc_info(sig, &info, pid);
-}
-
diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h
index 08a88b5349a2..72ab41a51f32 100644
--- a/arch/parisc/kernel/signal32.h
+++ b/arch/parisc/kernel/signal32.h
@@ -21,23 +21,6 @@
#include <linux/compat.h>
-typedef compat_uptr_t compat_sighandler_t;
-
-typedef struct compat_sigaltstack {
- compat_uptr_t ss_sp;
- compat_int_t ss_flags;
- compat_size_t ss_size;
-} compat_stack_t;
-
-/* Most things should be clean enough to redefine this at will, if care
- is taken to make libc match. */
-
-struct compat_sigaction {
- compat_sighandler_t sa_handler;
- compat_uint_t sa_flags;
- compat_sigset_t sa_mask; /* mask last for extensibility */
-};
-
/* 32-bit ucontext as seen from an 64-bit kernel */
struct compat_ucontext {
compat_uint_t uc_flags;
@@ -51,10 +34,6 @@ struct compat_ucontext {
/* ELF32 signal handling */
-struct k_sigaction32 {
- struct compat_sigaction sa;
-};
-
int copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from);
int copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from);
@@ -102,8 +81,6 @@ struct compat_rt_sigframe {
void sigset_32to64(sigset_t *s64, compat_sigset_t *s32);
void sigset_64to32(compat_sigset_t *s32, sigset_t *s64);
-int do_sigaltstack32 (const compat_stack_t __user *uss32,
- compat_stack_t __user *uoss32, unsigned long sp);
long restore_sigcontext32(struct compat_sigcontext __user *sc,
struct compat_regfile __user *rf,
struct pt_regs *regs);
diff --git a/arch/parisc/kernel/sys32.h b/arch/parisc/kernel/sys32.h
index 06c2090cfaba..60dd470f39f8 100644
--- a/arch/parisc/kernel/sys32.h
+++ b/arch/parisc/kernel/sys32.h
@@ -33,16 +33,4 @@
set_fs (old_fs); \
}
-#ifdef CONFIG_COMPAT
-
-typedef __u32 __sighandler_t32;
-
-struct sigaction32 {
- __sighandler_t32 sa_handler;
- unsigned int sa_flags;
- compat_sigset_t sa_mask; /* mask last for extensibility */
-};
-
-#endif
-
#endif
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index f76c10863c62..54d619d4cac6 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -94,11 +94,12 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
{
if (len > TASK_SIZE)
return -ENOMEM;
- /* Might want to check for cache aliasing issues for MAP_FIXED case
- * like ARM or MIPS ??? --BenH.
- */
- if (flags & MAP_FIXED)
+ if (flags & MAP_FIXED) {
+ if ((flags & MAP_SHARED) &&
+ (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
+ return -EINVAL;
return addr;
+ }
if (!addr)
addr = TASK_UNMAPPED_BASE;
@@ -212,6 +213,13 @@ asmlinkage long parisc_sync_file_range(int fd,
(loff_t)hi_nbytes << 32 | lo_nbytes, flags);
}
+asmlinkage long parisc_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+ u32 lenhi, u32 lenlo)
+{
+ return sys_fallocate(fd, mode, ((u64)offhi << 32) | offlo,
+ ((u64)lenhi << 32) | lenlo);
+}
+
asmlinkage unsigned long sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag)
{
return -ENOMEM;
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index 9cfdaa19ab63..eca69bb8ef5f 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -21,7 +21,6 @@
#include <linux/time.h>
#include <linux/smp.h>
#include <linux/sem.h>
-#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/slab.h>
#include <linux/uio.h>
@@ -61,111 +60,23 @@ asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
return -ENOSYS;
}
-asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
- struct compat_timespec __user *interval)
-{
- struct timespec t;
- int ret;
-
- KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, (struct timespec __user *)&t);
- if (put_compat_timespec(&t, interval))
- return -EFAULT;
- return ret;
-}
-
-struct msgbuf32 {
- int mtype;
- char mtext[1];
-};
-
-asmlinkage long sys32_msgsnd(int msqid,
- struct msgbuf32 __user *umsgp32,
- size_t msgsz, int msgflg)
-{
- struct msgbuf *mb;
- struct msgbuf32 mb32;
- int err;
-
- if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- err = get_user(mb32.mtype, &umsgp32->mtype);
- mb->mtype = mb32.mtype;
- err |= copy_from_user(mb->mtext, &umsgp32->mtext, msgsz);
-
- if (err)
- err = -EFAULT;
- else
- KERNEL_SYSCALL(err, sys_msgsnd, msqid, (struct msgbuf __user *)mb, msgsz, msgflg);
-
- kfree(mb);
- return err;
-}
-
-asmlinkage long sys32_msgrcv(int msqid,
- struct msgbuf32 __user *umsgp32,
- size_t msgsz, long msgtyp, int msgflg)
-{
- struct msgbuf *mb;
- struct msgbuf32 mb32;
- int err, len;
-
- if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- KERNEL_SYSCALL(err, sys_msgrcv, msqid, (struct msgbuf __user *)mb, msgsz, msgtyp, msgflg);
-
- if (err >= 0) {
- len = err;
- mb32.mtype = mb->mtype;
- err = put_user(mb32.mtype, &umsgp32->mtype);
- err |= copy_to_user(&umsgp32->mtext, mb->mtext, len);
- if (err)
- err = -EFAULT;
- else
- err = len;
- }
-
- kfree(mb);
- return err;
-}
-
-asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count)
+/* Note: it is necessary to treat out_fd and in_fd as unsigned ints, with the
+ * corresponding cast to a signed int to insure that the proper conversion
+ * (sign extension) between the register representation of a signed int (msr in
+ * 32-bit mode) and the register representation of a signed int (msr in 64-bit
+ * mode) is performed.
+ */
+asmlinkage long sys32_sendfile(u32 out_fd, u32 in_fd,
+ compat_off_t __user *offset, compat_size_t count)
{
- mm_segment_t old_fs = get_fs();
- int ret;
- off_t of;
-
- if (offset && get_user(of, offset))
- return -EFAULT;
-
- set_fs(KERNEL_DS);
- ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
- set_fs(old_fs);
-
- if (offset && put_user(of, offset))
- return -EFAULT;
-
- return ret;
+ return compat_sys_sendfile((int)out_fd, (int)in_fd, offset, count);
}
-asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count)
+asmlinkage long sys32_sendfile64(u32 out_fd, u32 in_fd,
+ compat_loff_t __user *offset, compat_size_t count)
{
- mm_segment_t old_fs = get_fs();
- int ret;
- loff_t lof;
-
- if (offset && get_user(lof, offset))
- return -EFAULT;
-
- set_fs(KERNEL_DS);
- ret = sys_sendfile64(out_fd, in_fd, offset ? (loff_t __user *)&lof : NULL, count);
- set_fs(old_fs);
-
- if (offset && put_user(lof, offset))
- return -EFAULT;
-
- return ret;
+ return sys_sendfile64((int)out_fd, (int)in_fd,
+ (loff_t __user *)offset, count);
}
@@ -200,13 +111,6 @@ long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
buf, len);
}
-asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
- u32 lenhi, u32 lenlo)
-{
- return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
- ((loff_t)lenhi << 32) | lenlo);
-}
-
asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi,
u32 mask_lo, int fd,
const char __user *pathname)
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
index 86742df0b194..5e055240f00b 100644
--- a/arch/parisc/kernel/syscall.S
+++ b/arch/parisc/kernel/syscall.S
@@ -309,10 +309,13 @@ tracesys_next:
LDREG TASK_PT_GR25(%r1), %r25
LDREG TASK_PT_GR24(%r1), %r24
LDREG TASK_PT_GR23(%r1), %r23
-#ifdef CONFIG_64BIT
LDREG TASK_PT_GR22(%r1), %r22
LDREG TASK_PT_GR21(%r1), %r21
+#ifdef CONFIG_64BIT
ldo -16(%r30),%r29 /* Reference param save area */
+#else
+ stw %r22, -52(%r30) /* 5th argument */
+ stw %r21, -56(%r30) /* 6th argument */
#endif
comiclr,>>= __NR_Linux_syscalls, %r20, %r0
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 54d950b067b7..fc9cab1cc2df 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -247,15 +247,12 @@
ENTRY_SAME(sched_yield)
ENTRY_SAME(sched_get_priority_max)
ENTRY_SAME(sched_get_priority_min) /* 160 */
- /* These 2 would've worked if someone had defined struct timespec
- * carefully, like timeval for example (which is about the same).
- * Unfortunately it contains a long :-( */
- ENTRY_DIFF(sched_rr_get_interval)
+ ENTRY_COMP(sched_rr_get_interval)
ENTRY_COMP(nanosleep)
ENTRY_SAME(mremap)
ENTRY_SAME(setresuid)
ENTRY_SAME(getresuid) /* 165 */
- ENTRY_DIFF(sigaltstack_wrapper)
+ ENTRY_COMP(sigaltstack)
ENTRY_SAME(ni_syscall) /* query_module */
ENTRY_SAME(poll)
/* structs contain pointers and an in_addr... */
@@ -265,9 +262,9 @@
ENTRY_SAME(prctl)
/* signals need a careful review */
ENTRY_SAME(rt_sigreturn_wrapper)
- ENTRY_DIFF(rt_sigaction)
- ENTRY_DIFF(rt_sigprocmask) /* 175 */
- ENTRY_DIFF(rt_sigpending)
+ ENTRY_COMP(rt_sigaction)
+ ENTRY_COMP(rt_sigprocmask) /* 175 */
+ ENTRY_COMP(rt_sigpending)
ENTRY_COMP(rt_sigtimedwait)
/* even though the struct siginfo_t is different, it appears like
* all the paths use values which should be same wide and narrow.
@@ -286,8 +283,8 @@
ENTRY_SAME(semop) /* 185 */
ENTRY_SAME(semget)
ENTRY_DIFF(semctl)
- ENTRY_DIFF(msgsnd)
- ENTRY_DIFF(msgrcv)
+ ENTRY_COMP(msgsnd)
+ ENTRY_COMP(msgrcv)
ENTRY_SAME(msgget) /* 190 */
ENTRY_SAME(msgctl)
ENTRY_SAME(shmat)
@@ -307,7 +304,7 @@
ENTRY_SAME(gettid)
ENTRY_OURS(readahead)
ENTRY_SAME(tkill)
- ENTRY_SAME(sendfile64)
+ ENTRY_DIFF(sendfile64)
ENTRY_COMP(futex) /* 210 */
ENTRY_COMP(sched_setaffinity)
ENTRY_COMP(sched_getaffinity)
@@ -327,12 +324,12 @@
ENTRY_SAME(epoll_wait)
ENTRY_SAME(remap_file_pages)
ENTRY_SAME(semtimedop)
- ENTRY_SAME(mq_open)
+ ENTRY_COMP(mq_open)
ENTRY_SAME(mq_unlink) /* 230 */
- ENTRY_SAME(mq_timedsend)
- ENTRY_SAME(mq_timedreceive)
- ENTRY_SAME(mq_notify)
- ENTRY_SAME(mq_getsetattr)
+ ENTRY_COMP(mq_timedsend)
+ ENTRY_COMP(mq_timedreceive)
+ ENTRY_COMP(mq_notify)
+ ENTRY_COMP(mq_getsetattr)
ENTRY_COMP(waitid) /* 235 */
ENTRY_OURS(fadvise64_64)
ENTRY_SAME(set_tid_address)
@@ -403,7 +400,7 @@
ENTRY_COMP(signalfd)
ENTRY_SAME(ni_syscall) /* was timerfd */
ENTRY_SAME(eventfd)
- ENTRY_COMP(fallocate) /* 305 */
+ ENTRY_OURS(fallocate) /* 305 */
ENTRY_SAME(timerfd_create)
ENTRY_COMP(timerfd_settime)
ENTRY_COMP(timerfd_gettime)
@@ -428,6 +425,10 @@
ENTRY_SAME(syncfs)
ENTRY_SAME(setns)
ENTRY_COMP(sendmmsg)
+ ENTRY_COMP(process_vm_readv) /* 330 */
+ ENTRY_COMP(process_vm_writev)
+ ENTRY_SAME(kcmp)
+ ENTRY_SAME(finit_module)
/* Nothing yet */
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 45ba99f5080b..aeb8f8f2c07a 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -282,7 +282,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
show_regs(regs);
dump_stack();
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
if (in_interrupt())
panic("Fatal exception in interrupt");
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
index 18162ce4261e..f247a3480e8e 100644
--- a/arch/parisc/mm/fault.c
+++ b/arch/parisc/mm/fault.c
@@ -175,10 +175,12 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
struct mm_struct *mm = tsk->mm;
unsigned long acc_type;
int fault;
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
if (in_atomic() || !mm)
goto no_context;
+retry:
down_read(&mm->mmap_sem);
vma = find_vma_prev(mm, address, &prev_vma);
if (!vma || address < vma->vm_start)
@@ -201,7 +203,12 @@ good_area:
* fault.
*/
- fault = handle_mm_fault(mm, vma, address, (acc_type & VM_WRITE) ? FAULT_FLAG_WRITE : 0);
+ fault = handle_mm_fault(mm, vma, address,
+ flags | ((acc_type & VM_WRITE) ? FAULT_FLAG_WRITE : 0));
+
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+ return;
+
if (unlikely(fault & VM_FAULT_ERROR)) {
/*
* We hit a shared mapping outside of the file, or some
@@ -214,10 +221,23 @@ good_area:
goto bad_area;
BUG();
}
- if (fault & VM_FAULT_MAJOR)
- current->maj_flt++;
- else
- current->min_flt++;
+ if (flags & FAULT_FLAG_ALLOW_RETRY) {
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
+ if (fault & VM_FAULT_RETRY) {
+ flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+ /*
+ * No need to up_read(&mm->mmap_sem) as we would
+ * have already released it in __lock_page_or_retry
+ * in mm/filemap.c.
+ */
+
+ goto retry;
+ }
+ }
up_read(&mm->mmap_sem);
return;
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 17903f1f356b..5c7470689a10 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -118,14 +118,12 @@ config PPC
select HAVE_SYSCALL_WRAPPERS if PPC64
select GENERIC_ATOMIC64 if PPC32
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
select HAVE_GENERIC_HARDIRQS
select ARCH_WANT_IPC_PARSE_VERSION
select SPARSE_IRQ
- select IRQ_PER_CPU
select IRQ_DOMAIN
select GENERIC_IRQ_SHOW
select GENERIC_IRQ_SHOW_LEVEL
@@ -144,6 +142,9 @@ config PPC
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
select CLONE_BACKWARDS
+ select ARCH_USE_BUILTIN_BSWAP
+ select OLD_SIGSUSPEND
+ select OLD_SIGACTION if PPC32
config EARLY_PRINTK
bool
@@ -154,6 +155,7 @@ config COMPAT
default y if PPC64
select COMPAT_BINFMT_ELF
select ARCH_WANT_OLD_COMPAT_IPC
+ select COMPAT_OLD_SIGACTION
config SYSVIPC_COMPAT
bool
@@ -275,6 +277,10 @@ config PPC_ADV_DEBUG_DAC_RANGE
depends on PPC_ADV_DEBUG_REGS && 44x
default y
+config PPC_EMULATE_SSTEP
+ bool
+ default y if KPROBES || UPROBES || XMON || HAVE_HW_BREAKPOINT
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
@@ -308,6 +314,14 @@ config MATH_EMULATION
unit, which will allow programs that use floating-point
instructions to run.
+config PPC_TRANSACTIONAL_MEM
+ bool "Transactional Memory support for POWERPC"
+ depends on PPC_BOOK3S_64
+ depends on SMP
+ default n
+ ---help---
+ Support user-mode Transactional Memory on POWERPC.
+
config 8XX_MINIMAL_FPEMU
bool "Minimal math emulation for 8xx"
depends on 8xx && !MATH_EMULATION
@@ -334,7 +348,7 @@ config SWIOTLB
config HOTPLUG_CPU
bool "Support for enabling/disabling CPUs"
- depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || \
+ depends on SMP && HOTPLUG && (PPC_PSERIES || \
PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC))
---help---
Say Y here to be able to disable and re-enable individual
@@ -356,8 +370,8 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
def_bool y
config KEXEC
- bool "kexec system call (EXPERIMENTAL)"
- depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) && EXPERIMENTAL
+ bool "kexec system call"
+ depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP))
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
@@ -852,8 +866,8 @@ config LOWMEM_CAM_NUM
default 3
config DYNAMIC_MEMSTART
- bool "Enable page aligned dynamic load address for kernel (EXPERIMENTAL)"
- depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM && (FSL_BOOKE || 44x)
+ bool "Enable page aligned dynamic load address for kernel"
+ depends on ADVANCED_OPTIONS && FLATMEM && (FSL_BOOKE || 44x)
select NONSTATIC_KERNEL
help
This option enables the kernel to be loaded at any page aligned
@@ -870,8 +884,8 @@ config DYNAMIC_MEMSTART
This option is overridden by CONFIG_RELOCATABLE
config RELOCATABLE
- bool "Build a relocatable kernel (EXPERIMENTAL)"
- depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM && 44x
+ bool "Build a relocatable kernel"
+ depends on ADVANCED_OPTIONS && FLATMEM && 44x
select NONSTATIC_KERNEL
help
This builds a kernel image that is capable of running at the
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index b639852116fa..967fd23ace78 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -67,7 +67,25 @@ LDFLAGS_vmlinux-y := -Bstatic
LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) := -pie
LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y)
-CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=no -mcall-aixdesc
+ifeq ($(CONFIG_PPC64),y)
+ifeq ($(call cc-option-yn,-mcmodel=medium),y)
+ # -mcmodel=medium breaks modules because it uses 32bit offsets from
+ # the TOC pointer to create pointers where possible. Pointers into the
+ # percpu data area are created by this method.
+ #
+ # The kernel module loader relocates the percpu data section from the
+ # original location (starting with 0xd...) to somewhere in the base
+ # kernel percpu data space (starting with 0xc...). We need a full
+ # 64bit relocation for this to work, hence -mcmodel=large.
+ KBUILD_CFLAGS_MODULE += -mcmodel=large
+else
+ export NO_MINIMAL_TOC := -mno-minimal-toc
+endif
+endif
+
+CFLAGS-$(CONFIG_PPC64) := -mtraceback=no -mcall-aixdesc
+CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcmodel=medium,-mminimal-toc)
+CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mno-pointers-to-nested-functions)
CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple
CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=power7,-mtune=power4)
@@ -136,6 +154,7 @@ head-$(CONFIG_FSL_BOOKE) := arch/powerpc/kernel/head_fsl_booke.o
head-$(CONFIG_PPC64) += arch/powerpc/kernel/entry_64.o
head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o
head-$(CONFIG_ALTIVEC) += arch/powerpc/kernel/vector.o
+head-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += arch/powerpc/kernel/prom_init.o
core-y += arch/powerpc/kernel/ \
arch/powerpc/mm/ \
@@ -143,6 +162,7 @@ core-y += arch/powerpc/kernel/ \
arch/powerpc/sysdev/ \
arch/powerpc/platforms/ \
arch/powerpc/math-emu/ \
+ arch/powerpc/crypto/ \
arch/powerpc/net/
core-$(CONFIG_XMON) += arch/powerpc/xmon/
core-$(CONFIG_KVM) += arch/powerpc/kvm/
diff --git a/arch/powerpc/boot/dts/a3m071.dts b/arch/powerpc/boot/dts/a3m071.dts
index 877a28cb77e4..bf81b8f9704c 100644
--- a/arch/powerpc/boot/dts/a3m071.dts
+++ b/arch/powerpc/boot/dts/a3m071.dts
@@ -17,6 +17,8 @@
/include/ "mpc5200b.dtsi"
+&gpt0 { fsl,has-wdt; };
+
/ {
model = "anonymous,a3m071";
compatible = "anonymous,a3m071";
@@ -30,10 +32,6 @@
bus-frequency = <0>; /* From boot loader */
system-frequency = <0>; /* From boot loader */
- timer@600 {
- fsl,has-wdt;
- };
-
spi@f00 {
status = "disabled";
};
diff --git a/arch/powerpc/boot/dts/a4m072.dts b/arch/powerpc/boot/dts/a4m072.dts
index fabe7b7d5f13..1f02034c7e99 100644
--- a/arch/powerpc/boot/dts/a4m072.dts
+++ b/arch/powerpc/boot/dts/a4m072.dts
@@ -15,6 +15,11 @@
/include/ "mpc5200b.dtsi"
+&gpt0 { fsl,has-wdt; };
+&gpt3 { gpio-controller; };
+&gpt4 { gpio-controller; };
+&gpt5 { gpio-controller; };
+
/ {
model = "anonymous,a4m072";
compatible = "anonymous,a4m072";
@@ -34,28 +39,6 @@
fsl,init-fd-counters = <0x3333>;
};
- timer@600 {
- fsl,has-wdt;
- };
-
- gpt3: timer@630 { /* General Purpose Timer in GPIO mode */
- compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt4: timer@640 { /* General Purpose Timer in GPIO mode */
- compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt5: timer@650 { /* General Purpose Timer in GPIO mode */
- compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
spi@f00 {
status = "disabled";
};
diff --git a/arch/powerpc/boot/dts/bluestone.dts b/arch/powerpc/boot/dts/bluestone.dts
index 9d4917aebe6b..7daaca324c01 100644
--- a/arch/powerpc/boot/dts/bluestone.dts
+++ b/arch/powerpc/boot/dts/bluestone.dts
@@ -107,6 +107,14 @@
interrupt-parent = <&UIC0>;
};
+ OCM: ocm@400040000 {
+ compatible = "ibm,ocm";
+ status = "ok";
+ cell-index = <1>;
+ /* configured in U-Boot */
+ reg = <4 0x00040000 0x8000>; /* 32K */
+ };
+
SDR0: sdr {
compatible = "ibm,sdr-apm821xx";
dcr-reg = <0x00e 0x002>;
diff --git a/arch/powerpc/boot/dts/bsc9131rdb.dtsi b/arch/powerpc/boot/dts/bsc9131rdb.dtsi
index 638adda2c218..9e6c01339ccc 100644
--- a/arch/powerpc/boot/dts/bsc9131rdb.dtsi
+++ b/arch/powerpc/boot/dts/bsc9131rdb.dtsi
@@ -126,7 +126,7 @@
};
};
- sdhci@2e000 {
+ sdhc@2e000 {
status = "disabled";
};
diff --git a/arch/powerpc/boot/dts/cm5200.dts b/arch/powerpc/boot/dts/cm5200.dts
index ad3a4f4a2b04..fb580dd84ddf 100644
--- a/arch/powerpc/boot/dts/cm5200.dts
+++ b/arch/powerpc/boot/dts/cm5200.dts
@@ -12,15 +12,13 @@
/include/ "mpc5200b.dtsi"
+&gpt0 { fsl,has-wdt; };
+
/ {
model = "schindler,cm5200";
compatible = "schindler,cm5200";
soc5200@f0000000 {
- timer@600 { // General Purpose Timer
- fsl,has-wdt;
- };
-
can@900 {
status = "disabled";
};
diff --git a/arch/powerpc/boot/dts/digsy_mtc.dts b/arch/powerpc/boot/dts/digsy_mtc.dts
index a7511f2d844d..955bff629df3 100644
--- a/arch/powerpc/boot/dts/digsy_mtc.dts
+++ b/arch/powerpc/boot/dts/digsy_mtc.dts
@@ -13,6 +13,9 @@
/include/ "mpc5200b.dtsi"
+&gpt0 { gpio-controller; fsl,has-wdt; };
+&gpt1 { gpio-controller; };
+
/ {
model = "intercontrol,digsy-mtc";
compatible = "intercontrol,digsy-mtc";
@@ -22,17 +25,6 @@
};
soc5200@f0000000 {
- timer@600 { // General Purpose Timer
- #gpio-cells = <2>;
- fsl,has-wdt;
- gpio-controller;
- };
-
- timer@610 {
- #gpio-cells = <2>;
- gpio-controller;
- };
-
rtc@800 {
status = "disabled";
};
diff --git a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
index 0bde9ee8afaf..af12ead88c5f 100644
--- a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
@@ -41,7 +41,7 @@
/* controller at 0x9000 */
&pci0 {
- compatible = "fsl,p1010-pcie", "fsl,qoriq-pcie-v2.3", "fsl,qoriq-pcie-v2.2";
+ compatible = "fsl,p1010-pcie", "fsl,qoriq-pcie-v2.3";
device_type = "pci";
#size-cells = <2>;
#address-cells = <3>;
@@ -69,7 +69,7 @@
/* controller at 0xa000 */
&pci1 {
- compatible = "fsl,p1010-pcie", "fsl,qoriq-pcie-v2.3", "fsl,qoriq-pcie-v2.2";
+ compatible = "fsl,p1010-pcie", "fsl,qoriq-pcie-v2.3";
device_type = "pci";
#size-cells = <2>;
#address-cells = <3>;
diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
index 06216b8c0af5..e179803a81ef 100644
--- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
@@ -45,7 +45,7 @@
/* controller at 0x9000 */
&pci0 {
- compatible = "fsl,p1022-pcie";
+ compatible = "fsl,mpc8548-pcie";
device_type = "pci";
#size-cells = <2>;
#address-cells = <3>;
@@ -73,7 +73,7 @@
/* controller at 0xa000 */
&pci1 {
- compatible = "fsl,p1022-pcie";
+ compatible = "fsl,mpc8548-pcie";
device_type = "pci";
#size-cells = <2>;
#address-cells = <3>;
@@ -102,7 +102,7 @@
/* controller at 0xb000 */
&pci2 {
- compatible = "fsl,p1022-pcie";
+ compatible = "fsl,mpc8548-pcie";
device_type = "pci";
#size-cells = <2>;
#address-cells = <3>;
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
index 531eab82c6c9..69ac1acd4349 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
@@ -48,6 +48,8 @@
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 15>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x500>; /* PEX1LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -75,6 +77,8 @@
bus-range = <0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 14>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x504>; /* PEX2LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -102,6 +106,8 @@
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 13>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x508>; /* PEX3LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -125,18 +131,21 @@
interrupts = <16 2 1 11>;
#address-cells = <2>;
#size-cells = <2>;
+ fsl,iommu-parent = <&pamu0>;
ranges;
port1 {
#address-cells = <2>;
#size-cells = <2>;
cell-index = <1>;
+ fsl,liodn-reg = <&guts 0x510>; /* RIO1LIODNR */
};
port2 {
#address-cells = <2>;
#size-cells = <2>;
cell-index = <2>;
+ fsl,liodn-reg = <&guts 0x514>; /* RIO2LIODNR */
};
};
@@ -246,10 +255,37 @@
iommu@20000 {
compatible = "fsl,pamu-v1.0", "fsl,pamu";
- reg = <0x20000 0x4000>;
+ reg = <0x20000 0x4000>; /* for compatibility with older PAMU drivers */
+ ranges = <0 0x20000 0x4000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
interrupts = <
24 2 0 0
16 2 1 30>;
+
+ pamu0: pamu@0 {
+ reg = <0 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu1: pamu@1000 {
+ reg = <0x1000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu2: pamu@2000 {
+ reg = <0x2000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu3: pamu@3000 {
+ reg = <0x3000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
};
/include/ "qoriq-mpic.dtsi"
@@ -291,7 +327,17 @@
};
/include/ "qoriq-dma-0.dtsi"
+ dma@100300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x580>; /* DMA1LIODNR */
+ };
+
/include/ "qoriq-dma-1.dtsi"
+ dma@101300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x584>; /* DMA2LIODNR */
+ };
+
/include/ "qoriq-espi-0.dtsi"
spi@110000 {
fsl,espi-num-chipselects = <4>;
@@ -299,6 +345,8 @@
/include/ "qoriq-esdhc-0.dtsi"
sdhc@114000 {
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
sdhci,auto-cmd12;
};
@@ -308,20 +356,37 @@
/include/ "qoriq-duart-1.dtsi"
/include/ "qoriq-gpio-0.dtsi"
/include/ "qoriq-usb2-mph-0.dtsi"
- usb0: usb@210000 {
- compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
- phy_type = "utmi";
- port0;
- };
+ usb0: usb@210000 {
+ compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+ phy_type = "utmi";
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x520>; /* USB1LIODNR */
+ port0;
+ };
/include/ "qoriq-usb2-dr-0.dtsi"
- usb1: usb@211000 {
- compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
- dr_mode = "host";
- phy_type = "utmi";
- };
+ usb1: usb@211000 {
+ compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x524>; /* USB2LIODNR */
+ dr_mode = "host";
+ phy_type = "utmi";
+ };
/include/ "qoriq-sata2-0.dtsi"
+ sata@220000 {
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x550>; /* SATA1LIODNR */
+ };
+
/include/ "qoriq-sata2-1.dtsi"
+ sata@221000 {
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x554>; /* SATA2LIODNR */
+ };
+
/include/ "qoriq-sec4.2-0.dtsi"
+crypto: crypto@300000 {
+ fsl,iommu-parent = <&pamu1>;
+ };
};
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
index af4ebc8009e3..9b5a81a4529c 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
@@ -48,6 +48,8 @@
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 15>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x500>; /* PEX1LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -75,6 +77,8 @@
bus-range = <0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 14>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x504>; /* PEX2LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -102,6 +106,8 @@
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 13>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x508>; /* PEX3LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -152,18 +158,21 @@
interrupts = <16 2 1 11>;
#address-cells = <2>;
#size-cells = <2>;
+ fsl,iommu-parent = <&pamu0>;
ranges;
port1 {
#address-cells = <2>;
#size-cells = <2>;
cell-index = <1>;
+ fsl,liodn-reg = <&guts 0x510>; /* RIO1LIODNR */
};
port2 {
#address-cells = <2>;
#size-cells = <2>;
cell-index = <2>;
+ fsl,liodn-reg = <&guts 0x514>; /* RIO2LIODNR */
};
};
@@ -273,10 +282,37 @@
iommu@20000 {
compatible = "fsl,pamu-v1.0", "fsl,pamu";
- reg = <0x20000 0x4000>;
+ reg = <0x20000 0x4000>; /* for compatibility with older PAMU drivers */
+ ranges = <0 0x20000 0x4000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
interrupts = <
24 2 0 0
16 2 1 30>;
+
+ pamu0: pamu@0 {
+ reg = <0 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu1: pamu@1000 {
+ reg = <0x1000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu2: pamu@2000 {
+ reg = <0x2000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu3: pamu@3000 {
+ reg = <0x3000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
};
/include/ "qoriq-mpic.dtsi"
@@ -318,7 +354,17 @@
};
/include/ "qoriq-dma-0.dtsi"
+ dma@100300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x580>; /* DMA1LIODNR */
+ };
+
/include/ "qoriq-dma-1.dtsi"
+ dma@101300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x584>; /* DMA2LIODNR */
+ };
+
/include/ "qoriq-espi-0.dtsi"
spi@110000 {
fsl,espi-num-chipselects = <4>;
@@ -326,6 +372,8 @@
/include/ "qoriq-esdhc-0.dtsi"
sdhc@114000 {
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
sdhci,auto-cmd12;
};
@@ -335,20 +383,37 @@
/include/ "qoriq-duart-1.dtsi"
/include/ "qoriq-gpio-0.dtsi"
/include/ "qoriq-usb2-mph-0.dtsi"
- usb0: usb@210000 {
- compatible = "fsl-usb2-mph-v1.6", "fsl-usb2-mph";
- phy_type = "utmi";
- port0;
- };
+ usb0: usb@210000 {
+ compatible = "fsl-usb2-mph-v1.6", "fsl-usb2-mph";
+ phy_type = "utmi";
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x520>; /* USB1LIODNR */
+ port0;
+ };
/include/ "qoriq-usb2-dr-0.dtsi"
- usb1: usb@211000 {
- compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
- dr_mode = "host";
- phy_type = "utmi";
- };
+ usb1: usb@211000 {
+ compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x524>; /* USB2LIODNR */
+ dr_mode = "host";
+ phy_type = "utmi";
+ };
/include/ "qoriq-sata2-0.dtsi"
+ sata@220000 {
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x550>; /* SATA1LIODNR */
+ };
+
/include/ "qoriq-sata2-1.dtsi"
+ sata@221000 {
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x554>; /* SATA2LIODNR */
+ };
+
/include/ "qoriq-sec4.2-0.dtsi"
+crypto: crypto@300000 {
+ fsl,iommu-parent = <&pamu1>;
+ };
};
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
index 4f9c9f682ecf..19859ad851eb 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
@@ -41,13 +41,15 @@
/* controller at 0x200000 */
&pci0 {
- compatible = "fsl,p4080-pcie";
+ compatible = "fsl,p4080-pcie", "fsl,qoriq-pcie-v2.1";
device_type = "pci";
#size-cells = <2>;
#address-cells = <3>;
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 15>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x500>; /* PEX1LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -68,13 +70,15 @@
/* controller at 0x201000 */
&pci1 {
- compatible = "fsl,p4080-pcie";
+ compatible = "fsl,p4080-pcie", "fsl,qoriq-pcie-v2.1";
device_type = "pci";
#size-cells = <2>;
#address-cells = <3>;
bus-range = <0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 14>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x504>; /* PEX2LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -95,13 +99,15 @@
/* controller at 0x202000 */
&pci2 {
- compatible = "fsl,p4080-pcie";
+ compatible = "fsl,p4080-pcie", "fsl,qoriq-pcie-v2.1";
device_type = "pci";
#size-cells = <2>;
#address-cells = <3>;
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 13>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x508>; /* PEX3LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -126,18 +132,21 @@
#address-cells = <2>;
#size-cells = <2>;
fsl,srio-rmu-handle = <&rmu>;
+ fsl,iommu-parent = <&pamu0>;
ranges;
port1 {
#address-cells = <2>;
#size-cells = <2>;
cell-index = <1>;
+ fsl,liodn-reg = <&guts 0x510>; /* RIO1LIODNR */
};
port2 {
#address-cells = <2>;
#size-cells = <2>;
cell-index = <2>;
+ fsl,liodn-reg = <&guts 0x514>; /* RIO2LIODNR */
};
};
@@ -281,13 +290,51 @@
iommu@20000 {
compatible = "fsl,pamu-v1.0", "fsl,pamu";
- reg = <0x20000 0x5000>;
+ reg = <0x20000 0x5000>; /* for compatibility with older PAMU drivers */
+ ranges = <0 0x20000 0x5000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
interrupts = <
24 2 0 0
16 2 1 30>;
+
+ pamu0: pamu@0 {
+ reg = <0 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu1: pamu@1000 {
+ reg = <0x1000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu2: pamu@2000 {
+ reg = <0x2000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu3: pamu@3000 {
+ reg = <0x3000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu4: pamu@4000 {
+ reg = <0x4000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
};
/include/ "qoriq-rmu-0.dtsi"
+ rmu@d3000 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x540>; /* RMULIODNR */
+ };
+
/include/ "qoriq-mpic.dtsi"
guts: global-utilities@e0000 {
@@ -327,7 +374,17 @@
};
/include/ "qoriq-dma-0.dtsi"
+ dma@100300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x580>; /* DMA1LIODNR */
+ };
+
/include/ "qoriq-dma-1.dtsi"
+ dma@101300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x584>; /* DMA2LIODNR */
+ };
+
/include/ "qoriq-espi-0.dtsi"
spi@110000 {
fsl,espi-num-chipselects = <4>;
@@ -335,6 +392,8 @@
/include/ "qoriq-esdhc-0.dtsi"
sdhc@114000 {
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
voltage-ranges = <3300 3300>;
sdhci,auto-cmd12;
};
@@ -347,11 +406,18 @@
/include/ "qoriq-usb2-mph-0.dtsi"
usb@210000 {
compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x520>; /* USB1LIODNR */
port0;
};
/include/ "qoriq-usb2-dr-0.dtsi"
usb@211000 {
compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x524>; /* USB2LIODNR */
};
/include/ "qoriq-sec4.0-0.dtsi"
+crypto: crypto@300000 {
+ fsl,iommu-parent = <&pamu1>;
+ };
};
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
index 5d7205b7bb05..9ea77c3513f6 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
@@ -48,6 +48,8 @@
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 15>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x500>; /* PEX1LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -75,6 +77,8 @@
bus-range = <0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 14>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x504>; /* PEX2LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -102,6 +106,8 @@
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 13>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x508>; /* PEX3LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -129,6 +135,8 @@
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 12>;
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x50c>; /* PEX4LIODNR */
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -152,18 +160,21 @@
interrupts = <16 2 1 11>;
#address-cells = <2>;
#size-cells = <2>;
+ fsl,iommu-parent = <&pamu0>;
ranges;
port1 {
#address-cells = <2>;
#size-cells = <2>;
cell-index = <1>;
+ fsl,liodn-reg = <&guts 0x510>; /* RIO1LIODNR */
};
port2 {
#address-cells = <2>;
#size-cells = <2>;
cell-index = <2>;
+ fsl,liodn-reg = <&guts 0x514>; /* RIO2LIODNR */
};
};
@@ -276,10 +287,37 @@
iommu@20000 {
compatible = "fsl,pamu-v1.0", "fsl,pamu";
- reg = <0x20000 0x4000>;
+ reg = <0x20000 0x4000>; /* for compatibility with older PAMU drivers */
+ ranges = <0 0x20000 0x4000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
interrupts = <
24 2 0 0
16 2 1 30>;
+
+ pamu0: pamu@0 {
+ reg = <0 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu1: pamu@1000 {
+ reg = <0x1000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu2: pamu@2000 {
+ reg = <0x2000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu3: pamu@3000 {
+ reg = <0x3000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
};
/include/ "qoriq-mpic.dtsi"
@@ -321,7 +359,17 @@
};
/include/ "qoriq-dma-0.dtsi"
+ dma@100300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x580>; /* DMA1LIODNR */
+ };
+
/include/ "qoriq-dma-1.dtsi"
+ dma@101300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x584>; /* DMA2LIODNR */
+ };
+
/include/ "qoriq-espi-0.dtsi"
spi@110000 {
fsl,espi-num-chipselects = <4>;
@@ -329,6 +377,8 @@
/include/ "qoriq-esdhc-0.dtsi"
sdhc@114000 {
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
sdhci,auto-cmd12;
};
@@ -338,21 +388,41 @@
/include/ "qoriq-duart-1.dtsi"
/include/ "qoriq-gpio-0.dtsi"
/include/ "qoriq-usb2-mph-0.dtsi"
- usb0: usb@210000 {
- compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
- phy_type = "utmi";
- port0;
- };
+ usb0: usb@210000 {
+ compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x520>; /* USB1LIODNR */
+ phy_type = "utmi";
+ port0;
+ };
/include/ "qoriq-usb2-dr-0.dtsi"
- usb1: usb@211000 {
- compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
- dr_mode = "host";
- phy_type = "utmi";
- };
+ usb1: usb@211000 {
+ compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x524>; /* USB2LIODNR */
+ dr_mode = "host";
+ phy_type = "utmi";
+ };
/include/ "qoriq-sata2-0.dtsi"
+ sata@220000 {
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x550>; /* SATA1LIODNR */
+ };
+
/include/ "qoriq-sata2-1.dtsi"
+ sata@221000 {
+ fsl,iommu-parent = <&pamu1>;
+ fsl,liodn-reg = <&guts 0x554>; /* SATA2LIODNR */
+ };
/include/ "qoriq-sec4.2-0.dtsi"
+ crypto@300000 {
+ fsl,iommu-parent = <&pamu1>;
+ };
+
/include/ "qoriq-raid1.0-0.dtsi"
+ raideng@320000 {
+ fsl,iommu-parent = <&pamu1>;
+ };
};
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
index db2c9a7b3a0e..97f8c26f9709 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
@@ -48,6 +48,7 @@
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 15>;
+ fsl,iommu-parent = <&pamu0>;
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -75,6 +76,7 @@
bus-range = <0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 14>;
+ fsl,iommu-parent = <&pamu0>;
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -102,6 +104,7 @@
bus-range = <0x0 0xff>;
clock-frequency = <33333333>;
interrupts = <16 2 1 13>;
+ fsl,iommu-parent = <&pamu0>;
pcie@0 {
reg = <0 0 0 0 0>;
#interrupt-cells = <1>;
@@ -239,10 +242,42 @@
iommu@20000 {
compatible = "fsl,pamu-v1.0", "fsl,pamu";
- reg = <0x20000 0x5000>;
- interrupts = <
- 24 2 0 0
- 16 2 1 30>;
+ reg = <0x20000 0x5000>; /* for compatibility with older PAMU drivers */
+ ranges = <0 0x20000 0x5000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupts = <24 2 0 0
+ 16 2 1 30>;
+
+ pamu0: pamu@0 {
+ reg = <0 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu1: pamu@1000 {
+ reg = <0x1000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu2: pamu@2000 {
+ reg = <0x2000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu3: pamu@3000 {
+ reg = <0x3000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
+
+ pamu4: pamu@4000 {
+ reg = <0x4000 0x1000>;
+ fsl,primary-cache-geometry = <32 1>;
+ fsl,secondary-cache-geometry = <128 2>;
+ };
};
/include/ "qoriq-mpic.dtsi"
@@ -284,7 +319,17 @@
};
/include/ "qoriq-dma-0.dtsi"
+ dma@100300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x580>; /* DMA1LIODNR */
+ };
+
/include/ "qoriq-dma-1.dtsi"
+ dma@101300 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x584>; /* DMA2LIODNR */
+ };
+
/include/ "qoriq-espi-0.dtsi"
spi@110000 {
fsl,espi-num-chipselects = <4>;
@@ -292,6 +337,8 @@
/include/ "qoriq-esdhc-0.dtsi"
sdhc@114000 {
+ fsl,iommu-parent = <&pamu2>;
+ fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
sdhci,auto-cmd12;
};
@@ -301,20 +348,37 @@
/include/ "qoriq-duart-1.dtsi"
/include/ "qoriq-gpio-0.dtsi"
/include/ "qoriq-usb2-mph-0.dtsi"
- usb0: usb@210000 {
- compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
- phy_type = "utmi";
- port0;
- };
+ usb0: usb@210000 {
+ compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+ fsl,iommu-parent = <&pamu4>;
+ fsl,liodn-reg = <&guts 0x520>; /* USB1LIODNR */
+ phy_type = "utmi";
+ port0;
+ };
/include/ "qoriq-usb2-dr-0.dtsi"
- usb1: usb@211000 {
- compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
- dr_mode = "host";
- phy_type = "utmi";
- };
+ usb1: usb@211000 {
+ compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+ fsl,iommu-parent = <&pamu4>;
+ fsl,liodn-reg = <&guts 0x524>; /* USB2LIODNR */
+ dr_mode = "host";
+ phy_type = "utmi";
+ };
/include/ "qoriq-sata2-0.dtsi"
+ sata@220000 {
+ fsl,iommu-parent = <&pamu4>;
+ fsl,liodn-reg = <&guts 0x550>; /* SATA1LIODNR */
+ };
+
/include/ "qoriq-sata2-1.dtsi"
+ sata@221000 {
+ fsl,iommu-parent = <&pamu4>;
+ fsl,liodn-reg = <&guts 0x554>; /* SATA2LIODNR */
+ };
+
/include/ "qoriq-sec5.2-0.dtsi"
+ crypto@300000 {
+ fsl,iommu-parent = <&pamu4>;
+ };
};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi
index d4c9d5daab21..ffadcb563ada 100644
--- a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi
@@ -36,6 +36,7 @@ crypto@30000 {
compatible = "fsl,sec-v4.4", "fsl,sec-v4.0";
#address-cells = <1>;
#size-cells = <1>;
+ ranges = <0x0 0x30000 0x10000>;
reg = <0x30000 0x10000>;
interrupts = <58 2 0 0>;
diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts
index fb288bb882b6..5abb46c5cc95 100644
--- a/arch/powerpc/boot/dts/lite5200b.dts
+++ b/arch/powerpc/boot/dts/lite5200b.dts
@@ -12,19 +12,34 @@
/include/ "mpc5200b.dtsi"
+&gpt0 { fsl,has-wdt; };
+&gpt2 { gpio-controller; };
+&gpt3 { gpio-controller; };
+
/ {
model = "fsl,lite5200b";
compatible = "fsl,lite5200b";
+ leds {
+ compatible = "gpio-leds";
+ tmr2 {
+ gpios = <&gpt2 0 1>;
+ };
+ tmr3 {
+ gpios = <&gpt3 0 1>;
+ linux,default-trigger = "heartbeat";
+ };
+ led1 { gpios = <&gpio_wkup 2 1>; };
+ led2 { gpios = <&gpio_simple 3 1>; };
+ led3 { gpios = <&gpio_wkup 3 1>; };
+ led4 { gpios = <&gpio_simple 2 1>; };
+ };
+
memory {
reg = <0x00000000 0x10000000>; // 256MB
};
soc5200@f0000000 {
- timer@600 { // General Purpose Timer
- fsl,has-wdt;
- };
-
psc@2000 { // PSC1
compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
cell-index = <0>;
diff --git a/arch/powerpc/boot/dts/media5200.dts b/arch/powerpc/boot/dts/media5200.dts
index 48d72f38e5ed..b5413cb85f13 100644
--- a/arch/powerpc/boot/dts/media5200.dts
+++ b/arch/powerpc/boot/dts/media5200.dts
@@ -13,6 +13,8 @@
/include/ "mpc5200b.dtsi"
+&gpt0 { fsl,has-wdt; };
+
/ {
model = "fsl,media5200";
compatible = "fsl,media5200";
@@ -41,10 +43,6 @@
soc5200@f0000000 {
bus-frequency = <132000000>;// 132 MHz
- timer@600 { // General Purpose Timer
- fsl,has-wdt;
- };
-
psc@2000 { // PSC1
status = "disabled";
};
diff --git a/arch/powerpc/boot/dts/motionpro.dts b/arch/powerpc/boot/dts/motionpro.dts
index 0b78e89ac69b..bbabd97492ad 100644
--- a/arch/powerpc/boot/dts/motionpro.dts
+++ b/arch/powerpc/boot/dts/motionpro.dts
@@ -12,26 +12,22 @@
/include/ "mpc5200b.dtsi"
+&gpt0 { fsl,has-wdt; };
+&gpt6 { // Motion-PRO status LED
+ compatible = "promess,motionpro-led";
+ label = "motionpro-statusled";
+ blink-delay = <100>; // 100 msec
+};
+&gpt7 { // Motion-PRO ready LED
+ compatible = "promess,motionpro-led";
+ label = "motionpro-readyled";
+};
+
/ {
model = "promess,motionpro";
compatible = "promess,motionpro";
soc5200@f0000000 {
- timer@600 { // General Purpose Timer
- fsl,has-wdt;
- };
-
- timer@660 { // Motion-PRO status LED
- compatible = "promess,motionpro-led";
- label = "motionpro-statusled";
- blink-delay = <100>; // 100 msec
- };
-
- timer@670 { // Motion-PRO ready LED
- compatible = "promess,motionpro-led";
- label = "motionpro-readyled";
- };
-
can@900 {
status = "disabled";
};
diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
new file mode 100644
index 000000000000..723e292b6b4e
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -0,0 +1,410 @@
+/*
+ * base MPC5121 Device Tree Source
+ *
+ * Copyright 2007-2008 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+
+/ {
+ model = "mpc5121";
+ compatible = "fsl,mpc5121";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&ipic>;
+
+ aliases {
+ ethernet0 = &eth0;
+ pci = &pci;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,5121@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <0x20>; /* 32 bytes */
+ i-cache-line-size = <0x20>; /* 32 bytes */
+ d-cache-size = <0x8000>; /* L1, 32K */
+ i-cache-size = <0x8000>; /* L1, 32K */
+ timebase-frequency = <49500000>;/* 49.5 MHz (csb/4) */
+ bus-frequency = <198000000>; /* 198 MHz csb bus */
+ clock-frequency = <396000000>; /* 396 MHz ppc core */
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>; /* 256MB at 0 */
+ };
+
+ mbx@20000000 {
+ compatible = "fsl,mpc5121-mbx";
+ reg = <0x20000000 0x4000>;
+ interrupts = <66 0x8>;
+ };
+
+ sram@30000000 {
+ compatible = "fsl,mpc5121-sram";
+ reg = <0x30000000 0x20000>; /* 128K at 0x30000000 */
+ };
+
+ nfc@40000000 {
+ compatible = "fsl,mpc5121-nfc";
+ reg = <0x40000000 0x100000>; /* 1M at 0x40000000 */
+ interrupts = <6 8>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
+ localbus@80000020 {
+ compatible = "fsl,mpc5121-localbus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0x80000020 0x40>;
+ interrupts = <7 0x8>;
+ ranges = <0x0 0x0 0xfc000000 0x04000000>;
+ };
+
+ soc@80000000 {
+ compatible = "fsl,mpc5121-immr";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ ranges = <0x0 0x80000000 0x400000>;
+ reg = <0x80000000 0x400000>;
+ bus-frequency = <66000000>; /* 66 MHz ips bus */
+
+
+ /*
+ * IPIC
+ * interrupts cell = <intr #, sense>
+ * sense values match linux IORESOURCE_IRQ_* defines:
+ * sense == 8: Level, low assertion
+ * sense == 2: Edge, high-to-low change
+ */
+ ipic: interrupt-controller@c00 {
+ compatible = "fsl,mpc5121-ipic", "fsl,ipic";
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0xc00 0x100>;
+ };
+
+ /* Watchdog timer */
+ wdt@900 {
+ compatible = "fsl,mpc5121-wdt";
+ reg = <0x900 0x100>;
+ };
+
+ /* Real time clock */
+ rtc@a00 {
+ compatible = "fsl,mpc5121-rtc";
+ reg = <0xa00 0x100>;
+ interrupts = <79 0x8 80 0x8>;
+ };
+
+ /* Reset module */
+ reset@e00 {
+ compatible = "fsl,mpc5121-reset";
+ reg = <0xe00 0x100>;
+ };
+
+ /* Clock control */
+ clock@f00 {
+ compatible = "fsl,mpc5121-clock";
+ reg = <0xf00 0x100>;
+ };
+
+ /* Power Management Controller */
+ pmc@1000{
+ compatible = "fsl,mpc5121-pmc";
+ reg = <0x1000 0x100>;
+ interrupts = <83 0x8>;
+ };
+
+ gpio@1100 {
+ compatible = "fsl,mpc5121-gpio";
+ reg = <0x1100 0x100>;
+ interrupts = <78 0x8>;
+ };
+
+ can@1300 {
+ compatible = "fsl,mpc5121-mscan";
+ reg = <0x1300 0x80>;
+ interrupts = <12 0x8>;
+ };
+
+ can@1380 {
+ compatible = "fsl,mpc5121-mscan";
+ reg = <0x1380 0x80>;
+ interrupts = <13 0x8>;
+ };
+
+ sdhc@1500 {
+ compatible = "fsl,mpc5121-sdhc";
+ reg = <0x1500 0x100>;
+ interrupts = <8 0x8>;
+ };
+
+ i2c@1700 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5121-i2c", "fsl-i2c";
+ reg = <0x1700 0x20>;
+ interrupts = <9 0x8>;
+ };
+
+ i2c@1720 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5121-i2c", "fsl-i2c";
+ reg = <0x1720 0x20>;
+ interrupts = <10 0x8>;
+ };
+
+ i2c@1740 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5121-i2c", "fsl-i2c";
+ reg = <0x1740 0x20>;
+ interrupts = <11 0x8>;
+ };
+
+ i2ccontrol@1760 {
+ compatible = "fsl,mpc5121-i2c-ctrl";
+ reg = <0x1760 0x8>;
+ };
+
+ axe@2000 {
+ compatible = "fsl,mpc5121-axe";
+ reg = <0x2000 0x100>;
+ interrupts = <42 0x8>;
+ };
+
+ display@2100 {
+ compatible = "fsl,mpc5121-diu";
+ reg = <0x2100 0x100>;
+ interrupts = <64 0x8>;
+ };
+
+ can@2300 {
+ compatible = "fsl,mpc5121-mscan";
+ reg = <0x2300 0x80>;
+ interrupts = <90 0x8>;
+ };
+
+ can@2380 {
+ compatible = "fsl,mpc5121-mscan";
+ reg = <0x2380 0x80>;
+ interrupts = <91 0x8>;
+ };
+
+ viu@2400 {
+ compatible = "fsl,mpc5121-viu";
+ reg = <0x2400 0x400>;
+ interrupts = <67 0x8>;
+ };
+
+ mdio@2800 {
+ compatible = "fsl,mpc5121-fec-mdio";
+ reg = <0x2800 0x800>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ eth0: ethernet@2800 {
+ device_type = "network";
+ compatible = "fsl,mpc5121-fec";
+ reg = <0x2800 0x800>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <4 0x8>;
+ };
+
+ /* USB1 using external ULPI PHY */
+ usb@3000 {
+ compatible = "fsl,mpc5121-usb2-dr";
+ reg = <0x3000 0x600>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <43 0x8>;
+ dr_mode = "otg";
+ phy_type = "ulpi";
+ };
+
+ /* USB0 using internal UTMI PHY */
+ usb@4000 {
+ compatible = "fsl,mpc5121-usb2-dr";
+ reg = <0x4000 0x600>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <44 0x8>;
+ dr_mode = "otg";
+ phy_type = "utmi_wide";
+ };
+
+ /* IO control */
+ ioctl@a000 {
+ compatible = "fsl,mpc5121-ioctl";
+ reg = <0xA000 0x1000>;
+ };
+
+ /* LocalPlus controller */
+ lpc@10000 {
+ compatible = "fsl,mpc5121-lpc";
+ reg = <0x10000 0x200>;
+ };
+
+ pata@10200 {
+ compatible = "fsl,mpc5121-pata";
+ reg = <0x10200 0x100>;
+ interrupts = <5 0x8>;
+ };
+
+ /* 512x PSCs are not 52xx PSC compatible */
+
+ /* PSC0 */
+ psc@11000 {
+ compatible = "fsl,mpc5121-psc";
+ reg = <0x11000 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC1 */
+ psc@11100 {
+ compatible = "fsl,mpc5121-psc";
+ reg = <0x11100 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC2 */
+ psc@11200 {
+ compatible = "fsl,mpc5121-psc";
+ reg = <0x11200 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC3 */
+ psc@11300 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ reg = <0x11300 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC4 */
+ psc@11400 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+ reg = <0x11400 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC5 */
+ psc@11500 {
+ compatible = "fsl,mpc5121-psc";
+ reg = <0x11500 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC6 */
+ psc@11600 {
+ compatible = "fsl,mpc5121-psc";
+ reg = <0x11600 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC7 */
+ psc@11700 {
+ compatible = "fsl,mpc5121-psc";
+ reg = <0x11700 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC8 */
+ psc@11800 {
+ compatible = "fsl,mpc5121-psc";
+ reg = <0x11800 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC9 */
+ psc@11900 {
+ compatible = "fsl,mpc5121-psc";
+ reg = <0x11900 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC10 */
+ psc@11a00 {
+ compatible = "fsl,mpc5121-psc";
+ reg = <0x11a00 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ /* PSC11 */
+ psc@11b00 {
+ compatible = "fsl,mpc5121-psc";
+ reg = <0x11b00 0x100>;
+ interrupts = <40 0x8>;
+ fsl,rx-fifo-size = <16>;
+ fsl,tx-fifo-size = <16>;
+ };
+
+ pscfifo@11f00 {
+ compatible = "fsl,mpc5121-psc-fifo";
+ reg = <0x11f00 0x100>;
+ interrupts = <40 0x8>;
+ };
+
+ dma@14000 {
+ compatible = "fsl,mpc5121-dma";
+ reg = <0x14000 0x1800>;
+ interrupts = <65 0x8>;
+ };
+ };
+
+ pci: pci@80008500 {
+ compatible = "fsl,mpc5121-pci";
+ device_type = "pci";
+ interrupts = <1 0x8>;
+ clock-frequency = <0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+
+ reg = <0x80008500 0x100 /* internal registers */
+ 0x80008300 0x8>; /* config space access registers */
+ bus-range = <0x0 0x0>;
+ ranges = <0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
+ 0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000
+ 0x01000000 0x0 0x00000000 0x84000000 0x0 0x01000000>;
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index c9ef6bbe26cf..f269b1382ef7 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -1,7 +1,7 @@
/*
* MPC5121E ADS Device Tree Source
*
- * Copyright 2007,2008 Freescale Semiconductor Inc.
+ * Copyright 2007-2008 Freescale Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -9,74 +9,26 @@
* option) any later version.
*/
-/dts-v1/;
+/include/ "mpc5121.dtsi"
/ {
model = "mpc5121ads";
compatible = "fsl,mpc5121ads";
- #address-cells = <1>;
- #size-cells = <1>;
-
- aliases {
- pci = &pci;
- };
-
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- PowerPC,5121@0 {
- device_type = "cpu";
- reg = <0>;
- d-cache-line-size = <0x20>; // 32 bytes
- i-cache-line-size = <0x20>; // 32 bytes
- d-cache-size = <0x8000>; // L1, 32K
- i-cache-size = <0x8000>; // L1, 32K
- timebase-frequency = <49500000>;// 49.5 MHz (csb/4)
- bus-frequency = <198000000>; // 198 MHz csb bus
- clock-frequency = <396000000>; // 396 MHz ppc core
- };
- };
-
- memory {
- device_type = "memory";
- reg = <0x00000000 0x10000000>; // 256MB at 0
- };
-
- mbx@20000000 {
- compatible = "fsl,mpc5121-mbx";
- reg = <0x20000000 0x4000>;
- interrupts = <66 0x8>;
- interrupt-parent = < &ipic >;
- };
-
- sram@30000000 {
- compatible = "fsl,mpc5121-sram";
- reg = <0x30000000 0x20000>; // 128K at 0x30000000
- };
nfc@40000000 {
- compatible = "fsl,mpc5121-nfc";
- reg = <0x40000000 0x100000>; // 1M at 0x40000000
- interrupts = <6 8>;
- interrupt-parent = < &ipic >;
- #address-cells = <1>;
- #size-cells = <1>;
- // ADS has two Hynix 512MB Nand flash chips in a single
- // stacked package.
+ /*
+ * ADS has two Hynix 512MB Nand flash chips in a single
+ * stacked package.
+ */
chips = <2>;
+
nand@0 {
label = "nand";
- reg = <0x00000000 0x40000000>; // 512MB + 512MB
+ reg = <0x00000000 0x40000000>; /* 512MB + 512MB */
};
};
localbus@80000020 {
- compatible = "fsl,mpc5121-localbus";
- #address-cells = <2>;
- #size-cells = <1>;
- reg = <0x80000020 0x40>;
-
ranges = <0x0 0x0 0xfc000000 0x04000000
0x2 0x0 0x82000000 0x00008000>;
@@ -87,6 +39,7 @@
#size-cells = <1>;
bank-width = <4>;
device-width = <2>;
+
protected@0 {
label = "protected";
reg = <0x00000000 0x00040000>; // first sector is protected
@@ -121,91 +74,18 @@
interrupt-controller;
#interrupt-cells = <2>;
reg = <0x2 0xa 0x5>;
- interrupt-parent = < &ipic >;
- // irq routing
- // all irqs but touch screen are routed to irq0 (ipic 48)
- // touch screen is statically routed to irq1 (ipic 17)
- // so don't use it here
+ /* irq routing:
+ * all irqs but touch screen are routed to irq0 (ipic 48)
+ * touch screen is statically routed to irq1 (ipic 17)
+ * so don't use it here
+ */
interrupts = <48 0x8>;
};
};
soc@80000000 {
- compatible = "fsl,mpc5121-immr";
- #address-cells = <1>;
- #size-cells = <1>;
- #interrupt-cells = <2>;
- ranges = <0x0 0x80000000 0x400000>;
- reg = <0x80000000 0x400000>;
- bus-frequency = <66000000>; // 66 MHz ips bus
-
-
- // IPIC
- // interrupts cell = <intr #, sense>
- // sense values match linux IORESOURCE_IRQ_* defines:
- // sense == 8: Level, low assertion
- // sense == 2: Edge, high-to-low change
- //
- ipic: interrupt-controller@c00 {
- compatible = "fsl,mpc5121-ipic", "fsl,ipic";
- interrupt-controller;
- #address-cells = <0>;
- #interrupt-cells = <2>;
- reg = <0xc00 0x100>;
- };
-
- rtc@a00 { // Real time clock
- compatible = "fsl,mpc5121-rtc";
- reg = <0xa00 0x100>;
- interrupts = <79 0x8 80 0x8>;
- interrupt-parent = < &ipic >;
- };
-
- reset@e00 { // Reset module
- compatible = "fsl,mpc5121-reset";
- reg = <0xe00 0x100>;
- };
-
- clock@f00 { // Clock control
- compatible = "fsl,mpc5121-clock";
- reg = <0xf00 0x100>;
- };
-
- pmc@1000{ //Power Management Controller
- compatible = "fsl,mpc5121-pmc";
- reg = <0x1000 0x100>;
- interrupts = <83 0x2>;
- interrupt-parent = < &ipic >;
- };
-
- gpio@1100 {
- compatible = "fsl,mpc5121-gpio";
- reg = <0x1100 0x100>;
- interrupts = <78 0x8>;
- interrupt-parent = < &ipic >;
- };
-
- can@1300 {
- compatible = "fsl,mpc5121-mscan";
- interrupts = <12 0x8>;
- interrupt-parent = < &ipic >;
- reg = <0x1300 0x80>;
- };
-
- can@1380 {
- compatible = "fsl,mpc5121-mscan";
- interrupts = <13 0x8>;
- interrupt-parent = < &ipic >;
- reg = <0x1380 0x80>;
- };
i2c@1700 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,mpc5121-i2c", "fsl-i2c";
- reg = <0x1700 0x20>;
- interrupts = <9 0x8>;
- interrupt-parent = < &ipic >;
fsl,preserve-clocking;
hwmon@4a {
@@ -224,196 +104,75 @@
};
};
- i2c@1720 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,mpc5121-i2c", "fsl-i2c";
- reg = <0x1720 0x20>;
- interrupts = <10 0x8>;
- interrupt-parent = < &ipic >;
- };
-
- i2c@1740 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,mpc5121-i2c", "fsl-i2c";
- reg = <0x1740 0x20>;
- interrupts = <11 0x8>;
- interrupt-parent = < &ipic >;
+ eth0: ethernet@2800 {
+ phy-handle = <&phy0>;
};
- i2ccontrol@1760 {
- compatible = "fsl,mpc5121-i2c-ctrl";
- reg = <0x1760 0x8>;
+ can@2300 {
+ status = "disabled";
};
- axe@2000 {
- compatible = "fsl,mpc5121-axe";
- reg = <0x2000 0x100>;
- interrupts = <42 0x8>;
- interrupt-parent = < &ipic >;
+ can@2380 {
+ status = "disabled";
};
- display@2100 {
- compatible = "fsl,mpc5121-diu";
- reg = <0x2100 0x100>;
- interrupts = <64 0x8>;
- interrupt-parent = < &ipic >;
+ viu@2400 {
+ status = "disabled";
};
mdio@2800 {
- compatible = "fsl,mpc5121-fec-mdio";
- reg = <0x2800 0x800>;
- #address-cells = <1>;
- #size-cells = <0>;
- phy: ethernet-phy@0 {
+ phy0: ethernet-phy@0 {
reg = <1>;
- device_type = "ethernet-phy";
};
};
- ethernet@2800 {
- device_type = "network";
- compatible = "fsl,mpc5121-fec";
- reg = <0x2800 0x800>;
- local-mac-address = [ 00 00 00 00 00 00 ];
- interrupts = <4 0x8>;
- interrupt-parent = < &ipic >;
- phy-handle = < &phy >;
- fsl,align-tx-packets = <4>;
+ /* mpc5121ads only uses USB0 */
+ usb@3000 {
+ status = "disabled";
};
- // 5121e has two dr usb modules
- // mpc5121_ads only uses USB0
-
- // USB1 using external ULPI PHY
- //usb@3000 {
- // compatible = "fsl,mpc5121-usb2-dr";
- // reg = <0x3000 0x1000>;
- // #address-cells = <1>;
- // #size-cells = <0>;
- // interrupt-parent = < &ipic >;
- // interrupts = <43 0x8>;
- // dr_mode = "otg";
- // phy_type = "ulpi";
- //};
-
- // USB0 using internal UTMI PHY
+ /* USB0 using internal UTMI PHY */
usb@4000 {
- compatible = "fsl,mpc5121-usb2-dr";
- reg = <0x4000 0x1000>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupt-parent = < &ipic >;
- interrupts = <44 0x8>;
- dr_mode = "otg";
- phy_type = "utmi_wide";
+ dr_mode = "host";
fsl,invert-drvvbus;
fsl,invert-pwr-fault;
};
- // IO control
- ioctl@a000 {
- compatible = "fsl,mpc5121-ioctl";
- reg = <0xA000 0x1000>;
- };
-
- pata@10200 {
- compatible = "fsl,mpc5121-pata";
- reg = <0x10200 0x100>;
- interrupts = <5 0x8>;
- interrupt-parent = < &ipic >;
- };
-
- // 512x PSCs are not 52xx PSC compatible
- // PSC3 serial port A aka ttyPSC0
- serial@11300 {
- device_type = "serial";
+ /* PSC3 serial port A aka ttyPSC0 */
+ psc@11300 {
compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
- // Logical port assignment needed until driver
- // learns to use aliases
- port-number = <0>;
- cell-index = <3>;
- reg = <0x11300 0x100>;
- interrupts = <40 0x8>;
- interrupt-parent = < &ipic >;
- rx-fifo-size = <16>;
- tx-fifo-size = <16>;
};
- // PSC4 serial port B aka ttyPSC1
- serial@11400 {
- device_type = "serial";
+ /* PSC4 serial port B aka ttyPSC1 */
+ psc@11400 {
compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
- // Logical port assignment needed until driver
- // learns to use aliases
- port-number = <1>;
- cell-index = <4>;
- reg = <0x11400 0x100>;
- interrupts = <40 0x8>;
- interrupt-parent = < &ipic >;
- rx-fifo-size = <16>;
- tx-fifo-size = <16>;
};
- // PSC5 in ac97 mode
- ac97@11500 {
+ /* PSC5 in ac97 mode */
+ ac97: psc@11500 {
compatible = "fsl,mpc5121-psc-ac97", "fsl,mpc5121-psc";
- cell-index = <5>;
- reg = <0x11500 0x100>;
- interrupts = <40 0x8>;
- interrupt-parent = < &ipic >;
fsl,mode = "ac97-slave";
- rx-fifo-size = <384>;
- tx-fifo-size = <384>;
- };
-
- pscfifo@11f00 {
- compatible = "fsl,mpc5121-psc-fifo";
- reg = <0x11f00 0x100>;
- interrupts = <40 0x8>;
- interrupt-parent = < &ipic >;
+ fsl,rx-fifo-size = <384>;
+ fsl,tx-fifo-size = <384>;
};
-
- dma@14000 {
- compatible = "fsl,mpc5121-dma";
- reg = <0x14000 0x1800>;
- interrupts = <65 0x8>;
- interrupt-parent = < &ipic >;
- };
-
};
pci: pci@80008500 {
interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
interrupt-map = <
- // IDSEL 0x15 - Slot 1 PCI
+ /* IDSEL 0x15 - Slot 1 PCI */
0xa800 0x0 0x0 0x1 &cpld_pic 0x0 0x8
0xa800 0x0 0x0 0x2 &cpld_pic 0x1 0x8
0xa800 0x0 0x0 0x3 &cpld_pic 0x2 0x8
0xa800 0x0 0x0 0x4 &cpld_pic 0x3 0x8
- // IDSEL 0x16 - Slot 2 MiniPCI
+ /* IDSEL 0x16 - Slot 2 MiniPCI */
0xb000 0x0 0x0 0x1 &cpld_pic 0x4 0x8
0xb000 0x0 0x0 0x2 &cpld_pic 0x5 0x8
- // IDSEL 0x17 - Slot 3 MiniPCI
+ /* IDSEL 0x17 - Slot 3 MiniPCI */
0xb800 0x0 0x0 0x1 &cpld_pic 0x6 0x8
0xb800 0x0 0x0 0x2 &cpld_pic 0x7 0x8
>;
- interrupt-parent = < &ipic >;
- interrupts = <1 0x8>;
- bus-range = <0 0>;
- ranges = <0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
- 0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000
- 0x01000000 0x0 0x00000000 0x84000000 0x0 0x01000000>;
- clock-frequency = <0>;
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0x80008500 0x100 /* internal registers */
- 0x80008300 0x8>; /* config space access registers */
- compatible = "fsl,mpc5121-pci";
- device_type = "pci";
};
};
diff --git a/arch/powerpc/boot/dts/mpc5200b.dtsi b/arch/powerpc/boot/dts/mpc5200b.dtsi
index 39ed65a44c5f..969b2200b2f9 100644
--- a/arch/powerpc/boot/dts/mpc5200b.dtsi
+++ b/arch/powerpc/boot/dts/mpc5200b.dtsi
@@ -64,50 +64,59 @@
reg = <0x500 0x80>;
};
- timer@600 { // General Purpose Timer
+ gpt0: timer@600 { // General Purpose Timer
compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ #gpio-cells = <2>; // Add 'gpio-controller;' to enable gpio mode
reg = <0x600 0x10>;
interrupts = <1 9 0>;
+ // add 'fsl,has-wdt' to enable watchdog
};
- timer@610 { // General Purpose Timer
+ gpt1: timer@610 { // General Purpose Timer
compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ #gpio-cells = <2>; // Add 'gpio-controller;' to enable gpio mode
reg = <0x610 0x10>;
interrupts = <1 10 0>;
};
- timer@620 { // General Purpose Timer
+ gpt2: timer@620 { // General Purpose Timer
compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ #gpio-cells = <2>; // Add 'gpio-controller;' to enable gpio mode
reg = <0x620 0x10>;
interrupts = <1 11 0>;
};
- timer@630 { // General Purpose Timer
+ gpt3: timer@630 { // General Purpose Timer
compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ #gpio-cells = <2>; // Add 'gpio-controller;' to enable gpio mode
reg = <0x630 0x10>;
interrupts = <1 12 0>;
};
- timer@640 { // General Purpose Timer
+ gpt4: timer@640 { // General Purpose Timer
compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ #gpio-cells = <2>; // Add 'gpio-controller;' to enable gpio mode
reg = <0x640 0x10>;
interrupts = <1 13 0>;
};
- timer@650 { // General Purpose Timer
+ gpt5: timer@650 { // General Purpose Timer
compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ #gpio-cells = <2>; // Add 'gpio-controller;' to enable gpio mode
reg = <0x650 0x10>;
interrupts = <1 14 0>;
};
- timer@660 { // General Purpose Timer
+ gpt6: timer@660 { // General Purpose Timer
compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ #gpio-cells = <2>; // Add 'gpio-controller;' to enable gpio mode
reg = <0x660 0x10>;
interrupts = <1 15 0>;
};
- timer@670 { // General Purpose Timer
+ gpt7: timer@670 { // General Purpose Timer
compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ #gpio-cells = <2>; // Add 'gpio-controller;' to enable gpio mode
reg = <0x670 0x10>;
interrupts = <1 16 0>;
};
diff --git a/arch/powerpc/boot/dts/mucmc52.dts b/arch/powerpc/boot/dts/mucmc52.dts
index 21d34720fcc9..d3a792bb5c1a 100644
--- a/arch/powerpc/boot/dts/mucmc52.dts
+++ b/arch/powerpc/boot/dts/mucmc52.dts
@@ -13,47 +13,23 @@
/include/ "mpc5200b.dtsi"
+/* Timer pins that need to be in GPIO mode */
+&gpt0 { gpio-controller; };
+&gpt1 { gpio-controller; };
+&gpt2 { gpio-controller; };
+&gpt3 { gpio-controller; };
+
+/* Disabled timers */
+&gpt4 { status = "disabled"; };
+&gpt5 { status = "disabled"; };
+&gpt6 { status = "disabled"; };
+&gpt7 { status = "disabled"; };
+
/ {
model = "manroland,mucmc52";
compatible = "manroland,mucmc52";
soc5200@f0000000 {
- gpt0: timer@600 { // GPT 0 in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt1: timer@610 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt2: timer@620 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt3: timer@630 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- timer@640 {
- status = "disabled";
- };
-
- timer@650 {
- status = "disabled";
- };
-
- timer@660 {
- status = "disabled";
- };
-
- timer@670 {
- status = "disabled";
- };
-
rtc@800 {
status = "disabled";
};
diff --git a/arch/powerpc/boot/dts/o2d.dtsi b/arch/powerpc/boot/dts/o2d.dtsi
index 24f668039295..cf073e693f24 100644
--- a/arch/powerpc/boot/dts/o2d.dtsi
+++ b/arch/powerpc/boot/dts/o2d.dtsi
@@ -12,6 +12,13 @@
/include/ "mpc5200b.dtsi"
+&gpt0 {
+ gpio-controller;
+ fsl,has-wdt;
+ fsl,wdt-on-boot = <0>;
+};
+&gpt1 { gpio-controller; };
+
/ {
model = "ifm,o2d";
compatible = "ifm,o2d";
@@ -22,24 +29,6 @@
soc5200@f0000000 {
- gpio_simple: gpio@b00 {
- };
-
- timer@600 { // General Purpose Timer
- #gpio-cells = <2>;
- gpio-controller;
- fsl,has-wdt;
- fsl,wdt-on-boot = <0>;
- };
-
- timer@610 {
- #gpio-cells = <2>;
- gpio-controller;
- };
-
- timer7: timer@670 {
- };
-
rtc@800 {
status = "disabled";
};
@@ -118,7 +107,7 @@
csi@3,0 {
compatible = "ifm,o2d-csi";
reg = <3 0 0x00100000>;
- ifm,csi-clk-handle = <&timer7>;
+ ifm,csi-clk-handle = <&gpt7>;
gpios = <&gpio_simple 23 0 /* imag_capture */
&gpio_simple 26 0 /* imag_reset */
&gpio_simple 29 0>; /* imag_master_en */
diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts
index 96512c058033..192e66af0001 100644
--- a/arch/powerpc/boot/dts/pcm030.dts
+++ b/arch/powerpc/boot/dts/pcm030.dts
@@ -14,51 +14,19 @@
/include/ "mpc5200b.dtsi"
+&gpt0 { fsl,has-wdt; };
+&gpt2 { gpio-controller; };
+&gpt3 { gpio-controller; };
+&gpt4 { gpio-controller; };
+&gpt5 { gpio-controller; };
+&gpt6 { gpio-controller; };
+&gpt7 { gpio-controller; };
+
/ {
model = "phytec,pcm030";
compatible = "phytec,pcm030";
soc5200@f0000000 {
- timer@600 { // General Purpose Timer
- fsl,has-wdt;
- };
-
- gpt2: timer@620 { // General Purpose Timer in GPIO mode
- compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt3: timer@630 { // General Purpose Timer in GPIO mode
- compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt4: timer@640 { // General Purpose Timer in GPIO mode
- compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt5: timer@650 { // General Purpose Timer in GPIO mode
- compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt6: timer@660 { // General Purpose Timer in GPIO mode
- compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt7: timer@670 { // General Purpose Timer in GPIO mode
- compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
- gpio-controller;
- #gpio-cells = <2>;
- };
-
audioplatform: psc@2000 { /* PSC1 in ac97 mode */
compatible = "mpc5200b-psc-ac97","fsl,mpc5200b-psc-ac97";
cell-index = <0>;
diff --git a/arch/powerpc/boot/dts/pcm032.dts b/arch/powerpc/boot/dts/pcm032.dts
index 1dd478bfff96..96b139bf50e9 100644
--- a/arch/powerpc/boot/dts/pcm032.dts
+++ b/arch/powerpc/boot/dts/pcm032.dts
@@ -14,6 +14,14 @@
/include/ "mpc5200b.dtsi"
+&gpt0 { fsl,has-wdt; };
+&gpt2 { gpio-controller; };
+&gpt3 { gpio-controller; };
+&gpt4 { gpio-controller; };
+&gpt5 { gpio-controller; };
+&gpt6 { gpio-controller; };
+&gpt7 { gpio-controller; };
+
/ {
model = "phytec,pcm032";
compatible = "phytec,pcm032";
@@ -23,43 +31,6 @@
};
soc5200@f0000000 {
- timer@600 { // General Purpose Timer
- fsl,has-wdt;
- };
-
- gpt2: timer@620 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt3: timer@630 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt4: timer@640 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt5: timer@650 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt6: timer@660 { // General Purpose Timer in GPIO mode
- compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
- reg = <0x660 0x10>;
- interrupts = <1 15 0>;
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt7: timer@670 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
psc@2000 { /* PSC1 is ac97 */
compatible = "fsl,mpc5200b-psc-ac97","fsl,mpc5200-psc-ac97";
cell-index = <0>;
diff --git a/arch/powerpc/boot/dts/pdm360ng.dts b/arch/powerpc/boot/dts/pdm360ng.dts
index 94dfa5c9a7f9..0b069477838a 100644
--- a/arch/powerpc/boot/dts/pdm360ng.dts
+++ b/arch/powerpc/boot/dts/pdm360ng.dts
@@ -13,7 +13,7 @@
* option) any later version.
*/
-/dts-v1/;
+/include/ "mpc5121.dtsi"
/ {
model = "pdm360ng";
@@ -22,38 +22,12 @@
#size-cells = <1>;
interrupt-parent = <&ipic>;
- aliases {
- ethernet0 = &eth0;
- };
-
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- PowerPC,5121@0 {
- device_type = "cpu";
- reg = <0>;
- d-cache-line-size = <0x20>; // 32 bytes
- i-cache-line-size = <0x20>; // 32 bytes
- d-cache-size = <0x8000>; // L1, 32K
- i-cache-size = <0x8000>; // L1, 32K
- timebase-frequency = <49500000>;// 49.5 MHz (csb/4)
- bus-frequency = <198000000>; // 198 MHz csb bus
- clock-frequency = <396000000>; // 396 MHz ppc core
- };
- };
-
memory {
device_type = "memory";
reg = <0x00000000 0x20000000>; // 512MB at 0
};
nfc@40000000 {
- compatible = "fsl,mpc5121-nfc";
- reg = <0x40000000 0x100000>;
- interrupts = <0x6 0x8>;
- #address-cells = <0x1>;
- #size-cells = <0x1>;
bank-width = <0x1>;
chips = <0x1>;
@@ -63,17 +37,7 @@
};
};
- sram@50000000 {
- compatible = "fsl,mpc5121-sram";
- reg = <0x50000000 0x20000>; // 128K at 0x50000000
- };
-
localbus@80000020 {
- compatible = "fsl,mpc5121-localbus";
- #address-cells = <2>;
- #size-cells = <1>;
- reg = <0x80000020 0x40>;
-
ranges = <0x0 0x0 0xf0000000 0x10000000 /* Flash */
0x2 0x0 0x50040000 0x00020000>; /* CS2: MRAM */
@@ -129,74 +93,8 @@
};
soc@80000000 {
- compatible = "fsl,mpc5121-immr";
- #address-cells = <1>;
- #size-cells = <1>;
- #interrupt-cells = <2>;
- ranges = <0x0 0x80000000 0x400000>;
- reg = <0x80000000 0x400000>;
- bus-frequency = <66000000>; // 66 MHz ips bus
-
- // IPIC
- // interrupts cell = <intr #, sense>
- // sense values match linux IORESOURCE_IRQ_* defines:
- // sense == 8: Level, low assertion
- // sense == 2: Edge, high-to-low change
- //
- ipic: interrupt-controller@c00 {
- compatible = "fsl,mpc5121-ipic", "fsl,ipic";
- interrupt-controller;
- #address-cells = <0>;
- #interrupt-cells = <2>;
- reg = <0xc00 0x100>;
- };
-
- rtc@a00 { // Real time clock
- compatible = "fsl,mpc5121-rtc";
- reg = <0xa00 0x100>;
- interrupts = <79 0x8 80 0x8>;
- };
-
- reset@e00 { // Reset module
- compatible = "fsl,mpc5121-reset";
- reg = <0xe00 0x100>;
- };
-
- clock@f00 { // Clock control
- compatible = "fsl,mpc5121-clock";
- reg = <0xf00 0x100>;
- };
-
- pmc@1000{ //Power Management Controller
- compatible = "fsl,mpc5121-pmc";
- reg = <0x1000 0x100>;
- interrupts = <83 0x2>;
- };
-
- gpio@1100 {
- compatible = "fsl,mpc5121-gpio";
- reg = <0x1100 0x100>;
- interrupts = <78 0x8>;
- };
-
- can@1300 {
- compatible = "fsl,mpc5121-mscan";
- interrupts = <12 0x8>;
- reg = <0x1300 0x80>;
- };
-
- can@1380 {
- compatible = "fsl,mpc5121-mscan";
- interrupts = <13 0x8>;
- reg = <0x1380 0x80>;
- };
i2c@1700 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,mpc5121-i2c";
- reg = <0x1700 0x20>;
- interrupts = <0x9 0x8>;
fsl,preserve-clocking;
eeprom@50 {
@@ -210,201 +108,92 @@
};
};
- i2c@1740 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,mpc5121-i2c";
- reg = <0x1740 0x20>;
- interrupts = <0xb 0x8>;
- fsl,preserve-clocking;
- };
-
- i2ccontrol@1760 {
- compatible = "fsl,mpc5121-i2c-ctrl";
- reg = <0x1760 0x8>;
- };
-
- axe@2000 {
- compatible = "fsl,mpc5121-axe";
- reg = <0x2000 0x100>;
- interrupts = <42 0x8>;
- };
-
- display@2100 {
- compatible = "fsl,mpc5121-diu";
- reg = <0x2100 0x100>;
- interrupts = <64 0x8>;
+ i2c@1720 {
+ status = "disabled";
};
- can@2300 {
- compatible = "fsl,mpc5121-mscan";
- interrupts = <90 0x8>;
- reg = <0x2300 0x80>;
- };
-
- can@2380 {
- compatible = "fsl,mpc5121-mscan";
- interrupts = <91 0x8>;
- reg = <0x2380 0x80>;
+ i2c@1740 {
+ fsl,preserve-clocking;
};
- viu@2400 {
- compatible = "fsl,mpc5121-viu";
- reg = <0x2400 0x400>;
- interrupts = <67 0x8>;
+ ethernet@2800 {
+ phy-handle = <&phy0>;
};
mdio@2800 {
- compatible = "fsl,mpc5121-fec-mdio";
- reg = <0x2800 0x200>;
- #address-cells = <1>;
- #size-cells = <0>;
- phy: ethernet-phy@0 {
+ phy0: ethernet-phy@1f {
compatible = "smsc,lan8700";
reg = <0x1f>;
};
};
- eth0: ethernet@2800 {
- compatible = "fsl,mpc5121-fec";
- reg = <0x2800 0x200>;
- local-mac-address = [ 00 00 00 00 00 00 ];
- interrupts = <4 0x8>;
- phy-handle = < &phy >;
- };
-
- // USB1 using external ULPI PHY
+ /* USB1 using external ULPI PHY */
usb@3000 {
- compatible = "fsl,mpc5121-usb2-dr";
- reg = <0x3000 0x600>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <43 0x8>;
dr_mode = "host";
- phy_type = "ulpi";
};
- // USB0 using internal UTMI PHY
+ /* USB0 using internal UTMI PHY */
usb@4000 {
- compatible = "fsl,mpc5121-usb2-dr";
- reg = <0x4000 0x600>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <44 0x8>;
- dr_mode = "otg";
- phy_type = "utmi_wide";
fsl,invert-pwr-fault;
};
- // IO control
- ioctl@a000 {
- compatible = "fsl,mpc5121-ioctl";
- reg = <0xA000 0x1000>;
- };
-
- // 512x PSCs are not 52xx PSCs compatible
- serial@11000 {
+ psc@11000 {
compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
- cell-index = <0>;
- reg = <0x11000 0x100>;
- interrupts = <40 0x8>;
- fsl,rx-fifo-size = <16>;
- fsl,tx-fifo-size = <16>;
};
- serial@11100 {
+ psc@11100 {
compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
- cell-index = <1>;
- reg = <0x11100 0x100>;
- interrupts = <40 0x8>;
- fsl,rx-fifo-size = <16>;
- fsl,tx-fifo-size = <16>;
};
- serial@11200 {
+ psc@11200 {
compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
- cell-index = <2>;
- reg = <0x11200 0x100>;
- interrupts = <40 0x8>;
- fsl,rx-fifo-size = <16>;
- fsl,tx-fifo-size = <16>;
};
- serial@11300 {
+ psc@11300 {
compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
- cell-index = <3>;
- reg = <0x11300 0x100>;
- interrupts = <40 0x8>;
- fsl,rx-fifo-size = <16>;
- fsl,tx-fifo-size = <16>;
};
- serial@11400 {
+ psc@11400 {
compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
- cell-index = <4>;
- reg = <0x11400 0x100>;
- interrupts = <40 0x8>;
- fsl,rx-fifo-size = <16>;
- fsl,tx-fifo-size = <16>;
};
- serial@11600 {
- compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
- cell-index = <6>;
- reg = <0x11600 0x100>;
- interrupts = <40 0x8>;
- fsl,rx-fifo-size = <16>;
- fsl,tx-fifo-size = <16>;
+ psc@11500 {
+ status = "disabled";
};
- serial@11800 {
+ psc@11600 {
compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
- cell-index = <8>;
- reg = <0x11800 0x100>;
- interrupts = <40 0x8>;
- fsl,rx-fifo-size = <16>;
- fsl,tx-fifo-size = <16>;
};
- serial@11B00 {
- compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
- cell-index = <11>;
- reg = <0x11B00 0x100>;
- interrupts = <40 0x8>;
- fsl,rx-fifo-size = <16>;
- fsl,tx-fifo-size = <16>;
+ psc@11700 {
+ status = "disabled";
};
- pscfifo@11f00 {
- compatible = "fsl,mpc5121-psc-fifo";
- reg = <0x11f00 0x100>;
- interrupts = <40 0x8>;
+ psc@11800 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
};
- spi@11900 {
+ psc@11900 {
compatible = "fsl,mpc5121-psc-spi", "fsl,mpc5121-psc";
- cell-index = <9>;
#address-cells = <1>;
#size-cells = <0>;
- reg = <0x11900 0x100>;
- interrupts = <40 0x8>;
- fsl,rx-fifo-size = <16>;
- fsl,tx-fifo-size = <16>;
- // 7845 touch screen controller
+ /* ADS7845 touch screen controller */
ts@0 {
compatible = "ti,ads7846";
reg = <0x0>;
spi-max-frequency = <3000000>;
- // pen irq is GPIO25
+ /* pen irq is GPIO25 */
interrupts = <78 0x8>;
};
};
- dma@14000 {
- compatible = "fsl,mpc5121-dma";
- reg = <0x14000 0x1800>;
- interrupts = <65 0x8>;
+ psc@11a00 {
+ status = "disabled";
+ };
+
+ psc@11b00 {
+ compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
};
};
};
diff --git a/arch/powerpc/boot/dts/ppa8548.dts b/arch/powerpc/boot/dts/ppa8548.dts
new file mode 100644
index 000000000000..f97eceed610a
--- /dev/null
+++ b/arch/powerpc/boot/dts/ppa8548.dts
@@ -0,0 +1,166 @@
+/*
+ * PPA8548 Device Tree Source (36-bit address map)
+ * Copyright 2013 Prodrive B.V.
+ *
+ * Based on:
+ * MPC8548 CDS Device Tree Source (36-bit address map)
+ * Copyright 2012 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/ "fsl/mpc8548si-pre.dtsi"
+
+/ {
+ model = "ppa8548";
+ compatible = "ppa8548";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&mpic>;
+
+ memory {
+ device_type = "memory";
+ reg = <0 0 0x0 0x40000000>;
+ };
+
+ lbc: localbus@fe0005000 {
+ reg = <0xf 0xe0005000 0 0x1000>;
+ ranges = <0x0 0x0 0xf 0xff800000 0x00800000>;
+ };
+
+ soc: soc8548@fe0000000 {
+ ranges = <0 0xf 0xe0000000 0x100000>;
+ };
+
+ pci0: pci@fe0008000 {
+ /* ppa8548 board doesn't support PCI */
+ status = "disabled";
+ };
+
+ pci1: pci@fe0009000 {
+ /* ppa8548 board doesn't support PCI */
+ status = "disabled";
+ };
+
+ pci2: pcie@fe000a000 {
+ /* ppa8548 board doesn't support PCI */
+ status = "disabled";
+ };
+
+ rio: rapidio@fe00c0000 {
+ reg = <0xf 0xe00c0000 0x0 0x11000>;
+ port1 {
+ ranges = <0x0 0x0 0x0 0x80000000 0x0 0x40000000>;
+ };
+ };
+};
+
+&lbc {
+ nor@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x00800000>;
+ bank-width = <2>;
+ device-width = <2>;
+
+ partition@0 {
+ reg = <0x0 0x7A0000>;
+ label = "user";
+ };
+
+ partition@7A0000 {
+ reg = <0x7A0000 0x20000>;
+ label = "env";
+ read-only;
+ };
+
+ partition@7C0000 {
+ reg = <0x7C0000 0x40000>;
+ label = "u-boot";
+ read-only;
+ };
+ };
+};
+
+&soc {
+ i2c@3000 {
+ rtc@6f {
+ compatible = "intersil,isl1208";
+ reg = <0x6f>;
+ };
+ };
+
+ i2c@3100 {
+ };
+
+ /*
+ * Only ethernet controller @25000 and @26000 are used.
+ * Use alias enet2 and enet3 for the remainig controllers,
+ * to stay compatible with mpc8548si-pre.dtsi.
+ */
+ enet2: ethernet@24000 {
+ status = "disabled";
+ };
+
+ mdio@24520 {
+ phy0: ethernet-phy@0 {
+ interrupts = <7 1 0 0>;
+ reg = <0x0>;
+ device_type = "ethernet-phy";
+ };
+ phy1: ethernet-phy@1 {
+ interrupts = <8 1 0 0>;
+ reg = <0x1>;
+ device_type = "ethernet-phy";
+ };
+ tbi0: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ enet0: ethernet@25000 {
+ tbi-handle = <&tbi1>;
+ phy-handle = <&phy0>;
+ };
+
+ mdio@25520 {
+ tbi1: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ enet1: ethernet@26000 {
+ tbi-handle = <&tbi2>;
+ phy-handle = <&phy1>;
+ };
+
+ mdio@26520 {
+ tbi2: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ enet3: ethernet@27000 {
+ status = "disabled";
+ };
+
+ mdio@27520 {
+ tbi3: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ crypto@30000 {
+ status = "disabled";
+ };
+};
+
+/include/ "fsl/mpc8548si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/sbc8548-altflash.dts b/arch/powerpc/boot/dts/sbc8548-altflash.dts
new file mode 100644
index 000000000000..0b38a0defd2c
--- /dev/null
+++ b/arch/powerpc/boot/dts/sbc8548-altflash.dts
@@ -0,0 +1,115 @@
+/*
+ * SBC8548 Device Tree Source
+ *
+ * Configured for booting off the alternate (64MB SODIMM) flash.
+ * Requires switching JP12 jumpers and changing SW2.8 setting.
+ *
+ * Copyright 2013 Wind River Systems Inc.
+ *
+ * Paul Gortmaker (see MAINTAINERS for contact information)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+
+/dts-v1/;
+
+/include/ "sbc8548-pre.dtsi"
+
+/{
+ localbus@e0000000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ reg = <0xe0000000 0x5000>;
+ interrupt-parent = <&mpic>;
+
+ ranges = <0x0 0x0 0xfc000000 0x04000000 /*64MB Flash*/
+ 0x3 0x0 0xf0000000 0x04000000 /*64MB SDRAM*/
+ 0x4 0x0 0xf4000000 0x04000000 /*64MB SDRAM*/
+ 0x5 0x0 0xf8000000 0x00b10000 /* EPLD */
+ 0x6 0x0 0xef800000 0x00800000>; /*8MB Flash*/
+
+ flash@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x0 0x0 0x04000000>;
+ compatible = "intel,JS28F128", "cfi-flash";
+ bank-width = <4>;
+ device-width = <1>;
+ partition@0x0 {
+ label = "space";
+ /* FC000000 -> FFEFFFFF */
+ reg = <0x00000000 0x03f00000>;
+ };
+ partition@0x03f00000 {
+ label = "bootloader";
+ /* FFF00000 -> FFFFFFFF */
+ reg = <0x03f00000 0x00100000>;
+ read-only;
+ };
+ };
+
+
+ epld@5,0 {
+ compatible = "wrs,epld-localbus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0x5 0x0 0x00b10000>;
+ ranges = <
+ 0x0 0x0 0x5 0x000000 0x1fff /* LED */
+ 0x1 0x0 0x5 0x100000 0x1fff /* Switches */
+ 0x3 0x0 0x5 0x300000 0x1fff /* HW Rev. */
+ 0xb 0x0 0x5 0xb00000 0x1fff /* EEPROM */
+ >;
+
+ led@0,0 {
+ compatible = "led";
+ reg = <0x0 0x0 0x1fff>;
+ };
+
+ switches@1,0 {
+ compatible = "switches";
+ reg = <0x1 0x0 0x1fff>;
+ };
+
+ hw-rev@3,0 {
+ compatible = "hw-rev";
+ reg = <0x3 0x0 0x1fff>;
+ };
+
+ eeprom@b,0 {
+ compatible = "eeprom";
+ reg = <0xb 0 0x1fff>;
+ };
+
+ };
+
+ alt-flash@6,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "intel,JS28F640", "cfi-flash";
+ reg = <0x6 0x0 0x800000>;
+ bank-width = <1>;
+ device-width = <1>;
+ partition@0x0 {
+ label = "space";
+ /* EF800000 -> EFF9FFFF */
+ reg = <0x00000000 0x007a0000>;
+ };
+ partition@0x7a0000 {
+ label = "bootloader";
+ /* EFFA0000 -> EFFFFFFF */
+ reg = <0x007a0000 0x00060000>;
+ read-only;
+ };
+ };
+
+
+ };
+};
+
+/include/ "sbc8548-post.dtsi"
diff --git a/arch/powerpc/boot/dts/sbc8548-post.dtsi b/arch/powerpc/boot/dts/sbc8548-post.dtsi
new file mode 100644
index 000000000000..33a47e27a11e
--- /dev/null
+++ b/arch/powerpc/boot/dts/sbc8548-post.dtsi
@@ -0,0 +1,295 @@
+/*
+ * SBC8548 Device Tree Source
+ *
+ * Copyright 2007 Wind River Systems Inc.
+ *
+ * Paul Gortmaker (see MAINTAINERS for contact information)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/{
+ soc8548@e0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ ranges = <0x00000000 0xe0000000 0x00100000>;
+ bus-frequency = <0>;
+ compatible = "simple-bus";
+
+ ecm-law@0 {
+ compatible = "fsl,ecm-law";
+ reg = <0x0 0x1000>;
+ fsl,num-laws = <10>;
+ };
+
+ ecm@1000 {
+ compatible = "fsl,mpc8548-ecm", "fsl,ecm";
+ reg = <0x1000 0x1000>;
+ interrupts = <17 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ memory-controller@2000 {
+ compatible = "fsl,mpc8548-memory-controller";
+ reg = <0x2000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <0x12 0x2>;
+ };
+
+ L2: l2-cache-controller@20000 {
+ compatible = "fsl,mpc8548-l2-cache-controller";
+ reg = <0x20000 0x1000>;
+ cache-line-size = <0x20>; // 32 bytes
+ cache-size = <0x80000>; // L2, 512K
+ interrupt-parent = <&mpic>;
+ interrupts = <0x10 0x2>;
+ };
+
+ i2c@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ compatible = "fsl-i2c";
+ reg = <0x3000 0x100>;
+ interrupts = <0x2b 0x2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+ i2c@3100 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <1>;
+ compatible = "fsl-i2c";
+ reg = <0x3100 0x100>;
+ interrupts = <0x2b 0x2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+ dma@21300 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8548-dma", "fsl,eloplus-dma";
+ reg = <0x21300 0x4>;
+ ranges = <0x0 0x21100 0x200>;
+ cell-index = <0>;
+ dma-channel@0 {
+ compatible = "fsl,mpc8548-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x0 0x80>;
+ cell-index = <0>;
+ interrupt-parent = <&mpic>;
+ interrupts = <20 2>;
+ };
+ dma-channel@80 {
+ compatible = "fsl,mpc8548-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <21 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,mpc8548-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupt-parent = <&mpic>;
+ interrupts = <22 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,mpc8548-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupt-parent = <&mpic>;
+ interrupts = <23 2>;
+ };
+ };
+
+ enet0: ethernet@24000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <0>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "gianfar";
+ reg = <0x24000 0x1000>;
+ ranges = <0x0 0x24000 0x1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
+ interrupt-parent = <&mpic>;
+ tbi-handle = <&tbi0>;
+ phy-handle = <&phy0>;
+
+ mdio@520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-mdio";
+ reg = <0x520 0x20>;
+
+ phy0: ethernet-phy@19 {
+ interrupt-parent = <&mpic>;
+ interrupts = <0x6 0x1>;
+ reg = <0x19>;
+ device_type = "ethernet-phy";
+ };
+ phy1: ethernet-phy@1a {
+ interrupt-parent = <&mpic>;
+ interrupts = <0x7 0x1>;
+ reg = <0x1a>;
+ device_type = "ethernet-phy";
+ };
+ tbi0: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+ };
+
+ enet1: ethernet@25000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <1>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "gianfar";
+ reg = <0x25000 0x1000>;
+ ranges = <0x0 0x25000 0x1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>;
+ interrupt-parent = <&mpic>;
+ tbi-handle = <&tbi1>;
+ phy-handle = <&phy1>;
+
+ mdio@520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-tbi";
+ reg = <0x520 0x20>;
+
+ tbi1: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+ };
+
+ serial0: serial@4500 {
+ cell-index = <0>;
+ device_type = "serial";
+ compatible = "fsl,ns16550", "ns16550";
+ reg = <0x4500 0x100>; // reg base, size
+ clock-frequency = <0>; // should we fill in in uboot?
+ interrupts = <0x2a 0x2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ serial1: serial@4600 {
+ cell-index = <1>;
+ device_type = "serial";
+ compatible = "fsl,ns16550", "ns16550";
+ reg = <0x4600 0x100>; // reg base, size
+ clock-frequency = <0>; // should we fill in in uboot?
+ interrupts = <0x2a 0x2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ global-utilities@e0000 { //global utilities reg
+ compatible = "fsl,mpc8548-guts";
+ reg = <0xe0000 0x1000>;
+ fsl,has-rstcr;
+ };
+
+ crypto@30000 {
+ compatible = "fsl,sec2.1", "fsl,sec2.0";
+ reg = <0x30000 0x10000>;
+ interrupts = <45 2>;
+ interrupt-parent = <&mpic>;
+ fsl,num-channels = <4>;
+ fsl,channel-fifo-len = <24>;
+ fsl,exec-units-mask = <0xfe>;
+ fsl,descriptor-types-mask = <0x12b0ebf>;
+ };
+
+ mpic: pic@40000 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0x40000 0x40000>;
+ compatible = "chrp,open-pic";
+ device_type = "open-pic";
+ };
+ };
+
+ pci0: pci@e0008000 {
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x01 (PCI-X slot) @66MHz */
+ 0x0800 0x0 0x0 0x1 &mpic 0x2 0x1
+ 0x0800 0x0 0x0 0x2 &mpic 0x3 0x1
+ 0x0800 0x0 0x0 0x3 &mpic 0x4 0x1
+ 0x0800 0x0 0x0 0x4 &mpic 0x1 0x1
+
+ /* IDSEL 0x11 (PCI, 3.3V 32bit) @33MHz */
+ 0x8800 0x0 0x0 0x1 &mpic 0x2 0x1
+ 0x8800 0x0 0x0 0x2 &mpic 0x3 0x1
+ 0x8800 0x0 0x0 0x3 &mpic 0x4 0x1
+ 0x8800 0x0 0x0 0x4 &mpic 0x1 0x1>;
+
+ interrupt-parent = <&mpic>;
+ interrupts = <0x18 0x2>;
+ bus-range = <0 0>;
+ ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x10000000
+ 0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00800000>;
+ clock-frequency = <66000000>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0xe0008000 0x1000>;
+ compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci";
+ device_type = "pci";
+ };
+
+ pci1: pcie@e000a000 {
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+
+ /* IDSEL 0x0 (PEX) */
+ 0x0000 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0x0000 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0x0000 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0x0000 0x0 0x0 0x4 &mpic 0x3 0x1>;
+
+ interrupt-parent = <&mpic>;
+ interrupts = <0x1a 0x2>;
+ bus-range = <0x0 0xff>;
+ ranges = <0x02000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
+ 0x01000000 0x0 0x00000000 0xe2800000 0x0 0x08000000>;
+ clock-frequency = <33000000>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0xe000a000 0x1000>;
+ compatible = "fsl,mpc8548-pcie";
+ device_type = "pci";
+ pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ ranges = <0x02000000 0x0 0xa0000000
+ 0x02000000 0x0 0xa0000000
+ 0x0 0x10000000
+
+ 0x01000000 0x0 0x00000000
+ 0x01000000 0x0 0x00000000
+ 0x0 0x00800000>;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/sbc8548-pre.dtsi b/arch/powerpc/boot/dts/sbc8548-pre.dtsi
new file mode 100644
index 000000000000..d8c66290c5b4
--- /dev/null
+++ b/arch/powerpc/boot/dts/sbc8548-pre.dtsi
@@ -0,0 +1,52 @@
+/*
+ * SBC8548 Device Tree Source
+ *
+ * Copyright 2007 Wind River Systems Inc.
+ *
+ * Paul Gortmaker (see MAINTAINERS for contact information)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/{
+ model = "SBC8548";
+ compatible = "SBC8548";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ ethernet0 = &enet0;
+ ethernet1 = &enet1;
+ serial0 = &serial0;
+ serial1 = &serial1;
+ pci0 = &pci0;
+ pci1 = &pci1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,8548@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <0x20>; // 32 bytes
+ i-cache-line-size = <0x20>; // 32 bytes
+ d-cache-size = <0x8000>; // L1, 32K
+ i-cache-size = <0x8000>; // L1, 32K
+ timebase-frequency = <0>; // From uboot
+ bus-frequency = <0>;
+ clock-frequency = <0>;
+ next-level-cache = <&L2>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>;
+ };
+
+};
diff --git a/arch/powerpc/boot/dts/sbc8548.dts b/arch/powerpc/boot/dts/sbc8548.dts
index 77be77116c2e..1df2a0955668 100644
--- a/arch/powerpc/boot/dts/sbc8548.dts
+++ b/arch/powerpc/boot/dts/sbc8548.dts
@@ -14,44 +14,9 @@
/dts-v1/;
-/ {
- model = "SBC8548";
- compatible = "SBC8548";
- #address-cells = <1>;
- #size-cells = <1>;
-
- aliases {
- ethernet0 = &enet0;
- ethernet1 = &enet1;
- serial0 = &serial0;
- serial1 = &serial1;
- pci0 = &pci0;
- pci1 = &pci1;
- };
-
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- PowerPC,8548@0 {
- device_type = "cpu";
- reg = <0>;
- d-cache-line-size = <0x20>; // 32 bytes
- i-cache-line-size = <0x20>; // 32 bytes
- d-cache-size = <0x8000>; // L1, 32K
- i-cache-size = <0x8000>; // L1, 32K
- timebase-frequency = <0>; // From uboot
- bus-frequency = <0>;
- clock-frequency = <0>;
- next-level-cache = <&L2>;
- };
- };
-
- memory {
- device_type = "memory";
- reg = <0x00000000 0x10000000>;
- };
+/include/ "sbc8548-pre.dtsi"
+/{
localbus@e0000000 {
#address-cells = <2>;
#size-cells = <1>;
@@ -63,23 +28,25 @@
0x3 0x0 0xf0000000 0x04000000 /*64MB SDRAM*/
0x4 0x0 0xf4000000 0x04000000 /*64MB SDRAM*/
0x5 0x0 0xf8000000 0x00b10000 /* EPLD */
- 0x6 0x0 0xfb800000 0x04000000>; /*64MB Flash*/
+ 0x6 0x0 0xec000000 0x04000000>; /*64MB Flash*/
flash@0,0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "cfi-flash";
+ compatible = "intel,JS28F640", "cfi-flash";
reg = <0x0 0x0 0x800000>;
bank-width = <1>;
device-width = <1>;
partition@0x0 {
label = "space";
- reg = <0x00000000 0x00100000>;
+ /* FF800000 -> FFF9FFFF */
+ reg = <0x00000000 0x007a0000>;
};
- partition@0x100000 {
+ partition@0x7a0000 {
label = "bootloader";
- reg = <0x00100000 0x00700000>;
+ /* FFFA0000 -> FFFFFFFF */
+ reg = <0x007a0000 0x00060000>;
read-only;
};
};
@@ -122,307 +89,22 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0x6 0x0 0x04000000>;
- compatible = "cfi-flash";
+ compatible = "intel,JS28F128", "cfi-flash";
bank-width = <4>;
device-width = <1>;
partition@0x0 {
+ label = "space";
+ /* EC000000 -> EFEFFFFF */
+ reg = <0x00000000 0x03f00000>;
+ };
+ partition@0x03f00000 {
label = "bootloader";
- reg = <0x00000000 0x00100000>;
+ /* EFF00000 -> EFFFFFFF */
+ reg = <0x03f00000 0x00100000>;
read-only;
};
- partition@0x00100000 {
- label = "file-system";
- reg = <0x00100000 0x01f00000>;
- };
- partition@0x02000000 {
- label = "boot-config";
- reg = <0x02000000 0x00100000>;
- };
- partition@0x02100000 {
- label = "space";
- reg = <0x02100000 0x01f00000>;
- };
};
};
-
- soc8548@e0000000 {
- #address-cells = <1>;
- #size-cells = <1>;
- device_type = "soc";
- ranges = <0x00000000 0xe0000000 0x00100000>;
- bus-frequency = <0>;
- compatible = "simple-bus";
-
- ecm-law@0 {
- compatible = "fsl,ecm-law";
- reg = <0x0 0x1000>;
- fsl,num-laws = <10>;
- };
-
- ecm@1000 {
- compatible = "fsl,mpc8548-ecm", "fsl,ecm";
- reg = <0x1000 0x1000>;
- interrupts = <17 2>;
- interrupt-parent = <&mpic>;
- };
-
- memory-controller@2000 {
- compatible = "fsl,mpc8548-memory-controller";
- reg = <0x2000 0x1000>;
- interrupt-parent = <&mpic>;
- interrupts = <0x12 0x2>;
- };
-
- L2: l2-cache-controller@20000 {
- compatible = "fsl,mpc8548-l2-cache-controller";
- reg = <0x20000 0x1000>;
- cache-line-size = <0x20>; // 32 bytes
- cache-size = <0x80000>; // L2, 512K
- interrupt-parent = <&mpic>;
- interrupts = <0x10 0x2>;
- };
-
- i2c@3000 {
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <0>;
- compatible = "fsl-i2c";
- reg = <0x3000 0x100>;
- interrupts = <0x2b 0x2>;
- interrupt-parent = <&mpic>;
- dfsrr;
- };
-
- i2c@3100 {
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <1>;
- compatible = "fsl-i2c";
- reg = <0x3100 0x100>;
- interrupts = <0x2b 0x2>;
- interrupt-parent = <&mpic>;
- dfsrr;
- };
-
- dma@21300 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "fsl,mpc8548-dma", "fsl,eloplus-dma";
- reg = <0x21300 0x4>;
- ranges = <0x0 0x21100 0x200>;
- cell-index = <0>;
- dma-channel@0 {
- compatible = "fsl,mpc8548-dma-channel",
- "fsl,eloplus-dma-channel";
- reg = <0x0 0x80>;
- cell-index = <0>;
- interrupt-parent = <&mpic>;
- interrupts = <20 2>;
- };
- dma-channel@80 {
- compatible = "fsl,mpc8548-dma-channel",
- "fsl,eloplus-dma-channel";
- reg = <0x80 0x80>;
- cell-index = <1>;
- interrupt-parent = <&mpic>;
- interrupts = <21 2>;
- };
- dma-channel@100 {
- compatible = "fsl,mpc8548-dma-channel",
- "fsl,eloplus-dma-channel";
- reg = <0x100 0x80>;
- cell-index = <2>;
- interrupt-parent = <&mpic>;
- interrupts = <22 2>;
- };
- dma-channel@180 {
- compatible = "fsl,mpc8548-dma-channel",
- "fsl,eloplus-dma-channel";
- reg = <0x180 0x80>;
- cell-index = <3>;
- interrupt-parent = <&mpic>;
- interrupts = <23 2>;
- };
- };
-
- enet0: ethernet@24000 {
- #address-cells = <1>;
- #size-cells = <1>;
- cell-index = <0>;
- device_type = "network";
- model = "eTSEC";
- compatible = "gianfar";
- reg = <0x24000 0x1000>;
- ranges = <0x0 0x24000 0x1000>;
- local-mac-address = [ 00 00 00 00 00 00 ];
- interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
- interrupt-parent = <&mpic>;
- tbi-handle = <&tbi0>;
- phy-handle = <&phy0>;
-
- mdio@520 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,gianfar-mdio";
- reg = <0x520 0x20>;
-
- phy0: ethernet-phy@19 {
- interrupt-parent = <&mpic>;
- interrupts = <0x6 0x1>;
- reg = <0x19>;
- device_type = "ethernet-phy";
- };
- phy1: ethernet-phy@1a {
- interrupt-parent = <&mpic>;
- interrupts = <0x7 0x1>;
- reg = <0x1a>;
- device_type = "ethernet-phy";
- };
- tbi0: tbi-phy@11 {
- reg = <0x11>;
- device_type = "tbi-phy";
- };
- };
- };
-
- enet1: ethernet@25000 {
- #address-cells = <1>;
- #size-cells = <1>;
- cell-index = <1>;
- device_type = "network";
- model = "eTSEC";
- compatible = "gianfar";
- reg = <0x25000 0x1000>;
- ranges = <0x0 0x25000 0x1000>;
- local-mac-address = [ 00 00 00 00 00 00 ];
- interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>;
- interrupt-parent = <&mpic>;
- tbi-handle = <&tbi1>;
- phy-handle = <&phy1>;
-
- mdio@520 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,gianfar-tbi";
- reg = <0x520 0x20>;
-
- tbi1: tbi-phy@11 {
- reg = <0x11>;
- device_type = "tbi-phy";
- };
- };
- };
-
- serial0: serial@4500 {
- cell-index = <0>;
- device_type = "serial";
- compatible = "fsl,ns16550", "ns16550";
- reg = <0x4500 0x100>; // reg base, size
- clock-frequency = <0>; // should we fill in in uboot?
- interrupts = <0x2a 0x2>;
- interrupt-parent = <&mpic>;
- };
-
- serial1: serial@4600 {
- cell-index = <1>;
- device_type = "serial";
- compatible = "fsl,ns16550", "ns16550";
- reg = <0x4600 0x100>; // reg base, size
- clock-frequency = <0>; // should we fill in in uboot?
- interrupts = <0x2a 0x2>;
- interrupt-parent = <&mpic>;
- };
-
- global-utilities@e0000 { //global utilities reg
- compatible = "fsl,mpc8548-guts";
- reg = <0xe0000 0x1000>;
- fsl,has-rstcr;
- };
-
- crypto@30000 {
- compatible = "fsl,sec2.1", "fsl,sec2.0";
- reg = <0x30000 0x10000>;
- interrupts = <45 2>;
- interrupt-parent = <&mpic>;
- fsl,num-channels = <4>;
- fsl,channel-fifo-len = <24>;
- fsl,exec-units-mask = <0xfe>;
- fsl,descriptor-types-mask = <0x12b0ebf>;
- };
-
- mpic: pic@40000 {
- interrupt-controller;
- #address-cells = <0>;
- #interrupt-cells = <2>;
- reg = <0x40000 0x40000>;
- compatible = "chrp,open-pic";
- device_type = "open-pic";
- };
- };
-
- pci0: pci@e0008000 {
- interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
- interrupt-map = <
- /* IDSEL 0x01 (PCI-X slot) @66MHz */
- 0x0800 0x0 0x0 0x1 &mpic 0x2 0x1
- 0x0800 0x0 0x0 0x2 &mpic 0x3 0x1
- 0x0800 0x0 0x0 0x3 &mpic 0x4 0x1
- 0x0800 0x0 0x0 0x4 &mpic 0x1 0x1
-
- /* IDSEL 0x11 (PCI, 3.3V 32bit) @33MHz */
- 0x8800 0x0 0x0 0x1 &mpic 0x2 0x1
- 0x8800 0x0 0x0 0x2 &mpic 0x3 0x1
- 0x8800 0x0 0x0 0x3 &mpic 0x4 0x1
- 0x8800 0x0 0x0 0x4 &mpic 0x1 0x1>;
-
- interrupt-parent = <&mpic>;
- interrupts = <0x18 0x2>;
- bus-range = <0 0>;
- ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x10000000
- 0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00800000>;
- clock-frequency = <66000000>;
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0xe0008000 0x1000>;
- compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci";
- device_type = "pci";
- };
-
- pci1: pcie@e000a000 {
- interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
- interrupt-map = <
-
- /* IDSEL 0x0 (PEX) */
- 0x0000 0x0 0x0 0x1 &mpic 0x0 0x1
- 0x0000 0x0 0x0 0x2 &mpic 0x1 0x1
- 0x0000 0x0 0x0 0x3 &mpic 0x2 0x1
- 0x0000 0x0 0x0 0x4 &mpic 0x3 0x1>;
-
- interrupt-parent = <&mpic>;
- interrupts = <0x1a 0x2>;
- bus-range = <0x0 0xff>;
- ranges = <0x02000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
- 0x01000000 0x0 0x00000000 0xe2800000 0x0 0x08000000>;
- clock-frequency = <33000000>;
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0xe000a000 0x1000>;
- compatible = "fsl,mpc8548-pcie";
- device_type = "pci";
- pcie@0 {
- reg = <0x0 0x0 0x0 0x0 0x0>;
- #size-cells = <2>;
- #address-cells = <3>;
- device_type = "pci";
- ranges = <0x02000000 0x0 0xa0000000
- 0x02000000 0x0 0xa0000000
- 0x0 0x10000000
-
- 0x01000000 0x0 0x00000000
- 0x01000000 0x0 0x00000000
- 0x0 0x00800000>;
- };
- };
};
+
+/include/ "sbc8548-post.dtsi"
diff --git a/arch/powerpc/boot/dts/uc101.dts b/arch/powerpc/boot/dts/uc101.dts
index ba83d5488ec6..5c462194ef06 100644
--- a/arch/powerpc/boot/dts/uc101.dts
+++ b/arch/powerpc/boot/dts/uc101.dts
@@ -13,54 +13,20 @@
/include/ "mpc5200b.dtsi"
+&gpt0 { gpio-controller; };
+&gpt1 { gpio-controller; };
+&gpt2 { gpio-controller; };
+&gpt3 { gpio-controller; };
+&gpt4 { gpio-controller; };
+&gpt5 { gpio-controller; };
+&gpt6 { gpio-controller; };
+&gpt7 { gpio-controller; };
+
/ {
model = "manroland,uc101";
compatible = "manroland,uc101";
soc5200@f0000000 {
- gpt0: timer@600 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt1: timer@610 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt2: timer@620 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt3: timer@630 { // General Purpose Timer in GPIO mode
- compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
- reg = <0x630 0x10>;
- interrupts = <1 12 0>;
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt4: timer@640 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt5: timer@650 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt6: timer@660 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
- gpt7: timer@670 { // General Purpose Timer in GPIO mode
- gpio-controller;
- #gpio-cells = <2>;
- };
-
rtc@800 {
status = "disabled";
};
diff --git a/arch/powerpc/boot/dts/virtex440-ml507.dts b/arch/powerpc/boot/dts/virtex440-ml507.dts
index 52d8c1ad26a1..fc7073bc547e 100644
--- a/arch/powerpc/boot/dts/virtex440-ml507.dts
+++ b/arch/powerpc/boot/dts/virtex440-ml507.dts
@@ -272,6 +272,12 @@
xlnx,temac-type = <0>;
xlnx,txcsum = <1>;
xlnx,txfifo = <0x1000>;
+ phy-handle = <&phy7>;
+ clock-frequency = <100000000>;
+ phy7: phy@7 {
+ compatible = "marvell,88e1111";
+ reg = <7>;
+ } ;
} ;
} ;
IIC_EEPROM: i2c@81600000 {
diff --git a/arch/powerpc/configs/83xx/kmeter1_defconfig b/arch/powerpc/configs/83xx/kmeter1_defconfig
index a0dfef1fcdb7..e12e60c3b9a2 100644
--- a/arch/powerpc/configs/83xx/kmeter1_defconfig
+++ b/arch/powerpc/configs/83xx/kmeter1_defconfig
@@ -2,6 +2,8 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_EXPERT=y
CONFIG_SLAB=y
@@ -16,8 +18,6 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_PPC_PMAC is not set
CONFIG_PPC_83xx=y
CONFIG_KMETER1=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
# CONFIG_SECCOMP is not set
CONFIG_NET=y
@@ -45,7 +45,6 @@ CONFIG_MTD_PHYSMAP_OF=y
CONFIG_MTD_PHRAM=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_GLUEBI=y
-CONFIG_MTD_UBI_DEBUG=y
CONFIG_PROC_DEVICETREE=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
@@ -76,5 +75,4 @@ CONFIG_TMPFS=y
CONFIG_JFFS2_FS=y
CONFIG_UBIFS_FS=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
diff --git a/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/arch/powerpc/configs/85xx/ge_imp3a_defconfig
index f8c51a4ab995..c9765b54dd1a 100644
--- a/arch/powerpc/configs/85xx/ge_imp3a_defconfig
+++ b/arch/powerpc/configs/85xx/ge_imp3a_defconfig
@@ -34,7 +34,6 @@ CONFIG_PREEMPT=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
-CONFIG_IRQ_ALL_CPUS=y
CONFIG_FORCE_MAX_ZONEORDER=17
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
diff --git a/arch/powerpc/configs/85xx/ppa8548_defconfig b/arch/powerpc/configs/85xx/ppa8548_defconfig
new file mode 100644
index 000000000000..a11337de8aa2
--- /dev/null
+++ b/arch/powerpc/configs/85xx/ppa8548_defconfig
@@ -0,0 +1,65 @@
+CONFIG_PPC_85xx=y
+CONFIG_PPA8548=y
+CONFIG_DTC=y
+CONFIG_DEFAULT_UIMAGE=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_PCI is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_ADVANCED_OPTIONS=y
+CONFIG_LOWMEM_SIZE_BOOL=y
+CONFIG_LOWMEM_SIZE=0x40000000
+CONFIG_LOWMEM_CAM_NUM_BOOL=y
+CONFIG_LOWMEM_CAM_NUM=4
+CONFIG_PAGE_OFFSET_BOOL=y
+CONFIG_PAGE_OFFSET=0xb0000000
+CONFIG_KERNEL_START_BOOL=y
+CONFIG_KERNEL_START=0xb0000000
+# CONFIG_PHYSICAL_START_BOOL is not set
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_PHYSICAL_ALIGN=0x04000000
+CONFIG_TASK_SIZE_BOOL=y
+CONFIG_TASK_SIZE=0xb0000000
+
+CONFIG_FSL_LBC=y
+CONFIG_FSL_DMA=y
+CONFIG_FSL_RIO=y
+
+CONFIG_RAPIDIO=y
+CONFIG_RAPIDIO_DMA_ENGINE=y
+CONFIG_RAPIDIO_TSI57X=y
+CONFIG_RAPIDIO_TSI568=y
+CONFIG_RAPIDIO_CPS_XX=y
+CONFIG_RAPIDIO_CPS_GEN2=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_PROC_DEVICETREE=y
+
+CONFIG_MTD=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_PHYSMAP_OF=y
+
+CONFIG_I2C=y
+CONFIG_I2C_MPC=y
+CONFIG_I2C_CHARDEV
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_DRV_ISL1208=y
+
+CONFIG_NET=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_GIANFAR=y
+CONFIG_MARVELL_PHY=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
diff --git a/arch/powerpc/configs/85xx/sbc8548_defconfig b/arch/powerpc/configs/85xx/sbc8548_defconfig
index 5b2b651dfb98..008a7a47b89b 100644
--- a/arch/powerpc/configs/85xx/sbc8548_defconfig
+++ b/arch/powerpc/configs/85xx/sbc8548_defconfig
@@ -55,3 +55,22 @@ CONFIG_ROOT_NFS=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_MTD=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+CONFIG_MTD_CFI_I4=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_PHYSMAP_OF=y
diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
index da731c2fe984..f2f6734d5f76 100644
--- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
+++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
@@ -25,7 +25,6 @@ CONFIG_HIGH_RES_TIMERS=y
CONFIG_HZ_1000=y
CONFIG_PREEMPT=y
CONFIG_BINFMT_MISC=m
-CONFIG_IRQ_ALL_CPUS=y
CONFIG_SPARSE_IRQ=y
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
index 2149360a1e62..be73219212b7 100644
--- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
@@ -25,7 +25,6 @@ CONFIG_HIGH_RES_TIMERS=y
CONFIG_HZ_1000=y
CONFIG_PREEMPT=y
CONFIG_BINFMT_MISC=y
-CONFIG_IRQ_ALL_CPUS=y
CONFIG_SPARSE_IRQ=y
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
index af2e8e1edba6..b3e2b1058f27 100644
--- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
@@ -25,7 +25,6 @@ CONFIG_HIGH_RES_TIMERS=y
CONFIG_HZ_1000=y
CONFIG_PREEMPT=y
CONFIG_BINFMT_MISC=m
-CONFIG_IRQ_ALL_CPUS=y
CONFIG_SPARSE_IRQ=y
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
diff --git a/arch/powerpc/configs/86xx/sbc8641d_defconfig b/arch/powerpc/configs/86xx/sbc8641d_defconfig
index 0a92ca045641..1a62baf855e9 100644
--- a/arch/powerpc/configs/86xx/sbc8641d_defconfig
+++ b/arch/powerpc/configs/86xx/sbc8641d_defconfig
@@ -23,7 +23,6 @@ CONFIG_SBC8641D=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
CONFIG_BINFMT_MISC=m
-CONFIG_IRQ_ALL_CPUS=y
CONFIG_SPARSE_IRQ=y
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
diff --git a/arch/powerpc/configs/chroma_defconfig b/arch/powerpc/configs/chroma_defconfig
index 29bb11ec6c64..4f35fc462385 100644
--- a/arch/powerpc/configs/chroma_defconfig
+++ b/arch/powerpc/configs/chroma_defconfig
@@ -1,6 +1,6 @@
CONFIG_PPC64=y
CONFIG_PPC_BOOK3E_64=y
-# CONFIG_VIRT_CPU_ACCOUNTING is not set
+# CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set
CONFIG_SMP=y
CONFIG_NR_CPUS=256
CONFIG_EXPERIMENTAL=y
diff --git a/arch/powerpc/configs/corenet32_smp_defconfig b/arch/powerpc/configs/corenet32_smp_defconfig
index 1c0f2432ecdb..60027c2a7034 100644
--- a/arch/powerpc/configs/corenet32_smp_defconfig
+++ b/arch/powerpc/configs/corenet32_smp_defconfig
@@ -32,7 +32,6 @@ CONFIG_HIGHMEM=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=m
CONFIG_KEXEC=y
-CONFIG_IRQ_ALL_CPUS=y
CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig
index 88fa5c46f66f..3d139fa04050 100644
--- a/arch/powerpc/configs/corenet64_smp_defconfig
+++ b/arch/powerpc/configs/corenet64_smp_defconfig
@@ -1,6 +1,6 @@
CONFIG_PPC64=y
CONFIG_PPC_BOOK3E_64=y
-# CONFIG_VIRT_CPU_ACCOUNTING is not set
+# CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_EXPERIMENTAL=y
@@ -26,7 +26,6 @@ CONFIG_P5020_DS=y
CONFIG_P5040_DS=y
# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
CONFIG_BINFMT_MISC=m
-CONFIG_IRQ_ALL_CPUS=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_MSI=y
CONFIG_RAPIDIO=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 502cd9e027e4..8d00ea5b8a9f 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -49,7 +49,6 @@ CONFIG_QE_GPIO=y
CONFIG_HIGHMEM=y
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
-CONFIG_IRQ_ALL_CPUS=y
CONFIG_FORCE_MAX_ZONEORDER=12
CONFIG_PCI=y
CONFIG_PCI_MSI=y
diff --git a/arch/powerpc/configs/pasemi_defconfig b/arch/powerpc/configs/pasemi_defconfig
index 840a2c2d0430..bd8a6f71944f 100644
--- a/arch/powerpc/configs/pasemi_defconfig
+++ b/arch/powerpc/configs/pasemi_defconfig
@@ -1,28 +1,27 @@
CONFIG_PPC64=y
CONFIG_ALTIVEC=y
-# CONFIG_VIRT_CPU_ACCOUNTING is not set
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
# CONFIG_PPC_PSERIES is not set
# CONFIG_PPC_PMAC is not set
CONFIG_PPC_PASEMI=y
CONFIG_PPC_PASEMI_IOMMU=y
CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_DEBUG=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
CONFIG_HZ_1000=y
CONFIG_PPC_64K_PAGES=y
# CONFIG_SECCOMP is not set
@@ -47,7 +46,6 @@ CONFIG_INET_ESP=y
# CONFIG_IPV6 is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_SLRAM=y
@@ -58,7 +56,6 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_MISC_DEVICES=y
CONFIG_EEPROM_LEGACY=y
CONFIG_IDE=y
CONFIG_BLK_DEV_IDECD=y
@@ -91,21 +88,19 @@ CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
-CONFIG_MARVELL_PHY=y
-CONFIG_NET_ETHERNET=y
CONFIG_MII=y
-CONFIG_NET_PCI=y
-CONFIG_E1000=y
CONFIG_TIGON3=y
+CONFIG_E1000=y
CONFIG_PASEMI_MAC=y
+CONFIG_MARVELL_PHY=y
CONFIG_INPUT_JOYDEV=y
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=4
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=4
CONFIG_HW_RANDOM=y
CONFIG_RAW_DRIVER=y
CONFIG_I2C_CHARDEV=y
@@ -146,14 +141,11 @@ CONFIG_HID_TOPSEED=y
CONFIG_HID_THRUSTMASTER=y
CONFIG_HID_ZEROPLUS=y
CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_UHCI_HCD=y
CONFIG_USB_SL811_HCD=y
CONFIG_USB_STORAGE=y
-CONFIG_USB_LIBUSUAL=y
CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=y
CONFIG_EDAC_PASEMI=y
@@ -164,8 +156,6 @@ CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_INOTIFY=y
-CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
CONFIG_ISO9660_FS=y
CONFIG_UDF_FS=y
@@ -177,27 +167,22 @@ CONFIG_HUGETLBFS=y
CONFIG_CONFIGFS_FS=y
CONFIG_JFFS2_FS=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
CONFIG_NFSD_V4=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAC_PARTITION=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_CRC_CCITT=y
+CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
# CONFIG_SCHED_DEBUG is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
-CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_BLOWFISH=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index 6d03530b7506..aef3f71de5ad 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -5,6 +5,9 @@ CONFIG_SMP=y
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_IKCONFIG=y
@@ -21,6 +24,8 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
CONFIG_PPC_SPLPAR=y
CONFIG_SCANLOG=m
CONFIG_PPC_SMLPAR=y
@@ -42,10 +47,9 @@ CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_PMAC64=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
CONFIG_HZ_100=y
CONFIG_BINFMT_MISC=m
+CONFIG_PPC_TRANSACTIONAL_MEM=y
CONFIG_HOTPLUG_CPU=y
CONFIG_KEXEC=y
CONFIG_IRQ_ALL_CPUS=y
@@ -73,7 +77,6 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CT_PROTO_SCTP=m
@@ -130,19 +133,12 @@ CONFIG_NETFILTER_XT_MATCH_U32=m
CONFIG_NF_CONNTRACK_IPV4=m
CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_NF_NAT=m
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_NF_NAT_SNMP_BASIC=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_CLUSTERIP=m
CONFIG_IP_NF_TARGET_ECN=m
@@ -151,7 +147,10 @@ CONFIG_IP_NF_RAW=m
CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_BPF_JIT=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_LOOP=y
@@ -173,7 +172,6 @@ CONFIG_CHR_DEV_SG=y
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
@@ -205,13 +203,6 @@ CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
-CONFIG_IEEE1394=y
-CONFIG_IEEE1394_OHCI1394=y
-CONFIG_IEEE1394_SBP2=m
-CONFIG_IEEE1394_ETH1394=m
-CONFIG_IEEE1394_RAWIO=y
-CONFIG_IEEE1394_VIDEO1394=m
-CONFIG_IEEE1394_DV1394=m
CONFIG_ADB_PMU=y
CONFIG_PMAC_SMU=y
CONFIG_THERM_PM72=y
@@ -220,50 +211,43 @@ CONFIG_WINDFARM_PM81=y
CONFIG_WINDFARM_PM91=y
CONFIG_WINDFARM_PM112=y
CONFIG_WINDFARM_PM121=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_NETCONSOLE=y
+CONFIG_NETPOLL_TRAP=y
CONFIG_TUN=m
-CONFIG_MARVELL_PHY=y
-CONFIG_BROADCOM_PHY=m
-CONFIG_NET_ETHERNET=y
-CONFIG_SUNGEM=y
-CONFIG_NET_VENDOR_3COM=y
CONFIG_VORTEX=y
-CONFIG_IBMVETH=m
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-CONFIG_E100=y
CONFIG_ACENIC=m
CONFIG_ACENIC_OMIT_TIGON_I=y
-CONFIG_E1000=y
-CONFIG_E1000E=y
+CONFIG_PCNET32=y
CONFIG_TIGON3=y
-CONFIG_BNX2=m
-CONFIG_SPIDER_NET=m
-CONFIG_GELIC_NET=m
-CONFIG_GELIC_WIRELESS=y
CONFIG_CHELSIO_T1=m
-CONFIG_CHELSIO_T3=m
-CONFIG_CHELSIO_T4=m
+CONFIG_BE2NET=m
+CONFIG_S2IO=m
+CONFIG_IBMVETH=m
CONFIG_EHEA=m
-CONFIG_IXGBE=m
+CONFIG_E100=y
+CONFIG_E1000=y
+CONFIG_E1000E=y
CONFIG_IXGB=m
-CONFIG_S2IO=m
+CONFIG_IXGBE=m
+CONFIG_MLX4_EN=m
CONFIG_MYRI10GE=m
-CONFIG_NETXEN_NIC=m
CONFIG_PASEMI_MAC=y
-CONFIG_MLX4_EN=m
CONFIG_QLGE=m
-CONFIG_BE2NET=m
+CONFIG_NETXEN_NIC=m
+CONFIG_SUNGEM=y
+CONFIG_GELIC_NET=m
+CONFIG_GELIC_WIRELESS=y
+CONFIG_SPIDER_NET=m
+CONFIG_MARVELL_PHY=y
+CONFIG_BROADCOM_PHY=m
CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
CONFIG_PPPOE=m
-CONFIG_NETCONSOLE=y
-CONFIG_NETPOLL_TRAP=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_EVDEV=m
CONFIG_INPUT_MISC=y
@@ -279,13 +263,10 @@ CONFIG_HVC_RTAS=y
CONFIG_HVC_BEAT=y
CONFIG_HVCS=m
CONFIG_IBM_BSR=m
-CONFIG_HW_RANDOM=m
-CONFIG_HW_RANDOM_PSERIES=m
CONFIG_RAW_DRIVER=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_AMD8111=y
CONFIG_I2C_PASEMI=y
-# CONFIG_HWMON is not set
CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
@@ -300,7 +281,6 @@ CONFIG_FB_RADEON=y
CONFIG_FB_IBM_GXT4500=y
CONFIG_FB_PS3=m
CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_DISPLAY_SUPPORT=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
@@ -317,18 +297,16 @@ CONFIG_SND_AOA_FABRIC_LAYOUT=m
CONFIG_SND_AOA_ONYX=m
CONFIG_SND_AOA_TAS=m
CONFIG_SND_AOA_TOONIE=m
-CONFIG_USB_HIDDEV=y
CONFIG_HID_GYRATION=y
CONFIG_HID_PANTHERLORD=y
CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
+CONFIG_USB_HIDDEV=y
CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
CONFIG_USB_MON=m
CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_TT_NEWSCHED=y
# CONFIG_USB_EHCI_HCD_PPC_OF is not set
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_STORAGE=m
@@ -370,11 +348,9 @@ CONFIG_JFS_POSIX_ACL=y
CONFIG_JFS_SECURITY=y
CONFIG_XFS_FS=m
CONFIG_XFS_POSIX_ACL=y
-CONFIG_OCFS2_FS=m
CONFIG_BTRFS_FS=m
CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_NILFS2_FS=m
-CONFIG_INOTIFY=y
CONFIG_AUTOFS4_FS=m
CONFIG_FUSE_FS=m
CONFIG_ISO9660_FS=y
@@ -383,100 +359,53 @@ CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
CONFIG_HFS_FS=m
CONFIG_HFSPLUS_FS=m
CONFIG_CRAMFS=m
CONFIG_SQUASHFS=m
CONFIG_SQUASHFS_XATTR=y
-CONFIG_SQUASHFS_ZLIB=y
CONFIG_SQUASHFS_LZO=y
CONFIG_SQUASHFS_XZ=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
CONFIG_NFSD=m
CONFIG_NFSD_V3_ACL=y
CONFIG_NFSD_V4=y
-CONFIG_RPCSEC_GSS_SPKM3=m
CONFIG_CIFS=m
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
-CONFIG_PARTITION_ADVANCED=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=m
+CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
-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=y
CONFIG_CRC_T10DIF=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
CONFIG_LOCKUP_DETECTOR=y
-CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEBUG_MUTEXES=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_DEBUG_STACK_USAGE=y
CONFIG_LATENCYTOP=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_SCHED_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_STACK_USAGE=y
CONFIG_CODE_PATCHING_SELFTEST=y
CONFIG_FTR_FIXUP_SELFTEST=y
CONFIG_MSI_BITMAP_SELFTEST=y
CONFIG_XMON=y
-CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_BOOTX_TEXT=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
-CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_KHAZAD=m
@@ -486,11 +415,9 @@ CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_LZO=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_NX=y
CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
CONFIG_VIRTUALIZATION=y
CONFIG_KVM_BOOK3S_64=m
CONFIG_KVM_BOOK3S_64_HV=y
CONFIG_VHOST_NET=m
-CONFIG_BPF_JIT=y
diff --git a/arch/powerpc/configs/ppc64e_defconfig b/arch/powerpc/configs/ppc64e_defconfig
index f55c27609fc6..4b20f76172e2 100644
--- a/arch/powerpc/configs/ppc64e_defconfig
+++ b/arch/powerpc/configs/ppc64e_defconfig
@@ -4,6 +4,8 @@ CONFIG_SMP=y
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_IKCONFIG=y
@@ -18,12 +20,13 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_EFI_PARTITION=y
CONFIG_P5020_DS=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
CONFIG_BINFMT_MISC=m
CONFIG_IRQ_ALL_CPUS=y
CONFIG_SPARSEMEM_MANUAL=y
@@ -46,7 +49,6 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CT_PROTO_SCTP=m
@@ -103,19 +105,12 @@ CONFIG_NETFILTER_XT_MATCH_U32=m
CONFIG_NF_CONNTRACK_IPV4=m
CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_NF_NAT=m
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_NF_NAT_SNMP_BASIC=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_CLUSTERIP=m
CONFIG_IP_NF_TARGET_ECN=m
@@ -125,6 +120,8 @@ CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_LOOP=y
@@ -167,41 +164,31 @@ CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
-CONFIG_IEEE1394=y
-CONFIG_IEEE1394_OHCI1394=y
-CONFIG_IEEE1394_SBP2=m
-CONFIG_IEEE1394_ETH1394=m
-CONFIG_IEEE1394_RAWIO=y
-CONFIG_IEEE1394_VIDEO1394=m
-CONFIG_IEEE1394_DV1394=m
CONFIG_MACINTOSH_DRIVERS=y
CONFIG_WINDFARM=y
CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_NETCONSOLE=y
+CONFIG_NETPOLL_TRAP=y
CONFIG_TUN=m
-CONFIG_MARVELL_PHY=y
-CONFIG_BROADCOM_PHY=m
-CONFIG_NET_ETHERNET=y
-CONFIG_SUNGEM=y
-CONFIG_NET_VENDOR_3COM=y
CONFIG_VORTEX=y
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-CONFIG_E100=y
CONFIG_ACENIC=y
CONFIG_ACENIC_OMIT_TIGON_I=y
-CONFIG_E1000=y
+CONFIG_PCNET32=y
CONFIG_TIGON3=y
+CONFIG_E100=y
+CONFIG_E1000=y
CONFIG_IXGB=m
+CONFIG_SUNGEM=y
+CONFIG_MARVELL_PHY=y
+CONFIG_BROADCOM_PHY=m
CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
CONFIG_PPPOE=m
-CONFIG_NETCONSOLE=y
-CONFIG_NETPOLL_TRAP=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_EVDEV=m
CONFIG_INPUT_MISC=y
@@ -213,7 +200,6 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_RAW_DRIVER=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_AMD8111=y
-# CONFIG_HWMON is not set
CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
@@ -227,7 +213,6 @@ CONFIG_FB_MATROX_MAVEN=m
CONFIG_FB_RADEON=y
CONFIG_FB_IBM_GXT4500=y
CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_DISPLAY_SUPPORT=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
@@ -238,7 +223,6 @@ CONFIG_SND_SEQ_DUMMY=m
CONFIG_SND_MIXER_OSS=m
CONFIG_SND_PCM_OSS=m
CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_USB_HIDDEV=y
CONFIG_HID_DRAGONRISE=y
CONFIG_HID_GYRATION=y
CONFIG_HID_TWINHAN=y
@@ -253,8 +237,8 @@ CONFIG_HID_SMARTJOYPLUS=y
CONFIG_HID_TOPSEED=y
CONFIG_HID_THRUSTMASTER=y
CONFIG_HID_ZEROPLUS=y
+CONFIG_USB_HIDDEV=y
CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_HCD_PPC_OF is not set
CONFIG_USB_OHCI_HCD=y
@@ -296,73 +280,36 @@ CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HFS_FS=m
CONFIG_HFSPLUS_FS=m
CONFIG_CRAMFS=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
CONFIG_NFSD=m
CONFIG_NFSD_V3_ACL=y
CONFIG_NFSD_V4=y
-CONFIG_RPCSEC_GSS_SPKM3=m
CONFIG_CIFS=m
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAC_PARTITION=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=m
+CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
-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=y
CONFIG_CRC_T10DIF=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEBUG_MUTEXES=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_DEBUG_STACK_USAGE=y
CONFIG_LATENCYTOP=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_IRQSOFF_TRACER=y
CONFIG_SCHED_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_STACK_USAGE=y
CONFIG_CODE_PATCHING_SELFTEST=y
CONFIG_FTR_FIXUP_SELFTEST=y
CONFIG_MSI_BITMAP_SELFTEST=y
@@ -371,16 +318,12 @@ CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_CCM=m
CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST6=m
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index c2f4b4a86ece..7a5c15fcc7cf 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -6,6 +6,7 @@ CONFIG_NR_CPUS=2
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_EMBEDDED=y
@@ -24,12 +25,13 @@ CONFIG_PS3_DISK=y
CONFIG_PS3_ROM=y
CONFIG_PS3_FLASH=y
CONFIG_PS3_VRAM=m
+CONFIG_PS3_LPM=m
# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
-CONFIG_HIGH_RES_TIMERS=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=y
CONFIG_KEXEC=y
# CONFIG_SPARSEMEM_VMEMMAP is not set
+# CONFIG_COMPACTION is not set
CONFIG_SCHED_SMT=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE=""
@@ -59,6 +61,7 @@ CONFIG_BT_BNEP_PROTO_FILTER=y
CONFIG_BT_HIDP=m
CONFIG_BT_HCIBTUSB=m
CONFIG_CFG80211=m
+CONFIG_CFG80211_WEXT=y
CONFIG_MAC80211=m
CONFIG_MAC80211_RC_PID=y
# CONFIG_MAC80211_RC_MINSTREL is not set
@@ -78,7 +81,6 @@ CONFIG_MD=y
CONFIG_BLK_DEV_DM=m
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_BROADCOM is not set
-# CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MICREL is not set
@@ -119,21 +121,21 @@ CONFIG_SND=m
# CONFIG_SND_DRIVERS is not set
CONFIG_SND_USB_AUDIO=m
CONFIG_HIDRAW=y
-CONFIG_USB_HIDDEV=y
CONFIG_HID_APPLE=m
CONFIG_HID_BELKIN=m
CONFIG_HID_CHERRY=m
CONFIG_HID_EZKEY=m
CONFIG_HID_TWINHAN=m
CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
CONFIG_HID_MICROSOFT=m
+CONFIG_HID_PS3REMOTE=m
CONFIG_HID_SONY=m
CONFIG_HID_SUNPLUS=m
CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_USB_HIDDEV=y
CONFIG_USB=m
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
CONFIG_USB_SUSPEND=y
CONFIG_USB_MON=m
CONFIG_USB_EHCI_HCD=m
@@ -158,8 +160,8 @@ CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_HUGETLBFS=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_NFS_V4=y
+CONFIG_NFS_SWAP=y
CONFIG_ROOT_NFS=y
CONFIG_CIFS=m
CONFIG_NLS=y
@@ -176,6 +178,7 @@ CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_WRITECOUNT=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DEBUG_LIST=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
# CONFIG_FTRACE is not set
CONFIG_DEBUG_STACKOVERFLOW=y
CONFIG_CRYPTO_CCM=m
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index 5b8e1e508270..c4dfbaf8b192 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -6,12 +6,15 @@ CONFIG_NR_CPUS=2048
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_AUDIT=y
-CONFIG_AUDITSYSCALL=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_CGROUPS=y
@@ -29,6 +32,8 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
CONFIG_PPC_SPLPAR=y
CONFIG_SCANLOG=m
CONFIG_PPC_SMLPAR=y
@@ -36,10 +41,9 @@ CONFIG_DTL=y
# CONFIG_PPC_PMAC is not set
CONFIG_RTAS_FLASH=m
CONFIG_IBMEBUS=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
CONFIG_HZ_100=y
CONFIG_BINFMT_MISC=m
+CONFIG_PPC_TRANSACTIONAL_MEM=y
CONFIG_HOTPLUG_CPU=y
CONFIG_KEXEC=y
CONFIG_IRQ_ALL_CPUS=y
@@ -65,7 +69,6 @@ CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CT_PROTO_UDPLITE=m
@@ -112,20 +115,15 @@ CONFIG_NETFILTER_XT_MATCH_U32=m
CONFIG_NF_CONNTRACK_IPV4=m
CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_NF_NAT=m
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_NF_NAT_SNMP_BASIC=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
CONFIG_PROC_DEVICETREE=y
CONFIG_PARPORT=m
CONFIG_PARPORT_PC=m
@@ -146,7 +144,6 @@ CONFIG_CHR_DEV_SG=y
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
@@ -177,43 +174,36 @@ CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_NETCONSOLE=y
+CONFIG_NETPOLL_TRAP=y
CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_VENDOR_3COM=y
CONFIG_VORTEX=y
-CONFIG_IBMVETH=y
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-CONFIG_E100=y
CONFIG_ACENIC=m
CONFIG_ACENIC_OMIT_TIGON_I=y
-CONFIG_E1000=y
-CONFIG_E1000E=y
+CONFIG_PCNET32=y
CONFIG_TIGON3=y
-CONFIG_BNX2=m
CONFIG_CHELSIO_T1=m
-CONFIG_CHELSIO_T3=m
-CONFIG_CHELSIO_T4=m
+CONFIG_BE2NET=m
+CONFIG_S2IO=m
+CONFIG_IBMVETH=y
CONFIG_EHEA=y
-CONFIG_IXGBE=m
+CONFIG_E100=y
+CONFIG_E1000=y
+CONFIG_E1000E=y
CONFIG_IXGB=m
-CONFIG_S2IO=m
-CONFIG_MYRI10GE=m
-CONFIG_NETXEN_NIC=m
+CONFIG_IXGBE=m
CONFIG_MLX4_EN=m
+CONFIG_MYRI10GE=m
CONFIG_QLGE=m
-CONFIG_BE2NET=m
+CONFIG_NETXEN_NIC=m
CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
CONFIG_PPPOE=m
-CONFIG_NETCONSOLE=y
-CONFIG_NETPOLL_TRAP=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_EVDEV=m
CONFIG_INPUT_MISC=y
@@ -227,12 +217,9 @@ CONFIG_HVC_CONSOLE=y
CONFIG_HVC_RTAS=y
CONFIG_HVCS=m
CONFIG_IBM_BSR=m
-CONFIG_HW_RANDOM=m
-CONFIG_HW_RANDOM_PSERIES=m
CONFIG_GEN_RTC=y
CONFIG_RAW_DRIVER=y
CONFIG_MAX_RAW_DEVS=1024
-# CONFIG_HWMON is not set
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_OF=y
@@ -243,19 +230,17 @@ CONFIG_FB_MATROX_G=y
CONFIG_FB_RADEON=y
CONFIG_FB_IBM_GXT4500=y
CONFIG_LCD_PLATFORM=m
-CONFIG_DISPLAY_SUPPORT=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
-CONFIG_USB_HIDDEV=y
CONFIG_HID_GYRATION=y
CONFIG_HID_PANTHERLORD=y
CONFIG_HID_PETALYNX=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
CONFIG_HID_SUNPLUS=y
+CONFIG_USB_HIDDEV=y
CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
CONFIG_USB_MON=m
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_HCD_PPC_OF is not set
@@ -293,7 +278,6 @@ CONFIG_JFS_POSIX_ACL=y
CONFIG_JFS_SECURITY=y
CONFIG_XFS_FS=m
CONFIG_XFS_POSIX_ACL=y
-CONFIG_OCFS2_FS=m
CONFIG_BTRFS_FS=m
CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_NILFS2_FS=m
@@ -305,61 +289,49 @@ CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
CONFIG_CRAMFS=m
CONFIG_SQUASHFS=m
CONFIG_SQUASHFS_XATTR=y
-CONFIG_SQUASHFS_ZLIB=y
CONFIG_SQUASHFS_LZO=y
CONFIG_SQUASHFS_XZ=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_NFSD=m
CONFIG_NFSD_V3_ACL=y
CONFIG_NFSD_V4=y
-CONFIG_RPCSEC_GSS_SPKM3=m
CONFIG_CIFS=m
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
+CONFIG_NLS_DEFAULT="utf8"
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
CONFIG_CRC_T10DIF=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
CONFIG_LOCKUP_DETECTOR=y
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_DEBUG_STACK_USAGE=y
CONFIG_LATENCYTOP=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_SCHED_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_STACK_USAGE=y
CONFIG_CODE_PATCHING_SELFTEST=y
CONFIG_FTR_FIXUP_SELFTEST=y
CONFIG_MSI_BITMAP_SELFTEST=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
-CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_CCM=m
-CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_KHAZAD=m
@@ -369,7 +341,6 @@ CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_LZO=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_NX=y
CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
CONFIG_VIRTUALIZATION=y
diff --git a/arch/powerpc/crypto/Makefile b/arch/powerpc/crypto/Makefile
new file mode 100644
index 000000000000..2926fb9c570a
--- /dev/null
+++ b/arch/powerpc/crypto/Makefile
@@ -0,0 +1,9 @@
+#
+# powerpc/crypto/Makefile
+#
+# Arch-specific CryptoAPI modules.
+#
+
+obj-$(CONFIG_CRYPTO_SHA1_PPC) += sha1-powerpc.o
+
+sha1-powerpc-y := sha1-powerpc-asm.o sha1.o
diff --git a/arch/powerpc/crypto/sha1-powerpc-asm.S b/arch/powerpc/crypto/sha1-powerpc-asm.S
new file mode 100644
index 000000000000..a5f8264d2d3c
--- /dev/null
+++ b/arch/powerpc/crypto/sha1-powerpc-asm.S
@@ -0,0 +1,179 @@
+/*
+ * SHA-1 implementation for PowerPC.
+ *
+ * Copyright (C) 2005 Paul Mackerras <paulus@samba.org>
+ */
+
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * We roll the registers for T, A, B, C, D, E around on each
+ * iteration; T on iteration t is A on iteration t+1, and so on.
+ * We use registers 7 - 12 for this.
+ */
+#define RT(t) ((((t)+5)%6)+7)
+#define RA(t) ((((t)+4)%6)+7)
+#define RB(t) ((((t)+3)%6)+7)
+#define RC(t) ((((t)+2)%6)+7)
+#define RD(t) ((((t)+1)%6)+7)
+#define RE(t) ((((t)+0)%6)+7)
+
+/* We use registers 16 - 31 for the W values */
+#define W(t) (((t)%16)+16)
+
+#define LOADW(t) \
+ lwz W(t),(t)*4(r4)
+
+#define STEPD0_LOAD(t) \
+ andc r0,RD(t),RB(t); \
+ and r6,RB(t),RC(t); \
+ rotlwi RT(t),RA(t),5; \
+ or r6,r6,r0; \
+ add r0,RE(t),r15; \
+ add RT(t),RT(t),r6; \
+ add r14,r0,W(t); \
+ lwz W((t)+4),((t)+4)*4(r4); \
+ rotlwi RB(t),RB(t),30; \
+ add RT(t),RT(t),r14
+
+#define STEPD0_UPDATE(t) \
+ and r6,RB(t),RC(t); \
+ andc r0,RD(t),RB(t); \
+ rotlwi RT(t),RA(t),5; \
+ rotlwi RB(t),RB(t),30; \
+ or r6,r6,r0; \
+ add r0,RE(t),r15; \
+ xor r5,W((t)+4-3),W((t)+4-8); \
+ add RT(t),RT(t),r6; \
+ xor W((t)+4),W((t)+4-16),W((t)+4-14); \
+ add r0,r0,W(t); \
+ xor W((t)+4),W((t)+4),r5; \
+ add RT(t),RT(t),r0; \
+ rotlwi W((t)+4),W((t)+4),1
+
+#define STEPD1(t) \
+ xor r6,RB(t),RC(t); \
+ rotlwi RT(t),RA(t),5; \
+ rotlwi RB(t),RB(t),30; \
+ xor r6,r6,RD(t); \
+ add r0,RE(t),r15; \
+ add RT(t),RT(t),r6; \
+ add r0,r0,W(t); \
+ add RT(t),RT(t),r0
+
+#define STEPD1_UPDATE(t) \
+ xor r6,RB(t),RC(t); \
+ rotlwi RT(t),RA(t),5; \
+ rotlwi RB(t),RB(t),30; \
+ xor r6,r6,RD(t); \
+ add r0,RE(t),r15; \
+ xor r5,W((t)+4-3),W((t)+4-8); \
+ add RT(t),RT(t),r6; \
+ xor W((t)+4),W((t)+4-16),W((t)+4-14); \
+ add r0,r0,W(t); \
+ xor W((t)+4),W((t)+4),r5; \
+ add RT(t),RT(t),r0; \
+ rotlwi W((t)+4),W((t)+4),1
+
+#define STEPD2_UPDATE(t) \
+ and r6,RB(t),RC(t); \
+ and r0,RB(t),RD(t); \
+ rotlwi RT(t),RA(t),5; \
+ or r6,r6,r0; \
+ rotlwi RB(t),RB(t),30; \
+ and r0,RC(t),RD(t); \
+ xor r5,W((t)+4-3),W((t)+4-8); \
+ or r6,r6,r0; \
+ xor W((t)+4),W((t)+4-16),W((t)+4-14); \
+ add r0,RE(t),r15; \
+ add RT(t),RT(t),r6; \
+ add r0,r0,W(t); \
+ xor W((t)+4),W((t)+4),r5; \
+ add RT(t),RT(t),r0; \
+ rotlwi W((t)+4),W((t)+4),1
+
+#define STEP0LD4(t) \
+ STEPD0_LOAD(t); \
+ STEPD0_LOAD((t)+1); \
+ STEPD0_LOAD((t)+2); \
+ STEPD0_LOAD((t)+3)
+
+#define STEPUP4(t, fn) \
+ STEP##fn##_UPDATE(t); \
+ STEP##fn##_UPDATE((t)+1); \
+ STEP##fn##_UPDATE((t)+2); \
+ STEP##fn##_UPDATE((t)+3)
+
+#define STEPUP20(t, fn) \
+ STEPUP4(t, fn); \
+ STEPUP4((t)+4, fn); \
+ STEPUP4((t)+8, fn); \
+ STEPUP4((t)+12, fn); \
+ STEPUP4((t)+16, fn)
+
+_GLOBAL(powerpc_sha_transform)
+ PPC_STLU r1,-STACKFRAMESIZE(r1)
+ SAVE_8GPRS(14, r1)
+ SAVE_10GPRS(22, r1)
+
+ /* Load up A - E */
+ lwz RA(0),0(r3) /* A */
+ lwz RB(0),4(r3) /* B */
+ lwz RC(0),8(r3) /* C */
+ lwz RD(0),12(r3) /* D */
+ lwz RE(0),16(r3) /* E */
+
+ LOADW(0)
+ LOADW(1)
+ LOADW(2)
+ LOADW(3)
+
+ lis r15,0x5a82 /* K0-19 */
+ ori r15,r15,0x7999
+ STEP0LD4(0)
+ STEP0LD4(4)
+ STEP0LD4(8)
+ STEPUP4(12, D0)
+ STEPUP4(16, D0)
+
+ lis r15,0x6ed9 /* K20-39 */
+ ori r15,r15,0xeba1
+ STEPUP20(20, D1)
+
+ lis r15,0x8f1b /* K40-59 */
+ ori r15,r15,0xbcdc
+ STEPUP20(40, D2)
+
+ lis r15,0xca62 /* K60-79 */
+ ori r15,r15,0xc1d6
+ STEPUP4(60, D1)
+ STEPUP4(64, D1)
+ STEPUP4(68, D1)
+ STEPUP4(72, D1)
+ lwz r20,16(r3)
+ STEPD1(76)
+ lwz r19,12(r3)
+ STEPD1(77)
+ lwz r18,8(r3)
+ STEPD1(78)
+ lwz r17,4(r3)
+ STEPD1(79)
+
+ lwz r16,0(r3)
+ add r20,RE(80),r20
+ add RD(0),RD(80),r19
+ add RC(0),RC(80),r18
+ add RB(0),RB(80),r17
+ add RA(0),RA(80),r16
+ mr RE(0),r20
+ stw RA(0),0(r3)
+ stw RB(0),4(r3)
+ stw RC(0),8(r3)
+ stw RD(0),12(r3)
+ stw RE(0),16(r3)
+
+ REST_8GPRS(14, r1)
+ REST_10GPRS(22, r1)
+ addi r1,r1,STACKFRAMESIZE
+ blr
diff --git a/arch/powerpc/crypto/sha1.c b/arch/powerpc/crypto/sha1.c
new file mode 100644
index 000000000000..f9e8b9491efc
--- /dev/null
+++ b/arch/powerpc/crypto/sha1.c
@@ -0,0 +1,157 @@
+/*
+ * Cryptographic API.
+ *
+ * powerpc implementation of the SHA1 Secure Hash Algorithm.
+ *
+ * Derived from cryptoapi implementation, adapted for in-place
+ * scatterlist interface.
+ *
+ * Derived from "crypto/sha1.c"
+ * Copyright (c) Alan Smithee.
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) Jean-Francois Dive <jef@linuxbe.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 <crypto/internal/hash.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/cryptohash.h>
+#include <linux/types.h>
+#include <crypto/sha.h>
+#include <asm/byteorder.h>
+
+extern void powerpc_sha_transform(u32 *state, const u8 *src, u32 *temp);
+
+static int sha1_init(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 sha1_update(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;
+
+ partial = sctx->count & 0x3f;
+ sctx->count += len;
+ done = 0;
+ src = data;
+
+ if ((partial + len) > 63) {
+ u32 temp[SHA_WORKSPACE_WORDS];
+
+ if (partial) {
+ done = -partial;
+ memcpy(sctx->buffer + partial, data, done + 64);
+ src = sctx->buffer;
+ }
+
+ do {
+ powerpc_sha_transform(sctx->state, src, temp);
+ done += 64;
+ src = data + done;
+ } while (done + 63 < len);
+
+ memset(temp, 0, sizeof(temp));
+ partial = 0;
+ }
+ memcpy(sctx->buffer + partial, src, len - done);
+
+ return 0;
+}
+
+
+/* Add padding and return the message digest. */
+static int sha1_final(struct shash_desc *desc, u8 *out)
+{
+ struct sha1_state *sctx = shash_desc_ctx(desc);
+ __be32 *dst = (__be32 *)out;
+ u32 i, index, padlen;
+ __be64 bits;
+ static const u8 padding[64] = { 0x80, };
+
+ bits = cpu_to_be64(sctx->count << 3);
+
+ /* Pad out to 56 mod 64 */
+ index = sctx->count & 0x3f;
+ padlen = (index < 56) ? (56 - index) : ((64+56) - index);
+ sha1_update(desc, padding, padlen);
+
+ /* Append length */
+ sha1_update(desc, (const u8 *)&bits, sizeof(bits));
+
+ /* Store state in digest */
+ for (i = 0; i < 5; i++)
+ dst[i] = cpu_to_be32(sctx->state[i]);
+
+ /* Wipe context */
+ memset(sctx, 0, sizeof *sctx);
+
+ return 0;
+}
+
+static int sha1_export(struct shash_desc *desc, void *out)
+{
+ struct sha1_state *sctx = shash_desc_ctx(desc);
+
+ memcpy(out, sctx, sizeof(*sctx));
+ return 0;
+}
+
+static int sha1_import(struct shash_desc *desc, const void *in)
+{
+ struct sha1_state *sctx = shash_desc_ctx(desc);
+
+ memcpy(sctx, in, sizeof(*sctx));
+ return 0;
+}
+
+static struct shash_alg alg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .init = sha1_init,
+ .update = sha1_update,
+ .final = sha1_final,
+ .export = sha1_export,
+ .import = sha1_import,
+ .descsize = sizeof(struct sha1_state),
+ .statesize = sizeof(struct sha1_state),
+ .base = {
+ .cra_name = "sha1",
+ .cra_driver_name= "sha1-powerpc",
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+};
+
+static int __init sha1_powerpc_mod_init(void)
+{
+ return crypto_register_shash(&alg);
+}
+
+static void __exit sha1_powerpc_mod_fini(void)
+{
+ crypto_unregister_shash(&alg);
+}
+
+module_init(sha1_powerpc_mod_init);
+module_exit(sha1_powerpc_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm");
+
+MODULE_ALIAS("sha1-powerpc");
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 76f81bd64f1d..fb3245e928ea 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -106,37 +106,37 @@ extern const char *powerpc_base_platform;
/* CPU kernel features */
/* Retain the 32b definitions all use bottom half of word */
-#define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0000000000000001)
-#define CPU_FTR_L2CR ASM_CONST(0x0000000000000002)
-#define CPU_FTR_SPEC7450 ASM_CONST(0x0000000000000004)
-#define CPU_FTR_ALTIVEC ASM_CONST(0x0000000000000008)
-#define CPU_FTR_TAU ASM_CONST(0x0000000000000010)
-#define CPU_FTR_CAN_DOZE ASM_CONST(0x0000000000000020)
-#define CPU_FTR_USE_TB ASM_CONST(0x0000000000000040)
-#define CPU_FTR_L2CSR ASM_CONST(0x0000000000000080)
-#define CPU_FTR_601 ASM_CONST(0x0000000000000100)
-#define CPU_FTR_DBELL ASM_CONST(0x0000000000000200)
-#define CPU_FTR_CAN_NAP ASM_CONST(0x0000000000000400)
-#define CPU_FTR_L3CR ASM_CONST(0x0000000000000800)
-#define CPU_FTR_L3_DISABLE_NAP ASM_CONST(0x0000000000001000)
-#define CPU_FTR_NAP_DISABLE_L2_PR ASM_CONST(0x0000000000002000)
-#define CPU_FTR_DUAL_PLL_750FX ASM_CONST(0x0000000000004000)
-#define CPU_FTR_NO_DPM ASM_CONST(0x0000000000008000)
-#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)
-#define CPU_FTR_FPU_UNAVAILABLE ASM_CONST(0x0000000000800000)
-#define CPU_FTR_UNIFIED_ID_CACHE ASM_CONST(0x0000000001000000)
-#define CPU_FTR_SPE ASM_CONST(0x0000000002000000)
-#define CPU_FTR_NEED_PAIRED_STWCX ASM_CONST(0x0000000004000000)
-#define CPU_FTR_LWSYNC ASM_CONST(0x0000000008000000)
-#define CPU_FTR_NOEXECUTE ASM_CONST(0x0000000010000000)
-#define CPU_FTR_INDEXED_DCR ASM_CONST(0x0000000020000000)
-#define CPU_FTR_EMB_HV ASM_CONST(0x0000000040000000)
+#define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x00000001)
+#define CPU_FTR_L2CR ASM_CONST(0x00000002)
+#define CPU_FTR_SPEC7450 ASM_CONST(0x00000004)
+#define CPU_FTR_ALTIVEC ASM_CONST(0x00000008)
+#define CPU_FTR_TAU ASM_CONST(0x00000010)
+#define CPU_FTR_CAN_DOZE ASM_CONST(0x00000020)
+#define CPU_FTR_USE_TB ASM_CONST(0x00000040)
+#define CPU_FTR_L2CSR ASM_CONST(0x00000080)
+#define CPU_FTR_601 ASM_CONST(0x00000100)
+#define CPU_FTR_DBELL ASM_CONST(0x00000200)
+#define CPU_FTR_CAN_NAP ASM_CONST(0x00000400)
+#define CPU_FTR_L3CR ASM_CONST(0x00000800)
+#define CPU_FTR_L3_DISABLE_NAP ASM_CONST(0x00001000)
+#define CPU_FTR_NAP_DISABLE_L2_PR ASM_CONST(0x00002000)
+#define CPU_FTR_DUAL_PLL_750FX ASM_CONST(0x00004000)
+#define CPU_FTR_NO_DPM ASM_CONST(0x00008000)
+#define CPU_FTR_476_DD2 ASM_CONST(0x00010000)
+#define CPU_FTR_NEED_COHERENT ASM_CONST(0x00020000)
+#define CPU_FTR_NO_BTIC ASM_CONST(0x00040000)
+#define CPU_FTR_DEBUG_LVL_EXC ASM_CONST(0x00080000)
+#define CPU_FTR_NODSISRALIGN ASM_CONST(0x00100000)
+#define CPU_FTR_PPC_LE ASM_CONST(0x00200000)
+#define CPU_FTR_REAL_LE ASM_CONST(0x00400000)
+#define CPU_FTR_FPU_UNAVAILABLE ASM_CONST(0x00800000)
+#define CPU_FTR_UNIFIED_ID_CACHE ASM_CONST(0x01000000)
+#define CPU_FTR_SPE ASM_CONST(0x02000000)
+#define CPU_FTR_NEED_PAIRED_STWCX ASM_CONST(0x04000000)
+#define CPU_FTR_LWSYNC ASM_CONST(0x08000000)
+#define CPU_FTR_NOEXECUTE ASM_CONST(0x10000000)
+#define CPU_FTR_INDEXED_DCR ASM_CONST(0x20000000)
+#define CPU_FTR_EMB_HV ASM_CONST(0x40000000)
/*
* Add the 64-bit processor unique features in the top half of the word;
@@ -148,29 +148,33 @@ extern const char *powerpc_base_platform;
#define LONG_ASM_CONST(x) 0
#endif
-#define CPU_FTR_HVMODE LONG_ASM_CONST(0x0000000200000000)
-#define CPU_FTR_ARCH_201 LONG_ASM_CONST(0x0000000400000000)
-#define CPU_FTR_ARCH_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_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_VSX LONG_ASM_CONST(0x0010000000000000)
-#define CPU_FTR_SAO LONG_ASM_CONST(0x0020000000000000)
-#define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0040000000000000)
-#define CPU_FTR_UNALIGNED_LD_STD LONG_ASM_CONST(0x0080000000000000)
-#define CPU_FTR_ASYM_SMT LONG_ASM_CONST(0x0100000000000000)
-#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)
-#define CPU_FTR_VMX_COPY LONG_ASM_CONST(0x2000000000000000)
+#define CPU_FTR_HVMODE LONG_ASM_CONST(0x0000000100000000)
+#define CPU_FTR_ARCH_201 LONG_ASM_CONST(0x0000000200000000)
+#define CPU_FTR_ARCH_206 LONG_ASM_CONST(0x0000000400000000)
+#define CPU_FTR_CFAR LONG_ASM_CONST(0x0000000800000000)
+#define CPU_FTR_IABR LONG_ASM_CONST(0x0000001000000000)
+#define CPU_FTR_MMCRA LONG_ASM_CONST(0x0000002000000000)
+#define CPU_FTR_CTRL LONG_ASM_CONST(0x0000004000000000)
+#define CPU_FTR_SMT LONG_ASM_CONST(0x0000008000000000)
+#define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000010000000000)
+#define CPU_FTR_PURR LONG_ASM_CONST(0x0000020000000000)
+#define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000040000000000)
+#define CPU_FTR_SPURR LONG_ASM_CONST(0x0000080000000000)
+#define CPU_FTR_DSCR LONG_ASM_CONST(0x0000100000000000)
+#define CPU_FTR_VSX LONG_ASM_CONST(0x0000200000000000)
+#define CPU_FTR_SAO LONG_ASM_CONST(0x0000400000000000)
+#define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0000800000000000)
+#define CPU_FTR_UNALIGNED_LD_STD LONG_ASM_CONST(0x0001000000000000)
+#define CPU_FTR_ASYM_SMT LONG_ASM_CONST(0x0002000000000000)
+#define CPU_FTR_STCX_CHECKS_ADDRESS LONG_ASM_CONST(0x0004000000000000)
+#define CPU_FTR_POPCNTB LONG_ASM_CONST(0x0008000000000000)
+#define CPU_FTR_POPCNTD LONG_ASM_CONST(0x0010000000000000)
+#define CPU_FTR_ICSWX LONG_ASM_CONST(0x0020000000000000)
+#define CPU_FTR_VMX_COPY LONG_ASM_CONST(0x0040000000000000)
+#define CPU_FTR_TM LONG_ASM_CONST(0x0080000000000000)
+#define CPU_FTR_BCTAR LONG_ASM_CONST(0x0100000000000000)
+#define CPU_FTR_HAS_PPR LONG_ASM_CONST(0x0200000000000000)
+#define CPU_FTR_DAWR LONG_ASM_CONST(0x0400000000000000)
#ifndef __ASSEMBLY__
@@ -216,6 +220,13 @@ extern const char *powerpc_base_platform;
#define PPC_FEATURE_HAS_EFP_DOUBLE_COMP 0
#endif
+/* We only set the TM feature if the kernel was compiled with TM supprt */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+#define CPU_FTR_TM_COMP CPU_FTR_TM
+#else
+#define CPU_FTR_TM_COMP 0
+#endif
+
/* We need to mark all pages as being coherent if we're SMP or we have a
* 74[45]x and an MPC107 host bridge. Also 83xx and PowerQUICC II
* require it for PCI "streaming/prefetch" to work properly.
@@ -400,7 +411,8 @@ extern const char *powerpc_base_platform;
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_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY)
+ CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | \
+ CPU_FTR_VMX_COPY | CPU_FTR_HAS_PPR)
#define CPU_FTRS_POWER8 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_ARCH_206 |\
CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -408,7 +420,9 @@ extern const char *powerpc_base_platform;
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
CPU_FTR_DSCR | CPU_FTR_SAO | \
CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
- CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY)
+ CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
+ CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | CPU_FTR_BCTAR | \
+ CPU_FTR_TM_COMP)
#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 | \
diff --git a/arch/powerpc/include/asm/cputime.h b/arch/powerpc/include/asm/cputime.h
index 483733bd06d4..607559ab271f 100644
--- a/arch/powerpc/include/asm/cputime.h
+++ b/arch/powerpc/include/asm/cputime.h
@@ -8,7 +8,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * If we have CONFIG_VIRT_CPU_ACCOUNTING, we measure cpu time in
+ * If we have CONFIG_VIRT_CPU_ACCOUNTING_NATIVE, we measure cpu time in
* the same units as the timebase. Otherwise we measure cpu time
* in jiffies using the generic definitions.
*/
@@ -16,7 +16,7 @@
#ifndef __POWERPC_CPUTIME_H
#define __POWERPC_CPUTIME_H
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
#include <asm-generic/cputime.h>
#ifdef __KERNEL__
static inline void setup_cputime_one_jiffy(void) { }
@@ -231,5 +231,5 @@ static inline cputime_t clock_t_to_cputime(const unsigned long clk)
static inline void arch_vtime_task_switch(struct task_struct *tsk) { }
#endif /* __KERNEL__ */
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
#endif /* __POWERPC_CPUTIME_H */
diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h
index 607e4eeeb694..5fa6b20eba10 100644
--- a/arch/powerpc/include/asm/dbell.h
+++ b/arch/powerpc/include/asm/dbell.h
@@ -28,8 +28,36 @@ enum ppc_dbell {
PPC_G_DBELL = 2, /* guest doorbell */
PPC_G_DBELL_CRIT = 3, /* guest critical doorbell */
PPC_G_DBELL_MC = 4, /* guest mcheck doorbell */
+ PPC_DBELL_SERVER = 5, /* doorbell on server */
};
+#ifdef CONFIG_PPC_BOOK3S
+
+#define PPC_DBELL_MSGTYPE PPC_DBELL_SERVER
+#define SPRN_DOORBELL_CPUTAG SPRN_TIR
+#define PPC_DBELL_TAG_MASK 0x7f
+
+static inline void _ppc_msgsnd(u32 msg)
+{
+ if (cpu_has_feature(CPU_FTR_HVMODE))
+ __asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg));
+ else
+ __asm__ __volatile__ (PPC_MSGSNDP(%0) : : "r" (msg));
+}
+
+#else /* CONFIG_PPC_BOOK3S */
+
+#define PPC_DBELL_MSGTYPE PPC_DBELL
+#define SPRN_DOORBELL_CPUTAG SPRN_PIR
+#define PPC_DBELL_TAG_MASK 0x3fff
+
+static inline void _ppc_msgsnd(u32 msg)
+{
+ __asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg));
+}
+
+#endif /* CONFIG_PPC_BOOK3S */
+
extern void doorbell_cause_ipi(int cpu, unsigned long data);
extern void doorbell_exception(struct pt_regs *regs);
extern void doorbell_setup_this_cpu(void);
@@ -39,7 +67,7 @@ static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag)
u32 msg = PPC_DBELL_TYPE(type) | (flags & PPC_DBELL_MSG_BRDCAST) |
(tag & 0x07ffffff);
- __asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg));
+ _ppc_msgsnd(msg);
}
#endif /* _ASM_POWERPC_DBELL_H */
diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h
index 32de2577bb6d..d2516308ed1e 100644
--- a/arch/powerpc/include/asm/debug.h
+++ b/arch/powerpc/include/asm/debug.h
@@ -4,6 +4,8 @@
#ifndef _ASM_POWERPC_DEBUG_H
#define _ASM_POWERPC_DEBUG_H
+#include <asm/hw_breakpoint.h>
+
struct pt_regs;
extern struct dentry *powerpc_debugfs_root;
@@ -15,7 +17,7 @@ extern int (*__debugger_ipi)(struct pt_regs *regs);
extern int (*__debugger_bpt)(struct pt_regs *regs);
extern int (*__debugger_sstep)(struct pt_regs *regs);
extern int (*__debugger_iabr_match)(struct pt_regs *regs);
-extern int (*__debugger_dabr_match)(struct pt_regs *regs);
+extern int (*__debugger_break_match)(struct pt_regs *regs);
extern int (*__debugger_fault_handler)(struct pt_regs *regs);
#define DEBUGGER_BOILERPLATE(__NAME) \
@@ -31,7 +33,7 @@ DEBUGGER_BOILERPLATE(debugger_ipi)
DEBUGGER_BOILERPLATE(debugger_bpt)
DEBUGGER_BOILERPLATE(debugger_sstep)
DEBUGGER_BOILERPLATE(debugger_iabr_match)
-DEBUGGER_BOILERPLATE(debugger_dabr_match)
+DEBUGGER_BOILERPLATE(debugger_break_match)
DEBUGGER_BOILERPLATE(debugger_fault_handler)
#else
@@ -40,17 +42,18 @@ static inline int debugger_ipi(struct pt_regs *regs) { return 0; }
static inline int debugger_bpt(struct pt_regs *regs) { return 0; }
static inline int debugger_sstep(struct pt_regs *regs) { return 0; }
static inline int debugger_iabr_match(struct pt_regs *regs) { return 0; }
-static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; }
+static inline int debugger_break_match(struct pt_regs *regs) { return 0; }
static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
#endif
-extern int set_dabr(unsigned long dabr, unsigned long dabrx);
+int set_breakpoint(struct arch_hw_breakpoint *brk);
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
extern void do_send_trap(struct pt_regs *regs, unsigned long address,
unsigned long error_code, int signal_code, int brkpt);
#else
-extern void do_dabr(struct pt_regs *regs, unsigned long address,
- unsigned long error_code);
+
+extern void do_break(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code);
#endif
#endif /* _ASM_POWERPC_DEBUG_H */
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index a8fb03e22770..a80e32b46c11 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -201,6 +201,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev);
void __init eeh_addr_cache_build(void);
void eeh_add_device_tree_early(struct device_node *);
void eeh_add_device_tree_late(struct pci_bus *);
+void eeh_add_sysfs_files(struct pci_bus *);
void eeh_remove_bus_device(struct pci_dev *, int);
/**
@@ -240,6 +241,8 @@ static inline void eeh_add_device_tree_early(struct device_node *dn) { }
static inline void eeh_add_device_tree_late(struct pci_bus *bus) { }
+static inline void eeh_add_sysfs_files(struct pci_bus *bus) { }
+
static inline void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) { }
static inline void eeh_lock(void) { }
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index ad708dda3ba3..05e6d2ee1db9 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -47,9 +47,10 @@
#define EX_R3 64
#define EX_LR 72
#define EX_CFAR 80
+#define EX_PPR 88 /* SMT thread status register (priority) */
#ifdef CONFIG_RELOCATABLE
-#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
+#define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
ld r12,PACAKBASE(r13); /* get high part of &label */ \
mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \
LOAD_HANDLER(r12,label); \
@@ -60,13 +61,15 @@
blr;
#else
/* If not relocatable, we can jump directly -- and save messing with LR */
-#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
+#define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \
mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \
li r10,MSR_RI; \
mtmsrd r10,1; /* Set RI (EE=0) */ \
b label;
#endif
+#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
+ __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
/*
* As EXCEPTION_PROLOG_PSERIES(), except we've already got relocation on
@@ -74,6 +77,7 @@
* case EXCEPTION_RELON_PROLOG_PSERIES_1 will be using lr.
*/
#define EXCEPTION_RELON_PROLOG_PSERIES(area, label, h, extra, vec) \
+ EXCEPTION_PROLOG_0(area); \
EXCEPTION_PROLOG_1(area, extra, vec); \
EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)
@@ -107,14 +111,59 @@
#define RESTORE_LR(reg, area)
#endif
-#define __EXCEPTION_PROLOG_1(area, extra, vec) \
+/*
+ * PPR save/restore macros used in exceptions_64s.S
+ * Used for P7 or later processors
+ */
+#define SAVE_PPR(area, ra, rb) \
+BEGIN_FTR_SECTION_NESTED(940) \
+ ld ra,PACACURRENT(r13); \
+ ld rb,area+EX_PPR(r13); /* Read PPR from paca */ \
+ std rb,TASKTHREADPPR(ra); \
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,940)
+
+#define RESTORE_PPR_PACA(area, ra) \
+BEGIN_FTR_SECTION_NESTED(941) \
+ ld ra,area+EX_PPR(r13); \
+ mtspr SPRN_PPR,ra; \
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,941)
+
+/*
+ * Increase the priority on systems where PPR save/restore is not
+ * implemented/ supported.
+ */
+#define HMT_MEDIUM_PPR_DISCARD \
+BEGIN_FTR_SECTION_NESTED(942) \
+ HMT_MEDIUM; \
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,0,942) /*non P7*/
+
+/*
+ * Get an SPR into a register if the CPU has the given feature
+ */
+#define OPT_GET_SPR(ra, spr, ftr) \
+BEGIN_FTR_SECTION_NESTED(943) \
+ mfspr ra,spr; \
+END_FTR_SECTION_NESTED(ftr,ftr,943)
+
+/*
+ * Save a register to the PACA if the CPU has the given feature
+ */
+#define OPT_SAVE_REG_TO_PACA(offset, ra, ftr) \
+BEGIN_FTR_SECTION_NESTED(943) \
+ std ra,offset(r13); \
+END_FTR_SECTION_NESTED(ftr,ftr,943)
+
+#define EXCEPTION_PROLOG_0(area) \
GET_PACA(r13); \
- std r9,area+EX_R9(r13); /* save r9 - r12 */ \
- std r10,area+EX_R10(r13); \
- 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); \
+ std r9,area+EX_R9(r13); /* save r9 */ \
+ OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR); \
+ HMT_MEDIUM; \
+ std r10,area+EX_R10(r13); /* save r10 - r12 */ \
+ OPT_GET_SPR(r10, SPRN_CFAR, CPU_FTR_CFAR)
+
+#define __EXCEPTION_PROLOG_1(area, extra, vec) \
+ OPT_SAVE_REG_TO_PACA(area+EX_PPR, r9, CPU_FTR_HAS_PPR); \
+ OPT_SAVE_REG_TO_PACA(area+EX_CFAR, r10, CPU_FTR_CFAR); \
SAVE_LR(r10, area); \
mfcr r9; \
extra(vec); \
@@ -139,6 +188,7 @@
__EXCEPTION_PROLOG_PSERIES_1(label, h)
#define EXCEPTION_PROLOG_PSERIES(area, label, h, extra, vec) \
+ EXCEPTION_PROLOG_0(area); \
EXCEPTION_PROLOG_1(area, extra, vec); \
EXCEPTION_PROLOG_PSERIES_1(label, h);
@@ -149,10 +199,14 @@
#define __KVM_HANDLER(area, h, n) \
do_kvm_##n: \
+ BEGIN_FTR_SECTION_NESTED(947) \
+ ld r10,area+EX_CFAR(r13); \
+ std r10,HSTATE_CFAR(r13); \
+ END_FTR_SECTION_NESTED(CPU_FTR_CFAR,CPU_FTR_CFAR,947); \
ld r10,area+EX_R10(r13); \
- stw r9,HSTATE_SCRATCH1(r13); \
+ stw r9,HSTATE_SCRATCH1(r13); \
ld r9,area+EX_R9(r13); \
- std r12,HSTATE_SCRATCH0(r13); \
+ std r12,HSTATE_SCRATCH0(r13); \
li r12,n; \
b kvmppc_interrupt
@@ -224,8 +278,10 @@ do_kvm_##n: \
std r10,0(r1); /* make stack chain pointer */ \
std r0,GPR0(r1); /* save r0 in stackframe */ \
std r10,GPR1(r1); /* save r1 in stackframe */ \
+ beq 4f; /* if from kernel mode */ \
ACCOUNT_CPU_USER_ENTRY(r9, r10); \
- std r2,GPR2(r1); /* save r2 in stackframe */ \
+ SAVE_PPR(area, r9, r10); \
+4: std r2,GPR2(r1); /* save r2 in stackframe */ \
SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \
SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \
ld r9,area+EX_R9(r13); /* move r9, r10 to stackframe */ \
@@ -266,45 +322,74 @@ do_kvm_##n: \
. = loc; \
.globl label##_pSeries; \
label##_pSeries: \
- HMT_MEDIUM; \
+ HMT_MEDIUM_PPR_DISCARD; \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
EXC_STD, KVMTEST_PR, vec)
+/* Version of above for when we have to branch out-of-line */
+#define STD_EXCEPTION_PSERIES_OOL(vec, label) \
+ .globl label##_pSeries; \
+label##_pSeries: \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, vec); \
+ EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_STD)
+
#define STD_EXCEPTION_HV(loc, vec, label) \
. = loc; \
.globl label##_hv; \
label##_hv: \
- HMT_MEDIUM; \
+ HMT_MEDIUM_PPR_DISCARD; \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
EXC_HV, KVMTEST, vec)
+/* Version of above for when we have to branch out-of-line */
+#define STD_EXCEPTION_HV_OOL(vec, label) \
+ .globl label##_hv; \
+label##_hv: \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec); \
+ EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV)
+
#define STD_RELON_EXCEPTION_PSERIES(loc, vec, label) \
. = loc; \
.globl label##_relon_pSeries; \
label##_relon_pSeries: \
- HMT_MEDIUM; \
+ HMT_MEDIUM_PPR_DISCARD; \
/* No guest interrupts come through here */ \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
EXC_STD, KVMTEST_PR, vec)
+#define STD_RELON_EXCEPTION_PSERIES_OOL(vec, label) \
+ .globl label##_relon_pSeries; \
+label##_relon_pSeries: \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, vec); \
+ EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_STD)
+
#define STD_RELON_EXCEPTION_HV(loc, vec, label) \
. = loc; \
.globl label##_relon_hv; \
label##_relon_hv: \
- HMT_MEDIUM; \
+ HMT_MEDIUM_PPR_DISCARD; \
/* No guest interrupts come through here */ \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
EXC_HV, KVMTEST, vec)
+#define STD_RELON_EXCEPTION_HV_OOL(vec, label) \
+ .globl label##_relon_hv; \
+label##_relon_hv: \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec); \
+ EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_HV)
+
/* This associate vector numbers with bits in paca->irq_happened */
#define SOFTEN_VALUE_0x500 PACA_IRQ_EE
#define SOFTEN_VALUE_0x502 PACA_IRQ_EE
#define SOFTEN_VALUE_0x900 PACA_IRQ_DEC
#define SOFTEN_VALUE_0x982 PACA_IRQ_DEC
+#define SOFTEN_VALUE_0xa00 PACA_IRQ_DBELL
+#define SOFTEN_VALUE_0xe80 PACA_IRQ_DBELL
+#define SOFTEN_VALUE_0xe82 PACA_IRQ_DBELL
#define __SOFTEN_TEST(h, vec) \
lbz r10,PACASOFTIRQEN(r13); \
@@ -329,10 +414,12 @@ label##_relon_hv: \
#define SOFTEN_NOTEST_HV(vec) _SOFTEN_TEST(EXC_HV, vec)
#define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \
- HMT_MEDIUM; \
+ HMT_MEDIUM_PPR_DISCARD; \
SET_SCRATCH0(r13); /* save r13 */ \
- __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \
+ EXCEPTION_PROLOG_0(PACA_EXGEN); \
+ __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \
EXCEPTION_PROLOG_PSERIES_1(label##_common, h);
+
#define _MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \
__MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)
@@ -350,9 +437,16 @@ label##_hv: \
_MASKABLE_EXCEPTION_PSERIES(vec, label, \
EXC_HV, SOFTEN_TEST_HV)
+#define MASKABLE_EXCEPTION_HV_OOL(vec, label) \
+ .globl label##_hv; \
+label##_hv: \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_TEST_HV, vec); \
+ EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV);
+
#define __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) \
- HMT_MEDIUM; \
+ HMT_MEDIUM_PPR_DISCARD; \
SET_SCRATCH0(r13); /* save r13 */ \
+ EXCEPTION_PROLOG_0(PACA_EXGEN); \
__EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \
EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, h);
#define _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) \
@@ -372,6 +466,12 @@ label##_relon_hv: \
_MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, \
EXC_HV, SOFTEN_NOTEST_HV)
+#define MASKABLE_RELON_EXCEPTION_HV_OOL(vec, label) \
+ .globl label##_relon_hv; \
+label##_relon_hv: \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_NOTEST_HV, vec); \
+ EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV);
+
/*
* Our exception common code can be passed various "additions"
* to specify the behaviour of interrupts, whether to kick the
diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h
index 973cc3be011b..097dee57a7a9 100644
--- a/arch/powerpc/include/asm/firmware.h
+++ b/arch/powerpc/include/asm/firmware.h
@@ -50,6 +50,7 @@
#define FW_FEATURE_OPAL ASM_CONST(0x0000000010000000)
#define FW_FEATURE_OPALv2 ASM_CONST(0x0000000020000000)
#define FW_FEATURE_SET_MODE ASM_CONST(0x0000000040000000)
+#define FW_FEATURE_BEST_ENERGY ASM_CONST(0x0000000080000000)
#ifndef __ASSEMBLY__
@@ -64,7 +65,7 @@ enum {
FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR |
FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO |
- FW_FEATURE_SET_MODE,
+ FW_FEATURE_SET_MODE | FW_FEATURE_BEST_ENERGY,
FW_FEATURE_PSERIES_ALWAYS = 0,
FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2,
FW_FEATURE_POWERNV_ALWAYS = 0,
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 0975e5c0bb19..4bc2c3dad6ad 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -395,6 +395,15 @@ static inline unsigned long cmo_get_page_size(void)
{
return CMO_PageSize;
}
+
+extern long pSeries_enable_reloc_on_exc(void);
+extern long pSeries_disable_reloc_on_exc(void);
+
+#else
+
+#define pSeries_enable_reloc_on_exc() do {} while (0)
+#define pSeries_disable_reloc_on_exc() do {} while (0)
+
#endif /* CONFIG_PPC_PSERIES */
#endif /* __ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index 423424599dad..eb0f4ac75c4c 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -24,16 +24,30 @@
#define _PPC_BOOK3S_64_HW_BREAKPOINT_H
#ifdef __KERNEL__
-#ifdef CONFIG_HAVE_HW_BREAKPOINT
-
struct arch_hw_breakpoint {
unsigned long address;
- unsigned long dabrx;
- int type;
- u8 len; /* length of the target data symbol */
- bool extraneous_interrupt;
+ u16 type;
+ u16 len; /* length of the target data symbol */
};
+/* Note: Don't change the the first 6 bits below as they are in the same order
+ * as the dabr and dabrx.
+ */
+#define HW_BRK_TYPE_READ 0x01
+#define HW_BRK_TYPE_WRITE 0x02
+#define HW_BRK_TYPE_TRANSLATE 0x04
+#define HW_BRK_TYPE_USER 0x08
+#define HW_BRK_TYPE_KERNEL 0x10
+#define HW_BRK_TYPE_HYP 0x20
+#define HW_BRK_TYPE_EXTRANEOUS_IRQ 0x80
+
+/* bits that overlap with the bottom 3 bits of the dabr */
+#define HW_BRK_TYPE_RDWR (HW_BRK_TYPE_READ | HW_BRK_TYPE_WRITE)
+#define HW_BRK_TYPE_DABR (HW_BRK_TYPE_RDWR | HW_BRK_TYPE_TRANSLATE)
+#define HW_BRK_TYPE_PRIV_ALL (HW_BRK_TYPE_USER | HW_BRK_TYPE_KERNEL | \
+ HW_BRK_TYPE_HYP)
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
#include <linux/kdebug.h>
#include <asm/reg.h>
#include <asm/debug.h>
@@ -43,8 +57,6 @@ struct pmu;
struct perf_sample_data;
#define HW_BREAKPOINT_ALIGN 0x7
-/* Maximum permissible length of any HW Breakpoint */
-#define HW_BREAKPOINT_LEN 0x8
extern int hw_breakpoint_slots(int type);
extern int arch_bp_generic_fields(int type, int *gen_bp_type);
@@ -62,7 +74,12 @@ extern void ptrace_triggered(struct perf_event *bp,
struct perf_sample_data *data, struct pt_regs *regs);
static inline void hw_breakpoint_disable(void)
{
- set_dabr(0, 0);
+ struct arch_hw_breakpoint brk;
+
+ brk.address = 0;
+ brk.type = 0;
+ brk.len = 0;
+ set_breakpoint(&brk);
}
extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs);
diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h
index 88609b23b775..cdc3d2717cc6 100644
--- a/arch/powerpc/include/asm/kvm_book3s_asm.h
+++ b/arch/powerpc/include/asm/kvm_book3s_asm.h
@@ -93,6 +93,9 @@ struct kvmppc_host_state {
u64 host_dscr;
u64 dec_expires;
#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+ u64 cfar;
+#endif
};
struct kvmppc_book3s_shadow_vcpu {
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index ca9bf459db6a..d1bb86074721 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -37,10 +37,8 @@
#define KVM_MAX_VCPUS NR_CPUS
#define KVM_MAX_VCORES NR_CPUS
-#define KVM_MEMORY_SLOTS 32
-/* memory slots that does not exposed to userspace */
-#define KVM_PRIVATE_MEM_SLOTS 4
-#define KVM_MEM_SLOTS_NUM (KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS)
+#define KVM_USER_MEM_SLOTS 32
+#define KVM_MEM_SLOTS_NUM KVM_USER_MEM_SLOTS
#ifdef CONFIG_KVM_MMIO
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
@@ -440,6 +438,7 @@ struct kvm_vcpu_arch {
ulong uamor;
u32 ctrl;
ulong dabr;
+ ulong cfar;
#endif
u32 vrsave; /* also USPRG0 */
u32 mmucr;
@@ -522,6 +521,8 @@ struct kvm_vcpu_arch {
u8 sane;
u8 cpu_type;
u8 hcall_needed;
+ u8 epr_enabled;
+ u8 epr_needed;
u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 572aa7530619..44a657adf416 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -44,12 +44,11 @@ enum emulation_result {
EMULATE_DO_DCR, /* kvm_run filled with DCR request */
EMULATE_FAIL, /* can't emulate this instruction */
EMULATE_AGAIN, /* something went wrong. go again */
+ EMULATE_DO_PAPR, /* kvm_run filled with PAPR request */
};
extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
-extern char kvmppc_handlers_start[];
-extern unsigned long kvmppc_handler_len;
extern void kvmppc_handler_highmem(void);
extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
@@ -263,6 +262,15 @@ static inline void kvm_linear_init(void)
{}
#endif
+static inline void kvmppc_set_epr(struct kvm_vcpu *vcpu, u32 epr)
+{
+#ifdef CONFIG_KVM_BOOKE_HV
+ mtspr(SPRN_GEPR, epr);
+#elif defined(CONFIG_BOOKE)
+ vcpu->arch.epr = epr;
+#endif
+}
+
int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
struct kvm_config_tlb *cfg);
int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index 531fe0c3108f..b1e7f2af1016 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -145,7 +145,7 @@ struct dtl_entry {
extern struct kmem_cache *dtl_cache;
/*
- * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls
+ * When CONFIG_VIRT_CPU_ACCOUNTING_NATIVE = y, the cpu accounting code controls
* reading from the dispatch trace log. If other code wants to consume
* DTL entries, it can set this pointer to a function that will get
* called once for each DTL entry that gets processed.
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 19d9d96eb8d3..3d6b4100dac1 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -180,6 +180,10 @@ struct machdep_calls {
int (*set_dabr)(unsigned long dabr,
unsigned long dabrx);
+ /* Set DAWR for this platform, leave empty for default implemenation */
+ int (*set_dawr)(unsigned long dawr,
+ unsigned long dawrx);
+
#ifdef CONFIG_PPC32 /* XXX for now */
/* A general init function, called by ppc_init in init/main.c.
May be NULL. */
diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h
index 8c0ab2ca689c..885c040d6194 100644
--- a/arch/powerpc/include/asm/mpc5121.h
+++ b/arch/powerpc/include/asm/mpc5121.h
@@ -53,4 +53,21 @@ struct mpc512x_ccm {
u32 m4ccr; /* MSCAN4 CCR */
u8 res[0x98]; /* Reserved */
};
+
+/*
+ * LPC Module
+ */
+struct mpc512x_lpc {
+ u32 cs_cfg[8]; /* CS config */
+ u32 cs_ctrl; /* CS Control Register */
+ u32 cs_status; /* CS Status Register */
+ u32 burst_ctrl; /* CS Burst Control Register */
+ u32 deadcycle_ctrl; /* CS Deadcycle Control Register */
+ u32 holdcycle_ctrl; /* CS Holdcycle Control Register */
+ u32 alt; /* Address Latch Timing Register */
+};
+
+int mpc512x_cs_config(unsigned int cs, u32 val);
+int __init mpc5121_clk_init(void);
+
#endif /* __ASM_POWERPC_MPC5121_H__ */
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index e9e7a6999bb8..77c91e74b612 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -93,9 +93,9 @@ struct paca_struct {
* Now, starting in cacheline 2, the exception save areas
*/
/* used for most interrupts/exceptions */
- u64 exgen[11] __attribute__((aligned(0x80)));
- u64 exmc[11]; /* used for machine checks */
- u64 exslb[11]; /* used for SLB/segment table misses
+ u64 exgen[12] __attribute__((aligned(0x80)));
+ u64 exmc[12]; /* used for machine checks */
+ u64 exslb[12]; /* used for SLB/segment table misses
* on the linear mapping */
/* SLB related definitions */
u16 vmalloc_sllp;
@@ -137,6 +137,9 @@ struct paca_struct {
u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */
u8 nap_state_lost; /* NV GPR values lost in power7_idle */
u64 sprg3; /* Saved user-visible sprg */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ u64 tm_scratch; /* TM scratch area for reclaim */
+#endif
#ifdef CONFIG_PPC_POWERNV
/* Pointer to OPAL machine check event structure set by the
@@ -167,7 +170,6 @@ struct paca_struct {
};
extern struct paca_struct *paca;
-extern __initdata struct paca_struct boot_paca;
extern void initialise_paca(struct paca_struct *new_paca, int cpu);
extern void setup_paca(struct paca_struct *new_paca);
extern void allocate_pacas(void);
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index 9710be3a2d17..d0aec72722e9 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <asm/hw_irq.h>
+#include <linux/device.h>
#define MAX_HWEVENTS 8
#define MAX_EVENT_ALTERNATIVES 8
@@ -35,6 +36,7 @@ struct power_pmu {
void (*disable_pmc)(unsigned int pmc, unsigned long mmcr[]);
int (*limited_pmc_event)(u64 event_id);
u32 flags;
+ const struct attribute_group **attr_groups;
int n_generic;
int *generic_events;
int (*cache_events)[PERF_COUNT_HW_CACHE_MAX]
@@ -45,11 +47,11 @@ struct power_pmu {
/*
* Values for power_pmu.flags
*/
-#define PPMU_LIMITED_PMC5_6 1 /* PMC5/6 have limited function */
-#define PPMU_ALT_SIPR 2 /* uses alternate posn for SIPR/HV */
-#define PPMU_NO_SIPR 4 /* no SIPR/HV in MMCRA at all */
-#define PPMU_NO_CONT_SAMPLING 8 /* no continuous sampling */
-#define PPMU_SIAR_VALID 16 /* Processor has SIAR Valid bit */
+#define PPMU_LIMITED_PMC5_6 0x00000001 /* PMC5/6 have limited function */
+#define PPMU_ALT_SIPR 0x00000002 /* uses alternate posn for SIPR/HV */
+#define PPMU_NO_SIPR 0x00000004 /* no SIPR/HV in MMCRA at all */
+#define PPMU_NO_CONT_SAMPLING 0x00000008 /* no continuous sampling */
+#define PPMU_SIAR_VALID 0x00000010 /* Processor has SIAR Valid bit */
/*
* Values for flags to get_alternatives()
@@ -109,3 +111,27 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
* If an event_id is not subject to the constraint expressed by a particular
* field, then it will have 0 in both the mask and value for that field.
*/
+
+extern ssize_t power_events_sysfs_show(struct device *dev,
+ struct device_attribute *attr, char *page);
+
+/*
+ * EVENT_VAR() is same as PMU_EVENT_VAR with a suffix.
+ *
+ * Having a suffix allows us to have aliases in sysfs - eg: the generic
+ * event 'cpu-cycles' can have two entries in sysfs: 'cpu-cycles' and
+ * 'PM_CYC' where the latter is the name by which the event is known in
+ * POWER CPU specification.
+ */
+#define EVENT_VAR(_id, _suffix) event_attr_##_id##_suffix
+#define EVENT_PTR(_id, _suffix) &EVENT_VAR(_id, _suffix).attr.attr
+
+#define EVENT_ATTR(_name, _id, _suffix) \
+ PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_PM_##_id, \
+ power_events_sysfs_show)
+
+#define GENERIC_EVENT_ATTR(_name, _id) EVENT_ATTR(_name, _id, _g)
+#define GENERIC_EVENT_PTR(_id) EVENT_PTR(_id, _g)
+
+#define POWER_EVENT_ATTR(_name, _id) EVENT_ATTR(PM_##_name, _id, _p)
+#define POWER_EVENT_PTR(_id) EVENT_PTR(_id, _p)
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 51fb00a20d7e..8752bc8e34a3 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -100,6 +100,7 @@
#define PPC_INST_MFSPR_PVR 0x7c1f42a6
#define PPC_INST_MFSPR_PVR_MASK 0xfc1fffff
#define PPC_INST_MSGSND 0x7c00019c
+#define PPC_INST_MSGSNDP 0x7c00011c
#define PPC_INST_NOP 0x60000000
#define PPC_INST_POPCNTB 0x7c0000f4
#define PPC_INST_POPCNTB_MASK 0xfc0007fe
@@ -128,6 +129,9 @@
#define PPC_INST_TLBSRX_DOT 0x7c0006a5
#define PPC_INST_XXLOR 0xf0000510
#define PPC_INST_XVCPSGNDP 0xf0000780
+#define PPC_INST_TRECHKPT 0x7c0007dd
+#define PPC_INST_TRECLAIM 0x7c00075d
+#define PPC_INST_TABORT 0x7c00071d
#define PPC_INST_NAP 0x4c000364
#define PPC_INST_SLEEP 0x4c0003a4
@@ -227,6 +231,8 @@
___PPC_RB(b) | __PPC_EH(eh))
#define PPC_MSGSND(b) stringify_in_c(.long PPC_INST_MSGSND | \
___PPC_RB(b))
+#define PPC_MSGSNDP(b) stringify_in_c(.long PPC_INST_MSGSNDP | \
+ ___PPC_RB(b))
#define PPC_POPCNTB(a, s) stringify_in_c(.long PPC_INST_POPCNTB | \
__PPC_RA(a) | __PPC_RS(s))
#define PPC_POPCNTD(a, s) stringify_in_c(.long PPC_INST_POPCNTD | \
@@ -291,4 +297,11 @@
#define PPC_NAP stringify_in_c(.long PPC_INST_NAP)
#define PPC_SLEEP stringify_in_c(.long PPC_INST_SLEEP)
+/* Transactional memory instructions */
+#define TRECHKPT stringify_in_c(.long PPC_INST_TRECHKPT)
+#define TRECLAIM(r) stringify_in_c(.long PPC_INST_TRECLAIM \
+ | __PPC_RA(r))
+#define TABORT(r) stringify_in_c(.long PPC_INST_TABORT \
+ | __PPC_RA(r))
+
#endif /* _ASM_POWERPC_PPC_OPCODE_H */
diff --git a/arch/powerpc/include/asm/ppc4xx_ocm.h b/arch/powerpc/include/asm/ppc4xx_ocm.h
new file mode 100644
index 000000000000..6ce904605538
--- /dev/null
+++ b/arch/powerpc/include/asm/ppc4xx_ocm.h
@@ -0,0 +1,45 @@
+/*
+ * PowerPC 4xx OCM memory allocation support
+ *
+ * (C) Copyright 2009, Applied Micro Circuits Corporation
+ * Victor Gallardo (vgallardo@amcc.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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_PPC4XX_OCM_H__
+#define __ASM_POWERPC_PPC4XX_OCM_H__
+
+#define PPC4XX_OCM_NON_CACHED 0
+#define PPC4XX_OCM_CACHED 1
+
+#if defined(CONFIG_PPC4xx_OCM)
+
+void *ppc4xx_ocm_alloc(phys_addr_t *phys, int size, int align,
+ int flags, const char *owner);
+void ppc4xx_ocm_free(const void *virt);
+
+#else
+
+#define ppc4xx_ocm_alloc(phys, size, align, flags, owner) NULL
+#define ppc4xx_ocm_free(addr) ((void)0)
+
+#endif /* CONFIG_PPC4xx_OCM */
+
+#endif /* __ASM_POWERPC_PPC4XX_OCM_H__ */
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index ea2a86e8ff95..cea8496091ff 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -24,13 +24,12 @@
* user_time and system_time fields in the paca.
*/
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
#define ACCOUNT_CPU_USER_ENTRY(ra, rb)
#define ACCOUNT_CPU_USER_EXIT(ra, rb)
#define ACCOUNT_STOLEN_TIME
#else
#define ACCOUNT_CPU_USER_ENTRY(ra, rb) \
- beq 2f; /* if from kernel mode */ \
MFTB(ra); /* get timebase */ \
ld rb,PACA_STARTTIME_USER(r13); \
std ra,PACA_STARTTIME(r13); \
@@ -38,7 +37,6 @@
ld ra,PACA_USER_TIME(r13); \
add ra,ra,rb; /* add on to user time */ \
std ra,PACA_USER_TIME(r13); \
-2:
#define ACCOUNT_CPU_USER_EXIT(ra, rb) \
MFTB(ra); /* get timebase */ \
@@ -70,7 +68,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
#endif /* CONFIG_PPC_SPLPAR */
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
/*
* Macros for storing registers into and loading registers from
@@ -125,6 +123,89 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
#define REST_16VRS(n,b,base) REST_8VRS(n,b,base); REST_8VRS(n+8,b,base)
#define REST_32VRS(n,b,base) REST_16VRS(n,b,base); REST_16VRS(n+16,b,base)
+/* Save/restore FPRs, VRs and VSRs from their checkpointed backups in
+ * thread_struct:
+ */
+#define SAVE_FPR_TRANSACT(n, base) stfd n,THREAD_TRANSACT_FPR0+ \
+ 8*TS_FPRWIDTH*(n)(base)
+#define SAVE_2FPRS_TRANSACT(n, base) SAVE_FPR_TRANSACT(n, base); \
+ SAVE_FPR_TRANSACT(n+1, base)
+#define SAVE_4FPRS_TRANSACT(n, base) SAVE_2FPRS_TRANSACT(n, base); \
+ SAVE_2FPRS_TRANSACT(n+2, base)
+#define SAVE_8FPRS_TRANSACT(n, base) SAVE_4FPRS_TRANSACT(n, base); \
+ SAVE_4FPRS_TRANSACT(n+4, base)
+#define SAVE_16FPRS_TRANSACT(n, base) SAVE_8FPRS_TRANSACT(n, base); \
+ SAVE_8FPRS_TRANSACT(n+8, base)
+#define SAVE_32FPRS_TRANSACT(n, base) SAVE_16FPRS_TRANSACT(n, base); \
+ SAVE_16FPRS_TRANSACT(n+16, base)
+
+#define REST_FPR_TRANSACT(n, base) lfd n,THREAD_TRANSACT_FPR0+ \
+ 8*TS_FPRWIDTH*(n)(base)
+#define REST_2FPRS_TRANSACT(n, base) REST_FPR_TRANSACT(n, base); \
+ REST_FPR_TRANSACT(n+1, base)
+#define REST_4FPRS_TRANSACT(n, base) REST_2FPRS_TRANSACT(n, base); \
+ REST_2FPRS_TRANSACT(n+2, base)
+#define REST_8FPRS_TRANSACT(n, base) REST_4FPRS_TRANSACT(n, base); \
+ REST_4FPRS_TRANSACT(n+4, base)
+#define REST_16FPRS_TRANSACT(n, base) REST_8FPRS_TRANSACT(n, base); \
+ REST_8FPRS_TRANSACT(n+8, base)
+#define REST_32FPRS_TRANSACT(n, base) REST_16FPRS_TRANSACT(n, base); \
+ REST_16FPRS_TRANSACT(n+16, base)
+
+
+#define SAVE_VR_TRANSACT(n,b,base) li b,THREAD_TRANSACT_VR0+(16*(n)); \
+ stvx n,b,base
+#define SAVE_2VRS_TRANSACT(n,b,base) SAVE_VR_TRANSACT(n,b,base); \
+ SAVE_VR_TRANSACT(n+1,b,base)
+#define SAVE_4VRS_TRANSACT(n,b,base) SAVE_2VRS_TRANSACT(n,b,base); \
+ SAVE_2VRS_TRANSACT(n+2,b,base)
+#define SAVE_8VRS_TRANSACT(n,b,base) SAVE_4VRS_TRANSACT(n,b,base); \
+ SAVE_4VRS_TRANSACT(n+4,b,base)
+#define SAVE_16VRS_TRANSACT(n,b,base) SAVE_8VRS_TRANSACT(n,b,base); \
+ SAVE_8VRS_TRANSACT(n+8,b,base)
+#define SAVE_32VRS_TRANSACT(n,b,base) SAVE_16VRS_TRANSACT(n,b,base); \
+ SAVE_16VRS_TRANSACT(n+16,b,base)
+
+#define REST_VR_TRANSACT(n,b,base) li b,THREAD_TRANSACT_VR0+(16*(n)); \
+ lvx n,b,base
+#define REST_2VRS_TRANSACT(n,b,base) REST_VR_TRANSACT(n,b,base); \
+ REST_VR_TRANSACT(n+1,b,base)
+#define REST_4VRS_TRANSACT(n,b,base) REST_2VRS_TRANSACT(n,b,base); \
+ REST_2VRS_TRANSACT(n+2,b,base)
+#define REST_8VRS_TRANSACT(n,b,base) REST_4VRS_TRANSACT(n,b,base); \
+ REST_4VRS_TRANSACT(n+4,b,base)
+#define REST_16VRS_TRANSACT(n,b,base) REST_8VRS_TRANSACT(n,b,base); \
+ REST_8VRS_TRANSACT(n+8,b,base)
+#define REST_32VRS_TRANSACT(n,b,base) REST_16VRS_TRANSACT(n,b,base); \
+ REST_16VRS_TRANSACT(n+16,b,base)
+
+
+#define SAVE_VSR_TRANSACT(n,b,base) li b,THREAD_TRANSACT_VSR0+(16*(n)); \
+ STXVD2X(n,R##base,R##b)
+#define SAVE_2VSRS_TRANSACT(n,b,base) SAVE_VSR_TRANSACT(n,b,base); \
+ SAVE_VSR_TRANSACT(n+1,b,base)
+#define SAVE_4VSRS_TRANSACT(n,b,base) SAVE_2VSRS_TRANSACT(n,b,base); \
+ SAVE_2VSRS_TRANSACT(n+2,b,base)
+#define SAVE_8VSRS_TRANSACT(n,b,base) SAVE_4VSRS_TRANSACT(n,b,base); \
+ SAVE_4VSRS_TRANSACT(n+4,b,base)
+#define SAVE_16VSRS_TRANSACT(n,b,base) SAVE_8VSRS_TRANSACT(n,b,base); \
+ SAVE_8VSRS_TRANSACT(n+8,b,base)
+#define SAVE_32VSRS_TRANSACT(n,b,base) SAVE_16VSRS_TRANSACT(n,b,base); \
+ SAVE_16VSRS_TRANSACT(n+16,b,base)
+
+#define REST_VSR_TRANSACT(n,b,base) li b,THREAD_TRANSACT_VSR0+(16*(n)); \
+ LXVD2X(n,R##base,R##b)
+#define REST_2VSRS_TRANSACT(n,b,base) REST_VSR_TRANSACT(n,b,base); \
+ REST_VSR_TRANSACT(n+1,b,base)
+#define REST_4VSRS_TRANSACT(n,b,base) REST_2VSRS_TRANSACT(n,b,base); \
+ REST_2VSRS_TRANSACT(n+2,b,base)
+#define REST_8VSRS_TRANSACT(n,b,base) REST_4VSRS_TRANSACT(n,b,base); \
+ REST_4VSRS_TRANSACT(n+4,b,base)
+#define REST_16VSRS_TRANSACT(n,b,base) REST_8VSRS_TRANSACT(n,b,base); \
+ REST_8VSRS_TRANSACT(n+8,b,base)
+#define REST_32VSRS_TRANSACT(n,b,base) REST_16VSRS_TRANSACT(n,b,base); \
+ REST_16VSRS_TRANSACT(n+16,b,base)
+
/* Save the lower 32 VSRs in the thread VSR region */
#define SAVE_VSR(n,b,base) li b,THREAD_VSR0+(16*(n)); STXVD2X(n,R##base,R##b)
#define SAVE_2VSRS(n,b,base) SAVE_VSR(n,b,base); SAVE_VSR(n+1,b,base)
@@ -391,6 +472,31 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
FTR_SECTION_ELSE_NESTED(848); \
mtocrf (FXM), RS; \
ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_NOEXECUTE, 848)
+
+/*
+ * PPR restore macros used in entry_64.S
+ * Used for P7 or later processors
+ */
+#define HMT_MEDIUM_LOW_HAS_PPR \
+BEGIN_FTR_SECTION_NESTED(944) \
+ HMT_MEDIUM_LOW; \
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,944)
+
+#define SET_DEFAULT_THREAD_PPR(ra, rb) \
+BEGIN_FTR_SECTION_NESTED(945) \
+ lis ra,INIT_PPR@highest; /* default ppr=3 */ \
+ ld rb,PACACURRENT(r13); \
+ sldi ra,ra,32; /* 11- 13 bits are used for ppr */ \
+ std ra,TASKTHREADPPR(rb); \
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,945)
+
+#define RESTORE_PPR(ra, rb) \
+BEGIN_FTR_SECTION_NESTED(946) \
+ ld ra,PACACURRENT(r13); \
+ ld rb,TASKTHREADPPR(ra); \
+ mtspr SPRN_PPR,rb; /* Restore PPR */ \
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,946)
+
#endif
/*
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 87502046c0dc..7ff9eaa3ea6c 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -18,11 +18,22 @@
#define TS_FPRWIDTH 1
#endif
+#ifdef CONFIG_PPC64
+/* Default SMT priority is set to 3. Use 11- 13bits to save priority. */
+#define PPR_PRIORITY 3
+#ifdef __ASSEMBLY__
+#define INIT_PPR (PPR_PRIORITY << 50)
+#else
+#define INIT_PPR ((u64)PPR_PRIORITY << 50)
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_PPC64 */
+
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
#include <linux/cache.h>
#include <asm/ptrace.h>
#include <asm/types.h>
+#include <asm/hw_breakpoint.h>
/* We do _not_ want to define new machine types at all, those must die
* in favor of using the device-tree
@@ -141,6 +152,7 @@ typedef struct {
#define TS_FPROFFSET 0
#define TS_VSRLOWOFFSET 1
#define TS_FPR(i) fpr[i][TS_FPROFFSET]
+#define TS_TRANS_FPR(i) transact_fpr[i][TS_FPROFFSET]
struct thread_struct {
unsigned long ksp; /* Kernel stack pointer */
@@ -215,8 +227,7 @@ struct thread_struct {
struct perf_event *last_hit_ubp;
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#endif
- unsigned long dabr; /* Data address breakpoint register */
- unsigned long dabrx; /* ... extension */
+ struct arch_hw_breakpoint hw_brk; /* info on the hardware breakpoint */
unsigned long trap_nr; /* last trap # on this thread */
#ifdef CONFIG_ALTIVEC
/* Complete AltiVec register set */
@@ -236,6 +247,34 @@ struct thread_struct {
unsigned long spefscr; /* SPE & eFP status */
int used_spe; /* set if process has used spe */
#endif /* CONFIG_SPE */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ u64 tm_tfhar; /* Transaction fail handler addr */
+ u64 tm_texasr; /* Transaction exception & summary */
+ u64 tm_tfiar; /* Transaction fail instr address reg */
+ unsigned long tm_orig_msr; /* Thread's MSR on ctx switch */
+ struct pt_regs ckpt_regs; /* Checkpointed registers */
+
+ /*
+ * Transactional FP and VSX 0-31 register set.
+ * NOTE: the sense of these is the opposite of the integer ckpt_regs!
+ *
+ * When a transaction is active/signalled/scheduled etc., *regs is the
+ * most recent set of/speculated GPRs with ckpt_regs being the older
+ * checkpointed regs to which we roll back if transaction aborts.
+ *
+ * However, fpr[] is the checkpointed 'base state' of FP regs, and
+ * transact_fpr[] is the new set of transactional values.
+ * VRs work the same way.
+ */
+ double transact_fpr[32][TS_FPRWIDTH];
+ struct {
+ unsigned int pad;
+ unsigned int val; /* Floating point status */
+ } transact_fpscr;
+ vector128 transact_vr[32] __attribute__((aligned(16)));
+ vector128 transact_vscr __attribute__((aligned(16)));
+ unsigned long transact_vrsave;
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
void* kvm_shadow_vcpu; /* KVM internal data */
#endif /* CONFIG_KVM_BOOK3S_32_HANDLER */
@@ -245,6 +284,10 @@ struct thread_struct {
#ifdef CONFIG_PPC64
unsigned long dscr;
int dscr_inherit;
+ unsigned long ppr; /* used to save/restore SMT priority */
+#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+ unsigned long tar;
#endif
};
@@ -278,6 +321,7 @@ struct thread_struct {
.fpr = {{0}}, \
.fpscr = { .val = 0, }, \
.fpexc_mode = 0, \
+ .ppr = INIT_PPR, \
}
#endif
diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h
index 0e15db4d703b..678a7c1d9cb8 100644
--- a/arch/powerpc/include/asm/ps3.h
+++ b/arch/powerpc/include/asm/ps3.h
@@ -245,7 +245,7 @@ enum lv1_result {
static inline const char* ps3_result(int result)
{
-#if defined(DEBUG)
+#if defined(DEBUG) || defined(PS3_VERBOSE_RESULT)
switch (result) {
case LV1_SUCCESS:
return "LV1_SUCCESS (0)";
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 3d5c9dc8917a..e66586122030 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -29,6 +29,10 @@
#define MSR_SF_LG 63 /* Enable 64 bit mode */
#define MSR_ISF_LG 61 /* Interrupt 64b mode valid on 630 */
#define MSR_HV_LG 60 /* Hypervisor state */
+#define MSR_TS_T_LG 34 /* Trans Mem state: Transactional */
+#define MSR_TS_S_LG 33 /* Trans Mem state: Suspended */
+#define MSR_TS_LG 33 /* Trans Mem state (2 bits) */
+#define MSR_TM_LG 32 /* Trans Mem Available */
#define MSR_VEC_LG 25 /* Enable AltiVec */
#define MSR_VSX_LG 23 /* Enable VSX */
#define MSR_POW_LG 18 /* Enable Power Management */
@@ -98,6 +102,26 @@
#define MSR_RI __MASK(MSR_RI_LG) /* Recoverable Exception */
#define MSR_LE __MASK(MSR_LE_LG) /* Little Endian */
+#define MSR_TM __MASK(MSR_TM_LG) /* Transactional Mem Available */
+#define MSR_TS_N 0 /* Non-transactional */
+#define MSR_TS_S __MASK(MSR_TS_S_LG) /* Transaction Suspended */
+#define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */
+#define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */
+#define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */
+#define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T)
+#define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S)
+
+/* Reason codes describing kernel causes for transaction aborts. By
+ convention, bit0 is copied to TEXASR[56] (IBM bit 7) which is set if
+ the failure is persistent.
+*/
+#define TM_CAUSE_RESCHED 0xfe
+#define TM_CAUSE_TLBI 0xfc
+#define TM_CAUSE_FAC_UNAV 0xfa
+#define TM_CAUSE_SYSCALL 0xf9 /* Persistent */
+#define TM_CAUSE_MISC 0xf6
+#define TM_CAUSE_SIGNAL 0xf4
+
#if defined(CONFIG_PPC_BOOK3S_64)
#define MSR_64BIT MSR_SF
@@ -193,6 +217,10 @@
#define SPRN_UAMOR 0x9d /* User Authority Mask Override Register */
#define SPRN_AMOR 0x15d /* Authority Mask Override Register */
#define SPRN_ACOP 0x1F /* Available Coprocessor Register */
+#define SPRN_TFIAR 0x81 /* Transaction Failure Inst Addr */
+#define SPRN_TEXASR 0x82 /* Transaction EXception & Summary */
+#define SPRN_TEXASRU 0x83 /* '' '' '' Upper 32 */
+#define SPRN_TFHAR 0x80 /* Transaction Failure Handler Addr */
#define SPRN_CTRLF 0x088
#define SPRN_CTRLT 0x098
#define CTRL_CT 0xc0000000 /* current thread */
@@ -200,10 +228,12 @@
#define CTRL_CT1 0x40000000 /* thread 1 */
#define CTRL_TE 0x00c00000 /* thread enable */
#define CTRL_RUNLATCH 0x1
+#define SPRN_DAWR 0xB4
+#define SPRN_DAWRX 0xBC
+#define DAWRX_USER (1UL << 0)
+#define DAWRX_KERNEL (1UL << 1)
+#define DAWRX_HYP (1UL << 2)
#define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */
-#define DABR_TRANSLATION (1UL << 2)
-#define DABR_DATA_WRITE (1UL << 1)
-#define DABR_DATA_READ (1UL << 0)
#define SPRN_DABR2 0x13D /* e300 */
#define SPRN_DABRX 0x3F7 /* Data Address Breakpoint Register Extension */
#define DABRX_USER (1UL << 0)
@@ -235,6 +265,9 @@
#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_FSCR 0x099 /* Facility Status & Control Register */
+#define FSCR_TAR (1<<8) /* Enable Target Adress Register */
+#define SPRN_TAR 0x32f /* Target Address Register */
#define SPRN_LPCR 0x13E /* LPAR Control Register */
#define LPCR_VPM0 (1ul << (63-0))
#define LPCR_VPM1 (1ul << (63-1))
@@ -289,6 +322,7 @@
#define SPRN_DBAT6U 0x23C /* Data BAT 6 Upper Register */
#define SPRN_DBAT7L 0x23F /* Data BAT 7 Lower Register */
#define SPRN_DBAT7U 0x23E /* Data BAT 7 Upper Register */
+#define SPRN_PPR 0x380 /* SMT Thread status Register */
#define SPRN_DEC 0x016 /* Decrement Register */
#define SPRN_DER 0x095 /* Debug Enable Regsiter */
@@ -483,6 +517,7 @@
#ifndef SPRN_PIR
#define SPRN_PIR 0x3FF /* Processor Identification Register */
#endif
+#define SPRN_TIR 0x1BE /* Thread Identification Register */
#define SPRN_PTEHI 0x3D5 /* 981 7450 PTE HI word (S/W TLB load) */
#define SPRN_PTELO 0x3D6 /* 982 7450 PTE LO word (S/W TLB load) */
#define SPRN_PURR 0x135 /* Processor Utilization of Resources Reg */
@@ -763,7 +798,7 @@
* HV mode in which case it is HSPRG0
*
* 64-bit server:
- * - SPRG0 unused (reserved for HV on Power4)
+ * - SPRG0 scratch for TM recheckpoint/reclaim (reserved for HV on Power4)
* - SPRG2 scratch for exception vectors
* - SPRG3 CPU and NUMA node for VDSO getcpu (user visible)
* - HSPRG0 stores PACA in HV mode
@@ -921,8 +956,6 @@
#define SPRN_SPRG_RSCRATCH_DBG SPRN_SPRG9
#define SPRN_SPRG_WSCRATCH_DBG SPRN_SPRG9
#endif
-#define SPRN_SPRG_RVCPU SPRN_SPRG1
-#define SPRN_SPRG_WVCPU SPRN_SPRG1
#endif
#ifdef CONFIG_8xx
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index e07e6af5e1ff..b417de3cc2c4 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -56,6 +56,7 @@
#define SPRN_SPRG7W 0x117 /* Special Purpose Register General 7 Write */
#define SPRN_EPCR 0x133 /* Embedded Processor Control Register */
#define SPRN_DBCR2 0x136 /* Debug Control Register 2 */
+#define SPRN_DBCR4 0x233 /* Debug Control Register 4 */
#define SPRN_MSRP 0x137 /* MSR Protect Register */
#define SPRN_IAC3 0x13A /* Instruction Address Compare 3 */
#define SPRN_IAC4 0x13B /* Instruction Address Compare 4 */
diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h
index a0f358d4a00c..4ee06fe15de4 100644
--- a/arch/powerpc/include/asm/sections.h
+++ b/arch/powerpc/include/asm/sections.h
@@ -10,6 +10,9 @@
extern char __end_interrupts[];
+extern char __prom_init_toc_start[];
+extern char __prom_init_toc_end[];
+
static inline int in_kernel_text(unsigned long addr)
{
if (addr >= (unsigned long)_stext && addr < (unsigned long)__init_end)
diff --git a/arch/powerpc/include/asm/signal.h b/arch/powerpc/include/asm/signal.h
index a101637725a2..fbe66c463891 100644
--- a/arch/powerpc/include/asm/signal.h
+++ b/arch/powerpc/include/asm/signal.h
@@ -1,6 +1,7 @@
#ifndef _ASM_POWERPC_SIGNAL_H
#define _ASM_POWERPC_SIGNAL_H
+#define __ARCH_HAS_SA_RESTORER
#include <uapi/asm/signal.h>
#endif /* _ASM_POWERPC_SIGNAL_H */
diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
index 7124fc06ad47..5b23f910ee57 100644
--- a/arch/powerpc/include/asm/spinlock.h
+++ b/arch/powerpc/include/asm/spinlock.h
@@ -96,7 +96,7 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
#if defined(CONFIG_PPC_SPLPAR)
/* We only yield to the hypervisor if we are in shared processor mode */
-#define SHARED_PROCESSOR (get_lppaca()->shared_proc)
+#define SHARED_PROCESSOR (local_paca->lppaca_ptr->shared_proc)
extern void __spin_yield(arch_spinlock_t *lock);
extern void __rw_yield(arch_rwlock_t *lock);
#else /* SPLPAR */
diff --git a/arch/powerpc/include/asm/syscalls.h b/arch/powerpc/include/asm/syscalls.h
index b5308d3e6d39..23be8f1e7e64 100644
--- a/arch/powerpc/include/asm/syscalls.h
+++ b/arch/powerpc/include/asm/syscalls.h
@@ -5,11 +5,8 @@
#include <linux/compiler.h>
#include <linux/linkage.h>
#include <linux/types.h>
-#include <asm/signal.h>
-struct pt_regs;
struct rtas_args;
-struct sigaction;
asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
unsigned long prot, unsigned long flags,
@@ -17,20 +14,8 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
asmlinkage unsigned long sys_mmap2(unsigned long addr, size_t len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff);
-asmlinkage long sys_pipe(int __user *fildes);
-asmlinkage long sys_pipe2(int __user *fildes, int flags);
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact, size_t sigsetsize);
asmlinkage long ppc64_personality(unsigned long personality);
asmlinkage int ppc_rtas(struct rtas_args __user *uargs);
-asmlinkage time_t sys64_time(time_t __user * tloc);
-
-asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset,
- size_t sigsetsize);
-asmlinkage long sys_sigaltstack(const stack_t __user *uss,
- stack_t __user *uoss, unsigned long r5, unsigned long r6,
- unsigned long r7, unsigned long r8, struct pt_regs *regs);
#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_SYSCALLS_H */
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index 97909d3b1d7b..d906f33441c6 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -10,8 +10,8 @@ SYSCALL_SPU(read)
SYSCALL_SPU(write)
COMPAT_SYS_SPU(open)
SYSCALL_SPU(close)
-COMPAT_SYS_SPU(waitpid)
-COMPAT_SYS_SPU(creat)
+SYSCALL_SPU(waitpid)
+SYSCALL_SPU(creat)
SYSCALL_SPU(link)
SYSCALL_SPU(unlink)
COMPAT_SYS(execve)
@@ -36,13 +36,13 @@ SYSCALL(pause)
COMPAT_SYS(utime)
SYSCALL(ni_syscall)
SYSCALL(ni_syscall)
-COMPAT_SYS_SPU(access)
-COMPAT_SYS_SPU(nice)
+SYSCALL_SPU(access)
+SYSCALL_SPU(nice)
SYSCALL(ni_syscall)
SYSCALL_SPU(sync)
-COMPAT_SYS_SPU(kill)
+SYSCALL_SPU(kill)
SYSCALL_SPU(rename)
-COMPAT_SYS_SPU(mkdir)
+SYSCALL_SPU(mkdir)
SYSCALL_SPU(rmdir)
SYSCALL_SPU(dup)
SYSCALL_SPU(pipe)
@@ -60,10 +60,10 @@ SYSCALL(ni_syscall)
COMPAT_SYS_SPU(ioctl)
COMPAT_SYS_SPU(fcntl)
SYSCALL(ni_syscall)
-COMPAT_SYS_SPU(setpgid)
+SYSCALL_SPU(setpgid)
SYSCALL(ni_syscall)
SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
-COMPAT_SYS_SPU(umask)
+SYSCALL_SPU(umask)
SYSCALL_SPU(chroot)
COMPAT_SYS(ustat)
SYSCALL_SPU(dup2)
@@ -72,23 +72,24 @@ SYSCALL_SPU(getpgrp)
SYSCALL_SPU(setsid)
SYS32ONLY(sigaction)
SYSCALL_SPU(sgetmask)
-COMPAT_SYS_SPU(ssetmask)
+SYSCALL_SPU(ssetmask)
SYSCALL_SPU(setreuid)
SYSCALL_SPU(setregid)
+#define compat_sys_sigsuspend sys_sigsuspend
SYS32ONLY(sigsuspend)
COMPAT_SYS(sigpending)
-COMPAT_SYS_SPU(sethostname)
+SYSCALL_SPU(sethostname)
COMPAT_SYS_SPU(setrlimit)
COMPAT_SYS(old_getrlimit)
COMPAT_SYS_SPU(getrusage)
COMPAT_SYS_SPU(gettimeofday)
COMPAT_SYS_SPU(settimeofday)
-COMPAT_SYS_SPU(getgroups)
-COMPAT_SYS_SPU(setgroups)
+SYSCALL_SPU(getgroups)
+SYSCALL_SPU(setgroups)
SYSX(sys_ni_syscall,sys_ni_syscall,ppc_select)
SYSCALL_SPU(symlink)
OLDSYS(lstat)
-COMPAT_SYS_SPU(readlink)
+SYSCALL_SPU(readlink)
SYSCALL(uselib)
SYSCALL(swapon)
SYSCALL(reboot)
@@ -99,14 +100,14 @@ COMPAT_SYS_SPU(truncate)
COMPAT_SYS_SPU(ftruncate)
SYSCALL_SPU(fchmod)
SYSCALL_SPU(fchown)
-COMPAT_SYS_SPU(getpriority)
-COMPAT_SYS_SPU(setpriority)
+SYSCALL_SPU(getpriority)
+SYSCALL_SPU(setpriority)
SYSCALL(ni_syscall)
COMPAT_SYS(statfs)
COMPAT_SYS(fstatfs)
SYSCALL(ni_syscall)
COMPAT_SYS_SPU(socketcall)
-COMPAT_SYS_SPU(syslog)
+SYSCALL_SPU(syslog)
COMPAT_SYS_SPU(setitimer)
COMPAT_SYS_SPU(getitimer)
COMPAT_SYS_SPU(newstat)
@@ -124,7 +125,7 @@ COMPAT_SYS(ipc)
SYSCALL_SPU(fsync)
SYS32ONLY(sigreturn)
PPC_SYS(clone)
-COMPAT_SYS_SPU(setdomainname)
+SYSCALL_SPU(setdomainname)
SYSCALL_SPU(newuname)
SYSCALL(ni_syscall)
COMPAT_SYS_SPU(adjtimex)
@@ -135,10 +136,10 @@ SYSCALL(init_module)
SYSCALL(delete_module)
SYSCALL(ni_syscall)
SYSCALL(quotactl)
-COMPAT_SYS_SPU(getpgid)
+SYSCALL_SPU(getpgid)
SYSCALL_SPU(fchdir)
SYSCALL_SPU(bdflush)
-COMPAT_SYS(sysfs)
+SYSCALL_SPU(sysfs)
SYSX_SPU(ppc64_personality,ppc64_personality,sys_personality)
SYSCALL(ni_syscall)
SYSCALL_SPU(setfsuid)
@@ -150,21 +151,21 @@ SYSCALL_SPU(flock)
SYSCALL_SPU(msync)
COMPAT_SYS_SPU(readv)
COMPAT_SYS_SPU(writev)
-COMPAT_SYS_SPU(getsid)
+SYSCALL_SPU(getsid)
SYSCALL_SPU(fdatasync)
COMPAT_SYS(sysctl)
SYSCALL_SPU(mlock)
SYSCALL_SPU(munlock)
SYSCALL_SPU(mlockall)
SYSCALL_SPU(munlockall)
-COMPAT_SYS_SPU(sched_setparam)
-COMPAT_SYS_SPU(sched_getparam)
-COMPAT_SYS_SPU(sched_setscheduler)
-COMPAT_SYS_SPU(sched_getscheduler)
+SYSCALL_SPU(sched_setparam)
+SYSCALL_SPU(sched_getparam)
+SYSCALL_SPU(sched_setscheduler)
+SYSCALL_SPU(sched_getscheduler)
SYSCALL_SPU(sched_yield)
-COMPAT_SYS_SPU(sched_get_priority_max)
-COMPAT_SYS_SPU(sched_get_priority_min)
-SYSX_SPU(sys_sched_rr_get_interval,compat_sys_sched_rr_get_interval_wrapper,sys_sched_rr_get_interval)
+SYSCALL_SPU(sched_get_priority_max)
+SYSCALL_SPU(sched_get_priority_min)
+COMPAT_SYS_SPU(sched_rr_get_interval)
COMPAT_SYS_SPU(nanosleep)
SYSCALL_SPU(mremap)
SYSCALL_SPU(setresuid)
@@ -174,7 +175,7 @@ SYSCALL_SPU(poll)
SYSCALL(ni_syscall)
SYSCALL_SPU(setresgid)
SYSCALL_SPU(getresgid)
-COMPAT_SYS_SPU(prctl)
+SYSCALL_SPU(prctl)
COMPAT_SYS(rt_sigreturn)
COMPAT_SYS(rt_sigaction)
COMPAT_SYS(rt_sigprocmask)
@@ -253,7 +254,7 @@ COMPAT_SYS_SPU(clock_gettime)
COMPAT_SYS_SPU(clock_getres)
COMPAT_SYS_SPU(clock_nanosleep)
SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext)
-COMPAT_SYS_SPU(tgkill)
+SYSCALL_SPU(tgkill)
COMPAT_SYS_SPU(utimes)
COMPAT_SYS_SPU(statfs64)
COMPAT_SYS_SPU(fstatfs64)
@@ -276,8 +277,8 @@ COMPAT_SYS(add_key)
COMPAT_SYS(request_key)
COMPAT_SYS(keyctl)
COMPAT_SYS(waitid)
-COMPAT_SYS(ioprio_set)
-COMPAT_SYS(ioprio_get)
+SYSCALL(ioprio_set)
+SYSCALL(ioprio_get)
SYSCALL(inotify_init)
SYSCALL(inotify_add_watch)
SYSCALL(inotify_rm_watch)
diff --git a/arch/powerpc/include/asm/tm.h b/arch/powerpc/include/asm/tm.h
new file mode 100644
index 000000000000..4b4449abf3f8
--- /dev/null
+++ b/arch/powerpc/include/asm/tm.h
@@ -0,0 +1,20 @@
+/*
+ * Transactional memory support routines to reclaim and recheckpoint
+ * transactional process state.
+ *
+ * Copyright 2012 Matt Evans & Michael Neuling, IBM Corporation.
+ */
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+extern void do_load_up_transact_fpu(struct thread_struct *thread);
+extern void do_load_up_transact_altivec(struct thread_struct *thread);
+#endif
+
+extern void tm_enable(void);
+extern void tm_reclaim(struct thread_struct *thread,
+ unsigned long orig_msr, uint8_t cause);
+extern void tm_recheckpoint(struct thread_struct *thread,
+ unsigned long orig_msr);
+extern void tm_abort(uint8_t cause);
+extern void tm_save_sprs(struct thread_struct *thread);
+extern void tm_restore_sprs(struct thread_struct *thread);
diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h
index 1d4864a40e35..f25b5c45c435 100644
--- a/arch/powerpc/include/asm/unistd.h
+++ b/arch/powerpc/include/asm/unistd.h
@@ -44,17 +44,13 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#ifdef CONFIG_PPC32
#define __ARCH_WANT_OLD_STAT
#endif
#ifdef CONFIG_PPC64
#define __ARCH_WANT_COMPAT_SYS_TIME
-#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_NEWFSTATAT
#define __ARCH_WANT_COMPAT_SYS_SENDFILE
-#define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL
#endif
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index 2fba8a66fb10..16064d00adb9 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -114,7 +114,10 @@ struct kvm_regs {
/* Embedded Floating Point (SPE) -- IVOR32-34 if KVM_SREGS_E_IVOR */
#define KVM_SREGS_E_SPE (1 << 9)
-/* External Proxy (EXP) -- EPR */
+/*
+ * DEPRECATED! USE ONE_REG FOR THIS ONE!
+ * External Proxy (EXP) -- EPR
+ */
#define KVM_SREGS_EXP (1 << 10)
/* External PID (E.PD) -- EPSC/EPLC */
@@ -412,5 +415,6 @@ struct kvm_get_htab_header {
#define KVM_REG_PPC_VPA_DTL (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x84)
#define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85)
+#define KVM_REG_PPC_EPR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x86)
#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/arch/powerpc/include/uapi/asm/ptrace.h b/arch/powerpc/include/uapi/asm/ptrace.h
index ee67a2bc91bb..66b9ca4ee94a 100644
--- a/arch/powerpc/include/uapi/asm/ptrace.h
+++ b/arch/powerpc/include/uapi/asm/ptrace.h
@@ -108,6 +108,7 @@ struct pt_regs {
#define PT_DAR 41
#define PT_DSISR 42
#define PT_RESULT 43
+#define PT_DSCR 44
#define PT_REGS_COUNT 44
#define PT_FPR0 48 /* each FP reg occupies 2 slots in this space */
@@ -146,34 +147,34 @@ struct pt_regs {
* structures. This also simplifies the implementation of a bi-arch
* (combined (32- and 64-bit) gdb.
*/
-#define PTRACE_GETVRREGS 18
-#define PTRACE_SETVRREGS 19
+#define PTRACE_GETVRREGS 0x12
+#define PTRACE_SETVRREGS 0x13
/* Get/set all the upper 32-bits of the SPE registers, accumulator, and
* spefscr, in one go */
-#define PTRACE_GETEVRREGS 20
-#define PTRACE_SETEVRREGS 21
+#define PTRACE_GETEVRREGS 0x14
+#define PTRACE_SETEVRREGS 0x15
/* Get the first 32 128bit VSX registers */
-#define PTRACE_GETVSRREGS 27
-#define PTRACE_SETVSRREGS 28
+#define PTRACE_GETVSRREGS 0x1b
+#define PTRACE_SETVSRREGS 0x1c
/*
* Get or set a debug register. The first 16 are DABR registers and the
* second 16 are IABR registers.
*/
-#define PTRACE_GET_DEBUGREG 25
-#define PTRACE_SET_DEBUGREG 26
+#define PTRACE_GET_DEBUGREG 0x19
+#define PTRACE_SET_DEBUGREG 0x1a
/* (new) PTRACE requests using the same numbers as x86 and the same
* argument ordering. Additionally, they support more registers too
*/
-#define PTRACE_GETREGS 12
-#define PTRACE_SETREGS 13
-#define PTRACE_GETFPREGS 14
-#define PTRACE_SETFPREGS 15
-#define PTRACE_GETREGS64 22
-#define PTRACE_SETREGS64 23
+#define PTRACE_GETREGS 0xc
+#define PTRACE_SETREGS 0xd
+#define PTRACE_GETFPREGS 0xe
+#define PTRACE_SETFPREGS 0xf
+#define PTRACE_GETREGS64 0x16
+#define PTRACE_SETREGS64 0x17
/* Calls to trace a 64bit program from a 32bit program */
#define PPC_PTRACE_PEEKTEXT_3264 0x95
diff --git a/arch/powerpc/include/uapi/asm/signal.h b/arch/powerpc/include/uapi/asm/signal.h
index e079fb39d5bc..6c69ee94fd8d 100644
--- a/arch/powerpc/include/uapi/asm/signal.h
+++ b/arch/powerpc/include/uapi/asm/signal.h
@@ -90,6 +90,7 @@ typedef struct {
#include <asm-generic/signal-defs.h>
+#ifndef __KERNEL__
struct old_sigaction {
__sighandler_t sa_handler;
old_sigset_t sa_mask;
@@ -103,10 +104,7 @@ struct sigaction {
__sigrestore_t sa_restorer;
sigset_t sa_mask; /* mask last for extensibility */
};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#endif
typedef struct sigaltstack {
void __user *ss_sp;
diff --git a/arch/powerpc/include/uapi/asm/socket.h b/arch/powerpc/include/uapi/asm/socket.h
index eb0b1864d400..a26dcaece509 100644
--- a/arch/powerpc/include/uapi/asm/socket.h
+++ b/arch/powerpc/include/uapi/asm/socket.h
@@ -29,7 +29,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT 15
#define SO_RCVLOWAT 16
#define SO_SNDLOWAT 17
#define SO_RCVTIMEO 18
@@ -77,4 +77,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
+
#endif /* _ASM_POWERPC_SOCKET_H */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 8f619342f14c..f960a7944553 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -7,7 +7,7 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
ifeq ($(CONFIG_PPC64),y)
-CFLAGS_prom_init.o += -mno-minimal-toc
+CFLAGS_prom_init.o += $(NO_MINIMAL_TOC)
endif
ifeq ($(CONFIG_PPC32),y)
CFLAGS_prom_init.o += -fPIC
@@ -75,8 +75,8 @@ endif
obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o
obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_44x) += cpu_setup_44x.o
-obj-$(CONFIG_PPC_FSL_BOOK3E) += cpu_setup_fsl_booke.o dbell.o
-obj-$(CONFIG_PPC_BOOK3E_64) += dbell.o
+obj-$(CONFIG_PPC_FSL_BOOK3E) += cpu_setup_fsl_booke.o
+obj-$(CONFIG_PPC_DOORBELL) += dbell.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
extra-y := head_$(CONFIG_WORD_SIZE).o
@@ -91,7 +91,6 @@ obj-$(CONFIG_RELOCATABLE_PPC32) += reloc_32.o
obj-$(CONFIG_PPC32) += entry_32.o setup_32.o
obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o
obj-$(CONFIG_KGDB) += kgdb.o
-obj-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += prom_init.o
obj-$(CONFIG_MODULES) += ppc_ksyms.o
obj-$(CONFIG_BOOTX_TEXT) += btext.o
obj-$(CONFIG_SMP) += smp.o
@@ -122,6 +121,8 @@ ifneq ($(CONFIG_PPC_INDIRECT_IO),y)
obj-y += iomap.o
endif
+obj64-$(CONFIG_PPC_TRANSACTIONAL_MEM) += tm.o
+
obj-$(CONFIG_PPC64) += $(obj64-y)
obj-$(CONFIG_PPC32) += $(obj32-y)
@@ -142,6 +143,7 @@ GCOV_PROFILE_kprobes.o := n
extra-$(CONFIG_PPC_FPU) += fpu.o
extra-$(CONFIG_ALTIVEC) += vector.o
extra-$(CONFIG_PPC64) += entry_64.o
+extra-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += prom_init.o
extra-y += systbl_chk.i
$(obj)/systbl.o: systbl_chk
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 4e23ba2f3ca7..b6c17ec9b169 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -77,6 +77,7 @@ int main(void)
DEFINE(NMI_MASK, NMI_MASK);
DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr));
DEFINE(THREAD_DSCR_INHERIT, offsetof(struct thread_struct, dscr_inherit));
+ DEFINE(TASKTHREADPPR, offsetof(struct task_struct, thread.ppr));
#else
DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
#endif /* CONFIG_PPC64 */
@@ -117,10 +118,38 @@ int main(void)
#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
DEFINE(THREAD_KVM_SVCPU, offsetof(struct thread_struct, kvm_shadow_vcpu));
#endif
-#ifdef CONFIG_KVM_BOOKE_HV
+#if defined(CONFIG_KVM) && defined(CONFIG_BOOKE)
DEFINE(THREAD_KVM_VCPU, offsetof(struct thread_struct, kvm_vcpu));
#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+ DEFINE(THREAD_TAR, offsetof(struct thread_struct, tar));
+#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ DEFINE(PACATMSCRATCH, offsetof(struct paca_struct, tm_scratch));
+ DEFINE(THREAD_TM_TFHAR, offsetof(struct thread_struct, tm_tfhar));
+ DEFINE(THREAD_TM_TEXASR, offsetof(struct thread_struct, tm_texasr));
+ DEFINE(THREAD_TM_TFIAR, offsetof(struct thread_struct, tm_tfiar));
+ DEFINE(PT_CKPT_REGS, offsetof(struct thread_struct, ckpt_regs));
+ DEFINE(THREAD_TRANSACT_VR0, offsetof(struct thread_struct,
+ transact_vr[0]));
+ DEFINE(THREAD_TRANSACT_VSCR, offsetof(struct thread_struct,
+ transact_vscr));
+ DEFINE(THREAD_TRANSACT_VRSAVE, offsetof(struct thread_struct,
+ transact_vrsave));
+ DEFINE(THREAD_TRANSACT_FPR0, offsetof(struct thread_struct,
+ transact_fpr[0]));
+ DEFINE(THREAD_TRANSACT_FPSCR, offsetof(struct thread_struct,
+ transact_fpscr));
+#ifdef CONFIG_VSX
+ DEFINE(THREAD_TRANSACT_VSR0, offsetof(struct thread_struct,
+ transact_fpr[0]));
+#endif
+ /* Local pt_regs on stack for Transactional Memory funcs. */
+ DEFINE(TM_FRAME_SIZE, STACK_FRAME_OVERHEAD +
+ sizeof(struct pt_regs) + 16);
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
@@ -474,6 +503,7 @@ int main(void)
DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap));
DEFINE(VCPU_PTID, offsetof(struct kvm_vcpu, arch.ptid));
+ DEFINE(VCPU_CFAR, offsetof(struct kvm_vcpu, arch.cfar));
DEFINE(VCORE_ENTRY_EXIT, offsetof(struct kvmppc_vcore, entry_exit_count));
DEFINE(VCORE_NAP_COUNT, offsetof(struct kvmppc_vcore, nap_count));
DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest));
@@ -553,6 +583,10 @@ int main(void)
DEFINE(IPI_PRIORITY, IPI_PRIORITY);
#endif /* CONFIG_KVM_BOOK3S_64_HV */
+#ifdef CONFIG_PPC_BOOK3S_64
+ HSTATE_FIELD(HSTATE_CFAR, cfar);
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
#else /* CONFIG_PPC_BOOK3S */
DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S
index 57cf14065aec..d29facbf9a28 100644
--- a/arch/powerpc/kernel/cpu_setup_power.S
+++ b/arch/powerpc/kernel/cpu_setup_power.S
@@ -56,6 +56,7 @@ _GLOBAL(__setup_cpu_power8)
mfspr r3,SPRN_LPCR
oris r3, r3, LPCR_AIL_3@h
bl __init_LPCR
+ bl __init_FSCR
bl __init_TLB
mtlr r11
blr
@@ -112,6 +113,12 @@ __init_LPCR:
isync
blr
+__init_FSCR:
+ mfspr r3,SPRN_FSCR
+ ori r3,r3,FSCR_TAR
+ mtspr SPRN_FSCR,r3
+ blr
+
__init_TLB:
/* Clear the TLB */
li r6,128
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c
index a892680668d8..9ebbc24bb23c 100644
--- a/arch/powerpc/kernel/dbell.c
+++ b/arch/powerpc/kernel/dbell.c
@@ -21,7 +21,7 @@
#ifdef CONFIG_SMP
void doorbell_setup_this_cpu(void)
{
- unsigned long tag = mfspr(SPRN_PIR) & 0x3fff;
+ unsigned long tag = mfspr(SPRN_DOORBELL_CPUTAG) & PPC_DBELL_TAG_MASK;
smp_muxed_ipi_set_data(smp_processor_id(), tag);
}
@@ -30,7 +30,7 @@ void doorbell_cause_ipi(int cpu, unsigned long data)
{
/* Order previous accesses vs. msgsnd, which is treated as a store */
mb();
- ppc_msgsnd(PPC_DBELL, 0, data);
+ ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, data);
}
void doorbell_exception(struct pt_regs *regs)
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 3d990d3bd8ba..256c5bf0adb7 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -62,8 +62,9 @@ system_call_common:
std r12,_MSR(r1)
std r0,GPR0(r1)
std r10,GPR1(r1)
+ beq 2f /* if from kernel mode */
ACCOUNT_CPU_USER_ENTRY(r10, r11)
- std r2,GPR2(r1)
+2: std r2,GPR2(r1)
std r3,GPR3(r1)
mfcr r2
std r4,GPR4(r1)
@@ -94,7 +95,7 @@ system_call_common:
addi r9,r1,STACK_FRAME_OVERHEAD
ld r11,exception_marker@toc(r2)
std r11,-16(r9) /* "regshere" marker */
-#if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR)
+#if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(CONFIG_PPC_SPLPAR)
BEGIN_FW_FTR_SECTION
beq 33f
/* if from user, see if there are any DTL entries to process */
@@ -110,7 +111,7 @@ BEGIN_FW_FTR_SECTION
addi r9,r1,STACK_FRAME_OVERHEAD
33:
END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE && CONFIG_PPC_SPLPAR */
/*
* A syscall should always be called with interrupts enabled
@@ -226,6 +227,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
beq- 1f
ACCOUNT_CPU_USER_EXIT(r11, r12)
+ HMT_MEDIUM_LOW_HAS_PPR
ld r13,GPR13(r1) /* only restore r13 if returning to usermode */
1: ld r2,GPR2(r1)
ld r1,GPR1(r1)
@@ -302,6 +304,7 @@ syscall_exit_work:
subi r12,r12,TI_FLAGS
4: /* Anything else left to do? */
+ SET_DEFAULT_THREAD_PPR(r3, r9) /* Set thread.ppr = 3 */
andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
beq .ret_from_except_lite
@@ -445,6 +448,19 @@ END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
std r23,_CCR(r1)
std r1,KSP(r3) /* Set old stack pointer */
+#ifdef CONFIG_PPC_BOOK3S_64
+BEGIN_FTR_SECTION
+ /*
+ * Back up the TAR across context switches. Note that the TAR is not
+ * available for use in the kernel. (To provide this, the TAR should
+ * be backed up/restored on exception entry/exit instead, and be in
+ * pt_regs. FIXME, this should be in pt_regs anyway (for debug).)
+ */
+ mfspr r0,SPRN_TAR
+ std r0,THREAD_TAR(r3)
+END_FTR_SECTION_IFSET(CPU_FTR_BCTAR)
+#endif
+
#ifdef CONFIG_SMP
/* We need a sync somewhere here to make sure that if the
* previous task gets rescheduled on another CPU, it sees all
@@ -527,6 +543,13 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
mr r1,r8 /* start using new stack pointer */
std r7,PACAKSAVE(r13)
+#ifdef CONFIG_PPC_BOOK3S_64
+BEGIN_FTR_SECTION
+ ld r0,THREAD_TAR(r4)
+ mtspr SPRN_TAR,r0
+END_FTR_SECTION_IFSET(CPU_FTR_BCTAR)
+#endif
+
#ifdef CONFIG_ALTIVEC
BEGIN_FTR_SECTION
ld r0,THREAD_VRSAVE(r4)
@@ -762,6 +785,10 @@ fast_exception_return:
andc r4,r4,r0 /* r0 contains MSR_RI here */
mtmsrd r4,1
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ /* TM debug */
+ std r3, PACATMSCRATCH(r13) /* Stash returned-to MSR */
+#endif
/*
* r13 is our per cpu area, only restore it if we are returning to
* userspace the value stored in the stack frame may belong to
@@ -770,6 +797,7 @@ fast_exception_return:
andi. r0,r3,MSR_PR
beq 1f
ACCOUNT_CPU_USER_EXIT(r2, r4)
+ RESTORE_PPR(r2, r4)
REST_GPR(13, r1)
1:
mtspr SPRN_SRR1,r3
@@ -849,13 +877,22 @@ restore_check_irq_replay:
addi r3,r1,STACK_FRAME_OVERHEAD;
bl .timer_interrupt
b .ret_from_except
+#ifdef CONFIG_PPC_DOORBELL
+1:
#ifdef CONFIG_PPC_BOOK3E
-1: cmpwi cr0,r3,0x280
+ cmpwi cr0,r3,0x280
+#else
+ BEGIN_FTR_SECTION
+ cmpwi cr0,r3,0xe80
+ FTR_SECTION_ELSE
+ cmpwi cr0,r3,0xa00
+ ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
+#endif /* CONFIG_PPC_BOOK3E */
bne 1f
addi r3,r1,STACK_FRAME_OVERHEAD;
bl .doorbell_exception
b .ret_from_except
-#endif /* CONFIG_PPC_BOOK3E */
+#endif /* CONFIG_PPC_DOORBELL */
1: b .ret_from_except /* What else to do here ? */
unrecov_restore:
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 4684e33a26c3..ae54553eacd9 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -159,8 +159,9 @@ exc_##n##_common: \
std r9,GPR9(r1); /* save r9 in stackframe */ \
std r10,_NIP(r1); /* save SRR0 to stackframe */ \
std r11,_MSR(r1); /* save SRR1 to stackframe */ \
+ beq 2f; /* if from kernel mode */ \
ACCOUNT_CPU_USER_ENTRY(r10,r11);/* accounting (uses cr0+eq) */ \
- ld r3,excf+EX_R10(r13); /* get back r10 */ \
+2: ld r3,excf+EX_R10(r13); /* get back r10 */ \
ld r4,excf+EX_R11(r13); /* get back r11 */ \
mfspr r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 */ \
std r12,GPR12(r1); /* save r12 in stackframe */ \
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 4665e82fa377..a8a5361fb70c 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -104,7 +104,7 @@ __start_interrupts:
.globl system_reset_pSeries;
system_reset_pSeries:
- HMT_MEDIUM;
+ HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13)
#ifdef CONFIG_PPC_P7_NAP
BEGIN_FTR_SECTION
@@ -153,12 +153,15 @@ machine_check_pSeries_1:
* some code path might still want to branch into the original
* vector
*/
- b machine_check_pSeries
+ HMT_MEDIUM_PPR_DISCARD
+ SET_SCRATCH0(r13) /* save r13 */
+ EXCEPTION_PROLOG_0(PACA_EXMC)
+ b machine_check_pSeries_0
. = 0x300
.globl data_access_pSeries
data_access_pSeries:
- HMT_MEDIUM
+ HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13)
BEGIN_FTR_SECTION
b data_access_check_stab
@@ -170,8 +173,9 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
. = 0x380
.globl data_access_slb_pSeries
data_access_slb_pSeries:
- HMT_MEDIUM
+ HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXSLB)
EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380)
std r3,PACA_EXSLB+EX_R3(r13)
mfspr r3,SPRN_DAR
@@ -201,8 +205,9 @@ data_access_slb_pSeries:
. = 0x480
.globl instruction_access_slb_pSeries
instruction_access_slb_pSeries:
- HMT_MEDIUM
+ HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXSLB)
EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480)
std r3,PACA_EXSLB+EX_R3(r13)
mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */
@@ -252,7 +257,7 @@ hardware_interrupt_hv:
MASKABLE_EXCEPTION_PSERIES(0x900, 0x900, decrementer)
STD_EXCEPTION_HV(0x980, 0x982, hdecrementer)
- STD_EXCEPTION_PSERIES(0xa00, 0xa00, trap_0a)
+ MASKABLE_EXCEPTION_PSERIES(0xa00, 0xa00, doorbell_super)
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xa00)
STD_EXCEPTION_PSERIES(0xb00, 0xb00, trap_0b)
@@ -284,16 +289,30 @@ system_call_pSeries:
*/
. = 0xe00
hv_exception_trampoline:
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b h_data_storage_hv
+
. = 0xe20
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b h_instr_storage_hv
+
. = 0xe40
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b emulation_assist_hv
- . = 0xe50
- b hmi_exception_hv
+
. = 0xe60
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b hmi_exception_hv
+ . = 0xe80
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
+ b h_doorbell_hv
+
/* We need to deal with the Altivec unavailable exception
* here which is at 0xf20, thus in the middle of the
* prolog code of the PerformanceMonitor one. A little
@@ -301,16 +320,27 @@ hv_exception_trampoline:
*/
performance_monitor_pSeries_1:
. = 0xf00
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b performance_monitor_pSeries
altivec_unavailable_pSeries_1:
. = 0xf20
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b altivec_unavailable_pSeries
vsx_unavailable_pSeries_1:
. = 0xf40
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b vsx_unavailable_pSeries
+ . = 0xf60
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
+ b tm_unavailable_pSeries
+
#ifdef CONFIG_CBE_RAS
STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error)
KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1202)
@@ -322,11 +352,9 @@ vsx_unavailable_pSeries_1:
. = 0x1500
.global denorm_exception_hv
denorm_exception_hv:
- HMT_MEDIUM
+ HMT_MEDIUM_PPR_DISCARD
mtspr SPRN_SPRG_HSCRATCH0,r13
- mfspr r13,SPRN_SPRG_HPACA
- std r9,PACA_EXGEN+EX_R9(r13)
- std r10,PACA_EXGEN+EX_R10(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
std r11,PACA_EXGEN+EX_R11(r13)
std r12,PACA_EXGEN+EX_R12(r13)
mfspr r9,SPRN_SPRG_HSCRATCH0
@@ -367,10 +395,12 @@ denorm_exception_hv:
machine_check_pSeries:
.globl machine_check_fwnmi
machine_check_fwnmi:
- HMT_MEDIUM
+ HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13) /* save r13 */
- EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common,
- EXC_STD, KVMTEST, 0x200)
+ EXCEPTION_PROLOG_0(PACA_EXMC)
+machine_check_pSeries_0:
+ EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST, 0x200)
+ EXCEPTION_PROLOG_PSERIES_1(machine_check_common, EXC_STD)
KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200)
/* moved from 0x300 */
@@ -496,6 +526,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
mtspr SPRN_HSRR0,r11
mtcrf 0x80,r9
ld r9,PACA_EXGEN+EX_R9(r13)
+ RESTORE_PPR_PACA(PACA_EXGEN, r10)
ld r10,PACA_EXGEN+EX_R10(r13)
ld r11,PACA_EXGEN+EX_R11(r13)
ld r12,PACA_EXGEN+EX_R12(r13)
@@ -506,28 +537,34 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
.align 7
/* moved from 0xe00 */
- STD_EXCEPTION_HV(., 0xe02, h_data_storage)
+ STD_EXCEPTION_HV_OOL(0xe02, h_data_storage)
KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0xe02)
- STD_EXCEPTION_HV(., 0xe22, h_instr_storage)
+ STD_EXCEPTION_HV_OOL(0xe22, h_instr_storage)
KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe22)
- STD_EXCEPTION_HV(., 0xe42, emulation_assist)
+ STD_EXCEPTION_HV_OOL(0xe42, emulation_assist)
KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe42)
- STD_EXCEPTION_HV(., 0xe62, hmi_exception) /* need to flush cache ? */
+ STD_EXCEPTION_HV_OOL(0xe62, hmi_exception) /* need to flush cache ? */
KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe62)
+ MASKABLE_EXCEPTION_HV_OOL(0xe82, h_doorbell)
+ KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe82)
/* moved from 0xf00 */
- STD_EXCEPTION_PSERIES(., 0xf00, performance_monitor)
+ STD_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor)
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf00)
- STD_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable)
+ STD_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf20)
- STD_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable)
+ STD_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)
+ STD_EXCEPTION_PSERIES_OOL(0xf60, tm_unavailable)
+ KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf60)
/*
- * An interrupt came in while soft-disabled. We set paca->irq_happened,
- * then, if it was a decrementer interrupt, we bump the dec to max and
- * and return, else we hard disable and return. This is called with
- * r10 containing the value to OR to the paca field.
+ * An interrupt came in while soft-disabled. We set paca->irq_happened, then:
+ * - If it was a decrementer interrupt, we bump the dec to max and and return.
+ * - If it was a doorbell we return immediately since doorbells are edge
+ * triggered and won't automatically refire.
+ * - else we hard disable and return.
+ * This is called with r10 containing the value to OR to the paca field.
*/
#define MASKED_INTERRUPT(_H) \
masked_##_H##interrupt: \
@@ -535,13 +572,15 @@ masked_##_H##interrupt: \
lbz r11,PACAIRQHAPPENED(r13); \
or r11,r11,r10; \
stb r11,PACAIRQHAPPENED(r13); \
- andi. r10,r10,PACA_IRQ_DEC; \
- beq 1f; \
+ cmpwi r10,PACA_IRQ_DEC; \
+ bne 1f; \
lis r10,0x7fff; \
ori r10,r10,0xffff; \
mtspr SPRN_DEC,r10; \
b 2f; \
-1: mfspr r10,SPRN_##_H##SRR1; \
+1: cmpwi r10,PACA_IRQ_DBELL; \
+ beq 2f; \
+ mfspr r10,SPRN_##_H##SRR1; \
rldicl r10,r10,48,1; /* clear MSR_EE */ \
rotldi r10,r10,16; \
mtspr SPRN_##_H##SRR1,r10; \
@@ -558,8 +597,8 @@ masked_##_H##interrupt: \
/*
* Called from arch_local_irq_enable when an interrupt needs
- * to be resent. r3 contains 0x500 or 0x900 to indicate which
- * kind of interrupt. MSR:EE is already off. We generate a
+ * to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
+ * which kind of interrupt. MSR:EE is already off. We generate a
* stackframe like if a real interrupt had happened.
*
* Note: While MSR:EE is off, we need to make sure that _MSR
@@ -575,9 +614,18 @@ _GLOBAL(__replay_interrupt)
mflr r11
mfcr r9
ori r12,r12,MSR_EE
- andi. r3,r3,0x0800
- bne decrementer_common
- b hardware_interrupt_common
+ cmpwi r3,0x900
+ beq decrementer_common
+ cmpwi r3,0x500
+ beq hardware_interrupt_common
+BEGIN_FTR_SECTION
+ cmpwi r3,0xe80
+ beq h_doorbell_common
+FTR_SECTION_ELSE
+ cmpwi r3,0xa00
+ beq doorbell_super_common
+ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
+ blr
#ifdef CONFIG_PPC_PSERIES
/*
@@ -586,7 +634,7 @@ _GLOBAL(__replay_interrupt)
.globl system_reset_fwnmi
.align 7
system_reset_fwnmi:
- HMT_MEDIUM
+ HMT_MEDIUM_PPR_DISCARD
SET_SCRATCH0(r13) /* save r13 */
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
NOTEST, 0x100)
@@ -651,12 +699,21 @@ machine_check_common:
STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ)
STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt)
STD_EXCEPTION_COMMON(0x980, hdecrementer, .hdec_interrupt)
- STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception)
+#ifdef CONFIG_PPC_DOORBELL
+ STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, .doorbell_exception)
+#else
+ STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, .unknown_exception)
+#endif
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)
+#ifdef CONFIG_PPC_DOORBELL
+ STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, .doorbell_exception)
+#else
+ STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, .unknown_exception)
+#endif
STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception)
STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception)
STD_EXCEPTION_COMMON(0x1502, denorm, .unknown_exception)
@@ -690,8 +747,8 @@ machine_check_common:
. = 0x4380
.globl data_access_slb_relon_pSeries
data_access_slb_relon_pSeries:
- HMT_MEDIUM
SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXSLB)
EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380)
std r3,PACA_EXSLB+EX_R3(r13)
mfspr r3,SPRN_DAR
@@ -715,8 +772,8 @@ data_access_slb_relon_pSeries:
. = 0x4480
.globl instruction_access_slb_relon_pSeries
instruction_access_slb_relon_pSeries:
- HMT_MEDIUM
SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXSLB)
EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480)
std r3,PACA_EXSLB+EX_R3(r13)
mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */
@@ -746,6 +803,7 @@ hardware_interrupt_relon_hv:
STD_RELON_EXCEPTION_PSERIES(0x4800, 0x800, fp_unavailable)
MASKABLE_RELON_EXCEPTION_PSERIES(0x4900, 0x900, decrementer)
STD_RELON_EXCEPTION_HV(0x4980, 0x982, hdecrementer)
+ MASKABLE_RELON_EXCEPTION_PSERIES(0x4a00, 0xa00, doorbell_super)
STD_RELON_EXCEPTION_PSERIES(0x4b00, 0xb00, trap_0b)
. = 0x4c00
@@ -759,56 +817,64 @@ system_call_relon_pSeries:
STD_RELON_EXCEPTION_PSERIES(0x4d00, 0xd00, single_step)
. = 0x4e00
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b h_data_storage_relon_hv
. = 0x4e20
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b h_instr_storage_relon_hv
. = 0x4e40
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b emulation_assist_relon_hv
- . = 0x4e50
- b hmi_exception_relon_hv
-
. = 0x4e60
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b hmi_exception_relon_hv
- /* For when we support the doorbell interrupt:
- STD_RELON_EXCEPTION_HYPERVISOR(0x4e80, 0xe80, doorbell_hyper)
- */
+ . = 0x4e80
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
+ b h_doorbell_relon_hv
performance_monitor_relon_pSeries_1:
. = 0x4f00
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b performance_monitor_relon_pSeries
altivec_unavailable_relon_pSeries_1:
. = 0x4f20
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b altivec_unavailable_relon_pSeries
vsx_unavailable_relon_pSeries_1:
. = 0x4f40
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
b vsx_unavailable_relon_pSeries
-#ifdef CONFIG_CBE_RAS
- STD_RELON_EXCEPTION_HV(0x5200, 0x1202, cbe_system_error)
-#endif /* CONFIG_CBE_RAS */
+tm_unavailable_relon_pSeries_1:
+ . = 0x4f60
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
+ b tm_unavailable_relon_pSeries
+
STD_RELON_EXCEPTION_PSERIES(0x5300, 0x1300, instruction_breakpoint)
#ifdef CONFIG_PPC_DENORMALISATION
. = 0x5500
b denorm_exception_hv
#endif
-#ifdef CONFIG_CBE_RAS
- STD_RELON_EXCEPTION_HV(0x5600, 0x1602, cbe_maintenance)
-#else
#ifdef CONFIG_HVC_SCOM
STD_RELON_EXCEPTION_HV(0x5600, 0x1600, maintence_interrupt)
KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1600)
#endif /* CONFIG_HVC_SCOM */
-#endif /* CONFIG_CBE_RAS */
STD_RELON_EXCEPTION_PSERIES(0x5700, 0x1700, altivec_assist)
-#ifdef CONFIG_CBE_RAS
- STD_RELON_EXCEPTION_HV(0x5800, 0x1802, cbe_thermal)
-#endif /* CONFIG_CBE_RAS */
/* Other future vectors */
.align 7
@@ -1036,6 +1102,7 @@ _GLOBAL(slb_miss_realmode)
mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */
.machine pop
+ RESTORE_PPR_PACA(PACA_EXSLB, r9)
ld r9,PACA_EXSLB+EX_R9(r13)
ld r10,PACA_EXSLB+EX_R10(r13)
ld r11,PACA_EXSLB+EX_R11(r13)
@@ -1109,9 +1176,26 @@ fp_unavailable_common:
addi r3,r1,STACK_FRAME_OVERHEAD
bl .kernel_fp_unavailable_exception
BUG_OPCODE
-1: bl .load_up_fpu
+1:
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+ /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
+ * transaction), go do TM stuff
+ */
+ rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
+ bne- 2f
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
+ bl .load_up_fpu
b fast_exception_return
-
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl .save_nvgprs
+ DISABLE_INTS
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .fp_unavailable_tm
+ b .ret_from_except
+#endif
.align 7
.globl altivec_unavailable_common
altivec_unavailable_common:
@@ -1119,8 +1203,25 @@ altivec_unavailable_common:
#ifdef CONFIG_ALTIVEC
BEGIN_FTR_SECTION
beq 1f
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ BEGIN_FTR_SECTION_NESTED(69)
+ /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
+ * transaction), go do TM stuff
+ */
+ rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
+ bne- 2f
+ END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
+#endif
bl .load_up_altivec
b fast_exception_return
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl .save_nvgprs
+ DISABLE_INTS
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .altivec_unavailable_tm
+ b .ret_from_except
+#endif
1:
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif
@@ -1137,7 +1238,24 @@ vsx_unavailable_common:
#ifdef CONFIG_VSX
BEGIN_FTR_SECTION
beq 1f
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ BEGIN_FTR_SECTION_NESTED(69)
+ /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
+ * transaction), go do TM stuff
+ */
+ rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
+ bne- 2f
+ END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
+#endif
b .load_up_vsx
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl .save_nvgprs
+ DISABLE_INTS
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .vsx_unavailable_tm
+ b .ret_from_except
+#endif
1:
END_FTR_SECTION_IFSET(CPU_FTR_VSX)
#endif
@@ -1148,9 +1266,75 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
b .ret_from_except
.align 7
+ .globl tm_unavailable_common
+tm_unavailable_common:
+ EXCEPTION_PROLOG_COMMON(0xf60, PACA_EXGEN)
+ bl .save_nvgprs
+ DISABLE_INTS
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .tm_unavailable_exception
+ b .ret_from_except
+
+ .align 7
.globl __end_handlers
__end_handlers:
+ /* Equivalents to the above handlers for relocation-on interrupt vectors */
+ STD_RELON_EXCEPTION_HV_OOL(0xe00, h_data_storage)
+ KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe00)
+ STD_RELON_EXCEPTION_HV_OOL(0xe20, h_instr_storage)
+ KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe20)
+ STD_RELON_EXCEPTION_HV_OOL(0xe40, emulation_assist)
+ KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe40)
+ STD_RELON_EXCEPTION_HV_OOL(0xe60, hmi_exception)
+ KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe60)
+ MASKABLE_RELON_EXCEPTION_HV_OOL(0xe80, h_doorbell)
+ KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe80)
+
+ STD_RELON_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor)
+ STD_RELON_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
+ STD_RELON_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
+ STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, tm_unavailable)
+
+#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
+/*
+ * Data area reserved for FWNMI option.
+ * This address (0x7000) is fixed by the RPA.
+ */
+ .= 0x7000
+ .globl fwnmi_data_area
+fwnmi_data_area:
+
+ /* pseries and powernv need to keep the whole page from
+ * 0x7000 to 0x8000 free for use by the firmware
+ */
+ . = 0x8000
+#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
+
+/* Space for CPU0's segment table */
+ .balign 4096
+ .globl initial_stab
+initial_stab:
+ .space 4096
+
+#ifdef CONFIG_PPC_POWERNV
+_GLOBAL(opal_mc_secondary_handler)
+ HMT_MEDIUM_PPR_DISCARD
+ SET_SCRATCH0(r13)
+ GET_PACA(r13)
+ clrldi r3,r3,2
+ tovirt(r3,r3)
+ std r3,PACA_OPAL_MC_EVT(r13)
+ ld r13,OPAL_MC_SRR0(r3)
+ mtspr SPRN_SRR0,r13
+ ld r13,OPAL_MC_SRR1(r3)
+ mtspr SPRN_SRR1,r13
+ ld r3,OPAL_MC_GPR3(r3)
+ GET_SCRATCH0(r13)
+ b machine_check_pSeries
+#endif /* CONFIG_PPC_POWERNV */
+
+
/*
* Hash table stuff
*/
@@ -1222,7 +1406,7 @@ handle_dabr_fault:
ld r4,_DAR(r1)
ld r5,_DSISR(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
- bl .do_dabr
+ bl .do_break
12: b .ret_from_except_lite
@@ -1344,56 +1528,3 @@ _GLOBAL(do_stab_bolted)
ld r13,PACA_EXSLB+EX_R13(r13)
rfid
b . /* prevent speculative execution */
-
-
- /* Equivalents to the above handlers for relocation-on interrupt vectors */
- STD_RELON_EXCEPTION_HV(., 0xe00, h_data_storage)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe00)
- STD_RELON_EXCEPTION_HV(., 0xe20, h_instr_storage)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe20)
- STD_RELON_EXCEPTION_HV(., 0xe40, emulation_assist)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe40)
- STD_RELON_EXCEPTION_HV(., 0xe60, hmi_exception)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe60)
-
- STD_RELON_EXCEPTION_PSERIES(., 0xf00, performance_monitor)
- STD_RELON_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable)
- STD_RELON_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable)
-
-#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
-/*
- * Data area reserved for FWNMI option.
- * This address (0x7000) is fixed by the RPA.
- */
- .= 0x7000
- .globl fwnmi_data_area
-fwnmi_data_area:
-
- /* pseries and powernv need to keep the whole page from
- * 0x7000 to 0x8000 free for use by the firmware
- */
- . = 0x8000
-#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
-
-/* Space for CPU0's segment table */
- .balign 4096
- .globl initial_stab
-initial_stab:
- .space 4096
-
-#ifdef CONFIG_PPC_POWERNV
-_GLOBAL(opal_mc_secondary_handler)
- HMT_MEDIUM
- SET_SCRATCH0(r13)
- GET_PACA(r13)
- clrldi r3,r3,2
- tovirt(r3,r3)
- std r3,PACA_OPAL_MC_EVT(r13)
- ld r13,OPAL_MC_SRR0(r3)
- mtspr SPRN_SRR0,r13
- ld r13,OPAL_MC_SRR1(r3)
- mtspr SPRN_SRR1,r13
- ld r3,OPAL_MC_GPR3(r3)
- GET_SCRATCH0(r13)
- b machine_check_pSeries
-#endif /* CONFIG_PPC_POWERNV */
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index e0ada05f2df3..caeaabf11a2f 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -35,6 +35,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
2: REST_32VSRS(n,c,base); \
3:
+#define __REST_32FPVSRS_TRANSACT(n,c,base) \
+BEGIN_FTR_SECTION \
+ b 2f; \
+END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
+ REST_32FPRS_TRANSACT(n,base); \
+ b 3f; \
+2: REST_32VSRS_TRANSACT(n,c,base); \
+3:
+
#define __SAVE_32FPVSRS(n,c,base) \
BEGIN_FTR_SECTION \
b 2f; \
@@ -45,11 +54,68 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
3:
#else
#define __REST_32FPVSRS(n,b,base) REST_32FPRS(n, base)
+#define __REST_32FPVSRS_TRANSACT(n,b,base) REST_32FPRS(n, base)
#define __SAVE_32FPVSRS(n,b,base) SAVE_32FPRS(n, base)
#endif
#define REST_32FPVSRS(n,c,base) __REST_32FPVSRS(n,__REG_##c,__REG_##base)
+#define REST_32FPVSRS_TRANSACT(n,c,base) \
+ __REST_32FPVSRS_TRANSACT(n,__REG_##c,__REG_##base)
#define SAVE_32FPVSRS(n,c,base) __SAVE_32FPVSRS(n,__REG_##c,__REG_##base)
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Wrapper to call load_up_fpu from C.
+ * void do_load_up_fpu(struct pt_regs *regs);
+ */
+_GLOBAL(do_load_up_fpu)
+ mflr r0
+ std r0, 16(r1)
+ stdu r1, -112(r1)
+
+ subi r6, r3, STACK_FRAME_OVERHEAD
+ /* load_up_fpu expects r12=MSR, r13=PACA, and returns
+ * with r12 = new MSR.
+ */
+ ld r12,_MSR(r6)
+ GET_PACA(r13)
+
+ bl load_up_fpu
+ std r12,_MSR(r6)
+
+ ld r0, 112+16(r1)
+ addi r1, r1, 112
+ mtlr r0
+ blr
+
+
+/* void do_load_up_transact_fpu(struct thread_struct *thread)
+ *
+ * This is similar to load_up_fpu but for the transactional version of the FP
+ * register set. It doesn't mess with the task MSR or valid flags.
+ * Furthermore, we don't do lazy FP with TM currently.
+ */
+_GLOBAL(do_load_up_transact_fpu)
+ mfmsr r6
+ ori r5,r6,MSR_FP
+#ifdef CONFIG_VSX
+BEGIN_FTR_SECTION
+ oris r5,r5,MSR_VSX@h
+END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif
+ SYNC
+ MTMSRD(r5)
+
+ lfd fr0,THREAD_TRANSACT_FPSCR(r3)
+ MTFSF_L(fr0)
+ REST_32FPVSRS_TRANSACT(0, R4, R3)
+
+ /* FP/VSX off again */
+ MTMSRD(r6)
+ SYNC
+
+ blr
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
/*
* This task wants to use the FPU now.
* On UP, disable FP for the task which had the FPU previously,
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index 4989661b710b..8a9b6f59822d 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -430,30 +430,18 @@ label:
EXCEPTION(0x0F00, Trap_0F, unknown_exception, EXC_XFER_EE)
/* 0x1000 - Programmable Interval Timer (PIT) Exception */
- START_EXCEPTION(0x1000, Decrementer)
- NORMAL_EXCEPTION_PROLOG
- lis r0,TSR_PIS@h
- mtspr SPRN_TSR,r0 /* Clear the PIT exception */
- addi r3,r1,STACK_FRAME_OVERHEAD
- EXC_XFER_LITE(0x1000, timer_interrupt)
-
-#if 0
-/* NOTE:
- * FIT and WDT handlers are not implemented yet.
- */
+ . = 0x1000
+ b Decrementer
/* 0x1010 - Fixed Interval Timer (FIT) Exception
*/
- STND_EXCEPTION(0x1010, FITException, unknown_exception)
+ . = 0x1010
+ b FITException
/* 0x1020 - Watchdog Timer (WDT) Exception
*/
-#ifdef CONFIG_BOOKE_WDT
- CRITICAL_EXCEPTION(0x1020, WDTException, WatchdogException)
-#else
- CRITICAL_EXCEPTION(0x1020, WDTException, unknown_exception)
-#endif
-#endif
+ . = 0x1020
+ b WDTException
/* 0x1100 - Data TLB Miss Exception
* As the name implies, translation is not in the MMU, so search the
@@ -738,6 +726,29 @@ label:
(MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+ /* Programmable Interval Timer (PIT) Exception. (from 0x1000) */
+Decrementer:
+ NORMAL_EXCEPTION_PROLOG
+ lis r0,TSR_PIS@h
+ mtspr SPRN_TSR,r0 /* Clear the PIT exception */
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_LITE(0x1000, timer_interrupt)
+
+ /* Fixed Interval Timer (FIT) Exception. (from 0x1010) */
+FITException:
+ NORMAL_EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD;
+ EXC_XFER_EE(0x1010, unknown_exception)
+
+ /* Watchdog Timer (WDT) Exception. (from 0x1020) */
+WDTException:
+ CRITICAL_EXCEPTION_PROLOG;
+ addi r3,r1,STACK_FRAME_OVERHEAD;
+ EXC_XFER_TEMPLATE(WatchdogException, 0x1020+2,
+ (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)),
+ NOCOPY, crit_transfer_to_handler,
+ ret_from_crit_exc)
+
/*
* The other Data TLB exceptions bail out to this point
* if they can't resolve the lightweight TLB fault.
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 116f0868695b..0886ae6dd5be 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -122,6 +122,8 @@ __secondary_hold:
#endif
/* Grab our physical cpu number */
mr r24,r3
+ /* stash r4 for book3e */
+ mr r25,r4
/* Tell the master cpu we're here */
/* Relocation is off & we are located at an address less */
@@ -129,16 +131,31 @@ __secondary_hold:
std r24,__secondary_hold_acknowledge-_stext(0)
sync
+ li r26,0
+#ifdef CONFIG_PPC_BOOK3E
+ tovirt(r26,r26)
+#endif
/* All secondary cpus wait here until told to start. */
-100: ld r4,__secondary_hold_spinloop-_stext(0)
+100: ld r4,__secondary_hold_spinloop-_stext(r26)
cmpdi 0,r4,0
beq 100b
#if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
+#ifdef CONFIG_PPC_BOOK3E
+ tovirt(r4,r4)
+#endif
ld r4,0(r4) /* deref function descriptor */
mtctr r4
mr r3,r24
+ /*
+ * it may be the case that other platforms have r4 right to
+ * begin with, this gives us some safety in case it is not
+ */
+#ifdef CONFIG_PPC_BOOK3E
+ mr r4,r25
+#else
li r4,0
+#endif
/* Make sure that patched code is visible */
isync
bctr
@@ -169,6 +186,7 @@ _GLOBAL(generic_secondary_thread_init)
/* get a valid TOC pointer, wherever we're mapped at */
bl .relative_toc
+ tovirt(r2,r2)
#ifdef CONFIG_PPC_BOOK3E
/* Book3E initialization */
@@ -195,6 +213,7 @@ _GLOBAL(generic_secondary_smp_init)
/* get a valid TOC pointer, wherever we're mapped at */
bl .relative_toc
+ tovirt(r2,r2)
#ifdef CONFIG_PPC_BOOK3E
/* Book3E initialization */
@@ -531,6 +550,7 @@ _GLOBAL(pmac_secondary_start)
/* get TOC pointer (real address) */
bl .relative_toc
+ tovirt(r2,r2)
/* Copy some CPU settings from CPU 0 */
bl .__restore_cpu_ppc970
@@ -665,6 +685,13 @@ _GLOBAL(enable_64b_mode)
* This puts the TOC pointer into r2, offset by 0x8000 (as expected
* by the toolchain). It computes the correct value for wherever we
* are running at the moment, using position-independent code.
+ *
+ * Note: The compiler constructs pointers using offsets from the
+ * TOC in -mcmodel=medium mode. After we relocate to 0 but before
+ * the MMU is on we need our TOC to be a virtual address otherwise
+ * these pointers will be real addresses which may get stored and
+ * accessed later with the MMU on. We use tovirt() at the call
+ * sites to handle this.
*/
_GLOBAL(relative_toc)
mflr r0
@@ -681,8 +708,9 @@ p_toc: .llong __toc_start + 0x8000 - 0b
* This is where the main kernel code starts.
*/
_INIT_STATIC(start_here_multiplatform)
- /* set up the TOC (real address) */
- bl .relative_toc
+ /* set up the TOC */
+ bl .relative_toc
+ tovirt(r2,r2)
/* Clear out the BSS. It may have been done in prom_init,
* already but that's irrelevant since prom_init will soon
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index a89cae481b04..a949bdfc9623 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -73,7 +73,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
* If so, DABR will be populated in single_step_dabr_instruction().
*/
if (current->thread.last_hit_ubp != bp)
- set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
+ set_breakpoint(info);
return 0;
}
@@ -97,7 +97,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
}
*slot = NULL;
- set_dabr(0, 0);
+ hw_breakpoint_disable();
}
/*
@@ -127,19 +127,13 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp)
int arch_bp_generic_fields(int type, int *gen_bp_type)
{
- switch (type) {
- case DABR_DATA_READ:
- *gen_bp_type = HW_BREAKPOINT_R;
- break;
- case DABR_DATA_WRITE:
- *gen_bp_type = HW_BREAKPOINT_W;
- break;
- case (DABR_DATA_WRITE | DABR_DATA_READ):
- *gen_bp_type = (HW_BREAKPOINT_W | HW_BREAKPOINT_R);
- break;
- default:
+ *gen_bp_type = 0;
+ if (type & HW_BRK_TYPE_READ)
+ *gen_bp_type |= HW_BREAKPOINT_R;
+ if (type & HW_BRK_TYPE_WRITE)
+ *gen_bp_type |= HW_BREAKPOINT_W;
+ if (*gen_bp_type == 0)
return -EINVAL;
- }
return 0;
}
@@ -148,35 +142,28 @@ int arch_bp_generic_fields(int type, int *gen_bp_type)
*/
int arch_validate_hwbkpt_settings(struct perf_event *bp)
{
- int ret = -EINVAL;
+ int ret = -EINVAL, length_max;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
if (!bp)
return ret;
- switch (bp->attr.bp_type) {
- case HW_BREAKPOINT_R:
- info->type = DABR_DATA_READ;
- break;
- case HW_BREAKPOINT_W:
- info->type = DABR_DATA_WRITE;
- break;
- case HW_BREAKPOINT_R | HW_BREAKPOINT_W:
- info->type = (DABR_DATA_READ | DABR_DATA_WRITE);
- break;
- default:
+ info->type = HW_BRK_TYPE_TRANSLATE;
+ if (bp->attr.bp_type & HW_BREAKPOINT_R)
+ info->type |= HW_BRK_TYPE_READ;
+ if (bp->attr.bp_type & HW_BREAKPOINT_W)
+ info->type |= HW_BRK_TYPE_WRITE;
+ if (info->type == HW_BRK_TYPE_TRANSLATE)
+ /* must set alteast read or write */
return ret;
- }
-
+ if (!(bp->attr.exclude_user))
+ info->type |= HW_BRK_TYPE_USER;
+ if (!(bp->attr.exclude_kernel))
+ info->type |= HW_BRK_TYPE_KERNEL;
+ if (!(bp->attr.exclude_hv))
+ info->type |= HW_BRK_TYPE_HYP;
info->address = bp->attr.bp_addr;
info->len = bp->attr.bp_len;
- info->dabrx = DABRX_ALL;
- if (bp->attr.exclude_user)
- info->dabrx &= ~DABRX_USER;
- if (bp->attr.exclude_kernel)
- info->dabrx &= ~DABRX_KERNEL;
- if (bp->attr.exclude_hv)
- info->dabrx &= ~DABRX_HYP;
/*
* Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8)
@@ -184,8 +171,16 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
* HW_BREAKPOINT_ALIGN by rounding off to the lower address, the
* 'symbolsize' should satisfy the check below.
*/
+ length_max = 8; /* DABR */
+ if (cpu_has_feature(CPU_FTR_DAWR)) {
+ length_max = 512 ; /* 64 doublewords */
+ /* DAWR region can't cross 512 boundary */
+ if ((bp->attr.bp_addr >> 10) !=
+ ((bp->attr.bp_addr + bp->attr.bp_len) >> 10))
+ return -EINVAL;
+ }
if (info->len >
- (HW_BREAKPOINT_LEN - (info->address & HW_BREAKPOINT_ALIGN)))
+ (length_max - (info->address & HW_BREAKPOINT_ALIGN)))
return -EINVAL;
return 0;
}
@@ -204,7 +199,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
info = counter_arch_bp(tsk->thread.last_hit_ubp);
regs->msr &= ~MSR_SE;
- set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
+ set_breakpoint(info);
tsk->thread.last_hit_ubp = NULL;
}
@@ -222,7 +217,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
unsigned long dar = regs->dar;
/* Disable breakpoints during exception handling */
- set_dabr(0, 0);
+ hw_breakpoint_disable();
/*
* The counter may be concurrently released but that can only
@@ -255,8 +250,9 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
* we still need to single-step the instruction, but we don't
* generate an event.
*/
- info->extraneous_interrupt = !((bp->attr.bp_addr <= dar) &&
- (dar - bp->attr.bp_addr < bp->attr.bp_len));
+ if (!((bp->attr.bp_addr <= dar) &&
+ (dar - bp->attr.bp_addr < bp->attr.bp_len)))
+ info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
/* Do not emulate user-space instructions, instead single-step them */
if (user_mode(regs)) {
@@ -285,10 +281,10 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
* As a policy, the callback is invoked in a 'trigger-after-execute'
* fashion
*/
- if (!info->extraneous_interrupt)
+ if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
perf_bp_event(bp, regs);
- set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
+ set_breakpoint(info);
out:
rcu_read_unlock();
return rc;
@@ -317,10 +313,10 @@ int __kprobes single_step_dabr_instruction(struct die_args *args)
* We shall invoke the user-defined callback function in the single
* stepping handler to confirm to 'trigger-after-execute' semantics
*/
- if (!info->extraneous_interrupt)
+ if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
perf_bp_event(bp, regs);
- set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
+ set_breakpoint(info);
current->thread.last_hit_ubp = NULL;
/*
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index c862fd716fe3..31c4fdc6859c 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -717,6 +717,13 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name)
return;
}
+ /*
+ * In case we have reserved the first bit, we should not emit
+ * the warning below.
+ */
+ if (tbl->it_offset == 0)
+ clear_bit(0, tbl->it_map);
+
/* verify that table contains no entries */
if (!bitmap_empty(tbl->it_map, tbl->it_size))
pr_warn("%s: Unexpected TCEs for %s\n", __func__, node_name);
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 71413f41278f..4f97fe345526 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -122,8 +122,8 @@ static inline notrace int decrementer_check_overflow(void)
}
/* This is called whenever we are re-enabling interrupts
- * and returns either 0 (nothing to do) or 500/900 if there's
- * either an EE or a DEC to generate.
+ * and returns either 0 (nothing to do) or 500/900/280/a00/e80 if
+ * there's an EE, DEC or DBELL to generate.
*
* This is called in two contexts: From arch_local_irq_restore()
* before soft-enabling interrupts, and from the exception exit
@@ -182,6 +182,13 @@ notrace unsigned int __check_irq_replay(void)
local_paca->irq_happened &= ~PACA_IRQ_DBELL;
if (happened & PACA_IRQ_DBELL)
return 0x280;
+#else
+ local_paca->irq_happened &= ~PACA_IRQ_DBELL;
+ if (happened & PACA_IRQ_DBELL) {
+ if (cpu_has_feature(CPU_FTR_HVMODE))
+ return 0xe80;
+ return 0xa00;
+ }
#endif /* CONFIG_PPC_BOOK3E */
/* There should be nothing left ! */
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index a7bc7521c064..5ca82cd4a374 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -199,7 +199,7 @@ static int kgdb_iabr_match(struct pt_regs *regs)
return 1;
}
-static int kgdb_dabr_match(struct pt_regs *regs)
+static int kgdb_break_match(struct pt_regs *regs)
{
if (user_mode(regs))
return 0;
@@ -459,7 +459,7 @@ static void *old__debugger;
static void *old__debugger_bpt;
static void *old__debugger_sstep;
static void *old__debugger_iabr_match;
-static void *old__debugger_dabr_match;
+static void *old__debugger_break_match;
static void *old__debugger_fault_handler;
int kgdb_arch_init(void)
@@ -469,7 +469,7 @@ int kgdb_arch_init(void)
old__debugger_bpt = __debugger_bpt;
old__debugger_sstep = __debugger_sstep;
old__debugger_iabr_match = __debugger_iabr_match;
- old__debugger_dabr_match = __debugger_dabr_match;
+ old__debugger_break_match = __debugger_break_match;
old__debugger_fault_handler = __debugger_fault_handler;
__debugger_ipi = kgdb_call_nmi_hook;
@@ -477,7 +477,7 @@ int kgdb_arch_init(void)
__debugger_bpt = kgdb_handle_breakpoint;
__debugger_sstep = kgdb_singlestep;
__debugger_iabr_match = kgdb_iabr_match;
- __debugger_dabr_match = kgdb_dabr_match;
+ __debugger_break_match = kgdb_break_match;
__debugger_fault_handler = kgdb_not_implemented;
return 0;
@@ -490,6 +490,6 @@ void kgdb_arch_exit(void)
__debugger_bpt = old__debugger_bpt;
__debugger_sstep = old__debugger_sstep;
__debugger_iabr_match = old__debugger_iabr_match;
- __debugger_dabr_match = old__debugger_dabr_match;
+ __debugger_break_match = old__debugger_break_match;
__debugger_fault_handler = old__debugger_fault_handler;
}
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 7206701b1ff1..466a2908bb63 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -162,6 +162,8 @@ static int kexec_all_irq_disabled = 0;
static void kexec_smp_down(void *arg)
{
local_irq_disable();
+ hard_irq_disable();
+
mb(); /* make sure our irqs are disabled before we say they are */
get_paca()->kexec_state = KEXEC_STATE_IRQS_OFF;
while(kexec_all_irq_disabled == 0)
@@ -244,6 +246,8 @@ static void kexec_prepare_cpus(void)
wake_offline_cpus();
smp_call_function(kexec_smp_down, NULL, /* wait */0);
local_irq_disable();
+ hard_irq_disable();
+
mb(); /* make sure IRQs are disabled before we say they are */
get_paca()->kexec_state = KEXEC_STATE_IRQS_OFF;
@@ -281,6 +285,7 @@ static void kexec_prepare_cpus(void)
if (ppc_md.kexec_cpu_down)
ppc_md.kexec_cpu_down(0, 0);
local_irq_disable();
+ hard_irq_disable();
}
#endif /* SMP */
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index 9f44a775a106..6ee59a0eb268 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -386,6 +386,14 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
| (value & 0xffff);
break;
+ case R_PPC64_TOC16_LO:
+ /* Subtract TOC pointer */
+ value -= my_r2(sechdrs, me);
+ *((uint16_t *) location)
+ = (*((uint16_t *) location) & ~0xffff)
+ | (value & 0xffff);
+ break;
+
case R_PPC64_TOC16_DS:
/* Subtract TOC pointer */
value -= my_r2(sechdrs, me);
@@ -399,6 +407,28 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
| (value & 0xfffc);
break;
+ case R_PPC64_TOC16_LO_DS:
+ /* Subtract TOC pointer */
+ value -= my_r2(sechdrs, me);
+ if ((value & 3) != 0) {
+ printk("%s: bad TOC16_LO_DS relocation (%lu)\n",
+ me->name, value);
+ return -ENOEXEC;
+ }
+ *((uint16_t *) location)
+ = (*((uint16_t *) location) & ~0xfffc)
+ | (value & 0xfffc);
+ break;
+
+ case R_PPC64_TOC16_HA:
+ /* Subtract TOC pointer */
+ value -= my_r2(sechdrs, me);
+ value = ((value + 0x8000) >> 16);
+ *((uint16_t *) location)
+ = (*((uint16_t *) location) & ~0xffff)
+ | (value & 0xffff);
+ break;
+
case R_PPC_REL24:
/* FIXME: Handle weak symbols here --RR */
if (sym->st_shndx == SHN_UNDEF) {
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index 07c12697d708..a7b743076720 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -71,10 +71,8 @@ static int of_pci_phb_probe(struct platform_device *dev)
eeh_dev_phb_init_dynamic(phb);
/* Register devices with EEH */
-#ifdef CONFIG_EEH
if (dev->dev.of_node->child)
eeh_add_device_tree_early(dev->dev.of_node);
-#endif /* CONFIG_EEH */
/* Scan the bus */
pcibios_scan_phb(phb);
@@ -88,13 +86,14 @@ static int of_pci_phb_probe(struct platform_device *dev)
pcibios_claim_one_bus(phb->bus);
/* Finish EEH setup */
-#ifdef CONFIG_EEH
eeh_add_device_tree_late(phb->bus);
-#endif
/* Add probed PCI devices to the device model */
pci_bus_add_devices(phb->bus);
+ /* sysfs files should only be added after devices are added */
+ eeh_add_sysfs_files(phb->bus);
+
return 0;
}
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index cd6da855090c..f8f24685f10a 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -120,8 +120,6 @@ struct slb_shadow slb_shadow[] __cacheline_aligned = {
struct paca_struct *paca;
EXPORT_SYMBOL(paca);
-struct paca_struct boot_paca;
-
void __init initialise_paca(struct paca_struct *new_paca, int cpu)
{
/* The TOC register (GPR2) points 32kB into the TOC, so that 64kB
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 7c37379ea9b1..fa12ae42d98c 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1477,11 +1477,14 @@ void pcibios_finish_adding_to_bus(struct pci_bus *bus)
pcibios_allocate_bus_resources(bus);
pcibios_claim_one_bus(bus);
+ /* Fixup EEH */
+ eeh_add_device_tree_late(bus);
+
/* Add new devices to global lists. Register in proc, sysfs. */
pci_bus_add_devices(bus);
- /* Fixup EEH */
- eeh_add_device_tree_late(bus);
+ /* sysfs files should only be added after devices are added */
+ eeh_add_sysfs_files(bus);
}
EXPORT_SYMBOL_GPL(pcibios_finish_adding_to_bus);
diff --git a/arch/powerpc/kernel/ppc32.h b/arch/powerpc/kernel/ppc32.h
index 02fb0ee26093..a27c914d5802 100644
--- a/arch/powerpc/kernel/ppc32.h
+++ b/arch/powerpc/kernel/ppc32.h
@@ -16,30 +16,6 @@
/* These are here to support 32-bit syscalls on a 64-bit kernel. */
-#define __old_sigaction32 old_sigaction32
-
-struct __old_sigaction32 {
- compat_uptr_t sa_handler;
- compat_old_sigset_t sa_mask;
- unsigned int sa_flags;
- compat_uptr_t sa_restorer; /* not used by Linux/SPARC yet */
-};
-
-
-
-struct sigaction32 {
- compat_uptr_t sa_handler; /* Really a pointer, but need to deal with 32 bits */
- unsigned int sa_flags;
- compat_uptr_t sa_restorer; /* Another 32 bit pointer */
- compat_sigset_t sa_mask; /* A 32 bit mask */
-};
-
-typedef struct sigaltstack_32 {
- unsigned int ss_sp;
- int ss_flags;
- compat_size_t ss_size;
-} stack_32_t;
-
struct pt_regs32 {
unsigned int gpr[32];
unsigned int nip;
@@ -75,7 +51,7 @@ struct mcontext32 {
struct ucontext32 {
unsigned int uc_flags;
unsigned int uc_link;
- stack_32_t uc_stack;
+ compat_stack_t uc_stack;
int uc_pad[7];
compat_uptr_t uc_regs; /* points to uc_mcontext field */
compat_sigset_t uc_sigmask; /* mask last for extensibility */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 81430674e71c..59dd545fdde1 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -50,6 +50,7 @@
#include <asm/runlatch.h>
#include <asm/syscalls.h>
#include <asm/switch_to.h>
+#include <asm/tm.h>
#include <asm/debug.h>
#ifdef CONFIG_PPC64
#include <asm/firmware.h>
@@ -57,6 +58,13 @@
#include <linux/kprobes.h>
#include <linux/kdebug.h>
+/* Transactional Memory debug */
+#ifdef TM_DEBUG_SW
+#define TM_DEBUG(x...) printk(KERN_INFO x)
+#else
+#define TM_DEBUG(x...) do { } while(0)
+#endif
+
extern unsigned long _get_SP(void);
#ifndef CONFIG_SMP
@@ -271,7 +279,7 @@ void do_send_trap(struct pt_regs *regs, unsigned long address,
force_sig_info(SIGTRAP, &info, current);
}
#else /* !CONFIG_PPC_ADV_DEBUG_REGS */
-void do_dabr(struct pt_regs *regs, unsigned long address,
+void do_break (struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
siginfo_t info;
@@ -281,11 +289,11 @@ void do_dabr(struct pt_regs *regs, unsigned long address,
11, SIGSEGV) == NOTIFY_STOP)
return;
- if (debugger_dabr_match(regs))
+ if (debugger_break_match(regs))
return;
- /* Clear the DABR */
- set_dabr(0, 0);
+ /* Clear the breakpoint */
+ hw_breakpoint_disable();
/* Deliver the signal to userspace */
info.si_signo = SIGTRAP;
@@ -296,7 +304,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address,
}
#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
-static DEFINE_PER_CPU(unsigned long, current_dabr);
+static DEFINE_PER_CPU(struct arch_hw_breakpoint, current_brk);
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
/*
@@ -364,39 +372,214 @@ static void switch_booke_debug_regs(struct thread_struct *new_thread)
#ifndef CONFIG_HAVE_HW_BREAKPOINT
static void set_debug_reg_defaults(struct thread_struct *thread)
{
- if (thread->dabr) {
- thread->dabr = 0;
- thread->dabrx = 0;
- set_dabr(0, 0);
- }
+ thread->hw_brk.address = 0;
+ thread->hw_brk.type = 0;
+ set_breakpoint(&thread->hw_brk);
}
#endif /* !CONFIG_HAVE_HW_BREAKPOINT */
#endif /* CONFIG_PPC_ADV_DEBUG_REGS */
-int set_dabr(unsigned long dabr, unsigned long dabrx)
-{
- __get_cpu_var(current_dabr) = dabr;
-
- if (ppc_md.set_dabr)
- return ppc_md.set_dabr(dabr, dabrx);
-
- /* XXX should we have a CPU_FTR_HAS_DABR ? */
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
+{
mtspr(SPRN_DAC1, dabr);
#ifdef CONFIG_PPC_47x
isync();
#endif
+ return 0;
+}
#elif defined(CONFIG_PPC_BOOK3S)
+static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
+{
mtspr(SPRN_DABR, dabr);
mtspr(SPRN_DABRX, dabrx);
+ return 0;
+}
+#else
+static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
+{
+ return -EINVAL;
+}
#endif
+
+static inline int set_dabr(struct arch_hw_breakpoint *brk)
+{
+ unsigned long dabr, dabrx;
+
+ dabr = brk->address | (brk->type & HW_BRK_TYPE_DABR);
+ dabrx = ((brk->type >> 3) & 0x7);
+
+ if (ppc_md.set_dabr)
+ return ppc_md.set_dabr(dabr, dabrx);
+
+ return __set_dabr(dabr, dabrx);
+}
+
+static inline int set_dawr(struct arch_hw_breakpoint *brk)
+{
+ unsigned long dawr, dawrx, mrd;
+
+ dawr = brk->address;
+
+ dawrx = (brk->type & (HW_BRK_TYPE_READ | HW_BRK_TYPE_WRITE)) \
+ << (63 - 58); //* read/write bits */
+ dawrx |= ((brk->type & (HW_BRK_TYPE_TRANSLATE)) >> 2) \
+ << (63 - 59); //* translate */
+ dawrx |= (brk->type & (HW_BRK_TYPE_PRIV_ALL)) \
+ >> 3; //* PRIM bits */
+ /* dawr length is stored in field MDR bits 48:53. Matches range in
+ doublewords (64 bits) baised by -1 eg. 0b000000=1DW and
+ 0b111111=64DW.
+ brk->len is in bytes.
+ This aligns up to double word size, shifts and does the bias.
+ */
+ mrd = ((brk->len + 7) >> 3) - 1;
+ dawrx |= (mrd & 0x3f) << (63 - 53);
+
+ if (ppc_md.set_dawr)
+ return ppc_md.set_dawr(dawr, dawrx);
+ mtspr(SPRN_DAWR, dawr);
+ mtspr(SPRN_DAWRX, dawrx);
return 0;
}
+int set_breakpoint(struct arch_hw_breakpoint *brk)
+{
+ __get_cpu_var(current_brk) = *brk;
+
+ if (cpu_has_feature(CPU_FTR_DAWR))
+ return set_dawr(brk);
+
+ return set_dabr(brk);
+}
+
#ifdef CONFIG_PPC64
DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array);
#endif
+static inline bool hw_brk_match(struct arch_hw_breakpoint *a,
+ struct arch_hw_breakpoint *b)
+{
+ if (a->address != b->address)
+ return false;
+ if (a->type != b->type)
+ return false;
+ if (a->len != b->len)
+ return false;
+ return true;
+}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static inline void tm_reclaim_task(struct task_struct *tsk)
+{
+ /* We have to work out if we're switching from/to a task that's in the
+ * middle of a transaction.
+ *
+ * In switching we need to maintain a 2nd register state as
+ * oldtask->thread.ckpt_regs. We tm_reclaim(oldproc); this saves the
+ * checkpointed (tbegin) state in ckpt_regs and saves the transactional
+ * (current) FPRs into oldtask->thread.transact_fpr[].
+ *
+ * We also context switch (save) TFHAR/TEXASR/TFIAR in here.
+ */
+ struct thread_struct *thr = &tsk->thread;
+
+ if (!thr->regs)
+ return;
+
+ if (!MSR_TM_ACTIVE(thr->regs->msr))
+ goto out_and_saveregs;
+
+ /* Stash the original thread MSR, as giveup_fpu et al will
+ * modify it. We hold onto it to see whether the task used
+ * FP & vector regs.
+ */
+ thr->tm_orig_msr = thr->regs->msr;
+
+ TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, "
+ "ccr=%lx, msr=%lx, trap=%lx)\n",
+ tsk->pid, thr->regs->nip,
+ thr->regs->ccr, thr->regs->msr,
+ thr->regs->trap);
+
+ tm_reclaim(thr, thr->regs->msr, TM_CAUSE_RESCHED);
+
+ TM_DEBUG("--- tm_reclaim on pid %d complete\n",
+ tsk->pid);
+
+out_and_saveregs:
+ /* Always save the regs here, even if a transaction's not active.
+ * This context-switches a thread's TM info SPRs. We do it here to
+ * be consistent with the restore path (in recheckpoint) which
+ * cannot happen later in _switch().
+ */
+ tm_save_sprs(thr);
+}
+
+static inline void tm_recheckpoint_new_task(struct task_struct *new)
+{
+ unsigned long msr;
+
+ if (!cpu_has_feature(CPU_FTR_TM))
+ return;
+
+ /* Recheckpoint the registers of the thread we're about to switch to.
+ *
+ * If the task was using FP, we non-lazily reload both the original and
+ * the speculative FP register states. This is because the kernel
+ * doesn't see if/when a TM rollback occurs, so if we take an FP
+ * unavoidable later, we are unable to determine which set of FP regs
+ * need to be restored.
+ */
+ if (!new->thread.regs)
+ return;
+
+ /* The TM SPRs are restored here, so that TEXASR.FS can be set
+ * before the trecheckpoint and no explosion occurs.
+ */
+ tm_restore_sprs(&new->thread);
+
+ if (!MSR_TM_ACTIVE(new->thread.regs->msr))
+ return;
+ msr = new->thread.tm_orig_msr;
+ /* Recheckpoint to restore original checkpointed register state. */
+ TM_DEBUG("*** tm_recheckpoint of pid %d "
+ "(new->msr 0x%lx, new->origmsr 0x%lx)\n",
+ new->pid, new->thread.regs->msr, msr);
+
+ /* This loads the checkpointed FP/VEC state, if used */
+ tm_recheckpoint(&new->thread, msr);
+
+ /* This loads the speculative FP/VEC state, if used */
+ if (msr & MSR_FP) {
+ do_load_up_transact_fpu(&new->thread);
+ new->thread.regs->msr |=
+ (MSR_FP | new->thread.fpexc_mode);
+ }
+ if (msr & MSR_VEC) {
+ do_load_up_transact_altivec(&new->thread);
+ new->thread.regs->msr |= MSR_VEC;
+ }
+ /* We may as well turn on VSX too since all the state is restored now */
+ if (msr & MSR_VSX)
+ new->thread.regs->msr |= MSR_VSX;
+
+ TM_DEBUG("*** tm_recheckpoint of pid %d complete "
+ "(kernel msr 0x%lx)\n",
+ new->pid, mfmsr());
+}
+
+static inline void __switch_to_tm(struct task_struct *prev)
+{
+ if (cpu_has_feature(CPU_FTR_TM)) {
+ tm_enable();
+ tm_reclaim_task(prev);
+ }
+}
+#else
+#define tm_recheckpoint_new_task(new)
+#define __switch_to_tm(prev)
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
struct task_struct *__switch_to(struct task_struct *prev,
struct task_struct *new)
{
@@ -407,6 +590,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
struct ppc64_tlb_batch *batch;
#endif
+ __switch_to_tm(prev);
+
#ifdef CONFIG_SMP
/* avoid complexity of lazy save/restore of fpu
* by just saving it every time we switch out if
@@ -481,8 +666,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
* schedule DABR
*/
#ifndef CONFIG_HAVE_HW_BREAKPOINT
- if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
- set_dabr(new->thread.dabr, new->thread.dabrx);
+ if (unlikely(hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk)))
+ set_breakpoint(&new->thread.hw_brk);
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#endif
@@ -522,6 +707,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
* of sync. Hard disable here.
*/
hard_irq_disable();
+
+ tm_recheckpoint_new_task(new);
+
last = _switch(old_thread, new_thread);
#ifdef CONFIG_PPC_BOOK3S_64
@@ -683,6 +871,9 @@ void show_regs(struct pt_regs * regs)
printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip);
printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link);
#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ printk("PACATMSCRATCH [%llx]\n", get_paca()->tm_scratch);
+#endif
show_stack(current, (unsigned long *) regs->gpr[1]);
if (!user_mode(regs))
show_instructions(regs);
@@ -813,6 +1004,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
p->thread.dscr_inherit = current->thread.dscr_inherit;
p->thread.dscr = current->thread.dscr;
}
+ if (cpu_has_feature(CPU_FTR_HAS_PPR))
+ p->thread.ppr = INIT_PPR;
#endif
/*
* The PPC64 ABI makes use of a TOC to contain function
@@ -892,7 +1085,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
regs->msr = MSR_USER32;
}
#endif
-
discard_lazy_cpu_state();
#ifdef CONFIG_VSX
current->thread.used_vsr = 0;
@@ -912,6 +1104,13 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
current->thread.spefscr = 0;
current->thread.used_spe = 0;
#endif /* CONFIG_SPE */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (cpu_has_feature(CPU_FTR_TM))
+ regs->msr |= MSR_TM;
+ current->thread.tm_tfhar = 0;
+ current->thread.tm_texasr = 0;
+ current->thread.tm_tfiar = 0;
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
}
#define PR_FP_ALL_EXCEPT (PR_FP_EXC_DIV | PR_FP_EXC_OVF | PR_FP_EXC_UND \
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 779f34049a56..7f7fb7fd991b 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -66,8 +66,8 @@
* is running at whatever address it has been loaded at.
* On ppc32 we compile with -mrelocatable, which means that references
* to extern and static variables get relocated automatically.
- * On ppc64 we have to relocate the references explicitly with
- * RELOC. (Note that strings count as static variables.)
+ * ppc64 objects are always relocatable, we just need to relocate the
+ * TOC.
*
* Because OF may have mapped I/O devices into the area starting at
* KERNELBASE, particularly on CHRP machines, we can't safely call
@@ -79,13 +79,11 @@
* On ppc64, 64 bit values are truncated to 32 bits (and
* fortunately don't get interpreted as two arguments).
*/
+#define ADDR(x) (u32)(unsigned long)(x)
+
#ifdef CONFIG_PPC64
-#define RELOC(x) (*PTRRELOC(&(x)))
-#define ADDR(x) (u32) add_reloc_offset((unsigned long)(x))
#define OF_WORKAROUNDS 0
#else
-#define RELOC(x) (x)
-#define ADDR(x) (u32) (x)
#define OF_WORKAROUNDS of_workarounds
int of_workarounds;
#endif
@@ -95,7 +93,7 @@ int of_workarounds;
#define PROM_BUG() do { \
prom_printf("kernel BUG at %s line 0x%x!\n", \
- RELOC(__FILE__), __LINE__); \
+ __FILE__, __LINE__); \
__asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \
} while (0)
@@ -233,7 +231,7 @@ static int __init call_prom(const char *service, int nargs, int nret, ...)
for (i = 0; i < nret; i++)
args.args[nargs+i] = 0;
- if (enter_prom(&args, RELOC(prom_entry)) < 0)
+ if (enter_prom(&args, prom_entry) < 0)
return PROM_ERROR;
return (nret > 0) ? args.args[nargs] : 0;
@@ -258,7 +256,7 @@ static int __init call_prom_ret(const char *service, int nargs, int nret,
for (i = 0; i < nret; i++)
args.args[nargs+i] = 0;
- if (enter_prom(&args, RELOC(prom_entry)) < 0)
+ if (enter_prom(&args, prom_entry) < 0)
return PROM_ERROR;
if (rets != NULL)
@@ -272,20 +270,19 @@ static int __init call_prom_ret(const char *service, int nargs, int nret,
static void __init prom_print(const char *msg)
{
const char *p, *q;
- struct prom_t *_prom = &RELOC(prom);
- if (_prom->stdout == 0)
+ if (prom.stdout == 0)
return;
for (p = msg; *p != 0; p = q) {
for (q = p; *q != 0 && *q != '\n'; ++q)
;
if (q > p)
- call_prom("write", 3, 1, _prom->stdout, p, q - p);
+ call_prom("write", 3, 1, prom.stdout, p, q - p);
if (*q == 0)
break;
++q;
- call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2);
+ call_prom("write", 3, 1, prom.stdout, ADDR("\r\n"), 2);
}
}
@@ -294,7 +291,6 @@ static void __init prom_print_hex(unsigned long val)
{
int i, nibbles = sizeof(val)*2;
char buf[sizeof(val)*2+1];
- struct prom_t *_prom = &RELOC(prom);
for (i = nibbles-1; i >= 0; i--) {
buf[i] = (val & 0xf) + '0';
@@ -303,7 +299,7 @@ static void __init prom_print_hex(unsigned long val)
val >>= 4;
}
buf[nibbles] = '\0';
- call_prom("write", 3, 1, _prom->stdout, buf, nibbles);
+ call_prom("write", 3, 1, prom.stdout, buf, nibbles);
}
/* max number of decimal digits in an unsigned long */
@@ -312,7 +308,6 @@ static void __init prom_print_dec(unsigned long val)
{
int i, size;
char buf[UL_DIGITS+1];
- struct prom_t *_prom = &RELOC(prom);
for (i = UL_DIGITS-1; i >= 0; i--) {
buf[i] = (val % 10) + '0';
@@ -322,7 +317,7 @@ static void __init prom_print_dec(unsigned long val)
}
/* shift stuff down */
size = UL_DIGITS - i;
- call_prom("write", 3, 1, _prom->stdout, buf+i, size);
+ call_prom("write", 3, 1, prom.stdout, buf+i, size);
}
static void __init prom_printf(const char *format, ...)
@@ -331,22 +326,18 @@ static void __init prom_printf(const char *format, ...)
va_list args;
unsigned long v;
long vs;
- struct prom_t *_prom = &RELOC(prom);
va_start(args, format);
-#ifdef CONFIG_PPC64
- format = PTRRELOC(format);
-#endif
for (p = format; *p != 0; p = q) {
for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q)
;
if (q > p)
- call_prom("write", 3, 1, _prom->stdout, p, q - p);
+ call_prom("write", 3, 1, prom.stdout, p, q - p);
if (*q == 0)
break;
if (*q == '\n') {
++q;
- call_prom("write", 3, 1, _prom->stdout,
+ call_prom("write", 3, 1, prom.stdout,
ADDR("\r\n"), 2);
continue;
}
@@ -368,7 +359,7 @@ static void __init prom_printf(const char *format, ...)
++q;
vs = va_arg(args, int);
if (vs < 0) {
- prom_print(RELOC("-"));
+ prom_print("-");
vs = -vs;
}
prom_print_dec(vs);
@@ -389,7 +380,7 @@ static void __init prom_printf(const char *format, ...)
++q;
vs = va_arg(args, long);
if (vs < 0) {
- prom_print(RELOC("-"));
+ prom_print("-");
vs = -vs;
}
prom_print_dec(vs);
@@ -403,7 +394,6 @@ static void __init prom_printf(const char *format, ...)
static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
unsigned long align)
{
- struct prom_t *_prom = &RELOC(prom);
if (align == 0 && (OF_WORKAROUNDS & OF_WA_CLAIM)) {
/*
@@ -414,21 +404,21 @@ static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
prom_arg_t result;
ret = call_prom_ret("call-method", 5, 2, &result,
- ADDR("claim"), _prom->memory,
+ ADDR("claim"), prom.memory,
align, size, virt);
if (ret != 0 || result == -1)
return -1;
ret = call_prom_ret("call-method", 5, 2, &result,
- ADDR("claim"), _prom->mmumap,
+ ADDR("claim"), prom.mmumap,
align, size, virt);
if (ret != 0) {
call_prom("call-method", 4, 1, ADDR("release"),
- _prom->memory, size, virt);
+ prom.memory, size, virt);
return -1;
}
/* the 0x12 is M (coherence) + PP == read/write */
call_prom("call-method", 6, 1,
- ADDR("map"), _prom->mmumap, 0x12, size, virt, virt);
+ ADDR("map"), prom.mmumap, 0x12, size, virt, virt);
return virt;
}
return call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size,
@@ -437,13 +427,10 @@ static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
static void __init __attribute__((noreturn)) prom_panic(const char *reason)
{
-#ifdef CONFIG_PPC64
- reason = PTRRELOC(reason);
-#endif
prom_print(reason);
/* Do not call exit because it clears the screen on pmac
* it also causes some sort of double-fault on early pmacs */
- if (RELOC(of_platform) == PLATFORM_POWERMAC)
+ if (of_platform == PLATFORM_POWERMAC)
asm("trap\n");
/* ToDo: should put up an SRC here on pSeries */
@@ -525,13 +512,13 @@ static int __init prom_setprop(phandle node, const char *nodename,
add_string(&p, tohex((u32)(unsigned long) value));
add_string(&p, tohex(valuelen));
add_string(&p, tohex(ADDR(pname)));
- add_string(&p, tohex(strlen(RELOC(pname))));
+ add_string(&p, tohex(strlen(pname)));
add_string(&p, "property");
*p = 0;
return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);
}
-/* We can't use the standard versions because of RELOC headaches. */
+/* We can't use the standard versions because of relocation headaches. */
#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
|| ('a' <= (c) && (c) <= 'f') \
|| ('A' <= (c) && (c) <= 'F'))
@@ -598,43 +585,42 @@ unsigned long prom_memparse(const char *ptr, const char **retptr)
*/
static void __init early_cmdline_parse(void)
{
- struct prom_t *_prom = &RELOC(prom);
const char *opt;
char *p;
int l = 0;
- RELOC(prom_cmd_line[0]) = 0;
- p = RELOC(prom_cmd_line);
- if ((long)_prom->chosen > 0)
- l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
+ prom_cmd_line[0] = 0;
+ p = prom_cmd_line;
+ if ((long)prom.chosen > 0)
+ l = prom_getprop(prom.chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
#ifdef CONFIG_CMDLINE
if (l <= 0 || p[0] == '\0') /* dbl check */
- strlcpy(RELOC(prom_cmd_line),
- RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line));
+ strlcpy(prom_cmd_line,
+ CONFIG_CMDLINE, sizeof(prom_cmd_line));
#endif /* CONFIG_CMDLINE */
- prom_printf("command line: %s\n", RELOC(prom_cmd_line));
+ prom_printf("command line: %s\n", prom_cmd_line);
#ifdef CONFIG_PPC64
- opt = strstr(RELOC(prom_cmd_line), RELOC("iommu="));
+ opt = strstr(prom_cmd_line, "iommu=");
if (opt) {
prom_printf("iommu opt is: %s\n", opt);
opt += 6;
while (*opt && *opt == ' ')
opt++;
- if (!strncmp(opt, RELOC("off"), 3))
- RELOC(prom_iommu_off) = 1;
- else if (!strncmp(opt, RELOC("force"), 5))
- RELOC(prom_iommu_force_on) = 1;
+ if (!strncmp(opt, "off", 3))
+ prom_iommu_off = 1;
+ else if (!strncmp(opt, "force", 5))
+ prom_iommu_force_on = 1;
}
#endif
- opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
+ opt = strstr(prom_cmd_line, "mem=");
if (opt) {
opt += 4;
- RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt);
+ prom_memory_limit = prom_memparse(opt, (const char **)&opt);
#ifdef CONFIG_PPC64
/* Align to 16 MB == size of ppc64 large page */
- RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
+ prom_memory_limit = ALIGN(prom_memory_limit, 0x1000000);
#endif
}
}
@@ -887,7 +873,7 @@ static int __init prom_count_smt_threads(void)
type[0] = 0;
prom_getprop(node, "device_type", type, sizeof(type));
- if (strcmp(type, RELOC("cpu")))
+ if (strcmp(type, "cpu"))
continue;
/*
* There is an entry for each smt thread, each entry being
@@ -929,7 +915,7 @@ static void __init prom_send_capabilities(void)
* (we assume this is the same for all cores) and use it to
* divide NR_CPUS.
*/
- cores = (u32 *)PTRRELOC(&ibm_architecture_vec[IBM_ARCH_VEC_NRCORES_OFFSET]);
+ cores = (u32 *)&ibm_architecture_vec[IBM_ARCH_VEC_NRCORES_OFFSET];
if (*cores != NR_CPUS) {
prom_printf("WARNING ! "
"ibm_architecture_vec structure inconsistent: %lu!\n",
@@ -1005,21 +991,21 @@ static void __init prom_send_capabilities(void)
*/
static unsigned long __init alloc_up(unsigned long size, unsigned long align)
{
- unsigned long base = RELOC(alloc_bottom);
+ unsigned long base = alloc_bottom;
unsigned long addr = 0;
if (align)
base = _ALIGN_UP(base, align);
prom_debug("alloc_up(%x, %x)\n", size, align);
- if (RELOC(ram_top) == 0)
+ if (ram_top == 0)
prom_panic("alloc_up() called with mem not initialized\n");
if (align)
- base = _ALIGN_UP(RELOC(alloc_bottom), align);
+ base = _ALIGN_UP(alloc_bottom, align);
else
- base = RELOC(alloc_bottom);
+ base = alloc_bottom;
- for(; (base + size) <= RELOC(alloc_top);
+ for(; (base + size) <= alloc_top;
base = _ALIGN_UP(base + 0x100000, align)) {
prom_debug(" trying: 0x%x\n\r", base);
addr = (unsigned long)prom_claim(base, size, 0);
@@ -1031,14 +1017,14 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align)
}
if (addr == 0)
return 0;
- RELOC(alloc_bottom) = addr + size;
+ alloc_bottom = addr + size;
prom_debug(" -> %x\n", addr);
- prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom));
- prom_debug(" alloc_top : %x\n", RELOC(alloc_top));
- prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
- prom_debug(" rmo_top : %x\n", RELOC(rmo_top));
- prom_debug(" ram_top : %x\n", RELOC(ram_top));
+ prom_debug(" alloc_bottom : %x\n", alloc_bottom);
+ prom_debug(" alloc_top : %x\n", alloc_top);
+ prom_debug(" alloc_top_hi : %x\n", alloc_top_high);
+ prom_debug(" rmo_top : %x\n", rmo_top);
+ prom_debug(" ram_top : %x\n", ram_top);
return addr;
}
@@ -1054,32 +1040,32 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align,
unsigned long base, addr = 0;
prom_debug("alloc_down(%x, %x, %s)\n", size, align,
- highmem ? RELOC("(high)") : RELOC("(low)"));
- if (RELOC(ram_top) == 0)
+ highmem ? "(high)" : "(low)");
+ if (ram_top == 0)
prom_panic("alloc_down() called with mem not initialized\n");
if (highmem) {
/* Carve out storage for the TCE table. */
- addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align);
- if (addr <= RELOC(alloc_bottom))
+ addr = _ALIGN_DOWN(alloc_top_high - size, align);
+ if (addr <= alloc_bottom)
return 0;
/* Will we bump into the RMO ? If yes, check out that we
* didn't overlap existing allocations there, if we did,
* we are dead, we must be the first in town !
*/
- if (addr < RELOC(rmo_top)) {
+ if (addr < rmo_top) {
/* Good, we are first */
- if (RELOC(alloc_top) == RELOC(rmo_top))
- RELOC(alloc_top) = RELOC(rmo_top) = addr;
+ if (alloc_top == rmo_top)
+ alloc_top = rmo_top = addr;
else
return 0;
}
- RELOC(alloc_top_high) = addr;
+ alloc_top_high = addr;
goto bail;
}
- base = _ALIGN_DOWN(RELOC(alloc_top) - size, align);
- for (; base > RELOC(alloc_bottom);
+ base = _ALIGN_DOWN(alloc_top - size, align);
+ for (; base > alloc_bottom;
base = _ALIGN_DOWN(base - 0x100000, align)) {
prom_debug(" trying: 0x%x\n\r", base);
addr = (unsigned long)prom_claim(base, size, 0);
@@ -1089,15 +1075,15 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align,
}
if (addr == 0)
return 0;
- RELOC(alloc_top) = addr;
+ alloc_top = addr;
bail:
prom_debug(" -> %x\n", addr);
- prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom));
- prom_debug(" alloc_top : %x\n", RELOC(alloc_top));
- prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
- prom_debug(" rmo_top : %x\n", RELOC(rmo_top));
- prom_debug(" ram_top : %x\n", RELOC(ram_top));
+ prom_debug(" alloc_bottom : %x\n", alloc_bottom);
+ prom_debug(" alloc_top : %x\n", alloc_top);
+ prom_debug(" alloc_top_hi : %x\n", alloc_top_high);
+ prom_debug(" rmo_top : %x\n", rmo_top);
+ prom_debug(" ram_top : %x\n", ram_top);
return addr;
}
@@ -1137,7 +1123,7 @@ static unsigned long __init prom_next_cell(int s, cell_t **cellp)
static void __init reserve_mem(u64 base, u64 size)
{
u64 top = base + size;
- unsigned long cnt = RELOC(mem_reserve_cnt);
+ unsigned long cnt = mem_reserve_cnt;
if (size == 0)
return;
@@ -1152,9 +1138,9 @@ static void __init reserve_mem(u64 base, u64 size)
if (cnt >= (MEM_RESERVE_MAP_SIZE - 1))
prom_panic("Memory reserve map exhausted !\n");
- RELOC(mem_reserve_map)[cnt].base = base;
- RELOC(mem_reserve_map)[cnt].size = size;
- RELOC(mem_reserve_cnt) = cnt + 1;
+ mem_reserve_map[cnt].base = base;
+ mem_reserve_map[cnt].size = size;
+ mem_reserve_cnt = cnt + 1;
}
/*
@@ -1167,7 +1153,6 @@ static void __init prom_init_mem(void)
char *path, type[64];
unsigned int plen;
cell_t *p, *endp;
- struct prom_t *_prom = &RELOC(prom);
u32 rac, rsc;
/*
@@ -1176,14 +1161,14 @@ static void __init prom_init_mem(void)
* 2) top of memory
*/
rac = 2;
- prom_getprop(_prom->root, "#address-cells", &rac, sizeof(rac));
+ prom_getprop(prom.root, "#address-cells", &rac, sizeof(rac));
rsc = 1;
- prom_getprop(_prom->root, "#size-cells", &rsc, sizeof(rsc));
+ prom_getprop(prom.root, "#size-cells", &rsc, sizeof(rsc));
prom_debug("root_addr_cells: %x\n", (unsigned long) rac);
prom_debug("root_size_cells: %x\n", (unsigned long) rsc);
prom_debug("scanning memory:\n");
- path = RELOC(prom_scratch);
+ path = prom_scratch;
for (node = 0; prom_next_node(&node); ) {
type[0] = 0;
@@ -1196,15 +1181,15 @@ static void __init prom_init_mem(void)
*/
prom_getprop(node, "name", type, sizeof(type));
}
- if (strcmp(type, RELOC("memory")))
+ if (strcmp(type, "memory"))
continue;
- plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf));
+ plen = prom_getprop(node, "reg", regbuf, sizeof(regbuf));
if (plen > sizeof(regbuf)) {
prom_printf("memory node too large for buffer !\n");
plen = sizeof(regbuf);
}
- p = RELOC(regbuf);
+ p = regbuf;
endp = p + (plen / sizeof(cell_t));
#ifdef DEBUG_PROM
@@ -1222,14 +1207,14 @@ static void __init prom_init_mem(void)
if (size == 0)
continue;
prom_debug(" %x %x\n", base, size);
- if (base == 0 && (RELOC(of_platform) & PLATFORM_LPAR))
- RELOC(rmo_top) = size;
- if ((base + size) > RELOC(ram_top))
- RELOC(ram_top) = base + size;
+ if (base == 0 && (of_platform & PLATFORM_LPAR))
+ rmo_top = size;
+ if ((base + size) > ram_top)
+ ram_top = base + size;
}
}
- RELOC(alloc_bottom) = PAGE_ALIGN((unsigned long)&RELOC(_end) + 0x4000);
+ alloc_bottom = PAGE_ALIGN((unsigned long)&_end + 0x4000);
/*
* If prom_memory_limit is set we reduce the upper limits *except* for
@@ -1237,20 +1222,20 @@ static void __init prom_init_mem(void)
* TCE's up there.
*/
- RELOC(alloc_top_high) = RELOC(ram_top);
+ alloc_top_high = ram_top;
- if (RELOC(prom_memory_limit)) {
- if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) {
+ if (prom_memory_limit) {
+ if (prom_memory_limit <= alloc_bottom) {
prom_printf("Ignoring mem=%x <= alloc_bottom.\n",
- RELOC(prom_memory_limit));
- RELOC(prom_memory_limit) = 0;
- } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) {
+ prom_memory_limit);
+ prom_memory_limit = 0;
+ } else if (prom_memory_limit >= ram_top) {
prom_printf("Ignoring mem=%x >= ram_top.\n",
- RELOC(prom_memory_limit));
- RELOC(prom_memory_limit) = 0;
+ prom_memory_limit);
+ prom_memory_limit = 0;
} else {
- RELOC(ram_top) = RELOC(prom_memory_limit);
- RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit));
+ ram_top = prom_memory_limit;
+ rmo_top = min(rmo_top, prom_memory_limit);
}
}
@@ -1262,36 +1247,35 @@ static void __init prom_init_mem(void)
* Since 768MB is plenty of room, and we need to cap to something
* reasonable on 32-bit, cap at 768MB on all machines.
*/
- if (!RELOC(rmo_top))
- RELOC(rmo_top) = RELOC(ram_top);
- RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top));
- RELOC(alloc_top) = RELOC(rmo_top);
- RELOC(alloc_top_high) = RELOC(ram_top);
+ if (!rmo_top)
+ rmo_top = ram_top;
+ rmo_top = min(0x30000000ul, rmo_top);
+ alloc_top = rmo_top;
+ alloc_top_high = ram_top;
/*
* Check if we have an initrd after the kernel but still inside
* the RMO. If we do move our bottom point to after it.
*/
- if (RELOC(prom_initrd_start) &&
- RELOC(prom_initrd_start) < RELOC(rmo_top) &&
- RELOC(prom_initrd_end) > RELOC(alloc_bottom))
- RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end));
+ if (prom_initrd_start &&
+ prom_initrd_start < rmo_top &&
+ prom_initrd_end > alloc_bottom)
+ alloc_bottom = PAGE_ALIGN(prom_initrd_end);
prom_printf("memory layout at init:\n");
- prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
- prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom));
- prom_printf(" alloc_top : %x\n", RELOC(alloc_top));
- prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
- prom_printf(" rmo_top : %x\n", RELOC(rmo_top));
- prom_printf(" ram_top : %x\n", RELOC(ram_top));
+ prom_printf(" memory_limit : %x (16 MB aligned)\n", prom_memory_limit);
+ prom_printf(" alloc_bottom : %x\n", alloc_bottom);
+ prom_printf(" alloc_top : %x\n", alloc_top);
+ prom_printf(" alloc_top_hi : %x\n", alloc_top_high);
+ prom_printf(" rmo_top : %x\n", rmo_top);
+ prom_printf(" ram_top : %x\n", ram_top);
}
static void __init prom_close_stdin(void)
{
- struct prom_t *_prom = &RELOC(prom);
ihandle val;
- if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0)
+ if (prom_getprop(prom.chosen, "stdin", &val, sizeof(val)) > 0)
call_prom("close", 1, 0, val);
}
@@ -1332,19 +1316,19 @@ static void __init prom_query_opal(void)
}
prom_printf("Querying for OPAL presence... ");
- rc = opal_query_takeover(&RELOC(prom_opal_size),
- &RELOC(prom_opal_align));
+ rc = opal_query_takeover(&prom_opal_size,
+ &prom_opal_align);
prom_debug("(rc = %ld) ", rc);
if (rc != 0) {
prom_printf("not there.\n");
return;
}
- RELOC(of_platform) = PLATFORM_OPAL;
+ of_platform = PLATFORM_OPAL;
prom_printf(" there !\n");
- prom_debug(" opal_size = 0x%lx\n", RELOC(prom_opal_size));
- prom_debug(" opal_align = 0x%lx\n", RELOC(prom_opal_align));
- if (RELOC(prom_opal_align) < 0x10000)
- RELOC(prom_opal_align) = 0x10000;
+ prom_debug(" opal_size = 0x%lx\n", prom_opal_size);
+ prom_debug(" opal_align = 0x%lx\n", prom_opal_align);
+ if (prom_opal_align < 0x10000)
+ prom_opal_align = 0x10000;
}
static int prom_rtas_call(int token, int nargs, int nret, int *outputs, ...)
@@ -1365,8 +1349,8 @@ static int prom_rtas_call(int token, int nargs, int nret, int *outputs, ...)
for (i = 0; i < nret; ++i)
rtas_args.rets[i] = 0;
- opal_enter_rtas(&rtas_args, RELOC(prom_rtas_data),
- RELOC(prom_rtas_entry));
+ opal_enter_rtas(&rtas_args, prom_rtas_data,
+ prom_rtas_entry);
if (nret > 1 && outputs != NULL)
for (i = 0; i < nret-1; ++i)
@@ -1381,9 +1365,8 @@ static void __init prom_opal_hold_cpus(void)
phandle node;
char type[64];
u32 servers[8];
- struct prom_t *_prom = &RELOC(prom);
- void *entry = (unsigned long *)&RELOC(opal_secondary_entry);
- struct opal_secondary_data *data = &RELOC(opal_secondary_data);
+ void *entry = (unsigned long *)&opal_secondary_entry;
+ struct opal_secondary_data *data = &opal_secondary_data;
prom_debug("prom_opal_hold_cpus: start...\n");
prom_debug(" - entry = 0x%x\n", entry);
@@ -1396,12 +1379,12 @@ static void __init prom_opal_hold_cpus(void)
for (node = 0; prom_next_node(&node); ) {
type[0] = 0;
prom_getprop(node, "device_type", type, sizeof(type));
- if (strcmp(type, RELOC("cpu")) != 0)
+ if (strcmp(type, "cpu") != 0)
continue;
/* Skip non-configured cpus. */
if (prom_getprop(node, "status", type, sizeof(type)) > 0)
- if (strcmp(type, RELOC("okay")) != 0)
+ if (strcmp(type, "okay") != 0)
continue;
cnt = prom_getprop(node, "ibm,ppc-interrupt-server#s", servers,
@@ -1412,7 +1395,7 @@ static void __init prom_opal_hold_cpus(void)
for (i = 0; i < cnt; i++) {
cpu = servers[i];
prom_debug("CPU %d ... ", cpu);
- if (cpu == _prom->cpu) {
+ if (cpu == prom.cpu) {
prom_debug("booted !\n");
continue;
}
@@ -1423,7 +1406,7 @@ static void __init prom_opal_hold_cpus(void)
* spinloop.
*/
data->ack = -1;
- rc = prom_rtas_call(RELOC(prom_rtas_start_cpu), 3, 1,
+ rc = prom_rtas_call(prom_rtas_start_cpu, 3, 1,
NULL, cpu, entry, data);
prom_debug("rtas rc=%d ...", rc);
@@ -1443,21 +1426,21 @@ static void __init prom_opal_hold_cpus(void)
static void __init prom_opal_takeover(void)
{
- struct opal_secondary_data *data = &RELOC(opal_secondary_data);
+ struct opal_secondary_data *data = &opal_secondary_data;
struct opal_takeover_args *args = &data->args;
- u64 align = RELOC(prom_opal_align);
+ u64 align = prom_opal_align;
u64 top_addr, opal_addr;
- args->k_image = (u64)RELOC(_stext);
+ args->k_image = (u64)_stext;
args->k_size = _end - _stext;
args->k_entry = 0;
args->k_entry2 = 0x60;
top_addr = _ALIGN_UP(args->k_size, align);
- if (RELOC(prom_initrd_start) != 0) {
- args->rd_image = RELOC(prom_initrd_start);
- args->rd_size = RELOC(prom_initrd_end) - args->rd_image;
+ if (prom_initrd_start != 0) {
+ args->rd_image = prom_initrd_start;
+ args->rd_size = prom_initrd_end - args->rd_image;
args->rd_loc = top_addr;
top_addr = _ALIGN_UP(args->rd_loc + args->rd_size, align);
}
@@ -1469,13 +1452,13 @@ static void __init prom_opal_takeover(void)
* has plenty of memory, and we ask for the HAL for now to
* be just below the 1G point, or above the initrd
*/
- opal_addr = _ALIGN_DOWN(0x40000000 - RELOC(prom_opal_size), align);
+ opal_addr = _ALIGN_DOWN(0x40000000 - prom_opal_size, align);
if (opal_addr < top_addr)
opal_addr = top_addr;
args->hal_addr = opal_addr;
/* Copy the command line to the kernel image */
- strlcpy(RELOC(boot_command_line), RELOC(prom_cmd_line),
+ strlcpy(boot_command_line, prom_cmd_line,
COMMAND_LINE_SIZE);
prom_debug(" k_image = 0x%lx\n", args->k_image);
@@ -1557,8 +1540,8 @@ static void __init prom_instantiate_opal(void)
&entry, sizeof(entry));
#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
- RELOC(prom_opal_base) = base;
- RELOC(prom_opal_entry) = entry;
+ prom_opal_base = base;
+ prom_opal_entry = entry;
#endif
prom_debug("prom_instantiate_opal: end...\n");
}
@@ -1616,9 +1599,9 @@ static void __init prom_instantiate_rtas(void)
#ifdef CONFIG_PPC_POWERNV
/* PowerVN takeover hack */
- RELOC(prom_rtas_data) = base;
- RELOC(prom_rtas_entry) = entry;
- prom_getprop(rtas_node, "start-cpu", &RELOC(prom_rtas_start_cpu), 4);
+ prom_rtas_data = base;
+ prom_rtas_entry = entry;
+ prom_getprop(rtas_node, "start-cpu", &prom_rtas_start_cpu, 4);
#endif
prom_debug("rtas base = 0x%x\n", base);
prom_debug("rtas entry = 0x%x\n", entry);
@@ -1693,20 +1676,20 @@ static void __init prom_initialize_tce_table(void)
phandle node;
ihandle phb_node;
char compatible[64], type[64], model[64];
- char *path = RELOC(prom_scratch);
+ char *path = prom_scratch;
u64 base, align;
u32 minalign, minsize;
u64 tce_entry, *tce_entryp;
u64 local_alloc_top, local_alloc_bottom;
u64 i;
- if (RELOC(prom_iommu_off))
+ if (prom_iommu_off)
return;
prom_debug("starting prom_initialize_tce_table\n");
/* Cache current top of allocs so we reserve a single block */
- local_alloc_top = RELOC(alloc_top_high);
+ local_alloc_top = alloc_top_high;
local_alloc_bottom = local_alloc_top;
/* Search all nodes looking for PHBs. */
@@ -1719,19 +1702,19 @@ static void __init prom_initialize_tce_table(void)
prom_getprop(node, "device_type", type, sizeof(type));
prom_getprop(node, "model", model, sizeof(model));
- if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL))
+ if ((type[0] == 0) || (strstr(type, "pci") == NULL))
continue;
/* Keep the old logic intact to avoid regression. */
if (compatible[0] != 0) {
- if ((strstr(compatible, RELOC("python")) == NULL) &&
- (strstr(compatible, RELOC("Speedwagon")) == NULL) &&
- (strstr(compatible, RELOC("Winnipeg")) == NULL))
+ if ((strstr(compatible, "python") == NULL) &&
+ (strstr(compatible, "Speedwagon") == NULL) &&
+ (strstr(compatible, "Winnipeg") == NULL))
continue;
} else if (model[0] != 0) {
- if ((strstr(model, RELOC("ython")) == NULL) &&
- (strstr(model, RELOC("peedwagon")) == NULL) &&
- (strstr(model, RELOC("innipeg")) == NULL))
+ if ((strstr(model, "ython") == NULL) &&
+ (strstr(model, "peedwagon") == NULL) &&
+ (strstr(model, "innipeg") == NULL))
continue;
}
@@ -1810,8 +1793,8 @@ static void __init prom_initialize_tce_table(void)
/* These are only really needed if there is a memory limit in
* effect, but we don't know so export them always. */
- RELOC(prom_tce_alloc_start) = local_alloc_bottom;
- RELOC(prom_tce_alloc_end) = local_alloc_top;
+ prom_tce_alloc_start = local_alloc_bottom;
+ prom_tce_alloc_end = local_alloc_top;
/* Flag the first invalid entry */
prom_debug("ending prom_initialize_tce_table\n");
@@ -1848,7 +1831,6 @@ static void __init prom_hold_cpus(void)
unsigned int reg;
phandle node;
char type[64];
- struct prom_t *_prom = &RELOC(prom);
unsigned long *spinloop
= (void *) LOW_ADDR(__secondary_hold_spinloop);
unsigned long *acknowledge
@@ -1874,12 +1856,12 @@ static void __init prom_hold_cpus(void)
for (node = 0; prom_next_node(&node); ) {
type[0] = 0;
prom_getprop(node, "device_type", type, sizeof(type));
- if (strcmp(type, RELOC("cpu")) != 0)
+ if (strcmp(type, "cpu") != 0)
continue;
/* Skip non-configured cpus. */
if (prom_getprop(node, "status", type, sizeof(type)) > 0)
- if (strcmp(type, RELOC("okay")) != 0)
+ if (strcmp(type, "okay") != 0)
continue;
reg = -1;
@@ -1893,7 +1875,7 @@ static void __init prom_hold_cpus(void)
*/
*acknowledge = (unsigned long)-1;
- if (reg != _prom->cpu) {
+ if (reg != prom.cpu) {
/* Primary Thread of non-boot cpu or any thread */
prom_printf("starting cpu hw idx %lu... ", reg);
call_prom("start-cpu", 3, 0, node,
@@ -1920,22 +1902,20 @@ static void __init prom_hold_cpus(void)
static void __init prom_init_client_services(unsigned long pp)
{
- struct prom_t *_prom = &RELOC(prom);
-
/* Get a handle to the prom entry point before anything else */
- RELOC(prom_entry) = pp;
+ prom_entry = pp;
/* get a handle for the stdout device */
- _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen"));
- if (!PHANDLE_VALID(_prom->chosen))
+ prom.chosen = call_prom("finddevice", 1, 1, ADDR("/chosen"));
+ if (!PHANDLE_VALID(prom.chosen))
prom_panic("cannot find chosen"); /* msg won't be printed :( */
/* get device tree root */
- _prom->root = call_prom("finddevice", 1, 1, ADDR("/"));
- if (!PHANDLE_VALID(_prom->root))
+ prom.root = call_prom("finddevice", 1, 1, ADDR("/"));
+ if (!PHANDLE_VALID(prom.root))
prom_panic("cannot find device tree root"); /* msg won't be printed :( */
- _prom->mmumap = 0;
+ prom.mmumap = 0;
}
#ifdef CONFIG_PPC32
@@ -1946,7 +1926,6 @@ static void __init prom_init_client_services(unsigned long pp)
*/
static void __init prom_find_mmu(void)
{
- struct prom_t *_prom = &RELOC(prom);
phandle oprom;
char version[64];
@@ -1964,10 +1943,10 @@ static void __init prom_find_mmu(void)
call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim");
} else
return;
- _prom->memory = call_prom("open", 1, 1, ADDR("/memory"));
- prom_getprop(_prom->chosen, "mmu", &_prom->mmumap,
- sizeof(_prom->mmumap));
- if (!IHANDLE_VALID(_prom->memory) || !IHANDLE_VALID(_prom->mmumap))
+ prom.memory = call_prom("open", 1, 1, ADDR("/memory"));
+ prom_getprop(prom.chosen, "mmu", &prom.mmumap,
+ sizeof(prom.mmumap));
+ if (!IHANDLE_VALID(prom.memory) || !IHANDLE_VALID(prom.mmumap))
of_workarounds &= ~OF_WA_CLAIM; /* hmmm */
}
#else
@@ -1976,36 +1955,34 @@ static void __init prom_find_mmu(void)
static void __init prom_init_stdout(void)
{
- struct prom_t *_prom = &RELOC(prom);
- char *path = RELOC(of_stdout_device);
+ char *path = of_stdout_device;
char type[16];
u32 val;
- if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0)
+ if (prom_getprop(prom.chosen, "stdout", &val, sizeof(val)) <= 0)
prom_panic("cannot find stdout");
- _prom->stdout = val;
+ prom.stdout = val;
/* Get the full OF pathname of the stdout device */
memset(path, 0, 256);
- call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255);
- val = call_prom("instance-to-package", 1, 1, _prom->stdout);
- prom_setprop(_prom->chosen, "/chosen", "linux,stdout-package",
+ call_prom("instance-to-path", 3, 1, prom.stdout, path, 255);
+ val = call_prom("instance-to-package", 1, 1, prom.stdout);
+ prom_setprop(prom.chosen, "/chosen", "linux,stdout-package",
&val, sizeof(val));
- prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device));
- prom_setprop(_prom->chosen, "/chosen", "linux,stdout-path",
+ prom_printf("OF stdout device is: %s\n", of_stdout_device);
+ prom_setprop(prom.chosen, "/chosen", "linux,stdout-path",
path, strlen(path) + 1);
/* If it's a display, note it */
memset(type, 0, sizeof(type));
prom_getprop(val, "device_type", type, sizeof(type));
- if (strcmp(type, RELOC("display")) == 0)
+ if (strcmp(type, "display") == 0)
prom_setprop(val, path, "linux,boot-display", NULL, 0);
}
static int __init prom_find_machine_type(void)
{
- struct prom_t *_prom = &RELOC(prom);
char compat[256];
int len, i = 0;
#ifdef CONFIG_PPC64
@@ -2014,7 +1991,7 @@ static int __init prom_find_machine_type(void)
#endif
/* Look for a PowerMac or a Cell */
- len = prom_getprop(_prom->root, "compatible",
+ len = prom_getprop(prom.root, "compatible",
compat, sizeof(compat)-1);
if (len > 0) {
compat[len] = 0;
@@ -2023,16 +2000,16 @@ static int __init prom_find_machine_type(void)
int sl = strlen(p);
if (sl == 0)
break;
- if (strstr(p, RELOC("Power Macintosh")) ||
- strstr(p, RELOC("MacRISC")))
+ if (strstr(p, "Power Macintosh") ||
+ strstr(p, "MacRISC"))
return PLATFORM_POWERMAC;
#ifdef CONFIG_PPC64
/* We must make sure we don't detect the IBM Cell
* blades as pSeries due to some firmware issues,
* so we do it here.
*/
- if (strstr(p, RELOC("IBM,CBEA")) ||
- strstr(p, RELOC("IBM,CPBW-1.0")))
+ if (strstr(p, "IBM,CBEA") ||
+ strstr(p, "IBM,CPBW-1.0"))
return PLATFORM_GENERIC;
#endif /* CONFIG_PPC64 */
i += sl + 1;
@@ -2049,11 +2026,11 @@ static int __init prom_find_machine_type(void)
* non-IBM designs !
* - it has /rtas
*/
- len = prom_getprop(_prom->root, "device_type",
+ len = prom_getprop(prom.root, "device_type",
compat, sizeof(compat)-1);
if (len <= 0)
return PLATFORM_GENERIC;
- if (strcmp(compat, RELOC("chrp")))
+ if (strcmp(compat, "chrp"))
return PLATFORM_GENERIC;
/* Default to pSeries. We need to know if we are running LPAR */
@@ -2115,11 +2092,11 @@ static void __init prom_check_displays(void)
for (node = 0; prom_next_node(&node); ) {
memset(type, 0, sizeof(type));
prom_getprop(node, "device_type", type, sizeof(type));
- if (strcmp(type, RELOC("display")) != 0)
+ if (strcmp(type, "display") != 0)
continue;
/* It seems OF doesn't null-terminate the path :-( */
- path = RELOC(prom_scratch);
+ path = prom_scratch;
memset(path, 0, PROM_SCRATCH_SIZE);
/*
@@ -2143,15 +2120,15 @@ static void __init prom_check_displays(void)
/* Setup a usable color table when the appropriate
* method is available. Should update this to set-colors */
- clut = RELOC(default_colors);
+ clut = default_colors;
for (i = 0; i < 16; i++, clut += 3)
if (prom_set_color(ih, i, clut[0], clut[1],
clut[2]) != 0)
break;
#ifdef CONFIG_LOGO_LINUX_CLUT224
- clut = PTRRELOC(RELOC(logo_linux_clut224.clut));
- for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3)
+ clut = PTRRELOC(logo_linux_clut224.clut);
+ for (i = 0; i < logo_linux_clut224.clutsize; i++, clut += 3)
if (prom_set_color(ih, i + 32, clut[0], clut[1],
clut[2]) != 0)
break;
@@ -2171,8 +2148,8 @@ static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end,
unsigned long room, chunk;
prom_debug("Chunk exhausted, claiming more at %x...\n",
- RELOC(alloc_bottom));
- room = RELOC(alloc_top) - RELOC(alloc_bottom);
+ alloc_bottom);
+ room = alloc_top - alloc_bottom;
if (room > DEVTREE_CHUNK_SIZE)
room = DEVTREE_CHUNK_SIZE;
if (room < PAGE_SIZE)
@@ -2198,9 +2175,9 @@ static unsigned long __init dt_find_string(char *str)
{
char *s, *os;
- s = os = (char *)RELOC(dt_string_start);
+ s = os = (char *)dt_string_start;
s += 4;
- while (s < (char *)RELOC(dt_string_end)) {
+ while (s < (char *)dt_string_end) {
if (strcmp(s, str) == 0)
return s - os;
s += strlen(s) + 1;
@@ -2222,10 +2199,10 @@ static void __init scan_dt_build_strings(phandle node,
unsigned long soff;
phandle child;
- sstart = (char *)RELOC(dt_string_start);
+ sstart = (char *)dt_string_start;
/* get and store all property names */
- prev_name = RELOC("");
+ prev_name = "";
for (;;) {
/* 64 is max len of name including nul. */
namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
@@ -2236,9 +2213,9 @@ static void __init scan_dt_build_strings(phandle node,
}
/* skip "name" */
- if (strcmp(namep, RELOC("name")) == 0) {
+ if (strcmp(namep, "name") == 0) {
*mem_start = (unsigned long)namep;
- prev_name = RELOC("name");
+ prev_name = "name";
continue;
}
/* get/create string entry */
@@ -2249,7 +2226,7 @@ static void __init scan_dt_build_strings(phandle node,
} else {
/* Trim off some if we can */
*mem_start = (unsigned long)namep + strlen(namep) + 1;
- RELOC(dt_string_end) = *mem_start;
+ dt_string_end = *mem_start;
}
prev_name = namep;
}
@@ -2304,35 +2281,35 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
}
/* get it again for debugging */
- path = RELOC(prom_scratch);
+ path = prom_scratch;
memset(path, 0, PROM_SCRATCH_SIZE);
call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
/* get and store all properties */
- prev_name = RELOC("");
- sstart = (char *)RELOC(dt_string_start);
+ prev_name = "";
+ sstart = (char *)dt_string_start;
for (;;) {
if (call_prom("nextprop", 3, 1, node, prev_name,
- RELOC(pname)) != 1)
+ pname) != 1)
break;
/* skip "name" */
- if (strcmp(RELOC(pname), RELOC("name")) == 0) {
- prev_name = RELOC("name");
+ if (strcmp(pname, "name") == 0) {
+ prev_name = "name";
continue;
}
/* find string offset */
- soff = dt_find_string(RELOC(pname));
+ soff = dt_find_string(pname);
if (soff == 0) {
prom_printf("WARNING: Can't find string index for"
- " <%s>, node %s\n", RELOC(pname), path);
+ " <%s>, node %s\n", pname, path);
break;
}
prev_name = sstart + soff;
/* get length */
- l = call_prom("getproplen", 2, 1, node, RELOC(pname));
+ l = call_prom("getproplen", 2, 1, node, pname);
/* sanity checks */
if (l == PROM_ERROR)
@@ -2345,10 +2322,10 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
/* push property content */
valp = make_room(mem_start, mem_end, l, 4);
- call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
+ call_prom("getprop", 4, 1, node, pname, valp, l);
*mem_start = _ALIGN(*mem_start, 4);
- if (!strcmp(RELOC(pname), RELOC("phandle")))
+ if (!strcmp(pname, "phandle"))
has_phandle = 1;
}
@@ -2356,7 +2333,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
* existed (can happen with OPAL)
*/
if (!has_phandle) {
- soff = dt_find_string(RELOC("linux,phandle"));
+ soff = dt_find_string("linux,phandle");
if (soff == 0)
prom_printf("WARNING: Can't find string index for"
" <linux-phandle> node %s\n", path);
@@ -2384,7 +2361,6 @@ static void __init flatten_device_tree(void)
phandle root;
unsigned long mem_start, mem_end, room;
struct boot_param_header *hdr;
- struct prom_t *_prom = &RELOC(prom);
char *namep;
u64 *rsvmap;
@@ -2392,10 +2368,10 @@ static void __init flatten_device_tree(void)
* Check how much room we have between alloc top & bottom (+/- a
* few pages), crop to 1MB, as this is our "chunk" size
*/
- room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000;
+ room = alloc_top - alloc_bottom - 0x4000;
if (room > DEVTREE_CHUNK_SIZE)
room = DEVTREE_CHUNK_SIZE;
- prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom));
+ prom_debug("starting device tree allocs at %x\n", alloc_bottom);
/* Now try to claim that */
mem_start = (unsigned long)alloc_up(room, PAGE_SIZE);
@@ -2412,66 +2388,66 @@ static void __init flatten_device_tree(void)
mem_start = _ALIGN(mem_start, 4);
hdr = make_room(&mem_start, &mem_end,
sizeof(struct boot_param_header), 4);
- RELOC(dt_header_start) = (unsigned long)hdr;
+ dt_header_start = (unsigned long)hdr;
rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
/* Start of strings */
mem_start = PAGE_ALIGN(mem_start);
- RELOC(dt_string_start) = mem_start;
+ dt_string_start = mem_start;
mem_start += 4; /* hole */
/* Add "linux,phandle" in there, we'll need it */
namep = make_room(&mem_start, &mem_end, 16, 1);
- strcpy(namep, RELOC("linux,phandle"));
+ strcpy(namep, "linux,phandle");
mem_start = (unsigned long)namep + strlen(namep) + 1;
/* Build string array */
prom_printf("Building dt strings...\n");
scan_dt_build_strings(root, &mem_start, &mem_end);
- RELOC(dt_string_end) = mem_start;
+ dt_string_end = mem_start;
/* Build structure */
mem_start = PAGE_ALIGN(mem_start);
- RELOC(dt_struct_start) = mem_start;
+ dt_struct_start = mem_start;
prom_printf("Building dt structure...\n");
scan_dt_build_struct(root, &mem_start, &mem_end);
dt_push_token(OF_DT_END, &mem_start, &mem_end);
- RELOC(dt_struct_end) = PAGE_ALIGN(mem_start);
+ dt_struct_end = PAGE_ALIGN(mem_start);
/* Finish header */
- hdr->boot_cpuid_phys = _prom->cpu;
+ hdr->boot_cpuid_phys = prom.cpu;
hdr->magic = OF_DT_HEADER;
- hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);
- hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);
- hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);
- hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start);
- hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);
+ hdr->totalsize = dt_struct_end - dt_header_start;
+ hdr->off_dt_struct = dt_struct_start - dt_header_start;
+ hdr->off_dt_strings = dt_string_start - dt_header_start;
+ hdr->dt_strings_size = dt_string_end - dt_string_start;
+ hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - dt_header_start;
hdr->version = OF_DT_VERSION;
/* Version 16 is not backward compatible */
hdr->last_comp_version = 0x10;
/* Copy the reserve map in */
- memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map));
+ memcpy(rsvmap, mem_reserve_map, sizeof(mem_reserve_map));
#ifdef DEBUG_PROM
{
int i;
prom_printf("reserved memory map:\n");
- for (i = 0; i < RELOC(mem_reserve_cnt); i++)
+ for (i = 0; i < mem_reserve_cnt; i++)
prom_printf(" %x - %x\n",
- RELOC(mem_reserve_map)[i].base,
- RELOC(mem_reserve_map)[i].size);
+ mem_reserve_map[i].base,
+ mem_reserve_map[i].size);
}
#endif
/* Bump mem_reserve_cnt to cause further reservations to fail
* since it's too late.
*/
- RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE;
+ mem_reserve_cnt = MEM_RESERVE_MAP_SIZE;
prom_printf("Device tree strings 0x%x -> 0x%x\n",
- RELOC(dt_string_start), RELOC(dt_string_end));
+ dt_string_start, dt_string_end);
prom_printf("Device tree struct 0x%x -> 0x%x\n",
- RELOC(dt_struct_start), RELOC(dt_struct_end));
+ dt_struct_start, dt_struct_end);
}
@@ -2526,7 +2502,6 @@ static void __init fixup_device_tree_maple_memory_controller(void)
phandle mc;
u32 mc_reg[4];
char *name = "/hostbridge@f8000000";
- struct prom_t *_prom = &RELOC(prom);
u32 ac, sc;
mc = call_prom("finddevice", 1, 1, ADDR(name));
@@ -2536,8 +2511,8 @@ static void __init fixup_device_tree_maple_memory_controller(void)
if (prom_getproplen(mc, "reg") != 8)
return;
- prom_getprop(_prom->root, "#address-cells", &ac, sizeof(ac));
- prom_getprop(_prom->root, "#size-cells", &sc, sizeof(sc));
+ prom_getprop(prom.root, "#address-cells", &ac, sizeof(ac));
+ prom_getprop(prom.root, "#size-cells", &sc, sizeof(sc));
if ((ac != 2) || (sc != 2))
return;
@@ -2806,50 +2781,94 @@ static void __init fixup_device_tree(void)
static void __init prom_find_boot_cpu(void)
{
- struct prom_t *_prom = &RELOC(prom);
u32 getprop_rval;
ihandle prom_cpu;
phandle cpu_pkg;
- _prom->cpu = 0;
- if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0)
+ prom.cpu = 0;
+ if (prom_getprop(prom.chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0)
return;
cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval));
- _prom->cpu = getprop_rval;
+ prom.cpu = getprop_rval;
- prom_debug("Booting CPU hw index = %lu\n", _prom->cpu);
+ prom_debug("Booting CPU hw index = %lu\n", prom.cpu);
}
static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
{
#ifdef CONFIG_BLK_DEV_INITRD
- struct prom_t *_prom = &RELOC(prom);
-
if (r3 && r4 && r4 != 0xdeadbeef) {
unsigned long val;
- RELOC(prom_initrd_start) = is_kernel_addr(r3) ? __pa(r3) : r3;
- RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4;
+ prom_initrd_start = is_kernel_addr(r3) ? __pa(r3) : r3;
+ prom_initrd_end = prom_initrd_start + r4;
- val = RELOC(prom_initrd_start);
- prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start",
+ val = prom_initrd_start;
+ prom_setprop(prom.chosen, "/chosen", "linux,initrd-start",
&val, sizeof(val));
- val = RELOC(prom_initrd_end);
- prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end",
+ val = prom_initrd_end;
+ prom_setprop(prom.chosen, "/chosen", "linux,initrd-end",
&val, sizeof(val));
- reserve_mem(RELOC(prom_initrd_start),
- RELOC(prom_initrd_end) - RELOC(prom_initrd_start));
+ reserve_mem(prom_initrd_start,
+ prom_initrd_end - prom_initrd_start);
- prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start));
- prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end));
+ prom_debug("initrd_start=0x%x\n", prom_initrd_start);
+ prom_debug("initrd_end=0x%x\n", prom_initrd_end);
}
#endif /* CONFIG_BLK_DEV_INITRD */
}
+#ifdef CONFIG_PPC64
+#ifdef CONFIG_RELOCATABLE
+static void reloc_toc(void)
+{
+}
+
+static void unreloc_toc(void)
+{
+}
+#else
+static void __reloc_toc(void *tocstart, unsigned long offset,
+ unsigned long nr_entries)
+{
+ unsigned long i;
+ unsigned long *toc_entry = (unsigned long *)tocstart;
+
+ for (i = 0; i < nr_entries; i++) {
+ *toc_entry = *toc_entry + offset;
+ toc_entry++;
+ }
+}
+
+static void reloc_toc(void)
+{
+ unsigned long offset = reloc_offset();
+ unsigned long nr_entries =
+ (__prom_init_toc_end - __prom_init_toc_start) / sizeof(long);
+
+ /* Need to add offset to get at __prom_init_toc_start */
+ __reloc_toc(__prom_init_toc_start + offset, offset, nr_entries);
+
+ mb();
+}
+
+static void unreloc_toc(void)
+{
+ unsigned long offset = reloc_offset();
+ unsigned long nr_entries =
+ (__prom_init_toc_end - __prom_init_toc_start) / sizeof(long);
+
+ mb();
+
+ /* __prom_init_toc_start has been relocated, no need to add offset */
+ __reloc_toc(__prom_init_toc_start, -offset, nr_entries);
+}
+#endif
+#endif
/*
* We enter here early on, when the Open Firmware prom is still
@@ -2861,20 +2880,19 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
unsigned long r6, unsigned long r7,
unsigned long kbase)
{
- struct prom_t *_prom;
unsigned long hdr;
#ifdef CONFIG_PPC32
unsigned long offset = reloc_offset();
reloc_got2(offset);
+#else
+ reloc_toc();
#endif
- _prom = &RELOC(prom);
-
/*
* First zero the BSS
*/
- memset(&RELOC(__bss_start), 0, __bss_stop - __bss_start);
+ memset(&__bss_start, 0, __bss_stop - __bss_start);
/*
* Init interface to Open Firmware, get some node references,
@@ -2893,14 +2911,14 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
*/
prom_init_stdout();
- prom_printf("Preparing to boot %s", RELOC(linux_banner));
+ prom_printf("Preparing to boot %s", linux_banner);
/*
* Get default machine type. At this point, we do not differentiate
* between pSeries SMP and pSeries LPAR
*/
- RELOC(of_platform) = prom_find_machine_type();
- prom_printf("Detected machine type: %x\n", RELOC(of_platform));
+ of_platform = prom_find_machine_type();
+ prom_printf("Detected machine type: %x\n", of_platform);
#ifndef CONFIG_NONSTATIC_KERNEL
/* Bail if this is a kdump kernel. */
@@ -2917,15 +2935,15 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
/*
* On pSeries, inform the firmware about our capabilities
*/
- if (RELOC(of_platform) == PLATFORM_PSERIES ||
- RELOC(of_platform) == PLATFORM_PSERIES_LPAR)
+ if (of_platform == PLATFORM_PSERIES ||
+ of_platform == PLATFORM_PSERIES_LPAR)
prom_send_capabilities();
#endif
/*
* Copy the CPU hold code
*/
- if (RELOC(of_platform) != PLATFORM_POWERMAC)
+ if (of_platform != PLATFORM_POWERMAC)
copy_and_flush(0, kbase, 0x100, 0);
/*
@@ -2954,7 +2972,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
* that uses the allocator, we need to make sure we get the top of memory
* available for us here...
*/
- if (RELOC(of_platform) == PLATFORM_PSERIES)
+ if (of_platform == PLATFORM_PSERIES)
prom_initialize_tce_table();
#endif
@@ -2962,19 +2980,19 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
* On non-powermacs, try to instantiate RTAS. PowerMacs don't
* have a usable RTAS implementation.
*/
- if (RELOC(of_platform) != PLATFORM_POWERMAC &&
- RELOC(of_platform) != PLATFORM_OPAL)
+ if (of_platform != PLATFORM_POWERMAC &&
+ of_platform != PLATFORM_OPAL)
prom_instantiate_rtas();
#ifdef CONFIG_PPC_POWERNV
/* Detect HAL and try instanciating it & doing takeover */
- if (RELOC(of_platform) == PLATFORM_PSERIES_LPAR) {
+ if (of_platform == PLATFORM_PSERIES_LPAR) {
prom_query_opal();
- if (RELOC(of_platform) == PLATFORM_OPAL) {
+ if (of_platform == PLATFORM_OPAL) {
prom_opal_hold_cpus();
prom_opal_takeover();
}
- } else if (RELOC(of_platform) == PLATFORM_OPAL)
+ } else if (of_platform == PLATFORM_OPAL)
prom_instantiate_opal();
#endif
@@ -2988,32 +3006,32 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
*
* PowerMacs use a different mechanism to spin CPUs
*/
- if (RELOC(of_platform) != PLATFORM_POWERMAC &&
- RELOC(of_platform) != PLATFORM_OPAL)
+ if (of_platform != PLATFORM_POWERMAC &&
+ of_platform != PLATFORM_OPAL)
prom_hold_cpus();
/*
* Fill in some infos for use by the kernel later on
*/
- if (RELOC(prom_memory_limit))
- prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit",
- &RELOC(prom_memory_limit),
+ if (prom_memory_limit)
+ prom_setprop(prom.chosen, "/chosen", "linux,memory-limit",
+ &prom_memory_limit,
sizeof(prom_memory_limit));
#ifdef CONFIG_PPC64
- if (RELOC(prom_iommu_off))
- prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
+ if (prom_iommu_off)
+ prom_setprop(prom.chosen, "/chosen", "linux,iommu-off",
NULL, 0);
- if (RELOC(prom_iommu_force_on))
- prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on",
+ if (prom_iommu_force_on)
+ prom_setprop(prom.chosen, "/chosen", "linux,iommu-force-on",
NULL, 0);
- if (RELOC(prom_tce_alloc_start)) {
- prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-start",
- &RELOC(prom_tce_alloc_start),
+ if (prom_tce_alloc_start) {
+ prom_setprop(prom.chosen, "/chosen", "linux,tce-alloc-start",
+ &prom_tce_alloc_start,
sizeof(prom_tce_alloc_start));
- prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-end",
- &RELOC(prom_tce_alloc_end),
+ prom_setprop(prom.chosen, "/chosen", "linux,tce-alloc-end",
+ &prom_tce_alloc_end,
sizeof(prom_tce_alloc_end));
}
#endif
@@ -3035,8 +3053,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
* closed stdin already (in particular the powerbook 101). It
* appears that the OPAL version of OFW doesn't like it either.
*/
- if (RELOC(of_platform) != PLATFORM_POWERMAC &&
- RELOC(of_platform) != PLATFORM_OPAL)
+ if (of_platform != PLATFORM_POWERMAC &&
+ of_platform != PLATFORM_OPAL)
prom_close_stdin();
/*
@@ -3051,22 +3069,24 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
* tree and NULL as r5, thus triggering the new entry point which
* is common to us and kexec
*/
- hdr = RELOC(dt_header_start);
+ hdr = dt_header_start;
/* Don't print anything after quiesce under OPAL, it crashes OFW */
- if (RELOC(of_platform) != PLATFORM_OPAL) {
+ if (of_platform != PLATFORM_OPAL) {
prom_printf("returning from prom_init\n");
prom_debug("->dt_header_start=0x%x\n", hdr);
}
#ifdef CONFIG_PPC32
reloc_got2(-offset);
+#else
+ unreloc_toc();
#endif
#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
/* OPAL early debug gets the OPAL base & entry in r8 and r9 */
__start(hdr, kbase, 0, 0, 0,
- RELOC(prom_opal_base), RELOC(prom_opal_entry));
+ prom_opal_base, prom_opal_entry);
#else
__start(hdr, kbase, 0, 0, 0, 0, 0);
#endif
diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh
index 70f4286eaa7a..3765da6be4f2 100644
--- a/arch/powerpc/kernel/prom_init_check.sh
+++ b/arch/powerpc/kernel/prom_init_check.sh
@@ -22,7 +22,7 @@ __secondary_hold_acknowledge __secondary_hold_spinloop __start
strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224
reloc_got2 kernstart_addr memstart_addr linux_banner _stext
opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry
-boot_command_line"
+boot_command_line __prom_init_toc_start __prom_init_toc_end"
NM="$1"
OBJ="$2"
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index c4970004d44d..245c1b6a0858 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -179,6 +179,30 @@ static int set_user_msr(struct task_struct *task, unsigned long msr)
return 0;
}
+#ifdef CONFIG_PPC64
+static unsigned long get_user_dscr(struct task_struct *task)
+{
+ return task->thread.dscr;
+}
+
+static int set_user_dscr(struct task_struct *task, unsigned long dscr)
+{
+ task->thread.dscr = dscr;
+ task->thread.dscr_inherit = 1;
+ return 0;
+}
+#else
+static unsigned long get_user_dscr(struct task_struct *task)
+{
+ return -EIO;
+}
+
+static int set_user_dscr(struct task_struct *task, unsigned long dscr)
+{
+ return -EIO;
+}
+#endif
+
/*
* We prevent mucking around with the reserved area of trap
* which are used internally by the kernel.
@@ -200,6 +224,9 @@ unsigned long ptrace_get_reg(struct task_struct *task, int regno)
if (regno == PT_MSR)
return get_user_msr(task);
+ if (regno == PT_DSCR)
+ return get_user_dscr(task);
+
if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
return ((unsigned long *)task->thread.regs)[regno];
@@ -218,6 +245,8 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
return set_user_msr(task, data);
if (regno == PT_TRAP)
return set_user_trap(task, data);
+ if (regno == PT_DSCR)
+ return set_user_dscr(task, data);
if (regno <= PT_MAX_PUT_REG) {
((unsigned long *)task->thread.regs)[regno] = data;
@@ -905,6 +934,9 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
struct perf_event *bp;
struct perf_event_attr attr;
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+#ifndef CONFIG_PPC_ADV_DEBUG_REGS
+ struct arch_hw_breakpoint hw_brk;
+#endif
/* For ppc64 we support one DABR and no IABR's at the moment (ppc64).
* For embedded processors we support one DAC and no IAC's at the
@@ -931,14 +963,17 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
*/
/* Ensure breakpoint translation bit is set */
- if (data && !(data & DABR_TRANSLATION))
+ if (data && !(data & HW_BRK_TYPE_TRANSLATE))
return -EIO;
+ hw_brk.address = data & (~HW_BRK_TYPE_DABR);
+ hw_brk.type = (data & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
+ hw_brk.len = 8;
#ifdef CONFIG_HAVE_HW_BREAKPOINT
if (ptrace_get_breakpoints(task) < 0)
return -ESRCH;
bp = thread->ptrace_bps[0];
- if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) {
+ if ((!data) || !(hw_brk.type & HW_BRK_TYPE_RDWR)) {
if (bp) {
unregister_hw_breakpoint(bp);
thread->ptrace_bps[0] = NULL;
@@ -948,10 +983,8 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
}
if (bp) {
attr = bp->attr;
- attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN;
- arch_bp_generic_fields(data &
- (DABR_DATA_WRITE | DABR_DATA_READ),
- &attr.bp_type);
+ attr.bp_addr = hw_brk.address;
+ arch_bp_generic_fields(hw_brk.type, &attr.bp_type);
/* Enable breakpoint */
attr.disabled = false;
@@ -963,16 +996,15 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
}
thread->ptrace_bps[0] = bp;
ptrace_put_breakpoints(task);
- thread->dabr = data;
- thread->dabrx = DABRX_ALL;
+ thread->hw_brk = hw_brk;
return 0;
}
/* Create a new breakpoint request if one doesn't exist already */
hw_breakpoint_init(&attr);
- attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN;
- arch_bp_generic_fields(data & (DABR_DATA_WRITE | DABR_DATA_READ),
- &attr.bp_type);
+ attr.bp_addr = hw_brk.address;
+ arch_bp_generic_fields(hw_brk.type,
+ &attr.bp_type);
thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
ptrace_triggered, NULL, task);
@@ -985,10 +1017,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
ptrace_put_breakpoints(task);
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
-
- /* Move contents to the DABR register */
- task->thread.dabr = data;
- task->thread.dabrx = DABRX_ALL;
+ task->thread.hw_brk = hw_brk;
#else /* CONFIG_PPC_ADV_DEBUG_REGS */
/* As described above, it was assumed 3 bits were passed with the data
* address, but we will assume only the mode bits will be passed
@@ -1349,7 +1378,7 @@ static long ppc_set_hwdebug(struct task_struct *child,
struct perf_event_attr attr;
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#ifndef CONFIG_PPC_ADV_DEBUG_REGS
- unsigned long dabr;
+ struct arch_hw_breakpoint brk;
#endif
if (bp_info->version != 1)
@@ -1397,12 +1426,12 @@ static long ppc_set_hwdebug(struct task_struct *child,
if ((unsigned long)bp_info->addr >= TASK_SIZE)
return -EIO;
- dabr = (unsigned long)bp_info->addr & ~7UL;
- dabr |= DABR_TRANSLATION;
+ brk.address = bp_info->addr & ~7UL;
+ brk.type = HW_BRK_TYPE_TRANSLATE;
if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
- dabr |= DABR_DATA_READ;
+ brk.type |= HW_BRK_TYPE_READ;
if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
- dabr |= DABR_DATA_WRITE;
+ brk.type |= HW_BRK_TYPE_WRITE;
#ifdef CONFIG_HAVE_HW_BREAKPOINT
if (ptrace_get_breakpoints(child) < 0)
return -ESRCH;
@@ -1427,8 +1456,7 @@ static long ppc_set_hwdebug(struct task_struct *child,
hw_breakpoint_init(&attr);
attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN;
attr.bp_len = len;
- arch_bp_generic_fields(dabr & (DABR_DATA_WRITE | DABR_DATA_READ),
- &attr.bp_type);
+ arch_bp_generic_fields(brk.type, &attr.bp_type);
thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
ptrace_triggered, NULL, child);
@@ -1445,11 +1473,10 @@ static long ppc_set_hwdebug(struct task_struct *child,
if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
return -EINVAL;
- if (child->thread.dabr)
+ if (child->thread.hw_brk.address)
return -ENOSPC;
- child->thread.dabr = dabr;
- child->thread.dabrx = DABRX_ALL;
+ child->thread.hw_brk = brk;
return 1;
#endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */
@@ -1495,10 +1522,11 @@ static long ppc_del_hwdebug(struct task_struct *child, long data)
ptrace_put_breakpoints(child);
return ret;
#else /* CONFIG_HAVE_HW_BREAKPOINT */
- if (child->thread.dabr == 0)
+ if (child->thread.hw_brk.address == 0)
return -ENOENT;
- child->thread.dabr = 0;
+ child->thread.hw_brk.address = 0;
+ child->thread.hw_brk.type = 0;
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
return 0;
@@ -1642,6 +1670,9 @@ long arch_ptrace(struct task_struct *child, long request,
}
case PTRACE_GET_DEBUGREG: {
+#ifndef CONFIG_PPC_ADV_DEBUG_REGS
+ unsigned long dabr_fake;
+#endif
ret = -EINVAL;
/* We only support one DABR and no IABRS at the moment */
if (addr > 0)
@@ -1649,7 +1680,9 @@ long arch_ptrace(struct task_struct *child, long request,
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
ret = put_user(child->thread.dac1, datalp);
#else
- ret = put_user(child->thread.dabr, datalp);
+ dabr_fake = ((child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) |
+ (child->thread.hw_brk.type & HW_BRK_TYPE_DABR));
+ ret = put_user(dabr_fake, datalp);
#endif
break;
}
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 8c21658719d9..c0244e766834 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -252,6 +252,9 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
}
case PTRACE_GET_DEBUGREG: {
+#ifndef CONFIG_PPC_ADV_DEBUG_REGS
+ unsigned long dabr_fake;
+#endif
ret = -EINVAL;
/* We only support one DABR and no IABRS at the moment */
if (addr > 0)
@@ -259,7 +262,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
ret = put_user(child->thread.dac1, (u32 __user *)data);
#else
- ret = put_user(child->thread.dabr, (u32 __user *)data);
+ dabr_fake = (
+ (child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) |
+ (child->thread.hw_brk.type & HW_BRK_TYPE_DABR));
+ ret = put_user(dabr_fake, (u32 __user *)data);
#endif
break;
}
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 6da881b35dac..75fbaceb5c87 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -156,6 +156,15 @@ early_param("smt-enabled", early_smt_enabled);
#define check_smt_enabled()
#endif /* CONFIG_SMP */
+/** Fix up paca fields required for the boot cpu */
+static void fixup_boot_paca(void)
+{
+ /* The boot cpu is started */
+ get_paca()->cpu_start = 1;
+ /* Allow percpu accesses to work until we setup percpu data */
+ get_paca()->data_offset = 0;
+}
+
/*
* Early initialization entry point. This is called by head.S
* with MMU translation disabled. We rely on the "feature" of
@@ -177,6 +186,8 @@ early_param("smt-enabled", early_smt_enabled);
void __init early_setup(unsigned long dt_ptr)
{
+ static __initdata struct paca_struct boot_paca;
+
/* -------- printk is _NOT_ safe to use here ! ------- */
/* Identify CPU type */
@@ -185,6 +196,7 @@ void __init early_setup(unsigned long dt_ptr)
/* Assume we're on cpu 0 for now. Don't write to the paca yet! */
initialise_paca(&boot_paca, 0);
setup_paca(&boot_paca);
+ fixup_boot_paca();
/* Initialize lockdep early or else spinlocks will blow */
lockdep_init();
@@ -205,11 +217,7 @@ void __init early_setup(unsigned long dt_ptr)
/* Now we know the logical id of our boot cpu, setup the paca. */
setup_paca(&paca[boot_cpuid]);
-
- /* Fix up paca fields required for the boot cpu */
- get_paca()->cpu_start = 1;
- /* Allow percpu accesses to "work" until we setup percpu data */
- get_paca()->data_offset = 0;
+ fixup_boot_paca();
/* Probe the machine type */
probe_machine();
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 3b997118df50..cf12eae02de5 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -130,8 +130,9 @@ static int do_signal(struct pt_regs *regs)
* user space. The DABR will have been cleared if it
* triggered inside the kernel.
*/
- if (current->thread.dabr)
- set_dabr(current->thread.dabr, current->thread.dabrx);
+ if (current->thread.hw_brk.address &&
+ current->thread.hw_brk.type)
+ set_breakpoint(&current->thread.hw_brk);
#endif
/* Re-enable the breakpoints for the signal stack */
thread_change_pc(current, regs);
@@ -169,10 +170,3 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
tracehook_notify_resume(regs);
}
}
-
-long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
- unsigned long r5, unsigned long r6, unsigned long r7,
- unsigned long r8, struct pt_regs *regs)
-{
- return do_sigaltstack(uss, uoss, regs->gpr[1]);
-}
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h
index e00acb413934..ec84c901ceab 100644
--- a/arch/powerpc/kernel/signal.h
+++ b/arch/powerpc/kernel/signal.h
@@ -25,13 +25,21 @@ extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
extern unsigned long copy_fpr_to_user(void __user *to,
struct task_struct *task);
+extern unsigned long copy_transact_fpr_to_user(void __user *to,
+ struct task_struct *task);
extern unsigned long copy_fpr_from_user(struct task_struct *task,
void __user *from);
+extern unsigned long copy_transact_fpr_from_user(struct task_struct *task,
+ void __user *from);
#ifdef CONFIG_VSX
extern unsigned long copy_vsx_to_user(void __user *to,
struct task_struct *task);
+extern unsigned long copy_transact_vsx_to_user(void __user *to,
+ struct task_struct *task);
extern unsigned long copy_vsx_from_user(struct task_struct *task,
void __user *from);
+extern unsigned long copy_transact_vsx_from_user(struct task_struct *task,
+ void __user *from);
#endif
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 804e323c139d..3acb28e245b4 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -43,6 +43,7 @@
#include <asm/sigcontext.h>
#include <asm/vdso.h>
#include <asm/switch_to.h>
+#include <asm/tm.h>
#ifdef CONFIG_PPC64
#include "ppc32.h"
#include <asm/unistd.h>
@@ -56,10 +57,7 @@
#undef DEBUG_SIG
#ifdef CONFIG_PPC64
-#define sys_sigsuspend compat_sys_sigsuspend
-#define sys_rt_sigsuspend compat_sys_rt_sigsuspend
#define sys_rt_sigreturn compat_sys_rt_sigreturn
-#define sys_sigaction compat_sys_sigaction
#define sys_swapcontext compat_sys_swapcontext
#define sys_sigreturn compat_sys_sigreturn
@@ -68,6 +66,8 @@
#define mcontext mcontext32
#define ucontext ucontext32
+#define __save_altstack __compat_save_altstack
+
/*
* Userspace code may pass a ucontext which doesn't include VSX added
* at the end. We need to check for this case.
@@ -130,23 +130,6 @@ static inline int get_sigset_t(sigset_t *set,
return 0;
}
-static inline int get_old_sigaction(struct k_sigaction *new_ka,
- struct old_sigaction __user *act)
-{
- compat_old_sigset_t mask;
- compat_uptr_t handler, restorer;
-
- if (get_user(handler, &act->sa_handler) ||
- __get_user(restorer, &act->sa_restorer) ||
- __get_user(new_ka->sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- new_ka->sa.sa_handler = compat_ptr(handler);
- new_ka->sa.sa_restorer = compat_ptr(restorer);
- siginitset(&new_ka->sa.sa_mask, mask);
- return 0;
-}
-
#define to_user_ptr(p) ptr_to_compat(p)
#define from_user_ptr(p) compat_ptr(p)
@@ -196,21 +179,6 @@ static inline int get_sigset_t(sigset_t *set, const sigset_t __user *uset)
return copy_from_user(set, uset, sizeof(*uset));
}
-static inline int get_old_sigaction(struct k_sigaction *new_ka,
- struct old_sigaction __user *act)
-{
- old_sigset_t mask;
-
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka->sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka->sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka->sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka->sa.sa_mask, mask);
- return 0;
-}
-
#define to_user_ptr(p) ((unsigned long)(p))
#define from_user_ptr(p) ((void __user *)(p))
@@ -234,50 +202,8 @@ static inline int restore_general_regs(struct pt_regs *regs,
return -EFAULT;
return 0;
}
-
-#endif /* CONFIG_PPC64 */
-
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-long sys_sigsuspend(old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-long sys_sigaction(int sig, struct old_sigaction __user *act,
- struct old_sigaction __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
-#ifdef CONFIG_PPC64
- if (sig < 0)
- sig = -sig;
#endif
- if (act) {
- if (get_old_sigaction(&new_ka, act))
- return -EFAULT;
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(to_user_ptr(old_ka.sa.sa_handler),
- &oact->sa_handler) ||
- __put_user(to_user_ptr(old_ka.sa.sa_restorer),
- &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
/*
* When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
@@ -293,6 +219,10 @@ long sys_sigaction(int sig, struct old_sigaction __user *act,
struct sigframe {
struct sigcontext sctx; /* the sigcontext */
struct mcontext mctx; /* all the register values */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ struct sigcontext sctx_transact;
+ struct mcontext mctx_transact;
+#endif
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
* regs and 18 fp regs below sp before decrementing it.
@@ -321,6 +251,9 @@ struct rt_sigframe {
struct siginfo info;
#endif
struct ucontext uc;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ struct ucontext uc_transact;
+#endif
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
* regs and 18 fp regs below sp before decrementing it.
@@ -381,6 +314,61 @@ unsigned long copy_vsx_from_user(struct task_struct *task,
task->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
return 0;
}
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+unsigned long copy_transact_fpr_to_user(void __user *to,
+ struct task_struct *task)
+{
+ double buf[ELF_NFPREG];
+ int i;
+
+ /* save FPR copy to local buffer then write to the thread_struct */
+ for (i = 0; i < (ELF_NFPREG - 1) ; i++)
+ buf[i] = task->thread.TS_TRANS_FPR(i);
+ memcpy(&buf[i], &task->thread.transact_fpscr, sizeof(double));
+ return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double));
+}
+
+unsigned long copy_transact_fpr_from_user(struct task_struct *task,
+ void __user *from)
+{
+ double buf[ELF_NFPREG];
+ int i;
+
+ if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double)))
+ return 1;
+ for (i = 0; i < (ELF_NFPREG - 1) ; i++)
+ task->thread.TS_TRANS_FPR(i) = buf[i];
+ memcpy(&task->thread.transact_fpscr, &buf[i], sizeof(double));
+
+ return 0;
+}
+
+unsigned long copy_transact_vsx_to_user(void __user *to,
+ struct task_struct *task)
+{
+ double buf[ELF_NVSRHALFREG];
+ int i;
+
+ /* save FPR copy to local buffer then write to the thread_struct */
+ for (i = 0; i < ELF_NVSRHALFREG; i++)
+ buf[i] = task->thread.transact_fpr[i][TS_VSRLOWOFFSET];
+ return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double));
+}
+
+unsigned long copy_transact_vsx_from_user(struct task_struct *task,
+ void __user *from)
+{
+ double buf[ELF_NVSRHALFREG];
+ int i;
+
+ if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double)))
+ return 1;
+ for (i = 0; i < ELF_NVSRHALFREG ; i++)
+ task->thread.transact_fpr[i][TS_VSRLOWOFFSET] = buf[i];
+ return 0;
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
#else
inline unsigned long copy_fpr_to_user(void __user *to,
struct task_struct *task)
@@ -395,6 +383,22 @@ inline unsigned long copy_fpr_from_user(struct task_struct *task,
return __copy_from_user(task->thread.fpr, from,
ELF_NFPREG * sizeof(double));
}
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+inline unsigned long copy_transact_fpr_to_user(void __user *to,
+ struct task_struct *task)
+{
+ return __copy_to_user(to, task->thread.transact_fpr,
+ ELF_NFPREG * sizeof(double));
+}
+
+inline unsigned long copy_transact_fpr_from_user(struct task_struct *task,
+ void __user *from)
+{
+ return __copy_from_user(task->thread.transact_fpr, from,
+ ELF_NFPREG * sizeof(double));
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
#endif
/*
@@ -483,6 +487,156 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
return 0;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Save the current user registers on the user stack.
+ * We only save the altivec/spe registers if the process has used
+ * altivec/spe instructions at some point.
+ * We also save the transactional registers to a second ucontext in the
+ * frame.
+ *
+ * See save_user_regs() and signal_64.c:setup_tm_sigcontexts().
+ */
+static int save_tm_user_regs(struct pt_regs *regs,
+ struct mcontext __user *frame,
+ struct mcontext __user *tm_frame, int sigret)
+{
+ unsigned long msr = regs->msr;
+
+ /* tm_reclaim rolls back all reg states, updating thread.ckpt_regs,
+ * thread.transact_fpr[], thread.transact_vr[], etc.
+ */
+ tm_enable();
+ tm_reclaim(&current->thread, msr, TM_CAUSE_SIGNAL);
+
+ /* Make sure floating point registers are stored in regs */
+ flush_fp_to_thread(current);
+
+ /* Save both sets of general registers */
+ if (save_general_regs(&current->thread.ckpt_regs, frame)
+ || save_general_regs(regs, tm_frame))
+ return 1;
+
+ /* Stash the top half of the 64bit MSR into the 32bit MSR word
+ * of the transactional mcontext. This way we have a backward-compatible
+ * MSR in the 'normal' (checkpointed) mcontext and additionally one can
+ * also look at what type of transaction (T or S) was active at the
+ * time of the signal.
+ */
+ if (__put_user((msr >> 32), &tm_frame->mc_gregs[PT_MSR]))
+ return 1;
+
+#ifdef CONFIG_ALTIVEC
+ /* save altivec registers */
+ if (current->thread.used_vr) {
+ flush_altivec_to_thread(current);
+ if (__copy_to_user(&frame->mc_vregs, current->thread.vr,
+ ELF_NVRREG * sizeof(vector128)))
+ return 1;
+ if (msr & MSR_VEC) {
+ if (__copy_to_user(&tm_frame->mc_vregs,
+ current->thread.transact_vr,
+ ELF_NVRREG * sizeof(vector128)))
+ return 1;
+ } else {
+ if (__copy_to_user(&tm_frame->mc_vregs,
+ current->thread.vr,
+ ELF_NVRREG * sizeof(vector128)))
+ return 1;
+ }
+
+ /* set MSR_VEC in the saved MSR value to indicate that
+ * frame->mc_vregs contains valid data
+ */
+ msr |= MSR_VEC;
+ }
+
+ /* We always copy to/from vrsave, it's 0 if we don't have or don't
+ * use altivec. Since VSCR only contains 32 bits saved in the least
+ * significant bits of a vector, we "cheat" and stuff VRSAVE in the
+ * most significant bits of that same vector. --BenH
+ */
+ if (__put_user(current->thread.vrsave,
+ (u32 __user *)&frame->mc_vregs[32]))
+ return 1;
+ if (msr & MSR_VEC) {
+ if (__put_user(current->thread.transact_vrsave,
+ (u32 __user *)&tm_frame->mc_vregs[32]))
+ return 1;
+ } else {
+ if (__put_user(current->thread.vrsave,
+ (u32 __user *)&tm_frame->mc_vregs[32]))
+ return 1;
+ }
+#endif /* CONFIG_ALTIVEC */
+
+ if (copy_fpr_to_user(&frame->mc_fregs, current))
+ return 1;
+ if (msr & MSR_FP) {
+ if (copy_transact_fpr_to_user(&tm_frame->mc_fregs, current))
+ return 1;
+ } else {
+ if (copy_fpr_to_user(&tm_frame->mc_fregs, current))
+ return 1;
+ }
+
+#ifdef CONFIG_VSX
+ /*
+ * Copy VSR 0-31 upper half from thread_struct to local
+ * buffer, then write that to userspace. Also set MSR_VSX in
+ * the saved MSR value to indicate that frame->mc_vregs
+ * contains valid data
+ */
+ if (current->thread.used_vsr) {
+ __giveup_vsx(current);
+ if (copy_vsx_to_user(&frame->mc_vsregs, current))
+ return 1;
+ if (msr & MSR_VSX) {
+ if (copy_transact_vsx_to_user(&tm_frame->mc_vsregs,
+ current))
+ return 1;
+ } else {
+ if (copy_vsx_to_user(&tm_frame->mc_vsregs, current))
+ return 1;
+ }
+
+ msr |= MSR_VSX;
+ }
+#endif /* CONFIG_VSX */
+#ifdef CONFIG_SPE
+ /* SPE regs are not checkpointed with TM, so this section is
+ * simply the same as in save_user_regs().
+ */
+ if (current->thread.used_spe) {
+ flush_spe_to_thread(current);
+ if (__copy_to_user(&frame->mc_vregs, current->thread.evr,
+ ELF_NEVRREG * sizeof(u32)))
+ return 1;
+ /* set MSR_SPE in the saved MSR value to indicate that
+ * frame->mc_vregs contains valid data */
+ msr |= MSR_SPE;
+ }
+
+ /* We always copy to/from spefscr */
+ if (__put_user(current->thread.spefscr, (u32 __user *)&frame->mc_vregs + ELF_NEVRREG))
+ return 1;
+#endif /* CONFIG_SPE */
+
+ if (__put_user(msr, &frame->mc_gregs[PT_MSR]))
+ return 1;
+ if (sigret) {
+ /* Set up the sigreturn trampoline: li r0,sigret; sc */
+ if (__put_user(0x38000000UL + sigret, &frame->tramp[0])
+ || __put_user(0x44000002UL, &frame->tramp[1]))
+ return 1;
+ flush_icache_range((unsigned long) &frame->tramp[0],
+ (unsigned long) &frame->tramp[2]);
+ }
+
+ return 0;
+}
+#endif
+
/*
* Restore the current user register values from the user stack,
* (except for MSR).
@@ -588,90 +742,140 @@ static long restore_user_regs(struct pt_regs *regs,
return 0;
}
-#ifdef CONFIG_PPC64
-long compat_sys_rt_sigaction(int sig, const struct sigaction32 __user *act,
- struct sigaction32 __user *oact, size_t sigsetsize)
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Restore the current user register values from the user stack, except for
+ * MSR, and recheckpoint the original checkpointed register state for processes
+ * in transactions.
+ */
+static long restore_tm_user_regs(struct pt_regs *regs,
+ struct mcontext __user *sr,
+ struct mcontext __user *tm_sr)
{
- struct k_sigaction new_ka, old_ka;
- int ret;
+ long err;
+ unsigned long msr;
+#ifdef CONFIG_VSX
+ int i;
+#endif
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(compat_sigset_t))
- return -EINVAL;
+ /*
+ * restore general registers but not including MSR or SOFTE. Also
+ * take care of keeping r2 (TLS) intact if not a signal.
+ * See comment in signal_64.c:restore_tm_sigcontexts();
+ * TFHAR is restored from the checkpointed NIP; TEXASR and TFIAR
+ * were set by the signal delivery.
+ */
+ err = restore_general_regs(regs, tm_sr);
+ err |= restore_general_regs(&current->thread.ckpt_regs, sr);
- if (act) {
- compat_uptr_t handler;
+ err |= __get_user(current->thread.tm_tfhar, &sr->mc_gregs[PT_NIP]);
- ret = get_user(handler, &act->sa_handler);
- new_ka.sa.sa_handler = compat_ptr(handler);
- ret |= get_sigset_t(&new_ka.sa.sa_mask, &act->sa_mask);
- ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- if (ret)
- return -EFAULT;
- }
+ err |= __get_user(msr, &sr->mc_gregs[PT_MSR]);
+ if (err)
+ return 1;
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
- if (!ret && oact) {
- ret = put_user(to_user_ptr(old_ka.sa.sa_handler), &oact->sa_handler);
- ret |= put_sigset_t(&oact->sa_mask, &old_ka.sa.sa_mask);
- ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- }
- return ret;
-}
+ /* Restore the previous little-endian mode */
+ regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
-/*
- * Note: it is necessary to treat how as an unsigned int, with the
- * corresponding cast to a signed int to insure that the proper
- * conversion (sign extension) between the register representation
- * of a signed int (msr in 32-bit mode) and the register representation
- * of a signed int (msr in 64-bit mode) is performed.
- */
-long compat_sys_rt_sigprocmask(u32 how, compat_sigset_t __user *set,
- compat_sigset_t __user *oset, size_t sigsetsize)
-{
- sigset_t s;
- sigset_t __user *up;
- int ret;
- mm_segment_t old_fs = get_fs();
+ /*
+ * Do this before updating the thread state in
+ * current->thread.fpr/vr/evr. That way, if we get preempted
+ * and another task grabs the FPU/Altivec/SPE, it won't be
+ * tempted to save the current CPU state into the thread_struct
+ * and corrupt what we are writing there.
+ */
+ discard_lazy_cpu_state();
- if (set) {
- if (get_sigset_t(&s, set))
- return -EFAULT;
+#ifdef CONFIG_ALTIVEC
+ regs->msr &= ~MSR_VEC;
+ if (msr & MSR_VEC) {
+ /* restore altivec registers from the stack */
+ if (__copy_from_user(current->thread.vr, &sr->mc_vregs,
+ sizeof(sr->mc_vregs)) ||
+ __copy_from_user(current->thread.transact_vr,
+ &tm_sr->mc_vregs,
+ sizeof(sr->mc_vregs)))
+ return 1;
+ } else if (current->thread.used_vr) {
+ memset(current->thread.vr, 0, ELF_NVRREG * sizeof(vector128));
+ memset(current->thread.transact_vr, 0,
+ ELF_NVRREG * sizeof(vector128));
}
- set_fs(KERNEL_DS);
- /* This is valid because of the set_fs() */
- up = (sigset_t __user *) &s;
- ret = sys_rt_sigprocmask((int)how, set ? up : NULL, oset ? up : NULL,
- sigsetsize);
- set_fs(old_fs);
- if (ret)
- return ret;
- if (oset) {
- if (put_sigset_t(oset, &s))
- return -EFAULT;
- }
- return 0;
-}
+ /* Always get VRSAVE back */
+ if (__get_user(current->thread.vrsave,
+ (u32 __user *)&sr->mc_vregs[32]) ||
+ __get_user(current->thread.transact_vrsave,
+ (u32 __user *)&tm_sr->mc_vregs[32]))
+ return 1;
+#endif /* CONFIG_ALTIVEC */
-long compat_sys_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize)
-{
- sigset_t s;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- /* The __user pointer cast is valid because of the set_fs() */
- ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
- set_fs(old_fs);
- if (!ret) {
- if (put_sigset_t(set, &s))
- return -EFAULT;
+ regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+
+ if (copy_fpr_from_user(current, &sr->mc_fregs) ||
+ copy_transact_fpr_from_user(current, &tm_sr->mc_fregs))
+ return 1;
+
+#ifdef CONFIG_VSX
+ regs->msr &= ~MSR_VSX;
+ if (msr & MSR_VSX) {
+ /*
+ * Restore altivec registers from the stack to a local
+ * buffer, then write this out to the thread_struct
+ */
+ if (copy_vsx_from_user(current, &sr->mc_vsregs) ||
+ copy_transact_vsx_from_user(current, &tm_sr->mc_vsregs))
+ return 1;
+ } else if (current->thread.used_vsr)
+ for (i = 0; i < 32 ; i++) {
+ current->thread.fpr[i][TS_VSRLOWOFFSET] = 0;
+ current->thread.transact_fpr[i][TS_VSRLOWOFFSET] = 0;
+ }
+#endif /* CONFIG_VSX */
+
+#ifdef CONFIG_SPE
+ /* SPE regs are not checkpointed with TM, so this section is
+ * simply the same as in restore_user_regs().
+ */
+ regs->msr &= ~MSR_SPE;
+ if (msr & MSR_SPE) {
+ if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
+ ELF_NEVRREG * sizeof(u32)))
+ return 1;
+ } else if (current->thread.used_spe)
+ memset(current->thread.evr, 0, ELF_NEVRREG * sizeof(u32));
+
+ /* Always get SPEFSCR back */
+ if (__get_user(current->thread.spefscr, (u32 __user *)&sr->mc_vregs
+ + ELF_NEVRREG))
+ return 1;
+#endif /* CONFIG_SPE */
+
+ /* Now, recheckpoint. This loads up all of the checkpointed (older)
+ * registers, including FP and V[S]Rs. After recheckpointing, the
+ * transactional versions should be loaded.
+ */
+ tm_enable();
+ /* This loads the checkpointed FP/VEC state, if used */
+ tm_recheckpoint(&current->thread, msr);
+ /* The task has moved into TM state S, so ensure MSR reflects this */
+ regs->msr = (regs->msr & ~MSR_TS_MASK) | MSR_TS_S;
+
+ /* This loads the speculative FP/VEC state, if used */
+ if (msr & MSR_FP) {
+ do_load_up_transact_fpu(&current->thread);
+ regs->msr |= (MSR_FP | current->thread.fpexc_mode);
+ }
+ if (msr & MSR_VEC) {
+ do_load_up_transact_altivec(&current->thread);
+ regs->msr |= MSR_VEC;
}
- return ret;
-}
+ return 0;
+}
+#endif
+#ifdef CONFIG_PPC64
int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s)
{
int err;
@@ -740,79 +944,6 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
return 0;
}
-
-/*
- * Note: it is necessary to treat pid and sig as unsigned ints, with the
- * corresponding cast to a signed int to insure that the proper conversion
- * (sign extension) between the register representation of a signed int
- * (msr in 32-bit mode) and the register representation of a signed int
- * (msr in 64-bit mode) is performed.
- */
-long compat_sys_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo)
-{
- siginfo_t info;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- ret = copy_siginfo_from_user32(&info, uinfo);
- if (unlikely(ret))
- return ret;
-
- set_fs (KERNEL_DS);
- /* The __user pointer cast is valid becasuse of the set_fs() */
- ret = sys_rt_sigqueueinfo((int)pid, (int)sig, (siginfo_t __user *) &info);
- set_fs (old_fs);
- return ret;
-}
-/*
- * Start Alternate signal stack support
- *
- * System Calls
- * sigaltatck compat_sys_sigaltstack
- */
-
-int compat_sys_sigaltstack(u32 __new, u32 __old, int r5,
- int r6, int r7, int r8, struct pt_regs *regs)
-{
- stack_32_t __user * newstack = compat_ptr(__new);
- stack_32_t __user * oldstack = compat_ptr(__old);
- stack_t uss, uoss;
- int ret;
- mm_segment_t old_fs;
- unsigned long sp;
- compat_uptr_t ss_sp;
-
- /*
- * set sp to the user stack on entry to the system call
- * the system call router sets R9 to the saved registers
- */
- sp = regs->gpr[1];
-
- /* Put new stack info in local 64 bit stack struct */
- if (newstack) {
- if (get_user(ss_sp, &newstack->ss_sp) ||
- __get_user(uss.ss_flags, &newstack->ss_flags) ||
- __get_user(uss.ss_size, &newstack->ss_size))
- return -EFAULT;
- uss.ss_sp = compat_ptr(ss_sp);
- }
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- /* The __user pointer casts are valid because of the set_fs() */
- ret = do_sigaltstack(
- newstack ? (stack_t __user *) &uss : NULL,
- oldstack ? (stack_t __user *) &uoss : NULL,
- sp);
- set_fs(old_fs);
- /* Copy the stack information to the user output buffer */
- if (!ret && oldstack &&
- (put_user(ptr_to_compat(uoss.ss_sp), &oldstack->ss_sp) ||
- __put_user(uoss.ss_flags, &oldstack->ss_flags) ||
- __put_user(uoss.ss_size, &oldstack->ss_size)))
- return -EFAULT;
- return ret;
-}
#endif /* CONFIG_PPC64 */
/*
@@ -827,6 +958,8 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
struct mcontext __user *frame;
void __user *addr;
unsigned long newsp = 0;
+ int sigret;
+ unsigned long tramp;
/* Set up Signal Frame */
/* Put a Real Time Context onto stack */
@@ -838,11 +971,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
/* Put the siginfo & fill in most of the ucontext */
if (copy_siginfo_to_user(&rt_sf->info, info)
|| __put_user(0, &rt_sf->uc.uc_flags)
- || __put_user(0, &rt_sf->uc.uc_link)
- || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
- || __put_user(sas_ss_flags(regs->gpr[1]),
- &rt_sf->uc.uc_stack.ss_flags)
- || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
+ || __save_altstack(&rt_sf->uc.uc_stack, regs->gpr[1])
|| __put_user(to_user_ptr(&rt_sf->uc.uc_mcontext),
&rt_sf->uc.uc_regs)
|| put_sigset_t(&rt_sf->uc.uc_sigmask, oldset))
@@ -852,14 +981,37 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
frame = &rt_sf->uc.uc_mcontext;
addr = frame;
if (vdso32_rt_sigtramp && current->mm->context.vdso_base) {
- if (save_user_regs(regs, frame, 0, 1))
- goto badframe;
- regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp;
+ sigret = 0;
+ tramp = current->mm->context.vdso_base + vdso32_rt_sigtramp;
} else {
- if (save_user_regs(regs, frame, __NR_rt_sigreturn, 1))
+ sigret = __NR_rt_sigreturn;
+ tramp = (unsigned long) frame->tramp;
+ }
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (MSR_TM_ACTIVE(regs->msr)) {
+ if (save_tm_user_regs(regs, &rt_sf->uc.uc_mcontext,
+ &rt_sf->uc_transact.uc_mcontext, sigret))
+ goto badframe;
+ }
+ else
+#endif
+ if (save_user_regs(regs, frame, sigret, 1))
+ goto badframe;
+ regs->link = tramp;
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (MSR_TM_ACTIVE(regs->msr)) {
+ if (__put_user((unsigned long)&rt_sf->uc_transact,
+ &rt_sf->uc.uc_link)
+ || __put_user(to_user_ptr(&rt_sf->uc_transact.uc_mcontext),
+ &rt_sf->uc_transact.uc_regs))
goto badframe;
- regs->link = (unsigned long) frame->tramp;
}
+ else
+#endif
+ if (__put_user(0, &rt_sf->uc.uc_link))
+ goto badframe;
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
@@ -878,6 +1030,13 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
regs->nip = (unsigned long) ka->sa.sa_handler;
/* enter the signal handler in big-endian mode */
regs->msr &= ~MSR_LE;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ /* Remove TM bits from thread's MSR. The MSR in the sigcontext
+ * just indicates to userland that we were doing a transaction, but we
+ * don't want to return in transactional state:
+ */
+ regs->msr &= ~MSR_TS_MASK;
+#endif
return 1;
badframe:
@@ -925,6 +1084,35 @@ static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int
return 0;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static int do_setcontext_tm(struct ucontext __user *ucp,
+ struct ucontext __user *tm_ucp,
+ struct pt_regs *regs)
+{
+ sigset_t set;
+ struct mcontext __user *mcp;
+ struct mcontext __user *tm_mcp;
+ u32 cmcp;
+ u32 tm_cmcp;
+
+ if (get_sigset_t(&set, &ucp->uc_sigmask))
+ return -EFAULT;
+
+ if (__get_user(cmcp, &ucp->uc_regs) ||
+ __get_user(tm_cmcp, &tm_ucp->uc_regs))
+ return -EFAULT;
+ mcp = (struct mcontext __user *)(u64)cmcp;
+ tm_mcp = (struct mcontext __user *)(u64)tm_cmcp;
+ /* no need to check access_ok(mcp), since mcp < 4GB */
+
+ set_current_blocked(&set);
+ if (restore_tm_user_regs(regs, mcp, tm_mcp))
+ return -EFAULT;
+
+ return 0;
+}
+#endif
+
long sys_swapcontext(struct ucontext __user *old_ctx,
struct ucontext __user *new_ctx,
int ctx_size, int r6, int r7, int r8, struct pt_regs *regs)
@@ -1020,7 +1208,12 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
struct pt_regs *regs)
{
struct rt_sigframe __user *rt_sf;
-
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ struct ucontext __user *uc_transact;
+ unsigned long msr_hi;
+ unsigned long tmp;
+ int tm_restore = 0;
+#endif
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
@@ -1028,6 +1221,34 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
(regs->gpr[1] + __SIGNAL_FRAMESIZE + 16);
if (!access_ok(VERIFY_READ, rt_sf, sizeof(*rt_sf)))
goto bad;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (__get_user(tmp, &rt_sf->uc.uc_link))
+ goto bad;
+ uc_transact = (struct ucontext __user *)(uintptr_t)tmp;
+ if (uc_transact) {
+ u32 cmcp;
+ struct mcontext __user *mcp;
+
+ if (__get_user(cmcp, &uc_transact->uc_regs))
+ return -EFAULT;
+ mcp = (struct mcontext __user *)(u64)cmcp;
+ /* The top 32 bits of the MSR are stashed in the transactional
+ * ucontext. */
+ if (__get_user(msr_hi, &mcp->mc_gregs[PT_MSR]))
+ goto bad;
+
+ if (MSR_TM_SUSPENDED(msr_hi<<32)) {
+ /* We only recheckpoint on return if we're
+ * transaction.
+ */
+ tm_restore = 1;
+ if (do_setcontext_tm(&rt_sf->uc, uc_transact, regs))
+ goto bad;
+ }
+ }
+ if (!tm_restore)
+ /* Fall through, for non-TM restore */
+#endif
if (do_setcontext(&rt_sf->uc, regs, 1))
goto bad;
@@ -1039,14 +1260,11 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
* change it. -- paulus
*/
#ifdef CONFIG_PPC64
- /*
- * We use the compat_sys_ version that does the 32/64 bits conversion
- * and takes userland pointer directly. What about error checking ?
- * nobody does any...
- */
- compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs);
+ if (compat_restore_altstack(&rt_sf->uc.uc_stack))
+ goto bad;
#else
- do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]);
+ if (restore_altstack(&rt_sf->uc.uc_stack))
+ goto bad;
#endif
set_thread_flag(TIF_RESTOREALL);
return 0;
@@ -1162,7 +1380,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
* always done it up until now so it is probably better not to
* change it. -- paulus
*/
- do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]);
+ restore_altstack(&ctx->uc_stack);
set_thread_flag(TIF_RESTOREALL);
out:
@@ -1179,6 +1397,8 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
struct sigcontext __user *sc;
struct sigframe __user *frame;
unsigned long newsp = 0;
+ int sigret;
+ unsigned long tramp;
/* Set up Signal Frame */
frame = get_sigframe(ka, regs, sizeof(*frame), 1);
@@ -1201,14 +1421,25 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
goto badframe;
if (vdso32_sigtramp && current->mm->context.vdso_base) {
- if (save_user_regs(regs, &frame->mctx, 0, 1))
- goto badframe;
- regs->link = current->mm->context.vdso_base + vdso32_sigtramp;
+ sigret = 0;
+ tramp = current->mm->context.vdso_base + vdso32_sigtramp;
} else {
- if (save_user_regs(regs, &frame->mctx, __NR_sigreturn, 1))
+ sigret = __NR_sigreturn;
+ tramp = (unsigned long) frame->mctx.tramp;
+ }
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (MSR_TM_ACTIVE(regs->msr)) {
+ if (save_tm_user_regs(regs, &frame->mctx, &frame->mctx_transact,
+ sigret))
goto badframe;
- regs->link = (unsigned long) frame->mctx.tramp;
}
+ else
+#endif
+ if (save_user_regs(regs, &frame->mctx, sigret, 1))
+ goto badframe;
+
+ regs->link = tramp;
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
@@ -1223,7 +1454,13 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
regs->nip = (unsigned long) ka->sa.sa_handler;
/* enter the signal handler in big-endian mode */
regs->msr &= ~MSR_LE;
-
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ /* Remove TM bits from thread's MSR. The MSR in the sigcontext
+ * just indicates to userland that we were doing a transaction, but we
+ * don't want to return in transactional state:
+ */
+ regs->msr &= ~MSR_TS_MASK;
+#endif
return 1;
badframe:
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 1ca045d44324..995f8543cb57 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -34,6 +34,7 @@
#include <asm/syscalls.h>
#include <asm/vdso.h>
#include <asm/switch_to.h>
+#include <asm/tm.h>
#include "signal.h"
@@ -56,6 +57,9 @@
struct rt_sigframe {
/* sys_rt_sigreturn requires the ucontext be the first field */
struct ucontext uc;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ struct ucontext uc_transact;
+#endif
unsigned long _unused[2];
unsigned int tramp[TRAMP_SIZE];
struct siginfo __user *pinfo;
@@ -145,6 +149,145 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
return err;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * As above, but Transactional Memory is in use, so deliver sigcontexts
+ * containing checkpointed and transactional register states.
+ *
+ * To do this, we treclaim to gather both sets of registers and set up the
+ * 'normal' sigcontext registers with rolled-back register values such that a
+ * simple signal handler sees a correct checkpointed register state.
+ * If interested, a TM-aware sighandler can examine the transactional registers
+ * in the 2nd sigcontext to determine the real origin of the signal.
+ */
+static long setup_tm_sigcontexts(struct sigcontext __user *sc,
+ struct sigcontext __user *tm_sc,
+ struct pt_regs *regs,
+ int signr, sigset_t *set, unsigned long handler)
+{
+ /* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the
+ * process never used altivec yet (MSR_VEC is zero in pt_regs of
+ * the context). This is very important because we must ensure we
+ * don't lose the VRSAVE content that may have been set prior to
+ * the process doing its first vector operation
+ * Userland shall check AT_HWCAP to know wether it can rely on the
+ * v_regs pointer or not.
+ */
+#ifdef CONFIG_ALTIVEC
+ elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)
+ (((unsigned long)sc->vmx_reserve + 15) & ~0xful);
+ elf_vrreg_t __user *tm_v_regs = (elf_vrreg_t __user *)
+ (((unsigned long)tm_sc->vmx_reserve + 15) & ~0xful);
+#endif
+ unsigned long msr = regs->msr;
+ long err = 0;
+
+ BUG_ON(!MSR_TM_ACTIVE(regs->msr));
+
+ /* tm_reclaim rolls back all reg states, saving checkpointed (older)
+ * GPRs to thread.ckpt_regs and (if used) FPRs to (newer)
+ * thread.transact_fp and/or VRs to (newer) thread.transact_vr.
+ * THEN we save out FP/VRs, if necessary, to the checkpointed (older)
+ * thread.fr[]/vr[]s. The transactional (newer) GPRs are on the
+ * stack, in *regs.
+ */
+ tm_enable();
+ tm_reclaim(&current->thread, msr, TM_CAUSE_SIGNAL);
+
+ flush_fp_to_thread(current);
+
+#ifdef CONFIG_ALTIVEC
+ err |= __put_user(v_regs, &sc->v_regs);
+ err |= __put_user(tm_v_regs, &tm_sc->v_regs);
+
+ /* save altivec registers */
+ if (current->thread.used_vr) {
+ flush_altivec_to_thread(current);
+ /* Copy 33 vec registers (vr0..31 and vscr) to the stack */
+ err |= __copy_to_user(v_regs, current->thread.vr,
+ 33 * sizeof(vector128));
+ /* If VEC was enabled there are transactional VRs valid too,
+ * else they're a copy of the checkpointed VRs.
+ */
+ if (msr & MSR_VEC)
+ err |= __copy_to_user(tm_v_regs,
+ current->thread.transact_vr,
+ 33 * sizeof(vector128));
+ else
+ err |= __copy_to_user(tm_v_regs,
+ current->thread.vr,
+ 33 * sizeof(vector128));
+
+ /* set MSR_VEC in the MSR value in the frame to indicate
+ * that sc->v_reg contains valid data.
+ */
+ msr |= MSR_VEC;
+ }
+ /* We always copy to/from vrsave, it's 0 if we don't have or don't
+ * use altivec.
+ */
+ err |= __put_user(current->thread.vrsave, (u32 __user *)&v_regs[33]);
+ if (msr & MSR_VEC)
+ err |= __put_user(current->thread.transact_vrsave,
+ (u32 __user *)&tm_v_regs[33]);
+ else
+ err |= __put_user(current->thread.vrsave,
+ (u32 __user *)&tm_v_regs[33]);
+
+#else /* CONFIG_ALTIVEC */
+ err |= __put_user(0, &sc->v_regs);
+ err |= __put_user(0, &tm_sc->v_regs);
+#endif /* CONFIG_ALTIVEC */
+
+ /* copy fpr regs and fpscr */
+ err |= copy_fpr_to_user(&sc->fp_regs, current);
+ if (msr & MSR_FP)
+ err |= copy_transact_fpr_to_user(&tm_sc->fp_regs, current);
+ else
+ err |= copy_fpr_to_user(&tm_sc->fp_regs, current);
+
+#ifdef CONFIG_VSX
+ /*
+ * Copy VSX low doubleword to local buffer for formatting,
+ * then out to userspace. Update v_regs to point after the
+ * VMX data.
+ */
+ if (current->thread.used_vsr) {
+ __giveup_vsx(current);
+ v_regs += ELF_NVRREG;
+ tm_v_regs += ELF_NVRREG;
+
+ err |= copy_vsx_to_user(v_regs, current);
+
+ if (msr & MSR_VSX)
+ err |= copy_transact_vsx_to_user(tm_v_regs, current);
+ else
+ err |= copy_vsx_to_user(tm_v_regs, current);
+
+ /* set MSR_VSX in the MSR value in the frame to
+ * indicate that sc->vs_reg) contains valid data.
+ */
+ msr |= MSR_VSX;
+ }
+#endif /* CONFIG_VSX */
+
+ err |= __put_user(&sc->gp_regs, &sc->regs);
+ err |= __put_user(&tm_sc->gp_regs, &tm_sc->regs);
+ WARN_ON(!FULL_REGS(regs));
+ err |= __copy_to_user(&tm_sc->gp_regs, regs, GP_REGS_SIZE);
+ err |= __copy_to_user(&sc->gp_regs,
+ &current->thread.ckpt_regs, GP_REGS_SIZE);
+ err |= __put_user(msr, &tm_sc->gp_regs[PT_MSR]);
+ err |= __put_user(msr, &sc->gp_regs[PT_MSR]);
+ err |= __put_user(signr, &sc->signal);
+ err |= __put_user(handler, &sc->handler);
+ if (set != NULL)
+ err |= __put_user(set->sig[0], &sc->oldmask);
+
+ return err;
+}
+#endif
+
/*
* Restore the sigcontext from the signal frame.
*/
@@ -241,6 +384,153 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
return err;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Restore the two sigcontexts from the frame of a transactional processes.
+ */
+
+static long restore_tm_sigcontexts(struct pt_regs *regs,
+ struct sigcontext __user *sc,
+ struct sigcontext __user *tm_sc)
+{
+#ifdef CONFIG_ALTIVEC
+ elf_vrreg_t __user *v_regs, *tm_v_regs;
+#endif
+ unsigned long err = 0;
+ unsigned long msr;
+#ifdef CONFIG_VSX
+ int i;
+#endif
+ /* copy the GPRs */
+ err |= __copy_from_user(regs->gpr, tm_sc->gp_regs, sizeof(regs->gpr));
+ err |= __copy_from_user(&current->thread.ckpt_regs, sc->gp_regs,
+ sizeof(regs->gpr));
+
+ /*
+ * TFHAR is restored from the checkpointed 'wound-back' ucontext's NIP.
+ * TEXASR was set by the signal delivery reclaim, as was TFIAR.
+ * Users doing anything abhorrent like thread-switching w/ signals for
+ * TM-Suspended code will have to back TEXASR/TFIAR up themselves.
+ * For the case of getting a signal and simply returning from it,
+ * we don't need to re-copy them here.
+ */
+ err |= __get_user(regs->nip, &tm_sc->gp_regs[PT_NIP]);
+ err |= __get_user(current->thread.tm_tfhar, &sc->gp_regs[PT_NIP]);
+
+ /* get MSR separately, transfer the LE bit if doing signal return */
+ err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
+ regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
+
+ /* The following non-GPR non-FPR non-VR state is also checkpointed: */
+ err |= __get_user(regs->ctr, &tm_sc->gp_regs[PT_CTR]);
+ err |= __get_user(regs->link, &tm_sc->gp_regs[PT_LNK]);
+ err |= __get_user(regs->xer, &tm_sc->gp_regs[PT_XER]);
+ err |= __get_user(regs->ccr, &tm_sc->gp_regs[PT_CCR]);
+ err |= __get_user(current->thread.ckpt_regs.ctr,
+ &sc->gp_regs[PT_CTR]);
+ err |= __get_user(current->thread.ckpt_regs.link,
+ &sc->gp_regs[PT_LNK]);
+ err |= __get_user(current->thread.ckpt_regs.xer,
+ &sc->gp_regs[PT_XER]);
+ err |= __get_user(current->thread.ckpt_regs.ccr,
+ &sc->gp_regs[PT_CCR]);
+
+ /* These regs are not checkpointed; they can go in 'regs'. */
+ err |= __get_user(regs->trap, &sc->gp_regs[PT_TRAP]);
+ err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]);
+ err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]);
+ err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]);
+
+ /*
+ * Do this before updating the thread state in
+ * current->thread.fpr/vr. That way, if we get preempted
+ * and another task grabs the FPU/Altivec, it won't be
+ * tempted to save the current CPU state into the thread_struct
+ * and corrupt what we are writing there.
+ */
+ discard_lazy_cpu_state();
+
+ /*
+ * Force reload of FP/VEC.
+ * This has to be done before copying stuff into current->thread.fpr/vr
+ * for the reasons explained in the previous comment.
+ */
+ regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC | MSR_VSX);
+
+#ifdef CONFIG_ALTIVEC
+ err |= __get_user(v_regs, &sc->v_regs);
+ err |= __get_user(tm_v_regs, &tm_sc->v_regs);
+ if (err)
+ return err;
+ if (v_regs && !access_ok(VERIFY_READ, v_regs, 34 * sizeof(vector128)))
+ return -EFAULT;
+ if (tm_v_regs && !access_ok(VERIFY_READ,
+ tm_v_regs, 34 * sizeof(vector128)))
+ return -EFAULT;
+ /* Copy 33 vec registers (vr0..31 and vscr) from the stack */
+ if (v_regs != 0 && tm_v_regs != 0 && (msr & MSR_VEC) != 0) {
+ err |= __copy_from_user(current->thread.vr, v_regs,
+ 33 * sizeof(vector128));
+ err |= __copy_from_user(current->thread.transact_vr, tm_v_regs,
+ 33 * sizeof(vector128));
+ }
+ else if (current->thread.used_vr) {
+ memset(current->thread.vr, 0, 33 * sizeof(vector128));
+ memset(current->thread.transact_vr, 0, 33 * sizeof(vector128));
+ }
+ /* Always get VRSAVE back */
+ if (v_regs != 0 && tm_v_regs != 0) {
+ err |= __get_user(current->thread.vrsave,
+ (u32 __user *)&v_regs[33]);
+ err |= __get_user(current->thread.transact_vrsave,
+ (u32 __user *)&tm_v_regs[33]);
+ }
+ else {
+ current->thread.vrsave = 0;
+ current->thread.transact_vrsave = 0;
+ }
+#endif /* CONFIG_ALTIVEC */
+ /* restore floating point */
+ err |= copy_fpr_from_user(current, &sc->fp_regs);
+ err |= copy_transact_fpr_from_user(current, &tm_sc->fp_regs);
+#ifdef CONFIG_VSX
+ /*
+ * Get additional VSX data. Update v_regs to point after the
+ * VMX data. Copy VSX low doubleword from userspace to local
+ * buffer for formatting, then into the taskstruct.
+ */
+ if (v_regs && ((msr & MSR_VSX) != 0)) {
+ v_regs += ELF_NVRREG;
+ tm_v_regs += ELF_NVRREG;
+ err |= copy_vsx_from_user(current, v_regs);
+ err |= copy_transact_vsx_from_user(current, tm_v_regs);
+ } else {
+ for (i = 0; i < 32 ; i++) {
+ current->thread.fpr[i][TS_VSRLOWOFFSET] = 0;
+ current->thread.transact_fpr[i][TS_VSRLOWOFFSET] = 0;
+ }
+ }
+#endif
+ tm_enable();
+ /* This loads the checkpointed FP/VEC state, if used */
+ tm_recheckpoint(&current->thread, msr);
+ /* The task has moved into TM state S, so ensure MSR reflects this: */
+ regs->msr = (regs->msr & ~MSR_TS_MASK) | __MASK(33);
+
+ /* This loads the speculative FP/VEC state, if used */
+ if (msr & MSR_FP) {
+ do_load_up_transact_fpu(&current->thread);
+ regs->msr |= (MSR_FP | current->thread.fpexc_mode);
+ }
+ if (msr & MSR_VEC) {
+ do_load_up_transact_altivec(&current->thread);
+ regs->msr |= MSR_VEC;
+ }
+
+ return err;
+}
+#endif
+
/*
* Setup the trampoline code on the stack
*/
@@ -355,6 +645,9 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
{
struct ucontext __user *uc = (struct ucontext __user *)regs->gpr[1];
sigset_t set;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ unsigned long msr;
+#endif
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
@@ -365,13 +658,26 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
goto badframe;
set_current_blocked(&set);
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (__get_user(msr, &uc->uc_mcontext.gp_regs[PT_MSR]))
+ goto badframe;
+ if (MSR_TM_SUSPENDED(msr)) {
+ /* We recheckpoint on return. */
+ struct ucontext __user *uc_transact;
+ if (__get_user(uc_transact, &uc->uc_link))
+ goto badframe;
+ if (restore_tm_sigcontexts(regs, &uc->uc_mcontext,
+ &uc_transact->uc_mcontext))
+ goto badframe;
+ }
+ else
+ /* Fall through, for non-TM restore */
+#endif
if (restore_sigcontext(regs, NULL, 1, &uc->uc_mcontext))
goto badframe;
- /* do_sigaltstack expects a __user pointer and won't modify
- * what's in there anyway
- */
- do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]);
+ if (restore_altstack(&uc->uc_stack))
+ goto badframe;
set_thread_flag(TIF_RESTOREALL);
return 0;
@@ -415,19 +721,39 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
- err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->gpr[1]),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
- err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL,
- (unsigned long)ka->sa.sa_handler, 1);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->gpr[1]);
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (MSR_TM_ACTIVE(regs->msr)) {
+ /* The ucontext_t passed to userland points to the second
+ * ucontext_t (for transactional state) with its uc_link ptr.
+ */
+ err |= __put_user(&frame->uc_transact, &frame->uc.uc_link);
+ err |= setup_tm_sigcontexts(&frame->uc.uc_mcontext,
+ &frame->uc_transact.uc_mcontext,
+ regs, signr,
+ NULL,
+ (unsigned long)ka->sa.sa_handler);
+ } else
+#endif
+ {
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr,
+ NULL, (unsigned long)ka->sa.sa_handler,
+ 1);
+ }
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
goto badframe;
/* Make sure signal handler doesn't get spurious FP exceptions */
current->thread.fpscr.val = 0;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ /* Remove TM bits from thread's MSR. The MSR in the sigcontext
+ * just indicates to userland that we were doing a transaction, but we
+ * don't want to return in transactional state:
+ */
+ regs->msr &= ~MSR_TS_MASK;
+#endif
/* Set up to return from userspace. */
if (vdso64_rt_sigtramp && current->mm->context.vdso_base) {
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 793401e65088..76bd9da8cb71 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -610,7 +610,7 @@ static struct device_node *cpu_to_l2cache(int cpu)
}
/* Activate a secondary processor. */
-void start_secondary(void *unused)
+__cpuinit void start_secondary(void *unused)
{
unsigned int cpu = smp_processor_id();
struct device_node *l2_cache;
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index 8a93778ed9f5..dbc44ba5b078 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -61,16 +61,6 @@ asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
return compat_sys_select((int)n, inp, outp, exp, compat_ptr(tvp_x));
}
-/* Note: it is necessary to treat option as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_sysfs(u32 option, u32 arg1, u32 arg2)
-{
- return sys_sysfs((int)option, arg1, arg2);
-}
-
#ifdef CONFIG_SYSVIPC
long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr,
u32 fifth)
@@ -156,125 +146,6 @@ asmlinkage long compat_sys_sendfile64_wrapper(u32 out_fd, u32 in_fd,
(off_t __user *)offset, count);
}
-/* Note: it is necessary to treat option as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
-{
- return sys_prctl((int)option,
- (unsigned long) arg2,
- (unsigned long) arg3,
- (unsigned long) arg4,
- (unsigned long) arg5);
-}
-
-/* Note: it is necessary to treat pid as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_sched_rr_get_interval_wrapper(u32 pid,
- struct compat_timespec __user *interval)
-{
- return compat_sys_sched_rr_get_interval((int)pid, interval);
-}
-
-/* Note: it is necessary to treat mode as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_access(const char __user * filename, u32 mode)
-{
- return sys_access(filename, (int)mode);
-}
-
-
-/* Note: it is necessary to treat mode as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_creat(const char __user * pathname, u32 mode)
-{
- return sys_creat(pathname, (int)mode);
-}
-
-
-/* Note: it is necessary to treat pid and options as unsigned ints,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_waitpid(u32 pid, unsigned int __user * stat_addr, u32 options)
-{
- return sys_waitpid((int)pid, stat_addr, (int)options);
-}
-
-
-/* Note: it is necessary to treat gidsetsize as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_getgroups(u32 gidsetsize, gid_t __user *grouplist)
-{
- return sys_getgroups((int)gidsetsize, grouplist);
-}
-
-
-/* Note: it is necessary to treat pid as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_getpgid(u32 pid)
-{
- return sys_getpgid((int)pid);
-}
-
-
-
-/* Note: it is necessary to treat pid as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_getsid(u32 pid)
-{
- return sys_getsid((int)pid);
-}
-
-
-/* Note: it is necessary to treat pid and sig as unsigned ints,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_kill(u32 pid, u32 sig)
-{
- return sys_kill((int)pid, (int)sig);
-}
-
-
-/* Note: it is necessary to treat mode as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_mkdir(const char __user * pathname, u32 mode)
-{
- return sys_mkdir(pathname, (int)mode);
-}
-
-long compat_sys_nice(u32 increment)
-{
- /* sign extend increment */
- return sys_nice((int)increment);
-}
-
off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin)
{
/* sign extend n */
@@ -293,172 +164,6 @@ long compat_sys_ftruncate(int fd, u32 length)
return sys_ftruncate(fd, (int)length);
}
-/* Note: it is necessary to treat bufsiz as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_readlink(const char __user * path, char __user * buf, u32 bufsiz)
-{
- return sys_readlink(path, buf, (int)bufsiz);
-}
-
-/* Note: it is necessary to treat option as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_sched_get_priority_max(u32 policy)
-{
- return sys_sched_get_priority_max((int)policy);
-}
-
-
-/* Note: it is necessary to treat policy as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_sched_get_priority_min(u32 policy)
-{
- return sys_sched_get_priority_min((int)policy);
-}
-
-
-/* Note: it is necessary to treat pid as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_sched_getparam(u32 pid, struct sched_param __user *param)
-{
- return sys_sched_getparam((int)pid, param);
-}
-
-
-/* Note: it is necessary to treat pid as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_sched_getscheduler(u32 pid)
-{
- return sys_sched_getscheduler((int)pid);
-}
-
-
-/* Note: it is necessary to treat pid as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_sched_setparam(u32 pid, struct sched_param __user *param)
-{
- return sys_sched_setparam((int)pid, param);
-}
-
-
-/* Note: it is necessary to treat pid and policy as unsigned ints,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_sched_setscheduler(u32 pid, u32 policy, struct sched_param __user *param)
-{
- return sys_sched_setscheduler((int)pid, (int)policy, param);
-}
-
-
-/* Note: it is necessary to treat len as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_setdomainname(char __user *name, u32 len)
-{
- return sys_setdomainname(name, (int)len);
-}
-
-
-/* Note: it is necessary to treat gidsetsize as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_setgroups(u32 gidsetsize, gid_t __user *grouplist)
-{
- return sys_setgroups((int)gidsetsize, grouplist);
-}
-
-
-asmlinkage long compat_sys_sethostname(char __user *name, u32 len)
-{
- /* sign extend len */
- return sys_sethostname(name, (int)len);
-}
-
-
-/* Note: it is necessary to treat pid and pgid as unsigned ints,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_setpgid(u32 pid, u32 pgid)
-{
- return sys_setpgid((int)pid, (int)pgid);
-}
-
-long compat_sys_getpriority(u32 which, u32 who)
-{
- /* sign extend which and who */
- return sys_getpriority((int)which, (int)who);
-}
-
-long compat_sys_setpriority(u32 which, u32 who, u32 niceval)
-{
- /* sign extend which, who and niceval */
- return sys_setpriority((int)which, (int)who, (int)niceval);
-}
-
-long compat_sys_ioprio_get(u32 which, u32 who)
-{
- /* sign extend which and who */
- return sys_ioprio_get((int)which, (int)who);
-}
-
-long compat_sys_ioprio_set(u32 which, u32 who, u32 ioprio)
-{
- /* sign extend which, who and ioprio */
- return sys_ioprio_set((int)which, (int)who, (int)ioprio);
-}
-
-/* Note: it is necessary to treat newmask as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_ssetmask(u32 newmask)
-{
- return sys_ssetmask((int) newmask);
-}
-
-asmlinkage long compat_sys_syslog(u32 type, char __user * buf, u32 len)
-{
- /* sign extend len */
- return sys_syslog(type, buf, (int)len);
-}
-
-
-/* Note: it is necessary to treat mask as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_umask(u32 mask)
-{
- return sys_umask((int)mask);
-}
-
unsigned long compat_sys_mmap2(unsigned long addr, size_t len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff)
@@ -467,12 +172,6 @@ unsigned long compat_sys_mmap2(unsigned long addr, size_t len,
return sys_mmap(addr, len, prot, flags, fd, pgoff << 12);
}
-long compat_sys_tgkill(u32 tgid, u32 pid, int sig)
-{
- /* sign extend tgid, pid */
- return sys_tgkill((int)tgid, (int)pid, sig);
-}
-
/*
* long long munging:
* The 32 bit ABI passes long longs in an odd even register pair.
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 127361e093f4..f77fa22754bc 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -143,7 +143,7 @@ EXPORT_SYMBOL_GPL(ppc_proc_freq);
unsigned long ppc_tb_freq;
EXPORT_SYMBOL_GPL(ppc_tb_freq);
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
/*
* Factors for converting from cputime_t (timebase ticks) to
* jiffies, microseconds, seconds, and clock_t (1/USER_HZ seconds).
@@ -347,6 +347,7 @@ void vtime_account_system(struct task_struct *tsk)
if (stolen)
account_steal_time(stolen);
}
+EXPORT_SYMBOL_GPL(vtime_account_system);
void vtime_account_idle(struct task_struct *tsk)
{
@@ -377,7 +378,7 @@ void vtime_account_user(struct task_struct *tsk)
account_user_time(tsk, utime, utimescaled);
}
-#else /* ! CONFIG_VIRT_CPU_ACCOUNTING */
+#else /* ! CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
#define calc_cputime_factors()
#endif
@@ -668,7 +669,7 @@ int update_persistent_clock(struct timespec now)
struct rtc_time tm;
if (!ppc_md.set_rtc_time)
- return 0;
+ return -ENODEV;
to_tm(now.tv_sec + 1 + timezone_offset, &tm);
tm.tm_year -= 1900;
diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
new file mode 100644
index 000000000000..84dbace657ce
--- /dev/null
+++ b/arch/powerpc/kernel/tm.S
@@ -0,0 +1,388 @@
+/*
+ * Transactional memory support routines to reclaim and recheckpoint
+ * transactional process state.
+ *
+ * Copyright 2012 Matt Evans & Michael Neuling, IBM Corporation.
+ */
+
+#include <asm/asm-offsets.h>
+#include <asm/ppc_asm.h>
+#include <asm/ppc-opcode.h>
+#include <asm/ptrace.h>
+#include <asm/reg.h>
+
+#ifdef CONFIG_VSX
+/* See fpu.S, this is very similar but to save/restore checkpointed FPRs/VSRs */
+#define __SAVE_32FPRS_VSRS_TRANSACT(n,c,base) \
+BEGIN_FTR_SECTION \
+ b 2f; \
+END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
+ SAVE_32FPRS_TRANSACT(n,base); \
+ b 3f; \
+2: SAVE_32VSRS_TRANSACT(n,c,base); \
+3:
+/* ...and this is just plain borrowed from there. */
+#define __REST_32FPRS_VSRS(n,c,base) \
+BEGIN_FTR_SECTION \
+ b 2f; \
+END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
+ REST_32FPRS(n,base); \
+ b 3f; \
+2: REST_32VSRS(n,c,base); \
+3:
+#else
+#define __SAVE_32FPRS_VSRS_TRANSACT(n,c,base) SAVE_32FPRS_TRANSACT(n, base)
+#define __REST_32FPRS_VSRS(n,c,base) REST_32FPRS(n, base)
+#endif
+#define SAVE_32FPRS_VSRS_TRANSACT(n,c,base) \
+ __SAVE_32FPRS_VSRS_TRANSACT(n,__REG_##c,__REG_##base)
+#define REST_32FPRS_VSRS(n,c,base) \
+ __REST_32FPRS_VSRS(n,__REG_##c,__REG_##base)
+
+/* Stack frame offsets for local variables. */
+#define TM_FRAME_L0 TM_FRAME_SIZE-16
+#define TM_FRAME_L1 TM_FRAME_SIZE-8
+#define STACK_PARAM(x) (48+((x)*8))
+
+
+/* In order to access the TM SPRs, TM must be enabled. So, do so: */
+_GLOBAL(tm_enable)
+ mfmsr r4
+ li r3, MSR_TM >> 32
+ sldi r3, r3, 32
+ and. r0, r4, r3
+ bne 1f
+ or r4, r4, r3
+ mtmsrd r4
+1: blr
+
+_GLOBAL(tm_save_sprs)
+ mfspr r0, SPRN_TFHAR
+ std r0, THREAD_TM_TFHAR(r3)
+ mfspr r0, SPRN_TEXASR
+ std r0, THREAD_TM_TEXASR(r3)
+ mfspr r0, SPRN_TFIAR
+ std r0, THREAD_TM_TFIAR(r3)
+ blr
+
+_GLOBAL(tm_restore_sprs)
+ ld r0, THREAD_TM_TFHAR(r3)
+ mtspr SPRN_TFHAR, r0
+ ld r0, THREAD_TM_TEXASR(r3)
+ mtspr SPRN_TEXASR, r0
+ ld r0, THREAD_TM_TFIAR(r3)
+ mtspr SPRN_TFIAR, r0
+ blr
+
+ /* Passed an 8-bit failure cause as first argument. */
+_GLOBAL(tm_abort)
+ TABORT(R3)
+ blr
+
+
+/* void tm_reclaim(struct thread_struct *thread,
+ * unsigned long orig_msr,
+ * uint8_t cause)
+ *
+ * - Performs a full reclaim. This destroys outstanding
+ * transactions and updates thread->regs.tm_ckpt_* with the
+ * original checkpointed state. Note that thread->regs is
+ * unchanged.
+ * - FP regs are written back to thread->transact_fpr before
+ * reclaiming. These are the transactional (current) versions.
+ *
+ * Purpose is to both abort transactions of, and preserve the state of,
+ * a transactions at a context switch. We preserve/restore both sets of process
+ * state to restore them when the thread's scheduled again. We continue in
+ * userland as though nothing happened, but when the transaction is resumed
+ * they will abort back to the checkpointed state we save out here.
+ *
+ * Call with IRQs off, stacks get all out of sync for some periods in here!
+ */
+_GLOBAL(tm_reclaim)
+ mfcr r6
+ mflr r0
+ std r6, 8(r1)
+ std r0, 16(r1)
+ std r2, 40(r1)
+ stdu r1, -TM_FRAME_SIZE(r1)
+
+ /* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD]. */
+
+ std r3, STACK_PARAM(0)(r1)
+ SAVE_NVGPRS(r1)
+
+ mfmsr r14
+ mr r15, r14
+ ori r15, r15, MSR_FP
+ oris r15, r15, MSR_VEC@h
+#ifdef CONFIG_VSX
+ BEGIN_FTR_SECTION
+ oris r15,r15, MSR_VSX@h
+ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif
+ mtmsrd r15
+ std r14, TM_FRAME_L0(r1)
+
+ /* Stash the stack pointer away for use after reclaim */
+ std r1, PACAR1(r13)
+
+ /* ******************** FPR/VR/VSRs ************
+ * Before reclaiming, capture the current/transactional FPR/VR
+ * versions /if used/.
+ *
+ * (If VSX used, FP and VMX are implied. Or, we don't need to look
+ * at MSR.VSX as copying FP regs if .FP, vector regs if .VMX covers it.)
+ *
+ * We're passed the thread's MSR as parameter 2.
+ *
+ * We enabled VEC/FP/VSX in the msr above, so we can execute these
+ * instructions!
+ */
+ andis. r0, r4, MSR_VEC@h
+ beq dont_backup_vec
+
+ SAVE_32VRS_TRANSACT(0, r6, r3) /* r6 scratch, r3 thread */
+ mfvscr vr0
+ li r6, THREAD_TRANSACT_VSCR
+ stvx vr0, r3, r6
+ mfspr r0, SPRN_VRSAVE
+ std r0, THREAD_TRANSACT_VRSAVE(r3)
+
+dont_backup_vec:
+ andi. r0, r4, MSR_FP
+ beq dont_backup_fp
+
+ SAVE_32FPRS_VSRS_TRANSACT(0, R6, R3) /* r6 scratch, r3 thread */
+
+ mffs fr0
+ stfd fr0,THREAD_TRANSACT_FPSCR(r3)
+
+dont_backup_fp:
+ /* The moment we treclaim, ALL of our GPRs will switch
+ * to user register state. (FPRs, CCR etc. also!)
+ * Use an sprg and a tm_scratch in the PACA to shuffle.
+ */
+ TRECLAIM(R5) /* Cause in r5 */
+
+ /* ******************** GPRs ******************** */
+ /* Stash the checkpointed r13 away in the scratch SPR and get the real
+ * paca
+ */
+ SET_SCRATCH0(r13)
+ GET_PACA(r13)
+
+ /* Stash the checkpointed r1 away in paca tm_scratch and get the real
+ * stack pointer back
+ */
+ std r1, PACATMSCRATCH(r13)
+ ld r1, PACAR1(r13)
+
+ /* Now get some more GPRS free */
+ std r7, GPR7(r1) /* Temporary stash */
+ std r12, GPR12(r1) /* '' '' '' */
+ ld r12, STACK_PARAM(0)(r1) /* Param 0, thread_struct * */
+
+ addi r7, r12, PT_CKPT_REGS /* Thread's ckpt_regs */
+
+ /* Make r7 look like an exception frame so that we
+ * can use the neat GPRx(n) macros. r7 is NOT a pt_regs ptr!
+ */
+ subi r7, r7, STACK_FRAME_OVERHEAD
+
+ /* Sync the userland GPRs 2-12, 14-31 to thread->regs: */
+ SAVE_GPR(0, r7) /* user r0 */
+ SAVE_GPR(2, r7) /* user r2 */
+ SAVE_4GPRS(3, r7) /* user r3-r6 */
+ SAVE_4GPRS(8, r7) /* user r8-r11 */
+ ld r3, PACATMSCRATCH(r13) /* user r1 */
+ ld r4, GPR7(r1) /* user r7 */
+ ld r5, GPR12(r1) /* user r12 */
+ GET_SCRATCH0(6) /* user r13 */
+ std r3, GPR1(r7)
+ std r4, GPR7(r7)
+ std r5, GPR12(r7)
+ std r6, GPR13(r7)
+
+ SAVE_NVGPRS(r7) /* user r14-r31 */
+
+ /* ******************** NIP ******************** */
+ mfspr r3, SPRN_TFHAR
+ std r3, _NIP(r7) /* Returns to failhandler */
+ /* The checkpointed NIP is ignored when rescheduling/rechkpting,
+ * but is used in signal return to 'wind back' to the abort handler.
+ */
+
+ /* ******************** CR,LR,CCR,MSR ********** */
+ mfctr r3
+ mflr r4
+ mfcr r5
+ mfxer r6
+
+ std r3, _CTR(r7)
+ std r4, _LINK(r7)
+ std r5, _CCR(r7)
+ std r6, _XER(r7)
+
+ /* MSR and flags: We don't change CRs, and we don't need to alter
+ * MSR.
+ */
+
+ /* TM regs, incl TEXASR -- these live in thread_struct. Note they've
+ * been updated by the treclaim, to explain to userland the failure
+ * cause (aborted).
+ */
+ mfspr r0, SPRN_TEXASR
+ mfspr r3, SPRN_TFHAR
+ mfspr r4, SPRN_TFIAR
+ std r0, THREAD_TM_TEXASR(r12)
+ std r3, THREAD_TM_TFHAR(r12)
+ std r4, THREAD_TM_TFIAR(r12)
+
+ /* AMR and PPR are checkpointed too, but are unsupported by Linux. */
+
+ /* Restore original MSR/IRQ state & clear TM mode */
+ ld r14, TM_FRAME_L0(r1) /* Orig MSR */
+ li r15, 0
+ rldimi r14, r15, MSR_TS_LG, (63-MSR_TS_LG)-1
+ mtmsrd r14
+
+ REST_NVGPRS(r1)
+
+ addi r1, r1, TM_FRAME_SIZE
+ ld r4, 8(r1)
+ ld r0, 16(r1)
+ mtcr r4
+ mtlr r0
+ ld r2, 40(r1)
+ blr
+
+
+ /* void tm_recheckpoint(struct thread_struct *thread,
+ * unsigned long orig_msr)
+ * - Restore the checkpointed register state saved by tm_reclaim
+ * when we switch_to a process.
+ *
+ * Call with IRQs off, stacks get all out of sync for
+ * some periods in here!
+ */
+_GLOBAL(tm_recheckpoint)
+ mfcr r5
+ mflr r0
+ std r5, 8(r1)
+ std r0, 16(r1)
+ std r2, 40(r1)
+ stdu r1, -TM_FRAME_SIZE(r1)
+
+ /* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD].
+ * This is used for backing up the NVGPRs:
+ */
+ SAVE_NVGPRS(r1)
+
+ std r1, PACAR1(r13)
+
+ /* Load complete register state from ts_ckpt* registers */
+
+ addi r7, r3, PT_CKPT_REGS /* Thread's ckpt_regs */
+
+ /* Make r7 look like an exception frame so that we
+ * can use the neat GPRx(n) macros. r7 is now NOT a pt_regs ptr!
+ */
+ subi r7, r7, STACK_FRAME_OVERHEAD
+
+ SET_SCRATCH0(r1)
+
+ mfmsr r6
+ /* R4 = original MSR to indicate whether thread used FP/Vector etc. */
+
+ /* Enable FP/vec in MSR if necessary! */
+ lis r5, MSR_VEC@h
+ ori r5, r5, MSR_FP
+ and. r5, r4, r5
+ beq restore_gprs /* if neither, skip both */
+
+#ifdef CONFIG_VSX
+ BEGIN_FTR_SECTION
+ oris r5, r5, MSR_VSX@h
+ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif
+ or r5, r6, r5 /* Set MSR.FP+.VSX/.VEC */
+ mtmsr r5
+
+ /* FP and VEC registers: These are recheckpointed from thread.fpr[]
+ * and thread.vr[] respectively. The thread.transact_fpr[] version
+ * is more modern, and will be loaded subsequently by any FPUnavailable
+ * trap.
+ */
+ andis. r0, r4, MSR_VEC@h
+ beq dont_restore_vec
+
+ li r5, THREAD_VSCR
+ lvx vr0, r3, r5
+ mtvscr vr0
+ REST_32VRS(0, r5, r3) /* r5 scratch, r3 THREAD ptr */
+ ld r5, THREAD_VRSAVE(r3)
+ mtspr SPRN_VRSAVE, r5
+
+dont_restore_vec:
+ andi. r0, r4, MSR_FP
+ beq dont_restore_fp
+
+ lfd fr0, THREAD_FPSCR(r3)
+ MTFSF_L(fr0)
+ REST_32FPRS_VSRS(0, R4, R3)
+
+dont_restore_fp:
+ mtmsr r6 /* FP/Vec off again! */
+
+restore_gprs:
+ /* ******************** CR,LR,CCR,MSR ********** */
+ ld r3, _CTR(r7)
+ ld r4, _LINK(r7)
+ ld r5, _CCR(r7)
+ ld r6, _XER(r7)
+
+ mtctr r3
+ mtlr r4
+ mtcr r5
+ mtxer r6
+
+ /* MSR and flags: We don't change CRs, and we don't need to alter
+ * MSR.
+ */
+
+ REST_4GPRS(0, r7) /* GPR0-3 */
+ REST_GPR(4, r7) /* GPR4-6 */
+ REST_GPR(5, r7)
+ REST_GPR(6, r7)
+ REST_4GPRS(8, r7) /* GPR8-11 */
+ REST_2GPRS(12, r7) /* GPR12-13 */
+
+ REST_NVGPRS(r7) /* GPR14-31 */
+
+ ld r7, GPR7(r7) /* GPR7 */
+
+ /* Commit register state as checkpointed state: */
+ TRECHKPT
+
+ /* Our transactional state has now changed.
+ *
+ * Now just get out of here. Transactional (current) state will be
+ * updated once restore is called on the return path in the _switch-ed
+ * -to process.
+ */
+
+ GET_PACA(r13)
+ GET_SCRATCH0(r1)
+
+ REST_NVGPRS(r1)
+
+ addi r1, r1, TM_FRAME_SIZE
+ ld r4, 8(r1)
+ ld r0, 16(r1)
+ mtcr r4
+ mtlr r0
+ ld r2, 40(r1)
+ blr
+
+ /* ****************************************************************** */
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 32518401af68..37cc40ef5043 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -58,6 +58,7 @@
#include <asm/rio.h>
#include <asm/fadump.h>
#include <asm/switch_to.h>
+#include <asm/tm.h>
#include <asm/debug.h>
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
@@ -66,7 +67,7 @@ int (*__debugger_ipi)(struct pt_regs *regs) __read_mostly;
int (*__debugger_bpt)(struct pt_regs *regs) __read_mostly;
int (*__debugger_sstep)(struct pt_regs *regs) __read_mostly;
int (*__debugger_iabr_match)(struct pt_regs *regs) __read_mostly;
-int (*__debugger_dabr_match)(struct pt_regs *regs) __read_mostly;
+int (*__debugger_break_match)(struct pt_regs *regs) __read_mostly;
int (*__debugger_fault_handler)(struct pt_regs *regs) __read_mostly;
EXPORT_SYMBOL(__debugger);
@@ -74,10 +75,17 @@ EXPORT_SYMBOL(__debugger_ipi);
EXPORT_SYMBOL(__debugger_bpt);
EXPORT_SYMBOL(__debugger_sstep);
EXPORT_SYMBOL(__debugger_iabr_match);
-EXPORT_SYMBOL(__debugger_dabr_match);
+EXPORT_SYMBOL(__debugger_break_match);
EXPORT_SYMBOL(__debugger_fault_handler);
#endif
+/* Transactional Memory trap debug */
+#ifdef TM_DEBUG_SW
+#define TM_DEBUG(x...) printk(KERN_INFO x)
+#else
+#define TM_DEBUG(x...) do { } while(0)
+#endif
+
/*
* Trap & Exception support
*/
@@ -138,7 +146,7 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs,
{
bust_spinlocks(0);
die_owner = -1;
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
die_nest_count--;
oops_exit();
printk("\n");
@@ -350,6 +358,7 @@ static inline int check_io_access(struct pt_regs *regs)
exception is in the MSR. */
#define get_reason(regs) ((regs)->msr)
#define get_mc_reason(regs) ((regs)->msr)
+#define REASON_TM 0x200000
#define REASON_FP 0x100000
#define REASON_ILLEGAL 0x80000
#define REASON_PRIVILEGED 0x40000
@@ -1020,6 +1029,38 @@ void __kprobes program_check_exception(struct pt_regs *regs)
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
return;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (reason & REASON_TM) {
+ /* This is a TM "Bad Thing Exception" program check.
+ * This occurs when:
+ * - An rfid/hrfid/mtmsrd attempts to cause an illegal
+ * transition in TM states.
+ * - A trechkpt is attempted when transactional.
+ * - A treclaim is attempted when non transactional.
+ * - A tend is illegally attempted.
+ * - writing a TM SPR when transactional.
+ */
+ if (!user_mode(regs) &&
+ report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) {
+ regs->nip += 4;
+ return;
+ }
+ /* If usermode caused this, it's done something illegal and
+ * gets a SIGILL slap on the wrist. We call it an illegal
+ * operand to distinguish from the instruction just being bad
+ * (e.g. executing a 'tend' on a CPU without TM!); it's an
+ * illegal /placement/ of a valid instruction.
+ */
+ if (user_mode(regs)) {
+ _exception(SIGILL, regs, ILL_ILLOPN, regs->nip);
+ return;
+ } else {
+ printk(KERN_EMERG "Unexpected TM Bad Thing exception "
+ "at %lx (msr 0x%x)\n", regs->nip, reason);
+ die("Unrecoverable exception", regs, SIGABRT);
+ }
+ }
+#endif
/* We restore the interrupt state now */
if (!arch_irq_disabled_regs(regs))
@@ -1160,6 +1201,109 @@ void vsx_unavailable_exception(struct pt_regs *regs)
die("Unrecoverable VSX Unavailable Exception", regs, SIGABRT);
}
+void tm_unavailable_exception(struct pt_regs *regs)
+{
+ /* We restore the interrupt state now */
+ if (!arch_irq_disabled_regs(regs))
+ local_irq_enable();
+
+ /* Currently we never expect a TMU exception. Catch
+ * this and kill the process!
+ */
+ printk(KERN_EMERG "Unexpected TM unavailable exception at %lx "
+ "(msr %lx)\n",
+ regs->nip, regs->msr);
+
+ if (user_mode(regs)) {
+ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+ return;
+ }
+
+ die("Unexpected TM unavailable exception", regs, SIGABRT);
+}
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+
+extern void do_load_up_fpu(struct pt_regs *regs);
+
+void fp_unavailable_tm(struct pt_regs *regs)
+{
+ /* Note: This does not handle any kind of FP laziness. */
+
+ TM_DEBUG("FP Unavailable trap whilst transactional at 0x%lx, MSR=%lx\n",
+ regs->nip, regs->msr);
+ tm_enable();
+
+ /* We can only have got here if the task started using FP after
+ * beginning the transaction. So, the transactional regs are just a
+ * copy of the checkpointed ones. But, we still need to recheckpoint
+ * as we're enabling FP for the process; it will return, abort the
+ * transaction, and probably retry but now with FP enabled. So the
+ * checkpointed FP registers need to be loaded.
+ */
+ tm_reclaim(&current->thread, current->thread.regs->msr,
+ TM_CAUSE_FAC_UNAV);
+ /* Reclaim didn't save out any FPRs to transact_fprs. */
+
+ /* Enable FP for the task: */
+ regs->msr |= (MSR_FP | current->thread.fpexc_mode);
+
+ /* This loads and recheckpoints the FP registers from
+ * thread.fpr[]. They will remain in registers after the
+ * checkpoint so we don't need to reload them after.
+ */
+ tm_recheckpoint(&current->thread, regs->msr);
+}
+
+#ifdef CONFIG_ALTIVEC
+extern void do_load_up_altivec(struct pt_regs *regs);
+
+void altivec_unavailable_tm(struct pt_regs *regs)
+{
+ /* See the comments in fp_unavailable_tm(). This function operates
+ * the same way.
+ */
+
+ TM_DEBUG("Vector Unavailable trap whilst transactional at 0x%lx,"
+ "MSR=%lx\n",
+ regs->nip, regs->msr);
+ tm_enable();
+ tm_reclaim(&current->thread, current->thread.regs->msr,
+ TM_CAUSE_FAC_UNAV);
+ regs->msr |= MSR_VEC;
+ tm_recheckpoint(&current->thread, regs->msr);
+ current->thread.used_vr = 1;
+}
+#endif
+
+#ifdef CONFIG_VSX
+void vsx_unavailable_tm(struct pt_regs *regs)
+{
+ /* See the comments in fp_unavailable_tm(). This works similarly,
+ * though we're loading both FP and VEC registers in here.
+ *
+ * If FP isn't in use, load FP regs. If VEC isn't in use, load VEC
+ * regs. Either way, set MSR_VSX.
+ */
+
+ TM_DEBUG("VSX Unavailable trap whilst transactional at 0x%lx,"
+ "MSR=%lx\n",
+ regs->nip, regs->msr);
+
+ tm_enable();
+ /* This reclaims FP and/or VR regs if they're already enabled */
+ tm_reclaim(&current->thread, current->thread.regs->msr,
+ TM_CAUSE_FAC_UNAV);
+
+ regs->msr |= MSR_VEC | MSR_FP | current->thread.fpexc_mode |
+ MSR_VSX;
+ /* This loads & recheckpoints FP and VRs. */
+ tm_recheckpoint(&current->thread, regs->msr);
+ current->thread.used_vsr = 1;
+}
+#endif
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
void performance_monitor_exception(struct pt_regs *regs)
{
__get_cpu_var(irq_stat).pmu_irqs++;
@@ -1515,7 +1659,7 @@ void unrecoverable_exception(struct pt_regs *regs)
die("Unrecoverable exception", regs, SIGABRT);
}
-#ifdef CONFIG_BOOKE_WDT
+#if defined(CONFIG_BOOKE_WDT) || defined(CONFIG_40x)
/*
* Default handler for a Watchdog exception,
* spins until a reboot occurs
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index e830289d2e48..9e20999aaef2 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -7,6 +7,57 @@
#include <asm/page.h>
#include <asm/ptrace.h>
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Wrapper to call load_up_altivec from C.
+ * void do_load_up_altivec(struct pt_regs *regs);
+ */
+_GLOBAL(do_load_up_altivec)
+ mflr r0
+ std r0, 16(r1)
+ stdu r1, -112(r1)
+
+ subi r6, r3, STACK_FRAME_OVERHEAD
+ /* load_up_altivec expects r12=MSR, r13=PACA, and returns
+ * with r12 = new MSR.
+ */
+ ld r12,_MSR(r6)
+ GET_PACA(r13)
+ bl load_up_altivec
+ std r12,_MSR(r6)
+
+ ld r0, 112+16(r1)
+ addi r1, r1, 112
+ mtlr r0
+ blr
+
+/* void do_load_up_transact_altivec(struct thread_struct *thread)
+ *
+ * This is similar to load_up_altivec but for the transactional version of the
+ * vector regs. It doesn't mess with the task MSR or valid flags.
+ * Furthermore, VEC laziness is not supported with TM currently.
+ */
+_GLOBAL(do_load_up_transact_altivec)
+ mfmsr r6
+ oris r5,r6,MSR_VEC@h
+ MTMSRD(r5)
+ isync
+
+ li r4,1
+ stw r4,THREAD_USED_VR(r3)
+
+ li r10,THREAD_TRANSACT_VSCR
+ lvx vr0,r10,r3
+ mtvscr vr0
+ REST_32VRS_TRANSACT(0,r4,r3)
+
+ /* Disable VEC again. */
+ MTMSRD(r6)
+ isync
+
+ blr
+#endif
+
/*
* load_up_altivec(unused, unused, tsk)
* Disable VMX for the task which had it previously,
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 65d1c08cf09e..654e479802f2 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -218,6 +218,11 @@ SECTIONS
.got : AT(ADDR(.got) - LOAD_OFFSET) {
__toc_start = .;
+#ifndef CONFIG_RELOCATABLE
+ __prom_init_toc_start = .;
+ arch/powerpc/kernel/prom_init.o*(.toc .got)
+ __prom_init_toc_end = .;
+#endif
*(.got)
*(.toc)
}
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 4730c953f435..63c67ec72e43 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -41,7 +41,7 @@ config KVM_BOOK3S_PR
config KVM_BOOK3S_32
tristate "KVM support for PowerPC book3s_32 processors"
- depends on EXPERIMENTAL && PPC_BOOK3S_32 && !SMP && !PTE_64BIT
+ depends on PPC_BOOK3S_32 && !SMP && !PTE_64BIT
select KVM
select KVM_BOOK3S_32_HANDLER
select KVM_BOOK3S_PR
@@ -56,7 +56,7 @@ config KVM_BOOK3S_32
config KVM_BOOK3S_64
tristate "KVM support for PowerPC book3s_64 processors"
- depends on EXPERIMENTAL && PPC_BOOK3S_64
+ depends on PPC_BOOK3S_64
select KVM_BOOK3S_64_HANDLER
select KVM
---help---
@@ -97,7 +97,7 @@ config KVM_BOOKE_HV
config KVM_440
bool "KVM support for PowerPC 440 processors"
- depends on EXPERIMENTAL && 44x
+ depends on 44x
select KVM
select KVM_MMIO
---help---
@@ -122,7 +122,7 @@ config KVM_EXIT_TIMING
config KVM_E500V2
bool "KVM support for PowerPC E500v2 processors"
- depends on EXPERIMENTAL && E500 && !PPC_E500MC
+ depends on E500 && !PPC_E500MC
select KVM
select KVM_MMIO
select MMU_NOTIFIER
@@ -137,7 +137,7 @@ config KVM_E500V2
config KVM_E500MC
bool "KVM support for PowerPC E500MC/E5500 processors"
- depends on EXPERIMENTAL && PPC_E500MC
+ depends on PPC_E500MC
select KVM
select KVM_MMIO
select KVM_BOOKE_HV
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 1e473d46322c..b772eded8c26 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -10,7 +10,8 @@ common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o \
eventfd.o)
CFLAGS_44x_tlb.o := -I.
-CFLAGS_e500_tlb.o := -I.
+CFLAGS_e500_mmu.o := -I.
+CFLAGS_e500_mmu_host.o := -I.
CFLAGS_emulate.o := -I.
common-objs-y += powerpc.o emulate.o
@@ -35,7 +36,8 @@ kvm-e500-objs := \
booke_emulate.o \
booke_interrupts.o \
e500.o \
- e500_tlb.o \
+ e500_mmu.o \
+ e500_mmu_host.o \
e500_emulate.o
kvm-objs-$(CONFIG_KVM_E500V2) := $(kvm-e500-objs)
@@ -45,7 +47,8 @@ kvm-e500mc-objs := \
booke_emulate.o \
bookehv_interrupts.o \
e500mc.o \
- e500_tlb.o \
+ e500_mmu.o \
+ e500_mmu_host.o \
e500_emulate.o
kvm-objs-$(CONFIG_KVM_E500MC) := $(kvm-e500mc-objs)
diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c
index d31a716f7f2b..836c56975e21 100644
--- a/arch/powerpc/kvm/book3s_emulate.c
+++ b/arch/powerpc/kvm/book3s_emulate.c
@@ -34,6 +34,8 @@
#define OP_31_XOP_MTSRIN 242
#define OP_31_XOP_TLBIEL 274
#define OP_31_XOP_TLBIE 306
+/* Opcode is officially reserved, reuse it as sc 1 when sc 1 doesn't trap */
+#define OP_31_XOP_FAKE_SC1 308
#define OP_31_XOP_SLBMTE 402
#define OP_31_XOP_SLBIE 434
#define OP_31_XOP_SLBIA 498
@@ -170,6 +172,32 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
vcpu->arch.mmu.tlbie(vcpu, addr, large);
break;
}
+#ifdef CONFIG_KVM_BOOK3S_64_PR
+ case OP_31_XOP_FAKE_SC1:
+ {
+ /* SC 1 papr hypercalls */
+ ulong cmd = kvmppc_get_gpr(vcpu, 3);
+ int i;
+
+ if ((vcpu->arch.shared->msr & MSR_PR) ||
+ !vcpu->arch.papr_enabled) {
+ emulated = EMULATE_FAIL;
+ break;
+ }
+
+ if (kvmppc_h_pr(vcpu, cmd) == EMULATE_DONE)
+ break;
+
+ run->papr_hcall.nr = cmd;
+ for (i = 0; i < 9; ++i) {
+ ulong gpr = kvmppc_get_gpr(vcpu, 4 + i);
+ run->papr_hcall.args[i] = gpr;
+ }
+
+ emulated = EMULATE_DO_PAPR;
+ break;
+ }
+#endif
case OP_31_XOP_EIOIO:
break;
case OP_31_XOP_SLBMTE:
@@ -427,6 +455,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
case SPRN_PMC3_GEKKO:
case SPRN_PMC4_GEKKO:
case SPRN_WPAR_GEKKO:
+ case SPRN_MSSSR0:
break;
unprivileged:
default:
@@ -523,6 +552,7 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
case SPRN_PMC3_GEKKO:
case SPRN_PMC4_GEKKO:
case SPRN_WPAR_GEKKO:
+ case SPRN_MSSSR0:
*spr_val = 0;
break;
default:
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 71d0c90b62bf..80dcc53a1aba 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -1549,7 +1549,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
mutex_lock(&kvm->slots_lock);
r = -EINVAL;
- if (log->slot >= KVM_MEMORY_SLOTS)
+ if (log->slot >= KVM_USER_MEM_SLOTS)
goto out;
memslot = id_to_memslot(kvm->memslots, log->slot);
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 10b6c358dd77..e33d11f1b977 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -539,6 +539,11 @@ fast_guest_return:
/* Enter guest */
+BEGIN_FTR_SECTION
+ ld r5, VCPU_CFAR(r4)
+ mtspr SPRN_CFAR, r5
+END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
+
ld r5, VCPU_LR(r4)
lwz r6, VCPU_CR(r4)
mtlr r5
@@ -604,6 +609,10 @@ kvmppc_interrupt:
lwz r4, HSTATE_SCRATCH1(r13)
std r3, VCPU_GPR(R12)(r9)
stw r4, VCPU_CR(r9)
+BEGIN_FTR_SECTION
+ ld r3, HSTATE_CFAR(r13)
+ std r3, VCPU_CFAR(r9)
+END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
/* Restore R1/R2 so we can handle faults */
ld r1, HSTATE_HOST_R1(r13)
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 28d38adeca73..5e93438afb06 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -34,6 +34,8 @@
#include <asm/kvm_book3s.h>
#include <asm/mmu_context.h>
#include <asm/switch_to.h>
+#include <asm/firmware.h>
+#include <asm/hvcall.h>
#include <linux/gfp.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
@@ -760,6 +762,11 @@ program_interrupt:
run->exit_reason = KVM_EXIT_MMIO;
r = RESUME_HOST_NV;
break;
+ case EMULATE_DO_PAPR:
+ run->exit_reason = KVM_EXIT_PAPR_HCALL;
+ vcpu->arch.hcall_needed = 1;
+ r = RESUME_HOST_NV;
+ break;
default:
BUG();
}
@@ -1284,12 +1291,21 @@ void kvmppc_core_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot)
{
}
+static unsigned int kvm_global_user_count = 0;
+static DEFINE_SPINLOCK(kvm_global_user_count_lock);
+
int kvmppc_core_init_vm(struct kvm *kvm)
{
#ifdef CONFIG_PPC64
INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
#endif
+ if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
+ spin_lock(&kvm_global_user_count_lock);
+ if (++kvm_global_user_count == 1)
+ pSeries_disable_reloc_on_exc();
+ spin_unlock(&kvm_global_user_count_lock);
+ }
return 0;
}
@@ -1298,6 +1314,14 @@ void kvmppc_core_destroy_vm(struct kvm *kvm)
#ifdef CONFIG_PPC64
WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables));
#endif
+
+ if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
+ spin_lock(&kvm_global_user_count_lock);
+ BUG_ON(kvm_global_user_count == 0);
+ if (--kvm_global_user_count == 0)
+ pSeries_enable_reloc_on_exc();
+ spin_unlock(&kvm_global_user_count_lock);
+ }
}
static int kvmppc_book3s_init(void)
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 69f114015780..020923e43134 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -182,6 +182,14 @@ static void kvmppc_core_queue_inst_storage(struct kvm_vcpu *vcpu,
kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_INST_STORAGE);
}
+static void kvmppc_core_queue_alignment(struct kvm_vcpu *vcpu, ulong dear_flags,
+ ulong esr_flags)
+{
+ vcpu->arch.queued_dear = dear_flags;
+ vcpu->arch.queued_esr = esr_flags;
+ kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALIGNMENT);
+}
+
void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong esr_flags)
{
vcpu->arch.queued_esr = esr_flags;
@@ -300,13 +308,22 @@ static void set_guest_esr(struct kvm_vcpu *vcpu, u32 esr)
#endif
}
+static unsigned long get_guest_epr(struct kvm_vcpu *vcpu)
+{
+#ifdef CONFIG_KVM_BOOKE_HV
+ return mfspr(SPRN_GEPR);
+#else
+ return vcpu->arch.epr;
+#endif
+}
+
/* Deliver the interrupt of the corresponding priority, if possible. */
static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
unsigned int priority)
{
int allowed = 0;
ulong msr_mask = 0;
- bool update_esr = false, update_dear = false;
+ bool update_esr = false, update_dear = false, update_epr = false;
ulong crit_raw = vcpu->arch.shared->critical;
ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
bool crit;
@@ -330,9 +347,13 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
keep_irq = true;
}
+ if ((priority == BOOKE_IRQPRIO_EXTERNAL) && vcpu->arch.epr_enabled)
+ update_epr = true;
+
switch (priority) {
case BOOKE_IRQPRIO_DTLB_MISS:
case BOOKE_IRQPRIO_DATA_STORAGE:
+ case BOOKE_IRQPRIO_ALIGNMENT:
update_dear = true;
/* fall through */
case BOOKE_IRQPRIO_INST_STORAGE:
@@ -346,7 +367,6 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
case BOOKE_IRQPRIO_SPE_FP_DATA:
case BOOKE_IRQPRIO_SPE_FP_ROUND:
case BOOKE_IRQPRIO_AP_UNAVAIL:
- case BOOKE_IRQPRIO_ALIGNMENT:
allowed = 1;
msr_mask = MSR_CE | MSR_ME | MSR_DE;
int_class = INT_CLASS_NONCRIT;
@@ -408,6 +428,8 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
set_guest_esr(vcpu, vcpu->arch.queued_esr);
if (update_dear == true)
set_guest_dear(vcpu, vcpu->arch.queued_dear);
+ if (update_epr == true)
+ kvm_make_request(KVM_REQ_EPR_EXIT, vcpu);
new_msr &= msr_mask;
#if defined(CONFIG_64BIT)
@@ -581,6 +603,11 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
kvmppc_core_check_exceptions(vcpu);
+ if (vcpu->requests) {
+ /* Exception delivery raised request; start over */
+ return 1;
+ }
+
if (vcpu->arch.shared->msr & MSR_WE) {
local_irq_enable();
kvm_vcpu_block(vcpu);
@@ -610,6 +637,13 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
r = 0;
}
+ if (kvm_check_request(KVM_REQ_EPR_EXIT, vcpu)) {
+ vcpu->run->epr.epr = 0;
+ vcpu->arch.epr_needed = true;
+ vcpu->run->exit_reason = KVM_EXIT_EPR;
+ r = 0;
+ }
+
return r;
}
@@ -945,6 +979,12 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
r = RESUME_GUEST;
break;
+ case BOOKE_INTERRUPT_ALIGNMENT:
+ kvmppc_core_queue_alignment(vcpu, vcpu->arch.fault_dear,
+ vcpu->arch.fault_esr);
+ r = RESUME_GUEST;
+ break;
+
#ifdef CONFIG_KVM_BOOKE_HV
case BOOKE_INTERRUPT_HV_SYSCALL:
if (!(vcpu->arch.shared->msr & MSR_PR)) {
@@ -1388,6 +1428,11 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
&vcpu->arch.dbg_reg.dac[dac], sizeof(u64));
break;
}
+ case KVM_REG_PPC_EPR: {
+ u32 epr = get_guest_epr(vcpu);
+ r = put_user(epr, (u32 __user *)(long)reg->addr);
+ break;
+ }
#if defined(CONFIG_64BIT)
case KVM_REG_PPC_EPCR:
r = put_user(vcpu->arch.epcr, (u32 __user *)(long)reg->addr);
@@ -1420,6 +1465,13 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
(u64 __user *)(long)reg->addr, sizeof(u64));
break;
}
+ case KVM_REG_PPC_EPR: {
+ u32 new_epr;
+ r = get_user(new_epr, (u32 __user *)(long)reg->addr);
+ if (!r)
+ kvmppc_set_epr(vcpu, new_epr);
+ break;
+ }
#if defined(CONFIG_64BIT)
case KVM_REG_PPC_EPCR: {
u32 new_epcr;
@@ -1556,7 +1608,9 @@ int __init kvmppc_booke_init(void)
{
#ifndef CONFIG_KVM_BOOKE_HV
unsigned long ivor[16];
+ unsigned long *handler = kvmppc_booke_handler_addr;
unsigned long max_ivor = 0;
+ unsigned long handler_len;
int i;
/* We install our own exception handlers by hijacking IVPR. IVPR must
@@ -1589,14 +1643,16 @@ int __init kvmppc_booke_init(void)
for (i = 0; i < 16; i++) {
if (ivor[i] > max_ivor)
- max_ivor = ivor[i];
+ max_ivor = i;
+ handler_len = handler[i + 1] - handler[i];
memcpy((void *)kvmppc_booke_handlers + ivor[i],
- kvmppc_handlers_start + i * kvmppc_handler_len,
- kvmppc_handler_len);
+ (void *)handler[i], handler_len);
}
- flush_icache_range(kvmppc_booke_handlers,
- kvmppc_booke_handlers + max_ivor + kvmppc_handler_len);
+
+ handler_len = handler[max_ivor + 1] - handler[max_ivor];
+ flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers +
+ ivor[max_ivor] + handler_len);
#endif /* !BOOKE_HV */
return 0;
}
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
index e9b88e433f64..5fd1ba693579 100644
--- a/arch/powerpc/kvm/booke.h
+++ b/arch/powerpc/kvm/booke.h
@@ -65,6 +65,7 @@
(1 << BOOKE_IRQPRIO_CRITICAL))
extern unsigned long kvmppc_booke_handlers;
+extern unsigned long kvmppc_booke_handler_addr[];
void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr);
void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr);
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
index 4685b8cf2249..27a4b2877c10 100644
--- a/arch/powerpc/kvm/booke_emulate.c
+++ b/arch/powerpc/kvm/booke_emulate.c
@@ -269,6 +269,9 @@ int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
case SPRN_ESR:
*spr_val = vcpu->arch.shared->esr;
break;
+ case SPRN_EPR:
+ *spr_val = vcpu->arch.epr;
+ break;
case SPRN_CSRR0:
*spr_val = vcpu->arch.csrr0;
break;
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
index bb46b32f9813..f4bb55c96517 100644
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -45,18 +45,21 @@
(1<<BOOKE_INTERRUPT_DEBUG))
#define NEED_DEAR_MASK ((1<<BOOKE_INTERRUPT_DATA_STORAGE) | \
- (1<<BOOKE_INTERRUPT_DTLB_MISS))
+ (1<<BOOKE_INTERRUPT_DTLB_MISS) | \
+ (1<<BOOKE_INTERRUPT_ALIGNMENT))
#define NEED_ESR_MASK ((1<<BOOKE_INTERRUPT_DATA_STORAGE) | \
(1<<BOOKE_INTERRUPT_INST_STORAGE) | \
(1<<BOOKE_INTERRUPT_PROGRAM) | \
- (1<<BOOKE_INTERRUPT_DTLB_MISS))
+ (1<<BOOKE_INTERRUPT_DTLB_MISS) | \
+ (1<<BOOKE_INTERRUPT_ALIGNMENT))
.macro KVM_HANDLER ivor_nr scratch srr0
_GLOBAL(kvmppc_handler_\ivor_nr)
/* Get pointer to vcpu and record exit number. */
mtspr \scratch , r4
- mfspr r4, SPRN_SPRG_RVCPU
+ mfspr r4, SPRN_SPRG_THREAD
+ lwz r4, THREAD_KVM_VCPU(r4)
stw r3, VCPU_GPR(R3)(r4)
stw r5, VCPU_GPR(R5)(r4)
stw r6, VCPU_GPR(R6)(r4)
@@ -73,6 +76,14 @@ _GLOBAL(kvmppc_handler_\ivor_nr)
bctr
.endm
+.macro KVM_HANDLER_ADDR ivor_nr
+ .long kvmppc_handler_\ivor_nr
+.endm
+
+.macro KVM_HANDLER_END
+ .long kvmppc_handlers_end
+.endm
+
_GLOBAL(kvmppc_handlers_start)
KVM_HANDLER BOOKE_INTERRUPT_CRITICAL SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
KVM_HANDLER BOOKE_INTERRUPT_MACHINE_CHECK SPRN_SPRG_RSCRATCH_MC SPRN_MCSRR0
@@ -93,9 +104,7 @@ KVM_HANDLER BOOKE_INTERRUPT_DEBUG SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL SPRN_SPRG_RSCRATCH0 SPRN_SRR0
KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA SPRN_SPRG_RSCRATCH0 SPRN_SRR0
KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_ROUND SPRN_SPRG_RSCRATCH0 SPRN_SRR0
-
-_GLOBAL(kvmppc_handler_len)
- .long kvmppc_handler_1 - kvmppc_handler_0
+_GLOBAL(kvmppc_handlers_end)
/* Registers:
* SPRG_SCRATCH0: guest r4
@@ -402,9 +411,6 @@ lightweight_exit:
lwz r8, kvmppc_booke_handlers@l(r8)
mtspr SPRN_IVPR, r8
- /* Save vcpu pointer for the exception handlers. */
- mtspr SPRN_SPRG_WVCPU, r4
-
lwz r5, VCPU_SHARED(r4)
/* Can't switch the stack pointer until after IVPR is switched,
@@ -463,6 +469,31 @@ lightweight_exit:
lwz r4, VCPU_GPR(R4)(r4)
rfi
+ .data
+ .align 4
+ .globl kvmppc_booke_handler_addr
+kvmppc_booke_handler_addr:
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_CRITICAL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_MACHINE_CHECK
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_DATA_STORAGE
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_INST_STORAGE
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_EXTERNAL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_ALIGNMENT
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_PROGRAM
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_FP_UNAVAIL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_SYSCALL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_AP_UNAVAIL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_DECREMENTER
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_FIT
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_WATCHDOG
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_DTLB_MISS
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_ITLB_MISS
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_DEBUG
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_UNAVAIL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_FP_DATA
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_FP_ROUND
+KVM_HANDLER_END /*Always keep this in end*/
+
#ifdef CONFIG_SPE
_GLOBAL(kvmppc_save_guest_spe)
cmpi 0,r3,0
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c
index b479ed77c515..6dd4de7802bf 100644
--- a/arch/powerpc/kvm/e500.c
+++ b/arch/powerpc/kvm/e500.c
@@ -491,6 +491,9 @@ static int __init kvmppc_e500_init(void)
{
int r, i;
unsigned long ivor[3];
+ /* Process remaining handlers above the generic first 16 */
+ unsigned long *handler = &kvmppc_booke_handler_addr[16];
+ unsigned long handler_len;
unsigned long max_ivor = 0;
r = kvmppc_core_check_processor_compat();
@@ -506,15 +509,16 @@ static int __init kvmppc_e500_init(void)
ivor[1] = mfspr(SPRN_IVOR33);
ivor[2] = mfspr(SPRN_IVOR34);
for (i = 0; i < 3; i++) {
- if (ivor[i] > max_ivor)
- max_ivor = ivor[i];
+ if (ivor[i] > ivor[max_ivor])
+ max_ivor = i;
+ handler_len = handler[i + 1] - handler[i];
memcpy((void *)kvmppc_booke_handlers + ivor[i],
- kvmppc_handlers_start + (i + 16) * kvmppc_handler_len,
- kvmppc_handler_len);
+ (void *)handler[i], handler_len);
}
- flush_icache_range(kvmppc_booke_handlers,
- kvmppc_booke_handlers + max_ivor + kvmppc_handler_len);
+ handler_len = handler[max_ivor + 1] - handler[max_ivor];
+ flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers +
+ ivor[max_ivor] + handler_len);
return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE);
}
diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h
index c70d37ed770a..41cefd43655f 100644
--- a/arch/powerpc/kvm/e500.h
+++ b/arch/powerpc/kvm/e500.h
@@ -28,6 +28,7 @@
#define E500_TLB_VALID 1
#define E500_TLB_BITMAP 2
+#define E500_TLB_TLB0 (1 << 2)
struct tlbe_ref {
pfn_t pfn;
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_mmu.c
index cf3f18012371..5c4475983f78 100644
--- a/arch/powerpc/kvm/e500_tlb.c
+++ b/arch/powerpc/kvm/e500_mmu.c
@@ -1,10 +1,11 @@
/*
- * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. All rights reserved.
*
* Author: Yu Liu, yu.liu@freescale.com
* Scott Wood, scottwood@freescale.com
* Ashish Kalra, ashish.kalra@freescale.com
* Varun Sethi, varun.sethi@freescale.com
+ * Alexander Graf, agraf@suse.de
*
* Description:
* This file is based on arch/powerpc/kvm/44x_tlb.c,
@@ -33,10 +34,7 @@
#include "e500.h"
#include "trace.h"
#include "timing.h"
-
-#define to_htlb1_esel(esel) (host_tlb_params[1].entries - (esel) - 1)
-
-static struct kvmppc_e500_tlb_params host_tlb_params[E500_TLB_NUM];
+#include "e500_mmu_host.h"
static inline unsigned int gtlb0_get_next_victim(
struct kvmppc_vcpu_e500 *vcpu_e500)
@@ -50,174 +48,6 @@ static inline unsigned int gtlb0_get_next_victim(
return victim;
}
-static inline unsigned int tlb1_max_shadow_size(void)
-{
- /* reserve one entry for magic page */
- return host_tlb_params[1].entries - tlbcam_index - 1;
-}
-
-static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)
-{
- return tlbe->mas7_3 & (MAS3_SW|MAS3_UW);
-}
-
-static inline u32 e500_shadow_mas3_attrib(u32 mas3, int usermode)
-{
- /* Mask off reserved bits. */
- mas3 &= MAS3_ATTRIB_MASK;
-
-#ifndef CONFIG_KVM_BOOKE_HV
- if (!usermode) {
- /* Guest is in supervisor mode,
- * so we need to translate guest
- * supervisor permissions into user permissions. */
- mas3 &= ~E500_TLB_USER_PERM_MASK;
- mas3 |= (mas3 & E500_TLB_SUPER_PERM_MASK) << 1;
- }
- mas3 |= E500_TLB_SUPER_PERM_MASK;
-#endif
- return mas3;
-}
-
-static inline u32 e500_shadow_mas2_attrib(u32 mas2, int usermode)
-{
-#ifdef CONFIG_SMP
- return (mas2 & MAS2_ATTRIB_MASK) | MAS2_M;
-#else
- return mas2 & MAS2_ATTRIB_MASK;
-#endif
-}
-
-/*
- * writing shadow tlb entry to host TLB
- */
-static inline void __write_host_tlbe(struct kvm_book3e_206_tlb_entry *stlbe,
- uint32_t mas0)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- mtspr(SPRN_MAS0, mas0);
- mtspr(SPRN_MAS1, stlbe->mas1);
- mtspr(SPRN_MAS2, (unsigned long)stlbe->mas2);
- mtspr(SPRN_MAS3, (u32)stlbe->mas7_3);
- mtspr(SPRN_MAS7, (u32)(stlbe->mas7_3 >> 32));
-#ifdef CONFIG_KVM_BOOKE_HV
- mtspr(SPRN_MAS8, stlbe->mas8);
-#endif
- asm volatile("isync; tlbwe" : : : "memory");
-
-#ifdef CONFIG_KVM_BOOKE_HV
- /* Must clear mas8 for other host tlbwe's */
- mtspr(SPRN_MAS8, 0);
- isync();
-#endif
- local_irq_restore(flags);
-
- trace_kvm_booke206_stlb_write(mas0, stlbe->mas8, stlbe->mas1,
- stlbe->mas2, stlbe->mas7_3);
-}
-
-/*
- * Acquire a mas0 with victim hint, as if we just took a TLB miss.
- *
- * We don't care about the address we're searching for, other than that it's
- * in the right set and is not present in the TLB. Using a zero PID and a
- * userspace address means we don't have to set and then restore MAS5, or
- * calculate a proper MAS6 value.
- */
-static u32 get_host_mas0(unsigned long eaddr)
-{
- unsigned long flags;
- u32 mas0;
-
- local_irq_save(flags);
- mtspr(SPRN_MAS6, 0);
- asm volatile("tlbsx 0, %0" : : "b" (eaddr & ~CONFIG_PAGE_OFFSET));
- mas0 = mfspr(SPRN_MAS0);
- local_irq_restore(flags);
-
- return mas0;
-}
-
-/* sesel is for tlb1 only */
-static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
- int tlbsel, int sesel, struct kvm_book3e_206_tlb_entry *stlbe)
-{
- u32 mas0;
-
- if (tlbsel == 0) {
- mas0 = get_host_mas0(stlbe->mas2);
- __write_host_tlbe(stlbe, mas0);
- } else {
- __write_host_tlbe(stlbe,
- MAS0_TLBSEL(1) |
- MAS0_ESEL(to_htlb1_esel(sesel)));
- }
-}
-
-#ifdef CONFIG_KVM_E500V2
-void kvmppc_map_magic(struct kvm_vcpu *vcpu)
-{
- struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
- struct kvm_book3e_206_tlb_entry magic;
- ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
- unsigned int stid;
- pfn_t pfn;
-
- pfn = (pfn_t)virt_to_phys((void *)shared_page) >> PAGE_SHIFT;
- get_page(pfn_to_page(pfn));
-
- preempt_disable();
- stid = kvmppc_e500_get_sid(vcpu_e500, 0, 0, 0, 0);
-
- magic.mas1 = MAS1_VALID | MAS1_TS | MAS1_TID(stid) |
- MAS1_TSIZE(BOOK3E_PAGESZ_4K);
- magic.mas2 = vcpu->arch.magic_page_ea | MAS2_M;
- magic.mas7_3 = ((u64)pfn << PAGE_SHIFT) |
- MAS3_SW | MAS3_SR | MAS3_UW | MAS3_UR;
- magic.mas8 = 0;
-
- __write_host_tlbe(&magic, MAS0_TLBSEL(1) | MAS0_ESEL(tlbcam_index));
- preempt_enable();
-}
-#endif
-
-static void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500,
- int tlbsel, int esel)
-{
- struct kvm_book3e_206_tlb_entry *gtlbe =
- get_entry(vcpu_e500, tlbsel, esel);
-
- if (tlbsel == 1 &&
- vcpu_e500->gtlb_priv[1][esel].ref.flags & E500_TLB_BITMAP) {
- u64 tmp = vcpu_e500->g2h_tlb1_map[esel];
- int hw_tlb_indx;
- unsigned long flags;
-
- local_irq_save(flags);
- while (tmp) {
- hw_tlb_indx = __ilog2_u64(tmp & -tmp);
- mtspr(SPRN_MAS0,
- MAS0_TLBSEL(1) |
- MAS0_ESEL(to_htlb1_esel(hw_tlb_indx)));
- mtspr(SPRN_MAS1, 0);
- asm volatile("tlbwe");
- vcpu_e500->h2g_tlb1_rmap[hw_tlb_indx] = 0;
- tmp &= tmp - 1;
- }
- mb();
- vcpu_e500->g2h_tlb1_map[esel] = 0;
- vcpu_e500->gtlb_priv[1][esel].ref.flags &= ~E500_TLB_BITMAP;
- local_irq_restore(flags);
-
- return;
- }
-
- /* Guest tlbe is backed by at most one host tlbe per shadow pid. */
- kvmppc_e500_tlbil_one(vcpu_e500, gtlbe);
-}
-
static int tlb0_set_base(gva_t addr, int sets, int ways)
{
int set_base;
@@ -296,70 +126,6 @@ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500,
return -1;
}
-static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
- struct kvm_book3e_206_tlb_entry *gtlbe,
- pfn_t pfn)
-{
- ref->pfn = pfn;
- ref->flags = E500_TLB_VALID;
-
- if (tlbe_is_writable(gtlbe))
- kvm_set_pfn_dirty(pfn);
-}
-
-static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
-{
- if (ref->flags & E500_TLB_VALID) {
- trace_kvm_booke206_ref_release(ref->pfn, ref->flags);
- ref->flags = 0;
- }
-}
-
-static void clear_tlb1_bitmap(struct kvmppc_vcpu_e500 *vcpu_e500)
-{
- if (vcpu_e500->g2h_tlb1_map)
- memset(vcpu_e500->g2h_tlb1_map, 0,
- sizeof(u64) * vcpu_e500->gtlb_params[1].entries);
- if (vcpu_e500->h2g_tlb1_rmap)
- memset(vcpu_e500->h2g_tlb1_rmap, 0,
- sizeof(unsigned int) * host_tlb_params[1].entries);
-}
-
-static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)
-{
- int tlbsel = 0;
- int i;
-
- for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) {
- struct tlbe_ref *ref =
- &vcpu_e500->gtlb_priv[tlbsel][i].ref;
- kvmppc_e500_ref_release(ref);
- }
-}
-
-static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500)
-{
- int stlbsel = 1;
- int i;
-
- kvmppc_e500_tlbil_all(vcpu_e500);
-
- for (i = 0; i < host_tlb_params[stlbsel].entries; i++) {
- struct tlbe_ref *ref =
- &vcpu_e500->tlb_refs[stlbsel][i];
- kvmppc_e500_ref_release(ref);
- }
-
- clear_tlb_privs(vcpu_e500);
-}
-
-void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu)
-{
- struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
- clear_tlb_refs(vcpu_e500);
- clear_tlb1_bitmap(vcpu_e500);
-}
-
static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
unsigned int eaddr, int as)
{
@@ -385,216 +151,6 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
| (as ? MAS6_SAS : 0);
}
-/* TID must be supplied by the caller */
-static inline void kvmppc_e500_setup_stlbe(
- struct kvm_vcpu *vcpu,
- struct kvm_book3e_206_tlb_entry *gtlbe,
- int tsize, struct tlbe_ref *ref, u64 gvaddr,
- struct kvm_book3e_206_tlb_entry *stlbe)
-{
- pfn_t pfn = ref->pfn;
- u32 pr = vcpu->arch.shared->msr & MSR_PR;
-
- BUG_ON(!(ref->flags & E500_TLB_VALID));
-
- /* Force IPROT=0 for all guest mappings. */
- stlbe->mas1 = MAS1_TSIZE(tsize) | get_tlb_sts(gtlbe) | MAS1_VALID;
- stlbe->mas2 = (gvaddr & MAS2_EPN) |
- e500_shadow_mas2_attrib(gtlbe->mas2, pr);
- stlbe->mas7_3 = ((u64)pfn << PAGE_SHIFT) |
- e500_shadow_mas3_attrib(gtlbe->mas7_3, pr);
-
-#ifdef CONFIG_KVM_BOOKE_HV
- stlbe->mas8 = MAS8_TGS | vcpu->kvm->arch.lpid;
-#endif
-}
-
-static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
- u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
- int tlbsel, struct kvm_book3e_206_tlb_entry *stlbe,
- struct tlbe_ref *ref)
-{
- struct kvm_memory_slot *slot;
- unsigned long pfn = 0; /* silence GCC warning */
- unsigned long hva;
- int pfnmap = 0;
- int tsize = BOOK3E_PAGESZ_4K;
-
- /*
- * Translate guest physical to true physical, acquiring
- * a page reference if it is normal, non-reserved memory.
- *
- * gfn_to_memslot() must succeed because otherwise we wouldn't
- * have gotten this far. Eventually we should just pass the slot
- * pointer through from the first lookup.
- */
- slot = gfn_to_memslot(vcpu_e500->vcpu.kvm, gfn);
- hva = gfn_to_hva_memslot(slot, gfn);
-
- if (tlbsel == 1) {
- struct vm_area_struct *vma;
- down_read(&current->mm->mmap_sem);
-
- vma = find_vma(current->mm, hva);
- if (vma && hva >= vma->vm_start &&
- (vma->vm_flags & VM_PFNMAP)) {
- /*
- * This VMA is a physically contiguous region (e.g.
- * /dev/mem) that bypasses normal Linux page
- * management. Find the overlap between the
- * vma and the memslot.
- */
-
- unsigned long start, end;
- unsigned long slot_start, slot_end;
-
- pfnmap = 1;
-
- start = vma->vm_pgoff;
- end = start +
- ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT);
-
- pfn = start + ((hva - vma->vm_start) >> PAGE_SHIFT);
-
- slot_start = pfn - (gfn - slot->base_gfn);
- slot_end = slot_start + slot->npages;
-
- if (start < slot_start)
- start = slot_start;
- if (end > slot_end)
- end = slot_end;
-
- tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >>
- MAS1_TSIZE_SHIFT;
-
- /*
- * e500 doesn't implement the lowest tsize bit,
- * or 1K pages.
- */
- tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1);
-
- /*
- * Now find the largest tsize (up to what the guest
- * requested) that will cover gfn, stay within the
- * range, and for which gfn and pfn are mutually
- * aligned.
- */
-
- for (; tsize > BOOK3E_PAGESZ_4K; tsize -= 2) {
- unsigned long gfn_start, gfn_end, tsize_pages;
- tsize_pages = 1 << (tsize - 2);
-
- gfn_start = gfn & ~(tsize_pages - 1);
- gfn_end = gfn_start + tsize_pages;
-
- if (gfn_start + pfn - gfn < start)
- continue;
- if (gfn_end + pfn - gfn > end)
- continue;
- if ((gfn & (tsize_pages - 1)) !=
- (pfn & (tsize_pages - 1)))
- continue;
-
- gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
- pfn &= ~(tsize_pages - 1);
- break;
- }
- } else if (vma && hva >= vma->vm_start &&
- (vma->vm_flags & VM_HUGETLB)) {
- unsigned long psize = vma_kernel_pagesize(vma);
-
- tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >>
- MAS1_TSIZE_SHIFT;
-
- /*
- * Take the largest page size that satisfies both host
- * and guest mapping
- */
- tsize = min(__ilog2(psize) - 10, tsize);
-
- /*
- * e500 doesn't implement the lowest tsize bit,
- * or 1K pages.
- */
- tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1);
- }
-
- up_read(&current->mm->mmap_sem);
- }
-
- if (likely(!pfnmap)) {
- unsigned long tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT);
- pfn = gfn_to_pfn_memslot(slot, gfn);
- if (is_error_noslot_pfn(pfn)) {
- printk(KERN_ERR "Couldn't get real page for gfn %lx!\n",
- (long)gfn);
- return;
- }
-
- /* Align guest and physical address to page map boundaries */
- pfn &= ~(tsize_pages - 1);
- gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
- }
-
- /* Drop old ref and setup new one. */
- kvmppc_e500_ref_release(ref);
- kvmppc_e500_ref_setup(ref, gtlbe, pfn);
-
- kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
- ref, gvaddr, stlbe);
-
- /* Clear i-cache for new pages */
- kvmppc_mmu_flush_icache(pfn);
-
- /* Drop refcount on page, so that mmu notifiers can clear it */
- kvm_release_pfn_clean(pfn);
-}
-
-/* XXX only map the one-one case, for now use TLB0 */
-static void kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500,
- int esel,
- struct kvm_book3e_206_tlb_entry *stlbe)
-{
- struct kvm_book3e_206_tlb_entry *gtlbe;
- struct tlbe_ref *ref;
-
- gtlbe = get_entry(vcpu_e500, 0, esel);
- ref = &vcpu_e500->gtlb_priv[0][esel].ref;
-
- kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe),
- get_tlb_raddr(gtlbe) >> PAGE_SHIFT,
- gtlbe, 0, stlbe, ref);
-}
-
-/* Caller must ensure that the specified guest TLB entry is safe to insert into
- * the shadow TLB. */
-/* XXX for both one-one and one-to-many , for now use TLB1 */
-static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,
- u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
- struct kvm_book3e_206_tlb_entry *stlbe, int esel)
-{
- struct tlbe_ref *ref;
- unsigned int victim;
-
- victim = vcpu_e500->host_tlb1_nv++;
-
- if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size()))
- vcpu_e500->host_tlb1_nv = 0;
-
- ref = &vcpu_e500->tlb_refs[1][victim];
- kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe, ref);
-
- vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << victim;
- vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP;
- if (vcpu_e500->h2g_tlb1_rmap[victim]) {
- unsigned int idx = vcpu_e500->h2g_tlb1_rmap[victim];
- vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << victim);
- }
- vcpu_e500->h2g_tlb1_rmap[victim] = esel;
-
- return victim;
-}
-
static void kvmppc_recalc_tlb1map_range(struct kvmppc_vcpu_e500 *vcpu_e500)
{
int size = vcpu_e500->gtlb_params[1].entries;
@@ -683,8 +239,8 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500, ulong value)
for (esel = 0; esel < vcpu_e500->gtlb_params[1].entries; esel++)
kvmppc_e500_gtlbe_invalidate(vcpu_e500, 1, esel);
- /* Invalidate all vcpu id mappings */
- kvmppc_e500_tlbil_all(vcpu_e500);
+ /* Invalidate all host shadow mappings */
+ kvmppc_core_flush_tlb(&vcpu_e500->vcpu);
return EMULATE_DONE;
}
@@ -713,8 +269,8 @@ int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, gva_t ea)
kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
}
- /* Invalidate all vcpu id mappings */
- kvmppc_e500_tlbil_all(vcpu_e500);
+ /* Invalidate all host shadow mappings */
+ kvmppc_core_flush_tlb(&vcpu_e500->vcpu);
return EMULATE_DONE;
}
@@ -834,27 +390,11 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, gva_t ea)
return EMULATE_DONE;
}
-/* sesel is for tlb1 only */
-static void write_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
- struct kvm_book3e_206_tlb_entry *gtlbe,
- struct kvm_book3e_206_tlb_entry *stlbe,
- int stlbsel, int sesel)
-{
- int stid;
-
- preempt_disable();
- stid = kvmppc_e500_get_tlb_stid(&vcpu_e500->vcpu, gtlbe);
-
- stlbe->mas1 |= MAS1_TID(stid);
- write_host_tlbe(vcpu_e500, stlbsel, sesel, stlbe);
- preempt_enable();
-}
-
int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
{
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
- struct kvm_book3e_206_tlb_entry *gtlbe, stlbe;
- int tlbsel, esel, stlbsel, sesel;
+ struct kvm_book3e_206_tlb_entry *gtlbe;
+ int tlbsel, esel;
int recal = 0;
tlbsel = get_tlb_tlbsel(vcpu);
@@ -892,40 +432,16 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
/* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
if (tlbe_is_host_safe(vcpu, gtlbe)) {
- u64 eaddr;
- u64 raddr;
+ u64 eaddr = get_tlb_eaddr(gtlbe);
+ u64 raddr = get_tlb_raddr(gtlbe);
- switch (tlbsel) {
- case 0:
- /* TLB0 */
+ if (tlbsel == 0) {
gtlbe->mas1 &= ~MAS1_TSIZE(~0);
gtlbe->mas1 |= MAS1_TSIZE(BOOK3E_PAGESZ_4K);
-
- stlbsel = 0;
- kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
- sesel = 0; /* unused */
-
- break;
-
- case 1:
- /* TLB1 */
- eaddr = get_tlb_eaddr(gtlbe);
- raddr = get_tlb_raddr(gtlbe);
-
- /* Create a 4KB mapping on the host.
- * If the guest wanted a large page,
- * only the first 4KB is mapped here and the rest
- * are mapped on the fly. */
- stlbsel = 1;
- sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr,
- raddr >> PAGE_SHIFT, gtlbe, &stlbe, esel);
- break;
-
- default:
- BUG();
}
- write_stlbe(vcpu_e500, gtlbe, &stlbe, stlbsel, sesel);
+ /* Premap the faulting page */
+ kvmppc_mmu_map(vcpu, eaddr, raddr, index_of(tlbsel, esel));
}
kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS);
@@ -1019,100 +535,14 @@ void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
{
}
-void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
- unsigned int index)
-{
- struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
- struct tlbe_priv *priv;
- struct kvm_book3e_206_tlb_entry *gtlbe, stlbe;
- int tlbsel = tlbsel_of(index);
- int esel = esel_of(index);
- int stlbsel, sesel;
-
- gtlbe = get_entry(vcpu_e500, tlbsel, esel);
-
- switch (tlbsel) {
- case 0:
- stlbsel = 0;
- sesel = 0; /* unused */
- priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
-
- /* Only triggers after clear_tlb_refs */
- if (unlikely(!(priv->ref.flags & E500_TLB_VALID)))
- kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
- else
- kvmppc_e500_setup_stlbe(vcpu, gtlbe, BOOK3E_PAGESZ_4K,
- &priv->ref, eaddr, &stlbe);
- break;
-
- case 1: {
- gfn_t gfn = gpaddr >> PAGE_SHIFT;
-
- stlbsel = 1;
- sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn,
- gtlbe, &stlbe, esel);
- break;
- }
-
- default:
- BUG();
- break;
- }
-
- write_stlbe(vcpu_e500, gtlbe, &stlbe, stlbsel, sesel);
-}
-
-/************* MMU Notifiers *************/
-
-int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
-{
- trace_kvm_unmap_hva(hva);
-
- /*
- * Flush all shadow tlb entries everywhere. This is slow, but
- * we are 100% sure that we catch the to be unmapped page
- */
- kvm_flush_remote_tlbs(kvm);
-
- return 0;
-}
-
-int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
-{
- /* kvm_unmap_hva flushes everything anyways */
- kvm_unmap_hva(kvm, start);
-
- return 0;
-}
-
-int kvm_age_hva(struct kvm *kvm, unsigned long hva)
-{
- /* XXX could be more clever ;) */
- return 0;
-}
-
-int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
-{
- /* XXX could be more clever ;) */
- return 0;
-}
-
-void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
-{
- /* The page will get remapped properly on its next fault */
- kvm_unmap_hva(kvm, hva);
-}
-
/*****************************************/
static void free_gtlb(struct kvmppc_vcpu_e500 *vcpu_e500)
{
int i;
- clear_tlb1_bitmap(vcpu_e500);
+ kvmppc_core_flush_tlb(&vcpu_e500->vcpu);
kfree(vcpu_e500->g2h_tlb1_map);
-
- clear_tlb_refs(vcpu_e500);
kfree(vcpu_e500->gtlb_priv[0]);
kfree(vcpu_e500->gtlb_priv[1]);
@@ -1303,7 +733,7 @@ int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
{
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
kvmppc_recalc_tlb1map_range(vcpu_e500);
- clear_tlb_refs(vcpu_e500);
+ kvmppc_core_flush_tlb(vcpu);
return 0;
}
@@ -1313,37 +743,8 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
int entry_size = sizeof(struct kvm_book3e_206_tlb_entry);
int entries = KVM_E500_TLB0_SIZE + KVM_E500_TLB1_SIZE;
- host_tlb_params[0].entries = mfspr(SPRN_TLB0CFG) & TLBnCFG_N_ENTRY;
- host_tlb_params[1].entries = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
-
- /*
- * This should never happen on real e500 hardware, but is
- * architecturally possible -- e.g. in some weird nested
- * virtualization case.
- */
- if (host_tlb_params[0].entries == 0 ||
- host_tlb_params[1].entries == 0) {
- pr_err("%s: need to know host tlb size\n", __func__);
- return -ENODEV;
- }
-
- host_tlb_params[0].ways = (mfspr(SPRN_TLB0CFG) & TLBnCFG_ASSOC) >>
- TLBnCFG_ASSOC_SHIFT;
- host_tlb_params[1].ways = host_tlb_params[1].entries;
-
- if (!is_power_of_2(host_tlb_params[0].entries) ||
- !is_power_of_2(host_tlb_params[0].ways) ||
- host_tlb_params[0].entries < host_tlb_params[0].ways ||
- host_tlb_params[0].ways == 0) {
- pr_err("%s: bad tlb0 host config: %u entries %u ways\n",
- __func__, host_tlb_params[0].entries,
- host_tlb_params[0].ways);
- return -ENODEV;
- }
-
- host_tlb_params[0].sets =
- host_tlb_params[0].entries / host_tlb_params[0].ways;
- host_tlb_params[1].sets = 1;
+ if (e500_mmu_host_init(vcpu_e500))
+ goto err;
vcpu_e500->gtlb_params[0].entries = KVM_E500_TLB0_SIZE;
vcpu_e500->gtlb_params[1].entries = KVM_E500_TLB1_SIZE;
@@ -1362,18 +763,6 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
vcpu_e500->gtlb_offset[0] = 0;
vcpu_e500->gtlb_offset[1] = KVM_E500_TLB0_SIZE;
- vcpu_e500->tlb_refs[0] =
- kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[0].entries,
- GFP_KERNEL);
- if (!vcpu_e500->tlb_refs[0])
- goto err;
-
- vcpu_e500->tlb_refs[1] =
- kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[1].entries,
- GFP_KERNEL);
- if (!vcpu_e500->tlb_refs[1])
- goto err;
-
vcpu_e500->gtlb_priv[0] = kzalloc(sizeof(struct tlbe_ref) *
vcpu_e500->gtlb_params[0].entries,
GFP_KERNEL);
@@ -1392,12 +781,6 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
if (!vcpu_e500->g2h_tlb1_map)
goto err;
- vcpu_e500->h2g_tlb1_rmap = kzalloc(sizeof(unsigned int) *
- host_tlb_params[1].entries,
- GFP_KERNEL);
- if (!vcpu_e500->h2g_tlb1_rmap)
- goto err;
-
/* Init TLB configuration register */
vcpu->arch.tlbcfg[0] = mfspr(SPRN_TLB0CFG) &
~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
@@ -1416,15 +799,11 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
err:
free_gtlb(vcpu_e500);
- kfree(vcpu_e500->tlb_refs[0]);
- kfree(vcpu_e500->tlb_refs[1]);
return -1;
}
void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)
{
free_gtlb(vcpu_e500);
- kfree(vcpu_e500->h2g_tlb1_rmap);
- kfree(vcpu_e500->tlb_refs[0]);
- kfree(vcpu_e500->tlb_refs[1]);
+ e500_mmu_host_uninit(vcpu_e500);
}
diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c
new file mode 100644
index 000000000000..a222edfb9a9b
--- /dev/null
+++ b/arch/powerpc/kvm/e500_mmu_host.c
@@ -0,0 +1,699 @@
+/*
+ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Yu Liu, yu.liu@freescale.com
+ * Scott Wood, scottwood@freescale.com
+ * Ashish Kalra, ashish.kalra@freescale.com
+ * Varun Sethi, varun.sethi@freescale.com
+ * Alexander Graf, agraf@suse.de
+ *
+ * Description:
+ * This file is based on arch/powerpc/kvm/44x_tlb.c,
+ * by Hollis Blanchard <hollisb@us.ibm.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/highmem.h>
+#include <linux/log2.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/rwsem.h>
+#include <linux/vmalloc.h>
+#include <linux/hugetlb.h>
+#include <asm/kvm_ppc.h>
+
+#include "e500.h"
+#include "trace.h"
+#include "timing.h"
+#include "e500_mmu_host.h"
+
+#define to_htlb1_esel(esel) (host_tlb_params[1].entries - (esel) - 1)
+
+static struct kvmppc_e500_tlb_params host_tlb_params[E500_TLB_NUM];
+
+static inline unsigned int tlb1_max_shadow_size(void)
+{
+ /* reserve one entry for magic page */
+ return host_tlb_params[1].entries - tlbcam_index - 1;
+}
+
+static inline u32 e500_shadow_mas3_attrib(u32 mas3, int usermode)
+{
+ /* Mask off reserved bits. */
+ mas3 &= MAS3_ATTRIB_MASK;
+
+#ifndef CONFIG_KVM_BOOKE_HV
+ if (!usermode) {
+ /* Guest is in supervisor mode,
+ * so we need to translate guest
+ * supervisor permissions into user permissions. */
+ mas3 &= ~E500_TLB_USER_PERM_MASK;
+ mas3 |= (mas3 & E500_TLB_SUPER_PERM_MASK) << 1;
+ }
+ mas3 |= E500_TLB_SUPER_PERM_MASK;
+#endif
+ return mas3;
+}
+
+static inline u32 e500_shadow_mas2_attrib(u32 mas2, int usermode)
+{
+#ifdef CONFIG_SMP
+ return (mas2 & MAS2_ATTRIB_MASK) | MAS2_M;
+#else
+ return mas2 & MAS2_ATTRIB_MASK;
+#endif
+}
+
+/*
+ * writing shadow tlb entry to host TLB
+ */
+static inline void __write_host_tlbe(struct kvm_book3e_206_tlb_entry *stlbe,
+ uint32_t mas0)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ mtspr(SPRN_MAS0, mas0);
+ mtspr(SPRN_MAS1, stlbe->mas1);
+ mtspr(SPRN_MAS2, (unsigned long)stlbe->mas2);
+ mtspr(SPRN_MAS3, (u32)stlbe->mas7_3);
+ mtspr(SPRN_MAS7, (u32)(stlbe->mas7_3 >> 32));
+#ifdef CONFIG_KVM_BOOKE_HV
+ mtspr(SPRN_MAS8, stlbe->mas8);
+#endif
+ asm volatile("isync; tlbwe" : : : "memory");
+
+#ifdef CONFIG_KVM_BOOKE_HV
+ /* Must clear mas8 for other host tlbwe's */
+ mtspr(SPRN_MAS8, 0);
+ isync();
+#endif
+ local_irq_restore(flags);
+
+ trace_kvm_booke206_stlb_write(mas0, stlbe->mas8, stlbe->mas1,
+ stlbe->mas2, stlbe->mas7_3);
+}
+
+/*
+ * Acquire a mas0 with victim hint, as if we just took a TLB miss.
+ *
+ * We don't care about the address we're searching for, other than that it's
+ * in the right set and is not present in the TLB. Using a zero PID and a
+ * userspace address means we don't have to set and then restore MAS5, or
+ * calculate a proper MAS6 value.
+ */
+static u32 get_host_mas0(unsigned long eaddr)
+{
+ unsigned long flags;
+ u32 mas0;
+
+ local_irq_save(flags);
+ mtspr(SPRN_MAS6, 0);
+ asm volatile("tlbsx 0, %0" : : "b" (eaddr & ~CONFIG_PAGE_OFFSET));
+ mas0 = mfspr(SPRN_MAS0);
+ local_irq_restore(flags);
+
+ return mas0;
+}
+
+/* sesel is for tlb1 only */
+static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
+ int tlbsel, int sesel, struct kvm_book3e_206_tlb_entry *stlbe)
+{
+ u32 mas0;
+
+ if (tlbsel == 0) {
+ mas0 = get_host_mas0(stlbe->mas2);
+ __write_host_tlbe(stlbe, mas0);
+ } else {
+ __write_host_tlbe(stlbe,
+ MAS0_TLBSEL(1) |
+ MAS0_ESEL(to_htlb1_esel(sesel)));
+ }
+}
+
+/* sesel is for tlb1 only */
+static void write_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
+ struct kvm_book3e_206_tlb_entry *gtlbe,
+ struct kvm_book3e_206_tlb_entry *stlbe,
+ int stlbsel, int sesel)
+{
+ int stid;
+
+ preempt_disable();
+ stid = kvmppc_e500_get_tlb_stid(&vcpu_e500->vcpu, gtlbe);
+
+ stlbe->mas1 |= MAS1_TID(stid);
+ write_host_tlbe(vcpu_e500, stlbsel, sesel, stlbe);
+ preempt_enable();
+}
+
+#ifdef CONFIG_KVM_E500V2
+/* XXX should be a hook in the gva2hpa translation */
+void kvmppc_map_magic(struct kvm_vcpu *vcpu)
+{
+ struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+ struct kvm_book3e_206_tlb_entry magic;
+ ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
+ unsigned int stid;
+ pfn_t pfn;
+
+ pfn = (pfn_t)virt_to_phys((void *)shared_page) >> PAGE_SHIFT;
+ get_page(pfn_to_page(pfn));
+
+ preempt_disable();
+ stid = kvmppc_e500_get_sid(vcpu_e500, 0, 0, 0, 0);
+
+ magic.mas1 = MAS1_VALID | MAS1_TS | MAS1_TID(stid) |
+ MAS1_TSIZE(BOOK3E_PAGESZ_4K);
+ magic.mas2 = vcpu->arch.magic_page_ea | MAS2_M;
+ magic.mas7_3 = ((u64)pfn << PAGE_SHIFT) |
+ MAS3_SW | MAS3_SR | MAS3_UW | MAS3_UR;
+ magic.mas8 = 0;
+
+ __write_host_tlbe(&magic, MAS0_TLBSEL(1) | MAS0_ESEL(tlbcam_index));
+ preempt_enable();
+}
+#endif
+
+void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
+ int esel)
+{
+ struct kvm_book3e_206_tlb_entry *gtlbe =
+ get_entry(vcpu_e500, tlbsel, esel);
+ struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[tlbsel][esel].ref;
+
+ /* Don't bother with unmapped entries */
+ if (!(ref->flags & E500_TLB_VALID))
+ return;
+
+ if (tlbsel == 1 && ref->flags & E500_TLB_BITMAP) {
+ u64 tmp = vcpu_e500->g2h_tlb1_map[esel];
+ int hw_tlb_indx;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ while (tmp) {
+ hw_tlb_indx = __ilog2_u64(tmp & -tmp);
+ mtspr(SPRN_MAS0,
+ MAS0_TLBSEL(1) |
+ MAS0_ESEL(to_htlb1_esel(hw_tlb_indx)));
+ mtspr(SPRN_MAS1, 0);
+ asm volatile("tlbwe");
+ vcpu_e500->h2g_tlb1_rmap[hw_tlb_indx] = 0;
+ tmp &= tmp - 1;
+ }
+ mb();
+ vcpu_e500->g2h_tlb1_map[esel] = 0;
+ ref->flags &= ~(E500_TLB_BITMAP | E500_TLB_VALID);
+ local_irq_restore(flags);
+ }
+
+ if (tlbsel == 1 && ref->flags & E500_TLB_TLB0) {
+ /*
+ * TLB1 entry is backed by 4k pages. This should happen
+ * rarely and is not worth optimizing. Invalidate everything.
+ */
+ kvmppc_e500_tlbil_all(vcpu_e500);
+ ref->flags &= ~(E500_TLB_TLB0 | E500_TLB_VALID);
+ }
+
+ /* Already invalidated in between */
+ if (!(ref->flags & E500_TLB_VALID))
+ return;
+
+ /* Guest tlbe is backed by at most one host tlbe per shadow pid. */
+ kvmppc_e500_tlbil_one(vcpu_e500, gtlbe);
+
+ /* Mark the TLB as not backed by the host anymore */
+ ref->flags &= ~E500_TLB_VALID;
+}
+
+static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)
+{
+ return tlbe->mas7_3 & (MAS3_SW|MAS3_UW);
+}
+
+static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
+ struct kvm_book3e_206_tlb_entry *gtlbe,
+ pfn_t pfn)
+{
+ ref->pfn = pfn;
+ ref->flags = E500_TLB_VALID;
+
+ if (tlbe_is_writable(gtlbe))
+ kvm_set_pfn_dirty(pfn);
+}
+
+static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
+{
+ if (ref->flags & E500_TLB_VALID) {
+ trace_kvm_booke206_ref_release(ref->pfn, ref->flags);
+ ref->flags = 0;
+ }
+}
+
+static void clear_tlb1_bitmap(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+ if (vcpu_e500->g2h_tlb1_map)
+ memset(vcpu_e500->g2h_tlb1_map, 0,
+ sizeof(u64) * vcpu_e500->gtlb_params[1].entries);
+ if (vcpu_e500->h2g_tlb1_rmap)
+ memset(vcpu_e500->h2g_tlb1_rmap, 0,
+ sizeof(unsigned int) * host_tlb_params[1].entries);
+}
+
+static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+ int tlbsel = 0;
+ int i;
+
+ for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) {
+ struct tlbe_ref *ref =
+ &vcpu_e500->gtlb_priv[tlbsel][i].ref;
+ kvmppc_e500_ref_release(ref);
+ }
+}
+
+static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+ int stlbsel = 1;
+ int i;
+
+ kvmppc_e500_tlbil_all(vcpu_e500);
+
+ for (i = 0; i < host_tlb_params[stlbsel].entries; i++) {
+ struct tlbe_ref *ref =
+ &vcpu_e500->tlb_refs[stlbsel][i];
+ kvmppc_e500_ref_release(ref);
+ }
+
+ clear_tlb_privs(vcpu_e500);
+}
+
+void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu)
+{
+ struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+ clear_tlb_refs(vcpu_e500);
+ clear_tlb1_bitmap(vcpu_e500);
+}
+
+/* TID must be supplied by the caller */
+static void kvmppc_e500_setup_stlbe(
+ struct kvm_vcpu *vcpu,
+ struct kvm_book3e_206_tlb_entry *gtlbe,
+ int tsize, struct tlbe_ref *ref, u64 gvaddr,
+ struct kvm_book3e_206_tlb_entry *stlbe)
+{
+ pfn_t pfn = ref->pfn;
+ u32 pr = vcpu->arch.shared->msr & MSR_PR;
+
+ BUG_ON(!(ref->flags & E500_TLB_VALID));
+
+ /* Force IPROT=0 for all guest mappings. */
+ stlbe->mas1 = MAS1_TSIZE(tsize) | get_tlb_sts(gtlbe) | MAS1_VALID;
+ stlbe->mas2 = (gvaddr & MAS2_EPN) |
+ e500_shadow_mas2_attrib(gtlbe->mas2, pr);
+ stlbe->mas7_3 = ((u64)pfn << PAGE_SHIFT) |
+ e500_shadow_mas3_attrib(gtlbe->mas7_3, pr);
+
+#ifdef CONFIG_KVM_BOOKE_HV
+ stlbe->mas8 = MAS8_TGS | vcpu->kvm->arch.lpid;
+#endif
+}
+
+static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
+ u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
+ int tlbsel, struct kvm_book3e_206_tlb_entry *stlbe,
+ struct tlbe_ref *ref)
+{
+ struct kvm_memory_slot *slot;
+ unsigned long pfn = 0; /* silence GCC warning */
+ unsigned long hva;
+ int pfnmap = 0;
+ int tsize = BOOK3E_PAGESZ_4K;
+
+ /*
+ * Translate guest physical to true physical, acquiring
+ * a page reference if it is normal, non-reserved memory.
+ *
+ * gfn_to_memslot() must succeed because otherwise we wouldn't
+ * have gotten this far. Eventually we should just pass the slot
+ * pointer through from the first lookup.
+ */
+ slot = gfn_to_memslot(vcpu_e500->vcpu.kvm, gfn);
+ hva = gfn_to_hva_memslot(slot, gfn);
+
+ if (tlbsel == 1) {
+ struct vm_area_struct *vma;
+ down_read(&current->mm->mmap_sem);
+
+ vma = find_vma(current->mm, hva);
+ if (vma && hva >= vma->vm_start &&
+ (vma->vm_flags & VM_PFNMAP)) {
+ /*
+ * This VMA is a physically contiguous region (e.g.
+ * /dev/mem) that bypasses normal Linux page
+ * management. Find the overlap between the
+ * vma and the memslot.
+ */
+
+ unsigned long start, end;
+ unsigned long slot_start, slot_end;
+
+ pfnmap = 1;
+
+ start = vma->vm_pgoff;
+ end = start +
+ ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT);
+
+ pfn = start + ((hva - vma->vm_start) >> PAGE_SHIFT);
+
+ slot_start = pfn - (gfn - slot->base_gfn);
+ slot_end = slot_start + slot->npages;
+
+ if (start < slot_start)
+ start = slot_start;
+ if (end > slot_end)
+ end = slot_end;
+
+ tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >>
+ MAS1_TSIZE_SHIFT;
+
+ /*
+ * e500 doesn't implement the lowest tsize bit,
+ * or 1K pages.
+ */
+ tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1);
+
+ /*
+ * Now find the largest tsize (up to what the guest
+ * requested) that will cover gfn, stay within the
+ * range, and for which gfn and pfn are mutually
+ * aligned.
+ */
+
+ for (; tsize > BOOK3E_PAGESZ_4K; tsize -= 2) {
+ unsigned long gfn_start, gfn_end, tsize_pages;
+ tsize_pages = 1 << (tsize - 2);
+
+ gfn_start = gfn & ~(tsize_pages - 1);
+ gfn_end = gfn_start + tsize_pages;
+
+ if (gfn_start + pfn - gfn < start)
+ continue;
+ if (gfn_end + pfn - gfn > end)
+ continue;
+ if ((gfn & (tsize_pages - 1)) !=
+ (pfn & (tsize_pages - 1)))
+ continue;
+
+ gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
+ pfn &= ~(tsize_pages - 1);
+ break;
+ }
+ } else if (vma && hva >= vma->vm_start &&
+ (vma->vm_flags & VM_HUGETLB)) {
+ unsigned long psize = vma_kernel_pagesize(vma);
+
+ tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >>
+ MAS1_TSIZE_SHIFT;
+
+ /*
+ * Take the largest page size that satisfies both host
+ * and guest mapping
+ */
+ tsize = min(__ilog2(psize) - 10, tsize);
+
+ /*
+ * e500 doesn't implement the lowest tsize bit,
+ * or 1K pages.
+ */
+ tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1);
+ }
+
+ up_read(&current->mm->mmap_sem);
+ }
+
+ if (likely(!pfnmap)) {
+ unsigned long tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT);
+ pfn = gfn_to_pfn_memslot(slot, gfn);
+ if (is_error_noslot_pfn(pfn)) {
+ printk(KERN_ERR "Couldn't get real page for gfn %lx!\n",
+ (long)gfn);
+ return -EINVAL;
+ }
+
+ /* Align guest and physical address to page map boundaries */
+ pfn &= ~(tsize_pages - 1);
+ gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
+ }
+
+ /* Drop old ref and setup new one. */
+ kvmppc_e500_ref_release(ref);
+ kvmppc_e500_ref_setup(ref, gtlbe, pfn);
+
+ kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
+ ref, gvaddr, stlbe);
+
+ /* Clear i-cache for new pages */
+ kvmppc_mmu_flush_icache(pfn);
+
+ /* Drop refcount on page, so that mmu notifiers can clear it */
+ kvm_release_pfn_clean(pfn);
+
+ return 0;
+}
+
+/* XXX only map the one-one case, for now use TLB0 */
+static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, int esel,
+ struct kvm_book3e_206_tlb_entry *stlbe)
+{
+ struct kvm_book3e_206_tlb_entry *gtlbe;
+ struct tlbe_ref *ref;
+ int stlbsel = 0;
+ int sesel = 0;
+ int r;
+
+ gtlbe = get_entry(vcpu_e500, 0, esel);
+ ref = &vcpu_e500->gtlb_priv[0][esel].ref;
+
+ r = kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe),
+ get_tlb_raddr(gtlbe) >> PAGE_SHIFT,
+ gtlbe, 0, stlbe, ref);
+ if (r)
+ return r;
+
+ write_stlbe(vcpu_e500, gtlbe, stlbe, stlbsel, sesel);
+
+ return 0;
+}
+
+static int kvmppc_e500_tlb1_map_tlb1(struct kvmppc_vcpu_e500 *vcpu_e500,
+ struct tlbe_ref *ref,
+ int esel)
+{
+ unsigned int sesel = vcpu_e500->host_tlb1_nv++;
+
+ if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size()))
+ vcpu_e500->host_tlb1_nv = 0;
+
+ vcpu_e500->tlb_refs[1][sesel] = *ref;
+ vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel;
+ vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP;
+ if (vcpu_e500->h2g_tlb1_rmap[sesel]) {
+ unsigned int idx = vcpu_e500->h2g_tlb1_rmap[sesel];
+ vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << sesel);
+ }
+ vcpu_e500->h2g_tlb1_rmap[sesel] = esel;
+
+ return sesel;
+}
+
+/* Caller must ensure that the specified guest TLB entry is safe to insert into
+ * the shadow TLB. */
+/* For both one-one and one-to-many */
+static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,
+ u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
+ struct kvm_book3e_206_tlb_entry *stlbe, int esel)
+{
+ struct tlbe_ref ref;
+ int sesel;
+ int r;
+
+ ref.flags = 0;
+ r = kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe,
+ &ref);
+ if (r)
+ return r;
+
+ /* Use TLB0 when we can only map a page with 4k */
+ if (get_tlb_tsize(stlbe) == BOOK3E_PAGESZ_4K) {
+ vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_TLB0;
+ write_stlbe(vcpu_e500, gtlbe, stlbe, 0, 0);
+ return 0;
+ }
+
+ /* Otherwise map into TLB1 */
+ sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, &ref, esel);
+ write_stlbe(vcpu_e500, gtlbe, stlbe, 1, sesel);
+
+ return 0;
+}
+
+void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
+ unsigned int index)
+{
+ struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+ struct tlbe_priv *priv;
+ struct kvm_book3e_206_tlb_entry *gtlbe, stlbe;
+ int tlbsel = tlbsel_of(index);
+ int esel = esel_of(index);
+
+ gtlbe = get_entry(vcpu_e500, tlbsel, esel);
+
+ switch (tlbsel) {
+ case 0:
+ priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
+
+ /* Triggers after clear_tlb_refs or on initial mapping */
+ if (!(priv->ref.flags & E500_TLB_VALID)) {
+ kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
+ } else {
+ kvmppc_e500_setup_stlbe(vcpu, gtlbe, BOOK3E_PAGESZ_4K,
+ &priv->ref, eaddr, &stlbe);
+ write_stlbe(vcpu_e500, gtlbe, &stlbe, 0, 0);
+ }
+ break;
+
+ case 1: {
+ gfn_t gfn = gpaddr >> PAGE_SHIFT;
+ kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn, gtlbe, &stlbe,
+ esel);
+ break;
+ }
+
+ default:
+ BUG();
+ break;
+ }
+}
+
+/************* MMU Notifiers *************/
+
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
+{
+ trace_kvm_unmap_hva(hva);
+
+ /*
+ * Flush all shadow tlb entries everywhere. This is slow, but
+ * we are 100% sure that we catch the to be unmapped page
+ */
+ kvm_flush_remote_tlbs(kvm);
+
+ return 0;
+}
+
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+ /* kvm_unmap_hva flushes everything anyways */
+ kvm_unmap_hva(kvm, start);
+
+ return 0;
+}
+
+int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+ /* XXX could be more clever ;) */
+ return 0;
+}
+
+int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+ /* XXX could be more clever ;) */
+ return 0;
+}
+
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
+{
+ /* The page will get remapped properly on its next fault */
+ kvm_unmap_hva(kvm, hva);
+}
+
+/*****************************************/
+
+int e500_mmu_host_init(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+ host_tlb_params[0].entries = mfspr(SPRN_TLB0CFG) & TLBnCFG_N_ENTRY;
+ host_tlb_params[1].entries = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
+
+ /*
+ * This should never happen on real e500 hardware, but is
+ * architecturally possible -- e.g. in some weird nested
+ * virtualization case.
+ */
+ if (host_tlb_params[0].entries == 0 ||
+ host_tlb_params[1].entries == 0) {
+ pr_err("%s: need to know host tlb size\n", __func__);
+ return -ENODEV;
+ }
+
+ host_tlb_params[0].ways = (mfspr(SPRN_TLB0CFG) & TLBnCFG_ASSOC) >>
+ TLBnCFG_ASSOC_SHIFT;
+ host_tlb_params[1].ways = host_tlb_params[1].entries;
+
+ if (!is_power_of_2(host_tlb_params[0].entries) ||
+ !is_power_of_2(host_tlb_params[0].ways) ||
+ host_tlb_params[0].entries < host_tlb_params[0].ways ||
+ host_tlb_params[0].ways == 0) {
+ pr_err("%s: bad tlb0 host config: %u entries %u ways\n",
+ __func__, host_tlb_params[0].entries,
+ host_tlb_params[0].ways);
+ return -ENODEV;
+ }
+
+ host_tlb_params[0].sets =
+ host_tlb_params[0].entries / host_tlb_params[0].ways;
+ host_tlb_params[1].sets = 1;
+
+ vcpu_e500->tlb_refs[0] =
+ kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[0].entries,
+ GFP_KERNEL);
+ if (!vcpu_e500->tlb_refs[0])
+ goto err;
+
+ vcpu_e500->tlb_refs[1] =
+ kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[1].entries,
+ GFP_KERNEL);
+ if (!vcpu_e500->tlb_refs[1])
+ goto err;
+
+ vcpu_e500->h2g_tlb1_rmap = kzalloc(sizeof(unsigned int) *
+ host_tlb_params[1].entries,
+ GFP_KERNEL);
+ if (!vcpu_e500->h2g_tlb1_rmap)
+ goto err;
+
+ return 0;
+
+err:
+ kfree(vcpu_e500->tlb_refs[0]);
+ kfree(vcpu_e500->tlb_refs[1]);
+ return -EINVAL;
+}
+
+void e500_mmu_host_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+ kfree(vcpu_e500->h2g_tlb1_rmap);
+ kfree(vcpu_e500->tlb_refs[0]);
+ kfree(vcpu_e500->tlb_refs[1]);
+}
diff --git a/arch/powerpc/kvm/e500_mmu_host.h b/arch/powerpc/kvm/e500_mmu_host.h
new file mode 100644
index 000000000000..7624835b76c7
--- /dev/null
+++ b/arch/powerpc/kvm/e500_mmu_host.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef KVM_E500_MMU_HOST_H
+#define KVM_E500_MMU_HOST_H
+
+void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
+ int esel);
+
+int e500_mmu_host_init(struct kvmppc_vcpu_e500 *vcpu_e500);
+void e500_mmu_host_uninit(struct kvmppc_vcpu_e500 *vcpu_e500);
+
+#endif /* KVM_E500_MMU_HOST_H */
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index 9d9cddc5b346..7a73b6f72a8b 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -150,8 +150,6 @@ static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
case SPRN_TBWL: break;
case SPRN_TBWU: break;
- case SPRN_MSSSR0: break;
-
case SPRN_DEC:
vcpu->arch.dec = spr_val;
kvmppc_emulate_dec(vcpu);
@@ -202,9 +200,6 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
case SPRN_PIR:
spr_val = vcpu->vcpu_id;
break;
- case SPRN_MSSSR0:
- spr_val = 0;
- break;
/* Note: mftb and TBRL/TBWL are user-accessible, so
* the guest can always access the real TB anyways.
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 70739a089560..934413cd3a1b 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -237,7 +237,8 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
r = RESUME_HOST;
break;
default:
- BUG();
+ WARN_ON(1);
+ r = RESUME_GUEST;
}
return r;
@@ -305,6 +306,7 @@ int kvm_dev_ioctl_check_extension(long ext)
#ifdef CONFIG_BOOKE
case KVM_CAP_PPC_BOOKE_SREGS:
case KVM_CAP_PPC_BOOKE_WATCHDOG:
+ case KVM_CAP_PPC_EPR:
#else
case KVM_CAP_PPC_SEGSTATE:
case KVM_CAP_PPC_HIOR:
@@ -412,7 +414,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
struct kvm_memory_slot old,
struct kvm_userspace_memory_region *mem,
- int user_alloc)
+ bool user_alloc)
{
return kvmppc_core_prepare_memory_region(kvm, memslot, mem);
}
@@ -420,7 +422,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
void kvm_arch_commit_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
struct kvm_memory_slot old,
- int user_alloc)
+ bool user_alloc)
{
kvmppc_core_commit_memory_region(kvm, mem, old);
}
@@ -720,6 +722,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
for (i = 0; i < 9; ++i)
kvmppc_set_gpr(vcpu, 4 + i, run->papr_hcall.args[i]);
vcpu->arch.hcall_needed = 0;
+#ifdef CONFIG_BOOKE
+ } else if (vcpu->arch.epr_needed) {
+ kvmppc_set_epr(vcpu, run->epr.epr);
+ vcpu->arch.epr_needed = 0;
+#endif
}
r = kvmppc_vcpu_run(run, vcpu);
@@ -761,6 +768,10 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
r = 0;
vcpu->arch.papr_enabled = true;
break;
+ case KVM_CAP_PPC_EPR:
+ r = 0;
+ vcpu->arch.epr_enabled = cap->args[0];
+ break;
#ifdef CONFIG_BOOKE
case KVM_CAP_PPC_BOOKE_WATCHDOG:
r = 0;
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 746e0c895cd7..450433276699 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -4,7 +4,7 @@
subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
-ccflags-$(CONFIG_PPC64) := -mno-minimal-toc
+ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
CFLAGS_REMOVE_code-patching.o = -pg
CFLAGS_REMOVE_feature-fixups.o = -pg
@@ -19,9 +19,7 @@ obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \
checksum_wrappers_64.o hweight_64.o \
copyuser_power7.o string_64.o copypage_power7.o \
memcpy_power7.o
-obj-$(CONFIG_XMON) += sstep.o ldstfp.o
-obj-$(CONFIG_KPROBES) += sstep.o ldstfp.o
-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += sstep.o ldstfp.o
+obj-$(CONFIG_PPC_EMULATE_SSTEP) += sstep.o ldstfp.o
ifeq ($(CONFIG_PPC64),y)
obj-$(CONFIG_SMP) += locks.o
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 3787b61f7d20..cf16b5733eaa 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -4,7 +4,7 @@
subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
-ccflags-$(CONFIG_PPC64) := -mno-minimal-toc
+ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
obj-y := fault.o mem.o pgtable.o gup.o \
init_$(CONFIG_WORD_SIZE).o \
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 3a8489a354e9..229951ffc351 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -249,8 +249,8 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE) || \
defined(CONFIG_PPC_BOOK3S_64))
if (error_code & DSISR_DABRMATCH) {
- /* DABR match */
- do_dabr(regs, address, error_code);
+ /* breakpoint match */
+ do_break(regs, address, error_code);
return 0;
}
#endif
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 3a292be2e079..1b6e1271719f 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -55,6 +55,7 @@
#include <asm/code-patching.h>
#include <asm/fadump.h>
#include <asm/firmware.h>
+#include <asm/tm.h>
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -1171,6 +1172,21 @@ void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize,
DBG_LOW(" sub %ld: hash=%lx, hidx=%lx\n", index, slot, hidx);
ppc_md.hpte_invalidate(slot, vpn, psize, ssize, local);
} pte_iterate_hashed_end();
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ /* Transactions are not aborted by tlbiel, only tlbie.
+ * Without, syncing a page back to a block device w/ PIO could pick up
+ * transactional data (bad!) so we force an abort here. Before the
+ * sync the page will be made read-only, which will flush_hash_page.
+ * BIG ISSUE here: if the kernel uses a page from userspace without
+ * unmapping it first, it may see the speculated version.
+ */
+ if (local && cpu_has_feature(CPU_FTR_TM) &&
+ MSR_TM_ACTIVE(current->thread.regs->msr)) {
+ tm_enable();
+ tm_abort(TM_CAUSE_TLBI);
+ }
+#endif
}
void flush_hash_range(unsigned long number, int local)
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 95a45293e5ac..7e2246fb2f31 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -297,5 +297,10 @@ int __meminit vmemmap_populate(struct page *start_page,
return 0;
}
+
+void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+{
+}
+
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 0dba5066c22a..f1f7409a4183 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -133,6 +133,18 @@ int arch_add_memory(int nid, u64 start, u64 size)
return __add_pages(nid, zone, start_pfn, nr_pages);
}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long nr_pages = size >> PAGE_SHIFT;
+ struct zone *zone;
+
+ zone = page_zone(pfn_to_page(start_pfn));
+ return __remove_pages(zone, start_pfn, nr_pages);
+}
+#endif
#endif /* CONFIG_MEMORY_HOTPLUG */
/*
@@ -195,13 +207,10 @@ void __init do_init_bootmem(void)
min_low_pfn = MEMORY_START >> PAGE_SHIFT;
boot_mapsize = init_bootmem_node(NODE_DATA(0), start >> PAGE_SHIFT, min_low_pfn, max_low_pfn);
- /* Add active regions with valid PFNs */
- for_each_memblock(memory, reg) {
- unsigned long start_pfn, end_pfn;
- start_pfn = memblock_region_memory_base_pfn(reg);
- end_pfn = memblock_region_memory_end_pfn(reg);
- memblock_set_node(0, (phys_addr_t)ULLONG_MAX, 0);
- }
+ /* Place all memblock_regions in the same node and merge contiguous
+ * memblock_regions
+ */
+ memblock_set_node(0, (phys_addr_t)ULLONG_MAX, 0);
/* Add all physical memory to the bootmem map, mark each area
* present.
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 73456c4cec28..751ec7bd5018 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -1,6 +1,6 @@
subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
-ccflags-$(CONFIG_PPC64) := -mno-minimal-toc
+ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
obj-$(CONFIG_OPROFILE) += oprofile.o
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index aa2465e21f1a..65362e98eb26 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -880,8 +880,16 @@ static int power_pmu_add(struct perf_event *event, int ef_flags)
cpuhw->events[n0] = event->hw.config;
cpuhw->flags[n0] = event->hw.event_base;
+ /*
+ * This event may have been disabled/stopped in record_and_restart()
+ * because we exceeded the ->event_limit. If re-starting the event,
+ * clear the ->hw.state (STOPPED and UPTODATE flags), so the user
+ * notification is re-enabled.
+ */
if (!(ef_flags & PERF_EF_START))
event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+ else
+ event->hw.state = 0;
/*
* If group events scheduling transaction was started,
@@ -1305,6 +1313,16 @@ static int power_pmu_event_idx(struct perf_event *event)
return event->hw.idx;
}
+ssize_t power_events_sysfs_show(struct device *dev,
+ struct device_attribute *attr, char *page)
+{
+ struct perf_pmu_events_attr *pmu_attr;
+
+ pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
+
+ return sprintf(page, "event=0x%02llx\n", pmu_attr->id);
+}
+
struct pmu power_pmu = {
.pmu_enable = power_pmu_enable,
.pmu_disable = power_pmu_disable,
@@ -1349,6 +1367,8 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
*/
val = 0;
left = local64_read(&event->hw.period_left) - delta;
+ if (delta == 0)
+ left++;
if (period) {
if (left <= 0) {
left += period;
@@ -1412,11 +1432,8 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs)
return regs->nip;
}
-static bool pmc_overflow(unsigned long val)
+static bool pmc_overflow_power7(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
@@ -1428,7 +1445,15 @@ static bool pmc_overflow(unsigned long val)
* PMCs because a user might set a period of less than 256 and we
* don't want to mistakenly reset them.
*/
- if (pvr_version_is(PVR_POWER7) && ((0x80000000 - val) <= 256))
+ if ((0x80000000 - val) <= 256)
+ return true;
+
+ return false;
+}
+
+static bool pmc_overflow(unsigned long val)
+{
+ if ((int)val < 0)
return true;
return false;
@@ -1439,11 +1464,11 @@ static bool pmc_overflow(unsigned long val)
*/
static void perf_event_interrupt(struct pt_regs *regs)
{
- int i;
+ int i, j;
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
struct perf_event *event;
- unsigned long val;
- int found = 0;
+ unsigned long val[8];
+ int found, active;
int nmi;
if (cpuhw->n_limited)
@@ -1458,33 +1483,53 @@ static void perf_event_interrupt(struct pt_regs *regs)
else
irq_enter();
- for (i = 0; i < cpuhw->n_events; ++i) {
- event = cpuhw->event[i];
- if (!event->hw.idx || is_limited_pmc(event->hw.idx))
+ /* Read all the PMCs since we'll need them a bunch of times */
+ for (i = 0; i < ppmu->n_counter; ++i)
+ val[i] = read_pmc(i + 1);
+
+ /* Try to find what caused the IRQ */
+ found = 0;
+ for (i = 0; i < ppmu->n_counter; ++i) {
+ if (!pmc_overflow(val[i]))
continue;
- val = read_pmc(event->hw.idx);
- if ((int)val < 0) {
- /* event has overflowed */
- found = 1;
- record_and_restart(event, val, regs);
+ if (is_limited_pmc(i + 1))
+ continue; /* these won't generate IRQs */
+ /*
+ * We've found one that's overflowed. For active
+ * counters we need to log this. For inactive
+ * counters, we need to reset it anyway
+ */
+ found = 1;
+ active = 0;
+ for (j = 0; j < cpuhw->n_events; ++j) {
+ event = cpuhw->event[j];
+ if (event->hw.idx == (i + 1)) {
+ active = 1;
+ record_and_restart(event, val[i], regs);
+ break;
+ }
}
+ if (!active)
+ /* reset non active counters that have overflowed */
+ write_pmc(i + 1, 0);
}
-
- /*
- * In case we didn't find and reset the event that caused
- * the interrupt, scan all events and reset any that are
- * negative, to avoid getting continual interrupts.
- * Any that we processed in the previous loop will not be negative.
- */
- if (!found) {
- for (i = 0; i < ppmu->n_counter; ++i) {
- if (is_limited_pmc(i + 1))
+ if (!found && pvr_version_is(PVR_POWER7)) {
+ /* check active counters for special buggy p7 overflow */
+ for (i = 0; i < cpuhw->n_events; ++i) {
+ event = cpuhw->event[i];
+ if (!event->hw.idx || is_limited_pmc(event->hw.idx))
continue;
- val = read_pmc(i + 1);
- if (pmc_overflow(val))
- write_pmc(i + 1, 0);
+ if (pmc_overflow_power7(val[event->hw.idx - 1])) {
+ /* event has overflowed in a buggy way*/
+ found = 1;
+ record_and_restart(event,
+ val[event->hw.idx - 1],
+ regs);
+ }
}
}
+ if ((!found) && printk_ratelimit())
+ printk(KERN_WARNING "Can't find PMC that caused IRQ\n");
/*
* Reset MMCR0 to its normal value. This will set PMXE and
@@ -1537,6 +1582,8 @@ int __cpuinit register_power_pmu(struct power_pmu *pmu)
pr_info("%s performance monitor hardware support registered\n",
pmu->name);
+ power_pmu.attr_groups = ppmu->attr_groups;
+
#ifdef MSR_HV
/*
* Use FCHV to ignore kernel events if MSR.HV is set.
diff --git a/arch/powerpc/perf/e500-pmu.c b/arch/powerpc/perf/e500-pmu.c
index cb2e2949c8d1..fb664929f5da 100644
--- a/arch/powerpc/perf/e500-pmu.c
+++ b/arch/powerpc/perf/e500-pmu.c
@@ -24,6 +24,8 @@ static int e500_generic_events[] = {
[PERF_COUNT_HW_CACHE_MISSES] = 41, /* Data L1 cache reloads */
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 12,
[PERF_COUNT_HW_BRANCH_MISSES] = 15,
+ [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 18,
+ [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 19,
};
#define C(x) PERF_COUNT_HW_CACHE_##x
diff --git a/arch/powerpc/perf/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c
index 2ee01e38d5e2..b554879bd31e 100644
--- a/arch/powerpc/perf/power7-pmu.c
+++ b/arch/powerpc/perf/power7-pmu.c
@@ -51,6 +51,18 @@
#define MMCR1_PMCSEL_MSK 0xff
/*
+ * Power7 event codes.
+ */
+#define PME_PM_CYC 0x1e
+#define PME_PM_GCT_NOSLOT_CYC 0x100f8
+#define PME_PM_CMPLU_STALL 0x4000a
+#define PME_PM_INST_CMPL 0x2
+#define PME_PM_LD_REF_L1 0xc880
+#define PME_PM_LD_MISS_L1 0x400f0
+#define PME_PM_BRU_FIN 0x10068
+#define PME_PM_BRU_MPRED 0x400f6
+
+/*
* Layout of constraint bits:
* 6666555555555544444444443333333333222222222211111111110000000000
* 3210987654321098765432109876543210987654321098765432109876543210
@@ -307,14 +319,14 @@ static void power7_disable_pmc(unsigned int pmc, unsigned long mmcr[])
}
static int power7_generic_events[] = {
- [PERF_COUNT_HW_CPU_CYCLES] = 0x1e,
- [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x100f8, /* GCT_NOSLOT_CYC */
- [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x4000a, /* CMPLU_STALL */
- [PERF_COUNT_HW_INSTRUCTIONS] = 2,
- [PERF_COUNT_HW_CACHE_REFERENCES] = 0xc880, /* LD_REF_L1_LSU*/
- [PERF_COUNT_HW_CACHE_MISSES] = 0x400f0, /* LD_MISS_L1 */
- [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x10068, /* BRU_FIN */
- [PERF_COUNT_HW_BRANCH_MISSES] = 0x400f6, /* BR_MPRED */
+ [PERF_COUNT_HW_CPU_CYCLES] = PME_PM_CYC,
+ [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = PME_PM_GCT_NOSLOT_CYC,
+ [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = PME_PM_CMPLU_STALL,
+ [PERF_COUNT_HW_INSTRUCTIONS] = PME_PM_INST_CMPL,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = PME_PM_LD_REF_L1,
+ [PERF_COUNT_HW_CACHE_MISSES] = PME_PM_LD_MISS_L1,
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = PME_PM_BRU_FIN,
+ [PERF_COUNT_HW_BRANCH_MISSES] = PME_PM_BRU_MPRED,
};
#define C(x) PERF_COUNT_HW_CACHE_##x
@@ -362,6 +374,57 @@ static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
},
};
+
+GENERIC_EVENT_ATTR(cpu-cycles, CYC);
+GENERIC_EVENT_ATTR(stalled-cycles-frontend, GCT_NOSLOT_CYC);
+GENERIC_EVENT_ATTR(stalled-cycles-backend, CMPLU_STALL);
+GENERIC_EVENT_ATTR(instructions, INST_CMPL);
+GENERIC_EVENT_ATTR(cache-references, LD_REF_L1);
+GENERIC_EVENT_ATTR(cache-misses, LD_MISS_L1);
+GENERIC_EVENT_ATTR(branch-instructions, BRU_FIN);
+GENERIC_EVENT_ATTR(branch-misses, BRU_MPRED);
+
+POWER_EVENT_ATTR(CYC, CYC);
+POWER_EVENT_ATTR(GCT_NOSLOT_CYC, GCT_NOSLOT_CYC);
+POWER_EVENT_ATTR(CMPLU_STALL, CMPLU_STALL);
+POWER_EVENT_ATTR(INST_CMPL, INST_CMPL);
+POWER_EVENT_ATTR(LD_REF_L1, LD_REF_L1);
+POWER_EVENT_ATTR(LD_MISS_L1, LD_MISS_L1);
+POWER_EVENT_ATTR(BRU_FIN, BRU_FIN)
+POWER_EVENT_ATTR(BRU_MPRED, BRU_MPRED);
+
+static struct attribute *power7_events_attr[] = {
+ GENERIC_EVENT_PTR(CYC),
+ GENERIC_EVENT_PTR(GCT_NOSLOT_CYC),
+ GENERIC_EVENT_PTR(CMPLU_STALL),
+ GENERIC_EVENT_PTR(INST_CMPL),
+ GENERIC_EVENT_PTR(LD_REF_L1),
+ GENERIC_EVENT_PTR(LD_MISS_L1),
+ GENERIC_EVENT_PTR(BRU_FIN),
+ GENERIC_EVENT_PTR(BRU_MPRED),
+
+ POWER_EVENT_PTR(CYC),
+ POWER_EVENT_PTR(GCT_NOSLOT_CYC),
+ POWER_EVENT_PTR(CMPLU_STALL),
+ POWER_EVENT_PTR(INST_CMPL),
+ POWER_EVENT_PTR(LD_REF_L1),
+ POWER_EVENT_PTR(LD_MISS_L1),
+ POWER_EVENT_PTR(BRU_FIN),
+ POWER_EVENT_PTR(BRU_MPRED),
+ NULL
+};
+
+
+static struct attribute_group power7_pmu_events_group = {
+ .name = "events",
+ .attrs = power7_events_attr,
+};
+
+static const struct attribute_group *power7_pmu_attr_groups[] = {
+ &power7_pmu_events_group,
+ NULL,
+};
+
static struct power_pmu power7_pmu = {
.name = "POWER7",
.n_counter = 6,
@@ -373,6 +436,7 @@ static struct power_pmu power7_pmu = {
.get_alternatives = power7_get_alternatives,
.disable_pmc = power7_disable_pmc,
.flags = PPMU_ALT_SIPR,
+ .attr_groups = power7_pmu_attr_groups,
.n_generic = ARRAY_SIZE(power7_generic_events),
.generic_events = power7_generic_events,
.cache_events = &power7_cache_events,
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 8abf6fb8f410..0effe9f5a1ea 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -252,6 +252,14 @@ config PPC4xx_GPIO
help
Enable gpiolib support for ppc440 based boards
+config PPC4xx_OCM
+ bool "PPC4xx On Chip Memory (OCM) support"
+ depends on 4xx
+ select PPC_LIB_RHEAP
+ help
+ Enable OCM support for PowerPC 4xx platforms with on chip memory,
+ OCM provides the fast place for memory access to improve performance.
+
# 44x specific CPU modules, selected based on the board above.
config 440EP
bool
diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c
index 9f771e05457c..52d57d281724 100644
--- a/arch/powerpc/platforms/512x/clock.c
+++ b/arch/powerpc/platforms/512x/clock.c
@@ -26,6 +26,7 @@
#include <linux/of_platform.h>
#include <asm/mpc5xxx.h>
+#include <asm/mpc5121.h>
#include <asm/clk_interface.h>
#undef CLK_DEBUG
@@ -122,7 +123,7 @@ struct mpc512x_clockctl {
u32 dccr; /* DIU Clk Cnfg Reg */
};
-struct mpc512x_clockctl __iomem *clockctl;
+static struct mpc512x_clockctl __iomem *clockctl;
static int mpc5121_clk_enable(struct clk *clk)
{
@@ -184,7 +185,7 @@ static unsigned long spmf_mult(void)
36, 40, 44, 48,
52, 56, 60, 64
};
- int spmf = (clockctl->spmr >> 24) & 0xf;
+ int spmf = (in_be32(&clockctl->spmr) >> 24) & 0xf;
return spmf_to_mult[spmf];
}
@@ -206,7 +207,7 @@ static unsigned long sysdiv_div_x_2(void)
52, 56, 58, 62,
60, 64, 66,
};
- int sysdiv = (clockctl->scfr2 >> 26) & 0x3f;
+ int sysdiv = (in_be32(&clockctl->scfr2) >> 26) & 0x3f;
return sysdiv_to_div_x_2[sysdiv];
}
@@ -230,7 +231,7 @@ static unsigned long sys_to_ref(unsigned long rate)
static long ips_to_ref(unsigned long rate)
{
- int ips_div = (clockctl->scfr1 >> 23) & 0x7;
+ int ips_div = (in_be32(&clockctl->scfr1) >> 23) & 0x7;
rate *= ips_div; /* csb_clk = ips_clk * ips_div */
rate *= 2; /* sys_clk = csb_clk * 2 */
@@ -284,7 +285,7 @@ static struct clk sys_clk = {
static void diu_clk_calc(struct clk *clk)
{
- int diudiv_x_2 = clockctl->scfr1 & 0xff;
+ int diudiv_x_2 = in_be32(&clockctl->scfr1) & 0xff;
unsigned long rate;
rate = sys_clk.rate;
@@ -311,7 +312,7 @@ static void half_clk_calc(struct clk *clk)
static void generic_div_clk_calc(struct clk *clk)
{
- int div = (clockctl->scfr1 >> clk->div_shift) & 0x7;
+ int div = (in_be32(&clockctl->scfr1) >> clk->div_shift) & 0x7;
clk->rate = clk->parent->rate / div;
}
@@ -329,7 +330,7 @@ static struct clk csb_clk = {
static void e300_clk_calc(struct clk *clk)
{
- int spmf = (clockctl->spmr >> 16) & 0xf;
+ int spmf = (in_be32(&clockctl->spmr) >> 16) & 0xf;
int ratex2 = clk->parent->rate * spmf;
clk->rate = ratex2 / 2;
@@ -551,7 +552,7 @@ static struct clk ac97_clk = {
.calc = ac97_clk_calc,
};
-struct clk *rate_clks[] = {
+static struct clk *rate_clks[] = {
&ref_clk,
&sys_clk,
&diu_clk,
@@ -607,7 +608,7 @@ static void rate_clks_init(void)
* There are two clk enable registers with 32 enable bits each
* psc clocks and device clocks are all stored in dev_clks
*/
-struct clk dev_clks[2][32];
+static struct clk dev_clks[2][32];
/*
* Given a psc number return the dev_clk
@@ -648,12 +649,12 @@ static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np)
out_be32(&clockctl->pccr[pscnum], 0x00020000);
out_be32(&clockctl->pccr[pscnum], 0x00030000);
- if (clockctl->pccr[pscnum] & 0x80) {
+ if (in_be32(&clockctl->pccr[pscnum]) & 0x80) {
clk->rate = spdif_rxclk.rate;
return;
}
- switch ((clockctl->pccr[pscnum] >> 14) & 0x3) {
+ switch ((in_be32(&clockctl->pccr[pscnum]) >> 14) & 0x3) {
case 0:
mclk_src = sys_clk.rate;
break;
@@ -668,7 +669,7 @@ static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np)
break;
}
- mclk_div = ((clockctl->pccr[pscnum] >> 17) & 0x7fff) + 1;
+ mclk_div = ((in_be32(&clockctl->pccr[pscnum]) >> 17) & 0x7fff) + 1;
clk->rate = mclk_src / mclk_div;
}
@@ -680,13 +681,12 @@ static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np)
static void psc_clks_init(void)
{
struct device_node *np;
- const u32 *cell_index;
struct platform_device *ofdev;
+ u32 reg;
for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") {
- cell_index = of_get_property(np, "cell-index", NULL);
- if (cell_index) {
- int pscnum = *cell_index;
+ if (!of_property_read_u32(np, "reg", &reg)) {
+ int pscnum = (reg & 0xf00) >> 8;
struct clk *clk = psc_dev_clk(pscnum);
clk->flags = CLK_HAS_RATE | CLK_HAS_CTRL;
@@ -696,7 +696,7 @@ static void psc_clks_init(void)
* AC97 is special rate clock does
* not go through normal path
*/
- if (strcmp("ac97", np->name) == 0)
+ if (of_device_is_compatible(np, "fsl,mpc5121-psc-ac97"))
clk->rate = ac97_clk.rate;
else
psc_calc_rate(clk, pscnum, np);
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 35f14fda108a..d30235b7e3f7 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -68,10 +68,6 @@ struct fsl_diu_shared_fb {
bool in_use;
};
-void mpc512x_set_monitor_port(enum fsl_diu_monitor_port port)
-{
-}
-
#define DIU_DIV_MASK 0x000000ff
void mpc512x_set_pixel_clock(unsigned int pixclock)
{
@@ -303,7 +299,6 @@ void __init mpc512x_setup_diu(void)
}
}
- diu_ops.set_monitor_port = mpc512x_set_monitor_port;
diu_ops.set_pixel_clock = mpc512x_set_pixel_clock;
diu_ops.valid_monitor_port = mpc512x_valid_monitor_port;
diu_ops.release_bootmem = mpc512x_release_bootmem;
@@ -431,8 +426,38 @@ void __init mpc512x_psc_fifo_init(void)
void __init mpc512x_init(void)
{
- mpc512x_declare_of_platform_devices();
mpc5121_clk_init();
+ mpc512x_declare_of_platform_devices();
mpc512x_restart_init();
mpc512x_psc_fifo_init();
}
+
+/**
+ * mpc512x_cs_config - Setup chip select configuration
+ * @cs: chip select number
+ * @val: chip select configuration value
+ *
+ * Perform chip select configuration for devices on LocalPlus Bus.
+ * Intended to dynamically reconfigure the chip select parameters
+ * for configurable devices on the bus.
+ */
+int mpc512x_cs_config(unsigned int cs, u32 val)
+{
+ static struct mpc512x_lpc __iomem *lpc;
+ struct device_node *np;
+
+ if (cs > 7)
+ return -EINVAL;
+
+ if (!lpc) {
+ np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-lpc");
+ lpc = of_iomap(np, 0);
+ of_node_put(np);
+ if (!lpc)
+ return -ENOMEM;
+ }
+
+ out_be32(&lpc->cs_cfg[cs], val);
+ return 0;
+}
+EXPORT_SYMBOL(mpc512x_cs_config);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
index f9f4537f546d..be7b1aa4d54c 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
@@ -20,9 +20,9 @@
#include <asm/mpc52xx.h>
#include <asm/time.h>
-#include <sysdev/bestcomm/bestcomm.h>
-#include <sysdev/bestcomm/bestcomm_priv.h>
-#include <sysdev/bestcomm/gen_bd.h>
+#include <linux/fsl/bestcomm/bestcomm.h>
+#include <linux/fsl/bestcomm/bestcomm_priv.h>
+#include <linux/fsl/bestcomm/gen_bd.h>
MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
MODULE_DESCRIPTION("MPC5200 LocalPlus FIFO device driver");
diff --git a/arch/powerpc/platforms/82xx/km82xx.c b/arch/powerpc/platforms/82xx/km82xx.c
index cf964e19573a..058cc1895c88 100644
--- a/arch/powerpc/platforms/82xx/km82xx.c
+++ b/arch/powerpc/platforms/82xx/km82xx.c
@@ -18,11 +18,11 @@
#include <linux/fsl_devices.h>
#include <linux/of_platform.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/cpm2.h>
#include <asm/udbg.h>
#include <asm/machdep.h>
-#include <asm/time.h>
+#include <linux/time.h>
#include <asm/mpc8260.h>
#include <asm/prom.h>
@@ -36,7 +36,7 @@ static void __init km82xx_pic_init(void)
struct device_node *np = of_find_compatible_node(NULL, NULL,
"fsl,pq2-pic");
if (!np) {
- printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
+ pr_err("PIC init: can not find cpm-pic node\n");
return;
}
diff --git a/arch/powerpc/platforms/82xx/pq2.c b/arch/powerpc/platforms/82xx/pq2.c
index fb94d10e5a4d..fc8b2d6a7d8d 100644
--- a/arch/powerpc/platforms/82xx/pq2.c
+++ b/arch/powerpc/platforms/82xx/pq2.c
@@ -71,11 +71,11 @@ err:
void __init pq2_init_pci(void)
{
- struct device_node *np = NULL;
+ struct device_node *np;
ppc_md.pci_exclude_device = pq2_pci_exclude_device;
- while ((np = of_find_compatible_node(np, NULL, "fsl,pq2-pci")))
+ for_each_compatible_node(np, NULL, "fsl,pq2-pci")
pq2_pci_add_bridge(np);
}
#endif
diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c
index 89923d723349..bf4c4473abb9 100644
--- a/arch/powerpc/platforms/83xx/km83xx.c
+++ b/arch/powerpc/platforms/83xx/km83xx.c
@@ -28,8 +28,8 @@
#include <linux/of_device.h>
#include <linux/atomic.h>
-#include <asm/time.h>
-#include <asm/io.h>
+#include <linux/time.h>
+#include <linux/io.h>
#include <asm/machdep.h>
#include <asm/ipic.h>
#include <asm/irq.h>
@@ -43,6 +43,82 @@
#include "mpc83xx.h"
#define SVR_REV(svr) (((svr) >> 0) & 0xFFFF) /* Revision field */
+
+static void quirk_mpc8360e_qe_enet10(void)
+{
+ /*
+ * handle mpc8360E Erratum QE_ENET10:
+ * RGMII AC values do not meet the specification
+ */
+ uint svid = mfspr(SPRN_SVR);
+ struct device_node *np_par;
+ struct resource res;
+ void __iomem *base;
+ int ret;
+
+ np_par = of_find_node_by_name(NULL, "par_io");
+ if (np_par == NULL) {
+ pr_warn("%s couldn;t find par_io node\n", __func__);
+ return;
+ }
+ /* Map Parallel I/O ports registers */
+ ret = of_address_to_resource(np_par, 0, &res);
+ if (ret) {
+ pr_warn("%s couldn;t map par_io registers\n", __func__);
+ return;
+ }
+
+ base = ioremap(res.start, res.end - res.start + 1);
+
+ /*
+ * set output delay adjustments to default values according
+ * table 5 in Errata Rev. 5, 9/2011:
+ *
+ * write 0b01 to UCC1 bits 18:19
+ * write 0b01 to UCC2 option 1 bits 4:5
+ * write 0b01 to UCC2 option 2 bits 16:17
+ */
+ clrsetbits_be32((base + 0xa8), 0x0c00f000, 0x04005000);
+
+ /*
+ * set output delay adjustments to default values according
+ * table 3-13 in Reference Manual Rev.3 05/2010:
+ *
+ * write 0b01 to UCC2 option 2 bits 16:17
+ * write 0b0101 to UCC1 bits 20:23
+ * write 0b0101 to UCC2 option 1 bits 24:27
+ */
+ clrsetbits_be32((base + 0xac), 0x0000cff0, 0x00004550);
+
+ if (SVR_REV(svid) == 0x0021) {
+ /*
+ * UCC2 option 1: write 0b1010 to bits 24:27
+ * at address IMMRBAR+0x14AC
+ */
+ clrsetbits_be32((base + 0xac), 0x000000f0, 0x000000a0);
+ } else if (SVR_REV(svid) == 0x0020) {
+ /*
+ * UCC1: write 0b11 to bits 18:19
+ * at address IMMRBAR+0x14A8
+ */
+ setbits32((base + 0xa8), 0x00003000);
+
+ /*
+ * UCC2 option 1: write 0b11 to bits 4:5
+ * at address IMMRBAR+0x14A8
+ */
+ setbits32((base + 0xa8), 0x0c000000);
+
+ /*
+ * UCC2 option 2: write 0b11 to bits 16:17
+ * at address IMMRBAR+0x14AC
+ */
+ setbits32((base + 0xac), 0x0000c000);
+ }
+ iounmap(base);
+ of_node_put(np_par);
+}
+
/* ************************************************************************
*
* Setup the architecture
@@ -72,84 +148,13 @@ static void __init mpc83xx_km_setup_arch(void)
for_each_node_by_name(np, "ucc")
par_io_of_config(np);
- }
-
- np = of_find_compatible_node(NULL, "network", "ucc_geth");
- if (np != NULL) {
- /*
- * handle mpc8360E Erratum QE_ENET10:
- * RGMII AC values do not meet the specification
- */
- uint svid = mfspr(SPRN_SVR);
- struct device_node *np_par;
- struct resource res;
- void __iomem *base;
- int ret;
-
- np_par = of_find_node_by_name(NULL, "par_io");
- if (np_par == NULL) {
- printk(KERN_WARNING "%s couldn;t find par_io node\n",
- __func__);
- return;
- }
- /* Map Parallel I/O ports registers */
- ret = of_address_to_resource(np_par, 0, &res);
- if (ret) {
- printk(KERN_WARNING "%s couldn;t map par_io registers\n",
- __func__);
- return;
- }
-
- base = ioremap(res.start, res.end - res.start + 1);
-
- /*
- * set output delay adjustments to default values according
- * table 5 in Errata Rev. 5, 9/2011:
- *
- * write 0b01 to UCC1 bits 18:19
- * write 0b01 to UCC2 option 1 bits 4:5
- * write 0b01 to UCC2 option 2 bits 16:17
- */
- clrsetbits_be32((base + 0xa8), 0x0c00f000, 0x04005000);
- /*
- * set output delay adjustments to default values according
- * table 3-13 in Reference Manual Rev.3 05/2010:
- *
- * write 0b01 to UCC2 option 2 bits 16:17
- * write 0b0101 to UCC1 bits 20:23
- * write 0b0101 to UCC2 option 1 bits 24:27
- */
- clrsetbits_be32((base + 0xac), 0x0000cff0, 0x00004550);
-
- if (SVR_REV(svid) == 0x0021) {
- /*
- * UCC2 option 1: write 0b1010 to bits 24:27
- * at address IMMRBAR+0x14AC
- */
- clrsetbits_be32((base + 0xac), 0x000000f0, 0x000000a0);
- } else if (SVR_REV(svid) == 0x0020) {
- /*
- * UCC1: write 0b11 to bits 18:19
- * at address IMMRBAR+0x14A8
- */
- setbits32((base + 0xa8), 0x00003000);
-
- /*
- * UCC2 option 1: write 0b11 to bits 4:5
- * at address IMMRBAR+0x14A8
- */
- setbits32((base + 0xa8), 0x0c000000);
-
- /*
- * UCC2 option 2: write 0b11 to bits 16:17
- * at address IMMRBAR+0x14AC
- */
- setbits32((base + 0xac), 0x0000c000);
+ /* Only apply this quirk when par_io is available */
+ np = of_find_compatible_node(NULL, "network", "ucc_geth");
+ if (np != NULL) {
+ quirk_mpc8360e_qe_enet10();
+ of_node_put(np);
}
- iounmap(base);
- of_node_put(np_par);
- of_node_put(np);
}
#endif /* CONFIG_QUICC_ENGINE */
}
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 02d02a09942d..a0dcd577fb0d 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -191,6 +191,13 @@ config SBC8548
help
This option enables support for the Wind River SBC8548 board
+config PPA8548
+ bool "Prodrive PPA8548"
+ help
+ This option enables support for the Prodrive PPA8548 board.
+ select DEFAULT_UIMAGE
+ select HAS_RAPIDIO
+
config GE_IMP3A
bool "GE Intelligent Platforms IMP3A"
select DEFAULT_UIMAGE
@@ -245,6 +252,14 @@ config P4080_DS
help
This option enables support for the P4080 DS board
+config SGY_CTS1000
+ tristate "Servergy CTS-1000 support"
+ select GPIOLIB
+ select OF_GPIO
+ depends on P4080_DS
+ help
+ Enable this to support functionality in Servergy's CTS-1000 systems.
+
endif # PPC32
config P5020_DS
@@ -277,7 +292,6 @@ config P5040_DS
config PPC_QEMU_E500
bool "QEMU generic e500 platform"
- depends on EXPERIMENTAL
select DEFAULT_UIMAGE
help
This option enables support for running as a QEMU guest using
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 76f679cb04a0..07d0dbb141c0 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -25,8 +25,10 @@ obj-$(CONFIG_P5040_DS) += p5040_ds.o corenet_ds.o
obj-$(CONFIG_STX_GP3) += stx_gp3.o
obj-$(CONFIG_TQM85xx) += tqm85xx.o
obj-$(CONFIG_SBC8548) += sbc8548.o
+obj-$(CONFIG_PPA8548) += ppa8548.o
obj-$(CONFIG_SOCRATES) += socrates.o socrates_fpga_pic.o
obj-$(CONFIG_KSI8560) += ksi8560.o
obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o
obj-$(CONFIG_GE_IMP3A) += ge_imp3a.o
obj-$(CONFIG_PPC_QEMU_E500) += qemu_e500.o
+obj-$(CONFIG_SGY_CTS1000) += sgy_cts1000.o
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index bd12588fa252..a7b3621a8df5 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -206,9 +206,7 @@ static void __init mpc85xx_mds_reset_ucc_phys(void)
setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
- for (np = NULL; (np = of_find_compatible_node(np,
- "network",
- "ucc_geth")) != NULL;) {
+ for_each_compatible_node(np, "network", "ucc_geth") {
const unsigned int *prop;
int ucc_num;
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c
index 7328b8d74129..e611e79f23ce 100644
--- a/arch/powerpc/platforms/85xx/p1022_ds.c
+++ b/arch/powerpc/platforms/85xx/p1022_ds.c
@@ -106,42 +106,6 @@
(c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
(c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
-/**
- * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth
- *
- * The Area Descriptor is a 32-bit value that determine which bits in each
- * pixel are to be used for each color.
- */
-static u32 p1022ds_get_pixel_format(enum fsl_diu_monitor_port port,
- unsigned int bits_per_pixel)
-{
- switch (bits_per_pixel) {
- case 32:
- /* 0x88883316 */
- return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8);
- case 24:
- /* 0x88082219 */
- return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8);
- case 16:
- /* 0x65053118 */
- return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0);
- default:
- pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
- return 0;
- }
-}
-
-/**
- * p1022ds_set_gamma_table: update the gamma table, if necessary
- *
- * On some boards, the gamma table for some ports may need to be modified.
- * This is not the case on the P1022DS, so we do nothing.
-*/
-static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port,
- char *gamma_table_base)
-{
-}
-
struct fsl_law {
u32 lawbar;
u32 reserved1;
@@ -215,13 +179,13 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
/* Map the global utilities registers. */
guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
if (!guts_node) {
- pr_err("p1022ds: missing global utilties device node\n");
+ pr_err("p1022ds: missing global utilities device node\n");
return;
}
guts = of_iomap(guts_node, 0);
if (!guts) {
- pr_err("p1022ds: could not map global utilties device\n");
+ pr_err("p1022ds: could not map global utilities device\n");
goto exit;
}
@@ -302,7 +266,7 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
goto exit;
}
cs1_addr = lbc_br_to_phys(ecm, num_laws, br1);
- if (!cs0_addr) {
+ if (!cs1_addr) {
pr_err("p1022ds: could not determine physical address for CS1"
" (BR1=%08x)\n", br1);
goto exit;
@@ -416,14 +380,14 @@ void p1022ds_set_pixel_clock(unsigned int pixclock)
/* Map the global utilities registers. */
guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
if (!guts_np) {
- pr_err("p1022ds: missing global utilties device node\n");
+ pr_err("p1022ds: missing global utilities device node\n");
return;
}
guts = of_iomap(guts_np, 0);
of_node_put(guts_np);
if (!guts) {
- pr_err("p1022ds: could not map global utilties device\n");
+ pr_err("p1022ds: could not map global utilities device\n");
return;
}
@@ -510,8 +474,6 @@ static void __init p1022_ds_setup_arch(void)
ppc_md.progress("p1022_ds_setup_arch()", 0);
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
- diu_ops.get_pixel_format = p1022ds_get_pixel_format;
- diu_ops.set_gamma_table = p1022ds_set_gamma_table;
diu_ops.set_monitor_port = p1022ds_set_monitor_port;
diu_ops.set_pixel_clock = p1022ds_set_pixel_clock;
diu_ops.valid_monitor_port = p1022ds_valid_monitor_port;
diff --git a/arch/powerpc/platforms/85xx/p1022_rdk.c b/arch/powerpc/platforms/85xx/p1022_rdk.c
index 55ffa1cc380c..8c9297112b30 100644
--- a/arch/powerpc/platforms/85xx/p1022_rdk.c
+++ b/arch/powerpc/platforms/85xx/p1022_rdk.c
@@ -35,17 +35,6 @@
#define CLKDVDR_PXCLK_MASK 0x00FF0000
/**
- * p1022rdk_set_monitor_port: switch the output to a different monitor port
- */
-static void p1022rdk_set_monitor_port(enum fsl_diu_monitor_port port)
-{
- if (port != FSL_DIU_PORT_DVI) {
- pr_err("p1022rdk: unsupported monitor port %i\n", port);
- return;
- }
-}
-
-/**
* p1022rdk_set_pixel_clock: program the DIU's clock
*
* @pixclock: the wavelength, in picoseconds, of the clock
@@ -124,7 +113,6 @@ static void __init p1022_rdk_setup_arch(void)
ppc_md.progress("p1022_rdk_setup_arch()", 0);
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
- diu_ops.set_monitor_port = p1022rdk_set_monitor_port;
diu_ops.set_pixel_clock = p1022rdk_set_pixel_clock;
diu_ops.valid_monitor_port = p1022rdk_valid_monitor_port;
#endif
diff --git a/arch/powerpc/platforms/85xx/ppa8548.c b/arch/powerpc/platforms/85xx/ppa8548.c
new file mode 100644
index 000000000000..6a7704b92c3b
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/ppa8548.c
@@ -0,0 +1,98 @@
+/*
+ * ppa8548 setup and early boot code.
+ *
+ * Copyright 2009 Prodrive B.V..
+ *
+ * By Stef van Os (see MAINTAINERS for contact information)
+ *
+ * Based on the SBC8548 support - Copyright 2007 Wind River Systems Inc.
+ * Based on the MPC8548CDS support - Copyright 2005 Freescale Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/seq_file.h>
+#include <linux/of_platform.h>
+
+#include <asm/machdep.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <sysdev/fsl_soc.h>
+
+static void __init ppa8548_pic_init(void)
+{
+ struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
+ 0, 256, " OpenPIC ");
+ BUG_ON(mpic == NULL);
+ mpic_init(mpic);
+}
+
+/*
+ * Setup the architecture
+ */
+static void __init ppa8548_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("ppa8548_setup_arch()", 0);
+}
+
+static void ppa8548_show_cpuinfo(struct seq_file *m)
+{
+ uint32_t svid, phid1;
+
+ svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: Prodrive B.V.\n");
+ seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+ /* Display cpu Pll setting */
+ phid1 = mfspr(SPRN_HID1);
+ seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+}
+
+static struct of_device_id __initdata of_bus_ids[] = {
+ { .name = "soc", },
+ { .type = "soc", },
+ { .compatible = "simple-bus", },
+ { .compatible = "gianfar", },
+ { .compatible = "fsl,srio", },
+ {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+ of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+ return 0;
+}
+machine_device_initcall(ppa8548, declare_of_platform_devices);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init ppa8548_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "ppa8548");
+}
+
+define_machine(ppa8548) {
+ .name = "ppa8548",
+ .probe = ppa8548_probe,
+ .setup_arch = ppa8548_setup_arch,
+ .init_IRQ = ppa8548_pic_init,
+ .show_cpuinfo = ppa8548_show_cpuinfo,
+ .get_irq = mpic_get_irq,
+ .restart = fsl_rstcr_restart,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/qemu_e500.c b/arch/powerpc/platforms/85xx/qemu_e500.c
index f6ea5618c733..5cefc5a9a144 100644
--- a/arch/powerpc/platforms/85xx/qemu_e500.c
+++ b/arch/powerpc/platforms/85xx/qemu_e500.c
@@ -29,9 +29,10 @@
void __init qemu_e500_pic_init(void)
{
struct mpic *mpic;
+ unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU |
+ MPIC_ENABLE_COREINT;
- mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU,
- 0, 256, " OpenPIC ");
+ mpic = mpic_alloc(NULL, 0, flags, 0, 256, " OpenPIC ");
BUG_ON(mpic == NULL);
mpic_init(mpic);
@@ -66,7 +67,7 @@ define_machine(qemu_e500) {
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
- .get_irq = mpic_get_irq,
+ .get_irq = mpic_get_coreint_irq,
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
diff --git a/arch/powerpc/platforms/85xx/sgy_cts1000.c b/arch/powerpc/platforms/85xx/sgy_cts1000.c
new file mode 100644
index 000000000000..611e92f291c4
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sgy_cts1000.c
@@ -0,0 +1,176 @@
+/*
+ * Servergy CTS-1000 Setup
+ *
+ * Maintained by Ben Collins <ben.c@servergy.com>
+ *
+ * Copyright 2012 by Servergy, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of_gpio.h>
+#include <linux/workqueue.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
+
+#include <asm/machdep.h>
+
+static struct device_node *halt_node;
+
+static struct of_device_id child_match[] = {
+ {
+ .compatible = "sgy,gpio-halt",
+ },
+ {},
+};
+
+static void gpio_halt_wfn(struct work_struct *work)
+{
+ /* Likely wont return */
+ orderly_poweroff(true);
+}
+static DECLARE_WORK(gpio_halt_wq, gpio_halt_wfn);
+
+static void gpio_halt_cb(void)
+{
+ enum of_gpio_flags flags;
+ int trigger, gpio;
+
+ if (!halt_node)
+ return;
+
+ gpio = of_get_gpio_flags(halt_node, 0, &flags);
+
+ if (!gpio_is_valid(gpio))
+ return;
+
+ trigger = (flags == OF_GPIO_ACTIVE_LOW);
+
+ printk(KERN_INFO "gpio-halt: triggering GPIO.\n");
+
+ /* Probably wont return */
+ gpio_set_value(gpio, trigger);
+}
+
+/* This IRQ means someone pressed the power button and it is waiting for us
+ * to handle the shutdown/poweroff. */
+static irqreturn_t gpio_halt_irq(int irq, void *__data)
+{
+ printk(KERN_INFO "gpio-halt: shutdown due to power button IRQ.\n");
+ schedule_work(&gpio_halt_wq);
+
+ return IRQ_HANDLED;
+};
+
+static int __devinit gpio_halt_probe(struct platform_device *pdev)
+{
+ enum of_gpio_flags flags;
+ struct device_node *node = pdev->dev.of_node;
+ int gpio, err, irq;
+ int trigger;
+
+ if (!node)
+ return -ENODEV;
+
+ /* If there's no matching child, this isn't really an error */
+ halt_node = of_find_matching_node(node, child_match);
+ if (!halt_node)
+ return 0;
+
+ /* Technically we could just read the first one, but punish
+ * DT writers for invalid form. */
+ if (of_gpio_count(halt_node) != 1)
+ return -EINVAL;
+
+ /* Get the gpio number relative to the dynamic base. */
+ gpio = of_get_gpio_flags(halt_node, 0, &flags);
+ if (!gpio_is_valid(gpio))
+ return -EINVAL;
+
+ err = gpio_request(gpio, "gpio-halt");
+ if (err) {
+ printk(KERN_ERR "gpio-halt: error requesting GPIO %d.\n",
+ gpio);
+ halt_node = NULL;
+ return err;
+ }
+
+ trigger = (flags == OF_GPIO_ACTIVE_LOW);
+
+ gpio_direction_output(gpio, !trigger);
+
+ /* Now get the IRQ which tells us when the power button is hit */
+ irq = irq_of_parse_and_map(halt_node, 0);
+ err = request_irq(irq, gpio_halt_irq, IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING, "gpio-halt", halt_node);
+ if (err) {
+ printk(KERN_ERR "gpio-halt: error requesting IRQ %d for "
+ "GPIO %d.\n", irq, gpio);
+ gpio_free(gpio);
+ halt_node = NULL;
+ return err;
+ }
+
+ /* Register our halt function */
+ ppc_md.halt = gpio_halt_cb;
+ ppc_md.power_off = gpio_halt_cb;
+
+ printk(KERN_INFO "gpio-halt: registered GPIO %d (%d trigger, %d"
+ " irq).\n", gpio, trigger, irq);
+
+ return 0;
+}
+
+static int __devexit gpio_halt_remove(struct platform_device *pdev)
+{
+ if (halt_node) {
+ int gpio = of_get_gpio(halt_node, 0);
+ int irq = irq_of_parse_and_map(halt_node, 0);
+
+ free_irq(irq, halt_node);
+
+ ppc_md.halt = NULL;
+ ppc_md.power_off = NULL;
+
+ gpio_free(gpio);
+
+ halt_node = NULL;
+ }
+
+ return 0;
+}
+
+static struct of_device_id gpio_halt_match[] = {
+ /* We match on the gpio bus itself and scan the children since they
+ * wont be matched against us. We know the bus wont match until it
+ * has been registered too. */
+ {
+ .compatible = "fsl,qoriq-gpio",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, gpio_halt_match);
+
+static struct platform_driver gpio_halt_driver = {
+ .driver = {
+ .name = "gpio-halt",
+ .owner = THIS_MODULE,
+ .of_match_table = gpio_halt_match,
+ },
+ .probe = gpio_halt_probe,
+ .remove = __devexit_p(gpio_halt_remove),
+};
+
+module_platform_driver(gpio_halt_driver);
+
+MODULE_DESCRIPTION("Driver to support GPIO triggered system halt for Servergy CTS-1000 Systems.");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Ben Collins <ben.c@servergy.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
index 04d9d317f741..d479d68fbb2b 100644
--- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
+++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
@@ -236,14 +236,14 @@ void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
/* Map the global utilities registers. */
guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
if (!guts_np) {
- pr_err("mpc8610hpcd: missing global utilties device node\n");
+ pr_err("mpc8610hpcd: missing global utilities device node\n");
return;
}
guts = of_iomap(guts_np, 0);
of_node_put(guts_np);
if (!guts) {
- pr_err("mpc8610hpcd: could not map global utilties device\n");
+ pr_err("mpc8610hpcd: could not map global utilities device\n");
return;
}
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 48a920d51489..52de8bccfb30 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -352,8 +352,6 @@ config OF_RTC
Uses information from the OF or flattened device tree to instantiate
platform devices for direct mapped RTC chips like the DS1742 or DS1743.
-source "arch/powerpc/sysdev/bestcomm/Kconfig"
-
config SIMPLE_GPIO
bool "Support for simple, memory-mapped GPIO controllers"
depends on PPC
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 72afd2888cad..cea2f09c4241 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -76,6 +76,7 @@ config PPC_BOOK3E_64
bool "Embedded processors"
select PPC_FPU # Make it a choice ?
select PPC_SMP_MUXED_IPI
+ select PPC_DOORBELL
endchoice
@@ -208,6 +209,7 @@ config PPC_FSL_BOOK3E
select FSL_EMB_PERFMON
select PPC_SMP_MUXED_IPI
select SYS_SUPPORTS_HUGETLBFS if PHYS_64BIT || PPC64
+ select PPC_DOORBELL
default y if FSL_BOOKE
config PTE_64BIT
@@ -382,4 +384,8 @@ config NOT_COHERENT_CACHE
config CHECK_CACHE_COHERENCY
bool
+config PPC_DOORBELL
+ bool
+ default n
+
endmenu
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 2e7ff0c5cf42..53aaefeb3386 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -124,7 +124,7 @@ config CBE_CPUFREQ
config CBE_CPUFREQ_PMI_ENABLE
bool "CBE frequency scaling using PMI interface"
- depends on CBE_CPUFREQ && EXPERIMENTAL
+ depends on CBE_CPUFREQ
default n
help
Select this, if you want to use the PMI interface
diff --git a/arch/powerpc/platforms/cell/celleb_scc_sio.c b/arch/powerpc/platforms/cell/celleb_scc_sio.c
index 3a16c5b3c464..9c339ec646f5 100644
--- a/arch/powerpc/platforms/cell/celleb_scc_sio.c
+++ b/arch/powerpc/platforms/cell/celleb_scc_sio.c
@@ -42,14 +42,13 @@ static struct {
static int __init txx9_serial_init(void)
{
extern int early_serial_txx9_setup(struct uart_port *port);
- struct device_node *node = NULL;
+ struct device_node *node;
int i;
struct uart_port req;
struct of_irq irq;
struct resource res;
- while ((node = of_find_compatible_node(node,
- "serial", "toshiba,sio-scc")) != NULL) {
+ for_each_compatible_node(node, "serial", "toshiba,sio-scc") {
for (i = 0; i < ARRAY_SIZE(txx9_scc_tab); i++) {
if (!(txx9_serial_bitmap & (1<<i)))
continue;
diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c
index 75d613313f10..b0ec78e8ad68 100644
--- a/arch/powerpc/platforms/cell/spu_callbacks.c
+++ b/arch/powerpc/platforms/cell/spu_callbacks.c
@@ -60,13 +60,12 @@ long spu_sys_callback(struct spu_syscall_block *s)
syscall = spu_syscall_table[s->nr_ret];
-#ifdef DEBUG
- print_symbol(KERN_DEBUG "SPU-syscall %s:", (unsigned long)syscall);
- printk("syscall%ld(%lx, %lx, %lx, %lx, %lx, %lx)\n",
- s->nr_ret,
- s->parm[0], s->parm[1], s->parm[2],
- s->parm[3], s->parm[4], s->parm[5]);
-#endif
+ pr_debug("SPU-syscall "
+ "%pSR:syscall%lld(%llx, %llx, %llx, %llx, %llx, %llx)\n",
+ syscall,
+ s->nr_ret,
+ s->parm[0], s->parm[1], s->parm[2],
+ s->parm[3], s->parm[4], s->parm[5]);
return syscall(s->parm[0], s->parm[1], s->parm[2],
s->parm[3], s->parm[4], s->parm[5]);
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 25db92a8e1cf..49318385d4fa 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -24,6 +24,7 @@
#include <linux/errno.h>
#include <linux/sched.h>
+#include <linux/sched/rt.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 46b7f0232523..e87c19473973 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -48,7 +48,7 @@ config PS3_HTAB_SIZE
system will have optimal runtime performance.
config PS3_DYNAMIC_DMA
- depends on PPC_PS3 && EXPERIMENTAL
+ depends on PPC_PS3
bool "PS3 Platform dynamic DMA page table management"
default n
help
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index d00d7b0a3bda..6cc58201db8c 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -27,6 +27,7 @@
#include <asm/lv1call.h>
#include <asm/ps3fb.h>
+#define PS3_VERBOSE_RESULT
#include "platform.h"
/**
@@ -75,8 +76,9 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long vpn,
if (result) {
/* all entries bolted !*/
- pr_info("%s:result=%d vpn=%lx pa=%lx ix=%lx v=%llx r=%llx\n",
- __func__, result, vpn, pa, hpte_group, hpte_v, hpte_r);
+ pr_info("%s:result=%s vpn=%lx pa=%lx ix=%lx v=%llx r=%llx\n",
+ __func__, ps3_result(result), vpn, pa, hpte_group,
+ hpte_v, hpte_r);
BUG();
}
@@ -125,8 +127,8 @@ static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
&hpte_rs);
if (result) {
- pr_info("%s: res=%d read vpn=%lx slot=%lx psize=%d\n",
- __func__, result, vpn, slot, psize);
+ pr_info("%s: result=%s read vpn=%lx slot=%lx psize=%d\n",
+ __func__, ps3_result(result), vpn, slot, psize);
BUG();
}
@@ -170,8 +172,8 @@ static void ps3_hpte_invalidate(unsigned long slot, unsigned long vpn,
result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, slot, 0, 0);
if (result) {
- pr_info("%s: res=%d vpn=%lx slot=%lx psize=%d\n",
- __func__, result, vpn, slot, psize);
+ pr_info("%s: result=%s vpn=%lx slot=%lx psize=%d\n",
+ __func__, ps3_result(result), vpn, slot, psize);
BUG();
}
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 837cf49357ed..9a0941bc4d31 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -17,6 +17,7 @@ config PPC_PSERIES
select PPC_NATIVE
select PPC_PCI_CHOICE if EXPERT
select ZLIB_DEFLATE
+ select PPC_DOORBELL
default y
config PPC_SPLPAR
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 890622b87c8f..53866e537a92 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -1,4 +1,4 @@
-ccflags-$(CONFIG_PPC64) := -mno-minimal-toc
+ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
ccflags-$(CONFIG_PPC_PSERIES_DEBUG) += -DDEBUG
obj-y := lpar.o hvCall.o nvram.o reconfig.o \
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
index a7648543c59e..0cc0ac07a55d 100644
--- a/arch/powerpc/platforms/pseries/dtl.c
+++ b/arch/powerpc/platforms/pseries/dtl.c
@@ -57,7 +57,7 @@ static u8 dtl_event_mask = 0x7;
*/
static int dtl_buf_entries = N_DISPATCH_LOG;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
struct dtl_ring {
u64 write_index;
struct dtl_entry *write_ptr;
@@ -142,7 +142,7 @@ static u64 dtl_current_index(struct dtl *dtl)
return per_cpu(dtl_rings, dtl->cpu).write_index;
}
-#else /* CONFIG_VIRT_CPU_ACCOUNTING */
+#else /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
static int dtl_start(struct dtl *dtl)
{
@@ -188,7 +188,7 @@ static u64 dtl_current_index(struct dtl *dtl)
{
return lppaca_of(dtl->cpu).dtl_idx;
}
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
static int dtl_enable(struct dtl *dtl)
{
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 9a04322b1736..6b73d6c44f51 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -788,7 +788,6 @@ static void eeh_add_device_late(struct pci_dev *dev)
dev->dev.archdata.edev = edev;
eeh_addr_cache_insert_dev(dev);
- eeh_sysfs_add_device(dev);
}
/**
@@ -815,6 +814,29 @@ void eeh_add_device_tree_late(struct pci_bus *bus)
EXPORT_SYMBOL_GPL(eeh_add_device_tree_late);
/**
+ * eeh_add_sysfs_files - Add EEH sysfs files for the indicated PCI bus
+ * @bus: PCI bus
+ *
+ * This routine must be used to add EEH sysfs files for PCI
+ * devices which are attached to the indicated PCI bus. The PCI bus
+ * is added after system boot through hotplug or dlpar.
+ */
+void eeh_add_sysfs_files(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ eeh_sysfs_add_device(dev);
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+ struct pci_bus *subbus = dev->subordinate;
+ if (subbus)
+ eeh_add_sysfs_files(subbus);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(eeh_add_sysfs_files);
+
+/**
* eeh_remove_device - Undo EEH setup for the indicated pci device
* @dev: pci device to be removed
* @purge_pe: remove the PE or not
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 7b56118f531c..aa3693f7fb27 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -33,6 +33,11 @@ typedef struct {
char * name;
} firmware_feature_t;
+/*
+ * The names in this table match names in rtas/ibm,hypertas-functions. If the
+ * entry ends in a '*', only upto the '*' is matched. Otherwise the entire
+ * string must match.
+ */
static __initdata firmware_feature_t
firmware_features_table[FIRMWARE_MAX_FEATURES] = {
{FW_FEATURE_PFT, "hcall-pft"},
@@ -57,6 +62,7 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = {
{FW_FEATURE_SPLPAR, "hcall-splpar"},
{FW_FEATURE_VPHN, "hcall-vphn"},
{FW_FEATURE_SET_MODE, "hcall-set-mode"},
+ {FW_FEATURE_BEST_ENERGY, "hcall-best-energy-1*"},
};
/* Build up the firmware features bitmask using the contents of
@@ -72,9 +78,20 @@ void __init fw_feature_init(const char *hypertas, unsigned long len)
for (s = hypertas; s < hypertas + len; s += strlen(s) + 1) {
for (i = 0; i < FIRMWARE_MAX_FEATURES; i++) {
+ const char *name = firmware_features_table[i].name;
+ size_t size;
/* check value against table of strings */
- if (!firmware_features_table[i].name ||
- strcmp(firmware_features_table[i].name, s))
+ if (!name)
+ continue;
+ /*
+ * If there is a '*' at the end of name, only check
+ * upto there
+ */
+ size = strlen(name);
+ if (size && name[size - 1] == '*') {
+ if (strncmp(name, s, size - 1))
+ continue;
+ } else if (strcmp(name, s))
continue;
/* we have a match */
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index a38956269fbf..217ca5c75b20 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -127,9 +127,16 @@ static void pseries_mach_cpu_die(void)
get_lppaca()->donate_dedicated_cpu = 1;
while (get_preferred_offline_state(cpu) == CPU_STATE_INACTIVE) {
+ while (!prep_irq_for_idle()) {
+ local_irq_enable();
+ local_irq_disable();
+ }
+
extended_cede_processor(cede_latency_hint);
}
+ local_irq_disable();
+
if (!get_lppaca()->shared_proc)
get_lppaca()->donate_dedicated_cpu = 0;
get_lppaca()->idle = 0;
@@ -137,6 +144,7 @@ static void pseries_mach_cpu_die(void)
if (get_preferred_offline_state(cpu) == CPU_STATE_ONLINE) {
unregister_slb_shadow(hwcpu);
+ hard_irq_disable();
/*
* Call to start_secondary_resume() will not return.
* Kernel stack will be reset and start_secondary()
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index e2685badb5db..1b2a174e7c59 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -382,6 +382,7 @@ static int tce_clearrange_multi_pSeriesLP(unsigned long start_pfn,
rc = plpar_tce_stuff((u64)be32_to_cpu(maprange->liobn),
dma_offset,
0, limit);
+ next += limit * tce_size;
num_tce -= limit;
} while (num_tce > 0 && !rc);
@@ -786,33 +787,68 @@ static u64 find_existing_ddw(struct device_node *pdn)
return dma_addr;
}
+static void __restore_default_window(struct eeh_dev *edev,
+ u32 ddw_restore_token)
+{
+ u32 cfg_addr;
+ u64 buid;
+ int ret;
+
+ /*
+ * Get the config address and phb buid of the PE window.
+ * Rely on eeh to retrieve this for us.
+ * Retrieve them from the pci device, not the node with the
+ * dma-window property
+ */
+ cfg_addr = edev->config_addr;
+ if (edev->pe_config_addr)
+ cfg_addr = edev->pe_config_addr;
+ buid = edev->phb->buid;
+
+ do {
+ ret = rtas_call(ddw_restore_token, 3, 1, NULL, cfg_addr,
+ BUID_HI(buid), BUID_LO(buid));
+ } while (rtas_busy_delay(ret));
+ pr_info("ibm,reset-pe-dma-windows(%x) %x %x %x returned %d\n",
+ ddw_restore_token, cfg_addr, BUID_HI(buid), BUID_LO(buid), ret);
+}
+
static int find_existing_ddw_windows(void)
{
- int len;
struct device_node *pdn;
- struct direct_window *window;
const struct dynamic_dma_window_prop *direct64;
+ const u32 *ddw_extensions;
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);
+ direct64 = of_get_property(pdn, DIRECT64_PROPNAME, NULL);
if (!direct64)
continue;
- window = kzalloc(sizeof(*window), GFP_KERNEL);
- if (!window || len < sizeof(struct dynamic_dma_window_prop)) {
- kfree(window);
- remove_ddw(pdn);
- continue;
- }
+ /*
+ * We need to ensure the IOMMU table is active when we
+ * return from the IOMMU setup so that the common code
+ * can clear the table or find the holes. To that end,
+ * first, remove any existing DDW configuration.
+ */
+ remove_ddw(pdn);
- 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);
+ /*
+ * Second, if we are running on a new enough level of
+ * firmware where the restore API is present, use it to
+ * restore the 32-bit window, which was removed in
+ * create_ddw.
+ * If the API is not present, then create_ddw couldn't
+ * have removed the 32-bit window in the first place, so
+ * removing the DDW configuration should be sufficient.
+ */
+ ddw_extensions = of_get_property(pdn, "ibm,ddw-extensions",
+ NULL);
+ if (ddw_extensions && ddw_extensions[0] > 0)
+ __restore_default_window(of_node_to_eeh_dev(pdn),
+ ddw_extensions[1]);
}
return 0;
@@ -883,32 +919,9 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail,
}
static void restore_default_window(struct pci_dev *dev,
- u32 ddw_restore_token, unsigned long liobn)
+ u32 ddw_restore_token)
{
- struct eeh_dev *edev;
- u32 cfg_addr;
- u64 buid;
- int ret;
-
- /*
- * Get the config address and phb buid of the PE window.
- * Rely on eeh to retrieve this for us.
- * Retrieve them from the pci device, not the node with the
- * dma-window property
- */
- edev = pci_dev_to_eeh_dev(dev);
- cfg_addr = edev->config_addr;
- if (edev->pe_config_addr)
- cfg_addr = edev->pe_config_addr;
- buid = edev->phb->buid;
-
- do {
- ret = rtas_call(ddw_restore_token, 3, 1, NULL, cfg_addr,
- BUID_HI(buid), BUID_LO(buid));
- } while (rtas_busy_delay(ret));
- dev_info(&dev->dev,
- "ibm,reset-pe-dma-windows(%x) %x %x %x returned %d\n",
- ddw_restore_token, cfg_addr, BUID_HI(buid), BUID_LO(buid), ret);
+ __restore_default_window(pci_dev_to_eeh_dev(dev), ddw_restore_token);
}
/*
@@ -1099,7 +1112,7 @@ out_free_prop:
out_restore_window:
if (ddw_restore_token)
- restore_default_window(dev, ddw_restore_token, liobn);
+ restore_default_window(dev, ddw_restore_token);
out_unlock:
mutex_unlock(&direct_window_init_mutex);
@@ -1295,6 +1308,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
switch (action) {
case OF_RECONFIG_DETACH_NODE:
+ remove_ddw(np);
if (pci && pci->iommu_table)
iommu_free_table(pci->iommu_table, np->full_name);
@@ -1307,16 +1321,6 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
}
}
spin_unlock(&direct_window_list_lock);
-
- /*
- * Because the notifier runs after isolation of the
- * slot, we are guaranteed any DMA window has already
- * been revoked and the TCEs have been marked invalid,
- * so we don't need a call to remove_ddw(np). However,
- * if an additional notifier action is added before the
- * isolate call, we should update this code for
- * completeness with such a call.
- */
break;
default:
err = NOTIFY_DONE;
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index 56b864d777ee..0b580f413a9a 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -40,7 +40,8 @@ void pcibios_name_device(struct pci_dev *dev)
*/
dn = pci_device_to_OF_node(dev);
if (dn) {
- const char *loc_code = of_get_property(dn, "ibm,loc-code", 0);
+ const char *loc_code = of_get_property(dn, "ibm,loc-code",
+ NULL);
if (loc_code) {
int loc_len = strlen(loc_code);
if (loc_len < sizeof(dev->dev.name)) {
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index e6cc34a67053..f368668d97b3 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -2,6 +2,7 @@
#define _PSERIES_PLPAR_WRAPPERS_H
#include <linux/string.h>
+#include <linux/irqflags.h>
#include <asm/hvcall.h>
#include <asm/paca.h>
@@ -41,7 +42,14 @@ static inline long extended_cede_processor(unsigned long latency_hint)
u8 old_latency_hint = get_cede_latency_hint();
set_cede_latency_hint(latency_hint);
+
rc = cede_processor();
+#ifdef CONFIG_TRACE_IRQFLAGS
+ /* Ensure that H_CEDE returns with IRQs on */
+ if (WARN_ON(!(mfmsr() & MSR_EE)))
+ __hard_irq_enable();
+#endif
+
set_cede_latency_hint(old_latency_hint);
return rc;
@@ -304,4 +312,14 @@ static inline long disable_reloc_on_exceptions(void) {
return plpar_set_mode(0, 3, 0, 0);
}
+static inline long plapr_set_ciabr(unsigned long ciabr)
+{
+ return plpar_set_mode(0, 1, ciabr, 0);
+}
+
+static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawrx0)
+{
+ return plpar_set_mode(0, 2, dawr0, dawrx0);
+}
+
#endif /* _PSERIES_PLPAR_WRAPPERS_H */
diff --git a/arch/powerpc/platforms/pseries/pseries_energy.c b/arch/powerpc/platforms/pseries/pseries_energy.c
index af281dce510a..a91e6dadda2c 100644
--- a/arch/powerpc/platforms/pseries/pseries_energy.c
+++ b/arch/powerpc/platforms/pseries/pseries_energy.c
@@ -21,6 +21,7 @@
#include <asm/cputhreads.h>
#include <asm/page.h>
#include <asm/hvcall.h>
+#include <asm/firmware.h>
#define MODULE_VERS "1.0"
@@ -32,40 +33,6 @@ static int sysfs_entries;
/* Helper routines */
-/*
- * Routine to detect firmware support for hcall
- * return 1 if H_BEST_ENERGY is supported
- * else return 0
- */
-
-static int check_for_h_best_energy(void)
-{
- struct device_node *rtas = NULL;
- const char *hypertas, *s;
- int length;
- int rc = 0;
-
- rtas = of_find_node_by_path("/rtas");
- if (!rtas)
- return 0;
-
- hypertas = of_get_property(rtas, "ibm,hypertas-functions", &length);
- if (!hypertas) {
- of_node_put(rtas);
- return 0;
- }
-
- /* hypertas will have list of strings with hcall names */
- for (s = hypertas; s < hypertas + length; s += strlen(s) + 1) {
- if (!strncmp("hcall-best-energy-1", s, 19)) {
- rc = 1; /* Found the string */
- break;
- }
- }
- of_node_put(rtas);
- return rc;
-}
-
/* Helper Routines to convert between drc_index to cpu numbers */
static u32 cpu_to_drc_index(int cpu)
@@ -262,7 +229,7 @@ static int __init pseries_energy_init(void)
int cpu, err;
struct device *cpu_dev;
- if (!check_for_h_best_energy()) {
+ if (!firmware_has_feature(FW_FEATURE_BEST_ENERGY)) {
printk(KERN_INFO "Hypercall H_BEST_ENERGY not supported\n");
return 0;
}
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index ca55882465d6..8bcc9ca6682f 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -65,6 +65,7 @@
#include <asm/smp.h>
#include <asm/firmware.h>
#include <asm/eeh.h>
+#include <asm/reg.h>
#include "plpar_wrappers.h"
#include "pseries.h"
@@ -281,7 +282,7 @@ static struct notifier_block pci_dn_reconfig_nb = {
struct kmem_cache *dtl_cache;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
/*
* Allocate space for the dispatch trace log for all possible cpus
* and register the buffers with the hypervisor. This is used for
@@ -332,12 +333,12 @@ static int alloc_dispatch_logs(void)
return 0;
}
-#else /* !CONFIG_VIRT_CPU_ACCOUNTING */
+#else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
static inline int alloc_dispatch_logs(void)
{
return 0;
}
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
static int alloc_dispatch_log_kmem_cache(void)
{
@@ -375,7 +376,7 @@ static void pSeries_idle(void)
* to ever be a problem in practice we can move this into a kernel thread to
* finish off the process later in boot.
*/
-static int __init pSeries_enable_reloc_on_exc(void)
+long pSeries_enable_reloc_on_exc(void)
{
long rc;
unsigned int delay, total_delay = 0;
@@ -397,9 +398,9 @@ static int __init pSeries_enable_reloc_on_exc(void)
mdelay(delay);
}
}
+EXPORT_SYMBOL(pSeries_enable_reloc_on_exc);
-#ifdef CONFIG_KEXEC
-static long pSeries_disable_reloc_on_exc(void)
+long pSeries_disable_reloc_on_exc(void)
{
long rc;
@@ -410,7 +411,9 @@ static long pSeries_disable_reloc_on_exc(void)
mdelay(get_longbusy_msecs(rc));
}
}
+EXPORT_SYMBOL(pSeries_disable_reloc_on_exc);
+#ifdef CONFIG_KEXEC
static void pSeries_machine_kexec(struct kimage *image)
{
long rc;
@@ -498,6 +501,14 @@ static int pseries_set_xdabr(unsigned long dabr, unsigned long dabrx)
return plpar_hcall_norets(H_SET_XDABR, dabr, dabrx);
}
+static int pseries_set_dawr(unsigned long dawr, unsigned long dawrx)
+{
+ /* PAPR says we can't set HYP */
+ dawrx &= ~DAWRX_HYP;
+
+ return plapr_set_watchpoint0(dawr, dawrx);
+}
+
#define CMO_CHARACTERISTICS_TOKEN 44
#define CMO_MAXLENGTH 1026
@@ -604,6 +615,9 @@ static void __init pSeries_init_early(void)
else if (firmware_has_feature(FW_FEATURE_DABR))
ppc_md.set_dabr = pseries_set_dabr;
+ if (firmware_has_feature(FW_FEATURE_SET_MODE))
+ ppc_md.set_dawr = pseries_set_dawr;
+
pSeries_cmo_feature_init();
iommu_init_early_pSeries();
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 80cd0be71e06..12bc8c3663ad 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -42,6 +42,7 @@
#include <asm/vdso_datapage.h>
#include <asm/cputhreads.h>
#include <asm/xics.h>
+#include <asm/dbell.h>
#include "plpar_wrappers.h"
#include "pseries.h"
@@ -54,6 +55,11 @@
*/
static cpumask_var_t of_spin_mask;
+/*
+ * If we multiplex IPI mechanisms, store the appropriate XICS IPI mechanism here
+ */
+static void (*xics_cause_ipi)(int cpu, unsigned long data);
+
/* Query where a cpu is now. Return codes #defined in plpar_wrappers.h */
int smp_query_cpu_stopped(unsigned int pcpu)
{
@@ -137,6 +143,8 @@ static void smp_xics_setup_cpu(int cpu)
{
if (cpu != boot_cpuid)
xics_setup_cpu();
+ if (cpu_has_feature(CPU_FTR_DBELL))
+ doorbell_setup_this_cpu();
if (firmware_has_feature(FW_FEATURE_SPLPAR))
vpa_init(cpu);
@@ -195,6 +203,27 @@ static int smp_pSeries_cpu_bootable(unsigned int nr)
return 1;
}
+/* Only used on systems that support multiple IPI mechanisms */
+static void pSeries_cause_ipi_mux(int cpu, unsigned long data)
+{
+ if (cpumask_test_cpu(cpu, cpu_sibling_mask(smp_processor_id())))
+ doorbell_cause_ipi(cpu, data);
+ else
+ xics_cause_ipi(cpu, data);
+}
+
+static __init int pSeries_smp_probe(void)
+{
+ int ret = xics_smp_probe();
+
+ if (cpu_has_feature(CPU_FTR_DBELL)) {
+ xics_cause_ipi = smp_ops->cause_ipi;
+ smp_ops->cause_ipi = pSeries_cause_ipi_mux;
+ }
+
+ return ret;
+}
+
static struct smp_ops_t pSeries_mpic_smp_ops = {
.message_pass = smp_mpic_message_pass,
.probe = smp_mpic_probe,
@@ -204,8 +233,8 @@ static struct smp_ops_t pSeries_mpic_smp_ops = {
static struct smp_ops_t pSeries_xics_smp_ops = {
.message_pass = NULL, /* Use smp_muxed_ipi_message_pass */
- .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */
- .probe = xics_smp_probe,
+ .cause_ipi = NULL, /* Filled at runtime by pSeries_smp_probe() */
+ .probe = pSeries_smp_probe,
.kick_cpu = smp_pSeries_kick_cpu,
.setup_cpu = smp_xics_setup_cpu,
.cpu_bootable = smp_pSeries_cpu_bootable,
diff --git a/arch/powerpc/platforms/wsp/Makefile b/arch/powerpc/platforms/wsp/Makefile
index 56817ac98fc9..162fc60125a2 100644
--- a/arch/powerpc/platforms/wsp/Makefile
+++ b/arch/powerpc/platforms/wsp/Makefile
@@ -1,4 +1,4 @@
-ccflags-y += -mno-minimal-toc
+ccflags-y += $(NO_MINIMAL_TOC)
obj-y += setup.o ics.o wsp.o
obj-$(CONFIG_PPC_PSR2) += psr2.o
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index a57600b3a4e3..b0a518e97599 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -1,6 +1,6 @@
subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
-ccflags-$(CONFIG_PPC64) := -mno-minimal-toc
+ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y)
@@ -26,7 +26,6 @@ obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o
obj-$(CONFIG_FSL_RIO) += fsl_rio.o fsl_rmu.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
-obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
mv64x60-$(CONFIG_PCI) += mv64x60_pci.o
obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \
mv64x60_udbg.o
@@ -37,6 +36,7 @@ obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
obj-$(CONFIG_PPC_I8259) += i8259.o
obj-$(CONFIG_IPIC) += ipic.o
obj-$(CONFIG_4xx) += uic.o
+obj-$(CONFIG_PPC4xx_OCM) += ppc4xx_ocm.o
obj-$(CONFIG_4xx_SOC) += ppc4xx_soc.o
obj-$(CONFIG_XILINX_VIRTEX) += xilinx_intc.o
obj-$(CONFIG_XILINX_PCI) += xilinx_pci.o
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
index 8cf93f029e17..afc2dbf37011 100644
--- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
+++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
@@ -203,6 +203,7 @@ static struct of_device_id mpc85xx_l2ctlr_of_match[] = {
{ .compatible = "fsl,p1024-l2-cache-controller",},
{ .compatible = "fsl,p1015-l2-cache-controller",},
{ .compatible = "fsl,p1010-l2-cache-controller",},
+ { .compatible = "fsl,bsc9131-l2-cache-controller",},
{},
};
diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/arch/powerpc/sysdev/fsl_ifc.c
index 2a36fd6a9583..d7fc72239144 100644
--- a/arch/powerpc/sysdev/fsl_ifc.c
+++ b/arch/powerpc/sysdev/fsl_ifc.c
@@ -63,7 +63,7 @@ int fsl_ifc_find(phys_addr_t addr_base)
return -ENODEV;
for (i = 0; i < ARRAY_SIZE(fsl_ifc_ctrl_dev->regs->cspr_cs); i++) {
- __be32 cspr = in_be32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr);
+ u32 cspr = in_be32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr);
if (cspr & CSPR_V && (cspr & CSPR_BA) ==
convert_ifc_address(addr_base))
return i;
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index 300be2d06a26..6bc5a546d49f 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -74,8 +74,8 @@ int fsl_lbc_find(phys_addr_t addr_base)
lbc = fsl_lbc_ctrl_dev->regs;
for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
- __be32 br = in_be32(&lbc->bank[i].br);
- __be32 or = in_be32(&lbc->bank[i].or);
+ u32 br = in_be32(&lbc->bank[i].br);
+ u32 or = in_be32(&lbc->bank[i].or);
if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base))
return i;
@@ -97,7 +97,7 @@ EXPORT_SYMBOL(fsl_lbc_find);
int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
{
int bank;
- __be32 br;
+ u32 br;
struct fsl_lbc_regs __iomem *lbc;
bank = fsl_lbc_find(addr_base);
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 6e53d97abd3f..178c99427b1c 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -28,7 +28,7 @@
#include "fsl_msi.h"
#include "fsl_pci.h"
-LIST_HEAD(msi_head);
+static LIST_HEAD(msi_head);
struct fsl_msi_feature {
u32 fsl_pic_ip;
@@ -130,7 +130,7 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
u64 address; /* Physical address of the MSIIR */
int len;
- const u64 *reg;
+ const __be64 *reg;
/* If the msi-address-64 property exists, then use it */
reg = of_get_property(hose->dn, "msi-address-64", &len);
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 92a5915b1827..682084dba19b 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -421,13 +421,16 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus)
}
}
-int __init fsl_add_bridge(struct device_node *dev, int is_primary)
+int __init fsl_add_bridge(struct platform_device *pdev, int is_primary)
{
int len;
struct pci_controller *hose;
struct resource rsrc;
const int *bus_range;
u8 hdr_type, progif;
+ struct device_node *dev;
+
+ dev = pdev->dev.of_node;
if (!of_device_is_available(dev)) {
pr_warning("%s: disabled\n", dev->full_name);
@@ -453,6 +456,8 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary)
if (!hose)
return -ENOMEM;
+ /* set platform device as the parent */
+ hose->parent = &pdev->dev;
hose->first_busno = bus_range ? bus_range[0] : 0x0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
@@ -827,13 +832,18 @@ static const struct of_device_id pci_ids[] = {
{ .compatible = "fsl,mpc8548-pcie", },
{ .compatible = "fsl,mpc8610-pci", },
{ .compatible = "fsl,mpc8641-pcie", },
+ { .compatible = "fsl,qoriq-pcie-v2.1", },
+ { .compatible = "fsl,qoriq-pcie-v2.2", },
+ { .compatible = "fsl,qoriq-pcie-v2.3", },
+ { .compatible = "fsl,qoriq-pcie-v2.4", },
+
+ /*
+ * The following entries are for compatibility with older device
+ * trees.
+ */
{ .compatible = "fsl,p1022-pcie", },
- { .compatible = "fsl,p1010-pcie", },
- { .compatible = "fsl,p1023-pcie", },
{ .compatible = "fsl,p4080-pcie", },
- { .compatible = "fsl,qoriq-pcie-v2.4", },
- { .compatible = "fsl,qoriq-pcie-v2.3", },
- { .compatible = "fsl,qoriq-pcie-v2.2", },
+
{},
};
@@ -880,7 +890,7 @@ static int fsl_pci_probe(struct platform_device *pdev)
#endif
node = pdev->dev.of_node;
- ret = fsl_add_bridge(node, fsl_pci_primary == node);
+ ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
#ifdef CONFIG_SWIOTLB
if (ret == 0) {
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index d078537adece..c495c00c8740 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -91,7 +91,7 @@ struct ccsr_pci {
__be32 pex_err_cap_r3; /* 0x.e34 - PCIE error capture register 0 */
};
-extern int fsl_add_bridge(struct device_node *dev, int is_primary);
+extern int fsl_add_bridge(struct platform_device *pdev, int is_primary);
extern void fsl_pcibios_fixup_bus(struct pci_bus *bus);
extern int mpc83xx_add_bridge(struct device_node *dev);
u64 fsl_pci_immrbar_base(struct pci_controller *hose);
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 97118dc3d285..228cf91b91c1 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -58,10 +58,10 @@ phys_addr_t get_immrbase(void)
if (soc) {
int size;
u32 naddr;
- const u32 *prop = of_get_property(soc, "#address-cells", &size);
+ const __be32 *prop = of_get_property(soc, "#address-cells", &size);
if (prop && size == 4)
- naddr = *prop;
+ naddr = be32_to_cpup(prop);
else
naddr = 2;
diff --git a/arch/powerpc/sysdev/mpc5xxx_clocks.c b/arch/powerpc/sysdev/mpc5xxx_clocks.c
index 96f815a55dfd..5492dc5f56f4 100644
--- a/arch/powerpc/sysdev/mpc5xxx_clocks.c
+++ b/arch/powerpc/sysdev/mpc5xxx_clocks.c
@@ -9,9 +9,9 @@
#include <linux/kernel.h>
#include <linux/of_platform.h>
#include <linux/export.h>
+#include <asm/mpc5xxx.h>
-unsigned int
-mpc5xxx_get_bus_frequency(struct device_node *node)
+unsigned long mpc5xxx_get_bus_frequency(struct device_node *node)
{
struct device_node *np;
const unsigned int *p_bus_freq = NULL;
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 3b2efd41abf2..d30e6a676c89 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -54,7 +54,7 @@ static DEFINE_RAW_SPINLOCK(mpic_lock);
#ifdef CONFIG_PPC32 /* XXX for now */
#ifdef CONFIG_IRQ_ALL_CPUS
-#define distribute_irqs (1)
+#define distribute_irqs (!(mpic->flags & MPIC_SINGLE_DEST_CPU))
#else
#define distribute_irqs (0)
#endif
@@ -1182,6 +1182,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
const char *vers;
const u32 *psrc;
u32 last_irq;
+ u32 fsl_version = 0;
/* Default MPIC search parameters */
static const struct of_device_id __initconst mpic_device_id[] = {
@@ -1314,7 +1315,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
if (mpic->flags & MPIC_FSL) {
- u32 brr1, version;
+ u32 brr1;
int ret;
/*
@@ -1327,7 +1328,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
MPIC_FSL_BRR1);
- version = brr1 & MPIC_FSL_BRR1_VER;
+ fsl_version = brr1 & MPIC_FSL_BRR1_VER;
/* Error interrupt mask register (EIMR) is required for
* handling individual device error interrupts. EIMR
@@ -1342,11 +1343,30 @@ struct mpic * __init mpic_alloc(struct device_node *node,
* is the number of vectors which have been consumed by
* ipis and timer interrupts.
*/
- if (version >= 0x401) {
+ if (fsl_version >= 0x401) {
ret = mpic_setup_error_int(mpic, intvec_top - 12);
if (ret)
return NULL;
}
+
+ }
+
+ /*
+ * EPR is only available starting with v4.0. To support
+ * platforms that don't know the MPIC version at compile-time,
+ * such as qemu-e500, turn off coreint if this MPIC doesn't
+ * support it. Note that we never enable it if it wasn't
+ * requested in the first place.
+ *
+ * This is done outside the MPIC_FSL check, so that we
+ * also disable coreint if the MPIC node doesn't have
+ * an "fsl,mpic" compatible at all. This will be the case
+ * with device trees generated by older versions of QEMU.
+ * fsl_version will be zero if MPIC_FSL is not set.
+ */
+ if (fsl_version < 0x400 && (flags & MPIC_ENABLE_COREINT)) {
+ WARN_ON(ppc_md.get_irq != mpic_get_coreint_irq);
+ ppc_md.get_irq = mpic_get_irq;
}
/* Reset */
diff --git a/arch/powerpc/sysdev/ppc4xx_ocm.c b/arch/powerpc/sysdev/ppc4xx_ocm.c
new file mode 100644
index 000000000000..1b15f93479c3
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_ocm.c
@@ -0,0 +1,415 @@
+/*
+ * PowerPC 4xx OCM memory allocation support
+ *
+ * (C) Copyright 2009, Applied Micro Circuits Corporation
+ * Victor Gallardo (vgallardo@amcc.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <asm/rheap.h>
+#include <asm/ppc4xx_ocm.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+
+#define OCM_DISABLED 0
+#define OCM_ENABLED 1
+
+struct ocm_block {
+ struct list_head list;
+ void __iomem *addr;
+ int size;
+ const char *owner;
+};
+
+/* non-cached or cached region */
+struct ocm_region {
+ phys_addr_t phys;
+ void __iomem *virt;
+
+ int memtotal;
+ int memfree;
+
+ rh_info_t *rh;
+ struct list_head list;
+};
+
+struct ocm_info {
+ int index;
+ int status;
+ int ready;
+
+ phys_addr_t phys;
+
+ int alignment;
+ int memtotal;
+ int cache_size;
+
+ struct ocm_region nc; /* non-cached region */
+ struct ocm_region c; /* cached region */
+};
+
+static struct ocm_info *ocm_nodes;
+static int ocm_count;
+
+static struct ocm_info *ocm_get_node(unsigned int index)
+{
+ if (index >= ocm_count) {
+ printk(KERN_ERR "PPC4XX OCM: invalid index");
+ return NULL;
+ }
+
+ return &ocm_nodes[index];
+}
+
+static int ocm_free_region(struct ocm_region *ocm_reg, const void *addr)
+{
+ struct ocm_block *blk, *tmp;
+ unsigned long offset;
+
+ if (!ocm_reg->virt)
+ return 0;
+
+ list_for_each_entry_safe(blk, tmp, &ocm_reg->list, list) {
+ if (blk->addr == addr) {
+ offset = addr - ocm_reg->virt;
+ ocm_reg->memfree += blk->size;
+ rh_free(ocm_reg->rh, offset);
+ list_del(&blk->list);
+ kfree(blk);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void __init ocm_init_node(int count, struct device_node *node)
+{
+ struct ocm_info *ocm;
+
+ const unsigned int *cell_index;
+ const unsigned int *cache_size;
+ int len;
+
+ struct resource rsrc;
+ int ioflags;
+
+ ocm = ocm_get_node(count);
+
+ cell_index = of_get_property(node, "cell-index", &len);
+ if (!cell_index) {
+ printk(KERN_ERR "PPC4XX OCM: missing cell-index property");
+ return;
+ }
+ ocm->index = *cell_index;
+
+ if (of_device_is_available(node))
+ ocm->status = OCM_ENABLED;
+
+ cache_size = of_get_property(node, "cached-region-size", &len);
+ if (cache_size)
+ ocm->cache_size = *cache_size;
+
+ if (of_address_to_resource(node, 0, &rsrc)) {
+ printk(KERN_ERR "PPC4XX OCM%d: could not get resource address\n",
+ ocm->index);
+ return;
+ }
+
+ ocm->phys = rsrc.start;
+ ocm->memtotal = (rsrc.end - rsrc.start + 1);
+
+ printk(KERN_INFO "PPC4XX OCM%d: %d Bytes (%s)\n",
+ ocm->index, ocm->memtotal,
+ (ocm->status == OCM_DISABLED) ? "disabled" : "enabled");
+
+ if (ocm->status == OCM_DISABLED)
+ return;
+
+ /* request region */
+
+ if (!request_mem_region(ocm->phys, ocm->memtotal, "ppc4xx_ocm")) {
+ printk(KERN_ERR "PPC4XX OCM%d: could not request region\n",
+ ocm->index);
+ return;
+ }
+
+ /* Configure non-cached and cached regions */
+
+ ocm->nc.phys = ocm->phys;
+ ocm->nc.memtotal = ocm->memtotal - ocm->cache_size;
+ ocm->nc.memfree = ocm->nc.memtotal;
+
+ ocm->c.phys = ocm->phys + ocm->nc.memtotal;
+ ocm->c.memtotal = ocm->cache_size;
+ ocm->c.memfree = ocm->c.memtotal;
+
+ if (ocm->nc.memtotal == 0)
+ ocm->nc.phys = 0;
+
+ if (ocm->c.memtotal == 0)
+ ocm->c.phys = 0;
+
+ printk(KERN_INFO "PPC4XX OCM%d: %d Bytes (non-cached)\n",
+ ocm->index, ocm->nc.memtotal);
+
+ printk(KERN_INFO "PPC4XX OCM%d: %d Bytes (cached)\n",
+ ocm->index, ocm->c.memtotal);
+
+ /* ioremap the non-cached region */
+ if (ocm->nc.memtotal) {
+ ioflags = _PAGE_NO_CACHE | _PAGE_GUARDED | _PAGE_EXEC;
+ ocm->nc.virt = __ioremap(ocm->nc.phys, ocm->nc.memtotal,
+ ioflags);
+
+ if (!ocm->nc.virt) {
+ printk(KERN_ERR
+ "PPC4XX OCM%d: failed to ioremap non-cached memory\n",
+ ocm->index);
+ ocm->nc.memfree = 0;
+ return;
+ }
+ }
+
+ /* ioremap the cached region */
+
+ if (ocm->c.memtotal) {
+ ioflags = _PAGE_EXEC;
+ ocm->c.virt = __ioremap(ocm->c.phys, ocm->c.memtotal,
+ ioflags);
+
+ if (!ocm->c.virt) {
+ printk(KERN_ERR
+ "PPC4XX OCM%d: failed to ioremap cached memory\n",
+ ocm->index);
+ ocm->c.memfree = 0;
+ return;
+ }
+ }
+
+ /* Create Remote Heaps */
+
+ ocm->alignment = 4; /* default 4 byte alignment */
+
+ if (ocm->nc.virt) {
+ ocm->nc.rh = rh_create(ocm->alignment);
+ rh_attach_region(ocm->nc.rh, 0, ocm->nc.memtotal);
+ }
+
+ if (ocm->c.virt) {
+ ocm->c.rh = rh_create(ocm->alignment);
+ rh_attach_region(ocm->c.rh, 0, ocm->c.memtotal);
+ }
+
+ INIT_LIST_HEAD(&ocm->nc.list);
+ INIT_LIST_HEAD(&ocm->c.list);
+
+ ocm->ready = 1;
+
+ return;
+}
+
+static int ocm_debugfs_show(struct seq_file *m, void *v)
+{
+ struct ocm_block *blk, *tmp;
+ unsigned int i;
+
+ for (i = 0; i < ocm_count; i++) {
+ struct ocm_info *ocm = ocm_get_node(i);
+
+ if (!ocm || !ocm->ready)
+ continue;
+
+ seq_printf(m, "PPC4XX OCM : %d\n", ocm->index);
+ seq_printf(m, "PhysAddr : 0x%llx\n", ocm->phys);
+ seq_printf(m, "MemTotal : %d Bytes\n", ocm->memtotal);
+ seq_printf(m, "MemTotal(NC) : %d Bytes\n", ocm->nc.memtotal);
+ seq_printf(m, "MemTotal(C) : %d Bytes\n", ocm->c.memtotal);
+
+ seq_printf(m, "\n");
+
+ seq_printf(m, "NC.PhysAddr : 0x%llx\n", ocm->nc.phys);
+ seq_printf(m, "NC.VirtAddr : 0x%p\n", ocm->nc.virt);
+ seq_printf(m, "NC.MemTotal : %d Bytes\n", ocm->nc.memtotal);
+ seq_printf(m, "NC.MemFree : %d Bytes\n", ocm->nc.memfree);
+
+ list_for_each_entry_safe(blk, tmp, &ocm->nc.list, list) {
+ seq_printf(m, "NC.MemUsed : %d Bytes (%s)\n",
+ blk->size, blk->owner);
+ }
+
+ seq_printf(m, "\n");
+
+ seq_printf(m, "C.PhysAddr : 0x%llx\n", ocm->c.phys);
+ seq_printf(m, "C.VirtAddr : 0x%p\n", ocm->c.virt);
+ seq_printf(m, "C.MemTotal : %d Bytes\n", ocm->c.memtotal);
+ seq_printf(m, "C.MemFree : %d Bytes\n", ocm->c.memfree);
+
+ list_for_each_entry_safe(blk, tmp, &ocm->c.list, list) {
+ seq_printf(m, "C.MemUsed : %d Bytes (%s)\n",
+ blk->size, blk->owner);
+ }
+
+ seq_printf(m, "\n");
+ }
+
+ return 0;
+}
+
+static int ocm_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ocm_debugfs_show, NULL);
+}
+
+static const struct file_operations ocm_debugfs_fops = {
+ .open = ocm_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int ocm_debugfs_init(void)
+{
+ struct dentry *junk;
+
+ junk = debugfs_create_dir("ppc4xx_ocm", 0);
+ if (!junk) {
+ printk(KERN_ALERT "debugfs ppc4xx ocm: failed to create dir\n");
+ return -1;
+ }
+
+ if (debugfs_create_file("info", 0644, junk, NULL, &ocm_debugfs_fops)) {
+ printk(KERN_ALERT "debugfs ppc4xx ocm: failed to create file\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void *ppc4xx_ocm_alloc(phys_addr_t *phys, int size, int align,
+ int flags, const char *owner)
+{
+ void __iomem *addr = NULL;
+ unsigned long offset;
+ struct ocm_info *ocm;
+ struct ocm_region *ocm_reg;
+ struct ocm_block *ocm_blk;
+ int i;
+
+ for (i = 0; i < ocm_count; i++) {
+ ocm = ocm_get_node(i);
+
+ if (!ocm || !ocm->ready)
+ continue;
+
+ if (flags == PPC4XX_OCM_NON_CACHED)
+ ocm_reg = &ocm->nc;
+ else
+ ocm_reg = &ocm->c;
+
+ if (!ocm_reg->virt)
+ continue;
+
+ if (align < ocm->alignment)
+ align = ocm->alignment;
+
+ offset = rh_alloc_align(ocm_reg->rh, size, align, NULL);
+
+ if (IS_ERR_VALUE(offset))
+ continue;
+
+ ocm_blk = kzalloc(sizeof(struct ocm_block *), GFP_KERNEL);
+ if (!ocm_blk) {
+ printk(KERN_ERR "PPC4XX OCM: could not allocate ocm block");
+ rh_free(ocm_reg->rh, offset);
+ break;
+ }
+
+ *phys = ocm_reg->phys + offset;
+ addr = ocm_reg->virt + offset;
+ size = ALIGN(size, align);
+
+ ocm_blk->addr = addr;
+ ocm_blk->size = size;
+ ocm_blk->owner = owner;
+ list_add_tail(&ocm_blk->list, &ocm_reg->list);
+
+ ocm_reg->memfree -= size;
+
+ break;
+ }
+
+ return addr;
+}
+
+void ppc4xx_ocm_free(const void *addr)
+{
+ int i;
+
+ if (!addr)
+ return;
+
+ for (i = 0; i < ocm_count; i++) {
+ struct ocm_info *ocm = ocm_get_node(i);
+
+ if (!ocm || !ocm->ready)
+ continue;
+
+ if (ocm_free_region(&ocm->nc, addr) ||
+ ocm_free_region(&ocm->c, addr))
+ return;
+ }
+}
+
+static int __init ppc4xx_ocm_init(void)
+{
+ struct device_node *np;
+ int count;
+
+ count = 0;
+ for_each_compatible_node(np, NULL, "ibm,ocm")
+ count++;
+
+ if (!count)
+ return 0;
+
+ ocm_nodes = kzalloc((count * sizeof(struct ocm_info)), GFP_KERNEL);
+ if (!ocm_nodes) {
+ printk(KERN_ERR "PPC4XX OCM: failed to allocate OCM nodes!\n");
+ return -ENOMEM;
+ }
+
+ ocm_count = count;
+ count = 0;
+
+ for_each_compatible_node(np, NULL, "ibm,ocm") {
+ ocm_init_node(count, np);
+ count++;
+ }
+
+ ocm_debugfs_init();
+
+ return 0;
+}
+
+arch_initcall(ppc4xx_ocm_init);
diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c
index c782f85cf7e4..936575d99c5c 100644
--- a/arch/powerpc/sysdev/xics/ics-rtas.c
+++ b/arch/powerpc/sysdev/xics/ics-rtas.c
@@ -213,7 +213,7 @@ static int ics_rtas_host_match(struct ics *ics, struct device_node *node)
return !of_device_is_compatible(node, "chrp,iic");
}
-int ics_rtas_init(void)
+__init int ics_rtas_init(void)
{
ibm_get_xive = rtas_token("ibm,get-xive");
ibm_set_xive = rtas_token("ibm,set-xive");
diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile
index b49fdbd15808..1278788d96e3 100644
--- a/arch/powerpc/xmon/Makefile
+++ b/arch/powerpc/xmon/Makefile
@@ -4,7 +4,7 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
GCOV_PROFILE := n
-ccflags-$(CONFIG_PPC64) := -mno-minimal-toc
+ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
obj-y += xmon.o nonstdio.o
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 1f8d2f10a432..13f85defabed 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -43,6 +43,7 @@
#include <asm/setjmp.h>
#include <asm/reg.h>
#include <asm/debug.h>
+#include <asm/hw_breakpoint.h>
#ifdef CONFIG_PPC64
#include <asm/hvcall.h>
@@ -607,7 +608,7 @@ static int xmon_sstep(struct pt_regs *regs)
return 1;
}
-static int xmon_dabr_match(struct pt_regs *regs)
+static int xmon_break_match(struct pt_regs *regs)
{
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
return 0;
@@ -740,8 +741,14 @@ static void insert_bpts(void)
static void insert_cpu_bpts(void)
{
- if (dabr.enabled)
- set_dabr(dabr.address | (dabr.enabled & 7), DABRX_ALL);
+ struct arch_hw_breakpoint brk;
+
+ if (dabr.enabled) {
+ brk.address = dabr.address;
+ brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
+ brk.len = 8;
+ set_breakpoint(&brk);
+ }
if (iabr && cpu_has_feature(CPU_FTR_IABR))
mtspr(SPRN_IABR, iabr->address
| (iabr->enabled & (BP_IABR|BP_IABR_TE)));
@@ -769,7 +776,7 @@ static void remove_bpts(void)
static void remove_cpu_bpts(void)
{
- set_dabr(0, 0);
+ hw_breakpoint_disable();
if (cpu_has_feature(CPU_FTR_IABR))
mtspr(SPRN_IABR, 0);
}
@@ -1138,7 +1145,7 @@ bpt_cmds(void)
printf(badaddr);
break;
}
- dabr.address &= ~7;
+ dabr.address &= ~HW_BRK_TYPE_DABR;
dabr.enabled = mode | BP_DABR;
}
break;
@@ -2917,7 +2924,7 @@ static void xmon_init(int enable)
__debugger_bpt = xmon_bpt;
__debugger_sstep = xmon_sstep;
__debugger_iabr_match = xmon_iabr_match;
- __debugger_dabr_match = xmon_dabr_match;
+ __debugger_break_match = xmon_break_match;
__debugger_fault_handler = xmon_fault_handler;
} else {
__debugger = NULL;
@@ -2925,7 +2932,7 @@ static void xmon_init(int enable)
__debugger_bpt = NULL;
__debugger_sstep = NULL;
__debugger_iabr_match = NULL;
- __debugger_dabr_match = NULL;
+ __debugger_break_match = NULL;
__debugger_fault_handler = NULL;
}
}
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index b5ea38c25647..f09ae7b0b4c5 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -60,86 +60,88 @@ config PCI_QUIRKS
config S390
def_bool y
- select USE_GENERIC_SMP_HELPERS if SMP
- select GENERIC_CPU_DEVICES if !SMP
- select HAVE_SYSCALL_WRAPPERS
- select HAVE_FUNCTION_TRACER
- select HAVE_FUNCTION_TRACE_MCOUNT_TEST
- select HAVE_FTRACE_MCOUNT_RECORD
- select HAVE_C_RECORDMCOUNT
- select HAVE_SYSCALL_TRACEPOINTS
- select SYSCTL_EXCEPTION_TRACE
- select HAVE_DYNAMIC_FTRACE
- select HAVE_FUNCTION_GRAPH_TRACER
- select HAVE_REGS_AND_STACK_ACCESS_API
- select HAVE_OPROFILE
- select HAVE_KPROBES
- select HAVE_KRETPROBES
- select HAVE_KVM if 64BIT
- select HAVE_ARCH_TRACEHOOK
- select INIT_ALL_POSSIBLE
- select HAVE_IRQ_WORK
- select HAVE_PERF_EVENTS
- select ARCH_HAVE_NMI_SAFE_CMPXCHG
- select HAVE_DEBUG_KMEMLEAK
- select HAVE_KERNEL_GZIP
- select HAVE_KERNEL_BZIP2
- select HAVE_KERNEL_LZMA
- select HAVE_KERNEL_LZO
- select HAVE_KERNEL_XZ
- select HAVE_ARCH_MUTEX_CPU_RELAX
- select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
- select HAVE_BPF_JIT if 64BIT && PACK_STACK
- select ARCH_SAVE_PAGE_KEYS if HIBERNATION
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
- select HAVE_MEMBLOCK
- select HAVE_MEMBLOCK_NODE_MAP
- select HAVE_CMPXCHG_LOCAL
- select HAVE_CMPXCHG_DOUBLE
- select HAVE_ALIGNED_STRUCT_PAGE if SLUB
- select HAVE_VIRT_CPU_ACCOUNTING
- select VIRT_CPU_ACCOUNTING
select ARCH_DISCARD_MEMBLOCK
- select BUILDTIME_EXTABLE_SORT
- select ARCH_INLINE_SPIN_TRYLOCK
- select ARCH_INLINE_SPIN_TRYLOCK_BH
- select ARCH_INLINE_SPIN_LOCK
- select ARCH_INLINE_SPIN_LOCK_BH
- select ARCH_INLINE_SPIN_LOCK_IRQ
- select ARCH_INLINE_SPIN_LOCK_IRQSAVE
- select ARCH_INLINE_SPIN_UNLOCK
- select ARCH_INLINE_SPIN_UNLOCK_BH
- select ARCH_INLINE_SPIN_UNLOCK_IRQ
- select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE
- select ARCH_INLINE_READ_TRYLOCK
+ select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+ select ARCH_HAVE_NMI_SAFE_CMPXCHG
select ARCH_INLINE_READ_LOCK
select ARCH_INLINE_READ_LOCK_BH
select ARCH_INLINE_READ_LOCK_IRQ
select ARCH_INLINE_READ_LOCK_IRQSAVE
+ select ARCH_INLINE_READ_TRYLOCK
select ARCH_INLINE_READ_UNLOCK
select ARCH_INLINE_READ_UNLOCK_BH
select ARCH_INLINE_READ_UNLOCK_IRQ
select ARCH_INLINE_READ_UNLOCK_IRQRESTORE
- select ARCH_INLINE_WRITE_TRYLOCK
+ select ARCH_INLINE_SPIN_LOCK
+ select ARCH_INLINE_SPIN_LOCK_BH
+ select ARCH_INLINE_SPIN_LOCK_IRQ
+ select ARCH_INLINE_SPIN_LOCK_IRQSAVE
+ select ARCH_INLINE_SPIN_TRYLOCK
+ select ARCH_INLINE_SPIN_TRYLOCK_BH
+ select ARCH_INLINE_SPIN_UNLOCK
+ select ARCH_INLINE_SPIN_UNLOCK_BH
+ select ARCH_INLINE_SPIN_UNLOCK_IRQ
+ select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE
select ARCH_INLINE_WRITE_LOCK
select ARCH_INLINE_WRITE_LOCK_BH
select ARCH_INLINE_WRITE_LOCK_IRQ
select ARCH_INLINE_WRITE_LOCK_IRQSAVE
+ select ARCH_INLINE_WRITE_TRYLOCK
select ARCH_INLINE_WRITE_UNLOCK
select ARCH_INLINE_WRITE_UNLOCK_BH
select ARCH_INLINE_WRITE_UNLOCK_IRQ
select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
- select HAVE_UID16 if 32BIT
+ select ARCH_SAVE_PAGE_KEYS if HIBERNATION
select ARCH_WANT_IPC_PARSE_VERSION
- select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT
+ select BUILDTIME_EXTABLE_SORT
+ select CLONE_BACKWARDS2
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_CPU_DEVICES if !SMP
+ select GENERIC_KERNEL_THREAD
select GENERIC_SMP_IDLE_THREAD
select GENERIC_TIME_VSYSCALL_OLD
- select GENERIC_CLOCKEVENTS
- select KTIME_SCALAR if 32BIT
+ select HAVE_ALIGNED_STRUCT_PAGE if SLUB
+ select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
+ select HAVE_ARCH_MUTEX_CPU_RELAX
select HAVE_ARCH_SECCOMP_FILTER
+ select HAVE_ARCH_TRACEHOOK
+ select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT
+ select HAVE_BPF_JIT if 64BIT && PACK_STACK
+ select HAVE_CMPXCHG_DOUBLE
+ select HAVE_CMPXCHG_LOCAL
+ select HAVE_C_RECORDMCOUNT
+ select HAVE_DEBUG_KMEMLEAK
+ select HAVE_DYNAMIC_FTRACE
+ select HAVE_FTRACE_MCOUNT_RECORD
+ select HAVE_FUNCTION_GRAPH_TRACER
+ select HAVE_FUNCTION_TRACER
+ select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+ select HAVE_KERNEL_BZIP2
+ select HAVE_KERNEL_GZIP
+ select HAVE_KERNEL_LZMA
+ select HAVE_KERNEL_LZO
+ select HAVE_KERNEL_XZ
+ select HAVE_KPROBES
+ select HAVE_KRETPROBES
+ select HAVE_KVM if 64BIT
+ select HAVE_MEMBLOCK
+ select HAVE_MEMBLOCK_NODE_MAP
select HAVE_MOD_ARCH_SPECIFIC
+ select HAVE_OPROFILE
+ select HAVE_PERF_EVENTS
+ select HAVE_REGS_AND_STACK_ACCESS_API
+ select HAVE_SYSCALL_TRACEPOINTS
+ select HAVE_SYSCALL_WRAPPERS
+ select HAVE_UID16 if 32BIT
+ select HAVE_VIRT_CPU_ACCOUNTING
+ select INIT_ALL_POSSIBLE
+ select KTIME_SCALAR if 32BIT
select MODULES_USE_ELF_RELA
- select CLONE_BACKWARDS2
+ select OLD_SIGSUSPEND3
+ select OLD_SIGACTION
+ select SYSCTL_EXCEPTION_TRACE
+ select USE_GENERIC_SMP_HELPERS if SMP
+ select VIRT_CPU_ACCOUNTING
config SCHED_OMIT_FRAME_POINTER
def_bool y
@@ -249,6 +251,7 @@ config COMPAT
depends on 64BIT
select COMPAT_BINFMT_ELF if BINFMT_ELF
select ARCH_WANT_OLD_COMPAT_IPC
+ select COMPAT_OLD_SIGACTION
help
Select this option if you want to enable your system kernel to
handle system-calls from ELF binaries for 31 bit ESA. This option
@@ -718,8 +721,8 @@ source "arch/s390/kvm/Kconfig"
config S390_GUEST
def_bool y
- prompt "s390 support for virtio devices (EXPERIMENTAL)"
- depends on 64BIT && EXPERIMENTAL
+ prompt "s390 support for virtio devices"
+ depends on 64BIT
select VIRTUALIZATION
select VIRTIO
select VIRTIO_CONSOLE
diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c
index 02d9a1cf5057..7ef60b52d6e0 100644
--- a/arch/s390/appldata/appldata_mem.c
+++ b/arch/s390/appldata/appldata_mem.c
@@ -108,7 +108,7 @@ static void appldata_get_mem_data(void *data)
mem_data->totalswap = P2K(val.totalswap);
mem_data->freeswap = P2K(val.freeswap);
- mem_data->timestamp = get_clock();
+ mem_data->timestamp = get_tod_clock();
mem_data->sync_count_2++;
}
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
index 1370e358d49a..2d224b945355 100644
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -111,7 +111,7 @@ static void appldata_get_net_sum_data(void *data)
net_data->tx_dropped = tx_dropped;
net_data->collisions = collisions;
- net_data->timestamp = get_clock();
+ net_data->timestamp = get_tod_clock();
net_data->sync_count_2++;
}
diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c
index 87521ba682e5..de8e2b3b0180 100644
--- a/arch/s390/appldata/appldata_os.c
+++ b/arch/s390/appldata/appldata_os.c
@@ -156,7 +156,7 @@ static void appldata_get_os_data(void *data)
}
ops.size = new_size;
}
- os_data->timestamp = get_clock();
+ os_data->timestamp = get_tod_clock();
os_data->sync_count_2++;
}
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c
index 4f6afaa8bd8f..f364dcf77e8e 100644
--- a/arch/s390/hypfs/hypfs_vm.c
+++ b/arch/s390/hypfs/hypfs_vm.c
@@ -245,7 +245,7 @@ static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)
d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr));
if (IS_ERR(d2fc))
return PTR_ERR(d2fc);
- get_clock_ext(d2fc->hdr.tod_ext);
+ get_tod_clock_ext(d2fc->hdr.tod_ext);
d2fc->hdr.len = count * sizeof(struct diag2fc_data);
d2fc->hdr.version = DBFS_D2FC_HDR_VERSION;
d2fc->hdr.count = count;
diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h
index 10a508802940..16760eeb79b0 100644
--- a/arch/s390/include/asm/barrier.h
+++ b/arch/s390/include/asm/barrier.h
@@ -13,15 +13,12 @@
* to devices.
*/
-static inline void mb(void)
-{
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
- /* Fast-BCR without checkpoint synchronization */
- asm volatile("bcr 14,0" : : : "memory");
+/* Fast-BCR without checkpoint synchronization */
+#define mb() do { asm volatile("bcr 14,0" : : : "memory"); } while (0)
#else
- asm volatile("bcr 15,0" : : : "memory");
+#define mb() do { asm volatile("bcr 15,0" : : : "memory"); } while (0)
#endif
-}
#define rmb() mb()
#define wmb() mb()
diff --git a/arch/s390/include/asm/clp.h b/arch/s390/include/asm/clp.h
index 6c3aecc245ff..a0e71a501f7c 100644
--- a/arch/s390/include/asm/clp.h
+++ b/arch/s390/include/asm/clp.h
@@ -2,7 +2,7 @@
#define _ASM_S390_CLP_H
/* CLP common request & response block size */
-#define CLP_BLK_SIZE (PAGE_SIZE * 2)
+#define CLP_BLK_SIZE PAGE_SIZE
struct clp_req_hdr {
u16 len;
diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h
index 35f0020b7ba7..f1eddd150dd7 100644
--- a/arch/s390/include/asm/cpu_mf.h
+++ b/arch/s390/include/asm/cpu_mf.h
@@ -34,12 +34,12 @@
/* CPU measurement facility support */
static inline int cpum_cf_avail(void)
{
- return MACHINE_HAS_SPP && test_facility(67);
+ return MACHINE_HAS_LPP && test_facility(67);
}
static inline int cpum_sf_avail(void)
{
- return MACHINE_HAS_SPP && test_facility(68);
+ return MACHINE_HAS_LPP && test_facility(68);
}
diff --git a/arch/s390/include/asm/dma-mapping.h b/arch/s390/include/asm/dma-mapping.h
index 8a32f7dfd3af..9411db653bac 100644
--- a/arch/s390/include/asm/dma-mapping.h
+++ b/arch/s390/include/asm/dma-mapping.h
@@ -19,9 +19,11 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
}
extern int dma_set_mask(struct device *dev, u64 mask);
-extern int dma_is_consistent(struct device *dev, dma_addr_t dma_handle);
-extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
- enum dma_data_direction direction);
+
+static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+ enum dma_data_direction direction)
+{
+}
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h
index 7def77302d63..87c17bfb2968 100644
--- a/arch/s390/include/asm/irq.h
+++ b/arch/s390/include/asm/irq.h
@@ -41,6 +41,7 @@ enum interruption_class {
IRQIO_CSC,
IRQIO_PCI,
IRQIO_MSI,
+ IRQIO_VIR,
NMI_NMI,
CPU_RST,
NR_ARCH_IRQS
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index b7841546991f..16bd5d169cdb 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -20,9 +20,7 @@
#include <asm/cpu.h>
#define KVM_MAX_VCPUS 64
-#define KVM_MEMORY_SLOTS 32
-/* memory slots that does not exposed to userspace */
-#define KVM_PRIVATE_MEM_SLOTS 4
+#define KVM_USER_MEM_SLOTS 32
struct sca_entry {
atomic_t scn;
@@ -76,8 +74,11 @@ struct kvm_s390_sie_block {
__u64 epoch; /* 0x0038 */
__u8 reserved40[4]; /* 0x0040 */
#define LCTL_CR0 0x8000
+#define LCTL_CR6 0x0200
+#define LCTL_CR14 0x0002
__u16 lctl; /* 0x0044 */
__s16 icpua; /* 0x0046 */
+#define ICTL_LPSW 0x00400000
__u32 ictl; /* 0x0048 */
__u32 eca; /* 0x004c */
__u8 icptcode; /* 0x0050 */
@@ -127,6 +128,7 @@ struct kvm_vcpu_stat {
u32 deliver_prefix_signal;
u32 deliver_restart_signal;
u32 deliver_program_int;
+ u32 deliver_io_int;
u32 exit_wait_state;
u32 instruction_stidp;
u32 instruction_spx;
@@ -187,6 +189,11 @@ struct kvm_s390_emerg_info {
__u16 code;
};
+struct kvm_s390_mchk_info {
+ __u64 cr14;
+ __u64 mcic;
+};
+
struct kvm_s390_interrupt_info {
struct list_head list;
u64 type;
@@ -197,6 +204,7 @@ struct kvm_s390_interrupt_info {
struct kvm_s390_emerg_info emerg;
struct kvm_s390_extcall_info extcall;
struct kvm_s390_prefix_info prefix;
+ struct kvm_s390_mchk_info mchk;
};
};
@@ -254,6 +262,7 @@ struct kvm_arch{
debug_info_t *dbf;
struct kvm_s390_float_interrupt float_int;
struct gmap *gmap;
+ int css_support;
};
extern int sie64a(struct kvm_s390_sie_block *, u64 *);
diff --git a/arch/s390/include/asm/mman.h b/arch/s390/include/asm/mman.h
index 0e47a576d666..9977e08df5bd 100644
--- a/arch/s390/include/asm/mman.h
+++ b/arch/s390/include/asm/mman.h
@@ -9,7 +9,7 @@
#include <uapi/asm/mman.h>
#if !defined(__ASSEMBLY__) && defined(CONFIG_64BIT)
-int s390_mmap_check(unsigned long addr, unsigned long len);
-#define arch_mmap_check(addr,len,flags) s390_mmap_check(addr,len)
+int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags);
+#define arch_mmap_check(addr, len, flags) s390_mmap_check(addr, len, flags)
#endif
#endif /* __S390_MMAN_H__ */
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index a86ad4084073..75ce9b065f9f 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -155,28 +155,6 @@ static inline int page_reset_referenced(unsigned long addr)
#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.
- *
- * Note that the bit gets set whenever page content is changed. That means
- * also when the page is modified by DMA or from inside the kernel.
- */
-#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
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index b1fa93c606ad..05333b7f0469 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -160,9 +160,14 @@ void zpci_teardown_msi_irq(struct zpci_dev *, struct msi_desc *);
int zpci_msihash_init(void);
void zpci_msihash_exit(void);
+#ifdef CONFIG_PCI
/* Error handling and recovery */
void zpci_event_error(void *);
void zpci_event_availability(void *);
+#else /* CONFIG_PCI */
+static inline void zpci_event_error(void *e) {}
+static inline void zpci_event_availability(void *e) {}
+#endif /* CONFIG_PCI */
/* Helpers */
struct zpci_dev *get_zdev(struct pci_dev *);
@@ -180,8 +185,10 @@ void zpci_dma_exit(void);
/* Hotplug */
extern struct mutex zpci_list_lock;
extern struct list_head zpci_list;
-extern struct pci_hp_callback_ops hotplug_ops;
-extern unsigned int pci_probe;
+extern unsigned int s390_pci_probe;
+
+void zpci_register_hp_ops(struct pci_hp_callback_ops *);
+void zpci_deregister_hp_ops(void);
/* FMB */
int zpci_fmb_enable_device(struct zpci_dev *);
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 098adbb62660..97de1200c849 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -29,6 +29,7 @@
#ifndef __ASSEMBLY__
#include <linux/sched.h>
#include <linux/mm_types.h>
+#include <linux/page-flags.h>
#include <asm/bug.h>
#include <asm/page.h>
@@ -221,13 +222,15 @@ extern unsigned long MODULES_END;
/* 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_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 _PAGE_SWC 0x004 /* SW pte changed bit */
+#define _PAGE_SWR 0x008 /* SW pte referenced bit */
+#define _PAGE_SWW 0x010 /* SW pte write bit */
+#define _PAGE_SPECIAL 0x020 /* 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 | _PAGE_SWC | _PAGE_SWR)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_CO | \
+ _PAGE_SWC | _PAGE_SWR)
/* Six different types of pages. */
#define _PAGE_TYPE_EMPTY 0x400
@@ -321,6 +324,7 @@ extern unsigned long MODULES_END;
/* Bits in the region table entry */
#define _REGION_ENTRY_ORIGIN ~0xfffUL/* region/segment table origin */
+#define _REGION_ENTRY_RO 0x200 /* region protection bit */
#define _REGION_ENTRY_INV 0x20 /* invalid region table entry */
#define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */
#define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */
@@ -382,9 +386,11 @@ extern unsigned long MODULES_END;
*/
#define PAGE_NONE __pgprot(_PAGE_TYPE_NONE)
#define PAGE_RO __pgprot(_PAGE_TYPE_RO)
-#define PAGE_RW __pgprot(_PAGE_TYPE_RW)
+#define PAGE_RW __pgprot(_PAGE_TYPE_RO | _PAGE_SWW)
+#define PAGE_RWC __pgprot(_PAGE_TYPE_RW | _PAGE_SWW | _PAGE_SWC)
-#define PAGE_KERNEL PAGE_RW
+#define PAGE_KERNEL PAGE_RWC
+#define PAGE_SHARED PAGE_KERNEL
#define PAGE_COPY PAGE_RO
/*
@@ -631,23 +637,23 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
/* Clear page changed & referenced bit in the storage key */
if (bits & _PAGE_CHANGED)
- page_set_storage_key(address, skey ^ bits, 1);
+ page_set_storage_key(address, skey ^ bits, 0);
else if (bits)
page_reset_referenced(address);
/* 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. */
+ /* Transfer page changed & referenced bit to kvm user bits */
+ pgste_val(pgste) |= bits << 45; /* KVM_UR_BIT & KVM_UC_BIT */
+ /* Clear relevant 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 */
+ /* Transfer referenced bit to pte */
+ pte_val(*ptep) |= (bits & _PAGE_REFERENCED) << 1;
#endif
return pgste;
@@ -660,20 +666,25 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
if (!pte_present(*ptep))
return pgste;
+ /* Get referenced bit from storage key */
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))
+ if (young)
+ pgste_val(pgste) |= RCP_GR_BIT;
+ /* Get host referenced bit from pgste */
+ if (pgste_val(pgste) & RCP_HR_BIT) {
+ pgste_val(pgste) &= ~RCP_HR_BIT;
+ young = 1;
+ }
+ /* Transfer referenced bit to kvm user bits and pte */
+ if (young) {
+ pgste_val(pgste) |= KVM_UR_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, pte_t entry)
+static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry)
{
#ifdef CONFIG_PGSTE
unsigned long address;
@@ -687,10 +698,23 @@ static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry)
/* 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(address, nkey, 1);
+ page_set_storage_key(address, nkey, 0);
#endif
}
+static inline void pgste_set_pte(pte_t *ptep, pte_t entry)
+{
+ if (!MACHINE_HAS_ESOP && (pte_val(entry) & _PAGE_SWW)) {
+ /*
+ * Without enhanced suppression-on-protection force
+ * the dirty bit on for all writable ptes.
+ */
+ pte_val(entry) |= _PAGE_SWC;
+ pte_val(entry) &= ~_PAGE_RO;
+ }
+ *ptep = entry;
+}
+
/**
* struct gmap_struct - guest address space
* @mm: pointer to the parent mm_struct
@@ -749,11 +773,14 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste_set_pte(ptep, pgste, entry);
- *ptep = entry;
+ pgste_set_key(ptep, pgste, entry);
+ pgste_set_pte(ptep, entry);
pgste_set_unlock(ptep, pgste);
- } else
+ } else {
+ if (!(pte_val(entry) & _PAGE_INVALID) && MACHINE_HAS_EDAT1)
+ pte_val(entry) |= _PAGE_CO;
*ptep = entry;
+ }
}
/*
@@ -762,16 +789,12 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
*/
static inline int pte_write(pte_t pte)
{
- return (pte_val(pte) & _PAGE_RO) == 0;
+ return (pte_val(pte) & _PAGE_SWW) != 0;
}
static inline int pte_dirty(pte_t pte)
{
-#ifdef CONFIG_PGSTE
- if (pte_val(pte) & _PAGE_SWC)
- return 1;
-#endif
- return 0;
+ return (pte_val(pte) & _PAGE_SWC) != 0;
}
static inline int pte_young(pte_t pte)
@@ -821,11 +844,14 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
pte_val(pte) &= _PAGE_CHG_MASK;
pte_val(pte) |= pgprot_val(newprot);
+ if ((pte_val(pte) & _PAGE_SWC) && (pte_val(pte) & _PAGE_SWW))
+ pte_val(pte) &= ~_PAGE_RO;
return pte;
}
static inline pte_t pte_wrprotect(pte_t pte)
{
+ pte_val(pte) &= ~_PAGE_SWW;
/* Do not clobber _PAGE_TYPE_NONE pages! */
if (!(pte_val(pte) & _PAGE_INVALID))
pte_val(pte) |= _PAGE_RO;
@@ -834,20 +860,26 @@ static inline pte_t pte_wrprotect(pte_t pte)
static inline pte_t pte_mkwrite(pte_t pte)
{
- pte_val(pte) &= ~_PAGE_RO;
+ pte_val(pte) |= _PAGE_SWW;
+ if (pte_val(pte) & _PAGE_SWC)
+ pte_val(pte) &= ~_PAGE_RO;
return pte;
}
static inline pte_t pte_mkclean(pte_t pte)
{
-#ifdef CONFIG_PGSTE
pte_val(pte) &= ~_PAGE_SWC;
-#endif
+ /* Do not clobber _PAGE_TYPE_NONE pages! */
+ if (!(pte_val(pte) & _PAGE_INVALID))
+ pte_val(pte) |= _PAGE_RO;
return pte;
}
static inline pte_t pte_mkdirty(pte_t pte)
{
+ pte_val(pte) |= _PAGE_SWC;
+ if (pte_val(pte) & _PAGE_SWW)
+ pte_val(pte) &= ~_PAGE_RO;
return pte;
}
@@ -885,10 +917,10 @@ static inline pte_t pte_mkhuge(pte_t pte)
pte_val(pte) |= _SEGMENT_ENTRY_INV;
}
/*
- * Clear SW pte bits SWT and SWX, there are no SW bits in a segment
- * table entry.
+ * Clear SW pte bits, there are no SW bits in a segment table entry.
*/
- pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX);
+ pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX | _PAGE_SWC |
+ _PAGE_SWR | _PAGE_SWW);
/*
* Also set the change-override bit because we don't need dirty bit
* tracking for hugetlbfs pages.
@@ -1040,9 +1072,11 @@ 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))
+ if (mm_has_pgste(mm)) {
+ pgste_set_pte(ptep, pte);
pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE));
+ } else
+ *ptep = pte;
}
#define __HAVE_ARCH_PTEP_CLEAR_FLUSH
@@ -1110,10 +1144,13 @@ static inline pte_t ptep_set_wrprotect(struct mm_struct *mm,
if (!mm_exclusive(mm))
__ptep_ipte(address, ptep);
- *ptep = pte_wrprotect(pte);
+ pte = pte_wrprotect(pte);
- if (mm_has_pgste(mm))
+ if (mm_has_pgste(mm)) {
+ pgste_set_pte(ptep, pte);
pgste_set_unlock(ptep, pgste);
+ } else
+ *ptep = pte;
}
return pte;
}
@@ -1131,10 +1168,12 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma,
pgste = pgste_get_lock(ptep);
__ptep_ipte(address, ptep);
- *ptep = entry;
- if (mm_has_pgste(vma->vm_mm))
+ if (mm_has_pgste(vma->vm_mm)) {
+ pgste_set_pte(ptep, entry);
pgste_set_unlock(ptep, pgste);
+ } else
+ *ptep = entry;
return 1;
}
@@ -1152,8 +1191,13 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
static inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
{
unsigned long physpage = page_to_phys(page);
+ pte_t __pte = mk_pte_phys(physpage, pgprot);
- return mk_pte_phys(physpage, pgprot);
+ if ((pte_val(__pte) & _PAGE_SWW) && PageDirty(page)) {
+ pte_val(__pte) |= _PAGE_SWC;
+ pte_val(__pte) &= ~_PAGE_RO;
+ }
+ return __pte;
}
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
@@ -1245,6 +1289,8 @@ static inline int pmd_trans_splitting(pmd_t pmd)
static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t entry)
{
+ if (!(pmd_val(entry) & _SEGMENT_ENTRY_INV) && MACHINE_HAS_EDAT1)
+ pmd_val(entry) |= _SEGMENT_ENTRY_CO;
*pmdp = entry;
}
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index 833788693f09..06a136136047 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -46,7 +46,6 @@ int sclp_cpu_deconfigure(u8 cpu);
void sclp_facilities_detect(void);
unsigned long long sclp_get_rnmax(void);
unsigned long long sclp_get_rzm(void);
-u8 sclp_get_fac85(void);
int sclp_sdias_blk_count(void);
int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
int sclp_chp_configure(struct chp_id chpid);
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index f69f76b3447a..ff67d730c00c 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -64,17 +64,18 @@ extern unsigned int s390_user_mode;
#define MACHINE_FLAG_VM (1UL << 0)
#define MACHINE_FLAG_IEEE (1UL << 1)
-#define MACHINE_FLAG_CSP (1UL << 3)
-#define MACHINE_FLAG_MVPG (1UL << 4)
-#define MACHINE_FLAG_DIAG44 (1UL << 5)
-#define MACHINE_FLAG_IDTE (1UL << 6)
-#define MACHINE_FLAG_DIAG9C (1UL << 7)
-#define MACHINE_FLAG_MVCOS (1UL << 8)
-#define MACHINE_FLAG_KVM (1UL << 9)
+#define MACHINE_FLAG_CSP (1UL << 2)
+#define MACHINE_FLAG_MVPG (1UL << 3)
+#define MACHINE_FLAG_DIAG44 (1UL << 4)
+#define MACHINE_FLAG_IDTE (1UL << 5)
+#define MACHINE_FLAG_DIAG9C (1UL << 6)
+#define MACHINE_FLAG_MVCOS (1UL << 7)
+#define MACHINE_FLAG_KVM (1UL << 8)
+#define MACHINE_FLAG_ESOP (1UL << 9)
#define MACHINE_FLAG_EDAT1 (1UL << 10)
#define MACHINE_FLAG_EDAT2 (1UL << 11)
#define MACHINE_FLAG_LPAR (1UL << 12)
-#define MACHINE_FLAG_SPP (1UL << 13)
+#define MACHINE_FLAG_LPP (1UL << 13)
#define MACHINE_FLAG_TOPOLOGY (1UL << 14)
#define MACHINE_FLAG_TE (1UL << 15)
#define MACHINE_FLAG_RRBM (1UL << 16)
@@ -84,6 +85,7 @@ extern unsigned int s390_user_mode;
#define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR)
#define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C)
+#define MACHINE_HAS_ESOP (S390_lowcore.machine_flags & MACHINE_FLAG_ESOP)
#define MACHINE_HAS_PFMF MACHINE_HAS_EDAT1
#define MACHINE_HAS_HPAGE MACHINE_HAS_EDAT1
@@ -96,7 +98,7 @@ extern unsigned int s390_user_mode;
#define MACHINE_HAS_MVCOS (0)
#define MACHINE_HAS_EDAT1 (0)
#define MACHINE_HAS_EDAT2 (0)
-#define MACHINE_HAS_SPP (0)
+#define MACHINE_HAS_LPP (0)
#define MACHINE_HAS_TOPOLOGY (0)
#define MACHINE_HAS_TE (0)
#define MACHINE_HAS_RRBM (0)
@@ -109,7 +111,7 @@ extern unsigned int s390_user_mode;
#define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS)
#define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1)
#define MACHINE_HAS_EDAT2 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2)
-#define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP)
+#define MACHINE_HAS_LPP (S390_lowcore.machine_flags & MACHINE_FLAG_LPP)
#define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
#define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE)
#define MACHINE_HAS_RRBM (S390_lowcore.machine_flags & MACHINE_FLAG_RRBM)
diff --git a/arch/s390/include/asm/signal.h b/arch/s390/include/asm/signal.h
index db7ddfaf5b79..abf9e5735943 100644
--- a/arch/s390/include/asm/signal.h
+++ b/arch/s390/include/asm/signal.h
@@ -21,22 +21,5 @@ typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
-};
-
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
-
+#define __ARCH_HAS_SA_RESTORER
#endif
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h
index 4c060bb5b8ea..8ad8af915032 100644
--- a/arch/s390/include/asm/timex.h
+++ b/arch/s390/include/asm/timex.h
@@ -15,7 +15,7 @@
#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
/* Inline functions for clock register access. */
-static inline int set_clock(__u64 time)
+static inline int set_tod_clock(__u64 time)
{
int cc;
@@ -27,7 +27,7 @@ static inline int set_clock(__u64 time)
return cc;
}
-static inline int store_clock(__u64 *time)
+static inline int store_tod_clock(__u64 *time)
{
int cc;
@@ -71,7 +71,7 @@ static inline void local_tick_enable(unsigned long long comp)
typedef unsigned long long cycles_t;
-static inline unsigned long long get_clock(void)
+static inline unsigned long long get_tod_clock(void)
{
unsigned long long clk;
@@ -83,21 +83,21 @@ static inline unsigned long long get_clock(void)
return clk;
}
-static inline void get_clock_ext(char *clk)
+static inline void get_tod_clock_ext(char *clk)
{
asm volatile("stcke %0" : "=Q" (*clk) : : "cc");
}
-static inline unsigned long long get_clock_xt(void)
+static inline unsigned long long get_tod_clock_xt(void)
{
unsigned char clk[16];
- get_clock_ext(clk);
+ get_tod_clock_ext(clk);
return *((unsigned long long *)&clk[1]);
}
static inline cycles_t get_cycles(void)
{
- return (cycles_t) get_clock() >> 2;
+ return (cycles_t) get_tod_clock() >> 2;
}
int get_sync_clock(unsigned long long *clock);
@@ -123,9 +123,9 @@ extern u64 sched_clock_base_cc;
* function, otherwise the returned value is not guaranteed to
* be monotonic.
*/
-static inline unsigned long long get_clock_monotonic(void)
+static inline unsigned long long get_tod_clock_monotonic(void)
{
- return get_clock_xt() - sched_clock_base_cc;
+ return get_tod_clock_xt() - sched_clock_base_cc;
}
/**
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h
index 636530872516..a6667a952969 100644
--- a/arch/s390/include/asm/unistd.h
+++ b/arch/s390/include/asm/unistd.h
@@ -43,15 +43,12 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
# ifndef CONFIG_64BIT
# define __ARCH_WANT_STAT64
# define __ARCH_WANT_SYS_TIME
# endif
# ifdef CONFIG_COMPAT
# define __ARCH_WANT_COMPAT_SYS_TIME
-# define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
# endif
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
diff --git a/arch/s390/include/uapi/asm/socket.h b/arch/s390/include/uapi/asm/socket.h
index 436d07c23be8..f99eea7fff0f 100644
--- a/arch/s390/include/uapi/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
@@ -28,7 +28,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT 15
#define SO_PASSCRED 16
#define SO_PEERCRED 17
#define SO_RCVLOWAT 18
@@ -76,4 +76,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 65cca95843e1..19f26de27fae 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -352,86 +352,6 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
return sys_ftruncate(fd, (high << 32) | low);
}
-asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
- struct compat_timespec __user *interval)
-{
- struct timespec t;
- int ret;
- mm_segment_t old_fs = get_fs ();
-
- set_fs (KERNEL_DS);
- ret = sys_sched_rr_get_interval(pid,
- (struct timespec __force __user *) &t);
- set_fs (old_fs);
- if (put_compat_timespec(&t, interval))
- return -EFAULT;
- return ret;
-}
-
-asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
- compat_sigset_t __user *oset, size_t sigsetsize)
-{
- sigset_t s;
- compat_sigset_t s32;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- if (set) {
- if (copy_from_user (&s32, set, sizeof(compat_sigset_t)))
- return -EFAULT;
- s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
- }
- set_fs (KERNEL_DS);
- ret = sys_rt_sigprocmask(how,
- set ? (sigset_t __force __user *) &s : NULL,
- oset ? (sigset_t __force __user *) &s : NULL,
- sigsetsize);
- set_fs (old_fs);
- if (ret) return ret;
- if (oset) {
- s32.sig[1] = (s.sig[0] >> 32);
- s32.sig[0] = s.sig[0];
- if (copy_to_user (oset, &s32, sizeof(compat_sigset_t)))
- return -EFAULT;
- }
- return 0;
-}
-
-asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
- size_t sigsetsize)
-{
- sigset_t s;
- compat_sigset_t s32;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs (KERNEL_DS);
- ret = sys_rt_sigpending((sigset_t __force __user *) &s, sigsetsize);
- set_fs (old_fs);
- if (!ret) {
- s32.sig[1] = (s.sig[0] >> 32);
- s32.sig[0] = s.sig[0];
- if (copy_to_user (set, &s32, sizeof(compat_sigset_t)))
- return -EFAULT;
- }
- return ret;
-}
-
-asmlinkage long
-sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
-{
- siginfo_t info;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- if (copy_siginfo_from_user32(&info, uinfo))
- return -EFAULT;
- set_fs (KERNEL_DS);
- ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *) &info);
- set_fs (old_fs);
- return ret;
-}
-
asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
size_t count, u32 poshi, u32 poslo)
{
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index d4d0239970ac..00d92a5a6f6c 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -17,13 +17,6 @@ struct ipc_kludge_32 {
__s32 msgtyp;
};
-struct old_sigaction32 {
- __u32 sa_handler; /* Really a pointer, but need to deal with 32 bits */
- compat_old_sigset_t sa_mask; /* A 32 bit mask */
- __u32 sa_flags;
- __u32 sa_restorer; /* Another 32 bit pointer */
-};
-
/* asm/sigcontext.h */
typedef union
{
@@ -68,24 +61,12 @@ struct sigcontext32
};
/* asm/signal.h */
-struct sigaction32 {
- __u32 sa_handler; /* pointer */
- __u32 sa_flags;
- __u32 sa_restorer; /* pointer */
- compat_sigset_t sa_mask; /* mask last for extensibility */
-};
-
-typedef struct {
- __u32 ss_sp; /* pointer */
- int ss_flags;
- compat_size_t ss_size;
-} stack_t32;
/* asm/ucontext.h */
struct ucontext32 {
__u32 uc_flags;
__u32 uc_link; /* pointer */
- stack_t32 uc_stack;
+ compat_stack_t uc_stack;
_sigregs32 uc_mcontext;
compat_sigset_t uc_sigmask; /* mask last for extensibility */
};
@@ -93,8 +74,6 @@ struct ucontext32 {
struct stat64_emu31;
struct mmap_arg_struct_emu31;
struct fadvise64_64_args;
-struct old_sigaction32;
-struct old_sigaction32;
long sys32_chown16(const char __user * filename, u16 user, u16 group);
long sys32_lchown16(const char __user * filename, u16 user, u16 group);
@@ -119,12 +98,6 @@ long sys32_ipc(u32 call, int first, int second, int third, u32 ptr);
long sys32_truncate64(const char __user * path, unsigned long high,
unsigned long low);
long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low);
-long sys32_sched_rr_get_interval(compat_pid_t pid,
- struct compat_timespec __user *interval);
-long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
- compat_sigset_t __user *oset, size_t sigsetsize);
-long sys32_rt_sigpending(compat_sigset_t __user *set, size_t sigsetsize);
-long sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo);
long sys32_init_module(void __user *umod, unsigned long len,
const char __user *uargs);
long sys32_delete_module(const char __user *name_user, unsigned int flags);
@@ -149,9 +122,4 @@ long sys32_read(unsigned int fd, char __user * buf, size_t count);
long sys32_write(unsigned int fd, const char __user * buf, size_t count);
long sys32_fadvise64(int fd, loff_t offset, size_t len, int advise);
long sys32_fadvise64_64(struct fadvise64_64_args __user *args);
-long sys32_sigaction(int sig, const struct old_sigaction32 __user *act,
- struct old_sigaction32 __user *oact);
-long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
- struct sigaction32 __user *oact, size_t sigsetsize);
-long sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss);
#endif /* _ASM_S390X_S390_H */
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 593fcc9253fc..3e71194c1902 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -157,122 +157,6 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
return err;
}
-asmlinkage long
-sys32_sigaction(int sig, const struct old_sigaction32 __user *act,
- struct old_sigaction32 __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- unsigned long sa_handler, sa_restorer;
- int ret;
-
- if (act) {
- compat_old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(sa_handler, &act->sa_handler) ||
- __get_user(sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
- new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- sa_handler = (unsigned long) old_ka.sa.sa_handler;
- sa_restorer = (unsigned long) old_ka.sa.sa_restorer;
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(sa_handler, &oact->sa_handler) ||
- __put_user(sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
-asmlinkage long
-sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
- struct sigaction32 __user *oact, size_t sigsetsize)
-{
- struct k_sigaction new_ka, old_ka;
- unsigned long sa_handler;
- int ret;
- compat_sigset_t set32;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(compat_sigset_t))
- return -EINVAL;
-
- if (act) {
- ret = get_user(sa_handler, &act->sa_handler);
- ret |= __copy_from_user(&set32, &act->sa_mask,
- sizeof(compat_sigset_t));
- new_ka.sa.sa_mask.sig[0] =
- set32.sig[0] | (((long)set32.sig[1]) << 32);
- ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
-
- if (ret)
- return -EFAULT;
- new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
- set32.sig[0] = old_ka.sa.sa_mask.sig[0];
- ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler);
- ret |= __copy_to_user(&oact->sa_mask, &set32,
- sizeof(compat_sigset_t));
- ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- }
-
- return ret;
-}
-
-asmlinkage long
-sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss)
-{
- struct pt_regs *regs = task_pt_regs(current);
- stack_t kss, koss;
- unsigned long ss_sp;
- int ret, err = 0;
- mm_segment_t old_fs = get_fs();
-
- if (uss) {
- if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
- return -EFAULT;
- err |= __get_user(ss_sp, &uss->ss_sp);
- err |= __get_user(kss.ss_size, &uss->ss_size);
- err |= __get_user(kss.ss_flags, &uss->ss_flags);
- if (err)
- return -EFAULT;
- kss.ss_sp = (void __user *) ss_sp;
- }
-
- set_fs (KERNEL_DS);
- ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),
- (stack_t __force __user *) (uoss ? &koss : NULL),
- regs->gprs[15]);
- set_fs (old_fs);
-
- if (!ret && uoss) {
- if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
- return -EFAULT;
- ss_sp = (unsigned long) koss.ss_sp;
- err |= __put_user(ss_sp, &uoss->ss_sp);
- err |= __put_user(koss.ss_size, &uoss->ss_size);
- err |= __put_user(koss.ss_flags, &uoss->ss_flags);
- if (err)
- return -EFAULT;
- }
- return ret;
-}
-
static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
{
_s390_regs_common32 regs32;
@@ -380,10 +264,6 @@ asmlinkage long sys32_rt_sigreturn(void)
struct pt_regs *regs = task_pt_regs(current);
rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
sigset_t set;
- stack_t st;
- __u32 ss_sp;
- int err;
- mm_segment_t old_fs = get_fs();
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
@@ -394,15 +274,8 @@ asmlinkage long sys32_rt_sigreturn(void)
goto badframe;
if (restore_sigregs_gprs_high(regs, frame->gprs_high))
goto badframe;
- err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
- st.ss_sp = compat_ptr(ss_sp);
- err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size);
- err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
- if (err)
+ if (compat_restore_altstack(&frame->uc.uc_stack))
goto badframe;
- set_fs (KERNEL_DS);
- do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
- set_fs (old_fs);
return regs->gprs[2];
badframe:
force_sig(SIGSEGV, current);
@@ -530,10 +403,7 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->gprs[15]),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]);
err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
err |= save_sigregs_gprs_high(regs, frame->gprs_high);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 9b9a805656b5..c14faf39ae36 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -24,12 +24,6 @@ ENTRY(sys32_write_wrapper)
llgfr %r4,%r4 # size_t
jg sys32_write # branch to system call
-ENTRY(sys32_open_wrapper)
- llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
- lgfr %r4,%r4 # int
- jg compat_sys_open # branch to system call
-
ENTRY(sys32_close_wrapper)
llgfr %r2,%r2 # unsigned int
jg sys_close # branch to system call
@@ -226,12 +220,6 @@ ENTRY(sys32_dup2_wrapper)
#sys32_setsid_wrapper # void
-ENTRY(sys32_sigaction_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const struct old_sigaction *
- llgtr %r4,%r4 # struct old_sigaction32 *
- jg sys32_sigaction # branch to system call
-
ENTRY(sys32_setreuid16_wrapper)
llgfr %r2,%r2 # __kernel_old_uid_emu31_t
llgfr %r3,%r3 # __kernel_old_uid_emu31_t
@@ -396,17 +384,6 @@ ENTRY(sys32_syslog_wrapper)
lgfr %r4,%r4 # int
jg sys_syslog # branch to system call
-ENTRY(compat_sys_setitimer_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # struct itimerval_emu31 *
- llgtr %r4,%r4 # struct itimerval_emu31 *
- jg compat_sys_setitimer # branch to system call
-
-ENTRY(compat_sys_getitimer_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # struct itimerval_emu31 *
- jg compat_sys_getitimer # branch to system call
-
ENTRY(compat_sys_newstat_wrapper)
llgtr %r2,%r2 # char *
llgtr %r3,%r3 # struct stat_emu31 *
@@ -424,13 +401,6 @@ ENTRY(compat_sys_newfstat_wrapper)
#sys32_vhangup_wrapper # void
-ENTRY(compat_sys_wait4_wrapper)
- lgfr %r2,%r2 # pid_t
- llgtr %r3,%r3 # unsigned int *
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # struct rusage *
- jg compat_sys_wait4 # branch to system call
-
ENTRY(sys32_swapoff_wrapper)
llgtr %r2,%r2 # const char *
jg sys_swapoff # branch to system call
@@ -474,12 +444,6 @@ ENTRY(sys32_mprotect_wrapper)
llgfr %r4,%r4 # unsigned long
jg sys_mprotect # branch to system call
-ENTRY(compat_sys_sigprocmask_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # compat_old_sigset_t *
- llgtr %r4,%r4 # compat_old_sigset_t *
- jg compat_sys_sigprocmask # branch to system call
-
ENTRY(sys_init_module_wrapper)
llgtr %r2,%r2 # void *
llgfr %r3,%r3 # unsigned long
@@ -628,11 +592,6 @@ ENTRY(sys32_sched_get_priority_min_wrapper)
lgfr %r2,%r2 # int
jg sys_sched_get_priority_min # branch to system call
-ENTRY(sys32_sched_rr_get_interval_wrapper)
- lgfr %r2,%r2 # pid_t
- llgtr %r3,%r3 # struct compat_timespec *
- jg sys32_sched_rr_get_interval # branch to system call
-
ENTRY(compat_sys_nanosleep_wrapper)
llgtr %r2,%r2 # struct compat_timespec *
llgtr %r3,%r3 # struct compat_timespec *
@@ -686,43 +645,6 @@ ENTRY(sys32_prctl_wrapper)
#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue
-ENTRY(sys32_rt_sigaction_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # const struct sigaction_emu31 *
- llgtr %r4,%r4 # const struct sigaction_emu31 *
- llgfr %r5,%r5 # size_t
- jg sys32_rt_sigaction # branch to system call
-
-ENTRY(sys32_rt_sigprocmask_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # old_sigset_emu31 *
- llgtr %r4,%r4 # old_sigset_emu31 *
- llgfr %r5,%r5 # size_t
- jg sys32_rt_sigprocmask # branch to system call
-
-ENTRY(sys32_rt_sigpending_wrapper)
- llgtr %r2,%r2 # sigset_emu31 *
- llgfr %r3,%r3 # size_t
- jg sys32_rt_sigpending # branch to system call
-
-ENTRY(compat_sys_rt_sigtimedwait_wrapper)
- llgtr %r2,%r2 # const sigset_emu31_t *
- llgtr %r3,%r3 # siginfo_emu31_t *
- llgtr %r4,%r4 # const struct compat_timespec *
- llgfr %r5,%r5 # size_t
- jg compat_sys_rt_sigtimedwait # branch to system call
-
-ENTRY(sys32_rt_sigqueueinfo_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # siginfo_emu31_t *
- jg sys32_rt_sigqueueinfo # branch to system call
-
-ENTRY(compat_sys_rt_sigsuspend_wrapper)
- llgtr %r2,%r2 # compat_sigset_t *
- llgfr %r3,%r3 # compat_size_t
- jg compat_sys_rt_sigsuspend
-
ENTRY(sys32_pread64_wrapper)
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # char *
@@ -760,11 +682,6 @@ ENTRY(sys32_capset_wrapper)
llgtr %r3,%r3 # const cap_user_data_t
jg sys_capset # branch to system call
-ENTRY(sys32_sigaltstack_wrapper)
- llgtr %r2,%r2 # const stack_emu31_t *
- llgtr %r3,%r3 # stack_emu31_t *
- jg sys32_sigaltstack
-
ENTRY(sys32_sendfile_wrapper)
lgfr %r2,%r2 # int
lgfr %r3,%r3 # int
@@ -921,16 +838,6 @@ ENTRY(sys32_fstat64_wrapper)
llgtr %r3,%r3 # struct stat64 *
jg sys32_fstat64 # branch to system call
-ENTRY(compat_sys_futex_wrapper)
- llgtr %r2,%r2 # u32 *
- lgfr %r3,%r3 # int
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # struct compat_timespec *
- llgtr %r6,%r6 # u32 *
- lgf %r0,164(%r15) # int
- stg %r0,160(%r15)
- jg compat_sys_futex # branch to system call
-
ENTRY(sys32_setxattr_wrapper)
llgtr %r2,%r2 # char *
llgtr %r3,%r3 # char *
@@ -1216,14 +1123,6 @@ ENTRY(sys32_remap_file_pages_wrapper)
llgfr %r6,%r6 # unsigned long
jg sys_remap_file_pages
-ENTRY(compat_sys_waitid_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # pid_t
- llgtr %r4,%r4 # siginfo_emu31_t *
- lgfr %r5,%r5 # int
- llgtr %r6,%r6 # struct rusage_emu31 *
- jg compat_sys_waitid
-
ENTRY(compat_sys_kexec_load_wrapper)
llgfr %r2,%r2 # unsigned long
llgfr %r3,%r3 # unsigned long
@@ -1253,13 +1152,6 @@ ENTRY(sys_inotify_rm_watch_wrapper)
llgfr %r3,%r3 # u32
jg sys_inotify_rm_watch
-ENTRY(compat_sys_openat_wrapper)
- llgfr %r2,%r2 # unsigned int
- llgtr %r3,%r3 # const char *
- lgfr %r4,%r4 # int
- lgfr %r5,%r5 # int
- jg compat_sys_openat
-
ENTRY(sys_mkdirat_wrapper)
lgfr %r2,%r2 # int
llgtr %r3,%r3 # const char *
@@ -1362,17 +1254,6 @@ ENTRY(sys_unshare_wrapper)
llgfr %r2,%r2 # unsigned long
jg sys_unshare
-ENTRY(compat_sys_set_robust_list_wrapper)
- llgtr %r2,%r2 # struct compat_robust_list_head *
- llgfr %r3,%r3 # size_t
- jg compat_sys_set_robust_list
-
-ENTRY(compat_sys_get_robust_list_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # compat_uptr_t_t *
- llgtr %r4,%r4 # compat_size_t *
- jg compat_sys_get_robust_list
-
ENTRY(sys_splice_wrapper)
lgfr %r2,%r2 # int
llgtr %r3,%r3 # loff_t *
@@ -1458,18 +1339,6 @@ ENTRY(sys_timerfd_create_wrapper)
lgfr %r3,%r3 # int
jg sys_timerfd_create
-ENTRY(compat_sys_timerfd_settime_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # struct compat_itimerspec *
- llgtr %r5,%r5 # struct compat_itimerspec *
- jg compat_sys_timerfd_settime
-
-ENTRY(compat_sys_timerfd_gettime_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # struct compat_itimerspec *
- jg compat_sys_timerfd_gettime
-
ENTRY(compat_sys_signalfd4_wrapper)
lgfr %r2,%r2 # int
llgtr %r3,%r3 # compat_sigset_t *
@@ -1550,13 +1419,6 @@ ENTRY(compat_sys_pwritev_wrapper)
llgfr %r6,%r6 # u32
jg compat_sys_pwritev # branch to system call
-ENTRY(compat_sys_rt_tgsigqueueinfo_wrapper)
- lgfr %r2,%r2 # compat_pid_t
- lgfr %r3,%r3 # compat_pid_t
- lgfr %r4,%r4 # int
- llgtr %r5,%r5 # struct compat_siginfo *
- jg compat_sys_rt_tgsigqueueinfo_wrapper # branch to system call
-
ENTRY(sys_perf_event_open_wrapper)
llgtr %r2,%r2 # const struct perf_event_attr *
lgfr %r3,%r3 # pid_t
@@ -1607,12 +1469,6 @@ ENTRY(sys_name_to_handle_at_wrapper)
lgfr %r6,%r6 # int
jg sys_name_to_handle_at
-ENTRY(compat_sys_open_by_handle_at_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # struct file_handle __user *
- lgfr %r4,%r4 # int
- jg compat_sys_open_by_handle_at
-
ENTRY(compat_sys_clock_adjtime_wrapper)
lgfr %r2,%r2 # clockid_t (int)
llgtr %r3,%r3 # struct compat_timex __user *
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index 4e8215e0d4b6..09a94cd9debc 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -867,7 +867,7 @@ static inline void
debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
int exception)
{
- active->id.stck = get_clock();
+ active->id.stck = get_tod_clock();
active->id.fields.cpuid = smp_processor_id();
active->caller = __builtin_return_address(0);
active->id.fields.exception = exception;
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index a7f9abd98cf2..c50665fe9435 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -840,7 +840,6 @@ static struct insn opcode_b2[] = {
{ "stcke", 0x78, INSTR_S_RD },
{ "sacf", 0x79, INSTR_S_RD },
{ "stsi", 0x7d, INSTR_S_RD },
- { "spp", 0x80, INSTR_S_RD },
{ "srnm", 0x99, INSTR_S_RD },
{ "stfpc", 0x9c, INSTR_S_RD },
{ "lfpc", 0x9d, INSTR_S_RD },
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 1f0eee9e7daa..bda011e2f8ae 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -47,10 +47,10 @@ static void __init reset_tod_clock(void)
{
u64 time;
- if (store_clock(&time) == 0)
+ if (store_tod_clock(&time) == 0)
return;
/* TOD clock not running. Set the clock to Unix Epoch. */
- if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0)
+ if (set_tod_clock(TOD_UNIX_EPOCH) != 0 || store_tod_clock(&time) != 0)
disabled_wait(0);
sched_clock_base_cc = TOD_UNIX_EPOCH;
@@ -173,7 +173,7 @@ static noinline __init void create_kernel_nss(void)
}
/* re-initialize cputime accounting. */
- sched_clock_base_cc = get_clock();
+ sched_clock_base_cc = get_tod_clock();
S390_lowcore.last_update_clock = sched_clock_base_cc;
S390_lowcore.last_update_timer = 0x7fffffffffffffffULL;
S390_lowcore.user_timer = 0;
@@ -381,7 +381,7 @@ static __init void detect_machine_facilities(void)
if (test_facility(27))
S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
if (test_facility(40))
- S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
+ S390_lowcore.machine_flags |= MACHINE_FLAG_LPP;
if (test_facility(50) && test_facility(73))
S390_lowcore.machine_flags |= MACHINE_FLAG_TE;
if (test_facility(66))
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index 2711936fe706..c3a736a3ed44 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -73,10 +73,6 @@ long sys_s390_fadvise64(int fd, u32 offset_high, u32 offset_low,
long sys_s390_fadvise64_64(struct fadvise64_64_args __user *args);
long sys_s390_fallocate(int fd, int mode, loff_t offset, u32 len_high,
u32 len_low);
-long sys_sigsuspend(int history0, int history1, old_sigset_t mask);
-long sys_sigaction(int sig, const struct old_sigaction __user *act,
- struct old_sigaction __user *oact);
-long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss);
long sys_sigreturn(void);
long sys_rt_sigreturn(void);
long sys32_sigreturn(void);
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 6d34e0c97a39..9c837c101297 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -72,9 +72,9 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
#endif
.endm
- .macro SPP newpp
+ .macro LPP newpp
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
- tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP
+ tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_LPP
jz .+8
.insn s,0xb2800000,\newpp
#endif
@@ -96,7 +96,7 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
jhe .+22
.endif
lg %r9,BASED(.Lsie_loop)
- SPP BASED(.Lhost_id) # set host id
+ LPP BASED(.Lhost_id) # set host id
#endif
.endm
@@ -967,10 +967,10 @@ sie_loop:
lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce
sie_gmap:
lg %r14,__SF_EMPTY(%r15) # get control block pointer
- SPP __SF_EMPTY(%r15) # set guest id
+ LPP __SF_EMPTY(%r15) # set guest id
sie 0(%r14)
sie_done:
- SPP __SF_EMPTY+16(%r15) # set host id
+ LPP __SF_EMPTY+16(%r15) # set host id
lg %r14,__LC_THREAD_INFO # pointer thread_info struct
sie_exit:
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 6ffcd3203215..d8a6a385d048 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -1414,6 +1414,16 @@ static struct kobj_attribute dump_type_attr =
static struct kset *dump_kset;
+static void diag308_dump(void *dump_block)
+{
+ diag308(DIAG308_SET, dump_block);
+ while (1) {
+ if (diag308(DIAG308_DUMP, NULL) != 0x302)
+ break;
+ udelay_simple(USEC_PER_SEC);
+ }
+}
+
static void __dump_run(void *unused)
{
struct ccw_dev_id devid;
@@ -1432,12 +1442,10 @@ static void __dump_run(void *unused)
__cpcmd(buf, NULL, 0, NULL);
break;
case DUMP_METHOD_CCW_DIAG:
- diag308(DIAG308_SET, dump_block_ccw);
- diag308(DIAG308_DUMP, NULL);
+ diag308_dump(dump_block_ccw);
break;
case DUMP_METHOD_FCP_DIAG:
- diag308(DIAG308_SET, dump_block_fcp);
- diag308(DIAG308_DUMP, NULL);
+ diag308_dump(dump_block_fcp);
break;
default:
break;
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index 9df824ea1667..1630f439cd2a 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -81,6 +81,7 @@ static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = {
[IRQIO_CSC] = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"},
[IRQIO_PCI] = {.name = "PCI", .desc = "[I/O] PCI Interrupt" },
[IRQIO_MSI] = {.name = "MSI", .desc = "[I/O] MSI Interrupt" },
+ [IRQIO_VIR] = {.name = "VIR", .desc = "[I/O] Virtual I/O Devices"},
[NMI_NMI] = {.name = "NMI", .desc = "[NMI] Machine Check"},
[CPU_RST] = {.name = "RST", .desc = "[CPU] CPU Restart"},
};
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index 4610deafd953..f750bd7bd2c2 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -65,8 +65,7 @@ void module_free(struct module *mod, void *module_region)
vfree(module_region);
}
-static void
-check_rela(Elf_Rela *rela, struct module *me)
+static void check_rela(Elf_Rela *rela, struct module *me)
{
struct mod_arch_syminfo *info;
@@ -115,9 +114,8 @@ check_rela(Elf_Rela *rela, struct module *me)
* Account for GOT and PLT relocations. We can't add sections for
* got and plt but we can increase the core module size.
*/
-int
-module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
- char *secstrings, struct module *me)
+int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+ char *secstrings, struct module *me)
{
Elf_Shdr *symtab;
Elf_Sym *symbols;
@@ -179,13 +177,52 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
return 0;
}
-static int
-apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
- struct module *me)
+static int apply_rela_bits(Elf_Addr loc, Elf_Addr val,
+ int sign, int bits, int shift)
+{
+ unsigned long umax;
+ long min, max;
+
+ if (val & ((1UL << shift) - 1))
+ return -ENOEXEC;
+ if (sign) {
+ val = (Elf_Addr)(((long) val) >> shift);
+ min = -(1L << (bits - 1));
+ max = (1L << (bits - 1)) - 1;
+ if ((long) val < min || (long) val > max)
+ return -ENOEXEC;
+ } else {
+ val >>= shift;
+ umax = ((1UL << (bits - 1)) << 1) - 1;
+ if ((unsigned long) val > umax)
+ return -ENOEXEC;
+ }
+
+ if (bits == 8)
+ *(unsigned char *) loc = val;
+ else if (bits == 12)
+ *(unsigned short *) loc = (val & 0xfff) |
+ (*(unsigned short *) loc & 0xf000);
+ else if (bits == 16)
+ *(unsigned short *) loc = val;
+ else if (bits == 20)
+ *(unsigned int *) loc = (val & 0xfff) << 16 |
+ (val & 0xff000) >> 4 |
+ (*(unsigned int *) loc & 0xf00000ff);
+ else if (bits == 32)
+ *(unsigned int *) loc = val;
+ else if (bits == 64)
+ *(unsigned long *) loc = val;
+ return 0;
+}
+
+static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
+ const char *strtab, struct module *me)
{
struct mod_arch_syminfo *info;
Elf_Addr loc, val;
int r_type, r_sym;
+ int rc;
/* This is where to make the change */
loc = base + rela->r_offset;
@@ -197,6 +234,9 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
val = symtab[r_sym].st_value;
switch (r_type) {
+ case R_390_NONE: /* No relocation. */
+ rc = 0;
+ break;
case R_390_8: /* Direct 8 bit. */
case R_390_12: /* Direct 12 bit. */
case R_390_16: /* Direct 16 bit. */
@@ -205,20 +245,17 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
case R_390_64: /* Direct 64 bit. */
val += rela->r_addend;
if (r_type == R_390_8)
- *(unsigned char *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 8, 0);
else if (r_type == R_390_12)
- *(unsigned short *) loc = (val & 0xfff) |
- (*(unsigned short *) loc & 0xf000);
+ rc = apply_rela_bits(loc, val, 0, 12, 0);
else if (r_type == R_390_16)
- *(unsigned short *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 16, 0);
else if (r_type == R_390_20)
- *(unsigned int *) loc =
- (*(unsigned int *) loc & 0xf00000ff) |
- (val & 0xfff) << 16 | (val & 0xff000) >> 4;
+ rc = apply_rela_bits(loc, val, 1, 20, 0);
else if (r_type == R_390_32)
- *(unsigned int *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 32, 0);
else if (r_type == R_390_64)
- *(unsigned long *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 64, 0);
break;
case R_390_PC16: /* PC relative 16 bit. */
case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */
@@ -227,15 +264,15 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
case R_390_PC64: /* PC relative 64 bit. */
val += rela->r_addend - loc;
if (r_type == R_390_PC16)
- *(unsigned short *) loc = val;
+ rc = apply_rela_bits(loc, val, 1, 16, 0);
else if (r_type == R_390_PC16DBL)
- *(unsigned short *) loc = val >> 1;
+ rc = apply_rela_bits(loc, val, 1, 16, 1);
else if (r_type == R_390_PC32DBL)
- *(unsigned int *) loc = val >> 1;
+ rc = apply_rela_bits(loc, val, 1, 32, 1);
else if (r_type == R_390_PC32)
- *(unsigned int *) loc = val;
+ rc = apply_rela_bits(loc, val, 1, 32, 0);
else if (r_type == R_390_PC64)
- *(unsigned long *) loc = val;
+ rc = apply_rela_bits(loc, val, 1, 64, 0);
break;
case R_390_GOT12: /* 12 bit GOT offset. */
case R_390_GOT16: /* 16 bit GOT offset. */
@@ -260,26 +297,24 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
val = info->got_offset + rela->r_addend;
if (r_type == R_390_GOT12 ||
r_type == R_390_GOTPLT12)
- *(unsigned short *) loc = (val & 0xfff) |
- (*(unsigned short *) loc & 0xf000);
+ rc = apply_rela_bits(loc, val, 0, 12, 0);
else if (r_type == R_390_GOT16 ||
r_type == R_390_GOTPLT16)
- *(unsigned short *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 16, 0);
else if (r_type == R_390_GOT20 ||
r_type == R_390_GOTPLT20)
- *(unsigned int *) loc =
- (*(unsigned int *) loc & 0xf00000ff) |
- (val & 0xfff) << 16 | (val & 0xff000) >> 4;
+ rc = apply_rela_bits(loc, val, 1, 20, 0);
else if (r_type == R_390_GOT32 ||
r_type == R_390_GOTPLT32)
- *(unsigned int *) loc = val;
- else if (r_type == R_390_GOTENT ||
- r_type == R_390_GOTPLTENT)
- *(unsigned int *) loc =
- (val + (Elf_Addr) me->module_core - loc) >> 1;
+ rc = apply_rela_bits(loc, val, 0, 32, 0);
else if (r_type == R_390_GOT64 ||
r_type == R_390_GOTPLT64)
- *(unsigned long *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 64, 0);
+ else if (r_type == R_390_GOTENT ||
+ r_type == R_390_GOTPLTENT) {
+ val += (Elf_Addr) me->module_core - loc;
+ rc = apply_rela_bits(loc, val, 1, 32, 1);
+ }
break;
case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
@@ -321,17 +356,17 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
val += rela->r_addend - loc;
}
if (r_type == R_390_PLT16DBL)
- *(unsigned short *) loc = val >> 1;
+ rc = apply_rela_bits(loc, val, 1, 16, 1);
else if (r_type == R_390_PLTOFF16)
- *(unsigned short *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 16, 0);
else if (r_type == R_390_PLT32DBL)
- *(unsigned int *) loc = val >> 1;
+ rc = apply_rela_bits(loc, val, 1, 32, 1);
else if (r_type == R_390_PLT32 ||
r_type == R_390_PLTOFF32)
- *(unsigned int *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 32, 0);
else if (r_type == R_390_PLT64 ||
r_type == R_390_PLTOFF64)
- *(unsigned long *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 64, 0);
break;
case R_390_GOTOFF16: /* 16 bit offset to GOT. */
case R_390_GOTOFF32: /* 32 bit offset to GOT. */
@@ -339,20 +374,20 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
val = val + rela->r_addend -
((Elf_Addr) me->module_core + me->arch.got_offset);
if (r_type == R_390_GOTOFF16)
- *(unsigned short *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 16, 0);
else if (r_type == R_390_GOTOFF32)
- *(unsigned int *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 32, 0);
else if (r_type == R_390_GOTOFF64)
- *(unsigned long *) loc = val;
+ rc = apply_rela_bits(loc, val, 0, 64, 0);
break;
case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
val = (Elf_Addr) me->module_core + me->arch.got_offset +
rela->r_addend - loc;
if (r_type == R_390_GOTPC)
- *(unsigned int *) loc = val;
+ rc = apply_rela_bits(loc, val, 1, 32, 0);
else if (r_type == R_390_GOTPCDBL)
- *(unsigned int *) loc = val >> 1;
+ rc = apply_rela_bits(loc, val, 1, 32, 1);
break;
case R_390_COPY:
case R_390_GLOB_DAT: /* Create GOT entry. */
@@ -360,19 +395,25 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
case R_390_RELATIVE: /* Adjust by program base. */
/* Only needed if we want to support loading of
modules linked with -shared. */
- break;
+ return -ENOEXEC;
default:
- printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+ printk(KERN_ERR "module %s: unknown relocation: %u\n",
me->name, r_type);
return -ENOEXEC;
}
+ if (rc) {
+ printk(KERN_ERR "module %s: relocation error for symbol %s "
+ "(r_type %i, value 0x%lx)\n",
+ me->name, strtab + symtab[r_sym].st_name,
+ r_type, (unsigned long) val);
+ return rc;
+ }
return 0;
}
-int
-apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
- unsigned int symindex, unsigned int relsec,
- struct module *me)
+int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
+ unsigned int symindex, unsigned int relsec,
+ struct module *me)
{
Elf_Addr base;
Elf_Sym *symtab;
@@ -388,7 +429,7 @@ apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
n = sechdrs[relsec].sh_size / sizeof(Elf_Rela);
for (i = 0; i < n; i++, rela++) {
- rc = apply_rela(rela, base, symtab, me);
+ rc = apply_rela(rela, base, symtab, strtab, me);
if (rc)
return rc;
}
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c
index 7918fbea36bb..504175ebf8b0 100644
--- a/arch/s390/kernel/nmi.c
+++ b/arch/s390/kernel/nmi.c
@@ -293,7 +293,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
* retry this instruction.
*/
spin_lock(&ipd_lock);
- tmp = get_clock();
+ tmp = get_tod_clock();
if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME)
ipd_count++;
else
diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c
index 86ec7447e1f5..390d9ae57bb2 100644
--- a/arch/s390/kernel/perf_cpum_cf.c
+++ b/arch/s390/kernel/perf_cpum_cf.c
@@ -367,13 +367,6 @@ static int __hw_perf_event_init(struct perf_event *event)
if (ev >= PERF_CPUM_CF_MAX_CTR)
return -EINVAL;
- /* The CPU measurement counter facility does not have any interrupts
- * to do sampling. Sampling must be provided by external means,
- * for example, by timers.
- */
- if (hwc->sample_period)
- return -EINVAL;
-
/* Use the hardware perf event structure to store the counter number
* in 'config' member and the counter set to which the counter belongs
* in the 'config_base'. The counter set (config_base) is then used
@@ -418,6 +411,12 @@ static int cpumf_pmu_event_init(struct perf_event *event)
case PERF_TYPE_HARDWARE:
case PERF_TYPE_HW_CACHE:
case PERF_TYPE_RAW:
+ /* The CPU measurement counter facility does not have overflow
+ * interrupts to do sampling. Sampling must be provided by
+ * external means, for example, by timers.
+ */
+ if (is_sampling_event(event))
+ return -ENOENT;
err = __hw_perf_event_init(event);
break;
default:
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index c3ff70a7b247..9c6e747a5e1e 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -48,54 +48,6 @@ typedef struct
struct ucontext uc;
} rt_sigframe;
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-SYSCALL_DEFINE3(sigaction, int, sig, const struct old_sigaction __user *, act,
- struct old_sigaction __user *, oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
-SYSCALL_DEFINE2(sigaltstack, const stack_t __user *, uss,
- stack_t __user *, uoss)
-{
- struct pt_regs *regs = task_pt_regs(current);
- return do_sigaltstack(uss, uoss, regs->gprs[15]);
-}
-
/* Returns non-zero on fault. */
static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
{
@@ -190,8 +142,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
set_current_blocked(&set);
if (restore_sigregs(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL,
- regs->gprs[15]) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return regs->gprs[2];
badframe:
@@ -325,10 +276,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
- err |= __put_user((void __user *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->gprs[15]),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->gprs[15]);
err |= save_sigregs(regs, &frame->uc.uc_mcontext);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 7433a2f9e5cc..549c9d173c0f 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -365,16 +365,16 @@ void smp_emergency_stop(cpumask_t *cpumask)
u64 end;
int cpu;
- end = get_clock() + (1000000UL << 12);
+ end = get_tod_clock() + (1000000UL << 12);
for_each_cpu(cpu, cpumask) {
struct pcpu *pcpu = pcpu_devices + cpu;
set_bit(ec_stop_cpu, &pcpu->ec_mask);
while (__pcpu_sigp(pcpu->address, SIGP_EMERGENCY_SIGNAL,
0, NULL) == SIGP_CC_BUSY &&
- get_clock() < end)
+ get_tod_clock() < end)
cpu_relax();
}
- while (get_clock() < end) {
+ while (get_tod_clock() < end) {
for_each_cpu(cpu, cpumask)
if (pcpu_stopped(pcpu_devices + cpu))
cpumask_clear_cpu(cpu, cpumask);
@@ -694,7 +694,7 @@ static void __init smp_detect_cpus(void)
*/
static void __cpuinit smp_start_secondary(void *cpuvoid)
{
- S390_lowcore.last_update_clock = get_clock();
+ S390_lowcore.last_update_clock = get_tod_clock();
S390_lowcore.restart_stack = (unsigned long) restart_stack;
S390_lowcore.restart_fn = (unsigned long) do_restart;
S390_lowcore.restart_data = 0;
@@ -947,7 +947,7 @@ static ssize_t show_idle_time(struct device *dev,
unsigned int sequence;
do {
- now = get_clock();
+ now = get_tod_clock();
sequence = ACCESS_ONCE(idle->sequence);
idle_time = ACCESS_ONCE(idle->idle_time);
idle_enter = ACCESS_ONCE(idle->clock_idle_enter);
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 6a6c61f94dd3..aaac708aa110 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -13,7 +13,7 @@ SYSCALL(sys_exit,sys_exit,sys32_exit_wrapper)
SYSCALL(sys_fork,sys_fork,sys_fork)
SYSCALL(sys_read,sys_read,sys32_read_wrapper)
SYSCALL(sys_write,sys_write,sys32_write_wrapper)
-SYSCALL(sys_open,sys_open,sys32_open_wrapper) /* 5 */
+SYSCALL(sys_open,sys_open,compat_sys_open) /* 5 */
SYSCALL(sys_close,sys_close,sys32_close_wrapper)
SYSCALL(sys_restart_syscall,sys_restart_syscall,sys_restart_syscall)
SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper)
@@ -75,7 +75,7 @@ SYSCALL(sys_dup2,sys_dup2,sys32_dup2_wrapper)
SYSCALL(sys_getppid,sys_getppid,sys_getppid)
SYSCALL(sys_getpgrp,sys_getpgrp,sys_getpgrp) /* 65 */
SYSCALL(sys_setsid,sys_setsid,sys_setsid)
-SYSCALL(sys_sigaction,sys_sigaction,sys32_sigaction_wrapper)
+SYSCALL(sys_sigaction,sys_sigaction,compat_sys_sigaction)
NI_SYSCALL /* old sgetmask syscall*/
NI_SYSCALL /* old ssetmask syscall*/
SYSCALL(sys_setreuid16,sys_ni_syscall,sys32_setreuid16_wrapper) /* old setreuid16 syscall */
@@ -112,8 +112,8 @@ SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs_wrapper) /* 100 */
NI_SYSCALL /* ioperm for i386 */
SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall_wrapper)
SYSCALL(sys_syslog,sys_syslog,sys32_syslog_wrapper)
-SYSCALL(sys_setitimer,sys_setitimer,compat_sys_setitimer_wrapper)
-SYSCALL(sys_getitimer,sys_getitimer,compat_sys_getitimer_wrapper) /* 105 */
+SYSCALL(sys_setitimer,sys_setitimer,compat_sys_setitimer)
+SYSCALL(sys_getitimer,sys_getitimer,compat_sys_getitimer) /* 105 */
SYSCALL(sys_newstat,sys_newstat,compat_sys_newstat_wrapper)
SYSCALL(sys_newlstat,sys_newlstat,compat_sys_newlstat_wrapper)
SYSCALL(sys_newfstat,sys_newfstat,compat_sys_newfstat_wrapper)
@@ -122,7 +122,7 @@ SYSCALL(sys_lookup_dcookie,sys_lookup_dcookie,sys32_lookup_dcookie_wrapper) /* 1
SYSCALL(sys_vhangup,sys_vhangup,sys_vhangup)
NI_SYSCALL /* old "idle" system call */
NI_SYSCALL /* vm86old for i386 */
-SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4_wrapper)
+SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4)
SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */
SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper)
SYSCALL(sys_s390_ipc,sys_s390_ipc,sys32_ipc_wrapper)
@@ -134,7 +134,7 @@ SYSCALL(sys_newuname,sys_newuname,sys32_newuname_wrapper)
NI_SYSCALL /* modify_ldt for i386 */
SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper)
SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper) /* 125 */
-SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask_wrapper)
+SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask)
NI_SYSCALL /* old "create module" */
SYSCALL(sys_init_module,sys_init_module,sys_init_module_wrapper)
SYSCALL(sys_delete_module,sys_delete_module,sys_delete_module_wrapper)
@@ -169,7 +169,7 @@ SYSCALL(sys_sched_getscheduler,sys_sched_getscheduler,sys32_sched_getscheduler_w
SYSCALL(sys_sched_yield,sys_sched_yield,sys_sched_yield)
SYSCALL(sys_sched_get_priority_max,sys_sched_get_priority_max,sys32_sched_get_priority_max_wrapper)
SYSCALL(sys_sched_get_priority_min,sys_sched_get_priority_min,sys32_sched_get_priority_min_wrapper) /* 160 */
-SYSCALL(sys_sched_rr_get_interval,sys_sched_rr_get_interval,sys32_sched_rr_get_interval_wrapper)
+SYSCALL(sys_sched_rr_get_interval,sys_sched_rr_get_interval,compat_sys_sched_rr_get_interval)
SYSCALL(sys_nanosleep,sys_nanosleep,compat_sys_nanosleep_wrapper)
SYSCALL(sys_mremap,sys_mremap,sys32_mremap_wrapper)
SYSCALL(sys_setresuid16,sys_ni_syscall,sys32_setresuid16_wrapper) /* old setresuid16 syscall */
@@ -182,19 +182,19 @@ SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper) /* 170 old set
SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */
SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,sys32_rt_sigreturn)
-SYSCALL(sys_rt_sigaction,sys_rt_sigaction,sys32_rt_sigaction_wrapper)
-SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,sys32_rt_sigprocmask_wrapper) /* 175 */
-SYSCALL(sys_rt_sigpending,sys_rt_sigpending,sys32_rt_sigpending_wrapper)
-SYSCALL(sys_rt_sigtimedwait,sys_rt_sigtimedwait,compat_sys_rt_sigtimedwait_wrapper)
-SYSCALL(sys_rt_sigqueueinfo,sys_rt_sigqueueinfo,sys32_rt_sigqueueinfo_wrapper)
-SYSCALL(sys_rt_sigsuspend,sys_rt_sigsuspend,compat_sys_rt_sigsuspend_wrapper)
+SYSCALL(sys_rt_sigaction,sys_rt_sigaction,compat_sys_rt_sigaction)
+SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,compat_sys_rt_sigprocmask) /* 175 */
+SYSCALL(sys_rt_sigpending,sys_rt_sigpending,compat_sys_rt_sigpending)
+SYSCALL(sys_rt_sigtimedwait,sys_rt_sigtimedwait,compat_sys_rt_sigtimedwait)
+SYSCALL(sys_rt_sigqueueinfo,sys_rt_sigqueueinfo,compat_sys_rt_sigqueueinfo)
+SYSCALL(sys_rt_sigsuspend,sys_rt_sigsuspend,compat_sys_rt_sigsuspend)
SYSCALL(sys_pread64,sys_pread64,sys32_pread64_wrapper) /* 180 */
SYSCALL(sys_pwrite64,sys_pwrite64,sys32_pwrite64_wrapper)
SYSCALL(sys_chown16,sys_ni_syscall,sys32_chown16_wrapper) /* old chown16 syscall */
SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper)
SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper)
SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper) /* 185 */
-SYSCALL(sys_sigaltstack,sys_sigaltstack,sys32_sigaltstack_wrapper)
+SYSCALL(sys_sigaltstack,sys_sigaltstack,compat_sys_sigaltstack)
SYSCALL(sys_sendfile,sys_sendfile64,sys32_sendfile_wrapper)
NI_SYSCALL /* streams1 */
NI_SYSCALL /* streams2 */
@@ -246,7 +246,7 @@ SYSCALL(sys_lremovexattr,sys_lremovexattr,sys32_lremovexattr_wrapper)
SYSCALL(sys_fremovexattr,sys_fremovexattr,sys32_fremovexattr_wrapper) /* 235 */
SYSCALL(sys_gettid,sys_gettid,sys_gettid)
SYSCALL(sys_tkill,sys_tkill,sys_tkill_wrapper)
-SYSCALL(sys_futex,sys_futex,compat_sys_futex_wrapper)
+SYSCALL(sys_futex,sys_futex,compat_sys_futex)
SYSCALL(sys_sched_setaffinity,sys_sched_setaffinity,sys32_sched_setaffinity_wrapper)
SYSCALL(sys_sched_getaffinity,sys_sched_getaffinity,sys32_sched_getaffinity_wrapper) /* 240 */
SYSCALL(sys_tgkill,sys_tgkill,sys_tgkill_wrapper)
@@ -289,14 +289,14 @@ SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper)
SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl_wrapper) /* 280 */
-SYSCALL(sys_waitid,sys_waitid,compat_sys_waitid_wrapper)
+SYSCALL(sys_waitid,sys_waitid,compat_sys_waitid)
SYSCALL(sys_ioprio_set,sys_ioprio_set,sys_ioprio_set_wrapper)
SYSCALL(sys_ioprio_get,sys_ioprio_get,sys_ioprio_get_wrapper)
SYSCALL(sys_inotify_init,sys_inotify_init,sys_inotify_init)
SYSCALL(sys_inotify_add_watch,sys_inotify_add_watch,sys_inotify_add_watch_wrapper) /* 285 */
SYSCALL(sys_inotify_rm_watch,sys_inotify_rm_watch,sys_inotify_rm_watch_wrapper)
NI_SYSCALL /* 287 sys_migrate_pages */
-SYSCALL(sys_openat,sys_openat,compat_sys_openat_wrapper)
+SYSCALL(sys_openat,sys_openat,compat_sys_openat)
SYSCALL(sys_mkdirat,sys_mkdirat,sys_mkdirat_wrapper)
SYSCALL(sys_mknodat,sys_mknodat,sys_mknodat_wrapper) /* 290 */
SYSCALL(sys_fchownat,sys_fchownat,sys_fchownat_wrapper)
@@ -312,8 +312,8 @@ SYSCALL(sys_faccessat,sys_faccessat,sys_faccessat_wrapper) /* 300 */
SYSCALL(sys_pselect6,sys_pselect6,compat_sys_pselect6_wrapper)
SYSCALL(sys_ppoll,sys_ppoll,compat_sys_ppoll_wrapper)
SYSCALL(sys_unshare,sys_unshare,sys_unshare_wrapper)
-SYSCALL(sys_set_robust_list,sys_set_robust_list,compat_sys_set_robust_list_wrapper)
-SYSCALL(sys_get_robust_list,sys_get_robust_list,compat_sys_get_robust_list_wrapper)
+SYSCALL(sys_set_robust_list,sys_set_robust_list,compat_sys_set_robust_list)
+SYSCALL(sys_get_robust_list,sys_get_robust_list,compat_sys_get_robust_list)
SYSCALL(sys_splice,sys_splice,sys_splice_wrapper)
SYSCALL(sys_sync_file_range,sys_sync_file_range,sys_sync_file_range_wrapper)
SYSCALL(sys_tee,sys_tee,sys_tee_wrapper)
@@ -328,8 +328,8 @@ SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper)
NI_SYSCALL /* 317 old sys_timer_fd */
SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper)
-SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime_wrapper) /* 320 */
-SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime_wrapper)
+SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime) /* 320 */
+SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime)
SYSCALL(sys_signalfd4,sys_signalfd4,compat_sys_signalfd4_wrapper)
SYSCALL(sys_eventfd2,sys_eventfd2,sys_eventfd2_wrapper)
SYSCALL(sys_inotify_init1,sys_inotify_init1,sys_inotify_init1_wrapper)
@@ -338,13 +338,13 @@ SYSCALL(sys_dup3,sys_dup3,sys_dup3_wrapper)
SYSCALL(sys_epoll_create1,sys_epoll_create1,sys_epoll_create1_wrapper)
SYSCALL(sys_preadv,sys_preadv,compat_sys_preadv_wrapper)
SYSCALL(sys_pwritev,sys_pwritev,compat_sys_pwritev_wrapper)
-SYSCALL(sys_rt_tgsigqueueinfo,sys_rt_tgsigqueueinfo,compat_sys_rt_tgsigqueueinfo_wrapper) /* 330 */
+SYSCALL(sys_rt_tgsigqueueinfo,sys_rt_tgsigqueueinfo,compat_sys_rt_tgsigqueueinfo) /* 330 */
SYSCALL(sys_perf_event_open,sys_perf_event_open,sys_perf_event_open_wrapper)
SYSCALL(sys_fanotify_init,sys_fanotify_init,sys_fanotify_init_wrapper)
SYSCALL(sys_fanotify_mark,sys_fanotify_mark,sys_fanotify_mark_wrapper)
SYSCALL(sys_prlimit64,sys_prlimit64,sys_prlimit64_wrapper)
SYSCALL(sys_name_to_handle_at,sys_name_to_handle_at,sys_name_to_handle_at_wrapper) /* 335 */
-SYSCALL(sys_open_by_handle_at,sys_open_by_handle_at,compat_sys_open_by_handle_at_wrapper)
+SYSCALL(sys_open_by_handle_at,sys_open_by_handle_at,compat_sys_open_by_handle_at)
SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime_wrapper)
SYSCALL(sys_syncfs,sys_syncfs,sys_syncfs_wrapper)
SYSCALL(sys_setns,sys_setns,sys_setns_wrapper)
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index a5f4f5a1d24b..876546b9cfa1 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -63,7 +63,7 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators);
*/
unsigned long long notrace __kprobes sched_clock(void)
{
- return tod_to_ns(get_clock_monotonic());
+ return tod_to_ns(get_tod_clock_monotonic());
}
/*
@@ -120,6 +120,9 @@ static int s390_next_ktime(ktime_t expires,
nsecs = ktime_to_ns(ktime_add(timespec_to_ktime(ts), expires));
do_div(nsecs, 125);
S390_lowcore.clock_comparator = sched_clock_base_cc + (nsecs << 9);
+ /* Program the maximum value if we have an overflow (== year 2042) */
+ if (unlikely(S390_lowcore.clock_comparator < sched_clock_base_cc))
+ S390_lowcore.clock_comparator = -1ULL;
set_clock_comparator(S390_lowcore.clock_comparator);
return 0;
}
@@ -191,7 +194,7 @@ static void stp_reset(void);
void read_persistent_clock(struct timespec *ts)
{
- tod_to_timeval(get_clock() - TOD_UNIX_EPOCH, ts);
+ tod_to_timeval(get_tod_clock() - TOD_UNIX_EPOCH, ts);
}
void read_boot_clock(struct timespec *ts)
@@ -201,7 +204,7 @@ void read_boot_clock(struct timespec *ts)
static cycle_t read_tod_clock(struct clocksource *cs)
{
- return get_clock();
+ return get_tod_clock();
}
static struct clocksource clocksource_tod = {
@@ -339,7 +342,7 @@ int get_sync_clock(unsigned long long *clock)
sw_ptr = &get_cpu_var(clock_sync_word);
sw0 = atomic_read(sw_ptr);
- *clock = get_clock();
+ *clock = get_tod_clock();
sw1 = atomic_read(sw_ptr);
put_cpu_var(clock_sync_word);
if (sw0 == sw1 && (sw0 & 0x80000000U))
@@ -483,7 +486,7 @@ static void etr_reset(void)
.p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0,
.es = 0, .sl = 0 };
if (etr_setr(&etr_eacr) == 0) {
- etr_tolec = get_clock();
+ etr_tolec = get_tod_clock();
set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags);
if (etr_port0_online && etr_port1_online)
set_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
@@ -765,8 +768,8 @@ static int etr_sync_clock(void *data)
__ctl_set_bit(14, 21);
__ctl_set_bit(0, 29);
clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32;
- old_clock = get_clock();
- if (set_clock(clock) == 0) {
+ old_clock = get_tod_clock();
+ if (set_tod_clock(clock) == 0) {
__udelay(1); /* Wait for the clock to start. */
__ctl_clear_bit(0, 29);
__ctl_clear_bit(14, 21);
@@ -842,7 +845,7 @@ static struct etr_eacr etr_handle_events(struct etr_eacr eacr)
* assume that this can have caused an stepping
* port switch.
*/
- etr_tolec = get_clock();
+ etr_tolec = get_tod_clock();
eacr.p0 = etr_port0_online;
if (!eacr.p0)
eacr.e0 = 0;
@@ -855,7 +858,7 @@ static struct etr_eacr etr_handle_events(struct etr_eacr eacr)
* assume that this can have caused an stepping
* port switch.
*/
- etr_tolec = get_clock();
+ etr_tolec = get_tod_clock();
eacr.p1 = etr_port1_online;
if (!eacr.p1)
eacr.e1 = 0;
@@ -971,7 +974,7 @@ static void etr_update_eacr(struct etr_eacr eacr)
etr_eacr = eacr;
etr_setr(&etr_eacr);
if (dp_changed)
- etr_tolec = get_clock();
+ etr_tolec = get_tod_clock();
}
/*
@@ -1009,7 +1012,7 @@ static void etr_work_fn(struct work_struct *work)
/* Store aib to get the current ETR status word. */
BUG_ON(etr_stetr(&aib) != 0);
etr_port0.esw = etr_port1.esw = aib.esw; /* Copy status word. */
- now = get_clock();
+ now = get_tod_clock();
/*
* Update the port information if the last stepping port change
@@ -1534,10 +1537,10 @@ static int stp_sync_clock(void *data)
if (stp_info.todoff[0] || stp_info.todoff[1] ||
stp_info.todoff[2] || stp_info.todoff[3] ||
stp_info.tmd != 2) {
- old_clock = get_clock();
+ old_clock = get_tod_clock();
rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0);
if (rc == 0) {
- delta = adjust_time(old_clock, get_clock(), 0);
+ delta = adjust_time(old_clock, get_tod_clock(), 0);
fixup_clock_comparator(delta);
rc = chsc_sstpi(stp_page, &stp_info,
sizeof(struct stp_sstpi));
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 70ecfc5fe8f0..13dd63fba367 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -271,7 +271,7 @@ void die(struct pt_regs *regs, const char *str)
print_modules();
show_regs(regs);
bust_spinlocks(0);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
spin_unlock_irq(&die_lock);
if (in_interrupt())
panic("Fatal exception in interrupt");
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 79cb51adc741..35b13ed0af5f 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -75,6 +75,10 @@ SECTIONS
EXIT_TEXT
}
+ .exit.data : {
+ EXIT_DATA
+ }
+
/* early.c uses stsi, which requires page aligned data. */
. = ALIGN(PAGE_SIZE);
INIT_DATA_SECTION(0x100)
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index e84b8b68444a..a0042acbd989 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -127,7 +127,7 @@ void vtime_account_user(struct task_struct *tsk)
* Update process times based on virtual cpu times stored by entry.S
* to the lowcore fields user_timer, system_timer & steal_clock.
*/
-void vtime_account(struct task_struct *tsk)
+void vtime_account_irq_enter(struct task_struct *tsk)
{
struct thread_info *ti = task_thread_info(tsk);
u64 timer, system;
@@ -145,10 +145,10 @@ void vtime_account(struct task_struct *tsk)
virt_timer_forward(system);
}
-EXPORT_SYMBOL_GPL(vtime_account);
+EXPORT_SYMBOL_GPL(vtime_account_irq_enter);
void vtime_account_system(struct task_struct *tsk)
-__attribute__((alias("vtime_account")));
+__attribute__((alias("vtime_account_irq_enter")));
EXPORT_SYMBOL_GPL(vtime_account_system);
void __kprobes vtime_stop_cpu(void)
@@ -191,7 +191,7 @@ cputime64_t s390_get_idle_time(int cpu)
unsigned int sequence;
do {
- now = get_clock();
+ now = get_tod_clock();
sequence = ACCESS_ONCE(idle->sequence);
idle_enter = ACCESS_ONCE(idle->clock_idle_enter);
idle_exit = ACCESS_ONCE(idle->clock_idle_exit);
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index b58dd869cb32..60f9f8ae0fc8 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -18,7 +18,7 @@ if VIRTUALIZATION
config KVM
def_tristate y
prompt "Kernel-based Virtual Machine (KVM) support"
- depends on HAVE_KVM && EXPERIMENTAL
+ depends on HAVE_KVM
select PREEMPT_NOTIFIERS
select ANON_INODES
select HAVE_KVM_CPU_RELAX_INTERCEPT
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 22798ec33fd1..f26ff1e31bdb 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -26,27 +26,20 @@ static int handle_lctlg(struct kvm_vcpu *vcpu)
{
int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
- int base2 = vcpu->arch.sie_block->ipb >> 28;
- int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) +
- ((vcpu->arch.sie_block->ipb & 0xff00) << 4);
u64 useraddr;
int reg, rc;
vcpu->stat.instruction_lctlg++;
- if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f)
- return -EOPNOTSUPP;
- useraddr = disp2;
- if (base2)
- useraddr += vcpu->run->s.regs.gprs[base2];
+ useraddr = kvm_s390_get_base_disp_rsy(vcpu);
if (useraddr & 7)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
reg = reg1;
- VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
- disp2);
+ VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3,
+ useraddr);
trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr);
do {
@@ -68,23 +61,19 @@ static int handle_lctl(struct kvm_vcpu *vcpu)
{
int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
- int base2 = vcpu->arch.sie_block->ipb >> 28;
- int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
u64 useraddr;
u32 val = 0;
int reg, rc;
vcpu->stat.instruction_lctl++;
- useraddr = disp2;
- if (base2)
- useraddr += vcpu->run->s.regs.gprs[base2];
+ useraddr = kvm_s390_get_base_disp_rs(vcpu);
if (useraddr & 3)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
- VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
- disp2);
+ VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3,
+ useraddr);
trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr);
reg = reg1;
@@ -104,14 +93,31 @@ static int handle_lctl(struct kvm_vcpu *vcpu)
return 0;
}
-static intercept_handler_t instruction_handlers[256] = {
+static const intercept_handler_t eb_handlers[256] = {
+ [0x2f] = handle_lctlg,
+ [0x8a] = kvm_s390_handle_priv_eb,
+};
+
+static int handle_eb(struct kvm_vcpu *vcpu)
+{
+ intercept_handler_t handler;
+
+ handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff];
+ if (handler)
+ return handler(vcpu);
+ return -EOPNOTSUPP;
+}
+
+static const intercept_handler_t instruction_handlers[256] = {
[0x01] = kvm_s390_handle_01,
+ [0x82] = kvm_s390_handle_lpsw,
[0x83] = kvm_s390_handle_diag,
[0xae] = kvm_s390_handle_sigp,
[0xb2] = kvm_s390_handle_b2,
[0xb7] = handle_lctl,
+ [0xb9] = kvm_s390_handle_b9,
[0xe5] = kvm_s390_handle_e5,
- [0xeb] = handle_lctlg,
+ [0xeb] = handle_eb,
};
static int handle_noop(struct kvm_vcpu *vcpu)
@@ -258,6 +264,7 @@ static const intercept_handler_t intercept_funcs[] = {
[0x0C >> 2] = handle_instruction_and_prog,
[0x10 >> 2] = handle_noop,
[0x14 >> 2] = handle_noop,
+ [0x18 >> 2] = handle_noop,
[0x1C >> 2] = kvm_s390_handle_wait,
[0x20 >> 2] = handle_validity,
[0x28 >> 2] = handle_stop,
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 82c481ddef76..37116a77cb4b 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -21,11 +21,31 @@
#include "gaccess.h"
#include "trace-s390.h"
+#define IOINT_SCHID_MASK 0x0000ffff
+#define IOINT_SSID_MASK 0x00030000
+#define IOINT_CSSID_MASK 0x03fc0000
+#define IOINT_AI_MASK 0x04000000
+
+static int is_ioint(u64 type)
+{
+ return ((type & 0xfffe0000u) != 0xfffe0000u);
+}
+
static int psw_extint_disabled(struct kvm_vcpu *vcpu)
{
return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);
}
+static int psw_ioint_disabled(struct kvm_vcpu *vcpu)
+{
+ return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO);
+}
+
+static int psw_mchk_disabled(struct kvm_vcpu *vcpu)
+{
+ return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_MCHECK);
+}
+
static int psw_interrupts_disabled(struct kvm_vcpu *vcpu)
{
if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) ||
@@ -35,6 +55,13 @@ static int psw_interrupts_disabled(struct kvm_vcpu *vcpu)
return 1;
}
+static u64 int_word_to_isc_bits(u32 int_word)
+{
+ u8 isc = (int_word & 0x38000000) >> 27;
+
+ return (0x80 >> isc) << 24;
+}
+
static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
struct kvm_s390_interrupt_info *inti)
{
@@ -67,7 +94,22 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
case KVM_S390_SIGP_SET_PREFIX:
case KVM_S390_RESTART:
return 1;
+ case KVM_S390_MCHK:
+ if (psw_mchk_disabled(vcpu))
+ return 0;
+ if (vcpu->arch.sie_block->gcr[14] & inti->mchk.cr14)
+ return 1;
+ return 0;
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+ if (psw_ioint_disabled(vcpu))
+ return 0;
+ if (vcpu->arch.sie_block->gcr[6] &
+ int_word_to_isc_bits(inti->io.io_int_word))
+ return 1;
+ return 0;
default:
+ printk(KERN_WARNING "illegal interrupt type %llx\n",
+ inti->type);
BUG();
}
return 0;
@@ -93,6 +135,7 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT,
&vcpu->arch.sie_block->cpuflags);
vcpu->arch.sie_block->lctl = 0x0000;
+ vcpu->arch.sie_block->ictl &= ~ICTL_LPSW;
}
static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag)
@@ -116,6 +159,18 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
case KVM_S390_SIGP_STOP:
__set_cpuflag(vcpu, CPUSTAT_STOP_INT);
break;
+ case KVM_S390_MCHK:
+ if (psw_mchk_disabled(vcpu))
+ vcpu->arch.sie_block->ictl |= ICTL_LPSW;
+ else
+ vcpu->arch.sie_block->lctl |= LCTL_CR14;
+ break;
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+ if (psw_ioint_disabled(vcpu))
+ __set_cpuflag(vcpu, CPUSTAT_IO_INT);
+ else
+ vcpu->arch.sie_block->lctl |= LCTL_CR6;
+ break;
default:
BUG();
}
@@ -297,6 +352,73 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
exception = 1;
break;
+ case KVM_S390_MCHK:
+ VCPU_EVENT(vcpu, 4, "interrupt: machine check mcic=%llx",
+ inti->mchk.mcic);
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+ inti->mchk.cr14,
+ inti->mchk.mcic);
+ rc = kvm_s390_vcpu_store_status(vcpu,
+ KVM_S390_STORE_STATUS_PREFIXED);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = put_guest_u64(vcpu, __LC_MCCK_CODE, inti->mchk.mcic);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_to_guest(vcpu, __LC_MCK_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_MCK_NEW_PSW, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+ break;
+
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+ {
+ __u32 param0 = ((__u32)inti->io.subchannel_id << 16) |
+ inti->io.subchannel_nr;
+ __u64 param1 = ((__u64)inti->io.io_int_parm << 32) |
+ inti->io.io_int_word;
+ VCPU_EVENT(vcpu, 4, "interrupt: I/O %llx", inti->type);
+ vcpu->stat.deliver_io_int++;
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+ param0, param1);
+ rc = put_guest_u16(vcpu, __LC_SUBCHANNEL_ID,
+ inti->io.subchannel_id);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = put_guest_u16(vcpu, __LC_SUBCHANNEL_NR,
+ inti->io.subchannel_nr);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = put_guest_u32(vcpu, __LC_IO_INT_PARM,
+ inti->io.io_int_parm);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = put_guest_u32(vcpu, __LC_IO_INT_WORD,
+ inti->io.io_int_word);
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_to_guest(vcpu, __LC_IO_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+
+ rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
+ __LC_IO_NEW_PSW, sizeof(psw_t));
+ if (rc == -EFAULT)
+ exception = 1;
+ break;
+ }
default:
BUG();
}
@@ -362,7 +484,7 @@ static int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
}
if ((!rc) && (vcpu->arch.sie_block->ckc <
- get_clock() + vcpu->arch.sie_block->epoch)) {
+ get_tod_clock() + vcpu->arch.sie_block->epoch)) {
if ((!psw_extint_disabled(vcpu)) &&
(vcpu->arch.sie_block->gcr[0] & 0x800ul))
rc = 1;
@@ -402,7 +524,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
goto no_timer;
}
- now = get_clock() + vcpu->arch.sie_block->epoch;
+ now = get_tod_clock() + vcpu->arch.sie_block->epoch;
if (vcpu->arch.sie_block->ckc < now) {
__unset_cpu_idle(vcpu);
return 0;
@@ -492,7 +614,7 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
}
if ((vcpu->arch.sie_block->ckc <
- get_clock() + vcpu->arch.sie_block->epoch))
+ get_tod_clock() + vcpu->arch.sie_block->epoch))
__try_deliver_ckc_interrupt(vcpu);
if (atomic_read(&fi->active)) {
@@ -518,6 +640,61 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
}
}
+void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int;
+ struct kvm_s390_interrupt_info *n, *inti = NULL;
+ int deliver;
+
+ __reset_intercept_indicators(vcpu);
+ if (atomic_read(&li->active)) {
+ do {
+ deliver = 0;
+ spin_lock_bh(&li->lock);
+ list_for_each_entry_safe(inti, n, &li->list, list) {
+ if ((inti->type == KVM_S390_MCHK) &&
+ __interrupt_is_deliverable(vcpu, inti)) {
+ list_del(&inti->list);
+ deliver = 1;
+ break;
+ }
+ __set_intercept_indicator(vcpu, inti);
+ }
+ if (list_empty(&li->list))
+ atomic_set(&li->active, 0);
+ spin_unlock_bh(&li->lock);
+ if (deliver) {
+ __do_deliver_interrupt(vcpu, inti);
+ kfree(inti);
+ }
+ } while (deliver);
+ }
+
+ if (atomic_read(&fi->active)) {
+ do {
+ deliver = 0;
+ spin_lock(&fi->lock);
+ list_for_each_entry_safe(inti, n, &fi->list, list) {
+ if ((inti->type == KVM_S390_MCHK) &&
+ __interrupt_is_deliverable(vcpu, inti)) {
+ list_del(&inti->list);
+ deliver = 1;
+ break;
+ }
+ __set_intercept_indicator(vcpu, inti);
+ }
+ if (list_empty(&fi->list))
+ atomic_set(&fi->active, 0);
+ spin_unlock(&fi->lock);
+ if (deliver) {
+ __do_deliver_interrupt(vcpu, inti);
+ kfree(inti);
+ }
+ } while (deliver);
+ }
+}
+
int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -540,12 +717,50 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
return 0;
}
+struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
+ u64 cr6, u64 schid)
+{
+ struct kvm_s390_float_interrupt *fi;
+ struct kvm_s390_interrupt_info *inti, *iter;
+
+ if ((!schid && !cr6) || (schid && cr6))
+ return NULL;
+ mutex_lock(&kvm->lock);
+ fi = &kvm->arch.float_int;
+ spin_lock(&fi->lock);
+ inti = NULL;
+ list_for_each_entry(iter, &fi->list, list) {
+ if (!is_ioint(iter->type))
+ continue;
+ if (cr6 &&
+ ((cr6 & int_word_to_isc_bits(iter->io.io_int_word)) == 0))
+ continue;
+ if (schid) {
+ if (((schid & 0x00000000ffff0000) >> 16) !=
+ iter->io.subchannel_id)
+ continue;
+ if ((schid & 0x000000000000ffff) !=
+ iter->io.subchannel_nr)
+ continue;
+ }
+ inti = iter;
+ break;
+ }
+ if (inti)
+ list_del_init(&inti->list);
+ if (list_empty(&fi->list))
+ atomic_set(&fi->active, 0);
+ spin_unlock(&fi->lock);
+ mutex_unlock(&kvm->lock);
+ return inti;
+}
+
int kvm_s390_inject_vm(struct kvm *kvm,
struct kvm_s390_interrupt *s390int)
{
struct kvm_s390_local_interrupt *li;
struct kvm_s390_float_interrupt *fi;
- struct kvm_s390_interrupt_info *inti;
+ struct kvm_s390_interrupt_info *inti, *iter;
int sigcpu;
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
@@ -569,6 +784,29 @@ int kvm_s390_inject_vm(struct kvm *kvm,
case KVM_S390_SIGP_STOP:
case KVM_S390_INT_EXTERNAL_CALL:
case KVM_S390_INT_EMERGENCY:
+ kfree(inti);
+ return -EINVAL;
+ case KVM_S390_MCHK:
+ VM_EVENT(kvm, 5, "inject: machine check parm64:%llx",
+ s390int->parm64);
+ inti->type = s390int->type;
+ inti->mchk.cr14 = s390int->parm; /* upper bits are not used */
+ inti->mchk.mcic = s390int->parm64;
+ break;
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+ if (s390int->type & IOINT_AI_MASK)
+ VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)");
+ else
+ VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x",
+ s390int->type & IOINT_CSSID_MASK,
+ s390int->type & IOINT_SSID_MASK,
+ s390int->type & IOINT_SCHID_MASK);
+ inti->type = s390int->type;
+ inti->io.subchannel_id = s390int->parm >> 16;
+ inti->io.subchannel_nr = s390int->parm & 0x0000ffffu;
+ inti->io.io_int_parm = s390int->parm64 >> 32;
+ inti->io.io_int_word = s390int->parm64 & 0x00000000ffffffffull;
+ break;
default:
kfree(inti);
return -EINVAL;
@@ -579,7 +817,22 @@ int kvm_s390_inject_vm(struct kvm *kvm,
mutex_lock(&kvm->lock);
fi = &kvm->arch.float_int;
spin_lock(&fi->lock);
- list_add_tail(&inti->list, &fi->list);
+ if (!is_ioint(inti->type))
+ list_add_tail(&inti->list, &fi->list);
+ else {
+ u64 isc_bits = int_word_to_isc_bits(inti->io.io_int_word);
+
+ /* Keep I/O interrupts sorted in isc order. */
+ list_for_each_entry(iter, &fi->list, list) {
+ if (!is_ioint(iter->type))
+ continue;
+ if (int_word_to_isc_bits(iter->io.io_int_word)
+ <= isc_bits)
+ continue;
+ break;
+ }
+ list_add_tail(&inti->list, &iter->list);
+ }
atomic_set(&fi->active, 1);
sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
if (sigcpu == KVM_MAX_VCPUS) {
@@ -651,8 +904,15 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
inti->type = s390int->type;
inti->emerg.code = s390int->parm;
break;
+ case KVM_S390_MCHK:
+ VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx",
+ s390int->parm64);
+ inti->type = s390int->type;
+ inti->mchk.mcic = s390int->parm64;
+ break;
case KVM_S390_INT_VIRTIO:
case KVM_S390_INT_SERVICE:
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
default:
kfree(inti);
return -EINVAL;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index f090e819bf71..4cf35a0a79e7 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -140,6 +140,8 @@ int kvm_dev_ioctl_check_extension(long ext)
#endif
case KVM_CAP_SYNC_REGS:
case KVM_CAP_ONE_REG:
+ case KVM_CAP_ENABLE_CAP:
+ case KVM_CAP_S390_CSS_SUPPORT:
r = 1;
break;
case KVM_CAP_NR_VCPUS:
@@ -147,7 +149,7 @@ int kvm_dev_ioctl_check_extension(long ext)
r = KVM_MAX_VCPUS;
break;
case KVM_CAP_S390_COW:
- r = sclp_get_fac85() & 0x2;
+ r = MACHINE_HAS_ESOP;
break;
default:
r = 0;
@@ -234,6 +236,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
if (!kvm->arch.gmap)
goto out_nogmap;
}
+
+ kvm->arch.css_support = 0;
+
return 0;
out_nogmap:
debug_unregister(kvm->arch.dbf);
@@ -659,6 +664,7 @@ rerun_vcpu:
case KVM_EXIT_INTR:
case KVM_EXIT_S390_RESET:
case KVM_EXIT_S390_UCONTROL:
+ case KVM_EXIT_S390_TSCH:
break;
default:
BUG();
@@ -766,6 +772,14 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
} else
prefix = 0;
+ /*
+ * The guest FPRS and ACRS are in the host FPRS/ACRS due to the lazy
+ * copying in vcpu load/put. Lets update our copies before we save
+ * it into the save area
+ */
+ save_fp_regs(&vcpu->arch.guest_fpregs);
+ save_access_regs(vcpu->run->s.regs.acrs);
+
if (__guestcopy(vcpu, addr + offsetof(struct save_area, fp_regs),
vcpu->arch.guest_fpregs.fprs, 128, prefix))
return -EFAULT;
@@ -810,6 +824,29 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
return 0;
}
+static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
+ struct kvm_enable_cap *cap)
+{
+ int r;
+
+ if (cap->flags)
+ return -EINVAL;
+
+ switch (cap->cap) {
+ case KVM_CAP_S390_CSS_SUPPORT:
+ if (!vcpu->kvm->arch.css_support) {
+ vcpu->kvm->arch.css_support = 1;
+ trace_kvm_s390_enable_css(vcpu->kvm);
+ }
+ r = 0;
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+ return r;
+}
+
long kvm_arch_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -896,6 +933,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = 0;
break;
}
+ case KVM_ENABLE_CAP:
+ {
+ struct kvm_enable_cap cap;
+ r = -EFAULT;
+ if (copy_from_user(&cap, argp, sizeof(cap)))
+ break;
+ r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
+ break;
+ }
default:
r = -ENOTTY;
}
@@ -930,7 +976,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
struct kvm_memory_slot old,
struct kvm_userspace_memory_region *mem,
- int user_alloc)
+ bool user_alloc)
{
/* A few sanity checks. We can have exactly one memory slot which has
to start at guest virtual zero and which has to be located at a
@@ -960,7 +1006,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
void kvm_arch_commit_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
struct kvm_memory_slot old,
- int user_alloc)
+ bool user_alloc)
{
int rc;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index d75bc5e92c5b..4d89d64a8161 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -65,21 +65,67 @@ static inline void kvm_s390_set_prefix(struct kvm_vcpu *vcpu, u32 prefix)
vcpu->arch.sie_block->ihcpu = 0xffff;
}
+static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu)
+{
+ u32 base2 = vcpu->arch.sie_block->ipb >> 28;
+ u32 disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
+
+ return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
+}
+
+static inline void kvm_s390_get_base_disp_sse(struct kvm_vcpu *vcpu,
+ u64 *address1, u64 *address2)
+{
+ u32 base1 = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28;
+ u32 disp1 = (vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16;
+ u32 base2 = (vcpu->arch.sie_block->ipb & 0xf000) >> 12;
+ u32 disp2 = vcpu->arch.sie_block->ipb & 0x0fff;
+
+ *address1 = (base1 ? vcpu->run->s.regs.gprs[base1] : 0) + disp1;
+ *address2 = (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
+}
+
+static inline u64 kvm_s390_get_base_disp_rsy(struct kvm_vcpu *vcpu)
+{
+ u32 base2 = vcpu->arch.sie_block->ipb >> 28;
+ u32 disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) +
+ ((vcpu->arch.sie_block->ipb & 0xff00) << 4);
+ /* The displacement is a 20bit _SIGNED_ value */
+ if (disp2 & 0x80000)
+ disp2+=0xfff00000;
+
+ return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + (long)(int)disp2;
+}
+
+static inline u64 kvm_s390_get_base_disp_rs(struct kvm_vcpu *vcpu)
+{
+ u32 base2 = vcpu->arch.sie_block->ipb >> 28;
+ u32 disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
+
+ return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
+}
+
int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
void kvm_s390_tasklet(unsigned long parm);
void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu);
+void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu);
int kvm_s390_inject_vm(struct kvm *kvm,
struct kvm_s390_interrupt *s390int);
int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
struct kvm_s390_interrupt *s390int);
int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action);
+struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
+ u64 cr6, u64 schid);
/* implemented in priv.c */
int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
int kvm_s390_handle_e5(struct kvm_vcpu *vcpu);
int kvm_s390_handle_01(struct kvm_vcpu *vcpu);
+int kvm_s390_handle_b9(struct kvm_vcpu *vcpu);
+int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu);
+int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu);
/* implemented in sigp.c */
int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index d768906f15c8..0ef9894606e5 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -18,23 +18,21 @@
#include <asm/debug.h>
#include <asm/ebcdic.h>
#include <asm/sysinfo.h>
+#include <asm/ptrace.h>
+#include <asm/compat.h>
#include "gaccess.h"
#include "kvm-s390.h"
#include "trace.h"
static int handle_set_prefix(struct kvm_vcpu *vcpu)
{
- int base2 = vcpu->arch.sie_block->ipb >> 28;
- int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
u64 operand2;
u32 address = 0;
u8 tmp;
vcpu->stat.instruction_spx++;
- operand2 = disp2;
- if (base2)
- operand2 += vcpu->run->s.regs.gprs[base2];
+ operand2 = kvm_s390_get_base_disp_s(vcpu);
/* must be word boundary */
if (operand2 & 3) {
@@ -67,15 +65,12 @@ out:
static int handle_store_prefix(struct kvm_vcpu *vcpu)
{
- int base2 = vcpu->arch.sie_block->ipb >> 28;
- int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
u64 operand2;
u32 address;
vcpu->stat.instruction_stpx++;
- operand2 = disp2;
- if (base2)
- operand2 += vcpu->run->s.regs.gprs[base2];
+
+ operand2 = kvm_s390_get_base_disp_s(vcpu);
/* must be word boundary */
if (operand2 & 3) {
@@ -100,15 +95,12 @@ out:
static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
{
- int base2 = vcpu->arch.sie_block->ipb >> 28;
- int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
u64 useraddr;
int rc;
vcpu->stat.instruction_stap++;
- useraddr = disp2;
- if (base2)
- useraddr += vcpu->run->s.regs.gprs[base2];
+
+ useraddr = kvm_s390_get_base_disp_s(vcpu);
if (useraddr & 1) {
kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -135,24 +127,96 @@ static int handle_skey(struct kvm_vcpu *vcpu)
return 0;
}
-static int handle_stsch(struct kvm_vcpu *vcpu)
+static int handle_tpi(struct kvm_vcpu *vcpu)
{
- vcpu->stat.instruction_stsch++;
- VCPU_EVENT(vcpu, 4, "%s", "store subchannel - CC3");
- /* condition code 3 */
+ u64 addr;
+ struct kvm_s390_interrupt_info *inti;
+ int cc;
+
+ addr = kvm_s390_get_base_disp_s(vcpu);
+
+ inti = kvm_s390_get_io_int(vcpu->kvm, vcpu->run->s.regs.crs[6], 0);
+ if (inti) {
+ if (addr) {
+ /*
+ * Store the two-word I/O interruption code into the
+ * provided area.
+ */
+ put_guest_u16(vcpu, addr, inti->io.subchannel_id);
+ put_guest_u16(vcpu, addr + 2, inti->io.subchannel_nr);
+ put_guest_u32(vcpu, addr + 4, inti->io.io_int_parm);
+ } else {
+ /*
+ * Store the three-word I/O interruption code into
+ * the appropriate lowcore area.
+ */
+ put_guest_u16(vcpu, 184, inti->io.subchannel_id);
+ put_guest_u16(vcpu, 186, inti->io.subchannel_nr);
+ put_guest_u32(vcpu, 188, inti->io.io_int_parm);
+ put_guest_u32(vcpu, 192, inti->io.io_int_word);
+ }
+ cc = 1;
+ } else
+ cc = 0;
+ kfree(inti);
+ /* Set condition code and we're done. */
vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
- vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
+ vcpu->arch.sie_block->gpsw.mask |= (cc & 3ul) << 44;
return 0;
}
-static int handle_chsc(struct kvm_vcpu *vcpu)
+static int handle_tsch(struct kvm_vcpu *vcpu)
{
- vcpu->stat.instruction_chsc++;
- VCPU_EVENT(vcpu, 4, "%s", "channel subsystem call - CC3");
- /* condition code 3 */
- vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
- vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
- return 0;
+ struct kvm_s390_interrupt_info *inti;
+
+ inti = kvm_s390_get_io_int(vcpu->kvm, 0,
+ vcpu->run->s.regs.gprs[1]);
+
+ /*
+ * Prepare exit to userspace.
+ * We indicate whether we dequeued a pending I/O interrupt
+ * so that userspace can re-inject it if the instruction gets
+ * a program check. While this may re-order the pending I/O
+ * interrupts, this is no problem since the priority is kept
+ * intact.
+ */
+ vcpu->run->exit_reason = KVM_EXIT_S390_TSCH;
+ vcpu->run->s390_tsch.dequeued = !!inti;
+ if (inti) {
+ vcpu->run->s390_tsch.subchannel_id = inti->io.subchannel_id;
+ vcpu->run->s390_tsch.subchannel_nr = inti->io.subchannel_nr;
+ vcpu->run->s390_tsch.io_int_parm = inti->io.io_int_parm;
+ vcpu->run->s390_tsch.io_int_word = inti->io.io_int_word;
+ }
+ vcpu->run->s390_tsch.ipb = vcpu->arch.sie_block->ipb;
+ kfree(inti);
+ return -EREMOTE;
+}
+
+static int handle_io_inst(struct kvm_vcpu *vcpu)
+{
+ VCPU_EVENT(vcpu, 4, "%s", "I/O instruction");
+
+ if (vcpu->kvm->arch.css_support) {
+ /*
+ * Most I/O instructions will be handled by userspace.
+ * Exceptions are tpi and the interrupt portion of tsch.
+ */
+ if (vcpu->arch.sie_block->ipa == 0xb236)
+ return handle_tpi(vcpu);
+ if (vcpu->arch.sie_block->ipa == 0xb235)
+ return handle_tsch(vcpu);
+ /* Handle in userspace. */
+ return -EOPNOTSUPP;
+ } else {
+ /*
+ * Set condition code 3 to stop the guest from issueing channel
+ * I/O instructions.
+ */
+ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
+ vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
+ return 0;
+ }
}
static int handle_stfl(struct kvm_vcpu *vcpu)
@@ -176,17 +240,107 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
return 0;
}
+static void handle_new_psw(struct kvm_vcpu *vcpu)
+{
+ /* Check whether the new psw is enabled for machine checks. */
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_MCHECK)
+ kvm_s390_deliver_pending_machine_checks(vcpu);
+}
+
+#define PSW_MASK_ADDR_MODE (PSW_MASK_EA | PSW_MASK_BA)
+#define PSW_MASK_UNASSIGNED 0xb80800fe7fffffffUL
+#define PSW_ADDR_24 0x00000000000fffffUL
+#define PSW_ADDR_31 0x000000007fffffffUL
+
+int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu)
+{
+ u64 addr;
+ psw_compat_t new_psw;
+
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu,
+ PGM_PRIVILEGED_OPERATION);
+
+ addr = kvm_s390_get_base_disp_s(vcpu);
+
+ if (addr & 7) {
+ kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ goto out;
+ }
+
+ if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) {
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ goto out;
+ }
+
+ if (!(new_psw.mask & PSW32_MASK_BASE)) {
+ kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ goto out;
+ }
+
+ vcpu->arch.sie_block->gpsw.mask =
+ (new_psw.mask & ~PSW32_MASK_BASE) << 32;
+ vcpu->arch.sie_block->gpsw.addr = new_psw.addr;
+
+ if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_UNASSIGNED) ||
+ (!(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) &&
+ (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_24)) ||
+ ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) ==
+ PSW_MASK_EA)) {
+ kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ goto out;
+ }
+
+ handle_new_psw(vcpu);
+out:
+ return 0;
+}
+
+static int handle_lpswe(struct kvm_vcpu *vcpu)
+{
+ u64 addr;
+ psw_t new_psw;
+
+ addr = kvm_s390_get_base_disp_s(vcpu);
+
+ if (addr & 7) {
+ kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ goto out;
+ }
+
+ if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) {
+ kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ goto out;
+ }
+
+ vcpu->arch.sie_block->gpsw.mask = new_psw.mask;
+ vcpu->arch.sie_block->gpsw.addr = new_psw.addr;
+
+ if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_UNASSIGNED) ||
+ (((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) ==
+ PSW_MASK_BA) &&
+ (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_31)) ||
+ (!(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) &&
+ (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_24)) ||
+ ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) ==
+ PSW_MASK_EA)) {
+ kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ goto out;
+ }
+
+ handle_new_psw(vcpu);
+out:
+ return 0;
+}
+
static int handle_stidp(struct kvm_vcpu *vcpu)
{
- int base2 = vcpu->arch.sie_block->ipb >> 28;
- int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
u64 operand2;
int rc;
vcpu->stat.instruction_stidp++;
- operand2 = disp2;
- if (base2)
- operand2 += vcpu->run->s.regs.gprs[base2];
+
+ operand2 = kvm_s390_get_base_disp_s(vcpu);
if (operand2 & 7) {
kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -240,17 +394,13 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
int fc = (vcpu->run->s.regs.gprs[0] & 0xf0000000) >> 28;
int sel1 = vcpu->run->s.regs.gprs[0] & 0xff;
int sel2 = vcpu->run->s.regs.gprs[1] & 0xffff;
- int base2 = vcpu->arch.sie_block->ipb >> 28;
- int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
u64 operand2;
unsigned long mem;
vcpu->stat.instruction_stsi++;
VCPU_EVENT(vcpu, 4, "stsi: fc: %x sel1: %x sel2: %x", fc, sel1, sel2);
- operand2 = disp2;
- if (base2)
- operand2 += vcpu->run->s.regs.gprs[base2];
+ operand2 = kvm_s390_get_base_disp_s(vcpu);
if (operand2 & 0xfff && fc > 0)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -297,7 +447,7 @@ out_fail:
return 0;
}
-static intercept_handler_t priv_handlers[256] = {
+static const intercept_handler_t b2_handlers[256] = {
[0x02] = handle_stidp,
[0x10] = handle_set_prefix,
[0x11] = handle_store_prefix,
@@ -305,10 +455,25 @@ static intercept_handler_t priv_handlers[256] = {
[0x29] = handle_skey,
[0x2a] = handle_skey,
[0x2b] = handle_skey,
- [0x34] = handle_stsch,
- [0x5f] = handle_chsc,
+ [0x30] = handle_io_inst,
+ [0x31] = handle_io_inst,
+ [0x32] = handle_io_inst,
+ [0x33] = handle_io_inst,
+ [0x34] = handle_io_inst,
+ [0x35] = handle_io_inst,
+ [0x36] = handle_io_inst,
+ [0x37] = handle_io_inst,
+ [0x38] = handle_io_inst,
+ [0x39] = handle_io_inst,
+ [0x3a] = handle_io_inst,
+ [0x3b] = handle_io_inst,
+ [0x3c] = handle_io_inst,
+ [0x5f] = handle_io_inst,
+ [0x74] = handle_io_inst,
+ [0x76] = handle_io_inst,
[0x7d] = handle_stsi,
[0xb1] = handle_stfl,
+ [0xb2] = handle_lpswe,
};
int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
@@ -322,7 +487,7 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
* state bit and (a) handle the instruction or (b) send a code 2
* program check.
* Anything else goes to userspace.*/
- handler = priv_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
+ handler = b2_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
if (handler) {
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu,
@@ -333,19 +498,74 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
return -EOPNOTSUPP;
}
+static int handle_epsw(struct kvm_vcpu *vcpu)
+{
+ int reg1, reg2;
+
+ reg1 = (vcpu->arch.sie_block->ipb & 0x00f00000) >> 24;
+ reg2 = (vcpu->arch.sie_block->ipb & 0x000f0000) >> 16;
+
+ /* This basically extracts the mask half of the psw. */
+ vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000;
+ vcpu->run->s.regs.gprs[reg1] |= vcpu->arch.sie_block->gpsw.mask >> 32;
+ if (reg2) {
+ vcpu->run->s.regs.gprs[reg2] &= 0xffffffff00000000;
+ vcpu->run->s.regs.gprs[reg2] |=
+ vcpu->arch.sie_block->gpsw.mask & 0x00000000ffffffff;
+ }
+ return 0;
+}
+
+static const intercept_handler_t b9_handlers[256] = {
+ [0x8d] = handle_epsw,
+ [0x9c] = handle_io_inst,
+};
+
+int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
+{
+ intercept_handler_t handler;
+
+ /* This is handled just as for the B2 instructions. */
+ handler = b9_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
+ if (handler) {
+ if ((handler != handle_epsw) &&
+ (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE))
+ return kvm_s390_inject_program_int(vcpu,
+ PGM_PRIVILEGED_OPERATION);
+ else
+ return handler(vcpu);
+ }
+ return -EOPNOTSUPP;
+}
+
+static const intercept_handler_t eb_handlers[256] = {
+ [0x8a] = handle_io_inst,
+};
+
+int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu)
+{
+ intercept_handler_t handler;
+
+ /* All eb instructions that end up here are privileged. */
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu,
+ PGM_PRIVILEGED_OPERATION);
+ handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff];
+ if (handler)
+ return handler(vcpu);
+ return -EOPNOTSUPP;
+}
+
static int handle_tprot(struct kvm_vcpu *vcpu)
{
- int base1 = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28;
- int disp1 = (vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16;
- int base2 = (vcpu->arch.sie_block->ipb & 0xf000) >> 12;
- int disp2 = vcpu->arch.sie_block->ipb & 0x0fff;
- u64 address1 = disp1 + base1 ? vcpu->run->s.regs.gprs[base1] : 0;
- u64 address2 = disp2 + base2 ? vcpu->run->s.regs.gprs[base2] : 0;
+ u64 address1, address2;
struct vm_area_struct *vma;
unsigned long user_address;
vcpu->stat.instruction_tprot++;
+ kvm_s390_get_base_disp_sse(vcpu, &address1, &address2);
+
/* we only handle the Linux memory detection case:
* access key == 0
* guest DAT == off
@@ -405,7 +625,7 @@ static int handle_sckpf(struct kvm_vcpu *vcpu)
return 0;
}
-static intercept_handler_t x01_handlers[256] = {
+static const intercept_handler_t x01_handlers[256] = {
[0x07] = handle_sckpf,
};
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 566ddf6e8dfb..1c48ab2845e0 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -137,8 +137,10 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
inti->type = KVM_S390_SIGP_STOP;
spin_lock_bh(&li->lock);
- if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED))
+ if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
+ kfree(inti);
goto out;
+ }
list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1);
atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
@@ -324,8 +326,6 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
{
int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
int r3 = vcpu->arch.sie_block->ipa & 0x000f;
- int base2 = vcpu->arch.sie_block->ipb >> 28;
- int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
u32 parameter;
u16 cpu_addr = vcpu->run->s.regs.gprs[r3];
u8 order_code;
@@ -336,9 +336,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
return kvm_s390_inject_program_int(vcpu,
PGM_PRIVILEGED_OPERATION);
- order_code = disp2;
- if (base2)
- order_code += vcpu->run->s.regs.gprs[base2];
+ order_code = kvm_s390_get_base_disp_rs(vcpu);
if (r1 % 2)
parameter = vcpu->run->s.regs.gprs[r1];
diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h
index 90fdf85b5ff7..13f30f58a2df 100644
--- a/arch/s390/kvm/trace-s390.h
+++ b/arch/s390/kvm/trace-s390.h
@@ -141,13 +141,13 @@ TRACE_EVENT(kvm_s390_inject_vcpu,
* Trace point for the actual delivery of interrupts.
*/
TRACE_EVENT(kvm_s390_deliver_interrupt,
- TP_PROTO(unsigned int id, __u64 type, __u32 data0, __u64 data1),
+ TP_PROTO(unsigned int id, __u64 type, __u64 data0, __u64 data1),
TP_ARGS(id, type, data0, data1),
TP_STRUCT__entry(
__field(int, id)
__field(__u32, inttype)
- __field(__u32, data0)
+ __field(__u64, data0)
__field(__u64, data1)
),
@@ -159,7 +159,7 @@ TRACE_EVENT(kvm_s390_deliver_interrupt,
),
TP_printk("deliver interrupt (vcpu %d): type:%x (%s) " \
- "data:%08x %016llx",
+ "data:%08llx %016llx",
__entry->id, __entry->inttype,
__print_symbolic(__entry->inttype, kvm_s390_int_type),
__entry->data0, __entry->data1)
@@ -204,6 +204,26 @@ TRACE_EVENT(kvm_s390_stop_request,
);
+/*
+ * Trace point for enabling channel I/O instruction support.
+ */
+TRACE_EVENT(kvm_s390_enable_css,
+ TP_PROTO(void *kvm),
+ TP_ARGS(kvm),
+
+ TP_STRUCT__entry(
+ __field(void *, kvm)
+ ),
+
+ TP_fast_assign(
+ __entry->kvm = kvm;
+ ),
+
+ TP_printk("enabling channel I/O support (kvm @ %p)\n",
+ __entry->kvm)
+ );
+
+
#endif /* _TRACE_KVMS390_H */
/* This part must be outside protection */
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index 42d0cf89121d..c61b9fad43cc 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -32,7 +32,7 @@ static void __udelay_disabled(unsigned long long usecs)
unsigned long cr0, cr6, new;
u64 clock_saved, end;
- end = get_clock() + (usecs << 12);
+ end = get_tod_clock() + (usecs << 12);
clock_saved = local_tick_disable();
__ctl_store(cr0, 0, 0);
__ctl_store(cr6, 6, 6);
@@ -45,7 +45,7 @@ static void __udelay_disabled(unsigned long long usecs)
set_clock_comparator(end);
vtime_stop_cpu();
local_irq_disable();
- } while (get_clock() < end);
+ } while (get_tod_clock() < end);
lockdep_on();
__ctl_load(cr0, 0, 0);
__ctl_load(cr6, 6, 6);
@@ -56,7 +56,7 @@ static void __udelay_enabled(unsigned long long usecs)
{
u64 clock_saved, end;
- end = get_clock() + (usecs << 12);
+ end = get_tod_clock() + (usecs << 12);
do {
clock_saved = 0;
if (end < S390_lowcore.clock_comparator) {
@@ -67,7 +67,7 @@ static void __udelay_enabled(unsigned long long usecs)
local_irq_disable();
if (clock_saved)
local_tick_enable(clock_saved);
- } while (get_clock() < end);
+ } while (get_tod_clock() < end);
}
/*
@@ -111,8 +111,8 @@ void udelay_simple(unsigned long long usecs)
{
u64 end;
- end = get_clock() + (usecs << 12);
- while (get_clock() < end)
+ end = get_tod_clock() + (usecs << 12);
+ while (get_tod_clock() < end)
cpu_relax();
}
@@ -122,10 +122,10 @@ void __ndelay(unsigned long long nsecs)
nsecs <<= 9;
do_div(nsecs, 125);
- end = get_clock() + nsecs;
+ end = get_tod_clock() + nsecs;
if (nsecs & ~0xfffUL)
__udelay(nsecs >> 12);
- while (get_clock() < end)
+ while (get_tod_clock() < end)
barrier();
}
EXPORT_SYMBOL(__ndelay);
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 9017a63dda3d..a70ee84c0241 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -50,7 +50,7 @@ static __always_inline unsigned long follow_table(struct mm_struct *mm,
ptep = pte_offset_map(pmd, addr);
if (!pte_present(*ptep))
return -0x11UL;
- if (write && !pte_write(*ptep))
+ if (write && (!pte_write(*ptep) || !pte_dirty(*ptep)))
return -0x04UL;
return (pte_val(*ptep) & PAGE_MASK) + (addr & ~PAGE_MASK);
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index ae672f41c464..49ce6bb2c641 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -228,4 +228,16 @@ int arch_add_memory(int nid, u64 start, u64 size)
vmem_remove_mapping(start, size);
return rc;
}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+ /*
+ * There is no hardware or firmware interface which could trigger a
+ * hot memory remove on s390. So there is nothing that needs to be
+ * implemented.
+ */
+ return -EBUSY;
+}
+#endif
#endif /* CONFIG_MEMORY_HOTPLUG */
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
index c59a5efa58b1..06bafec00278 100644
--- a/arch/s390/mm/mmap.c
+++ b/arch/s390/mm/mmap.c
@@ -101,12 +101,15 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
#else
-int s390_mmap_check(unsigned long addr, unsigned long len)
+int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags)
{
int rc;
- if (!is_compat_task() &&
- len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) {
+ if (is_compat_task() || (TASK_SIZE >= (1UL << 53)))
+ return 0;
+ if (!(flags & MAP_FIXED))
+ addr = 0;
+ if ((addr + len) >= TASK_SIZE) {
rc = crst_table_upgrade(current->mm, 1UL << 53);
if (rc)
return rc;
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c
index 29ccee3651f4..d21040ed5e59 100644
--- a/arch/s390/mm/pageattr.c
+++ b/arch/s390/mm/pageattr.c
@@ -127,7 +127,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
pte_val(*pte) = _PAGE_TYPE_EMPTY;
continue;
}
- *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW));
+ pte_val(*pte) = __pa(address);
}
}
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 6ed1426d27c5..e21aaf4f5cb6 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -85,11 +85,9 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
pud_t *pu_dir;
pmd_t *pm_dir;
pte_t *pt_dir;
- pte_t pte;
int ret = -ENOMEM;
while (address < end) {
- pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
pg_dir = pgd_offset_k(address);
if (pgd_none(*pg_dir)) {
pu_dir = vmem_pud_alloc();
@@ -101,9 +99,9 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
#if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC)
if (MACHINE_HAS_EDAT2 && pud_none(*pu_dir) && address &&
!(address & ~PUD_MASK) && (address + PUD_SIZE <= end)) {
- pte_val(pte) |= _REGION3_ENTRY_LARGE;
- pte_val(pte) |= _REGION_ENTRY_TYPE_R3;
- pud_val(*pu_dir) = pte_val(pte);
+ pud_val(*pu_dir) = __pa(address) |
+ _REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE |
+ (ro ? _REGION_ENTRY_RO : 0);
address += PUD_SIZE;
continue;
}
@@ -118,8 +116,9 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
#if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC)
if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address &&
!(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) {
- pte_val(pte) |= _SEGMENT_ENTRY_LARGE;
- pmd_val(*pm_dir) = pte_val(pte);
+ pmd_val(*pm_dir) = __pa(address) |
+ _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE |
+ (ro ? _SEGMENT_ENTRY_RO : 0);
address += PMD_SIZE;
continue;
}
@@ -132,7 +131,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
}
pt_dir = pte_offset_kernel(pm_dir, address);
- *pt_dir = pte;
+ pte_val(*pt_dir) = __pa(address) | (ro ? _PAGE_RO : 0);
address += PAGE_SIZE;
}
ret = 0;
@@ -199,7 +198,6 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
pud_t *pu_dir;
pmd_t *pm_dir;
pte_t *pt_dir;
- pte_t pte;
int ret = -ENOMEM;
start_addr = (unsigned long) start;
@@ -237,9 +235,8 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
new_page = vmemmap_alloc_block(PMD_SIZE, node);
if (!new_page)
goto out;
- pte = mk_pte_phys(__pa(new_page), PAGE_RW);
- pte_val(pte) |= _SEGMENT_ENTRY_LARGE;
- pmd_val(*pm_dir) = pte_val(pte);
+ pmd_val(*pm_dir) = __pa(new_page) |
+ _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE;
address = (address + PMD_SIZE) & PMD_MASK;
continue;
}
@@ -260,8 +257,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
new_page =__pa(vmem_alloc_pages(0));
if (!new_page)
goto out;
- pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
- *pt_dir = pte;
+ pte_val(*pt_dir) = __pa(new_page);
}
address += PAGE_SIZE;
}
@@ -272,6 +268,10 @@ out:
return ret;
}
+void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+{
+}
+
/*
* Add memory segment to the segment list if it doesn't overlap with
* an already present segment.
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index bb284419b0fd..0972e91cced2 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -7,6 +7,7 @@
*/
#include <linux/moduleloader.h>
#include <linux/netdevice.h>
+#include <linux/if_vlan.h>
#include <linux/filter.h>
#include <asm/cacheflush.h>
#include <asm/processor.h>
@@ -254,6 +255,8 @@ static void bpf_jit_noleaks(struct bpf_jit *jit, struct sock_filter *filter)
case BPF_S_ANC_HATYPE:
case BPF_S_ANC_RXHASH:
case BPF_S_ANC_CPU:
+ case BPF_S_ANC_VLAN_TAG:
+ case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_S_RET_K:
/* first instruction sets A register */
break;
@@ -699,6 +702,24 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
/* l %r5,<d(rxhash)>(%r2) */
EMIT4_DISP(0x58502000, offsetof(struct sk_buff, rxhash));
break;
+ case BPF_S_ANC_VLAN_TAG:
+ case BPF_S_ANC_VLAN_TAG_PRESENT:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2);
+ BUILD_BUG_ON(VLAN_TAG_PRESENT != 0x1000);
+ /* lhi %r5,0 */
+ EMIT4(0xa7580000);
+ /* icm %r5,3,<d(vlan_tci)>(%r2) */
+ EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, vlan_tci));
+ if (filter->code == BPF_S_ANC_VLAN_TAG) {
+ /* nill %r5,0xefff */
+ EMIT4_IMM(0xa5570000, ~VLAN_TAG_PRESENT);
+ } else {
+ /* nill %r5,0x1000 */
+ EMIT4_IMM(0xa5570000, VLAN_TAG_PRESENT);
+ /* srl %r5,12 */
+ EMIT4_DISP(0x88500000, 12);
+ }
+ break;
case BPF_S_ANC_CPU: /* A = smp_processor_id() */
#ifdef CONFIG_SMP
/* l %r5,<d(cpu_nr)> */
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 60e0372545d2..27b4c17855b9 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -51,8 +51,7 @@ EXPORT_SYMBOL_GPL(zpci_list);
DEFINE_MUTEX(zpci_list_lock);
EXPORT_SYMBOL_GPL(zpci_list_lock);
-struct pci_hp_callback_ops hotplug_ops;
-EXPORT_SYMBOL_GPL(hotplug_ops);
+static struct pci_hp_callback_ops *hotplug_ops;
static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);
static DEFINE_SPINLOCK(zpci_domain_lock);
@@ -974,8 +973,8 @@ int zpci_create_device(struct zpci_dev *zdev)
mutex_lock(&zpci_list_lock);
list_add_tail(&zdev->entry, &zpci_list);
- if (hotplug_ops.create_slot)
- hotplug_ops.create_slot(zdev);
+ if (hotplug_ops)
+ hotplug_ops->create_slot(zdev);
mutex_unlock(&zpci_list_lock);
if (zdev->state == ZPCI_FN_STATE_STANDBY)
@@ -989,8 +988,8 @@ int zpci_create_device(struct zpci_dev *zdev)
out_start:
mutex_lock(&zpci_list_lock);
list_del(&zdev->entry);
- if (hotplug_ops.remove_slot)
- hotplug_ops.remove_slot(zdev);
+ if (hotplug_ops)
+ hotplug_ops->remove_slot(zdev);
mutex_unlock(&zpci_list_lock);
out_bus:
zpci_free_domain(zdev);
@@ -1072,13 +1071,29 @@ static void zpci_mem_exit(void)
kmem_cache_destroy(zdev_fmb_cache);
}
-unsigned int pci_probe = 1;
-EXPORT_SYMBOL_GPL(pci_probe);
+void zpci_register_hp_ops(struct pci_hp_callback_ops *ops)
+{
+ mutex_lock(&zpci_list_lock);
+ hotplug_ops = ops;
+ mutex_unlock(&zpci_list_lock);
+}
+EXPORT_SYMBOL_GPL(zpci_register_hp_ops);
+
+void zpci_deregister_hp_ops(void)
+{
+ mutex_lock(&zpci_list_lock);
+ hotplug_ops = NULL;
+ mutex_unlock(&zpci_list_lock);
+}
+EXPORT_SYMBOL_GPL(zpci_deregister_hp_ops);
+
+unsigned int s390_pci_probe = 1;
+EXPORT_SYMBOL_GPL(s390_pci_probe);
char * __init pcibios_setup(char *str)
{
if (!strcmp(str, "off")) {
- pci_probe = 0;
+ s390_pci_probe = 0;
return NULL;
}
return str;
@@ -1088,7 +1103,7 @@ static int __init pci_base_init(void)
{
int rc;
- if (!pci_probe)
+ if (!s390_pci_probe)
return 0;
if (!test_facility(2) || !test_facility(69)
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c
index 2c847143cbd1..f339fe2feb15 100644
--- a/arch/s390/pci/pci_clp.c
+++ b/arch/s390/pci/pci_clp.c
@@ -19,25 +19,25 @@
* Call Logical Processor
* Retry logic is handled by the caller.
*/
-static inline u8 clp_instr(void *req)
+static inline u8 clp_instr(void *data)
{
- u64 ilpm;
+ struct { u8 _[CLP_BLK_SIZE]; } *req = data;
+ u64 ignored;
u8 cc;
asm volatile (
- " .insn rrf,0xb9a00000,%[ilpm],%[req],0x0,0x2\n"
+ " .insn rrf,0xb9a00000,%[ign],%[req],0x0,0x2\n"
" ipm %[cc]\n"
" srl %[cc],28\n"
- : [cc] "=d" (cc), [ilpm] "=d" (ilpm)
+ : [cc] "=d" (cc), [ign] "=d" (ignored), "+m" (*req)
: [req] "a" (req)
- : "cc", "memory");
+ : "cc");
return cc;
}
static void *clp_alloc_block(void)
{
- struct page *page = alloc_pages(GFP_KERNEL, get_order(CLP_BLK_SIZE));
- return (page) ? page_address(page) : NULL;
+ return (void *) __get_free_pages(GFP_KERNEL, get_order(CLP_BLK_SIZE));
}
static void clp_free_block(void *ptr)
diff --git a/arch/score/include/asm/syscalls.h b/arch/score/include/asm/syscalls.h
index acaeed680956..98d1df92fbd1 100644
--- a/arch/score/include/asm/syscalls.h
+++ b/arch/score/include/asm/syscalls.h
@@ -1,7 +1,6 @@
#ifndef _ASM_SCORE_SYSCALLS_H
#define _ASM_SCORE_SYSCALLS_H
-asmlinkage long score_sigaltstack(struct pt_regs *regs);
asmlinkage long score_rt_sigreturn(struct pt_regs *regs);
#include <asm-generic/syscalls.h>
diff --git a/arch/score/kernel/entry.S b/arch/score/kernel/entry.S
index 1557ca1a2951..7234ed09b7b7 100644
--- a/arch/score/kernel/entry.S
+++ b/arch/score/kernel/entry.S
@@ -491,8 +491,3 @@ ENTRY(sys_rt_sigreturn)
mv r4, r0
la r8, score_rt_sigreturn
br r8
-
-ENTRY(sys_sigaltstack)
- mv r4, r0
- la r8, score_sigaltstack
- br r8
diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c
index 02353bde92d8..a00fba32b0eb 100644
--- a/arch/score/kernel/signal.c
+++ b/arch/score/kernel/signal.c
@@ -134,16 +134,6 @@ static void __user *get_sigframe(struct k_sigaction *ka,
}
asmlinkage long
-score_sigaltstack(struct pt_regs *regs)
-{
- const stack_t __user *uss = (const stack_t __user *) regs->regs[4];
- stack_t __user *uoss = (stack_t __user *) regs->regs[5];
- unsigned long usp = regs->regs[0];
-
- return do_sigaltstack(uss, uoss, usp);
-}
-
-asmlinkage long
score_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
@@ -167,9 +157,7 @@ score_rt_sigreturn(struct pt_regs *regs)
else if (sig)
force_sig(sig, current);
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- if (do_sigaltstack(&frame->rs_uc.uc_stack, NULL, regs->regs[0]) == -EFAULT)
+ if (restore_altstack(&frame->rs_uc.uc_stack))
goto badframe;
regs->is_syscall = 0;
@@ -209,12 +197,7 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
err |= copy_siginfo_to_user(&frame->rs_info, info);
err |= __put_user(0, &frame->rs_uc.uc_flags);
err |= __put_user(NULL, &frame->rs_uc.uc_link);
- err |= __put_user((void __user *)current->sas_ss_sp,
- &frame->rs_uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->regs[0]),
- &frame->rs_uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size,
- &frame->rs_uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->rs_uc.uc_stack, regs->regs[0]);
err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index babc2b826c5c..ef6717a64bc7 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -11,7 +11,6 @@ config SUPERH
select HAVE_ARCH_TRACEHOOK
select HAVE_DMA_API_DEBUG
select HAVE_DMA_ATTRS
- select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select HAVE_DEBUG_BUGVERBOSE
select ARCH_HAVE_CUSTOM_GPIO_H
@@ -40,6 +39,8 @@ config SUPERH
select GENERIC_STRNLEN_USER
select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER
select MODULES_USE_ELF_RELA
+ select OLD_SIGSUSPEND
+ select OLD_SIGACTION
help
The SuperH is a RISC processor targeted for use in embedded systems
and consumer electronics; it was also used in the Sega Dreamcast
@@ -91,9 +92,6 @@ config GENERIC_CSUM
config GENERIC_HWEIGHT
def_bool y
-config IRQ_PER_CPU
- def_bool y
-
config GENERIC_GPIO
def_bool n
@@ -276,6 +274,7 @@ config CPU_SUBTYPE_SH7203
select SYS_SUPPORTS_CMT
select SYS_SUPPORTS_MTU2
select ARCH_WANT_OPTIONAL_GPIOLIB
+ select PINCTRL
config CPU_SUBTYPE_SH7206
bool "Support SH7206 processor"
@@ -296,6 +295,7 @@ config CPU_SUBTYPE_SH7264
select CPU_HAS_FPU
select SYS_SUPPORTS_CMT
select SYS_SUPPORTS_MTU2
+ select PINCTRL
config CPU_SUBTYPE_SH7269
bool "Support SH7269 processor"
@@ -303,6 +303,7 @@ config CPU_SUBTYPE_SH7269
select CPU_HAS_FPU
select SYS_SUPPORTS_CMT
select SYS_SUPPORTS_MTU2
+ select PINCTRL
config CPU_SUBTYPE_MXG
bool "Support MX-G processor"
@@ -364,6 +365,7 @@ config CPU_SUBTYPE_SH7720
select ARCH_WANT_OPTIONAL_GPIOLIB
select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
+ select PINCTRL
help
Select SH7720 if you have a SH3-DSP SH7720 CPU.
@@ -429,6 +431,7 @@ config CPU_SUBTYPE_SH7723
select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
+ select PINCTRL
help
Select SH7723 if you have an SH-MobileR2 CPU.
@@ -440,6 +443,7 @@ config CPU_SUBTYPE_SH7724
select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
+ select PINCTRL
help
Select SH7724 if you have an SH-MobileR2R CPU.
@@ -450,6 +454,7 @@ config CPU_SUBTYPE_SH7734
select ARCH_WANT_OPTIONAL_GPIOLIB
select USB_ARCH_HAS_OHCI
select USB_ARCH_HAS_EHCI
+ select PINCTRL
help
Select SH7734 if you have a SH4A SH7734 CPU.
@@ -460,6 +465,7 @@ config CPU_SUBTYPE_SH7757
select ARCH_WANT_OPTIONAL_GPIOLIB
select USB_ARCH_HAS_OHCI
select USB_ARCH_HAS_EHCI
+ select PINCTRL
help
Select SH7757 if you have a SH4A SH7757 CPU.
@@ -486,6 +492,7 @@ config CPU_SUBTYPE_SH7785
select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_NUMA
select ARCH_WANT_OPTIONAL_GPIOLIB
+ select PINCTRL
config CPU_SUBTYPE_SH7786
bool "Support SH7786 processor"
@@ -498,6 +505,7 @@ config CPU_SUBTYPE_SH7786
select USB_OHCI_SH if USB_OHCI_HCD
select USB_ARCH_HAS_EHCI
select USB_EHCI_SH if USB_EHCI_HCD
+ select PINCTRL
config CPU_SUBTYPE_SHX3
bool "Support SH-X3 processor"
@@ -505,6 +513,7 @@ config CPU_SUBTYPE_SHX3
select CPU_SHX3
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select ARCH_REQUIRE_GPIOLIB
+ select PINCTRL
# SH4AL-DSP Processor Support
@@ -523,6 +532,7 @@ config CPU_SUBTYPE_SH7722
select SYS_SUPPORTS_NUMA
select SYS_SUPPORTS_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
+ select PINCTRL
config CPU_SUBTYPE_SH7366
bool "Support SH7366 processor"
@@ -648,7 +658,7 @@ source kernel/Kconfig.hz
config KEXEC
bool "kexec system call (EXPERIMENTAL)"
- depends on SUPERH32 && EXPERIMENTAL && MMU
+ depends on SUPERH32 && MMU
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
@@ -665,7 +675,7 @@ config KEXEC
config CRASH_DUMP
bool "kernel crash dumps (EXPERIMENTAL)"
- depends on SUPERH32 && EXPERIMENTAL && BROKEN_ON_SMP
+ depends on SUPERH32 && BROKEN_ON_SMP
help
Generate crash dump after being started by kexec.
This should be normally only set in special crash dump kernels
@@ -679,7 +689,7 @@ config CRASH_DUMP
config KEXEC_JUMP
bool "kexec jump (EXPERIMENTAL)"
- depends on SUPERH32 && KEXEC && HIBERNATION && EXPERIMENTAL
+ depends on SUPERH32 && KEXEC && HIBERNATION
help
Jump between original kernel and kexeced kernel and invoke
code via KEXEC
@@ -713,7 +723,7 @@ config SECCOMP
config CC_STACKPROTECTOR
bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
- depends on SUPERH32 && EXPERIMENTAL
+ depends on SUPERH32
help
This option turns on the -fstack-protector GCC feature. This
feature puts, at the beginning of functions, a canary value on
@@ -764,7 +774,7 @@ config NR_CPUS
config HOTPLUG_CPU
bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
- depends on SMP && HOTPLUG && EXPERIMENTAL
+ depends on SMP && HOTPLUG
help
Say Y here to experiment with turning CPUs off and on. CPUs
can be controlled through /sys/devices/system/cpu.
@@ -843,7 +853,7 @@ config ENTRY_OFFSET
config ROMIMAGE_MMCIF
bool "Include MMCIF loader in romImage (EXPERIMENTAL)"
- depends on CPU_SUBTYPE_SH7724 && EXPERIMENTAL
+ depends on CPU_SUBTYPE_SH7724
help
Say Y here to include experimental MMCIF loading code in
romImage. With this enabled it is possible to write the romImage
@@ -929,7 +939,6 @@ source "fs/Kconfig.binfmt"
endmenu
menu "Power management options (EXPERIMENTAL)"
-depends on EXPERIMENTAL
source "kernel/power/Kconfig"
diff --git a/arch/sh/Kconfig.cpu b/arch/sh/Kconfig.cpu
index 770ff2d5b94d..05b518e90cf7 100644
--- a/arch/sh/Kconfig.cpu
+++ b/arch/sh/Kconfig.cpu
@@ -33,7 +33,7 @@ config SH64_FPU_DENORM_FLUSH
config SH_FPU_EMU
def_bool n
prompt "FPU emulation support"
- depends on !SH_FPU && EXPERIMENTAL
+ depends on !SH_FPU
help
Selecting this option will enable support for software FPU emulation.
Most SH-3 users will want to say Y here, whereas most SH-4 users will
@@ -68,7 +68,6 @@ config SH_STORE_QUEUES
config SPECULATIVE_EXECUTION
bool "Speculative subroutine return"
- depends on EXPERIMENTAL
depends on CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785 || CPU_SUBTYPE_SH7786
help
This enables support for a speculative instruction fetch for
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index a0fa5791cd44..aaff7671101b 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -887,12 +887,6 @@ static struct platform_device camera_devices[] = {
};
/* FSI */
-static struct sh_fsi_platform_info fsi_info = {
- .port_b = {
- .flags = SH_FSI_BRS_INV,
- },
-};
-
static struct resource fsi_resources[] = {
[0] = {
.name = "FSI",
@@ -911,25 +905,22 @@ static struct platform_device fsi_device = {
.id = 0,
.num_resources = ARRAY_SIZE(fsi_resources),
.resource = fsi_resources,
- .dev = {
- .platform_data = &fsi_info,
- },
-};
-
-static struct asoc_simple_dai_init_info fsi_da7210_init_info = {
- .fmt = SND_SOC_DAIFMT_I2S,
- .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
- .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
};
static struct asoc_simple_card_info fsi_da7210_info = {
.name = "DA7210",
.card = "FSIB-DA7210",
- .cpu_dai = "fsib-dai",
.codec = "da7210.0-001a",
.platform = "sh_fsi.0",
- .codec_dai = "da7210-hifi",
- .init = &fsi_da7210_init_info,
+ .daifmt = SND_SOC_DAIFMT_I2S,
+ .cpu_dai = {
+ .name = "fsib-dai",
+ .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
+ },
+ .codec_dai = {
+ .name = "da7210-hifi",
+ .fmt = SND_SOC_DAIFMT_CBM_CFM,
+ },
};
static struct platform_device fsi_da7210_device = {
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 35f6efa3ac0e..4010e63e82d8 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -279,12 +279,6 @@ static struct platform_device ceu1_device = {
/* FSI */
/* change J20, J21, J22 pin to 1-2 connection to use slave mode */
-static struct sh_fsi_platform_info fsi_info = {
- .port_a = {
- .flags = SH_FSI_BRS_INV,
- },
-};
-
static struct resource fsi_resources[] = {
[0] = {
.name = "FSI",
@@ -303,26 +297,23 @@ static struct platform_device fsi_device = {
.id = 0,
.num_resources = ARRAY_SIZE(fsi_resources),
.resource = fsi_resources,
- .dev = {
- .platform_data = &fsi_info,
- },
-};
-
-static struct asoc_simple_dai_init_info fsi2_ak4642_init_info = {
- .fmt = SND_SOC_DAIFMT_LEFT_J,
- .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
- .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
- .sysclk = 11289600,
};
static struct asoc_simple_card_info fsi_ak4642_info = {
.name = "AK4642",
.card = "FSIA-AK4642",
- .cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi.0",
- .codec_dai = "ak4642-hifi",
- .init = &fsi2_ak4642_init_info,
+ .daifmt = SND_SOC_DAIFMT_LEFT_J,
+ .cpu_dai = {
+ .name = "fsia-dai",
+ .fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
+ },
+ .codec_dai = {
+ .name = "ak4642-hifi",
+ .fmt = SND_SOC_DAIFMT_CBM_CFM,
+ .sysclk = 11289600,
+ },
};
static struct platform_device fsi_ak4642_device = {
diff --git a/arch/sh/include/asm/gpio.h b/arch/sh/include/asm/gpio.h
index 04f53d31489f..7dfe15e2e990 100644
--- a/arch/sh/include/asm/gpio.h
+++ b/arch/sh/include/asm/gpio.h
@@ -20,7 +20,7 @@
#endif
#define ARCH_NR_GPIOS 512
-#include <linux/sh_pfc.h>
+#include <asm-generic/gpio.h>
#ifdef CONFIG_GPIOLIB
diff --git a/arch/sh/include/asm/syscalls_32.h b/arch/sh/include/asm/syscalls_32.h
index cc25485996bb..4f97df87d7d5 100644
--- a/arch/sh/include/asm/syscalls_32.h
+++ b/arch/sh/include/asm/syscalls_32.h
@@ -9,12 +9,6 @@
struct pt_regs;
-asmlinkage int sys_sigsuspend(old_sigset_t mask);
-asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user *act,
- struct old_sigaction __user *oact);
-asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs __regs);
diff --git a/arch/sh/include/asm/unistd.h b/arch/sh/include/asm/unistd.h
index 012004ed3330..5e90fa2b7eed 100644
--- a/arch/sh/include/asm/unistd.h
+++ b/arch/sh/include/asm/unistd.h
@@ -4,7 +4,6 @@
# include <asm/unistd_64.h>
# endif
-# define __ARCH_WANT_SYS_RT_SIGSUSPEND
# define __ARCH_WANT_OLD_READDIR
# define __ARCH_WANT_OLD_STAT
# define __ARCH_WANT_STAT64
@@ -27,7 +26,6 @@
# define __ARCH_WANT_SYS_OLDUMOUNT
# define __ARCH_WANT_SYS_SIGPENDING
# define __ARCH_WANT_SYS_SIGPROCMASK
-# define __ARCH_WANT_SYS_RT_SIGACTION
# define __ARCH_WANT_SYS_FORK
# define __ARCH_WANT_SYS_VFORK
# define __ARCH_WANT_SYS_CLONE
diff --git a/include/linux/clk/sunxi.h b/arch/sh/include/cpu-common/cpu/pfc.h
index e074fdd5a236..e538813286a8 100644
--- a/include/linux/clk/sunxi.h
+++ b/arch/sh/include/cpu-common/cpu/pfc.h
@@ -1,12 +1,11 @@
/*
- * Copyright 2012 Maxime Ripard
+ * SH Pin Function Control Initialization
*
- * Maxime Ripard <maxime.ripard@free-electrons.com>
+ * Copyright (C) 2012 Renesas Solutions 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.
+ * 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
@@ -14,9 +13,14 @@
* GNU General Public License for more details.
*/
-#ifndef __LINUX_CLK_SUNXI_H_
-#define __LINUX_CLK_SUNXI_H_
+#ifndef __ARCH_SH_CPU_PFC_H__
+#define __ARCH_SH_CPU_PFC_H__
-void __init sunxi_init_clocks(void);
+#include <linux/types.h>
-#endif
+struct resource;
+
+int sh_pfc_register(const char *name,
+ struct resource *resource, u32 num_resources);
+
+#endif /* __ARCH_SH_CPU_PFC_H__ */
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7723.h b/arch/sh/include/cpu-sh4/cpu/sh7723.h
index 6fae50cb1e94..668da89bdac4 100644
--- a/arch/sh/include/cpu-sh4/cpu/sh7723.h
+++ b/arch/sh/include/cpu-sh4/cpu/sh7723.h
@@ -184,7 +184,7 @@ enum {
/* SIUA */
GPIO_FN_SIUAFCK, GPIO_FN_SIUAILR, GPIO_FN_SIUAIBT, GPIO_FN_SIUAISLD,
GPIO_FN_SIUAOLR, GPIO_FN_SIUAOBT, GPIO_FN_SIUAOSLD, GPIO_FN_SIUAMCK,
- GPIO_FN_SIUAISPD, GPIO_FN_SIUOSPD,
+ GPIO_FN_SIUAISPD, GPIO_FN_SIUAOSPD,
/* SIUB */
GPIO_FN_SIUBFCK, GPIO_FN_SIUBILR, GPIO_FN_SIUBIBT, GPIO_FN_SIUBISLD,
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7786.h b/arch/sh/include/cpu-sh4/cpu/sh7786.h
index 977862f9072a..0df09e638f09 100644
--- a/arch/sh/include/cpu-sh4/cpu/sh7786.h
+++ b/arch/sh/include/cpu-sh4/cpu/sh7786.h
@@ -32,16 +32,14 @@ enum {
GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
/* PE */
- GPIO_PE5, GPIO_PE4, GPIO_PE3, GPIO_PE2,
- GPIO_PE1, GPIO_PE0,
+ GPIO_PE7, GPIO_PE6,
/* PF */
GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
/* PG */
- GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
- GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+ GPIO_PG7, GPIO_PG6, GPIO_PG5,
/* PH */
GPIO_PH7, GPIO_PH6, GPIO_PH5, GPIO_PH4,
@@ -49,7 +47,7 @@ enum {
/* PJ */
GPIO_PJ7, GPIO_PJ6, GPIO_PJ5, GPIO_PJ4,
- GPIO_PJ3, GPIO_PJ2, GPIO_PJ1, GPIO_PJ0,
+ GPIO_PJ3, GPIO_PJ2, GPIO_PJ1,
/* DU */
GPIO_FN_DCLKIN, GPIO_FN_DCLKOUT, GPIO_FN_ODDF,
diff --git a/arch/sh/include/uapi/asm/signal.h b/arch/sh/include/uapi/asm/signal.h
index 9ac530a90bce..cb96d02f55a4 100644
--- a/arch/sh/include/uapi/asm/signal.h
+++ b/arch/sh/include/uapi/asm/signal.h
@@ -5,11 +5,13 @@
#include <asm-generic/signal.h>
+#ifndef __KERNEL__
struct old_sigaction {
__sighandler_t sa_handler;
old_sigset_t sa_mask;
unsigned long sa_flags;
void (*sa_restorer)(void);
};
+#endif
#endif /* __ASM_SH_SIGNAL_H */
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index fa58bfd30d82..accc7ca722e1 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -18,4 +18,4 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG_LEGACY) += clock-cpg.o
-obj-y += irq/ init.o clock.o fpu.o proc.o
+obj-y += irq/ init.o clock.o fpu.o pfc.o proc.o
diff --git a/arch/sh/kernel/cpu/pfc.c b/arch/sh/kernel/cpu/pfc.c
new file mode 100644
index 000000000000..d766564ef7c2
--- /dev/null
+++ b/arch/sh/kernel/cpu/pfc.c
@@ -0,0 +1,33 @@
+/*
+ * SH Pin Function Control Initialization
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <cpu/pfc.h>
+
+static struct platform_device sh_pfc_device = {
+ .id = -1,
+};
+
+int __init sh_pfc_register(const char *name,
+ struct resource *resource, u32 num_resources)
+{
+ sh_pfc_device.name = name;
+ sh_pfc_device.num_resources = num_resources;
+ sh_pfc_device.resource = resource;
+
+ return platform_device_register(&sh_pfc_device);
+}
diff --git a/arch/sh/kernel/cpu/sh2a/pinmux-sh7203.c b/arch/sh/kernel/cpu/sh2a/pinmux-sh7203.c
index c465af7283fc..96c6c2634cb4 100644
--- a/arch/sh/kernel/cpu/sh2a/pinmux-sh7203.c
+++ b/arch/sh/kernel/cpu/sh2a/pinmux-sh7203.c
@@ -10,1588 +10,10 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/sh7203.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
- PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
- PB12_DATA,
- PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
- PC14_DATA, PC13_DATA, PC12_DATA,
- PC11_DATA, PC10_DATA, PC9_DATA, PC8_DATA,
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
- PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
- PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
- PE15_DATA, PE14_DATA, PE13_DATA, PE12_DATA,
- PE11_DATA, PE10_DATA, PE9_DATA, PE8_DATA,
- PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
- PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
- PF30_DATA, PF29_DATA, PF28_DATA,
- PF27_DATA, PF26_DATA, PF25_DATA, PF24_DATA,
- PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
- PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA,
- PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
- PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- FORCE_IN,
- PA7_IN, PA6_IN, PA5_IN, PA4_IN,
- PA3_IN, PA2_IN, PA1_IN, PA0_IN,
- PB11_IN, PB10_IN, PB9_IN, PB8_IN,
- PC14_IN, PC13_IN, PC12_IN,
- PC11_IN, PC10_IN, PC9_IN, PC8_IN,
- PC7_IN, PC6_IN, PC5_IN, PC4_IN,
- PC3_IN, PC2_IN, PC1_IN, PC0_IN,
- PD15_IN, PD14_IN, PD13_IN, PD12_IN,
- PD11_IN, PD10_IN, PD9_IN, PD8_IN,
- PD7_IN, PD6_IN, PD5_IN, PD4_IN,
- PD3_IN, PD2_IN, PD1_IN, PD0_IN,
- PE15_IN, PE14_IN, PE13_IN, PE12_IN,
- PE11_IN, PE10_IN, PE9_IN, PE8_IN,
- PE7_IN, PE6_IN, PE5_IN, PE4_IN,
- PE3_IN, PE2_IN, PE1_IN, PE0_IN,
- PF30_IN, PF29_IN, PF28_IN,
- PF27_IN, PF26_IN, PF25_IN, PF24_IN,
- PF23_IN, PF22_IN, PF21_IN, PF20_IN,
- PF19_IN, PF18_IN, PF17_IN, PF16_IN,
- PF15_IN, PF14_IN, PF13_IN, PF12_IN,
- PF11_IN, PF10_IN, PF9_IN, PF8_IN,
- PF7_IN, PF6_IN, PF5_IN, PF4_IN,
- PF3_IN, PF2_IN, PF1_IN, PF0_IN,
- PINMUX_INPUT_END,
-
- PINMUX_OUTPUT_BEGIN,
- FORCE_OUT,
- PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
- PC14_OUT, PC13_OUT, PC12_OUT,
- PC11_OUT, PC10_OUT, PC9_OUT, PC8_OUT,
- PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
- PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
- PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
- PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
- PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
- PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
- PE15_OUT, PE14_OUT, PE13_OUT, PE12_OUT,
- PE11_OUT, PE10_OUT, PE9_OUT, PE8_OUT,
- PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
- PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
- PF30_OUT, PF29_OUT, PF28_OUT,
- PF27_OUT, PF26_OUT, PF25_OUT, PF24_OUT,
- PF23_OUT, PF22_OUT, PF21_OUT, PF20_OUT,
- PF19_OUT, PF18_OUT, PF17_OUT, PF16_OUT,
- PF15_OUT, PF14_OUT, PF13_OUT, PF12_OUT,
- PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
- PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
- PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- PB11_IOR_IN, PB11_IOR_OUT,
- PB10_IOR_IN, PB10_IOR_OUT,
- PB9_IOR_IN, PB9_IOR_OUT,
- PB8_IOR_IN, PB8_IOR_OUT,
- PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
- PB11MD_0, PB11MD_1,
- PB10MD_0, PB10MD_1,
- PB9MD_00, PB9MD_01, PB9MD_10,
- PB8MD_00, PB8MD_01, PB8MD_10,
- PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
- PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
- PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
- PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
- PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11,
- PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11,
- PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11,
- PB0MD_00, PB0MD_01, PB0MD_10, PB0MD_11,
-
- PB12IRQ_00, PB12IRQ_01, PB12IRQ_10,
-
- PC14MD_0, PC14MD_1,
- PC13MD_0, PC13MD_1,
- PC12MD_0, PC12MD_1,
- PC11MD_00, PC11MD_01, PC11MD_10,
- PC10MD_00, PC10MD_01, PC10MD_10,
- PC9MD_0, PC9MD_1,
- PC8MD_0, PC8MD_1,
- PC7MD_0, PC7MD_1,
- PC6MD_0, PC6MD_1,
- PC5MD_0, PC5MD_1,
- PC4MD_0, PC4MD_1,
- PC3MD_0, PC3MD_1,
- PC2MD_0, PC2MD_1,
- PC1MD_0, PC1MD_1,
- PC0MD_00, PC0MD_01, PC0MD_10,
-
- PD15MD_000, PD15MD_001, PD15MD_010, PD15MD_100, PD15MD_101,
- PD14MD_000, PD14MD_001, PD14MD_010, PD14MD_101,
- PD13MD_000, PD13MD_001, PD13MD_010, PD13MD_100, PD13MD_101,
- PD12MD_000, PD12MD_001, PD12MD_010, PD12MD_100, PD12MD_101,
- PD11MD_000, PD11MD_001, PD11MD_010, PD11MD_100, PD11MD_101,
- PD10MD_000, PD10MD_001, PD10MD_010, PD10MD_100, PD10MD_101,
- PD9MD_000, PD9MD_001, PD9MD_010, PD9MD_100, PD9MD_101,
- PD8MD_000, PD8MD_001, PD8MD_010, PD8MD_100, PD8MD_101,
- PD7MD_000, PD7MD_001, PD7MD_010, PD7MD_011, PD7MD_100, PD7MD_101,
- PD6MD_000, PD6MD_001, PD6MD_010, PD6MD_011, PD6MD_100, PD6MD_101,
- PD5MD_000, PD5MD_001, PD5MD_010, PD5MD_011, PD5MD_100, PD5MD_101,
- PD4MD_000, PD4MD_001, PD4MD_010, PD4MD_011, PD4MD_100, PD4MD_101,
- PD3MD_000, PD3MD_001, PD3MD_010, PD3MD_011, PD3MD_100, PD3MD_101,
- PD2MD_000, PD2MD_001, PD2MD_010, PD2MD_011, PD2MD_100, PD2MD_101,
- PD1MD_000, PD1MD_001, PD1MD_010, PD1MD_011, PD1MD_100, PD1MD_101,
- PD0MD_000, PD0MD_001, PD0MD_010, PD0MD_011, PD0MD_100, PD0MD_101,
-
- PE15MD_00, PE15MD_01, PE15MD_11,
- PE14MD_00, PE14MD_01, PE14MD_11,
- PE13MD_00, PE13MD_11,
- PE12MD_00, PE12MD_11,
- PE11MD_000, PE11MD_001, PE11MD_010, PE11MD_100,
- PE10MD_000, PE10MD_001, PE10MD_010, PE10MD_100,
- PE9MD_00, PE9MD_01, PE9MD_10, PE9MD_11,
- PE8MD_00, PE8MD_01, PE8MD_10, PE8MD_11,
- PE7MD_000, PE7MD_001, PE7MD_010, PE7MD_011, PE7MD_100,
- PE6MD_000, PE6MD_001, PE6MD_010, PE6MD_011, PE6MD_100,
- PE5MD_000, PE5MD_001, PE5MD_010, PE5MD_011, PE5MD_100,
- PE4MD_000, PE4MD_001, PE4MD_010, PE4MD_011, PE4MD_100,
- PE3MD_00, PE3MD_01, PE3MD_11,
- PE2MD_00, PE2MD_01, PE2MD_11,
- PE1MD_00, PE1MD_01, PE1MD_10, PE1MD_11,
- PE0MD_000, PE0MD_001, PE0MD_011, PE0MD_100,
-
- PF30MD_0, PF30MD_1,
- PF29MD_0, PF29MD_1,
- PF28MD_0, PF28MD_1,
- PF27MD_0, PF27MD_1,
- PF26MD_0, PF26MD_1,
- PF25MD_0, PF25MD_1,
- PF24MD_0, PF24MD_1,
- PF23MD_00, PF23MD_01, PF23MD_10,
- PF22MD_00, PF22MD_01, PF22MD_10,
- PF21MD_00, PF21MD_01, PF21MD_10,
- PF20MD_00, PF20MD_01, PF20MD_10,
- PF19MD_00, PF19MD_01, PF19MD_10,
- PF18MD_00, PF18MD_01, PF18MD_10,
- PF17MD_00, PF17MD_01, PF17MD_10,
- PF16MD_00, PF16MD_01, PF16MD_10,
- PF15MD_00, PF15MD_01, PF15MD_10,
- PF14MD_00, PF14MD_01, PF14MD_10,
- PF13MD_00, PF13MD_01, PF13MD_10,
- PF12MD_00, PF12MD_01, PF12MD_10,
- PF11MD_00, PF11MD_01, PF11MD_10,
- PF10MD_00, PF10MD_01, PF10MD_10,
- PF9MD_00, PF9MD_01, PF9MD_10,
- PF8MD_00, PF8MD_01, PF8MD_10,
- PF7MD_00, PF7MD_01, PF7MD_10, PF7MD_11,
- PF6MD_00, PF6MD_01, PF6MD_10, PF6MD_11,
- PF5MD_00, PF5MD_01, PF5MD_10, PF5MD_11,
- PF4MD_00, PF4MD_01, PF4MD_10, PF4MD_11,
- PF3MD_00, PF3MD_01, PF3MD_10, PF3MD_11,
- PF2MD_00, PF2MD_01, PF2MD_10, PF2MD_11,
- PF1MD_00, PF1MD_01, PF1MD_10, PF1MD_11,
- PF0MD_00, PF0MD_01, PF0MD_10, PF0MD_11,
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
- PINT7_PB_MARK, PINT6_PB_MARK, PINT5_PB_MARK, PINT4_PB_MARK,
- PINT3_PB_MARK, PINT2_PB_MARK, PINT1_PB_MARK, PINT0_PB_MARK,
- PINT7_PD_MARK, PINT6_PD_MARK, PINT5_PD_MARK, PINT4_PD_MARK,
- PINT3_PD_MARK, PINT2_PD_MARK, PINT1_PD_MARK, PINT0_PD_MARK,
- IRQ7_PB_MARK, IRQ6_PB_MARK, IRQ5_PB_MARK, IRQ4_PB_MARK,
- IRQ3_PB_MARK, IRQ2_PB_MARK, IRQ1_PB_MARK, IRQ0_PB_MARK,
- IRQ7_PD_MARK, IRQ6_PD_MARK, IRQ5_PD_MARK, IRQ4_PD_MARK,
- IRQ3_PD_MARK, IRQ2_PD_MARK, IRQ1_PD_MARK, IRQ0_PD_MARK,
- IRQ7_PE_MARK, IRQ6_PE_MARK, IRQ5_PE_MARK, IRQ4_PE_MARK,
- IRQ3_PE_MARK, IRQ2_PE_MARK, IRQ1_PE_MARK, IRQ0_PE_MARK,
- WDTOVF_MARK, IRQOUT_MARK, REFOUT_MARK, IRQOUT_REFOUT_MARK,
- UBCTRG_MARK,
- CTX1_MARK, CRX1_MARK, CTX0_MARK, CTX0_CTX1_MARK,
- CRX0_MARK, CRX0_CRX1_MARK,
- SDA3_MARK, SCL3_MARK,
- SDA2_MARK, SCL2_MARK,
- SDA1_MARK, SCL1_MARK,
- SDA0_MARK, SCL0_MARK,
- TEND0_PD_MARK, TEND0_PE_MARK, DACK0_PD_MARK, DACK0_PE_MARK,
- DREQ0_PD_MARK, DREQ0_PE_MARK, TEND1_PD_MARK, TEND1_PE_MARK,
- DACK1_PD_MARK, DACK1_PE_MARK, DREQ1_PD_MARK, DREQ1_PE_MARK,
- DACK2_MARK, DREQ2_MARK, DACK3_MARK, DREQ3_MARK,
- ADTRG_PD_MARK, ADTRG_PE_MARK,
- D31_MARK, D30_MARK, D29_MARK, D28_MARK,
- D27_MARK, D26_MARK, D25_MARK, D24_MARK,
- D23_MARK, D22_MARK, D21_MARK, D20_MARK,
- D19_MARK, D18_MARK, D17_MARK, D16_MARK,
- A25_MARK, A24_MARK, A23_MARK, A22_MARK,
- A21_MARK, CS4_MARK, MRES_MARK, BS_MARK,
- IOIS16_MARK, CS1_MARK, CS6_CE1B_MARK, CE2B_MARK,
- CS5_CE1A_MARK, CE2A_MARK, FRAME_MARK, WAIT_MARK,
- RDWR_MARK, CKE_MARK, CASU_MARK, BREQ_MARK,
- RASU_MARK, BACK_MARK, CASL_MARK, RASL_MARK,
- WE3_DQMUU_AH_ICIO_WR_MARK, WE2_DQMUL_ICIORD_MARK,
- WE1_DQMLU_WE_MARK, WE0_DQMLL_MARK,
- CS3_MARK, CS2_MARK, A1_MARK, A0_MARK, CS7_MARK,
- TIOC4D_MARK, TIOC4C_MARK, TIOC4B_MARK, TIOC4A_MARK,
- TIOC3D_MARK, TIOC3C_MARK, TIOC3B_MARK, TIOC3A_MARK,
- TIOC2B_MARK, TIOC1B_MARK, TIOC2A_MARK, TIOC1A_MARK,
- TIOC0D_MARK, TIOC0C_MARK, TIOC0B_MARK, TIOC0A_MARK,
- TCLKD_PD_MARK, TCLKC_PD_MARK, TCLKB_PD_MARK, TCLKA_PD_MARK,
- TCLKD_PF_MARK, TCLKC_PF_MARK, TCLKB_PF_MARK, TCLKA_PF_MARK,
- SCS0_PD_MARK, SSO0_PD_MARK, SSI0_PD_MARK, SSCK0_PD_MARK,
- SCS0_PF_MARK, SSO0_PF_MARK, SSI0_PF_MARK, SSCK0_PF_MARK,
- SCS1_PD_MARK, SSO1_PD_MARK, SSI1_PD_MARK, SSCK1_PD_MARK,
- SCS1_PF_MARK, SSO1_PF_MARK, SSI1_PF_MARK, SSCK1_PF_MARK,
- TXD0_MARK, RXD0_MARK, SCK0_MARK,
- TXD1_MARK, RXD1_MARK, SCK1_MARK,
- TXD2_MARK, RXD2_MARK, SCK2_MARK,
- RTS3_MARK, CTS3_MARK, TXD3_MARK,
- RXD3_MARK, SCK3_MARK,
- AUDIO_CLK_MARK,
- SSIDATA3_MARK, SSIWS3_MARK, SSISCK3_MARK,
- SSIDATA2_MARK, SSIWS2_MARK, SSISCK2_MARK,
- SSIDATA1_MARK, SSIWS1_MARK, SSISCK1_MARK,
- SSIDATA0_MARK, SSIWS0_MARK, SSISCK0_MARK,
- FCE_MARK, FRB_MARK,
- NAF7_MARK, NAF6_MARK, NAF5_MARK, NAF4_MARK,
- NAF3_MARK, NAF2_MARK, NAF1_MARK, NAF0_MARK,
- FSC_MARK, FOE_MARK, FCDE_MARK, FWE_MARK,
- LCD_VEPWC_MARK, LCD_VCPWC_MARK, LCD_CLK_MARK, LCD_FLM_MARK,
- LCD_M_DISP_MARK, LCD_CL2_MARK, LCD_CL1_MARK, LCD_DON_MARK,
- LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
- LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
- LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
- LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
-
- /* PA */
- PINMUX_DATA(PA7_DATA, PA7_IN),
- PINMUX_DATA(PA6_DATA, PA6_IN),
- PINMUX_DATA(PA5_DATA, PA5_IN),
- PINMUX_DATA(PA4_DATA, PA4_IN),
- PINMUX_DATA(PA3_DATA, PA3_IN),
- PINMUX_DATA(PA2_DATA, PA2_IN),
- PINMUX_DATA(PA1_DATA, PA1_IN),
- PINMUX_DATA(PA0_DATA, PA0_IN),
-
- /* PB */
- PINMUX_DATA(PB12_DATA, PB12MD_00, FORCE_OUT),
- PINMUX_DATA(WDTOVF_MARK, PB12MD_01),
- PINMUX_DATA(IRQOUT_MARK, PB12MD_10, PB12IRQ_00),
- PINMUX_DATA(REFOUT_MARK, PB12MD_10, PB12IRQ_01),
- PINMUX_DATA(IRQOUT_REFOUT_MARK, PB12MD_10, PB12IRQ_10),
- PINMUX_DATA(UBCTRG_MARK, PB12MD_11),
-
- PINMUX_DATA(PB11_DATA, PB11MD_0, PB11_IN, PB11_OUT),
- PINMUX_DATA(CTX1_MARK, PB11MD_1),
-
- PINMUX_DATA(PB10_DATA, PB10MD_0, PB10_IN, PB10_OUT),
- PINMUX_DATA(CRX1_MARK, PB10MD_1),
-
- PINMUX_DATA(PB9_DATA, PB9MD_00, PB9_IN, PB9_OUT),
- PINMUX_DATA(CTX0_MARK, PB9MD_01),
- PINMUX_DATA(CTX0_CTX1_MARK, PB9MD_10),
-
- PINMUX_DATA(PB8_DATA, PB8MD_00, PB8_IN, PB8_OUT),
- PINMUX_DATA(CRX0_MARK, PB8MD_01),
- PINMUX_DATA(CRX0_CRX1_MARK, PB8MD_10),
-
- PINMUX_DATA(PB7_DATA, PB7MD_00, FORCE_IN),
- PINMUX_DATA(SDA3_MARK, PB7MD_01),
- PINMUX_DATA(PINT7_PB_MARK, PB7MD_10),
- PINMUX_DATA(IRQ7_PB_MARK, PB7MD_11),
-
- PINMUX_DATA(PB6_DATA, PB6MD_00, FORCE_IN),
- PINMUX_DATA(SCL3_MARK, PB6MD_01),
- PINMUX_DATA(PINT6_PB_MARK, PB6MD_10),
- PINMUX_DATA(IRQ6_PB_MARK, PB6MD_11),
-
- PINMUX_DATA(PB5_DATA, PB5MD_00, FORCE_IN),
- PINMUX_DATA(SDA2_MARK, PB6MD_01),
- PINMUX_DATA(PINT5_PB_MARK, PB6MD_10),
- PINMUX_DATA(IRQ5_PB_MARK, PB6MD_11),
-
- PINMUX_DATA(PB4_DATA, PB4MD_00, FORCE_IN),
- PINMUX_DATA(SCL2_MARK, PB4MD_01),
- PINMUX_DATA(PINT4_PB_MARK, PB4MD_10),
- PINMUX_DATA(IRQ4_PB_MARK, PB4MD_11),
-
- PINMUX_DATA(PB3_DATA, PB3MD_00, FORCE_IN),
- PINMUX_DATA(SDA1_MARK, PB3MD_01),
- PINMUX_DATA(PINT3_PB_MARK, PB3MD_10),
- PINMUX_DATA(IRQ3_PB_MARK, PB3MD_11),
-
- PINMUX_DATA(PB2_DATA, PB2MD_00, FORCE_IN),
- PINMUX_DATA(SCL1_MARK, PB2MD_01),
- PINMUX_DATA(PINT2_PB_MARK, PB2MD_10),
- PINMUX_DATA(IRQ2_PB_MARK, PB2MD_11),
-
- PINMUX_DATA(PB1_DATA, PB1MD_00, FORCE_IN),
- PINMUX_DATA(SDA0_MARK, PB1MD_01),
- PINMUX_DATA(PINT1_PB_MARK, PB1MD_10),
- PINMUX_DATA(IRQ1_PB_MARK, PB1MD_11),
-
- PINMUX_DATA(PB0_DATA, PB0MD_00, FORCE_IN),
- PINMUX_DATA(SCL0_MARK, PB0MD_01),
- PINMUX_DATA(PINT0_PB_MARK, PB0MD_10),
- PINMUX_DATA(IRQ0_PB_MARK, PB0MD_11),
-
- /* PC */
- PINMUX_DATA(PC14_DATA, PC14MD_0, PC14_IN, PC14_OUT),
- PINMUX_DATA(WAIT_MARK, PC14MD_1),
-
- PINMUX_DATA(PC13_DATA, PC13MD_0, PC13_IN, PC13_OUT),
- PINMUX_DATA(RDWR_MARK, PC13MD_1),
-
- PINMUX_DATA(PC12_DATA, PC12MD_0, PC12_IN, PC12_OUT),
- PINMUX_DATA(CKE_MARK, PC12MD_1),
-
- PINMUX_DATA(PC11_DATA, PC11MD_00, PC11_IN, PC11_OUT),
- PINMUX_DATA(CASU_MARK, PC11MD_01),
- PINMUX_DATA(BREQ_MARK, PC11MD_10),
-
- PINMUX_DATA(PC10_DATA, PC10MD_00, PC10_IN, PC10_OUT),
- PINMUX_DATA(RASU_MARK, PC10MD_01),
- PINMUX_DATA(BACK_MARK, PC10MD_10),
-
- PINMUX_DATA(PC9_DATA, PC9MD_0, PC9_IN, PC9_OUT),
- PINMUX_DATA(CASL_MARK, PC9MD_1),
-
- PINMUX_DATA(PC8_DATA, PC8MD_0, PC8_IN, PC8_OUT),
- PINMUX_DATA(RASL_MARK, PC8MD_1),
-
- PINMUX_DATA(PC7_DATA, PC7MD_0, PC7_IN, PC7_OUT),
- PINMUX_DATA(WE3_DQMUU_AH_ICIO_WR_MARK, PC7MD_1),
-
- PINMUX_DATA(PC6_DATA, PC6MD_0, PC6_IN, PC6_OUT),
- PINMUX_DATA(WE2_DQMUL_ICIORD_MARK, PC6MD_1),
-
- PINMUX_DATA(PC5_DATA, PC5MD_0, PC5_IN, PC5_OUT),
- PINMUX_DATA(WE1_DQMLU_WE_MARK, PC5MD_1),
-
- PINMUX_DATA(PC4_DATA, PC4MD_0, PC4_IN, PC4_OUT),
- PINMUX_DATA(WE0_DQMLL_MARK, PC4MD_1),
-
- PINMUX_DATA(PC3_DATA, PC3MD_0, PC3_IN, PC3_OUT),
- PINMUX_DATA(CS3_MARK, PC3MD_1),
-
- PINMUX_DATA(PC2_DATA, PC2MD_0, PC2_IN, PC2_OUT),
- PINMUX_DATA(CS2_MARK, PC2MD_1),
-
- PINMUX_DATA(PC1_DATA, PC1MD_0, PC1_IN, PC1_OUT),
- PINMUX_DATA(A1_MARK, PC1MD_1),
-
- PINMUX_DATA(PC0_DATA, PC0MD_00, PC0_IN, PC0_OUT),
- PINMUX_DATA(A0_MARK, PC0MD_01),
- PINMUX_DATA(CS7_MARK, PC0MD_10),
-
- /* PD */
- PINMUX_DATA(PD15_DATA, PD15MD_000, PD15_IN, PD15_OUT),
- PINMUX_DATA(D31_MARK, PD15MD_001),
- PINMUX_DATA(PINT7_PD_MARK, PD15MD_010),
- PINMUX_DATA(ADTRG_PD_MARK, PD15MD_100),
- PINMUX_DATA(TIOC4D_MARK, PD15MD_101),
-
- PINMUX_DATA(PD14_DATA, PD14MD_000, PD14_IN, PD14_OUT),
- PINMUX_DATA(D30_MARK, PD14MD_001),
- PINMUX_DATA(PINT6_PD_MARK, PD14MD_010),
- PINMUX_DATA(TIOC4C_MARK, PD14MD_101),
-
- PINMUX_DATA(PD13_DATA, PD13MD_000, PD13_IN, PD13_OUT),
- PINMUX_DATA(D29_MARK, PD13MD_001),
- PINMUX_DATA(PINT5_PD_MARK, PD13MD_010),
- PINMUX_DATA(TEND1_PD_MARK, PD13MD_100),
- PINMUX_DATA(TIOC4B_MARK, PD13MD_101),
-
- PINMUX_DATA(PD12_DATA, PD12MD_000, PD12_IN, PD12_OUT),
- PINMUX_DATA(D28_MARK, PD12MD_001),
- PINMUX_DATA(PINT4_PD_MARK, PD12MD_010),
- PINMUX_DATA(DACK1_PD_MARK, PD12MD_100),
- PINMUX_DATA(TIOC4A_MARK, PD12MD_101),
-
- PINMUX_DATA(PD11_DATA, PD11MD_000, PD11_IN, PD11_OUT),
- PINMUX_DATA(D27_MARK, PD11MD_001),
- PINMUX_DATA(PINT3_PD_MARK, PD11MD_010),
- PINMUX_DATA(DREQ1_PD_MARK, PD11MD_100),
- PINMUX_DATA(TIOC3D_MARK, PD11MD_101),
-
- PINMUX_DATA(PD10_DATA, PD10MD_000, PD10_IN, PD10_OUT),
- PINMUX_DATA(D26_MARK, PD10MD_001),
- PINMUX_DATA(PINT2_PD_MARK, PD10MD_010),
- PINMUX_DATA(TEND0_PD_MARK, PD10MD_100),
- PINMUX_DATA(TIOC3C_MARK, PD10MD_101),
-
- PINMUX_DATA(PD9_DATA, PD9MD_000, PD9_IN, PD9_OUT),
- PINMUX_DATA(D25_MARK, PD9MD_001),
- PINMUX_DATA(PINT1_PD_MARK, PD9MD_010),
- PINMUX_DATA(DACK0_PD_MARK, PD9MD_100),
- PINMUX_DATA(TIOC3B_MARK, PD9MD_101),
-
- PINMUX_DATA(PD8_DATA, PD8MD_000, PD8_IN, PD8_OUT),
- PINMUX_DATA(D24_MARK, PD8MD_001),
- PINMUX_DATA(PINT0_PD_MARK, PD8MD_010),
- PINMUX_DATA(DREQ0_PD_MARK, PD8MD_100),
- PINMUX_DATA(TIOC3A_MARK, PD8MD_101),
-
- PINMUX_DATA(PD7_DATA, PD7MD_000, PD7_IN, PD7_OUT),
- PINMUX_DATA(D23_MARK, PD7MD_001),
- PINMUX_DATA(IRQ7_PD_MARK, PD7MD_010),
- PINMUX_DATA(SCS1_PD_MARK, PD7MD_011),
- PINMUX_DATA(TCLKD_PD_MARK, PD7MD_100),
- PINMUX_DATA(TIOC2B_MARK, PD7MD_101),
-
- PINMUX_DATA(PD6_DATA, PD6MD_000, PD6_IN, PD6_OUT),
- PINMUX_DATA(D22_MARK, PD6MD_001),
- PINMUX_DATA(IRQ6_PD_MARK, PD6MD_010),
- PINMUX_DATA(SSO1_PD_MARK, PD6MD_011),
- PINMUX_DATA(TCLKC_PD_MARK, PD6MD_100),
- PINMUX_DATA(TIOC2A_MARK, PD6MD_101),
-
- PINMUX_DATA(PD5_DATA, PD5MD_000, PD5_IN, PD5_OUT),
- PINMUX_DATA(D21_MARK, PD5MD_001),
- PINMUX_DATA(IRQ5_PD_MARK, PD5MD_010),
- PINMUX_DATA(SSI1_PD_MARK, PD5MD_011),
- PINMUX_DATA(TCLKB_PD_MARK, PD5MD_100),
- PINMUX_DATA(TIOC1B_MARK, PD5MD_101),
-
- PINMUX_DATA(PD4_DATA, PD4MD_000, PD4_IN, PD4_OUT),
- PINMUX_DATA(D20_MARK, PD4MD_001),
- PINMUX_DATA(IRQ4_PD_MARK, PD4MD_010),
- PINMUX_DATA(SSCK1_PD_MARK, PD4MD_011),
- PINMUX_DATA(TCLKA_PD_MARK, PD4MD_100),
- PINMUX_DATA(TIOC1A_MARK, PD4MD_101),
-
- PINMUX_DATA(PD3_DATA, PD3MD_000, PD3_IN, PD3_OUT),
- PINMUX_DATA(D19_MARK, PD3MD_001),
- PINMUX_DATA(IRQ3_PD_MARK, PD3MD_010),
- PINMUX_DATA(SCS0_PD_MARK, PD3MD_011),
- PINMUX_DATA(DACK3_MARK, PD3MD_100),
- PINMUX_DATA(TIOC0D_MARK, PD3MD_101),
-
- PINMUX_DATA(PD2_DATA, PD2MD_000, PD2_IN, PD2_OUT),
- PINMUX_DATA(D18_MARK, PD2MD_001),
- PINMUX_DATA(IRQ2_PD_MARK, PD2MD_010),
- PINMUX_DATA(SSO0_PD_MARK, PD2MD_011),
- PINMUX_DATA(DREQ3_MARK, PD2MD_100),
- PINMUX_DATA(TIOC0C_MARK, PD2MD_101),
-
- PINMUX_DATA(PD1_DATA, PD1MD_000, PD1_IN, PD1_OUT),
- PINMUX_DATA(D17_MARK, PD1MD_001),
- PINMUX_DATA(IRQ1_PD_MARK, PD1MD_010),
- PINMUX_DATA(SSI0_PD_MARK, PD1MD_011),
- PINMUX_DATA(DACK2_MARK, PD1MD_100),
- PINMUX_DATA(TIOC0B_MARK, PD1MD_101),
-
- PINMUX_DATA(PD0_DATA, PD0MD_000, PD0_IN, PD0_OUT),
- PINMUX_DATA(D16_MARK, PD0MD_001),
- PINMUX_DATA(IRQ0_PD_MARK, PD0MD_010),
- PINMUX_DATA(SSCK0_PD_MARK, PD0MD_011),
- PINMUX_DATA(DREQ2_MARK, PD0MD_100),
- PINMUX_DATA(TIOC0A_MARK, PD0MD_101),
-
- /* PE */
- PINMUX_DATA(PE15_DATA, PE15MD_00, PE15_IN, PE15_OUT),
- PINMUX_DATA(IOIS16_MARK, PE15MD_01),
- PINMUX_DATA(RTS3_MARK, PE15MD_11),
-
- PINMUX_DATA(PE14_DATA, PE14MD_00, PE14_IN, PE14_OUT),
- PINMUX_DATA(CS1_MARK, PE14MD_01),
- PINMUX_DATA(CTS3_MARK, PE14MD_11),
-
- PINMUX_DATA(PE13_DATA, PE13MD_00, PE13_IN, PE13_OUT),
- PINMUX_DATA(TXD3_MARK, PE13MD_11),
-
- PINMUX_DATA(PE12_DATA, PE12MD_00, PE12_IN, PE12_OUT),
- PINMUX_DATA(RXD3_MARK, PE12MD_11),
-
- PINMUX_DATA(PE11_DATA, PE11MD_000, PE11_IN, PE11_OUT),
- PINMUX_DATA(CS6_CE1B_MARK, PE11MD_001),
- PINMUX_DATA(IRQ7_PE_MARK, PE11MD_010),
- PINMUX_DATA(TEND1_PE_MARK, PE11MD_100),
-
- PINMUX_DATA(PE10_DATA, PE10MD_000, PE10_IN, PE10_OUT),
- PINMUX_DATA(CE2B_MARK, PE10MD_001),
- PINMUX_DATA(IRQ6_PE_MARK, PE10MD_010),
- PINMUX_DATA(TEND0_PE_MARK, PE10MD_100),
-
- PINMUX_DATA(PE9_DATA, PE9MD_00, PE9_IN, PE9_OUT),
- PINMUX_DATA(CS5_CE1A_MARK, PE9MD_01),
- PINMUX_DATA(IRQ5_PE_MARK, PE9MD_10),
- PINMUX_DATA(SCK3_MARK, PE9MD_11),
-
- PINMUX_DATA(PE8_DATA, PE8MD_00, PE8_IN, PE8_OUT),
- PINMUX_DATA(CE2A_MARK, PE8MD_01),
- PINMUX_DATA(IRQ4_PE_MARK, PE8MD_10),
- PINMUX_DATA(SCK2_MARK, PE8MD_11),
-
- PINMUX_DATA(PE7_DATA, PE7MD_000, PE7_IN, PE7_OUT),
- PINMUX_DATA(FRAME_MARK, PE7MD_001),
- PINMUX_DATA(IRQ3_PE_MARK, PE7MD_010),
- PINMUX_DATA(TXD2_MARK, PE7MD_011),
- PINMUX_DATA(DACK1_PE_MARK, PE7MD_100),
-
- PINMUX_DATA(PE6_DATA, PE6MD_000, PE6_IN, PE6_OUT),
- PINMUX_DATA(A25_MARK, PE6MD_001),
- PINMUX_DATA(IRQ2_PE_MARK, PE6MD_010),
- PINMUX_DATA(RXD2_MARK, PE6MD_011),
- PINMUX_DATA(DREQ1_PE_MARK, PE6MD_100),
-
- PINMUX_DATA(PE5_DATA, PE5MD_000, PE5_IN, PE5_OUT),
- PINMUX_DATA(A24_MARK, PE5MD_001),
- PINMUX_DATA(IRQ1_PE_MARK, PE5MD_010),
- PINMUX_DATA(TXD1_MARK, PE5MD_011),
- PINMUX_DATA(DACK0_PE_MARK, PE5MD_100),
-
- PINMUX_DATA(PE4_DATA, PE4MD_000, PE4_IN, PE4_OUT),
- PINMUX_DATA(A23_MARK, PE4MD_001),
- PINMUX_DATA(IRQ0_PE_MARK, PE4MD_010),
- PINMUX_DATA(RXD1_MARK, PE4MD_011),
- PINMUX_DATA(DREQ0_PE_MARK, PE4MD_100),
-
- PINMUX_DATA(PE3_DATA, PE3MD_00, PE3_IN, PE3_OUT),
- PINMUX_DATA(A22_MARK, PE3MD_01),
- PINMUX_DATA(SCK1_MARK, PE3MD_11),
-
- PINMUX_DATA(PE2_DATA, PE2MD_00, PE2_IN, PE2_OUT),
- PINMUX_DATA(A21_MARK, PE2MD_01),
- PINMUX_DATA(SCK0_MARK, PE2MD_11),
-
- PINMUX_DATA(PE1_DATA, PE1MD_00, PE1_IN, PE1_OUT),
- PINMUX_DATA(CS4_MARK, PE1MD_01),
- PINMUX_DATA(MRES_MARK, PE1MD_10),
- PINMUX_DATA(TXD0_MARK, PE1MD_11),
-
- PINMUX_DATA(PE0_DATA, PE0MD_000, PE0_IN, PE0_OUT),
- PINMUX_DATA(BS_MARK, PE0MD_001),
- PINMUX_DATA(RXD0_MARK, PE0MD_011),
- PINMUX_DATA(ADTRG_PE_MARK, PE0MD_100),
-
- /* PF */
- PINMUX_DATA(PF30_DATA, PF30MD_0, PF30_IN, PF30_OUT),
- PINMUX_DATA(AUDIO_CLK_MARK, PF30MD_1),
-
- PINMUX_DATA(PF29_DATA, PF29MD_0, PF29_IN, PF29_OUT),
- PINMUX_DATA(SSIDATA3_MARK, PF29MD_1),
-
- PINMUX_DATA(PF28_DATA, PF28MD_0, PF28_IN, PF28_OUT),
- PINMUX_DATA(SSIWS3_MARK, PF28MD_1),
-
- PINMUX_DATA(PF27_DATA, PF27MD_0, PF27_IN, PF27_OUT),
- PINMUX_DATA(SSISCK3_MARK, PF27MD_1),
-
- PINMUX_DATA(PF26_DATA, PF26MD_0, PF26_IN, PF26_OUT),
- PINMUX_DATA(SSIDATA2_MARK, PF26MD_1),
-
- PINMUX_DATA(PF25_DATA, PF25MD_0, PF25_IN, PF25_OUT),
- PINMUX_DATA(SSIWS2_MARK, PF25MD_1),
-
- PINMUX_DATA(PF24_DATA, PF24MD_0, PF24_IN, PF24_OUT),
- PINMUX_DATA(SSISCK2_MARK, PF24MD_1),
-
- PINMUX_DATA(PF23_DATA, PF23MD_00, PF23_IN, PF23_OUT),
- PINMUX_DATA(SSIDATA1_MARK, PF23MD_01),
- PINMUX_DATA(LCD_VEPWC_MARK, PF23MD_10),
-
- PINMUX_DATA(PF22_DATA, PF22MD_00, PF22_IN, PF22_OUT),
- PINMUX_DATA(SSIWS1_MARK, PF22MD_01),
- PINMUX_DATA(LCD_VCPWC_MARK, PF22MD_10),
-
- PINMUX_DATA(PF21_DATA, PF21MD_00, PF21_IN, PF21_OUT),
- PINMUX_DATA(SSISCK1_MARK, PF21MD_01),
- PINMUX_DATA(LCD_CLK_MARK, PF21MD_10),
-
- PINMUX_DATA(PF20_DATA, PF20MD_00, PF20_IN, PF20_OUT),
- PINMUX_DATA(SSIDATA0_MARK, PF20MD_01),
- PINMUX_DATA(LCD_FLM_MARK, PF20MD_10),
-
- PINMUX_DATA(PF19_DATA, PF19MD_00, PF19_IN, PF19_OUT),
- PINMUX_DATA(SSIWS0_MARK, PF19MD_01),
- PINMUX_DATA(LCD_M_DISP_MARK, PF19MD_10),
-
- PINMUX_DATA(PF18_DATA, PF18MD_00, PF18_IN, PF18_OUT),
- PINMUX_DATA(SSISCK0_MARK, PF18MD_01),
- PINMUX_DATA(LCD_CL2_MARK, PF18MD_10),
-
- PINMUX_DATA(PF17_DATA, PF17MD_00, PF17_IN, PF17_OUT),
- PINMUX_DATA(FCE_MARK, PF17MD_01),
- PINMUX_DATA(LCD_CL1_MARK, PF17MD_10),
-
- PINMUX_DATA(PF16_DATA, PF16MD_00, PF16_IN, PF16_OUT),
- PINMUX_DATA(FRB_MARK, PF16MD_01),
- PINMUX_DATA(LCD_DON_MARK, PF16MD_10),
-
- PINMUX_DATA(PF15_DATA, PF15MD_00, PF15_IN, PF15_OUT),
- PINMUX_DATA(NAF7_MARK, PF15MD_01),
- PINMUX_DATA(LCD_DATA15_MARK, PF15MD_10),
-
- PINMUX_DATA(PF14_DATA, PF14MD_00, PF14_IN, PF14_OUT),
- PINMUX_DATA(NAF6_MARK, PF14MD_01),
- PINMUX_DATA(LCD_DATA14_MARK, PF14MD_10),
-
- PINMUX_DATA(PF13_DATA, PF13MD_00, PF13_IN, PF13_OUT),
- PINMUX_DATA(NAF5_MARK, PF13MD_01),
- PINMUX_DATA(LCD_DATA13_MARK, PF13MD_10),
-
- PINMUX_DATA(PF12_DATA, PF12MD_00, PF12_IN, PF12_OUT),
- PINMUX_DATA(NAF4_MARK, PF12MD_01),
- PINMUX_DATA(LCD_DATA12_MARK, PF12MD_10),
-
- PINMUX_DATA(PF11_DATA, PF11MD_00, PF11_IN, PF11_OUT),
- PINMUX_DATA(NAF3_MARK, PF11MD_01),
- PINMUX_DATA(LCD_DATA11_MARK, PF11MD_10),
-
- PINMUX_DATA(PF10_DATA, PF10MD_00, PF10_IN, PF10_OUT),
- PINMUX_DATA(NAF2_MARK, PF10MD_01),
- PINMUX_DATA(LCD_DATA10_MARK, PF10MD_10),
-
- PINMUX_DATA(PF9_DATA, PF9MD_00, PF9_IN, PF9_OUT),
- PINMUX_DATA(NAF1_MARK, PF9MD_01),
- PINMUX_DATA(LCD_DATA9_MARK, PF9MD_10),
-
- PINMUX_DATA(PF8_DATA, PF8MD_00, PF8_IN, PF8_OUT),
- PINMUX_DATA(NAF0_MARK, PF8MD_01),
- PINMUX_DATA(LCD_DATA8_MARK, PF8MD_10),
-
- PINMUX_DATA(PF7_DATA, PF7MD_00, PF7_IN, PF7_OUT),
- PINMUX_DATA(FSC_MARK, PF7MD_01),
- PINMUX_DATA(LCD_DATA7_MARK, PF7MD_10),
- PINMUX_DATA(SCS1_PF_MARK, PF7MD_11),
-
- PINMUX_DATA(PF6_DATA, PF6MD_00, PF6_IN, PF6_OUT),
- PINMUX_DATA(FOE_MARK, PF6MD_01),
- PINMUX_DATA(LCD_DATA6_MARK, PF6MD_10),
- PINMUX_DATA(SSO1_PF_MARK, PF6MD_11),
-
- PINMUX_DATA(PF5_DATA, PF5MD_00, PF5_IN, PF5_OUT),
- PINMUX_DATA(FCDE_MARK, PF5MD_01),
- PINMUX_DATA(LCD_DATA5_MARK, PF5MD_10),
- PINMUX_DATA(SSI1_PF_MARK, PF5MD_11),
-
- PINMUX_DATA(PF4_DATA, PF4MD_00, PF4_IN, PF4_OUT),
- PINMUX_DATA(FWE_MARK, PF4MD_01),
- PINMUX_DATA(LCD_DATA4_MARK, PF4MD_10),
- PINMUX_DATA(SSCK1_PF_MARK, PF4MD_11),
-
- PINMUX_DATA(PF3_DATA, PF3MD_00, PF3_IN, PF3_OUT),
- PINMUX_DATA(TCLKD_PF_MARK, PF3MD_01),
- PINMUX_DATA(LCD_DATA3_MARK, PF3MD_10),
- PINMUX_DATA(SCS0_PF_MARK, PF3MD_11),
-
- PINMUX_DATA(PF2_DATA, PF2MD_00, PF2_IN, PF2_OUT),
- PINMUX_DATA(TCLKC_PF_MARK, PF2MD_01),
- PINMUX_DATA(LCD_DATA2_MARK, PF2MD_10),
- PINMUX_DATA(SSO0_PF_MARK, PF2MD_11),
-
- PINMUX_DATA(PF1_DATA, PF1MD_00, PF1_IN, PF1_OUT),
- PINMUX_DATA(TCLKB_PF_MARK, PF1MD_01),
- PINMUX_DATA(LCD_DATA1_MARK, PF1MD_10),
- PINMUX_DATA(SSI0_PF_MARK, PF1MD_11),
-
- PINMUX_DATA(PF0_DATA, PF0MD_00, PF0_IN, PF0_OUT),
- PINMUX_DATA(TCLKA_PF_MARK, PF0MD_01),
- PINMUX_DATA(LCD_DATA0_MARK, PF0MD_10),
- PINMUX_DATA(SSCK0_PF_MARK, PF0MD_11),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
-
- /* PA */
- PINMUX_GPIO(GPIO_PA7, PA7_DATA),
- PINMUX_GPIO(GPIO_PA6, PA6_DATA),
- PINMUX_GPIO(GPIO_PA5, PA5_DATA),
- PINMUX_GPIO(GPIO_PA4, PA4_DATA),
- PINMUX_GPIO(GPIO_PA3, PA3_DATA),
- PINMUX_GPIO(GPIO_PA2, PA2_DATA),
- PINMUX_GPIO(GPIO_PA1, PA1_DATA),
- PINMUX_GPIO(GPIO_PA0, PA0_DATA),
-
- /* PB */
- PINMUX_GPIO(GPIO_PB12, PB12_DATA),
- PINMUX_GPIO(GPIO_PB11, PB11_DATA),
- PINMUX_GPIO(GPIO_PB10, PB10_DATA),
- PINMUX_GPIO(GPIO_PB9, PB9_DATA),
- PINMUX_GPIO(GPIO_PB8, PB8_DATA),
- PINMUX_GPIO(GPIO_PB7, PB7_DATA),
- PINMUX_GPIO(GPIO_PB6, PB6_DATA),
- PINMUX_GPIO(GPIO_PB5, PB5_DATA),
- PINMUX_GPIO(GPIO_PB4, PB4_DATA),
- PINMUX_GPIO(GPIO_PB3, PB3_DATA),
- PINMUX_GPIO(GPIO_PB2, PB2_DATA),
- PINMUX_GPIO(GPIO_PB1, PB1_DATA),
- PINMUX_GPIO(GPIO_PB0, PB0_DATA),
-
- /* PC */
- PINMUX_GPIO(GPIO_PC14, PC14_DATA),
- PINMUX_GPIO(GPIO_PC13, PC13_DATA),
- PINMUX_GPIO(GPIO_PC12, PC12_DATA),
- PINMUX_GPIO(GPIO_PC11, PC11_DATA),
- PINMUX_GPIO(GPIO_PC10, PC10_DATA),
- PINMUX_GPIO(GPIO_PC9, PC9_DATA),
- PINMUX_GPIO(GPIO_PC8, PC8_DATA),
- PINMUX_GPIO(GPIO_PC7, PC7_DATA),
- PINMUX_GPIO(GPIO_PC6, PC6_DATA),
- PINMUX_GPIO(GPIO_PC5, PC5_DATA),
- PINMUX_GPIO(GPIO_PC4, PC4_DATA),
- PINMUX_GPIO(GPIO_PC3, PC3_DATA),
- PINMUX_GPIO(GPIO_PC2, PC2_DATA),
- PINMUX_GPIO(GPIO_PC1, PC1_DATA),
- PINMUX_GPIO(GPIO_PC0, PC0_DATA),
-
- /* PD */
- PINMUX_GPIO(GPIO_PD15, PD15_DATA),
- PINMUX_GPIO(GPIO_PD14, PD14_DATA),
- PINMUX_GPIO(GPIO_PD13, PD13_DATA),
- PINMUX_GPIO(GPIO_PD12, PD12_DATA),
- PINMUX_GPIO(GPIO_PD11, PD11_DATA),
- PINMUX_GPIO(GPIO_PD10, PD10_DATA),
- PINMUX_GPIO(GPIO_PD9, PD9_DATA),
- PINMUX_GPIO(GPIO_PD8, PD8_DATA),
- PINMUX_GPIO(GPIO_PD7, PD7_DATA),
- PINMUX_GPIO(GPIO_PD6, PD6_DATA),
- PINMUX_GPIO(GPIO_PD5, PD5_DATA),
- PINMUX_GPIO(GPIO_PD4, PD4_DATA),
- PINMUX_GPIO(GPIO_PD3, PD3_DATA),
- PINMUX_GPIO(GPIO_PD2, PD2_DATA),
- PINMUX_GPIO(GPIO_PD1, PD1_DATA),
- PINMUX_GPIO(GPIO_PD0, PD0_DATA),
-
- /* PE */
- PINMUX_GPIO(GPIO_PE15, PE15_DATA),
- PINMUX_GPIO(GPIO_PE14, PE14_DATA),
- PINMUX_GPIO(GPIO_PE13, PE13_DATA),
- PINMUX_GPIO(GPIO_PE12, PE12_DATA),
- PINMUX_GPIO(GPIO_PE11, PE11_DATA),
- PINMUX_GPIO(GPIO_PE10, PE10_DATA),
- PINMUX_GPIO(GPIO_PE9, PE9_DATA),
- PINMUX_GPIO(GPIO_PE8, PE8_DATA),
- PINMUX_GPIO(GPIO_PE7, PE7_DATA),
- PINMUX_GPIO(GPIO_PE6, PE6_DATA),
- PINMUX_GPIO(GPIO_PE5, PE5_DATA),
- PINMUX_GPIO(GPIO_PE4, PE4_DATA),
- PINMUX_GPIO(GPIO_PE3, PE3_DATA),
- PINMUX_GPIO(GPIO_PE2, PE2_DATA),
- PINMUX_GPIO(GPIO_PE1, PE1_DATA),
- PINMUX_GPIO(GPIO_PE0, PE0_DATA),
-
- /* PF */
- PINMUX_GPIO(GPIO_PF30, PF30_DATA),
- PINMUX_GPIO(GPIO_PF29, PF29_DATA),
- PINMUX_GPIO(GPIO_PF28, PF28_DATA),
- PINMUX_GPIO(GPIO_PF27, PF27_DATA),
- PINMUX_GPIO(GPIO_PF26, PF26_DATA),
- PINMUX_GPIO(GPIO_PF25, PF25_DATA),
- PINMUX_GPIO(GPIO_PF24, PF24_DATA),
- PINMUX_GPIO(GPIO_PF23, PF23_DATA),
- PINMUX_GPIO(GPIO_PF22, PF22_DATA),
- PINMUX_GPIO(GPIO_PF21, PF21_DATA),
- PINMUX_GPIO(GPIO_PF20, PF20_DATA),
- PINMUX_GPIO(GPIO_PF19, PF19_DATA),
- PINMUX_GPIO(GPIO_PF18, PF18_DATA),
- PINMUX_GPIO(GPIO_PF17, PF17_DATA),
- PINMUX_GPIO(GPIO_PF16, PF16_DATA),
- PINMUX_GPIO(GPIO_PF15, PF15_DATA),
- PINMUX_GPIO(GPIO_PF14, PF14_DATA),
- PINMUX_GPIO(GPIO_PF13, PF13_DATA),
- PINMUX_GPIO(GPIO_PF12, PF12_DATA),
- PINMUX_GPIO(GPIO_PF11, PF11_DATA),
- PINMUX_GPIO(GPIO_PF10, PF10_DATA),
- PINMUX_GPIO(GPIO_PF9, PF9_DATA),
- PINMUX_GPIO(GPIO_PF8, PF8_DATA),
- PINMUX_GPIO(GPIO_PF7, PF7_DATA),
- PINMUX_GPIO(GPIO_PF6, PF6_DATA),
- PINMUX_GPIO(GPIO_PF5, PF5_DATA),
- PINMUX_GPIO(GPIO_PF4, PF4_DATA),
- PINMUX_GPIO(GPIO_PF3, PF3_DATA),
- PINMUX_GPIO(GPIO_PF2, PF2_DATA),
- PINMUX_GPIO(GPIO_PF1, PF1_DATA),
- PINMUX_GPIO(GPIO_PF0, PF0_DATA),
-
- /* INTC */
- PINMUX_GPIO(GPIO_FN_PINT7_PB, PINT7_PB_MARK),
- PINMUX_GPIO(GPIO_FN_PINT6_PB, PINT6_PB_MARK),
- PINMUX_GPIO(GPIO_FN_PINT5_PB, PINT5_PB_MARK),
- PINMUX_GPIO(GPIO_FN_PINT4_PB, PINT4_PB_MARK),
- PINMUX_GPIO(GPIO_FN_PINT3_PB, PINT3_PB_MARK),
- PINMUX_GPIO(GPIO_FN_PINT2_PB, PINT2_PB_MARK),
- PINMUX_GPIO(GPIO_FN_PINT1_PB, PINT1_PB_MARK),
- PINMUX_GPIO(GPIO_FN_PINT0_PB, PINT0_PB_MARK),
- PINMUX_GPIO(GPIO_FN_PINT7_PD, PINT7_PD_MARK),
- PINMUX_GPIO(GPIO_FN_PINT6_PD, PINT6_PD_MARK),
- PINMUX_GPIO(GPIO_FN_PINT5_PD, PINT5_PD_MARK),
- PINMUX_GPIO(GPIO_FN_PINT4_PD, PINT4_PD_MARK),
- PINMUX_GPIO(GPIO_FN_PINT3_PD, PINT3_PD_MARK),
- PINMUX_GPIO(GPIO_FN_PINT2_PD, PINT2_PD_MARK),
- PINMUX_GPIO(GPIO_FN_PINT1_PD, PINT1_PD_MARK),
- PINMUX_GPIO(GPIO_FN_PINT0_PD, PINT0_PD_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ7_PB, IRQ7_PB_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ6_PB, IRQ6_PB_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ5_PB, IRQ5_PB_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ4_PB, IRQ4_PB_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3_PB, IRQ3_PB_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2_PB, IRQ2_PB_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1_PB, IRQ1_PB_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0_PB, IRQ0_PB_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ7_PD, IRQ7_PD_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ6_PD, IRQ6_PD_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ5_PD, IRQ5_PD_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ4_PD, IRQ4_PD_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3_PD, IRQ3_PD_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2_PD, IRQ2_PD_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1_PD, IRQ1_PD_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0_PD, IRQ0_PD_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ7_PE, IRQ7_PE_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ6_PE, IRQ6_PE_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ5_PE, IRQ5_PE_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ4_PE, IRQ4_PE_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3_PE, IRQ3_PE_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2_PE, IRQ2_PE_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1_PE, IRQ1_PE_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0_PE, IRQ0_PE_MARK),
-
- PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
- PINMUX_GPIO(GPIO_FN_IRQOUT, IRQOUT_MARK),
- PINMUX_GPIO(GPIO_FN_REFOUT, REFOUT_MARK),
- PINMUX_GPIO(GPIO_FN_IRQOUT_REFOUT, IRQOUT_REFOUT_MARK),
- PINMUX_GPIO(GPIO_FN_UBCTRG, UBCTRG_MARK),
-
- /* CAN */
- PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
- PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
- PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
- PINMUX_GPIO(GPIO_FN_CTX0_CTX1, CTX0_CTX1_MARK),
- PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
- PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0_CRX1_MARK),
-
- /* IIC3 */
- PINMUX_GPIO(GPIO_FN_SDA3, SDA3_MARK),
- PINMUX_GPIO(GPIO_FN_SCL3, SCL3_MARK),
- PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
- PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
- PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
- PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
- PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
- PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
-
- /* DMAC */
- PINMUX_GPIO(GPIO_FN_TEND0_PD, TEND0_PD_MARK),
- PINMUX_GPIO(GPIO_FN_TEND0_PE, TEND0_PE_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0_PD, DACK0_PD_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0_PE, DACK0_PE_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0_PD, DREQ0_PD_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0_PE, DREQ0_PE_MARK),
- PINMUX_GPIO(GPIO_FN_TEND1_PD, TEND1_PD_MARK),
- PINMUX_GPIO(GPIO_FN_TEND1_PE, TEND1_PE_MARK),
- PINMUX_GPIO(GPIO_FN_DACK1_PD, DACK1_PD_MARK),
- PINMUX_GPIO(GPIO_FN_DACK1_PE, DACK1_PE_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1_PD, DREQ1_PD_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1_PE, DREQ1_PE_MARK),
- PINMUX_GPIO(GPIO_FN_DACK2, DACK2_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ2, DREQ2_MARK),
- PINMUX_GPIO(GPIO_FN_DACK3, DACK3_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ3, DREQ3_MARK),
-
- /* ADC */
- PINMUX_GPIO(GPIO_FN_ADTRG_PD, ADTRG_PD_MARK),
- PINMUX_GPIO(GPIO_FN_ADTRG_PE, ADTRG_PE_MARK),
-
- /* BSC */
- PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
- PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
- PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
- PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
- PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
- PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
- PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
- PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
- PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
- PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
- PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
- PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
- PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
- PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
- PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
- PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
- PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
- PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
- PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
- PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
- PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
- PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
- PINMUX_GPIO(GPIO_FN_MRES, MRES_MARK),
- PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
- PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
- PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
- PINMUX_GPIO(GPIO_FN_CS6_CE1B, CS6_CE1B_MARK),
- PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
- PINMUX_GPIO(GPIO_FN_CS5_CE1A, CS5_CE1A_MARK),
- PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
- PINMUX_GPIO(GPIO_FN_FRAME, FRAME_MARK),
- PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
- PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
- PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
- PINMUX_GPIO(GPIO_FN_CASU, CASU_MARK),
- PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
- PINMUX_GPIO(GPIO_FN_RASU, RASU_MARK),
- PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
- PINMUX_GPIO(GPIO_FN_CASL, CASL_MARK),
- PINMUX_GPIO(GPIO_FN_RASL, RASL_MARK),
- PINMUX_GPIO(GPIO_FN_WE3_DQMUU_AH_ICIO_WR, WE3_DQMUU_AH_ICIO_WR_MARK),
- PINMUX_GPIO(GPIO_FN_WE2_DQMUL_ICIORD, WE2_DQMUL_ICIORD_MARK),
- PINMUX_GPIO(GPIO_FN_WE1_DQMLU_WE, WE1_DQMLU_WE_MARK),
- PINMUX_GPIO(GPIO_FN_WE0_DQMLL, WE0_DQMLL_MARK),
- PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
- PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
- PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
- PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
- PINMUX_GPIO(GPIO_FN_CS7, CS7_MARK),
-
- /* TMU */
- PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKD_PD, TCLKD_PD_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKC_PD, TCLKC_PD_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKB_PD, TCLKB_PD_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKA_PD, TCLKA_PD_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKD_PF, TCLKD_PF_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKC_PF, TCLKC_PF_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKB_PF, TCLKB_PF_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKA_PF, TCLKA_PF_MARK),
-
- /* SSU */
- PINMUX_GPIO(GPIO_FN_SCS0_PD, SCS0_PD_MARK),
- PINMUX_GPIO(GPIO_FN_SSO0_PD, SSO0_PD_MARK),
- PINMUX_GPIO(GPIO_FN_SSI0_PD, SSI0_PD_MARK),
- PINMUX_GPIO(GPIO_FN_SSCK0_PD, SSCK0_PD_MARK),
- PINMUX_GPIO(GPIO_FN_SCS0_PF, SCS0_PF_MARK),
- PINMUX_GPIO(GPIO_FN_SSO0_PF, SSO0_PF_MARK),
- PINMUX_GPIO(GPIO_FN_SSI0_PF, SSI0_PF_MARK),
- PINMUX_GPIO(GPIO_FN_SSCK0_PF, SSCK0_PF_MARK),
- PINMUX_GPIO(GPIO_FN_SCS1_PD, SCS1_PD_MARK),
- PINMUX_GPIO(GPIO_FN_SSO1_PD, SSO1_PD_MARK),
- PINMUX_GPIO(GPIO_FN_SSI1_PD, SSI1_PD_MARK),
- PINMUX_GPIO(GPIO_FN_SSCK1_PD, SSCK1_PD_MARK),
- PINMUX_GPIO(GPIO_FN_SCS1_PF, SCS1_PF_MARK),
- PINMUX_GPIO(GPIO_FN_SSO1_PF, SSO1_PF_MARK),
- PINMUX_GPIO(GPIO_FN_SSI1_PF, SSI1_PF_MARK),
- PINMUX_GPIO(GPIO_FN_SSCK1_PF, SSCK1_PF_MARK),
-
- /* SCIF */
- PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
- PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
- PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
- PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
- PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
- PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
- PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
- PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
- PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
- PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
-
- /* SSI */
- PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
- PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
- PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
- PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
- PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
- PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
- PINMUX_GPIO(GPIO_FN_SSIDATA0, SSIDATA0_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
- PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
-
- /* FLCTL */
- PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
- PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
- PINMUX_GPIO(GPIO_FN_NAF7, NAF7_MARK),
- PINMUX_GPIO(GPIO_FN_NAF6, NAF6_MARK),
- PINMUX_GPIO(GPIO_FN_NAF5, NAF5_MARK),
- PINMUX_GPIO(GPIO_FN_NAF4, NAF4_MARK),
- PINMUX_GPIO(GPIO_FN_NAF3, NAF3_MARK),
- PINMUX_GPIO(GPIO_FN_NAF2, NAF2_MARK),
- PINMUX_GPIO(GPIO_FN_NAF1, NAF1_MARK),
- PINMUX_GPIO(GPIO_FN_NAF0, NAF0_MARK),
- PINMUX_GPIO(GPIO_FN_FSC, FSC_MARK),
- PINMUX_GPIO(GPIO_FN_FOE, FOE_MARK),
- PINMUX_GPIO(GPIO_FN_FCDE, FCDE_MARK),
- PINMUX_GPIO(GPIO_FN_FWE, FWE_MARK),
-
- /* LCDC */
- PINMUX_GPIO(GPIO_FN_LCD_VEPWC, LCD_VEPWC_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_VCPWC, LCD_VCPWC_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_FLM, LCD_FLM_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_CL2, LCD_CL2_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_CL1, LCD_CL1_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DON, LCD_DON_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
-};
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- { PINMUX_CFG_REG("PBIORL", 0xfffe3886, 16, 1) {
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- PB11_IN, PB11_OUT,
- PB10_IN, PB10_OUT,
- PB9_IN, PB9_OUT,
- PB8_IN, PB8_OUT,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0 }
- },
- { PINMUX_CFG_REG("PBCRL4", 0xfffe3890, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCRL3", 0xfffe3892, 16, 4) {
- PB11MD_0, PB11MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB10MD_0, PB10MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB9MD_00, PB9MD_01, PB9MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB8MD_00, PB8MD_01, PB8MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCRL2", 0xfffe3894, 16, 4) {
- PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCRL1", 0xfffe3896, 16, 4) {
- PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB0MD_00, PB0MD_01, PB0MD_10, PB0MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("IFCR", 0xfffe38a2, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB12IRQ_00, PB12IRQ_01, PB12IRQ_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PCIORL", 0xfffe3906, 16, 1) {
- 0, 0,
- PC14_IN, PC14_OUT,
- PC13_IN, PC13_OUT,
- PC12_IN, PC12_OUT,
- PC11_IN, PC11_OUT,
- PC10_IN, PC10_OUT,
- PC9_IN, PC9_OUT,
- PC8_IN, PC8_OUT,
- PC7_IN, PC7_OUT,
- PC6_IN, PC6_OUT,
- PC5_IN, PC5_OUT,
- PC4_IN, PC4_OUT,
- PC3_IN, PC3_OUT,
- PC2_IN, PC2_OUT,
- PC1_IN, PC1_OUT,
- PC0_IN, PC0_OUT }
- },
- { PINMUX_CFG_REG("PCCRL4", 0xfffe3910, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC14MD_0, PC14MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC13MD_0, PC13MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC12MD_0, PC12MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PCCRL3", 0xfffe3912, 16, 4) {
- PC11MD_00, PC11MD_01, PC11MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC10MD_00, PC10MD_01, PC10MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC9MD_0, PC9MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC8MD_0, PC8MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PCCRL2", 0xfffe3914, 16, 4) {
- PC7MD_0, PC7MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC6MD_0, PC6MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC5MD_0, PC5MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC4MD_0, PC4MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PCCRL1", 0xfffe3916, 16, 4) {
- PC3MD_0, PC3MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC2MD_0, PC2MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC1MD_0, PC1MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC0MD_00, PC0MD_01, PC0MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PDIORL", 0xfffe3986, 16, 1) {
- PD15_IN, PD15_OUT,
- PD14_IN, PD14_OUT,
- PD13_IN, PD13_OUT,
- PD12_IN, PD12_OUT,
- PD11_IN, PD11_OUT,
- PD10_IN, PD10_OUT,
- PD9_IN, PD9_OUT,
- PD8_IN, PD8_OUT,
- PD7_IN, PD7_OUT,
- PD6_IN, PD6_OUT,
- PD5_IN, PD5_OUT,
- PD4_IN, PD4_OUT,
- PD3_IN, PD3_OUT,
- PD2_IN, PD2_OUT,
- PD1_IN, PD1_OUT,
- PD0_IN, PD0_OUT }
- },
- { PINMUX_CFG_REG("PDCRL4", 0xfffe3990, 16, 4) {
- PD15MD_000, PD15MD_001, PD15MD_010, 0,
- PD15MD_100, PD15MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD14MD_000, PD14MD_001, PD14MD_010, 0,
- 0, PD14MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD13MD_000, PD13MD_001, PD13MD_010, 0,
- PD13MD_100, PD13MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD12MD_000, PD12MD_001, PD12MD_010, 0,
- PD12MD_100, PD12MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PDCRL3", 0xfffe3992, 16, 4) {
- PD11MD_000, PD11MD_001, PD11MD_010, 0,
- PD11MD_100, PD11MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD10MD_000, PD10MD_001, PD10MD_010, 0,
- PD10MD_100, PD10MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD9MD_000, PD9MD_001, PD9MD_010, 0,
- PD9MD_100, PD9MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD8MD_000, PD8MD_001, PD8MD_010, 0,
- PD8MD_100, PD8MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PDCRL2", 0xfffe3994, 16, 4) {
- PD7MD_000, PD7MD_001, PD7MD_010, PD7MD_011,
- PD7MD_100, PD7MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD6MD_000, PD6MD_001, PD6MD_010, PD6MD_011,
- PD6MD_100, PD6MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD5MD_000, PD5MD_001, PD5MD_010, PD5MD_011,
- PD5MD_100, PD5MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD4MD_000, PD4MD_001, PD4MD_010, PD4MD_011,
- PD4MD_100, PD4MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PDCRL1", 0xfffe3996, 16, 4) {
- PD3MD_000, PD3MD_001, PD3MD_010, PD3MD_011,
- PD3MD_100, PD3MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD2MD_000, PD2MD_001, PD2MD_010, PD2MD_011,
- PD2MD_100, PD2MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD1MD_000, PD1MD_001, PD1MD_010, PD1MD_011,
- PD1MD_100, PD1MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD0MD_000, PD0MD_001, PD0MD_010, PD0MD_011,
- PD0MD_100, PD0MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PEIORL", 0xfffe3a06, 16, 1) {
- PE15_IN, PE15_OUT,
- PE14_IN, PE14_OUT,
- PE13_IN, PE13_OUT,
- PE12_IN, PE12_OUT,
- PE11_IN, PE11_OUT,
- PE10_IN, PE10_OUT,
- PE9_IN, PE9_OUT,
- PE8_IN, PE8_OUT,
- PE7_IN, PE7_OUT,
- PE6_IN, PE6_OUT,
- PE5_IN, PE5_OUT,
- PE4_IN, PE4_OUT,
- PE3_IN, PE3_OUT,
- PE2_IN, PE2_OUT,
- PE1_IN, PE1_OUT,
- PE0_IN, PE0_OUT }
- },
- { PINMUX_CFG_REG("PECRL4", 0xfffe3a10, 16, 4) {
- PE15MD_00, PE15MD_01, 0, PE15MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE14MD_00, PE14MD_01, 0, PE14MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE13MD_00, 0, 0, PE13MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE12MD_00, 0, 0, PE12MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PECRL3", 0xfffe3a12, 16, 4) {
- PE11MD_000, PE11MD_001, PE11MD_010, 0,
- PE11MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE10MD_000, PE10MD_001, PE10MD_010, 0,
- PE10MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE9MD_00, PE9MD_01, PE9MD_10, PE9MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE8MD_00, PE8MD_01, PE8MD_10, PE8MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PECRL2", 0xfffe3a14, 16, 4) {
- PE7MD_000, PE7MD_001, PE7MD_010, PE7MD_011,
- PE7MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE6MD_000, PE6MD_001, PE6MD_010, PE6MD_011,
- PE6MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE5MD_000, PE5MD_001, PE5MD_010, PE5MD_011,
- PE5MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE4MD_000, PE4MD_001, PE4MD_010, PE4MD_011,
- PE4MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PECRL1", 0xfffe3a16, 16, 4) {
- PE3MD_00, PE3MD_01, 0, PE3MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE2MD_00, PE2MD_01, 0, PE2MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE1MD_00, PE1MD_01, PE1MD_10, PE1MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE0MD_000, PE0MD_001, 0, PE0MD_011,
- PE0MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFIORH", 0xfffe3a84, 16, 1) {
- 0, 0,
- PF30_IN, PF30_OUT,
- PF29_IN, PF29_OUT,
- PF28_IN, PF28_OUT,
- PF27_IN, PF27_OUT,
- PF26_IN, PF26_OUT,
- PF25_IN, PF25_OUT,
- PF24_IN, PF24_OUT,
- PF23_IN, PF23_OUT,
- PF22_IN, PF22_OUT,
- PF21_IN, PF21_OUT,
- PF20_IN, PF20_OUT,
- PF19_IN, PF19_OUT,
- PF18_IN, PF18_OUT,
- PF17_IN, PF17_OUT,
- PF16_IN, PF16_OUT }
- },
- { PINMUX_CFG_REG("PFIORL", 0xfffe3a86, 16, 1) {
- PF15_IN, PF15_OUT,
- PF14_IN, PF14_OUT,
- PF13_IN, PF13_OUT,
- PF12_IN, PF12_OUT,
- PF11_IN, PF11_OUT,
- PF10_IN, PF10_OUT,
- PF9_IN, PF9_OUT,
- PF8_IN, PF8_OUT,
- PF7_IN, PF7_OUT,
- PF6_IN, PF6_OUT,
- PF5_IN, PF5_OUT,
- PF4_IN, PF4_OUT,
- PF3_IN, PF3_OUT,
- PF2_IN, PF2_OUT,
- PF1_IN, PF1_OUT,
- PF0_IN, PF0_OUT }
- },
- { PINMUX_CFG_REG("PFCRH4", 0xfffe3a88, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF30MD_0, PF30MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF29MD_0, PF29MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF28MD_0, PF28MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCRH3", 0xfffe3a8a, 16, 4) {
- PF27MD_0, PF27MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF26MD_0, PF26MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF25MD_0, PF25MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF24MD_0, PF24MD_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCRH2", 0xfffe3a8c, 16, 4) {
- PF23MD_00, PF23MD_01, PF23MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF22MD_00, PF22MD_01, PF22MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF21MD_00, PF21MD_01, PF21MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF20MD_00, PF20MD_01, PF20MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCRH1", 0xfffe3a8e, 16, 4) {
- PF19MD_00, PF19MD_01, PF19MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF18MD_00, PF18MD_01, PF18MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF17MD_00, PF17MD_01, PF17MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF16MD_00, PF16MD_01, PF16MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCRL4", 0xfffe3a90, 16, 4) {
- PF15MD_00, PF15MD_01, PF15MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF14MD_00, PF14MD_01, PF14MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF13MD_00, PF13MD_01, PF13MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF12MD_00, PF12MD_01, PF12MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCRL3", 0xfffe3a92, 16, 4) {
- PF11MD_00, PF11MD_01, PF11MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF10MD_00, PF10MD_01, PF10MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF9MD_00, PF9MD_01, PF9MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF8MD_00, PF8MD_01, PF8MD_10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCRL2", 0xfffe3a94, 16, 4) {
- PF7MD_00, PF7MD_01, PF7MD_10, PF7MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF6MD_00, PF6MD_01, PF6MD_10, PF6MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF5MD_00, PF5MD_01, PF5MD_10, PF5MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF4MD_00, PF4MD_01, PF4MD_10, PF4MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCRL1", 0xfffe3a96, 16, 4) {
- PF3MD_00, PF3MD_01, PF3MD_10, PF3MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF2MD_00, PF2MD_01, PF2MD_10, PF2MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF1MD_00, PF1MD_01, PF1MD_10, PF1MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF0MD_00, PF0MD_01, PF0MD_10, PF0MD_11,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- {}
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PADRL", 0xfffe3802, 16) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
- PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA }
- },
- { PINMUX_DATA_REG("PBDRL", 0xfffe3882, 16) {
- 0, 0, 0, PB12_DATA,
- PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA }
- },
- { PINMUX_DATA_REG("PCDRL", 0xfffe3902, 16) {
- 0, PC14_DATA, PC13_DATA, PC12_DATA,
- PC11_DATA, PC10_DATA, PC9_DATA, PC8_DATA,
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
- },
- { PINMUX_DATA_REG("PDDRL", 0xfffe3982, 16) {
- PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
- PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
- },
- { PINMUX_DATA_REG("PEDRL", 0xfffe3a02, 16) {
- PE15_DATA, PE14_DATA, PE13_DATA, PE12_DATA,
- PE11_DATA, PE10_DATA, PE9_DATA, PE8_DATA,
- PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
- PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
- },
- { PINMUX_DATA_REG("PFDRH", 0xfffe3a80, 16) {
- 0, PF30_DATA, PF29_DATA, PF28_DATA,
- PF27_DATA, PF26_DATA, PF25_DATA, PF24_DATA,
- PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
- PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA }
- },
- { PINMUX_DATA_REG("PFDRL", 0xfffe3a82, 16) {
- PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
- PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
- },
- { },
-};
-
-static struct pinmux_info sh7203_pinmux_info = {
- .name = "sh7203_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_PA7,
- .last_gpio = GPIO_FN_LCD_DATA0,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
+#include <cpu/pfc.h>
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7203_pinmux_info);
+ return sh_pfc_register("pfc-sh7203", NULL, 0);
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c b/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c
index b055b55d6f27..b1b7c1bae127 100644
--- a/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c
+++ b/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c
@@ -10,2127 +10,10 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/sh7264.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- /* Port A */
- PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
- /* Port B */
- PB22_DATA, PB21_DATA, PB20_DATA,
- PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA,
- PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
- PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA,
- /* Port C */
- PC10_DATA, PC9_DATA, PC8_DATA,
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
- /* Port D */
- PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
- PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
- /* Port E */
- PE5_DATA, PE4_DATA,
- PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
- /* Port F */
- PF12_DATA,
- PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
- /* Port G */
- PG24_DATA,
- PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
- PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA,
- PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
- PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
- PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
- PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
- /* Port H */
- /* NOTE - Port H does not have a Data Register, but PH Data is
- connected to PH Port Register */
- PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
- PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
- /* Port I - not on device */
- /* Port J */
- PJ12_DATA,
- PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
- PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
- PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
- /* Port K */
- PK12_DATA,
- PK11_DATA, PK10_DATA, PK9_DATA, PK8_DATA,
- PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
- PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- FORCE_IN,
- /* Port A */
- PA3_IN, PA2_IN, PA1_IN, PA0_IN,
- /* Port B */
- PB22_IN, PB21_IN, PB20_IN,
- PB19_IN, PB18_IN, PB17_IN, PB16_IN,
- PB15_IN, PB14_IN, PB13_IN, PB12_IN,
- PB11_IN, PB10_IN, PB9_IN, PB8_IN,
- PB7_IN, PB6_IN, PB5_IN, PB4_IN,
- PB3_IN, PB2_IN, PB1_IN,
- /* Port C */
- PC10_IN, PC9_IN, PC8_IN,
- PC7_IN, PC6_IN, PC5_IN, PC4_IN,
- PC3_IN, PC2_IN, PC1_IN, PC0_IN,
- /* Port D */
- PD15_IN, PD14_IN, PD13_IN, PD12_IN,
- PD11_IN, PD10_IN, PD9_IN, PD8_IN,
- PD7_IN, PD6_IN, PD5_IN, PD4_IN,
- PD3_IN, PD2_IN, PD1_IN, PD0_IN,
- /* Port E */
- PE5_IN, PE4_IN,
- PE3_IN, PE2_IN, PE1_IN, PE0_IN,
- /* Port F */
- PF12_IN,
- PF11_IN, PF10_IN, PF9_IN, PF8_IN,
- PF7_IN, PF6_IN, PF5_IN, PF4_IN,
- PF3_IN, PF2_IN, PF1_IN, PF0_IN,
- /* Port G */
- PG24_IN,
- PG23_IN, PG22_IN, PG21_IN, PG20_IN,
- PG19_IN, PG18_IN, PG17_IN, PG16_IN,
- PG15_IN, PG14_IN, PG13_IN, PG12_IN,
- PG11_IN, PG10_IN, PG9_IN, PG8_IN,
- PG7_IN, PG6_IN, PG5_IN, PG4_IN,
- PG3_IN, PG2_IN, PG1_IN, PG0_IN,
- /* Port H - Port H does not have a Data Register */
- /* Port I - not on device */
- /* Port J */
- PJ12_IN,
- PJ11_IN, PJ10_IN, PJ9_IN, PJ8_IN,
- PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
- PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
- /* Port K */
- PK12_IN,
- PK11_IN, PK10_IN, PK9_IN, PK8_IN,
- PK7_IN, PK6_IN, PK5_IN, PK4_IN,
- PK3_IN, PK2_IN, PK1_IN, PK0_IN,
- PINMUX_INPUT_END,
-
- PINMUX_OUTPUT_BEGIN,
- FORCE_OUT,
- /* Port A */
- PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
- /* Port B */
- PB22_OUT, PB21_OUT, PB20_OUT,
- PB19_OUT, PB18_OUT, PB17_OUT, PB16_OUT,
- PB15_OUT, PB14_OUT, PB13_OUT, PB12_OUT,
- PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
- PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
- PB3_OUT, PB2_OUT, PB1_OUT,
- /* Port C */
- PC10_OUT, PC9_OUT, PC8_OUT,
- PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
- PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
- /* Port D */
- PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
- PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
- PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
- PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
- /* Port E */
- PE5_OUT, PE4_OUT,
- PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
- /* Port F */
- PF12_OUT,
- PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
- PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
- PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
- /* Port G */
- PG24_OUT,
- PG23_OUT, PG22_OUT, PG21_OUT, PG20_OUT,
- PG19_OUT, PG18_OUT, PG17_OUT, PG16_OUT,
- PG15_OUT, PG14_OUT, PG13_OUT, PG12_OUT,
- PG11_OUT, PG10_OUT, PG9_OUT, PG8_OUT,
- PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
- PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
- /* Port H - Port H does not have a Data Register */
- /* Port I - not on device */
- /* Port J */
- PJ12_OUT,
- PJ11_OUT, PJ10_OUT, PJ9_OUT, PJ8_OUT,
- PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
- PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
- /* Port K */
- PK12_OUT,
- PK11_OUT, PK10_OUT, PK9_OUT, PK8_OUT,
- PK7_OUT, PK6_OUT, PK5_OUT, PK4_OUT,
- PK3_OUT, PK2_OUT, PK1_OUT, PK0_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- /* Port A */
- PA3_IOR_IN, PA3_IOR_OUT,
- PA2_IOR_IN, PA2_IOR_OUT,
- PA1_IOR_IN, PA1_IOR_OUT,
- PA0_IOR_IN, PA0_IOR_OUT,
-
- /* Port B */
- PB11_IOR_IN, PB11_IOR_OUT,
- PB10_IOR_IN, PB10_IOR_OUT,
- PB9_IOR_IN, PB9_IOR_OUT,
- PB8_IOR_IN, PB8_IOR_OUT,
-
- PB22MD_00, PB22MD_01, PB22MD_10,
- PB21MD_0, PB21MD_1,
- PB20MD_0, PB20MD_1,
- PB19MD_00, PB19MD_01, PB19MD_10, PB19MD_11,
- PB18MD_00, PB18MD_01, PB18MD_10, PB18MD_11,
- PB17MD_00, PB17MD_01, PB17MD_10, PB17MD_11,
- PB16MD_00, PB16MD_01, PB16MD_10, PB16MD_11,
- PB15MD_00, PB15MD_01, PB15MD_10, PB15MD_11,
- PB14MD_00, PB14MD_01, PB14MD_10, PB14MD_11,
- PB13MD_00, PB13MD_01, PB13MD_10, PB13MD_11,
- PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
- PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11,
- PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11,
- PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11,
- PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11,
- PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
- PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
- PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
- PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
- PB3MD_0, PB3MD_1,
- PB2MD_0, PB2MD_1,
- PB1MD_0, PB1MD_1,
-
- /* Port C */
- PC14_IOR_IN, PC14_IOR_OUT,
- PC13_IOR_IN, PC13_IOR_OUT,
- PC12_IOR_IN, PC12_IOR_OUT,
- PC11_IOR_IN, PC11_IOR_OUT,
- PC10_IOR_IN, PC10_IOR_OUT,
- PC9_IOR_IN, PC9_IOR_OUT,
- PC8_IOR_IN, PC8_IOR_OUT,
- PC7_IOR_IN, PC7_IOR_OUT,
- PC6_IOR_IN, PC6_IOR_OUT,
- PC5_IOR_IN, PC5_IOR_OUT,
- PC4_IOR_IN, PC4_IOR_OUT,
- PC3_IOR_IN, PC3_IOR_OUT,
- PC2_IOR_IN, PC2_IOR_OUT,
- PC1_IOR_IN, PC1_IOR_OUT,
- PC0_IOR_IN, PC0_IOR_OUT,
-
- PC10MD_0, PC10MD_1,
- PC9MD_0, PC9MD_1,
- PC8MD_00, PC8MD_01, PC8MD_10, PC8MD_11,
- PC7MD_00, PC7MD_01, PC7MD_10, PC7MD_11,
- PC6MD_00, PC6MD_01, PC6MD_10, PC6MD_11,
- PC5MD_00, PC5MD_01, PC5MD_10, PC5MD_11,
- PC4MD_0, PC4MD_1,
- PC3MD_0, PC3MD_1,
- PC2MD_0, PC2MD_1,
- PC1MD_0, PC1MD_1,
- PC0MD_0, PC0MD_1,
-
- /* Port D */
- PD15_IOR_IN, PD15_IOR_OUT,
- PD14_IOR_IN, PD14_IOR_OUT,
- PD13_IOR_IN, PD13_IOR_OUT,
- PD12_IOR_IN, PD12_IOR_OUT,
- PD11_IOR_IN, PD11_IOR_OUT,
- PD10_IOR_IN, PD10_IOR_OUT,
- PD9_IOR_IN, PD9_IOR_OUT,
- PD8_IOR_IN, PD8_IOR_OUT,
- PD7_IOR_IN, PD7_IOR_OUT,
- PD6_IOR_IN, PD6_IOR_OUT,
- PD5_IOR_IN, PD5_IOR_OUT,
- PD4_IOR_IN, PD4_IOR_OUT,
- PD3_IOR_IN, PD3_IOR_OUT,
- PD2_IOR_IN, PD2_IOR_OUT,
- PD1_IOR_IN, PD1_IOR_OUT,
- PD0_IOR_IN, PD0_IOR_OUT,
-
- PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11,
- PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11,
- PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11,
- PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11,
- PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11,
- PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11,
- PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11,
- PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11,
- PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11,
- PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11,
- PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11,
- PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11,
- PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11,
- PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11,
- PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11,
- PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11,
-
- /* Port E */
- PE5_IOR_IN, PE5_IOR_OUT,
- PE4_IOR_IN, PE4_IOR_OUT,
- PE3_IOR_IN, PE3_IOR_OUT,
- PE2_IOR_IN, PE2_IOR_OUT,
- PE1_IOR_IN, PE1_IOR_OUT,
- PE0_IOR_IN, PE0_IOR_OUT,
-
- PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11,
- PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11,
- PE3MD_00, PE3MD_01, PE3MD_10, PE3MD_11,
- PE2MD_00, PE2MD_01, PE2MD_10, PE2MD_11,
- PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
- PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
- PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11,
-
- /* Port F */
- PF12_IOR_IN, PF12_IOR_OUT,
- PF11_IOR_IN, PF11_IOR_OUT,
- PF10_IOR_IN, PF10_IOR_OUT,
- PF9_IOR_IN, PF9_IOR_OUT,
- PF8_IOR_IN, PF8_IOR_OUT,
- PF7_IOR_IN, PF7_IOR_OUT,
- PF6_IOR_IN, PF6_IOR_OUT,
- PF5_IOR_IN, PF5_IOR_OUT,
- PF4_IOR_IN, PF4_IOR_OUT,
- PF3_IOR_IN, PF3_IOR_OUT,
- PF2_IOR_IN, PF2_IOR_OUT,
- PF1_IOR_IN, PF1_IOR_OUT,
- PF0_IOR_IN, PF0_IOR_OUT,
-
- PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
- PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
- PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
- PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
- PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
- PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
- PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
- PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
- PF8MD_00, PF8MD_01, PF8MD_10, PF8MD_11,
- PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
- PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
- PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
- PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
- PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
- PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
- PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
- PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
- PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
- PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
- PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
- PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
- PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
- PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
- PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
- PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
-
- /* Port G */
- PG24_IOR_IN, PG24_IOR_OUT,
- PG23_IOR_IN, PG23_IOR_OUT,
- PG22_IOR_IN, PG22_IOR_OUT,
- PG21_IOR_IN, PG21_IOR_OUT,
- PG20_IOR_IN, PG20_IOR_OUT,
- PG19_IOR_IN, PG19_IOR_OUT,
- PG18_IOR_IN, PG18_IOR_OUT,
- PG17_IOR_IN, PG17_IOR_OUT,
- PG16_IOR_IN, PG16_IOR_OUT,
- PG15_IOR_IN, PG15_IOR_OUT,
- PG14_IOR_IN, PG14_IOR_OUT,
- PG13_IOR_IN, PG13_IOR_OUT,
- PG12_IOR_IN, PG12_IOR_OUT,
- PG11_IOR_IN, PG11_IOR_OUT,
- PG10_IOR_IN, PG10_IOR_OUT,
- PG9_IOR_IN, PG9_IOR_OUT,
- PG8_IOR_IN, PG8_IOR_OUT,
- PG7_IOR_IN, PG7_IOR_OUT,
- PG6_IOR_IN, PG6_IOR_OUT,
- PG5_IOR_IN, PG5_IOR_OUT,
- PG4_IOR_IN, PG4_IOR_OUT,
- PG3_IOR_IN, PG3_IOR_OUT,
- PG2_IOR_IN, PG2_IOR_OUT,
- PG1_IOR_IN, PG1_IOR_OUT,
- PG0_IOR_IN, PG0_IOR_OUT,
-
- PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11,
- PG23MD_00, PG23MD_01, PG23MD_10, PG23MD_11,
- PG22MD_00, PG22MD_01, PG22MD_10, PG22MD_11,
- PG21MD_00, PG21MD_01, PG21MD_10, PG21MD_11,
- PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
- PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
- PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
- PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
- PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
- PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
- PG17MD_000, PG17MD_001, PG17MD_010, PG17MD_011,
- PG17MD_100, PG17MD_101, PG17MD_110, PG17MD_111,
- PG16MD_000, PG16MD_001, PG16MD_010, PG16MD_011,
- PG16MD_100, PG16MD_101, PG16MD_110, PG16MD_111,
- PG15MD_000, PG15MD_001, PG15MD_010, PG15MD_011,
- PG15MD_100, PG15MD_101, PG15MD_110, PG15MD_111,
- PG14MD_000, PG14MD_001, PG14MD_010, PG14MD_011,
- PG14MD_100, PG14MD_101, PG14MD_110, PG14MD_111,
- PG13MD_000, PG13MD_001, PG13MD_010, PG13MD_011,
- PG13MD_100, PG13MD_101, PG13MD_110, PG13MD_111,
- PG12MD_000, PG12MD_001, PG12MD_010, PG12MD_011,
- PG12MD_100, PG12MD_101, PG12MD_110, PG12MD_111,
- PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
- PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
- PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
- PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
- PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
- PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
- PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
- PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
- PG7MD_00, PG7MD_01, PG7MD_10, PG7MD_11,
- PG6MD_00, PG6MD_01, PG6MD_10, PG6MD_11,
- PG5MD_00, PG5MD_01, PG5MD_10, PG5MD_11,
- PG4MD_00, PG4MD_01, PG4MD_10, PG4MD_11,
- PG3MD_00, PG3MD_01, PG3MD_10, PG3MD_11,
- PG2MD_00, PG2MD_01, PG2MD_10, PG2MD_11,
- PG1MD_00, PG1MD_01, PG1MD_10, PG1MD_11,
- PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
- PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
-
- /* Port H */
- PH7MD_0, PH7MD_1,
- PH6MD_0, PH6MD_1,
- PH5MD_0, PH5MD_1,
- PH4MD_0, PH4MD_1,
- PH3MD_0, PH3MD_1,
- PH2MD_0, PH2MD_1,
- PH1MD_0, PH1MD_1,
- PH0MD_0, PH0MD_1,
-
- /* Port I - not on device */
-
- /* Port J */
- PJ11_IOR_IN, PJ11_IOR_OUT,
- PJ10_IOR_IN, PJ10_IOR_OUT,
- PJ9_IOR_IN, PJ9_IOR_OUT,
- PJ8_IOR_IN, PJ8_IOR_OUT,
- PJ7_IOR_IN, PJ7_IOR_OUT,
- PJ6_IOR_IN, PJ6_IOR_OUT,
- PJ5_IOR_IN, PJ5_IOR_OUT,
- PJ4_IOR_IN, PJ4_IOR_OUT,
- PJ3_IOR_IN, PJ3_IOR_OUT,
- PJ2_IOR_IN, PJ2_IOR_OUT,
- PJ1_IOR_IN, PJ1_IOR_OUT,
- PJ0_IOR_IN, PJ0_IOR_OUT,
-
- PJ11MD_00, PJ11MD_01, PJ11MD_10, PJ11MD_11,
- PJ10MD_00, PJ10MD_01, PJ10MD_10, PJ10MD_11,
- PJ9MD_00, PJ9MD_01, PJ9MD_10, PJ9MD_11,
- PJ8MD_00, PJ8MD_01, PJ8MD_10, PJ8MD_11,
- PJ7MD_00, PJ7MD_01, PJ7MD_10, PJ7MD_11,
- PJ6MD_00, PJ6MD_01, PJ6MD_10, PJ6MD_11,
- PJ5MD_00, PJ5MD_01, PJ5MD_10, PJ5MD_11,
- PJ4MD_00, PJ4MD_01, PJ4MD_10, PJ4MD_11,
- PJ3MD_00, PJ3MD_01, PJ3MD_10, PJ3MD_11,
- PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
- PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
- PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
- PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
- PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
- PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
-
- /* Port K */
- PK11_IOR_IN, PK11_IOR_OUT,
- PK10_IOR_IN, PK10_IOR_OUT,
- PK9_IOR_IN, PK9_IOR_OUT,
- PK8_IOR_IN, PK8_IOR_OUT,
- PK7_IOR_IN, PK7_IOR_OUT,
- PK6_IOR_IN, PK6_IOR_OUT,
- PK5_IOR_IN, PK5_IOR_OUT,
- PK4_IOR_IN, PK4_IOR_OUT,
- PK3_IOR_IN, PK3_IOR_OUT,
- PK2_IOR_IN, PK2_IOR_OUT,
- PK1_IOR_IN, PK1_IOR_OUT,
- PK0_IOR_IN, PK0_IOR_OUT,
-
- PK11MD_00, PK11MD_01, PK11MD_10, PK11MD_11,
- PK10MD_00, PK10MD_01, PK10MD_10, PK10MD_11,
- PK9MD_00, PK9MD_01, PK9MD_10, PK9MD_11,
- PK8MD_00, PK8MD_01, PK8MD_10, PK8MD_11,
- PK7MD_00, PK7MD_01, PK7MD_10, PK7MD_11,
- PK6MD_00, PK6MD_01, PK6MD_10, PK6MD_11,
- PK5MD_00, PK5MD_01, PK5MD_10, PK5MD_11,
- PK4MD_00, PK4MD_01, PK4MD_10, PK4MD_11,
- PK3MD_00, PK3MD_01, PK3MD_10, PK3MD_11,
- PK2MD_00, PK2MD_01, PK2MD_10, PK2MD_11,
- PK1MD_00, PK1MD_01, PK1MD_10, PK1MD_11,
- PK0MD_00, PK0MD_01, PK0MD_10, PK0MD_11,
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
- /* Port A */
-
- /* Port B */
-
- /* Port C */
-
- /* Port D */
-
- /* Port E */
-
- /* Port F */
-
- /* Port G */
-
- /* Port H */
- PHAN7_MARK, PHAN6_MARK, PHAN5_MARK, PHAN4_MARK,
- PHAN3_MARK, PHAN2_MARK, PHAN1_MARK, PHAN0_MARK,
-
- /* Port I - not on device */
-
- /* Port J */
-
- /* Port K */
-
- IRQ7_PC_MARK, IRQ6_PC_MARK, IRQ5_PC_MARK, IRQ4_PC_MARK,
- IRQ3_PG_MARK, IRQ2_PG_MARK, IRQ1_PJ_MARK, IRQ0_PJ_MARK,
- IRQ3_PE_MARK, IRQ2_PE_MARK, IRQ1_PE_MARK, IRQ0_PE_MARK,
-
- PINT7_PG_MARK, PINT6_PG_MARK, PINT5_PG_MARK, PINT4_PG_MARK,
- PINT3_PG_MARK, PINT2_PG_MARK, PINT1_PG_MARK, PINT0_PG_MARK,
-
- SD_CD_MARK, SD_D0_MARK, SD_D1_MARK, SD_D2_MARK, SD_D3_MARK,
- SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK,
- CRX0_MARK, CRX1_MARK,
- CTX0_MARK, CTX1_MARK,
-
- PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
- PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
- PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
- PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
- IERXD_MARK, IETXD_MARK,
- CRX0CRX1_MARK,
- WDTOVF_MARK,
-
- CRX0X1_MARK,
-
- /* DMAC */
- TEND0_MARK, DACK0_MARK, DREQ0_MARK,
- TEND1_MARK, DACK1_MARK, DREQ1_MARK,
-
- /* ADC */
- ADTRG_MARK,
-
- /* BSC */
- A25_MARK, A24_MARK,
- A23_MARK, A22_MARK, A21_MARK, A20_MARK,
- A19_MARK, A18_MARK, A17_MARK, A16_MARK,
- A15_MARK, A14_MARK, A13_MARK, A12_MARK,
- A11_MARK, A10_MARK, A9_MARK, A8_MARK,
- A7_MARK, A6_MARK, A5_MARK, A4_MARK,
- A3_MARK, A2_MARK, A1_MARK, A0_MARK,
- D15_MARK, D14_MARK, D13_MARK, D12_MARK,
- D11_MARK, D10_MARK, D9_MARK, D8_MARK,
- D7_MARK, D6_MARK, D5_MARK, D4_MARK,
- D3_MARK, D2_MARK, D1_MARK, D0_MARK,
- BS_MARK,
- CS4_MARK, CS3_MARK, CS2_MARK, CS1_MARK, CS0_MARK,
- CS6CE1B_MARK, CS5CE1A_MARK,
- CE2A_MARK, CE2B_MARK,
- RD_MARK, RDWR_MARK,
- ICIOWRAH_MARK,
- ICIORD_MARK,
- WE1DQMUWE_MARK,
- WE0DQML_MARK,
- RAS_MARK, CAS_MARK, CKE_MARK,
- WAIT_MARK, BREQ_MARK, BACK_MARK, IOIS16_MARK,
-
- /* TMU */
- TIOC0A_MARK, TIOC0B_MARK, TIOC0C_MARK, TIOC0D_MARK,
- TIOC1A_MARK, TIOC1B_MARK,
- TIOC2A_MARK, TIOC2B_MARK,
- TIOC3A_MARK, TIOC3B_MARK, TIOC3C_MARK, TIOC3D_MARK,
- TIOC4A_MARK, TIOC4B_MARK, TIOC4C_MARK, TIOC4D_MARK,
- TCLKA_MARK, TCLKB_MARK, TCLKC_MARK, TCLKD_MARK,
-
- /* SCIF */
- SCK0_MARK, SCK1_MARK, SCK2_MARK, SCK3_MARK,
- RXD0_MARK, RXD1_MARK, RXD2_MARK, RXD3_MARK,
- TXD0_MARK, TXD1_MARK, TXD2_MARK, TXD3_MARK,
- RXD4_MARK, RXD5_MARK, RXD6_MARK, RXD7_MARK,
- TXD4_MARK, TXD5_MARK, TXD6_MARK, TXD7_MARK,
- RTS1_MARK, RTS3_MARK,
- CTS1_MARK, CTS3_MARK,
-
- /* RSPI */
- RSPCK0_MARK, RSPCK1_MARK,
- MOSI0_MARK, MOSI1_MARK,
- MISO0_PF12_MARK, MISO1_MARK, MISO1_PG19_MARK,
- SSL00_MARK, SSL10_MARK,
-
- /* IIC3 */
- SCL0_MARK, SCL1_MARK, SCL2_MARK,
- SDA0_MARK, SDA1_MARK, SDA2_MARK,
-
- /* SSI */
- SSISCK0_MARK,
- SSIWS0_MARK,
- SSITXD0_MARK,
- SSIRXD0_MARK,
- SSIWS1_MARK, SSIWS2_MARK, SSIWS3_MARK,
- SSISCK1_MARK, SSISCK2_MARK, SSISCK3_MARK,
- SSIDATA1_MARK, SSIDATA2_MARK, SSIDATA3_MARK,
- AUDIO_CLK_MARK,
-
- /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
- SIOFTXD_MARK, SIOFRXD_MARK, SIOFSYNC_MARK, SIOFSCK_MARK,
-
- /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
- SPDIF_IN_MARK, SPDIF_OUT_MARK,
-
- /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
- FCE_MARK,
- FRB_MARK,
-
- /* VDC3 */
- DV_CLK_MARK,
- DV_VSYNC_MARK, DV_HSYNC_MARK,
- DV_DATA7_MARK, DV_DATA6_MARK, DV_DATA5_MARK, DV_DATA4_MARK,
- DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
- LCD_CLK_MARK, LCD_EXTCLK_MARK,
- LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
- LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
- LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
- LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
- LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
- LCD_M_DISP_MARK,
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
-
- /* Port A */
- PINMUX_DATA(PA3_DATA, PA3_IN),
- PINMUX_DATA(PA2_DATA, PA2_IN),
- PINMUX_DATA(PA1_DATA, PA1_IN),
- PINMUX_DATA(PA0_DATA, PA0_IN),
-
- /* Port B */
- PINMUX_DATA(PB22_DATA, PB22MD_00, PB22_IN, PB22_OUT),
- PINMUX_DATA(A22_MARK, PB22MD_01),
- PINMUX_DATA(CS4_MARK, PB22MD_10),
-
- PINMUX_DATA(PB21_DATA, PB21MD_0, PB21_IN, PB21_OUT),
- PINMUX_DATA(A21_MARK, PB21MD_1),
- PINMUX_DATA(A20_MARK, PB20MD_1),
- PINMUX_DATA(A19_MARK, PB19MD_01),
- PINMUX_DATA(A18_MARK, PB18MD_01),
- PINMUX_DATA(A17_MARK, PB17MD_01),
- PINMUX_DATA(A16_MARK, PB16MD_01),
- PINMUX_DATA(A15_MARK, PB15MD_01),
- PINMUX_DATA(A14_MARK, PB14MD_01),
- PINMUX_DATA(A13_MARK, PB13MD_01),
- PINMUX_DATA(A12_MARK, PB12MD_01),
- PINMUX_DATA(A11_MARK, PB11MD_01),
- PINMUX_DATA(A10_MARK, PB10MD_01),
- PINMUX_DATA(A9_MARK, PB9MD_01),
- PINMUX_DATA(A8_MARK, PB8MD_01),
- PINMUX_DATA(A7_MARK, PB7MD_01),
- PINMUX_DATA(A6_MARK, PB6MD_01),
- PINMUX_DATA(A5_MARK, PB5MD_01),
- PINMUX_DATA(A4_MARK, PB4MD_01),
- PINMUX_DATA(A3_MARK, PB3MD_1),
- PINMUX_DATA(A2_MARK, PB2MD_1),
- PINMUX_DATA(A1_MARK, PB1MD_1),
-
- /* Port C */
- PINMUX_DATA(PC10_DATA, PC10MD_0),
- PINMUX_DATA(TIOC2B_MARK, PC1MD_1),
- PINMUX_DATA(PC9_DATA, PC9MD_0),
- PINMUX_DATA(TIOC2A_MARK, PC9MD_1),
- PINMUX_DATA(PC8_DATA, PC8MD_00),
- PINMUX_DATA(CS3_MARK, PC8MD_01),
- PINMUX_DATA(TIOC4D_MARK, PC8MD_10),
- PINMUX_DATA(IRQ7_PC_MARK, PC8MD_11),
- PINMUX_DATA(PC7_DATA, PC7MD_00),
- PINMUX_DATA(CKE_MARK, PC7MD_01),
- PINMUX_DATA(TIOC4C_MARK, PC7MD_10),
- PINMUX_DATA(IRQ6_PC_MARK, PC7MD_11),
- PINMUX_DATA(PC6_DATA, PC6MD_00),
- PINMUX_DATA(CAS_MARK, PC6MD_01),
- PINMUX_DATA(TIOC4B_MARK, PC6MD_10),
- PINMUX_DATA(IRQ5_PC_MARK, PC6MD_11),
- PINMUX_DATA(PC5_DATA, PC5MD_00),
- PINMUX_DATA(RAS_MARK, PC5MD_01),
- PINMUX_DATA(TIOC4A_MARK, PC5MD_10),
- PINMUX_DATA(IRQ4_PC_MARK, PC5MD_11),
- PINMUX_DATA(PC4_DATA, PC4MD_0),
- PINMUX_DATA(WE1DQMUWE_MARK, PC4MD_1),
- PINMUX_DATA(PC3_DATA, PC3MD_0),
- PINMUX_DATA(WE0DQML_MARK, PC3MD_1),
- PINMUX_DATA(PC2_DATA, PC2MD_0),
- PINMUX_DATA(RDWR_MARK, PC2MD_1),
- PINMUX_DATA(PC1_DATA, PC1MD_0),
- PINMUX_DATA(RD_MARK, PC1MD_1),
- PINMUX_DATA(PC0_DATA, PC0MD_0),
- PINMUX_DATA(CS0_MARK, PC0MD_1),
-
- /* Port D */
- PINMUX_DATA(D15_MARK, PD15MD_01),
- PINMUX_DATA(D14_MARK, PD14MD_01),
- PINMUX_DATA(D13_MARK, PD13MD_01),
- PINMUX_DATA(D12_MARK, PD12MD_01),
- PINMUX_DATA(D11_MARK, PD11MD_01),
- PINMUX_DATA(D10_MARK, PD10MD_01),
- PINMUX_DATA(D9_MARK, PD9MD_01),
- PINMUX_DATA(D8_MARK, PD8MD_01),
- PINMUX_DATA(D7_MARK, PD7MD_01),
- PINMUX_DATA(D6_MARK, PD6MD_01),
- PINMUX_DATA(D5_MARK, PD5MD_01),
- PINMUX_DATA(D4_MARK, PD4MD_01),
- PINMUX_DATA(D3_MARK, PD3MD_01),
- PINMUX_DATA(D2_MARK, PD2MD_01),
- PINMUX_DATA(D1_MARK, PD1MD_01),
- PINMUX_DATA(D0_MARK, PD0MD_01),
-
- /* Port E */
- PINMUX_DATA(PE5_DATA, PE5MD_00),
- PINMUX_DATA(SDA2_MARK, PE5MD_01),
- PINMUX_DATA(DV_HSYNC_MARK, PE5MD_11),
-
- PINMUX_DATA(PE4_DATA, PE4MD_00),
- PINMUX_DATA(SCL2_MARK, PE4MD_01),
- PINMUX_DATA(DV_VSYNC_MARK, PE4MD_11),
-
- PINMUX_DATA(PE3_DATA, PE3MD_00),
- PINMUX_DATA(SDA1_MARK, PE3MD_01),
- PINMUX_DATA(IRQ3_PE_MARK, PE3MD_11),
-
- PINMUX_DATA(PE2_DATA, PE2MD_00),
- PINMUX_DATA(SCL1_MARK, PE2MD_01),
- PINMUX_DATA(IRQ2_PE_MARK, PE2MD_11),
-
- PINMUX_DATA(PE1_DATA, PE1MD_000),
- PINMUX_DATA(SDA0_MARK, PE1MD_001),
- PINMUX_DATA(IOIS16_MARK, PE1MD_010),
- PINMUX_DATA(IRQ1_PE_MARK, PE1MD_011),
- PINMUX_DATA(TCLKA_MARK, PE1MD_100),
- PINMUX_DATA(ADTRG_MARK, PE1MD_101),
-
- PINMUX_DATA(PE0_DATA, PE0MD_00),
- PINMUX_DATA(SCL0_MARK, PE0MD_01),
- PINMUX_DATA(AUDIO_CLK_MARK, PE0MD_10),
- PINMUX_DATA(IRQ0_PE_MARK, PE0MD_11),
-
- /* Port F */
- PINMUX_DATA(PF12_DATA, PF12MD_000),
- PINMUX_DATA(BS_MARK, PF12MD_001),
- PINMUX_DATA(MISO0_PF12_MARK, PF12MD_011),
- PINMUX_DATA(TIOC3D_MARK, PF12MD_100),
- PINMUX_DATA(SPDIF_OUT_MARK, PF12MD_101),
-
- PINMUX_DATA(PF11_DATA, PF11MD_000),
- PINMUX_DATA(A25_MARK, PF11MD_001),
- PINMUX_DATA(SSIDATA3_MARK, PF11MD_010),
- PINMUX_DATA(MOSI0_MARK, PF11MD_011),
- PINMUX_DATA(TIOC3C_MARK, PF11MD_100),
- PINMUX_DATA(SPDIF_IN_MARK, PF11MD_101),
-
- PINMUX_DATA(PF10_DATA, PF10MD_000),
- PINMUX_DATA(A24_MARK, PF10MD_001),
- PINMUX_DATA(SSIWS3_MARK, PF10MD_010),
- PINMUX_DATA(SSL00_MARK, PF10MD_011),
- PINMUX_DATA(TIOC3B_MARK, PF10MD_100),
- PINMUX_DATA(FCE_MARK, PF10MD_101),
-
- PINMUX_DATA(PF9_DATA, PF9MD_000),
- PINMUX_DATA(A23_MARK, PF9MD_001),
- PINMUX_DATA(SSISCK3_MARK, PF9MD_010),
- PINMUX_DATA(RSPCK0_MARK, PF9MD_011),
- PINMUX_DATA(TIOC3A_MARK, PF9MD_100),
- PINMUX_DATA(FRB_MARK, PF9MD_101),
-
- PINMUX_DATA(PF8_DATA, PF8MD_00),
- PINMUX_DATA(CE2B_MARK, PF8MD_01),
- PINMUX_DATA(SSIDATA3_MARK, PF8MD_10),
- PINMUX_DATA(DV_CLK_MARK, PF8MD_11),
-
- PINMUX_DATA(PF7_DATA, PF7MD_000),
- PINMUX_DATA(CE2A_MARK, PF7MD_001),
- PINMUX_DATA(SSIWS3_MARK, PF7MD_010),
- PINMUX_DATA(DV_DATA7_MARK, PF7MD_011),
- PINMUX_DATA(TCLKD_MARK, PF7MD_100),
-
- PINMUX_DATA(PF6_DATA, PF6MD_000),
- PINMUX_DATA(CS6CE1B_MARK, PF6MD_001),
- PINMUX_DATA(SSISCK3_MARK, PF6MD_010),
- PINMUX_DATA(DV_DATA6_MARK, PF6MD_011),
- PINMUX_DATA(TCLKB_MARK, PF6MD_100),
-
- PINMUX_DATA(PF5_DATA, PF5MD_000),
- PINMUX_DATA(CS5CE1A_MARK, PF5MD_001),
- PINMUX_DATA(SSIDATA2_MARK, PF5MD_010),
- PINMUX_DATA(DV_DATA5_MARK, PF5MD_011),
- PINMUX_DATA(TCLKC_MARK, PF5MD_100),
-
- PINMUX_DATA(PF4_DATA, PF4MD_000),
- PINMUX_DATA(ICIOWRAH_MARK, PF4MD_001),
- PINMUX_DATA(SSIWS2_MARK, PF4MD_010),
- PINMUX_DATA(DV_DATA4_MARK, PF4MD_011),
- PINMUX_DATA(TXD3_MARK, PF4MD_100),
-
- PINMUX_DATA(PF3_DATA, PF3MD_000),
- PINMUX_DATA(ICIORD_MARK, PF3MD_001),
- PINMUX_DATA(SSISCK2_MARK, PF3MD_010),
- PINMUX_DATA(DV_DATA3_MARK, PF3MD_011),
- PINMUX_DATA(RXD3_MARK, PF3MD_100),
-
- PINMUX_DATA(PF2_DATA, PF2MD_000),
- PINMUX_DATA(BACK_MARK, PF2MD_001),
- PINMUX_DATA(SSIDATA1_MARK, PF2MD_010),
- PINMUX_DATA(DV_DATA2_MARK, PF2MD_011),
- PINMUX_DATA(TXD2_MARK, PF2MD_100),
- PINMUX_DATA(DACK0_MARK, PF2MD_101),
-
- PINMUX_DATA(PF1_DATA, PF1MD_000),
- PINMUX_DATA(BREQ_MARK, PF1MD_001),
- PINMUX_DATA(SSIWS1_MARK, PF1MD_010),
- PINMUX_DATA(DV_DATA1_MARK, PF1MD_011),
- PINMUX_DATA(RXD2_MARK, PF1MD_100),
- PINMUX_DATA(DREQ0_MARK, PF1MD_101),
-
- PINMUX_DATA(PF0_DATA, PF0MD_000),
- PINMUX_DATA(WAIT_MARK, PF0MD_001),
- PINMUX_DATA(SSISCK1_MARK, PF0MD_010),
- PINMUX_DATA(DV_DATA0_MARK, PF0MD_011),
- PINMUX_DATA(SCK2_MARK, PF0MD_100),
- PINMUX_DATA(TEND0_MARK, PF0MD_101),
-
- /* Port G */
- PINMUX_DATA(PG24_DATA, PG24MD_00),
- PINMUX_DATA(MOSI0_MARK, PG24MD_01),
- PINMUX_DATA(TIOC0D_MARK, PG24MD_10),
-
- PINMUX_DATA(PG23_DATA, PG23MD_00),
- PINMUX_DATA(MOSI1_MARK, PG23MD_01),
- PINMUX_DATA(TIOC0C_MARK, PG23MD_10),
-
- PINMUX_DATA(PG22_DATA, PG22MD_00),
- PINMUX_DATA(SSL10_MARK, PG22MD_01),
- PINMUX_DATA(TIOC0B_MARK, PG22MD_10),
-
- PINMUX_DATA(PG21_DATA, PG21MD_00),
- PINMUX_DATA(RSPCK1_MARK, PG21MD_01),
- PINMUX_DATA(TIOC0A_MARK, PG21MD_10),
-
- PINMUX_DATA(PG20_DATA, PG20MD_000),
- PINMUX_DATA(LCD_EXTCLK_MARK, PG20MD_001),
- PINMUX_DATA(MISO1_MARK, PG20MD_011),
- PINMUX_DATA(TXD7_MARK, PG20MD_100),
-
- PINMUX_DATA(PG19_DATA, PG19MD_000),
- PINMUX_DATA(LCD_CLK_MARK, PG19MD_001),
- PINMUX_DATA(TIOC2B_MARK, PG19MD_010),
- PINMUX_DATA(MISO1_PG19_MARK, PG19MD_011),
- PINMUX_DATA(RXD7_MARK, PG19MD_100),
-
- PINMUX_DATA(PG18_DATA, PG18MD_000),
- PINMUX_DATA(LCD_DE_MARK, PG18MD_001),
- PINMUX_DATA(TIOC2A_MARK, PG18MD_010),
- PINMUX_DATA(SSL10_MARK, PG18MD_011),
- PINMUX_DATA(TXD6_MARK, PG18MD_100),
-
- PINMUX_DATA(PG17_DATA, PG17MD_000),
- PINMUX_DATA(LCD_HSYNC_MARK, PG17MD_001),
- PINMUX_DATA(TIOC1B_MARK, PG17MD_010),
- PINMUX_DATA(RSPCK1_MARK, PG17MD_011),
- PINMUX_DATA(RXD6_MARK, PG17MD_100),
-
- PINMUX_DATA(PG16_DATA, PG16MD_000),
- PINMUX_DATA(LCD_VSYNC_MARK, PG16MD_001),
- PINMUX_DATA(TIOC1A_MARK, PG16MD_010),
- PINMUX_DATA(TXD3_MARK, PG16MD_011),
- PINMUX_DATA(CTS1_MARK, PG16MD_100),
-
- PINMUX_DATA(PG15_DATA, PG15MD_000),
- PINMUX_DATA(LCD_DATA15_MARK, PG15MD_001),
- PINMUX_DATA(TIOC0D_MARK, PG15MD_010),
- PINMUX_DATA(RXD3_MARK, PG15MD_011),
- PINMUX_DATA(RTS1_MARK, PG15MD_100),
-
- PINMUX_DATA(PG14_DATA, PG14MD_000),
- PINMUX_DATA(LCD_DATA14_MARK, PG14MD_001),
- PINMUX_DATA(TIOC0C_MARK, PG14MD_010),
- PINMUX_DATA(SCK1_MARK, PG14MD_100),
-
- PINMUX_DATA(PG13_DATA, PG13MD_000),
- PINMUX_DATA(LCD_DATA13_MARK, PG13MD_001),
- PINMUX_DATA(TIOC0B_MARK, PG13MD_010),
- PINMUX_DATA(TXD1_MARK, PG13MD_100),
-
- PINMUX_DATA(PG12_DATA, PG12MD_000),
- PINMUX_DATA(LCD_DATA12_MARK, PG12MD_001),
- PINMUX_DATA(TIOC0A_MARK, PG12MD_010),
- PINMUX_DATA(RXD1_MARK, PG12MD_100),
-
- PINMUX_DATA(PG11_DATA, PG11MD_000),
- PINMUX_DATA(LCD_DATA11_MARK, PG11MD_001),
- PINMUX_DATA(SSITXD0_MARK, PG11MD_010),
- PINMUX_DATA(IRQ3_PG_MARK, PG11MD_011),
- PINMUX_DATA(TXD5_MARK, PG11MD_100),
- PINMUX_DATA(SIOFTXD_MARK, PG11MD_101),
-
- PINMUX_DATA(PG10_DATA, PG10MD_000),
- PINMUX_DATA(LCD_DATA10_MARK, PG10MD_001),
- PINMUX_DATA(SSIRXD0_MARK, PG10MD_010),
- PINMUX_DATA(IRQ2_PG_MARK, PG10MD_011),
- PINMUX_DATA(RXD5_MARK, PG10MD_100),
- PINMUX_DATA(SIOFRXD_MARK, PG10MD_101),
-
- PINMUX_DATA(PG9_DATA, PG9MD_000),
- PINMUX_DATA(LCD_DATA9_MARK, PG9MD_001),
- PINMUX_DATA(SSIWS0_MARK, PG9MD_010),
- PINMUX_DATA(TXD4_MARK, PG9MD_100),
- PINMUX_DATA(SIOFSYNC_MARK, PG9MD_101),
-
- PINMUX_DATA(PG8_DATA, PG8MD_000),
- PINMUX_DATA(LCD_DATA8_MARK, PG8MD_001),
- PINMUX_DATA(SSISCK0_MARK, PG8MD_010),
- PINMUX_DATA(RXD4_MARK, PG8MD_100),
- PINMUX_DATA(SIOFSCK_MARK, PG8MD_101),
-
- PINMUX_DATA(PG7_DATA, PG7MD_00),
- PINMUX_DATA(LCD_DATA7_MARK, PG7MD_01),
- PINMUX_DATA(SD_CD_MARK, PG7MD_10),
- PINMUX_DATA(PINT7_PG_MARK, PG7MD_11),
-
- PINMUX_DATA(PG6_DATA, PG7MD_00),
- PINMUX_DATA(LCD_DATA6_MARK, PG7MD_01),
- PINMUX_DATA(SD_WP_MARK, PG7MD_10),
- PINMUX_DATA(PINT6_PG_MARK, PG7MD_11),
-
- PINMUX_DATA(PG5_DATA, PG5MD_00),
- PINMUX_DATA(LCD_DATA5_MARK, PG5MD_01),
- PINMUX_DATA(SD_D1_MARK, PG5MD_10),
- PINMUX_DATA(PINT5_PG_MARK, PG5MD_11),
-
- PINMUX_DATA(PG4_DATA, PG4MD_00),
- PINMUX_DATA(LCD_DATA4_MARK, PG4MD_01),
- PINMUX_DATA(SD_D0_MARK, PG4MD_10),
- PINMUX_DATA(PINT4_PG_MARK, PG4MD_11),
-
- PINMUX_DATA(PG3_DATA, PG3MD_00),
- PINMUX_DATA(LCD_DATA3_MARK, PG3MD_01),
- PINMUX_DATA(SD_CLK_MARK, PG3MD_10),
- PINMUX_DATA(PINT3_PG_MARK, PG3MD_11),
-
- PINMUX_DATA(PG2_DATA, PG2MD_00),
- PINMUX_DATA(LCD_DATA2_MARK, PG2MD_01),
- PINMUX_DATA(SD_CMD_MARK, PG2MD_10),
- PINMUX_DATA(PINT2_PG_MARK, PG2MD_11),
-
- PINMUX_DATA(PG1_DATA, PG1MD_00),
- PINMUX_DATA(LCD_DATA1_MARK, PG1MD_01),
- PINMUX_DATA(SD_D3_MARK, PG1MD_10),
- PINMUX_DATA(PINT1_PG_MARK, PG1MD_11),
-
- PINMUX_DATA(PG0_DATA, PG0MD_000),
- PINMUX_DATA(LCD_DATA0_MARK, PG0MD_001),
- PINMUX_DATA(SD_D2_MARK, PG0MD_010),
- PINMUX_DATA(PINT0_PG_MARK, PG0MD_011),
- PINMUX_DATA(WDTOVF_MARK, PG0MD_100),
-
- /* Port H */
- PINMUX_DATA(PH7_DATA, PH7MD_0),
- PINMUX_DATA(PHAN7_MARK, PH7MD_1),
-
- PINMUX_DATA(PH6_DATA, PH6MD_0),
- PINMUX_DATA(PHAN6_MARK, PH6MD_1),
-
- PINMUX_DATA(PH5_DATA, PH5MD_0),
- PINMUX_DATA(PHAN5_MARK, PH5MD_1),
-
- PINMUX_DATA(PH4_DATA, PH4MD_0),
- PINMUX_DATA(PHAN4_MARK, PH4MD_1),
-
- PINMUX_DATA(PH3_DATA, PH3MD_0),
- PINMUX_DATA(PHAN3_MARK, PH3MD_1),
-
- PINMUX_DATA(PH2_DATA, PH2MD_0),
- PINMUX_DATA(PHAN2_MARK, PH2MD_1),
-
- PINMUX_DATA(PH1_DATA, PH1MD_0),
- PINMUX_DATA(PHAN1_MARK, PH1MD_1),
-
- PINMUX_DATA(PH0_DATA, PH0MD_0),
- PINMUX_DATA(PHAN0_MARK, PH0MD_1),
-
- /* Port I - not on device */
-
- /* Port J */
- PINMUX_DATA(PJ11_DATA, PJ11MD_00),
- PINMUX_DATA(PWM2H_MARK, PJ11MD_01),
- PINMUX_DATA(DACK1_MARK, PJ11MD_10),
-
- PINMUX_DATA(PJ10_DATA, PJ10MD_00),
- PINMUX_DATA(PWM2G_MARK, PJ10MD_01),
- PINMUX_DATA(DREQ1_MARK, PJ10MD_10),
-
- PINMUX_DATA(PJ9_DATA, PJ9MD_00),
- PINMUX_DATA(PWM2F_MARK, PJ9MD_01),
- PINMUX_DATA(TEND1_MARK, PJ9MD_10),
-
- PINMUX_DATA(PJ8_DATA, PJ8MD_00),
- PINMUX_DATA(PWM2E_MARK, PJ8MD_01),
- PINMUX_DATA(RTS3_MARK, PJ8MD_10),
-
- PINMUX_DATA(PJ7_DATA, PJ7MD_00),
- PINMUX_DATA(TIOC1B_MARK, PJ7MD_01),
- PINMUX_DATA(CTS3_MARK, PJ7MD_10),
-
- PINMUX_DATA(PJ6_DATA, PJ6MD_00),
- PINMUX_DATA(TIOC1A_MARK, PJ6MD_01),
- PINMUX_DATA(SCK3_MARK, PJ6MD_10),
-
- PINMUX_DATA(PJ5_DATA, PJ5MD_00),
- PINMUX_DATA(IERXD_MARK, PJ5MD_01),
- PINMUX_DATA(TXD3_MARK, PJ5MD_10),
-
- PINMUX_DATA(PJ4_DATA, PJ4MD_00),
- PINMUX_DATA(IETXD_MARK, PJ4MD_01),
- PINMUX_DATA(RXD3_MARK, PJ4MD_10),
-
- PINMUX_DATA(PJ3_DATA, PJ3MD_00),
- PINMUX_DATA(CRX1_MARK, PJ3MD_01),
- PINMUX_DATA(CRX0X1_MARK, PJ3MD_10),
- PINMUX_DATA(IRQ1_PJ_MARK, PJ3MD_11),
-
- PINMUX_DATA(PJ2_DATA, PJ2MD_000),
- PINMUX_DATA(CTX1_MARK, PJ2MD_001),
- PINMUX_DATA(CRX0CRX1_MARK, PJ2MD_010),
- PINMUX_DATA(CS2_MARK, PJ2MD_011),
- PINMUX_DATA(SCK0_MARK, PJ2MD_100),
- PINMUX_DATA(LCD_M_DISP_MARK, PJ2MD_101),
-
- PINMUX_DATA(PJ1_DATA, PJ1MD_000),
- PINMUX_DATA(CRX0_MARK, PJ1MD_001),
- PINMUX_DATA(IERXD_MARK, PJ1MD_010),
- PINMUX_DATA(IRQ0_PJ_MARK, PJ1MD_011),
- PINMUX_DATA(RXD0_MARK, PJ1MD_100),
-
- PINMUX_DATA(PJ0_DATA, PJ0MD_000),
- PINMUX_DATA(CTX0_MARK, PJ0MD_001),
- PINMUX_DATA(IERXD_MARK, PJ0MD_010),
- PINMUX_DATA(CS1_MARK, PJ0MD_011),
- PINMUX_DATA(TXD0_MARK, PJ0MD_100),
- PINMUX_DATA(A0_MARK, PJ0MD_101),
-
- /* Port K */
- PINMUX_DATA(PK11_DATA, PK11MD_00),
- PINMUX_DATA(PWM2D_MARK, PK11MD_01),
- PINMUX_DATA(SSITXD0_MARK, PK11MD_10),
-
- PINMUX_DATA(PK10_DATA, PK10MD_00),
- PINMUX_DATA(PWM2C_MARK, PK10MD_01),
- PINMUX_DATA(SSIRXD0_MARK, PK10MD_10),
-
- PINMUX_DATA(PK9_DATA, PK9MD_00),
- PINMUX_DATA(PWM2B_MARK, PK9MD_01),
- PINMUX_DATA(SSIWS0_MARK, PK9MD_10),
-
- PINMUX_DATA(PK8_DATA, PK8MD_00),
- PINMUX_DATA(PWM2A_MARK, PK8MD_01),
- PINMUX_DATA(SSISCK0_MARK, PK8MD_10),
-
- PINMUX_DATA(PK7_DATA, PK7MD_00),
- PINMUX_DATA(PWM1H_MARK, PK7MD_01),
- PINMUX_DATA(SD_CD_MARK, PK7MD_10),
-
- PINMUX_DATA(PK6_DATA, PK6MD_00),
- PINMUX_DATA(PWM1G_MARK, PK6MD_01),
- PINMUX_DATA(SD_WP_MARK, PK6MD_10),
-
- PINMUX_DATA(PK5_DATA, PK5MD_00),
- PINMUX_DATA(PWM1F_MARK, PK5MD_01),
- PINMUX_DATA(SD_D1_MARK, PK5MD_10),
-
- PINMUX_DATA(PK4_DATA, PK4MD_00),
- PINMUX_DATA(PWM1E_MARK, PK4MD_01),
- PINMUX_DATA(SD_D0_MARK, PK4MD_10),
-
- PINMUX_DATA(PK3_DATA, PK3MD_00),
- PINMUX_DATA(PWM1D_MARK, PK3MD_01),
- PINMUX_DATA(SD_CLK_MARK, PK3MD_10),
-
- PINMUX_DATA(PK2_DATA, PK2MD_00),
- PINMUX_DATA(PWM1C_MARK, PK2MD_01),
- PINMUX_DATA(SD_CMD_MARK, PK2MD_10),
-
- PINMUX_DATA(PK1_DATA, PK1MD_00),
- PINMUX_DATA(PWM1B_MARK, PK1MD_01),
- PINMUX_DATA(SD_D3_MARK, PK1MD_10),
-
- PINMUX_DATA(PK0_DATA, PK0MD_00),
- PINMUX_DATA(PWM1A_MARK, PK0MD_01),
- PINMUX_DATA(SD_D2_MARK, PK0MD_10),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
-
- /* Port A */
- PINMUX_GPIO(GPIO_PA3, PA3_DATA),
- PINMUX_GPIO(GPIO_PA2, PA2_DATA),
- PINMUX_GPIO(GPIO_PA1, PA1_DATA),
- PINMUX_GPIO(GPIO_PA0, PA0_DATA),
-
- /* Port B */
- PINMUX_GPIO(GPIO_PB22, PB22_DATA),
- PINMUX_GPIO(GPIO_PB21, PB21_DATA),
- PINMUX_GPIO(GPIO_PB20, PB20_DATA),
- PINMUX_GPIO(GPIO_PB19, PB19_DATA),
- PINMUX_GPIO(GPIO_PB18, PB18_DATA),
- PINMUX_GPIO(GPIO_PB17, PB17_DATA),
- PINMUX_GPIO(GPIO_PB16, PB16_DATA),
- PINMUX_GPIO(GPIO_PB15, PB15_DATA),
- PINMUX_GPIO(GPIO_PB14, PB14_DATA),
- PINMUX_GPIO(GPIO_PB13, PB13_DATA),
- PINMUX_GPIO(GPIO_PB12, PB12_DATA),
- PINMUX_GPIO(GPIO_PB11, PB11_DATA),
- PINMUX_GPIO(GPIO_PB10, PB10_DATA),
- PINMUX_GPIO(GPIO_PB9, PB9_DATA),
- PINMUX_GPIO(GPIO_PB8, PB8_DATA),
- PINMUX_GPIO(GPIO_PB7, PB7_DATA),
- PINMUX_GPIO(GPIO_PB6, PB6_DATA),
- PINMUX_GPIO(GPIO_PB5, PB5_DATA),
- PINMUX_GPIO(GPIO_PB4, PB4_DATA),
- PINMUX_GPIO(GPIO_PB3, PB3_DATA),
- PINMUX_GPIO(GPIO_PB2, PB2_DATA),
- PINMUX_GPIO(GPIO_PB1, PB1_DATA),
-
- /* Port C */
- PINMUX_GPIO(GPIO_PC10, PC10_DATA),
- PINMUX_GPIO(GPIO_PC9, PC9_DATA),
- PINMUX_GPIO(GPIO_PC8, PC8_DATA),
- PINMUX_GPIO(GPIO_PC7, PC7_DATA),
- PINMUX_GPIO(GPIO_PC6, PC6_DATA),
- PINMUX_GPIO(GPIO_PC5, PC5_DATA),
- PINMUX_GPIO(GPIO_PC4, PC4_DATA),
- PINMUX_GPIO(GPIO_PC3, PC3_DATA),
- PINMUX_GPIO(GPIO_PC2, PC2_DATA),
- PINMUX_GPIO(GPIO_PC1, PC1_DATA),
- PINMUX_GPIO(GPIO_PC0, PC0_DATA),
-
- /* Port D */
- PINMUX_GPIO(GPIO_PD15, PD15_DATA),
- PINMUX_GPIO(GPIO_PD14, PD14_DATA),
- PINMUX_GPIO(GPIO_PD13, PD13_DATA),
- PINMUX_GPIO(GPIO_PD12, PD12_DATA),
- PINMUX_GPIO(GPIO_PD11, PD11_DATA),
- PINMUX_GPIO(GPIO_PD10, PD10_DATA),
- PINMUX_GPIO(GPIO_PD9, PD9_DATA),
- PINMUX_GPIO(GPIO_PD8, PD8_DATA),
- PINMUX_GPIO(GPIO_PD7, PD7_DATA),
- PINMUX_GPIO(GPIO_PD6, PD6_DATA),
- PINMUX_GPIO(GPIO_PD5, PD5_DATA),
- PINMUX_GPIO(GPIO_PD4, PD4_DATA),
- PINMUX_GPIO(GPIO_PD3, PD3_DATA),
- PINMUX_GPIO(GPIO_PD2, PD2_DATA),
- PINMUX_GPIO(GPIO_PD1, PD1_DATA),
- PINMUX_GPIO(GPIO_PD0, PD0_DATA),
-
- /* Port E */
- PINMUX_GPIO(GPIO_PE5, PE5_DATA),
- PINMUX_GPIO(GPIO_PE4, PE4_DATA),
- PINMUX_GPIO(GPIO_PE3, PE3_DATA),
- PINMUX_GPIO(GPIO_PE2, PE2_DATA),
- PINMUX_GPIO(GPIO_PE1, PE1_DATA),
- PINMUX_GPIO(GPIO_PE0, PE0_DATA),
-
- /* Port F */
- PINMUX_GPIO(GPIO_PF12, PF12_DATA),
- PINMUX_GPIO(GPIO_PF11, PF11_DATA),
- PINMUX_GPIO(GPIO_PF10, PF10_DATA),
- PINMUX_GPIO(GPIO_PF9, PF9_DATA),
- PINMUX_GPIO(GPIO_PF8, PF8_DATA),
- PINMUX_GPIO(GPIO_PF7, PF7_DATA),
- PINMUX_GPIO(GPIO_PF6, PF6_DATA),
- PINMUX_GPIO(GPIO_PF5, PF5_DATA),
- PINMUX_GPIO(GPIO_PF4, PF4_DATA),
- PINMUX_GPIO(GPIO_PF3, PF3_DATA),
- PINMUX_GPIO(GPIO_PF2, PF2_DATA),
- PINMUX_GPIO(GPIO_PF1, PF1_DATA),
- PINMUX_GPIO(GPIO_PF0, PF0_DATA),
-
- /* Port G */
- PINMUX_GPIO(GPIO_PG24, PG24_DATA),
- PINMUX_GPIO(GPIO_PG23, PG23_DATA),
- PINMUX_GPIO(GPIO_PG22, PG22_DATA),
- PINMUX_GPIO(GPIO_PG21, PG21_DATA),
- PINMUX_GPIO(GPIO_PG20, PG20_DATA),
- PINMUX_GPIO(GPIO_PG19, PG19_DATA),
- PINMUX_GPIO(GPIO_PG18, PG18_DATA),
- PINMUX_GPIO(GPIO_PG17, PG17_DATA),
- PINMUX_GPIO(GPIO_PG16, PG16_DATA),
- PINMUX_GPIO(GPIO_PG15, PG15_DATA),
- PINMUX_GPIO(GPIO_PG14, PG14_DATA),
- PINMUX_GPIO(GPIO_PG13, PG13_DATA),
- PINMUX_GPIO(GPIO_PG12, PG12_DATA),
- PINMUX_GPIO(GPIO_PG11, PG11_DATA),
- PINMUX_GPIO(GPIO_PG10, PG10_DATA),
- PINMUX_GPIO(GPIO_PG9, PG9_DATA),
- PINMUX_GPIO(GPIO_PG8, PG8_DATA),
- PINMUX_GPIO(GPIO_PG7, PG7_DATA),
- PINMUX_GPIO(GPIO_PG6, PG6_DATA),
- PINMUX_GPIO(GPIO_PG5, PG5_DATA),
- PINMUX_GPIO(GPIO_PG4, PG4_DATA),
- PINMUX_GPIO(GPIO_PG3, PG3_DATA),
- PINMUX_GPIO(GPIO_PG2, PG2_DATA),
- PINMUX_GPIO(GPIO_PG1, PG1_DATA),
- PINMUX_GPIO(GPIO_PG0, PG0_DATA),
-
- /* Port H - Port H does not have a Data Register */
-
- /* Port I - not on device */
-
- /* Port J */
- PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
- PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
- PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
- PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
- PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
- PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
- PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
- PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
- PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
- PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
- PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
- PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
-
- /* Port K */
- PINMUX_GPIO(GPIO_PK11, PK11_DATA),
- PINMUX_GPIO(GPIO_PK10, PK10_DATA),
- PINMUX_GPIO(GPIO_PK9, PK9_DATA),
- PINMUX_GPIO(GPIO_PK8, PK8_DATA),
- PINMUX_GPIO(GPIO_PK7, PK7_DATA),
- PINMUX_GPIO(GPIO_PK6, PK6_DATA),
- PINMUX_GPIO(GPIO_PK5, PK5_DATA),
- PINMUX_GPIO(GPIO_PK4, PK4_DATA),
- PINMUX_GPIO(GPIO_PK3, PK3_DATA),
- PINMUX_GPIO(GPIO_PK2, PK2_DATA),
- PINMUX_GPIO(GPIO_PK1, PK1_DATA),
- PINMUX_GPIO(GPIO_PK0, PK0_DATA),
-
- /* INTC */
- PINMUX_GPIO(GPIO_FN_PINT7_PG, PINT7_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT6_PG, PINT6_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT5_PG, PINT5_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT4_PG, PINT4_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT3_PG, PINT3_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT2_PG, PINT2_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT1_PG, PINT1_PG_MARK),
-
- PINMUX_GPIO(GPIO_FN_IRQ7_PC, IRQ7_PC_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ6_PC, IRQ6_PC_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ5_PC, IRQ5_PC_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ4_PC, IRQ4_PC_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3_PG, IRQ3_PG_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2_PG, IRQ2_PG_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1_PJ, IRQ1_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0_PJ, IRQ0_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3_PE, IRQ3_PE_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2_PE, IRQ2_PE_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1_PE, IRQ1_PE_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0_PE, IRQ0_PE_MARK),
-
- /* WDT */
- PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
-
- /* CAN */
- PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
- PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
- PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
- PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
- PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0CRX1_MARK),
-
- /* DMAC */
- PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
- PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
- PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
-
- /* ADC */
- PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
-
- /* BSCh */
- PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
- PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
- PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
- PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
- PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
- PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
- PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
- PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
- PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
- PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
- PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
- PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
- PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
- PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
- PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
- PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
- PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
- PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
- PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
- PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
- PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
- PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
- PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
- PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
- PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
- PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
-
- PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
- PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
- PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
- PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
- PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
- PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
- PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
- PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
- PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
- PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
- PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
- PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
- PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
- PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
- PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
- PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
-
- PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
- PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
- PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
- PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
- PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
- PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
- PINMUX_GPIO(GPIO_FN_CS6CE1B, CS6CE1B_MARK),
- PINMUX_GPIO(GPIO_FN_CS5CE1A, CS5CE1A_MARK),
- PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
- PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
- PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
- PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
- PINMUX_GPIO(GPIO_FN_ICIOWRAH, ICIOWRAH_MARK),
- PINMUX_GPIO(GPIO_FN_ICIORD, ICIORD_MARK),
- PINMUX_GPIO(GPIO_FN_WE1DQMUWE, WE1DQMUWE_MARK),
- PINMUX_GPIO(GPIO_FN_WE0DQML, WE0DQML_MARK),
- PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
- PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
- PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
- PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
- PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
- PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
- PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
-
- /* TMU */
- PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKD, TCLKD_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKC, TCLKC_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKB, TCLKB_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKA, TCLKA_MARK),
-
- /* SCIF */
- PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
- PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
- PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
- PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
- PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
- PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
- PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
- PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
- PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
- PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
- PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
- PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
- PINMUX_GPIO(GPIO_FN_TXD5, TXD5_MARK),
- PINMUX_GPIO(GPIO_FN_RXD5, RXD5_MARK),
- PINMUX_GPIO(GPIO_FN_TXD6, TXD6_MARK),
- PINMUX_GPIO(GPIO_FN_RXD6, RXD6_MARK),
- PINMUX_GPIO(GPIO_FN_TXD7, TXD7_MARK),
- PINMUX_GPIO(GPIO_FN_RXD7, RXD7_MARK),
- PINMUX_GPIO(GPIO_FN_RTS1, RTS1_MARK),
- PINMUX_GPIO(GPIO_FN_CTS1, CTS1_MARK),
-
- /* RSPI */
- PINMUX_GPIO(GPIO_FN_RSPCK0, RSPCK0_MARK),
- PINMUX_GPIO(GPIO_FN_MOSI0, MOSI0_MARK),
- PINMUX_GPIO(GPIO_FN_MISO0_PF12, MISO0_PF12_MARK),
- PINMUX_GPIO(GPIO_FN_MISO1, MISO1_MARK),
- PINMUX_GPIO(GPIO_FN_SSL00, SSL00_MARK),
- PINMUX_GPIO(GPIO_FN_RSPCK1, RSPCK1_MARK),
- PINMUX_GPIO(GPIO_FN_MOSI1, MOSI1_MARK),
- PINMUX_GPIO(GPIO_FN_MISO1_PG19, MISO1_PG19_MARK),
- PINMUX_GPIO(GPIO_FN_SSL10, SSL10_MARK),
-
- /* IIC3 */
- PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
- PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
- PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
- PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
- PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
- PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
-
- /* SSI */
- PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
- PINMUX_GPIO(GPIO_FN_SSITXD0, SSITXD0_MARK),
- PINMUX_GPIO(GPIO_FN_SSIRXD0, SSIRXD0_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
- PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
- PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
- PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
- PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
- PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
- PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
- PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
-
- /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
- PINMUX_GPIO(GPIO_FN_SIOFTXD, SIOFTXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOFRXD, SIOFRXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOFSYNC, SIOFSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_SIOFSCK, SIOFSCK_MARK),
-
- /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
- PINMUX_GPIO(GPIO_FN_SPDIF_IN, SPDIF_IN_MARK),
- PINMUX_GPIO(GPIO_FN_SPDIF_OUT, SPDIF_OUT_MARK),
-
- /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
- PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
- PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
-
- /* VDC3 */
- PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
-
- PINMUX_GPIO(GPIO_FN_DV_DATA7, DV_DATA7_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA6, DV_DATA6_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA5, DV_DATA5_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA4, DV_DATA4_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA3, DV_DATA3_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA2, DV_DATA2_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA1, DV_DATA1_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA0, DV_DATA0_MARK),
-
- PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_EXTCLK, LCD_EXTCLK_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_VSYNC, LCD_VSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
-
- PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
-
- PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
-};
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- { PINMUX_CFG_REG("PAIOR0", 0xfffe3812, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PA3_IN, PA3_OUT,
- PA2_IN, PA2_OUT,
- PA1_IN, PA1_OUT,
- PA0_IN, PA0_OUT }
- },
-
- { PINMUX_CFG_REG("PBCR5", 0xfffe3824, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PB22MD_00, PB22MD_01, PB22MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PB21MD_0, PB21MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB20MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
-
- },
- { PINMUX_CFG_REG("PBCR4", 0xfffe3826, 16, 4) {
- 0, PB19MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB18MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB17MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB16MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCR3", 0xfffe3828, 16, 4) {
- 0, PB15MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB14MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB13MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB12MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCR2", 0xfffe382a, 16, 4) {
- 0, PB11MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB10MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB9MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB8MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCR1", 0xfffe382c, 16, 4) {
- 0, PB7MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB6MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB5MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB4MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCR0", 0xfffe382e, 16, 4) {
- 0, PB3MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB2MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB1MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PBIOR1", 0xfffe3830, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- PB22_IN, PB22_OUT,
- PB21_IN, PB21_OUT,
- PB20_IN, PB20_OUT,
- PB19_IN, PB19_OUT,
- PB18_IN, PB18_OUT,
- PB17_IN, PB17_OUT,
- PB16_IN, PB16_OUT }
- },
-
- { PINMUX_CFG_REG("PBIOR0", 0xfffe3832, 16, 1) {
- PB15_IN, PB15_OUT,
- PB14_IN, PB14_OUT,
- PB13_IN, PB13_OUT,
- PB12_IN, PB12_OUT,
- PB11_IN, PB11_OUT,
- PB10_IN, PB10_OUT,
- PB9_IN, PB9_OUT,
- PB8_IN, PB8_OUT,
- PB7_IN, PB7_OUT,
- PB6_IN, PB6_OUT,
- PB5_IN, PB5_OUT,
- PB4_IN, PB4_OUT,
- PB3_IN, PB3_OUT,
- PB2_IN, PB2_OUT,
- PB1_IN, PB1_OUT,
- 0, 0 }
- },
-
- { PINMUX_CFG_REG("PCCR2", 0xfffe384a, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PC10MD_0, PC10MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PC9MD_0, PC9MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PC8MD_00, PC8MD_01, PC8MD_10, PC8MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PCCR1", 0xfffe384c, 16, 4) {
- PC7MD_00, PC7MD_01, PC7MD_10, PC7MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PC6MD_00, PC6MD_01, PC6MD_10, PC6MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PC5MD_00, PC5MD_01, PC5MD_10, PC5MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PC4MD_0, PC4MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PCCR0", 0xfffe384e, 16, 4) {
- PC3MD_0, PC3MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PC2MD_0, PC2MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PC1MD_0, PC1MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PC0MD_0, PC0MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- PC10_IN, PC10_OUT,
- PC9_IN, PC9_OUT,
- PC8_IN, PC8_OUT,
- PC7_IN, PC7_OUT,
- PC6_IN, PC6_OUT,
- PC5_IN, PC5_OUT,
- PC4_IN, PC4_OUT,
- PC3_IN, PC3_OUT,
- PC2_IN, PC2_OUT,
- PC1_IN, PC1_OUT,
- PC0_IN, PC0_OUT
- }
- },
-
- { PINMUX_CFG_REG("PDCR3", 0xfffe3868, 16, 4) {
- 0, PD15MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD14MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD13MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD12MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PDCR2", 0xfffe386a, 16, 4) {
- 0, PD11MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD10MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD9MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD8MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PDCR1", 0xfffe386c, 16, 4) {
- 0, PD7MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD6MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD5MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD4MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PDCR0", 0xfffe386e, 16, 4) {
- 0, PD3MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD2MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD1MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PD0MD_01, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PDIOR0", 0xfffe3872, 16, 1) {
- PD15_IN, PD15_OUT,
- PD14_IN, PD14_OUT,
- PD13_IN, PD13_OUT,
- PD12_IN, PD12_OUT,
- PD11_IN, PD11_OUT,
- PD10_IN, PD10_OUT,
- PD9_IN, PD9_OUT,
- PD8_IN, PD8_OUT,
- PD7_IN, PD7_OUT,
- PD6_IN, PD6_OUT,
- PD5_IN, PD5_OUT,
- PD4_IN, PD4_OUT,
- PD3_IN, PD3_OUT,
- PD2_IN, PD2_OUT,
- PD1_IN, PD1_OUT,
- PD0_IN, PD0_OUT }
- },
-
- { PINMUX_CFG_REG("PECR1", 0xfffe388c, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PE5MD_00, PE5MD_01, 0, PE5MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PE4MD_00, PE4MD_01, 0, PE4MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PECR0", 0xfffe388e, 16, 4) {
- PE3MD_00, PE3MD_01, 0, PE3MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PE2MD_00, PE2MD_01, 0, PE2MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
- PE1MD_100, PE1MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PEIOR0", 0xfffe3892, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- PE5_IN, PE5_OUT,
- PE4_IN, PE4_OUT,
- PE3_IN, PE3_OUT,
- PE2_IN, PE2_OUT,
- PE1_IN, PE1_OUT,
- PE0_IN, PE0_OUT }
- },
-
- { PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
- PF12MD_000, PF12MD_001, 0, PF12MD_011,
- PF12MD_100, PF12MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PFCR2", 0xfffe38aa, 16, 4) {
- PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
- PF11MD_100, PF11MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
- PF10MD_100, PF10MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
- PF9MD_100, PF9MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF8MD_00, PF8MD_01, PF8MD_10, PF8MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PFCR1", 0xfffe38ac, 16, 4) {
- PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
- PF7MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
- PF6MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
- PF5MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
- PF4MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PFCR0", 0xfffe38ae, 16, 4) {
- PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
- PF3MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
- PF2MD_100, PF2MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
- PF1MD_100, PF1MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
- }
- },
-
- { PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
- 0, 0, 0, 0, 0, 0,
- PF12_IN, PF12_OUT,
- PF11_IN, PF11_OUT,
- PF10_IN, PF10_OUT,
- PF9_IN, PF9_OUT,
- PF8_IN, PF8_OUT,
- PF7_IN, PF7_OUT,
- PF6_IN, PF6_OUT,
- PF5_IN, PF5_OUT,
- PF4_IN, PF4_OUT,
- PF3_IN, PF3_OUT,
- PF2_IN, PF2_OUT,
- PF1_IN, PF1_OUT,
- PF0_IN, PF0_OUT }
- },
-
- { PINMUX_CFG_REG("PGCR7", 0xfffe38c0, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
- PG0MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PGCR6", 0xfffe38c2, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PGCR5", 0xfffe38c4, 16, 4) {
- PG23MD_00, PG23MD_01, PG23MD_10, PG23MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG22MD_00, PG22MD_01, PG22MD_10, PG22MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG21MD_00, PG21MD_01, PG21MD_10, PG21MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
- PG20MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PGCR4", 0xfffe38c6, 16, 4) {
- PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
- PG19MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
- PG18MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG17MD_000, PG17MD_001, PG17MD_010, PG17MD_011,
- PG17MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG16MD_000, PG16MD_001, PG16MD_010, PG16MD_011,
- PG16MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PGCR3", 0xfffe38c8, 16, 4) {
- PG15MD_000, PG15MD_001, PG15MD_010, PG15MD_011,
- PG15MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG14MD_000, PG14MD_001, PG14MD_010, 0,
- PG14MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG13MD_000, PG13MD_001, PG13MD_010, 0,
- PG13MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG12MD_000, PG12MD_001, PG12MD_010, 0,
- PG12MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PGCR2", 0xfffe38ca, 16, 4) {
- PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
- PG11MD_100, PG11MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
- PG10MD_100, PG10MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
- PG9MD_100, PG9MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
- PG8MD_100, PG8MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PGCR1", 0xfffe38cc, 16, 4) {
- PG7MD_00, PG7MD_01, PG7MD_10, PG7MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG6MD_00, PG6MD_01, PG6MD_10, PG6MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG5MD_00, PG5MD_01, PG5MD_10, PG5MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG4MD_00, PG4MD_01, PG4MD_10, PG4MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PGCR0", 0xfffe38ce, 16, 4) {
- PG3MD_00, PG3MD_01, PG3MD_10, PG3MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG2MD_00, PG2MD_01, PG2MD_10, PG2MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG1MD_00, PG1MD_01, PG1MD_10, PG1MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PGIOR1", 0xfffe38d0, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,
- PG24_IN, PG24_OUT,
- PG23_IN, PG23_OUT,
- PG22_IN, PG22_OUT,
- PG21_IN, PG21_OUT,
- PG20_IN, PG20_OUT,
- PG19_IN, PG19_OUT,
- PG18_IN, PG18_OUT,
- PG17_IN, PG17_OUT,
- PG16_IN, PG16_OUT }
- },
-
- { PINMUX_CFG_REG("PGIOR0", 0xfffe38d2, 16, 1) {
- PG15_IN, PG15_OUT,
- PG14_IN, PG14_OUT,
- PG13_IN, PG13_OUT,
- PG12_IN, PG12_OUT,
- PG11_IN, PG11_OUT,
- PG10_IN, PG10_OUT,
- PG9_IN, PG9_OUT,
- PG8_IN, PG8_OUT,
- PG7_IN, PG7_OUT,
- PG6_IN, PG6_OUT,
- PG5_IN, PG5_OUT,
- PG4_IN, PG4_OUT,
- PG3_IN, PG3_OUT,
- PG2_IN, PG2_OUT,
- PG1_IN, PG1_OUT,
- PG0_IN, PG0_OUT
- }
- },
-
- { PINMUX_CFG_REG("PHCR1", 0xfffe38ec, 16, 4) {
- PH7MD_0, PH7MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PH6MD_0, PH6MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PH5MD_0, PH5MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PH4MD_0, PH4MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PHCR0", 0xfffe38ee, 16, 4) {
- PH3MD_0, PH3MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PH2MD_0, PH2MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PH1MD_0, PH1MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PH0MD_0, PH0MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PJCR2", 0xfffe390a, 16, 4) {
- PJ11MD_00, PJ11MD_01, PJ11MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ10MD_00, PJ10MD_01, PJ10MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ9MD_00, PJ9MD_01, PJ9MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ8MD_00, PJ8MD_01, PJ8MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PJCR1", 0xfffe390c, 16, 4) {
- PJ7MD_00, PJ7MD_01, PJ7MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ6MD_00, PJ6MD_01, PJ6MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ5MD_00, PJ5MD_01, PJ5MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ4MD_00, PJ4MD_01, PJ4MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PJCR0", 0xfffe390e, 16, 4) {
- PJ3MD_00, PJ3MD_01, PJ3MD_10, PJ3MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
- PJ2MD_100, PJ2MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
- PJ1MD_100, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
- PJ0MD_100, PJ0MD_101, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, }
- },
- { PINMUX_CFG_REG("PJIOR0", 0xfffe3912, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ11_IN, PJ11_OUT,
- PJ10_IN, PJ10_OUT,
- PJ9_IN, PJ9_OUT,
- PJ8_IN, PJ8_OUT,
- PJ7_IN, PJ7_OUT,
- PJ6_IN, PJ6_OUT,
- PJ5_IN, PJ5_OUT,
- PJ4_IN, PJ4_OUT,
- PJ3_IN, PJ3_OUT,
- PJ2_IN, PJ2_OUT,
- PJ1_IN, PJ1_OUT,
- PJ0_IN, PJ0_OUT }
- },
-
- { PINMUX_CFG_REG("PKCR2", 0xfffe392a, 16, 4) {
- PK11MD_00, PK11MD_01, PK11MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PK10MD_00, PK10MD_01, PK10MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PK9MD_00, PK9MD_01, PK9MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PK8MD_00, PK8MD_01, PK8MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PKCR1", 0xfffe392c, 16, 4) {
- PK7MD_00, PK7MD_01, PK7MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PK6MD_00, PK6MD_01, PK6MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PK5MD_00, PK5MD_01, PK5MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PK4MD_00, PK4MD_01, PK4MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PKCR0", 0xfffe392e, 16, 4) {
- PK3MD_00, PK3MD_01, PK3MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PK2MD_00, PK2MD_01, PK2MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PK1MD_00, PK1MD_01, PK1MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PK0MD_00, PK0MD_01, PK0MD_10, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PKIOR0", 0xfffe3932, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- PJ11_IN, PJ11_OUT,
- PJ10_IN, PJ10_OUT,
- PJ9_IN, PJ9_OUT,
- PJ8_IN, PJ8_OUT,
- PJ7_IN, PJ7_OUT,
- PJ6_IN, PJ6_OUT,
- PJ5_IN, PJ5_OUT,
- PJ4_IN, PJ4_OUT,
- PJ3_IN, PJ3_OUT,
- PJ2_IN, PJ2_OUT,
- PJ1_IN, PJ1_OUT,
- PJ0_IN, PJ0_OUT }
- },
- {}
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PADR1", 0xfffe3814, 16) {
- 0, 0, 0, 0, 0, 0, 0, PA3_DATA,
- 0, 0, 0, 0, 0, 0, 0, PA2_DATA }
- },
-
- { PINMUX_DATA_REG("PADR0", 0xfffe3816, 16) {
- 0, 0, 0, 0, 0, 0, 0, PA1_DATA,
- 0, 0, 0, 0, 0, 0, 0, PA0_DATA }
- },
-
- { PINMUX_DATA_REG("PBDR1", 0xfffe3834, 16) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB22_DATA, PB21_DATA, PB20_DATA,
- PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA }
- },
-
- { PINMUX_DATA_REG("PBDR0", 0xfffe3836, 16) {
- PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
- PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA, 0 }
- },
-
- { PINMUX_DATA_REG("PCDR0", 0xfffe3856, 16) {
- 0, 0, 0, 0,
- 0, PC10_DATA, PC9_DATA, PC8_DATA,
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
- },
-
- { PINMUX_DATA_REG("PDDR0", 0xfffe3876, 16) {
- PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
- PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
- },
-
- { PINMUX_DATA_REG("PEDR0", 0xfffe3896, 16) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, PE5_DATA, PE4_DATA,
- PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
- },
-
- { PINMUX_DATA_REG("PFDR0", 0xfffe38b6, 16) {
- 0, 0, 0, PF12_DATA,
- PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
- },
-
- { PINMUX_DATA_REG("PGDR1", 0xfffe38d4, 16) {
- 0, 0, 0, 0, 0, 0, 0, PG24_DATA,
- PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
- PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA }
- },
-
- { PINMUX_DATA_REG("PGDR0", 0xfffe38d6, 16) {
- PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
- PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
- PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
- PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
- },
- { PINMUX_DATA_REG("PJDR0", 0xfffe3916, 16) {
- 0, 0, 0, PJ12_DATA,
- PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
- PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
- PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
- },
- { PINMUX_DATA_REG("PKDR0", 0xfffe3936, 16) {
- 0, 0, 0, PK12_DATA,
- PK11_DATA, PK10_DATA, PK9_DATA, PK8_DATA,
- PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
- PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA }
- },
- { }
-};
-
-static struct pinmux_info sh7264_pinmux_info = {
- .name = "sh7264_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_PA3,
- .last_gpio = GPIO_FN_LCD_M_DISP,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
+#include <cpu/pfc.h>
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7264_pinmux_info);
+ return sh_pfc_register("pfc-sh7264", NULL, 0);
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c b/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c
index 039e4587dd9b..dc2a86830456 100644
--- a/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c
+++ b/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c
@@ -11,2829 +11,10 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/sh7269.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- /* Port A */
- PA1_DATA, PA0_DATA,
- /* Port B */
- PB22_DATA, PB21_DATA, PB20_DATA,
- PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA,
- PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
- PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA,
- /* Port C */
- PC8_DATA,
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
- /* Port D */
- PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
- PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
- /* Port E */
- PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
- PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
- /* Port F */
- PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
- PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA,
- PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
- PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
- /* Port G */
- PG27_DATA, PG26_DATA, PG25_DATA, PG24_DATA,
- PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
- PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA,
- PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
- PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
- PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
- PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
- /* Port H */
- /* NOTE - Port H does not have a Data Register, but PH Data is
- connected to PH Port Register */
- PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
- PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
- /* Port I - not on device */
- /* Port J */
- PJ31_DATA, PJ30_DATA, PJ29_DATA, PJ28_DATA,
- PJ27_DATA, PJ26_DATA, PJ25_DATA, PJ24_DATA,
- PJ23_DATA, PJ22_DATA, PJ21_DATA, PJ20_DATA,
- PJ19_DATA, PJ18_DATA, PJ17_DATA, PJ16_DATA,
- PJ15_DATA, PJ14_DATA, PJ13_DATA, PJ12_DATA,
- PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
- PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
- PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- FORCE_IN,
- /* Port A */
- PA1_IN, PA0_IN,
- /* Port B */
- PB22_IN, PB21_IN, PB20_IN,
- PB19_IN, PB18_IN, PB17_IN, PB16_IN,
- PB15_IN, PB14_IN, PB13_IN, PB12_IN,
- PB11_IN, PB10_IN, PB9_IN, PB8_IN,
- PB7_IN, PB6_IN, PB5_IN, PB4_IN,
- PB3_IN, PB2_IN, PB1_IN,
- /* Port C */
- PC8_IN,
- PC7_IN, PC6_IN, PC5_IN, PC4_IN,
- PC3_IN, PC2_IN, PC1_IN, PC0_IN,
- /* Port D */
- PD15_IN, PD14_IN, PD13_IN, PD12_IN,
- PD11_IN, PD10_IN, PD9_IN, PD8_IN,
- PD7_IN, PD6_IN, PD5_IN, PD4_IN,
- PD3_IN, PD2_IN, PD1_IN, PD0_IN,
- /* Port E */
- PE7_IN, PE6_IN, PE5_IN, PE4_IN,
- PE3_IN, PE2_IN, PE1_IN, PE0_IN,
- /* Port F */
- PF23_IN, PF22_IN, PF21_IN, PF20_IN,
- PF19_IN, PF18_IN, PF17_IN, PF16_IN,
- PF15_IN, PF14_IN, PF13_IN, PF12_IN,
- PF11_IN, PF10_IN, PF9_IN, PF8_IN,
- PF7_IN, PF6_IN, PF5_IN, PF4_IN,
- PF3_IN, PF2_IN, PF1_IN, PF0_IN,
- /* Port G */
- PG27_IN, PG26_IN, PG25_IN, PG24_IN,
- PG23_IN, PG22_IN, PG21_IN, PG20_IN,
- PG19_IN, PG18_IN, PG17_IN, PG16_IN,
- PG15_IN, PG14_IN, PG13_IN, PG12_IN,
- PG11_IN, PG10_IN, PG9_IN, PG8_IN,
- PG7_IN, PG6_IN, PG5_IN, PG4_IN,
- PG3_IN, PG2_IN, PG1_IN, PG0_IN,
- /* Port H - Port H does not have a Data Register */
- /* Port I - not on device */
- /* Port J */
- PJ31_IN, PJ30_IN, PJ29_IN, PJ28_IN,
- PJ27_IN, PJ26_IN, PJ25_IN, PJ24_IN,
- PJ23_IN, PJ22_IN, PJ21_IN, PJ20_IN,
- PJ19_IN, PJ18_IN, PJ17_IN, PJ16_IN,
- PJ15_IN, PJ14_IN, PJ13_IN, PJ12_IN,
- PJ11_IN, PJ10_IN, PJ9_IN, PJ8_IN,
- PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
- PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
- PINMUX_INPUT_END,
-
- PINMUX_OUTPUT_BEGIN,
- FORCE_OUT,
- /* Port A */
- PA1_OUT, PA0_OUT,
- /* Port B */
- PB22_OUT, PB21_OUT, PB20_OUT,
- PB19_OUT, PB18_OUT, PB17_OUT, PB16_OUT,
- PB15_OUT, PB14_OUT, PB13_OUT, PB12_OUT,
- PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
- PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
- PB3_OUT, PB2_OUT, PB1_OUT,
- /* Port C */
- PC8_OUT,
- PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
- PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
- /* Port D */
- PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
- PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
- PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
- PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
- /* Port E */
- PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
- PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
- /* Port F */
- PF23_OUT, PF22_OUT, PF21_OUT, PF20_OUT,
- PF19_OUT, PF18_OUT, PF17_OUT, PF16_OUT,
- PF15_OUT, PF14_OUT, PF13_OUT, PF12_OUT,
- PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
- PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
- PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
- /* Port G */
- PG27_OUT, PG26_OUT, PG25_OUT, PG24_OUT,
- PG23_OUT, PG22_OUT, PG21_OUT, PG20_OUT,
- PG19_OUT, PG18_OUT, PG17_OUT, PG16_OUT,
- PG15_OUT, PG14_OUT, PG13_OUT, PG12_OUT,
- PG11_OUT, PG10_OUT, PG9_OUT, PG8_OUT,
- PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
- PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
- /* Port H - Port H does not have a Data Register */
- /* Port I - not on device */
- /* Port J */
- PJ31_OUT, PJ30_OUT, PJ29_OUT, PJ28_OUT,
- PJ27_OUT, PJ26_OUT, PJ25_OUT, PJ24_OUT,
- PJ23_OUT, PJ22_OUT, PJ21_OUT, PJ20_OUT,
- PJ19_OUT, PJ18_OUT, PJ17_OUT, PJ16_OUT,
- PJ15_OUT, PJ14_OUT, PJ13_OUT, PJ12_OUT,
- PJ11_OUT, PJ10_OUT, PJ9_OUT, PJ8_OUT,
- PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
- PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- /* Port A */
- PA1_IOR_IN, PA1_IOR_OUT,
- PA0_IOR_IN, PA0_IOR_OUT,
-
- /* Port B */
- PB22_IOR_IN, PB22_IOR_OUT,
- PB21_IOR_IN, PB21_IOR_OUT,
- PB20_IOR_IN, PB20_IOR_OUT,
- PB19_IOR_IN, PB19_IOR_OUT,
- PB18_IOR_IN, PB18_IOR_OUT,
- PB17_IOR_IN, PB17_IOR_OUT,
- PB16_IOR_IN, PB16_IOR_OUT,
-
- PB15_IOR_IN, PB15_IOR_OUT,
- PB14_IOR_IN, PB14_IOR_OUT,
- PB13_IOR_IN, PB13_IOR_OUT,
- PB12_IOR_IN, PB12_IOR_OUT,
- PB11_IOR_IN, PB11_IOR_OUT,
- PB10_IOR_IN, PB10_IOR_OUT,
- PB9_IOR_IN, PB9_IOR_OUT,
- PB8_IOR_IN, PB8_IOR_OUT,
-
- PB7_IOR_IN, PB7_IOR_OUT,
- PB6_IOR_IN, PB6_IOR_OUT,
- PB5_IOR_IN, PB5_IOR_OUT,
- PB4_IOR_IN, PB4_IOR_OUT,
- PB3_IOR_IN, PB3_IOR_OUT,
- PB2_IOR_IN, PB2_IOR_OUT,
- PB1_IOR_IN, PB1_IOR_OUT,
- PB0_IOR_IN, PB0_IOR_OUT,
-
- PB22MD_000, PB22MD_001, PB22MD_010, PB22MD_011,
- PB22MD_100, PB22MD_101, PB22MD_110, PB22MD_111,
- PB21MD_00, PB21MD_01, PB21MD_10, PB21MD_11,
- PB20MD_000, PB20MD_001, PB20MD_010, PB20MD_011,
- PB20MD_100, PB20MD_101, PB20MD_110, PB20MD_111,
- PB19MD_000, PB19MD_001, PB19MD_010, PB19MD_011,
- PB19MD_100, PB19MD_101, PB19MD_110, PB19MD_111,
- PB18MD_000, PB18MD_001, PB18MD_010, PB18MD_011,
- PB18MD_100, PB18MD_101, PB18MD_110, PB18MD_111,
- PB17MD_000, PB17MD_001, PB17MD_010, PB17MD_011,
- PB17MD_100, PB17MD_101, PB17MD_110, PB17MD_111,
- PB16MD_000, PB16MD_001, PB16MD_010, PB16MD_011,
- PB16MD_100, PB16MD_101, PB16MD_110, PB16MD_111,
- PB15MD_000, PB15MD_001, PB15MD_010, PB15MD_011,
- PB15MD_100, PB15MD_101, PB15MD_110, PB15MD_111,
- PB14MD_000, PB14MD_001, PB14MD_010, PB14MD_011,
- PB14MD_100, PB14MD_101, PB14MD_110, PB14MD_111,
- PB13MD_000, PB13MD_001, PB13MD_010, PB13MD_011,
- PB13MD_100, PB13MD_101, PB13MD_110, PB13MD_111,
- PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
-
- PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11,
- PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11,
- PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11,
- PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11,
-
- PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
- PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
- PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
- PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
-
- PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11,
- PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11,
- PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11,
-
- /* Port C */
- PC8_IOR_IN, PC8_IOR_OUT,
- PC7_IOR_IN, PC7_IOR_OUT,
- PC6_IOR_IN, PC6_IOR_OUT,
- PC5_IOR_IN, PC5_IOR_OUT,
- PC4_IOR_IN, PC4_IOR_OUT,
- PC3_IOR_IN, PC3_IOR_OUT,
- PC2_IOR_IN, PC2_IOR_OUT,
- PC1_IOR_IN, PC1_IOR_OUT,
- PC0_IOR_IN, PC0_IOR_OUT,
-
- PC8MD_000, PC8MD_001, PC8MD_010, PC8MD_011,
- PC8MD_100, PC8MD_101, PC8MD_110, PC8MD_111,
- PC7MD_000, PC7MD_001, PC7MD_010, PC7MD_011,
- PC7MD_100, PC7MD_101, PC7MD_110, PC7MD_111,
- PC6MD_000, PC6MD_001, PC6MD_010, PC6MD_011,
- PC6MD_100, PC6MD_101, PC6MD_110, PC6MD_111,
- PC5MD_000, PC5MD_001, PC5MD_010, PC5MD_011,
- PC5MD_100, PC5MD_101, PC5MD_110, PC5MD_111,
- PC4MD_00, PC4MD_01, PC4MD_10, PC4MD_11,
-
- PC3MD_00, PC3MD_01, PC3MD_10, PC3MD_11,
- PC2MD_00, PC2MD_01, PC2MD_10, PC2MD_11,
- PC1MD_0, PC1MD_1,
- PC0MD_0, PC0MD_1,
-
- /* Port D */
- PD15_IOR_IN, PD15_IOR_OUT,
- PD14_IOR_IN, PD14_IOR_OUT,
- PD13_IOR_IN, PD13_IOR_OUT,
- PD12_IOR_IN, PD12_IOR_OUT,
- PD11_IOR_IN, PD11_IOR_OUT,
- PD10_IOR_IN, PD10_IOR_OUT,
- PD9_IOR_IN, PD9_IOR_OUT,
- PD8_IOR_IN, PD8_IOR_OUT,
- PD7_IOR_IN, PD7_IOR_OUT,
- PD6_IOR_IN, PD6_IOR_OUT,
- PD5_IOR_IN, PD5_IOR_OUT,
- PD4_IOR_IN, PD4_IOR_OUT,
- PD3_IOR_IN, PD3_IOR_OUT,
- PD2_IOR_IN, PD2_IOR_OUT,
- PD1_IOR_IN, PD1_IOR_OUT,
- PD0_IOR_IN, PD0_IOR_OUT,
-
- PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11,
- PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11,
- PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11,
- PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11,
-
- PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11,
- PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11,
- PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11,
- PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11,
-
- PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11,
- PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11,
- PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11,
- PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11,
-
- PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11,
- PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11,
- PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11,
- PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11,
-
- /* Port E */
- PE7_IOR_IN, PE7_IOR_OUT,
- PE6_IOR_IN, PE6_IOR_OUT,
- PE5_IOR_IN, PE5_IOR_OUT,
- PE4_IOR_IN, PE4_IOR_OUT,
- PE3_IOR_IN, PE3_IOR_OUT,
- PE2_IOR_IN, PE2_IOR_OUT,
- PE1_IOR_IN, PE1_IOR_OUT,
- PE0_IOR_IN, PE0_IOR_OUT,
-
- PE7MD_00, PE7MD_01, PE7MD_10, PE7MD_11,
- PE6MD_00, PE6MD_01, PE6MD_10, PE6MD_11,
- PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11,
- PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11,
-
- PE3MD_000, PE3MD_001, PE3MD_010, PE3MD_011,
- PE3MD_100, PE3MD_101, PE3MD_110, PE3MD_111,
- PE2MD_000, PE2MD_001, PE2MD_010, PE2MD_011,
- PE2MD_100, PE2MD_101, PE2MD_110, PE2MD_111,
- PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
- PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
- PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11,
-
- /* Port F */
- PF23_IOR_IN, PF23_IOR_OUT,
- PF22_IOR_IN, PF22_IOR_OUT,
- PF21_IOR_IN, PF21_IOR_OUT,
- PF20_IOR_IN, PF20_IOR_OUT,
- PF19_IOR_IN, PF19_IOR_OUT,
- PF18_IOR_IN, PF18_IOR_OUT,
- PF17_IOR_IN, PF17_IOR_OUT,
- PF16_IOR_IN, PF16_IOR_OUT,
- PF15_IOR_IN, PF15_IOR_OUT,
- PF14_IOR_IN, PF14_IOR_OUT,
- PF13_IOR_IN, PF13_IOR_OUT,
- PF12_IOR_IN, PF12_IOR_OUT,
- PF11_IOR_IN, PF11_IOR_OUT,
- PF10_IOR_IN, PF10_IOR_OUT,
- PF9_IOR_IN, PF9_IOR_OUT,
- PF8_IOR_IN, PF8_IOR_OUT,
- PF7_IOR_IN, PF7_IOR_OUT,
- PF6_IOR_IN, PF6_IOR_OUT,
- PF5_IOR_IN, PF5_IOR_OUT,
- PF4_IOR_IN, PF4_IOR_OUT,
- PF3_IOR_IN, PF3_IOR_OUT,
- PF2_IOR_IN, PF2_IOR_OUT,
- PF1_IOR_IN, PF1_IOR_OUT,
- PF0_IOR_IN, PF0_IOR_OUT,
-
- PF23MD_000, PF23MD_001, PF23MD_010, PF23MD_011,
- PF23MD_100, PF23MD_101, PF23MD_110, PF23MD_111,
- PF22MD_000, PF22MD_001, PF22MD_010, PF22MD_011,
- PF22MD_100, PF22MD_101, PF22MD_110, PF22MD_111,
- PF21MD_000, PF21MD_001, PF21MD_010, PF21MD_011,
- PF21MD_100, PF21MD_101, PF21MD_110, PF21MD_111,
- PF20MD_000, PF20MD_001, PF20MD_010, PF20MD_011,
- PF20MD_100, PF20MD_101, PF20MD_110, PF20MD_111,
-
- PF19MD_000, PF19MD_001, PF19MD_010, PF19MD_011,
- PF19MD_100, PF19MD_101, PF19MD_110, PF19MD_111,
- PF18MD_000, PF18MD_001, PF18MD_010, PF18MD_011,
- PF18MD_100, PF18MD_101, PF18MD_110, PF18MD_111,
- PF17MD_000, PF17MD_001, PF17MD_010, PF17MD_011,
- PF17MD_100, PF17MD_101, PF17MD_110, PF17MD_111,
- PF16MD_000, PF16MD_001, PF16MD_010, PF16MD_011,
- PF16MD_100, PF16MD_101, PF16MD_110, PF16MD_111,
-
- PF15MD_000, PF15MD_001, PF15MD_010, PF15MD_011,
- PF15MD_100, PF15MD_101, PF15MD_110, PF15MD_111,
- PF14MD_000, PF14MD_001, PF14MD_010, PF14MD_011,
- PF14MD_100, PF14MD_101, PF14MD_110, PF14MD_111,
- PF13MD_000, PF13MD_001, PF13MD_010, PF13MD_011,
- PF13MD_100, PF13MD_101, PF13MD_110, PF13MD_111,
- PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
- PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
-
- PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
- PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
- PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
- PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
- PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
- PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
- PF8MD_000, PF8MD_001, PF8MD_010, PF8MD_011,
- PF8MD_100, PF8MD_101, PF8MD_110, PF8MD_111,
-
- PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
- PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
- PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
- PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
- PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
- PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
- PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
- PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
-
- PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
- PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
- PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
- PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
- PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
- PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
- PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
- PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
-
- /* Port G */
- PG27_IOR_IN, PG27_IOR_OUT,
- PG26_IOR_IN, PG26_IOR_OUT,
- PG25_IOR_IN, PG25_IOR_OUT,
- PG24_IOR_IN, PG24_IOR_OUT,
- PG23_IOR_IN, PG23_IOR_OUT,
- PG22_IOR_IN, PG22_IOR_OUT,
- PG21_IOR_IN, PG21_IOR_OUT,
- PG20_IOR_IN, PG20_IOR_OUT,
- PG19_IOR_IN, PG19_IOR_OUT,
- PG18_IOR_IN, PG18_IOR_OUT,
- PG17_IOR_IN, PG17_IOR_OUT,
- PG16_IOR_IN, PG16_IOR_OUT,
- PG15_IOR_IN, PG15_IOR_OUT,
- PG14_IOR_IN, PG14_IOR_OUT,
- PG13_IOR_IN, PG13_IOR_OUT,
- PG12_IOR_IN, PG12_IOR_OUT,
- PG11_IOR_IN, PG11_IOR_OUT,
- PG10_IOR_IN, PG10_IOR_OUT,
- PG9_IOR_IN, PG9_IOR_OUT,
- PG8_IOR_IN, PG8_IOR_OUT,
- PG7_IOR_IN, PG7_IOR_OUT,
- PG6_IOR_IN, PG6_IOR_OUT,
- PG5_IOR_IN, PG5_IOR_OUT,
- PG4_IOR_IN, PG4_IOR_OUT,
- PG3_IOR_IN, PG3_IOR_OUT,
- PG2_IOR_IN, PG2_IOR_OUT,
- PG1_IOR_IN, PG1_IOR_OUT,
- PG0_IOR_IN, PG0_IOR_OUT,
-
- PG27MD_00, PG27MD_01, PG27MD_10, PG27MD_11,
- PG26MD_00, PG26MD_01, PG26MD_10, PG26MD_11,
- PG25MD_00, PG25MD_01, PG25MD_10, PG25MD_11,
- PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11,
-
- PG23MD_000, PG23MD_001, PG23MD_010, PG23MD_011,
- PG23MD_100, PG23MD_101, PG23MD_110, PG23MD_111,
- PG22MD_000, PG22MD_001, PG22MD_010, PG22MD_011,
- PG22MD_100, PG22MD_101, PG22MD_110, PG22MD_111,
- PG21MD_000, PG21MD_001, PG21MD_010, PG21MD_011,
- PG21MD_100, PG21MD_101, PG21MD_110, PG21MD_111,
- PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
- PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
-
- PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
- PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
- PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
- PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
- PG17MD_00, PG17MD_01, PG17MD_10, PG17MD_11,
- PG16MD_00, PG16MD_01, PG16MD_10, PG16MD_11,
-
- PG15MD_00, PG15MD_01, PG15MD_10, PG15MD_11,
- PG14MD_00, PG14MD_01, PG14MD_10, PG14MD_11,
- PG13MD_00, PG13MD_01, PG13MD_10, PG13MD_11,
- PG12MD_00, PG12MD_01, PG12MD_10, PG12MD_11,
-
- PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
- PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
- PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
- PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
- PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
- PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
- PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
- PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
-
- PG7MD_000, PG7MD_001, PG7MD_010, PG7MD_011,
- PG7MD_100, PG7MD_101, PG7MD_110, PG7MD_111,
- PG6MD_000, PG6MD_001, PG6MD_010, PG6MD_011,
- PG6MD_100, PG6MD_101, PG6MD_110, PG6MD_111,
- PG5MD_000, PG5MD_001, PG5MD_010, PG5MD_011,
- PG5MD_100, PG5MD_101, PG5MD_110, PG5MD_111,
- PG4MD_000, PG4MD_001, PG4MD_010, PG4MD_011,
- PG4MD_100, PG4MD_101, PG4MD_110, PG4MD_111,
-
- PG3MD_000, PG3MD_001, PG3MD_010, PG3MD_011,
- PG3MD_100, PG3MD_101, PG3MD_110, PG3MD_111,
- PG2MD_000, PG2MD_001, PG2MD_010, PG2MD_011,
- PG2MD_100, PG2MD_101, PG2MD_110, PG2MD_111,
- PG1MD_000, PG1MD_001, PG1MD_010, PG1MD_011,
- PG1MD_100, PG1MD_101, PG1MD_110, PG1MD_111,
- PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
- PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
-
- /* Port H */
- PH7MD_00, PH7MD_01, PH7MD_10, PH7MD_11,
- PH6MD_00, PH6MD_01, PH6MD_10, PH6MD_11,
- PH5MD_00, PH5MD_01, PH5MD_10, PH5MD_11,
- PH4MD_00, PH4MD_01, PH4MD_10, PH4MD_11,
-
- PH3MD_00, PH3MD_01, PH3MD_10, PH3MD_11,
- PH2MD_00, PH2MD_01, PH2MD_10, PH2MD_11,
- PH1MD_00, PH1MD_01, PH1MD_10, PH1MD_11,
- PH0MD_00, PH0MD_01, PH0MD_10, PH0MD_11,
-
- /* Port I - not on device */
-
- /* Port J */
- PJ31_IOR_IN, PJ31_IOR_OUT,
- PJ30_IOR_IN, PJ30_IOR_OUT,
- PJ29_IOR_IN, PJ29_IOR_OUT,
- PJ28_IOR_IN, PJ28_IOR_OUT,
- PJ27_IOR_IN, PJ27_IOR_OUT,
- PJ26_IOR_IN, PJ26_IOR_OUT,
- PJ25_IOR_IN, PJ25_IOR_OUT,
- PJ24_IOR_IN, PJ24_IOR_OUT,
- PJ23_IOR_IN, PJ23_IOR_OUT,
- PJ22_IOR_IN, PJ22_IOR_OUT,
- PJ21_IOR_IN, PJ21_IOR_OUT,
- PJ20_IOR_IN, PJ20_IOR_OUT,
- PJ19_IOR_IN, PJ19_IOR_OUT,
- PJ18_IOR_IN, PJ18_IOR_OUT,
- PJ17_IOR_IN, PJ17_IOR_OUT,
- PJ16_IOR_IN, PJ16_IOR_OUT,
- PJ15_IOR_IN, PJ15_IOR_OUT,
- PJ14_IOR_IN, PJ14_IOR_OUT,
- PJ13_IOR_IN, PJ13_IOR_OUT,
- PJ12_IOR_IN, PJ12_IOR_OUT,
- PJ11_IOR_IN, PJ11_IOR_OUT,
- PJ10_IOR_IN, PJ10_IOR_OUT,
- PJ9_IOR_IN, PJ9_IOR_OUT,
- PJ8_IOR_IN, PJ8_IOR_OUT,
- PJ7_IOR_IN, PJ7_IOR_OUT,
- PJ6_IOR_IN, PJ6_IOR_OUT,
- PJ5_IOR_IN, PJ5_IOR_OUT,
- PJ4_IOR_IN, PJ4_IOR_OUT,
- PJ3_IOR_IN, PJ3_IOR_OUT,
- PJ2_IOR_IN, PJ2_IOR_OUT,
- PJ1_IOR_IN, PJ1_IOR_OUT,
- PJ0_IOR_IN, PJ0_IOR_OUT,
-
- PJ31MD_0, PJ31MD_1,
- PJ30MD_000, PJ30MD_001, PJ30MD_010, PJ30MD_011,
- PJ30MD_100, PJ30MD_101, PJ30MD_110, PJ30MD_111,
- PJ29MD_000, PJ29MD_001, PJ29MD_010, PJ29MD_011,
- PJ29MD_100, PJ29MD_101, PJ29MD_110, PJ29MD_111,
- PJ28MD_000, PJ28MD_001, PJ28MD_010, PJ28MD_011,
- PJ28MD_100, PJ28MD_101, PJ28MD_110, PJ28MD_111,
-
- PJ27MD_000, PJ27MD_001, PJ27MD_010, PJ27MD_011,
- PJ27MD_100, PJ27MD_101, PJ27MD_110, PJ27MD_111,
- PJ26MD_000, PJ26MD_001, PJ26MD_010, PJ26MD_011,
- PJ26MD_100, PJ26MD_101, PJ26MD_110, PJ26MD_111,
- PJ25MD_000, PJ25MD_001, PJ25MD_010, PJ25MD_011,
- PJ25MD_100, PJ25MD_101, PJ25MD_110, PJ25MD_111,
- PJ24MD_000, PJ24MD_001, PJ24MD_010, PJ24MD_011,
- PJ24MD_100, PJ24MD_101, PJ24MD_110, PJ24MD_111,
-
- PJ23MD_000, PJ23MD_001, PJ23MD_010, PJ23MD_011,
- PJ23MD_100, PJ23MD_101, PJ23MD_110, PJ23MD_111,
- PJ22MD_000, PJ22MD_001, PJ22MD_010, PJ22MD_011,
- PJ22MD_100, PJ22MD_101, PJ22MD_110, PJ22MD_111,
- PJ21MD_000, PJ21MD_001, PJ21MD_010, PJ21MD_011,
- PJ21MD_100, PJ21MD_101, PJ21MD_110, PJ21MD_111,
- PJ20MD_000, PJ20MD_001, PJ20MD_010, PJ20MD_011,
- PJ20MD_100, PJ20MD_101, PJ20MD_110, PJ20MD_111,
-
- PJ19MD_000, PJ19MD_001, PJ19MD_010, PJ19MD_011,
- PJ19MD_100, PJ19MD_101, PJ19MD_110, PJ19MD_111,
- PJ18MD_000, PJ18MD_001, PJ18MD_010, PJ18MD_011,
- PJ18MD_100, PJ18MD_101, PJ18MD_110, PJ18MD_111,
- PJ17MD_000, PJ17MD_001, PJ17MD_010, PJ17MD_011,
- PJ17MD_100, PJ17MD_101, PJ17MD_110, PJ17MD_111,
- PJ16MD_000, PJ16MD_001, PJ16MD_010, PJ16MD_011,
- PJ16MD_100, PJ16MD_101, PJ16MD_110, PJ16MD_111,
-
- PJ15MD_000, PJ15MD_001, PJ15MD_010, PJ15MD_011,
- PJ15MD_100, PJ15MD_101, PJ15MD_110, PJ15MD_111,
- PJ14MD_000, PJ14MD_001, PJ14MD_010, PJ14MD_011,
- PJ14MD_100, PJ14MD_101, PJ14MD_110, PJ14MD_111,
- PJ13MD_000, PJ13MD_001, PJ13MD_010, PJ13MD_011,
- PJ13MD_100, PJ13MD_101, PJ13MD_110, PJ13MD_111,
- PJ12MD_000, PJ12MD_001, PJ12MD_010, PJ12MD_011,
- PJ12MD_100, PJ12MD_101, PJ12MD_110, PJ12MD_111,
-
- PJ11MD_000, PJ11MD_001, PJ11MD_010, PJ11MD_011,
- PJ11MD_100, PJ11MD_101, PJ11MD_110, PJ11MD_111,
- PJ10MD_000, PJ10MD_001, PJ10MD_010, PJ10MD_011,
- PJ10MD_100, PJ10MD_101, PJ10MD_110, PJ10MD_111,
- PJ9MD_000, PJ9MD_001, PJ9MD_010, PJ9MD_011,
- PJ9MD_100, PJ9MD_101, PJ9MD_110, PJ9MD_111,
- PJ8MD_000, PJ8MD_001, PJ8MD_010, PJ8MD_011,
- PJ8MD_100, PJ8MD_101, PJ8MD_110, PJ8MD_111,
-
- PJ7MD_000, PJ7MD_001, PJ7MD_010, PJ7MD_011,
- PJ7MD_100, PJ7MD_101, PJ7MD_110, PJ7MD_111,
- PJ6MD_000, PJ6MD_001, PJ6MD_010, PJ6MD_011,
- PJ6MD_100, PJ6MD_101, PJ6MD_110, PJ6MD_111,
- PJ5MD_000, PJ5MD_001, PJ5MD_010, PJ5MD_011,
- PJ5MD_100, PJ5MD_101, PJ5MD_110, PJ5MD_111,
- PJ4MD_000, PJ4MD_001, PJ4MD_010, PJ4MD_011,
- PJ4MD_100, PJ4MD_101, PJ4MD_110, PJ4MD_111,
-
- PJ3MD_000, PJ3MD_001, PJ3MD_010, PJ3MD_011,
- PJ3MD_100, PJ3MD_101, PJ3MD_110, PJ3MD_111,
- PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
- PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
- PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
- PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
- PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
- PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
-
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
- /* Port H */
- PHAN7_MARK, PHAN6_MARK, PHAN5_MARK, PHAN4_MARK,
- PHAN3_MARK, PHAN2_MARK, PHAN1_MARK, PHAN0_MARK,
-
- /* IRQs */
- IRQ7_PG_MARK, IRQ6_PG_MARK, IRQ5_PG_MARK, IRQ4_PG_MARK,
- IRQ3_PG_MARK, IRQ2_PG_MARK, IRQ1_PG_MARK, IRQ0_PG_MARK,
- IRQ7_PF_MARK, IRQ6_PF_MARK, IRQ5_PF_MARK, IRQ4_PF_MARK,
- IRQ3_PJ_MARK, IRQ2_PJ_MARK, IRQ1_PJ_MARK, IRQ0_PJ_MARK,
- IRQ1_PC_MARK, IRQ0_PC_MARK,
-
- PINT7_PG_MARK, PINT6_PG_MARK, PINT5_PG_MARK, PINT4_PG_MARK,
- PINT3_PG_MARK, PINT2_PG_MARK, PINT1_PG_MARK, PINT0_PG_MARK,
- PINT7_PH_MARK, PINT6_PH_MARK, PINT5_PH_MARK, PINT4_PH_MARK,
- PINT3_PH_MARK, PINT2_PH_MARK, PINT1_PH_MARK, PINT0_PH_MARK,
- PINT7_PJ_MARK, PINT6_PJ_MARK, PINT5_PJ_MARK, PINT4_PJ_MARK,
- PINT3_PJ_MARK, PINT2_PJ_MARK, PINT1_PJ_MARK, PINT0_PJ_MARK,
-
- /* SD */
- SD_D0_MARK, SD_D1_MARK, SD_D2_MARK, SD_D3_MARK,
- SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK, SD_CD_MARK,
-
- /* MMC */
- MMC_D0_MARK, MMC_D1_MARK, MMC_D2_MARK, MMC_D3_MARK,
- MMC_D4_MARK, MMC_D5_MARK, MMC_D6_MARK, MMC_D7_MARK,
- MMC_CLK_MARK, MMC_CMD_MARK, MMC_CD_MARK,
-
- /* PWM */
- PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
- PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
- PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
- PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
-
- /* IEBus */
- IERXD_MARK, IETXD_MARK,
-
- /* WDT */
- WDTOVF_MARK,
-
- /* DMAC */
- TEND0_MARK, DACK0_MARK, DREQ0_MARK,
- TEND1_MARK, DACK1_MARK, DREQ1_MARK,
-
- /* ADC */
- ADTRG_MARK,
-
- /* BSC */
- A25_MARK, A24_MARK,
- A23_MARK, A22_MARK, A21_MARK, A20_MARK,
- A19_MARK, A18_MARK, A17_MARK, A16_MARK,
- A15_MARK, A14_MARK, A13_MARK, A12_MARK,
- A11_MARK, A10_MARK, A9_MARK, A8_MARK,
- A7_MARK, A6_MARK, A5_MARK, A4_MARK,
- A3_MARK, A2_MARK, A1_MARK, A0_MARK,
- D31_MARK, D30_MARK, D29_MARK, D28_MARK,
- D27_MARK, D26_MARK, D25_MARK, D24_MARK,
- D23_MARK, D22_MARK, D21_MARK, D20_MARK,
- D19_MARK, D18_MARK, D17_MARK, D16_MARK,
- D15_MARK, D14_MARK, D13_MARK, D12_MARK,
- D11_MARK, D10_MARK, D9_MARK, D8_MARK,
- D7_MARK, D6_MARK, D5_MARK, D4_MARK,
- D3_MARK, D2_MARK, D1_MARK, D0_MARK,
- BS_MARK,
- CS4_MARK, CS3_MARK, CS2_MARK, CS1_MARK, CS0_MARK,
- CS5CE1A_MARK,
- CE2A_MARK, CE2B_MARK,
- RD_MARK, RDWR_MARK,
- WE3ICIOWRAHDQMUU_MARK,
- WE2ICIORDDQMUL_MARK,
- WE1DQMUWE_MARK,
- WE0DQML_MARK,
- RAS_MARK, CAS_MARK, CKE_MARK,
- WAIT_MARK, BREQ_MARK, BACK_MARK, IOIS16_MARK,
-
- /* TMU */
- TIOC0A_MARK, TIOC0B_MARK, TIOC0C_MARK, TIOC0D_MARK,
- TIOC1A_MARK, TIOC1B_MARK,
- TIOC2A_MARK, TIOC2B_MARK,
- TIOC3A_MARK, TIOC3B_MARK, TIOC3C_MARK, TIOC3D_MARK,
- TIOC4A_MARK, TIOC4B_MARK, TIOC4C_MARK, TIOC4D_MARK,
- TCLKA_MARK, TCLKB_MARK, TCLKC_MARK, TCLKD_MARK,
-
- /* SCIF */
- SCK0_MARK, RXD0_MARK, TXD0_MARK,
- SCK1_MARK, RXD1_MARK, TXD1_MARK, RTS1_MARK, CTS1_MARK,
- SCK2_MARK, RXD2_MARK, TXD2_MARK,
- SCK3_MARK, RXD3_MARK, TXD3_MARK,
- SCK4_MARK, RXD4_MARK, TXD4_MARK,
- SCK5_MARK, RXD5_MARK, TXD5_MARK, RTS5_MARK, CTS5_MARK,
- SCK6_MARK, RXD6_MARK, TXD6_MARK,
- SCK7_MARK, RXD7_MARK, TXD7_MARK, RTS7_MARK, CTS7_MARK,
-
- /* RSPI */
- MISO0_PB20_MARK, MOSI0_PB19_MARK, SSL00_PB18_MARK, RSPCK0_PB17_MARK,
- MISO0_PJ19_MARK, MOSI0_PJ18_MARK, SSL00_PJ17_MARK, RSPCK0_PJ16_MARK,
- MISO1_MARK, MOSI1_MARK, SSL10_MARK, RSPCK1_MARK,
-
- /* IIC3 */
- SCL0_MARK, SDA0_MARK,
- SCL1_MARK, SDA1_MARK,
- SCL2_MARK, SDA2_MARK,
- SCL3_MARK, SDA3_MARK,
-
- /* SSI */
- SSISCK0_MARK, SSIWS0_MARK, SSITXD0_MARK, SSIRXD0_MARK,
- SSISCK1_MARK, SSIWS1_MARK, SSIDATA1_MARK,
- SSISCK2_MARK, SSIWS2_MARK, SSIDATA2_MARK,
- SSISCK3_MARK, SSIWS3_MARK, SSIDATA3_MARK,
- SSISCK4_MARK, SSIWS4_MARK, SSIDATA4_MARK,
- SSISCK5_MARK, SSIWS5_MARK, SSIDATA5_MARK,
- AUDIO_CLK_MARK,
- AUDIO_XOUT_MARK,
-
- /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
- SIOFTXD_MARK, SIOFRXD_MARK, SIOFSYNC_MARK, SIOFSCK_MARK,
-
- /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
- SPDIF_IN_MARK, SPDIF_OUT_MARK,
- SPDIF_IN_PJ24_MARK, SPDIF_OUT_PJ25_MARK,
-
- /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
- FCE_MARK,
- FRB_MARK,
-
- /* CAN */
- CRX0_MARK, CTX0_MARK,
- CRX1_MARK, CTX1_MARK,
- CRX2_MARK, CTX2_MARK,
- CRX0CRX1_MARK,
- CRX0CRX1CRX2_MARK,
- CTX0CTX1CTX2_MARK,
- CRX1_PJ22_MARK, CTX1_PJ23_MARK,
- CRX2_PJ20_MARK, CTX2_PJ21_MARK,
- CRX0CRX1_PJ22_MARK,
- CRX0CRX1CRX2_PJ20_MARK,
-
- /* VDC */
- DV_CLK_MARK,
- DV_VSYNC_MARK, DV_HSYNC_MARK,
- DV_DATA23_MARK, DV_DATA22_MARK, DV_DATA21_MARK, DV_DATA20_MARK,
- DV_DATA19_MARK, DV_DATA18_MARK, DV_DATA17_MARK, DV_DATA16_MARK,
- DV_DATA15_MARK, DV_DATA14_MARK, DV_DATA13_MARK, DV_DATA12_MARK,
- DV_DATA11_MARK, DV_DATA10_MARK, DV_DATA9_MARK, DV_DATA8_MARK,
- DV_DATA7_MARK, DV_DATA6_MARK, DV_DATA5_MARK, DV_DATA4_MARK,
- DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
- LCD_CLK_MARK, LCD_EXTCLK_MARK,
- LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
- LCD_DATA23_PG23_MARK, LCD_DATA22_PG22_MARK, LCD_DATA21_PG21_MARK,
- LCD_DATA20_PG20_MARK, LCD_DATA19_PG19_MARK, LCD_DATA18_PG18_MARK,
- LCD_DATA17_PG17_MARK, LCD_DATA16_PG16_MARK, LCD_DATA15_PG15_MARK,
- LCD_DATA14_PG14_MARK, LCD_DATA13_PG13_MARK, LCD_DATA12_PG12_MARK,
- LCD_DATA11_PG11_MARK, LCD_DATA10_PG10_MARK, LCD_DATA9_PG9_MARK,
- LCD_DATA8_PG8_MARK, LCD_DATA7_PG7_MARK, LCD_DATA6_PG6_MARK,
- LCD_DATA5_PG5_MARK, LCD_DATA4_PG4_MARK, LCD_DATA3_PG3_MARK,
- LCD_DATA2_PG2_MARK, LCD_DATA1_PG1_MARK, LCD_DATA0_PG0_MARK,
- LCD_DATA23_PJ23_MARK, LCD_DATA22_PJ22_MARK, LCD_DATA21_PJ21_MARK,
- LCD_DATA20_PJ20_MARK, LCD_DATA19_PJ19_MARK, LCD_DATA18_PJ18_MARK,
- LCD_DATA17_PJ17_MARK, LCD_DATA16_PJ16_MARK, LCD_DATA15_PJ15_MARK,
- LCD_DATA14_PJ14_MARK, LCD_DATA13_PJ13_MARK, LCD_DATA12_PJ12_MARK,
- LCD_DATA11_PJ11_MARK, LCD_DATA10_PJ10_MARK, LCD_DATA9_PJ9_MARK,
- LCD_DATA8_PJ8_MARK, LCD_DATA7_PJ7_MARK, LCD_DATA6_PJ6_MARK,
- LCD_DATA5_PJ5_MARK, LCD_DATA4_PJ4_MARK, LCD_DATA3_PJ3_MARK,
- LCD_DATA2_PJ2_MARK, LCD_DATA1_PJ1_MARK, LCD_DATA0_PJ0_MARK,
- LCD_TCON6_MARK, LCD_TCON5_MARK, LCD_TCON4_MARK,
- LCD_TCON3_MARK, LCD_TCON2_MARK, LCD_TCON1_MARK, LCD_TCON0_MARK,
- LCD_M_DISP_MARK,
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
-
- /* Port A */
- PINMUX_DATA(PA1_DATA, PA1_IN),
- PINMUX_DATA(PA0_DATA, PA0_IN),
-
- /* Port B */
- PINMUX_DATA(PB22_DATA, PB22MD_000, PB22_IN, PB22_OUT),
- PINMUX_DATA(A22_MARK, PB22MD_001),
- PINMUX_DATA(CTX2_MARK, PB22MD_010),
- PINMUX_DATA(IETXD_MARK, PB22MD_011),
- PINMUX_DATA(CS4_MARK, PB22MD_100),
-
- PINMUX_DATA(PB21_DATA, PB21MD_00, PB21_IN, PB21_OUT),
- PINMUX_DATA(A21_MARK, PB21MD_01),
- PINMUX_DATA(CRX2_MARK, PB21MD_10),
- PINMUX_DATA(IERXD_MARK, PB21MD_11),
-
- PINMUX_DATA(A20_MARK, PB20MD_001),
- PINMUX_DATA(A19_MARK, PB19MD_001),
- PINMUX_DATA(A18_MARK, PB18MD_001),
- PINMUX_DATA(A17_MARK, PB17MD_001),
- PINMUX_DATA(A16_MARK, PB16MD_001),
- PINMUX_DATA(A15_MARK, PB15MD_001),
- PINMUX_DATA(A14_MARK, PB14MD_001),
- PINMUX_DATA(A13_MARK, PB13MD_001),
- PINMUX_DATA(A12_MARK, PB12MD_01),
- PINMUX_DATA(A11_MARK, PB11MD_01),
- PINMUX_DATA(A10_MARK, PB10MD_01),
- PINMUX_DATA(A9_MARK, PB9MD_01),
- PINMUX_DATA(A8_MARK, PB8MD_01),
- PINMUX_DATA(A7_MARK, PB7MD_01),
- PINMUX_DATA(A6_MARK, PB6MD_01),
- PINMUX_DATA(A5_MARK, PB5MD_01),
- PINMUX_DATA(A4_MARK, PB4MD_01),
- PINMUX_DATA(A3_MARK, PB3MD_01),
- PINMUX_DATA(A2_MARK, PB2MD_01),
- PINMUX_DATA(A1_MARK, PB1MD_01),
-
- /* Port C */
- PINMUX_DATA(PC8_DATA, PC8MD_000),
- PINMUX_DATA(CS3_MARK, PC8MD_001),
- PINMUX_DATA(TXD7_MARK, PC8MD_010),
- PINMUX_DATA(CTX1_MARK, PC8MD_011),
-
- PINMUX_DATA(PC7_DATA, PC7MD_000),
- PINMUX_DATA(CKE_MARK, PC7MD_001),
- PINMUX_DATA(RXD7_MARK, PC7MD_010),
- PINMUX_DATA(CRX1_MARK, PC7MD_011),
- PINMUX_DATA(CRX0CRX1_MARK, PC7MD_100),
- PINMUX_DATA(IRQ1_PC_MARK, PC7MD_101),
-
- PINMUX_DATA(PC6_DATA, PC6MD_000),
- PINMUX_DATA(CAS_MARK, PC6MD_001),
- PINMUX_DATA(SCK7_MARK, PC6MD_010),
- PINMUX_DATA(CTX0_MARK, PC6MD_011),
-
- PINMUX_DATA(PC5_DATA, PC5MD_000),
- PINMUX_DATA(RAS_MARK, PC5MD_001),
- PINMUX_DATA(CRX0_MARK, PC5MD_011),
- PINMUX_DATA(CTX0CTX1CTX2_MARK, PC5MD_100),
- PINMUX_DATA(IRQ0_PC_MARK, PC5MD_101),
-
- PINMUX_DATA(PC4_DATA, PC4MD_00),
- PINMUX_DATA(WE1DQMUWE_MARK, PC4MD_01),
- PINMUX_DATA(TXD6_MARK, PC4MD_10),
-
- PINMUX_DATA(PC3_DATA, PC3MD_00),
- PINMUX_DATA(WE0DQML_MARK, PC3MD_01),
- PINMUX_DATA(RXD6_MARK, PC3MD_10),
-
- PINMUX_DATA(PC2_DATA, PC2MD_00),
- PINMUX_DATA(RDWR_MARK, PC2MD_01),
- PINMUX_DATA(SCK5_MARK, PC2MD_10),
-
- PINMUX_DATA(PC1_DATA, PC1MD_0),
- PINMUX_DATA(RD_MARK, PC1MD_1),
-
- PINMUX_DATA(PC0_DATA, PC0MD_0),
- PINMUX_DATA(CS0_MARK, PC0MD_1),
-
- /* Port D */
- PINMUX_DATA(D15_MARK, PD15MD_01),
- PINMUX_DATA(D14_MARK, PD14MD_01),
-
- PINMUX_DATA(PD13_DATA, PD13MD_00),
- PINMUX_DATA(D13_MARK, PD13MD_01),
- PINMUX_DATA(PWM2F_MARK, PD13MD_10),
-
- PINMUX_DATA(PD12_DATA, PD12MD_00),
- PINMUX_DATA(D12_MARK, PD12MD_01),
- PINMUX_DATA(PWM2E_MARK, PD12MD_10),
-
- PINMUX_DATA(D11_MARK, PD11MD_01),
- PINMUX_DATA(D10_MARK, PD10MD_01),
- PINMUX_DATA(D9_MARK, PD9MD_01),
- PINMUX_DATA(D8_MARK, PD8MD_01),
- PINMUX_DATA(D7_MARK, PD7MD_01),
- PINMUX_DATA(D6_MARK, PD6MD_01),
- PINMUX_DATA(D5_MARK, PD5MD_01),
- PINMUX_DATA(D4_MARK, PD4MD_01),
- PINMUX_DATA(D3_MARK, PD3MD_01),
- PINMUX_DATA(D2_MARK, PD2MD_01),
- PINMUX_DATA(D1_MARK, PD1MD_01),
- PINMUX_DATA(D0_MARK, PD0MD_01),
-
- /* Port E */
- PINMUX_DATA(PE7_DATA, PE7MD_00),
- PINMUX_DATA(SDA3_MARK, PE7MD_01),
- PINMUX_DATA(RXD7_MARK, PE7MD_10),
-
- PINMUX_DATA(PE6_DATA, PE6MD_00),
- PINMUX_DATA(SCL3_MARK, PE6MD_01),
- PINMUX_DATA(RXD6_MARK, PE6MD_10),
-
- PINMUX_DATA(PE5_DATA, PE5MD_00),
- PINMUX_DATA(SDA2_MARK, PE5MD_01),
- PINMUX_DATA(RXD5_MARK, PE5MD_10),
- PINMUX_DATA(DV_HSYNC_MARK, PE5MD_11),
-
- PINMUX_DATA(PE4_DATA, PE4MD_00),
- PINMUX_DATA(SCL2_MARK, PE4MD_01),
- PINMUX_DATA(DV_VSYNC_MARK, PE4MD_11),
-
- PINMUX_DATA(PE3_DATA, PE3MD_000),
- PINMUX_DATA(SDA1_MARK, PE3MD_001),
- PINMUX_DATA(TCLKD_MARK, PE3MD_010),
- PINMUX_DATA(ADTRG_MARK, PE3MD_011),
- PINMUX_DATA(DV_HSYNC_MARK, PE3MD_100),
-
- PINMUX_DATA(PE2_DATA, PE2MD_000),
- PINMUX_DATA(SCL1_MARK, PE2MD_001),
- PINMUX_DATA(TCLKD_MARK, PE2MD_010),
- PINMUX_DATA(IOIS16_MARK, PE2MD_011),
- PINMUX_DATA(DV_VSYNC_MARK, PE2MD_100),
-
- PINMUX_DATA(PE1_DATA, PE1MD_000),
- PINMUX_DATA(SDA0_MARK, PE1MD_001),
- PINMUX_DATA(TCLKB_MARK, PE1MD_010),
- PINMUX_DATA(AUDIO_CLK_MARK, PE1MD_010),
- PINMUX_DATA(DV_CLK_MARK, PE1MD_100),
-
- PINMUX_DATA(PE0_DATA, PE0MD_00),
- PINMUX_DATA(SCL0_MARK, PE0MD_01),
- PINMUX_DATA(TCLKA_MARK, PE0MD_10),
- PINMUX_DATA(LCD_EXTCLK_MARK, PE0MD_11),
-
- /* Port F */
- PINMUX_DATA(PF23_DATA, PF23MD_000),
- PINMUX_DATA(SD_D2_MARK, PF23MD_001),
- PINMUX_DATA(TXD3_MARK, PF23MD_100),
- PINMUX_DATA(MMC_D2_MARK, PF23MD_101),
-
- PINMUX_DATA(PF22_DATA, PF22MD_000),
- PINMUX_DATA(SD_D3_MARK, PF22MD_001),
- PINMUX_DATA(RXD3_MARK, PF22MD_100),
- PINMUX_DATA(MMC_D3_MARK, PF22MD_101),
-
- PINMUX_DATA(PF21_DATA, PF21MD_000),
- PINMUX_DATA(SD_CMD_MARK, PF21MD_001),
- PINMUX_DATA(SCK3_MARK, PF21MD_100),
- PINMUX_DATA(MMC_CMD_MARK, PF21MD_101),
-
- PINMUX_DATA(PF20_DATA, PF20MD_000),
- PINMUX_DATA(SD_CLK_MARK, PF20MD_001),
- PINMUX_DATA(SSIDATA3_MARK, PF20MD_010),
- PINMUX_DATA(MMC_CLK_MARK, PF20MD_101),
-
- PINMUX_DATA(PF19_DATA, PF19MD_000),
- PINMUX_DATA(SD_D0_MARK, PF19MD_001),
- PINMUX_DATA(SSIWS3_MARK, PF19MD_010),
- PINMUX_DATA(IRQ7_PF_MARK, PF19MD_100),
- PINMUX_DATA(MMC_D0_MARK, PF19MD_101),
-
- PINMUX_DATA(PF18_DATA, PF18MD_000),
- PINMUX_DATA(SD_D1_MARK, PF18MD_001),
- PINMUX_DATA(SSISCK3_MARK, PF18MD_010),
- PINMUX_DATA(IRQ6_PF_MARK, PF18MD_100),
- PINMUX_DATA(MMC_D1_MARK, PF18MD_101),
-
- PINMUX_DATA(PF17_DATA, PF17MD_000),
- PINMUX_DATA(SD_WP_MARK, PF17MD_001),
- PINMUX_DATA(FRB_MARK, PF17MD_011),
- PINMUX_DATA(IRQ5_PF_MARK, PF17MD_100),
-
- PINMUX_DATA(PF16_DATA, PF16MD_000),
- PINMUX_DATA(SD_CD_MARK, PF16MD_001),
- PINMUX_DATA(FCE_MARK, PF16MD_011),
- PINMUX_DATA(IRQ4_PF_MARK, PF16MD_100),
- PINMUX_DATA(MMC_CD_MARK, PF16MD_101),
-
- PINMUX_DATA(PF15_DATA, PF15MD_000),
- PINMUX_DATA(A0_MARK, PF15MD_001),
- PINMUX_DATA(SSIDATA2_MARK, PF15MD_010),
- PINMUX_DATA(WDTOVF_MARK, PF15MD_011),
- PINMUX_DATA(TXD2_MARK, PF15MD_100),
-
- PINMUX_DATA(PF14_DATA, PF14MD_000),
- PINMUX_DATA(A25_MARK, PF14MD_001),
- PINMUX_DATA(SSIWS2_MARK, PF14MD_010),
- PINMUX_DATA(RXD2_MARK, PF14MD_100),
-
- PINMUX_DATA(PF13_DATA, PF13MD_000),
- PINMUX_DATA(A24_MARK, PF13MD_001),
- PINMUX_DATA(SSISCK2_MARK, PF13MD_010),
- PINMUX_DATA(SCK2_MARK, PF13MD_100),
-
- PINMUX_DATA(PF12_DATA, PF12MD_000),
- PINMUX_DATA(SSIDATA1_MARK, PF12MD_010),
- PINMUX_DATA(DV_DATA12_MARK, PF12MD_011),
- PINMUX_DATA(TXD1_MARK, PF12MD_100),
- PINMUX_DATA(MMC_D7_MARK, PF12MD_101),
-
- PINMUX_DATA(PF11_DATA, PF11MD_000),
- PINMUX_DATA(SSIWS1_MARK, PF11MD_010),
- PINMUX_DATA(DV_DATA2_MARK, PF11MD_011),
- PINMUX_DATA(RXD1_MARK, PF11MD_100),
- PINMUX_DATA(MMC_D6_MARK, PF11MD_101),
-
- PINMUX_DATA(PF10_DATA, PF10MD_000),
- PINMUX_DATA(CS1_MARK, PF10MD_001),
- PINMUX_DATA(SSISCK1_MARK, PF10MD_010),
- PINMUX_DATA(DV_DATA1_MARK, PF10MD_011),
- PINMUX_DATA(SCK1_MARK, PF10MD_100),
- PINMUX_DATA(MMC_D5_MARK, PF10MD_101),
-
- PINMUX_DATA(PF9_DATA, PF9MD_000),
- PINMUX_DATA(BS_MARK, PF9MD_001),
- PINMUX_DATA(DV_DATA0_MARK, PF9MD_011),
- PINMUX_DATA(SCK0_MARK, PF9MD_100),
- PINMUX_DATA(MMC_D4_MARK, PF9MD_101),
- PINMUX_DATA(RTS1_MARK, PF9MD_110),
-
- PINMUX_DATA(PF8_DATA, PF8MD_000),
- PINMUX_DATA(A23_MARK, PF8MD_001),
- PINMUX_DATA(TXD0_MARK, PF8MD_100),
-
- PINMUX_DATA(PF7_DATA, PF7MD_000),
- PINMUX_DATA(SSIRXD0_MARK, PF7MD_010),
- PINMUX_DATA(RXD0_MARK, PF7MD_100),
- PINMUX_DATA(CTS1_MARK, PF7MD_110),
-
- PINMUX_DATA(PF6_DATA, PF6MD_000),
- PINMUX_DATA(CE2A_MARK, PF6MD_001),
- PINMUX_DATA(SSITXD0_MARK, PF6MD_010),
-
- PINMUX_DATA(PF5_DATA, PF5MD_000),
- PINMUX_DATA(SSIWS0_MARK, PF5MD_010),
-
- PINMUX_DATA(PF4_DATA, PF4MD_000),
- PINMUX_DATA(CS5CE1A_MARK, PF4MD_001),
- PINMUX_DATA(SSISCK0_MARK, PF4MD_010),
-
- PINMUX_DATA(PF3_DATA, PF3MD_000),
- PINMUX_DATA(CS2_MARK, PF3MD_001),
- PINMUX_DATA(MISO1_MARK, PF3MD_011),
- PINMUX_DATA(TIOC4D_MARK, PF3MD_100),
-
- PINMUX_DATA(PF2_DATA, PF2MD_000),
- PINMUX_DATA(WAIT_MARK, PF2MD_001),
- PINMUX_DATA(MOSI1_MARK, PF2MD_011),
- PINMUX_DATA(TIOC4C_MARK, PF2MD_100),
- PINMUX_DATA(TEND0_MARK, PF2MD_101),
-
- PINMUX_DATA(PF1_DATA, PF1MD_000),
- PINMUX_DATA(BACK_MARK, PF1MD_001),
- PINMUX_DATA(SSL10_MARK, PF1MD_011),
- PINMUX_DATA(TIOC4B_MARK, PF1MD_100),
- PINMUX_DATA(DACK0_MARK, PF1MD_101),
-
- PINMUX_DATA(PF0_DATA, PF0MD_000),
- PINMUX_DATA(BREQ_MARK, PF0MD_001),
- PINMUX_DATA(RSPCK1_MARK, PF0MD_011),
- PINMUX_DATA(TIOC4A_MARK, PF0MD_100),
- PINMUX_DATA(DREQ0_MARK, PF0MD_101),
-
- /* Port G */
- PINMUX_DATA(PG27_DATA, PG27MD_00),
- PINMUX_DATA(LCD_TCON2_MARK, PG27MD_10),
- PINMUX_DATA(LCD_EXTCLK_MARK, PG27MD_11),
- PINMUX_DATA(LCD_DE_MARK, PG27MD_11),
-
- PINMUX_DATA(PG26_DATA, PG26MD_00),
- PINMUX_DATA(LCD_TCON1_MARK, PG26MD_10),
- PINMUX_DATA(LCD_HSYNC_MARK, PG26MD_10),
-
- PINMUX_DATA(PG25_DATA, PG25MD_00),
- PINMUX_DATA(LCD_TCON0_MARK, PG25MD_10),
- PINMUX_DATA(LCD_VSYNC_MARK, PG25MD_10),
-
- PINMUX_DATA(PG24_DATA, PG24MD_00),
- PINMUX_DATA(LCD_CLK_MARK, PG24MD_10),
-
- PINMUX_DATA(PG23_DATA, PG23MD_000),
- PINMUX_DATA(LCD_DATA23_PG23_MARK, PG23MD_010),
- PINMUX_DATA(LCD_TCON6_MARK, PG23MD_011),
- PINMUX_DATA(TXD5_MARK, PG23MD_100),
-
- PINMUX_DATA(PG22_DATA, PG22MD_000),
- PINMUX_DATA(LCD_DATA22_PG22_MARK, PG22MD_010),
- PINMUX_DATA(LCD_TCON5_MARK, PG22MD_011),
- PINMUX_DATA(RXD5_MARK, PG22MD_100),
-
- PINMUX_DATA(PG21_DATA, PG21MD_000),
- PINMUX_DATA(DV_DATA7_MARK, PG21MD_001),
- PINMUX_DATA(LCD_DATA21_PG21_MARK, PG21MD_010),
- PINMUX_DATA(LCD_TCON4_MARK, PG21MD_011),
- PINMUX_DATA(TXD4_MARK, PG21MD_100),
-
- PINMUX_DATA(PG20_DATA, PG20MD_000),
- PINMUX_DATA(DV_DATA6_MARK, PG20MD_001),
- PINMUX_DATA(LCD_DATA20_PG20_MARK, PG21MD_010),
- PINMUX_DATA(LCD_TCON3_MARK, PG20MD_011),
- PINMUX_DATA(RXD4_MARK, PG20MD_100),
-
- PINMUX_DATA(PG19_DATA, PG19MD_000),
- PINMUX_DATA(DV_DATA5_MARK, PG19MD_001),
- PINMUX_DATA(LCD_DATA19_PG19_MARK, PG19MD_010),
- PINMUX_DATA(SPDIF_OUT_MARK, PG19MD_011),
- PINMUX_DATA(SCK5_MARK, PG19MD_100),
-
- PINMUX_DATA(PG18_DATA, PG18MD_000),
- PINMUX_DATA(DV_DATA4_MARK, PG18MD_001),
- PINMUX_DATA(LCD_DATA18_PG18_MARK, PG18MD_010),
- PINMUX_DATA(SPDIF_IN_MARK, PG18MD_011),
- PINMUX_DATA(SCK4_MARK, PG18MD_100),
-
-// TODO hardware manual has PG17 3 bits wide in reg picture and 2 bits in description
-// we're going with 2 bits
- PINMUX_DATA(PG17_DATA, PG17MD_00),
- PINMUX_DATA(WE3ICIOWRAHDQMUU_MARK, PG17MD_01),
- PINMUX_DATA(LCD_DATA17_PG17_MARK, PG17MD_10),
-
-// TODO hardware manual has PG16 3 bits wide in reg picture and 2 bits in description
-// we're going with 2 bits
- PINMUX_DATA(PG16_DATA, PG16MD_00),
- PINMUX_DATA(WE2ICIORDDQMUL_MARK, PG16MD_01),
- PINMUX_DATA(LCD_DATA16_PG16_MARK, PG16MD_10),
-
- PINMUX_DATA(PG15_DATA, PG15MD_00),
- PINMUX_DATA(D31_MARK, PG15MD_01),
- PINMUX_DATA(LCD_DATA15_PG15_MARK, PG15MD_10),
- PINMUX_DATA(PINT7_PG_MARK, PG15MD_11),
-
- PINMUX_DATA(PG14_DATA, PG14MD_00),
- PINMUX_DATA(D30_MARK, PG14MD_01),
- PINMUX_DATA(LCD_DATA14_PG14_MARK, PG14MD_10),
- PINMUX_DATA(PINT6_PG_MARK, PG14MD_11),
-
- PINMUX_DATA(PG13_DATA, PG13MD_00),
- PINMUX_DATA(D29_MARK, PG13MD_01),
- PINMUX_DATA(LCD_DATA13_PG13_MARK, PG13MD_10),
- PINMUX_DATA(PINT5_PG_MARK, PG13MD_11),
-
- PINMUX_DATA(PG12_DATA, PG12MD_00),
- PINMUX_DATA(D28_MARK, PG12MD_01),
- PINMUX_DATA(LCD_DATA12_PG12_MARK, PG12MD_10),
- PINMUX_DATA(PINT4_PG_MARK, PG12MD_11),
-
- PINMUX_DATA(PG11_DATA, PG11MD_000),
- PINMUX_DATA(D27_MARK, PG11MD_001),
- PINMUX_DATA(LCD_DATA11_PG11_MARK, PG11MD_010),
- PINMUX_DATA(PINT3_PG_MARK, PG11MD_011),
- PINMUX_DATA(TIOC3D_MARK, PG11MD_100),
-
- PINMUX_DATA(PG10_DATA, PG10MD_000),
- PINMUX_DATA(D26_MARK, PG10MD_001),
- PINMUX_DATA(LCD_DATA10_PG10_MARK, PG10MD_010),
- PINMUX_DATA(PINT2_PG_MARK, PG10MD_011),
- PINMUX_DATA(TIOC3C_MARK, PG10MD_100),
-
- PINMUX_DATA(PG9_DATA, PG9MD_000),
- PINMUX_DATA(D25_MARK, PG9MD_001),
- PINMUX_DATA(LCD_DATA9_PG9_MARK, PG9MD_010),
- PINMUX_DATA(PINT1_PG_MARK, PG9MD_011),
- PINMUX_DATA(TIOC3B_MARK, PG9MD_100),
-
- PINMUX_DATA(PG8_DATA, PG8MD_000),
- PINMUX_DATA(D24_MARK, PG8MD_001),
- PINMUX_DATA(LCD_DATA8_PG8_MARK, PG8MD_010),
- PINMUX_DATA(PINT0_PG_MARK, PG8MD_011),
- PINMUX_DATA(TIOC3A_MARK, PG8MD_100),
-
- PINMUX_DATA(PG7_DATA, PG7MD_000),
- PINMUX_DATA(D23_MARK, PG7MD_001),
- PINMUX_DATA(LCD_DATA7_PG7_MARK, PG7MD_010),
- PINMUX_DATA(IRQ7_PG_MARK, PG7MD_011),
- PINMUX_DATA(TIOC2B_MARK, PG7MD_100),
-
- PINMUX_DATA(PG6_DATA, PG6MD_000),
- PINMUX_DATA(D22_MARK, PG6MD_001),
- PINMUX_DATA(LCD_DATA6_PG6_MARK, PG6MD_010),
- PINMUX_DATA(IRQ6_PG_MARK, PG6MD_011),
- PINMUX_DATA(TIOC2A_MARK, PG6MD_100),
-
- PINMUX_DATA(PG5_DATA, PG5MD_000),
- PINMUX_DATA(D21_MARK, PG5MD_001),
- PINMUX_DATA(LCD_DATA5_PG5_MARK, PG5MD_010),
- PINMUX_DATA(IRQ5_PG_MARK, PG5MD_011),
- PINMUX_DATA(TIOC1B_MARK, PG5MD_100),
-
- PINMUX_DATA(PG4_DATA, PG4MD_000),
- PINMUX_DATA(D20_MARK, PG4MD_001),
- PINMUX_DATA(LCD_DATA4_PG4_MARK, PG4MD_010),
- PINMUX_DATA(IRQ4_PG_MARK, PG4MD_011),
- PINMUX_DATA(TIOC1A_MARK, PG4MD_100),
-
- PINMUX_DATA(PG3_DATA, PG3MD_000),
- PINMUX_DATA(D19_MARK, PG3MD_001),
- PINMUX_DATA(LCD_DATA3_PG3_MARK, PG3MD_010),
- PINMUX_DATA(IRQ3_PG_MARK, PG3MD_011),
- PINMUX_DATA(TIOC0D_MARK, PG3MD_100),
-
- PINMUX_DATA(PG2_DATA, PG2MD_000),
- PINMUX_DATA(D18_MARK, PG2MD_001),
- PINMUX_DATA(LCD_DATA2_PG2_MARK, PG2MD_010),
- PINMUX_DATA(IRQ2_PG_MARK, PG2MD_011),
- PINMUX_DATA(TIOC0C_MARK, PG2MD_100),
-
- PINMUX_DATA(PG1_DATA, PG1MD_000),
- PINMUX_DATA(D17_MARK, PG1MD_001),
- PINMUX_DATA(LCD_DATA1_PG1_MARK, PG1MD_010),
- PINMUX_DATA(IRQ1_PG_MARK, PG1MD_011),
- PINMUX_DATA(TIOC0B_MARK, PG1MD_100),
-
- PINMUX_DATA(PG0_DATA, PG0MD_000),
- PINMUX_DATA(D16_MARK, PG0MD_001),
- PINMUX_DATA(LCD_DATA0_PG0_MARK, PG0MD_010),
- PINMUX_DATA(IRQ0_PG_MARK, PG0MD_011),
- PINMUX_DATA(TIOC0A_MARK, PG0MD_100),
-
- /* Port H */
- PINMUX_DATA(PH7_DATA, PH7MD_00),
- PINMUX_DATA(PHAN7_MARK, PH7MD_01),
- PINMUX_DATA(PINT7_PH_MARK, PH7MD_10),
-
- PINMUX_DATA(PH6_DATA, PH6MD_00),
- PINMUX_DATA(PHAN6_MARK, PH6MD_01),
- PINMUX_DATA(PINT6_PH_MARK, PH6MD_10),
-
- PINMUX_DATA(PH5_DATA, PH5MD_00),
- PINMUX_DATA(PHAN5_MARK, PH5MD_01),
- PINMUX_DATA(PINT5_PH_MARK, PH5MD_10),
- PINMUX_DATA(LCD_EXTCLK_MARK, PH5MD_11),
-
- PINMUX_DATA(PH4_DATA, PH4MD_00),
- PINMUX_DATA(PHAN4_MARK, PH4MD_01),
- PINMUX_DATA(PINT4_PH_MARK, PH4MD_10),
-
- PINMUX_DATA(PH3_DATA, PH3MD_00),
- PINMUX_DATA(PHAN3_MARK, PH3MD_01),
- PINMUX_DATA(PINT3_PH_MARK, PH3MD_10),
-
- PINMUX_DATA(PH2_DATA, PH2MD_00),
- PINMUX_DATA(PHAN2_MARK, PH2MD_01),
- PINMUX_DATA(PINT2_PH_MARK, PH2MD_10),
-
- PINMUX_DATA(PH1_DATA, PH1MD_00),
- PINMUX_DATA(PHAN1_MARK, PH1MD_01),
- PINMUX_DATA(PINT1_PH_MARK, PH1MD_10),
-
- PINMUX_DATA(PH0_DATA, PH0MD_00),
- PINMUX_DATA(PHAN0_MARK, PH0MD_01),
- PINMUX_DATA(PINT0_PH_MARK, PH0MD_10),
-
- /* Port I - not on device */
-
- /* Port J */
- PINMUX_DATA(PJ31_DATA, PJ31MD_0),
- PINMUX_DATA(DV_CLK_MARK, PJ31MD_1),
-
- PINMUX_DATA(PJ30_DATA, PJ30MD_000),
- PINMUX_DATA(SSIDATA5_MARK, PJ30MD_010),
- PINMUX_DATA(TIOC2B_MARK, PJ30MD_100),
- PINMUX_DATA(IETXD_MARK, PJ30MD_101),
-
- PINMUX_DATA(PJ29_DATA, PJ29MD_000),
- PINMUX_DATA(SSIWS5_MARK, PJ29MD_010),
- PINMUX_DATA(TIOC2A_MARK, PJ29MD_100),
- PINMUX_DATA(IERXD_MARK, PJ29MD_101),
-
- PINMUX_DATA(PJ28_DATA, PJ28MD_000),
- PINMUX_DATA(SSISCK5_MARK, PJ28MD_010),
- PINMUX_DATA(TIOC1B_MARK, PJ28MD_100),
- PINMUX_DATA(RTS7_MARK, PJ28MD_101),
-
- PINMUX_DATA(PJ27_DATA, PJ27MD_000),
- PINMUX_DATA(TIOC1A_MARK, PJ27MD_100),
- PINMUX_DATA(CTS7_MARK, PJ27MD_101),
-
- PINMUX_DATA(PJ26_DATA, PJ26MD_000),
- PINMUX_DATA(SSIDATA4_MARK, PJ26MD_010),
- PINMUX_DATA(LCD_TCON5_MARK, PJ26MD_011),
- PINMUX_DATA(TXD7_MARK, PJ26MD_101),
-
- PINMUX_DATA(PJ25_DATA, PJ25MD_000),
- PINMUX_DATA(SSIWS4_MARK, PJ25MD_010),
- PINMUX_DATA(LCD_TCON4_MARK, PJ25MD_011),
- PINMUX_DATA(SPDIF_OUT_MARK, PJ25MD_100),
- PINMUX_DATA(RXD7_MARK, PJ25MD_101),
-
- PINMUX_DATA(PJ24_DATA, PJ24MD_000),
- PINMUX_DATA(SSISCK4_MARK, PJ24MD_010),
- PINMUX_DATA(LCD_TCON3_MARK, PJ24MD_011),
- PINMUX_DATA(SPDIF_IN_MARK, PJ24MD_100),
- PINMUX_DATA(SCK7_MARK, PJ24MD_101),
-
- PINMUX_DATA(PJ23_DATA, PJ23MD_000),
- PINMUX_DATA(DV_DATA23_MARK, PJ23MD_001),
- PINMUX_DATA(LCD_DATA23_PJ23_MARK, PJ23MD_010),
- PINMUX_DATA(LCD_TCON6_MARK, PJ23MD_011),
- PINMUX_DATA(IRQ3_PJ_MARK, PJ23MD_100),
- PINMUX_DATA(CTX1_MARK, PJ23MD_101),
-
- PINMUX_DATA(PJ22_DATA, PJ22MD_000),
- PINMUX_DATA(DV_DATA22_MARK, PJ22MD_001),
- PINMUX_DATA(LCD_DATA22_PJ22_MARK, PJ22MD_010),
- PINMUX_DATA(LCD_TCON5_MARK, PJ22MD_011),
- PINMUX_DATA(IRQ2_PJ_MARK, PJ22MD_100),
- PINMUX_DATA(CRX1_MARK, PJ22MD_101),
- PINMUX_DATA(CRX0CRX1_MARK, PJ22MD_110),
-
- PINMUX_DATA(PJ21_DATA, PJ21MD_000),
- PINMUX_DATA(DV_DATA21_MARK, PJ21MD_001),
- PINMUX_DATA(LCD_DATA21_PJ21_MARK, PJ21MD_010),
- PINMUX_DATA(LCD_TCON4_MARK, PJ21MD_011),
- PINMUX_DATA(IRQ1_PJ_MARK, PJ21MD_100),
- PINMUX_DATA(CTX2_MARK, PJ21MD_101),
-
- PINMUX_DATA(PJ20_DATA, PJ20MD_000),
- PINMUX_DATA(DV_DATA20_MARK, PJ20MD_001),
- PINMUX_DATA(LCD_DATA20_PJ20_MARK, PJ20MD_010),
- PINMUX_DATA(LCD_TCON3_MARK, PJ20MD_011),
- PINMUX_DATA(IRQ0_PJ_MARK, PJ20MD_100),
- PINMUX_DATA(CRX2_MARK, PJ20MD_101),
- PINMUX_DATA(CRX0CRX1CRX2_PJ20_MARK, PJ20MD_110),
-
- PINMUX_DATA(PJ19_DATA, PJ19MD_000),
- PINMUX_DATA(DV_DATA19_MARK, PJ19MD_001),
- PINMUX_DATA(LCD_DATA19_PJ19_MARK, PJ19MD_010),
- PINMUX_DATA(MISO0_PJ19_MARK, PJ19MD_011),
- PINMUX_DATA(TIOC0D_MARK, PJ19MD_100),
- PINMUX_DATA(SIOFRXD_MARK, PJ19MD_101),
- PINMUX_DATA(AUDIO_XOUT_MARK, PJ19MD_110),
-
- PINMUX_DATA(PJ18_DATA, PJ18MD_000),
- PINMUX_DATA(DV_DATA18_MARK, PJ18MD_001),
- PINMUX_DATA(LCD_DATA18_PJ18_MARK, PJ18MD_010),
- PINMUX_DATA(MOSI0_PJ18_MARK, PJ18MD_011),
- PINMUX_DATA(TIOC0C_MARK, PJ18MD_100),
- PINMUX_DATA(SIOFTXD_MARK, PJ18MD_101),
-
- PINMUX_DATA(PJ17_DATA, PJ17MD_000),
- PINMUX_DATA(DV_DATA17_MARK, PJ17MD_001),
- PINMUX_DATA(LCD_DATA17_PJ17_MARK, PJ17MD_010),
- PINMUX_DATA(SSL00_PJ17_MARK, PJ17MD_011),
- PINMUX_DATA(TIOC0B_MARK, PJ17MD_100),
- PINMUX_DATA(SIOFSYNC_MARK, PJ17MD_101),
-
- PINMUX_DATA(PJ16_DATA, PJ16MD_000),
- PINMUX_DATA(DV_DATA16_MARK, PJ16MD_001),
- PINMUX_DATA(LCD_DATA16_PJ16_MARK, PJ16MD_010),
- PINMUX_DATA(RSPCK0_PJ16_MARK, PJ16MD_011),
- PINMUX_DATA(TIOC0A_MARK, PJ16MD_100),
- PINMUX_DATA(SIOFSCK_MARK, PJ16MD_101),
-
- PINMUX_DATA(PJ15_DATA, PJ15MD_000),
- PINMUX_DATA(DV_DATA15_MARK, PJ15MD_001),
- PINMUX_DATA(LCD_DATA15_PJ15_MARK, PJ15MD_010),
- PINMUX_DATA(PINT7_PJ_MARK, PJ15MD_011),
- PINMUX_DATA(PWM2H_MARK, PJ15MD_100),
- PINMUX_DATA(TXD7_MARK, PJ15MD_101),
-
- PINMUX_DATA(PJ14_DATA, PJ14MD_000),
- PINMUX_DATA(DV_DATA14_MARK, PJ14MD_001),
- PINMUX_DATA(LCD_DATA14_PJ14_MARK, PJ14MD_010),
- PINMUX_DATA(PINT6_PJ_MARK, PJ14MD_011),
- PINMUX_DATA(PWM2G_MARK, PJ14MD_100),
- PINMUX_DATA(TXD6_MARK, PJ14MD_101),
-
- PINMUX_DATA(PJ13_DATA, PJ13MD_000),
- PINMUX_DATA(DV_DATA13_MARK, PJ13MD_001),
- PINMUX_DATA(LCD_DATA13_PJ13_MARK, PJ13MD_010),
- PINMUX_DATA(PINT5_PJ_MARK, PJ13MD_011),
- PINMUX_DATA(PWM2F_MARK, PJ13MD_100),
- PINMUX_DATA(TXD5_MARK, PJ13MD_101),
-
- PINMUX_DATA(PJ12_DATA, PJ12MD_000),
- PINMUX_DATA(DV_DATA12_MARK, PJ12MD_001),
- PINMUX_DATA(LCD_DATA12_PJ12_MARK, PJ12MD_010),
- PINMUX_DATA(PINT4_PJ_MARK, PJ12MD_011),
- PINMUX_DATA(PWM2E_MARK, PJ12MD_100),
- PINMUX_DATA(SCK7_MARK, PJ12MD_101),
-
- PINMUX_DATA(PJ11_DATA, PJ11MD_000),
- PINMUX_DATA(DV_DATA11_MARK, PJ11MD_001),
- PINMUX_DATA(LCD_DATA11_PJ11_MARK, PJ11MD_010),
- PINMUX_DATA(PINT3_PJ_MARK, PJ11MD_011),
- PINMUX_DATA(PWM2D_MARK, PJ11MD_100),
- PINMUX_DATA(SCK6_MARK, PJ11MD_101),
-
- PINMUX_DATA(PJ10_DATA, PJ10MD_000),
- PINMUX_DATA(DV_DATA10_MARK, PJ10MD_001),
- PINMUX_DATA(LCD_DATA10_PJ10_MARK, PJ10MD_010),
- PINMUX_DATA(PINT2_PJ_MARK, PJ10MD_011),
- PINMUX_DATA(PWM2C_MARK, PJ10MD_100),
- PINMUX_DATA(SCK5_MARK, PJ10MD_101),
-
- PINMUX_DATA(PJ9_DATA, PJ9MD_000),
- PINMUX_DATA(DV_DATA9_MARK, PJ9MD_001),
- PINMUX_DATA(LCD_DATA9_PJ9_MARK, PJ9MD_010),
- PINMUX_DATA(PINT1_PJ_MARK, PJ9MD_011),
- PINMUX_DATA(PWM2B_MARK, PJ9MD_100),
- PINMUX_DATA(RTS5_MARK, PJ9MD_101),
-
- PINMUX_DATA(PJ8_DATA, PJ8MD_000),
- PINMUX_DATA(DV_DATA8_MARK, PJ8MD_001),
- PINMUX_DATA(LCD_DATA8_PJ8_MARK, PJ8MD_010),
- PINMUX_DATA(PINT0_PJ_MARK, PJ8MD_011),
- PINMUX_DATA(PWM2A_MARK, PJ8MD_100),
- PINMUX_DATA(CTS5_MARK, PJ8MD_101),
-
- PINMUX_DATA(PJ7_DATA, PJ7MD_000),
- PINMUX_DATA(DV_DATA7_MARK, PJ7MD_001),
- PINMUX_DATA(LCD_DATA7_PJ7_MARK, PJ7MD_010),
- PINMUX_DATA(SD_D2_MARK, PJ7MD_011),
- PINMUX_DATA(PWM1H_MARK, PJ7MD_100),
-
- PINMUX_DATA(PJ6_DATA, PJ6MD_000),
- PINMUX_DATA(DV_DATA6_MARK, PJ6MD_001),
- PINMUX_DATA(LCD_DATA6_PJ6_MARK, PJ6MD_010),
- PINMUX_DATA(SD_D3_MARK, PJ6MD_011),
- PINMUX_DATA(PWM1G_MARK, PJ6MD_100),
-
- PINMUX_DATA(PJ5_DATA, PJ5MD_000),
- PINMUX_DATA(DV_DATA5_MARK, PJ5MD_001),
- PINMUX_DATA(LCD_DATA5_PJ5_MARK, PJ5MD_010),
- PINMUX_DATA(SD_CMD_MARK, PJ5MD_011),
- PINMUX_DATA(PWM1F_MARK, PJ5MD_100),
-
- PINMUX_DATA(PJ4_DATA, PJ4MD_000),
- PINMUX_DATA(DV_DATA4_MARK, PJ4MD_001),
- PINMUX_DATA(LCD_DATA4_PJ4_MARK, PJ4MD_010),
- PINMUX_DATA(SD_CLK_MARK, PJ4MD_011),
- PINMUX_DATA(PWM1E_MARK, PJ4MD_100),
-
- PINMUX_DATA(PJ3_DATA, PJ3MD_000),
- PINMUX_DATA(DV_DATA3_MARK, PJ3MD_001),
- PINMUX_DATA(LCD_DATA3_PJ3_MARK, PJ3MD_010),
- PINMUX_DATA(SD_D0_MARK, PJ3MD_011),
- PINMUX_DATA(PWM1D_MARK, PJ3MD_100),
-
- PINMUX_DATA(PJ2_DATA, PJ2MD_000),
- PINMUX_DATA(DV_DATA2_MARK, PJ2MD_001),
- PINMUX_DATA(LCD_DATA2_PJ2_MARK, PJ2MD_010),
- PINMUX_DATA(SD_D1_MARK, PJ2MD_011),
- PINMUX_DATA(PWM1C_MARK, PJ2MD_100),
-
- PINMUX_DATA(PJ1_DATA, PJ1MD_000),
- PINMUX_DATA(DV_DATA1_MARK, PJ1MD_001),
- PINMUX_DATA(LCD_DATA1_PJ1_MARK, PJ1MD_010),
- PINMUX_DATA(SD_WP_MARK, PJ1MD_011),
- PINMUX_DATA(PWM1B_MARK, PJ1MD_100),
-
- PINMUX_DATA(PJ0_DATA, PJ0MD_000),
- PINMUX_DATA(DV_DATA0_MARK, PJ0MD_001),
- PINMUX_DATA(LCD_DATA0_PJ0_MARK, PJ0MD_010),
- PINMUX_DATA(SD_CD_MARK, PJ0MD_011),
- PINMUX_DATA(PWM1A_MARK, PJ0MD_100),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
- /* Port A */
- PINMUX_GPIO(GPIO_PA1, PA1_DATA),
- PINMUX_GPIO(GPIO_PA0, PA0_DATA),
-
- /* Port B */
- PINMUX_GPIO(GPIO_PB22, PB22_DATA),
- PINMUX_GPIO(GPIO_PB21, PB21_DATA),
- PINMUX_GPIO(GPIO_PB20, PB20_DATA),
- PINMUX_GPIO(GPIO_PB19, PB19_DATA),
- PINMUX_GPIO(GPIO_PB18, PB18_DATA),
- PINMUX_GPIO(GPIO_PB17, PB17_DATA),
- PINMUX_GPIO(GPIO_PB16, PB16_DATA),
- PINMUX_GPIO(GPIO_PB15, PB15_DATA),
- PINMUX_GPIO(GPIO_PB14, PB14_DATA),
- PINMUX_GPIO(GPIO_PB13, PB13_DATA),
- PINMUX_GPIO(GPIO_PB12, PB12_DATA),
- PINMUX_GPIO(GPIO_PB11, PB11_DATA),
- PINMUX_GPIO(GPIO_PB10, PB10_DATA),
- PINMUX_GPIO(GPIO_PB9, PB9_DATA),
- PINMUX_GPIO(GPIO_PB8, PB8_DATA),
- PINMUX_GPIO(GPIO_PB7, PB7_DATA),
- PINMUX_GPIO(GPIO_PB6, PB6_DATA),
- PINMUX_GPIO(GPIO_PB5, PB5_DATA),
- PINMUX_GPIO(GPIO_PB4, PB4_DATA),
- PINMUX_GPIO(GPIO_PB3, PB3_DATA),
- PINMUX_GPIO(GPIO_PB2, PB2_DATA),
- PINMUX_GPIO(GPIO_PB1, PB1_DATA),
-
- /* Port C */
- PINMUX_GPIO(GPIO_PC8, PC8_DATA),
- PINMUX_GPIO(GPIO_PC7, PC7_DATA),
- PINMUX_GPIO(GPIO_PC6, PC6_DATA),
- PINMUX_GPIO(GPIO_PC5, PC5_DATA),
- PINMUX_GPIO(GPIO_PC4, PC4_DATA),
- PINMUX_GPIO(GPIO_PC3, PC3_DATA),
- PINMUX_GPIO(GPIO_PC2, PC2_DATA),
- PINMUX_GPIO(GPIO_PC1, PC1_DATA),
- PINMUX_GPIO(GPIO_PC0, PC0_DATA),
-
- /* Port D */
- PINMUX_GPIO(GPIO_PD15, PD15_DATA),
- PINMUX_GPIO(GPIO_PD14, PD14_DATA),
- PINMUX_GPIO(GPIO_PD13, PD13_DATA),
- PINMUX_GPIO(GPIO_PD12, PD12_DATA),
- PINMUX_GPIO(GPIO_PD11, PD11_DATA),
- PINMUX_GPIO(GPIO_PD10, PD10_DATA),
- PINMUX_GPIO(GPIO_PD9, PD9_DATA),
- PINMUX_GPIO(GPIO_PD8, PD8_DATA),
- PINMUX_GPIO(GPIO_PD7, PD7_DATA),
- PINMUX_GPIO(GPIO_PD6, PD6_DATA),
- PINMUX_GPIO(GPIO_PD5, PD5_DATA),
- PINMUX_GPIO(GPIO_PD4, PD4_DATA),
- PINMUX_GPIO(GPIO_PD3, PD3_DATA),
- PINMUX_GPIO(GPIO_PD2, PD2_DATA),
- PINMUX_GPIO(GPIO_PD1, PD1_DATA),
- PINMUX_GPIO(GPIO_PD0, PD0_DATA),
-
- /* Port E */
- PINMUX_GPIO(GPIO_PE7, PE7_DATA),
- PINMUX_GPIO(GPIO_PE6, PE6_DATA),
- PINMUX_GPIO(GPIO_PE5, PE5_DATA),
- PINMUX_GPIO(GPIO_PE4, PE4_DATA),
- PINMUX_GPIO(GPIO_PE3, PE3_DATA),
- PINMUX_GPIO(GPIO_PE2, PE2_DATA),
- PINMUX_GPIO(GPIO_PE1, PE1_DATA),
- PINMUX_GPIO(GPIO_PE0, PE0_DATA),
-
- /* Port F */
- PINMUX_GPIO(GPIO_PF23, PF23_DATA),
- PINMUX_GPIO(GPIO_PF22, PF22_DATA),
- PINMUX_GPIO(GPIO_PF21, PF21_DATA),
- PINMUX_GPIO(GPIO_PF20, PF20_DATA),
- PINMUX_GPIO(GPIO_PF19, PF19_DATA),
- PINMUX_GPIO(GPIO_PF18, PF18_DATA),
- PINMUX_GPIO(GPIO_PF17, PF17_DATA),
- PINMUX_GPIO(GPIO_PF16, PF16_DATA),
- PINMUX_GPIO(GPIO_PF15, PF15_DATA),
- PINMUX_GPIO(GPIO_PF14, PF14_DATA),
- PINMUX_GPIO(GPIO_PF13, PF13_DATA),
- PINMUX_GPIO(GPIO_PF12, PF12_DATA),
- PINMUX_GPIO(GPIO_PF11, PF11_DATA),
- PINMUX_GPIO(GPIO_PF10, PF10_DATA),
- PINMUX_GPIO(GPIO_PF9, PF9_DATA),
- PINMUX_GPIO(GPIO_PF8, PF8_DATA),
- PINMUX_GPIO(GPIO_PF7, PF7_DATA),
- PINMUX_GPIO(GPIO_PF6, PF6_DATA),
- PINMUX_GPIO(GPIO_PF5, PF5_DATA),
- PINMUX_GPIO(GPIO_PF4, PF4_DATA),
- PINMUX_GPIO(GPIO_PF3, PF3_DATA),
- PINMUX_GPIO(GPIO_PF2, PF2_DATA),
- PINMUX_GPIO(GPIO_PF1, PF1_DATA),
- PINMUX_GPIO(GPIO_PF0, PF0_DATA),
-
- /* Port G */
- PINMUX_GPIO(GPIO_PG27, PG27_DATA),
- PINMUX_GPIO(GPIO_PG26, PG26_DATA),
- PINMUX_GPIO(GPIO_PG25, PG25_DATA),
- PINMUX_GPIO(GPIO_PG24, PG24_DATA),
- PINMUX_GPIO(GPIO_PG23, PG23_DATA),
- PINMUX_GPIO(GPIO_PG22, PG22_DATA),
- PINMUX_GPIO(GPIO_PG21, PG21_DATA),
- PINMUX_GPIO(GPIO_PG20, PG20_DATA),
- PINMUX_GPIO(GPIO_PG19, PG19_DATA),
- PINMUX_GPIO(GPIO_PG18, PG18_DATA),
- PINMUX_GPIO(GPIO_PG17, PG17_DATA),
- PINMUX_GPIO(GPIO_PG16, PG16_DATA),
- PINMUX_GPIO(GPIO_PG15, PG15_DATA),
- PINMUX_GPIO(GPIO_PG14, PG14_DATA),
- PINMUX_GPIO(GPIO_PG13, PG13_DATA),
- PINMUX_GPIO(GPIO_PG12, PG12_DATA),
- PINMUX_GPIO(GPIO_PG11, PG11_DATA),
- PINMUX_GPIO(GPIO_PG10, PG10_DATA),
- PINMUX_GPIO(GPIO_PG9, PG9_DATA),
- PINMUX_GPIO(GPIO_PG8, PG8_DATA),
- PINMUX_GPIO(GPIO_PG7, PG7_DATA),
- PINMUX_GPIO(GPIO_PG6, PG6_DATA),
- PINMUX_GPIO(GPIO_PG5, PG5_DATA),
- PINMUX_GPIO(GPIO_PG4, PG4_DATA),
- PINMUX_GPIO(GPIO_PG3, PG3_DATA),
- PINMUX_GPIO(GPIO_PG2, PG2_DATA),
- PINMUX_GPIO(GPIO_PG1, PG1_DATA),
- PINMUX_GPIO(GPIO_PG0, PG0_DATA),
-
- /* Port H - Port H does not have a Data Register */
-
- /* Port I - not on device */
-
- /* Port J */
- PINMUX_GPIO(GPIO_PJ31, PJ31_DATA),
- PINMUX_GPIO(GPIO_PJ30, PJ30_DATA),
- PINMUX_GPIO(GPIO_PJ29, PJ29_DATA),
- PINMUX_GPIO(GPIO_PJ28, PJ28_DATA),
- PINMUX_GPIO(GPIO_PJ27, PJ27_DATA),
- PINMUX_GPIO(GPIO_PJ26, PJ26_DATA),
- PINMUX_GPIO(GPIO_PJ25, PJ25_DATA),
- PINMUX_GPIO(GPIO_PJ24, PJ24_DATA),
- PINMUX_GPIO(GPIO_PJ23, PJ23_DATA),
- PINMUX_GPIO(GPIO_PJ22, PJ22_DATA),
- PINMUX_GPIO(GPIO_PJ21, PJ21_DATA),
- PINMUX_GPIO(GPIO_PJ20, PJ20_DATA),
- PINMUX_GPIO(GPIO_PJ19, PJ19_DATA),
- PINMUX_GPIO(GPIO_PJ18, PJ18_DATA),
- PINMUX_GPIO(GPIO_PJ17, PJ17_DATA),
- PINMUX_GPIO(GPIO_PJ16, PJ16_DATA),
- PINMUX_GPIO(GPIO_PJ15, PJ15_DATA),
- PINMUX_GPIO(GPIO_PJ14, PJ14_DATA),
- PINMUX_GPIO(GPIO_PJ13, PJ13_DATA),
- PINMUX_GPIO(GPIO_PJ12, PJ12_DATA),
- PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
- PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
- PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
- PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
- PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
- PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
- PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
- PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
- PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
- PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
- PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
- PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
-
- /* INTC */
- PINMUX_GPIO(GPIO_FN_IRQ7_PG, IRQ7_PG_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ6_PG, IRQ6_PG_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ5_PG, IRQ5_PG_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ4_PG, IRQ4_PG_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3_PG, IRQ3_PG_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2_PG, IRQ2_PG_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1_PG, IRQ1_PG_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0_PG, IRQ0_PG_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ7_PF, IRQ7_PF_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ6_PF, IRQ6_PF_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ5_PF, IRQ5_PF_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ4_PF, IRQ4_PF_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3_PJ, IRQ3_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2_PJ, IRQ2_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1_PJ, IRQ1_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0_PJ, IRQ0_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1_PC, IRQ1_PC_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0_PC, IRQ0_PC_MARK),
-
- PINMUX_GPIO(GPIO_FN_PINT7_PG, PINT7_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT6_PG, PINT6_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT5_PG, PINT5_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT4_PG, PINT4_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT3_PG, PINT3_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT2_PG, PINT2_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT1_PG, PINT1_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT0_PG, PINT0_PG_MARK),
- PINMUX_GPIO(GPIO_FN_PINT7_PH, PINT7_PH_MARK),
- PINMUX_GPIO(GPIO_FN_PINT6_PH, PINT6_PH_MARK),
- PINMUX_GPIO(GPIO_FN_PINT5_PH, PINT5_PH_MARK),
- PINMUX_GPIO(GPIO_FN_PINT4_PH, PINT4_PH_MARK),
- PINMUX_GPIO(GPIO_FN_PINT3_PH, PINT3_PH_MARK),
- PINMUX_GPIO(GPIO_FN_PINT2_PH, PINT2_PH_MARK),
- PINMUX_GPIO(GPIO_FN_PINT1_PH, PINT1_PH_MARK),
- PINMUX_GPIO(GPIO_FN_PINT0_PH, PINT0_PH_MARK),
- PINMUX_GPIO(GPIO_FN_PINT7_PJ, PINT7_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_PINT6_PJ, PINT6_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_PINT5_PJ, PINT5_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_PINT4_PJ, PINT4_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_PINT3_PJ, PINT3_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_PINT2_PJ, PINT2_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_PINT1_PJ, PINT1_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_PINT0_PJ, PINT0_PJ_MARK),
-
- /* WDT */
- PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
-
- /* CAN */
- PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
- PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
- PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
- PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
- PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0CRX1_MARK),
- PINMUX_GPIO(GPIO_FN_CRX0_CRX1_CRX2, CRX0CRX1CRX2_MARK),
-
- /* DMAC */
- PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
- PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
- PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
-
- /* ADC */
- PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
-
- /* BSCh */
- PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
- PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
- PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
- PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
- PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
- PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
- PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
- PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
- PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
- PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
- PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
- PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
- PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
- PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
- PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
- PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
- PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
- PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
- PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
- PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
- PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
- PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
- PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
- PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
- PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
- PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
-
- PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
- PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
- PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
- PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
- PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
- PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
- PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
- PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
- PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
- PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
- PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
- PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
- PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
- PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
- PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
- PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
-
- PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
- PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
- PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
- PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
- PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
- PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
- PINMUX_GPIO(GPIO_FN_CS5CE1A, CS5CE1A_MARK),
- PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
- PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
- PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
- PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
- PINMUX_GPIO(GPIO_FN_WE3ICIOWRAHDQMUU, WE3ICIOWRAHDQMUU_MARK),
- PINMUX_GPIO(GPIO_FN_WE2ICIORDDQMUL, WE2ICIORDDQMUL_MARK),
- PINMUX_GPIO(GPIO_FN_WE1DQMUWE, WE1DQMUWE_MARK),
- PINMUX_GPIO(GPIO_FN_WE0DQML, WE0DQML_MARK),
- PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
- PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
- PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
- PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
- PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
- PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
- PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
-
- /* TMU */
- PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
- PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKD, TCLKD_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKC, TCLKC_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKB, TCLKB_MARK),
- PINMUX_GPIO(GPIO_FN_TCLKA, TCLKA_MARK),
-
- /* SCIF */
- PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
- PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
- PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RTS1, RTS1_MARK),
- PINMUX_GPIO(GPIO_FN_CTS1, CTS1_MARK),
- PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
- PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
- PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
- PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
- PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
- PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
- PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
- PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
- PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
- PINMUX_GPIO(GPIO_FN_SCK5, SCK5_MARK),
- PINMUX_GPIO(GPIO_FN_TXD5, TXD5_MARK),
- PINMUX_GPIO(GPIO_FN_RXD5, RXD5_MARK),
- PINMUX_GPIO(GPIO_FN_RTS5, RTS5_MARK),
- PINMUX_GPIO(GPIO_FN_CTS5, CTS5_MARK),
- PINMUX_GPIO(GPIO_FN_SCK6, SCK6_MARK),
- PINMUX_GPIO(GPIO_FN_TXD6, TXD6_MARK),
- PINMUX_GPIO(GPIO_FN_RXD6, RXD6_MARK),
- PINMUX_GPIO(GPIO_FN_SCK7, SCK7_MARK),
- PINMUX_GPIO(GPIO_FN_TXD7, TXD7_MARK),
- PINMUX_GPIO(GPIO_FN_RXD7, RXD7_MARK),
- PINMUX_GPIO(GPIO_FN_RTS7, RTS7_MARK),
- PINMUX_GPIO(GPIO_FN_CTS7, CTS7_MARK),
-
- /* RSPI */
- PINMUX_GPIO(GPIO_FN_RSPCK0_PJ16, RSPCK0_PJ16_MARK),
- PINMUX_GPIO(GPIO_FN_SSL00_PJ17, SSL00_PJ17_MARK),
- PINMUX_GPIO(GPIO_FN_MOSI0_PJ18, MOSI0_PJ18_MARK),
- PINMUX_GPIO(GPIO_FN_MISO0_PJ19, MISO0_PJ19_MARK),
- PINMUX_GPIO(GPIO_FN_RSPCK0_PB17, RSPCK0_PB17_MARK),
- PINMUX_GPIO(GPIO_FN_SSL00_PB18, SSL00_PB18_MARK),
- PINMUX_GPIO(GPIO_FN_MOSI0_PB19, MOSI0_PB19_MARK),
- PINMUX_GPIO(GPIO_FN_MISO0_PB20, MISO0_PB20_MARK),
- PINMUX_GPIO(GPIO_FN_RSPCK1, RSPCK1_MARK),
- PINMUX_GPIO(GPIO_FN_MOSI1, MOSI1_MARK),
- PINMUX_GPIO(GPIO_FN_MISO1, MISO1_MARK),
- PINMUX_GPIO(GPIO_FN_SSL10, SSL10_MARK),
-
- /* IIC3 */
- PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
- PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
- PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
- PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
- PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
- PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
-
- /* SSI */
- PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
- PINMUX_GPIO(GPIO_FN_SSITXD0, SSITXD0_MARK),
- PINMUX_GPIO(GPIO_FN_SSIRXD0, SSIRXD0_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
- PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
- PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
- PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
- PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
- PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
- PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
- PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
- PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_AUDIO_XOUT, AUDIO_XOUT_MARK),
-
- /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
- PINMUX_GPIO(GPIO_FN_SIOFTXD, SIOFTXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOFRXD, SIOFRXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOFSYNC, SIOFSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_SIOFSCK, SIOFSCK_MARK),
-
- /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
- PINMUX_GPIO(GPIO_FN_SPDIF_IN, SPDIF_IN_MARK),
- PINMUX_GPIO(GPIO_FN_SPDIF_OUT, SPDIF_OUT_MARK),
-
- /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
- PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
- PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
-
- /* VDC3 */
- PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
-
- PINMUX_GPIO(GPIO_FN_DV_DATA23, DV_DATA23_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA22, DV_DATA22_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA21, DV_DATA21_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA20, DV_DATA20_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA19, DV_DATA19_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA18, DV_DATA18_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA17, DV_DATA17_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA16, DV_DATA16_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA15, DV_DATA15_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA14, DV_DATA14_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA13, DV_DATA13_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA12, DV_DATA12_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA11, DV_DATA11_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA10, DV_DATA10_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA9, DV_DATA9_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA8, DV_DATA8_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA7, DV_DATA7_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA6, DV_DATA6_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA5, DV_DATA5_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA4, DV_DATA4_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA3, DV_DATA3_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA2, DV_DATA2_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA1, DV_DATA1_MARK),
- PINMUX_GPIO(GPIO_FN_DV_DATA0, DV_DATA0_MARK),
-
- PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_EXTCLK, LCD_EXTCLK_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_VSYNC, LCD_VSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
-
- PINMUX_GPIO(GPIO_FN_LCD_DATA23_PG23, LCD_DATA23_PG23_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA22_PG22, LCD_DATA22_PG22_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA21_PG21, LCD_DATA21_PG21_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA20_PG20, LCD_DATA20_PG20_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA19_PG19, LCD_DATA19_PG19_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA18_PG18, LCD_DATA18_PG18_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA17_PG17, LCD_DATA17_PG17_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA16_PG16, LCD_DATA16_PG16_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA15_PG15, LCD_DATA15_PG15_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA14_PG14, LCD_DATA14_PG14_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA13_PG13, LCD_DATA13_PG13_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA12_PG12, LCD_DATA12_PG12_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA11_PG11, LCD_DATA11_PG11_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA10_PG10, LCD_DATA10_PG10_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA9_PG9, LCD_DATA9_PG9_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA8_PG8, LCD_DATA8_PG8_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA7_PG7, LCD_DATA7_PG7_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA6_PG6, LCD_DATA6_PG6_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA5_PG5, LCD_DATA5_PG5_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA4_PG4, LCD_DATA4_PG4_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA3_PG3, LCD_DATA3_PG3_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA2_PG2, LCD_DATA2_PG2_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA1_PG1, LCD_DATA1_PG1_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA0_PG0, LCD_DATA0_PG0_MARK),
-
- PINMUX_GPIO(GPIO_FN_LCD_DATA23_PJ23, LCD_DATA23_PJ23_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA22_PJ22, LCD_DATA22_PJ22_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA21_PJ21, LCD_DATA21_PJ21_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA20_PJ20, LCD_DATA20_PJ20_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA19_PJ19, LCD_DATA19_PJ19_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA18_PJ18, LCD_DATA18_PJ18_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA17_PJ17, LCD_DATA17_PJ17_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA16_PJ16, LCD_DATA16_PJ16_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA15_PJ15, LCD_DATA15_PJ15_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA14_PJ14, LCD_DATA14_PJ14_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA13_PJ13, LCD_DATA13_PJ13_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA12_PJ12, LCD_DATA12_PJ12_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA11_PJ11, LCD_DATA11_PJ11_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA10_PJ10, LCD_DATA10_PJ10_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA9_PJ9, LCD_DATA9_PJ9_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA8_PJ8, LCD_DATA8_PJ8_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA7_PJ7, LCD_DATA7_PJ7_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA6_PJ6, LCD_DATA6_PJ6_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA5_PJ5, LCD_DATA5_PJ5_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA4_PJ4, LCD_DATA4_PJ4_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA3_PJ3, LCD_DATA3_PJ3_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA2_PJ2, LCD_DATA2_PJ2_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA1_PJ1, LCD_DATA1_PJ1_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA0_PJ0, LCD_DATA0_PJ0_MARK),
-
- PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
-};
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- /* "name" addr register_size Field_Width */
-
- /* where Field_Width is 1 for single mode registers or 4 for upto 16
- mode registers and modes are described in assending order [0..16] */
-
- { PINMUX_CFG_REG("PAIOR0", 0xfffe3812, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, PA1_IN, PA1_OUT,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, PA0_IN, PA0_OUT }
- },
- { PINMUX_CFG_REG("PBCR5", 0xfffe3824, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB22MD_000, PB22MD_001, PB22MD_010, PB22MD_011,
- PB22MD_100, PB22MD_101, PB22MD_110, PB22MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB21MD_00, PB21MD_01, PB21MD_10, PB21MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB20MD_000, PB20MD_001, PB20MD_010, PB20MD_011,
- PB20MD_100, PB20MD_101, PB20MD_110, PB20MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCR4", 0xfffe3826, 16, 4) {
- PB19MD_000, PB19MD_001, PB19MD_010, PB19MD_011,
- PB19MD_100, PB19MD_101, PB19MD_110, PB19MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB18MD_000, PB18MD_001, PB18MD_010, PB18MD_011,
- PB18MD_100, PB18MD_101, PB18MD_110, PB18MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB17MD_000, PB17MD_001, PB17MD_010, PB17MD_011,
- PB17MD_100, PB17MD_101, PB17MD_110, PB17MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB16MD_000, PB16MD_001, PB16MD_010, PB16MD_011,
- PB16MD_100, PB16MD_101, PB16MD_110, PB16MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCR3", 0xfffe3828, 16, 4) {
- PB15MD_000, PB15MD_001, PB15MD_010, PB15MD_011,
- PB15MD_100, PB15MD_101, PB15MD_110, PB15MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB14MD_000, PB14MD_001, PB14MD_010, PB14MD_011,
- PB14MD_100, PB14MD_101, PB14MD_110, PB14MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB13MD_000, PB13MD_001, PB13MD_010, PB13MD_011,
- PB13MD_100, PB13MD_101, PB13MD_110, PB13MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCR2", 0xfffe382a, 16, 4) {
- PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCR1", 0xfffe382c, 16, 4) {
- PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PBCR0", 0xfffe382e, 16, 4) {
- PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PBIOR1", 0xfffe3830, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- PB22_IN, PB22_OUT,
- PB21_IN, PB21_OUT,
- PB20_IN, PB20_OUT,
- PB19_IN, PB19_OUT,
- PB18_IN, PB18_OUT,
- PB17_IN, PB17_OUT,
- PB16_IN, PB16_OUT }
- },
- { PINMUX_CFG_REG("PBIOR0", 0xfffe3832, 16, 1) {
- PB15_IN, PB15_OUT,
- PB14_IN, PB14_OUT,
- PB13_IN, PB13_OUT,
- PB12_IN, PB12_OUT,
- PB11_IN, PB11_OUT,
- PB10_IN, PB10_OUT,
- PB9_IN, PB9_OUT,
- PB8_IN, PB8_OUT,
- PB7_IN, PB7_OUT,
- PB6_IN, PB6_OUT,
- PB5_IN, PB5_OUT,
- PB4_IN, PB4_OUT,
- PB3_IN, PB3_OUT,
- PB2_IN, PB2_OUT,
- PB1_IN, PB1_OUT,
- 0, 0 }
- },
-
- { PINMUX_CFG_REG("PCCR2", 0xfffe384a, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC8MD_000, PC8MD_001, PC8MD_010, PC8MD_011,
- PC8MD_100, PC8MD_101, PC8MD_110, PC8MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PCCR1", 0xfffe384c, 16, 4) {
- PC7MD_000, PC7MD_001, PC7MD_010, PC7MD_011,
- PC7MD_100, PC7MD_101, PC7MD_110, PC7MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC6MD_000, PC6MD_001, PC6MD_010, PC6MD_011,
- PC6MD_100, PC6MD_101, PC6MD_110, PC6MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC5MD_000, PC5MD_001, PC5MD_010, PC5MD_011,
- PC5MD_100, PC5MD_101, PC5MD_110, PC5MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC4MD_00, PC4MD_01, PC4MD_10, PC4MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PCCR0", 0xfffe384e, 16, 4) {
- PC3MD_00, PC3MD_01, PC3MD_10, PC3MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC2MD_00, PC2MD_01, PC2MD_10, PC2MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC1MD_0, PC1MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PC0MD_0, PC0MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- PC8_IN, PC8_OUT,
- PC7_IN, PC7_OUT,
- PC6_IN, PC6_OUT,
- PC5_IN, PC5_OUT,
- PC4_IN, PC4_OUT,
- PC3_IN, PC3_OUT,
- PC2_IN, PC2_OUT,
- PC1_IN, PC1_OUT,
- PC0_IN, PC0_OUT }
- },
-
- { PINMUX_CFG_REG("PDCR3", 0xfffe3868, 16, 4) {
- PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PDCR2", 0xfffe386a, 16, 4) {
- PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PDCR1", 0xfffe386c, 16, 4) {
- PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PDCR0", 0xfffe386e, 16, 4) {
- PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PDIOR0", 0xfffe3872, 16, 1) {
- PD15_IN, PD15_OUT,
- PD14_IN, PD14_OUT,
- PD13_IN, PD13_OUT,
- PD12_IN, PD12_OUT,
- PD11_IN, PD11_OUT,
- PD10_IN, PD10_OUT,
- PD9_IN, PD9_OUT,
- PD8_IN, PD8_OUT,
- PD7_IN, PD7_OUT,
- PD6_IN, PD6_OUT,
- PD5_IN, PD5_OUT,
- PD4_IN, PD4_OUT,
- PD3_IN, PD3_OUT,
- PD2_IN, PD2_OUT,
- PD1_IN, PD1_OUT,
- PD0_IN, PD0_OUT }
- },
-
- { PINMUX_CFG_REG("PECR1", 0xfffe388c, 16, 4) {
- PE7MD_00, PE7MD_01, PE7MD_10, PE7MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE6MD_00, PE6MD_01, PE6MD_10, PE6MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PECR0", 0xfffe388e, 16, 4) {
- PE3MD_000, PE3MD_001, PE3MD_010, PE3MD_011,
- PE3MD_100, PE3MD_101, PE3MD_110, PE3MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE2MD_000, PE2MD_001, PE2MD_010, PE2MD_011,
- PE2MD_100, PE2MD_101, PE2MD_110, PE2MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
- PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PEIOR0", 0xfffe3892, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PE7_IN, PE7_OUT,
- PE6_IN, PE6_OUT,
- PE5_IN, PE5_OUT,
- PE4_IN, PE4_OUT,
- PE3_IN, PE3_OUT,
- PE2_IN, PE2_OUT,
- PE1_IN, PE1_OUT,
- PE0_IN, PE0_OUT }
- },
-
- { PINMUX_CFG_REG("PFCR6", 0xfffe38a2, 16, 4) {
- PF23MD_000, PF23MD_001, PF23MD_010, PF23MD_011,
- PF23MD_100, PF23MD_101, PF23MD_110, PF23MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF22MD_000, PF22MD_001, PF22MD_010, PF22MD_011,
- PF22MD_100, PF22MD_101, PF22MD_110, PF22MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF21MD_000, PF21MD_001, PF21MD_010, PF21MD_011,
- PF21MD_100, PF21MD_101, PF21MD_110, PF21MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF20MD_000, PF20MD_001, PF20MD_010, PF20MD_011,
- PF20MD_100, PF20MD_101, PF20MD_110, PF20MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCR5", 0xfffe38a4, 16, 4) {
- PF19MD_000, PF19MD_001, PF19MD_010, PF19MD_011,
- PF19MD_100, PF19MD_101, PF19MD_110, PF19MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF18MD_000, PF18MD_001, PF18MD_010, PF18MD_011,
- PF18MD_100, PF18MD_101, PF18MD_110, PF18MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF17MD_000, PF17MD_001, PF17MD_010, PF17MD_011,
- PF17MD_100, PF17MD_101, PF17MD_110, PF17MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF16MD_000, PF16MD_001, PF16MD_010, PF16MD_011,
- PF16MD_100, PF16MD_101, PF16MD_110, PF16MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCR4", 0xfffe38a6, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF15MD_000, PF15MD_001, PF15MD_010, PF15MD_011,
- PF15MD_100, PF15MD_101, PF15MD_110, PF15MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF14MD_000, PF14MD_001, PF14MD_010, PF14MD_011,
- PF14MD_100, PF14MD_101, PF14MD_110, PF14MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF13MD_000, PF13MD_001, PF13MD_010, PF13MD_011,
- PF13MD_100, PF13MD_101, PF13MD_110, PF13MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
- PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCR2", 0xfffe38aa, 16, 4) {
- PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
- PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
- PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
- PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF8MD_000, PF8MD_001, PF8MD_010, PF8MD_011,
- PF8MD_100, PF8MD_101, PF8MD_110, PF8MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCR1", 0xfffe38ac, 16, 4) {
- PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
- PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
- PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
- PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
- PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PFCR0", 0xfffe38ae, 16, 4) {
- PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
- PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
- PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
- PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
- PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PFIOR1", 0xfffe38b0, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF23_IN, PF23_OUT,
- PF22_IN, PF22_OUT,
- PF21_IN, PF21_OUT,
- PF20_IN, PF20_OUT,
- PF19_IN, PF19_OUT,
- PF18_IN, PF18_OUT,
- PF17_IN, PF17_OUT,
- PF16_IN, PF16_OUT }
- },
- { PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
- PF15_IN, PF15_OUT,
- PF14_IN, PF14_OUT,
- PF13_IN, PF13_OUT,
- PF12_IN, PF12_OUT,
- PF11_IN, PF11_OUT,
- PF10_IN, PF10_OUT,
- PF9_IN, PF9_OUT,
- PF8_IN, PF8_OUT,
- PF7_IN, PF7_OUT,
- PF6_IN, PF6_OUT,
- PF5_IN, PF5_OUT,
- PF4_IN, PF4_OUT,
- PF3_IN, PF3_OUT,
- PF2_IN, PF2_OUT,
- PF1_IN, PF1_OUT,
- PF0_IN, PF0_OUT }
- },
-
- { PINMUX_CFG_REG("PGCR6", 0xfffe38c2, 16, 4) {
- PG27MD_00, PG27MD_01, PG27MD_10, PG27MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG26MD_00, PG26MD_01, PG26MD_10, PG26MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG25MD_00, PG25MD_01, PG25MD_10, PG25MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PGCR5", 0xfffe38c4, 16, 4) {
- PG23MD_000, PG23MD_001, PG23MD_010, PG23MD_011,
- PG23MD_100, PG23MD_101, PG23MD_110, PG23MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG22MD_000, PG22MD_001, PG22MD_010, PG22MD_011,
- PG22MD_100, PG22MD_101, PG22MD_110, PG22MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG21MD_000, PG21MD_001, PG21MD_010, PG21MD_011,
- PG21MD_100, PG21MD_101, PG21MD_110, PG21MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
- PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PGCR4", 0xfffe38c6, 16, 4) {
- PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
- PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
- PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG17MD_00, PG17MD_01, PG17MD_10, PG17MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG16MD_00, PG16MD_01, PG16MD_10, PG16MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PGCR3", 0xfffe38c8, 16, 4) {
- PG15MD_00, PG15MD_01, PG15MD_10, PG15MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG14MD_00, PG14MD_01, PG14MD_10, PG14MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG13MD_00, PG13MD_01, PG13MD_10, PG13MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG12MD_00, PG12MD_01, PG12MD_10, PG12MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PGCR2", 0xfffe38ca, 16, 4) {
- PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
- PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
- PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
- PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
- PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PGCR1", 0xfffe38cc, 16, 4) {
- PG7MD_000, PG7MD_001, PG7MD_010, PG7MD_011,
- PG7MD_100, PG7MD_101, PG7MD_110, PG7MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG6MD_000, PG6MD_001, PG6MD_010, PG6MD_011,
- PG6MD_100, PG6MD_101, PG6MD_110, PG6MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG5MD_000, PG5MD_001, PG5MD_010, PG5MD_011,
- PG5MD_100, PG5MD_101, PG5MD_110, PG5MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG4MD_000, PG4MD_001, PG4MD_010, PG4MD_011,
- PG4MD_100, PG4MD_101, PG4MD_110, PG4MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PGCR0", 0xfffe38ce, 16, 4) {
- PG3MD_000, PG3MD_001, PG3MD_010, PG3MD_011,
- PG3MD_100, PG3MD_101, PG3MD_110, PG3MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG2MD_000, PG2MD_001, PG2MD_010, PG2MD_011,
- PG2MD_100, PG2MD_101, PG2MD_110, PG2MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG1MD_000, PG1MD_001, PG1MD_010, PG1MD_011,
- PG1MD_100, PG1MD_101, PG1MD_110, PG1MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
- PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PGIOR1", 0xfffe38d0, 16, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG27_IN, PG27_OUT,
- PG26_IN, PG26_OUT,
- PG25_IN, PG25_OUT,
- PG24_IN, PG24_OUT,
- PG23_IN, PG23_OUT,
- PG22_IN, PG22_OUT,
- PG21_IN, PG21_OUT,
- PG20_IN, PG20_OUT,
- PG19_IN, PG19_OUT,
- PG18_IN, PG18_OUT,
- PG17_IN, PG17_OUT,
- PG16_IN, PG16_OUT }
- },
- { PINMUX_CFG_REG("PGIOR0", 0xfffe38d2, 16, 1) {
- PG15_IN, PG15_OUT,
- PG14_IN, PG14_OUT,
- PG13_IN, PG13_OUT,
- PG12_IN, PG12_OUT,
- PG11_IN, PG11_OUT,
- PG10_IN, PG10_OUT,
- PG9_IN, PG9_OUT,
- PG8_IN, PG8_OUT,
- PG7_IN, PG7_OUT,
- PG6_IN, PG6_OUT,
- PG5_IN, PG5_OUT,
- PG4_IN, PG4_OUT,
- PG3_IN, PG3_OUT,
- PG2_IN, PG2_OUT,
- PG1_IN, PG1_OUT,
- PG0_IN, PG0_OUT }
- },
-
- { PINMUX_CFG_REG("PHCR1", 0xfffe38ec, 16, 4) {
- PH7MD_00, PH7MD_01, PH7MD_10, PH7MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PH6MD_00, PH6MD_01, PH6MD_10, PH6MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PH5MD_00, PH5MD_01, PH5MD_10, PH5MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PH4MD_00, PH4MD_01, PH4MD_10, PH4MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PHCR0", 0xfffe38ee, 16, 4) {
- PH3MD_00, PH3MD_01, PH3MD_10, PH3MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PH2MD_00, PH2MD_01, PH2MD_10, PH2MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PH1MD_00, PH1MD_01, PH1MD_10, PH1MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PH0MD_00, PH0MD_01, PH0MD_10, PH0MD_11, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PJCR7", 0xfffe3900, 16, 4) {
- PJ31MD_0, PJ31MD_1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ30MD_000, PJ30MD_001, PJ30MD_010, PJ30MD_011,
- PJ30MD_100, PJ30MD_101, PJ30MD_110, PJ30MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ29MD_000, PJ29MD_001, PJ29MD_010, PJ29MD_011,
- PJ29MD_100, PJ29MD_101, PJ29MD_110, PJ29MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ28MD_000, PJ28MD_001, PJ28MD_010, PJ28MD_011,
- PJ28MD_100, PJ28MD_101, PJ28MD_110, PJ28MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PJCR6", 0xfffe3902, 16, 4) {
- PJ27MD_000, PJ27MD_001, PJ27MD_010, PJ27MD_011,
- PJ27MD_100, PJ27MD_101, PJ27MD_110, PJ27MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ26MD_000, PJ26MD_001, PJ26MD_010, PJ26MD_011,
- PJ26MD_100, PJ26MD_101, PJ26MD_110, PJ26MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ25MD_000, PJ25MD_001, PJ25MD_010, PJ25MD_011,
- PJ25MD_100, PJ25MD_101, PJ25MD_110, PJ25MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ24MD_000, PJ24MD_001, PJ24MD_010, PJ24MD_011,
- PJ24MD_100, PJ24MD_101, PJ24MD_110, PJ24MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PJCR5", 0xfffe3904, 16, 4) {
- PJ23MD_000, PJ23MD_001, PJ23MD_010, PJ23MD_011,
- PJ23MD_100, PJ23MD_101, PJ23MD_110, PJ23MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ22MD_000, PJ22MD_001, PJ22MD_010, PJ22MD_011,
- PJ22MD_100, PJ22MD_101, PJ22MD_110, PJ22MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ21MD_000, PJ21MD_001, PJ21MD_010, PJ21MD_011,
- PJ21MD_100, PJ21MD_101, PJ21MD_110, PJ21MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ20MD_000, PJ20MD_001, PJ20MD_010, PJ20MD_011,
- PJ20MD_100, PJ20MD_101, PJ20MD_110, PJ20MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PJCR4", 0xfffe3906, 16, 4) {
- PJ19MD_000, PJ19MD_001, PJ19MD_010, PJ19MD_011,
- PJ19MD_100, PJ19MD_101, PJ19MD_110, PJ19MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ18MD_000, PJ18MD_001, PJ18MD_010, PJ18MD_011,
- PJ18MD_100, PJ18MD_101, PJ18MD_110, PJ18MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ17MD_000, PJ17MD_001, PJ17MD_010, PJ17MD_011,
- PJ17MD_100, PJ17MD_101, PJ17MD_110, PJ17MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ16MD_000, PJ16MD_001, PJ16MD_010, PJ16MD_011,
- PJ16MD_100, PJ16MD_101, PJ16MD_110, PJ16MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PJCR3", 0xfffe3908, 16, 4) {
- PJ15MD_000, PJ15MD_001, PJ15MD_010, PJ15MD_011,
- PJ15MD_100, PJ15MD_101, PJ15MD_110, PJ15MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ14MD_000, PJ14MD_001, PJ14MD_010, PJ14MD_011,
- PJ14MD_100, PJ14MD_101, PJ14MD_110, PJ14MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ13MD_000, PJ13MD_001, PJ13MD_010, PJ13MD_011,
- PJ13MD_100, PJ13MD_101, PJ13MD_110, PJ13MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ12MD_000, PJ12MD_001, PJ12MD_010, PJ12MD_011,
- PJ12MD_100, PJ12MD_101, PJ12MD_110, PJ12MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PJCR2", 0xfffe390a, 16, 4) {
- PJ11MD_000, PJ11MD_001, PJ11MD_010, PJ11MD_011,
- PJ11MD_100, PJ11MD_101, PJ11MD_110, PJ11MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ10MD_000, PJ10MD_001, PJ10MD_010, PJ10MD_011,
- PJ10MD_100, PJ10MD_101, PJ10MD_110, PJ10MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ9MD_000, PJ9MD_001, PJ9MD_010, PJ9MD_011,
- PJ9MD_100, PJ9MD_101, PJ9MD_110, PJ9MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ8MD_000, PJ8MD_001, PJ8MD_010, PJ8MD_011,
- PJ8MD_100, PJ8MD_101, PJ8MD_110, PJ8MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PJCR1", 0xfffe390c, 16, 4) {
- PJ7MD_000, PJ7MD_001, PJ7MD_010, PJ7MD_011,
- PJ7MD_100, PJ7MD_101, PJ7MD_110, PJ7MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ6MD_000, PJ6MD_001, PJ6MD_010, PJ6MD_011,
- PJ6MD_100, PJ6MD_101, PJ6MD_110, PJ6MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ5MD_000, PJ5MD_001, PJ5MD_010, PJ5MD_011,
- PJ5MD_100, PJ5MD_101, PJ5MD_110, PJ5MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ4MD_000, PJ4MD_001, PJ4MD_010, PJ4MD_011,
- PJ4MD_100, PJ4MD_101, PJ4MD_110, PJ4MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PJCR0", 0xfffe390e, 16, 4) {
- PJ3MD_000, PJ3MD_001, PJ3MD_010, PJ3MD_011,
- PJ3MD_100, PJ3MD_101, PJ3MD_110, PJ3MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
- PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
- PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
- PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
- 0, 0, 0, 0, 0, 0, 0, 0 }
- },
-
- { PINMUX_CFG_REG("PJIOR1", 0xfffe3910, 16, 1) {
- PJ31_IN, PJ31_OUT,
- PJ30_IN, PJ30_OUT,
- PJ29_IN, PJ29_OUT,
- PJ28_IN, PJ28_OUT,
- PJ27_IN, PJ27_OUT,
- PJ26_IN, PJ26_OUT,
- PJ25_IN, PJ25_OUT,
- PJ24_IN, PJ24_OUT,
- PJ23_IN, PJ23_OUT,
- PJ22_IN, PJ22_OUT,
- PJ21_IN, PJ21_OUT,
- PJ20_IN, PJ20_OUT,
- PJ19_IN, PJ19_OUT,
- PJ18_IN, PJ18_OUT,
- PJ17_IN, PJ17_OUT,
- PJ16_IN, PJ16_OUT }
- },
- { PINMUX_CFG_REG("PJIOR0", 0xfffe3912, 16, 1) {
- PJ15_IN, PJ15_OUT,
- PJ14_IN, PJ14_OUT,
- PJ13_IN, PJ13_OUT,
- PJ12_IN, PJ12_OUT,
- PJ11_IN, PJ11_OUT,
- PJ10_IN, PJ10_OUT,
- PJ9_IN, PJ9_OUT,
- PJ8_IN, PJ8_OUT,
- PJ7_IN, PJ7_OUT,
- PJ6_IN, PJ6_OUT,
- PJ5_IN, PJ5_OUT,
- PJ4_IN, PJ4_OUT,
- PJ3_IN, PJ3_OUT,
- PJ2_IN, PJ2_OUT,
- PJ1_IN, PJ1_OUT,
- PJ0_IN, PJ0_OUT }
- },
-
- {}
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PADR0", 0xfffe3816, 16) {
- 0, 0, 0, 0, 0, 0, 0, PA1_DATA,
- 0, 0, 0, 0, 0, 0, 0, PA0_DATA }
- },
-
- { PINMUX_DATA_REG("PBDR1", 0xfffe3834, 16) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, PB22_DATA, PB21_DATA, PB20_DATA,
- PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA }
- },
- { PINMUX_DATA_REG("PBDR0", 0xfffe3836, 16) {
- PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
- PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA, 0 }
- },
-
- { PINMUX_DATA_REG("PCDR0", 0xfffe3856, 16) {
- 0, 0, 0, 0,
- 0, 0, 0, PC8_DATA,
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
- },
-
- { PINMUX_DATA_REG("PDDR0", 0xfffe3876, 16) {
- PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
- PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
- },
-
- { PINMUX_DATA_REG("PEDR0", 0xfffe3896, 16) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
- PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
- },
-
- { PINMUX_DATA_REG("PFDR1", 0xfffe38b4, 16) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
- PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA }
- },
- { PINMUX_DATA_REG("PFDR0", 0xfffe38b6, 16) {
- PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
- PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
- },
-
- { PINMUX_DATA_REG("PGDR1", 0xfffe38d4, 16) {
- 0, 0, 0, 0,
- PG27_DATA, PG26_DATA, PG25_DATA, PG24_DATA,
- PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
- PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA }
- },
- { PINMUX_DATA_REG("PGDR0", 0xfffe38d6, 16) {
- PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
- PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
- PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
- PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
- },
-
- { PINMUX_DATA_REG("PJDR1", 0xfffe3914, 16) {
- PJ31_DATA, PJ30_DATA, PJ29_DATA, PJ28_DATA,
- PJ27_DATA, PJ26_DATA, PJ25_DATA, PJ24_DATA,
- PJ23_DATA, PJ22_DATA, PJ21_DATA, PJ20_DATA,
- PJ19_DATA, PJ18_DATA, PJ17_DATA, PJ16_DATA }
- },
- { PINMUX_DATA_REG("PJDR0", 0xfffe3916, 16) {
- PJ15_DATA, PJ14_DATA, PJ13_DATA, PJ12_DATA,
- PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
- PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
- PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
- },
-
- { }
-};
-
-static struct pinmux_info sh7269_pinmux_info = {
- .name = "sh7269_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_PA1,
- .last_gpio = GPIO_FN_LCD_M_DISP,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
+#include <cpu/pfc.h>
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7269_pinmux_info);
+ return sh_pfc_register("pfc-sh7269", NULL, 0);
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh3/pinmux-sh7720.c b/arch/sh/kernel/cpu/sh3/pinmux-sh7720.c
index 9ca154627147..7d3744ac7b08 100644
--- a/arch/sh/kernel/cpu/sh3/pinmux-sh7720.c
+++ b/arch/sh/kernel/cpu/sh3/pinmux-sh7720.c
@@ -10,1233 +10,11 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/sh7720.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
- PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
- PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
- PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
- PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
- PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA,
- PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
- PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
- PTE6_DATA, PTE5_DATA, PTE4_DATA,
- PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA,
- PTF6_DATA, PTF5_DATA, PTF4_DATA,
- PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
- PTG6_DATA, PTG5_DATA, PTG4_DATA,
- PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
- PTH6_DATA, PTH5_DATA, PTH4_DATA,
- PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
- PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
- PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
- PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA, PTL3_DATA,
- PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
- PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
- PTP4_DATA, PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA,
- PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
- PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
- PTS4_DATA, PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
- PTT4_DATA, PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
- PTU4_DATA, PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
- PTV4_DATA, PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
- PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
- PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
- PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
- PTC7_IN, PTC6_IN, PTC5_IN, PTC4_IN,
- PTC3_IN, PTC2_IN, PTC1_IN, PTC0_IN,
- PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN,
- PTD3_IN, PTD2_IN, PTD1_IN, PTD0_IN,
- PTE6_IN, PTE5_IN, PTE4_IN,
- PTE3_IN, PTE2_IN, PTE1_IN, PTE0_IN,
- PTF6_IN, PTF5_IN, PTF4_IN,
- PTF3_IN, PTF2_IN, PTF1_IN, PTF0_IN,
- PTG6_IN, PTG5_IN, PTG4_IN,
- PTG3_IN, PTG2_IN, PTG1_IN, PTG0_IN,
- PTH6_IN, PTH5_IN, PTH4_IN,
- PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
- PTJ6_IN, PTJ5_IN, PTJ4_IN,
- PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
- PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
- PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN, PTL3_IN,
- PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
- PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
- PTP4_IN, PTP3_IN, PTP2_IN, PTP1_IN, PTP0_IN,
- PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
- PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
- PTS4_IN, PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
- PTT4_IN, PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
- PTU4_IN, PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
- PTV4_IN, PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
- PINMUX_INPUT_END,
-
- PINMUX_INPUT_PULLUP_BEGIN,
- PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
- PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
- PTB7_IN_PU, PTB6_IN_PU, PTB5_IN_PU, PTB4_IN_PU,
- PTB3_IN_PU, PTB2_IN_PU, PTB1_IN_PU, PTB0_IN_PU,
- PTC7_IN_PU, PTC6_IN_PU, PTC5_IN_PU, PTC4_IN_PU,
- PTC3_IN_PU, PTC2_IN_PU, PTC1_IN_PU, PTC0_IN_PU,
- PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
- PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
- PTE4_IN_PU, PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
- PTF0_IN_PU,
- PTG6_IN_PU, PTG5_IN_PU, PTG4_IN_PU,
- PTG3_IN_PU, PTG2_IN_PU, PTG1_IN_PU, PTG0_IN_PU,
- PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
- PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
- PTJ6_IN_PU, PTJ5_IN_PU, PTJ4_IN_PU,
- PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
- PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
- PTL7_IN_PU, PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU, PTL3_IN_PU,
- PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
- PTM3_IN_PU, PTM2_IN_PU, PTM1_IN_PU, PTM0_IN_PU,
- PTP4_IN_PU, PTP3_IN_PU, PTP2_IN_PU, PTP1_IN_PU, PTP0_IN_PU,
- PTR7_IN_PU, PTR6_IN_PU, PTR5_IN_PU, PTR4_IN_PU,
- PTR3_IN_PU, PTR2_IN_PU, PTR1_IN_PU, PTR0_IN_PU,
- PTS4_IN_PU, PTS3_IN_PU, PTS2_IN_PU, PTS1_IN_PU, PTS0_IN_PU,
- PTT4_IN_PU, PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
- PTU4_IN_PU, PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
- PTV4_IN_PU, PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
- PINMUX_INPUT_PULLUP_END,
-
- PINMUX_OUTPUT_BEGIN,
- PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
- PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
- PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
- PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
- PTC7_OUT, PTC6_OUT, PTC5_OUT, PTC4_OUT,
- PTC3_OUT, PTC2_OUT, PTC1_OUT, PTC0_OUT,
- PTD7_OUT, PTD6_OUT, PTD5_OUT, PTD4_OUT,
- PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
- PTE4_OUT, PTE3_OUT, PTE2_OUT, PTE1_OUT, PTE0_OUT,
- PTF0_OUT,
- PTG6_OUT, PTG5_OUT, PTG4_OUT,
- PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
- PTH6_OUT, PTH5_OUT, PTH4_OUT,
- PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
- PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
- PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
- PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
- PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT, PTL3_OUT,
- PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
- PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
- PTP4_OUT, PTP3_OUT, PTP2_OUT, PTP1_OUT, PTP0_OUT,
- PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
- PTR3_OUT, PTR2_OUT, PTR1_OUT, PTR0_OUT,
- PTS4_OUT, PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
- PTT4_OUT, PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
- PTU4_OUT, PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
- PTV4_OUT, PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- PTA7_FN, PTA6_FN, PTA5_FN, PTA4_FN,
- PTA3_FN, PTA2_FN, PTA1_FN, PTA0_FN,
- PTB7_FN, PTB6_FN, PTB5_FN, PTB4_FN,
- PTB3_FN, PTB2_FN, PTB1_FN, PTB0_FN,
- PTC7_FN, PTC6_FN, PTC5_FN, PTC4_FN,
- PTC3_FN, PTC2_FN, PTC1_FN, PTC0_FN,
- PTD7_FN, PTD6_FN, PTD5_FN, PTD4_FN,
- PTD3_FN, PTD2_FN, PTD1_FN, PTD0_FN,
- PTE6_FN, PTE5_FN, PTE4_FN,
- PTE3_FN, PTE2_FN, PTE1_FN, PTE0_FN,
- PTF6_FN, PTF5_FN, PTF4_FN,
- PTF3_FN, PTF2_FN, PTF1_FN, PTF0_FN,
- PTG6_FN, PTG5_FN, PTG4_FN,
- PTG3_FN, PTG2_FN, PTG1_FN, PTG0_FN,
- PTH6_FN, PTH5_FN, PTH4_FN,
- PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
- PTJ6_FN, PTJ5_FN, PTJ4_FN,
- PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
- PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
- PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN, PTL3_FN,
- PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
- PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
- PTP4_FN, PTP3_FN, PTP2_FN, PTP1_FN, PTP0_FN,
- PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
- PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
- PTS4_FN, PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
- PTT4_FN, PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
- PTU4_FN, PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
- PTV4_FN, PTV3_FN, PTV2_FN, PTV1_FN, PTV0_FN,
-
- PSELA_1_0_00, PSELA_1_0_01, PSELA_1_0_10,
- PSELA_3_2_00, PSELA_3_2_01, PSELA_3_2_10, PSELA_3_2_11,
- PSELA_5_4_00, PSELA_5_4_01, PSELA_5_4_10, PSELA_5_4_11,
- PSELA_7_6_00, PSELA_7_6_01, PSELA_7_6_10,
- PSELA_9_8_00, PSELA_9_8_01, PSELA_9_8_10,
- PSELA_11_10_00, PSELA_11_10_01, PSELA_11_10_10,
- PSELA_13_12_00, PSELA_13_12_10,
- PSELA_15_14_00, PSELA_15_14_10,
- PSELB_9_8_00, PSELB_9_8_11,
- PSELB_11_10_00, PSELB_11_10_01, PSELB_11_10_10, PSELB_11_10_11,
- PSELB_13_12_00, PSELB_13_12_01, PSELB_13_12_10, PSELB_13_12_11,
- PSELB_15_14_00, PSELB_15_14_11,
- PSELC_9_8_00, PSELC_9_8_10,
- PSELC_11_10_00, PSELC_11_10_10,
- PSELC_13_12_00, PSELC_13_12_01, PSELC_13_12_10,
- PSELC_15_14_00, PSELC_15_14_01, PSELC_15_14_10,
- PSELD_1_0_00, PSELD_1_0_10,
- PSELD_11_10_00, PSELD_11_10_01,
- PSELD_15_14_00, PSELD_15_14_01, PSELD_15_14_10,
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
- D31_MARK, D30_MARK, D29_MARK, D28_MARK,
- D27_MARK, D26_MARK, D25_MARK, D24_MARK,
- D23_MARK, D22_MARK, D21_MARK, D20_MARK,
- D19_MARK, D18_MARK, D17_MARK, D16_MARK,
- IOIS16_MARK, RAS_MARK, CAS_MARK, CKE_MARK,
- CS5B_CE1A_MARK, CS6B_CE1B_MARK,
- A25_MARK, A24_MARK, A23_MARK, A22_MARK,
- A21_MARK, A20_MARK, A19_MARK, A0_MARK,
- REFOUT_MARK, IRQOUT_MARK,
- LCD_DATA15_MARK, LCD_DATA14_MARK,
- LCD_DATA13_MARK, LCD_DATA12_MARK,
- LCD_DATA11_MARK, LCD_DATA10_MARK,
- LCD_DATA9_MARK, LCD_DATA8_MARK,
- LCD_DATA7_MARK, LCD_DATA6_MARK,
- LCD_DATA5_MARK, LCD_DATA4_MARK,
- LCD_DATA3_MARK, LCD_DATA2_MARK,
- LCD_DATA1_MARK, LCD_DATA0_MARK,
- LCD_M_DISP_MARK,
- LCD_CL1_MARK, LCD_CL2_MARK,
- LCD_DON_MARK, LCD_FLM_MARK,
- LCD_VEPWC_MARK, LCD_VCPWC_MARK,
- AFE_RXIN_MARK, AFE_RDET_MARK,
- AFE_FS_MARK, AFE_TXOUT_MARK,
- AFE_SCLK_MARK, AFE_RLYCNT_MARK,
- AFE_HC1_MARK,
- IIC_SCL_MARK, IIC_SDA_MARK,
- DA1_MARK, DA0_MARK,
- AN3_MARK, AN2_MARK, AN1_MARK, AN0_MARK, ADTRG_MARK,
- USB1D_RCV_MARK, USB1D_TXSE0_MARK,
- USB1D_TXDPLS_MARK, USB1D_DMNS_MARK,
- USB1D_DPLS_MARK, USB1D_SPEED_MARK,
- USB1D_TXENL_MARK,
- USB2_PWR_EN_MARK, USB1_PWR_EN_USBF_UPLUP_MARK, USB1D_SUSPEND_MARK,
- IRQ5_MARK, IRQ4_MARK,
- IRQ3_IRL3_MARK, IRQ2_IRL2_MARK,
- IRQ1_IRL1_MARK, IRQ0_IRL0_MARK,
- PCC_REG_MARK, PCC_DRV_MARK,
- PCC_BVD2_MARK, PCC_BVD1_MARK,
- PCC_CD2_MARK, PCC_CD1_MARK,
- PCC_RESET_MARK, PCC_RDY_MARK,
- PCC_VS2_MARK, PCC_VS1_MARK,
- AUDATA3_MARK, AUDATA2_MARK, AUDATA1_MARK, AUDATA0_MARK,
- AUDCK_MARK, AUDSYNC_MARK, ASEBRKAK_MARK, TRST_MARK,
- TMS_MARK, TDO_MARK, TDI_MARK, TCK_MARK,
- DACK1_MARK, DREQ1_MARK, DACK0_MARK, DREQ0_MARK,
- TEND1_MARK, TEND0_MARK,
- SIOF0_SYNC_MARK, SIOF0_MCLK_MARK,
- SIOF0_TXD_MARK, SIOF0_RXD_MARK,
- SIOF0_SCK_MARK,
- SIOF1_SYNC_MARK, SIOF1_MCLK_MARK,
- SIOF1_TXD_MARK, SIOF1_RXD_MARK,
- SIOF1_SCK_MARK,
- SCIF0_TXD_MARK, SCIF0_RXD_MARK,
- SCIF0_RTS_MARK, SCIF0_CTS_MARK, SCIF0_SCK_MARK,
- SCIF1_TXD_MARK, SCIF1_RXD_MARK,
- SCIF1_RTS_MARK, SCIF1_CTS_MARK, SCIF1_SCK_MARK,
- TPU_TO1_MARK, TPU_TO0_MARK,
- TPU_TI3B_MARK, TPU_TI3A_MARK,
- TPU_TI2B_MARK, TPU_TI2A_MARK,
- TPU_TO3_MARK, TPU_TO2_MARK,
- SIM_D_MARK, SIM_CLK_MARK, SIM_RST_MARK,
- MMC_DAT_MARK, MMC_CMD_MARK,
- MMC_CLK_MARK, MMC_VDDON_MARK,
- MMC_ODMOD_MARK,
- STATUS0_MARK, STATUS1_MARK,
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
- /* PTA GPIO */
- PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT, PTA7_IN_PU),
- PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT, PTA6_IN_PU),
- PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT, PTA5_IN_PU),
- PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT, PTA4_IN_PU),
- PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT, PTA3_IN_PU),
- PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT, PTA2_IN_PU),
- PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT, PTA1_IN_PU),
- PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT, PTA0_IN_PU),
-
- /* PTB GPIO */
- PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT, PTB7_IN_PU),
- PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT, PTB6_IN_PU),
- PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT, PTB5_IN_PU),
- PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT, PTB4_IN_PU),
- PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT, PTB3_IN_PU),
- PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT, PTB2_IN_PU),
- PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT, PTB1_IN_PU),
- PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT, PTB0_IN_PU),
-
- /* PTC GPIO */
- PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT, PTC7_IN_PU),
- PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT, PTC6_IN_PU),
- PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT, PTC5_IN_PU),
- PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT, PTC4_IN_PU),
- PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT, PTC3_IN_PU),
- PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT, PTC2_IN_PU),
- PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT, PTC1_IN_PU),
- PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT, PTC0_IN_PU),
-
- /* PTD GPIO */
- PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT, PTD7_IN_PU),
- PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT, PTD6_IN_PU),
- PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT, PTD5_IN_PU),
- PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT, PTD4_IN_PU),
- PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT, PTD3_IN_PU),
- PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT, PTD2_IN_PU),
- PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT, PTD1_IN_PU),
- PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT, PTD0_IN_PU),
-
- /* PTE GPIO */
- PINMUX_DATA(PTE6_DATA, PTE6_IN),
- PINMUX_DATA(PTE5_DATA, PTE5_IN),
- PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT, PTE4_IN_PU),
- PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT, PTE3_IN_PU),
- PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT, PTE2_IN_PU),
- PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT, PTE1_IN_PU),
- PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT, PTE0_IN_PU),
-
- /* PTF GPIO */
- PINMUX_DATA(PTF6_DATA, PTF6_IN),
- PINMUX_DATA(PTF5_DATA, PTF5_IN),
- PINMUX_DATA(PTF4_DATA, PTF4_IN),
- PINMUX_DATA(PTF3_DATA, PTF3_IN),
- PINMUX_DATA(PTF2_DATA, PTF2_IN),
- PINMUX_DATA(PTF1_DATA, PTF1_IN),
- PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT, PTF0_IN_PU),
-
- /* PTG GPIO */
- PINMUX_DATA(PTG6_DATA, PTG6_IN, PTG6_OUT, PTG6_IN_PU),
- PINMUX_DATA(PTG5_DATA, PTG5_IN, PTG5_OUT, PTG5_IN_PU),
- PINMUX_DATA(PTG4_DATA, PTG4_IN, PTG4_OUT, PTG4_IN_PU),
- PINMUX_DATA(PTG3_DATA, PTG3_IN, PTG3_OUT, PTG3_IN_PU),
- PINMUX_DATA(PTG2_DATA, PTG2_IN, PTG2_OUT, PTG2_IN_PU),
- PINMUX_DATA(PTG1_DATA, PTG1_IN, PTG1_OUT, PTG1_IN_PU),
- PINMUX_DATA(PTG0_DATA, PTG0_IN, PTG0_OUT, PTG0_IN_PU),
-
- /* PTH GPIO */
- PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT, PTH6_IN_PU),
- PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT, PTH5_IN_PU),
- PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT, PTH4_IN_PU),
- PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT, PTH3_IN_PU),
- PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT, PTH2_IN_PU),
- PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT, PTH1_IN_PU),
- PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT, PTH0_IN_PU),
-
- /* PTJ GPIO */
- PINMUX_DATA(PTJ6_DATA, PTJ6_IN, PTJ6_OUT, PTJ6_IN_PU),
- PINMUX_DATA(PTJ5_DATA, PTJ5_IN, PTJ5_OUT, PTJ5_IN_PU),
- PINMUX_DATA(PTJ4_DATA, PTJ4_IN, PTJ4_OUT, PTJ4_IN_PU),
- PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT, PTJ3_IN_PU),
- PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT, PTJ2_IN_PU),
- PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT, PTJ1_IN_PU),
- PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT, PTJ0_IN_PU),
-
- /* PTK GPIO */
- PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT, PTK3_IN_PU),
- PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT, PTK2_IN_PU),
- PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT, PTK1_IN_PU),
- PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT, PTK0_IN_PU),
-
- /* PTL GPIO */
- PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT, PTL7_IN_PU),
- PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT, PTL6_IN_PU),
- PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT, PTL5_IN_PU),
- PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT, PTL4_IN_PU),
- PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT, PTL3_IN_PU),
-
- /* PTM GPIO */
- PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT, PTM7_IN_PU),
- PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT, PTM6_IN_PU),
- PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT, PTM5_IN_PU),
- PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT, PTM4_IN_PU),
- PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT, PTM3_IN_PU),
- PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT, PTM2_IN_PU),
- PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT, PTM1_IN_PU),
- PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT, PTM0_IN_PU),
-
- /* PTP GPIO */
- PINMUX_DATA(PTP4_DATA, PTP4_IN, PTP4_OUT, PTP4_IN_PU),
- PINMUX_DATA(PTP3_DATA, PTP3_IN, PTP3_OUT, PTP3_IN_PU),
- PINMUX_DATA(PTP2_DATA, PTP2_IN, PTP2_OUT, PTP2_IN_PU),
- PINMUX_DATA(PTP1_DATA, PTP1_IN, PTP1_OUT, PTP1_IN_PU),
- PINMUX_DATA(PTP0_DATA, PTP0_IN, PTP0_OUT, PTP0_IN_PU),
-
- /* PTR GPIO */
- PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT, PTR7_IN_PU),
- PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT, PTR6_IN_PU),
- PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT, PTR5_IN_PU),
- PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT, PTR4_IN_PU),
- PINMUX_DATA(PTR3_DATA, PTR3_IN, PTR3_OUT, PTR3_IN_PU),
- PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_OUT, PTR2_IN_PU),
- PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT, PTR1_IN_PU),
- PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT, PTR0_IN_PU),
-
- /* PTS GPIO */
- PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT, PTS4_IN_PU),
- PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT, PTS3_IN_PU),
- PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT, PTS2_IN_PU),
- PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT, PTS1_IN_PU),
- PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT, PTS0_IN_PU),
-
- /* PTT GPIO */
- PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT, PTT4_IN_PU),
- PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT, PTT3_IN_PU),
- PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT, PTT2_IN_PU),
- PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT, PTT1_IN_PU),
- PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT, PTT0_IN_PU),
-
- /* PTU GPIO */
- PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT, PTU4_IN_PU),
- PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT, PTU3_IN_PU),
- PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT, PTU2_IN_PU),
- PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT, PTU1_IN_PU),
- PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT, PTU0_IN_PU),
-
- /* PTV GPIO */
- PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT, PTV4_IN_PU),
- PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT, PTV3_IN_PU),
- PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT, PTV2_IN_PU),
- PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT, PTV1_IN_PU),
- PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT, PTV0_IN_PU),
-
- /* PTA FN */
- PINMUX_DATA(D23_MARK, PTA7_FN),
- PINMUX_DATA(D22_MARK, PTA6_FN),
- PINMUX_DATA(D21_MARK, PTA5_FN),
- PINMUX_DATA(D20_MARK, PTA4_FN),
- PINMUX_DATA(D19_MARK, PTA3_FN),
- PINMUX_DATA(D18_MARK, PTA2_FN),
- PINMUX_DATA(D17_MARK, PTA1_FN),
- PINMUX_DATA(D16_MARK, PTA0_FN),
-
- /* PTB FN */
- PINMUX_DATA(D31_MARK, PTB7_FN),
- PINMUX_DATA(D30_MARK, PTB6_FN),
- PINMUX_DATA(D29_MARK, PTB5_FN),
- PINMUX_DATA(D28_MARK, PTB4_FN),
- PINMUX_DATA(D27_MARK, PTB3_FN),
- PINMUX_DATA(D26_MARK, PTB2_FN),
- PINMUX_DATA(D25_MARK, PTB1_FN),
- PINMUX_DATA(D24_MARK, PTB0_FN),
-
- /* PTC FN */
- PINMUX_DATA(LCD_DATA7_MARK, PTC7_FN),
- PINMUX_DATA(LCD_DATA6_MARK, PTC6_FN),
- PINMUX_DATA(LCD_DATA5_MARK, PTC5_FN),
- PINMUX_DATA(LCD_DATA4_MARK, PTC4_FN),
- PINMUX_DATA(LCD_DATA3_MARK, PTC3_FN),
- PINMUX_DATA(LCD_DATA2_MARK, PTC2_FN),
- PINMUX_DATA(LCD_DATA1_MARK, PTC1_FN),
- PINMUX_DATA(LCD_DATA0_MARK, PTC0_FN),
-
- /* PTD FN */
- PINMUX_DATA(LCD_DATA15_MARK, PTD7_FN),
- PINMUX_DATA(LCD_DATA14_MARK, PTD6_FN),
- PINMUX_DATA(LCD_DATA13_MARK, PTD5_FN),
- PINMUX_DATA(LCD_DATA12_MARK, PTD4_FN),
- PINMUX_DATA(LCD_DATA11_MARK, PTD3_FN),
- PINMUX_DATA(LCD_DATA10_MARK, PTD2_FN),
- PINMUX_DATA(LCD_DATA9_MARK, PTD1_FN),
- PINMUX_DATA(LCD_DATA8_MARK, PTD0_FN),
-
- /* PTE FN */
- PINMUX_DATA(IIC_SCL_MARK, PSELB_9_8_00, PTE6_FN),
- PINMUX_DATA(AFE_RXIN_MARK, PSELB_9_8_11, PTE6_FN),
- PINMUX_DATA(IIC_SDA_MARK, PSELB_9_8_00, PTE5_FN),
- PINMUX_DATA(AFE_RDET_MARK, PSELB_9_8_11, PTE5_FN),
- PINMUX_DATA(LCD_M_DISP_MARK, PTE4_FN),
- PINMUX_DATA(LCD_CL1_MARK, PTE3_FN),
- PINMUX_DATA(LCD_CL2_MARK, PTE2_FN),
- PINMUX_DATA(LCD_DON_MARK, PTE1_FN),
- PINMUX_DATA(LCD_FLM_MARK, PTE0_FN),
-
- /* PTF FN */
- PINMUX_DATA(DA1_MARK, PTF6_FN),
- PINMUX_DATA(DA0_MARK, PTF5_FN),
- PINMUX_DATA(AN3_MARK, PTF4_FN),
- PINMUX_DATA(AN2_MARK, PTF3_FN),
- PINMUX_DATA(AN1_MARK, PTF2_FN),
- PINMUX_DATA(AN0_MARK, PTF1_FN),
- PINMUX_DATA(ADTRG_MARK, PTF0_FN),
-
- /* PTG FN */
- PINMUX_DATA(USB1D_RCV_MARK, PSELA_3_2_00, PTG6_FN),
- PINMUX_DATA(AFE_FS_MARK, PSELA_3_2_01, PTG6_FN),
- PINMUX_DATA(PCC_REG_MARK, PSELA_3_2_10, PTG6_FN),
- PINMUX_DATA(IRQ5_MARK, PSELA_3_2_11, PTG6_FN),
- PINMUX_DATA(USB1D_TXSE0_MARK, PSELA_5_4_00, PTG5_FN),
- PINMUX_DATA(AFE_TXOUT_MARK, PSELA_5_4_01, PTG5_FN),
- PINMUX_DATA(PCC_DRV_MARK, PSELA_5_4_10, PTG5_FN),
- PINMUX_DATA(IRQ4_MARK, PSELA_5_4_11, PTG5_FN),
- PINMUX_DATA(USB1D_TXDPLS_MARK, PSELA_7_6_00, PTG4_FN),
- PINMUX_DATA(AFE_SCLK_MARK, PSELA_7_6_01, PTG4_FN),
- PINMUX_DATA(IOIS16_MARK, PSELA_7_6_10, PTG4_FN),
- PINMUX_DATA(USB1D_DMNS_MARK, PSELA_9_8_00, PTG3_FN),
- PINMUX_DATA(AFE_RLYCNT_MARK, PSELA_9_8_01, PTG3_FN),
- PINMUX_DATA(PCC_BVD2_MARK, PSELA_9_8_10, PTG3_FN),
- PINMUX_DATA(USB1D_DPLS_MARK, PSELA_11_10_00, PTG2_FN),
- PINMUX_DATA(AFE_HC1_MARK, PSELA_11_10_01, PTG2_FN),
- PINMUX_DATA(PCC_BVD1_MARK, PSELA_11_10_10, PTG2_FN),
- PINMUX_DATA(USB1D_SPEED_MARK, PSELA_13_12_00, PTG1_FN),
- PINMUX_DATA(PCC_CD2_MARK, PSELA_13_12_10, PTG1_FN),
- PINMUX_DATA(USB1D_TXENL_MARK, PSELA_15_14_00, PTG0_FN),
- PINMUX_DATA(PCC_CD1_MARK, PSELA_15_14_10, PTG0_FN),
-
- /* PTH FN */
- PINMUX_DATA(RAS_MARK, PTH6_FN),
- PINMUX_DATA(CAS_MARK, PTH5_FN),
- PINMUX_DATA(CKE_MARK, PTH4_FN),
- PINMUX_DATA(STATUS1_MARK, PTH3_FN),
- PINMUX_DATA(STATUS0_MARK, PTH2_FN),
- PINMUX_DATA(USB2_PWR_EN_MARK, PTH1_FN),
- PINMUX_DATA(USB1_PWR_EN_USBF_UPLUP_MARK, PTH0_FN),
-
- /* PTJ FN */
- PINMUX_DATA(AUDCK_MARK, PTJ6_FN),
- PINMUX_DATA(ASEBRKAK_MARK, PTJ5_FN),
- PINMUX_DATA(AUDATA3_MARK, PTJ4_FN),
- PINMUX_DATA(AUDATA2_MARK, PTJ3_FN),
- PINMUX_DATA(AUDATA1_MARK, PTJ2_FN),
- PINMUX_DATA(AUDATA0_MARK, PTJ1_FN),
- PINMUX_DATA(AUDSYNC_MARK, PTJ0_FN),
-
- /* PTK FN */
- PINMUX_DATA(PCC_RESET_MARK, PTK3_FN),
- PINMUX_DATA(PCC_RDY_MARK, PTK2_FN),
- PINMUX_DATA(PCC_VS2_MARK, PTK1_FN),
- PINMUX_DATA(PCC_VS1_MARK, PTK0_FN),
-
- /* PTL FN */
- PINMUX_DATA(TRST_MARK, PTL7_FN),
- PINMUX_DATA(TMS_MARK, PTL6_FN),
- PINMUX_DATA(TDO_MARK, PTL5_FN),
- PINMUX_DATA(TDI_MARK, PTL4_FN),
- PINMUX_DATA(TCK_MARK, PTL3_FN),
-
- /* PTM FN */
- PINMUX_DATA(DREQ1_MARK, PTM7_FN),
- PINMUX_DATA(DREQ0_MARK, PTM6_FN),
- PINMUX_DATA(DACK1_MARK, PTM5_FN),
- PINMUX_DATA(DACK0_MARK, PTM4_FN),
- PINMUX_DATA(TEND1_MARK, PTM3_FN),
- PINMUX_DATA(TEND0_MARK, PTM2_FN),
- PINMUX_DATA(CS5B_CE1A_MARK, PTM1_FN),
- PINMUX_DATA(CS6B_CE1B_MARK, PTM0_FN),
-
- /* PTP FN */
- PINMUX_DATA(USB1D_SUSPEND_MARK, PSELA_1_0_00, PTP4_FN),
- PINMUX_DATA(REFOUT_MARK, PSELA_1_0_01, PTP4_FN),
- PINMUX_DATA(IRQOUT_MARK, PSELA_1_0_10, PTP4_FN),
- PINMUX_DATA(IRQ3_IRL3_MARK, PTP3_FN),
- PINMUX_DATA(IRQ2_IRL2_MARK, PTP2_FN),
- PINMUX_DATA(IRQ1_IRL1_MARK, PTP1_FN),
- PINMUX_DATA(IRQ0_IRL0_MARK, PTP0_FN),
-
- /* PTR FN */
- PINMUX_DATA(A25_MARK, PTR7_FN),
- PINMUX_DATA(A24_MARK, PTR6_FN),
- PINMUX_DATA(A23_MARK, PTR5_FN),
- PINMUX_DATA(A22_MARK, PTR4_FN),
- PINMUX_DATA(A21_MARK, PTR3_FN),
- PINMUX_DATA(A20_MARK, PTR2_FN),
- PINMUX_DATA(A19_MARK, PTR1_FN),
- PINMUX_DATA(A0_MARK, PTR0_FN),
-
- /* PTS FN */
- PINMUX_DATA(SIOF0_SYNC_MARK, PTS4_FN),
- PINMUX_DATA(SIOF0_MCLK_MARK, PTS3_FN),
- PINMUX_DATA(SIOF0_TXD_MARK, PTS2_FN),
- PINMUX_DATA(SIOF0_RXD_MARK, PTS1_FN),
- PINMUX_DATA(SIOF0_SCK_MARK, PTS0_FN),
-
- /* PTT FN */
- PINMUX_DATA(SCIF0_CTS_MARK, PSELB_15_14_00, PTT4_FN),
- PINMUX_DATA(TPU_TO1_MARK, PSELB_15_14_11, PTT4_FN),
- PINMUX_DATA(SCIF0_RTS_MARK, PSELB_15_14_00, PTT3_FN),
- PINMUX_DATA(TPU_TO0_MARK, PSELB_15_14_11, PTT3_FN),
- PINMUX_DATA(SCIF0_TXD_MARK, PTT2_FN),
- PINMUX_DATA(SCIF0_RXD_MARK, PTT1_FN),
- PINMUX_DATA(SCIF0_SCK_MARK, PTT0_FN),
-
- /* PTU FN */
- PINMUX_DATA(SIOF1_SYNC_MARK, PTU4_FN),
- PINMUX_DATA(SIOF1_MCLK_MARK, PSELD_11_10_00, PTU3_FN),
- PINMUX_DATA(TPU_TI3B_MARK, PSELD_11_10_01, PTU3_FN),
- PINMUX_DATA(SIOF1_TXD_MARK, PSELD_15_14_00, PTU2_FN),
- PINMUX_DATA(TPU_TI3A_MARK, PSELD_15_14_01, PTU2_FN),
- PINMUX_DATA(MMC_DAT_MARK, PSELD_15_14_10, PTU2_FN),
- PINMUX_DATA(SIOF1_RXD_MARK, PSELC_13_12_00, PTU1_FN),
- PINMUX_DATA(TPU_TI2B_MARK, PSELC_13_12_01, PTU1_FN),
- PINMUX_DATA(MMC_CMD_MARK, PSELC_13_12_10, PTU1_FN),
- PINMUX_DATA(SIOF1_SCK_MARK, PSELC_15_14_00, PTU0_FN),
- PINMUX_DATA(TPU_TI2A_MARK, PSELC_15_14_01, PTU0_FN),
- PINMUX_DATA(MMC_CLK_MARK, PSELC_15_14_10, PTU0_FN),
-
- /* PTV FN */
- PINMUX_DATA(SCIF1_CTS_MARK, PSELB_11_10_00, PTV4_FN),
- PINMUX_DATA(TPU_TO3_MARK, PSELB_11_10_01, PTV4_FN),
- PINMUX_DATA(MMC_VDDON_MARK, PSELB_11_10_10, PTV4_FN),
- PINMUX_DATA(LCD_VEPWC_MARK, PSELB_11_10_11, PTV4_FN),
- PINMUX_DATA(SCIF1_RTS_MARK, PSELB_13_12_00, PTV3_FN),
- PINMUX_DATA(TPU_TO2_MARK, PSELB_13_12_01, PTV3_FN),
- PINMUX_DATA(MMC_ODMOD_MARK, PSELB_13_12_10, PTV3_FN),
- PINMUX_DATA(LCD_VCPWC_MARK, PSELB_13_12_11, PTV3_FN),
- PINMUX_DATA(SCIF1_TXD_MARK, PSELC_9_8_00, PTV2_FN),
- PINMUX_DATA(SIM_D_MARK, PSELC_9_8_10, PTV2_FN),
- PINMUX_DATA(SCIF1_RXD_MARK, PSELC_11_10_00, PTV1_FN),
- PINMUX_DATA(SIM_RST_MARK, PSELC_11_10_10, PTV1_FN),
- PINMUX_DATA(SCIF1_SCK_MARK, PSELD_1_0_00, PTV0_FN),
- PINMUX_DATA(SIM_CLK_MARK, PSELD_1_0_10, PTV0_FN),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
- /* PTA */
- PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
- PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
- PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
- PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
- PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
- PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
- PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
- PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
-
- /* PTB */
- PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
- PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
- PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
- PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
- PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
- PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
- PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
- PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
-
- /* PTC */
- PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
- PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
- PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
- PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
- PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
- PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
- PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
- PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
-
- /* PTD */
- PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
- PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
- PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
- PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
- PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
- PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
- PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
- PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
-
- /* PTE */
- PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
- PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
- PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
- PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
- PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
- PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
- PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
-
- /* PTF */
- PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
- PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
- PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
- PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
- PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
- PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
- PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
-
- /* PTG */
- PINMUX_GPIO(GPIO_PTG6, PTG6_DATA),
- PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
- PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
- PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
- PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
- PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
- PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
-
- /* PTH */
- PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
- PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
- PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
- PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
- PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
- PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
- PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
-
- /* PTJ */
- PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
- PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
- PINMUX_GPIO(GPIO_PTJ4, PTJ4_DATA),
- PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
- PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
- PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
- PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
-
- /* PTK */
- PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
- PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
- PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
- PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
-
- /* PTL */
- PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
- PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
- PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
- PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
- PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
-
- /* PTM */
- PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
- PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
- PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
- PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
- PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
- PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
- PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
- PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
-
- /* PTP */
- PINMUX_GPIO(GPIO_PTP4, PTP4_DATA),
- PINMUX_GPIO(GPIO_PTP3, PTP3_DATA),
- PINMUX_GPIO(GPIO_PTP2, PTP2_DATA),
- PINMUX_GPIO(GPIO_PTP1, PTP1_DATA),
- PINMUX_GPIO(GPIO_PTP0, PTP0_DATA),
-
- /* PTR */
- PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
- PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
- PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
- PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
- PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
- PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
- PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
- PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
-
- /* PTS */
- PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
- PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
- PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
- PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
- PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
-
- /* PTT */
- PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
- PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
- PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
- PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
- PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
-
- /* PTU */
- PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
- PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
- PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
- PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
- PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
-
- /* PTV */
- PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
- PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
- PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
- PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
- PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
-
- /* BSC */
- PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
- PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
- PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
- PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
- PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
- PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
- PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
- PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
- PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
- PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
- PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
- PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
- PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
- PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
- PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
- PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
- PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
- PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
- PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
- PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
- PINMUX_GPIO(GPIO_FN_CS5B_CE1A, CS5B_CE1A_MARK),
- PINMUX_GPIO(GPIO_FN_CS6B_CE1B, CS6B_CE1B_MARK),
- PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
- PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
- PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
- PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
- PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
- PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
- PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
- PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
- PINMUX_GPIO(GPIO_FN_REFOUT, REFOUT_MARK),
- PINMUX_GPIO(GPIO_FN_IRQOUT, IRQOUT_MARK),
-
- /* LCDC */
- PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_CL1, LCD_CL1_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_CL2, LCD_CL2_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_DON, LCD_DON_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_FLM, LCD_FLM_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_VEPWC, LCD_VEPWC_MARK),
- PINMUX_GPIO(GPIO_FN_LCD_VCPWC, LCD_VCPWC_MARK),
-
- /* AFEIF */
- PINMUX_GPIO(GPIO_FN_AFE_RXIN, AFE_RXIN_MARK),
- PINMUX_GPIO(GPIO_FN_AFE_RDET, AFE_RDET_MARK),
- PINMUX_GPIO(GPIO_FN_AFE_FS, AFE_FS_MARK),
- PINMUX_GPIO(GPIO_FN_AFE_TXOUT, AFE_TXOUT_MARK),
- PINMUX_GPIO(GPIO_FN_AFE_SCLK, AFE_SCLK_MARK),
- PINMUX_GPIO(GPIO_FN_AFE_RLYCNT, AFE_RLYCNT_MARK),
- PINMUX_GPIO(GPIO_FN_AFE_HC1, AFE_HC1_MARK),
-
- /* IIC */
- PINMUX_GPIO(GPIO_FN_IIC_SCL, IIC_SCL_MARK),
- PINMUX_GPIO(GPIO_FN_IIC_SDA, IIC_SDA_MARK),
-
- /* DAC */
- PINMUX_GPIO(GPIO_FN_DA1, DA1_MARK),
- PINMUX_GPIO(GPIO_FN_DA0, DA0_MARK),
-
- /* ADC */
- PINMUX_GPIO(GPIO_FN_AN3, AN3_MARK),
- PINMUX_GPIO(GPIO_FN_AN2, AN2_MARK),
- PINMUX_GPIO(GPIO_FN_AN1, AN1_MARK),
- PINMUX_GPIO(GPIO_FN_AN0, AN0_MARK),
- PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
-
- /* USB */
- PINMUX_GPIO(GPIO_FN_USB1D_RCV, USB1D_RCV_MARK),
- PINMUX_GPIO(GPIO_FN_USB1D_TXSE0, USB1D_TXSE0_MARK),
- PINMUX_GPIO(GPIO_FN_USB1D_TXDPLS, USB1D_TXDPLS_MARK),
- PINMUX_GPIO(GPIO_FN_USB1D_DMNS, USB1D_DMNS_MARK),
- PINMUX_GPIO(GPIO_FN_USB1D_DPLS, USB1D_DPLS_MARK),
- PINMUX_GPIO(GPIO_FN_USB1D_SPEED, USB1D_SPEED_MARK),
- PINMUX_GPIO(GPIO_FN_USB1D_TXENL, USB1D_TXENL_MARK),
-
- PINMUX_GPIO(GPIO_FN_USB2_PWR_EN, USB2_PWR_EN_MARK),
- PINMUX_GPIO(GPIO_FN_USB1_PWR_EN_USBF_UPLUP,
- USB1_PWR_EN_USBF_UPLUP_MARK),
- PINMUX_GPIO(GPIO_FN_USB1D_SUSPEND, USB1D_SUSPEND_MARK),
-
- /* INTC */
- PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ4, IRQ4_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3_IRL3, IRQ3_IRL3_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2_IRL2, IRQ2_IRL2_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1_IRL1, IRQ1_IRL1_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0_IRL0, IRQ0_IRL0_MARK),
-
- /* PCC */
- PINMUX_GPIO(GPIO_FN_PCC_REG, PCC_REG_MARK),
- PINMUX_GPIO(GPIO_FN_PCC_DRV, PCC_DRV_MARK),
- PINMUX_GPIO(GPIO_FN_PCC_BVD2, PCC_BVD2_MARK),
- PINMUX_GPIO(GPIO_FN_PCC_BVD1, PCC_BVD1_MARK),
- PINMUX_GPIO(GPIO_FN_PCC_CD2, PCC_CD2_MARK),
- PINMUX_GPIO(GPIO_FN_PCC_CD1, PCC_CD1_MARK),
- PINMUX_GPIO(GPIO_FN_PCC_RESET, PCC_RESET_MARK),
- PINMUX_GPIO(GPIO_FN_PCC_RDY, PCC_RDY_MARK),
- PINMUX_GPIO(GPIO_FN_PCC_VS2, PCC_VS2_MARK),
- PINMUX_GPIO(GPIO_FN_PCC_VS1, PCC_VS1_MARK),
-
- /* HUDI */
- PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
- PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
- PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_ASEBRKAK, ASEBRKAK_MARK),
- PINMUX_GPIO(GPIO_FN_TRST, TRST_MARK),
- PINMUX_GPIO(GPIO_FN_TMS, TMS_MARK),
- PINMUX_GPIO(GPIO_FN_TDO, TDO_MARK),
- PINMUX_GPIO(GPIO_FN_TDI, TDI_MARK),
- PINMUX_GPIO(GPIO_FN_TCK, TCK_MARK),
-
- /* DMAC */
- PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
- PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
- PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
-
- /* SIOF0 */
- PINMUX_GPIO(GPIO_FN_SIOF0_SYNC, SIOF0_SYNC_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF0_MCLK, SIOF0_MCLK_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF0_TXD, SIOF0_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF0_RXD, SIOF0_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF0_SCK, SIOF0_SCK_MARK),
-
- /* SIOF1 */
- PINMUX_GPIO(GPIO_FN_SIOF1_SYNC, SIOF1_SYNC_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF1_MCLK, SIOF1_MCLK_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF1_TXD, SIOF1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF1_RXD, SIOF1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF1_SCK, SIOF1_SCK_MARK),
-
- /* SCIF0 */
- PINMUX_GPIO(GPIO_FN_SCIF0_TXD, SCIF0_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_RXD, SCIF0_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_RTS, SCIF0_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_CTS, SCIF0_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_SCK, SCIF0_SCK_MARK),
-
- /* SCIF1 */
- PINMUX_GPIO(GPIO_FN_SCIF1_TXD, SCIF1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_RXD, SCIF1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_RTS, SCIF1_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_CTS, SCIF1_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_SCK, SCIF1_SCK_MARK),
-
- /* TPU */
- PINMUX_GPIO(GPIO_FN_TPU_TO1, TPU_TO1_MARK),
- PINMUX_GPIO(GPIO_FN_TPU_TO0, TPU_TO0_MARK),
- PINMUX_GPIO(GPIO_FN_TPU_TI3B, TPU_TI3B_MARK),
- PINMUX_GPIO(GPIO_FN_TPU_TI3A, TPU_TI3A_MARK),
- PINMUX_GPIO(GPIO_FN_TPU_TI2B, TPU_TI2B_MARK),
- PINMUX_GPIO(GPIO_FN_TPU_TI2A, TPU_TI2A_MARK),
- PINMUX_GPIO(GPIO_FN_TPU_TO3, TPU_TO3_MARK),
- PINMUX_GPIO(GPIO_FN_TPU_TO2, TPU_TO2_MARK),
-
- /* SIM */
- PINMUX_GPIO(GPIO_FN_SIM_D, SIM_D_MARK),
- PINMUX_GPIO(GPIO_FN_SIM_CLK, SIM_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SIM_RST, SIM_RST_MARK),
-
- /* MMC */
- PINMUX_GPIO(GPIO_FN_MMC_DAT, MMC_DAT_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_CMD, MMC_CMD_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_CLK, MMC_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_VDDON, MMC_VDDON_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_ODMOD, MMC_ODMOD_MARK),
-
- /* SYSC */
- PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
-};
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- { PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
- PTA7_FN, PTA7_OUT, PTA7_IN_PU, PTA7_IN,
- PTA6_FN, PTA6_OUT, PTA6_IN_PU, PTA6_IN,
- PTA5_FN, PTA5_OUT, PTA5_IN_PU, PTA5_IN,
- PTA4_FN, PTA4_OUT, PTA4_IN_PU, PTA4_IN,
- PTA3_FN, PTA3_OUT, PTA3_IN_PU, PTA3_IN,
- PTA2_FN, PTA2_OUT, PTA2_IN_PU, PTA2_IN,
- PTA1_FN, PTA1_OUT, PTA1_IN_PU, PTA1_IN,
- PTA0_FN, PTA0_OUT, PTA0_IN_PU, PTA0_IN }
- },
- { PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
- PTB7_FN, PTB7_OUT, PTB7_IN_PU, PTB7_IN,
- PTB6_FN, PTB6_OUT, PTB6_IN_PU, PTB6_IN,
- PTB5_FN, PTB5_OUT, PTB5_IN_PU, PTB5_IN,
- PTB4_FN, PTB4_OUT, PTB4_IN_PU, PTB4_IN,
- PTB3_FN, PTB3_OUT, PTB3_IN_PU, PTB3_IN,
- PTB2_FN, PTB2_OUT, PTB2_IN_PU, PTB2_IN,
- PTB1_FN, PTB1_OUT, PTB1_IN_PU, PTB1_IN,
- PTB0_FN, PTB0_OUT, PTB0_IN_PU, PTB0_IN }
- },
- { PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
- PTC7_FN, PTC7_OUT, PTC7_IN_PU, PTC7_IN,
- PTC6_FN, PTC6_OUT, PTC6_IN_PU, PTC6_IN,
- PTC5_FN, PTC5_OUT, PTC5_IN_PU, PTC5_IN,
- PTC4_FN, PTC4_OUT, PTC4_IN_PU, PTC4_IN,
- PTC3_FN, PTC3_OUT, PTC3_IN_PU, PTC3_IN,
- PTC2_FN, PTC2_OUT, PTC2_IN_PU, PTC2_IN,
- PTC1_FN, PTC1_OUT, PTC1_IN_PU, PTC1_IN,
- PTC0_FN, PTC0_OUT, PTC0_IN_PU, PTC0_IN }
- },
- { PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
- PTD7_FN, PTD7_OUT, PTD7_IN_PU, PTD7_IN,
- PTD6_FN, PTD6_OUT, PTD6_IN_PU, PTD6_IN,
- PTD5_FN, PTD5_OUT, PTD5_IN_PU, PTD5_IN,
- PTD4_FN, PTD4_OUT, PTD4_IN_PU, PTD4_IN,
- PTD3_FN, PTD3_OUT, PTD3_IN_PU, PTD3_IN,
- PTD2_FN, PTD2_OUT, PTD2_IN_PU, PTD2_IN,
- PTD1_FN, PTD1_OUT, PTD1_IN_PU, PTD1_IN,
- PTD0_FN, PTD0_OUT, PTD0_IN_PU, PTD0_IN }
- },
- { PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
- 0, 0, 0, 0,
- PTE6_FN, 0, 0, PTE6_IN,
- PTE5_FN, 0, 0, PTE5_IN,
- PTE4_FN, PTE4_OUT, PTE4_IN_PU, PTE4_IN,
- PTE3_FN, PTE3_OUT, PTE3_IN_PU, PTE3_IN,
- PTE2_FN, PTE2_OUT, PTE2_IN_PU, PTE2_IN,
- PTE1_FN, PTE1_OUT, PTE1_IN_PU, PTE1_IN,
- PTE0_FN, PTE0_OUT, PTE0_IN_PU, PTE0_IN }
- },
- { PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
- 0, 0, 0, 0,
- PTF6_FN, 0, 0, PTF6_IN,
- PTF5_FN, 0, 0, PTF5_IN,
- PTF4_FN, 0, 0, PTF4_IN,
- PTF3_FN, 0, 0, PTF3_IN,
- PTF2_FN, 0, 0, PTF2_IN,
- PTF1_FN, 0, 0, PTF1_IN,
- PTF0_FN, 0, 0, PTF0_IN }
- },
- { PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
- 0, 0, 0, 0,
- PTG6_FN, PTG6_OUT, PTG6_IN_PU, PTG6_IN,
- PTG5_FN, PTG5_OUT, PTG5_IN_PU, PTG5_IN,
- PTG4_FN, PTG4_OUT, PTG4_IN_PU, PTG4_IN,
- PTG3_FN, PTG3_OUT, PTG3_IN_PU, PTG3_IN,
- PTG2_FN, PTG2_OUT, PTG2_IN_PU, PTG2_IN,
- PTG1_FN, PTG1_OUT, PTG1_IN_PU, PTG1_IN,
- PTG0_FN, PTG0_OUT, PTG0_IN_PU, PTG0_IN }
- },
- { PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
- 0, 0, 0, 0,
- PTH6_FN, PTH6_OUT, PTH6_IN_PU, PTH6_IN,
- PTH5_FN, PTH5_OUT, PTH5_IN_PU, PTH5_IN,
- PTH4_FN, PTH4_OUT, PTH4_IN_PU, PTH4_IN,
- PTH3_FN, PTH3_OUT, PTH3_IN_PU, PTH3_IN,
- PTH2_FN, PTH2_OUT, PTH2_IN_PU, PTH2_IN,
- PTH1_FN, PTH1_OUT, PTH1_IN_PU, PTH1_IN,
- PTH0_FN, PTH0_OUT, PTH0_IN_PU, PTH0_IN }
- },
- { PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
- 0, 0, 0, 0,
- PTJ6_FN, PTJ6_OUT, PTJ6_IN_PU, PTJ6_IN,
- PTJ5_FN, PTJ5_OUT, PTJ5_IN_PU, PTJ5_IN,
- PTJ4_FN, PTJ4_OUT, PTJ4_IN_PU, PTJ4_IN,
- PTJ3_FN, PTJ3_OUT, PTJ3_IN_PU, PTJ3_IN,
- PTJ2_FN, PTJ2_OUT, PTJ2_IN_PU, PTJ2_IN,
- PTJ1_FN, PTJ1_OUT, PTJ1_IN_PU, PTJ1_IN,
- PTJ0_FN, PTJ0_OUT, PTJ0_IN_PU, PTJ0_IN }
- },
- { PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTK3_FN, PTK3_OUT, PTK3_IN_PU, PTK3_IN,
- PTK2_FN, PTK2_OUT, PTK2_IN_PU, PTK2_IN,
- PTK1_FN, PTK1_OUT, PTK1_IN_PU, PTK1_IN,
- PTK0_FN, PTK0_OUT, PTK0_IN_PU, PTK0_IN }
- },
- { PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
- PTL7_FN, PTL7_OUT, PTL7_IN_PU, PTL7_IN,
- PTL6_FN, PTL6_OUT, PTL6_IN_PU, PTL6_IN,
- PTL5_FN, PTL5_OUT, PTL5_IN_PU, PTL5_IN,
- PTL4_FN, PTL4_OUT, PTL4_IN_PU, PTL4_IN,
- PTL3_FN, PTL3_OUT, PTL3_IN_PU, PTL3_IN,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
- PTM7_FN, PTM7_OUT, PTM7_IN_PU, PTM7_IN,
- PTM6_FN, PTM6_OUT, PTM6_IN_PU, PTM6_IN,
- PTM5_FN, PTM5_OUT, PTM5_IN_PU, PTM5_IN,
- PTM4_FN, PTM4_OUT, PTM4_IN_PU, PTM4_IN,
- PTM3_FN, PTM3_OUT, PTM3_IN_PU, PTM3_IN,
- PTM2_FN, PTM2_OUT, PTM2_IN_PU, PTM2_IN,
- PTM1_FN, PTM1_OUT, PTM1_IN_PU, PTM1_IN,
- PTM0_FN, PTM0_OUT, PTM0_IN_PU, PTM0_IN }
- },
- { PINMUX_CFG_REG("PPCR", 0xa4050118, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTP4_FN, PTP4_OUT, PTP4_IN_PU, PTP4_IN,
- PTP3_FN, PTP3_OUT, PTP3_IN_PU, PTP3_IN,
- PTP2_FN, PTP2_OUT, PTP2_IN_PU, PTP2_IN,
- PTP1_FN, PTP1_OUT, PTP1_IN_PU, PTP1_IN,
- PTP0_FN, PTP0_OUT, PTP0_IN_PU, PTP0_IN }
- },
- { PINMUX_CFG_REG("PRCR", 0xa405011a, 16, 2) {
- PTR7_FN, PTR7_OUT, PTR7_IN_PU, PTR7_IN,
- PTR6_FN, PTR6_OUT, PTR6_IN_PU, PTR6_IN,
- PTR5_FN, PTR5_OUT, PTR5_IN_PU, PTR5_IN,
- PTR4_FN, PTR4_OUT, PTR4_IN_PU, PTR4_IN,
- PTR3_FN, PTR3_OUT, PTR3_IN_PU, PTR3_IN,
- PTR2_FN, PTR2_OUT, PTR2_IN_PU, PTR2_IN,
- PTR1_FN, PTR1_OUT, PTR1_IN_PU, PTR1_IN,
- PTR0_FN, PTR0_OUT, PTR0_IN_PU, PTR0_IN }
- },
- { PINMUX_CFG_REG("PSCR", 0xa405011c, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTS4_FN, PTS4_OUT, PTS4_IN_PU, PTS4_IN,
- PTS3_FN, PTS3_OUT, PTS3_IN_PU, PTS3_IN,
- PTS2_FN, PTS2_OUT, PTS2_IN_PU, PTS2_IN,
- PTS1_FN, PTS1_OUT, PTS1_IN_PU, PTS1_IN,
- PTS0_FN, PTS0_OUT, PTS0_IN_PU, PTS0_IN }
- },
- { PINMUX_CFG_REG("PTCR", 0xa405011e, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTT4_FN, PTT4_OUT, PTT4_IN_PU, PTT4_IN,
- PTT3_FN, PTT3_OUT, PTT3_IN_PU, PTT3_IN,
- PTT2_FN, PTT2_OUT, PTT2_IN_PU, PTT2_IN,
- PTT1_FN, PTT1_OUT, PTT1_IN_PU, PTT1_IN,
- PTT0_FN, PTT0_OUT, PTT0_IN_PU, PTT0_IN }
- },
- { PINMUX_CFG_REG("PUCR", 0xa4050120, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTU4_FN, PTU4_OUT, PTU4_IN_PU, PTU4_IN,
- PTU3_FN, PTU3_OUT, PTU3_IN_PU, PTU3_IN,
- PTU2_FN, PTU2_OUT, PTU2_IN_PU, PTU2_IN,
- PTU1_FN, PTU1_OUT, PTU1_IN_PU, PTU1_IN,
- PTU0_FN, PTU0_OUT, PTU0_IN_PU, PTU0_IN }
- },
- { PINMUX_CFG_REG("PVCR", 0xa4050122, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTV4_FN, PTV4_OUT, PTV4_IN_PU, PTV4_IN,
- PTV3_FN, PTV3_OUT, PTV3_IN_PU, PTV3_IN,
- PTV2_FN, PTV2_OUT, PTV2_IN_PU, PTV2_IN,
- PTV1_FN, PTV1_OUT, PTV1_IN_PU, PTV1_IN,
- PTV0_FN, PTV0_OUT, PTV0_IN_PU, PTV0_IN }
- },
- {}
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PADR", 0xa4050140, 8) {
- PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
- PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
- },
- { PINMUX_DATA_REG("PBDR", 0xa4050142, 8) {
- PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
- PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
- },
- { PINMUX_DATA_REG("PCDR", 0xa4050144, 8) {
- PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
- PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA }
- },
- { PINMUX_DATA_REG("PDDR", 0xa4050126, 8) {
- PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
- PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
- },
- { PINMUX_DATA_REG("PEDR", 0xa4050148, 8) {
- 0, PTE6_DATA, PTE5_DATA, PTE4_DATA,
- PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA }
- },
- { PINMUX_DATA_REG("PFDR", 0xa405014a, 8) {
- 0, PTF6_DATA, PTF5_DATA, PTF4_DATA,
- PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
- },
- { PINMUX_DATA_REG("PGDR", 0xa405014c, 8) {
- 0, PTG6_DATA, PTG5_DATA, PTG4_DATA,
- PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
- },
- { PINMUX_DATA_REG("PHDR", 0xa405014e, 8) {
- 0, PTH6_DATA, PTH5_DATA, PTH4_DATA,
- PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
- },
- { PINMUX_DATA_REG("PJDR", 0xa4050150, 8) {
- 0, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
- PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
- },
- { PINMUX_DATA_REG("PKDR", 0xa4050152, 8) {
- 0, 0, 0, 0,
- PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
- },
- { PINMUX_DATA_REG("PLDR", 0xa4050154, 8) {
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
- PTL3_DATA, 0, 0, 0 }
- },
- { PINMUX_DATA_REG("PMDR", 0xa4050156, 8) {
- PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
- PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
- },
- { PINMUX_DATA_REG("PPDR", 0xa4050158, 8) {
- 0, 0, 0, PTP4_DATA,
- PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA }
- },
- { PINMUX_DATA_REG("PRDR", 0xa405015a, 8) {
- PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
- PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
- },
- { PINMUX_DATA_REG("PSDR", 0xa405015c, 8) {
- 0, 0, 0, PTS4_DATA,
- PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
- },
- { PINMUX_DATA_REG("PTDR", 0xa405015e, 8) {
- 0, 0, 0, PTT4_DATA,
- PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
- },
- { PINMUX_DATA_REG("PUDR", 0xa4050160, 8) {
- 0, 0, 0, PTU4_DATA,
- PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
- },
- { PINMUX_DATA_REG("PVDR", 0xa4050162, 8) {
- 0, 0, 0, PTV4_DATA,
- PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
- },
- { },
-};
-
-static struct pinmux_info sh7720_pinmux_info = {
- .name = "sh7720_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
- .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_PTA7,
- .last_gpio = GPIO_FN_STATUS1,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
+#include <cpu/pfc.h>
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7720_pinmux_info);
+ return sh_pfc_register("pfc-sh7720", NULL, 0);
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7722.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7722.c
index 0688a7502f86..d9bcc4290997 100644
--- a/arch/sh/kernel/cpu/sh4a/pinmux-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7722.c
@@ -1,1784 +1,10 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/sh7722.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
- PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
- PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
- PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
- PTC7_DATA, PTC5_DATA, PTC4_DATA, PTC3_DATA, PTC2_DATA, PTC0_DATA,
- PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
- PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
- PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA, PTE1_DATA, PTE0_DATA,
- PTF6_DATA, PTF5_DATA, PTF4_DATA,
- PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
- PTG4_DATA, PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
- PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
- PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
- PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, PTJ1_DATA, PTJ0_DATA,
- PTK6_DATA, PTK5_DATA, PTK4_DATA,
- PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
- PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
- PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
- PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
- PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
- PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
- PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
- PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
- PTR4_DATA, PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
- PTS4_DATA, PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
- PTT4_DATA, PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
- PTU4_DATA, PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
- PTV4_DATA, PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
- PTW6_DATA, PTW5_DATA, PTW4_DATA,
- PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA,
- PTX6_DATA, PTX5_DATA, PTX4_DATA,
- PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA,
- PTY6_DATA, PTY5_DATA, PTY4_DATA,
- PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA,
- PTZ5_DATA, PTZ4_DATA, PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
- PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
- PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
- PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
- PTC7_IN, PTC5_IN, PTC4_IN, PTC3_IN, PTC2_IN, PTC0_IN,
- PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN, PTD3_IN, PTD2_IN, PTD1_IN,
- PTE7_IN, PTE6_IN, PTE5_IN, PTE4_IN, PTE1_IN, PTE0_IN,
- PTF6_IN, PTF5_IN, PTF4_IN, PTF3_IN, PTF2_IN, PTF1_IN,
- PTH6_IN, PTH5_IN, PTH1_IN, PTH0_IN,
- PTJ1_IN, PTJ0_IN,
- PTK6_IN, PTK5_IN, PTK4_IN, PTK3_IN, PTK2_IN, PTK0_IN,
- PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
- PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
- PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
- PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
- PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
- PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
- PTQ5_IN, PTQ4_IN, PTQ3_IN, PTQ2_IN, PTQ0_IN,
- PTR2_IN,
- PTS4_IN, PTS2_IN, PTS1_IN,
- PTT4_IN, PTT3_IN, PTT2_IN, PTT1_IN,
- PTU4_IN, PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
- PTV4_IN, PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
- PTW6_IN, PTW4_IN, PTW3_IN, PTW2_IN, PTW1_IN, PTW0_IN,
- PTX6_IN, PTX5_IN, PTX4_IN, PTX3_IN, PTX2_IN, PTX1_IN, PTX0_IN,
- PTY5_IN, PTY4_IN, PTY3_IN, PTY2_IN, PTY0_IN,
- PTZ5_IN, PTZ4_IN, PTZ3_IN, PTZ2_IN, PTZ1_IN,
- PINMUX_INPUT_END,
-
- PINMUX_INPUT_PULLDOWN_BEGIN,
- PTA7_IN_PD, PTA6_IN_PD, PTA5_IN_PD, PTA4_IN_PD,
- PTA3_IN_PD, PTA2_IN_PD, PTA1_IN_PD, PTA0_IN_PD,
- PTE7_IN_PD, PTE6_IN_PD, PTE5_IN_PD, PTE4_IN_PD, PTE1_IN_PD, PTE0_IN_PD,
- PTF6_IN_PD, PTF5_IN_PD, PTF4_IN_PD, PTF3_IN_PD, PTF2_IN_PD, PTF1_IN_PD,
- PTH6_IN_PD, PTH5_IN_PD, PTH1_IN_PD, PTH0_IN_PD,
- PTK6_IN_PD, PTK5_IN_PD, PTK4_IN_PD, PTK3_IN_PD, PTK2_IN_PD, PTK0_IN_PD,
- PTL7_IN_PD, PTL6_IN_PD, PTL5_IN_PD, PTL4_IN_PD,
- PTL3_IN_PD, PTL2_IN_PD, PTL1_IN_PD, PTL0_IN_PD,
- PTM7_IN_PD, PTM6_IN_PD, PTM5_IN_PD, PTM4_IN_PD,
- PTM3_IN_PD, PTM2_IN_PD, PTM1_IN_PD, PTM0_IN_PD,
- PTQ5_IN_PD, PTQ4_IN_PD, PTQ3_IN_PD, PTQ2_IN_PD,
- PTS4_IN_PD, PTS2_IN_PD, PTS1_IN_PD,
- PTT4_IN_PD, PTT3_IN_PD, PTT2_IN_PD, PTT1_IN_PD,
- PTU4_IN_PD, PTU3_IN_PD, PTU2_IN_PD, PTU1_IN_PD, PTU0_IN_PD,
- PTV4_IN_PD, PTV3_IN_PD, PTV2_IN_PD, PTV1_IN_PD, PTV0_IN_PD,
- PTW6_IN_PD, PTW4_IN_PD, PTW3_IN_PD, PTW2_IN_PD, PTW1_IN_PD, PTW0_IN_PD,
- PTX6_IN_PD, PTX5_IN_PD, PTX4_IN_PD,
- PTX3_IN_PD, PTX2_IN_PD, PTX1_IN_PD, PTX0_IN_PD,
- PINMUX_INPUT_PULLDOWN_END,
-
- PINMUX_INPUT_PULLUP_BEGIN,
- PTC7_IN_PU, PTC5_IN_PU,
- PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
- PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU,
- PTJ1_IN_PU, PTJ0_IN_PU,
- PTQ0_IN_PU,
- PTR2_IN_PU,
- PTX6_IN_PU,
- PTY5_IN_PU, PTY4_IN_PU, PTY3_IN_PU, PTY2_IN_PU, PTY0_IN_PU,
- PTZ5_IN_PU, PTZ4_IN_PU, PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU,
- PINMUX_INPUT_PULLUP_END,
-
- PINMUX_OUTPUT_BEGIN,
- PTA7_OUT, PTA5_OUT,
- PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
- PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
- PTC4_OUT, PTC3_OUT, PTC2_OUT, PTC0_OUT,
- PTD6_OUT, PTD5_OUT, PTD4_OUT,
- PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
- PTE7_OUT, PTE6_OUT, PTE5_OUT, PTE4_OUT, PTE1_OUT, PTE0_OUT,
- PTF6_OUT, PTF5_OUT, PTF4_OUT, PTF3_OUT, PTF2_OUT, PTF0_OUT,
- PTG4_OUT, PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
- PTH7_OUT, PTH6_OUT, PTH5_OUT, PTH4_OUT,
- PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
- PTJ7_OUT, PTJ6_OUT, PTJ5_OUT, PTJ1_OUT, PTJ0_OUT,
- PTK6_OUT, PTK5_OUT, PTK4_OUT, PTK3_OUT, PTK1_OUT, PTK0_OUT,
- PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
- PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
- PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
- PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
- PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
- PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT, PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
- PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
- PTR4_OUT, PTR3_OUT, PTR1_OUT, PTR0_OUT,
- PTS3_OUT, PTS2_OUT, PTS0_OUT,
- PTT4_OUT, PTT3_OUT, PTT2_OUT, PTT0_OUT,
- PTU4_OUT, PTU3_OUT, PTU2_OUT, PTU0_OUT,
- PTV4_OUT, PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
- PTW5_OUT, PTW4_OUT, PTW3_OUT, PTW2_OUT, PTW1_OUT, PTW0_OUT,
- PTX6_OUT, PTX5_OUT, PTX4_OUT, PTX3_OUT, PTX2_OUT, PTX1_OUT, PTX0_OUT,
- PTY5_OUT, PTY4_OUT, PTY3_OUT, PTY2_OUT, PTY1_OUT, PTY0_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_MARK_BEGIN,
- SCIF0_TXD_MARK, SCIF0_RXD_MARK,
- SCIF0_RTS_MARK, SCIF0_CTS_MARK, SCIF0_SCK_MARK,
- SCIF1_TXD_MARK, SCIF1_RXD_MARK,
- SCIF1_RTS_MARK, SCIF1_CTS_MARK, SCIF1_SCK_MARK,
- SCIF2_TXD_MARK, SCIF2_RXD_MARK,
- SCIF2_RTS_MARK, SCIF2_CTS_MARK, SCIF2_SCK_MARK,
- SIOTXD_MARK, SIORXD_MARK,
- SIOD_MARK, SIOSTRB0_MARK, SIOSTRB1_MARK,
- SIOSCK_MARK, SIOMCK_MARK,
- VIO_D15_MARK, VIO_D14_MARK, VIO_D13_MARK, VIO_D12_MARK,
- VIO_D11_MARK, VIO_D10_MARK, VIO_D9_MARK, VIO_D8_MARK,
- VIO_D7_MARK, VIO_D6_MARK, VIO_D5_MARK, VIO_D4_MARK,
- VIO_D3_MARK, VIO_D2_MARK, VIO_D1_MARK, VIO_D0_MARK,
- VIO_CLK_MARK, VIO_VD_MARK, VIO_HD_MARK, VIO_FLD_MARK,
- VIO_CKO_MARK, VIO_STEX_MARK, VIO_STEM_MARK, VIO_VD2_MARK,
- VIO_HD2_MARK, VIO_CLK2_MARK,
- LCDD23_MARK, LCDD22_MARK, LCDD21_MARK, LCDD20_MARK,
- LCDD19_MARK, LCDD18_MARK, LCDD17_MARK, LCDD16_MARK,
- LCDD15_MARK, LCDD14_MARK, LCDD13_MARK, LCDD12_MARK,
- LCDD11_MARK, LCDD10_MARK, LCDD9_MARK, LCDD8_MARK,
- LCDD7_MARK, LCDD6_MARK, LCDD5_MARK, LCDD4_MARK,
- LCDD3_MARK, LCDD2_MARK, LCDD1_MARK, LCDD0_MARK,
- LCDLCLK_MARK, LCDDON_MARK, LCDVCPWC_MARK, LCDVEPWC_MARK,
- LCDVSYN_MARK, LCDDCK_MARK, LCDHSYN_MARK, LCDDISP_MARK,
- LCDRS_MARK, LCDCS_MARK, LCDWR_MARK, LCDRD_MARK,
- LCDDON2_MARK, LCDVCPWC2_MARK, LCDVEPWC2_MARK, LCDVSYN2_MARK,
- LCDCS2_MARK,
- IOIS16_MARK, A25_MARK, A24_MARK, A23_MARK, A22_MARK,
- BS_MARK, CS6B_CE1B_MARK, WAIT_MARK, CS6A_CE2B_MARK,
- HPD63_MARK, HPD62_MARK, HPD61_MARK, HPD60_MARK,
- HPD59_MARK, HPD58_MARK, HPD57_MARK, HPD56_MARK,
- HPD55_MARK, HPD54_MARK, HPD53_MARK, HPD52_MARK,
- HPD51_MARK, HPD50_MARK, HPD49_MARK, HPD48_MARK,
- HPDQM7_MARK, HPDQM6_MARK, HPDQM5_MARK, HPDQM4_MARK,
- IRQ0_MARK, IRQ1_MARK, IRQ2_MARK, IRQ3_MARK,
- IRQ4_MARK, IRQ5_MARK, IRQ6_MARK, IRQ7_MARK,
- SDHICD_MARK, SDHIWP_MARK, SDHID3_MARK, SDHID2_MARK,
- SDHID1_MARK, SDHID0_MARK, SDHICMD_MARK, SDHICLK_MARK,
- SIUAOLR_MARK, SIUAOBT_MARK, SIUAISLD_MARK, SIUAILR_MARK,
- SIUAIBT_MARK, SIUAOSLD_MARK, SIUMCKA_MARK, SIUFCKA_MARK,
- SIUBOLR_MARK, SIUBOBT_MARK, SIUBISLD_MARK, SIUBILR_MARK,
- SIUBIBT_MARK, SIUBOSLD_MARK, SIUMCKB_MARK, SIUFCKB_MARK,
- AUDSYNC_MARK, AUDATA3_MARK, AUDATA2_MARK, AUDATA1_MARK, AUDATA0_MARK,
- DACK_MARK, DREQ0_MARK,
- DV_CLKI_MARK, DV_CLK_MARK, DV_HSYNC_MARK, DV_VSYNC_MARK,
- DV_D15_MARK, DV_D14_MARK, DV_D13_MARK, DV_D12_MARK,
- DV_D11_MARK, DV_D10_MARK, DV_D9_MARK, DV_D8_MARK,
- DV_D7_MARK, DV_D6_MARK, DV_D5_MARK, DV_D4_MARK,
- DV_D3_MARK, DV_D2_MARK, DV_D1_MARK, DV_D0_MARK,
- STATUS0_MARK, PDSTATUS_MARK,
- SIOF0_MCK_MARK, SIOF0_SCK_MARK,
- SIOF0_SYNC_MARK, SIOF0_SS1_MARK, SIOF0_SS2_MARK,
- SIOF0_TXD_MARK, SIOF0_RXD_MARK,
- SIOF1_MCK_MARK, SIOF1_SCK_MARK,
- SIOF1_SYNC_MARK, SIOF1_SS1_MARK, SIOF1_SS2_MARK,
- SIOF1_TXD_MARK, SIOF1_RXD_MARK,
- SIM_D_MARK, SIM_CLK_MARK, SIM_RST_MARK,
- TS_SDAT_MARK, TS_SCK_MARK, TS_SDEN_MARK, TS_SPSYNC_MARK,
- IRDA_IN_MARK, IRDA_OUT_MARK,
- TPUTO_MARK,
- FCE_MARK, NAF7_MARK, NAF6_MARK, NAF5_MARK, NAF4_MARK,
- NAF3_MARK, NAF2_MARK, NAF1_MARK, NAF0_MARK, FCDE_MARK,
- FOE_MARK, FSC_MARK, FWE_MARK, FRB_MARK,
- KEYIN0_MARK, KEYIN1_MARK, KEYIN2_MARK, KEYIN3_MARK, KEYIN4_MARK,
- KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK,
- KEYOUT4_IN6_MARK, KEYOUT5_IN5_MARK,
- PINMUX_MARK_END,
-
- PINMUX_FUNCTION_BEGIN,
- VIO_D7_SCIF1_SCK, VIO_D6_SCIF1_RXD, VIO_D5_SCIF1_TXD, VIO_D4,
- VIO_D3, VIO_D2, VIO_D1, VIO_D0_LCDLCLK,
- HPD55, HPD54, HPD53, HPD52, HPD51, HPD50, HPD49, HPD48,
- IOIS16, HPDQM7, HPDQM6, HPDQM5, HPDQM4,
- SDHICD, SDHIWP, SDHID3, IRQ2_SDHID2, SDHID1, SDHID0, SDHICMD, SDHICLK,
- A25, A24, A23, A22, IRQ5, IRQ4_BS,
- PTF6, SIOSCK_SIUBOBT, SIOSTRB1_SIUBOLR,
- SIOSTRB0_SIUBIBT, SIOD_SIUBILR, SIORXD_SIUBISLD, SIOTXD_SIUBOSLD,
- AUDSYNC, AUDATA3, AUDATA2, AUDATA1, AUDATA0,
- LCDVCPWC_LCDVCPWC2, LCDVSYN2_DACK, LCDVSYN, LCDDISP_LCDRS,
- LCDHSYN_LCDCS, LCDDON_LCDDON2, LCDD17_DV_HSYNC, LCDD16_DV_VSYNC,
- STATUS0, PDSTATUS, IRQ1, IRQ0,
- SIUAILR_SIOF1_SS2, SIUAIBT_SIOF1_SS1, SIUAOLR_SIOF1_SYNC,
- SIUAOBT_SIOF1_SCK, SIUAISLD_SIOF1_RXD, SIUAOSLD_SIOF1_TXD, PTK0,
- LCDD15_DV_D15, LCDD14_DV_D14, LCDD13_DV_D13, LCDD12_DV_D12,
- LCDD11_DV_D11, LCDD10_DV_D10, LCDD9_DV_D9, LCDD8_DV_D8,
- LCDD7_DV_D7, LCDD6_DV_D6, LCDD5_DV_D5, LCDD4_DV_D4,
- LCDD3_DV_D3, LCDD2_DV_D2, LCDD1_DV_D1, LCDD0_DV_D0,
- HPD63, HPD62, HPD61, HPD60, HPD59, HPD58, HPD57, HPD56,
- SIOF0_SS2_SIM_RST, SIOF0_SS1_TS_SPSYNC, SIOF0_SYNC_TS_SDEN,
- SIOF0_SCK_TS_SCK, PTQ2, PTQ1, PTQ0,
- LCDRD, CS6B_CE1B_LCDCS2, WAIT, LCDDCK_LCDWR, LCDVEPWC_LCDVEPWC2,
- SCIF0_CTS_SIUAISPD, SCIF0_RTS_SIUAOSPD,
- SCIF0_SCK_TPUTO, SCIF0_RXD, SCIF0_TXD,
- FOE_VIO_VD2, FWE, FSC, DREQ0, FCDE,
- NAF2_VIO_D10, NAF1_VIO_D9, NAF0_VIO_D8,
- FRB_VIO_CLK2, FCE_VIO_HD2,
- NAF7_VIO_D15, NAF6_VIO_D14, NAF5_VIO_D13, NAF4_VIO_D12, NAF3_VIO_D11,
- VIO_FLD_SCIF2_CTS, VIO_CKO_SCIF2_RTS, VIO_STEX_SCIF2_SCK,
- VIO_STEM_SCIF2_TXD, VIO_HD_SCIF2_RXD,
- VIO_VD_SCIF1_CTS, VIO_CLK_SCIF1_RTS,
- CS6A_CE2B, LCDD23, LCDD22, LCDD21, LCDD20,
- LCDD19_DV_CLKI, LCDD18_DV_CLK,
- KEYOUT5_IN5, KEYOUT4_IN6, KEYOUT3, KEYOUT2, KEYOUT1, KEYOUT0,
- KEYIN4_IRQ7, KEYIN3, KEYIN2, KEYIN1, KEYIN0_IRQ6,
-
- PSA15_KEYIN0, PSA15_IRQ6, PSA14_KEYIN4, PSA14_IRQ7,
- PSA9_IRQ4, PSA9_BS, PSA4_IRQ2, PSA4_SDHID2,
- PSB15_SIOTXD, PSB15_SIUBOSLD, PSB14_SIORXD, PSB14_SIUBISLD,
- PSB13_SIOD, PSB13_SIUBILR, PSB12_SIOSTRB0, PSB12_SIUBIBT,
- PSB11_SIOSTRB1, PSB11_SIUBOLR, PSB10_SIOSCK, PSB10_SIUBOBT,
- PSB9_SIOMCK, PSB9_SIUMCKB, PSB8_SIOF0_MCK, PSB8_IRQ3,
- PSB7_SIOF0_TXD, PSB7_IRDA_OUT, PSB6_SIOF0_RXD, PSB6_IRDA_IN,
- PSB5_SIOF0_SCK, PSB5_TS_SCK, PSB4_SIOF0_SYNC, PSB4_TS_SDEN,
- PSB3_SIOF0_SS1, PSB3_TS_SPSYNC, PSB2_SIOF0_SS2, PSB2_SIM_RST,
- PSB1_SIUMCKA, PSB1_SIOF1_MCK, PSB0_SIUAOSLD, PSB0_SIOF1_TXD,
- PSC15_SIUAISLD, PSC15_SIOF1_RXD, PSC14_SIUAOBT, PSC14_SIOF1_SCK,
- PSC13_SIUAOLR, PSC13_SIOF1_SYNC, PSC12_SIUAIBT, PSC12_SIOF1_SS1,
- PSC11_SIUAILR, PSC11_SIOF1_SS2, PSC0_NAF, PSC0_VIO,
- PSD13_VIO, PSD13_SCIF2, PSD12_VIO, PSD12_SCIF1,
- PSD11_VIO, PSD11_SCIF1, PSD10_VIO_D0, PSD10_LCDLCLK,
- PSD9_SIOMCK_SIUMCKB, PSD9_SIUFCKB, PSD8_SCIF0_SCK, PSD8_TPUTO,
- PSD7_SCIF0_RTS, PSD7_SIUAOSPD, PSD6_SCIF0_CTS, PSD6_SIUAISPD,
- PSD5_CS6B_CE1B, PSD5_LCDCS2,
- PSD3_LCDVEPWC_LCDVCPWC, PSD3_LCDVEPWC2_LCDVCPWC2,
- PSD2_LCDDON, PSD2_LCDDON2, PSD0_LCDD19_LCDD0, PSD0_DV,
- PSE15_SIOF0_MCK_IRQ3, PSE15_SIM_D,
- PSE14_SIOF0_TXD_IRDA_OUT, PSE14_SIM_CLK,
- PSE13_SIOF0_RXD_IRDA_IN, PSE13_TS_SDAT, PSE12_LCDVSYN2, PSE12_DACK,
- PSE11_SIUMCKA_SIOF1_MCK, PSE11_SIUFCKA,
- PSE3_FLCTL, PSE3_VIO, PSE2_NAF2, PSE2_VIO_D10,
- PSE1_NAF1, PSE1_VIO_D9, PSE0_NAF0, PSE0_VIO_D8,
-
- HIZA14_KEYSC, HIZA14_HIZ,
- HIZA10_NAF, HIZA10_HIZ,
- HIZA9_VIO, HIZA9_HIZ,
- HIZA8_LCDC, HIZA8_HIZ,
- HIZA7_LCDC, HIZA7_HIZ,
- HIZA6_LCDC, HIZA6_HIZ,
- HIZB4_SIUA, HIZB4_HIZ,
- HIZB1_VIO, HIZB1_HIZ,
- HIZB0_VIO, HIZB0_HIZ,
- HIZC15_IRQ7, HIZC15_HIZ,
- HIZC14_IRQ6, HIZC14_HIZ,
- HIZC13_IRQ5, HIZC13_HIZ,
- HIZC12_IRQ4, HIZC12_HIZ,
- HIZC11_IRQ3, HIZC11_HIZ,
- HIZC10_IRQ2, HIZC10_HIZ,
- HIZC9_IRQ1, HIZC9_HIZ,
- HIZC8_IRQ0, HIZC8_HIZ,
- MSELB9_VIO, MSELB9_VIO2,
- MSELB8_RGB, MSELB8_SYS,
- PINMUX_FUNCTION_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
- /* PTA */
- PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_IN_PD, PTA7_OUT),
- PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_IN_PD),
- PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_IN_PD, PTA5_OUT),
- PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_IN_PD),
- PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_IN_PD),
- PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_IN_PD),
- PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_IN_PD),
- PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_IN_PD),
-
- /* PTB */
- PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT),
- PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT),
- PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT),
- PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT),
- PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT),
- PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT),
- PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT),
- PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT),
-
- /* PTC */
- PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_IN_PU),
- PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_IN_PU),
- PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT),
- PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT),
- PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT),
- PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT),
-
- /* PTD */
- PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_IN_PU),
- PINMUX_DATA(PTD6_DATA, PTD6_OUT, PTD6_IN, PTD6_IN_PU),
- PINMUX_DATA(PTD5_DATA, PTD5_OUT, PTD5_IN, PTD5_IN_PU),
- PINMUX_DATA(PTD4_DATA, PTD4_OUT, PTD4_IN, PTD4_IN_PU),
- PINMUX_DATA(PTD3_DATA, PTD3_OUT, PTD3_IN, PTD3_IN_PU),
- PINMUX_DATA(PTD2_DATA, PTD2_OUT, PTD2_IN, PTD2_IN_PU),
- PINMUX_DATA(PTD1_DATA, PTD1_OUT, PTD1_IN, PTD1_IN_PU),
- PINMUX_DATA(PTD0_DATA, PTD0_OUT),
-
- /* PTE */
- PINMUX_DATA(PTE7_DATA, PTE7_OUT, PTE7_IN, PTE7_IN_PD),
- PINMUX_DATA(PTE6_DATA, PTE6_OUT, PTE6_IN, PTE6_IN_PD),
- PINMUX_DATA(PTE5_DATA, PTE5_OUT, PTE5_IN, PTE5_IN_PD),
- PINMUX_DATA(PTE4_DATA, PTE4_OUT, PTE4_IN, PTE4_IN_PD),
- PINMUX_DATA(PTE1_DATA, PTE1_OUT, PTE1_IN, PTE1_IN_PD),
- PINMUX_DATA(PTE0_DATA, PTE0_OUT, PTE0_IN, PTE0_IN_PD),
-
- /* PTF */
- PINMUX_DATA(PTF6_DATA, PTF6_OUT, PTF6_IN, PTF6_IN_PD),
- PINMUX_DATA(PTF5_DATA, PTF5_OUT, PTF5_IN, PTF5_IN_PD),
- PINMUX_DATA(PTF4_DATA, PTF4_OUT, PTF4_IN, PTF4_IN_PD),
- PINMUX_DATA(PTF3_DATA, PTF3_OUT, PTF3_IN, PTF3_IN_PD),
- PINMUX_DATA(PTF2_DATA, PTF2_OUT, PTF2_IN, PTF2_IN_PD),
- PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_IN_PD),
- PINMUX_DATA(PTF0_DATA, PTF0_OUT),
-
- /* PTG */
- PINMUX_DATA(PTG4_DATA, PTG4_OUT),
- PINMUX_DATA(PTG3_DATA, PTG3_OUT),
- PINMUX_DATA(PTG2_DATA, PTG2_OUT),
- PINMUX_DATA(PTG1_DATA, PTG1_OUT),
- PINMUX_DATA(PTG0_DATA, PTG0_OUT),
-
- /* PTH */
- PINMUX_DATA(PTH7_DATA, PTH7_OUT),
- PINMUX_DATA(PTH6_DATA, PTH6_OUT, PTH6_IN, PTH6_IN_PD),
- PINMUX_DATA(PTH5_DATA, PTH5_OUT, PTH5_IN, PTH5_IN_PD),
- PINMUX_DATA(PTH4_DATA, PTH4_OUT),
- PINMUX_DATA(PTH3_DATA, PTH3_OUT),
- PINMUX_DATA(PTH2_DATA, PTH2_OUT),
- PINMUX_DATA(PTH1_DATA, PTH1_OUT, PTH1_IN, PTH1_IN_PD),
- PINMUX_DATA(PTH0_DATA, PTH0_OUT, PTH0_IN, PTH0_IN_PD),
-
- /* PTJ */
- PINMUX_DATA(PTJ7_DATA, PTJ7_OUT),
- PINMUX_DATA(PTJ6_DATA, PTJ6_OUT),
- PINMUX_DATA(PTJ5_DATA, PTJ5_OUT),
- PINMUX_DATA(PTJ1_DATA, PTJ1_OUT, PTJ1_IN, PTJ1_IN_PU),
- PINMUX_DATA(PTJ0_DATA, PTJ0_OUT, PTJ0_IN, PTJ0_IN_PU),
-
- /* PTK */
- PINMUX_DATA(PTK6_DATA, PTK6_OUT, PTK6_IN, PTK6_IN_PD),
- PINMUX_DATA(PTK5_DATA, PTK5_OUT, PTK5_IN, PTK5_IN_PD),
- PINMUX_DATA(PTK4_DATA, PTK4_OUT, PTK4_IN, PTK4_IN_PD),
- PINMUX_DATA(PTK3_DATA, PTK3_OUT, PTK3_IN, PTK3_IN_PD),
- PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_IN_PD),
- PINMUX_DATA(PTK1_DATA, PTK1_OUT),
- PINMUX_DATA(PTK0_DATA, PTK0_OUT, PTK0_IN, PTK0_IN_PD),
-
- /* PTL */
- PINMUX_DATA(PTL7_DATA, PTL7_OUT, PTL7_IN, PTL7_IN_PD),
- PINMUX_DATA(PTL6_DATA, PTL6_OUT, PTL6_IN, PTL6_IN_PD),
- PINMUX_DATA(PTL5_DATA, PTL5_OUT, PTL5_IN, PTL5_IN_PD),
- PINMUX_DATA(PTL4_DATA, PTL4_OUT, PTL4_IN, PTL4_IN_PD),
- PINMUX_DATA(PTL3_DATA, PTL3_OUT, PTL3_IN, PTL3_IN_PD),
- PINMUX_DATA(PTL2_DATA, PTL2_OUT, PTL2_IN, PTL2_IN_PD),
- PINMUX_DATA(PTL1_DATA, PTL1_OUT, PTL1_IN, PTL1_IN_PD),
- PINMUX_DATA(PTL0_DATA, PTL0_OUT, PTL0_IN, PTL0_IN_PD),
-
- /* PTM */
- PINMUX_DATA(PTM7_DATA, PTM7_OUT, PTM7_IN, PTM7_IN_PD),
- PINMUX_DATA(PTM6_DATA, PTM6_OUT, PTM6_IN, PTM6_IN_PD),
- PINMUX_DATA(PTM5_DATA, PTM5_OUT, PTM5_IN, PTM5_IN_PD),
- PINMUX_DATA(PTM4_DATA, PTM4_OUT, PTM4_IN, PTM4_IN_PD),
- PINMUX_DATA(PTM3_DATA, PTM3_OUT, PTM3_IN, PTM3_IN_PD),
- PINMUX_DATA(PTM2_DATA, PTM2_OUT, PTM2_IN, PTM2_IN_PD),
- PINMUX_DATA(PTM1_DATA, PTM1_OUT, PTM1_IN, PTM1_IN_PD),
- PINMUX_DATA(PTM0_DATA, PTM0_OUT, PTM0_IN, PTM0_IN_PD),
-
- /* PTN */
- PINMUX_DATA(PTN7_DATA, PTN7_OUT, PTN7_IN),
- PINMUX_DATA(PTN6_DATA, PTN6_OUT, PTN6_IN),
- PINMUX_DATA(PTN5_DATA, PTN5_OUT, PTN5_IN),
- PINMUX_DATA(PTN4_DATA, PTN4_OUT, PTN4_IN),
- PINMUX_DATA(PTN3_DATA, PTN3_OUT, PTN3_IN),
- PINMUX_DATA(PTN2_DATA, PTN2_OUT, PTN2_IN),
- PINMUX_DATA(PTN1_DATA, PTN1_OUT, PTN1_IN),
- PINMUX_DATA(PTN0_DATA, PTN0_OUT, PTN0_IN),
-
- /* PTQ */
- PINMUX_DATA(PTQ6_DATA, PTQ6_OUT),
- PINMUX_DATA(PTQ5_DATA, PTQ5_OUT, PTQ5_IN, PTQ5_IN_PD),
- PINMUX_DATA(PTQ4_DATA, PTQ4_OUT, PTQ4_IN, PTQ4_IN_PD),
- PINMUX_DATA(PTQ3_DATA, PTQ3_OUT, PTQ3_IN, PTQ3_IN_PD),
- PINMUX_DATA(PTQ2_DATA, PTQ2_IN, PTQ2_IN_PD),
- PINMUX_DATA(PTQ1_DATA, PTQ1_OUT),
- PINMUX_DATA(PTQ0_DATA, PTQ0_OUT, PTQ0_IN, PTQ0_IN_PU),
-
- /* PTR */
- PINMUX_DATA(PTR4_DATA, PTR4_OUT),
- PINMUX_DATA(PTR3_DATA, PTR3_OUT),
- PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_IN_PU),
- PINMUX_DATA(PTR1_DATA, PTR1_OUT),
- PINMUX_DATA(PTR0_DATA, PTR0_OUT),
-
- /* PTS */
- PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_IN_PD),
- PINMUX_DATA(PTS3_DATA, PTS3_OUT),
- PINMUX_DATA(PTS2_DATA, PTS2_OUT, PTS2_IN, PTS2_IN_PD),
- PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_IN_PD),
- PINMUX_DATA(PTS0_DATA, PTS0_OUT),
-
- /* PTT */
- PINMUX_DATA(PTT4_DATA, PTT4_OUT, PTT4_IN, PTT4_IN_PD),
- PINMUX_DATA(PTT3_DATA, PTT3_OUT, PTT3_IN, PTT3_IN_PD),
- PINMUX_DATA(PTT2_DATA, PTT2_OUT, PTT2_IN, PTT2_IN_PD),
- PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_IN_PD),
- PINMUX_DATA(PTT0_DATA, PTT0_OUT),
-
- /* PTU */
- PINMUX_DATA(PTU4_DATA, PTU4_OUT, PTU4_IN, PTU4_IN_PD),
- PINMUX_DATA(PTU3_DATA, PTU3_OUT, PTU3_IN, PTU3_IN_PD),
- PINMUX_DATA(PTU2_DATA, PTU2_OUT, PTU2_IN, PTU2_IN_PD),
- PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_IN_PD),
- PINMUX_DATA(PTU0_DATA, PTU0_OUT, PTU0_IN, PTU0_IN_PD),
-
- /* PTV */
- PINMUX_DATA(PTV4_DATA, PTV4_OUT, PTV4_IN, PTV4_IN_PD),
- PINMUX_DATA(PTV3_DATA, PTV3_OUT, PTV3_IN, PTV3_IN_PD),
- PINMUX_DATA(PTV2_DATA, PTV2_OUT, PTV2_IN, PTV2_IN_PD),
- PINMUX_DATA(PTV1_DATA, PTV1_OUT, PTV1_IN, PTV1_IN_PD),
- PINMUX_DATA(PTV0_DATA, PTV0_OUT, PTV0_IN, PTV0_IN_PD),
-
- /* PTW */
- PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_IN_PD),
- PINMUX_DATA(PTW5_DATA, PTW5_OUT),
- PINMUX_DATA(PTW4_DATA, PTW4_OUT, PTW4_IN, PTW4_IN_PD),
- PINMUX_DATA(PTW3_DATA, PTW3_OUT, PTW3_IN, PTW3_IN_PD),
- PINMUX_DATA(PTW2_DATA, PTW2_OUT, PTW2_IN, PTW2_IN_PD),
- PINMUX_DATA(PTW1_DATA, PTW1_OUT, PTW1_IN, PTW1_IN_PD),
- PINMUX_DATA(PTW0_DATA, PTW0_OUT, PTW0_IN, PTW0_IN_PD),
-
- /* PTX */
- PINMUX_DATA(PTX6_DATA, PTX6_OUT, PTX6_IN, PTX6_IN_PD),
- PINMUX_DATA(PTX5_DATA, PTX5_OUT, PTX5_IN, PTX5_IN_PD),
- PINMUX_DATA(PTX4_DATA, PTX4_OUT, PTX4_IN, PTX4_IN_PD),
- PINMUX_DATA(PTX3_DATA, PTX3_OUT, PTX3_IN, PTX3_IN_PD),
- PINMUX_DATA(PTX2_DATA, PTX2_OUT, PTX2_IN, PTX2_IN_PD),
- PINMUX_DATA(PTX1_DATA, PTX1_OUT, PTX1_IN, PTX1_IN_PD),
- PINMUX_DATA(PTX0_DATA, PTX0_OUT, PTX0_IN, PTX0_IN_PD),
-
- /* PTY */
- PINMUX_DATA(PTY5_DATA, PTY5_OUT, PTY5_IN, PTY5_IN_PU),
- PINMUX_DATA(PTY4_DATA, PTY4_OUT, PTY4_IN, PTY4_IN_PU),
- PINMUX_DATA(PTY3_DATA, PTY3_OUT, PTY3_IN, PTY3_IN_PU),
- PINMUX_DATA(PTY2_DATA, PTY2_OUT, PTY2_IN, PTY2_IN_PU),
- PINMUX_DATA(PTY1_DATA, PTY1_OUT),
- PINMUX_DATA(PTY0_DATA, PTY0_OUT, PTY0_IN, PTY0_IN_PU),
-
- /* PTZ */
- PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_IN_PU),
- PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_IN_PU),
- PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_IN_PU),
- PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_IN_PU),
- PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_IN_PU),
-
- /* SCIF0 */
- PINMUX_DATA(SCIF0_TXD_MARK, SCIF0_TXD),
- PINMUX_DATA(SCIF0_RXD_MARK, SCIF0_RXD),
- PINMUX_DATA(SCIF0_RTS_MARK, PSD7_SCIF0_RTS, SCIF0_RTS_SIUAOSPD),
- PINMUX_DATA(SCIF0_CTS_MARK, PSD6_SCIF0_CTS, SCIF0_CTS_SIUAISPD),
- PINMUX_DATA(SCIF0_SCK_MARK, PSD8_SCIF0_SCK, SCIF0_SCK_TPUTO),
-
- /* SCIF1 */
- PINMUX_DATA(SCIF1_TXD_MARK, PSD11_SCIF1, VIO_D5_SCIF1_TXD),
- PINMUX_DATA(SCIF1_RXD_MARK, PSD11_SCIF1, VIO_D6_SCIF1_RXD),
- PINMUX_DATA(SCIF1_RTS_MARK, PSD12_SCIF1, VIO_CLK_SCIF1_RTS),
- PINMUX_DATA(SCIF1_CTS_MARK, PSD12_SCIF1, VIO_VD_SCIF1_CTS),
- PINMUX_DATA(SCIF1_SCK_MARK, PSD11_SCIF1, VIO_D7_SCIF1_SCK),
-
- /* SCIF2 */
- PINMUX_DATA(SCIF2_TXD_MARK, PSD13_SCIF2, VIO_STEM_SCIF2_TXD),
- PINMUX_DATA(SCIF2_RXD_MARK, PSD13_SCIF2, VIO_HD_SCIF2_RXD),
- PINMUX_DATA(SCIF2_RTS_MARK, PSD13_SCIF2, VIO_CKO_SCIF2_RTS),
- PINMUX_DATA(SCIF2_CTS_MARK, PSD13_SCIF2, VIO_FLD_SCIF2_CTS),
- PINMUX_DATA(SCIF2_SCK_MARK, PSD13_SCIF2, VIO_STEX_SCIF2_SCK),
-
- /* SIO */
- PINMUX_DATA(SIOTXD_MARK, PSB15_SIOTXD, SIOTXD_SIUBOSLD),
- PINMUX_DATA(SIORXD_MARK, PSB14_SIORXD, SIORXD_SIUBISLD),
- PINMUX_DATA(SIOD_MARK, PSB13_SIOD, SIOD_SIUBILR),
- PINMUX_DATA(SIOSTRB0_MARK, PSB12_SIOSTRB0, SIOSTRB0_SIUBIBT),
- PINMUX_DATA(SIOSTRB1_MARK, PSB11_SIOSTRB1, SIOSTRB1_SIUBOLR),
- PINMUX_DATA(SIOSCK_MARK, PSB10_SIOSCK, SIOSCK_SIUBOBT),
- PINMUX_DATA(SIOMCK_MARK, PSD9_SIOMCK_SIUMCKB, PSB9_SIOMCK, PTF6),
-
- /* CEU */
- PINMUX_DATA(VIO_D15_MARK, PSC0_VIO, HIZA10_NAF, NAF7_VIO_D15),
- PINMUX_DATA(VIO_D14_MARK, PSC0_VIO, HIZA10_NAF, NAF6_VIO_D14),
- PINMUX_DATA(VIO_D13_MARK, PSC0_VIO, HIZA10_NAF, NAF5_VIO_D13),
- PINMUX_DATA(VIO_D12_MARK, PSC0_VIO, HIZA10_NAF, NAF4_VIO_D12),
- PINMUX_DATA(VIO_D11_MARK, PSC0_VIO, HIZA10_NAF, NAF3_VIO_D11),
- PINMUX_DATA(VIO_D10_MARK, PSE2_VIO_D10, HIZB0_VIO, NAF2_VIO_D10),
- PINMUX_DATA(VIO_D9_MARK, PSE1_VIO_D9, HIZB0_VIO, NAF1_VIO_D9),
- PINMUX_DATA(VIO_D8_MARK, PSE0_VIO_D8, HIZB0_VIO, NAF0_VIO_D8),
- PINMUX_DATA(VIO_D7_MARK, PSD11_VIO, VIO_D7_SCIF1_SCK),
- PINMUX_DATA(VIO_D6_MARK, PSD11_VIO, VIO_D6_SCIF1_RXD),
- PINMUX_DATA(VIO_D5_MARK, PSD11_VIO, VIO_D5_SCIF1_TXD),
- PINMUX_DATA(VIO_D4_MARK, VIO_D4),
- PINMUX_DATA(VIO_D3_MARK, VIO_D3),
- PINMUX_DATA(VIO_D2_MARK, VIO_D2),
- PINMUX_DATA(VIO_D1_MARK, VIO_D1),
- PINMUX_DATA(VIO_D0_MARK, PSD10_VIO_D0, VIO_D0_LCDLCLK),
- PINMUX_DATA(VIO_CLK_MARK, PSD12_VIO, MSELB9_VIO, VIO_CLK_SCIF1_RTS),
- PINMUX_DATA(VIO_VD_MARK, PSD12_VIO, MSELB9_VIO, VIO_VD_SCIF1_CTS),
- PINMUX_DATA(VIO_HD_MARK, PSD13_VIO, MSELB9_VIO, VIO_HD_SCIF2_RXD),
- PINMUX_DATA(VIO_FLD_MARK, PSD13_VIO, HIZA9_VIO, VIO_FLD_SCIF2_CTS),
- PINMUX_DATA(VIO_CKO_MARK, PSD13_VIO, HIZA9_VIO, VIO_CKO_SCIF2_RTS),
- PINMUX_DATA(VIO_STEX_MARK, PSD13_VIO, HIZA9_VIO, VIO_STEX_SCIF2_SCK),
- PINMUX_DATA(VIO_STEM_MARK, PSD13_VIO, HIZA9_VIO, VIO_STEM_SCIF2_TXD),
- PINMUX_DATA(VIO_VD2_MARK, PSE3_VIO, MSELB9_VIO2,
- HIZB0_VIO, FOE_VIO_VD2),
- PINMUX_DATA(VIO_HD2_MARK, PSE3_VIO, MSELB9_VIO2,
- HIZB1_VIO, FCE_VIO_HD2),
- PINMUX_DATA(VIO_CLK2_MARK, PSE3_VIO, MSELB9_VIO2,
- HIZB1_VIO, FRB_VIO_CLK2),
-
- /* LCDC */
- PINMUX_DATA(LCDD23_MARK, HIZA8_LCDC, LCDD23),
- PINMUX_DATA(LCDD22_MARK, HIZA8_LCDC, LCDD22),
- PINMUX_DATA(LCDD21_MARK, HIZA8_LCDC, LCDD21),
- PINMUX_DATA(LCDD20_MARK, HIZA8_LCDC, LCDD20),
- PINMUX_DATA(LCDD19_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD19_DV_CLKI),
- PINMUX_DATA(LCDD18_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD18_DV_CLK),
- PINMUX_DATA(LCDD17_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC,
- LCDD17_DV_HSYNC),
- PINMUX_DATA(LCDD16_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC,
- LCDD16_DV_VSYNC),
- PINMUX_DATA(LCDD15_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD15_DV_D15),
- PINMUX_DATA(LCDD14_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD14_DV_D14),
- PINMUX_DATA(LCDD13_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD13_DV_D13),
- PINMUX_DATA(LCDD12_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD12_DV_D12),
- PINMUX_DATA(LCDD11_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD11_DV_D11),
- PINMUX_DATA(LCDD10_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD10_DV_D10),
- PINMUX_DATA(LCDD9_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD9_DV_D9),
- PINMUX_DATA(LCDD8_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD8_DV_D8),
- PINMUX_DATA(LCDD7_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD7_DV_D7),
- PINMUX_DATA(LCDD6_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD6_DV_D6),
- PINMUX_DATA(LCDD5_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD5_DV_D5),
- PINMUX_DATA(LCDD4_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD4_DV_D4),
- PINMUX_DATA(LCDD3_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD3_DV_D3),
- PINMUX_DATA(LCDD2_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD2_DV_D2),
- PINMUX_DATA(LCDD1_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD1_DV_D1),
- PINMUX_DATA(LCDD0_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD0_DV_D0),
- PINMUX_DATA(LCDLCLK_MARK, PSD10_LCDLCLK, VIO_D0_LCDLCLK),
- /* Main LCD */
- PINMUX_DATA(LCDDON_MARK, PSD2_LCDDON, HIZA7_LCDC, LCDDON_LCDDON2),
- PINMUX_DATA(LCDVCPWC_MARK, PSD3_LCDVEPWC_LCDVCPWC,
- HIZA6_LCDC, LCDVCPWC_LCDVCPWC2),
- PINMUX_DATA(LCDVEPWC_MARK, PSD3_LCDVEPWC_LCDVCPWC,
- HIZA6_LCDC, LCDVEPWC_LCDVEPWC2),
- PINMUX_DATA(LCDVSYN_MARK, HIZA7_LCDC, LCDVSYN),
- /* Main LCD - RGB Mode */
- PINMUX_DATA(LCDDCK_MARK, MSELB8_RGB, HIZA8_LCDC, LCDDCK_LCDWR),
- PINMUX_DATA(LCDHSYN_MARK, MSELB8_RGB, HIZA7_LCDC, LCDHSYN_LCDCS),
- PINMUX_DATA(LCDDISP_MARK, MSELB8_RGB, HIZA7_LCDC, LCDDISP_LCDRS),
- /* Main LCD - SYS Mode */
- PINMUX_DATA(LCDRS_MARK, MSELB8_SYS, HIZA7_LCDC, LCDDISP_LCDRS),
- PINMUX_DATA(LCDCS_MARK, MSELB8_SYS, HIZA7_LCDC, LCDHSYN_LCDCS),
- PINMUX_DATA(LCDWR_MARK, MSELB8_SYS, HIZA8_LCDC, LCDDCK_LCDWR),
- PINMUX_DATA(LCDRD_MARK, HIZA7_LCDC, LCDRD),
- /* Sub LCD - SYS Mode */
- PINMUX_DATA(LCDDON2_MARK, PSD2_LCDDON2, HIZA7_LCDC, LCDDON_LCDDON2),
- PINMUX_DATA(LCDVCPWC2_MARK, PSD3_LCDVEPWC2_LCDVCPWC2,
- HIZA6_LCDC, LCDVCPWC_LCDVCPWC2),
- PINMUX_DATA(LCDVEPWC2_MARK, PSD3_LCDVEPWC2_LCDVCPWC2,
- HIZA6_LCDC, LCDVEPWC_LCDVEPWC2),
- PINMUX_DATA(LCDVSYN2_MARK, PSE12_LCDVSYN2, HIZA8_LCDC, LCDVSYN2_DACK),
- PINMUX_DATA(LCDCS2_MARK, PSD5_LCDCS2, CS6B_CE1B_LCDCS2),
-
- /* BSC */
- PINMUX_DATA(IOIS16_MARK, IOIS16),
- PINMUX_DATA(A25_MARK, A25),
- PINMUX_DATA(A24_MARK, A24),
- PINMUX_DATA(A23_MARK, A23),
- PINMUX_DATA(A22_MARK, A22),
- PINMUX_DATA(BS_MARK, PSA9_BS, IRQ4_BS),
- PINMUX_DATA(CS6B_CE1B_MARK, PSD5_CS6B_CE1B, CS6B_CE1B_LCDCS2),
- PINMUX_DATA(WAIT_MARK, WAIT),
- PINMUX_DATA(CS6A_CE2B_MARK, CS6A_CE2B),
-
- /* SBSC */
- PINMUX_DATA(HPD63_MARK, HPD63),
- PINMUX_DATA(HPD62_MARK, HPD62),
- PINMUX_DATA(HPD61_MARK, HPD61),
- PINMUX_DATA(HPD60_MARK, HPD60),
- PINMUX_DATA(HPD59_MARK, HPD59),
- PINMUX_DATA(HPD58_MARK, HPD58),
- PINMUX_DATA(HPD57_MARK, HPD57),
- PINMUX_DATA(HPD56_MARK, HPD56),
- PINMUX_DATA(HPD55_MARK, HPD55),
- PINMUX_DATA(HPD54_MARK, HPD54),
- PINMUX_DATA(HPD53_MARK, HPD53),
- PINMUX_DATA(HPD52_MARK, HPD52),
- PINMUX_DATA(HPD51_MARK, HPD51),
- PINMUX_DATA(HPD50_MARK, HPD50),
- PINMUX_DATA(HPD49_MARK, HPD49),
- PINMUX_DATA(HPD48_MARK, HPD48),
- PINMUX_DATA(HPDQM7_MARK, HPDQM7),
- PINMUX_DATA(HPDQM6_MARK, HPDQM6),
- PINMUX_DATA(HPDQM5_MARK, HPDQM5),
- PINMUX_DATA(HPDQM4_MARK, HPDQM4),
-
- /* IRQ */
- PINMUX_DATA(IRQ0_MARK, HIZC8_IRQ0, IRQ0),
- PINMUX_DATA(IRQ1_MARK, HIZC9_IRQ1, IRQ1),
- PINMUX_DATA(IRQ2_MARK, PSA4_IRQ2, HIZC10_IRQ2, IRQ2_SDHID2),
- PINMUX_DATA(IRQ3_MARK, PSE15_SIOF0_MCK_IRQ3, PSB8_IRQ3,
- HIZC11_IRQ3, PTQ0),
- PINMUX_DATA(IRQ4_MARK, PSA9_IRQ4, HIZC12_IRQ4, IRQ4_BS),
- PINMUX_DATA(IRQ5_MARK, HIZC13_IRQ5, IRQ5),
- PINMUX_DATA(IRQ6_MARK, PSA15_IRQ6, HIZC14_IRQ6, KEYIN0_IRQ6),
- PINMUX_DATA(IRQ7_MARK, PSA14_IRQ7, HIZC15_IRQ7, KEYIN4_IRQ7),
-
- /* SDHI */
- PINMUX_DATA(SDHICD_MARK, SDHICD),
- PINMUX_DATA(SDHIWP_MARK, SDHIWP),
- PINMUX_DATA(SDHID3_MARK, SDHID3),
- PINMUX_DATA(SDHID2_MARK, PSA4_SDHID2, IRQ2_SDHID2),
- PINMUX_DATA(SDHID1_MARK, SDHID1),
- PINMUX_DATA(SDHID0_MARK, SDHID0),
- PINMUX_DATA(SDHICMD_MARK, SDHICMD),
- PINMUX_DATA(SDHICLK_MARK, SDHICLK),
-
- /* SIU - Port A */
- PINMUX_DATA(SIUAOLR_MARK, PSC13_SIUAOLR, HIZB4_SIUA, SIUAOLR_SIOF1_SYNC),
- PINMUX_DATA(SIUAOBT_MARK, PSC14_SIUAOBT, HIZB4_SIUA, SIUAOBT_SIOF1_SCK),
- PINMUX_DATA(SIUAISLD_MARK, PSC15_SIUAISLD, HIZB4_SIUA, SIUAISLD_SIOF1_RXD),
- PINMUX_DATA(SIUAILR_MARK, PSC11_SIUAILR, HIZB4_SIUA, SIUAILR_SIOF1_SS2),
- PINMUX_DATA(SIUAIBT_MARK, PSC12_SIUAIBT, HIZB4_SIUA, SIUAIBT_SIOF1_SS1),
- PINMUX_DATA(SIUAOSLD_MARK, PSB0_SIUAOSLD, HIZB4_SIUA, SIUAOSLD_SIOF1_TXD),
- PINMUX_DATA(SIUMCKA_MARK, PSE11_SIUMCKA_SIOF1_MCK, HIZB4_SIUA, PSB1_SIUMCKA, PTK0),
- PINMUX_DATA(SIUFCKA_MARK, PSE11_SIUFCKA, HIZB4_SIUA, PTK0),
-
- /* SIU - Port B */
- PINMUX_DATA(SIUBOLR_MARK, PSB11_SIUBOLR, SIOSTRB1_SIUBOLR),
- PINMUX_DATA(SIUBOBT_MARK, PSB10_SIUBOBT, SIOSCK_SIUBOBT),
- PINMUX_DATA(SIUBISLD_MARK, PSB14_SIUBISLD, SIORXD_SIUBISLD),
- PINMUX_DATA(SIUBILR_MARK, PSB13_SIUBILR, SIOD_SIUBILR),
- PINMUX_DATA(SIUBIBT_MARK, PSB12_SIUBIBT, SIOSTRB0_SIUBIBT),
- PINMUX_DATA(SIUBOSLD_MARK, PSB15_SIUBOSLD, SIOTXD_SIUBOSLD),
- PINMUX_DATA(SIUMCKB_MARK, PSD9_SIOMCK_SIUMCKB, PSB9_SIUMCKB, PTF6),
- PINMUX_DATA(SIUFCKB_MARK, PSD9_SIUFCKB, PTF6),
-
- /* AUD */
- PINMUX_DATA(AUDSYNC_MARK, AUDSYNC),
- PINMUX_DATA(AUDATA3_MARK, AUDATA3),
- PINMUX_DATA(AUDATA2_MARK, AUDATA2),
- PINMUX_DATA(AUDATA1_MARK, AUDATA1),
- PINMUX_DATA(AUDATA0_MARK, AUDATA0),
-
- /* DMAC */
- PINMUX_DATA(DACK_MARK, PSE12_DACK, LCDVSYN2_DACK),
- PINMUX_DATA(DREQ0_MARK, DREQ0),
-
- /* VOU */
- PINMUX_DATA(DV_CLKI_MARK, PSD0_DV, LCDD19_DV_CLKI),
- PINMUX_DATA(DV_CLK_MARK, PSD0_DV, LCDD18_DV_CLK),
- PINMUX_DATA(DV_HSYNC_MARK, PSD0_DV, LCDD17_DV_HSYNC),
- PINMUX_DATA(DV_VSYNC_MARK, PSD0_DV, LCDD16_DV_VSYNC),
- PINMUX_DATA(DV_D15_MARK, PSD0_DV, LCDD15_DV_D15),
- PINMUX_DATA(DV_D14_MARK, PSD0_DV, LCDD14_DV_D14),
- PINMUX_DATA(DV_D13_MARK, PSD0_DV, LCDD13_DV_D13),
- PINMUX_DATA(DV_D12_MARK, PSD0_DV, LCDD12_DV_D12),
- PINMUX_DATA(DV_D11_MARK, PSD0_DV, LCDD11_DV_D11),
- PINMUX_DATA(DV_D10_MARK, PSD0_DV, LCDD10_DV_D10),
- PINMUX_DATA(DV_D9_MARK, PSD0_DV, LCDD9_DV_D9),
- PINMUX_DATA(DV_D8_MARK, PSD0_DV, LCDD8_DV_D8),
- PINMUX_DATA(DV_D7_MARK, PSD0_DV, LCDD7_DV_D7),
- PINMUX_DATA(DV_D6_MARK, PSD0_DV, LCDD6_DV_D6),
- PINMUX_DATA(DV_D5_MARK, PSD0_DV, LCDD5_DV_D5),
- PINMUX_DATA(DV_D4_MARK, PSD0_DV, LCDD4_DV_D4),
- PINMUX_DATA(DV_D3_MARK, PSD0_DV, LCDD3_DV_D3),
- PINMUX_DATA(DV_D2_MARK, PSD0_DV, LCDD2_DV_D2),
- PINMUX_DATA(DV_D1_MARK, PSD0_DV, LCDD1_DV_D1),
- PINMUX_DATA(DV_D0_MARK, PSD0_DV, LCDD0_DV_D0),
-
- /* CPG */
- PINMUX_DATA(STATUS0_MARK, STATUS0),
- PINMUX_DATA(PDSTATUS_MARK, PDSTATUS),
-
- /* SIOF0 */
- PINMUX_DATA(SIOF0_MCK_MARK, PSE15_SIOF0_MCK_IRQ3, PSB8_SIOF0_MCK, PTQ0),
- PINMUX_DATA(SIOF0_SCK_MARK, PSB5_SIOF0_SCK, SIOF0_SCK_TS_SCK),
- PINMUX_DATA(SIOF0_SYNC_MARK, PSB4_SIOF0_SYNC, SIOF0_SYNC_TS_SDEN),
- PINMUX_DATA(SIOF0_SS1_MARK, PSB3_SIOF0_SS1, SIOF0_SS1_TS_SPSYNC),
- PINMUX_DATA(SIOF0_SS2_MARK, PSB2_SIOF0_SS2, SIOF0_SS2_SIM_RST),
- PINMUX_DATA(SIOF0_TXD_MARK, PSE14_SIOF0_TXD_IRDA_OUT,
- PSB7_SIOF0_TXD, PTQ1),
- PINMUX_DATA(SIOF0_RXD_MARK, PSE13_SIOF0_RXD_IRDA_IN,
- PSB6_SIOF0_RXD, PTQ2),
-
- /* SIOF1 */
- PINMUX_DATA(SIOF1_MCK_MARK, PSE11_SIUMCKA_SIOF1_MCK,
- PSB1_SIOF1_MCK, PTK0),
- PINMUX_DATA(SIOF1_SCK_MARK, PSC14_SIOF1_SCK, SIUAOBT_SIOF1_SCK),
- PINMUX_DATA(SIOF1_SYNC_MARK, PSC13_SIOF1_SYNC, SIUAOLR_SIOF1_SYNC),
- PINMUX_DATA(SIOF1_SS1_MARK, PSC12_SIOF1_SS1, SIUAIBT_SIOF1_SS1),
- PINMUX_DATA(SIOF1_SS2_MARK, PSC11_SIOF1_SS2, SIUAILR_SIOF1_SS2),
- PINMUX_DATA(SIOF1_TXD_MARK, PSB0_SIOF1_TXD, SIUAOSLD_SIOF1_TXD),
- PINMUX_DATA(SIOF1_RXD_MARK, PSC15_SIOF1_RXD, SIUAISLD_SIOF1_RXD),
-
- /* SIM */
- PINMUX_DATA(SIM_D_MARK, PSE15_SIM_D, PTQ0),
- PINMUX_DATA(SIM_CLK_MARK, PSE14_SIM_CLK, PTQ1),
- PINMUX_DATA(SIM_RST_MARK, PSB2_SIM_RST, SIOF0_SS2_SIM_RST),
-
- /* TSIF */
- PINMUX_DATA(TS_SDAT_MARK, PSE13_TS_SDAT, PTQ2),
- PINMUX_DATA(TS_SCK_MARK, PSB5_TS_SCK, SIOF0_SCK_TS_SCK),
- PINMUX_DATA(TS_SDEN_MARK, PSB4_TS_SDEN, SIOF0_SYNC_TS_SDEN),
- PINMUX_DATA(TS_SPSYNC_MARK, PSB3_TS_SPSYNC, SIOF0_SS1_TS_SPSYNC),
-
- /* IRDA */
- PINMUX_DATA(IRDA_IN_MARK, PSE13_SIOF0_RXD_IRDA_IN, PSB6_IRDA_IN, PTQ2),
- PINMUX_DATA(IRDA_OUT_MARK, PSE14_SIOF0_TXD_IRDA_OUT,
- PSB7_IRDA_OUT, PTQ1),
-
- /* TPU */
- PINMUX_DATA(TPUTO_MARK, PSD8_TPUTO, SCIF0_SCK_TPUTO),
-
- /* FLCTL */
- PINMUX_DATA(FCE_MARK, PSE3_FLCTL, FCE_VIO_HD2),
- PINMUX_DATA(NAF7_MARK, PSC0_NAF, HIZA10_NAF, NAF7_VIO_D15),
- PINMUX_DATA(NAF6_MARK, PSC0_NAF, HIZA10_NAF, NAF6_VIO_D14),
- PINMUX_DATA(NAF5_MARK, PSC0_NAF, HIZA10_NAF, NAF5_VIO_D13),
- PINMUX_DATA(NAF4_MARK, PSC0_NAF, HIZA10_NAF, NAF4_VIO_D12),
- PINMUX_DATA(NAF3_MARK, PSC0_NAF, HIZA10_NAF, NAF3_VIO_D11),
- PINMUX_DATA(NAF2_MARK, PSE2_NAF2, HIZB0_VIO, NAF2_VIO_D10),
- PINMUX_DATA(NAF1_MARK, PSE1_NAF1, HIZB0_VIO, NAF1_VIO_D9),
- PINMUX_DATA(NAF0_MARK, PSE0_NAF0, HIZB0_VIO, NAF0_VIO_D8),
- PINMUX_DATA(FCDE_MARK, FCDE),
- PINMUX_DATA(FOE_MARK, PSE3_FLCTL, HIZB0_VIO, FOE_VIO_VD2),
- PINMUX_DATA(FSC_MARK, FSC),
- PINMUX_DATA(FWE_MARK, FWE),
- PINMUX_DATA(FRB_MARK, PSE3_FLCTL, FRB_VIO_CLK2),
-
- /* KEYSC */
- PINMUX_DATA(KEYIN0_MARK, PSA15_KEYIN0, HIZC14_IRQ6, KEYIN0_IRQ6),
- PINMUX_DATA(KEYIN1_MARK, HIZA14_KEYSC, KEYIN1),
- PINMUX_DATA(KEYIN2_MARK, HIZA14_KEYSC, KEYIN2),
- PINMUX_DATA(KEYIN3_MARK, HIZA14_KEYSC, KEYIN3),
- PINMUX_DATA(KEYIN4_MARK, PSA14_KEYIN4, HIZC15_IRQ7, KEYIN4_IRQ7),
- PINMUX_DATA(KEYOUT0_MARK, HIZA14_KEYSC, KEYOUT0),
- PINMUX_DATA(KEYOUT1_MARK, HIZA14_KEYSC, KEYOUT1),
- PINMUX_DATA(KEYOUT2_MARK, HIZA14_KEYSC, KEYOUT2),
- PINMUX_DATA(KEYOUT3_MARK, HIZA14_KEYSC, KEYOUT3),
- PINMUX_DATA(KEYOUT4_IN6_MARK, HIZA14_KEYSC, KEYOUT4_IN6),
- PINMUX_DATA(KEYOUT5_IN5_MARK, HIZA14_KEYSC, KEYOUT5_IN5),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
- /* PTA */
- PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
- PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
- PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
- PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
- PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
- PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
- PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
- PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
-
- /* PTB */
- PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
- PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
- PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
- PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
- PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
- PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
- PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
- PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
-
- /* PTC */
- PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
- PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
- PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
- PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
- PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
- PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
-
- /* PTD */
- PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
- PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
- PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
- PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
- PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
- PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
- PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
- PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
-
- /* PTE */
- PINMUX_GPIO(GPIO_PTE7, PTE7_DATA),
- PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
- PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
- PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
- PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
- PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
-
- /* PTF */
- PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
- PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
- PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
- PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
- PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
- PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
- PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
-
- /* PTG */
- PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
- PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
- PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
- PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
- PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
-
- /* PTH */
- PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
- PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
- PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
- PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
- PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
- PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
- PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
- PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
-
- /* PTJ */
- PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
- PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
- PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
- PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
- PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
-
- /* PTK */
- PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
- PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
- PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
- PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
- PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
- PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
- PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
-
- /* PTL */
- PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
- PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
- PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
- PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
- PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
- PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
- PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
- PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
-
- /* PTM */
- PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
- PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
- PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
- PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
- PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
- PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
- PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
- PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
-
- /* PTN */
- PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
- PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
- PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
- PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
- PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
- PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
- PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
- PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
-
- /* PTQ */
- PINMUX_GPIO(GPIO_PTQ6, PTQ6_DATA),
- PINMUX_GPIO(GPIO_PTQ5, PTQ5_DATA),
- PINMUX_GPIO(GPIO_PTQ4, PTQ4_DATA),
- PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
- PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
- PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
- PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
-
- /* PTR */
- PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
- PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
- PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
- PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
- PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
-
- /* PTS */
- PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
- PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
- PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
- PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
- PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
-
- /* PTT */
- PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
- PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
- PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
- PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
- PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
-
- /* PTU */
- PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
- PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
- PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
- PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
- PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
-
- /* PTV */
- PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
- PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
- PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
- PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
- PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
-
- /* PTW */
- PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
- PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
- PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
- PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
- PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
- PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
- PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
-
- /* PTX */
- PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
- PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
- PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
- PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
- PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
- PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
- PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
-
- /* PTY */
- PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
- PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
- PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
- PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
- PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
- PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
-
- /* PTZ */
- PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
- PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
- PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
- PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
- PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
-
- /* SCIF0 */
- PINMUX_GPIO(GPIO_FN_SCIF0_TXD, SCIF0_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_RXD, SCIF0_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_RTS, SCIF0_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_CTS, SCIF0_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_SCK, SCIF0_SCK_MARK),
-
- /* SCIF1 */
- PINMUX_GPIO(GPIO_FN_SCIF1_TXD, SCIF1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_RXD, SCIF1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_RTS, SCIF1_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_CTS, SCIF1_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_SCK, SCIF1_SCK_MARK),
-
- /* SCIF2 */
- PINMUX_GPIO(GPIO_FN_SCIF2_TXD, SCIF2_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_RXD, SCIF2_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_RTS, SCIF2_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_CTS, SCIF2_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_SCK, SCIF2_SCK_MARK),
-
- /* SIO */
- PINMUX_GPIO(GPIO_FN_SIOTXD, SIOTXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIORXD, SIORXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOD, SIOD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOSTRB0, SIOSTRB0_MARK),
- PINMUX_GPIO(GPIO_FN_SIOSTRB1, SIOSTRB1_MARK),
- PINMUX_GPIO(GPIO_FN_SIOSCK, SIOSCK_MARK),
- PINMUX_GPIO(GPIO_FN_SIOMCK, SIOMCK_MARK),
-
- /* CEU */
- PINMUX_GPIO(GPIO_FN_VIO_D15, VIO_D15_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D14, VIO_D14_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D13, VIO_D13_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D12, VIO_D12_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D11, VIO_D11_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D10, VIO_D10_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D9, VIO_D9_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D8, VIO_D8_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D7, VIO_D7_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D6, VIO_D6_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D5, VIO_D5_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D4, VIO_D4_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D3, VIO_D3_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D2, VIO_D2_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D1, VIO_D1_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D0, VIO_D0_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_CLK, VIO_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_VD, VIO_VD_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_HD, VIO_HD_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_FLD, VIO_FLD_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_CKO, VIO_CKO_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_STEX, VIO_STEX_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_STEM, VIO_STEM_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_VD2, VIO_VD2_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_HD2, VIO_HD2_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_CLK2, VIO_CLK2_MARK),
-
- /* LCDC */
- PINMUX_GPIO(GPIO_FN_LCDD23, LCDD23_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD22, LCDD22_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD21, LCDD21_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD20, LCDD20_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD19, LCDD19_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD18, LCDD18_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD17, LCDD17_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD16, LCDD16_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD15, LCDD15_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD14, LCDD14_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD13, LCDD13_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD12, LCDD12_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD11, LCDD11_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD10, LCDD10_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD9, LCDD9_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD8, LCDD8_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD7, LCDD7_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD6, LCDD6_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD5, LCDD5_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD4, LCDD4_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD3, LCDD3_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD2, LCDD2_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD1, LCDD1_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD0, LCDD0_MARK),
- PINMUX_GPIO(GPIO_FN_LCDLCLK, LCDLCLK_MARK),
- /* Main LCD */
- PINMUX_GPIO(GPIO_FN_LCDDON, LCDDON_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVCPWC, LCDVCPWC_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVEPWC, LCDVEPWC_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVSYN, LCDVSYN_MARK),
- /* Main LCD - RGB Mode */
- PINMUX_GPIO(GPIO_FN_LCDDCK, LCDDCK_MARK),
- PINMUX_GPIO(GPIO_FN_LCDHSYN, LCDHSYN_MARK),
- PINMUX_GPIO(GPIO_FN_LCDDISP, LCDDISP_MARK),
- /* Main LCD - SYS Mode */
- PINMUX_GPIO(GPIO_FN_LCDRS, LCDRS_MARK),
- PINMUX_GPIO(GPIO_FN_LCDCS, LCDCS_MARK),
- PINMUX_GPIO(GPIO_FN_LCDWR, LCDWR_MARK),
- PINMUX_GPIO(GPIO_FN_LCDRD, LCDRD_MARK),
- /* Sub LCD - SYS Mode */
- PINMUX_GPIO(GPIO_FN_LCDDON2, LCDDON2_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVCPWC2, LCDVCPWC2_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVEPWC2, LCDVEPWC2_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVSYN2, LCDVSYN2_MARK),
- PINMUX_GPIO(GPIO_FN_LCDCS2, LCDCS2_MARK),
-
- /* BSC */
- PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
- PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
- PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
- PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
- PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
- PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
- PINMUX_GPIO(GPIO_FN_CS6B_CE1B, CS6B_CE1B_MARK),
- PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
- PINMUX_GPIO(GPIO_FN_CS6A_CE2B, CS6A_CE2B_MARK),
-
- /* SBSC */
- PINMUX_GPIO(GPIO_FN_HPD63, HPD63_MARK),
- PINMUX_GPIO(GPIO_FN_HPD62, HPD62_MARK),
- PINMUX_GPIO(GPIO_FN_HPD61, HPD61_MARK),
- PINMUX_GPIO(GPIO_FN_HPD60, HPD60_MARK),
- PINMUX_GPIO(GPIO_FN_HPD59, HPD59_MARK),
- PINMUX_GPIO(GPIO_FN_HPD58, HPD58_MARK),
- PINMUX_GPIO(GPIO_FN_HPD57, HPD57_MARK),
- PINMUX_GPIO(GPIO_FN_HPD56, HPD56_MARK),
- PINMUX_GPIO(GPIO_FN_HPD55, HPD55_MARK),
- PINMUX_GPIO(GPIO_FN_HPD54, HPD54_MARK),
- PINMUX_GPIO(GPIO_FN_HPD53, HPD53_MARK),
- PINMUX_GPIO(GPIO_FN_HPD52, HPD52_MARK),
- PINMUX_GPIO(GPIO_FN_HPD51, HPD51_MARK),
- PINMUX_GPIO(GPIO_FN_HPD50, HPD50_MARK),
- PINMUX_GPIO(GPIO_FN_HPD49, HPD49_MARK),
- PINMUX_GPIO(GPIO_FN_HPD48, HPD48_MARK),
- PINMUX_GPIO(GPIO_FN_HPDQM7, HPDQM7_MARK),
- PINMUX_GPIO(GPIO_FN_HPDQM6, HPDQM6_MARK),
- PINMUX_GPIO(GPIO_FN_HPDQM5, HPDQM5_MARK),
- PINMUX_GPIO(GPIO_FN_HPDQM4, HPDQM4_MARK),
-
- /* IRQ */
- PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3, IRQ3_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ4, IRQ4_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ6, IRQ6_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ7, IRQ7_MARK),
-
- /* SDHI */
- PINMUX_GPIO(GPIO_FN_SDHICD, SDHICD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHIWP, SDHIWP_MARK),
- PINMUX_GPIO(GPIO_FN_SDHID3, SDHID3_MARK),
- PINMUX_GPIO(GPIO_FN_SDHID2, SDHID2_MARK),
- PINMUX_GPIO(GPIO_FN_SDHID1, SDHID1_MARK),
- PINMUX_GPIO(GPIO_FN_SDHID0, SDHID0_MARK),
- PINMUX_GPIO(GPIO_FN_SDHICMD, SDHICMD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHICLK, SDHICLK_MARK),
-
- /* SIU - Port A */
- PINMUX_GPIO(GPIO_FN_SIUAOLR, SIUAOLR_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAOBT, SIUAOBT_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAISLD, SIUAISLD_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAILR, SIUAILR_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAIBT, SIUAIBT_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAOSLD, SIUAOSLD_MARK),
- PINMUX_GPIO(GPIO_FN_SIUMCKA, SIUMCKA_MARK),
- PINMUX_GPIO(GPIO_FN_SIUFCKA, SIUFCKA_MARK),
-
- /* SIU - Port B */
- PINMUX_GPIO(GPIO_FN_SIUBOLR, SIUBOLR_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBOBT, SIUBOBT_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBISLD, SIUBISLD_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBILR, SIUBILR_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBIBT, SIUBIBT_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBOSLD, SIUBOSLD_MARK),
- PINMUX_GPIO(GPIO_FN_SIUMCKB, SIUMCKB_MARK),
- PINMUX_GPIO(GPIO_FN_SIUFCKB, SIUFCKB_MARK),
-
- /* AUD */
- PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
-
- /* DMAC */
- PINMUX_GPIO(GPIO_FN_DACK, DACK_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
-
- /* VOU */
- PINMUX_GPIO(GPIO_FN_DV_CLKI, DV_CLKI_MARK),
- PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D15, DV_D15_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D14, DV_D14_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D13, DV_D13_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D12, DV_D12_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D11, DV_D11_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D10, DV_D10_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D9, DV_D9_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D8, DV_D8_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D7, DV_D7_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D6, DV_D6_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D5, DV_D5_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D4, DV_D4_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D3, DV_D3_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D2, DV_D2_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D1, DV_D1_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D0, DV_D0_MARK),
-
- /* CPG */
- PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
- PINMUX_GPIO(GPIO_FN_PDSTATUS, PDSTATUS_MARK),
-
- /* SIOF0 */
- PINMUX_GPIO(GPIO_FN_SIOF0_MCK, SIOF0_MCK_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF0_SCK, SIOF0_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF0_SYNC, SIOF0_SYNC_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF0_SS1, SIOF0_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF0_SS2, SIOF0_SS2_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF0_TXD, SIOF0_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF0_RXD, SIOF0_RXD_MARK),
-
- /* SIOF1 */
- PINMUX_GPIO(GPIO_FN_SIOF1_MCK, SIOF1_MCK_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF1_SCK, SIOF1_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF1_SYNC, SIOF1_SYNC_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF1_SS1, SIOF1_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF1_SS2, SIOF1_SS2_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF1_TXD, SIOF1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF1_RXD, SIOF1_RXD_MARK),
-
- /* SIM */
- PINMUX_GPIO(GPIO_FN_SIM_D, SIM_D_MARK),
- PINMUX_GPIO(GPIO_FN_SIM_CLK, SIM_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SIM_RST, SIM_RST_MARK),
-
- /* TSIF */
- PINMUX_GPIO(GPIO_FN_TS_SDAT, TS_SDAT_MARK),
- PINMUX_GPIO(GPIO_FN_TS_SCK, TS_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_TS_SDEN, TS_SDEN_MARK),
- PINMUX_GPIO(GPIO_FN_TS_SPSYNC, TS_SPSYNC_MARK),
-
- /* IRDA */
- PINMUX_GPIO(GPIO_FN_IRDA_IN, IRDA_IN_MARK),
- PINMUX_GPIO(GPIO_FN_IRDA_OUT, IRDA_OUT_MARK),
-
- /* TPU */
- PINMUX_GPIO(GPIO_FN_TPUTO, TPUTO_MARK),
-
- /* FLCTL */
- PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
- PINMUX_GPIO(GPIO_FN_NAF7, NAF7_MARK),
- PINMUX_GPIO(GPIO_FN_NAF6, NAF6_MARK),
- PINMUX_GPIO(GPIO_FN_NAF5, NAF5_MARK),
- PINMUX_GPIO(GPIO_FN_NAF4, NAF4_MARK),
- PINMUX_GPIO(GPIO_FN_NAF3, NAF3_MARK),
- PINMUX_GPIO(GPIO_FN_NAF2, NAF2_MARK),
- PINMUX_GPIO(GPIO_FN_NAF1, NAF1_MARK),
- PINMUX_GPIO(GPIO_FN_NAF0, NAF0_MARK),
- PINMUX_GPIO(GPIO_FN_FCDE, FCDE_MARK),
- PINMUX_GPIO(GPIO_FN_FOE, FOE_MARK),
- PINMUX_GPIO(GPIO_FN_FSC, FSC_MARK),
- PINMUX_GPIO(GPIO_FN_FWE, FWE_MARK),
- PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
-
- /* KEYSC */
- PINMUX_GPIO(GPIO_FN_KEYIN0, KEYIN0_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN1, KEYIN1_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN2, KEYIN2_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN3, KEYIN3_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN4, KEYIN4_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT0, KEYOUT0_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT1, KEYOUT1_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT2, KEYOUT2_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT3, KEYOUT3_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT4_IN6, KEYOUT4_IN6_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT5_IN5, KEYOUT5_IN5_MARK),
-};
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- { PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
- VIO_D7_SCIF1_SCK, PTA7_OUT, PTA7_IN_PD, PTA7_IN,
- VIO_D6_SCIF1_RXD, 0, PTA6_IN_PD, PTA6_IN,
- VIO_D5_SCIF1_TXD, PTA5_OUT, PTA5_IN_PD, PTA5_IN,
- VIO_D4, 0, PTA4_IN_PD, PTA4_IN,
- VIO_D3, 0, PTA3_IN_PD, PTA3_IN,
- VIO_D2, 0, PTA2_IN_PD, PTA2_IN,
- VIO_D1, 0, PTA1_IN_PD, PTA1_IN,
- VIO_D0_LCDLCLK, 0, PTA0_IN_PD, PTA0_IN }
- },
- { PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
- HPD55, PTB7_OUT, 0, PTB7_IN,
- HPD54, PTB6_OUT, 0, PTB6_IN,
- HPD53, PTB5_OUT, 0, PTB5_IN,
- HPD52, PTB4_OUT, 0, PTB4_IN,
- HPD51, PTB3_OUT, 0, PTB3_IN,
- HPD50, PTB2_OUT, 0, PTB2_IN,
- HPD49, PTB1_OUT, 0, PTB1_IN,
- HPD48, PTB0_OUT, 0, PTB0_IN }
- },
- { PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
- 0, 0, PTC7_IN_PU, PTC7_IN,
- 0, 0, 0, 0,
- IOIS16, 0, PTC5_IN_PU, PTC5_IN,
- HPDQM7, PTC4_OUT, 0, PTC4_IN,
- HPDQM6, PTC3_OUT, 0, PTC3_IN,
- HPDQM5, PTC2_OUT, 0, PTC2_IN,
- 0, 0, 0, 0,
- HPDQM4, PTC0_OUT, 0, PTC0_IN }
- },
- { PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
- SDHICD, 0, PTD7_IN_PU, PTD7_IN,
- SDHIWP, PTD6_OUT, PTD6_IN_PU, PTD6_IN,
- SDHID3, PTD5_OUT, PTD5_IN_PU, PTD5_IN,
- IRQ2_SDHID2, PTD4_OUT, PTD4_IN_PU, PTD4_IN,
- SDHID1, PTD3_OUT, PTD3_IN_PU, PTD3_IN,
- SDHID0, PTD2_OUT, PTD2_IN_PU, PTD2_IN,
- SDHICMD, PTD1_OUT, PTD1_IN_PU, PTD1_IN,
- SDHICLK, PTD0_OUT, 0, 0 }
- },
- { PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
- A25, PTE7_OUT, PTE7_IN_PD, PTE7_IN,
- A24, PTE6_OUT, PTE6_IN_PD, PTE6_IN,
- A23, PTE5_OUT, PTE5_IN_PD, PTE5_IN,
- A22, PTE4_OUT, PTE4_IN_PD, PTE4_IN,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- IRQ5, PTE1_OUT, PTE1_IN_PD, PTE1_IN,
- IRQ4_BS, PTE0_OUT, PTE0_IN_PD, PTE0_IN }
- },
- { PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
- 0, 0, 0, 0,
- PTF6, PTF6_OUT, PTF6_IN_PD, PTF6_IN,
- SIOSCK_SIUBOBT, PTF5_OUT, PTF5_IN_PD, PTF5_IN,
- SIOSTRB1_SIUBOLR, PTF4_OUT, PTF4_IN_PD, PTF4_IN,
- SIOSTRB0_SIUBIBT, PTF3_OUT, PTF3_IN_PD, PTF3_IN,
- SIOD_SIUBILR, PTF2_OUT, PTF2_IN_PD, PTF2_IN,
- SIORXD_SIUBISLD, 0, PTF1_IN_PD, PTF1_IN,
- SIOTXD_SIUBOSLD, PTF0_OUT, 0, 0 }
- },
- { PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- AUDSYNC, PTG4_OUT, 0, 0,
- AUDATA3, PTG3_OUT, 0, 0,
- AUDATA2, PTG2_OUT, 0, 0,
- AUDATA1, PTG1_OUT, 0, 0,
- AUDATA0, PTG0_OUT, 0, 0 }
- },
- { PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
- LCDVCPWC_LCDVCPWC2, PTH7_OUT, 0, 0,
- LCDVSYN2_DACK, PTH6_OUT, PTH6_IN_PD, PTH6_IN,
- LCDVSYN, PTH5_OUT, PTH5_IN_PD, PTH5_IN,
- LCDDISP_LCDRS, PTH4_OUT, 0, 0,
- LCDHSYN_LCDCS, PTH3_OUT, 0, 0,
- LCDDON_LCDDON2, PTH2_OUT, 0, 0,
- LCDD17_DV_HSYNC, PTH1_OUT, PTH1_IN_PD, PTH1_IN,
- LCDD16_DV_VSYNC, PTH0_OUT, PTH0_IN_PD, PTH0_IN }
- },
- { PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
- STATUS0, PTJ7_OUT, 0, 0,
- 0, PTJ6_OUT, 0, 0,
- PDSTATUS, PTJ5_OUT, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- IRQ1, PTJ1_OUT, PTJ1_IN_PU, PTJ1_IN,
- IRQ0, PTJ0_OUT, PTJ0_IN_PU, PTJ0_IN }
- },
- { PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
- 0, 0, 0, 0,
- SIUAILR_SIOF1_SS2, PTK6_OUT, PTK6_IN_PD, PTK6_IN,
- SIUAIBT_SIOF1_SS1, PTK5_OUT, PTK5_IN_PD, PTK5_IN,
- SIUAOLR_SIOF1_SYNC, PTK4_OUT, PTK4_IN_PD, PTK4_IN,
- SIUAOBT_SIOF1_SCK, PTK3_OUT, PTK3_IN_PD, PTK3_IN,
- SIUAISLD_SIOF1_RXD, 0, PTK2_IN_PD, PTK2_IN,
- SIUAOSLD_SIOF1_TXD, PTK1_OUT, 0, 0,
- PTK0, PTK0_OUT, PTK0_IN_PD, PTK0_IN }
- },
- { PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
- LCDD15_DV_D15, PTL7_OUT, PTL7_IN_PD, PTL7_IN,
- LCDD14_DV_D14, PTL6_OUT, PTL6_IN_PD, PTL6_IN,
- LCDD13_DV_D13, PTL5_OUT, PTL5_IN_PD, PTL5_IN,
- LCDD12_DV_D12, PTL4_OUT, PTL4_IN_PD, PTL4_IN,
- LCDD11_DV_D11, PTL3_OUT, PTL3_IN_PD, PTL3_IN,
- LCDD10_DV_D10, PTL2_OUT, PTL2_IN_PD, PTL2_IN,
- LCDD9_DV_D9, PTL1_OUT, PTL1_IN_PD, PTL1_IN,
- LCDD8_DV_D8, PTL0_OUT, PTL0_IN_PD, PTL0_IN }
- },
- { PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
- LCDD7_DV_D7, PTM7_OUT, PTM7_IN_PD, PTM7_IN,
- LCDD6_DV_D6, PTM6_OUT, PTM6_IN_PD, PTM6_IN,
- LCDD5_DV_D5, PTM5_OUT, PTM5_IN_PD, PTM5_IN,
- LCDD4_DV_D4, PTM4_OUT, PTM4_IN_PD, PTM4_IN,
- LCDD3_DV_D3, PTM3_OUT, PTM3_IN_PD, PTM3_IN,
- LCDD2_DV_D2, PTM2_OUT, PTM2_IN_PD, PTM2_IN,
- LCDD1_DV_D1, PTM1_OUT, PTM1_IN_PD, PTM1_IN,
- LCDD0_DV_D0, PTM0_OUT, PTM0_IN_PD, PTM0_IN }
- },
- { PINMUX_CFG_REG("PNCR", 0xa4050118, 16, 2) {
- HPD63, PTN7_OUT, 0, PTN7_IN,
- HPD62, PTN6_OUT, 0, PTN6_IN,
- HPD61, PTN5_OUT, 0, PTN5_IN,
- HPD60, PTN4_OUT, 0, PTN4_IN,
- HPD59, PTN3_OUT, 0, PTN3_IN,
- HPD58, PTN2_OUT, 0, PTN2_IN,
- HPD57, PTN1_OUT, 0, PTN1_IN,
- HPD56, PTN0_OUT, 0, PTN0_IN }
- },
- { PINMUX_CFG_REG("PQCR", 0xa405011a, 16, 2) {
- 0, 0, 0, 0,
- SIOF0_SS2_SIM_RST, PTQ6_OUT, 0, 0,
- SIOF0_SS1_TS_SPSYNC, PTQ5_OUT, PTQ5_IN_PD, PTQ5_IN,
- SIOF0_SYNC_TS_SDEN, PTQ4_OUT, PTQ4_IN_PD, PTQ4_IN,
- SIOF0_SCK_TS_SCK, PTQ3_OUT, PTQ3_IN_PD, PTQ3_IN,
- PTQ2, 0, PTQ2_IN_PD, PTQ2_IN,
- PTQ1, PTQ1_OUT, 0, 0,
- PTQ0, PTQ0_OUT, PTQ0_IN_PU, PTQ0_IN }
- },
- { PINMUX_CFG_REG("PRCR", 0xa405011c, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- LCDRD, PTR4_OUT, 0, 0,
- CS6B_CE1B_LCDCS2, PTR3_OUT, 0, 0,
- WAIT, 0, PTR2_IN_PU, PTR2_IN,
- LCDDCK_LCDWR, PTR1_OUT, 0, 0,
- LCDVEPWC_LCDVEPWC2, PTR0_OUT, 0, 0 }
- },
- { PINMUX_CFG_REG("PSCR", 0xa405011e, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- SCIF0_CTS_SIUAISPD, 0, PTS4_IN_PD, PTS4_IN,
- SCIF0_RTS_SIUAOSPD, PTS3_OUT, 0, 0,
- SCIF0_SCK_TPUTO, PTS2_OUT, PTS2_IN_PD, PTS2_IN,
- SCIF0_RXD, 0, PTS1_IN_PD, PTS1_IN,
- SCIF0_TXD, PTS0_OUT, 0, 0 }
- },
- { PINMUX_CFG_REG("PTCR", 0xa4050140, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- FOE_VIO_VD2, PTT4_OUT, PTT4_IN_PD, PTT4_IN,
- FWE, PTT3_OUT, PTT3_IN_PD, PTT3_IN,
- FSC, PTT2_OUT, PTT2_IN_PD, PTT2_IN,
- DREQ0, 0, PTT1_IN_PD, PTT1_IN,
- FCDE, PTT0_OUT, 0, 0 }
- },
- { PINMUX_CFG_REG("PUCR", 0xa4050142, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- NAF2_VIO_D10, PTU4_OUT, PTU4_IN_PD, PTU4_IN,
- NAF1_VIO_D9, PTU3_OUT, PTU3_IN_PD, PTU3_IN,
- NAF0_VIO_D8, PTU2_OUT, PTU2_IN_PD, PTU2_IN,
- FRB_VIO_CLK2, 0, PTU1_IN_PD, PTU1_IN,
- FCE_VIO_HD2, PTU0_OUT, PTU0_IN_PD, PTU0_IN }
- },
- { PINMUX_CFG_REG("PVCR", 0xa4050144, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- NAF7_VIO_D15, PTV4_OUT, PTV4_IN_PD, PTV4_IN,
- NAF6_VIO_D14, PTV3_OUT, PTV3_IN_PD, PTV3_IN,
- NAF5_VIO_D13, PTV2_OUT, PTV2_IN_PD, PTV2_IN,
- NAF4_VIO_D12, PTV1_OUT, PTV1_IN_PD, PTV1_IN,
- NAF3_VIO_D11, PTV0_OUT, PTV0_IN_PD, PTV0_IN }
- },
- { PINMUX_CFG_REG("PWCR", 0xa4050146, 16, 2) {
- 0, 0, 0, 0,
- VIO_FLD_SCIF2_CTS, 0, PTW6_IN_PD, PTW6_IN,
- VIO_CKO_SCIF2_RTS, PTW5_OUT, 0, 0,
- VIO_STEX_SCIF2_SCK, PTW4_OUT, PTW4_IN_PD, PTW4_IN,
- VIO_STEM_SCIF2_TXD, PTW3_OUT, PTW3_IN_PD, PTW3_IN,
- VIO_HD_SCIF2_RXD, PTW2_OUT, PTW2_IN_PD, PTW2_IN,
- VIO_VD_SCIF1_CTS, PTW1_OUT, PTW1_IN_PD, PTW1_IN,
- VIO_CLK_SCIF1_RTS, PTW0_OUT, PTW0_IN_PD, PTW0_IN }
- },
- { PINMUX_CFG_REG("PXCR", 0xa4050148, 16, 2) {
- 0, 0, 0, 0,
- CS6A_CE2B, PTX6_OUT, PTX6_IN_PU, PTX6_IN,
- LCDD23, PTX5_OUT, PTX5_IN_PD, PTX5_IN,
- LCDD22, PTX4_OUT, PTX4_IN_PD, PTX4_IN,
- LCDD21, PTX3_OUT, PTX3_IN_PD, PTX3_IN,
- LCDD20, PTX2_OUT, PTX2_IN_PD, PTX2_IN,
- LCDD19_DV_CLKI, PTX1_OUT, PTX1_IN_PD, PTX1_IN,
- LCDD18_DV_CLK, PTX0_OUT, PTX0_IN_PD, PTX0_IN }
- },
- { PINMUX_CFG_REG("PYCR", 0xa405014a, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- KEYOUT5_IN5, PTY5_OUT, PTY5_IN_PU, PTY5_IN,
- KEYOUT4_IN6, PTY4_OUT, PTY4_IN_PU, PTY4_IN,
- KEYOUT3, PTY3_OUT, PTY3_IN_PU, PTY3_IN,
- KEYOUT2, PTY2_OUT, PTY2_IN_PU, PTY2_IN,
- KEYOUT1, PTY1_OUT, 0, 0,
- KEYOUT0, PTY0_OUT, PTY0_IN_PU, PTY0_IN }
- },
- { PINMUX_CFG_REG("PZCR", 0xa405014c, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- KEYIN4_IRQ7, 0, PTZ5_IN_PU, PTZ5_IN,
- KEYIN3, 0, PTZ4_IN_PU, PTZ4_IN,
- KEYIN2, 0, PTZ3_IN_PU, PTZ3_IN,
- KEYIN1, 0, PTZ2_IN_PU, PTZ2_IN,
- KEYIN0_IRQ6, 0, PTZ1_IN_PU, PTZ1_IN,
- 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PSELA", 0xa405014e, 16, 1) {
- PSA15_KEYIN0, PSA15_IRQ6,
- PSA14_KEYIN4, PSA14_IRQ7,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- PSA9_IRQ4, PSA9_BS,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- PSA4_IRQ2, PSA4_SDHID2,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0 }
- },
- { PINMUX_CFG_REG("PSELB", 0xa4050150, 16, 1) {
- PSB15_SIOTXD, PSB15_SIUBOSLD,
- PSB14_SIORXD, PSB14_SIUBISLD,
- PSB13_SIOD, PSB13_SIUBILR,
- PSB12_SIOSTRB0, PSB12_SIUBIBT,
- PSB11_SIOSTRB1, PSB11_SIUBOLR,
- PSB10_SIOSCK, PSB10_SIUBOBT,
- PSB9_SIOMCK, PSB9_SIUMCKB,
- PSB8_SIOF0_MCK, PSB8_IRQ3,
- PSB7_SIOF0_TXD, PSB7_IRDA_OUT,
- PSB6_SIOF0_RXD, PSB6_IRDA_IN,
- PSB5_SIOF0_SCK, PSB5_TS_SCK,
- PSB4_SIOF0_SYNC, PSB4_TS_SDEN,
- PSB3_SIOF0_SS1, PSB3_TS_SPSYNC,
- PSB2_SIOF0_SS2, PSB2_SIM_RST,
- PSB1_SIUMCKA, PSB1_SIOF1_MCK,
- PSB0_SIUAOSLD, PSB0_SIOF1_TXD }
- },
- { PINMUX_CFG_REG("PSELC", 0xa4050152, 16, 1) {
- PSC15_SIUAISLD, PSC15_SIOF1_RXD,
- PSC14_SIUAOBT, PSC14_SIOF1_SCK,
- PSC13_SIUAOLR, PSC13_SIOF1_SYNC,
- PSC12_SIUAIBT, PSC12_SIOF1_SS1,
- PSC11_SIUAILR, PSC11_SIOF1_SS2,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- PSC0_NAF, PSC0_VIO }
- },
- { PINMUX_CFG_REG("PSELD", 0xa4050154, 16, 1) {
- 0, 0,
- 0, 0,
- PSD13_VIO, PSD13_SCIF2,
- PSD12_VIO, PSD12_SCIF1,
- PSD11_VIO, PSD11_SCIF1,
- PSD10_VIO_D0, PSD10_LCDLCLK,
- PSD9_SIOMCK_SIUMCKB, PSD9_SIUFCKB,
- PSD8_SCIF0_SCK, PSD8_TPUTO,
- PSD7_SCIF0_RTS, PSD7_SIUAOSPD,
- PSD6_SCIF0_CTS, PSD6_SIUAISPD,
- PSD5_CS6B_CE1B, PSD5_LCDCS2,
- 0, 0,
- PSD3_LCDVEPWC_LCDVCPWC, PSD3_LCDVEPWC2_LCDVCPWC2,
- PSD2_LCDDON, PSD2_LCDDON2,
- 0, 0,
- PSD0_LCDD19_LCDD0, PSD0_DV }
- },
- { PINMUX_CFG_REG("PSELE", 0xa4050156, 16, 1) {
- PSE15_SIOF0_MCK_IRQ3, PSE15_SIM_D,
- PSE14_SIOF0_TXD_IRDA_OUT, PSE14_SIM_CLK,
- PSE13_SIOF0_RXD_IRDA_IN, PSE13_TS_SDAT,
- PSE12_LCDVSYN2, PSE12_DACK,
- PSE11_SIUMCKA_SIOF1_MCK, PSE11_SIUFCKA,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- PSE3_FLCTL, PSE3_VIO,
- PSE2_NAF2, PSE2_VIO_D10,
- PSE1_NAF1, PSE1_VIO_D9,
- PSE0_NAF0, PSE0_VIO_D8 }
- },
- { PINMUX_CFG_REG("HIZCRA", 0xa4050158, 16, 1) {
- 0, 0,
- HIZA14_KEYSC, HIZA14_HIZ,
- 0, 0,
- 0, 0,
- 0, 0,
- HIZA10_NAF, HIZA10_HIZ,
- HIZA9_VIO, HIZA9_HIZ,
- HIZA8_LCDC, HIZA8_HIZ,
- HIZA7_LCDC, HIZA7_HIZ,
- HIZA6_LCDC, HIZA6_HIZ,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0 }
- },
- { PINMUX_CFG_REG("HIZCRB", 0xa405015a, 16, 1) {
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- HIZB4_SIUA, HIZB4_HIZ,
- 0, 0,
- 0, 0,
- HIZB1_VIO, HIZB1_HIZ,
- HIZB0_VIO, HIZB0_HIZ }
- },
- { PINMUX_CFG_REG("HIZCRC", 0xa405015c, 16, 1) {
- HIZC15_IRQ7, HIZC15_HIZ,
- HIZC14_IRQ6, HIZC14_HIZ,
- HIZC13_IRQ5, HIZC13_HIZ,
- HIZC12_IRQ4, HIZC12_HIZ,
- HIZC11_IRQ3, HIZC11_HIZ,
- HIZC10_IRQ2, HIZC10_HIZ,
- HIZC9_IRQ1, HIZC9_HIZ,
- HIZC8_IRQ0, HIZC8_HIZ,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0 }
- },
- { PINMUX_CFG_REG("MSELCRB", 0xa4050182, 16, 1) {
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- MSELB9_VIO, MSELB9_VIO2,
- MSELB8_RGB, MSELB8_SYS,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0 }
- },
- {}
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PADR", 0xa4050120, 8) {
- PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
- PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
- },
- { PINMUX_DATA_REG("PBDR", 0xa4050122, 8) {
- PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
- PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
- },
- { PINMUX_DATA_REG("PCDR", 0xa4050124, 8) {
- PTC7_DATA, 0, PTC5_DATA, PTC4_DATA,
- PTC3_DATA, PTC2_DATA, 0, PTC0_DATA }
- },
- { PINMUX_DATA_REG("PDDR", 0xa4050126, 8) {
- PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
- PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
- },
- { PINMUX_DATA_REG("PEDR", 0xa4050128, 8) {
- PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
- 0, 0, PTE1_DATA, PTE0_DATA }
- },
- { PINMUX_DATA_REG("PFDR", 0xa405012a, 8) {
- 0, PTF6_DATA, PTF5_DATA, PTF4_DATA,
- PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
- },
- { PINMUX_DATA_REG("PGDR", 0xa405012c, 8) {
- 0, 0, 0, PTG4_DATA,
- PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
- },
- { PINMUX_DATA_REG("PHDR", 0xa405012e, 8) {
- PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
- PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
- },
- { PINMUX_DATA_REG("PJDR", 0xa4050130, 8) {
- PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, 0,
- 0, 0, PTJ1_DATA, PTJ0_DATA }
- },
- { PINMUX_DATA_REG("PKDR", 0xa4050132, 8) {
- 0, PTK6_DATA, PTK5_DATA, PTK4_DATA,
- PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
- },
- { PINMUX_DATA_REG("PLDR", 0xa4050134, 8) {
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
- PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
- },
- { PINMUX_DATA_REG("PMDR", 0xa4050136, 8) {
- PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
- PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
- },
- { PINMUX_DATA_REG("PNDR", 0xa4050138, 8) {
- PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
- PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
- },
- { PINMUX_DATA_REG("PQDR", 0xa405013a, 8) {
- 0, PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
- PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA }
- },
- { PINMUX_DATA_REG("PRDR", 0xa405013c, 8) {
- 0, 0, 0, PTR4_DATA,
- PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
- },
- { PINMUX_DATA_REG("PSDR", 0xa405013e, 8) {
- 0, 0, 0, PTS4_DATA,
- PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
- },
- { PINMUX_DATA_REG("PTDR", 0xa4050160, 8) {
- 0, 0, 0, PTT4_DATA,
- PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
- },
- { PINMUX_DATA_REG("PUDR", 0xa4050162, 8) {
- 0, 0, 0, PTU4_DATA,
- PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
- },
- { PINMUX_DATA_REG("PVDR", 0xa4050164, 8) {
- 0, 0, 0, PTV4_DATA,
- PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
- },
- { PINMUX_DATA_REG("PWDR", 0xa4050166, 8) {
- 0, PTW6_DATA, PTW5_DATA, PTW4_DATA,
- PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA }
- },
- { PINMUX_DATA_REG("PXDR", 0xa4050168, 8) {
- 0, PTX6_DATA, PTX5_DATA, PTX4_DATA,
- PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA }
- },
- { PINMUX_DATA_REG("PYDR", 0xa405016a, 8) {
- 0, PTY6_DATA, PTY5_DATA, PTY4_DATA,
- PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA }
- },
- { PINMUX_DATA_REG("PZDR", 0xa405016c, 8) {
- 0, 0, PTZ5_DATA, PTZ4_DATA,
- PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA }
- },
- { },
-};
-
-static struct pinmux_info sh7722_pinmux_info = {
- .name = "sh7722_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
- .input_pd = { PINMUX_INPUT_PULLDOWN_BEGIN, PINMUX_INPUT_PULLDOWN_END },
- .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_PTA7,
- .last_gpio = GPIO_FN_KEYOUT5_IN5,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
+#include <cpu/pfc.h>
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7722_pinmux_info);
+ return sh_pfc_register("pfc-sh7722", NULL, 0);
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7723.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7723.c
index 88bf5ecda849..bcec7ad7f783 100644
--- a/arch/sh/kernel/cpu/sh4a/pinmux-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7723.c
@@ -10,1900 +10,11 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/sh7723.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
- PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
- PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
- PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
- PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
- PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA,
- PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
- PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
- PTE5_DATA, PTE4_DATA, PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA,
- PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
- PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
- PTG5_DATA, PTG4_DATA, PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
- PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
- PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
- PTJ7_DATA, PTJ5_DATA, PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
- PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
- PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
- PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
- PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
- PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
- PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
- PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
- PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
- PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
- PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
- PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
- PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
- PTT5_DATA, PTT4_DATA, PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
- PTU5_DATA, PTU4_DATA, PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
- PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
- PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
- PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
- PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA,
- PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
- PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA,
- PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
- PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA,
- PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
- PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
- PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
- PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
- PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
- PTC7_IN, PTC6_IN, PTC5_IN, PTC4_IN,
- PTC3_IN, PTC2_IN, PTC1_IN, PTC0_IN,
- PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN,
- PTD3_IN, PTD2_IN, PTD1_IN, PTD0_IN,
- PTE5_IN, PTE4_IN, PTE3_IN, PTE2_IN, PTE1_IN, PTE0_IN,
- PTF7_IN, PTF6_IN, PTF5_IN, PTF4_IN,
- PTF3_IN, PTF2_IN, PTF1_IN, PTF0_IN,
- PTH7_IN, PTH6_IN, PTH5_IN, PTH4_IN,
- PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
- PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
- PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
- PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
- PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
- PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
- PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
- PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
- PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
- PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
- PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
- PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
- PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
- PTS7_IN, PTS6_IN, PTS5_IN, PTS4_IN,
- PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
- PTT5_IN, PTT4_IN, PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
- PTU5_IN, PTU4_IN, PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
- PTV7_IN, PTV6_IN, PTV5_IN, PTV4_IN,
- PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
- PTW7_IN, PTW6_IN, PTW5_IN, PTW4_IN,
- PTW3_IN, PTW2_IN, PTW1_IN, PTW0_IN,
- PTX7_IN, PTX6_IN, PTX5_IN, PTX4_IN,
- PTX3_IN, PTX2_IN, PTX1_IN, PTX0_IN,
- PTY7_IN, PTY6_IN, PTY5_IN, PTY4_IN,
- PTY3_IN, PTY2_IN, PTY1_IN, PTY0_IN,
- PTZ7_IN, PTZ6_IN, PTZ5_IN, PTZ4_IN,
- PTZ3_IN, PTZ2_IN, PTZ1_IN, PTZ0_IN,
- PINMUX_INPUT_END,
-
- PINMUX_INPUT_PULLUP_BEGIN,
- PTA4_IN_PU, PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
- PTB2_IN_PU, PTB1_IN_PU,
- PTR2_IN_PU,
- PINMUX_INPUT_PULLUP_END,
-
- PINMUX_OUTPUT_BEGIN,
- PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
- PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
- PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
- PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
- PTC7_OUT, PTC6_OUT, PTC5_OUT, PTC4_OUT,
- PTC3_OUT, PTC2_OUT, PTC1_OUT, PTC0_OUT,
- PTD7_OUT, PTD6_OUT, PTD5_OUT, PTD4_OUT,
- PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
- PTE5_OUT, PTE4_OUT, PTE3_OUT, PTE2_OUT, PTE1_OUT, PTE0_OUT,
- PTF7_OUT, PTF6_OUT, PTF5_OUT, PTF4_OUT,
- PTF3_OUT, PTF2_OUT, PTF1_OUT, PTF0_OUT,
- PTG5_OUT, PTG4_OUT, PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
- PTH7_OUT, PTH6_OUT, PTH5_OUT, PTH4_OUT,
- PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
- PTJ7_OUT, PTJ5_OUT, PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
- PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
- PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
- PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
- PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
- PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
- PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
- PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
- PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
- PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
- PTR1_OUT, PTR0_OUT,
- PTS7_OUT, PTS6_OUT, PTS5_OUT, PTS4_OUT,
- PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
- PTT5_OUT, PTT4_OUT, PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
- PTU5_OUT, PTU4_OUT, PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
- PTV7_OUT, PTV6_OUT, PTV5_OUT, PTV4_OUT,
- PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
- PTW7_OUT, PTW6_OUT, PTW5_OUT, PTW4_OUT,
- PTW3_OUT, PTW2_OUT, PTW1_OUT, PTW0_OUT,
- PTX7_OUT, PTX6_OUT, PTX5_OUT, PTX4_OUT,
- PTX3_OUT, PTX2_OUT, PTX1_OUT, PTX0_OUT,
- PTY7_OUT, PTY6_OUT, PTY5_OUT, PTY4_OUT,
- PTY3_OUT, PTY2_OUT, PTY1_OUT, PTY0_OUT,
- PTZ7_OUT, PTZ6_OUT, PTZ5_OUT, PTZ4_OUT,
- PTZ3_OUT, PTZ2_OUT, PTZ1_OUT, PTZ0_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- PTA7_FN, PTA6_FN, PTA5_FN, PTA4_FN,
- PTA3_FN, PTA2_FN, PTA1_FN, PTA0_FN,
- PTB7_FN, PTB6_FN, PTB5_FN, PTB4_FN,
- PTB3_FN, PTB2_FN, PTB1_FN, PTB0_FN,
- PTC7_FN, PTC6_FN, PTC5_FN, PTC4_FN,
- PTC3_FN, PTC2_FN, PTC1_FN, PTC0_FN,
- PTD7_FN, PTD6_FN, PTD5_FN, PTD4_FN,
- PTD3_FN, PTD2_FN, PTD1_FN, PTD0_FN,
- PTE5_FN, PTE4_FN, PTE3_FN, PTE2_FN, PTE1_FN, PTE0_FN,
- PTF7_FN, PTF6_FN, PTF5_FN, PTF4_FN,
- PTF3_FN, PTF2_FN, PTF1_FN, PTF0_FN,
- PTG5_FN, PTG4_FN, PTG3_FN, PTG2_FN, PTG1_FN, PTG0_FN,
- PTH7_FN, PTH6_FN, PTH5_FN, PTH4_FN,
- PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
- PTJ7_FN, PTJ5_FN, PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
- PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
- PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
- PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN,
- PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
- PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
- PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
- PTN7_FN, PTN6_FN, PTN5_FN, PTN4_FN,
- PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
- PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
- PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
- PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
- PTS7_FN, PTS6_FN, PTS5_FN, PTS4_FN,
- PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
- PTT5_FN, PTT4_FN, PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
- PTU5_FN, PTU4_FN, PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
- PTV7_FN, PTV6_FN, PTV5_FN, PTV4_FN,
- PTV3_FN, PTV2_FN, PTV1_FN, PTV0_FN,
- PTW7_FN, PTW6_FN, PTW5_FN, PTW4_FN,
- PTW3_FN, PTW2_FN, PTW1_FN, PTW0_FN,
- PTX7_FN, PTX6_FN, PTX5_FN, PTX4_FN,
- PTX3_FN, PTX2_FN, PTX1_FN, PTX0_FN,
- PTY7_FN, PTY6_FN, PTY5_FN, PTY4_FN,
- PTY3_FN, PTY2_FN, PTY1_FN, PTY0_FN,
- PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
- PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
-
-
- PSA15_PSA14_FN1, PSA15_PSA14_FN2,
- PSA13_PSA12_FN1, PSA13_PSA12_FN2,
- PSA11_PSA10_FN1, PSA11_PSA10_FN2,
- PSA5_PSA4_FN1, PSA5_PSA4_FN2, PSA5_PSA4_FN3,
- PSA3_PSA2_FN1, PSA3_PSA2_FN2,
- PSB15_PSB14_FN1, PSB15_PSB14_FN2,
- PSB13_PSB12_LCDC_RGB, PSB13_PSB12_LCDC_SYS,
- PSB9_PSB8_FN1, PSB9_PSB8_FN2, PSB9_PSB8_FN3,
- PSB7_PSB6_FN1, PSB7_PSB6_FN2,
- PSB5_PSB4_FN1, PSB5_PSB4_FN2,
- PSB3_PSB2_FN1, PSB3_PSB2_FN2,
- PSC15_PSC14_FN1, PSC15_PSC14_FN2,
- PSC13_PSC12_FN1, PSC13_PSC12_FN2,
- PSC11_PSC10_FN1, PSC11_PSC10_FN2, PSC11_PSC10_FN3,
- PSC9_PSC8_FN1, PSC9_PSC8_FN2,
- PSC7_PSC6_FN1, PSC7_PSC6_FN2, PSC7_PSC6_FN3,
- PSD15_PSD14_FN1, PSD15_PSD14_FN2,
- PSD13_PSD12_FN1, PSD13_PSD12_FN2,
- PSD11_PSD10_FN1, PSD11_PSD10_FN2, PSD11_PSD10_FN3,
- PSD9_PSD8_FN1, PSD9_PSD8_FN2,
- PSD7_PSD6_FN1, PSD7_PSD6_FN2,
- PSD5_PSD4_FN1, PSD5_PSD4_FN2,
- PSD3_PSD2_FN1, PSD3_PSD2_FN2,
- PSD1_PSD0_FN1, PSD1_PSD0_FN2,
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
- SCIF0_PTT_TXD_MARK, SCIF0_PTT_RXD_MARK,
- SCIF0_PTT_SCK_MARK, SCIF0_PTU_TXD_MARK,
- SCIF0_PTU_RXD_MARK, SCIF0_PTU_SCK_MARK,
-
- SCIF1_PTS_TXD_MARK, SCIF1_PTS_RXD_MARK,
- SCIF1_PTS_SCK_MARK, SCIF1_PTV_TXD_MARK,
- SCIF1_PTV_RXD_MARK, SCIF1_PTV_SCK_MARK,
-
- SCIF2_PTT_TXD_MARK, SCIF2_PTT_RXD_MARK,
- SCIF2_PTT_SCK_MARK, SCIF2_PTU_TXD_MARK,
- SCIF2_PTU_RXD_MARK, SCIF2_PTU_SCK_MARK,
-
- SCIF3_PTS_TXD_MARK, SCIF3_PTS_RXD_MARK,
- SCIF3_PTS_SCK_MARK, SCIF3_PTS_RTS_MARK,
- SCIF3_PTS_CTS_MARK, SCIF3_PTV_TXD_MARK,
- SCIF3_PTV_RXD_MARK, SCIF3_PTV_SCK_MARK,
- SCIF3_PTV_RTS_MARK, SCIF3_PTV_CTS_MARK,
-
- SCIF4_PTE_TXD_MARK, SCIF4_PTE_RXD_MARK,
- SCIF4_PTE_SCK_MARK, SCIF4_PTN_TXD_MARK,
- SCIF4_PTN_RXD_MARK, SCIF4_PTN_SCK_MARK,
-
- SCIF5_PTE_TXD_MARK, SCIF5_PTE_RXD_MARK,
- SCIF5_PTE_SCK_MARK, SCIF5_PTN_TXD_MARK,
- SCIF5_PTN_RXD_MARK, SCIF5_PTN_SCK_MARK,
-
- VIO_D15_MARK, VIO_D14_MARK, VIO_D13_MARK, VIO_D12_MARK,
- VIO_D11_MARK, VIO_D10_MARK, VIO_D9_MARK, VIO_D8_MARK,
- VIO_D7_MARK, VIO_D6_MARK, VIO_D5_MARK, VIO_D4_MARK,
- VIO_D3_MARK, VIO_D2_MARK, VIO_D1_MARK, VIO_D0_MARK,
- VIO_FLD_MARK, VIO_CKO_MARK,
- VIO_VD1_MARK, VIO_HD1_MARK, VIO_CLK1_MARK,
- VIO_HD2_MARK, VIO_VD2_MARK, VIO_CLK2_MARK,
-
- LCDD23_MARK, LCDD22_MARK, LCDD21_MARK, LCDD20_MARK,
- LCDD19_MARK, LCDD18_MARK, LCDD17_MARK, LCDD16_MARK,
- LCDD15_MARK, LCDD14_MARK, LCDD13_MARK, LCDD12_MARK,
- LCDD11_MARK, LCDD10_MARK, LCDD9_MARK, LCDD8_MARK,
- LCDD7_MARK, LCDD6_MARK, LCDD5_MARK, LCDD4_MARK,
- LCDD3_MARK, LCDD2_MARK, LCDD1_MARK, LCDD0_MARK,
- LCDDON_MARK, LCDVCPWC_MARK, LCDVEPWC_MARK,
- LCDVSYN_MARK, LCDDCK_MARK, LCDHSYN_MARK, LCDDISP_MARK,
- LCDRS_MARK, LCDCS_MARK, LCDWR_MARK, LCDRD_MARK,
- LCDLCLK_PTR_MARK, LCDLCLK_PTW_MARK,
-
- IRQ0_MARK, IRQ1_MARK, IRQ2_MARK, IRQ3_MARK,
- IRQ4_MARK, IRQ5_MARK, IRQ6_MARK, IRQ7_MARK,
-
- AUDATA3_MARK, AUDATA2_MARK, AUDATA1_MARK, AUDATA0_MARK,
- AUDCK_MARK, AUDSYNC_MARK,
-
- SDHI0CD_PTD_MARK, SDHI0WP_PTD_MARK,
- SDHI0D3_PTD_MARK, SDHI0D2_PTD_MARK,
- SDHI0D1_PTD_MARK, SDHI0D0_PTD_MARK,
- SDHI0CMD_PTD_MARK, SDHI0CLK_PTD_MARK,
-
- SDHI0CD_PTS_MARK, SDHI0WP_PTS_MARK,
- SDHI0D3_PTS_MARK, SDHI0D2_PTS_MARK,
- SDHI0D1_PTS_MARK, SDHI0D0_PTS_MARK,
- SDHI0CMD_PTS_MARK, SDHI0CLK_PTS_MARK,
-
- SDHI1CD_MARK, SDHI1WP_MARK, SDHI1D3_MARK, SDHI1D2_MARK,
- SDHI1D1_MARK, SDHI1D0_MARK, SDHI1CMD_MARK, SDHI1CLK_MARK,
-
- SIUAFCK_MARK, SIUAILR_MARK, SIUAIBT_MARK, SIUAISLD_MARK,
- SIUAOLR_MARK, SIUAOBT_MARK, SIUAOSLD_MARK, SIUAMCK_MARK,
- SIUAISPD_MARK, SIUAOSPD_MARK,
-
- SIUBFCK_MARK, SIUBILR_MARK, SIUBIBT_MARK, SIUBISLD_MARK,
- SIUBOLR_MARK, SIUBOBT_MARK, SIUBOSLD_MARK, SIUBMCK_MARK,
-
- IRDA_IN_MARK, IRDA_OUT_MARK,
-
- DV_CLKI_MARK, DV_CLK_MARK, DV_HSYNC_MARK, DV_VSYNC_MARK,
- DV_D15_MARK, DV_D14_MARK, DV_D13_MARK, DV_D12_MARK,
- DV_D11_MARK, DV_D10_MARK, DV_D9_MARK, DV_D8_MARK,
- DV_D7_MARK, DV_D6_MARK, DV_D5_MARK, DV_D4_MARK,
- DV_D3_MARK, DV_D2_MARK, DV_D1_MARK, DV_D0_MARK,
-
- KEYIN0_MARK, KEYIN1_MARK, KEYIN2_MARK, KEYIN3_MARK, KEYIN4_MARK,
- KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK,
- KEYOUT4_IN6_MARK, KEYOUT5_IN5_MARK,
-
- MSIOF0_PTF_TXD_MARK, MSIOF0_PTF_RXD_MARK, MSIOF0_PTF_MCK_MARK,
- MSIOF0_PTF_TSYNC_MARK, MSIOF0_PTF_TSCK_MARK, MSIOF0_PTF_RSYNC_MARK,
- MSIOF0_PTF_RSCK_MARK, MSIOF0_PTF_SS1_MARK, MSIOF0_PTF_SS2_MARK,
-
- MSIOF0_PTT_TXD_MARK, MSIOF0_PTT_RXD_MARK, MSIOF0_PTX_MCK_MARK,
- MSIOF0_PTT_TSYNC_MARK, MSIOF0_PTT_TSCK_MARK, MSIOF0_PTT_RSYNC_MARK,
- MSIOF0_PTT_RSCK_MARK, MSIOF0_PTT_SS1_MARK, MSIOF0_PTT_SS2_MARK,
-
- MSIOF1_TXD_MARK, MSIOF1_RXD_MARK, MSIOF1_MCK_MARK,
- MSIOF1_TSYNC_MARK, MSIOF1_TSCK_MARK, MSIOF1_RSYNC_MARK,
- MSIOF1_RSCK_MARK, MSIOF1_SS1_MARK, MSIOF1_SS2_MARK,
-
- TS0_SDAT_MARK, TS0_SCK_MARK, TS0_SDEN_MARK, TS0_SPSYNC_MARK,
-
- FCE_MARK, NAF7_MARK, NAF6_MARK, NAF5_MARK, NAF4_MARK,
- NAF3_MARK, NAF2_MARK, NAF1_MARK, NAF0_MARK, FCDE_MARK,
- FOE_MARK, FSC_MARK, FWE_MARK, FRB_MARK,
-
- DACK1_MARK, DREQ1_MARK, DACK0_MARK, DREQ0_MARK,
-
- AN3_MARK, AN2_MARK, AN1_MARK, AN0_MARK, ADTRG_MARK,
-
- STATUS0_MARK, PDSTATUS_MARK,
-
- TPUTO3_MARK, TPUTO2_MARK, TPUTO1_MARK, TPUTO0_MARK,
-
- D31_MARK, D30_MARK, D29_MARK, D28_MARK,
- D27_MARK, D26_MARK, D25_MARK, D24_MARK,
- D23_MARK, D22_MARK, D21_MARK, D20_MARK,
- D19_MARK, D18_MARK, D17_MARK, D16_MARK,
- IOIS16_MARK, WAIT_MARK, BS_MARK,
- A25_MARK, A24_MARK, A23_MARK, A22_MARK,
- CS6B_CE1B_MARK, CS6A_CE2B_MARK,
- CS5B_CE1A_MARK, CS5A_CE2A_MARK,
- WE3_ICIOWR_MARK, WE2_ICIORD_MARK,
-
- IDED15_MARK, IDED14_MARK, IDED13_MARK, IDED12_MARK,
- IDED11_MARK, IDED10_MARK, IDED9_MARK, IDED8_MARK,
- IDED7_MARK, IDED6_MARK, IDED5_MARK, IDED4_MARK,
- IDED3_MARK, IDED2_MARK, IDED1_MARK, IDED0_MARK,
- DIRECTION_MARK, EXBUF_ENB_MARK, IDERST_MARK, IODACK_MARK,
- IODREQ_MARK, IDEIORDY_MARK, IDEINT_MARK, IDEIOWR_MARK,
- IDEIORD_MARK, IDECS1_MARK, IDECS0_MARK, IDEA2_MARK,
- IDEA1_MARK, IDEA0_MARK,
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
- /* PTA GPIO */
- PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT),
- PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT),
- PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT),
- PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT, PTA4_IN_PU),
- PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT, PTA3_IN_PU),
- PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT, PTA2_IN_PU),
- PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT, PTA1_IN_PU),
- PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT, PTA0_IN_PU),
-
- /* PTB GPIO */
- PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT),
- PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT),
- PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT),
- PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT),
- PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT),
- PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT, PTB2_IN_PU),
- PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT, PTB1_IN_PU),
- PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT),
-
- /* PTC GPIO */
- PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT),
- PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT),
- PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT),
- PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT),
- PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT),
- PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT),
- PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT),
- PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT),
-
- /* PTD GPIO */
- PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT),
- PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT),
- PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT),
- PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT),
- PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT),
- PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT),
- PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT),
- PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT),
-
- /* PTE GPIO */
- PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT),
- PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT),
- PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT),
- PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT),
- PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT),
- PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT),
-
- /* PTF GPIO */
- PINMUX_DATA(PTF7_DATA, PTF7_IN, PTF7_OUT),
- PINMUX_DATA(PTF6_DATA, PTF6_IN, PTF6_OUT),
- PINMUX_DATA(PTF5_DATA, PTF5_IN, PTF5_OUT),
- PINMUX_DATA(PTF4_DATA, PTF4_IN, PTF4_OUT),
- PINMUX_DATA(PTF3_DATA, PTF3_IN, PTF3_OUT),
- PINMUX_DATA(PTF2_DATA, PTF2_IN, PTF2_OUT),
- PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_OUT),
- PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT),
-
- /* PTG GPIO */
- PINMUX_DATA(PTG5_DATA, PTG5_OUT),
- PINMUX_DATA(PTG4_DATA, PTG4_OUT),
- PINMUX_DATA(PTG3_DATA, PTG3_OUT),
- PINMUX_DATA(PTG2_DATA, PTG2_OUT),
- PINMUX_DATA(PTG1_DATA, PTG1_OUT),
- PINMUX_DATA(PTG0_DATA, PTG0_OUT),
-
- /* PTH GPIO */
- PINMUX_DATA(PTH7_DATA, PTH7_IN, PTH7_OUT),
- PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT),
- PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT),
- PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT),
- PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT),
- PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT),
- PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT),
- PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT),
-
- /* PTJ GPIO */
- PINMUX_DATA(PTJ7_DATA, PTJ7_OUT),
- PINMUX_DATA(PTJ5_DATA, PTJ5_OUT),
- PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT),
- PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT),
- PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT),
- PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT),
-
- /* PTK GPIO */
- PINMUX_DATA(PTK7_DATA, PTK7_IN, PTK7_OUT),
- PINMUX_DATA(PTK6_DATA, PTK6_IN, PTK6_OUT),
- PINMUX_DATA(PTK5_DATA, PTK5_IN, PTK5_OUT),
- PINMUX_DATA(PTK4_DATA, PTK4_IN, PTK4_OUT),
- PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT),
- PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT),
- PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT),
- PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT),
-
- /* PTL GPIO */
- PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT),
- PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT),
- PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT),
- PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT),
- PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT),
- PINMUX_DATA(PTL2_DATA, PTL2_IN, PTL2_OUT),
- PINMUX_DATA(PTL1_DATA, PTL1_IN, PTL1_OUT),
- PINMUX_DATA(PTL0_DATA, PTL0_IN, PTL0_OUT),
-
- /* PTM GPIO */
- PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT),
- PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT),
- PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT),
- PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT),
- PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT),
- PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT),
- PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT),
- PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT),
-
- /* PTN GPIO */
- PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT),
- PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT),
- PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT),
- PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT),
- PINMUX_DATA(PTN3_DATA, PTN3_IN, PTN3_OUT),
- PINMUX_DATA(PTN2_DATA, PTN2_IN, PTN2_OUT),
- PINMUX_DATA(PTN1_DATA, PTN1_IN, PTN1_OUT),
- PINMUX_DATA(PTN0_DATA, PTN0_IN, PTN0_OUT),
-
- /* PTQ GPIO */
- PINMUX_DATA(PTQ3_DATA, PTQ3_IN),
- PINMUX_DATA(PTQ2_DATA, PTQ2_IN),
- PINMUX_DATA(PTQ1_DATA, PTQ1_IN),
- PINMUX_DATA(PTQ0_DATA, PTQ0_IN),
-
- /* PTR GPIO */
- PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT),
- PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT),
- PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT),
- PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT),
- PINMUX_DATA(PTR3_DATA, PTR3_IN),
- PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_IN_PU),
- PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT),
- PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT),
-
- /* PTS GPIO */
- PINMUX_DATA(PTS7_DATA, PTS7_IN, PTS7_OUT),
- PINMUX_DATA(PTS6_DATA, PTS6_IN, PTS6_OUT),
- PINMUX_DATA(PTS5_DATA, PTS5_IN, PTS5_OUT),
- PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT),
- PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT),
- PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT),
- PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT),
- PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT),
-
- /* PTT GPIO */
- PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT),
- PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT),
- PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT),
- PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT),
- PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT),
- PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT),
-
- /* PTU GPIO */
- PINMUX_DATA(PTU5_DATA, PTU5_IN, PTU5_OUT),
- PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT),
- PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT),
- PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT),
- PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT),
- PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT),
-
- /* PTV GPIO */
- PINMUX_DATA(PTV7_DATA, PTV7_IN, PTV7_OUT),
- PINMUX_DATA(PTV6_DATA, PTV6_IN, PTV6_OUT),
- PINMUX_DATA(PTV5_DATA, PTV5_IN, PTV5_OUT),
- PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT),
- PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT),
- PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT),
- PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT),
- PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT),
-
- /* PTW GPIO */
- PINMUX_DATA(PTW7_DATA, PTW7_IN, PTW7_OUT),
- PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_OUT),
- PINMUX_DATA(PTW5_DATA, PTW5_IN, PTW5_OUT),
- PINMUX_DATA(PTW4_DATA, PTW4_IN, PTW4_OUT),
- PINMUX_DATA(PTW3_DATA, PTW3_IN, PTW3_OUT),
- PINMUX_DATA(PTW2_DATA, PTW2_IN, PTW2_OUT),
- PINMUX_DATA(PTW1_DATA, PTW1_IN, PTW1_OUT),
- PINMUX_DATA(PTW0_DATA, PTW0_IN, PTW0_OUT),
-
- /* PTX GPIO */
- PINMUX_DATA(PTX7_DATA, PTX7_IN, PTX7_OUT),
- PINMUX_DATA(PTX6_DATA, PTX6_IN, PTX6_OUT),
- PINMUX_DATA(PTX5_DATA, PTX5_IN, PTX5_OUT),
- PINMUX_DATA(PTX4_DATA, PTX4_IN, PTX4_OUT),
- PINMUX_DATA(PTX3_DATA, PTX3_IN, PTX3_OUT),
- PINMUX_DATA(PTX2_DATA, PTX2_IN, PTX2_OUT),
- PINMUX_DATA(PTX1_DATA, PTX1_IN, PTX1_OUT),
- PINMUX_DATA(PTX0_DATA, PTX0_IN, PTX0_OUT),
-
- /* PTY GPIO */
- PINMUX_DATA(PTY7_DATA, PTY7_IN, PTY7_OUT),
- PINMUX_DATA(PTY6_DATA, PTY6_IN, PTY6_OUT),
- PINMUX_DATA(PTY5_DATA, PTY5_IN, PTY5_OUT),
- PINMUX_DATA(PTY4_DATA, PTY4_IN, PTY4_OUT),
- PINMUX_DATA(PTY3_DATA, PTY3_IN, PTY3_OUT),
- PINMUX_DATA(PTY2_DATA, PTY2_IN, PTY2_OUT),
- PINMUX_DATA(PTY1_DATA, PTY1_IN, PTY1_OUT),
- PINMUX_DATA(PTY0_DATA, PTY0_IN, PTY0_OUT),
-
- /* PTZ GPIO */
- PINMUX_DATA(PTZ7_DATA, PTZ7_IN, PTZ7_OUT),
- PINMUX_DATA(PTZ6_DATA, PTZ6_IN, PTZ6_OUT),
- PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_OUT),
- PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_OUT),
- PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_OUT),
- PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_OUT),
- PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_OUT),
- PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT),
-
- /* PTA FN */
- PINMUX_DATA(D23_MARK, PSA15_PSA14_FN1, PTA7_FN),
- PINMUX_DATA(KEYOUT2_MARK, PSA15_PSA14_FN2, PTA7_FN),
- PINMUX_DATA(D22_MARK, PSA15_PSA14_FN1, PTA6_FN),
- PINMUX_DATA(KEYOUT1_MARK, PSA15_PSA14_FN2, PTA6_FN),
- PINMUX_DATA(D21_MARK, PSA15_PSA14_FN1, PTA5_FN),
- PINMUX_DATA(KEYOUT0_MARK, PSA15_PSA14_FN2, PTA5_FN),
- PINMUX_DATA(D20_MARK, PSA15_PSA14_FN1, PTA4_FN),
- PINMUX_DATA(KEYIN4_MARK, PSA15_PSA14_FN2, PTA4_FN),
- PINMUX_DATA(D19_MARK, PSA15_PSA14_FN1, PTA3_FN),
- PINMUX_DATA(KEYIN3_MARK, PSA15_PSA14_FN2, PTA3_FN),
- PINMUX_DATA(D18_MARK, PSA15_PSA14_FN1, PTA2_FN),
- PINMUX_DATA(KEYIN2_MARK, PSA15_PSA14_FN2, PTA2_FN),
- PINMUX_DATA(D17_MARK, PSA15_PSA14_FN1, PTA1_FN),
- PINMUX_DATA(KEYIN1_MARK, PSA15_PSA14_FN2, PTA1_FN),
- PINMUX_DATA(D16_MARK, PSA15_PSA14_FN1, PTA0_FN),
- PINMUX_DATA(KEYIN0_MARK, PSA15_PSA14_FN2, PTA0_FN),
-
- /* PTB FN */
- PINMUX_DATA(D31_MARK, PTB7_FN),
- PINMUX_DATA(D30_MARK, PTB6_FN),
- PINMUX_DATA(D29_MARK, PTB5_FN),
- PINMUX_DATA(D28_MARK, PTB4_FN),
- PINMUX_DATA(D27_MARK, PTB3_FN),
- PINMUX_DATA(D26_MARK, PSA15_PSA14_FN1, PTB2_FN),
- PINMUX_DATA(KEYOUT5_IN5_MARK, PSA15_PSA14_FN2, PTB2_FN),
- PINMUX_DATA(D25_MARK, PSA15_PSA14_FN1, PTB1_FN),
- PINMUX_DATA(KEYOUT4_IN6_MARK, PSA15_PSA14_FN2, PTB1_FN),
- PINMUX_DATA(D24_MARK, PSA15_PSA14_FN1, PTB0_FN),
- PINMUX_DATA(KEYOUT3_MARK, PSA15_PSA14_FN2, PTB0_FN),
-
- /* PTC FN */
- PINMUX_DATA(IDED15_MARK, PSA11_PSA10_FN1, PTC7_FN),
- PINMUX_DATA(SDHI1CD_MARK, PSA11_PSA10_FN2, PTC7_FN),
- PINMUX_DATA(IDED14_MARK, PSA11_PSA10_FN1, PTC6_FN),
- PINMUX_DATA(SDHI1WP_MARK, PSA11_PSA10_FN2, PTC6_FN),
- PINMUX_DATA(IDED13_MARK, PSA11_PSA10_FN1, PTC5_FN),
- PINMUX_DATA(SDHI1D3_MARK, PSA11_PSA10_FN2, PTC5_FN),
- PINMUX_DATA(IDED12_MARK, PSA11_PSA10_FN1, PTC4_FN),
- PINMUX_DATA(SDHI1D2_MARK, PSA11_PSA10_FN2, PTC4_FN),
- PINMUX_DATA(IDED11_MARK, PSA11_PSA10_FN1, PTC3_FN),
- PINMUX_DATA(SDHI1D1_MARK, PSA11_PSA10_FN2, PTC3_FN),
- PINMUX_DATA(IDED10_MARK, PSA11_PSA10_FN1, PTC2_FN),
- PINMUX_DATA(SDHI1D0_MARK, PSA11_PSA10_FN2, PTC2_FN),
- PINMUX_DATA(IDED9_MARK, PSA11_PSA10_FN1, PTC1_FN),
- PINMUX_DATA(SDHI1CMD_MARK, PSA11_PSA10_FN2, PTC1_FN),
- PINMUX_DATA(IDED8_MARK, PSA11_PSA10_FN1, PTC0_FN),
- PINMUX_DATA(SDHI1CLK_MARK, PSA11_PSA10_FN2, PTC0_FN),
-
- /* PTD FN */
- PINMUX_DATA(IDED7_MARK, PSA11_PSA10_FN1, PTD7_FN),
- PINMUX_DATA(SDHI0CD_PTD_MARK, PSA11_PSA10_FN2, PTD7_FN),
- PINMUX_DATA(IDED6_MARK, PSA11_PSA10_FN1, PTD6_FN),
- PINMUX_DATA(SDHI0WP_PTD_MARK, PSA11_PSA10_FN2, PTD6_FN),
- PINMUX_DATA(IDED5_MARK, PSA11_PSA10_FN1, PTD5_FN),
- PINMUX_DATA(SDHI0D3_PTD_MARK, PSA11_PSA10_FN2, PTD5_FN),
- PINMUX_DATA(IDED4_MARK, PSA11_PSA10_FN1, PTD4_FN),
- PINMUX_DATA(SDHI0D2_PTD_MARK, PSA11_PSA10_FN2, PTD4_FN),
- PINMUX_DATA(IDED3_MARK, PSA11_PSA10_FN1, PTD3_FN),
- PINMUX_DATA(SDHI0D1_PTD_MARK, PSA11_PSA10_FN2, PTD3_FN),
- PINMUX_DATA(IDED2_MARK, PSA11_PSA10_FN1, PTD2_FN),
- PINMUX_DATA(SDHI0D0_PTD_MARK, PSA11_PSA10_FN2, PTD2_FN),
- PINMUX_DATA(IDED1_MARK, PSA11_PSA10_FN1, PTD1_FN),
- PINMUX_DATA(SDHI0CMD_PTD_MARK, PSA11_PSA10_FN2, PTD1_FN),
- PINMUX_DATA(IDED0_MARK, PSA11_PSA10_FN1, PTD0_FN),
- PINMUX_DATA(SDHI0CLK_PTD_MARK, PSA11_PSA10_FN2, PTD0_FN),
-
- /* PTE FN */
- PINMUX_DATA(DIRECTION_MARK, PSA11_PSA10_FN1, PTE5_FN),
- PINMUX_DATA(SCIF5_PTE_SCK_MARK, PSA11_PSA10_FN2, PTE5_FN),
- PINMUX_DATA(EXBUF_ENB_MARK, PSA11_PSA10_FN1, PTE4_FN),
- PINMUX_DATA(SCIF5_PTE_RXD_MARK, PSA11_PSA10_FN2, PTE4_FN),
- PINMUX_DATA(IDERST_MARK, PSA11_PSA10_FN1, PTE3_FN),
- PINMUX_DATA(SCIF5_PTE_TXD_MARK, PSA11_PSA10_FN2, PTE3_FN),
- PINMUX_DATA(IODACK_MARK, PSA11_PSA10_FN1, PTE2_FN),
- PINMUX_DATA(SCIF4_PTE_SCK_MARK, PSA11_PSA10_FN2, PTE2_FN),
- PINMUX_DATA(IODREQ_MARK, PSA11_PSA10_FN1, PTE1_FN),
- PINMUX_DATA(SCIF4_PTE_RXD_MARK, PSA11_PSA10_FN2, PTE1_FN),
- PINMUX_DATA(IDEIORDY_MARK, PSA11_PSA10_FN1, PTE0_FN),
- PINMUX_DATA(SCIF4_PTE_TXD_MARK, PSA11_PSA10_FN2, PTE0_FN),
-
- /* PTF FN */
- PINMUX_DATA(IDEINT_MARK, PTF7_FN),
- PINMUX_DATA(IDEIOWR_MARK, PSA5_PSA4_FN1, PTF6_FN),
- PINMUX_DATA(MSIOF0_PTF_SS2_MARK, PSA5_PSA4_FN2, PTF6_FN),
- PINMUX_DATA(MSIOF0_PTF_RSYNC_MARK, PSA5_PSA4_FN3, PTF6_FN),
- PINMUX_DATA(IDEIORD_MARK, PSA5_PSA4_FN1, PTF5_FN),
- PINMUX_DATA(MSIOF0_PTF_SS1_MARK, PSA5_PSA4_FN2, PTF5_FN),
- PINMUX_DATA(MSIOF0_PTF_RSCK_MARK, PSA5_PSA4_FN3, PTF5_FN),
- PINMUX_DATA(IDECS1_MARK, PSA11_PSA10_FN1, PTF4_FN),
- PINMUX_DATA(MSIOF0_PTF_TSYNC_MARK, PSA11_PSA10_FN2, PTF4_FN),
- PINMUX_DATA(IDECS0_MARK, PSA11_PSA10_FN1, PTF3_FN),
- PINMUX_DATA(MSIOF0_PTF_TSCK_MARK, PSA11_PSA10_FN2, PTF3_FN),
- PINMUX_DATA(IDEA2_MARK, PSA11_PSA10_FN1, PTF2_FN),
- PINMUX_DATA(MSIOF0_PTF_RXD_MARK, PSA11_PSA10_FN2, PTF2_FN),
- PINMUX_DATA(IDEA1_MARK, PSA11_PSA10_FN1, PTF1_FN),
- PINMUX_DATA(MSIOF0_PTF_TXD_MARK, PSA11_PSA10_FN2, PTF1_FN),
- PINMUX_DATA(IDEA0_MARK, PSA11_PSA10_FN1, PTF0_FN),
- PINMUX_DATA(MSIOF0_PTF_MCK_MARK, PSA11_PSA10_FN2, PTF0_FN),
-
- /* PTG FN */
- PINMUX_DATA(AUDCK_MARK, PTG5_FN),
- PINMUX_DATA(AUDSYNC_MARK, PTG4_FN),
- PINMUX_DATA(AUDATA3_MARK, PSA3_PSA2_FN1, PTG3_FN),
- PINMUX_DATA(TPUTO3_MARK, PSA3_PSA2_FN2, PTG3_FN),
- PINMUX_DATA(AUDATA2_MARK, PSA3_PSA2_FN1, PTG2_FN),
- PINMUX_DATA(TPUTO2_MARK, PSA3_PSA2_FN2, PTG2_FN),
- PINMUX_DATA(AUDATA1_MARK, PSA3_PSA2_FN1, PTG1_FN),
- PINMUX_DATA(TPUTO1_MARK, PSA3_PSA2_FN2, PTG1_FN),
- PINMUX_DATA(AUDATA0_MARK, PSA3_PSA2_FN1, PTG0_FN),
- PINMUX_DATA(TPUTO0_MARK, PSA3_PSA2_FN2, PTG0_FN),
-
- /* PTG FN */
- PINMUX_DATA(LCDVCPWC_MARK, PTH7_FN),
- PINMUX_DATA(LCDRD_MARK, PSB15_PSB14_FN1, PTH6_FN),
- PINMUX_DATA(DV_CLKI_MARK, PSB15_PSB14_FN2, PTH6_FN),
- PINMUX_DATA(LCDVSYN_MARK, PSB15_PSB14_FN1, PTH5_FN),
- PINMUX_DATA(DV_CLK_MARK, PSB15_PSB14_FN2, PTH5_FN),
- PINMUX_DATA(LCDDISP_MARK, PSB13_PSB12_LCDC_RGB, PTH4_FN),
- PINMUX_DATA(LCDRS_MARK, PSB13_PSB12_LCDC_SYS, PTH4_FN),
- PINMUX_DATA(LCDHSYN_MARK, PSB13_PSB12_LCDC_RGB, PTH3_FN),
- PINMUX_DATA(LCDCS_MARK, PSB13_PSB12_LCDC_SYS, PTH3_FN),
- PINMUX_DATA(LCDDON_MARK, PTH2_FN),
- PINMUX_DATA(LCDDCK_MARK, PSB13_PSB12_LCDC_RGB, PTH1_FN),
- PINMUX_DATA(LCDWR_MARK, PSB13_PSB12_LCDC_SYS, PTH1_FN),
- PINMUX_DATA(LCDVEPWC_MARK, PTH0_FN),
-
- /* PTJ FN */
- PINMUX_DATA(STATUS0_MARK, PTJ7_FN),
- PINMUX_DATA(PDSTATUS_MARK, PTJ5_FN),
- PINMUX_DATA(A25_MARK, PTJ3_FN),
- PINMUX_DATA(A24_MARK, PTJ2_FN),
- PINMUX_DATA(A23_MARK, PTJ1_FN),
- PINMUX_DATA(A22_MARK, PTJ0_FN),
-
- /* PTK FN */
- PINMUX_DATA(SIUAFCK_MARK, PTK7_FN),
- PINMUX_DATA(SIUAILR_MARK, PSB9_PSB8_FN1, PTK6_FN),
- PINMUX_DATA(MSIOF1_SS2_MARK, PSB9_PSB8_FN2, PTK6_FN),
- PINMUX_DATA(MSIOF1_RSYNC_MARK, PSB9_PSB8_FN3, PTK6_FN),
- PINMUX_DATA(SIUAIBT_MARK, PSB9_PSB8_FN1, PTK5_FN),
- PINMUX_DATA(MSIOF1_SS1_MARK, PSB9_PSB8_FN2, PTK5_FN),
- PINMUX_DATA(MSIOF1_RSCK_MARK, PSB9_PSB8_FN3, PTK5_FN),
- PINMUX_DATA(SIUAISLD_MARK, PSB7_PSB6_FN1, PTK4_FN),
- PINMUX_DATA(MSIOF1_RXD_MARK, PSB7_PSB6_FN2, PTK4_FN),
- PINMUX_DATA(SIUAOLR_MARK, PSB7_PSB6_FN1, PTK3_FN),
- PINMUX_DATA(MSIOF1_TSYNC_MARK, PSB7_PSB6_FN2, PTK3_FN),
- PINMUX_DATA(SIUAOBT_MARK, PSB7_PSB6_FN1, PTK2_FN),
- PINMUX_DATA(MSIOF1_TSCK_MARK, PSB7_PSB6_FN2, PTK2_FN),
- PINMUX_DATA(SIUAOSLD_MARK, PSB7_PSB6_FN1, PTK1_FN),
- PINMUX_DATA(MSIOF1_RXD_MARK, PSB7_PSB6_FN2, PTK1_FN),
- PINMUX_DATA(SIUAMCK_MARK, PSB7_PSB6_FN1, PTK0_FN),
- PINMUX_DATA(MSIOF1_MCK_MARK, PSB7_PSB6_FN2, PTK0_FN),
-
- /* PTL FN */
- PINMUX_DATA(LCDD15_MARK, PSB5_PSB4_FN1, PTL7_FN),
- PINMUX_DATA(DV_D15_MARK, PSB5_PSB4_FN2, PTL7_FN),
- PINMUX_DATA(LCDD14_MARK, PSB5_PSB4_FN1, PTL6_FN),
- PINMUX_DATA(DV_D14_MARK, PSB5_PSB4_FN2, PTL6_FN),
- PINMUX_DATA(LCDD13_MARK, PSB5_PSB4_FN1, PTL5_FN),
- PINMUX_DATA(DV_D13_MARK, PSB5_PSB4_FN2, PTL5_FN),
- PINMUX_DATA(LCDD12_MARK, PSB5_PSB4_FN1, PTL4_FN),
- PINMUX_DATA(DV_D12_MARK, PSB5_PSB4_FN2, PTL4_FN),
- PINMUX_DATA(LCDD11_MARK, PSB5_PSB4_FN1, PTL3_FN),
- PINMUX_DATA(DV_D11_MARK, PSB5_PSB4_FN2, PTL3_FN),
- PINMUX_DATA(LCDD10_MARK, PSB5_PSB4_FN1, PTL2_FN),
- PINMUX_DATA(DV_D10_MARK, PSB5_PSB4_FN2, PTL2_FN),
- PINMUX_DATA(LCDD9_MARK, PSB5_PSB4_FN1, PTL1_FN),
- PINMUX_DATA(DV_D9_MARK, PSB5_PSB4_FN2, PTL1_FN),
- PINMUX_DATA(LCDD8_MARK, PSB5_PSB4_FN1, PTL0_FN),
- PINMUX_DATA(DV_D8_MARK, PSB5_PSB4_FN2, PTL0_FN),
-
- /* PTM FN */
- PINMUX_DATA(LCDD7_MARK, PSB5_PSB4_FN1, PTM7_FN),
- PINMUX_DATA(DV_D7_MARK, PSB5_PSB4_FN2, PTM7_FN),
- PINMUX_DATA(LCDD6_MARK, PSB5_PSB4_FN1, PTM6_FN),
- PINMUX_DATA(DV_D6_MARK, PSB5_PSB4_FN2, PTM6_FN),
- PINMUX_DATA(LCDD5_MARK, PSB5_PSB4_FN1, PTM5_FN),
- PINMUX_DATA(DV_D5_MARK, PSB5_PSB4_FN2, PTM5_FN),
- PINMUX_DATA(LCDD4_MARK, PSB5_PSB4_FN1, PTM4_FN),
- PINMUX_DATA(DV_D4_MARK, PSB5_PSB4_FN2, PTM4_FN),
- PINMUX_DATA(LCDD3_MARK, PSB5_PSB4_FN1, PTM3_FN),
- PINMUX_DATA(DV_D3_MARK, PSB5_PSB4_FN2, PTM3_FN),
- PINMUX_DATA(LCDD2_MARK, PSB5_PSB4_FN1, PTM2_FN),
- PINMUX_DATA(DV_D2_MARK, PSB5_PSB4_FN2, PTM2_FN),
- PINMUX_DATA(LCDD1_MARK, PSB5_PSB4_FN1, PTM1_FN),
- PINMUX_DATA(DV_D1_MARK, PSB5_PSB4_FN2, PTM1_FN),
- PINMUX_DATA(LCDD0_MARK, PSB5_PSB4_FN1, PTM0_FN),
- PINMUX_DATA(DV_D0_MARK, PSB5_PSB4_FN2, PTM0_FN),
-
- /* PTN FN */
- PINMUX_DATA(LCDD23_MARK, PSB3_PSB2_FN1, PTN7_FN),
- PINMUX_DATA(SCIF5_PTN_SCK_MARK, PSB3_PSB2_FN2, PTN7_FN),
- PINMUX_DATA(LCDD22_MARK, PSB3_PSB2_FN1, PTN6_FN),
- PINMUX_DATA(SCIF5_PTN_RXD_MARK, PSB3_PSB2_FN2, PTN6_FN),
- PINMUX_DATA(LCDD21_MARK, PSB3_PSB2_FN1, PTN5_FN),
- PINMUX_DATA(SCIF5_PTN_TXD_MARK, PSB3_PSB2_FN2, PTN5_FN),
- PINMUX_DATA(LCDD20_MARK, PSB3_PSB2_FN1, PTN4_FN),
- PINMUX_DATA(SCIF4_PTN_SCK_MARK, PSB3_PSB2_FN2, PTN4_FN),
- PINMUX_DATA(LCDD19_MARK, PSB3_PSB2_FN1, PTN3_FN),
- PINMUX_DATA(SCIF4_PTN_RXD_MARK, PSB3_PSB2_FN2, PTN3_FN),
- PINMUX_DATA(LCDD18_MARK, PSB3_PSB2_FN1, PTN2_FN),
- PINMUX_DATA(SCIF4_PTN_TXD_MARK, PSB3_PSB2_FN2, PTN2_FN),
- PINMUX_DATA(LCDD17_MARK, PSB5_PSB4_FN1, PTN1_FN),
- PINMUX_DATA(DV_VSYNC_MARK, PSB5_PSB4_FN2, PTN1_FN),
- PINMUX_DATA(LCDD16_MARK, PSB5_PSB4_FN1, PTN0_FN),
- PINMUX_DATA(DV_HSYNC_MARK, PSB5_PSB4_FN2, PTN0_FN),
-
- /* PTQ FN */
- PINMUX_DATA(AN3_MARK, PTQ3_FN),
- PINMUX_DATA(AN2_MARK, PTQ2_FN),
- PINMUX_DATA(AN1_MARK, PTQ1_FN),
- PINMUX_DATA(AN0_MARK, PTQ0_FN),
-
- /* PTR FN */
- PINMUX_DATA(CS6B_CE1B_MARK, PTR7_FN),
- PINMUX_DATA(CS6A_CE2B_MARK, PTR6_FN),
- PINMUX_DATA(CS5B_CE1A_MARK, PTR5_FN),
- PINMUX_DATA(CS5A_CE2A_MARK, PTR4_FN),
- PINMUX_DATA(IOIS16_MARK, PSA13_PSA12_FN1, PTR3_FN),
- PINMUX_DATA(LCDLCLK_PTR_MARK, PSA13_PSA12_FN2, PTR3_FN),
- PINMUX_DATA(WAIT_MARK, PTR2_FN),
- PINMUX_DATA(WE3_ICIOWR_MARK, PTR1_FN),
- PINMUX_DATA(WE2_ICIORD_MARK, PTR0_FN),
-
- /* PTS FN */
- PINMUX_DATA(SCIF1_PTS_SCK_MARK, PSC15_PSC14_FN1, PTS7_FN),
- PINMUX_DATA(SDHI0CD_PTS_MARK, PSC15_PSC14_FN2, PTS7_FN),
- PINMUX_DATA(SCIF1_PTS_RXD_MARK, PSC15_PSC14_FN1, PTS6_FN),
- PINMUX_DATA(SDHI0WP_PTS_MARK, PSC15_PSC14_FN2, PTS6_FN),
- PINMUX_DATA(SCIF1_PTS_TXD_MARK, PSC15_PSC14_FN1, PTS5_FN),
- PINMUX_DATA(SDHI0D3_PTS_MARK, PSC15_PSC14_FN2, PTS5_FN),
- PINMUX_DATA(SCIF3_PTS_CTS_MARK, PSC15_PSC14_FN1, PTS4_FN),
- PINMUX_DATA(SDHI0D2_PTS_MARK, PSC15_PSC14_FN2, PTS4_FN),
- PINMUX_DATA(SCIF3_PTS_RTS_MARK, PSC15_PSC14_FN1, PTS3_FN),
- PINMUX_DATA(SDHI0D1_PTS_MARK, PSC15_PSC14_FN2, PTS3_FN),
- PINMUX_DATA(SCIF3_PTS_SCK_MARK, PSC15_PSC14_FN1, PTS2_FN),
- PINMUX_DATA(SDHI0D0_PTS_MARK, PSC15_PSC14_FN2, PTS2_FN),
- PINMUX_DATA(SCIF3_PTS_RXD_MARK, PSC15_PSC14_FN1, PTS1_FN),
- PINMUX_DATA(SDHI0CMD_PTS_MARK, PSC15_PSC14_FN2, PTS1_FN),
- PINMUX_DATA(SCIF3_PTS_TXD_MARK, PSC15_PSC14_FN1, PTS0_FN),
- PINMUX_DATA(SDHI0CLK_PTS_MARK, PSC15_PSC14_FN2, PTS0_FN),
-
- /* PTT FN */
- PINMUX_DATA(SCIF0_PTT_SCK_MARK, PSC13_PSC12_FN1, PTT5_FN),
- PINMUX_DATA(MSIOF0_PTT_TSCK_MARK, PSC13_PSC12_FN2, PTT5_FN),
- PINMUX_DATA(SCIF0_PTT_RXD_MARK, PSC13_PSC12_FN1, PTT4_FN),
- PINMUX_DATA(MSIOF0_PTT_RXD_MARK, PSC13_PSC12_FN2, PTT4_FN),
- PINMUX_DATA(SCIF0_PTT_TXD_MARK, PSC13_PSC12_FN1, PTT3_FN),
- PINMUX_DATA(MSIOF0_PTT_TXD_MARK, PSC13_PSC12_FN2, PTT3_FN),
- PINMUX_DATA(SCIF2_PTT_SCK_MARK, PSC11_PSC10_FN1, PTT2_FN),
- PINMUX_DATA(MSIOF0_PTT_TSYNC_MARK, PSC11_PSC10_FN2, PTT2_FN),
- PINMUX_DATA(SCIF2_PTT_RXD_MARK, PSC11_PSC10_FN1, PTT1_FN),
- PINMUX_DATA(MSIOF0_PTT_SS1_MARK, PSC11_PSC10_FN2, PTT1_FN),
- PINMUX_DATA(MSIOF0_PTT_RSCK_MARK, PSC11_PSC10_FN3, PTT1_FN),
- PINMUX_DATA(SCIF2_PTT_TXD_MARK, PSC11_PSC10_FN1, PTT0_FN),
- PINMUX_DATA(MSIOF0_PTT_SS2_MARK, PSC11_PSC10_FN2, PTT0_FN),
- PINMUX_DATA(MSIOF0_PTT_RSYNC_MARK, PSC11_PSC10_FN3, PTT0_FN),
-
- /* PTU FN */
- PINMUX_DATA(FCDE_MARK, PSC9_PSC8_FN1, PTU5_FN),
- PINMUX_DATA(SCIF0_PTU_SCK_MARK, PSC9_PSC8_FN2, PTU5_FN),
- PINMUX_DATA(FSC_MARK, PSC9_PSC8_FN1, PTU4_FN),
- PINMUX_DATA(SCIF0_PTU_RXD_MARK, PSC9_PSC8_FN2, PTU4_FN),
- PINMUX_DATA(FWE_MARK, PSC9_PSC8_FN1, PTU3_FN),
- PINMUX_DATA(SCIF0_PTU_TXD_MARK, PSC9_PSC8_FN2, PTU3_FN),
- PINMUX_DATA(FOE_MARK, PSC7_PSC6_FN1, PTU2_FN),
- PINMUX_DATA(SCIF2_PTU_SCK_MARK, PSC7_PSC6_FN2, PTU2_FN),
- PINMUX_DATA(VIO_VD2_MARK, PSC7_PSC6_FN3, PTU2_FN),
- PINMUX_DATA(FRB_MARK, PSC7_PSC6_FN1, PTU1_FN),
- PINMUX_DATA(SCIF2_PTU_RXD_MARK, PSC7_PSC6_FN2, PTU1_FN),
- PINMUX_DATA(VIO_CLK2_MARK, PSC7_PSC6_FN3, PTU1_FN),
- PINMUX_DATA(FCE_MARK, PSC7_PSC6_FN1, PTU0_FN),
- PINMUX_DATA(SCIF2_PTU_TXD_MARK, PSC7_PSC6_FN2, PTU0_FN),
- PINMUX_DATA(VIO_HD2_MARK, PSC7_PSC6_FN3, PTU0_FN),
-
- /* PTV FN */
- PINMUX_DATA(NAF7_MARK, PSC7_PSC6_FN1, PTV7_FN),
- PINMUX_DATA(SCIF1_PTV_SCK_MARK, PSC7_PSC6_FN2, PTV7_FN),
- PINMUX_DATA(VIO_D15_MARK, PSC7_PSC6_FN3, PTV7_FN),
- PINMUX_DATA(NAF6_MARK, PSC7_PSC6_FN1, PTV6_FN),
- PINMUX_DATA(SCIF1_PTV_RXD_MARK, PSC7_PSC6_FN2, PTV6_FN),
- PINMUX_DATA(VIO_D14_MARK, PSC7_PSC6_FN3, PTV6_FN),
- PINMUX_DATA(NAF5_MARK, PSC7_PSC6_FN1, PTV5_FN),
- PINMUX_DATA(SCIF1_PTV_TXD_MARK, PSC7_PSC6_FN2, PTV5_FN),
- PINMUX_DATA(VIO_D13_MARK, PSC7_PSC6_FN3, PTV5_FN),
- PINMUX_DATA(NAF4_MARK, PSC7_PSC6_FN1, PTV4_FN),
- PINMUX_DATA(SCIF3_PTV_CTS_MARK, PSC7_PSC6_FN2, PTV4_FN),
- PINMUX_DATA(VIO_D12_MARK, PSC7_PSC6_FN3, PTV4_FN),
- PINMUX_DATA(NAF3_MARK, PSC7_PSC6_FN1, PTV3_FN),
- PINMUX_DATA(SCIF3_PTV_RTS_MARK, PSC7_PSC6_FN2, PTV3_FN),
- PINMUX_DATA(VIO_D11_MARK, PSC7_PSC6_FN3, PTV3_FN),
- PINMUX_DATA(NAF2_MARK, PSC7_PSC6_FN1, PTV2_FN),
- PINMUX_DATA(SCIF3_PTV_SCK_MARK, PSC7_PSC6_FN2, PTV2_FN),
- PINMUX_DATA(VIO_D10_MARK, PSC7_PSC6_FN3, PTV2_FN),
- PINMUX_DATA(NAF1_MARK, PSC7_PSC6_FN1, PTV1_FN),
- PINMUX_DATA(SCIF3_PTV_RXD_MARK, PSC7_PSC6_FN2, PTV1_FN),
- PINMUX_DATA(VIO_D9_MARK, PSC7_PSC6_FN3, PTV1_FN),
- PINMUX_DATA(NAF0_MARK, PSC7_PSC6_FN1, PTV0_FN),
- PINMUX_DATA(SCIF3_PTV_TXD_MARK, PSC7_PSC6_FN2, PTV0_FN),
- PINMUX_DATA(VIO_D8_MARK, PSC7_PSC6_FN3, PTV0_FN),
-
- /* PTW FN */
- PINMUX_DATA(IRQ7_MARK, PTW7_FN),
- PINMUX_DATA(IRQ6_MARK, PTW6_FN),
- PINMUX_DATA(IRQ5_MARK, PTW5_FN),
- PINMUX_DATA(IRQ4_MARK, PSD15_PSD14_FN1, PTW4_FN),
- PINMUX_DATA(LCDLCLK_PTW_MARK, PSD15_PSD14_FN2, PTW4_FN),
- PINMUX_DATA(IRQ3_MARK, PSD13_PSD12_FN1, PTW3_FN),
- PINMUX_DATA(ADTRG_MARK, PSD13_PSD12_FN2, PTW3_FN),
- PINMUX_DATA(IRQ2_MARK, PSD11_PSD10_FN1, PTW2_FN),
- PINMUX_DATA(BS_MARK, PSD11_PSD10_FN2, PTW2_FN),
- PINMUX_DATA(VIO_CKO_MARK, PSD11_PSD10_FN3, PTW2_FN),
- PINMUX_DATA(IRQ1_MARK, PSD9_PSD8_FN1, PTW1_FN),
- PINMUX_DATA(SIUAISPD_MARK, PSD9_PSD8_FN2, PTW1_FN),
- PINMUX_DATA(IRQ0_MARK, PSD7_PSD6_FN1, PTW0_FN),
- PINMUX_DATA(SIUAOSPD_MARK, PSD7_PSD6_FN2, PTW0_FN),
-
- /* PTX FN */
- PINMUX_DATA(DACK1_MARK, PTX7_FN),
- PINMUX_DATA(DREQ1_MARK, PSD3_PSD2_FN1, PTX6_FN),
- PINMUX_DATA(MSIOF0_PTX_MCK_MARK, PSD3_PSD2_FN2, PTX6_FN),
- PINMUX_DATA(DACK1_MARK, PTX5_FN),
- PINMUX_DATA(IRDA_OUT_MARK, PSD5_PSD4_FN2, PTX5_FN),
- PINMUX_DATA(DREQ1_MARK, PTX4_FN),
- PINMUX_DATA(IRDA_IN_MARK, PSD5_PSD4_FN2, PTX4_FN),
- PINMUX_DATA(TS0_SDAT_MARK, PTX3_FN),
- PINMUX_DATA(TS0_SCK_MARK, PTX2_FN),
- PINMUX_DATA(TS0_SDEN_MARK, PTX1_FN),
- PINMUX_DATA(TS0_SPSYNC_MARK, PTX0_FN),
-
- /* PTY FN */
- PINMUX_DATA(VIO_D7_MARK, PTY7_FN),
- PINMUX_DATA(VIO_D6_MARK, PTY6_FN),
- PINMUX_DATA(VIO_D5_MARK, PTY5_FN),
- PINMUX_DATA(VIO_D4_MARK, PTY4_FN),
- PINMUX_DATA(VIO_D3_MARK, PTY3_FN),
- PINMUX_DATA(VIO_D2_MARK, PTY2_FN),
- PINMUX_DATA(VIO_D1_MARK, PTY1_FN),
- PINMUX_DATA(VIO_D0_MARK, PTY0_FN),
-
- /* PTZ FN */
- PINMUX_DATA(SIUBOBT_MARK, PTZ7_FN),
- PINMUX_DATA(SIUBOLR_MARK, PTZ6_FN),
- PINMUX_DATA(SIUBOSLD_MARK, PTZ5_FN),
- PINMUX_DATA(SIUBMCK_MARK, PTZ4_FN),
- PINMUX_DATA(VIO_FLD_MARK, PSD1_PSD0_FN1, PTZ3_FN),
- PINMUX_DATA(SIUBFCK_MARK, PSD1_PSD0_FN2, PTZ3_FN),
- PINMUX_DATA(VIO_HD1_MARK, PSD1_PSD0_FN1, PTZ2_FN),
- PINMUX_DATA(SIUBILR_MARK, PSD1_PSD0_FN2, PTZ2_FN),
- PINMUX_DATA(VIO_VD1_MARK, PSD1_PSD0_FN1, PTZ1_FN),
- PINMUX_DATA(SIUBIBT_MARK, PSD1_PSD0_FN2, PTZ1_FN),
- PINMUX_DATA(VIO_CLK1_MARK, PSD1_PSD0_FN1, PTZ0_FN),
- PINMUX_DATA(SIUBISLD_MARK, PSD1_PSD0_FN2, PTZ0_FN),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
- /* PTA */
- PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
- PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
- PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
- PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
- PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
- PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
- PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
- PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
-
- /* PTB */
- PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
- PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
- PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
- PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
- PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
- PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
- PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
- PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
-
- /* PTC */
- PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
- PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
- PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
- PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
- PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
- PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
- PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
- PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
-
- /* PTD */
- PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
- PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
- PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
- PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
- PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
- PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
- PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
- PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
-
- /* PTE */
- PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
- PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
- PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
- PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
- PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
- PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
-
- /* PTF */
- PINMUX_GPIO(GPIO_PTF7, PTF7_DATA),
- PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
- PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
- PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
- PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
- PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
- PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
- PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
-
- /* PTG */
- PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
- PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
- PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
- PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
- PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
- PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
-
- /* PTH */
- PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
- PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
- PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
- PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
- PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
- PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
- PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
- PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
-
- /* PTJ */
- PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
- PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
- PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
- PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
- PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
- PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
-
- /* PTK */
- PINMUX_GPIO(GPIO_PTK7, PTK7_DATA),
- PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
- PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
- PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
- PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
- PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
- PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
- PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
-
- /* PTL */
- PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
- PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
- PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
- PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
- PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
- PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
- PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
- PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
-
- /* PTM */
- PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
- PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
- PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
- PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
- PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
- PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
- PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
- PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
-
- /* PTN */
- PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
- PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
- PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
- PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
- PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
- PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
- PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
- PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
-
- /* PTQ */
- PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
- PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
- PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
- PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
-
- /* PTR */
- PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
- PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
- PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
- PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
- PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
- PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
- PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
- PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
-
- /* PTS */
- PINMUX_GPIO(GPIO_PTS7, PTS7_DATA),
- PINMUX_GPIO(GPIO_PTS6, PTS6_DATA),
- PINMUX_GPIO(GPIO_PTS5, PTS5_DATA),
- PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
- PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
- PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
- PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
- PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
-
- /* PTT */
- PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
- PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
- PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
- PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
- PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
- PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
-
- /* PTU */
- PINMUX_GPIO(GPIO_PTU5, PTU5_DATA),
- PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
- PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
- PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
- PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
- PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
-
- /* PTV */
- PINMUX_GPIO(GPIO_PTV7, PTV7_DATA),
- PINMUX_GPIO(GPIO_PTV6, PTV6_DATA),
- PINMUX_GPIO(GPIO_PTV5, PTV5_DATA),
- PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
- PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
- PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
- PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
- PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
-
- /* PTW */
- PINMUX_GPIO(GPIO_PTW7, PTW7_DATA),
- PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
- PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
- PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
- PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
- PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
- PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
- PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
-
- /* PTX */
- PINMUX_GPIO(GPIO_PTX7, PTX7_DATA),
- PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
- PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
- PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
- PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
- PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
- PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
- PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
-
- /* PTY */
- PINMUX_GPIO(GPIO_PTY7, PTY7_DATA),
- PINMUX_GPIO(GPIO_PTY6, PTY6_DATA),
- PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
- PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
- PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
- PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
- PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
- PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
-
- /* PTZ */
- PINMUX_GPIO(GPIO_PTZ7, PTZ7_DATA),
- PINMUX_GPIO(GPIO_PTZ6, PTZ6_DATA),
- PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
- PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
- PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
- PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
- PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
- PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
-
- /* SCIF0 */
- PINMUX_GPIO(GPIO_FN_SCIF0_PTT_TXD, SCIF0_PTT_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_PTT_RXD, SCIF0_PTT_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_PTT_SCK, SCIF0_PTT_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_PTU_TXD, SCIF0_PTU_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_PTU_RXD, SCIF0_PTU_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_PTU_SCK, SCIF0_PTU_SCK_MARK),
-
- /* SCIF1 */
- PINMUX_GPIO(GPIO_FN_SCIF1_PTS_TXD, SCIF1_PTS_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_PTS_RXD, SCIF1_PTS_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_PTS_SCK, SCIF1_PTS_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_PTV_TXD, SCIF1_PTV_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_PTV_RXD, SCIF1_PTV_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_PTV_SCK, SCIF1_PTV_SCK_MARK),
-
- /* SCIF2 */
- PINMUX_GPIO(GPIO_FN_SCIF2_PTT_TXD, SCIF2_PTT_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_PTT_RXD, SCIF2_PTT_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_PTT_SCK, SCIF2_PTT_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_PTU_TXD, SCIF2_PTU_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_PTU_RXD, SCIF2_PTU_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_PTU_SCK, SCIF2_PTU_SCK_MARK),
-
- /* SCIF3 */
- PINMUX_GPIO(GPIO_FN_SCIF3_PTS_TXD, SCIF3_PTS_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_PTS_RXD, SCIF3_PTS_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_PTS_SCK, SCIF3_PTS_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_PTS_RTS, SCIF3_PTS_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_PTS_CTS, SCIF3_PTS_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_PTV_TXD, SCIF3_PTV_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_PTV_RXD, SCIF3_PTV_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_PTV_SCK, SCIF3_PTV_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_PTV_RTS, SCIF3_PTV_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_PTV_CTS, SCIF3_PTV_CTS_MARK),
-
- /* SCIF4 */
- PINMUX_GPIO(GPIO_FN_SCIF4_PTE_TXD, SCIF4_PTE_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_PTE_RXD, SCIF4_PTE_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_PTE_SCK, SCIF4_PTE_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_PTN_TXD, SCIF4_PTN_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_PTN_RXD, SCIF4_PTN_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_PTN_SCK, SCIF4_PTN_SCK_MARK),
-
- /* SCIF5 */
- PINMUX_GPIO(GPIO_FN_SCIF5_PTE_TXD, SCIF5_PTE_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_PTE_RXD, SCIF5_PTE_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_PTE_SCK, SCIF5_PTE_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_PTN_TXD, SCIF5_PTN_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_PTN_RXD, SCIF5_PTN_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_PTN_SCK, SCIF5_PTN_SCK_MARK),
-
- /* CEU */
- PINMUX_GPIO(GPIO_FN_VIO_D15, VIO_D15_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D14, VIO_D14_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D13, VIO_D13_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D12, VIO_D12_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D11, VIO_D11_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D10, VIO_D10_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D9, VIO_D9_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D8, VIO_D8_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D7, VIO_D7_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D6, VIO_D6_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D5, VIO_D5_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D4, VIO_D4_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D3, VIO_D3_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D2, VIO_D2_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D1, VIO_D1_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_D0, VIO_D0_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_CLK1, VIO_CLK1_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_VD1, VIO_VD1_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_HD1, VIO_HD1_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_FLD, VIO_FLD_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_CKO, VIO_CKO_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_VD2, VIO_VD2_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_HD2, VIO_HD2_MARK),
- PINMUX_GPIO(GPIO_FN_VIO_CLK2, VIO_CLK2_MARK),
-
- /* LCDC */
- PINMUX_GPIO(GPIO_FN_LCDD23, LCDD23_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD22, LCDD22_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD21, LCDD21_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD20, LCDD20_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD19, LCDD19_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD18, LCDD18_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD17, LCDD17_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD16, LCDD16_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD15, LCDD15_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD14, LCDD14_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD13, LCDD13_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD12, LCDD12_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD11, LCDD11_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD10, LCDD10_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD9, LCDD9_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD8, LCDD8_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD7, LCDD7_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD6, LCDD6_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD5, LCDD5_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD4, LCDD4_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD3, LCDD3_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD2, LCDD2_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD1, LCDD1_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD0, LCDD0_MARK),
- PINMUX_GPIO(GPIO_FN_LCDLCLK_PTR, LCDLCLK_PTR_MARK),
- PINMUX_GPIO(GPIO_FN_LCDLCLK_PTW, LCDLCLK_PTW_MARK),
- /* Main LCD */
- PINMUX_GPIO(GPIO_FN_LCDDON, LCDDON_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVCPWC, LCDVCPWC_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVEPWC, LCDVEPWC_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVSYN, LCDVSYN_MARK),
- /* Main LCD - RGB Mode */
- PINMUX_GPIO(GPIO_FN_LCDDCK, LCDDCK_MARK),
- PINMUX_GPIO(GPIO_FN_LCDHSYN, LCDHSYN_MARK),
- PINMUX_GPIO(GPIO_FN_LCDDISP, LCDDISP_MARK),
- /* Main LCD - SYS Mode */
- PINMUX_GPIO(GPIO_FN_LCDRS, LCDRS_MARK),
- PINMUX_GPIO(GPIO_FN_LCDCS, LCDCS_MARK),
- PINMUX_GPIO(GPIO_FN_LCDWR, LCDWR_MARK),
- PINMUX_GPIO(GPIO_FN_LCDRD, LCDRD_MARK),
-
- /* IRQ */
- PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3, IRQ3_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ4, IRQ4_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ6, IRQ6_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ7, IRQ7_MARK),
-
- /* AUD */
- PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
- PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
-
- /* SDHI0 (PTD) */
- PINMUX_GPIO(GPIO_FN_SDHI0CD_PTD, SDHI0CD_PTD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0WP_PTD, SDHI0WP_PTD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D3_PTD, SDHI0D3_PTD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D2_PTD, SDHI0D2_PTD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D1_PTD, SDHI0D1_PTD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D0_PTD, SDHI0D0_PTD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0CMD_PTD, SDHI0CMD_PTD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0CLK_PTD, SDHI0CLK_PTD_MARK),
-
- /* SDHI0 (PTS) */
- PINMUX_GPIO(GPIO_FN_SDHI0CD_PTS, SDHI0CD_PTS_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0WP_PTS, SDHI0WP_PTS_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D3_PTS, SDHI0D3_PTS_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D2_PTS, SDHI0D2_PTS_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D1_PTS, SDHI0D1_PTS_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D0_PTS, SDHI0D0_PTS_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0CMD_PTS, SDHI0CMD_PTS_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0CLK_PTS, SDHI0CLK_PTS_MARK),
-
- /* SDHI1 */
- PINMUX_GPIO(GPIO_FN_SDHI1CD, SDHI1CD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1WP, SDHI1WP_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1D3, SDHI1D3_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1D2, SDHI1D2_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1D1, SDHI1D1_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1D0, SDHI1D0_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1CMD, SDHI1CMD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1CLK, SDHI1CLK_MARK),
-
- /* SIUA */
- PINMUX_GPIO(GPIO_FN_SIUAFCK, SIUAFCK_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAILR, SIUAILR_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAIBT, SIUAIBT_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAISLD, SIUAISLD_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAOLR, SIUAOLR_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAOBT, SIUAOBT_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAOSLD, SIUAOSLD_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAMCK, SIUAMCK_MARK),
- PINMUX_GPIO(GPIO_FN_SIUAISPD, SIUAISPD_MARK),
- PINMUX_GPIO(GPIO_FN_SIUOSPD, SIUAOSPD_MARK),
-
- /* SIUB */
- PINMUX_GPIO(GPIO_FN_SIUBFCK, SIUBFCK_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBILR, SIUBILR_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBIBT, SIUBIBT_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBISLD, SIUBISLD_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBOLR, SIUBOLR_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBOBT, SIUBOBT_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBOSLD, SIUBOSLD_MARK),
- PINMUX_GPIO(GPIO_FN_SIUBMCK, SIUBMCK_MARK),
-
- /* IRDA */
- PINMUX_GPIO(GPIO_FN_IRDA_IN, IRDA_IN_MARK),
- PINMUX_GPIO(GPIO_FN_IRDA_OUT, IRDA_OUT_MARK),
-
- /* VOU */
- PINMUX_GPIO(GPIO_FN_DV_CLKI, DV_CLKI_MARK),
- PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D15, DV_D15_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D14, DV_D14_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D13, DV_D13_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D12, DV_D12_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D11, DV_D11_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D10, DV_D10_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D9, DV_D9_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D8, DV_D8_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D7, DV_D7_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D6, DV_D6_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D5, DV_D5_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D4, DV_D4_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D3, DV_D3_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D2, DV_D2_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D1, DV_D1_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D0, DV_D0_MARK),
-
- /* KEYSC */
- PINMUX_GPIO(GPIO_FN_KEYIN0, KEYIN0_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN1, KEYIN1_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN2, KEYIN2_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN3, KEYIN3_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN4, KEYIN4_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT0, KEYOUT0_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT1, KEYOUT1_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT2, KEYOUT2_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT3, KEYOUT3_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT4_IN6, KEYOUT4_IN6_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT5_IN5, KEYOUT5_IN5_MARK),
-
- /* MSIOF0 (PTF) */
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_TXD, MSIOF0_PTF_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_RXD, MSIOF0_PTF_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_MCK, MSIOF0_PTF_MCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_TSYNC, MSIOF0_PTF_TSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_TSCK, MSIOF0_PTF_TSCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_RSYNC, MSIOF0_PTF_RSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_RSCK, MSIOF0_PTF_RSCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_SS1, MSIOF0_PTF_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_SS2, MSIOF0_PTF_SS2_MARK),
-
- /* MSIOF0 (PTT+PTX) */
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_TXD, MSIOF0_PTT_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_RXD, MSIOF0_PTT_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTX_MCK, MSIOF0_PTX_MCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_TSYNC, MSIOF0_PTT_TSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_TSCK, MSIOF0_PTT_TSCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_RSYNC, MSIOF0_PTT_RSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_RSCK, MSIOF0_PTT_RSCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_SS1, MSIOF0_PTT_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_SS2, MSIOF0_PTT_SS2_MARK),
-
- /* MSIOF1 */
- PINMUX_GPIO(GPIO_FN_MSIOF1_TXD, MSIOF1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_RXD, MSIOF1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_MCK, MSIOF1_MCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_TSYNC, MSIOF1_TSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_TSCK, MSIOF1_TSCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_RSYNC, MSIOF1_RSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_RSCK, MSIOF1_RSCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_SS1, MSIOF1_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_SS2, MSIOF1_SS2_MARK),
-
- /* TSIF */
- PINMUX_GPIO(GPIO_FN_TS0_SDAT, TS0_SDAT_MARK),
- PINMUX_GPIO(GPIO_FN_TS0_SCK, TS0_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_TS0_SDEN, TS0_SDEN_MARK),
- PINMUX_GPIO(GPIO_FN_TS0_SPSYNC, TS0_SPSYNC_MARK),
-
- /* FLCTL */
- PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
- PINMUX_GPIO(GPIO_FN_NAF7, NAF7_MARK),
- PINMUX_GPIO(GPIO_FN_NAF6, NAF6_MARK),
- PINMUX_GPIO(GPIO_FN_NAF5, NAF5_MARK),
- PINMUX_GPIO(GPIO_FN_NAF4, NAF4_MARK),
- PINMUX_GPIO(GPIO_FN_NAF3, NAF3_MARK),
- PINMUX_GPIO(GPIO_FN_NAF2, NAF2_MARK),
- PINMUX_GPIO(GPIO_FN_NAF1, NAF1_MARK),
- PINMUX_GPIO(GPIO_FN_NAF0, NAF0_MARK),
- PINMUX_GPIO(GPIO_FN_FCDE, FCDE_MARK),
- PINMUX_GPIO(GPIO_FN_FOE, FOE_MARK),
- PINMUX_GPIO(GPIO_FN_FSC, FSC_MARK),
- PINMUX_GPIO(GPIO_FN_FWE, FWE_MARK),
- PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
-
- /* DMAC */
- PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
-
- /* ADC */
- PINMUX_GPIO(GPIO_FN_AN3, AN3_MARK),
- PINMUX_GPIO(GPIO_FN_AN2, AN2_MARK),
- PINMUX_GPIO(GPIO_FN_AN1, AN1_MARK),
- PINMUX_GPIO(GPIO_FN_AN0, AN0_MARK),
- PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
-
- /* CPG */
- PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
- PINMUX_GPIO(GPIO_FN_PDSTATUS, PDSTATUS_MARK),
-
- /* TPU */
- PINMUX_GPIO(GPIO_FN_TPUTO0, TPUTO0_MARK),
- PINMUX_GPIO(GPIO_FN_TPUTO1, TPUTO1_MARK),
- PINMUX_GPIO(GPIO_FN_TPUTO2, TPUTO2_MARK),
- PINMUX_GPIO(GPIO_FN_TPUTO3, TPUTO3_MARK),
-
- /* BSC */
- PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
- PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
- PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
- PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
- PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
- PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
- PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
- PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
- PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
- PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
- PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
- PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
- PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
- PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
- PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
- PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
- PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
- PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
- PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
- PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
- PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
- PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
- PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
- PINMUX_GPIO(GPIO_FN_CS6B_CE1B, CS6B_CE1B_MARK),
- PINMUX_GPIO(GPIO_FN_CS6A_CE2B, CS6A_CE2B_MARK),
- PINMUX_GPIO(GPIO_FN_CS5B_CE1A, CS5B_CE1A_MARK),
- PINMUX_GPIO(GPIO_FN_CS5A_CE2A, CS5A_CE2A_MARK),
- PINMUX_GPIO(GPIO_FN_WE3_ICIOWR, WE3_ICIOWR_MARK),
- PINMUX_GPIO(GPIO_FN_WE2_ICIORD, WE2_ICIORD_MARK),
-
- /* ATAPI */
- PINMUX_GPIO(GPIO_FN_IDED15, IDED15_MARK),
- PINMUX_GPIO(GPIO_FN_IDED14, IDED14_MARK),
- PINMUX_GPIO(GPIO_FN_IDED13, IDED13_MARK),
- PINMUX_GPIO(GPIO_FN_IDED12, IDED12_MARK),
- PINMUX_GPIO(GPIO_FN_IDED11, IDED11_MARK),
- PINMUX_GPIO(GPIO_FN_IDED10, IDED10_MARK),
- PINMUX_GPIO(GPIO_FN_IDED9, IDED9_MARK),
- PINMUX_GPIO(GPIO_FN_IDED8, IDED8_MARK),
- PINMUX_GPIO(GPIO_FN_IDED7, IDED7_MARK),
- PINMUX_GPIO(GPIO_FN_IDED6, IDED6_MARK),
- PINMUX_GPIO(GPIO_FN_IDED5, IDED5_MARK),
- PINMUX_GPIO(GPIO_FN_IDED4, IDED4_MARK),
- PINMUX_GPIO(GPIO_FN_IDED3, IDED3_MARK),
- PINMUX_GPIO(GPIO_FN_IDED2, IDED2_MARK),
- PINMUX_GPIO(GPIO_FN_IDED1, IDED1_MARK),
- PINMUX_GPIO(GPIO_FN_IDED0, IDED0_MARK),
- PINMUX_GPIO(GPIO_FN_DIRECTION, DIRECTION_MARK),
- PINMUX_GPIO(GPIO_FN_EXBUF_ENB, EXBUF_ENB_MARK),
- PINMUX_GPIO(GPIO_FN_IDERST, IDERST_MARK),
- PINMUX_GPIO(GPIO_FN_IODACK, IODACK_MARK),
- PINMUX_GPIO(GPIO_FN_IODREQ, IODREQ_MARK),
- PINMUX_GPIO(GPIO_FN_IDEIORDY, IDEIORDY_MARK),
- PINMUX_GPIO(GPIO_FN_IDEINT, IDEINT_MARK),
- PINMUX_GPIO(GPIO_FN_IDEIOWR, IDEIOWR_MARK),
- PINMUX_GPIO(GPIO_FN_IDEIORD, IDEIORD_MARK),
- PINMUX_GPIO(GPIO_FN_IDECS1, IDECS1_MARK),
- PINMUX_GPIO(GPIO_FN_IDECS0, IDECS0_MARK),
- PINMUX_GPIO(GPIO_FN_IDEA2, IDEA2_MARK),
- PINMUX_GPIO(GPIO_FN_IDEA1, IDEA1_MARK),
- PINMUX_GPIO(GPIO_FN_IDEA0, IDEA0_MARK),
- };
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- { PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
- PTA7_FN, PTA7_OUT, 0, PTA7_IN,
- PTA6_FN, PTA6_OUT, 0, PTA6_IN,
- PTA5_FN, PTA5_OUT, 0, PTA5_IN,
- PTA4_FN, PTA4_OUT, PTA4_IN_PU, PTA4_IN,
- PTA3_FN, PTA3_OUT, PTA3_IN_PU, PTA3_IN,
- PTA2_FN, PTA2_OUT, PTA2_IN_PU, PTA2_IN,
- PTA1_FN, PTA1_OUT, PTA1_IN_PU, PTA1_IN,
- PTA0_FN, PTA0_OUT, PTA0_IN_PU, PTA0_IN }
- },
- { PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
- PTB7_FN, PTB7_OUT, 0, PTB7_IN,
- PTB6_FN, PTB6_OUT, 0, PTB6_IN,
- PTB5_FN, PTB5_OUT, 0, PTB5_IN,
- PTB4_FN, PTB4_OUT, 0, PTB4_IN,
- PTB3_FN, PTB3_OUT, 0, PTB3_IN,
- PTB2_FN, PTB2_OUT, PTB2_IN_PU, PTB2_IN,
- PTB1_FN, PTB1_OUT, PTB1_IN_PU, PTB1_IN,
- PTB0_FN, PTB0_OUT, 0, PTB0_IN }
- },
- { PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
- PTC7_FN, PTC7_OUT, 0, PTC7_IN,
- PTC6_FN, PTC6_OUT, 0, PTC6_IN,
- PTC5_FN, PTC5_OUT, 0, PTC5_IN,
- PTC4_FN, PTC4_OUT, 0, PTC4_IN,
- PTC3_FN, PTC3_OUT, 0, PTC3_IN,
- PTC2_FN, PTC2_OUT, 0, PTC2_IN,
- PTC1_FN, PTC1_OUT, 0, PTC1_IN,
- PTC0_FN, PTC0_OUT, 0, PTC0_IN }
- },
- { PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
- PTD7_FN, PTD7_OUT, 0, PTD7_IN,
- PTD6_FN, PTD6_OUT, 0, PTD6_IN,
- PTD5_FN, PTD5_OUT, 0, PTD5_IN,
- PTD4_FN, PTD4_OUT, 0, PTD4_IN,
- PTD3_FN, PTD3_OUT, 0, PTD3_IN,
- PTD2_FN, PTD2_OUT, 0, PTD2_IN,
- PTD1_FN, PTD1_OUT, 0, PTD1_IN,
- PTD0_FN, PTD0_OUT, 0, PTD0_IN }
- },
- { PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTE5_FN, PTE5_OUT, 0, PTE5_IN,
- PTE4_FN, PTE4_OUT, 0, PTE4_IN,
- PTE3_FN, PTE3_OUT, 0, PTE3_IN,
- PTE2_FN, PTE2_OUT, 0, PTE2_IN,
- PTE1_FN, PTE1_OUT, 0, PTE1_IN,
- PTE0_FN, PTE0_OUT, 0, PTE0_IN }
- },
- { PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
- PTF7_FN, PTF7_OUT, 0, PTF7_IN,
- PTF6_FN, PTF6_OUT, 0, PTF6_IN,
- PTF5_FN, PTF5_OUT, 0, PTF5_IN,
- PTF4_FN, PTF4_OUT, 0, PTF4_IN,
- PTF3_FN, PTF3_OUT, 0, PTF3_IN,
- PTF2_FN, PTF2_OUT, 0, PTF2_IN,
- PTF1_FN, PTF1_OUT, 0, PTF1_IN,
- PTF0_FN, PTF0_OUT, 0, PTF0_IN }
- },
- { PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTG5_FN, PTG5_OUT, 0, 0,
- PTG4_FN, PTG4_OUT, 0, 0,
- PTG3_FN, PTG3_OUT, 0, 0,
- PTG2_FN, PTG2_OUT, 0, 0,
- PTG1_FN, PTG1_OUT, 0, 0,
- PTG0_FN, PTG0_OUT, 0, 0 }
- },
- { PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
- PTH7_FN, PTH7_OUT, 0, PTH7_IN,
- PTH6_FN, PTH6_OUT, 0, PTH6_IN,
- PTH5_FN, PTH5_OUT, 0, PTH5_IN,
- PTH4_FN, PTH4_OUT, 0, PTH4_IN,
- PTH3_FN, PTH3_OUT, 0, PTH3_IN,
- PTH2_FN, PTH2_OUT, 0, PTH2_IN,
- PTH1_FN, PTH1_OUT, 0, PTH1_IN,
- PTH0_FN, PTH0_OUT, 0, PTH0_IN }
- },
- { PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
- PTJ7_FN, PTJ7_OUT, 0, 0,
- 0, 0, 0, 0,
- PTJ5_FN, PTJ5_OUT, 0, 0,
- 0, 0, 0, 0,
- PTJ3_FN, PTJ3_OUT, 0, PTJ3_IN,
- PTJ2_FN, PTJ2_OUT, 0, PTJ2_IN,
- PTJ1_FN, PTJ1_OUT, 0, PTJ1_IN,
- PTJ0_FN, PTJ0_OUT, 0, PTJ0_IN }
- },
- { PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
- PTK7_FN, PTK7_OUT, 0, PTK7_IN,
- PTK6_FN, PTK6_OUT, 0, PTK6_IN,
- PTK5_FN, PTK5_OUT, 0, PTK5_IN,
- PTK4_FN, PTK4_OUT, 0, PTK4_IN,
- PTK3_FN, PTK3_OUT, 0, PTK3_IN,
- PTK2_FN, PTK2_OUT, 0, PTK2_IN,
- PTK1_FN, PTK1_OUT, 0, PTK1_IN,
- PTK0_FN, PTK0_OUT, 0, PTK0_IN }
- },
- { PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
- PTL7_FN, PTL7_OUT, 0, PTL7_IN,
- PTL6_FN, PTL6_OUT, 0, PTL6_IN,
- PTL5_FN, PTL5_OUT, 0, PTL5_IN,
- PTL4_FN, PTL4_OUT, 0, PTL4_IN,
- PTL3_FN, PTL3_OUT, 0, PTL3_IN,
- PTL2_FN, PTL2_OUT, 0, PTL2_IN,
- PTL1_FN, PTL1_OUT, 0, PTL1_IN,
- PTL0_FN, PTL0_OUT, 0, PTL0_IN }
- },
- { PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
- PTM7_FN, PTM7_OUT, 0, PTM7_IN,
- PTM6_FN, PTM6_OUT, 0, PTM6_IN,
- PTM5_FN, PTM5_OUT, 0, PTM5_IN,
- PTM4_FN, PTM4_OUT, 0, PTM4_IN,
- PTM3_FN, PTM3_OUT, 0, PTM3_IN,
- PTM2_FN, PTM2_OUT, 0, PTM2_IN,
- PTM1_FN, PTM1_OUT, 0, PTM1_IN,
- PTM0_FN, PTM0_OUT, 0, PTM0_IN }
- },
- { PINMUX_CFG_REG("PNCR", 0xa4050118, 16, 2) {
- PTN7_FN, PTN7_OUT, 0, PTN7_IN,
- PTN6_FN, PTN6_OUT, 0, PTN6_IN,
- PTN5_FN, PTN5_OUT, 0, PTN5_IN,
- PTN4_FN, PTN4_OUT, 0, PTN4_IN,
- PTN3_FN, PTN3_OUT, 0, PTN3_IN,
- PTN2_FN, PTN2_OUT, 0, PTN2_IN,
- PTN1_FN, PTN1_OUT, 0, PTN1_IN,
- PTN0_FN, PTN0_OUT, 0, PTN0_IN }
- },
- { PINMUX_CFG_REG("PQCR", 0xa405011a, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTQ3_FN, 0, 0, PTQ3_IN,
- PTQ2_FN, 0, 0, PTQ2_IN,
- PTQ1_FN, 0, 0, PTQ1_IN,
- PTQ0_FN, 0, 0, PTQ0_IN }
- },
- { PINMUX_CFG_REG("PRCR", 0xa405011c, 16, 2) {
- PTR7_FN, PTR7_OUT, 0, PTR7_IN,
- PTR6_FN, PTR6_OUT, 0, PTR6_IN,
- PTR5_FN, PTR5_OUT, 0, PTR5_IN,
- PTR4_FN, PTR4_OUT, 0, PTR4_IN,
- PTR3_FN, 0, 0, PTR3_IN,
- PTR2_FN, 0, PTR2_IN_PU, PTR2_IN,
- PTR1_FN, PTR1_OUT, 0, PTR1_IN,
- PTR0_FN, PTR0_OUT, 0, PTR0_IN }
- },
- { PINMUX_CFG_REG("PSCR", 0xa405011e, 16, 2) {
- PTS7_FN, PTS7_OUT, 0, PTS7_IN,
- PTS6_FN, PTS6_OUT, 0, PTS6_IN,
- PTS5_FN, PTS5_OUT, 0, PTS5_IN,
- PTS4_FN, PTS4_OUT, 0, PTS4_IN,
- PTS3_FN, PTS3_OUT, 0, PTS3_IN,
- PTS2_FN, PTS2_OUT, 0, PTS2_IN,
- PTS1_FN, PTS1_OUT, 0, PTS1_IN,
- PTS0_FN, PTS0_OUT, 0, PTS0_IN }
- },
- { PINMUX_CFG_REG("PTCR", 0xa4050140, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTT5_FN, PTT5_OUT, 0, PTT5_IN,
- PTT4_FN, PTT4_OUT, 0, PTT4_IN,
- PTT3_FN, PTT3_OUT, 0, PTT3_IN,
- PTT2_FN, PTT2_OUT, 0, PTT2_IN,
- PTT1_FN, PTT1_OUT, 0, PTT1_IN,
- PTT0_FN, PTT0_OUT, 0, PTT0_IN }
- },
- { PINMUX_CFG_REG("PUCR", 0xa4050142, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTU5_FN, PTU5_OUT, 0, PTU5_IN,
- PTU4_FN, PTU4_OUT, 0, PTU4_IN,
- PTU3_FN, PTU3_OUT, 0, PTU3_IN,
- PTU2_FN, PTU2_OUT, 0, PTU2_IN,
- PTU1_FN, PTU1_OUT, 0, PTU1_IN,
- PTU0_FN, PTU0_OUT, 0, PTU0_IN }
- },
- { PINMUX_CFG_REG("PVCR", 0xa4050144, 16, 2) {
- PTV7_FN, PTV7_OUT, 0, PTV7_IN,
- PTV6_FN, PTV6_OUT, 0, PTV6_IN,
- PTV5_FN, PTV5_OUT, 0, PTV5_IN,
- PTV4_FN, PTV4_OUT, 0, PTV4_IN,
- PTV3_FN, PTV3_OUT, 0, PTV3_IN,
- PTV2_FN, PTV2_OUT, 0, PTV2_IN,
- PTV1_FN, PTV1_OUT, 0, PTV1_IN,
- PTV0_FN, PTV0_OUT, 0, PTV0_IN }
- },
- { PINMUX_CFG_REG("PWCR", 0xa4050146, 16, 2) {
- PTW7_FN, PTW7_OUT, 0, PTW7_IN,
- PTW6_FN, PTW6_OUT, 0, PTW6_IN,
- PTW5_FN, PTW5_OUT, 0, PTW5_IN,
- PTW4_FN, PTW4_OUT, 0, PTW4_IN,
- PTW3_FN, PTW3_OUT, 0, PTW3_IN,
- PTW2_FN, PTW2_OUT, 0, PTW2_IN,
- PTW1_FN, PTW1_OUT, 0, PTW1_IN,
- PTW0_FN, PTW0_OUT, 0, PTW0_IN }
- },
- { PINMUX_CFG_REG("PXCR", 0xa4050148, 16, 2) {
- PTX7_FN, PTX7_OUT, 0, PTX7_IN,
- PTX6_FN, PTX6_OUT, 0, PTX6_IN,
- PTX5_FN, PTX5_OUT, 0, PTX5_IN,
- PTX4_FN, PTX4_OUT, 0, PTX4_IN,
- PTX3_FN, PTX3_OUT, 0, PTX3_IN,
- PTX2_FN, PTX2_OUT, 0, PTX2_IN,
- PTX1_FN, PTX1_OUT, 0, PTX1_IN,
- PTX0_FN, PTX0_OUT, 0, PTX0_IN }
- },
- { PINMUX_CFG_REG("PYCR", 0xa405014a, 16, 2) {
- PTY7_FN, PTY7_OUT, 0, PTY7_IN,
- PTY6_FN, PTY6_OUT, 0, PTY6_IN,
- PTY5_FN, PTY5_OUT, 0, PTY5_IN,
- PTY4_FN, PTY4_OUT, 0, PTY4_IN,
- PTY3_FN, PTY3_OUT, 0, PTY3_IN,
- PTY2_FN, PTY2_OUT, 0, PTY2_IN,
- PTY1_FN, PTY1_OUT, 0, PTY1_IN,
- PTY0_FN, PTY0_OUT, 0, PTY0_IN }
- },
- { PINMUX_CFG_REG("PZCR", 0xa405014c, 16, 2) {
- PTZ7_FN, PTZ7_OUT, 0, PTZ7_IN,
- PTZ6_FN, PTZ6_OUT, 0, PTZ6_IN,
- PTZ5_FN, PTZ5_OUT, 0, PTZ5_IN,
- PTZ4_FN, PTZ4_OUT, 0, PTZ4_IN,
- PTZ3_FN, PTZ3_OUT, 0, PTZ3_IN,
- PTZ2_FN, PTZ2_OUT, 0, PTZ2_IN,
- PTZ1_FN, PTZ1_OUT, 0, PTZ1_IN,
- PTZ0_FN, PTZ0_OUT, 0, PTZ0_IN }
- },
- { PINMUX_CFG_REG("PSELA", 0xa405014e, 16, 2) {
- PSA15_PSA14_FN1, PSA15_PSA14_FN2, 0, 0,
- PSA13_PSA12_FN1, PSA13_PSA12_FN2, 0, 0,
- PSA11_PSA10_FN1, PSA11_PSA10_FN2, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PSA5_PSA4_FN1, PSA5_PSA4_FN2, PSA5_PSA4_FN3, 0,
- PSA3_PSA2_FN1, PSA3_PSA2_FN2, 0, 0,
- 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PSELB", 0xa4050150, 16, 2) {
- PSB15_PSB14_FN1, PSB15_PSB14_FN2, 0, 0,
- PSB13_PSB12_LCDC_RGB, PSB13_PSB12_LCDC_SYS, 0, 0,
- 0, 0, 0, 0,
- PSB9_PSB8_FN1, PSB9_PSB8_FN2, PSB9_PSB8_FN3, 0,
- PSB7_PSB6_FN1, PSB7_PSB6_FN2, 0, 0,
- PSB5_PSB4_FN1, PSB5_PSB4_FN2, 0, 0,
- PSB3_PSB2_FN1, PSB3_PSB2_FN2, 0, 0,
- 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PSELC", 0xa4050152, 16, 2) {
- PSC15_PSC14_FN1, PSC15_PSC14_FN2, 0, 0,
- PSC13_PSC12_FN1, PSC13_PSC12_FN2, 0, 0,
- PSC11_PSC10_FN1, PSC11_PSC10_FN2, PSC11_PSC10_FN3, 0,
- PSC9_PSC8_FN1, PSC9_PSC8_FN2, 0, 0,
- PSC7_PSC6_FN1, PSC7_PSC6_FN2, PSC7_PSC6_FN3, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0 }
- },
- { PINMUX_CFG_REG("PSELD", 0xa4050154, 16, 2) {
- PSD15_PSD14_FN1, PSD15_PSD14_FN2, 0, 0,
- PSD13_PSD12_FN1, PSD13_PSD12_FN2, 0, 0,
- PSD11_PSD10_FN1, PSD11_PSD10_FN2, PSD11_PSD10_FN3, 0,
- PSD9_PSD8_FN1, PSD9_PSD8_FN2, 0, 0,
- PSD7_PSD6_FN1, PSD7_PSD6_FN2, 0, 0,
- PSD5_PSD4_FN1, PSD5_PSD4_FN2, 0, 0,
- PSD3_PSD2_FN1, PSD3_PSD2_FN2, 0, 0,
- PSD1_PSD0_FN1, PSD1_PSD0_FN2, 0, 0 }
- },
- {}
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PADR", 0xa4050120, 8) {
- PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
- PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
- },
- { PINMUX_DATA_REG("PBDR", 0xa4050122, 8) {
- PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
- PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
- },
- { PINMUX_DATA_REG("PCDR", 0xa4050124, 8) {
- PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
- PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA }
- },
- { PINMUX_DATA_REG("PDDR", 0xa4050126, 8) {
- PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
- PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
- },
- { PINMUX_DATA_REG("PEDR", 0xa4050128, 8) {
- 0, 0, PTE5_DATA, PTE4_DATA,
- PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA }
- },
- { PINMUX_DATA_REG("PFDR", 0xa405012a, 8) {
- PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
- PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
- },
- { PINMUX_DATA_REG("PGDR", 0xa405012c, 8) {
- 0, 0, PTG5_DATA, PTG4_DATA,
- PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
- },
- { PINMUX_DATA_REG("PHDR", 0xa405012e, 8) {
- PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
- PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
- },
- { PINMUX_DATA_REG("PJDR", 0xa4050130, 8) {
- PTJ7_DATA, 0, PTJ5_DATA, 0,
- PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
- },
- { PINMUX_DATA_REG("PKDR", 0xa4050132, 8) {
- PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
- PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
- },
- { PINMUX_DATA_REG("PLDR", 0xa4050134, 8) {
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
- PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
- },
- { PINMUX_DATA_REG("PMDR", 0xa4050136, 8) {
- PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
- PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
- },
- { PINMUX_DATA_REG("PNDR", 0xa4050138, 8) {
- PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
- PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
- },
- { PINMUX_DATA_REG("PQDR", 0xa405013a, 8) {
- 0, 0, 0, 0,
- PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA }
- },
- { PINMUX_DATA_REG("PRDR", 0xa405013c, 8) {
- PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
- PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
- },
- { PINMUX_DATA_REG("PSDR", 0xa405013e, 8) {
- PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
- PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
- },
- { PINMUX_DATA_REG("PTDR", 0xa4050160, 8) {
- 0, 0, PTT5_DATA, PTT4_DATA,
- PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
- },
- { PINMUX_DATA_REG("PUDR", 0xa4050162, 8) {
- 0, 0, PTU5_DATA, PTU4_DATA,
- PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
- },
- { PINMUX_DATA_REG("PVDR", 0xa4050164, 8) {
- PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
- PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
- },
- { PINMUX_DATA_REG("PWDR", 0xa4050166, 8) {
- PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
- PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA }
- },
- { PINMUX_DATA_REG("PXDR", 0xa4050168, 8) {
- PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
- PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA }
- },
- { PINMUX_DATA_REG("PYDR", 0xa405016a, 8) {
- PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
- PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA }
- },
- { PINMUX_DATA_REG("PZDR", 0xa405016c, 8) {
- PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
- PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA }
- },
- { },
-};
-
-static struct pinmux_info sh7723_pinmux_info = {
- .name = "sh7723_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
- .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_PTA7,
- .last_gpio = GPIO_FN_IDEA0,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
+#include <cpu/pfc.h>
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7723_pinmux_info);
+ return sh_pfc_register("pfc-sh7723", NULL, 0);
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7724.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7724.c
index 1af0f9586379..5c3541d6aed8 100644
--- a/arch/sh/kernel/cpu/sh4a/pinmux-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7724.c
@@ -15,2216 +15,10 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/sh7724.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
- PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
- PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
- PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
- PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
- PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA,
- PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
- PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
- PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
- PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA,
- PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
- PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
- PTG5_DATA, PTG4_DATA,
- PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
- PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
- PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
- PTJ7_DATA, PTJ6_DATA, PTJ5_DATA,
- PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
- PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
- PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
- PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
- PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
- PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
- PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
- PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
- PTQ7_DATA, PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
- PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
- PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
- PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
- PTS6_DATA, PTS5_DATA, PTS4_DATA,
- PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
- PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
- PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
- PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
- PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
- PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
- PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
- PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
- PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA,
- PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
- PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA,
- PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
- PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA,
- PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
- PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
- PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
- PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
- PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
- PTC7_IN, PTC6_IN, PTC5_IN, PTC4_IN,
- PTC3_IN, PTC2_IN, PTC1_IN, PTC0_IN,
- PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN,
- PTD3_IN, PTD2_IN, PTD1_IN, PTD0_IN,
- PTE7_IN, PTE6_IN, PTE5_IN, PTE4_IN,
- PTE3_IN, PTE2_IN, PTE1_IN, PTE0_IN,
- PTF7_IN, PTF6_IN, PTF5_IN, PTF4_IN,
- PTF3_IN, PTF2_IN, PTF1_IN, PTF0_IN,
- PTH7_IN, PTH6_IN, PTH5_IN, PTH4_IN,
- PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
- PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
- PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
- PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
- PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
- PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
- PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
- PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
- PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
- PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
- PTQ7_IN, PTQ6_IN, PTQ5_IN, PTQ4_IN,
- PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
- PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
- PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
- PTS6_IN, PTS5_IN, PTS4_IN,
- PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
- PTT7_IN, PTT6_IN, PTT5_IN, PTT4_IN,
- PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
- PTU7_IN, PTU6_IN, PTU5_IN, PTU4_IN,
- PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
- PTV7_IN, PTV6_IN, PTV5_IN, PTV4_IN,
- PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
- PTW7_IN, PTW6_IN, PTW5_IN, PTW4_IN,
- PTW3_IN, PTW2_IN, PTW1_IN, PTW0_IN,
- PTX7_IN, PTX6_IN, PTX5_IN, PTX4_IN,
- PTX3_IN, PTX2_IN, PTX1_IN, PTX0_IN,
- PTY7_IN, PTY6_IN, PTY5_IN, PTY4_IN,
- PTY3_IN, PTY2_IN, PTY1_IN, PTY0_IN,
- PTZ7_IN, PTZ6_IN, PTZ5_IN, PTZ4_IN,
- PTZ3_IN, PTZ2_IN, PTZ1_IN, PTZ0_IN,
- PINMUX_INPUT_END,
-
- PINMUX_INPUT_PULLUP_BEGIN,
- PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
- PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
- PTB7_IN_PU, PTB6_IN_PU, PTB5_IN_PU, PTB4_IN_PU,
- PTB3_IN_PU, PTB2_IN_PU, PTB1_IN_PU, PTB0_IN_PU,
- PTC7_IN_PU, PTC6_IN_PU, PTC5_IN_PU, PTC4_IN_PU,
- PTC3_IN_PU, PTC2_IN_PU, PTC1_IN_PU, PTC0_IN_PU,
- PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
- PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
- PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
- PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
- PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
- PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
- PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
- PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
- PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
- PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
- PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
- PTL7_IN_PU, PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
- PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
- PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
- PTM3_IN_PU, PTM2_IN_PU, PTM1_IN_PU, PTM0_IN_PU,
- PTN7_IN_PU, PTN6_IN_PU, PTN5_IN_PU, PTN4_IN_PU,
- PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
- PTQ7_IN_PU, PTQ6_IN_PU, PTQ5_IN_PU, PTQ4_IN_PU,
- PTQ3_IN_PU, PTQ2_IN_PU, PTQ1_IN_PU, PTQ0_IN_PU,
- PTR7_IN_PU, PTR6_IN_PU, PTR5_IN_PU, PTR4_IN_PU,
- PTR3_IN_PU, PTR2_IN_PU, PTR1_IN_PU, PTR0_IN_PU,
- PTS6_IN_PU, PTS5_IN_PU, PTS4_IN_PU,
- PTS3_IN_PU, PTS2_IN_PU, PTS1_IN_PU, PTS0_IN_PU,
- PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
- PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
- PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
- PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
- PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
- PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
- PTW7_IN_PU, PTW6_IN_PU, PTW5_IN_PU, PTW4_IN_PU,
- PTW3_IN_PU, PTW2_IN_PU, PTW1_IN_PU, PTW0_IN_PU,
- PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
- PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
- PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
- PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
- PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
- PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
- PINMUX_INPUT_PULLUP_END,
-
- PINMUX_OUTPUT_BEGIN,
- PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
- PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
- PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
- PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
- PTC7_OUT, PTC6_OUT, PTC5_OUT, PTC4_OUT,
- PTC3_OUT, PTC2_OUT, PTC1_OUT, PTC0_OUT,
- PTD7_OUT, PTD6_OUT, PTD5_OUT, PTD4_OUT,
- PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
- PTE7_OUT, PTE6_OUT, PTE5_OUT, PTE4_OUT,
- PTE3_OUT, PTE2_OUT, PTE1_OUT, PTE0_OUT,
- PTF7_OUT, PTF6_OUT, PTF5_OUT, PTF4_OUT,
- PTF3_OUT, PTF2_OUT, PTF1_OUT, PTF0_OUT,
- PTG5_OUT, PTG4_OUT,
- PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
- PTH7_OUT, PTH6_OUT, PTH5_OUT, PTH4_OUT,
- PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
- PTJ7_OUT, PTJ6_OUT, PTJ5_OUT,
- PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
- PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
- PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
- PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
- PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
- PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
- PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
- PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
- PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
- PTQ7_OUT, PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
- PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
- PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
- PTR1_OUT, PTR0_OUT,
- PTS6_OUT, PTS5_OUT, PTS4_OUT,
- PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
- PTT7_OUT, PTT6_OUT, PTT5_OUT, PTT4_OUT,
- PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
- PTU7_OUT, PTU6_OUT, PTU5_OUT, PTU4_OUT,
- PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
- PTV7_OUT, PTV6_OUT, PTV5_OUT, PTV4_OUT,
- PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
- PTW7_OUT, PTW6_OUT, PTW5_OUT, PTW4_OUT,
- PTW3_OUT, PTW2_OUT, PTW1_OUT, PTW0_OUT,
- PTX7_OUT, PTX6_OUT, PTX5_OUT, PTX4_OUT,
- PTX3_OUT, PTX2_OUT, PTX1_OUT, PTX0_OUT,
- PTY7_OUT, PTY6_OUT, PTY5_OUT, PTY4_OUT,
- PTY3_OUT, PTY2_OUT, PTY1_OUT, PTY0_OUT,
- PTZ7_OUT, PTZ6_OUT, PTZ5_OUT, PTZ4_OUT,
- PTZ3_OUT, PTZ2_OUT, PTZ1_OUT, PTZ0_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- PTA7_FN, PTA6_FN, PTA5_FN, PTA4_FN,
- PTA3_FN, PTA2_FN, PTA1_FN, PTA0_FN,
- PTB7_FN, PTB6_FN, PTB5_FN, PTB4_FN,
- PTB3_FN, PTB2_FN, PTB1_FN, PTB0_FN,
- PTC7_FN, PTC6_FN, PTC5_FN, PTC4_FN,
- PTC3_FN, PTC2_FN, PTC1_FN, PTC0_FN,
- PTD7_FN, PTD6_FN, PTD5_FN, PTD4_FN,
- PTD3_FN, PTD2_FN, PTD1_FN, PTD0_FN,
- PTE7_FN, PTE6_FN, PTE5_FN, PTE4_FN,
- PTE3_FN, PTE2_FN, PTE1_FN, PTE0_FN,
- PTF7_FN, PTF6_FN, PTF5_FN, PTF4_FN,
- PTF3_FN, PTF2_FN, PTF1_FN, PTF0_FN,
- PTG5_FN, PTG4_FN,
- PTG3_FN, PTG2_FN, PTG1_FN, PTG0_FN,
- PTH7_FN, PTH6_FN, PTH5_FN, PTH4_FN,
- PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
- PTJ7_FN, PTJ6_FN, PTJ5_FN,
- PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
- PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
- PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
- PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN,
- PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
- PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
- PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
- PTN7_FN, PTN6_FN, PTN5_FN, PTN4_FN,
- PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
- PTQ7_FN, PTQ6_FN, PTQ5_FN, PTQ4_FN,
- PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
- PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
- PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
- PTS6_FN, PTS5_FN, PTS4_FN,
- PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
- PTT7_FN, PTT6_FN, PTT5_FN, PTT4_FN,
- PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
- PTU7_FN, PTU6_FN, PTU5_FN, PTU4_FN,
- PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
- PTV7_FN, PTV6_FN, PTV5_FN, PTV4_FN,
- PTV3_FN, PTV2_FN, PTV1_FN, PTV0_FN,
- PTW7_FN, PTW6_FN, PTW5_FN, PTW4_FN,
- PTW3_FN, PTW2_FN, PTW1_FN, PTW0_FN,
- PTX7_FN, PTX6_FN, PTX5_FN, PTX4_FN,
- PTX3_FN, PTX2_FN, PTX1_FN, PTX0_FN,
- PTY7_FN, PTY6_FN, PTY5_FN, PTY4_FN,
- PTY3_FN, PTY2_FN, PTY1_FN, PTY0_FN,
- PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
- PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
-
-
- PSA15_0, PSA15_1,
- PSA14_0, PSA14_1,
- PSA13_0, PSA13_1,
- PSA12_0, PSA12_1,
- PSA10_0, PSA10_1,
- PSA9_0, PSA9_1,
- PSA8_0, PSA8_1,
- PSA7_0, PSA7_1,
- PSA6_0, PSA6_1,
- PSA5_0, PSA5_1,
- PSA3_0, PSA3_1,
- PSA2_0, PSA2_1,
- PSA1_0, PSA1_1,
- PSA0_0, PSA0_1,
-
- PSB14_0, PSB14_1,
- PSB13_0, PSB13_1,
- PSB12_0, PSB12_1,
- PSB11_0, PSB11_1,
- PSB10_0, PSB10_1,
- PSB9_0, PSB9_1,
- PSB8_0, PSB8_1,
- PSB7_0, PSB7_1,
- PSB6_0, PSB6_1,
- PSB5_0, PSB5_1,
- PSB4_0, PSB4_1,
- PSB3_0, PSB3_1,
- PSB2_0, PSB2_1,
- PSB1_0, PSB1_1,
- PSB0_0, PSB0_1,
-
- PSC15_0, PSC15_1,
- PSC14_0, PSC14_1,
- PSC13_0, PSC13_1,
- PSC12_0, PSC12_1,
- PSC11_0, PSC11_1,
- PSC10_0, PSC10_1,
- PSC9_0, PSC9_1,
- PSC8_0, PSC8_1,
- PSC7_0, PSC7_1,
- PSC6_0, PSC6_1,
- PSC5_0, PSC5_1,
- PSC4_0, PSC4_1,
- PSC2_0, PSC2_1,
- PSC1_0, PSC1_1,
- PSC0_0, PSC0_1,
-
- PSD15_0, PSD15_1,
- PSD14_0, PSD14_1,
- PSD13_0, PSD13_1,
- PSD12_0, PSD12_1,
- PSD11_0, PSD11_1,
- PSD10_0, PSD10_1,
- PSD9_0, PSD9_1,
- PSD8_0, PSD8_1,
- PSD7_0, PSD7_1,
- PSD6_0, PSD6_1,
- PSD5_0, PSD5_1,
- PSD4_0, PSD4_1,
- PSD3_0, PSD3_1,
- PSD2_0, PSD2_1,
- PSD1_0, PSD1_1,
- PSD0_0, PSD0_1,
-
- PSE15_0, PSE15_1,
- PSE14_0, PSE14_1,
- PSE13_0, PSE13_1,
- PSE12_0, PSE12_1,
- PSE11_0, PSE11_1,
- PSE10_0, PSE10_1,
- PSE9_0, PSE9_1,
- PSE8_0, PSE8_1,
- PSE7_0, PSE7_1,
- PSE6_0, PSE6_1,
- PSE5_0, PSE5_1,
- PSE4_0, PSE4_1,
- PSE3_0, PSE3_1,
- PSE2_0, PSE2_1,
- PSE1_0, PSE1_1,
- PSE0_0, PSE0_1,
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
- /*PTA*/
- D23_MARK, KEYOUT2_MARK, IDED15_MARK,
- D22_MARK, KEYOUT1_MARK, IDED14_MARK,
- D21_MARK, KEYOUT0_MARK, IDED13_MARK,
- D20_MARK, KEYIN4_MARK, IDED12_MARK,
- D19_MARK, KEYIN3_MARK, IDED11_MARK,
- D18_MARK, KEYIN2_MARK, IDED10_MARK,
- D17_MARK, KEYIN1_MARK, IDED9_MARK,
- D16_MARK, KEYIN0_MARK, IDED8_MARK,
-
- /*PTB*/
- D31_MARK, TPUTO1_MARK, IDEA1_MARK,
- D30_MARK, TPUTO0_MARK, IDEA0_MARK,
- D29_MARK, IODREQ_MARK,
- D28_MARK, IDECS0_MARK,
- D27_MARK, IDECS1_MARK,
- D26_MARK, KEYOUT5_IN5_MARK, IDEIORD_MARK,
- D25_MARK, KEYOUT4_IN6_MARK, IDEIOWR_MARK,
- D24_MARK, KEYOUT3_MARK, IDEINT_MARK,
-
- /*PTC*/
- LCDD7_MARK,
- LCDD6_MARK,
- LCDD5_MARK,
- LCDD4_MARK,
- LCDD3_MARK,
- LCDD2_MARK,
- LCDD1_MARK,
- LCDD0_MARK,
-
- /*PTD*/
- LCDD15_MARK,
- LCDD14_MARK,
- LCDD13_MARK,
- LCDD12_MARK,
- LCDD11_MARK,
- LCDD10_MARK,
- LCDD9_MARK,
- LCDD8_MARK,
-
- /*PTE*/
- FSIMCKB_MARK,
- FSIMCKA_MARK,
- LCDD21_MARK, SCIF2_L_TXD_MARK,
- LCDD20_MARK, SCIF4_SCK_MARK,
- LCDD19_MARK, SCIF4_RXD_MARK,
- LCDD18_MARK, SCIF4_TXD_MARK,
- LCDD17_MARK,
- LCDD16_MARK,
-
- /*PTF*/
- LCDVSYN_MARK,
- LCDDISP_MARK, LCDRS_MARK,
- LCDHSYN_MARK, LCDCS_MARK,
- LCDDON_MARK,
- LCDDCK_MARK, LCDWR_MARK,
- LCDVEPWC_MARK, SCIF0_TXD_MARK,
- LCDD23_MARK, SCIF2_L_SCK_MARK,
- LCDD22_MARK, SCIF2_L_RXD_MARK,
-
- /*PTG*/
- AUDCK_MARK,
- AUDSYNC_MARK,
- AUDATA3_MARK,
- AUDATA2_MARK,
- AUDATA1_MARK,
- AUDATA0_MARK,
-
- /*PTH*/
- VIO0_VD_MARK,
- VIO0_CLK_MARK,
- VIO0_D7_MARK,
- VIO0_D6_MARK,
- VIO0_D5_MARK,
- VIO0_D4_MARK,
- VIO0_D3_MARK,
- VIO0_D2_MARK,
-
- /*PTJ*/
- PDSTATUS_MARK,
- STATUS2_MARK,
- STATUS0_MARK,
- A25_MARK, BS_MARK,
- A24_MARK,
- A23_MARK,
- A22_MARK,
-
- /*PTK*/
- VIO1_D5_MARK, VIO0_D13_MARK, IDED5_MARK,
- VIO1_D4_MARK, VIO0_D12_MARK, IDED4_MARK,
- VIO1_D3_MARK, VIO0_D11_MARK, IDED3_MARK,
- VIO1_D2_MARK, VIO0_D10_MARK, IDED2_MARK,
- VIO1_D1_MARK, VIO0_D9_MARK, IDED1_MARK,
- VIO1_D0_MARK, VIO0_D8_MARK, IDED0_MARK,
- VIO0_FLD_MARK,
- VIO0_HD_MARK,
-
- /*PTL*/
- DV_D5_MARK, SCIF3_V_SCK_MARK, RMII_RXD0_MARK,
- DV_D4_MARK, SCIF3_V_RXD_MARK, RMII_RXD1_MARK,
- DV_D3_MARK, SCIF3_V_TXD_MARK, RMII_REF_CLK_MARK,
- DV_D2_MARK, SCIF1_SCK_MARK, RMII_TX_EN_MARK,
- DV_D1_MARK, SCIF1_RXD_MARK, RMII_TXD0_MARK,
- DV_D0_MARK, SCIF1_TXD_MARK, RMII_TXD1_MARK,
- DV_D15_MARK,
- DV_D14_MARK, MSIOF0_MCK_MARK,
-
- /*PTM*/
- DV_D13_MARK, MSIOF0_TSCK_MARK,
- DV_D12_MARK, MSIOF0_RXD_MARK,
- DV_D11_MARK, MSIOF0_TXD_MARK,
- DV_D10_MARK, MSIOF0_TSYNC_MARK,
- DV_D9_MARK, MSIOF0_SS1_MARK, MSIOF0_RSCK_MARK,
- DV_D8_MARK, MSIOF0_SS2_MARK, MSIOF0_RSYNC_MARK,
- LCDVCPWC_MARK, SCIF0_RXD_MARK,
- LCDRD_MARK, SCIF0_SCK_MARK,
-
- /*PTN*/
- VIO0_D1_MARK,
- VIO0_D0_MARK,
- DV_CLKI_MARK,
- DV_CLK_MARK, SCIF2_V_SCK_MARK,
- DV_VSYNC_MARK, SCIF2_V_RXD_MARK,
- DV_HSYNC_MARK, SCIF2_V_TXD_MARK,
- DV_D7_MARK, SCIF3_V_CTS_MARK, RMII_RX_ER_MARK,
- DV_D6_MARK, SCIF3_V_RTS_MARK, RMII_CRS_DV_MARK,
-
- /*PTQ*/
- D7_MARK,
- D6_MARK,
- D5_MARK,
- D4_MARK,
- D3_MARK,
- D2_MARK,
- D1_MARK,
- D0_MARK,
-
- /*PTR*/
- CS6B_CE1B_MARK,
- CS6A_CE2B_MARK,
- CS5B_CE1A_MARK,
- CS5A_CE2A_MARK,
- IOIS16_MARK, LCDLCLK_MARK,
- WAIT_MARK,
- WE3_ICIOWR_MARK, TPUTO3_MARK, TPUTI3_MARK,
- WE2_ICIORD_MARK, TPUTO2_MARK, IDEA2_MARK,
-
- /*PTS*/
- VIO_CKO_MARK,
- VIO1_FLD_MARK, TPUTI2_MARK, IDEIORDY_MARK,
- VIO1_HD_MARK, SCIF5_SCK_MARK,
- VIO1_VD_MARK, SCIF5_RXD_MARK,
- VIO1_CLK_MARK, SCIF5_TXD_MARK,
- VIO1_D7_MARK, VIO0_D15_MARK, IDED7_MARK,
- VIO1_D6_MARK, VIO0_D14_MARK, IDED6_MARK,
-
- /*PTT*/
- D15_MARK,
- D14_MARK,
- D13_MARK,
- D12_MARK,
- D11_MARK,
- D10_MARK,
- D9_MARK,
- D8_MARK,
-
- /*PTU*/
- DMAC_DACK0_MARK,
- DMAC_DREQ0_MARK,
- FSIOASD_MARK,
- FSIIABCK_MARK,
- FSIIALRCK_MARK,
- FSIOABCK_MARK,
- FSIOALRCK_MARK,
- CLKAUDIOAO_MARK,
-
- /*PTV*/
- FSIIBSD_MARK, MSIOF1_SS2_MARK, MSIOF1_RSYNC_MARK,
- FSIOBSD_MARK, MSIOF1_SS1_MARK, MSIOF1_RSCK_MARK,
- FSIIBBCK_MARK, MSIOF1_RXD_MARK,
- FSIIBLRCK_MARK, MSIOF1_TSYNC_MARK,
- FSIOBBCK_MARK, MSIOF1_TSCK_MARK,
- FSIOBLRCK_MARK, MSIOF1_TXD_MARK,
- CLKAUDIOBO_MARK, MSIOF1_MCK_MARK,
- FSIIASD_MARK,
-
- /*PTW*/
- MMC_D7_MARK, SDHI1CD_MARK, IODACK_MARK,
- MMC_D6_MARK, SDHI1WP_MARK, IDERST_MARK,
- MMC_D5_MARK, SDHI1D3_MARK, EXBUF_ENB_MARK,
- MMC_D4_MARK, SDHI1D2_MARK, DIRECTION_MARK,
- MMC_D3_MARK, SDHI1D1_MARK,
- MMC_D2_MARK, SDHI1D0_MARK,
- MMC_D1_MARK, SDHI1CMD_MARK,
- MMC_D0_MARK, SDHI1CLK_MARK,
-
- /*PTX*/
- DMAC_DACK1_MARK, IRDA_OUT_MARK,
- DMAC_DREQ1_MARK, IRDA_IN_MARK,
- TSIF_TS0_SDAT_MARK, LNKSTA_MARK,
- TSIF_TS0_SCK_MARK, MDIO_MARK,
- TSIF_TS0_SDEN_MARK, MDC_MARK,
- TSIF_TS0_SPSYNC_MARK,
- MMC_CLK_MARK,
- MMC_CMD_MARK,
-
- /*PTY*/
- SDHI0CD_MARK,
- SDHI0WP_MARK,
- SDHI0D3_MARK,
- SDHI0D2_MARK,
- SDHI0D1_MARK,
- SDHI0D0_MARK,
- SDHI0CMD_MARK,
- SDHI0CLK_MARK,
-
- /*PTZ*/
- INTC_IRQ7_MARK, SCIF3_I_CTS_MARK,
- INTC_IRQ6_MARK, SCIF3_I_RTS_MARK,
- INTC_IRQ5_MARK, SCIF3_I_SCK_MARK,
- INTC_IRQ4_MARK, SCIF3_I_RXD_MARK,
- INTC_IRQ3_MARK, SCIF3_I_TXD_MARK,
- INTC_IRQ2_MARK,
- INTC_IRQ1_MARK,
- INTC_IRQ0_MARK,
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
- /* PTA GPIO */
- PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT, PTA7_IN_PU),
- PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT, PTA6_IN_PU),
- PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT, PTA5_IN_PU),
- PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT, PTA4_IN_PU),
- PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT, PTA3_IN_PU),
- PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT, PTA2_IN_PU),
- PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT, PTA1_IN_PU),
- PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT, PTA0_IN_PU),
-
- /* PTB GPIO */
- PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT, PTB7_IN_PU),
- PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT, PTB6_IN_PU),
- PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT, PTB5_IN_PU),
- PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT, PTB4_IN_PU),
- PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT, PTB3_IN_PU),
- PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT, PTB2_IN_PU),
- PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT, PTB1_IN_PU),
- PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT, PTB0_IN_PU),
-
- /* PTC GPIO */
- PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT, PTC7_IN_PU),
- PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT, PTC6_IN_PU),
- PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT, PTC5_IN_PU),
- PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT, PTC4_IN_PU),
- PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT, PTC3_IN_PU),
- PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT, PTC2_IN_PU),
- PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT, PTC1_IN_PU),
- PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT, PTC0_IN_PU),
-
- /* PTD GPIO */
- PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT, PTD7_IN_PU),
- PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT, PTD6_IN_PU),
- PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT, PTD5_IN_PU),
- PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT, PTD4_IN_PU),
- PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT, PTD3_IN_PU),
- PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT, PTD2_IN_PU),
- PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT, PTD1_IN_PU),
- PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT, PTD0_IN_PU),
-
- /* PTE GPIO */
- PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT, PTE7_IN_PU),
- PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT, PTE6_IN_PU),
- PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT, PTE5_IN_PU),
- PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT, PTE4_IN_PU),
- PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT, PTE3_IN_PU),
- PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT, PTE2_IN_PU),
- PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT, PTE1_IN_PU),
- PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT, PTE0_IN_PU),
-
- /* PTF GPIO */
- PINMUX_DATA(PTF7_DATA, PTF7_IN, PTF7_OUT, PTF7_IN_PU),
- PINMUX_DATA(PTF6_DATA, PTF6_IN, PTF6_OUT, PTF6_IN_PU),
- PINMUX_DATA(PTF5_DATA, PTF5_IN, PTF5_OUT, PTF5_IN_PU),
- PINMUX_DATA(PTF4_DATA, PTF4_IN, PTF4_OUT, PTF4_IN_PU),
- PINMUX_DATA(PTF3_DATA, PTF3_IN, PTF3_OUT, PTF3_IN_PU),
- PINMUX_DATA(PTF2_DATA, PTF2_IN, PTF2_OUT, PTF2_IN_PU),
- PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_OUT, PTF1_IN_PU),
- PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT, PTF0_IN_PU),
-
- /* PTG GPIO */
- PINMUX_DATA(PTG5_DATA, PTG5_OUT),
- PINMUX_DATA(PTG4_DATA, PTG4_OUT),
- PINMUX_DATA(PTG3_DATA, PTG3_OUT),
- PINMUX_DATA(PTG2_DATA, PTG2_OUT),
- PINMUX_DATA(PTG1_DATA, PTG1_OUT),
- PINMUX_DATA(PTG0_DATA, PTG0_OUT),
-
- /* PTH GPIO */
- PINMUX_DATA(PTH7_DATA, PTH7_IN, PTH7_OUT, PTH7_IN_PU),
- PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT, PTH6_IN_PU),
- PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT, PTH5_IN_PU),
- PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT, PTH4_IN_PU),
- PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT, PTH3_IN_PU),
- PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT, PTH2_IN_PU),
- PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT, PTH1_IN_PU),
- PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT, PTH0_IN_PU),
-
- /* PTJ GPIO */
- PINMUX_DATA(PTJ7_DATA, PTJ7_OUT),
- PINMUX_DATA(PTJ6_DATA, PTJ6_OUT),
- PINMUX_DATA(PTJ5_DATA, PTJ5_OUT),
- PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT, PTJ3_IN_PU),
- PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT, PTJ2_IN_PU),
- PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT, PTJ1_IN_PU),
- PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT, PTJ0_IN_PU),
-
- /* PTK GPIO */
- PINMUX_DATA(PTK7_DATA, PTK7_IN, PTK7_OUT, PTK7_IN_PU),
- PINMUX_DATA(PTK6_DATA, PTK6_IN, PTK6_OUT, PTK6_IN_PU),
- PINMUX_DATA(PTK5_DATA, PTK5_IN, PTK5_OUT, PTK5_IN_PU),
- PINMUX_DATA(PTK4_DATA, PTK4_IN, PTK4_OUT, PTK4_IN_PU),
- PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT, PTK3_IN_PU),
- PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT, PTK2_IN_PU),
- PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT, PTK1_IN_PU),
- PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT, PTK0_IN_PU),
-
- /* PTL GPIO */
- PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT, PTL7_IN_PU),
- PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT, PTL6_IN_PU),
- PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT, PTL5_IN_PU),
- PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT, PTL4_IN_PU),
- PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT, PTL3_IN_PU),
- PINMUX_DATA(PTL2_DATA, PTL2_IN, PTL2_OUT, PTL2_IN_PU),
- PINMUX_DATA(PTL1_DATA, PTL1_IN, PTL1_OUT, PTL1_IN_PU),
- PINMUX_DATA(PTL0_DATA, PTL0_IN, PTL0_OUT, PTL0_IN_PU),
-
- /* PTM GPIO */
- PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT, PTM7_IN_PU),
- PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT, PTM6_IN_PU),
- PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT, PTM5_IN_PU),
- PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT, PTM4_IN_PU),
- PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT, PTM3_IN_PU),
- PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT, PTM2_IN_PU),
- PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT, PTM1_IN_PU),
- PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT, PTM0_IN_PU),
-
- /* PTN GPIO */
- PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT, PTN7_IN_PU),
- PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT, PTN6_IN_PU),
- PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT, PTN5_IN_PU),
- PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT, PTN4_IN_PU),
- PINMUX_DATA(PTN3_DATA, PTN3_IN, PTN3_OUT, PTN3_IN_PU),
- PINMUX_DATA(PTN2_DATA, PTN2_IN, PTN2_OUT, PTN2_IN_PU),
- PINMUX_DATA(PTN1_DATA, PTN1_IN, PTN1_OUT, PTN1_IN_PU),
- PINMUX_DATA(PTN0_DATA, PTN0_IN, PTN0_OUT, PTN0_IN_PU),
-
- /* PTQ GPIO */
- PINMUX_DATA(PTQ7_DATA, PTQ7_IN, PTQ7_OUT, PTQ7_IN_PU),
- PINMUX_DATA(PTQ6_DATA, PTQ6_IN, PTQ6_OUT, PTQ6_IN_PU),
- PINMUX_DATA(PTQ5_DATA, PTQ5_IN, PTQ5_OUT, PTQ5_IN_PU),
- PINMUX_DATA(PTQ4_DATA, PTQ4_IN, PTQ4_OUT, PTQ4_IN_PU),
- PINMUX_DATA(PTQ3_DATA, PTQ3_IN, PTQ3_OUT, PTQ3_IN_PU),
- PINMUX_DATA(PTQ2_DATA, PTQ2_IN, PTQ2_OUT, PTQ2_IN_PU),
- PINMUX_DATA(PTQ1_DATA, PTQ1_IN, PTQ1_OUT, PTQ1_IN_PU),
- PINMUX_DATA(PTQ0_DATA, PTQ0_IN, PTQ0_OUT, PTQ0_IN_PU),
-
- /* PTR GPIO */
- PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT, PTR7_IN_PU),
- PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT, PTR6_IN_PU),
- PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT, PTR5_IN_PU),
- PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT, PTR4_IN_PU),
- PINMUX_DATA(PTR3_DATA, PTR3_IN, PTR3_IN_PU),
- PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_IN_PU),
- PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT, PTR1_IN_PU),
- PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT, PTR0_IN_PU),
-
- /* PTS GPIO */
- PINMUX_DATA(PTS6_DATA, PTS6_IN, PTS6_OUT, PTS6_IN_PU),
- PINMUX_DATA(PTS5_DATA, PTS5_IN, PTS5_OUT, PTS5_IN_PU),
- PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT, PTS4_IN_PU),
- PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT, PTS3_IN_PU),
- PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT, PTS2_IN_PU),
- PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT, PTS1_IN_PU),
- PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT, PTS0_IN_PU),
-
- /* PTT GPIO */
- PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT, PTT7_IN_PU),
- PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT, PTT6_IN_PU),
- PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT, PTT5_IN_PU),
- PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT, PTT4_IN_PU),
- PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT, PTT3_IN_PU),
- PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT, PTT2_IN_PU),
- PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT, PTT1_IN_PU),
- PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT, PTT0_IN_PU),
-
- /* PTU GPIO */
- PINMUX_DATA(PTU7_DATA, PTU7_IN, PTU7_OUT, PTU7_IN_PU),
- PINMUX_DATA(PTU6_DATA, PTU6_IN, PTU6_OUT, PTU6_IN_PU),
- PINMUX_DATA(PTU5_DATA, PTU5_IN, PTU5_OUT, PTU5_IN_PU),
- PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT, PTU4_IN_PU),
- PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT, PTU3_IN_PU),
- PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT, PTU2_IN_PU),
- PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT, PTU1_IN_PU),
- PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT, PTU0_IN_PU),
-
- /* PTV GPIO */
- PINMUX_DATA(PTV7_DATA, PTV7_IN, PTV7_OUT, PTV7_IN_PU),
- PINMUX_DATA(PTV6_DATA, PTV6_IN, PTV6_OUT, PTV6_IN_PU),
- PINMUX_DATA(PTV5_DATA, PTV5_IN, PTV5_OUT, PTV5_IN_PU),
- PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT, PTV4_IN_PU),
- PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT, PTV3_IN_PU),
- PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT, PTV2_IN_PU),
- PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT, PTV1_IN_PU),
- PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT, PTV0_IN_PU),
-
- /* PTW GPIO */
- PINMUX_DATA(PTW7_DATA, PTW7_IN, PTW7_OUT, PTW7_IN_PU),
- PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_OUT, PTW6_IN_PU),
- PINMUX_DATA(PTW5_DATA, PTW5_IN, PTW5_OUT, PTW5_IN_PU),
- PINMUX_DATA(PTW4_DATA, PTW4_IN, PTW4_OUT, PTW4_IN_PU),
- PINMUX_DATA(PTW3_DATA, PTW3_IN, PTW3_OUT, PTW3_IN_PU),
- PINMUX_DATA(PTW2_DATA, PTW2_IN, PTW2_OUT, PTW2_IN_PU),
- PINMUX_DATA(PTW1_DATA, PTW1_IN, PTW1_OUT, PTW1_IN_PU),
- PINMUX_DATA(PTW0_DATA, PTW0_IN, PTW0_OUT, PTW0_IN_PU),
-
- /* PTX GPIO */
- PINMUX_DATA(PTX7_DATA, PTX7_IN, PTX7_OUT, PTX7_IN_PU),
- PINMUX_DATA(PTX6_DATA, PTX6_IN, PTX6_OUT, PTX6_IN_PU),
- PINMUX_DATA(PTX5_DATA, PTX5_IN, PTX5_OUT, PTX5_IN_PU),
- PINMUX_DATA(PTX4_DATA, PTX4_IN, PTX4_OUT, PTX4_IN_PU),
- PINMUX_DATA(PTX3_DATA, PTX3_IN, PTX3_OUT, PTX3_IN_PU),
- PINMUX_DATA(PTX2_DATA, PTX2_IN, PTX2_OUT, PTX2_IN_PU),
- PINMUX_DATA(PTX1_DATA, PTX1_IN, PTX1_OUT, PTX1_IN_PU),
- PINMUX_DATA(PTX0_DATA, PTX0_IN, PTX0_OUT, PTX0_IN_PU),
-
- /* PTY GPIO */
- PINMUX_DATA(PTY7_DATA, PTY7_IN, PTY7_OUT, PTY7_IN_PU),
- PINMUX_DATA(PTY6_DATA, PTY6_IN, PTY6_OUT, PTY6_IN_PU),
- PINMUX_DATA(PTY5_DATA, PTY5_IN, PTY5_OUT, PTY5_IN_PU),
- PINMUX_DATA(PTY4_DATA, PTY4_IN, PTY4_OUT, PTY4_IN_PU),
- PINMUX_DATA(PTY3_DATA, PTY3_IN, PTY3_OUT, PTY3_IN_PU),
- PINMUX_DATA(PTY2_DATA, PTY2_IN, PTY2_OUT, PTY2_IN_PU),
- PINMUX_DATA(PTY1_DATA, PTY1_IN, PTY1_OUT, PTY1_IN_PU),
- PINMUX_DATA(PTY0_DATA, PTY0_IN, PTY0_OUT, PTY0_IN_PU),
-
- /* PTZ GPIO */
- PINMUX_DATA(PTZ7_DATA, PTZ7_IN, PTZ7_OUT, PTZ7_IN_PU),
- PINMUX_DATA(PTZ6_DATA, PTZ6_IN, PTZ6_OUT, PTZ6_IN_PU),
- PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_OUT, PTZ5_IN_PU),
- PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_OUT, PTZ4_IN_PU),
- PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_OUT, PTZ3_IN_PU),
- PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_OUT, PTZ2_IN_PU),
- PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_OUT, PTZ1_IN_PU),
- PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT, PTZ0_IN_PU),
-
- /* PTA FN */
- PINMUX_DATA(D23_MARK, PSA15_0, PSA14_0, PTA7_FN),
- PINMUX_DATA(D22_MARK, PSA15_0, PSA14_0, PTA6_FN),
- PINMUX_DATA(D21_MARK, PSA15_0, PSA14_0, PTA5_FN),
- PINMUX_DATA(D20_MARK, PSA15_0, PSA14_0, PTA4_FN),
- PINMUX_DATA(D19_MARK, PSA15_0, PSA14_0, PTA3_FN),
- PINMUX_DATA(D18_MARK, PSA15_0, PSA14_0, PTA2_FN),
- PINMUX_DATA(D17_MARK, PSA15_0, PSA14_0, PTA1_FN),
- PINMUX_DATA(D16_MARK, PSA15_0, PSA14_0, PTA0_FN),
-
- PINMUX_DATA(KEYOUT2_MARK, PSA15_0, PSA14_1, PTA7_FN),
- PINMUX_DATA(KEYOUT1_MARK, PSA15_0, PSA14_1, PTA6_FN),
- PINMUX_DATA(KEYOUT0_MARK, PSA15_0, PSA14_1, PTA5_FN),
- PINMUX_DATA(KEYIN4_MARK, PSA15_0, PSA14_1, PTA4_FN),
- PINMUX_DATA(KEYIN3_MARK, PSA15_0, PSA14_1, PTA3_FN),
- PINMUX_DATA(KEYIN2_MARK, PSA15_0, PSA14_1, PTA2_FN),
- PINMUX_DATA(KEYIN1_MARK, PSA15_0, PSA14_1, PTA1_FN),
- PINMUX_DATA(KEYIN0_MARK, PSA15_0, PSA14_1, PTA0_FN),
-
- PINMUX_DATA(IDED15_MARK, PSA15_1, PSA14_0, PTA7_FN),
- PINMUX_DATA(IDED14_MARK, PSA15_1, PSA14_0, PTA6_FN),
- PINMUX_DATA(IDED13_MARK, PSA15_1, PSA14_0, PTA5_FN),
- PINMUX_DATA(IDED12_MARK, PSA15_1, PSA14_0, PTA4_FN),
- PINMUX_DATA(IDED11_MARK, PSA15_1, PSA14_0, PTA3_FN),
- PINMUX_DATA(IDED10_MARK, PSA15_1, PSA14_0, PTA2_FN),
- PINMUX_DATA(IDED9_MARK, PSA15_1, PSA14_0, PTA1_FN),
- PINMUX_DATA(IDED8_MARK, PSA15_1, PSA14_0, PTA0_FN),
-
- /* PTB FN */
- PINMUX_DATA(D31_MARK, PSE15_0, PSE14_0, PTB7_FN),
- PINMUX_DATA(D30_MARK, PSE15_0, PSE14_0, PTB6_FN),
- PINMUX_DATA(D29_MARK, PSE11_0, PTB5_FN),
- PINMUX_DATA(D28_MARK, PSE11_0, PTB4_FN),
- PINMUX_DATA(D27_MARK, PSE11_0, PTB3_FN),
- PINMUX_DATA(D26_MARK, PSA15_0, PSA14_0, PTB2_FN),
- PINMUX_DATA(D25_MARK, PSA15_0, PSA14_0, PTB1_FN),
- PINMUX_DATA(D24_MARK, PSA15_0, PSA14_0, PTB0_FN),
-
- PINMUX_DATA(IDEA1_MARK, PSE15_1, PSE14_0, PTB7_FN),
- PINMUX_DATA(IDEA0_MARK, PSE15_1, PSE14_0, PTB6_FN),
- PINMUX_DATA(IODREQ_MARK, PSE11_1, PTB5_FN),
- PINMUX_DATA(IDECS0_MARK, PSE11_1, PTB4_FN),
- PINMUX_DATA(IDECS1_MARK, PSE11_1, PTB3_FN),
- PINMUX_DATA(IDEIORD_MARK, PSA15_1, PSA14_0, PTB2_FN),
- PINMUX_DATA(IDEIOWR_MARK, PSA15_1, PSA14_0, PTB1_FN),
- PINMUX_DATA(IDEINT_MARK, PSA15_1, PSA14_0, PTB0_FN),
-
- PINMUX_DATA(TPUTO1_MARK, PSE15_0, PSE14_1, PTB7_FN),
- PINMUX_DATA(TPUTO0_MARK, PSE15_0, PSE14_1, PTB6_FN),
-
- PINMUX_DATA(KEYOUT5_IN5_MARK, PSA15_0, PSA14_1, PTB2_FN),
- PINMUX_DATA(KEYOUT4_IN6_MARK, PSA15_0, PSA14_1, PTB1_FN),
- PINMUX_DATA(KEYOUT3_MARK, PSA15_0, PSA14_1, PTB0_FN),
-
- /* PTC FN */
- PINMUX_DATA(LCDD7_MARK, PSD5_0, PTC7_FN),
- PINMUX_DATA(LCDD6_MARK, PSD5_0, PTC6_FN),
- PINMUX_DATA(LCDD5_MARK, PSD5_0, PTC5_FN),
- PINMUX_DATA(LCDD4_MARK, PSD5_0, PTC4_FN),
- PINMUX_DATA(LCDD3_MARK, PSD5_0, PTC3_FN),
- PINMUX_DATA(LCDD2_MARK, PSD5_0, PTC2_FN),
- PINMUX_DATA(LCDD1_MARK, PSD5_0, PTC1_FN),
- PINMUX_DATA(LCDD0_MARK, PSD5_0, PTC0_FN),
-
- /* PTD FN */
- PINMUX_DATA(LCDD15_MARK, PSD5_0, PTD7_FN),
- PINMUX_DATA(LCDD14_MARK, PSD5_0, PTD6_FN),
- PINMUX_DATA(LCDD13_MARK, PSD5_0, PTD5_FN),
- PINMUX_DATA(LCDD12_MARK, PSD5_0, PTD4_FN),
- PINMUX_DATA(LCDD11_MARK, PSD5_0, PTD3_FN),
- PINMUX_DATA(LCDD10_MARK, PSD5_0, PTD2_FN),
- PINMUX_DATA(LCDD9_MARK, PSD5_0, PTD1_FN),
- PINMUX_DATA(LCDD8_MARK, PSD5_0, PTD0_FN),
-
- /* PTE FN */
- PINMUX_DATA(FSIMCKB_MARK, PTE7_FN),
- PINMUX_DATA(FSIMCKA_MARK, PTE6_FN),
-
- PINMUX_DATA(LCDD21_MARK, PSC5_0, PSC4_0, PTE5_FN),
- PINMUX_DATA(LCDD20_MARK, PSD3_0, PSD2_0, PTE4_FN),
- PINMUX_DATA(LCDD19_MARK, PSA3_0, PSA2_0, PTE3_FN),
- PINMUX_DATA(LCDD18_MARK, PSA3_0, PSA2_0, PTE2_FN),
- PINMUX_DATA(LCDD17_MARK, PSD5_0, PTE1_FN),
- PINMUX_DATA(LCDD16_MARK, PSD5_0, PTE0_FN),
-
- PINMUX_DATA(SCIF2_L_TXD_MARK, PSC5_0, PSC4_1, PTE5_FN),
- PINMUX_DATA(SCIF4_SCK_MARK, PSD3_0, PSD2_1, PTE4_FN),
- PINMUX_DATA(SCIF4_RXD_MARK, PSA3_0, PSA2_1, PTE3_FN),
- PINMUX_DATA(SCIF4_TXD_MARK, PSA3_0, PSA2_1, PTE2_FN),
-
- /* PTF FN */
- PINMUX_DATA(LCDVSYN_MARK, PSD8_0, PTF7_FN),
- PINMUX_DATA(LCDDISP_MARK, PSD10_0, PSD9_0, PTF6_FN),
- PINMUX_DATA(LCDHSYN_MARK, PSD10_0, PSD9_0, PTF5_FN),
- PINMUX_DATA(LCDDON_MARK, PSD8_0, PTF4_FN),
- PINMUX_DATA(LCDDCK_MARK, PSD10_0, PSD9_0, PTF3_FN),
- PINMUX_DATA(LCDVEPWC_MARK, PSA6_0, PTF2_FN),
- PINMUX_DATA(LCDD23_MARK, PSC7_0, PSC6_0, PTF1_FN),
- PINMUX_DATA(LCDD22_MARK, PSC5_0, PSC4_0, PTF0_FN),
-
- PINMUX_DATA(LCDRS_MARK, PSD10_0, PSD9_1, PTF6_FN),
- PINMUX_DATA(LCDCS_MARK, PSD10_0, PSD9_1, PTF5_FN),
- PINMUX_DATA(LCDWR_MARK, PSD10_0, PSD9_1, PTF3_FN),
-
- PINMUX_DATA(SCIF0_TXD_MARK, PSA6_1, PTF2_FN),
- PINMUX_DATA(SCIF2_L_SCK_MARK, PSC7_0, PSC6_1, PTF1_FN),
- PINMUX_DATA(SCIF2_L_RXD_MARK, PSC5_0, PSC4_1, PTF0_FN),
-
- /* PTG FN */
- PINMUX_DATA(AUDCK_MARK, PTG5_FN),
- PINMUX_DATA(AUDSYNC_MARK, PTG4_FN),
- PINMUX_DATA(AUDATA3_MARK, PTG3_FN),
- PINMUX_DATA(AUDATA2_MARK, PTG2_FN),
- PINMUX_DATA(AUDATA1_MARK, PTG1_FN),
- PINMUX_DATA(AUDATA0_MARK, PTG0_FN),
-
- /* PTH FN */
- PINMUX_DATA(VIO0_VD_MARK, PTH7_FN),
- PINMUX_DATA(VIO0_CLK_MARK, PTH6_FN),
- PINMUX_DATA(VIO0_D7_MARK, PTH5_FN),
- PINMUX_DATA(VIO0_D6_MARK, PTH4_FN),
- PINMUX_DATA(VIO0_D5_MARK, PTH3_FN),
- PINMUX_DATA(VIO0_D4_MARK, PTH2_FN),
- PINMUX_DATA(VIO0_D3_MARK, PTH1_FN),
- PINMUX_DATA(VIO0_D2_MARK, PTH0_FN),
-
- /* PTJ FN */
- PINMUX_DATA(PDSTATUS_MARK, PTJ7_FN),
- PINMUX_DATA(STATUS2_MARK, PTJ6_FN),
- PINMUX_DATA(STATUS0_MARK, PTJ5_FN),
- PINMUX_DATA(A25_MARK, PSA8_0, PTJ3_FN),
- PINMUX_DATA(BS_MARK, PSA8_1, PTJ3_FN),
- PINMUX_DATA(A24_MARK, PTJ2_FN),
- PINMUX_DATA(A23_MARK, PTJ1_FN),
- PINMUX_DATA(A22_MARK, PTJ0_FN),
-
- /* PTK FN */
- PINMUX_DATA(VIO1_D5_MARK, PSB7_0, PSB6_0, PTK7_FN),
- PINMUX_DATA(VIO1_D4_MARK, PSB7_0, PSB6_0, PTK6_FN),
- PINMUX_DATA(VIO1_D3_MARK, PSB7_0, PSB6_0, PTK5_FN),
- PINMUX_DATA(VIO1_D2_MARK, PSB7_0, PSB6_0, PTK4_FN),
- PINMUX_DATA(VIO1_D1_MARK, PSB7_0, PSB6_0, PTK3_FN),
- PINMUX_DATA(VIO1_D0_MARK, PSB7_0, PSB6_0, PTK2_FN),
-
- PINMUX_DATA(VIO0_D13_MARK, PSB7_0, PSB6_1, PTK7_FN),
- PINMUX_DATA(VIO0_D12_MARK, PSB7_0, PSB6_1, PTK6_FN),
- PINMUX_DATA(VIO0_D11_MARK, PSB7_0, PSB6_1, PTK5_FN),
- PINMUX_DATA(VIO0_D10_MARK, PSB7_0, PSB6_1, PTK4_FN),
- PINMUX_DATA(VIO0_D9_MARK, PSB7_0, PSB6_1, PTK3_FN),
- PINMUX_DATA(VIO0_D8_MARK, PSB7_0, PSB6_1, PTK2_FN),
-
- PINMUX_DATA(IDED5_MARK, PSB7_1, PSB6_0, PTK7_FN),
- PINMUX_DATA(IDED4_MARK, PSB7_1, PSB6_0, PTK6_FN),
- PINMUX_DATA(IDED3_MARK, PSB7_1, PSB6_0, PTK5_FN),
- PINMUX_DATA(IDED2_MARK, PSB7_1, PSB6_0, PTK4_FN),
- PINMUX_DATA(IDED1_MARK, PSB7_1, PSB6_0, PTK3_FN),
- PINMUX_DATA(IDED0_MARK, PSB7_1, PSB6_0, PTK2_FN),
-
- PINMUX_DATA(VIO0_FLD_MARK, PTK1_FN),
- PINMUX_DATA(VIO0_HD_MARK, PTK0_FN),
-
- /* PTL FN */
- PINMUX_DATA(DV_D5_MARK, PSB9_0, PSB8_0, PTL7_FN),
- PINMUX_DATA(DV_D4_MARK, PSB9_0, PSB8_0, PTL6_FN),
- PINMUX_DATA(DV_D3_MARK, PSE7_0, PSE6_0, PTL5_FN),
- PINMUX_DATA(DV_D2_MARK, PSC9_0, PSC8_0, PTL4_FN),
- PINMUX_DATA(DV_D1_MARK, PSC9_0, PSC8_0, PTL3_FN),
- PINMUX_DATA(DV_D0_MARK, PSC9_0, PSC8_0, PTL2_FN),
- PINMUX_DATA(DV_D15_MARK, PSD4_0, PTL1_FN),
- PINMUX_DATA(DV_D14_MARK, PSE5_0, PSE4_0, PTL0_FN),
-
- PINMUX_DATA(SCIF3_V_SCK_MARK, PSB9_0, PSB8_1, PTL7_FN),
- PINMUX_DATA(SCIF3_V_RXD_MARK, PSB9_0, PSB8_1, PTL6_FN),
- PINMUX_DATA(SCIF3_V_TXD_MARK, PSE7_0, PSE6_1, PTL5_FN),
- PINMUX_DATA(SCIF1_SCK_MARK, PSC9_0, PSC8_1, PTL4_FN),
- PINMUX_DATA(SCIF1_RXD_MARK, PSC9_0, PSC8_1, PTL3_FN),
- PINMUX_DATA(SCIF1_TXD_MARK, PSC9_0, PSC8_1, PTL2_FN),
-
- PINMUX_DATA(RMII_RXD0_MARK, PSB9_1, PSB8_0, PTL7_FN),
- PINMUX_DATA(RMII_RXD1_MARK, PSB9_1, PSB8_0, PTL6_FN),
- PINMUX_DATA(RMII_REF_CLK_MARK, PSE7_1, PSE6_0, PTL5_FN),
- PINMUX_DATA(RMII_TX_EN_MARK, PSC9_1, PSC8_0, PTL4_FN),
- PINMUX_DATA(RMII_TXD0_MARK, PSC9_1, PSC8_0, PTL3_FN),
- PINMUX_DATA(RMII_TXD1_MARK, PSC9_1, PSC8_0, PTL2_FN),
-
- PINMUX_DATA(MSIOF0_MCK_MARK, PSE5_0, PSE4_1, PTL0_FN),
-
- /* PTM FN */
- PINMUX_DATA(DV_D13_MARK, PSC13_0, PSC12_0, PTM7_FN),
- PINMUX_DATA(DV_D12_MARK, PSC13_0, PSC12_0, PTM6_FN),
- PINMUX_DATA(DV_D11_MARK, PSC13_0, PSC12_0, PTM5_FN),
- PINMUX_DATA(DV_D10_MARK, PSC13_0, PSC12_0, PTM4_FN),
- PINMUX_DATA(DV_D9_MARK, PSC11_0, PSC10_0, PTM3_FN),
- PINMUX_DATA(DV_D8_MARK, PSC11_0, PSC10_0, PTM2_FN),
-
- PINMUX_DATA(MSIOF0_TSCK_MARK, PSC13_0, PSC12_1, PTM7_FN),
- PINMUX_DATA(MSIOF0_RXD_MARK, PSC13_0, PSC12_1, PTM6_FN),
- PINMUX_DATA(MSIOF0_TXD_MARK, PSC13_0, PSC12_1, PTM5_FN),
- PINMUX_DATA(MSIOF0_TSYNC_MARK, PSC13_0, PSC12_1, PTM4_FN),
- PINMUX_DATA(MSIOF0_SS1_MARK, PSC11_0, PSC10_1, PTM3_FN),
- PINMUX_DATA(MSIOF0_RSCK_MARK, PSC11_1, PSC10_0, PTM3_FN),
- PINMUX_DATA(MSIOF0_SS2_MARK, PSC11_0, PSC10_1, PTM2_FN),
- PINMUX_DATA(MSIOF0_RSYNC_MARK, PSC11_1, PSC10_0, PTM2_FN),
-
- PINMUX_DATA(LCDVCPWC_MARK, PSA6_0, PTM1_FN),
- PINMUX_DATA(LCDRD_MARK, PSA7_0, PTM0_FN),
-
- PINMUX_DATA(SCIF0_RXD_MARK, PSA6_1, PTM1_FN),
- PINMUX_DATA(SCIF0_SCK_MARK, PSA7_1, PTM0_FN),
-
- /* PTN FN */
- PINMUX_DATA(VIO0_D1_MARK, PTN7_FN),
- PINMUX_DATA(VIO0_D0_MARK, PTN6_FN),
-
- PINMUX_DATA(DV_CLKI_MARK, PSD11_0, PTN5_FN),
- PINMUX_DATA(DV_CLK_MARK, PSD13_0, PSD12_0, PTN4_FN),
- PINMUX_DATA(DV_VSYNC_MARK, PSD15_0, PSD14_0, PTN3_FN),
- PINMUX_DATA(DV_HSYNC_MARK, PSB5_0, PSB4_0, PTN2_FN),
- PINMUX_DATA(DV_D7_MARK, PSB3_0, PSB2_0, PTN1_FN),
- PINMUX_DATA(DV_D6_MARK, PSB1_0, PSB0_0, PTN0_FN),
-
- PINMUX_DATA(SCIF2_V_SCK_MARK, PSD13_0, PSD12_1, PTN4_FN),
- PINMUX_DATA(SCIF2_V_RXD_MARK, PSD15_0, PSD14_1, PTN3_FN),
- PINMUX_DATA(SCIF2_V_TXD_MARK, PSB5_0, PSB4_1, PTN2_FN),
- PINMUX_DATA(SCIF3_V_CTS_MARK, PSB3_0, PSB2_1, PTN1_FN),
- PINMUX_DATA(SCIF3_V_RTS_MARK, PSB1_0, PSB0_1, PTN0_FN),
-
- PINMUX_DATA(RMII_RX_ER_MARK, PSB3_1, PSB2_0, PTN1_FN),
- PINMUX_DATA(RMII_CRS_DV_MARK, PSB1_1, PSB0_0, PTN0_FN),
-
- /* PTQ FN */
- PINMUX_DATA(D7_MARK, PTQ7_FN),
- PINMUX_DATA(D6_MARK, PTQ6_FN),
- PINMUX_DATA(D5_MARK, PTQ5_FN),
- PINMUX_DATA(D4_MARK, PTQ4_FN),
- PINMUX_DATA(D3_MARK, PTQ3_FN),
- PINMUX_DATA(D2_MARK, PTQ2_FN),
- PINMUX_DATA(D1_MARK, PTQ1_FN),
- PINMUX_DATA(D0_MARK, PTQ0_FN),
-
- /* PTR FN */
- PINMUX_DATA(CS6B_CE1B_MARK, PTR7_FN),
- PINMUX_DATA(CS6A_CE2B_MARK, PTR6_FN),
- PINMUX_DATA(CS5B_CE1A_MARK, PTR5_FN),
- PINMUX_DATA(CS5A_CE2A_MARK, PTR4_FN),
- PINMUX_DATA(IOIS16_MARK, PSA5_0, PTR3_FN),
- PINMUX_DATA(WAIT_MARK, PTR2_FN),
- PINMUX_DATA(WE3_ICIOWR_MARK, PSA1_0, PSA0_0, PTR1_FN),
- PINMUX_DATA(WE2_ICIORD_MARK, PSD1_0, PSD0_0, PTR0_FN),
-
- PINMUX_DATA(LCDLCLK_MARK, PSA5_1, PTR3_FN),
-
- PINMUX_DATA(IDEA2_MARK, PSD1_1, PSD0_0, PTR0_FN),
-
- PINMUX_DATA(TPUTO3_MARK, PSA1_0, PSA0_1, PTR1_FN),
- PINMUX_DATA(TPUTI3_MARK, PSA1_1, PSA0_0, PTR1_FN),
- PINMUX_DATA(TPUTO2_MARK, PSD1_0, PSD0_1, PTR0_FN),
-
- /* PTS FN */
- PINMUX_DATA(VIO_CKO_MARK, PTS6_FN),
-
- PINMUX_DATA(TPUTI2_MARK, PSE9_0, PSE8_1, PTS5_FN),
-
- PINMUX_DATA(IDEIORDY_MARK, PSE9_1, PSE8_0, PTS5_FN),
-
- PINMUX_DATA(VIO1_FLD_MARK, PSE9_0, PSE8_0, PTS5_FN),
- PINMUX_DATA(VIO1_HD_MARK, PSA10_0, PTS4_FN),
- PINMUX_DATA(VIO1_VD_MARK, PSA9_0, PTS3_FN),
- PINMUX_DATA(VIO1_CLK_MARK, PSA9_0, PTS2_FN),
- PINMUX_DATA(VIO1_D7_MARK, PSB7_0, PSB6_0, PTS1_FN),
- PINMUX_DATA(VIO1_D6_MARK, PSB7_0, PSB6_0, PTS0_FN),
-
- PINMUX_DATA(SCIF5_SCK_MARK, PSA10_1, PTS4_FN),
- PINMUX_DATA(SCIF5_RXD_MARK, PSA9_1, PTS3_FN),
- PINMUX_DATA(SCIF5_TXD_MARK, PSA9_1, PTS2_FN),
-
- PINMUX_DATA(VIO0_D15_MARK, PSB7_0, PSB6_1, PTS1_FN),
- PINMUX_DATA(VIO0_D14_MARK, PSB7_0, PSB6_1, PTS0_FN),
-
- PINMUX_DATA(IDED7_MARK, PSB7_1, PSB6_0, PTS1_FN),
- PINMUX_DATA(IDED6_MARK, PSB7_1, PSB6_0, PTS0_FN),
-
- /* PTT FN */
- PINMUX_DATA(D15_MARK, PTT7_FN),
- PINMUX_DATA(D14_MARK, PTT6_FN),
- PINMUX_DATA(D13_MARK, PTT5_FN),
- PINMUX_DATA(D12_MARK, PTT4_FN),
- PINMUX_DATA(D11_MARK, PTT3_FN),
- PINMUX_DATA(D10_MARK, PTT2_FN),
- PINMUX_DATA(D9_MARK, PTT1_FN),
- PINMUX_DATA(D8_MARK, PTT0_FN),
-
- /* PTU FN */
- PINMUX_DATA(DMAC_DACK0_MARK, PTU7_FN),
- PINMUX_DATA(DMAC_DREQ0_MARK, PTU6_FN),
-
- PINMUX_DATA(FSIOASD_MARK, PSE1_0, PTU5_FN),
- PINMUX_DATA(FSIIABCK_MARK, PSE1_0, PTU4_FN),
- PINMUX_DATA(FSIIALRCK_MARK, PSE1_0, PTU3_FN),
- PINMUX_DATA(FSIOABCK_MARK, PSE1_0, PTU2_FN),
- PINMUX_DATA(FSIOALRCK_MARK, PSE1_0, PTU1_FN),
- PINMUX_DATA(CLKAUDIOAO_MARK, PSE0_0, PTU0_FN),
-
- /* PTV FN */
- PINMUX_DATA(FSIIBSD_MARK, PSD7_0, PSD6_0, PTV7_FN),
- PINMUX_DATA(FSIOBSD_MARK, PSD7_0, PSD6_0, PTV6_FN),
- PINMUX_DATA(FSIIBBCK_MARK, PSC15_0, PSC14_0, PTV5_FN),
- PINMUX_DATA(FSIIBLRCK_MARK, PSC15_0, PSC14_0, PTV4_FN),
- PINMUX_DATA(FSIOBBCK_MARK, PSC15_0, PSC14_0, PTV3_FN),
- PINMUX_DATA(FSIOBLRCK_MARK, PSC15_0, PSC14_0, PTV2_FN),
- PINMUX_DATA(CLKAUDIOBO_MARK, PSE3_0, PSE2_0, PTV1_FN),
- PINMUX_DATA(FSIIASD_MARK, PSE10_0, PTV0_FN),
-
- PINMUX_DATA(MSIOF1_SS2_MARK, PSD7_0, PSD6_1, PTV7_FN),
- PINMUX_DATA(MSIOF1_RSYNC_MARK, PSD7_1, PSD6_0, PTV7_FN),
- PINMUX_DATA(MSIOF1_SS1_MARK, PSD7_0, PSD6_1, PTV6_FN),
- PINMUX_DATA(MSIOF1_RSCK_MARK, PSD7_1, PSD6_0, PTV6_FN),
- PINMUX_DATA(MSIOF1_RXD_MARK, PSC15_0, PSC14_1, PTV5_FN),
- PINMUX_DATA(MSIOF1_TSYNC_MARK, PSC15_0, PSC14_1, PTV4_FN),
- PINMUX_DATA(MSIOF1_TSCK_MARK, PSC15_0, PSC14_1, PTV3_FN),
- PINMUX_DATA(MSIOF1_TXD_MARK, PSC15_0, PSC14_1, PTV2_FN),
- PINMUX_DATA(MSIOF1_MCK_MARK, PSE3_0, PSE2_1, PTV1_FN),
-
- /* PTW FN */
- PINMUX_DATA(MMC_D7_MARK, PSE13_0, PSE12_0, PTW7_FN),
- PINMUX_DATA(MMC_D6_MARK, PSE13_0, PSE12_0, PTW6_FN),
- PINMUX_DATA(MMC_D5_MARK, PSE13_0, PSE12_0, PTW5_FN),
- PINMUX_DATA(MMC_D4_MARK, PSE13_0, PSE12_0, PTW4_FN),
- PINMUX_DATA(MMC_D3_MARK, PSA13_0, PTW3_FN),
- PINMUX_DATA(MMC_D2_MARK, PSA13_0, PTW2_FN),
- PINMUX_DATA(MMC_D1_MARK, PSA13_0, PTW1_FN),
- PINMUX_DATA(MMC_D0_MARK, PSA13_0, PTW0_FN),
-
- PINMUX_DATA(SDHI1CD_MARK, PSE13_0, PSE12_1, PTW7_FN),
- PINMUX_DATA(SDHI1WP_MARK, PSE13_0, PSE12_1, PTW6_FN),
- PINMUX_DATA(SDHI1D3_MARK, PSE13_0, PSE12_1, PTW5_FN),
- PINMUX_DATA(SDHI1D2_MARK, PSE13_0, PSE12_1, PTW4_FN),
- PINMUX_DATA(SDHI1D1_MARK, PSA13_1, PTW3_FN),
- PINMUX_DATA(SDHI1D0_MARK, PSA13_1, PTW2_FN),
- PINMUX_DATA(SDHI1CMD_MARK, PSA13_1, PTW1_FN),
- PINMUX_DATA(SDHI1CLK_MARK, PSA13_1, PTW0_FN),
-
- PINMUX_DATA(IODACK_MARK, PSE13_1, PSE12_0, PTW7_FN),
- PINMUX_DATA(IDERST_MARK, PSE13_1, PSE12_0, PTW6_FN),
- PINMUX_DATA(EXBUF_ENB_MARK, PSE13_1, PSE12_0, PTW5_FN),
- PINMUX_DATA(DIRECTION_MARK, PSE13_1, PSE12_0, PTW4_FN),
-
- /* PTX FN */
- PINMUX_DATA(DMAC_DACK1_MARK, PSA12_0, PTX7_FN),
- PINMUX_DATA(DMAC_DREQ1_MARK, PSA12_0, PTX6_FN),
-
- PINMUX_DATA(IRDA_OUT_MARK, PSA12_1, PTX7_FN),
- PINMUX_DATA(IRDA_IN_MARK, PSA12_1, PTX6_FN),
-
- PINMUX_DATA(TSIF_TS0_SDAT_MARK, PSC0_0, PTX5_FN),
- PINMUX_DATA(TSIF_TS0_SCK_MARK, PSC1_0, PTX4_FN),
- PINMUX_DATA(TSIF_TS0_SDEN_MARK, PSC2_0, PTX3_FN),
- PINMUX_DATA(TSIF_TS0_SPSYNC_MARK, PTX2_FN),
-
- PINMUX_DATA(LNKSTA_MARK, PSC0_1, PTX5_FN),
- PINMUX_DATA(MDIO_MARK, PSC1_1, PTX4_FN),
- PINMUX_DATA(MDC_MARK, PSC2_1, PTX3_FN),
-
- PINMUX_DATA(MMC_CLK_MARK, PTX1_FN),
- PINMUX_DATA(MMC_CMD_MARK, PTX0_FN),
-
- /* PTY FN */
- PINMUX_DATA(SDHI0CD_MARK, PTY7_FN),
- PINMUX_DATA(SDHI0WP_MARK, PTY6_FN),
- PINMUX_DATA(SDHI0D3_MARK, PTY5_FN),
- PINMUX_DATA(SDHI0D2_MARK, PTY4_FN),
- PINMUX_DATA(SDHI0D1_MARK, PTY3_FN),
- PINMUX_DATA(SDHI0D0_MARK, PTY2_FN),
- PINMUX_DATA(SDHI0CMD_MARK, PTY1_FN),
- PINMUX_DATA(SDHI0CLK_MARK, PTY0_FN),
-
- /* PTZ FN */
- PINMUX_DATA(INTC_IRQ7_MARK, PSB10_0, PTZ7_FN),
- PINMUX_DATA(INTC_IRQ6_MARK, PSB11_0, PTZ6_FN),
- PINMUX_DATA(INTC_IRQ5_MARK, PSB12_0, PTZ5_FN),
- PINMUX_DATA(INTC_IRQ4_MARK, PSB13_0, PTZ4_FN),
- PINMUX_DATA(INTC_IRQ3_MARK, PSB14_0, PTZ3_FN),
- PINMUX_DATA(INTC_IRQ2_MARK, PTZ2_FN),
- PINMUX_DATA(INTC_IRQ1_MARK, PTZ1_FN),
- PINMUX_DATA(INTC_IRQ0_MARK, PTZ0_FN),
-
- PINMUX_DATA(SCIF3_I_CTS_MARK, PSB10_1, PTZ7_FN),
- PINMUX_DATA(SCIF3_I_RTS_MARK, PSB11_1, PTZ6_FN),
- PINMUX_DATA(SCIF3_I_SCK_MARK, PSB12_1, PTZ5_FN),
- PINMUX_DATA(SCIF3_I_RXD_MARK, PSB13_1, PTZ4_FN),
- PINMUX_DATA(SCIF3_I_TXD_MARK, PSB14_1, PTZ3_FN),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
- /* PTA */
- PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
- PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
- PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
- PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
- PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
- PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
- PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
- PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
-
- /* PTB */
- PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
- PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
- PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
- PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
- PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
- PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
- PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
- PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
-
- /* PTC */
- PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
- PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
- PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
- PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
- PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
- PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
- PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
- PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
-
- /* PTD */
- PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
- PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
- PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
- PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
- PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
- PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
- PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
- PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
-
- /* PTE */
- PINMUX_GPIO(GPIO_PTE7, PTE7_DATA),
- PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
- PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
- PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
- PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
- PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
- PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
- PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
-
- /* PTF */
- PINMUX_GPIO(GPIO_PTF7, PTF7_DATA),
- PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
- PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
- PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
- PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
- PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
- PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
- PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
-
- /* PTG */
- PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
- PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
- PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
- PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
- PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
- PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
-
- /* PTH */
- PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
- PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
- PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
- PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
- PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
- PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
- PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
- PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
-
- /* PTJ */
- PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
- PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
- PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
- PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
- PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
- PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
- PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
-
- /* PTK */
- PINMUX_GPIO(GPIO_PTK7, PTK7_DATA),
- PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
- PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
- PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
- PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
- PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
- PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
- PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
-
- /* PTL */
- PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
- PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
- PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
- PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
- PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
- PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
- PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
- PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
-
- /* PTM */
- PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
- PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
- PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
- PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
- PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
- PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
- PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
- PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
-
- /* PTN */
- PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
- PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
- PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
- PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
- PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
- PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
- PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
- PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
-
- /* PTQ */
- PINMUX_GPIO(GPIO_PTQ7, PTQ7_DATA),
- PINMUX_GPIO(GPIO_PTQ6, PTQ6_DATA),
- PINMUX_GPIO(GPIO_PTQ5, PTQ5_DATA),
- PINMUX_GPIO(GPIO_PTQ4, PTQ4_DATA),
- PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
- PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
- PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
- PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
-
- /* PTR */
- PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
- PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
- PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
- PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
- PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
- PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
- PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
- PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
-
- /* PTS */
- PINMUX_GPIO(GPIO_PTS6, PTS6_DATA),
- PINMUX_GPIO(GPIO_PTS5, PTS5_DATA),
- PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
- PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
- PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
- PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
- PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
-
- /* PTT */
- PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
- PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
- PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
- PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
- PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
- PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
- PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
- PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
-
- /* PTU */
- PINMUX_GPIO(GPIO_PTU7, PTU7_DATA),
- PINMUX_GPIO(GPIO_PTU6, PTU6_DATA),
- PINMUX_GPIO(GPIO_PTU5, PTU5_DATA),
- PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
- PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
- PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
- PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
- PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
-
- /* PTV */
- PINMUX_GPIO(GPIO_PTV7, PTV7_DATA),
- PINMUX_GPIO(GPIO_PTV6, PTV6_DATA),
- PINMUX_GPIO(GPIO_PTV5, PTV5_DATA),
- PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
- PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
- PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
- PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
- PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
-
- /* PTW */
- PINMUX_GPIO(GPIO_PTW7, PTW7_DATA),
- PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
- PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
- PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
- PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
- PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
- PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
- PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
-
- /* PTX */
- PINMUX_GPIO(GPIO_PTX7, PTX7_DATA),
- PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
- PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
- PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
- PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
- PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
- PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
- PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
-
- /* PTY */
- PINMUX_GPIO(GPIO_PTY7, PTY7_DATA),
- PINMUX_GPIO(GPIO_PTY6, PTY6_DATA),
- PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
- PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
- PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
- PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
- PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
- PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
-
- /* PTZ */
- PINMUX_GPIO(GPIO_PTZ7, PTZ7_DATA),
- PINMUX_GPIO(GPIO_PTZ6, PTZ6_DATA),
- PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
- PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
- PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
- PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
- PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
- PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
-
- /* BSC */
- PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
- PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
- PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
- PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
- PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
- PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
- PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
- PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
- PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
- PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
- PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
- PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
- PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
- PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
- PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
- PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
- PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
- PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
- PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
- PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
- PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
- PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
- PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
- PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
- PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
- PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
- PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
- PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
- PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
- PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
- PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
- PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
- PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
- PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
- PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
- PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
- PINMUX_GPIO(GPIO_FN_CS6B_CE1B, CS6B_CE1B_MARK),
- PINMUX_GPIO(GPIO_FN_CS6A_CE2B, CS6A_CE2B_MARK),
- PINMUX_GPIO(GPIO_FN_CS5B_CE1A, CS5B_CE1A_MARK),
- PINMUX_GPIO(GPIO_FN_CS5A_CE2A, CS5A_CE2A_MARK),
- PINMUX_GPIO(GPIO_FN_WE3_ICIOWR, WE3_ICIOWR_MARK),
- PINMUX_GPIO(GPIO_FN_WE2_ICIORD, WE2_ICIORD_MARK),
- PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
- PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
- PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
-
- /* KEYSC */
- PINMUX_GPIO(GPIO_FN_KEYOUT5_IN5, KEYOUT5_IN5_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT4_IN6, KEYOUT4_IN6_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN4, KEYIN4_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN3, KEYIN3_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN2, KEYIN2_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN1, KEYIN1_MARK),
- PINMUX_GPIO(GPIO_FN_KEYIN0, KEYIN0_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT3, KEYOUT3_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT2, KEYOUT2_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT1, KEYOUT1_MARK),
- PINMUX_GPIO(GPIO_FN_KEYOUT0, KEYOUT0_MARK),
-
- /* ATAPI */
- PINMUX_GPIO(GPIO_FN_IDED15, IDED15_MARK),
- PINMUX_GPIO(GPIO_FN_IDED14, IDED14_MARK),
- PINMUX_GPIO(GPIO_FN_IDED13, IDED13_MARK),
- PINMUX_GPIO(GPIO_FN_IDED12, IDED12_MARK),
- PINMUX_GPIO(GPIO_FN_IDED11, IDED11_MARK),
- PINMUX_GPIO(GPIO_FN_IDED10, IDED10_MARK),
- PINMUX_GPIO(GPIO_FN_IDED9, IDED9_MARK),
- PINMUX_GPIO(GPIO_FN_IDED8, IDED8_MARK),
- PINMUX_GPIO(GPIO_FN_IDED7, IDED7_MARK),
- PINMUX_GPIO(GPIO_FN_IDED6, IDED6_MARK),
- PINMUX_GPIO(GPIO_FN_IDED5, IDED5_MARK),
- PINMUX_GPIO(GPIO_FN_IDED4, IDED4_MARK),
- PINMUX_GPIO(GPIO_FN_IDED3, IDED3_MARK),
- PINMUX_GPIO(GPIO_FN_IDED2, IDED2_MARK),
- PINMUX_GPIO(GPIO_FN_IDED1, IDED1_MARK),
- PINMUX_GPIO(GPIO_FN_IDED0, IDED0_MARK),
- PINMUX_GPIO(GPIO_FN_IDEA2, IDEA2_MARK),
- PINMUX_GPIO(GPIO_FN_IDEA1, IDEA1_MARK),
- PINMUX_GPIO(GPIO_FN_IDEA0, IDEA0_MARK),
- PINMUX_GPIO(GPIO_FN_IDEIOWR, IDEIOWR_MARK),
- PINMUX_GPIO(GPIO_FN_IODREQ, IODREQ_MARK),
- PINMUX_GPIO(GPIO_FN_IDECS0, IDECS0_MARK),
- PINMUX_GPIO(GPIO_FN_IDECS1, IDECS1_MARK),
- PINMUX_GPIO(GPIO_FN_IDEIORD, IDEIORD_MARK),
- PINMUX_GPIO(GPIO_FN_DIRECTION, DIRECTION_MARK),
- PINMUX_GPIO(GPIO_FN_EXBUF_ENB, EXBUF_ENB_MARK),
- PINMUX_GPIO(GPIO_FN_IDERST, IDERST_MARK),
- PINMUX_GPIO(GPIO_FN_IODACK, IODACK_MARK),
- PINMUX_GPIO(GPIO_FN_IDEINT, IDEINT_MARK),
- PINMUX_GPIO(GPIO_FN_IDEIORDY, IDEIORDY_MARK),
-
- /* TPU */
- PINMUX_GPIO(GPIO_FN_TPUTO3, TPUTO3_MARK),
- PINMUX_GPIO(GPIO_FN_TPUTO2, TPUTO2_MARK),
- PINMUX_GPIO(GPIO_FN_TPUTO1, TPUTO1_MARK),
- PINMUX_GPIO(GPIO_FN_TPUTO0, TPUTO0_MARK),
- PINMUX_GPIO(GPIO_FN_TPUTI3, TPUTI3_MARK),
- PINMUX_GPIO(GPIO_FN_TPUTI2, TPUTI2_MARK),
-
- /* LCDC */
- PINMUX_GPIO(GPIO_FN_LCDD23, LCDD23_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD22, LCDD22_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD21, LCDD21_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD20, LCDD20_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD19, LCDD19_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD18, LCDD18_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD17, LCDD17_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD16, LCDD16_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD15, LCDD15_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD14, LCDD14_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD13, LCDD13_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD12, LCDD12_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD11, LCDD11_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD10, LCDD10_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD9, LCDD9_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD8, LCDD8_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD7, LCDD7_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD6, LCDD6_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD5, LCDD5_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD4, LCDD4_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD3, LCDD3_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD2, LCDD2_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD1, LCDD1_MARK),
- PINMUX_GPIO(GPIO_FN_LCDD0, LCDD0_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVSYN, LCDVSYN_MARK),
- PINMUX_GPIO(GPIO_FN_LCDDISP, LCDDISP_MARK),
- PINMUX_GPIO(GPIO_FN_LCDRS, LCDRS_MARK),
- PINMUX_GPIO(GPIO_FN_LCDHSYN, LCDHSYN_MARK),
- PINMUX_GPIO(GPIO_FN_LCDCS, LCDCS_MARK),
- PINMUX_GPIO(GPIO_FN_LCDDON, LCDDON_MARK),
- PINMUX_GPIO(GPIO_FN_LCDDCK, LCDDCK_MARK),
- PINMUX_GPIO(GPIO_FN_LCDWR, LCDWR_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVEPWC, LCDVEPWC_MARK),
- PINMUX_GPIO(GPIO_FN_LCDVCPWC, LCDVCPWC_MARK),
- PINMUX_GPIO(GPIO_FN_LCDRD, LCDRD_MARK),
- PINMUX_GPIO(GPIO_FN_LCDLCLK, LCDLCLK_MARK),
-
- /* SCIF0 */
- PINMUX_GPIO(GPIO_FN_SCIF0_TXD, SCIF0_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_RXD, SCIF0_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_SCK, SCIF0_SCK_MARK),
-
- /* SCIF1 */
- PINMUX_GPIO(GPIO_FN_SCIF1_SCK, SCIF1_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_RXD, SCIF1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_TXD, SCIF1_TXD_MARK),
-
- /* SCIF2 */
- PINMUX_GPIO(GPIO_FN_SCIF2_L_TXD, SCIF2_L_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_L_SCK, SCIF2_L_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_L_RXD, SCIF2_L_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_V_TXD, SCIF2_V_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_V_SCK, SCIF2_V_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_V_RXD, SCIF2_V_RXD_MARK),
-
- /* SCIF3 */
- PINMUX_GPIO(GPIO_FN_SCIF3_V_SCK, SCIF3_V_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_V_RXD, SCIF3_V_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_V_TXD, SCIF3_V_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_V_CTS, SCIF3_V_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_V_RTS, SCIF3_V_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_I_SCK, SCIF3_I_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_I_RXD, SCIF3_I_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_I_TXD, SCIF3_I_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_I_CTS, SCIF3_I_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_I_RTS, SCIF3_I_RTS_MARK),
-
- /* SCIF4 */
- PINMUX_GPIO(GPIO_FN_SCIF4_SCK, SCIF4_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_RXD, SCIF4_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_TXD, SCIF4_TXD_MARK),
-
- /* SCIF5 */
- PINMUX_GPIO(GPIO_FN_SCIF5_SCK, SCIF5_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_RXD, SCIF5_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_TXD, SCIF5_TXD_MARK),
-
- /* FSI */
- PINMUX_GPIO(GPIO_FN_FSIMCKB, FSIMCKB_MARK),
- PINMUX_GPIO(GPIO_FN_FSIMCKA, FSIMCKA_MARK),
- PINMUX_GPIO(GPIO_FN_FSIOASD, FSIOASD_MARK),
- PINMUX_GPIO(GPIO_FN_FSIIABCK, FSIIABCK_MARK),
- PINMUX_GPIO(GPIO_FN_FSIIALRCK, FSIIALRCK_MARK),
- PINMUX_GPIO(GPIO_FN_FSIOABCK, FSIOABCK_MARK),
- PINMUX_GPIO(GPIO_FN_FSIOALRCK, FSIOALRCK_MARK),
- PINMUX_GPIO(GPIO_FN_CLKAUDIOAO, CLKAUDIOAO_MARK),
- PINMUX_GPIO(GPIO_FN_FSIIBSD, FSIIBSD_MARK),
- PINMUX_GPIO(GPIO_FN_FSIOBSD, FSIOBSD_MARK),
- PINMUX_GPIO(GPIO_FN_FSIIBBCK, FSIIBBCK_MARK),
- PINMUX_GPIO(GPIO_FN_FSIIBLRCK, FSIIBLRCK_MARK),
- PINMUX_GPIO(GPIO_FN_FSIOBBCK, FSIOBBCK_MARK),
- PINMUX_GPIO(GPIO_FN_FSIOBLRCK, FSIOBLRCK_MARK),
- PINMUX_GPIO(GPIO_FN_CLKAUDIOBO, CLKAUDIOBO_MARK),
- PINMUX_GPIO(GPIO_FN_FSIIASD, FSIIASD_MARK),
-
- /* AUD */
- PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
- PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
-
- /* VIO */
- PINMUX_GPIO(GPIO_FN_VIO_CKO, VIO_CKO_MARK),
-
- /* VIO0 */
- PINMUX_GPIO(GPIO_FN_VIO0_D15, VIO0_D15_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D14, VIO0_D14_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D13, VIO0_D13_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D12, VIO0_D12_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D11, VIO0_D11_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D10, VIO0_D10_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D9, VIO0_D9_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D8, VIO0_D8_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D7, VIO0_D7_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D6, VIO0_D6_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D5, VIO0_D5_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D4, VIO0_D4_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D3, VIO0_D3_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D2, VIO0_D2_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D1, VIO0_D1_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_D0, VIO0_D0_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_VD, VIO0_VD_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_CLK, VIO0_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_FLD, VIO0_FLD_MARK),
- PINMUX_GPIO(GPIO_FN_VIO0_HD, VIO0_HD_MARK),
-
- /* VIO1 */
- PINMUX_GPIO(GPIO_FN_VIO1_D7, VIO1_D7_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_D6, VIO1_D6_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_D5, VIO1_D5_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_D4, VIO1_D4_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_D3, VIO1_D3_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_D2, VIO1_D2_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_D1, VIO1_D1_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_D0, VIO1_D0_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_FLD, VIO1_FLD_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_HD, VIO1_HD_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_VD, VIO1_VD_MARK),
- PINMUX_GPIO(GPIO_FN_VIO1_CLK, VIO1_CLK_MARK),
-
- /* Eth */
- PINMUX_GPIO(GPIO_FN_RMII_RXD0, RMII_RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_RMII_RXD1, RMII_RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RMII_TXD0, RMII_TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_RMII_TXD1, RMII_TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RMII_REF_CLK, RMII_REF_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_RMII_TX_EN, RMII_TX_EN_MARK),
- PINMUX_GPIO(GPIO_FN_RMII_RX_ER, RMII_RX_ER_MARK),
- PINMUX_GPIO(GPIO_FN_RMII_CRS_DV, RMII_CRS_DV_MARK),
- PINMUX_GPIO(GPIO_FN_LNKSTA, LNKSTA_MARK),
- PINMUX_GPIO(GPIO_FN_MDIO, MDIO_MARK),
- PINMUX_GPIO(GPIO_FN_MDC, MDC_MARK),
-
- /* System */
- PINMUX_GPIO(GPIO_FN_PDSTATUS, PDSTATUS_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS2, STATUS2_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
-
- /* VOU */
- PINMUX_GPIO(GPIO_FN_DV_D15, DV_D15_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D14, DV_D14_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D13, DV_D13_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D12, DV_D12_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D11, DV_D11_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D10, DV_D10_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D9, DV_D9_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D8, DV_D8_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D7, DV_D7_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D6, DV_D6_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D5, DV_D5_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D4, DV_D4_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D3, DV_D3_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D2, DV_D2_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D1, DV_D1_MARK),
- PINMUX_GPIO(GPIO_FN_DV_D0, DV_D0_MARK),
- PINMUX_GPIO(GPIO_FN_DV_CLKI, DV_CLKI_MARK),
- PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
-
- /* MSIOF0 */
- PINMUX_GPIO(GPIO_FN_MSIOF0_RXD, MSIOF0_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_TXD, MSIOF0_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_MCK, MSIOF0_MCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_TSCK, MSIOF0_TSCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_SS1, MSIOF0_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_SS2, MSIOF0_SS2_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_TSYNC, MSIOF0_TSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_RSCK, MSIOF0_RSCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF0_RSYNC, MSIOF0_RSYNC_MARK),
-
- /* MSIOF1 */
- PINMUX_GPIO(GPIO_FN_MSIOF1_RXD, MSIOF1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_TXD, MSIOF1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_MCK, MSIOF1_MCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_TSCK, MSIOF1_TSCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_SS1, MSIOF1_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_SS2, MSIOF1_SS2_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_TSYNC, MSIOF1_TSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_RSCK, MSIOF1_RSCK_MARK),
- PINMUX_GPIO(GPIO_FN_MSIOF1_RSYNC, MSIOF1_RSYNC_MARK),
-
- /* DMAC */
- PINMUX_GPIO(GPIO_FN_DMAC_DACK0, DMAC_DACK0_MARK),
- PINMUX_GPIO(GPIO_FN_DMAC_DREQ0, DMAC_DREQ0_MARK),
- PINMUX_GPIO(GPIO_FN_DMAC_DACK1, DMAC_DACK1_MARK),
- PINMUX_GPIO(GPIO_FN_DMAC_DREQ1, DMAC_DREQ1_MARK),
-
- /* SDHI0 */
- PINMUX_GPIO(GPIO_FN_SDHI0CD, SDHI0CD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0WP, SDHI0WP_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0CMD, SDHI0CMD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0CLK, SDHI0CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D3, SDHI0D3_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D2, SDHI0D2_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D1, SDHI0D1_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI0D0, SDHI0D0_MARK),
-
- /* SDHI1 */
- PINMUX_GPIO(GPIO_FN_SDHI1CD, SDHI1CD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1WP, SDHI1WP_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1CMD, SDHI1CMD_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1CLK, SDHI1CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1D3, SDHI1D3_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1D2, SDHI1D2_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1D1, SDHI1D1_MARK),
- PINMUX_GPIO(GPIO_FN_SDHI1D0, SDHI1D0_MARK),
-
- /* MMC */
- PINMUX_GPIO(GPIO_FN_MMC_D7, MMC_D7_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_D6, MMC_D6_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_D5, MMC_D5_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_D4, MMC_D4_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_D3, MMC_D3_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_D2, MMC_D2_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_D1, MMC_D1_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_D0, MMC_D0_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_CLK, MMC_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_MMC_CMD, MMC_CMD_MARK),
-
- /* IrDA */
- PINMUX_GPIO(GPIO_FN_IRDA_OUT, IRDA_OUT_MARK),
- PINMUX_GPIO(GPIO_FN_IRDA_IN, IRDA_IN_MARK),
-
- /* TSIF */
- PINMUX_GPIO(GPIO_FN_TSIF_TS0_SDAT, TSIF_TS0_SDAT_MARK),
- PINMUX_GPIO(GPIO_FN_TSIF_TS0_SCK, TSIF_TS0_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_TSIF_TS0_SDEN, TSIF_TS0_SDEN_MARK),
- PINMUX_GPIO(GPIO_FN_TSIF_TS0_SPSYNC, TSIF_TS0_SPSYNC_MARK),
-
- /* IRQ */
- PINMUX_GPIO(GPIO_FN_INTC_IRQ7, INTC_IRQ7_MARK),
- PINMUX_GPIO(GPIO_FN_INTC_IRQ6, INTC_IRQ6_MARK),
- PINMUX_GPIO(GPIO_FN_INTC_IRQ5, INTC_IRQ5_MARK),
- PINMUX_GPIO(GPIO_FN_INTC_IRQ4, INTC_IRQ4_MARK),
- PINMUX_GPIO(GPIO_FN_INTC_IRQ3, INTC_IRQ3_MARK),
- PINMUX_GPIO(GPIO_FN_INTC_IRQ2, INTC_IRQ2_MARK),
- PINMUX_GPIO(GPIO_FN_INTC_IRQ1, INTC_IRQ1_MARK),
- PINMUX_GPIO(GPIO_FN_INTC_IRQ0, INTC_IRQ0_MARK),
- };
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- { PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
- PTA7_FN, PTA7_OUT, PTA7_IN_PU, PTA7_IN,
- PTA6_FN, PTA6_OUT, PTA6_IN_PU, PTA6_IN,
- PTA5_FN, PTA5_OUT, PTA5_IN_PU, PTA5_IN,
- PTA4_FN, PTA4_OUT, PTA4_IN_PU, PTA4_IN,
- PTA3_FN, PTA3_OUT, PTA3_IN_PU, PTA3_IN,
- PTA2_FN, PTA2_OUT, PTA2_IN_PU, PTA2_IN,
- PTA1_FN, PTA1_OUT, PTA1_IN_PU, PTA1_IN,
- PTA0_FN, PTA0_OUT, PTA0_IN_PU, PTA0_IN }
- },
- { PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
- PTB7_FN, PTB7_OUT, PTB7_IN_PU, PTB7_IN,
- PTB6_FN, PTB6_OUT, PTB6_IN_PU, PTB6_IN,
- PTB5_FN, PTB5_OUT, PTB5_IN_PU, PTB5_IN,
- PTB4_FN, PTB4_OUT, PTB4_IN_PU, PTB4_IN,
- PTB3_FN, PTB3_OUT, PTB3_IN_PU, PTB3_IN,
- PTB2_FN, PTB2_OUT, PTB2_IN_PU, PTB2_IN,
- PTB1_FN, PTB1_OUT, PTB1_IN_PU, PTB1_IN,
- PTB0_FN, PTB0_OUT, PTB0_IN_PU, PTB0_IN }
- },
- { PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
- PTC7_FN, PTC7_OUT, PTC7_IN_PU, PTC7_IN,
- PTC6_FN, PTC6_OUT, PTC6_IN_PU, PTC6_IN,
- PTC5_FN, PTC5_OUT, PTC5_IN_PU, PTC5_IN,
- PTC4_FN, PTC4_OUT, PTC4_IN_PU, PTC4_IN,
- PTC3_FN, PTC3_OUT, PTC3_IN_PU, PTC3_IN,
- PTC2_FN, PTC2_OUT, PTC2_IN_PU, PTC2_IN,
- PTC1_FN, PTC1_OUT, PTC1_IN_PU, PTC1_IN,
- PTC0_FN, PTC0_OUT, PTC0_IN_PU, PTC0_IN }
- },
- { PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
- PTD7_FN, PTD7_OUT, PTD7_IN_PU, PTD7_IN,
- PTD6_FN, PTD6_OUT, PTD6_IN_PU, PTD6_IN,
- PTD5_FN, PTD5_OUT, PTD5_IN_PU, PTD5_IN,
- PTD4_FN, PTD4_OUT, PTD4_IN_PU, PTD4_IN,
- PTD3_FN, PTD3_OUT, PTD3_IN_PU, PTD3_IN,
- PTD2_FN, PTD2_OUT, PTD2_IN_PU, PTD2_IN,
- PTD1_FN, PTD1_OUT, PTD1_IN_PU, PTD1_IN,
- PTD0_FN, PTD0_OUT, PTD0_IN_PU, PTD0_IN }
- },
- { PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
- PTE7_FN, PTE7_OUT, PTE7_IN_PU, PTE7_IN,
- PTE6_FN, PTE6_OUT, PTE6_IN_PU, PTE6_IN,
- PTE5_FN, PTE5_OUT, PTE5_IN_PU, PTE5_IN,
- PTE4_FN, PTE4_OUT, PTE4_IN_PU, PTE4_IN,
- PTE3_FN, PTE3_OUT, PTE3_IN_PU, PTE3_IN,
- PTE2_FN, PTE2_OUT, PTE2_IN_PU, PTE2_IN,
- PTE1_FN, PTE1_OUT, PTE1_IN_PU, PTE1_IN,
- PTE0_FN, PTE0_OUT, PTE0_IN_PU, PTE0_IN }
- },
- { PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
- PTF7_FN, PTF7_OUT, PTF7_IN_PU, PTF7_IN,
- PTF6_FN, PTF6_OUT, PTF6_IN_PU, PTF6_IN,
- PTF5_FN, PTF5_OUT, PTF5_IN_PU, PTF5_IN,
- PTF4_FN, PTF4_OUT, PTF4_IN_PU, PTF4_IN,
- PTF3_FN, PTF3_OUT, PTF3_IN_PU, PTF3_IN,
- PTF2_FN, PTF2_OUT, PTF2_IN_PU, PTF2_IN,
- PTF1_FN, PTF1_OUT, PTF1_IN_PU, PTF1_IN,
- PTF0_FN, PTF0_OUT, PTF0_IN_PU, PTF0_IN }
- },
- { PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PTG5_FN, PTG5_OUT, 0, 0,
- PTG4_FN, PTG4_OUT, 0, 0,
- PTG3_FN, PTG3_OUT, 0, 0,
- PTG2_FN, PTG2_OUT, 0, 0,
- PTG1_FN, PTG1_OUT, 0, 0,
- PTG0_FN, PTG0_OUT, 0, 0 }
- },
- { PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
- PTH7_FN, PTH7_OUT, PTH7_IN_PU, PTH7_IN,
- PTH6_FN, PTH6_OUT, PTH6_IN_PU, PTH6_IN,
- PTH5_FN, PTH5_OUT, PTH5_IN_PU, PTH5_IN,
- PTH4_FN, PTH4_OUT, PTH4_IN_PU, PTH4_IN,
- PTH3_FN, PTH3_OUT, PTH3_IN_PU, PTH3_IN,
- PTH2_FN, PTH2_OUT, PTH2_IN_PU, PTH2_IN,
- PTH1_FN, PTH1_OUT, PTH1_IN_PU, PTH1_IN,
- PTH0_FN, PTH0_OUT, PTH0_IN_PU, PTH0_IN }
- },
- { PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
- PTJ7_FN, PTJ7_OUT, 0, 0,
- PTJ6_FN, PTJ6_OUT, 0, 0,
- PTJ5_FN, PTJ5_OUT, 0, 0,
- 0, 0, 0, 0,
- PTJ3_FN, PTJ3_OUT, PTJ3_IN_PU, PTJ3_IN,
- PTJ2_FN, PTJ2_OUT, PTJ2_IN_PU, PTJ2_IN,
- PTJ1_FN, PTJ1_OUT, PTJ1_IN_PU, PTJ1_IN,
- PTJ0_FN, PTJ0_OUT, PTJ0_IN_PU, PTJ0_IN }
- },
- { PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
- PTK7_FN, PTK7_OUT, PTK7_IN_PU, PTK7_IN,
- PTK6_FN, PTK6_OUT, PTK6_IN_PU, PTK6_IN,
- PTK5_FN, PTK5_OUT, PTK5_IN_PU, PTK5_IN,
- PTK4_FN, PTK4_OUT, PTK4_IN_PU, PTK4_IN,
- PTK3_FN, PTK3_OUT, PTK3_IN_PU, PTK3_IN,
- PTK2_FN, PTK2_OUT, PTK2_IN_PU, PTK2_IN,
- PTK1_FN, PTK1_OUT, PTK1_IN_PU, PTK1_IN,
- PTK0_FN, PTK0_OUT, PTK0_IN_PU, PTK0_IN }
- },
- { PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
- PTL7_FN, PTL7_OUT, PTL7_IN_PU, PTL7_IN,
- PTL6_FN, PTL6_OUT, PTL6_IN_PU, PTL6_IN,
- PTL5_FN, PTL5_OUT, PTL5_IN_PU, PTL5_IN,
- PTL4_FN, PTL4_OUT, PTL4_IN_PU, PTL4_IN,
- PTL3_FN, PTL3_OUT, PTL3_IN_PU, PTL3_IN,
- PTL2_FN, PTL2_OUT, PTL2_IN_PU, PTL2_IN,
- PTL1_FN, PTL1_OUT, PTL1_IN_PU, PTL1_IN,
- PTL0_FN, PTL0_OUT, PTL0_IN_PU, PTL0_IN }
- },
- { PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
- PTM7_FN, PTM7_OUT, PTM7_IN_PU, PTM7_IN,
- PTM6_FN, PTM6_OUT, PTM6_IN_PU, PTM6_IN,
- PTM5_FN, PTM5_OUT, PTM5_IN_PU, PTM5_IN,
- PTM4_FN, PTM4_OUT, PTM4_IN_PU, PTM4_IN,
- PTM3_FN, PTM3_OUT, PTM3_IN_PU, PTM3_IN,
- PTM2_FN, PTM2_OUT, PTM2_IN_PU, PTM2_IN,
- PTM1_FN, PTM1_OUT, PTM1_IN_PU, PTM1_IN,
- PTM0_FN, PTM0_OUT, PTM0_IN_PU, PTM0_IN }
- },
- { PINMUX_CFG_REG("PNCR", 0xa4050118, 16, 2) {
- PTN7_FN, PTN7_OUT, PTN7_IN_PU, PTN7_IN,
- PTN6_FN, PTN6_OUT, PTN6_IN_PU, PTN6_IN,
- PTN5_FN, PTN5_OUT, PTN5_IN_PU, PTN5_IN,
- PTN4_FN, PTN4_OUT, PTN4_IN_PU, PTN4_IN,
- PTN3_FN, PTN3_OUT, PTN3_IN_PU, PTN3_IN,
- PTN2_FN, PTN2_OUT, PTN2_IN_PU, PTN2_IN,
- PTN1_FN, PTN1_OUT, PTN1_IN_PU, PTN1_IN,
- PTN0_FN, PTN0_OUT, PTN0_IN_PU, PTN0_IN }
- },
- { PINMUX_CFG_REG("PQCR", 0xa405011a, 16, 2) {
- PTQ7_FN, PTQ7_OUT, PTQ7_IN_PU, PTQ7_IN,
- PTQ6_FN, PTQ6_OUT, PTQ6_IN_PU, PTQ6_IN,
- PTQ5_FN, PTQ5_OUT, PTQ5_IN_PU, PTQ5_IN,
- PTQ4_FN, PTQ4_OUT, PTQ4_IN_PU, PTQ4_IN,
- PTQ3_FN, PTQ3_OUT, PTQ3_IN_PU, PTQ3_IN,
- PTQ2_FN, PTQ2_OUT, PTQ2_IN_PU, PTQ2_IN,
- PTQ1_FN, PTQ1_OUT, PTQ1_IN_PU, PTQ1_IN,
- PTQ0_FN, PTQ0_OUT, PTQ0_IN_PU, PTQ0_IN }
- },
- { PINMUX_CFG_REG("PRCR", 0xa405011c, 16, 2) {
- PTR7_FN, PTR7_OUT, PTR7_IN_PU, PTR7_IN,
- PTR6_FN, PTR6_OUT, PTR6_IN_PU, PTR6_IN,
- PTR5_FN, PTR5_OUT, PTR5_IN_PU, PTR5_IN,
- PTR4_FN, PTR4_OUT, PTR4_IN_PU, PTR4_IN,
- PTR3_FN, 0, PTR3_IN_PU, PTR3_IN,
- PTR2_FN, 0, PTR2_IN_PU, PTR2_IN,
- PTR1_FN, PTR1_OUT, PTR1_IN_PU, PTR1_IN,
- PTR0_FN, PTR0_OUT, PTR0_IN_PU, PTR0_IN }
- },
- { PINMUX_CFG_REG("PSCR", 0xa405011e, 16, 2) {
- 0, 0, 0, 0,
- PTS6_FN, PTS6_OUT, PTS6_IN_PU, PTS6_IN,
- PTS5_FN, PTS5_OUT, PTS5_IN_PU, PTS5_IN,
- PTS4_FN, PTS4_OUT, PTS4_IN_PU, PTS4_IN,
- PTS3_FN, PTS3_OUT, PTS3_IN_PU, PTS3_IN,
- PTS2_FN, PTS2_OUT, PTS2_IN_PU, PTS2_IN,
- PTS1_FN, PTS1_OUT, PTS1_IN_PU, PTS1_IN,
- PTS0_FN, PTS0_OUT, PTS0_IN_PU, PTS0_IN }
- },
- { PINMUX_CFG_REG("PTCR", 0xa4050140, 16, 2) {
- PTT7_FN, PTT7_OUT, PTT7_IN_PU, PTT7_IN,
- PTT6_FN, PTT6_OUT, PTT6_IN_PU, PTT6_IN,
- PTT5_FN, PTT5_OUT, PTT5_IN_PU, PTT5_IN,
- PTT4_FN, PTT4_OUT, PTT4_IN_PU, PTT4_IN,
- PTT3_FN, PTT3_OUT, PTT3_IN_PU, PTT3_IN,
- PTT2_FN, PTT2_OUT, PTT2_IN_PU, PTT2_IN,
- PTT1_FN, PTT1_OUT, PTT1_IN_PU, PTT1_IN,
- PTT0_FN, PTT0_OUT, PTT0_IN_PU, PTT0_IN }
- },
- { PINMUX_CFG_REG("PUCR", 0xa4050142, 16, 2) {
- PTU7_FN, PTU7_OUT, PTU7_IN_PU, PTU7_IN,
- PTU6_FN, PTU6_OUT, PTU6_IN_PU, PTU6_IN,
- PTU5_FN, PTU5_OUT, PTU5_IN_PU, PTU5_IN,
- PTU4_FN, PTU4_OUT, PTU4_IN_PU, PTU4_IN,
- PTU3_FN, PTU3_OUT, PTU3_IN_PU, PTU3_IN,
- PTU2_FN, PTU2_OUT, PTU2_IN_PU, PTU2_IN,
- PTU1_FN, PTU1_OUT, PTU1_IN_PU, PTU1_IN,
- PTU0_FN, PTU0_OUT, PTU0_IN_PU, PTU0_IN }
- },
- { PINMUX_CFG_REG("PVCR", 0xa4050144, 16, 2) {
- PTV7_FN, PTV7_OUT, PTV7_IN_PU, PTV7_IN,
- PTV6_FN, PTV6_OUT, PTV6_IN_PU, PTV6_IN,
- PTV5_FN, PTV5_OUT, PTV5_IN_PU, PTV5_IN,
- PTV4_FN, PTV4_OUT, PTV4_IN_PU, PTV4_IN,
- PTV3_FN, PTV3_OUT, PTV3_IN_PU, PTV3_IN,
- PTV2_FN, PTV2_OUT, PTV2_IN_PU, PTV2_IN,
- PTV1_FN, PTV1_OUT, PTV1_IN_PU, PTV1_IN,
- PTV0_FN, PTV0_OUT, PTV0_IN_PU, PTV0_IN }
- },
- { PINMUX_CFG_REG("PWCR", 0xa4050146, 16, 2) {
- PTW7_FN, PTW7_OUT, PTW7_IN_PU, PTW7_IN,
- PTW6_FN, PTW6_OUT, PTW6_IN_PU, PTW6_IN,
- PTW5_FN, PTW5_OUT, PTW5_IN_PU, PTW5_IN,
- PTW4_FN, PTW4_OUT, PTW4_IN_PU, PTW4_IN,
- PTW3_FN, PTW3_OUT, PTW3_IN_PU, PTW3_IN,
- PTW2_FN, PTW2_OUT, PTW2_IN_PU, PTW2_IN,
- PTW1_FN, PTW1_OUT, PTW1_IN_PU, PTW1_IN,
- PTW0_FN, PTW0_OUT, PTW0_IN_PU, PTW0_IN }
- },
- { PINMUX_CFG_REG("PXCR", 0xa4050148, 16, 2) {
- PTX7_FN, PTX7_OUT, PTX7_IN_PU, PTX7_IN,
- PTX6_FN, PTX6_OUT, PTX6_IN_PU, PTX6_IN,
- PTX5_FN, PTX5_OUT, PTX5_IN_PU, PTX5_IN,
- PTX4_FN, PTX4_OUT, PTX4_IN_PU, PTX4_IN,
- PTX3_FN, PTX3_OUT, PTX3_IN_PU, PTX3_IN,
- PTX2_FN, PTX2_OUT, PTX2_IN_PU, PTX2_IN,
- PTX1_FN, PTX1_OUT, PTX1_IN_PU, PTX1_IN,
- PTX0_FN, PTX0_OUT, PTX0_IN_PU, PTX0_IN }
- },
- { PINMUX_CFG_REG("PYCR", 0xa405014a, 16, 2) {
- PTY7_FN, PTY7_OUT, PTY7_IN_PU, PTY7_IN,
- PTY6_FN, PTY6_OUT, PTY6_IN_PU, PTY6_IN,
- PTY5_FN, PTY5_OUT, PTY5_IN_PU, PTY5_IN,
- PTY4_FN, PTY4_OUT, PTY4_IN_PU, PTY4_IN,
- PTY3_FN, PTY3_OUT, PTY3_IN_PU, PTY3_IN,
- PTY2_FN, PTY2_OUT, PTY2_IN_PU, PTY2_IN,
- PTY1_FN, PTY1_OUT, PTY1_IN_PU, PTY1_IN,
- PTY0_FN, PTY0_OUT, PTY0_IN_PU, PTY0_IN }
- },
- { PINMUX_CFG_REG("PZCR", 0xa405014c, 16, 2) {
- PTZ7_FN, PTZ7_OUT, PTZ7_IN_PU, PTZ7_IN,
- PTZ6_FN, PTZ6_OUT, PTZ6_IN_PU, PTZ6_IN,
- PTZ5_FN, PTZ5_OUT, PTZ5_IN_PU, PTZ5_IN,
- PTZ4_FN, PTZ4_OUT, PTZ4_IN_PU, PTZ4_IN,
- PTZ3_FN, PTZ3_OUT, PTZ3_IN_PU, PTZ3_IN,
- PTZ2_FN, PTZ2_OUT, PTZ2_IN_PU, PTZ2_IN,
- PTZ1_FN, PTZ1_OUT, PTZ1_IN_PU, PTZ1_IN,
- PTZ0_FN, PTZ0_OUT, PTZ0_IN_PU, PTZ0_IN }
- },
- { PINMUX_CFG_REG("PSELA", 0xa405014e, 16, 1) {
- PSA15_0, PSA15_1,
- PSA14_0, PSA14_1,
- PSA13_0, PSA13_1,
- PSA12_0, PSA12_1,
- 0, 0,
- PSA10_0, PSA10_1,
- PSA9_0, PSA9_1,
- PSA8_0, PSA8_1,
- PSA7_0, PSA7_1,
- PSA6_0, PSA6_1,
- PSA5_0, PSA5_1,
- 0, 0,
- PSA3_0, PSA3_1,
- PSA2_0, PSA2_1,
- PSA1_0, PSA1_1,
- PSA0_0, PSA0_1}
- },
- { PINMUX_CFG_REG("PSELB", 0xa4050150, 16, 1) {
- 0, 0,
- PSB14_0, PSB14_1,
- PSB13_0, PSB13_1,
- PSB12_0, PSB12_1,
- PSB11_0, PSB11_1,
- PSB10_0, PSB10_1,
- PSB9_0, PSB9_1,
- PSB8_0, PSB8_1,
- PSB7_0, PSB7_1,
- PSB6_0, PSB6_1,
- PSB5_0, PSB5_1,
- PSB4_0, PSB4_1,
- PSB3_0, PSB3_1,
- PSB2_0, PSB2_1,
- PSB1_0, PSB1_1,
- PSB0_0, PSB0_1}
- },
- { PINMUX_CFG_REG("PSELC", 0xa4050152, 16, 1) {
- PSC15_0, PSC15_1,
- PSC14_0, PSC14_1,
- PSC13_0, PSC13_1,
- PSC12_0, PSC12_1,
- PSC11_0, PSC11_1,
- PSC10_0, PSC10_1,
- PSC9_0, PSC9_1,
- PSC8_0, PSC8_1,
- PSC7_0, PSC7_1,
- PSC6_0, PSC6_1,
- PSC5_0, PSC5_1,
- PSC4_0, PSC4_1,
- 0, 0,
- PSC2_0, PSC2_1,
- PSC1_0, PSC1_1,
- PSC0_0, PSC0_1}
- },
- { PINMUX_CFG_REG("PSELD", 0xa4050154, 16, 1) {
- PSD15_0, PSD15_1,
- PSD14_0, PSD14_1,
- PSD13_0, PSD13_1,
- PSD12_0, PSD12_1,
- PSD11_0, PSD11_1,
- PSD10_0, PSD10_1,
- PSD9_0, PSD9_1,
- PSD8_0, PSD8_1,
- PSD7_0, PSD7_1,
- PSD6_0, PSD6_1,
- PSD5_0, PSD5_1,
- PSD4_0, PSD4_1,
- PSD3_0, PSD3_1,
- PSD2_0, PSD2_1,
- PSD1_0, PSD1_1,
- PSD0_0, PSD0_1}
- },
- { PINMUX_CFG_REG("PSELE", 0xa4050156, 16, 1) {
- PSE15_0, PSE15_1,
- PSE14_0, PSE14_1,
- PSE13_0, PSE13_1,
- PSE12_0, PSE12_1,
- PSE11_0, PSE11_1,
- PSE10_0, PSE10_1,
- PSE9_0, PSE9_1,
- PSE8_0, PSE8_1,
- PSE7_0, PSE7_1,
- PSE6_0, PSE6_1,
- PSE5_0, PSE5_1,
- PSE4_0, PSE4_1,
- PSE3_0, PSE3_1,
- PSE2_0, PSE2_1,
- PSE1_0, PSE1_1,
- PSE0_0, PSE0_1}
- },
- {}
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PADR", 0xa4050120, 8) {
- PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
- PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
- },
- { PINMUX_DATA_REG("PBDR", 0xa4050122, 8) {
- PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
- PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
- },
- { PINMUX_DATA_REG("PCDR", 0xa4050124, 8) {
- PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
- PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA }
- },
- { PINMUX_DATA_REG("PDDR", 0xa4050126, 8) {
- PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
- PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
- },
- { PINMUX_DATA_REG("PEDR", 0xa4050128, 8) {
- PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
- PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA }
- },
- { PINMUX_DATA_REG("PFDR", 0xa405012a, 8) {
- PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
- PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
- },
- { PINMUX_DATA_REG("PGDR", 0xa405012c, 8) {
- 0, 0, PTG5_DATA, PTG4_DATA,
- PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
- },
- { PINMUX_DATA_REG("PHDR", 0xa405012e, 8) {
- PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
- PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
- },
- { PINMUX_DATA_REG("PJDR", 0xa4050130, 8) {
- PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, 0,
- PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
- },
- { PINMUX_DATA_REG("PKDR", 0xa4050132, 8) {
- PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
- PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
- },
- { PINMUX_DATA_REG("PLDR", 0xa4050134, 8) {
- PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
- PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
- },
- { PINMUX_DATA_REG("PMDR", 0xa4050136, 8) {
- PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
- PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
- },
- { PINMUX_DATA_REG("PNDR", 0xa4050138, 8) {
- PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
- PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
- },
- { PINMUX_DATA_REG("PQDR", 0xa405013a, 8) {
- PTQ7_DATA, PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
- PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA }
- },
- { PINMUX_DATA_REG("PRDR", 0xa405013c, 8) {
- PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
- PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
- },
- { PINMUX_DATA_REG("PSDR", 0xa405013e, 8) {
- 0, PTS6_DATA, PTS5_DATA, PTS4_DATA,
- PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
- },
- { PINMUX_DATA_REG("PTDR", 0xa4050160, 8) {
- PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
- PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
- },
- { PINMUX_DATA_REG("PUDR", 0xa4050162, 8) {
- PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
- PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
- },
- { PINMUX_DATA_REG("PVDR", 0xa4050164, 8) {
- PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
- PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
- },
- { PINMUX_DATA_REG("PWDR", 0xa4050166, 8) {
- PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
- PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA }
- },
- { PINMUX_DATA_REG("PXDR", 0xa4050168, 8) {
- PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
- PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA }
- },
- { PINMUX_DATA_REG("PYDR", 0xa405016a, 8) {
- PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
- PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA }
- },
- { PINMUX_DATA_REG("PZDR", 0xa405016c, 8) {
- PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
- PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA }
- },
- { },
-};
-
-static struct pinmux_info sh7724_pinmux_info = {
- .name = "sh7724_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
- .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_PTA7,
- .last_gpio = GPIO_FN_INTC_IRQ0,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
+#include <cpu/pfc.h>
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7724_pinmux_info);
+ return sh_pfc_register("pfc-sh7724", NULL, 0);
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c
index eed3b9d19d38..ea2db632a764 100644
--- a/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c
@@ -8,2448 +8,11 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#include <linux/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
#include <linux/ioport.h>
-#include <cpu/sh7734.h>
-
-#define CPU_32_PORT(fn, pfx, sfx) \
- PORT_10(fn, pfx, sfx), PORT_10(fn, pfx##1, sfx), \
- PORT_10(fn, pfx##2, sfx), PORT_1(fn, pfx##30, sfx), \
- PORT_1(fn, pfx##31, sfx)
-
-#define CPU_32_PORT5(fn, pfx, sfx) \
- PORT_1(fn, pfx##0, sfx), PORT_1(fn, pfx##1, sfx), \
- PORT_1(fn, pfx##2, sfx), PORT_1(fn, pfx##3, sfx), \
- PORT_1(fn, pfx##4, sfx), PORT_1(fn, pfx##5, sfx), \
- PORT_1(fn, pfx##6, sfx), PORT_1(fn, pfx##7, sfx), \
- PORT_1(fn, pfx##8, sfx), PORT_1(fn, pfx##9, sfx), \
- PORT_1(fn, pfx##10, sfx), PORT_1(fn, pfx##11, sfx)
-
-/* GPSR0 - GPSR5 */
-#define CPU_ALL_PORT(fn, pfx, sfx) \
- CPU_32_PORT(fn, pfx##_0_, sfx), \
- CPU_32_PORT(fn, pfx##_1_, sfx), \
- CPU_32_PORT(fn, pfx##_2_, sfx), \
- CPU_32_PORT(fn, pfx##_3_, sfx), \
- CPU_32_PORT(fn, pfx##_4_, sfx), \
- CPU_32_PORT5(fn, pfx##_5_, sfx)
-
-#define _GP_GPIO(pfx, sfx) PINMUX_GPIO(GPIO_GP##pfx, GP##pfx##_DATA)
-#define _GP_DATA(pfx, sfx) PINMUX_DATA(GP##pfx##_DATA, GP##pfx##_FN, \
- GP##pfx##_IN, GP##pfx##_OUT)
-
-#define _GP_INOUTSEL(pfx, sfx) GP##pfx##_IN, GP##pfx##_OUT
-#define _GP_INDT(pfx, sfx) GP##pfx##_DATA
-
-#define GP_ALL(str) CPU_ALL_PORT(_PORT_ALL, GP, str)
-#define PINMUX_GPIO_GP_ALL() CPU_ALL_PORT(_GP_GPIO, , unused)
-#define PINMUX_DATA_GP_ALL() CPU_ALL_PORT(_GP_DATA, , unused)
-
-#define PORT_10_REV(fn, pfx, sfx) \
- PORT_1(fn, pfx##9, sfx), PORT_1(fn, pfx##8, sfx), \
- PORT_1(fn, pfx##7, sfx), PORT_1(fn, pfx##6, sfx), \
- PORT_1(fn, pfx##5, sfx), PORT_1(fn, pfx##4, sfx), \
- PORT_1(fn, pfx##3, sfx), PORT_1(fn, pfx##2, sfx), \
- PORT_1(fn, pfx##1, sfx), PORT_1(fn, pfx##0, sfx)
-
-#define CPU_32_PORT_REV(fn, pfx, sfx) \
- PORT_1(fn, pfx##31, sfx), PORT_1(fn, pfx##30, sfx), \
- PORT_10_REV(fn, pfx##2, sfx), PORT_10_REV(fn, pfx##1, sfx), \
- PORT_10_REV(fn, pfx, sfx)
-
-#define GP_INOUTSEL(bank) CPU_32_PORT_REV(_GP_INOUTSEL, _##bank##_, unused)
-#define GP_INDT(bank) CPU_32_PORT_REV(_GP_INDT, _##bank##_, unused)
-
-#define PINMUX_IPSR_DATA(ipsr, fn) PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##fn)
-#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) PINMUX_DATA(fn##_MARK, FN_##ms, \
- FN_##ipsr, FN_##fn)
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- GP_ALL(DATA), /* GP_0_0_DATA -> GP_5_11_DATA */
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- GP_ALL(IN), /* GP_0_0_IN -> GP_5_11_IN */
- PINMUX_INPUT_END,
-
- PINMUX_OUTPUT_BEGIN,
- GP_ALL(OUT), /* GP_0_0_OUT -> GP_5_11_OUT */
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- GP_ALL(FN), /* GP_0_0_FN -> GP_5_11_FN */
-
- /* GPSR0 */
- FN_IP1_9_8, FN_IP1_11_10, FN_IP1_13_12, FN_IP1_15_14,
- FN_IP0_7_6, FN_IP0_9_8, FN_IP0_11_10, FN_IP0_13_12,
- FN_IP0_15_14, FN_IP0_17_16, FN_IP0_19_18, FN_IP0_21_20,
- FN_IP0_23_22, FN_IP0_25_24, FN_IP0_27_26, FN_IP0_29_28,
- FN_IP0_31_30, FN_IP1_1_0, FN_IP1_3_2, FN_IP1_5_4,
- FN_IP1_7_6, FN_IP11_28, FN_IP0_1_0, FN_IP0_3_2,
- FN_IP0_5_4, FN_IP1_17_16, FN_IP1_19_18, FN_IP1_22_20,
- FN_IP1_25_23, FN_IP1_28_26, FN_IP1_31_29, FN_IP2_2_0,
-
- /* GPSR1 */
- FN_IP3_20, FN_IP3_29_27, FN_IP11_20_19, FN_IP11_22_21,
- FN_IP2_16_14, FN_IP2_19_17, FN_IP2_22_20, FN_IP2_24_23,
- FN_IP2_27_25, FN_IP2_30_28, FN_IP3_1_0, FN_CLKOUT,
- FN_BS, FN_CS0, FN_IP3_2, FN_EX_CS0,
- FN_IP3_5_3, FN_IP3_8_6, FN_IP3_11_9, FN_IP3_14_12,
- FN_IP3_17_15, FN_RD, FN_IP3_19_18, FN_WE0,
- FN_WE1, FN_IP2_4_3, FN_IP3_23_21, FN_IP3_26_24,
- FN_IP2_7_5, FN_IP2_10_8, FN_IP2_13_11, FN_IP11_25_23,
-
- /* GPSR2 */
- FN_IP11_6_4, FN_IP11_9_7, FN_IP11_11_10, FN_IP4_2_0,
- FN_IP8_29_28, FN_IP11_27_26, FN_IP8_22_20, FN_IP8_25_23,
- FN_IP11_12, FN_IP8_27_26, FN_IP4_5_3, FN_IP4_8_6,
- FN_IP4_11_9, FN_IP4_14_12, FN_IP4_17_15, FN_IP4_19_18,
- FN_IP4_21_20, FN_IP4_23_22, FN_IP4_25_24, FN_IP4_27_26,
- FN_IP4_29_28, FN_IP4_31_30, FN_IP5_2_0, FN_IP5_5_3,
- FN_IP5_8_6, FN_IP5_11_9, FN_IP5_14_12, FN_IP5_17_15,
- FN_IP5_20_18, FN_IP5_22_21, FN_IP5_24_23, FN_IP5_26_25,
-
- /* GPSR3 */
- FN_IP6_2_0, FN_IP6_5_3, FN_IP6_7_6, FN_IP6_9_8,
- FN_IP6_11_10, FN_IP6_13_12, FN_IP6_15_14, FN_IP6_17_16,
- FN_IP6_20_18, FN_IP6_23_21, FN_IP7_2_0, FN_IP7_5_3,
- FN_IP7_8_6, FN_IP7_11_9, FN_IP7_14_12, FN_IP7_17_15,
- FN_IP7_20_18, FN_IP7_23_21, FN_IP7_26_24, FN_IP7_28_27,
- FN_IP7_30_29, FN_IP8_1_0, FN_IP8_3_2, FN_IP8_5_4,
- FN_IP8_7_6, FN_IP8_9_8, FN_IP8_11_10, FN_IP8_13_12,
- FN_IP8_15_14, FN_IP8_17_16, FN_IP8_19_18, FN_IP9_1_0,
-
- /* GPSR4 */
- FN_IP9_19_18, FN_IP9_21_20, FN_IP9_23_22, FN_IP9_25_24,
- FN_IP9_11_10, FN_IP9_13_12, FN_IP9_15_14, FN_IP9_17_16,
- FN_IP9_3_2, FN_IP9_5_4, FN_IP9_7_6, FN_IP9_9_8,
- FN_IP9_27_26, FN_IP9_29_28, FN_IP10_2_0, FN_IP10_5_3,
- FN_IP10_8_6, FN_IP10_11_9, FN_IP10_14_12, FN_IP10_15,
- FN_IP10_18_16, FN_IP10_21_19, FN_IP11_0, FN_IP11_1,
- FN_SCL0, FN_IP11_2, FN_PENC0, FN_IP11_15_13, /* Need check*/
- FN_USB_OVC0, FN_IP11_18_16,
- FN_IP10_22, FN_IP10_24_23,
-
- /* GPSR5 */
- FN_IP10_25, FN_IP11_3, FN_IRQ2_B, FN_IRQ3_B,
- FN_IP10_27_26, /* 10 */
- FN_IP10_29_28, /* 11 */
-
- /* IPSR0 */
- FN_A15, FN_ST0_VCO_CLKIN, FN_LCD_DATA15_A, FN_TIOC3D_C,
- FN_A14, FN_LCD_DATA14_A, FN_TIOC3C_C,
- FN_A13, FN_LCD_DATA13_A, FN_TIOC3B_C,
- FN_A12, FN_LCD_DATA12_A, FN_TIOC3A_C,
- FN_A11, FN_ST0_D7, FN_LCD_DATA11_A, FN_TIOC2B_C,
- FN_A10, FN_ST0_D6, FN_LCD_DATA10_A, FN_TIOC2A_C,
- FN_A9, FN_ST0_D5, FN_LCD_DATA9_A, FN_TIOC1B_C,
- FN_A8, FN_ST0_D4, FN_LCD_DATA8_A, FN_TIOC1A_C,
- FN_A7, FN_ST0_D3, FN_LCD_DATA7_A, FN_TIOC0D_C,
- FN_A6, FN_ST0_D2, FN_LCD_DATA6_A, FN_TIOC0C_C,
- FN_A5, FN_ST0_D1, FN_LCD_DATA5_A, FN_TIOC0B_C,
- FN_A4, FN_ST0_D0, FN_LCD_DATA4_A, FN_TIOC0A_C,
- FN_A3, FN_ST0_VLD, FN_LCD_DATA3_A, FN_TCLKD_C,
- FN_A2, FN_ST0_SYC, FN_LCD_DATA2_A, FN_TCLKC_C,
- FN_A1, FN_ST0_REQ, FN_LCD_DATA1_A, FN_TCLKB_C,
- FN_A0, FN_ST0_CLKIN, FN_LCD_DATA0_A, FN_TCLKA_C,
-
- /* IPSR1 */
- FN_D3, FN_SD0_DAT3_A, FN_MMC_D3_A, FN_ST1_D6, FN_FD3_A,
- FN_D2, FN_SD0_DAT2_A, FN_MMC_D2_A, FN_ST1_D5, FN_FD2_A,
- FN_D1, FN_SD0_DAT1_A, FN_MMC_D1_A, FN_ST1_D4, FN_FD1_A,
- FN_D0, FN_SD0_DAT0_A, FN_MMC_D0_A, FN_ST1_D3, FN_FD0_A,
- FN_A25, FN_TX2_D, FN_ST1_D2,
- FN_A24, FN_RX2_D, FN_ST1_D1,
- FN_A23, FN_ST1_D0, FN_LCD_M_DISP_A,
- FN_A22, FN_ST1_VLD, FN_LCD_VEPWC_A,
- FN_A21, FN_ST1_SYC, FN_LCD_VCPWC_A,
- FN_A20, FN_ST1_REQ, FN_LCD_FLM_A,
- FN_A19, FN_ST1_CLKIN, FN_LCD_CLK_A, FN_TIOC4D_C,
- FN_A18, FN_ST1_PWM, FN_LCD_CL2_A, FN_TIOC4C_C,
- FN_A17, FN_ST1_VCO_CLKIN, FN_LCD_CL1_A, FN_TIOC4B_C,
- FN_A16, FN_ST0_PWM, FN_LCD_DON_A, FN_TIOC4A_C,
-
- /* IPSR2 */
- FN_D14, FN_TX2_B, FN_FSE_A, FN_ET0_TX_CLK_B,
- FN_D13, FN_RX2_B, FN_FRB_A, FN_ET0_ETXD6_B,
- FN_D12, FN_FWE_A, FN_ET0_ETXD5_B,
- FN_D11, FN_RSPI_MISO_A, FN_QMI_QIO1_A, FN_FRE_A,
- FN_ET0_ETXD3_B,
- FN_D10, FN_RSPI_MOSI_A, FN_QMO_QIO0_A, FN_FALE_A,
- FN_ET0_ETXD2_B,
- FN_D9, FN_SD0_CMD_A, FN_MMC_CMD_A, FN_QIO3_A, FN_FCLE_A,
- FN_ET0_ETXD1_B,
- FN_D8, FN_SD0_CLK_A, FN_MMC_CLK_A, FN_QIO2_A, FN_FCE_A,
- FN_ET0_GTX_CLK_B,
- FN_D7, FN_RSPI_SSL_A, FN_MMC_D7_A, FN_QSSL_A, FN_FD7_A,
- FN_D6, FN_RSPI_RSPCK_A, FN_MMC_D6_A, FN_QSPCLK_A, FN_FD6_A,
- FN_D5, FN_SD0_WP_A, FN_MMC_D5_A, FN_FD5_A,
- FN_D4, FN_SD0_CD_A, FN_MMC_D4_A, FN_ST1_D7, FN_FD4_A,
-
- /* IPSR3 */
- FN_DRACK0, FN_SD1_DAT2_A, FN_ATAG, FN_TCLK1_A, FN_ET0_ETXD7,
- FN_EX_WAIT2, FN_SD1_DAT1_A, FN_DACK2, FN_CAN1_RX_C,
- FN_ET0_MAGIC_C, FN_ET0_ETXD6_A,
- FN_EX_WAIT1, FN_SD1_DAT0_A, FN_DREQ2, FN_CAN1_TX_C,
- FN_ET0_LINK_C, FN_ET0_ETXD5_A,
- FN_EX_WAIT0, FN_TCLK1_B,
- FN_RD_WR, FN_TCLK0, FN_CAN_CLK_B, FN_ET0_ETXD4,
- FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B, FN_ET0_ETXD3_A,
- FN_EX_CS4, FN_SD1_WP_A, FN_ATAWR, FN_QMI_QIO1_B, FN_ET0_ETXD2_A,
- FN_EX_CS3, FN_SD1_CD_A, FN_ATARD, FN_QMO_QIO0_B, FN_ET0_ETXD1_A,
- FN_EX_CS2, FN_TX3_B, FN_ATACS1, FN_QSPCLK_B, FN_ET0_GTX_CLK_A,
- FN_EX_CS1, FN_RX3_B, FN_ATACS0, FN_QIO2_B, FN_ET0_ETXD0,
- FN_CS1_A26, FN_QIO3_B,
- FN_D15, FN_SCK2_B,
-
- /* IPSR4 */
- FN_SCK2_A, FN_VI0_G3,
- FN_RTS1_B, FN_VI0_G2,
- FN_CTS1_B, FN_VI0_DATA7_VI0_G1,
- FN_TX1_B, FN_VI0_DATA6_VI0_G0, FN_ET0_PHY_INT_A,
- FN_RX1_B, FN_VI0_DATA5_VI0_B5, FN_ET0_MAGIC_A,
- FN_SCK1_B, FN_VI0_DATA4_VI0_B4, FN_ET0_LINK_A,
- FN_RTS0_B, FN_VI0_DATA3_VI0_B3, FN_ET0_MDIO_A,
- FN_CTS0_B, FN_VI0_DATA2_VI0_B2, FN_RMII0_MDIO_A, FN_ET0_MDC,
- FN_HTX0_A, FN_TX1_A, FN_VI0_DATA1_VI0_B1, FN_RMII0_MDC_A, FN_ET0_COL,
- FN_HRX0_A, FN_RX1_A, FN_VI0_DATA0_VI0_B0, FN_RMII0_CRS_DV_A, FN_ET0_CRS,
- FN_HSCK0_A, FN_SCK1_A, FN_VI0_VSYNC, FN_RMII0_RX_ER_A, FN_ET0_RX_ER,
- FN_HRTS0_A, FN_RTS1_A, FN_VI0_HSYNC, FN_RMII0_TXD_EN_A, FN_ET0_RX_DV,
- FN_HCTS0_A, FN_CTS1_A, FN_VI0_FIELD, FN_RMII0_RXD1_A, FN_ET0_ERXD7,
-
- /* IPSR5 */
- FN_SD2_CLK_A, FN_RX2_A, FN_VI0_G4, FN_ET0_RX_CLK_B,
- FN_SD2_CMD_A, FN_TX2_A, FN_VI0_G5, FN_ET0_ERXD2_B,
- FN_SD2_DAT0_A, FN_RX3_A, FN_VI0_R0, FN_ET0_ERXD3_B,
- FN_SD2_DAT1_A, FN_TX3_A, FN_VI0_R1, FN_ET0_MDIO_B,
- FN_SD2_DAT2_A, FN_RX4_A, FN_VI0_R2, FN_ET0_LINK_B,
- FN_SD2_DAT3_A, FN_TX4_A, FN_VI0_R3, FN_ET0_MAGIC_B,
- FN_SD2_CD_A, FN_RX5_A, FN_VI0_R4, FN_ET0_PHY_INT_B,
- FN_SD2_WP_A, FN_TX5_A, FN_VI0_R5,
- FN_REF125CK, FN_ADTRG, FN_RX5_C,
- FN_REF50CK, FN_CTS1_E, FN_HCTS0_D,
-
- /* IPSR6 */
- FN_DU0_DR0, FN_SCIF_CLK_B, FN_HRX0_D, FN_IETX_A, FN_TCLKA_A, FN_HIFD00,
- FN_DU0_DR1, FN_SCK0_B, FN_HTX0_D, FN_IERX_A, FN_TCLKB_A, FN_HIFD01,
- FN_DU0_DR2, FN_RX0_B, FN_TCLKC_A, FN_HIFD02,
- FN_DU0_DR3, FN_TX0_B, FN_TCLKD_A, FN_HIFD03,
- FN_DU0_DR4, FN_CTS0_C, FN_TIOC0A_A, FN_HIFD04,
- FN_DU0_DR5, FN_RTS0_C, FN_TIOC0B_A, FN_HIFD05,
- FN_DU0_DR6, FN_SCK1_C, FN_TIOC0C_A, FN_HIFD06,
- FN_DU0_DR7, FN_RX1_C, FN_TIOC0D_A, FN_HIFD07,
- FN_DU0_DG0, FN_TX1_C, FN_HSCK0_D, FN_IECLK_A, FN_TIOC1A_A, FN_HIFD08,
- FN_DU0_DG1, FN_CTS1_C, FN_HRTS0_D, FN_TIOC1B_A, FN_HIFD09,
-
- /* IPSR7 */
- FN_DU0_DG2, FN_RTS1_C, FN_RMII0_MDC_B, FN_TIOC2A_A, FN_HIFD10,
- FN_DU0_DG3, FN_SCK2_C, FN_RMII0_MDIO_B, FN_TIOC2B_A, FN_HIFD11,
- FN_DU0_DG4, FN_RX2_C, FN_RMII0_CRS_DV_B, FN_TIOC3A_A, FN_HIFD12,
- FN_DU0_DG5, FN_TX2_C, FN_RMII0_RX_ER_B, FN_TIOC3B_A, FN_HIFD13,
- FN_DU0_DG6, FN_RX3_C, FN_RMII0_RXD0_B, FN_TIOC3C_A, FN_HIFD14,
- FN_DU0_DG7, FN_TX3_C, FN_RMII0_RXD1_B, FN_TIOC3D_A, FN_HIFD15,
- FN_DU0_DB0, FN_RX4_C, FN_RMII0_TXD_EN_B, FN_TIOC4A_A, FN_HIFCS,
- FN_DU0_DB1, FN_TX4_C, FN_RMII0_TXD0_B, FN_TIOC4B_A, FN_HIFRS,
- FN_DU0_DB2, FN_RX5_B, FN_RMII0_TXD1_B, FN_TIOC4C_A, FN_HIFWR,
- FN_DU0_DB3, FN_TX5_B, FN_TIOC4D_A, FN_HIFRD,
- FN_DU0_DB4, FN_HIFINT,
-
- /* IPSR8 */
- FN_DU0_DB5, FN_HIFDREQ,
- FN_DU0_DB6, FN_HIFRDY,
- FN_DU0_DB7, FN_SSI_SCK0_B, FN_HIFEBL_B,
- FN_DU0_DOTCLKIN, FN_HSPI_CS0_C, FN_SSI_WS0_B,
- FN_DU0_DOTCLKOUT, FN_HSPI_CLK0_C, FN_SSI_SDATA0_B,
- FN_DU0_EXHSYNC_DU0_HSYNC, FN_HSPI_TX0_C, FN_SSI_SCK1_B,
- FN_DU0_EXVSYNC_DU0_VSYNC, FN_HSPI_RX0_C, FN_SSI_WS1_B,
- FN_DU0_EXODDF_DU0_ODDF, FN_CAN0_RX_B, FN_HSCK0_B, FN_SSI_SDATA1_B,
- FN_DU0_DISP, FN_CAN0_TX_B, FN_HRX0_B, FN_AUDIO_CLKA_B,
- FN_DU0_CDE, FN_HTX0_B, FN_AUDIO_CLKB_B, FN_LCD_VCPWC_B,
- FN_IRQ0_A, FN_HSPI_TX_B, FN_RX3_E, FN_ET0_ERXD0,
- FN_IRQ1_A, FN_HSPI_RX_B, FN_TX3_E, FN_ET0_ERXD1,
- FN_IRQ2_A, FN_CTS0_A, FN_HCTS0_B, FN_ET0_ERXD2_A,
- FN_IRQ3_A, FN_RTS0_A, FN_HRTS0_B, FN_ET0_ERXD3_A,
-
- /* IPSR9 */
- FN_VI1_CLK_A, FN_FD0_B, FN_LCD_DATA0_B,
- FN_VI1_0_A, FN_FD1_B, FN_LCD_DATA1_B,
- FN_VI1_1_A, FN_FD2_B, FN_LCD_DATA2_B,
- FN_VI1_2_A, FN_FD3_B, FN_LCD_DATA3_B,
- FN_VI1_3_A, FN_FD4_B, FN_LCD_DATA4_B,
- FN_VI1_4_A, FN_FD5_B, FN_LCD_DATA5_B,
- FN_VI1_5_A, FN_FD6_B, FN_LCD_DATA6_B,
- FN_VI1_6_A, FN_FD7_B, FN_LCD_DATA7_B,
- FN_VI1_7_A, FN_FCE_B, FN_LCD_DATA8_B,
- FN_SSI_SCK0_A, FN_TIOC1A_B, FN_LCD_DATA9_B,
- FN_SSI_WS0_A, FN_TIOC1B_B, FN_LCD_DATA10_B,
- FN_SSI_SDATA0_A, FN_VI1_0_B, FN_TIOC2A_B, FN_LCD_DATA11_B,
- FN_SSI_SCK1_A, FN_VI1_1_B, FN_TIOC2B_B, FN_LCD_DATA12_B,
- FN_SSI_WS1_A, FN_VI1_2_B, FN_LCD_DATA13_B,
- FN_SSI_SDATA1_A, FN_VI1_3_B, FN_LCD_DATA14_B,
-
- /* IPSR10 */
- FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B, FN_LCD_DATA15_B,
- FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B, FN_LCD_DON_B,
- FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B, FN_LCD_CL1_B,
- FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B, FN_LCD_CL2_B,
- FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B, FN_LCD_FLM_B,
- FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
- FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B, FN_LCD_VEPWC_B,
- FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B, FN_LCD_M_DISP_B,
- FN_CAN_CLK_A, FN_RX4_D,
- FN_CAN0_TX_A, FN_TX4_D, FN_MLB_CLK,
- FN_CAN1_RX_A, FN_IRQ1_B,
- FN_CAN0_RX_A, FN_IRQ0_B, FN_MLB_SIG,
- FN_CAN1_TX_A, FN_TX5_C, FN_MLB_DAT,
-
- /* IPSR11 */
- FN_SCL1, FN_SCIF_CLK_C,
- FN_SDA1, FN_RX1_E,
- FN_SDA0, FN_HIFEBL_A,
- FN_SDSELF, FN_RTS1_E,
- FN_SCIF_CLK_A, FN_HSPI_CLK_A, FN_VI0_CLK, FN_RMII0_TXD0_A, FN_ET0_ERXD4,
- FN_SCK0_A, FN_HSPI_CS_A, FN_VI0_CLKENB, FN_RMII0_TXD1_A, FN_ET0_ERXD5,
- FN_RX0_A, FN_HSPI_RX_A, FN_RMII0_RXD0_A, FN_ET0_ERXD6,
- FN_TX0_A, FN_HSPI_TX_A,
- FN_PENC1, FN_TX3_D, FN_CAN1_TX_B, FN_TX5_D, FN_IETX_B,
- FN_USB_OVC1, FN_RX3_D, FN_CAN1_RX_B, FN_RX5_D, FN_IERX_B,
- FN_DREQ0, FN_SD1_CLK_A, FN_ET0_TX_EN,
- FN_DACK0, FN_SD1_DAT3_A, FN_ET0_TX_ER,
- FN_DREQ1, FN_HSPI_CLK_B, FN_RX4_B, FN_ET0_PHY_INT_C, FN_ET0_TX_CLK_A,
- FN_DACK1, FN_HSPI_CS_B, FN_TX4_B, FN_ET0_RX_CLK_A,
- FN_PRESETOUT, FN_ST_CLKOUT,
-
- /* MOD_SEL1 */
- FN_SEL_IEBUS_0, FN_SEL_IEBUS_1,
- FN_SEL_RQSPI_0, FN_SEL_RQSPI_1,
- FN_SEL_VIN1_0, FN_SEL_VIN1_1,
- FN_SEL_HIF_0, FN_SEL_HIF_1,
- FN_SEL_RSPI_0, FN_SEL_RSPI_1,
- FN_SEL_LCDC_0, FN_SEL_LCDC_1,
- FN_SEL_ET0_CTL_0, FN_SEL_ET0_CTL_1, FN_SEL_ET0_CTL_2,
- FN_SEL_ET0_0, FN_SEL_ET0_1,
- FN_SEL_RMII_0, FN_SEL_RMII_1,
- FN_SEL_TMU_0, FN_SEL_TMU_1,
- FN_SEL_HSPI_0, FN_SEL_HSPI_1, FN_SEL_HSPI_2,
- FN_SEL_HSCIF_0, FN_SEL_HSCIF_1, FN_SEL_HSCIF_2, FN_SEL_HSCIF_3,
- FN_SEL_RCAN_CLK_0, FN_SEL_RCAN_CLK_1,
- FN_SEL_RCAN1_0, FN_SEL_RCAN1_1, FN_SEL_RCAN1_2,
- FN_SEL_RCAN0_0, FN_SEL_RCAN0_1,
- FN_SEL_SDHI2_0, FN_SEL_SDHI2_1,
- FN_SEL_SDHI1_0, FN_SEL_SDHI1_1,
- FN_SEL_SDHI0_0, FN_SEL_SDHI0_1,
- FN_SEL_SSI1_0, FN_SEL_SSI1_1,
- FN_SEL_SSI0_0, FN_SEL_SSI0_1,
- FN_SEL_AUDIO_CLKB_0, FN_SEL_AUDIO_CLKB_1,
- FN_SEL_AUDIO_CLKA_0, FN_SEL_AUDIO_CLKA_1,
- FN_SEL_FLCTL_0, FN_SEL_FLCTL_1,
- FN_SEL_MMC_0, FN_SEL_MMC_1,
- FN_SEL_INTC_0, FN_SEL_INTC_1,
-
- /* MOD_SEL2 */
- FN_SEL_MTU2_CLK_0, FN_SEL_MTU2_CLK_1,
- FN_SEL_MTU2_CH4_0, FN_SEL_MTU2_CH4_1,
- FN_SEL_MTU2_CH3_0, FN_SEL_MTU2_CH3_1,
- FN_SEL_MTU2_CH2_0, FN_SEL_MTU2_CH2_1, FN_SEL_MTU2_CH2_2,
- FN_SEL_MTU2_CH1_0, FN_SEL_MTU2_CH1_1, FN_SEL_MTU2_CH1_2,
- FN_SEL_MTU2_CH0_0, FN_SEL_MTU2_CH0_1,
- FN_SEL_SCIF5_0, FN_SEL_SCIF5_1,
- FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
- FN_SEL_SCIF4_0, FN_SEL_SCIF4_1,
- FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
- FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2,
- FN_SEL_SCIF3_3, FN_SEL_SCIF3_4,
- FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2,
- FN_SEL_SCIF2_3,
- FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2,
- FN_SEL_SCIF1_3, FN_SEL_SCIF1_4,
- FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2,
- FN_SEL_SCIF_CLK_0, FN_SEL_SCIF_CLK_1, FN_SEL_SCIF_CLK_2,
-
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
-
- CLKOUT_MARK, BS_MARK, CS0_MARK, EX_CS0_MARK, RD_MARK,
- WE0_MARK, WE1_MARK,
-
- SCL0_MARK, PENC0_MARK, USB_OVC0_MARK,
-
- IRQ2_B_MARK, IRQ3_B_MARK,
-
- /* IPSR0 */
- A15_MARK, ST0_VCO_CLKIN_MARK, LCD_DATA15_A_MARK, TIOC3D_C_MARK,
- A14_MARK, LCD_DATA14_A_MARK, TIOC3C_C_MARK,
- A13_MARK, LCD_DATA13_A_MARK, TIOC3B_C_MARK,
- A12_MARK, LCD_DATA12_A_MARK, TIOC3A_C_MARK,
- A11_MARK, ST0_D7_MARK, LCD_DATA11_A_MARK, TIOC2B_C_MARK,
- A10_MARK, ST0_D6_MARK, LCD_DATA10_A_MARK, TIOC2A_C_MARK,
- A9_MARK, ST0_D5_MARK, LCD_DATA9_A_MARK, TIOC1B_C_MARK,
- A8_MARK, ST0_D4_MARK, LCD_DATA8_A_MARK, TIOC1A_C_MARK,
- A7_MARK, ST0_D3_MARK, LCD_DATA7_A_MARK, TIOC0D_C_MARK,
- A6_MARK, ST0_D2_MARK, LCD_DATA6_A_MARK, TIOC0C_C_MARK,
- A5_MARK, ST0_D1_MARK, LCD_DATA5_A_MARK, TIOC0B_C_MARK,
- A4_MARK, ST0_D0_MARK, LCD_DATA4_A_MARK, TIOC0A_C_MARK,
- A3_MARK, ST0_VLD_MARK, LCD_DATA3_A_MARK, TCLKD_C_MARK,
- A2_MARK, ST0_SYC_MARK, LCD_DATA2_A_MARK, TCLKC_C_MARK,
- A1_MARK, ST0_REQ_MARK, LCD_DATA1_A_MARK, TCLKB_C_MARK,
- A0_MARK, ST0_CLKIN_MARK, LCD_DATA0_A_MARK, TCLKA_C_MARK,
-
- /* IPSR1 */
- D3_MARK, SD0_DAT3_A_MARK, MMC_D3_A_MARK, ST1_D6_MARK, FD3_A_MARK,
- D2_MARK, SD0_DAT2_A_MARK, MMC_D2_A_MARK, ST1_D5_MARK, FD2_A_MARK,
- D1_MARK, SD0_DAT1_A_MARK, MMC_D1_A_MARK, ST1_D4_MARK, FD1_A_MARK,
- D0_MARK, SD0_DAT0_A_MARK, MMC_D0_A_MARK, ST1_D3_MARK, FD0_A_MARK,
- A25_MARK, TX2_D_MARK, ST1_D2_MARK,
- A24_MARK, RX2_D_MARK, ST1_D1_MARK,
- A23_MARK, ST1_D0_MARK, LCD_M_DISP_A_MARK,
- A22_MARK, ST1_VLD_MARK, LCD_VEPWC_A_MARK,
- A21_MARK, ST1_SYC_MARK, LCD_VCPWC_A_MARK,
- A20_MARK, ST1_REQ_MARK, LCD_FLM_A_MARK,
- A19_MARK, ST1_CLKIN_MARK, LCD_CLK_A_MARK, TIOC4D_C_MARK,
- A18_MARK, ST1_PWM_MARK, LCD_CL2_A_MARK, TIOC4C_C_MARK,
- A17_MARK, ST1_VCO_CLKIN_MARK, LCD_CL1_A_MARK, TIOC4B_C_MARK,
- A16_MARK, ST0_PWM_MARK, LCD_DON_A_MARK, TIOC4A_C_MARK,
-
- /* IPSR2 */
- D14_MARK, TX2_B_MARK, FSE_A_MARK, ET0_TX_CLK_B_MARK,
- D13_MARK, RX2_B_MARK, FRB_A_MARK, ET0_ETXD6_B_MARK,
- D12_MARK, FWE_A_MARK, ET0_ETXD5_B_MARK,
- D11_MARK, RSPI_MISO_A_MARK, QMI_QIO1_A_MARK, FRE_A_MARK,
- ET0_ETXD3_B_MARK,
- D10_MARK, RSPI_MOSI_A_MARK, QMO_QIO0_A_MARK, FALE_A_MARK,
- ET0_ETXD2_B_MARK,
- D9_MARK, SD0_CMD_A_MARK, MMC_CMD_A_MARK, QIO3_A_MARK,
- FCLE_A_MARK, ET0_ETXD1_B_MARK,
- D8_MARK, SD0_CLK_A_MARK, MMC_CLK_A_MARK, QIO2_A_MARK,
- FCE_A_MARK, ET0_GTX_CLK_B_MARK,
- D7_MARK, RSPI_SSL_A_MARK, MMC_D7_A_MARK, QSSL_A_MARK,
- FD7_A_MARK,
- D6_MARK, RSPI_RSPCK_A_MARK, MMC_D6_A_MARK, QSPCLK_A_MARK,
- FD6_A_MARK,
- D5_MARK, SD0_WP_A_MARK, MMC_D5_A_MARK, FD5_A_MARK,
- D4_MARK, SD0_CD_A_MARK, MMC_D4_A_MARK, ST1_D7_MARK,
- FD4_A_MARK,
-
- /* IPSR3 */
- DRACK0_MARK, SD1_DAT2_A_MARK, ATAG_MARK, TCLK1_A_MARK, ET0_ETXD7_MARK,
- EX_WAIT2_MARK, SD1_DAT1_A_MARK, DACK2_MARK, CAN1_RX_C_MARK,
- ET0_MAGIC_C_MARK, ET0_ETXD6_A_MARK,
- EX_WAIT1_MARK, SD1_DAT0_A_MARK, DREQ2_MARK, CAN1_TX_C_MARK,
- ET0_LINK_C_MARK, ET0_ETXD5_A_MARK,
- EX_WAIT0_MARK, TCLK1_B_MARK,
- RD_WR_MARK, TCLK0_MARK, CAN_CLK_B_MARK, ET0_ETXD4_MARK,
- EX_CS5_MARK, SD1_CMD_A_MARK, ATADIR_MARK, QSSL_B_MARK,
- ET0_ETXD3_A_MARK,
- EX_CS4_MARK, SD1_WP_A_MARK, ATAWR_MARK, QMI_QIO1_B_MARK,
- ET0_ETXD2_A_MARK,
- EX_CS3_MARK, SD1_CD_A_MARK, ATARD_MARK, QMO_QIO0_B_MARK,
- ET0_ETXD1_A_MARK,
- EX_CS2_MARK, TX3_B_MARK, ATACS1_MARK, QSPCLK_B_MARK,
- ET0_GTX_CLK_A_MARK,
- EX_CS1_MARK, RX3_B_MARK, ATACS0_MARK, QIO2_B_MARK,
- ET0_ETXD0_MARK,
- CS1_A26_MARK, QIO3_B_MARK,
- D15_MARK, SCK2_B_MARK,
-
- /* IPSR4 */
- SCK2_A_MARK, VI0_G3_MARK,
- RTS1_B_MARK, VI0_G2_MARK,
- CTS1_B_MARK, VI0_DATA7_VI0_G1_MARK,
- TX1_B_MARK, VI0_DATA6_VI0_G0_MARK, ET0_PHY_INT_A_MARK,
- RX1_B_MARK, VI0_DATA5_VI0_B5_MARK, ET0_MAGIC_A_MARK,
- SCK1_B_MARK, VI0_DATA4_VI0_B4_MARK, ET0_LINK_A_MARK,
- RTS0_B_MARK, VI0_DATA3_VI0_B3_MARK, ET0_MDIO_A_MARK,
- CTS0_B_MARK, VI0_DATA2_VI0_B2_MARK, RMII0_MDIO_A_MARK,
- ET0_MDC_MARK,
- HTX0_A_MARK, TX1_A_MARK, VI0_DATA1_VI0_B1_MARK,
- RMII0_MDC_A_MARK, ET0_COL_MARK,
- HRX0_A_MARK, RX1_A_MARK, VI0_DATA0_VI0_B0_MARK,
- RMII0_CRS_DV_A_MARK, ET0_CRS_MARK,
- HSCK0_A_MARK, SCK1_A_MARK, VI0_VSYNC_MARK,
- RMII0_RX_ER_A_MARK, ET0_RX_ER_MARK,
- HRTS0_A_MARK, RTS1_A_MARK, VI0_HSYNC_MARK,
- RMII0_TXD_EN_A_MARK, ET0_RX_DV_MARK,
- HCTS0_A_MARK, CTS1_A_MARK, VI0_FIELD_MARK,
- RMII0_RXD1_A_MARK, ET0_ERXD7_MARK,
-
- /* IPSR5 */
- SD2_CLK_A_MARK, RX2_A_MARK, VI0_G4_MARK, ET0_RX_CLK_B_MARK,
- SD2_CMD_A_MARK, TX2_A_MARK, VI0_G5_MARK, ET0_ERXD2_B_MARK,
- SD2_DAT0_A_MARK, RX3_A_MARK, VI0_R0_MARK, ET0_ERXD3_B_MARK,
- SD2_DAT1_A_MARK, TX3_A_MARK, VI0_R1_MARK, ET0_MDIO_B_MARK,
- SD2_DAT2_A_MARK, RX4_A_MARK, VI0_R2_MARK, ET0_LINK_B_MARK,
- SD2_DAT3_A_MARK, TX4_A_MARK, VI0_R3_MARK, ET0_MAGIC_B_MARK,
- SD2_CD_A_MARK, RX5_A_MARK, VI0_R4_MARK, ET0_PHY_INT_B_MARK,
- SD2_WP_A_MARK, TX5_A_MARK, VI0_R5_MARK,
- REF125CK_MARK, ADTRG_MARK, RX5_C_MARK,
- REF50CK_MARK, CTS1_E_MARK, HCTS0_D_MARK,
-
- /* IPSR6 */
- DU0_DR0_MARK, SCIF_CLK_B_MARK, HRX0_D_MARK, IETX_A_MARK,
- TCLKA_A_MARK, HIFD00_MARK,
- DU0_DR1_MARK, SCK0_B_MARK, HTX0_D_MARK, IERX_A_MARK,
- TCLKB_A_MARK, HIFD01_MARK,
- DU0_DR2_MARK, RX0_B_MARK, TCLKC_A_MARK, HIFD02_MARK,
- DU0_DR3_MARK, TX0_B_MARK, TCLKD_A_MARK, HIFD03_MARK,
- DU0_DR4_MARK, CTS0_C_MARK, TIOC0A_A_MARK, HIFD04_MARK,
- DU0_DR5_MARK, RTS0_C_MARK, TIOC0B_A_MARK, HIFD05_MARK,
- DU0_DR6_MARK, SCK1_C_MARK, TIOC0C_A_MARK, HIFD06_MARK,
- DU0_DR7_MARK, RX1_C_MARK, TIOC0D_A_MARK, HIFD07_MARK,
- DU0_DG0_MARK, TX1_C_MARK, HSCK0_D_MARK, IECLK_A_MARK,
- TIOC1A_A_MARK, HIFD08_MARK,
- DU0_DG1_MARK, CTS1_C_MARK, HRTS0_D_MARK, TIOC1B_A_MARK,
- HIFD09_MARK,
-
- /* IPSR7 */
- DU0_DG2_MARK, RTS1_C_MARK, RMII0_MDC_B_MARK, TIOC2A_A_MARK,
- HIFD10_MARK,
- DU0_DG3_MARK, SCK2_C_MARK, RMII0_MDIO_B_MARK, TIOC2B_A_MARK,
- HIFD11_MARK,
- DU0_DG4_MARK, RX2_C_MARK, RMII0_CRS_DV_B_MARK, TIOC3A_A_MARK,
- HIFD12_MARK,
- DU0_DG5_MARK, TX2_C_MARK, RMII0_RX_ER_B_MARK, TIOC3B_A_MARK,
- HIFD13_MARK,
- DU0_DG6_MARK, RX3_C_MARK, RMII0_RXD0_B_MARK, TIOC3C_A_MARK,
- HIFD14_MARK,
- DU0_DG7_MARK, TX3_C_MARK, RMII0_RXD1_B_MARK, TIOC3D_A_MARK,
- HIFD15_MARK,
- DU0_DB0_MARK, RX4_C_MARK, RMII0_TXD_EN_B_MARK, TIOC4A_A_MARK,
- HIFCS_MARK,
- DU0_DB1_MARK, TX4_C_MARK, RMII0_TXD0_B_MARK, TIOC4B_A_MARK,
- HIFRS_MARK,
- DU0_DB2_MARK, RX5_B_MARK, RMII0_TXD1_B_MARK, TIOC4C_A_MARK,
- HIFWR_MARK,
- DU0_DB3_MARK, TX5_B_MARK, TIOC4D_A_MARK, HIFRD_MARK,
- DU0_DB4_MARK, HIFINT_MARK,
-
- /* IPSR8 */
- DU0_DB5_MARK, HIFDREQ_MARK,
- DU0_DB6_MARK, HIFRDY_MARK,
- DU0_DB7_MARK, SSI_SCK0_B_MARK, HIFEBL_B_MARK,
- DU0_DOTCLKIN_MARK, HSPI_CS0_C_MARK, SSI_WS0_B_MARK,
- DU0_DOTCLKOUT_MARK, HSPI_CLK0_C_MARK, SSI_SDATA0_B_MARK,
- DU0_EXHSYNC_DU0_HSYNC_MARK, HSPI_TX0_C_MARK, SSI_SCK1_B_MARK,
- DU0_EXVSYNC_DU0_VSYNC_MARK, HSPI_RX0_C_MARK, SSI_WS1_B_MARK,
- DU0_EXODDF_DU0_ODDF_MARK, CAN0_RX_B_MARK, HSCK0_B_MARK,
- SSI_SDATA1_B_MARK,
- DU0_DISP_MARK, CAN0_TX_B_MARK, HRX0_B_MARK, AUDIO_CLKA_B_MARK,
- DU0_CDE_MARK, HTX0_B_MARK, AUDIO_CLKB_B_MARK, LCD_VCPWC_B_MARK,
- IRQ0_A_MARK, HSPI_TX_B_MARK, RX3_E_MARK, ET0_ERXD0_MARK,
- IRQ1_A_MARK, HSPI_RX_B_MARK, TX3_E_MARK, ET0_ERXD1_MARK,
- IRQ2_A_MARK, CTS0_A_MARK, HCTS0_B_MARK, ET0_ERXD2_A_MARK,
- IRQ3_A_MARK, RTS0_A_MARK, HRTS0_B_MARK, ET0_ERXD3_A_MARK,
-
- /* IPSR9 */
- VI1_CLK_A_MARK, FD0_B_MARK, LCD_DATA0_B_MARK,
- VI1_0_A_MARK, FD1_B_MARK, LCD_DATA1_B_MARK,
- VI1_1_A_MARK, FD2_B_MARK, LCD_DATA2_B_MARK,
- VI1_2_A_MARK, FD3_B_MARK, LCD_DATA3_B_MARK,
- VI1_3_A_MARK, FD4_B_MARK, LCD_DATA4_B_MARK,
- VI1_4_A_MARK, FD5_B_MARK, LCD_DATA5_B_MARK,
- VI1_5_A_MARK, FD6_B_MARK, LCD_DATA6_B_MARK,
- VI1_6_A_MARK, FD7_B_MARK, LCD_DATA7_B_MARK,
- VI1_7_A_MARK, FCE_B_MARK, LCD_DATA8_B_MARK,
- SSI_SCK0_A_MARK, TIOC1A_B_MARK, LCD_DATA9_B_MARK,
- SSI_WS0_A_MARK, TIOC1B_B_MARK, LCD_DATA10_B_MARK,
- SSI_SDATA0_A_MARK, VI1_0_B_MARK, TIOC2A_B_MARK, LCD_DATA11_B_MARK,
- SSI_SCK1_A_MARK, VI1_1_B_MARK, TIOC2B_B_MARK, LCD_DATA12_B_MARK,
- SSI_WS1_A_MARK, VI1_2_B_MARK, LCD_DATA13_B_MARK,
- SSI_SDATA1_A_MARK, VI1_3_B_MARK, LCD_DATA14_B_MARK,
-
- /* IPSR10 */
- SSI_SCK23_MARK, VI1_4_B_MARK, RX1_D_MARK, FCLE_B_MARK,
- LCD_DATA15_B_MARK,
- SSI_WS23_MARK, VI1_5_B_MARK, TX1_D_MARK, HSCK0_C_MARK,
- FALE_B_MARK, LCD_DON_B_MARK,
- SSI_SDATA2_MARK, VI1_6_B_MARK, HRX0_C_MARK, FRE_B_MARK,
- LCD_CL1_B_MARK,
- SSI_SDATA3_MARK, VI1_7_B_MARK, HTX0_C_MARK, FWE_B_MARK,
- LCD_CL2_B_MARK,
- AUDIO_CLKA_A_MARK, VI1_CLK_B_MARK, SCK1_D_MARK, IECLK_B_MARK,
- LCD_FLM_B_MARK,
- AUDIO_CLKB_A_MARK, LCD_CLK_B_MARK,
- AUDIO_CLKC_MARK, SCK1_E_MARK, HCTS0_C_MARK, FRB_B_MARK,
- LCD_VEPWC_B_MARK,
- AUDIO_CLKOUT_MARK, TX1_E_MARK, HRTS0_C_MARK, FSE_B_MARK,
- LCD_M_DISP_B_MARK,
- CAN_CLK_A_MARK, RX4_D_MARK,
- CAN0_TX_A_MARK, TX4_D_MARK, MLB_CLK_MARK,
- CAN1_RX_A_MARK, IRQ1_B_MARK,
- CAN0_RX_A_MARK, IRQ0_B_MARK, MLB_SIG_MARK,
- CAN1_TX_A_MARK, TX5_C_MARK, MLB_DAT_MARK,
-
- /* IPSR11 */
- SCL1_MARK, SCIF_CLK_C_MARK,
- SDA1_MARK, RX1_E_MARK,
- SDA0_MARK, HIFEBL_A_MARK,
- SDSELF_MARK, RTS1_E_MARK,
- SCIF_CLK_A_MARK, HSPI_CLK_A_MARK, VI0_CLK_MARK, RMII0_TXD0_A_MARK,
- ET0_ERXD4_MARK,
- SCK0_A_MARK, HSPI_CS_A_MARK, VI0_CLKENB_MARK, RMII0_TXD1_A_MARK,
- ET0_ERXD5_MARK,
- RX0_A_MARK, HSPI_RX_A_MARK, RMII0_RXD0_A_MARK, ET0_ERXD6_MARK,
- TX0_A_MARK, HSPI_TX_A_MARK,
- PENC1_MARK, TX3_D_MARK, CAN1_TX_B_MARK, TX5_D_MARK,
- IETX_B_MARK,
- USB_OVC1_MARK, RX3_D_MARK, CAN1_RX_B_MARK, RX5_D_MARK,
- IERX_B_MARK,
- DREQ0_MARK, SD1_CLK_A_MARK, ET0_TX_EN_MARK,
- DACK0_MARK, SD1_DAT3_A_MARK, ET0_TX_ER_MARK,
- DREQ1_MARK, HSPI_CLK_B_MARK, RX4_B_MARK, ET0_PHY_INT_C_MARK,
- ET0_TX_CLK_A_MARK,
- DACK1_MARK, HSPI_CS_B_MARK, TX4_B_MARK, ET0_RX_CLK_A_MARK,
- PRESETOUT_MARK, ST_CLKOUT_MARK,
-
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
- PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
-
- PINMUX_DATA(CLKOUT_MARK, FN_CLKOUT),
- PINMUX_DATA(BS_MARK, FN_BS), PINMUX_DATA(CS0_MARK, FN_CS0),
- PINMUX_DATA(EX_CS0_MARK, FN_EX_CS0),
- PINMUX_DATA(RD_MARK, FN_RD), PINMUX_DATA(WE0_MARK, FN_WE0),
- PINMUX_DATA(WE1_MARK, FN_WE1),
- PINMUX_DATA(SCL0_MARK, FN_SCL0), PINMUX_DATA(PENC0_MARK, FN_PENC0),
- PINMUX_DATA(USB_OVC0_MARK, FN_USB_OVC0),
- PINMUX_DATA(IRQ2_B_MARK, FN_IRQ2_B),
- PINMUX_DATA(IRQ3_B_MARK, FN_IRQ3_B),
-
- /* IPSR0 */
- PINMUX_IPSR_DATA(IP0_1_0, A0),
- PINMUX_IPSR_DATA(IP0_1_0, ST0_CLKIN),
- PINMUX_IPSR_MODSEL_DATA(IP0_1_0, LCD_DATA0_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_1_0, TCLKA_C, SEL_MTU2_CLK_1),
-
- PINMUX_IPSR_DATA(IP0_3_2, A1),
- PINMUX_IPSR_DATA(IP0_3_2, ST0_REQ),
- PINMUX_IPSR_MODSEL_DATA(IP0_3_2, LCD_DATA1_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_3_2, TCLKB_C, SEL_MTU2_CLK_1),
-
- PINMUX_IPSR_DATA(IP0_5_4, A2),
- PINMUX_IPSR_DATA(IP0_5_4, ST0_SYC),
- PINMUX_IPSR_MODSEL_DATA(IP0_5_4, LCD_DATA2_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_5_4, TCLKC_C, SEL_MTU2_CLK_1),
-
- PINMUX_IPSR_DATA(IP0_7_6, A3),
- PINMUX_IPSR_DATA(IP0_7_6, ST0_VLD),
- PINMUX_IPSR_MODSEL_DATA(IP0_7_6, LCD_DATA3_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_7_6, TCLKD_C, SEL_MTU2_CLK_1),
-
- PINMUX_IPSR_DATA(IP0_9_8, A4),
- PINMUX_IPSR_DATA(IP0_9_8, ST0_D0),
- PINMUX_IPSR_MODSEL_DATA(IP0_9_8, LCD_DATA4_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_9_8, TIOC0A_C, SEL_MTU2_CH0_1),
-
- PINMUX_IPSR_DATA(IP0_11_10, A5),
- PINMUX_IPSR_DATA(IP0_11_10, ST0_D1),
- PINMUX_IPSR_MODSEL_DATA(IP0_11_10, LCD_DATA5_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_11_10, TIOC0B_C, SEL_MTU2_CH0_1),
-
- PINMUX_IPSR_DATA(IP0_13_12, A6),
- PINMUX_IPSR_DATA(IP0_13_12, ST0_D2),
- PINMUX_IPSR_MODSEL_DATA(IP0_13_12, LCD_DATA6_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_13_12, TIOC0C_C, SEL_MTU2_CH0_1),
-
- PINMUX_IPSR_DATA(IP0_15_14, A7),
- PINMUX_IPSR_DATA(IP0_15_14, ST0_D3),
- PINMUX_IPSR_MODSEL_DATA(IP0_15_14, LCD_DATA7_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_15_14, TIOC0D_C, SEL_MTU2_CH0_1),
-
- PINMUX_IPSR_DATA(IP0_17_16, A8),
- PINMUX_IPSR_DATA(IP0_17_16, ST0_D4),
- PINMUX_IPSR_MODSEL_DATA(IP0_17_16, LCD_DATA8_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_17_16, TIOC1A_C, SEL_MTU2_CH1_2),
-
- PINMUX_IPSR_DATA(IP0_19_18, A9),
- PINMUX_IPSR_DATA(IP0_19_18, ST0_D5),
- PINMUX_IPSR_MODSEL_DATA(IP0_19_18, LCD_DATA9_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_19_18, TIOC1B_C, SEL_MTU2_CH1_2),
-
- PINMUX_IPSR_DATA(IP0_21_20, A10),
- PINMUX_IPSR_DATA(IP0_21_20, ST0_D6),
- PINMUX_IPSR_MODSEL_DATA(IP0_21_20, LCD_DATA10_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_21_20, TIOC2A_C, SEL_MTU2_CH2_2),
-
- PINMUX_IPSR_DATA(IP0_23_22, A11),
- PINMUX_IPSR_DATA(IP0_23_22, ST0_D7),
- PINMUX_IPSR_MODSEL_DATA(IP0_23_22, LCD_DATA11_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_23_22, TIOC2B_C, SEL_MTU2_CH2_2),
-
- PINMUX_IPSR_DATA(IP0_25_24, A12),
- PINMUX_IPSR_MODSEL_DATA(IP0_25_24, LCD_DATA12_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_25_24, TIOC3A_C, SEL_MTU2_CH3_1),
-
- PINMUX_IPSR_DATA(IP0_27_26, A13),
- PINMUX_IPSR_MODSEL_DATA(IP0_27_26, LCD_DATA13_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_27_26, TIOC3B_C, SEL_MTU2_CH3_1),
-
- PINMUX_IPSR_DATA(IP0_29_28, A14),
- PINMUX_IPSR_MODSEL_DATA(IP0_29_28, LCD_DATA14_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_29_28, TIOC3C_C, SEL_MTU2_CH3_1),
-
- PINMUX_IPSR_DATA(IP0_31_30, A15),
- PINMUX_IPSR_DATA(IP0_31_30, ST0_VCO_CLKIN),
- PINMUX_IPSR_MODSEL_DATA(IP0_31_30, LCD_DATA15_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP0_31_30, TIOC3D_C, SEL_MTU2_CH3_1),
-
-
- /* IPSR1 */
- PINMUX_IPSR_DATA(IP1_1_0, A16),
- PINMUX_IPSR_DATA(IP1_1_0, ST0_PWM),
- PINMUX_IPSR_MODSEL_DATA(IP1_1_0, LCD_DON_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP1_1_0, TIOC4A_C, SEL_MTU2_CH4_1),
-
- PINMUX_IPSR_DATA(IP1_3_2, A17),
- PINMUX_IPSR_DATA(IP1_3_2, ST1_VCO_CLKIN),
- PINMUX_IPSR_MODSEL_DATA(IP1_3_2, LCD_CL1_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP1_3_2, TIOC4B_C, SEL_MTU2_CH4_1),
-
- PINMUX_IPSR_DATA(IP1_5_4, A18),
- PINMUX_IPSR_DATA(IP1_5_4, ST1_PWM),
- PINMUX_IPSR_MODSEL_DATA(IP1_5_4, LCD_CL2_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP1_5_4, TIOC4C_C, SEL_MTU2_CH4_1),
-
- PINMUX_IPSR_DATA(IP1_7_6, A19),
- PINMUX_IPSR_DATA(IP1_7_6, ST1_CLKIN),
- PINMUX_IPSR_MODSEL_DATA(IP1_7_6, LCD_CLK_A, SEL_LCDC_0),
- PINMUX_IPSR_MODSEL_DATA(IP1_7_6, TIOC4D_C, SEL_MTU2_CH4_1),
-
- PINMUX_IPSR_DATA(IP1_9_8, A20),
- PINMUX_IPSR_DATA(IP1_9_8, ST1_REQ),
- PINMUX_IPSR_MODSEL_DATA(IP1_9_8, LCD_FLM_A, SEL_LCDC_0),
-
- PINMUX_IPSR_DATA(IP1_11_10, A21),
- PINMUX_IPSR_DATA(IP1_11_10, ST1_SYC),
- PINMUX_IPSR_MODSEL_DATA(IP1_11_10, LCD_VCPWC_A, SEL_LCDC_0),
-
- PINMUX_IPSR_DATA(IP1_13_12, A22),
- PINMUX_IPSR_DATA(IP1_13_12, ST1_VLD),
- PINMUX_IPSR_MODSEL_DATA(IP1_13_12, LCD_VEPWC_A, SEL_LCDC_0),
-
- PINMUX_IPSR_DATA(IP1_15_14, A23),
- PINMUX_IPSR_DATA(IP1_15_14, ST1_D0),
- PINMUX_IPSR_MODSEL_DATA(IP1_15_14, LCD_M_DISP_A, SEL_LCDC_0),
-
- PINMUX_IPSR_DATA(IP1_17_16, A24),
- PINMUX_IPSR_MODSEL_DATA(IP1_17_16, RX2_D, SEL_SCIF2_3),
- PINMUX_IPSR_DATA(IP1_17_16, ST1_D1),
-
- PINMUX_IPSR_DATA(IP1_19_18, A25),
- PINMUX_IPSR_MODSEL_DATA(IP1_17_16, RX2_D, SEL_SCIF2_3),
- PINMUX_IPSR_DATA(IP1_17_16, ST1_D2),
-
- PINMUX_IPSR_DATA(IP1_22_20, D0),
- PINMUX_IPSR_MODSEL_DATA(IP1_22_20, SD0_DAT0_A, SEL_SDHI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP1_22_20, MMC_D0_A, SEL_MMC_0),
- PINMUX_IPSR_DATA(IP1_22_20, ST1_D3),
- PINMUX_IPSR_MODSEL_DATA(IP1_22_20, FD0_A, SEL_FLCTL_0),
-
- PINMUX_IPSR_DATA(IP1_25_23, D1),
- PINMUX_IPSR_MODSEL_DATA(IP1_25_23, SD0_DAT0_A, SEL_SDHI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP1_25_23, MMC_D1_A, SEL_MMC_0),
- PINMUX_IPSR_DATA(IP1_25_23, ST1_D4),
- PINMUX_IPSR_MODSEL_DATA(IP1_25_23, FD1_A, SEL_FLCTL_0),
-
- PINMUX_IPSR_DATA(IP1_28_26, D2),
- PINMUX_IPSR_MODSEL_DATA(IP1_28_26, SD0_DAT0_A, SEL_SDHI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP1_28_26, MMC_D2_A, SEL_MMC_0),
- PINMUX_IPSR_DATA(IP1_28_26, ST1_D5),
- PINMUX_IPSR_MODSEL_DATA(IP1_28_26, FD2_A, SEL_FLCTL_0),
-
- PINMUX_IPSR_DATA(IP1_31_29, D3),
- PINMUX_IPSR_MODSEL_DATA(IP1_31_29, SD0_DAT0_A, SEL_SDHI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP1_31_29, MMC_D3_A, SEL_MMC_0),
- PINMUX_IPSR_DATA(IP1_31_29, ST1_D6),
- PINMUX_IPSR_MODSEL_DATA(IP1_31_29, FD3_A, SEL_FLCTL_0),
-
- /* IPSR2 */
- PINMUX_IPSR_DATA(IP2_2_0, D4),
- PINMUX_IPSR_MODSEL_DATA(IP2_2_0, SD0_CD_A, SEL_SDHI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_2_0, MMC_D4_A, SEL_MMC_0),
- PINMUX_IPSR_DATA(IP2_2_0, ST1_D7),
- PINMUX_IPSR_MODSEL_DATA(IP2_2_0, FD4_A, SEL_FLCTL_0),
-
- PINMUX_IPSR_DATA(IP2_4_3, D5),
- PINMUX_IPSR_MODSEL_DATA(IP2_4_3, SD0_WP_A, SEL_SDHI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_4_3, MMC_D5_A, SEL_MMC_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_4_3, FD5_A, SEL_FLCTL_0),
-
- PINMUX_IPSR_DATA(IP2_7_5, D6),
- PINMUX_IPSR_MODSEL_DATA(IP2_7_5, RSPI_RSPCK_A, SEL_RSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_7_5, MMC_D6_A, SEL_MMC_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_7_5, QSPCLK_A, SEL_RQSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_7_5, FD6_A, SEL_FLCTL_0),
-
- PINMUX_IPSR_DATA(IP2_10_8, D7),
- PINMUX_IPSR_MODSEL_DATA(IP2_10_8, RSPI_SSL_A, SEL_RSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_10_8, MMC_D7_A, SEL_MMC_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_10_8, QSSL_A, SEL_RQSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_10_8, FD7_A, SEL_FLCTL_0),
-
- PINMUX_IPSR_DATA(IP2_13_11, D8),
- PINMUX_IPSR_MODSEL_DATA(IP2_13_11, SD0_CLK_A, SEL_SDHI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_13_11, MMC_CLK_A, SEL_MMC_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_13_11, QIO2_A, SEL_RQSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_13_11, FCE_A, SEL_FLCTL_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_13_11, ET0_GTX_CLK_B, SEL_ET0_1),
-
- PINMUX_IPSR_DATA(IP2_16_14, D9),
- PINMUX_IPSR_MODSEL_DATA(IP2_16_14, SD0_CMD_A, SEL_SDHI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_16_14, MMC_CMD_A, SEL_MMC_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_16_14, QIO3_A, SEL_RQSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_16_14, FCLE_A, SEL_FLCTL_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_16_14, ET0_ETXD1_B, SEL_ET0_1),
-
- PINMUX_IPSR_DATA(IP2_19_17, D10),
- PINMUX_IPSR_MODSEL_DATA(IP2_19_17, RSPI_MOSI_A, SEL_RSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_19_17, QMO_QIO0_A, SEL_RQSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_19_17, FALE_A, SEL_FLCTL_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_19_17, ET0_ETXD2_B, SEL_ET0_1),
-
- PINMUX_IPSR_DATA(IP2_22_20, D11),
- PINMUX_IPSR_MODSEL_DATA(IP2_22_20, RSPI_MISO_A, SEL_RSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_22_20, QMI_QIO1_A, SEL_RQSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_22_20, FRE_A, SEL_FLCTL_0),
-
- PINMUX_IPSR_DATA(IP2_24_23, D12),
- PINMUX_IPSR_MODSEL_DATA(IP2_24_23, FWE_A, SEL_FLCTL_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_24_23, ET0_ETXD5_B, SEL_ET0_1),
-
- PINMUX_IPSR_DATA(IP2_27_25, D13),
- PINMUX_IPSR_MODSEL_DATA(IP2_27_25, RX2_B, SEL_SCIF2_1),
- PINMUX_IPSR_MODSEL_DATA(IP2_27_25, FRB_A, SEL_FLCTL_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_27_25, ET0_ETXD6_B, SEL_ET0_1),
-
- PINMUX_IPSR_DATA(IP2_30_28, D14),
- PINMUX_IPSR_MODSEL_DATA(IP2_30_28, TX2_B, SEL_SCIF2_1),
- PINMUX_IPSR_MODSEL_DATA(IP2_30_28, FSE_A, SEL_FLCTL_0),
- PINMUX_IPSR_MODSEL_DATA(IP2_30_28, ET0_TX_CLK_B, SEL_ET0_1),
-
- /* IPSR3 */
- PINMUX_IPSR_DATA(IP3_1_0, D15),
- PINMUX_IPSR_MODSEL_DATA(IP3_1_0, SCK2_B, SEL_SCIF2_1),
-
- PINMUX_IPSR_DATA(IP3_2, CS1_A26),
- PINMUX_IPSR_MODSEL_DATA(IP3_2, QIO3_B, SEL_RQSPI_1),
-
- PINMUX_IPSR_DATA(IP3_5_3, EX_CS1),
- PINMUX_IPSR_MODSEL_DATA(IP3_5_3, RX3_B, SEL_SCIF2_1),
- PINMUX_IPSR_DATA(IP3_5_3, ATACS0),
- PINMUX_IPSR_MODSEL_DATA(IP3_5_3, QIO2_B, SEL_RQSPI_1),
- PINMUX_IPSR_DATA(IP3_5_3, ET0_ETXD0),
-
- PINMUX_IPSR_DATA(IP3_8_6, EX_CS2),
- PINMUX_IPSR_MODSEL_DATA(IP3_8_6, TX3_B, SEL_SCIF3_1),
- PINMUX_IPSR_DATA(IP3_8_6, ATACS1),
- PINMUX_IPSR_MODSEL_DATA(IP3_8_6, QSPCLK_B, SEL_RQSPI_1),
- PINMUX_IPSR_MODSEL_DATA(IP3_8_6, ET0_GTX_CLK_A, SEL_ET0_0),
-
- PINMUX_IPSR_DATA(IP3_11_9, EX_CS3),
- PINMUX_IPSR_MODSEL_DATA(IP3_11_9, SD1_CD_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_11_9, ATARD),
- PINMUX_IPSR_MODSEL_DATA(IP3_11_9, QMO_QIO0_B, SEL_RQSPI_1),
- PINMUX_IPSR_MODSEL_DATA(IP3_11_9, ET0_ETXD1_A, SEL_ET0_0),
-
- PINMUX_IPSR_DATA(IP3_14_12, EX_CS4),
- PINMUX_IPSR_MODSEL_DATA(IP3_14_12, SD1_WP_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_14_12, ATAWR),
- PINMUX_IPSR_MODSEL_DATA(IP3_14_12, QMI_QIO1_B, SEL_RQSPI_1),
- PINMUX_IPSR_MODSEL_DATA(IP3_14_12, ET0_ETXD2_A, SEL_ET0_0),
-
- PINMUX_IPSR_DATA(IP3_17_15, EX_CS5),
- PINMUX_IPSR_MODSEL_DATA(IP3_17_15, SD1_CMD_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_17_15, ATADIR),
- PINMUX_IPSR_MODSEL_DATA(IP3_17_15, QSSL_B, SEL_RQSPI_1),
- PINMUX_IPSR_MODSEL_DATA(IP3_17_15, ET0_ETXD3_A, SEL_ET0_0),
-
- PINMUX_IPSR_DATA(IP3_19_18, RD_WR),
- PINMUX_IPSR_DATA(IP3_19_18, TCLK0),
- PINMUX_IPSR_MODSEL_DATA(IP3_19_18, CAN_CLK_B, SEL_RCAN_CLK_1),
- PINMUX_IPSR_DATA(IP3_19_18, ET0_ETXD4),
-
- PINMUX_IPSR_DATA(IP3_20, EX_WAIT0),
- PINMUX_IPSR_MODSEL_DATA(IP3_20, TCLK1_B, SEL_TMU_1),
-
- PINMUX_IPSR_DATA(IP3_23_21, EX_WAIT1),
- PINMUX_IPSR_MODSEL_DATA(IP3_23_21, SD1_DAT0_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_23_21, DREQ2),
- PINMUX_IPSR_MODSEL_DATA(IP3_23_21, CAN1_TX_C, SEL_RCAN1_2),
- PINMUX_IPSR_MODSEL_DATA(IP3_23_21, ET0_LINK_C, SEL_ET0_CTL_2),
- PINMUX_IPSR_MODSEL_DATA(IP3_23_21, ET0_ETXD5_A, SEL_ET0_0),
-
- PINMUX_IPSR_DATA(IP3_26_24, EX_WAIT2),
- PINMUX_IPSR_MODSEL_DATA(IP3_26_24, SD1_DAT1_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_26_24, DACK2),
- PINMUX_IPSR_MODSEL_DATA(IP3_26_24, CAN1_RX_C, SEL_RCAN1_2),
- PINMUX_IPSR_MODSEL_DATA(IP3_26_24, ET0_MAGIC_C, SEL_ET0_CTL_2),
- PINMUX_IPSR_MODSEL_DATA(IP3_26_24, ET0_ETXD6_A, SEL_ET0_0),
-
- PINMUX_IPSR_DATA(IP3_29_27, DRACK0),
- PINMUX_IPSR_MODSEL_DATA(IP3_29_27, SD1_DAT2_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP3_29_27, ATAG),
- PINMUX_IPSR_MODSEL_DATA(IP3_29_27, TCLK1_A, SEL_TMU_0),
- PINMUX_IPSR_DATA(IP3_29_27, ET0_ETXD7),
-
- /* IPSR4 */
- PINMUX_IPSR_MODSEL_DATA(IP4_2_0, HCTS0_A, SEL_HSCIF_0),
- PINMUX_IPSR_MODSEL_DATA(IP4_2_0, CTS1_A, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP4_2_0, VI0_FIELD),
- PINMUX_IPSR_MODSEL_DATA(IP4_2_0, RMII0_RXD1_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_2_0, ET0_ERXD7),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_5_3, HRTS0_A, SEL_HSCIF_0),
- PINMUX_IPSR_MODSEL_DATA(IP4_5_3, RTS1_A, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP4_5_3, VI0_HSYNC),
- PINMUX_IPSR_MODSEL_DATA(IP4_5_3, RMII0_TXD_EN_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_5_3, ET0_RX_DV),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_8_6, HSCK0_A, SEL_HSCIF_0),
- PINMUX_IPSR_MODSEL_DATA(IP4_8_6, SCK1_A, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP4_8_6, VI0_VSYNC),
- PINMUX_IPSR_MODSEL_DATA(IP4_8_6, RMII0_RX_ER_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_8_6, ET0_RX_ER),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_11_9, HRX0_A, SEL_HSCIF_0),
- PINMUX_IPSR_MODSEL_DATA(IP4_11_9, RX1_A, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP4_11_9, VI0_DATA0_VI0_B0),
- PINMUX_IPSR_MODSEL_DATA(IP4_11_9, RMII0_CRS_DV_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_11_9, ET0_CRS),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_14_12, HTX0_A, SEL_HSCIF_0),
- PINMUX_IPSR_MODSEL_DATA(IP4_14_12, TX1_A, SEL_SCIF1_0),
- PINMUX_IPSR_DATA(IP4_14_12, VI0_DATA1_VI0_B1),
- PINMUX_IPSR_MODSEL_DATA(IP4_14_12, RMII0_MDC_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_14_12, ET0_COL),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_17_15, CTS0_B, SEL_SCIF0_1),
- PINMUX_IPSR_DATA(IP4_17_15, VI0_DATA2_VI0_B2),
- PINMUX_IPSR_MODSEL_DATA(IP4_17_15, RMII0_MDIO_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP4_17_15, ET0_MDC),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_19_18, RTS0_B, SEL_SCIF0_1),
- PINMUX_IPSR_DATA(IP4_19_18, VI0_DATA3_VI0_B3),
- PINMUX_IPSR_MODSEL_DATA(IP4_19_18, ET0_MDIO_A, SEL_ET0_0),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_21_20, SCK1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP4_21_20, VI0_DATA4_VI0_B4),
- PINMUX_IPSR_MODSEL_DATA(IP4_21_20, ET0_LINK_A, SEL_ET0_CTL_0),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_23_22, RX1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP4_23_22, VI0_DATA5_VI0_B5),
- PINMUX_IPSR_MODSEL_DATA(IP4_23_22, ET0_MAGIC_A, SEL_ET0_CTL_0),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_25_24, TX1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP4_25_24, VI0_DATA6_VI0_G0),
- PINMUX_IPSR_MODSEL_DATA(IP4_25_24, ET0_PHY_INT_A, SEL_ET0_CTL_0),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_27_26, CTS1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP4_27_26, VI0_DATA7_VI0_G1),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_29_28, RTS1_B, SEL_SCIF1_1),
- PINMUX_IPSR_DATA(IP4_29_28, VI0_G2),
-
- PINMUX_IPSR_MODSEL_DATA(IP4_31_30, SCK2_A, SEL_SCIF2_0),
- PINMUX_IPSR_DATA(IP4_31_30, VI0_G3),
-
- /* IPSR5 */
- PINMUX_IPSR_MODSEL_DATA(IP5_2_0, SD2_CLK_A, SEL_SDHI2_0),
- PINMUX_IPSR_MODSEL_DATA(IP5_2_0, RX2_A, SEL_SCIF2_0),
- PINMUX_IPSR_DATA(IP5_2_0, VI0_G4),
- PINMUX_IPSR_MODSEL_DATA(IP5_2_0, ET0_RX_CLK_B, SEL_ET0_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP5_5_3, SD2_CMD_A, SEL_SDHI2_0),
- PINMUX_IPSR_MODSEL_DATA(IP5_5_3, TX2_A, SEL_SCIF2_0),
- PINMUX_IPSR_DATA(IP5_5_3, VI0_G5),
- PINMUX_IPSR_MODSEL_DATA(IP5_5_3, ET0_ERXD2_B, SEL_ET0_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP5_8_6, SD2_DAT0_A, SEL_SDHI2_0),
- PINMUX_IPSR_MODSEL_DATA(IP5_8_6, RX3_A, SEL_SCIF3_0),
- PINMUX_IPSR_DATA(IP4_8_6, VI0_R0),
- PINMUX_IPSR_MODSEL_DATA(IP4_8_6, ET0_ERXD2_B, SEL_ET0_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP5_11_9, SD2_DAT1_A, SEL_SDHI2_0),
- PINMUX_IPSR_MODSEL_DATA(IP5_11_9, TX3_A, SEL_SCIF3_0),
- PINMUX_IPSR_DATA(IP5_11_9, VI0_R1),
- PINMUX_IPSR_MODSEL_DATA(IP5_11_9, ET0_MDIO_B, SEL_ET0_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP5_14_12, SD2_DAT2_A, SEL_SDHI2_0),
- PINMUX_IPSR_MODSEL_DATA(IP5_14_12, RX4_A, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP5_14_12, VI0_R2),
- PINMUX_IPSR_MODSEL_DATA(IP5_14_12, ET0_LINK_B, SEL_ET0_CTL_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP5_17_15, SD2_DAT3_A, SEL_SDHI2_0),
- PINMUX_IPSR_MODSEL_DATA(IP5_17_15, TX4_A, SEL_SCIF4_0),
- PINMUX_IPSR_DATA(IP5_17_15, VI0_R3),
- PINMUX_IPSR_MODSEL_DATA(IP5_17_15, ET0_MAGIC_B, SEL_ET0_CTL_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP5_20_18, SD2_CD_A, SEL_SDHI2_0),
- PINMUX_IPSR_MODSEL_DATA(IP5_20_18, RX5_A, SEL_SCIF5_0),
- PINMUX_IPSR_DATA(IP5_20_18, VI0_R4),
- PINMUX_IPSR_MODSEL_DATA(IP5_20_18, ET0_PHY_INT_B, SEL_ET0_CTL_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP5_22_21, SD2_WP_A, SEL_SDHI2_0),
- PINMUX_IPSR_MODSEL_DATA(IP5_22_21, TX5_A, SEL_SCIF5_0),
- PINMUX_IPSR_DATA(IP5_22_21, VI0_R5),
-
- PINMUX_IPSR_DATA(IP5_24_23, REF125CK),
- PINMUX_IPSR_DATA(IP5_24_23, ADTRG),
- PINMUX_IPSR_MODSEL_DATA(IP5_24_23, RX5_C, SEL_SCIF5_2),
- PINMUX_IPSR_DATA(IP5_26_25, REF50CK),
- PINMUX_IPSR_MODSEL_DATA(IP5_26_25, CTS1_E, SEL_SCIF1_3),
- PINMUX_IPSR_MODSEL_DATA(IP5_26_25, HCTS0_D, SEL_HSCIF_3),
-
- /* IPSR6 */
- PINMUX_IPSR_DATA(IP6_2_0, DU0_DR0),
- PINMUX_IPSR_MODSEL_DATA(IP6_2_0, SCIF_CLK_B, SEL_SCIF_CLK_1),
- PINMUX_IPSR_MODSEL_DATA(IP6_2_0, HRX0_D, SEL_HSCIF_3),
- PINMUX_IPSR_MODSEL_DATA(IP6_2_0, IETX_A, SEL_IEBUS_0),
- PINMUX_IPSR_MODSEL_DATA(IP6_2_0, TCLKA_A, SEL_MTU2_CLK_0),
- PINMUX_IPSR_DATA(IP6_2_0, HIFD00),
-
- PINMUX_IPSR_DATA(IP6_5_3, DU0_DR1),
- PINMUX_IPSR_MODSEL_DATA(IP6_5_3, SCK0_B, SEL_SCIF0_1),
- PINMUX_IPSR_MODSEL_DATA(IP6_5_3, HTX0_D, SEL_HSCIF_3),
- PINMUX_IPSR_MODSEL_DATA(IP6_5_3, IERX_A, SEL_IEBUS_0),
- PINMUX_IPSR_MODSEL_DATA(IP6_5_3, TCLKB_A, SEL_MTU2_CLK_0),
- PINMUX_IPSR_DATA(IP6_5_3, HIFD01),
-
- PINMUX_IPSR_DATA(IP6_7_6, DU0_DR2),
- PINMUX_IPSR_MODSEL_DATA(IP6_7_6, RX0_B, SEL_SCIF0_1),
- PINMUX_IPSR_MODSEL_DATA(IP6_7_6, TCLKC_A, SEL_MTU2_CLK_0),
- PINMUX_IPSR_DATA(IP6_7_6, HIFD02),
-
- PINMUX_IPSR_DATA(IP6_9_8, DU0_DR3),
- PINMUX_IPSR_MODSEL_DATA(IP6_9_8, TX0_B, SEL_SCIF0_1),
- PINMUX_IPSR_MODSEL_DATA(IP6_9_8, TCLKD_A, SEL_MTU2_CLK_0),
- PINMUX_IPSR_DATA(IP6_9_8, HIFD03),
-
- PINMUX_IPSR_DATA(IP6_11_10, DU0_DR4),
- PINMUX_IPSR_MODSEL_DATA(IP6_11_10, CTS0_C, SEL_SCIF0_2),
- PINMUX_IPSR_MODSEL_DATA(IP6_11_10, TIOC0A_A, SEL_MTU2_CH0_0),
- PINMUX_IPSR_DATA(IP6_11_10, HIFD04),
-
- PINMUX_IPSR_DATA(IP6_13_12, DU0_DR5),
- PINMUX_IPSR_MODSEL_DATA(IP6_13_12, RTS0_C, SEL_SCIF0_1),
- PINMUX_IPSR_MODSEL_DATA(IP6_13_12, TIOC0B_A, SEL_MTU2_CH0_0),
- PINMUX_IPSR_DATA(IP6_13_12, HIFD05),
-
- PINMUX_IPSR_DATA(IP6_15_14, DU0_DR6),
- PINMUX_IPSR_MODSEL_DATA(IP6_15_14, SCK1_C, SEL_SCIF1_2),
- PINMUX_IPSR_MODSEL_DATA(IP6_15_14, TIOC0C_A, SEL_MTU2_CH0_0),
- PINMUX_IPSR_DATA(IP6_15_14, HIFD06),
-
- PINMUX_IPSR_DATA(IP6_17_16, DU0_DR7),
- PINMUX_IPSR_MODSEL_DATA(IP6_17_16, RX1_C, SEL_SCIF1_2),
- PINMUX_IPSR_MODSEL_DATA(IP6_17_16, TIOC0D_A, SEL_MTU2_CH0_0),
- PINMUX_IPSR_DATA(IP6_17_16, HIFD07),
-
- PINMUX_IPSR_DATA(IP6_20_18, DU0_DG0),
- PINMUX_IPSR_MODSEL_DATA(IP6_20_18, TX1_C, SEL_SCIF1_2),
- PINMUX_IPSR_MODSEL_DATA(IP6_20_18, HSCK0_D, SEL_HSCIF_3),
- PINMUX_IPSR_MODSEL_DATA(IP6_20_18, IECLK_A, SEL_IEBUS_0),
- PINMUX_IPSR_MODSEL_DATA(IP6_20_18, TIOC1A_A, SEL_MTU2_CH1_0),
- PINMUX_IPSR_DATA(IP6_20_18, HIFD08),
-
- PINMUX_IPSR_DATA(IP6_23_21, DU0_DG1),
- PINMUX_IPSR_MODSEL_DATA(IP6_23_21, CTS1_C, SEL_SCIF1_2),
- PINMUX_IPSR_MODSEL_DATA(IP6_23_21, HRTS0_D, SEL_HSCIF_3),
- PINMUX_IPSR_MODSEL_DATA(IP6_23_21, TIOC1B_A, SEL_MTU2_CH1_0),
- PINMUX_IPSR_DATA(IP6_23_21, HIFD09),
-
- /* IPSR7 */
- PINMUX_IPSR_DATA(IP7_2_0, DU0_DG2),
- PINMUX_IPSR_MODSEL_DATA(IP7_2_0, RTS1_C, SEL_SCIF1_2),
- PINMUX_IPSR_MODSEL_DATA(IP7_2_0, RMII0_MDC_B, SEL_RMII_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_2_0, TIOC2A_A, SEL_MTU2_CH2_0),
- PINMUX_IPSR_DATA(IP7_2_0, HIFD10),
-
- PINMUX_IPSR_DATA(IP7_5_3, DU0_DG3),
- PINMUX_IPSR_MODSEL_DATA(IP7_5_3, SCK2_C, SEL_SCIF2_2),
- PINMUX_IPSR_MODSEL_DATA(IP7_5_3, RMII0_MDIO_B, SEL_RMII_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_5_3, TIOC2B_A, SEL_MTU2_CH2_0),
- PINMUX_IPSR_DATA(IP7_5_3, HIFD11),
-
- PINMUX_IPSR_DATA(IP7_8_6, DU0_DG4),
- PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RX2_C, SEL_SCIF2_2),
- PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RMII0_CRS_DV_B, SEL_RMII_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_8_6, TIOC3A_A, SEL_MTU2_CH3_0),
- PINMUX_IPSR_DATA(IP7_8_6, HIFD12),
-
- PINMUX_IPSR_DATA(IP7_11_9, DU0_DG5),
- PINMUX_IPSR_MODSEL_DATA(IP7_11_9, TX2_C, SEL_SCIF2_2),
- PINMUX_IPSR_MODSEL_DATA(IP7_11_9, RMII0_RX_ER_B, SEL_RMII_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_11_9, TIOC3B_A, SEL_MTU2_CH3_0),
- PINMUX_IPSR_DATA(IP7_11_9, HIFD13),
-
- PINMUX_IPSR_DATA(IP7_14_12, DU0_DG6),
- PINMUX_IPSR_MODSEL_DATA(IP7_14_12, RX3_C, SEL_SCIF3_2),
- PINMUX_IPSR_MODSEL_DATA(IP7_14_12, RMII0_RXD0_B, SEL_RMII_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_14_12, TIOC3C_A, SEL_MTU2_CH3_0),
- PINMUX_IPSR_DATA(IP7_14_12, HIFD14),
-
- PINMUX_IPSR_DATA(IP7_17_15, DU0_DG7),
- PINMUX_IPSR_MODSEL_DATA(IP7_17_15, TX3_C, SEL_SCIF3_2),
- PINMUX_IPSR_MODSEL_DATA(IP7_17_15, RMII0_RXD1_B, SEL_RMII_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_17_15, TIOC3D_A, SEL_MTU2_CH3_0),
- PINMUX_IPSR_DATA(IP7_17_15, HIFD15),
-
- PINMUX_IPSR_DATA(IP7_20_18, DU0_DB0),
- PINMUX_IPSR_MODSEL_DATA(IP7_20_18, RX4_C, SEL_SCIF4_2),
- PINMUX_IPSR_MODSEL_DATA(IP7_20_18, RMII0_TXD_EN_B, SEL_RMII_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_20_18, TIOC4A_A, SEL_MTU2_CH4_0),
- PINMUX_IPSR_DATA(IP7_20_18, HIFCS),
-
- PINMUX_IPSR_DATA(IP7_23_21, DU0_DB1),
- PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TX4_C, SEL_SCIF4_2),
- PINMUX_IPSR_MODSEL_DATA(IP7_23_21, RMII0_TXD0_B, SEL_RMII_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TIOC4B_A, SEL_MTU2_CH4_0),
- PINMUX_IPSR_DATA(IP7_23_21, HIFWR),
-
- PINMUX_IPSR_DATA(IP7_26_24, DU0_DB2),
- PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RX5_B, SEL_SCIF5_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RMII0_TXD1_B, SEL_RMII_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_26_24, TIOC4C_A, SEL_MTU2_CH4_0),
-
- PINMUX_IPSR_DATA(IP7_28_27, DU0_DB3),
- PINMUX_IPSR_MODSEL_DATA(IP7_28_27, TX5_B, SEL_SCIF5_1),
- PINMUX_IPSR_MODSEL_DATA(IP7_28_27, TIOC4D_A, SEL_MTU2_CH4_0),
- PINMUX_IPSR_DATA(IP7_28_27, HIFRD),
-
- PINMUX_IPSR_DATA(IP7_30_29, DU0_DB4),
- PINMUX_IPSR_DATA(IP7_30_29, HIFINT),
-
- /* IPSR8 */
- PINMUX_IPSR_DATA(IP8_1_0, DU0_DB5),
- PINMUX_IPSR_DATA(IP8_1_0, HIFDREQ),
-
- PINMUX_IPSR_DATA(IP8_3_2, DU0_DB6),
- PINMUX_IPSR_DATA(IP8_3_2, HIFRDY),
-
- PINMUX_IPSR_DATA(IP8_5_4, DU0_DB7),
- PINMUX_IPSR_MODSEL_DATA(IP8_5_4, SSI_SCK0_B, SEL_SSI0_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_5_4, HIFEBL_B, SEL_HIF_1),
-
- PINMUX_IPSR_DATA(IP8_7_6, DU0_DOTCLKIN),
- PINMUX_IPSR_MODSEL_DATA(IP8_7_6, HSPI_CS0_C, SEL_HSPI_2),
- PINMUX_IPSR_MODSEL_DATA(IP8_7_6, SSI_WS0_B, SEL_SSI0_1),
-
- PINMUX_IPSR_DATA(IP8_9_8, DU0_DOTCLKOUT),
- PINMUX_IPSR_MODSEL_DATA(IP8_9_8, HSPI_CLK0_C, SEL_HSPI_2),
- PINMUX_IPSR_MODSEL_DATA(IP8_9_8, SSI_SDATA0_B, SEL_SSI0_1),
-
- PINMUX_IPSR_DATA(IP8_11_10, DU0_EXHSYNC_DU0_HSYNC),
- PINMUX_IPSR_MODSEL_DATA(IP8_11_10, HSPI_TX0_C, SEL_HSPI_2),
- PINMUX_IPSR_MODSEL_DATA(IP8_11_10, SSI_SCK1_B, SEL_SSI1_1),
-
- PINMUX_IPSR_DATA(IP8_13_12, DU0_EXVSYNC_DU0_VSYNC),
- PINMUX_IPSR_MODSEL_DATA(IP8_13_12, HSPI_RX0_C, SEL_HSPI_2),
- PINMUX_IPSR_MODSEL_DATA(IP8_13_12, SSI_WS1_B, SEL_SSI1_1),
-
- PINMUX_IPSR_DATA(IP8_15_14, DU0_EXODDF_DU0_ODDF),
- PINMUX_IPSR_MODSEL_DATA(IP8_15_14, CAN0_RX_B, SEL_RCAN0_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_15_14, HSCK0_B, SEL_HSCIF_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_15_14, SSI_SDATA1_B, SEL_SSI1_1),
-
- PINMUX_IPSR_DATA(IP8_17_16, DU0_DISP),
- PINMUX_IPSR_MODSEL_DATA(IP8_17_16, CAN0_TX_B, SEL_RCAN0_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_17_16, HRX0_B, SEL_HSCIF_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_17_16, AUDIO_CLKA_B, SEL_AUDIO_CLKA_1),
-
- PINMUX_IPSR_DATA(IP8_19_18, DU0_CDE),
- PINMUX_IPSR_MODSEL_DATA(IP8_19_18, HTX0_B, SEL_HSCIF_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_19_18, AUDIO_CLKB_B, SEL_AUDIO_CLKB_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_19_18, LCD_VCPWC_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP8_22_20, IRQ0_A, SEL_INTC_0),
- PINMUX_IPSR_MODSEL_DATA(IP8_22_20, HSPI_TX_B, SEL_HSPI_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_22_20, RX3_E, SEL_SCIF3_4),
- PINMUX_IPSR_DATA(IP8_22_20, ET0_ERXD0),
-
- PINMUX_IPSR_MODSEL_DATA(IP8_25_23, IRQ1_A, SEL_INTC_0),
- PINMUX_IPSR_MODSEL_DATA(IP8_25_23, HSPI_RX_B, SEL_HSPI_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_25_23, TX3_E, SEL_SCIF3_4),
- PINMUX_IPSR_DATA(IP8_25_23, ET0_ERXD1),
-
- PINMUX_IPSR_MODSEL_DATA(IP8_27_26, IRQ2_A, SEL_INTC_0),
- PINMUX_IPSR_MODSEL_DATA(IP8_27_26, CTS0_A, SEL_SCIF0_0),
- PINMUX_IPSR_MODSEL_DATA(IP8_27_26, HCTS0_B, SEL_HSCIF_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_27_26, ET0_ERXD2_A, SEL_ET0_0),
-
- PINMUX_IPSR_MODSEL_DATA(IP8_29_28, IRQ3_A, SEL_INTC_0),
- PINMUX_IPSR_MODSEL_DATA(IP8_29_28, RTS0_A, SEL_SCIF0_0),
- PINMUX_IPSR_MODSEL_DATA(IP8_29_28, HRTS0_B, SEL_HSCIF_1),
- PINMUX_IPSR_MODSEL_DATA(IP8_29_28, ET0_ERXD3_A, SEL_ET0_0),
-
- /* IPSR9 */
- PINMUX_IPSR_MODSEL_DATA(IP9_1_0, VI1_CLK_A, SEL_VIN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_1_0, FD0_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_1_0, LCD_DATA0_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_3_2, VI1_0_A, SEL_VIN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_3_2, FD1_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_3_2, LCD_DATA1_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_5_4, VI1_1_A, SEL_VIN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_5_4, FD2_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_5_4, LCD_DATA2_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_7_6, VI1_2_A, SEL_VIN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_7_6, FD3_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_7_6, LCD_DATA3_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_9_8, VI1_3_A, SEL_VIN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_9_8, FD4_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_9_8, LCD_DATA4_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_11_10, VI1_4_A, SEL_VIN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_11_10, FD5_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_11_10, LCD_DATA5_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_13_12, VI1_5_A, SEL_VIN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_13_12, FD6_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_13_12, LCD_DATA6_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_15_14, VI1_6_A, SEL_VIN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_15_14, FD7_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_15_14, LCD_DATA7_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_17_16, VI1_7_A, SEL_VIN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_17_16, FCE_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_17_16, LCD_DATA8_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_19_18, SSI_SCK0_A, SEL_SSI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_19_18, TIOC1A_B, SEL_MTU2_CH1_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_19_18, LCD_DATA9_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_21_20, SSI_WS0_A, SEL_SSI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_21_20, TIOC1B_B, SEL_MTU2_CH1_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_21_20, LCD_DATA10_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_23_22, SSI_SDATA0_A, SEL_SSI0_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_23_22, VI1_0_B, SEL_VIN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_23_22, TIOC2A_B, SEL_MTU2_CH2_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_23_22, LCD_DATA11_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_25_24, SSI_SCK1_A, SEL_SSI1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_25_24, VI1_1_B, SEL_VIN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_25_24, TIOC2B_B, SEL_MTU2_CH2_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_25_24, LCD_DATA12_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_27_26, SSI_WS1_A, SEL_SSI1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_27_26, VI1_2_B, SEL_VIN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_27_26, LCD_DATA13_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP9_29_28, SSI_SDATA1_A, SEL_SSI1_0),
- PINMUX_IPSR_MODSEL_DATA(IP9_29_28, VI1_3_B, SEL_VIN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP9_29_28, LCD_DATA14_B, SEL_LCDC_1),
-
- /* IPSE10 */
- PINMUX_IPSR_DATA(IP10_2_0, SSI_SCK23),
- PINMUX_IPSR_MODSEL_DATA(IP10_2_0, VI1_4_B, SEL_VIN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_2_0, RX1_D, SEL_SCIF1_3),
- PINMUX_IPSR_MODSEL_DATA(IP10_2_0, FCLE_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_2_0, LCD_DATA15_B, SEL_LCDC_1),
-
- PINMUX_IPSR_DATA(IP10_5_3, SSI_WS23),
- PINMUX_IPSR_MODSEL_DATA(IP10_5_3, VI1_5_B, SEL_VIN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_5_3, TX1_D, SEL_SCIF1_3),
- PINMUX_IPSR_MODSEL_DATA(IP10_5_3, HSCK0_C, SEL_HSCIF_2),
- PINMUX_IPSR_MODSEL_DATA(IP10_5_3, FALE_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_5_3, LCD_DON_B, SEL_LCDC_1),
-
- PINMUX_IPSR_DATA(IP10_8_6, SSI_SDATA2),
- PINMUX_IPSR_MODSEL_DATA(IP10_8_6, VI1_6_B, SEL_VIN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_8_6, HRX0_C, SEL_HSCIF_2),
- PINMUX_IPSR_MODSEL_DATA(IP10_8_6, FRE_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_8_6, LCD_CL1_B, SEL_LCDC_1),
-
- PINMUX_IPSR_DATA(IP10_11_9, SSI_SDATA3),
- PINMUX_IPSR_MODSEL_DATA(IP10_11_9, VI1_7_B, SEL_VIN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_11_9, HTX0_C, SEL_HSCIF_2),
- PINMUX_IPSR_MODSEL_DATA(IP10_11_9, FWE_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_11_9, LCD_CL2_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP10_14_12, AUDIO_CLKA_A, SEL_AUDIO_CLKA_0),
- PINMUX_IPSR_MODSEL_DATA(IP10_14_12, VI1_CLK_B, SEL_VIN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_14_12, SCK1_D, SEL_SCIF1_3),
- PINMUX_IPSR_MODSEL_DATA(IP10_14_12, IECLK_B, SEL_IEBUS_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_14_12, LCD_FLM_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP10_15, AUDIO_CLKB_A, SEL_AUDIO_CLKB_0),
- PINMUX_IPSR_MODSEL_DATA(IP10_15, LCD_CLK_B, SEL_LCDC_1),
-
- PINMUX_IPSR_DATA(IP10_18_16, AUDIO_CLKC),
- PINMUX_IPSR_MODSEL_DATA(IP10_18_16, SCK1_E, SEL_SCIF1_4),
- PINMUX_IPSR_MODSEL_DATA(IP10_18_16, HCTS0_C, SEL_HSCIF_2),
- PINMUX_IPSR_MODSEL_DATA(IP10_18_16, FRB_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_18_16, LCD_VEPWC_B, SEL_LCDC_1),
-
- PINMUX_IPSR_DATA(IP10_21_19, AUDIO_CLKOUT),
- PINMUX_IPSR_MODSEL_DATA(IP10_21_19, TX1_E, SEL_SCIF1_4),
- PINMUX_IPSR_MODSEL_DATA(IP10_21_19, HRTS0_C, SEL_HSCIF_2),
- PINMUX_IPSR_MODSEL_DATA(IP10_21_19, FSE_B, SEL_FLCTL_1),
- PINMUX_IPSR_MODSEL_DATA(IP10_21_19, LCD_M_DISP_B, SEL_LCDC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP10_22, CAN_CLK_A, SEL_RCAN_CLK_0),
- PINMUX_IPSR_MODSEL_DATA(IP10_22, RX4_D, SEL_SCIF4_3),
-
- PINMUX_IPSR_MODSEL_DATA(IP10_24_23, CAN0_TX_A, SEL_RCAN0_0),
- PINMUX_IPSR_MODSEL_DATA(IP10_24_23, TX4_D, SEL_SCIF4_3),
- PINMUX_IPSR_DATA(IP10_24_23, MLB_CLK),
-
- PINMUX_IPSR_MODSEL_DATA(IP10_25, CAN1_RX_A, SEL_RCAN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP10_25, IRQ1_B, SEL_INTC_1),
-
- PINMUX_IPSR_MODSEL_DATA(IP10_27_26, CAN0_RX_A, SEL_RCAN0_0),
- PINMUX_IPSR_MODSEL_DATA(IP10_27_26, IRQ0_B, SEL_INTC_1),
- PINMUX_IPSR_DATA(IP10_27_26, MLB_SIG),
-
- PINMUX_IPSR_MODSEL_DATA(IP10_29_28, CAN1_TX_A, SEL_RCAN1_0),
- PINMUX_IPSR_MODSEL_DATA(IP10_29_28, TX5_C, SEL_SCIF1_2),
- PINMUX_IPSR_DATA(IP10_29_28, MLB_DAT),
-
- /* IPSR11 */
- PINMUX_IPSR_DATA(IP11_0, SCL1),
- PINMUX_IPSR_MODSEL_DATA(IP11_0, SCIF_CLK_C, SEL_SCIF_CLK_2),
-
- PINMUX_IPSR_DATA(IP11_1, SDA1),
- PINMUX_IPSR_MODSEL_DATA(IP11_0, RX1_E, SEL_SCIF1_4),
-
- PINMUX_IPSR_DATA(IP11_2, SDA0),
- PINMUX_IPSR_MODSEL_DATA(IP11_2, HIFEBL_A, SEL_HIF_0),
-
- PINMUX_IPSR_DATA(IP11_3, SDSELF),
- PINMUX_IPSR_MODSEL_DATA(IP11_3, RTS1_E, SEL_SCIF1_3),
-
- PINMUX_IPSR_MODSEL_DATA(IP11_6_4, SCIF_CLK_A, SEL_SCIF_CLK_0),
- PINMUX_IPSR_MODSEL_DATA(IP11_6_4, HSPI_CLK_A, SEL_HSPI_0),
- PINMUX_IPSR_DATA(IP11_6_4, VI0_CLK),
- PINMUX_IPSR_MODSEL_DATA(IP11_6_4, RMII0_TXD0_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP11_6_4, ET0_ERXD4),
-
- PINMUX_IPSR_MODSEL_DATA(IP11_9_7, SCK0_A, SEL_SCIF0_0),
- PINMUX_IPSR_MODSEL_DATA(IP11_9_7, HSPI_CS_A, SEL_HSPI_0),
- PINMUX_IPSR_DATA(IP11_9_7, VI0_CLKENB),
- PINMUX_IPSR_MODSEL_DATA(IP11_9_7, RMII0_TXD1_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP11_9_7, ET0_ERXD5),
-
- PINMUX_IPSR_MODSEL_DATA(IP11_11_10, RX0_A, SEL_SCIF0_0),
- PINMUX_IPSR_MODSEL_DATA(IP11_11_10, HSPI_RX_A, SEL_HSPI_0),
- PINMUX_IPSR_MODSEL_DATA(IP11_11_10, RMII0_RXD0_A, SEL_RMII_0),
- PINMUX_IPSR_DATA(IP11_11_10, ET0_ERXD6),
-
- PINMUX_IPSR_MODSEL_DATA(IP11_12, TX0_A, SEL_SCIF0_0),
- PINMUX_IPSR_MODSEL_DATA(IP11_12, HSPI_TX_A, SEL_HSPI_0),
-
- PINMUX_IPSR_DATA(IP11_15_13, PENC1),
- PINMUX_IPSR_MODSEL_DATA(IP11_15_13, TX3_D, SEL_SCIF3_3),
- PINMUX_IPSR_MODSEL_DATA(IP11_15_13, CAN1_TX_B, SEL_RCAN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP11_15_13, TX5_D, SEL_SCIF5_3),
- PINMUX_IPSR_MODSEL_DATA(IP11_15_13, IETX_B, SEL_IEBUS_1),
-
- PINMUX_IPSR_DATA(IP11_18_16, USB_OVC1),
- PINMUX_IPSR_MODSEL_DATA(IP11_18_16, RX3_D, SEL_SCIF3_3),
- PINMUX_IPSR_MODSEL_DATA(IP11_18_16, CAN1_RX_B, SEL_RCAN1_1),
- PINMUX_IPSR_MODSEL_DATA(IP11_18_16, RX5_D, SEL_SCIF5_3),
- PINMUX_IPSR_MODSEL_DATA(IP11_18_16, IERX_B, SEL_IEBUS_1),
-
- PINMUX_IPSR_DATA(IP11_20_19, DREQ0),
- PINMUX_IPSR_MODSEL_DATA(IP11_20_19, SD1_CLK_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP11_20_19, ET0_TX_EN),
-
- PINMUX_IPSR_DATA(IP11_22_21, DACK0),
- PINMUX_IPSR_MODSEL_DATA(IP11_22_21, SD1_DAT3_A, SEL_SDHI1_0),
- PINMUX_IPSR_DATA(IP11_22_21, ET0_TX_ER),
-
- PINMUX_IPSR_DATA(IP11_25_23, DREQ1),
- PINMUX_IPSR_MODSEL_DATA(IP11_25_23, HSPI_CLK_B, SEL_HSPI_1),
- PINMUX_IPSR_MODSEL_DATA(IP11_25_23, RX4_B, SEL_SCIF4_1),
- PINMUX_IPSR_MODSEL_DATA(IP11_25_23, ET0_PHY_INT_C, SEL_ET0_CTL_0),
- PINMUX_IPSR_MODSEL_DATA(IP11_25_23, ET0_TX_CLK_A, SEL_ET0_0),
-
- PINMUX_IPSR_DATA(IP11_27_26, DACK1),
- PINMUX_IPSR_MODSEL_DATA(IP11_27_26, HSPI_CS_B, SEL_HSPI_1),
- PINMUX_IPSR_MODSEL_DATA(IP11_27_26, TX4_B, SEL_SCIF3_1),
- PINMUX_IPSR_MODSEL_DATA(IP11_27_26, ET0_RX_CLK_A, SEL_ET0_0),
-
- PINMUX_IPSR_DATA(IP11_28, PRESETOUT),
- PINMUX_IPSR_DATA(IP11_28, ST_CLKOUT),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
- PINMUX_GPIO_GP_ALL(),
-
- GPIO_FN(CLKOUT), GPIO_FN(BS), GPIO_FN(CS0), GPIO_FN(EX_CS0),
- GPIO_FN(RD), GPIO_FN(WE0), GPIO_FN(WE1),
- GPIO_FN(SCL0), GPIO_FN(PENC0), GPIO_FN(USB_OVC0),
- GPIO_FN(IRQ2_B), GPIO_FN(IRQ3_B),
-
- /* IPSR0 */
- GPIO_FN(A0), GPIO_FN(ST0_CLKIN), GPIO_FN(LCD_DATA0_A),
- GPIO_FN(TCLKA_C),
- GPIO_FN(A1), GPIO_FN(ST0_REQ), GPIO_FN(LCD_DATA1_A),
- GPIO_FN(TCLKB_C),
- GPIO_FN(A2), GPIO_FN(ST0_SYC), GPIO_FN(LCD_DATA2_A),
- GPIO_FN(TCLKC_C),
- GPIO_FN(A3), GPIO_FN(ST0_VLD), GPIO_FN(LCD_DATA3_A),
- GPIO_FN(TCLKD_C),
- GPIO_FN(A4), GPIO_FN(ST0_D0), GPIO_FN(LCD_DATA4_A),
- GPIO_FN(TIOC0A_C),
- GPIO_FN(A5), GPIO_FN(ST0_D1), GPIO_FN(LCD_DATA5_A),
- GPIO_FN(TIOC0B_C),
- GPIO_FN(A6), GPIO_FN(ST0_D2), GPIO_FN(LCD_DATA6_A),
- GPIO_FN(TIOC0C_C),
- GPIO_FN(A7), GPIO_FN(ST0_D3), GPIO_FN(LCD_DATA7_A),
- GPIO_FN(TIOC0D_C),
- GPIO_FN(A8), GPIO_FN(ST0_D4), GPIO_FN(LCD_DATA8_A),
- GPIO_FN(TIOC1A_C),
- GPIO_FN(A9), GPIO_FN(ST0_D5), GPIO_FN(LCD_DATA9_A),
- GPIO_FN(TIOC1B_C),
- GPIO_FN(A10), GPIO_FN(ST0_D6), GPIO_FN(LCD_DATA10_A),
- GPIO_FN(TIOC2A_C),
- GPIO_FN(A11), GPIO_FN(ST0_D7), GPIO_FN(LCD_DATA11_A),
- GPIO_FN(TIOC2B_C),
- GPIO_FN(A12), GPIO_FN(LCD_DATA12_A), GPIO_FN(TIOC3A_C),
- GPIO_FN(A13), GPIO_FN(LCD_DATA13_A), GPIO_FN(TIOC3B_C),
- GPIO_FN(A14), GPIO_FN(LCD_DATA14_A), GPIO_FN(TIOC3C_C),
- GPIO_FN(A15), GPIO_FN(ST0_VCO_CLKIN), GPIO_FN(LCD_DATA15_A),
- GPIO_FN(TIOC3D_C),
-
- /* IPSR1 */
- GPIO_FN(A16), GPIO_FN(ST0_PWM), GPIO_FN(LCD_DON_A),
- GPIO_FN(TIOC4A_C),
- GPIO_FN(A17), GPIO_FN(ST1_VCO_CLKIN), GPIO_FN(LCD_CL1_A),
- GPIO_FN(TIOC4B_C),
- GPIO_FN(A18), GPIO_FN(ST1_PWM), GPIO_FN(LCD_CL2_A),
- GPIO_FN(TIOC4C_C),
- GPIO_FN(A19), GPIO_FN(ST1_CLKIN), GPIO_FN(LCD_CLK_A),
- GPIO_FN(TIOC4D_C),
- GPIO_FN(A20), GPIO_FN(ST1_REQ), GPIO_FN(LCD_FLM_A),
- GPIO_FN(A21), GPIO_FN(ST1_SYC), GPIO_FN(LCD_VCPWC_A),
- GPIO_FN(A22), GPIO_FN(ST1_VLD), GPIO_FN(LCD_VEPWC_A),
- GPIO_FN(A23), GPIO_FN(ST1_D0), GPIO_FN(LCD_M_DISP_A),
- GPIO_FN(A24), GPIO_FN(RX2_D), GPIO_FN(ST1_D1),
- GPIO_FN(A25), GPIO_FN(TX2_D), GPIO_FN(ST1_D2),
- GPIO_FN(D0), GPIO_FN(SD0_DAT0_A), GPIO_FN(MMC_D0_A),
- GPIO_FN(ST1_D3), GPIO_FN(FD0_A),
- GPIO_FN(D1), GPIO_FN(SD0_DAT1_A), GPIO_FN(MMC_D1_A),
- GPIO_FN(ST1_D4), GPIO_FN(FD1_A),
- GPIO_FN(D2), GPIO_FN(SD0_DAT2_A), GPIO_FN(MMC_D2_A),
- GPIO_FN(ST1_D5), GPIO_FN(FD2_A),
- GPIO_FN(D3), GPIO_FN(SD0_DAT3_A), GPIO_FN(MMC_D3_A),
- GPIO_FN(ST1_D6), GPIO_FN(FD3_A),
-
- /* IPSR2 */
- GPIO_FN(D4), GPIO_FN(SD0_CD_A), GPIO_FN(MMC_D4_A), GPIO_FN(ST1_D7),
- GPIO_FN(FD4_A),
- GPIO_FN(D5), GPIO_FN(SD0_WP_A), GPIO_FN(MMC_D5_A), GPIO_FN(FD5_A),
- GPIO_FN(D6), GPIO_FN(RSPI_RSPCK_A), GPIO_FN(MMC_D6_A),
- GPIO_FN(QSPCLK_A),
- GPIO_FN(FD6_A),
- GPIO_FN(D7), GPIO_FN(RSPI_SSL_A), GPIO_FN(MMC_D7_A), GPIO_FN(QSSL_A),
- GPIO_FN(FD7_A),
- GPIO_FN(D8), GPIO_FN(SD0_CLK_A), GPIO_FN(MMC_CLK_A), GPIO_FN(QIO2_A),
- GPIO_FN(FCE_A), GPIO_FN(ET0_GTX_CLK_B),
- GPIO_FN(D9), GPIO_FN(SD0_CMD_A), GPIO_FN(MMC_CMD_A), GPIO_FN(QIO3_A),
- GPIO_FN(FCLE_A), GPIO_FN(ET0_ETXD1_B),
- GPIO_FN(D10), GPIO_FN(RSPI_MOSI_A), GPIO_FN(QMO_QIO0_A),
- GPIO_FN(FALE_A), GPIO_FN(ET0_ETXD2_B),
- GPIO_FN(D11), GPIO_FN(RSPI_MISO_A), GPIO_FN(QMI_QIO1_A), GPIO_FN(FRE_A),
- GPIO_FN(ET0_ETXD3_B),
- GPIO_FN(D12), GPIO_FN(FWE_A), GPIO_FN(ET0_ETXD5_B),
- GPIO_FN(D13), GPIO_FN(RX2_B), GPIO_FN(FRB_A), GPIO_FN(ET0_ETXD6_B),
- GPIO_FN(D14), GPIO_FN(TX2_B), GPIO_FN(FSE_A), GPIO_FN(ET0_TX_CLK_B),
-
- /* IPSR3 */
- GPIO_FN(D15), GPIO_FN(SCK2_B),
- GPIO_FN(CS1_A26), GPIO_FN(QIO3_B),
- GPIO_FN(EX_CS1), GPIO_FN(RX3_B), GPIO_FN(ATACS0), GPIO_FN(QIO2_B),
- GPIO_FN(ET0_ETXD0),
- GPIO_FN(EX_CS2), GPIO_FN(TX3_B), GPIO_FN(ATACS1), GPIO_FN(QSPCLK_B),
- GPIO_FN(ET0_GTX_CLK_A),
- GPIO_FN(EX_CS3), GPIO_FN(SD1_CD_A), GPIO_FN(ATARD), GPIO_FN(QMO_QIO0_B),
- GPIO_FN(ET0_ETXD1_A),
- GPIO_FN(EX_CS4), GPIO_FN(SD1_WP_A), GPIO_FN(ATAWR), GPIO_FN(QMI_QIO1_B),
- GPIO_FN(ET0_ETXD2_A),
- GPIO_FN(EX_CS5), GPIO_FN(SD1_CMD_A), GPIO_FN(ATADIR), GPIO_FN(QSSL_B),
- GPIO_FN(ET0_ETXD3_A),
- GPIO_FN(RD_WR), GPIO_FN(TCLK1_B),
- GPIO_FN(EX_WAIT0), GPIO_FN(TCLK1_B),
- GPIO_FN(EX_WAIT1), GPIO_FN(SD1_DAT0_A), GPIO_FN(DREQ2),
- GPIO_FN(CAN1_TX_C), GPIO_FN(ET0_LINK_C), GPIO_FN(ET0_ETXD5_A),
- GPIO_FN(EX_WAIT2), GPIO_FN(SD1_DAT1_A), GPIO_FN(DACK2),
- GPIO_FN(CAN1_RX_C), GPIO_FN(ET0_MAGIC_C), GPIO_FN(ET0_ETXD6_A),
- GPIO_FN(DRACK0), GPIO_FN(SD1_DAT2_A), GPIO_FN(ATAG), GPIO_FN(TCLK1_A),
- GPIO_FN(ET0_ETXD7),
-
- /* IPSR4 */
- GPIO_FN(HCTS0_A), GPIO_FN(CTS1_A), GPIO_FN(VI0_FIELD),
- GPIO_FN(RMII0_RXD1_A), GPIO_FN(ET0_ERXD7),
- GPIO_FN(HRTS0_A), GPIO_FN(RTS1_A), GPIO_FN(VI0_HSYNC),
- GPIO_FN(RMII0_TXD_EN_A), GPIO_FN(ET0_RX_DV),
- GPIO_FN(HSCK0_A), GPIO_FN(SCK1_A), GPIO_FN(VI0_VSYNC),
- GPIO_FN(RMII0_RX_ER_A), GPIO_FN(ET0_RX_ER),
- GPIO_FN(HRX0_A), GPIO_FN(RX1_A), GPIO_FN(VI0_DATA0_VI0_B0),
- GPIO_FN(RMII0_CRS_DV_A), GPIO_FN(ET0_CRS),
- GPIO_FN(HTX0_A), GPIO_FN(TX1_A), GPIO_FN(VI0_DATA1_VI0_B1),
- GPIO_FN(RMII0_MDC_A), GPIO_FN(ET0_COL),
- GPIO_FN(CTS0_B), GPIO_FN(VI0_DATA2_VI0_B2), GPIO_FN(RMII0_MDIO_A),
- GPIO_FN(ET0_MDC),
- GPIO_FN(RTS0_B), GPIO_FN(VI0_DATA3_VI0_B3), GPIO_FN(ET0_MDIO_A),
- GPIO_FN(SCK1_B), GPIO_FN(VI0_DATA4_VI0_B4), GPIO_FN(ET0_LINK_A),
- GPIO_FN(RX1_B), GPIO_FN(VI0_DATA5_VI0_B5), GPIO_FN(ET0_MAGIC_A),
- GPIO_FN(TX1_B), GPIO_FN(VI0_DATA6_VI0_G0), GPIO_FN(ET0_PHY_INT_A),
- GPIO_FN(CTS1_B), GPIO_FN(VI0_DATA7_VI0_G1),
- GPIO_FN(RTS1_B), GPIO_FN(VI0_G2),
- GPIO_FN(SCK2_A), GPIO_FN(VI0_G3),
-
- /* IPSR5 */
- GPIO_FN(REF50CK), GPIO_FN(CTS1_E), GPIO_FN(HCTS0_D),
- GPIO_FN(REF125CK), GPIO_FN(ADTRG), GPIO_FN(RX5_C),
- GPIO_FN(SD2_WP_A), GPIO_FN(TX5_A), GPIO_FN(VI0_R5),
- GPIO_FN(SD2_CD_A), GPIO_FN(RX5_A), GPIO_FN(VI0_R4),
- GPIO_FN(ET0_PHY_INT_B),
- GPIO_FN(SD2_DAT3_A), GPIO_FN(TX4_A), GPIO_FN(VI0_R3),
- GPIO_FN(ET0_MAGIC_B),
- GPIO_FN(SD2_DAT2_A), GPIO_FN(RX4_A), GPIO_FN(VI0_R2),
- GPIO_FN(ET0_LINK_B),
- GPIO_FN(SD2_DAT1_A), GPIO_FN(TX3_A), GPIO_FN(VI0_R1),
- GPIO_FN(ET0_MDIO_B),
- GPIO_FN(SD2_DAT0_A), GPIO_FN(RX3_A), GPIO_FN(VI0_R0),
- GPIO_FN(ET0_ERXD3_B),
- GPIO_FN(SD2_CMD_A), GPIO_FN(TX2_A), GPIO_FN(VI0_G5),
- GPIO_FN(ET0_ERXD2_B),
- GPIO_FN(SD2_CLK_A), GPIO_FN(RX2_A), GPIO_FN(VI0_G4),
- GPIO_FN(ET0_RX_CLK_B),
-
- /* IPSR6 */
- GPIO_FN(DU0_DG1), GPIO_FN(CTS1_C), GPIO_FN(HRTS0_D),
- GPIO_FN(TIOC1B_A), GPIO_FN(HIFD09),
- GPIO_FN(DU0_DG0), GPIO_FN(TX1_C), GPIO_FN(HSCK0_D),
- GPIO_FN(IECLK_A), GPIO_FN(TIOC1A_A), GPIO_FN(HIFD08),
- GPIO_FN(DU0_DR7), GPIO_FN(RX1_C), GPIO_FN(TIOC0D_A),
- GPIO_FN(HIFD07),
- GPIO_FN(DU0_DR6), GPIO_FN(SCK1_C), GPIO_FN(TIOC0C_A),
- GPIO_FN(HIFD06),
- GPIO_FN(DU0_DR5), GPIO_FN(RTS0_C), GPIO_FN(TIOC0B_A),
- GPIO_FN(HIFD05),
- GPIO_FN(DU0_DR4), GPIO_FN(CTS0_C), GPIO_FN(TIOC0A_A),
- GPIO_FN(HIFD04),
- GPIO_FN(DU0_DR3), GPIO_FN(TX0_B), GPIO_FN(TCLKD_A), GPIO_FN(HIFD03),
- GPIO_FN(DU0_DR2), GPIO_FN(RX0_B), GPIO_FN(TCLKC_A), GPIO_FN(HIFD02),
- GPIO_FN(DU0_DR1), GPIO_FN(SCK0_B), GPIO_FN(HTX0_D),
- GPIO_FN(IERX_A), GPIO_FN(TCLKB_A), GPIO_FN(HIFD01),
- GPIO_FN(DU0_DR0), GPIO_FN(SCIF_CLK_B), GPIO_FN(HRX0_D),
- GPIO_FN(IETX_A), GPIO_FN(TCLKA_A), GPIO_FN(HIFD00),
-
- /* IPSR7 */
- GPIO_FN(DU0_DB4), GPIO_FN(HIFINT),
- GPIO_FN(DU0_DB3), GPIO_FN(TX5_B), GPIO_FN(TIOC4D_A), GPIO_FN(HIFRD),
- GPIO_FN(DU0_DB2), GPIO_FN(RX5_B), GPIO_FN(RMII0_TXD1_B),
- GPIO_FN(TIOC4C_A), GPIO_FN(HIFWR),
- GPIO_FN(DU0_DB1), GPIO_FN(TX4_C), GPIO_FN(RMII0_TXD0_B),
- GPIO_FN(TIOC4B_A), GPIO_FN(HIFRS),
- GPIO_FN(DU0_DB0), GPIO_FN(RX4_C), GPIO_FN(RMII0_TXD_EN_B),
- GPIO_FN(TIOC4A_A), GPIO_FN(HIFCS),
- GPIO_FN(DU0_DG7), GPIO_FN(TX3_C), GPIO_FN(RMII0_RXD1_B),
- GPIO_FN(TIOC3D_A), GPIO_FN(HIFD15),
- GPIO_FN(DU0_DG6), GPIO_FN(RX3_C), GPIO_FN(RMII0_RXD0_B),
- GPIO_FN(TIOC3C_A), GPIO_FN(HIFD14),
- GPIO_FN(DU0_DG5), GPIO_FN(TX2_C), GPIO_FN(RMII0_RX_ER_B),
- GPIO_FN(TIOC3B_A), GPIO_FN(HIFD13),
- GPIO_FN(DU0_DG4), GPIO_FN(RX2_C), GPIO_FN(RMII0_CRS_DV_B),
- GPIO_FN(TIOC3A_A), GPIO_FN(HIFD12),
- GPIO_FN(DU0_DG3), GPIO_FN(SCK2_C), GPIO_FN(RMII0_MDIO_B),
- GPIO_FN(TIOC2B_A), GPIO_FN(HIFD11),
- GPIO_FN(DU0_DG2), GPIO_FN(RTS1_C), GPIO_FN(RMII0_MDC_B),
- GPIO_FN(TIOC2A_A), GPIO_FN(HIFD10),
-
- /* IPSR8 */
- GPIO_FN(IRQ3_A), GPIO_FN(RTS0_A), GPIO_FN(HRTS0_B),
- GPIO_FN(ET0_ERXD3_A),
- GPIO_FN(IRQ2_A), GPIO_FN(CTS0_A), GPIO_FN(HCTS0_B),
- GPIO_FN(ET0_ERXD2_A),
- GPIO_FN(IRQ1_A), GPIO_FN(HSPI_RX_B), GPIO_FN(TX3_E),
- GPIO_FN(ET0_ERXD1),
- GPIO_FN(IRQ0_A), GPIO_FN(HSPI_TX_B), GPIO_FN(RX3_E),
- GPIO_FN(ET0_ERXD0),
- GPIO_FN(DU0_CDE), GPIO_FN(HTX0_B), GPIO_FN(AUDIO_CLKB_B),
- GPIO_FN(LCD_VCPWC_B),
- GPIO_FN(DU0_DISP), GPIO_FN(CAN0_TX_B), GPIO_FN(HRX0_B),
- GPIO_FN(AUDIO_CLKA_B),
- GPIO_FN(DU0_EXODDF_DU0_ODDF), GPIO_FN(CAN0_RX_B), GPIO_FN(HSCK0_B),
- GPIO_FN(SSI_SDATA1_B),
- GPIO_FN(DU0_EXVSYNC_DU0_VSYNC), GPIO_FN(HSPI_RX0_C),
- GPIO_FN(SSI_WS1_B),
- GPIO_FN(DU0_EXHSYNC_DU0_HSYNC), GPIO_FN(HSPI_TX0_C),
- GPIO_FN(SSI_SCK1_B),
- GPIO_FN(DU0_DOTCLKOUT), GPIO_FN(HSPI_CLK0_C),
- GPIO_FN(SSI_SDATA0_B),
- GPIO_FN(DU0_DOTCLKIN), GPIO_FN(HSPI_CS0_C),
- GPIO_FN(SSI_WS0_B),
- GPIO_FN(DU0_DB7), GPIO_FN(SSI_SCK0_B), GPIO_FN(HIFEBL_B),
- GPIO_FN(DU0_DB6), GPIO_FN(HIFRDY),
- GPIO_FN(DU0_DB5), GPIO_FN(HIFDREQ),
-
- /* IPSR9 */
- GPIO_FN(SSI_SDATA1_A), GPIO_FN(VI1_3_B), GPIO_FN(LCD_DATA14_B),
- GPIO_FN(SSI_WS1_A), GPIO_FN(VI1_2_B), GPIO_FN(LCD_DATA13_B),
- GPIO_FN(SSI_SCK1_A), GPIO_FN(VI1_1_B), GPIO_FN(TIOC2B_B),
- GPIO_FN(LCD_DATA12_B),
- GPIO_FN(SSI_SDATA0_A), GPIO_FN(VI1_0_B), GPIO_FN(TIOC2A_B),
- GPIO_FN(LCD_DATA11_B),
- GPIO_FN(SSI_WS0_A), GPIO_FN(TIOC1B_B), GPIO_FN(LCD_DATA10_B),
- GPIO_FN(SSI_SCK0_A), GPIO_FN(TIOC1A_B), GPIO_FN(LCD_DATA9_B),
- GPIO_FN(VI1_7_A), GPIO_FN(FCE_B), GPIO_FN(LCD_DATA8_B),
- GPIO_FN(VI1_6_A), GPIO_FN(FD7_B), GPIO_FN(LCD_DATA7_B),
- GPIO_FN(VI1_5_A), GPIO_FN(FD6_B), GPIO_FN(LCD_DATA6_B),
- GPIO_FN(VI1_4_A), GPIO_FN(FD5_B), GPIO_FN(LCD_DATA5_B),
- GPIO_FN(VI1_3_A), GPIO_FN(FD4_B), GPIO_FN(LCD_DATA4_B),
- GPIO_FN(VI1_2_A), GPIO_FN(FD3_B), GPIO_FN(LCD_DATA3_B),
- GPIO_FN(VI1_1_A), GPIO_FN(FD2_B), GPIO_FN(LCD_DATA2_B),
- GPIO_FN(VI1_0_A), GPIO_FN(FD1_B), GPIO_FN(LCD_DATA1_B),
- GPIO_FN(VI1_CLK_A), GPIO_FN(FD0_B), GPIO_FN(LCD_DATA0_B),
-
- /* IPSR10 */
- GPIO_FN(CAN1_TX_A), GPIO_FN(TX5_C), GPIO_FN(MLB_DAT),
- GPIO_FN(CAN0_RX_A), GPIO_FN(IRQ0_B), GPIO_FN(MLB_SIG),
- GPIO_FN(CAN1_RX_A), GPIO_FN(IRQ1_B),
- GPIO_FN(CAN0_TX_A), GPIO_FN(TX4_D), GPIO_FN(MLB_CLK),
- GPIO_FN(CAN_CLK_A), GPIO_FN(RX4_D),
- GPIO_FN(AUDIO_CLKOUT), GPIO_FN(TX1_E), GPIO_FN(HRTS0_C),
- GPIO_FN(FSE_B), GPIO_FN(LCD_M_DISP_B),
- GPIO_FN(AUDIO_CLKC), GPIO_FN(SCK1_E), GPIO_FN(HCTS0_C),
- GPIO_FN(FRB_B), GPIO_FN(LCD_VEPWC_B),
- GPIO_FN(AUDIO_CLKB_A), GPIO_FN(LCD_CLK_B),
- GPIO_FN(AUDIO_CLKA_A), GPIO_FN(VI1_CLK_B), GPIO_FN(SCK1_D),
- GPIO_FN(IECLK_B), GPIO_FN(LCD_FLM_B),
- GPIO_FN(SSI_SDATA3), GPIO_FN(VI1_7_B), GPIO_FN(HTX0_C),
- GPIO_FN(FWE_B), GPIO_FN(LCD_CL2_B),
- GPIO_FN(SSI_SDATA2), GPIO_FN(VI1_6_B), GPIO_FN(HRX0_C),
- GPIO_FN(FRE_B), GPIO_FN(LCD_CL1_B),
- GPIO_FN(SSI_WS23), GPIO_FN(VI1_5_B), GPIO_FN(TX1_D),
- GPIO_FN(HSCK0_C), GPIO_FN(FALE_B), GPIO_FN(LCD_DON_B),
- GPIO_FN(SSI_SCK23), GPIO_FN(VI1_4_B), GPIO_FN(RX1_D),
- GPIO_FN(FCLE_B), GPIO_FN(LCD_DATA15_B),
-
- /* IPSR11 */
- GPIO_FN(PRESETOUT), GPIO_FN(ST_CLKOUT),
- GPIO_FN(DACK1), GPIO_FN(HSPI_CS_B), GPIO_FN(TX4_B),
- GPIO_FN(ET0_RX_CLK_A),
- GPIO_FN(DREQ1), GPIO_FN(HSPI_CLK_B), GPIO_FN(RX4_B),
- GPIO_FN(ET0_PHY_INT_C), GPIO_FN(ET0_TX_CLK_A),
- GPIO_FN(DACK0), GPIO_FN(SD1_DAT3_A), GPIO_FN(ET0_TX_ER),
- GPIO_FN(DREQ0), GPIO_FN(SD1_CLK_A), GPIO_FN(ET0_TX_EN),
- GPIO_FN(USB_OVC1), GPIO_FN(RX3_D), GPIO_FN(CAN1_RX_B),
- GPIO_FN(RX5_D), GPIO_FN(IERX_B),
- GPIO_FN(PENC1), GPIO_FN(TX3_D), GPIO_FN(CAN1_TX_B),
- GPIO_FN(TX5_D), GPIO_FN(IETX_B),
- GPIO_FN(TX0_A), GPIO_FN(HSPI_TX_A),
- GPIO_FN(RX0_A), GPIO_FN(HSPI_RX_A), GPIO_FN(RMII0_RXD0_A),
- GPIO_FN(ET0_ERXD6),
- GPIO_FN(SCK0_A), GPIO_FN(HSPI_CS_A), GPIO_FN(VI0_CLKENB),
- GPIO_FN(RMII0_TXD1_A), GPIO_FN(ET0_ERXD5),
- GPIO_FN(SCIF_CLK_A), GPIO_FN(HSPI_CLK_A), GPIO_FN(VI0_CLK),
- GPIO_FN(RMII0_TXD0_A), GPIO_FN(ET0_ERXD4),
- GPIO_FN(SDSELF), GPIO_FN(RTS1_E),
- GPIO_FN(SDA0), GPIO_FN(HIFEBL_A),
- GPIO_FN(SDA1), GPIO_FN(RX1_E),
- GPIO_FN(SCL1), GPIO_FN(SCIF_CLK_C),
-};
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- { PINMUX_CFG_REG("GPSR0", 0xFFFC0004, 32, 1) {
- GP_0_31_FN, FN_IP2_2_0,
- GP_0_30_FN, FN_IP1_31_29,
- GP_0_29_FN, FN_IP1_28_26,
- GP_0_28_FN, FN_IP1_25_23,
- GP_0_27_FN, FN_IP1_22_20,
- GP_0_26_FN, FN_IP1_19_18,
- GP_0_25_FN, FN_IP1_17_16,
- GP_0_24_FN, FN_IP0_5_4,
- GP_0_23_FN, FN_IP0_3_2,
- GP_0_22_FN, FN_IP0_1_0,
- GP_0_21_FN, FN_IP11_28,
- GP_0_20_FN, FN_IP1_7_6,
- GP_0_19_FN, FN_IP1_5_4,
- GP_0_18_FN, FN_IP1_3_2,
- GP_0_17_FN, FN_IP1_1_0,
- GP_0_16_FN, FN_IP0_31_30,
- GP_0_15_FN, FN_IP0_29_28,
- GP_0_14_FN, FN_IP0_27_26,
- GP_0_13_FN, FN_IP0_25_24,
- GP_0_12_FN, FN_IP0_23_22,
- GP_0_11_FN, FN_IP0_21_20,
- GP_0_10_FN, FN_IP0_19_18,
- GP_0_9_FN, FN_IP0_17_16,
- GP_0_8_FN, FN_IP0_15_14,
- GP_0_7_FN, FN_IP0_13_12,
- GP_0_6_FN, FN_IP0_11_10,
- GP_0_5_FN, FN_IP0_9_8,
- GP_0_4_FN, FN_IP0_7_6,
- GP_0_3_FN, FN_IP1_15_14,
- GP_0_2_FN, FN_IP1_13_12,
- GP_0_1_FN, FN_IP1_11_10,
- GP_0_0_FN, FN_IP1_9_8 }
- },
- { PINMUX_CFG_REG("GPSR1", 0xFFFC0008, 32, 1) {
- GP_1_31_FN, FN_IP11_25_23,
- GP_1_30_FN, FN_IP2_13_11,
- GP_1_29_FN, FN_IP2_10_8,
- GP_1_28_FN, FN_IP2_7_5,
- GP_1_27_FN, FN_IP3_26_24,
- GP_1_26_FN, FN_IP3_23_21,
- GP_1_25_FN, FN_IP2_4_3,
- GP_1_24_FN, FN_WE1,
- GP_1_23_FN, FN_WE0,
- GP_1_22_FN, FN_IP3_19_18,
- GP_1_21_FN, FN_RD,
- GP_1_20_FN, FN_IP3_17_15,
- GP_1_19_FN, FN_IP3_14_12,
- GP_1_18_FN, FN_IP3_11_9,
- GP_1_17_FN, FN_IP3_8_6,
- GP_1_16_FN, FN_IP3_5_3,
- GP_1_15_FN, FN_EX_CS0,
- GP_1_14_FN, FN_IP3_2,
- GP_1_13_FN, FN_CS0,
- GP_1_12_FN, FN_BS,
- GP_1_11_FN, FN_CLKOUT,
- GP_1_10_FN, FN_IP3_1_0,
- GP_1_9_FN, FN_IP2_30_28,
- GP_1_8_FN, FN_IP2_27_25,
- GP_1_7_FN, FN_IP2_24_23,
- GP_1_6_FN, FN_IP2_22_20,
- GP_1_5_FN, FN_IP2_19_17,
- GP_1_4_FN, FN_IP2_16_14,
- GP_1_3_FN, FN_IP11_22_21,
- GP_1_2_FN, FN_IP11_20_19,
- GP_1_1_FN, FN_IP3_29_27,
- GP_1_0_FN, FN_IP3_20 }
- },
- { PINMUX_CFG_REG("GPSR2", 0xFFFC000C, 32, 1) {
- GP_2_31_FN, FN_IP4_31_30,
- GP_2_30_FN, FN_IP5_2_0,
- GP_2_29_FN, FN_IP5_5_3,
- GP_2_28_FN, FN_IP5_8_6,
- GP_2_27_FN, FN_IP5_11_9,
- GP_2_26_FN, FN_IP5_14_12,
- GP_2_25_FN, FN_IP5_17_15,
- GP_2_24_FN, FN_IP5_20_18,
- GP_2_23_FN, FN_IP5_22_21,
- GP_2_22_FN, FN_IP5_24_23,
- GP_2_21_FN, FN_IP5_26_25,
- GP_2_20_FN, FN_IP4_29_28,
- GP_2_19_FN, FN_IP4_27_26,
- GP_2_18_FN, FN_IP4_25_24,
- GP_2_17_FN, FN_IP4_23_22,
- GP_2_16_FN, FN_IP4_21_20,
- GP_2_15_FN, FN_IP4_19_18,
- GP_2_14_FN, FN_IP4_17_15,
- GP_2_13_FN, FN_IP4_14_12,
- GP_2_12_FN, FN_IP4_11_9,
- GP_2_11_FN, FN_IP4_8_6,
- GP_2_10_FN, FN_IP4_5_3,
- GP_2_9_FN, FN_IP8_27_26,
- GP_2_8_FN, FN_IP11_12,
- GP_2_7_FN, FN_IP8_25_23,
- GP_2_6_FN, FN_IP8_22_20,
- GP_2_5_FN, FN_IP11_27_26,
- GP_2_4_FN, FN_IP8_29_28,
- GP_2_3_FN, FN_IP4_2_0,
- GP_2_2_FN, FN_IP11_11_10,
- GP_2_1_FN, FN_IP11_9_7,
- GP_2_0_FN, FN_IP11_6_4 }
- },
- { PINMUX_CFG_REG("GPSR3", 0xFFFC0010, 32, 1) {
- GP_3_31_FN, FN_IP9_1_0,
- GP_3_30_FN, FN_IP8_19_18,
- GP_3_29_FN, FN_IP8_17_16,
- GP_3_28_FN, FN_IP8_15_14,
- GP_3_27_FN, FN_IP8_13_12,
- GP_3_26_FN, FN_IP8_11_10,
- GP_3_25_FN, FN_IP8_9_8,
- GP_3_24_FN, FN_IP8_7_6,
- GP_3_23_FN, FN_IP8_5_4,
- GP_3_22_FN, FN_IP8_3_2,
- GP_3_21_FN, FN_IP8_1_0,
- GP_3_20_FN, FN_IP7_30_29,
- GP_3_19_FN, FN_IP7_28_27,
- GP_3_18_FN, FN_IP7_26_24,
- GP_3_17_FN, FN_IP7_23_21,
- GP_3_16_FN, FN_IP7_20_18,
- GP_3_15_FN, FN_IP7_17_15,
- GP_3_14_FN, FN_IP7_14_12,
- GP_3_13_FN, FN_IP7_11_9,
- GP_3_12_FN, FN_IP7_8_6,
- GP_3_11_FN, FN_IP7_5_3,
- GP_3_10_FN, FN_IP7_2_0,
- GP_3_9_FN, FN_IP6_23_21,
- GP_3_8_FN, FN_IP6_20_18,
- GP_3_7_FN, FN_IP6_17_16,
- GP_3_6_FN, FN_IP6_15_14,
- GP_3_5_FN, FN_IP6_13_12,
- GP_3_4_FN, FN_IP6_11_10,
- GP_3_3_FN, FN_IP6_9_8,
- GP_3_2_FN, FN_IP6_7_6,
- GP_3_1_FN, FN_IP6_5_3,
- GP_3_0_FN, FN_IP6_2_0 }
- },
-
- { PINMUX_CFG_REG("GPSR4", 0xFFFC0014, 32, 1) {
- GP_4_31_FN, FN_IP10_24_23,
- GP_4_30_FN, FN_IP10_22,
- GP_4_29_FN, FN_IP11_18_16,
- GP_4_28_FN, FN_USB_OVC0,
- GP_4_27_FN, FN_IP11_15_13,
- GP_4_26_FN, FN_PENC0,
- GP_4_25_FN, FN_IP11_2,
- GP_4_24_FN, FN_SCL0,
- GP_4_23_FN, FN_IP11_1,
- GP_4_22_FN, FN_IP11_0,
- GP_4_21_FN, FN_IP10_21_19,
- GP_4_20_FN, FN_IP10_18_16,
- GP_4_19_FN, FN_IP10_15,
- GP_4_18_FN, FN_IP10_14_12,
- GP_4_17_FN, FN_IP10_11_9,
- GP_4_16_FN, FN_IP10_8_6,
- GP_4_15_FN, FN_IP10_5_3,
- GP_4_14_FN, FN_IP10_2_0,
- GP_4_13_FN, FN_IP9_29_28,
- GP_4_12_FN, FN_IP9_27_26,
- GP_4_11_FN, FN_IP9_9_8,
- GP_4_10_FN, FN_IP9_7_6,
- GP_4_9_FN, FN_IP9_5_4,
- GP_4_8_FN, FN_IP9_3_2,
- GP_4_7_FN, FN_IP9_17_16,
- GP_4_6_FN, FN_IP9_15_14,
- GP_4_5_FN, FN_IP9_13_12,
- GP_4_4_FN, FN_IP9_11_10,
- GP_4_3_FN, FN_IP9_25_24,
- GP_4_2_FN, FN_IP9_23_22,
- GP_4_1_FN, FN_IP9_21_20,
- GP_4_0_FN, FN_IP9_19_18 }
- },
- { PINMUX_CFG_REG("GPSR5", 0xFFFC0018, 32, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0, /* 31 - 28 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 27 - 24 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 23 - 20 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 19 - 16 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 15 - 12 */
- GP_5_11_FN, FN_IP10_29_28,
- GP_5_10_FN, FN_IP10_27_26,
- 0, 0, 0, 0, 0, 0, 0, 0, /* 9 - 6 */
- 0, 0, 0, 0, /* 5, 4 */
- GP_5_3_FN, FN_IRQ3_B,
- GP_5_2_FN, FN_IRQ2_B,
- GP_5_1_FN, FN_IP11_3,
- GP_5_0_FN, FN_IP10_25 }
- },
-
- { PINMUX_CFG_REG_VAR("IPSR0", 0xFFFC001C, 32,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2) {
- /* IP0_31_30 [2] */
- FN_A15, FN_ST0_VCO_CLKIN, FN_LCD_DATA15_A,
- FN_TIOC3D_C,
- /* IP0_29_28 [2] */
- FN_A14, FN_LCD_DATA14_A, FN_TIOC3C_C, 0,
- /* IP0_27_26 [2] */
- FN_A13, FN_LCD_DATA13_A, FN_TIOC3B_C, 0,
- /* IP0_25_24 [2] */
- FN_A12, FN_LCD_DATA12_A, FN_TIOC3A_C, 0,
- /* IP0_23_22 [2] */
- FN_A11, FN_ST0_D7, FN_LCD_DATA11_A, FN_TIOC2B_C,
- /* IP0_21_20 [2] */
- FN_A10, FN_ST0_D6, FN_LCD_DATA10_A, FN_TIOC2A_C,
- /* IP0_19_18 [2] */
- FN_A9, FN_ST0_D5, FN_LCD_DATA9_A, FN_TIOC1B_C,
- /* IP0_17_16 [2] */
- FN_A8, FN_ST0_D4, FN_LCD_DATA8_A, FN_TIOC1A_C,
- /* IP0_15_14 [2] */
- FN_A7, FN_ST0_D3, FN_LCD_DATA7_A, FN_TIOC0D_C,
- /* IP0_13_12 [2] */
- FN_A6, FN_ST0_D2, FN_LCD_DATA6_A, FN_TIOC0C_C,
- /* IP0_11_10 [2] */
- FN_A5, FN_ST0_D1, FN_LCD_DATA5_A, FN_TIOC0B_C,
- /* IP0_9_8 [2] */
- FN_A4, FN_ST0_D0, FN_LCD_DATA4_A, FN_TIOC0A_C,
- /* IP0_7_6 [2] */
- FN_A3, FN_ST0_VLD, FN_LCD_DATA3_A, FN_TCLKD_C,
- /* IP0_5_4 [2] */
- FN_A2, FN_ST0_SYC, FN_LCD_DATA2_A, FN_TCLKC_C,
- /* IP0_3_2 [2] */
- FN_A1, FN_ST0_REQ, FN_LCD_DATA1_A, FN_TCLKB_C,
- /* IP0_1_0 [2] */
- FN_A0, FN_ST0_CLKIN, FN_LCD_DATA0_A, FN_TCLKA_C }
- },
- { PINMUX_CFG_REG_VAR("IPSR1", 0xFFFC0020, 32,
- 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
- /* IP1_31_29 [3] */
- FN_D3, FN_SD0_DAT3_A, FN_MMC_D3_A, FN_ST1_D6,
- FN_FD3_A, 0, 0, 0,
- /* IP1_28_26 [3] */
- FN_D2, FN_SD0_DAT2_A, FN_MMC_D2_A, FN_ST1_D5,
- FN_FD2_A, 0, 0, 0,
- /* IP1_25_23 [3] */
- FN_D1, FN_SD0_DAT1_A, FN_MMC_D1_A, FN_ST1_D4,
- FN_FD1_A, 0, 0, 0,
- /* IP1_22_20 [3] */
- FN_D0, FN_SD0_DAT0_A, FN_MMC_D0_A, FN_ST1_D3,
- FN_FD0_A, 0, 0, 0,
- /* IP1_19_18 [2] */
- FN_A25, FN_TX2_D, FN_ST1_D2, 0,
- /* IP1_17_16 [2] */
- FN_A24, FN_RX2_D, FN_ST1_D1, 0,
- /* IP1_15_14 [2] */
- FN_A23, FN_ST1_D0, FN_LCD_M_DISP_A, 0,
- /* IP1_13_12 [2] */
- FN_A22, FN_ST1_VLD, FN_LCD_VEPWC_A, 0,
- /* IP1_11_10 [2] */
- FN_A21, FN_ST1_SYC, FN_LCD_VCPWC_A, 0,
- /* IP1_9_8 [2] */
- FN_A20, FN_ST1_REQ, FN_LCD_FLM_A, 0,
- /* IP1_7_6 [2] */
- FN_A19, FN_ST1_CLKIN, FN_LCD_CLK_A, FN_TIOC4D_C,
- /* IP1_5_4 [2] */
- FN_A18, FN_ST1_PWM, FN_LCD_CL2_A, FN_TIOC4C_C,
- /* IP1_3_2 [2] */
- FN_A17, FN_ST1_VCO_CLKIN, FN_LCD_CL1_A, FN_TIOC4B_C,
- /* IP1_1_0 [2] */
- FN_A16, FN_ST0_PWM, FN_LCD_DON_A, FN_TIOC4A_C }
- },
- { PINMUX_CFG_REG_VAR("IPSR2", 0xFFFC0024, 32,
- 1, 3, 3, 2, 3, 3, 3, 3, 3, 3, 2, 3) {
- /* IP2_31 [1] */
- 0, 0,
- /* IP2_30_28 [3] */
- FN_D14, FN_TX2_B, 0, FN_FSE_A,
- FN_ET0_TX_CLK_B, 0, 0, 0,
- /* IP2_27_25 [3] */
- FN_D13, FN_RX2_B, 0, FN_FRB_A,
- FN_ET0_ETXD6_B, 0, 0, 0,
- /* IP2_24_23 [2] */
- FN_D12, 0, FN_FWE_A, FN_ET0_ETXD5_B,
- /* IP2_22_20 [3] */
- FN_D11, FN_RSPI_MISO_A, 0, FN_QMI_QIO1_A,
- FN_FRE_A, FN_ET0_ETXD3_B, 0, 0,
- /* IP2_19_17 [3] */
- FN_D10, FN_RSPI_MOSI_A, 0, FN_QMO_QIO0_A,
- FN_FALE_A, FN_ET0_ETXD2_B, 0, 0,
- /* IP2_16_14 [3] */
- FN_D9, FN_SD0_CMD_A, FN_MMC_CMD_A, FN_QIO3_A,
- FN_FCLE_A, FN_ET0_ETXD1_B, 0, 0,
- /* IP2_13_11 [3] */
- FN_D8, FN_SD0_CLK_A, FN_MMC_CLK_A, FN_QIO2_A,
- FN_FCE_A, FN_ET0_GTX_CLK_B, 0, 0,
- /* IP2_10_8 [3] */
- FN_D7, FN_RSPI_SSL_A, FN_MMC_D7_A, FN_QSSL_A,
- FN_FD7_A, 0, 0, 0,
- /* IP2_7_5 [3] */
- FN_D6, FN_RSPI_RSPCK_A, FN_MMC_D6_A, FN_QSPCLK_A,
- FN_FD6_A, 0, 0, 0,
- /* IP2_4_3 [2] */
- FN_D5, FN_SD0_WP_A, FN_MMC_D5_A, FN_FD5_A,
- /* IP2_2_0 [3] */
- FN_D4, FN_SD0_CD_A, FN_MMC_D4_A, FN_ST1_D7,
- FN_FD4_A, 0, 0, 0 }
- },
- { PINMUX_CFG_REG_VAR("IPSR3", 0xFFFC0028, 32,
- 2, 3, 3, 3, 1, 2, 3, 3, 3, 3, 3, 1, 2) {
- /* IP3_31_30 [2] */
- 0, 0, 0, 0,
- /* IP3_29_27 [3] */
- FN_DRACK0, FN_SD1_DAT2_A, FN_ATAG, FN_TCLK1_A,
- FN_ET0_ETXD7, 0, 0, 0,
- /* IP3_26_24 [3] */
- FN_EX_WAIT2, FN_SD1_DAT1_A, FN_DACK2, FN_CAN1_RX_C,
- FN_ET0_MAGIC_C, FN_ET0_ETXD6_A, 0, 0,
- /* IP3_23_21 [3] */
- FN_EX_WAIT1, FN_SD1_DAT0_A, FN_DREQ2, FN_CAN1_TX_C,
- FN_ET0_LINK_C, FN_ET0_ETXD5_A, 0, 0,
- /* IP3_20 [1] */
- FN_EX_WAIT0, FN_TCLK1_B,
- /* IP3_19_18 [2] */
- FN_RD_WR, FN_TCLK1_B, 0, 0,
- /* IP3_17_15 [3] */
- FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B,
- FN_ET0_ETXD3_A, 0, 0, 0,
- /* IP3_14_12 [3] */
- FN_EX_CS4, FN_SD1_WP_A, FN_ATAWR, FN_QMI_QIO1_B,
- FN_ET0_ETXD2_A, 0, 0, 0,
- /* IP3_11_9 [3] */
- FN_EX_CS3, FN_SD1_CD_A, FN_ATARD, FN_QMO_QIO0_B,
- FN_ET0_ETXD1_A, 0, 0, 0,
- /* IP3_8_6 [3] */
- FN_EX_CS2, FN_TX3_B, FN_ATACS1, FN_QSPCLK_B,
- FN_ET0_GTX_CLK_A, 0, 0, 0,
- /* IP3_5_3 [3] */
- FN_EX_CS1, FN_RX3_B, FN_ATACS0, FN_QIO2_B,
- FN_ET0_ETXD0, 0, 0, 0,
- /* IP3_2 [1] */
- FN_CS1_A26, FN_QIO3_B,
- /* IP3_1_0 [2] */
- FN_D15, FN_SCK2_B, 0, 0 }
- },
- { PINMUX_CFG_REG_VAR("IPSR4", 0xFFFC002C, 32,
- 2, 2, 2, 2, 2, 2 , 2, 3, 3, 3, 3, 3, 3) {
- /* IP4_31_30 [2] */
- 0, FN_SCK2_A, FN_VI0_G3, 0,
- /* IP4_29_28 [2] */
- 0, FN_RTS1_B, FN_VI0_G2, 0,
- /* IP4_27_26 [2] */
- 0, FN_CTS1_B, FN_VI0_DATA7_VI0_G1, 0,
- /* IP4_25_24 [2] */
- 0, FN_TX1_B, FN_VI0_DATA6_VI0_G0, FN_ET0_PHY_INT_A,
- /* IP4_23_22 [2] */
- 0, FN_RX1_B, FN_VI0_DATA5_VI0_B5, FN_ET0_MAGIC_A,
- /* IP4_21_20 [2] */
- 0, FN_SCK1_B, FN_VI0_DATA4_VI0_B4, FN_ET0_LINK_A,
- /* IP4_19_18 [2] */
- 0, FN_RTS0_B, FN_VI0_DATA3_VI0_B3, FN_ET0_MDIO_A,
- /* IP4_17_15 [3] */
- 0, FN_CTS0_B, FN_VI0_DATA2_VI0_B2, FN_RMII0_MDIO_A,
- FN_ET0_MDC, 0, 0, 0,
- /* IP4_14_12 [3] */
- FN_HTX0_A, FN_TX1_A, FN_VI0_DATA1_VI0_B1, FN_RMII0_MDC_A,
- FN_ET0_COL, 0, 0, 0,
- /* IP4_11_9 [3] */
- FN_HRX0_A, FN_RX1_A, FN_VI0_DATA0_VI0_B0, FN_RMII0_CRS_DV_A,
- FN_ET0_CRS, 0, 0, 0,
- /* IP4_8_6 [3] */
- FN_HSCK0_A, FN_SCK1_A, FN_VI0_VSYNC, FN_RMII0_RX_ER_A,
- FN_ET0_RX_ER, 0, 0, 0,
- /* IP4_5_3 [3] */
- FN_HRTS0_A, FN_RTS1_A, FN_VI0_HSYNC, FN_RMII0_TXD_EN_A,
- FN_ET0_RX_DV, 0, 0, 0,
- /* IP4_2_0 [3] */
- FN_HCTS0_A, FN_CTS1_A, FN_VI0_FIELD, FN_RMII0_RXD1_A,
- FN_ET0_ERXD7, 0, 0, 0 }
- },
- { PINMUX_CFG_REG_VAR("IPSR5", 0xFFFC0030, 32,
- 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3) {
- /* IP5_31 [1] */
- 0, 0,
- /* IP5_30 [1] */
- 0, 0,
- /* IP5_29 [1] */
- 0, 0,
- /* IP5_28 [1] */
- 0, 0,
- /* IP5_27 [1] */
- 0, 0,
- /* IP5_26_25 [2] */
- FN_REF50CK, FN_CTS1_E, FN_HCTS0_D, 0,
- /* IP5_24_23 [2] */
- FN_REF125CK, FN_ADTRG, FN_RX5_C, 0,
- /* IP5_22_21 [2] */
- FN_SD2_WP_A, FN_TX5_A, FN_VI0_R5, 0,
- /* IP5_20_18 [3] */
- FN_SD2_CD_A, FN_RX5_A, FN_VI0_R4, 0,
- 0, 0, 0, FN_ET0_PHY_INT_B,
- /* IP5_17_15 [3] */
- FN_SD2_DAT3_A, FN_TX4_A, FN_VI0_R3, 0,
- 0, 0, 0, FN_ET0_MAGIC_B,
- /* IP5_14_12 [3] */
- FN_SD2_DAT2_A, FN_RX4_A, FN_VI0_R2, 0,
- 0, 0, 0, FN_ET0_LINK_B,
- /* IP5_11_9 [3] */
- FN_SD2_DAT1_A, FN_TX3_A, FN_VI0_R1, 0,
- 0, 0, 0, FN_ET0_MDIO_B,
- /* IP5_8_6 [3] */
- FN_SD2_DAT0_A, FN_RX3_A, FN_VI0_R0, 0,
- 0, 0, 0, FN_ET0_ERXD3_B,
- /* IP5_5_3 [3] */
- FN_SD2_CMD_A, FN_TX2_A, FN_VI0_G5, 0,
- 0, 0, 0, FN_ET0_ERXD2_B,
- /* IP5_2_0 [3] */
- FN_SD2_CLK_A, FN_RX2_A, FN_VI0_G4, 0,
- FN_ET0_RX_CLK_B, 0, 0, 0 }
- },
- { PINMUX_CFG_REG_VAR("IPSR6", 0xFFFC0034, 32,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 3, 3, 2, 2, 2, 2, 2, 2, 3, 3) {
- /* IP5_31 [1] */
- 0, 0,
- /* IP6_30 [1] */
- 0, 0,
- /* IP6_29 [1] */
- 0, 0,
- /* IP6_28 [1] */
- 0, 0,
- /* IP6_27 [1] */
- 0, 0,
- /* IP6_26 [1] */
- 0, 0,
- /* IP6_25 [1] */
- 0, 0,
- /* IP6_24 [1] */
- 0, 0,
- /* IP6_23_21 [3] */
- FN_DU0_DG1, FN_CTS1_C, FN_HRTS0_D, FN_TIOC1B_A,
- FN_HIFD09, 0, 0, 0,
- /* IP6_20_18 [3] */
- FN_DU0_DG0, FN_TX1_C, FN_HSCK0_D, FN_IECLK_A,
- FN_TIOC1A_A, FN_HIFD08, 0, 0,
- /* IP6_17_16 [2] */
- FN_DU0_DR7, FN_RX1_C, FN_TIOC0D_A, FN_HIFD07,
- /* IP6_15_14 [2] */
- FN_DU0_DR6, FN_SCK1_C, FN_TIOC0C_A, FN_HIFD06,
- /* IP6_13_12 [2] */
- FN_DU0_DR5, FN_RTS0_C, FN_TIOC0B_A, FN_HIFD05,
- /* IP6_11_10 [2] */
- FN_DU0_DR4, FN_CTS0_C, FN_TIOC0A_A, FN_HIFD04,
- /* IP6_9_8 [2] */
- FN_DU0_DR3, FN_TX0_B, FN_TCLKD_A, FN_HIFD03,
- /* IP6_7_6 [2] */
- FN_DU0_DR2, FN_RX0_B, FN_TCLKC_A, FN_HIFD02,
- /* IP6_5_3 [3] */
- FN_DU0_DR1, FN_SCK0_B, FN_HTX0_D, FN_IERX_A,
- FN_TCLKB_A, FN_HIFD01, 0, 0,
- /* IP6_2_0 [3] */
- FN_DU0_DR0, FN_SCIF_CLK_B, FN_HRX0_D, FN_IETX_A,
- FN_TCLKA_A, FN_HIFD00, 0, 0 }
- },
- { PINMUX_CFG_REG_VAR("IPSR7", 0xFFFC0038, 32,
- 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) {
- /* IP7_31 [1] */
- 0, 0,
- /* IP7_30_29 [2] */
- FN_DU0_DB4, 0, FN_HIFINT, 0,
- /* IP7_28_27 [2] */
- FN_DU0_DB3, FN_TX5_B, FN_TIOC4D_A, FN_HIFRD,
- /* IP7_26_24 [3] */
- FN_DU0_DB2, FN_RX5_B, FN_RMII0_TXD1_B, FN_TIOC4C_A,
- FN_HIFWR, 0, 0, 0,
- /* IP7_23_21 [3] */
- FN_DU0_DB1, FN_TX4_C, FN_RMII0_TXD0_B, FN_TIOC4B_A,
- FN_HIFRS, 0, 0, 0,
- /* IP7_20_18 [3] */
- FN_DU0_DB0, FN_RX4_C, FN_RMII0_TXD_EN_B, FN_TIOC4A_A,
- FN_HIFCS, 0, 0, 0,
- /* IP7_17_15 [3] */
- FN_DU0_DG7, FN_TX3_C, FN_RMII0_RXD1_B, FN_TIOC3D_A,
- FN_HIFD15, 0, 0, 0,
- /* IP7_14_12 [3] */
- FN_DU0_DG6, FN_RX3_C, FN_RMII0_RXD0_B, FN_TIOC3C_A,
- FN_HIFD14, 0, 0, 0,
- /* IP7_11_9 [3] */
- FN_DU0_DG5, FN_TX2_C, FN_RMII0_RX_ER_B, FN_TIOC3B_A,
- FN_HIFD13, 0, 0, 0,
- /* IP7_8_6 [3] */
- FN_DU0_DG4, FN_RX2_C, FN_RMII0_CRS_DV_B, FN_TIOC3A_A,
- FN_HIFD12, 0, 0, 0,
- /* IP7_5_3 [3] */
- FN_DU0_DG3, FN_SCK2_C, FN_RMII0_MDIO_B, FN_TIOC2B_A,
- FN_HIFD11, 0, 0, 0,
- /* IP7_2_0 [3] */
- FN_DU0_DG2, FN_RTS1_C, FN_RMII0_MDC_B, FN_TIOC2A_A,
- FN_HIFD10, 0, 0, 0 }
- },
- { PINMUX_CFG_REG_VAR("IPSR8", 0xFFFC003C, 32,
- 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
- /* IP9_31_30 [2] */
- 0, 0, 0, 0,
- /* IP8_29_28 [2] */
- FN_IRQ3_A, FN_RTS0_A, FN_HRTS0_B, FN_ET0_ERXD3_A,
- /* IP8_27_26 [2] */
- FN_IRQ2_A, FN_CTS0_A, FN_HCTS0_B, FN_ET0_ERXD2_A,
- /* IP8_25_23 [3] */
- FN_IRQ1_A, 0, FN_HSPI_RX_B, FN_TX3_E,
- FN_ET0_ERXD1, 0, 0, 0,
- /* IP8_22_20 [3] */
- FN_IRQ0_A, 0, FN_HSPI_TX_B, FN_RX3_E,
- FN_ET0_ERXD0, 0, 0, 0,
- /* IP8_19_18 [2] */
- FN_DU0_CDE, FN_HTX0_B, FN_AUDIO_CLKB_B, FN_LCD_VCPWC_B,
- /* IP8_17_16 [2] */
- FN_DU0_DISP, FN_CAN0_TX_B, FN_HRX0_B, FN_AUDIO_CLKA_B,
- /* IP8_15_14 [2] */
- FN_DU0_EXODDF_DU0_ODDF, FN_CAN0_RX_B, FN_HSCK0_B,
- FN_SSI_SDATA1_B,
- /* IP8_13_12 [2] */
- FN_DU0_EXVSYNC_DU0_VSYNC, 0, FN_HSPI_RX0_C, FN_SSI_WS1_B,
- /* IP8_11_10 [2] */
- FN_DU0_EXHSYNC_DU0_HSYNC, 0, FN_HSPI_TX0_C, FN_SSI_SCK1_B,
- /* IP8_9_8 [2] */
- FN_DU0_DOTCLKOUT, 0, FN_HSPI_CLK0_C, FN_SSI_SDATA0_B,
- /* IP8_7_6 [2] */
- FN_DU0_DOTCLKIN, 0, FN_HSPI_CS0_C, FN_SSI_WS0_B,
- /* IP8_5_4 [2] */
- FN_DU0_DB7, 0, FN_SSI_SCK0_B, FN_HIFEBL_B,
- /* IP8_3_2 [2] */
- FN_DU0_DB6, 0, FN_HIFRDY, 0,
- /* IP8_1_0 [2] */
- FN_DU0_DB5, 0, FN_HIFDREQ, 0 }
- },
- { PINMUX_CFG_REG_VAR("IPSR9", 0xFFFC0040, 32,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2) {
- /* IP9_31_30 [2] */
- 0, 0, 0, 0,
- /* IP9_29_28 [2] */
- FN_SSI_SDATA1_A, FN_VI1_3_B, FN_LCD_DATA14_B, 0,
- /* IP9_27_26 [2] */
- FN_SSI_WS1_A, FN_VI1_2_B, FN_LCD_DATA13_B, 0,
- /* IP9_25_24 [2] */
- FN_SSI_SCK1_A, FN_VI1_1_B, FN_TIOC2B_B, FN_LCD_DATA12_B,
- /* IP9_23_22 [2] */
- FN_SSI_SDATA0_A, FN_VI1_0_B, FN_TIOC2A_B, FN_LCD_DATA11_B,
- /* IP9_21_20 [2] */
- FN_SSI_WS0_A, FN_TIOC1B_B, FN_LCD_DATA10_B, 0,
- /* IP9_19_18 [2] */
- FN_SSI_SCK0_A, FN_TIOC1A_B, FN_LCD_DATA9_B, 0,
- /* IP9_17_16 [2] */
- FN_VI1_7_A, FN_FCE_B, FN_LCD_DATA8_B, 0,
- /* IP9_15_14 [2] */
- FN_VI1_6_A, 0, FN_FD7_B, FN_LCD_DATA7_B,
- /* IP9_13_12 [2] */
- FN_VI1_5_A, 0, FN_FD6_B, FN_LCD_DATA6_B,
- /* IP9_11_10 [2] */
- FN_VI1_4_A, 0, FN_FD5_B, FN_LCD_DATA5_B,
- /* IP9_9_8 [2] */
- FN_VI1_3_A, 0, FN_FD4_B, FN_LCD_DATA4_B,
- /* IP9_7_6 [2] */
- FN_VI1_2_A, 0, FN_FD3_B, FN_LCD_DATA3_B,
- /* IP9_5_4 [2] */
- FN_VI1_1_A, 0, FN_FD2_B, FN_LCD_DATA2_B,
- /* IP9_3_2 [2] */
- FN_VI1_0_A, 0, FN_FD1_B, FN_LCD_DATA1_B,
- /* IP9_1_0 [2] */
- FN_VI1_CLK_A, 0, FN_FD0_B, FN_LCD_DATA0_B }
- },
- { PINMUX_CFG_REG_VAR("IPSR10", 0xFFFC0044, 32,
- 2, 2, 2, 1, 2, 1, 3,
- 3, 1, 3, 3, 3, 3, 3) {
- /* IP9_31_30 [2] */
- 0, 0, 0, 0,
- /* IP10_29_28 [2] */
- FN_CAN1_TX_A, FN_TX5_C, FN_MLB_DAT, 0,
- /* IP10_27_26 [2] */
- FN_CAN0_RX_A, FN_IRQ0_B, FN_MLB_SIG, 0,
- /* IP10_25 [1] */
- FN_CAN1_RX_A, FN_IRQ1_B,
- /* IP10_24_23 [2] */
- FN_CAN0_TX_A, FN_TX4_D, FN_MLB_CLK, 0,
- /* IP10_22 [1] */
- FN_CAN_CLK_A, FN_RX4_D,
- /* IP10_21_19 [3] */
- FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B,
- FN_LCD_M_DISP_B, 0, 0, 0,
- /* IP10_18_16 [3] */
- FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B,
- FN_LCD_VEPWC_B, 0, 0, 0,
- /* IP10_15 [1] */
- FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
- /* IP10_14_12 [3] */
- FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B,
- FN_LCD_FLM_B, 0, 0, 0,
- /* IP10_11_9 [3] */
- FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B,
- FN_LCD_CL2_B, 0, 0, 0,
- /* IP10_8_6 [3] */
- FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B,
- FN_LCD_CL1_B, 0, 0, 0,
- /* IP10_5_3 [3] */
- FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B,
- FN_LCD_DON_B, 0, 0, 0,
- /* IP10_2_0 [3] */
- FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B,
- FN_LCD_DATA15_B, 0, 0, 0 }
- },
- { PINMUX_CFG_REG_VAR("IPSR11", 0xFFFC0048, 32,
- 3, 1, 2, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) {
- /* IP11_31_29 [3] */
- 0, 0, 0, 0, 0, 0, 0, 0,
- /* IP11_28 [1] */
- FN_PRESETOUT, FN_ST_CLKOUT,
- /* IP11_27_26 [2] */
- FN_DACK1, FN_HSPI_CS_B, FN_TX4_B, FN_ET0_RX_CLK_A,
- /* IP11_25_23 [3] */
- FN_DREQ1, FN_HSPI_CLK_B, FN_RX4_B, FN_ET0_PHY_INT_C,
- FN_ET0_TX_CLK_A, 0, 0, 0,
- /* IP11_22_21 [2] */
- FN_DACK0, FN_SD1_DAT3_A, FN_ET0_TX_ER, 0,
- /* IP11_20_19 [2] */
- FN_DREQ0, FN_SD1_CLK_A, FN_ET0_TX_EN, 0,
- /* IP11_18_16 [3] */
- FN_USB_OVC1, FN_RX3_D, FN_CAN1_RX_B, FN_RX5_D,
- FN_IERX_B, 0, 0, 0,
- /* IP11_15_13 [3] */
- FN_PENC1, FN_TX3_D, FN_CAN1_TX_B, FN_TX5_D,
- FN_IETX_B, 0, 0, 0,
- /* IP11_12 [1] */
- FN_TX0_A, FN_HSPI_TX_A,
- /* IP11_11_10 [2] */
- FN_RX0_A, FN_HSPI_RX_A, FN_RMII0_RXD0_A, FN_ET0_ERXD6,
- /* IP11_9_7 [3] */
- FN_SCK0_A, FN_HSPI_CS_A, FN_VI0_CLKENB, FN_RMII0_TXD1_A,
- FN_ET0_ERXD5, 0, 0, 0,
- /* IP11_6_4 [3] */
- FN_SCIF_CLK_A, FN_HSPI_CLK_A, FN_VI0_CLK, FN_RMII0_TXD0_A,
- FN_ET0_ERXD4, 0, 0, 0,
- /* IP11_3 [1] */
- FN_SDSELF, FN_RTS1_E,
- /* IP11_2 [1] */
- FN_SDA0, FN_HIFEBL_A,
- /* IP11_1 [1] */
- FN_SDA1, FN_RX1_E,
- /* IP11_0 [1] */
- FN_SCL1, FN_SCIF_CLK_C }
- },
- { PINMUX_CFG_REG_VAR("MOD_SEL1", 0xFFFC004C, 32,
- 3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2,
- 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) {
- /* SEL1_31_29 [3] */
- 0, 0, 0, 0, 0, 0, 0, 0,
- /* SEL1_28 [1] */
- FN_SEL_IEBUS_0, FN_SEL_IEBUS_1,
- /* SEL1_27 [1] */
- FN_SEL_RQSPI_0, FN_SEL_RQSPI_1,
- /* SEL1_26 [1] */
- FN_SEL_VIN1_0, FN_SEL_VIN1_1,
- /* SEL1_25 [1] */
- FN_SEL_HIF_0, FN_SEL_HIF_1,
- /* SEL1_24 [1] */
- FN_SEL_RSPI_0, FN_SEL_RSPI_1,
- /* SEL1_23 [1] */
- FN_SEL_LCDC_0, FN_SEL_LCDC_1,
- /* SEL1_22_21 [2] */
- FN_SEL_ET0_CTL_0, FN_SEL_ET0_CTL_1, FN_SEL_ET0_CTL_2, 0,
- /* SEL1_20 [1] */
- FN_SEL_ET0_0, FN_SEL_ET0_1,
- /* SEL1_19 [1] */
- FN_SEL_RMII_0, FN_SEL_RMII_1,
- /* SEL1_18 [1] */
- FN_SEL_TMU_0, FN_SEL_TMU_1,
- /* SEL1_17_16 [2] */
- FN_SEL_HSPI_0, FN_SEL_HSPI_1, FN_SEL_HSPI_2, 0,
- /* SEL1_15_14 [2] */
- FN_SEL_HSCIF_0, FN_SEL_HSCIF_1, FN_SEL_HSCIF_2, FN_SEL_HSCIF_3,
- /* SEL1_13 [1] */
- FN_SEL_RCAN_CLK_0, FN_SEL_RCAN_CLK_1,
- /* SEL1_12_11 [2] */
- FN_SEL_RCAN1_0, FN_SEL_RCAN1_1, FN_SEL_RCAN1_2, 0,
- /* SEL1_10 [1] */
- FN_SEL_RCAN0_0, FN_SEL_RCAN0_1,
- /* SEL1_9 [1] */
- FN_SEL_SDHI2_0, FN_SEL_SDHI2_1,
- /* SEL1_8 [1] */
- FN_SEL_SDHI1_0, FN_SEL_SDHI1_1,
- /* SEL1_7 [1] */
- FN_SEL_SDHI0_0, FN_SEL_SDHI0_1,
- /* SEL1_6 [1] */
- FN_SEL_SSI1_0, FN_SEL_SSI1_1,
- /* SEL1_5 [1] */
- FN_SEL_SSI0_0, FN_SEL_SSI0_1,
- /* SEL1_4 [1] */
- FN_SEL_AUDIO_CLKB_0, FN_SEL_AUDIO_CLKB_1,
- /* SEL1_3 [1] */
- FN_SEL_AUDIO_CLKA_0, FN_SEL_AUDIO_CLKA_1,
- /* SEL1_2 [1] */
- FN_SEL_FLCTL_0, FN_SEL_FLCTL_1,
- /* SEL1_1 [1] */
- FN_SEL_MMC_0, FN_SEL_MMC_1,
- /* SEL1_0 [1] */
- FN_SEL_INTC_0, FN_SEL_INTC_1 }
- },
- { PINMUX_CFG_REG_VAR("MOD_SEL2", 0xFFFC0050, 32,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 2, 2, 1, 2, 2, 3, 2, 3, 2, 2) {
- /* SEL2_31 [1] */
- 0, 0,
- /* SEL2_30 [1] */
- 0, 0,
- /* SEL2_29 [1] */
- 0, 0,
- /* SEL2_28 [1] */
- 0, 0,
- /* SEL2_27 [1] */
- 0, 0,
- /* SEL2_26 [1] */
- 0, 0,
- /* SEL2_25 [1] */
- 0, 0,
- /* SEL2_24 [1] */
- 0, 0,
- /* SEL2_23 [1] */
- FN_SEL_MTU2_CLK_0, FN_SEL_MTU2_CLK_1,
- /* SEL2_22 [1] */
- FN_SEL_MTU2_CH4_0, FN_SEL_MTU2_CH4_1,
- /* SEL2_21 [1] */
- FN_SEL_MTU2_CH3_0, FN_SEL_MTU2_CH3_1,
- /* SEL2_20_19 [2] */
- FN_SEL_MTU2_CH2_0, FN_SEL_MTU2_CH2_1, FN_SEL_MTU2_CH2_2, 0,
- /* SEL2_18_17 [2] */
- FN_SEL_MTU2_CH1_0, FN_SEL_MTU2_CH1_1, FN_SEL_MTU2_CH1_2, 0,
- /* SEL2_16 [1] */
- FN_SEL_MTU2_CH0_0, FN_SEL_MTU2_CH0_1,
- /* SEL2_15_14 [2] */
- FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
- /* SEL2_13_12 [2] */
- FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
- /* SEL2_11_9 [3] */
- FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2, FN_SEL_SCIF3_3,
- FN_SEL_SCIF3_4, 0, 0, 0,
- /* SEL2_8_7 [2] */
- FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2, FN_SEL_SCIF2_3,
- /* SEL2_6_4 [3] */
- FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, FN_SEL_SCIF1_3,
- FN_SEL_SCIF1_4, 0, 0, 0,
- /* SEL2_3_2 [2] */
- FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, 0,
- /* SEL2_1_0 [2] */
- FN_SEL_SCIF_CLK_0, FN_SEL_SCIF_CLK_1, FN_SEL_SCIF_CLK_2, 0 }
- },
- /* GPIO 0 - 5*/
- { PINMUX_CFG_REG("INOUTSEL0", 0xFFC40004, 32, 1) { GP_INOUTSEL(0) } },
- { PINMUX_CFG_REG("INOUTSEL1", 0xFFC41004, 32, 1) { GP_INOUTSEL(1) } },
- { PINMUX_CFG_REG("INOUTSEL2", 0xFFC42004, 32, 1) { GP_INOUTSEL(2) } },
- { PINMUX_CFG_REG("INOUTSEL3", 0xFFC43004, 32, 1) { GP_INOUTSEL(3) } },
- { PINMUX_CFG_REG("INOUTSEL4", 0xFFC44004, 32, 1) { GP_INOUTSEL(4) } },
- { PINMUX_CFG_REG("INOUTSEL5", 0xffc45004, 32, 1) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 31 - 24 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 23 - 16 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 15 - 12 */
- GP_5_11_IN, GP_5_11_OUT,
- GP_5_10_IN, GP_5_10_OUT,
- GP_5_9_IN, GP_5_9_OUT,
- GP_5_8_IN, GP_5_8_OUT,
- GP_5_7_IN, GP_5_7_OUT,
- GP_5_6_IN, GP_5_6_OUT,
- GP_5_5_IN, GP_5_5_OUT,
- GP_5_4_IN, GP_5_4_OUT,
- GP_5_3_IN, GP_5_3_OUT,
- GP_5_2_IN, GP_5_2_OUT,
- GP_5_1_IN, GP_5_1_OUT,
- GP_5_0_IN, GP_5_0_OUT }
- },
- { },
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- /* GPIO 0 - 5*/
- { PINMUX_DATA_REG("INDT0", 0xFFC4000C, 32) { GP_INDT(0) } },
- { PINMUX_DATA_REG("INDT1", 0xFFC4100C, 32) { GP_INDT(1) } },
- { PINMUX_DATA_REG("INDT2", 0xFFC4200C, 32) { GP_INDT(2) } },
- { PINMUX_DATA_REG("INDT3", 0xFFC4300C, 32) { GP_INDT(3) } },
- { PINMUX_DATA_REG("INDT4", 0xFFC4400C, 32) { GP_INDT(4) } },
- { PINMUX_DATA_REG("INDT5", 0xFFC4500C, 32) {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- GP_5_11_DATA, GP_5_10_DATA, GP_5_9_DATA, GP_5_8_DATA,
- GP_5_7_DATA, GP_5_6_DATA, GP_5_5_DATA, GP_5_4_DATA,
- GP_5_3_DATA, GP_5_2_DATA, GP_5_1_DATA, GP_5_0_DATA }
- },
- { },
-};
+#include <cpu/pfc.h>
static struct resource sh7734_pfc_resources[] = {
[0] = { /* PFC */
@@ -2464,34 +27,9 @@ static struct resource sh7734_pfc_resources[] = {
}
};
-static struct pinmux_info sh7734_pinmux_info = {
- .name = "sh7734_pfc",
-
- .resource = sh7734_pfc_resources,
- .num_resources = ARRAY_SIZE(sh7734_pfc_resources),
-
- .unlock_reg = 0xFFFC0000,
-
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_GP_0_0,
- .last_gpio = GPIO_FN_ST_CLKOUT,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
-
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7734_pinmux_info);
+ return sh_pfc_register("pfc-sh7734", sh7734_pfc_resources,
+ ARRAY_SIZE(sh7734_pfc_resources));
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
index 4c74bd04bba4..cda6bd177b8c 100644
--- a/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
@@ -15,2273 +15,10 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/sh7757.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
- PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
- PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
- PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
- PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
- PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA,
- PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
- PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
- PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
- PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA,
- PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
- PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
- PTG7_DATA, PTG6_DATA, PTG5_DATA, PTG4_DATA,
- PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
- PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
- PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
- PTI7_DATA, PTI6_DATA, PTI5_DATA, PTI4_DATA,
- PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA,
- PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
- PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
- PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
- PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
- PTL6_DATA, PTL5_DATA, PTL4_DATA,
- PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
- PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
- PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
- PTN6_DATA, PTN5_DATA, PTN4_DATA,
- PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
- PTO7_DATA, PTO6_DATA, PTO5_DATA, PTO4_DATA,
- PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA,
- PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
- PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA,
- PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
- PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
- PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
- PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
- PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
- PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
- PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
- PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
- PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
- PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
- PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
- PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
- PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
- PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA,
- PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
- PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA,
- PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
- PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA,
- PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
- PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
- PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
- PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
- PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
- PTC7_IN, PTC6_IN, PTC5_IN, PTC4_IN,
- PTC3_IN, PTC2_IN, PTC1_IN, PTC0_IN,
- PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN,
- PTD3_IN, PTD2_IN, PTD1_IN, PTD0_IN,
- PTE7_IN, PTE6_IN, PTE5_IN, PTE4_IN,
- PTE3_IN, PTE2_IN, PTE1_IN, PTE0_IN,
- PTF7_IN, PTF6_IN, PTF5_IN, PTF4_IN,
- PTF3_IN, PTF2_IN, PTF1_IN, PTF0_IN,
- PTG7_IN, PTG6_IN, PTG5_IN, PTG4_IN,
- PTG3_IN, PTG2_IN, PTG1_IN, PTG0_IN,
- PTH7_IN, PTH6_IN, PTH5_IN, PTH4_IN,
- PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
- PTI7_IN, PTI6_IN, PTI5_IN, PTI4_IN,
- PTI3_IN, PTI2_IN, PTI1_IN, PTI0_IN,
- PTJ6_IN, PTJ5_IN, PTJ4_IN,
- PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
- PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
- PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
- PTL6_IN, PTL5_IN, PTL4_IN,
- PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
- PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
- PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
- PTN6_IN, PTN5_IN, PTN4_IN,
- PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
- PTO7_IN, PTO6_IN, PTO5_IN, PTO4_IN,
- PTO3_IN, PTO2_IN, PTO1_IN, PTO0_IN,
- PTP7_IN, PTP6_IN, PTP5_IN, PTP4_IN,
- PTP3_IN, PTP2_IN, PTP1_IN, PTP0_IN,
- PTQ6_IN, PTQ5_IN, PTQ4_IN,
- PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
- PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
- PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
- PTS7_IN, PTS6_IN, PTS5_IN, PTS4_IN,
- PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
- PTT7_IN, PTT6_IN, PTT5_IN, PTT4_IN,
- PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
- PTU7_IN, PTU6_IN, PTU5_IN, PTU4_IN,
- PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
- PTV7_IN, PTV6_IN, PTV5_IN, PTV4_IN,
- PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
- PTW7_IN, PTW6_IN, PTW5_IN, PTW4_IN,
- PTW3_IN, PTW2_IN, PTW1_IN, PTW0_IN,
- PTX7_IN, PTX6_IN, PTX5_IN, PTX4_IN,
- PTX3_IN, PTX2_IN, PTX1_IN, PTX0_IN,
- PTY7_IN, PTY6_IN, PTY5_IN, PTY4_IN,
- PTY3_IN, PTY2_IN, PTY1_IN, PTY0_IN,
- PTZ7_IN, PTZ6_IN, PTZ5_IN, PTZ4_IN,
- PTZ3_IN, PTZ2_IN, PTZ1_IN, PTZ0_IN,
- PINMUX_INPUT_END,
-
- PINMUX_INPUT_PULLUP_BEGIN,
- PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
- PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
- PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
- PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
- PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
- PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
- PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
- PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
- PTG7_IN_PU, PTG6_IN_PU, PTG4_IN_PU,
- PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
- PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
- PTI7_IN_PU, PTI6_IN_PU, PTI4_IN_PU,
- PTI3_IN_PU, PTI2_IN_PU, PTI1_IN_PU, PTI0_IN_PU,
- PTJ6_IN_PU, PTJ5_IN_PU, PTJ4_IN_PU,
- PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
- PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
- PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
- PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
- PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
- PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
- PTN4_IN_PU,
- PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
- PTO7_IN_PU, PTO6_IN_PU, PTO5_IN_PU, PTO4_IN_PU,
- PTO3_IN_PU, PTO2_IN_PU, PTO1_IN_PU, PTO0_IN_PU,
- PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
- PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
- PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
- PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
- PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
- PTV3_IN_PU, PTV2_IN_PU,
- PTW1_IN_PU, PTW0_IN_PU,
- PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
- PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
- PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
- PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
- PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
- PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
- PINMUX_INPUT_PULLUP_END,
-
- PINMUX_OUTPUT_BEGIN,
- PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
- PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
- PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
- PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
- PTC7_OUT, PTC6_OUT, PTC5_OUT, PTC4_OUT,
- PTC3_OUT, PTC2_OUT, PTC1_OUT, PTC0_OUT,
- PTD7_OUT, PTD6_OUT, PTD5_OUT, PTD4_OUT,
- PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
- PTE7_OUT, PTE6_OUT, PTE5_OUT, PTE4_OUT,
- PTE3_OUT, PTE2_OUT, PTE1_OUT, PTE0_OUT,
- PTF7_OUT, PTF6_OUT, PTF5_OUT, PTF4_OUT,
- PTF3_OUT, PTF2_OUT, PTF1_OUT, PTF0_OUT,
- PTG7_OUT, PTG6_OUT, PTG5_OUT, PTG4_OUT,
- PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
- PTH7_OUT, PTH6_OUT, PTH5_OUT, PTH4_OUT,
- PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
- PTI7_OUT, PTI6_OUT, PTI5_OUT, PTI4_OUT,
- PTI3_OUT, PTI2_OUT, PTI1_OUT, PTI0_OUT,
- PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
- PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
- PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
- PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
- PTL6_OUT, PTL5_OUT, PTL4_OUT,
- PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
- PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
- PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
- PTN6_OUT, PTN5_OUT, PTN4_OUT,
- PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
- PTO7_OUT, PTO6_OUT, PTO5_OUT, PTO4_OUT,
- PTO3_OUT, PTO2_OUT, PTO1_OUT, PTO0_OUT,
- PTP7_OUT, PTP6_OUT, PTP5_OUT, PTP4_OUT,
- PTP3_OUT, PTP2_OUT, PTP1_OUT, PTP0_OUT,
- PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
- PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
- PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
- PTR3_OUT, PTR2_OUT, PTR1_OUT, PTR0_OUT,
- PTS7_OUT, PTS6_OUT, PTS5_OUT, PTS4_OUT,
- PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
- PTT7_OUT, PTT6_OUT, PTT5_OUT, PTT4_OUT,
- PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
- PTU7_OUT, PTU6_OUT, PTU5_OUT, PTU4_OUT,
- PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
- PTV7_OUT, PTV6_OUT, PTV5_OUT, PTV4_OUT,
- PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
- PTW7_OUT, PTW6_OUT, PTW5_OUT, PTW4_OUT,
- PTW3_OUT, PTW2_OUT, PTW1_OUT, PTW0_OUT,
- PTX7_OUT, PTX6_OUT, PTX5_OUT, PTX4_OUT,
- PTX3_OUT, PTX2_OUT, PTX1_OUT, PTX0_OUT,
- PTY7_OUT, PTY6_OUT, PTY5_OUT, PTY4_OUT,
- PTY3_OUT, PTY2_OUT, PTY1_OUT, PTY0_OUT,
- PTZ7_OUT, PTZ6_OUT, PTZ5_OUT, PTZ4_OUT,
- PTZ3_OUT, PTZ2_OUT, PTZ1_OUT, PTZ0_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- PTA7_FN, PTA6_FN, PTA5_FN, PTA4_FN,
- PTA3_FN, PTA2_FN, PTA1_FN, PTA0_FN,
- PTB7_FN, PTB6_FN, PTB5_FN, PTB4_FN,
- PTB3_FN, PTB2_FN, PTB1_FN, PTB0_FN,
- PTC7_FN, PTC6_FN, PTC5_FN, PTC4_FN,
- PTC3_FN, PTC2_FN, PTC1_FN, PTC0_FN,
- PTD7_FN, PTD6_FN, PTD5_FN, PTD4_FN,
- PTD3_FN, PTD2_FN, PTD1_FN, PTD0_FN,
- PTE7_FN, PTE6_FN, PTE5_FN, PTE4_FN,
- PTE3_FN, PTE2_FN, PTE1_FN, PTE0_FN,
- PTF7_FN, PTF6_FN, PTF5_FN, PTF4_FN,
- PTF3_FN, PTF2_FN, PTF1_FN, PTF0_FN,
- PTG7_FN, PTG6_FN, PTG5_FN, PTG4_FN,
- PTG3_FN, PTG2_FN, PTG1_FN, PTG0_FN,
- PTH7_FN, PTH6_FN, PTH5_FN, PTH4_FN,
- PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
- PTI7_FN, PTI6_FN, PTI5_FN, PTI4_FN,
- PTI3_FN, PTI2_FN, PTI1_FN, PTI0_FN,
- PTJ6_FN, PTJ5_FN, PTJ4_FN,
- PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
- PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
- PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
- PTL6_FN, PTL5_FN, PTL4_FN,
- PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
- PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
- PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
- PTN6_FN, PTN5_FN, PTN4_FN,
- PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
- PTO7_FN, PTO6_FN, PTO5_FN, PTO4_FN,
- PTO3_FN, PTO2_FN, PTO1_FN, PTO0_FN,
- PTP7_FN, PTP6_FN, PTP5_FN, PTP4_FN,
- PTP3_FN, PTP2_FN, PTP1_FN, PTP0_FN,
- PTQ6_FN, PTQ5_FN, PTQ4_FN,
- PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
- PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
- PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
- PTS7_FN, PTS6_FN, PTS5_FN, PTS4_FN,
- PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
- PTT7_FN, PTT6_FN, PTT5_FN, PTT4_FN,
- PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
- PTU7_FN, PTU6_FN, PTU5_FN, PTU4_FN,
- PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
- PTV7_FN, PTV6_FN, PTV5_FN, PTV4_FN,
- PTV3_FN, PTV2_FN, PTV1_FN, PTV0_FN,
- PTW7_FN, PTW6_FN, PTW5_FN, PTW4_FN,
- PTW3_FN, PTW2_FN, PTW1_FN, PTW0_FN,
- PTX7_FN, PTX6_FN, PTX5_FN, PTX4_FN,
- PTX3_FN, PTX2_FN, PTX1_FN, PTX0_FN,
- PTY7_FN, PTY6_FN, PTY5_FN, PTY4_FN,
- PTY3_FN, PTY2_FN, PTY1_FN, PTY0_FN,
- PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
- PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
-
- PS0_15_FN1, PS0_15_FN2,
- PS0_14_FN1, PS0_14_FN2,
- PS0_13_FN1, PS0_13_FN2,
- PS0_12_FN1, PS0_12_FN2,
- PS0_11_FN1, PS0_11_FN2,
- PS0_10_FN1, PS0_10_FN2,
- PS0_9_FN1, PS0_9_FN2,
- PS0_8_FN1, PS0_8_FN2,
- PS0_7_FN1, PS0_7_FN2,
- PS0_6_FN1, PS0_6_FN2,
- PS0_5_FN1, PS0_5_FN2,
- PS0_4_FN1, PS0_4_FN2,
- PS0_3_FN1, PS0_3_FN2,
- PS0_2_FN1, PS0_2_FN2,
-
- PS1_10_FN1, PS1_10_FN2,
- PS1_9_FN1, PS1_9_FN2,
- PS1_8_FN1, PS1_8_FN2,
- PS1_2_FN1, PS1_2_FN2,
-
- PS2_13_FN1, PS2_13_FN2,
- PS2_12_FN1, PS2_12_FN2,
- PS2_7_FN1, PS2_7_FN2,
- PS2_6_FN1, PS2_6_FN2,
- PS2_5_FN1, PS2_5_FN2,
- PS2_4_FN1, PS2_4_FN2,
- PS2_2_FN1, PS2_2_FN2,
-
- PS3_15_FN1, PS3_15_FN2,
- PS3_14_FN1, PS3_14_FN2,
- PS3_13_FN1, PS3_13_FN2,
- PS3_12_FN1, PS3_12_FN2,
- PS3_11_FN1, PS3_11_FN2,
- PS3_10_FN1, PS3_10_FN2,
- PS3_9_FN1, PS3_9_FN2,
- PS3_8_FN1, PS3_8_FN2,
- PS3_7_FN1, PS3_7_FN2,
- PS3_2_FN1, PS3_2_FN2,
- PS3_1_FN1, PS3_1_FN2,
-
- PS4_14_FN1, PS4_14_FN2,
- PS4_13_FN1, PS4_13_FN2,
- PS4_12_FN1, PS4_12_FN2,
- PS4_10_FN1, PS4_10_FN2,
- PS4_9_FN1, PS4_9_FN2,
- PS4_8_FN1, PS4_8_FN2,
- PS4_4_FN1, PS4_4_FN2,
- PS4_3_FN1, PS4_3_FN2,
- PS4_2_FN1, PS4_2_FN2,
- PS4_1_FN1, PS4_1_FN2,
- PS4_0_FN1, PS4_0_FN2,
-
- PS5_11_FN1, PS5_11_FN2,
- PS5_10_FN1, PS5_10_FN2,
- PS5_9_FN1, PS5_9_FN2,
- PS5_8_FN1, PS5_8_FN2,
- PS5_7_FN1, PS5_7_FN2,
- PS5_6_FN1, PS5_6_FN2,
- PS5_5_FN1, PS5_5_FN2,
- PS5_4_FN1, PS5_4_FN2,
- PS5_3_FN1, PS5_3_FN2,
- PS5_2_FN1, PS5_2_FN2,
-
- PS6_15_FN1, PS6_15_FN2,
- PS6_14_FN1, PS6_14_FN2,
- PS6_13_FN1, PS6_13_FN2,
- PS6_12_FN1, PS6_12_FN2,
- PS6_11_FN1, PS6_11_FN2,
- PS6_10_FN1, PS6_10_FN2,
- PS6_9_FN1, PS6_9_FN2,
- PS6_8_FN1, PS6_8_FN2,
- PS6_7_FN1, PS6_7_FN2,
- PS6_6_FN1, PS6_6_FN2,
- PS6_5_FN1, PS6_5_FN2,
- PS6_4_FN1, PS6_4_FN2,
- PS6_3_FN1, PS6_3_FN2,
- PS6_2_FN1, PS6_2_FN2,
- PS6_1_FN1, PS6_1_FN2,
- PS6_0_FN1, PS6_0_FN2,
-
- PS7_15_FN1, PS7_15_FN2,
- PS7_14_FN1, PS7_14_FN2,
- PS7_13_FN1, PS7_13_FN2,
- PS7_12_FN1, PS7_12_FN2,
- PS7_11_FN1, PS7_11_FN2,
- PS7_10_FN1, PS7_10_FN2,
- PS7_9_FN1, PS7_9_FN2,
- PS7_8_FN1, PS7_8_FN2,
- PS7_7_FN1, PS7_7_FN2,
- PS7_6_FN1, PS7_6_FN2,
- PS7_5_FN1, PS7_5_FN2,
- PS7_4_FN1, PS7_4_FN2,
-
- PS8_15_FN1, PS8_15_FN2,
- PS8_14_FN1, PS8_14_FN2,
- PS8_13_FN1, PS8_13_FN2,
- PS8_12_FN1, PS8_12_FN2,
- PS8_11_FN1, PS8_11_FN2,
- PS8_10_FN1, PS8_10_FN2,
- PS8_9_FN1, PS8_9_FN2,
- PS8_8_FN1, PS8_8_FN2,
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
- /* PTA (mobule: LBSC, RGMII) */
- BS_MARK, RDWR_MARK, WE1_MARK, RDY_MARK,
- ET0_MDC_MARK, ET0_MDIO_MARK, ET1_MDC_MARK, ET1_MDIO_MARK,
-
- /* PTB (mobule: INTC, ONFI, TMU) */
- IRQ15_MARK, IRQ14_MARK, IRQ13_MARK, IRQ12_MARK,
- IRQ11_MARK, IRQ10_MARK, IRQ9_MARK, IRQ8_MARK,
- ON_NRE_MARK, ON_NWE_MARK, ON_NWP_MARK, ON_NCE0_MARK,
- ON_R_B0_MARK, ON_ALE_MARK, ON_CLE_MARK, TCLK_MARK,
-
- /* PTC (mobule: IRQ, PWMU) */
- IRQ7_MARK, IRQ6_MARK, IRQ5_MARK, IRQ4_MARK,
- IRQ3_MARK, IRQ2_MARK, IRQ1_MARK, IRQ0_MARK,
- PWMU0_MARK, PWMU1_MARK, PWMU2_MARK, PWMU3_MARK,
- PWMU4_MARK, PWMU5_MARK,
-
- /* PTD (mobule: SPI0, DMAC) */
- SP0_MOSI_MARK, SP0_MISO_MARK, SP0_SCK_MARK, SP0_SCK_FB_MARK,
- SP0_SS0_MARK, SP0_SS1_MARK, SP0_SS2_MARK, SP0_SS3_MARK,
- DREQ0_MARK, DACK0_MARK, TEND0_MARK,
-
- /* PTE (mobule: RMII) */
- RMII0_CRS_DV_MARK, RMII0_TXD1_MARK,
- RMII0_TXD0_MARK, RMII0_TXEN_MARK,
- RMII0_REFCLK_MARK, RMII0_RXD1_MARK,
- RMII0_RXD0_MARK, RMII0_RX_ER_MARK,
-
- /* PTF (mobule: RMII, SerMux) */
- RMII1_CRS_DV_MARK, RMII1_TXD1_MARK,
- RMII1_TXD0_MARK, RMII1_TXEN_MARK,
- RMII1_REFCLK_MARK, RMII1_RXD1_MARK,
- RMII1_RXD0_MARK, RMII1_RX_ER_MARK,
- RAC_RI_MARK,
-
- /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
- BOOTFMS_MARK, BOOTWP_MARK, A25_MARK, A24_MARK,
- SERIRQ_MARK, WDTOVF_MARK, LPCPD_MARK, LDRQ_MARK,
- MMCCLK_MARK, MMCCMD_MARK,
-
- /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
- SP1_MOSI_MARK, SP1_MISO_MARK, SP1_SCK_MARK, SP1_SCK_FB_MARK,
- SP1_SS0_MARK, SP1_SS1_MARK, WP_MARK, FMS0_MARK,
- TEND1_MARK, DREQ1_MARK, DACK1_MARK, ADTRG1_MARK,
- ADTRG0_MARK,
-
- /* PTI (mobule: LBSC, SDHI) */
- D15_MARK, D14_MARK, D13_MARK, D12_MARK,
- D11_MARK, D10_MARK, D9_MARK, D8_MARK,
- SD_WP_MARK, SD_CD_MARK, SD_CLK_MARK, SD_CMD_MARK,
- SD_D3_MARK, SD_D2_MARK, SD_D1_MARK, SD_D0_MARK,
-
- /* PTJ (mobule: SCIF234) */
- RTS3_MARK, CTS3_MARK, TXD3_MARK, RXD3_MARK,
- RTS4_MARK, RXD4_MARK, TXD4_MARK,
-
- /* PTK (mobule: SERMUX, LBSC, SCIF) */
- COM2_TXD_MARK, COM2_RXD_MARK, COM2_RTS_MARK, COM2_CTS_MARK,
- COM2_DTR_MARK, COM2_DSR_MARK, COM2_DCD_MARK, CLKOUT_MARK,
- SCK2_MARK, SCK4_MARK, SCK3_MARK,
-
- /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
- RAC_RXD_MARK, RAC_RTS_MARK, RAC_CTS_MARK, RAC_DTR_MARK,
- RAC_DSR_MARK, RAC_DCD_MARK, RAC_TXD_MARK, RXD2_MARK,
- CS5_MARK, CS6_MARK, AUDSYNC_MARK, AUDCK_MARK,
- TXD2_MARK,
-
- /* PTM (mobule: LBSC, IIC) */
- CS4_MARK, RD_MARK, WE0_MARK, CS0_MARK,
- SDA6_MARK, SCL6_MARK, SDA7_MARK, SCL7_MARK,
-
- /* PTN (mobule: USB, JMC, SGPIO, WDT) */
- VBUS_EN_MARK, VBUS_OC_MARK, JMCTCK_MARK, JMCTMS_MARK,
- JMCTDO_MARK, JMCTDI_MARK, JMCTRST_MARK,
- SGPIO1_CLK_MARK, SGPIO1_LOAD_MARK, SGPIO1_DI_MARK,
- SGPIO1_DO_MARK, SUB_CLKIN_MARK,
-
- /* PTO (mobule: SGPIO, SerMux) */
- SGPIO0_CLK_MARK, SGPIO0_LOAD_MARK, SGPIO0_DI_MARK,
- SGPIO0_DO_MARK, SGPIO2_CLK_MARK, SGPIO2_LOAD_MARK,
- SGPIO2_DI_MARK, SGPIO2_DO_MARK,
- COM1_TXD_MARK, COM1_RXD_MARK, COM1_RTS_MARK, COM1_CTS_MARK,
-
- /* PTQ (mobule: LPC) */
- LAD3_MARK, LAD2_MARK, LAD1_MARK, LAD0_MARK,
- LFRAME_MARK, LRESET_MARK, LCLK_MARK,
-
- /* PTR (mobule: GRA, IIC) */
- DDC3_MARK, DDC2_MARK, SDA2_MARK, SCL2_MARK,
- SDA1_MARK, SCL1_MARK, SDA0_MARK, SCL0_MARK,
- SDA8_MARK, SCL8_MARK,
-
- /* PTS (mobule: GRA, IIC) */
- DDC1_MARK, DDC0_MARK, SDA5_MARK, SCL5_MARK,
- SDA4_MARK, SCL4_MARK, SDA3_MARK, SCL3_MARK,
- SDA9_MARK, SCL9_MARK,
-
- /* PTT (mobule: PWMX, AUD) */
- PWMX7_MARK, PWMX6_MARK, PWMX5_MARK, PWMX4_MARK,
- PWMX3_MARK, PWMX2_MARK, PWMX1_MARK, PWMX0_MARK,
- AUDATA3_MARK, AUDATA2_MARK, AUDATA1_MARK, AUDATA0_MARK,
- STATUS1_MARK, STATUS0_MARK,
-
- /* PTU (mobule: LPC, APM) */
- LGPIO7_MARK, LGPIO6_MARK, LGPIO5_MARK, LGPIO4_MARK,
- LGPIO3_MARK, LGPIO2_MARK, LGPIO1_MARK, LGPIO0_MARK,
- APMONCTL_O_MARK, APMPWBTOUT_O_MARK, APMSCI_O_MARK,
- APMVDDON_MARK, APMSLPBTN_MARK, APMPWRBTN_MARK, APMS5N_MARK,
- APMS3N_MARK,
-
- /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
- A23_MARK, A22_MARK, A21_MARK, A20_MARK,
- A19_MARK, A18_MARK, A17_MARK, A16_MARK,
- COM2_RI_MARK, R_SPI_MOSI_MARK, R_SPI_MISO_MARK,
- R_SPI_RSPCK_MARK, R_SPI_SSL0_MARK, R_SPI_SSL1_MARK,
- EVENT7_MARK, EVENT6_MARK, VBIOS_DI_MARK, VBIOS_DO_MARK,
- VBIOS_CLK_MARK, VBIOS_CS_MARK,
-
- /* PTW (mobule: LBSC, EVC, SCIF) */
- A15_MARK, A14_MARK, A13_MARK, A12_MARK,
- A11_MARK, A10_MARK, A9_MARK, A8_MARK,
- EVENT5_MARK, EVENT4_MARK, EVENT3_MARK, EVENT2_MARK,
- EVENT1_MARK, EVENT0_MARK, CTS4_MARK, CTS2_MARK,
-
- /* PTX (mobule: LBSC, SCIF, SIM) */
- A7_MARK, A6_MARK, A5_MARK, A4_MARK,
- A3_MARK, A2_MARK, A1_MARK, A0_MARK,
- RTS2_MARK, SIM_D_MARK, SIM_CLK_MARK, SIM_RST_MARK,
-
- /* PTY (mobule: LBSC) */
- D7_MARK, D6_MARK, D5_MARK, D4_MARK,
- D3_MARK, D2_MARK, D1_MARK, D0_MARK,
-
- /* PTZ (mobule: eMMC, ONFI) */
- MMCDAT7_MARK, MMCDAT6_MARK, MMCDAT5_MARK, MMCDAT4_MARK,
- MMCDAT3_MARK, MMCDAT2_MARK, MMCDAT1_MARK, MMCDAT0_MARK,
- ON_DQ7_MARK, ON_DQ6_MARK, ON_DQ5_MARK, ON_DQ4_MARK,
- ON_DQ3_MARK, ON_DQ2_MARK, ON_DQ1_MARK, ON_DQ0_MARK,
-
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
- /* PTA GPIO */
- PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT),
- PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT),
- PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT),
- PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT),
- PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT),
- PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT),
- PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT),
- PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT),
-
- /* PTB GPIO */
- PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT),
- PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT),
- PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT),
- PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT),
- PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT),
- PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT),
- PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT),
- PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT),
-
- /* PTC GPIO */
- PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT),
- PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT),
- PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT),
- PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT),
- PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT),
- PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT),
- PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT),
- PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT),
-
- /* PTD GPIO */
- PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT),
- PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT),
- PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT),
- PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT),
- PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT),
- PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT),
- PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT),
- PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT),
-
- /* PTE GPIO */
- PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT),
- PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT),
- PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT),
- PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT),
- PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT),
- PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT),
- PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT),
- PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT),
-
- /* PTF GPIO */
- PINMUX_DATA(PTF7_DATA, PTF7_IN, PTF7_OUT),
- PINMUX_DATA(PTF6_DATA, PTF6_IN, PTF6_OUT),
- PINMUX_DATA(PTF5_DATA, PTF5_IN, PTF5_OUT),
- PINMUX_DATA(PTF4_DATA, PTF4_IN, PTF4_OUT),
- PINMUX_DATA(PTF3_DATA, PTF3_IN, PTF3_OUT),
- PINMUX_DATA(PTF2_DATA, PTF2_IN, PTF2_OUT),
- PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_OUT),
- PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT),
-
- /* PTG GPIO */
- PINMUX_DATA(PTG7_DATA, PTG7_IN, PTG7_OUT),
- PINMUX_DATA(PTG6_DATA, PTG6_IN, PTG6_OUT),
- PINMUX_DATA(PTG5_DATA, PTG5_IN, PTG5_OUT),
- PINMUX_DATA(PTG4_DATA, PTG4_IN, PTG4_OUT),
- PINMUX_DATA(PTG3_DATA, PTG3_IN, PTG3_OUT),
- PINMUX_DATA(PTG2_DATA, PTG2_IN, PTG2_OUT),
- PINMUX_DATA(PTG1_DATA, PTG1_IN, PTG1_OUT),
- PINMUX_DATA(PTG0_DATA, PTG0_IN, PTG0_OUT),
-
- /* PTH GPIO */
- PINMUX_DATA(PTH7_DATA, PTH7_IN, PTH7_OUT),
- PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT),
- PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT),
- PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT),
- PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT),
- PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT),
- PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT),
- PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT),
-
- /* PTI GPIO */
- PINMUX_DATA(PTI7_DATA, PTI7_IN, PTI7_OUT),
- PINMUX_DATA(PTI6_DATA, PTI6_IN, PTI6_OUT),
- PINMUX_DATA(PTI5_DATA, PTI5_IN, PTI5_OUT),
- PINMUX_DATA(PTI4_DATA, PTI4_IN, PTI4_OUT),
- PINMUX_DATA(PTI3_DATA, PTI3_IN, PTI3_OUT),
- PINMUX_DATA(PTI2_DATA, PTI2_IN, PTI2_OUT),
- PINMUX_DATA(PTI1_DATA, PTI1_IN, PTI1_OUT),
- PINMUX_DATA(PTI0_DATA, PTI0_IN, PTI0_OUT),
-
- /* PTJ GPIO */
- PINMUX_DATA(PTJ6_DATA, PTJ6_IN, PTJ6_OUT),
- PINMUX_DATA(PTJ5_DATA, PTJ5_IN, PTJ5_OUT),
- PINMUX_DATA(PTJ4_DATA, PTJ4_IN, PTJ4_OUT),
- PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT),
- PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT),
- PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT),
- PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT),
-
- /* PTK GPIO */
- PINMUX_DATA(PTK7_DATA, PTK7_IN, PTK7_OUT),
- PINMUX_DATA(PTK6_DATA, PTK6_IN, PTK6_OUT),
- PINMUX_DATA(PTK5_DATA, PTK5_IN, PTK5_OUT),
- PINMUX_DATA(PTK4_DATA, PTK4_IN, PTK4_OUT),
- PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT),
- PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT),
- PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT),
- PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT),
-
- /* PTL GPIO */
- PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT),
- PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT),
- PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT),
- PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT),
- PINMUX_DATA(PTL2_DATA, PTL2_IN, PTL2_OUT),
- PINMUX_DATA(PTL1_DATA, PTL1_IN, PTL1_OUT),
- PINMUX_DATA(PTL0_DATA, PTL0_IN, PTL0_OUT),
-
- /* PTM GPIO */
- PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT),
- PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT),
- PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT),
- PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT),
- PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT),
- PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT),
- PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT),
-
- /* PTN GPIO */
- PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT),
- PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT),
- PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT),
- PINMUX_DATA(PTN3_DATA, PTN3_IN, PTN3_OUT),
- PINMUX_DATA(PTN2_DATA, PTN2_IN, PTN2_OUT),
- PINMUX_DATA(PTN1_DATA, PTN1_IN, PTN1_OUT),
- PINMUX_DATA(PTN0_DATA, PTN0_IN, PTN0_OUT),
-
- /* PTO GPIO */
- PINMUX_DATA(PTO7_DATA, PTO7_IN, PTO7_OUT),
- PINMUX_DATA(PTO6_DATA, PTO6_IN, PTO6_OUT),
- PINMUX_DATA(PTO5_DATA, PTO5_IN, PTO5_OUT),
- PINMUX_DATA(PTO4_DATA, PTO4_IN, PTO4_OUT),
- PINMUX_DATA(PTO3_DATA, PTO3_IN, PTO3_OUT),
- PINMUX_DATA(PTO2_DATA, PTO2_IN, PTO2_OUT),
- PINMUX_DATA(PTO1_DATA, PTO1_IN, PTO1_OUT),
- PINMUX_DATA(PTO0_DATA, PTO0_IN, PTO0_OUT),
-
- /* PTQ GPIO */
- PINMUX_DATA(PTQ6_DATA, PTQ6_IN, PTQ6_OUT),
- PINMUX_DATA(PTQ5_DATA, PTQ5_IN, PTQ5_OUT),
- PINMUX_DATA(PTQ4_DATA, PTQ4_IN, PTQ4_OUT),
- PINMUX_DATA(PTQ3_DATA, PTQ3_IN, PTQ3_OUT),
- PINMUX_DATA(PTQ2_DATA, PTQ2_IN, PTQ2_OUT),
- PINMUX_DATA(PTQ1_DATA, PTQ1_IN, PTQ1_OUT),
- PINMUX_DATA(PTQ0_DATA, PTQ0_IN, PTQ0_OUT),
-
- /* PTR GPIO */
- PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT),
- PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT),
- PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT),
- PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT),
- PINMUX_DATA(PTR3_DATA, PTR3_IN, PTR3_OUT),
- PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_OUT),
- PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT),
- PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT),
-
- /* PTS GPIO */
- PINMUX_DATA(PTS7_DATA, PTS7_IN, PTS7_OUT),
- PINMUX_DATA(PTS6_DATA, PTS6_IN, PTS6_OUT),
- PINMUX_DATA(PTS5_DATA, PTS5_IN, PTS5_OUT),
- PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT),
- PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT),
- PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT),
- PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT),
- PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT),
-
- /* PTT GPIO */
- PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT),
- PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT),
- PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT),
- PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT),
- PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT),
- PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT),
- PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT),
- PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT),
-
- /* PTU GPIO */
- PINMUX_DATA(PTU7_DATA, PTU7_IN, PTU7_OUT),
- PINMUX_DATA(PTU6_DATA, PTU6_IN, PTU6_OUT),
- PINMUX_DATA(PTU5_DATA, PTU5_IN, PTU5_OUT),
- PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT),
- PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT),
- PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT),
- PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT),
- PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT),
-
- /* PTV GPIO */
- PINMUX_DATA(PTV7_DATA, PTV7_IN, PTV7_OUT),
- PINMUX_DATA(PTV6_DATA, PTV6_IN, PTV6_OUT),
- PINMUX_DATA(PTV5_DATA, PTV5_IN, PTV5_OUT),
- PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT),
- PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT),
- PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT),
- PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT),
- PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT),
-
- /* PTW GPIO */
- PINMUX_DATA(PTW7_DATA, PTW7_IN, PTW7_OUT),
- PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_OUT),
- PINMUX_DATA(PTW5_DATA, PTW5_IN, PTW5_OUT),
- PINMUX_DATA(PTW4_DATA, PTW4_IN, PTW4_OUT),
- PINMUX_DATA(PTW3_DATA, PTW3_IN, PTW3_OUT),
- PINMUX_DATA(PTW2_DATA, PTW2_IN, PTW2_OUT),
- PINMUX_DATA(PTW1_DATA, PTW1_IN, PTW1_OUT),
- PINMUX_DATA(PTW0_DATA, PTW0_IN, PTW0_OUT),
-
- /* PTX GPIO */
- PINMUX_DATA(PTX7_DATA, PTX7_IN, PTX7_OUT),
- PINMUX_DATA(PTX6_DATA, PTX6_IN, PTX6_OUT),
- PINMUX_DATA(PTX5_DATA, PTX5_IN, PTX5_OUT),
- PINMUX_DATA(PTX4_DATA, PTX4_IN, PTX4_OUT),
- PINMUX_DATA(PTX3_DATA, PTX3_IN, PTX3_OUT),
- PINMUX_DATA(PTX2_DATA, PTX2_IN, PTX2_OUT),
- PINMUX_DATA(PTX1_DATA, PTX1_IN, PTX1_OUT),
- PINMUX_DATA(PTX0_DATA, PTX0_IN, PTX0_OUT),
-
- /* PTY GPIO */
- PINMUX_DATA(PTY7_DATA, PTY7_IN, PTY7_OUT),
- PINMUX_DATA(PTY6_DATA, PTY6_IN, PTY6_OUT),
- PINMUX_DATA(PTY5_DATA, PTY5_IN, PTY5_OUT),
- PINMUX_DATA(PTY4_DATA, PTY4_IN, PTY4_OUT),
- PINMUX_DATA(PTY3_DATA, PTY3_IN, PTY3_OUT),
- PINMUX_DATA(PTY2_DATA, PTY2_IN, PTY2_OUT),
- PINMUX_DATA(PTY1_DATA, PTY1_IN, PTY1_OUT),
- PINMUX_DATA(PTY0_DATA, PTY0_IN, PTY0_OUT),
-
- /* PTZ GPIO */
- PINMUX_DATA(PTZ7_DATA, PTZ7_IN, PTZ7_OUT),
- PINMUX_DATA(PTZ6_DATA, PTZ6_IN, PTZ6_OUT),
- PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_OUT),
- PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_OUT),
- PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_OUT),
- PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_OUT),
- PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_OUT),
- PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT),
-
- /* PTA FN */
- PINMUX_DATA(BS_MARK, PTA7_FN),
- PINMUX_DATA(RDWR_MARK, PTA6_FN),
- PINMUX_DATA(WE1_MARK, PTA5_FN),
- PINMUX_DATA(RDY_MARK, PTA4_FN),
- PINMUX_DATA(ET0_MDC_MARK, PTA3_FN),
- PINMUX_DATA(ET0_MDIO_MARK, PTA2_FN),
- PINMUX_DATA(ET1_MDC_MARK, PTA1_FN),
- PINMUX_DATA(ET1_MDIO_MARK, PTA0_FN),
-
- /* PTB FN */
- PINMUX_DATA(IRQ15_MARK, PS0_15_FN1, PTB7_FN),
- PINMUX_DATA(ON_NRE_MARK, PS0_15_FN2, PTB7_FN),
- PINMUX_DATA(IRQ14_MARK, PS0_14_FN1, PTB6_FN),
- PINMUX_DATA(ON_NWE_MARK, PS0_14_FN2, PTB6_FN),
- PINMUX_DATA(IRQ13_MARK, PS0_13_FN1, PTB5_FN),
- PINMUX_DATA(ON_NWP_MARK, PS0_13_FN2, PTB5_FN),
- PINMUX_DATA(IRQ12_MARK, PS0_12_FN1, PTB4_FN),
- PINMUX_DATA(ON_NCE0_MARK, PS0_12_FN2, PTB4_FN),
- PINMUX_DATA(IRQ11_MARK, PS0_11_FN1, PTB3_FN),
- PINMUX_DATA(ON_R_B0_MARK, PS0_11_FN2, PTB3_FN),
- PINMUX_DATA(IRQ10_MARK, PS0_10_FN1, PTB2_FN),
- PINMUX_DATA(ON_ALE_MARK, PS0_10_FN2, PTB2_FN),
- PINMUX_DATA(IRQ9_MARK, PS0_9_FN1, PTB1_FN),
- PINMUX_DATA(ON_CLE_MARK, PS0_9_FN2, PTB1_FN),
- PINMUX_DATA(IRQ8_MARK, PS0_8_FN1, PTB0_FN),
- PINMUX_DATA(TCLK_MARK, PS0_8_FN2, PTB0_FN),
-
- /* PTC FN */
- PINMUX_DATA(IRQ7_MARK, PS0_7_FN1, PTC7_FN),
- PINMUX_DATA(PWMU0_MARK, PS0_7_FN2, PTC7_FN),
- PINMUX_DATA(IRQ6_MARK, PS0_6_FN1, PTC6_FN),
- PINMUX_DATA(PWMU1_MARK, PS0_6_FN2, PTC6_FN),
- PINMUX_DATA(IRQ5_MARK, PS0_5_FN1, PTC5_FN),
- PINMUX_DATA(PWMU2_MARK, PS0_5_FN2, PTC5_FN),
- PINMUX_DATA(IRQ4_MARK, PS0_4_FN1, PTC5_FN),
- PINMUX_DATA(PWMU3_MARK, PS0_4_FN2, PTC4_FN),
- PINMUX_DATA(IRQ3_MARK, PS0_3_FN1, PTC3_FN),
- PINMUX_DATA(PWMU4_MARK, PS0_3_FN2, PTC3_FN),
- PINMUX_DATA(IRQ2_MARK, PS0_2_FN1, PTC2_FN),
- PINMUX_DATA(PWMU5_MARK, PS0_2_FN2, PTC2_FN),
- PINMUX_DATA(IRQ1_MARK, PTC1_FN),
- PINMUX_DATA(IRQ0_MARK, PTC0_FN),
-
- /* PTD FN */
- PINMUX_DATA(SP0_MOSI_MARK, PTD7_FN),
- PINMUX_DATA(SP0_MISO_MARK, PTD6_FN),
- PINMUX_DATA(SP0_SCK_MARK, PTD5_FN),
- PINMUX_DATA(SP0_SCK_FB_MARK, PTD4_FN),
- PINMUX_DATA(SP0_SS0_MARK, PTD3_FN),
- PINMUX_DATA(SP0_SS1_MARK, PS1_10_FN1, PTD2_FN),
- PINMUX_DATA(DREQ0_MARK, PS1_10_FN2, PTD2_FN),
- PINMUX_DATA(SP0_SS2_MARK, PS1_9_FN1, PTD1_FN),
- PINMUX_DATA(DACK0_MARK, PS1_9_FN2, PTD1_FN),
- PINMUX_DATA(SP0_SS3_MARK, PS1_8_FN1, PTD0_FN),
- PINMUX_DATA(TEND0_MARK, PS1_8_FN2, PTD0_FN),
-
- /* PTE FN */
- PINMUX_DATA(RMII0_CRS_DV_MARK, PTE7_FN),
- PINMUX_DATA(RMII0_TXD1_MARK, PTE6_FN),
- PINMUX_DATA(RMII0_TXD0_MARK, PTE5_FN),
- PINMUX_DATA(RMII0_TXEN_MARK, PTE4_FN),
- PINMUX_DATA(RMII0_REFCLK_MARK, PTE3_FN),
- PINMUX_DATA(RMII0_RXD1_MARK, PTE2_FN),
- PINMUX_DATA(RMII0_RXD0_MARK, PTE1_FN),
- PINMUX_DATA(RMII0_RX_ER_MARK, PTE0_FN),
-
- /* PTF FN */
- PINMUX_DATA(RMII1_CRS_DV_MARK, PTF7_FN),
- PINMUX_DATA(RMII1_TXD1_MARK, PTF6_FN),
- PINMUX_DATA(RMII1_TXD0_MARK, PTF5_FN),
- PINMUX_DATA(RMII1_TXEN_MARK, PTF4_FN),
- PINMUX_DATA(RMII1_REFCLK_MARK, PTF3_FN),
- PINMUX_DATA(RMII1_RXD1_MARK, PS1_2_FN1, PTF2_FN),
- PINMUX_DATA(RAC_RI_MARK, PS1_2_FN2, PTF2_FN),
- PINMUX_DATA(RMII1_RXD0_MARK, PTF1_FN),
- PINMUX_DATA(RMII1_RX_ER_MARK, PTF0_FN),
-
- /* PTG FN */
- PINMUX_DATA(BOOTFMS_MARK, PTG7_FN),
- PINMUX_DATA(BOOTWP_MARK, PTG6_FN),
- PINMUX_DATA(A25_MARK, PS2_13_FN1, PTG5_FN),
- PINMUX_DATA(MMCCLK_MARK, PS2_13_FN2, PTG5_FN),
- PINMUX_DATA(A24_MARK, PS2_12_FN1, PTG4_FN),
- PINMUX_DATA(MMCCMD_MARK, PS2_12_FN2, PTG4_FN),
- PINMUX_DATA(SERIRQ_MARK, PTG3_FN),
- PINMUX_DATA(WDTOVF_MARK, PTG2_FN),
- PINMUX_DATA(LPCPD_MARK, PTG1_FN),
- PINMUX_DATA(LDRQ_MARK, PTG0_FN),
-
- /* PTH FN */
- PINMUX_DATA(SP1_MOSI_MARK, PS2_7_FN1, PTH7_FN),
- PINMUX_DATA(TEND1_MARK, PS2_7_FN2, PTH7_FN),
- PINMUX_DATA(SP1_MISO_MARK, PS2_6_FN1, PTH6_FN),
- PINMUX_DATA(DREQ1_MARK, PS2_6_FN2, PTH6_FN),
- PINMUX_DATA(SP1_SCK_MARK, PS2_5_FN1, PTH5_FN),
- PINMUX_DATA(DACK1_MARK, PS2_5_FN2, PTH5_FN),
- PINMUX_DATA(SP1_SCK_FB_MARK, PS2_4_FN1, PTH4_FN),
- PINMUX_DATA(ADTRG1_MARK, PS2_4_FN2, PTH4_FN),
- PINMUX_DATA(SP1_SS0_MARK, PTH3_FN),
- PINMUX_DATA(SP1_SS1_MARK, PS2_2_FN1, PTH2_FN),
- PINMUX_DATA(ADTRG0_MARK, PS2_2_FN2, PTH2_FN),
- PINMUX_DATA(WP_MARK, PTH1_FN),
- PINMUX_DATA(FMS0_MARK, PTH0_FN),
-
- /* PTI FN */
- PINMUX_DATA(D15_MARK, PS3_15_FN1, PTI7_FN),
- PINMUX_DATA(SD_WP_MARK, PS3_15_FN2, PTI7_FN),
- PINMUX_DATA(D14_MARK, PS3_14_FN1, PTI6_FN),
- PINMUX_DATA(SD_CD_MARK, PS3_14_FN2, PTI6_FN),
- PINMUX_DATA(D13_MARK, PS3_13_FN1, PTI5_FN),
- PINMUX_DATA(SD_CLK_MARK, PS3_13_FN2, PTI5_FN),
- PINMUX_DATA(D12_MARK, PS3_12_FN1, PTI4_FN),
- PINMUX_DATA(SD_CMD_MARK, PS3_12_FN2, PTI4_FN),
- PINMUX_DATA(D11_MARK, PS3_11_FN1, PTI3_FN),
- PINMUX_DATA(SD_D3_MARK, PS3_11_FN2, PTI3_FN),
- PINMUX_DATA(D10_MARK, PS3_10_FN1, PTI2_FN),
- PINMUX_DATA(SD_D2_MARK, PS3_10_FN2, PTI2_FN),
- PINMUX_DATA(D9_MARK, PS3_9_FN1, PTI1_FN),
- PINMUX_DATA(SD_D1_MARK, PS3_9_FN2, PTI1_FN),
- PINMUX_DATA(D8_MARK, PS3_8_FN1, PTI0_FN),
- PINMUX_DATA(SD_D0_MARK, PS3_8_FN2, PTI0_FN),
-
- /* PTJ FN */
- PINMUX_DATA(RTS3_MARK, PTJ6_FN),
- PINMUX_DATA(CTS3_MARK, PTJ5_FN),
- PINMUX_DATA(TXD3_MARK, PTJ4_FN),
- PINMUX_DATA(RXD3_MARK, PTJ3_FN),
- PINMUX_DATA(RTS4_MARK, PTJ2_FN),
- PINMUX_DATA(RXD4_MARK, PTJ1_FN),
- PINMUX_DATA(TXD4_MARK, PTJ0_FN),
-
- /* PTK FN */
- PINMUX_DATA(COM2_TXD_MARK, PS3_7_FN1, PTK7_FN),
- PINMUX_DATA(SCK2_MARK, PS3_7_FN2, PTK7_FN),
- PINMUX_DATA(COM2_RXD_MARK, PTK6_FN),
- PINMUX_DATA(COM2_RTS_MARK, PTK5_FN),
- PINMUX_DATA(COM2_CTS_MARK, PTK4_FN),
- PINMUX_DATA(COM2_DTR_MARK, PTK3_FN),
- PINMUX_DATA(COM2_DSR_MARK, PS3_2_FN1, PTK2_FN),
- PINMUX_DATA(SCK4_MARK, PS3_2_FN2, PTK2_FN),
- PINMUX_DATA(COM2_DCD_MARK, PS3_1_FN1, PTK1_FN),
- PINMUX_DATA(SCK3_MARK, PS3_1_FN2, PTK1_FN),
- PINMUX_DATA(CLKOUT_MARK, PTK0_FN),
-
- /* PTL FN */
- PINMUX_DATA(RAC_RXD_MARK, PS4_14_FN1, PTL6_FN),
- PINMUX_DATA(RXD2_MARK, PS4_14_FN2, PTL6_FN),
- PINMUX_DATA(RAC_RTS_MARK, PS4_13_FN1, PTL5_FN),
- PINMUX_DATA(CS5_MARK, PS4_13_FN2, PTL5_FN),
- PINMUX_DATA(RAC_CTS_MARK, PS4_12_FN1, PTL4_FN),
- PINMUX_DATA(CS6_MARK, PS4_12_FN2, PTL4_FN),
- PINMUX_DATA(RAC_DTR_MARK, PTL3_FN),
- PINMUX_DATA(RAC_DSR_MARK, PS4_10_FN1, PTL2_FN),
- PINMUX_DATA(AUDSYNC_MARK, PS4_10_FN2, PTL2_FN),
- PINMUX_DATA(RAC_DCD_MARK, PS4_9_FN1, PTL1_FN),
- PINMUX_DATA(AUDCK_MARK, PS4_9_FN2, PTL1_FN),
- PINMUX_DATA(RAC_TXD_MARK, PS4_8_FN1, PTL0_FN),
- PINMUX_DATA(TXD2_MARK, PS4_8_FN1, PTL0_FN),
-
- /* PTM FN */
- PINMUX_DATA(CS4_MARK, PTM7_FN),
- PINMUX_DATA(RD_MARK, PTM6_FN),
- PINMUX_DATA(WE0_MARK, PTM7_FN),
- PINMUX_DATA(CS0_MARK, PTM4_FN),
- PINMUX_DATA(SDA6_MARK, PTM3_FN),
- PINMUX_DATA(SCL6_MARK, PTM2_FN),
- PINMUX_DATA(SDA7_MARK, PTM1_FN),
- PINMUX_DATA(SCL7_MARK, PTM0_FN),
-
- /* PTN FN */
- PINMUX_DATA(VBUS_EN_MARK, PTN6_FN),
- PINMUX_DATA(VBUS_OC_MARK, PTN5_FN),
- PINMUX_DATA(JMCTCK_MARK, PS4_4_FN1, PTN4_FN),
- PINMUX_DATA(SGPIO1_CLK_MARK, PS4_4_FN2, PTN4_FN),
- PINMUX_DATA(JMCTMS_MARK, PS4_3_FN1, PTN5_FN),
- PINMUX_DATA(SGPIO1_LOAD_MARK, PS4_3_FN2, PTN5_FN),
- PINMUX_DATA(JMCTDO_MARK, PS4_2_FN1, PTN2_FN),
- PINMUX_DATA(SGPIO1_DO_MARK, PS4_2_FN2, PTN2_FN),
- PINMUX_DATA(JMCTDI_MARK, PS4_1_FN1, PTN1_FN),
- PINMUX_DATA(SGPIO1_DI_MARK, PS4_1_FN2, PTN1_FN),
- PINMUX_DATA(JMCTRST_MARK, PS4_0_FN1, PTN0_FN),
- PINMUX_DATA(SUB_CLKIN_MARK, PS4_0_FN2, PTN0_FN),
-
- /* PTO FN */
- PINMUX_DATA(SGPIO0_CLK_MARK, PTO7_FN),
- PINMUX_DATA(SGPIO0_LOAD_MARK, PTO6_FN),
- PINMUX_DATA(SGPIO0_DI_MARK, PTO5_FN),
- PINMUX_DATA(SGPIO0_DO_MARK, PTO4_FN),
- PINMUX_DATA(SGPIO2_CLK_MARK, PS5_11_FN1, PTO3_FN),
- PINMUX_DATA(COM1_TXD_MARK, PS5_11_FN2, PTO3_FN),
- PINMUX_DATA(SGPIO2_LOAD_MARK, PS5_10_FN1, PTO2_FN),
- PINMUX_DATA(COM1_RXD_MARK, PS5_10_FN2, PTO2_FN),
- PINMUX_DATA(SGPIO2_DI_MARK, PS5_9_FN1, PTO1_FN),
- PINMUX_DATA(COM1_RTS_MARK, PS5_9_FN2, PTO1_FN),
- PINMUX_DATA(SGPIO2_DO_MARK, PS5_8_FN1, PTO0_FN),
- PINMUX_DATA(COM1_CTS_MARK, PS5_8_FN2, PTO0_FN),
-
- /* PTP FN */
-
- /* PTQ FN */
- PINMUX_DATA(LAD3_MARK, PTQ6_FN),
- PINMUX_DATA(LAD2_MARK, PTQ5_FN),
- PINMUX_DATA(LAD1_MARK, PTQ4_FN),
- PINMUX_DATA(LAD0_MARK, PTQ3_FN),
- PINMUX_DATA(LFRAME_MARK, PTQ2_FN),
- PINMUX_DATA(LRESET_MARK, PTQ1_FN),
- PINMUX_DATA(LCLK_MARK, PTQ0_FN),
-
- /* PTR FN */
- PINMUX_DATA(SDA8_MARK, PTR7_FN), /* DDC3? */
- PINMUX_DATA(SCL8_MARK, PTR6_FN), /* DDC2? */
- PINMUX_DATA(SDA2_MARK, PTR5_FN),
- PINMUX_DATA(SCL2_MARK, PTR4_FN),
- PINMUX_DATA(SDA1_MARK, PTR3_FN),
- PINMUX_DATA(SCL1_MARK, PTR2_FN),
- PINMUX_DATA(SDA0_MARK, PTR1_FN),
- PINMUX_DATA(SCL0_MARK, PTR0_FN),
-
- /* PTS FN */
- PINMUX_DATA(SDA9_MARK, PTS7_FN), /* DDC1? */
- PINMUX_DATA(SCL9_MARK, PTS6_FN), /* DDC0? */
- PINMUX_DATA(SDA5_MARK, PTS5_FN),
- PINMUX_DATA(SCL5_MARK, PTS4_FN),
- PINMUX_DATA(SDA4_MARK, PTS3_FN),
- PINMUX_DATA(SCL4_MARK, PTS2_FN),
- PINMUX_DATA(SDA3_MARK, PTS1_FN),
- PINMUX_DATA(SCL3_MARK, PTS0_FN),
-
- /* PTT FN */
- PINMUX_DATA(PWMX7_MARK, PS5_7_FN1, PTT7_FN),
- PINMUX_DATA(AUDATA3_MARK, PS5_7_FN2, PTT7_FN),
- PINMUX_DATA(PWMX6_MARK, PS5_6_FN1, PTT6_FN),
- PINMUX_DATA(AUDATA2_MARK, PS5_6_FN2, PTT6_FN),
- PINMUX_DATA(PWMX5_MARK, PS5_5_FN1, PTT5_FN),
- PINMUX_DATA(AUDATA1_MARK, PS5_5_FN2, PTT5_FN),
- PINMUX_DATA(PWMX4_MARK, PS5_4_FN1, PTT4_FN),
- PINMUX_DATA(AUDATA0_MARK, PS5_4_FN2, PTT4_FN),
- PINMUX_DATA(PWMX3_MARK, PS5_3_FN1, PTT3_FN),
- PINMUX_DATA(STATUS1_MARK, PS5_3_FN2, PTT3_FN),
- PINMUX_DATA(PWMX2_MARK, PS5_2_FN1, PTT2_FN),
- PINMUX_DATA(STATUS0_MARK, PS5_2_FN2, PTT2_FN),
- PINMUX_DATA(PWMX1_MARK, PTT1_FN),
- PINMUX_DATA(PWMX0_MARK, PTT0_FN),
-
- /* PTU FN */
- PINMUX_DATA(LGPIO7_MARK, PS6_15_FN1, PTU7_FN),
- PINMUX_DATA(APMONCTL_O_MARK, PS6_15_FN2, PTU7_FN),
- PINMUX_DATA(LGPIO6_MARK, PS6_14_FN1, PTU6_FN),
- PINMUX_DATA(APMPWBTOUT_O_MARK, PS6_14_FN2, PTU6_FN),
- PINMUX_DATA(LGPIO5_MARK, PS6_13_FN1, PTU5_FN),
- PINMUX_DATA(APMSCI_O_MARK, PS6_13_FN2, PTU5_FN),
- PINMUX_DATA(LGPIO4_MARK, PS6_12_FN1, PTU4_FN),
- PINMUX_DATA(APMVDDON_MARK, PS6_12_FN2, PTU4_FN),
- PINMUX_DATA(LGPIO3_MARK, PS6_11_FN1, PTU3_FN),
- PINMUX_DATA(APMSLPBTN_MARK, PS6_11_FN2, PTU3_FN),
- PINMUX_DATA(LGPIO2_MARK, PS6_10_FN1, PTU2_FN),
- PINMUX_DATA(APMPWRBTN_MARK, PS6_10_FN2, PTU2_FN),
- PINMUX_DATA(LGPIO1_MARK, PS6_9_FN1, PTU1_FN),
- PINMUX_DATA(APMS5N_MARK, PS6_9_FN2, PTU1_FN),
- PINMUX_DATA(LGPIO0_MARK, PS6_8_FN1, PTU0_FN),
- PINMUX_DATA(APMS3N_MARK, PS6_8_FN2, PTU0_FN),
-
- /* PTV FN */
- PINMUX_DATA(A23_MARK, PS6_7_FN1, PTV7_FN),
- PINMUX_DATA(COM2_RI_MARK, PS6_7_FN2, PTV7_FN),
- PINMUX_DATA(A22_MARK, PS6_6_FN1, PTV6_FN),
- PINMUX_DATA(R_SPI_MOSI_MARK, PS6_6_FN2, PTV6_FN),
- PINMUX_DATA(A21_MARK, PS6_5_FN1, PTV5_FN),
- PINMUX_DATA(R_SPI_MISO_MARK, PS6_5_FN2, PTV5_FN),
- PINMUX_DATA(A20_MARK, PS6_4_FN1, PTV4_FN),
- PINMUX_DATA(R_SPI_RSPCK_MARK, PS6_4_FN2, PTV4_FN),
- PINMUX_DATA(A19_MARK, PS6_3_FN1, PTV3_FN),
- PINMUX_DATA(R_SPI_SSL0_MARK, PS6_3_FN2, PTV3_FN),
- PINMUX_DATA(A18_MARK, PS6_2_FN1, PTV2_FN),
- PINMUX_DATA(R_SPI_SSL1_MARK, PS6_2_FN2, PTV2_FN),
- PINMUX_DATA(A17_MARK, PS6_1_FN1, PTV1_FN),
- PINMUX_DATA(EVENT7_MARK, PS6_1_FN2, PTV1_FN),
- PINMUX_DATA(A16_MARK, PS6_0_FN1, PTV0_FN),
- PINMUX_DATA(EVENT6_MARK, PS6_0_FN1, PTV0_FN),
-
- /* PTW FN */
- PINMUX_DATA(A15_MARK, PS7_15_FN1, PTW7_FN),
- PINMUX_DATA(EVENT5_MARK, PS7_15_FN2, PTW7_FN),
- PINMUX_DATA(A14_MARK, PS7_14_FN1, PTW6_FN),
- PINMUX_DATA(EVENT4_MARK, PS7_14_FN2, PTW6_FN),
- PINMUX_DATA(A13_MARK, PS7_13_FN1, PTW5_FN),
- PINMUX_DATA(EVENT3_MARK, PS7_13_FN2, PTW5_FN),
- PINMUX_DATA(A12_MARK, PS7_12_FN1, PTW4_FN),
- PINMUX_DATA(EVENT2_MARK, PS7_12_FN2, PTW4_FN),
- PINMUX_DATA(A11_MARK, PS7_11_FN1, PTW3_FN),
- PINMUX_DATA(EVENT1_MARK, PS7_11_FN2, PTW3_FN),
- PINMUX_DATA(A10_MARK, PS7_10_FN1, PTW2_FN),
- PINMUX_DATA(EVENT0_MARK, PS7_10_FN2, PTW2_FN),
- PINMUX_DATA(A9_MARK, PS7_9_FN1, PTW1_FN),
- PINMUX_DATA(CTS4_MARK, PS7_9_FN2, PTW1_FN),
- PINMUX_DATA(A8_MARK, PS7_8_FN1, PTW0_FN),
- PINMUX_DATA(CTS2_MARK, PS7_8_FN2, PTW0_FN),
-
- /* PTX FN */
- PINMUX_DATA(A7_MARK, PS7_7_FN1, PTX7_FN),
- PINMUX_DATA(RTS2_MARK, PS7_7_FN2, PTX7_FN),
- PINMUX_DATA(A6_MARK, PS7_6_FN1, PTX6_FN),
- PINMUX_DATA(SIM_D_MARK, PS7_6_FN2, PTX6_FN),
- PINMUX_DATA(A5_MARK, PS7_5_FN1, PTX5_FN),
- PINMUX_DATA(SIM_CLK_MARK, PS7_5_FN2, PTX5_FN),
- PINMUX_DATA(A4_MARK, PS7_4_FN1, PTX4_FN),
- PINMUX_DATA(SIM_RST_MARK, PS7_4_FN2, PTX4_FN),
- PINMUX_DATA(A3_MARK, PTX3_FN),
- PINMUX_DATA(A2_MARK, PTX2_FN),
- PINMUX_DATA(A1_MARK, PTX1_FN),
- PINMUX_DATA(A0_MARK, PTX0_FN),
-
- /* PTY FN */
- PINMUX_DATA(D7_MARK, PTY7_FN),
- PINMUX_DATA(D6_MARK, PTY6_FN),
- PINMUX_DATA(D5_MARK, PTY5_FN),
- PINMUX_DATA(D4_MARK, PTY4_FN),
- PINMUX_DATA(D3_MARK, PTY3_FN),
- PINMUX_DATA(D2_MARK, PTY2_FN),
- PINMUX_DATA(D1_MARK, PTY1_FN),
- PINMUX_DATA(D0_MARK, PTY0_FN),
-
- /* PTZ FN */
- PINMUX_DATA(MMCDAT7_MARK, PS8_15_FN1, PTZ7_FN),
- PINMUX_DATA(ON_DQ7_MARK, PS8_15_FN2, PTZ7_FN),
- PINMUX_DATA(MMCDAT6_MARK, PS8_14_FN1, PTZ6_FN),
- PINMUX_DATA(ON_DQ6_MARK, PS8_14_FN2, PTZ6_FN),
- PINMUX_DATA(MMCDAT5_MARK, PS8_13_FN1, PTZ5_FN),
- PINMUX_DATA(ON_DQ5_MARK, PS8_13_FN2, PTZ5_FN),
- PINMUX_DATA(MMCDAT4_MARK, PS8_12_FN1, PTZ4_FN),
- PINMUX_DATA(ON_DQ4_MARK, PS8_12_FN2, PTZ4_FN),
- PINMUX_DATA(MMCDAT3_MARK, PS8_11_FN1, PTZ3_FN),
- PINMUX_DATA(ON_DQ3_MARK, PS8_11_FN2, PTZ3_FN),
- PINMUX_DATA(MMCDAT2_MARK, PS8_10_FN1, PTZ2_FN),
- PINMUX_DATA(ON_DQ2_MARK, PS8_10_FN2, PTZ2_FN),
- PINMUX_DATA(MMCDAT1_MARK, PS8_9_FN1, PTZ1_FN),
- PINMUX_DATA(ON_DQ1_MARK, PS8_9_FN2, PTZ1_FN),
- PINMUX_DATA(MMCDAT0_MARK, PS8_8_FN1, PTZ0_FN),
- PINMUX_DATA(ON_DQ0_MARK, PS8_8_FN2, PTZ0_FN),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
- /* PTA */
- PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
- PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
- PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
- PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
- PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
- PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
- PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
- PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
-
- /* PTB */
- PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
- PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
- PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
- PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
- PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
- PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
- PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
- PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
-
- /* PTC */
- PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
- PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
- PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
- PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
- PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
- PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
- PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
- PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
-
- /* PTD */
- PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
- PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
- PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
- PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
- PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
- PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
- PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
- PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
-
- /* PTE */
- PINMUX_GPIO(GPIO_PTE7, PTE7_DATA),
- PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
- PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
- PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
- PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
- PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
- PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
- PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
-
- /* PTF */
- PINMUX_GPIO(GPIO_PTF7, PTF7_DATA),
- PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
- PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
- PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
- PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
- PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
- PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
- PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
-
- /* PTG */
- PINMUX_GPIO(GPIO_PTG7, PTG7_DATA),
- PINMUX_GPIO(GPIO_PTG6, PTG6_DATA),
- PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
- PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
- PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
- PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
- PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
- PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
-
- /* PTH */
- PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
- PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
- PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
- PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
- PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
- PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
- PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
- PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
-
- /* PTI */
- PINMUX_GPIO(GPIO_PTI7, PTI7_DATA),
- PINMUX_GPIO(GPIO_PTI6, PTI6_DATA),
- PINMUX_GPIO(GPIO_PTI5, PTI5_DATA),
- PINMUX_GPIO(GPIO_PTI4, PTI4_DATA),
- PINMUX_GPIO(GPIO_PTI3, PTI3_DATA),
- PINMUX_GPIO(GPIO_PTI2, PTI2_DATA),
- PINMUX_GPIO(GPIO_PTI1, PTI1_DATA),
- PINMUX_GPIO(GPIO_PTI0, PTI0_DATA),
-
- /* PTJ */
- PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
- PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
- PINMUX_GPIO(GPIO_PTJ4, PTJ4_DATA),
- PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
- PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
- PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
- PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
-
- /* PTK */
- PINMUX_GPIO(GPIO_PTK7, PTK7_DATA),
- PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
- PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
- PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
- PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
- PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
- PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
- PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
-
- /* PTL */
- PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
- PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
- PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
- PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
- PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
- PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
- PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
-
- /* PTM */
- PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
- PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
- PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
- PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
- PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
- PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
- PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
- PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
-
- /* PTN */
- PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
- PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
- PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
- PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
- PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
- PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
- PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
-
- /* PTO */
- PINMUX_GPIO(GPIO_PTO7, PTO7_DATA),
- PINMUX_GPIO(GPIO_PTO6, PTO6_DATA),
- PINMUX_GPIO(GPIO_PTO5, PTO5_DATA),
- PINMUX_GPIO(GPIO_PTO4, PTO4_DATA),
- PINMUX_GPIO(GPIO_PTO3, PTO3_DATA),
- PINMUX_GPIO(GPIO_PTO2, PTO2_DATA),
- PINMUX_GPIO(GPIO_PTO1, PTO1_DATA),
- PINMUX_GPIO(GPIO_PTO0, PTO0_DATA),
-
- /* PTP */
- PINMUX_GPIO(GPIO_PTP7, PTP7_DATA),
- PINMUX_GPIO(GPIO_PTP6, PTP6_DATA),
- PINMUX_GPIO(GPIO_PTP5, PTP5_DATA),
- PINMUX_GPIO(GPIO_PTP4, PTP4_DATA),
- PINMUX_GPIO(GPIO_PTP3, PTP3_DATA),
- PINMUX_GPIO(GPIO_PTP2, PTP2_DATA),
- PINMUX_GPIO(GPIO_PTP1, PTP1_DATA),
- PINMUX_GPIO(GPIO_PTP0, PTP0_DATA),
-
- /* PTQ */
- PINMUX_GPIO(GPIO_PTQ6, PTQ6_DATA),
- PINMUX_GPIO(GPIO_PTQ5, PTQ5_DATA),
- PINMUX_GPIO(GPIO_PTQ4, PTQ4_DATA),
- PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
- PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
- PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
- PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
-
- /* PTR */
- PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
- PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
- PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
- PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
- PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
- PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
- PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
- PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
-
- /* PTS */
- PINMUX_GPIO(GPIO_PTS7, PTS7_DATA),
- PINMUX_GPIO(GPIO_PTS6, PTS6_DATA),
- PINMUX_GPIO(GPIO_PTS5, PTS5_DATA),
- PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
- PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
- PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
- PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
- PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
-
- /* PTT */
- PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
- PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
- PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
- PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
- PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
- PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
- PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
- PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
-
- /* PTU */
- PINMUX_GPIO(GPIO_PTU7, PTU7_DATA),
- PINMUX_GPIO(GPIO_PTU6, PTU6_DATA),
- PINMUX_GPIO(GPIO_PTU5, PTU5_DATA),
- PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
- PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
- PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
- PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
- PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
-
- /* PTV */
- PINMUX_GPIO(GPIO_PTV7, PTV7_DATA),
- PINMUX_GPIO(GPIO_PTV6, PTV6_DATA),
- PINMUX_GPIO(GPIO_PTV5, PTV5_DATA),
- PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
- PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
- PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
- PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
- PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
-
- /* PTW */
- PINMUX_GPIO(GPIO_PTW7, PTW7_DATA),
- PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
- PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
- PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
- PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
- PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
- PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
- PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
-
- /* PTX */
- PINMUX_GPIO(GPIO_PTX7, PTX7_DATA),
- PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
- PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
- PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
- PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
- PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
- PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
- PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
-
- /* PTY */
- PINMUX_GPIO(GPIO_PTY7, PTY7_DATA),
- PINMUX_GPIO(GPIO_PTY6, PTY6_DATA),
- PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
- PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
- PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
- PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
- PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
- PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
-
- /* PTZ */
- PINMUX_GPIO(GPIO_PTZ7, PTZ7_DATA),
- PINMUX_GPIO(GPIO_PTZ6, PTZ6_DATA),
- PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
- PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
- PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
- PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
- PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
- PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
-
- /* PTA (mobule: LBSC, RGMII) */
- PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
- PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
- PINMUX_GPIO(GPIO_FN_WE1, WE1_MARK),
- PINMUX_GPIO(GPIO_FN_RDY, RDY_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_MDC, ET0_MDC_MARK),
- PINMUX_GPIO(GPIO_FN_ET0_MDIO, ET0_MDC_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_MDC, ET1_MDC_MARK),
- PINMUX_GPIO(GPIO_FN_ET1_MDIO, ET1_MDC_MARK),
-
- /* PTB (mobule: INTC, ONFI, TMU) */
- PINMUX_GPIO(GPIO_FN_IRQ15, IRQ15_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ14, IRQ14_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ13, IRQ13_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ12, IRQ12_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ11, IRQ11_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ10, IRQ10_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ9, IRQ9_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ8, IRQ8_MARK),
- PINMUX_GPIO(GPIO_FN_ON_NRE, ON_NRE_MARK),
- PINMUX_GPIO(GPIO_FN_ON_NWE, ON_NWE_MARK),
- PINMUX_GPIO(GPIO_FN_ON_NWP, ON_NWP_MARK),
- PINMUX_GPIO(GPIO_FN_ON_NCE0, ON_NCE0_MARK),
- PINMUX_GPIO(GPIO_FN_ON_R_B0, ON_R_B0_MARK),
- PINMUX_GPIO(GPIO_FN_ON_ALE, ON_ALE_MARK),
- PINMUX_GPIO(GPIO_FN_ON_CLE, ON_CLE_MARK),
- PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
-
- /* PTC (mobule: IRQ, PWMU) */
- PINMUX_GPIO(GPIO_FN_IRQ7, IRQ7_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ6, IRQ6_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ4, IRQ4_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3, IRQ3_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
- PINMUX_GPIO(GPIO_FN_PWMU0, PWMU0_MARK),
- PINMUX_GPIO(GPIO_FN_PWMU1, PWMU1_MARK),
- PINMUX_GPIO(GPIO_FN_PWMU2, PWMU2_MARK),
- PINMUX_GPIO(GPIO_FN_PWMU3, PWMU3_MARK),
- PINMUX_GPIO(GPIO_FN_PWMU4, PWMU4_MARK),
- PINMUX_GPIO(GPIO_FN_PWMU5, PWMU5_MARK),
-
- /* PTD (mobule: SPI0, DMAC) */
- PINMUX_GPIO(GPIO_FN_SP0_MOSI, SP0_MOSI_MARK),
- PINMUX_GPIO(GPIO_FN_SP0_MISO, SP0_MISO_MARK),
- PINMUX_GPIO(GPIO_FN_SP0_SCK, SP0_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SP0_SCK_FB, SP0_SCK_FB_MARK),
- PINMUX_GPIO(GPIO_FN_SP0_SS0, SP0_SS0_MARK),
- PINMUX_GPIO(GPIO_FN_SP0_SS1, SP0_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_SP0_SS2, SP0_SS2_MARK),
- PINMUX_GPIO(GPIO_FN_SP0_SS3, SP0_SS3_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
- PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
-
- /* PTE (mobule: RMII) */
- PINMUX_GPIO(GPIO_FN_RMII0_CRS_DV, RMII0_CRS_DV_MARK),
- PINMUX_GPIO(GPIO_FN_RMII0_TXD1, RMII0_TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RMII0_TXD0, RMII0_TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_RMII0_TXEN, RMII0_TXEN_MARK),
- PINMUX_GPIO(GPIO_FN_RMII0_REFCLK, RMII0_REFCLK_MARK),
- PINMUX_GPIO(GPIO_FN_RMII0_RXD1, RMII0_RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RMII0_RXD0, RMII0_RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_RMII0_RX_ER, RMII0_RX_ER_MARK),
-
- /* PTF (mobule: RMII, SerMux) */
- PINMUX_GPIO(GPIO_FN_RMII1_CRS_DV, RMII1_CRS_DV_MARK),
- PINMUX_GPIO(GPIO_FN_RMII1_TXD1, RMII1_TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RMII1_TXD0, RMII1_TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_RMII1_TXEN, RMII1_TXEN_MARK),
- PINMUX_GPIO(GPIO_FN_RMII1_REFCLK, RMII1_REFCLK_MARK),
- PINMUX_GPIO(GPIO_FN_RMII1_RXD1, RMII1_RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RMII1_RXD0, RMII1_RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_RMII1_RX_ER, RMII1_RX_ER_MARK),
- PINMUX_GPIO(GPIO_FN_RAC_RI, RAC_RI_MARK),
-
- /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
- PINMUX_GPIO(GPIO_FN_BOOTFMS, BOOTFMS_MARK),
- PINMUX_GPIO(GPIO_FN_BOOTWP, BOOTWP_MARK),
- PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
- PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
- PINMUX_GPIO(GPIO_FN_SERIRQ, SERIRQ_MARK),
- PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
- PINMUX_GPIO(GPIO_FN_LPCPD, LPCPD_MARK),
- PINMUX_GPIO(GPIO_FN_LDRQ, LDRQ_MARK),
- PINMUX_GPIO(GPIO_FN_MMCCLK, MMCCLK_MARK),
- PINMUX_GPIO(GPIO_FN_MMCCMD, MMCCMD_MARK),
-
- /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
- PINMUX_GPIO(GPIO_FN_SP1_MOSI, SP1_MOSI_MARK),
- PINMUX_GPIO(GPIO_FN_SP1_MISO, SP1_MISO_MARK),
- PINMUX_GPIO(GPIO_FN_SP1_SCK, SP1_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SP1_SCK_FB, SP1_SCK_FB_MARK),
- PINMUX_GPIO(GPIO_FN_SP1_SS0, SP1_SS0_MARK),
- PINMUX_GPIO(GPIO_FN_SP1_SS1, SP1_SS1_MARK),
- PINMUX_GPIO(GPIO_FN_WP, WP_MARK),
- PINMUX_GPIO(GPIO_FN_FMS0, FMS0_MARK),
- PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
- PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
- PINMUX_GPIO(GPIO_FN_ADTRG1, ADTRG1_MARK),
- PINMUX_GPIO(GPIO_FN_ADTRG0, ADTRG0_MARK),
-
- /* PTI (mobule: LBSC, SDHI) */
- PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
- PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
- PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
- PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
- PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
- PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
- PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
- PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
- PINMUX_GPIO(GPIO_FN_SD_WP, SD_WP_MARK),
- PINMUX_GPIO(GPIO_FN_SD_CD, SD_CD_MARK),
- PINMUX_GPIO(GPIO_FN_SD_CLK, SD_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SD_CMD, SD_CMD_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D3, SD_D3_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D2, SD_D2_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D1, SD_D1_MARK),
- PINMUX_GPIO(GPIO_FN_SD_D0, SD_D0_MARK),
-
- /* PTJ (mobule: SCIF234, SERMUX) */
- PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
- PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
- PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
- PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
- PINMUX_GPIO(GPIO_FN_RTS4, RTS4_MARK),
- PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
- PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
-
- /* PTK (mobule: SERMUX, LBSC, SCIF) */
- PINMUX_GPIO(GPIO_FN_COM2_TXD, COM2_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_COM2_RXD, COM2_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_COM2_RTS, COM2_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_COM2_CTS, COM2_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_COM2_DTR, COM2_DTR_MARK),
- PINMUX_GPIO(GPIO_FN_COM2_DSR, COM2_DSR_MARK),
- PINMUX_GPIO(GPIO_FN_COM2_DCD, COM2_DCD_MARK),
- PINMUX_GPIO(GPIO_FN_CLKOUT, CLKOUT_MARK),
- PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
- PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
- PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
-
- /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
- PINMUX_GPIO(GPIO_FN_RAC_RXD, RAC_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_RAC_RTS, RAC_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_RAC_CTS, RAC_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_RAC_DTR, RAC_DTR_MARK),
- PINMUX_GPIO(GPIO_FN_RAC_DSR, RAC_DSR_MARK),
- PINMUX_GPIO(GPIO_FN_RAC_DCD, RAC_DCD_MARK),
- PINMUX_GPIO(GPIO_FN_RAC_TXD, RAC_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
- PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
- PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
- PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
- PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
-
- /* PTM (mobule: LBSC, IIC) */
- PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
- PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
- PINMUX_GPIO(GPIO_FN_WE0, WE0_MARK),
- PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
- PINMUX_GPIO(GPIO_FN_SDA6, SDA6_MARK),
- PINMUX_GPIO(GPIO_FN_SCL6, SCL6_MARK),
- PINMUX_GPIO(GPIO_FN_SDA7, SDA7_MARK),
- PINMUX_GPIO(GPIO_FN_SCL7, SCL7_MARK),
-
- /* PTN (mobule: USB, JMC, SGPIO, WDT) */
- PINMUX_GPIO(GPIO_FN_VBUS_EN, VBUS_EN_MARK),
- PINMUX_GPIO(GPIO_FN_VBUS_OC, VBUS_OC_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTCK, JMCTCK_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTMS, JMCTMS_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTDO, JMCTDO_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTDI, JMCTDI_MARK),
- PINMUX_GPIO(GPIO_FN_JMCTRST, JMCTRST_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_CLK, SGPIO1_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_LOAD, SGPIO1_LOAD_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_DI, SGPIO1_DI_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO1_DO, SGPIO1_DO_MARK),
- PINMUX_GPIO(GPIO_FN_SUB_CLKIN, SUB_CLKIN_MARK),
-
- /* PTO (mobule: SGPIO, SerMux) */
- PINMUX_GPIO(GPIO_FN_SGPIO0_CLK, SGPIO0_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO0_LOAD, SGPIO0_LOAD_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO0_DI, SGPIO0_DI_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO0_DO, SGPIO0_DO_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO2_CLK, SGPIO2_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO2_LOAD, SGPIO2_LOAD_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO2_DI, SGPIO2_DI_MARK),
- PINMUX_GPIO(GPIO_FN_SGPIO2_DO, SGPIO2_DO_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_TXD, COM1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_RXD, COM1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_RTS, COM1_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_COM1_CTS, COM1_CTS_MARK),
-
- /* PTP (mobule: EVC, ADC) */
-
- /* PTQ (mobule: LPC) */
- PINMUX_GPIO(GPIO_FN_LAD3, LAD3_MARK),
- PINMUX_GPIO(GPIO_FN_LAD2, LAD2_MARK),
- PINMUX_GPIO(GPIO_FN_LAD1, LAD1_MARK),
- PINMUX_GPIO(GPIO_FN_LAD0, LAD0_MARK),
- PINMUX_GPIO(GPIO_FN_LFRAME, LFRAME_MARK),
- PINMUX_GPIO(GPIO_FN_LRESET, LRESET_MARK),
- PINMUX_GPIO(GPIO_FN_LCLK, LCLK_MARK),
-
- /* PTR (mobule: GRA, IIC) */
- PINMUX_GPIO(GPIO_FN_DDC3, DDC3_MARK),
- PINMUX_GPIO(GPIO_FN_DDC2, DDC2_MARK),
- PINMUX_GPIO(GPIO_FN_SDA8, SDA8_MARK),
- PINMUX_GPIO(GPIO_FN_SCL8, SCL8_MARK),
- PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
- PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
- PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
- PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
- PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
- PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
-
- /* PTS (mobule: GRA, IIC) */
- PINMUX_GPIO(GPIO_FN_DDC1, DDC1_MARK),
- PINMUX_GPIO(GPIO_FN_DDC0, DDC0_MARK),
- PINMUX_GPIO(GPIO_FN_SDA9, SDA9_MARK),
- PINMUX_GPIO(GPIO_FN_SCL9, SCL9_MARK),
- PINMUX_GPIO(GPIO_FN_SDA5, SDA5_MARK),
- PINMUX_GPIO(GPIO_FN_SCL5, SCL5_MARK),
- PINMUX_GPIO(GPIO_FN_SDA4, SDA4_MARK),
- PINMUX_GPIO(GPIO_FN_SCL4, SCL4_MARK),
- PINMUX_GPIO(GPIO_FN_SDA3, SDA3_MARK),
- PINMUX_GPIO(GPIO_FN_SCL3, SCL3_MARK),
-
- /* PTT (mobule: PWMX, AUD) */
- PINMUX_GPIO(GPIO_FN_PWMX7, PWMX7_MARK),
- PINMUX_GPIO(GPIO_FN_PWMX6, PWMX6_MARK),
- PINMUX_GPIO(GPIO_FN_PWMX5, PWMX5_MARK),
- PINMUX_GPIO(GPIO_FN_PWMX4, PWMX4_MARK),
- PINMUX_GPIO(GPIO_FN_PWMX3, PWMX3_MARK),
- PINMUX_GPIO(GPIO_FN_PWMX2, PWMX2_MARK),
- PINMUX_GPIO(GPIO_FN_PWMX1, PWMX1_MARK),
- PINMUX_GPIO(GPIO_FN_PWMX0, PWMX0_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
- PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
-
- /* PTU (mobule: LPC, APM) */
- PINMUX_GPIO(GPIO_FN_LGPIO7, LGPIO7_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO6, LGPIO6_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO5, LGPIO5_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO4, LGPIO4_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO3, LGPIO3_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO2, LGPIO2_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO1, LGPIO1_MARK),
- PINMUX_GPIO(GPIO_FN_LGPIO0, LGPIO0_MARK),
- PINMUX_GPIO(GPIO_FN_APMONCTL_O, APMONCTL_O_MARK),
- PINMUX_GPIO(GPIO_FN_APMPWBTOUT_O, APMPWBTOUT_O_MARK),
- PINMUX_GPIO(GPIO_FN_APMSCI_O, APMSCI_O_MARK),
- PINMUX_GPIO(GPIO_FN_APMVDDON, APMVDDON_MARK),
- PINMUX_GPIO(GPIO_FN_APMSLPBTN, APMSLPBTN_MARK),
- PINMUX_GPIO(GPIO_FN_APMPWRBTN, APMPWRBTN_MARK),
- PINMUX_GPIO(GPIO_FN_APMS5N, APMS5N_MARK),
- PINMUX_GPIO(GPIO_FN_APMS3N, APMS3N_MARK),
-
- /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
- PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
- PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
- PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
- PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
- PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
- PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
- PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
- PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
- PINMUX_GPIO(GPIO_FN_COM2_RI, COM2_RI_MARK),
- PINMUX_GPIO(GPIO_FN_R_SPI_MOSI, R_SPI_MOSI_MARK),
- PINMUX_GPIO(GPIO_FN_R_SPI_MISO, R_SPI_MISO_MARK),
- PINMUX_GPIO(GPIO_FN_R_SPI_RSPCK, R_SPI_RSPCK_MARK),
- PINMUX_GPIO(GPIO_FN_R_SPI_SSL0, R_SPI_SSL0_MARK),
- PINMUX_GPIO(GPIO_FN_R_SPI_SSL1, R_SPI_SSL1_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT7, EVENT7_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT6, EVENT6_MARK),
- PINMUX_GPIO(GPIO_FN_VBIOS_DI, VBIOS_DI_MARK),
- PINMUX_GPIO(GPIO_FN_VBIOS_DO, VBIOS_DO_MARK),
- PINMUX_GPIO(GPIO_FN_VBIOS_CLK, VBIOS_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_VBIOS_CS, VBIOS_CS_MARK),
-
- /* PTW (mobule: LBSC, EVC, SCIF) */
- PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
- PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
- PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
- PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
- PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
- PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
- PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
- PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
- PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT5, EVENT5_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT4, EVENT4_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT3, EVENT3_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT2, EVENT2_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT1, EVENT1_MARK),
- PINMUX_GPIO(GPIO_FN_EVENT0, EVENT0_MARK),
- PINMUX_GPIO(GPIO_FN_CTS4, CTS4_MARK),
- PINMUX_GPIO(GPIO_FN_CTS2, CTS2_MARK),
-
- /* PTX (mobule: LBSC) */
- PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
- PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
- PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
- PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
- PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
- PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
- PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
- PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
- PINMUX_GPIO(GPIO_FN_RTS2, RTS2_MARK),
- PINMUX_GPIO(GPIO_FN_SIM_D, SIM_D_MARK),
- PINMUX_GPIO(GPIO_FN_SIM_CLK, SIM_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SIM_RST, SIM_RST_MARK),
-
- /* PTY (mobule: LBSC) */
- PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
- PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
- PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
- PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
- PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
- PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
- PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
- PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
-
- /* PTZ (mobule: eMMC, ONFI) */
- PINMUX_GPIO(GPIO_FN_MMCDAT7, MMCDAT7_MARK),
- PINMUX_GPIO(GPIO_FN_MMCDAT6, MMCDAT6_MARK),
- PINMUX_GPIO(GPIO_FN_MMCDAT5, MMCDAT5_MARK),
- PINMUX_GPIO(GPIO_FN_MMCDAT4, MMCDAT4_MARK),
- PINMUX_GPIO(GPIO_FN_MMCDAT3, MMCDAT3_MARK),
- PINMUX_GPIO(GPIO_FN_MMCDAT2, MMCDAT2_MARK),
- PINMUX_GPIO(GPIO_FN_MMCDAT1, MMCDAT1_MARK),
- PINMUX_GPIO(GPIO_FN_MMCDAT0, MMCDAT0_MARK),
- PINMUX_GPIO(GPIO_FN_ON_DQ7, ON_DQ7_MARK),
- PINMUX_GPIO(GPIO_FN_ON_DQ6, ON_DQ6_MARK),
- PINMUX_GPIO(GPIO_FN_ON_DQ5, ON_DQ5_MARK),
- PINMUX_GPIO(GPIO_FN_ON_DQ4, ON_DQ4_MARK),
- PINMUX_GPIO(GPIO_FN_ON_DQ3, ON_DQ3_MARK),
- PINMUX_GPIO(GPIO_FN_ON_DQ2, ON_DQ2_MARK),
- PINMUX_GPIO(GPIO_FN_ON_DQ1, ON_DQ1_MARK),
- PINMUX_GPIO(GPIO_FN_ON_DQ0, ON_DQ0_MARK),
- };
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- { PINMUX_CFG_REG("PACR", 0xffec0000, 16, 2) {
- PTA7_FN, PTA7_OUT, PTA7_IN, PTA7_IN_PU,
- PTA6_FN, PTA6_OUT, PTA6_IN, PTA6_IN_PU,
- PTA5_FN, PTA5_OUT, PTA5_IN, PTA5_IN_PU,
- PTA4_FN, PTA4_OUT, PTA4_IN, PTA4_IN_PU,
- PTA3_FN, PTA3_OUT, PTA3_IN, PTA3_IN_PU,
- PTA2_FN, PTA2_OUT, PTA2_IN, PTA2_IN_PU,
- PTA1_FN, PTA1_OUT, PTA1_IN, PTA1_IN_PU,
- PTA0_FN, PTA0_OUT, PTA0_IN, PTA0_IN_PU }
- },
- { PINMUX_CFG_REG("PBCR", 0xffec0002, 16, 2) {
- PTB7_FN, PTB7_OUT, PTB7_IN, 0,
- PTB6_FN, PTB6_OUT, PTB6_IN, 0,
- PTB5_FN, PTB5_OUT, PTB5_IN, 0,
- PTB4_FN, PTB4_OUT, PTB4_IN, 0,
- PTB3_FN, PTB3_OUT, PTB3_IN, 0,
- PTB2_FN, PTB2_OUT, PTB2_IN, 0,
- PTB1_FN, PTB1_OUT, PTB1_IN, 0,
- PTB0_FN, PTB0_OUT, PTB0_IN, 0 }
- },
- { PINMUX_CFG_REG("PCCR", 0xffec0004, 16, 2) {
- PTC7_FN, PTC7_OUT, PTC7_IN, 0,
- PTC6_FN, PTC6_OUT, PTC6_IN, 0,
- PTC5_FN, PTC5_OUT, PTC5_IN, 0,
- PTC4_FN, PTC4_OUT, PTC4_IN, 0,
- PTC3_FN, PTC3_OUT, PTC3_IN, 0,
- PTC2_FN, PTC2_OUT, PTC2_IN, 0,
- PTC1_FN, PTC1_OUT, PTC1_IN, 0,
- PTC0_FN, PTC0_OUT, PTC0_IN, 0 }
- },
- { PINMUX_CFG_REG("PDCR", 0xffec0006, 16, 2) {
- PTD7_FN, PTD7_OUT, PTD7_IN, PTD7_IN_PU,
- PTD6_FN, PTD6_OUT, PTD6_IN, PTD6_IN_PU,
- PTD5_FN, PTD5_OUT, PTD5_IN, PTD5_IN_PU,
- PTD4_FN, PTD4_OUT, PTD4_IN, PTD4_IN_PU,
- PTD3_FN, PTD3_OUT, PTD3_IN, PTD3_IN_PU,
- PTD2_FN, PTD2_OUT, PTD2_IN, PTD2_IN_PU,
- PTD1_FN, PTD1_OUT, PTD1_IN, PTD1_IN_PU,
- PTD0_FN, PTD0_OUT, PTD0_IN, PTD0_IN_PU }
- },
- { PINMUX_CFG_REG("PECR", 0xffec0008, 16, 2) {
- PTE7_FN, PTE7_OUT, PTE7_IN, PTE7_IN_PU,
- PTE6_FN, PTE6_OUT, PTE6_IN, PTE6_IN_PU,
- PTE5_FN, PTE5_OUT, PTE5_IN, PTE5_IN_PU,
- PTE4_FN, PTE4_OUT, PTE4_IN, PTE4_IN_PU,
- PTE3_FN, PTE3_OUT, PTE3_IN, PTE3_IN_PU,
- PTE2_FN, PTE2_OUT, PTE2_IN, PTE2_IN_PU,
- PTE1_FN, PTE1_OUT, PTE1_IN, PTE1_IN_PU,
- PTE0_FN, PTE0_OUT, PTE0_IN, PTE0_IN_PU }
- },
- { PINMUX_CFG_REG("PFCR", 0xffec000a, 16, 2) {
- PTF7_FN, PTF7_OUT, PTF7_IN, PTF7_IN_PU,
- PTF6_FN, PTF6_OUT, PTF6_IN, PTF6_IN_PU,
- PTF5_FN, PTF5_OUT, PTF5_IN, PTF5_IN_PU,
- PTF4_FN, PTF4_OUT, PTF4_IN, PTF4_IN_PU,
- PTF3_FN, PTF3_OUT, PTF3_IN, PTF3_IN_PU,
- PTF2_FN, PTF2_OUT, PTF2_IN, PTF2_IN_PU,
- PTF1_FN, PTF1_OUT, PTF1_IN, PTF1_IN_PU,
- PTF0_FN, PTF0_OUT, PTF0_IN, PTF0_IN_PU }
- },
- { PINMUX_CFG_REG("PGCR", 0xffec000c, 16, 2) {
- PTG7_FN, PTG7_OUT, PTG7_IN, PTG7_IN_PU ,
- PTG6_FN, PTG6_OUT, PTG6_IN, PTG6_IN_PU ,
- PTG5_FN, PTG5_OUT, PTG5_IN, 0,
- PTG4_FN, PTG4_OUT, PTG4_IN, PTG4_IN_PU ,
- PTG3_FN, PTG3_OUT, PTG3_IN, 0,
- PTG2_FN, PTG2_OUT, PTG2_IN, 0,
- PTG1_FN, PTG1_OUT, PTG1_IN, 0,
- PTG0_FN, PTG0_OUT, PTG0_IN, 0 }
- },
- { PINMUX_CFG_REG("PHCR", 0xffec000e, 16, 2) {
- PTH7_FN, PTH7_OUT, PTH7_IN, PTH7_IN_PU,
- PTH6_FN, PTH6_OUT, PTH6_IN, PTH6_IN_PU,
- PTH5_FN, PTH5_OUT, PTH5_IN, PTH5_IN_PU,
- PTH4_FN, PTH4_OUT, PTH4_IN, PTH4_IN_PU,
- PTH3_FN, PTH3_OUT, PTH3_IN, PTH3_IN_PU,
- PTH2_FN, PTH2_OUT, PTH2_IN, PTH2_IN_PU,
- PTH1_FN, PTH1_OUT, PTH1_IN, PTH1_IN_PU,
- PTH0_FN, PTH0_OUT, PTH0_IN, PTH0_IN_PU }
- },
- { PINMUX_CFG_REG("PICR", 0xffec0010, 16, 2) {
- PTI7_FN, PTI7_OUT, PTI7_IN, PTI7_IN_PU,
- PTI6_FN, PTI6_OUT, PTI6_IN, PTI6_IN_PU,
- PTI5_FN, PTI5_OUT, PTI5_IN, 0,
- PTI4_FN, PTI4_OUT, PTI4_IN, PTI4_IN_PU,
- PTI3_FN, PTI3_OUT, PTI3_IN, PTI3_IN_PU,
- PTI2_FN, PTI2_OUT, PTI2_IN, PTI2_IN_PU,
- PTI1_FN, PTI1_OUT, PTI1_IN, PTI1_IN_PU,
- PTI0_FN, PTI0_OUT, PTI0_IN, PTI0_IN_PU }
- },
- { PINMUX_CFG_REG("PJCR", 0xffec0012, 16, 2) {
- 0, 0, 0, 0, /* reserved: always set 1 */
- PTJ6_FN, PTJ6_OUT, PTJ6_IN, PTJ6_IN_PU,
- PTJ5_FN, PTJ5_OUT, PTJ5_IN, PTJ5_IN_PU,
- PTJ4_FN, PTJ4_OUT, PTJ4_IN, PTJ4_IN_PU,
- PTJ3_FN, PTJ3_OUT, PTJ3_IN, PTJ3_IN_PU,
- PTJ2_FN, PTJ2_OUT, PTJ2_IN, PTJ2_IN_PU,
- PTJ1_FN, PTJ1_OUT, PTJ1_IN, PTJ1_IN_PU,
- PTJ0_FN, PTJ0_OUT, PTJ0_IN, PTJ0_IN_PU }
- },
- { PINMUX_CFG_REG("PKCR", 0xffec0014, 16, 2) {
- PTK7_FN, PTK7_OUT, PTK7_IN, PTK7_IN_PU,
- PTK6_FN, PTK6_OUT, PTK6_IN, PTK6_IN_PU,
- PTK5_FN, PTK5_OUT, PTK5_IN, PTK5_IN_PU,
- PTK4_FN, PTK4_OUT, PTK4_IN, PTK4_IN_PU,
- PTK3_FN, PTK3_OUT, PTK3_IN, PTK3_IN_PU,
- PTK2_FN, PTK2_OUT, PTK2_IN, PTK2_IN_PU,
- PTK1_FN, PTK1_OUT, PTK1_IN, PTK1_IN_PU,
- PTK0_FN, PTK0_OUT, PTK0_IN, PTK0_IN_PU }
- },
- { PINMUX_CFG_REG("PLCR", 0xffec0016, 16, 2) {
- 0, 0, 0, 0, /* reserved: always set 1 */
- PTL6_FN, PTL6_OUT, PTL6_IN, PTL6_IN_PU,
- PTL5_FN, PTL5_OUT, PTL5_IN, PTL5_IN_PU,
- PTL4_FN, PTL4_OUT, PTL4_IN, PTL4_IN_PU,
- PTL3_FN, PTL3_OUT, PTL3_IN, PTL3_IN_PU,
- PTL2_FN, PTL2_OUT, PTL2_IN, PTL2_IN_PU,
- PTL1_FN, PTL1_OUT, PTL1_IN, PTL1_IN_PU,
- PTL0_FN, PTL0_OUT, PTL0_IN, PTL0_IN_PU }
- },
- { PINMUX_CFG_REG("PMCR", 0xffec0018, 16, 2) {
- PTM7_FN, PTM7_OUT, PTM7_IN, PTM7_IN_PU,
- PTM6_FN, PTM6_OUT, PTM6_IN, PTM6_IN_PU,
- PTM5_FN, PTM5_OUT, PTM5_IN, PTM5_IN_PU,
- PTM4_FN, PTM4_OUT, PTM4_IN, PTM4_IN_PU,
- PTM3_FN, PTM3_OUT, PTM3_IN, 0,
- PTM2_FN, PTM2_OUT, PTM2_IN, 0,
- PTM1_FN, PTM1_OUT, PTM1_IN, 0,
- PTM0_FN, PTM0_OUT, PTM0_IN, 0 }
- },
- { PINMUX_CFG_REG("PNCR", 0xffec001a, 16, 2) {
- 0, 0, 0, 0, /* reserved: always set 1 */
- PTN6_FN, PTN6_OUT, PTN6_IN, 0,
- PTN5_FN, PTN5_OUT, PTN5_IN, 0,
- PTN4_FN, PTN4_OUT, PTN4_IN, PTN4_IN_PU,
- PTN3_FN, PTN3_OUT, PTN3_IN, PTN3_IN_PU,
- PTN2_FN, PTN2_OUT, PTN2_IN, PTN2_IN_PU,
- PTN1_FN, PTN1_OUT, PTN1_IN, PTN1_IN_PU,
- PTN0_FN, PTN0_OUT, PTN0_IN, PTN0_IN_PU }
- },
- { PINMUX_CFG_REG("POCR", 0xffec001c, 16, 2) {
- PTO7_FN, PTO7_OUT, PTO7_IN, PTO7_IN_PU,
- PTO6_FN, PTO6_OUT, PTO6_IN, PTO6_IN_PU,
- PTO5_FN, PTO5_OUT, PTO5_IN, PTO5_IN_PU,
- PTO4_FN, PTO4_OUT, PTO4_IN, PTO4_IN_PU,
- PTO3_FN, PTO3_OUT, PTO3_IN, PTO3_IN_PU,
- PTO2_FN, PTO2_OUT, PTO2_IN, PTO2_IN_PU,
- PTO1_FN, PTO1_OUT, PTO1_IN, PTO1_IN_PU,
- PTO0_FN, PTO0_OUT, PTO0_IN, PTO0_IN_PU }
- },
-#if 0 /* FIXME: Remove it? */
- { PINMUX_CFG_REG("PPCR", 0xffec001e, 16, 2) {
- 0, 0, 0, 0, /* reserved: always set 1 */
- PTP6_FN, PTP6_OUT, PTP6_IN, 0,
- PTP5_FN, PTP5_OUT, PTP5_IN, 0,
- PTP4_FN, PTP4_OUT, PTP4_IN, 0,
- PTP3_FN, PTP3_OUT, PTP3_IN, 0,
- PTP2_FN, PTP2_OUT, PTP2_IN, 0,
- PTP1_FN, PTP1_OUT, PTP1_IN, 0,
- PTP0_FN, PTP0_OUT, PTP0_IN, 0 }
- },
-#endif
- { PINMUX_CFG_REG("PQCR", 0xffec0020, 16, 2) {
- 0, 0, 0, 0, /* reserved: always set 1 */
- PTQ6_FN, PTQ6_OUT, PTQ6_IN, 0,
- PTQ5_FN, PTQ5_OUT, PTQ5_IN, 0,
- PTQ4_FN, PTQ4_OUT, PTQ4_IN, 0,
- PTQ3_FN, PTQ3_OUT, PTQ3_IN, 0,
- PTQ2_FN, PTQ2_OUT, PTQ2_IN, 0,
- PTQ1_FN, PTQ1_OUT, PTQ1_IN, 0,
- PTQ0_FN, PTQ0_OUT, PTQ0_IN, 0 }
- },
- { PINMUX_CFG_REG("PRCR", 0xffec0022, 16, 2) {
- PTR7_FN, PTR7_OUT, PTR7_IN, 0,
- PTR6_FN, PTR6_OUT, PTR6_IN, 0,
- PTR5_FN, PTR5_OUT, PTR5_IN, 0,
- PTR4_FN, PTR4_OUT, PTR4_IN, 0,
- PTR3_FN, PTR3_OUT, PTR3_IN, 0,
- PTR2_FN, PTR2_OUT, PTR2_IN, 0,
- PTR1_FN, PTR1_OUT, PTR1_IN, 0,
- PTR0_FN, PTR0_OUT, PTR0_IN, 0 }
- },
- { PINMUX_CFG_REG("PSCR", 0xffec0024, 16, 2) {
- PTS7_FN, PTS7_OUT, PTS7_IN, 0,
- PTS6_FN, PTS6_OUT, PTS6_IN, 0,
- PTS5_FN, PTS5_OUT, PTS5_IN, 0,
- PTS4_FN, PTS4_OUT, PTS4_IN, 0,
- PTS3_FN, PTS3_OUT, PTS3_IN, 0,
- PTS2_FN, PTS2_OUT, PTS2_IN, 0,
- PTS1_FN, PTS1_OUT, PTS1_IN, 0,
- PTS0_FN, PTS0_OUT, PTS0_IN, 0 }
- },
- { PINMUX_CFG_REG("PTCR", 0xffec0026, 16, 2) {
- PTT7_FN, PTT7_OUT, PTT7_IN, PTO7_IN_PU,
- PTT6_FN, PTT6_OUT, PTT6_IN, PTO6_IN_PU,
- PTT5_FN, PTT5_OUT, PTT5_IN, PTO5_IN_PU,
- PTT4_FN, PTT4_OUT, PTT4_IN, PTO4_IN_PU,
- PTT3_FN, PTT3_OUT, PTT3_IN, PTO3_IN_PU,
- PTT2_FN, PTT2_OUT, PTT2_IN, PTO2_IN_PU,
- PTT1_FN, PTT1_OUT, PTT1_IN, PTO1_IN_PU,
- PTT0_FN, PTT0_OUT, PTT0_IN, PTO0_IN_PU }
- },
- { PINMUX_CFG_REG("PUCR", 0xffec0028, 16, 2) {
- PTU7_FN, PTU7_OUT, PTU7_IN, PTU7_IN_PU,
- PTU6_FN, PTU6_OUT, PTU6_IN, PTU6_IN_PU,
- PTU5_FN, PTU5_OUT, PTU5_IN, PTU5_IN_PU,
- PTU4_FN, PTU4_OUT, PTU4_IN, PTU4_IN_PU,
- PTU3_FN, PTU3_OUT, PTU3_IN, PTU3_IN_PU,
- PTU2_FN, PTU2_OUT, PTU2_IN, PTU2_IN_PU,
- PTU1_FN, PTU1_OUT, PTU1_IN, PTU1_IN_PU,
- PTU0_FN, PTU0_OUT, PTU0_IN, PTU0_IN_PU }
- },
- { PINMUX_CFG_REG("PVCR", 0xffec002a, 16, 2) {
- PTV7_FN, PTV7_OUT, PTV7_IN, PTV7_IN_PU,
- PTV6_FN, PTV6_OUT, PTV6_IN, PTV6_IN_PU,
- PTV5_FN, PTV5_OUT, PTV5_IN, PTV5_IN_PU,
- PTV4_FN, PTV4_OUT, PTV4_IN, PTV4_IN_PU,
- PTV3_FN, PTV3_OUT, PTV3_IN, PTV3_IN_PU,
- PTV2_FN, PTV2_OUT, PTV2_IN, PTV2_IN_PU,
- PTV1_FN, PTV1_OUT, PTV1_IN, 0,
- PTV0_FN, PTV0_OUT, PTV0_IN, 0 }
- },
- { PINMUX_CFG_REG("PWCR", 0xffec002c, 16, 2) {
- PTW7_FN, PTW7_OUT, PTW7_IN, 0,
- PTW6_FN, PTW6_OUT, PTW6_IN, 0,
- PTW5_FN, PTW5_OUT, PTW5_IN, 0,
- PTW4_FN, PTW4_OUT, PTW4_IN, 0,
- PTW3_FN, PTW3_OUT, PTW3_IN, 0,
- PTW2_FN, PTW2_OUT, PTW2_IN, 0,
- PTW1_FN, PTW1_OUT, PTW1_IN, PTW1_IN_PU,
- PTW0_FN, PTW0_OUT, PTW0_IN, PTW0_IN_PU }
- },
- { PINMUX_CFG_REG("PXCR", 0xffec002e, 16, 2) {
- PTX7_FN, PTX7_OUT, PTX7_IN, PTX7_IN_PU,
- PTX6_FN, PTX6_OUT, PTX6_IN, PTX6_IN_PU,
- PTX5_FN, PTX5_OUT, PTX5_IN, PTX5_IN_PU,
- PTX4_FN, PTX4_OUT, PTX4_IN, PTX4_IN_PU,
- PTX3_FN, PTX3_OUT, PTX3_IN, PTX3_IN_PU,
- PTX2_FN, PTX2_OUT, PTX2_IN, PTX2_IN_PU,
- PTX1_FN, PTX1_OUT, PTX1_IN, PTX1_IN_PU,
- PTX0_FN, PTX0_OUT, PTX0_IN, PTX0_IN_PU }
- },
- { PINMUX_CFG_REG("PYCR", 0xffec0030, 16, 2) {
- PTY7_FN, PTY7_OUT, PTY7_IN, PTY7_IN_PU,
- PTY6_FN, PTY6_OUT, PTY6_IN, PTY6_IN_PU,
- PTY5_FN, PTY5_OUT, PTY5_IN, PTY5_IN_PU,
- PTY4_FN, PTY4_OUT, PTY4_IN, PTY4_IN_PU,
- PTY3_FN, PTY3_OUT, PTY3_IN, PTY3_IN_PU,
- PTY2_FN, PTY2_OUT, PTY2_IN, PTY2_IN_PU,
- PTY1_FN, PTY1_OUT, PTY1_IN, PTY1_IN_PU,
- PTY0_FN, PTY0_OUT, PTY0_IN, PTY0_IN_PU }
- },
- { PINMUX_CFG_REG("PZCR", 0xffec0032, 16, 2) {
- PTZ7_FN, PTZ7_OUT, PTZ7_IN, 0,
- PTZ6_FN, PTZ6_OUT, PTZ6_IN, 0,
- PTZ5_FN, PTZ5_OUT, PTZ5_IN, 0,
- PTZ4_FN, PTZ4_OUT, PTZ4_IN, 0,
- PTZ3_FN, PTZ3_OUT, PTZ3_IN, 0,
- PTZ2_FN, PTZ2_OUT, PTZ2_IN, 0,
- PTZ1_FN, PTZ1_OUT, PTZ1_IN, 0,
- PTZ0_FN, PTZ0_OUT, PTZ0_IN, 0 }
- },
-
- { PINMUX_CFG_REG("PSEL0", 0xffec0070, 16, 1) {
- PS0_15_FN1, PS0_15_FN2,
- PS0_14_FN1, PS0_14_FN2,
- PS0_13_FN1, PS0_13_FN2,
- PS0_12_FN1, PS0_12_FN2,
- PS0_11_FN1, PS0_11_FN2,
- PS0_10_FN1, PS0_10_FN2,
- PS0_9_FN1, PS0_9_FN2,
- PS0_8_FN1, PS0_8_FN2,
- PS0_7_FN1, PS0_7_FN2,
- PS0_6_FN1, PS0_6_FN2,
- PS0_5_FN1, PS0_5_FN2,
- PS0_4_FN1, PS0_4_FN2,
- PS0_3_FN1, PS0_3_FN2,
- PS0_2_FN1, PS0_2_FN2,
- 0, 0,
- 0, 0, }
- },
- { PINMUX_CFG_REG("PSEL1", 0xffec0072, 16, 1) {
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- PS1_10_FN1, PS1_10_FN2,
- PS1_9_FN1, PS1_9_FN2,
- PS1_8_FN1, PS1_8_FN2,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- PS1_2_FN1, PS1_2_FN2,
- 0, 0,
- 0, 0, }
- },
- { PINMUX_CFG_REG("PSEL2", 0xffec0074, 16, 1) {
- 0, 0,
- 0, 0,
- PS2_13_FN1, PS2_13_FN2,
- PS2_12_FN1, PS2_12_FN2,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- PS2_7_FN1, PS2_7_FN2,
- PS2_6_FN1, PS2_6_FN2,
- PS2_5_FN1, PS2_5_FN2,
- PS2_4_FN1, PS2_4_FN2,
- 0, 0,
- PS2_2_FN1, PS2_2_FN2,
- 0, 0,
- 0, 0, }
- },
- { PINMUX_CFG_REG("PSEL3", 0xffec0076, 16, 1) {
- PS3_15_FN1, PS3_15_FN2,
- PS3_14_FN1, PS3_14_FN2,
- PS3_13_FN1, PS3_13_FN2,
- PS3_12_FN1, PS3_12_FN2,
- PS3_11_FN1, PS3_11_FN2,
- PS3_10_FN1, PS3_10_FN2,
- PS3_9_FN1, PS3_9_FN2,
- PS3_8_FN1, PS3_8_FN2,
- PS3_7_FN1, PS3_7_FN2,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- PS3_2_FN1, PS3_2_FN2,
- PS3_1_FN1, PS3_1_FN2,
- 0, 0, }
- },
-
- { PINMUX_CFG_REG("PSEL4", 0xffec0078, 16, 1) {
- 0, 0,
- PS4_14_FN1, PS4_14_FN2,
- PS4_13_FN1, PS4_13_FN2,
- PS4_12_FN1, PS4_12_FN2,
- 0, 0,
- PS4_10_FN1, PS4_10_FN2,
- PS4_9_FN1, PS4_9_FN2,
- PS4_8_FN1, PS4_8_FN2,
- 0, 0,
- 0, 0,
- 0, 0,
- PS4_4_FN1, PS4_4_FN2,
- PS4_3_FN1, PS4_3_FN2,
- PS4_2_FN1, PS4_2_FN2,
- PS4_1_FN1, PS4_1_FN2,
- PS4_0_FN1, PS4_0_FN2, }
- },
- { PINMUX_CFG_REG("PSEL5", 0xffec007a, 16, 1) {
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- PS5_11_FN1, PS5_11_FN2,
- PS5_10_FN1, PS5_10_FN2,
- PS5_9_FN1, PS5_9_FN2,
- PS5_8_FN1, PS5_8_FN2,
- PS5_7_FN1, PS5_7_FN2,
- PS5_6_FN1, PS5_6_FN2,
- PS5_5_FN1, PS5_5_FN2,
- PS5_4_FN1, PS5_4_FN2,
- PS5_3_FN1, PS5_3_FN2,
- PS5_2_FN1, PS5_2_FN2,
- 0, 0,
- 0, 0, }
- },
- { PINMUX_CFG_REG("PSEL6", 0xffec007c, 16, 1) {
- PS6_15_FN1, PS6_15_FN2,
- PS6_14_FN1, PS6_14_FN2,
- PS6_13_FN1, PS6_13_FN2,
- PS6_12_FN1, PS6_12_FN2,
- PS6_11_FN1, PS6_11_FN2,
- PS6_10_FN1, PS6_10_FN2,
- PS6_9_FN1, PS6_9_FN2,
- PS6_8_FN1, PS6_8_FN2,
- PS6_7_FN1, PS6_7_FN2,
- PS6_6_FN1, PS6_6_FN2,
- PS6_5_FN1, PS6_5_FN2,
- PS6_4_FN1, PS6_4_FN2,
- PS6_3_FN1, PS6_3_FN2,
- PS6_2_FN1, PS6_2_FN2,
- PS6_1_FN1, PS6_1_FN2,
- PS6_0_FN1, PS6_0_FN2, }
- },
- { PINMUX_CFG_REG("PSEL7", 0xffec0082, 16, 1) {
- PS7_15_FN1, PS7_15_FN2,
- PS7_14_FN1, PS7_14_FN2,
- PS7_13_FN1, PS7_13_FN2,
- PS7_12_FN1, PS7_12_FN2,
- PS7_11_FN1, PS7_11_FN2,
- PS7_10_FN1, PS7_10_FN2,
- PS7_9_FN1, PS7_9_FN2,
- PS7_8_FN1, PS7_8_FN2,
- PS7_7_FN1, PS7_7_FN2,
- PS7_6_FN1, PS7_6_FN2,
- PS7_5_FN1, PS7_5_FN2,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0, }
- },
- { PINMUX_CFG_REG("PSEL8", 0xffec0084, 16, 1) {
- PS8_15_FN1, PS8_15_FN2,
- PS8_14_FN1, PS8_14_FN2,
- PS8_13_FN1, PS8_13_FN2,
- PS8_12_FN1, PS8_12_FN2,
- PS8_11_FN1, PS8_11_FN2,
- PS8_10_FN1, PS8_10_FN2,
- PS8_9_FN1, PS8_9_FN2,
- PS8_8_FN1, PS8_8_FN2,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0, }
- },
- {}
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PADR", 0xffec0034, 8) {
- PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
- PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
- },
- { PINMUX_DATA_REG("PBDR", 0xffec0036, 8) {
- PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
- PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
- },
- { PINMUX_DATA_REG("PCDR", 0xffec0038, 8) {
- PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
- PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA }
- },
- { PINMUX_DATA_REG("PDDR", 0xffec003a, 8) {
- PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
- PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
- },
- { PINMUX_DATA_REG("PEDR", 0xffec003c, 8) {
- PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
- PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA }
- },
- { PINMUX_DATA_REG("PFDR", 0xffec003e, 8) {
- PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
- PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
- },
- { PINMUX_DATA_REG("PGDR", 0xffec0040, 8) {
- PTG7_DATA, PTG6_DATA, PTG5_DATA, PTG4_DATA,
- PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
- },
- { PINMUX_DATA_REG("PHDR", 0xffec0042, 8) {
- PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
- PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
- },
- { PINMUX_DATA_REG("PIDR", 0xffec0044, 8) {
- PTI7_DATA, PTI6_DATA, PTI5_DATA, PTI4_DATA,
- PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA }
- },
- { PINMUX_DATA_REG("PJDR", 0xffec0046, 8) {
- 0, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
- PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
- },
- { PINMUX_DATA_REG("PKDR", 0xffec0048, 8) {
- PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
- PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
- },
- { PINMUX_DATA_REG("PLDR", 0xffec004a, 8) {
- 0, PTL6_DATA, PTL5_DATA, PTL4_DATA,
- PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
- },
- { PINMUX_DATA_REG("PMDR", 0xffec004c, 8) {
- PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
- PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
- },
- { PINMUX_DATA_REG("PNDR", 0xffec004e, 8) {
- 0, PTN6_DATA, PTN5_DATA, PTN4_DATA,
- PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
- },
- { PINMUX_DATA_REG("PODR", 0xffec0050, 8) {
- PTO7_DATA, PTO6_DATA, PTO5_DATA, PTO4_DATA,
- PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA }
- },
- { PINMUX_DATA_REG("PPDR", 0xffec0052, 8) {
- PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
- PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA }
- },
- { PINMUX_DATA_REG("PQDR", 0xffec0054, 8) {
- 0, PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
- PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA }
- },
- { PINMUX_DATA_REG("PRDR", 0xffec0056, 8) {
- PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
- PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
- },
- { PINMUX_DATA_REG("PSDR", 0xffec0058, 8) {
- PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
- PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
- },
- { PINMUX_DATA_REG("PTDR", 0xffec005a, 8) {
- PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
- PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
- },
- { PINMUX_DATA_REG("PUDR", 0xffec005c, 8) {
- PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
- PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
- },
- { PINMUX_DATA_REG("PVDR", 0xffec005e, 8) {
- PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
- PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
- },
- { PINMUX_DATA_REG("PWDR", 0xffec0060, 8) {
- PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
- PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA }
- },
- { PINMUX_DATA_REG("PXDR", 0xffec0062, 8) {
- PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
- PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA }
- },
- { PINMUX_DATA_REG("PYDR", 0xffec0064, 8) {
- PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
- PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA }
- },
- { PINMUX_DATA_REG("PZDR", 0xffec0066, 8) {
- PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
- PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA }
- },
- { },
-};
-
-static struct pinmux_info sh7757_pinmux_info = {
- .name = "sh7757_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
- .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_PTA0,
- .last_gpio = GPIO_FN_ON_DQ0,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
+#include <cpu/pfc.h>
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7757_pinmux_info);
+ return sh_pfc_register("pfc-sh7757", NULL, 0);
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7785.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7785.c
index 5ebc25fd9b2a..01055b809f64 100644
--- a/arch/sh/kernel/cpu/sh4a/pinmux-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7785.c
@@ -10,1301 +10,11 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/sh7785.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
- PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
- PE5_DATA, PE4_DATA, PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
- PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
- PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
- PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
- PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
- PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
- PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
- PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
- PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA,
- PL7_DATA, PL6_DATA, PL5_DATA, PL4_DATA,
- PL3_DATA, PL2_DATA, PL1_DATA, PL0_DATA,
- PM1_DATA, PM0_DATA,
- PN7_DATA, PN6_DATA, PN5_DATA, PN4_DATA,
- PN3_DATA, PN2_DATA, PN1_DATA, PN0_DATA,
- PP5_DATA, PP4_DATA, PP3_DATA, PP2_DATA, PP1_DATA, PP0_DATA,
- PQ4_DATA, PQ3_DATA, PQ2_DATA, PQ1_DATA, PQ0_DATA,
- PR3_DATA, PR2_DATA, PR1_DATA, PR0_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- PA7_IN, PA6_IN, PA5_IN, PA4_IN,
- PA3_IN, PA2_IN, PA1_IN, PA0_IN,
- PB7_IN, PB6_IN, PB5_IN, PB4_IN,
- PB3_IN, PB2_IN, PB1_IN, PB0_IN,
- PC7_IN, PC6_IN, PC5_IN, PC4_IN,
- PC3_IN, PC2_IN, PC1_IN, PC0_IN,
- PD7_IN, PD6_IN, PD5_IN, PD4_IN,
- PD3_IN, PD2_IN, PD1_IN, PD0_IN,
- PE5_IN, PE4_IN, PE3_IN, PE2_IN, PE1_IN, PE0_IN,
- PF7_IN, PF6_IN, PF5_IN, PF4_IN,
- PF3_IN, PF2_IN, PF1_IN, PF0_IN,
- PG7_IN, PG6_IN, PG5_IN, PG4_IN,
- PG3_IN, PG2_IN, PG1_IN, PG0_IN,
- PH7_IN, PH6_IN, PH5_IN, PH4_IN,
- PH3_IN, PH2_IN, PH1_IN, PH0_IN,
- PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
- PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
- PK7_IN, PK6_IN, PK5_IN, PK4_IN,
- PK3_IN, PK2_IN, PK1_IN, PK0_IN,
- PL7_IN, PL6_IN, PL5_IN, PL4_IN,
- PL3_IN, PL2_IN, PL1_IN, PL0_IN,
- PM1_IN, PM0_IN,
- PN7_IN, PN6_IN, PN5_IN, PN4_IN,
- PN3_IN, PN2_IN, PN1_IN, PN0_IN,
- PP5_IN, PP4_IN, PP3_IN, PP2_IN, PP1_IN, PP0_IN,
- PQ4_IN, PQ3_IN, PQ2_IN, PQ1_IN, PQ0_IN,
- PR3_IN, PR2_IN, PR1_IN, PR0_IN,
- PINMUX_INPUT_END,
-
- PINMUX_INPUT_PULLUP_BEGIN,
- PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
- PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
- PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
- PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
- PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
- PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
- PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
- PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
- PE5_IN_PU, PE4_IN_PU, PE3_IN_PU, PE2_IN_PU, PE1_IN_PU, PE0_IN_PU,
- PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
- PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
- PG7_IN_PU, PG6_IN_PU, PG5_IN_PU, PG4_IN_PU,
- PG3_IN_PU, PG2_IN_PU, PG1_IN_PU, PG0_IN_PU,
- PH7_IN_PU, PH6_IN_PU, PH5_IN_PU, PH4_IN_PU,
- PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
- PJ7_IN_PU, PJ6_IN_PU, PJ5_IN_PU, PJ4_IN_PU,
- PJ3_IN_PU, PJ2_IN_PU, PJ1_IN_PU, PJ0_IN_PU,
- PK7_IN_PU, PK6_IN_PU, PK5_IN_PU, PK4_IN_PU,
- PK3_IN_PU, PK2_IN_PU, PK1_IN_PU, PK0_IN_PU,
- PL7_IN_PU, PL6_IN_PU, PL5_IN_PU, PL4_IN_PU,
- PL3_IN_PU, PL2_IN_PU, PL1_IN_PU, PL0_IN_PU,
- PM1_IN_PU, PM0_IN_PU,
- PN7_IN_PU, PN6_IN_PU, PN5_IN_PU, PN4_IN_PU,
- PN3_IN_PU, PN2_IN_PU, PN1_IN_PU, PN0_IN_PU,
- PP5_IN_PU, PP4_IN_PU, PP3_IN_PU, PP2_IN_PU, PP1_IN_PU, PP0_IN_PU,
- PQ4_IN_PU, PQ3_IN_PU, PQ2_IN_PU, PQ1_IN_PU, PQ0_IN_PU,
- PR3_IN_PU, PR2_IN_PU, PR1_IN_PU, PR0_IN_PU,
- PINMUX_INPUT_PULLUP_END,
-
- PINMUX_OUTPUT_BEGIN,
- PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
- PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
- PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
- PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
- PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
- PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
- PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
- PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
- PE5_OUT, PE4_OUT, PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
- PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
- PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
- PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
- PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
- PH7_OUT, PH6_OUT, PH5_OUT, PH4_OUT,
- PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
- PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
- PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
- PK7_OUT, PK6_OUT, PK5_OUT, PK4_OUT,
- PK3_OUT, PK2_OUT, PK1_OUT, PK0_OUT,
- PL7_OUT, PL6_OUT, PL5_OUT, PL4_OUT,
- PL3_OUT, PL2_OUT, PL1_OUT, PL0_OUT,
- PM1_OUT, PM0_OUT,
- PN7_OUT, PN6_OUT, PN5_OUT, PN4_OUT,
- PN3_OUT, PN2_OUT, PN1_OUT, PN0_OUT,
- PP5_OUT, PP4_OUT, PP3_OUT, PP2_OUT, PP1_OUT, PP0_OUT,
- PQ4_OUT, PQ3_OUT, PQ2_OUT, PQ1_OUT, PQ0_OUT,
- PR3_OUT, PR2_OUT, PR1_OUT, PR0_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- PA7_FN, PA6_FN, PA5_FN, PA4_FN,
- PA3_FN, PA2_FN, PA1_FN, PA0_FN,
- PB7_FN, PB6_FN, PB5_FN, PB4_FN,
- PB3_FN, PB2_FN, PB1_FN, PB0_FN,
- PC7_FN, PC6_FN, PC5_FN, PC4_FN,
- PC3_FN, PC2_FN, PC1_FN, PC0_FN,
- PD7_FN, PD6_FN, PD5_FN, PD4_FN,
- PD3_FN, PD2_FN, PD1_FN, PD0_FN,
- PE5_FN, PE4_FN, PE3_FN, PE2_FN, PE1_FN, PE0_FN,
- PF7_FN, PF6_FN, PF5_FN, PF4_FN,
- PF3_FN, PF2_FN, PF1_FN, PF0_FN,
- PG7_FN, PG6_FN, PG5_FN, PG4_FN,
- PG3_FN, PG2_FN, PG1_FN, PG0_FN,
- PH7_FN, PH6_FN, PH5_FN, PH4_FN,
- PH3_FN, PH2_FN, PH1_FN, PH0_FN,
- PJ7_FN, PJ6_FN, PJ5_FN, PJ4_FN,
- PJ3_FN, PJ2_FN, PJ1_FN, PJ0_FN,
- PK7_FN, PK6_FN, PK5_FN, PK4_FN,
- PK3_FN, PK2_FN, PK1_FN, PK0_FN,
- PL7_FN, PL6_FN, PL5_FN, PL4_FN,
- PL3_FN, PL2_FN, PL1_FN, PL0_FN,
- PM1_FN, PM0_FN,
- PN7_FN, PN6_FN, PN5_FN, PN4_FN,
- PN3_FN, PN2_FN, PN1_FN, PN0_FN,
- PP5_FN, PP4_FN, PP3_FN, PP2_FN, PP1_FN, PP0_FN,
- PQ4_FN, PQ3_FN, PQ2_FN, PQ1_FN, PQ0_FN,
- PR3_FN, PR2_FN, PR1_FN, PR0_FN,
- P1MSEL15_0, P1MSEL15_1,
- P1MSEL14_0, P1MSEL14_1,
- P1MSEL13_0, P1MSEL13_1,
- P1MSEL12_0, P1MSEL12_1,
- P1MSEL11_0, P1MSEL11_1,
- P1MSEL10_0, P1MSEL10_1,
- P1MSEL9_0, P1MSEL9_1,
- P1MSEL8_0, P1MSEL8_1,
- P1MSEL7_0, P1MSEL7_1,
- P1MSEL6_0, P1MSEL6_1,
- P1MSEL5_0,
- P1MSEL4_0, P1MSEL4_1,
- P1MSEL3_0, P1MSEL3_1,
- P1MSEL2_0, P1MSEL2_1,
- P1MSEL1_0, P1MSEL1_1,
- P1MSEL0_0, P1MSEL0_1,
- P2MSEL2_0, P2MSEL2_1,
- P2MSEL1_0, P2MSEL1_1,
- P2MSEL0_0, P2MSEL0_1,
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
- D63_AD31_MARK,
- D62_AD30_MARK,
- D61_AD29_MARK,
- D60_AD28_MARK,
- D59_AD27_MARK,
- D58_AD26_MARK,
- D57_AD25_MARK,
- D56_AD24_MARK,
- D55_AD23_MARK,
- D54_AD22_MARK,
- D53_AD21_MARK,
- D52_AD20_MARK,
- D51_AD19_MARK,
- D50_AD18_MARK,
- D49_AD17_DB5_MARK,
- D48_AD16_DB4_MARK,
- D47_AD15_DB3_MARK,
- D46_AD14_DB2_MARK,
- D45_AD13_DB1_MARK,
- D44_AD12_DB0_MARK,
- D43_AD11_DG5_MARK,
- D42_AD10_DG4_MARK,
- D41_AD9_DG3_MARK,
- D40_AD8_DG2_MARK,
- D39_AD7_DG1_MARK,
- D38_AD6_DG0_MARK,
- D37_AD5_DR5_MARK,
- D36_AD4_DR4_MARK,
- D35_AD3_DR3_MARK,
- D34_AD2_DR2_MARK,
- D33_AD1_DR1_MARK,
- D32_AD0_DR0_MARK,
- REQ1_MARK,
- REQ2_MARK,
- REQ3_MARK,
- GNT1_MARK,
- GNT2_MARK,
- GNT3_MARK,
- MMCCLK_MARK,
- D31_MARK,
- D30_MARK,
- D29_MARK,
- D28_MARK,
- D27_MARK,
- D26_MARK,
- D25_MARK,
- D24_MARK,
- D23_MARK,
- D22_MARK,
- D21_MARK,
- D20_MARK,
- D19_MARK,
- D18_MARK,
- D17_MARK,
- D16_MARK,
- SCIF1_SCK_MARK,
- SCIF1_RXD_MARK,
- SCIF1_TXD_MARK,
- SCIF0_CTS_MARK,
- INTD_MARK,
- FCE_MARK,
- SCIF0_RTS_MARK,
- HSPI_CS_MARK,
- FSE_MARK,
- SCIF0_SCK_MARK,
- HSPI_CLK_MARK,
- FRE_MARK,
- SCIF0_RXD_MARK,
- HSPI_RX_MARK,
- FRB_MARK,
- SCIF0_TXD_MARK,
- HSPI_TX_MARK,
- FWE_MARK,
- SCIF5_TXD_MARK,
- HAC1_SYNC_MARK,
- SSI1_WS_MARK,
- SIOF_TXD_PJ_MARK,
- HAC0_SDOUT_MARK,
- SSI0_SDATA_MARK,
- SIOF_RXD_PJ_MARK,
- HAC0_SDIN_MARK,
- SSI0_SCK_MARK,
- SIOF_SYNC_PJ_MARK,
- HAC0_SYNC_MARK,
- SSI0_WS_MARK,
- SIOF_MCLK_PJ_MARK,
- HAC_RES_MARK,
- SIOF_SCK_PJ_MARK,
- HAC0_BITCLK_MARK,
- SSI0_CLK_MARK,
- HAC1_BITCLK_MARK,
- SSI1_CLK_MARK,
- TCLK_MARK,
- IOIS16_MARK,
- STATUS0_MARK,
- DRAK0_PK3_MARK,
- STATUS1_MARK,
- DRAK1_PK2_MARK,
- DACK2_MARK,
- SCIF2_TXD_MARK,
- MMCCMD_MARK,
- SIOF_TXD_PK_MARK,
- DACK3_MARK,
- SCIF2_SCK_MARK,
- MMCDAT_MARK,
- SIOF_SCK_PK_MARK,
- DREQ0_MARK,
- DREQ1_MARK,
- DRAK0_PK1_MARK,
- DRAK1_PK0_MARK,
- DREQ2_MARK,
- INTB_MARK,
- DREQ3_MARK,
- INTC_MARK,
- DRAK2_MARK,
- CE2A_MARK,
- IRL4_MARK,
- FD4_MARK,
- IRL5_MARK,
- FD5_MARK,
- IRL6_MARK,
- FD6_MARK,
- IRL7_MARK,
- FD7_MARK,
- DRAK3_MARK,
- CE2B_MARK,
- BREQ_BSACK_MARK,
- BACK_BSREQ_MARK,
- SCIF5_RXD_MARK,
- HAC1_SDIN_MARK,
- SSI1_SCK_MARK,
- SCIF5_SCK_MARK,
- HAC1_SDOUT_MARK,
- SSI1_SDATA_MARK,
- SCIF3_TXD_MARK,
- FCLE_MARK,
- SCIF3_RXD_MARK,
- FALE_MARK,
- SCIF3_SCK_MARK,
- FD0_MARK,
- SCIF4_TXD_MARK,
- FD1_MARK,
- SCIF4_RXD_MARK,
- FD2_MARK,
- SCIF4_SCK_MARK,
- FD3_MARK,
- DEVSEL_DCLKOUT_MARK,
- STOP_CDE_MARK,
- LOCK_ODDF_MARK,
- TRDY_DISPL_MARK,
- IRDY_HSYNC_MARK,
- PCIFRAME_VSYNC_MARK,
- INTA_MARK,
- GNT0_GNTIN_MARK,
- REQ0_REQOUT_MARK,
- PERR_MARK,
- SERR_MARK,
- WE7_CBE3_MARK,
- WE6_CBE2_MARK,
- WE5_CBE1_MARK,
- WE4_CBE0_MARK,
- SCIF2_RXD_MARK,
- SIOF_RXD_MARK,
- MRESETOUT_MARK,
- IRQOUT_MARK,
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
-
- /* PA GPIO */
- PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
- PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
- PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
- PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
- PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
- PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
- PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
- PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
-
- /* PB GPIO */
- PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
- PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
- PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
- PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
- PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
- PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
- PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
- PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
-
- /* PC GPIO */
- PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
- PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
- PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
- PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
- PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
- PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
- PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
- PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
-
- /* PD GPIO */
- PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
- PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
- PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
- PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
- PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
- PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
- PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
- PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
-
- /* PE GPIO */
- PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT, PE5_IN_PU),
- PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT, PE4_IN_PU),
- PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT, PE3_IN_PU),
- PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT, PE2_IN_PU),
- PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT, PE1_IN_PU),
- PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT, PE0_IN_PU),
-
- /* PF GPIO */
- PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
- PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
- PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
- PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
- PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
- PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
- PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
- PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
-
- /* PG GPIO */
- PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
- PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
- PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
- PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT, PG4_IN_PU),
- PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT, PG3_IN_PU),
- PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT, PG2_IN_PU),
- PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT, PG1_IN_PU),
- PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT, PG0_IN_PU),
-
- /* PH GPIO */
- PINMUX_DATA(PH7_DATA, PH7_IN, PH7_OUT, PH7_IN_PU),
- PINMUX_DATA(PH6_DATA, PH6_IN, PH6_OUT, PH6_IN_PU),
- PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
- PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
- PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
- PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
- PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
- PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
-
- /* PJ GPIO */
- PINMUX_DATA(PJ7_DATA, PJ7_IN, PJ7_OUT, PJ7_IN_PU),
- PINMUX_DATA(PJ6_DATA, PJ6_IN, PJ6_OUT, PJ6_IN_PU),
- PINMUX_DATA(PJ5_DATA, PJ5_IN, PJ5_OUT, PJ5_IN_PU),
- PINMUX_DATA(PJ4_DATA, PJ4_IN, PJ4_OUT, PJ4_IN_PU),
- PINMUX_DATA(PJ3_DATA, PJ3_IN, PJ3_OUT, PJ3_IN_PU),
- PINMUX_DATA(PJ2_DATA, PJ2_IN, PJ2_OUT, PJ2_IN_PU),
- PINMUX_DATA(PJ1_DATA, PJ1_IN, PJ1_OUT, PJ1_IN_PU),
- PINMUX_DATA(PJ0_DATA, PJ0_IN, PJ0_OUT, PJ0_IN_PU),
-
- /* PK GPIO */
- PINMUX_DATA(PK7_DATA, PK7_IN, PK7_OUT, PK7_IN_PU),
- PINMUX_DATA(PK6_DATA, PK6_IN, PK6_OUT, PK6_IN_PU),
- PINMUX_DATA(PK5_DATA, PK5_IN, PK5_OUT, PK5_IN_PU),
- PINMUX_DATA(PK4_DATA, PK4_IN, PK4_OUT, PK4_IN_PU),
- PINMUX_DATA(PK3_DATA, PK3_IN, PK3_OUT, PK3_IN_PU),
- PINMUX_DATA(PK2_DATA, PK2_IN, PK2_OUT, PK2_IN_PU),
- PINMUX_DATA(PK1_DATA, PK1_IN, PK1_OUT, PK1_IN_PU),
- PINMUX_DATA(PK0_DATA, PK0_IN, PK0_OUT, PK0_IN_PU),
-
- /* PL GPIO */
- PINMUX_DATA(PL7_DATA, PL7_IN, PL7_OUT, PL7_IN_PU),
- PINMUX_DATA(PL6_DATA, PL6_IN, PL6_OUT, PL6_IN_PU),
- PINMUX_DATA(PL5_DATA, PL5_IN, PL5_OUT, PL5_IN_PU),
- PINMUX_DATA(PL4_DATA, PL4_IN, PL4_OUT, PL4_IN_PU),
- PINMUX_DATA(PL3_DATA, PL3_IN, PL3_OUT, PL3_IN_PU),
- PINMUX_DATA(PL2_DATA, PL2_IN, PL2_OUT, PL2_IN_PU),
- PINMUX_DATA(PL1_DATA, PL1_IN, PL1_OUT, PL1_IN_PU),
- PINMUX_DATA(PL0_DATA, PL0_IN, PL0_OUT, PL0_IN_PU),
-
- /* PM GPIO */
- PINMUX_DATA(PM1_DATA, PM1_IN, PM1_OUT, PM1_IN_PU),
- PINMUX_DATA(PM0_DATA, PM0_IN, PM0_OUT, PM0_IN_PU),
-
- /* PN GPIO */
- PINMUX_DATA(PN7_DATA, PN7_IN, PN7_OUT, PN7_IN_PU),
- PINMUX_DATA(PN6_DATA, PN6_IN, PN6_OUT, PN6_IN_PU),
- PINMUX_DATA(PN5_DATA, PN5_IN, PN5_OUT, PN5_IN_PU),
- PINMUX_DATA(PN4_DATA, PN4_IN, PN4_OUT, PN4_IN_PU),
- PINMUX_DATA(PN3_DATA, PN3_IN, PN3_OUT, PN3_IN_PU),
- PINMUX_DATA(PN2_DATA, PN2_IN, PN2_OUT, PN2_IN_PU),
- PINMUX_DATA(PN1_DATA, PN1_IN, PN1_OUT, PN1_IN_PU),
- PINMUX_DATA(PN0_DATA, PN0_IN, PN0_OUT, PN0_IN_PU),
-
- /* PP GPIO */
- PINMUX_DATA(PP5_DATA, PP5_IN, PP5_OUT, PP5_IN_PU),
- PINMUX_DATA(PP4_DATA, PP4_IN, PP4_OUT, PP4_IN_PU),
- PINMUX_DATA(PP3_DATA, PP3_IN, PP3_OUT, PP3_IN_PU),
- PINMUX_DATA(PP2_DATA, PP2_IN, PP2_OUT, PP2_IN_PU),
- PINMUX_DATA(PP1_DATA, PP1_IN, PP1_OUT, PP1_IN_PU),
- PINMUX_DATA(PP0_DATA, PP0_IN, PP0_OUT, PP0_IN_PU),
-
- /* PQ GPIO */
- PINMUX_DATA(PQ4_DATA, PQ4_IN, PQ4_OUT, PQ4_IN_PU),
- PINMUX_DATA(PQ3_DATA, PQ3_IN, PQ3_OUT, PQ3_IN_PU),
- PINMUX_DATA(PQ2_DATA, PQ2_IN, PQ2_OUT, PQ2_IN_PU),
- PINMUX_DATA(PQ1_DATA, PQ1_IN, PQ1_OUT, PQ1_IN_PU),
- PINMUX_DATA(PQ0_DATA, PQ0_IN, PQ0_OUT, PQ0_IN_PU),
-
- /* PR GPIO */
- PINMUX_DATA(PR3_DATA, PR3_IN, PR3_OUT, PR3_IN_PU),
- PINMUX_DATA(PR2_DATA, PR2_IN, PR2_OUT, PR2_IN_PU),
- PINMUX_DATA(PR1_DATA, PR1_IN, PR1_OUT, PR1_IN_PU),
- PINMUX_DATA(PR0_DATA, PR0_IN, PR0_OUT, PR0_IN_PU),
-
- /* PA FN */
- PINMUX_DATA(D63_AD31_MARK, PA7_FN),
- PINMUX_DATA(D62_AD30_MARK, PA6_FN),
- PINMUX_DATA(D61_AD29_MARK, PA5_FN),
- PINMUX_DATA(D60_AD28_MARK, PA4_FN),
- PINMUX_DATA(D59_AD27_MARK, PA3_FN),
- PINMUX_DATA(D58_AD26_MARK, PA2_FN),
- PINMUX_DATA(D57_AD25_MARK, PA1_FN),
- PINMUX_DATA(D56_AD24_MARK, PA0_FN),
-
- /* PB FN */
- PINMUX_DATA(D55_AD23_MARK, PB7_FN),
- PINMUX_DATA(D54_AD22_MARK, PB6_FN),
- PINMUX_DATA(D53_AD21_MARK, PB5_FN),
- PINMUX_DATA(D52_AD20_MARK, PB4_FN),
- PINMUX_DATA(D51_AD19_MARK, PB3_FN),
- PINMUX_DATA(D50_AD18_MARK, PB2_FN),
- PINMUX_DATA(D49_AD17_DB5_MARK, PB1_FN),
- PINMUX_DATA(D48_AD16_DB4_MARK, PB0_FN),
-
- /* PC FN */
- PINMUX_DATA(D47_AD15_DB3_MARK, PC7_FN),
- PINMUX_DATA(D46_AD14_DB2_MARK, PC6_FN),
- PINMUX_DATA(D45_AD13_DB1_MARK, PC5_FN),
- PINMUX_DATA(D44_AD12_DB0_MARK, PC4_FN),
- PINMUX_DATA(D43_AD11_DG5_MARK, PC3_FN),
- PINMUX_DATA(D42_AD10_DG4_MARK, PC2_FN),
- PINMUX_DATA(D41_AD9_DG3_MARK, PC1_FN),
- PINMUX_DATA(D40_AD8_DG2_MARK, PC0_FN),
-
- /* PD FN */
- PINMUX_DATA(D39_AD7_DG1_MARK, PD7_FN),
- PINMUX_DATA(D38_AD6_DG0_MARK, PD6_FN),
- PINMUX_DATA(D37_AD5_DR5_MARK, PD5_FN),
- PINMUX_DATA(D36_AD4_DR4_MARK, PD4_FN),
- PINMUX_DATA(D35_AD3_DR3_MARK, PD3_FN),
- PINMUX_DATA(D34_AD2_DR2_MARK, PD2_FN),
- PINMUX_DATA(D33_AD1_DR1_MARK, PD1_FN),
- PINMUX_DATA(D32_AD0_DR0_MARK, PD0_FN),
-
- /* PE FN */
- PINMUX_DATA(REQ1_MARK, PE5_FN),
- PINMUX_DATA(REQ2_MARK, PE4_FN),
- PINMUX_DATA(REQ3_MARK, P2MSEL0_0, PE3_FN),
- PINMUX_DATA(GNT1_MARK, PE2_FN),
- PINMUX_DATA(GNT2_MARK, PE1_FN),
- PINMUX_DATA(GNT3_MARK, P2MSEL0_0, PE0_FN),
- PINMUX_DATA(MMCCLK_MARK, P2MSEL0_1, PE0_FN),
-
- /* PF FN */
- PINMUX_DATA(D31_MARK, PF7_FN),
- PINMUX_DATA(D30_MARK, PF6_FN),
- PINMUX_DATA(D29_MARK, PF5_FN),
- PINMUX_DATA(D28_MARK, PF4_FN),
- PINMUX_DATA(D27_MARK, PF3_FN),
- PINMUX_DATA(D26_MARK, PF2_FN),
- PINMUX_DATA(D25_MARK, PF1_FN),
- PINMUX_DATA(D24_MARK, PF0_FN),
-
- /* PF FN */
- PINMUX_DATA(D23_MARK, PG7_FN),
- PINMUX_DATA(D22_MARK, PG6_FN),
- PINMUX_DATA(D21_MARK, PG5_FN),
- PINMUX_DATA(D20_MARK, PG4_FN),
- PINMUX_DATA(D19_MARK, PG3_FN),
- PINMUX_DATA(D18_MARK, PG2_FN),
- PINMUX_DATA(D17_MARK, PG1_FN),
- PINMUX_DATA(D16_MARK, PG0_FN),
-
- /* PH FN */
- PINMUX_DATA(SCIF1_SCK_MARK, PH7_FN),
- PINMUX_DATA(SCIF1_RXD_MARK, PH6_FN),
- PINMUX_DATA(SCIF1_TXD_MARK, PH5_FN),
- PINMUX_DATA(SCIF0_CTS_MARK, PH4_FN),
- PINMUX_DATA(INTD_MARK, P1MSEL7_1, PH4_FN),
- PINMUX_DATA(FCE_MARK, P1MSEL8_1, P1MSEL7_0, PH4_FN),
- PINMUX_DATA(SCIF0_RTS_MARK, P1MSEL8_0, P1MSEL7_0, PH3_FN),
- PINMUX_DATA(HSPI_CS_MARK, P1MSEL8_0, P1MSEL7_1, PH3_FN),
- PINMUX_DATA(FSE_MARK, P1MSEL8_1, P1MSEL7_0, PH3_FN),
- PINMUX_DATA(SCIF0_SCK_MARK, P1MSEL8_0, P1MSEL7_0, PH2_FN),
- PINMUX_DATA(HSPI_CLK_MARK, P1MSEL8_0, P1MSEL7_1, PH2_FN),
- PINMUX_DATA(FRE_MARK, P1MSEL8_1, P1MSEL7_0, PH2_FN),
- PINMUX_DATA(SCIF0_RXD_MARK, P1MSEL8_0, P1MSEL7_0, PH1_FN),
- PINMUX_DATA(HSPI_RX_MARK, P1MSEL8_0, P1MSEL7_1, PH1_FN),
- PINMUX_DATA(FRB_MARK, P1MSEL8_1, P1MSEL7_0, PH1_FN),
- PINMUX_DATA(SCIF0_TXD_MARK, P1MSEL8_0, P1MSEL7_0, PH0_FN),
- PINMUX_DATA(HSPI_TX_MARK, P1MSEL8_0, P1MSEL7_1, PH0_FN),
- PINMUX_DATA(FWE_MARK, P1MSEL8_1, P1MSEL7_0, PH0_FN),
-
- /* PJ FN */
- PINMUX_DATA(SCIF5_TXD_MARK, P1MSEL2_0, P1MSEL1_0, PJ7_FN),
- PINMUX_DATA(HAC1_SYNC_MARK, P1MSEL2_0, P1MSEL1_1, PJ7_FN),
- PINMUX_DATA(SSI1_WS_MARK, P1MSEL2_1, P1MSEL1_0, PJ7_FN),
- PINMUX_DATA(SIOF_TXD_PJ_MARK, P2MSEL1_0, P1MSEL4_0, P1MSEL3_0, PJ6_FN),
- PINMUX_DATA(HAC0_SDOUT_MARK, P1MSEL4_0, P1MSEL3_1, PJ6_FN),
- PINMUX_DATA(SSI0_SDATA_MARK, P1MSEL4_1, P1MSEL3_0, PJ6_FN),
- PINMUX_DATA(SIOF_RXD_PJ_MARK, P2MSEL1_0, P1MSEL4_0, P1MSEL3_0, PJ5_FN),
- PINMUX_DATA(HAC0_SDIN_MARK, P1MSEL4_0, P1MSEL3_1, PJ5_FN),
- PINMUX_DATA(SSI0_SCK_MARK, P1MSEL4_1, P1MSEL3_0, PJ5_FN),
- PINMUX_DATA(SIOF_SYNC_PJ_MARK, P2MSEL1_0, P1MSEL4_0, P1MSEL3_0, PJ4_FN),
- PINMUX_DATA(HAC0_SYNC_MARK, P1MSEL4_0, P1MSEL3_1, PJ4_FN),
- PINMUX_DATA(SSI0_WS_MARK, P1MSEL4_1, P1MSEL3_0, PJ4_FN),
- PINMUX_DATA(SIOF_MCLK_PJ_MARK, P2MSEL1_0, P1MSEL4_0, P1MSEL3_0, PJ3_FN),
- PINMUX_DATA(HAC_RES_MARK, P1MSEL4_0, P1MSEL3_1, PJ3_FN),
- PINMUX_DATA(SIOF_SCK_PJ_MARK, P2MSEL1_0, P1MSEL4_0, P1MSEL3_0, PJ2_FN),
- PINMUX_DATA(HAC0_BITCLK_MARK, P1MSEL4_0, P1MSEL3_1, PJ2_FN),
- PINMUX_DATA(SSI0_CLK_MARK, P1MSEL4_1, P1MSEL3_0, PJ2_FN),
- PINMUX_DATA(HAC1_BITCLK_MARK, P1MSEL2_0, PJ1_FN),
- PINMUX_DATA(SSI1_CLK_MARK, P1MSEL2_1, P1MSEL1_0, PJ1_FN),
- PINMUX_DATA(TCLK_MARK, P1MSEL9_0, PJ0_FN),
- PINMUX_DATA(IOIS16_MARK, P1MSEL9_1, PJ0_FN),
-
- /* PK FN */
- PINMUX_DATA(STATUS0_MARK, P1MSEL15_0, PK7_FN),
- PINMUX_DATA(DRAK0_PK3_MARK, P1MSEL15_1, PK7_FN),
- PINMUX_DATA(STATUS1_MARK, P1MSEL15_0, PK6_FN),
- PINMUX_DATA(DRAK1_PK2_MARK, P1MSEL15_1, PK6_FN),
- PINMUX_DATA(DACK2_MARK, P1MSEL12_0, P1MSEL11_0, PK5_FN),
- PINMUX_DATA(SCIF2_TXD_MARK, P1MSEL12_1, P1MSEL11_0, PK5_FN),
- PINMUX_DATA(MMCCMD_MARK, P1MSEL12_1, P1MSEL11_1, PK5_FN),
- PINMUX_DATA(SIOF_TXD_PK_MARK, P2MSEL1_1,
- P1MSEL12_0, P1MSEL11_1, PK5_FN),
- PINMUX_DATA(DACK3_MARK, P1MSEL12_0, P1MSEL11_0, PK4_FN),
- PINMUX_DATA(SCIF2_SCK_MARK, P1MSEL12_1, P1MSEL11_0, PK4_FN),
- PINMUX_DATA(MMCDAT_MARK, P1MSEL12_1, P1MSEL11_1, PK4_FN),
- PINMUX_DATA(SIOF_SCK_PK_MARK, P2MSEL1_1,
- P1MSEL12_0, P1MSEL11_1, PK4_FN),
- PINMUX_DATA(DREQ0_MARK, PK3_FN),
- PINMUX_DATA(DREQ1_MARK, PK2_FN),
- PINMUX_DATA(DRAK0_PK1_MARK, PK1_FN),
- PINMUX_DATA(DRAK1_PK0_MARK, PK0_FN),
-
- /* PL FN */
- PINMUX_DATA(DREQ2_MARK, P1MSEL13_0, PL7_FN),
- PINMUX_DATA(INTB_MARK, P1MSEL13_1, PL7_FN),
- PINMUX_DATA(DREQ3_MARK, P1MSEL13_0, PL6_FN),
- PINMUX_DATA(INTC_MARK, P1MSEL13_1, PL6_FN),
- PINMUX_DATA(DRAK2_MARK, P1MSEL10_0, PL5_FN),
- PINMUX_DATA(CE2A_MARK, P1MSEL10_1, PL5_FN),
- PINMUX_DATA(IRL4_MARK, P1MSEL14_0, PL4_FN),
- PINMUX_DATA(FD4_MARK, P1MSEL14_1, PL4_FN),
- PINMUX_DATA(IRL5_MARK, P1MSEL14_0, PL3_FN),
- PINMUX_DATA(FD5_MARK, P1MSEL14_1, PL3_FN),
- PINMUX_DATA(IRL6_MARK, P1MSEL14_0, PL2_FN),
- PINMUX_DATA(FD6_MARK, P1MSEL14_1, PL2_FN),
- PINMUX_DATA(IRL7_MARK, P1MSEL14_0, PL1_FN),
- PINMUX_DATA(FD7_MARK, P1MSEL14_1, PL1_FN),
- PINMUX_DATA(DRAK3_MARK, P1MSEL10_0, PL0_FN),
- PINMUX_DATA(CE2B_MARK, P1MSEL10_1, PL0_FN),
-
- /* PM FN */
- PINMUX_DATA(BREQ_BSACK_MARK, PM1_FN),
- PINMUX_DATA(BACK_BSREQ_MARK, PM0_FN),
-
- /* PN FN */
- PINMUX_DATA(SCIF5_RXD_MARK, P1MSEL2_0, P1MSEL1_0, PN7_FN),
- PINMUX_DATA(HAC1_SDIN_MARK, P1MSEL2_0, P1MSEL1_1, PN7_FN),
- PINMUX_DATA(SSI1_SCK_MARK, P1MSEL2_1, P1MSEL1_0, PN7_FN),
- PINMUX_DATA(SCIF5_SCK_MARK, P1MSEL2_0, P1MSEL1_0, PN6_FN),
- PINMUX_DATA(HAC1_SDOUT_MARK, P1MSEL2_0, P1MSEL1_1, PN6_FN),
- PINMUX_DATA(SSI1_SDATA_MARK, P1MSEL2_1, P1MSEL1_0, PN6_FN),
- PINMUX_DATA(SCIF3_TXD_MARK, P1MSEL0_0, PN5_FN),
- PINMUX_DATA(FCLE_MARK, P1MSEL0_1, PN5_FN),
- PINMUX_DATA(SCIF3_RXD_MARK, P1MSEL0_0, PN4_FN),
- PINMUX_DATA(FALE_MARK, P1MSEL0_1, PN4_FN),
- PINMUX_DATA(SCIF3_SCK_MARK, P1MSEL0_0, PN3_FN),
- PINMUX_DATA(FD0_MARK, P1MSEL0_1, PN3_FN),
- PINMUX_DATA(SCIF4_TXD_MARK, P1MSEL0_0, PN2_FN),
- PINMUX_DATA(FD1_MARK, P1MSEL0_1, PN2_FN),
- PINMUX_DATA(SCIF4_RXD_MARK, P1MSEL0_0, PN1_FN),
- PINMUX_DATA(FD2_MARK, P1MSEL0_1, PN1_FN),
- PINMUX_DATA(SCIF4_SCK_MARK, P1MSEL0_0, PN0_FN),
- PINMUX_DATA(FD3_MARK, P1MSEL0_1, PN0_FN),
-
- /* PP FN */
- PINMUX_DATA(DEVSEL_DCLKOUT_MARK, PP5_FN),
- PINMUX_DATA(STOP_CDE_MARK, PP4_FN),
- PINMUX_DATA(LOCK_ODDF_MARK, PP3_FN),
- PINMUX_DATA(TRDY_DISPL_MARK, PP2_FN),
- PINMUX_DATA(IRDY_HSYNC_MARK, PP1_FN),
- PINMUX_DATA(PCIFRAME_VSYNC_MARK, PP0_FN),
-
- /* PQ FN */
- PINMUX_DATA(INTA_MARK, PQ4_FN),
- PINMUX_DATA(GNT0_GNTIN_MARK, PQ3_FN),
- PINMUX_DATA(REQ0_REQOUT_MARK, PQ2_FN),
- PINMUX_DATA(PERR_MARK, PQ1_FN),
- PINMUX_DATA(SERR_MARK, PQ0_FN),
-
- /* PR FN */
- PINMUX_DATA(WE7_CBE3_MARK, PR3_FN),
- PINMUX_DATA(WE6_CBE2_MARK, PR2_FN),
- PINMUX_DATA(WE5_CBE1_MARK, PR1_FN),
- PINMUX_DATA(WE4_CBE0_MARK, PR0_FN),
-
- /* MISC FN */
- PINMUX_DATA(SCIF2_RXD_MARK, P1MSEL6_0, P1MSEL5_0),
- PINMUX_DATA(SIOF_RXD_MARK, P2MSEL1_1, P1MSEL6_1, P1MSEL5_0),
- PINMUX_DATA(MRESETOUT_MARK, P2MSEL2_0),
- PINMUX_DATA(IRQOUT_MARK, P2MSEL2_1),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
- /* PA */
- PINMUX_GPIO(GPIO_PA7, PA7_DATA),
- PINMUX_GPIO(GPIO_PA6, PA6_DATA),
- PINMUX_GPIO(GPIO_PA5, PA5_DATA),
- PINMUX_GPIO(GPIO_PA4, PA4_DATA),
- PINMUX_GPIO(GPIO_PA3, PA3_DATA),
- PINMUX_GPIO(GPIO_PA2, PA2_DATA),
- PINMUX_GPIO(GPIO_PA1, PA1_DATA),
- PINMUX_GPIO(GPIO_PA0, PA0_DATA),
-
- /* PB */
- PINMUX_GPIO(GPIO_PB7, PB7_DATA),
- PINMUX_GPIO(GPIO_PB6, PB6_DATA),
- PINMUX_GPIO(GPIO_PB5, PB5_DATA),
- PINMUX_GPIO(GPIO_PB4, PB4_DATA),
- PINMUX_GPIO(GPIO_PB3, PB3_DATA),
- PINMUX_GPIO(GPIO_PB2, PB2_DATA),
- PINMUX_GPIO(GPIO_PB1, PB1_DATA),
- PINMUX_GPIO(GPIO_PB0, PB0_DATA),
-
- /* PC */
- PINMUX_GPIO(GPIO_PC7, PC7_DATA),
- PINMUX_GPIO(GPIO_PC6, PC6_DATA),
- PINMUX_GPIO(GPIO_PC5, PC5_DATA),
- PINMUX_GPIO(GPIO_PC4, PC4_DATA),
- PINMUX_GPIO(GPIO_PC3, PC3_DATA),
- PINMUX_GPIO(GPIO_PC2, PC2_DATA),
- PINMUX_GPIO(GPIO_PC1, PC1_DATA),
- PINMUX_GPIO(GPIO_PC0, PC0_DATA),
-
- /* PD */
- PINMUX_GPIO(GPIO_PD7, PD7_DATA),
- PINMUX_GPIO(GPIO_PD6, PD6_DATA),
- PINMUX_GPIO(GPIO_PD5, PD5_DATA),
- PINMUX_GPIO(GPIO_PD4, PD4_DATA),
- PINMUX_GPIO(GPIO_PD3, PD3_DATA),
- PINMUX_GPIO(GPIO_PD2, PD2_DATA),
- PINMUX_GPIO(GPIO_PD1, PD1_DATA),
- PINMUX_GPIO(GPIO_PD0, PD0_DATA),
-
- /* PE */
- PINMUX_GPIO(GPIO_PE5, PE5_DATA),
- PINMUX_GPIO(GPIO_PE4, PE4_DATA),
- PINMUX_GPIO(GPIO_PE3, PE3_DATA),
- PINMUX_GPIO(GPIO_PE2, PE2_DATA),
- PINMUX_GPIO(GPIO_PE1, PE1_DATA),
- PINMUX_GPIO(GPIO_PE0, PE0_DATA),
-
- /* PF */
- PINMUX_GPIO(GPIO_PF7, PF7_DATA),
- PINMUX_GPIO(GPIO_PF6, PF6_DATA),
- PINMUX_GPIO(GPIO_PF5, PF5_DATA),
- PINMUX_GPIO(GPIO_PF4, PF4_DATA),
- PINMUX_GPIO(GPIO_PF3, PF3_DATA),
- PINMUX_GPIO(GPIO_PF2, PF2_DATA),
- PINMUX_GPIO(GPIO_PF1, PF1_DATA),
- PINMUX_GPIO(GPIO_PF0, PF0_DATA),
-
- /* PG */
- PINMUX_GPIO(GPIO_PG7, PG7_DATA),
- PINMUX_GPIO(GPIO_PG6, PG6_DATA),
- PINMUX_GPIO(GPIO_PG5, PG5_DATA),
- PINMUX_GPIO(GPIO_PG4, PG4_DATA),
- PINMUX_GPIO(GPIO_PG3, PG3_DATA),
- PINMUX_GPIO(GPIO_PG2, PG2_DATA),
- PINMUX_GPIO(GPIO_PG1, PG1_DATA),
- PINMUX_GPIO(GPIO_PG0, PG0_DATA),
-
- /* PH */
- PINMUX_GPIO(GPIO_PH7, PH7_DATA),
- PINMUX_GPIO(GPIO_PH6, PH6_DATA),
- PINMUX_GPIO(GPIO_PH5, PH5_DATA),
- PINMUX_GPIO(GPIO_PH4, PH4_DATA),
- PINMUX_GPIO(GPIO_PH3, PH3_DATA),
- PINMUX_GPIO(GPIO_PH2, PH2_DATA),
- PINMUX_GPIO(GPIO_PH1, PH1_DATA),
- PINMUX_GPIO(GPIO_PH0, PH0_DATA),
-
- /* PJ */
- PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
- PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
- PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
- PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
- PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
- PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
- PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
- PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
-
- /* PK */
- PINMUX_GPIO(GPIO_PK7, PK7_DATA),
- PINMUX_GPIO(GPIO_PK6, PK6_DATA),
- PINMUX_GPIO(GPIO_PK5, PK5_DATA),
- PINMUX_GPIO(GPIO_PK4, PK4_DATA),
- PINMUX_GPIO(GPIO_PK3, PK3_DATA),
- PINMUX_GPIO(GPIO_PK2, PK2_DATA),
- PINMUX_GPIO(GPIO_PK1, PK1_DATA),
- PINMUX_GPIO(GPIO_PK0, PK0_DATA),
-
- /* PL */
- PINMUX_GPIO(GPIO_PL7, PL7_DATA),
- PINMUX_GPIO(GPIO_PL6, PL6_DATA),
- PINMUX_GPIO(GPIO_PL5, PL5_DATA),
- PINMUX_GPIO(GPIO_PL4, PL4_DATA),
- PINMUX_GPIO(GPIO_PL3, PL3_DATA),
- PINMUX_GPIO(GPIO_PL2, PL2_DATA),
- PINMUX_GPIO(GPIO_PL1, PL1_DATA),
- PINMUX_GPIO(GPIO_PL0, PL0_DATA),
-
- /* PM */
- PINMUX_GPIO(GPIO_PM1, PM1_DATA),
- PINMUX_GPIO(GPIO_PM0, PM0_DATA),
-
- /* PN */
- PINMUX_GPIO(GPIO_PN7, PN7_DATA),
- PINMUX_GPIO(GPIO_PN6, PN6_DATA),
- PINMUX_GPIO(GPIO_PN5, PN5_DATA),
- PINMUX_GPIO(GPIO_PN4, PN4_DATA),
- PINMUX_GPIO(GPIO_PN3, PN3_DATA),
- PINMUX_GPIO(GPIO_PN2, PN2_DATA),
- PINMUX_GPIO(GPIO_PN1, PN1_DATA),
- PINMUX_GPIO(GPIO_PN0, PN0_DATA),
-
- /* PP */
- PINMUX_GPIO(GPIO_PP5, PP5_DATA),
- PINMUX_GPIO(GPIO_PP4, PP4_DATA),
- PINMUX_GPIO(GPIO_PP3, PP3_DATA),
- PINMUX_GPIO(GPIO_PP2, PP2_DATA),
- PINMUX_GPIO(GPIO_PP1, PP1_DATA),
- PINMUX_GPIO(GPIO_PP0, PP0_DATA),
-
- /* PQ */
- PINMUX_GPIO(GPIO_PQ4, PQ4_DATA),
- PINMUX_GPIO(GPIO_PQ3, PQ3_DATA),
- PINMUX_GPIO(GPIO_PQ2, PQ2_DATA),
- PINMUX_GPIO(GPIO_PQ1, PQ1_DATA),
- PINMUX_GPIO(GPIO_PQ0, PQ0_DATA),
-
- /* PR */
- PINMUX_GPIO(GPIO_PR3, PR3_DATA),
- PINMUX_GPIO(GPIO_PR2, PR2_DATA),
- PINMUX_GPIO(GPIO_PR1, PR1_DATA),
- PINMUX_GPIO(GPIO_PR0, PR0_DATA),
-
- /* FN */
- PINMUX_GPIO(GPIO_FN_D63_AD31, D63_AD31_MARK),
- PINMUX_GPIO(GPIO_FN_D62_AD30, D62_AD30_MARK),
- PINMUX_GPIO(GPIO_FN_D61_AD29, D61_AD29_MARK),
- PINMUX_GPIO(GPIO_FN_D60_AD28, D60_AD28_MARK),
- PINMUX_GPIO(GPIO_FN_D59_AD27, D59_AD27_MARK),
- PINMUX_GPIO(GPIO_FN_D58_AD26, D58_AD26_MARK),
- PINMUX_GPIO(GPIO_FN_D57_AD25, D57_AD25_MARK),
- PINMUX_GPIO(GPIO_FN_D56_AD24, D56_AD24_MARK),
- PINMUX_GPIO(GPIO_FN_D55_AD23, D55_AD23_MARK),
- PINMUX_GPIO(GPIO_FN_D54_AD22, D54_AD22_MARK),
- PINMUX_GPIO(GPIO_FN_D53_AD21, D53_AD21_MARK),
- PINMUX_GPIO(GPIO_FN_D52_AD20, D52_AD20_MARK),
- PINMUX_GPIO(GPIO_FN_D51_AD19, D51_AD19_MARK),
- PINMUX_GPIO(GPIO_FN_D50_AD18, D50_AD18_MARK),
- PINMUX_GPIO(GPIO_FN_D49_AD17_DB5, D49_AD17_DB5_MARK),
- PINMUX_GPIO(GPIO_FN_D48_AD16_DB4, D48_AD16_DB4_MARK),
- PINMUX_GPIO(GPIO_FN_D47_AD15_DB3, D47_AD15_DB3_MARK),
- PINMUX_GPIO(GPIO_FN_D46_AD14_DB2, D46_AD14_DB2_MARK),
- PINMUX_GPIO(GPIO_FN_D45_AD13_DB1, D45_AD13_DB1_MARK),
- PINMUX_GPIO(GPIO_FN_D44_AD12_DB0, D44_AD12_DB0_MARK),
- PINMUX_GPIO(GPIO_FN_D43_AD11_DG5, D43_AD11_DG5_MARK),
- PINMUX_GPIO(GPIO_FN_D42_AD10_DG4, D42_AD10_DG4_MARK),
- PINMUX_GPIO(GPIO_FN_D41_AD9_DG3, D41_AD9_DG3_MARK),
- PINMUX_GPIO(GPIO_FN_D40_AD8_DG2, D40_AD8_DG2_MARK),
- PINMUX_GPIO(GPIO_FN_D39_AD7_DG1, D39_AD7_DG1_MARK),
- PINMUX_GPIO(GPIO_FN_D38_AD6_DG0, D38_AD6_DG0_MARK),
- PINMUX_GPIO(GPIO_FN_D37_AD5_DR5, D37_AD5_DR5_MARK),
- PINMUX_GPIO(GPIO_FN_D36_AD4_DR4, D36_AD4_DR4_MARK),
- PINMUX_GPIO(GPIO_FN_D35_AD3_DR3, D35_AD3_DR3_MARK),
- PINMUX_GPIO(GPIO_FN_D34_AD2_DR2, D34_AD2_DR2_MARK),
- PINMUX_GPIO(GPIO_FN_D33_AD1_DR1, D33_AD1_DR1_MARK),
- PINMUX_GPIO(GPIO_FN_D32_AD0_DR0, D32_AD0_DR0_MARK),
- PINMUX_GPIO(GPIO_FN_REQ1, REQ1_MARK),
- PINMUX_GPIO(GPIO_FN_REQ2, REQ2_MARK),
- PINMUX_GPIO(GPIO_FN_REQ3, REQ3_MARK),
- PINMUX_GPIO(GPIO_FN_GNT1, GNT1_MARK),
- PINMUX_GPIO(GPIO_FN_GNT2, GNT2_MARK),
- PINMUX_GPIO(GPIO_FN_GNT3, GNT3_MARK),
- PINMUX_GPIO(GPIO_FN_MMCCLK, MMCCLK_MARK),
- PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
- PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
- PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
- PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
- PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
- PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
- PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
- PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
- PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
- PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
- PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
- PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
- PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
- PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
- PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
- PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_SCK, SCIF1_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_RXD, SCIF1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_TXD, SCIF1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_CTS, SCIF0_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_INTD, INTD_MARK),
- PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_RTS, SCIF0_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_HSPI_CS, HSPI_CS_MARK),
- PINMUX_GPIO(GPIO_FN_FSE, FSE_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_SCK, SCIF0_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_HSPI_CLK, HSPI_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_FRE, FRE_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_RXD, SCIF0_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_HSPI_RX, HSPI_RX_MARK),
- PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_TXD, SCIF0_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_HSPI_TX, HSPI_TX_MARK),
- PINMUX_GPIO(GPIO_FN_FWE, FWE_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_TXD, SCIF5_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_HAC1_SYNC, HAC1_SYNC_MARK),
- PINMUX_GPIO(GPIO_FN_SSI1_WS, SSI1_WS_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF_TXD_PJ, SIOF_TXD_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_HAC0_SDOUT, HAC0_SDOUT_MARK),
- PINMUX_GPIO(GPIO_FN_SSI0_SDATA, SSI0_SDATA_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF_RXD_PJ, SIOF_RXD_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_HAC0_SDIN, HAC0_SDIN_MARK),
- PINMUX_GPIO(GPIO_FN_SSI0_SCK, SSI0_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF_SYNC_PJ, SIOF_SYNC_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_HAC0_SYNC, HAC0_SYNC_MARK),
- PINMUX_GPIO(GPIO_FN_SSI0_WS, SSI0_WS_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF_MCLK_PJ, SIOF_MCLK_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_HAC_RES, HAC_RES_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF_SCK_PJ, SIOF_SCK_PJ_MARK),
- PINMUX_GPIO(GPIO_FN_HAC0_BITCLK, HAC0_BITCLK_MARK),
- PINMUX_GPIO(GPIO_FN_SSI0_CLK, SSI0_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_HAC1_BITCLK, HAC1_BITCLK_MARK),
- PINMUX_GPIO(GPIO_FN_SSI1_CLK, SSI1_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
- PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK0_PK3, DRAK0_PK3_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK1_PK2, DRAK1_PK2_MARK),
- PINMUX_GPIO(GPIO_FN_DACK2, DACK2_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_TXD, SCIF2_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_MMCCMD, MMCCMD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF_TXD_PK, SIOF_TXD_PK_MARK),
- PINMUX_GPIO(GPIO_FN_DACK3, DACK3_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_SCK, SCIF2_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_MMCDAT, MMCDAT_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF_SCK_PK, SIOF_SCK_PK_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK0_PK1, DRAK0_PK1_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK1_PK0, DRAK1_PK0_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ2, DREQ2_MARK),
- PINMUX_GPIO(GPIO_FN_INTB, INTB_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ3, DREQ3_MARK),
- PINMUX_GPIO(GPIO_FN_INTC, INTC_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK2, DRAK2_MARK),
- PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
- PINMUX_GPIO(GPIO_FN_IRL4, IRL4_MARK),
- PINMUX_GPIO(GPIO_FN_FD4, FD4_MARK),
- PINMUX_GPIO(GPIO_FN_IRL5, IRL5_MARK),
- PINMUX_GPIO(GPIO_FN_FD5, FD5_MARK),
- PINMUX_GPIO(GPIO_FN_IRL6, IRL6_MARK),
- PINMUX_GPIO(GPIO_FN_FD6, FD6_MARK),
- PINMUX_GPIO(GPIO_FN_IRL7, IRL7_MARK),
- PINMUX_GPIO(GPIO_FN_FD7, FD7_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK3, DRAK3_MARK),
- PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
- PINMUX_GPIO(GPIO_FN_BREQ_BSACK, BREQ_BSACK_MARK),
- PINMUX_GPIO(GPIO_FN_BACK_BSREQ, BACK_BSREQ_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_RXD, SCIF5_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_HAC1_SDIN, HAC1_SDIN_MARK),
- PINMUX_GPIO(GPIO_FN_SSI1_SCK, SSI1_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_SCK, SCIF5_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_HAC1_SDOUT, HAC1_SDOUT_MARK),
- PINMUX_GPIO(GPIO_FN_SSI1_SDATA, SSI1_SDATA_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_TXD, SCIF3_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_FCLE, FCLE_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_RXD, SCIF3_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_FALE, FALE_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_SCK, SCIF3_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_FD0, FD0_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_TXD, SCIF4_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_FD1, FD1_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_RXD, SCIF4_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_FD2, FD2_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_SCK, SCIF4_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_FD3, FD3_MARK),
- PINMUX_GPIO(GPIO_FN_DEVSEL_DCLKOUT, DEVSEL_DCLKOUT_MARK),
- PINMUX_GPIO(GPIO_FN_STOP_CDE, STOP_CDE_MARK),
- PINMUX_GPIO(GPIO_FN_LOCK_ODDF, LOCK_ODDF_MARK),
- PINMUX_GPIO(GPIO_FN_TRDY_DISPL, TRDY_DISPL_MARK),
- PINMUX_GPIO(GPIO_FN_IRDY_HSYNC, IRDY_HSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_PCIFRAME_VSYNC, PCIFRAME_VSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_INTA, INTA_MARK),
- PINMUX_GPIO(GPIO_FN_GNT0_GNTIN, GNT0_GNTIN_MARK),
- PINMUX_GPIO(GPIO_FN_REQ0_REQOUT, REQ0_REQOUT_MARK),
- PINMUX_GPIO(GPIO_FN_PERR, PERR_MARK),
- PINMUX_GPIO(GPIO_FN_SERR, SERR_MARK),
- PINMUX_GPIO(GPIO_FN_WE7_CBE3, WE7_CBE3_MARK),
- PINMUX_GPIO(GPIO_FN_WE6_CBE2, WE6_CBE2_MARK),
- PINMUX_GPIO(GPIO_FN_WE5_CBE1, WE5_CBE1_MARK),
- PINMUX_GPIO(GPIO_FN_WE4_CBE0, WE4_CBE0_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF2_RXD, SCIF2_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SIOF_RXD, SIOF_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_MRESETOUT, MRESETOUT_MARK),
- PINMUX_GPIO(GPIO_FN_IRQOUT, IRQOUT_MARK),
-};
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- { PINMUX_CFG_REG("PACR", 0xffe70000, 16, 2) {
- PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
- PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
- PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
- PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
- PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
- PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
- PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
- PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU }
- },
- { PINMUX_CFG_REG("PBCR", 0xffe70002, 16, 2) {
- PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
- PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
- PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
- PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
- PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
- PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
- PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
- PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU }
- },
- { PINMUX_CFG_REG("PCCR", 0xffe70004, 16, 2) {
- PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
- PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
- PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
- PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
- PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
- PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
- PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
- PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU }
- },
- { PINMUX_CFG_REG("PDCR", 0xffe70006, 16, 2) {
- PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
- PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
- PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
- PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
- PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
- PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
- PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
- PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU }
- },
- { PINMUX_CFG_REG("PECR", 0xffe70008, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PE5_FN, PE5_OUT, PE5_IN, PE5_IN_PU,
- PE4_FN, PE4_OUT, PE4_IN, PE4_IN_PU,
- PE3_FN, PE3_OUT, PE3_IN, PE3_IN_PU,
- PE2_FN, PE2_OUT, PE2_IN, PE2_IN_PU,
- PE1_FN, PE1_OUT, PE1_IN, PE1_IN_PU,
- PE0_FN, PE0_OUT, PE0_IN, PE0_IN_PU }
- },
- { PINMUX_CFG_REG("PFCR", 0xffe7000a, 16, 2) {
- PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
- PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
- PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
- PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
- PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
- PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
- PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
- PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU }
- },
- { PINMUX_CFG_REG("PGCR", 0xffe7000c, 16, 2) {
- PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
- PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
- PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
- PG4_FN, PG4_OUT, PG4_IN, PG4_IN_PU,
- PG3_FN, PG3_OUT, PG3_IN, PG3_IN_PU,
- PG2_FN, PG2_OUT, PG2_IN, PG2_IN_PU,
- PG1_FN, PG1_OUT, PG1_IN, PG1_IN_PU,
- PG0_FN, PG0_OUT, PG0_IN, PG0_IN_PU }
- },
- { PINMUX_CFG_REG("PHCR", 0xffe7000e, 16, 2) {
- PH7_FN, PH7_OUT, PH7_IN, PH7_IN_PU,
- PH6_FN, PH6_OUT, PH6_IN, PH6_IN_PU,
- PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
- PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
- PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
- PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
- PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
- PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU }
- },
- { PINMUX_CFG_REG("PJCR", 0xffe70010, 16, 2) {
- PJ7_FN, PJ7_OUT, PJ7_IN, PJ7_IN_PU,
- PJ6_FN, PJ6_OUT, PJ6_IN, PJ6_IN_PU,
- PJ5_FN, PJ5_OUT, PJ5_IN, PJ5_IN_PU,
- PJ4_FN, PJ4_OUT, PJ4_IN, PJ4_IN_PU,
- PJ3_FN, PJ3_OUT, PJ3_IN, PJ3_IN_PU,
- PJ2_FN, PJ2_OUT, PJ2_IN, PJ2_IN_PU,
- PJ1_FN, PJ1_OUT, PJ1_IN, PJ1_IN_PU,
- PJ0_FN, PJ0_OUT, PJ0_IN, PJ0_IN_PU }
- },
- { PINMUX_CFG_REG("PKCR", 0xffe70012, 16, 2) {
- PK7_FN, PK7_OUT, PK7_IN, PK7_IN_PU,
- PK6_FN, PK6_OUT, PK6_IN, PK6_IN_PU,
- PK5_FN, PK5_OUT, PK5_IN, PK5_IN_PU,
- PK4_FN, PK4_OUT, PK4_IN, PK4_IN_PU,
- PK3_FN, PK3_OUT, PK3_IN, PK3_IN_PU,
- PK2_FN, PK2_OUT, PK2_IN, PK2_IN_PU,
- PK1_FN, PK1_OUT, PK1_IN, PK1_IN_PU,
- PK0_FN, PK0_OUT, PK0_IN, PK0_IN_PU }
- },
- { PINMUX_CFG_REG("PLCR", 0xffe70014, 16, 2) {
- PL7_FN, PL7_OUT, PL7_IN, PL7_IN_PU,
- PL6_FN, PL6_OUT, PL6_IN, PL6_IN_PU,
- PL5_FN, PL5_OUT, PL5_IN, PL5_IN_PU,
- PL4_FN, PL4_OUT, PL4_IN, PL4_IN_PU,
- PL3_FN, PL3_OUT, PL3_IN, PL3_IN_PU,
- PL2_FN, PL2_OUT, PL2_IN, PL2_IN_PU,
- PL1_FN, PL1_OUT, PL1_IN, PL1_IN_PU,
- PL0_FN, PL0_OUT, PL0_IN, PL0_IN_PU }
- },
- { PINMUX_CFG_REG("PMCR", 0xffe70016, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PM1_FN, PM1_OUT, PM1_IN, PM1_IN_PU,
- PM0_FN, PM0_OUT, PM0_IN, PM0_IN_PU }
- },
- { PINMUX_CFG_REG("PNCR", 0xffe70018, 16, 2) {
- PN7_FN, PN7_OUT, PN7_IN, PN7_IN_PU,
- PN6_FN, PN6_OUT, PN6_IN, PN6_IN_PU,
- PN5_FN, PN5_OUT, PN5_IN, PN5_IN_PU,
- PN4_FN, PN4_OUT, PN4_IN, PN4_IN_PU,
- PN3_FN, PN3_OUT, PN3_IN, PN3_IN_PU,
- PN2_FN, PN2_OUT, PN2_IN, PN2_IN_PU,
- PN1_FN, PN1_OUT, PN1_IN, PN1_IN_PU,
- PN0_FN, PN0_OUT, PN0_IN, PN0_IN_PU }
- },
- { PINMUX_CFG_REG("PPCR", 0xffe7001a, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PP5_FN, PP5_OUT, PP5_IN, PP5_IN_PU,
- PP4_FN, PP4_OUT, PP4_IN, PP4_IN_PU,
- PP3_FN, PP3_OUT, PP3_IN, PP3_IN_PU,
- PP2_FN, PP2_OUT, PP2_IN, PP2_IN_PU,
- PP1_FN, PP1_OUT, PP1_IN, PP1_IN_PU,
- PP0_FN, PP0_OUT, PP0_IN, PP0_IN_PU }
- },
- { PINMUX_CFG_REG("PQCR", 0xffe7001c, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PQ4_FN, PQ4_OUT, PQ4_IN, PQ4_IN_PU,
- PQ3_FN, PQ3_OUT, PQ3_IN, PQ3_IN_PU,
- PQ2_FN, PQ2_OUT, PQ2_IN, PQ2_IN_PU,
- PQ1_FN, PQ1_OUT, PQ1_IN, PQ1_IN_PU,
- PQ0_FN, PQ0_OUT, PQ0_IN, PQ0_IN_PU }
- },
- { PINMUX_CFG_REG("PRCR", 0xffe7001e, 16, 2) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PR3_FN, PR3_OUT, PR3_IN, PR3_IN_PU,
- PR2_FN, PR2_OUT, PR2_IN, PR2_IN_PU,
- PR1_FN, PR1_OUT, PR1_IN, PR1_IN_PU,
- PR0_FN, PR0_OUT, PR0_IN, PR0_IN_PU }
- },
- { PINMUX_CFG_REG("P1MSELR", 0xffe70080, 16, 1) {
- P1MSEL15_0, P1MSEL15_1,
- P1MSEL14_0, P1MSEL14_1,
- P1MSEL13_0, P1MSEL13_1,
- P1MSEL12_0, P1MSEL12_1,
- P1MSEL11_0, P1MSEL11_1,
- P1MSEL10_0, P1MSEL10_1,
- P1MSEL9_0, P1MSEL9_1,
- P1MSEL8_0, P1MSEL8_1,
- P1MSEL7_0, P1MSEL7_1,
- P1MSEL6_0, P1MSEL6_1,
- P1MSEL5_0, 0,
- P1MSEL4_0, P1MSEL4_1,
- P1MSEL3_0, P1MSEL3_1,
- P1MSEL2_0, P1MSEL2_1,
- P1MSEL1_0, P1MSEL1_1,
- P1MSEL0_0, P1MSEL0_1 }
- },
- { PINMUX_CFG_REG("P2MSELR", 0xffe70082, 16, 1) {
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- P2MSEL2_0, P2MSEL2_1,
- P2MSEL1_0, P2MSEL1_1,
- P2MSEL0_0, P2MSEL0_1 }
- },
- {}
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PADR", 0xffe70020, 8) {
- PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
- PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA }
- },
- { PINMUX_DATA_REG("PBDR", 0xffe70022, 8) {
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA }
- },
- { PINMUX_DATA_REG("PCDR", 0xffe70024, 8) {
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
- },
- { PINMUX_DATA_REG("PDDR", 0xffe70026, 8) {
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
- },
- { PINMUX_DATA_REG("PEDR", 0xffe70028, 8) {
- 0, 0, PE5_DATA, PE4_DATA,
- PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
- },
- { PINMUX_DATA_REG("PFDR", 0xffe7002a, 8) {
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
- },
- { PINMUX_DATA_REG("PGDR", 0xffe7002c, 8) {
- PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
- PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
- },
- { PINMUX_DATA_REG("PHDR", 0xffe7002e, 8) {
- PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
- PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA }
- },
- { PINMUX_DATA_REG("PJDR", 0xffe70030, 8) {
- PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
- PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
- },
- { PINMUX_DATA_REG("PKDR", 0xffe70032, 8) {
- PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
- PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA }
- },
- { PINMUX_DATA_REG("PLDR", 0xffe70034, 8) {
- PL7_DATA, PL6_DATA, PL5_DATA, PL4_DATA,
- PL3_DATA, PL2_DATA, PL1_DATA, PL0_DATA }
- },
- { PINMUX_DATA_REG("PMDR", 0xffe70036, 8) {
- 0, 0, 0, 0,
- 0, 0, PM1_DATA, PM0_DATA }
- },
- { PINMUX_DATA_REG("PNDR", 0xffe70038, 8) {
- PN7_DATA, PN6_DATA, PN5_DATA, PN4_DATA,
- PN3_DATA, PN2_DATA, PN1_DATA, PN0_DATA }
- },
- { PINMUX_DATA_REG("PPDR", 0xffe7003a, 8) {
- 0, 0, PP5_DATA, PP4_DATA,
- PP3_DATA, PP2_DATA, PP1_DATA, PP0_DATA }
- },
- { PINMUX_DATA_REG("PQDR", 0xffe7003c, 8) {
- 0, 0, 0, PQ4_DATA,
- PQ3_DATA, PQ2_DATA, PQ1_DATA, PQ0_DATA }
- },
- { PINMUX_DATA_REG("PRDR", 0xffe7003e, 8) {
- 0, 0, 0, 0,
- PR3_DATA, PR2_DATA, PR1_DATA, PR0_DATA }
- },
- { },
-};
-
-static struct pinmux_info sh7785_pinmux_info = {
- .name = "sh7785_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
- .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_PA7,
- .last_gpio = GPIO_FN_IRQOUT,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
+#include <cpu/pfc.h>
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7785_pinmux_info);
+ return sh_pfc_register("pfc-sh7785", NULL, 0);
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7786.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7786.c
index 4229e0724c89..3061778d55da 100644
--- a/arch/sh/kernel/cpu/sh4a/pinmux-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7786.c
@@ -15,829 +15,11 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/sh7786.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
- PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
- PE7_DATA, PE6_DATA,
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
- PG7_DATA, PG6_DATA, PG5_DATA,
- PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
- PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
- PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
- PJ3_DATA, PJ2_DATA, PJ1_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- PA7_IN, PA6_IN, PA5_IN, PA4_IN,
- PA3_IN, PA2_IN, PA1_IN, PA0_IN,
- PB7_IN, PB6_IN, PB5_IN, PB4_IN,
- PB3_IN, PB2_IN, PB1_IN, PB0_IN,
- PC7_IN, PC6_IN, PC5_IN, PC4_IN,
- PC3_IN, PC2_IN, PC1_IN, PC0_IN,
- PD7_IN, PD6_IN, PD5_IN, PD4_IN,
- PD3_IN, PD2_IN, PD1_IN, PD0_IN,
- PE7_IN, PE6_IN,
- PF7_IN, PF6_IN, PF5_IN, PF4_IN,
- PF3_IN, PF2_IN, PF1_IN, PF0_IN,
- PG7_IN, PG6_IN, PG5_IN,
- PH7_IN, PH6_IN, PH5_IN, PH4_IN,
- PH3_IN, PH2_IN, PH1_IN, PH0_IN,
- PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
- PJ3_IN, PJ2_IN, PJ1_IN,
- PINMUX_INPUT_END,
-
- PINMUX_INPUT_PULLUP_BEGIN,
- PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
- PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
- PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
- PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
- PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
- PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
- PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
- PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
- PE7_IN_PU, PE6_IN_PU,
- PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
- PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
- PG7_IN_PU, PG6_IN_PU, PG5_IN_PU,
- PH7_IN_PU, PH6_IN_PU, PH5_IN_PU, PH4_IN_PU,
- PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
- PJ7_IN_PU, PJ6_IN_PU, PJ5_IN_PU, PJ4_IN_PU,
- PJ3_IN_PU, PJ2_IN_PU, PJ1_IN_PU,
- PINMUX_INPUT_PULLUP_END,
-
- PINMUX_OUTPUT_BEGIN,
- PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
- PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
- PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
- PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
- PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
- PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
- PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
- PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
- PE7_OUT, PE6_OUT,
- PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
- PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
- PG7_OUT, PG6_OUT, PG5_OUT,
- PH7_OUT, PH6_OUT, PH5_OUT, PH4_OUT,
- PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
- PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
- PJ3_OUT, PJ2_OUT, PJ1_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- PA7_FN, PA6_FN, PA5_FN, PA4_FN,
- PA3_FN, PA2_FN, PA1_FN, PA0_FN,
- PB7_FN, PB6_FN, PB5_FN, PB4_FN,
- PB3_FN, PB2_FN, PB1_FN, PB0_FN,
- PC7_FN, PC6_FN, PC5_FN, PC4_FN,
- PC3_FN, PC2_FN, PC1_FN, PC0_FN,
- PD7_FN, PD6_FN, PD5_FN, PD4_FN,
- PD3_FN, PD2_FN, PD1_FN, PD0_FN,
- PE7_FN, PE6_FN,
- PF7_FN, PF6_FN, PF5_FN, PF4_FN,
- PF3_FN, PF2_FN, PF1_FN, PF0_FN,
- PG7_FN, PG6_FN, PG5_FN,
- PH7_FN, PH6_FN, PH5_FN, PH4_FN,
- PH3_FN, PH2_FN, PH1_FN, PH0_FN,
- PJ7_FN, PJ6_FN, PJ5_FN, PJ4_FN,
- PJ3_FN, PJ2_FN, PJ1_FN,
- P1MSEL14_0, P1MSEL14_1,
- P1MSEL13_0, P1MSEL13_1,
- P1MSEL12_0, P1MSEL12_1,
- P1MSEL11_0, P1MSEL11_1,
- P1MSEL10_0, P1MSEL10_1,
- P1MSEL9_0, P1MSEL9_1,
- P1MSEL8_0, P1MSEL8_1,
- P1MSEL7_0, P1MSEL7_1,
- P1MSEL6_0, P1MSEL6_1,
- P1MSEL5_0, P1MSEL5_1,
- P1MSEL4_0, P1MSEL4_1,
- P1MSEL3_0, P1MSEL3_1,
- P1MSEL2_0, P1MSEL2_1,
- P1MSEL1_0, P1MSEL1_1,
- P1MSEL0_0, P1MSEL0_1,
-
- P2MSEL15_0, P2MSEL15_1,
- P2MSEL14_0, P2MSEL14_1,
- P2MSEL13_0, P2MSEL13_1,
- P2MSEL12_0, P2MSEL12_1,
- P2MSEL11_0, P2MSEL11_1,
- P2MSEL10_0, P2MSEL10_1,
- P2MSEL9_0, P2MSEL9_1,
- P2MSEL8_0, P2MSEL8_1,
- P2MSEL7_0, P2MSEL7_1,
- P2MSEL6_0, P2MSEL6_1,
- P2MSEL5_0, P2MSEL5_1,
- P2MSEL4_0, P2MSEL4_1,
- P2MSEL3_0, P2MSEL3_1,
- P2MSEL2_0, P2MSEL2_1,
- P2MSEL1_0, P2MSEL1_1,
- P2MSEL0_0, P2MSEL0_1,
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
- DCLKIN_MARK, DCLKOUT_MARK, ODDF_MARK,
- VSYNC_MARK, HSYNC_MARK, CDE_MARK, DISP_MARK,
- DR0_MARK, DR1_MARK, DR2_MARK, DR3_MARK, DR4_MARK, DR5_MARK,
- DG0_MARK, DG1_MARK, DG2_MARK, DG3_MARK, DG4_MARK, DG5_MARK,
- DB0_MARK, DB1_MARK, DB2_MARK, DB3_MARK, DB4_MARK, DB5_MARK,
- ETH_MAGIC_MARK, ETH_LINK_MARK, ETH_TX_ER_MARK, ETH_TX_EN_MARK,
- ETH_MDIO_MARK, ETH_RX_CLK_MARK, ETH_MDC_MARK, ETH_COL_MARK,
- ETH_TX_CLK_MARK, ETH_CRS_MARK, ETH_RX_DV_MARK, ETH_RX_ER_MARK,
- ETH_TXD3_MARK, ETH_TXD2_MARK, ETH_TXD1_MARK, ETH_TXD0_MARK,
- ETH_RXD3_MARK, ETH_RXD2_MARK, ETH_RXD1_MARK, ETH_RXD0_MARK,
- HSPI_CLK_MARK, HSPI_CS_MARK, HSPI_RX_MARK, HSPI_TX_MARK,
- SCIF0_CTS_MARK, SCIF0_RTS_MARK,
- SCIF0_SCK_MARK, SCIF0_RXD_MARK, SCIF0_TXD_MARK,
- SCIF1_SCK_MARK, SCIF1_RXD_MARK, SCIF1_TXD_MARK,
- SCIF3_SCK_MARK, SCIF3_RXD_MARK, SCIF3_TXD_MARK,
- SCIF4_SCK_MARK, SCIF4_RXD_MARK, SCIF4_TXD_MARK,
- SCIF5_SCK_MARK, SCIF5_RXD_MARK, SCIF5_TXD_MARK,
- BREQ_MARK, IOIS16_MARK, CE2B_MARK, CE2A_MARK, BACK_MARK,
- FALE_MARK, FRB_MARK, FSTATUS_MARK,
- FSE_MARK, FCLE_MARK,
- DACK0_MARK, DACK1_MARK, DACK2_MARK, DACK3_MARK,
- DREQ0_MARK, DREQ1_MARK, DREQ2_MARK, DREQ3_MARK,
- DRAK0_MARK, DRAK1_MARK, DRAK2_MARK, DRAK3_MARK,
- USB_OVC1_MARK, USB_OVC0_MARK,
- USB_PENC1_MARK, USB_PENC0_MARK,
- HAC_RES_MARK,
- HAC1_SDOUT_MARK, HAC1_SDIN_MARK, HAC1_SYNC_MARK, HAC1_BITCLK_MARK,
- HAC0_SDOUT_MARK, HAC0_SDIN_MARK, HAC0_SYNC_MARK, HAC0_BITCLK_MARK,
- SSI0_SDATA_MARK, SSI0_SCK_MARK, SSI0_WS_MARK, SSI0_CLK_MARK,
- SSI1_SDATA_MARK, SSI1_SCK_MARK, SSI1_WS_MARK, SSI1_CLK_MARK,
- SSI2_SDATA_MARK, SSI2_SCK_MARK, SSI2_WS_MARK,
- SSI3_SDATA_MARK, SSI3_SCK_MARK, SSI3_WS_MARK,
- SDIF1CMD_MARK, SDIF1CD_MARK, SDIF1WP_MARK, SDIF1CLK_MARK,
- SDIF1D3_MARK, SDIF1D2_MARK, SDIF1D1_MARK, SDIF1D0_MARK,
- SDIF0CMD_MARK, SDIF0CD_MARK, SDIF0WP_MARK, SDIF0CLK_MARK,
- SDIF0D3_MARK, SDIF0D2_MARK, SDIF0D1_MARK, SDIF0D0_MARK,
- TCLK_MARK,
- IRL7_MARK, IRL6_MARK, IRL5_MARK, IRL4_MARK,
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t pinmux_data[] = {
-
- /* PA GPIO */
- PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
- PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
- PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
- PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
- PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
- PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
- PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
- PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
-
- /* PB GPIO */
- PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
- PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
- PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
- PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
- PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
- PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
- PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
- PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
-
- /* PC GPIO */
- PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
- PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
- PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
- PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
- PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
- PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
- PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
- PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
-
- /* PD GPIO */
- PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
- PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
- PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
- PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
- PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
- PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
- PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
- PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
-
- /* PE GPIO */
- PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
- PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
-
- /* PF GPIO */
- PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
- PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
- PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
- PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
- PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
- PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
- PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
- PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
-
- /* PG GPIO */
- PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
- PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
- PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
-
- /* PH GPIO */
- PINMUX_DATA(PH7_DATA, PH7_IN, PH7_OUT, PH7_IN_PU),
- PINMUX_DATA(PH6_DATA, PH6_IN, PH6_OUT, PH6_IN_PU),
- PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
- PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
- PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
- PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
- PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
- PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
-
- /* PJ GPIO */
- PINMUX_DATA(PJ7_DATA, PJ7_IN, PJ7_OUT, PJ7_IN_PU),
- PINMUX_DATA(PJ6_DATA, PJ6_IN, PJ6_OUT, PJ6_IN_PU),
- PINMUX_DATA(PJ5_DATA, PJ5_IN, PJ5_OUT, PJ5_IN_PU),
- PINMUX_DATA(PJ4_DATA, PJ4_IN, PJ4_OUT, PJ4_IN_PU),
- PINMUX_DATA(PJ3_DATA, PJ3_IN, PJ3_OUT, PJ3_IN_PU),
- PINMUX_DATA(PJ2_DATA, PJ2_IN, PJ2_OUT, PJ2_IN_PU),
- PINMUX_DATA(PJ1_DATA, PJ1_IN, PJ1_OUT, PJ1_IN_PU),
-
- /* PA FN */
- PINMUX_DATA(CDE_MARK, P1MSEL2_0, PA7_FN),
- PINMUX_DATA(DISP_MARK, P1MSEL2_0, PA6_FN),
- PINMUX_DATA(DR5_MARK, P1MSEL2_0, PA5_FN),
- PINMUX_DATA(DR4_MARK, P1MSEL2_0, PA4_FN),
- PINMUX_DATA(DR3_MARK, P1MSEL2_0, PA3_FN),
- PINMUX_DATA(DR2_MARK, P1MSEL2_0, PA2_FN),
- PINMUX_DATA(DR1_MARK, P1MSEL2_0, PA1_FN),
- PINMUX_DATA(DR0_MARK, P1MSEL2_0, PA0_FN),
- PINMUX_DATA(ETH_MAGIC_MARK, P1MSEL2_1, PA7_FN),
- PINMUX_DATA(ETH_LINK_MARK, P1MSEL2_1, PA6_FN),
- PINMUX_DATA(ETH_TX_ER_MARK, P1MSEL2_1, PA5_FN),
- PINMUX_DATA(ETH_TX_EN_MARK, P1MSEL2_1, PA4_FN),
- PINMUX_DATA(ETH_TXD3_MARK, P1MSEL2_1, PA3_FN),
- PINMUX_DATA(ETH_TXD2_MARK, P1MSEL2_1, PA2_FN),
- PINMUX_DATA(ETH_TXD1_MARK, P1MSEL2_1, PA1_FN),
- PINMUX_DATA(ETH_TXD0_MARK, P1MSEL2_1, PA0_FN),
-
- /* PB FN */
- PINMUX_DATA(VSYNC_MARK, P1MSEL3_0, PB7_FN),
- PINMUX_DATA(ODDF_MARK, P1MSEL3_0, PB6_FN),
- PINMUX_DATA(DG5_MARK, P1MSEL2_0, PB5_FN),
- PINMUX_DATA(DG4_MARK, P1MSEL2_0, PB4_FN),
- PINMUX_DATA(DG3_MARK, P1MSEL2_0, PB3_FN),
- PINMUX_DATA(DG2_MARK, P1MSEL2_0, PB2_FN),
- PINMUX_DATA(DG1_MARK, P1MSEL2_0, PB1_FN),
- PINMUX_DATA(DG0_MARK, P1MSEL2_0, PB0_FN),
- PINMUX_DATA(HSPI_CLK_MARK, P1MSEL3_1, PB7_FN),
- PINMUX_DATA(HSPI_CS_MARK, P1MSEL3_1, PB6_FN),
- PINMUX_DATA(ETH_MDIO_MARK, P1MSEL2_1, PB5_FN),
- PINMUX_DATA(ETH_RX_CLK_MARK, P1MSEL2_1, PB4_FN),
- PINMUX_DATA(ETH_MDC_MARK, P1MSEL2_1, PB3_FN),
- PINMUX_DATA(ETH_COL_MARK, P1MSEL2_1, PB2_FN),
- PINMUX_DATA(ETH_TX_CLK_MARK, P1MSEL2_1, PB1_FN),
- PINMUX_DATA(ETH_CRS_MARK, P1MSEL2_1, PB0_FN),
-
- /* PC FN */
- PINMUX_DATA(DCLKIN_MARK, P1MSEL3_0, PC7_FN),
- PINMUX_DATA(HSYNC_MARK, P1MSEL3_0, PC6_FN),
- PINMUX_DATA(DB5_MARK, P1MSEL2_0, PC5_FN),
- PINMUX_DATA(DB4_MARK, P1MSEL2_0, PC4_FN),
- PINMUX_DATA(DB3_MARK, P1MSEL2_0, PC3_FN),
- PINMUX_DATA(DB2_MARK, P1MSEL2_0, PC2_FN),
- PINMUX_DATA(DB1_MARK, P1MSEL2_0, PC1_FN),
- PINMUX_DATA(DB0_MARK, P1MSEL2_0, PC0_FN),
-
- PINMUX_DATA(HSPI_RX_MARK, P1MSEL3_1, PC7_FN),
- PINMUX_DATA(HSPI_TX_MARK, P1MSEL3_1, PC6_FN),
- PINMUX_DATA(ETH_RXD3_MARK, P1MSEL2_1, PC5_FN),
- PINMUX_DATA(ETH_RXD2_MARK, P1MSEL2_1, PC4_FN),
- PINMUX_DATA(ETH_RXD1_MARK, P1MSEL2_1, PC3_FN),
- PINMUX_DATA(ETH_RXD0_MARK, P1MSEL2_1, PC2_FN),
- PINMUX_DATA(ETH_RX_DV_MARK, P1MSEL2_1, PC1_FN),
- PINMUX_DATA(ETH_RX_ER_MARK, P1MSEL2_1, PC0_FN),
-
- /* PD FN */
- PINMUX_DATA(DCLKOUT_MARK, PD7_FN),
- PINMUX_DATA(SCIF1_SCK_MARK, PD6_FN),
- PINMUX_DATA(SCIF1_RXD_MARK, PD5_FN),
- PINMUX_DATA(SCIF1_TXD_MARK, PD4_FN),
- PINMUX_DATA(DACK1_MARK, P1MSEL13_1, P1MSEL12_0, PD3_FN),
- PINMUX_DATA(BACK_MARK, P1MSEL13_0, P1MSEL12_1, PD3_FN),
- PINMUX_DATA(FALE_MARK, P1MSEL13_0, P1MSEL12_0, PD3_FN),
- PINMUX_DATA(DACK0_MARK, P1MSEL14_1, PD2_FN),
- PINMUX_DATA(FCLE_MARK, P1MSEL14_0, PD2_FN),
- PINMUX_DATA(DREQ1_MARK, P1MSEL10_0, P1MSEL9_1, PD1_FN),
- PINMUX_DATA(BREQ_MARK, P1MSEL10_1, P1MSEL9_0, PD1_FN),
- PINMUX_DATA(USB_OVC1_MARK, P1MSEL10_0, P1MSEL9_0, PD1_FN),
- PINMUX_DATA(DREQ0_MARK, P1MSEL11_1, PD0_FN),
- PINMUX_DATA(USB_OVC0_MARK, P1MSEL11_0, PD0_FN),
-
- /* PE FN */
- PINMUX_DATA(USB_PENC1_MARK, PE7_FN),
- PINMUX_DATA(USB_PENC0_MARK, PE6_FN),
-
- /* PF FN */
- PINMUX_DATA(HAC1_SDOUT_MARK, P2MSEL15_0, P2MSEL14_0, PF7_FN),
- PINMUX_DATA(HAC1_SDIN_MARK, P2MSEL15_0, P2MSEL14_0, PF6_FN),
- PINMUX_DATA(HAC1_SYNC_MARK, P2MSEL15_0, P2MSEL14_0, PF5_FN),
- PINMUX_DATA(HAC1_BITCLK_MARK, P2MSEL15_0, P2MSEL14_0, PF4_FN),
- PINMUX_DATA(HAC0_SDOUT_MARK, P2MSEL13_0, P2MSEL12_0, PF3_FN),
- PINMUX_DATA(HAC0_SDIN_MARK, P2MSEL13_0, P2MSEL12_0, PF2_FN),
- PINMUX_DATA(HAC0_SYNC_MARK, P2MSEL13_0, P2MSEL12_0, PF1_FN),
- PINMUX_DATA(HAC0_BITCLK_MARK, P2MSEL13_0, P2MSEL12_0, PF0_FN),
- PINMUX_DATA(SSI1_SDATA_MARK, P2MSEL15_0, P2MSEL14_1, PF7_FN),
- PINMUX_DATA(SSI1_SCK_MARK, P2MSEL15_0, P2MSEL14_1, PF6_FN),
- PINMUX_DATA(SSI1_WS_MARK, P2MSEL15_0, P2MSEL14_1, PF5_FN),
- PINMUX_DATA(SSI1_CLK_MARK, P2MSEL15_0, P2MSEL14_1, PF4_FN),
- PINMUX_DATA(SSI0_SDATA_MARK, P2MSEL13_0, P2MSEL12_1, PF3_FN),
- PINMUX_DATA(SSI0_SCK_MARK, P2MSEL13_0, P2MSEL12_1, PF2_FN),
- PINMUX_DATA(SSI0_WS_MARK, P2MSEL13_0, P2MSEL12_1, PF1_FN),
- PINMUX_DATA(SSI0_CLK_MARK, P2MSEL13_0, P2MSEL12_1, PF0_FN),
- PINMUX_DATA(SDIF1CMD_MARK, P2MSEL15_1, P2MSEL14_0, PF7_FN),
- PINMUX_DATA(SDIF1CD_MARK, P2MSEL15_1, P2MSEL14_0, PF6_FN),
- PINMUX_DATA(SDIF1WP_MARK, P2MSEL15_1, P2MSEL14_0, PF5_FN),
- PINMUX_DATA(SDIF1CLK_MARK, P2MSEL15_1, P2MSEL14_0, PF4_FN),
- PINMUX_DATA(SDIF1D3_MARK, P2MSEL13_1, P2MSEL12_0, PF3_FN),
- PINMUX_DATA(SDIF1D2_MARK, P2MSEL13_1, P2MSEL12_0, PF2_FN),
- PINMUX_DATA(SDIF1D1_MARK, P2MSEL13_1, P2MSEL12_0, PF1_FN),
- PINMUX_DATA(SDIF1D0_MARK, P2MSEL13_1, P2MSEL12_0, PF0_FN),
-
- /* PG FN */
- PINMUX_DATA(SCIF3_SCK_MARK, P1MSEL8_0, PG7_FN),
- PINMUX_DATA(SSI2_SDATA_MARK, P1MSEL8_1, PG7_FN),
- PINMUX_DATA(SCIF3_RXD_MARK, P1MSEL7_0, P1MSEL6_0, PG6_FN),
- PINMUX_DATA(SSI2_SCK_MARK, P1MSEL7_1, P1MSEL6_0, PG6_FN),
- PINMUX_DATA(TCLK_MARK, P1MSEL7_0, P1MSEL6_1, PG6_FN),
- PINMUX_DATA(SCIF3_TXD_MARK, P1MSEL5_0, P1MSEL4_0, PG5_FN),
- PINMUX_DATA(SSI2_WS_MARK, P1MSEL5_1, P1MSEL4_0, PG5_FN),
- PINMUX_DATA(HAC_RES_MARK, P1MSEL5_0, P1MSEL4_1, PG5_FN),
-
- /* PH FN */
- PINMUX_DATA(DACK3_MARK, P2MSEL4_0, PH7_FN),
- PINMUX_DATA(SDIF0CMD_MARK, P2MSEL4_1, PH7_FN),
- PINMUX_DATA(DACK2_MARK, P2MSEL4_0, PH6_FN),
- PINMUX_DATA(SDIF0CD_MARK, P2MSEL4_1, PH6_FN),
- PINMUX_DATA(DREQ3_MARK, P2MSEL4_0, PH5_FN),
- PINMUX_DATA(SDIF0WP_MARK, P2MSEL4_1, PH5_FN),
- PINMUX_DATA(DREQ2_MARK, P2MSEL3_0, P2MSEL2_1, PH4_FN),
- PINMUX_DATA(SDIF0CLK_MARK, P2MSEL3_1, P2MSEL2_0, PH4_FN),
- PINMUX_DATA(SCIF0_CTS_MARK, P2MSEL3_0, P2MSEL2_0, PH4_FN),
- PINMUX_DATA(SDIF0D3_MARK, P2MSEL1_1, P2MSEL0_0, PH3_FN),
- PINMUX_DATA(SCIF0_RTS_MARK, P2MSEL1_0, P2MSEL0_0, PH3_FN),
- PINMUX_DATA(IRL7_MARK, P2MSEL1_0, P2MSEL0_1, PH3_FN),
- PINMUX_DATA(SDIF0D2_MARK, P2MSEL1_1, P2MSEL0_0, PH2_FN),
- PINMUX_DATA(SCIF0_SCK_MARK, P2MSEL1_0, P2MSEL0_0, PH2_FN),
- PINMUX_DATA(IRL6_MARK, P2MSEL1_0, P2MSEL0_1, PH2_FN),
- PINMUX_DATA(SDIF0D1_MARK, P2MSEL1_1, P2MSEL0_0, PH1_FN),
- PINMUX_DATA(SCIF0_RXD_MARK, P2MSEL1_0, P2MSEL0_0, PH1_FN),
- PINMUX_DATA(IRL5_MARK, P2MSEL1_0, P2MSEL0_1, PH1_FN),
- PINMUX_DATA(SDIF0D0_MARK, P2MSEL1_1, P2MSEL0_0, PH0_FN),
- PINMUX_DATA(SCIF0_TXD_MARK, P2MSEL1_0, P2MSEL0_0, PH0_FN),
- PINMUX_DATA(IRL4_MARK, P2MSEL1_0, P2MSEL0_1, PH0_FN),
-
- /* PJ FN */
- PINMUX_DATA(SCIF5_SCK_MARK, P2MSEL11_1, PJ7_FN),
- PINMUX_DATA(FRB_MARK, P2MSEL11_0, PJ7_FN),
- PINMUX_DATA(SCIF5_RXD_MARK, P2MSEL10_0, PJ6_FN),
- PINMUX_DATA(IOIS16_MARK, P2MSEL10_1, PJ6_FN),
- PINMUX_DATA(SCIF5_TXD_MARK, P2MSEL10_0, PJ5_FN),
- PINMUX_DATA(CE2B_MARK, P2MSEL10_1, PJ5_FN),
- PINMUX_DATA(DRAK3_MARK, P2MSEL7_0, PJ4_FN),
- PINMUX_DATA(CE2A_MARK, P2MSEL7_1, PJ4_FN),
- PINMUX_DATA(SCIF4_SCK_MARK, P2MSEL9_0, P2MSEL8_0, PJ3_FN),
- PINMUX_DATA(DRAK2_MARK, P2MSEL9_0, P2MSEL8_1, PJ3_FN),
- PINMUX_DATA(SSI3_WS_MARK, P2MSEL9_1, P2MSEL8_0, PJ3_FN),
- PINMUX_DATA(SCIF4_RXD_MARK, P2MSEL6_1, P2MSEL5_0, PJ2_FN),
- PINMUX_DATA(DRAK1_MARK, P2MSEL6_0, P2MSEL5_1, PJ2_FN),
- PINMUX_DATA(FSTATUS_MARK, P2MSEL6_0, P2MSEL5_0, PJ2_FN),
- PINMUX_DATA(SSI3_SDATA_MARK, P2MSEL6_1, P2MSEL5_1, PJ2_FN),
- PINMUX_DATA(SCIF4_TXD_MARK, P2MSEL6_1, P2MSEL5_0, PJ1_FN),
- PINMUX_DATA(DRAK0_MARK, P2MSEL6_0, P2MSEL5_1, PJ1_FN),
- PINMUX_DATA(FSE_MARK, P2MSEL6_0, P2MSEL5_0, PJ1_FN),
- PINMUX_DATA(SSI3_SCK_MARK, P2MSEL6_1, P2MSEL5_1, PJ1_FN),
-};
-
-static struct pinmux_gpio pinmux_gpios[] = {
- /* PA */
- PINMUX_GPIO(GPIO_PA7, PA7_DATA),
- PINMUX_GPIO(GPIO_PA6, PA6_DATA),
- PINMUX_GPIO(GPIO_PA5, PA5_DATA),
- PINMUX_GPIO(GPIO_PA4, PA4_DATA),
- PINMUX_GPIO(GPIO_PA3, PA3_DATA),
- PINMUX_GPIO(GPIO_PA2, PA2_DATA),
- PINMUX_GPIO(GPIO_PA1, PA1_DATA),
- PINMUX_GPIO(GPIO_PA0, PA0_DATA),
-
- /* PB */
- PINMUX_GPIO(GPIO_PB7, PB7_DATA),
- PINMUX_GPIO(GPIO_PB6, PB6_DATA),
- PINMUX_GPIO(GPIO_PB5, PB5_DATA),
- PINMUX_GPIO(GPIO_PB4, PB4_DATA),
- PINMUX_GPIO(GPIO_PB3, PB3_DATA),
- PINMUX_GPIO(GPIO_PB2, PB2_DATA),
- PINMUX_GPIO(GPIO_PB1, PB1_DATA),
- PINMUX_GPIO(GPIO_PB0, PB0_DATA),
-
- /* PC */
- PINMUX_GPIO(GPIO_PC7, PC7_DATA),
- PINMUX_GPIO(GPIO_PC6, PC6_DATA),
- PINMUX_GPIO(GPIO_PC5, PC5_DATA),
- PINMUX_GPIO(GPIO_PC4, PC4_DATA),
- PINMUX_GPIO(GPIO_PC3, PC3_DATA),
- PINMUX_GPIO(GPIO_PC2, PC2_DATA),
- PINMUX_GPIO(GPIO_PC1, PC1_DATA),
- PINMUX_GPIO(GPIO_PC0, PC0_DATA),
-
- /* PD */
- PINMUX_GPIO(GPIO_PD7, PD7_DATA),
- PINMUX_GPIO(GPIO_PD6, PD6_DATA),
- PINMUX_GPIO(GPIO_PD5, PD5_DATA),
- PINMUX_GPIO(GPIO_PD4, PD4_DATA),
- PINMUX_GPIO(GPIO_PD3, PD3_DATA),
- PINMUX_GPIO(GPIO_PD2, PD2_DATA),
- PINMUX_GPIO(GPIO_PD1, PD1_DATA),
- PINMUX_GPIO(GPIO_PD0, PD0_DATA),
-
- /* PE */
- PINMUX_GPIO(GPIO_PE5, PE7_DATA),
- PINMUX_GPIO(GPIO_PE4, PE6_DATA),
-
- /* PF */
- PINMUX_GPIO(GPIO_PF7, PF7_DATA),
- PINMUX_GPIO(GPIO_PF6, PF6_DATA),
- PINMUX_GPIO(GPIO_PF5, PF5_DATA),
- PINMUX_GPIO(GPIO_PF4, PF4_DATA),
- PINMUX_GPIO(GPIO_PF3, PF3_DATA),
- PINMUX_GPIO(GPIO_PF2, PF2_DATA),
- PINMUX_GPIO(GPIO_PF1, PF1_DATA),
- PINMUX_GPIO(GPIO_PF0, PF0_DATA),
-
- /* PG */
- PINMUX_GPIO(GPIO_PG7, PG7_DATA),
- PINMUX_GPIO(GPIO_PG6, PG6_DATA),
- PINMUX_GPIO(GPIO_PG5, PG5_DATA),
-
- /* PH */
- PINMUX_GPIO(GPIO_PH7, PH7_DATA),
- PINMUX_GPIO(GPIO_PH6, PH6_DATA),
- PINMUX_GPIO(GPIO_PH5, PH5_DATA),
- PINMUX_GPIO(GPIO_PH4, PH4_DATA),
- PINMUX_GPIO(GPIO_PH3, PH3_DATA),
- PINMUX_GPIO(GPIO_PH2, PH2_DATA),
- PINMUX_GPIO(GPIO_PH1, PH1_DATA),
- PINMUX_GPIO(GPIO_PH0, PH0_DATA),
-
- /* PJ */
- PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
- PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
- PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
- PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
- PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
- PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
- PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
-
- /* FN */
- PINMUX_GPIO(GPIO_FN_CDE, CDE_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_MAGIC, ETH_MAGIC_MARK),
- PINMUX_GPIO(GPIO_FN_DISP, DISP_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_LINK, ETH_LINK_MARK),
- PINMUX_GPIO(GPIO_FN_DR5, DR5_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_TX_ER, ETH_TX_ER_MARK),
- PINMUX_GPIO(GPIO_FN_DR4, DR4_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_TX_EN, ETH_TX_EN_MARK),
- PINMUX_GPIO(GPIO_FN_DR3, DR3_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_TXD3, ETH_TXD3_MARK),
- PINMUX_GPIO(GPIO_FN_DR2, DR2_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_TXD2, ETH_TXD2_MARK),
- PINMUX_GPIO(GPIO_FN_DR1, DR1_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_TXD1, ETH_TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_DR0, DR0_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_TXD0, ETH_TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_VSYNC, VSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_HSPI_CLK, HSPI_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_ODDF, ODDF_MARK),
- PINMUX_GPIO(GPIO_FN_HSPI_CS, HSPI_CS_MARK),
- PINMUX_GPIO(GPIO_FN_DG5, DG5_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_MDIO, ETH_MDIO_MARK),
- PINMUX_GPIO(GPIO_FN_DG4, DG4_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_RX_CLK, ETH_RX_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_DG3, DG3_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_MDC, ETH_MDC_MARK),
- PINMUX_GPIO(GPIO_FN_DG2, DG2_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_COL, ETH_COL_MARK),
- PINMUX_GPIO(GPIO_FN_DG1, DG1_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_TX_CLK, ETH_TX_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_DG0, DG0_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_CRS, ETH_CRS_MARK),
- PINMUX_GPIO(GPIO_FN_DCLKIN, DCLKIN_MARK),
- PINMUX_GPIO(GPIO_FN_HSPI_RX, HSPI_RX_MARK),
- PINMUX_GPIO(GPIO_FN_HSYNC, HSYNC_MARK),
- PINMUX_GPIO(GPIO_FN_HSPI_TX, HSPI_TX_MARK),
- PINMUX_GPIO(GPIO_FN_DB5, DB5_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_RXD3, ETH_RXD3_MARK),
- PINMUX_GPIO(GPIO_FN_DB4, DB4_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_RXD2, ETH_RXD2_MARK),
- PINMUX_GPIO(GPIO_FN_DB3, DB3_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_RXD1, ETH_RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_DB2, DB2_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_RXD0, ETH_RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_DB1, DB1_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_RX_DV, ETH_RX_DV_MARK),
- PINMUX_GPIO(GPIO_FN_DB0, DB0_MARK),
- PINMUX_GPIO(GPIO_FN_ETH_RX_ER, ETH_RX_ER_MARK),
- PINMUX_GPIO(GPIO_FN_DCLKOUT, DCLKOUT_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_SCK, SCIF1_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_RXD, SCIF1_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF1_TXD, SCIF1_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
- PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
- PINMUX_GPIO(GPIO_FN_FALE, FALE_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
- PINMUX_GPIO(GPIO_FN_FCLE, FCLE_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
- PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
- PINMUX_GPIO(GPIO_FN_USB_OVC1, USB_OVC1_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
- PINMUX_GPIO(GPIO_FN_USB_OVC0, USB_OVC0_MARK),
- PINMUX_GPIO(GPIO_FN_USB_PENC1, USB_PENC1_MARK),
- PINMUX_GPIO(GPIO_FN_USB_PENC0, USB_PENC0_MARK),
- PINMUX_GPIO(GPIO_FN_HAC1_SDOUT, HAC1_SDOUT_MARK),
- PINMUX_GPIO(GPIO_FN_SSI1_SDATA, SSI1_SDATA_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF1CMD, SDIF1CMD_MARK),
- PINMUX_GPIO(GPIO_FN_HAC1_SDIN, HAC1_SDIN_MARK),
- PINMUX_GPIO(GPIO_FN_SSI1_SCK, SSI1_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF1CD, SDIF1CD_MARK),
- PINMUX_GPIO(GPIO_FN_HAC1_SYNC, HAC1_SYNC_MARK),
- PINMUX_GPIO(GPIO_FN_SSI1_WS, SSI1_WS_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF1WP, SDIF1WP_MARK),
- PINMUX_GPIO(GPIO_FN_HAC1_BITCLK, HAC1_BITCLK_MARK),
- PINMUX_GPIO(GPIO_FN_SSI1_CLK, SSI1_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF1CLK, SDIF1CLK_MARK),
- PINMUX_GPIO(GPIO_FN_HAC0_SDOUT, HAC0_SDOUT_MARK),
- PINMUX_GPIO(GPIO_FN_SSI0_SDATA, SSI0_SDATA_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF1D3, SDIF1D3_MARK),
- PINMUX_GPIO(GPIO_FN_HAC0_SDIN, HAC0_SDIN_MARK),
- PINMUX_GPIO(GPIO_FN_SSI0_SCK, SSI0_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF1D2, SDIF1D2_MARK),
- PINMUX_GPIO(GPIO_FN_HAC0_SYNC, HAC0_SYNC_MARK),
- PINMUX_GPIO(GPIO_FN_SSI0_WS, SSI0_WS_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF1D1, SDIF1D1_MARK),
- PINMUX_GPIO(GPIO_FN_HAC0_BITCLK, HAC0_BITCLK_MARK),
- PINMUX_GPIO(GPIO_FN_SSI0_CLK, SSI0_CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF1D0, SDIF1D0_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_SCK, SCIF3_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SSI2_SDATA, SSI2_SDATA_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_RXD, SCIF3_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
- PINMUX_GPIO(GPIO_FN_SSI2_SCK, SSI2_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF3_TXD, SCIF3_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_HAC_RES, HAC_RES_MARK),
- PINMUX_GPIO(GPIO_FN_SSI2_WS, SSI2_WS_MARK),
- PINMUX_GPIO(GPIO_FN_DACK3, DACK3_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF0CMD, SDIF0CMD_MARK),
- PINMUX_GPIO(GPIO_FN_DACK2, DACK2_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF0CD, SDIF0CD_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ3, DREQ3_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF0WP, SDIF0WP_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_CTS, SCIF0_CTS_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ2, DREQ2_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF0CLK, SDIF0CLK_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_RTS, SCIF0_RTS_MARK),
- PINMUX_GPIO(GPIO_FN_IRL7, IRL7_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF0D3, SDIF0D3_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_SCK, SCIF0_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_IRL6, IRL6_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF0D2, SDIF0D2_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_RXD, SCIF0_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_IRL5, IRL5_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF0D1, SDIF0D1_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF0_TXD, SCIF0_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_IRL4, IRL4_MARK),
- PINMUX_GPIO(GPIO_FN_SDIF0D0, SDIF0D0_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_SCK, SCIF5_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_RXD, SCIF5_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF5_TXD, SCIF5_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK3, DRAK3_MARK),
- PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_SCK, SCIF4_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK2, DRAK2_MARK),
- PINMUX_GPIO(GPIO_FN_SSI3_WS, SSI3_WS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_RXD, SCIF4_RXD_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK1, DRAK1_MARK),
- PINMUX_GPIO(GPIO_FN_SSI3_SDATA, SSI3_SDATA_MARK),
- PINMUX_GPIO(GPIO_FN_FSTATUS, FSTATUS_MARK),
- PINMUX_GPIO(GPIO_FN_SCIF4_TXD, SCIF4_TXD_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK0, DRAK0_MARK),
- PINMUX_GPIO(GPIO_FN_SSI3_SCK, SSI3_SCK_MARK),
- PINMUX_GPIO(GPIO_FN_FSE, FSE_MARK),
-};
-
-static struct pinmux_cfg_reg pinmux_config_regs[] = {
- { PINMUX_CFG_REG("PACR", 0xffcc0000, 16, 2) {
- PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
- PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
- PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
- PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
- PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
- PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
- PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
- PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU }
- },
- { PINMUX_CFG_REG("PBCR", 0xffcc0002, 16, 2) {
- PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
- PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
- PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
- PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
- PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
- PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
- PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
- PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU }
- },
- { PINMUX_CFG_REG("PCCR", 0xffcc0004, 16, 2) {
- PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
- PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
- PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
- PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
- PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
- PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
- PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
- PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU }
- },
- { PINMUX_CFG_REG("PDCR", 0xffcc0006, 16, 2) {
- PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
- PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
- PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
- PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
- PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
- PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
- PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
- PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU }
- },
- { PINMUX_CFG_REG("PECR", 0xffcc0008, 16, 2) {
- PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
- PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, }
- },
- { PINMUX_CFG_REG("PFCR", 0xffcc000a, 16, 2) {
- PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
- PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
- PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
- PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
- PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
- PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
- PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
- PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU }
- },
- { PINMUX_CFG_REG("PGCR", 0xffcc000c, 16, 2) {
- PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
- PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
- PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, }
- },
- { PINMUX_CFG_REG("PHCR", 0xffcc000e, 16, 2) {
- PH7_FN, PH7_OUT, PH7_IN, PH7_IN_PU,
- PH6_FN, PH6_OUT, PH6_IN, PH6_IN_PU,
- PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
- PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
- PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
- PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
- PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
- PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU }
- },
- { PINMUX_CFG_REG("PJCR", 0xffcc0010, 16, 2) {
- PJ7_FN, PJ7_OUT, PJ7_IN, PJ7_IN_PU,
- PJ6_FN, PJ6_OUT, PJ6_IN, PJ6_IN_PU,
- PJ5_FN, PJ5_OUT, PJ5_IN, PJ5_IN_PU,
- PJ4_FN, PJ4_OUT, PJ4_IN, PJ4_IN_PU,
- PJ3_FN, PJ3_OUT, PJ3_IN, PJ3_IN_PU,
- PJ2_FN, PJ2_OUT, PJ2_IN, PJ2_IN_PU,
- PJ1_FN, PJ1_OUT, PJ1_IN, PJ1_IN_PU,
- 0, 0, 0, 0, }
- },
- { PINMUX_CFG_REG("P1MSELR", 0xffcc0080, 16, 1) {
- 0, 0,
- P1MSEL14_0, P1MSEL14_1,
- P1MSEL13_0, P1MSEL13_1,
- P1MSEL12_0, P1MSEL12_1,
- P1MSEL11_0, P1MSEL11_1,
- P1MSEL10_0, P1MSEL10_1,
- P1MSEL9_0, P1MSEL9_1,
- P1MSEL8_0, P1MSEL8_1,
- P1MSEL7_0, P1MSEL7_1,
- P1MSEL6_0, P1MSEL6_1,
- P1MSEL5_0, P1MSEL5_1,
- P1MSEL4_0, P1MSEL4_1,
- P1MSEL3_0, P1MSEL3_1,
- P1MSEL2_0, P1MSEL2_1,
- P1MSEL1_0, P1MSEL1_1,
- P1MSEL0_0, P1MSEL0_1 }
- },
- { PINMUX_CFG_REG("P2MSELR", 0xffcc0082, 16, 1) {
- P2MSEL15_0, P2MSEL15_1,
- P2MSEL14_0, P2MSEL14_1,
- P2MSEL13_0, P2MSEL13_1,
- P2MSEL12_0, P2MSEL12_1,
- P2MSEL11_0, P2MSEL11_1,
- P2MSEL10_0, P2MSEL10_1,
- P2MSEL9_0, P2MSEL9_1,
- P2MSEL8_0, P2MSEL8_1,
- P2MSEL7_0, P2MSEL7_1,
- P2MSEL6_0, P2MSEL6_1,
- P2MSEL5_0, P2MSEL5_1,
- P2MSEL4_0, P2MSEL4_1,
- P2MSEL3_0, P2MSEL3_1,
- P2MSEL2_0, P2MSEL2_1,
- P2MSEL1_0, P2MSEL1_1,
- P2MSEL0_0, P2MSEL0_1 }
- },
- {}
-};
-
-static struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PADR", 0xffcc0020, 8) {
- PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
- PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA }
- },
- { PINMUX_DATA_REG("PBDR", 0xffcc0022, 8) {
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA }
- },
- { PINMUX_DATA_REG("PCDR", 0xffcc0024, 8) {
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
- },
- { PINMUX_DATA_REG("PDDR", 0xffcc0026, 8) {
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
- },
- { PINMUX_DATA_REG("PEDR", 0xffcc0028, 8) {
- PE7_DATA, PE6_DATA,
- 0, 0, 0, 0, 0, 0 }
- },
- { PINMUX_DATA_REG("PFDR", 0xffcc002a, 8) {
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
- },
- { PINMUX_DATA_REG("PGDR", 0xffcc002c, 8) {
- PG7_DATA, PG6_DATA, PG5_DATA, 0,
- 0, 0, 0, 0 }
- },
- { PINMUX_DATA_REG("PHDR", 0xffcc002e, 8) {
- PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
- PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA }
- },
- { PINMUX_DATA_REG("PJDR", 0xffcc0030, 8) {
- PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
- PJ3_DATA, PJ2_DATA, PJ1_DATA, 0 }
- },
- { },
-};
-
-static struct pinmux_info sh7786_pinmux_info = {
- .name = "sh7786_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
- .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .first_gpio = GPIO_PA7,
- .last_gpio = GPIO_FN_FSE,
-
- .gpios = pinmux_gpios,
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-};
+#include <cpu/pfc.h>
static int __init plat_pinmux_setup(void)
{
- return register_pinmux(&sh7786_pinmux_info);
+ return sh_pfc_register("pfc-sh7786", NULL, 0);
}
arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c b/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c
index aaa5338abbff..ace84acc55ea 100644
--- a/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c
@@ -9,579 +9,10 @@
*/
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <cpu/shx3.h>
-
-enum {
- PINMUX_RESERVED = 0,
-
- PINMUX_DATA_BEGIN,
- PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
- PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
- PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
- PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
- PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
- PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
-
- PH5_DATA, PH4_DATA,
- PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
- PINMUX_DATA_END,
-
- PINMUX_INPUT_BEGIN,
- PA7_IN, PA6_IN, PA5_IN, PA4_IN,
- PA3_IN, PA2_IN, PA1_IN, PA0_IN,
- PB7_IN, PB6_IN, PB5_IN, PB4_IN,
- PB3_IN, PB2_IN, PB1_IN, PB0_IN,
- PC7_IN, PC6_IN, PC5_IN, PC4_IN,
- PC3_IN, PC2_IN, PC1_IN, PC0_IN,
- PD7_IN, PD6_IN, PD5_IN, PD4_IN,
- PD3_IN, PD2_IN, PD1_IN, PD0_IN,
- PE7_IN, PE6_IN, PE5_IN, PE4_IN,
- PE3_IN, PE2_IN, PE1_IN, PE0_IN,
- PF7_IN, PF6_IN, PF5_IN, PF4_IN,
- PF3_IN, PF2_IN, PF1_IN, PF0_IN,
- PG7_IN, PG6_IN, PG5_IN, PG4_IN,
- PG3_IN, PG2_IN, PG1_IN, PG0_IN,
-
- PH5_IN, PH4_IN,
- PH3_IN, PH2_IN, PH1_IN, PH0_IN,
- PINMUX_INPUT_END,
-
- PINMUX_INPUT_PULLUP_BEGIN,
- PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
- PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
- PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
- PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
- PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
- PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
- PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
- PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
- PE7_IN_PU, PE6_IN_PU, PE5_IN_PU, PE4_IN_PU,
- PE3_IN_PU, PE2_IN_PU, PE1_IN_PU, PE0_IN_PU,
- PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
- PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
- PG7_IN_PU, PG6_IN_PU, PG5_IN_PU, PG4_IN_PU,
- PG3_IN_PU, PG2_IN_PU, PG1_IN_PU, PG0_IN_PU,
-
- PH5_IN_PU, PH4_IN_PU,
- PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
- PINMUX_INPUT_PULLUP_END,
-
- PINMUX_OUTPUT_BEGIN,
- PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
- PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
- PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
- PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
- PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
- PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
- PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
- PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
- PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
- PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
- PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
- PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
- PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
- PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
-
- PH5_OUT, PH4_OUT,
- PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- PA7_FN, PA6_FN, PA5_FN, PA4_FN,
- PA3_FN, PA2_FN, PA1_FN, PA0_FN,
- PB7_FN, PB6_FN, PB5_FN, PB4_FN,
- PB3_FN, PB2_FN, PB1_FN, PB0_FN,
- PC7_FN, PC6_FN, PC5_FN, PC4_FN,
- PC3_FN, PC2_FN, PC1_FN, PC0_FN,
- PD7_FN, PD6_FN, PD5_FN, PD4_FN,
- PD3_FN, PD2_FN, PD1_FN, PD0_FN,
- PE7_FN, PE6_FN, PE5_FN, PE4_FN,
- PE3_FN, PE2_FN, PE1_FN, PE0_FN,
- PF7_FN, PF6_FN, PF5_FN, PF4_FN,
- PF3_FN, PF2_FN, PF1_FN, PF0_FN,
- PG7_FN, PG6_FN, PG5_FN, PG4_FN,
- PG3_FN, PG2_FN, PG1_FN, PG0_FN,
-
- PH5_FN, PH4_FN,
- PH3_FN, PH2_FN, PH1_FN, PH0_FN,
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
-
- D31_MARK, D30_MARK, D29_MARK, D28_MARK, D27_MARK, D26_MARK,
- D25_MARK, D24_MARK, D23_MARK, D22_MARK, D21_MARK, D20_MARK,
- D19_MARK, D18_MARK, D17_MARK, D16_MARK,
-
- BACK_MARK, BREQ_MARK,
- WE3_MARK, WE2_MARK,
- CS6_MARK, CS5_MARK, CS4_MARK,
- CLKOUTENB_MARK,
-
- DACK3_MARK, DACK2_MARK, DACK1_MARK, DACK0_MARK,
- DREQ3_MARK, DREQ2_MARK, DREQ1_MARK, DREQ0_MARK,
-
- IRQ3_MARK, IRQ2_MARK, IRQ1_MARK, IRQ0_MARK,
-
- DRAK3_MARK, DRAK2_MARK, DRAK1_MARK, DRAK0_MARK,
-
- SCK3_MARK, SCK2_MARK, SCK1_MARK, SCK0_MARK,
- IRL3_MARK, IRL2_MARK, IRL1_MARK, IRL0_MARK,
- TXD3_MARK, TXD2_MARK, TXD1_MARK, TXD0_MARK,
- RXD3_MARK, RXD2_MARK, RXD1_MARK, RXD0_MARK,
-
- CE2B_MARK, CE2A_MARK, IOIS16_MARK,
- STATUS1_MARK, STATUS0_MARK,
-
- IRQOUT_MARK,
-
- PINMUX_MARK_END,
-};
-
-static pinmux_enum_t shx3_pinmux_data[] = {
-
- /* PA GPIO */
- PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
- PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
- PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
- PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
- PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
- PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
- PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
- PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
-
- /* PB GPIO */
- PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
- PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
- PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
- PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
- PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
- PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
- PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
- PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
-
- /* PC GPIO */
- PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
- PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
- PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
- PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
- PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
- PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
- PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
- PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
-
- /* PD GPIO */
- PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
- PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
- PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
- PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
- PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
- PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
- PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
- PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
-
- /* PE GPIO */
- PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
- PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
- PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT, PE5_IN_PU),
- PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT, PE4_IN_PU),
- PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT, PE3_IN_PU),
- PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT, PE2_IN_PU),
- PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT, PE1_IN_PU),
- PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT, PE0_IN_PU),
-
- /* PF GPIO */
- PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
- PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
- PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
- PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
- PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
- PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
- PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
- PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
-
- /* PG GPIO */
- PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
- PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
- PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
- PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT, PG4_IN_PU),
- PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT, PG3_IN_PU),
- PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT, PG2_IN_PU),
- PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT, PG1_IN_PU),
- PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT, PG0_IN_PU),
-
- /* PH GPIO */
- PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
- PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
- PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
- PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
- PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
- PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
-
- /* PA FN */
- PINMUX_DATA(D31_MARK, PA7_FN),
- PINMUX_DATA(D30_MARK, PA6_FN),
- PINMUX_DATA(D29_MARK, PA5_FN),
- PINMUX_DATA(D28_MARK, PA4_FN),
- PINMUX_DATA(D27_MARK, PA3_FN),
- PINMUX_DATA(D26_MARK, PA2_FN),
- PINMUX_DATA(D25_MARK, PA1_FN),
- PINMUX_DATA(D24_MARK, PA0_FN),
-
- /* PB FN */
- PINMUX_DATA(D23_MARK, PB7_FN),
- PINMUX_DATA(D22_MARK, PB6_FN),
- PINMUX_DATA(D21_MARK, PB5_FN),
- PINMUX_DATA(D20_MARK, PB4_FN),
- PINMUX_DATA(D19_MARK, PB3_FN),
- PINMUX_DATA(D18_MARK, PB2_FN),
- PINMUX_DATA(D17_MARK, PB1_FN),
- PINMUX_DATA(D16_MARK, PB0_FN),
-
- /* PC FN */
- PINMUX_DATA(BACK_MARK, PC7_FN),
- PINMUX_DATA(BREQ_MARK, PC6_FN),
- PINMUX_DATA(WE3_MARK, PC5_FN),
- PINMUX_DATA(WE2_MARK, PC4_FN),
- PINMUX_DATA(CS6_MARK, PC3_FN),
- PINMUX_DATA(CS5_MARK, PC2_FN),
- PINMUX_DATA(CS4_MARK, PC1_FN),
- PINMUX_DATA(CLKOUTENB_MARK, PC0_FN),
-
- /* PD FN */
- PINMUX_DATA(DACK3_MARK, PD7_FN),
- PINMUX_DATA(DACK2_MARK, PD6_FN),
- PINMUX_DATA(DACK1_MARK, PD5_FN),
- PINMUX_DATA(DACK0_MARK, PD4_FN),
- PINMUX_DATA(DREQ3_MARK, PD3_FN),
- PINMUX_DATA(DREQ2_MARK, PD2_FN),
- PINMUX_DATA(DREQ1_MARK, PD1_FN),
- PINMUX_DATA(DREQ0_MARK, PD0_FN),
-
- /* PE FN */
- PINMUX_DATA(IRQ3_MARK, PE7_FN),
- PINMUX_DATA(IRQ2_MARK, PE6_FN),
- PINMUX_DATA(IRQ1_MARK, PE5_FN),
- PINMUX_DATA(IRQ0_MARK, PE4_FN),
- PINMUX_DATA(DRAK3_MARK, PE3_FN),
- PINMUX_DATA(DRAK2_MARK, PE2_FN),
- PINMUX_DATA(DRAK1_MARK, PE1_FN),
- PINMUX_DATA(DRAK0_MARK, PE0_FN),
-
- /* PF FN */
- PINMUX_DATA(SCK3_MARK, PF7_FN),
- PINMUX_DATA(SCK2_MARK, PF6_FN),
- PINMUX_DATA(SCK1_MARK, PF5_FN),
- PINMUX_DATA(SCK0_MARK, PF4_FN),
- PINMUX_DATA(IRL3_MARK, PF3_FN),
- PINMUX_DATA(IRL2_MARK, PF2_FN),
- PINMUX_DATA(IRL1_MARK, PF1_FN),
- PINMUX_DATA(IRL0_MARK, PF0_FN),
-
- /* PG FN */
- PINMUX_DATA(TXD3_MARK, PG7_FN),
- PINMUX_DATA(TXD2_MARK, PG6_FN),
- PINMUX_DATA(TXD1_MARK, PG5_FN),
- PINMUX_DATA(TXD0_MARK, PG4_FN),
- PINMUX_DATA(RXD3_MARK, PG3_FN),
- PINMUX_DATA(RXD2_MARK, PG2_FN),
- PINMUX_DATA(RXD1_MARK, PG1_FN),
- PINMUX_DATA(RXD0_MARK, PG0_FN),
-
- /* PH FN */
- PINMUX_DATA(CE2B_MARK, PH5_FN),
- PINMUX_DATA(CE2A_MARK, PH4_FN),
- PINMUX_DATA(IOIS16_MARK, PH3_FN),
- PINMUX_DATA(STATUS1_MARK, PH2_FN),
- PINMUX_DATA(STATUS0_MARK, PH1_FN),
- PINMUX_DATA(IRQOUT_MARK, PH0_FN),
-};
-
-static struct pinmux_gpio shx3_pinmux_gpios[] = {
- /* PA */
- PINMUX_GPIO(GPIO_PA7, PA7_DATA),
- PINMUX_GPIO(GPIO_PA6, PA6_DATA),
- PINMUX_GPIO(GPIO_PA5, PA5_DATA),
- PINMUX_GPIO(GPIO_PA4, PA4_DATA),
- PINMUX_GPIO(GPIO_PA3, PA3_DATA),
- PINMUX_GPIO(GPIO_PA2, PA2_DATA),
- PINMUX_GPIO(GPIO_PA1, PA1_DATA),
- PINMUX_GPIO(GPIO_PA0, PA0_DATA),
-
- /* PB */
- PINMUX_GPIO(GPIO_PB7, PB7_DATA),
- PINMUX_GPIO(GPIO_PB6, PB6_DATA),
- PINMUX_GPIO(GPIO_PB5, PB5_DATA),
- PINMUX_GPIO(GPIO_PB4, PB4_DATA),
- PINMUX_GPIO(GPIO_PB3, PB3_DATA),
- PINMUX_GPIO(GPIO_PB2, PB2_DATA),
- PINMUX_GPIO(GPIO_PB1, PB1_DATA),
- PINMUX_GPIO(GPIO_PB0, PB0_DATA),
-
- /* PC */
- PINMUX_GPIO(GPIO_PC7, PC7_DATA),
- PINMUX_GPIO(GPIO_PC6, PC6_DATA),
- PINMUX_GPIO(GPIO_PC5, PC5_DATA),
- PINMUX_GPIO(GPIO_PC4, PC4_DATA),
- PINMUX_GPIO(GPIO_PC3, PC3_DATA),
- PINMUX_GPIO(GPIO_PC2, PC2_DATA),
- PINMUX_GPIO(GPIO_PC1, PC1_DATA),
- PINMUX_GPIO(GPIO_PC0, PC0_DATA),
-
- /* PD */
- PINMUX_GPIO(GPIO_PD7, PD7_DATA),
- PINMUX_GPIO(GPIO_PD6, PD6_DATA),
- PINMUX_GPIO(GPIO_PD5, PD5_DATA),
- PINMUX_GPIO(GPIO_PD4, PD4_DATA),
- PINMUX_GPIO(GPIO_PD3, PD3_DATA),
- PINMUX_GPIO(GPIO_PD2, PD2_DATA),
- PINMUX_GPIO(GPIO_PD1, PD1_DATA),
- PINMUX_GPIO(GPIO_PD0, PD0_DATA),
-
- /* PE */
- PINMUX_GPIO(GPIO_PE7, PE7_DATA),
- PINMUX_GPIO(GPIO_PE6, PE6_DATA),
- PINMUX_GPIO(GPIO_PE5, PE5_DATA),
- PINMUX_GPIO(GPIO_PE4, PE4_DATA),
- PINMUX_GPIO(GPIO_PE3, PE3_DATA),
- PINMUX_GPIO(GPIO_PE2, PE2_DATA),
- PINMUX_GPIO(GPIO_PE1, PE1_DATA),
- PINMUX_GPIO(GPIO_PE0, PE0_DATA),
-
- /* PF */
- PINMUX_GPIO(GPIO_PF7, PF7_DATA),
- PINMUX_GPIO(GPIO_PF6, PF6_DATA),
- PINMUX_GPIO(GPIO_PF5, PF5_DATA),
- PINMUX_GPIO(GPIO_PF4, PF4_DATA),
- PINMUX_GPIO(GPIO_PF3, PF3_DATA),
- PINMUX_GPIO(GPIO_PF2, PF2_DATA),
- PINMUX_GPIO(GPIO_PF1, PF1_DATA),
- PINMUX_GPIO(GPIO_PF0, PF0_DATA),
-
- /* PG */
- PINMUX_GPIO(GPIO_PG7, PG7_DATA),
- PINMUX_GPIO(GPIO_PG6, PG6_DATA),
- PINMUX_GPIO(GPIO_PG5, PG5_DATA),
- PINMUX_GPIO(GPIO_PG4, PG4_DATA),
- PINMUX_GPIO(GPIO_PG3, PG3_DATA),
- PINMUX_GPIO(GPIO_PG2, PG2_DATA),
- PINMUX_GPIO(GPIO_PG1, PG1_DATA),
- PINMUX_GPIO(GPIO_PG0, PG0_DATA),
-
- /* PH */
- PINMUX_GPIO(GPIO_PH5, PH5_DATA),
- PINMUX_GPIO(GPIO_PH4, PH4_DATA),
- PINMUX_GPIO(GPIO_PH3, PH3_DATA),
- PINMUX_GPIO(GPIO_PH2, PH2_DATA),
- PINMUX_GPIO(GPIO_PH1, PH1_DATA),
- PINMUX_GPIO(GPIO_PH0, PH0_DATA),
-
- /* FN */
- PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
- PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
- PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
- PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
- PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
- PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
- PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
- PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
- PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
- PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
- PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
- PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
- PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
- PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
- PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
- PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
- PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
- PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
- PINMUX_GPIO(GPIO_FN_WE3, WE3_MARK),
- PINMUX_GPIO(GPIO_FN_WE2, WE2_MARK),
- PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
- PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
- PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
- PINMUX_GPIO(GPIO_FN_CLKOUTENB, CLKOUTENB_MARK),
- PINMUX_GPIO(GPIO_FN_DACK3, DACK3_MARK),
- PINMUX_GPIO(GPIO_FN_DACK2, DACK2_MARK),
- PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
- PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ3, DREQ3_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ2, DREQ2_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
- PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ3, IRQ3_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
- PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK3, DRAK3_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK2, DRAK2_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK1, DRAK1_MARK),
- PINMUX_GPIO(GPIO_FN_DRAK0, DRAK0_MARK),
- PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
- PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
- PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
- PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
- PINMUX_GPIO(GPIO_FN_IRL3, IRL3_MARK),
- PINMUX_GPIO(GPIO_FN_IRL2, IRL2_MARK),
- PINMUX_GPIO(GPIO_FN_IRL1, IRL1_MARK),
- PINMUX_GPIO(GPIO_FN_IRL0, IRL0_MARK),
- PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
- PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
- PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
- PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
- PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
- PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
- PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
- PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
- PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
- PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
- PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
- PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
- PINMUX_GPIO(GPIO_FN_IRQOUT, IRQOUT_MARK),
-};
-
-static struct pinmux_cfg_reg shx3_pinmux_config_regs[] = {
- { PINMUX_CFG_REG("PABCR", 0xffc70000, 32, 2) {
- PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
- PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
- PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
- PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
- PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
- PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
- PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
- PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU,
- PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
- PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
- PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
- PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
- PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
- PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
- PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
- PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU, },
- },
- { PINMUX_CFG_REG("PCDCR", 0xffc70004, 32, 2) {
- PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
- PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
- PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
- PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
- PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
- PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
- PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
- PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU,
- PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
- PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
- PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
- PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
- PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
- PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
- PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
- PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU, },
- },
- { PINMUX_CFG_REG("PEFCR", 0xffc70008, 32, 2) {
- PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
- PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
- PE5_FN, PE5_OUT, PE5_IN, PE5_IN_PU,
- PE4_FN, PE4_OUT, PE4_IN, PE4_IN_PU,
- PE3_FN, PE3_OUT, PE3_IN, PE3_IN_PU,
- PE2_FN, PE2_OUT, PE2_IN, PE2_IN_PU,
- PE1_FN, PE1_OUT, PE1_IN, PE1_IN_PU,
- PE0_FN, PE0_OUT, PE0_IN, PE0_IN_PU,
- PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
- PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
- PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
- PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
- PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
- PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
- PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
- PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU, },
- },
- { PINMUX_CFG_REG("PGHCR", 0xffc7000c, 32, 2) {
- PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
- PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
- PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
- PG4_FN, PG4_OUT, PG4_IN, PG4_IN_PU,
- PG3_FN, PG3_OUT, PG3_IN, PG3_IN_PU,
- PG2_FN, PG2_OUT, PG2_IN, PG2_IN_PU,
- PG1_FN, PG1_OUT, PG1_IN, PG1_IN_PU,
- PG0_FN, PG0_OUT, PG0_IN, PG0_IN_PU,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
- PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
- PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
- PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
- PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
- PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU, },
- },
- { },
-};
-
-static struct pinmux_data_reg shx3_pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PABDR", 0xffc70010, 32) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
- PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
- PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA, },
- },
- { PINMUX_DATA_REG("PCDDR", 0xffc70014, 32) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
- PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
- PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA, },
- },
- { PINMUX_DATA_REG("PEFDR", 0xffc70018, 32) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
- PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
- 0, 0, 0, 0, 0, 0, 0, 0,
- PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
- PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA, },
- },
- { PINMUX_DATA_REG("PGHDR", 0xffc7001c, 32) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
- PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, PH5_DATA, PH4_DATA,
- PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA, },
- },
- { },
-};
-
-static struct pinmux_info shx3_pinmux_info = {
- .name = "shx3_pfc",
- .reserved_id = PINMUX_RESERVED,
- .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
- .input_pu = { PINMUX_INPUT_PULLUP_BEGIN,
- PINMUX_INPUT_PULLUP_END },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
- .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
- .first_gpio = GPIO_PA7,
- .last_gpio = GPIO_FN_IRQOUT,
- .gpios = shx3_pinmux_gpios,
- .gpio_data = shx3_pinmux_data,
- .gpio_data_size = ARRAY_SIZE(shx3_pinmux_data),
- .cfg_regs = shx3_pinmux_config_regs,
- .data_regs = shx3_pinmux_data_regs,
-};
+#include <cpu/pfc.h>
static int __init shx3_pinmux_setup(void)
{
- return register_pinmux(&shx3_pinmux_info);
+ return sh_pfc_register("pfc-shx3", NULL, 0);
}
arch_initcall(shx3_pinmux_setup);
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 0c910163caa3..3d5a1b387cc0 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -22,7 +22,7 @@
#include <asm/smp.h>
#include <asm/bl_bit.h>
-void (*pm_idle)(void);
+static void (*sh_idle)(void);
static int hlt_counter;
@@ -103,9 +103,9 @@ void cpu_idle(void)
/* Don't trace irqs off for idle */
stop_critical_timings();
if (cpuidle_idle_call())
- pm_idle();
+ sh_idle();
/*
- * Sanity check to ensure that pm_idle() returns
+ * Sanity check to ensure that sh_idle() returns
* with IRQs enabled
*/
WARN_ON(irqs_disabled());
@@ -123,13 +123,13 @@ void __init select_idle_routine(void)
/*
* If a platform has set its own idle routine, leave it alone.
*/
- if (pm_idle)
+ if (sh_idle)
return;
if (hlt_works())
- pm_idle = default_idle;
+ sh_idle = default_idle;
else
- pm_idle = poll_idle;
+ sh_idle = poll_idle;
}
void stop_this_cpu(void *unused)
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index 2f1f65356c0c..6af6e7c5cac8 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -47,60 +47,6 @@ struct fdpic_func_descriptor {
#define UNWINDGUARD 64
/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction __user *act,
- struct old_sigaction __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
-asmlinkage int
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
-{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
-
- return do_sigaltstack(uss, uoss, regs->regs[15]);
-}
-
-
-/*
* Do a signal return; undo the signal stack.
*/
@@ -257,8 +203,7 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL,
- regs->regs[15]) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return r0;
@@ -423,11 +368,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
- err |= __put_user((void *)current->sas_ss_sp,
- &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->regs[15]),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->regs[15]);
err |= setup_sigcontext(&frame->uc.uc_mcontext,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index d867cd95a622..23d4c71c91af 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -128,58 +128,6 @@ static void do_signal(struct pt_regs *regs)
}
/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction __user *act,
- struct old_sigaction __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
-asmlinkage int
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
- unsigned long r4, unsigned long r5, unsigned long r6,
- unsigned long r7,
- struct pt_regs * regs)
-{
- return do_sigaltstack(uss, uoss, REF_REG_SP);
-}
-
-/*
* Do a signal return; undo the signal stack.
*/
struct sigframe {
@@ -364,9 +312,7 @@ asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
goto badframe;
regs->pc -= 4;
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, REF_REG_SP) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return (int) ret;
@@ -560,11 +506,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user((void *)current->sas_ss_sp,
- &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->regs[REG_SP]),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->regs[REG_SP]);
err |= setup_sigcontext(&frame->uc.uc_mcontext,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 72246bc06884..dfdad72c61ca 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -38,7 +38,7 @@ void die(const char *str, struct pt_regs *regs, long err)
notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV);
bust_spinlocks(0);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
spin_unlock_irq(&die_lock);
oops_exit();
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 0f7c852f355c..5a43a871e097 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -83,7 +83,7 @@ config 32BIT
config PMB
bool "Support 32-bit physical addressing through PMB"
- depends on MMU && EXPERIMENTAL && CPU_SH4A && !CPU_SH4AL_DSP
+ depends on MMU && CPU_SH4A && !CPU_SH4AL_DSP
select 32BIT
select UNCACHED_MAPPING
help
@@ -110,7 +110,7 @@ config VSYSCALL
config NUMA
bool "Non Uniform Memory Access (NUMA) Support"
- depends on MMU && SYS_SUPPORTS_NUMA && EXPERIMENTAL
+ depends on MMU && SYS_SUPPORTS_NUMA
select ARCH_WANT_NUMA_VARIABLE_LOCALITY
default n
help
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 82cc576fab15..105794037143 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -558,4 +558,21 @@ int memory_add_physaddr_to_nid(u64 addr)
EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
#endif
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long nr_pages = size >> PAGE_SHIFT;
+ struct zone *zone;
+ int ret;
+
+ zone = page_zone(pfn_to_page(start_pfn));
+ ret = __remove_pages(zone, start_pfn, nr_pages);
+ if (unlikely(ret))
+ pr_warn("%s: Failed, __remove_pages() == %d\n", __func__,
+ ret);
+
+ return ret;
+}
+#endif
#endif /* CONFIG_MEMORY_HOTPLUG */
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 9f2edb5c5551..58fb1e3f631d 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -23,7 +23,6 @@ config SPARC
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select RTC_CLASS
select RTC_DRV_M48T59
- select HAVE_IRQ_WORK
select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG
select HAVE_ARCH_JUMP_LABEL
@@ -41,12 +40,15 @@ config SPARC
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select MODULES_USE_ELF_RELA
+ select ODD_RT_SIGACTION
+ select OLD_SIGSUSPEND
config SPARC32
def_bool !64BIT
select GENERIC_ATOMIC64
select CLZ_TAB
select HAVE_UID16
+ select OLD_SIGACTION
config SPARC64
def_bool 64BIT
@@ -61,6 +63,7 @@ config SPARC64
select HAVE_MEMBLOCK
select HAVE_MEMBLOCK_NODE_MAP
select HAVE_SYSCALL_WRAPPERS
+ select HAVE_ARCH_TRANSPARENT_HUGEPAGE
select HAVE_DYNAMIC_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_SYSCALL_TRACEPOINTS
@@ -543,6 +546,7 @@ config COMPAT
select COMPAT_BINFMT_ELF
select HAVE_UID16
select ARCH_WANT_OLD_COMPAT_IPC
+ select COMPAT_OLD_SIGACTION
config SYSVIPC_COMPAT
bool
diff --git a/arch/sparc/include/asm/compat_signal.h b/arch/sparc/include/asm/compat_signal.h
index b759eab9b51c..9ed1f128b4d1 100644
--- a/arch/sparc/include/asm/compat_signal.h
+++ b/arch/sparc/include/asm/compat_signal.h
@@ -18,12 +18,6 @@ struct __old_sigaction32 {
unsigned int sa_flags;
unsigned sa_restorer; /* not used by Linux/SPARC yet */
};
-
-typedef struct sigaltstack32 {
- u32 ss_sp;
- int ss_flags;
- compat_size_t ss_size;
-} stack_t32;
#endif
#endif /* !(_COMPAT_SIGNAL_H) */
diff --git a/arch/sparc/include/asm/hugetlb.h b/arch/sparc/include/asm/hugetlb.h
index 9661e9bc7bb6..7eb57d245044 100644
--- a/arch/sparc/include/asm/hugetlb.h
+++ b/arch/sparc/include/asm/hugetlb.h
@@ -12,7 +12,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
{
- hugetlb_setup(mm);
}
static inline int is_hugepage_only_range(struct mm_struct *mm,
diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h
index 4b39f74d6ca0..e15538899f3d 100644
--- a/arch/sparc/include/asm/page_64.h
+++ b/arch/sparc/include/asm/page_64.h
@@ -27,8 +27,8 @@
#ifndef __ASSEMBLY__
#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-struct mm_struct;
-extern void hugetlb_setup(struct mm_struct *mm);
+struct pt_regs;
+extern void hugetlb_setup(struct pt_regs *regs);
#endif
#define WANT_PAGE_VIRTUAL
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 7870be0f5adc..08fcce90316b 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -71,7 +71,6 @@
#define PMD_PADDR _AC(0xfffffffe,UL)
#define PMD_PADDR_SHIFT _AC(11,UL)
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define PMD_ISHUGE _AC(0x00000001,UL)
/* This is the PMD layout when PMD_ISHUGE is set. With 4MB huge
@@ -86,7 +85,6 @@
#define PMD_HUGE_ACCESSED _AC(0x00000080,UL)
#define PMD_HUGE_EXEC _AC(0x00000040,UL)
#define PMD_HUGE_SPLITTING _AC(0x00000020,UL)
-#endif
/* PGDs point to PMD tables which are 8K aligned. */
#define PGD_PADDR _AC(0xfffffffc,UL)
@@ -628,6 +626,12 @@ static inline unsigned long pte_special(pte_t pte)
return pte_val(pte) & _PAGE_SPECIAL;
}
+static inline int pmd_large(pmd_t pmd)
+{
+ return (pmd_val(pmd) & (PMD_ISHUGE | PMD_HUGE_PRESENT)) ==
+ (PMD_ISHUGE | PMD_HUGE_PRESENT);
+}
+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static inline int pmd_young(pmd_t pmd)
{
@@ -646,12 +650,6 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
return val >> (PAGE_SHIFT - PMD_PADDR_SHIFT);
}
-static inline int pmd_large(pmd_t pmd)
-{
- return (pmd_val(pmd) & (PMD_ISHUGE | PMD_HUGE_PRESENT)) ==
- (PMD_ISHUGE | PMD_HUGE_PRESENT);
-}
-
static inline int pmd_trans_splitting(pmd_t pmd)
{
return (pmd_val(pmd) & (PMD_ISHUGE|PMD_HUGE_SPLITTING)) ==
diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h
index c1e01914fd98..2c7baa4c4505 100644
--- a/arch/sparc/include/asm/processor_32.h
+++ b/arch/sparc/include/asm/processor_32.h
@@ -118,6 +118,7 @@ extern unsigned long get_wchan(struct task_struct *);
extern struct task_struct *last_task_used_math;
#define cpu_relax() barrier()
+extern void (*sparc_idle)(void);
#endif
diff --git a/arch/sparc/include/asm/signal.h b/arch/sparc/include/asm/signal.h
index 77b85850d543..c33ce3f2ba84 100644
--- a/arch/sparc/include/asm/signal.h
+++ b/arch/sparc/include/asm/signal.h
@@ -21,10 +21,8 @@
*/
#define SA_STATIC_ALLOC 0x8000
-struct k_sigaction {
- struct __new_sigaction sa;
- void __user *ka_restorer;
-};
+#define __ARCH_HAS_KA_RESTORER
+#define __ARCH_HAS_SA_RESTORER
#endif /* !(__ASSEMBLY__) */
#endif /* !(__SPARC_SIGNAL_H) */
diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h
index b4c258de4443..e696432b950d 100644
--- a/arch/sparc/include/asm/tsb.h
+++ b/arch/sparc/include/asm/tsb.h
@@ -157,17 +157,26 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
andn REG2, 0x7, REG2; \
add REG1, REG2, REG1;
- /* This macro exists only to make the PMD translator below easier
- * to read. It hides the ELF section switch for the sun4v code
- * patching.
+ /* These macros exists only to make the PMD translator below
+ * easier to read. It hides the ELF section switch for the
+ * sun4v code patching.
*/
-#define OR_PTE_BIT(REG, NAME) \
+#define OR_PTE_BIT_1INSN(REG, NAME) \
661: or REG, _PAGE_##NAME##_4U, REG; \
.section .sun4v_1insn_patch, "ax"; \
.word 661b; \
or REG, _PAGE_##NAME##_4V, REG; \
.previous;
+#define OR_PTE_BIT_2INSN(REG, TMP, NAME) \
+661: sethi %hi(_PAGE_##NAME##_4U), TMP; \
+ or REG, TMP, REG; \
+ .section .sun4v_2insn_patch, "ax"; \
+ .word 661b; \
+ mov -1, TMP; \
+ or REG, _PAGE_##NAME##_4V, REG; \
+ .previous;
+
/* Load into REG the PTE value for VALID, CACHE, and SZHUGE. */
#define BUILD_PTE_VALID_SZHUGE_CACHE(REG) \
661: sethi %uhi(_PAGE_VALID|_PAGE_SZHUGE_4U), REG; \
@@ -214,12 +223,13 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
andn REG1, PMD_HUGE_PROTBITS, REG2; \
sllx REG2, PMD_PADDR_SHIFT, REG2; \
/* REG2 now holds PFN << PAGE_SHIFT */ \
- andcc REG1, PMD_HUGE_EXEC, %g0; \
- bne,a,pt %xcc, 1f; \
- OR_PTE_BIT(REG2, EXEC); \
-1: andcc REG1, PMD_HUGE_WRITE, %g0; \
+ andcc REG1, PMD_HUGE_WRITE, %g0; \
bne,a,pt %xcc, 1f; \
- OR_PTE_BIT(REG2, W); \
+ OR_PTE_BIT_1INSN(REG2, W); \
+1: andcc REG1, PMD_HUGE_EXEC, %g0; \
+ be,pt %xcc, 1f; \
+ nop; \
+ OR_PTE_BIT_2INSN(REG2, REG1, EXEC); \
/* REG1 can now be clobbered, build final PTE */ \
1: BUILD_PTE_VALID_SZHUGE_CACHE(REG1); \
ba,pt %xcc, PTE_LABEL; \
diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h
index 87ce24c5eb95..5356810bd7e7 100644
--- a/arch/sparc/include/asm/unistd.h
+++ b/arch/sparc/include/asm/unistd.h
@@ -38,14 +38,11 @@
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#ifdef __32bit_syscall_numbers__
#define __ARCH_WANT_SYS_IPC
#else
#define __ARCH_WANT_COMPAT_SYS_TIME
-#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_COMPAT_SYS_SENDFILE
-#define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL
#endif
/*
diff --git a/arch/sparc/include/uapi/asm/signal.h b/arch/sparc/include/uapi/asm/signal.h
index c4ffd6c97106..f387400fcfdf 100644
--- a/arch/sparc/include/uapi/asm/signal.h
+++ b/arch/sparc/include/uapi/asm/signal.h
@@ -153,6 +153,7 @@ struct sigstack {
#include <asm-generic/signal-defs.h>
+#ifndef __KERNEL__
struct __new_sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
@@ -166,6 +167,7 @@ struct __old_sigaction {
unsigned long sa_flags;
void (*sa_restorer)(void); /* not used by Linux/SPARC yet */
};
+#endif
typedef struct sigaltstack {
void __user *ss_sp;
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index c83a937ead00..cbbad74b2e06 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -15,7 +15,7 @@
#define SO_PEERCRED 0x0040
#define SO_LINGER 0x0080
#define SO_OOBINLINE 0x0100
-/* To add :#define SO_REUSEPORT 0x0200 */
+#define SO_REUSEPORT 0x0200
#define SO_BSDCOMPAT 0x0400
#define SO_RCVLOWAT 0x0800
#define SO_SNDLOWAT 0x1000
@@ -66,6 +66,7 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 0x0027
+#define SO_LOCK_FILTER 0x0028
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c
index 348fa1aeabce..eefda32b595e 100644
--- a/arch/sparc/kernel/apc.c
+++ b/arch/sparc/kernel/apc.c
@@ -20,6 +20,7 @@
#include <asm/uaccess.h>
#include <asm/auxio.h>
#include <asm/apc.h>
+#include <asm/processor.h>
/* Debugging
*
@@ -158,7 +159,7 @@ static int apc_probe(struct platform_device *op)
/* Assign power management IDLE handler */
if (!apc_no_idle)
- pm_idle = apc_swift_idle;
+ sparc_idle = apc_swift_idle;
printk(KERN_INFO "%s: power management initialized%s\n",
APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 21fd1a8f47d2..e2a030045089 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -820,14 +820,6 @@ sys_sparc_pipe:
mov %l5, %o7
.align 4
- .globl sys_sigaltstack
-sys_sigaltstack:
- mov %o7, %l5
- mov %fp, %o2
- call do_sigaltstack
- mov %l5, %o7
-
- .align 4
.globl sys_sigstack
sys_sigstack:
mov %o7, %l5
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index 291bb5de9ce0..a702d9ab019c 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -48,6 +48,10 @@ extern void sun4m_init_IRQ(void);
extern void sun4m_unmask_profile_irq(void);
extern void sun4m_clear_profile_irq(int cpu);
+/* sun4m_smp.c */
+void sun4m_cpu_pre_starting(void *arg);
+void sun4m_cpu_pre_online(void *arg);
+
/* sun4d_irq.c */
extern spinlock_t sun4d_imsk_lock;
@@ -60,6 +64,14 @@ extern int show_sun4d_interrupts(struct seq_file *, void *);
extern void sun4d_distribute_irqs(void);
extern void sun4d_free_irq(unsigned int irq, void *dev_id);
+/* sun4d_smp.c */
+void sun4d_cpu_pre_starting(void *arg);
+void sun4d_cpu_pre_online(void *arg);
+
+/* leon_smp.c */
+void leon_cpu_pre_starting(void *arg);
+void leon_cpu_pre_online(void *arg);
+
/* head_32.S */
extern unsigned int t_nmi[];
extern unsigned int linux_trap_ipi15_sun4d[];
diff --git a/arch/sparc/kernel/kgdb_32.c b/arch/sparc/kernel/kgdb_32.c
index 2e424a576a36..dcf210811af4 100644
--- a/arch/sparc/kernel/kgdb_32.c
+++ b/arch/sparc/kernel/kgdb_32.c
@@ -5,6 +5,7 @@
#include <linux/kgdb.h>
#include <linux/kdebug.h>
+#include <linux/sched.h>
#include <asm/kdebug.h>
#include <asm/ptrace.h>
diff --git a/arch/sparc/kernel/leon_pmc.c b/arch/sparc/kernel/leon_pmc.c
index 4e174321097d..708bca435219 100644
--- a/arch/sparc/kernel/leon_pmc.c
+++ b/arch/sparc/kernel/leon_pmc.c
@@ -9,6 +9,7 @@
#include <asm/leon_amba.h>
#include <asm/cpu_type.h>
#include <asm/leon.h>
+#include <asm/processor.h>
/* List of Systems that need fixup instructions around power-down instruction */
unsigned int pmc_leon_fixup_ids[] = {
@@ -69,9 +70,9 @@ static int __init leon_pmc_install(void)
if (sparc_cpu_model == sparc_leon) {
/* Assign power management IDLE handler */
if (pmc_leon_need_fixup())
- pm_idle = pmc_leon_idle_fixup;
+ sparc_idle = pmc_leon_idle_fixup;
else
- pm_idle = pmc_leon_idle;
+ sparc_idle = pmc_leon_idle;
printk(KERN_INFO "leon: power management initialized\n");
}
diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c
index 0f3fb6d9c8ef..9b40c9c12a0c 100644
--- a/arch/sparc/kernel/leon_smp.c
+++ b/arch/sparc/kernel/leon_smp.c
@@ -69,31 +69,19 @@ static inline unsigned long do_swap(volatile unsigned long *ptr,
return val;
}
-void __cpuinit leon_callin(void)
+void __cpuinit leon_cpu_pre_starting(void *arg)
{
- int cpuid = hard_smp_processor_id();
-
- local_ops->cache_all();
- local_ops->tlb_all();
leon_configure_cache_smp();
+}
- notify_cpu_starting(cpuid);
-
- /* Get our local ticker going. */
- register_percpu_ce(cpuid);
-
- calibrate_delay();
- smp_store_cpu_info(cpuid);
-
- local_ops->cache_all();
- local_ops->tlb_all();
+void __cpuinit leon_cpu_pre_online(void *arg)
+{
+ int cpuid = hard_smp_processor_id();
- /*
- * Unblock the master CPU _only_ when the scheduler state
- * of all secondary CPUs will be up-to-date, so after
- * the SMP initialization the master will be just allowed
- * to call the scheduler code.
- * Allow master to continue.
+ /* Allow master to continue. The master will then give us the
+ * go-ahead by setting the smp_commenced_mask and will wait without
+ * timeouts until our setup is completed fully (signified by
+ * our bit being set in the cpu_online_mask).
*/
do_swap(&cpu_callin_map[cpuid], 1);
@@ -110,9 +98,6 @@ void __cpuinit leon_callin(void)
while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
mb();
-
- local_irq_enable();
- set_cpu_online(cpuid, true);
}
/*
diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c
index dcbb62f63068..8b7297faca79 100644
--- a/arch/sparc/kernel/pmc.c
+++ b/arch/sparc/kernel/pmc.c
@@ -17,6 +17,7 @@
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/auxio.h>
+#include <asm/processor.h>
/* Debug
*
@@ -63,7 +64,7 @@ static int pmc_probe(struct platform_device *op)
#ifndef PMC_NO_IDLE
/* Assign power management IDLE handler */
- pm_idle = pmc_swift_idle;
+ sparc_idle = pmc_swift_idle;
#endif
printk(KERN_INFO "%s: power management initialized\n", PMC_DEVNAME);
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index be8e862badaf..62eede13831a 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -43,8 +43,7 @@
* Power management idle function
* Set in pm platform drivers (apc.c and pmc.c)
*/
-void (*pm_idle)(void);
-EXPORT_SYMBOL(pm_idle);
+void (*sparc_idle)(void);
/*
* Power-off handler instantiation for pm.h compliance
@@ -75,8 +74,8 @@ void cpu_idle(void)
/* endless idle loop with no priority at all */
for (;;) {
while (!need_resched()) {
- if (pm_idle)
- (*pm_idle)();
+ if (sparc_idle)
+ (*sparc_idle)();
else
cpu_relax();
}
diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c
index 1303021748c8..9f20566b0773 100644
--- a/arch/sparc/kernel/prom_common.c
+++ b/arch/sparc/kernel/prom_common.c
@@ -64,7 +64,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
err = -ENODEV;
mutex_lock(&of_set_property_mutex);
- write_lock(&devtree_lock);
+ raw_spin_lock(&devtree_lock);
prevp = &dp->properties;
while (*prevp) {
struct property *prop = *prevp;
@@ -91,7 +91,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
}
prevp = &(*prevp)->next;
}
- write_unlock(&devtree_lock);
+ raw_spin_unlock(&devtree_lock);
mutex_unlock(&of_set_property_mutex);
/* XXX Upate procfs if necessary... */
diff --git a/arch/sparc/kernel/sbus.c b/arch/sparc/kernel/sbus.c
index 1271b3a27d4e..be5bdf93c767 100644
--- a/arch/sparc/kernel/sbus.c
+++ b/arch/sparc/kernel/sbus.c
@@ -554,10 +554,8 @@ static void __init sbus_iommu_init(struct platform_device *op)
regs = pr->phys_addr;
iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
strbuf = kzalloc(sizeof(*strbuf), GFP_ATOMIC);
- if (!strbuf)
+ if (!iommu || !strbuf)
goto fatal_memory_error;
op->dev.archdata.iommu = iommu;
@@ -656,6 +654,8 @@ static void __init sbus_iommu_init(struct platform_device *op)
return;
fatal_memory_error:
+ kfree(iommu);
+ kfree(strbuf);
prom_printf("sbus_iommu_init: Fatal memory allocation error.\n");
}
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 0eaf0059aaef..88a127b9c69e 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -115,7 +115,7 @@ static void __init process_switch(char c)
break;
}
cheetah_pcache_forced_on = 1;
- add_taint(TAINT_MACHINE_CHECK);
+ add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
cheetah_enable_pcache();
break;
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 53e48f721ce3..cd5dc4d411d1 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -61,7 +61,7 @@ struct rt_signal_frame32 {
compat_sigset_t mask;
/* __siginfo_fpu_t * */ u32 fpu_save;
unsigned int insns[2];
- stack_t32 stack;
+ compat_stack_t stack;
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
siginfo_extra_v8plus_t v8plus;
@@ -230,13 +230,11 @@ segv:
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
{
struct rt_signal_frame32 __user *sf;
- unsigned int psr, pc, npc, u_ss_sp;
+ unsigned int psr, pc, npc;
compat_uptr_t fpu_save;
compat_uptr_t rwin_save;
- mm_segment_t old_fs;
sigset_t set;
compat_sigset_t seta;
- stack_t st;
int err, i;
/* Always make any pending restarted system calls return -EINTR */
@@ -295,20 +293,10 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
if (!err && fpu_save)
err |= restore_fpu_state(regs, compat_ptr(fpu_save));
err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
- err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
- st.ss_sp = compat_ptr(u_ss_sp);
- err |= __get_user(st.ss_flags, &sf->stack.ss_flags);
- err |= __get_user(st.ss_size, &sf->stack.ss_size);
+ err |= compat_restore_altstack(&sf->stack);
if (err)
goto segv;
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
- set_fs(old_fs);
-
err |= __get_user(rwin_save, &sf->rwin_save);
if (!err && rwin_save) {
if (restore_rwin_state(compat_ptr(rwin_save)))
@@ -335,7 +323,7 @@ static int invalid_frame_pointer(void __user *fp, int fplen)
return 0;
}
-static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
+static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
{
unsigned long sp;
@@ -350,12 +338,7 @@ static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, uns
return (void __user *) -1L;
/* This is the X/Open sanctioned signal stack switching. */
- if (sa->sa_flags & SA_ONSTACK) {
- if (sas_ss_flags(sp) == 0)
- sp = current->sas_ss_sp + current->sas_ss_size;
- }
-
- sp -= framesize;
+ sp = sigsp(sp, ksig) - framesize;
/* Always align the stack frame. This handles two cases. First,
* sigaltstack need not be mindful of platform specific stack
@@ -426,8 +409,8 @@ out_irqs_on:
}
-static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset)
+static int setup_frame32(struct ksignal *ksig, struct pt_regs *regs,
+ sigset_t *oldset)
{
struct signal_frame32 __user *sf;
int i, err, wsaved;
@@ -449,10 +432,12 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct signal_frame32 __user *)
- get_sigframe(&ka->sa, regs, sigframe_size);
+ get_sigframe(ksig, regs, sigframe_size);
- if (invalid_frame_pointer(sf, sigframe_size))
- goto sigill;
+ if (invalid_frame_pointer(sf, sigframe_size)) {
+ do_exit(SIGILL);
+ return -EINVAL;
+ }
tail = (sf + 1);
@@ -526,16 +511,16 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
}
if (err)
- goto sigsegv;
+ return err;
/* 3. signal handler back-trampoline and parameters */
regs->u_regs[UREG_FP] = (unsigned long) sf;
- regs->u_regs[UREG_I0] = signo;
+ regs->u_regs[UREG_I0] = ksig->sig;
regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
/* 4. signal handler */
- regs->tpc = (unsigned long) ka->sa.sa_handler;
+ regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;
regs->tnpc = (regs->tpc + 4);
if (test_thread_flag(TIF_32BIT)) {
regs->tpc &= 0xffffffff;
@@ -543,8 +528,8 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
}
/* 5. return to kernel instructions */
- if (ka->ka_restorer) {
- regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ if (ksig->ka.ka_restorer) {
+ regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;
} else {
unsigned long address = ((unsigned long)&(sf->insns[0]));
@@ -553,23 +538,14 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
err = __put_user(0x821020d8, &sf->insns[0]); /*mov __NR_sigreturn, %g1*/
err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
if (err)
- goto sigsegv;
+ return err;
flush_signal_insns(address);
}
return 0;
-
-sigill:
- do_exit(SIGILL);
- return -EINVAL;
-
-sigsegv:
- force_sigsegv(signo, current);
- return -EFAULT;
}
-static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
- unsigned long signr, sigset_t *oldset,
- siginfo_t *info)
+static int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs,
+ sigset_t *oldset)
{
struct rt_signal_frame32 __user *sf;
int i, err, wsaved;
@@ -591,10 +567,12 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame32 __user *)
- get_sigframe(&ka->sa, regs, sigframe_size);
+ get_sigframe(ksig, regs, sigframe_size);
- if (invalid_frame_pointer(sf, sigframe_size))
- goto sigill;
+ if (invalid_frame_pointer(sf, sigframe_size)) {
+ do_exit(SIGILL);
+ return -EINVAL;
+ }
tail = (sf + 1);
@@ -639,12 +617,10 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
}
/* Update the siginfo structure. */
- err |= copy_siginfo_to_user32(&sf->info, info);
+ err |= copy_siginfo_to_user32(&sf->info, &ksig->info);
/* Setup sigaltstack */
- err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
+ err |= __compat_save_altstack(&sf->stack, regs->u_regs[UREG_FP]);
switch (_NSIG_WORDS) {
case 4: seta.sig[7] = (oldset->sig[3] >> 32);
@@ -674,16 +650,16 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
}
if (err)
- goto sigsegv;
+ return err;
/* 3. signal handler back-trampoline and parameters */
regs->u_regs[UREG_FP] = (unsigned long) sf;
- regs->u_regs[UREG_I0] = signr;
+ regs->u_regs[UREG_I0] = ksig->sig;
regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;
/* 4. signal handler */
- regs->tpc = (unsigned long) ka->sa.sa_handler;
+ regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;
regs->tnpc = (regs->tpc + 4);
if (test_thread_flag(TIF_32BIT)) {
regs->tpc &= 0xffffffff;
@@ -691,8 +667,8 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
}
/* 5. return to kernel instructions */
- if (ka->ka_restorer)
- regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ if (ksig->ka.ka_restorer)
+ regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;
else {
unsigned long address = ((unsigned long)&(sf->insns[0]));
@@ -704,36 +680,25 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
/* t 0x10 */
err |= __put_user(0x91d02010, &sf->insns[1]);
if (err)
- goto sigsegv;
+ return err;
flush_signal_insns(address);
}
return 0;
-
-sigill:
- do_exit(SIGILL);
- return -EINVAL;
-
-sigsegv:
- force_sigsegv(signr, current);
- return -EFAULT;
}
-static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
- siginfo_t *info,
- sigset_t *oldset, struct pt_regs *regs)
+static inline void handle_signal32(struct ksignal *ksig,
+ struct pt_regs *regs)
{
+ sigset_t *oldset = sigmask_to_save();
int err;
- if (ka->sa.sa_flags & SA_SIGINFO)
- err = setup_rt_frame32(ka, regs, signr, oldset, info);
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+ err = setup_rt_frame32(ksig, regs, oldset);
else
- err = setup_frame32(ka, regs, signr, oldset);
-
- if (err)
- return;
+ err = setup_frame32(ksig, regs, oldset);
- signal_delivered(signr, info, ka, regs, 0);
+ signal_setup_done(err, ksig, 0);
}
static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
@@ -763,50 +728,41 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs
*/
void do_signal32(sigset_t *oldset, struct pt_regs * regs)
{
- struct k_sigaction ka;
- unsigned long orig_i0;
- int restart_syscall;
- siginfo_t info;
- int signr;
-
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ struct ksignal ksig;
+ unsigned long orig_i0 = 0;
+ int restart_syscall = 0;
+ bool has_handler = get_signal(&ksig);
- restart_syscall = 0;
- orig_i0 = 0;
if (pt_regs_is_syscall(regs) &&
(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
restart_syscall = 1;
orig_i0 = regs->u_regs[UREG_G6];
}
- if (signr > 0) {
+ if (has_handler) {
if (restart_syscall)
- syscall_restart32(orig_i0, regs, &ka.sa);
- handle_signal32(signr, &ka, &info, oldset, regs);
- return;
- }
- if (restart_syscall &&
- (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
- regs->u_regs[UREG_I0] == ERESTARTSYS ||
- regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
- /* replay the system call when we are done */
- regs->u_regs[UREG_I0] = orig_i0;
- regs->tpc -= 4;
- regs->tnpc -= 4;
- pt_regs_clear_syscall(regs);
- }
- if (restart_syscall &&
- regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
- regs->u_regs[UREG_G1] = __NR_restart_syscall;
- regs->tpc -= 4;
- regs->tnpc -= 4;
- pt_regs_clear_syscall(regs);
+ syscall_restart32(orig_i0, regs, &ksig.ka.sa);
+ handle_signal32(&ksig, regs);
+ } else {
+ if (restart_syscall) {
+ switch (regs->u_regs[UREG_I0]) {
+ case ERESTARTNOHAND:
+ case ERESTARTSYS:
+ case ERESTARTNOINTR:
+ /* replay the system call when we are done */
+ regs->u_regs[UREG_I0] = orig_i0;
+ regs->tpc -= 4;
+ regs->tnpc -= 4;
+ pt_regs_clear_syscall(regs);
+ case ERESTART_RESTARTBLOCK:
+ regs->u_regs[UREG_G1] = __NR_restart_syscall;
+ regs->tpc -= 4;
+ regs->tnpc -= 4;
+ pt_regs_clear_syscall(regs);
+ }
+ }
+ restore_saved_sigmask();
}
-
- /* If there's no signal to deliver, we just put the saved sigmask
- * back
- */
- restore_saved_sigmask();
}
struct sigstack32 {
@@ -856,29 +812,3 @@ asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp)
out:
return ret;
}
-
-asmlinkage long do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp)
-{
- stack_t uss, uoss;
- u32 u_ss_sp = 0;
- int ret;
- mm_segment_t old_fs;
- stack_t32 __user *uss32 = compat_ptr(ussa);
- stack_t32 __user *uoss32 = compat_ptr(uossa);
-
- if (ussa && (get_user(u_ss_sp, &uss32->ss_sp) ||
- __get_user(uss.ss_flags, &uss32->ss_flags) ||
- __get_user(uss.ss_size, &uss32->ss_size)))
- return -EFAULT;
- uss.ss_sp = compat_ptr(u_ss_sp);
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = do_sigaltstack(ussa ? (stack_t __user *) &uss : NULL,
- uossa ? (stack_t __user *) &uoss : NULL, sp);
- set_fs(old_fs);
- if (!ret && uossa && (put_user(ptr_to_compat(uoss.ss_sp), &uoss32->ss_sp) ||
- __put_user(uoss.ss_flags, &uoss32->ss_flags) ||
- __put_user(uoss.ss_size, &uoss32->ss_size)))
- return -EFAULT;
- return ret;
-}
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index 68f9c8650af4..7d5d8e1f8415 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -59,18 +59,6 @@ struct rt_signal_frame {
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
-static int _sigpause_common(old_sigset_t set)
-{
- sigset_t blocked;
- siginitset(&blocked, set);
- return sigsuspend(&blocked);
-}
-
-asmlinkage int sys_sigsuspend(old_sigset_t set)
-{
- return _sigpause_common(set);
-}
-
asmlinkage void do_sigreturn(struct pt_regs *regs)
{
struct signal_frame __user *sf;
@@ -141,9 +129,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
unsigned int psr, pc, npc;
__siginfo_fpu_t __user *fpu_save;
__siginfo_rwin_t __user *rwin_save;
- mm_segment_t old_fs;
sigset_t set;
- stack_t st;
int err;
synchronize_user_stack();
@@ -171,8 +157,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
if (!err && fpu_save)
err |= restore_fpu_state(regs, fpu_save);
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
-
- err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
+ err |= restore_altstack(&sf->stack);
if (err)
goto segv;
@@ -180,14 +165,6 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
regs->pc = pc;
regs->npc = npc;
- /* It is more difficult to avoid calling this function than to
- * call it and ignore errors.
- */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
- set_fs(old_fs);
-
err |= __get_user(rwin_save, &sf->rwin_save);
if (!err && rwin_save) {
if (restore_rwin_state(rwin_save))
@@ -209,7 +186,7 @@ static inline int invalid_frame_pointer(void __user *fp, int fplen)
return 0;
}
-static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
+static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
{
unsigned long sp = regs->u_regs[UREG_FP];
@@ -221,12 +198,7 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re
return (void __user *) -1L;
/* This is the X/Open sanctioned signal stack switching. */
- if (sa->sa_flags & SA_ONSTACK) {
- if (sas_ss_flags(sp) == 0)
- sp = current->sas_ss_sp + current->sas_ss_size;
- }
-
- sp -= framesize;
+ sp = sigsp(sp, ksig) - framesize;
/* Always align the stack frame. This handles two cases. First,
* sigaltstack need not be mindful of platform specific stack
@@ -239,8 +211,8 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re
return (void __user *) sp;
}
-static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset)
+static int setup_frame(struct ksignal *ksig, struct pt_regs *regs,
+ sigset_t *oldset)
{
struct signal_frame __user *sf;
int sigframe_size, err, wsaved;
@@ -258,10 +230,12 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct signal_frame __user *)
- get_sigframe(&ka->sa, regs, sigframe_size);
+ get_sigframe(ksig, regs, sigframe_size);
- if (invalid_frame_pointer(sf, sigframe_size))
- goto sigill_and_return;
+ if (invalid_frame_pointer(sf, sigframe_size)) {
+ do_exit(SIGILL);
+ return -EINVAL;
+ }
tail = sf + 1;
@@ -300,21 +274,21 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
}
if (err)
- goto sigsegv;
+ return err;
/* 3. signal handler back-trampoline and parameters */
regs->u_regs[UREG_FP] = (unsigned long) sf;
- regs->u_regs[UREG_I0] = signo;
+ regs->u_regs[UREG_I0] = ksig->sig;
regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
/* 4. signal handler */
- regs->pc = (unsigned long) ka->sa.sa_handler;
+ regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
regs->npc = (regs->pc + 4);
/* 5. return to kernel instructions */
- if (ka->ka_restorer)
- regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ if (ksig->ka.ka_restorer)
+ regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;
else {
regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
@@ -324,24 +298,16 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
/* t 0x10 */
err |= __put_user(0x91d02010, &sf->insns[1]);
if (err)
- goto sigsegv;
+ return err;
/* Flush instruction space. */
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
}
return 0;
-
-sigill_and_return:
- do_exit(SIGILL);
- return -EINVAL;
-
-sigsegv:
- force_sigsegv(signo, current);
- return -EFAULT;
}
-static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset, siginfo_t *info)
+static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs,
+ sigset_t *oldset)
{
struct rt_signal_frame __user *sf;
int sigframe_size, wsaved;
@@ -357,9 +323,11 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
if (wsaved)
sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame __user *)
- get_sigframe(&ka->sa, regs, sigframe_size);
- if (invalid_frame_pointer(sf, sigframe_size))
- goto sigill;
+ get_sigframe(ksig, regs, sigframe_size);
+ if (invalid_frame_pointer(sf, sigframe_size)) {
+ do_exit(SIGILL);
+ return -EINVAL;
+ }
tail = sf + 1;
err = __put_user(regs->pc, &sf->regs.pc);
@@ -391,9 +359,7 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
/* Setup sigaltstack */
- err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
+ err |= __save_altstack(&sf->stack, regs->u_regs[UREG_FP]);
if (!wsaved) {
err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
@@ -405,21 +371,21 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
}
- err |= copy_siginfo_to_user(&sf->info, info);
+ err |= copy_siginfo_to_user(&sf->info, &ksig->info);
if (err)
- goto sigsegv;
+ return err;
regs->u_regs[UREG_FP] = (unsigned long) sf;
- regs->u_regs[UREG_I0] = signo;
+ regs->u_regs[UREG_I0] = ksig->sig;
regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;
- regs->pc = (unsigned long) ka->sa.sa_handler;
+ regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
regs->npc = (regs->pc + 4);
- if (ka->ka_restorer)
- regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ if (ksig->ka.ka_restorer)
+ regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;
else {
regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
@@ -429,38 +395,25 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
/* t 0x10 */
err |= __put_user(0x91d02010, &sf->insns[1]);
if (err)
- goto sigsegv;
+ return err;
/* Flush instruction space. */
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
}
return 0;
-
-sigill:
- do_exit(SIGILL);
- return -EINVAL;
-
-sigsegv:
- force_sigsegv(signo, current);
- return -EFAULT;
}
static inline void
-handle_signal(unsigned long signr, struct k_sigaction *ka,
- siginfo_t *info, struct pt_regs *regs)
+handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
sigset_t *oldset = sigmask_to_save();
int err;
- if (ka->sa.sa_flags & SA_SIGINFO)
- err = setup_rt_frame(ka, regs, signr, oldset, info);
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+ err = setup_rt_frame(ksig, regs, oldset);
else
- err = setup_frame(ka, regs, signr, oldset);
-
- if (err)
- return;
-
- signal_delivered(signr, info, ka, regs, 0);
+ err = setup_frame(ksig, regs, oldset);
+ signal_setup_done(err, ksig, 0);
}
static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
@@ -490,10 +443,9 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
*/
static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
{
- struct k_sigaction ka;
+ struct ksignal ksig;
int restart_syscall;
- siginfo_t info;
- int signr;
+ bool has_handler;
/* It's a lot of work and synchronization to add a new ptrace
* register for GDB to save and restore in order to get
@@ -516,7 +468,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
regs->u_regs[UREG_G6] = orig_i0;
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ has_handler = get_signal(&ksig);
/* If the debugger messes with the program counter, it clears
* the software "in syscall" bit, directing us to not perform
@@ -528,35 +480,30 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
orig_i0 = regs->u_regs[UREG_G6];
}
-
- if (signr > 0) {
+ if (has_handler) {
if (restart_syscall)
- syscall_restart(orig_i0, regs, &ka.sa);
- handle_signal(signr, &ka, &info, regs);
- return;
- }
- if (restart_syscall &&
- (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
- regs->u_regs[UREG_I0] == ERESTARTSYS ||
- regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
- /* replay the system call when we are done */
- regs->u_regs[UREG_I0] = orig_i0;
- regs->pc -= 4;
- regs->npc -= 4;
- pt_regs_clear_syscall(regs);
- }
- if (restart_syscall &&
- regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
- regs->u_regs[UREG_G1] = __NR_restart_syscall;
- regs->pc -= 4;
- regs->npc -= 4;
- pt_regs_clear_syscall(regs);
+ syscall_restart(orig_i0, regs, &ksig.ka.sa);
+ handle_signal(&ksig, regs);
+ } else {
+ if (restart_syscall) {
+ switch (regs->u_regs[UREG_I0]) {
+ case ERESTARTNOHAND:
+ case ERESTARTSYS:
+ case ERESTARTNOINTR:
+ /* replay the system call when we are done */
+ regs->u_regs[UREG_I0] = orig_i0;
+ regs->pc -= 4;
+ regs->npc -= 4;
+ pt_regs_clear_syscall(regs);
+ case ERESTART_RESTARTBLOCK:
+ regs->u_regs[UREG_G1] = __NR_restart_syscall;
+ regs->pc -= 4;
+ regs->npc -= 4;
+ pt_regs_clear_syscall(regs);
+ }
+ }
+ restore_saved_sigmask();
}
-
- /* if there's no signal to deliver, we just put the saved sigmask
- * back
- */
- restore_saved_sigmask();
}
void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 689e1ba62809..35923e8abd82 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -236,23 +236,6 @@ struct rt_signal_frame {
__siginfo_rwin_t *rwin_save;
};
-static long _sigpause_common(old_sigset_t set)
-{
- sigset_t blocked;
- siginitset(&blocked, set);
- return sigsuspend(&blocked);
-}
-
-asmlinkage long sys_sigpause(unsigned int set)
-{
- return _sigpause_common(set);
-}
-
-asmlinkage long sys_sigsuspend(old_sigset_t set)
-{
- return _sigpause_common(set);
-}
-
void do_rt_sigreturn(struct pt_regs *regs)
{
struct rt_signal_frame __user *sf;
@@ -295,7 +278,8 @@ void do_rt_sigreturn(struct pt_regs *regs)
err |= restore_fpu_state(regs, fpu_save);
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
- if (err || do_sigaltstack(&sf->stack, NULL, (unsigned long)sf) == -EFAULT)
+ err |= restore_altstack(&sf->stack);
+ if (err)
goto segv;
err |= __get_user(rwin_save, &sf->rwin_save);
@@ -324,7 +308,7 @@ static int invalid_frame_pointer(void __user *fp)
return 0;
}
-static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
+static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
{
unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
@@ -336,12 +320,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *
return (void __user *) -1L;
/* This is the X/Open sanctioned signal stack switching. */
- if (ka->sa.sa_flags & SA_ONSTACK) {
- if (sas_ss_flags(sp) == 0)
- sp = current->sas_ss_sp + current->sas_ss_size;
- }
-
- sp -= framesize;
+ sp = sigsp(sp, ksig) - framesize;
/* Always align the stack frame. This handles two cases. First,
* sigaltstack need not be mindful of platform specific stack
@@ -355,8 +334,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *
}
static inline int
-setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset, siginfo_t *info)
+setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
{
struct rt_signal_frame __user *sf;
int wsaved, err, sf_size;
@@ -374,10 +352,12 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
if (wsaved)
sf_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame __user *)
- get_sigframe(ka, regs, sf_size);
+ get_sigframe(ksig, regs, sf_size);
- if (invalid_frame_pointer (sf))
- goto sigill;
+ if (invalid_frame_pointer (sf)) {
+ do_exit(SIGILL); /* won't return, actually */
+ return -EINVAL;
+ }
tail = (sf + 1);
@@ -403,11 +383,9 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
}
/* Setup sigaltstack */
- err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
+ err |= __save_altstack(&sf->stack, regs->u_regs[UREG_FP]);
- err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
+ err |= copy_to_user(&sf->mask, sigmask_to_save(), sizeof(sigset_t));
if (!wsaved) {
err |= copy_in_user((u64 __user *)sf,
@@ -420,18 +398,18 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
rp = &current_thread_info()->reg_window[wsaved - 1];
err |= copy_to_user(sf, rp, sizeof(struct reg_window));
}
- if (info)
- err |= copy_siginfo_to_user(&sf->info, info);
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+ err |= copy_siginfo_to_user(&sf->info, &ksig->info);
else {
- err |= __put_user(signo, &sf->info.si_signo);
+ err |= __put_user(ksig->sig, &sf->info.si_signo);
err |= __put_user(SI_NOINFO, &sf->info.si_code);
}
if (err)
- goto sigsegv;
+ return err;
/* 3. signal handler back-trampoline and parameters */
regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS;
- regs->u_regs[UREG_I0] = signo;
+ regs->u_regs[UREG_I0] = ksig->sig;
regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
/* The sigcontext is passed in this way because of how it
@@ -441,37 +419,15 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
/* 5. signal handler */
- regs->tpc = (unsigned long) ka->sa.sa_handler;
+ regs->tpc = (unsigned long) ksig->ka.sa.sa_handler;
regs->tnpc = (regs->tpc + 4);
if (test_thread_flag(TIF_32BIT)) {
regs->tpc &= 0xffffffff;
regs->tnpc &= 0xffffffff;
}
/* 4. return to kernel instructions */
- regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ regs->u_regs[UREG_I7] = (unsigned long)ksig->ka.ka_restorer;
return 0;
-
-sigill:
- do_exit(SIGILL);
- return -EINVAL;
-
-sigsegv:
- force_sigsegv(signo, current);
- return -EFAULT;
-}
-
-static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
- siginfo_t *info,
- sigset_t *oldset, struct pt_regs *regs)
-{
- int err;
-
- err = setup_rt_frame(ka, regs, signr, oldset,
- (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
- if (err)
- return;
-
- signal_delivered(signr, info, ka, regs, 0);
}
static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
@@ -501,11 +457,9 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
*/
static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
{
- struct k_sigaction ka;
+ struct ksignal ksig;
int restart_syscall;
- sigset_t *oldset = sigmask_to_save();
- siginfo_t info;
- int signr;
+ bool has_handler;
/* It's a lot of work and synchronization to add a new ptrace
* register for GDB to save and restore in order to get
@@ -531,13 +485,13 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
#ifdef CONFIG_COMPAT
if (test_thread_flag(TIF_32BIT)) {
- extern void do_signal32(sigset_t *, struct pt_regs *);
- do_signal32(oldset, regs);
+ extern void do_signal32(struct pt_regs *);
+ do_signal32(regs);
return;
}
#endif
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ has_handler = get_signal(&ksig);
restart_syscall = 0;
if (pt_regs_is_syscall(regs) &&
@@ -546,34 +500,30 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
orig_i0 = regs->u_regs[UREG_G6];
}
- if (signr > 0) {
+ if (has_handler) {
if (restart_syscall)
- syscall_restart(orig_i0, regs, &ka.sa);
- handle_signal(signr, &ka, &info, oldset, regs);
- return;
- }
- if (restart_syscall &&
- (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
- regs->u_regs[UREG_I0] == ERESTARTSYS ||
- regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
- /* replay the system call when we are done */
- regs->u_regs[UREG_I0] = orig_i0;
- regs->tpc -= 4;
- regs->tnpc -= 4;
- pt_regs_clear_syscall(regs);
- }
- if (restart_syscall &&
- regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
- regs->u_regs[UREG_G1] = __NR_restart_syscall;
- regs->tpc -= 4;
- regs->tnpc -= 4;
- pt_regs_clear_syscall(regs);
+ syscall_restart(orig_i0, regs, &ksig.ka.sa);
+ signal_setup_done(setup_rt_frame(&ksig, regs), &ksig, 0);
+ } else {
+ if (restart_syscall) {
+ switch (regs->u_regs[UREG_I0]) {
+ case ERESTARTNOHAND:
+ case ERESTARTSYS:
+ case ERESTARTNOINTR:
+ /* replay the system call when we are done */
+ regs->u_regs[UREG_I0] = orig_i0;
+ regs->tpc -= 4;
+ regs->tnpc -= 4;
+ pt_regs_clear_syscall(regs);
+ case ERESTART_RESTARTBLOCK:
+ regs->u_regs[UREG_G1] = __NR_restart_syscall;
+ regs->tpc -= 4;
+ regs->tnpc -= 4;
+ pt_regs_clear_syscall(regs);
+ }
+ }
+ restore_saved_sigmask();
}
-
- /* If there's no signal to deliver, we just put the saved sigmask
- * back
- */
- restore_saved_sigmask();
}
void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags)
diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c
index 79db45e5134a..9e7e6d718367 100644
--- a/arch/sparc/kernel/smp_32.c
+++ b/arch/sparc/kernel/smp_32.c
@@ -20,6 +20,7 @@
#include <linux/seq_file.h>
#include <linux/cache.h>
#include <linux/delay.h>
+#include <linux/cpu.h>
#include <asm/ptrace.h>
#include <linux/atomic.h>
@@ -32,8 +33,10 @@
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/cpudata.h>
+#include <asm/timer.h>
#include <asm/leon.h>
+#include "kernel.h"
#include "irq.h"
volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,};
@@ -294,6 +297,89 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
return ret;
}
+void __cpuinit arch_cpu_pre_starting(void *arg)
+{
+ local_ops->cache_all();
+ local_ops->tlb_all();
+
+ switch(sparc_cpu_model) {
+ case sun4m:
+ sun4m_cpu_pre_starting(arg);
+ break;
+ case sun4d:
+ sun4d_cpu_pre_starting(arg);
+ break;
+ case sparc_leon:
+ leon_cpu_pre_starting(arg);
+ break;
+ default:
+ BUG();
+ }
+}
+
+void __cpuinit arch_cpu_pre_online(void *arg)
+{
+ unsigned int cpuid = hard_smp_processor_id();
+
+ register_percpu_ce(cpuid);
+
+ calibrate_delay();
+ smp_store_cpu_info(cpuid);
+
+ local_ops->cache_all();
+ local_ops->tlb_all();
+
+ switch(sparc_cpu_model) {
+ case sun4m:
+ sun4m_cpu_pre_online(arg);
+ break;
+ case sun4d:
+ sun4d_cpu_pre_online(arg);
+ break;
+ case sparc_leon:
+ leon_cpu_pre_online(arg);
+ break;
+ default:
+ BUG();
+ }
+}
+
+void __cpuinit sparc_start_secondary(void *arg)
+{
+ unsigned int cpu;
+
+ /*
+ * SMP booting is extremely fragile in some architectures. So run
+ * the cpu initialization code first before anything else.
+ */
+ arch_cpu_pre_starting(arg);
+
+ preempt_disable();
+ cpu = smp_processor_id();
+
+ /* Invoke the CPU_STARTING notifier callbacks */
+ notify_cpu_starting(cpu);
+
+ arch_cpu_pre_online(arg);
+
+ /* Set the CPU in the cpu_online_mask */
+ set_cpu_online(cpu, true);
+
+ /* Enable local interrupts now */
+ local_irq_enable();
+
+ wmb();
+ cpu_idle();
+
+ /* We should never reach here! */
+ BUG();
+}
+
+void __cpuinit smp_callin(void)
+{
+ sparc_start_secondary(NULL);
+}
+
void smp_bogo(struct seq_file *m)
{
int i;
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index ddaea31de586..c9eb82f23d92 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -50,10 +50,9 @@ static inline void show_leds(int cpuid)
"i" (ASI_M_CTL));
}
-void __cpuinit smp4d_callin(void)
+void __cpuinit sun4d_cpu_pre_starting(void *arg)
{
int cpuid = hard_smp_processor_id();
- unsigned long flags;
/* Show we are alive */
cpu_leds[cpuid] = 0x6;
@@ -61,26 +60,20 @@ void __cpuinit smp4d_callin(void)
/* Enable level15 interrupt, disable level14 interrupt for now */
cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000);
+}
- local_ops->cache_all();
- local_ops->tlb_all();
+void __cpuinit sun4d_cpu_pre_online(void *arg)
+{
+ unsigned long flags;
+ int cpuid;
- notify_cpu_starting(cpuid);
- /*
- * Unblock the master CPU _only_ when the scheduler state
+ cpuid = hard_smp_processor_id();
+
+ /* Unblock the master CPU _only_ when the scheduler state
* of all secondary CPUs will be up-to-date, so after
* the SMP initialization the master will be just allowed
* to call the scheduler code.
*/
- /* Get our local ticker going. */
- register_percpu_ce(cpuid);
-
- calibrate_delay();
- smp_store_cpu_info(cpuid);
- local_ops->cache_all();
- local_ops->tlb_all();
-
- /* Allow master to continue. */
sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1);
local_ops->cache_all();
local_ops->tlb_all();
@@ -106,16 +99,12 @@ void __cpuinit smp4d_callin(void)
local_ops->cache_all();
local_ops->tlb_all();
- local_irq_enable(); /* We don't allow PIL 14 yet */
-
while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
barrier();
spin_lock_irqsave(&sun4d_imsk_lock, flags);
cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
- set_cpu_online(cpuid, true);
-
}
/*
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 128af7304288..8a65f158153d 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -34,30 +34,19 @@ swap_ulong(volatile unsigned long *ptr, unsigned long val)
return val;
}
-void __cpuinit smp4m_callin(void)
+void __cpuinit sun4m_cpu_pre_starting(void *arg)
{
- int cpuid = hard_smp_processor_id();
-
- local_ops->cache_all();
- local_ops->tlb_all();
-
- notify_cpu_starting(cpuid);
-
- register_percpu_ce(cpuid);
-
- calibrate_delay();
- smp_store_cpu_info(cpuid);
+}
- local_ops->cache_all();
- local_ops->tlb_all();
+void __cpuinit sun4m_cpu_pre_online(void *arg)
+{
+ int cpuid = hard_smp_processor_id();
- /*
- * Unblock the master CPU _only_ when the scheduler state
- * of all secondary CPUs will be up-to-date, so after
- * the SMP initialization the master will be just allowed
- * to call the scheduler code.
+ /* Allow master to continue. The master will then give us the
+ * go-ahead by setting the smp_commenced_mask and will wait without
+ * timeouts until our setup is completed fully (signified by
+ * our bit being set in the cpu_online_mask).
*/
- /* Allow master to continue. */
swap_ulong(&cpu_callin_map[cpuid], 1);
/* XXX: What's up with all the flushes? */
@@ -75,10 +64,6 @@ void __cpuinit smp4m_callin(void)
while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
mb();
-
- local_irq_enable();
-
- set_cpu_online(cpuid, true);
}
/*
diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S
index 8475a474273a..240a3cecc11e 100644
--- a/arch/sparc/kernel/sys32.S
+++ b/arch/sparc/kernel/sys32.S
@@ -36,108 +36,22 @@ STUB: sra REG1, 0, REG1; \
jmpl %g1 + %lo(SYSCALL), %g0; \
sra REG3, 0, REG3
-#define SIGN4(STUB,SYSCALL,REG1,REG2,REG3,REG4) \
- .align 32; \
- .globl STUB; \
-STUB: sra REG1, 0, REG1; \
- sethi %hi(SYSCALL), %g1; \
- sra REG2, 0, REG2; \
- sra REG3, 0, REG3; \
- jmpl %g1 + %lo(SYSCALL), %g0; \
- sra REG4, 0, REG4
-
-SIGN1(sys32_exit, sparc_exit, %o0)
-SIGN1(sys32_exit_group, sparc_exit_group, %o0)
-SIGN1(sys32_wait4, compat_sys_wait4, %o2)
-SIGN1(sys32_creat, sys_creat, %o1)
-SIGN1(sys32_mknod, sys_mknod, %o1)
-SIGN1(sys32_umount, sys_umount, %o1)
-SIGN1(sys32_signal, sys_signal, %o0)
-SIGN1(sys32_access, sys_access, %o1)
-SIGN1(sys32_msync, sys_msync, %o2)
-SIGN2(sys32_reboot, sys_reboot, %o0, %o1)
-SIGN1(sys32_setitimer, compat_sys_setitimer, %o0)
-SIGN1(sys32_getitimer, compat_sys_getitimer, %o0)
-SIGN1(sys32_sethostname, sys_sethostname, %o1)
-SIGN1(sys32_swapon, sys_swapon, %o1)
-SIGN1(sys32_sigaction, compat_sys_sigaction, %o0)
-SIGN1(sys32_rt_sigaction, compat_sys_rt_sigaction, %o0)
-SIGN1(sys32_sigprocmask, compat_sys_sigprocmask, %o0)
-SIGN1(sys32_rt_sigprocmask, compat_sys_rt_sigprocmask, %o0)
-SIGN2(sys32_rt_sigqueueinfo, compat_sys_rt_sigqueueinfo, %o0, %o1)
SIGN1(sys32_getrusage, compat_sys_getrusage, %o0)
-SIGN1(sys32_setxattr, sys_setxattr, %o4)
-SIGN1(sys32_lsetxattr, sys_lsetxattr, %o4)
-SIGN1(sys32_fsetxattr, sys_fsetxattr, %o4)
-SIGN1(sys32_fgetxattr, sys_fgetxattr, %o0)
-SIGN1(sys32_flistxattr, sys_flistxattr, %o0)
-SIGN1(sys32_fremovexattr, sys_fremovexattr, %o0)
-SIGN2(sys32_tkill, sys_tkill, %o0, %o1)
-SIGN1(sys32_epoll_create, sys_epoll_create, %o0)
-SIGN3(sys32_epoll_ctl, sys_epoll_ctl, %o0, %o1, %o2)
-SIGN3(sys32_epoll_wait, sys_epoll_wait, %o0, %o2, %o3)
SIGN1(sys32_readahead, compat_sys_readahead, %o0)
SIGN2(sys32_fadvise64, compat_sys_fadvise64, %o0, %o4)
SIGN2(sys32_fadvise64_64, compat_sys_fadvise64_64, %o0, %o5)
-SIGN2(sys32_bdflush, sys_bdflush, %o0, %o1)
-SIGN1(sys32_mlockall, sys_mlockall, %o0)
SIGN1(sys32_clock_nanosleep, compat_sys_clock_nanosleep, %o1)
SIGN1(sys32_timer_settime, compat_sys_timer_settime, %o1)
SIGN1(sys32_io_submit, compat_sys_io_submit, %o1)
SIGN1(sys32_mq_open, compat_sys_mq_open, %o1)
SIGN1(sys32_select, compat_sys_select, %o0)
-SIGN1(sys32_mkdir, sys_mkdir, %o1)
SIGN3(sys32_futex, compat_sys_futex, %o1, %o2, %o5)
-SIGN1(sys32_sysfs, compat_sys_sysfs, %o0)
SIGN2(sys32_sendfile, compat_sys_sendfile, %o0, %o1)
-SIGN2(sys32_sendfile64, sys_sendfile, %o0, %o1)
-SIGN1(sys32_prctl, sys_prctl, %o0)
-SIGN1(sys32_sched_rr_get_interval, compat_sys_sched_rr_get_interval, %o0)
-SIGN2(sys32_waitpid, sys_waitpid, %o0, %o2)
-SIGN1(sys32_getgroups, sys_getgroups, %o0)
-SIGN1(sys32_getpgid, sys_getpgid, %o0)
-SIGN2(sys32_getpriority, sys_getpriority, %o0, %o1)
-SIGN1(sys32_getsid, sys_getsid, %o0)
-SIGN2(sys32_kill, sys_kill, %o0, %o1)
-SIGN1(sys32_nice, sys_nice, %o0)
-SIGN1(sys32_lseek, sys_lseek, %o1)
-SIGN2(sys32_open, sparc32_open, %o1, %o2)
-SIGN1(sys32_readlink, sys_readlink, %o2)
-SIGN1(sys32_sched_get_priority_max, sys_sched_get_priority_max, %o0)
-SIGN1(sys32_sched_get_priority_min, sys_sched_get_priority_min, %o0)
-SIGN1(sys32_sched_getparam, sys_sched_getparam, %o0)
-SIGN1(sys32_sched_getscheduler, sys_sched_getscheduler, %o0)
-SIGN1(sys32_sched_setparam, sys_sched_setparam, %o0)
-SIGN2(sys32_sched_setscheduler, sys_sched_setscheduler, %o0, %o1)
-SIGN1(sys32_getdomainname, sys_getdomainname, %o1)
-SIGN1(sys32_setdomainname, sys_setdomainname, %o1)
-SIGN1(sys32_setgroups, sys_setgroups, %o0)
-SIGN2(sys32_setpgid, sys_setpgid, %o0, %o1)
-SIGN3(sys32_setpriority, sys_setpriority, %o0, %o1, %o2)
-SIGN1(sys32_ssetmask, sys_ssetmask, %o0)
-SIGN2(sys32_syslog, sys_syslog, %o0, %o2)
-SIGN1(sys32_umask, sys_umask, %o0)
-SIGN3(sys32_tgkill, sys_tgkill, %o0, %o1, %o2)
-SIGN1(sys32_sendto, sys_sendto, %o0)
SIGN1(sys32_recvfrom, compat_sys_recvfrom, %o0)
-SIGN3(sys32_socket, sys_socket, %o0, %o1, %o2)
-SIGN2(sys32_connect, sys_connect, %o0, %o2)
-SIGN2(sys32_bind, sys_bind, %o0, %o2)
-SIGN2(sys32_listen, sys_listen, %o0, %o1)
SIGN1(sys32_recvmsg, compat_sys_recvmsg, %o0)
SIGN1(sys32_sendmsg, compat_sys_sendmsg, %o0)
-SIGN2(sys32_shutdown, sys_shutdown, %o0, %o1)
-SIGN3(sys32_socketpair, sys_socketpair, %o0, %o1, %o2)
-SIGN1(sys32_getpeername, sys_getpeername, %o0)
-SIGN1(sys32_getsockname, sys_getsockname, %o0)
-SIGN2(sys32_ioprio_get, sys_ioprio_get, %o0, %o1)
-SIGN3(sys32_ioprio_set, sys_ioprio_set, %o0, %o1, %o2)
-SIGN2(sys32_splice, sys_splice, %o0, %o2)
SIGN2(sys32_sync_file_range, compat_sync_file_range, %o0, %o5)
-SIGN2(sys32_tee, sys_tee, %o0, %o1)
SIGN1(sys32_vmsplice, compat_sys_vmsplice, %o0)
-SIGN1(sys32_truncate, sys_truncate, %o1)
-SIGN1(sys32_ftruncate, sys_ftruncate, %o1)
.globl sys32_mmap2
sys32_mmap2:
diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c
index 4a4cdc633f6b..f38f2280fade 100644
--- a/arch/sparc/kernel/sys_sparc32.c
+++ b/arch/sparc/kernel/sys_sparc32.c
@@ -206,133 +206,19 @@ asmlinkage long compat_sys_fstatat64(unsigned int dfd,
return cp_compat_stat64(&stat, statbuf);
}
-asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2)
+COMPAT_SYSCALL_DEFINE3(sparc_sigaction, int, sig,
+ struct compat_old_sigaction __user *,act,
+ struct compat_old_sigaction __user *,oact)
{
- return sys_sysfs(option, arg1, arg2);
-}
-
-asmlinkage long compat_sys_rt_sigprocmask(int how,
- compat_sigset_t __user *set,
- compat_sigset_t __user *oset,
- compat_size_t sigsetsize)
-{
- sigset_t s;
- compat_sigset_t s32;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- if (set) {
- if (copy_from_user (&s32, set, sizeof(compat_sigset_t)))
- return -EFAULT;
- switch (_NSIG_WORDS) {
- case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
- case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
- case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
- case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
- }
- }
- set_fs (KERNEL_DS);
- ret = sys_rt_sigprocmask(how,
- set ? (sigset_t __user *) &s : NULL,
- oset ? (sigset_t __user *) &s : NULL,
- sigsetsize);
- set_fs (old_fs);
- if (ret) return ret;
- if (oset) {
- switch (_NSIG_WORDS) {
- case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
- case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
- case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
- case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
- }
- if (copy_to_user (oset, &s32, sizeof(compat_sigset_t)))
- return -EFAULT;
- }
- return 0;
-}
-
-asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
- compat_size_t sigsetsize)
-{
- sigset_t s;
- compat_sigset_t s32;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs (KERNEL_DS);
- ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
- set_fs (old_fs);
- if (!ret) {
- switch (_NSIG_WORDS) {
- case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
- case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
- case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
- case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
- }
- if (copy_to_user (set, &s32, sizeof(compat_sigset_t)))
- return -EFAULT;
- }
- return ret;
-}
-
-asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig,
- struct compat_siginfo __user *uinfo)
-{
- siginfo_t info;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- if (copy_siginfo_from_user32(&info, uinfo))
- return -EFAULT;
-
- set_fs (KERNEL_DS);
- ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
- set_fs (old_fs);
- return ret;
-}
-
-asmlinkage long compat_sys_sigaction(int sig, struct old_sigaction32 __user *act,
- struct old_sigaction32 __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
WARN_ON_ONCE(sig >= 0);
- sig = -sig;
-
- if (act) {
- compat_old_sigset_t mask;
- u32 u_handler, u_restorer;
-
- ret = get_user(u_handler, &act->sa_handler);
- new_ka.sa.sa_handler = compat_ptr(u_handler);
- ret |= __get_user(u_restorer, &act->sa_restorer);
- new_ka.sa.sa_restorer = compat_ptr(u_restorer);
- ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- ret |= __get_user(mask, &act->sa_mask);
- if (ret)
- return ret;
- new_ka.ka_restorer = NULL;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
- ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
- ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
- }
-
- return ret;
+ return compat_sys_sigaction(-sig, act, oact);
}
-asmlinkage long compat_sys_rt_sigaction(int sig,
- struct sigaction32 __user *act,
- struct sigaction32 __user *oact,
- void __user *restorer,
- compat_size_t sigsetsize)
+COMPAT_SYSCALL_DEFINE5(rt_sigaction, int, sig,
+ struct compat_sigaction __user *,act,
+ struct compat_sigaction __user *,oact,
+ void __user *,restorer,
+ compat_size_t,sigsetsize)
{
struct k_sigaction new_ka, old_ka;
int ret;
@@ -349,12 +235,7 @@ asmlinkage long compat_sys_rt_sigaction(int sig,
ret = get_user(u_handler, &act->sa_handler);
new_ka.sa.sa_handler = compat_ptr(u_handler);
ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t));
- switch (_NSIG_WORDS) {
- case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32);
- case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32);
- case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32);
- case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32);
- }
+ sigset_from_compat(&new_ka.sa.sa_mask, &set32);
ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
ret |= __get_user(u_restorer, &act->sa_restorer);
new_ka.sa.sa_restorer = compat_ptr(u_restorer);
@@ -365,12 +246,7 @@ asmlinkage long compat_sys_rt_sigaction(int sig,
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
if (!ret && oact) {
- switch (_NSIG_WORDS) {
- case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3];
- case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2];
- case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1];
- case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0];
- }
+ sigset_to_compat(&set32, &old_ka.sa.sa_mask);
ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t));
ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
@@ -382,35 +258,6 @@ asmlinkage long compat_sys_rt_sigaction(int sig,
return ret;
}
-#ifdef CONFIG_MODULES
-
-asmlinkage long sys32_init_module(void __user *umod, u32 len,
- const char __user *uargs)
-{
- return sys_init_module(umod, len, uargs);
-}
-
-asmlinkage long sys32_delete_module(const char __user *name_user,
- unsigned int flags)
-{
- return sys_delete_module(name_user, flags);
-}
-
-#else /* CONFIG_MODULES */
-
-asmlinkage long sys32_init_module(const char __user *name_user,
- struct module __user *mod_user)
-{
- return -ENOSYS;
-}
-
-asmlinkage long sys32_delete_module(const char __user *name_user)
-{
- return -ENOSYS;
-}
-
-#endif /* CONFIG_MODULES */
-
asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,
char __user *ubuf,
compat_size_t count,
@@ -456,16 +303,6 @@ long compat_sys_fadvise64_64(int fd,
advice);
}
-/* This is just a version for 32-bit applications which does
- * not force O_LARGEFILE on.
- */
-
-asmlinkage long sparc32_open(const char __user *filename,
- int flags, int mode)
-{
- return do_sys_open(AT_FDCWD, filename, flags, mode);
-}
-
long sys32_lookup_dcookie(unsigned long cookie_high,
unsigned long cookie_low,
char __user *buf, size_t len)
diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c
index 2da0bdcae52f..3a8d1844402e 100644
--- a/arch/sparc/kernel/sys_sparc_32.c
+++ b/arch/sparc/kernel/sys_sparc_32.c
@@ -160,49 +160,19 @@ sparc_breakpoint (struct pt_regs *regs)
#endif
}
-asmlinkage int
-sparc_sigaction (int sig, const struct old_sigaction __user *act,
- struct old_sigaction __user *oact)
+SYSCALL_DEFINE3(sparc_sigaction, int, sig,
+ struct old_sigaction __user *,act,
+ struct old_sigaction __user *,oact)
{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
WARN_ON_ONCE(sig >= 0);
- sig = -sig;
-
- if (act) {
- unsigned long mask;
-
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- new_ka.ka_restorer = NULL;
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
+ return sys_sigaction(-sig, act, oact);
}
-asmlinkage long
-sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- void __user *restorer,
- size_t sigsetsize)
+SYSCALL_DEFINE5(rt_sigaction, int, sig,
+ const struct sigaction __user *, act,
+ struct sigaction __user *, oact,
+ void __user *, restorer,
+ size_t, sigsetsize)
{
struct k_sigaction new_ka, old_ka;
int ret;
diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S
index e0fed7711a94..22a1098961f5 100644
--- a/arch/sparc/kernel/syscalls.S
+++ b/arch/sparc/kernel/syscalls.S
@@ -25,16 +25,10 @@ sys_nis_syscall:
sys_memory_ordering:
ba,pt %xcc, sparc_memory_ordering
add %sp, PTREGS_OFF, %o1
-sys_sigaltstack:
- ba,pt %xcc, do_sigaltstack
- add %i6, STACK_BIAS, %o2
#ifdef CONFIG_COMPAT
sys32_sigstack:
ba,pt %xcc, do_sys32_sigstack
mov %i6, %o2
-sys32_sigaltstack:
- ba,pt %xcc, do_sys32_sigaltstack
- mov %i6, %o2
#endif
.align 32
#ifdef CONFIG_COMPAT
diff --git a/arch/sparc/kernel/systbls.h b/arch/sparc/kernel/systbls.h
index 118759cd7342..26e6dd72e92a 100644
--- a/arch/sparc/kernel/systbls.h
+++ b/arch/sparc/kernel/systbls.h
@@ -3,8 +3,8 @@
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/signal.h>
#include <asm/utrap.h>
-#include <asm/signal.h>
extern asmlinkage unsigned long sys_getpagesize(void);
extern asmlinkage long sparc_pipe(struct pt_regs *regs);
@@ -36,8 +36,6 @@ extern asmlinkage long sys_rt_sigaction(int sig,
extern asmlinkage void sparc64_set_context(struct pt_regs *regs);
extern asmlinkage void sparc64_get_context(struct pt_regs *regs);
-extern asmlinkage long sys_sigpause(unsigned int set);
-extern asmlinkage long sys_sigsuspend(old_sigset_t set);
extern void do_rt_sigreturn(struct pt_regs *regs);
#endif /* _SYSTBLS_H */
diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S
index 6ac43c36bbbf..7b87171ecf1e 100644
--- a/arch/sparc/kernel/systbls_32.S
+++ b/arch/sparc/kernel/systbls_32.S
@@ -55,7 +55,7 @@ sys_call_table:
/*180*/ .long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_ni_syscall
/*185*/ .long sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname
/*190*/ .long sys_init_module, sys_personality, sparc_remap_file_pages, sys_epoll_create, sys_epoll_ctl
-/*195*/ .long sys_epoll_wait, sys_ioprio_set, sys_getppid, sparc_sigaction, sys_sgetmask
+/*195*/ .long sys_epoll_wait, sys_ioprio_set, sys_getppid, sys_sparc_sigaction, sys_sgetmask
/*200*/ .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_old_readdir
/*205*/ .long sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64
/*210*/ .long sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S
index 1009ecb92678..260ddcd412bf 100644
--- a/arch/sparc/kernel/systbls_64.S
+++ b/arch/sparc/kernel/systbls_64.S
@@ -18,63 +18,63 @@
.globl sys_call_table32
sys_call_table32:
-/*0*/ .word sys_restart_syscall, sys32_exit, sys_fork, sys_read, sys_write
-/*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys_link
-/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod
-/*15*/ .word sys_chmod, sys_lchown16, sys_brk, sys_nis_syscall, sys32_lseek
+/*0*/ .word sys_restart_syscall, sparc_exit, sys_fork, sys_read, sys_write
+/*5*/ .word compat_sys_open, sys_close, compat_sys_wait4, sys_creat, sys_link
+/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod
+/*15*/ .word sys_chmod, sys_lchown16, sys_brk, sys_nis_syscall, sys_lseek
/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16
-/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_pause
-/*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice
- .word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile
+/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, compat_sys_sigaltstack, sys_pause
+/*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice
+ .word sys_chown, sys_sync, sys_kill, compat_sys_newstat, sys32_sendfile
/*40*/ .word compat_sys_newlstat, sys_dup, sys_sparc_pipe, compat_sys_times, sys_getuid
- .word sys32_umount, sys_setgid16, sys_getgid16, sys32_signal, sys_geteuid16
+ .word sys_umount, sys_setgid16, sys_getgid16, sys_signal, sys_geteuid16
/*50*/ .word sys_getegid16, sys_acct, sys_nis_syscall, sys_getgid, compat_sys_ioctl
- .word sys32_reboot, sys32_mmap2, sys_symlink, sys32_readlink, sys32_execve
-/*60*/ .word sys32_umask, sys_chroot, compat_sys_newfstat, compat_sys_fstat64, sys_getpagesize
- .word sys32_msync, sys_vfork, sys32_pread64, sys32_pwrite64, sys_geteuid
+ .word sys_reboot, sys32_mmap2, sys_symlink, sys_readlink, sys32_execve
+/*60*/ .word sys_umask, sys_chroot, compat_sys_newfstat, compat_sys_fstat64, sys_getpagesize
+ .word sys_msync, sys_vfork, sys32_pread64, sys32_pwrite64, sys_geteuid
/*70*/ .word sys_getegid, sys_mmap, sys_setreuid, sys_munmap, sys_mprotect
.word sys_madvise, sys_vhangup, sys32_truncate64, sys_mincore, sys_getgroups16
-/*80*/ .word sys_setgroups16, sys_getpgrp, sys32_setgroups, sys32_setitimer, sys32_ftruncate64
- .word sys32_swapon, sys32_getitimer, sys_setuid, sys32_sethostname, sys_setgid
+/*80*/ .word sys_setgroups16, sys_getpgrp, sys_setgroups, compat_sys_setitimer, sys32_ftruncate64
+ .word sys_swapon, compat_sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
/*90*/ .word sys_dup2, sys_setfsuid, compat_sys_fcntl, sys32_select, sys_setfsgid
- .word sys_fsync, sys32_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*100*/ .word sys32_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending
- .word compat_sys_rt_sigtimedwait, sys32_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid
+ .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/ .word sys_getpriority, sys32_rt_sigreturn, compat_sys_rt_sigaction, compat_sys_rt_sigprocmask, compat_sys_rt_sigpending
+ .word compat_sys_rt_sigtimedwait, compat_sys_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid
/*110*/ .word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
- .word sys32_getgroups, compat_sys_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
+ .word sys_getgroups, compat_sys_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
/*120*/ .word compat_sys_readv, compat_sys_writev, compat_sys_settimeofday, sys_fchown16, sys_fchmod
- .word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys32_truncate
-/*130*/ .word sys32_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys32_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
-/*140*/ .word sys32_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit
- .word compat_sys_setrlimit, sys_pivot_root, sys32_prctl, sys_pciconfig_read, sys_pciconfig_write
+ .word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
+/*130*/ .word sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
+/*140*/ .word sys_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit
+ .word compat_sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
.word compat_sys_fcntl64, sys_inotify_rm_watch, compat_sys_statfs, compat_sys_fstatfs, sys_oldumount
-/*160*/ .word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys32_getdomainname, sys32_setdomainname, sys_nis_syscall
- .word sys_quotactl, sys_set_tid_address, compat_sys_mount, compat_sys_ustat, sys32_setxattr
-/*170*/ .word sys32_lsetxattr, sys32_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents
- .word sys_setsid, sys_fchdir, sys32_fgetxattr, sys_listxattr, sys_llistxattr
-/*180*/ .word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
- .word sys32_setpgid, sys32_fremovexattr, sys32_tkill, sys32_exit_group, sys_newuname
-/*190*/ .word sys32_init_module, sys_sparc64_personality, sys_remap_file_pages, sys32_epoll_create, sys32_epoll_ctl
- .word sys32_epoll_wait, sys32_ioprio_set, sys_getppid, sys32_sigaction, sys_sgetmask
-/*200*/ .word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir
- .word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64
-/*210*/ .word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, compat_sys_sysinfo
- .word compat_sys_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex
-/*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid
- .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16
-/*230*/ .word sys32_select, compat_sys_time, sys32_splice, compat_sys_stime, compat_sys_statfs64
- .word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall
-/*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler
- .word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
-/*250*/ .word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys_nis_syscall
+/*160*/ .word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
+ .word sys_quotactl, sys_set_tid_address, compat_sys_mount, compat_sys_ustat, sys_setxattr
+/*170*/ .word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, compat_sys_getdents
+ .word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/ .word sys_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
+ .word sys_setpgid, sys_fremovexattr, sys_tkill, sparc_exit_group, sys_newuname
+/*190*/ .word sys_init_module, sys_sparc64_personality, sys_remap_file_pages, sys_epoll_create, sys_epoll_ctl
+ .word sys_epoll_wait, sys_ioprio_set, sys_getppid, compat_sys_sparc_sigaction, sys_sgetmask
+/*200*/ .word sys_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir
+ .word sys32_readahead, sys32_socketcall, sys_syslog, sys32_lookup_dcookie, sys32_fadvise64
+/*210*/ .word sys32_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, compat_sys_sysinfo
+ .word compat_sys_ipc, sys32_sigreturn, sys_clone, sys_ioprio_get, compat_sys_adjtimex
+/*220*/ .word compat_sys_sigprocmask, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid
+ .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16
+/*230*/ .word sys32_select, compat_sys_time, sys_splice, compat_sys_stime, compat_sys_statfs64
+ .word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
+ .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, compat_sys_sched_rr_get_interval, compat_sys_nanosleep
+/*250*/ .word sys_mremap, compat_sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall
.word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep
/*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun
.word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy
/*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink
.word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid
-/*280*/ .word sys32_tee, sys_add_key, sys_request_key, compat_sys_keyctl, compat_sys_openat
+/*280*/ .word sys_tee, sys_add_key, sys_request_key, compat_sys_keyctl, compat_sys_openat
.word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64
/*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat
.word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
diff --git a/arch/sparc/kernel/trampoline_32.S b/arch/sparc/kernel/trampoline_32.S
index af27acab4486..6cdb08cdabf0 100644
--- a/arch/sparc/kernel/trampoline_32.S
+++ b/arch/sparc/kernel/trampoline_32.S
@@ -79,18 +79,15 @@ cpu3_startup:
nop
/* Start this processor. */
- call smp4m_callin
+ call smp_callin
nop
- b,a smp_do_cpu_idle
+ b,a smp_panic
.text
.align 4
-smp_do_cpu_idle:
- call cpu_idle
- mov 0, %o0
-
+smp_panic:
call cpu_panic
nop
@@ -144,10 +141,10 @@ sun4d_cpu_startup:
nop
/* Start this processor. */
- call smp4d_callin
+ call smp_callin
nop
- b,a smp_do_cpu_idle
+ b,a smp_panic
__CPUINIT
.align 4
@@ -201,7 +198,7 @@ leon_smp_cpu_startup:
nop
/* Start this processor. */
- call leon_callin
+ call smp_callin
nop
- b,a smp_do_cpu_idle
+ b,a smp_panic
diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c
index a5785ea2a85d..662982946a89 100644
--- a/arch/sparc/kernel/traps_32.c
+++ b/arch/sparc/kernel/traps_32.c
@@ -58,7 +58,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter);
show_regs(regs);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
__SAVE; __SAVE; __SAVE; __SAVE;
__SAVE; __SAVE; __SAVE; __SAVE;
diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
index e7ecf1507d90..8d38ca97aa23 100644
--- a/arch/sparc/kernel/traps_64.c
+++ b/arch/sparc/kernel/traps_64.c
@@ -2383,7 +2383,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV);
__asm__ __volatile__("flushw");
show_regs(regs);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
if (regs->tstate & TSTATE_PRIV) {
struct thread_info *tp = current_thread_info();
struct reg_window *rw = (struct reg_window *)
diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S
index d4bdc7a62375..a313e4a9399b 100644
--- a/arch/sparc/kernel/tsb.S
+++ b/arch/sparc/kernel/tsb.S
@@ -136,12 +136,43 @@ tsb_miss_page_table_walk_sun4v_fastpath:
nop
/* It is a huge page, use huge page TSB entry address we
- * calculated above.
+ * calculated above. If the huge page TSB has not been
+ * allocated, setup a trap stack and call hugetlb_setup()
+ * to do so, then return from the trap to replay the TLB
+ * miss.
+ *
+ * This is necessary to handle the case of transparent huge
+ * pages where we don't really have a non-atomic context
+ * in which to allocate the hugepage TSB hash table. When
+ * the 'mm' faults in the hugepage for the first time, we
+ * thus handle it here. This also makes sure that we can
+ * allocate the TSB hash table on the correct NUMA node.
*/
TRAP_LOAD_TRAP_BLOCK(%g7, %g2)
- ldx [%g7 + TRAP_PER_CPU_TSB_HUGE_TEMP], %g2
- cmp %g2, -1
- movne %xcc, %g2, %g1
+ ldx [%g7 + TRAP_PER_CPU_TSB_HUGE_TEMP], %g1
+ cmp %g1, -1
+ bne,pt %xcc, 60f
+ nop
+
+661: rdpr %pstate, %g5
+ wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate
+ .section .sun4v_2insn_patch, "ax"
+ .word 661b
+ SET_GL(1)
+ nop
+ .previous
+
+ rdpr %tl, %g3
+ cmp %g3, 1
+ bne,pn %xcc, winfix_trampoline
+ nop
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ call hugetlb_setup
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+
60:
#endif
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c
index 097aee763af3..5062ff389e83 100644
--- a/arch/sparc/mm/fault_64.c
+++ b/arch/sparc/mm/fault_64.c
@@ -472,8 +472,13 @@ good_area:
#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
mm_rss = mm->context.huge_pte_count;
if (unlikely(mm_rss >
- mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit))
- tsb_grow(mm, MM_TSB_HUGE, mm_rss);
+ mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) {
+ if (mm->context.tsb_block[MM_TSB_HUGE].tsb)
+ tsb_grow(mm, MM_TSB_HUGE, mm_rss);
+ else
+ hugetlb_setup(regs);
+
+ }
#endif
return;
diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c
index 42c55df3aec3..01ee23dd724d 100644
--- a/arch/sparc/mm/gup.c
+++ b/arch/sparc/mm/gup.c
@@ -66,6 +66,56 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
return 1;
}
+static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
+ unsigned long end, int write, struct page **pages,
+ int *nr)
+{
+ struct page *head, *page, *tail;
+ u32 mask;
+ int refs;
+
+ mask = PMD_HUGE_PRESENT;
+ if (write)
+ mask |= PMD_HUGE_WRITE;
+ if ((pmd_val(pmd) & mask) != mask)
+ return 0;
+
+ refs = 0;
+ head = pmd_page(pmd);
+ page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+ tail = page;
+ do {
+ VM_BUG_ON(compound_head(page) != head);
+ pages[*nr] = page;
+ (*nr)++;
+ page++;
+ refs++;
+ } while (addr += PAGE_SIZE, addr != end);
+
+ if (!page_cache_add_speculative(head, refs)) {
+ *nr -= refs;
+ return 0;
+ }
+
+ if (unlikely(pmd_val(pmd) != pmd_val(*pmdp))) {
+ *nr -= refs;
+ while (refs--)
+ put_page(head);
+ return 0;
+ }
+
+ /* Any tail page need their mapcount reference taken before we
+ * return.
+ */
+ while (refs--) {
+ if (PageTail(tail))
+ get_huge_page_tail(tail);
+ tail++;
+ }
+
+ return 1;
+}
+
static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
int write, struct page **pages, int *nr)
{
@@ -77,9 +127,14 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
pmd_t pmd = *pmdp;
next = pmd_addr_end(addr, end);
- if (pmd_none(pmd))
+ if (pmd_none(pmd) || pmd_trans_splitting(pmd))
return 0;
- if (!gup_pte_range(pmd, addr, next, write, pages, nr))
+ if (unlikely(pmd_large(pmd))) {
+ if (!gup_huge_pmd(pmdp, pmd, addr, next,
+ write, pages, nr))
+ return 0;
+ } else if (!gup_pte_range(pmd, addr, next, write,
+ pages, nr))
return 0;
} while (pmdp++, addr = next, addr != end);
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index dde85ef1c56d..48e0c030e8f5 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -57,7 +57,7 @@ void show_mem(unsigned int filter)
printk("Mem-info:\n");
show_free_areas(filter);
printk("Free swap: %6ldkB\n",
- nr_swap_pages << (PAGE_SHIFT-10));
+ get_nr_swap_pages() << (PAGE_SHIFT-10));
printk("%ld pages of RAM\n", totalram_pages);
printk("%ld free pages\n", nr_free_pages());
}
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index c3b72423c846..1588d33d5492 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -314,16 +314,31 @@ static void __update_mmu_tsb_insert(struct mm_struct *mm, unsigned long tsb_inde
struct tsb *tsb = mm->context.tsb_block[tsb_index].tsb;
unsigned long tag;
+ if (unlikely(!tsb))
+ return;
+
tsb += ((address >> tsb_hash_shift) &
(mm->context.tsb_block[tsb_index].tsb_nentries - 1UL));
tag = (address >> 22UL);
tsb_insert(tsb, tag, tte);
}
+#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
+static inline bool is_hugetlb_pte(pte_t pte)
+{
+ if ((tlb_type == hypervisor &&
+ (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) ||
+ (tlb_type != hypervisor &&
+ (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U))
+ return true;
+ return false;
+}
+#endif
+
void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
{
- unsigned long tsb_index, tsb_hash_shift, flags;
struct mm_struct *mm;
+ unsigned long flags;
pte_t pte = *ptep;
if (tlb_type != hypervisor) {
@@ -335,25 +350,16 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *
mm = vma->vm_mm;
- tsb_index = MM_TSB_BASE;
- tsb_hash_shift = PAGE_SHIFT;
-
spin_lock_irqsave(&mm->context.lock, flags);
#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
- if (mm->context.tsb_block[MM_TSB_HUGE].tsb != NULL) {
- if ((tlb_type == hypervisor &&
- (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) ||
- (tlb_type != hypervisor &&
- (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U)) {
- tsb_index = MM_TSB_HUGE;
- tsb_hash_shift = HPAGE_SHIFT;
- }
- }
+ if (mm->context.huge_pte_count && is_hugetlb_pte(pte))
+ __update_mmu_tsb_insert(mm, MM_TSB_HUGE, HPAGE_SHIFT,
+ address, pte_val(pte));
+ else
#endif
-
- __update_mmu_tsb_insert(mm, tsb_index, tsb_hash_shift,
- address, pte_val(pte));
+ __update_mmu_tsb_insert(mm, MM_TSB_BASE, PAGE_SHIFT,
+ address, pte_val(pte));
spin_unlock_irqrestore(&mm->context.lock, flags);
}
@@ -2021,6 +2027,16 @@ static void __init patch_tlb_miss_handler_bitmap(void)
flushi(&valid_addr_bitmap_insn[0]);
}
+static void __init register_page_bootmem_info(void)
+{
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+ int i;
+
+ for_each_online_node(i)
+ if (NODE_DATA(i)->node_spanned_pages)
+ register_page_bootmem_info_node(NODE_DATA(i));
+#endif
+}
void __init mem_init(void)
{
unsigned long codepages, datapages, initpages;
@@ -2038,20 +2054,8 @@ void __init mem_init(void)
high_memory = __va(last_valid_pfn << PAGE_SHIFT);
-#ifdef CONFIG_NEED_MULTIPLE_NODES
- {
- int i;
- for_each_online_node(i) {
- if (NODE_DATA(i)->node_spanned_pages != 0) {
- totalram_pages +=
- free_all_bootmem_node(NODE_DATA(i));
- }
- }
- totalram_pages += free_low_memory_core_early(MAX_NUMNODES);
- }
-#else
+ register_page_bootmem_info();
totalram_pages = free_all_bootmem();
-#endif
/* We subtract one to account for the mem_map_zero page
* allocated below.
@@ -2231,6 +2235,11 @@ void __meminit vmemmap_populate_print_last(void)
node_start = 0;
}
}
+
+void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+{
+}
+
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
static void prot_init_common(unsigned long page_none,
@@ -2712,14 +2721,28 @@ static void context_reload(void *__data)
load_secondary_context(mm);
}
-void hugetlb_setup(struct mm_struct *mm)
+void hugetlb_setup(struct pt_regs *regs)
{
- struct tsb_config *tp = &mm->context.tsb_block[MM_TSB_HUGE];
+ struct mm_struct *mm = current->mm;
+ struct tsb_config *tp;
- if (likely(tp->tsb != NULL))
- return;
+ if (in_atomic() || !mm) {
+ const struct exception_table_entry *entry;
+
+ entry = search_exception_tables(regs->tpc);
+ if (entry) {
+ regs->tpc = entry->fixup;
+ regs->tnpc = regs->tpc + 4;
+ return;
+ }
+ pr_alert("Unexpected HugeTLB setup in atomic context.\n");
+ die_if_kernel("HugeTSB in atomic", regs);
+ }
+
+ tp = &mm->context.tsb_block[MM_TSB_HUGE];
+ if (likely(tp->tsb == NULL))
+ tsb_grow(mm, MM_TSB_HUGE, 0);
- tsb_grow(mm, MM_TSB_HUGE, 0);
tsb_context_switch(mm);
smp_tsb_sync(mm);
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index 3e8fec391fe0..ba6ae7ffdc2c 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -135,8 +135,15 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
mm->context.huge_pte_count++;
else
mm->context.huge_pte_count--;
- if (mm->context.huge_pte_count == 1)
- hugetlb_setup(mm);
+
+ /* Do not try to allocate the TSB hash table if we
+ * don't have one already. We have various locks held
+ * and thus we'll end up doing a GFP_KERNEL allocation
+ * in an atomic context.
+ *
+ * Instead, we let the first TLB miss on a hugepage
+ * take care of this.
+ */
}
if (!pmd_none(orig)) {
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c
index 7f6474347491..428982b9becf 100644
--- a/arch/sparc/mm/tsb.c
+++ b/arch/sparc/mm/tsb.c
@@ -314,7 +314,7 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss)
retry_tsb_alloc:
gfp_flags = GFP_KERNEL;
if (new_size > (PAGE_SIZE * 2))
- gfp_flags = __GFP_NOWARN | __GFP_NORETRY;
+ gfp_flags |= __GFP_NOWARN | __GFP_NORETRY;
new_tsb = kmem_cache_alloc_node(tsb_caches[new_cache_index],
gfp_flags, numa_node_id());
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 875d008828b8..4ce6e4c390e0 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -121,6 +121,7 @@ config DEBUG_COPY_FROM_USER
def_bool n
config HVC_TILE
+ depends on TTY
select HVC_DRIVER
def_bool y
@@ -140,6 +141,8 @@ config ARCH_DEFCONFIG
source "init/Kconfig"
+source "kernel/Kconfig.freezer"
+
menu "Tilera-specific configuration"
config NR_CPUS
@@ -410,12 +413,6 @@ config TILE_USB
Provides USB host adapter support for the built-in EHCI and OHCI
interfaces on TILE-Gx chips.
-# USB OHCI needs the bounce pool since tilegx will often have more
-# than 4GB of memory, but we don't currently use the IOTLB to present
-# a 32-bit address to OHCI. So we need to use a bounce pool instead.
-config NEED_BOUNCE_POOL
- def_bool USB_OHCI_HCD
-
source "drivers/pci/hotplug/Kconfig"
endmenu
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
index 88f3c227afd9..001d418a8957 100644
--- a/arch/tile/include/asm/compat.h
+++ b/arch/tile/include/asm/compat.h
@@ -272,17 +272,9 @@ extern int compat_setup_rt_frame(int sig, struct k_sigaction *ka,
struct pt_regs *regs);
/* Compat syscalls. */
-struct compat_sigaction;
struct compat_siginfo;
struct compat_sigaltstack;
-long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
- struct compat_sigaction __user *oact,
- size_t sigsetsize);
-long compat_sys_rt_sigqueueinfo(int pid, int sig,
- struct compat_siginfo __user *uinfo);
long compat_sys_rt_sigreturn(void);
-long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr);
long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high);
long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high);
long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count,
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h
index 2a9b293fece6..31672918064c 100644
--- a/arch/tile/include/asm/io.h
+++ b/arch/tile/include/asm/io.h
@@ -250,7 +250,9 @@ static inline void writeq(u64 val, unsigned long addr)
#define iowrite32 writel
#define iowrite64 writeq
-static inline void memset_io(void *dst, int val, size_t len)
+#if CHIP_HAS_MMIO() || defined(CONFIG_PCI)
+
+static inline void memset_io(volatile void *dst, int val, size_t len)
{
int x;
BUG_ON((unsigned long)dst & 0x3);
@@ -277,6 +279,8 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src,
writel(*(u32 *)(src + x), dst + x);
}
+#endif
+
/*
* The Tile architecture does not support IOPORT, even with PCI.
* Unfortunately we can't yet simply not declare these methods,
diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h
index b4e96fef2cf8..241c0bb60b12 100644
--- a/arch/tile/include/asm/irqflags.h
+++ b/arch/tile/include/asm/irqflags.h
@@ -18,32 +18,20 @@
#include <arch/interrupts.h>
#include <arch/chip.h>
-#if !defined(__tilegx__) && defined(__ASSEMBLY__)
-
/*
* The set of interrupts we want to allow when interrupts are nominally
* disabled. The remainder are effectively "NMI" interrupts from
* the point of view of the generic Linux code. Note that synchronous
* interrupts (aka "non-queued") are not blocked by the mask in any case.
*/
-#if CHIP_HAS_AUX_PERF_COUNTERS()
-#define LINUX_MASKABLE_INTERRUPTS_HI \
- (~(INT_MASK_HI(INT_PERF_COUNT) | INT_MASK_HI(INT_AUX_PERF_COUNT)))
-#else
-#define LINUX_MASKABLE_INTERRUPTS_HI \
- (~(INT_MASK_HI(INT_PERF_COUNT)))
-#endif
-
-#else
-
-#if CHIP_HAS_AUX_PERF_COUNTERS()
-#define LINUX_MASKABLE_INTERRUPTS \
- (~(INT_MASK(INT_PERF_COUNT) | INT_MASK(INT_AUX_PERF_COUNT)))
-#else
#define LINUX_MASKABLE_INTERRUPTS \
- (~(INT_MASK(INT_PERF_COUNT)))
-#endif
+ (~((_AC(1,ULL) << INT_PERF_COUNT) | (_AC(1,ULL) << INT_AUX_PERF_COUNT)))
+#if CHIP_HAS_SPLIT_INTR_MASK()
+/* The same macro, but for the two 32-bit SPRs separately. */
+#define LINUX_MASKABLE_INTERRUPTS_LO (-1)
+#define LINUX_MASKABLE_INTERRUPTS_HI \
+ (~((1 << (INT_PERF_COUNT - 32)) | (1 << (INT_AUX_PERF_COUNT - 32))))
#endif
#ifndef __ASSEMBLY__
@@ -126,7 +114,7 @@
* to know our current state.
*/
DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
-#define INITIAL_INTERRUPTS_ENABLED INT_MASK(INT_MEM_ERROR)
+#define INITIAL_INTERRUPTS_ENABLED (1ULL << INT_MEM_ERROR)
/* Disable interrupts. */
#define arch_local_irq_disable() \
@@ -165,7 +153,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
/* Prevent the given interrupt from being enabled next time we enable irqs. */
#define arch_local_irq_mask(interrupt) \
- (__get_cpu_var(interrupts_enabled_mask) &= ~INT_MASK(interrupt))
+ (__get_cpu_var(interrupts_enabled_mask) &= ~(1ULL << (interrupt)))
/* Prevent the given interrupt from being enabled immediately. */
#define arch_local_irq_mask_now(interrupt) do { \
@@ -175,7 +163,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
/* Allow the given interrupt to be enabled next time we enable irqs. */
#define arch_local_irq_unmask(interrupt) \
- (__get_cpu_var(interrupts_enabled_mask) |= INT_MASK(interrupt))
+ (__get_cpu_var(interrupts_enabled_mask) |= (1ULL << (interrupt)))
/* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */
#define arch_local_irq_unmask_now(interrupt) do { \
@@ -250,7 +238,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
/* Disable interrupts. */
#define IRQ_DISABLE(tmp0, tmp1) \
{ \
- movei tmp0, -1; \
+ movei tmp0, LINUX_MASKABLE_INTERRUPTS_LO; \
moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS_HI) \
}; \
{ \
diff --git a/arch/tile/include/asm/syscalls.h b/arch/tile/include/asm/syscalls.h
index 4c8462a62cb6..78886e2417a6 100644
--- a/arch/tile/include/asm/syscalls.h
+++ b/arch/tile/include/asm/syscalls.h
@@ -64,9 +64,7 @@ long sys_ftruncate64(unsigned int fd, loff_t length);
/* Provide versions of standard syscalls that use current_pt_regs(). */
long sys_rt_sigreturn(void);
-long sys_sigaltstack(const stack_t __user *, stack_t __user *);
#define sys_rt_sigreturn sys_rt_sigreturn
-#define sys_sigaltstack sys_sigaltstack
/* These are the intvec*.S trampolines. */
long _sys_rt_sigreturn(void);
diff --git a/arch/tile/include/asm/unistd.h b/arch/tile/include/asm/unistd.h
index 6ac21034f69a..940831fe9e94 100644
--- a/arch/tile/include/asm/unistd.h
+++ b/arch/tile/include/asm/unistd.h
@@ -14,7 +14,6 @@
/* In compat mode, we use sys_llseek() for compat_sys_llseek(). */
#ifdef CONFIG_COMPAT
#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL
#endif
#define __ARCH_WANT_SYS_NEWFSTATAT
#define __ARCH_WANT_SYS_CLONE
diff --git a/arch/tile/include/uapi/arch/interrupts_32.h b/arch/tile/include/uapi/arch/interrupts_32.h
index 96b5710505b6..2efe3f68b2d6 100644
--- a/arch/tile/include/uapi/arch/interrupts_32.h
+++ b/arch/tile/include/uapi/arch/interrupts_32.h
@@ -15,6 +15,7 @@
#ifndef __ARCH_INTERRUPTS_H__
#define __ARCH_INTERRUPTS_H__
+#ifndef __KERNEL__
/** Mask for an interrupt. */
/* Note: must handle breaking interrupts into high and low words manually. */
#define INT_MASK_LO(intno) (1 << (intno))
@@ -23,6 +24,7 @@
#ifndef __ASSEMBLER__
#define INT_MASK(intno) (1ULL << (intno))
#endif
+#endif
/** Where a given interrupt executes */
@@ -92,216 +94,216 @@
#ifndef __ASSEMBLER__
#define QUEUED_INTERRUPTS ( \
- INT_MASK(INT_MEM_ERROR) | \
- INT_MASK(INT_DMATLB_MISS) | \
- INT_MASK(INT_DMATLB_ACCESS) | \
- INT_MASK(INT_SNITLB_MISS) | \
- INT_MASK(INT_SN_NOTIFY) | \
- INT_MASK(INT_SN_FIREWALL) | \
- INT_MASK(INT_IDN_FIREWALL) | \
- INT_MASK(INT_UDN_FIREWALL) | \
- INT_MASK(INT_TILE_TIMER) | \
- INT_MASK(INT_IDN_TIMER) | \
- INT_MASK(INT_UDN_TIMER) | \
- INT_MASK(INT_DMA_NOTIFY) | \
- INT_MASK(INT_IDN_CA) | \
- INT_MASK(INT_UDN_CA) | \
- INT_MASK(INT_IDN_AVAIL) | \
- INT_MASK(INT_UDN_AVAIL) | \
- INT_MASK(INT_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_DMA_ASID) | \
- INT_MASK(INT_SNI_ASID) | \
- INT_MASK(INT_DMA_CPL) | \
- INT_MASK(INT_SN_CPL) | \
- INT_MASK(INT_DOUBLE_FAULT) | \
- INT_MASK(INT_AUX_PERF_COUNT) | \
+ (1ULL << INT_MEM_ERROR) | \
+ (1ULL << INT_DMATLB_MISS) | \
+ (1ULL << INT_DMATLB_ACCESS) | \
+ (1ULL << INT_SNITLB_MISS) | \
+ (1ULL << INT_SN_NOTIFY) | \
+ (1ULL << INT_SN_FIREWALL) | \
+ (1ULL << INT_IDN_FIREWALL) | \
+ (1ULL << INT_UDN_FIREWALL) | \
+ (1ULL << INT_TILE_TIMER) | \
+ (1ULL << INT_IDN_TIMER) | \
+ (1ULL << INT_UDN_TIMER) | \
+ (1ULL << INT_DMA_NOTIFY) | \
+ (1ULL << INT_IDN_CA) | \
+ (1ULL << INT_UDN_CA) | \
+ (1ULL << INT_IDN_AVAIL) | \
+ (1ULL << INT_UDN_AVAIL) | \
+ (1ULL << INT_PERF_COUNT) | \
+ (1ULL << INT_INTCTRL_3) | \
+ (1ULL << INT_INTCTRL_2) | \
+ (1ULL << INT_INTCTRL_1) | \
+ (1ULL << INT_INTCTRL_0) | \
+ (1ULL << INT_BOOT_ACCESS) | \
+ (1ULL << INT_WORLD_ACCESS) | \
+ (1ULL << INT_I_ASID) | \
+ (1ULL << INT_D_ASID) | \
+ (1ULL << INT_DMA_ASID) | \
+ (1ULL << INT_SNI_ASID) | \
+ (1ULL << INT_DMA_CPL) | \
+ (1ULL << INT_SN_CPL) | \
+ (1ULL << INT_DOUBLE_FAULT) | \
+ (1ULL << INT_AUX_PERF_COUNT) | \
0)
#define NONQUEUED_INTERRUPTS ( \
- INT_MASK(INT_ITLB_MISS) | \
- INT_MASK(INT_ILL) | \
- INT_MASK(INT_GPV) | \
- INT_MASK(INT_SN_ACCESS) | \
- INT_MASK(INT_IDN_ACCESS) | \
- INT_MASK(INT_UDN_ACCESS) | \
- INT_MASK(INT_IDN_REFILL) | \
- INT_MASK(INT_UDN_REFILL) | \
- INT_MASK(INT_IDN_COMPLETE) | \
- INT_MASK(INT_UDN_COMPLETE) | \
- INT_MASK(INT_SWINT_3) | \
- INT_MASK(INT_SWINT_2) | \
- INT_MASK(INT_SWINT_1) | \
- INT_MASK(INT_SWINT_0) | \
- INT_MASK(INT_UNALIGN_DATA) | \
- INT_MASK(INT_DTLB_MISS) | \
- INT_MASK(INT_DTLB_ACCESS) | \
- INT_MASK(INT_SN_STATIC_ACCESS) | \
+ (1ULL << INT_ITLB_MISS) | \
+ (1ULL << INT_ILL) | \
+ (1ULL << INT_GPV) | \
+ (1ULL << INT_SN_ACCESS) | \
+ (1ULL << INT_IDN_ACCESS) | \
+ (1ULL << INT_UDN_ACCESS) | \
+ (1ULL << INT_IDN_REFILL) | \
+ (1ULL << INT_UDN_REFILL) | \
+ (1ULL << INT_IDN_COMPLETE) | \
+ (1ULL << INT_UDN_COMPLETE) | \
+ (1ULL << INT_SWINT_3) | \
+ (1ULL << INT_SWINT_2) | \
+ (1ULL << INT_SWINT_1) | \
+ (1ULL << INT_SWINT_0) | \
+ (1ULL << INT_UNALIGN_DATA) | \
+ (1ULL << INT_DTLB_MISS) | \
+ (1ULL << INT_DTLB_ACCESS) | \
+ (1ULL << INT_SN_STATIC_ACCESS) | \
0)
#define CRITICAL_MASKED_INTERRUPTS ( \
- INT_MASK(INT_MEM_ERROR) | \
- INT_MASK(INT_DMATLB_MISS) | \
- INT_MASK(INT_DMATLB_ACCESS) | \
- INT_MASK(INT_SNITLB_MISS) | \
- INT_MASK(INT_SN_NOTIFY) | \
- INT_MASK(INT_SN_FIREWALL) | \
- INT_MASK(INT_IDN_FIREWALL) | \
- INT_MASK(INT_UDN_FIREWALL) | \
- INT_MASK(INT_TILE_TIMER) | \
- INT_MASK(INT_IDN_TIMER) | \
- INT_MASK(INT_UDN_TIMER) | \
- INT_MASK(INT_DMA_NOTIFY) | \
- INT_MASK(INT_IDN_CA) | \
- INT_MASK(INT_UDN_CA) | \
- INT_MASK(INT_IDN_AVAIL) | \
- INT_MASK(INT_UDN_AVAIL) | \
- INT_MASK(INT_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_AUX_PERF_COUNT) | \
+ (1ULL << INT_MEM_ERROR) | \
+ (1ULL << INT_DMATLB_MISS) | \
+ (1ULL << INT_DMATLB_ACCESS) | \
+ (1ULL << INT_SNITLB_MISS) | \
+ (1ULL << INT_SN_NOTIFY) | \
+ (1ULL << INT_SN_FIREWALL) | \
+ (1ULL << INT_IDN_FIREWALL) | \
+ (1ULL << INT_UDN_FIREWALL) | \
+ (1ULL << INT_TILE_TIMER) | \
+ (1ULL << INT_IDN_TIMER) | \
+ (1ULL << INT_UDN_TIMER) | \
+ (1ULL << INT_DMA_NOTIFY) | \
+ (1ULL << INT_IDN_CA) | \
+ (1ULL << INT_UDN_CA) | \
+ (1ULL << INT_IDN_AVAIL) | \
+ (1ULL << INT_UDN_AVAIL) | \
+ (1ULL << INT_PERF_COUNT) | \
+ (1ULL << INT_INTCTRL_3) | \
+ (1ULL << INT_INTCTRL_2) | \
+ (1ULL << INT_INTCTRL_1) | \
+ (1ULL << INT_INTCTRL_0) | \
+ (1ULL << INT_AUX_PERF_COUNT) | \
0)
#define CRITICAL_UNMASKED_INTERRUPTS ( \
- INT_MASK(INT_ITLB_MISS) | \
- INT_MASK(INT_ILL) | \
- INT_MASK(INT_GPV) | \
- INT_MASK(INT_SN_ACCESS) | \
- INT_MASK(INT_IDN_ACCESS) | \
- INT_MASK(INT_UDN_ACCESS) | \
- INT_MASK(INT_IDN_REFILL) | \
- INT_MASK(INT_UDN_REFILL) | \
- INT_MASK(INT_IDN_COMPLETE) | \
- INT_MASK(INT_UDN_COMPLETE) | \
- INT_MASK(INT_SWINT_3) | \
- INT_MASK(INT_SWINT_2) | \
- INT_MASK(INT_SWINT_1) | \
- INT_MASK(INT_SWINT_0) | \
- 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_DMA_ASID) | \
- INT_MASK(INT_SNI_ASID) | \
- INT_MASK(INT_DMA_CPL) | \
- INT_MASK(INT_SN_CPL) | \
- INT_MASK(INT_DOUBLE_FAULT) | \
- INT_MASK(INT_SN_STATIC_ACCESS) | \
+ (1ULL << INT_ITLB_MISS) | \
+ (1ULL << INT_ILL) | \
+ (1ULL << INT_GPV) | \
+ (1ULL << INT_SN_ACCESS) | \
+ (1ULL << INT_IDN_ACCESS) | \
+ (1ULL << INT_UDN_ACCESS) | \
+ (1ULL << INT_IDN_REFILL) | \
+ (1ULL << INT_UDN_REFILL) | \
+ (1ULL << INT_IDN_COMPLETE) | \
+ (1ULL << INT_UDN_COMPLETE) | \
+ (1ULL << INT_SWINT_3) | \
+ (1ULL << INT_SWINT_2) | \
+ (1ULL << INT_SWINT_1) | \
+ (1ULL << INT_SWINT_0) | \
+ (1ULL << INT_UNALIGN_DATA) | \
+ (1ULL << INT_DTLB_MISS) | \
+ (1ULL << INT_DTLB_ACCESS) | \
+ (1ULL << INT_BOOT_ACCESS) | \
+ (1ULL << INT_WORLD_ACCESS) | \
+ (1ULL << INT_I_ASID) | \
+ (1ULL << INT_D_ASID) | \
+ (1ULL << INT_DMA_ASID) | \
+ (1ULL << INT_SNI_ASID) | \
+ (1ULL << INT_DMA_CPL) | \
+ (1ULL << INT_SN_CPL) | \
+ (1ULL << INT_DOUBLE_FAULT) | \
+ (1ULL << INT_SN_STATIC_ACCESS) | \
0)
#define MASKABLE_INTERRUPTS ( \
- INT_MASK(INT_MEM_ERROR) | \
- INT_MASK(INT_IDN_REFILL) | \
- INT_MASK(INT_UDN_REFILL) | \
- INT_MASK(INT_IDN_COMPLETE) | \
- INT_MASK(INT_UDN_COMPLETE) | \
- INT_MASK(INT_DMATLB_MISS) | \
- INT_MASK(INT_DMATLB_ACCESS) | \
- INT_MASK(INT_SNITLB_MISS) | \
- INT_MASK(INT_SN_NOTIFY) | \
- INT_MASK(INT_SN_FIREWALL) | \
- INT_MASK(INT_IDN_FIREWALL) | \
- INT_MASK(INT_UDN_FIREWALL) | \
- INT_MASK(INT_TILE_TIMER) | \
- INT_MASK(INT_IDN_TIMER) | \
- INT_MASK(INT_UDN_TIMER) | \
- INT_MASK(INT_DMA_NOTIFY) | \
- INT_MASK(INT_IDN_CA) | \
- INT_MASK(INT_UDN_CA) | \
- INT_MASK(INT_IDN_AVAIL) | \
- INT_MASK(INT_UDN_AVAIL) | \
- INT_MASK(INT_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_AUX_PERF_COUNT) | \
+ (1ULL << INT_MEM_ERROR) | \
+ (1ULL << INT_IDN_REFILL) | \
+ (1ULL << INT_UDN_REFILL) | \
+ (1ULL << INT_IDN_COMPLETE) | \
+ (1ULL << INT_UDN_COMPLETE) | \
+ (1ULL << INT_DMATLB_MISS) | \
+ (1ULL << INT_DMATLB_ACCESS) | \
+ (1ULL << INT_SNITLB_MISS) | \
+ (1ULL << INT_SN_NOTIFY) | \
+ (1ULL << INT_SN_FIREWALL) | \
+ (1ULL << INT_IDN_FIREWALL) | \
+ (1ULL << INT_UDN_FIREWALL) | \
+ (1ULL << INT_TILE_TIMER) | \
+ (1ULL << INT_IDN_TIMER) | \
+ (1ULL << INT_UDN_TIMER) | \
+ (1ULL << INT_DMA_NOTIFY) | \
+ (1ULL << INT_IDN_CA) | \
+ (1ULL << INT_UDN_CA) | \
+ (1ULL << INT_IDN_AVAIL) | \
+ (1ULL << INT_UDN_AVAIL) | \
+ (1ULL << INT_PERF_COUNT) | \
+ (1ULL << INT_INTCTRL_3) | \
+ (1ULL << INT_INTCTRL_2) | \
+ (1ULL << INT_INTCTRL_1) | \
+ (1ULL << INT_INTCTRL_0) | \
+ (1ULL << INT_AUX_PERF_COUNT) | \
0)
#define UNMASKABLE_INTERRUPTS ( \
- INT_MASK(INT_ITLB_MISS) | \
- INT_MASK(INT_ILL) | \
- INT_MASK(INT_GPV) | \
- INT_MASK(INT_SN_ACCESS) | \
- 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_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_DMA_ASID) | \
- INT_MASK(INT_SNI_ASID) | \
- INT_MASK(INT_DMA_CPL) | \
- INT_MASK(INT_SN_CPL) | \
- INT_MASK(INT_DOUBLE_FAULT) | \
- INT_MASK(INT_SN_STATIC_ACCESS) | \
+ (1ULL << INT_ITLB_MISS) | \
+ (1ULL << INT_ILL) | \
+ (1ULL << INT_GPV) | \
+ (1ULL << INT_SN_ACCESS) | \
+ (1ULL << INT_IDN_ACCESS) | \
+ (1ULL << INT_UDN_ACCESS) | \
+ (1ULL << INT_SWINT_3) | \
+ (1ULL << INT_SWINT_2) | \
+ (1ULL << INT_SWINT_1) | \
+ (1ULL << INT_SWINT_0) | \
+ (1ULL << INT_UNALIGN_DATA) | \
+ (1ULL << INT_DTLB_MISS) | \
+ (1ULL << INT_DTLB_ACCESS) | \
+ (1ULL << INT_BOOT_ACCESS) | \
+ (1ULL << INT_WORLD_ACCESS) | \
+ (1ULL << INT_I_ASID) | \
+ (1ULL << INT_D_ASID) | \
+ (1ULL << INT_DMA_ASID) | \
+ (1ULL << INT_SNI_ASID) | \
+ (1ULL << INT_DMA_CPL) | \
+ (1ULL << INT_SN_CPL) | \
+ (1ULL << INT_DOUBLE_FAULT) | \
+ (1ULL << INT_SN_STATIC_ACCESS) | \
0)
#define SYNC_INTERRUPTS ( \
- INT_MASK(INT_ITLB_MISS) | \
- INT_MASK(INT_ILL) | \
- INT_MASK(INT_GPV) | \
- INT_MASK(INT_SN_ACCESS) | \
- INT_MASK(INT_IDN_ACCESS) | \
- INT_MASK(INT_UDN_ACCESS) | \
- INT_MASK(INT_IDN_REFILL) | \
- INT_MASK(INT_UDN_REFILL) | \
- INT_MASK(INT_IDN_COMPLETE) | \
- INT_MASK(INT_UDN_COMPLETE) | \
- INT_MASK(INT_SWINT_3) | \
- INT_MASK(INT_SWINT_2) | \
- INT_MASK(INT_SWINT_1) | \
- INT_MASK(INT_SWINT_0) | \
- INT_MASK(INT_UNALIGN_DATA) | \
- INT_MASK(INT_DTLB_MISS) | \
- INT_MASK(INT_DTLB_ACCESS) | \
- INT_MASK(INT_SN_STATIC_ACCESS) | \
+ (1ULL << INT_ITLB_MISS) | \
+ (1ULL << INT_ILL) | \
+ (1ULL << INT_GPV) | \
+ (1ULL << INT_SN_ACCESS) | \
+ (1ULL << INT_IDN_ACCESS) | \
+ (1ULL << INT_UDN_ACCESS) | \
+ (1ULL << INT_IDN_REFILL) | \
+ (1ULL << INT_UDN_REFILL) | \
+ (1ULL << INT_IDN_COMPLETE) | \
+ (1ULL << INT_UDN_COMPLETE) | \
+ (1ULL << INT_SWINT_3) | \
+ (1ULL << INT_SWINT_2) | \
+ (1ULL << INT_SWINT_1) | \
+ (1ULL << INT_SWINT_0) | \
+ (1ULL << INT_UNALIGN_DATA) | \
+ (1ULL << INT_DTLB_MISS) | \
+ (1ULL << INT_DTLB_ACCESS) | \
+ (1ULL << INT_SN_STATIC_ACCESS) | \
0)
#define NON_SYNC_INTERRUPTS ( \
- INT_MASK(INT_MEM_ERROR) | \
- INT_MASK(INT_DMATLB_MISS) | \
- INT_MASK(INT_DMATLB_ACCESS) | \
- INT_MASK(INT_SNITLB_MISS) | \
- INT_MASK(INT_SN_NOTIFY) | \
- INT_MASK(INT_SN_FIREWALL) | \
- INT_MASK(INT_IDN_FIREWALL) | \
- INT_MASK(INT_UDN_FIREWALL) | \
- INT_MASK(INT_TILE_TIMER) | \
- INT_MASK(INT_IDN_TIMER) | \
- INT_MASK(INT_UDN_TIMER) | \
- INT_MASK(INT_DMA_NOTIFY) | \
- INT_MASK(INT_IDN_CA) | \
- INT_MASK(INT_UDN_CA) | \
- INT_MASK(INT_IDN_AVAIL) | \
- INT_MASK(INT_UDN_AVAIL) | \
- INT_MASK(INT_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_DMA_ASID) | \
- INT_MASK(INT_SNI_ASID) | \
- INT_MASK(INT_DMA_CPL) | \
- INT_MASK(INT_SN_CPL) | \
- INT_MASK(INT_DOUBLE_FAULT) | \
- INT_MASK(INT_AUX_PERF_COUNT) | \
+ (1ULL << INT_MEM_ERROR) | \
+ (1ULL << INT_DMATLB_MISS) | \
+ (1ULL << INT_DMATLB_ACCESS) | \
+ (1ULL << INT_SNITLB_MISS) | \
+ (1ULL << INT_SN_NOTIFY) | \
+ (1ULL << INT_SN_FIREWALL) | \
+ (1ULL << INT_IDN_FIREWALL) | \
+ (1ULL << INT_UDN_FIREWALL) | \
+ (1ULL << INT_TILE_TIMER) | \
+ (1ULL << INT_IDN_TIMER) | \
+ (1ULL << INT_UDN_TIMER) | \
+ (1ULL << INT_DMA_NOTIFY) | \
+ (1ULL << INT_IDN_CA) | \
+ (1ULL << INT_UDN_CA) | \
+ (1ULL << INT_IDN_AVAIL) | \
+ (1ULL << INT_UDN_AVAIL) | \
+ (1ULL << INT_PERF_COUNT) | \
+ (1ULL << INT_INTCTRL_3) | \
+ (1ULL << INT_INTCTRL_2) | \
+ (1ULL << INT_INTCTRL_1) | \
+ (1ULL << INT_INTCTRL_0) | \
+ (1ULL << INT_BOOT_ACCESS) | \
+ (1ULL << INT_WORLD_ACCESS) | \
+ (1ULL << INT_I_ASID) | \
+ (1ULL << INT_D_ASID) | \
+ (1ULL << INT_DMA_ASID) | \
+ (1ULL << INT_SNI_ASID) | \
+ (1ULL << INT_DMA_CPL) | \
+ (1ULL << INT_SN_CPL) | \
+ (1ULL << INT_DOUBLE_FAULT) | \
+ (1ULL << INT_AUX_PERF_COUNT) | \
0)
#endif /* !__ASSEMBLER__ */
#endif /* !__ARCH_INTERRUPTS_H__ */
diff --git a/arch/tile/include/uapi/arch/interrupts_64.h b/arch/tile/include/uapi/arch/interrupts_64.h
index 5bb58b2e4e6f..13c9f9182348 100644
--- a/arch/tile/include/uapi/arch/interrupts_64.h
+++ b/arch/tile/include/uapi/arch/interrupts_64.h
@@ -15,6 +15,7 @@
#ifndef __ARCH_INTERRUPTS_H__
#define __ARCH_INTERRUPTS_H__
+#ifndef __KERNEL__
/** Mask for an interrupt. */
#ifdef __ASSEMBLER__
/* Note: must handle breaking interrupts into high and low words manually. */
@@ -22,6 +23,7 @@
#else
#define INT_MASK(intno) (1ULL << (intno))
#endif
+#endif
/** Where a given interrupt executes */
@@ -85,192 +87,192 @@
#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) | \
+ (1ULL << INT_MEM_ERROR) | \
+ (1ULL << INT_IDN_COMPLETE) | \
+ (1ULL << INT_UDN_COMPLETE) | \
+ (1ULL << INT_IDN_FIREWALL) | \
+ (1ULL << INT_UDN_FIREWALL) | \
+ (1ULL << INT_TILE_TIMER) | \
+ (1ULL << INT_AUX_TILE_TIMER) | \
+ (1ULL << INT_IDN_TIMER) | \
+ (1ULL << INT_UDN_TIMER) | \
+ (1ULL << INT_IDN_AVAIL) | \
+ (1ULL << INT_UDN_AVAIL) | \
+ (1ULL << INT_IPI_3) | \
+ (1ULL << INT_IPI_2) | \
+ (1ULL << INT_IPI_1) | \
+ (1ULL << INT_IPI_0) | \
+ (1ULL << INT_PERF_COUNT) | \
+ (1ULL << INT_AUX_PERF_COUNT) | \
+ (1ULL << INT_INTCTRL_3) | \
+ (1ULL << INT_INTCTRL_2) | \
+ (1ULL << INT_INTCTRL_1) | \
+ (1ULL << INT_INTCTRL_0) | \
+ (1ULL << INT_BOOT_ACCESS) | \
+ (1ULL << INT_WORLD_ACCESS) | \
+ (1ULL << INT_I_ASID) | \
+ (1ULL << INT_D_ASID) | \
+ (1ULL << 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) | \
+ (1ULL << INT_SINGLE_STEP_3) | \
+ (1ULL << INT_SINGLE_STEP_2) | \
+ (1ULL << INT_SINGLE_STEP_1) | \
+ (1ULL << INT_SINGLE_STEP_0) | \
+ (1ULL << INT_ITLB_MISS) | \
+ (1ULL << INT_ILL) | \
+ (1ULL << INT_GPV) | \
+ (1ULL << INT_IDN_ACCESS) | \
+ (1ULL << INT_UDN_ACCESS) | \
+ (1ULL << INT_SWINT_3) | \
+ (1ULL << INT_SWINT_2) | \
+ (1ULL << INT_SWINT_1) | \
+ (1ULL << INT_SWINT_0) | \
+ (1ULL << INT_ILL_TRANS) | \
+ (1ULL << INT_UNALIGN_DATA) | \
+ (1ULL << INT_DTLB_MISS) | \
+ (1ULL << 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) | \
+ (1ULL << INT_MEM_ERROR) | \
+ (1ULL << INT_SINGLE_STEP_3) | \
+ (1ULL << INT_SINGLE_STEP_2) | \
+ (1ULL << INT_SINGLE_STEP_1) | \
+ (1ULL << INT_SINGLE_STEP_0) | \
+ (1ULL << INT_IDN_COMPLETE) | \
+ (1ULL << INT_UDN_COMPLETE) | \
+ (1ULL << INT_IDN_FIREWALL) | \
+ (1ULL << INT_UDN_FIREWALL) | \
+ (1ULL << INT_TILE_TIMER) | \
+ (1ULL << INT_AUX_TILE_TIMER) | \
+ (1ULL << INT_IDN_TIMER) | \
+ (1ULL << INT_UDN_TIMER) | \
+ (1ULL << INT_IDN_AVAIL) | \
+ (1ULL << INT_UDN_AVAIL) | \
+ (1ULL << INT_IPI_3) | \
+ (1ULL << INT_IPI_2) | \
+ (1ULL << INT_IPI_1) | \
+ (1ULL << INT_IPI_0) | \
+ (1ULL << INT_PERF_COUNT) | \
+ (1ULL << INT_AUX_PERF_COUNT) | \
+ (1ULL << INT_INTCTRL_3) | \
+ (1ULL << INT_INTCTRL_2) | \
+ (1ULL << INT_INTCTRL_1) | \
+ (1ULL << 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) | \
+ (1ULL << INT_ITLB_MISS) | \
+ (1ULL << INT_ILL) | \
+ (1ULL << INT_GPV) | \
+ (1ULL << INT_IDN_ACCESS) | \
+ (1ULL << INT_UDN_ACCESS) | \
+ (1ULL << INT_SWINT_3) | \
+ (1ULL << INT_SWINT_2) | \
+ (1ULL << INT_SWINT_1) | \
+ (1ULL << INT_SWINT_0) | \
+ (1ULL << INT_ILL_TRANS) | \
+ (1ULL << INT_UNALIGN_DATA) | \
+ (1ULL << INT_DTLB_MISS) | \
+ (1ULL << INT_DTLB_ACCESS) | \
+ (1ULL << INT_BOOT_ACCESS) | \
+ (1ULL << INT_WORLD_ACCESS) | \
+ (1ULL << INT_I_ASID) | \
+ (1ULL << INT_D_ASID) | \
+ (1ULL << 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) | \
+ (1ULL << INT_MEM_ERROR) | \
+ (1ULL << INT_SINGLE_STEP_3) | \
+ (1ULL << INT_SINGLE_STEP_2) | \
+ (1ULL << INT_SINGLE_STEP_1) | \
+ (1ULL << INT_SINGLE_STEP_0) | \
+ (1ULL << INT_IDN_COMPLETE) | \
+ (1ULL << INT_UDN_COMPLETE) | \
+ (1ULL << INT_IDN_FIREWALL) | \
+ (1ULL << INT_UDN_FIREWALL) | \
+ (1ULL << INT_TILE_TIMER) | \
+ (1ULL << INT_AUX_TILE_TIMER) | \
+ (1ULL << INT_IDN_TIMER) | \
+ (1ULL << INT_UDN_TIMER) | \
+ (1ULL << INT_IDN_AVAIL) | \
+ (1ULL << INT_UDN_AVAIL) | \
+ (1ULL << INT_IPI_3) | \
+ (1ULL << INT_IPI_2) | \
+ (1ULL << INT_IPI_1) | \
+ (1ULL << INT_IPI_0) | \
+ (1ULL << INT_PERF_COUNT) | \
+ (1ULL << INT_AUX_PERF_COUNT) | \
+ (1ULL << INT_INTCTRL_3) | \
+ (1ULL << INT_INTCTRL_2) | \
+ (1ULL << INT_INTCTRL_1) | \
+ (1ULL << 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) | \
+ (1ULL << INT_ITLB_MISS) | \
+ (1ULL << INT_ILL) | \
+ (1ULL << INT_GPV) | \
+ (1ULL << INT_IDN_ACCESS) | \
+ (1ULL << INT_UDN_ACCESS) | \
+ (1ULL << INT_SWINT_3) | \
+ (1ULL << INT_SWINT_2) | \
+ (1ULL << INT_SWINT_1) | \
+ (1ULL << INT_SWINT_0) | \
+ (1ULL << INT_ILL_TRANS) | \
+ (1ULL << INT_UNALIGN_DATA) | \
+ (1ULL << INT_DTLB_MISS) | \
+ (1ULL << INT_DTLB_ACCESS) | \
+ (1ULL << INT_BOOT_ACCESS) | \
+ (1ULL << INT_WORLD_ACCESS) | \
+ (1ULL << INT_I_ASID) | \
+ (1ULL << INT_D_ASID) | \
+ (1ULL << 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) | \
+ (1ULL << INT_SINGLE_STEP_3) | \
+ (1ULL << INT_SINGLE_STEP_2) | \
+ (1ULL << INT_SINGLE_STEP_1) | \
+ (1ULL << INT_SINGLE_STEP_0) | \
+ (1ULL << INT_IDN_COMPLETE) | \
+ (1ULL << INT_UDN_COMPLETE) | \
+ (1ULL << INT_ITLB_MISS) | \
+ (1ULL << INT_ILL) | \
+ (1ULL << INT_GPV) | \
+ (1ULL << INT_IDN_ACCESS) | \
+ (1ULL << INT_UDN_ACCESS) | \
+ (1ULL << INT_SWINT_3) | \
+ (1ULL << INT_SWINT_2) | \
+ (1ULL << INT_SWINT_1) | \
+ (1ULL << INT_SWINT_0) | \
+ (1ULL << INT_ILL_TRANS) | \
+ (1ULL << INT_UNALIGN_DATA) | \
+ (1ULL << INT_DTLB_MISS) | \
+ (1ULL << 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) | \
+ (1ULL << INT_MEM_ERROR) | \
+ (1ULL << INT_IDN_FIREWALL) | \
+ (1ULL << INT_UDN_FIREWALL) | \
+ (1ULL << INT_TILE_TIMER) | \
+ (1ULL << INT_AUX_TILE_TIMER) | \
+ (1ULL << INT_IDN_TIMER) | \
+ (1ULL << INT_UDN_TIMER) | \
+ (1ULL << INT_IDN_AVAIL) | \
+ (1ULL << INT_UDN_AVAIL) | \
+ (1ULL << INT_IPI_3) | \
+ (1ULL << INT_IPI_2) | \
+ (1ULL << INT_IPI_1) | \
+ (1ULL << INT_IPI_0) | \
+ (1ULL << INT_PERF_COUNT) | \
+ (1ULL << INT_AUX_PERF_COUNT) | \
+ (1ULL << INT_INTCTRL_3) | \
+ (1ULL << INT_INTCTRL_2) | \
+ (1ULL << INT_INTCTRL_1) | \
+ (1ULL << INT_INTCTRL_0) | \
+ (1ULL << INT_BOOT_ACCESS) | \
+ (1ULL << INT_WORLD_ACCESS) | \
+ (1ULL << INT_I_ASID) | \
+ (1ULL << INT_D_ASID) | \
+ (1ULL << INT_DOUBLE_FAULT) | \
0)
#endif /* !__ASSEMBLER__ */
#endif /* !__ARCH_INTERRUPTS_H__ */
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 2e4cc69224a6..d0a052e725be 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -34,19 +34,6 @@
#include <asm/syscalls.h>
#include <arch/interrupts.h>
-struct compat_sigaction {
- compat_uptr_t sa_handler;
- compat_ulong_t sa_flags;
- compat_uptr_t sa_restorer;
- sigset_t sa_mask __packed;
-};
-
-struct compat_sigaltstack {
- compat_uptr_t ss_sp;
- int ss_flags;
- compat_size_t ss_size;
-};
-
struct compat_ucontext {
compat_ulong_t uc_flags;
compat_uptr_t uc_link;
@@ -61,63 +48,6 @@ struct compat_rt_sigframe {
struct compat_ucontext uc;
};
-long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
- struct compat_sigaction __user *oact,
- size_t sigsetsize)
-{
- struct k_sigaction new_sa, old_sa;
- int ret = -EINVAL;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- goto out;
-
- if (act) {
- compat_uptr_t handler, restorer;
-
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(handler, &act->sa_handler) ||
- __get_user(new_sa.sa.sa_flags, &act->sa_flags) ||
- __get_user(restorer, &act->sa_restorer) ||
- __copy_from_user(&new_sa.sa.sa_mask, &act->sa_mask,
- sizeof(sigset_t)))
- return -EFAULT;
- new_sa.sa.sa_handler = compat_ptr(handler);
- new_sa.sa.sa_restorer = compat_ptr(restorer);
- }
-
- ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(ptr_to_compat(old_sa.sa.sa_handler),
- &oact->sa_handler) ||
- __put_user(ptr_to_compat(old_sa.sa.sa_restorer),
- &oact->sa_restorer) ||
- __put_user(old_sa.sa.sa_flags, &oact->sa_flags) ||
- __copy_to_user(&oact->sa_mask, &old_sa.sa.sa_mask,
- sizeof(sigset_t)))
- return -EFAULT;
- }
-out:
- return ret;
-}
-
-long compat_sys_rt_sigqueueinfo(int pid, int sig,
- struct compat_siginfo __user *uinfo)
-{
- siginfo_t info;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- if (copy_siginfo_from_user32(&info, uinfo))
- return -EFAULT;
- set_fs(KERNEL_DS);
- ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *)&info);
- set_fs(old_fs);
- return ret;
-}
-
int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from)
{
int err;
@@ -196,40 +126,6 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
return err;
}
-long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr)
-{
- stack_t uss, uoss;
- int ret;
- mm_segment_t seg;
-
- if (uss_ptr) {
- u32 ptr;
-
- memset(&uss, 0, sizeof(stack_t));
- if (!access_ok(VERIFY_READ, uss_ptr, sizeof(*uss_ptr)) ||
- __get_user(ptr, &uss_ptr->ss_sp) ||
- __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
- __get_user(uss.ss_size, &uss_ptr->ss_size))
- return -EFAULT;
- uss.ss_sp = compat_ptr(ptr);
- }
- seg = get_fs();
- set_fs(KERNEL_DS);
- ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL,
- (stack_t __user __force *)&uoss,
- (unsigned long)compat_ptr(current_pt_regs()->sp));
- set_fs(seg);
- if (ret >= 0 && uoss_ptr) {
- if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) ||
- __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
- __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
- __put_user(uoss.ss_size, &uoss_ptr->ss_size))
- ret = -EFAULT;
- }
- return ret;
-}
-
/* The assembly shim for this function arranges to ignore the return value. */
long compat_sys_rt_sigreturn(void)
{
@@ -248,7 +144,7 @@ long compat_sys_rt_sigreturn(void)
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL) == -EFAULT)
+ if (compat_restore_altstack(&frame->uc.uc_stack))
goto badframe;
return 0;
@@ -325,11 +221,7 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(ptr_to_compat((void *)(current->sas_ss_sp)),
- &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
index 54bc9a6678e8..4ea080902654 100644
--- a/arch/tile/kernel/intvec_64.S
+++ b/arch/tile/kernel/intvec_64.S
@@ -1035,7 +1035,9 @@ handle_syscall:
/* Ensure that the syscall number is within the legal range. */
{
moveli r20, hw2(sys_call_table)
+#ifdef CONFIG_COMPAT
blbs r30, .Lcompat_syscall
+#endif
}
{
cmpltu r21, TREG_SYSCALL_NR_NAME, r21
@@ -1093,6 +1095,7 @@ handle_syscall:
j .Lresume_userspace /* jump into middle of interrupt_return */
}
+#ifdef CONFIG_COMPAT
.Lcompat_syscall:
/*
* Load the base of the compat syscall table in r20, and
@@ -1117,6 +1120,7 @@ handle_syscall:
{ move r15, r4; addxi r4, r4, 0 }
{ move r16, r5; addxi r5, r5, 0 }
j .Lload_syscall_pointer
+#endif
.Linvalid_syscall:
/* Report an invalid syscall back to the user program */
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 0e5661e7d00d..caf93ae11793 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -159,7 +159,7 @@ static void save_arch_state(struct thread_struct *t);
int copy_thread(unsigned long clone_flags, unsigned long sp,
unsigned long arg, struct task_struct *p)
{
- struct pt_regs *childregs = task_pt_regs(p), *regs = current_pt_regs();
+ struct pt_regs *childregs = task_pt_regs(p);
unsigned long ksp;
unsigned long *callee_regs;
diff --git a/arch/tile/kernel/reboot.c b/arch/tile/kernel/reboot.c
index baa3d905fee2..d1b5c913ae72 100644
--- a/arch/tile/kernel/reboot.c
+++ b/arch/tile/kernel/reboot.c
@@ -16,6 +16,7 @@
#include <linux/reboot.h>
#include <linux/smp.h>
#include <linux/pm.h>
+#include <linux/export.h>
#include <asm/page.h>
#include <asm/setup.h>
#include <hv/hypervisor.h>
@@ -49,3 +50,4 @@ void machine_restart(char *cmd)
/* No interesting distinction to be made here. */
void (*pm_power_off)(void) = NULL;
+EXPORT_SYMBOL(pm_power_off);
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index 6a649a4462d3..d1e15f7b59c6 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -31,6 +31,7 @@
#include <linux/timex.h>
#include <linux/hugetlb.h>
#include <linux/start_kernel.h>
+#include <linux/screen_info.h>
#include <asm/setup.h>
#include <asm/sections.h>
#include <asm/cacheflush.h>
@@ -49,6 +50,10 @@ static inline int ABS(int x) { return x >= 0 ? x : -x; }
/* Chip information */
char chip_model[64] __write_once;
+#ifdef CONFIG_VT
+struct screen_info screen_info;
+#endif
+
struct pglist_data node_data[MAX_NUMNODES] __read_mostly;
EXPORT_SYMBOL(node_data);
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index 657a7ace4ab4..9531845bf661 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -37,13 +37,6 @@
#define DEBUG_SIG 0
-SYSCALL_DEFINE2(sigaltstack, const stack_t __user *, uss,
- stack_t __user *, uoss)
-{
- return do_sigaltstack(uss, uoss, current_pt_regs()->sp);
-}
-
-
/*
* Do a signal return; undo the signal stack.
*/
@@ -100,7 +93,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return 0;
@@ -191,11 +184,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
- err |= __put_user((void __user *)(current->sas_ss_sp),
- &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index b2f44c28dda6..ed258b8ae320 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -112,7 +112,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
p->pc, p->sp, p->ex1);
p = NULL;
}
- if (!kbt->profile || (INT_MASK(p->faultnum) & QUEUED_INTERRUPTS) == 0)
+ if (!kbt->profile || ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) == 0)
return p;
return NULL;
}
@@ -484,6 +484,7 @@ void save_stack_trace(struct stack_trace *trace)
{
save_stack_trace_tsk(NULL, trace);
}
+EXPORT_SYMBOL_GPL(save_stack_trace);
#endif
diff --git a/arch/tile/kvm/Kconfig b/arch/tile/kvm/Kconfig
index 669fcdba31ea..2298cb1daff7 100644
--- a/arch/tile/kvm/Kconfig
+++ b/arch/tile/kvm/Kconfig
@@ -18,7 +18,7 @@ if VIRTUALIZATION
config KVM
tristate "Kernel-based Virtual Machine (KVM) support"
- depends on HAVE_KVM && MODULES && EXPERIMENTAL
+ depends on HAVE_KVM && MODULES
select PREEMPT_NOTIFIERS
select ANON_INODES
---help---
diff --git a/arch/tile/lib/cacheflush.c b/arch/tile/lib/cacheflush.c
index db4fb89e12d8..8f8ad814b139 100644
--- a/arch/tile/lib/cacheflush.c
+++ b/arch/tile/lib/cacheflush.c
@@ -12,6 +12,7 @@
* more details.
*/
+#include <linux/export.h>
#include <asm/page.h>
#include <asm/cacheflush.h>
#include <arch/icache.h>
@@ -165,3 +166,4 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
__insn_mtspr(SPR_DSTREAM_PF, old_dstream_pf);
#endif
}
+EXPORT_SYMBOL_GPL(finv_buffer_remote);
diff --git a/arch/tile/lib/cpumask.c b/arch/tile/lib/cpumask.c
index fdc403614d12..75947edccb26 100644
--- a/arch/tile/lib/cpumask.c
+++ b/arch/tile/lib/cpumask.c
@@ -16,6 +16,7 @@
#include <linux/ctype.h>
#include <linux/errno.h>
#include <linux/smp.h>
+#include <linux/export.h>
/*
* Allow cropping out bits beyond the end of the array.
@@ -50,3 +51,4 @@ int bitmap_parselist_crop(const char *bp, unsigned long *maskp, int nmaskbits)
} while (*bp != '\0' && *bp != '\n');
return 0;
}
+EXPORT_SYMBOL(bitmap_parselist_crop);
diff --git a/arch/tile/lib/exports.c b/arch/tile/lib/exports.c
index dd5f0a33fdaf..4385cb6fa00a 100644
--- a/arch/tile/lib/exports.c
+++ b/arch/tile/lib/exports.c
@@ -55,6 +55,8 @@ EXPORT_SYMBOL(hv_dev_poll_cancel);
EXPORT_SYMBOL(hv_dev_close);
EXPORT_SYMBOL(hv_sysconf);
EXPORT_SYMBOL(hv_confstr);
+EXPORT_SYMBOL(hv_get_rtc);
+EXPORT_SYMBOL(hv_set_rtc);
/* libgcc.a */
uint32_t __udivsi3(uint32_t dividend, uint32_t divisor);
diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c
index 3cfa98bf9125..743c951c61b0 100644
--- a/arch/tile/mm/elf.c
+++ b/arch/tile/mm/elf.c
@@ -130,7 +130,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
if (!retval) {
unsigned long addr = MEM_USER_INTRPT;
addr = mmap_region(NULL, addr, INTRPT_SIZE,
- MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
VM_READ|VM_EXEC|
VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 0);
if (addr > (unsigned long) -PAGE_SIZE)
diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c
index 5f7868dcd6d4..1ae911939a18 100644
--- a/arch/tile/mm/homecache.c
+++ b/arch/tile/mm/homecache.c
@@ -408,6 +408,7 @@ void homecache_change_page_home(struct page *page, int order, int home)
__set_pte(ptep, pte_set_home(pteval, home));
}
}
+EXPORT_SYMBOL(homecache_change_page_home);
struct page *homecache_alloc_pages(gfp_t gfp_mask,
unsigned int order, int home)
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index ef29d6c5e10e..2749515a0547 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
@@ -935,6 +935,14 @@ int remove_memory(u64 start, u64 size)
{
return -EINVAL;
}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+ /* TODO */
+ return -EBUSY;
+}
+#endif
#endif
struct kmem_cache *pgd_cache;
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
index de0de0c0e8a1..b3b4972c2451 100644
--- a/arch/tile/mm/pgtable.c
+++ b/arch/tile/mm/pgtable.c
@@ -61,7 +61,7 @@ void show_mem(unsigned int filter)
global_page_state(NR_PAGETABLE),
global_page_state(NR_BOUNCE),
global_page_state(NR_FILE_PAGES),
- nr_swap_pages);
+ get_nr_swap_pages());
for_each_zone(zone) {
unsigned long flags, order, total = 0, largest_order = -1;
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common
index 648121b037d5..bceee6623b00 100644
--- a/arch/um/Kconfig.common
+++ b/arch/um/Kconfig.common
@@ -12,6 +12,7 @@ config UML
select GENERIC_CPU_DEVICES
select GENERIC_IO
select GENERIC_CLOCKEVENTS
+ select TTY # Needed for line.c
config MMU
bool
diff --git a/arch/um/Kconfig.net b/arch/um/Kconfig.net
index 3160b1a5adb7..820a56f00332 100644
--- a/arch/um/Kconfig.net
+++ b/arch/um/Kconfig.net
@@ -157,7 +157,7 @@ config UML_NET_MCAST
config UML_NET_PCAP
bool "pcap transport"
- depends on UML_NET && EXPERIMENTAL
+ depends on UML_NET
help
The pcap transport makes a pcap packet stream on the host look
like an ethernet device inside UML. This is useful for making
diff --git a/arch/um/Kconfig.um b/arch/um/Kconfig.um
index bf87f25eb2de..a7520c90f62d 100644
--- a/arch/um/Kconfig.um
+++ b/arch/um/Kconfig.um
@@ -45,8 +45,8 @@ config HOSTFS
say Y or M here; otherwise say N.
config HPPFS
- tristate "HoneyPot ProcFS (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PROC_FS
+ tristate "HoneyPot ProcFS"
+ depends on PROC_FS
help
hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
entries to be overridden, removed, or fabricated from the host.
@@ -96,7 +96,7 @@ config MAGIC_SYSRQ
unless you really know what this hack does.
config SMP
- bool "Symmetric multi-processing support (EXPERIMENTAL)"
+ bool "Symmetric multi-processing support"
default n
depends on BROKEN
help
@@ -126,7 +126,7 @@ config NR_CPUS
default "32"
config HIGHMEM
- bool "Highmem support (EXPERIMENTAL)"
+ bool "Highmem support"
depends on !64BIT && BROKEN
default n
help
diff --git a/arch/um/drivers/chan.h b/arch/um/drivers/chan.h
index 02b5a76e98d9..78f1b8999964 100644
--- a/arch/um/drivers/chan.h
+++ b/arch/um/drivers/chan.h
@@ -27,8 +27,7 @@ struct chan {
void *data;
};
-extern void chan_interrupt(struct line *line,
- struct tty_struct *tty, int irq);
+extern void chan_interrupt(struct line *line, int irq);
extern int parse_chan_pair(char *str, struct line *line, int device,
const struct chan_opts *opts, char **error_out);
extern int write_chan(struct chan *chan, const char *buf, int len,
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index e9a0abc6a32f..15c553c239a1 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -81,12 +81,6 @@ static const struct chan_ops not_configged_ops = {
};
#endif /* CONFIG_NOCONFIG_CHAN */
-static void tty_receive_char(struct tty_struct *tty, char ch)
-{
- if (tty)
- tty_insert_flip_char(tty, ch, TTY_NORMAL);
-}
-
static int open_one_chan(struct chan *chan)
{
int fd, err;
@@ -137,11 +131,9 @@ void chan_enable_winch(struct chan *chan, struct tty_struct *tty)
static void line_timer_cb(struct work_struct *work)
{
struct line *line = container_of(work, struct line, task.work);
- struct tty_struct *tty = tty_port_tty_get(&line->port);
if (!line->throttled)
- chan_interrupt(line, tty, line->driver->read_irq);
- tty_kref_put(tty);
+ chan_interrupt(line, line->driver->read_irq);
}
int enable_chan(struct line *line)
@@ -552,8 +544,9 @@ int parse_chan_pair(char *str, struct line *line, int device,
return 0;
}
-void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
+void chan_interrupt(struct line *line, int irq)
{
+ struct tty_port *port = &line->port;
struct chan *chan = line->chan_in;
int err;
char c;
@@ -562,21 +555,24 @@ void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
goto out;
do {
- if (tty && !tty_buffer_request_room(tty, 1)) {
+ if (!tty_buffer_request_room(port, 1)) {
schedule_delayed_work(&line->task, 1);
goto out;
}
err = chan->ops->read(chan->fd, &c, chan->data);
if (err > 0)
- tty_receive_char(tty, c);
+ tty_insert_flip_char(port, c, TTY_NORMAL);
} while (err > 0);
if (err == 0)
reactivate_fd(chan->fd, irq);
if (err == -EIO) {
if (chan->primary) {
- if (tty != NULL)
+ struct tty_struct *tty = tty_port_tty_get(&line->port);
+ if (tty != NULL) {
tty_hangup(tty);
+ tty_kref_put(tty);
+ }
if (line->chan_out != chan)
close_one_chan(line->chan_out, 1);
}
@@ -585,6 +581,5 @@ void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
return;
}
out:
- if (tty)
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(port);
}
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 9ffc28bd4b7a..f1b38571f94e 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -19,11 +19,10 @@ static irqreturn_t line_interrupt(int irq, void *data)
{
struct chan *chan = data;
struct line *line = chan->line;
- struct tty_struct *tty = tty_port_tty_get(&line->port);
if (line)
- chan_interrupt(line, tty, irq);
- tty_kref_put(tty);
+ chan_interrupt(line, irq);
+
return IRQ_HANDLED;
}
@@ -234,7 +233,7 @@ void line_unthrottle(struct tty_struct *tty)
struct line *line = tty->driver_data;
line->throttled = 0;
- chan_interrupt(line, tty, line->driver->read_irq);
+ chan_interrupt(line, line->driver->read_irq);
/*
* Maybe there is enough stuff pending that calling the interrupt
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index b1314ebf1f72..d8926c303629 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -274,8 +274,8 @@ static void uml_net_poll_controller(struct net_device *dev)
static void uml_net_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, DRIVER_NAME);
- strcpy(info->version, "42");
+ strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->version, "42", sizeof(info->version));
}
static const struct ethtool_ops uml_net_ethtool_ops = {
@@ -293,8 +293,9 @@ static void uml_net_user_timer_expire(unsigned long _conn)
#endif
}
-static int setup_etheraddr(char *str, unsigned char *addr, char *name)
+static void setup_etheraddr(struct net_device *dev, char *str)
{
+ unsigned char *addr = dev->dev_addr;
char *end;
int i;
@@ -334,13 +335,12 @@ static int setup_etheraddr(char *str, unsigned char *addr, char *name)
addr[0] | 0x02, addr[1], addr[2], addr[3], addr[4],
addr[5]);
}
- return 0;
+ return;
random:
printk(KERN_INFO
- "Choosing a random ethernet address for device %s\n", name);
- eth_random_addr(addr);
- return 1;
+ "Choosing a random ethernet address for device %s\n", dev->name);
+ eth_hw_addr_random(dev);
}
static DEFINE_SPINLOCK(devices_lock);
@@ -392,7 +392,6 @@ static void eth_configure(int n, void *init, char *mac,
struct net_device *dev;
struct uml_net_private *lp;
int err, size;
- int random_mac;
size = transport->private_size + sizeof(struct uml_net_private);
@@ -419,9 +418,9 @@ static void eth_configure(int n, void *init, char *mac,
*/
snprintf(dev->name, sizeof(dev->name), "eth%d", n);
- random_mac = setup_etheraddr(mac, device->mac, dev->name);
+ setup_etheraddr(dev, mac);
- printk(KERN_INFO "Netdevice %d (%pM) : ", n, device->mac);
+ printk(KERN_INFO "Netdevice %d (%pM) : ", n, dev->dev_addr);
lp = netdev_priv(dev);
/* This points to the transport private data. It's still clear, but we
@@ -468,17 +467,12 @@ static void eth_configure(int n, void *init, char *mac,
init_timer(&lp->tl);
spin_lock_init(&lp->lock);
lp->tl.function = uml_net_user_timer_expire;
- memcpy(lp->mac, device->mac, sizeof(lp->mac));
+ memcpy(lp->mac, dev->dev_addr, sizeof(lp->mac));
if ((transport->user->init != NULL) &&
((*transport->user->init)(&lp->user, dev) != 0))
goto out_unregister;
- /* don't use eth_mac_addr, it will not work here */
- memcpy(dev->dev_addr, device->mac, ETH_ALEN);
- if (random_mac)
- dev->addr_assign_type |= NET_ADDR_RANDOM;
-
dev->mtu = transport->user->mtu;
dev->netdev_ops = &uml_netdev_ops;
dev->ethtool_ops = &uml_net_ethtool_ops;
diff --git a/arch/um/include/shared/net_kern.h b/arch/um/include/shared/net_kern.h
index 5c367f22595b..012ac87d4900 100644
--- a/arch/um/include/shared/net_kern.h
+++ b/arch/um/include/shared/net_kern.h
@@ -18,7 +18,6 @@ struct uml_net {
struct net_device *dev;
struct platform_device pdev;
int index;
- unsigned char mac[ETH_ALEN];
};
struct uml_net_private {
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index 48ccf718e290..3e831b3fd07b 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -122,13 +122,3 @@ int do_signal(void)
{
return kern_do_signal(&current->thread.regs);
}
-
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
diff --git a/arch/unicore32/kernel/entry.S b/arch/unicore32/kernel/entry.S
index 581630d91444..bcdedd80890e 100644
--- a/arch/unicore32/kernel/entry.S
+++ b/arch/unicore32/kernel/entry.S
@@ -674,11 +674,6 @@ ENTRY(sys_rt_sigreturn)
b __sys_rt_sigreturn
ENDPROC(sys_rt_sigreturn)
-ENTRY(sys_sigaltstack)
- ldw r2, [sp+], #S_OFF + S_SP
- b do_sigaltstack
-ENDPROC(sys_sigaltstack)
-
__INIT
/*
diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c
index 62bad9fed03e..872d7e22d847 100644
--- a/arch/unicore32/kernel/process.c
+++ b/arch/unicore32/kernel/process.c
@@ -45,11 +45,6 @@ static const char * const processor_modes[] = {
"UK18", "UK19", "UK1A", "EXTN", "UK1C", "UK1D", "UK1E", "SUSR"
};
-/*
- * The idle thread, has rather strange semantics for calling pm_idle,
- * but this is what x86 does and we need to do the same, so that
- * things like cpuidle get called in the same way.
- */
void cpu_idle(void)
{
/* endless idle loop with no priority at all */
diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c
index b8b2ffd774d6..6905f0ebdc77 100644
--- a/arch/unicore32/kernel/signal.c
+++ b/arch/unicore32/kernel/signal.c
@@ -123,8 +123,7 @@ asmlinkage int __sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigframe(regs, &frame->sig))
goto badframe;
- if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->UCreg_sp)
- == -EFAULT)
+ if (restore_altstack(&frame->sig.uc.uc_stack))
goto badframe;
return regs->UCreg_00;
@@ -265,7 +264,6 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
{
struct rt_sigframe __user *frame =
get_sigframe(ka, regs, sizeof(*frame));
- stack_t stack;
int err = 0;
if (!frame)
@@ -275,13 +273,7 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(0, &frame->sig.uc.uc_flags);
err |= __put_user(NULL, &frame->sig.uc.uc_link);
-
- memset(&stack, 0, sizeof(stack));
- stack.ss_sp = (void __user *)current->sas_ss_sp;
- stack.ss_flags = sas_ss_flags(regs->UCreg_sp);
- stack.ss_size = current->sas_ss_size;
- err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack));
-
+ err |= __save_altstack(&frame->sig.uc.uc_stack, regs->UCreg_sp);
err |= setup_sigframe(&frame->sig, regs, set);
if (err == 0)
err |= setup_return(regs, ka, frame->sig.retcode, frame, usig);
diff --git a/arch/unicore32/kernel/traps.c b/arch/unicore32/kernel/traps.c
index 2054f0d4db13..0870b68d2ad9 100644
--- a/arch/unicore32/kernel/traps.c
+++ b/arch/unicore32/kernel/traps.c
@@ -231,7 +231,7 @@ void die(const char *str, struct pt_regs *regs, int err)
ret = __die(str, err, thread, regs);
bust_spinlocks(0);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
spin_unlock_irq(&die_lock);
oops_exit();
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 225543bf45a5..6a9383370311 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1,7 +1,7 @@
# Select 32 or 64 bit
config 64BIT
bool "64-bit kernel" if ARCH = "x86"
- default ARCH = "x86_64"
+ default ARCH != "i386"
---help---
Say yes to build a 64-bit kernel - formerly known as x86_64
Say no to build a 32-bit kernel - formerly known as i386
@@ -28,7 +28,6 @@ config X86
select HAVE_OPROFILE
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
- select HAVE_IRQ_WORK
select HAVE_IOREMAP_PROT
select HAVE_KPROBES
select HAVE_MEMBLOCK
@@ -40,10 +39,12 @@ config X86
select HAVE_DMA_CONTIGUOUS if !SWIOTLB
select HAVE_KRETPROBES
select HAVE_OPTPROBES
+ select HAVE_KPROBES_ON_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FENTRY if X86_64
select HAVE_C_RECORDMCOUNT
select HAVE_DYNAMIC_FTRACE
+ select HAVE_DYNAMIC_FTRACE_WITH_REGS
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_GRAPH_FP_TEST
@@ -106,6 +107,7 @@ config X86
select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC)
select GENERIC_TIME_VSYSCALL if X86_64
select KTIME_SCALAR if X86_32
+ select ALWAYS_USE_PERSISTENT_CLOCK
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select HAVE_CONTEXT_TRACKING if X86_64
@@ -113,7 +115,10 @@ config X86
select MODULES_USE_ELF_REL if X86_32
select MODULES_USE_ELF_RELA if X86_64
select CLONE_BACKWARDS if X86_32
- select GENERIC_SIGALTSTACK
+ select ARCH_USE_BUILTIN_BSWAP
+ select OLD_SIGSUSPEND3 if X86_32 || IA32_EMULATION
+ select OLD_SIGACTION if X86_32
+ select COMPAT_OLD_SIGACTION if IA32_EMULATION
config INSTRUCTION_DECODER
def_bool y
@@ -222,7 +227,7 @@ config ARCH_SUPPORTS_DEBUG_PAGEALLOC
config HAVE_INTEL_TXT
def_bool y
- depends on EXPERIMENTAL && INTEL_IOMMU && ACPI
+ depends on INTEL_IOMMU && ACPI
config X86_32_SMP
def_bool y
@@ -320,6 +325,10 @@ config X86_BIGSMP
---help---
This option is needed for the systems that have more than 8 CPUs
+config GOLDFISH
+ def_bool y
+ depends on X86_GOLDFISH
+
if X86_32
config X86_EXTENDED_PLATFORM
bool "Support for extended (non-PC) x86 platforms"
@@ -402,6 +411,14 @@ 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_GOLDFISH
+ bool "Goldfish (Virtual Platform)"
+ depends on X86_32
+ ---help---
+ Enable support for the Goldfish virtual platform used primarily
+ for Android development. Unless you are building for the Android
+ Goldfish emulator say N here.
+
config X86_INTEL_CE
bool "CE4100 TV platform"
depends on PCI
@@ -454,6 +471,16 @@ config X86_MDFLD
endif
+config X86_INTEL_LPSS
+ bool "Intel Low Power Subsystem Support"
+ depends on ACPI
+ select COMMON_CLK
+ ---help---
+ Select to build support for Intel Low Power Subsystem such as
+ found on Intel Lynxpoint PCH. Selecting this option enables
+ things like clock tree (common clock framework) which are needed
+ by the LPSS peripheral drivers.
+
config X86_RDC321X
bool "RDC R-321x SoC"
depends on X86_32
@@ -617,7 +644,7 @@ config PARAVIRT
config PARAVIRT_SPINLOCKS
bool "Paravirtualization layer for spinlocks"
- depends on PARAVIRT && SMP && EXPERIMENTAL
+ depends on PARAVIRT && SMP
---help---
Paravirtualized spinlocks allow a pvops backend to replace the
spinlock implementation with something virtualization-friendly
@@ -729,7 +756,7 @@ config GART_IOMMU
config CALGARY_IOMMU
bool "IBM Calgary IOMMU support"
select SWIOTLB
- depends on X86_64 && PCI && EXPERIMENTAL
+ depends on X86_64 && PCI
---help---
Support for hardware IOMMUs in IBM's xSeries x366 and x460
systems. Needed to run systems with more than 3GB of memory
@@ -771,7 +798,7 @@ config IOMMU_HELPER
config MAXSMP
bool "Enable Maximum number of SMP Processors and NUMA Nodes"
- depends on X86_64 && SMP && DEBUG_KERNEL && EXPERIMENTAL
+ depends on X86_64 && SMP && DEBUG_KERNEL
select CPUMASK_OFFSTACK
---help---
Enable maximum number of CPUS and NUMA Nodes for this architecture.
@@ -1029,6 +1056,24 @@ config MICROCODE_OLD_INTERFACE
def_bool y
depends on MICROCODE
+config MICROCODE_INTEL_LIB
+ def_bool y
+ depends on MICROCODE_INTEL
+
+config MICROCODE_INTEL_EARLY
+ bool "Early load microcode"
+ depends on MICROCODE_INTEL && BLK_DEV_INITRD
+ default y
+ help
+ This option provides functionality to read additional microcode data
+ at the beginning of initrd image. The data tells kernel to load
+ microcode to CPU's as early as possible. No functional change if no
+ microcode data is glued to the initrd, therefore it's safe to say Y.
+
+config MICROCODE_EARLY
+ def_bool y
+ depends on MICROCODE_INTEL_EARLY
+
config X86_MSR
tristate "/dev/cpu/*/msr - Model-specific register support"
---help---
@@ -1107,7 +1152,6 @@ config HIGHMEM64G
endchoice
choice
- depends on EXPERIMENTAL
prompt "Memory split" if EXPERT
default VMSPLIT_3G
depends on X86_32
@@ -1184,7 +1228,7 @@ config DIRECT_GBPAGES
config NUMA
bool "Numa Memory Allocation and Scheduler Support"
depends on SMP
- depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || X86_BIGSMP || X86_SUMMIT && ACPI) && EXPERIMENTAL)
+ depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || X86_BIGSMP || X86_SUMMIT && ACPI))
default y if (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP)
---help---
Enable NUMA (Non Uniform Memory Access) support.
@@ -1253,10 +1297,6 @@ config NODES_SHIFT
Specify the maximum number of NUMA Nodes available on the target
system. Increases memory reserved to accommodate various tables.
-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
@@ -1279,7 +1319,7 @@ config ARCH_DISCONTIGMEM_DEFAULT
config ARCH_SPARSEMEM_ENABLE
def_bool y
- depends on X86_64 || NUMA || (EXPERIMENTAL && X86_32) || X86_32_NON_STANDARD
+ depends on X86_64 || NUMA || X86_32 || X86_32_NON_STANDARD
select SPARSEMEM_STATIC if X86_32
select SPARSEMEM_VMEMMAP_ENABLE if X86_64
@@ -1593,8 +1633,7 @@ config CRASH_DUMP
For more details see Documentation/kdump/kdump.txt
config KEXEC_JUMP
- bool "kexec jump (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "kexec jump"
depends on KEXEC && HIBERNATION
---help---
Jump between original kernel and kexeced kernel and invoke
@@ -1699,7 +1738,7 @@ config HOTPLUG_CPU
config BOOTPARAM_HOTPLUG_CPU0
bool "Set default setting of cpu0_hotpluggable"
default n
- depends on HOTPLUG_CPU && EXPERIMENTAL
+ depends on HOTPLUG_CPU
---help---
Set whether default state of cpu0_hotpluggable is on or off.
@@ -1728,7 +1767,7 @@ config BOOTPARAM_HOTPLUG_CPU0
config DEBUG_HOTPLUG_CPU0
def_bool n
prompt "Debug CPU0 hotplug"
- depends on HOTPLUG_CPU && EXPERIMENTAL
+ depends on HOTPLUG_CPU
---help---
Enabling this option offlines CPU0 (if CPU0 can be offlined) as
soon as possible and boots up userspace with CPU0 offlined. User
@@ -1912,6 +1951,7 @@ config APM_DO_ENABLE
this feature.
config APM_CPU_IDLE
+ depends on CPU_IDLE
bool "Make CPU Idle calls when idle"
---help---
Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.
@@ -2037,7 +2077,7 @@ config PCI_MMCONFIG
config PCI_CNB20LE_QUIRK
bool "Read CNB20LE Host Bridge Windows" if EXPERT
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
Read the PCI windows out of the CNB20LE host bridge. This allows
PCI hotplug to work on systems with the CNB20LE chipset which do
@@ -2188,6 +2228,15 @@ config GEOS
---help---
This option enables system support for the Traverse Technologies GEOS.
+config TS5500
+ bool "Technologic Systems TS-5500 platform support"
+ depends on MELAN
+ select CHECK_SIGNATURE
+ select NEW_LEDS
+ select LEDS_CLASS
+ ---help---
+ This option enables system support for the Technologic Systems TS-5500.
+
endif # X86_32
config AMD_NB
@@ -2232,8 +2281,8 @@ config IA32_AOUT
Support old a.out binaries in the 32bit emulation.
config X86_X32
- bool "x32 ABI for 64-bit mode (EXPERIMENTAL)"
- depends on X86_64 && IA32_EMULATION && EXPERIMENTAL
+ bool "x32 ABI for 64-bit mode"
+ depends on X86_64 && IA32_EMULATION
---help---
Include code to run binaries for the x32 native 32-bit ABI
for 64-bit processors. An x32 process gets access to the
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index e71fc4279aab..5c477260294f 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -2,7 +2,11 @@
# select defconfig based on actual architecture
ifeq ($(ARCH),x86)
+ ifeq ($(shell uname -m),x86_64)
+ KBUILD_DEFCONFIG := x86_64_defconfig
+ else
KBUILD_DEFCONFIG := i386_defconfig
+ endif
else
KBUILD_DEFCONFIG := $(ARCH)_defconfig
endif
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index 18997e5a1053..5b7531966b84 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -285,16 +285,26 @@ struct biosregs {
void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg);
/* cmdline.c */
-int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int bufsize);
-int __cmdline_find_option_bool(u32 cmdline_ptr, const char *option);
+int __cmdline_find_option(unsigned long cmdline_ptr, const char *option, char *buffer, int bufsize);
+int __cmdline_find_option_bool(unsigned long cmdline_ptr, const char *option);
static inline int cmdline_find_option(const char *option, char *buffer, int bufsize)
{
- return __cmdline_find_option(boot_params.hdr.cmd_line_ptr, option, buffer, bufsize);
+ unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr;
+
+ if (cmd_line_ptr >= 0x100000)
+ return -1; /* inaccessible */
+
+ return __cmdline_find_option(cmd_line_ptr, option, buffer, bufsize);
}
static inline int cmdline_find_option_bool(const char *option)
{
- return __cmdline_find_option_bool(boot_params.hdr.cmd_line_ptr, option);
+ unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr;
+
+ if (cmd_line_ptr >= 0x100000)
+ return -1; /* inaccessible */
+
+ return __cmdline_find_option_bool(cmd_line_ptr, option);
}
diff --git a/arch/x86/boot/cmdline.c b/arch/x86/boot/cmdline.c
index 6b3b6f708c04..625d21b0cd3f 100644
--- a/arch/x86/boot/cmdline.c
+++ b/arch/x86/boot/cmdline.c
@@ -27,7 +27,7 @@ static inline int myisspace(u8 c)
* Returns the length of the argument (regardless of if it was
* truncated to fit in the buffer), or -1 on not found.
*/
-int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int bufsize)
+int __cmdline_find_option(unsigned long cmdline_ptr, const char *option, char *buffer, int bufsize)
{
addr_t cptr;
char c;
@@ -41,8 +41,8 @@ int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int
st_bufcpy /* Copying this to buffer */
} state = st_wordstart;
- if (!cmdline_ptr || cmdline_ptr >= 0x100000)
- return -1; /* No command line, or inaccessible */
+ if (!cmdline_ptr)
+ return -1; /* No command line */
cptr = cmdline_ptr & 0xf;
set_fs(cmdline_ptr >> 4);
@@ -99,7 +99,7 @@ int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int
* Returns the position of that option (starts counting with 1)
* or 0 on not found
*/
-int __cmdline_find_option_bool(u32 cmdline_ptr, const char *option)
+int __cmdline_find_option_bool(unsigned long cmdline_ptr, const char *option)
{
addr_t cptr;
char c;
@@ -111,8 +111,8 @@ int __cmdline_find_option_bool(u32 cmdline_ptr, const char *option)
st_wordskip, /* Miscompare, skip */
} state = st_wordstart;
- if (!cmdline_ptr || cmdline_ptr >= 0x100000)
- return -1; /* No command line, or inaccessible */
+ if (!cmdline_ptr)
+ return -1; /* No command line */
cptr = cmdline_ptr & 0xf;
set_fs(cmdline_ptr >> 4);
diff --git a/arch/x86/boot/compressed/cmdline.c b/arch/x86/boot/compressed/cmdline.c
index 10f6b1178c68..bffd73b45b1f 100644
--- a/arch/x86/boot/compressed/cmdline.c
+++ b/arch/x86/boot/compressed/cmdline.c
@@ -13,13 +13,21 @@ static inline char rdfs8(addr_t addr)
return *((char *)(fs + addr));
}
#include "../cmdline.c"
+static unsigned long get_cmd_line_ptr(void)
+{
+ unsigned long cmd_line_ptr = real_mode->hdr.cmd_line_ptr;
+
+ cmd_line_ptr |= (u64)real_mode->ext_cmd_line_ptr << 32;
+
+ return cmd_line_ptr;
+}
int cmdline_find_option(const char *option, char *buffer, int bufsize)
{
- return __cmdline_find_option(real_mode->hdr.cmd_line_ptr, option, buffer, bufsize);
+ return __cmdline_find_option(get_cmd_line_ptr(), option, buffer, bufsize);
}
int cmdline_find_option_bool(const char *option)
{
- return __cmdline_find_option_bool(real_mode->hdr.cmd_line_ptr, option);
+ return __cmdline_find_option_bool(get_cmd_line_ptr(), option);
}
#endif
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index f5d1aaa0dec8..c1d383d1fb7e 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -37,6 +37,12 @@
__HEAD
.code32
ENTRY(startup_32)
+ /*
+ * 32bit entry is 0 and it is ABI so immutable!
+ * If we come here directly from a bootloader,
+ * kernel(text+data+bss+brk) ramdisk, zero_page, command line
+ * all need to be under the 4G limit.
+ */
cld
/*
* Test KEEP_SEGMENTS flag to see if the bootloader is asking
@@ -154,6 +160,12 @@ ENTRY(startup_32)
btsl $_EFER_LME, %eax
wrmsr
+ /* After gdt is loaded */
+ xorl %eax, %eax
+ lldt %ax
+ movl $0x20, %eax
+ ltr %ax
+
/*
* Setup for the jump to 64bit mode
*
@@ -176,28 +188,18 @@ ENTRY(startup_32)
lret
ENDPROC(startup_32)
-no_longmode:
- /* This isn't an x86-64 CPU so hang */
-1:
- hlt
- jmp 1b
-
-#include "../../kernel/verify_cpu.S"
-
- /*
- * Be careful here startup_64 needs to be at a predictable
- * address so I can export it in an ELF header. Bootloaders
- * should look at the ELF header to find this address, as
- * it may change in the future.
- */
.code64
.org 0x200
ENTRY(startup_64)
/*
+ * 64bit entry is 0x200 and it is ABI so immutable!
* We come here either from startup_32 or directly from a
- * 64bit bootloader. If we come here from a bootloader we depend on
- * an identity mapped page table being provied that maps our
- * entire text+data+bss and hopefully all of memory.
+ * 64bit bootloader.
+ * If we come here from a bootloader, kernel(text+data+bss+brk),
+ * ramdisk, zero_page, command line could be above 4G.
+ * We depend on an identity mapped page table being provided
+ * that maps our entire kernel(text+data+bss+brk), zero page
+ * and command line.
*/
#ifdef CONFIG_EFI_STUB
/*
@@ -247,9 +249,6 @@ preferred_addr:
movl %eax, %ss
movl %eax, %fs
movl %eax, %gs
- lldt %ax
- movl $0x20, %eax
- ltr %ax
/*
* Compute the decompressed kernel start address. It is where
@@ -349,6 +348,15 @@ relocated:
*/
jmp *%rbp
+ .code32
+no_longmode:
+ /* This isn't an x86-64 CPU so hang */
+1:
+ hlt
+ jmp 1b
+
+#include "../../kernel/verify_cpu.S"
+
.data
gdt:
.word gdt_end - gdt
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 88f7ff6da404..7cb56c6ca351 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -325,6 +325,8 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
{
real_mode = rmode;
+ sanitize_boot_params(real_mode);
+
if (real_mode->screen_info.orig_video_mode == 7) {
vidmem = (char *) 0xb0000;
vidport = 0x3b4;
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index 0e6dc0ee0eea..674019d8e235 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -18,6 +18,7 @@
#include <asm/page.h>
#include <asm/boot.h>
#include <asm/bootparam.h>
+#include <asm/bootparam_utils.h>
#define BOOT_BOOT_H
#include "../ctype.h"
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 944ce595f767..9ec06a1f6d61 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -374,6 +374,14 @@ xloadflags:
#else
# define XLF0 0
#endif
+
+#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64)
+ /* kernel/boot_param/ramdisk could be loaded above 4g */
+# define XLF1 XLF_CAN_BE_LOADED_ABOVE_4G
+#else
+# define XLF1 0
+#endif
+
#ifdef CONFIG_EFI_STUB
# ifdef CONFIG_X86_64
# define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
@@ -383,7 +391,7 @@ xloadflags:
#else
# define XLF23 0
#endif
- .word XLF0 | XLF23
+ .word XLF0 | XLF1 | XLF23
cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line,
#added with boot protocol
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index 5598547281a7..94447086e551 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -1,3 +1,4 @@
+# CONFIG_64BIT is not set
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index e0ca7c9ac383..63947a8f9f0f 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o
obj-$(CONFIG_CRYPTO_SHA1_SSSE3) += sha1-ssse3.o
+obj-$(CONFIG_CRYPTO_CRC32_PCLMUL) += crc32-pclmul.o
aes-i586-y := aes-i586-asm_32.o aes_glue.o
twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
@@ -52,3 +53,4 @@ ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
sha1-ssse3-y := sha1_ssse3_asm.o sha1_ssse3_glue.o
crc32c-intel-y := crc32c-intel_glue.o
crc32c-intel-$(CONFIG_CRYPTO_CRC32C_X86_64) += crc32c-pcl-intel-asm_64.o
+crc32-pclmul-y := crc32-pclmul_asm.o crc32-pclmul_glue.o
diff --git a/arch/x86/crypto/aes-i586-asm_32.S b/arch/x86/crypto/aes-i586-asm_32.S
index b949ec2f9af4..2849dbc59e11 100644
--- a/arch/x86/crypto/aes-i586-asm_32.S
+++ b/arch/x86/crypto/aes-i586-asm_32.S
@@ -36,6 +36,7 @@
.file "aes-i586-asm.S"
.text
+#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#define tlen 1024 // length of each of 4 'xor' arrays (256 32-bit words)
@@ -219,14 +220,10 @@
// AES (Rijndael) Encryption Subroutine
/* void aes_enc_blk(struct crypto_aes_ctx *ctx, u8 *out_blk, const u8 *in_blk) */
-.global aes_enc_blk
-
.extern crypto_ft_tab
.extern crypto_fl_tab
-.align 4
-
-aes_enc_blk:
+ENTRY(aes_enc_blk)
push %ebp
mov ctx(%esp),%ebp
@@ -290,18 +287,15 @@ aes_enc_blk:
mov %r0,(%ebp)
pop %ebp
ret
+ENDPROC(aes_enc_blk)
// AES (Rijndael) Decryption Subroutine
/* void aes_dec_blk(struct crypto_aes_ctx *ctx, u8 *out_blk, const u8 *in_blk) */
-.global aes_dec_blk
-
.extern crypto_it_tab
.extern crypto_il_tab
-.align 4
-
-aes_dec_blk:
+ENTRY(aes_dec_blk)
push %ebp
mov ctx(%esp),%ebp
@@ -365,3 +359,4 @@ aes_dec_blk:
mov %r0,(%ebp)
pop %ebp
ret
+ENDPROC(aes_dec_blk)
diff --git a/arch/x86/crypto/aes-x86_64-asm_64.S b/arch/x86/crypto/aes-x86_64-asm_64.S
index 5b577d5a059b..910565547163 100644
--- a/arch/x86/crypto/aes-x86_64-asm_64.S
+++ b/arch/x86/crypto/aes-x86_64-asm_64.S
@@ -15,6 +15,7 @@
.text
+#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#define R1 %rax
@@ -49,10 +50,8 @@
#define R11 %r11
#define prologue(FUNC,KEY,B128,B192,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11) \
- .global FUNC; \
- .type FUNC,@function; \
- .align 8; \
-FUNC: movq r1,r2; \
+ ENTRY(FUNC); \
+ movq r1,r2; \
movq r3,r4; \
leaq KEY+48(r8),r9; \
movq r10,r11; \
@@ -71,14 +70,15 @@ FUNC: movq r1,r2; \
je B192; \
leaq 32(r9),r9;
-#define epilogue(r1,r2,r3,r4,r5,r6,r7,r8,r9) \
+#define epilogue(FUNC,r1,r2,r3,r4,r5,r6,r7,r8,r9) \
movq r1,r2; \
movq r3,r4; \
movl r5 ## E,(r9); \
movl r6 ## E,4(r9); \
movl r7 ## E,8(r9); \
movl r8 ## E,12(r9); \
- ret;
+ ret; \
+ ENDPROC(FUNC);
#define round(TAB,OFFSET,r1,r2,r3,r4,r5,r6,r7,r8,ra,rb,rc,rd) \
movzbl r2 ## H,r5 ## E; \
@@ -133,7 +133,7 @@ FUNC: movq r1,r2; \
#define entry(FUNC,KEY,B128,B192) \
prologue(FUNC,KEY,B128,B192,R2,R8,R7,R9,R1,R3,R4,R6,R10,R5,R11)
-#define return epilogue(R8,R2,R9,R7,R5,R6,R3,R4,R11)
+#define return(FUNC) epilogue(FUNC,R8,R2,R9,R7,R5,R6,R3,R4,R11)
#define encrypt_round(TAB,OFFSET) \
round(TAB,OFFSET,R1,R2,R3,R4,R5,R6,R7,R10,R5,R6,R3,R4) \
@@ -151,12 +151,12 @@ FUNC: movq r1,r2; \
/* void aes_enc_blk(stuct crypto_tfm *tfm, u8 *out, const u8 *in) */
- entry(aes_enc_blk,0,enc128,enc192)
+ entry(aes_enc_blk,0,.Le128,.Le192)
encrypt_round(crypto_ft_tab,-96)
encrypt_round(crypto_ft_tab,-80)
-enc192: encrypt_round(crypto_ft_tab,-64)
+.Le192: encrypt_round(crypto_ft_tab,-64)
encrypt_round(crypto_ft_tab,-48)
-enc128: encrypt_round(crypto_ft_tab,-32)
+.Le128: encrypt_round(crypto_ft_tab,-32)
encrypt_round(crypto_ft_tab,-16)
encrypt_round(crypto_ft_tab, 0)
encrypt_round(crypto_ft_tab, 16)
@@ -166,16 +166,16 @@ enc128: encrypt_round(crypto_ft_tab,-32)
encrypt_round(crypto_ft_tab, 80)
encrypt_round(crypto_ft_tab, 96)
encrypt_final(crypto_fl_tab,112)
- return
+ return(aes_enc_blk)
/* void aes_dec_blk(struct crypto_tfm *tfm, u8 *out, const u8 *in) */
- entry(aes_dec_blk,240,dec128,dec192)
+ entry(aes_dec_blk,240,.Ld128,.Ld192)
decrypt_round(crypto_it_tab,-96)
decrypt_round(crypto_it_tab,-80)
-dec192: decrypt_round(crypto_it_tab,-64)
+.Ld192: decrypt_round(crypto_it_tab,-64)
decrypt_round(crypto_it_tab,-48)
-dec128: decrypt_round(crypto_it_tab,-32)
+.Ld128: decrypt_round(crypto_it_tab,-32)
decrypt_round(crypto_it_tab,-16)
decrypt_round(crypto_it_tab, 0)
decrypt_round(crypto_it_tab, 16)
@@ -185,4 +185,4 @@ dec128: decrypt_round(crypto_it_tab,-32)
decrypt_round(crypto_it_tab, 80)
decrypt_round(crypto_it_tab, 96)
decrypt_final(crypto_il_tab,112)
- return
+ return(aes_dec_blk)
diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S
index 3470624d7835..04b797767b9e 100644
--- a/arch/x86/crypto/aesni-intel_asm.S
+++ b/arch/x86/crypto/aesni-intel_asm.S
@@ -1262,7 +1262,6 @@ TMP7 XMM1 XMM2 XMM3 XMM4 XMMDst
* poly = x^128 + x^127 + x^126 + x^121 + 1
*
*****************************************************************************/
-
ENTRY(aesni_gcm_dec)
push %r12
push %r13
@@ -1437,6 +1436,7 @@ _return_T_done_decrypt:
pop %r13
pop %r12
ret
+ENDPROC(aesni_gcm_dec)
/*****************************************************************************
@@ -1700,10 +1700,12 @@ _return_T_done_encrypt:
pop %r13
pop %r12
ret
+ENDPROC(aesni_gcm_enc)
#endif
+.align 4
_key_expansion_128:
_key_expansion_256a:
pshufd $0b11111111, %xmm1, %xmm1
@@ -1715,6 +1717,8 @@ _key_expansion_256a:
movaps %xmm0, (TKEYP)
add $0x10, TKEYP
ret
+ENDPROC(_key_expansion_128)
+ENDPROC(_key_expansion_256a)
.align 4
_key_expansion_192a:
@@ -1739,6 +1743,7 @@ _key_expansion_192a:
movaps %xmm1, 0x10(TKEYP)
add $0x20, TKEYP
ret
+ENDPROC(_key_expansion_192a)
.align 4
_key_expansion_192b:
@@ -1758,6 +1763,7 @@ _key_expansion_192b:
movaps %xmm0, (TKEYP)
add $0x10, TKEYP
ret
+ENDPROC(_key_expansion_192b)
.align 4
_key_expansion_256b:
@@ -1770,6 +1776,7 @@ _key_expansion_256b:
movaps %xmm2, (TKEYP)
add $0x10, TKEYP
ret
+ENDPROC(_key_expansion_256b)
/*
* int aesni_set_key(struct crypto_aes_ctx *ctx, const u8 *in_key,
@@ -1882,6 +1889,7 @@ ENTRY(aesni_set_key)
popl KEYP
#endif
ret
+ENDPROC(aesni_set_key)
/*
* void aesni_enc(struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src)
@@ -1903,6 +1911,7 @@ ENTRY(aesni_enc)
popl KEYP
#endif
ret
+ENDPROC(aesni_enc)
/*
* _aesni_enc1: internal ABI
@@ -1960,6 +1969,7 @@ _aesni_enc1:
movaps 0x70(TKEYP), KEY
AESENCLAST KEY STATE
ret
+ENDPROC(_aesni_enc1)
/*
* _aesni_enc4: internal ABI
@@ -2068,6 +2078,7 @@ _aesni_enc4:
AESENCLAST KEY STATE3
AESENCLAST KEY STATE4
ret
+ENDPROC(_aesni_enc4)
/*
* void aesni_dec (struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src)
@@ -2090,6 +2101,7 @@ ENTRY(aesni_dec)
popl KEYP
#endif
ret
+ENDPROC(aesni_dec)
/*
* _aesni_dec1: internal ABI
@@ -2147,6 +2159,7 @@ _aesni_dec1:
movaps 0x70(TKEYP), KEY
AESDECLAST KEY STATE
ret
+ENDPROC(_aesni_dec1)
/*
* _aesni_dec4: internal ABI
@@ -2255,6 +2268,7 @@ _aesni_dec4:
AESDECLAST KEY STATE3
AESDECLAST KEY STATE4
ret
+ENDPROC(_aesni_dec4)
/*
* void aesni_ecb_enc(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
@@ -2312,6 +2326,7 @@ ENTRY(aesni_ecb_enc)
popl LEN
#endif
ret
+ENDPROC(aesni_ecb_enc)
/*
* void aesni_ecb_dec(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
@@ -2370,6 +2385,7 @@ ENTRY(aesni_ecb_dec)
popl LEN
#endif
ret
+ENDPROC(aesni_ecb_dec)
/*
* void aesni_cbc_enc(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
@@ -2411,6 +2427,7 @@ ENTRY(aesni_cbc_enc)
popl IVP
#endif
ret
+ENDPROC(aesni_cbc_enc)
/*
* void aesni_cbc_dec(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
@@ -2501,6 +2518,7 @@ ENTRY(aesni_cbc_dec)
popl IVP
#endif
ret
+ENDPROC(aesni_cbc_dec)
#ifdef __x86_64__
.align 16
@@ -2527,6 +2545,7 @@ _aesni_inc_init:
MOVQ_R64_XMM TCTR_LOW INC
MOVQ_R64_XMM CTR TCTR_LOW
ret
+ENDPROC(_aesni_inc_init)
/*
* _aesni_inc: internal ABI
@@ -2555,6 +2574,7 @@ _aesni_inc:
movaps CTR, IV
PSHUFB_XMM BSWAP_MASK IV
ret
+ENDPROC(_aesni_inc)
/*
* void aesni_ctr_enc(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
@@ -2615,4 +2635,5 @@ ENTRY(aesni_ctr_enc)
movups IV, (IVP)
.Lctr_enc_just_ret:
ret
+ENDPROC(aesni_ctr_enc)
#endif
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index 1b9c22bea8a7..a0795da22c02 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -40,10 +40,6 @@
#include <linux/workqueue.h>
#include <linux/spinlock.h>
-#if defined(CONFIG_CRYPTO_CTR) || defined(CONFIG_CRYPTO_CTR_MODULE)
-#define HAS_CTR
-#endif
-
#if defined(CONFIG_CRYPTO_PCBC) || defined(CONFIG_CRYPTO_PCBC_MODULE)
#define HAS_PCBC
#endif
@@ -395,12 +391,6 @@ static int ablk_ctr_init(struct crypto_tfm *tfm)
return ablk_init_common(tfm, "__driver-ctr-aes-aesni");
}
-#ifdef HAS_CTR
-static int ablk_rfc3686_ctr_init(struct crypto_tfm *tfm)
-{
- return ablk_init_common(tfm, "rfc3686(__driver-ctr-aes-aesni)");
-}
-#endif
#endif
#ifdef HAS_PCBC
@@ -1158,33 +1148,6 @@ static struct crypto_alg aesni_algs[] = { {
.maxauthsize = 16,
},
},
-#ifdef HAS_CTR
-}, {
- .cra_name = "rfc3686(ctr(aes))",
- .cra_driver_name = "rfc3686-ctr-aes-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_rfc3686_ctr_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE +
- CTR_RFC3686_NONCE_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE +
- CTR_RFC3686_NONCE_SIZE,
- .ivsize = CTR_RFC3686_IV_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- .geniv = "seqiv",
- },
- },
-#endif
#endif
#ifdef HAS_PCBC
}, {
diff --git a/arch/x86/crypto/blowfish-x86_64-asm_64.S b/arch/x86/crypto/blowfish-x86_64-asm_64.S
index 391d245dc086..246c67006ed0 100644
--- a/arch/x86/crypto/blowfish-x86_64-asm_64.S
+++ b/arch/x86/crypto/blowfish-x86_64-asm_64.S
@@ -20,6 +20,8 @@
*
*/
+#include <linux/linkage.h>
+
.file "blowfish-x86_64-asm.S"
.text
@@ -116,11 +118,7 @@
bswapq RX0; \
xorq RX0, (RIO);
-.align 8
-.global __blowfish_enc_blk
-.type __blowfish_enc_blk,@function;
-
-__blowfish_enc_blk:
+ENTRY(__blowfish_enc_blk)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -148,19 +146,16 @@ __blowfish_enc_blk:
movq %r10, RIO;
test %cl, %cl;
- jnz __enc_xor;
+ jnz .L__enc_xor;
write_block();
ret;
-__enc_xor:
+.L__enc_xor:
xor_block();
ret;
+ENDPROC(__blowfish_enc_blk)
-.align 8
-.global blowfish_dec_blk
-.type blowfish_dec_blk,@function;
-
-blowfish_dec_blk:
+ENTRY(blowfish_dec_blk)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -189,6 +184,7 @@ blowfish_dec_blk:
movq %r11, %rbp;
ret;
+ENDPROC(blowfish_dec_blk)
/**********************************************************************
4-way blowfish, four blocks parallel
@@ -300,11 +296,7 @@ blowfish_dec_blk:
bswapq RX3; \
xorq RX3, 24(RIO);
-.align 8
-.global __blowfish_enc_blk_4way
-.type __blowfish_enc_blk_4way,@function;
-
-__blowfish_enc_blk_4way:
+ENTRY(__blowfish_enc_blk_4way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -336,7 +328,7 @@ __blowfish_enc_blk_4way:
movq %r11, RIO;
test %bpl, %bpl;
- jnz __enc_xor4;
+ jnz .L__enc_xor4;
write_block4();
@@ -344,18 +336,15 @@ __blowfish_enc_blk_4way:
popq %rbp;
ret;
-__enc_xor4:
+.L__enc_xor4:
xor_block4();
popq %rbx;
popq %rbp;
ret;
+ENDPROC(__blowfish_enc_blk_4way)
-.align 8
-.global blowfish_dec_blk_4way
-.type blowfish_dec_blk_4way,@function;
-
-blowfish_dec_blk_4way:
+ENTRY(blowfish_dec_blk_4way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -387,4 +376,4 @@ blowfish_dec_blk_4way:
popq %rbp;
ret;
-
+ENDPROC(blowfish_dec_blk_4way)
diff --git a/arch/x86/crypto/camellia-aesni-avx-asm_64.S b/arch/x86/crypto/camellia-aesni-avx-asm_64.S
index 2306d2e4816f..cfc163469c71 100644
--- a/arch/x86/crypto/camellia-aesni-avx-asm_64.S
+++ b/arch/x86/crypto/camellia-aesni-avx-asm_64.S
@@ -15,6 +15,8 @@
* http://koti.mbnet.fi/axh/crypto/camellia-BSD-1.2.0-aesni1.tar.xz
*/
+#include <linux/linkage.h>
+
#define CAMELLIA_TABLE_BYTE_LEN 272
/* struct camellia_ctx: */
@@ -190,6 +192,7 @@ roundsm16_x0_x1_x2_x3_x4_x5_x6_x7_y0_y1_y2_y3_y4_y5_y6_y7_cd:
%xmm8, %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, %xmm15,
%rcx, (%r9));
ret;
+ENDPROC(roundsm16_x0_x1_x2_x3_x4_x5_x6_x7_y0_y1_y2_y3_y4_y5_y6_y7_cd)
.align 8
roundsm16_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab:
@@ -197,6 +200,7 @@ roundsm16_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab:
%xmm12, %xmm13, %xmm14, %xmm15, %xmm8, %xmm9, %xmm10, %xmm11,
%rax, (%r9));
ret;
+ENDPROC(roundsm16_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab)
/*
* IN/OUT:
@@ -709,8 +713,6 @@ roundsm16_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab:
.text
.align 8
-.type __camellia_enc_blk16,@function;
-
__camellia_enc_blk16:
/* input:
* %rdi: ctx, CTX
@@ -793,10 +795,9 @@ __camellia_enc_blk16:
%xmm15, %rax, %rcx, 24);
jmp .Lenc_done;
+ENDPROC(__camellia_enc_blk16)
.align 8
-.type __camellia_dec_blk16,@function;
-
__camellia_dec_blk16:
/* input:
* %rdi: ctx, CTX
@@ -877,12 +878,9 @@ __camellia_dec_blk16:
((key_table + (24) * 8) + 4)(CTX));
jmp .Ldec_max24;
+ENDPROC(__camellia_dec_blk16)
-.align 8
-.global camellia_ecb_enc_16way
-.type camellia_ecb_enc_16way,@function;
-
-camellia_ecb_enc_16way:
+ENTRY(camellia_ecb_enc_16way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst (16 blocks)
@@ -903,12 +901,9 @@ camellia_ecb_enc_16way:
%xmm8, %rsi);
ret;
+ENDPROC(camellia_ecb_enc_16way)
-.align 8
-.global camellia_ecb_dec_16way
-.type camellia_ecb_dec_16way,@function;
-
-camellia_ecb_dec_16way:
+ENTRY(camellia_ecb_dec_16way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst (16 blocks)
@@ -934,12 +929,9 @@ camellia_ecb_dec_16way:
%xmm8, %rsi);
ret;
+ENDPROC(camellia_ecb_dec_16way)
-.align 8
-.global camellia_cbc_dec_16way
-.type camellia_cbc_dec_16way,@function;
-
-camellia_cbc_dec_16way:
+ENTRY(camellia_cbc_dec_16way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst (16 blocks)
@@ -986,6 +978,7 @@ camellia_cbc_dec_16way:
%xmm8, %rsi);
ret;
+ENDPROC(camellia_cbc_dec_16way)
#define inc_le128(x, minus_one, tmp) \
vpcmpeqq minus_one, x, tmp; \
@@ -993,11 +986,7 @@ camellia_cbc_dec_16way:
vpslldq $8, tmp, tmp; \
vpsubq tmp, x, x;
-.align 8
-.global camellia_ctr_16way
-.type camellia_ctr_16way,@function;
-
-camellia_ctr_16way:
+ENTRY(camellia_ctr_16way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst (16 blocks)
@@ -1100,3 +1089,4 @@ camellia_ctr_16way:
%xmm8, %rsi);
ret;
+ENDPROC(camellia_ctr_16way)
diff --git a/arch/x86/crypto/camellia-x86_64-asm_64.S b/arch/x86/crypto/camellia-x86_64-asm_64.S
index 0b3374335fdc..310319c601ed 100644
--- a/arch/x86/crypto/camellia-x86_64-asm_64.S
+++ b/arch/x86/crypto/camellia-x86_64-asm_64.S
@@ -20,6 +20,8 @@
*
*/
+#include <linux/linkage.h>
+
.file "camellia-x86_64-asm_64.S"
.text
@@ -188,10 +190,7 @@
bswapq RAB0; \
movq RAB0, 4*2(RIO);
-.global __camellia_enc_blk;
-.type __camellia_enc_blk,@function;
-
-__camellia_enc_blk:
+ENTRY(__camellia_enc_blk)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -214,33 +213,31 @@ __camellia_enc_blk:
movl $24, RT1d; /* max */
cmpb $16, key_length(CTX);
- je __enc_done;
+ je .L__enc_done;
enc_fls(24);
enc_rounds(24);
movl $32, RT1d; /* max */
-__enc_done:
+.L__enc_done:
testb RXORbl, RXORbl;
movq RDST, RIO;
- jnz __enc_xor;
+ jnz .L__enc_xor;
enc_outunpack(mov, RT1);
movq RRBP, %rbp;
ret;
-__enc_xor:
+.L__enc_xor:
enc_outunpack(xor, RT1);
movq RRBP, %rbp;
ret;
+ENDPROC(__camellia_enc_blk)
-.global camellia_dec_blk;
-.type camellia_dec_blk,@function;
-
-camellia_dec_blk:
+ENTRY(camellia_dec_blk)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -258,12 +255,12 @@ camellia_dec_blk:
dec_inpack(RT2);
cmpb $24, RT2bl;
- je __dec_rounds16;
+ je .L__dec_rounds16;
dec_rounds(24);
dec_fls(24);
-__dec_rounds16:
+.L__dec_rounds16:
dec_rounds(16);
dec_fls(16);
dec_rounds(8);
@@ -276,6 +273,7 @@ __dec_rounds16:
movq RRBP, %rbp;
ret;
+ENDPROC(camellia_dec_blk)
/**********************************************************************
2-way camellia
@@ -426,10 +424,7 @@ __dec_rounds16:
bswapq RAB1; \
movq RAB1, 12*2(RIO);
-.global __camellia_enc_blk_2way;
-.type __camellia_enc_blk_2way,@function;
-
-__camellia_enc_blk_2way:
+ENTRY(__camellia_enc_blk_2way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -453,16 +448,16 @@ __camellia_enc_blk_2way:
movl $24, RT2d; /* max */
cmpb $16, key_length(CTX);
- je __enc2_done;
+ je .L__enc2_done;
enc_fls2(24);
enc_rounds2(24);
movl $32, RT2d; /* max */
-__enc2_done:
+.L__enc2_done:
test RXORbl, RXORbl;
movq RDST, RIO;
- jnz __enc2_xor;
+ jnz .L__enc2_xor;
enc_outunpack2(mov, RT2);
@@ -470,17 +465,15 @@ __enc2_done:
popq %rbx;
ret;
-__enc2_xor:
+.L__enc2_xor:
enc_outunpack2(xor, RT2);
movq RRBP, %rbp;
popq %rbx;
ret;
+ENDPROC(__camellia_enc_blk_2way)
-.global camellia_dec_blk_2way;
-.type camellia_dec_blk_2way,@function;
-
-camellia_dec_blk_2way:
+ENTRY(camellia_dec_blk_2way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -499,12 +492,12 @@ camellia_dec_blk_2way:
dec_inpack2(RT2);
cmpb $24, RT2bl;
- je __dec2_rounds16;
+ je .L__dec2_rounds16;
dec_rounds2(24);
dec_fls2(24);
-__dec2_rounds16:
+.L__dec2_rounds16:
dec_rounds2(16);
dec_fls2(16);
dec_rounds2(8);
@@ -518,3 +511,4 @@ __dec2_rounds16:
movq RRBP, %rbp;
movq RXOR, %rbx;
ret;
+ENDPROC(camellia_dec_blk_2way)
diff --git a/arch/x86/crypto/cast5-avx-x86_64-asm_64.S b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S
index 15b00ac7cbd3..c35fd5d6ecd2 100644
--- a/arch/x86/crypto/cast5-avx-x86_64-asm_64.S
+++ b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S
@@ -23,6 +23,8 @@
*
*/
+#include <linux/linkage.h>
+
.file "cast5-avx-x86_64-asm_64.S"
.extern cast_s1
@@ -211,8 +213,6 @@
.text
.align 16
-.type __cast5_enc_blk16,@function;
-
__cast5_enc_blk16:
/* input:
* %rdi: ctx, CTX
@@ -263,14 +263,14 @@ __cast5_enc_blk16:
movzbl rr(CTX), %eax;
testl %eax, %eax;
- jnz __skip_enc;
+ jnz .L__skip_enc;
round(RL, RR, 12, 1);
round(RR, RL, 13, 2);
round(RL, RR, 14, 3);
round(RR, RL, 15, 1);
-__skip_enc:
+.L__skip_enc:
popq %rbx;
popq %rbp;
@@ -282,10 +282,9 @@ __skip_enc:
outunpack_blocks(RR4, RL4, RTMP, RX, RKM);
ret;
+ENDPROC(__cast5_enc_blk16)
.align 16
-.type __cast5_dec_blk16,@function;
-
__cast5_dec_blk16:
/* input:
* %rdi: ctx, CTX
@@ -323,14 +322,14 @@ __cast5_dec_blk16:
movzbl rr(CTX), %eax;
testl %eax, %eax;
- jnz __skip_dec;
+ jnz .L__skip_dec;
round(RL, RR, 15, 1);
round(RR, RL, 14, 3);
round(RL, RR, 13, 2);
round(RR, RL, 12, 1);
-__dec_tail:
+.L__dec_tail:
round(RL, RR, 11, 3);
round(RR, RL, 10, 2);
round(RL, RR, 9, 1);
@@ -355,15 +354,12 @@ __dec_tail:
ret;
-__skip_dec:
+.L__skip_dec:
vpsrldq $4, RKR, RKR;
- jmp __dec_tail;
+ jmp .L__dec_tail;
+ENDPROC(__cast5_dec_blk16)
-.align 16
-.global cast5_ecb_enc_16way
-.type cast5_ecb_enc_16way,@function;
-
-cast5_ecb_enc_16way:
+ENTRY(cast5_ecb_enc_16way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -393,12 +389,9 @@ cast5_ecb_enc_16way:
vmovdqu RL4, (7*4*4)(%r11);
ret;
+ENDPROC(cast5_ecb_enc_16way)
-.align 16
-.global cast5_ecb_dec_16way
-.type cast5_ecb_dec_16way,@function;
-
-cast5_ecb_dec_16way:
+ENTRY(cast5_ecb_dec_16way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -428,12 +421,9 @@ cast5_ecb_dec_16way:
vmovdqu RL4, (7*4*4)(%r11);
ret;
+ENDPROC(cast5_ecb_dec_16way)
-.align 16
-.global cast5_cbc_dec_16way
-.type cast5_cbc_dec_16way,@function;
-
-cast5_cbc_dec_16way:
+ENTRY(cast5_cbc_dec_16way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -480,12 +470,9 @@ cast5_cbc_dec_16way:
popq %r12;
ret;
+ENDPROC(cast5_cbc_dec_16way)
-.align 16
-.global cast5_ctr_16way
-.type cast5_ctr_16way,@function;
-
-cast5_ctr_16way:
+ENTRY(cast5_ctr_16way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -556,3 +543,4 @@ cast5_ctr_16way:
popq %r12;
ret;
+ENDPROC(cast5_ctr_16way)
diff --git a/arch/x86/crypto/cast6-avx-x86_64-asm_64.S b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S
index 2569d0da841f..f93b6105a0ce 100644
--- a/arch/x86/crypto/cast6-avx-x86_64-asm_64.S
+++ b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S
@@ -23,6 +23,7 @@
*
*/
+#include <linux/linkage.h>
#include "glue_helper-asm-avx.S"
.file "cast6-avx-x86_64-asm_64.S"
@@ -250,8 +251,6 @@
.text
.align 8
-.type __cast6_enc_blk8,@function;
-
__cast6_enc_blk8:
/* input:
* %rdi: ctx, CTX
@@ -295,10 +294,9 @@ __cast6_enc_blk8:
outunpack_blocks(RA2, RB2, RC2, RD2, RTMP, RX, RKRF, RKM);
ret;
+ENDPROC(__cast6_enc_blk8)
.align 8
-.type __cast6_dec_blk8,@function;
-
__cast6_dec_blk8:
/* input:
* %rdi: ctx, CTX
@@ -341,12 +339,9 @@ __cast6_dec_blk8:
outunpack_blocks(RA2, RB2, RC2, RD2, RTMP, RX, RKRF, RKM);
ret;
+ENDPROC(__cast6_dec_blk8)
-.align 8
-.global cast6_ecb_enc_8way
-.type cast6_ecb_enc_8way,@function;
-
-cast6_ecb_enc_8way:
+ENTRY(cast6_ecb_enc_8way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -362,12 +357,9 @@ cast6_ecb_enc_8way:
store_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
ret;
+ENDPROC(cast6_ecb_enc_8way)
-.align 8
-.global cast6_ecb_dec_8way
-.type cast6_ecb_dec_8way,@function;
-
-cast6_ecb_dec_8way:
+ENTRY(cast6_ecb_dec_8way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -383,12 +375,9 @@ cast6_ecb_dec_8way:
store_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
ret;
+ENDPROC(cast6_ecb_dec_8way)
-.align 8
-.global cast6_cbc_dec_8way
-.type cast6_cbc_dec_8way,@function;
-
-cast6_cbc_dec_8way:
+ENTRY(cast6_cbc_dec_8way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -409,12 +398,9 @@ cast6_cbc_dec_8way:
popq %r12;
ret;
+ENDPROC(cast6_cbc_dec_8way)
-.align 8
-.global cast6_ctr_8way
-.type cast6_ctr_8way,@function;
-
-cast6_ctr_8way:
+ENTRY(cast6_ctr_8way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -437,3 +423,4 @@ cast6_ctr_8way:
popq %r12;
ret;
+ENDPROC(cast6_ctr_8way)
diff --git a/arch/x86/crypto/crc32-pclmul_asm.S b/arch/x86/crypto/crc32-pclmul_asm.S
new file mode 100644
index 000000000000..c8335014a044
--- /dev/null
+++ b/arch/x86/crypto/crc32-pclmul_asm.S
@@ -0,0 +1,246 @@
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ *
+ * Using hardware provided PCLMULQDQ instruction to accelerate the CRC32
+ * calculation.
+ * CRC32 polynomial:0x04c11db7(BE)/0xEDB88320(LE)
+ * PCLMULQDQ is a new instruction in Intel SSE4.2, the reference can be found
+ * at:
+ * http://www.intel.com/products/processor/manuals/
+ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual
+ * Volume 2B: Instruction Set Reference, N-Z
+ *
+ * Authors: Gregory Prestas <Gregory_Prestas@us.xyratex.com>
+ * Alexander Boyko <Alexander_Boyko@xyratex.com>
+ */
+
+#include <linux/linkage.h>
+#include <asm/inst.h>
+
+
+.align 16
+/*
+ * [x4*128+32 mod P(x) << 32)]' << 1 = 0x154442bd4
+ * #define CONSTANT_R1 0x154442bd4LL
+ *
+ * [(x4*128-32 mod P(x) << 32)]' << 1 = 0x1c6e41596
+ * #define CONSTANT_R2 0x1c6e41596LL
+ */
+.Lconstant_R2R1:
+ .octa 0x00000001c6e415960000000154442bd4
+/*
+ * [(x128+32 mod P(x) << 32)]' << 1 = 0x1751997d0
+ * #define CONSTANT_R3 0x1751997d0LL
+ *
+ * [(x128-32 mod P(x) << 32)]' << 1 = 0x0ccaa009e
+ * #define CONSTANT_R4 0x0ccaa009eLL
+ */
+.Lconstant_R4R3:
+ .octa 0x00000000ccaa009e00000001751997d0
+/*
+ * [(x64 mod P(x) << 32)]' << 1 = 0x163cd6124
+ * #define CONSTANT_R5 0x163cd6124LL
+ */
+.Lconstant_R5:
+ .octa 0x00000000000000000000000163cd6124
+.Lconstant_mask32:
+ .octa 0x000000000000000000000000FFFFFFFF
+/*
+ * #define CRCPOLY_TRUE_LE_FULL 0x1DB710641LL
+ *
+ * Barrett Reduction constant (u64`) = u` = (x**64 / P(x))` = 0x1F7011641LL
+ * #define CONSTANT_RU 0x1F7011641LL
+ */
+.Lconstant_RUpoly:
+ .octa 0x00000001F701164100000001DB710641
+
+#define CONSTANT %xmm0
+
+#ifdef __x86_64__
+#define BUF %rdi
+#define LEN %rsi
+#define CRC %edx
+#else
+#define BUF %eax
+#define LEN %edx
+#define CRC %ecx
+#endif
+
+
+
+.text
+/**
+ * Calculate crc32
+ * BUF - buffer (16 bytes aligned)
+ * LEN - sizeof buffer (16 bytes aligned), LEN should be grater than 63
+ * CRC - initial crc32
+ * return %eax crc32
+ * uint crc32_pclmul_le_16(unsigned char const *buffer,
+ * size_t len, uint crc32)
+ */
+.globl crc32_pclmul_le_16
+.align 4, 0x90
+crc32_pclmul_le_16:/* buffer and buffer size are 16 bytes aligned */
+ movdqa (BUF), %xmm1
+ movdqa 0x10(BUF), %xmm2
+ movdqa 0x20(BUF), %xmm3
+ movdqa 0x30(BUF), %xmm4
+ movd CRC, CONSTANT
+ pxor CONSTANT, %xmm1
+ sub $0x40, LEN
+ add $0x40, BUF
+#ifndef __x86_64__
+ /* This is for position independent code(-fPIC) support for 32bit */
+ call delta
+delta:
+ pop %ecx
+#endif
+ cmp $0x40, LEN
+ jb less_64
+
+#ifdef __x86_64__
+ movdqa .Lconstant_R2R1(%rip), CONSTANT
+#else
+ movdqa .Lconstant_R2R1 - delta(%ecx), CONSTANT
+#endif
+
+loop_64:/* 64 bytes Full cache line folding */
+ prefetchnta 0x40(BUF)
+ movdqa %xmm1, %xmm5
+ movdqa %xmm2, %xmm6
+ movdqa %xmm3, %xmm7
+#ifdef __x86_64__
+ movdqa %xmm4, %xmm8
+#endif
+ PCLMULQDQ 00, CONSTANT, %xmm1
+ PCLMULQDQ 00, CONSTANT, %xmm2
+ PCLMULQDQ 00, CONSTANT, %xmm3
+#ifdef __x86_64__
+ PCLMULQDQ 00, CONSTANT, %xmm4
+#endif
+ PCLMULQDQ 0x11, CONSTANT, %xmm5
+ PCLMULQDQ 0x11, CONSTANT, %xmm6
+ PCLMULQDQ 0x11, CONSTANT, %xmm7
+#ifdef __x86_64__
+ PCLMULQDQ 0x11, CONSTANT, %xmm8
+#endif
+ pxor %xmm5, %xmm1
+ pxor %xmm6, %xmm2
+ pxor %xmm7, %xmm3
+#ifdef __x86_64__
+ pxor %xmm8, %xmm4
+#else
+ /* xmm8 unsupported for x32 */
+ movdqa %xmm4, %xmm5
+ PCLMULQDQ 00, CONSTANT, %xmm4
+ PCLMULQDQ 0x11, CONSTANT, %xmm5
+ pxor %xmm5, %xmm4
+#endif
+
+ pxor (BUF), %xmm1
+ pxor 0x10(BUF), %xmm2
+ pxor 0x20(BUF), %xmm3
+ pxor 0x30(BUF), %xmm4
+
+ sub $0x40, LEN
+ add $0x40, BUF
+ cmp $0x40, LEN
+ jge loop_64
+less_64:/* Folding cache line into 128bit */
+#ifdef __x86_64__
+ movdqa .Lconstant_R4R3(%rip), CONSTANT
+#else
+ movdqa .Lconstant_R4R3 - delta(%ecx), CONSTANT
+#endif
+ prefetchnta (BUF)
+
+ movdqa %xmm1, %xmm5
+ PCLMULQDQ 0x00, CONSTANT, %xmm1
+ PCLMULQDQ 0x11, CONSTANT, %xmm5
+ pxor %xmm5, %xmm1
+ pxor %xmm2, %xmm1
+
+ movdqa %xmm1, %xmm5
+ PCLMULQDQ 0x00, CONSTANT, %xmm1
+ PCLMULQDQ 0x11, CONSTANT, %xmm5
+ pxor %xmm5, %xmm1
+ pxor %xmm3, %xmm1
+
+ movdqa %xmm1, %xmm5
+ PCLMULQDQ 0x00, CONSTANT, %xmm1
+ PCLMULQDQ 0x11, CONSTANT, %xmm5
+ pxor %xmm5, %xmm1
+ pxor %xmm4, %xmm1
+
+ cmp $0x10, LEN
+ jb fold_64
+loop_16:/* Folding rest buffer into 128bit */
+ movdqa %xmm1, %xmm5
+ PCLMULQDQ 0x00, CONSTANT, %xmm1
+ PCLMULQDQ 0x11, CONSTANT, %xmm5
+ pxor %xmm5, %xmm1
+ pxor (BUF), %xmm1
+ sub $0x10, LEN
+ add $0x10, BUF
+ cmp $0x10, LEN
+ jge loop_16
+
+fold_64:
+ /* perform the last 64 bit fold, also adds 32 zeroes
+ * to the input stream */
+ PCLMULQDQ 0x01, %xmm1, CONSTANT /* R4 * xmm1.low */
+ psrldq $0x08, %xmm1
+ pxor CONSTANT, %xmm1
+
+ /* final 32-bit fold */
+ movdqa %xmm1, %xmm2
+#ifdef __x86_64__
+ movdqa .Lconstant_R5(%rip), CONSTANT
+ movdqa .Lconstant_mask32(%rip), %xmm3
+#else
+ movdqa .Lconstant_R5 - delta(%ecx), CONSTANT
+ movdqa .Lconstant_mask32 - delta(%ecx), %xmm3
+#endif
+ psrldq $0x04, %xmm2
+ pand %xmm3, %xmm1
+ PCLMULQDQ 0x00, CONSTANT, %xmm1
+ pxor %xmm2, %xmm1
+
+ /* Finish up with the bit-reversed barrett reduction 64 ==> 32 bits */
+#ifdef __x86_64__
+ movdqa .Lconstant_RUpoly(%rip), CONSTANT
+#else
+ movdqa .Lconstant_RUpoly - delta(%ecx), CONSTANT
+#endif
+ movdqa %xmm1, %xmm2
+ pand %xmm3, %xmm1
+ PCLMULQDQ 0x10, CONSTANT, %xmm1
+ pand %xmm3, %xmm1
+ PCLMULQDQ 0x00, CONSTANT, %xmm1
+ pxor %xmm2, %xmm1
+ pextrd $0x01, %xmm1, %eax
+
+ ret
diff --git a/arch/x86/crypto/crc32-pclmul_glue.c b/arch/x86/crypto/crc32-pclmul_glue.c
new file mode 100644
index 000000000000..9d014a74ef96
--- /dev/null
+++ b/arch/x86/crypto/crc32-pclmul_glue.c
@@ -0,0 +1,201 @@
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ *
+ * Wrappers for kernel crypto shash api to pclmulqdq crc32 imlementation.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/crc32.h>
+#include <crypto/internal/hash.h>
+
+#include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
+#include <asm/i387.h>
+
+#define CHKSUM_BLOCK_SIZE 1
+#define CHKSUM_DIGEST_SIZE 4
+
+#define PCLMUL_MIN_LEN 64L /* minimum size of buffer
+ * for crc32_pclmul_le_16 */
+#define SCALE_F 16L /* size of xmm register */
+#define SCALE_F_MASK (SCALE_F - 1)
+
+u32 crc32_pclmul_le_16(unsigned char const *buffer, size_t len, u32 crc32);
+
+static u32 __attribute__((pure))
+ crc32_pclmul_le(u32 crc, unsigned char const *p, size_t len)
+{
+ unsigned int iquotient;
+ unsigned int iremainder;
+ unsigned int prealign;
+
+ if (len < PCLMUL_MIN_LEN + SCALE_F_MASK || !irq_fpu_usable())
+ return crc32_le(crc, p, len);
+
+ if ((long)p & SCALE_F_MASK) {
+ /* align p to 16 byte */
+ prealign = SCALE_F - ((long)p & SCALE_F_MASK);
+
+ crc = crc32_le(crc, p, prealign);
+ len -= prealign;
+ p = (unsigned char *)(((unsigned long)p + SCALE_F_MASK) &
+ ~SCALE_F_MASK);
+ }
+ iquotient = len & (~SCALE_F_MASK);
+ iremainder = len & SCALE_F_MASK;
+
+ kernel_fpu_begin();
+ crc = crc32_pclmul_le_16(p, iquotient, crc);
+ kernel_fpu_end();
+
+ if (iremainder)
+ crc = crc32_le(crc, p + iquotient, iremainder);
+
+ return crc;
+}
+
+static int crc32_pclmul_cra_init(struct crypto_tfm *tfm)
+{
+ u32 *key = crypto_tfm_ctx(tfm);
+
+ *key = 0;
+
+ return 0;
+}
+
+static int crc32_pclmul_setkey(struct crypto_shash *hash, const u8 *key,
+ unsigned int keylen)
+{
+ u32 *mctx = crypto_shash_ctx(hash);
+
+ if (keylen != sizeof(u32)) {
+ crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+ *mctx = le32_to_cpup((__le32 *)key);
+ return 0;
+}
+
+static int crc32_pclmul_init(struct shash_desc *desc)
+{
+ u32 *mctx = crypto_shash_ctx(desc->tfm);
+ u32 *crcp = shash_desc_ctx(desc);
+
+ *crcp = *mctx;
+
+ return 0;
+}
+
+static int crc32_pclmul_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ u32 *crcp = shash_desc_ctx(desc);
+
+ *crcp = crc32_pclmul_le(*crcp, data, len);
+ return 0;
+}
+
+/* No final XOR 0xFFFFFFFF, like crc32_le */
+static int __crc32_pclmul_finup(u32 *crcp, const u8 *data, unsigned int len,
+ u8 *out)
+{
+ *(__le32 *)out = cpu_to_le32(crc32_pclmul_le(*crcp, data, len));
+ return 0;
+}
+
+static int crc32_pclmul_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ return __crc32_pclmul_finup(shash_desc_ctx(desc), data, len, out);
+}
+
+static int crc32_pclmul_final(struct shash_desc *desc, u8 *out)
+{
+ u32 *crcp = shash_desc_ctx(desc);
+
+ *(__le32 *)out = cpu_to_le32p(crcp);
+ return 0;
+}
+
+static int crc32_pclmul_digest(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ return __crc32_pclmul_finup(crypto_shash_ctx(desc->tfm), data, len,
+ out);
+}
+
+static struct shash_alg alg = {
+ .setkey = crc32_pclmul_setkey,
+ .init = crc32_pclmul_init,
+ .update = crc32_pclmul_update,
+ .final = crc32_pclmul_final,
+ .finup = crc32_pclmul_finup,
+ .digest = crc32_pclmul_digest,
+ .descsize = sizeof(u32),
+ .digestsize = CHKSUM_DIGEST_SIZE,
+ .base = {
+ .cra_name = "crc32",
+ .cra_driver_name = "crc32-pclmul",
+ .cra_priority = 200,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(u32),
+ .cra_module = THIS_MODULE,
+ .cra_init = crc32_pclmul_cra_init,
+ }
+};
+
+static const struct x86_cpu_id crc32pclmul_cpu_id[] = {
+ X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ),
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, crc32pclmul_cpu_id);
+
+
+static int __init crc32_pclmul_mod_init(void)
+{
+
+ if (!x86_match_cpu(crc32pclmul_cpu_id)) {
+ pr_info("PCLMULQDQ-NI instructions are not detected.\n");
+ return -ENODEV;
+ }
+ return crypto_register_shash(&alg);
+}
+
+static void __exit crc32_pclmul_mod_fini(void)
+{
+ crypto_unregister_shash(&alg);
+}
+
+module_init(crc32_pclmul_mod_init);
+module_exit(crc32_pclmul_mod_fini);
+
+MODULE_AUTHOR("Alexander Boyko <alexander_boyko@xyratex.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("crc32");
+MODULE_ALIAS("crc32-pclmul");
diff --git a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S
index 93c6d39237ac..cf1a7ec4cc3a 100644
--- a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S
+++ b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S
@@ -42,6 +42,8 @@
* SOFTWARE.
*/
+#include <linux/linkage.h>
+
## ISCSI CRC 32 Implementation with crc32 and pclmulqdq Instruction
.macro LABEL prefix n
@@ -68,8 +70,7 @@
# unsigned int crc_pcl(u8 *buffer, int len, unsigned int crc_init);
-.global crc_pcl
-crc_pcl:
+ENTRY(crc_pcl)
#define bufp %rdi
#define bufp_dw %edi
#define bufp_w %di
@@ -323,6 +324,9 @@ JMPTBL_ENTRY %i
.noaltmacro
i=i+1
.endr
+
+ENDPROC(crc_pcl)
+
################################################################
## PCLMULQDQ tables
## Table is 128 entries x 2 quad words each
diff --git a/arch/x86/crypto/ghash-clmulni-intel_asm.S b/arch/x86/crypto/ghash-clmulni-intel_asm.S
index 1eb7f90cb7b9..586f41aac361 100644
--- a/arch/x86/crypto/ghash-clmulni-intel_asm.S
+++ b/arch/x86/crypto/ghash-clmulni-intel_asm.S
@@ -94,6 +94,7 @@ __clmul_gf128mul_ble:
pxor T2, T1
pxor T1, DATA
ret
+ENDPROC(__clmul_gf128mul_ble)
/* void clmul_ghash_mul(char *dst, const be128 *shash) */
ENTRY(clmul_ghash_mul)
@@ -105,6 +106,7 @@ ENTRY(clmul_ghash_mul)
PSHUFB_XMM BSWAP DATA
movups DATA, (%rdi)
ret
+ENDPROC(clmul_ghash_mul)
/*
* void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
@@ -131,6 +133,7 @@ ENTRY(clmul_ghash_update)
movups DATA, (%rdi)
.Lupdate_just_ret:
ret
+ENDPROC(clmul_ghash_update)
/*
* void clmul_ghash_setkey(be128 *shash, const u8 *key);
@@ -155,3 +158,4 @@ ENTRY(clmul_ghash_setkey)
pxor %xmm1, %xmm0
movups %xmm0, (%rdi)
ret
+ENDPROC(clmul_ghash_setkey)
diff --git a/arch/x86/crypto/salsa20-i586-asm_32.S b/arch/x86/crypto/salsa20-i586-asm_32.S
index 72eb306680b2..329452b8f794 100644
--- a/arch/x86/crypto/salsa20-i586-asm_32.S
+++ b/arch/x86/crypto/salsa20-i586-asm_32.S
@@ -2,11 +2,12 @@
# D. J. Bernstein
# Public domain.
-# enter ECRYPT_encrypt_bytes
+#include <linux/linkage.h>
+
.text
-.p2align 5
-.globl ECRYPT_encrypt_bytes
-ECRYPT_encrypt_bytes:
+
+# enter salsa20_encrypt_bytes
+ENTRY(salsa20_encrypt_bytes)
mov %esp,%eax
and $31,%eax
add $256,%eax
@@ -933,11 +934,10 @@ ECRYPT_encrypt_bytes:
add $64,%esi
# goto bytesatleast1
jmp ._bytesatleast1
-# enter ECRYPT_keysetup
-.text
-.p2align 5
-.globl ECRYPT_keysetup
-ECRYPT_keysetup:
+ENDPROC(salsa20_encrypt_bytes)
+
+# enter salsa20_keysetup
+ENTRY(salsa20_keysetup)
mov %esp,%eax
and $31,%eax
add $256,%eax
@@ -1060,11 +1060,10 @@ ECRYPT_keysetup:
# leave
add %eax,%esp
ret
-# enter ECRYPT_ivsetup
-.text
-.p2align 5
-.globl ECRYPT_ivsetup
-ECRYPT_ivsetup:
+ENDPROC(salsa20_keysetup)
+
+# enter salsa20_ivsetup
+ENTRY(salsa20_ivsetup)
mov %esp,%eax
and $31,%eax
add $256,%eax
@@ -1112,3 +1111,4 @@ ECRYPT_ivsetup:
# leave
add %eax,%esp
ret
+ENDPROC(salsa20_ivsetup)
diff --git a/arch/x86/crypto/salsa20-x86_64-asm_64.S b/arch/x86/crypto/salsa20-x86_64-asm_64.S
index 6214a9b09706..9279e0b2d60e 100644
--- a/arch/x86/crypto/salsa20-x86_64-asm_64.S
+++ b/arch/x86/crypto/salsa20-x86_64-asm_64.S
@@ -1,8 +1,7 @@
-# enter ECRYPT_encrypt_bytes
-.text
-.p2align 5
-.globl ECRYPT_encrypt_bytes
-ECRYPT_encrypt_bytes:
+#include <linux/linkage.h>
+
+# enter salsa20_encrypt_bytes
+ENTRY(salsa20_encrypt_bytes)
mov %rsp,%r11
and $31,%r11
add $256,%r11
@@ -802,11 +801,10 @@ ECRYPT_encrypt_bytes:
# comment:fp stack unchanged by jump
# goto bytesatleast1
jmp ._bytesatleast1
-# enter ECRYPT_keysetup
-.text
-.p2align 5
-.globl ECRYPT_keysetup
-ECRYPT_keysetup:
+ENDPROC(salsa20_encrypt_bytes)
+
+# enter salsa20_keysetup
+ENTRY(salsa20_keysetup)
mov %rsp,%r11
and $31,%r11
add $256,%r11
@@ -892,11 +890,10 @@ ECRYPT_keysetup:
mov %rdi,%rax
mov %rsi,%rdx
ret
-# enter ECRYPT_ivsetup
-.text
-.p2align 5
-.globl ECRYPT_ivsetup
-ECRYPT_ivsetup:
+ENDPROC(salsa20_keysetup)
+
+# enter salsa20_ivsetup
+ENTRY(salsa20_ivsetup)
mov %rsp,%r11
and $31,%r11
add $256,%r11
@@ -918,3 +915,4 @@ ECRYPT_ivsetup:
mov %rdi,%rax
mov %rsi,%rdx
ret
+ENDPROC(salsa20_ivsetup)
diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c
index a3a3c0205c16..5e8e67739bb5 100644
--- a/arch/x86/crypto/salsa20_glue.c
+++ b/arch/x86/crypto/salsa20_glue.c
@@ -26,11 +26,6 @@
#define SALSA20_MIN_KEY_SIZE 16U
#define SALSA20_MAX_KEY_SIZE 32U
-// use the ECRYPT_* function names
-#define salsa20_keysetup ECRYPT_keysetup
-#define salsa20_ivsetup ECRYPT_ivsetup
-#define salsa20_encrypt_bytes ECRYPT_encrypt_bytes
-
struct salsa20_ctx
{
u32 input[16];
diff --git a/arch/x86/crypto/serpent-avx-x86_64-asm_64.S b/arch/x86/crypto/serpent-avx-x86_64-asm_64.S
index 02b0e9fe997c..43c938612b74 100644
--- a/arch/x86/crypto/serpent-avx-x86_64-asm_64.S
+++ b/arch/x86/crypto/serpent-avx-x86_64-asm_64.S
@@ -24,6 +24,7 @@
*
*/
+#include <linux/linkage.h>
#include "glue_helper-asm-avx.S"
.file "serpent-avx-x86_64-asm_64.S"
@@ -566,8 +567,6 @@
transpose_4x4(x0, x1, x2, x3, t0, t1, t2)
.align 8
-.type __serpent_enc_blk8_avx,@function;
-
__serpent_enc_blk8_avx:
/* input:
* %rdi: ctx, CTX
@@ -619,10 +618,9 @@ __serpent_enc_blk8_avx:
write_blocks(RA2, RB2, RC2, RD2, RK0, RK1, RK2);
ret;
+ENDPROC(__serpent_enc_blk8_avx)
.align 8
-.type __serpent_dec_blk8_avx,@function;
-
__serpent_dec_blk8_avx:
/* input:
* %rdi: ctx, CTX
@@ -674,12 +672,9 @@ __serpent_dec_blk8_avx:
write_blocks(RC2, RD2, RB2, RE2, RK0, RK1, RK2);
ret;
+ENDPROC(__serpent_dec_blk8_avx)
-.align 8
-.global serpent_ecb_enc_8way_avx
-.type serpent_ecb_enc_8way_avx,@function;
-
-serpent_ecb_enc_8way_avx:
+ENTRY(serpent_ecb_enc_8way_avx)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -693,12 +688,9 @@ serpent_ecb_enc_8way_avx:
store_8way(%rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
ret;
+ENDPROC(serpent_ecb_enc_8way_avx)
-.align 8
-.global serpent_ecb_dec_8way_avx
-.type serpent_ecb_dec_8way_avx,@function;
-
-serpent_ecb_dec_8way_avx:
+ENTRY(serpent_ecb_dec_8way_avx)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -712,12 +704,9 @@ serpent_ecb_dec_8way_avx:
store_8way(%rsi, RC1, RD1, RB1, RE1, RC2, RD2, RB2, RE2);
ret;
+ENDPROC(serpent_ecb_dec_8way_avx)
-.align 8
-.global serpent_cbc_dec_8way_avx
-.type serpent_cbc_dec_8way_avx,@function;
-
-serpent_cbc_dec_8way_avx:
+ENTRY(serpent_cbc_dec_8way_avx)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -731,12 +720,9 @@ serpent_cbc_dec_8way_avx:
store_cbc_8way(%rdx, %rsi, RC1, RD1, RB1, RE1, RC2, RD2, RB2, RE2);
ret;
+ENDPROC(serpent_cbc_dec_8way_avx)
-.align 8
-.global serpent_ctr_8way_avx
-.type serpent_ctr_8way_avx,@function;
-
-serpent_ctr_8way_avx:
+ENTRY(serpent_ctr_8way_avx)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -752,3 +738,4 @@ serpent_ctr_8way_avx:
store_ctr_8way(%rdx, %rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
ret;
+ENDPROC(serpent_ctr_8way_avx)
diff --git a/arch/x86/crypto/serpent-sse2-i586-asm_32.S b/arch/x86/crypto/serpent-sse2-i586-asm_32.S
index c00053d42f99..d348f1553a79 100644
--- a/arch/x86/crypto/serpent-sse2-i586-asm_32.S
+++ b/arch/x86/crypto/serpent-sse2-i586-asm_32.S
@@ -24,6 +24,8 @@
*
*/
+#include <linux/linkage.h>
+
.file "serpent-sse2-i586-asm_32.S"
.text
@@ -510,11 +512,7 @@
pxor t0, x3; \
movdqu x3, (3*4*4)(out);
-.align 8
-.global __serpent_enc_blk_4way
-.type __serpent_enc_blk_4way,@function;
-
-__serpent_enc_blk_4way:
+ENTRY(__serpent_enc_blk_4way)
/* input:
* arg_ctx(%esp): ctx, CTX
* arg_dst(%esp): dst
@@ -566,22 +564,19 @@ __serpent_enc_blk_4way:
movl arg_dst(%esp), %eax;
cmpb $0, arg_xor(%esp);
- jnz __enc_xor4;
+ jnz .L__enc_xor4;
write_blocks(%eax, RA, RB, RC, RD, RT0, RT1, RE);
ret;
-__enc_xor4:
+.L__enc_xor4:
xor_blocks(%eax, RA, RB, RC, RD, RT0, RT1, RE);
ret;
+ENDPROC(__serpent_enc_blk_4way)
-.align 8
-.global serpent_dec_blk_4way
-.type serpent_dec_blk_4way,@function;
-
-serpent_dec_blk_4way:
+ENTRY(serpent_dec_blk_4way)
/* input:
* arg_ctx(%esp): ctx, CTX
* arg_dst(%esp): dst
@@ -633,3 +628,4 @@ serpent_dec_blk_4way:
write_blocks(%eax, RC, RD, RB, RE, RT0, RT1, RA);
ret;
+ENDPROC(serpent_dec_blk_4way)
diff --git a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S
index 3ee1ff04d3e9..acc066c7c6b2 100644
--- a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S
+++ b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S
@@ -24,6 +24,8 @@
*
*/
+#include <linux/linkage.h>
+
.file "serpent-sse2-x86_64-asm_64.S"
.text
@@ -632,11 +634,7 @@
pxor t0, x3; \
movdqu x3, (3*4*4)(out);
-.align 8
-.global __serpent_enc_blk_8way
-.type __serpent_enc_blk_8way,@function;
-
-__serpent_enc_blk_8way:
+ENTRY(__serpent_enc_blk_8way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -687,24 +685,21 @@ __serpent_enc_blk_8way:
leaq (4*4*4)(%rsi), %rax;
testb %cl, %cl;
- jnz __enc_xor8;
+ jnz .L__enc_xor8;
write_blocks(%rsi, RA1, RB1, RC1, RD1, RK0, RK1, RK2);
write_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2);
ret;
-__enc_xor8:
+.L__enc_xor8:
xor_blocks(%rsi, RA1, RB1, RC1, RD1, RK0, RK1, RK2);
xor_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2);
ret;
+ENDPROC(__serpent_enc_blk_8way)
-.align 8
-.global serpent_dec_blk_8way
-.type serpent_dec_blk_8way,@function;
-
-serpent_dec_blk_8way:
+ENTRY(serpent_dec_blk_8way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -756,3 +751,4 @@ serpent_dec_blk_8way:
write_blocks(%rax, RC2, RD2, RB2, RE2, RK0, RK1, RK2);
ret;
+ENDPROC(serpent_dec_blk_8way)
diff --git a/arch/x86/crypto/sha1_ssse3_asm.S b/arch/x86/crypto/sha1_ssse3_asm.S
index 49d6987a73d9..a4109506a5e8 100644
--- a/arch/x86/crypto/sha1_ssse3_asm.S
+++ b/arch/x86/crypto/sha1_ssse3_asm.S
@@ -28,6 +28,8 @@
* (at your option) any later version.
*/
+#include <linux/linkage.h>
+
#define CTX %rdi // arg1
#define BUF %rsi // arg2
#define CNT %rdx // arg3
@@ -69,10 +71,8 @@
* param: function's name
*/
.macro SHA1_VECTOR_ASM name
- .global \name
- .type \name, @function
- .align 32
-\name:
+ ENTRY(\name)
+
push %rbx
push %rbp
push %r12
@@ -106,7 +106,7 @@
pop %rbx
ret
- .size \name, .-\name
+ ENDPROC(\name)
.endm
/*
diff --git a/arch/x86/crypto/twofish-avx-x86_64-asm_64.S b/arch/x86/crypto/twofish-avx-x86_64-asm_64.S
index ebac16bfa830..8d3e113b2c95 100644
--- a/arch/x86/crypto/twofish-avx-x86_64-asm_64.S
+++ b/arch/x86/crypto/twofish-avx-x86_64-asm_64.S
@@ -23,6 +23,7 @@
*
*/
+#include <linux/linkage.h>
#include "glue_helper-asm-avx.S"
.file "twofish-avx-x86_64-asm_64.S"
@@ -243,8 +244,6 @@
vpxor x3, wkey, x3;
.align 8
-.type __twofish_enc_blk8,@function;
-
__twofish_enc_blk8:
/* input:
* %rdi: ctx, CTX
@@ -284,10 +283,9 @@ __twofish_enc_blk8:
outunpack_blocks(RC2, RD2, RA2, RB2, RK1, RX0, RY0, RK2);
ret;
+ENDPROC(__twofish_enc_blk8)
.align 8
-.type __twofish_dec_blk8,@function;
-
__twofish_dec_blk8:
/* input:
* %rdi: ctx, CTX
@@ -325,12 +323,9 @@ __twofish_dec_blk8:
outunpack_blocks(RA2, RB2, RC2, RD2, RK1, RX0, RY0, RK2);
ret;
+ENDPROC(__twofish_dec_blk8)
-.align 8
-.global twofish_ecb_enc_8way
-.type twofish_ecb_enc_8way,@function;
-
-twofish_ecb_enc_8way:
+ENTRY(twofish_ecb_enc_8way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -346,12 +341,9 @@ twofish_ecb_enc_8way:
store_8way(%r11, RC1, RD1, RA1, RB1, RC2, RD2, RA2, RB2);
ret;
+ENDPROC(twofish_ecb_enc_8way)
-.align 8
-.global twofish_ecb_dec_8way
-.type twofish_ecb_dec_8way,@function;
-
-twofish_ecb_dec_8way:
+ENTRY(twofish_ecb_dec_8way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -367,12 +359,9 @@ twofish_ecb_dec_8way:
store_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
ret;
+ENDPROC(twofish_ecb_dec_8way)
-.align 8
-.global twofish_cbc_dec_8way
-.type twofish_cbc_dec_8way,@function;
-
-twofish_cbc_dec_8way:
+ENTRY(twofish_cbc_dec_8way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -393,12 +382,9 @@ twofish_cbc_dec_8way:
popq %r12;
ret;
+ENDPROC(twofish_cbc_dec_8way)
-.align 8
-.global twofish_ctr_8way
-.type twofish_ctr_8way,@function;
-
-twofish_ctr_8way:
+ENTRY(twofish_ctr_8way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -421,3 +407,4 @@ twofish_ctr_8way:
popq %r12;
ret;
+ENDPROC(twofish_ctr_8way)
diff --git a/arch/x86/crypto/twofish-i586-asm_32.S b/arch/x86/crypto/twofish-i586-asm_32.S
index 658af4bb35c9..694ea4587ba7 100644
--- a/arch/x86/crypto/twofish-i586-asm_32.S
+++ b/arch/x86/crypto/twofish-i586-asm_32.S
@@ -20,6 +20,7 @@
.file "twofish-i586-asm.S"
.text
+#include <linux/linkage.h>
#include <asm/asm-offsets.h>
/* return address at 0 */
@@ -219,11 +220,7 @@
xor %esi, d ## D;\
ror $1, d ## D;
-.align 4
-.global twofish_enc_blk
-.global twofish_dec_blk
-
-twofish_enc_blk:
+ENTRY(twofish_enc_blk)
push %ebp /* save registers according to calling convention*/
push %ebx
push %esi
@@ -277,8 +274,9 @@ twofish_enc_blk:
pop %ebp
mov $1, %eax
ret
+ENDPROC(twofish_enc_blk)
-twofish_dec_blk:
+ENTRY(twofish_dec_blk)
push %ebp /* save registers according to calling convention*/
push %ebx
push %esi
@@ -333,3 +331,4 @@ twofish_dec_blk:
pop %ebp
mov $1, %eax
ret
+ENDPROC(twofish_dec_blk)
diff --git a/arch/x86/crypto/twofish-x86_64-asm_64-3way.S b/arch/x86/crypto/twofish-x86_64-asm_64-3way.S
index 5b012a2c5119..1c3b7ceb36d2 100644
--- a/arch/x86/crypto/twofish-x86_64-asm_64-3way.S
+++ b/arch/x86/crypto/twofish-x86_64-asm_64-3way.S
@@ -20,6 +20,8 @@
*
*/
+#include <linux/linkage.h>
+
.file "twofish-x86_64-asm-3way.S"
.text
@@ -214,11 +216,7 @@
rorq $32, RAB2; \
outunpack3(mov, RIO, 2, RAB, 2);
-.align 8
-.global __twofish_enc_blk_3way
-.type __twofish_enc_blk_3way,@function;
-
-__twofish_enc_blk_3way:
+ENTRY(__twofish_enc_blk_3way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -250,7 +248,7 @@ __twofish_enc_blk_3way:
popq %rbp; /* bool xor */
testb %bpl, %bpl;
- jnz __enc_xor3;
+ jnz .L__enc_xor3;
outunpack_enc3(mov);
@@ -262,7 +260,7 @@ __twofish_enc_blk_3way:
popq %r15;
ret;
-__enc_xor3:
+.L__enc_xor3:
outunpack_enc3(xor);
popq %rbx;
@@ -272,11 +270,9 @@ __enc_xor3:
popq %r14;
popq %r15;
ret;
+ENDPROC(__twofish_enc_blk_3way)
-.global twofish_dec_blk_3way
-.type twofish_dec_blk_3way,@function;
-
-twofish_dec_blk_3way:
+ENTRY(twofish_dec_blk_3way)
/* input:
* %rdi: ctx, CTX
* %rsi: dst
@@ -313,4 +309,4 @@ twofish_dec_blk_3way:
popq %r14;
popq %r15;
ret;
-
+ENDPROC(twofish_dec_blk_3way)
diff --git a/arch/x86/crypto/twofish-x86_64-asm_64.S b/arch/x86/crypto/twofish-x86_64-asm_64.S
index 7bcf3fcc3668..a039d21986a2 100644
--- a/arch/x86/crypto/twofish-x86_64-asm_64.S
+++ b/arch/x86/crypto/twofish-x86_64-asm_64.S
@@ -20,6 +20,7 @@
.file "twofish-x86_64-asm.S"
.text
+#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#define a_offset 0
@@ -214,11 +215,7 @@
xor %r8d, d ## D;\
ror $1, d ## D;
-.align 8
-.global twofish_enc_blk
-.global twofish_dec_blk
-
-twofish_enc_blk:
+ENTRY(twofish_enc_blk)
pushq R1
/* %rdi contains the ctx address */
@@ -269,8 +266,9 @@ twofish_enc_blk:
popq R1
movq $1,%rax
ret
+ENDPROC(twofish_enc_blk)
-twofish_dec_blk:
+ENTRY(twofish_dec_blk)
pushq R1
/* %rdi contains the ctx address */
@@ -320,3 +318,4 @@ twofish_dec_blk:
popq R1
movq $1,%rax
ret
+ENDPROC(twofish_dec_blk)
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index a1daf4a65009..cf1a471a18a2 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -129,13 +129,6 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
return err;
}
-asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
/*
* Do a signal return; undo the signal stack.
*/
@@ -215,8 +208,9 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
return err;
}
-asmlinkage long sys32_sigreturn(struct pt_regs *regs)
+asmlinkage long sys32_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
sigset_t set;
unsigned int ax;
@@ -241,8 +235,9 @@ badframe:
return 0;
}
-asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
+asmlinkage long sys32_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct rt_sigframe_ia32 __user *frame;
sigset_t set;
unsigned int ax;
@@ -314,7 +309,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
/*
* Determine which stack to use..
*/
-static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
size_t frame_size,
void __user **fpstate)
{
@@ -324,16 +319,13 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
sp = regs->sp;
/* This is the X/Open sanctioned signal stack switching. */
- if (ka->sa.sa_flags & SA_ONSTACK) {
- if (sas_ss_flags(sp) == 0)
- sp = current->sas_ss_sp + current->sas_ss_size;
- }
-
+ if (ksig->ka.sa.sa_flags & SA_ONSTACK)
+ sp = sigsp(sp, ksig);
/* This is the legacy signal stack switching. */
else if ((regs->ss & 0xffff) != __USER32_DS &&
- !(ka->sa.sa_flags & SA_RESTORER) &&
- ka->sa.sa_restorer)
- sp = (unsigned long) ka->sa.sa_restorer;
+ !(ksig->ka.sa.sa_flags & SA_RESTORER) &&
+ ksig->ka.sa.sa_restorer)
+ sp = (unsigned long) ksig->ka.sa.sa_restorer;
if (used_math()) {
unsigned long fx_aligned, math_size;
@@ -352,7 +344,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
return (void __user *) sp;
}
-int ia32_setup_frame(int sig, struct k_sigaction *ka,
+int ia32_setup_frame(int sig, struct ksignal *ksig,
compat_sigset_t *set, struct pt_regs *regs)
{
struct sigframe_ia32 __user *frame;
@@ -371,7 +363,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
0x80cd, /* int $0x80 */
};
- frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
+ frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;
@@ -388,8 +380,8 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
return -EFAULT;
}
- if (ka->sa.sa_flags & SA_RESTORER) {
- restorer = ka->sa.sa_restorer;
+ if (ksig->ka.sa.sa_flags & SA_RESTORER) {
+ restorer = ksig->ka.sa.sa_restorer;
} else {
/* Return stub is in 32bit vsyscall page */
if (current->mm->context.vdso)
@@ -414,7 +406,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
/* Set up registers for signal handler */
regs->sp = (unsigned long) frame;
- regs->ip = (unsigned long) ka->sa.sa_handler;
+ regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
/* Make -mregparm=3 work */
regs->ax = sig;
@@ -430,7 +422,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
return 0;
}
-int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
compat_sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe_ia32 __user *frame;
@@ -451,7 +443,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
0,
};
- frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
+ frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;
@@ -469,8 +461,8 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
put_user_ex(0, &frame->uc.uc_link);
err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
- if (ka->sa.sa_flags & SA_RESTORER)
- restorer = ka->sa.sa_restorer;
+ if (ksig->ka.sa.sa_flags & SA_RESTORER)
+ restorer = ksig->ka.sa.sa_restorer;
else
restorer = VDSO32_SYMBOL(current->mm->context.vdso,
rt_sigreturn);
@@ -483,7 +475,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
} put_user_catch(err);
- err |= copy_siginfo_to_user32(&frame->info, info);
+ err |= copy_siginfo_to_user32(&frame->info, &ksig->info);
err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
@@ -493,7 +485,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up registers for signal handler */
regs->sp = (unsigned long) frame;
- regs->ip = (unsigned long) ka->sa.sa_handler;
+ regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
/* Make -mregparm=3 work */
regs->ax = sig;
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 142c4ceff112..474dc1b59f72 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -456,18 +456,16 @@ ia32_badsys:
ALIGN
GLOBAL(\label)
leaq \func(%rip),%rax
- leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
jmp ia32_ptregs_common
.endm
CFI_STARTPROC32
- PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi
- PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
- PTREGSCALL stub32_execve, compat_sys_execve, %rcx
- PTREGSCALL stub32_fork, sys_fork, %rdi
- PTREGSCALL stub32_vfork, sys_vfork, %rdi
- PTREGSCALL stub32_iopl, sys_iopl, %rsi
+ PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn
+ PTREGSCALL stub32_sigreturn, sys32_sigreturn
+ PTREGSCALL stub32_execve, compat_sys_execve
+ PTREGSCALL stub32_fork, sys_fork
+ PTREGSCALL stub32_vfork, sys_vfork
ALIGN
GLOBAL(stub32_clone)
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index d0b689ba7be2..592f5a9a9c0e 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -172,183 +172,12 @@ asmlinkage long sys32_mprotect(unsigned long start, size_t len,
return sys_mprotect(start, len, prot);
}
-asmlinkage long sys32_rt_sigaction(int sig, struct sigaction32 __user *act,
- struct sigaction32 __user *oact,
- unsigned int sigsetsize)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
- compat_sigset_t set32;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(compat_sigset_t))
- return -EINVAL;
-
- if (act) {
- compat_uptr_t handler, restorer;
-
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(restorer, &act->sa_restorer) ||
- __copy_from_user(&set32, &act->sa_mask,
- sizeof(compat_sigset_t)))
- return -EFAULT;
- new_ka.sa.sa_handler = compat_ptr(handler);
- new_ka.sa.sa_restorer = compat_ptr(restorer);
-
- /*
- * FIXME: here we rely on _COMPAT_NSIG_WORS to be >=
- * than _NSIG_WORDS << 1
- */
- switch (_NSIG_WORDS) {
- case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
- | (((long)set32.sig[7]) << 32);
- case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
- | (((long)set32.sig[5]) << 32);
- case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
- | (((long)set32.sig[3]) << 32);
- case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
- | (((long)set32.sig[1]) << 32);
- }
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- /*
- * FIXME: here we rely on _COMPAT_NSIG_WORS to be >=
- * than _NSIG_WORDS << 1
- */
- switch (_NSIG_WORDS) {
- case 4:
- set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
- set32.sig[6] = old_ka.sa.sa_mask.sig[3];
- case 3:
- set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
- set32.sig[4] = old_ka.sa.sa_mask.sig[2];
- case 2:
- set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
- set32.sig[2] = old_ka.sa.sa_mask.sig[1];
- case 1:
- set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
- set32.sig[0] = old_ka.sa.sa_mask.sig[0];
- }
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(ptr_to_compat(old_ka.sa.sa_handler),
- &oact->sa_handler) ||
- __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
- &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __copy_to_user(&oact->sa_mask, &set32,
- sizeof(compat_sigset_t)))
- return -EFAULT;
- }
-
- return ret;
-}
-
-asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 __user *act,
- struct old_sigaction32 __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- compat_old_sigset_t mask;
- compat_uptr_t handler, restorer;
-
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(restorer, &act->sa_restorer) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
-
- new_ka.sa.sa_handler = compat_ptr(handler);
- new_ka.sa.sa_restorer = compat_ptr(restorer);
-
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(ptr_to_compat(old_ka.sa.sa_handler),
- &oact->sa_handler) ||
- __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
- &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
-
asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int __user *stat_addr,
int options)
{
return compat_sys_wait4(pid, stat_addr, options, NULL);
}
-/* 32-bit timeval and related flotsam. */
-
-asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
- struct compat_timespec __user *interval)
-{
- struct timespec t;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
- set_fs(old_fs);
- if (put_compat_timespec(&t, interval))
- return -EFAULT;
- return ret;
-}
-
-asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
- compat_size_t sigsetsize)
-{
- sigset_t s;
- compat_sigset_t s32;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- ret = sys_rt_sigpending((sigset_t __user *)&s, sigsetsize);
- set_fs(old_fs);
- if (!ret) {
- switch (_NSIG_WORDS) {
- case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
- case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
- case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
- case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
- }
- if (copy_to_user(set, &s32, sizeof(compat_sigset_t)))
- return -EFAULT;
- }
- return ret;
-}
-
-asmlinkage long sys32_rt_sigqueueinfo(int pid, int sig,
- compat_siginfo_t __user *uinfo)
-{
- siginfo_t info;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- if (copy_siginfo_from_user32(&info, uinfo))
- return -EFAULT;
- set_fs(KERNEL_DS);
- ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
- set_fs(old_fs);
- return ret;
-}
-
/* warning: next two assume little endian */
asmlinkage long sys32_pread(unsigned int fd, char __user *ubuf, u32 count,
u32 poslo, u32 poshi)
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index 0c44630d1789..b31bf97775fc 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -49,10 +49,6 @@
/* Asm macros */
-#define ACPI_ASM_MACROS
-#define BREAKPOINT3
-#define ACPI_DISABLE_IRQS() local_irq_disable()
-#define ACPI_ENABLE_IRQS() local_irq_enable()
#define ACPI_FLUSH_CPU_CACHE() wbinvd()
int __acpi_acquire_global_lock(unsigned int *lock);
diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h
index b3341e9cd8fd..a54ee1d054d9 100644
--- a/arch/x86/include/asm/amd_nb.h
+++ b/arch/x86/include/asm/amd_nb.h
@@ -81,6 +81,23 @@ static inline struct amd_northbridge *node_to_amd_nb(int node)
return (node < amd_northbridges.num) ? &amd_northbridges.nb[node] : NULL;
}
+static inline u16 amd_get_node_id(struct pci_dev *pdev)
+{
+ struct pci_dev *misc;
+ int i;
+
+ for (i = 0; i != amd_nb_num(); i++) {
+ misc = node_to_amd_nb(i)->misc;
+
+ if (pci_domain_nr(misc->bus) == pci_domain_nr(pdev->bus) &&
+ PCI_SLOT(misc->devfn) == PCI_SLOT(pdev->devfn))
+ return i;
+ }
+
+ WARN(1, "Unable to find AMD Northbridge id for %s\n", pci_name(pdev));
+ return 0;
+}
+
#else
#define amd_nb_num(x) 0
diff --git a/arch/x86/include/asm/bootparam_utils.h b/arch/x86/include/asm/bootparam_utils.h
new file mode 100644
index 000000000000..5b5e9cb774b5
--- /dev/null
+++ b/arch/x86/include/asm/bootparam_utils.h
@@ -0,0 +1,38 @@
+#ifndef _ASM_X86_BOOTPARAM_UTILS_H
+#define _ASM_X86_BOOTPARAM_UTILS_H
+
+#include <asm/bootparam.h>
+
+/*
+ * This file is included from multiple environments. Do not
+ * add completing #includes to make it standalone.
+ */
+
+/*
+ * Deal with bootloaders which fail to initialize unknown fields in
+ * boot_params to zero. The list fields in this list are taken from
+ * analysis of kexec-tools; if other broken bootloaders initialize a
+ * different set of fields we will need to figure out how to disambiguate.
+ *
+ */
+static void sanitize_boot_params(struct boot_params *boot_params)
+{
+ if (boot_params->sentinel) {
+ /*fields in boot_params are not valid, clear them */
+ memset(&boot_params->olpc_ofw_header, 0,
+ (char *)&boot_params->alt_mem_k -
+ (char *)&boot_params->olpc_ofw_header);
+ memset(&boot_params->kbd_status, 0,
+ (char *)&boot_params->hdr -
+ (char *)&boot_params->kbd_status);
+ memset(&boot_params->_pad7[0], 0,
+ (char *)&boot_params->edd_mbr_sig_buffer[0] -
+ (char *)&boot_params->_pad7[0]);
+ memset(&boot_params->_pad8[0], 0,
+ (char *)&boot_params->eddbuf[0] -
+ (char *)&boot_params->_pad8[0]);
+ memset(&boot_params->_pad9[0], 0, sizeof(boot_params->_pad9));
+ }
+}
+
+#endif /* _ASM_X86_BOOTPARAM_UTILS_H */
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 2d9075e863a0..93fe929d1cee 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -167,6 +167,7 @@
#define X86_FEATURE_TBM (6*32+21) /* trailing bit manipulations */
#define X86_FEATURE_TOPOEXT (6*32+22) /* topology extensions CPUID leafs */
#define X86_FEATURE_PERFCTR_CORE (6*32+23) /* core performance counter extensions */
+#define X86_FEATURE_PERFCTR_NB (6*32+24) /* NB performance counter extensions */
/*
* Auxiliary flags: Linux defined - For features scattered in various
@@ -309,6 +310,7 @@ extern const char * const x86_power_flags[32];
#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR)
#define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ)
#define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
+#define cpu_has_perfctr_nb boot_cpu_has(X86_FEATURE_PERFCTR_NB)
#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8)
#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16)
#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index 41ab26ea6564..e25cc33ec54d 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -26,9 +26,10 @@
#ifdef CONFIG_X86_64
# include <asm/sigcontext32.h>
# include <asm/user32.h>
-int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+struct ksignal;
+int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
compat_sigset_t *set, struct pt_regs *regs);
-int ia32_setup_frame(int sig, struct k_sigaction *ka,
+int ia32_setup_frame(int sig, struct ksignal *ksig,
compat_sigset_t *set, struct pt_regs *regs);
#else
# define user_i387_ia32_struct user_i387_struct
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index 9a25b522d377..86cb51e1ca96 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -44,7 +44,6 @@
#ifdef CONFIG_DYNAMIC_FTRACE
#define ARCH_SUPPORTS_FTRACE_OPS 1
-#define ARCH_SUPPORTS_FTRACE_SAVE_REGS
#endif
#ifndef __ASSEMBLY__
diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h
index 434e2106cc87..b18df579c0e9 100644
--- a/arch/x86/include/asm/hpet.h
+++ b/arch/x86/include/asm/hpet.h
@@ -80,9 +80,9 @@ extern void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg);
extern void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg);
#ifdef CONFIG_PCI_MSI
-extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id);
+extern int default_setup_hpet_msi(unsigned int irq, unsigned int id);
#else
-static inline int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
+static inline int default_setup_hpet_msi(unsigned int irq, unsigned int id)
{
return -EINVAL;
}
@@ -111,6 +111,7 @@ extern void hpet_unregister_irq_handler(rtc_irq_handler handler);
static inline int hpet_enable(void) { return 0; }
static inline int is_hpet_enabled(void) { return 0; }
#define hpet_readl(a) 0
+#define default_setup_hpet_msi NULL
#endif
#endif /* _ASM_X86_HPET_H */
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index eb92a6ed2be7..10a78c3d3d5a 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -101,6 +101,7 @@ static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
irq_attr->polarity = polarity;
}
+/* Intel specific interrupt remapping information */
struct irq_2_iommu {
struct intel_iommu *iommu;
u16 irte_index;
@@ -108,6 +109,12 @@ struct irq_2_iommu {
u8 irte_mask;
};
+/* AMD specific interrupt remapping information */
+struct irq_2_irte {
+ u16 devid; /* Device ID for IRTE table */
+ u16 index; /* Index into IRTE table*/
+};
+
/*
* This is performance-critical, we want to do it O(1)
*
@@ -120,7 +127,11 @@ struct irq_cfg {
u8 vector;
u8 move_in_progress : 1;
#ifdef CONFIG_IRQ_REMAP
- struct irq_2_iommu irq_2_iommu;
+ u8 remapped : 1;
+ union {
+ struct irq_2_iommu irq_2_iommu;
+ struct irq_2_irte irq_2_irte;
+ };
#endif
};
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h
index b518c7509933..86095ed14135 100644
--- a/arch/x86/include/asm/hypervisor.h
+++ b/arch/x86/include/asm/hypervisor.h
@@ -25,6 +25,7 @@
extern void init_hypervisor(struct cpuinfo_x86 *c);
extern void init_hypervisor_platform(void);
+extern bool hypervisor_x2apic_available(void);
/*
* x86 hypervisor information
@@ -41,6 +42,9 @@ struct hypervisor_x86 {
/* Platform setup (run once per boot) */
void (*init_platform)(void);
+
+ /* X2APIC detection (run once per boot) */
+ bool (*x2apic_available)(void);
};
extern const struct hypervisor_x86 *x86_hyper;
@@ -51,13 +55,4 @@ extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
extern const struct hypervisor_x86 x86_hyper_xen_hvm;
extern const struct hypervisor_x86 x86_hyper_kvm;
-static inline bool hypervisor_x2apic_available(void)
-{
- if (kvm_para_available())
- return true;
- if (xen_x2apic_para_available())
- return true;
- return false;
-}
-
#endif
diff --git a/arch/x86/include/asm/ia32.h b/arch/x86/include/asm/ia32.h
index 4c6da2e4bb1d..d0e8e0141041 100644
--- a/arch/x86/include/asm/ia32.h
+++ b/arch/x86/include/asm/ia32.h
@@ -13,21 +13,6 @@
#include <asm/sigcontext32.h>
/* signal.h */
-struct sigaction32 {
- unsigned int sa_handler; /* Really a pointer, but need to deal
- with 32 bits */
- unsigned int sa_flags;
- unsigned int sa_restorer; /* Another 32 bit pointer */
- compat_sigset_t sa_mask; /* A 32 bit mask */
-};
-
-struct old_sigaction32 {
- unsigned int sa_handler; /* Really a pointer, but need to deal
- with 32 bits */
- compat_old_sigset_t sa_mask; /* A 32 bit mask */
- unsigned int sa_flags;
- unsigned int sa_restorer; /* Another 32 bit pointer */
-};
struct ucontext_ia32 {
unsigned int uc_flags;
diff --git a/arch/x86/include/asm/init.h b/arch/x86/include/asm/init.h
index adcc0ae73d09..223042086f4e 100644
--- a/arch/x86/include/asm/init.h
+++ b/arch/x86/include/asm/init.h
@@ -1,20 +1,14 @@
-#ifndef _ASM_X86_INIT_32_H
-#define _ASM_X86_INIT_32_H
+#ifndef _ASM_X86_INIT_H
+#define _ASM_X86_INIT_H
-#ifdef CONFIG_X86_32
-extern void __init early_ioremap_page_table_range_init(void);
-#endif
+struct x86_mapping_info {
+ void *(*alloc_pgt_page)(void *); /* allocate buf for page table */
+ void *context; /* context for alloc_pgt_page */
+ unsigned long pmd_flag; /* page flag for PMD entry */
+ bool kernel_mapping; /* kernel mapping or ident mapping */
+};
-extern void __init zone_sizes_init(void);
+int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
+ unsigned long addr, unsigned long end);
-extern unsigned long __init
-kernel_physical_mapping_init(unsigned long start,
- unsigned long end,
- unsigned long page_size_mask);
-
-
-extern unsigned long __initdata pgt_buf_start;
-extern unsigned long __meminitdata pgt_buf_end;
-extern unsigned long __meminitdata pgt_buf_top;
-
-#endif /* _ASM_X86_INIT_32_H */
+#endif /* _ASM_X86_INIT_H */
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 73d8c5398ea9..459e50a424d1 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -144,11 +144,24 @@ extern int timer_through_8259;
(mp_irq_entries && !skip_ioapic_setup && io_apic_irqs)
struct io_apic_irq_attr;
+struct irq_cfg;
extern int io_apic_set_pci_routing(struct device *dev, int irq,
struct io_apic_irq_attr *irq_attr);
void setup_IO_APIC_irq_extra(u32 gsi);
extern void ioapic_insert_resources(void);
+extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *,
+ unsigned int, int,
+ struct io_apic_irq_attr *);
+extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *,
+ unsigned int, int,
+ struct io_apic_irq_attr *);
+extern void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg);
+
+extern void native_compose_msi_msg(struct pci_dev *pdev,
+ unsigned int irq, unsigned int dest,
+ struct msi_msg *msg, u8 hpet_id);
+extern void native_eoi_ioapic_pin(int apic, int pin, int vector);
int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr);
extern int save_ioapic_entries(void);
@@ -179,6 +192,12 @@ extern void __init native_io_apic_init_mappings(void);
extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg);
extern void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int val);
extern void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
+extern void native_disable_io_apic(void);
+extern void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries);
+extern void intel_ir_io_apic_print_entries(unsigned int apic, unsigned int nr_entries);
+extern int native_ioapic_set_affinity(struct irq_data *,
+ const struct cpumask *,
+ bool);
static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
{
@@ -193,6 +212,9 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned
{
x86_io_apic_ops.modify(apic, reg, value);
}
+
+extern void io_apic_eoi(unsigned int apic, unsigned int vector);
+
#else /* !CONFIG_X86_IO_APIC */
#define io_apic_assign_pci_irqs 0
@@ -223,6 +245,12 @@ static inline void disable_ioapic_support(void) { }
#define native_io_apic_read NULL
#define native_io_apic_write NULL
#define native_io_apic_modify NULL
+#define native_disable_io_apic NULL
+#define native_io_apic_print_entries NULL
+#define native_ioapic_set_affinity NULL
+#define native_setup_ioapic_entry NULL
+#define native_compose_msi_msg NULL
+#define native_eoi_ioapic_pin NULL
#endif
#endif /* _ASM_X86_IO_APIC_H */
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index 5fb9bbbd2f14..95fd3527f632 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -26,8 +26,6 @@
#ifdef CONFIG_IRQ_REMAP
-extern int irq_remapping_enabled;
-
extern void setup_irq_remapping_ops(void);
extern int irq_remapping_supported(void);
extern int irq_remapping_prepare(void);
@@ -40,21 +38,19 @@ extern int setup_ioapic_remapped_entry(int irq,
unsigned int destination,
int vector,
struct io_apic_irq_attr *attr);
-extern int set_remapped_irq_affinity(struct irq_data *data,
- const struct cpumask *mask,
- bool force);
extern void free_remapped_irq(int irq);
extern void compose_remapped_msi_msg(struct pci_dev *pdev,
unsigned int irq, unsigned int dest,
struct msi_msg *msg, u8 hpet_id);
-extern int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
-extern int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
- int index, int sub_handle);
extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id);
+extern void panic_if_irq_remap(const char *msg);
+extern bool setup_remapped_irq(int irq,
+ struct irq_cfg *cfg,
+ struct irq_chip *chip);
-#else /* CONFIG_IRQ_REMAP */
+void irq_remap_modify_chip_defaults(struct irq_chip *chip);
-#define irq_remapping_enabled 0
+#else /* CONFIG_IRQ_REMAP */
static inline void setup_irq_remapping_ops(void) { }
static inline int irq_remapping_supported(void) { return 0; }
@@ -71,30 +67,30 @@ static inline int setup_ioapic_remapped_entry(int irq,
{
return -ENODEV;
}
-static inline int set_remapped_irq_affinity(struct irq_data *data,
- const struct cpumask *mask,
- bool force)
-{
- return 0;
-}
static inline void free_remapped_irq(int irq) { }
static inline void compose_remapped_msi_msg(struct pci_dev *pdev,
unsigned int irq, unsigned int dest,
struct msi_msg *msg, u8 hpet_id)
{
}
-static inline int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
+static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
{
return -ENODEV;
}
-static inline int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
- int index, int sub_handle)
+
+static inline void panic_if_irq_remap(const char *msg)
+{
+}
+
+static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
{
- return -ENODEV;
}
-static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
+
+static inline bool setup_remapped_irq(int irq,
+ struct irq_cfg *cfg,
+ struct irq_chip *chip)
{
- return -ENODEV;
+ return false;
}
#endif /* CONFIG_IRQ_REMAP */
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index 1508e518c7e3..aac5fa62a86c 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -109,8 +109,8 @@
#define UV_BAU_MESSAGE 0xf5
-/* Xen vector callback to receive events in a HVM domain */
-#define XEN_HVM_EVTCHN_CALLBACK 0xf3
+/* Vector on which hypervisor callbacks will be delivered */
+#define HYPERVISOR_CALLBACK_VECTOR 0xf3
/*
* Local APIC timer IRQ vector is on a different priority level,
diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h
index 6080d2694bad..17483a492f18 100644
--- a/arch/x86/include/asm/kexec.h
+++ b/arch/x86/include/asm/kexec.h
@@ -48,11 +48,11 @@
# define vmcore_elf_check_arch_cross(x) ((x)->e_machine == EM_X86_64)
#else
/* Maximum physical address we can use pages from */
-# define KEXEC_SOURCE_MEMORY_LIMIT (0xFFFFFFFFFFUL)
+# define KEXEC_SOURCE_MEMORY_LIMIT (MAXMEM-1)
/* Maximum address we can reach in physical address mode */
-# define KEXEC_DESTINATION_MEMORY_LIMIT (0xFFFFFFFFFFUL)
+# define KEXEC_DESTINATION_MEMORY_LIMIT (MAXMEM-1)
/* Maximum address we can use for the control pages */
-# define KEXEC_CONTROL_MEMORY_LIMIT (0xFFFFFFFFFFUL)
+# define KEXEC_CONTROL_MEMORY_LIMIT (MAXMEM-1)
/* Allocate one page for the pdp and the second for the code */
# define KEXEC_CONTROL_PAGE_SIZE (4096UL + 4096UL)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index dc87b65e9c3a..635a74d22409 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -33,10 +33,10 @@
#define KVM_MAX_VCPUS 254
#define KVM_SOFT_MAX_VCPUS 160
-#define KVM_MEMORY_SLOTS 32
-/* memory slots that does not exposed to userspace */
-#define KVM_PRIVATE_MEM_SLOTS 4
-#define KVM_MEM_SLOTS_NUM (KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS)
+#define KVM_USER_MEM_SLOTS 125
+/* memory slots that are not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS 3
+#define KVM_MEM_SLOTS_NUM (KVM_USER_MEM_SLOTS + KVM_PRIVATE_MEM_SLOTS)
#define KVM_MMIO_SIZE 16
@@ -219,11 +219,6 @@ struct kvm_mmu_page {
u64 *spt;
/* hold the gfn of each spte inside spt */
gfn_t *gfns;
- /*
- * One bit set per slot which has memory
- * in this shadow page.
- */
- DECLARE_BITMAP(slot_bitmap, KVM_MEM_SLOTS_NUM);
bool unsync;
int root_count; /* Currently serving as active root */
unsigned int unsync_children;
@@ -502,6 +497,13 @@ struct kvm_vcpu_arch {
u64 msr_val;
struct gfn_to_hva_cache data;
} pv_eoi;
+
+ /*
+ * Indicate whether the access faults on its page table in guest
+ * which is set when fix page fault and used to detect unhandeable
+ * instruction.
+ */
+ bool write_fault_to_shadow_pgtable;
};
struct kvm_lpage_info {
@@ -697,6 +699,11 @@ struct kvm_x86_ops {
void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
void (*enable_irq_window)(struct kvm_vcpu *vcpu);
void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
+ int (*vm_has_apicv)(struct kvm *kvm);
+ void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
+ void (*hwapic_isr_update)(struct kvm *kvm, int isr);
+ void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
+ void (*set_virtual_x2apic_mode)(struct kvm_vcpu *vcpu, bool set);
int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
int (*get_tdp_level)(void);
u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio);
@@ -991,6 +998,7 @@ int kvm_age_hva(struct kvm *kvm, unsigned long hva);
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
int cpuid_maxphyaddr(struct kvm_vcpu *vcpu);
+int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v);
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h
index 5ed1f16187be..695399f2d5eb 100644
--- a/arch/x86/include/asm/kvm_para.h
+++ b/arch/x86/include/asm/kvm_para.h
@@ -27,7 +27,7 @@ static inline bool kvm_check_and_clear_guest_paused(void)
*
* Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively.
* The hypercall number should be placed in rax and the return value will be
- * placed in rax. No other registers will be clobbered unless explicited
+ * placed in rax. No other registers will be clobbered unless explicitly
* noted by the particular hypercall.
*/
@@ -85,13 +85,13 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
return ret;
}
-static inline int kvm_para_available(void)
+static inline bool kvm_para_available(void)
{
unsigned int eax, ebx, ecx, edx;
char signature[13];
if (boot_cpu_data.cpuid_level < 0)
- return 0; /* So we don't blow up on old processors */
+ return false; /* So we don't blow up on old processors */
if (cpu_has_hypervisor) {
cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
@@ -101,10 +101,10 @@ static inline int kvm_para_available(void)
signature[12] = 0;
if (strcmp(signature, "KVMKVMKVM") == 0)
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static inline unsigned int kvm_arch_para_features(void)
diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h
index 48142971b25d..79327e9483a3 100644
--- a/arch/x86/include/asm/linkage.h
+++ b/arch/x86/include/asm/linkage.h
@@ -27,20 +27,20 @@
#define __asmlinkage_protect0(ret) \
__asmlinkage_protect_n(ret)
#define __asmlinkage_protect1(ret, arg1) \
- __asmlinkage_protect_n(ret, "g" (arg1))
+ __asmlinkage_protect_n(ret, "m" (arg1))
#define __asmlinkage_protect2(ret, arg1, arg2) \
- __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2))
+ __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2))
#define __asmlinkage_protect3(ret, arg1, arg2, arg3) \
- __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3))
+ __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3))
#define __asmlinkage_protect4(ret, arg1, arg2, arg3, arg4) \
- __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \
- "g" (arg4))
+ __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \
+ "m" (arg4))
#define __asmlinkage_protect5(ret, arg1, arg2, arg3, arg4, arg5) \
- __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \
- "g" (arg4), "g" (arg5))
+ __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \
+ "m" (arg4), "m" (arg5))
#define __asmlinkage_protect6(ret, arg1, arg2, arg3, arg4, arg5, arg6) \
- __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \
- "g" (arg4), "g" (arg5), "g" (arg6))
+ __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \
+ "m" (arg4), "m" (arg5), "m" (arg6))
#endif /* CONFIG_X86_32 */
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index ecdfee60ee4a..f4076af1f4ed 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -3,6 +3,90 @@
#include <uapi/asm/mce.h>
+/*
+ * Machine Check support for x86
+ */
+
+/* MCG_CAP register defines */
+#define MCG_BANKCNT_MASK 0xff /* Number of Banks */
+#define MCG_CTL_P (1ULL<<8) /* MCG_CTL register available */
+#define MCG_EXT_P (1ULL<<9) /* Extended registers available */
+#define MCG_CMCI_P (1ULL<<10) /* CMCI supported */
+#define MCG_EXT_CNT_MASK 0xff0000 /* Number of Extended registers */
+#define MCG_EXT_CNT_SHIFT 16
+#define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT)
+#define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */
+
+/* MCG_STATUS register defines */
+#define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */
+#define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */
+#define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */
+
+/* MCi_STATUS register defines */
+#define MCI_STATUS_VAL (1ULL<<63) /* valid error */
+#define MCI_STATUS_OVER (1ULL<<62) /* previous errors lost */
+#define MCI_STATUS_UC (1ULL<<61) /* uncorrected error */
+#define MCI_STATUS_EN (1ULL<<60) /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */
+#define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */
+#define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */
+#define MCI_STATUS_AR (1ULL<<55) /* Action required */
+#define MCACOD 0xffff /* MCA Error Code */
+
+/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */
+#define MCACOD_SCRUB 0x00C0 /* 0xC0-0xCF Memory Scrubbing */
+#define MCACOD_SCRUBMSK 0xfff0
+#define MCACOD_L3WB 0x017A /* L3 Explicit Writeback */
+#define MCACOD_DATA 0x0134 /* Data Load */
+#define MCACOD_INSTR 0x0150 /* Instruction Fetch */
+
+/* MCi_MISC register defines */
+#define MCI_MISC_ADDR_LSB(m) ((m) & 0x3f)
+#define MCI_MISC_ADDR_MODE(m) (((m) >> 6) & 7)
+#define MCI_MISC_ADDR_SEGOFF 0 /* segment offset */
+#define MCI_MISC_ADDR_LINEAR 1 /* linear address */
+#define MCI_MISC_ADDR_PHYS 2 /* physical address */
+#define MCI_MISC_ADDR_MEM 3 /* memory address */
+#define MCI_MISC_ADDR_GENERIC 7 /* generic */
+
+/* CTL2 register defines */
+#define MCI_CTL2_CMCI_EN (1ULL << 30)
+#define MCI_CTL2_CMCI_THRESHOLD_MASK 0x7fffULL
+
+#define MCJ_CTX_MASK 3
+#define MCJ_CTX(flags) ((flags) & MCJ_CTX_MASK)
+#define MCJ_CTX_RANDOM 0 /* inject context: random */
+#define MCJ_CTX_PROCESS 0x1 /* inject context: process */
+#define MCJ_CTX_IRQ 0x2 /* inject context: IRQ */
+#define MCJ_NMI_BROADCAST 0x4 /* do NMI broadcasting */
+#define MCJ_EXCEPTION 0x8 /* raise as exception */
+#define MCJ_IRQ_BRAODCAST 0x10 /* do IRQ broadcasting */
+
+#define MCE_OVERFLOW 0 /* bit 0 in flags means overflow */
+
+/* Software defined banks */
+#define MCE_EXTENDED_BANK 128
+#define MCE_THERMAL_BANK (MCE_EXTENDED_BANK + 0)
+#define K8_MCE_THRESHOLD_BASE (MCE_EXTENDED_BANK + 1)
+
+#define MCE_LOG_LEN 32
+#define MCE_LOG_SIGNATURE "MACHINECHECK"
+
+/*
+ * This structure contains all data related to the MCE log. Also
+ * carries a signature to make it easier to find from external
+ * debugging tools. Each entry is only valid when its finished flag
+ * is set.
+ */
+struct mce_log {
+ char signature[12]; /* "MACHINECHECK" */
+ unsigned len; /* = MCE_LOG_LEN */
+ unsigned next;
+ unsigned flags;
+ unsigned recordlen; /* length of struct mce */
+ struct mce entry[MCE_LOG_LEN];
+};
struct mca_config {
bool dont_log_ce;
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index 43d921b4752c..6825e2efd1b4 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -57,4 +57,18 @@ static inline struct microcode_ops * __init init_amd_microcode(void)
static inline void __exit exit_amd_microcode(void) {}
#endif
+#ifdef CONFIG_MICROCODE_EARLY
+#define MAX_UCODE_COUNT 128
+extern void __init load_ucode_bsp(void);
+extern __init void load_ucode_ap(void);
+extern int __init save_microcode_in_initrd(void);
+#else
+static inline void __init load_ucode_bsp(void) {}
+static inline __init void load_ucode_ap(void) {}
+static inline int __init save_microcode_in_initrd(void)
+{
+ return 0;
+}
+#endif
+
#endif /* _ASM_X86_MICROCODE_H */
diff --git a/arch/x86/include/asm/microcode_intel.h b/arch/x86/include/asm/microcode_intel.h
new file mode 100644
index 000000000000..5356f927d411
--- /dev/null
+++ b/arch/x86/include/asm/microcode_intel.h
@@ -0,0 +1,85 @@
+#ifndef _ASM_X86_MICROCODE_INTEL_H
+#define _ASM_X86_MICROCODE_INTEL_H
+
+#include <asm/microcode.h>
+
+struct microcode_header_intel {
+ unsigned int hdrver;
+ unsigned int rev;
+ unsigned int date;
+ unsigned int sig;
+ unsigned int cksum;
+ unsigned int ldrver;
+ unsigned int pf;
+ unsigned int datasize;
+ unsigned int totalsize;
+ unsigned int reserved[3];
+};
+
+struct microcode_intel {
+ struct microcode_header_intel hdr;
+ unsigned int bits[0];
+};
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+ unsigned int sig;
+ unsigned int pf;
+ unsigned int cksum;
+};
+
+struct extended_sigtable {
+ unsigned int count;
+ unsigned int cksum;
+ unsigned int reserved[3];
+ struct extended_signature sigs[0];
+};
+
+#define DEFAULT_UCODE_DATASIZE (2000)
+#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable))
+#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature))
+#define DWSIZE (sizeof(u32))
+
+#define get_totalsize(mc) \
+ (((struct microcode_intel *)mc)->hdr.totalsize ? \
+ ((struct microcode_intel *)mc)->hdr.totalsize : \
+ DEFAULT_UCODE_TOTALSIZE)
+
+#define get_datasize(mc) \
+ (((struct microcode_intel *)mc)->hdr.datasize ? \
+ ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
+
+#define sigmatch(s1, s2, p1, p2) \
+ (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
+
+#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
+
+extern int
+get_matching_microcode(unsigned int csig, int cpf, void *mc, int rev);
+extern int microcode_sanity_check(void *mc, int print_err);
+extern int get_matching_sig(unsigned int csig, int cpf, void *mc, int rev);
+extern int
+update_match_revision(struct microcode_header_intel *mc_header, int rev);
+
+#ifdef CONFIG_MICROCODE_INTEL_EARLY
+extern void __init load_ucode_intel_bsp(void);
+extern void __cpuinit load_ucode_intel_ap(void);
+extern void show_ucode_info_early(void);
+#else
+static inline __init void load_ucode_intel_bsp(void) {}
+static inline __cpuinit void load_ucode_intel_ap(void) {}
+static inline void show_ucode_info_early(void) {}
+#endif
+
+#if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU)
+extern int save_mc_for_early(u8 *mc);
+#else
+static inline int save_mc_for_early(u8 *mc)
+{
+ return 0;
+}
+#endif
+
+#endif /* _ASM_X86_MICROCODE_INTEL_H */
diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h
index eb05fb3b02fb..8a9b3e288cb4 100644
--- a/arch/x86/include/asm/mmzone_32.h
+++ b/arch/x86/include/asm/mmzone_32.h
@@ -14,12 +14,6 @@ extern struct pglist_data *node_data[];
#include <asm/numaq.h>
-extern void resume_map_numa_kva(pgd_t *pgd);
-
-#else /* !CONFIG_NUMA */
-
-static inline void resume_map_numa_kva(pgd_t *pgd) {}
-
#endif /* CONFIG_NUMA */
#ifdef CONFIG_DISCONTIGMEM
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
index 79ce5685ab64..c2934be2446a 100644
--- a/arch/x86/include/asm/mshyperv.h
+++ b/arch/x86/include/asm/mshyperv.h
@@ -11,4 +11,8 @@ struct ms_hyperv_info {
extern struct ms_hyperv_info ms_hyperv;
+void hyperv_callback_vector(void);
+void hyperv_vector_handler(struct pt_regs *regs);
+void hv_register_vmbus_handler(int irq, irq_handler_t handler);
+
#endif
diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h
index bcdff997668c..2f366d0ac6b4 100644
--- a/arch/x86/include/asm/mwait.h
+++ b/arch/x86/include/asm/mwait.h
@@ -4,7 +4,8 @@
#define MWAIT_SUBSTATE_MASK 0xf
#define MWAIT_CSTATE_MASK 0xf
#define MWAIT_SUBSTATE_SIZE 4
-#define MWAIT_MAX_NUM_CSTATES 8
+#define MWAIT_HINT2CSTATE(hint) (((hint) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK)
+#define MWAIT_HINT2SUBSTATE(hint) ((hint) & MWAIT_CSTATE_MASK)
#define CPUID_MWAIT_LEAF 5
#define CPUID5_ECX_EXTENSIONS_SUPPORTED 0x1
diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h
index 49119fcea2dc..1b99ee5c9f00 100644
--- a/arch/x86/include/asm/numa.h
+++ b/arch/x86/include/asm/numa.h
@@ -54,13 +54,11 @@ static inline int numa_cpu_node(int cpu)
#ifdef CONFIG_X86_32
# include <asm/numa_32.h>
-#else
-# include <asm/numa_64.h>
#endif
#ifdef CONFIG_NUMA
-extern void __cpuinit numa_set_node(int cpu, int node);
-extern void __cpuinit numa_clear_node(int cpu);
+extern void numa_set_node(int cpu, int node);
+extern void numa_clear_node(int cpu);
extern void __init init_cpu_to_node(void);
extern void __cpuinit numa_add_cpu(int cpu);
extern void __cpuinit numa_remove_cpu(int cpu);
diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h
deleted file mode 100644
index 0c05f7ae46e8..000000000000
--- a/arch/x86/include/asm/numa_64.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_X86_NUMA_64_H
-#define _ASM_X86_NUMA_64_H
-
-extern unsigned long numa_free_all_bootmem(void);
-
-#endif /* _ASM_X86_NUMA_64_H */
diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h
index 8ca82839288a..c87892442e53 100644
--- a/arch/x86/include/asm/page.h
+++ b/arch/x86/include/asm/page.h
@@ -17,6 +17,10 @@
struct page;
+#include <linux/range.h>
+extern struct range pfn_mapped[];
+extern int nr_pfn_mapped;
+
static inline void clear_user_page(void *page, unsigned long vaddr,
struct page *pg)
{
@@ -44,7 +48,8 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
* case properly. Once all supported versions of gcc understand it, we can
* remove this Voodoo magic stuff. (i.e. once gcc3.x is deprecated)
*/
-#define __pa_symbol(x) __pa(__phys_reloc_hide((unsigned long)(x)))
+#define __pa_symbol(x) \
+ __phys_addr_symbol(__phys_reloc_hide((unsigned long)(x)))
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
diff --git a/arch/x86/include/asm/page_32.h b/arch/x86/include/asm/page_32.h
index da4e762406f7..4d550d04b609 100644
--- a/arch/x86/include/asm/page_32.h
+++ b/arch/x86/include/asm/page_32.h
@@ -15,6 +15,7 @@ extern unsigned long __phys_addr(unsigned long);
#else
#define __phys_addr(x) __phys_addr_nodebug(x)
#endif
+#define __phys_addr_symbol(x) __phys_addr(x)
#define __phys_reloc_hide(x) RELOC_HIDE((x), 0)
#ifdef CONFIG_FLATMEM
diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h
index 072694ed81a5..0f1ddee6a0ce 100644
--- a/arch/x86/include/asm/page_64.h
+++ b/arch/x86/include/asm/page_64.h
@@ -3,4 +3,40 @@
#include <asm/page_64_types.h>
+#ifndef __ASSEMBLY__
+
+/* duplicated to the one in bootmem.h */
+extern unsigned long max_pfn;
+extern unsigned long phys_base;
+
+static inline unsigned long __phys_addr_nodebug(unsigned long x)
+{
+ unsigned long y = x - __START_KERNEL_map;
+
+ /* use the carry flag to determine if x was < __START_KERNEL_map */
+ x = y + ((x > y) ? phys_base : (__START_KERNEL_map - PAGE_OFFSET));
+
+ return x;
+}
+
+#ifdef CONFIG_DEBUG_VIRTUAL
+extern unsigned long __phys_addr(unsigned long);
+extern unsigned long __phys_addr_symbol(unsigned long);
+#else
+#define __phys_addr(x) __phys_addr_nodebug(x)
+#define __phys_addr_symbol(x) \
+ ((unsigned long)(x) - __START_KERNEL_map + phys_base)
+#endif
+
+#define __phys_reloc_hide(x) (x)
+
+#ifdef CONFIG_FLATMEM
+#define pfn_valid(pfn) ((pfn) < max_pfn)
+#endif
+
+void clear_page(void *page);
+void copy_page(void *to, void *from);
+
+#endif /* !__ASSEMBLY__ */
+
#endif /* _ASM_X86_PAGE_64_H */
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
index 320f7bb95f76..8b491e66eaa8 100644
--- a/arch/x86/include/asm/page_64_types.h
+++ b/arch/x86/include/asm/page_64_types.h
@@ -50,26 +50,4 @@
#define KERNEL_IMAGE_SIZE (512 * 1024 * 1024)
#define KERNEL_IMAGE_START _AC(0xffffffff80000000, UL)
-#ifndef __ASSEMBLY__
-void clear_page(void *page);
-void copy_page(void *to, void *from);
-
-/* duplicated to the one in bootmem.h */
-extern unsigned long max_pfn;
-extern unsigned long phys_base;
-
-extern unsigned long __phys_addr(unsigned long);
-#define __phys_reloc_hide(x) (x)
-
-#define vmemmap ((struct page *)VMEMMAP_START)
-
-extern void init_extra_mapping_uc(unsigned long phys, unsigned long size);
-extern void init_extra_mapping_wb(unsigned long phys, unsigned long size);
-
-#endif /* !__ASSEMBLY__ */
-
-#ifdef CONFIG_FLATMEM
-#define pfn_valid(pfn) ((pfn) < max_pfn)
-#endif
-
#endif /* _ASM_X86_PAGE_64_DEFS_H */
diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
index e21fdd10479f..54c97879195e 100644
--- a/arch/x86/include/asm/page_types.h
+++ b/arch/x86/include/asm/page_types.h
@@ -51,6 +51,8 @@ static inline phys_addr_t get_max_mapped(void)
return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT;
}
+bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn);
+
extern unsigned long init_memory_mapping(unsigned long start,
unsigned long end);
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index dba7805176bf..c28fd02f4bf7 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -121,9 +121,12 @@ static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq)
#define arch_teardown_msi_irq x86_teardown_msi_irq
#define arch_restore_msi_irqs x86_restore_msi_irqs
/* implemented in arch/x86/kernel/apic/io_apic. */
+struct msi_desc;
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
void native_teardown_msi_irq(unsigned int irq);
void native_restore_msi_irqs(struct pci_dev *dev, int irq);
+int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
+ unsigned int irq_base, unsigned int irq_offset);
/* default to the implementation in drivers/lib/msi.c */
#define HAVE_DEFAULT_MSI_TEARDOWN_IRQS
#define HAVE_DEFAULT_MSI_RESTORE_IRQS
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 4fabcdf1cfa7..57cb63402213 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -29,8 +29,13 @@
#define ARCH_PERFMON_EVENTSEL_INV (1ULL << 23)
#define ARCH_PERFMON_EVENTSEL_CMASK 0xFF000000ULL
-#define AMD_PERFMON_EVENTSEL_GUESTONLY (1ULL << 40)
-#define AMD_PERFMON_EVENTSEL_HOSTONLY (1ULL << 41)
+#define AMD64_EVENTSEL_INT_CORE_ENABLE (1ULL << 36)
+#define AMD64_EVENTSEL_GUESTONLY (1ULL << 40)
+#define AMD64_EVENTSEL_HOSTONLY (1ULL << 41)
+
+#define AMD64_EVENTSEL_INT_CORE_SEL_SHIFT 37
+#define AMD64_EVENTSEL_INT_CORE_SEL_MASK \
+ (0xFULL << AMD64_EVENTSEL_INT_CORE_SEL_SHIFT)
#define AMD64_EVENTSEL_EVENT \
(ARCH_PERFMON_EVENTSEL_EVENT | (0x0FULL << 32))
@@ -46,8 +51,12 @@
#define AMD64_RAW_EVENT_MASK \
(X86_RAW_EVENT_MASK | \
AMD64_EVENTSEL_EVENT)
+#define AMD64_RAW_EVENT_MASK_NB \
+ (AMD64_EVENTSEL_EVENT | \
+ ARCH_PERFMON_EVENTSEL_UMASK)
#define AMD64_NUM_COUNTERS 4
#define AMD64_NUM_COUNTERS_CORE 6
+#define AMD64_NUM_COUNTERS_NB 4
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8)
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 5199db2923d3..1e672234c4ff 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -142,6 +142,11 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT;
}
+static inline unsigned long pud_pfn(pud_t pud)
+{
+ return (pud_val(pud) & PTE_PFN_MASK) >> PAGE_SHIFT;
+}
+
#define pte_page(pte) pfn_to_page(pte_pfn(pte))
static inline int pmd_large(pmd_t pte)
@@ -390,6 +395,7 @@ pte_t *populate_extra_pte(unsigned long vaddr);
#ifndef __ASSEMBLY__
#include <linux/mm_types.h>
+#include <linux/log2.h>
static inline int pte_none(pte_t pte)
{
@@ -615,6 +621,8 @@ static inline int pgd_none(pgd_t pgd)
#ifndef __ASSEMBLY__
extern int direct_gbpages;
+void init_mem_mapping(void);
+void early_alloc_pgt_buf(void);
/* local pte updates need not use xchg for locking */
static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
@@ -781,6 +789,32 @@ static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
memcpy(dst, src, count * sizeof(pgd_t));
}
+#define PTE_SHIFT ilog2(PTRS_PER_PTE)
+static inline int page_level_shift(enum pg_level level)
+{
+ return (PAGE_SHIFT - PTE_SHIFT) + level * PTE_SHIFT;
+}
+static inline unsigned long page_level_size(enum pg_level level)
+{
+ return 1UL << page_level_shift(level);
+}
+static inline unsigned long page_level_mask(enum pg_level level)
+{
+ return ~(page_level_size(level) - 1);
+}
+
+/*
+ * The x86 doesn't have any external MMU info: the kernel page
+ * tables contain all the necessary information.
+ */
+static inline void update_mmu_cache(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+}
+static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
+ unsigned long addr, pmd_t *pmd)
+{
+}
#include <asm-generic/pgtable.h>
#endif /* __ASSEMBLY__ */
diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h
index 8faa215a503e..9ee322103c6d 100644
--- a/arch/x86/include/asm/pgtable_32.h
+++ b/arch/x86/include/asm/pgtable_32.h
@@ -66,13 +66,6 @@ do { \
__flush_tlb_one((vaddr)); \
} while (0)
-/*
- * The i386 doesn't have any external MMU info: the kernel page
- * tables contain all the necessary information.
- */
-#define update_mmu_cache(vma, address, ptep) do { } while (0)
-#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
-
#endif /* !__ASSEMBLY__ */
/*
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
index 47356f9df82e..e22c1dbf7feb 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -142,9 +142,6 @@ static inline int pgd_large(pgd_t pgd) { return 0; }
#define pte_offset_map(dir, address) pte_offset_kernel((dir), (address))
#define pte_unmap(pte) ((void)(pte))/* NOP */
-#define update_mmu_cache(vma, address, ptep) do { } while (0)
-#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
-
/* Encode and de-code a swap entry */
#if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE
#define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1)
@@ -183,6 +180,11 @@ extern void cleanup_highmap(void);
#define __HAVE_ARCH_PTE_SAME
+#define vmemmap ((struct page *)VMEMMAP_START)
+
+extern void init_extra_mapping_uc(unsigned long phys, unsigned long size);
+extern void init_extra_mapping_wb(unsigned long phys, unsigned long size);
+
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_X86_PGTABLE_64_H */
diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h
index 766ea16fbbbd..2d883440cb9a 100644
--- a/arch/x86/include/asm/pgtable_64_types.h
+++ b/arch/x86/include/asm/pgtable_64_types.h
@@ -1,6 +1,8 @@
#ifndef _ASM_X86_PGTABLE_64_DEFS_H
#define _ASM_X86_PGTABLE_64_DEFS_H
+#include <asm/sparsemem.h>
+
#ifndef __ASSEMBLY__
#include <linux/types.h>
@@ -60,4 +62,6 @@ typedef struct { pteval_t pte; } pte_t;
#define MODULES_END _AC(0xffffffffff000000, UL)
#define MODULES_LEN (MODULES_END - MODULES_VADDR)
+#define EARLY_DYNAMIC_PAGE_TABLES 64
+
#endif /* _ASM_X86_PGTABLE_64_DEFS_H */
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 3c32db8c539d..567b5d0632b2 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -321,7 +321,6 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
/* Install a pte for a particular vaddr in kernel space. */
void set_pte_vaddr(unsigned long vaddr, pte_t pte);
-extern void native_pagetable_reserve(u64 start, u64 end);
#ifdef CONFIG_X86_32
extern void native_pagetable_init(void);
#else
@@ -331,7 +330,7 @@ extern void native_pagetable_init(void);
struct seq_file;
extern void arch_report_meminfo(struct seq_file *m);
-enum {
+enum pg_level {
PG_LEVEL_NONE,
PG_LEVEL_4K,
PG_LEVEL_2M,
@@ -352,6 +351,8 @@ static inline void update_page_count(int level, unsigned long pages) { }
* as a pte too.
*/
extern pte_t *lookup_address(unsigned long address, unsigned int *level);
+extern int __split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase);
+extern phys_addr_t slow_virt_to_phys(void *__address);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 888184b2fc85..3270116b1488 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -89,7 +89,6 @@ struct cpuinfo_x86 {
char wp_works_ok; /* It doesn't on 386's */
/* Problems on some 486Dx4's and old 386's: */
- char hlt_works_ok;
char hard_math;
char rfu;
char fdiv_bug;
@@ -165,15 +164,6 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
extern const struct seq_operations cpuinfo_op;
-static inline int hlt_works(int cpu)
-{
-#ifdef CONFIG_X86_32
- return cpu_data(cpu).hlt_works_ok;
-#else
- return 1;
-#endif
-}
-
#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
extern void cpu_detect(struct cpuinfo_x86 *c);
@@ -190,6 +180,14 @@ extern void init_amd_cacheinfo(struct cpuinfo_x86 *c);
extern void detect_extended_topology(struct cpuinfo_x86 *c);
extern void detect_ht(struct cpuinfo_x86 *c);
+#ifdef CONFIG_X86_32
+extern int have_cpuid_p(void);
+#else
+static inline int have_cpuid_p(void)
+{
+ return 1;
+}
+#endif
static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
@@ -725,12 +723,13 @@ extern unsigned long boot_option_idle_override;
extern bool amd_e400_c1e_detected;
enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_NOMWAIT,
- IDLE_POLL, IDLE_FORCE_MWAIT};
+ IDLE_POLL};
extern void enable_sep_cpu(void);
extern int sysenter_setup(void);
extern void early_trap_init(void);
+void early_trap_pf_init(void);
/* Defined in head.S */
extern struct desc_ptr early_gdt_descr;
@@ -943,7 +942,7 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip,
extern int get_tsc_mode(unsigned long adr);
extern int set_tsc_mode(unsigned int val);
-extern int amd_get_nb_id(int cpu);
+extern u16 amd_get_nb_id(int cpu);
struct aperfmperf {
u64 aperf, mperf;
@@ -998,7 +997,11 @@ extern unsigned long arch_align_stack(unsigned long sp);
extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
void default_idle(void);
-bool set_pm_idle_to_default(void);
+#ifdef CONFIG_XEN
+bool xen_set_default_idle(void);
+#else
+#define xen_set_default_idle 0
+#endif
void stop_this_cpu(void *dummy);
diff --git a/arch/x86/include/asm/proto.h b/arch/x86/include/asm/proto.h
index 6f414ed88620..6fd3fd769796 100644
--- a/arch/x86/include/asm/proto.h
+++ b/arch/x86/include/asm/proto.h
@@ -5,8 +5,6 @@
/* misc architecture specific prototypes */
-void early_idt_handler(void);
-
void system_call(void);
void syscall_init(void);
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index fe1ec5bcd846..9c6b890d5e7a 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -58,6 +58,7 @@ extern unsigned char boot_gdt[];
extern unsigned char secondary_startup_64[];
#endif
-extern void __init setup_real_mode(void);
+void reserve_real_mode(void);
+void setup_real_mode(void);
#endif /* _ARCH_X86_REALMODE_H */
diff --git a/arch/x86/include/asm/required-features.h b/arch/x86/include/asm/required-features.h
index 6c7fc25f2c34..5c6e4fb370f5 100644
--- a/arch/x86/include/asm/required-features.h
+++ b/arch/x86/include/asm/required-features.h
@@ -47,6 +47,12 @@
# define NEED_NOPL 0
#endif
+#ifdef CONFIG_MATOM
+# define NEED_MOVBE (1<<(X86_FEATURE_MOVBE & 31))
+#else
+# define NEED_MOVBE 0
+#endif
+
#ifdef CONFIG_X86_64
#ifdef CONFIG_PARAVIRT
/* Paravirtualized systems may not have PSE or PGE available */
@@ -80,7 +86,7 @@
#define REQUIRED_MASK2 0
#define REQUIRED_MASK3 (NEED_NOPL)
-#define REQUIRED_MASK4 0
+#define REQUIRED_MASK4 (NEED_MOVBE)
#define REQUIRED_MASK5 0
#define REQUIRED_MASK6 0
#define REQUIRED_MASK7 0
diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
index 216bf364a7e7..35e67a457182 100644
--- a/arch/x86/include/asm/signal.h
+++ b/arch/x86/include/asm/signal.h
@@ -31,27 +31,9 @@ typedef sigset_t compat_sigset_t;
#include <uapi/asm/signal.h>
#ifndef __ASSEMBLY__
extern void do_notify_resume(struct pt_regs *, void *, __u32);
-#ifdef __i386__
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
-};
-
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
-#else /* __i386__ */
-#endif /* !__i386__ */
+#define __ARCH_HAS_SA_RESTORER
+
#include <asm/sigcontext.h>
#ifdef __i386__
diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h
index 31f61f96e0fb..0218d917f509 100644
--- a/arch/x86/include/asm/sys_ia32.h
+++ b/arch/x86/include/asm/sys_ia32.h
@@ -32,22 +32,11 @@ struct mmap_arg_struct32;
asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *);
asmlinkage long sys32_mprotect(unsigned long, size_t, unsigned long);
-struct sigaction32;
-struct old_sigaction32;
-asmlinkage long sys32_rt_sigaction(int, struct sigaction32 __user *,
- struct sigaction32 __user *, unsigned int);
-asmlinkage long sys32_sigaction(int, struct old_sigaction32 __user *,
- struct old_sigaction32 __user *);
asmlinkage long sys32_alarm(unsigned int);
asmlinkage long sys32_waitpid(compat_pid_t, unsigned int __user *, int);
asmlinkage long sys32_sysfs(int, u32, u32);
-asmlinkage long sys32_sched_rr_get_interval(compat_pid_t,
- struct compat_timespec __user *);
-asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *, compat_size_t);
-asmlinkage long sys32_rt_sigqueueinfo(int, int, compat_siginfo_t __user *);
-
asmlinkage long sys32_pread(unsigned int, char __user *, u32, u32, u32);
asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32);
@@ -68,9 +57,8 @@ asmlinkage long sys32_fallocate(int, int, unsigned,
unsigned, unsigned, unsigned);
/* ia32/ia32_signal.c */
-asmlinkage long sys32_sigsuspend(int, int, old_sigset_t);
-asmlinkage long sys32_sigreturn(struct pt_regs *);
-asmlinkage long sys32_rt_sigreturn(struct pt_regs *);
+asmlinkage long sys32_sigreturn(void);
+asmlinkage long sys32_rt_sigreturn(void);
/* ia32/ipc32.c */
asmlinkage long sys32_ipc(u32, int, int, int, compat_uptr_t, u32);
diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h
index 58b7e3eac0ae..6cf0a9cc60cd 100644
--- a/arch/x86/include/asm/syscalls.h
+++ b/arch/x86/include/asm/syscalls.h
@@ -18,13 +18,13 @@
/* Common in X86_32 and X86_64 */
/* kernel/ioport.c */
asmlinkage long sys_ioperm(unsigned long, unsigned long, int);
-long sys_iopl(unsigned int, struct pt_regs *);
+asmlinkage long sys_iopl(unsigned int);
/* kernel/ldt.c */
asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
/* kernel/signal.c */
-long sys_rt_sigreturn(struct pt_regs *);
+long sys_rt_sigreturn(void);
/* kernel/tls.c */
asmlinkage int sys_set_thread_area(struct user_desc __user *);
@@ -34,14 +34,11 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *);
#ifdef CONFIG_X86_32
/* kernel/signal.c */
-asmlinkage int sys_sigsuspend(int, int, old_sigset_t);
-asmlinkage int sys_sigaction(int, const struct old_sigaction __user *,
- struct old_sigaction __user *);
-unsigned long sys_sigreturn(struct pt_regs *);
+unsigned long sys_sigreturn(void);
/* kernel/vm86_32.c */
-int sys_vm86old(struct vm86_struct __user *, struct pt_regs *);
-int sys_vm86(unsigned long, unsigned long, struct pt_regs *);
+int sys_vm86old(struct vm86_struct __user *);
+int sys_vm86(unsigned long, unsigned long);
#else /* CONFIG_X86_32 */
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index 0fee48e279cc..50a7fc0f824a 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -20,10 +20,20 @@ static inline void __native_flush_tlb(void)
native_write_cr3(native_read_cr3());
}
+static inline void __native_flush_tlb_global_irq_disabled(void)
+{
+ unsigned long cr4;
+
+ cr4 = native_read_cr4();
+ /* clear PGE */
+ native_write_cr4(cr4 & ~X86_CR4_PGE);
+ /* write old PGE again and flush TLBs */
+ native_write_cr4(cr4);
+}
+
static inline void __native_flush_tlb_global(void)
{
unsigned long flags;
- unsigned long cr4;
/*
* Read-modify-write to CR4 - protect it from preemption and
@@ -32,11 +42,7 @@ static inline void __native_flush_tlb_global(void)
*/
raw_local_irq_save(flags);
- cr4 = native_read_cr4();
- /* clear PGE */
- native_write_cr4(cr4 & ~X86_CR4_PGE);
- /* write old PGE again and flush TLBs */
- native_write_cr4(cr4);
+ __native_flush_tlb_global_irq_disabled();
raw_local_irq_restore(flags);
}
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 1709801d18ec..5ee26875baea 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -125,13 +125,12 @@ extern int __get_user_4(void);
extern int __get_user_8(void);
extern int __get_user_bad(void);
-#define __get_user_x(size, ret, x, ptr) \
- asm volatile("call __get_user_" #size \
- : "=a" (ret), "=d" (x) \
- : "0" (ptr)) \
-
-/* Careful: we have to cast the result to the type of the pointer
- * for sign reasons */
+/*
+ * This is a type: either unsigned long, if the argument fits into
+ * that type, or otherwise unsigned long long.
+ */
+#define __inttype(x) \
+__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
/**
* get_user: - Get a simple variable from user space.
@@ -150,38 +149,26 @@ extern int __get_user_bad(void);
* Returns zero on success, or -EFAULT on error.
* On error, the variable @x is set to zero.
*/
-#ifdef CONFIG_X86_32
-#define __get_user_8(__ret_gu, __val_gu, ptr) \
- __get_user_x(X, __ret_gu, __val_gu, ptr)
-#else
-#define __get_user_8(__ret_gu, __val_gu, ptr) \
- __get_user_x(8, __ret_gu, __val_gu, ptr)
-#endif
-
+/*
+ * Careful: we have to cast the result to the type of the pointer
+ * for sign reasons.
+ *
+ * The use of %edx as the register specifier is a bit of a
+ * simplification, as gcc only cares about it as the starting point
+ * and not size: for a 64-bit value it will use %ecx:%edx on 32 bits
+ * (%ecx being the next register in gcc's x86 register sequence), and
+ * %rdx on 64 bits.
+ */
#define get_user(x, ptr) \
({ \
int __ret_gu; \
- unsigned long __val_gu; \
+ register __inttype(*(ptr)) __val_gu asm("%edx"); \
__chk_user_ptr(ptr); \
might_fault(); \
- switch (sizeof(*(ptr))) { \
- case 1: \
- __get_user_x(1, __ret_gu, __val_gu, ptr); \
- break; \
- case 2: \
- __get_user_x(2, __ret_gu, __val_gu, ptr); \
- break; \
- case 4: \
- __get_user_x(4, __ret_gu, __val_gu, ptr); \
- break; \
- case 8: \
- __get_user_8(__ret_gu, __val_gu, ptr); \
- break; \
- default: \
- __get_user_x(X, __ret_gu, __val_gu, ptr); \
- break; \
- } \
- (x) = (__typeof__(*(ptr)))__val_gu; \
+ asm volatile("call __get_user_%P3" \
+ : "=a" (__ret_gu), "=r" (__val_gu) \
+ : "0" (ptr), "i" (sizeof(*(ptr)))); \
+ (x) = (__typeof__(*(ptr))) __val_gu; \
__ret_gu; \
})
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h
index a0790e07ba65..3d5df1c4447f 100644
--- a/arch/x86/include/asm/unistd.h
+++ b/arch/x86/include/asm/unistd.h
@@ -38,8 +38,6 @@
# define __ARCH_WANT_SYS_OLD_GETRLIMIT
# define __ARCH_WANT_SYS_OLD_UNAME
# define __ARCH_WANT_SYS_PAUSE
-# define __ARCH_WANT_SYS_RT_SIGACTION
-# define __ARCH_WANT_SYS_RT_SIGSUSPEND
# define __ARCH_WANT_SYS_SGETMASK
# define __ARCH_WANT_SYS_SIGNAL
# define __ARCH_WANT_SYS_SIGPENDING
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
index 21f7385badb8..2c32df95bb78 100644
--- a/arch/x86/include/asm/uv/uv_hub.h
+++ b/arch/x86/include/asm/uv/uv_hub.h
@@ -5,7 +5,7 @@
*
* SGI UV architectural definitions
*
- * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_X86_UV_UV_HUB_H
@@ -175,6 +175,7 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
*/
#define UV1_HUB_REVISION_BASE 1
#define UV2_HUB_REVISION_BASE 3
+#define UV3_HUB_REVISION_BASE 5
static inline int is_uv1_hub(void)
{
@@ -183,6 +184,23 @@ static inline int is_uv1_hub(void)
static inline int is_uv2_hub(void)
{
+ return ((uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE) &&
+ (uv_hub_info->hub_revision < UV3_HUB_REVISION_BASE));
+}
+
+static inline int is_uv3_hub(void)
+{
+ return uv_hub_info->hub_revision >= UV3_HUB_REVISION_BASE;
+}
+
+static inline int is_uv_hub(void)
+{
+ return uv_hub_info->hub_revision;
+}
+
+/* code common to uv2 and uv3 only */
+static inline int is_uvx_hub(void)
+{
return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE;
}
@@ -230,14 +248,23 @@ union uvh_apicid {
#define UV2_LOCAL_MMR_SIZE (32UL * 1024 * 1024)
#define UV2_GLOBAL_MMR32_SIZE (32UL * 1024 * 1024)
-#define UV_LOCAL_MMR_BASE (is_uv1_hub() ? UV1_LOCAL_MMR_BASE \
- : UV2_LOCAL_MMR_BASE)
-#define UV_GLOBAL_MMR32_BASE (is_uv1_hub() ? UV1_GLOBAL_MMR32_BASE \
- : UV2_GLOBAL_MMR32_BASE)
-#define UV_LOCAL_MMR_SIZE (is_uv1_hub() ? UV1_LOCAL_MMR_SIZE : \
- UV2_LOCAL_MMR_SIZE)
+#define UV3_LOCAL_MMR_BASE 0xfa000000UL
+#define UV3_GLOBAL_MMR32_BASE 0xfc000000UL
+#define UV3_LOCAL_MMR_SIZE (32UL * 1024 * 1024)
+#define UV3_GLOBAL_MMR32_SIZE (32UL * 1024 * 1024)
+
+#define UV_LOCAL_MMR_BASE (is_uv1_hub() ? UV1_LOCAL_MMR_BASE : \
+ (is_uv2_hub() ? UV2_LOCAL_MMR_BASE : \
+ UV3_LOCAL_MMR_BASE))
+#define UV_GLOBAL_MMR32_BASE (is_uv1_hub() ? UV1_GLOBAL_MMR32_BASE :\
+ (is_uv2_hub() ? UV2_GLOBAL_MMR32_BASE :\
+ UV3_GLOBAL_MMR32_BASE))
+#define UV_LOCAL_MMR_SIZE (is_uv1_hub() ? UV1_LOCAL_MMR_SIZE : \
+ (is_uv2_hub() ? UV2_LOCAL_MMR_SIZE : \
+ UV3_LOCAL_MMR_SIZE))
#define UV_GLOBAL_MMR32_SIZE (is_uv1_hub() ? UV1_GLOBAL_MMR32_SIZE :\
- UV2_GLOBAL_MMR32_SIZE)
+ (is_uv2_hub() ? UV2_GLOBAL_MMR32_SIZE :\
+ UV3_GLOBAL_MMR32_SIZE))
#define UV_GLOBAL_MMR64_BASE (uv_hub_info->global_mmr_base)
#define UV_GLOBAL_GRU_MMR_BASE 0x4000000
@@ -599,6 +626,7 @@ static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
* 1 - UV1 rev 1.0 initial silicon
* 2 - UV1 rev 2.0 production silicon
* 3 - UV2 rev 1.0 initial silicon
+ * 5 - UV3 rev 1.0 initial silicon
*/
static inline int uv_get_min_hub_revision_id(void)
{
diff --git a/arch/x86/include/asm/uv/uv_mmrs.h b/arch/x86/include/asm/uv/uv_mmrs.h
index cf1d73643f60..bd5f80e58a23 100644
--- a/arch/x86/include/asm/uv/uv_mmrs.h
+++ b/arch/x86/include/asm/uv/uv_mmrs.h
@@ -5,16 +5,25 @@
*
* SGI UV MMR definitions
*
- * Copyright (C) 2007-2011 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_X86_UV_UV_MMRS_H
#define _ASM_X86_UV_UV_MMRS_H
/*
- * This file contains MMR definitions for both UV1 & UV2 hubs.
+ * This file contains MMR definitions for all UV hubs types.
*
- * In general, MMR addresses and structures are identical on both hubs.
+ * To minimize coding differences between hub types, the symbols are
+ * grouped by architecture types.
+ *
+ * UVH - definitions common to all UV hub types.
+ * UVXH - definitions common to all UV eXtended hub types (currently 2 & 3).
+ * UV1H - definitions specific to UV type 1 hub.
+ * UV2H - definitions specific to UV type 2 hub.
+ * UV3H - definitions specific to UV type 3 hub.
+ *
+ * So in general, MMR addresses and structures are identical on all hubs types.
* These MMRs are identified as:
* #define UVH_xxx <address>
* union uvh_xxx {
@@ -23,24 +32,36 @@
* } s;
* };
*
- * If the MMR exists on both hub type but has different addresses or
- * contents, the MMR definition is similar to:
- * #define UV1H_xxx <uv1 address>
- * #define UV2H_xxx <uv2address>
- * #define UVH_xxx (is_uv1_hub() ? UV1H_xxx : UV2H_xxx)
+ * If the MMR exists on all hub types but have different addresses:
+ * #define UV1Hxxx a
+ * #define UV2Hxxx b
+ * #define UV3Hxxx c
+ * #define UVHxxx (is_uv1_hub() ? UV1Hxxx :
+ * (is_uv2_hub() ? UV2Hxxx :
+ * UV3Hxxx))
+ *
+ * If the MMR exists on all hub types > 1 but have different addresses:
+ * #define UV2Hxxx b
+ * #define UV3Hxxx c
+ * #define UVXHxxx (is_uv2_hub() ? UV2Hxxx :
+ * UV3Hxxx))
+ *
* union uvh_xxx {
* unsigned long v;
- * struct uv1h_int_cmpd_s { (Common fields only)
+ * struct uvh_xxx_s { # Common fields only
* } s;
- * struct uv1h_int_cmpd_s { (Full UV1 definition)
+ * struct uv1h_xxx_s { # Full UV1 definition (*)
* } s1;
- * struct uv2h_int_cmpd_s { (Full UV2 definition)
+ * struct uv2h_xxx_s { # Full UV2 definition (*)
* } s2;
+ * struct uv3h_xxx_s { # Full UV3 definition (*)
+ * } s3;
* };
+ * (* - if present and different than the common struct)
*
- * Only essential difference are enumerated. For example, if the address is
- * the same for both UV1 & UV2, only a single #define is generated. Likewise,
- * if the contents is the same for both hubs, only the "s" structure is
+ * Only essential differences are enumerated. For example, if the address is
+ * the same for all UV's, only a single #define is generated. Likewise,
+ * if the contents is the same for all hubs, only the "s" structure is
* generated.
*
* If the MMR exists on ONLY 1 type of hub, no generic definition is
@@ -51,6 +72,8 @@
* struct uvh_int_cmpd_s {
* } sn;
* };
+ *
+ * (GEN Flags: mflags_opt= undefs=0 UV23=UVXH)
*/
#define UV_MMR_ENABLE (1UL << 63)
@@ -58,15 +81,18 @@
#define UV1_HUB_PART_NUMBER 0x88a5
#define UV2_HUB_PART_NUMBER 0x8eb8
#define UV2_HUB_PART_NUMBER_X 0x1111
+#define UV3_HUB_PART_NUMBER 0x9578
+#define UV3_HUB_PART_NUMBER_X 0x4321
-/* Compat: if this #define is present, UV headers support UV2 */
+/* Compat: Indicate which UV Hubs are supported. */
#define UV2_HUB_IS_SUPPORTED 1
+#define UV3_HUB_IS_SUPPORTED 1
/* ========================================================================= */
/* UVH_BAU_DATA_BROADCAST */
/* ========================================================================= */
-#define UVH_BAU_DATA_BROADCAST 0x61688UL
-#define UVH_BAU_DATA_BROADCAST_32 0x440
+#define UVH_BAU_DATA_BROADCAST 0x61688UL
+#define UVH_BAU_DATA_BROADCAST_32 0x440
#define UVH_BAU_DATA_BROADCAST_ENABLE_SHFT 0
#define UVH_BAU_DATA_BROADCAST_ENABLE_MASK 0x0000000000000001UL
@@ -82,8 +108,8 @@ union uvh_bau_data_broadcast_u {
/* ========================================================================= */
/* UVH_BAU_DATA_CONFIG */
/* ========================================================================= */
-#define UVH_BAU_DATA_CONFIG 0x61680UL
-#define UVH_BAU_DATA_CONFIG_32 0x438
+#define UVH_BAU_DATA_CONFIG 0x61680UL
+#define UVH_BAU_DATA_CONFIG_32 0x438
#define UVH_BAU_DATA_CONFIG_VECTOR_SHFT 0
#define UVH_BAU_DATA_CONFIG_DM_SHFT 8
@@ -121,10 +147,14 @@ union uvh_bau_data_config_u {
/* ========================================================================= */
/* UVH_EVENT_OCCURRED0 */
/* ========================================================================= */
-#define UVH_EVENT_OCCURRED0 0x70000UL
-#define UVH_EVENT_OCCURRED0_32 0x5e8
+#define UVH_EVENT_OCCURRED0 0x70000UL
+#define UVH_EVENT_OCCURRED0_32 0x5e8
+
+#define UVH_EVENT_OCCURRED0_LB_HCERR_SHFT 0
+#define UVH_EVENT_OCCURRED0_RH_AOERR0_SHFT 11
+#define UVH_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL
+#define UVH_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL
-#define UV1H_EVENT_OCCURRED0_LB_HCERR_SHFT 0
#define UV1H_EVENT_OCCURRED0_GR0_HCERR_SHFT 1
#define UV1H_EVENT_OCCURRED0_GR1_HCERR_SHFT 2
#define UV1H_EVENT_OCCURRED0_LH_HCERR_SHFT 3
@@ -135,7 +165,6 @@ union uvh_bau_data_config_u {
#define UV1H_EVENT_OCCURRED0_GR0_AOERR0_SHFT 8
#define UV1H_EVENT_OCCURRED0_GR1_AOERR0_SHFT 9
#define UV1H_EVENT_OCCURRED0_LH_AOERR0_SHFT 10
-#define UV1H_EVENT_OCCURRED0_RH_AOERR0_SHFT 11
#define UV1H_EVENT_OCCURRED0_XN_AOERR0_SHFT 12
#define UV1H_EVENT_OCCURRED0_SI_AOERR0_SHFT 13
#define UV1H_EVENT_OCCURRED0_LB_AOERR1_SHFT 14
@@ -181,7 +210,6 @@ union uvh_bau_data_config_u {
#define UV1H_EVENT_OCCURRED0_RTC3_SHFT 54
#define UV1H_EVENT_OCCURRED0_BAU_DATA_SHFT 55
#define UV1H_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_SHFT 56
-#define UV1H_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL
#define UV1H_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000002UL
#define UV1H_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000004UL
#define UV1H_EVENT_OCCURRED0_LH_HCERR_MASK 0x0000000000000008UL
@@ -192,7 +220,6 @@ union uvh_bau_data_config_u {
#define UV1H_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000000100UL
#define UV1H_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000000200UL
#define UV1H_EVENT_OCCURRED0_LH_AOERR0_MASK 0x0000000000000400UL
-#define UV1H_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL
#define UV1H_EVENT_OCCURRED0_XN_AOERR0_MASK 0x0000000000001000UL
#define UV1H_EVENT_OCCURRED0_SI_AOERR0_MASK 0x0000000000002000UL
#define UV1H_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000004000UL
@@ -239,188 +266,130 @@ union uvh_bau_data_config_u {
#define UV1H_EVENT_OCCURRED0_BAU_DATA_MASK 0x0080000000000000UL
#define UV1H_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_MASK 0x0100000000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_HCERR_SHFT 0
-#define UV2H_EVENT_OCCURRED0_QP_HCERR_SHFT 1
-#define UV2H_EVENT_OCCURRED0_RH_HCERR_SHFT 2
-#define UV2H_EVENT_OCCURRED0_LH0_HCERR_SHFT 3
-#define UV2H_EVENT_OCCURRED0_LH1_HCERR_SHFT 4
-#define UV2H_EVENT_OCCURRED0_GR0_HCERR_SHFT 5
-#define UV2H_EVENT_OCCURRED0_GR1_HCERR_SHFT 6
-#define UV2H_EVENT_OCCURRED0_NI0_HCERR_SHFT 7
-#define UV2H_EVENT_OCCURRED0_NI1_HCERR_SHFT 8
-#define UV2H_EVENT_OCCURRED0_LB_AOERR0_SHFT 9
-#define UV2H_EVENT_OCCURRED0_QP_AOERR0_SHFT 10
-#define UV2H_EVENT_OCCURRED0_RH_AOERR0_SHFT 11
-#define UV2H_EVENT_OCCURRED0_LH0_AOERR0_SHFT 12
-#define UV2H_EVENT_OCCURRED0_LH1_AOERR0_SHFT 13
-#define UV2H_EVENT_OCCURRED0_GR0_AOERR0_SHFT 14
-#define UV2H_EVENT_OCCURRED0_GR1_AOERR0_SHFT 15
-#define UV2H_EVENT_OCCURRED0_XB_AOERR0_SHFT 16
-#define UV2H_EVENT_OCCURRED0_RT_AOERR0_SHFT 17
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_SHFT 18
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_SHFT 19
-#define UV2H_EVENT_OCCURRED0_LB_AOERR1_SHFT 20
-#define UV2H_EVENT_OCCURRED0_QP_AOERR1_SHFT 21
-#define UV2H_EVENT_OCCURRED0_RH_AOERR1_SHFT 22
-#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_SHFT 23
-#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_SHFT 24
-#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_SHFT 25
-#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_SHFT 26
-#define UV2H_EVENT_OCCURRED0_XB_AOERR1_SHFT 27
-#define UV2H_EVENT_OCCURRED0_RT_AOERR1_SHFT 28
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_SHFT 29
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_SHFT 30
-#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT 31
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT 32
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT 33
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT 34
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT 35
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT 36
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT 37
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT 38
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT 39
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT 40
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT 41
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT 42
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT 43
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT 44
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT 45
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT 46
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT 47
-#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_SHFT 48
-#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_SHFT 49
-#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT 50
-#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT 51
-#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT 52
-#define UV2H_EVENT_OCCURRED0_IPI_INT_SHFT 53
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_SHFT 54
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_SHFT 55
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_SHFT 56
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_SHFT 57
-#define UV2H_EVENT_OCCURRED0_PROFILE_INT_SHFT 58
-#define UV2H_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL
-#define UV2H_EVENT_OCCURRED0_QP_HCERR_MASK 0x0000000000000002UL
-#define UV2H_EVENT_OCCURRED0_RH_HCERR_MASK 0x0000000000000004UL
-#define UV2H_EVENT_OCCURRED0_LH0_HCERR_MASK 0x0000000000000008UL
-#define UV2H_EVENT_OCCURRED0_LH1_HCERR_MASK 0x0000000000000010UL
-#define UV2H_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000020UL
-#define UV2H_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000040UL
-#define UV2H_EVENT_OCCURRED0_NI0_HCERR_MASK 0x0000000000000080UL
-#define UV2H_EVENT_OCCURRED0_NI1_HCERR_MASK 0x0000000000000100UL
-#define UV2H_EVENT_OCCURRED0_LB_AOERR0_MASK 0x0000000000000200UL
-#define UV2H_EVENT_OCCURRED0_QP_AOERR0_MASK 0x0000000000000400UL
-#define UV2H_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL
-#define UV2H_EVENT_OCCURRED0_LH0_AOERR0_MASK 0x0000000000001000UL
-#define UV2H_EVENT_OCCURRED0_LH1_AOERR0_MASK 0x0000000000002000UL
-#define UV2H_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000004000UL
-#define UV2H_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000008000UL
-#define UV2H_EVENT_OCCURRED0_XB_AOERR0_MASK 0x0000000000010000UL
-#define UV2H_EVENT_OCCURRED0_RT_AOERR0_MASK 0x0000000000020000UL
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_MASK 0x0000000000040000UL
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_MASK 0x0000000000080000UL
-#define UV2H_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000100000UL
-#define UV2H_EVENT_OCCURRED0_QP_AOERR1_MASK 0x0000000000200000UL
-#define UV2H_EVENT_OCCURRED0_RH_AOERR1_MASK 0x0000000000400000UL
-#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_MASK 0x0000000000800000UL
-#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_MASK 0x0000000001000000UL
-#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_MASK 0x0000000002000000UL
-#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_MASK 0x0000000004000000UL
-#define UV2H_EVENT_OCCURRED0_XB_AOERR1_MASK 0x0000000008000000UL
-#define UV2H_EVENT_OCCURRED0_RT_AOERR1_MASK 0x0000000010000000UL
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_MASK 0x0000000020000000UL
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_MASK 0x0000000040000000UL
-#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK 0x0000000080000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK 0x0000000100000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK 0x0000000200000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK 0x0000000400000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK 0x0000000800000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK 0x0000001000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK 0x0000002000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK 0x0000004000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK 0x0000008000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK 0x0000010000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK 0x0000020000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK 0x0000040000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK 0x0000080000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK 0x0000100000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK 0x0000200000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK 0x0000400000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK 0x0000800000000000UL
-#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_MASK 0x0001000000000000UL
-#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_MASK 0x0002000000000000UL
-#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_MASK 0x0004000000000000UL
-#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_MASK 0x0008000000000000UL
-#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK 0x0010000000000000UL
-#define UV2H_EVENT_OCCURRED0_IPI_INT_MASK 0x0020000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_MASK 0x0040000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_MASK 0x0080000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_MASK 0x0100000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_MASK 0x0200000000000000UL
-#define UV2H_EVENT_OCCURRED0_PROFILE_INT_MASK 0x0400000000000000UL
+#define UVXH_EVENT_OCCURRED0_QP_HCERR_SHFT 1
+#define UVXH_EVENT_OCCURRED0_RH_HCERR_SHFT 2
+#define UVXH_EVENT_OCCURRED0_LH0_HCERR_SHFT 3
+#define UVXH_EVENT_OCCURRED0_LH1_HCERR_SHFT 4
+#define UVXH_EVENT_OCCURRED0_GR0_HCERR_SHFT 5
+#define UVXH_EVENT_OCCURRED0_GR1_HCERR_SHFT 6
+#define UVXH_EVENT_OCCURRED0_NI0_HCERR_SHFT 7
+#define UVXH_EVENT_OCCURRED0_NI1_HCERR_SHFT 8
+#define UVXH_EVENT_OCCURRED0_LB_AOERR0_SHFT 9
+#define UVXH_EVENT_OCCURRED0_QP_AOERR0_SHFT 10
+#define UVXH_EVENT_OCCURRED0_LH0_AOERR0_SHFT 12
+#define UVXH_EVENT_OCCURRED0_LH1_AOERR0_SHFT 13
+#define UVXH_EVENT_OCCURRED0_GR0_AOERR0_SHFT 14
+#define UVXH_EVENT_OCCURRED0_GR1_AOERR0_SHFT 15
+#define UVXH_EVENT_OCCURRED0_XB_AOERR0_SHFT 16
+#define UVXH_EVENT_OCCURRED0_RT_AOERR0_SHFT 17
+#define UVXH_EVENT_OCCURRED0_NI0_AOERR0_SHFT 18
+#define UVXH_EVENT_OCCURRED0_NI1_AOERR0_SHFT 19
+#define UVXH_EVENT_OCCURRED0_LB_AOERR1_SHFT 20
+#define UVXH_EVENT_OCCURRED0_QP_AOERR1_SHFT 21
+#define UVXH_EVENT_OCCURRED0_RH_AOERR1_SHFT 22
+#define UVXH_EVENT_OCCURRED0_LH0_AOERR1_SHFT 23
+#define UVXH_EVENT_OCCURRED0_LH1_AOERR1_SHFT 24
+#define UVXH_EVENT_OCCURRED0_GR0_AOERR1_SHFT 25
+#define UVXH_EVENT_OCCURRED0_GR1_AOERR1_SHFT 26
+#define UVXH_EVENT_OCCURRED0_XB_AOERR1_SHFT 27
+#define UVXH_EVENT_OCCURRED0_RT_AOERR1_SHFT 28
+#define UVXH_EVENT_OCCURRED0_NI0_AOERR1_SHFT 29
+#define UVXH_EVENT_OCCURRED0_NI1_AOERR1_SHFT 30
+#define UVXH_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT 31
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT 32
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT 33
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT 34
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT 35
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT 36
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT 37
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT 38
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT 39
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT 40
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT 41
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT 42
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT 43
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT 44
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT 45
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT 46
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT 47
+#define UVXH_EVENT_OCCURRED0_L1_NMI_INT_SHFT 48
+#define UVXH_EVENT_OCCURRED0_STOP_CLOCK_SHFT 49
+#define UVXH_EVENT_OCCURRED0_ASIC_TO_L1_SHFT 50
+#define UVXH_EVENT_OCCURRED0_L1_TO_ASIC_SHFT 51
+#define UVXH_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT 52
+#define UVXH_EVENT_OCCURRED0_IPI_INT_SHFT 53
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT0_SHFT 54
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT1_SHFT 55
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT2_SHFT 56
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT3_SHFT 57
+#define UVXH_EVENT_OCCURRED0_PROFILE_INT_SHFT 58
+#define UVXH_EVENT_OCCURRED0_QP_HCERR_MASK 0x0000000000000002UL
+#define UVXH_EVENT_OCCURRED0_RH_HCERR_MASK 0x0000000000000004UL
+#define UVXH_EVENT_OCCURRED0_LH0_HCERR_MASK 0x0000000000000008UL
+#define UVXH_EVENT_OCCURRED0_LH1_HCERR_MASK 0x0000000000000010UL
+#define UVXH_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000020UL
+#define UVXH_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000040UL
+#define UVXH_EVENT_OCCURRED0_NI0_HCERR_MASK 0x0000000000000080UL
+#define UVXH_EVENT_OCCURRED0_NI1_HCERR_MASK 0x0000000000000100UL
+#define UVXH_EVENT_OCCURRED0_LB_AOERR0_MASK 0x0000000000000200UL
+#define UVXH_EVENT_OCCURRED0_QP_AOERR0_MASK 0x0000000000000400UL
+#define UVXH_EVENT_OCCURRED0_LH0_AOERR0_MASK 0x0000000000001000UL
+#define UVXH_EVENT_OCCURRED0_LH1_AOERR0_MASK 0x0000000000002000UL
+#define UVXH_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000004000UL
+#define UVXH_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000008000UL
+#define UVXH_EVENT_OCCURRED0_XB_AOERR0_MASK 0x0000000000010000UL
+#define UVXH_EVENT_OCCURRED0_RT_AOERR0_MASK 0x0000000000020000UL
+#define UVXH_EVENT_OCCURRED0_NI0_AOERR0_MASK 0x0000000000040000UL
+#define UVXH_EVENT_OCCURRED0_NI1_AOERR0_MASK 0x0000000000080000UL
+#define UVXH_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000100000UL
+#define UVXH_EVENT_OCCURRED0_QP_AOERR1_MASK 0x0000000000200000UL
+#define UVXH_EVENT_OCCURRED0_RH_AOERR1_MASK 0x0000000000400000UL
+#define UVXH_EVENT_OCCURRED0_LH0_AOERR1_MASK 0x0000000000800000UL
+#define UVXH_EVENT_OCCURRED0_LH1_AOERR1_MASK 0x0000000001000000UL
+#define UVXH_EVENT_OCCURRED0_GR0_AOERR1_MASK 0x0000000002000000UL
+#define UVXH_EVENT_OCCURRED0_GR1_AOERR1_MASK 0x0000000004000000UL
+#define UVXH_EVENT_OCCURRED0_XB_AOERR1_MASK 0x0000000008000000UL
+#define UVXH_EVENT_OCCURRED0_RT_AOERR1_MASK 0x0000000010000000UL
+#define UVXH_EVENT_OCCURRED0_NI0_AOERR1_MASK 0x0000000020000000UL
+#define UVXH_EVENT_OCCURRED0_NI1_AOERR1_MASK 0x0000000040000000UL
+#define UVXH_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK 0x0000000080000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK 0x0000000100000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK 0x0000000200000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK 0x0000000400000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK 0x0000000800000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK 0x0000001000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK 0x0000002000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK 0x0000004000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK 0x0000008000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK 0x0000010000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK 0x0000020000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK 0x0000040000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK 0x0000080000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK 0x0000100000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK 0x0000200000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK 0x0000400000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK 0x0000800000000000UL
+#define UVXH_EVENT_OCCURRED0_L1_NMI_INT_MASK 0x0001000000000000UL
+#define UVXH_EVENT_OCCURRED0_STOP_CLOCK_MASK 0x0002000000000000UL
+#define UVXH_EVENT_OCCURRED0_ASIC_TO_L1_MASK 0x0004000000000000UL
+#define UVXH_EVENT_OCCURRED0_L1_TO_ASIC_MASK 0x0008000000000000UL
+#define UVXH_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK 0x0010000000000000UL
+#define UVXH_EVENT_OCCURRED0_IPI_INT_MASK 0x0020000000000000UL
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT0_MASK 0x0040000000000000UL
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT1_MASK 0x0080000000000000UL
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT2_MASK 0x0100000000000000UL
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT3_MASK 0x0200000000000000UL
+#define UVXH_EVENT_OCCURRED0_PROFILE_INT_MASK 0x0400000000000000UL
union uvh_event_occurred0_u {
unsigned long v;
- struct uv1h_event_occurred0_s {
+ struct uvh_event_occurred0_s {
unsigned long lb_hcerr:1; /* RW, W1C */
- unsigned long gr0_hcerr:1; /* RW, W1C */
- unsigned long gr1_hcerr:1; /* RW, W1C */
- unsigned long lh_hcerr:1; /* RW, W1C */
- unsigned long rh_hcerr:1; /* RW, W1C */
- unsigned long xn_hcerr:1; /* RW, W1C */
- unsigned long si_hcerr:1; /* RW, W1C */
- unsigned long lb_aoerr0:1; /* RW, W1C */
- unsigned long gr0_aoerr0:1; /* RW, W1C */
- unsigned long gr1_aoerr0:1; /* RW, W1C */
- unsigned long lh_aoerr0:1; /* RW, W1C */
+ unsigned long rsvd_1_10:10;
unsigned long rh_aoerr0:1; /* RW, W1C */
- unsigned long xn_aoerr0:1; /* RW, W1C */
- unsigned long si_aoerr0:1; /* RW, W1C */
- unsigned long lb_aoerr1:1; /* RW, W1C */
- unsigned long gr0_aoerr1:1; /* RW, W1C */
- unsigned long gr1_aoerr1:1; /* RW, W1C */
- unsigned long lh_aoerr1:1; /* RW, W1C */
- unsigned long rh_aoerr1:1; /* RW, W1C */
- unsigned long xn_aoerr1:1; /* RW, W1C */
- unsigned long si_aoerr1:1; /* RW, W1C */
- unsigned long rh_vpi_int:1; /* RW, W1C */
- unsigned long system_shutdown_int:1; /* RW, W1C */
- unsigned long lb_irq_int_0:1; /* RW, W1C */
- unsigned long lb_irq_int_1:1; /* RW, W1C */
- unsigned long lb_irq_int_2:1; /* RW, W1C */
- unsigned long lb_irq_int_3:1; /* RW, W1C */
- unsigned long lb_irq_int_4:1; /* RW, W1C */
- unsigned long lb_irq_int_5:1; /* RW, W1C */
- unsigned long lb_irq_int_6:1; /* RW, W1C */
- unsigned long lb_irq_int_7:1; /* RW, W1C */
- unsigned long lb_irq_int_8:1; /* RW, W1C */
- unsigned long lb_irq_int_9:1; /* RW, W1C */
- unsigned long lb_irq_int_10:1; /* RW, W1C */
- unsigned long lb_irq_int_11:1; /* RW, W1C */
- unsigned long lb_irq_int_12:1; /* RW, W1C */
- unsigned long lb_irq_int_13:1; /* RW, W1C */
- unsigned long lb_irq_int_14:1; /* RW, W1C */
- unsigned long lb_irq_int_15:1; /* RW, W1C */
- unsigned long l1_nmi_int:1; /* RW, W1C */
- unsigned long stop_clock:1; /* RW, W1C */
- unsigned long asic_to_l1:1; /* RW, W1C */
- unsigned long l1_to_asic:1; /* RW, W1C */
- unsigned long ltc_int:1; /* RW, W1C */
- unsigned long la_seq_trigger:1; /* RW, W1C */
- unsigned long ipi_int:1; /* RW, W1C */
- unsigned long extio_int0:1; /* RW, W1C */
- unsigned long extio_int1:1; /* RW, W1C */
- unsigned long extio_int2:1; /* RW, W1C */
- unsigned long extio_int3:1; /* RW, W1C */
- unsigned long profile_int:1; /* RW, W1C */
- unsigned long rtc0:1; /* RW, W1C */
- unsigned long rtc1:1; /* RW, W1C */
- unsigned long rtc2:1; /* RW, W1C */
- unsigned long rtc3:1; /* RW, W1C */
- unsigned long bau_data:1; /* RW, W1C */
- unsigned long power_management_req:1; /* RW, W1C */
- unsigned long rsvd_57_63:7;
- } s1;
- struct uv2h_event_occurred0_s {
+ unsigned long rsvd_12_63:52;
+ } s;
+ struct uvxh_event_occurred0_s {
unsigned long lb_hcerr:1; /* RW */
unsigned long qp_hcerr:1; /* RW */
unsigned long rh_hcerr:1; /* RW */
@@ -481,19 +450,20 @@ union uvh_event_occurred0_u {
unsigned long extio_int3:1; /* RW */
unsigned long profile_int:1; /* RW */
unsigned long rsvd_59_63:5;
- } s2;
+ } sx;
};
/* ========================================================================= */
/* UVH_EVENT_OCCURRED0_ALIAS */
/* ========================================================================= */
-#define UVH_EVENT_OCCURRED0_ALIAS 0x0000000000070008UL
-#define UVH_EVENT_OCCURRED0_ALIAS_32 0x5f0
+#define UVH_EVENT_OCCURRED0_ALIAS 0x70008UL
+#define UVH_EVENT_OCCURRED0_ALIAS_32 0x5f0
+
/* ========================================================================= */
/* UVH_GR0_TLB_INT0_CONFIG */
/* ========================================================================= */
-#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL
+#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL
#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT 0
#define UVH_GR0_TLB_INT0_CONFIG_DM_SHFT 8
@@ -531,7 +501,7 @@ union uvh_gr0_tlb_int0_config_u {
/* ========================================================================= */
/* UVH_GR0_TLB_INT1_CONFIG */
/* ========================================================================= */
-#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL
+#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL
#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT 0
#define UVH_GR0_TLB_INT1_CONFIG_DM_SHFT 8
@@ -571,9 +541,11 @@ union uvh_gr0_tlb_int1_config_u {
/* ========================================================================= */
#define UV1H_GR0_TLB_MMR_CONTROL 0x401080UL
#define UV2H_GR0_TLB_MMR_CONTROL 0xc01080UL
-#define UVH_GR0_TLB_MMR_CONTROL (is_uv1_hub() ? \
- UV1H_GR0_TLB_MMR_CONTROL : \
- UV2H_GR0_TLB_MMR_CONTROL)
+#define UV3H_GR0_TLB_MMR_CONTROL 0xc01080UL
+#define UVH_GR0_TLB_MMR_CONTROL \
+ (is_uv1_hub() ? UV1H_GR0_TLB_MMR_CONTROL : \
+ (is_uv2_hub() ? UV2H_GR0_TLB_MMR_CONTROL : \
+ UV3H_GR0_TLB_MMR_CONTROL))
#define UVH_GR0_TLB_MMR_CONTROL_INDEX_SHFT 0
#define UVH_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT 12
@@ -611,6 +583,21 @@ union uvh_gr0_tlb_int1_config_u {
#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRREG_MASK 0x0100000000000000UL
#define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBLRUV_MASK 0x1000000000000000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_INDEX_SHFT 0
+#define UVXH_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT 12
+#define UVXH_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT 30
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT 31
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT 32
+#define UVXH_GR0_TLB_MMR_CONTROL_INDEX_MASK 0x0000000000000fffUL
+#define UVXH_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK 0x0000000000003000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK 0x0000000000010000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK 0x0000000040000000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_READ_MASK 0x0000000080000000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_MASK 0x0000000100000000UL
+
#define UV2H_GR0_TLB_MMR_CONTROL_INDEX_SHFT 0
#define UV2H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT 12
#define UV2H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16
@@ -630,6 +617,23 @@ union uvh_gr0_tlb_int1_config_u {
#define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_CON_MASK 0x0001000000000000UL
#define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_MASK 0x0010000000000000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_INDEX_SHFT 0
+#define UV3H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT 12
+#define UV3H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20
+#define UV3H_GR0_TLB_MMR_CONTROL_ECC_SEL_SHFT 21
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT 30
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT 31
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT 32
+#define UV3H_GR0_TLB_MMR_CONTROL_INDEX_MASK 0x0000000000000fffUL
+#define UV3H_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK 0x0000000000003000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK 0x0000000000010000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_ECC_SEL_MASK 0x0000000000200000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK 0x0000000040000000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_READ_MASK 0x0000000080000000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_MASK 0x0000000100000000UL
+
union uvh_gr0_tlb_mmr_control_u {
unsigned long v;
struct uvh_gr0_tlb_mmr_control_s {
@@ -642,7 +646,9 @@ union uvh_gr0_tlb_mmr_control_u {
unsigned long rsvd_21_29:9;
unsigned long mmr_write:1; /* WP */
unsigned long mmr_read:1; /* WP */
- unsigned long rsvd_32_63:32;
+ unsigned long rsvd_32_48:17;
+ unsigned long rsvd_49_51:3;
+ unsigned long rsvd_52_63:12;
} s;
struct uv1h_gr0_tlb_mmr_control_s {
unsigned long index:12; /* RW */
@@ -666,6 +672,23 @@ union uvh_gr0_tlb_mmr_control_u {
unsigned long mmr_inj_tlblruv:1; /* RW */
unsigned long rsvd_61_63:3;
} s1;
+ struct uvxh_gr0_tlb_mmr_control_s {
+ unsigned long index:12; /* RW */
+ unsigned long mem_sel:2; /* RW */
+ unsigned long rsvd_14_15:2;
+ unsigned long auto_valid_en:1; /* RW */
+ unsigned long rsvd_17_19:3;
+ unsigned long mmr_hash_index_en:1; /* RW */
+ unsigned long rsvd_21_29:9;
+ unsigned long mmr_write:1; /* WP */
+ unsigned long mmr_read:1; /* WP */
+ unsigned long mmr_op_done:1; /* RW */
+ unsigned long rsvd_33_47:15;
+ unsigned long rsvd_48:1;
+ unsigned long rsvd_49_51:3;
+ unsigned long rsvd_52:1;
+ unsigned long rsvd_53_63:11;
+ } sx;
struct uv2h_gr0_tlb_mmr_control_s {
unsigned long index:12; /* RW */
unsigned long mem_sel:2; /* RW */
@@ -683,6 +706,24 @@ union uvh_gr0_tlb_mmr_control_u {
unsigned long mmr_inj_tlbram:1; /* RW */
unsigned long rsvd_53_63:11;
} s2;
+ struct uv3h_gr0_tlb_mmr_control_s {
+ unsigned long index:12; /* RW */
+ unsigned long mem_sel:2; /* RW */
+ unsigned long rsvd_14_15:2;
+ unsigned long auto_valid_en:1; /* RW */
+ unsigned long rsvd_17_19:3;
+ unsigned long mmr_hash_index_en:1; /* RW */
+ unsigned long ecc_sel:1; /* RW */
+ unsigned long rsvd_22_29:8;
+ unsigned long mmr_write:1; /* WP */
+ unsigned long mmr_read:1; /* WP */
+ unsigned long mmr_op_done:1; /* RW */
+ unsigned long rsvd_33_47:15;
+ unsigned long undef_48:1; /* Undefined */
+ unsigned long rsvd_49_51:3;
+ unsigned long undef_52:1; /* Undefined */
+ unsigned long rsvd_53_63:11;
+ } s3;
};
/* ========================================================================= */
@@ -690,9 +731,11 @@ union uvh_gr0_tlb_mmr_control_u {
/* ========================================================================= */
#define UV1H_GR0_TLB_MMR_READ_DATA_HI 0x4010a0UL
#define UV2H_GR0_TLB_MMR_READ_DATA_HI 0xc010a0UL
-#define UVH_GR0_TLB_MMR_READ_DATA_HI (is_uv1_hub() ? \
- UV1H_GR0_TLB_MMR_READ_DATA_HI : \
- UV2H_GR0_TLB_MMR_READ_DATA_HI)
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI 0xc010a0UL
+#define UVH_GR0_TLB_MMR_READ_DATA_HI \
+ (is_uv1_hub() ? UV1H_GR0_TLB_MMR_READ_DATA_HI : \
+ (is_uv2_hub() ? UV2H_GR0_TLB_MMR_READ_DATA_HI : \
+ UV3H_GR0_TLB_MMR_READ_DATA_HI))
#define UVH_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT 0
#define UVH_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT 41
@@ -703,6 +746,46 @@ union uvh_gr0_tlb_mmr_control_u {
#define UVH_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL
#define UVH_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT 0
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT 41
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT 43
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT 44
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK 0x000001ffffffffffUL
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK 0x0000060000000000UL
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL
+
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT 0
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT 41
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT 43
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT 44
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK 0x000001ffffffffffUL
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK 0x0000060000000000UL
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL
+
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT 0
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT 41
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT 43
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT 44
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK 0x000001ffffffffffUL
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK 0x0000060000000000UL
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL
+
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT 0
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT 41
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT 43
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT 44
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_AA_EXT_SHFT 45
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_WAY_ECC_SHFT 55
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK 0x000001ffffffffffUL
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK 0x0000060000000000UL
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_AA_EXT_MASK 0x0000200000000000UL
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_WAY_ECC_MASK 0xff80000000000000UL
+
union uvh_gr0_tlb_mmr_read_data_hi_u {
unsigned long v;
struct uvh_gr0_tlb_mmr_read_data_hi_s {
@@ -712,6 +795,36 @@ union uvh_gr0_tlb_mmr_read_data_hi_u {
unsigned long larger:1; /* RO */
unsigned long rsvd_45_63:19;
} s;
+ struct uv1h_gr0_tlb_mmr_read_data_hi_s {
+ unsigned long pfn:41; /* RO */
+ unsigned long gaa:2; /* RO */
+ unsigned long dirty:1; /* RO */
+ unsigned long larger:1; /* RO */
+ unsigned long rsvd_45_63:19;
+ } s1;
+ struct uvxh_gr0_tlb_mmr_read_data_hi_s {
+ unsigned long pfn:41; /* RO */
+ unsigned long gaa:2; /* RO */
+ unsigned long dirty:1; /* RO */
+ unsigned long larger:1; /* RO */
+ unsigned long rsvd_45_63:19;
+ } sx;
+ struct uv2h_gr0_tlb_mmr_read_data_hi_s {
+ unsigned long pfn:41; /* RO */
+ unsigned long gaa:2; /* RO */
+ unsigned long dirty:1; /* RO */
+ unsigned long larger:1; /* RO */
+ unsigned long rsvd_45_63:19;
+ } s2;
+ struct uv3h_gr0_tlb_mmr_read_data_hi_s {
+ unsigned long pfn:41; /* RO */
+ unsigned long gaa:2; /* RO */
+ unsigned long dirty:1; /* RO */
+ unsigned long larger:1; /* RO */
+ unsigned long aa_ext:1; /* RO */
+ unsigned long undef_46_54:9; /* Undefined */
+ unsigned long way_ecc:9; /* RO */
+ } s3;
};
/* ========================================================================= */
@@ -719,9 +832,11 @@ union uvh_gr0_tlb_mmr_read_data_hi_u {
/* ========================================================================= */
#define UV1H_GR0_TLB_MMR_READ_DATA_LO 0x4010a8UL
#define UV2H_GR0_TLB_MMR_READ_DATA_LO 0xc010a8UL
-#define UVH_GR0_TLB_MMR_READ_DATA_LO (is_uv1_hub() ? \
- UV1H_GR0_TLB_MMR_READ_DATA_LO : \
- UV2H_GR0_TLB_MMR_READ_DATA_LO)
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO 0xc010a8UL
+#define UVH_GR0_TLB_MMR_READ_DATA_LO \
+ (is_uv1_hub() ? UV1H_GR0_TLB_MMR_READ_DATA_LO : \
+ (is_uv2_hub() ? UV2H_GR0_TLB_MMR_READ_DATA_LO : \
+ UV3H_GR0_TLB_MMR_READ_DATA_LO))
#define UVH_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT 0
#define UVH_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT 39
@@ -730,6 +845,34 @@ union uvh_gr0_tlb_mmr_read_data_hi_u {
#define UVH_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL
#define UVH_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT 0
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT 39
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT 63
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK 0x0000007fffffffffUL
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL
+
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT 0
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT 39
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT 63
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK 0x0000007fffffffffUL
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL
+
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT 0
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT 39
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT 63
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK 0x0000007fffffffffUL
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL
+
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT 0
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT 39
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT 63
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK 0x0000007fffffffffUL
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL
+
union uvh_gr0_tlb_mmr_read_data_lo_u {
unsigned long v;
struct uvh_gr0_tlb_mmr_read_data_lo_s {
@@ -737,12 +880,32 @@ union uvh_gr0_tlb_mmr_read_data_lo_u {
unsigned long asid:24; /* RO */
unsigned long valid:1; /* RO */
} s;
+ struct uv1h_gr0_tlb_mmr_read_data_lo_s {
+ unsigned long vpn:39; /* RO */
+ unsigned long asid:24; /* RO */
+ unsigned long valid:1; /* RO */
+ } s1;
+ struct uvxh_gr0_tlb_mmr_read_data_lo_s {
+ unsigned long vpn:39; /* RO */
+ unsigned long asid:24; /* RO */
+ unsigned long valid:1; /* RO */
+ } sx;
+ struct uv2h_gr0_tlb_mmr_read_data_lo_s {
+ unsigned long vpn:39; /* RO */
+ unsigned long asid:24; /* RO */
+ unsigned long valid:1; /* RO */
+ } s2;
+ struct uv3h_gr0_tlb_mmr_read_data_lo_s {
+ unsigned long vpn:39; /* RO */
+ unsigned long asid:24; /* RO */
+ unsigned long valid:1; /* RO */
+ } s3;
};
/* ========================================================================= */
/* UVH_GR1_TLB_INT0_CONFIG */
/* ========================================================================= */
-#define UVH_GR1_TLB_INT0_CONFIG 0x61f00UL
+#define UVH_GR1_TLB_INT0_CONFIG 0x61f00UL
#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT 0
#define UVH_GR1_TLB_INT0_CONFIG_DM_SHFT 8
@@ -780,7 +943,7 @@ union uvh_gr1_tlb_int0_config_u {
/* ========================================================================= */
/* UVH_GR1_TLB_INT1_CONFIG */
/* ========================================================================= */
-#define UVH_GR1_TLB_INT1_CONFIG 0x61f40UL
+#define UVH_GR1_TLB_INT1_CONFIG 0x61f40UL
#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT 0
#define UVH_GR1_TLB_INT1_CONFIG_DM_SHFT 8
@@ -820,9 +983,11 @@ union uvh_gr1_tlb_int1_config_u {
/* ========================================================================= */
#define UV1H_GR1_TLB_MMR_CONTROL 0x801080UL
#define UV2H_GR1_TLB_MMR_CONTROL 0x1001080UL
-#define UVH_GR1_TLB_MMR_CONTROL (is_uv1_hub() ? \
- UV1H_GR1_TLB_MMR_CONTROL : \
- UV2H_GR1_TLB_MMR_CONTROL)
+#define UV3H_GR1_TLB_MMR_CONTROL 0x1001080UL
+#define UVH_GR1_TLB_MMR_CONTROL \
+ (is_uv1_hub() ? UV1H_GR1_TLB_MMR_CONTROL : \
+ (is_uv2_hub() ? UV2H_GR1_TLB_MMR_CONTROL : \
+ UV3H_GR1_TLB_MMR_CONTROL))
#define UVH_GR1_TLB_MMR_CONTROL_INDEX_SHFT 0
#define UVH_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT 12
@@ -860,6 +1025,21 @@ union uvh_gr1_tlb_int1_config_u {
#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRREG_MASK 0x0100000000000000UL
#define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBLRUV_MASK 0x1000000000000000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_INDEX_SHFT 0
+#define UVXH_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT 12
+#define UVXH_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT 30
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT 31
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT 32
+#define UVXH_GR1_TLB_MMR_CONTROL_INDEX_MASK 0x0000000000000fffUL
+#define UVXH_GR1_TLB_MMR_CONTROL_MEM_SEL_MASK 0x0000000000003000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK 0x0000000000010000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK 0x0000000040000000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_READ_MASK 0x0000000080000000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_MASK 0x0000000100000000UL
+
#define UV2H_GR1_TLB_MMR_CONTROL_INDEX_SHFT 0
#define UV2H_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT 12
#define UV2H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16
@@ -879,6 +1059,23 @@ union uvh_gr1_tlb_int1_config_u {
#define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_CON_MASK 0x0001000000000000UL
#define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_MASK 0x0010000000000000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_INDEX_SHFT 0
+#define UV3H_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT 12
+#define UV3H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT 16
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT 20
+#define UV3H_GR1_TLB_MMR_CONTROL_ECC_SEL_SHFT 21
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT 30
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT 31
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT 32
+#define UV3H_GR1_TLB_MMR_CONTROL_INDEX_MASK 0x0000000000000fffUL
+#define UV3H_GR1_TLB_MMR_CONTROL_MEM_SEL_MASK 0x0000000000003000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK 0x0000000000010000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK 0x0000000000100000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_ECC_SEL_MASK 0x0000000000200000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK 0x0000000040000000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_READ_MASK 0x0000000080000000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_MASK 0x0000000100000000UL
+
union uvh_gr1_tlb_mmr_control_u {
unsigned long v;
struct uvh_gr1_tlb_mmr_control_s {
@@ -891,7 +1088,9 @@ union uvh_gr1_tlb_mmr_control_u {
unsigned long rsvd_21_29:9;
unsigned long mmr_write:1; /* WP */
unsigned long mmr_read:1; /* WP */
- unsigned long rsvd_32_63:32;
+ unsigned long rsvd_32_48:17;
+ unsigned long rsvd_49_51:3;
+ unsigned long rsvd_52_63:12;
} s;
struct uv1h_gr1_tlb_mmr_control_s {
unsigned long index:12; /* RW */
@@ -915,6 +1114,23 @@ union uvh_gr1_tlb_mmr_control_u {
unsigned long mmr_inj_tlblruv:1; /* RW */
unsigned long rsvd_61_63:3;
} s1;
+ struct uvxh_gr1_tlb_mmr_control_s {
+ unsigned long index:12; /* RW */
+ unsigned long mem_sel:2; /* RW */
+ unsigned long rsvd_14_15:2;
+ unsigned long auto_valid_en:1; /* RW */
+ unsigned long rsvd_17_19:3;
+ unsigned long mmr_hash_index_en:1; /* RW */
+ unsigned long rsvd_21_29:9;
+ unsigned long mmr_write:1; /* WP */
+ unsigned long mmr_read:1; /* WP */
+ unsigned long mmr_op_done:1; /* RW */
+ unsigned long rsvd_33_47:15;
+ unsigned long rsvd_48:1;
+ unsigned long rsvd_49_51:3;
+ unsigned long rsvd_52:1;
+ unsigned long rsvd_53_63:11;
+ } sx;
struct uv2h_gr1_tlb_mmr_control_s {
unsigned long index:12; /* RW */
unsigned long mem_sel:2; /* RW */
@@ -932,6 +1148,24 @@ union uvh_gr1_tlb_mmr_control_u {
unsigned long mmr_inj_tlbram:1; /* RW */
unsigned long rsvd_53_63:11;
} s2;
+ struct uv3h_gr1_tlb_mmr_control_s {
+ unsigned long index:12; /* RW */
+ unsigned long mem_sel:2; /* RW */
+ unsigned long rsvd_14_15:2;
+ unsigned long auto_valid_en:1; /* RW */
+ unsigned long rsvd_17_19:3;
+ unsigned long mmr_hash_index_en:1; /* RW */
+ unsigned long ecc_sel:1; /* RW */
+ unsigned long rsvd_22_29:8;
+ unsigned long mmr_write:1; /* WP */
+ unsigned long mmr_read:1; /* WP */
+ unsigned long mmr_op_done:1; /* RW */
+ unsigned long rsvd_33_47:15;
+ unsigned long undef_48:1; /* Undefined */
+ unsigned long rsvd_49_51:3;
+ unsigned long undef_52:1; /* Undefined */
+ unsigned long rsvd_53_63:11;
+ } s3;
};
/* ========================================================================= */
@@ -939,9 +1173,11 @@ union uvh_gr1_tlb_mmr_control_u {
/* ========================================================================= */
#define UV1H_GR1_TLB_MMR_READ_DATA_HI 0x8010a0UL
#define UV2H_GR1_TLB_MMR_READ_DATA_HI 0x10010a0UL
-#define UVH_GR1_TLB_MMR_READ_DATA_HI (is_uv1_hub() ? \
- UV1H_GR1_TLB_MMR_READ_DATA_HI : \
- UV2H_GR1_TLB_MMR_READ_DATA_HI)
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI 0x10010a0UL
+#define UVH_GR1_TLB_MMR_READ_DATA_HI \
+ (is_uv1_hub() ? UV1H_GR1_TLB_MMR_READ_DATA_HI : \
+ (is_uv2_hub() ? UV2H_GR1_TLB_MMR_READ_DATA_HI : \
+ UV3H_GR1_TLB_MMR_READ_DATA_HI))
#define UVH_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT 0
#define UVH_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT 41
@@ -952,6 +1188,46 @@ union uvh_gr1_tlb_mmr_control_u {
#define UVH_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL
#define UVH_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT 0
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT 41
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT 43
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT 44
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK 0x000001ffffffffffUL
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK 0x0000060000000000UL
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL
+
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT 0
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT 41
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT 43
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT 44
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK 0x000001ffffffffffUL
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK 0x0000060000000000UL
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL
+
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT 0
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT 41
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT 43
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT 44
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK 0x000001ffffffffffUL
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK 0x0000060000000000UL
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL
+
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT 0
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT 41
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT 43
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT 44
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_AA_EXT_SHFT 45
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_WAY_ECC_SHFT 55
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK 0x000001ffffffffffUL
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK 0x0000060000000000UL
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK 0x0000080000000000UL
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK 0x0000100000000000UL
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_AA_EXT_MASK 0x0000200000000000UL
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_WAY_ECC_MASK 0xff80000000000000UL
+
union uvh_gr1_tlb_mmr_read_data_hi_u {
unsigned long v;
struct uvh_gr1_tlb_mmr_read_data_hi_s {
@@ -961,6 +1237,36 @@ union uvh_gr1_tlb_mmr_read_data_hi_u {
unsigned long larger:1; /* RO */
unsigned long rsvd_45_63:19;
} s;
+ struct uv1h_gr1_tlb_mmr_read_data_hi_s {
+ unsigned long pfn:41; /* RO */
+ unsigned long gaa:2; /* RO */
+ unsigned long dirty:1; /* RO */
+ unsigned long larger:1; /* RO */
+ unsigned long rsvd_45_63:19;
+ } s1;
+ struct uvxh_gr1_tlb_mmr_read_data_hi_s {
+ unsigned long pfn:41; /* RO */
+ unsigned long gaa:2; /* RO */
+ unsigned long dirty:1; /* RO */
+ unsigned long larger:1; /* RO */
+ unsigned long rsvd_45_63:19;
+ } sx;
+ struct uv2h_gr1_tlb_mmr_read_data_hi_s {
+ unsigned long pfn:41; /* RO */
+ unsigned long gaa:2; /* RO */
+ unsigned long dirty:1; /* RO */
+ unsigned long larger:1; /* RO */
+ unsigned long rsvd_45_63:19;
+ } s2;
+ struct uv3h_gr1_tlb_mmr_read_data_hi_s {
+ unsigned long pfn:41; /* RO */
+ unsigned long gaa:2; /* RO */
+ unsigned long dirty:1; /* RO */
+ unsigned long larger:1; /* RO */
+ unsigned long aa_ext:1; /* RO */
+ unsigned long undef_46_54:9; /* Undefined */
+ unsigned long way_ecc:9; /* RO */
+ } s3;
};
/* ========================================================================= */
@@ -968,9 +1274,11 @@ union uvh_gr1_tlb_mmr_read_data_hi_u {
/* ========================================================================= */
#define UV1H_GR1_TLB_MMR_READ_DATA_LO 0x8010a8UL
#define UV2H_GR1_TLB_MMR_READ_DATA_LO 0x10010a8UL
-#define UVH_GR1_TLB_MMR_READ_DATA_LO (is_uv1_hub() ? \
- UV1H_GR1_TLB_MMR_READ_DATA_LO : \
- UV2H_GR1_TLB_MMR_READ_DATA_LO)
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO 0x10010a8UL
+#define UVH_GR1_TLB_MMR_READ_DATA_LO \
+ (is_uv1_hub() ? UV1H_GR1_TLB_MMR_READ_DATA_LO : \
+ (is_uv2_hub() ? UV2H_GR1_TLB_MMR_READ_DATA_LO : \
+ UV3H_GR1_TLB_MMR_READ_DATA_LO))
#define UVH_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT 0
#define UVH_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT 39
@@ -979,6 +1287,34 @@ union uvh_gr1_tlb_mmr_read_data_hi_u {
#define UVH_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL
#define UVH_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT 0
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT 39
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT 63
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK 0x0000007fffffffffUL
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL
+
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT 0
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT 39
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT 63
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK 0x0000007fffffffffUL
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL
+
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT 0
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT 39
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT 63
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK 0x0000007fffffffffUL
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL
+
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT 0
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT 39
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT 63
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK 0x0000007fffffffffUL
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK 0x7fffff8000000000UL
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK 0x8000000000000000UL
+
union uvh_gr1_tlb_mmr_read_data_lo_u {
unsigned long v;
struct uvh_gr1_tlb_mmr_read_data_lo_s {
@@ -986,12 +1322,32 @@ union uvh_gr1_tlb_mmr_read_data_lo_u {
unsigned long asid:24; /* RO */
unsigned long valid:1; /* RO */
} s;
+ struct uv1h_gr1_tlb_mmr_read_data_lo_s {
+ unsigned long vpn:39; /* RO */
+ unsigned long asid:24; /* RO */
+ unsigned long valid:1; /* RO */
+ } s1;
+ struct uvxh_gr1_tlb_mmr_read_data_lo_s {
+ unsigned long vpn:39; /* RO */
+ unsigned long asid:24; /* RO */
+ unsigned long valid:1; /* RO */
+ } sx;
+ struct uv2h_gr1_tlb_mmr_read_data_lo_s {
+ unsigned long vpn:39; /* RO */
+ unsigned long asid:24; /* RO */
+ unsigned long valid:1; /* RO */
+ } s2;
+ struct uv3h_gr1_tlb_mmr_read_data_lo_s {
+ unsigned long vpn:39; /* RO */
+ unsigned long asid:24; /* RO */
+ unsigned long valid:1; /* RO */
+ } s3;
};
/* ========================================================================= */
/* UVH_INT_CMPB */
/* ========================================================================= */
-#define UVH_INT_CMPB 0x22080UL
+#define UVH_INT_CMPB 0x22080UL
#define UVH_INT_CMPB_REAL_TIME_CMPB_SHFT 0
#define UVH_INT_CMPB_REAL_TIME_CMPB_MASK 0x00ffffffffffffffUL
@@ -1007,10 +1363,13 @@ union uvh_int_cmpb_u {
/* ========================================================================= */
/* UVH_INT_CMPC */
/* ========================================================================= */
-#define UVH_INT_CMPC 0x22100UL
+#define UVH_INT_CMPC 0x22100UL
+
+#define UV1H_INT_CMPC_REAL_TIME_CMPC_SHFT 0
+#define UV1H_INT_CMPC_REAL_TIME_CMPC_MASK 0x00ffffffffffffffUL
-#define UVH_INT_CMPC_REAL_TIME_CMPC_SHFT 0
-#define UVH_INT_CMPC_REAL_TIME_CMPC_MASK 0xffffffffffffffUL
+#define UVXH_INT_CMPC_REAL_TIME_CMP_2_SHFT 0
+#define UVXH_INT_CMPC_REAL_TIME_CMP_2_MASK 0x00ffffffffffffffUL
union uvh_int_cmpc_u {
unsigned long v;
@@ -1023,10 +1382,13 @@ union uvh_int_cmpc_u {
/* ========================================================================= */
/* UVH_INT_CMPD */
/* ========================================================================= */
-#define UVH_INT_CMPD 0x22180UL
+#define UVH_INT_CMPD 0x22180UL
-#define UVH_INT_CMPD_REAL_TIME_CMPD_SHFT 0
-#define UVH_INT_CMPD_REAL_TIME_CMPD_MASK 0xffffffffffffffUL
+#define UV1H_INT_CMPD_REAL_TIME_CMPD_SHFT 0
+#define UV1H_INT_CMPD_REAL_TIME_CMPD_MASK 0x00ffffffffffffffUL
+
+#define UVXH_INT_CMPD_REAL_TIME_CMP_3_SHFT 0
+#define UVXH_INT_CMPD_REAL_TIME_CMP_3_MASK 0x00ffffffffffffffUL
union uvh_int_cmpd_u {
unsigned long v;
@@ -1039,8 +1401,8 @@ union uvh_int_cmpd_u {
/* ========================================================================= */
/* UVH_IPI_INT */
/* ========================================================================= */
-#define UVH_IPI_INT 0x60500UL
-#define UVH_IPI_INT_32 0x348
+#define UVH_IPI_INT 0x60500UL
+#define UVH_IPI_INT_32 0x348
#define UVH_IPI_INT_VECTOR_SHFT 0
#define UVH_IPI_INT_DELIVERY_MODE_SHFT 8
@@ -1069,8 +1431,8 @@ union uvh_ipi_int_u {
/* ========================================================================= */
/* UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST */
/* ========================================================================= */
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST 0x320050UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32 0x9c0
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST 0x320050UL
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32 0x9c0
#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_SHFT 4
#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_NODE_ID_SHFT 49
@@ -1091,8 +1453,8 @@ union uvh_lb_bau_intd_payload_queue_first_u {
/* ========================================================================= */
/* UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST */
/* ========================================================================= */
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST 0x320060UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32 0x9c8
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST 0x320060UL
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32 0x9c8
#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_SHFT 4
#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_MASK 0x000007fffffffff0UL
@@ -1109,8 +1471,8 @@ union uvh_lb_bau_intd_payload_queue_last_u {
/* ========================================================================= */
/* UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL */
/* ========================================================================= */
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL 0x320070UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32 0x9d0
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL 0x320070UL
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32 0x9d0
#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_SHFT 4
#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_MASK 0x000007fffffffff0UL
@@ -1127,8 +1489,8 @@ union uvh_lb_bau_intd_payload_queue_tail_u {
/* ========================================================================= */
/* UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE */
/* ========================================================================= */
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE 0x320080UL
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_32 0xa68
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE 0x320080UL
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_32 0xa68
#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_SHFT 0
#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_1_SHFT 1
@@ -1189,14 +1551,21 @@ union uvh_lb_bau_intd_software_acknowledge_u {
/* ========================================================================= */
/* UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS */
/* ========================================================================= */
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS 0x0000000000320088UL
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS_32 0xa70
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS 0x320088UL
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS_32 0xa70
+
/* ========================================================================= */
/* UVH_LB_BAU_MISC_CONTROL */
/* ========================================================================= */
-#define UVH_LB_BAU_MISC_CONTROL 0x320170UL
-#define UVH_LB_BAU_MISC_CONTROL_32 0xa10
+#define UVH_LB_BAU_MISC_CONTROL 0x320170UL
+#define UV1H_LB_BAU_MISC_CONTROL 0x320170UL
+#define UV2H_LB_BAU_MISC_CONTROL 0x320170UL
+#define UV3H_LB_BAU_MISC_CONTROL 0x320170UL
+#define UVH_LB_BAU_MISC_CONTROL_32 0xa10
+#define UV1H_LB_BAU_MISC_CONTROL_32 0x320170UL
+#define UV2H_LB_BAU_MISC_CONTROL_32 0x320170UL
+#define UV3H_LB_BAU_MISC_CONTROL_32 0x320170UL
#define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0
#define UVH_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8
@@ -1213,6 +1582,7 @@ union uvh_lb_bau_intd_software_acknowledge_u {
#define UVH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
#define UVH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
#define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
+#define UVH_LB_BAU_MISC_CONTROL_FUN_SHFT 48
#define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL
#define UVH_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL
#define UVH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL
@@ -1228,6 +1598,7 @@ union uvh_lb_bau_intd_software_acknowledge_u {
#define UVH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
#define UVH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
#define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
+#define UVH_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL
#define UV1H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0
#define UV1H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8
@@ -1262,6 +1633,53 @@ union uvh_lb_bau_intd_software_acknowledge_u {
#define UV1H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
#define UV1H_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0
+#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8
+#define UVXH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9
+#define UVXH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10
+#define UVXH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
+#define UVXH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15
+#define UVXH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
+#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
+#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
+#define UVXH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
+#define UVXH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29
+#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34
+#define UVXH_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35
+#define UVXH_LB_BAU_MISC_CONTROL_FUN_SHFT 48
+#define UVXH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL
+#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL
+#define UVXH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL
+#define UVXH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL
+#define UVXH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
+#define UVXH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL
+#define UVXH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
+#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
+#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
+#define UVXH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_MASK 0x0000000020000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_MASK 0x0000000080000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_MASK 0x0000000100000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_MASK 0x0000000200000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_MASK 0x0000000400000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL
+
#define UV2H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0
#define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8
#define UV2H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9
@@ -1309,6 +1727,59 @@ union uvh_lb_bau_intd_software_acknowledge_u {
#define UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
#define UV2H_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT 0
+#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT 8
+#define UV3H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT 9
+#define UV3H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT 10
+#define UV3H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
+#define UV3H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15
+#define UV3H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
+#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
+#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
+#define UV3H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
+#define UV3H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29
+#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34
+#define UV3H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_QUIESCE_MSGS_TO_QPI_SHFT 36
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_PREFETCH_HINT_SHFT 37
+#define UV3H_LB_BAU_MISC_CONTROL_THREAD_KILL_TIMEBASE_SHFT 38
+#define UV3H_LB_BAU_MISC_CONTROL_FUN_SHFT 48
+#define UV3H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK 0x00000000000000ffUL
+#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK 0x0000000000000100UL
+#define UV3H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK 0x0000000000000200UL
+#define UV3H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK 0x0000000000000400UL
+#define UV3H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
+#define UV3H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL
+#define UV3H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
+#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
+#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
+#define UV3H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_MASK 0x0000000020000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_MASK 0x0000000080000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_MASK 0x0000000100000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_MASK 0x0000000200000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_MASK 0x0000000400000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_QUIESCE_MSGS_TO_QPI_MASK 0x0000001000000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_PREFETCH_HINT_MASK 0x0000002000000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_THREAD_KILL_TIMEBASE_MASK 0x00003fc000000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_FUN_MASK 0xffff000000000000UL
+
union uvh_lb_bau_misc_control_u {
unsigned long v;
struct uvh_lb_bau_misc_control_s {
@@ -1327,7 +1798,8 @@ union uvh_lb_bau_misc_control_u {
unsigned long programmed_initial_priority:3; /* RW */
unsigned long use_incoming_priority:1; /* RW */
unsigned long enable_programmed_initial_priority:1;/* RW */
- unsigned long rsvd_29_63:35;
+ unsigned long rsvd_29_47:19;
+ unsigned long fun:16; /* RW */
} s;
struct uv1h_lb_bau_misc_control_s {
unsigned long rejection_delay:8; /* RW */
@@ -1348,6 +1820,32 @@ union uvh_lb_bau_misc_control_u {
unsigned long rsvd_29_47:19;
unsigned long fun:16; /* RW */
} s1;
+ struct uvxh_lb_bau_misc_control_s {
+ unsigned long rejection_delay:8; /* RW */
+ unsigned long apic_mode:1; /* RW */
+ unsigned long force_broadcast:1; /* RW */
+ unsigned long force_lock_nop:1; /* RW */
+ unsigned long qpi_agent_presence_vector:3; /* RW */
+ unsigned long descriptor_fetch_mode:1; /* RW */
+ unsigned long enable_intd_soft_ack_mode:1; /* RW */
+ unsigned long intd_soft_ack_timeout_period:4; /* RW */
+ unsigned long enable_dual_mapping_mode:1; /* RW */
+ unsigned long vga_io_port_decode_enable:1; /* RW */
+ unsigned long vga_io_port_16_bit_decode:1; /* RW */
+ unsigned long suppress_dest_registration:1; /* RW */
+ unsigned long programmed_initial_priority:3; /* RW */
+ unsigned long use_incoming_priority:1; /* RW */
+ unsigned long enable_programmed_initial_priority:1;/* RW */
+ unsigned long enable_automatic_apic_mode_selection:1;/* RW */
+ unsigned long apic_mode_status:1; /* RO */
+ unsigned long suppress_interrupts_to_self:1; /* RW */
+ unsigned long enable_lock_based_system_flush:1;/* RW */
+ unsigned long enable_extended_sb_status:1; /* RW */
+ unsigned long suppress_int_prio_udt_to_self:1;/* RW */
+ unsigned long use_legacy_descriptor_formats:1;/* RW */
+ unsigned long rsvd_36_47:12;
+ unsigned long fun:16; /* RW */
+ } sx;
struct uv2h_lb_bau_misc_control_s {
unsigned long rejection_delay:8; /* RW */
unsigned long apic_mode:1; /* RW */
@@ -1374,13 +1872,42 @@ union uvh_lb_bau_misc_control_u {
unsigned long rsvd_36_47:12;
unsigned long fun:16; /* RW */
} s2;
+ struct uv3h_lb_bau_misc_control_s {
+ unsigned long rejection_delay:8; /* RW */
+ unsigned long apic_mode:1; /* RW */
+ unsigned long force_broadcast:1; /* RW */
+ unsigned long force_lock_nop:1; /* RW */
+ unsigned long qpi_agent_presence_vector:3; /* RW */
+ unsigned long descriptor_fetch_mode:1; /* RW */
+ unsigned long enable_intd_soft_ack_mode:1; /* RW */
+ unsigned long intd_soft_ack_timeout_period:4; /* RW */
+ unsigned long enable_dual_mapping_mode:1; /* RW */
+ unsigned long vga_io_port_decode_enable:1; /* RW */
+ unsigned long vga_io_port_16_bit_decode:1; /* RW */
+ unsigned long suppress_dest_registration:1; /* RW */
+ unsigned long programmed_initial_priority:3; /* RW */
+ unsigned long use_incoming_priority:1; /* RW */
+ unsigned long enable_programmed_initial_priority:1;/* RW */
+ unsigned long enable_automatic_apic_mode_selection:1;/* RW */
+ unsigned long apic_mode_status:1; /* RO */
+ unsigned long suppress_interrupts_to_self:1; /* RW */
+ unsigned long enable_lock_based_system_flush:1;/* RW */
+ unsigned long enable_extended_sb_status:1; /* RW */
+ unsigned long suppress_int_prio_udt_to_self:1;/* RW */
+ unsigned long use_legacy_descriptor_formats:1;/* RW */
+ unsigned long suppress_quiesce_msgs_to_qpi:1; /* RW */
+ unsigned long enable_intd_prefetch_hint:1; /* RW */
+ unsigned long thread_kill_timebase:8; /* RW */
+ unsigned long rsvd_46_47:2;
+ unsigned long fun:16; /* RW */
+ } s3;
};
/* ========================================================================= */
/* UVH_LB_BAU_SB_ACTIVATION_CONTROL */
/* ========================================================================= */
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL 0x320020UL
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32 0x9a8
+#define UVH_LB_BAU_SB_ACTIVATION_CONTROL 0x320020UL
+#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32 0x9a8
#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_SHFT 0
#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT 62
@@ -1402,8 +1929,8 @@ union uvh_lb_bau_sb_activation_control_u {
/* ========================================================================= */
/* UVH_LB_BAU_SB_ACTIVATION_STATUS_0 */
/* ========================================================================= */
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0 0x320030UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x9b0
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0 0x320030UL
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x9b0
#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_SHFT 0
#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_MASK 0xffffffffffffffffUL
@@ -1418,8 +1945,8 @@ union uvh_lb_bau_sb_activation_status_0_u {
/* ========================================================================= */
/* UVH_LB_BAU_SB_ACTIVATION_STATUS_1 */
/* ========================================================================= */
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1 0x320040UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x9b8
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1 0x320040UL
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x9b8
#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_SHFT 0
#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_MASK 0xffffffffffffffffUL
@@ -1434,8 +1961,8 @@ union uvh_lb_bau_sb_activation_status_1_u {
/* ========================================================================= */
/* UVH_LB_BAU_SB_DESCRIPTOR_BASE */
/* ========================================================================= */
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE 0x320010UL
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32 0x9a0
+#define UVH_LB_BAU_SB_DESCRIPTOR_BASE 0x320010UL
+#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32 0x9a0
#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_SHFT 12
#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT 49
@@ -1456,7 +1983,10 @@ union uvh_lb_bau_sb_descriptor_base_u {
/* ========================================================================= */
/* UVH_NODE_ID */
/* ========================================================================= */
-#define UVH_NODE_ID 0x0UL
+#define UVH_NODE_ID 0x0UL
+#define UV1H_NODE_ID 0x0UL
+#define UV2H_NODE_ID 0x0UL
+#define UV3H_NODE_ID 0x0UL
#define UVH_NODE_ID_FORCE1_SHFT 0
#define UVH_NODE_ID_MANUFACTURER_SHFT 1
@@ -1484,6 +2014,21 @@ union uvh_lb_bau_sb_descriptor_base_u {
#define UV1H_NODE_ID_NODES_PER_BIT_MASK 0x007f000000000000UL
#define UV1H_NODE_ID_NI_PORT_MASK 0x0f00000000000000UL
+#define UVXH_NODE_ID_FORCE1_SHFT 0
+#define UVXH_NODE_ID_MANUFACTURER_SHFT 1
+#define UVXH_NODE_ID_PART_NUMBER_SHFT 12
+#define UVXH_NODE_ID_REVISION_SHFT 28
+#define UVXH_NODE_ID_NODE_ID_SHFT 32
+#define UVXH_NODE_ID_NODES_PER_BIT_SHFT 50
+#define UVXH_NODE_ID_NI_PORT_SHFT 57
+#define UVXH_NODE_ID_FORCE1_MASK 0x0000000000000001UL
+#define UVXH_NODE_ID_MANUFACTURER_MASK 0x0000000000000ffeUL
+#define UVXH_NODE_ID_PART_NUMBER_MASK 0x000000000ffff000UL
+#define UVXH_NODE_ID_REVISION_MASK 0x00000000f0000000UL
+#define UVXH_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL
+#define UVXH_NODE_ID_NODES_PER_BIT_MASK 0x01fc000000000000UL
+#define UVXH_NODE_ID_NI_PORT_MASK 0x3e00000000000000UL
+
#define UV2H_NODE_ID_FORCE1_SHFT 0
#define UV2H_NODE_ID_MANUFACTURER_SHFT 1
#define UV2H_NODE_ID_PART_NUMBER_SHFT 12
@@ -1499,6 +2044,25 @@ union uvh_lb_bau_sb_descriptor_base_u {
#define UV2H_NODE_ID_NODES_PER_BIT_MASK 0x01fc000000000000UL
#define UV2H_NODE_ID_NI_PORT_MASK 0x3e00000000000000UL
+#define UV3H_NODE_ID_FORCE1_SHFT 0
+#define UV3H_NODE_ID_MANUFACTURER_SHFT 1
+#define UV3H_NODE_ID_PART_NUMBER_SHFT 12
+#define UV3H_NODE_ID_REVISION_SHFT 28
+#define UV3H_NODE_ID_NODE_ID_SHFT 32
+#define UV3H_NODE_ID_ROUTER_SELECT_SHFT 48
+#define UV3H_NODE_ID_RESERVED_2_SHFT 49
+#define UV3H_NODE_ID_NODES_PER_BIT_SHFT 50
+#define UV3H_NODE_ID_NI_PORT_SHFT 57
+#define UV3H_NODE_ID_FORCE1_MASK 0x0000000000000001UL
+#define UV3H_NODE_ID_MANUFACTURER_MASK 0x0000000000000ffeUL
+#define UV3H_NODE_ID_PART_NUMBER_MASK 0x000000000ffff000UL
+#define UV3H_NODE_ID_REVISION_MASK 0x00000000f0000000UL
+#define UV3H_NODE_ID_NODE_ID_MASK 0x00007fff00000000UL
+#define UV3H_NODE_ID_ROUTER_SELECT_MASK 0x0001000000000000UL
+#define UV3H_NODE_ID_RESERVED_2_MASK 0x0002000000000000UL
+#define UV3H_NODE_ID_NODES_PER_BIT_MASK 0x01fc000000000000UL
+#define UV3H_NODE_ID_NI_PORT_MASK 0x3e00000000000000UL
+
union uvh_node_id_u {
unsigned long v;
struct uvh_node_id_s {
@@ -1521,6 +2085,17 @@ union uvh_node_id_u {
unsigned long ni_port:4; /* RO */
unsigned long rsvd_60_63:4;
} s1;
+ struct uvxh_node_id_s {
+ unsigned long force1:1; /* RO */
+ unsigned long manufacturer:11; /* RO */
+ unsigned long part_number:16; /* RO */
+ unsigned long revision:4; /* RO */
+ unsigned long node_id:15; /* RW */
+ unsigned long rsvd_47_49:3;
+ unsigned long nodes_per_bit:7; /* RO */
+ unsigned long ni_port:5; /* RO */
+ unsigned long rsvd_62_63:2;
+ } sx;
struct uv2h_node_id_s {
unsigned long force1:1; /* RO */
unsigned long manufacturer:11; /* RO */
@@ -1532,13 +2107,26 @@ union uvh_node_id_u {
unsigned long ni_port:5; /* RO */
unsigned long rsvd_62_63:2;
} s2;
+ struct uv3h_node_id_s {
+ unsigned long force1:1; /* RO */
+ unsigned long manufacturer:11; /* RO */
+ unsigned long part_number:16; /* RO */
+ unsigned long revision:4; /* RO */
+ unsigned long node_id:15; /* RW */
+ unsigned long rsvd_47:1;
+ unsigned long router_select:1; /* RO */
+ unsigned long rsvd_49:1;
+ unsigned long nodes_per_bit:7; /* RO */
+ unsigned long ni_port:5; /* RO */
+ unsigned long rsvd_62_63:2;
+ } s3;
};
/* ========================================================================= */
/* UVH_NODE_PRESENT_TABLE */
/* ========================================================================= */
-#define UVH_NODE_PRESENT_TABLE 0x1400UL
-#define UVH_NODE_PRESENT_TABLE_DEPTH 16
+#define UVH_NODE_PRESENT_TABLE 0x1400UL
+#define UVH_NODE_PRESENT_TABLE_DEPTH 16
#define UVH_NODE_PRESENT_TABLE_NODES_SHFT 0
#define UVH_NODE_PRESENT_TABLE_NODES_MASK 0xffffffffffffffffUL
@@ -1553,7 +2141,7 @@ union uvh_node_present_table_u {
/* ========================================================================= */
/* UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR */
/* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR 0x16000c8UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR 0x16000c8UL
#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_SHFT 24
#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48
@@ -1577,7 +2165,7 @@ union uvh_rh_gam_alias210_overlay_config_0_mmr_u {
/* ========================================================================= */
/* UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR */
/* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR 0x16000d8UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR 0x16000d8UL
#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_SHFT 24
#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48
@@ -1601,7 +2189,7 @@ union uvh_rh_gam_alias210_overlay_config_1_mmr_u {
/* ========================================================================= */
/* UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR */
/* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR 0x16000e8UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR 0x16000e8UL
#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_SHFT 24
#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48
@@ -1625,7 +2213,7 @@ union uvh_rh_gam_alias210_overlay_config_2_mmr_u {
/* ========================================================================= */
/* UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR */
/* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR 0x16000d0UL
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR 0x16000d0UL
#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT 24
#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_MASK 0x00003fffff000000UL
@@ -1642,7 +2230,7 @@ union uvh_rh_gam_alias210_redirect_config_0_mmr_u {
/* ========================================================================= */
/* UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR */
/* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR 0x16000e0UL
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR 0x16000e0UL
#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_SHFT 24
#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_MASK 0x00003fffff000000UL
@@ -1659,7 +2247,7 @@ union uvh_rh_gam_alias210_redirect_config_1_mmr_u {
/* ========================================================================= */
/* UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR */
/* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR 0x16000f0UL
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR 0x16000f0UL
#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_SHFT 24
#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_MASK 0x00003fffff000000UL
@@ -1676,7 +2264,10 @@ union uvh_rh_gam_alias210_redirect_config_2_mmr_u {
/* ========================================================================= */
/* UVH_RH_GAM_CONFIG_MMR */
/* ========================================================================= */
-#define UVH_RH_GAM_CONFIG_MMR 0x1600000UL
+#define UVH_RH_GAM_CONFIG_MMR 0x1600000UL
+#define UV1H_RH_GAM_CONFIG_MMR 0x1600000UL
+#define UV2H_RH_GAM_CONFIG_MMR 0x1600000UL
+#define UV3H_RH_GAM_CONFIG_MMR 0x1600000UL
#define UVH_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0
#define UVH_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6
@@ -1690,11 +2281,21 @@ union uvh_rh_gam_alias210_redirect_config_2_mmr_u {
#define UV1H_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL
#define UV1H_RH_GAM_CONFIG_MMR_MMIOL_CFG_MASK 0x0000000000001000UL
+#define UVXH_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0
+#define UVXH_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6
+#define UVXH_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL
+#define UVXH_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL
+
#define UV2H_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0
#define UV2H_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6
#define UV2H_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL
#define UV2H_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL
+#define UV3H_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0
+#define UV3H_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6
+#define UV3H_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL
+#define UV3H_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL
+
union uvh_rh_gam_config_mmr_u {
unsigned long v;
struct uvh_rh_gam_config_mmr_s {
@@ -1709,20 +2310,37 @@ union uvh_rh_gam_config_mmr_u {
unsigned long mmiol_cfg:1; /* RW */
unsigned long rsvd_13_63:51;
} s1;
+ struct uvxh_rh_gam_config_mmr_s {
+ unsigned long m_skt:6; /* RW */
+ unsigned long n_skt:4; /* RW */
+ unsigned long rsvd_10_63:54;
+ } sx;
struct uv2h_rh_gam_config_mmr_s {
unsigned long m_skt:6; /* RW */
unsigned long n_skt:4; /* RW */
unsigned long rsvd_10_63:54;
} s2;
+ struct uv3h_rh_gam_config_mmr_s {
+ unsigned long m_skt:6; /* RW */
+ unsigned long n_skt:4; /* RW */
+ unsigned long rsvd_10_63:54;
+ } s3;
};
/* ========================================================================= */
/* UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR */
/* ========================================================================= */
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
+#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
+#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28
#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_SHFT 48
@@ -1733,6 +2351,13 @@ union uvh_rh_gam_config_mmr_u {
#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL
#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28
#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52
#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
@@ -1740,12 +2365,23 @@ union uvh_rh_gam_config_mmr_u {
#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL
#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_MODE_SHFT 62
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_MODE_MASK 0x4000000000000000UL
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
union uvh_rh_gam_gru_overlay_config_mmr_u {
unsigned long v;
struct uvh_rh_gam_gru_overlay_config_mmr_s {
unsigned long rsvd_0_27:28;
unsigned long base:18; /* RW */
- unsigned long rsvd_46_62:17;
+ unsigned long rsvd_46_51:6;
+ unsigned long n_gru:4; /* RW */
+ unsigned long rsvd_56_62:7;
unsigned long enable:1; /* RW */
} s;
struct uv1h_rh_gam_gru_overlay_config_mmr_s {
@@ -1758,6 +2394,14 @@ union uvh_rh_gam_gru_overlay_config_mmr_u {
unsigned long rsvd_56_62:7;
unsigned long enable:1; /* RW */
} s1;
+ struct uvxh_rh_gam_gru_overlay_config_mmr_s {
+ unsigned long rsvd_0_27:28;
+ unsigned long base:18; /* RW */
+ unsigned long rsvd_46_51:6;
+ unsigned long n_gru:4; /* RW */
+ unsigned long rsvd_56_62:7;
+ unsigned long enable:1; /* RW */
+ } sx;
struct uv2h_rh_gam_gru_overlay_config_mmr_s {
unsigned long rsvd_0_27:28;
unsigned long base:18; /* RW */
@@ -1766,12 +2410,22 @@ union uvh_rh_gam_gru_overlay_config_mmr_u {
unsigned long rsvd_56_62:7;
unsigned long enable:1; /* RW */
} s2;
+ struct uv3h_rh_gam_gru_overlay_config_mmr_s {
+ unsigned long rsvd_0_27:28;
+ unsigned long base:18; /* RW */
+ unsigned long rsvd_46_51:6;
+ unsigned long n_gru:4; /* RW */
+ unsigned long rsvd_56_61:6;
+ unsigned long mode:1; /* RW */
+ unsigned long enable:1; /* RW */
+ } s3;
};
/* ========================================================================= */
/* UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR */
/* ========================================================================= */
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR 0x1600030UL
+#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR 0x1600030UL
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR 0x1600030UL
#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 30
#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46
@@ -1814,10 +2468,15 @@ union uvh_rh_gam_mmioh_overlay_config_mmr_u {
/* ========================================================================= */
/* UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR */
/* ========================================================================= */
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
+#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
+#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
+#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
+#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26
+#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL
+#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26
#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_DUAL_HUB_SHFT 46
@@ -1826,11 +2485,21 @@ union uvh_rh_gam_mmioh_overlay_config_mmr_u {
#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_DUAL_HUB_MASK 0x0000400000000000UL
#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26
#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL
#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT 26
+#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL
+#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
union uvh_rh_gam_mmr_overlay_config_mmr_u {
unsigned long v;
struct uvh_rh_gam_mmr_overlay_config_mmr_s {
@@ -1846,18 +2515,30 @@ union uvh_rh_gam_mmr_overlay_config_mmr_u {
unsigned long rsvd_47_62:16;
unsigned long enable:1; /* RW */
} s1;
+ struct uvxh_rh_gam_mmr_overlay_config_mmr_s {
+ unsigned long rsvd_0_25:26;
+ unsigned long base:20; /* RW */
+ unsigned long rsvd_46_62:17;
+ unsigned long enable:1; /* RW */
+ } sx;
struct uv2h_rh_gam_mmr_overlay_config_mmr_s {
unsigned long rsvd_0_25:26;
unsigned long base:20; /* RW */
unsigned long rsvd_46_62:17;
unsigned long enable:1; /* RW */
} s2;
+ struct uv3h_rh_gam_mmr_overlay_config_mmr_s {
+ unsigned long rsvd_0_25:26;
+ unsigned long base:20; /* RW */
+ unsigned long rsvd_46_62:17;
+ unsigned long enable:1; /* RW */
+ } s3;
};
/* ========================================================================= */
/* UVH_RTC */
/* ========================================================================= */
-#define UVH_RTC 0x340000UL
+#define UVH_RTC 0x340000UL
#define UVH_RTC_REAL_TIME_CLOCK_SHFT 0
#define UVH_RTC_REAL_TIME_CLOCK_MASK 0x00ffffffffffffffUL
@@ -1873,7 +2554,7 @@ union uvh_rtc_u {
/* ========================================================================= */
/* UVH_RTC1_INT_CONFIG */
/* ========================================================================= */
-#define UVH_RTC1_INT_CONFIG 0x615c0UL
+#define UVH_RTC1_INT_CONFIG 0x615c0UL
#define UVH_RTC1_INT_CONFIG_VECTOR_SHFT 0
#define UVH_RTC1_INT_CONFIG_DM_SHFT 8
@@ -1911,8 +2592,8 @@ union uvh_rtc1_int_config_u {
/* ========================================================================= */
/* UVH_SCRATCH5 */
/* ========================================================================= */
-#define UVH_SCRATCH5 0x2d0200UL
-#define UVH_SCRATCH5_32 0x778
+#define UVH_SCRATCH5 0x2d0200UL
+#define UVH_SCRATCH5_32 0x778
#define UVH_SCRATCH5_SCRATCH5_SHFT 0
#define UVH_SCRATCH5_SCRATCH5_MASK 0xffffffffffffffffUL
@@ -1925,79 +2606,79 @@ union uvh_scratch5_u {
};
/* ========================================================================= */
-/* UV2H_EVENT_OCCURRED2 */
-/* ========================================================================= */
-#define UV2H_EVENT_OCCURRED2 0x70100UL
-#define UV2H_EVENT_OCCURRED2_32 0xb68
-
-#define UV2H_EVENT_OCCURRED2_RTC_0_SHFT 0
-#define UV2H_EVENT_OCCURRED2_RTC_1_SHFT 1
-#define UV2H_EVENT_OCCURRED2_RTC_2_SHFT 2
-#define UV2H_EVENT_OCCURRED2_RTC_3_SHFT 3
-#define UV2H_EVENT_OCCURRED2_RTC_4_SHFT 4
-#define UV2H_EVENT_OCCURRED2_RTC_5_SHFT 5
-#define UV2H_EVENT_OCCURRED2_RTC_6_SHFT 6
-#define UV2H_EVENT_OCCURRED2_RTC_7_SHFT 7
-#define UV2H_EVENT_OCCURRED2_RTC_8_SHFT 8
-#define UV2H_EVENT_OCCURRED2_RTC_9_SHFT 9
-#define UV2H_EVENT_OCCURRED2_RTC_10_SHFT 10
-#define UV2H_EVENT_OCCURRED2_RTC_11_SHFT 11
-#define UV2H_EVENT_OCCURRED2_RTC_12_SHFT 12
-#define UV2H_EVENT_OCCURRED2_RTC_13_SHFT 13
-#define UV2H_EVENT_OCCURRED2_RTC_14_SHFT 14
-#define UV2H_EVENT_OCCURRED2_RTC_15_SHFT 15
-#define UV2H_EVENT_OCCURRED2_RTC_16_SHFT 16
-#define UV2H_EVENT_OCCURRED2_RTC_17_SHFT 17
-#define UV2H_EVENT_OCCURRED2_RTC_18_SHFT 18
-#define UV2H_EVENT_OCCURRED2_RTC_19_SHFT 19
-#define UV2H_EVENT_OCCURRED2_RTC_20_SHFT 20
-#define UV2H_EVENT_OCCURRED2_RTC_21_SHFT 21
-#define UV2H_EVENT_OCCURRED2_RTC_22_SHFT 22
-#define UV2H_EVENT_OCCURRED2_RTC_23_SHFT 23
-#define UV2H_EVENT_OCCURRED2_RTC_24_SHFT 24
-#define UV2H_EVENT_OCCURRED2_RTC_25_SHFT 25
-#define UV2H_EVENT_OCCURRED2_RTC_26_SHFT 26
-#define UV2H_EVENT_OCCURRED2_RTC_27_SHFT 27
-#define UV2H_EVENT_OCCURRED2_RTC_28_SHFT 28
-#define UV2H_EVENT_OCCURRED2_RTC_29_SHFT 29
-#define UV2H_EVENT_OCCURRED2_RTC_30_SHFT 30
-#define UV2H_EVENT_OCCURRED2_RTC_31_SHFT 31
-#define UV2H_EVENT_OCCURRED2_RTC_0_MASK 0x0000000000000001UL
-#define UV2H_EVENT_OCCURRED2_RTC_1_MASK 0x0000000000000002UL
-#define UV2H_EVENT_OCCURRED2_RTC_2_MASK 0x0000000000000004UL
-#define UV2H_EVENT_OCCURRED2_RTC_3_MASK 0x0000000000000008UL
-#define UV2H_EVENT_OCCURRED2_RTC_4_MASK 0x0000000000000010UL
-#define UV2H_EVENT_OCCURRED2_RTC_5_MASK 0x0000000000000020UL
-#define UV2H_EVENT_OCCURRED2_RTC_6_MASK 0x0000000000000040UL
-#define UV2H_EVENT_OCCURRED2_RTC_7_MASK 0x0000000000000080UL
-#define UV2H_EVENT_OCCURRED2_RTC_8_MASK 0x0000000000000100UL
-#define UV2H_EVENT_OCCURRED2_RTC_9_MASK 0x0000000000000200UL
-#define UV2H_EVENT_OCCURRED2_RTC_10_MASK 0x0000000000000400UL
-#define UV2H_EVENT_OCCURRED2_RTC_11_MASK 0x0000000000000800UL
-#define UV2H_EVENT_OCCURRED2_RTC_12_MASK 0x0000000000001000UL
-#define UV2H_EVENT_OCCURRED2_RTC_13_MASK 0x0000000000002000UL
-#define UV2H_EVENT_OCCURRED2_RTC_14_MASK 0x0000000000004000UL
-#define UV2H_EVENT_OCCURRED2_RTC_15_MASK 0x0000000000008000UL
-#define UV2H_EVENT_OCCURRED2_RTC_16_MASK 0x0000000000010000UL
-#define UV2H_EVENT_OCCURRED2_RTC_17_MASK 0x0000000000020000UL
-#define UV2H_EVENT_OCCURRED2_RTC_18_MASK 0x0000000000040000UL
-#define UV2H_EVENT_OCCURRED2_RTC_19_MASK 0x0000000000080000UL
-#define UV2H_EVENT_OCCURRED2_RTC_20_MASK 0x0000000000100000UL
-#define UV2H_EVENT_OCCURRED2_RTC_21_MASK 0x0000000000200000UL
-#define UV2H_EVENT_OCCURRED2_RTC_22_MASK 0x0000000000400000UL
-#define UV2H_EVENT_OCCURRED2_RTC_23_MASK 0x0000000000800000UL
-#define UV2H_EVENT_OCCURRED2_RTC_24_MASK 0x0000000001000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_25_MASK 0x0000000002000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_26_MASK 0x0000000004000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_27_MASK 0x0000000008000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_28_MASK 0x0000000010000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_29_MASK 0x0000000020000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_30_MASK 0x0000000040000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_31_MASK 0x0000000080000000UL
-
-union uv2h_event_occurred2_u {
+/* UVXH_EVENT_OCCURRED2 */
+/* ========================================================================= */
+#define UVXH_EVENT_OCCURRED2 0x70100UL
+#define UVXH_EVENT_OCCURRED2_32 0xb68
+
+#define UVXH_EVENT_OCCURRED2_RTC_0_SHFT 0
+#define UVXH_EVENT_OCCURRED2_RTC_1_SHFT 1
+#define UVXH_EVENT_OCCURRED2_RTC_2_SHFT 2
+#define UVXH_EVENT_OCCURRED2_RTC_3_SHFT 3
+#define UVXH_EVENT_OCCURRED2_RTC_4_SHFT 4
+#define UVXH_EVENT_OCCURRED2_RTC_5_SHFT 5
+#define UVXH_EVENT_OCCURRED2_RTC_6_SHFT 6
+#define UVXH_EVENT_OCCURRED2_RTC_7_SHFT 7
+#define UVXH_EVENT_OCCURRED2_RTC_8_SHFT 8
+#define UVXH_EVENT_OCCURRED2_RTC_9_SHFT 9
+#define UVXH_EVENT_OCCURRED2_RTC_10_SHFT 10
+#define UVXH_EVENT_OCCURRED2_RTC_11_SHFT 11
+#define UVXH_EVENT_OCCURRED2_RTC_12_SHFT 12
+#define UVXH_EVENT_OCCURRED2_RTC_13_SHFT 13
+#define UVXH_EVENT_OCCURRED2_RTC_14_SHFT 14
+#define UVXH_EVENT_OCCURRED2_RTC_15_SHFT 15
+#define UVXH_EVENT_OCCURRED2_RTC_16_SHFT 16
+#define UVXH_EVENT_OCCURRED2_RTC_17_SHFT 17
+#define UVXH_EVENT_OCCURRED2_RTC_18_SHFT 18
+#define UVXH_EVENT_OCCURRED2_RTC_19_SHFT 19
+#define UVXH_EVENT_OCCURRED2_RTC_20_SHFT 20
+#define UVXH_EVENT_OCCURRED2_RTC_21_SHFT 21
+#define UVXH_EVENT_OCCURRED2_RTC_22_SHFT 22
+#define UVXH_EVENT_OCCURRED2_RTC_23_SHFT 23
+#define UVXH_EVENT_OCCURRED2_RTC_24_SHFT 24
+#define UVXH_EVENT_OCCURRED2_RTC_25_SHFT 25
+#define UVXH_EVENT_OCCURRED2_RTC_26_SHFT 26
+#define UVXH_EVENT_OCCURRED2_RTC_27_SHFT 27
+#define UVXH_EVENT_OCCURRED2_RTC_28_SHFT 28
+#define UVXH_EVENT_OCCURRED2_RTC_29_SHFT 29
+#define UVXH_EVENT_OCCURRED2_RTC_30_SHFT 30
+#define UVXH_EVENT_OCCURRED2_RTC_31_SHFT 31
+#define UVXH_EVENT_OCCURRED2_RTC_0_MASK 0x0000000000000001UL
+#define UVXH_EVENT_OCCURRED2_RTC_1_MASK 0x0000000000000002UL
+#define UVXH_EVENT_OCCURRED2_RTC_2_MASK 0x0000000000000004UL
+#define UVXH_EVENT_OCCURRED2_RTC_3_MASK 0x0000000000000008UL
+#define UVXH_EVENT_OCCURRED2_RTC_4_MASK 0x0000000000000010UL
+#define UVXH_EVENT_OCCURRED2_RTC_5_MASK 0x0000000000000020UL
+#define UVXH_EVENT_OCCURRED2_RTC_6_MASK 0x0000000000000040UL
+#define UVXH_EVENT_OCCURRED2_RTC_7_MASK 0x0000000000000080UL
+#define UVXH_EVENT_OCCURRED2_RTC_8_MASK 0x0000000000000100UL
+#define UVXH_EVENT_OCCURRED2_RTC_9_MASK 0x0000000000000200UL
+#define UVXH_EVENT_OCCURRED2_RTC_10_MASK 0x0000000000000400UL
+#define UVXH_EVENT_OCCURRED2_RTC_11_MASK 0x0000000000000800UL
+#define UVXH_EVENT_OCCURRED2_RTC_12_MASK 0x0000000000001000UL
+#define UVXH_EVENT_OCCURRED2_RTC_13_MASK 0x0000000000002000UL
+#define UVXH_EVENT_OCCURRED2_RTC_14_MASK 0x0000000000004000UL
+#define UVXH_EVENT_OCCURRED2_RTC_15_MASK 0x0000000000008000UL
+#define UVXH_EVENT_OCCURRED2_RTC_16_MASK 0x0000000000010000UL
+#define UVXH_EVENT_OCCURRED2_RTC_17_MASK 0x0000000000020000UL
+#define UVXH_EVENT_OCCURRED2_RTC_18_MASK 0x0000000000040000UL
+#define UVXH_EVENT_OCCURRED2_RTC_19_MASK 0x0000000000080000UL
+#define UVXH_EVENT_OCCURRED2_RTC_20_MASK 0x0000000000100000UL
+#define UVXH_EVENT_OCCURRED2_RTC_21_MASK 0x0000000000200000UL
+#define UVXH_EVENT_OCCURRED2_RTC_22_MASK 0x0000000000400000UL
+#define UVXH_EVENT_OCCURRED2_RTC_23_MASK 0x0000000000800000UL
+#define UVXH_EVENT_OCCURRED2_RTC_24_MASK 0x0000000001000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_25_MASK 0x0000000002000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_26_MASK 0x0000000004000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_27_MASK 0x0000000008000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_28_MASK 0x0000000010000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_29_MASK 0x0000000020000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_30_MASK 0x0000000040000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_31_MASK 0x0000000080000000UL
+
+union uvxh_event_occurred2_u {
unsigned long v;
- struct uv2h_event_occurred2_s {
+ struct uvxh_event_occurred2_s {
unsigned long rtc_0:1; /* RW */
unsigned long rtc_1:1; /* RW */
unsigned long rtc_2:1; /* RW */
@@ -2031,29 +2712,46 @@ union uv2h_event_occurred2_u {
unsigned long rtc_30:1; /* RW */
unsigned long rtc_31:1; /* RW */
unsigned long rsvd_32_63:32;
- } s1;
+ } sx;
};
/* ========================================================================= */
-/* UV2H_EVENT_OCCURRED2_ALIAS */
+/* UVXH_EVENT_OCCURRED2_ALIAS */
/* ========================================================================= */
-#define UV2H_EVENT_OCCURRED2_ALIAS 0x70108UL
-#define UV2H_EVENT_OCCURRED2_ALIAS_32 0xb70
+#define UVXH_EVENT_OCCURRED2_ALIAS 0x70108UL
+#define UVXH_EVENT_OCCURRED2_ALIAS_32 0xb70
+
/* ========================================================================= */
-/* UV2H_LB_BAU_SB_ACTIVATION_STATUS_2 */
+/* UVXH_LB_BAU_SB_ACTIVATION_STATUS_2 */
/* ========================================================================= */
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x9f0
+#define UVXH_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL
+#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL
+#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL
+#define UVXH_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x9f0
+#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x320130UL
+#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x320130UL
+
+#define UVXH_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
+#define UVXH_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
-union uv2h_lb_bau_sb_activation_status_2_u {
+#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
+#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
+
+union uvxh_lb_bau_sb_activation_status_2_u {
unsigned long v;
+ struct uvxh_lb_bau_sb_activation_status_2_s {
+ unsigned long aux_error:64; /* RW */
+ } sx;
struct uv2h_lb_bau_sb_activation_status_2_s {
unsigned long aux_error:64; /* RW */
- } s1;
+ } s2;
+ struct uv3h_lb_bau_sb_activation_status_2_s {
+ unsigned long aux_error:64; /* RW */
+ } s3;
};
/* ========================================================================= */
@@ -2073,5 +2771,87 @@ union uv1h_lb_target_physical_apic_id_mask_u {
} s1;
};
+/* ========================================================================= */
+/* UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR */
+/* ========================================================================= */
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR 0x1603000UL
+
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_SHFT 26
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT 46
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_SHFT 63
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_MASK 0x00003ffffc000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_MASK 0x000fc00000000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uv3h_rh_gam_mmioh_overlay_config0_mmr_u {
+ unsigned long v;
+ struct uv3h_rh_gam_mmioh_overlay_config0_mmr_s {
+ unsigned long rsvd_0_25:26;
+ unsigned long base:20; /* RW */
+ unsigned long m_io:6; /* RW */
+ unsigned long n_io:4;
+ unsigned long rsvd_56_62:7;
+ unsigned long enable:1; /* RW */
+ } s3;
+};
+
+/* ========================================================================= */
+/* UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR */
+/* ========================================================================= */
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR 0x1604000UL
+
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_SHFT 26
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT 46
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_ENABLE_SHFT 63
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_MASK 0x00003ffffc000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_MASK 0x000fc00000000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uv3h_rh_gam_mmioh_overlay_config1_mmr_u {
+ unsigned long v;
+ struct uv3h_rh_gam_mmioh_overlay_config1_mmr_s {
+ unsigned long rsvd_0_25:26;
+ unsigned long base:20; /* RW */
+ unsigned long m_io:6; /* RW */
+ unsigned long n_io:4;
+ unsigned long rsvd_56_62:7;
+ unsigned long enable:1; /* RW */
+ } s3;
+};
+
+/* ========================================================================= */
+/* UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR */
+/* ========================================================================= */
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR 0x1603800UL
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH 128
+
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_SHFT 0
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_MASK 0x0000000000007fffUL
+
+union uv3h_rh_gam_mmioh_redirect_config0_mmr_u {
+ unsigned long v;
+ struct uv3h_rh_gam_mmioh_redirect_config0_mmr_s {
+ unsigned long nasid:15; /* RW */
+ unsigned long rsvd_15_63:49;
+ } s3;
+};
+
+/* ========================================================================= */
+/* UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR */
+/* ========================================================================= */
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR 0x1604800UL
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH 128
+
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_SHFT 0
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_MASK 0x0000000000007fffUL
+
+union uv3h_rh_gam_mmioh_redirect_config1_mmr_u {
+ unsigned long v;
+ struct uv3h_rh_gam_mmioh_redirect_config1_mmr_s {
+ unsigned long nasid:15; /* RW */
+ unsigned long rsvd_15_63:49;
+ } s3;
+};
+
#endif /* _ASM_X86_UV_UV_MMRS_H */
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 235b49fa554b..b6fbf860e398 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -57,9 +57,12 @@
#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
#define SECONDARY_EXEC_ENABLE_EPT 0x00000002
#define SECONDARY_EXEC_RDTSCP 0x00000008
+#define SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE 0x00000010
#define SECONDARY_EXEC_ENABLE_VPID 0x00000020
#define SECONDARY_EXEC_WBINVD_EXITING 0x00000040
#define SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080
+#define SECONDARY_EXEC_APIC_REGISTER_VIRT 0x00000100
+#define SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY 0x00000200
#define SECONDARY_EXEC_PAUSE_LOOP_EXITING 0x00000400
#define SECONDARY_EXEC_ENABLE_INVPCID 0x00001000
@@ -97,6 +100,7 @@ enum vmcs_field {
GUEST_GS_SELECTOR = 0x0000080a,
GUEST_LDTR_SELECTOR = 0x0000080c,
GUEST_TR_SELECTOR = 0x0000080e,
+ GUEST_INTR_STATUS = 0x00000810,
HOST_ES_SELECTOR = 0x00000c00,
HOST_CS_SELECTOR = 0x00000c02,
HOST_SS_SELECTOR = 0x00000c04,
@@ -124,6 +128,14 @@ enum vmcs_field {
APIC_ACCESS_ADDR_HIGH = 0x00002015,
EPT_POINTER = 0x0000201a,
EPT_POINTER_HIGH = 0x0000201b,
+ EOI_EXIT_BITMAP0 = 0x0000201c,
+ EOI_EXIT_BITMAP0_HIGH = 0x0000201d,
+ EOI_EXIT_BITMAP1 = 0x0000201e,
+ EOI_EXIT_BITMAP1_HIGH = 0x0000201f,
+ EOI_EXIT_BITMAP2 = 0x00002020,
+ EOI_EXIT_BITMAP2_HIGH = 0x00002021,
+ EOI_EXIT_BITMAP3 = 0x00002022,
+ EOI_EXIT_BITMAP3_HIGH = 0x00002023,
GUEST_PHYSICAL_ADDRESS = 0x00002400,
GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401,
VMCS_LINK_POINTER = 0x00002800,
@@ -346,9 +358,9 @@ enum vmcs_field {
#define AR_RESERVD_MASK 0xfffe0f00
-#define TSS_PRIVATE_MEMSLOT (KVM_MEMORY_SLOTS + 0)
-#define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (KVM_MEMORY_SLOTS + 1)
-#define IDENTITY_PAGETABLE_PRIVATE_MEMSLOT (KVM_MEMORY_SLOTS + 2)
+#define TSS_PRIVATE_MEMSLOT (KVM_USER_MEM_SLOTS + 0)
+#define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (KVM_USER_MEM_SLOTS + 1)
+#define IDENTITY_PAGETABLE_PRIVATE_MEMSLOT (KVM_USER_MEM_SLOTS + 2)
#define VMX_NR_VPIDS (1 << 16)
#define VMX_VPID_EXTENT_SINGLE_CONTEXT 1
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 57693498519c..d8d99222b36a 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -69,17 +69,6 @@ struct x86_init_oem {
};
/**
- * struct x86_init_mapping - platform specific initial kernel pagetable setup
- * @pagetable_reserve: reserve a range of addresses for kernel pagetable usage
- *
- * For more details on the purpose of this hook, look in
- * init_memory_mapping and the commit that added it.
- */
-struct x86_init_mapping {
- void (*pagetable_reserve)(u64 start, u64 end);
-};
-
-/**
* struct x86_init_paging - platform specific paging functions
* @pagetable_init: platform specific paging initialization call to setup
* the kernel pagetables and prepare accessors functions.
@@ -136,7 +125,6 @@ struct x86_init_ops {
struct x86_init_mpparse mpparse;
struct x86_init_irqs irqs;
struct x86_init_oem oem;
- struct x86_init_mapping mapping;
struct x86_init_paging paging;
struct x86_init_timers timers;
struct x86_init_iommu iommu;
@@ -181,19 +169,38 @@ struct x86_platform_ops {
};
struct pci_dev;
+struct msi_msg;
struct x86_msi_ops {
int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
+ void (*compose_msi_msg)(struct pci_dev *dev, unsigned int irq,
+ unsigned int dest, struct msi_msg *msg,
+ u8 hpet_id);
void (*teardown_msi_irq)(unsigned int irq);
void (*teardown_msi_irqs)(struct pci_dev *dev);
void (*restore_msi_irqs)(struct pci_dev *dev, int irq);
+ int (*setup_hpet_msi)(unsigned int irq, unsigned int id);
};
+struct IO_APIC_route_entry;
+struct io_apic_irq_attr;
+struct irq_data;
+struct cpumask;
+
struct x86_io_apic_ops {
- void (*init) (void);
- unsigned int (*read) (unsigned int apic, unsigned int reg);
- void (*write) (unsigned int apic, unsigned int reg, unsigned int value);
- void (*modify)(unsigned int apic, unsigned int reg, unsigned int value);
+ void (*init) (void);
+ unsigned int (*read) (unsigned int apic, unsigned int reg);
+ void (*write) (unsigned int apic, unsigned int reg, unsigned int value);
+ void (*modify) (unsigned int apic, unsigned int reg, unsigned int value);
+ void (*disable)(void);
+ void (*print_entries)(unsigned int apic, unsigned int nr_entries);
+ int (*set_affinity)(struct irq_data *data,
+ const struct cpumask *mask,
+ bool force);
+ int (*setup_entry)(int irq, struct IO_APIC_route_entry *entry,
+ unsigned int destination, int vector,
+ struct io_apic_irq_attr *attr);
+ void (*eoi_ioapic_pin)(int apic, int pin, int vector);
};
extern struct x86_init_ops x86_init;
diff --git a/arch/x86/include/asm/xen/events.h b/arch/x86/include/asm/xen/events.h
index cc146d51449e..ca842f2769ef 100644
--- a/arch/x86/include/asm/xen/events.h
+++ b/arch/x86/include/asm/xen/events.h
@@ -16,4 +16,7 @@ static inline int xen_irqs_disabled(struct pt_regs *regs)
return raw_irqs_disabled_flags(regs->flags);
}
+/* No need for a barrier -- XCHG is a barrier on x86. */
+#define xchg_xen_ulong(ptr, val) xchg((ptr), (val))
+
#endif /* _ASM_X86_XEN_EVENTS_H */
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index 472b9b783019..6aef9fbc09b7 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -212,4 +212,6 @@ unsigned long arbitrary_virt_to_mfn(void *vaddr);
void make_lowmem_page_readonly(void *vaddr);
void make_lowmem_page_readwrite(void *vaddr);
+#define xen_remap(cookie, size) ioremap((cookie), (size));
+
#endif /* _ASM_X86_XEN_PAGE_H */
diff --git a/arch/x86/include/asm/xor.h b/arch/x86/include/asm/xor.h
index f8fde90bc45e..d8829751b3f8 100644
--- a/arch/x86/include/asm/xor.h
+++ b/arch/x86/include/asm/xor.h
@@ -1,10 +1,499 @@
#ifdef CONFIG_KMEMCHECK
/* kmemcheck doesn't handle MMX/SSE/SSE2 instructions */
# include <asm-generic/xor.h>
+#elif !defined(_ASM_X86_XOR_H)
+#define _ASM_X86_XOR_H
+
+/*
+ * Optimized RAID-5 checksumming functions for SSE.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Cache avoiding checksumming functions utilizing KNI instructions
+ * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
+ */
+
+/*
+ * Based on
+ * High-speed RAID5 checksumming functions utilizing SSE instructions.
+ * Copyright (C) 1998 Ingo Molnar.
+ */
+
+/*
+ * x86-64 changes / gcc fixes from Andi Kleen.
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ *
+ * This hasn't been optimized for the hammer yet, but there are likely
+ * no advantages to be gotten from x86-64 here anyways.
+ */
+
+#include <asm/i387.h>
+
+#ifdef CONFIG_X86_32
+/* reduce register pressure */
+# define XOR_CONSTANT_CONSTRAINT "i"
#else
+# define XOR_CONSTANT_CONSTRAINT "re"
+#endif
+
+#define OFFS(x) "16*("#x")"
+#define PF_OFFS(x) "256+16*("#x")"
+#define PF0(x) " prefetchnta "PF_OFFS(x)"(%[p1]) ;\n"
+#define LD(x, y) " movaps "OFFS(x)"(%[p1]), %%xmm"#y" ;\n"
+#define ST(x, y) " movaps %%xmm"#y", "OFFS(x)"(%[p1]) ;\n"
+#define PF1(x) " prefetchnta "PF_OFFS(x)"(%[p2]) ;\n"
+#define PF2(x) " prefetchnta "PF_OFFS(x)"(%[p3]) ;\n"
+#define PF3(x) " prefetchnta "PF_OFFS(x)"(%[p4]) ;\n"
+#define PF4(x) " prefetchnta "PF_OFFS(x)"(%[p5]) ;\n"
+#define XO1(x, y) " xorps "OFFS(x)"(%[p2]), %%xmm"#y" ;\n"
+#define XO2(x, y) " xorps "OFFS(x)"(%[p3]), %%xmm"#y" ;\n"
+#define XO3(x, y) " xorps "OFFS(x)"(%[p4]), %%xmm"#y" ;\n"
+#define XO4(x, y) " xorps "OFFS(x)"(%[p5]), %%xmm"#y" ;\n"
+#define NOP(x)
+
+#define BLK64(pf, op, i) \
+ pf(i) \
+ op(i, 0) \
+ op(i + 1, 1) \
+ op(i + 2, 2) \
+ op(i + 3, 3)
+
+static void
+xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+ unsigned long lines = bytes >> 8;
+
+ kernel_fpu_begin();
+
+ asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+ LD(i, 0) \
+ LD(i + 1, 1) \
+ PF1(i) \
+ PF1(i + 2) \
+ LD(i + 2, 2) \
+ LD(i + 3, 3) \
+ PF0(i + 4) \
+ PF0(i + 6) \
+ XO1(i, 0) \
+ XO1(i + 1, 1) \
+ XO1(i + 2, 2) \
+ XO1(i + 3, 3) \
+ ST(i, 0) \
+ ST(i + 1, 1) \
+ ST(i + 2, 2) \
+ ST(i + 3, 3) \
+
+
+ PF0(0)
+ PF0(2)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " add %[inc], %[p1] ;\n"
+ " add %[inc], %[p2] ;\n"
+ " dec %[cnt] ;\n"
+ " jnz 1b ;\n"
+ : [cnt] "+r" (lines),
+ [p1] "+r" (p1), [p2] "+r" (p2)
+ : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+ : "memory");
+
+ kernel_fpu_end();
+}
+
+static void
+xor_sse_2_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+ unsigned long lines = bytes >> 8;
+
+ kernel_fpu_begin();
+
+ asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+ BLK64(PF0, LD, i) \
+ BLK64(PF1, XO1, i) \
+ BLK64(NOP, ST, i) \
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " add %[inc], %[p1] ;\n"
+ " add %[inc], %[p2] ;\n"
+ " dec %[cnt] ;\n"
+ " jnz 1b ;\n"
+ : [cnt] "+r" (lines),
+ [p1] "+r" (p1), [p2] "+r" (p2)
+ : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+ : "memory");
+
+ kernel_fpu_end();
+}
+
+static void
+xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3)
+{
+ unsigned long lines = bytes >> 8;
+
+ kernel_fpu_begin();
+
+ asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+ PF1(i) \
+ PF1(i + 2) \
+ LD(i, 0) \
+ LD(i + 1, 1) \
+ LD(i + 2, 2) \
+ LD(i + 3, 3) \
+ PF2(i) \
+ PF2(i + 2) \
+ PF0(i + 4) \
+ PF0(i + 6) \
+ XO1(i, 0) \
+ XO1(i + 1, 1) \
+ XO1(i + 2, 2) \
+ XO1(i + 3, 3) \
+ XO2(i, 0) \
+ XO2(i + 1, 1) \
+ XO2(i + 2, 2) \
+ XO2(i + 3, 3) \
+ ST(i, 0) \
+ ST(i + 1, 1) \
+ ST(i + 2, 2) \
+ ST(i + 3, 3) \
+
+
+ PF0(0)
+ PF0(2)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " add %[inc], %[p1] ;\n"
+ " add %[inc], %[p2] ;\n"
+ " add %[inc], %[p3] ;\n"
+ " dec %[cnt] ;\n"
+ " jnz 1b ;\n"
+ : [cnt] "+r" (lines),
+ [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
+ : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+ : "memory");
+
+ kernel_fpu_end();
+}
+
+static void
+xor_sse_3_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3)
+{
+ unsigned long lines = bytes >> 8;
+
+ kernel_fpu_begin();
+
+ asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+ BLK64(PF0, LD, i) \
+ BLK64(PF1, XO1, i) \
+ BLK64(PF2, XO2, i) \
+ BLK64(NOP, ST, i) \
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " add %[inc], %[p1] ;\n"
+ " add %[inc], %[p2] ;\n"
+ " add %[inc], %[p3] ;\n"
+ " dec %[cnt] ;\n"
+ " jnz 1b ;\n"
+ : [cnt] "+r" (lines),
+ [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
+ : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+ : "memory");
+
+ kernel_fpu_end();
+}
+
+static void
+xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4)
+{
+ unsigned long lines = bytes >> 8;
+
+ kernel_fpu_begin();
+
+ asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+ PF1(i) \
+ PF1(i + 2) \
+ LD(i, 0) \
+ LD(i + 1, 1) \
+ LD(i + 2, 2) \
+ LD(i + 3, 3) \
+ PF2(i) \
+ PF2(i + 2) \
+ XO1(i, 0) \
+ XO1(i + 1, 1) \
+ XO1(i + 2, 2) \
+ XO1(i + 3, 3) \
+ PF3(i) \
+ PF3(i + 2) \
+ PF0(i + 4) \
+ PF0(i + 6) \
+ XO2(i, 0) \
+ XO2(i + 1, 1) \
+ XO2(i + 2, 2) \
+ XO2(i + 3, 3) \
+ XO3(i, 0) \
+ XO3(i + 1, 1) \
+ XO3(i + 2, 2) \
+ XO3(i + 3, 3) \
+ ST(i, 0) \
+ ST(i + 1, 1) \
+ ST(i + 2, 2) \
+ ST(i + 3, 3) \
+
+
+ PF0(0)
+ PF0(2)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " add %[inc], %[p1] ;\n"
+ " add %[inc], %[p2] ;\n"
+ " add %[inc], %[p3] ;\n"
+ " add %[inc], %[p4] ;\n"
+ " dec %[cnt] ;\n"
+ " jnz 1b ;\n"
+ : [cnt] "+r" (lines), [p1] "+r" (p1),
+ [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4)
+ : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+ : "memory");
+
+ kernel_fpu_end();
+}
+
+static void
+xor_sse_4_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4)
+{
+ unsigned long lines = bytes >> 8;
+
+ kernel_fpu_begin();
+
+ asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+ BLK64(PF0, LD, i) \
+ BLK64(PF1, XO1, i) \
+ BLK64(PF2, XO2, i) \
+ BLK64(PF3, XO3, i) \
+ BLK64(NOP, ST, i) \
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " add %[inc], %[p1] ;\n"
+ " add %[inc], %[p2] ;\n"
+ " add %[inc], %[p3] ;\n"
+ " add %[inc], %[p4] ;\n"
+ " dec %[cnt] ;\n"
+ " jnz 1b ;\n"
+ : [cnt] "+r" (lines), [p1] "+r" (p1),
+ [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4)
+ : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+ : "memory");
+
+ kernel_fpu_end();
+}
+
+static void
+xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+ unsigned long lines = bytes >> 8;
+
+ kernel_fpu_begin();
+
+ asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+ PF1(i) \
+ PF1(i + 2) \
+ LD(i, 0) \
+ LD(i + 1, 1) \
+ LD(i + 2, 2) \
+ LD(i + 3, 3) \
+ PF2(i) \
+ PF2(i + 2) \
+ XO1(i, 0) \
+ XO1(i + 1, 1) \
+ XO1(i + 2, 2) \
+ XO1(i + 3, 3) \
+ PF3(i) \
+ PF3(i + 2) \
+ XO2(i, 0) \
+ XO2(i + 1, 1) \
+ XO2(i + 2, 2) \
+ XO2(i + 3, 3) \
+ PF4(i) \
+ PF4(i + 2) \
+ PF0(i + 4) \
+ PF0(i + 6) \
+ XO3(i, 0) \
+ XO3(i + 1, 1) \
+ XO3(i + 2, 2) \
+ XO3(i + 3, 3) \
+ XO4(i, 0) \
+ XO4(i + 1, 1) \
+ XO4(i + 2, 2) \
+ XO4(i + 3, 3) \
+ ST(i, 0) \
+ ST(i + 1, 1) \
+ ST(i + 2, 2) \
+ ST(i + 3, 3) \
+
+
+ PF0(0)
+ PF0(2)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " add %[inc], %[p1] ;\n"
+ " add %[inc], %[p2] ;\n"
+ " add %[inc], %[p3] ;\n"
+ " add %[inc], %[p4] ;\n"
+ " add %[inc], %[p5] ;\n"
+ " dec %[cnt] ;\n"
+ " jnz 1b ;\n"
+ : [cnt] "+r" (lines), [p1] "+r" (p1), [p2] "+r" (p2),
+ [p3] "+r" (p3), [p4] "+r" (p4), [p5] "+r" (p5)
+ : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+ : "memory");
+
+ kernel_fpu_end();
+}
+
+static void
+xor_sse_5_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+ unsigned long lines = bytes >> 8;
+
+ kernel_fpu_begin();
+
+ asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+ BLK64(PF0, LD, i) \
+ BLK64(PF1, XO1, i) \
+ BLK64(PF2, XO2, i) \
+ BLK64(PF3, XO3, i) \
+ BLK64(PF4, XO4, i) \
+ BLK64(NOP, ST, i) \
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " add %[inc], %[p1] ;\n"
+ " add %[inc], %[p2] ;\n"
+ " add %[inc], %[p3] ;\n"
+ " add %[inc], %[p4] ;\n"
+ " add %[inc], %[p5] ;\n"
+ " dec %[cnt] ;\n"
+ " jnz 1b ;\n"
+ : [cnt] "+r" (lines), [p1] "+r" (p1), [p2] "+r" (p2),
+ [p3] "+r" (p3), [p4] "+r" (p4), [p5] "+r" (p5)
+ : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+ : "memory");
+
+ kernel_fpu_end();
+}
+
+static struct xor_block_template xor_block_sse_pf64 = {
+ .name = "prefetch64-sse",
+ .do_2 = xor_sse_2_pf64,
+ .do_3 = xor_sse_3_pf64,
+ .do_4 = xor_sse_4_pf64,
+ .do_5 = xor_sse_5_pf64,
+};
+
+#undef LD
+#undef XO1
+#undef XO2
+#undef XO3
+#undef XO4
+#undef ST
+#undef NOP
+#undef BLK64
+#undef BLOCK
+
+#undef XOR_CONSTANT_CONSTRAINT
+
#ifdef CONFIG_X86_32
# include <asm/xor_32.h>
#else
# include <asm/xor_64.h>
#endif
-#endif
+
+#define XOR_SELECT_TEMPLATE(FASTEST) \
+ AVX_SELECT(FASTEST)
+
+#endif /* _ASM_X86_XOR_H */
diff --git a/arch/x86/include/asm/xor_32.h b/arch/x86/include/asm/xor_32.h
index f79cb7ec0e06..ce05722e3c68 100644
--- a/arch/x86/include/asm/xor_32.h
+++ b/arch/x86/include/asm/xor_32.h
@@ -2,7 +2,7 @@
#define _ASM_X86_XOR_32_H
/*
- * Optimized RAID-5 checksumming functions for MMX and SSE.
+ * Optimized RAID-5 checksumming functions for MMX.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -529,290 +529,6 @@ static struct xor_block_template xor_block_p5_mmx = {
.do_5 = xor_p5_mmx_5,
};
-/*
- * Cache avoiding checksumming functions utilizing KNI instructions
- * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
- */
-
-#define OFFS(x) "16*("#x")"
-#define PF_OFFS(x) "256+16*("#x")"
-#define PF0(x) " prefetchnta "PF_OFFS(x)"(%1) ;\n"
-#define LD(x, y) " movaps "OFFS(x)"(%1), %%xmm"#y" ;\n"
-#define ST(x, y) " movaps %%xmm"#y", "OFFS(x)"(%1) ;\n"
-#define PF1(x) " prefetchnta "PF_OFFS(x)"(%2) ;\n"
-#define PF2(x) " prefetchnta "PF_OFFS(x)"(%3) ;\n"
-#define PF3(x) " prefetchnta "PF_OFFS(x)"(%4) ;\n"
-#define PF4(x) " prefetchnta "PF_OFFS(x)"(%5) ;\n"
-#define PF5(x) " prefetchnta "PF_OFFS(x)"(%6) ;\n"
-#define XO1(x, y) " xorps "OFFS(x)"(%2), %%xmm"#y" ;\n"
-#define XO2(x, y) " xorps "OFFS(x)"(%3), %%xmm"#y" ;\n"
-#define XO3(x, y) " xorps "OFFS(x)"(%4), %%xmm"#y" ;\n"
-#define XO4(x, y) " xorps "OFFS(x)"(%5), %%xmm"#y" ;\n"
-#define XO5(x, y) " xorps "OFFS(x)"(%6), %%xmm"#y" ;\n"
-
-
-static void
-xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
-{
- unsigned long lines = bytes >> 8;
-
- kernel_fpu_begin();
-
- asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
- LD(i, 0) \
- LD(i + 1, 1) \
- PF1(i) \
- PF1(i + 2) \
- LD(i + 2, 2) \
- LD(i + 3, 3) \
- PF0(i + 4) \
- PF0(i + 6) \
- XO1(i, 0) \
- XO1(i + 1, 1) \
- XO1(i + 2, 2) \
- XO1(i + 3, 3) \
- ST(i, 0) \
- ST(i + 1, 1) \
- ST(i + 2, 2) \
- ST(i + 3, 3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addl $256, %1 ;\n"
- " addl $256, %2 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
- : "+r" (lines),
- "+r" (p1), "+r" (p2)
- :
- : "memory");
-
- kernel_fpu_end();
-}
-
-static void
-xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3)
-{
- unsigned long lines = bytes >> 8;
-
- kernel_fpu_begin();
-
- asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
- PF1(i) \
- PF1(i + 2) \
- LD(i,0) \
- LD(i + 1, 1) \
- LD(i + 2, 2) \
- LD(i + 3, 3) \
- PF2(i) \
- PF2(i + 2) \
- PF0(i + 4) \
- PF0(i + 6) \
- XO1(i,0) \
- XO1(i + 1, 1) \
- XO1(i + 2, 2) \
- XO1(i + 3, 3) \
- XO2(i,0) \
- XO2(i + 1, 1) \
- XO2(i + 2, 2) \
- XO2(i + 3, 3) \
- ST(i,0) \
- ST(i + 1, 1) \
- ST(i + 2, 2) \
- ST(i + 3, 3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addl $256, %1 ;\n"
- " addl $256, %2 ;\n"
- " addl $256, %3 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
- : "+r" (lines),
- "+r" (p1), "+r"(p2), "+r"(p3)
- :
- : "memory" );
-
- kernel_fpu_end();
-}
-
-static void
-xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3, unsigned long *p4)
-{
- unsigned long lines = bytes >> 8;
-
- kernel_fpu_begin();
-
- asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
- PF1(i) \
- PF1(i + 2) \
- LD(i,0) \
- LD(i + 1, 1) \
- LD(i + 2, 2) \
- LD(i + 3, 3) \
- PF2(i) \
- PF2(i + 2) \
- XO1(i,0) \
- XO1(i + 1, 1) \
- XO1(i + 2, 2) \
- XO1(i + 3, 3) \
- PF3(i) \
- PF3(i + 2) \
- PF0(i + 4) \
- PF0(i + 6) \
- XO2(i,0) \
- XO2(i + 1, 1) \
- XO2(i + 2, 2) \
- XO2(i + 3, 3) \
- XO3(i,0) \
- XO3(i + 1, 1) \
- XO3(i + 2, 2) \
- XO3(i + 3, 3) \
- ST(i,0) \
- ST(i + 1, 1) \
- ST(i + 2, 2) \
- ST(i + 3, 3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addl $256, %1 ;\n"
- " addl $256, %2 ;\n"
- " addl $256, %3 ;\n"
- " addl $256, %4 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
- : "+r" (lines),
- "+r" (p1), "+r" (p2), "+r" (p3), "+r" (p4)
- :
- : "memory" );
-
- kernel_fpu_end();
-}
-
-static void
-xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3, unsigned long *p4, unsigned long *p5)
-{
- unsigned long lines = bytes >> 8;
-
- kernel_fpu_begin();
-
- /* Make sure GCC forgets anything it knows about p4 or p5,
- such that it won't pass to the asm volatile below a
- register that is shared with any other variable. That's
- because we modify p4 and p5 there, but we can't mark them
- as read/write, otherwise we'd overflow the 10-asm-operands
- limit of GCC < 3.1. */
- asm("" : "+r" (p4), "+r" (p5));
-
- asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
- PF1(i) \
- PF1(i + 2) \
- LD(i,0) \
- LD(i + 1, 1) \
- LD(i + 2, 2) \
- LD(i + 3, 3) \
- PF2(i) \
- PF2(i + 2) \
- XO1(i,0) \
- XO1(i + 1, 1) \
- XO1(i + 2, 2) \
- XO1(i + 3, 3) \
- PF3(i) \
- PF3(i + 2) \
- XO2(i,0) \
- XO2(i + 1, 1) \
- XO2(i + 2, 2) \
- XO2(i + 3, 3) \
- PF4(i) \
- PF4(i + 2) \
- PF0(i + 4) \
- PF0(i + 6) \
- XO3(i,0) \
- XO3(i + 1, 1) \
- XO3(i + 2, 2) \
- XO3(i + 3, 3) \
- XO4(i,0) \
- XO4(i + 1, 1) \
- XO4(i + 2, 2) \
- XO4(i + 3, 3) \
- ST(i,0) \
- ST(i + 1, 1) \
- ST(i + 2, 2) \
- ST(i + 3, 3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addl $256, %1 ;\n"
- " addl $256, %2 ;\n"
- " addl $256, %3 ;\n"
- " addl $256, %4 ;\n"
- " addl $256, %5 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
- : "+r" (lines),
- "+r" (p1), "+r" (p2), "+r" (p3)
- : "r" (p4), "r" (p5)
- : "memory");
-
- /* p4 and p5 were modified, and now the variables are dead.
- Clobber them just to be sure nobody does something stupid
- like assuming they have some legal value. */
- asm("" : "=r" (p4), "=r" (p5));
-
- kernel_fpu_end();
-}
-
static struct xor_block_template xor_block_pIII_sse = {
.name = "pIII_sse",
.do_2 = xor_sse_2,
@@ -827,26 +543,25 @@ static struct xor_block_template xor_block_pIII_sse = {
/* Also try the generic routines. */
#include <asm-generic/xor.h>
+/* We force the use of the SSE xor block because it can write around L2.
+ We may also be able to load into the L1 only depending on how the cpu
+ deals with a load to a line that is being prefetched. */
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
- xor_speed(&xor_block_8regs); \
- xor_speed(&xor_block_8regs_p); \
- xor_speed(&xor_block_32regs); \
- xor_speed(&xor_block_32regs_p); \
AVX_XOR_SPEED; \
- if (cpu_has_xmm) \
+ if (cpu_has_xmm) { \
xor_speed(&xor_block_pIII_sse); \
- if (cpu_has_mmx) { \
+ xor_speed(&xor_block_sse_pf64); \
+ } else if (cpu_has_mmx) { \
xor_speed(&xor_block_pII_mmx); \
xor_speed(&xor_block_p5_mmx); \
+ } else { \
+ xor_speed(&xor_block_8regs); \
+ xor_speed(&xor_block_8regs_p); \
+ xor_speed(&xor_block_32regs); \
+ xor_speed(&xor_block_32regs_p); \
} \
} while (0)
-/* We force the use of the SSE xor block because it can write around L2.
- We may also be able to load into the L1 only depending on how the cpu
- deals with a load to a line that is being prefetched. */
-#define XOR_SELECT_TEMPLATE(FASTEST) \
- AVX_SELECT(cpu_has_xmm ? &xor_block_pIII_sse : FASTEST)
-
#endif /* _ASM_X86_XOR_32_H */
diff --git a/arch/x86/include/asm/xor_64.h b/arch/x86/include/asm/xor_64.h
index 87ac522c4af5..546f1e3b87cc 100644
--- a/arch/x86/include/asm/xor_64.h
+++ b/arch/x86/include/asm/xor_64.h
@@ -1,301 +1,6 @@
#ifndef _ASM_X86_XOR_64_H
#define _ASM_X86_XOR_64_H
-/*
- * Optimized RAID-5 checksumming functions for MMX and SSE.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * You should have received a copy of the GNU General Public License
- * (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-/*
- * Cache avoiding checksumming functions utilizing KNI instructions
- * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
- */
-
-/*
- * Based on
- * High-speed RAID5 checksumming functions utilizing SSE instructions.
- * Copyright (C) 1998 Ingo Molnar.
- */
-
-/*
- * x86-64 changes / gcc fixes from Andi Kleen.
- * Copyright 2002 Andi Kleen, SuSE Labs.
- *
- * This hasn't been optimized for the hammer yet, but there are likely
- * no advantages to be gotten from x86-64 here anyways.
- */
-
-#include <asm/i387.h>
-
-#define OFFS(x) "16*("#x")"
-#define PF_OFFS(x) "256+16*("#x")"
-#define PF0(x) " prefetchnta "PF_OFFS(x)"(%[p1]) ;\n"
-#define LD(x, y) " movaps "OFFS(x)"(%[p1]), %%xmm"#y" ;\n"
-#define ST(x, y) " movaps %%xmm"#y", "OFFS(x)"(%[p1]) ;\n"
-#define PF1(x) " prefetchnta "PF_OFFS(x)"(%[p2]) ;\n"
-#define PF2(x) " prefetchnta "PF_OFFS(x)"(%[p3]) ;\n"
-#define PF3(x) " prefetchnta "PF_OFFS(x)"(%[p4]) ;\n"
-#define PF4(x) " prefetchnta "PF_OFFS(x)"(%[p5]) ;\n"
-#define PF5(x) " prefetchnta "PF_OFFS(x)"(%[p6]) ;\n"
-#define XO1(x, y) " xorps "OFFS(x)"(%[p2]), %%xmm"#y" ;\n"
-#define XO2(x, y) " xorps "OFFS(x)"(%[p3]), %%xmm"#y" ;\n"
-#define XO3(x, y) " xorps "OFFS(x)"(%[p4]), %%xmm"#y" ;\n"
-#define XO4(x, y) " xorps "OFFS(x)"(%[p5]), %%xmm"#y" ;\n"
-#define XO5(x, y) " xorps "OFFS(x)"(%[p6]), %%xmm"#y" ;\n"
-
-
-static void
-xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
-{
- unsigned int lines = bytes >> 8;
-
- kernel_fpu_begin();
-
- asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
- LD(i, 0) \
- LD(i + 1, 1) \
- PF1(i) \
- PF1(i + 2) \
- LD(i + 2, 2) \
- LD(i + 3, 3) \
- PF0(i + 4) \
- PF0(i + 6) \
- XO1(i, 0) \
- XO1(i + 1, 1) \
- XO1(i + 2, 2) \
- XO1(i + 3, 3) \
- ST(i, 0) \
- ST(i + 1, 1) \
- ST(i + 2, 2) \
- ST(i + 3, 3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addq %[inc], %[p1] ;\n"
- " addq %[inc], %[p2] ;\n"
- " decl %[cnt] ; jnz 1b"
- : [p1] "+r" (p1), [p2] "+r" (p2), [cnt] "+r" (lines)
- : [inc] "r" (256UL)
- : "memory");
-
- kernel_fpu_end();
-}
-
-static void
-xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3)
-{
- unsigned int lines = bytes >> 8;
-
- kernel_fpu_begin();
- asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
- PF1(i) \
- PF1(i + 2) \
- LD(i, 0) \
- LD(i + 1, 1) \
- LD(i + 2, 2) \
- LD(i + 3, 3) \
- PF2(i) \
- PF2(i + 2) \
- PF0(i + 4) \
- PF0(i + 6) \
- XO1(i, 0) \
- XO1(i + 1, 1) \
- XO1(i + 2, 2) \
- XO1(i + 3, 3) \
- XO2(i, 0) \
- XO2(i + 1, 1) \
- XO2(i + 2, 2) \
- XO2(i + 3, 3) \
- ST(i, 0) \
- ST(i + 1, 1) \
- ST(i + 2, 2) \
- ST(i + 3, 3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addq %[inc], %[p1] ;\n"
- " addq %[inc], %[p2] ;\n"
- " addq %[inc], %[p3] ;\n"
- " decl %[cnt] ; jnz 1b"
- : [cnt] "+r" (lines),
- [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
- : [inc] "r" (256UL)
- : "memory");
- kernel_fpu_end();
-}
-
-static void
-xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3, unsigned long *p4)
-{
- unsigned int lines = bytes >> 8;
-
- kernel_fpu_begin();
-
- asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
- PF1(i) \
- PF1(i + 2) \
- LD(i, 0) \
- LD(i + 1, 1) \
- LD(i + 2, 2) \
- LD(i + 3, 3) \
- PF2(i) \
- PF2(i + 2) \
- XO1(i, 0) \
- XO1(i + 1, 1) \
- XO1(i + 2, 2) \
- XO1(i + 3, 3) \
- PF3(i) \
- PF3(i + 2) \
- PF0(i + 4) \
- PF0(i + 6) \
- XO2(i, 0) \
- XO2(i + 1, 1) \
- XO2(i + 2, 2) \
- XO2(i + 3, 3) \
- XO3(i, 0) \
- XO3(i + 1, 1) \
- XO3(i + 2, 2) \
- XO3(i + 3, 3) \
- ST(i, 0) \
- ST(i + 1, 1) \
- ST(i + 2, 2) \
- ST(i + 3, 3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addq %[inc], %[p1] ;\n"
- " addq %[inc], %[p2] ;\n"
- " addq %[inc], %[p3] ;\n"
- " addq %[inc], %[p4] ;\n"
- " decl %[cnt] ; jnz 1b"
- : [cnt] "+c" (lines),
- [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4)
- : [inc] "r" (256UL)
- : "memory" );
-
- kernel_fpu_end();
-}
-
-static void
-xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
- unsigned long *p3, unsigned long *p4, unsigned long *p5)
-{
- unsigned int lines = bytes >> 8;
-
- kernel_fpu_begin();
-
- asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
- PF1(i) \
- PF1(i + 2) \
- LD(i, 0) \
- LD(i + 1, 1) \
- LD(i + 2, 2) \
- LD(i + 3, 3) \
- PF2(i) \
- PF2(i + 2) \
- XO1(i, 0) \
- XO1(i + 1, 1) \
- XO1(i + 2, 2) \
- XO1(i + 3, 3) \
- PF3(i) \
- PF3(i + 2) \
- XO2(i, 0) \
- XO2(i + 1, 1) \
- XO2(i + 2, 2) \
- XO2(i + 3, 3) \
- PF4(i) \
- PF4(i + 2) \
- PF0(i + 4) \
- PF0(i + 6) \
- XO3(i, 0) \
- XO3(i + 1, 1) \
- XO3(i + 2, 2) \
- XO3(i + 3, 3) \
- XO4(i, 0) \
- XO4(i + 1, 1) \
- XO4(i + 2, 2) \
- XO4(i + 3, 3) \
- ST(i, 0) \
- ST(i + 1, 1) \
- ST(i + 2, 2) \
- ST(i + 3, 3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addq %[inc], %[p1] ;\n"
- " addq %[inc], %[p2] ;\n"
- " addq %[inc], %[p3] ;\n"
- " addq %[inc], %[p4] ;\n"
- " addq %[inc], %[p5] ;\n"
- " decl %[cnt] ; jnz 1b"
- : [cnt] "+c" (lines),
- [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4),
- [p5] "+r" (p5)
- : [inc] "r" (256UL)
- : "memory");
-
- kernel_fpu_end();
-}
-
static struct xor_block_template xor_block_sse = {
.name = "generic_sse",
.do_2 = xor_sse_2,
@@ -308,17 +13,15 @@ static struct xor_block_template xor_block_sse = {
/* Also try the AVX routines */
#include <asm/xor_avx.h>
+/* We force the use of the SSE xor block because it can write around L2.
+ We may also be able to load into the L1 only depending on how the cpu
+ deals with a load to a line that is being prefetched. */
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
AVX_XOR_SPEED; \
+ xor_speed(&xor_block_sse_pf64); \
xor_speed(&xor_block_sse); \
} while (0)
-/* We force the use of the SSE xor block because it can write around L2.
- We may also be able to load into the L1 only depending on how the cpu
- deals with a load to a line that is being prefetched. */
-#define XOR_SELECT_TEMPLATE(FASTEST) \
- AVX_SELECT(&xor_block_sse)
-
#endif /* _ASM_X86_XOR_64_H */
diff --git a/arch/x86/include/uapi/asm/mce.h b/arch/x86/include/uapi/asm/mce.h
index 58c829871c31..a0eab85ce7b8 100644
--- a/arch/x86/include/uapi/asm/mce.h
+++ b/arch/x86/include/uapi/asm/mce.h
@@ -4,66 +4,6 @@
#include <linux/types.h>
#include <asm/ioctls.h>
-/*
- * Machine Check support for x86
- */
-
-/* MCG_CAP register defines */
-#define MCG_BANKCNT_MASK 0xff /* Number of Banks */
-#define MCG_CTL_P (1ULL<<8) /* MCG_CTL register available */
-#define MCG_EXT_P (1ULL<<9) /* Extended registers available */
-#define MCG_CMCI_P (1ULL<<10) /* CMCI supported */
-#define MCG_EXT_CNT_MASK 0xff0000 /* Number of Extended registers */
-#define MCG_EXT_CNT_SHIFT 16
-#define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT)
-#define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */
-
-/* MCG_STATUS register defines */
-#define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */
-#define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */
-#define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */
-
-/* MCi_STATUS register defines */
-#define MCI_STATUS_VAL (1ULL<<63) /* valid error */
-#define MCI_STATUS_OVER (1ULL<<62) /* previous errors lost */
-#define MCI_STATUS_UC (1ULL<<61) /* uncorrected error */
-#define MCI_STATUS_EN (1ULL<<60) /* error enabled */
-#define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */
-#define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */
-#define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */
-#define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */
-#define MCI_STATUS_AR (1ULL<<55) /* Action required */
-#define MCACOD 0xffff /* MCA Error Code */
-
-/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */
-#define MCACOD_SCRUB 0x00C0 /* 0xC0-0xCF Memory Scrubbing */
-#define MCACOD_SCRUBMSK 0xfff0
-#define MCACOD_L3WB 0x017A /* L3 Explicit Writeback */
-#define MCACOD_DATA 0x0134 /* Data Load */
-#define MCACOD_INSTR 0x0150 /* Instruction Fetch */
-
-/* MCi_MISC register defines */
-#define MCI_MISC_ADDR_LSB(m) ((m) & 0x3f)
-#define MCI_MISC_ADDR_MODE(m) (((m) >> 6) & 7)
-#define MCI_MISC_ADDR_SEGOFF 0 /* segment offset */
-#define MCI_MISC_ADDR_LINEAR 1 /* linear address */
-#define MCI_MISC_ADDR_PHYS 2 /* physical address */
-#define MCI_MISC_ADDR_MEM 3 /* memory address */
-#define MCI_MISC_ADDR_GENERIC 7 /* generic */
-
-/* CTL2 register defines */
-#define MCI_CTL2_CMCI_EN (1ULL << 30)
-#define MCI_CTL2_CMCI_THRESHOLD_MASK 0x7fffULL
-
-#define MCJ_CTX_MASK 3
-#define MCJ_CTX(flags) ((flags) & MCJ_CTX_MASK)
-#define MCJ_CTX_RANDOM 0 /* inject context: random */
-#define MCJ_CTX_PROCESS 0x1 /* inject context: process */
-#define MCJ_CTX_IRQ 0x2 /* inject context: IRQ */
-#define MCJ_NMI_BROADCAST 0x4 /* do NMI broadcasting */
-#define MCJ_EXCEPTION 0x8 /* raise as exception */
-#define MCJ_IRQ_BRAODCAST 0x10 /* do IRQ broadcasting */
-
/* Fields are zero when not available */
struct mce {
__u64 status;
@@ -87,35 +27,8 @@ struct mce {
__u64 mcgcap; /* MCGCAP MSR: machine check capabilities of CPU */
};
-/*
- * This structure contains all data related to the MCE log. Also
- * carries a signature to make it easier to find from external
- * debugging tools. Each entry is only valid when its finished flag
- * is set.
- */
-
-#define MCE_LOG_LEN 32
-
-struct mce_log {
- char signature[12]; /* "MACHINECHECK" */
- unsigned len; /* = MCE_LOG_LEN */
- unsigned next;
- unsigned flags;
- unsigned recordlen; /* length of struct mce */
- struct mce entry[MCE_LOG_LEN];
-};
-
-#define MCE_OVERFLOW 0 /* bit 0 in flags means overflow */
-
-#define MCE_LOG_SIGNATURE "MACHINECHECK"
-
#define MCE_GET_RECORD_LEN _IOR('M', 1, int)
#define MCE_GET_LOG_LEN _IOR('M', 2, int)
#define MCE_GETCLEAR_FLAGS _IOR('M', 3, int)
-/* Software defined banks */
-#define MCE_EXTENDED_BANK 128
-#define MCE_THERMAL_BANK MCE_EXTENDED_BANK + 0
-#define K8_MCE_THRESHOLD_BASE (MCE_EXTENDED_BANK + 1)
-
#endif /* _UAPI_ASM_X86_MCE_H */
diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h
index 433a59fb1a74..892ce40a7470 100644
--- a/arch/x86/include/uapi/asm/msr-index.h
+++ b/arch/x86/include/uapi/asm/msr-index.h
@@ -103,6 +103,8 @@
#define DEBUGCTLMSR_BTS_OFF_USR (1UL << 10)
#define DEBUGCTLMSR_FREEZE_LBRS_ON_PMI (1UL << 11)
+#define MSR_IA32_POWER_CTL 0x000001fc
+
#define MSR_IA32_MC0_CTL 0x00000400
#define MSR_IA32_MC0_STATUS 0x00000401
#define MSR_IA32_MC0_ADDR 0x00000402
@@ -173,6 +175,7 @@
#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140
#define MSR_AMD64_OSVW_STATUS 0xc0010141
#define MSR_AMD64_DC_CFG 0xc0011022
+#define MSR_AMD64_BU_CFG2 0xc001102a
#define MSR_AMD64_IBSFETCHCTL 0xc0011030
#define MSR_AMD64_IBSFETCHLINAD 0xc0011031
#define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032
@@ -194,6 +197,8 @@
/* Fam 15h MSRs */
#define MSR_F15H_PERF_CTL 0xc0010200
#define MSR_F15H_PERF_CTR 0xc0010201
+#define MSR_F15H_NB_PERF_CTL 0xc0010240
+#define MSR_F15H_NB_PERF_CTR 0xc0010241
/* Fam 10h MSRs */
#define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058
@@ -272,6 +277,7 @@
#define MSR_IA32_PLATFORM_ID 0x00000017
#define MSR_IA32_EBL_CR_POWERON 0x0000002a
#define MSR_EBC_FREQUENCY_ID 0x0000002c
+#define MSR_SMI_COUNT 0x00000034
#define MSR_IA32_FEATURE_CONTROL 0x0000003a
#define MSR_IA32_TSC_ADJUST 0x0000003b
diff --git a/arch/x86/include/uapi/asm/signal.h b/arch/x86/include/uapi/asm/signal.h
index aa7d6ae39e0e..8264f47cf53e 100644
--- a/arch/x86/include/uapi/asm/signal.h
+++ b/arch/x86/include/uapi/asm/signal.h
@@ -95,9 +95,9 @@ typedef unsigned long sigset_t;
#ifndef __ASSEMBLY__
-#ifdef __i386__
# ifndef __KERNEL__
/* Here we must cater to libcs that poke about in kernel headers. */
+#ifdef __i386__
struct sigaction {
union {
@@ -112,7 +112,6 @@ struct sigaction {
#define sa_handler _u._sa_handler
#define sa_sigaction _u._sa_sigaction
-# endif /* ! __KERNEL__ */
#else /* __i386__ */
struct sigaction {
@@ -122,11 +121,8 @@ struct sigaction {
sigset_t sa_mask; /* mask last for extensibility */
};
-struct k_sigaction {
- struct sigaction sa;
-};
-
#endif /* !__i386__ */
+# endif /* ! __KERNEL__ */
typedef struct sigaltstack {
void __user *ss_sp;
diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h
index 979d03bce135..2871fccfee68 100644
--- a/arch/x86/include/uapi/asm/vmx.h
+++ b/arch/x86/include/uapi/asm/vmx.h
@@ -62,10 +62,12 @@
#define EXIT_REASON_MCE_DURING_VMENTRY 41
#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
#define EXIT_REASON_APIC_ACCESS 44
+#define EXIT_REASON_EOI_INDUCED 45
#define EXIT_REASON_EPT_VIOLATION 48
#define EXIT_REASON_EPT_MISCONFIG 49
#define EXIT_REASON_WBINVD 54
#define EXIT_REASON_XSETBV 55
+#define EXIT_REASON_APIC_WRITE 56
#define EXIT_REASON_INVPCID 58
#define VMX_EXIT_REASONS \
@@ -103,7 +105,12 @@
{ EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \
{ EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \
{ EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \
- { EXIT_REASON_WBINVD, "WBINVD" }
+ { EXIT_REASON_WBINVD, "WBINVD" }, \
+ { EXIT_REASON_APIC_WRITE, "APIC_WRITE" }, \
+ { EXIT_REASON_EOI_INDUCED, "EOI_INDUCED" }, \
+ { EXIT_REASON_INVALID_STATE, "INVALID_STATE" }, \
+ { EXIT_REASON_INVD, "INVD" }, \
+ { EXIT_REASON_INVPCID, "INVPCID" }
#endif /* _UAPIVMX_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 34e923a53762..7bd3bd310106 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -65,8 +65,7 @@ obj-$(CONFIG_X86_TSC) += trace_clock.o
obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o
obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o
-obj-$(CONFIG_KPROBES) += kprobes.o
-obj-$(CONFIG_OPTPROBES) += kprobes-opt.o
+obj-y += kprobes/
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o
obj-$(CONFIG_KGDB) += kgdb.o
@@ -88,6 +87,9 @@ obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o
obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o
+obj-$(CONFIG_MICROCODE_EARLY) += microcode_core_early.o
+obj-$(CONFIG_MICROCODE_INTEL_EARLY) += microcode_intel_early.o
+obj-$(CONFIG_MICROCODE_INTEL_LIB) += microcode_intel_lib.o
microcode-y := microcode_core.o
microcode-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o
microcode-$(CONFIG_MICROCODE_AMD) += microcode_amd.o
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index bacf4b0d91f4..230c8ea878e5 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -51,7 +51,6 @@ EXPORT_SYMBOL(acpi_disabled);
#ifdef CONFIG_X86_64
# include <asm/proto.h>
-# include <asm/numa_64.h>
#endif /* X86 */
#define BAD_MADT_ENTRY(entry, end) ( \
@@ -697,6 +696,10 @@ EXPORT_SYMBOL(acpi_map_lsapic);
int acpi_unmap_lsapic(int cpu)
{
+#ifdef CONFIG_ACPI_NUMA
+ set_apicid_to_node(per_cpu(x86_cpu_to_apicid, cpu), NUMA_NO_NODE);
+#endif
+
per_cpu(x86_cpu_to_apicid, cpu) = -1;
set_cpu_present(cpu, false);
num_processors--;
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index d5e0d717005a..0532f5d6e4ef 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -69,7 +69,7 @@ int acpi_suspend_lowlevel(void)
#ifndef CONFIG_64BIT
header->pmode_entry = (u32)&wakeup_pmode_return;
- header->pmode_cr3 = (u32)__pa(&initial_page_table);
+ header->pmode_cr3 = (u32)__pa_symbol(initial_page_table);
saved_magic = 0x12345678;
#else /* CONFIG_64BIT */
#ifdef CONFIG_SMP
diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c
index e66311200cbd..b574b295a2f9 100644
--- a/arch/x86/kernel/amd_gart_64.c
+++ b/arch/x86/kernel/amd_gart_64.c
@@ -768,10 +768,9 @@ int __init gart_iommu_init(void)
aper_base = info.aper_base;
end_pfn = (aper_base>>PAGE_SHIFT) + (aper_size>>PAGE_SHIFT);
- if (end_pfn > max_low_pfn_mapped) {
- start_pfn = (aper_base>>PAGE_SHIFT);
+ start_pfn = PFN_DOWN(aper_base);
+ if (!pfn_range_is_mapped(start_pfn, end_pfn))
init_memory_mapping(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
- }
pr_info("PCI-DMA: using GART IOMMU.\n");
iommu_size = check_iommu_size(info.aper_base, aper_size);
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c
index afdc3f756dea..c9876efecafb 100644
--- a/arch/x86/kernel/apb_timer.c
+++ b/arch/x86/kernel/apb_timer.c
@@ -240,7 +240,7 @@ static int apbt_cpuhp_notify(struct notifier_block *n,
dw_apb_clockevent_pause(adev->timer);
if (system_state == SYSTEM_RUNNING) {
pr_debug("skipping APBT CPU %lu offline\n", cpu);
- } else if (adev) {
+ } else {
pr_debug("APBT clockevent for cpu %lu offline\n", cpu);
dw_apb_clockevent_stop(adev->timer);
}
@@ -311,7 +311,6 @@ void __init apbt_time_init(void)
#ifdef CONFIG_SMP
int i;
struct sfi_timer_table_entry *p_mtmr;
- unsigned int percpu_timer;
struct apbt_dev *adev;
#endif
@@ -346,13 +345,10 @@ void __init apbt_time_init(void)
return;
}
pr_debug("%s: %d CPUs online\n", __func__, num_online_cpus());
- if (num_possible_cpus() <= sfi_mtimer_num) {
- percpu_timer = 1;
+ if (num_possible_cpus() <= sfi_mtimer_num)
apbt_num_timers_used = num_possible_cpus();
- } else {
- percpu_timer = 0;
+ else
apbt_num_timers_used = 1;
- }
pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used);
/* here we set up per CPU timer data structure */
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index b994cc84aa7e..a5b4dce1b7ac 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1477,8 +1477,7 @@ void __init bsp_end_local_APIC_setup(void)
* Now that local APIC setup is completed for BP, configure the fault
* handling for interrupt remapping.
*/
- if (irq_remapping_enabled)
- irq_remap_enable_fault_handling();
+ irq_remap_enable_fault_handling();
}
@@ -2251,8 +2250,7 @@ static int lapic_suspend(void)
local_irq_save(flags);
disable_local_APIC();
- if (irq_remapping_enabled)
- irq_remapping_disable();
+ irq_remapping_disable();
local_irq_restore(flags);
return 0;
@@ -2268,16 +2266,15 @@ static void lapic_resume(void)
return;
local_irq_save(flags);
- if (irq_remapping_enabled) {
- /*
- * 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();
- }
+
+ /*
+ * 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();
if (x2apic_mode)
enable_x2apic();
@@ -2320,8 +2317,7 @@ static void lapic_resume(void)
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);
- if (irq_remapping_enabled)
- irq_remapping_reenable(x2apic_mode);
+ irq_remapping_reenable(x2apic_mode);
local_irq_restore(flags);
}
diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c
index 9c2aa89a11cb..9a9110918ca7 100644
--- a/arch/x86/kernel/apic/apic_numachip.c
+++ b/arch/x86/kernel/apic/apic_numachip.c
@@ -28,6 +28,7 @@
#include <asm/apic.h>
#include <asm/ipi.h>
#include <asm/apic_flat_64.h>
+#include <asm/pgtable.h>
static int numachip_system __read_mostly;
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index b739d398bb29..9ed796ccc32c 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -68,22 +68,6 @@
#define for_each_irq_pin(entry, head) \
for (entry = head; entry; entry = entry->next)
-#ifdef CONFIG_IRQ_REMAP
-static void irq_remap_modify_chip_defaults(struct irq_chip *chip);
-static inline bool irq_remapped(struct irq_cfg *cfg)
-{
- return cfg->irq_2_iommu.iommu != NULL;
-}
-#else
-static inline bool irq_remapped(struct irq_cfg *cfg)
-{
- return false;
-}
-static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
-{
-}
-#endif
-
/*
* Is the SiS APIC rmw bug present ?
* -1 = don't know, 0 = no, 1 = yes
@@ -300,9 +284,9 @@ static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)
return cfg;
}
-static int alloc_irq_from(unsigned int from, int node)
+static int alloc_irqs_from(unsigned int from, unsigned int count, int node)
{
- return irq_alloc_desc_from(from, node);
+ return irq_alloc_descs_from(from, count, node);
}
static void free_irq_at(unsigned int at, struct irq_cfg *cfg)
@@ -326,7 +310,7 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
+ (mpc_ioapic_addr(idx) & ~PAGE_MASK);
}
-static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
+void io_apic_eoi(unsigned int apic, unsigned int vector)
{
struct io_apic __iomem *io_apic = io_apic_base(apic);
writel(vector, &io_apic->eoi);
@@ -573,19 +557,10 @@ static void unmask_ioapic_irq(struct irq_data *data)
* Otherwise, we simulate the EOI message manually by changing the trigger
* mode to edge and then back to level, with RTE being masked during this.
*/
-static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg)
+void native_eoi_ioapic_pin(int apic, int pin, int vector)
{
if (mpc_ioapic_ver(apic) >= 0x20) {
- /*
- * Intr-remapping uses pin number as the virtual vector
- * in the RTE. Actual vector is programmed in
- * intr-remapping table entry. Hence for the io-apic
- * EOI we use the pin number.
- */
- if (cfg && irq_remapped(cfg))
- io_apic_eoi(apic, pin);
- else
- io_apic_eoi(apic, vector);
+ io_apic_eoi(apic, vector);
} else {
struct IO_APIC_route_entry entry, entry1;
@@ -606,14 +581,15 @@ static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg)
}
}
-static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
+void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
{
struct irq_pin_list *entry;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags);
for_each_irq_pin(entry, cfg->irq_2_pin)
- __eoi_ioapic_pin(entry->apic, entry->pin, cfg->vector, cfg);
+ x86_io_apic_ops.eoi_ioapic_pin(entry->apic, entry->pin,
+ cfg->vector);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
}
@@ -650,7 +626,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
}
raw_spin_lock_irqsave(&ioapic_lock, flags);
- __eoi_ioapic_pin(apic, pin, entry.vector, NULL);
+ x86_io_apic_ops.eoi_ioapic_pin(apic, pin, entry.vector);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
}
@@ -1304,25 +1280,18 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg,
fasteoi = false;
}
- if (irq_remapped(cfg)) {
- irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
- irq_remap_modify_chip_defaults(chip);
+ if (setup_remapped_irq(irq, cfg, chip))
fasteoi = trigger != 0;
- }
hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq;
irq_set_chip_and_handler_name(irq, chip, hdl,
fasteoi ? "fasteoi" : "edge");
}
-static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
- unsigned int destination, int vector,
- struct io_apic_irq_attr *attr)
+int native_setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
+ unsigned int destination, int vector,
+ struct io_apic_irq_attr *attr)
{
- if (irq_remapping_enabled)
- return setup_ioapic_remapped_entry(irq, entry, destination,
- vector, attr);
-
memset(entry, 0, sizeof(*entry));
entry->delivery_mode = apic->irq_delivery_mode;
@@ -1370,8 +1339,8 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
attr->ioapic, mpc_ioapic_id(attr->ioapic), attr->ioapic_pin,
cfg->vector, irq, attr->trigger, attr->polarity, dest);
- if (setup_ioapic_entry(irq, &entry, dest, cfg->vector, attr)) {
- pr_warn("Failed to setup ioapic entry for ioapic %d, pin %d\n",
+ if (x86_io_apic_ops.setup_entry(irq, &entry, dest, cfg->vector, attr)) {
+ pr_warn("Failed to setup ioapic entry for ioapic %d, pin %d\n",
mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
__clear_irq_vector(irq, cfg);
@@ -1479,9 +1448,6 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
struct IO_APIC_route_entry entry;
unsigned int dest;
- if (irq_remapping_enabled)
- return;
-
memset(&entry, 0, sizeof(entry));
/*
@@ -1513,9 +1479,63 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
ioapic_write_entry(ioapic_idx, pin, entry);
}
-__apicdebuginit(void) print_IO_APIC(int ioapic_idx)
+void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
{
int i;
+
+ pr_debug(" NR Dst Mask Trig IRR Pol Stat Dmod Deli Vect:\n");
+
+ for (i = 0; i <= nr_entries; i++) {
+ struct IO_APIC_route_entry entry;
+
+ entry = ioapic_read_entry(apic, i);
+
+ pr_debug(" %02x %02X ", i, entry.dest);
+ pr_cont("%1d %1d %1d %1d %1d "
+ "%1d %1d %02X\n",
+ entry.mask,
+ entry.trigger,
+ entry.irr,
+ entry.polarity,
+ entry.delivery_status,
+ entry.dest_mode,
+ entry.delivery_mode,
+ entry.vector);
+ }
+}
+
+void intel_ir_io_apic_print_entries(unsigned int apic,
+ unsigned int nr_entries)
+{
+ int i;
+
+ pr_debug(" NR Indx Fmt Mask Trig IRR Pol Stat Indx2 Zero Vect:\n");
+
+ for (i = 0; i <= nr_entries; i++) {
+ struct IR_IO_APIC_route_entry *ir_entry;
+ struct IO_APIC_route_entry entry;
+
+ entry = ioapic_read_entry(apic, i);
+
+ ir_entry = (struct IR_IO_APIC_route_entry *)&entry;
+
+ pr_debug(" %02x %04X ", i, ir_entry->index);
+ pr_cont("%1d %1d %1d %1d %1d "
+ "%1d %1d %X %02X\n",
+ ir_entry->format,
+ ir_entry->mask,
+ ir_entry->trigger,
+ ir_entry->irr,
+ ir_entry->polarity,
+ ir_entry->delivery_status,
+ ir_entry->index2,
+ ir_entry->zero,
+ ir_entry->vector);
+ }
+}
+
+__apicdebuginit(void) print_IO_APIC(int ioapic_idx)
+{
union IO_APIC_reg_00 reg_00;
union IO_APIC_reg_01 reg_01;
union IO_APIC_reg_02 reg_02;
@@ -1568,58 +1588,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
printk(KERN_DEBUG ".... IRQ redirection table:\n");
- if (irq_remapping_enabled) {
- printk(KERN_DEBUG " NR Indx Fmt Mask Trig IRR"
- " Pol Stat Indx2 Zero Vect:\n");
- } else {
- printk(KERN_DEBUG " NR Dst Mask Trig IRR Pol"
- " Stat Dmod Deli Vect:\n");
- }
-
- for (i = 0; i <= reg_01.bits.entries; i++) {
- if (irq_remapping_enabled) {
- struct IO_APIC_route_entry entry;
- struct IR_IO_APIC_route_entry *ir_entry;
-
- entry = ioapic_read_entry(ioapic_idx, i);
- ir_entry = (struct IR_IO_APIC_route_entry *) &entry;
- printk(KERN_DEBUG " %02x %04X ",
- i,
- ir_entry->index
- );
- pr_cont("%1d %1d %1d %1d %1d "
- "%1d %1d %X %02X\n",
- ir_entry->format,
- ir_entry->mask,
- ir_entry->trigger,
- ir_entry->irr,
- ir_entry->polarity,
- ir_entry->delivery_status,
- ir_entry->index2,
- ir_entry->zero,
- ir_entry->vector
- );
- } else {
- struct IO_APIC_route_entry entry;
-
- entry = ioapic_read_entry(ioapic_idx, i);
- printk(KERN_DEBUG " %02x %02X ",
- i,
- entry.dest
- );
- pr_cont("%1d %1d %1d %1d %1d "
- "%1d %1d %02X\n",
- entry.mask,
- entry.trigger,
- entry.irr,
- entry.polarity,
- entry.delivery_status,
- entry.dest_mode,
- entry.delivery_mode,
- entry.vector
- );
- }
- }
+ x86_io_apic_ops.print_entries(ioapic_idx, reg_01.bits.entries);
}
__apicdebuginit(void) print_IO_APICs(void)
@@ -1921,30 +1890,14 @@ void __init enable_IO_APIC(void)
clear_IO_APIC();
}
-/*
- * Not an __init, needed by the reboot code
- */
-void disable_IO_APIC(void)
+void native_disable_io_apic(void)
{
/*
- * Clear the IO-APIC before rebooting:
- */
- clear_IO_APIC();
-
- if (!legacy_pic->nr_legacy_irqs)
- return;
-
- /*
* If the i8259 is routed through an IOAPIC
* Put that IOAPIC in virtual wire mode
* so legacy interrupts can be delivered.
- *
- * With interrupt-remapping, for now we will use virtual wire A mode,
- * as virtual wire B is little complex (need to configure both
- * IOAPIC RTE as well as interrupt-remapping table entry).
- * As this gets called during crash dump, keep this simple for now.
*/
- if (ioapic_i8259.pin != -1 && !irq_remapping_enabled) {
+ if (ioapic_i8259.pin != -1) {
struct IO_APIC_route_entry entry;
memset(&entry, 0, sizeof(entry));
@@ -1964,12 +1917,25 @@ void disable_IO_APIC(void)
ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
}
+ if (cpu_has_apic || apic_from_smp_config())
+ disconnect_bsp_APIC(ioapic_i8259.pin != -1);
+
+}
+
+/*
+ * Not an __init, needed by the reboot code
+ */
+void disable_IO_APIC(void)
+{
/*
- * Use virtual wire A mode when interrupt remapping is enabled.
+ * Clear the IO-APIC before rebooting:
*/
- if (cpu_has_apic || apic_from_smp_config())
- disconnect_bsp_APIC(!irq_remapping_enabled &&
- ioapic_i8259.pin != -1);
+ clear_IO_APIC();
+
+ if (!legacy_pic->nr_legacy_irqs)
+ return;
+
+ x86_io_apic_ops.disable();
}
#ifdef CONFIG_X86_32
@@ -2322,12 +2288,8 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq
apic = entry->apic;
pin = entry->pin;
- /*
- * With interrupt-remapping, destination information comes
- * from interrupt-remapping table entry.
- */
- if (!irq_remapped(cfg))
- io_apic_write(apic, 0x11 + pin*2, dest);
+
+ io_apic_write(apic, 0x11 + pin*2, dest);
reg = io_apic_read(apic, 0x10 + pin*2);
reg &= ~IO_APIC_REDIR_VECTOR_MASK;
reg |= vector;
@@ -2369,9 +2331,10 @@ int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
return 0;
}
-static int
-ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
- bool force)
+
+int native_ioapic_set_affinity(struct irq_data *data,
+ const struct cpumask *mask,
+ bool force)
{
unsigned int dest, irq = data->irq;
unsigned long flags;
@@ -2548,33 +2511,6 @@ static void ack_apic_level(struct irq_data *data)
ioapic_irqd_unmask(data, cfg, masked);
}
-#ifdef CONFIG_IRQ_REMAP
-static void ir_ack_apic_edge(struct irq_data *data)
-{
- ack_APIC_irq();
-}
-
-static void ir_ack_apic_level(struct irq_data *data)
-{
- ack_APIC_irq();
- eoi_ioapic_irq(data->irq, data->chip_data);
-}
-
-static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
-{
- seq_printf(p, " IR-%s", data->chip->name);
-}
-
-static void irq_remap_modify_chip_defaults(struct irq_chip *chip)
-{
- chip->irq_print_chip = ir_print_prefix;
- chip->irq_ack = ir_ack_apic_edge;
- chip->irq_eoi = ir_ack_apic_level;
-
- chip->irq_set_affinity = set_remapped_irq_affinity;
-}
-#endif /* CONFIG_IRQ_REMAP */
-
static struct irq_chip ioapic_chip __read_mostly = {
.name = "IO-APIC",
.irq_startup = startup_ioapic_irq,
@@ -2582,7 +2518,7 @@ static struct irq_chip ioapic_chip __read_mostly = {
.irq_unmask = unmask_ioapic_irq,
.irq_ack = ack_apic_edge,
.irq_eoi = ack_apic_level,
- .irq_set_affinity = ioapic_set_affinity,
+ .irq_set_affinity = native_ioapic_set_affinity,
.irq_retrigger = ioapic_retrigger_irq,
};
@@ -2781,8 +2717,7 @@ static inline void __init check_timer(void)
* 8259A.
*/
if (pin1 == -1) {
- if (irq_remapping_enabled)
- panic("BIOS bug: timer not connected to IO-APIC");
+ panic_if_irq_remap("BIOS bug: timer not connected to IO-APIC");
pin1 = pin2;
apic1 = apic2;
no_pin1 = 1;
@@ -2814,8 +2749,7 @@ static inline void __init check_timer(void)
clear_IO_APIC_pin(0, pin1);
goto out;
}
- if (irq_remapping_enabled)
- panic("timer doesn't work through Interrupt-remapped IO-APIC");
+ panic_if_irq_remap("timer doesn't work through Interrupt-remapped IO-APIC");
local_irq_disable();
clear_IO_APIC_pin(apic1, pin1);
if (!no_pin1)
@@ -2982,37 +2916,58 @@ device_initcall(ioapic_init_ops);
/*
* Dynamic irq allocate and deallocation
*/
-unsigned int create_irq_nr(unsigned int from, int node)
+unsigned int __create_irqs(unsigned int from, unsigned int count, int node)
{
- struct irq_cfg *cfg;
+ struct irq_cfg **cfg;
unsigned long flags;
- unsigned int ret = 0;
- int irq;
+ int irq, i;
if (from < nr_irqs_gsi)
from = nr_irqs_gsi;
- irq = alloc_irq_from(from, node);
- if (irq < 0)
- return 0;
- cfg = alloc_irq_cfg(irq, node);
- if (!cfg) {
- free_irq_at(irq, NULL);
+ cfg = kzalloc_node(count * sizeof(cfg[0]), GFP_KERNEL, node);
+ if (!cfg)
return 0;
+
+ irq = alloc_irqs_from(from, count, node);
+ if (irq < 0)
+ goto out_cfgs;
+
+ for (i = 0; i < count; i++) {
+ cfg[i] = alloc_irq_cfg(irq + i, node);
+ if (!cfg[i])
+ goto out_irqs;
}
raw_spin_lock_irqsave(&vector_lock, flags);
- if (!__assign_irq_vector(irq, cfg, apic->target_cpus()))
- ret = irq;
+ for (i = 0; i < count; i++)
+ if (__assign_irq_vector(irq + i, cfg[i], apic->target_cpus()))
+ goto out_vecs;
raw_spin_unlock_irqrestore(&vector_lock, flags);
- if (ret) {
- irq_set_chip_data(irq, cfg);
- irq_clear_status_flags(irq, IRQ_NOREQUEST);
- } else {
- free_irq_at(irq, cfg);
+ for (i = 0; i < count; i++) {
+ irq_set_chip_data(irq + i, cfg[i]);
+ irq_clear_status_flags(irq + i, IRQ_NOREQUEST);
}
- return ret;
+
+ kfree(cfg);
+ return irq;
+
+out_vecs:
+ for (i--; i >= 0; i--)
+ __clear_irq_vector(irq + i, cfg[i]);
+ raw_spin_unlock_irqrestore(&vector_lock, flags);
+out_irqs:
+ for (i = 0; i < count; i++)
+ free_irq_at(irq + i, cfg[i]);
+out_cfgs:
+ kfree(cfg);
+ return 0;
+}
+
+unsigned int create_irq_nr(unsigned int from, int node)
+{
+ return __create_irqs(from, 1, node);
}
int create_irq(void)
@@ -3037,48 +2992,35 @@ void destroy_irq(unsigned int irq)
irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE);
- if (irq_remapped(cfg))
- free_remapped_irq(irq);
+ free_remapped_irq(irq);
+
raw_spin_lock_irqsave(&vector_lock, flags);
__clear_irq_vector(irq, cfg);
raw_spin_unlock_irqrestore(&vector_lock, flags);
free_irq_at(irq, cfg);
}
+void destroy_irqs(unsigned int irq, unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++)
+ destroy_irq(irq + i);
+}
+
/*
* MSI message composition
*/
-#ifdef CONFIG_PCI_MSI
-static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
- struct msi_msg *msg, u8 hpet_id)
+void native_compose_msi_msg(struct pci_dev *pdev,
+ unsigned int irq, unsigned int dest,
+ struct msi_msg *msg, u8 hpet_id)
{
- struct irq_cfg *cfg;
- int err;
- unsigned dest;
-
- if (disable_apic)
- return -ENXIO;
-
- cfg = irq_cfg(irq);
- err = assign_irq_vector(irq, cfg, apic->target_cpus());
- if (err)
- return err;
+ struct irq_cfg *cfg = irq_cfg(irq);
- err = apic->cpu_mask_to_apicid_and(cfg->domain,
- apic->target_cpus(), &dest);
- if (err)
- return err;
-
- if (irq_remapped(cfg)) {
- compose_remapped_msi_msg(pdev, irq, dest, msg, hpet_id);
- return err;
- }
+ msg->address_hi = MSI_ADDR_BASE_HI;
if (x2apic_enabled())
- msg->address_hi = MSI_ADDR_BASE_HI |
- MSI_ADDR_EXT_DEST_ID(dest);
- else
- msg->address_hi = MSI_ADDR_BASE_HI;
+ msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest);
msg->address_lo =
MSI_ADDR_BASE_LO |
@@ -3097,8 +3039,32 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
MSI_DATA_DELIVERY_FIXED:
MSI_DATA_DELIVERY_LOWPRI) |
MSI_DATA_VECTOR(cfg->vector);
+}
- return err;
+#ifdef CONFIG_PCI_MSI
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
+ struct msi_msg *msg, u8 hpet_id)
+{
+ struct irq_cfg *cfg;
+ int err;
+ unsigned dest;
+
+ if (disable_apic)
+ return -ENXIO;
+
+ cfg = irq_cfg(irq);
+ err = assign_irq_vector(irq, cfg, apic->target_cpus());
+ if (err)
+ return err;
+
+ err = apic->cpu_mask_to_apicid_and(cfg->domain,
+ apic->target_cpus(), &dest);
+ if (err)
+ return err;
+
+ x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+
+ return 0;
}
static int
@@ -3136,23 +3102,28 @@ static struct irq_chip msi_chip = {
.irq_retrigger = ioapic_retrigger_irq,
};
-static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
+int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
+ unsigned int irq_base, unsigned int irq_offset)
{
struct irq_chip *chip = &msi_chip;
struct msi_msg msg;
+ unsigned int irq = irq_base + irq_offset;
int ret;
ret = msi_compose_msg(dev, irq, &msg, -1);
if (ret < 0)
return ret;
- irq_set_msi_desc(irq, msidesc);
- write_msi_msg(irq, &msg);
+ irq_set_msi_desc_off(irq_base, irq_offset, msidesc);
- if (irq_remapped(irq_get_chip_data(irq))) {
- irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
- irq_remap_modify_chip_defaults(chip);
- }
+ /*
+ * MSI-X message is written per-IRQ, the offset is always 0.
+ * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
+ */
+ if (!irq_offset)
+ write_msi_msg(irq, &msg);
+
+ setup_remapped_irq(irq, irq_get_chip_data(irq), chip);
irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
@@ -3163,46 +3134,26 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
- int node, ret, sub_handle, index = 0;
unsigned int irq, irq_want;
struct msi_desc *msidesc;
+ int node, ret;
- /* x86 doesn't support multiple MSI yet */
+ /* Multiple MSI vectors only supported with interrupt remapping */
if (type == PCI_CAP_ID_MSI && nvec > 1)
return 1;
node = dev_to_node(&dev->dev);
irq_want = nr_irqs_gsi;
- sub_handle = 0;
list_for_each_entry(msidesc, &dev->msi_list, list) {
irq = create_irq_nr(irq_want, node);
if (irq == 0)
- return -1;
+ return -ENOSPC;
+
irq_want = irq + 1;
- if (!irq_remapping_enabled)
- goto no_ir;
- if (!sub_handle) {
- /*
- * allocate the consecutive block of IRTE's
- * for 'nvec'
- */
- index = msi_alloc_remapped_irq(dev, irq, nvec);
- if (index < 0) {
- ret = index;
- goto error;
- }
- } else {
- ret = msi_setup_remapped_irq(dev, irq, index,
- sub_handle);
- if (ret < 0)
- goto error;
- }
-no_ir:
- ret = setup_msi_irq(dev, msidesc, irq);
+ ret = setup_msi_irq(dev, msidesc, irq, 0);
if (ret < 0)
goto error;
- sub_handle++;
}
return 0;
@@ -3298,26 +3249,19 @@ static struct irq_chip hpet_msi_type = {
.irq_retrigger = ioapic_retrigger_irq,
};
-int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
+int default_setup_hpet_msi(unsigned int irq, unsigned int id)
{
struct irq_chip *chip = &hpet_msi_type;
struct msi_msg msg;
int ret;
- if (irq_remapping_enabled) {
- ret = setup_hpet_msi_remapped(irq, id);
- if (ret)
- return ret;
- }
-
ret = msi_compose_msg(NULL, irq, &msg, id);
if (ret < 0)
return ret;
hpet_msi_write(irq_get_handler_data(irq), &msg);
irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
- if (irq_remapped(irq_get_chip_data(irq)))
- irq_remap_modify_chip_defaults(chip);
+ setup_remapped_irq(irq, irq_get_chip_data(irq), chip);
irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
return 0;
@@ -3683,10 +3627,7 @@ void __init setup_ioapic_dest(void)
else
mask = apic->target_cpus();
- if (irq_remapping_enabled)
- set_remapped_irq_affinity(idata, mask, false);
- else
- ioapic_set_affinity(idata, mask, false);
+ x86_io_apic_ops.set_affinity(idata, mask, false);
}
}
diff --git a/arch/x86/kernel/apic/ipi.c b/arch/x86/kernel/apic/ipi.c
index cce91bf26676..7434d8556d09 100644
--- a/arch/x86/kernel/apic/ipi.c
+++ b/arch/x86/kernel/apic/ipi.c
@@ -106,7 +106,7 @@ void default_send_IPI_mask_logical(const struct cpumask *cpumask, int vector)
unsigned long mask = cpumask_bits(cpumask)[0];
unsigned long flags;
- if (WARN_ONCE(!mask, "empty IPI mask"))
+ if (!mask)
return;
local_irq_save(flags);
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index e03a1e180e81..562a76d433c8 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -20,18 +20,19 @@ static int set_x2apic_phys_mode(char *arg)
}
early_param("x2apic_phys", set_x2apic_phys_mode);
-static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+static bool x2apic_fadt_phys(void)
{
- if (x2apic_phys)
- return x2apic_enabled();
- else if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
- (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) &&
- x2apic_enabled()) {
+ if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
+ (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
printk(KERN_DEBUG "System requires x2apic physical mode\n");
- return 1;
+ return true;
}
- else
- return 0;
+ return false;
+}
+
+static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+ return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys());
}
static void
@@ -82,7 +83,7 @@ static void init_x2apic_ldr(void)
static int x2apic_phys_probe(void)
{
- if (x2apic_mode && x2apic_phys)
+ if (x2apic_mode && (x2apic_phys || x2apic_fadt_phys()))
return 1;
return apic == &apic_x2apic_phys;
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 8cfade9510a4..794f6eb54cd3 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -5,7 +5,7 @@
*
* SGI UV APIC functions (note: not an Intel compatible APIC)
*
- * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/cpumask.h>
#include <linux/hardirq.h>
@@ -91,10 +91,16 @@ static int __init early_get_pnodeid(void)
m_n_config.v = uv_early_read_mmr(UVH_RH_GAM_CONFIG_MMR);
uv_min_hub_revision_id = node_id.s.revision;
- if (node_id.s.part_number == UV2_HUB_PART_NUMBER)
- uv_min_hub_revision_id += UV2_HUB_REVISION_BASE - 1;
- if (node_id.s.part_number == UV2_HUB_PART_NUMBER_X)
+ switch (node_id.s.part_number) {
+ case UV2_HUB_PART_NUMBER:
+ case UV2_HUB_PART_NUMBER_X:
uv_min_hub_revision_id += UV2_HUB_REVISION_BASE - 1;
+ break;
+ case UV3_HUB_PART_NUMBER:
+ case UV3_HUB_PART_NUMBER_X:
+ uv_min_hub_revision_id += UV3_HUB_REVISION_BASE - 1;
+ break;
+ }
uv_hub_info->hub_revision = uv_min_hub_revision_id;
pnode = (node_id.s.node_id >> 1) & ((1 << m_n_config.s.n_skt) - 1);
@@ -130,13 +136,16 @@ static void __init uv_set_apicid_hibit(void)
static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
- int pnodeid, is_uv1, is_uv2;
+ int pnodeid, is_uv1, is_uv2, is_uv3;
is_uv1 = !strcmp(oem_id, "SGI");
is_uv2 = !strcmp(oem_id, "SGI2");
- if (is_uv1 || is_uv2) {
+ is_uv3 = !strncmp(oem_id, "SGI3", 4); /* there are varieties of UV3 */
+ if (is_uv1 || is_uv2 || is_uv3) {
uv_hub_info->hub_revision =
- is_uv1 ? UV1_HUB_REVISION_BASE : UV2_HUB_REVISION_BASE;
+ (is_uv1 ? UV1_HUB_REVISION_BASE :
+ (is_uv2 ? UV2_HUB_REVISION_BASE :
+ UV3_HUB_REVISION_BASE));
pnodeid = early_get_pnodeid();
early_get_apic_pnode_shift();
x86_platform.is_untracked_pat_range = uv_is_untracked_pat_range;
@@ -450,14 +459,17 @@ static __init void map_high(char *id, unsigned long base, int pshift,
paddr = base << pshift;
bytes = (1UL << bshift) * (max_pnode + 1);
- printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr,
- paddr + bytes);
+ if (!paddr) {
+ pr_info("UV: Map %s_HI base address NULL\n", id);
+ return;
+ }
+ pr_info("UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, paddr + bytes);
if (map_type == map_uc)
init_extra_mapping_uc(paddr, bytes);
else
init_extra_mapping_wb(paddr, bytes);
-
}
+
static __init void map_gru_high(int max_pnode)
{
union uvh_rh_gam_gru_overlay_config_mmr_u gru;
@@ -468,7 +480,8 @@ static __init void map_gru_high(int max_pnode)
map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb);
gru_start_paddr = ((u64)gru.s.base << shift);
gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1);
-
+ } else {
+ pr_info("UV: GRU disabled\n");
}
}
@@ -480,23 +493,146 @@ static __init void map_mmr_high(int max_pnode)
mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR);
if (mmr.s.enable)
map_high("MMR", mmr.s.base, shift, shift, max_pnode, map_uc);
+ else
+ pr_info("UV: MMR disabled\n");
+}
+
+/*
+ * This commonality works because both 0 & 1 versions of the MMIOH OVERLAY
+ * and REDIRECT MMR regs are exactly the same on UV3.
+ */
+struct mmioh_config {
+ unsigned long overlay;
+ unsigned long redirect;
+ char *id;
+};
+
+static __initdata struct mmioh_config mmiohs[] = {
+ {
+ UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR,
+ UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR,
+ "MMIOH0"
+ },
+ {
+ UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR,
+ UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR,
+ "MMIOH1"
+ },
+};
+
+static __init void map_mmioh_high_uv3(int index, int min_pnode, int max_pnode)
+{
+ union uv3h_rh_gam_mmioh_overlay_config0_mmr_u overlay;
+ unsigned long mmr;
+ unsigned long base;
+ int i, n, shift, m_io, max_io;
+ int nasid, lnasid, fi, li;
+ char *id;
+
+ id = mmiohs[index].id;
+ overlay.v = uv_read_local_mmr(mmiohs[index].overlay);
+ pr_info("UV: %s overlay 0x%lx base:0x%x m_io:%d\n",
+ id, overlay.v, overlay.s3.base, overlay.s3.m_io);
+ if (!overlay.s3.enable) {
+ pr_info("UV: %s disabled\n", id);
+ return;
+ }
+
+ shift = UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_SHFT;
+ base = (unsigned long)overlay.s3.base;
+ m_io = overlay.s3.m_io;
+ mmr = mmiohs[index].redirect;
+ n = UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH;
+ min_pnode *= 2; /* convert to NASID */
+ max_pnode *= 2;
+ max_io = lnasid = fi = li = -1;
+
+ for (i = 0; i < n; i++) {
+ union uv3h_rh_gam_mmioh_redirect_config0_mmr_u redirect;
+
+ redirect.v = uv_read_local_mmr(mmr + i * 8);
+ nasid = redirect.s3.nasid;
+ if (nasid < min_pnode || max_pnode < nasid)
+ nasid = -1; /* invalid NASID */
+
+ if (nasid == lnasid) {
+ li = i;
+ if (i != n-1) /* last entry check */
+ continue;
+ }
+
+ /* check if we have a cached (or last) redirect to print */
+ if (lnasid != -1 || (i == n-1 && nasid != -1)) {
+ unsigned long addr1, addr2;
+ int f, l;
+
+ if (lnasid == -1) {
+ f = l = i;
+ lnasid = nasid;
+ } else {
+ f = fi;
+ l = li;
+ }
+ addr1 = (base << shift) +
+ f * (unsigned long)(1 << m_io);
+ addr2 = (base << shift) +
+ (l + 1) * (unsigned long)(1 << m_io);
+ pr_info("UV: %s[%03d..%03d] NASID 0x%04x ADDR 0x%016lx - 0x%016lx\n",
+ id, fi, li, lnasid, addr1, addr2);
+ if (max_io < l)
+ max_io = l;
+ }
+ fi = li = i;
+ lnasid = nasid;
+ }
+
+ pr_info("UV: %s base:0x%lx shift:%d M_IO:%d MAX_IO:%d\n",
+ id, base, shift, m_io, max_io);
+
+ if (max_io >= 0)
+ map_high(id, base, shift, m_io, max_io, map_uc);
}
-static __init void map_mmioh_high(int max_pnode)
+static __init void map_mmioh_high(int min_pnode, int max_pnode)
{
union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh;
- int shift;
+ unsigned long mmr, base;
+ int shift, enable, m_io, n_io;
- mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
- if (is_uv1_hub() && mmioh.s1.enable) {
- shift = UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
- map_high("MMIOH", mmioh.s1.base, shift, mmioh.s1.m_io,
- max_pnode, map_uc);
+ if (is_uv3_hub()) {
+ /* Map both MMIOH Regions */
+ map_mmioh_high_uv3(0, min_pnode, max_pnode);
+ map_mmioh_high_uv3(1, min_pnode, max_pnode);
+ return;
}
- if (is_uv2_hub() && mmioh.s2.enable) {
+
+ if (is_uv1_hub()) {
+ mmr = UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR;
+ shift = UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
+ mmioh.v = uv_read_local_mmr(mmr);
+ enable = !!mmioh.s1.enable;
+ base = mmioh.s1.base;
+ m_io = mmioh.s1.m_io;
+ n_io = mmioh.s1.n_io;
+ } else if (is_uv2_hub()) {
+ mmr = UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR;
shift = UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
- map_high("MMIOH", mmioh.s2.base, shift, mmioh.s2.m_io,
- max_pnode, map_uc);
+ mmioh.v = uv_read_local_mmr(mmr);
+ enable = !!mmioh.s2.enable;
+ base = mmioh.s2.base;
+ m_io = mmioh.s2.m_io;
+ n_io = mmioh.s2.n_io;
+ } else
+ return;
+
+ if (enable) {
+ max_pnode &= (1 << n_io) - 1;
+ pr_info(
+ "UV: base:0x%lx shift:%d N_IO:%d M_IO:%d max_pnode:0x%x\n",
+ base, shift, m_io, n_io, max_pnode);
+ map_high("MMIOH", base, shift, m_io, max_pnode, map_uc);
+ } else {
+ pr_info("UV: MMIOH disabled\n");
}
}
@@ -724,42 +860,41 @@ void uv_nmi_init(void)
void __init uv_system_init(void)
{
union uvh_rh_gam_config_mmr_u m_n_config;
- union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh;
union uvh_node_id_u node_id;
unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size;
- int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val, n_io;
- int gnode_extra, max_pnode = 0;
+ int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val;
+ int gnode_extra, min_pnode = 999999, max_pnode = -1;
unsigned long mmr_base, present, paddr;
- unsigned short pnode_mask, pnode_io_mask;
+ unsigned short pnode_mask;
+ char *hub = (is_uv1_hub() ? "UV1" :
+ (is_uv2_hub() ? "UV2" :
+ "UV3"));
- printk(KERN_INFO "UV: Found %s hub\n", is_uv1_hub() ? "UV1" : "UV2");
+ pr_info("UV: Found %s hub\n", hub);
map_low_mmrs();
m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR );
m_val = m_n_config.s.m_skt;
n_val = m_n_config.s.n_skt;
- mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
- n_io = is_uv1_hub() ? mmioh.s1.n_io : mmioh.s2.n_io;
+ pnode_mask = (1 << n_val) - 1;
mmr_base =
uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
~UV_MMR_ENABLE;
- pnode_mask = (1 << n_val) - 1;
- pnode_io_mask = (1 << n_io) - 1;
node_id.v = uv_read_local_mmr(UVH_NODE_ID);
gnode_extra = (node_id.s.node_id & ~((1 << n_val) - 1)) >> 1;
gnode_upper = ((unsigned long)gnode_extra << m_val);
- printk(KERN_INFO "UV: N %d, M %d, N_IO: %d, gnode_upper 0x%lx, gnode_extra 0x%x, pnode_mask 0x%x, pnode_io_mask 0x%x\n",
- n_val, m_val, n_io, gnode_upper, gnode_extra, pnode_mask, pnode_io_mask);
+ pr_info("UV: N:%d M:%d pnode_mask:0x%x gnode_upper/extra:0x%lx/0x%x\n",
+ n_val, m_val, pnode_mask, gnode_upper, gnode_extra);
- printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base);
+ pr_info("UV: global MMR base 0x%lx\n", mmr_base);
for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++)
uv_possible_blades +=
hweight64(uv_read_local_mmr( UVH_NODE_PRESENT_TABLE + i * 8));
/* uv_num_possible_blades() is really the hub count */
- printk(KERN_INFO "UV: Found %d blades, %d hubs\n",
+ pr_info("UV: Found %d blades, %d hubs\n",
is_uv1_hub() ? uv_num_possible_blades() :
(uv_num_possible_blades() + 1) / 2,
uv_num_possible_blades());
@@ -794,6 +929,7 @@ void __init uv_system_init(void)
uv_blade_info[blade].nr_possible_cpus = 0;
uv_blade_info[blade].nr_online_cpus = 0;
spin_lock_init(&uv_blade_info[blade].nmi_lock);
+ min_pnode = min(pnode, min_pnode);
max_pnode = max(pnode, max_pnode);
blade++;
}
@@ -856,7 +992,7 @@ void __init uv_system_init(void)
map_gru_high(max_pnode);
map_mmr_high(max_pnode);
- map_mmioh_high(max_pnode & pnode_io_mask);
+ map_mmioh_high(min_pnode, max_pnode);
uv_cpu_init();
uv_scir_register_cpu_notifier();
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index d65464e43503..66b5faffe14a 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -232,6 +232,7 @@
#include <linux/acpi.h>
#include <linux/syscore_ops.h>
#include <linux/i8253.h>
+#include <linux/cpuidle.h>
#include <asm/uaccess.h>
#include <asm/desc.h>
@@ -360,13 +361,35 @@ struct apm_user {
* idle percentage above which bios idle calls are done
*/
#ifdef CONFIG_APM_CPU_IDLE
-#warning deprecated CONFIG_APM_CPU_IDLE will be deleted in 2012
#define DEFAULT_IDLE_THRESHOLD 95
#else
#define DEFAULT_IDLE_THRESHOLD 100
#endif
#define DEFAULT_IDLE_PERIOD (100 / 3)
+static int apm_cpu_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index);
+
+static struct cpuidle_driver apm_idle_driver = {
+ .name = "apm_idle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
+ .states = {
+ { /* entry 0 is for polling */ },
+ { /* entry 1 is for APM idle */
+ .name = "APM",
+ .desc = "APM idle",
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 250, /* WAG */
+ .target_residency = 500, /* WAG */
+ .enter = &apm_cpu_idle
+ },
+ },
+ .state_count = 2,
+};
+
+static struct cpuidle_device apm_cpuidle_device;
+
/*
* Local variables
*/
@@ -377,7 +400,6 @@ static struct {
static int clock_slowed;
static int idle_threshold __read_mostly = DEFAULT_IDLE_THRESHOLD;
static int idle_period __read_mostly = DEFAULT_IDLE_PERIOD;
-static int set_pm_idle;
static int suspends_pending;
static int standbys_pending;
static int ignore_sys_suspend;
@@ -884,8 +906,6 @@ static void apm_do_busy(void)
#define IDLE_CALC_LIMIT (HZ * 100)
#define IDLE_LEAKY_MAX 16
-static void (*original_pm_idle)(void) __read_mostly;
-
/**
* apm_cpu_idle - cpu idling for APM capable Linux
*
@@ -894,35 +914,36 @@ static void (*original_pm_idle)(void) __read_mostly;
* Furthermore it calls the system default idle routine.
*/
-static void apm_cpu_idle(void)
+static int apm_cpu_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
static int use_apm_idle; /* = 0 */
static unsigned int last_jiffies; /* = 0 */
static unsigned int last_stime; /* = 0 */
+ cputime_t stime;
int apm_idle_done = 0;
unsigned int jiffies_since_last_check = jiffies - last_jiffies;
unsigned int bucket;
- WARN_ONCE(1, "deprecated apm_cpu_idle will be deleted in 2012");
recalc:
+ task_cputime(current, NULL, &stime);
if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
use_apm_idle = 0;
- last_jiffies = jiffies;
- last_stime = current->stime;
} else if (jiffies_since_last_check > idle_period) {
unsigned int idle_percentage;
- idle_percentage = current->stime - last_stime;
+ idle_percentage = stime - last_stime;
idle_percentage *= 100;
idle_percentage /= jiffies_since_last_check;
use_apm_idle = (idle_percentage > idle_threshold);
if (apm_info.forbid_idle)
use_apm_idle = 0;
- last_jiffies = jiffies;
- last_stime = current->stime;
}
+ last_jiffies = jiffies;
+ last_stime = stime;
+
bucket = IDLE_LEAKY_MAX;
while (!need_resched()) {
@@ -950,10 +971,7 @@ recalc:
break;
}
}
- if (original_pm_idle)
- original_pm_idle();
- else
- default_idle();
+ default_idle();
local_irq_disable();
jiffies_since_last_check = jiffies - last_jiffies;
if (jiffies_since_last_check > idle_period)
@@ -963,7 +981,7 @@ recalc:
if (apm_idle_done)
apm_do_busy();
- local_irq_enable();
+ return index;
}
/**
@@ -2381,9 +2399,9 @@ static int __init apm_init(void)
if (HZ != 100)
idle_period = (idle_period * HZ) / 100;
if (idle_threshold < 100) {
- original_pm_idle = pm_idle;
- pm_idle = apm_cpu_idle;
- set_pm_idle = 1;
+ if (!cpuidle_register_driver(&apm_idle_driver))
+ if (cpuidle_register_device(&apm_cpuidle_device))
+ cpuidle_unregister_driver(&apm_idle_driver);
}
return 0;
@@ -2393,15 +2411,9 @@ static void __exit apm_exit(void)
{
int error;
- if (set_pm_idle) {
- pm_idle = original_pm_idle;
- /*
- * We are about to unload the current idle thread pm callback
- * (pm_idle), Wait for all processors to update cached/local
- * copies of pm_idle before proceeding.
- */
- kick_all_cpus_sync();
- }
+ cpuidle_unregister_device(&apm_cpuidle_device);
+ cpuidle_unregister_driver(&apm_idle_driver);
+
if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
&& (apm_info.connection_version > 0x0100)) {
error = apm_engage_power_management(APM_DEVICE_ALL, 0);
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 15239fffd6fe..fa96eb0d02fb 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -12,7 +12,6 @@
#include <asm/pci-direct.h>
#ifdef CONFIG_X86_64
-# include <asm/numa_64.h>
# include <asm/mmconfig.h>
# include <asm/cacheflush.h>
#endif
@@ -220,8 +219,7 @@ static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
*/
WARN_ONCE(1, "WARNING: This combination of AMD"
" processors is not suitable for SMP.\n");
- if (!test_taint(TAINT_UNSAFE_SMP))
- add_taint(TAINT_UNSAFE_SMP);
+ add_taint(TAINT_UNSAFE_SMP, LOCKDEP_NOW_UNRELIABLE);
valid_k7:
;
@@ -364,9 +362,9 @@ static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
#endif
}
-int amd_get_nb_id(int cpu)
+u16 amd_get_nb_id(int cpu)
{
- int id = 0;
+ u16 id = 0;
#ifdef CONFIG_SMP
id = per_cpu(cpu_llc_id, cpu);
#endif
@@ -518,10 +516,9 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
{
u32 dummy;
-
-#ifdef CONFIG_SMP
unsigned long long value;
+#ifdef CONFIG_SMP
/*
* Disable TLB flush filter by setting HWCR.FFDIS on K8
* bit 6 of msr C001_0015
@@ -559,12 +556,10 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
* (AMD Erratum #110, docId: 25759).
*/
if (c->x86_model < 0x14 && cpu_has(c, X86_FEATURE_LAHF_LM)) {
- u64 val;
-
clear_cpu_cap(c, X86_FEATURE_LAHF_LM);
- if (!rdmsrl_amd_safe(0xc001100d, &val)) {
- val &= ~(1ULL << 32);
- wrmsrl_amd_safe(0xc001100d, val);
+ if (!rdmsrl_amd_safe(0xc001100d, &value)) {
+ value &= ~(1ULL << 32);
+ wrmsrl_amd_safe(0xc001100d, value);
}
}
@@ -617,13 +612,12 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
if ((c->x86 == 0x15) &&
(c->x86_model >= 0x10) && (c->x86_model <= 0x1f) &&
!cpu_has(c, X86_FEATURE_TOPOEXT)) {
- u64 val;
- if (!rdmsrl_safe(0xc0011005, &val)) {
- val |= 1ULL << 54;
- wrmsrl_safe(0xc0011005, val);
- rdmsrl(0xc0011005, val);
- if (val & (1ULL << 54)) {
+ if (!rdmsrl_safe(0xc0011005, &value)) {
+ value |= 1ULL << 54;
+ wrmsrl_safe(0xc0011005, value);
+ rdmsrl(0xc0011005, value);
+ if (value & (1ULL << 54)) {
set_cpu_cap(c, X86_FEATURE_TOPOEXT);
printk(KERN_INFO FW_INFO "CPU: Re-enabling "
"disabled Topology Extensions Support\n");
@@ -637,11 +631,10 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
*/
if ((c->x86 == 0x15) &&
(c->x86_model >= 0x02) && (c->x86_model < 0x20)) {
- u64 val;
- if (!rdmsrl_safe(0xc0011021, &val) && !(val & 0x1E)) {
- val |= 0x1E;
- wrmsrl_safe(0xc0011021, val);
+ if (!rdmsrl_safe(0xc0011021, &value) && !(value & 0x1E)) {
+ value |= 0x1E;
+ wrmsrl_safe(0xc0011021, value);
}
}
@@ -685,12 +678,10 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
* benefit in doing so.
*/
if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg)) {
+ unsigned long pfn = tseg >> PAGE_SHIFT;
+
printk(KERN_DEBUG "tseg: %010llx\n", tseg);
- if ((tseg>>PMD_SHIFT) <
- (max_low_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) ||
- ((tseg>>PMD_SHIFT) <
- (max_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) &&
- (tseg>>PMD_SHIFT) >= (1ULL<<(32 - PMD_SHIFT))))
+ if (pfn_range_is_mapped(pfn, pfn + 1))
set_memory_4k((unsigned long)__va(tseg), 1);
}
}
@@ -703,13 +694,11 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
if (c->x86 > 0x11)
set_cpu_cap(c, X86_FEATURE_ARAT);
- /*
- * Disable GART TLB Walk Errors on Fam10h. We do this here
- * because this is always needed when GART is enabled, even in a
- * kernel which has no MCE support built in.
- */
if (c->x86 == 0x10) {
/*
+ * Disable GART TLB Walk Errors on Fam10h. We do this here
+ * because this is always needed when GART is enabled, even in a
+ * kernel which has no MCE support built in.
* BIOS should disable GartTlbWlk Errors themself. If
* it doesn't do it here as suggested by the BKDG.
*
@@ -723,6 +712,21 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
mask |= (1 << 10);
wrmsrl_safe(MSR_AMD64_MCx_MASK(4), mask);
}
+
+ /*
+ * On family 10h BIOS may not have properly enabled WC+ support,
+ * causing it to be converted to CD memtype. This may result in
+ * performance degradation for certain nested-paging guests.
+ * Prevent this conversion by clearing bit 24 in
+ * MSR_AMD64_BU_CFG2.
+ *
+ * NOTE: we want to use the _safe accessors so as not to #GP kvm
+ * guests on older kvm hosts.
+ */
+
+ rdmsrl_safe(MSR_AMD64_BU_CFG2, &value);
+ value &= ~(1ULL << 24);
+ wrmsrl_safe(MSR_AMD64_BU_CFG2, value);
}
rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 92dfec986a48..af6455e3fcc9 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -17,15 +17,6 @@
#include <asm/paravirt.h>
#include <asm/alternative.h>
-static int __init no_halt(char *s)
-{
- WARN_ONCE(1, "\"no-hlt\" is deprecated, please use \"idle=poll\"\n");
- boot_cpu_data.hlt_works_ok = 0;
- return 1;
-}
-
-__setup("no-hlt", no_halt);
-
static int __init no_387(char *s)
{
boot_cpu_data.hard_math = 0;
@@ -89,23 +80,6 @@ static void __init check_fpu(void)
pr_warn("Hmm, FPU with FDIV bug\n");
}
-static void __init check_hlt(void)
-{
- if (boot_cpu_data.x86 >= 5 || paravirt_enabled())
- return;
-
- pr_info("Checking 'hlt' instruction... ");
- if (!boot_cpu_data.hlt_works_ok) {
- pr_cont("disabled\n");
- return;
- }
- halt();
- halt();
- halt();
- halt();
- pr_cont("OK\n");
-}
-
/*
* Check whether we are able to run this kernel safely on SMP.
*
@@ -129,7 +103,6 @@ void __init check_bugs(void)
print_cpu_info(&boot_cpu_data);
#endif
check_config();
- check_hlt();
init_utsname()->machine[1] =
'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
alternative_instructions();
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 9c3ab43a6954..d814772c5bed 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -37,6 +37,8 @@
#include <asm/mce.h>
#include <asm/msr.h>
#include <asm/pat.h>
+#include <asm/microcode.h>
+#include <asm/microcode_intel.h>
#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/uv/uv.h>
@@ -213,7 +215,7 @@ static inline int flag_is_changeable_p(u32 flag)
}
/* Probe for the CPUID instruction */
-static int __cpuinit have_cpuid_p(void)
+int __cpuinit have_cpuid_p(void)
{
return flag_is_changeable_p(X86_EFLAGS_ID);
}
@@ -249,11 +251,6 @@ static inline int flag_is_changeable_p(u32 flag)
{
return 1;
}
-/* Probe for the CPUID instruction */
-static inline int have_cpuid_p(void)
-{
- return 1;
-}
static inline void squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
{
}
@@ -1223,6 +1220,12 @@ void __cpuinit cpu_init(void)
int cpu;
int i;
+ /*
+ * Load microcode on this cpu if a valid microcode is available.
+ * This is early microcode loading procedure.
+ */
+ load_ucode_ap();
+
cpu = stack_smp_processor_id();
t = &per_cpu(init_tss, cpu);
oist = &per_cpu(orig_ist, cpu);
@@ -1314,6 +1317,8 @@ void __cpuinit cpu_init(void)
struct tss_struct *t = &per_cpu(init_tss, cpu);
struct thread_struct *thread = &curr->thread;
+ show_ucode_info_early();
+
if (cpumask_test_and_set_cpu(cpu, cpu_initialized_mask)) {
printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
for (;;)
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c
index a8f8fa9769d6..1e7e84a02eba 100644
--- a/arch/x86/kernel/cpu/hypervisor.c
+++ b/arch/x86/kernel/cpu/hypervisor.c
@@ -79,3 +79,10 @@ void __init init_hypervisor_platform(void)
if (x86_hyper->init_platform)
x86_hyper->init_platform();
}
+
+bool __init hypervisor_x2apic_available(void)
+{
+ return x86_hyper &&
+ x86_hyper->x2apic_available &&
+ x86_hyper->x2apic_available();
+}
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index fcaabd0432c5..1905ce98bee0 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -17,7 +17,6 @@
#ifdef CONFIG_X86_64
#include <linux/topology.h>
-#include <asm/numa_64.h>
#endif
#include "cpu.h"
@@ -168,7 +167,7 @@ int __cpuinit ppro_with_ram_bug(void)
#ifdef CONFIG_X86_F00F_BUG
static void __cpuinit trap_init_f00f_bug(void)
{
- __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
+ __set_fixmap(FIX_F00F_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO);
/*
* Update the IDT descriptor and reload the IDT so that
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 84c1309c4c0c..7c6f7d548c0f 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -1226,7 +1226,7 @@ static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier = {
.notifier_call = cacheinfo_cpu_callback,
};
-static int __cpuinit cache_sysfs_init(void)
+static int __init cache_sysfs_init(void)
{
int i;
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 80dbda84f1c3..7bc126346ace 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -512,11 +512,8 @@ int mce_available(struct cpuinfo_x86 *c)
static void mce_schedule_work(void)
{
- if (!mce_ring_empty()) {
- struct work_struct *work = &__get_cpu_var(mce_work);
- if (!work_pending(work))
- schedule_work(work);
- }
+ if (!mce_ring_empty())
+ schedule_work(&__get_cpu_var(mce_work));
}
DEFINE_PER_CPU(struct irq_work, mce_irq_work);
@@ -1085,7 +1082,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)
/*
* Set taint even when machine check was not enabled.
*/
- add_taint(TAINT_MACHINE_CHECK);
+ add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
severity = mce_severity(&m, cfg->tolerant, NULL);
@@ -1351,12 +1348,7 @@ int mce_notify_irq(void)
/* wake processes polling /dev/mcelog */
wake_up_interruptible(&mce_chrdev_wait);
- /*
- * There is no risk of missing notifications because
- * work_pending is always cleared before the function is
- * executed.
- */
- if (mce_helper[0] && !work_pending(&mce_trigger_work))
+ if (mce_helper[0])
schedule_work(&mce_trigger_work);
if (__ratelimit(&ratelimit))
diff --git a/arch/x86/kernel/cpu/mcheck/p5.c b/arch/x86/kernel/cpu/mcheck/p5.c
index 2d5454cd2c4f..1c044b1ccc59 100644
--- a/arch/x86/kernel/cpu/mcheck/p5.c
+++ b/arch/x86/kernel/cpu/mcheck/p5.c
@@ -33,7 +33,7 @@ static void pentium_machine_check(struct pt_regs *regs, long error_code)
smp_processor_id());
}
- add_taint(TAINT_MACHINE_CHECK);
+ add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
}
/* Set up machine check reporting for processors with Intel style MCE: */
diff --git a/arch/x86/kernel/cpu/mcheck/winchip.c b/arch/x86/kernel/cpu/mcheck/winchip.c
index 2d7998fb628c..e9a701aecaa1 100644
--- a/arch/x86/kernel/cpu/mcheck/winchip.c
+++ b/arch/x86/kernel/cpu/mcheck/winchip.c
@@ -15,7 +15,7 @@
static void winchip_machine_check(struct pt_regs *regs, long error_code)
{
printk(KERN_EMERG "CPU0: Machine Check Exception.\n");
- add_taint(TAINT_MACHINE_CHECK);
+ add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
}
/* Set up machine check reporting on the Winchip C6 series */
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 0a630dd4b620..a7d26d83fb70 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -14,10 +14,15 @@
#include <linux/time.h>
#include <linux/clocksource.h>
#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
#include <asm/processor.h>
#include <asm/hypervisor.h>
#include <asm/hyperv.h>
#include <asm/mshyperv.h>
+#include <asm/desc.h>
+#include <asm/idle.h>
+#include <asm/irq_regs.h>
struct ms_hyperv_info ms_hyperv;
EXPORT_SYMBOL_GPL(ms_hyperv);
@@ -30,6 +35,13 @@ static bool __init ms_hyperv_platform(void)
if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
return false;
+ /*
+ * Xen emulates Hyper-V to support enlightened Windows.
+ * Check to see first if we are on a Xen Hypervisor.
+ */
+ if (xen_cpuid_base())
+ return false;
+
cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
&eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
@@ -68,7 +80,14 @@ static void __init ms_hyperv_init_platform(void)
printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n",
ms_hyperv.features, ms_hyperv.hints);
- clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
+ if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
+ clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
+#if IS_ENABLED(CONFIG_HYPERV)
+ /*
+ * Setup the IDT for hypervisor callback.
+ */
+ alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
+#endif
}
const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
@@ -77,3 +96,36 @@ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
.init_platform = ms_hyperv_init_platform,
};
EXPORT_SYMBOL(x86_hyper_ms_hyperv);
+
+#if IS_ENABLED(CONFIG_HYPERV)
+static int vmbus_irq = -1;
+static irq_handler_t vmbus_isr;
+
+void hv_register_vmbus_handler(int irq, irq_handler_t handler)
+{
+ vmbus_irq = irq;
+ vmbus_isr = handler;
+}
+
+void hyperv_vector_handler(struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ struct irq_desc *desc;
+
+ irq_enter();
+ exit_idle();
+
+ desc = irq_to_desc(vmbus_irq);
+
+ if (desc)
+ generic_handle_irq_desc(vmbus_irq, desc);
+
+ irq_exit();
+ set_irq_regs(old_regs);
+}
+#else
+void hv_register_vmbus_handler(int irq, irq_handler_t handler)
+{
+}
+#endif
+EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index e9fe907cd249..fa72a39e5d46 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -542,7 +542,7 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
if (tmp != mask_lo) {
printk(KERN_WARNING "mtrr: your BIOS has configured an incorrect mask, fixing it.\n");
- add_taint(TAINT_FIRMWARE_WORKAROUND);
+ add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
mask_lo = tmp;
}
}
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 6774c17a5576..bf0f01aea994 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -829,7 +829,7 @@ static inline void x86_assign_hw_event(struct perf_event *event,
} else {
hwc->config_base = x86_pmu_config_addr(hwc->idx);
hwc->event_base = x86_pmu_event_addr(hwc->idx);
- hwc->event_base_rdpmc = hwc->idx;
+ hwc->event_base_rdpmc = x86_pmu_rdpmc_index(hwc->idx);
}
}
@@ -1310,11 +1310,6 @@ static struct attribute_group x86_pmu_format_group = {
.attrs = NULL,
};
-struct perf_pmu_events_attr {
- struct device_attribute attr;
- u64 id;
-};
-
/*
* Remove all undefined events (x86_pmu.event_map(id) == 0)
* out of events_attr attributes.
@@ -1348,11 +1343,9 @@ static ssize_t events_sysfs_show(struct device *dev, struct device_attribute *at
#define EVENT_VAR(_id) event_attr_##_id
#define EVENT_PTR(_id) &event_attr_##_id.attr.attr
-#define EVENT_ATTR(_name, _id) \
-static struct perf_pmu_events_attr EVENT_VAR(_id) = { \
- .attr = __ATTR(_name, 0444, events_sysfs_show, NULL), \
- .id = PERF_COUNT_HW_##_id, \
-};
+#define EVENT_ATTR(_name, _id) \
+ PMU_EVENT_ATTR(_name, EVENT_VAR(_id), PERF_COUNT_HW_##_id, \
+ events_sysfs_show)
EVENT_ATTR(cpu-cycles, CPU_CYCLES );
EVENT_ATTR(instructions, INSTRUCTIONS );
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 115c1ea97746..7f5c75c2afdd 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -325,6 +325,8 @@ struct x86_pmu {
int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign);
unsigned eventsel;
unsigned perfctr;
+ int (*addr_offset)(int index, bool eventsel);
+ int (*rdpmc_index)(int index);
u64 (*event_map)(int);
int max_events;
int num_counters;
@@ -446,28 +448,21 @@ extern u64 __read_mostly hw_cache_extra_regs
u64 x86_perf_event_update(struct perf_event *event);
-static inline int x86_pmu_addr_offset(int index)
+static inline unsigned int x86_pmu_config_addr(int 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;
+ return x86_pmu.eventsel + (x86_pmu.addr_offset ?
+ x86_pmu.addr_offset(index, true) : index);
}
-static inline unsigned int x86_pmu_config_addr(int index)
+static inline unsigned int x86_pmu_event_addr(int index)
{
- return x86_pmu.eventsel + x86_pmu_addr_offset(index);
+ return x86_pmu.perfctr + (x86_pmu.addr_offset ?
+ x86_pmu.addr_offset(index, false) : index);
}
-static inline unsigned int x86_pmu_event_addr(int index)
+static inline int x86_pmu_rdpmc_index(int index)
{
- return x86_pmu.perfctr + x86_pmu_addr_offset(index);
+ return x86_pmu.rdpmc_index ? x86_pmu.rdpmc_index(index) : index;
}
int x86_setup_perfctr(struct perf_event *event);
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c
index c93bc4e813a0..dfdab42aed27 100644
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -132,21 +132,102 @@ static u64 amd_pmu_event_map(int hw_event)
return amd_perfmon_event_map[hw_event];
}
-static int amd_pmu_hw_config(struct perf_event *event)
+static struct event_constraint *amd_nb_event_constraint;
+
+/*
+ * Previously calculated offsets
+ */
+static unsigned int event_offsets[X86_PMC_IDX_MAX] __read_mostly;
+static unsigned int count_offsets[X86_PMC_IDX_MAX] __read_mostly;
+static unsigned int rdpmc_indexes[X86_PMC_IDX_MAX] __read_mostly;
+
+/*
+ * Legacy CPUs:
+ * 4 counters starting at 0xc0010000 each offset by 1
+ *
+ * CPUs with core performance counter extensions:
+ * 6 counters starting at 0xc0010200 each offset by 2
+ *
+ * CPUs with north bridge performance counter extensions:
+ * 4 additional counters starting at 0xc0010240 each offset by 2
+ * (indexed right above either one of the above core counters)
+ */
+static inline int amd_pmu_addr_offset(int index, bool eventsel)
{
- int ret;
+ int offset, first, base;
- /* pass precise event sampling to ibs: */
- if (event->attr.precise_ip && get_ibs_caps())
- return -ENOENT;
+ if (!index)
+ return index;
+
+ if (eventsel)
+ offset = event_offsets[index];
+ else
+ offset = count_offsets[index];
+
+ if (offset)
+ return offset;
+
+ if (amd_nb_event_constraint &&
+ test_bit(index, amd_nb_event_constraint->idxmsk)) {
+ /*
+ * calculate the offset of NB counters with respect to
+ * base eventsel or perfctr
+ */
+
+ first = find_first_bit(amd_nb_event_constraint->idxmsk,
+ X86_PMC_IDX_MAX);
+
+ if (eventsel)
+ base = MSR_F15H_NB_PERF_CTL - x86_pmu.eventsel;
+ else
+ base = MSR_F15H_NB_PERF_CTR - x86_pmu.perfctr;
+
+ offset = base + ((index - first) << 1);
+ } else if (!cpu_has_perfctr_core)
+ offset = index;
+ else
+ offset = index << 1;
+
+ if (eventsel)
+ event_offsets[index] = offset;
+ else
+ count_offsets[index] = offset;
+
+ return offset;
+}
+
+static inline int amd_pmu_rdpmc_index(int index)
+{
+ int ret, first;
+
+ if (!index)
+ return index;
+
+ ret = rdpmc_indexes[index];
- ret = x86_pmu_hw_config(event);
if (ret)
return ret;
- if (has_branch_stack(event))
- return -EOPNOTSUPP;
+ if (amd_nb_event_constraint &&
+ test_bit(index, amd_nb_event_constraint->idxmsk)) {
+ /*
+ * according to the mnual, ECX value of the NB counters is
+ * the index of the NB counter (0, 1, 2 or 3) plus 6
+ */
+
+ first = find_first_bit(amd_nb_event_constraint->idxmsk,
+ X86_PMC_IDX_MAX);
+ ret = index - first + 6;
+ } else
+ ret = index;
+
+ rdpmc_indexes[index] = ret;
+
+ return ret;
+}
+static int amd_core_hw_config(struct perf_event *event)
+{
if (event->attr.exclude_host && event->attr.exclude_guest)
/*
* When HO == GO == 1 the hardware treats that as GO == HO == 0
@@ -156,14 +237,37 @@ static int amd_pmu_hw_config(struct perf_event *event)
event->hw.config &= ~(ARCH_PERFMON_EVENTSEL_USR |
ARCH_PERFMON_EVENTSEL_OS);
else if (event->attr.exclude_host)
- event->hw.config |= AMD_PERFMON_EVENTSEL_GUESTONLY;
+ event->hw.config |= AMD64_EVENTSEL_GUESTONLY;
else if (event->attr.exclude_guest)
- event->hw.config |= AMD_PERFMON_EVENTSEL_HOSTONLY;
+ event->hw.config |= AMD64_EVENTSEL_HOSTONLY;
+
+ return 0;
+}
+
+/*
+ * NB counters do not support the following event select bits:
+ * Host/Guest only
+ * Counter mask
+ * Invert counter mask
+ * Edge detect
+ * OS/User mode
+ */
+static int amd_nb_hw_config(struct perf_event *event)
+{
+ /* for NB, we only allow system wide counting mode */
+ if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+ return -EINVAL;
+
+ if (event->attr.exclude_user || event->attr.exclude_kernel ||
+ event->attr.exclude_host || event->attr.exclude_guest)
+ return -EINVAL;
- if (event->attr.type != PERF_TYPE_RAW)
- return 0;
+ event->hw.config &= ~(ARCH_PERFMON_EVENTSEL_USR |
+ ARCH_PERFMON_EVENTSEL_OS);
- event->hw.config |= event->attr.config & AMD64_RAW_EVENT_MASK;
+ if (event->hw.config & ~(AMD64_RAW_EVENT_MASK_NB |
+ ARCH_PERFMON_EVENTSEL_INT))
+ return -EINVAL;
return 0;
}
@@ -181,6 +285,11 @@ static inline int amd_is_nb_event(struct hw_perf_event *hwc)
return (hwc->config & 0xe0) == 0xe0;
}
+static inline int amd_is_perfctr_nb_event(struct hw_perf_event *hwc)
+{
+ return amd_nb_event_constraint && amd_is_nb_event(hwc);
+}
+
static inline int amd_has_nb(struct cpu_hw_events *cpuc)
{
struct amd_nb *nb = cpuc->amd_nb;
@@ -188,20 +297,37 @@ static inline int amd_has_nb(struct cpu_hw_events *cpuc)
return nb && nb->nb_id != -1;
}
-static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
- struct perf_event *event)
+static int amd_pmu_hw_config(struct perf_event *event)
+{
+ int ret;
+
+ /* pass precise event sampling to ibs: */
+ if (event->attr.precise_ip && get_ibs_caps())
+ return -ENOENT;
+
+ if (has_branch_stack(event))
+ return -EOPNOTSUPP;
+
+ ret = x86_pmu_hw_config(event);
+ if (ret)
+ return ret;
+
+ if (event->attr.type == PERF_TYPE_RAW)
+ event->hw.config |= event->attr.config & AMD64_RAW_EVENT_MASK;
+
+ if (amd_is_perfctr_nb_event(&event->hw))
+ return amd_nb_hw_config(event);
+
+ return amd_core_hw_config(event);
+}
+
+static void __amd_put_nb_event_constraints(struct cpu_hw_events *cpuc,
+ struct perf_event *event)
{
- struct hw_perf_event *hwc = &event->hw;
struct amd_nb *nb = cpuc->amd_nb;
int i;
/*
- * only care about NB events
- */
- if (!(amd_has_nb(cpuc) && amd_is_nb_event(hwc)))
- return;
-
- /*
* need to scan whole list because event may not have
* been assigned during scheduling
*
@@ -215,6 +341,19 @@ static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
}
}
+static void amd_nb_interrupt_hw_config(struct hw_perf_event *hwc)
+{
+ int core_id = cpu_data(smp_processor_id()).cpu_core_id;
+
+ /* deliver interrupts only to this core */
+ if (hwc->config & ARCH_PERFMON_EVENTSEL_INT) {
+ hwc->config |= AMD64_EVENTSEL_INT_CORE_ENABLE;
+ hwc->config &= ~AMD64_EVENTSEL_INT_CORE_SEL_MASK;
+ hwc->config |= (u64)(core_id) <<
+ AMD64_EVENTSEL_INT_CORE_SEL_SHIFT;
+ }
+}
+
/*
* AMD64 NorthBridge events need special treatment because
* counter access needs to be synchronized across all cores
@@ -247,24 +386,24 @@ static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
*
* Given that resources are allocated (cmpxchg), they must be
* eventually freed for others to use. This is accomplished by
- * calling amd_put_event_constraints().
+ * calling __amd_put_nb_event_constraints()
*
* Non NB events are not impacted by this restriction.
*/
static struct event_constraint *
-amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
+__amd_get_nb_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
+ struct event_constraint *c)
{
struct hw_perf_event *hwc = &event->hw;
struct amd_nb *nb = cpuc->amd_nb;
- struct perf_event *old = NULL;
- int max = x86_pmu.num_counters;
- int i, j, k = -1;
+ struct perf_event *old;
+ int idx, new = -1;
- /*
- * if not NB event or no NB, then no constraints
- */
- if (!(amd_has_nb(cpuc) && amd_is_nb_event(hwc)))
- return &unconstrained;
+ if (!c)
+ c = &unconstrained;
+
+ if (cpuc->is_fake)
+ return c;
/*
* detect if already present, if so reuse
@@ -276,48 +415,36 @@ amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
* because of successive calls to x86_schedule_events() from
* hw_perf_group_sched_in() without hw_perf_enable()
*/
- for (i = 0; i < max; i++) {
- /*
- * keep track of first free slot
- */
- if (k == -1 && !nb->owners[i])
- k = i;
+ for_each_set_bit(idx, c->idxmsk, x86_pmu.num_counters) {
+ if (new == -1 || hwc->idx == idx)
+ /* assign free slot, prefer hwc->idx */
+ old = cmpxchg(nb->owners + idx, NULL, event);
+ else if (nb->owners[idx] == event)
+ /* event already present */
+ old = event;
+ else
+ continue;
+
+ if (old && old != event)
+ continue;
+
+ /* reassign to this slot */
+ if (new != -1)
+ cmpxchg(nb->owners + new, event, NULL);
+ new = idx;
/* already present, reuse */
- if (nb->owners[i] == event)
- goto done;
- }
- /*
- * not present, so grab a new slot
- * starting either at:
- */
- if (hwc->idx != -1) {
- /* previous assignment */
- i = hwc->idx;
- } else if (k != -1) {
- /* start from free slot found */
- i = k;
- } else {
- /*
- * event not found, no slot found in
- * first pass, try again from the
- * beginning
- */
- i = 0;
- }
- j = i;
- do {
- old = cmpxchg(nb->owners+i, NULL, event);
- if (!old)
+ if (old == event)
break;
- if (++i == max)
- i = 0;
- } while (i != j);
-done:
- if (!old)
- return &nb->event_constraints[i];
-
- return &emptyconstraint;
+ }
+
+ if (new == -1)
+ return &emptyconstraint;
+
+ if (amd_is_perfctr_nb_event(hwc))
+ amd_nb_interrupt_hw_config(hwc);
+
+ return &nb->event_constraints[new];
}
static struct amd_nb *amd_alloc_nb(int cpu)
@@ -364,7 +491,7 @@ static void amd_pmu_cpu_starting(int cpu)
struct amd_nb *nb;
int i, nb_id;
- cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY;
+ cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY;
if (boot_cpu_data.x86_max_cores < 2)
return;
@@ -407,6 +534,26 @@ static void amd_pmu_cpu_dead(int cpu)
}
}
+static struct event_constraint *
+amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
+{
+ /*
+ * if not NB event or no NB, then no constraints
+ */
+ if (!(amd_has_nb(cpuc) && amd_is_nb_event(&event->hw)))
+ return &unconstrained;
+
+ return __amd_get_nb_event_constraints(cpuc, event,
+ amd_nb_event_constraint);
+}
+
+static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
+ struct perf_event *event)
+{
+ if (amd_has_nb(cpuc) && amd_is_nb_event(&event->hw))
+ __amd_put_nb_event_constraints(cpuc, event);
+}
+
PMU_FORMAT_ATTR(event, "config:0-7,32-35");
PMU_FORMAT_ATTR(umask, "config:8-15" );
PMU_FORMAT_ATTR(edge, "config:18" );
@@ -496,6 +643,9 @@ static struct event_constraint amd_f15_PMC30 = EVENT_CONSTRAINT_OVERLAP(0, 0x09,
static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0);
static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0);
+static struct event_constraint amd_NBPMC96 = EVENT_CONSTRAINT(0, 0x3C0, 0);
+static struct event_constraint amd_NBPMC74 = EVENT_CONSTRAINT(0, 0xF0, 0);
+
static struct event_constraint *
amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event)
{
@@ -561,8 +711,8 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev
return &amd_f15_PMC20;
}
case AMD_EVENT_NB:
- /* not yet implemented */
- return &emptyconstraint;
+ return __amd_get_nb_event_constraints(cpuc, event,
+ amd_nb_event_constraint);
default:
return &emptyconstraint;
}
@@ -587,6 +737,8 @@ static __initconst const struct x86_pmu amd_pmu = {
.schedule_events = x86_schedule_events,
.eventsel = MSR_K7_EVNTSEL0,
.perfctr = MSR_K7_PERFCTR0,
+ .addr_offset = amd_pmu_addr_offset,
+ .rdpmc_index = amd_pmu_rdpmc_index,
.event_map = amd_pmu_event_map,
.max_events = ARRAY_SIZE(amd_perfmon_event_map),
.num_counters = AMD64_NUM_COUNTERS,
@@ -608,7 +760,7 @@ static __initconst const struct x86_pmu amd_pmu = {
static int setup_event_constraints(void)
{
- if (boot_cpu_data.x86 >= 0x15)
+ if (boot_cpu_data.x86 == 0x15)
x86_pmu.get_event_constraints = amd_get_event_constraints_f15h;
return 0;
}
@@ -638,6 +790,23 @@ static int setup_perfctr_core(void)
return 0;
}
+static int setup_perfctr_nb(void)
+{
+ if (!cpu_has_perfctr_nb)
+ return -ENODEV;
+
+ x86_pmu.num_counters += AMD64_NUM_COUNTERS_NB;
+
+ if (cpu_has_perfctr_core)
+ amd_nb_event_constraint = &amd_NBPMC96;
+ else
+ amd_nb_event_constraint = &amd_NBPMC74;
+
+ printk(KERN_INFO "perf: AMD northbridge performance counters detected\n");
+
+ return 0;
+}
+
__init int amd_pmu_init(void)
{
/* Performance-monitoring supported from K7 and later: */
@@ -648,6 +817,7 @@ __init int amd_pmu_init(void)
setup_event_constraints();
setup_perfctr_core();
+ setup_perfctr_nb();
/* Events are common for all AMDs */
memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
@@ -678,7 +848,7 @@ void amd_pmu_disable_virt(void)
* SVM is disabled the Guest-only bits still gets set and the counter
* will not count anything.
*/
- cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY;
+ cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY;
/* Reload all events */
x86_pmu_disable_all();
diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
index 6336bcbd0618..5f0581e713c2 100644
--- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c
+++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
@@ -528,7 +528,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
if (!test_bit(IBS_STARTED, pcpu->state)) {
/*
* Catch spurious interrupts after stopping IBS: After
- * disabling IBS there could be still incomming NMIs
+ * disabling IBS there could be still incoming NMIs
* with samples that even have the valid bit cleared.
* Mark all this NMIs as handled.
*/
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index 3286a92e662a..e280253f6f94 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -28,7 +28,6 @@ static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c)
{
seq_printf(m,
"fdiv_bug\t: %s\n"
- "hlt_bug\t\t: %s\n"
"f00f_bug\t: %s\n"
"coma_bug\t: %s\n"
"fpu\t\t: %s\n"
@@ -36,7 +35,6 @@ static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c)
"cpuid level\t: %d\n"
"wp\t\t: %s\n",
c->fdiv_bug ? "yes" : "no",
- c->hlt_works_ok ? "no" : "yes",
c->f00f_bug ? "yes" : "no",
c->coma_bug ? "yes" : "no",
c->hard_math ? "yes" : "no",
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index d22d0c4edcfd..03a36321ec54 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -33,6 +33,9 @@
#define VMWARE_PORT_CMD_GETVERSION 10
#define VMWARE_PORT_CMD_GETHZ 45
+#define VMWARE_PORT_CMD_GETVCPU_INFO 68
+#define VMWARE_PORT_CMD_LEGACY_X2APIC 3
+#define VMWARE_PORT_CMD_VCPU_RESERVED 31
#define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \
__asm__("inl (%%dx)" : \
@@ -125,10 +128,20 @@ static void __cpuinit vmware_set_cpu_features(struct cpuinfo_x86 *c)
set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE);
}
+/* Checks if hypervisor supports x2apic without VT-D interrupt remapping. */
+static bool __init vmware_legacy_x2apic_available(void)
+{
+ uint32_t eax, ebx, ecx, edx;
+ VMWARE_PORT(GETVCPU_INFO, eax, ebx, ecx, edx);
+ return (eax & (1 << VMWARE_PORT_CMD_VCPU_RESERVED)) == 0 &&
+ (eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC)) != 0;
+}
+
const __refconst struct hypervisor_x86 x86_hyper_vmware = {
.name = "VMware",
.detect = vmware_platform,
.set_cpu_features = vmware_set_cpu_features,
.init_platform = vmware_platform_setup,
+ .x2apic_available = vmware_legacy_x2apic_available,
};
EXPORT_SYMBOL(x86_hyper_vmware);
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index ae42418bc50f..c8797d55b245 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -232,7 +232,7 @@ void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
bust_spinlocks(0);
die_owner = -1;
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
die_nest_count--;
if (!die_nest_count)
/* Nest count reaches zero, release the lock. */
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index df06ade26bef..d32abeabbda5 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -835,7 +835,7 @@ static int __init parse_memopt(char *p)
}
early_param("mem", parse_memopt);
-static int __init parse_memmap_opt(char *p)
+static int __init parse_memmap_one(char *p)
{
char *oldp;
u64 start_at, mem_size;
@@ -877,6 +877,20 @@ static int __init parse_memmap_opt(char *p)
return *p == '\0' ? 0 : -EINVAL;
}
+static int __init parse_memmap_opt(char *str)
+{
+ while (str) {
+ char *k = strchr(str, ',');
+
+ if (k)
+ *k++ = 0;
+
+ parse_memmap_one(str);
+ str = k;
+ }
+
+ return 0;
+}
early_param("memmap", parse_memmap_opt);
void __init finish_e820_parsing(void)
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 6ed91d9980e2..8f3e2dec1df3 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -699,51 +699,6 @@ END(syscall_badsys)
*/
.popsection
-/*
- * System calls that need a pt_regs pointer.
- */
-#define PTREGSCALL0(name) \
-ENTRY(ptregs_##name) ; \
- leal 4(%esp),%eax; \
- jmp sys_##name; \
-ENDPROC(ptregs_##name)
-
-#define PTREGSCALL1(name) \
-ENTRY(ptregs_##name) ; \
- leal 4(%esp),%edx; \
- movl (PT_EBX+4)(%esp),%eax; \
- jmp sys_##name; \
-ENDPROC(ptregs_##name)
-
-#define PTREGSCALL2(name) \
-ENTRY(ptregs_##name) ; \
- leal 4(%esp),%ecx; \
- movl (PT_ECX+4)(%esp),%edx; \
- movl (PT_EBX+4)(%esp),%eax; \
- jmp sys_##name; \
-ENDPROC(ptregs_##name)
-
-#define PTREGSCALL3(name) \
-ENTRY(ptregs_##name) ; \
- CFI_STARTPROC; \
- leal 4(%esp),%eax; \
- pushl_cfi %eax; \
- movl PT_EDX(%eax),%ecx; \
- movl PT_ECX(%eax),%edx; \
- movl PT_EBX(%eax),%eax; \
- call sys_##name; \
- addl $4,%esp; \
- CFI_ADJUST_CFA_OFFSET -4; \
- ret; \
- CFI_ENDPROC; \
-ENDPROC(ptregs_##name)
-
-PTREGSCALL1(iopl)
-PTREGSCALL0(sigreturn)
-PTREGSCALL0(rt_sigreturn)
-PTREGSCALL2(vm86)
-PTREGSCALL1(vm86old)
-
.macro FIXUP_ESPFIX_STACK
/*
* Switch back for ESPFIX stack to the normal zerobased stack
@@ -1091,11 +1046,18 @@ ENTRY(xen_failsafe_callback)
_ASM_EXTABLE(4b,9b)
ENDPROC(xen_failsafe_callback)
-BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK,
+BUILD_INTERRUPT3(xen_hvm_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
xen_evtchn_do_upcall)
#endif /* CONFIG_XEN */
+#if IS_ENABLED(CONFIG_HYPERV)
+
+BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
+ hyperv_vector_handler)
+
+#endif /* CONFIG_HYPERV */
+
#ifdef CONFIG_FUNCTION_TRACER
#ifdef CONFIG_DYNAMIC_FTRACE
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index cb3c591339aa..c1d01e6ca790 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -828,23 +828,6 @@ int_restore_rest:
CFI_ENDPROC
END(system_call)
-/*
- * Certain special system calls that need to save a complete full stack frame.
- */
- .macro PTREGSCALL label,func,arg
-ENTRY(\label)
- PARTIAL_FRAME 1 8 /* offset 8: return address */
- subq $REST_SKIP, %rsp
- CFI_ADJUST_CFA_OFFSET REST_SKIP
- call save_rest
- DEFAULT_FRAME 0 8 /* offset 8: return address */
- leaq 8(%rsp), \arg /* pt_regs pointer */
- call \func
- jmp ptregscall_common
- CFI_ENDPROC
-END(\label)
- .endm
-
.macro FORK_LIKE func
ENTRY(stub_\func)
CFI_STARTPROC
@@ -861,10 +844,22 @@ ENTRY(stub_\func)
END(stub_\func)
.endm
+ .macro FIXED_FRAME label,func
+ENTRY(\label)
+ CFI_STARTPROC
+ PARTIAL_FRAME 0 8 /* offset 8: return address */
+ FIXUP_TOP_OF_STACK %r11, 8-ARGOFFSET
+ call \func
+ RESTORE_TOP_OF_STACK %r11, 8-ARGOFFSET
+ ret
+ CFI_ENDPROC
+END(\label)
+ .endm
+
FORK_LIKE clone
FORK_LIKE fork
FORK_LIKE vfork
- PTREGSCALL stub_iopl, sys_iopl, %rsi
+ FIXED_FRAME stub_iopl, sys_iopl
ENTRY(ptregscall_common)
DEFAULT_FRAME 1 8 /* offset 8: return address */
@@ -886,7 +881,6 @@ ENTRY(stub_execve)
SAVE_REST
FIXUP_TOP_OF_STACK %r11
call sys_execve
- RESTORE_TOP_OF_STACK %r11
movq %rax,RAX(%rsp)
RESTORE_REST
jmp int_ret_from_sys_call
@@ -902,7 +896,6 @@ ENTRY(stub_rt_sigreturn)
addq $8, %rsp
PARTIAL_FRAME 0
SAVE_REST
- movq %rsp,%rdi
FIXUP_TOP_OF_STACK %r11
call sys_rt_sigreturn
movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
@@ -917,7 +910,6 @@ ENTRY(stub_x32_rt_sigreturn)
addq $8, %rsp
PARTIAL_FRAME 0
SAVE_REST
- movq %rsp,%rdi
FIXUP_TOP_OF_STACK %r11
call sys32_x32_rt_sigreturn
movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
@@ -1454,11 +1446,16 @@ ENTRY(xen_failsafe_callback)
CFI_ENDPROC
END(xen_failsafe_callback)
-apicinterrupt XEN_HVM_EVTCHN_CALLBACK \
+apicinterrupt HYPERVISOR_CALLBACK_VECTOR \
xen_hvm_callback_vector xen_evtchn_do_upcall
#endif /* CONFIG_XEN */
+#if IS_ENABLED(CONFIG_HYPERV)
+apicinterrupt HYPERVISOR_CALLBACK_VECTOR \
+ hyperv_callback_vector hyperv_vector_handler
+#endif /* CONFIG_HYPERV */
+
/*
* Some functions should be protected against kprobes
*/
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 1d414029f1d8..42a392a9fd02 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -89,7 +89,7 @@ do_ftrace_mod_code(unsigned long ip, const void *new_code)
* kernel identity mapping to modify code.
*/
if (within(ip, (unsigned long)_text, (unsigned long)_etext))
- ip = (unsigned long)__va(__pa(ip));
+ ip = (unsigned long)__va(__pa_symbol(ip));
return probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE);
}
@@ -279,7 +279,7 @@ static int ftrace_write(unsigned long ip, const char *val, int size)
* kernel identity mapping to modify code.
*/
if (within(ip, (unsigned long)_text, (unsigned long)_etext))
- ip = (unsigned long)__va(__pa(ip));
+ ip = (unsigned long)__va(__pa_symbol(ip));
return probe_kernel_write((void *)ip, val, size);
}
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index c18f59d10101..138463a24877 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -18,6 +18,7 @@
#include <asm/io_apic.h>
#include <asm/bios_ebda.h>
#include <asm/tlbflush.h>
+#include <asm/bootparam_utils.h>
static void __init i386_default_early_setup(void)
{
@@ -30,19 +31,7 @@ static void __init i386_default_early_setup(void)
void __init i386_start_kernel(void)
{
- memblock_reserve(__pa_symbol(&_text),
- __pa_symbol(&__bss_stop) - __pa_symbol(&_text));
-
-#ifdef CONFIG_BLK_DEV_INITRD
- /* Reserve INITRD */
- if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
- /* Assume only end is not page aligned */
- u64 ramdisk_image = boot_params.hdr.ramdisk_image;
- u64 ramdisk_size = boot_params.hdr.ramdisk_size;
- u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
- memblock_reserve(ramdisk_image, ramdisk_end - ramdisk_image);
- }
-#endif
+ sanitize_boot_params(&boot_params);
/* Call the subarch specific early setup function */
switch (boot_params.hdr.hardware_subarch) {
@@ -57,11 +46,5 @@ void __init i386_start_kernel(void)
break;
}
- /*
- * At this point everything still needed from the boot loader
- * or BIOS or kernel text should be early reserved or marked not
- * RAM in e820. All other memory is free game.
- */
-
start_kernel();
}
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 037df57a99ac..c5e403f6d869 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -25,12 +25,84 @@
#include <asm/kdebug.h>
#include <asm/e820.h>
#include <asm/bios_ebda.h>
+#include <asm/bootparam_utils.h>
+#include <asm/microcode.h>
-static void __init zap_identity_mappings(void)
+/*
+ * Manage page tables very early on.
+ */
+extern pgd_t early_level4_pgt[PTRS_PER_PGD];
+extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD];
+static unsigned int __initdata next_early_pgt = 2;
+
+/* Wipe all early page tables except for the kernel symbol map */
+static void __init reset_early_page_tables(void)
{
- pgd_t *pgd = pgd_offset_k(0UL);
- pgd_clear(pgd);
- __flush_tlb_all();
+ unsigned long i;
+
+ for (i = 0; i < PTRS_PER_PGD-1; i++)
+ early_level4_pgt[i].pgd = 0;
+
+ next_early_pgt = 0;
+
+ write_cr3(__pa(early_level4_pgt));
+}
+
+/* Create a new PMD entry */
+int __init early_make_pgtable(unsigned long address)
+{
+ unsigned long physaddr = address - __PAGE_OFFSET;
+ unsigned long i;
+ pgdval_t pgd, *pgd_p;
+ pudval_t pud, *pud_p;
+ pmdval_t pmd, *pmd_p;
+
+ /* Invalid address or early pgt is done ? */
+ if (physaddr >= MAXMEM || read_cr3() != __pa(early_level4_pgt))
+ return -1;
+
+again:
+ pgd_p = &early_level4_pgt[pgd_index(address)].pgd;
+ pgd = *pgd_p;
+
+ /*
+ * The use of __START_KERNEL_map rather than __PAGE_OFFSET here is
+ * critical -- __PAGE_OFFSET would point us back into the dynamic
+ * range and we might end up looping forever...
+ */
+ if (pgd)
+ pud_p = (pudval_t *)((pgd & PTE_PFN_MASK) + __START_KERNEL_map - phys_base);
+ else {
+ if (next_early_pgt >= EARLY_DYNAMIC_PAGE_TABLES) {
+ reset_early_page_tables();
+ goto again;
+ }
+
+ pud_p = (pudval_t *)early_dynamic_pgts[next_early_pgt++];
+ for (i = 0; i < PTRS_PER_PUD; i++)
+ pud_p[i] = 0;
+ *pgd_p = (pgdval_t)pud_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE;
+ }
+ pud_p += pud_index(address);
+ pud = *pud_p;
+
+ if (pud)
+ pmd_p = (pmdval_t *)((pud & PTE_PFN_MASK) + __START_KERNEL_map - phys_base);
+ else {
+ if (next_early_pgt >= EARLY_DYNAMIC_PAGE_TABLES) {
+ reset_early_page_tables();
+ goto again;
+ }
+
+ pmd_p = (pmdval_t *)early_dynamic_pgts[next_early_pgt++];
+ for (i = 0; i < PTRS_PER_PMD; i++)
+ pmd_p[i] = 0;
+ *pud_p = (pudval_t)pmd_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE;
+ }
+ pmd = (physaddr & PMD_MASK) + (__PAGE_KERNEL_LARGE & ~_PAGE_GLOBAL);
+ pmd_p[pmd_index(address)] = pmd;
+
+ return 0;
}
/* Don't add a printk in there. printk relies on the PDA which is not initialized
@@ -41,13 +113,25 @@ static void __init clear_bss(void)
(unsigned long) __bss_stop - (unsigned long) __bss_start);
}
+static unsigned long get_cmd_line_ptr(void)
+{
+ unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr;
+
+ cmd_line_ptr |= (u64)boot_params.ext_cmd_line_ptr << 32;
+
+ return cmd_line_ptr;
+}
+
static void __init copy_bootdata(char *real_mode_data)
{
char * command_line;
+ unsigned long cmd_line_ptr;
memcpy(&boot_params, real_mode_data, sizeof boot_params);
- if (boot_params.hdr.cmd_line_ptr) {
- command_line = __va(boot_params.hdr.cmd_line_ptr);
+ sanitize_boot_params(&boot_params);
+ cmd_line_ptr = get_cmd_line_ptr();
+ if (cmd_line_ptr) {
+ command_line = __va(cmd_line_ptr);
memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
}
}
@@ -70,54 +154,40 @@ void __init x86_64_start_kernel(char * real_mode_data)
(__START_KERNEL & PGDIR_MASK)));
BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) <= MODULES_END);
+ /* Kill off the identity-map trampoline */
+ reset_early_page_tables();
+
/* clear bss before set_intr_gate with early_idt_handler */
clear_bss();
- /* Make NULL pointers segfault */
- zap_identity_mappings();
-
- max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT;
-
- for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) {
-#ifdef CONFIG_EARLY_PRINTK
+ for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
set_intr_gate(i, &early_idt_handlers[i]);
-#else
- set_intr_gate(i, early_idt_handler);
-#endif
- }
load_idt((const struct desc_ptr *)&idt_descr);
+ copy_bootdata(__va(real_mode_data));
+
+ /*
+ * Load microcode early on BSP.
+ */
+ load_ucode_bsp();
+
if (console_loglevel == 10)
early_printk("Kernel alive\n");
+ clear_page(init_level4_pgt);
+ /* set init_level4_pgt kernel high mapping*/
+ init_level4_pgt[511] = early_level4_pgt[511];
+
x86_64_start_reservations(real_mode_data);
}
void __init x86_64_start_reservations(char *real_mode_data)
{
- copy_bootdata(__va(real_mode_data));
-
- memblock_reserve(__pa_symbol(&_text),
- __pa_symbol(&__bss_stop) - __pa_symbol(&_text));
-
-#ifdef CONFIG_BLK_DEV_INITRD
- /* Reserve INITRD */
- if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
- /* Assume only end is not page aligned */
- unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
- unsigned long ramdisk_size = boot_params.hdr.ramdisk_size;
- unsigned long ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
- memblock_reserve(ramdisk_image, ramdisk_end - ramdisk_image);
- }
-#endif
+ /* version is always not zero if it is copied */
+ if (!boot_params.hdr.version)
+ copy_bootdata(__va(real_mode_data));
reserve_ebda_region();
- /*
- * At this point everything still needed from the boot loader
- * or BIOS or kernel text should be early reserved or marked not
- * RAM in e820. All other memory is free game.
- */
-
start_kernel();
}
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index c8932c79e78b..73afd11799ca 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -144,6 +144,11 @@ ENTRY(startup_32)
movl %eax, pa(olpc_ofw_pgd)
#endif
+#ifdef CONFIG_MICROCODE_EARLY
+ /* Early load ucode on BSP. */
+ call load_ucode_bsp
+#endif
+
/*
* Initialize page tables. This creates a PDE and a set of page
* tables, which are located immediately beyond __brk_base. The variable
@@ -299,6 +304,12 @@ ENTRY(startup_32_smp)
movl %eax,%ss
leal -__PAGE_OFFSET(%ecx),%esp
+#ifdef CONFIG_MICROCODE_EARLY
+ /* Early load ucode on AP. */
+ call load_ucode_ap
+#endif
+
+
default_entry:
#define CR0_STATE (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \
X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \
@@ -307,36 +318,45 @@ default_entry:
movl %eax,%cr0
/*
- * New page tables may be in 4Mbyte page mode and may
- * be using the global pages.
+ * We want to start out with EFLAGS unambiguously cleared. Some BIOSes leave
+ * bits like NT set. This would confuse the debugger if this code is traced. So
+ * initialize them properly now before switching to protected mode. That means
+ * DF in particular (even though we have cleared it earlier after copying the
+ * command line) because GCC expects it.
+ */
+ pushl $0
+ popfl
+
+/*
+ * New page tables may be in 4Mbyte page mode and may be using the global pages.
*
- * NOTE! If we are on a 486 we may have no cr4 at all!
- * Specifically, cr4 exists if and only if CPUID exists
- * and has flags other than the FPU flag set.
+ * NOTE! If we are on a 486 we may have no cr4 at all! Specifically, cr4 exists
+ * if and only if CPUID exists and has flags other than the FPU flag set.
*/
+ movl $-1,pa(X86_CPUID) # preset CPUID level
movl $X86_EFLAGS_ID,%ecx
pushl %ecx
- popfl
- pushfl
- popl %eax
- pushl $0
- popfl
+ popfl # set EFLAGS=ID
pushfl
- popl %edx
- xorl %edx,%eax
- testl %ecx,%eax
- jz 6f # No ID flag = no CPUID = no CR4
+ popl %eax # get EFLAGS
+ testl $X86_EFLAGS_ID,%eax # did EFLAGS.ID remained set?
+ jz enable_paging # hw disallowed setting of ID bit
+ # which means no CPUID and no CR4
+
+ xorl %eax,%eax
+ cpuid
+ movl %eax,pa(X86_CPUID) # save largest std CPUID function
movl $1,%eax
cpuid
- andl $~1,%edx # Ignore CPUID.FPU
- jz 6f # No flags or only CPUID.FPU = no CR4
+ andl $~1,%edx # Ignore CPUID.FPU
+ jz enable_paging # No flags or only CPUID.FPU = no CR4
movl pa(mmu_cr4_features),%eax
movl %eax,%cr4
testb $X86_CR4_PAE, %al # check if PAE is enabled
- jz 6f
+ jz enable_paging
/* Check if extended functions are implemented */
movl $0x80000000, %eax
@@ -344,7 +364,7 @@ default_entry:
/* Value must be in the range 0x80000001 to 0x8000ffff */
subl $0x80000001, %eax
cmpl $(0x8000ffff-0x80000001), %eax
- ja 6f
+ ja enable_paging
/* Clear bogus XD_DISABLE bits */
call verify_cpu
@@ -353,7 +373,7 @@ default_entry:
cpuid
/* Execute Disable bit supported? */
btl $(X86_FEATURE_NX & 31), %edx
- jnc 6f
+ jnc enable_paging
/* Setup EFER (Extended Feature Enable Register) */
movl $MSR_EFER, %ecx
@@ -363,7 +383,7 @@ default_entry:
/* Make changes effective */
wrmsr
-6:
+enable_paging:
/*
* Enable paging
@@ -378,14 +398,6 @@ default_entry:
addl $__PAGE_OFFSET, %esp
/*
- * Initialize eflags. Some BIOS's leave bits like NT set. This would
- * confuse the debugger if this code is traced.
- * XXX - best to initialize before switching to protected mode.
- */
- pushl $0
- popfl
-
-/*
* start system 32-bit setup. We need to re-do some of the things done
* in 16-bit mode for the "real" operations.
*/
@@ -394,31 +406,11 @@ default_entry:
jz 1f # Did we do this already?
call *%eax
1:
-
-/* check if it is 486 or 386. */
+
/*
- * XXX - this does a lot of unnecessary setup. Alignment checks don't
- * apply at our cpl of 0 and the stack ought to be aligned already, and
- * we don't need to preserve eflags.
+ * Check if it is 486
*/
- movl $-1,X86_CPUID # -1 for no CPUID initially
- movb $3,X86 # at least 386
- pushfl # push EFLAGS
- popl %eax # get EFLAGS
- movl %eax,%ecx # save original EFLAGS
- xorl $0x240000,%eax # flip AC and ID bits in EFLAGS
- pushl %eax # copy to EFLAGS
- popfl # set EFLAGS
- pushfl # get new EFLAGS
- popl %eax # put it in eax
- xorl %ecx,%eax # change in flags
- pushl %ecx # restore original EFLAGS
- popfl
- testl $0x40000,%eax # check if AC bit changed
- je is386
-
- movb $4,X86 # at least 486
- testl $0x200000,%eax # check if ID bit changed
+ cmpl $-1,X86_CPUID
je is486
/* get vendor info */
@@ -444,11 +436,10 @@ default_entry:
movb %cl,X86_MASK
movl %edx,X86_CAPABILITY
-is486: movl $0x50022,%ecx # set AM, WP, NE and MP
- jmp 2f
-
-is386: movl $2,%ecx # set MP
-2: movl %cr0,%eax
+is486:
+ movb $4,X86
+ movl $0x50022,%ecx # set AM, WP, NE and MP
+ movl %cr0,%eax
andl $0x80000011,%eax # Save PG,PE,ET
orl %ecx,%eax
movl %eax,%cr0
@@ -473,7 +464,6 @@ is386: movl $2,%ecx # set MP
xorl %eax,%eax # Clear LDT
lldt %ax
- cld # gcc2 wants the direction flag cleared at all times
pushl $0 # fake return address for unwinder
jmp *(initial_code)
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 980053c4b9cc..b7de3b25adb5 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -47,14 +47,13 @@ L3_START_KERNEL = pud_index(__START_KERNEL_map)
.code64
.globl startup_64
startup_64:
-
/*
* At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 1,
* and someone has loaded an identity mapped page table
* for us. These identity mapped page tables map all of the
* kernel pages and possibly all of memory.
*
- * %esi holds a physical pointer to real_mode_data.
+ * %rsi holds a physical pointer to real_mode_data.
*
* We come here either directly from a 64bit bootloader, or from
* arch/x86_64/boot/compressed/head.S.
@@ -66,7 +65,8 @@ startup_64:
* tables and then reload them.
*/
- /* Compute the delta between the address I am compiled to run at and the
+ /*
+ * Compute the delta between the address I am compiled to run at and the
* address I am actually running at.
*/
leaq _text(%rip), %rbp
@@ -78,45 +78,62 @@ startup_64:
testl %eax, %eax
jnz bad_address
- /* Is the address too large? */
- leaq _text(%rip), %rdx
- movq $PGDIR_SIZE, %rax
- cmpq %rax, %rdx
- jae bad_address
-
- /* Fixup the physical addresses in the page table
+ /*
+ * Is the address too large?
*/
- addq %rbp, init_level4_pgt + 0(%rip)
- addq %rbp, init_level4_pgt + (L4_PAGE_OFFSET*8)(%rip)
- addq %rbp, init_level4_pgt + (L4_START_KERNEL*8)(%rip)
+ leaq _text(%rip), %rax
+ shrq $MAX_PHYSMEM_BITS, %rax
+ jnz bad_address
- addq %rbp, level3_ident_pgt + 0(%rip)
+ /*
+ * Fixup the physical addresses in the page table
+ */
+ addq %rbp, early_level4_pgt + (L4_START_KERNEL*8)(%rip)
addq %rbp, level3_kernel_pgt + (510*8)(%rip)
addq %rbp, level3_kernel_pgt + (511*8)(%rip)
addq %rbp, level2_fixmap_pgt + (506*8)(%rip)
- /* Add an Identity mapping if I am above 1G */
+ /*
+ * Set up the identity mapping for the switchover. These
+ * entries should *NOT* have the global bit set! This also
+ * creates a bunch of nonsense entries but that is fine --
+ * it avoids problems around wraparound.
+ */
leaq _text(%rip), %rdi
- andq $PMD_PAGE_MASK, %rdi
+ leaq early_level4_pgt(%rip), %rbx
movq %rdi, %rax
- shrq $PUD_SHIFT, %rax
- andq $(PTRS_PER_PUD - 1), %rax
- jz ident_complete
+ shrq $PGDIR_SHIFT, %rax
- leaq (level2_spare_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
- leaq level3_ident_pgt(%rip), %rbx
- movq %rdx, 0(%rbx, %rax, 8)
+ leaq (4096 + _KERNPG_TABLE)(%rbx), %rdx
+ movq %rdx, 0(%rbx,%rax,8)
+ movq %rdx, 8(%rbx,%rax,8)
+ addq $4096, %rdx
movq %rdi, %rax
- shrq $PMD_SHIFT, %rax
- andq $(PTRS_PER_PMD - 1), %rax
- leaq __PAGE_KERNEL_IDENT_LARGE_EXEC(%rdi), %rdx
- leaq level2_spare_pgt(%rip), %rbx
- movq %rdx, 0(%rbx, %rax, 8)
-ident_complete:
+ shrq $PUD_SHIFT, %rax
+ andl $(PTRS_PER_PUD-1), %eax
+ movq %rdx, (4096+0)(%rbx,%rax,8)
+ movq %rdx, (4096+8)(%rbx,%rax,8)
+
+ addq $8192, %rbx
+ movq %rdi, %rax
+ shrq $PMD_SHIFT, %rdi
+ addq $(__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL), %rax
+ leaq (_end - 1)(%rip), %rcx
+ shrq $PMD_SHIFT, %rcx
+ subq %rdi, %rcx
+ incl %ecx
+
+1:
+ andq $(PTRS_PER_PMD - 1), %rdi
+ movq %rax, (%rbx,%rdi,8)
+ incq %rdi
+ addq $PMD_SIZE, %rax
+ decl %ecx
+ jnz 1b
/*
* Fixup the kernel text+data virtual addresses. Note that
@@ -124,7 +141,6 @@ ident_complete:
* cleanup_highmap() fixes this up along with the mappings
* beyond _end.
*/
-
leaq level2_kernel_pgt(%rip), %rdi
leaq 4096(%rdi), %r8
/* See if it is a valid page table entry */
@@ -139,17 +155,14 @@ ident_complete:
/* Fixup phys_base */
addq %rbp, phys_base(%rip)
- /* Due to ENTRY(), sometimes the empty space gets filled with
- * zeros. Better take a jmp than relying on empty space being
- * filled with 0x90 (nop)
- */
- jmp secondary_startup_64
+ movq $(early_level4_pgt - __START_KERNEL_map), %rax
+ jmp 1f
ENTRY(secondary_startup_64)
/*
* At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 1,
* and someone has loaded a mapped page table.
*
- * %esi holds a physical pointer to real_mode_data.
+ * %rsi holds a physical pointer to real_mode_data.
*
* We come here either from startup_64 (using physical addresses)
* or from trampoline.S (using virtual addresses).
@@ -159,12 +172,14 @@ ENTRY(secondary_startup_64)
* after the boot processor executes this code.
*/
+ movq $(init_level4_pgt - __START_KERNEL_map), %rax
+1:
+
/* Enable PAE mode and PGE */
- movl $(X86_CR4_PAE | X86_CR4_PGE), %eax
- movq %rax, %cr4
+ movl $(X86_CR4_PAE | X86_CR4_PGE), %ecx
+ movq %rcx, %cr4
/* Setup early boot stage 4 level pagetables. */
- movq $(init_level4_pgt - __START_KERNEL_map), %rax
addq phys_base(%rip), %rax
movq %rax, %cr3
@@ -196,7 +211,7 @@ ENTRY(secondary_startup_64)
movq %rax, %cr0
/* Setup a boot time stack */
- movq stack_start(%rip),%rsp
+ movq stack_start(%rip), %rsp
/* zero EFLAGS after setting rsp */
pushq $0
@@ -236,15 +251,33 @@ ENTRY(secondary_startup_64)
movl initial_gs+4(%rip),%edx
wrmsr
- /* esi is pointer to real mode structure with interesting info.
+ /* rsi is pointer to real mode structure with interesting info.
pass it to C */
- movl %esi, %edi
+ movq %rsi, %rdi
/* Finally jump to run C code and to be on real kernel address
* Since we are running on identity-mapped space we have to jump
* to the full 64bit address, this is only possible as indirect
* jump. In addition we need to ensure %cs is set so we make this
* a far return.
+ *
+ * Note: do not change to far jump indirect with 64bit offset.
+ *
+ * AMD does not support far jump indirect with 64bit offset.
+ * AMD64 Architecture Programmer's Manual, Volume 3: states only
+ * JMP FAR mem16:16 FF /5 Far jump indirect,
+ * with the target specified by a far pointer in memory.
+ * JMP FAR mem16:32 FF /5 Far jump indirect,
+ * with the target specified by a far pointer in memory.
+ *
+ * Intel64 does support 64bit offset.
+ * Software Developer Manual Vol 2: states:
+ * FF /5 JMP m16:16 Jump far, absolute indirect,
+ * address given in m16:16
+ * FF /5 JMP m16:32 Jump far, absolute indirect,
+ * address given in m16:32.
+ * REX.W + FF /5 JMP m16:64 Jump far, absolute indirect,
+ * address given in m16:64.
*/
movq initial_code(%rip),%rax
pushq $0 # fake return address to stop unwinder
@@ -270,13 +303,13 @@ ENDPROC(start_cpu0)
/* SMP bootup changes these two */
__REFDATA
- .align 8
- ENTRY(initial_code)
+ .balign 8
+ GLOBAL(initial_code)
.quad x86_64_start_kernel
- ENTRY(initial_gs)
+ GLOBAL(initial_gs)
.quad INIT_PER_CPU_VAR(irq_stack_union)
- ENTRY(stack_start)
+ GLOBAL(stack_start)
.quad init_thread_union+THREAD_SIZE-8
.word 0
__FINITDATA
@@ -284,7 +317,7 @@ ENDPROC(start_cpu0)
bad_address:
jmp bad_address
- .section ".init.text","ax"
+ __INIT
.globl early_idt_handlers
early_idt_handlers:
# 104(%rsp) %rflags
@@ -303,6 +336,7 @@ early_idt_handlers:
i = i + 1
.endr
+/* This is global to keep gas from relaxing the jumps */
ENTRY(early_idt_handler)
cld
@@ -321,14 +355,22 @@ ENTRY(early_idt_handler)
pushq %r11 # 0(%rsp)
cmpl $__KERNEL_CS,96(%rsp)
- jne 10f
+ jne 11f
+
+ cmpl $14,72(%rsp) # Page fault?
+ jnz 10f
+ GET_CR2_INTO(%rdi) # can clobber any volatile register if pv
+ call early_make_pgtable
+ andl %eax,%eax
+ jz 20f # All good
+10:
leaq 88(%rsp),%rdi # Pointer to %rip
call early_fixup_exception
andl %eax,%eax
jnz 20f # Found an exception entry
-10:
+11:
#ifdef CONFIG_EARLY_PRINTK
GET_CR2_INTO(%r9) # can clobber any volatile register if pv
movl 80(%rsp),%r8d # error code
@@ -350,7 +392,7 @@ ENTRY(early_idt_handler)
1: hlt
jmp 1b
-20: # Exception table entry found
+20: # Exception table entry found or page table generated
popq %r11
popq %r10
popq %r9
@@ -363,6 +405,9 @@ ENTRY(early_idt_handler)
addq $16,%rsp # drop vector number and error code
decl early_recursion_flag(%rip)
INTERRUPT_RETURN
+ENDPROC(early_idt_handler)
+
+ __INITDATA
.balign 4
early_recursion_flag:
@@ -374,11 +419,10 @@ early_idt_msg:
early_idt_ripmsg:
.asciz "RIP %s\n"
#endif /* CONFIG_EARLY_PRINTK */
- .previous
#define NEXT_PAGE(name) \
.balign PAGE_SIZE; \
-ENTRY(name)
+GLOBAL(name)
/* Automate the creation of 1 to 1 mapping pmd entries */
#define PMDS(START, PERM, COUNT) \
@@ -388,24 +432,37 @@ ENTRY(name)
i = i + 1 ; \
.endr
+ __INITDATA
+NEXT_PAGE(early_level4_pgt)
+ .fill 511,8,0
+ .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
+
+NEXT_PAGE(early_dynamic_pgts)
+ .fill 512*EARLY_DYNAMIC_PAGE_TABLES,8,0
+
.data
- /*
- * This default setting generates an ident mapping at address 0x100000
- * and a mapping for the kernel that precisely maps virtual address
- * 0xffffffff80000000 to physical address 0x000000. (always using
- * 2Mbyte large pages provided by PAE mode)
- */
+
+#ifndef CONFIG_XEN
NEXT_PAGE(init_level4_pgt)
- .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
- .org init_level4_pgt + L4_PAGE_OFFSET*8, 0
- .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
- .org init_level4_pgt + L4_START_KERNEL*8, 0
+ .fill 512,8,0
+#else
+NEXT_PAGE(init_level4_pgt)
+ .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+ .org init_level4_pgt + L4_PAGE_OFFSET*8, 0
+ .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+ .org init_level4_pgt + L4_START_KERNEL*8, 0
/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
- .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
+ .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
NEXT_PAGE(level3_ident_pgt)
.quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
- .fill 511,8,0
+ .fill 511, 8, 0
+NEXT_PAGE(level2_ident_pgt)
+ /* Since I easily can, map the first 1G.
+ * Don't set NX because code runs from these pages.
+ */
+ PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
+#endif
NEXT_PAGE(level3_kernel_pgt)
.fill L3_START_KERNEL,8,0
@@ -413,21 +470,6 @@ NEXT_PAGE(level3_kernel_pgt)
.quad level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
.quad level2_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE
-NEXT_PAGE(level2_fixmap_pgt)
- .fill 506,8,0
- .quad level1_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE
- /* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */
- .fill 5,8,0
-
-NEXT_PAGE(level1_fixmap_pgt)
- .fill 512,8,0
-
-NEXT_PAGE(level2_ident_pgt)
- /* Since I easily can, map the first 1G.
- * Don't set NX because code runs from these pages.
- */
- PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
-
NEXT_PAGE(level2_kernel_pgt)
/*
* 512 MB kernel mapping. We spend a full page on this pagetable
@@ -442,11 +484,16 @@ NEXT_PAGE(level2_kernel_pgt)
PMDS(0, __PAGE_KERNEL_LARGE_EXEC,
KERNEL_IMAGE_SIZE/PMD_SIZE)
-NEXT_PAGE(level2_spare_pgt)
- .fill 512, 8, 0
+NEXT_PAGE(level2_fixmap_pgt)
+ .fill 506,8,0
+ .quad level1_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE
+ /* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */
+ .fill 5,8,0
+
+NEXT_PAGE(level1_fixmap_pgt)
+ .fill 512,8,0
#undef PMDS
-#undef NEXT_PAGE
.data
.align 16
@@ -472,6 +519,5 @@ ENTRY(nmi_idt_table)
.skip IDT_ENTRIES * 16
__PAGE_ALIGNED_BSS
- .align PAGE_SIZE
-ENTRY(empty_zero_page)
+NEXT_PAGE(empty_zero_page)
.skip PAGE_SIZE
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index e28670f9a589..da85a8e830a1 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -478,7 +478,7 @@ static int hpet_msi_next_event(unsigned long delta,
static int hpet_setup_msi_irq(unsigned int irq)
{
- if (arch_setup_hpet_msi(irq, hpet_blockid)) {
+ if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) {
destroy_irq(irq);
return -EINVAL;
}
diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c
index 9c3bd4a2050e..0fa69127209a 100644
--- a/arch/x86/kernel/i386_ksyms_32.c
+++ b/arch/x86/kernel/i386_ksyms_32.c
@@ -26,6 +26,7 @@ EXPORT_SYMBOL(csum_partial_copy_generic);
EXPORT_SYMBOL(__get_user_1);
EXPORT_SYMBOL(__get_user_2);
EXPORT_SYMBOL(__get_user_4);
+EXPORT_SYMBOL(__get_user_8);
EXPORT_SYMBOL(__put_user_1);
EXPORT_SYMBOL(__put_user_2);
diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c
index 8c968974253d..4ddaf66ea35f 100644
--- a/arch/x86/kernel/ioport.c
+++ b/arch/x86/kernel/ioport.c
@@ -93,8 +93,9 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
* on system-call entry - see also fork() and the signal handling
* code.
*/
-long sys_iopl(unsigned int level, struct pt_regs *regs)
+SYSCALL_DEFINE1(iopl, unsigned int, level)
{
+ struct pt_regs *regs = current_pt_regs();
unsigned int old = (regs->flags >> 12) & 3;
struct thread_struct *t = &current->thread;
diff --git a/arch/x86/kernel/kprobes/Makefile b/arch/x86/kernel/kprobes/Makefile
new file mode 100644
index 000000000000..0d33169cc1a2
--- /dev/null
+++ b/arch/x86/kernel/kprobes/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for kernel probes
+#
+
+obj-$(CONFIG_KPROBES) += core.o
+obj-$(CONFIG_OPTPROBES) += opt.o
+obj-$(CONFIG_KPROBES_ON_FTRACE) += ftrace.o
diff --git a/arch/x86/kernel/kprobes-common.h b/arch/x86/kernel/kprobes/common.h
index 3230b68ef29a..2e9d4b5af036 100644
--- a/arch/x86/kernel/kprobes-common.h
+++ b/arch/x86/kernel/kprobes/common.h
@@ -99,4 +99,15 @@ static inline unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsig
return addr;
}
#endif
+
+#ifdef CONFIG_KPROBES_ON_FTRACE
+extern int skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+ struct kprobe_ctlblk *kcb);
+#else
+static inline int skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+ struct kprobe_ctlblk *kcb)
+{
+ return 0;
+}
+#endif
#endif
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes/core.c
index 57916c0d3cf6..e124554598ee 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -58,7 +58,7 @@
#include <asm/insn.h>
#include <asm/debugreg.h>
-#include "kprobes-common.h"
+#include "common.h"
void jprobe_return_end(void);
@@ -78,7 +78,7 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
* Groups, and some special opcodes can not boost.
* This is non-const and volatile to keep gcc from statically
* optimizing it out, as variable_test_bit makes gcc think only
- * *(unsigned long*) is used.
+ * *(unsigned long*) is used.
*/
static volatile u32 twobyte_is_boostable[256 / 32] = {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
@@ -117,7 +117,7 @@ static void __kprobes __synthesize_relative_insn(void *from, void *to, u8 op)
struct __arch_relative_insn {
u8 op;
s32 raddr;
- } __attribute__((packed)) *insn;
+ } __packed *insn;
insn = (struct __arch_relative_insn *)from;
insn->raddr = (s32)((long)(to) - ((long)(from) + 5));
@@ -541,23 +541,6 @@ reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb
return 1;
}
-#ifdef KPROBES_CAN_USE_FTRACE
-static void __kprobes skip_singlestep(struct kprobe *p, struct pt_regs *regs,
- struct kprobe_ctlblk *kcb)
-{
- /*
- * Emulate singlestep (and also recover regs->ip)
- * as if there is a 5byte nop
- */
- regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE;
- if (unlikely(p->post_handler)) {
- kcb->kprobe_status = KPROBE_HIT_SSDONE;
- p->post_handler(p, regs, 0);
- }
- __this_cpu_write(current_kprobe, NULL);
-}
-#endif
-
/*
* Interrupts are disabled on entry as trap3 is an interrupt gate and they
* remain disabled throughout this function.
@@ -616,13 +599,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
} else if (kprobe_running()) {
p = __this_cpu_read(current_kprobe);
if (p->break_handler && p->break_handler(p, regs)) {
-#ifdef KPROBES_CAN_USE_FTRACE
- if (kprobe_ftrace(p)) {
- skip_singlestep(p, regs, kcb);
- return 1;
- }
-#endif
- setup_singlestep(p, regs, kcb, 0);
+ if (!skip_singlestep(p, regs, kcb))
+ setup_singlestep(p, regs, kcb, 0);
return 1;
}
} /* else: not a kprobe fault; let the kernel handle it */
@@ -1075,50 +1053,6 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
return 0;
}
-#ifdef KPROBES_CAN_USE_FTRACE
-/* Ftrace callback handler for kprobes */
-void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
- struct ftrace_ops *ops, struct pt_regs *regs)
-{
- struct kprobe *p;
- struct kprobe_ctlblk *kcb;
- unsigned long flags;
-
- /* Disable irq for emulating a breakpoint and avoiding preempt */
- local_irq_save(flags);
-
- p = get_kprobe((kprobe_opcode_t *)ip);
- if (unlikely(!p) || kprobe_disabled(p))
- goto end;
-
- kcb = get_kprobe_ctlblk();
- if (kprobe_running()) {
- kprobes_inc_nmissed_count(p);
- } else {
- /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
- regs->ip = ip + sizeof(kprobe_opcode_t);
-
- __this_cpu_write(current_kprobe, p);
- kcb->kprobe_status = KPROBE_HIT_ACTIVE;
- if (!p->pre_handler || !p->pre_handler(p, regs))
- skip_singlestep(p, regs, kcb);
- /*
- * If pre_handler returns !0, it sets regs->ip and
- * resets current kprobe.
- */
- }
-end:
- local_irq_restore(flags);
-}
-
-int __kprobes arch_prepare_kprobe_ftrace(struct kprobe *p)
-{
- p->ainsn.insn = NULL;
- p->ainsn.boostable = -1;
- return 0;
-}
-#endif
-
int __init arch_init_kprobes(void)
{
return arch_init_optprobes();
diff --git a/arch/x86/kernel/kprobes/ftrace.c b/arch/x86/kernel/kprobes/ftrace.c
new file mode 100644
index 000000000000..23ef5c556f06
--- /dev/null
+++ b/arch/x86/kernel/kprobes/ftrace.c
@@ -0,0 +1,93 @@
+/*
+ * Dynamic Ftrace based Kprobes Optimization
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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) Hitachi Ltd., 2012
+ */
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <linux/preempt.h>
+#include <linux/ftrace.h>
+
+#include "common.h"
+
+static int __skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+ struct kprobe_ctlblk *kcb)
+{
+ /*
+ * Emulate singlestep (and also recover regs->ip)
+ * as if there is a 5byte nop
+ */
+ regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE;
+ if (unlikely(p->post_handler)) {
+ kcb->kprobe_status = KPROBE_HIT_SSDONE;
+ p->post_handler(p, regs, 0);
+ }
+ __this_cpu_write(current_kprobe, NULL);
+ return 1;
+}
+
+int __kprobes skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+ struct kprobe_ctlblk *kcb)
+{
+ if (kprobe_ftrace(p))
+ return __skip_singlestep(p, regs, kcb);
+ else
+ return 0;
+}
+
+/* Ftrace callback handler for kprobes */
+void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_ops *ops, struct pt_regs *regs)
+{
+ struct kprobe *p;
+ struct kprobe_ctlblk *kcb;
+ unsigned long flags;
+
+ /* Disable irq for emulating a breakpoint and avoiding preempt */
+ local_irq_save(flags);
+
+ p = get_kprobe((kprobe_opcode_t *)ip);
+ if (unlikely(!p) || kprobe_disabled(p))
+ goto end;
+
+ kcb = get_kprobe_ctlblk();
+ if (kprobe_running()) {
+ kprobes_inc_nmissed_count(p);
+ } else {
+ /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
+ regs->ip = ip + sizeof(kprobe_opcode_t);
+
+ __this_cpu_write(current_kprobe, p);
+ kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+ if (!p->pre_handler || !p->pre_handler(p, regs))
+ __skip_singlestep(p, regs, kcb);
+ /*
+ * If pre_handler returns !0, it sets regs->ip and
+ * resets current kprobe.
+ */
+ }
+end:
+ local_irq_restore(flags);
+}
+
+int __kprobes arch_prepare_kprobe_ftrace(struct kprobe *p)
+{
+ p->ainsn.insn = NULL;
+ p->ainsn.boostable = -1;
+ return 0;
+}
diff --git a/arch/x86/kernel/kprobes-opt.c b/arch/x86/kernel/kprobes/opt.c
index c5e410eed403..76dc6f095724 100644
--- a/arch/x86/kernel/kprobes-opt.c
+++ b/arch/x86/kernel/kprobes/opt.c
@@ -37,7 +37,7 @@
#include <asm/insn.h>
#include <asm/debugreg.h>
-#include "kprobes-common.h"
+#include "common.h"
unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr)
{
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 9c2bd8bd4b4c..b686a904d7c3 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -297,9 +297,9 @@ static void kvm_register_steal_time(void)
memset(st, 0, sizeof(*st));
- wrmsrl(MSR_KVM_STEAL_TIME, (__pa(st) | KVM_MSR_ENABLED));
- printk(KERN_INFO "kvm-stealtime: cpu %d, msr %lx\n",
- cpu, __pa(st));
+ wrmsrl(MSR_KVM_STEAL_TIME, (slow_virt_to_phys(st) | KVM_MSR_ENABLED));
+ pr_info("kvm-stealtime: cpu %d, msr %llx\n",
+ cpu, (unsigned long long) slow_virt_to_phys(st));
}
static DEFINE_PER_CPU(unsigned long, kvm_apic_eoi) = KVM_PV_EOI_DISABLED;
@@ -324,7 +324,7 @@ void __cpuinit kvm_guest_cpu_init(void)
return;
if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF) && kvmapf) {
- u64 pa = __pa(&__get_cpu_var(apf_reason));
+ u64 pa = slow_virt_to_phys(&__get_cpu_var(apf_reason));
#ifdef CONFIG_PREEMPT
pa |= KVM_ASYNC_PF_SEND_ALWAYS;
@@ -340,7 +340,8 @@ void __cpuinit kvm_guest_cpu_init(void)
/* Size alignment is implied but just to make it explicit. */
BUILD_BUG_ON(__alignof__(kvm_apic_eoi) < 4);
__get_cpu_var(kvm_apic_eoi) = 0;
- pa = __pa(&__get_cpu_var(kvm_apic_eoi)) | KVM_MSR_ENABLED;
+ pa = slow_virt_to_phys(&__get_cpu_var(kvm_apic_eoi))
+ | KVM_MSR_ENABLED;
wrmsrl(MSR_KVM_PV_EOI_EN, pa);
}
@@ -505,6 +506,7 @@ static bool __init kvm_detect(void)
const struct hypervisor_x86 x86_hyper_kvm __refconst = {
.name = "KVM",
.detect = kvm_detect,
+ .x2apic_available = kvm_para_available,
};
EXPORT_SYMBOL_GPL(x86_hyper_kvm);
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index 220a360010f8..0732f0089a3d 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -162,8 +162,8 @@ int kvm_register_clock(char *txt)
int low, high, ret;
struct pvclock_vcpu_time_info *src = &hv_clock[cpu].pvti;
- low = (int)__pa(src) | 1;
- high = ((u64)__pa(src) >> 32);
+ low = (int)slow_virt_to_phys(src) | 1;
+ high = ((u64)slow_virt_to_phys(src) >> 32);
ret = native_write_msr_safe(msr_kvm_system_time, low, high);
printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n",
cpu, high, low, txt);
@@ -218,6 +218,9 @@ static void kvm_shutdown(void)
void __init kvmclock_init(void)
{
unsigned long mem;
+ int size;
+
+ size = PAGE_ALIGN(sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS);
if (!kvm_para_available())
return;
@@ -231,16 +234,14 @@ void __init kvmclock_init(void)
printk(KERN_INFO "kvm-clock: Using msrs %x and %x",
msr_kvm_system_time, msr_kvm_wall_clock);
- mem = memblock_alloc(sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS,
- PAGE_SIZE);
+ mem = memblock_alloc(size, PAGE_SIZE);
if (!mem)
return;
hv_clock = __va(mem);
if (kvm_register_clock("boot clock")) {
hv_clock = NULL;
- memblock_free(mem,
- sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS);
+ memblock_free(mem, size);
return;
}
pv_time_ops.sched_clock = kvm_clock_read;
@@ -275,7 +276,7 @@ int __init kvm_setup_vsyscall_timeinfo(void)
struct pvclock_vcpu_time_info *vcpu_time;
unsigned int size;
- size = sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS;
+ size = PAGE_ALIGN(sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS);
preempt_disable();
cpu = smp_processor_id();
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index b3ea9db39db6..4eabc160696f 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -16,125 +16,12 @@
#include <linux/io.h>
#include <linux/suspend.h>
+#include <asm/init.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
#include <asm/debugreg.h>
-static int init_one_level2_page(struct kimage *image, pgd_t *pgd,
- unsigned long addr)
-{
- pud_t *pud;
- pmd_t *pmd;
- struct page *page;
- int result = -ENOMEM;
-
- addr &= PMD_MASK;
- pgd += pgd_index(addr);
- if (!pgd_present(*pgd)) {
- page = kimage_alloc_control_pages(image, 0);
- if (!page)
- goto out;
- pud = (pud_t *)page_address(page);
- clear_page(pud);
- set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
- }
- pud = pud_offset(pgd, addr);
- if (!pud_present(*pud)) {
- page = kimage_alloc_control_pages(image, 0);
- if (!page)
- goto out;
- pmd = (pmd_t *)page_address(page);
- clear_page(pmd);
- set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
- }
- pmd = pmd_offset(pud, addr);
- if (!pmd_present(*pmd))
- set_pmd(pmd, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC));
- result = 0;
-out:
- return result;
-}
-
-static void init_level2_page(pmd_t *level2p, unsigned long addr)
-{
- unsigned long end_addr;
-
- addr &= PAGE_MASK;
- end_addr = addr + PUD_SIZE;
- while (addr < end_addr) {
- set_pmd(level2p++, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC));
- addr += PMD_SIZE;
- }
-}
-
-static int init_level3_page(struct kimage *image, pud_t *level3p,
- unsigned long addr, unsigned long last_addr)
-{
- unsigned long end_addr;
- int result;
-
- result = 0;
- addr &= PAGE_MASK;
- end_addr = addr + PGDIR_SIZE;
- while ((addr < last_addr) && (addr < end_addr)) {
- struct page *page;
- pmd_t *level2p;
-
- page = kimage_alloc_control_pages(image, 0);
- if (!page) {
- result = -ENOMEM;
- goto out;
- }
- level2p = (pmd_t *)page_address(page);
- init_level2_page(level2p, addr);
- set_pud(level3p++, __pud(__pa(level2p) | _KERNPG_TABLE));
- addr += PUD_SIZE;
- }
- /* clear the unused entries */
- while (addr < end_addr) {
- pud_clear(level3p++);
- addr += PUD_SIZE;
- }
-out:
- return result;
-}
-
-
-static int init_level4_page(struct kimage *image, pgd_t *level4p,
- unsigned long addr, unsigned long last_addr)
-{
- unsigned long end_addr;
- int result;
-
- result = 0;
- addr &= PAGE_MASK;
- end_addr = addr + (PTRS_PER_PGD * PGDIR_SIZE);
- while ((addr < last_addr) && (addr < end_addr)) {
- struct page *page;
- pud_t *level3p;
-
- page = kimage_alloc_control_pages(image, 0);
- if (!page) {
- result = -ENOMEM;
- goto out;
- }
- level3p = (pud_t *)page_address(page);
- result = init_level3_page(image, level3p, addr, last_addr);
- if (result)
- goto out;
- set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE));
- addr += PGDIR_SIZE;
- }
- /* clear the unused entries */
- while (addr < end_addr) {
- pgd_clear(level4p++);
- addr += PGDIR_SIZE;
- }
-out:
- return result;
-}
-
static void free_transition_pgtable(struct kimage *image)
{
free_page((unsigned long)image->arch.pud);
@@ -184,22 +71,62 @@ err:
return result;
}
+static void *alloc_pgt_page(void *data)
+{
+ struct kimage *image = (struct kimage *)data;
+ struct page *page;
+ void *p = NULL;
+
+ page = kimage_alloc_control_pages(image, 0);
+ if (page) {
+ p = page_address(page);
+ clear_page(p);
+ }
+
+ return p;
+}
static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
{
+ struct x86_mapping_info info = {
+ .alloc_pgt_page = alloc_pgt_page,
+ .context = image,
+ .pmd_flag = __PAGE_KERNEL_LARGE_EXEC,
+ };
+ unsigned long mstart, mend;
pgd_t *level4p;
int result;
+ int i;
+
level4p = (pgd_t *)__va(start_pgtable);
- result = init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT);
- if (result)
- return result;
+ clear_page(level4p);
+ for (i = 0; i < nr_pfn_mapped; i++) {
+ mstart = pfn_mapped[i].start << PAGE_SHIFT;
+ mend = pfn_mapped[i].end << PAGE_SHIFT;
+
+ result = kernel_ident_mapping_init(&info,
+ level4p, mstart, mend);
+ if (result)
+ return result;
+ }
+
/*
- * image->start may be outside 0 ~ max_pfn, for example when
- * jump back to original kernel from kexeced kernel
+ * segments's mem ranges could be outside 0 ~ max_pfn,
+ * for example when jump back to original kernel from kexeced kernel.
+ * or first kernel is booted with user mem map, and second kernel
+ * could be loaded out of that range.
*/
- result = init_one_level2_page(image, level4p, image->start);
- if (result)
- return result;
+ for (i = 0; i < image->nr_segments; i++) {
+ mstart = image->segment[i].mem;
+ mend = mstart + image->segment[i].memsz;
+
+ result = kernel_ident_mapping_init(&info,
+ level4p, mstart, mend);
+
+ if (result)
+ return result;
+ }
+
return init_transition_pgtable(image, level4p);
}
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index 3a04b224d0c0..22db92bbdf1a 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -364,10 +364,7 @@ static struct attribute_group mc_attr_group = {
static void microcode_fini_cpu(int cpu)
{
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
microcode_ops->microcode_fini_cpu(cpu);
- uci->valid = 0;
}
static enum ucode_state microcode_resume_cpu(int cpu)
@@ -383,6 +380,10 @@ static enum ucode_state microcode_resume_cpu(int cpu)
static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw)
{
enum ucode_state ustate;
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ if (uci && uci->valid)
+ return UCODE_OK;
if (collect_cpu_info(cpu))
return UCODE_ERROR;
diff --git a/arch/x86/kernel/microcode_core_early.c b/arch/x86/kernel/microcode_core_early.c
new file mode 100644
index 000000000000..577db8417d15
--- /dev/null
+++ b/arch/x86/kernel/microcode_core_early.c
@@ -0,0 +1,76 @@
+/*
+ * X86 CPU microcode early update for Linux
+ *
+ * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com>
+ * H Peter Anvin" <hpa@zytor.com>
+ *
+ * This driver allows to early upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
+ *
+ * Reference: Section 9.11 of Volume 3, IA-32 Intel Architecture
+ * Software Developer's Manual.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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 <asm/microcode_intel.h>
+#include <asm/processor.h>
+
+#define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
+#define CPUID_INTEL1 QCHAR('G', 'e', 'n', 'u')
+#define CPUID_INTEL2 QCHAR('i', 'n', 'e', 'I')
+#define CPUID_INTEL3 QCHAR('n', 't', 'e', 'l')
+#define CPUID_AMD1 QCHAR('A', 'u', 't', 'h')
+#define CPUID_AMD2 QCHAR('e', 'n', 't', 'i')
+#define CPUID_AMD3 QCHAR('c', 'A', 'M', 'D')
+
+#define CPUID_IS(a, b, c, ebx, ecx, edx) \
+ (!((ebx ^ (a))|(edx ^ (b))|(ecx ^ (c))))
+
+/*
+ * In early loading microcode phase on BSP, boot_cpu_data is not set up yet.
+ * x86_vendor() gets vendor id for BSP.
+ *
+ * In 32 bit AP case, accessing boot_cpu_data needs linear address. To simplify
+ * coding, we still use x86_vendor() to get vendor id for AP.
+ *
+ * x86_vendor() gets vendor information directly through cpuid.
+ */
+static int __cpuinit x86_vendor(void)
+{
+ u32 eax = 0x00000000;
+ u32 ebx, ecx = 0, edx;
+
+ if (!have_cpuid_p())
+ return X86_VENDOR_UNKNOWN;
+
+ native_cpuid(&eax, &ebx, &ecx, &edx);
+
+ if (CPUID_IS(CPUID_INTEL1, CPUID_INTEL2, CPUID_INTEL3, ebx, ecx, edx))
+ return X86_VENDOR_INTEL;
+
+ if (CPUID_IS(CPUID_AMD1, CPUID_AMD2, CPUID_AMD3, ebx, ecx, edx))
+ return X86_VENDOR_AMD;
+
+ return X86_VENDOR_UNKNOWN;
+}
+
+void __init load_ucode_bsp(void)
+{
+ int vendor = x86_vendor();
+
+ if (vendor == X86_VENDOR_INTEL)
+ load_ucode_intel_bsp();
+}
+
+void __cpuinit load_ucode_ap(void)
+{
+ int vendor = x86_vendor();
+
+ if (vendor == X86_VENDOR_INTEL)
+ load_ucode_intel_ap();
+}
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
index 3544aed39338..5fb2cebf556b 100644
--- a/arch/x86/kernel/microcode_intel.c
+++ b/arch/x86/kernel/microcode_intel.c
@@ -79,7 +79,7 @@
#include <linux/module.h>
#include <linux/vmalloc.h>
-#include <asm/microcode.h>
+#include <asm/microcode_intel.h>
#include <asm/processor.h>
#include <asm/msr.h>
@@ -87,59 +87,6 @@ MODULE_DESCRIPTION("Microcode Update Driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
MODULE_LICENSE("GPL");
-struct microcode_header_intel {
- unsigned int hdrver;
- unsigned int rev;
- unsigned int date;
- unsigned int sig;
- unsigned int cksum;
- unsigned int ldrver;
- unsigned int pf;
- unsigned int datasize;
- unsigned int totalsize;
- unsigned int reserved[3];
-};
-
-struct microcode_intel {
- struct microcode_header_intel hdr;
- unsigned int bits[0];
-};
-
-/* microcode format is extended from prescott processors */
-struct extended_signature {
- unsigned int sig;
- unsigned int pf;
- unsigned int cksum;
-};
-
-struct extended_sigtable {
- unsigned int count;
- unsigned int cksum;
- unsigned int reserved[3];
- struct extended_signature sigs[0];
-};
-
-#define DEFAULT_UCODE_DATASIZE (2000)
-#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
-#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
-#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable))
-#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature))
-#define DWSIZE (sizeof(u32))
-
-#define get_totalsize(mc) \
- (((struct microcode_intel *)mc)->hdr.totalsize ? \
- ((struct microcode_intel *)mc)->hdr.totalsize : \
- DEFAULT_UCODE_TOTALSIZE)
-
-#define get_datasize(mc) \
- (((struct microcode_intel *)mc)->hdr.datasize ? \
- ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
-
-#define sigmatch(s1, s2, p1, p2) \
- (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
-
-#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
-
static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
{
struct cpuinfo_x86 *c = &cpu_data(cpu_num);
@@ -162,128 +109,25 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
return 0;
}
-static inline int update_match_cpu(struct cpu_signature *csig, int sig, int pf)
-{
- return (!sigmatch(sig, csig->sig, pf, csig->pf)) ? 0 : 1;
-}
-
-static inline int
-update_match_revision(struct microcode_header_intel *mc_header, int rev)
-{
- return (mc_header->rev <= rev) ? 0 : 1;
-}
-
-static int microcode_sanity_check(void *mc)
-{
- unsigned long total_size, data_size, ext_table_size;
- struct microcode_header_intel *mc_header = mc;
- struct extended_sigtable *ext_header = NULL;
- int sum, orig_sum, ext_sigcount = 0, i;
- struct extended_signature *ext_sig;
-
- total_size = get_totalsize(mc_header);
- data_size = get_datasize(mc_header);
-
- if (data_size + MC_HEADER_SIZE > total_size) {
- pr_err("error! Bad data size in microcode data file\n");
- return -EINVAL;
- }
-
- if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
- pr_err("error! Unknown microcode update format\n");
- return -EINVAL;
- }
- ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
- if (ext_table_size) {
- if ((ext_table_size < EXT_HEADER_SIZE)
- || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
- pr_err("error! Small exttable size in microcode data file\n");
- return -EINVAL;
- }
- ext_header = mc + MC_HEADER_SIZE + data_size;
- if (ext_table_size != exttable_size(ext_header)) {
- pr_err("error! Bad exttable size in microcode data file\n");
- return -EFAULT;
- }
- ext_sigcount = ext_header->count;
- }
-
- /* check extended table checksum */
- if (ext_table_size) {
- int ext_table_sum = 0;
- int *ext_tablep = (int *)ext_header;
-
- i = ext_table_size / DWSIZE;
- while (i--)
- ext_table_sum += ext_tablep[i];
- if (ext_table_sum) {
- pr_warning("aborting, bad extended signature table checksum\n");
- return -EINVAL;
- }
- }
-
- /* calculate the checksum */
- orig_sum = 0;
- i = (MC_HEADER_SIZE + data_size) / DWSIZE;
- while (i--)
- orig_sum += ((int *)mc)[i];
- if (orig_sum) {
- pr_err("aborting, bad checksum\n");
- return -EINVAL;
- }
- if (!ext_table_size)
- return 0;
- /* check extended signature checksum */
- for (i = 0; i < ext_sigcount; i++) {
- ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
- EXT_SIGNATURE_SIZE * i;
- sum = orig_sum
- - (mc_header->sig + mc_header->pf + mc_header->cksum)
- + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
- if (sum) {
- pr_err("aborting, bad checksum\n");
- return -EINVAL;
- }
- }
- return 0;
-}
-
/*
* return 0 - no update found
* return 1 - found update
*/
-static int
-get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
+static int get_matching_mc(struct microcode_intel *mc_intel, int cpu)
{
- struct microcode_header_intel *mc_header = mc;
- struct extended_sigtable *ext_header;
- unsigned long total_size = get_totalsize(mc_header);
- int ext_sigcount, i;
- struct extended_signature *ext_sig;
-
- if (!update_match_revision(mc_header, rev))
- return 0;
-
- if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf))
- return 1;
+ struct cpu_signature cpu_sig;
+ unsigned int csig, cpf, crev;
- /* Look for ext. headers: */
- if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
- return 0;
+ collect_cpu_info(cpu, &cpu_sig);
- ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
- ext_sigcount = ext_header->count;
- ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+ csig = cpu_sig.sig;
+ cpf = cpu_sig.pf;
+ crev = cpu_sig.rev;
- for (i = 0; i < ext_sigcount; i++) {
- if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf))
- return 1;
- ext_sig++;
- }
- return 0;
+ return get_matching_microcode(csig, cpf, mc_intel, crev);
}
-static int apply_microcode(int cpu)
+int apply_microcode(int cpu)
{
struct microcode_intel *mc_intel;
struct ucode_cpu_info *uci;
@@ -300,6 +144,14 @@ static int apply_microcode(int cpu)
if (mc_intel == NULL)
return 0;
+ /*
+ * Microcode on this CPU could be updated earlier. Only apply the
+ * microcode patch in mc_intel when it is newer than the one on this
+ * CPU.
+ */
+ if (get_matching_mc(mc_intel, cpu) == 0)
+ return 0;
+
/* write microcode via MSR 0x79 */
wrmsr(MSR_IA32_UCODE_WRITE,
(unsigned long) mc_intel->bits,
@@ -338,6 +190,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
unsigned int leftover = size;
enum ucode_state state = UCODE_OK;
unsigned int curr_mc_size = 0;
+ unsigned int csig, cpf;
while (leftover) {
struct microcode_header_intel mc_header;
@@ -362,11 +215,13 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
}
if (get_ucode_data(mc, ucode_ptr, mc_size) ||
- microcode_sanity_check(mc) < 0) {
+ microcode_sanity_check(mc, 1) < 0) {
break;
}
- if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
+ csig = uci->cpu_sig.sig;
+ cpf = uci->cpu_sig.pf;
+ if (get_matching_microcode(csig, cpf, mc, new_rev)) {
vfree(new_mc);
new_rev = mc_header.rev;
new_mc = mc;
@@ -393,6 +248,13 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
vfree(uci->mc);
uci->mc = (struct microcode_intel *)new_mc;
+ /*
+ * If early loading microcode is supported, save this mc into
+ * permanent memory. So it will be loaded early when a CPU is hot added
+ * or resumes.
+ */
+ save_mc_for_early(new_mc);
+
pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
cpu, new_rev, uci->cpu_sig.rev);
out:
diff --git a/arch/x86/kernel/microcode_intel_early.c b/arch/x86/kernel/microcode_intel_early.c
new file mode 100644
index 000000000000..7890bc838952
--- /dev/null
+++ b/arch/x86/kernel/microcode_intel_early.c
@@ -0,0 +1,796 @@
+/*
+ * Intel CPU microcode early update for Linux
+ *
+ * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com>
+ * H Peter Anvin" <hpa@zytor.com>
+ *
+ * This allows to early upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
+ *
+ * Reference: Section 9.11 of Volume 3, IA-32 Intel Architecture
+ * Software Developer's Manual.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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/mm.h>
+#include <linux/slab.h>
+#include <linux/earlycpio.h>
+#include <linux/initrd.h>
+#include <linux/cpu.h>
+#include <asm/msr.h>
+#include <asm/microcode_intel.h>
+#include <asm/processor.h>
+#include <asm/tlbflush.h>
+#include <asm/setup.h>
+
+unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT];
+struct mc_saved_data {
+ unsigned int mc_saved_count;
+ struct microcode_intel **mc_saved;
+} mc_saved_data;
+
+static enum ucode_state __cpuinit
+generic_load_microcode_early(struct microcode_intel **mc_saved_p,
+ unsigned int mc_saved_count,
+ struct ucode_cpu_info *uci)
+{
+ struct microcode_intel *ucode_ptr, *new_mc = NULL;
+ int new_rev = uci->cpu_sig.rev;
+ enum ucode_state state = UCODE_OK;
+ unsigned int mc_size;
+ struct microcode_header_intel *mc_header;
+ unsigned int csig = uci->cpu_sig.sig;
+ unsigned int cpf = uci->cpu_sig.pf;
+ int i;
+
+ for (i = 0; i < mc_saved_count; i++) {
+ ucode_ptr = mc_saved_p[i];
+
+ mc_header = (struct microcode_header_intel *)ucode_ptr;
+ mc_size = get_totalsize(mc_header);
+ if (get_matching_microcode(csig, cpf, ucode_ptr, new_rev)) {
+ new_rev = mc_header->rev;
+ new_mc = ucode_ptr;
+ }
+ }
+
+ if (!new_mc) {
+ state = UCODE_NFOUND;
+ goto out;
+ }
+
+ uci->mc = (struct microcode_intel *)new_mc;
+out:
+ return state;
+}
+
+static void __cpuinit
+microcode_pointer(struct microcode_intel **mc_saved,
+ unsigned long *mc_saved_in_initrd,
+ unsigned long initrd_start, int mc_saved_count)
+{
+ int i;
+
+ for (i = 0; i < mc_saved_count; i++)
+ mc_saved[i] = (struct microcode_intel *)
+ (mc_saved_in_initrd[i] + initrd_start);
+}
+
+#ifdef CONFIG_X86_32
+static void __cpuinit
+microcode_phys(struct microcode_intel **mc_saved_tmp,
+ struct mc_saved_data *mc_saved_data)
+{
+ int i;
+ struct microcode_intel ***mc_saved;
+
+ mc_saved = (struct microcode_intel ***)
+ __pa_symbol(&mc_saved_data->mc_saved);
+ for (i = 0; i < mc_saved_data->mc_saved_count; i++) {
+ struct microcode_intel *p;
+
+ p = *(struct microcode_intel **)
+ __pa(mc_saved_data->mc_saved + i);
+ mc_saved_tmp[i] = (struct microcode_intel *)__pa(p);
+ }
+}
+#endif
+
+static enum ucode_state __cpuinit
+load_microcode(struct mc_saved_data *mc_saved_data,
+ unsigned long *mc_saved_in_initrd,
+ unsigned long initrd_start,
+ struct ucode_cpu_info *uci)
+{
+ struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT];
+ unsigned int count = mc_saved_data->mc_saved_count;
+
+ if (!mc_saved_data->mc_saved) {
+ microcode_pointer(mc_saved_tmp, mc_saved_in_initrd,
+ initrd_start, count);
+
+ return generic_load_microcode_early(mc_saved_tmp, count, uci);
+ } else {
+#ifdef CONFIG_X86_32
+ microcode_phys(mc_saved_tmp, mc_saved_data);
+ return generic_load_microcode_early(mc_saved_tmp, count, uci);
+#else
+ return generic_load_microcode_early(mc_saved_data->mc_saved,
+ count, uci);
+#endif
+ }
+}
+
+static u8 get_x86_family(unsigned long sig)
+{
+ u8 x86;
+
+ x86 = (sig >> 8) & 0xf;
+
+ if (x86 == 0xf)
+ x86 += (sig >> 20) & 0xff;
+
+ return x86;
+}
+
+static u8 get_x86_model(unsigned long sig)
+{
+ u8 x86, x86_model;
+
+ x86 = get_x86_family(sig);
+ x86_model = (sig >> 4) & 0xf;
+
+ if (x86 == 0x6 || x86 == 0xf)
+ x86_model += ((sig >> 16) & 0xf) << 4;
+
+ return x86_model;
+}
+
+/*
+ * Given CPU signature and a microcode patch, this function finds if the
+ * microcode patch has matching family and model with the CPU.
+ */
+static enum ucode_state
+matching_model_microcode(struct microcode_header_intel *mc_header,
+ unsigned long sig)
+{
+ u8 x86, x86_model;
+ u8 x86_ucode, x86_model_ucode;
+ struct extended_sigtable *ext_header;
+ unsigned long total_size = get_totalsize(mc_header);
+ unsigned long data_size = get_datasize(mc_header);
+ int ext_sigcount, i;
+ struct extended_signature *ext_sig;
+
+ x86 = get_x86_family(sig);
+ x86_model = get_x86_model(sig);
+
+ x86_ucode = get_x86_family(mc_header->sig);
+ x86_model_ucode = get_x86_model(mc_header->sig);
+
+ if (x86 == x86_ucode && x86_model == x86_model_ucode)
+ return UCODE_OK;
+
+ /* Look for ext. headers: */
+ if (total_size <= data_size + MC_HEADER_SIZE)
+ return UCODE_NFOUND;
+
+ ext_header = (struct extended_sigtable *)
+ mc_header + data_size + MC_HEADER_SIZE;
+ ext_sigcount = ext_header->count;
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+
+ for (i = 0; i < ext_sigcount; i++) {
+ x86_ucode = get_x86_family(ext_sig->sig);
+ x86_model_ucode = get_x86_model(ext_sig->sig);
+
+ if (x86 == x86_ucode && x86_model == x86_model_ucode)
+ return UCODE_OK;
+
+ ext_sig++;
+ }
+
+ return UCODE_NFOUND;
+}
+
+static int
+save_microcode(struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_src,
+ unsigned int mc_saved_count)
+{
+ int i, j;
+ struct microcode_intel **mc_saved_p;
+ int ret;
+
+ if (!mc_saved_count)
+ return -EINVAL;
+
+ /*
+ * Copy new microcode data.
+ */
+ mc_saved_p = kmalloc(mc_saved_count*sizeof(struct microcode_intel *),
+ GFP_KERNEL);
+ if (!mc_saved_p)
+ return -ENOMEM;
+
+ for (i = 0; i < mc_saved_count; i++) {
+ struct microcode_intel *mc = mc_saved_src[i];
+ struct microcode_header_intel *mc_header = &mc->hdr;
+ unsigned long mc_size = get_totalsize(mc_header);
+ mc_saved_p[i] = kmalloc(mc_size, GFP_KERNEL);
+ if (!mc_saved_p[i]) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ if (!mc_saved_src[i]) {
+ ret = -EINVAL;
+ goto err;
+ }
+ memcpy(mc_saved_p[i], mc, mc_size);
+ }
+
+ /*
+ * Point to newly saved microcode.
+ */
+ mc_saved_data->mc_saved = mc_saved_p;
+ mc_saved_data->mc_saved_count = mc_saved_count;
+
+ return 0;
+
+err:
+ for (j = 0; j <= i; j++)
+ kfree(mc_saved_p[j]);
+ kfree(mc_saved_p);
+
+ return ret;
+}
+
+/*
+ * A microcode patch in ucode_ptr is saved into mc_saved
+ * - if it has matching signature and newer revision compared to an existing
+ * patch mc_saved.
+ * - or if it is a newly discovered microcode patch.
+ *
+ * The microcode patch should have matching model with CPU.
+ */
+static void _save_mc(struct microcode_intel **mc_saved, u8 *ucode_ptr,
+ unsigned int *mc_saved_count_p)
+{
+ int i;
+ int found = 0;
+ unsigned int mc_saved_count = *mc_saved_count_p;
+ struct microcode_header_intel *mc_header;
+
+ mc_header = (struct microcode_header_intel *)ucode_ptr;
+ for (i = 0; i < mc_saved_count; i++) {
+ unsigned int sig, pf;
+ unsigned int new_rev;
+ struct microcode_header_intel *mc_saved_header =
+ (struct microcode_header_intel *)mc_saved[i];
+ sig = mc_saved_header->sig;
+ pf = mc_saved_header->pf;
+ new_rev = mc_header->rev;
+
+ if (get_matching_sig(sig, pf, ucode_ptr, new_rev)) {
+ found = 1;
+ if (update_match_revision(mc_header, new_rev)) {
+ /*
+ * Found an older ucode saved before.
+ * Replace the older one with this newer
+ * one.
+ */
+ mc_saved[i] =
+ (struct microcode_intel *)ucode_ptr;
+ break;
+ }
+ }
+ }
+ if (i >= mc_saved_count && !found)
+ /*
+ * This ucode is first time discovered in ucode file.
+ * Save it to memory.
+ */
+ mc_saved[mc_saved_count++] =
+ (struct microcode_intel *)ucode_ptr;
+
+ *mc_saved_count_p = mc_saved_count;
+}
+
+/*
+ * Get microcode matching with BSP's model. Only CPUs with the same model as
+ * BSP can stay in the platform.
+ */
+static enum ucode_state __init
+get_matching_model_microcode(int cpu, unsigned long start,
+ void *data, size_t size,
+ struct mc_saved_data *mc_saved_data,
+ unsigned long *mc_saved_in_initrd,
+ struct ucode_cpu_info *uci)
+{
+ u8 *ucode_ptr = data;
+ unsigned int leftover = size;
+ enum ucode_state state = UCODE_OK;
+ unsigned int mc_size;
+ struct microcode_header_intel *mc_header;
+ struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT];
+ unsigned int mc_saved_count = mc_saved_data->mc_saved_count;
+ int i;
+
+ while (leftover) {
+ mc_header = (struct microcode_header_intel *)ucode_ptr;
+
+ mc_size = get_totalsize(mc_header);
+ if (!mc_size || mc_size > leftover ||
+ microcode_sanity_check(ucode_ptr, 0) < 0)
+ break;
+
+ leftover -= mc_size;
+
+ /*
+ * Since APs with same family and model as the BSP may boot in
+ * the platform, we need to find and save microcode patches
+ * with the same family and model as the BSP.
+ */
+ if (matching_model_microcode(mc_header, uci->cpu_sig.sig) !=
+ UCODE_OK) {
+ ucode_ptr += mc_size;
+ continue;
+ }
+
+ _save_mc(mc_saved_tmp, ucode_ptr, &mc_saved_count);
+
+ ucode_ptr += mc_size;
+ }
+
+ if (leftover) {
+ state = UCODE_ERROR;
+ goto out;
+ }
+
+ if (mc_saved_count == 0) {
+ state = UCODE_NFOUND;
+ goto out;
+ }
+
+ for (i = 0; i < mc_saved_count; i++)
+ mc_saved_in_initrd[i] = (unsigned long)mc_saved_tmp[i] - start;
+
+ mc_saved_data->mc_saved_count = mc_saved_count;
+out:
+ return state;
+}
+
+#define native_rdmsr(msr, val1, val2) \
+do { \
+ u64 __val = native_read_msr((msr)); \
+ (void)((val1) = (u32)__val); \
+ (void)((val2) = (u32)(__val >> 32)); \
+} while (0)
+
+#define native_wrmsr(msr, low, high) \
+ native_write_msr(msr, low, high);
+
+static int __cpuinit collect_cpu_info_early(struct ucode_cpu_info *uci)
+{
+ unsigned int val[2];
+ u8 x86, x86_model;
+ struct cpu_signature csig;
+ unsigned int eax, ebx, ecx, edx;
+
+ csig.sig = 0;
+ csig.pf = 0;
+ csig.rev = 0;
+
+ memset(uci, 0, sizeof(*uci));
+
+ eax = 0x00000001;
+ ecx = 0;
+ native_cpuid(&eax, &ebx, &ecx, &edx);
+ csig.sig = eax;
+
+ x86 = get_x86_family(csig.sig);
+ x86_model = get_x86_model(csig.sig);
+
+ if ((x86_model >= 5) || (x86 > 6)) {
+ /* get processor flags from MSR 0x17 */
+ native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+ csig.pf = 1 << ((val[1] >> 18) & 7);
+ }
+ native_wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+
+ /* As documented in the SDM: Do a CPUID 1 here */
+ sync_core();
+
+ /* get the current revision from MSR 0x8B */
+ native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+ csig.rev = val[1];
+
+ uci->cpu_sig = csig;
+ uci->valid = 1;
+
+ return 0;
+}
+
+#ifdef DEBUG
+static void __ref show_saved_mc(void)
+{
+ int i, j;
+ unsigned int sig, pf, rev, total_size, data_size, date;
+ struct ucode_cpu_info uci;
+
+ if (mc_saved_data.mc_saved_count == 0) {
+ pr_debug("no micorcode data saved.\n");
+ return;
+ }
+ pr_debug("Total microcode saved: %d\n", mc_saved_data.mc_saved_count);
+
+ collect_cpu_info_early(&uci);
+
+ sig = uci.cpu_sig.sig;
+ pf = uci.cpu_sig.pf;
+ rev = uci.cpu_sig.rev;
+ pr_debug("CPU%d: sig=0x%x, pf=0x%x, rev=0x%x\n",
+ smp_processor_id(), sig, pf, rev);
+
+ for (i = 0; i < mc_saved_data.mc_saved_count; i++) {
+ struct microcode_header_intel *mc_saved_header;
+ struct extended_sigtable *ext_header;
+ int ext_sigcount;
+ struct extended_signature *ext_sig;
+
+ mc_saved_header = (struct microcode_header_intel *)
+ mc_saved_data.mc_saved[i];
+ sig = mc_saved_header->sig;
+ pf = mc_saved_header->pf;
+ rev = mc_saved_header->rev;
+ total_size = get_totalsize(mc_saved_header);
+ data_size = get_datasize(mc_saved_header);
+ date = mc_saved_header->date;
+
+ pr_debug("mc_saved[%d]: sig=0x%x, pf=0x%x, rev=0x%x, toal size=0x%x, date = %04x-%02x-%02x\n",
+ i, sig, pf, rev, total_size,
+ date & 0xffff,
+ date >> 24,
+ (date >> 16) & 0xff);
+
+ /* Look for ext. headers: */
+ if (total_size <= data_size + MC_HEADER_SIZE)
+ continue;
+
+ ext_header = (struct extended_sigtable *)
+ mc_saved_header + data_size + MC_HEADER_SIZE;
+ ext_sigcount = ext_header->count;
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+
+ for (j = 0; j < ext_sigcount; j++) {
+ sig = ext_sig->sig;
+ pf = ext_sig->pf;
+
+ pr_debug("\tExtended[%d]: sig=0x%x, pf=0x%x\n",
+ j, sig, pf);
+
+ ext_sig++;
+ }
+
+ }
+}
+#else
+static inline void show_saved_mc(void)
+{
+}
+#endif
+
+#if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU)
+/*
+ * Save this mc into mc_saved_data. So it will be loaded early when a CPU is
+ * hot added or resumes.
+ *
+ * Please make sure this mc should be a valid microcode patch before calling
+ * this function.
+ */
+int save_mc_for_early(u8 *mc)
+{
+ struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT];
+ unsigned int mc_saved_count_init;
+ unsigned int mc_saved_count;
+ struct microcode_intel **mc_saved;
+ int ret = 0;
+ int i;
+
+ /*
+ * Hold hotplug lock so mc_saved_data is not accessed by a CPU in
+ * hotplug.
+ */
+ cpu_hotplug_driver_lock();
+
+ mc_saved_count_init = mc_saved_data.mc_saved_count;
+ mc_saved_count = mc_saved_data.mc_saved_count;
+ mc_saved = mc_saved_data.mc_saved;
+
+ if (mc_saved && mc_saved_count)
+ memcpy(mc_saved_tmp, mc_saved,
+ mc_saved_count * sizeof(struct mirocode_intel *));
+ /*
+ * Save the microcode patch mc in mc_save_tmp structure if it's a newer
+ * version.
+ */
+
+ _save_mc(mc_saved_tmp, mc, &mc_saved_count);
+
+ /*
+ * Save the mc_save_tmp in global mc_saved_data.
+ */
+ ret = save_microcode(&mc_saved_data, mc_saved_tmp, mc_saved_count);
+ if (ret) {
+ pr_err("Can not save microcode patch.\n");
+ goto out;
+ }
+
+ show_saved_mc();
+
+ /*
+ * Free old saved microcod data.
+ */
+ if (mc_saved) {
+ for (i = 0; i < mc_saved_count_init; i++)
+ kfree(mc_saved[i]);
+ kfree(mc_saved);
+ }
+
+out:
+ cpu_hotplug_driver_unlock();
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(save_mc_for_early);
+#endif
+
+static __initdata char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin";
+static __init enum ucode_state
+scan_microcode(unsigned long start, unsigned long end,
+ struct mc_saved_data *mc_saved_data,
+ unsigned long *mc_saved_in_initrd,
+ struct ucode_cpu_info *uci)
+{
+ unsigned int size = end - start + 1;
+ struct cpio_data cd;
+ long offset = 0;
+#ifdef CONFIG_X86_32
+ char *p = (char *)__pa_symbol(ucode_name);
+#else
+ char *p = ucode_name;
+#endif
+
+ cd.data = NULL;
+ cd.size = 0;
+
+ cd = find_cpio_data(p, (void *)start, size, &offset);
+ if (!cd.data)
+ return UCODE_ERROR;
+
+
+ return get_matching_model_microcode(0, start, cd.data, cd.size,
+ mc_saved_data, mc_saved_in_initrd,
+ uci);
+}
+
+/*
+ * Print ucode update info.
+ */
+static void __cpuinit
+print_ucode_info(struct ucode_cpu_info *uci, unsigned int date)
+{
+ int cpu = smp_processor_id();
+
+ pr_info("CPU%d microcode updated early to revision 0x%x, date = %04x-%02x-%02x\n",
+ cpu,
+ uci->cpu_sig.rev,
+ date & 0xffff,
+ date >> 24,
+ (date >> 16) & 0xff);
+}
+
+#ifdef CONFIG_X86_32
+
+static int delay_ucode_info;
+static int current_mc_date;
+
+/*
+ * Print early updated ucode info after printk works. This is delayed info dump.
+ */
+void __cpuinit show_ucode_info_early(void)
+{
+ struct ucode_cpu_info uci;
+
+ if (delay_ucode_info) {
+ collect_cpu_info_early(&uci);
+ print_ucode_info(&uci, current_mc_date);
+ delay_ucode_info = 0;
+ }
+}
+
+/*
+ * At this point, we can not call printk() yet. Keep microcode patch number in
+ * mc_saved_data.mc_saved and delay printing microcode info in
+ * show_ucode_info_early() until printk() works.
+ */
+static void __cpuinit print_ucode(struct ucode_cpu_info *uci)
+{
+ struct microcode_intel *mc_intel;
+ int *delay_ucode_info_p;
+ int *current_mc_date_p;
+
+ mc_intel = uci->mc;
+ if (mc_intel == NULL)
+ return;
+
+ delay_ucode_info_p = (int *)__pa_symbol(&delay_ucode_info);
+ current_mc_date_p = (int *)__pa_symbol(&current_mc_date);
+
+ *delay_ucode_info_p = 1;
+ *current_mc_date_p = mc_intel->hdr.date;
+}
+#else
+
+/*
+ * Flush global tlb. We only do this in x86_64 where paging has been enabled
+ * already and PGE should be enabled as well.
+ */
+static inline void __cpuinit flush_tlb_early(void)
+{
+ __native_flush_tlb_global_irq_disabled();
+}
+
+static inline void __cpuinit print_ucode(struct ucode_cpu_info *uci)
+{
+ struct microcode_intel *mc_intel;
+
+ mc_intel = uci->mc;
+ if (mc_intel == NULL)
+ return;
+
+ print_ucode_info(uci, mc_intel->hdr.date);
+}
+#endif
+
+static int apply_microcode_early(struct mc_saved_data *mc_saved_data,
+ struct ucode_cpu_info *uci)
+{
+ struct microcode_intel *mc_intel;
+ unsigned int val[2];
+
+ mc_intel = uci->mc;
+ if (mc_intel == NULL)
+ return 0;
+
+ /* write microcode via MSR 0x79 */
+ native_wrmsr(MSR_IA32_UCODE_WRITE,
+ (unsigned long) mc_intel->bits,
+ (unsigned long) mc_intel->bits >> 16 >> 16);
+ native_wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+
+ /* As documented in the SDM: Do a CPUID 1 here */
+ sync_core();
+
+ /* get the current revision from MSR 0x8B */
+ native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+ if (val[1] != mc_intel->hdr.rev)
+ return -1;
+
+#ifdef CONFIG_X86_64
+ /* Flush global tlb. This is precaution. */
+ flush_tlb_early();
+#endif
+ uci->cpu_sig.rev = val[1];
+
+ print_ucode(uci);
+
+ return 0;
+}
+
+/*
+ * This function converts microcode patch offsets previously stored in
+ * mc_saved_in_initrd to pointers and stores the pointers in mc_saved_data.
+ */
+int __init save_microcode_in_initrd(void)
+{
+ unsigned int count = mc_saved_data.mc_saved_count;
+ struct microcode_intel *mc_saved[MAX_UCODE_COUNT];
+ int ret = 0;
+
+ if (count == 0)
+ return ret;
+
+ microcode_pointer(mc_saved, mc_saved_in_initrd, initrd_start, count);
+ ret = save_microcode(&mc_saved_data, mc_saved, count);
+ if (ret)
+ pr_err("Can not save microcod patches from initrd");
+
+ show_saved_mc();
+
+ return ret;
+}
+
+static void __init
+_load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data,
+ unsigned long *mc_saved_in_initrd,
+ unsigned long initrd_start_early,
+ unsigned long initrd_end_early,
+ struct ucode_cpu_info *uci)
+{
+ collect_cpu_info_early(uci);
+ scan_microcode(initrd_start_early, initrd_end_early, mc_saved_data,
+ mc_saved_in_initrd, uci);
+ load_microcode(mc_saved_data, mc_saved_in_initrd,
+ initrd_start_early, uci);
+ apply_microcode_early(mc_saved_data, uci);
+}
+
+void __init
+load_ucode_intel_bsp(void)
+{
+ u64 ramdisk_image, ramdisk_size;
+ unsigned long initrd_start_early, initrd_end_early;
+ struct ucode_cpu_info uci;
+#ifdef CONFIG_X86_32
+ struct boot_params *boot_params_p;
+
+ boot_params_p = (struct boot_params *)__pa_symbol(&boot_params);
+ ramdisk_image = boot_params_p->hdr.ramdisk_image;
+ ramdisk_size = boot_params_p->hdr.ramdisk_size;
+ initrd_start_early = ramdisk_image;
+ initrd_end_early = initrd_start_early + ramdisk_size;
+
+ _load_ucode_intel_bsp(
+ (struct mc_saved_data *)__pa_symbol(&mc_saved_data),
+ (unsigned long *)__pa_symbol(&mc_saved_in_initrd),
+ initrd_start_early, initrd_end_early, &uci);
+#else
+ ramdisk_image = boot_params.hdr.ramdisk_image;
+ ramdisk_size = boot_params.hdr.ramdisk_size;
+ initrd_start_early = ramdisk_image + PAGE_OFFSET;
+ initrd_end_early = initrd_start_early + ramdisk_size;
+
+ _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd,
+ initrd_start_early, initrd_end_early, &uci);
+#endif
+}
+
+void __cpuinit load_ucode_intel_ap(void)
+{
+ struct mc_saved_data *mc_saved_data_p;
+ struct ucode_cpu_info uci;
+ unsigned long *mc_saved_in_initrd_p;
+ unsigned long initrd_start_addr;
+#ifdef CONFIG_X86_32
+ unsigned long *initrd_start_p;
+
+ mc_saved_in_initrd_p =
+ (unsigned long *)__pa_symbol(mc_saved_in_initrd);
+ mc_saved_data_p = (struct mc_saved_data *)__pa_symbol(&mc_saved_data);
+ initrd_start_p = (unsigned long *)__pa_symbol(&initrd_start);
+ initrd_start_addr = (unsigned long)__pa_symbol(*initrd_start_p);
+#else
+ mc_saved_data_p = &mc_saved_data;
+ mc_saved_in_initrd_p = mc_saved_in_initrd;
+ initrd_start_addr = initrd_start;
+#endif
+
+ /*
+ * If there is no valid ucode previously saved in memory, no need to
+ * update ucode on this AP.
+ */
+ if (mc_saved_data_p->mc_saved_count == 0)
+ return;
+
+ collect_cpu_info_early(&uci);
+ load_microcode(mc_saved_data_p, mc_saved_in_initrd_p,
+ initrd_start_addr, &uci);
+ apply_microcode_early(mc_saved_data_p, &uci);
+}
diff --git a/arch/x86/kernel/microcode_intel_lib.c b/arch/x86/kernel/microcode_intel_lib.c
new file mode 100644
index 000000000000..ce69320d0179
--- /dev/null
+++ b/arch/x86/kernel/microcode_intel_lib.c
@@ -0,0 +1,174 @@
+/*
+ * Intel CPU Microcode Update Driver for Linux
+ *
+ * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com>
+ * H Peter Anvin" <hpa@zytor.com>
+ *
+ * This driver allows to upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
+ *
+ * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ * Software Developer's Manual
+ * Order Number 253668 or free download from:
+ *
+ * http://developer.intel.com/Assets/PDF/manual/253668.pdf
+ *
+ * For more information, go to http://www.urbanmyth.org/microcode
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/firmware.h>
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/microcode_intel.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+
+static inline int
+update_match_cpu(unsigned int csig, unsigned int cpf,
+ unsigned int sig, unsigned int pf)
+{
+ return (!sigmatch(sig, csig, pf, cpf)) ? 0 : 1;
+}
+
+int
+update_match_revision(struct microcode_header_intel *mc_header, int rev)
+{
+ return (mc_header->rev <= rev) ? 0 : 1;
+}
+
+int microcode_sanity_check(void *mc, int print_err)
+{
+ unsigned long total_size, data_size, ext_table_size;
+ struct microcode_header_intel *mc_header = mc;
+ struct extended_sigtable *ext_header = NULL;
+ int sum, orig_sum, ext_sigcount = 0, i;
+ struct extended_signature *ext_sig;
+
+ total_size = get_totalsize(mc_header);
+ data_size = get_datasize(mc_header);
+
+ if (data_size + MC_HEADER_SIZE > total_size) {
+ if (print_err)
+ pr_err("error! Bad data size in microcode data file\n");
+ return -EINVAL;
+ }
+
+ if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
+ if (print_err)
+ pr_err("error! Unknown microcode update format\n");
+ return -EINVAL;
+ }
+ ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+ if (ext_table_size) {
+ if ((ext_table_size < EXT_HEADER_SIZE)
+ || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+ if (print_err)
+ pr_err("error! Small exttable size in microcode data file\n");
+ return -EINVAL;
+ }
+ ext_header = mc + MC_HEADER_SIZE + data_size;
+ if (ext_table_size != exttable_size(ext_header)) {
+ if (print_err)
+ pr_err("error! Bad exttable size in microcode data file\n");
+ return -EFAULT;
+ }
+ ext_sigcount = ext_header->count;
+ }
+
+ /* check extended table checksum */
+ if (ext_table_size) {
+ int ext_table_sum = 0;
+ int *ext_tablep = (int *)ext_header;
+
+ i = ext_table_size / DWSIZE;
+ while (i--)
+ ext_table_sum += ext_tablep[i];
+ if (ext_table_sum) {
+ if (print_err)
+ pr_warn("aborting, bad extended signature table checksum\n");
+ return -EINVAL;
+ }
+ }
+
+ /* calculate the checksum */
+ orig_sum = 0;
+ i = (MC_HEADER_SIZE + data_size) / DWSIZE;
+ while (i--)
+ orig_sum += ((int *)mc)[i];
+ if (orig_sum) {
+ if (print_err)
+ pr_err("aborting, bad checksum\n");
+ return -EINVAL;
+ }
+ if (!ext_table_size)
+ return 0;
+ /* check extended signature checksum */
+ for (i = 0; i < ext_sigcount; i++) {
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
+ EXT_SIGNATURE_SIZE * i;
+ sum = orig_sum
+ - (mc_header->sig + mc_header->pf + mc_header->cksum)
+ + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
+ if (sum) {
+ if (print_err)
+ pr_err("aborting, bad checksum\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(microcode_sanity_check);
+
+/*
+ * return 0 - no update found
+ * return 1 - found update
+ */
+int get_matching_sig(unsigned int csig, int cpf, void *mc, int rev)
+{
+ struct microcode_header_intel *mc_header = mc;
+ struct extended_sigtable *ext_header;
+ unsigned long total_size = get_totalsize(mc_header);
+ int ext_sigcount, i;
+ struct extended_signature *ext_sig;
+
+ if (update_match_cpu(csig, cpf, mc_header->sig, mc_header->pf))
+ return 1;
+
+ /* Look for ext. headers: */
+ if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
+ return 0;
+
+ ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
+ ext_sigcount = ext_header->count;
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+
+ for (i = 0; i < ext_sigcount; i++) {
+ if (update_match_cpu(csig, cpf, ext_sig->sig, ext_sig->pf))
+ return 1;
+ ext_sig++;
+ }
+ return 0;
+}
+
+/*
+ * return 0 - no update found
+ * return 1 - found update
+ */
+int get_matching_microcode(unsigned int csig, int cpf, void *mc, int rev)
+{
+ struct microcode_header_intel *mc_header = mc;
+
+ if (!update_match_revision(mc_header, rev))
+ return 0;
+
+ return get_matching_sig(csig, cpf, mc, rev);
+}
+EXPORT_SYMBOL_GPL(get_matching_microcode);
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 2ed787f15bf0..14ae10031ff0 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -268,13 +268,7 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE;
EXPORT_SYMBOL(boot_option_idle_override);
-/*
- * Powermanagement idle function, if any..
- */
-void (*pm_idle)(void);
-#ifdef CONFIG_APM_MODULE
-EXPORT_SYMBOL(pm_idle);
-#endif
+static void (*x86_idle)(void);
#ifndef CONFIG_SMP
static inline void play_dead(void)
@@ -351,7 +345,7 @@ void cpu_idle(void)
rcu_idle_enter();
if (cpuidle_idle_call())
- pm_idle();
+ x86_idle();
rcu_idle_exit();
start_critical_timings();
@@ -375,7 +369,6 @@ void cpu_idle(void)
*/
void default_idle(void)
{
- trace_power_start_rcuidle(POWER_CSTATE, 1, smp_processor_id());
trace_cpu_idle_rcuidle(1, smp_processor_id());
current_thread_info()->status &= ~TS_POLLING;
/*
@@ -389,21 +382,22 @@ void default_idle(void)
else
local_irq_enable();
current_thread_info()->status |= TS_POLLING;
- trace_power_end_rcuidle(smp_processor_id());
trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
}
#ifdef CONFIG_APM_MODULE
EXPORT_SYMBOL(default_idle);
#endif
-bool set_pm_idle_to_default(void)
+#ifdef CONFIG_XEN
+bool xen_set_default_idle(void)
{
- bool ret = !!pm_idle;
+ bool ret = !!x86_idle;
- pm_idle = default_idle;
+ x86_idle = default_idle;
return ret;
}
+#endif
void stop_this_cpu(void *dummy)
{
local_irq_disable();
@@ -413,31 +407,8 @@ void stop_this_cpu(void *dummy)
set_cpu_online(smp_processor_id(), false);
disable_local_APIC();
- for (;;) {
- if (hlt_works(smp_processor_id()))
- halt();
- }
-}
-
-/* Default MONITOR/MWAIT with no hints, used for default C1 state */
-static void mwait_idle(void)
-{
- if (!need_resched()) {
- trace_power_start_rcuidle(POWER_CSTATE, 1, smp_processor_id());
- trace_cpu_idle_rcuidle(1, smp_processor_id());
- if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
- clflush((void *)&current_thread_info()->flags);
-
- __monitor((void *)&current_thread_info()->flags, 0, 0);
- smp_mb();
- if (!need_resched())
- __sti_mwait(0, 0);
- else
- local_irq_enable();
- trace_power_end_rcuidle(smp_processor_id());
- trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
- } else
- local_irq_enable();
+ for (;;)
+ halt();
}
/*
@@ -447,62 +418,13 @@ static void mwait_idle(void)
*/
static void poll_idle(void)
{
- trace_power_start_rcuidle(POWER_CSTATE, 0, smp_processor_id());
trace_cpu_idle_rcuidle(0, smp_processor_id());
local_irq_enable();
while (!need_resched())
cpu_relax();
- trace_power_end_rcuidle(smp_processor_id());
trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
}
-/*
- * mwait selection logic:
- *
- * It depends on the CPU. For AMD CPUs that support MWAIT this is
- * wrong. Family 0x10 and 0x11 CPUs will enter C1 on HLT. Powersavings
- * then depend on a clock divisor and current Pstate of the core. If
- * all cores of a processor are in halt state (C1) the processor can
- * enter the C1E (C1 enhanced) state. If mwait is used this will never
- * happen.
- *
- * idle=mwait overrides this decision and forces the usage of mwait.
- */
-
-#define MWAIT_INFO 0x05
-#define MWAIT_ECX_EXTENDED_INFO 0x01
-#define MWAIT_EDX_C1 0xf0
-
-int mwait_usable(const struct cpuinfo_x86 *c)
-{
- u32 eax, ebx, ecx, edx;
-
- /* Use mwait if idle=mwait boot option is given */
- if (boot_option_idle_override == IDLE_FORCE_MWAIT)
- return 1;
-
- /*
- * Any idle= boot option other than idle=mwait means that we must not
- * use mwait. Eg: idle=halt or idle=poll or idle=nomwait
- */
- if (boot_option_idle_override != IDLE_NO_OVERRIDE)
- return 0;
-
- if (c->cpuid_level < MWAIT_INFO)
- return 0;
-
- cpuid(MWAIT_INFO, &eax, &ebx, &ecx, &edx);
- /* Check, whether EDX has extended info about MWAIT */
- if (!(ecx & MWAIT_ECX_EXTENDED_INFO))
- return 1;
-
- /*
- * edx enumeratios MONITOR/MWAIT extensions. Check, whether
- * C1 supports MWAIT
- */
- return (edx & MWAIT_EDX_C1);
-}
-
bool amd_e400_c1e_detected;
EXPORT_SYMBOL(amd_e400_c1e_detected);
@@ -567,31 +489,24 @@ static void amd_e400_idle(void)
void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
{
#ifdef CONFIG_SMP
- if (pm_idle == poll_idle && smp_num_siblings > 1) {
+ if (x86_idle == poll_idle && smp_num_siblings > 1)
pr_warn_once("WARNING: polling idle and HT enabled, performance may degrade\n");
- }
#endif
- if (pm_idle)
+ if (x86_idle)
return;
- if (cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)) {
- /*
- * One CPU supports mwait => All CPUs supports mwait
- */
- pr_info("using mwait in idle threads\n");
- pm_idle = mwait_idle;
- } else if (cpu_has_amd_erratum(amd_erratum_400)) {
+ if (cpu_has_amd_erratum(amd_erratum_400)) {
/* E400: APIC timer interrupt does not wake up CPU from C1e */
pr_info("using AMD E400 aware idle routine\n");
- pm_idle = amd_e400_idle;
+ x86_idle = amd_e400_idle;
} else
- pm_idle = default_idle;
+ x86_idle = default_idle;
}
void __init init_amd_e400_c1e_mask(void)
{
/* If we're using amd_e400_idle, we need to allocate amd_e400_c1e_mask. */
- if (pm_idle == amd_e400_idle)
+ if (x86_idle == amd_e400_idle)
zalloc_cpumask_var(&amd_e400_c1e_mask, GFP_KERNEL);
}
@@ -602,11 +517,8 @@ static int __init idle_setup(char *str)
if (!strcmp(str, "poll")) {
pr_info("using polling idle threads\n");
- pm_idle = poll_idle;
+ x86_idle = poll_idle;
boot_option_idle_override = IDLE_POLL;
- } else if (!strcmp(str, "mwait")) {
- boot_option_idle_override = IDLE_FORCE_MWAIT;
- WARN_ONCE(1, "\"idle=mwait\" will be removed in 2012\n");
} else if (!strcmp(str, "halt")) {
/*
* When the boot option of idle=halt is added, halt is
@@ -615,7 +527,7 @@ static int __init idle_setup(char *str)
* To continue to load the CPU idle driver, don't touch
* the boot_option_idle_override.
*/
- pm_idle = default_idle;
+ x86_idle = default_idle;
boot_option_idle_override = IDLE_HALT;
} else if (!strcmp(str, "nomwait")) {
/*
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 6e68a6194965..0f49677da51e 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -117,7 +117,7 @@ void release_thread(struct task_struct *dead_task)
{
if (dead_task->mm) {
if (dead_task->mm->context.size) {
- pr_warn("WARNING: dead process %8s still has LDT? <%p/%d>\n",
+ pr_warn("WARNING: dead process %s still has LDT? <%p/%d>\n",
dead_task->comm,
dead_task->mm->context.ldt,
dead_task->mm->context.size);
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index b629bbe0d9bd..29a8120e6fe8 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -22,7 +22,7 @@
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <linux/rcupdate.h>
-#include <linux/module.h>
+#include <linux/export.h>
#include <linux/context_tracking.h>
#include <asm/uaccess.h>
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c
index 801602b5d745..2e8f3d3b5641 100644
--- a/arch/x86/kernel/rtc.c
+++ b/arch/x86/kernel/rtc.c
@@ -149,7 +149,6 @@ unsigned long mach_get_cmos_time(void)
if (century) {
century = bcd2bin(century);
year += century * 100;
- printk(KERN_INFO "Extended CMOS year: %d\n", century * 100);
} else
year += CMOS_YEARS_OFFS;
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 8b24289cc10c..9c857f05cef0 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -108,17 +108,16 @@
#include <asm/topology.h>
#include <asm/apicdef.h>
#include <asm/amd_nb.h>
-#ifdef CONFIG_X86_64
-#include <asm/numa_64.h>
-#endif
#include <asm/mce.h>
#include <asm/alternative.h>
#include <asm/prom.h>
/*
- * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
- * The direct mapping extends to max_pfn_mapped, so that we can directly access
- * apertures, ACPI and other tables without having to play with fixmaps.
+ * max_low_pfn_mapped: highest direct mapped pfn under 4GB
+ * max_pfn_mapped: highest direct mapped pfn over 4GB
+ *
+ * The direct mapping only covers E820_RAM regions, so the ranges and gaps are
+ * represented by pfn_mapped
*/
unsigned long max_low_pfn_mapped;
unsigned long max_pfn_mapped;
@@ -276,18 +275,7 @@ void * __init extend_brk(size_t size, size_t align)
return ret;
}
-#ifdef CONFIG_X86_64
-static void __init init_gbpages(void)
-{
- if (direct_gbpages && cpu_has_gbpages)
- printk(KERN_INFO "Using GB pages for direct mapping\n");
- else
- direct_gbpages = 0;
-}
-#else
-static inline void init_gbpages(void)
-{
-}
+#ifdef CONFIG_X86_32
static void __init cleanup_highmap(void)
{
}
@@ -296,8 +284,8 @@ static void __init cleanup_highmap(void)
static void __init reserve_brk(void)
{
if (_brk_end > _brk_start)
- memblock_reserve(__pa(_brk_start),
- __pa(_brk_end) - __pa(_brk_start));
+ memblock_reserve(__pa_symbol(_brk_start),
+ _brk_end - _brk_start);
/* Mark brk area as locked down and no longer taking any
new allocations */
@@ -306,27 +294,43 @@ static void __init reserve_brk(void)
#ifdef CONFIG_BLK_DEV_INITRD
+static u64 __init get_ramdisk_image(void)
+{
+ u64 ramdisk_image = boot_params.hdr.ramdisk_image;
+
+ ramdisk_image |= (u64)boot_params.ext_ramdisk_image << 32;
+
+ return ramdisk_image;
+}
+static u64 __init get_ramdisk_size(void)
+{
+ u64 ramdisk_size = boot_params.hdr.ramdisk_size;
+
+ ramdisk_size |= (u64)boot_params.ext_ramdisk_size << 32;
+
+ return ramdisk_size;
+}
+
#define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT)
static void __init relocate_initrd(void)
{
/* Assume only end is not page aligned */
- u64 ramdisk_image = boot_params.hdr.ramdisk_image;
- u64 ramdisk_size = boot_params.hdr.ramdisk_size;
+ u64 ramdisk_image = get_ramdisk_image();
+ u64 ramdisk_size = get_ramdisk_size();
u64 area_size = PAGE_ALIGN(ramdisk_size);
- u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT;
u64 ramdisk_here;
unsigned long slop, clen, mapaddr;
char *p, *q;
- /* We need to move the initrd down into lowmem */
- ramdisk_here = memblock_find_in_range(0, end_of_lowmem, area_size,
- PAGE_SIZE);
+ /* We need to move the initrd down into directly mapped mem */
+ ramdisk_here = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped),
+ area_size, PAGE_SIZE);
if (!ramdisk_here)
panic("Cannot find place for new RAMDISK of size %lld\n",
ramdisk_size);
- /* Note: this includes all the lowmem currently occupied by
+ /* Note: this includes all the mem currently occupied by
the initrd, we rely on that fact to keep the data intact. */
memblock_reserve(ramdisk_here, area_size);
initrd_start = ramdisk_here + PAGE_OFFSET;
@@ -336,17 +340,7 @@ static void __init relocate_initrd(void)
q = (char *)initrd_start;
- /* Copy any lowmem portion of the initrd */
- if (ramdisk_image < end_of_lowmem) {
- clen = end_of_lowmem - ramdisk_image;
- p = (char *)__va(ramdisk_image);
- memcpy(q, p, clen);
- q += clen;
- ramdisk_image += clen;
- ramdisk_size -= clen;
- }
-
- /* Copy the highmem portion of the initrd */
+ /* Copy the initrd */
while (ramdisk_size) {
slop = ramdisk_image & ~PAGE_MASK;
clen = ramdisk_size;
@@ -360,22 +354,35 @@ static void __init relocate_initrd(void)
ramdisk_image += clen;
ramdisk_size -= clen;
}
- /* high pages is not converted by early_res_to_bootmem */
- ramdisk_image = boot_params.hdr.ramdisk_image;
- ramdisk_size = boot_params.hdr.ramdisk_size;
+
+ ramdisk_image = get_ramdisk_image();
+ ramdisk_size = get_ramdisk_size();
printk(KERN_INFO "Move RAMDISK from [mem %#010llx-%#010llx] to"
" [mem %#010llx-%#010llx]\n",
ramdisk_image, ramdisk_image + ramdisk_size - 1,
ramdisk_here, ramdisk_here + ramdisk_size - 1);
}
+static void __init early_reserve_initrd(void)
+{
+ /* Assume only end is not page aligned */
+ u64 ramdisk_image = get_ramdisk_image();
+ u64 ramdisk_size = get_ramdisk_size();
+ u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
+
+ if (!boot_params.hdr.type_of_loader ||
+ !ramdisk_image || !ramdisk_size)
+ return; /* No initrd provided by bootloader */
+
+ memblock_reserve(ramdisk_image, ramdisk_end - ramdisk_image);
+}
static void __init reserve_initrd(void)
{
/* Assume only end is not page aligned */
- u64 ramdisk_image = boot_params.hdr.ramdisk_image;
- u64 ramdisk_size = boot_params.hdr.ramdisk_size;
+ u64 ramdisk_image = get_ramdisk_image();
+ u64 ramdisk_size = get_ramdisk_size();
u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
- u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT;
+ u64 mapped_size;
if (!boot_params.hdr.type_of_loader ||
!ramdisk_image || !ramdisk_size)
@@ -383,22 +390,18 @@ static void __init reserve_initrd(void)
initrd_start = 0;
- if (ramdisk_size >= (end_of_lowmem>>1)) {
+ mapped_size = memblock_mem_size(max_pfn_mapped);
+ if (ramdisk_size >= (mapped_size>>1))
panic("initrd too large to handle, "
"disabling initrd (%lld needed, %lld available)\n",
- ramdisk_size, end_of_lowmem>>1);
- }
+ ramdisk_size, mapped_size>>1);
printk(KERN_INFO "RAMDISK: [mem %#010llx-%#010llx]\n", ramdisk_image,
ramdisk_end - 1);
-
- if (ramdisk_end <= end_of_lowmem) {
- /* All in lowmem, easy case */
- /*
- * don't need to reserve again, already reserved early
- * in i386_start_kernel
- */
+ if (pfn_range_is_mapped(PFN_DOWN(ramdisk_image),
+ PFN_DOWN(ramdisk_end))) {
+ /* All are mapped, easy case */
initrd_start = ramdisk_image + PAGE_OFFSET;
initrd_end = initrd_start + ramdisk_size;
return;
@@ -409,6 +412,9 @@ static void __init reserve_initrd(void)
memblock_free(ramdisk_image, ramdisk_end - ramdisk_image);
}
#else
+static void __init early_reserve_initrd(void)
+{
+}
static void __init reserve_initrd(void)
{
}
@@ -419,8 +425,6 @@ static void __init parse_setup_data(void)
struct setup_data *data;
u64 pa_data;
- if (boot_params.hdr.version < 0x0209)
- return;
pa_data = boot_params.hdr.setup_data;
while (pa_data) {
u32 data_len, map_len;
@@ -456,8 +460,6 @@ static void __init e820_reserve_setup_data(void)
u64 pa_data;
int found = 0;
- if (boot_params.hdr.version < 0x0209)
- return;
pa_data = boot_params.hdr.setup_data;
while (pa_data) {
data = early_memremap(pa_data, sizeof(*data));
@@ -481,8 +483,6 @@ static void __init memblock_x86_reserve_range_setup_data(void)
struct setup_data *data;
u64 pa_data;
- if (boot_params.hdr.version < 0x0209)
- return;
pa_data = boot_params.hdr.setup_data;
while (pa_data) {
data = early_memremap(pa_data, sizeof(*data));
@@ -501,17 +501,51 @@ static void __init memblock_x86_reserve_range_setup_data(void)
/*
* Keep the crash kernel below this limit. On 32 bits earlier kernels
* would limit the kernel to the low 512 MiB due to mapping restrictions.
- * On 64 bits, kexec-tools currently limits us to 896 MiB; increase this
- * limit once kexec-tools are fixed.
*/
#ifdef CONFIG_X86_32
# define CRASH_KERNEL_ADDR_MAX (512 << 20)
#else
-# define CRASH_KERNEL_ADDR_MAX (896 << 20)
+# define CRASH_KERNEL_ADDR_MAX MAXMEM
#endif
+static void __init reserve_crashkernel_low(void)
+{
+#ifdef CONFIG_X86_64
+ const unsigned long long alignment = 16<<20; /* 16M */
+ unsigned long long low_base = 0, low_size = 0;
+ unsigned long total_low_mem;
+ unsigned long long base;
+ int ret;
+
+ total_low_mem = memblock_mem_size(1UL<<(32-PAGE_SHIFT));
+ ret = parse_crashkernel_low(boot_command_line, total_low_mem,
+ &low_size, &base);
+ if (ret != 0 || low_size <= 0)
+ return;
+
+ low_base = memblock_find_in_range(low_size, (1ULL<<32),
+ low_size, alignment);
+
+ if (!low_base) {
+ pr_info("crashkernel low reservation failed - No suitable area found.\n");
+
+ return;
+ }
+
+ memblock_reserve(low_base, low_size);
+ pr_info("Reserving %ldMB of low memory at %ldMB for crashkernel (System low RAM: %ldMB)\n",
+ (unsigned long)(low_size >> 20),
+ (unsigned long)(low_base >> 20),
+ (unsigned long)(total_low_mem >> 20));
+ crashk_low_res.start = low_base;
+ crashk_low_res.end = low_base + low_size - 1;
+ insert_resource(&iomem_resource, &crashk_low_res);
+#endif
+}
+
static void __init reserve_crashkernel(void)
{
+ const unsigned long long alignment = 16<<20; /* 16M */
unsigned long long total_mem;
unsigned long long crash_size, crash_base;
int ret;
@@ -525,8 +559,6 @@ static void __init reserve_crashkernel(void)
/* 0 means: find the address automatically */
if (crash_base <= 0) {
- const unsigned long long alignment = 16<<20; /* 16M */
-
/*
* kexec want bzImage is below CRASH_KERNEL_ADDR_MAX
*/
@@ -537,6 +569,7 @@ static void __init reserve_crashkernel(void)
pr_info("crashkernel reservation failed - No suitable area found.\n");
return;
}
+
} else {
unsigned long long start;
@@ -558,6 +591,9 @@ static void __init reserve_crashkernel(void)
crashk_res.start = crash_base;
crashk_res.end = crash_base + crash_size - 1;
insert_resource(&iomem_resource, &crashk_res);
+
+ if (crash_base >= (1ULL<<32))
+ reserve_crashkernel_low();
}
#else
static void __init reserve_crashkernel(void)
@@ -608,8 +644,6 @@ static __init void reserve_ibft_region(void)
memblock_reserve(addr, size);
}
-static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10;
-
static bool __init snb_gfx_workaround_needed(void)
{
#ifdef CONFIG_PCI
@@ -698,8 +732,7 @@ static void __init trim_bios_range(void)
* since some BIOSes are known to corrupt low memory. See the
* Kconfig help text for X86_RESERVE_LOW.
*/
- e820_update_range(0, ALIGN(reserve_low, PAGE_SIZE),
- E820_RAM, E820_RESERVED);
+ e820_update_range(0, PAGE_SIZE, E820_RAM, E820_RESERVED);
/*
* special case: Some BIOSen report the PC BIOS
@@ -711,6 +744,29 @@ static void __init trim_bios_range(void)
sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
}
+/* called before trim_bios_range() to spare extra sanitize */
+static void __init e820_add_kernel_range(void)
+{
+ u64 start = __pa_symbol(_text);
+ u64 size = __pa_symbol(_end) - start;
+
+ /*
+ * Complain if .text .data and .bss are not marked as E820_RAM and
+ * attempt to fix it by adding the range. We may have a confused BIOS,
+ * or the user may have used memmap=exactmap or memmap=xxM$yyM to
+ * exclude kernel range. If we really are running on top non-RAM,
+ * we will crash later anyways.
+ */
+ if (e820_all_mapped(start, start + size, E820_RAM))
+ return;
+
+ pr_warn(".text .data .bss are not marked as E820_RAM!\n");
+ e820_remove_range(start, size, E820_RAM, 0);
+ e820_add_region(start, size, E820_RAM);
+}
+
+static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10;
+
static int __init parse_reservelow(char *p)
{
unsigned long long size;
@@ -733,6 +789,11 @@ static int __init parse_reservelow(char *p)
early_param("reservelow", parse_reservelow);
+static void __init trim_low_memory_range(void)
+{
+ memblock_reserve(0, ALIGN(reserve_low, PAGE_SIZE));
+}
+
/*
* Determine if we were loaded by an EFI loader. If so, then we have also been
* passed the efi memmap, systab, etc., so we should use these data structures
@@ -748,6 +809,17 @@ early_param("reservelow", parse_reservelow);
void __init setup_arch(char **cmdline_p)
{
+ memblock_reserve(__pa_symbol(_text),
+ (unsigned long)__bss_stop - (unsigned long)_text);
+
+ early_reserve_initrd();
+
+ /*
+ * At this point everything still needed from the boot loader
+ * or BIOS or kernel text should be early reserved or marked not
+ * RAM in e820. All other memory is free game.
+ */
+
#ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
visws_early_detect();
@@ -835,12 +907,12 @@ void __init setup_arch(char **cmdline_p)
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = _brk_end;
- code_resource.start = virt_to_phys(_text);
- code_resource.end = virt_to_phys(_etext)-1;
- data_resource.start = virt_to_phys(_etext);
- data_resource.end = virt_to_phys(_edata)-1;
- bss_resource.start = virt_to_phys(&__bss_start);
- bss_resource.end = virt_to_phys(&__bss_stop)-1;
+ code_resource.start = __pa_symbol(_text);
+ code_resource.end = __pa_symbol(_etext)-1;
+ data_resource.start = __pa_symbol(_etext);
+ data_resource.end = __pa_symbol(_edata)-1;
+ bss_resource.start = __pa_symbol(__bss_start);
+ bss_resource.end = __pa_symbol(__bss_stop)-1;
#ifdef CONFIG_CMDLINE_BOOL
#ifdef CONFIG_CMDLINE_OVERRIDE
@@ -906,6 +978,7 @@ void __init setup_arch(char **cmdline_p)
insert_resource(&iomem_resource, &data_resource);
insert_resource(&iomem_resource, &bss_resource);
+ e820_add_kernel_range();
trim_bios_range();
#ifdef CONFIG_X86_32
if (ppro_with_ram_bug()) {
@@ -955,6 +1028,8 @@ void __init setup_arch(char **cmdline_p)
reserve_ibft_region();
+ early_alloc_pgt_buf();
+
/*
* Need to conclude brk, before memblock_x86_fill()
* it could use memblock_find_in_range, could overlap with
@@ -964,7 +1039,7 @@ void __init setup_arch(char **cmdline_p)
cleanup_highmap();
- memblock.current_limit = get_max_mapped();
+ memblock.current_limit = ISA_END_ADDRESS;
memblock_x86_fill();
/*
@@ -981,41 +1056,31 @@ void __init setup_arch(char **cmdline_p)
setup_bios_corruption_check();
#endif
+ /*
+ * In the memory hotplug case, the kernel needs info from SRAT to
+ * determine which memory is hotpluggable before allocating memory
+ * using memblock.
+ */
+ acpi_boot_table_init();
+ early_acpi_boot_init();
+ early_parse_srat();
+
+#ifdef CONFIG_X86_32
printk(KERN_DEBUG "initial memory mapped: [mem 0x00000000-%#010lx]\n",
(max_pfn_mapped<<PAGE_SHIFT) - 1);
+#endif
- setup_real_mode();
+ reserve_real_mode();
trim_platform_memory_ranges();
+ trim_low_memory_range();
- init_gbpages();
+ init_mem_mapping();
- /* max_pfn_mapped is updated here */
- max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
- max_pfn_mapped = max_low_pfn_mapped;
+ early_trap_pf_init();
-#ifdef CONFIG_X86_64
- if (max_pfn > max_low_pfn) {
- int i;
- unsigned long start, end;
- unsigned long start_pfn, end_pfn;
-
- for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn,
- NULL) {
-
- end = PFN_PHYS(end_pfn);
- if (end <= (1UL<<32))
- continue;
-
- start = PFN_PHYS(start_pfn);
- max_pfn_mapped = init_memory_mapping(
- max((1UL<<32), start), end);
- }
+ setup_real_mode();
- /* can we preseve max_low_pfn ?*/
- max_low_pfn = max_pfn;
- }
-#endif
memblock.current_limit = get_max_mapped();
dma_contiguous_reserve(0);
@@ -1045,10 +1110,6 @@ void __init setup_arch(char **cmdline_p)
/*
* Parse the ACPI tables for possible boot-time SMP configuration.
*/
- acpi_boot_table_init();
-
- early_acpi_boot_init();
-
initmem_init();
memblock_find_dma_reserve();
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index d6bf1f34a6e9..69562992e457 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -278,7 +278,7 @@ static const struct {
};
static int
-__setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
+__setup_frame(int sig, struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs)
{
struct sigframe __user *frame;
@@ -286,7 +286,7 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
int err = 0;
void __user *fpstate = NULL;
- frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
+ frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;
@@ -307,8 +307,8 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
restorer = VDSO32_SYMBOL(current->mm->context.vdso, sigreturn);
else
restorer = &frame->retcode;
- if (ka->sa.sa_flags & SA_RESTORER)
- restorer = ka->sa.sa_restorer;
+ if (ksig->ka.sa.sa_flags & SA_RESTORER)
+ restorer = ksig->ka.sa.sa_restorer;
/* Set up to return from userspace. */
err |= __put_user(restorer, &frame->pretcode);
@@ -327,7 +327,7 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
/* Set up registers for signal handler */
regs->sp = (unsigned long)frame;
- regs->ip = (unsigned long)ka->sa.sa_handler;
+ regs->ip = (unsigned long)ksig->ka.sa.sa_handler;
regs->ax = (unsigned long)sig;
regs->dx = 0;
regs->cx = 0;
@@ -340,7 +340,7 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
return 0;
}
-static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+static int __setup_rt_frame(int sig, struct ksignal *ksig,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
@@ -348,7 +348,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
int err = 0;
void __user *fpstate = NULL;
- frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
+ frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;
@@ -368,8 +368,8 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up to return from userspace. */
restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
- if (ka->sa.sa_flags & SA_RESTORER)
- restorer = ka->sa.sa_restorer;
+ if (ksig->ka.sa.sa_flags & SA_RESTORER)
+ restorer = ksig->ka.sa.sa_restorer;
put_user_ex(restorer, &frame->pretcode);
/*
@@ -382,7 +382,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
} put_user_catch(err);
- err |= copy_siginfo_to_user(&frame->info, info);
+ err |= copy_siginfo_to_user(&frame->info, &ksig->info);
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
@@ -392,7 +392,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up registers for signal handler */
regs->sp = (unsigned long)frame;
- regs->ip = (unsigned long)ka->sa.sa_handler;
+ regs->ip = (unsigned long)ksig->ka.sa.sa_handler;
regs->ax = (unsigned long)sig;
regs->dx = (unsigned long)&frame->info;
regs->cx = (unsigned long)&frame->uc;
@@ -405,20 +405,20 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return 0;
}
#else /* !CONFIG_X86_32 */
-static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+static int __setup_rt_frame(int sig, struct ksignal *ksig,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
void __user *fp = NULL;
int err = 0;
- frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe), &fp);
+ frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;
- if (ka->sa.sa_flags & SA_SIGINFO) {
- if (copy_siginfo_to_user(&frame->info, info))
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
+ if (copy_siginfo_to_user(&frame->info, &ksig->info))
return -EFAULT;
}
@@ -434,8 +434,8 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
/* x86-64 should always use SA_RESTORER. */
- if (ka->sa.sa_flags & SA_RESTORER) {
- put_user_ex(ka->sa.sa_restorer, &frame->pretcode);
+ if (ksig->ka.sa.sa_flags & SA_RESTORER) {
+ put_user_ex(ksig->ka.sa.sa_restorer, &frame->pretcode);
} else {
/* could use a vstub here */
err |= -EFAULT;
@@ -457,7 +457,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
next argument after the signal number on the stack. */
regs->si = (unsigned long)&frame->info;
regs->dx = (unsigned long)&frame->uc;
- regs->ip = (unsigned long) ka->sa.sa_handler;
+ regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
regs->sp = (unsigned long)frame;
@@ -469,8 +469,8 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
}
#endif /* CONFIG_X86_32 */
-static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
- siginfo_t *info, compat_sigset_t *set,
+static int x32_setup_rt_frame(struct ksignal *ksig,
+ compat_sigset_t *set,
struct pt_regs *regs)
{
#ifdef CONFIG_X86_X32_ABI
@@ -479,13 +479,13 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
int err = 0;
void __user *fpstate = NULL;
- frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
+ frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;
- if (ka->sa.sa_flags & SA_SIGINFO) {
- if (copy_siginfo_to_user32(&frame->info, info))
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
+ if (copy_siginfo_to_user32(&frame->info, &ksig->info))
return -EFAULT;
}
@@ -499,8 +499,8 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
put_user_ex(0, &frame->uc.uc__pad0);
- if (ka->sa.sa_flags & SA_RESTORER) {
- restorer = ka->sa.sa_restorer;
+ if (ksig->ka.sa.sa_flags & SA_RESTORER) {
+ restorer = ksig->ka.sa.sa_restorer;
} else {
/* could use a vstub here */
restorer = NULL;
@@ -518,10 +518,10 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
/* Set up registers for signal handler */
regs->sp = (unsigned long) frame;
- regs->ip = (unsigned long) ka->sa.sa_handler;
+ regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
/* We use the x32 calling convention here... */
- regs->di = sig;
+ regs->di = ksig->sig;
regs->si = (unsigned long) &frame->info;
regs->dx = (unsigned long) &frame->uc;
@@ -535,70 +535,13 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
return 0;
}
-#ifdef CONFIG_X86_32
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(int history0, int history1, old_sigset_t mask)
-{
- sigset_t blocked;
- siginitset(&blocked, mask);
- return sigsuspend(&blocked);
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction __user *act,
- struct old_sigaction __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret = 0;
-
- if (act) {
- old_sigset_t mask;
-
- if (!access_ok(VERIFY_READ, act, sizeof(*act)))
- return -EFAULT;
-
- get_user_try {
- get_user_ex(new_ka.sa.sa_handler, &act->sa_handler);
- get_user_ex(new_ka.sa.sa_flags, &act->sa_flags);
- get_user_ex(mask, &act->sa_mask);
- get_user_ex(new_ka.sa.sa_restorer, &act->sa_restorer);
- } get_user_catch(ret);
-
- if (ret)
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
- return -EFAULT;
-
- put_user_try {
- put_user_ex(old_ka.sa.sa_handler, &oact->sa_handler);
- put_user_ex(old_ka.sa.sa_flags, &oact->sa_flags);
- put_user_ex(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
- put_user_ex(old_ka.sa.sa_restorer, &oact->sa_restorer);
- } put_user_catch(ret);
-
- if (ret)
- return -EFAULT;
- }
-
- return ret;
-}
-#endif /* CONFIG_X86_32 */
-
/*
* Do a signal return; undo the signal stack.
*/
#ifdef CONFIG_X86_32
-unsigned long sys_sigreturn(struct pt_regs *regs)
+unsigned long sys_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct sigframe __user *frame;
unsigned long ax;
sigset_t set;
@@ -625,8 +568,9 @@ badframe:
}
#endif /* CONFIG_X86_32 */
-long sys_rt_sigreturn(struct pt_regs *regs)
+long sys_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct rt_sigframe __user *frame;
unsigned long ax;
sigset_t set;
@@ -667,30 +611,29 @@ static int signr_convert(int sig)
}
static int
-setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
- struct pt_regs *regs)
+setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
{
- int usig = signr_convert(sig);
+ int usig = signr_convert(ksig->sig);
sigset_t *set = sigmask_to_save();
compat_sigset_t *cset = (compat_sigset_t *) set;
/* Set up the stack frame */
if (is_ia32_frame()) {
- if (ka->sa.sa_flags & SA_SIGINFO)
- return ia32_setup_rt_frame(usig, ka, info, cset, regs);
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+ return ia32_setup_rt_frame(usig, ksig, cset, regs);
else
- return ia32_setup_frame(usig, ka, cset, regs);
+ return ia32_setup_frame(usig, ksig, cset, regs);
} else if (is_x32_frame()) {
- return x32_setup_rt_frame(usig, ka, info, cset, regs);
+ return x32_setup_rt_frame(ksig, cset, regs);
} else {
- return __setup_rt_frame(sig, ka, info, set, regs);
+ return __setup_rt_frame(ksig->sig, ksig, set, regs);
}
}
static void
-handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
- struct pt_regs *regs)
+handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
+ bool failed;
/* Are we from a system call? */
if (syscall_get_nr(current, regs) >= 0) {
/* If so, check system call restarting.. */
@@ -701,7 +644,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
break;
case -ERESTARTSYS:
- if (!(ka->sa.sa_flags & SA_RESTART)) {
+ if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
regs->ax = -EINTR;
break;
}
@@ -721,26 +664,21 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
regs->flags &= ~X86_EFLAGS_TF;
- if (setup_rt_frame(sig, ka, info, regs) < 0) {
- force_sigsegv(sig, current);
- return;
+ failed = (setup_rt_frame(ksig, regs) < 0);
+ if (!failed) {
+ /*
+ * Clear the direction flag as per the ABI for function entry.
+ */
+ regs->flags &= ~X86_EFLAGS_DF;
+ /*
+ * Clear TF when entering the signal handler, but
+ * notify any tracer that was single-stepping it.
+ * The tracer may want to single-step inside the
+ * handler too.
+ */
+ regs->flags &= ~X86_EFLAGS_TF;
}
-
- /*
- * Clear the direction flag as per the ABI for function entry.
- */
- regs->flags &= ~X86_EFLAGS_DF;
-
- /*
- * Clear TF when entering the signal handler, but
- * notify any tracer that was single-stepping it.
- * The tracer may want to single-step inside the
- * handler too.
- */
- regs->flags &= ~X86_EFLAGS_TF;
-
- signal_delivered(sig, info, ka, regs,
- test_thread_flag(TIF_SINGLESTEP));
+ signal_setup_done(failed, ksig, test_thread_flag(TIF_SINGLESTEP));
}
#ifdef CONFIG_X86_32
@@ -757,14 +695,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
*/
static void do_signal(struct pt_regs *regs)
{
- struct k_sigaction ka;
- siginfo_t info;
- int signr;
+ struct ksignal ksig;
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
- if (signr > 0) {
+ if (get_signal(&ksig)) {
/* Whee! Actually deliver the signal. */
- handle_signal(signr, &info, &ka, regs);
+ handle_signal(&ksig, regs);
return;
}
@@ -843,8 +778,9 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
}
#ifdef CONFIG_X86_X32_ABI
-asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs)
+asmlinkage long sys32_x32_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct rt_sigframe_x32 __user *frame;
sigset_t set;
unsigned long ax;
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index ed0fe385289d..a6ceaedc396a 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1369,7 +1369,7 @@ static inline void mwait_play_dead(void)
void *mwait_ptr;
struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info);
- if (!(this_cpu_has(X86_FEATURE_MWAIT) && mwait_usable(c)))
+ if (!this_cpu_has(X86_FEATURE_MWAIT))
return;
if (!this_cpu_has(X86_FEATURE_CLFLSH))
return;
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
index 97ef74b88e0f..dbded5aedb81 100644
--- a/arch/x86/kernel/sys_x86_64.c
+++ b/arch/x86/kernel/sys_x86_64.c
@@ -157,7 +157,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
if (flags & MAP_FIXED)
return addr;
- /* for MAP_32BIT mappings we force the legact mmap base */
+ /* for MAP_32BIT mappings we force the legacy mmap base */
if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT))
goto bottomup;
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index ecffca11f4e9..68bda7a84159 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -688,10 +688,19 @@ void __init early_trap_init(void)
set_intr_gate_ist(X86_TRAP_DB, &debug, DEBUG_STACK);
/* int3 can be called from all */
set_system_intr_gate_ist(X86_TRAP_BP, &int3, DEBUG_STACK);
+#ifdef CONFIG_X86_32
set_intr_gate(X86_TRAP_PF, &page_fault);
+#endif
load_idt(&idt_descr);
}
+void __init early_trap_pf_init(void)
+{
+#ifdef CONFIG_X86_64
+ set_intr_gate(X86_TRAP_PF, &page_fault);
+#endif
+}
+
void __init trap_init(void)
{
int i;
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 06ccb5073a3f..4b9ea101fe3b 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -623,7 +623,8 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
ns_now = __cycles_2_ns(tsc_now);
if (cpu_khz) {
- *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz;
+ *scale = ((NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR) +
+ cpu_khz / 2) / cpu_khz;
*offset = ns_now - mult_frac(tsc_now, *scale,
(1UL << CYC2NS_SCALE_FACTOR));
}
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index c71025b67462..0ba4cfb4f412 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -680,8 +680,10 @@ static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
if (auprobe->insn[i] == 0x66)
continue;
- if (auprobe->insn[i] == 0x90)
+ if (auprobe->insn[i] == 0x90) {
+ regs->ip += i + 1;
return true;
+ }
break;
}
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 1dfe69cc78a8..1cf5766dde16 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -202,7 +202,7 @@ out:
static int do_vm86_irq_handling(int subfunction, int irqnumber);
static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk);
-int sys_vm86old(struct vm86_struct __user *v86, struct pt_regs *regs)
+int sys_vm86old(struct vm86_struct __user *v86)
{
struct kernel_vm86_struct info; /* declare this _on top_,
* this avoids wasting of stack space.
@@ -222,7 +222,7 @@ int sys_vm86old(struct vm86_struct __user *v86, struct pt_regs *regs)
if (tmp)
goto out;
memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
- info.regs32 = regs;
+ info.regs32 = current_pt_regs();
tsk->thread.vm86_info = v86;
do_sys_vm86(&info, tsk);
ret = 0; /* we never return here */
@@ -231,7 +231,7 @@ out:
}
-int sys_vm86(unsigned long cmd, unsigned long arg, struct pt_regs *regs)
+int sys_vm86(unsigned long cmd, unsigned long arg)
{
struct kernel_vm86_struct info; /* declare this _on top_,
* this avoids wasting of stack space.
@@ -272,7 +272,7 @@ int sys_vm86(unsigned long cmd, unsigned long arg, struct pt_regs *regs)
ret = -EFAULT;
if (tmp)
goto out;
- info.regs32 = regs;
+ info.regs32 = current_pt_regs();
info.vm86plus.is_vm86pus = 1;
tsk->thread.vm86_info = (struct vm86_struct __user *)v86;
do_sys_vm86(&info, tsk);
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c
index 1330dd102950..b014d9414d08 100644
--- a/arch/x86/kernel/x8664_ksyms_64.c
+++ b/arch/x86/kernel/x8664_ksyms_64.c
@@ -59,6 +59,9 @@ EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(memmove);
+#ifndef CONFIG_DEBUG_VIRTUAL
+EXPORT_SYMBOL(phys_base);
+#endif
EXPORT_SYMBOL(empty_zero_page);
#ifndef CONFIG_PARAVIRT
EXPORT_SYMBOL(native_load_gs_index);
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 7a3d075a814a..45a14dbbddaf 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -19,6 +19,7 @@
#include <asm/time.h>
#include <asm/irq.h>
#include <asm/io_apic.h>
+#include <asm/hpet.h>
#include <asm/pat.h>
#include <asm/tsc.h>
#include <asm/iommu.h>
@@ -62,10 +63,6 @@ struct x86_init_ops x86_init __initdata = {
.banner = default_banner,
},
- .mapping = {
- .pagetable_reserve = native_pagetable_reserve,
- },
-
.paging = {
.pagetable_init = native_pagetable_init,
},
@@ -111,15 +108,22 @@ struct x86_platform_ops x86_platform = {
EXPORT_SYMBOL_GPL(x86_platform);
struct x86_msi_ops x86_msi = {
- .setup_msi_irqs = native_setup_msi_irqs,
- .teardown_msi_irq = native_teardown_msi_irq,
- .teardown_msi_irqs = default_teardown_msi_irqs,
- .restore_msi_irqs = default_restore_msi_irqs,
+ .setup_msi_irqs = native_setup_msi_irqs,
+ .compose_msi_msg = native_compose_msi_msg,
+ .teardown_msi_irq = native_teardown_msi_irq,
+ .teardown_msi_irqs = default_teardown_msi_irqs,
+ .restore_msi_irqs = default_restore_msi_irqs,
+ .setup_hpet_msi = default_setup_hpet_msi,
};
struct x86_io_apic_ops x86_io_apic_ops = {
- .init = native_io_apic_init_mappings,
- .read = native_io_apic_read,
- .write = native_io_apic_write,
- .modify = native_io_apic_modify,
+ .init = native_io_apic_init_mappings,
+ .read = native_io_apic_read,
+ .write = native_io_apic_write,
+ .modify = native_io_apic_modify,
+ .disable = native_disable_io_apic,
+ .print_entries = native_io_apic_print_entries,
+ .set_affinity = native_ioapic_set_affinity,
+ .setup_entry = native_setup_ioapic_entry,
+ .eoi_ioapic_pin = native_eoi_ioapic_pin,
};
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index a27e76371108..a335cc6cde72 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -24,6 +24,7 @@
#include "kvm_cache_regs.h"
#include <linux/module.h>
#include <asm/kvm_emulate.h>
+#include <linux/stringify.h>
#include "x86.h"
#include "tss.h"
@@ -43,7 +44,7 @@
#define OpCL 9ull /* CL register (for shifts) */
#define OpImmByte 10ull /* 8-bit sign extended immediate */
#define OpOne 11ull /* Implied 1 */
-#define OpImm 12ull /* Sign extended immediate */
+#define OpImm 12ull /* Sign extended up to 32-bit immediate */
#define OpMem16 13ull /* Memory operand (16-bit). */
#define OpMem32 14ull /* Memory operand (32-bit). */
#define OpImmU 15ull /* Immediate operand, zero extended */
@@ -58,6 +59,7 @@
#define OpFS 24ull /* FS */
#define OpGS 25ull /* GS */
#define OpMem8 26ull /* 8-bit zero extended memory operand */
+#define OpImm64 27ull /* Sign extended 16/32/64-bit immediate */
#define OpBits 5 /* Width of operand field */
#define OpMask ((1ull << OpBits) - 1)
@@ -101,6 +103,7 @@
#define SrcMemFAddr (OpMemFAddr << SrcShift)
#define SrcAcc (OpAcc << SrcShift)
#define SrcImmU16 (OpImmU16 << SrcShift)
+#define SrcImm64 (OpImm64 << SrcShift)
#define SrcDX (OpDX << SrcShift)
#define SrcMem8 (OpMem8 << SrcShift)
#define SrcMask (OpMask << SrcShift)
@@ -113,6 +116,7 @@
#define GroupDual (2<<15) /* Alternate decoding of mod == 3 */
#define Prefix (3<<15) /* Instruction varies with 66/f2/f3 prefix */
#define RMExt (4<<15) /* Opcode extension in ModRM r/m if mod == 3 */
+#define Escape (5<<15) /* Escape to coprocessor instruction */
#define Sse (1<<18) /* SSE Vector instruction */
/* Generic ModRM decode. */
#define ModRM (1<<19)
@@ -146,6 +150,8 @@
#define Aligned ((u64)1 << 41) /* Explicitly aligned (e.g. MOVDQA) */
#define Unaligned ((u64)1 << 42) /* Explicitly unaligned (e.g. MOVDQU) */
#define Avx ((u64)1 << 43) /* Advanced Vector Extensions */
+#define Fastop ((u64)1 << 44) /* Use opcode::u.fastop */
+#define NoWrite ((u64)1 << 45) /* No writeback */
#define X2(x...) x, x
#define X3(x...) X2(x), x
@@ -156,6 +162,27 @@
#define X8(x...) X4(x), X4(x)
#define X16(x...) X8(x), X8(x)
+#define NR_FASTOP (ilog2(sizeof(ulong)) + 1)
+#define FASTOP_SIZE 8
+
+/*
+ * fastop functions have a special calling convention:
+ *
+ * dst: [rdx]:rax (in/out)
+ * src: rbx (in/out)
+ * src2: rcx (in)
+ * flags: rflags (in/out)
+ *
+ * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for
+ * different operand sizes can be reached by calculation, rather than a jump
+ * table (which would be bigger than the code).
+ *
+ * fastop functions are declared as taking a never-defined fastop parameter,
+ * so they can't be called from C directly.
+ */
+
+struct fastop;
+
struct opcode {
u64 flags : 56;
u64 intercept : 8;
@@ -164,6 +191,8 @@ struct opcode {
const struct opcode *group;
const struct group_dual *gdual;
const struct gprefix *gprefix;
+ const struct escape *esc;
+ void (*fastop)(struct fastop *fake);
} u;
int (*check_perm)(struct x86_emulate_ctxt *ctxt);
};
@@ -180,6 +209,11 @@ struct gprefix {
struct opcode pfx_f3;
};
+struct escape {
+ struct opcode op[8];
+ struct opcode high[64];
+};
+
/* EFLAGS bit definitions. */
#define EFLG_ID (1<<21)
#define EFLG_VIP (1<<20)
@@ -407,6 +441,97 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
} \
} while (0)
+static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
+
+#define FOP_ALIGN ".align " __stringify(FASTOP_SIZE) " \n\t"
+#define FOP_RET "ret \n\t"
+
+#define FOP_START(op) \
+ extern void em_##op(struct fastop *fake); \
+ asm(".pushsection .text, \"ax\" \n\t" \
+ ".global em_" #op " \n\t" \
+ FOP_ALIGN \
+ "em_" #op ": \n\t"
+
+#define FOP_END \
+ ".popsection")
+
+#define FOPNOP() FOP_ALIGN FOP_RET
+
+#define FOP1E(op, dst) \
+ FOP_ALIGN #op " %" #dst " \n\t" FOP_RET
+
+#define FASTOP1(op) \
+ FOP_START(op) \
+ FOP1E(op##b, al) \
+ FOP1E(op##w, ax) \
+ FOP1E(op##l, eax) \
+ ON64(FOP1E(op##q, rax)) \
+ FOP_END
+
+#define FOP2E(op, dst, src) \
+ FOP_ALIGN #op " %" #src ", %" #dst " \n\t" FOP_RET
+
+#define FASTOP2(op) \
+ FOP_START(op) \
+ FOP2E(op##b, al, bl) \
+ FOP2E(op##w, ax, bx) \
+ FOP2E(op##l, eax, ebx) \
+ ON64(FOP2E(op##q, rax, rbx)) \
+ FOP_END
+
+/* 2 operand, word only */
+#define FASTOP2W(op) \
+ FOP_START(op) \
+ FOPNOP() \
+ FOP2E(op##w, ax, bx) \
+ FOP2E(op##l, eax, ebx) \
+ ON64(FOP2E(op##q, rax, rbx)) \
+ FOP_END
+
+/* 2 operand, src is CL */
+#define FASTOP2CL(op) \
+ FOP_START(op) \
+ FOP2E(op##b, al, cl) \
+ FOP2E(op##w, ax, cl) \
+ FOP2E(op##l, eax, cl) \
+ ON64(FOP2E(op##q, rax, cl)) \
+ FOP_END
+
+#define FOP3E(op, dst, src, src2) \
+ FOP_ALIGN #op " %" #src2 ", %" #src ", %" #dst " \n\t" FOP_RET
+
+/* 3-operand, word-only, src2=cl */
+#define FASTOP3WCL(op) \
+ FOP_START(op) \
+ FOPNOP() \
+ FOP3E(op##w, ax, bx, cl) \
+ FOP3E(op##l, eax, ebx, cl) \
+ ON64(FOP3E(op##q, rax, rbx, cl)) \
+ FOP_END
+
+/* Special case for SETcc - 1 instruction per cc */
+#define FOP_SETCC(op) ".align 4; " #op " %al; ret \n\t"
+
+FOP_START(setcc)
+FOP_SETCC(seto)
+FOP_SETCC(setno)
+FOP_SETCC(setc)
+FOP_SETCC(setnc)
+FOP_SETCC(setz)
+FOP_SETCC(setnz)
+FOP_SETCC(setbe)
+FOP_SETCC(setnbe)
+FOP_SETCC(sets)
+FOP_SETCC(setns)
+FOP_SETCC(setp)
+FOP_SETCC(setnp)
+FOP_SETCC(setl)
+FOP_SETCC(setnl)
+FOP_SETCC(setle)
+FOP_SETCC(setnle)
+FOP_END;
+
#define __emulate_1op_rax_rdx(ctxt, _op, _suffix, _ex) \
do { \
unsigned long _tmp; \
@@ -663,7 +788,7 @@ static int __linearize(struct x86_emulate_ctxt *ctxt,
ulong la;
u32 lim;
u16 sel;
- unsigned cpl, rpl;
+ unsigned cpl;
la = seg_base(ctxt, addr.seg) + addr.ea;
switch (ctxt->mode) {
@@ -697,11 +822,6 @@ static int __linearize(struct x86_emulate_ctxt *ctxt,
goto bad;
}
cpl = ctxt->ops->cpl(ctxt);
- if (ctxt->mode == X86EMUL_MODE_REAL)
- rpl = 0;
- else
- rpl = sel & 3;
- cpl = max(cpl, rpl);
if (!(desc.type & 8)) {
/* data segment */
if (cpl > desc.dpl)
@@ -852,39 +972,50 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt,
return rc;
}
-static int test_cc(unsigned int condition, unsigned int flags)
-{
- int rc = 0;
-
- switch ((condition & 15) >> 1) {
- case 0: /* o */
- rc |= (flags & EFLG_OF);
- break;
- case 1: /* b/c/nae */
- rc |= (flags & EFLG_CF);
- break;
- case 2: /* z/e */
- rc |= (flags & EFLG_ZF);
- break;
- case 3: /* be/na */
- rc |= (flags & (EFLG_CF|EFLG_ZF));
- break;
- case 4: /* s */
- rc |= (flags & EFLG_SF);
- break;
- case 5: /* p/pe */
- rc |= (flags & EFLG_PF);
- break;
- case 7: /* le/ng */
- rc |= (flags & EFLG_ZF);
- /* fall through */
- case 6: /* l/nge */
- rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF));
- break;
- }
-
- /* Odd condition identifiers (lsb == 1) have inverted sense. */
- return (!!rc ^ (condition & 1));
+FASTOP2(add);
+FASTOP2(or);
+FASTOP2(adc);
+FASTOP2(sbb);
+FASTOP2(and);
+FASTOP2(sub);
+FASTOP2(xor);
+FASTOP2(cmp);
+FASTOP2(test);
+
+FASTOP3WCL(shld);
+FASTOP3WCL(shrd);
+
+FASTOP2W(imul);
+
+FASTOP1(not);
+FASTOP1(neg);
+FASTOP1(inc);
+FASTOP1(dec);
+
+FASTOP2CL(rol);
+FASTOP2CL(ror);
+FASTOP2CL(rcl);
+FASTOP2CL(rcr);
+FASTOP2CL(shl);
+FASTOP2CL(shr);
+FASTOP2CL(sar);
+
+FASTOP2W(bsf);
+FASTOP2W(bsr);
+FASTOP2W(bt);
+FASTOP2W(bts);
+FASTOP2W(btr);
+FASTOP2W(btc);
+
+static u8 test_cc(unsigned int condition, unsigned long flags)
+{
+ u8 rc;
+ void (*fop)(void) = (void *)em_setcc + 4 * (condition & 0xf);
+
+ flags = (flags & EFLAGS_MASK) | X86_EFLAGS_IF;
+ asm("push %[flags]; popf; call *%[fastop]"
+ : "=a"(rc) : [fastop]"r"(fop), [flags]"r"(flags));
+ return rc;
}
static void fetch_register_operand(struct operand *op)
@@ -994,6 +1125,53 @@ static void write_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg)
ctxt->ops->put_fpu(ctxt);
}
+static int em_fninit(struct x86_emulate_ctxt *ctxt)
+{
+ if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
+ return emulate_nm(ctxt);
+
+ ctxt->ops->get_fpu(ctxt);
+ asm volatile("fninit");
+ ctxt->ops->put_fpu(ctxt);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_fnstcw(struct x86_emulate_ctxt *ctxt)
+{
+ u16 fcw;
+
+ if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
+ return emulate_nm(ctxt);
+
+ ctxt->ops->get_fpu(ctxt);
+ asm volatile("fnstcw %0": "+m"(fcw));
+ ctxt->ops->put_fpu(ctxt);
+
+ /* force 2 byte destination */
+ ctxt->dst.bytes = 2;
+ ctxt->dst.val = fcw;
+
+ return X86EMUL_CONTINUE;
+}
+
+static int em_fnstsw(struct x86_emulate_ctxt *ctxt)
+{
+ u16 fsw;
+
+ if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
+ return emulate_nm(ctxt);
+
+ ctxt->ops->get_fpu(ctxt);
+ asm volatile("fnstsw %0": "+m"(fsw));
+ ctxt->ops->put_fpu(ctxt);
+
+ /* force 2 byte destination */
+ ctxt->dst.bytes = 2;
+ ctxt->dst.val = fsw;
+
+ return X86EMUL_CONTINUE;
+}
+
static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
struct operand *op)
{
@@ -1534,6 +1712,9 @@ static int writeback(struct x86_emulate_ctxt *ctxt)
{
int rc;
+ if (ctxt->d & NoWrite)
+ return X86EMUL_CONTINUE;
+
switch (ctxt->dst.type) {
case OP_REG:
write_register_operand(&ctxt->dst);
@@ -1918,47 +2099,6 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
-static int em_grp2(struct x86_emulate_ctxt *ctxt)
-{
- switch (ctxt->modrm_reg) {
- case 0: /* rol */
- emulate_2op_SrcB(ctxt, "rol");
- break;
- case 1: /* ror */
- emulate_2op_SrcB(ctxt, "ror");
- break;
- case 2: /* rcl */
- emulate_2op_SrcB(ctxt, "rcl");
- break;
- case 3: /* rcr */
- emulate_2op_SrcB(ctxt, "rcr");
- break;
- case 4: /* sal/shl */
- case 6: /* sal/shl */
- emulate_2op_SrcB(ctxt, "sal");
- break;
- case 5: /* shr */
- emulate_2op_SrcB(ctxt, "shr");
- break;
- case 7: /* sar */
- emulate_2op_SrcB(ctxt, "sar");
- break;
- }
- return X86EMUL_CONTINUE;
-}
-
-static int em_not(struct x86_emulate_ctxt *ctxt)
-{
- ctxt->dst.val = ~ctxt->dst.val;
- return X86EMUL_CONTINUE;
-}
-
-static int em_neg(struct x86_emulate_ctxt *ctxt)
-{
- emulate_1op(ctxt, "neg");
- return X86EMUL_CONTINUE;
-}
-
static int em_mul_ex(struct x86_emulate_ctxt *ctxt)
{
u8 ex = 0;
@@ -2000,12 +2140,6 @@ static int em_grp45(struct x86_emulate_ctxt *ctxt)
int rc = X86EMUL_CONTINUE;
switch (ctxt->modrm_reg) {
- case 0: /* inc */
- emulate_1op(ctxt, "inc");
- break;
- case 1: /* dec */
- emulate_1op(ctxt, "dec");
- break;
case 2: /* call near abs */ {
long int old_eip;
old_eip = ctxt->_eip;
@@ -2075,7 +2209,7 @@ static int em_cmpxchg(struct x86_emulate_ctxt *ctxt)
/* Save real source value, then compare EAX against destination. */
ctxt->src.orig_val = ctxt->src.val;
ctxt->src.val = reg_read(ctxt, VCPU_REGS_RAX);
- emulate_2op_SrcV(ctxt, "cmp");
+ fastop(ctxt, em_cmp);
if (ctxt->eflags & EFLG_ZF) {
/* Success: write back to memory. */
@@ -2843,7 +2977,7 @@ static int em_das(struct x86_emulate_ctxt *ctxt)
ctxt->src.type = OP_IMM;
ctxt->src.val = 0;
ctxt->src.bytes = 1;
- emulate_2op_SrcV(ctxt, "or");
+ fastop(ctxt, em_or);
ctxt->eflags &= ~(X86_EFLAGS_AF | X86_EFLAGS_CF);
if (cf)
ctxt->eflags |= X86_EFLAGS_CF;
@@ -2852,6 +2986,24 @@ static int em_das(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
+static int em_aad(struct x86_emulate_ctxt *ctxt)
+{
+ u8 al = ctxt->dst.val & 0xff;
+ u8 ah = (ctxt->dst.val >> 8) & 0xff;
+
+ al = (al + (ah * ctxt->src.val)) & 0xff;
+
+ ctxt->dst.val = (ctxt->dst.val & 0xffff0000) | al;
+
+ /* Set PF, ZF, SF */
+ ctxt->src.type = OP_IMM;
+ ctxt->src.val = 0;
+ ctxt->src.bytes = 1;
+ fastop(ctxt, em_or);
+
+ return X86EMUL_CONTINUE;
+}
+
static int em_call(struct x86_emulate_ctxt *ctxt)
{
long rel = ctxt->src.val;
@@ -2900,64 +3052,6 @@ static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
-static int em_add(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV(ctxt, "add");
- return X86EMUL_CONTINUE;
-}
-
-static int em_or(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV(ctxt, "or");
- return X86EMUL_CONTINUE;
-}
-
-static int em_adc(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV(ctxt, "adc");
- return X86EMUL_CONTINUE;
-}
-
-static int em_sbb(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV(ctxt, "sbb");
- return X86EMUL_CONTINUE;
-}
-
-static int em_and(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV(ctxt, "and");
- return X86EMUL_CONTINUE;
-}
-
-static int em_sub(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV(ctxt, "sub");
- return X86EMUL_CONTINUE;
-}
-
-static int em_xor(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV(ctxt, "xor");
- return X86EMUL_CONTINUE;
-}
-
-static int em_cmp(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV(ctxt, "cmp");
- /* Disable writeback. */
- ctxt->dst.type = OP_NONE;
- return X86EMUL_CONTINUE;
-}
-
-static int em_test(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV(ctxt, "test");
- /* Disable writeback. */
- ctxt->dst.type = OP_NONE;
- return X86EMUL_CONTINUE;
-}
-
static int em_xchg(struct x86_emulate_ctxt *ctxt)
{
/* Write back the register source. */
@@ -2970,16 +3064,10 @@ static int em_xchg(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
-static int em_imul(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV_nobyte(ctxt, "imul");
- return X86EMUL_CONTINUE;
-}
-
static int em_imul_3op(struct x86_emulate_ctxt *ctxt)
{
ctxt->dst.val = ctxt->src2.val;
- return em_imul(ctxt);
+ return fastop(ctxt, em_imul);
}
static int em_cwd(struct x86_emulate_ctxt *ctxt)
@@ -3300,47 +3388,6 @@ static int em_sti(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
-static int em_bt(struct x86_emulate_ctxt *ctxt)
-{
- /* Disable writeback. */
- ctxt->dst.type = OP_NONE;
- /* only subword offset */
- ctxt->src.val &= (ctxt->dst.bytes << 3) - 1;
-
- emulate_2op_SrcV_nobyte(ctxt, "bt");
- return X86EMUL_CONTINUE;
-}
-
-static int em_bts(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV_nobyte(ctxt, "bts");
- return X86EMUL_CONTINUE;
-}
-
-static int em_btr(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV_nobyte(ctxt, "btr");
- return X86EMUL_CONTINUE;
-}
-
-static int em_btc(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV_nobyte(ctxt, "btc");
- return X86EMUL_CONTINUE;
-}
-
-static int em_bsf(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV_nobyte(ctxt, "bsf");
- return X86EMUL_CONTINUE;
-}
-
-static int em_bsr(struct x86_emulate_ctxt *ctxt)
-{
- emulate_2op_SrcV_nobyte(ctxt, "bsr");
- return X86EMUL_CONTINUE;
-}
-
static int em_cpuid(struct x86_emulate_ctxt *ctxt)
{
u32 eax, ebx, ecx, edx;
@@ -3572,7 +3619,9 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt)
#define EXT(_f, _e) { .flags = ((_f) | RMExt), .u.group = (_e) }
#define G(_f, _g) { .flags = ((_f) | Group | ModRM), .u.group = (_g) }
#define GD(_f, _g) { .flags = ((_f) | GroupDual | ModRM), .u.gdual = (_g) }
+#define E(_f, _e) { .flags = ((_f) | Escape | ModRM), .u.esc = (_e) }
#define I(_f, _e) { .flags = (_f), .u.execute = (_e) }
+#define F(_f, _e) { .flags = (_f) | Fastop, .u.fastop = (_e) }
#define II(_f, _e, _i) \
{ .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i }
#define IIP(_f, _e, _i, _p) \
@@ -3583,12 +3632,13 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt)
#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 F2bv(_f, _e) F((_f) | ByteOp, _e), F(_f, _e)
#define I2bvIP(_f, _e, _i, _p) \
IIP((_f) | ByteOp, _e, _i, _p), IIP(_f, _e, _i, _p)
-#define I6ALU(_f, _e) I2bv((_f) | DstMem | SrcReg | ModRM, _e), \
- I2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e), \
- I2bv(((_f) & ~Lock) | DstAcc | SrcImm, _e)
+#define F6ALU(_f, _e) F2bv((_f) | DstMem | SrcReg | ModRM, _e), \
+ F2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e), \
+ F2bv(((_f) & ~Lock) | DstAcc | SrcImm, _e)
static const struct opcode group7_rm1[] = {
DI(SrcNone | Priv, monitor),
@@ -3614,25 +3664,36 @@ static const struct opcode group7_rm7[] = {
};
static const struct opcode group1[] = {
- I(Lock, em_add),
- I(Lock | PageTable, em_or),
- I(Lock, em_adc),
- I(Lock, em_sbb),
- I(Lock | PageTable, em_and),
- I(Lock, em_sub),
- I(Lock, em_xor),
- I(0, em_cmp),
+ F(Lock, em_add),
+ F(Lock | PageTable, em_or),
+ F(Lock, em_adc),
+ F(Lock, em_sbb),
+ F(Lock | PageTable, em_and),
+ F(Lock, em_sub),
+ F(Lock, em_xor),
+ F(NoWrite, em_cmp),
};
static const struct opcode group1A[] = {
I(DstMem | SrcNone | Mov | Stack, em_pop), N, N, N, N, N, N, N,
};
+static const struct opcode group2[] = {
+ F(DstMem | ModRM, em_rol),
+ F(DstMem | ModRM, em_ror),
+ F(DstMem | ModRM, em_rcl),
+ F(DstMem | ModRM, em_rcr),
+ F(DstMem | ModRM, em_shl),
+ F(DstMem | ModRM, em_shr),
+ F(DstMem | ModRM, em_shl),
+ F(DstMem | ModRM, em_sar),
+};
+
static const struct opcode group3[] = {
- I(DstMem | SrcImm, em_test),
- I(DstMem | SrcImm, em_test),
- I(DstMem | SrcNone | Lock, em_not),
- I(DstMem | SrcNone | Lock, em_neg),
+ F(DstMem | SrcImm | NoWrite, em_test),
+ F(DstMem | SrcImm | NoWrite, em_test),
+ F(DstMem | SrcNone | Lock, em_not),
+ F(DstMem | SrcNone | Lock, em_neg),
I(SrcMem, em_mul_ex),
I(SrcMem, em_imul_ex),
I(SrcMem, em_div_ex),
@@ -3640,14 +3701,14 @@ static const struct opcode group3[] = {
};
static const struct opcode group4[] = {
- I(ByteOp | DstMem | SrcNone | Lock, em_grp45),
- I(ByteOp | DstMem | SrcNone | Lock, em_grp45),
+ F(ByteOp | DstMem | SrcNone | Lock, em_inc),
+ F(ByteOp | DstMem | SrcNone | Lock, em_dec),
N, N, N, N, N, N,
};
static const struct opcode group5[] = {
- I(DstMem | SrcNone | Lock, em_grp45),
- I(DstMem | SrcNone | Lock, em_grp45),
+ F(DstMem | SrcNone | Lock, em_inc),
+ F(DstMem | SrcNone | Lock, em_dec),
I(SrcMem | Stack, em_grp45),
I(SrcMemFAddr | ImplicitOps | Stack, em_call_far),
I(SrcMem | Stack, em_grp45),
@@ -3682,10 +3743,10 @@ static const struct group_dual group7 = { {
static const struct opcode group8[] = {
N, N, N, N,
- I(DstMem | SrcImmByte, em_bt),
- I(DstMem | SrcImmByte | Lock | PageTable, em_bts),
- I(DstMem | SrcImmByte | Lock, em_btr),
- I(DstMem | SrcImmByte | Lock | PageTable, em_btc),
+ F(DstMem | SrcImmByte | NoWrite, em_bt),
+ F(DstMem | SrcImmByte | Lock | PageTable, em_bts),
+ F(DstMem | SrcImmByte | Lock, em_btr),
+ F(DstMem | SrcImmByte | Lock | PageTable, em_btc),
};
static const struct group_dual group9 = { {
@@ -3707,33 +3768,96 @@ static const struct gprefix pfx_vmovntpx = {
I(0, em_mov), N, N, N,
};
+static const struct escape escape_d9 = { {
+ N, N, N, N, N, N, N, I(DstMem, em_fnstcw),
+}, {
+ /* 0xC0 - 0xC7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xC8 - 0xCF */
+ N, N, N, N, N, N, N, N,
+ /* 0xD0 - 0xC7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xD8 - 0xDF */
+ N, N, N, N, N, N, N, N,
+ /* 0xE0 - 0xE7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xE8 - 0xEF */
+ N, N, N, N, N, N, N, N,
+ /* 0xF0 - 0xF7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xF8 - 0xFF */
+ N, N, N, N, N, N, N, N,
+} };
+
+static const struct escape escape_db = { {
+ N, N, N, N, N, N, N, N,
+}, {
+ /* 0xC0 - 0xC7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xC8 - 0xCF */
+ N, N, N, N, N, N, N, N,
+ /* 0xD0 - 0xC7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xD8 - 0xDF */
+ N, N, N, N, N, N, N, N,
+ /* 0xE0 - 0xE7 */
+ N, N, N, I(ImplicitOps, em_fninit), N, N, N, N,
+ /* 0xE8 - 0xEF */
+ N, N, N, N, N, N, N, N,
+ /* 0xF0 - 0xF7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xF8 - 0xFF */
+ N, N, N, N, N, N, N, N,
+} };
+
+static const struct escape escape_dd = { {
+ N, N, N, N, N, N, N, I(DstMem, em_fnstsw),
+}, {
+ /* 0xC0 - 0xC7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xC8 - 0xCF */
+ N, N, N, N, N, N, N, N,
+ /* 0xD0 - 0xC7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xD8 - 0xDF */
+ N, N, N, N, N, N, N, N,
+ /* 0xE0 - 0xE7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xE8 - 0xEF */
+ N, N, N, N, N, N, N, N,
+ /* 0xF0 - 0xF7 */
+ N, N, N, N, N, N, N, N,
+ /* 0xF8 - 0xFF */
+ N, N, N, N, N, N, N, N,
+} };
+
static const struct opcode opcode_table[256] = {
/* 0x00 - 0x07 */
- I6ALU(Lock, em_add),
+ F6ALU(Lock, em_add),
I(ImplicitOps | Stack | No64 | Src2ES, em_push_sreg),
I(ImplicitOps | Stack | No64 | Src2ES, em_pop_sreg),
/* 0x08 - 0x0F */
- I6ALU(Lock | PageTable, em_or),
+ F6ALU(Lock | PageTable, em_or),
I(ImplicitOps | Stack | No64 | Src2CS, em_push_sreg),
N,
/* 0x10 - 0x17 */
- I6ALU(Lock, em_adc),
+ F6ALU(Lock, em_adc),
I(ImplicitOps | Stack | No64 | Src2SS, em_push_sreg),
I(ImplicitOps | Stack | No64 | Src2SS, em_pop_sreg),
/* 0x18 - 0x1F */
- I6ALU(Lock, em_sbb),
+ F6ALU(Lock, em_sbb),
I(ImplicitOps | Stack | No64 | Src2DS, em_push_sreg),
I(ImplicitOps | Stack | No64 | Src2DS, em_pop_sreg),
/* 0x20 - 0x27 */
- I6ALU(Lock | PageTable, em_and), N, N,
+ F6ALU(Lock | PageTable, em_and), N, N,
/* 0x28 - 0x2F */
- I6ALU(Lock, em_sub), N, I(ByteOp | DstAcc | No64, em_das),
+ F6ALU(Lock, em_sub), N, I(ByteOp | DstAcc | No64, em_das),
/* 0x30 - 0x37 */
- I6ALU(Lock, em_xor), N, N,
+ F6ALU(Lock, em_xor), N, N,
/* 0x38 - 0x3F */
- I6ALU(0, em_cmp), N, N,
+ F6ALU(NoWrite, em_cmp), N, N,
/* 0x40 - 0x4F */
- X16(D(DstReg)),
+ X8(F(DstReg, em_inc)), X8(F(DstReg, em_dec)),
/* 0x50 - 0x57 */
X8(I(SrcReg | Stack, em_push)),
/* 0x58 - 0x5F */
@@ -3757,7 +3881,7 @@ static const struct opcode opcode_table[256] = {
G(DstMem | SrcImm, group1),
G(ByteOp | DstMem | SrcImm | No64, group1),
G(DstMem | SrcImmByte, group1),
- I2bv(DstMem | SrcReg | ModRM, em_test),
+ F2bv(DstMem | SrcReg | ModRM | NoWrite, em_test),
I2bv(DstMem | SrcReg | ModRM | Lock | PageTable, em_xchg),
/* 0x88 - 0x8F */
I2bv(DstMem | SrcReg | ModRM | Mov | PageTable, em_mov),
@@ -3777,18 +3901,18 @@ static const struct opcode opcode_table[256] = {
I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov),
I2bv(DstMem | SrcAcc | Mov | MemAbs | PageTable, em_mov),
I2bv(SrcSI | DstDI | Mov | String, em_mov),
- I2bv(SrcSI | DstDI | String, em_cmp),
+ F2bv(SrcSI | DstDI | String | NoWrite, em_cmp),
/* 0xA8 - 0xAF */
- I2bv(DstAcc | SrcImm, em_test),
+ F2bv(DstAcc | SrcImm | NoWrite, em_test),
I2bv(SrcAcc | DstDI | Mov | String, em_mov),
I2bv(SrcSI | DstAcc | Mov | String, em_mov),
- I2bv(SrcAcc | DstDI | String, em_cmp),
+ F2bv(SrcAcc | DstDI | String | NoWrite, em_cmp),
/* 0xB0 - 0xB7 */
X8(I(ByteOp | DstReg | SrcImm | Mov, em_mov)),
/* 0xB8 - 0xBF */
- X8(I(DstReg | SrcImm | Mov, em_mov)),
+ X8(I(DstReg | SrcImm64 | Mov, em_mov)),
/* 0xC0 - 0xC7 */
- D2bv(DstMem | SrcImmByte | ModRM),
+ G(ByteOp | Src2ImmByte, group2), G(Src2ImmByte, group2),
I(ImplicitOps | Stack | SrcImmU16, em_ret_near_imm),
I(ImplicitOps | Stack, em_ret),
I(DstReg | SrcMemFAddr | ModRM | No64 | Src2ES, em_lseg),
@@ -3800,10 +3924,11 @@ static const struct opcode opcode_table[256] = {
D(ImplicitOps), DI(SrcImmByte, intn),
D(ImplicitOps | No64), II(ImplicitOps, em_iret, iret),
/* 0xD0 - 0xD7 */
- D2bv(DstMem | SrcOne | ModRM), D2bv(DstMem | ModRM),
- N, N, N, N,
+ G(Src2One | ByteOp, group2), G(Src2One, group2),
+ G(Src2CL | ByteOp, group2), G(Src2CL, group2),
+ N, I(DstAcc | SrcImmByte | No64, em_aad), N, N,
/* 0xD8 - 0xDF */
- N, N, N, N, N, N, N, N,
+ N, E(0, &escape_d9), N, E(0, &escape_db), N, E(0, &escape_dd), N, N,
/* 0xE0 - 0xE7 */
X3(I(SrcImmByte, em_loop)),
I(SrcImmByte, em_jcxz),
@@ -3870,28 +3995,29 @@ static const struct opcode twobyte_table[256] = {
X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)),
/* 0xA0 - 0xA7 */
I(Stack | Src2FS, em_push_sreg), I(Stack | Src2FS, em_pop_sreg),
- II(ImplicitOps, em_cpuid, cpuid), I(DstMem | SrcReg | ModRM | BitOp, em_bt),
- D(DstMem | SrcReg | Src2ImmByte | ModRM),
- D(DstMem | SrcReg | Src2CL | ModRM), N, N,
+ II(ImplicitOps, em_cpuid, cpuid),
+ F(DstMem | SrcReg | ModRM | BitOp | NoWrite, em_bt),
+ F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shld),
+ F(DstMem | SrcReg | Src2CL | ModRM, em_shld), N, N,
/* 0xA8 - 0xAF */
I(Stack | Src2GS, em_push_sreg), I(Stack | Src2GS, em_pop_sreg),
DI(ImplicitOps, rsm),
- I(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_bts),
- D(DstMem | SrcReg | Src2ImmByte | ModRM),
- D(DstMem | SrcReg | Src2CL | ModRM),
- D(ModRM), I(DstReg | SrcMem | ModRM, em_imul),
+ F(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_bts),
+ F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shrd),
+ F(DstMem | SrcReg | Src2CL | ModRM, em_shrd),
+ D(ModRM), F(DstReg | SrcMem | ModRM, em_imul),
/* 0xB0 - 0xB7 */
I2bv(DstMem | SrcReg | ModRM | Lock | PageTable, em_cmpxchg),
I(DstReg | SrcMemFAddr | ModRM | Src2SS, em_lseg),
- I(DstMem | SrcReg | ModRM | BitOp | Lock, em_btr),
+ F(DstMem | SrcReg | ModRM | BitOp | Lock, em_btr),
I(DstReg | SrcMemFAddr | ModRM | Src2FS, em_lseg),
I(DstReg | SrcMemFAddr | ModRM | Src2GS, em_lseg),
D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
/* 0xB8 - 0xBF */
N, N,
G(BitOp, group8),
- I(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_btc),
- I(DstReg | SrcMem | ModRM, em_bsf), I(DstReg | SrcMem | ModRM, em_bsr),
+ F(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_btc),
+ F(DstReg | SrcMem | ModRM, em_bsf), F(DstReg | SrcMem | ModRM, em_bsr),
D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
/* 0xC0 - 0xC7 */
D2bv(DstMem | SrcReg | ModRM | Lock),
@@ -3950,6 +4076,9 @@ static int decode_imm(struct x86_emulate_ctxt *ctxt, struct operand *op,
case 4:
op->val = insn_fetch(s32, ctxt);
break;
+ case 8:
+ op->val = insn_fetch(s64, ctxt);
+ break;
}
if (!sign_extension) {
switch (op->bytes) {
@@ -4028,6 +4157,9 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op,
case OpImm:
rc = decode_imm(ctxt, op, imm_size(ctxt), true);
break;
+ case OpImm64:
+ rc = decode_imm(ctxt, op, ctxt->op_bytes, true);
+ break;
case OpMem8:
ctxt->memop.bytes = 1;
goto mem_common;
@@ -4222,6 +4354,12 @@ done_prefixes:
case 0xf3: opcode = opcode.u.gprefix->pfx_f3; break;
}
break;
+ case Escape:
+ if (ctxt->modrm > 0xbf)
+ opcode = opcode.u.esc->high[ctxt->modrm - 0xc0];
+ else
+ opcode = opcode.u.esc->op[(ctxt->modrm >> 3) & 7];
+ break;
default:
return EMULATION_FAILED;
}
@@ -4354,6 +4492,16 @@ static void fetch_possible_mmx_operand(struct x86_emulate_ctxt *ctxt,
read_mmx_reg(ctxt, &op->mm_val, op->addr.mm);
}
+static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *))
+{
+ ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF;
+ fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE;
+ asm("push %[flags]; popf; call *%[fastop]; pushf; pop %[flags]\n"
+ : "+a"(ctxt->dst.val), "+b"(ctxt->src.val), [flags]"+D"(flags)
+ : "c"(ctxt->src2.val), [fastop]"S"(fop));
+ ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK);
+ return X86EMUL_CONTINUE;
+}
int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
{
@@ -4483,6 +4631,13 @@ special_insn:
}
if (ctxt->execute) {
+ if (ctxt->d & Fastop) {
+ void (*fop)(struct fastop *) = (void *)ctxt->execute;
+ rc = fastop(ctxt, fop);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ goto writeback;
+ }
rc = ctxt->execute(ctxt);
if (rc != X86EMUL_CONTINUE)
goto done;
@@ -4493,12 +4648,6 @@ special_insn:
goto twobyte_insn;
switch (ctxt->b) {
- case 0x40 ... 0x47: /* inc r16/r32 */
- emulate_1op(ctxt, "inc");
- break;
- case 0x48 ... 0x4f: /* dec r16/r32 */
- emulate_1op(ctxt, "dec");
- break;
case 0x63: /* movsxd */
if (ctxt->mode != X86EMUL_MODE_PROT64)
goto cannot_emulate;
@@ -4523,9 +4672,6 @@ special_insn:
case 8: ctxt->dst.val = (s32)ctxt->dst.val; break;
}
break;
- case 0xc0 ... 0xc1:
- rc = em_grp2(ctxt);
- break;
case 0xcc: /* int3 */
rc = emulate_int(ctxt, 3);
break;
@@ -4536,13 +4682,6 @@ special_insn:
if (ctxt->eflags & EFLG_OF)
rc = emulate_int(ctxt, 4);
break;
- case 0xd0 ... 0xd1: /* Grp2 */
- rc = em_grp2(ctxt);
- break;
- case 0xd2 ... 0xd3: /* Grp2 */
- ctxt->src.val = reg_read(ctxt, VCPU_REGS_RCX);
- rc = em_grp2(ctxt);
- break;
case 0xe9: /* jmp rel */
case 0xeb: /* jmp rel short */
jmp_rel(ctxt, ctxt->src.val);
@@ -4661,14 +4800,6 @@ twobyte_insn:
case 0x90 ... 0x9f: /* setcc r/m8 */
ctxt->dst.val = test_cc(ctxt->b, ctxt->eflags);
break;
- case 0xa4: /* shld imm8, r, r/m */
- case 0xa5: /* shld cl, r, r/m */
- emulate_2op_cl(ctxt, "shld");
- break;
- case 0xac: /* shrd imm8, r, r/m */
- case 0xad: /* shrd cl, r, r/m */
- emulate_2op_cl(ctxt, "shrd");
- break;
case 0xae: /* clflush */
break;
case 0xb6 ... 0xb7: /* movzx */
@@ -4682,7 +4813,7 @@ twobyte_insn:
(s16) ctxt->src.val;
break;
case 0xc0 ... 0xc1: /* xadd */
- emulate_2op_SrcV(ctxt, "add");
+ fastop(ctxt, em_add);
/* Write back the register source. */
ctxt->src.val = ctxt->dst.orig_val;
write_register_operand(&ctxt->src);
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 11300d2fa714..c1d30b2fc9bb 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -122,7 +122,6 @@ static s64 __kpit_elapsed(struct kvm *kvm)
*/
remaining = hrtimer_get_remaining(&ps->timer);
elapsed = ps->period - ktime_to_ns(remaining);
- elapsed = mod_64(elapsed, ps->period);
return elapsed;
}
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 848206df0967..cc31f7c06d3d 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -241,6 +241,8 @@ int kvm_pic_read_irq(struct kvm *kvm)
int irq, irq2, intno;
struct kvm_pic *s = pic_irqchip(kvm);
+ s->output = 0;
+
pic_lock(s);
irq = pic_get_irq(&s->pics[0]);
if (irq >= 0) {
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index 7e06ba1618bd..484bc874688b 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -38,49 +38,81 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
/*
+ * check if there is pending interrupt from
+ * non-APIC source without intack.
+ */
+static int kvm_cpu_has_extint(struct kvm_vcpu *v)
+{
+ if (kvm_apic_accept_pic_intr(v))
+ return pic_irqchip(v->kvm)->output; /* PIC */
+ else
+ return 0;
+}
+
+/*
+ * check if there is injectable interrupt:
+ * when virtual interrupt delivery enabled,
+ * interrupt from apic will handled by hardware,
+ * we don't need to check it here.
+ */
+int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
+{
+ if (!irqchip_in_kernel(v->kvm))
+ return v->arch.interrupt.pending;
+
+ if (kvm_cpu_has_extint(v))
+ return 1;
+
+ if (kvm_apic_vid_enabled(v->kvm))
+ return 0;
+
+ return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
+}
+
+/*
* check if there is pending interrupt without
* intack.
*/
int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
{
- struct kvm_pic *s;
-
if (!irqchip_in_kernel(v->kvm))
return v->arch.interrupt.pending;
- if (kvm_apic_has_interrupt(v) == -1) { /* LAPIC */
- if (kvm_apic_accept_pic_intr(v)) {
- s = pic_irqchip(v->kvm); /* PIC */
- return s->output;
- } else
- return 0;
- }
- return 1;
+ if (kvm_cpu_has_extint(v))
+ return 1;
+
+ return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
}
EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
/*
+ * Read pending interrupt(from non-APIC source)
+ * vector and intack.
+ */
+static int kvm_cpu_get_extint(struct kvm_vcpu *v)
+{
+ if (kvm_cpu_has_extint(v))
+ return kvm_pic_read_irq(v->kvm); /* PIC */
+ return -1;
+}
+
+/*
* Read pending interrupt vector and intack.
*/
int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
{
- struct kvm_pic *s;
int vector;
if (!irqchip_in_kernel(v->kvm))
return v->arch.interrupt.nr;
- vector = kvm_get_apic_interrupt(v); /* APIC */
- if (vector == -1) {
- if (kvm_apic_accept_pic_intr(v)) {
- s = pic_irqchip(v->kvm);
- s->output = 0; /* PIC */
- vector = kvm_pic_read_irq(v->kvm);
- }
- }
- return vector;
+ vector = kvm_cpu_get_extint(v);
+
+ if (kvm_apic_vid_enabled(v->kvm) || vector != -1)
+ return vector; /* PIC */
+
+ return kvm_get_apic_interrupt(v); /* APIC */
}
-EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
{
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 9392f527f107..02b51dd4e4ad 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -140,31 +140,56 @@ static inline int apic_enabled(struct kvm_lapic *apic)
(LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
-static inline int apic_x2apic_mode(struct kvm_lapic *apic)
-{
- return apic->vcpu->arch.apic_base & X2APIC_ENABLE;
-}
-
static inline int kvm_apic_id(struct kvm_lapic *apic)
{
return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
}
-static inline u16 apic_cluster_id(struct kvm_apic_map *map, u32 ldr)
+void kvm_calculate_eoi_exitmap(struct kvm_vcpu *vcpu,
+ struct kvm_lapic_irq *irq,
+ u64 *eoi_exit_bitmap)
{
- u16 cid;
- ldr >>= 32 - map->ldr_bits;
- cid = (ldr >> map->cid_shift) & map->cid_mask;
+ struct kvm_lapic **dst;
+ struct kvm_apic_map *map;
+ unsigned long bitmap = 1;
+ int i;
- BUG_ON(cid >= ARRAY_SIZE(map->logical_map));
+ rcu_read_lock();
+ map = rcu_dereference(vcpu->kvm->arch.apic_map);
- return cid;
-}
+ if (unlikely(!map)) {
+ __set_bit(irq->vector, (unsigned long *)eoi_exit_bitmap);
+ goto out;
+ }
-static inline u16 apic_logical_id(struct kvm_apic_map *map, u32 ldr)
-{
- ldr >>= (32 - map->ldr_bits);
- return ldr & map->lid_mask;
+ if (irq->dest_mode == 0) { /* physical mode */
+ if (irq->delivery_mode == APIC_DM_LOWEST ||
+ irq->dest_id == 0xff) {
+ __set_bit(irq->vector,
+ (unsigned long *)eoi_exit_bitmap);
+ goto out;
+ }
+ dst = &map->phys_map[irq->dest_id & 0xff];
+ } else {
+ u32 mda = irq->dest_id << (32 - map->ldr_bits);
+
+ dst = map->logical_map[apic_cluster_id(map, mda)];
+
+ bitmap = apic_logical_id(map, mda);
+ }
+
+ for_each_set_bit(i, &bitmap, 16) {
+ if (!dst[i])
+ continue;
+ if (dst[i]->vcpu == vcpu) {
+ __set_bit(irq->vector,
+ (unsigned long *)eoi_exit_bitmap);
+ break;
+ }
+ }
+
+out:
+ rcu_read_unlock();
}
static void recalculate_apic_map(struct kvm *kvm)
@@ -230,6 +255,8 @@ out:
if (old)
kfree_rcu(old, rcu);
+
+ kvm_ioapic_make_eoibitmap_request(kvm);
}
static inline void kvm_apic_set_id(struct kvm_lapic *apic, u8 id)
@@ -345,6 +372,10 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic)
{
int result;
+ /*
+ * Note that irr_pending is just a hint. It will be always
+ * true with virtual interrupt delivery enabled.
+ */
if (!apic->irr_pending)
return -1;
@@ -461,6 +492,8 @@ static void pv_eoi_clr_pending(struct kvm_vcpu *vcpu)
static inline int apic_find_highest_isr(struct kvm_lapic *apic)
{
int result;
+
+ /* Note that isr_count is always 1 with vid enabled */
if (!apic->isr_count)
return -1;
if (likely(apic->highest_isr_cache != -1))
@@ -740,6 +773,19 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
return vcpu1->arch.apic_arb_prio - vcpu2->arch.apic_arb_prio;
}
+static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
+{
+ if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
+ kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
+ int trigger_mode;
+ if (apic_test_vector(vector, apic->regs + APIC_TMR))
+ trigger_mode = IOAPIC_LEVEL_TRIG;
+ else
+ trigger_mode = IOAPIC_EDGE_TRIG;
+ kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
+ }
+}
+
static int apic_set_eoi(struct kvm_lapic *apic)
{
int vector = apic_find_highest_isr(apic);
@@ -756,19 +802,26 @@ static int apic_set_eoi(struct kvm_lapic *apic)
apic_clear_isr(vector, apic);
apic_update_ppr(apic);
- if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
- kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
- int trigger_mode;
- if (apic_test_vector(vector, apic->regs + APIC_TMR))
- trigger_mode = IOAPIC_LEVEL_TRIG;
- else
- trigger_mode = IOAPIC_EDGE_TRIG;
- kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
- }
+ kvm_ioapic_send_eoi(apic, vector);
kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
return vector;
}
+/*
+ * this interface assumes a trap-like exit, which has already finished
+ * desired side effect including vISR and vPPR update.
+ */
+void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector)
+{
+ struct kvm_lapic *apic = vcpu->arch.apic;
+
+ trace_kvm_eoi(apic, vector);
+
+ kvm_ioapic_send_eoi(apic, vector);
+ kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
+}
+EXPORT_SYMBOL_GPL(kvm_apic_set_eoi_accelerated);
+
static void apic_send_ipi(struct kvm_lapic *apic)
{
u32 icr_low = kvm_apic_get_reg(apic, APIC_ICR);
@@ -1212,6 +1265,21 @@ void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi);
+/* emulate APIC access in a trap manner */
+void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset)
+{
+ u32 val = 0;
+
+ /* hw has done the conditional check and inst decode */
+ offset &= 0xff0;
+
+ apic_reg_read(vcpu->arch.apic, offset, 4, &val);
+
+ /* TODO: optimize to just emulate side effect w/o one more write */
+ apic_reg_write(vcpu->arch.apic, offset, val);
+}
+EXPORT_SYMBOL_GPL(kvm_apic_write_nodecode);
+
void kvm_free_lapic(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic = vcpu->arch.apic;
@@ -1288,6 +1356,7 @@ u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
{
+ u64 old_value = vcpu->arch.apic_base;
struct kvm_lapic *apic = vcpu->arch.apic;
if (!apic) {
@@ -1309,11 +1378,16 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
value &= ~MSR_IA32_APICBASE_BSP;
vcpu->arch.apic_base = value;
- if (apic_x2apic_mode(apic)) {
- u32 id = kvm_apic_id(apic);
- u32 ldr = ((id >> 4) << 16) | (1 << (id & 0xf));
- kvm_apic_set_ldr(apic, ldr);
+ if ((old_value ^ value) & X2APIC_ENABLE) {
+ if (value & X2APIC_ENABLE) {
+ u32 id = kvm_apic_id(apic);
+ u32 ldr = ((id >> 4) << 16) | (1 << (id & 0xf));
+ kvm_apic_set_ldr(apic, ldr);
+ kvm_x86_ops->set_virtual_x2apic_mode(vcpu, true);
+ } else
+ kvm_x86_ops->set_virtual_x2apic_mode(vcpu, false);
}
+
apic->base_address = apic->vcpu->arch.apic_base &
MSR_IA32_APICBASE_BASE;
@@ -1359,8 +1433,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
}
- apic->irr_pending = false;
- apic->isr_count = 0;
+ apic->irr_pending = kvm_apic_vid_enabled(vcpu->kvm);
+ apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm);
apic->highest_isr_cache = -1;
update_divide_count(apic);
atomic_set(&apic->lapic_timer.pending, 0);
@@ -1575,8 +1649,10 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
update_divide_count(apic);
start_apic_timer(apic);
apic->irr_pending = true;
- apic->isr_count = count_vectors(apic->regs + APIC_ISR);
+ apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm) ?
+ 1 : count_vectors(apic->regs + APIC_ISR);
apic->highest_isr_cache = -1;
+ kvm_x86_ops->hwapic_isr_update(vcpu->kvm, apic_find_highest_isr(apic));
kvm_make_request(KVM_REQ_EVENT, vcpu);
}
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index e5ebf9f3571f..1676d34ddb4e 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -64,6 +64,9 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data);
+void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset);
+void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector);
+
void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
@@ -124,4 +127,35 @@ static inline int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
return kvm_apic_present(vcpu) && kvm_apic_sw_enabled(vcpu->arch.apic);
}
+static inline int apic_x2apic_mode(struct kvm_lapic *apic)
+{
+ return apic->vcpu->arch.apic_base & X2APIC_ENABLE;
+}
+
+static inline bool kvm_apic_vid_enabled(struct kvm *kvm)
+{
+ return kvm_x86_ops->vm_has_apicv(kvm);
+}
+
+static inline u16 apic_cluster_id(struct kvm_apic_map *map, u32 ldr)
+{
+ u16 cid;
+ ldr >>= 32 - map->ldr_bits;
+ cid = (ldr >> map->cid_shift) & map->cid_mask;
+
+ BUG_ON(cid >= ARRAY_SIZE(map->logical_map));
+
+ return cid;
+}
+
+static inline u16 apic_logical_id(struct kvm_apic_map *map, u32 ldr)
+{
+ ldr >>= (32 - map->ldr_bits);
+ return ldr & map->lid_mask;
+}
+
+void kvm_calculate_eoi_exitmap(struct kvm_vcpu *vcpu,
+ struct kvm_lapic_irq *irq,
+ u64 *eoi_bitmap);
+
#endif
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 01d7c2ad05f5..4ed3edbe06bd 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -448,7 +448,8 @@ static bool __check_direct_spte_mmio_pf(u64 spte)
static bool spte_is_locklessly_modifiable(u64 spte)
{
- return !(~spte & (SPTE_HOST_WRITEABLE | SPTE_MMU_WRITEABLE));
+ return (spte & (SPTE_HOST_WRITEABLE | SPTE_MMU_WRITEABLE)) ==
+ (SPTE_HOST_WRITEABLE | SPTE_MMU_WRITEABLE);
}
static bool spte_has_volatile_bits(u64 spte)
@@ -831,8 +832,7 @@ static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn)
if (host_level == PT_PAGE_TABLE_LEVEL)
return host_level;
- max_level = kvm_x86_ops->get_lpage_level() < host_level ?
- kvm_x86_ops->get_lpage_level() : host_level;
+ max_level = min(kvm_x86_ops->get_lpage_level(), host_level);
for (level = PT_DIRECTORY_LEVEL; level <= max_level; ++level)
if (has_wrprotected_page(vcpu->kvm, large_gfn, level))
@@ -1142,7 +1142,7 @@ spte_write_protect(struct kvm *kvm, u64 *sptep, bool *flush, bool pt_protect)
}
static bool __rmap_write_protect(struct kvm *kvm, unsigned long *rmapp,
- int level, bool pt_protect)
+ bool pt_protect)
{
u64 *sptep;
struct rmap_iterator iter;
@@ -1180,7 +1180,7 @@ void kvm_mmu_write_protect_pt_masked(struct kvm *kvm,
while (mask) {
rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
PT_PAGE_TABLE_LEVEL, slot);
- __rmap_write_protect(kvm, rmapp, PT_PAGE_TABLE_LEVEL, false);
+ __rmap_write_protect(kvm, rmapp, false);
/* clear the first set bit */
mask &= mask - 1;
@@ -1199,7 +1199,7 @@ static bool rmap_write_protect(struct kvm *kvm, u64 gfn)
for (i = PT_PAGE_TABLE_LEVEL;
i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
rmapp = __gfn_to_rmap(gfn, i, slot);
- write_protected |= __rmap_write_protect(kvm, rmapp, i, true);
+ write_protected |= __rmap_write_protect(kvm, rmapp, true);
}
return write_protected;
@@ -1460,28 +1460,14 @@ static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, int nr)
percpu_counter_add(&kvm_total_used_mmu_pages, nr);
}
-/*
- * Remove the sp from shadow page cache, after call it,
- * we can not find this sp from the cache, and the shadow
- * page table is still valid.
- * It should be under the protection of mmu lock.
- */
-static void kvm_mmu_isolate_page(struct kvm_mmu_page *sp)
+static void kvm_mmu_free_page(struct kvm_mmu_page *sp)
{
ASSERT(is_empty_shadow_page(sp->spt));
hlist_del(&sp->hash_link);
- if (!sp->role.direct)
- free_page((unsigned long)sp->gfns);
-}
-
-/*
- * Free the shadow page table and the sp, we can do it
- * out of the protection of mmu lock.
- */
-static void kvm_mmu_free_page(struct kvm_mmu_page *sp)
-{
list_del(&sp->link);
free_page((unsigned long)sp->spt);
+ if (!sp->role.direct)
+ free_page((unsigned long)sp->gfns);
kmem_cache_free(mmu_page_header_cache, sp);
}
@@ -1522,7 +1508,6 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache);
set_page_private(virt_to_page(sp->spt), (unsigned long)sp);
list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages);
- bitmap_zero(sp->slot_bitmap, KVM_MEM_SLOTS_NUM);
sp->parent_ptes = 0;
mmu_page_add_parent_pte(vcpu, sp, parent_pte);
kvm_mod_used_mmu_pages(vcpu->kvm, +1);
@@ -1973,9 +1958,9 @@ static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp)
{
u64 spte;
- spte = __pa(sp->spt)
- | PT_PRESENT_MASK | PT_ACCESSED_MASK
- | PT_WRITABLE_MASK | PT_USER_MASK;
+ spte = __pa(sp->spt) | PT_PRESENT_MASK | PT_WRITABLE_MASK |
+ shadow_user_mask | shadow_x_mask | shadow_accessed_mask;
+
mmu_spte_set(sptep, spte);
}
@@ -2126,7 +2111,6 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm,
do {
sp = list_first_entry(invalid_list, struct kvm_mmu_page, link);
WARN_ON(!sp->role.invalid || sp->root_count);
- kvm_mmu_isolate_page(sp);
kvm_mmu_free_page(sp);
} while (!list_empty(invalid_list));
}
@@ -2144,6 +2128,8 @@ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int goal_nr_mmu_pages)
* change the value
*/
+ spin_lock(&kvm->mmu_lock);
+
if (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages) {
while (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages &&
!list_empty(&kvm->arch.active_mmu_pages)) {
@@ -2158,6 +2144,8 @@ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int goal_nr_mmu_pages)
}
kvm->arch.n_max_mmu_pages = goal_nr_mmu_pages;
+
+ spin_unlock(&kvm->mmu_lock);
}
int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
@@ -2183,14 +2171,6 @@ int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
}
EXPORT_SYMBOL_GPL(kvm_mmu_unprotect_page);
-static void page_header_update_slot(struct kvm *kvm, void *pte, gfn_t gfn)
-{
- int slot = memslot_id(kvm, gfn);
- struct kvm_mmu_page *sp = page_header(__pa(pte));
-
- __set_bit(slot, sp->slot_bitmap);
-}
-
/*
* The function is based on mtrr_type_lookup() in
* arch/x86/kernel/cpu/mtrr/generic.c
@@ -2332,9 +2312,8 @@ static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
if (s->role.level != PT_PAGE_TABLE_LEVEL)
return 1;
- if (!need_unsync && !s->unsync) {
+ if (!s->unsync)
need_unsync = true;
- }
}
if (need_unsync)
kvm_unsync_pages(vcpu, gfn);
@@ -2342,8 +2321,7 @@ static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
}
static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
- unsigned pte_access, int user_fault,
- int write_fault, int level,
+ unsigned pte_access, int level,
gfn_t gfn, pfn_t pfn, bool speculative,
bool can_unsync, bool host_writable)
{
@@ -2378,20 +2356,13 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
spte |= (u64)pfn << PAGE_SHIFT;
- if ((pte_access & ACC_WRITE_MASK)
- || (!vcpu->arch.mmu.direct_map && write_fault
- && !is_write_protection(vcpu) && !user_fault)) {
+ if (pte_access & ACC_WRITE_MASK) {
/*
- * There are two cases:
- * - the one is other vcpu creates new sp in the window
- * between mapping_level() and acquiring mmu-lock.
- * - the another case is the new sp is created by itself
- * (page-fault path) when guest uses the target gfn as
- * its page table.
- * Both of these cases can be fixed by allowing guest to
- * retry the access, it will refault, then we can establish
- * the mapping by using small page.
+ * Other vcpu creates new sp in the window between
+ * mapping_level() and acquiring mmu-lock. We can
+ * allow guest to retry the access, the mapping can
+ * be fixed if guest refault.
*/
if (level > PT_PAGE_TABLE_LEVEL &&
has_wrprotected_page(vcpu->kvm, gfn, level))
@@ -2399,19 +2370,6 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
spte |= PT_WRITABLE_MASK | SPTE_MMU_WRITEABLE;
- if (!vcpu->arch.mmu.direct_map
- && !(pte_access & ACC_WRITE_MASK)) {
- spte &= ~PT_USER_MASK;
- /*
- * If we converted a user page to a kernel page,
- * so that the kernel can write to it when cr0.wp=0,
- * then we should prevent the kernel from executing it
- * if SMEP is enabled.
- */
- if (kvm_read_cr4_bits(vcpu, X86_CR4_SMEP))
- spte |= PT64_NX_MASK;
- }
-
/*
* Optimization: for pte sync, if spte was writable the hash
* lookup is unnecessary (and expensive). Write protection
@@ -2441,19 +2399,15 @@ done:
}
static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
- unsigned pt_access, unsigned pte_access,
- int user_fault, int write_fault,
- int *emulate, int level, gfn_t gfn,
- pfn_t pfn, bool speculative,
+ unsigned pte_access, int write_fault, int *emulate,
+ int level, gfn_t gfn, pfn_t pfn, bool speculative,
bool host_writable)
{
int was_rmapped = 0;
int rmap_count;
- pgprintk("%s: spte %llx access %x write_fault %d"
- " user_fault %d gfn %llx\n",
- __func__, *sptep, pt_access,
- write_fault, user_fault, gfn);
+ pgprintk("%s: spte %llx write_fault %d gfn %llx\n", __func__,
+ *sptep, write_fault, gfn);
if (is_rmap_spte(*sptep)) {
/*
@@ -2477,9 +2431,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
was_rmapped = 1;
}
- if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault,
- level, gfn, pfn, speculative, true,
- host_writable)) {
+ if (set_spte(vcpu, sptep, pte_access, level, gfn, pfn, speculative,
+ true, host_writable)) {
if (write_fault)
*emulate = 1;
kvm_mmu_flush_tlb(vcpu);
@@ -2497,7 +2450,6 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
++vcpu->kvm->stat.lpages;
if (is_shadow_present_pte(*sptep)) {
- page_header_update_slot(vcpu->kvm, sptep, gfn);
if (!was_rmapped) {
rmap_count = rmap_add(vcpu, sptep, gfn);
if (rmap_count > RMAP_RECYCLE_THRESHOLD)
@@ -2571,10 +2523,9 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
return -1;
for (i = 0; i < ret; i++, gfn++, start++)
- mmu_set_spte(vcpu, start, ACC_ALL,
- access, 0, 0, NULL,
- sp->role.level, gfn,
- page_to_pfn(pages[i]), true, true);
+ mmu_set_spte(vcpu, start, access, 0, NULL,
+ sp->role.level, gfn, page_to_pfn(pages[i]),
+ true, true);
return 0;
}
@@ -2633,11 +2584,9 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) {
if (iterator.level == level) {
- unsigned pte_access = ACC_ALL;
-
- mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, pte_access,
- 0, write, &emulate,
- level, gfn, pfn, prefault, map_writable);
+ mmu_set_spte(vcpu, iterator.sptep, ACC_ALL,
+ write, &emulate, level, gfn, pfn,
+ prefault, map_writable);
direct_pte_prefetch(vcpu, iterator.sptep);
++vcpu->stat.pf_fixed;
break;
@@ -2652,11 +2601,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
iterator.level - 1,
1, ACC_ALL, iterator.sptep);
- mmu_spte_set(iterator.sptep,
- __pa(sp->spt)
- | PT_PRESENT_MASK | PT_WRITABLE_MASK
- | shadow_user_mask | shadow_x_mask
- | shadow_accessed_mask);
+ link_shadow_page(iterator.sptep, sp);
}
}
return emulate;
@@ -3719,6 +3664,7 @@ int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context)
else
r = paging32_init_context(vcpu, context);
+ vcpu->arch.mmu.base_role.nxe = is_nx(vcpu);
vcpu->arch.mmu.base_role.cr4_pae = !!is_pae(vcpu);
vcpu->arch.mmu.base_role.cr0_wp = is_write_protection(vcpu);
vcpu->arch.mmu.base_role.smep_andnot_wp
@@ -3885,7 +3831,7 @@ static u64 mmu_pte_write_fetch_gpte(struct kvm_vcpu *vcpu, gpa_t *gpa,
/* Handle a 32-bit guest writing two halves of a 64-bit gpte */
*gpa &= ~(gpa_t)7;
*bytes = 8;
- r = kvm_read_guest(vcpu->kvm, *gpa, &gentry, min(*bytes, 8));
+ r = kvm_read_guest(vcpu->kvm, *gpa, &gentry, 8);
if (r)
gentry = 0;
new = (const u8 *)&gentry;
@@ -4039,7 +3985,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
!((sp->role.word ^ vcpu->arch.mmu.base_role.word)
& mask.word) && rmap_can_add(vcpu))
mmu_pte_write_new_pte(vcpu, sp, spte, &gentry);
- if (!remote_flush && need_remote_flush(entry, *spte))
+ if (need_remote_flush(entry, *spte))
remote_flush = true;
++spte;
}
@@ -4198,26 +4144,36 @@ int kvm_mmu_setup(struct kvm_vcpu *vcpu)
void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
{
- struct kvm_mmu_page *sp;
- bool flush = false;
+ struct kvm_memory_slot *memslot;
+ gfn_t last_gfn;
+ int i;
- list_for_each_entry(sp, &kvm->arch.active_mmu_pages, link) {
- int i;
- u64 *pt;
+ memslot = id_to_memslot(kvm->memslots, slot);
+ last_gfn = memslot->base_gfn + memslot->npages - 1;
- if (!test_bit(slot, sp->slot_bitmap))
- continue;
+ spin_lock(&kvm->mmu_lock);
- pt = sp->spt;
- for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
- if (!is_shadow_present_pte(pt[i]) ||
- !is_last_spte(pt[i], sp->role.level))
- continue;
+ for (i = PT_PAGE_TABLE_LEVEL;
+ i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
+ unsigned long *rmapp;
+ unsigned long last_index, index;
- spte_write_protect(kvm, &pt[i], &flush, false);
+ rmapp = memslot->arch.rmap[i - PT_PAGE_TABLE_LEVEL];
+ last_index = gfn_to_index(last_gfn, memslot->base_gfn, i);
+
+ for (index = 0; index <= last_index; ++index, ++rmapp) {
+ if (*rmapp)
+ __rmap_write_protect(kvm, rmapp, false);
+
+ if (need_resched() || spin_needbreak(&kvm->mmu_lock)) {
+ kvm_flush_remote_tlbs(kvm);
+ cond_resched_lock(&kvm->mmu_lock);
+ }
}
}
+
kvm_flush_remote_tlbs(kvm);
+ spin_unlock(&kvm->mmu_lock);
}
void kvm_mmu_zap_all(struct kvm *kvm)
diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
index cd6e98333ba3..b8f6172f4174 100644
--- a/arch/x86/kvm/mmutrace.h
+++ b/arch/x86/kvm/mmutrace.h
@@ -195,12 +195,6 @@ DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_prepare_zap_page,
TP_ARGS(sp)
);
-DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_delay_free_pages,
- TP_PROTO(struct kvm_mmu_page *sp),
-
- TP_ARGS(sp)
-);
-
TRACE_EVENT(
mark_mmio_spte,
TP_PROTO(u64 *sptep, gfn_t gfn, unsigned access),
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 891eb6d93b8b..105dd5bd550e 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -151,7 +151,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
pt_element_t pte;
pt_element_t __user *uninitialized_var(ptep_user);
gfn_t table_gfn;
- unsigned index, pt_access, pte_access, accessed_dirty, shift;
+ unsigned index, pt_access, pte_access, accessed_dirty;
gpa_t pte_gpa;
int offset;
const int write_fault = access & PFERR_WRITE_MASK;
@@ -249,16 +249,12 @@ retry_walk:
if (!write_fault)
protect_clean_gpte(&pte_access, pte);
-
- /*
- * On a write fault, fold the dirty bit into accessed_dirty by shifting it one
- * place right.
- *
- * On a read fault, do nothing.
- */
- shift = write_fault >> ilog2(PFERR_WRITE_MASK);
- shift *= PT_DIRTY_SHIFT - PT_ACCESSED_SHIFT;
- accessed_dirty &= pte >> shift;
+ else
+ /*
+ * On a write fault, fold the dirty bit into accessed_dirty by
+ * shifting it one place right.
+ */
+ accessed_dirty &= pte >> (PT_DIRTY_SHIFT - PT_ACCESSED_SHIFT);
if (unlikely(!accessed_dirty)) {
ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, write_fault);
@@ -330,8 +326,8 @@ FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
* we call mmu_set_spte() with host_writable = true because
* pte_prefetch_gfn_to_pfn always gets a writable pfn.
*/
- mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
- NULL, PT_PAGE_TABLE_LEVEL, gfn, pfn, true, true);
+ mmu_set_spte(vcpu, spte, pte_access, 0, NULL, PT_PAGE_TABLE_LEVEL,
+ gfn, pfn, true, true);
return true;
}
@@ -405,7 +401,7 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
*/
static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
struct guest_walker *gw,
- int user_fault, int write_fault, int hlevel,
+ int write_fault, int hlevel,
pfn_t pfn, bool map_writable, bool prefault)
{
struct kvm_mmu_page *sp = NULL;
@@ -413,9 +409,6 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
unsigned direct_access, access = gw->pt_access;
int top_level, emulate = 0;
- if (!is_present_gpte(gw->ptes[gw->level - 1]))
- return 0;
-
direct_access = gw->pte_access;
top_level = vcpu->arch.mmu.root_level;
@@ -477,9 +470,8 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
}
clear_sp_write_flooding_count(it.sptep);
- mmu_set_spte(vcpu, it.sptep, access, gw->pte_access,
- user_fault, write_fault, &emulate, it.level,
- gw->gfn, pfn, prefault, map_writable);
+ mmu_set_spte(vcpu, it.sptep, gw->pte_access, write_fault, &emulate,
+ it.level, gw->gfn, pfn, prefault, map_writable);
FNAME(pte_prefetch)(vcpu, gw, it.sptep);
return emulate;
@@ -491,6 +483,46 @@ out_gpte_changed:
return 0;
}
+ /*
+ * To see whether the mapped gfn can write its page table in the current
+ * mapping.
+ *
+ * It is the helper function of FNAME(page_fault). When guest uses large page
+ * size to map the writable gfn which is used as current page table, we should
+ * force kvm to use small page size to map it because new shadow page will be
+ * created when kvm establishes shadow page table that stop kvm using large
+ * page size. Do it early can avoid unnecessary #PF and emulation.
+ *
+ * @write_fault_to_shadow_pgtable will return true if the fault gfn is
+ * currently used as its page table.
+ *
+ * Note: the PDPT page table is not checked for PAE-32 bit guest. It is ok
+ * since the PDPT is always shadowed, that means, we can not use large page
+ * size to map the gfn which is used as PDPT.
+ */
+static bool
+FNAME(is_self_change_mapping)(struct kvm_vcpu *vcpu,
+ struct guest_walker *walker, int user_fault,
+ bool *write_fault_to_shadow_pgtable)
+{
+ int level;
+ gfn_t mask = ~(KVM_PAGES_PER_HPAGE(walker->level) - 1);
+ bool self_changed = false;
+
+ if (!(walker->pte_access & ACC_WRITE_MASK ||
+ (!is_write_protection(vcpu) && !user_fault)))
+ return false;
+
+ for (level = walker->level; level <= walker->max_level; level++) {
+ gfn_t gfn = walker->gfn ^ walker->table_gfn[level - 1];
+
+ self_changed |= !(gfn & mask);
+ *write_fault_to_shadow_pgtable |= !gfn;
+ }
+
+ return self_changed;
+}
+
/*
* Page fault handler. There are several causes for a page fault:
* - there is no shadow pte for the guest pte
@@ -516,7 +548,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
int level = PT_PAGE_TABLE_LEVEL;
int force_pt_level;
unsigned long mmu_seq;
- bool map_writable;
+ bool map_writable, is_self_change_mapping;
pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
@@ -544,8 +576,14 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
return 0;
}
+ vcpu->arch.write_fault_to_shadow_pgtable = false;
+
+ is_self_change_mapping = FNAME(is_self_change_mapping)(vcpu,
+ &walker, user_fault, &vcpu->arch.write_fault_to_shadow_pgtable);
+
if (walker.level >= PT_DIRECTORY_LEVEL)
- force_pt_level = mapping_level_dirty_bitmap(vcpu, walker.gfn);
+ force_pt_level = mapping_level_dirty_bitmap(vcpu, walker.gfn)
+ || is_self_change_mapping;
else
force_pt_level = 1;
if (!force_pt_level) {
@@ -564,6 +602,26 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
walker.gfn, pfn, walker.pte_access, &r))
return r;
+ /*
+ * Do not change pte_access if the pfn is a mmio page, otherwise
+ * we will cache the incorrect access into mmio spte.
+ */
+ if (write_fault && !(walker.pte_access & ACC_WRITE_MASK) &&
+ !is_write_protection(vcpu) && !user_fault &&
+ !is_noslot_pfn(pfn)) {
+ walker.pte_access |= ACC_WRITE_MASK;
+ walker.pte_access &= ~ACC_USER_MASK;
+
+ /*
+ * If we converted a user page to a kernel page,
+ * so that the kernel can write to it when cr0.wp=0,
+ * then we should prevent the kernel from executing it
+ * if SMEP is enabled.
+ */
+ if (kvm_read_cr4_bits(vcpu, X86_CR4_SMEP))
+ walker.pte_access &= ~ACC_EXEC_MASK;
+ }
+
spin_lock(&vcpu->kvm->mmu_lock);
if (mmu_notifier_retry(vcpu->kvm, mmu_seq))
goto out_unlock;
@@ -572,7 +630,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
kvm_mmu_free_some_pages(vcpu);
if (!force_pt_level)
transparent_hugepage_adjust(vcpu, &walker.gfn, &pfn, &level);
- r = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
+ r = FNAME(fetch)(vcpu, addr, &walker, write_fault,
level, pfn, map_writable, prefault);
++vcpu->stat.pf_fixed;
kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT);
@@ -747,7 +805,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
host_writable = sp->spt[i] & SPTE_HOST_WRITEABLE;
- set_spte(vcpu, &sp->spt[i], pte_access, 0, 0,
+ set_spte(vcpu, &sp->spt[i], pte_access,
PT_PAGE_TABLE_LEVEL, gfn,
spte_to_pfn(sp->spt[i]), true, false,
host_writable);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index d29d3cd1c156..e1b1ce21bc00 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3571,6 +3571,26 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
set_cr_intercept(svm, INTERCEPT_CR8_WRITE);
}
+static void svm_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
+{
+ return;
+}
+
+static int svm_vm_has_apicv(struct kvm *kvm)
+{
+ return 0;
+}
+
+static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+{
+ return;
+}
+
+static void svm_hwapic_isr_update(struct kvm *kvm, int isr)
+{
+ return;
+}
+
static int svm_nmi_allowed(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -4290,6 +4310,10 @@ static struct kvm_x86_ops svm_x86_ops = {
.enable_nmi_window = enable_nmi_window,
.enable_irq_window = enable_irq_window,
.update_cr8_intercept = update_cr8_intercept,
+ .set_virtual_x2apic_mode = svm_set_virtual_x2apic_mode,
+ .vm_has_apicv = svm_vm_has_apicv,
+ .load_eoi_exitmap = svm_load_eoi_exitmap,
+ .hwapic_isr_update = svm_hwapic_isr_update,
.set_tss_addr = svm_set_tss_addr,
.get_tdp_level = get_npt_level,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 9120ae1901e4..6667042714cc 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -84,6 +84,8 @@ module_param(vmm_exclusive, bool, S_IRUGO);
static bool __read_mostly fasteoi = 1;
module_param(fasteoi, bool, S_IRUGO);
+static bool __read_mostly enable_apicv_reg_vid;
+
/*
* If nested=1, nested virtualization is supported, i.e., guests may use
* VMX and be a hypervisor for its own guests. If nested=0, guests may not
@@ -92,12 +94,8 @@ module_param(fasteoi, bool, S_IRUGO);
static bool __read_mostly nested = 0;
module_param(nested, bool, S_IRUGO);
-#define KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST \
- (X86_CR0_WP | X86_CR0_NE | X86_CR0_NW | X86_CR0_CD)
-#define KVM_GUEST_CR0_MASK \
- (KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE)
-#define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST \
- (X86_CR0_WP | X86_CR0_NE)
+#define KVM_GUEST_CR0_MASK (X86_CR0_NW | X86_CR0_CD)
+#define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST (X86_CR0_WP | X86_CR0_NE)
#define KVM_VM_CR0_ALWAYS_ON \
(KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE)
#define KVM_CR4_GUEST_OWNED_BITS \
@@ -624,6 +622,8 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg);
static void vmx_get_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg);
+static bool guest_state_valid(struct kvm_vcpu *vcpu);
+static u32 vmx_segment_access_rights(struct kvm_segment *var);
static DEFINE_PER_CPU(struct vmcs *, vmxarea);
static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
@@ -638,6 +638,8 @@ static unsigned long *vmx_io_bitmap_a;
static unsigned long *vmx_io_bitmap_b;
static unsigned long *vmx_msr_bitmap_legacy;
static unsigned long *vmx_msr_bitmap_longmode;
+static unsigned long *vmx_msr_bitmap_legacy_x2apic;
+static unsigned long *vmx_msr_bitmap_longmode_x2apic;
static bool cpu_has_load_ia32_efer;
static bool cpu_has_load_perf_global_ctrl;
@@ -762,6 +764,24 @@ static inline bool cpu_has_vmx_virtualize_apic_accesses(void)
SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
}
+static inline bool cpu_has_vmx_virtualize_x2apic_mode(void)
+{
+ return vmcs_config.cpu_based_2nd_exec_ctrl &
+ SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
+}
+
+static inline bool cpu_has_vmx_apic_register_virt(void)
+{
+ return vmcs_config.cpu_based_2nd_exec_ctrl &
+ SECONDARY_EXEC_APIC_REGISTER_VIRT;
+}
+
+static inline bool cpu_has_vmx_virtual_intr_delivery(void)
+{
+ return vmcs_config.cpu_based_2nd_exec_ctrl &
+ SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY;
+}
+
static inline bool cpu_has_vmx_flexpriority(void)
{
return cpu_has_vmx_tpr_shadow() &&
@@ -1694,7 +1714,6 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
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;
@@ -1820,6 +1839,25 @@ static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
vmx->guest_msrs[from] = tmp;
}
+static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
+{
+ unsigned long *msr_bitmap;
+
+ if (irqchip_in_kernel(vcpu->kvm) && apic_x2apic_mode(vcpu->arch.apic)) {
+ if (is_long_mode(vcpu))
+ msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
+ else
+ msr_bitmap = vmx_msr_bitmap_legacy_x2apic;
+ } else {
+ if (is_long_mode(vcpu))
+ msr_bitmap = vmx_msr_bitmap_longmode;
+ else
+ msr_bitmap = vmx_msr_bitmap_legacy;
+ }
+
+ vmcs_write64(MSR_BITMAP, __pa(msr_bitmap));
+}
+
/*
* Set up the vmcs to automatically save and restore system
* msrs. Don't touch the 64-bit msrs if the guest is in legacy
@@ -1828,7 +1866,6 @@ static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
static void setup_msrs(struct vcpu_vmx *vmx)
{
int save_nmsrs, index;
- unsigned long *msr_bitmap;
save_nmsrs = 0;
#ifdef CONFIG_X86_64
@@ -1860,14 +1897,8 @@ static void setup_msrs(struct vcpu_vmx *vmx)
vmx->save_nmsrs = save_nmsrs;
- if (cpu_has_vmx_msr_bitmap()) {
- if (is_long_mode(&vmx->vcpu))
- msr_bitmap = vmx_msr_bitmap_longmode;
- else
- msr_bitmap = vmx_msr_bitmap_legacy;
-
- vmcs_write64(MSR_BITMAP, __pa(msr_bitmap));
- }
+ if (cpu_has_vmx_msr_bitmap())
+ vmx_set_msr_bitmap(&vmx->vcpu);
}
/*
@@ -2533,13 +2564,16 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) {
min2 = 0;
opt2 = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
+ SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE |
SECONDARY_EXEC_WBINVD_EXITING |
SECONDARY_EXEC_ENABLE_VPID |
SECONDARY_EXEC_ENABLE_EPT |
SECONDARY_EXEC_UNRESTRICTED_GUEST |
SECONDARY_EXEC_PAUSE_LOOP_EXITING |
SECONDARY_EXEC_RDTSCP |
- SECONDARY_EXEC_ENABLE_INVPCID;
+ SECONDARY_EXEC_ENABLE_INVPCID |
+ SECONDARY_EXEC_APIC_REGISTER_VIRT |
+ SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY;
if (adjust_vmx_controls(min2, opt2,
MSR_IA32_VMX_PROCBASED_CTLS2,
&_cpu_based_2nd_exec_control) < 0)
@@ -2550,6 +2584,13 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES))
_cpu_based_exec_control &= ~CPU_BASED_TPR_SHADOW;
#endif
+
+ if (!(_cpu_based_exec_control & CPU_BASED_TPR_SHADOW))
+ _cpu_based_2nd_exec_control &= ~(
+ SECONDARY_EXEC_APIC_REGISTER_VIRT |
+ SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE |
+ SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
+
if (_cpu_based_2nd_exec_control & SECONDARY_EXEC_ENABLE_EPT) {
/* CR3 accesses and invlpg don't need to cause VM Exits when EPT
enabled */
@@ -2747,6 +2788,15 @@ static __init int hardware_setup(void)
if (!cpu_has_vmx_ple())
ple_gap = 0;
+ if (!cpu_has_vmx_apic_register_virt() ||
+ !cpu_has_vmx_virtual_intr_delivery())
+ enable_apicv_reg_vid = 0;
+
+ if (enable_apicv_reg_vid)
+ kvm_x86_ops->update_cr8_intercept = NULL;
+ else
+ kvm_x86_ops->hwapic_irr_update = NULL;
+
if (nested)
nested_vmx_setup_ctls_msrs();
@@ -2758,18 +2808,28 @@ static __exit void hardware_unsetup(void)
free_kvm_area();
}
-static void fix_pmode_dataseg(struct kvm_vcpu *vcpu, int seg, struct kvm_segment *save)
+static bool emulation_required(struct kvm_vcpu *vcpu)
{
- const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
- struct kvm_segment tmp = *save;
+ return emulate_invalid_guest_state && !guest_state_valid(vcpu);
+}
- if (!(vmcs_readl(sf->base) == tmp.base && tmp.s)) {
- tmp.base = vmcs_readl(sf->base);
- tmp.selector = vmcs_read16(sf->selector);
- tmp.dpl = tmp.selector & SELECTOR_RPL_MASK;
- tmp.s = 1;
+static void fix_pmode_seg(struct kvm_vcpu *vcpu, int seg,
+ struct kvm_segment *save)
+{
+ if (!emulate_invalid_guest_state) {
+ /*
+ * CS and SS RPL should be equal during guest entry according
+ * to VMX spec, but in reality it is not always so. Since vcpu
+ * is in the middle of the transition from real mode to
+ * protected mode it is safe to assume that RPL 0 is a good
+ * default value.
+ */
+ if (seg == VCPU_SREG_CS || seg == VCPU_SREG_SS)
+ save->selector &= ~SELECTOR_RPL_MASK;
+ save->dpl = save->selector & SELECTOR_RPL_MASK;
+ save->s = 1;
}
- vmx_set_segment(vcpu, &tmp, seg);
+ vmx_set_segment(vcpu, save, seg);
}
static void enter_pmode(struct kvm_vcpu *vcpu)
@@ -2777,7 +2837,17 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
unsigned long flags;
struct vcpu_vmx *vmx = to_vmx(vcpu);
- vmx->emulation_required = 1;
+ /*
+ * Update real mode segment cache. It may be not up-to-date if sement
+ * register was written while vcpu was in a guest mode.
+ */
+ vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_ES], VCPU_SREG_ES);
+ vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_DS], VCPU_SREG_DS);
+ vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_FS], VCPU_SREG_FS);
+ vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_GS], VCPU_SREG_GS);
+ vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_SS], VCPU_SREG_SS);
+ vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_CS], VCPU_SREG_CS);
+
vmx->rmode.vm86_active = 0;
vmx_segment_cache_clear(vmx);
@@ -2794,22 +2864,16 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
update_exception_bitmap(vcpu);
- if (emulate_invalid_guest_state)
- return;
-
- fix_pmode_dataseg(vcpu, VCPU_SREG_ES, &vmx->rmode.segs[VCPU_SREG_ES]);
- fix_pmode_dataseg(vcpu, VCPU_SREG_DS, &vmx->rmode.segs[VCPU_SREG_DS]);
- fix_pmode_dataseg(vcpu, VCPU_SREG_FS, &vmx->rmode.segs[VCPU_SREG_FS]);
- fix_pmode_dataseg(vcpu, VCPU_SREG_GS, &vmx->rmode.segs[VCPU_SREG_GS]);
-
- vmx_segment_cache_clear(vmx);
+ fix_pmode_seg(vcpu, VCPU_SREG_CS, &vmx->rmode.segs[VCPU_SREG_CS]);
+ fix_pmode_seg(vcpu, VCPU_SREG_SS, &vmx->rmode.segs[VCPU_SREG_SS]);
+ fix_pmode_seg(vcpu, VCPU_SREG_ES, &vmx->rmode.segs[VCPU_SREG_ES]);
+ fix_pmode_seg(vcpu, VCPU_SREG_DS, &vmx->rmode.segs[VCPU_SREG_DS]);
+ fix_pmode_seg(vcpu, VCPU_SREG_FS, &vmx->rmode.segs[VCPU_SREG_FS]);
+ fix_pmode_seg(vcpu, VCPU_SREG_GS, &vmx->rmode.segs[VCPU_SREG_GS]);
- vmcs_write16(GUEST_SS_SELECTOR, 0);
- vmcs_write32(GUEST_SS_AR_BYTES, 0x93);
-
- vmcs_write16(GUEST_CS_SELECTOR,
- vmcs_read16(GUEST_CS_SELECTOR) & ~SELECTOR_RPL_MASK);
- vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
+ /* CPL is always 0 when CPU enters protected mode */
+ __set_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
+ vmx->cpl = 0;
}
static gva_t rmode_tss_base(struct kvm *kvm)
@@ -2831,36 +2895,51 @@ static gva_t rmode_tss_base(struct kvm *kvm)
static void fix_rmode_seg(int seg, struct kvm_segment *save)
{
const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
-
- vmcs_write16(sf->selector, save->base >> 4);
- vmcs_write32(sf->base, save->base & 0xffff0);
- vmcs_write32(sf->limit, 0xffff);
- vmcs_write32(sf->ar_bytes, 0xf3);
- if (save->base & 0xf)
- printk_once(KERN_WARNING "kvm: segment base is not paragraph"
- " aligned when entering protected mode (seg=%d)",
- seg);
+ struct kvm_segment var = *save;
+
+ var.dpl = 0x3;
+ if (seg == VCPU_SREG_CS)
+ var.type = 0x3;
+
+ if (!emulate_invalid_guest_state) {
+ var.selector = var.base >> 4;
+ var.base = var.base & 0xffff0;
+ var.limit = 0xffff;
+ var.g = 0;
+ var.db = 0;
+ var.present = 1;
+ var.s = 1;
+ var.l = 0;
+ var.unusable = 0;
+ var.type = 0x3;
+ var.avl = 0;
+ if (save->base & 0xf)
+ printk_once(KERN_WARNING "kvm: segment base is not "
+ "paragraph aligned when entering "
+ "protected mode (seg=%d)", seg);
+ }
+
+ vmcs_write16(sf->selector, var.selector);
+ vmcs_write32(sf->base, var.base);
+ vmcs_write32(sf->limit, var.limit);
+ vmcs_write32(sf->ar_bytes, vmx_segment_access_rights(&var));
}
static void enter_rmode(struct kvm_vcpu *vcpu)
{
unsigned long flags;
struct vcpu_vmx *vmx = to_vmx(vcpu);
- struct kvm_segment var;
-
- if (enable_unrestricted_guest)
- return;
vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_TR], VCPU_SREG_TR);
vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_ES], VCPU_SREG_ES);
vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_DS], VCPU_SREG_DS);
vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_FS], VCPU_SREG_FS);
vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_GS], VCPU_SREG_GS);
+ vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_SS], VCPU_SREG_SS);
+ vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_CS], VCPU_SREG_CS);
- vmx->emulation_required = 1;
vmx->rmode.vm86_active = 1;
-
/*
* Very old userspace does not call KVM_SET_TSS_ADDR before entering
* vcpu. Call it here with phys address pointing 16M below 4G.
@@ -2888,28 +2967,13 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME);
update_exception_bitmap(vcpu);
- if (emulate_invalid_guest_state)
- goto continue_rmode;
-
- vmx_get_segment(vcpu, &var, VCPU_SREG_SS);
- vmx_set_segment(vcpu, &var, VCPU_SREG_SS);
-
- vmx_get_segment(vcpu, &var, VCPU_SREG_CS);
- vmx_set_segment(vcpu, &var, VCPU_SREG_CS);
-
- vmx_get_segment(vcpu, &var, VCPU_SREG_ES);
- vmx_set_segment(vcpu, &var, VCPU_SREG_ES);
-
- vmx_get_segment(vcpu, &var, VCPU_SREG_DS);
- vmx_set_segment(vcpu, &var, VCPU_SREG_DS);
+ fix_rmode_seg(VCPU_SREG_SS, &vmx->rmode.segs[VCPU_SREG_SS]);
+ fix_rmode_seg(VCPU_SREG_CS, &vmx->rmode.segs[VCPU_SREG_CS]);
+ fix_rmode_seg(VCPU_SREG_ES, &vmx->rmode.segs[VCPU_SREG_ES]);
+ fix_rmode_seg(VCPU_SREG_DS, &vmx->rmode.segs[VCPU_SREG_DS]);
+ fix_rmode_seg(VCPU_SREG_GS, &vmx->rmode.segs[VCPU_SREG_GS]);
+ fix_rmode_seg(VCPU_SREG_FS, &vmx->rmode.segs[VCPU_SREG_FS]);
- vmx_get_segment(vcpu, &var, VCPU_SREG_GS);
- vmx_set_segment(vcpu, &var, VCPU_SREG_GS);
-
- vmx_get_segment(vcpu, &var, VCPU_SREG_FS);
- vmx_set_segment(vcpu, &var, VCPU_SREG_FS);
-
-continue_rmode:
kvm_mmu_reset_context(vcpu);
}
@@ -3068,17 +3132,18 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
struct vcpu_vmx *vmx = to_vmx(vcpu);
unsigned long hw_cr0;
+ hw_cr0 = (cr0 & ~KVM_GUEST_CR0_MASK);
if (enable_unrestricted_guest)
- hw_cr0 = (cr0 & ~KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST)
- | KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST;
- else
- hw_cr0 = (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON;
+ hw_cr0 |= KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST;
+ else {
+ hw_cr0 |= KVM_VM_CR0_ALWAYS_ON;
- if (vmx->rmode.vm86_active && (cr0 & X86_CR0_PE))
- enter_pmode(vcpu);
+ if (vmx->rmode.vm86_active && (cr0 & X86_CR0_PE))
+ enter_pmode(vcpu);
- if (!vmx->rmode.vm86_active && !(cr0 & X86_CR0_PE))
- enter_rmode(vcpu);
+ if (!vmx->rmode.vm86_active && !(cr0 & X86_CR0_PE))
+ enter_rmode(vcpu);
+ }
#ifdef CONFIG_X86_64
if (vcpu->arch.efer & EFER_LME) {
@@ -3098,7 +3163,9 @@ 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);
+
+ /* depends on vcpu->arch.cr0 to be set to a new value */
+ vmx->emulation_required = emulation_required(vcpu);
}
static u64 construct_eptp(unsigned long root_hpa)
@@ -3155,6 +3222,14 @@ static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
if (!is_paging(vcpu)) {
hw_cr4 &= ~X86_CR4_PAE;
hw_cr4 |= X86_CR4_PSE;
+ /*
+ * SMEP is disabled if CPU is in non-paging mode in
+ * hardware. However KVM always uses paging mode to
+ * emulate guest non-paging mode with TDP.
+ * To emulate this behavior, SMEP needs to be manually
+ * disabled when guest switches to non-paging mode.
+ */
+ hw_cr4 &= ~X86_CR4_SMEP;
} else if (!(cr4 & X86_CR4_PAE)) {
hw_cr4 &= ~X86_CR4_PAE;
}
@@ -3171,10 +3246,7 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
struct vcpu_vmx *vmx = to_vmx(vcpu);
u32 ar;
- if (vmx->rmode.vm86_active
- && (seg == VCPU_SREG_TR || seg == VCPU_SREG_ES
- || seg == VCPU_SREG_DS || seg == VCPU_SREG_FS
- || seg == VCPU_SREG_GS)) {
+ if (vmx->rmode.vm86_active && seg != VCPU_SREG_LDTR) {
*var = vmx->rmode.segs[seg];
if (seg == VCPU_SREG_TR
|| var->selector == vmx_read_guest_seg_selector(vmx, seg))
@@ -3187,8 +3259,6 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
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);
- if ((ar & AR_UNUSABLE_MASK) && !emulate_invalid_guest_state)
- ar = 0;
var->type = ar & 15;
var->s = (ar >> 4) & 1;
var->dpl = (ar >> 5) & 3;
@@ -3211,8 +3281,10 @@ static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
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)
{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
if (!is_protmode(vcpu))
return 0;
@@ -3220,24 +3292,9 @@ static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
&& (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086 */
return 3;
- return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;
-}
-
-static int vmx_get_cpl(struct kvm_vcpu *vcpu)
-{
- struct vcpu_vmx *vmx = to_vmx(vcpu);
-
- /*
- * If we enter real mode with cs.sel & 3 != 0, the normal CPL calculations
- * fail; use the cache instead.
- */
- if (unlikely(vmx->emulation_required && emulate_invalid_guest_state)) {
- return vmx->cpl;
- }
-
if (!test_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail)) {
__set_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
- vmx->cpl = __vmx_get_cpl(vcpu);
+ vmx->cpl = vmx_read_guest_seg_selector(vmx, VCPU_SREG_CS) & 3;
}
return vmx->cpl;
@@ -3269,28 +3326,23 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
- u32 ar;
vmx_segment_cache_clear(vmx);
+ if (seg == VCPU_SREG_CS)
+ __clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
- if (vmx->rmode.vm86_active && seg == VCPU_SREG_TR) {
- vmcs_write16(sf->selector, var->selector);
- vmx->rmode.segs[VCPU_SREG_TR] = *var;
- return;
+ if (vmx->rmode.vm86_active && seg != VCPU_SREG_LDTR) {
+ vmx->rmode.segs[seg] = *var;
+ if (seg == VCPU_SREG_TR)
+ vmcs_write16(sf->selector, var->selector);
+ else if (var->s)
+ fix_rmode_seg(seg, &vmx->rmode.segs[seg]);
+ goto out;
}
+
vmcs_writel(sf->base, var->base);
vmcs_write32(sf->limit, var->limit);
vmcs_write16(sf->selector, var->selector);
- if (vmx->rmode.vm86_active && var->s) {
- vmx->rmode.segs[seg] = *var;
- /*
- * Hack real-mode segments into vm86 compatibility.
- */
- if (var->base == 0xffff0000 && var->selector == 0xf000)
- vmcs_writel(sf->base, 0xf0000);
- ar = 0xf3;
- } else
- ar = vmx_segment_access_rights(var);
/*
* Fix the "Accessed" bit in AR field of segment registers for older
@@ -3304,42 +3356,12 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
* kvm hack.
*/
if (enable_unrestricted_guest && (seg != VCPU_SREG_LDTR))
- ar |= 0x1; /* Accessed */
+ var->type |= 0x1; /* Accessed */
- vmcs_write32(sf->ar_bytes, ar);
- __clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
+ vmcs_write32(sf->ar_bytes, vmx_segment_access_rights(var));
- /*
- * Fix segments for real mode guest in hosts that don't have
- * "unrestricted_mode" or it was disabled.
- * This is done to allow migration of the guests from hosts with
- * unrestricted guest like Westmere to older host that don't have
- * unrestricted guest like Nehelem.
- */
- if (vmx->rmode.vm86_active) {
- switch (seg) {
- case VCPU_SREG_CS:
- vmcs_write32(GUEST_CS_AR_BYTES, 0xf3);
- vmcs_write32(GUEST_CS_LIMIT, 0xffff);
- if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000)
- vmcs_writel(GUEST_CS_BASE, 0xf0000);
- vmcs_write16(GUEST_CS_SELECTOR,
- vmcs_readl(GUEST_CS_BASE) >> 4);
- break;
- case VCPU_SREG_ES:
- case VCPU_SREG_DS:
- case VCPU_SREG_GS:
- case VCPU_SREG_FS:
- fix_rmode_seg(seg, &vmx->rmode.segs[seg]);
- break;
- case VCPU_SREG_SS:
- vmcs_write16(GUEST_SS_SELECTOR,
- vmcs_readl(GUEST_SS_BASE) >> 4);
- vmcs_write32(GUEST_SS_LIMIT, 0xffff);
- vmcs_write32(GUEST_SS_AR_BYTES, 0xf3);
- break;
- }
- }
+out:
+ vmx->emulation_required |= emulation_required(vcpu);
}
static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
@@ -3380,13 +3402,16 @@ static bool rmode_segment_valid(struct kvm_vcpu *vcpu, int seg)
u32 ar;
vmx_get_segment(vcpu, &var, seg);
+ var.dpl = 0x3;
+ if (seg == VCPU_SREG_CS)
+ var.type = 0x3;
ar = vmx_segment_access_rights(&var);
if (var.base != (var.selector << 4))
return false;
- if (var.limit < 0xffff)
+ if (var.limit != 0xffff)
return false;
- if (((ar | (3 << AR_DPL_SHIFT)) & ~(AR_G_MASK | AR_DB_MASK)) != 0xf3)
+ if (ar != 0xf3)
return false;
return true;
@@ -3521,6 +3546,9 @@ static bool cs_ss_rpl_check(struct kvm_vcpu *vcpu)
*/
static bool guest_state_valid(struct kvm_vcpu *vcpu)
{
+ if (enable_unrestricted_guest)
+ return true;
+
/* real mode guest state checks */
if (!is_protmode(vcpu)) {
if (!rmode_segment_valid(vcpu, VCPU_SREG_CS))
@@ -3644,12 +3672,9 @@ static void seg_setup(int seg)
vmcs_write16(sf->selector, 0);
vmcs_writel(sf->base, 0);
vmcs_write32(sf->limit, 0xffff);
- if (enable_unrestricted_guest) {
- ar = 0x93;
- if (seg == VCPU_SREG_CS)
- ar |= 0x08; /* code segment */
- } else
- ar = 0xf3;
+ ar = 0x93;
+ if (seg == VCPU_SREG_CS)
+ ar |= 0x08; /* code segment */
vmcs_write32(sf->ar_bytes, ar);
}
@@ -3667,7 +3692,7 @@ static int alloc_apic_access_page(struct kvm *kvm)
kvm_userspace_mem.flags = 0;
kvm_userspace_mem.guest_phys_addr = 0xfee00000ULL;
kvm_userspace_mem.memory_size = PAGE_SIZE;
- r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, 0);
+ r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, false);
if (r)
goto out;
@@ -3697,7 +3722,7 @@ static int alloc_identity_pagetable(struct kvm *kvm)
kvm_userspace_mem.guest_phys_addr =
kvm->arch.ept_identity_map_addr;
kvm_userspace_mem.memory_size = PAGE_SIZE;
- r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, 0);
+ r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, false);
if (r)
goto out;
@@ -3739,7 +3764,10 @@ static void free_vpid(struct vcpu_vmx *vmx)
spin_unlock(&vmx_vpid_lock);
}
-static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr)
+#define MSR_TYPE_R 1
+#define MSR_TYPE_W 2
+static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap,
+ u32 msr, int type)
{
int f = sizeof(unsigned long);
@@ -3752,20 +3780,93 @@ static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr)
* We can control MSRs 0x00000000-0x00001fff and 0xc0000000-0xc0001fff.
*/
if (msr <= 0x1fff) {
- __clear_bit(msr, msr_bitmap + 0x000 / f); /* read-low */
- __clear_bit(msr, msr_bitmap + 0x800 / f); /* write-low */
+ if (type & MSR_TYPE_R)
+ /* read-low */
+ __clear_bit(msr, msr_bitmap + 0x000 / f);
+
+ if (type & MSR_TYPE_W)
+ /* write-low */
+ __clear_bit(msr, msr_bitmap + 0x800 / f);
+
} else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
msr &= 0x1fff;
- __clear_bit(msr, msr_bitmap + 0x400 / f); /* read-high */
- __clear_bit(msr, msr_bitmap + 0xc00 / f); /* write-high */
+ if (type & MSR_TYPE_R)
+ /* read-high */
+ __clear_bit(msr, msr_bitmap + 0x400 / f);
+
+ if (type & MSR_TYPE_W)
+ /* write-high */
+ __clear_bit(msr, msr_bitmap + 0xc00 / f);
+
+ }
+}
+
+static void __vmx_enable_intercept_for_msr(unsigned long *msr_bitmap,
+ u32 msr, int type)
+{
+ int f = sizeof(unsigned long);
+
+ if (!cpu_has_vmx_msr_bitmap())
+ return;
+
+ /*
+ * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals
+ * have the write-low and read-high bitmap offsets the wrong way round.
+ * We can control MSRs 0x00000000-0x00001fff and 0xc0000000-0xc0001fff.
+ */
+ if (msr <= 0x1fff) {
+ if (type & MSR_TYPE_R)
+ /* read-low */
+ __set_bit(msr, msr_bitmap + 0x000 / f);
+
+ if (type & MSR_TYPE_W)
+ /* write-low */
+ __set_bit(msr, msr_bitmap + 0x800 / f);
+
+ } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+ msr &= 0x1fff;
+ if (type & MSR_TYPE_R)
+ /* read-high */
+ __set_bit(msr, msr_bitmap + 0x400 / f);
+
+ if (type & MSR_TYPE_W)
+ /* write-high */
+ __set_bit(msr, msr_bitmap + 0xc00 / f);
+
}
}
static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only)
{
if (!longmode_only)
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy, msr);
- __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode, msr);
+ __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy,
+ msr, MSR_TYPE_R | MSR_TYPE_W);
+ __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode,
+ msr, MSR_TYPE_R | MSR_TYPE_W);
+}
+
+static void vmx_enable_intercept_msr_read_x2apic(u32 msr)
+{
+ __vmx_enable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
+ msr, MSR_TYPE_R);
+ __vmx_enable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
+ msr, MSR_TYPE_R);
+}
+
+static void vmx_disable_intercept_msr_read_x2apic(u32 msr)
+{
+ __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
+ msr, MSR_TYPE_R);
+ __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
+ msr, MSR_TYPE_R);
+}
+
+static void vmx_disable_intercept_msr_write_x2apic(u32 msr)
+{
+ __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
+ msr, MSR_TYPE_W);
+ __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
+ msr, MSR_TYPE_W);
}
/*
@@ -3844,6 +3945,11 @@ static u32 vmx_exec_control(struct vcpu_vmx *vmx)
return exec_control;
}
+static int vmx_vm_has_apicv(struct kvm *kvm)
+{
+ return enable_apicv_reg_vid && irqchip_in_kernel(kvm);
+}
+
static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx)
{
u32 exec_control = vmcs_config.cpu_based_2nd_exec_ctrl;
@@ -3861,6 +3967,10 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx)
exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
if (!ple_gap)
exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING;
+ if (!vmx_vm_has_apicv(vmx->vcpu.kvm))
+ exec_control &= ~(SECONDARY_EXEC_APIC_REGISTER_VIRT |
+ SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
+ exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
return exec_control;
}
@@ -3905,6 +4015,15 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmx_secondary_exec_control(vmx));
}
+ if (enable_apicv_reg_vid) {
+ vmcs_write64(EOI_EXIT_BITMAP0, 0);
+ vmcs_write64(EOI_EXIT_BITMAP1, 0);
+ vmcs_write64(EOI_EXIT_BITMAP2, 0);
+ vmcs_write64(EOI_EXIT_BITMAP3, 0);
+
+ vmcs_write16(GUEST_INTR_STATUS, 0);
+ }
+
if (ple_gap) {
vmcs_write32(PLE_GAP, ple_gap);
vmcs_write32(PLE_WINDOW, ple_window);
@@ -3990,14 +4109,9 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmx_segment_cache_clear(vmx);
seg_setup(VCPU_SREG_CS);
- /*
- * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
- * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4. Sigh.
- */
- if (kvm_vcpu_is_bsp(&vmx->vcpu)) {
+ if (kvm_vcpu_is_bsp(&vmx->vcpu))
vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
- vmcs_writel(GUEST_CS_BASE, 0x000f0000);
- } else {
+ else {
vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.arch.sipi_vector << 8);
vmcs_writel(GUEST_CS_BASE, vmx->vcpu.arch.sipi_vector << 12);
}
@@ -4073,9 +4187,6 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
ret = 0;
- /* HACK: Don't enable emulation on guest boot/reset */
- vmx->emulation_required = 0;
-
return ret;
}
@@ -4251,7 +4362,7 @@ static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr)
.flags = 0,
};
- ret = kvm_set_memory_region(kvm, &tss_mem, 0);
+ ret = kvm_set_memory_region(kvm, &tss_mem, false);
if (ret)
return ret;
kvm->arch.tss_addr = addr;
@@ -4261,28 +4372,9 @@ static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr)
return 0;
}
-static int handle_rmode_exception(struct kvm_vcpu *vcpu,
- int vec, u32 err_code)
+static bool rmode_exception(struct kvm_vcpu *vcpu, int vec)
{
- /*
- * Instruction with address size override prefix opcode 0x67
- * Cause the #SS fault with 0 error code in VM86 mode.
- */
- if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0)
- if (emulate_instruction(vcpu, 0) == EMULATE_DONE)
- return 1;
- /*
- * Forward all other exceptions that are valid in real mode.
- * FIXME: Breaks guest debugging in real mode, needs to be fixed with
- * the required debugging infrastructure rework.
- */
switch (vec) {
- case DB_VECTOR:
- if (vcpu->guest_debug &
- (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
- return 0;
- kvm_queue_exception(vcpu, vec);
- return 1;
case BP_VECTOR:
/*
* Update instruction length as we may reinject the exception
@@ -4291,7 +4383,12 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
to_vmx(vcpu)->vcpu.arch.event_exit_inst_len =
vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
- return 0;
+ return false;
+ /* fall through */
+ case DB_VECTOR:
+ if (vcpu->guest_debug &
+ (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
+ return false;
/* fall through */
case DE_VECTOR:
case OF_VECTOR:
@@ -4301,10 +4398,37 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
case SS_VECTOR:
case GP_VECTOR:
case MF_VECTOR:
- kvm_queue_exception(vcpu, vec);
- return 1;
+ return true;
+ break;
}
- return 0;
+ return false;
+}
+
+static int handle_rmode_exception(struct kvm_vcpu *vcpu,
+ int vec, u32 err_code)
+{
+ /*
+ * Instruction with address size override prefix opcode 0x67
+ * Cause the #SS fault with 0 error code in VM86 mode.
+ */
+ if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0) {
+ if (emulate_instruction(vcpu, 0) == EMULATE_DONE) {
+ if (vcpu->arch.halt_request) {
+ vcpu->arch.halt_request = 0;
+ return kvm_emulate_halt(vcpu);
+ }
+ return 1;
+ }
+ return 0;
+ }
+
+ /*
+ * Forward all other exceptions that are valid in real mode.
+ * FIXME: Breaks guest debugging in real mode, needs to be fixed with
+ * the required debugging infrastructure rework.
+ */
+ kvm_queue_exception(vcpu, vec);
+ return 1;
}
/*
@@ -4392,17 +4516,11 @@ static int handle_exception(struct kvm_vcpu *vcpu)
return kvm_mmu_page_fault(vcpu, cr2, error_code, NULL, 0);
}
- if (vmx->rmode.vm86_active &&
- handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK,
- error_code)) {
- if (vcpu->arch.halt_request) {
- vcpu->arch.halt_request = 0;
- return kvm_emulate_halt(vcpu);
- }
- return 1;
- }
-
ex_no = intr_info & INTR_INFO_VECTOR_MASK;
+
+ if (vmx->rmode.vm86_active && rmode_exception(vcpu, ex_no))
+ return handle_rmode_exception(vcpu, ex_no, error_code);
+
switch (ex_no) {
case DB_VECTOR:
dr6 = vmcs_readl(EXIT_QUALIFICATION);
@@ -4820,6 +4938,26 @@ static int handle_apic_access(struct kvm_vcpu *vcpu)
return emulate_instruction(vcpu, 0) == EMULATE_DONE;
}
+static int handle_apic_eoi_induced(struct kvm_vcpu *vcpu)
+{
+ unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
+ int vector = exit_qualification & 0xff;
+
+ /* EOI-induced VM exit is trap-like and thus no need to adjust IP */
+ kvm_apic_set_eoi_accelerated(vcpu, vector);
+ return 1;
+}
+
+static int handle_apic_write(struct kvm_vcpu *vcpu)
+{
+ unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
+ u32 offset = exit_qualification & 0xfff;
+
+ /* APIC-write VM exit is trap-like and thus no need to adjust IP */
+ kvm_apic_write_nodecode(vcpu, offset);
+ return 1;
+}
+
static int handle_task_switch(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -5065,7 +5203,7 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu)
schedule();
}
- vmx->emulation_required = !guest_state_valid(vcpu);
+ vmx->emulation_required = emulation_required(vcpu);
out:
return ret;
}
@@ -5754,6 +5892,8 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[EXIT_REASON_VMON] = handle_vmon,
[EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold,
[EXIT_REASON_APIC_ACCESS] = handle_apic_access,
+ [EXIT_REASON_APIC_WRITE] = handle_apic_write,
+ [EXIT_REASON_EOI_INDUCED] = handle_apic_eoi_induced,
[EXIT_REASON_WBINVD] = handle_wbinvd,
[EXIT_REASON_XSETBV] = handle_xsetbv,
[EXIT_REASON_TASK_SWITCH] = handle_task_switch,
@@ -5780,7 +5920,7 @@ static bool nested_vmx_exit_handled_msr(struct kvm_vcpu *vcpu,
u32 msr_index = vcpu->arch.regs[VCPU_REGS_RCX];
gpa_t bitmap;
- if (!nested_cpu_has(get_vmcs12(vcpu), CPU_BASED_USE_MSR_BITMAPS))
+ if (!nested_cpu_has(vmcs12, CPU_BASED_USE_MSR_BITMAPS))
return 1;
/*
@@ -6008,7 +6148,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
u32 vectoring_info = vmx->idt_vectoring_info;
/* If guest state is invalid, start emulating */
- if (vmx->emulation_required && emulate_invalid_guest_state)
+ if (vmx->emulation_required)
return handle_invalid_guest_state(vcpu);
/*
@@ -6103,6 +6243,85 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
vmcs_write32(TPR_THRESHOLD, irr);
}
+static void vmx_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
+{
+ u32 sec_exec_control;
+
+ /*
+ * There is not point to enable virtualize x2apic without enable
+ * apicv
+ */
+ if (!cpu_has_vmx_virtualize_x2apic_mode() ||
+ !vmx_vm_has_apicv(vcpu->kvm))
+ return;
+
+ if (!vm_need_tpr_shadow(vcpu->kvm))
+ return;
+
+ sec_exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL);
+
+ if (set) {
+ sec_exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
+ sec_exec_control |= SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
+ } else {
+ sec_exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
+ sec_exec_control |= SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
+ }
+ vmcs_write32(SECONDARY_VM_EXEC_CONTROL, sec_exec_control);
+
+ vmx_set_msr_bitmap(vcpu);
+}
+
+static void vmx_hwapic_isr_update(struct kvm *kvm, int isr)
+{
+ u16 status;
+ u8 old;
+
+ if (!vmx_vm_has_apicv(kvm))
+ return;
+
+ if (isr == -1)
+ isr = 0;
+
+ status = vmcs_read16(GUEST_INTR_STATUS);
+ old = status >> 8;
+ if (isr != old) {
+ status &= 0xff;
+ status |= isr << 8;
+ vmcs_write16(GUEST_INTR_STATUS, status);
+ }
+}
+
+static void vmx_set_rvi(int vector)
+{
+ u16 status;
+ u8 old;
+
+ status = vmcs_read16(GUEST_INTR_STATUS);
+ old = (u8)status & 0xff;
+ if ((u8)vector != old) {
+ status &= ~0xff;
+ status |= (u8)vector;
+ vmcs_write16(GUEST_INTR_STATUS, status);
+ }
+}
+
+static void vmx_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
+{
+ if (max_irr == -1)
+ return;
+
+ vmx_set_rvi(max_irr);
+}
+
+static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+{
+ vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
+ vmcs_write64(EOI_EXIT_BITMAP1, eoi_exit_bitmap[1]);
+ vmcs_write64(EOI_EXIT_BITMAP2, eoi_exit_bitmap[2]);
+ vmcs_write64(EOI_EXIT_BITMAP3, eoi_exit_bitmap[3]);
+}
+
static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
{
u32 exit_intr_info;
@@ -6291,7 +6510,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
/* Don't enter VMX if guest state is invalid, let the exit handler
start emulation until we arrive back to a valid state */
- if (vmx->emulation_required && emulate_invalid_guest_state)
+ if (vmx->emulation_required)
return;
if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty))
@@ -7366,6 +7585,11 @@ static struct kvm_x86_ops vmx_x86_ops = {
.enable_nmi_window = enable_nmi_window,
.enable_irq_window = enable_irq_window,
.update_cr8_intercept = update_cr8_intercept,
+ .set_virtual_x2apic_mode = vmx_set_virtual_x2apic_mode,
+ .vm_has_apicv = vmx_vm_has_apicv,
+ .load_eoi_exitmap = vmx_load_eoi_exitmap,
+ .hwapic_irr_update = vmx_hwapic_irr_update,
+ .hwapic_isr_update = vmx_hwapic_isr_update,
.set_tss_addr = vmx_set_tss_addr,
.get_tdp_level = get_ept_level,
@@ -7398,7 +7622,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
static int __init vmx_init(void)
{
- int r, i;
+ int r, i, msr;
rdmsrl_safe(MSR_EFER, &host_efer);
@@ -7419,11 +7643,19 @@ static int __init vmx_init(void)
if (!vmx_msr_bitmap_legacy)
goto out1;
+ vmx_msr_bitmap_legacy_x2apic =
+ (unsigned long *)__get_free_page(GFP_KERNEL);
+ if (!vmx_msr_bitmap_legacy_x2apic)
+ goto out2;
vmx_msr_bitmap_longmode = (unsigned long *)__get_free_page(GFP_KERNEL);
if (!vmx_msr_bitmap_longmode)
- goto out2;
+ goto out3;
+ vmx_msr_bitmap_longmode_x2apic =
+ (unsigned long *)__get_free_page(GFP_KERNEL);
+ if (!vmx_msr_bitmap_longmode_x2apic)
+ goto out4;
/*
* Allow direct access to the PC debug port (it is often used for I/O
@@ -7455,6 +7687,28 @@ static int __init vmx_init(void)
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
+ memcpy(vmx_msr_bitmap_legacy_x2apic,
+ vmx_msr_bitmap_legacy, PAGE_SIZE);
+ memcpy(vmx_msr_bitmap_longmode_x2apic,
+ vmx_msr_bitmap_longmode, PAGE_SIZE);
+
+ if (enable_apicv_reg_vid) {
+ for (msr = 0x800; msr <= 0x8ff; msr++)
+ vmx_disable_intercept_msr_read_x2apic(msr);
+
+ /* According SDM, in x2apic mode, the whole id reg is used.
+ * But in KVM, it only use the highest eight bits. Need to
+ * intercept it */
+ vmx_enable_intercept_msr_read_x2apic(0x802);
+ /* TMCCT */
+ vmx_enable_intercept_msr_read_x2apic(0x839);
+ /* TPR */
+ vmx_disable_intercept_msr_write_x2apic(0x808);
+ /* EOI */
+ vmx_disable_intercept_msr_write_x2apic(0x80b);
+ /* SELF-IPI */
+ vmx_disable_intercept_msr_write_x2apic(0x83f);
+ }
if (enable_ept) {
kvm_mmu_set_mask_ptes(0ull,
@@ -7468,8 +7722,10 @@ static int __init vmx_init(void)
return 0;
-out3:
+out4:
free_page((unsigned long)vmx_msr_bitmap_longmode);
+out3:
+ free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic);
out2:
free_page((unsigned long)vmx_msr_bitmap_legacy);
out1:
@@ -7481,6 +7737,8 @@ out:
static void __exit vmx_exit(void)
{
+ free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic);
+ free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic);
free_page((unsigned long)vmx_msr_bitmap_legacy);
free_page((unsigned long)vmx_msr_bitmap_longmode);
free_page((unsigned long)vmx_io_bitmap_b);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index c243b81e3c74..f71500af1f81 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -872,8 +872,6 @@ static int set_efer(struct kvm_vcpu *vcpu, u64 efer)
kvm_x86_ops->set_efer(vcpu, efer);
- vcpu->arch.mmu.base_role.nxe = (efer & EFER_NX) && !tdp_enabled;
-
/* Update reserved bits */
if ((efer ^ old_efer) & EFER_NX)
kvm_mmu_reset_context(vcpu);
@@ -1881,6 +1879,14 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
u64 data = msr_info->data;
switch (msr) {
+ case MSR_AMD64_NB_CFG:
+ case MSR_IA32_UCODE_REV:
+ case MSR_IA32_UCODE_WRITE:
+ case MSR_VM_HSAVE_PA:
+ case MSR_AMD64_PATCH_LOADER:
+ case MSR_AMD64_BU_CFG2:
+ break;
+
case MSR_EFER:
return set_efer(vcpu, data);
case MSR_K7_HWCR:
@@ -1900,8 +1906,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
return 1;
}
break;
- case MSR_AMD64_NB_CFG:
- break;
case MSR_IA32_DEBUGCTLMSR:
if (!data) {
/* We support the non-activated case already */
@@ -1914,11 +1918,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTLMSR 0x%llx, nop\n",
__func__, data);
break;
- case MSR_IA32_UCODE_REV:
- case MSR_IA32_UCODE_WRITE:
- case MSR_VM_HSAVE_PA:
- case MSR_AMD64_PATCH_LOADER:
- break;
case 0x200 ... 0x2ff:
return set_msr_mtrr(vcpu, msr, data);
case MSR_IA32_APICBASE:
@@ -2253,6 +2252,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case MSR_K8_INT_PENDING_MSG:
case MSR_AMD64_NB_CFG:
case MSR_FAM10H_MMIO_CONF_BASE:
+ case MSR_AMD64_BU_CFG2:
data = 0;
break;
case MSR_P6_PERFCTR0:
@@ -2520,7 +2520,7 @@ int kvm_dev_ioctl_check_extension(long ext)
r = KVM_MAX_VCPUS;
break;
case KVM_CAP_NR_MEMSLOTS:
- r = KVM_MEMORY_SLOTS;
+ r = KVM_USER_MEM_SLOTS;
break;
case KVM_CAP_PV_MMU: /* obsolete */
r = 0;
@@ -3272,12 +3272,10 @@ static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm,
return -EINVAL;
mutex_lock(&kvm->slots_lock);
- spin_lock(&kvm->mmu_lock);
kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages);
kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages;
- spin_unlock(&kvm->mmu_lock);
mutex_unlock(&kvm->slots_lock);
return 0;
}
@@ -3437,7 +3435,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
mutex_lock(&kvm->slots_lock);
r = -EINVAL;
- if (log->slot >= KVM_MEMORY_SLOTS)
+ if (log->slot >= KVM_USER_MEM_SLOTS)
goto out;
memslot = id_to_memslot(kvm->memslots, log->slot);
@@ -4493,8 +4491,10 @@ static bool emulator_get_segment(struct x86_emulate_ctxt *ctxt, u16 *selector,
kvm_get_segment(emul_to_vcpu(ctxt), &var, seg);
*selector = var.selector;
- if (var.unusable)
+ if (var.unusable) {
+ memset(desc, 0, sizeof(*desc));
return false;
+ }
if (var.g)
var.limit >>= 12;
@@ -4755,26 +4755,26 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu)
return r;
}
-static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva)
+static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2,
+ bool write_fault_to_shadow_pgtable)
{
- gpa_t gpa;
+ gpa_t gpa = cr2;
pfn_t pfn;
- if (tdp_enabled)
- return false;
-
- /*
- * if emulation was due to access to shadowed page table
- * and it failed try to unshadow page and re-enter the
- * guest to let CPU execute the instruction.
- */
- if (kvm_mmu_unprotect_page_virt(vcpu, gva))
- return true;
-
- gpa = kvm_mmu_gva_to_gpa_system(vcpu, gva, NULL);
+ if (!vcpu->arch.mmu.direct_map) {
+ /*
+ * Write permission should be allowed since only
+ * write access need to be emulated.
+ */
+ gpa = kvm_mmu_gva_to_gpa_write(vcpu, cr2, NULL);
- if (gpa == UNMAPPED_GVA)
- return true; /* let cpu generate fault */
+ /*
+ * If the mapping is invalid in guest, let cpu retry
+ * it to generate fault.
+ */
+ if (gpa == UNMAPPED_GVA)
+ return true;
+ }
/*
* Do not retry the unhandleable instruction if it faults on the
@@ -4783,12 +4783,43 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva)
* instruction -> ...
*/
pfn = gfn_to_pfn(vcpu->kvm, gpa_to_gfn(gpa));
- if (!is_error_noslot_pfn(pfn)) {
- kvm_release_pfn_clean(pfn);
+
+ /*
+ * If the instruction failed on the error pfn, it can not be fixed,
+ * report the error to userspace.
+ */
+ if (is_error_noslot_pfn(pfn))
+ return false;
+
+ kvm_release_pfn_clean(pfn);
+
+ /* The instructions are well-emulated on direct mmu. */
+ if (vcpu->arch.mmu.direct_map) {
+ unsigned int indirect_shadow_pages;
+
+ spin_lock(&vcpu->kvm->mmu_lock);
+ indirect_shadow_pages = vcpu->kvm->arch.indirect_shadow_pages;
+ spin_unlock(&vcpu->kvm->mmu_lock);
+
+ if (indirect_shadow_pages)
+ kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa));
+
return true;
}
- return false;
+ /*
+ * if emulation was due to access to shadowed page table
+ * and it failed try to unshadow page and re-enter the
+ * guest to let CPU execute the instruction.
+ */
+ kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa));
+
+ /*
+ * If the access faults on its page table, it can not
+ * be fixed by unprotecting shadow page and it should
+ * be reported to userspace.
+ */
+ return !write_fault_to_shadow_pgtable;
}
static bool retry_instruction(struct x86_emulate_ctxt *ctxt,
@@ -4830,7 +4861,7 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt,
if (!vcpu->arch.mmu.direct_map)
gpa = kvm_mmu_gva_to_gpa_write(vcpu, cr2, NULL);
- kvm_mmu_unprotect_page(vcpu->kvm, gpa >> PAGE_SHIFT);
+ kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa));
return true;
}
@@ -4847,7 +4878,13 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
int r;
struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
bool writeback = true;
+ bool write_fault_to_spt = vcpu->arch.write_fault_to_shadow_pgtable;
+ /*
+ * Clear write_fault_to_shadow_pgtable here to ensure it is
+ * never reused.
+ */
+ vcpu->arch.write_fault_to_shadow_pgtable = false;
kvm_clear_exception_queue(vcpu);
if (!(emulation_type & EMULTYPE_NO_DECODE)) {
@@ -4866,7 +4903,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
if (r != EMULATION_OK) {
if (emulation_type & EMULTYPE_TRAP_UD)
return EMULATE_FAIL;
- if (reexecute_instruction(vcpu, cr2))
+ if (reexecute_instruction(vcpu, cr2,
+ write_fault_to_spt))
return EMULATE_DONE;
if (emulation_type & EMULTYPE_SKIP)
return EMULATE_FAIL;
@@ -4896,7 +4934,7 @@ restart:
return EMULATE_DONE;
if (r == EMULATION_FAILED) {
- if (reexecute_instruction(vcpu, cr2))
+ if (reexecute_instruction(vcpu, cr2, write_fault_to_spt))
return EMULATE_DONE;
return handle_emulation_failure(vcpu);
@@ -5539,7 +5577,7 @@ static void inject_pending_event(struct kvm_vcpu *vcpu)
vcpu->arch.nmi_injected = true;
kvm_x86_ops->set_nmi(vcpu);
}
- } else if (kvm_cpu_has_interrupt(vcpu)) {
+ } else if (kvm_cpu_has_injectable_intr(vcpu)) {
if (kvm_x86_ops->interrupt_allowed(vcpu)) {
kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu),
false);
@@ -5607,6 +5645,16 @@ static void kvm_gen_update_masterclock(struct kvm *kvm)
#endif
}
+static void update_eoi_exitmap(struct kvm_vcpu *vcpu)
+{
+ u64 eoi_exit_bitmap[4];
+
+ memset(eoi_exit_bitmap, 0, 32);
+
+ kvm_ioapic_calculate_eoi_exitmap(vcpu, eoi_exit_bitmap);
+ kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap);
+}
+
static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
{
int r;
@@ -5660,6 +5708,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
kvm_handle_pmu_event(vcpu);
if (kvm_check_request(KVM_REQ_PMI, vcpu))
kvm_deliver_pmi(vcpu);
+ if (kvm_check_request(KVM_REQ_EOIBITMAP, vcpu))
+ update_eoi_exitmap(vcpu);
}
if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
@@ -5668,10 +5718,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
/* enable NMI/IRQ window open exits if needed */
if (vcpu->arch.nmi_pending)
kvm_x86_ops->enable_nmi_window(vcpu);
- else if (kvm_cpu_has_interrupt(vcpu) || req_int_win)
+ else if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
kvm_x86_ops->enable_irq_window(vcpu);
if (kvm_lapic_enabled(vcpu)) {
+ /*
+ * Update architecture specific hints for APIC
+ * virtual interrupt delivery.
+ */
+ if (kvm_x86_ops->hwapic_irr_update)
+ kvm_x86_ops->hwapic_irr_update(vcpu,
+ kvm_lapic_find_highest_irr(vcpu));
update_cr8_intercept(vcpu);
kvm_lapic_sync_to_vapic(vcpu);
}
@@ -6851,48 +6908,43 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
struct kvm_memory_slot old,
struct kvm_userspace_memory_region *mem,
- int user_alloc)
+ bool user_alloc)
{
int npages = memslot->npages;
- int map_flags = MAP_PRIVATE | MAP_ANONYMOUS;
-
- /* Prevent internal slot pages from being moved by fork()/COW. */
- if (memslot->id >= KVM_MEMORY_SLOTS)
- map_flags = MAP_SHARED | MAP_ANONYMOUS;
- /*To keep backward compatibility with older userspace,
- *x86 needs to handle !user_alloc case.
+ /*
+ * Only private memory slots need to be mapped here since
+ * KVM_SET_MEMORY_REGION ioctl is no longer supported.
*/
- if (!user_alloc) {
- if (npages && !old.npages) {
- unsigned long userspace_addr;
+ if ((memslot->id >= KVM_USER_MEM_SLOTS) && npages && !old.npages) {
+ unsigned long userspace_addr;
- userspace_addr = vm_mmap(NULL, 0,
- npages * PAGE_SIZE,
- PROT_READ | PROT_WRITE,
- map_flags,
- 0);
+ /*
+ * MAP_SHARED to prevent internal slot pages from being moved
+ * by fork()/COW.
+ */
+ userspace_addr = vm_mmap(NULL, 0, npages * PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, 0);
- if (IS_ERR((void *)userspace_addr))
- return PTR_ERR((void *)userspace_addr);
+ if (IS_ERR((void *)userspace_addr))
+ return PTR_ERR((void *)userspace_addr);
- memslot->userspace_addr = userspace_addr;
- }
+ memslot->userspace_addr = userspace_addr;
}
-
return 0;
}
void kvm_arch_commit_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
struct kvm_memory_slot old,
- int user_alloc)
+ bool user_alloc)
{
int nr_mmu_pages = 0, npages = mem->memory_size >> PAGE_SHIFT;
- if (!user_alloc && !old.user_alloc && old.npages && !npages) {
+ if ((mem->slot >= KVM_USER_MEM_SLOTS) && old.npages && !npages) {
int ret;
ret = vm_munmap(old.userspace_addr,
@@ -6906,11 +6958,15 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
if (!kvm->arch.n_requested_mmu_pages)
nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm);
- spin_lock(&kvm->mmu_lock);
if (nr_mmu_pages)
kvm_mmu_change_mmu_pages(kvm, nr_mmu_pages);
- kvm_mmu_slot_remove_write_access(kvm, mem->slot);
- spin_unlock(&kvm->mmu_lock);
+ /*
+ * Write protect all pages for dirty logging.
+ * Existing largepage mappings are destroyed here and new ones will
+ * not be created until the end of the logging.
+ */
+ if (npages && (mem->flags & KVM_MEM_LOG_DIRTY_PAGES))
+ kvm_mmu_slot_remove_write_access(kvm, mem->slot);
/*
* If memory slot is created, or moved, we need to clear all
* mmio sptes.
diff --git a/arch/x86/lguest/Kconfig b/arch/x86/lguest/Kconfig
index 7872a3330fb5..29043d2048a0 100644
--- a/arch/x86/lguest/Kconfig
+++ b/arch/x86/lguest/Kconfig
@@ -2,6 +2,7 @@ config LGUEST_GUEST
bool "Lguest guest support"
select PARAVIRT
depends on X86_32
+ select TTY
select VIRTUALIZATION
select VIRTIO
select VIRTIO_CONSOLE
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index df4176cdbb32..1cbd89ca5569 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -552,7 +552,8 @@ static void lguest_write_cr3(unsigned long cr3)
current_cr3 = cr3;
/* These two page tables are simple, linear, and used during boot */
- if (cr3 != __pa(swapper_pg_dir) && cr3 != __pa(initial_page_table))
+ if (cr3 != __pa_symbol(swapper_pg_dir) &&
+ cr3 != __pa_symbol(initial_page_table))
cr3_changed = true;
}
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index 156b9c804670..a4512359656a 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -15,11 +15,10 @@
* __get_user_X
*
* Inputs: %[r|e]ax contains the address.
- * The register is modified, but all changes are undone
- * before returning because the C code doesn't know about it.
*
* Outputs: %[r|e]ax is error code (0 or -EFAULT)
* %[r|e]dx contains zero-extended value
+ * %ecx contains the high half for 32-bit __get_user_8
*
*
* These functions should not modify any other registers,
@@ -42,7 +41,7 @@ ENTRY(__get_user_1)
cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
jae bad_get_user
ASM_STAC
-1: movzb (%_ASM_AX),%edx
+1: movzbl (%_ASM_AX),%edx
xor %eax,%eax
ASM_CLAC
ret
@@ -72,29 +71,42 @@ ENTRY(__get_user_4)
cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
jae bad_get_user
ASM_STAC
-3: mov -3(%_ASM_AX),%edx
+3: movl -3(%_ASM_AX),%edx
xor %eax,%eax
ASM_CLAC
ret
CFI_ENDPROC
ENDPROC(__get_user_4)
-#ifdef CONFIG_X86_64
ENTRY(__get_user_8)
CFI_STARTPROC
+#ifdef CONFIG_X86_64
add $7,%_ASM_AX
jc bad_get_user
GET_THREAD_INFO(%_ASM_DX)
cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
- jae bad_get_user
+ jae bad_get_user
ASM_STAC
-4: movq -7(%_ASM_AX),%_ASM_DX
+4: movq -7(%_ASM_AX),%rdx
xor %eax,%eax
ASM_CLAC
ret
+#else
+ add $7,%_ASM_AX
+ jc bad_get_user_8
+ GET_THREAD_INFO(%_ASM_DX)
+ cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
+ jae bad_get_user_8
+ ASM_STAC
+4: movl -7(%_ASM_AX),%edx
+5: movl -3(%_ASM_AX),%ecx
+ xor %eax,%eax
+ ASM_CLAC
+ ret
+#endif
CFI_ENDPROC
ENDPROC(__get_user_8)
-#endif
+
bad_get_user:
CFI_STARTPROC
@@ -105,9 +117,24 @@ bad_get_user:
CFI_ENDPROC
END(bad_get_user)
+#ifdef CONFIG_X86_32
+bad_get_user_8:
+ CFI_STARTPROC
+ xor %edx,%edx
+ xor %ecx,%ecx
+ mov $(-EFAULT),%_ASM_AX
+ ASM_CLAC
+ ret
+ CFI_ENDPROC
+END(bad_get_user_8)
+#endif
+
_ASM_EXTABLE(1b,bad_get_user)
_ASM_EXTABLE(2b,bad_get_user)
_ASM_EXTABLE(3b,bad_get_user)
#ifdef CONFIG_X86_64
_ASM_EXTABLE(4b,bad_get_user)
+#else
+ _ASM_EXTABLE(4b,bad_get_user_8)
+ _ASM_EXTABLE(5b,bad_get_user_8)
#endif
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 027088f2f7dd..fb674fd3fc22 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -748,13 +748,15 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
return;
}
#endif
+ /* Kernel addresses are always protection faults: */
+ if (address >= TASK_SIZE)
+ error_code |= PF_PROT;
- if (unlikely(show_unhandled_signals))
+ if (likely(show_unhandled_signals))
show_signal_msg(regs, error_code, address, tsk);
- /* Kernel addresses are always protection faults: */
tsk->thread.cr2 = address;
- tsk->thread.error_code = error_code | (address >= TASK_SIZE);
+ tsk->thread.error_code = error_code;
tsk->thread.trap_nr = X86_TRAP_PF;
force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0);
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index d7aea41563b3..4903a03ae876 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -16,87 +16,134 @@
#include <asm/tlb.h>
#include <asm/proto.h>
#include <asm/dma.h> /* for MAX_DMA_PFN */
+#include <asm/microcode.h>
-unsigned long __initdata pgt_buf_start;
-unsigned long __meminitdata pgt_buf_end;
-unsigned long __meminitdata pgt_buf_top;
+#include "mm_internal.h"
-int after_bootmem;
+static unsigned long __initdata pgt_buf_start;
+static unsigned long __initdata pgt_buf_end;
+static unsigned long __initdata pgt_buf_top;
-int direct_gbpages
-#ifdef CONFIG_DIRECT_GBPAGES
- = 1
-#endif
-;
+static unsigned long min_pfn_mapped;
-struct map_range {
- unsigned long start;
- unsigned long end;
- unsigned page_size_mask;
-};
+static bool __initdata can_use_brk_pgt = true;
/*
- * First calculate space needed for kernel direct mapping page tables to cover
- * mr[0].start to mr[nr_range - 1].end, while accounting for possible 2M and 1GB
- * pages. Then find enough contiguous space for those page tables.
+ * Pages returned are already directly mapped.
+ *
+ * Changing that is likely to break Xen, see commit:
+ *
+ * 279b706 x86,xen: introduce x86_init.mapping.pagetable_reserve
+ *
+ * for detailed information.
*/
-static void __init find_early_table_space(struct map_range *mr, int nr_range)
+__ref void *alloc_low_pages(unsigned int num)
{
+ unsigned long pfn;
int i;
- unsigned long puds = 0, pmds = 0, ptes = 0, tables;
- unsigned long start = 0, good_end;
- phys_addr_t base;
- for (i = 0; i < nr_range; i++) {
- unsigned long range, extra;
+ if (after_bootmem) {
+ unsigned int order;
- range = mr[i].end - mr[i].start;
- puds += (range + PUD_SIZE - 1) >> PUD_SHIFT;
+ order = get_order((unsigned long)num << PAGE_SHIFT);
+ return (void *)__get_free_pages(GFP_ATOMIC | __GFP_NOTRACK |
+ __GFP_ZERO, order);
+ }
- if (mr[i].page_size_mask & (1 << PG_LEVEL_1G)) {
- extra = range - ((range >> PUD_SHIFT) << PUD_SHIFT);
- pmds += (extra + PMD_SIZE - 1) >> PMD_SHIFT;
- } else {
- pmds += (range + PMD_SIZE - 1) >> PMD_SHIFT;
- }
+ if ((pgt_buf_end + num) > pgt_buf_top || !can_use_brk_pgt) {
+ unsigned long ret;
+ if (min_pfn_mapped >= max_pfn_mapped)
+ panic("alloc_low_page: ran out of memory");
+ ret = memblock_find_in_range(min_pfn_mapped << PAGE_SHIFT,
+ max_pfn_mapped << PAGE_SHIFT,
+ PAGE_SIZE * num , PAGE_SIZE);
+ if (!ret)
+ panic("alloc_low_page: can not alloc memory");
+ memblock_reserve(ret, PAGE_SIZE * num);
+ pfn = ret >> PAGE_SHIFT;
+ } else {
+ pfn = pgt_buf_end;
+ pgt_buf_end += num;
+ printk(KERN_DEBUG "BRK [%#010lx, %#010lx] PGTABLE\n",
+ pfn << PAGE_SHIFT, (pgt_buf_end << PAGE_SHIFT) - 1);
+ }
- if (mr[i].page_size_mask & (1 << PG_LEVEL_2M)) {
- extra = range - ((range >> PMD_SHIFT) << PMD_SHIFT);
-#ifdef CONFIG_X86_32
- extra += PMD_SIZE;
-#endif
- ptes += (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
- } else {
- ptes += (range + PAGE_SIZE - 1) >> PAGE_SHIFT;
- }
+ for (i = 0; i < num; i++) {
+ void *adr;
+
+ adr = __va((pfn + i) << PAGE_SHIFT);
+ clear_page(adr);
}
- tables = roundup(puds * sizeof(pud_t), PAGE_SIZE);
- tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE);
- tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE);
+ return __va(pfn << PAGE_SHIFT);
+}
-#ifdef CONFIG_X86_32
- /* for fixmap */
- tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE);
-#endif
- good_end = max_pfn_mapped << PAGE_SHIFT;
+/* need 4 4k for initial PMD_SIZE, 4k for 0-ISA_END_ADDRESS */
+#define INIT_PGT_BUF_SIZE (5 * PAGE_SIZE)
+RESERVE_BRK(early_pgt_alloc, INIT_PGT_BUF_SIZE);
+void __init early_alloc_pgt_buf(void)
+{
+ unsigned long tables = INIT_PGT_BUF_SIZE;
+ phys_addr_t base;
- base = memblock_find_in_range(start, good_end, tables, PAGE_SIZE);
- if (!base)
- panic("Cannot find space for the kernel page tables");
+ base = __pa(extend_brk(tables, PAGE_SIZE));
pgt_buf_start = base >> PAGE_SHIFT;
pgt_buf_end = pgt_buf_start;
pgt_buf_top = pgt_buf_start + (tables >> PAGE_SHIFT);
+}
- printk(KERN_DEBUG "kernel direct mapping tables up to %#lx @ [mem %#010lx-%#010lx]\n",
- mr[nr_range - 1].end - 1, pgt_buf_start << PAGE_SHIFT,
- (pgt_buf_top << PAGE_SHIFT) - 1);
+int after_bootmem;
+
+int direct_gbpages
+#ifdef CONFIG_DIRECT_GBPAGES
+ = 1
+#endif
+;
+
+static void __init init_gbpages(void)
+{
+#ifdef CONFIG_X86_64
+ if (direct_gbpages && cpu_has_gbpages)
+ printk(KERN_INFO "Using GB pages for direct mapping\n");
+ else
+ direct_gbpages = 0;
+#endif
}
-void __init native_pagetable_reserve(u64 start, u64 end)
+struct map_range {
+ unsigned long start;
+ unsigned long end;
+ unsigned page_size_mask;
+};
+
+static int page_size_mask;
+
+static void __init probe_page_size_mask(void)
{
- memblock_reserve(start, end - start);
+ init_gbpages();
+
+#if !defined(CONFIG_DEBUG_PAGEALLOC) && !defined(CONFIG_KMEMCHECK)
+ /*
+ * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
+ * This will simplify cpa(), which otherwise needs to support splitting
+ * large pages into small in interrupt context, etc.
+ */
+ if (direct_gbpages)
+ page_size_mask |= 1 << PG_LEVEL_1G;
+ if (cpu_has_pse)
+ page_size_mask |= 1 << PG_LEVEL_2M;
+#endif
+
+ /* Enable PSE if available */
+ if (cpu_has_pse)
+ set_in_cr4(X86_CR4_PSE);
+
+ /* Enable PGE if available */
+ if (cpu_has_pge) {
+ set_in_cr4(X86_CR4_PGE);
+ __supported_pte_mask |= _PAGE_GLOBAL;
+ }
}
#ifdef CONFIG_X86_32
@@ -122,58 +169,51 @@ static int __meminit save_mr(struct map_range *mr, int nr_range,
}
/*
- * Setup the direct mapping of the physical memory at PAGE_OFFSET.
- * This runs before bootmem is initialized and gets pages directly from
- * the physical memory. To access them they are temporarily mapped.
+ * adjust the page_size_mask for small range to go with
+ * big page size instead small one if nearby are ram too.
*/
-unsigned long __init_refok init_memory_mapping(unsigned long start,
- unsigned long end)
+static void __init_refok adjust_range_page_size_mask(struct map_range *mr,
+ int nr_range)
{
- unsigned long page_size_mask = 0;
- unsigned long start_pfn, end_pfn;
- unsigned long ret = 0;
- unsigned long pos;
-
- struct map_range mr[NR_RANGE_MR];
- int nr_range, i;
- int use_pse, use_gbpages;
+ int i;
- printk(KERN_INFO "init_memory_mapping: [mem %#010lx-%#010lx]\n",
- start, end - 1);
+ for (i = 0; i < nr_range; i++) {
+ if ((page_size_mask & (1<<PG_LEVEL_2M)) &&
+ !(mr[i].page_size_mask & (1<<PG_LEVEL_2M))) {
+ unsigned long start = round_down(mr[i].start, PMD_SIZE);
+ unsigned long end = round_up(mr[i].end, PMD_SIZE);
-#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KMEMCHECK)
- /*
- * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
- * This will simplify cpa(), which otherwise needs to support splitting
- * large pages into small in interrupt context, etc.
- */
- use_pse = use_gbpages = 0;
-#else
- use_pse = cpu_has_pse;
- use_gbpages = direct_gbpages;
+#ifdef CONFIG_X86_32
+ if ((end >> PAGE_SHIFT) > max_low_pfn)
+ continue;
#endif
- /* Enable PSE if available */
- if (cpu_has_pse)
- set_in_cr4(X86_CR4_PSE);
+ if (memblock_is_region_memory(start, end - start))
+ mr[i].page_size_mask |= 1<<PG_LEVEL_2M;
+ }
+ if ((page_size_mask & (1<<PG_LEVEL_1G)) &&
+ !(mr[i].page_size_mask & (1<<PG_LEVEL_1G))) {
+ unsigned long start = round_down(mr[i].start, PUD_SIZE);
+ unsigned long end = round_up(mr[i].end, PUD_SIZE);
- /* Enable PGE if available */
- if (cpu_has_pge) {
- set_in_cr4(X86_CR4_PGE);
- __supported_pte_mask |= _PAGE_GLOBAL;
+ if (memblock_is_region_memory(start, end - start))
+ mr[i].page_size_mask |= 1<<PG_LEVEL_1G;
+ }
}
+}
- if (use_gbpages)
- page_size_mask |= 1 << PG_LEVEL_1G;
- if (use_pse)
- page_size_mask |= 1 << PG_LEVEL_2M;
+static int __meminit split_mem_range(struct map_range *mr, int nr_range,
+ unsigned long start,
+ unsigned long end)
+{
+ unsigned long start_pfn, end_pfn, limit_pfn;
+ unsigned long pfn;
+ int i;
- memset(mr, 0, sizeof(mr));
- nr_range = 0;
+ limit_pfn = PFN_DOWN(end);
/* head if not big page alignment ? */
- start_pfn = start >> PAGE_SHIFT;
- pos = start_pfn << PAGE_SHIFT;
+ pfn = start_pfn = PFN_DOWN(start);
#ifdef CONFIG_X86_32
/*
* Don't use a large page for the first 2/4MB of memory
@@ -181,66 +221,60 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
* and overlapping MTRRs into large pages can cause
* slowdowns.
*/
- if (pos == 0)
- end_pfn = 1<<(PMD_SHIFT - PAGE_SHIFT);
+ if (pfn == 0)
+ end_pfn = PFN_DOWN(PMD_SIZE);
else
- end_pfn = ((pos + (PMD_SIZE - 1))>>PMD_SHIFT)
- << (PMD_SHIFT - PAGE_SHIFT);
+ end_pfn = round_up(pfn, PFN_DOWN(PMD_SIZE));
#else /* CONFIG_X86_64 */
- end_pfn = ((pos + (PMD_SIZE - 1)) >> PMD_SHIFT)
- << (PMD_SHIFT - PAGE_SHIFT);
+ end_pfn = round_up(pfn, PFN_DOWN(PMD_SIZE));
#endif
- if (end_pfn > (end >> PAGE_SHIFT))
- end_pfn = end >> PAGE_SHIFT;
+ if (end_pfn > limit_pfn)
+ end_pfn = limit_pfn;
if (start_pfn < end_pfn) {
nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0);
- pos = end_pfn << PAGE_SHIFT;
+ pfn = end_pfn;
}
/* big page (2M) range */
- start_pfn = ((pos + (PMD_SIZE - 1))>>PMD_SHIFT)
- << (PMD_SHIFT - PAGE_SHIFT);
+ start_pfn = round_up(pfn, PFN_DOWN(PMD_SIZE));
#ifdef CONFIG_X86_32
- end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT);
+ end_pfn = round_down(limit_pfn, PFN_DOWN(PMD_SIZE));
#else /* CONFIG_X86_64 */
- end_pfn = ((pos + (PUD_SIZE - 1))>>PUD_SHIFT)
- << (PUD_SHIFT - PAGE_SHIFT);
- if (end_pfn > ((end>>PMD_SHIFT)<<(PMD_SHIFT - PAGE_SHIFT)))
- end_pfn = ((end>>PMD_SHIFT)<<(PMD_SHIFT - PAGE_SHIFT));
+ end_pfn = round_up(pfn, PFN_DOWN(PUD_SIZE));
+ if (end_pfn > round_down(limit_pfn, PFN_DOWN(PMD_SIZE)))
+ end_pfn = round_down(limit_pfn, PFN_DOWN(PMD_SIZE));
#endif
if (start_pfn < end_pfn) {
nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
page_size_mask & (1<<PG_LEVEL_2M));
- pos = end_pfn << PAGE_SHIFT;
+ pfn = end_pfn;
}
#ifdef CONFIG_X86_64
/* big page (1G) range */
- start_pfn = ((pos + (PUD_SIZE - 1))>>PUD_SHIFT)
- << (PUD_SHIFT - PAGE_SHIFT);
- end_pfn = (end >> PUD_SHIFT) << (PUD_SHIFT - PAGE_SHIFT);
+ start_pfn = round_up(pfn, PFN_DOWN(PUD_SIZE));
+ end_pfn = round_down(limit_pfn, PFN_DOWN(PUD_SIZE));
if (start_pfn < end_pfn) {
nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
page_size_mask &
((1<<PG_LEVEL_2M)|(1<<PG_LEVEL_1G)));
- pos = end_pfn << PAGE_SHIFT;
+ pfn = end_pfn;
}
/* tail is not big page (1G) alignment */
- start_pfn = ((pos + (PMD_SIZE - 1))>>PMD_SHIFT)
- << (PMD_SHIFT - PAGE_SHIFT);
- end_pfn = (end >> PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT);
+ start_pfn = round_up(pfn, PFN_DOWN(PMD_SIZE));
+ end_pfn = round_down(limit_pfn, PFN_DOWN(PMD_SIZE));
if (start_pfn < end_pfn) {
nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
page_size_mask & (1<<PG_LEVEL_2M));
- pos = end_pfn << PAGE_SHIFT;
+ pfn = end_pfn;
}
#endif
/* tail is not big page (2M) alignment */
- start_pfn = pos>>PAGE_SHIFT;
- end_pfn = end>>PAGE_SHIFT;
+ start_pfn = pfn;
+ end_pfn = limit_pfn;
nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0);
/* try to merge same page size and continuous */
@@ -257,59 +291,169 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
nr_range--;
}
+ if (!after_bootmem)
+ adjust_range_page_size_mask(mr, nr_range);
+
for (i = 0; i < nr_range; i++)
printk(KERN_DEBUG " [mem %#010lx-%#010lx] page %s\n",
mr[i].start, mr[i].end - 1,
(mr[i].page_size_mask & (1<<PG_LEVEL_1G))?"1G":(
(mr[i].page_size_mask & (1<<PG_LEVEL_2M))?"2M":"4k"));
- /*
- * Find space for the kernel direct mapping tables.
- *
- * Later we should allocate these tables in the local node of the
- * memory mapped. Unfortunately this is done currently before the
- * nodes are discovered.
- */
- if (!after_bootmem)
- find_early_table_space(mr, nr_range);
+ return nr_range;
+}
+
+struct range pfn_mapped[E820_X_MAX];
+int nr_pfn_mapped;
+
+static void add_pfn_range_mapped(unsigned long start_pfn, unsigned long end_pfn)
+{
+ nr_pfn_mapped = add_range_with_merge(pfn_mapped, E820_X_MAX,
+ nr_pfn_mapped, start_pfn, end_pfn);
+ nr_pfn_mapped = clean_sort_range(pfn_mapped, E820_X_MAX);
+
+ max_pfn_mapped = max(max_pfn_mapped, end_pfn);
+
+ if (start_pfn < (1UL<<(32-PAGE_SHIFT)))
+ max_low_pfn_mapped = max(max_low_pfn_mapped,
+ min(end_pfn, 1UL<<(32-PAGE_SHIFT)));
+}
+
+bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn)
+{
+ int i;
+
+ for (i = 0; i < nr_pfn_mapped; i++)
+ if ((start_pfn >= pfn_mapped[i].start) &&
+ (end_pfn <= pfn_mapped[i].end))
+ return true;
+
+ return false;
+}
+
+/*
+ * Setup the direct mapping of the physical memory at PAGE_OFFSET.
+ * This runs before bootmem is initialized and gets pages directly from
+ * the physical memory. To access them they are temporarily mapped.
+ */
+unsigned long __init_refok init_memory_mapping(unsigned long start,
+ unsigned long end)
+{
+ struct map_range mr[NR_RANGE_MR];
+ unsigned long ret = 0;
+ int nr_range, i;
+
+ pr_info("init_memory_mapping: [mem %#010lx-%#010lx]\n",
+ start, end - 1);
+
+ memset(mr, 0, sizeof(mr));
+ nr_range = split_mem_range(mr, 0, start, end);
for (i = 0; i < nr_range; i++)
ret = kernel_physical_mapping_init(mr[i].start, mr[i].end,
mr[i].page_size_mask);
-#ifdef CONFIG_X86_32
- early_ioremap_page_table_range_init();
+ add_pfn_range_mapped(start >> PAGE_SHIFT, ret >> PAGE_SHIFT);
- load_cr3(swapper_pg_dir);
-#endif
+ return ret >> PAGE_SHIFT;
+}
- __flush_tlb_all();
+/*
+ * would have hole in the middle or ends, and only ram parts will be mapped.
+ */
+static unsigned long __init init_range_memory_mapping(
+ unsigned long r_start,
+ unsigned long r_end)
+{
+ unsigned long start_pfn, end_pfn;
+ unsigned long mapped_ram_size = 0;
+ int i;
- /*
- * Reserve the kernel pagetable pages we used (pgt_buf_start -
- * pgt_buf_end) and free the other ones (pgt_buf_end - pgt_buf_top)
- * so that they can be reused for other purposes.
- *
- * On native it just means calling memblock_reserve, on Xen it also
- * means marking RW the pagetable pages that we allocated before
- * but that haven't been used.
- *
- * In fact on xen we mark RO the whole range pgt_buf_start -
- * pgt_buf_top, because we have to make sure that when
- * init_memory_mapping reaches the pagetable pages area, it maps
- * RO all the pagetable pages, including the ones that are beyond
- * pgt_buf_end at that time.
- */
- if (!after_bootmem && pgt_buf_end > pgt_buf_start)
- x86_init.mapping.pagetable_reserve(PFN_PHYS(pgt_buf_start),
- PFN_PHYS(pgt_buf_end));
+ for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, NULL) {
+ u64 start = clamp_val(PFN_PHYS(start_pfn), r_start, r_end);
+ u64 end = clamp_val(PFN_PHYS(end_pfn), r_start, r_end);
+ if (start >= end)
+ continue;
- if (!after_bootmem)
- early_memtest(start, end);
+ /*
+ * if it is overlapping with brk pgt, we need to
+ * alloc pgt buf from memblock instead.
+ */
+ can_use_brk_pgt = max(start, (u64)pgt_buf_end<<PAGE_SHIFT) >=
+ min(end, (u64)pgt_buf_top<<PAGE_SHIFT);
+ init_memory_mapping(start, end);
+ mapped_ram_size += end - start;
+ can_use_brk_pgt = true;
+ }
- return ret >> PAGE_SHIFT;
+ return mapped_ram_size;
}
+/* (PUD_SHIFT-PMD_SHIFT)/2 */
+#define STEP_SIZE_SHIFT 5
+void __init init_mem_mapping(void)
+{
+ unsigned long end, real_end, start, last_start;
+ unsigned long step_size;
+ unsigned long addr;
+ unsigned long mapped_ram_size = 0;
+ unsigned long new_mapped_ram_size;
+
+ probe_page_size_mask();
+
+#ifdef CONFIG_X86_64
+ end = max_pfn << PAGE_SHIFT;
+#else
+ end = max_low_pfn << PAGE_SHIFT;
+#endif
+
+ /* the ISA range is always mapped regardless of memory holes */
+ init_memory_mapping(0, ISA_END_ADDRESS);
+
+ /* xen has big range in reserved near end of ram, skip it at first */
+ addr = memblock_find_in_range(ISA_END_ADDRESS, end, PMD_SIZE,
+ PAGE_SIZE);
+ real_end = addr + PMD_SIZE;
+
+ /* step_size need to be small so pgt_buf from BRK could cover it */
+ step_size = PMD_SIZE;
+ max_pfn_mapped = 0; /* will get exact value next */
+ min_pfn_mapped = real_end >> PAGE_SHIFT;
+ last_start = start = real_end;
+ while (last_start > ISA_END_ADDRESS) {
+ if (last_start > step_size) {
+ start = round_down(last_start - 1, step_size);
+ if (start < ISA_END_ADDRESS)
+ start = ISA_END_ADDRESS;
+ } else
+ start = ISA_END_ADDRESS;
+ new_mapped_ram_size = init_range_memory_mapping(start,
+ last_start);
+ last_start = start;
+ min_pfn_mapped = last_start >> PAGE_SHIFT;
+ /* only increase step_size after big range get mapped */
+ if (new_mapped_ram_size > mapped_ram_size)
+ step_size <<= STEP_SIZE_SHIFT;
+ mapped_ram_size += new_mapped_ram_size;
+ }
+
+ if (real_end < end)
+ init_range_memory_mapping(real_end, end);
+
+#ifdef CONFIG_X86_64
+ if (max_pfn > max_low_pfn) {
+ /* can we preseve max_low_pfn ?*/
+ max_low_pfn = max_pfn;
+ }
+#else
+ early_ioremap_page_table_range_init();
+#endif
+
+ load_cr3(swapper_pg_dir);
+ __flush_tlb_all();
+
+ early_memtest(0, max_pfn_mapped << PAGE_SHIFT);
+}
/*
* devmem_is_allowed() checks to see if /dev/mem access to a certain address
@@ -391,6 +535,15 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
+#ifdef CONFIG_MICROCODE_EARLY
+ /*
+ * Remember, initrd memory may contain microcode or other useful things.
+ * Before we lose initrd mem, we need to find a place to hold them
+ * now that normal virtual memory is enabled.
+ */
+ save_microcode_in_initrd();
+#endif
+
/*
* end could be not aligned, and We can not align that,
* decompresser could be confused by aligned initrd_end
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 745d66b843c8..2d19001151d5 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -53,25 +53,14 @@
#include <asm/page_types.h>
#include <asm/init.h>
+#include "mm_internal.h"
+
unsigned long highstart_pfn, highend_pfn;
static noinline int do_test_wp_bit(void);
bool __read_mostly __vmalloc_start_set = false;
-static __init void *alloc_low_page(void)
-{
- unsigned long pfn = pgt_buf_end++;
- void *adr;
-
- if (pfn >= pgt_buf_top)
- panic("alloc_low_page: ran out of memory");
-
- adr = __va(pfn * PAGE_SIZE);
- clear_page(adr);
- return adr;
-}
-
/*
* Creates a middle page table and puts a pointer to it in the
* given global directory entry. This only returns the gd entry
@@ -84,10 +73,7 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd)
#ifdef CONFIG_X86_PAE
if (!(pgd_val(*pgd) & _PAGE_PRESENT)) {
- if (after_bootmem)
- pmd_table = (pmd_t *)alloc_bootmem_pages(PAGE_SIZE);
- else
- pmd_table = (pmd_t *)alloc_low_page();
+ pmd_table = (pmd_t *)alloc_low_page();
paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT);
set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
pud = pud_offset(pgd, 0);
@@ -109,17 +95,7 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd)
static pte_t * __init one_page_table_init(pmd_t *pmd)
{
if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
- pte_t *page_table = NULL;
-
- if (after_bootmem) {
-#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KMEMCHECK)
- page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
-#endif
- if (!page_table)
- page_table =
- (pte_t *)alloc_bootmem_pages(PAGE_SIZE);
- } else
- page_table = (pte_t *)alloc_low_page();
+ pte_t *page_table = (pte_t *)alloc_low_page();
paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT);
set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
@@ -146,8 +122,39 @@ pte_t * __init populate_extra_pte(unsigned long vaddr)
return one_page_table_init(pmd) + pte_idx;
}
+static unsigned long __init
+page_table_range_init_count(unsigned long start, unsigned long end)
+{
+ unsigned long count = 0;
+#ifdef CONFIG_HIGHMEM
+ int pmd_idx_kmap_begin = fix_to_virt(FIX_KMAP_END) >> PMD_SHIFT;
+ int pmd_idx_kmap_end = fix_to_virt(FIX_KMAP_BEGIN) >> PMD_SHIFT;
+ int pgd_idx, pmd_idx;
+ unsigned long vaddr;
+
+ if (pmd_idx_kmap_begin == pmd_idx_kmap_end)
+ return 0;
+
+ vaddr = start;
+ pgd_idx = pgd_index(vaddr);
+
+ for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd_idx++) {
+ for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end);
+ pmd_idx++) {
+ if ((vaddr >> PMD_SHIFT) >= pmd_idx_kmap_begin &&
+ (vaddr >> PMD_SHIFT) <= pmd_idx_kmap_end)
+ count++;
+ vaddr += PMD_SIZE;
+ }
+ pmd_idx = 0;
+ }
+#endif
+ return count;
+}
+
static pte_t *__init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
- unsigned long vaddr, pte_t *lastpte)
+ unsigned long vaddr, pte_t *lastpte,
+ void **adr)
{
#ifdef CONFIG_HIGHMEM
/*
@@ -161,16 +168,15 @@ static pte_t *__init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
if (pmd_idx_kmap_begin != pmd_idx_kmap_end
&& (vaddr >> PMD_SHIFT) >= pmd_idx_kmap_begin
- && (vaddr >> PMD_SHIFT) <= pmd_idx_kmap_end
- && ((__pa(pte) >> PAGE_SHIFT) < pgt_buf_start
- || (__pa(pte) >> PAGE_SHIFT) >= pgt_buf_end)) {
+ && (vaddr >> PMD_SHIFT) <= pmd_idx_kmap_end) {
pte_t *newpte;
int i;
BUG_ON(after_bootmem);
- newpte = alloc_low_page();
+ newpte = *adr;
for (i = 0; i < PTRS_PER_PTE; i++)
set_pte(newpte + i, pte[i]);
+ *adr = (void *)(((unsigned long)(*adr)) + PAGE_SIZE);
paravirt_alloc_pte(&init_mm, __pa(newpte) >> PAGE_SHIFT);
set_pmd(pmd, __pmd(__pa(newpte)|_PAGE_TABLE));
@@ -204,6 +210,11 @@ page_table_range_init(unsigned long start, unsigned long end, pgd_t *pgd_base)
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte = NULL;
+ unsigned long count = page_table_range_init_count(start, end);
+ void *adr = NULL;
+
+ if (count)
+ adr = alloc_low_pages(count);
vaddr = start;
pgd_idx = pgd_index(vaddr);
@@ -216,7 +227,7 @@ page_table_range_init(unsigned long start, unsigned long end, pgd_t *pgd_base)
for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end);
pmd++, pmd_idx++) {
pte = page_table_kmap_check(one_page_table_init(pmd),
- pmd, vaddr, pte);
+ pmd, vaddr, pte, &adr);
vaddr += PMD_SIZE;
}
@@ -310,6 +321,7 @@ repeat:
__pgprot(PTE_IDENT_ATTR |
_PAGE_PSE);
+ pfn &= PMD_MASK >> PAGE_SHIFT;
addr2 = (pfn + PTRS_PER_PTE-1) * PAGE_SIZE +
PAGE_OFFSET + PAGE_SIZE-1;
@@ -455,9 +467,14 @@ void __init native_pagetable_init(void)
/*
* Remove any mappings which extend past the end of physical
- * memory from the boot time page table:
+ * memory from the boot time page table.
+ * In virtual address space, we should have at least two pages
+ * from VMALLOC_END to pkmap or fixmap according to VMALLOC_END
+ * definition. And max_low_pfn is set to VMALLOC_END physical
+ * address. If initial memory mapping is doing right job, we
+ * should have pte used near max_low_pfn or one pmd is not present.
*/
- for (pfn = max_low_pfn + 1; pfn < 1<<(32-PAGE_SHIFT); pfn++) {
+ for (pfn = max_low_pfn; pfn < 1<<(32-PAGE_SHIFT); pfn++) {
va = PAGE_OFFSET + (pfn<<PAGE_SHIFT);
pgd = base + pgd_index(va);
if (!pgd_present(*pgd))
@@ -468,10 +485,19 @@ void __init native_pagetable_init(void)
if (!pmd_present(*pmd))
break;
+ /* should not be large page here */
+ if (pmd_large(*pmd)) {
+ pr_warn("try to clear pte for ram above max_low_pfn: pfn: %lx pmd: %p pmd phys: %lx, but pmd is big page and is not using pte !\n",
+ pfn, pmd, __pa(pmd));
+ BUG_ON(1);
+ }
+
pte = pte_offset_kernel(pmd, va);
if (!pte_present(*pte))
break;
+ printk(KERN_DEBUG "clearing pte for ram above max_low_pfn: pfn: %lx pmd: %p pmd phys: %lx pte: %p pte phys: %lx\n",
+ pfn, pmd, __pa(pmd), pte, __pa(pte));
pte_clear(NULL, va, pte);
}
paravirt_alloc_pmd(&init_mm, __pa(base) >> PAGE_SHIFT);
@@ -550,7 +576,7 @@ early_param("highmem", parse_highmem);
* artificially via the highmem=x boot parameter then create
* it:
*/
-void __init lowmem_pfn_init(void)
+static void __init lowmem_pfn_init(void)
{
/* max_low_pfn is 0, we already have early_res support */
max_low_pfn = max_pfn;
@@ -586,7 +612,7 @@ void __init lowmem_pfn_init(void)
* We have more RAM than fits into lowmem - we try to put it into
* highmem, also taking the highmem=x boot parameter into account:
*/
-void __init highmem_pfn_init(void)
+static void __init highmem_pfn_init(void)
{
max_low_pfn = MAXMEM_PFN;
@@ -669,8 +695,6 @@ void __init setup_bootmem_allocator(void)
printk(KERN_INFO " mapped low ram: 0 - %08lx\n",
max_pfn_mapped<<PAGE_SHIFT);
printk(KERN_INFO " low ram: 0 - %08lx\n", max_low_pfn<<PAGE_SHIFT);
-
- after_bootmem = 1;
}
/*
@@ -753,6 +777,8 @@ void __init mem_init(void)
if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
reservedpages++;
+ after_bootmem = 1;
+
codesize = (unsigned long) &_etext - (unsigned long) &_text;
datasize = (unsigned long) &_edata - (unsigned long) &_etext;
initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
@@ -836,6 +862,18 @@ int arch_add_memory(int nid, u64 start, u64 size)
return __add_pages(nid, zone, start_pfn, nr_pages);
}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long nr_pages = size >> PAGE_SHIFT;
+ struct zone *zone;
+
+ zone = page_zone(pfn_to_page(start_pfn));
+ return __remove_pages(zone, start_pfn, nr_pages);
+}
+#endif
#endif
/*
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 2ead3c8a4c84..474e28f10815 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -54,6 +54,82 @@
#include <asm/uv/uv.h>
#include <asm/setup.h>
+#include "mm_internal.h"
+
+static void ident_pmd_init(unsigned long pmd_flag, pmd_t *pmd_page,
+ unsigned long addr, unsigned long end)
+{
+ addr &= PMD_MASK;
+ for (; addr < end; addr += PMD_SIZE) {
+ pmd_t *pmd = pmd_page + pmd_index(addr);
+
+ if (!pmd_present(*pmd))
+ set_pmd(pmd, __pmd(addr | pmd_flag));
+ }
+}
+static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
+ unsigned long addr, unsigned long end)
+{
+ unsigned long next;
+
+ for (; addr < end; addr = next) {
+ pud_t *pud = pud_page + pud_index(addr);
+ pmd_t *pmd;
+
+ next = (addr & PUD_MASK) + PUD_SIZE;
+ if (next > end)
+ next = end;
+
+ if (pud_present(*pud)) {
+ pmd = pmd_offset(pud, 0);
+ ident_pmd_init(info->pmd_flag, pmd, addr, next);
+ continue;
+ }
+ pmd = (pmd_t *)info->alloc_pgt_page(info->context);
+ if (!pmd)
+ return -ENOMEM;
+ ident_pmd_init(info->pmd_flag, pmd, addr, next);
+ set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
+ }
+
+ return 0;
+}
+
+int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
+ unsigned long addr, unsigned long end)
+{
+ unsigned long next;
+ int result;
+ int off = info->kernel_mapping ? pgd_index(__PAGE_OFFSET) : 0;
+
+ for (; addr < end; addr = next) {
+ pgd_t *pgd = pgd_page + pgd_index(addr) + off;
+ pud_t *pud;
+
+ next = (addr & PGDIR_MASK) + PGDIR_SIZE;
+ if (next > end)
+ next = end;
+
+ if (pgd_present(*pgd)) {
+ pud = pud_offset(pgd, 0);
+ result = ident_pud_init(info, pud, addr, next);
+ if (result)
+ return result;
+ continue;
+ }
+
+ pud = (pud_t *)info->alloc_pgt_page(info->context);
+ if (!pud)
+ return -ENOMEM;
+ result = ident_pud_init(info, pud, addr, next);
+ if (result)
+ return result;
+ set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
+ }
+
+ return 0;
+}
+
static int __init parse_direct_gbpages_off(char *arg)
{
direct_gbpages = 0;
@@ -302,10 +378,18 @@ void __init init_extra_mapping_uc(unsigned long phys, unsigned long size)
void __init cleanup_highmap(void)
{
unsigned long vaddr = __START_KERNEL_map;
- unsigned long vaddr_end = __START_KERNEL_map + (max_pfn_mapped << PAGE_SHIFT);
+ unsigned long vaddr_end = __START_KERNEL_map + KERNEL_IMAGE_SIZE;
unsigned long end = roundup((unsigned long)_brk_end, PMD_SIZE) - 1;
pmd_t *pmd = level2_kernel_pgt;
+ /*
+ * Native path, max_pfn_mapped is not set yet.
+ * Xen has valid max_pfn_mapped set in
+ * arch/x86/xen/mmu.c:xen_setup_kernel_pagetable().
+ */
+ if (max_pfn_mapped)
+ vaddr_end = __START_KERNEL_map + (max_pfn_mapped << PAGE_SHIFT);
+
for (; vaddr + PMD_SIZE - 1 < vaddr_end; pmd++, vaddr += PMD_SIZE) {
if (pmd_none(*pmd))
continue;
@@ -314,69 +398,24 @@ void __init cleanup_highmap(void)
}
}
-static __ref void *alloc_low_page(unsigned long *phys)
-{
- unsigned long pfn = pgt_buf_end++;
- void *adr;
-
- if (after_bootmem) {
- adr = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_NOTRACK);
- *phys = __pa(adr);
-
- return adr;
- }
-
- if (pfn >= pgt_buf_top)
- panic("alloc_low_page: ran out of memory");
-
- adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE);
- clear_page(adr);
- *phys = pfn * PAGE_SIZE;
- return adr;
-}
-
-static __ref void *map_low_page(void *virt)
-{
- void *adr;
- unsigned long phys, left;
-
- if (after_bootmem)
- return virt;
-
- phys = __pa(virt);
- left = phys & (PAGE_SIZE - 1);
- adr = early_memremap(phys & PAGE_MASK, PAGE_SIZE);
- adr = (void *)(((unsigned long)adr) | left);
-
- return adr;
-}
-
-static __ref void unmap_low_page(void *adr)
-{
- if (after_bootmem)
- return;
-
- early_iounmap((void *)((unsigned long)adr & PAGE_MASK), PAGE_SIZE);
-}
-
static unsigned long __meminit
phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end,
pgprot_t prot)
{
- unsigned pages = 0;
+ unsigned long pages = 0, next;
unsigned long last_map_addr = end;
int i;
pte_t *pte = pte_page + pte_index(addr);
- for(i = pte_index(addr); i < PTRS_PER_PTE; i++, addr += PAGE_SIZE, pte++) {
-
+ for (i = pte_index(addr); i < PTRS_PER_PTE; i++, addr = next, pte++) {
+ next = (addr & PAGE_MASK) + PAGE_SIZE;
if (addr >= end) {
- if (!after_bootmem) {
- for(; i < PTRS_PER_PTE; i++, pte++)
- set_pte(pte, __pte(0));
- }
- break;
+ if (!after_bootmem &&
+ !e820_any_mapped(addr & PAGE_MASK, next, E820_RAM) &&
+ !e820_any_mapped(addr & PAGE_MASK, next, E820_RESERVED_KERN))
+ set_pte(pte, __pte(0));
+ continue;
}
/*
@@ -414,28 +453,25 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
int i = pmd_index(address);
for (; i < PTRS_PER_PMD; i++, address = next) {
- unsigned long pte_phys;
pmd_t *pmd = pmd_page + pmd_index(address);
pte_t *pte;
pgprot_t new_prot = prot;
+ next = (address & PMD_MASK) + PMD_SIZE;
if (address >= end) {
- if (!after_bootmem) {
- for (; i < PTRS_PER_PMD; i++, pmd++)
- set_pmd(pmd, __pmd(0));
- }
- break;
+ if (!after_bootmem &&
+ !e820_any_mapped(address & PMD_MASK, next, E820_RAM) &&
+ !e820_any_mapped(address & PMD_MASK, next, E820_RESERVED_KERN))
+ set_pmd(pmd, __pmd(0));
+ continue;
}
- next = (address & PMD_MASK) + PMD_SIZE;
-
if (pmd_val(*pmd)) {
if (!pmd_large(*pmd)) {
spin_lock(&init_mm.page_table_lock);
- pte = map_low_page((pte_t *)pmd_page_vaddr(*pmd));
+ pte = (pte_t *)pmd_page_vaddr(*pmd);
last_map_addr = phys_pte_init(pte, address,
end, prot);
- unmap_low_page(pte);
spin_unlock(&init_mm.page_table_lock);
continue;
}
@@ -464,19 +500,18 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
pages++;
spin_lock(&init_mm.page_table_lock);
set_pte((pte_t *)pmd,
- pfn_pte(address >> PAGE_SHIFT,
+ pfn_pte((address & PMD_MASK) >> PAGE_SHIFT,
__pgprot(pgprot_val(prot) | _PAGE_PSE)));
spin_unlock(&init_mm.page_table_lock);
last_map_addr = next;
continue;
}
- pte = alloc_low_page(&pte_phys);
+ pte = alloc_low_page();
last_map_addr = phys_pte_init(pte, address, end, new_prot);
- unmap_low_page(pte);
spin_lock(&init_mm.page_table_lock);
- pmd_populate_kernel(&init_mm, pmd, __va(pte_phys));
+ pmd_populate_kernel(&init_mm, pmd, pte);
spin_unlock(&init_mm.page_table_lock);
}
update_page_count(PG_LEVEL_2M, pages);
@@ -492,27 +527,24 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
int i = pud_index(addr);
for (; i < PTRS_PER_PUD; i++, addr = next) {
- unsigned long pmd_phys;
pud_t *pud = pud_page + pud_index(addr);
pmd_t *pmd;
pgprot_t prot = PAGE_KERNEL;
- if (addr >= end)
- break;
-
next = (addr & PUD_MASK) + PUD_SIZE;
-
- if (!after_bootmem && !e820_any_mapped(addr, next, 0)) {
- set_pud(pud, __pud(0));
+ if (addr >= end) {
+ if (!after_bootmem &&
+ !e820_any_mapped(addr & PUD_MASK, next, E820_RAM) &&
+ !e820_any_mapped(addr & PUD_MASK, next, E820_RESERVED_KERN))
+ set_pud(pud, __pud(0));
continue;
}
if (pud_val(*pud)) {
if (!pud_large(*pud)) {
- pmd = map_low_page(pmd_offset(pud, 0));
+ pmd = pmd_offset(pud, 0);
last_map_addr = phys_pmd_init(pmd, addr, end,
page_size_mask, prot);
- unmap_low_page(pmd);
__flush_tlb_all();
continue;
}
@@ -541,19 +573,19 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
pages++;
spin_lock(&init_mm.page_table_lock);
set_pte((pte_t *)pud,
- pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
+ pfn_pte((addr & PUD_MASK) >> PAGE_SHIFT,
+ PAGE_KERNEL_LARGE));
spin_unlock(&init_mm.page_table_lock);
last_map_addr = next;
continue;
}
- pmd = alloc_low_page(&pmd_phys);
+ pmd = alloc_low_page();
last_map_addr = phys_pmd_init(pmd, addr, end, page_size_mask,
prot);
- unmap_low_page(pmd);
spin_lock(&init_mm.page_table_lock);
- pud_populate(&init_mm, pud, __va(pmd_phys));
+ pud_populate(&init_mm, pud, pmd);
spin_unlock(&init_mm.page_table_lock);
}
__flush_tlb_all();
@@ -578,34 +610,29 @@ kernel_physical_mapping_init(unsigned long start,
for (; start < end; start = next) {
pgd_t *pgd = pgd_offset_k(start);
- unsigned long pud_phys;
pud_t *pud;
- next = (start + PGDIR_SIZE) & PGDIR_MASK;
- if (next > end)
- next = end;
+ next = (start & PGDIR_MASK) + PGDIR_SIZE;
if (pgd_val(*pgd)) {
- pud = map_low_page((pud_t *)pgd_page_vaddr(*pgd));
+ pud = (pud_t *)pgd_page_vaddr(*pgd);
last_map_addr = phys_pud_init(pud, __pa(start),
__pa(end), page_size_mask);
- unmap_low_page(pud);
continue;
}
- pud = alloc_low_page(&pud_phys);
- last_map_addr = phys_pud_init(pud, __pa(start), __pa(next),
+ pud = alloc_low_page();
+ last_map_addr = phys_pud_init(pud, __pa(start), __pa(end),
page_size_mask);
- unmap_low_page(pud);
spin_lock(&init_mm.page_table_lock);
- pgd_populate(&init_mm, pgd, __va(pud_phys));
+ pgd_populate(&init_mm, pgd, pud);
spin_unlock(&init_mm.page_table_lock);
pgd_changed = true;
}
if (pgd_changed)
- sync_global_pgds(addr, end);
+ sync_global_pgds(addr, end - 1);
__flush_tlb_all();
@@ -664,13 +691,11 @@ int arch_add_memory(int nid, u64 start, u64 size)
{
struct pglist_data *pgdat = NODE_DATA(nid);
struct zone *zone = pgdat->node_zones + ZONE_NORMAL;
- unsigned long last_mapped_pfn, start_pfn = start >> PAGE_SHIFT;
+ unsigned long start_pfn = start >> PAGE_SHIFT;
unsigned long nr_pages = size >> PAGE_SHIFT;
int ret;
- last_mapped_pfn = init_memory_mapping(start, start + size);
- if (last_mapped_pfn > max_pfn_mapped)
- max_pfn_mapped = last_mapped_pfn;
+ init_memory_mapping(start, start + size);
ret = __add_pages(nid, zone, start_pfn, nr_pages);
WARN_ON_ONCE(ret);
@@ -682,10 +707,357 @@ int arch_add_memory(int nid, u64 start, u64 size)
}
EXPORT_SYMBOL_GPL(arch_add_memory);
+#define PAGE_INUSE 0xFD
+
+static void __meminit free_pagetable(struct page *page, int order)
+{
+ struct zone *zone;
+ bool bootmem = false;
+ unsigned long magic;
+ unsigned int nr_pages = 1 << order;
+
+ /* bootmem page has reserved flag */
+ if (PageReserved(page)) {
+ __ClearPageReserved(page);
+ bootmem = true;
+
+ magic = (unsigned long)page->lru.next;
+ if (magic == SECTION_INFO || magic == MIX_SECTION_INFO) {
+ while (nr_pages--)
+ put_page_bootmem(page++);
+ } else
+ __free_pages_bootmem(page, order);
+ } else
+ free_pages((unsigned long)page_address(page), order);
+
+ /*
+ * SECTION_INFO pages and MIX_SECTION_INFO pages
+ * are all allocated by bootmem.
+ */
+ if (bootmem) {
+ zone = page_zone(page);
+ zone_span_writelock(zone);
+ zone->present_pages += nr_pages;
+ zone_span_writeunlock(zone);
+ totalram_pages += nr_pages;
+ }
+}
+
+static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd)
+{
+ pte_t *pte;
+ int i;
+
+ for (i = 0; i < PTRS_PER_PTE; i++) {
+ pte = pte_start + i;
+ if (pte_val(*pte))
+ return;
+ }
+
+ /* free a pte talbe */
+ free_pagetable(pmd_page(*pmd), 0);
+ spin_lock(&init_mm.page_table_lock);
+ pmd_clear(pmd);
+ spin_unlock(&init_mm.page_table_lock);
+}
+
+static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud)
+{
+ pmd_t *pmd;
+ int i;
+
+ for (i = 0; i < PTRS_PER_PMD; i++) {
+ pmd = pmd_start + i;
+ if (pmd_val(*pmd))
+ return;
+ }
+
+ /* free a pmd talbe */
+ free_pagetable(pud_page(*pud), 0);
+ spin_lock(&init_mm.page_table_lock);
+ pud_clear(pud);
+ spin_unlock(&init_mm.page_table_lock);
+}
+
+/* Return true if pgd is changed, otherwise return false. */
+static bool __meminit free_pud_table(pud_t *pud_start, pgd_t *pgd)
+{
+ pud_t *pud;
+ int i;
+
+ for (i = 0; i < PTRS_PER_PUD; i++) {
+ pud = pud_start + i;
+ if (pud_val(*pud))
+ return false;
+ }
+
+ /* free a pud table */
+ free_pagetable(pgd_page(*pgd), 0);
+ spin_lock(&init_mm.page_table_lock);
+ pgd_clear(pgd);
+ spin_unlock(&init_mm.page_table_lock);
+
+ return true;
+}
+
+static void __meminit
+remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end,
+ bool direct)
+{
+ unsigned long next, pages = 0;
+ pte_t *pte;
+ void *page_addr;
+ phys_addr_t phys_addr;
+
+ pte = pte_start + pte_index(addr);
+ for (; addr < end; addr = next, pte++) {
+ next = (addr + PAGE_SIZE) & PAGE_MASK;
+ if (next > end)
+ next = end;
+
+ if (!pte_present(*pte))
+ continue;
+
+ /*
+ * We mapped [0,1G) memory as identity mapping when
+ * initializing, in arch/x86/kernel/head_64.S. These
+ * pagetables cannot be removed.
+ */
+ phys_addr = pte_val(*pte) + (addr & PAGE_MASK);
+ if (phys_addr < (phys_addr_t)0x40000000)
+ return;
+
+ if (IS_ALIGNED(addr, PAGE_SIZE) &&
+ IS_ALIGNED(next, PAGE_SIZE)) {
+ /*
+ * Do not free direct mapping pages since they were
+ * freed when offlining, or simplely not in use.
+ */
+ if (!direct)
+ free_pagetable(pte_page(*pte), 0);
+
+ spin_lock(&init_mm.page_table_lock);
+ pte_clear(&init_mm, addr, pte);
+ spin_unlock(&init_mm.page_table_lock);
+
+ /* For non-direct mapping, pages means nothing. */
+ pages++;
+ } else {
+ /*
+ * If we are here, we are freeing vmemmap pages since
+ * direct mapped memory ranges to be freed are aligned.
+ *
+ * If we are not removing the whole page, it means
+ * other page structs in this page are being used and
+ * we canot remove them. So fill the unused page_structs
+ * with 0xFD, and remove the page when it is wholly
+ * filled with 0xFD.
+ */
+ memset((void *)addr, PAGE_INUSE, next - addr);
+
+ page_addr = page_address(pte_page(*pte));
+ if (!memchr_inv(page_addr, PAGE_INUSE, PAGE_SIZE)) {
+ free_pagetable(pte_page(*pte), 0);
+
+ spin_lock(&init_mm.page_table_lock);
+ pte_clear(&init_mm, addr, pte);
+ spin_unlock(&init_mm.page_table_lock);
+ }
+ }
+ }
+
+ /* Call free_pte_table() in remove_pmd_table(). */
+ flush_tlb_all();
+ if (direct)
+ update_page_count(PG_LEVEL_4K, -pages);
+}
+
+static void __meminit
+remove_pmd_table(pmd_t *pmd_start, unsigned long addr, unsigned long end,
+ bool direct)
+{
+ unsigned long next, pages = 0;
+ pte_t *pte_base;
+ pmd_t *pmd;
+ void *page_addr;
+
+ pmd = pmd_start + pmd_index(addr);
+ for (; addr < end; addr = next, pmd++) {
+ next = pmd_addr_end(addr, end);
+
+ if (!pmd_present(*pmd))
+ continue;
+
+ if (pmd_large(*pmd)) {
+ if (IS_ALIGNED(addr, PMD_SIZE) &&
+ IS_ALIGNED(next, PMD_SIZE)) {
+ if (!direct)
+ free_pagetable(pmd_page(*pmd),
+ get_order(PMD_SIZE));
+
+ spin_lock(&init_mm.page_table_lock);
+ pmd_clear(pmd);
+ spin_unlock(&init_mm.page_table_lock);
+ pages++;
+ } else {
+ /* If here, we are freeing vmemmap pages. */
+ memset((void *)addr, PAGE_INUSE, next - addr);
+
+ page_addr = page_address(pmd_page(*pmd));
+ if (!memchr_inv(page_addr, PAGE_INUSE,
+ PMD_SIZE)) {
+ free_pagetable(pmd_page(*pmd),
+ get_order(PMD_SIZE));
+
+ spin_lock(&init_mm.page_table_lock);
+ pmd_clear(pmd);
+ spin_unlock(&init_mm.page_table_lock);
+ }
+ }
+
+ continue;
+ }
+
+ pte_base = (pte_t *)pmd_page_vaddr(*pmd);
+ remove_pte_table(pte_base, addr, next, direct);
+ free_pte_table(pte_base, pmd);
+ }
+
+ /* Call free_pmd_table() in remove_pud_table(). */
+ if (direct)
+ update_page_count(PG_LEVEL_2M, -pages);
+}
+
+static void __meminit
+remove_pud_table(pud_t *pud_start, unsigned long addr, unsigned long end,
+ bool direct)
+{
+ unsigned long next, pages = 0;
+ pmd_t *pmd_base;
+ pud_t *pud;
+ void *page_addr;
+
+ pud = pud_start + pud_index(addr);
+ for (; addr < end; addr = next, pud++) {
+ next = pud_addr_end(addr, end);
+
+ if (!pud_present(*pud))
+ continue;
+
+ if (pud_large(*pud)) {
+ if (IS_ALIGNED(addr, PUD_SIZE) &&
+ IS_ALIGNED(next, PUD_SIZE)) {
+ if (!direct)
+ free_pagetable(pud_page(*pud),
+ get_order(PUD_SIZE));
+
+ spin_lock(&init_mm.page_table_lock);
+ pud_clear(pud);
+ spin_unlock(&init_mm.page_table_lock);
+ pages++;
+ } else {
+ /* If here, we are freeing vmemmap pages. */
+ memset((void *)addr, PAGE_INUSE, next - addr);
+
+ page_addr = page_address(pud_page(*pud));
+ if (!memchr_inv(page_addr, PAGE_INUSE,
+ PUD_SIZE)) {
+ free_pagetable(pud_page(*pud),
+ get_order(PUD_SIZE));
+
+ spin_lock(&init_mm.page_table_lock);
+ pud_clear(pud);
+ spin_unlock(&init_mm.page_table_lock);
+ }
+ }
+
+ continue;
+ }
+
+ pmd_base = (pmd_t *)pud_page_vaddr(*pud);
+ remove_pmd_table(pmd_base, addr, next, direct);
+ free_pmd_table(pmd_base, pud);
+ }
+
+ if (direct)
+ update_page_count(PG_LEVEL_1G, -pages);
+}
+
+/* start and end are both virtual address. */
+static void __meminit
+remove_pagetable(unsigned long start, unsigned long end, bool direct)
+{
+ unsigned long next;
+ pgd_t *pgd;
+ pud_t *pud;
+ bool pgd_changed = false;
+
+ for (; start < end; start = next) {
+ next = pgd_addr_end(start, end);
+
+ pgd = pgd_offset_k(start);
+ if (!pgd_present(*pgd))
+ continue;
+
+ pud = (pud_t *)pgd_page_vaddr(*pgd);
+ remove_pud_table(pud, start, next, direct);
+ if (free_pud_table(pud, pgd))
+ pgd_changed = true;
+ }
+
+ if (pgd_changed)
+ sync_global_pgds(start, end - 1);
+
+ flush_tlb_all();
+}
+
+void __ref vmemmap_free(struct page *memmap, unsigned long nr_pages)
+{
+ unsigned long start = (unsigned long)memmap;
+ unsigned long end = (unsigned long)(memmap + nr_pages);
+
+ remove_pagetable(start, end, false);
+}
+
+static void __meminit
+kernel_physical_mapping_remove(unsigned long start, unsigned long end)
+{
+ start = (unsigned long)__va(start);
+ end = (unsigned long)__va(end);
+
+ remove_pagetable(start, end, true);
+}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int __ref arch_remove_memory(u64 start, u64 size)
+{
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long nr_pages = size >> PAGE_SHIFT;
+ struct zone *zone;
+ int ret;
+
+ zone = page_zone(pfn_to_page(start_pfn));
+ kernel_physical_mapping_remove(start, start + size);
+ ret = __remove_pages(zone, start_pfn, nr_pages);
+ WARN_ON_ONCE(ret);
+
+ return ret;
+}
+#endif
#endif /* CONFIG_MEMORY_HOTPLUG */
static struct kcore_list kcore_vsyscall;
+static void __init register_page_bootmem_info(void)
+{
+#ifdef CONFIG_NUMA
+ int i;
+
+ for_each_online_node(i)
+ register_page_bootmem_info_node(NODE_DATA(i));
+#endif
+}
+
void __init mem_init(void)
{
long codesize, reservedpages, datasize, initsize;
@@ -698,11 +1070,8 @@ void __init mem_init(void)
reservedpages = 0;
/* this will put all low memory onto the freelists */
-#ifdef CONFIG_NUMA
- totalram_pages = numa_free_all_bootmem();
-#else
+ register_page_bootmem_info();
totalram_pages = free_all_bootmem();
-#endif
absent_pages = absent_pages_in_range(0, max_pfn);
reservedpages = max_pfn - totalram_pages - absent_pages;
@@ -772,12 +1141,11 @@ void set_kernel_text_ro(void)
void mark_rodata_ro(void)
{
unsigned long start = PFN_ALIGN(_text);
- unsigned long rodata_start =
- ((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
+ unsigned long rodata_start = PFN_ALIGN(__start_rodata);
unsigned long end = (unsigned long) &__end_rodata_hpage_align;
- unsigned long text_end = PAGE_ALIGN((unsigned long) &__stop___ex_table);
- unsigned long rodata_end = PAGE_ALIGN((unsigned long) &__end_rodata);
- unsigned long data_start = (unsigned long) &_sdata;
+ unsigned long text_end = PFN_ALIGN(&__stop___ex_table);
+ unsigned long rodata_end = PFN_ALIGN(&__end_rodata);
+ unsigned long all_end = PFN_ALIGN(&_end);
printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
(end - start) >> 10);
@@ -786,10 +1154,10 @@ void mark_rodata_ro(void)
kernel_set_to_readonly = 1;
/*
- * The rodata section (but not the kernel text!) should also be
- * not-executable.
+ * The rodata/data/bss/brk section (but not the kernel text!)
+ * should also be not-executable.
*/
- set_memory_nx(rodata_start, (end - rodata_start) >> PAGE_SHIFT);
+ set_memory_nx(rodata_start, (all_end - rodata_start) >> PAGE_SHIFT);
rodata_test();
@@ -802,12 +1170,12 @@ void mark_rodata_ro(void)
#endif
free_init_pages("unused kernel memory",
- (unsigned long) page_address(virt_to_page(text_end)),
- (unsigned long)
- page_address(virt_to_page(rodata_start)));
+ (unsigned long) __va(__pa_symbol(text_end)),
+ (unsigned long) __va(__pa_symbol(rodata_start)));
+
free_init_pages("unused kernel memory",
- (unsigned long) page_address(virt_to_page(rodata_end)),
- (unsigned long) page_address(virt_to_page(data_start)));
+ (unsigned long) __va(__pa_symbol(rodata_end)),
+ (unsigned long) __va(__pa_symbol(_sdata)));
}
#endif
@@ -831,6 +1199,9 @@ int kern_addr_valid(unsigned long addr)
if (pud_none(*pud))
return 0;
+ if (pud_large(*pud))
+ return pfn_valid(pud_pfn(*pud));
+
pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd))
return 0;
@@ -981,10 +1352,70 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)
}
}
- sync_global_pgds((unsigned long)start_page, end);
+ sync_global_pgds((unsigned long)start_page, end - 1);
return 0;
}
+#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HAVE_BOOTMEM_INFO_NODE)
+void register_page_bootmem_memmap(unsigned long section_nr,
+ struct page *start_page, unsigned long size)
+{
+ unsigned long addr = (unsigned long)start_page;
+ unsigned long end = (unsigned long)(start_page + size);
+ unsigned long next;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ unsigned int nr_pages;
+ struct page *page;
+
+ for (; addr < end; addr = next) {
+ pte_t *pte = NULL;
+
+ pgd = pgd_offset_k(addr);
+ if (pgd_none(*pgd)) {
+ next = (addr + PAGE_SIZE) & PAGE_MASK;
+ continue;
+ }
+ get_page_bootmem(section_nr, pgd_page(*pgd), MIX_SECTION_INFO);
+
+ pud = pud_offset(pgd, addr);
+ if (pud_none(*pud)) {
+ next = (addr + PAGE_SIZE) & PAGE_MASK;
+ continue;
+ }
+ get_page_bootmem(section_nr, pud_page(*pud), MIX_SECTION_INFO);
+
+ if (!cpu_has_pse) {
+ next = (addr + PAGE_SIZE) & PAGE_MASK;
+ pmd = pmd_offset(pud, addr);
+ if (pmd_none(*pmd))
+ continue;
+ get_page_bootmem(section_nr, pmd_page(*pmd),
+ MIX_SECTION_INFO);
+
+ pte = pte_offset_kernel(pmd, addr);
+ if (pte_none(*pte))
+ continue;
+ get_page_bootmem(section_nr, pte_page(*pte),
+ SECTION_INFO);
+ } else {
+ next = pmd_addr_end(addr, end);
+
+ pmd = pmd_offset(pud, addr);
+ if (pmd_none(*pmd))
+ continue;
+
+ nr_pages = 1 << (get_order(PMD_SIZE));
+ page = pmd_page(*pmd);
+ while (nr_pages--)
+ get_page_bootmem(section_nr, page++,
+ SECTION_INFO);
+ }
+ }
+}
+#endif
+
void __meminit vmemmap_populate_print_last(void)
{
if (p_start) {
diff --git a/arch/x86/mm/memtest.c b/arch/x86/mm/memtest.c
index c80b9fb95734..8dabbed409ee 100644
--- a/arch/x86/mm/memtest.c
+++ b/arch/x86/mm/memtest.c
@@ -9,6 +9,7 @@
#include <linux/memblock.h>
static u64 patterns[] __initdata = {
+ /* The first entry has to be 0 to leave memtest with zeroed memory */
0,
0xffffffffffffffffULL,
0x5555555555555555ULL,
@@ -110,15 +111,8 @@ void __init early_memtest(unsigned long start, unsigned long end)
return;
printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern);
- for (i = 0; i < memtest_pattern; i++) {
+ for (i = memtest_pattern-1; i < UINT_MAX; --i) {
idx = i % ARRAY_SIZE(patterns);
do_one_pass(patterns[idx], start, end);
}
-
- if (idx > 0) {
- printk(KERN_INFO "early_memtest: wipe out "
- "test pattern from memory\n");
- /* additional test with pattern 0 will do this */
- do_one_pass(0, start, end);
- }
}
diff --git a/arch/x86/mm/mm_internal.h b/arch/x86/mm/mm_internal.h
new file mode 100644
index 000000000000..6b563a118891
--- /dev/null
+++ b/arch/x86/mm/mm_internal.h
@@ -0,0 +1,19 @@
+#ifndef __X86_MM_INTERNAL_H
+#define __X86_MM_INTERNAL_H
+
+void *alloc_low_pages(unsigned int num);
+static inline void *alloc_low_page(void)
+{
+ return alloc_low_pages(1);
+}
+
+void early_ioremap_page_table_range_init(void);
+
+unsigned long kernel_physical_mapping_init(unsigned long start,
+ unsigned long end,
+ unsigned long page_size_mask);
+void zone_sizes_init(void);
+
+extern int after_bootmem;
+
+#endif /* __X86_MM_INTERNAL_H */
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c
index 2d125be1bae9..dfd30259eb89 100644
--- a/arch/x86/mm/numa.c
+++ b/arch/x86/mm/numa.c
@@ -56,7 +56,7 @@ early_param("numa", numa_setup);
/*
* apicid, cpu, node mappings
*/
-s16 __apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
+s16 __apicid_to_node[MAX_LOCAL_APIC] = {
[0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
};
@@ -78,7 +78,7 @@ EXPORT_SYMBOL(node_to_cpumask_map);
DEFINE_EARLY_PER_CPU(int, x86_cpu_to_node_map, NUMA_NO_NODE);
EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_node_map);
-void __cpuinit numa_set_node(int cpu, int node)
+void numa_set_node(int cpu, int node)
{
int *cpu_to_node_map = early_per_cpu_ptr(x86_cpu_to_node_map);
@@ -101,7 +101,7 @@ void __cpuinit numa_set_node(int cpu, int node)
set_cpu_numa_node(cpu, node);
}
-void __cpuinit numa_clear_node(int cpu)
+void numa_clear_node(int cpu)
{
numa_set_node(cpu, NUMA_NO_NODE);
}
@@ -193,7 +193,6 @@ int __init numa_add_memblk(int nid, u64 start, u64 end)
static void __init setup_node_data(int nid, u64 start, u64 end)
{
const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
- bool remapped = false;
u64 nd_pa;
void *nd;
int tnid;
@@ -205,37 +204,27 @@ static void __init setup_node_data(int nid, u64 start, u64 end)
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 [mem %#010Lx-%#010Lx]\n",
nid, start, end - 1);
/*
- * Allocate node data. Try remap allocator first, node-local
- * memory and then any node. Never allocate in DMA zone.
+ * Allocate node data. Try 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_alloc_nid(nd_size, SMP_CACHE_BYTES, nid);
- if (!nd_pa) {
- pr_err("Cannot find %zu bytes in node %d\n",
- nd_size, nid);
- return;
- }
- nd = __va(nd_pa);
+ nd_pa = memblock_alloc_try_nid(nd_size, SMP_CACHE_BYTES, nid);
+ if (!nd_pa) {
+ pr_err("Cannot find %zu bytes in any node\n", nd_size);
+ return;
}
+ nd = __va(nd_pa);
/* report and initialize */
- printk(KERN_INFO " NODE_DATA [mem %#010Lx-%#010Lx]%s\n",
- nd_pa, nd_pa + nd_size - 1, remapped ? " (remapped)" : "");
+ printk(KERN_INFO " NODE_DATA [mem %#010Lx-%#010Lx]\n",
+ nd_pa, nd_pa + nd_size - 1);
tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT);
- if (!remapped && tnid != nid)
+ if (tnid != nid)
printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nid, tnid);
node_data[nid] = nd;
@@ -571,10 +560,12 @@ static int __init numa_init(int (*init_func)(void))
for (i = 0; i < MAX_LOCAL_APIC; i++)
set_apicid_to_node(i, NUMA_NO_NODE);
- nodes_clear(numa_nodes_parsed);
+ /*
+ * Do not clear numa_nodes_parsed or zero numa_meminfo here, because
+ * SRAT was parsed earlier in early_parse_srat().
+ */
nodes_clear(node_possible_map);
nodes_clear(node_online_map);
- memset(&numa_meminfo, 0, sizeof(numa_meminfo));
WARN_ON(memblock_set_node(0, ULLONG_MAX, MAX_NUMNODES));
numa_reset_distance();
diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c
index 534255a36b6b..73a6d7395bd3 100644
--- a/arch/x86/mm/numa_32.c
+++ b/arch/x86/mm/numa_32.c
@@ -73,167 +73,6 @@ unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn,
extern unsigned long highend_pfn, highstart_pfn;
-#define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE)
-
-static void *node_remap_start_vaddr[MAX_NUMNODES];
-void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
-
-/*
- * 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];
-
-/**
- * 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])
- return NULL;
-
- node_remap_alloc_vaddr[nid] += size;
- memset(allocation, 0, size);
-
- return allocation;
-}
-
-#ifdef CONFIG_HIBERNATION
-/**
- * resume_map_numa_kva - add KVA mapping to the temporary page tables created
- * during resume from hibernation
- * @pgd_base - temporary resume page directory
- */
-void resume_map_numa_kva(pgd_t *pgd_base)
-{
- int node;
-
- for_each_online_node(node) {
- 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];
- 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 < 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);
- pmd_t *pmd = pmd_offset(pud, vaddr);
-
- set_pmd(pmd, pfn_pmd(start_pfn + pfn,
- PAGE_KERNEL_LARGE_EXEC));
-
- printk(KERN_DEBUG "%s: %08lx -> pfn %08lx\n",
- __func__, vaddr, start_pfn + pfn);
- }
- }
-}
-#endif
-
-/**
- * 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)
-{
- 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;
-
- /*
- * 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) {
- pr_warning("remap_alloc: failed to allocate %lu bytes for node %d\n",
- size, nid);
- return;
- }
- memblock_reserve(node_pa, size);
-
- remap_pa = memblock_find_in_range(min_low_pfn << PAGE_SHIFT,
- max_low_pfn << PAGE_SHIFT,
- size, LARGE_PAGE_BYTES);
- if (!remap_pa) {
- pr_warning("remap_alloc: failed to allocate %lu bytes remap area for node %d\n",
- size, nid);
- memblock_free(node_pa, size);
- return;
- }
- memblock_reserve(remap_pa, size);
- 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)
{
x86_numa_init();
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 92e27119ee1a..9405ffc91502 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -10,16 +10,3 @@ void __init initmem_init(void)
{
x86_numa_init();
}
-
-unsigned long __init numa_free_all_bootmem(void)
-{
- unsigned long pages = 0;
- int i;
-
- for_each_online_node(i)
- pages += free_all_bootmem_node(NODE_DATA(i));
-
- pages += free_low_memory_core_early(MAX_NUMNODES);
-
- return pages;
-}
diff --git a/arch/x86/mm/numa_internal.h b/arch/x86/mm/numa_internal.h
index 7178c3afe05e..ad86ec91e640 100644
--- a/arch/x86/mm/numa_internal.h
+++ b/arch/x86/mm/numa_internal.h
@@ -21,12 +21,6 @@ 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/pageattr.c b/arch/x86/mm/pageattr.c
index a718e0d23503..ca1f1c2bb7be 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -94,12 +94,12 @@ static inline void split_page_count(int level) { }
static inline unsigned long highmap_start_pfn(void)
{
- return __pa(_text) >> PAGE_SHIFT;
+ return __pa_symbol(_text) >> PAGE_SHIFT;
}
static inline unsigned long highmap_end_pfn(void)
{
- return __pa(roundup(_brk_end, PMD_SIZE)) >> PAGE_SHIFT;
+ return __pa_symbol(roundup(_brk_end, PMD_SIZE)) >> PAGE_SHIFT;
}
#endif
@@ -276,8 +276,8 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
* The .rodata section needs to be read-only. Using the pfn
* catches all aliases.
*/
- if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT,
- __pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
+ if (within(pfn, __pa_symbol(__start_rodata) >> PAGE_SHIFT,
+ __pa_symbol(__end_rodata) >> PAGE_SHIFT))
pgprot_val(forbidden) |= _PAGE_RW;
#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
@@ -364,6 +364,37 @@ pte_t *lookup_address(unsigned long address, unsigned int *level)
EXPORT_SYMBOL_GPL(lookup_address);
/*
+ * This is necessary because __pa() does not work on some
+ * kinds of memory, like vmalloc() or the alloc_remap()
+ * areas on 32-bit NUMA systems. The percpu areas can
+ * end up in this kind of memory, for instance.
+ *
+ * This could be optimized, but it is only intended to be
+ * used at inititalization time, and keeping it
+ * unoptimized should increase the testing coverage for
+ * the more obscure platforms.
+ */
+phys_addr_t slow_virt_to_phys(void *__virt_addr)
+{
+ unsigned long virt_addr = (unsigned long)__virt_addr;
+ phys_addr_t phys_addr;
+ unsigned long offset;
+ enum pg_level level;
+ unsigned long psize;
+ unsigned long pmask;
+ pte_t *pte;
+
+ pte = lookup_address(virt_addr, &level);
+ BUG_ON(!pte);
+ psize = page_level_size(level);
+ pmask = page_level_mask(level);
+ offset = virt_addr & ~pmask;
+ phys_addr = pte_pfn(*pte) << PAGE_SHIFT;
+ return (phys_addr | offset);
+}
+EXPORT_SYMBOL_GPL(slow_virt_to_phys);
+
+/*
* Set the new pmd in all the pgds we know about:
*/
static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
@@ -396,7 +427,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
pte_t new_pte, old_pte, *tmp;
pgprot_t old_prot, new_prot, req_prot;
int i, do_split = 1;
- unsigned int level;
+ enum pg_level level;
if (cpa->force_split)
return 1;
@@ -412,15 +443,12 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
switch (level) {
case PG_LEVEL_2M:
- psize = PMD_PAGE_SIZE;
- pmask = PMD_PAGE_MASK;
- break;
#ifdef CONFIG_X86_64
case PG_LEVEL_1G:
- psize = PUD_PAGE_SIZE;
- pmask = PUD_PAGE_MASK;
- break;
#endif
+ psize = page_level_size(level);
+ pmask = page_level_mask(level);
+ break;
default:
do_split = -EINVAL;
goto out_unlock;
@@ -501,21 +529,13 @@ out_unlock:
return do_split;
}
-static int split_large_page(pte_t *kpte, unsigned long address)
+int __split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase)
{
unsigned long pfn, pfninc = 1;
unsigned int i, level;
- pte_t *pbase, *tmp;
+ pte_t *tmp;
pgprot_t ref_prot;
- struct page *base;
-
- if (!debug_pagealloc)
- spin_unlock(&cpa_lock);
- base = alloc_pages(GFP_KERNEL | __GFP_NOTRACK, 0);
- if (!debug_pagealloc)
- spin_lock(&cpa_lock);
- if (!base)
- return -ENOMEM;
+ struct page *base = virt_to_page(pbase);
spin_lock(&pgd_lock);
/*
@@ -523,10 +543,11 @@ static int split_large_page(pte_t *kpte, unsigned long address)
* up for us already:
*/
tmp = lookup_address(address, &level);
- if (tmp != kpte)
- goto out_unlock;
+ if (tmp != kpte) {
+ spin_unlock(&pgd_lock);
+ return 1;
+ }
- pbase = (pte_t *)page_address(base);
paravirt_alloc_pte(&init_mm, page_to_pfn(base));
ref_prot = pte_pgprot(pte_clrhuge(*kpte));
/*
@@ -551,16 +572,10 @@ static int split_large_page(pte_t *kpte, unsigned long address)
for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
set_pte(&pbase[i], pfn_pte(pfn, ref_prot));
- if (address >= (unsigned long)__va(0) &&
- address < (unsigned long)__va(max_low_pfn_mapped << PAGE_SHIFT))
+ if (pfn_range_is_mapped(PFN_DOWN(__pa(address)),
+ PFN_DOWN(__pa(address)) + 1))
split_page_count(level);
-#ifdef CONFIG_X86_64
- if (address >= (unsigned long)__va(1UL<<32) &&
- address < (unsigned long)__va(max_pfn_mapped << PAGE_SHIFT))
- split_page_count(level);
-#endif
-
/*
* Install the new, split up pagetable.
*
@@ -579,17 +594,27 @@ static int split_large_page(pte_t *kpte, unsigned long address)
* going on.
*/
__flush_tlb_all();
+ spin_unlock(&pgd_lock);
+
+ return 0;
+}
- base = NULL;
+static int split_large_page(pte_t *kpte, unsigned long address)
+{
+ pte_t *pbase;
+ struct page *base;
-out_unlock:
- /*
- * If we dropped out via the lookup_address check under
- * pgd_lock then stick the page back into the pool:
- */
- if (base)
+ if (!debug_pagealloc)
+ spin_unlock(&cpa_lock);
+ base = alloc_pages(GFP_KERNEL | __GFP_NOTRACK, 0);
+ if (!debug_pagealloc)
+ spin_lock(&cpa_lock);
+ if (!base)
+ return -ENOMEM;
+
+ pbase = (pte_t *)page_address(base);
+ if (__split_large_page(kpte, address, pbase))
__free_page(base);
- spin_unlock(&pgd_lock);
return 0;
}
@@ -729,13 +754,9 @@ static int cpa_process_alias(struct cpa_data *cpa)
unsigned long vaddr;
int ret;
- if (cpa->pfn >= max_pfn_mapped)
+ if (!pfn_range_is_mapped(cpa->pfn, cpa->pfn + 1))
return 0;
-#ifdef CONFIG_X86_64
- if (cpa->pfn >= max_low_pfn_mapped && cpa->pfn < (1UL<<(32-PAGE_SHIFT)))
- return 0;
-#endif
/*
* No need to redo, when the primary call touched the direct
* mapping already:
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 0eb572eda406..2610bd93c896 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -560,10 +560,10 @@ int kernel_map_sync_memtype(u64 base, unsigned long size, unsigned long flags)
{
unsigned long id_sz;
- if (base >= __pa(high_memory))
+ if (base > __pa(high_memory-1))
return 0;
- id_sz = (__pa(high_memory) < base + size) ?
+ id_sz = (__pa(high_memory-1) <= base + size) ?
__pa(high_memory) - base :
size;
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index e27fbf887f3b..193350b51f90 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -334,7 +334,12 @@ int pmdp_set_access_flags(struct vm_area_struct *vma,
if (changed && dirty) {
*pmdp = entry;
pmd_update_defer(vma->vm_mm, address, pmdp);
- flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
+ /*
+ * We had a write-protection fault here and changed the pmd
+ * to to more permissive. No need to flush the TLB for that,
+ * #PF is architecturally guaranteed to do that and in the
+ * worst-case we'll generate a spurious fault.
+ */
}
return changed;
diff --git a/arch/x86/mm/physaddr.c b/arch/x86/mm/physaddr.c
index d2e2735327b4..e666cbbb9261 100644
--- a/arch/x86/mm/physaddr.c
+++ b/arch/x86/mm/physaddr.c
@@ -1,3 +1,4 @@
+#include <linux/bootmem.h>
#include <linux/mmdebug.h>
#include <linux/module.h>
#include <linux/mm.h>
@@ -8,33 +9,54 @@
#ifdef CONFIG_X86_64
+#ifdef CONFIG_DEBUG_VIRTUAL
unsigned long __phys_addr(unsigned long x)
{
- if (x >= __START_KERNEL_map) {
- x -= __START_KERNEL_map;
- VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE);
- x += phys_base;
+ unsigned long y = x - __START_KERNEL_map;
+
+ /* use the carry flag to determine if x was < __START_KERNEL_map */
+ if (unlikely(x > y)) {
+ x = y + phys_base;
+
+ VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE);
} else {
- VIRTUAL_BUG_ON(x < PAGE_OFFSET);
- x -= PAGE_OFFSET;
- VIRTUAL_BUG_ON(!phys_addr_valid(x));
+ x = y + (__START_KERNEL_map - PAGE_OFFSET);
+
+ /* carry flag will be set if starting x was >= PAGE_OFFSET */
+ VIRTUAL_BUG_ON((x > y) || !phys_addr_valid(x));
}
+
return x;
}
EXPORT_SYMBOL(__phys_addr);
+unsigned long __phys_addr_symbol(unsigned long x)
+{
+ unsigned long y = x - __START_KERNEL_map;
+
+ /* only check upper bounds since lower bounds will trigger carry */
+ VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE);
+
+ return y + phys_base;
+}
+EXPORT_SYMBOL(__phys_addr_symbol);
+#endif
+
bool __virt_addr_valid(unsigned long x)
{
- if (x >= __START_KERNEL_map) {
- x -= __START_KERNEL_map;
- if (x >= KERNEL_IMAGE_SIZE)
+ unsigned long y = x - __START_KERNEL_map;
+
+ /* use the carry flag to determine if x was < __START_KERNEL_map */
+ if (unlikely(x > y)) {
+ x = y + phys_base;
+
+ if (y >= KERNEL_IMAGE_SIZE)
return false;
- x += phys_base;
} else {
- if (x < PAGE_OFFSET)
- return false;
- x -= PAGE_OFFSET;
- if (!phys_addr_valid(x))
+ x = y + (__START_KERNEL_map - PAGE_OFFSET);
+
+ /* carry flag will be set if starting x was >= PAGE_OFFSET */
+ if ((x > y) || !phys_addr_valid(x))
return false;
}
@@ -47,10 +69,16 @@ EXPORT_SYMBOL(__virt_addr_valid);
#ifdef CONFIG_DEBUG_VIRTUAL
unsigned long __phys_addr(unsigned long x)
{
+ unsigned long phys_addr = x - PAGE_OFFSET;
/* VMALLOC_* aren't constants */
VIRTUAL_BUG_ON(x < PAGE_OFFSET);
VIRTUAL_BUG_ON(__vmalloc_start_set && is_vmalloc_addr((void *) x));
- return x - PAGE_OFFSET;
+ /* max_low_pfn is set early, but not _that_ early */
+ if (max_low_pfn) {
+ VIRTUAL_BUG_ON((phys_addr >> PAGE_SHIFT) > max_low_pfn);
+ BUG_ON(slow_virt_to_phys((void *)x) != phys_addr);
+ }
+ return phys_addr;
}
EXPORT_SYMBOL(__phys_addr);
#endif
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c
index 4ddf497ca65b..79836d01f789 100644
--- a/arch/x86/mm/srat.c
+++ b/arch/x86/mm/srat.c
@@ -141,47 +141,167 @@ static inline int save_add_info(void) {return 1;}
static inline int save_add_info(void) {return 0;}
#endif
+#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
+static void __init
+handle_movablemem(int node, u64 start, u64 end, u32 hotpluggable)
+{
+ int overlap, i;
+ unsigned long start_pfn, end_pfn;
+
+ start_pfn = PFN_DOWN(start);
+ end_pfn = PFN_UP(end);
+
+ /*
+ * For movablemem_map=acpi:
+ *
+ * SRAT: |_____| |_____| |_________| |_________| ......
+ * node id: 0 1 1 2
+ * hotpluggable: n y y n
+ * movablemem_map: |_____| |_________|
+ *
+ * Using movablemem_map, we can prevent memblock from allocating memory
+ * on ZONE_MOVABLE at boot time.
+ *
+ * Before parsing SRAT, memblock has already reserve some memory ranges
+ * for other purposes, such as for kernel image. We cannot prevent
+ * kernel from using these memory, so we need to exclude these memory
+ * even if it is hotpluggable.
+ * Furthermore, to ensure the kernel has enough memory to boot, we make
+ * all the memory on the node which the kernel resides in
+ * un-hotpluggable.
+ */
+ if (hotpluggable && movablemem_map.acpi) {
+ /* Exclude ranges reserved by memblock. */
+ struct memblock_type *rgn = &memblock.reserved;
+
+ for (i = 0; i < rgn->cnt; i++) {
+ if (end <= rgn->regions[i].base ||
+ start >= rgn->regions[i].base +
+ rgn->regions[i].size)
+ continue;
+
+ /*
+ * If the memory range overlaps the memory reserved by
+ * memblock, then the kernel resides in this node.
+ */
+ node_set(node, movablemem_map.numa_nodes_kernel);
+
+ goto out;
+ }
+
+ /*
+ * If the kernel resides in this node, then the whole node
+ * should not be hotpluggable.
+ */
+ if (node_isset(node, movablemem_map.numa_nodes_kernel))
+ goto out;
+
+ insert_movablemem_map(start_pfn, end_pfn);
+
+ /*
+ * numa_nodes_hotplug nodemask represents which nodes are put
+ * into movablemem_map.map[].
+ */
+ node_set(node, movablemem_map.numa_nodes_hotplug);
+ goto out;
+ }
+
+ /*
+ * For movablemem_map=nn[KMG]@ss[KMG]:
+ *
+ * SRAT: |_____| |_____| |_________| |_________| ......
+ * node id: 0 1 1 2
+ * user specified: |__| |___|
+ * movablemem_map: |___| |_________| |______| ......
+ *
+ * Using movablemem_map, we can prevent memblock from allocating memory
+ * on ZONE_MOVABLE at boot time.
+ *
+ * NOTE: In this case, SRAT info will be ingored.
+ */
+ overlap = movablemem_map_overlap(start_pfn, end_pfn);
+ if (overlap >= 0) {
+ /*
+ * If part of this range is in movablemem_map, we need to
+ * add the range after it to extend the range to the end
+ * of the node, because from the min address specified to
+ * the end of the node will be ZONE_MOVABLE.
+ */
+ start_pfn = max(start_pfn,
+ movablemem_map.map[overlap].start_pfn);
+ insert_movablemem_map(start_pfn, end_pfn);
+
+ /*
+ * Set the nodemask, so that if the address range on one node
+ * is not continuse, we can add the subsequent ranges on the
+ * same node into movablemem_map.
+ */
+ node_set(node, movablemem_map.numa_nodes_hotplug);
+ } else {
+ if (node_isset(node, movablemem_map.numa_nodes_hotplug))
+ /*
+ * Insert the range if we already have movable ranges
+ * on the same node.
+ */
+ insert_movablemem_map(start_pfn, end_pfn);
+ }
+out:
+ return;
+}
+#else /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
+static inline void
+handle_movablemem(int node, u64 start, u64 end, u32 hotpluggable)
+{
+}
+#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
+
/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
int __init
acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
{
u64 start, end;
+ u32 hotpluggable;
int node, pxm;
if (srat_disabled())
- return -1;
- if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
- bad_srat();
- return -1;
- }
+ goto out_err;
+ if (ma->header.length != sizeof(struct acpi_srat_mem_affinity))
+ goto out_err_bad_srat;
if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
- return -1;
+ goto out_err;
+ hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE;
+ if (hotpluggable && !save_add_info())
+ goto out_err;
- if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
- return -1;
start = ma->base_address;
end = start + ma->length;
pxm = ma->proximity_domain;
if (acpi_srat_revision <= 1)
pxm &= 0xff;
+
node = setup_node(pxm);
if (node < 0) {
printk(KERN_ERR "SRAT: Too many proximity domains.\n");
- bad_srat();
- return -1;
+ goto out_err_bad_srat;
}
- if (numa_add_memblk(node, start, end) < 0) {
- bad_srat();
- return -1;
- }
+ if (numa_add_memblk(node, start, end) < 0)
+ goto out_err_bad_srat;
node_set(node, numa_nodes_parsed);
- printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n",
+ printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx] %s\n",
node, pxm,
- (unsigned long long) start, (unsigned long long) end - 1);
+ (unsigned long long) start, (unsigned long long) end - 1,
+ hotpluggable ? "Hot Pluggable": "");
+
+ handle_movablemem(node, start, end, hotpluggable);
+
return 0;
+out_err_bad_srat:
+ bad_srat();
+out_err:
+ return -1;
}
void __init acpi_numa_arch_fixup(void) {}
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 13a6b29e2e5d..282375f13c7e 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -335,7 +335,7 @@ static const struct file_operations fops_tlbflush = {
.llseek = default_llseek,
};
-static int __cpuinit create_tlb_flushall_shift(void)
+static int __init create_tlb_flushall_shift(void)
{
debugfs_create_file("tlb_flushall_shift", S_IRUSR | S_IWUSR,
arch_debugfs_dir, NULL, &fops_tlbflush);
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index d11a47099d33..3cbe45381bbb 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -1,6 +1,6 @@
/* bpf_jit_comp.c : BPF JIT compiler
*
- * Copyright (C) 2011 Eric Dumazet (eric.dumazet@gmail.com)
+ * Copyright (C) 2011-2013 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
@@ -124,6 +124,26 @@ static inline void bpf_flush_icache(void *start, void *end)
#define CHOOSE_LOAD_FUNC(K, func) \
((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset)
+/* Helper to find the offset of pkt_type in sk_buff
+ * We want to make sure its still a 3bit field starting at a byte boundary.
+ */
+#define PKT_TYPE_MAX 7
+static int pkt_type_offset(void)
+{
+ struct sk_buff skb_probe = {
+ .pkt_type = ~0,
+ };
+ char *ct = (char *)&skb_probe;
+ unsigned int off;
+
+ for (off = 0; off < sizeof(struct sk_buff); off++) {
+ if (ct[off] == PKT_TYPE_MAX)
+ return off;
+ }
+ pr_err_once("Please fix pkt_type_offset(), as pkt_type couldn't be found\n");
+ return -1;
+}
+
void bpf_jit_compile(struct sk_filter *fp)
{
u8 temp[64];
@@ -216,6 +236,7 @@ void bpf_jit_compile(struct sk_filter *fp)
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_S_ANC_QUEUE:
+ case BPF_S_ANC_PKTTYPE:
case BPF_S_LD_W_ABS:
case BPF_S_LD_H_ABS:
case BPF_S_LD_B_ABS:
@@ -536,6 +557,23 @@ void bpf_jit_compile(struct sk_filter *fp)
EMIT3(0x83, 0xe0, 0x01); /* and $0x1,%eax */
}
break;
+ case BPF_S_ANC_PKTTYPE:
+ {
+ int off = pkt_type_offset();
+
+ if (off < 0)
+ goto out;
+ if (is_imm8(off)) {
+ /* movzbl off8(%rdi),%eax */
+ EMIT4(0x0f, 0xb6, 0x47, off);
+ } else {
+ /* movbl off32(%rdi),%eax */
+ EMIT3(0x0f, 0xb6, 0x87);
+ EMIT(off, 4);
+ }
+ EMIT3(0x83, 0xe0, PKT_TYPE_MAX); /* and $0x7,%eax */
+ break;
+ }
case BPF_S_LD_W_ABS:
func = CHOOSE_LOAD_FUNC(K, sk_load_word);
common_load: seen |= SEEN_DATAREF;
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index fb29968a7cd5..082e88129712 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -548,8 +548,7 @@ static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
if (cfg->address < 0xFFFFFFFF)
return 0;
- if (!strcmp(mcfg->header.oem_id, "SGI") ||
- !strcmp(mcfg->header.oem_id, "SGI2"))
+ if (!strncmp(mcfg->header.oem_id, "SGI", 3))
return 0;
if (mcfg->header.revision >= 1) {
diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile
index 8d874396cb29..01e0231a113e 100644
--- a/arch/x86/platform/Makefile
+++ b/arch/x86/platform/Makefile
@@ -2,10 +2,12 @@
obj-y += ce4100/
obj-y += efi/
obj-y += geode/
+obj-y += goldfish/
obj-y += iris/
obj-y += mrst/
obj-y += olpc/
obj-y += scx200/
obj-y += sfi/
+obj-y += ts5500/
obj-y += visws/
obj-y += uv/
diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c
index d9c1b95af17c..7145ec63c520 100644
--- a/arch/x86/platform/efi/efi-bgrt.c
+++ b/arch/x86/platform/efi/efi-bgrt.c
@@ -11,20 +11,21 @@
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
+#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/efi.h>
#include <linux/efi-bgrt.h>
struct acpi_table_bgrt *bgrt_tab;
-void *bgrt_image;
-size_t bgrt_image_size;
+void *__initdata bgrt_image;
+size_t __initdata bgrt_image_size;
struct bmp_header {
u16 id;
u32 size;
} __packed;
-void efi_bgrt_init(void)
+void __init efi_bgrt_init(void)
{
acpi_status status;
void __iomem *image;
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 77cf0090c0a3..70b2a3a305d6 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -87,7 +87,7 @@ EXPORT_SYMBOL(efi_enabled);
static int __init setup_noefi(char *arg)
{
- clear_bit(EFI_BOOT, &x86_efi_facility);
+ clear_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility);
return 0;
}
early_param("noefi", setup_noefi);
@@ -416,8 +416,8 @@ void __init efi_reserve_boot_services(void)
* - Not within any part of the kernel
* - Not the bios reserved area
*/
- if ((start+size >= virt_to_phys(_text)
- && start <= virt_to_phys(_end)) ||
+ if ((start+size >= __pa_symbol(_text)
+ && start <= __pa_symbol(_end)) ||
!e820_all_mapped(start, start+size, E820_RAM) ||
memblock_is_region_reserved(start, size)) {
/* Could not reserve, skip it */
@@ -843,7 +843,7 @@ void __init efi_enter_virtual_mode(void)
efi_memory_desc_t *md, *prev_md = NULL;
efi_status_t status;
unsigned long size;
- u64 end, systab, end_pfn;
+ u64 end, systab, start_pfn, end_pfn;
void *p, *va, *new_memmap = NULL;
int count = 0;
@@ -896,10 +896,9 @@ void __init efi_enter_virtual_mode(void)
size = md->num_pages << EFI_PAGE_SHIFT;
end = md->phys_addr + size;
+ start_pfn = PFN_DOWN(md->phys_addr);
end_pfn = PFN_UP(end);
- if (end_pfn <= max_low_pfn_mapped
- || (end_pfn > (1UL << (32 - PAGE_SHIFT))
- && end_pfn <= max_pfn_mapped)) {
+ if (pfn_range_is_mapped(start_pfn, end_pfn)) {
va = __va(md->phys_addr);
if (!(md->attribute & EFI_MEMORY_WB))
diff --git a/arch/x86/platform/goldfish/Makefile b/arch/x86/platform/goldfish/Makefile
new file mode 100644
index 000000000000..f030b532fdf3
--- /dev/null
+++ b/arch/x86/platform/goldfish/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_GOLDFISH) += goldfish.o
diff --git a/arch/x86/platform/goldfish/goldfish.c b/arch/x86/platform/goldfish/goldfish.c
new file mode 100644
index 000000000000..1693107a518e
--- /dev/null
+++ b/arch/x86/platform/goldfish/goldfish.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2011 Intel, Inc.
+ * Copyright (C) 2013 Intel, Inc.
+ *
+ * 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/kernel.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+
+/*
+ * Where in virtual device memory the IO devices (timers, system controllers
+ * and so on)
+ */
+
+#define GOLDFISH_PDEV_BUS_BASE (0xff001000)
+#define GOLDFISH_PDEV_BUS_END (0xff7fffff)
+#define GOLDFISH_PDEV_BUS_IRQ (4)
+
+#define GOLDFISH_TTY_BASE (0x2000)
+
+static struct resource goldfish_pdev_bus_resources[] = {
+ {
+ .start = GOLDFISH_PDEV_BUS_BASE,
+ .end = GOLDFISH_PDEV_BUS_END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = GOLDFISH_PDEV_BUS_IRQ,
+ .end = GOLDFISH_PDEV_BUS_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static int __init goldfish_init(void)
+{
+ platform_device_register_simple("goldfish_pdev_bus", -1,
+ goldfish_pdev_bus_resources, 2);
+ return 0;
+}
+device_initcall(goldfish_init);
diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c
index 2fdca25905ae..fef7d0ba7e3a 100644
--- a/arch/x86/platform/olpc/olpc-xo15-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo15-sci.c
@@ -195,7 +195,7 @@ err_sysfs:
return r;
}
-static int xo15_sci_remove(struct acpi_device *device, int type)
+static int xo15_sci_remove(struct acpi_device *device)
{
acpi_disable_gpe(NULL, xo15_sci_gpe);
acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
diff --git a/arch/x86/platform/sfi/sfi.c b/arch/x86/platform/sfi/sfi.c
index 7785b72ecc3a..bcd1a703e3e6 100644
--- a/arch/x86/platform/sfi/sfi.c
+++ b/arch/x86/platform/sfi/sfi.c
@@ -35,7 +35,7 @@
static unsigned long sfi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
/* All CPUs enumerated by SFI must be present and enabled */
-static void __cpuinit mp_sfi_register_lapic(u8 id)
+static void __init mp_sfi_register_lapic(u8 id)
{
if (MAX_LOCAL_APIC - id <= 0) {
pr_warning("Processor #%d invalid (max %d)\n",
diff --git a/arch/x86/platform/ts5500/Makefile b/arch/x86/platform/ts5500/Makefile
new file mode 100644
index 000000000000..c54e348c96a7
--- /dev/null
+++ b/arch/x86/platform/ts5500/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_TS5500) += ts5500.o
diff --git a/arch/x86/platform/ts5500/ts5500.c b/arch/x86/platform/ts5500/ts5500.c
new file mode 100644
index 000000000000..39febb214e8c
--- /dev/null
+++ b/arch/x86/platform/ts5500/ts5500.c
@@ -0,0 +1,339 @@
+/*
+ * Technologic Systems TS-5500 Single Board Computer support
+ *
+ * Copyright (C) 2013 Savoir-faire Linux Inc.
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.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 driver registers the Technologic Systems TS-5500 Single Board Computer
+ * (SBC) and its devices, and exposes information to userspace such as jumpers'
+ * state or available options. For further information about sysfs entries, see
+ * Documentation/ABI/testing/sysfs-platform-ts5500.
+ *
+ * This code actually supports the TS-5500 platform, but it may be extended to
+ * support similar Technologic Systems x86-based platforms, such as the TS-5600.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_data/gpio-ts5500.h>
+#include <linux/platform_data/max197.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* Product code register */
+#define TS5500_PRODUCT_CODE_ADDR 0x74
+#define TS5500_PRODUCT_CODE 0x60 /* TS-5500 product code */
+
+/* SRAM/RS-485/ADC options, and RS-485 RTS/Automatic RS-485 flags register */
+#define TS5500_SRAM_RS485_ADC_ADDR 0x75
+#define TS5500_SRAM BIT(0) /* SRAM option */
+#define TS5500_RS485 BIT(1) /* RS-485 option */
+#define TS5500_ADC BIT(2) /* A/D converter option */
+#define TS5500_RS485_RTS BIT(6) /* RTS for RS-485 */
+#define TS5500_RS485_AUTO BIT(7) /* Automatic RS-485 */
+
+/* External Reset/Industrial Temperature Range options register */
+#define TS5500_ERESET_ITR_ADDR 0x76
+#define TS5500_ERESET BIT(0) /* External Reset option */
+#define TS5500_ITR BIT(1) /* Indust. Temp. Range option */
+
+/* LED/Jumpers register */
+#define TS5500_LED_JP_ADDR 0x77
+#define TS5500_LED BIT(0) /* LED flag */
+#define TS5500_JP1 BIT(1) /* Automatic CMOS */
+#define TS5500_JP2 BIT(2) /* Enable Serial Console */
+#define TS5500_JP3 BIT(3) /* Write Enable Drive A */
+#define TS5500_JP4 BIT(4) /* Fast Console (115K baud) */
+#define TS5500_JP5 BIT(5) /* User Jumper */
+#define TS5500_JP6 BIT(6) /* Console on COM1 (req. JP2) */
+#define TS5500_JP7 BIT(7) /* Undocumented (Unused) */
+
+/* A/D Converter registers */
+#define TS5500_ADC_CONV_BUSY_ADDR 0x195 /* Conversion state register */
+#define TS5500_ADC_CONV_BUSY BIT(0)
+#define TS5500_ADC_CONV_INIT_LSB_ADDR 0x196 /* Start conv. / LSB register */
+#define TS5500_ADC_CONV_MSB_ADDR 0x197 /* MSB register */
+#define TS5500_ADC_CONV_DELAY 12 /* usec */
+
+/**
+ * struct ts5500_sbc - TS-5500 board description
+ * @id: Board product ID.
+ * @sram: Flag for SRAM option.
+ * @rs485: Flag for RS-485 option.
+ * @adc: Flag for Analog/Digital converter option.
+ * @ereset: Flag for External Reset option.
+ * @itr: Flag for Industrial Temperature Range option.
+ * @jumpers: Bitfield for jumpers' state.
+ */
+struct ts5500_sbc {
+ int id;
+ bool sram;
+ bool rs485;
+ bool adc;
+ bool ereset;
+ bool itr;
+ u8 jumpers;
+};
+
+/* Board signatures in BIOS shadow RAM */
+static const struct {
+ const char * const string;
+ const ssize_t offset;
+} ts5500_signatures[] __initdata = {
+ { "TS-5x00 AMD Elan", 0xb14 },
+};
+
+static int __init ts5500_check_signature(void)
+{
+ void __iomem *bios;
+ int i, ret = -ENODEV;
+
+ bios = ioremap(0xf0000, 0x10000);
+ if (!bios)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(ts5500_signatures); i++) {
+ if (check_signature(bios + ts5500_signatures[i].offset,
+ ts5500_signatures[i].string,
+ strlen(ts5500_signatures[i].string))) {
+ ret = 0;
+ break;
+ }
+ }
+
+ iounmap(bios);
+ return ret;
+}
+
+static int __init ts5500_detect_config(struct ts5500_sbc *sbc)
+{
+ u8 tmp;
+ int ret = 0;
+
+ if (!request_region(TS5500_PRODUCT_CODE_ADDR, 4, "ts5500"))
+ return -EBUSY;
+
+ tmp = inb(TS5500_PRODUCT_CODE_ADDR);
+ if (tmp != TS5500_PRODUCT_CODE) {
+ pr_err("This platform is not a TS-5500 (found ID 0x%x)\n", tmp);
+ ret = -ENODEV;
+ goto cleanup;
+ }
+ sbc->id = tmp;
+
+ tmp = inb(TS5500_SRAM_RS485_ADC_ADDR);
+ sbc->sram = tmp & TS5500_SRAM;
+ sbc->rs485 = tmp & TS5500_RS485;
+ sbc->adc = tmp & TS5500_ADC;
+
+ tmp = inb(TS5500_ERESET_ITR_ADDR);
+ sbc->ereset = tmp & TS5500_ERESET;
+ sbc->itr = tmp & TS5500_ITR;
+
+ tmp = inb(TS5500_LED_JP_ADDR);
+ sbc->jumpers = tmp & ~TS5500_LED;
+
+cleanup:
+ release_region(TS5500_PRODUCT_CODE_ADDR, 4);
+ return ret;
+}
+
+static ssize_t ts5500_show_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ts5500_sbc *sbc = dev_get_drvdata(dev);
+
+ return sprintf(buf, "0x%.2x\n", sbc->id);
+}
+
+static ssize_t ts5500_show_jumpers(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ts5500_sbc *sbc = dev_get_drvdata(dev);
+
+ return sprintf(buf, "0x%.2x\n", sbc->jumpers >> 1);
+}
+
+#define TS5500_SHOW(field) \
+ static ssize_t ts5500_show_##field(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
+ struct ts5500_sbc *sbc = dev_get_drvdata(dev); \
+ return sprintf(buf, "%d\n", sbc->field); \
+ }
+
+TS5500_SHOW(sram)
+TS5500_SHOW(rs485)
+TS5500_SHOW(adc)
+TS5500_SHOW(ereset)
+TS5500_SHOW(itr)
+
+static DEVICE_ATTR(id, S_IRUGO, ts5500_show_id, NULL);
+static DEVICE_ATTR(jumpers, S_IRUGO, ts5500_show_jumpers, NULL);
+static DEVICE_ATTR(sram, S_IRUGO, ts5500_show_sram, NULL);
+static DEVICE_ATTR(rs485, S_IRUGO, ts5500_show_rs485, NULL);
+static DEVICE_ATTR(adc, S_IRUGO, ts5500_show_adc, NULL);
+static DEVICE_ATTR(ereset, S_IRUGO, ts5500_show_ereset, NULL);
+static DEVICE_ATTR(itr, S_IRUGO, ts5500_show_itr, NULL);
+
+static struct attribute *ts5500_attributes[] = {
+ &dev_attr_id.attr,
+ &dev_attr_jumpers.attr,
+ &dev_attr_sram.attr,
+ &dev_attr_rs485.attr,
+ &dev_attr_adc.attr,
+ &dev_attr_ereset.attr,
+ &dev_attr_itr.attr,
+ NULL
+};
+
+static const struct attribute_group ts5500_attr_group = {
+ .attrs = ts5500_attributes,
+};
+
+static struct resource ts5500_dio1_resource[] = {
+ DEFINE_RES_IRQ_NAMED(7, "DIO1 interrupt"),
+};
+
+static struct platform_device ts5500_dio1_pdev = {
+ .name = "ts5500-dio1",
+ .id = -1,
+ .resource = ts5500_dio1_resource,
+ .num_resources = 1,
+};
+
+static struct resource ts5500_dio2_resource[] = {
+ DEFINE_RES_IRQ_NAMED(6, "DIO2 interrupt"),
+};
+
+static struct platform_device ts5500_dio2_pdev = {
+ .name = "ts5500-dio2",
+ .id = -1,
+ .resource = ts5500_dio2_resource,
+ .num_resources = 1,
+};
+
+static void ts5500_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ outb(!!brightness, TS5500_LED_JP_ADDR);
+}
+
+static enum led_brightness ts5500_led_get(struct led_classdev *led_cdev)
+{
+ return (inb(TS5500_LED_JP_ADDR) & TS5500_LED) ? LED_FULL : LED_OFF;
+}
+
+static struct led_classdev ts5500_led_cdev = {
+ .name = "ts5500:green:",
+ .brightness_set = ts5500_led_set,
+ .brightness_get = ts5500_led_get,
+};
+
+static int ts5500_adc_convert(u8 ctrl)
+{
+ u8 lsb, msb;
+
+ /* Start conversion (ensure the 3 MSB are set to 0) */
+ outb(ctrl & 0x1f, TS5500_ADC_CONV_INIT_LSB_ADDR);
+
+ /*
+ * The platform has CPLD logic driving the A/D converter.
+ * The conversion must complete within 11 microseconds,
+ * otherwise we have to re-initiate a conversion.
+ */
+ udelay(TS5500_ADC_CONV_DELAY);
+ if (inb(TS5500_ADC_CONV_BUSY_ADDR) & TS5500_ADC_CONV_BUSY)
+ return -EBUSY;
+
+ /* Read the raw data */
+ lsb = inb(TS5500_ADC_CONV_INIT_LSB_ADDR);
+ msb = inb(TS5500_ADC_CONV_MSB_ADDR);
+
+ return (msb << 8) | lsb;
+}
+
+static struct max197_platform_data ts5500_adc_pdata = {
+ .convert = ts5500_adc_convert,
+};
+
+static struct platform_device ts5500_adc_pdev = {
+ .name = "max197",
+ .id = -1,
+ .dev = {
+ .platform_data = &ts5500_adc_pdata,
+ },
+};
+
+static int __init ts5500_init(void)
+{
+ struct platform_device *pdev;
+ struct ts5500_sbc *sbc;
+ int err;
+
+ /*
+ * There is no DMI available or PCI bridge subvendor info,
+ * only the BIOS provides a 16-bit identification call.
+ * It is safer to find a signature in the BIOS shadow RAM.
+ */
+ err = ts5500_check_signature();
+ if (err)
+ return err;
+
+ pdev = platform_device_register_simple("ts5500", -1, NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ sbc = devm_kzalloc(&pdev->dev, sizeof(struct ts5500_sbc), GFP_KERNEL);
+ if (!sbc) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ err = ts5500_detect_config(sbc);
+ if (err)
+ goto error;
+
+ platform_set_drvdata(pdev, sbc);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &ts5500_attr_group);
+ if (err)
+ goto error;
+
+ ts5500_dio1_pdev.dev.parent = &pdev->dev;
+ if (platform_device_register(&ts5500_dio1_pdev))
+ dev_warn(&pdev->dev, "DIO1 block registration failed\n");
+ ts5500_dio2_pdev.dev.parent = &pdev->dev;
+ if (platform_device_register(&ts5500_dio2_pdev))
+ dev_warn(&pdev->dev, "DIO2 block registration failed\n");
+
+ if (led_classdev_register(&pdev->dev, &ts5500_led_cdev))
+ dev_warn(&pdev->dev, "LED registration failed\n");
+
+ if (sbc->adc) {
+ ts5500_adc_pdev.dev.parent = &pdev->dev;
+ if (platform_device_register(&ts5500_adc_pdev))
+ dev_warn(&pdev->dev, "ADC registration failed\n");
+ }
+
+ return 0;
+error:
+ platform_device_unregister(pdev);
+ return err;
+}
+device_initcall(ts5500_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
+MODULE_DESCRIPTION("Technologic Systems TS-5500 platform driver");
diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c
index dbbdca5f508c..0f92173a12b6 100644
--- a/arch/x86/platform/uv/tlb_uv.c
+++ b/arch/x86/platform/uv/tlb_uv.c
@@ -1467,7 +1467,7 @@ static ssize_t ptc_proc_write(struct file *file, const char __user *user,
}
if (input_arg == 0) {
- elements = sizeof(stat_description)/sizeof(*stat_description);
+ elements = ARRAY_SIZE(stat_description);
printk(KERN_DEBUG "# cpu: cpu number\n");
printk(KERN_DEBUG "Sender statistics:\n");
for (i = 0; i < elements; i++)
@@ -1508,7 +1508,7 @@ static int parse_tunables_write(struct bau_control *bcp, char *instr,
char *q;
int cnt = 0;
int val;
- int e = sizeof(tunables) / sizeof(*tunables);
+ int e = ARRAY_SIZE(tunables);
p = instr + strspn(instr, WHITESPACE);
q = p;
diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c
index 5032e0d19b86..98718f604eb6 100644
--- a/arch/x86/platform/uv/uv_time.c
+++ b/arch/x86/platform/uv/uv_time.c
@@ -15,7 +15,7 @@
* 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) 2009 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2009-2013 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) Dimitri Sivanich
*/
#include <linux/clockchips.h>
@@ -102,9 +102,10 @@ static int uv_intr_pending(int pnode)
if (is_uv1_hub())
return uv_read_global_mmr64(pnode, UVH_EVENT_OCCURRED0) &
UV1H_EVENT_OCCURRED0_RTC1_MASK;
- else
- return uv_read_global_mmr64(pnode, UV2H_EVENT_OCCURRED2) &
- UV2H_EVENT_OCCURRED2_RTC_1_MASK;
+ else if (is_uvx_hub())
+ return uv_read_global_mmr64(pnode, UVXH_EVENT_OCCURRED2) &
+ UVXH_EVENT_OCCURRED2_RTC_1_MASK;
+ return 0;
}
/* Setup interrupt and return non-zero if early expiration occurred. */
@@ -122,8 +123,8 @@ static int uv_setup_intr(int cpu, u64 expires)
uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS,
UV1H_EVENT_OCCURRED0_RTC1_MASK);
else
- uv_write_global_mmr64(pnode, UV2H_EVENT_OCCURRED2_ALIAS,
- UV2H_EVENT_OCCURRED2_RTC_1_MASK);
+ uv_write_global_mmr64(pnode, UVXH_EVENT_OCCURRED2_ALIAS,
+ UVXH_EVENT_OCCURRED2_RTC_1_MASK);
val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
((u64)apicid << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
diff --git a/arch/x86/power/hibernate_32.c b/arch/x86/power/hibernate_32.c
index 74202c1910cd..7d28c885d238 100644
--- a/arch/x86/power/hibernate_32.c
+++ b/arch/x86/power/hibernate_32.c
@@ -129,8 +129,6 @@ static int resume_physical_mapping_init(pgd_t *pgd_base)
}
}
- resume_map_numa_kva(pgd_base);
-
return 0;
}
diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c
index 460f314d13e5..a0fde91c16cf 100644
--- a/arch/x86/power/hibernate_64.c
+++ b/arch/x86/power/hibernate_64.c
@@ -11,6 +11,8 @@
#include <linux/gfp.h>
#include <linux/smp.h>
#include <linux/suspend.h>
+
+#include <asm/init.h>
#include <asm/proto.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -39,41 +41,21 @@ pgd_t *temp_level4_pgt;
void *relocated_restore_code;
-static int res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long end)
+static void *alloc_pgt_page(void *context)
{
- long i, j;
-
- i = pud_index(address);
- pud = pud + i;
- for (; i < PTRS_PER_PUD; pud++, i++) {
- unsigned long paddr;
- pmd_t *pmd;
-
- paddr = address + i*PUD_SIZE;
- if (paddr >= end)
- break;
-
- pmd = (pmd_t *)get_safe_page(GFP_ATOMIC);
- if (!pmd)
- return -ENOMEM;
- set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
- for (j = 0; j < PTRS_PER_PMD; pmd++, j++, paddr += PMD_SIZE) {
- unsigned long pe;
-
- if (paddr >= end)
- break;
- pe = __PAGE_KERNEL_LARGE_EXEC | paddr;
- pe &= __supported_pte_mask;
- set_pmd(pmd, __pmd(pe));
- }
- }
- return 0;
+ return (void *)get_safe_page(GFP_ATOMIC);
}
static int set_up_temporary_mappings(void)
{
- unsigned long start, end, next;
- int error;
+ struct x86_mapping_info info = {
+ .alloc_pgt_page = alloc_pgt_page,
+ .pmd_flag = __PAGE_KERNEL_LARGE_EXEC,
+ .kernel_mapping = true,
+ };
+ unsigned long mstart, mend;
+ int result;
+ int i;
temp_level4_pgt = (pgd_t *)get_safe_page(GFP_ATOMIC);
if (!temp_level4_pgt)
@@ -84,21 +66,17 @@ static int set_up_temporary_mappings(void)
init_level4_pgt[pgd_index(__START_KERNEL_map)]);
/* Set up the direct mapping from scratch */
- start = (unsigned long)pfn_to_kaddr(0);
- end = (unsigned long)pfn_to_kaddr(max_pfn);
-
- for (; start < end; start = next) {
- pud_t *pud = (pud_t *)get_safe_page(GFP_ATOMIC);
- if (!pud)
- return -ENOMEM;
- next = start + PGDIR_SIZE;
- if (next > end)
- next = end;
- if ((error = res_phys_pud_init(pud, __pa(start), __pa(next))))
- return error;
- set_pgd(temp_level4_pgt + pgd_index(start),
- mk_kernel_pgd(__pa(pud)));
+ for (i = 0; i < nr_pfn_mapped; i++) {
+ mstart = pfn_mapped[i].start << PAGE_SHIFT;
+ mend = pfn_mapped[i].end << PAGE_SHIFT;
+
+ result = kernel_ident_mapping_init(&info, temp_level4_pgt,
+ mstart, mend);
+
+ if (result)
+ return result;
}
+
return 0;
}
diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c
index cbca565af5bd..a44f457e70a1 100644
--- a/arch/x86/realmode/init.c
+++ b/arch/x86/realmode/init.c
@@ -8,9 +8,26 @@
struct real_mode_header *real_mode_header;
u32 *trampoline_cr4_features;
-void __init setup_real_mode(void)
+void __init reserve_real_mode(void)
{
phys_addr_t mem;
+ unsigned char *base;
+ size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
+
+ /* Has to be under 1M so we can execute real-mode AP code. */
+ mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
+ if (!mem)
+ panic("Cannot allocate trampoline\n");
+
+ base = __va(mem);
+ memblock_reserve(mem, size);
+ real_mode_header = (struct real_mode_header *) base;
+ printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
+ base, (unsigned long long)mem, size);
+}
+
+void __init setup_real_mode(void)
+{
u16 real_mode_seg;
u32 *rel;
u32 count;
@@ -25,16 +42,7 @@ void __init setup_real_mode(void)
u64 efer;
#endif
- /* Has to be in very low memory so we can execute real-mode AP code. */
- mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
- if (!mem)
- panic("Cannot allocate trampoline\n");
-
- base = __va(mem);
- memblock_reserve(mem, size);
- real_mode_header = (struct real_mode_header *) base;
- printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
- base, (unsigned long long)mem, size);
+ base = (unsigned char *)real_mode_header;
memcpy(base, real_mode_blob, size);
@@ -62,9 +70,9 @@ void __init setup_real_mode(void)
__va(real_mode_header->trampoline_header);
#ifdef CONFIG_X86_32
- trampoline_header->start = __pa(startup_32_smp);
+ trampoline_header->start = __pa_symbol(startup_32_smp);
trampoline_header->gdt_limit = __BOOT_DS + 7;
- trampoline_header->gdt_base = __pa(boot_gdt);
+ trampoline_header->gdt_base = __pa_symbol(boot_gdt);
#else
/*
* Some AMD processors will #GP(0) if EFER.LMA is set in WRMSR
@@ -78,16 +86,18 @@ void __init setup_real_mode(void)
*trampoline_cr4_features = read_cr4();
trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
- trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE;
- trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE;
+ trampoline_pgd[0] = init_level4_pgt[pgd_index(__PAGE_OFFSET)].pgd;
+ trampoline_pgd[511] = init_level4_pgt[511].pgd;
#endif
}
/*
- * set_real_mode_permissions() gets called very early, to guarantee the
- * availability of low memory. This is before the proper kernel page
+ * reserve_real_mode() gets called very early, to guarantee the
+ * availability of low memory. This is before the proper kernel page
* tables are set up, so we cannot set page permissions in that
- * function. Thus, we use an arch_initcall instead.
+ * function. Also trampoline code will be executed by APs so we
+ * need to mark it executable at do_pre_smp_initcalls() at least,
+ * thus run it as a early_initcall().
*/
static int __init set_real_mode_permissions(void)
{
@@ -111,5 +121,4 @@ static int __init set_real_mode_permissions(void)
return 0;
}
-
-arch_initcall(set_real_mode_permissions);
+early_initcall(set_real_mode_permissions);
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index 28e3fa9056ea..f2fe78ff22cc 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -73,12 +73,12 @@
64 i386 getppid sys_getppid
65 i386 getpgrp sys_getpgrp
66 i386 setsid sys_setsid
-67 i386 sigaction sys_sigaction sys32_sigaction
+67 i386 sigaction sys_sigaction compat_sys_sigaction
68 i386 sgetmask sys_sgetmask
69 i386 ssetmask sys_ssetmask
70 i386 setreuid sys_setreuid16
71 i386 setregid sys_setregid16
-72 i386 sigsuspend sys_sigsuspend sys32_sigsuspend
+72 i386 sigsuspend sys_sigsuspend sys_sigsuspend
73 i386 sigpending sys_sigpending compat_sys_sigpending
74 i386 sethostname sys_sethostname
75 i386 setrlimit sys_setrlimit compat_sys_setrlimit
@@ -116,16 +116,16 @@
107 i386 lstat sys_newlstat compat_sys_newlstat
108 i386 fstat sys_newfstat compat_sys_newfstat
109 i386 olduname sys_uname
-110 i386 iopl ptregs_iopl stub32_iopl
+110 i386 iopl sys_iopl
111 i386 vhangup sys_vhangup
112 i386 idle
-113 i386 vm86old ptregs_vm86old sys32_vm86_warning
+113 i386 vm86old sys_vm86old sys32_vm86_warning
114 i386 wait4 sys_wait4 compat_sys_wait4
115 i386 swapoff sys_swapoff
116 i386 sysinfo sys_sysinfo compat_sys_sysinfo
117 i386 ipc sys_ipc sys32_ipc
118 i386 fsync sys_fsync
-119 i386 sigreturn ptregs_sigreturn stub32_sigreturn
+119 i386 sigreturn sys_sigreturn stub32_sigreturn
120 i386 clone sys_clone stub32_clone
121 i386 setdomainname sys_setdomainname
122 i386 uname sys_newuname
@@ -167,24 +167,24 @@
158 i386 sched_yield sys_sched_yield
159 i386 sched_get_priority_max sys_sched_get_priority_max
160 i386 sched_get_priority_min sys_sched_get_priority_min
-161 i386 sched_rr_get_interval sys_sched_rr_get_interval sys32_sched_rr_get_interval
+161 i386 sched_rr_get_interval sys_sched_rr_get_interval compat_sys_sched_rr_get_interval
162 i386 nanosleep sys_nanosleep compat_sys_nanosleep
163 i386 mremap sys_mremap
164 i386 setresuid sys_setresuid16
165 i386 getresuid sys_getresuid16
-166 i386 vm86 ptregs_vm86 sys32_vm86_warning
+166 i386 vm86 sys_vm86 sys32_vm86_warning
167 i386 query_module
168 i386 poll sys_poll
169 i386 nfsservctl
170 i386 setresgid sys_setresgid16
171 i386 getresgid sys_getresgid16
172 i386 prctl sys_prctl
-173 i386 rt_sigreturn ptregs_rt_sigreturn stub32_rt_sigreturn
-174 i386 rt_sigaction sys_rt_sigaction sys32_rt_sigaction
+173 i386 rt_sigreturn sys_rt_sigreturn stub32_rt_sigreturn
+174 i386 rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction
175 i386 rt_sigprocmask sys_rt_sigprocmask
-176 i386 rt_sigpending sys_rt_sigpending sys32_rt_sigpending
+176 i386 rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending
177 i386 rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait
-178 i386 rt_sigqueueinfo sys_rt_sigqueueinfo sys32_rt_sigqueueinfo
+178 i386 rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
179 i386 rt_sigsuspend sys_rt_sigsuspend
180 i386 pread64 sys_pread64 sys32_pread
181 i386 pwrite64 sys_pwrite64 sys32_pwrite
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
index dc97328bd90a..38ae65dfd14f 100644
--- a/arch/x86/syscalls/syscall_64.tbl
+++ b/arch/x86/syscalls/syscall_64.tbl
@@ -325,7 +325,7 @@
# x32-specific system call numbers start at 512 to avoid cache impact
# for native 64-bit operation.
#
-512 x32 rt_sigaction sys32_rt_sigaction
+512 x32 rt_sigaction compat_sys_rt_sigaction
513 x32 rt_sigreturn stub_x32_rt_sigreturn
514 x32 ioctl compat_sys_ioctl
515 x32 readv compat_sys_readv
@@ -335,9 +335,9 @@
519 x32 recvmsg compat_sys_recvmsg
520 x32 execve stub_x32_execve
521 x32 ptrace compat_sys_ptrace
-522 x32 rt_sigpending sys32_rt_sigpending
+522 x32 rt_sigpending compat_sys_rt_sigpending
523 x32 rt_sigtimedwait compat_sys_rt_sigtimedwait
-524 x32 rt_sigqueueinfo sys32_rt_sigqueueinfo
+524 x32 rt_sigqueueinfo compat_sys_rt_sigqueueinfo
525 x32 sigaltstack compat_sys_sigaltstack
526 x32 timer_create compat_sys_timer_create
527 x32 mq_notify compat_sys_mq_notify
diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig
index 53c90fd412d1..14ef8d1dbc33 100644
--- a/arch/x86/um/Kconfig
+++ b/arch/x86/um/Kconfig
@@ -13,7 +13,6 @@ endmenu
config UML_X86
def_bool y
select GENERIC_FIND_FIRST_BIT
- select GENERIC_SIGALTSTACK
config 64BIT
bool "64-bit kernel" if SUBARCH = "x86"
@@ -25,6 +24,8 @@ config X86_32
select ARCH_WANT_IPC_PARSE_VERSION
select MODULES_USE_ELF_REL
select CLONE_BACKWARDS
+ select OLD_SIGSUSPEND3
+ select OLD_SIGACTION
config X86_64
def_bool 64BIT
@@ -37,9 +38,8 @@ config RWSEM_GENERIC_SPINLOCK
def_bool !RWSEM_XCHGADD_ALGORITHM
config 3_LEVEL_PGTABLES
- bool "Three-level pagetables (EXPERIMENTAL)" if !64BIT
+ bool "Three-level pagetables" if !64BIT
default 64BIT
- depends on EXPERIMENTAL
help
Three-level pagetables will let UML have more than 4G of physical
memory. All the memory that can't be mapped directly will be treated
diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile
index 5d065b2222d3..eafa324eb7a5 100644
--- a/arch/x86/um/Makefile
+++ b/arch/x86/um/Makefile
@@ -10,7 +10,7 @@ endif
obj-y = bug.o bugs_$(BITS).o delay.o fault.o ksyms.o ldt.o \
ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \
- stub_$(BITS).o stub_segv.o syscalls_$(BITS).o \
+ stub_$(BITS).o stub_segv.o \
sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \
mem_$(BITS).o subarch.o os-$(OS)/
@@ -25,7 +25,7 @@ subarch-$(CONFIG_HIGHMEM) += ../mm/highmem_32.o
else
-obj-y += vdso/
+obj-y += syscalls_64.o vdso/
subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o ../lib/thunk_64.o \
../lib/rwsem.o
diff --git a/arch/x86/um/fault.c b/arch/x86/um/fault.c
index 8784ab30d91b..84ac7f7b0257 100644
--- a/arch/x86/um/fault.c
+++ b/arch/x86/um/fault.c
@@ -20,7 +20,7 @@ int arch_fixup(unsigned long address, struct uml_pt_regs *regs)
const struct exception_table_entry *fixup;
fixup = search_exception_tables(address);
- if (fixup != 0) {
+ if (fixup) {
UPT_IP(regs) = fixup->fixup;
return 1;
}
diff --git a/arch/x86/um/shared/sysdep/syscalls_32.h b/arch/x86/um/shared/sysdep/syscalls_32.h
index 8436079be914..68fd2cf526fd 100644
--- a/arch/x86/um/shared/sysdep/syscalls_32.h
+++ b/arch/x86/um/shared/sysdep/syscalls_32.h
@@ -8,11 +8,6 @@
typedef long syscall_handler_t(struct pt_regs);
-/* Not declared on x86, incompatible declarations on x86_64, so these have
- * to go here rather than in sys_call_table.c
- */
-extern syscall_handler_t sys_rt_sigaction;
-
extern syscall_handler_t *sys_call_table[];
#define EXECUTE_SYSCALL(syscall, regs) \
diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c
index 71cef48ea5cd..ae7319db18ee 100644
--- a/arch/x86/um/signal.c
+++ b/arch/x86/um/signal.c
@@ -464,7 +464,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
return 0;
}
-long sys_sigreturn(struct pt_regs *regs)
+long sys_sigreturn(void)
{
unsigned long sp = PT_REGS_SP(&current->thread.regs);
struct sigframe __user *frame = (struct sigframe __user *)(sp - 8);
@@ -577,7 +577,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
}
#endif
-long sys_rt_sigreturn(struct pt_regs *regs)
+long sys_rt_sigreturn(void)
{
unsigned long sp = PT_REGS_SP(&current->thread.regs);
struct rt_sigframe __user *frame =
@@ -601,14 +601,3 @@ long sys_rt_sigreturn(struct pt_regs *regs)
force_sig(SIGSEGV, current);
return 0;
}
-
-#ifdef CONFIG_X86_32
-long ptregs_sigreturn(void)
-{
- return sys_sigreturn(NULL);
-}
-long ptregs_rt_sigreturn(void)
-{
- return sys_rt_sigreturn(NULL);
-}
-#endif
diff --git a/arch/x86/um/sys_call_table_32.c b/arch/x86/um/sys_call_table_32.c
index a0c3b0d1a122..531d4269e2e3 100644
--- a/arch/x86/um/sys_call_table_32.c
+++ b/arch/x86/um/sys_call_table_32.c
@@ -24,10 +24,6 @@
#define old_mmap sys_old_mmap
-#define ptregs_iopl sys_iopl
-#define ptregs_vm86old sys_vm86old
-#define ptregs_vm86 sys_vm86
-
#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ;
#include <asm/syscalls_32.h>
diff --git a/arch/x86/um/syscalls_32.c b/arch/x86/um/syscalls_32.c
deleted file mode 100644
index e8bcea99acdb..000000000000
--- a/arch/x86/um/syscalls_32.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
- * Licensed under the GPL
- */
-
-#include <linux/syscalls.h>
-#include <sysdep/syscalls.h>
-
-long sys_sigaction(int sig, const struct old_sigaction __user *act,
- struct old_sigaction __user *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
- __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
- __get_user(mask, &act->sa_mask))
- return -EFAULT;
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
- return -EFAULT;
- }
-
- return ret;
-}
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c
index 205ad328aa52..c74436e687bf 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/vdso/vclock_gettime.c
@@ -60,7 +60,7 @@ notrace static cycle_t vread_tsc(void)
static notrace cycle_t vread_hpet(void)
{
- return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
+ return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + HPET_COUNTER);
}
#ifdef CONFIG_PARAVIRT_CLOCK
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 138e5667409a..39928d16be3b 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1517,72 +1517,51 @@ asmlinkage void __init xen_start_kernel(void)
#endif
}
-#ifdef CONFIG_XEN_PVHVM
-#define HVM_SHARED_INFO_ADDR 0xFE700000UL
-static struct shared_info *xen_hvm_shared_info;
-static unsigned long xen_hvm_sip_phys;
-static int xen_major, xen_minor;
-
-static void xen_hvm_connect_shared_info(unsigned long pfn)
+void __ref xen_hvm_init_shared_info(void)
{
+ int cpu;
struct xen_add_to_physmap xatp;
+ static struct shared_info *shared_info_page = 0;
+ if (!shared_info_page)
+ shared_info_page = (struct shared_info *)
+ extend_brk(PAGE_SIZE, PAGE_SIZE);
xatp.domid = DOMID_SELF;
xatp.idx = 0;
xatp.space = XENMAPSPACE_shared_info;
- xatp.gpfn = pfn;
+ xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT;
if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
BUG();
-}
-static void __init xen_hvm_set_shared_info(struct shared_info *sip)
-{
- int cpu;
-
- HYPERVISOR_shared_info = sip;
+ HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
/* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
* page, we use it in the event channel upcall and in some pvclock
* related functions. We don't need the vcpu_info placement
* optimizations because we don't use any pv_mmu or pv_irq op on
- * HVM. */
- for_each_online_cpu(cpu)
+ * HVM.
+ * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is
+ * online but xen_hvm_init_shared_info is run at resume time too and
+ * in that case multiple vcpus might be online. */
+ for_each_online_cpu(cpu) {
per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
-}
-
-/* Reconnect the shared_info pfn to a (new) mfn */
-void xen_hvm_resume_shared_info(void)
-{
- xen_hvm_connect_shared_info(xen_hvm_sip_phys >> PAGE_SHIFT);
-}
-
-/* Xen tools prior to Xen 4 do not provide a E820_Reserved area for guest usage.
- * On these old tools the shared info page will be placed in E820_Ram.
- * Xen 4 provides a E820_Reserved area at 0xFC000000, and this code expects
- * that nothing is mapped up to HVM_SHARED_INFO_ADDR.
- * Xen 4.3+ provides an explicit 1MB area at HVM_SHARED_INFO_ADDR which is used
- * here for the shared info page. */
-static void __init xen_hvm_init_shared_info(void)
-{
- if (xen_major < 4) {
- xen_hvm_shared_info = extend_brk(PAGE_SIZE, PAGE_SIZE);
- xen_hvm_sip_phys = __pa(xen_hvm_shared_info);
- } else {
- xen_hvm_sip_phys = HVM_SHARED_INFO_ADDR;
- set_fixmap(FIX_PARAVIRT_BOOTMAP, xen_hvm_sip_phys);
- xen_hvm_shared_info =
- (struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP);
}
- xen_hvm_connect_shared_info(xen_hvm_sip_phys >> PAGE_SHIFT);
- xen_hvm_set_shared_info(xen_hvm_shared_info);
}
+#ifdef CONFIG_XEN_PVHVM
static void __init init_hvm_pv_info(void)
{
- uint32_t ecx, edx, pages, msr, base;
+ int major, minor;
+ uint32_t eax, ebx, ecx, edx, pages, msr, base;
u64 pfn;
base = xen_cpuid_base();
+ cpuid(base + 1, &eax, &ebx, &ecx, &edx);
+
+ major = eax >> 16;
+ minor = eax & 0xffff;
+ printk(KERN_INFO "Xen version %d.%d.\n", major, minor);
+
cpuid(base + 2, &pages, &msr, &ecx, &edx);
pfn = __pa(hypercall_page);
@@ -1633,22 +1612,12 @@ static void __init xen_hvm_guest_init(void)
static bool __init xen_hvm_platform(void)
{
- uint32_t eax, ebx, ecx, edx, base;
-
if (xen_pv_domain())
return false;
- base = xen_cpuid_base();
- if (!base)
+ if (!xen_cpuid_base())
return false;
- cpuid(base + 1, &eax, &ebx, &ecx, &edx);
-
- xen_major = eax >> 16;
- xen_minor = eax & 0xffff;
-
- printk(KERN_INFO "Xen version %d.%d.\n", xen_major, xen_minor);
-
return true;
}
@@ -1668,6 +1637,7 @@ const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = {
.name = "Xen HVM",
.detect = xen_hvm_platform,
.init_platform = xen_hvm_guest_init,
+ .x2apic_available = xen_x2apic_para_available,
};
EXPORT_SYMBOL(x86_hyper_xen_hvm);
#endif
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 01de35c77221..e8e34938c57d 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1178,20 +1178,6 @@ static void xen_exit_mmap(struct mm_struct *mm)
static void xen_post_allocator_init(void);
-static __init void xen_mapping_pagetable_reserve(u64 start, u64 end)
-{
- /* reserve the range used */
- native_pagetable_reserve(start, end);
-
- /* set as RW the rest */
- printk(KERN_DEBUG "xen: setting RW the range %llx - %llx\n", end,
- PFN_PHYS(pgt_buf_top));
- while (end < PFN_PHYS(pgt_buf_top)) {
- make_lowmem_page_readwrite(__va(end));
- end += PAGE_SIZE;
- }
-}
-
#ifdef CONFIG_X86_64
static void __init xen_cleanhighmap(unsigned long vaddr,
unsigned long vaddr_end)
@@ -1422,7 +1408,6 @@ static void __xen_write_cr3(bool kernel, unsigned long cr3)
xen_mc_callback(set_current_cr3, (void *)cr3);
}
}
-
static void xen_write_cr3(unsigned long cr3)
{
BUG_ON(preemptible());
@@ -1448,6 +1433,45 @@ static void xen_write_cr3(unsigned long cr3)
xen_mc_issue(PARAVIRT_LAZY_CPU); /* interrupts restored */
}
+#ifdef CONFIG_X86_64
+/*
+ * At the start of the day - when Xen launches a guest, it has already
+ * built pagetables for the guest. We diligently look over them
+ * in xen_setup_kernel_pagetable and graft as appropiate them in the
+ * init_level4_pgt and its friends. Then when we are happy we load
+ * the new init_level4_pgt - and continue on.
+ *
+ * The generic code starts (start_kernel) and 'init_mem_mapping' sets
+ * up the rest of the pagetables. When it has completed it loads the cr3.
+ * N.B. that baremetal would start at 'start_kernel' (and the early
+ * #PF handler would create bootstrap pagetables) - so we are running
+ * with the same assumptions as what to do when write_cr3 is executed
+ * at this point.
+ *
+ * Since there are no user-page tables at all, we have two variants
+ * of xen_write_cr3 - the early bootup (this one), and the late one
+ * (xen_write_cr3). The reason we have to do that is that in 64-bit
+ * the Linux kernel and user-space are both in ring 3 while the
+ * hypervisor is in ring 0.
+ */
+static void __init xen_write_cr3_init(unsigned long cr3)
+{
+ BUG_ON(preemptible());
+
+ xen_mc_batch(); /* disables interrupts */
+
+ /* Update while interrupts are disabled, so its atomic with
+ respect to ipis */
+ this_cpu_write(xen_cr3, cr3);
+
+ __xen_write_cr3(true, cr3);
+
+ xen_mc_issue(PARAVIRT_LAZY_CPU); /* interrupts restored */
+
+ pv_mmu_ops.write_cr3 = &xen_write_cr3;
+}
+#endif
+
static int xen_pgd_alloc(struct mm_struct *mm)
{
pgd_t *pgd = mm->pgd;
@@ -1503,19 +1527,6 @@ static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
#else /* CONFIG_X86_64 */
static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
{
- unsigned long pfn = pte_pfn(pte);
-
- /*
- * If the new pfn is within the range of the newly allocated
- * kernel pagetable, and it isn't being mapped into an
- * early_ioremap fixmap slot as a freshly allocated page, make sure
- * it is RO.
- */
- if (((!is_early_ioremap_ptep(ptep) &&
- pfn >= pgt_buf_start && pfn < pgt_buf_top)) ||
- (is_early_ioremap_ptep(ptep) && pfn != (pgt_buf_end - 1)))
- pte = pte_wrprotect(pte);
-
return pte;
}
#endif /* CONFIG_X86_64 */
@@ -2129,11 +2140,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
.write_cr2 = xen_write_cr2,
.read_cr3 = xen_read_cr3,
-#ifdef CONFIG_X86_32
.write_cr3 = xen_write_cr3_init,
-#else
- .write_cr3 = xen_write_cr3,
-#endif
.flush_tlb_user = xen_flush_tlb,
.flush_tlb_kernel = xen_flush_tlb,
@@ -2197,7 +2204,6 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
void __init xen_init_mmu_ops(void)
{
- x86_init.mapping.pagetable_reserve = xen_mapping_pagetable_reserve;
x86_init.paging.pagetable_init = xen_pagetable_init;
pv_mmu_ops = xen_mmu_ops;
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index 8971a26d21ab..94eac5c85cdc 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -556,12 +556,9 @@ void __init xen_arch_setup(void)
COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE);
/* Set up idle, making sure it calls safe_halt() pvop */
-#ifdef CONFIG_X86_32
- boot_cpu_data.hlt_works_ok = 1;
-#endif
disable_cpuidle();
disable_cpufreq();
- WARN_ON(set_pm_idle_to_default());
+ WARN_ON(xen_set_default_idle());
fiddle_vdso();
#ifdef CONFIG_NUMA
numa_off = 1;
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 34bc4cee8887..09ea61d2e02f 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -300,8 +300,6 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
gdt = get_cpu_gdt_table(cpu);
ctxt->flags = VGCF_IN_KERNEL;
- ctxt->user_regs.ds = __USER_DS;
- ctxt->user_regs.es = __USER_DS;
ctxt->user_regs.ss = __KERNEL_DS;
#ifdef CONFIG_X86_32
ctxt->user_regs.fs = __KERNEL_PERCPU;
@@ -310,35 +308,41 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
ctxt->gs_base_kernel = per_cpu_offset(cpu);
#endif
ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
- ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
- xen_copy_trap_info(ctxt->trap_ctxt);
+ {
+ ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
+ ctxt->user_regs.ds = __USER_DS;
+ ctxt->user_regs.es = __USER_DS;
- ctxt->ldt_ents = 0;
+ xen_copy_trap_info(ctxt->trap_ctxt);
- BUG_ON((unsigned long)gdt & ~PAGE_MASK);
+ ctxt->ldt_ents = 0;
- gdt_mfn = arbitrary_virt_to_mfn(gdt);
- make_lowmem_page_readonly(gdt);
- make_lowmem_page_readonly(mfn_to_virt(gdt_mfn));
+ BUG_ON((unsigned long)gdt & ~PAGE_MASK);
- ctxt->gdt_frames[0] = gdt_mfn;
- ctxt->gdt_ents = GDT_ENTRIES;
+ gdt_mfn = arbitrary_virt_to_mfn(gdt);
+ make_lowmem_page_readonly(gdt);
+ make_lowmem_page_readonly(mfn_to_virt(gdt_mfn));
- ctxt->user_regs.cs = __KERNEL_CS;
- ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs);
+ ctxt->gdt_frames[0] = gdt_mfn;
+ ctxt->gdt_ents = GDT_ENTRIES;
- ctxt->kernel_ss = __KERNEL_DS;
- ctxt->kernel_sp = idle->thread.sp0;
+ ctxt->kernel_ss = __KERNEL_DS;
+ ctxt->kernel_sp = idle->thread.sp0;
#ifdef CONFIG_X86_32
- ctxt->event_callback_cs = __KERNEL_CS;
- ctxt->failsafe_callback_cs = __KERNEL_CS;
+ ctxt->event_callback_cs = __KERNEL_CS;
+ ctxt->failsafe_callback_cs = __KERNEL_CS;
#endif
- ctxt->event_callback_eip = (unsigned long)xen_hypervisor_callback;
- ctxt->failsafe_callback_eip = (unsigned long)xen_failsafe_callback;
+ ctxt->event_callback_eip =
+ (unsigned long)xen_hypervisor_callback;
+ ctxt->failsafe_callback_eip =
+ (unsigned long)xen_failsafe_callback;
+ }
+ ctxt->user_regs.cs = __KERNEL_CS;
+ ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs);
per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir);
ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index 83e866d714ce..f7a080ef0354 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -328,7 +328,6 @@ static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
if (per_cpu(lock_spinners, cpu) == xl) {
ADD_STATS(released_slow_kicked, 1);
xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
- break;
}
}
}
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c
index ae8a00c39de4..45329c8c226e 100644
--- a/arch/x86/xen/suspend.c
+++ b/arch/x86/xen/suspend.c
@@ -30,7 +30,7 @@ void xen_arch_hvm_post_suspend(int suspend_cancelled)
{
#ifdef CONFIG_XEN_PVHVM
int cpu;
- xen_hvm_resume_shared_info();
+ xen_hvm_init_shared_info();
xen_callback_vector();
xen_unplug_emulated_devices();
if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index f9643fc50de5..33ca6e42a4ca 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -89,11 +89,11 @@ ENTRY(xen_iret)
*/
#ifdef CONFIG_SMP
GET_THREAD_INFO(%eax)
- movl TI_cpu(%eax), %eax
- movl __per_cpu_offset(,%eax,4), %eax
- mov xen_vcpu(%eax), %eax
+ movl %ss:TI_cpu(%eax), %eax
+ movl %ss:__per_cpu_offset(,%eax,4), %eax
+ mov %ss:xen_vcpu(%eax), %eax
#else
- movl xen_vcpu, %eax
+ movl %ss:xen_vcpu, %eax
#endif
/* check IF state we're restoring */
@@ -106,11 +106,11 @@ ENTRY(xen_iret)
* resuming the code, so we don't have to be worried about
* being preempted to another CPU.
*/
- setz XEN_vcpu_info_mask(%eax)
+ setz %ss:XEN_vcpu_info_mask(%eax)
xen_iret_start_crit:
/* check for unmasked and pending */
- cmpw $0x0001, XEN_vcpu_info_pending(%eax)
+ cmpw $0x0001, %ss:XEN_vcpu_info_pending(%eax)
/*
* If there's something pending, mask events again so we can
@@ -118,7 +118,7 @@ xen_iret_start_crit:
* touch XEN_vcpu_info_mask.
*/
jne 1f
- movb $1, XEN_vcpu_info_mask(%eax)
+ movb $1, %ss:XEN_vcpu_info_mask(%eax)
1: popl %eax
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index d2e73d19d366..a95b41744ad0 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -40,7 +40,7 @@ void xen_enable_syscall(void);
void xen_vcpu_restore(void);
void xen_callback_vector(void);
-void xen_hvm_resume_shared_info(void);
+void xen_hvm_init_shared_info(void);
void xen_unplug_emulated_devices(void);
void __init xen_build_dynamic_phys_to_machine(void);
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 5aab1acabf1c..cb557be492b1 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -22,7 +22,7 @@ config XTENSA
configurable and extensible. The Linux port to the Xtensa
architecture supports all processor configurations and extensions,
with reasonable minimum requirements. The Xtensa Linux project has
- a home page at <http://xtensa.sourceforge.net/>.
+ a home page at <http://www.linux-xtensa.org/>.
config RWSEM_XCHGADD_ALGORITHM
def_bool y
@@ -132,6 +132,7 @@ choice
config XTENSA_PLATFORM_ISS
bool "ISS"
+ depends on TTY
select XTENSA_CALIBRATE_CCOUNT
select SERIAL_CONSOLE
select XTENSA_ISS_NETWORK
diff --git a/arch/xtensa/include/asm/signal.h b/arch/xtensa/include/asm/signal.h
index 6f586bd90e18..de169b4eaeef 100644
--- a/arch/xtensa/include/asm/signal.h
+++ b/arch/xtensa/include/asm/signal.h
@@ -15,16 +15,7 @@
#include <uapi/asm/signal.h>
#ifndef __ASSEMBLY__
-struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
- sigset_t sa_mask; /* mask last for extensibility */
-};
-
-struct k_sigaction {
- struct sigaction sa;
-};
+#define __ARCH_HAS_SA_RESTORER
#include <asm/sigcontext.h>
diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
index 8d5e47fad095..3673ff1f1bc5 100644
--- a/arch/xtensa/include/asm/syscall.h
+++ b/arch/xtensa/include/asm/syscall.h
@@ -9,15 +9,9 @@
*/
struct pt_regs;
-struct sigaction;
asmlinkage long xtensa_ptrace(long, long, long, long);
asmlinkage long xtensa_sigreturn(struct pt_regs*);
asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);
-asmlinkage long xtensa_sigaltstack(struct pt_regs *regs);
-asmlinkage long sys_rt_sigaction(int,
- const struct sigaction __user *,
- struct sigaction __user *,
- size_t);
asmlinkage long xtensa_shmat(int, char __user *, int);
asmlinkage long xtensa_fadvise64_64(int, int,
unsigned long long, unsigned long long);
@@ -31,4 +25,3 @@ asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
struct timespec __user *tsp,
const sigset_t __user *sigmask,
size_t sigsetsize);
-asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize);
diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h
index eb63ea87815c..c38834de9ac7 100644
--- a/arch/xtensa/include/asm/unistd.h
+++ b/arch/xtensa/include/asm/unistd.h
@@ -15,8 +15,6 @@
#define __ARCH_WANT_STAT64
#define __ARCH_WANT_SYS_UTIME
#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_GETPGRP
/*
diff --git a/arch/xtensa/include/uapi/asm/socket.h b/arch/xtensa/include/uapi/asm/socket.h
index 38079be1cf1e..35905cb6e419 100644
--- a/arch/xtensa/include/uapi/asm/socket.h
+++ b/arch/xtensa/include/uapi/asm/socket.h
@@ -32,7 +32,7 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 15 */
+#define SO_REUSEPORT 15
#define SO_PASSCRED 16
#define SO_PEERCRED 17
#define SO_RCVLOWAT 18
@@ -81,4 +81,6 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#define SO_LOCK_FILTER 44
+
#endif /* _XTENSA_SOCKET_H */
diff --git a/arch/xtensa/include/uapi/asm/unistd.h b/arch/xtensa/include/uapi/asm/unistd.h
index 5162418c5d90..19fac3f543a2 100644
--- a/arch/xtensa/include/uapi/asm/unistd.h
+++ b/arch/xtensa/include/uapi/asm/unistd.h
@@ -483,7 +483,7 @@ __SYSCALL(222, sys_ni_syscall, 0)
#define __NR_restart_syscall 223
__SYSCALL(223, sys_restart_syscall, 0)
#define __NR_sigaltstack 224
-__SYSCALL(224, xtensa_sigaltstack, 2)
+__SYSCALL(224, sys_sigaltstack, 2)
#define __NR_rt_sigreturn 225
__SYSCALL(225, xtensa_rt_sigreturn, 1)
#define __NR_rt_sigaction 226
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index de34d6be91cd..d7590dddd084 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -265,7 +265,7 @@ asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3,
ret = regs->areg[2];
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->areg[1]) == -EFAULT)
+ if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return ret;
@@ -368,11 +368,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user((void *)current->sas_ss_sp,
- &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->areg[1]),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->areg[1]);
err |= setup_sigcontext(frame, regs);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
@@ -424,16 +420,6 @@ give_sigsegv:
return -EFAULT;
}
-asmlinkage long xtensa_sigaltstack(const stack_t __user *uss,
- stack_t __user *uoss,
- long a2, long a3, long a4, long a5,
- struct pt_regs *regs)
-{
- return do_sigaltstack(uss, uoss, regs->areg[1]);
-}
-
-
-
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
index 01e0111bf787..ded955d45155 100644
--- a/arch/xtensa/kernel/traps.c
+++ b/arch/xtensa/kernel/traps.c
@@ -524,7 +524,7 @@ void die(const char * str, struct pt_regs * regs, long err)
if (!user_mode(regs))
show_stack(NULL, (unsigned long*)regs->areg[1]);
- add_taint(TAINT_DIE);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
spin_unlock_irq(&die_lock);
if (in_interrupt())
diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c
index 8207a119eee9..da9866f7fecf 100644
--- a/arch/xtensa/platforms/iss/console.c
+++ b/arch/xtensa/platforms/iss/console.c
@@ -58,7 +58,8 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
tty->port = &serial_port;
spin_lock(&timer_lock);
if (tty->count == 1) {
- setup_timer(&serial_timer, rs_poll, (unsigned long)tty);
+ setup_timer(&serial_timer, rs_poll,
+ (unsigned long)&serial_port);
mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
}
spin_unlock(&timer_lock);
@@ -97,8 +98,7 @@ static int rs_write(struct tty_struct * tty,
static void rs_poll(unsigned long priv)
{
- struct tty_struct* tty = (struct tty_struct*) priv;
-
+ struct tty_port *port = (struct tty_port *)priv;
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
int i = 0;
unsigned char c;
@@ -107,12 +107,12 @@ static void rs_poll(unsigned long priv)
while (__simc(SYS_select_one, 0, XTISS_SELECT_ONE_READ, (int)&tv,0,0)){
__simc (SYS_read, 0, (unsigned long)&c, 1, 0, 0);
- tty_insert_flip_char(tty, c, TTY_NORMAL);
+ tty_insert_flip_char(port, c, TTY_NORMAL);
i++;
}
if (i)
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(port);
mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
diff --git a/block/blk-core.c b/block/blk-core.c
index c973249d68cd..277134cb5d32 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1474,6 +1474,11 @@ void blk_queue_bio(struct request_queue *q, struct bio *bio)
*/
blk_queue_bounce(q, &bio);
+ if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
+ bio_endio(bio, -EIO);
+ return;
+ }
+
if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {
spin_lock_irq(q->queue_lock);
where = ELEVATOR_INSERT_FLUSH;
@@ -1714,9 +1719,6 @@ generic_make_request_checks(struct bio *bio)
*/
blk_partition_remap(bio);
- if (bio_integrity_enabled(bio) && bio_integrity_prep(bio))
- goto end_io;
-
if (bio_check_eod(bio, nr_sectors))
goto end_io;
diff --git a/block/blk-exec.c b/block/blk-exec.c
index 74638ec234c8..c88202f973d9 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -5,6 +5,7 @@
#include <linux/module.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
+#include <linux/sched/sysctl.h>
#include "blk.h"
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index da2a818c3a92..dabd221857e1 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -420,6 +420,8 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
} else
bi->name = bi_unsupported_name;
+ disk->queue->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
+
return 0;
}
EXPORT_SYMBOL(blk_integrity_register);
@@ -438,6 +440,8 @@ void blk_integrity_unregister(struct gendisk *disk)
if (!disk || !disk->integrity)
return;
+ disk->queue->backing_dev_info.capabilities &= ~BDI_CAP_STABLE_WRITES;
+
bi = disk->integrity;
kobject_uevent(&bi->kobj, KOBJ_REMOVE);
diff --git a/block/elevator.c b/block/elevator.c
index 9edba1b8323e..603b2c178740 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -100,14 +100,14 @@ static void elevator_put(struct elevator_type *e)
module_put(e->elevator_owner);
}
-static struct elevator_type *elevator_get(const char *name)
+static struct elevator_type *elevator_get(const char *name, bool try_loading)
{
struct elevator_type *e;
spin_lock(&elv_list_lock);
e = elevator_find(name);
- if (!e) {
+ if (!e && try_loading) {
spin_unlock(&elv_list_lock);
request_module("%s-iosched", name);
spin_lock(&elv_list_lock);
@@ -136,6 +136,22 @@ static int __init elevator_setup(char *str)
__setup("elevator=", elevator_setup);
+/* called during boot to load the elevator chosen by the elevator param */
+void __init load_default_elevator_module(void)
+{
+ struct elevator_type *e;
+
+ if (!chosen_elevator[0])
+ return;
+
+ spin_lock(&elv_list_lock);
+ e = elevator_find(chosen_elevator);
+ spin_unlock(&elv_list_lock);
+
+ if (!e)
+ request_module("%s-iosched", chosen_elevator);
+}
+
static struct kobj_type elv_ktype;
static struct elevator_queue *elevator_alloc(struct request_queue *q,
@@ -191,25 +207,30 @@ int elevator_init(struct request_queue *q, char *name)
q->boundary_rq = NULL;
if (name) {
- e = elevator_get(name);
+ e = elevator_get(name, true);
if (!e)
return -EINVAL;
}
+ /*
+ * Use the default elevator specified by config boot param or
+ * config option. Don't try to load modules as we could be running
+ * off async and request_module() isn't allowed from async.
+ */
if (!e && *chosen_elevator) {
- e = elevator_get(chosen_elevator);
+ e = elevator_get(chosen_elevator, false);
if (!e)
printk(KERN_ERR "I/O scheduler %s not found\n",
chosen_elevator);
}
if (!e) {
- e = elevator_get(CONFIG_DEFAULT_IOSCHED);
+ e = elevator_get(CONFIG_DEFAULT_IOSCHED, false);
if (!e) {
printk(KERN_ERR
"Default I/O scheduler not found. " \
"Using noop.\n");
- e = elevator_get("noop");
+ e = elevator_get("noop", false);
}
}
@@ -951,7 +972,7 @@ int elevator_change(struct request_queue *q, const char *name)
return -ENXIO;
strlcpy(elevator_name, name, sizeof(elevator_name));
- e = elevator_get(strstrip(elevator_name));
+ e = elevator_get(strstrip(elevator_name), true);
if (!e) {
printk(KERN_ERR "elevator: type %s not found\n", elevator_name);
return -EINVAL;
diff --git a/block/genhd.c b/block/genhd.c
index 9a289d7c84bb..5f73c2435fde 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -18,6 +18,7 @@
#include <linux/mutex.h>
#include <linux/idr.h>
#include <linux/log2.h>
+#include <linux/pm_runtime.h>
#include "blk.h"
@@ -35,6 +36,8 @@ static DEFINE_IDR(ext_devt_idr);
static struct device_type disk_type;
+static void disk_check_events(struct disk_events *ev,
+ unsigned int *clearing_ptr);
static void disk_alloc_events(struct gendisk *disk);
static void disk_add_events(struct gendisk *disk);
static void disk_del_events(struct gendisk *disk);
@@ -532,6 +535,14 @@ static void register_disk(struct gendisk *disk)
return;
}
}
+
+ /*
+ * avoid probable deadlock caused by allocating memory with
+ * GFP_KERNEL in runtime_resume callback of its all ancestor
+ * devices
+ */
+ pm_runtime_set_memalloc_noio(ddev, true);
+
disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
@@ -661,6 +672,7 @@ void del_gendisk(struct gendisk *disk)
disk->driverfs_dev = NULL;
if (!sysfs_deprecated)
sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
+ pm_runtime_set_memalloc_noio(disk_to_dev(disk), false);
device_del(disk_to_dev(disk));
}
EXPORT_SYMBOL(del_gendisk);
@@ -1549,6 +1561,7 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
const struct block_device_operations *bdops = disk->fops;
struct disk_events *ev = disk->ev;
unsigned int pending;
+ unsigned int clearing = mask;
if (!ev) {
/* for drivers still using the old ->media_changed method */
@@ -1558,34 +1571,53 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
return 0;
}
- /* tell the workfn about the events being cleared */
+ disk_block_events(disk);
+
+ /*
+ * store the union of mask and ev->clearing on the stack so that the
+ * race with disk_flush_events does not cause ambiguity (ev->clearing
+ * can still be modified even if events are blocked).
+ */
spin_lock_irq(&ev->lock);
- ev->clearing |= mask;
+ clearing |= ev->clearing;
+ ev->clearing = 0;
spin_unlock_irq(&ev->lock);
- /* uncondtionally schedule event check and wait for it to finish */
- disk_block_events(disk);
- queue_delayed_work(system_freezable_wq, &ev->dwork, 0);
- flush_delayed_work(&ev->dwork);
- __disk_unblock_events(disk, false);
+ disk_check_events(ev, &clearing);
+ /*
+ * if ev->clearing is not 0, the disk_flush_events got called in the
+ * middle of this function, so we want to run the workfn without delay.
+ */
+ __disk_unblock_events(disk, ev->clearing ? true : false);
/* then, fetch and clear pending events */
spin_lock_irq(&ev->lock);
- WARN_ON_ONCE(ev->clearing & mask); /* cleared by workfn */
pending = ev->pending & mask;
ev->pending &= ~mask;
spin_unlock_irq(&ev->lock);
+ WARN_ON_ONCE(clearing & mask);
return pending;
}
+/*
+ * Separate this part out so that a different pointer for clearing_ptr can be
+ * passed in for disk_clear_events.
+ */
static void disk_events_workfn(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct disk_events *ev = container_of(dwork, struct disk_events, dwork);
+
+ disk_check_events(ev, &ev->clearing);
+}
+
+static void disk_check_events(struct disk_events *ev,
+ unsigned int *clearing_ptr)
+{
struct gendisk *disk = ev->disk;
char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
- unsigned int clearing = ev->clearing;
+ unsigned int clearing = *clearing_ptr;
unsigned int events;
unsigned long intv;
int nr_events = 0, i;
@@ -1598,7 +1630,7 @@ static void disk_events_workfn(struct work_struct *work)
events &= ~ev->pending;
ev->pending |= events;
- ev->clearing &= ~clearing;
+ *clearing_ptr &= ~clearing;
intv = disk_events_poll_jiffies(disk);
if (!ev->block && intv)
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 4641d95651d3..05c0ce52f96d 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -134,8 +134,8 @@ config CRYPTO_NULL
These are 'Null' algorithms, used by IPsec, which do nothing.
config CRYPTO_PCRYPT
- tristate "Parallel crypto engine (EXPERIMENTAL)"
- depends on SMP && EXPERIMENTAL
+ tristate "Parallel crypto engine"
+ depends on SMP
select PADATA
select CRYPTO_MANAGER
select CRYPTO_AEAD
@@ -292,7 +292,6 @@ config CRYPTO_HMAC
config CRYPTO_XCBC
tristate "XCBC support"
- depends on EXPERIMENTAL
select CRYPTO_HASH
select CRYPTO_MANAGER
help
@@ -303,7 +302,6 @@ config CRYPTO_XCBC
config CRYPTO_VMAC
tristate "VMAC support"
- depends on EXPERIMENTAL
select CRYPTO_HASH
select CRYPTO_MANAGER
help
@@ -355,6 +353,27 @@ config CRYPTO_CRC32C_SPARC64
CRC32c CRC algorithm implemented using sparc64 crypto instructions,
when available.
+config CRYPTO_CRC32
+ tristate "CRC32 CRC algorithm"
+ select CRYPTO_HASH
+ select CRC32
+ help
+ CRC-32-IEEE 802.3 cyclic redundancy-check algorithm.
+ Shash crypto api wrappers to crc32_le function.
+
+config CRYPTO_CRC32_PCLMUL
+ tristate "CRC32 PCLMULQDQ hardware acceleration"
+ depends on X86
+ select CRYPTO_HASH
+ select CRC32
+ help
+ From Intel Westmere and AMD Bulldozer processor with SSE4.2
+ and PCLMULQDQ supported, the processor will support
+ CRC32 PCLMULQDQ implementation using hardware accelerated PCLMULQDQ
+ instruction. This option will create 'crc32-plcmul' module,
+ which will enable any routine to use the CRC-32-IEEE 802.3 checksum
+ and gain better performance as compared with the table implementation.
+
config CRYPTO_GHASH
tristate "GHASH digest algorithm"
select CRYPTO_GF128MUL
@@ -479,6 +498,13 @@ config CRYPTO_SHA1_ARM
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented
using optimized ARM assembler.
+config CRYPTO_SHA1_PPC
+ tristate "SHA1 digest algorithm (powerpc)"
+ depends on PPC
+ help
+ This is the powerpc hardware accelerated implementation of the
+ SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
config CRYPTO_SHA256
tristate "SHA224 and SHA256 digest algorithm"
select CRYPTO_HASH
@@ -932,8 +958,7 @@ config CRYPTO_KHAZAD
<http://www.larc.usp.br/~pbarreto/KhazadPage.html>
config CRYPTO_SALSA20
- tristate "Salsa20 stream cipher algorithm (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "Salsa20 stream cipher algorithm"
select CRYPTO_BLKCIPHER
help
Salsa20 stream cipher algorithm.
@@ -945,9 +970,8 @@ config CRYPTO_SALSA20
Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html>
config CRYPTO_SALSA20_586
- tristate "Salsa20 stream cipher algorithm (i586) (EXPERIMENTAL)"
+ tristate "Salsa20 stream cipher algorithm (i586)"
depends on (X86 || UML_X86) && !64BIT
- depends on EXPERIMENTAL
select CRYPTO_BLKCIPHER
help
Salsa20 stream cipher algorithm.
@@ -959,9 +983,8 @@ config CRYPTO_SALSA20_586
Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html>
config CRYPTO_SALSA20_X86_64
- tristate "Salsa20 stream cipher algorithm (x86_64) (EXPERIMENTAL)"
+ tristate "Salsa20 stream cipher algorithm (x86_64)"
depends on (X86 || UML_X86) && 64BIT
- depends on EXPERIMENTAL
select CRYPTO_BLKCIPHER
help
Salsa20 stream cipher algorithm.
diff --git a/crypto/Makefile b/crypto/Makefile
index d59dec749804..be1a1bebbb86 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
+obj-$(CONFIG_CRYPTO_CRC32) += crc32.o
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
obj-$(CONFIG_CRYPTO_LZO) += lzo.o
obj-$(CONFIG_CRYPTO_842) += 842.o
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
index 533de9550a82..7d4a8d28277e 100644
--- a/crypto/ablkcipher.c
+++ b/crypto/ablkcipher.c
@@ -388,9 +388,9 @@ static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_report_blkcipher rblkcipher;
- snprintf(rblkcipher.type, CRYPTO_MAX_ALG_NAME, "%s", "ablkcipher");
- snprintf(rblkcipher.geniv, CRYPTO_MAX_ALG_NAME, "%s",
- alg->cra_ablkcipher.geniv ?: "<default>");
+ strncpy(rblkcipher.type, "ablkcipher", sizeof(rblkcipher.type));
+ strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "<default>",
+ sizeof(rblkcipher.geniv));
rblkcipher.blocksize = alg->cra_blocksize;
rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize;
@@ -469,9 +469,9 @@ static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_report_blkcipher rblkcipher;
- snprintf(rblkcipher.type, CRYPTO_MAX_ALG_NAME, "%s", "givcipher");
- snprintf(rblkcipher.geniv, CRYPTO_MAX_ALG_NAME, "%s",
- alg->cra_ablkcipher.geniv ?: "<built-in>");
+ strncpy(rblkcipher.type, "givcipher", sizeof(rblkcipher.type));
+ strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "<built-in>",
+ sizeof(rblkcipher.geniv));
rblkcipher.blocksize = alg->cra_blocksize;
rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize;
diff --git a/crypto/aead.c b/crypto/aead.c
index 0b8121ebec07..547491e35c63 100644
--- a/crypto/aead.c
+++ b/crypto/aead.c
@@ -117,9 +117,8 @@ static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
struct crypto_report_aead raead;
struct aead_alg *aead = &alg->cra_aead;
- snprintf(raead.type, CRYPTO_MAX_ALG_NAME, "%s", "aead");
- snprintf(raead.geniv, CRYPTO_MAX_ALG_NAME, "%s",
- aead->geniv ?: "<built-in>");
+ strncpy(raead.type, "aead", sizeof(raead.type));
+ strncpy(raead.geniv, aead->geniv ?: "<built-in>", sizeof(raead.geniv));
raead.blocksize = alg->cra_blocksize;
raead.maxauthsize = aead->maxauthsize;
@@ -203,8 +202,8 @@ static int crypto_nivaead_report(struct sk_buff *skb, struct crypto_alg *alg)
struct crypto_report_aead raead;
struct aead_alg *aead = &alg->cra_aead;
- snprintf(raead.type, CRYPTO_MAX_ALG_NAME, "%s", "nivaead");
- snprintf(raead.geniv, CRYPTO_MAX_ALG_NAME, "%s", aead->geniv);
+ strncpy(raead.type, "nivaead", sizeof(raead.type));
+ strncpy(raead.geniv, aead->geniv, sizeof(raead.geniv));
raead.blocksize = alg->cra_blocksize;
raead.maxauthsize = aead->maxauthsize;
@@ -282,18 +281,16 @@ struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl,
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV)) &
algt->mask)
return ERR_PTR(-EINVAL);
name = crypto_attr_alg_name(tb[1]);
- err = PTR_ERR(name);
if (IS_ERR(name))
- return ERR_PTR(err);
+ return ERR_CAST(name);
inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
if (!inst)
diff --git a/crypto/ahash.c b/crypto/ahash.c
index 3887856c2dd6..793a27f2493e 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -404,7 +404,7 @@ static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_report_hash rhash;
- snprintf(rhash.type, CRYPTO_MAX_ALG_NAME, "%s", "ahash");
+ strncpy(rhash.type, "ahash", sizeof(rhash.type));
rhash.blocksize = alg->cra_blocksize;
rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize;
diff --git a/crypto/algapi.c b/crypto/algapi.c
index c3b9bfeeb7ff..08c57c8aec95 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -749,12 +749,10 @@ struct crypto_alg *crypto_attr_alg2(struct rtattr *rta,
u32 type, u32 mask)
{
const char *name;
- int err;
name = crypto_attr_alg_name(rta);
- err = PTR_ERR(name);
if (IS_ERR(name))
- return ERR_PTR(err);
+ return ERR_CAST(name);
return crypto_find_alg(name, frontend, type, mask);
}
diff --git a/crypto/authenc.c b/crypto/authenc.c
index d0583a4489e6..ffce19de05cf 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -592,9 +592,8 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
return ERR_PTR(-EINVAL);
diff --git a/crypto/authencesn.c b/crypto/authencesn.c
index 136b68b9d8d4..ab53762fc309 100644
--- a/crypto/authencesn.c
+++ b/crypto/authencesn.c
@@ -715,9 +715,8 @@ static struct crypto_instance *crypto_authenc_esn_alloc(struct rtattr **tb)
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
return ERR_PTR(-EINVAL);
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index a8d85a1d670e..a79e7e9ab86e 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -499,9 +499,9 @@ static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_report_blkcipher rblkcipher;
- snprintf(rblkcipher.type, CRYPTO_MAX_ALG_NAME, "%s", "blkcipher");
- snprintf(rblkcipher.geniv, CRYPTO_MAX_ALG_NAME, "%s",
- alg->cra_blkcipher.geniv ?: "<default>");
+ strncpy(rblkcipher.type, "blkcipher", sizeof(rblkcipher.type));
+ strncpy(rblkcipher.geniv, alg->cra_blkcipher.geniv ?: "<default>",
+ sizeof(rblkcipher.geniv));
rblkcipher.blocksize = alg->cra_blocksize;
rblkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
@@ -588,18 +588,16 @@ struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl,
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
if ((algt->type ^ (CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_GENIV)) &
algt->mask)
return ERR_PTR(-EINVAL);
name = crypto_attr_alg_name(tb[1]);
- err = PTR_ERR(name);
if (IS_ERR(name))
- return ERR_PTR(err);
+ return ERR_CAST(name);
inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
if (!inst)
diff --git a/crypto/ccm.c b/crypto/ccm.c
index 32fe1bb5decb..499c91717d93 100644
--- a/crypto/ccm.c
+++ b/crypto/ccm.c
@@ -484,18 +484,16 @@ static struct crypto_instance *crypto_ccm_alloc_common(struct rtattr **tb,
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
return ERR_PTR(-EINVAL);
cipher = crypto_alg_mod_lookup(cipher_name, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
- err = PTR_ERR(cipher);
if (IS_ERR(cipher))
- return ERR_PTR(err);
+ return ERR_CAST(cipher);
err = -EINVAL;
if (cipher->cra_blocksize != 16)
@@ -573,15 +571,13 @@ out_put_cipher:
static struct crypto_instance *crypto_ccm_alloc(struct rtattr **tb)
{
- int err;
const char *cipher_name;
char ctr_name[CRYPTO_MAX_ALG_NAME];
char full_name[CRYPTO_MAX_ALG_NAME];
cipher_name = crypto_attr_alg_name(tb[1]);
- err = PTR_ERR(cipher_name);
if (IS_ERR(cipher_name))
- return ERR_PTR(err);
+ return ERR_CAST(cipher_name);
if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)",
cipher_name) >= CRYPTO_MAX_ALG_NAME)
@@ -612,20 +608,17 @@ static struct crypto_template crypto_ccm_tmpl = {
static struct crypto_instance *crypto_ccm_base_alloc(struct rtattr **tb)
{
- int err;
const char *ctr_name;
const char *cipher_name;
char full_name[CRYPTO_MAX_ALG_NAME];
ctr_name = crypto_attr_alg_name(tb[1]);
- err = PTR_ERR(ctr_name);
if (IS_ERR(ctr_name))
- return ERR_PTR(err);
+ return ERR_CAST(ctr_name);
cipher_name = crypto_attr_alg_name(tb[2]);
- err = PTR_ERR(cipher_name);
if (IS_ERR(cipher_name))
- return ERR_PTR(err);
+ return ERR_CAST(cipher_name);
if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "ccm_base(%s,%s)",
ctr_name, cipher_name) >= CRYPTO_MAX_ALG_NAME)
@@ -760,17 +753,15 @@ static struct crypto_instance *crypto_rfc4309_alloc(struct rtattr **tb)
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
return ERR_PTR(-EINVAL);
ccm_name = crypto_attr_alg_name(tb[1]);
- err = PTR_ERR(ccm_name);
if (IS_ERR(ccm_name))
- return ERR_PTR(err);
+ return ERR_CAST(ccm_name);
inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
if (!inst)
diff --git a/crypto/chainiv.c b/crypto/chainiv.c
index ba200b07449d..834d8dd3d4fc 100644
--- a/crypto/chainiv.c
+++ b/crypto/chainiv.c
@@ -291,9 +291,8 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb)
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
err = crypto_get_default_rng();
if (err)
diff --git a/crypto/crc32.c b/crypto/crc32.c
new file mode 100644
index 000000000000..9d1c41569898
--- /dev/null
+++ b/crypto/crc32.c
@@ -0,0 +1,158 @@
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see http://www.gnu.org/licenses
+ *
+ * Please visit http://www.xyratex.com/contact if you need additional
+ * information or have any questions.
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright 2012 Xyratex Technology Limited
+ */
+
+/*
+ * This is crypto api shash wrappers to crc32_le.
+ */
+
+#include <linux/crc32.h>
+#include <crypto/internal/hash.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#define CHKSUM_BLOCK_SIZE 1
+#define CHKSUM_DIGEST_SIZE 4
+
+static u32 __crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+ return crc32_le(crc, p, len);
+}
+
+/** No default init with ~0 */
+static int crc32_cra_init(struct crypto_tfm *tfm)
+{
+ u32 *key = crypto_tfm_ctx(tfm);
+
+ *key = 0;
+
+ return 0;
+}
+
+
+/*
+ * Setting the seed allows arbitrary accumulators and flexible XOR policy
+ * If your algorithm starts with ~0, then XOR with ~0 before you set
+ * the seed.
+ */
+static int crc32_setkey(struct crypto_shash *hash, const u8 *key,
+ unsigned int keylen)
+{
+ u32 *mctx = crypto_shash_ctx(hash);
+
+ if (keylen != sizeof(u32)) {
+ crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+ *mctx = le32_to_cpup((__le32 *)key);
+ return 0;
+}
+
+static int crc32_init(struct shash_desc *desc)
+{
+ u32 *mctx = crypto_shash_ctx(desc->tfm);
+ u32 *crcp = shash_desc_ctx(desc);
+
+ *crcp = *mctx;
+
+ return 0;
+}
+
+static int crc32_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ u32 *crcp = shash_desc_ctx(desc);
+
+ *crcp = __crc32_le(*crcp, data, len);
+ return 0;
+}
+
+/* No final XOR 0xFFFFFFFF, like crc32_le */
+static int __crc32_finup(u32 *crcp, const u8 *data, unsigned int len,
+ u8 *out)
+{
+ *(__le32 *)out = cpu_to_le32(__crc32_le(*crcp, data, len));
+ return 0;
+}
+
+static int crc32_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ return __crc32_finup(shash_desc_ctx(desc), data, len, out);
+}
+
+static int crc32_final(struct shash_desc *desc, u8 *out)
+{
+ u32 *crcp = shash_desc_ctx(desc);
+
+ *(__le32 *)out = cpu_to_le32p(crcp);
+ return 0;
+}
+
+static int crc32_digest(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ return __crc32_finup(crypto_shash_ctx(desc->tfm), data, len,
+ out);
+}
+static struct shash_alg alg = {
+ .setkey = crc32_setkey,
+ .init = crc32_init,
+ .update = crc32_update,
+ .final = crc32_final,
+ .finup = crc32_finup,
+ .digest = crc32_digest,
+ .descsize = sizeof(u32),
+ .digestsize = CHKSUM_DIGEST_SIZE,
+ .base = {
+ .cra_name = "crc32",
+ .cra_driver_name = "crc32-table",
+ .cra_priority = 100,
+ .cra_blocksize = CHKSUM_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(u32),
+ .cra_module = THIS_MODULE,
+ .cra_init = crc32_cra_init,
+ }
+};
+
+static int __init crc32_mod_init(void)
+{
+ return crypto_register_shash(&alg);
+}
+
+static void __exit crc32_mod_fini(void)
+{
+ crypto_unregister_shash(&alg);
+}
+
+module_init(crc32_mod_init);
+module_exit(crc32_mod_fini);
+
+MODULE_AUTHOR("Alexander Boyko <alexander_boyko@xyratex.com>");
+MODULE_DESCRIPTION("CRC32 calculations wrapper for lib/crc32");
+MODULE_LICENSE("GPL");
diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
index 35d700a97d79..dfd511fb39ee 100644
--- a/crypto/crypto_user.c
+++ b/crypto/crypto_user.c
@@ -30,6 +30,8 @@
#include "internal.h"
+#define null_terminated(x) (strnlen(x, sizeof(x)) < sizeof(x))
+
static DEFINE_MUTEX(crypto_cfg_mutex);
/* The crypto netlink socket */
@@ -75,7 +77,7 @@ static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_report_cipher rcipher;
- snprintf(rcipher.type, CRYPTO_MAX_ALG_NAME, "%s", "cipher");
+ strncpy(rcipher.type, "cipher", sizeof(rcipher.type));
rcipher.blocksize = alg->cra_blocksize;
rcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
@@ -94,8 +96,7 @@ static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_report_comp rcomp;
- snprintf(rcomp.type, CRYPTO_MAX_ALG_NAME, "%s", "compression");
-
+ strncpy(rcomp.type, "compression", sizeof(rcomp.type));
if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
sizeof(struct crypto_report_comp), &rcomp))
goto nla_put_failure;
@@ -108,12 +109,14 @@ nla_put_failure:
static int crypto_report_one(struct crypto_alg *alg,
struct crypto_user_alg *ualg, struct sk_buff *skb)
{
- memcpy(&ualg->cru_name, &alg->cra_name, sizeof(ualg->cru_name));
- memcpy(&ualg->cru_driver_name, &alg->cra_driver_name,
- sizeof(ualg->cru_driver_name));
- memcpy(&ualg->cru_module_name, module_name(alg->cra_module),
- CRYPTO_MAX_ALG_NAME);
-
+ strncpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
+ strncpy(ualg->cru_driver_name, alg->cra_driver_name,
+ sizeof(ualg->cru_driver_name));
+ strncpy(ualg->cru_module_name, module_name(alg->cra_module),
+ sizeof(ualg->cru_module_name));
+
+ ualg->cru_type = 0;
+ ualg->cru_mask = 0;
ualg->cru_flags = alg->cra_flags;
ualg->cru_refcnt = atomic_read(&alg->cra_refcnt);
@@ -122,8 +125,7 @@ static int crypto_report_one(struct crypto_alg *alg,
if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
struct crypto_report_larval rl;
- snprintf(rl.type, CRYPTO_MAX_ALG_NAME, "%s", "larval");
-
+ strncpy(rl.type, "larval", sizeof(rl.type));
if (nla_put(skb, CRYPTOCFGA_REPORT_LARVAL,
sizeof(struct crypto_report_larval), &rl))
goto nla_put_failure;
@@ -196,7 +198,10 @@ static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
struct crypto_dump_info info;
int err;
- if (!p->cru_driver_name)
+ if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
+ return -EINVAL;
+
+ if (!p->cru_driver_name[0])
return -EINVAL;
alg = crypto_alg_match(p, 1);
@@ -260,6 +265,9 @@ static int crypto_update_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL];
LIST_HEAD(list);
+ if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
+ return -EINVAL;
+
if (priority && !strlen(p->cru_driver_name))
return -EINVAL;
@@ -287,6 +295,9 @@ static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
struct crypto_alg *alg;
struct crypto_user_alg *p = nlmsg_data(nlh);
+ if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
+ return -EINVAL;
+
alg = crypto_alg_match(p, 1);
if (!alg)
return -ENOENT;
@@ -368,6 +379,9 @@ static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
struct crypto_user_alg *p = nlmsg_data(nlh);
struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL];
+ if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
+ return -EINVAL;
+
if (strlen(p->cru_driver_name))
exact = 1;
diff --git a/crypto/ctr.c b/crypto/ctr.c
index 4ca7222cfeb6..f2b94f27bb2c 100644
--- a/crypto/ctr.c
+++ b/crypto/ctr.c
@@ -12,6 +12,7 @@
#include <crypto/algapi.h>
#include <crypto/ctr.h>
+#include <crypto/internal/skcipher.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -25,10 +26,15 @@ struct crypto_ctr_ctx {
};
struct crypto_rfc3686_ctx {
- struct crypto_blkcipher *child;
+ struct crypto_ablkcipher *child;
u8 nonce[CTR_RFC3686_NONCE_SIZE];
};
+struct crypto_rfc3686_req_ctx {
+ u8 iv[CTR_RFC3686_BLOCK_SIZE];
+ struct ablkcipher_request subreq CRYPTO_MINALIGN_ATTR;
+};
+
static int crypto_ctr_setkey(struct crypto_tfm *parent, const u8 *key,
unsigned int keylen)
{
@@ -243,11 +249,11 @@ static struct crypto_template crypto_ctr_tmpl = {
.module = THIS_MODULE,
};
-static int crypto_rfc3686_setkey(struct crypto_tfm *parent, const u8 *key,
- unsigned int keylen)
+static int crypto_rfc3686_setkey(struct crypto_ablkcipher *parent,
+ const u8 *key, unsigned int keylen)
{
- struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(parent);
- struct crypto_blkcipher *child = ctx->child;
+ struct crypto_rfc3686_ctx *ctx = crypto_ablkcipher_ctx(parent);
+ struct crypto_ablkcipher *child = ctx->child;
int err;
/* the nonce is stored in bytes at end of key */
@@ -259,59 +265,64 @@ static int crypto_rfc3686_setkey(struct crypto_tfm *parent, const u8 *key,
keylen -= CTR_RFC3686_NONCE_SIZE;
- crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
- crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) &
- CRYPTO_TFM_REQ_MASK);
- err = crypto_blkcipher_setkey(child, key, keylen);
- crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) &
- CRYPTO_TFM_RES_MASK);
+ crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ err = crypto_ablkcipher_setkey(child, key, keylen);
+ crypto_ablkcipher_set_flags(parent, crypto_ablkcipher_get_flags(child) &
+ CRYPTO_TFM_RES_MASK);
return err;
}
-static int crypto_rfc3686_crypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int crypto_rfc3686_crypt(struct ablkcipher_request *req)
{
- struct crypto_blkcipher *tfm = desc->tfm;
- struct crypto_rfc3686_ctx *ctx = crypto_blkcipher_ctx(tfm);
- struct crypto_blkcipher *child = ctx->child;
- unsigned long alignmask = crypto_blkcipher_alignmask(tfm);
- u8 ivblk[CTR_RFC3686_BLOCK_SIZE + alignmask];
- u8 *iv = PTR_ALIGN(ivblk + 0, alignmask + 1);
- u8 *info = desc->info;
- int err;
+ struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+ struct crypto_rfc3686_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+ struct crypto_ablkcipher *child = ctx->child;
+ unsigned long align = crypto_ablkcipher_alignmask(tfm);
+ struct crypto_rfc3686_req_ctx *rctx =
+ (void *)PTR_ALIGN((u8 *)ablkcipher_request_ctx(req), align + 1);
+ struct ablkcipher_request *subreq = &rctx->subreq;
+ u8 *iv = rctx->iv;
/* set up counter block */
memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
- memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE);
+ memcpy(iv + CTR_RFC3686_NONCE_SIZE, req->info, CTR_RFC3686_IV_SIZE);
/* initialize counter portion of counter block */
*(__be32 *)(iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) =
cpu_to_be32(1);
- desc->tfm = child;
- desc->info = iv;
- err = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
- desc->tfm = tfm;
- desc->info = info;
+ ablkcipher_request_set_tfm(subreq, child);
+ ablkcipher_request_set_callback(subreq, req->base.flags,
+ req->base.complete, req->base.data);
+ ablkcipher_request_set_crypt(subreq, req->src, req->dst, req->nbytes,
+ iv);
- return err;
+ return crypto_ablkcipher_encrypt(subreq);
}
static int crypto_rfc3686_init_tfm(struct crypto_tfm *tfm)
{
struct crypto_instance *inst = (void *)tfm->__crt_alg;
- struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+ struct crypto_skcipher_spawn *spawn = crypto_instance_ctx(inst);
struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(tfm);
- struct crypto_blkcipher *cipher;
+ struct crypto_ablkcipher *cipher;
+ unsigned long align;
- cipher = crypto_spawn_blkcipher(spawn);
+ cipher = crypto_spawn_skcipher(spawn);
if (IS_ERR(cipher))
return PTR_ERR(cipher);
ctx->child = cipher;
+ align = crypto_tfm_alg_alignmask(tfm);
+ align &= ~(crypto_tfm_ctx_alignment() - 1);
+ tfm->crt_ablkcipher.reqsize = align +
+ sizeof(struct crypto_rfc3686_req_ctx) +
+ crypto_ablkcipher_reqsize(cipher);
+
return 0;
}
@@ -319,74 +330,108 @@ static void crypto_rfc3686_exit_tfm(struct crypto_tfm *tfm)
{
struct crypto_rfc3686_ctx *ctx = crypto_tfm_ctx(tfm);
- crypto_free_blkcipher(ctx->child);
+ crypto_free_ablkcipher(ctx->child);
}
static struct crypto_instance *crypto_rfc3686_alloc(struct rtattr **tb)
{
+ struct crypto_attr_type *algt;
struct crypto_instance *inst;
struct crypto_alg *alg;
+ struct crypto_skcipher_spawn *spawn;
+ const char *cipher_name;
int err;
- err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+ algt = crypto_get_attr_type(tb);
+ if (IS_ERR(algt))
+ return ERR_CAST(algt);
+
+ if ((algt->type ^ CRYPTO_ALG_TYPE_BLKCIPHER) & algt->mask)
+ return ERR_PTR(-EINVAL);
+
+ cipher_name = crypto_attr_alg_name(tb[1]);
+ if (IS_ERR(cipher_name))
+ return ERR_CAST(cipher_name);
+
+ inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+ if (!inst)
+ return ERR_PTR(-ENOMEM);
+
+ spawn = crypto_instance_ctx(inst);
+
+ crypto_set_skcipher_spawn(spawn, inst);
+ err = crypto_grab_skcipher(spawn, cipher_name, 0,
+ crypto_requires_sync(algt->type,
+ algt->mask));
if (err)
- return ERR_PTR(err);
+ goto err_free_inst;
- alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER,
- CRYPTO_ALG_TYPE_MASK);
- err = PTR_ERR(alg);
- if (IS_ERR(alg))
- return ERR_PTR(err);
+ alg = crypto_skcipher_spawn_alg(spawn);
/* We only support 16-byte blocks. */
err = -EINVAL;
- if (alg->cra_blkcipher.ivsize != CTR_RFC3686_BLOCK_SIZE)
- goto out_put_alg;
+ if (alg->cra_ablkcipher.ivsize != CTR_RFC3686_BLOCK_SIZE)
+ goto err_drop_spawn;
/* Not a stream cipher? */
if (alg->cra_blocksize != 1)
- goto out_put_alg;
+ goto err_drop_spawn;
- inst = crypto_alloc_instance("rfc3686", alg);
- if (IS_ERR(inst))
- goto out;
+ err = -ENAMETOOLONG;
+ if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "rfc3686(%s)",
+ alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
+ goto err_drop_spawn;
+ if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+ "rfc3686(%s)", alg->cra_driver_name) >=
+ CRYPTO_MAX_ALG_NAME)
+ goto err_drop_spawn;
- inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
inst->alg.cra_priority = alg->cra_priority;
inst->alg.cra_blocksize = 1;
inst->alg.cra_alignmask = alg->cra_alignmask;
- inst->alg.cra_type = &crypto_blkcipher_type;
- inst->alg.cra_blkcipher.ivsize = CTR_RFC3686_IV_SIZE;
- inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize
- + CTR_RFC3686_NONCE_SIZE;
- inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize
- + CTR_RFC3686_NONCE_SIZE;
+ inst->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ (alg->cra_flags & CRYPTO_ALG_ASYNC);
+ inst->alg.cra_type = &crypto_ablkcipher_type;
+
+ inst->alg.cra_ablkcipher.ivsize = CTR_RFC3686_IV_SIZE;
+ inst->alg.cra_ablkcipher.min_keysize =
+ alg->cra_ablkcipher.min_keysize + CTR_RFC3686_NONCE_SIZE;
+ inst->alg.cra_ablkcipher.max_keysize =
+ alg->cra_ablkcipher.max_keysize + CTR_RFC3686_NONCE_SIZE;
- inst->alg.cra_blkcipher.geniv = "seqiv";
+ inst->alg.cra_ablkcipher.geniv = "seqiv";
+
+ inst->alg.cra_ablkcipher.setkey = crypto_rfc3686_setkey;
+ inst->alg.cra_ablkcipher.encrypt = crypto_rfc3686_crypt;
+ inst->alg.cra_ablkcipher.decrypt = crypto_rfc3686_crypt;
inst->alg.cra_ctxsize = sizeof(struct crypto_rfc3686_ctx);
inst->alg.cra_init = crypto_rfc3686_init_tfm;
inst->alg.cra_exit = crypto_rfc3686_exit_tfm;
- inst->alg.cra_blkcipher.setkey = crypto_rfc3686_setkey;
- inst->alg.cra_blkcipher.encrypt = crypto_rfc3686_crypt;
- inst->alg.cra_blkcipher.decrypt = crypto_rfc3686_crypt;
-
-out:
- crypto_mod_put(alg);
return inst;
-out_put_alg:
- inst = ERR_PTR(err);
- goto out;
+err_drop_spawn:
+ crypto_drop_skcipher(spawn);
+err_free_inst:
+ kfree(inst);
+ return ERR_PTR(err);
+}
+
+static void crypto_rfc3686_free(struct crypto_instance *inst)
+{
+ struct crypto_skcipher_spawn *spawn = crypto_instance_ctx(inst);
+
+ crypto_drop_skcipher(spawn);
+ kfree(inst);
}
static struct crypto_template crypto_rfc3686_tmpl = {
.name = "rfc3686",
.alloc = crypto_rfc3686_alloc,
- .free = crypto_ctr_free,
+ .free = crypto_rfc3686_free,
.module = THIS_MODULE,
};
diff --git a/crypto/cts.c b/crypto/cts.c
index ccf9c5de3958..042223f8e733 100644
--- a/crypto/cts.c
+++ b/crypto/cts.c
@@ -282,9 +282,8 @@ static struct crypto_instance *crypto_cts_alloc(struct rtattr **tb)
alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER,
CRYPTO_ALG_TYPE_MASK);
- err = PTR_ERR(alg);
if (IS_ERR(alg))
- return ERR_PTR(err);
+ return ERR_CAST(alg);
inst = ERR_PTR(-EINVAL);
if (!is_power_of_2(alg->cra_blocksize))
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 1a252639ef91..137ad1ec5438 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -701,9 +701,8 @@ static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb,
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
return ERR_PTR(-EINVAL);
@@ -711,9 +710,8 @@ static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb,
ghash_alg = crypto_find_alg(ghash_name, &crypto_ahash_type,
CRYPTO_ALG_TYPE_HASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
- err = PTR_ERR(ghash_alg);
if (IS_ERR(ghash_alg))
- return ERR_PTR(err);
+ return ERR_CAST(ghash_alg);
err = -ENOMEM;
inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
@@ -787,15 +785,13 @@ out_put_ghash:
static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb)
{
- int err;
const char *cipher_name;
char ctr_name[CRYPTO_MAX_ALG_NAME];
char full_name[CRYPTO_MAX_ALG_NAME];
cipher_name = crypto_attr_alg_name(tb[1]);
- err = PTR_ERR(cipher_name);
if (IS_ERR(cipher_name))
- return ERR_PTR(err);
+ return ERR_CAST(cipher_name);
if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >=
CRYPTO_MAX_ALG_NAME)
@@ -826,20 +822,17 @@ static struct crypto_template crypto_gcm_tmpl = {
static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb)
{
- int err;
const char *ctr_name;
const char *ghash_name;
char full_name[CRYPTO_MAX_ALG_NAME];
ctr_name = crypto_attr_alg_name(tb[1]);
- err = PTR_ERR(ctr_name);
if (IS_ERR(ctr_name))
- return ERR_PTR(err);
+ return ERR_CAST(ctr_name);
ghash_name = crypto_attr_alg_name(tb[2]);
- err = PTR_ERR(ghash_name);
if (IS_ERR(ghash_name))
- return ERR_PTR(err);
+ return ERR_CAST(ghash_name);
if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s,%s)",
ctr_name, ghash_name) >= CRYPTO_MAX_ALG_NAME)
@@ -971,17 +964,15 @@ static struct crypto_instance *crypto_rfc4106_alloc(struct rtattr **tb)
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
return ERR_PTR(-EINVAL);
ccm_name = crypto_attr_alg_name(tb[1]);
- err = PTR_ERR(ccm_name);
if (IS_ERR(ccm_name))
- return ERR_PTR(err);
+ return ERR_CAST(ccm_name);
inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
if (!inst)
@@ -1222,17 +1213,15 @@ static struct crypto_instance *crypto_rfc4543_alloc(struct rtattr **tb)
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
return ERR_PTR(-EINVAL);
ccm_name = crypto_attr_alg_name(tb[1]);
- err = PTR_ERR(ccm_name);
if (IS_ERR(ccm_name))
- return ERR_PTR(err);
+ return ERR_CAST(ccm_name);
inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
if (!inst)
diff --git a/crypto/pcompress.c b/crypto/pcompress.c
index 04e083ff5373..7140fe70c7af 100644
--- a/crypto/pcompress.c
+++ b/crypto/pcompress.c
@@ -53,8 +53,7 @@ static int crypto_pcomp_report(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_report_comp rpcomp;
- snprintf(rpcomp.type, CRYPTO_MAX_ALG_NAME, "%s", "pcomp");
-
+ strncpy(rpcomp.type, "pcomp", sizeof(rpcomp.type));
if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
sizeof(struct crypto_report_comp), &rpcomp))
goto nla_put_failure;
diff --git a/crypto/rng.c b/crypto/rng.c
index f3b7894dec00..e0a25c2456de 100644
--- a/crypto/rng.c
+++ b/crypto/rng.c
@@ -65,7 +65,7 @@ static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_report_rng rrng;
- snprintf(rrng.type, CRYPTO_MAX_ALG_NAME, "%s", "rng");
+ strncpy(rrng.type, "rng", sizeof(rrng.type));
rrng.seedsize = alg->cra_rng.seedsize;
diff --git a/crypto/seqiv.c b/crypto/seqiv.c
index 4c4491229417..f2cba4ed6f25 100644
--- a/crypto/seqiv.c
+++ b/crypto/seqiv.c
@@ -305,9 +305,8 @@ static struct crypto_instance *seqiv_alloc(struct rtattr **tb)
int err;
algt = crypto_get_attr_type(tb);
- err = PTR_ERR(algt);
if (IS_ERR(algt))
- return ERR_PTR(err);
+ return ERR_CAST(algt);
err = crypto_get_default_rng();
if (err)
diff --git a/crypto/shash.c b/crypto/shash.c
index f426330f1017..929058a68561 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -530,7 +530,8 @@ static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg)
struct crypto_report_hash rhash;
struct shash_alg *salg = __crypto_shash_alg(alg);
- snprintf(rhash.type, CRYPTO_MAX_ALG_NAME, "%s", "shash");
+ strncpy(rhash.type, "shash", sizeof(rhash.type));
+
rhash.blocksize = alg->cra_blocksize;
rhash.digestsize = salg->digestsize;
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 7ae2130e1b00..87ef7d66bc20 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -1591,6 +1591,10 @@ static int do_test(int m)
speed_template_16_24_32);
test_acipher_speed("ofb(aes)", DECRYPT, sec, NULL, 0,
speed_template_16_24_32);
+ test_acipher_speed("rfc3686(ctr(aes))", ENCRYPT, sec, NULL, 0,
+ speed_template_20_28_36);
+ test_acipher_speed("rfc3686(ctr(aes))", DECRYPT, sec, NULL, 0,
+ speed_template_20_28_36);
break;
case 501:
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index cd2068524f3f..ecdeeb1a7b05 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -51,6 +51,7 @@ static u8 speed_template_8_16[] = {8, 16, 0};
static u8 speed_template_8_32[] = {8, 32, 0};
static u8 speed_template_16_32[] = {16, 32, 0};
static u8 speed_template_16_24_32[] = {16, 24, 32, 0};
+static u8 speed_template_20_28_36[] = {20, 28, 36, 0};
static u8 speed_template_32_40_48[] = {32, 40, 48, 0};
static u8 speed_template_32_48[] = {32, 48, 0};
static u8 speed_template_32_48_64[] = {32, 48, 64, 0};
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index edf4a0818773..efd8b20e13dc 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -2269,6 +2269,21 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "ecb(fcrypt)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = {
+ .vecs = fcrypt_pcbc_enc_tv_template,
+ .count = 1
+ },
+ .dec = {
+ .vecs = fcrypt_pcbc_dec_tv_template,
+ .count = 1
+ }
+ }
+ }
+ }, {
.alg = "ecb(khazad)",
.test = alg_test_skcipher,
.suite = {
diff --git a/drivers/Kconfig b/drivers/Kconfig
index f5fb0722a63a..202fa6d051b9 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -134,6 +134,8 @@ source "drivers/hwspinlock/Kconfig"
source "drivers/clocksource/Kconfig"
+source "drivers/mailbox/Kconfig"
+
source "drivers/iommu/Kconfig"
source "drivers/remoteproc/Kconfig"
@@ -150,6 +152,8 @@ source "drivers/memory/Kconfig"
source "drivers/iio/Kconfig"
+source "drivers/ntb/Kconfig"
+
source "drivers/vme/Kconfig"
source "drivers/pwm/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 7863b9fee50b..dce39a95fa71 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -29,7 +29,7 @@ obj-$(CONFIG_PNP) += pnp/
obj-y += amba/
# Many drivers will want to use DMA so this has to be made available
# really early.
-obj-$(CONFIG_DMA_ENGINE) += dma/
+obj-$(CONFIG_DMADEVICES) += dma/
obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_XEN) += xen/
@@ -130,6 +130,7 @@ obj-y += platform/
#common clk code
obj-y += clk/
+obj-$(CONFIG_MAILBOX) += mailbox/
obj-$(CONFIG_HWSPINLOCK) += hwspinlock/
obj-$(CONFIG_NFC) += nfc/
obj-$(CONFIG_IOMMU_SUPPORT) += iommu/
@@ -146,3 +147,4 @@ obj-$(CONFIG_MEMORY) += memory/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_IPACK_BUS) += ipack/
+obj-$(CONFIG_NTB) += ntb/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 38c5078da11d..1a4ed64586a7 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -176,7 +176,6 @@ config ACPI_FAN
config ACPI_DOCK
bool "Dock"
- depends on EXPERIMENTAL
help
This driver supports ACPI-controlled docking stations and removable
drive bays such as the IBM Ultrabay and the Dell Module Bay.
@@ -202,7 +201,7 @@ config ACPI_PROCESSOR
the module will be called processor.
config ACPI_IPMI
tristate "IPMI"
- depends on EXPERIMENTAL && IPMI_SI && IPMI_HANDLER
+ depends on IPMI_SI && IPMI_HANDLER
default n
help
This driver enables the ACPI to access the BMC controller. And it
@@ -214,14 +213,13 @@ config ACPI_IPMI
config ACPI_HOTPLUG_CPU
bool
- depends on EXPERIMENTAL && ACPI_PROCESSOR && HOTPLUG_CPU
+ depends on ACPI_PROCESSOR && HOTPLUG_CPU
select ACPI_CONTAINER
default y
config ACPI_PROCESSOR_AGGREGATOR
tristate "Processor Aggregator"
depends on ACPI_PROCESSOR
- depends on EXPERIMENTAL
depends on X86
help
ACPI 4.0 defines processor Aggregator, which enables OS to perform
@@ -337,8 +335,7 @@ config X86_PM_TIMER
systems require this timer.
config ACPI_CONTAINER
- tristate "Container and Module Devices (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "Container and Module Devices"
default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
help
This driver supports ACPI Container and Module devices (IDs
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 2a4502becd13..474fcfeba66c 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -37,7 +37,8 @@ acpi-y += resource.o
acpi-y += processor_core.o
acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
-acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
+acpi-y += pci_root.o pci_link.o pci_irq.o
+acpi-y += csrt.o
acpi-y += acpi_platform.o
acpi-y += power.o
acpi-y += event.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index d5fdd36190cc..6d5bf649196d 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -60,7 +60,7 @@ static int acpi_ac_open_fs(struct inode *inode, struct file *file);
#endif
static int acpi_ac_add(struct acpi_device *device);
-static int acpi_ac_remove(struct acpi_device *device, int type);
+static int acpi_ac_remove(struct acpi_device *device);
static void acpi_ac_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id ac_device_ids[] = {
@@ -337,7 +337,7 @@ static int acpi_ac_resume(struct device *dev)
}
#endif
-static int acpi_ac_remove(struct acpi_device *device, int type)
+static int acpi_ac_remove(struct acpi_device *device)
{
struct acpi_ac *ac = NULL;
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index b679bf8478f7..da1f82b445e0 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -54,7 +54,7 @@ MODULE_LICENSE("GPL");
#define MEMORY_POWER_OFF_STATE 2
static int acpi_memory_device_add(struct acpi_device *device);
-static int acpi_memory_device_remove(struct acpi_device *device, int type);
+static int acpi_memory_device_remove(struct acpi_device *device);
static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
@@ -153,51 +153,46 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
return 0;
}
-static int
-acpi_memory_get_device(acpi_handle handle,
- struct acpi_memory_device **mem_device)
+static int acpi_memory_get_device(acpi_handle handle,
+ struct acpi_memory_device **mem_device)
{
- acpi_status status;
- acpi_handle phandle;
struct acpi_device *device = NULL;
- struct acpi_device *pdevice = NULL;
- int result;
+ int result = 0;
+ acpi_scan_lock_acquire();
- if (!acpi_bus_get_device(handle, &device) && device)
+ acpi_bus_get_device(handle, &device);
+ if (device)
goto end;
- status = acpi_get_parent(handle, &phandle);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Cannot find acpi parent"));
- return -EINVAL;
- }
-
- /* Get the parent device */
- result = acpi_bus_get_device(phandle, &pdevice);
- if (result) {
- acpi_handle_warn(phandle, "Cannot get acpi bus device\n");
- return -EINVAL;
- }
-
/*
* Now add the notified device. This creates the acpi_device
* and invokes .add function
*/
- result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
+ result = acpi_bus_scan(handle);
if (result) {
- acpi_handle_warn(handle, "Cannot add acpi bus\n");
- return -EINVAL;
+ acpi_handle_warn(handle, "ACPI namespace scan failed\n");
+ result = -EINVAL;
+ goto out;
+ }
+ result = acpi_bus_get_device(handle, &device);
+ if (result) {
+ acpi_handle_warn(handle, "Missing device object\n");
+ result = -EINVAL;
+ goto out;
}
- end:
+ end:
*mem_device = acpi_driver_data(device);
if (!(*mem_device)) {
dev_err(&device->dev, "driver data not found\n");
- return -ENODEV;
+ result = -ENODEV;
+ goto out;
}
- return 0;
+ out:
+ acpi_scan_lock_release();
+ return result;
}
static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
@@ -285,9 +280,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
{
- int result = 0;
+ int result = 0, nid;
struct acpi_memory_info *info, *n;
+ nid = acpi_get_node(mem_device->device->handle);
+
list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
if (info->failed)
/* The kernel does not use this memory block */
@@ -300,7 +297,9 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
*/
return -EBUSY;
- result = remove_memory(info->start_addr, info->length);
+ if (nid < 0)
+ nid = memory_add_physaddr_to_nid(info->start_addr);
+ result = remove_memory(nid, info->start_addr, info->length);
if (result)
return result;
@@ -317,6 +316,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
struct acpi_device *device;
struct acpi_eject_event *ej_event = NULL;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+ acpi_status status;
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
@@ -339,29 +339,40 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"\nReceived EJECT REQUEST notification for device\n"));
+ status = AE_ERROR;
+ acpi_scan_lock_acquire();
+
if (acpi_bus_get_device(handle, &device)) {
acpi_handle_err(handle, "Device doesn't exist\n");
- break;
+ goto unlock;
}
mem_device = acpi_driver_data(device);
if (!mem_device) {
acpi_handle_err(handle, "Driver Data is NULL\n");
- break;
+ goto unlock;
}
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
if (!ej_event) {
pr_err(PREFIX "No memory, dropping EJECT\n");
- break;
+ goto unlock;
}
- ej_event->handle = handle;
+ get_device(&device->dev);
+ ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
- acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
- (void *)ej_event);
+ /* The eject is carried out asynchronously. */
+ status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
+ ej_event);
+ if (ACPI_FAILURE(status)) {
+ put_device(&device->dev);
+ kfree(ej_event);
+ }
- /* eject is performed asynchronously */
- return;
+ unlock:
+ acpi_scan_lock_release();
+ if (ACPI_SUCCESS(status))
+ return;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
@@ -372,7 +383,6 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
- return;
}
static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
@@ -427,7 +437,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
return result;
}
-static int acpi_memory_device_remove(struct acpi_device *device, int type)
+static int acpi_memory_device_remove(struct acpi_device *device)
{
struct acpi_memory_device *mem_device = NULL;
int result;
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 16fa979f7180..31de1043eea0 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -482,8 +482,7 @@ static int acpi_pad_add(struct acpi_device *device)
return 0;
}
-static int acpi_pad_remove(struct acpi_device *device,
- int type)
+static int acpi_pad_remove(struct acpi_device *device)
{
mutex_lock(&isolated_cpus_lock);
acpi_pad_idle_cpus(0);
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index db129b9f52cb..26fce4b8a632 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -13,6 +13,7 @@
#include <linux/acpi.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -21,18 +22,59 @@
ACPI_MODULE_NAME("platform");
+/* Flags for acpi_create_platform_device */
+#define ACPI_PLATFORM_CLK BIT(0)
+
+/*
+ * The following ACPI IDs are known to be suitable for representing as
+ * platform devices.
+ */
+static const struct acpi_device_id acpi_platform_device_ids[] = {
+
+ { "PNP0D40" },
+
+ /* Haswell LPSS devices */
+ { "INT33C0", ACPI_PLATFORM_CLK },
+ { "INT33C1", ACPI_PLATFORM_CLK },
+ { "INT33C2", ACPI_PLATFORM_CLK },
+ { "INT33C3", ACPI_PLATFORM_CLK },
+ { "INT33C4", ACPI_PLATFORM_CLK },
+ { "INT33C5", ACPI_PLATFORM_CLK },
+ { "INT33C6", ACPI_PLATFORM_CLK },
+ { "INT33C7", ACPI_PLATFORM_CLK },
+
+ { }
+};
+
+static int acpi_create_platform_clks(struct acpi_device *adev)
+{
+ static struct platform_device *pdev;
+
+ /* Create Lynxpoint LPSS clocks */
+ if (!pdev && !strncmp(acpi_device_hid(adev), "INT33C", 6)) {
+ pdev = platform_device_register_simple("clk-lpt", -1, NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+ }
+
+ return 0;
+}
+
/**
* acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for.
+ * @id: ACPI device ID used to match @adev.
*
* Check if the given @adev can be represented as a platform device and, if
* that's the case, create and register a platform device, populate its common
* resources and returns a pointer to it. Otherwise, return %NULL.
*
- * The platform device's name will be taken from the @adev's _HID and _UID.
+ * Name of the platform device will be the same as @adev's.
*/
-struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
+static int acpi_create_platform_device(struct acpi_device *adev,
+ const struct acpi_device_id *id)
{
+ unsigned long flags = id->driver_data;
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
struct platform_device_info pdevinfo;
@@ -41,20 +83,28 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
struct resource *resources;
int count;
+ if (flags & ACPI_PLATFORM_CLK) {
+ int ret = acpi_create_platform_clks(adev);
+ if (ret) {
+ dev_err(&adev->dev, "failed to create clocks\n");
+ return ret;
+ }
+ }
+
/* If the ACPI node already has a physical device attached, skip it. */
if (adev->physical_node_count)
- return NULL;
+ return 0;
INIT_LIST_HEAD(&resource_list);
count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
if (count <= 0)
- return NULL;
+ return 0;
resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL);
if (!resources) {
dev_err(&adev->dev, "No memory for resources\n");
acpi_dev_free_resource_list(&resource_list);
- return NULL;
+ return -ENOMEM;
}
count = 0;
list_for_each_entry(rentry, &resource_list, node)
@@ -100,5 +150,15 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
}
kfree(resources);
- return pdev;
+ return 1;
+}
+
+static struct acpi_scan_handler platform_handler = {
+ .ids = acpi_platform_device_ids,
+ .attach = acpi_create_platform_device,
+};
+
+void __init acpi_platform_init(void)
+{
+ acpi_scan_add_handler(&platform_handler);
}
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index bc7a03ded064..a1b9bf5085a2 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -31,6 +31,7 @@ acpi-y += \
evgpeinit.o \
evgpeutil.o \
evglock.o \
+ evhandler.o \
evmisc.o \
evregion.o \
evrgnini.o \
@@ -90,6 +91,7 @@ acpi-y += \
nsobject.o \
nsparse.o \
nspredef.o \
+ nsprepkg.o \
nsrepair.o \
nsrepair2.o \
nssearch.o \
@@ -104,7 +106,9 @@ acpi-$(ACPI_FUTURE_USAGE) += nsdumpdv.o
acpi-y += \
psargs.o \
psloop.o \
+ psobject.o \
psopcode.o \
+ psopinfo.o \
psparse.o \
psscope.o \
pstree.o \
@@ -126,7 +130,7 @@ acpi-y += \
rsutils.o \
rsxface.o
-acpi-$(ACPI_FUTURE_USAGE) += rsdump.o
+acpi-$(ACPI_FUTURE_USAGE) += rsdump.o rsdumpinfo.o
acpi-y += \
tbfadt.o \
@@ -155,8 +159,10 @@ acpi-y += \
utmutex.o \
utobject.o \
utosi.o \
+ utownerid.o \
utresrc.o \
utstate.o \
+ utstring.o \
utxface.o \
utxfinit.o \
utxferror.o \
diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h
index 8a7d51bfb3b3..8a6c4a0d22db 100644
--- a/drivers/acpi/acpica/accommon.h
+++ b/drivers/acpi/acpica/accommon.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,7 @@
*
* Note: The order of these include files is important.
*/
+#include <acpi/acconfig.h> /* Global configuration constants */
#include "acmacros.h" /* C macros */
#include "aclocal.h" /* Internal data types */
#include "acobject.h" /* ACPI internal object */
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 432a318c9ed1..9feba08c29fe 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -115,6 +115,21 @@ ACPI_HW_DEPENDENT_RETURN_VOID(void
char *block_arg))
/*
+ * dbconvert - miscellaneous conversion routines
+ */
+ acpi_status acpi_db_hex_char_to_value(int hex_char, u8 *return_value);
+
+acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object);
+
+acpi_status
+acpi_db_convert_to_object(acpi_object_type type,
+ char *string, union acpi_object *object);
+
+u8 *acpi_db_encode_pld_buffer(struct acpi_pld_info *pld_info);
+
+void acpi_db_dump_pld_buffer(union acpi_object *obj_desc);
+
+/*
* dbmethod - control method commands
*/
void
@@ -191,6 +206,8 @@ void
acpi_db_create_execution_threads(char *num_threads_arg,
char *num_loops_arg, char *method_name_arg);
+void acpi_db_delete_objects(u32 count, union acpi_object *objects);
+
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
u32 acpi_db_get_cache_info(struct acpi_memory_list *cache);
#endif
diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h
index ed33ebcdaebe..427db72a6302 100644
--- a/drivers/acpi/acpica/acdispat.h
+++ b/drivers/acpi/acpica/acdispat.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index e975c6720448..ab0e97710381 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -158,10 +158,23 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
void *context);
/*
- * evregion - Address Space handling
+ * evhandler - Address space handling
*/
+u8
+acpi_ev_has_default_handler(struct acpi_namespace_node *node,
+ acpi_adr_space_type space_id);
+
acpi_status acpi_ev_install_region_handlers(void);
+acpi_status
+acpi_ev_install_space_handler(struct acpi_namespace_node *node,
+ acpi_adr_space_type space_id,
+ acpi_adr_space_handler handler,
+ acpi_adr_space_setup setup, void *context);
+
+/*
+ * evregion - Operation region support
+ */
acpi_status acpi_ev_initialize_op_regions(void);
acpi_status
@@ -180,12 +193,6 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
u8 acpi_ns_is_locked);
acpi_status
-acpi_ev_install_space_handler(struct acpi_namespace_node *node,
- acpi_adr_space_type space_id,
- acpi_adr_space_handler handler,
- acpi_adr_space_setup setup, void *context);
-
-acpi_status
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
acpi_adr_space_type space_id);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 64472e4ec329..ecb49927b817 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -192,14 +192,6 @@ ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
-/* Mutex for _OSI support */
-
-ACPI_EXTERN acpi_mutex acpi_gbl_osi_mutex;
-
-/* Reader/Writer lock is used for namespace walk and dynamic table unload */
-
-ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
-
/*****************************************************************************
*
* Mutual exclusion within ACPICA subsystem
@@ -233,6 +225,14 @@ ACPI_EXTERN u8 acpi_gbl_global_lock_pending;
ACPI_EXTERN acpi_spinlock acpi_gbl_gpe_lock; /* For GPE data structs and registers */
ACPI_EXTERN acpi_spinlock acpi_gbl_hardware_lock; /* For ACPI H/W except GPE registers */
+/* Mutex for _OSI support */
+
+ACPI_EXTERN acpi_mutex acpi_gbl_osi_mutex;
+
+/* Reader/Writer lock is used for namespace walk and dynamic table unload */
+
+ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
+
/*****************************************************************************
*
* Miscellaneous globals
@@ -252,7 +252,7 @@ ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;
ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
-ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
+ACPI_EXTERN acpi_table_handler acpi_gbl_table_handler;
ACPI_EXTERN void *acpi_gbl_table_handler_context;
ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
ACPI_EXTERN acpi_interface_handler acpi_gbl_interface_handler;
@@ -304,6 +304,7 @@ extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list;
ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list;
ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats;
+ACPI_EXTERN u8 acpi_gbl_disable_mem_tracking;
#endif
/*****************************************************************************
@@ -365,19 +366,18 @@ ACPI_EXTERN u8 acpi_gbl_sleep_type_b;
*
****************************************************************************/
-extern struct acpi_fixed_event_info
- acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS];
-ACPI_EXTERN struct acpi_fixed_event_handler
- acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS];
-ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
-ACPI_EXTERN struct acpi_gpe_block_info
-*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
-
#if (!ACPI_REDUCED_HARDWARE)
ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized;
+ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
+ACPI_EXTERN struct acpi_gpe_block_info
+ *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
ACPI_EXTERN acpi_gbl_event_handler acpi_gbl_global_event_handler;
ACPI_EXTERN void *acpi_gbl_global_event_handler_context;
+ACPI_EXTERN struct acpi_fixed_event_handler
+ acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS];
+extern struct acpi_fixed_event_info
+ acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS];
#endif /* !ACPI_REDUCED_HARDWARE */
@@ -405,7 +405,7 @@ ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
/*****************************************************************************
*
- * Debugger globals
+ * Debugger and Disassembler globals
*
****************************************************************************/
@@ -413,8 +413,12 @@ ACPI_EXTERN u8 acpi_gbl_db_output_flags;
#ifdef ACPI_DISASSEMBLER
+u8 ACPI_INIT_GLOBAL(acpi_gbl_ignore_noop_operator, FALSE);
+
ACPI_EXTERN u8 acpi_gbl_db_opt_disasm;
ACPI_EXTERN u8 acpi_gbl_db_opt_verbose;
+ACPI_EXTERN struct acpi_external_list *acpi_gbl_external_list;
+ACPI_EXTERN struct acpi_external_file *acpi_gbl_external_file_list;
#endif
#ifdef ACPI_DEBUGGER
@@ -426,6 +430,7 @@ extern u8 acpi_gbl_db_terminate_threads;
ACPI_EXTERN u8 acpi_gbl_db_opt_tables;
ACPI_EXTERN u8 acpi_gbl_db_opt_stats;
ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods;
+ACPI_EXTERN u8 acpi_gbl_db_opt_no_region_support;
ACPI_EXTERN char *acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS];
ACPI_EXTERN acpi_object_type acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS];
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index d902d31abc6c..6357e932bfd9 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index eb308635da72..8af8c9bdeb35 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -458,7 +458,7 @@ void acpi_ex_reacquire_interpreter(void);
void acpi_ex_relinquish_interpreter(void);
-void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
+u8 acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
void acpi_ex_acquire_global_lock(u32 rule);
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index ff8bd0061e8b..805f419086ab 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -189,11 +189,10 @@ struct acpi_namespace_node {
#define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */
#define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */
-#define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */
-#define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */
-#define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* i_aSL only: Method has at least one return value */
-#define ANOBJ_IS_BIT_OFFSET 0x40 /* i_aSL only: Reference is a bit offset */
-#define ANOBJ_IS_REFERENCED 0x80 /* i_aSL only: Object was referenced */
+#define ANOBJ_IS_EXTERNAL 0x08 /* iASL only: This object created via External() */
+#define ANOBJ_METHOD_NO_RETVAL 0x10 /* iASL only: Method has no return value */
+#define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* iASL only: Method has at least one return value */
+#define ANOBJ_IS_REFERENCED 0x80 /* iASL only: Object was referenced */
/* Internal ACPI table management - master table list */
@@ -411,11 +410,10 @@ struct acpi_gpe_notify_info {
struct acpi_gpe_notify_info *next;
};
-struct acpi_gpe_notify_object {
- struct acpi_namespace_node *node;
- struct acpi_gpe_notify_object *next;
-};
-
+/*
+ * GPE dispatch info. At any time, the GPE can have at most one type
+ * of dispatch - Method, Handler, or Implicit Notify.
+ */
union acpi_gpe_dispatch_info {
struct acpi_namespace_node *method_node; /* Method node for this GPE level */
struct acpi_gpe_handler_info *handler; /* Installed GPE handler */
@@ -679,6 +677,8 @@ struct acpi_opcode_info {
u8 type; /* Opcode type */
};
+/* Value associated with the parse object */
+
union acpi_parse_value {
u64 integer; /* Integer constant (Up to 64 bits) */
u32 size; /* bytelist or field size */
@@ -1025,6 +1025,31 @@ struct acpi_port_info {
/*****************************************************************************
*
+ * Disassembler
+ *
+ ****************************************************************************/
+
+struct acpi_external_list {
+ char *path;
+ char *internal_path;
+ struct acpi_external_list *next;
+ u32 value;
+ u16 length;
+ u8 type;
+ u8 flags;
+};
+
+/* Values for Flags field above */
+
+#define ACPI_IPATH_ALLOCATED 0x01
+
+struct acpi_external_file {
+ char *path;
+ struct acpi_external_file *next;
+};
+
+/*****************************************************************************
+ *
* Debugger
*
****************************************************************************/
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 5efad99f2169..ed7943b9044f 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,14 +49,18 @@
* get into potential aligment issues -- see the STORE macros below.
* Use with care.
*/
-#define ACPI_GET8(ptr) *ACPI_CAST_PTR (u8, ptr)
-#define ACPI_GET16(ptr) *ACPI_CAST_PTR (u16, ptr)
-#define ACPI_GET32(ptr) *ACPI_CAST_PTR (u32, ptr)
-#define ACPI_GET64(ptr) *ACPI_CAST_PTR (u64, ptr)
-#define ACPI_SET8(ptr) *ACPI_CAST_PTR (u8, ptr)
-#define ACPI_SET16(ptr) *ACPI_CAST_PTR (u16, ptr)
-#define ACPI_SET32(ptr) *ACPI_CAST_PTR (u32, ptr)
-#define ACPI_SET64(ptr) *ACPI_CAST_PTR (u64, ptr)
+#define ACPI_CAST8(ptr) ACPI_CAST_PTR (u8, (ptr))
+#define ACPI_CAST16(ptr) ACPI_CAST_PTR (u16, (ptr))
+#define ACPI_CAST32(ptr) ACPI_CAST_PTR (u32, (ptr))
+#define ACPI_CAST64(ptr) ACPI_CAST_PTR (u64, (ptr))
+#define ACPI_GET8(ptr) (*ACPI_CAST8 (ptr))
+#define ACPI_GET16(ptr) (*ACPI_CAST16 (ptr))
+#define ACPI_GET32(ptr) (*ACPI_CAST32 (ptr))
+#define ACPI_GET64(ptr) (*ACPI_CAST64 (ptr))
+#define ACPI_SET8(ptr, val) (*ACPI_CAST8 (ptr) = (u8) (val))
+#define ACPI_SET16(ptr, val) (*ACPI_CAST16 (ptr) = (u16) (val))
+#define ACPI_SET32(ptr, val) (*ACPI_CAST32 (ptr) = (u32) (val))
+#define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (u64) (val))
/*
* printf() format helpers
@@ -293,6 +297,26 @@
#define ACPI_16BIT_MASK 0x0000FFFF
#define ACPI_24BIT_MASK 0x00FFFFFF
+/* Macros to extract flag bits from position zero */
+
+#define ACPI_GET_1BIT_FLAG(value) ((value) & ACPI_1BIT_MASK)
+#define ACPI_GET_2BIT_FLAG(value) ((value) & ACPI_2BIT_MASK)
+#define ACPI_GET_3BIT_FLAG(value) ((value) & ACPI_3BIT_MASK)
+#define ACPI_GET_4BIT_FLAG(value) ((value) & ACPI_4BIT_MASK)
+
+/* Macros to extract flag bits from position one and above */
+
+#define ACPI_EXTRACT_1BIT_FLAG(field, position) (ACPI_GET_1BIT_FLAG ((field) >> position))
+#define ACPI_EXTRACT_2BIT_FLAG(field, position) (ACPI_GET_2BIT_FLAG ((field) >> position))
+#define ACPI_EXTRACT_3BIT_FLAG(field, position) (ACPI_GET_3BIT_FLAG ((field) >> position))
+#define ACPI_EXTRACT_4BIT_FLAG(field, position) (ACPI_GET_4BIT_FLAG ((field) >> position))
+
+/* ACPI Pathname helpers */
+
+#define ACPI_IS_ROOT_PREFIX(c) ((c) == (u8) 0x5C) /* Backslash */
+#define ACPI_IS_PARENT_PREFIX(c) ((c) == (u8) 0x5E) /* Carat */
+#define ACPI_IS_PATH_SEPARATOR(c) ((c) == (u8) 0x2E) /* Period (dot) */
+
/*
* An object of type struct acpi_namespace_node can appear in some contexts
* where a pointer to an object of type union acpi_operand_object can also
@@ -364,137 +388,6 @@
#endif /* ACPI_NO_ERROR_MESSAGES */
-/*
- * Debug macros that are conditionally compiled
- */
-#ifdef ACPI_DEBUG_OUTPUT
-/*
- * Function entry tracing
- */
-#define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \
- acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
-#define ACPI_FUNCTION_TRACE_PTR(a, b) ACPI_FUNCTION_NAME(a) \
- acpi_ut_trace_ptr(ACPI_DEBUG_PARAMETERS, (void *)b)
-#define ACPI_FUNCTION_TRACE_U32(a, b) ACPI_FUNCTION_NAME(a) \
- acpi_ut_trace_u32(ACPI_DEBUG_PARAMETERS, (u32)b)
-#define ACPI_FUNCTION_TRACE_STR(a, b) ACPI_FUNCTION_NAME(a) \
- acpi_ut_trace_str(ACPI_DEBUG_PARAMETERS, (char *)b)
-
-#define ACPI_FUNCTION_ENTRY() acpi_ut_track_stack_ptr()
-
-/*
- * Function exit tracing.
- * WARNING: These macros include a return statement. This is usually considered
- * bad form, but having a separate exit macro is very ugly and difficult to maintain.
- * One of the FUNCTION_TRACE macros above must be used in conjunction with these macros
- * so that "_AcpiFunctionName" is defined.
- *
- * Note: the DO_WHILE0 macro is used to prevent some compilers from complaining
- * about these constructs.
- */
-#ifdef ACPI_USE_DO_WHILE_0
-#define ACPI_DO_WHILE0(a) do a while(0)
-#else
-#define ACPI_DO_WHILE0(a) a
-#endif
-
-#define return_VOID ACPI_DO_WHILE0 ({ \
- acpi_ut_exit (ACPI_DEBUG_PARAMETERS); \
- return;})
-/*
- * There are two versions of most of the return macros. The default version is
- * safer, since it avoids side-effects by guaranteeing that the argument will
- * not be evaluated twice.
- *
- * A less-safe version of the macros is provided for optional use if the
- * compiler uses excessive CPU stack (for example, this may happen in the
- * debug case if code optimzation is disabled.)
- */
-#ifndef ACPI_SIMPLE_RETURN_MACROS
-
-#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({ \
- register acpi_status _s = (s); \
- acpi_ut_status_exit (ACPI_DEBUG_PARAMETERS, _s); \
- return (_s); })
-#define return_PTR(s) ACPI_DO_WHILE0 ({ \
- register void *_s = (void *) (s); \
- acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) _s); \
- return (_s); })
-#define return_VALUE(s) ACPI_DO_WHILE0 ({ \
- register u64 _s = (s); \
- acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, _s); \
- return (_s); })
-#define return_UINT8(s) ACPI_DO_WHILE0 ({ \
- register u8 _s = (u8) (s); \
- acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) _s); \
- return (_s); })
-#define return_UINT32(s) ACPI_DO_WHILE0 ({ \
- register u32 _s = (u32) (s); \
- acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) _s); \
- return (_s); })
-#else /* Use original less-safe macros */
-
-#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({ \
- acpi_ut_status_exit (ACPI_DEBUG_PARAMETERS, (s)); \
- return((s)); })
-#define return_PTR(s) ACPI_DO_WHILE0 ({ \
- acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) (s)); \
- return((s)); })
-#define return_VALUE(s) ACPI_DO_WHILE0 ({ \
- acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (u64) (s)); \
- return((s)); })
-#define return_UINT8(s) return_VALUE(s)
-#define return_UINT32(s) return_VALUE(s)
-
-#endif /* ACPI_SIMPLE_RETURN_MACROS */
-
-/* Conditional execution */
-
-#define ACPI_DEBUG_EXEC(a) a
-#define ACPI_DEBUG_ONLY_MEMBERS(a) a;
-#define _VERBOSE_STRUCTURES
-
-/* Various object display routines for debug */
-
-#define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand((a), 0)
-#define ACPI_DUMP_OPERANDS(a, b ,c) acpi_ex_dump_operands(a, b, c)
-#define ACPI_DUMP_ENTRY(a, b) acpi_ns_dump_entry (a, b)
-#define ACPI_DUMP_PATHNAME(a, b, c, d) acpi_ns_dump_pathname(a, b, c, d)
-#define ACPI_DUMP_BUFFER(a, b) acpi_ut_debug_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT)
-
-#else
-/*
- * This is the non-debug case -- make everything go away,
- * leaving no executable debug code!
- */
-#define ACPI_DEBUG_EXEC(a)
-#define ACPI_DEBUG_ONLY_MEMBERS(a)
-#define ACPI_FUNCTION_TRACE(a)
-#define ACPI_FUNCTION_TRACE_PTR(a, b)
-#define ACPI_FUNCTION_TRACE_U32(a, b)
-#define ACPI_FUNCTION_TRACE_STR(a, b)
-#define ACPI_FUNCTION_EXIT
-#define ACPI_FUNCTION_STATUS_EXIT(s)
-#define ACPI_FUNCTION_VALUE_EXIT(s)
-#define ACPI_FUNCTION_ENTRY()
-#define ACPI_DUMP_STACK_ENTRY(a)
-#define ACPI_DUMP_OPERANDS(a, b, c)
-#define ACPI_DUMP_ENTRY(a, b)
-#define ACPI_DUMP_TABLES(a, b)
-#define ACPI_DUMP_PATHNAME(a, b, c, d)
-#define ACPI_DUMP_BUFFER(a, b)
-#define ACPI_DEBUG_PRINT(pl)
-#define ACPI_DEBUG_PRINT_RAW(pl)
-
-#define return_VOID return
-#define return_ACPI_STATUS(s) return(s)
-#define return_VALUE(s) return(s)
-#define return_UINT8(s) return(s)
-#define return_UINT32(s) return(s)
-#define return_PTR(s) return(s)
-
-#endif /* ACPI_DEBUG_OUTPUT */
-
#if (!ACPI_REDUCED_HARDWARE)
#define ACPI_HW_OPTIONAL_FUNCTION(addr) addr
#else
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 9b19d4b86424..02cd5482ff8b 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -218,6 +218,18 @@ acpi_ns_check_parameter_count(char *pathname,
u32 user_param_count,
const union acpi_predefined_info *info);
+acpi_status
+acpi_ns_check_object_type(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr,
+ u32 expected_btypes, u32 package_index);
+
+/*
+ * nsprepkg - Validation of predefined name packages
+ */
+acpi_status
+acpi_ns_check_package(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr);
+
/*
* nsnames - Name and Scope manipulation
*/
@@ -333,8 +345,6 @@ acpi_ns_install_node(struct acpi_walk_state *walk_state,
/*
* nsutils - Utility functions
*/
-u8 acpi_ns_valid_root_prefix(char prefix);
-
acpi_object_type acpi_ns_get_type(struct acpi_namespace_node *node);
u32 acpi_ns_local(acpi_object_type type);
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 24eb9eac9514..cc7ab6dd724e 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -307,7 +307,7 @@ struct acpi_object_addr_handler {
struct acpi_namespace_node *node; /* Parent device */
void *context;
acpi_adr_space_setup setup;
- union acpi_operand_object *region_list; /* regions using this handler */
+ union acpi_operand_object *region_list; /* Regions using this handler */
union acpi_operand_object *next;
};
diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
index d786a5128b78..3fc9ca7e8aa3 100644
--- a/drivers/acpi/acpica/acopcode.h
+++ b/drivers/acpi/acpica/acopcode.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index eefcf47a61a0..aed319318835 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -105,7 +105,28 @@ union acpi_parse_object *acpi_ps_find_name(union acpi_parse_object *scope,
union acpi_parse_object *acpi_ps_get_parent(union acpi_parse_object *op);
/*
- * psopcode - AML Opcode information
+ * psobject - support for parse object processing
+ */
+acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+ u8 *aml_op_start,
+ union acpi_parse_object *unnamed_op,
+ union acpi_parse_object **op);
+
+acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+ u8 *aml_op_start, union acpi_parse_object **new_op);
+
+acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **op, acpi_status status);
+
+acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op, acpi_status status);
+
+/*
+ * psopinfo - AML Opcode information
*/
const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode);
@@ -211,8 +232,6 @@ void acpi_ps_free_op(union acpi_parse_object *op);
u8 acpi_ps_is_leading_char(u32 c);
-u8 acpi_ps_is_prefix_char(u32 c);
-
#ifdef ACPI_FUTURE_USAGE
u32 acpi_ps_get_name(union acpi_parse_object *op);
#endif /* ACPI_FUTURE_USAGE */
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 9dfa1c83bd4e..752cc40cdc1e 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -1,12 +1,11 @@
/******************************************************************************
*
* Name: acpredef - Information table for ACPI predefined methods and objects
- * $Revision: 1.1 $
*
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,13 +50,13 @@
*
* 1) PTYPE1 packages do not contain sub-packages.
*
- * ACPI_PTYPE1_FIXED: Fixed length, 1 or 2 object types:
+ * ACPI_PTYPE1_FIXED: Fixed-length length, 1 or 2 object types:
* object type
* count
* object type
* count
*
- * ACPI_PTYPE1_VAR: Variable length:
+ * ACPI_PTYPE1_VAR: Variable-length length:
* object type (Int/Buf/Ref)
*
* ACPI_PTYPE1_OPTION: Package has some required and some optional elements
@@ -85,10 +84,10 @@
* count
* (Used for _CST)
*
- * ACPI_PTYPE2_FIXED: Each subpackage is of fixed length
+ * ACPI_PTYPE2_FIXED: Each subpackage is of Fixed-length
* (Used for _PRT)
*
- * ACPI_PTYPE2_MIN: Each subpackage has a variable but minimum length
+ * ACPI_PTYPE2_MIN: Each subpackage has a Variable-length but minimum length
* (Used for _HPX)
*
* ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length
@@ -124,7 +123,8 @@ enum acpi_return_package_types {
* These are the names that can actually be evaluated via acpi_evaluate_object.
* Not present in this table are the following:
*
- * 1) Predefined/Reserved names that are never evaluated via acpi_evaluate_object:
+ * 1) Predefined/Reserved names that are never evaluated via
+ * acpi_evaluate_object:
* _Lxx and _Exx GPE methods
* _Qxx EC methods
* _T_x compiler temporary variables
@@ -149,6 +149,8 @@ enum acpi_return_package_types {
* information about the expected structure of the package. This information
* is saved here (rather than in a separate table) in order to minimize the
* overall size of the stored data.
+ *
+ * Note: The additional braces are intended to promote portability.
*/
static const union acpi_predefined_info predefined_names[] = {
{{"_AC0", 0, ACPI_RTYPE_INTEGER}},
@@ -212,9 +214,8 @@ static const union acpi_predefined_info predefined_names[] = {
{{"_BCT", 1, ACPI_RTYPE_INTEGER}},
{{"_BDN", 0, ACPI_RTYPE_INTEGER}},
{{"_BFS", 1, 0}},
- {{"_BIF", 0, ACPI_RTYPE_PACKAGE} }, /* Fixed-length (9 Int),(4 Str/Buf) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9,
- ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER}, 4, 0} },
+ {{"_BIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (9 Int),(4 Str) */
+ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9, ACPI_RTYPE_STRING}, 4, 0}},
{{"_BIX", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int),(4 Str) */
{{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, ACPI_RTYPE_STRING}, 4,
@@ -236,7 +237,8 @@ static const union acpi_predefined_info predefined_names[] = {
{{"_CBA", 0, ACPI_RTYPE_INTEGER}}, /* See PCI firmware spec 3.0 */
{{"_CDM", 0, ACPI_RTYPE_INTEGER}},
{{"_CID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Strs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,0}, 0,0}},
+ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0, 0}, 0,
+ 0}},
{{"_CLS", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (3 Int) */
{{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}},
@@ -251,7 +253,8 @@ static const union acpi_predefined_info predefined_names[] = {
{{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
{{"_CST", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */
- {{{ACPI_PTYPE2_PKG_COUNT,ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER}, 3,0}},
+ {{{ACPI_PTYPE2_PKG_COUNT, ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER}, 3,
+ 0}},
{{"_CWS", 1, ACPI_RTYPE_INTEGER}},
{{"_DCK", 1, ACPI_RTYPE_INTEGER}},
@@ -342,8 +345,8 @@ static const union acpi_predefined_info predefined_names[] = {
{{"_MBM", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (8 Int) */
{{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 8, 0}, 0, 0}},
- {{"_MLS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (2 Str) */
- {{{ACPI_PTYPE2, ACPI_RTYPE_STRING, 2,0}, 0,0}},
+ {{"_MLS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (1 Str/1 Buf) */
+ {{{ACPI_PTYPE2, ACPI_RTYPE_STRING, 1, ACPI_RTYPE_BUFFER}, 1, 0}},
{{"_MSG", 1, 0}},
{{"_MSM", 4, ACPI_RTYPE_INTEGER}},
diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h
index 0347d0993497..f691d0e4d9fa 100644
--- a/drivers/acpi/acpica/acresrc.h
+++ b/drivers/acpi/acpica/acresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -347,18 +347,21 @@ extern struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[];
extern struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[];
/*
- * rsdump
+ * rsdumpinfo
*/
extern struct acpi_rsdump_info acpi_rs_dump_irq[];
+extern struct acpi_rsdump_info acpi_rs_dump_prt[];
extern struct acpi_rsdump_info acpi_rs_dump_dma[];
extern struct acpi_rsdump_info acpi_rs_dump_start_dpf[];
extern struct acpi_rsdump_info acpi_rs_dump_end_dpf[];
extern struct acpi_rsdump_info acpi_rs_dump_io[];
+extern struct acpi_rsdump_info acpi_rs_dump_io_flags[];
extern struct acpi_rsdump_info acpi_rs_dump_fixed_io[];
extern struct acpi_rsdump_info acpi_rs_dump_vendor[];
extern struct acpi_rsdump_info acpi_rs_dump_end_tag[];
extern struct acpi_rsdump_info acpi_rs_dump_memory24[];
extern struct acpi_rsdump_info acpi_rs_dump_memory32[];
+extern struct acpi_rsdump_info acpi_rs_dump_memory_flags[];
extern struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[];
extern struct acpi_rsdump_info acpi_rs_dump_address16[];
extern struct acpi_rsdump_info acpi_rs_dump_address32[];
@@ -372,6 +375,7 @@ extern struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[];
extern struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[];
extern struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[];
extern struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[];
+extern struct acpi_rsdump_info acpi_rs_dump_general_flags[];
#endif
#endif /* __ACRESRC_H__ */
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
index 937e66c65d1e..7896d85876ca 100644
--- a/drivers/acpi/acpica/acstruct.h
+++ b/drivers/acpi/acpica/acstruct.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index 6712965ba8ae..7755e915a007 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index b0f5f92b674a..0082fa0a6139 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -483,39 +483,17 @@ acpi_ut_short_divide(u64 in_dividend,
/*
* utmisc
*/
-void ut_convert_backslashes(char *pathname);
-
const char *acpi_ut_validate_exception(acpi_status status);
u8 acpi_ut_is_pci_root_bridge(char *id);
u8 acpi_ut_is_aml_table(struct acpi_table_header *table);
-acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
-
-void acpi_ut_release_owner_id(acpi_owner_id * owner_id);
-
acpi_status
acpi_ut_walk_package_tree(union acpi_operand_object *source_object,
void *target_object,
acpi_pkg_callback walk_callback, void *context);
-void acpi_ut_strupr(char *src_string);
-
-void acpi_ut_strlwr(char *src_string);
-
-int acpi_ut_stricmp(char *string1, char *string2);
-
-void acpi_ut_print_string(char *string, u8 max_length);
-
-u8 acpi_ut_valid_acpi_name(u32 name);
-
-void acpi_ut_repair_name(char *name);
-
-u8 acpi_ut_valid_acpi_char(char character, u32 position);
-
-acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer);
-
/* Values for Base above (16=Hex, 10=Decimal) */
#define ACPI_ANY_BASE 0
@@ -532,15 +510,25 @@ acpi_ut_display_init_pathname(u8 type,
#endif
/*
+ * utownerid - Support for Table/Method Owner IDs
+ */
+acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
+
+void acpi_ut_release_owner_id(acpi_owner_id * owner_id);
+
+/*
* utresrc
*/
acpi_status
-acpi_ut_walk_aml_resources(u8 *aml,
+acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
+ u8 *aml,
acpi_size aml_length,
acpi_walk_aml_callback user_function,
void **context);
-acpi_status acpi_ut_validate_resource(void *aml, u8 *return_index);
+acpi_status
+acpi_ut_validate_resource(struct acpi_walk_state *walk_state,
+ void *aml, u8 *return_index);
u32 acpi_ut_get_descriptor_length(void *aml);
@@ -554,6 +542,27 @@ acpi_status
acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag);
/*
+ * utstring - String and character utilities
+ */
+void acpi_ut_strupr(char *src_string);
+
+void acpi_ut_strlwr(char *src_string);
+
+int acpi_ut_stricmp(char *string1, char *string2);
+
+acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer);
+
+void acpi_ut_print_string(char *string, u8 max_length);
+
+void ut_convert_backslashes(char *pathname);
+
+u8 acpi_ut_valid_acpi_name(u32 name);
+
+u8 acpi_ut_valid_acpi_char(char character, u32 position);
+
+void acpi_ut_repair_name(char *name);
+
+/*
* utmutex - mutex support
*/
acpi_status acpi_ut_mutex_initialize(void);
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index c26f8ff6c3b9..48a3e331b72d 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h
index 968449685e06..87c26366d1df 100644
--- a/drivers/acpi/acpica/amlresrc.h
+++ b/drivers/acpi/acpica/amlresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -199,6 +199,12 @@ struct aml_resource_fixed_dma {
struct aml_resource_large_header {
AML_RESOURCE_LARGE_HEADER_COMMON};
+/* General Flags for address space resource descriptors */
+
+#define ACPI_RESOURCE_FLAG_DEC 2
+#define ACPI_RESOURCE_FLAG_MIF 4
+#define ACPI_RESOURCE_FLAG_MAF 8
+
struct aml_resource_memory24 {
AML_RESOURCE_LARGE_HEADER_COMMON u8 flags;
u16 minimum;
diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c
index c8b5e2565b98..fb09b08d7080 100644
--- a/drivers/acpi/acpica/dsargs.c
+++ b/drivers/acpi/acpica/dsargs.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index 57895db3231a..7ea0f162f11c 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index b5b904ee815f..feadeed1012d 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index 87eff701ecfa..bc8e63f7784b 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 52eb4e01622a..a9ffd44c18fe 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,7 @@
#include "acinterp.h"
#include "acnamesp.h"
#ifdef ACPI_DISASSEMBLER
-#include <acpi/acdisasm.h>
+#include "acdisasm.h"
#endif
#define _COMPONENT ACPI_DISPATCHER
@@ -151,6 +151,7 @@ acpi_ds_create_method_mutex(union acpi_operand_object *method_desc)
status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex);
if (ACPI_FAILURE(status)) {
+ acpi_ut_delete_object_desc(mutex_desc);
return_ACPI_STATUS(status);
}
@@ -378,7 +379,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
*/
info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
if (!info) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ status = AE_NO_MEMORY;
+ goto cleanup;
}
info->parameters = &this_walk_state->operands[0];
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index 9a83b7e0f3ba..3da80460ce38 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index c9f15d3a3686..e20e9f84eee8 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -388,7 +388,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
union acpi_parse_object *parent;
union acpi_operand_object *obj_desc = NULL;
acpi_status status = AE_OK;
- unsigned i;
+ u32 i;
u16 index;
u16 reference_count;
@@ -525,7 +525,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
}
ACPI_INFO((AE_INFO,
- "Actual Package length (%u) is larger than NumElements field (%u), truncated\n",
+ "Actual Package length (%u) is larger than NumElements field (%u), truncated",
i, element_count));
} else if (i < element_count) {
/*
@@ -703,7 +703,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
/* Truncate value if we are executing from a 32-bit ACPI table */
#ifndef ACPI_NO_METHOD_EXECUTION
- acpi_ex_truncate_for32bit_table(obj_desc);
+ (void)acpi_ex_truncate_for32bit_table(obj_desc);
#endif
break;
@@ -725,8 +725,18 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
case AML_TYPE_LITERAL:
obj_desc->integer.value = op->common.value.integer;
+
#ifndef ACPI_NO_METHOD_EXECUTION
- acpi_ex_truncate_for32bit_table(obj_desc);
+ if (acpi_ex_truncate_for32bit_table(obj_desc)) {
+
+ /* Warn if we found a 64-bit constant in a 32-bit table */
+
+ ACPI_WARNING((AE_INFO,
+ "Truncated 64-bit constant found in 32-bit table: %8.8X%8.8X => %8.8X",
+ ACPI_FORMAT_UINT64(op->common.
+ value.integer),
+ (u32)obj_desc->integer.value));
+ }
#endif
break;
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index d09c6b4bab2c..ee6367b8eaf7 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -486,18 +486,18 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op);
/*
- * This is where we evaluate the signature_string and oem_iDString
- * and oem_table_iDString of the data_table_region declaration
+ * This is where we evaluate the Signature string, oem_id string,
+ * and oem_table_id string of the Data Table Region declaration
*/
node = op->common.node;
- /* next_op points to signature_string op */
+ /* next_op points to Signature string op */
next_op = op->common.value.arg;
/*
- * Evaluate/create the signature_string and oem_iDString
- * and oem_table_iDString operands
+ * Evaluate/create the Signature string, oem_id string,
+ * and oem_table_id string operands
*/
status = acpi_ds_create_operands(walk_state, next_op);
if (ACPI_FAILURE(status)) {
@@ -505,8 +505,8 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
}
/*
- * Resolve the signature_string and oem_iDString
- * and oem_table_iDString operands
+ * Resolve the Signature string, oem_id string,
+ * and oem_table_id string operands
*/
status = acpi_ex_resolve_operands(op->common.aml_opcode,
ACPI_WALK_OPERANDS, walk_state);
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index afeb99f49482..4d8c992a51d8 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -178,7 +178,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
if (!op) {
ACPI_ERROR((AE_INFO, "Null Op"));
- return_UINT8(TRUE);
+ return_VALUE(TRUE);
}
/*
@@ -210,7 +210,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
"At Method level, result of [%s] not used\n",
acpi_ps_get_opcode_name(op->common.
aml_opcode)));
- return_UINT8(FALSE);
+ return_VALUE(FALSE);
}
/* Get info on the parent. The root_op is AML_SCOPE */
@@ -219,7 +219,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
acpi_ps_get_opcode_info(op->common.parent->common.aml_opcode);
if (parent_info->class == AML_CLASS_UNKNOWN) {
ACPI_ERROR((AE_INFO, "Unknown parent opcode Op=%p", op));
- return_UINT8(FALSE);
+ return_VALUE(FALSE);
}
/*
@@ -307,7 +307,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
acpi_ps_get_opcode_name(op->common.parent->common.
aml_opcode), op));
- return_UINT8(TRUE);
+ return_VALUE(TRUE);
result_not_used:
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
@@ -316,7 +316,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
acpi_ps_get_opcode_name(op->common.parent->common.
aml_opcode), op));
- return_UINT8(FALSE);
+ return_VALUE(FALSE);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index 58593931be96..44f8325c2bae 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -149,7 +149,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
/* Truncate the predicate to 32-bits if necessary */
- acpi_ex_truncate_for32bit_table(local_obj_desc);
+ (void)acpi_ex_truncate_for32bit_table(local_obj_desc);
/*
* Save the result of the predicate evaluation on
@@ -706,7 +706,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
* ACPI 2.0 support for 64-bit integers: Truncate numeric
* result value if we are executing from a 32-bit ACPI table
*/
- acpi_ex_truncate_for32bit_table(walk_state->result_obj);
+ (void)acpi_ex_truncate_for32bit_table(walk_state->result_obj);
/*
* Check if we just completed the evaluation of a
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c
index 557510084c7a..6e17c0e24e63 100644
--- a/drivers/acpi/acpica/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,7 +50,7 @@
#include "acnamesp.h"
#ifdef ACPI_ASL_COMPILER
-#include <acpi/acdisasm.h>
+#include "acdisasm.h"
#endif
#define _COMPONENT ACPI_DISPATCHER
@@ -178,7 +178,8 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
* Target of Scope() not found. Generate an External for it, and
* insert the name into the namespace.
*/
- acpi_dm_add_to_external_list(path, ACPI_TYPE_DEVICE, 0);
+ acpi_dm_add_to_external_list(op, path, ACPI_TYPE_DEVICE,
+ 0);
status =
acpi_ns_lookup(walk_state->scope_info, path,
object_type, ACPI_IMODE_LOAD_PASS1,
diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c
index 379835748357..4407ff2377d5 100644
--- a/drivers/acpi/acpica/dswload2.c
+++ b/drivers/acpi/acpica/dswload2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -222,7 +222,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
*/
ACPI_WARNING((AE_INFO,
"Type override - [%4.4s] had invalid type (%s) "
- "for Scope operator, changed to type ANY\n",
+ "for Scope operator, changed to type ANY",
acpi_ut_get_node_name(node),
acpi_ut_get_type_name(node->type)));
diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c
index f6c4295470ae..d67891de1b54 100644
--- a/drivers/acpi/acpica/dswscope.c
+++ b/drivers/acpi/acpica/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c
index 3e65a15a735f..ecb12e2137ff 100644
--- a/drivers/acpi/acpica/dswstate.c
+++ b/drivers/acpi/acpica/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index d4acfbbe5b29..b8ea0b26cde3 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c
index af14a7137632..a621481c6cf2 100644
--- a/drivers/acpi/acpica/evglock.c
+++ b/drivers/acpi/acpica/evglock.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 36d120574423..b9adb9a7ed85 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -561,8 +561,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
status = AE_NO_MEMORY;
} else {
/*
- * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
- * control method that corresponds to this GPE
+ * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the
+ * _Lxx/_Exx control method that corresponds to this GPE
*/
info->prefix_node =
local_gpe_event_info->dispatch.method_node;
@@ -707,7 +707,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Unable to clear GPE%02X", gpe_number));
- return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
+ return_VALUE(ACPI_INTERRUPT_NOT_HANDLED);
}
}
@@ -724,7 +724,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Unable to disable GPE%02X", gpe_number));
- return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
+ return_VALUE(ACPI_INTERRUPT_NOT_HANDLED);
}
/*
@@ -765,7 +765,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Unable to queue handler for GPE%2X - event disabled",
+ "Unable to queue handler for GPE%02X - event disabled",
gpe_number));
}
break;
@@ -784,7 +784,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
break;
}
- return_UINT32(ACPI_INTERRUPT_HANDLED);
+ return_VALUE(ACPI_INTERRUPT_HANDLED);
}
#endif /* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 1571a61a7833..a2d688bbac02 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -405,13 +405,13 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
(*return_gpe_block) = gpe_block;
}
- ACPI_DEBUG_PRINT((ACPI_DB_INIT,
- "GPE %02X to %02X [%4.4s] %u regs on int 0x%X\n",
- (u32) gpe_block->block_base_number,
- (u32) (gpe_block->block_base_number +
- (gpe_block->gpe_count - 1)),
- gpe_device->name.ascii, gpe_block->register_count,
- interrupt_number));
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
+ " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X\n",
+ (u32)gpe_block->block_base_number,
+ (u32)(gpe_block->block_base_number +
+ (gpe_block->gpe_count - 1)),
+ gpe_device->name.ascii, gpe_block->register_count,
+ interrupt_number));
/* Update global count of currently available GPEs */
@@ -496,9 +496,11 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
}
if (gpe_enabled_count) {
- ACPI_DEBUG_PRINT((ACPI_DB_INIT,
- "Enabled %u GPEs in this block\n",
- gpe_enabled_count));
+ ACPI_INFO((AE_INFO,
+ "Enabled %u GPEs in block %02X to %02X",
+ gpe_enabled_count, (u32)gpe_block->block_base_number,
+ (u32)(gpe_block->block_base_number +
+ (gpe_block->gpe_count - 1))));
}
gpe_block->initialized = TRUE;
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index da0add858f81..72b8f6b3f4ca 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -86,6 +86,9 @@ acpi_status acpi_ev_gpe_initialize(void)
ACPI_FUNCTION_TRACE(ev_gpe_initialize);
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
+ "Initializing General Purpose Events (GPEs):\n"));
+
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
index 228a0c3b1d49..b24dbb80fab8 100644
--- a/drivers/acpi/acpica/evgpeutil.c
+++ b/drivers/acpi/acpica/evgpeutil.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c
new file mode 100644
index 000000000000..d4f83112c2e2
--- /dev/null
+++ b/drivers/acpi/acpica/evhandler.c
@@ -0,0 +1,529 @@
+/******************************************************************************
+ *
+ * Module Name: evhandler - Support for Address Space handlers
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
+#include "acinterp.h"
+
+#define _COMPONENT ACPI_EVENTS
+ACPI_MODULE_NAME("evhandler")
+
+/* Local prototypes */
+static acpi_status
+acpi_ev_install_handler(acpi_handle obj_handle,
+ u32 level, void *context, void **return_value);
+
+/* These are the address spaces that will get default handlers */
+
+u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = {
+ ACPI_ADR_SPACE_SYSTEM_MEMORY,
+ ACPI_ADR_SPACE_SYSTEM_IO,
+ ACPI_ADR_SPACE_PCI_CONFIG,
+ ACPI_ADR_SPACE_DATA_TABLE
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_install_region_handlers
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Installs the core subsystem default address space handlers.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ev_install_region_handlers(void)
+{
+ acpi_status status;
+ u32 i;
+
+ ACPI_FUNCTION_TRACE(ev_install_region_handlers);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * All address spaces (PCI Config, EC, SMBus) are scope dependent and
+ * registration must occur for a specific device.
+ *
+ * In the case of the system memory and IO address spaces there is
+ * currently no device associated with the address space. For these we
+ * use the root.
+ *
+ * We install the default PCI config space handler at the root so that
+ * this space is immediately available even though the we have not
+ * enumerated all the PCI Root Buses yet. This is to conform to the ACPI
+ * specification which states that the PCI config space must be always
+ * available -- even though we are nowhere near ready to find the PCI root
+ * buses at this point.
+ *
+ * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
+ * has already been installed (via acpi_install_address_space_handler).
+ * Similar for AE_SAME_HANDLER.
+ */
+ for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
+ status = acpi_ev_install_space_handler(acpi_gbl_root_node,
+ acpi_gbl_default_address_spaces
+ [i],
+ ACPI_DEFAULT_HANDLER,
+ NULL, NULL);
+ switch (status) {
+ case AE_OK:
+ case AE_SAME_HANDLER:
+ case AE_ALREADY_EXISTS:
+
+ /* These exceptions are all OK */
+
+ status = AE_OK;
+ break;
+
+ default:
+
+ goto unlock_and_exit;
+ }
+ }
+
+ unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_has_default_handler
+ *
+ * PARAMETERS: node - Namespace node for the device
+ * space_id - The address space ID
+ *
+ * RETURN: TRUE if default handler is installed, FALSE otherwise
+ *
+ * DESCRIPTION: Check if the default handler is installed for the requested
+ * space ID.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ev_has_default_handler(struct acpi_namespace_node *node,
+ acpi_adr_space_type space_id)
+{
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *handler_obj;
+
+ /* Must have an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (obj_desc) {
+ handler_obj = obj_desc->device.handler;
+
+ /* Walk the linked list of handlers for this object */
+
+ while (handler_obj) {
+ if (handler_obj->address_space.space_id == space_id) {
+ if (handler_obj->address_space.handler_flags &
+ ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
+ return (TRUE);
+ }
+ }
+
+ handler_obj = handler_obj->address_space.next;
+ }
+ }
+
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_install_handler
+ *
+ * PARAMETERS: walk_namespace callback
+ *
+ * DESCRIPTION: This routine installs an address handler into objects that are
+ * of type Region or Device.
+ *
+ * If the Object is a Device, and the device has a handler of
+ * the same type then the search is terminated in that branch.
+ *
+ * This is because the existing handler is closer in proximity
+ * to any more regions than the one we are trying to install.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ev_install_handler(acpi_handle obj_handle,
+ u32 level, void *context, void **return_value)
+{
+ union acpi_operand_object *handler_obj;
+ union acpi_operand_object *next_handler_obj;
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_NAME(ev_install_handler);
+
+ handler_obj = (union acpi_operand_object *)context;
+
+ /* Parameter validation */
+
+ if (!handler_obj) {
+ return (AE_OK);
+ }
+
+ /* Convert and validate the device handle */
+
+ node = acpi_ns_validate_handle(obj_handle);
+ if (!node) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * We only care about regions and objects that are allowed to have
+ * address space handlers
+ */
+ if ((node->type != ACPI_TYPE_DEVICE) &&
+ (node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
+ return (AE_OK);
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+
+ /* No object, just exit */
+
+ return (AE_OK);
+ }
+
+ /* Devices are handled different than regions */
+
+ if (obj_desc->common.type == ACPI_TYPE_DEVICE) {
+
+ /* Check if this Device already has a handler for this address space */
+
+ next_handler_obj = obj_desc->device.handler;
+ while (next_handler_obj) {
+
+ /* Found a handler, is it for the same address space? */
+
+ if (next_handler_obj->address_space.space_id ==
+ handler_obj->address_space.space_id) {
+ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+ "Found handler for region [%s] in device %p(%p) "
+ "handler %p\n",
+ acpi_ut_get_region_name
+ (handler_obj->address_space.
+ space_id), obj_desc,
+ next_handler_obj,
+ handler_obj));
+
+ /*
+ * Since the object we found it on was a device, then it
+ * means that someone has already installed a handler for
+ * the branch of the namespace from this device on. Just
+ * bail out telling the walk routine to not traverse this
+ * branch. This preserves the scoping rule for handlers.
+ */
+ return (AE_CTRL_DEPTH);
+ }
+
+ /* Walk the linked list of handlers attached to this device */
+
+ next_handler_obj = next_handler_obj->address_space.next;
+ }
+
+ /*
+ * As long as the device didn't have a handler for this space we
+ * don't care about it. We just ignore it and proceed.
+ */
+ return (AE_OK);
+ }
+
+ /* Object is a Region */
+
+ if (obj_desc->region.space_id != handler_obj->address_space.space_id) {
+
+ /* This region is for a different address space, just ignore it */
+
+ return (AE_OK);
+ }
+
+ /*
+ * Now we have a region and it is for the handler's address space type.
+ *
+ * First disconnect region for any previous handler (if any)
+ */
+ acpi_ev_detach_region(obj_desc, FALSE);
+
+ /* Connect the region to the new handler */
+
+ status = acpi_ev_attach_region(handler_obj, obj_desc, FALSE);
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_install_space_handler
+ *
+ * PARAMETERS: node - Namespace node for the device
+ * space_id - The address space ID
+ * handler - Address of the handler
+ * setup - Address of the setup function
+ * context - Value passed to the handler on each access
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for all op_regions of a given space_id.
+ * Assumes namespace is locked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_install_space_handler(struct acpi_namespace_node * node,
+ acpi_adr_space_type space_id,
+ acpi_adr_space_handler handler,
+ acpi_adr_space_setup setup, void *context)
+{
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *handler_obj;
+ acpi_status status;
+ acpi_object_type type;
+ u8 flags = 0;
+
+ ACPI_FUNCTION_TRACE(ev_install_space_handler);
+
+ /*
+ * This registration is valid for only the types below and the root. This
+ * is where the default handlers get placed.
+ */
+ if ((node->type != ACPI_TYPE_DEVICE) &&
+ (node->type != ACPI_TYPE_PROCESSOR) &&
+ (node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ if (handler == ACPI_DEFAULT_HANDLER) {
+ flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;
+
+ switch (space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+ handler = acpi_ex_system_memory_space_handler;
+ setup = acpi_ev_system_memory_region_setup;
+ break;
+
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ handler = acpi_ex_system_io_space_handler;
+ setup = acpi_ev_io_space_region_setup;
+ break;
+
+ case ACPI_ADR_SPACE_PCI_CONFIG:
+ handler = acpi_ex_pci_config_space_handler;
+ setup = acpi_ev_pci_config_region_setup;
+ break;
+
+ case ACPI_ADR_SPACE_CMOS:
+ handler = acpi_ex_cmos_space_handler;
+ setup = acpi_ev_cmos_region_setup;
+ break;
+
+ case ACPI_ADR_SPACE_PCI_BAR_TARGET:
+ handler = acpi_ex_pci_bar_space_handler;
+ setup = acpi_ev_pci_bar_region_setup;
+ break;
+
+ case ACPI_ADR_SPACE_DATA_TABLE:
+ handler = acpi_ex_data_table_space_handler;
+ setup = NULL;
+ break;
+
+ default:
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+ }
+
+ /* If the caller hasn't specified a setup routine, use the default */
+
+ if (!setup) {
+ setup = acpi_ev_default_region_setup;
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (obj_desc) {
+ /*
+ * The attached device object already exists. Make sure the handler
+ * is not already installed.
+ */
+ handler_obj = obj_desc->device.handler;
+
+ /* Walk the handler list for this device */
+
+ while (handler_obj) {
+
+ /* Same space_id indicates a handler already installed */
+
+ if (handler_obj->address_space.space_id == space_id) {
+ if (handler_obj->address_space.handler ==
+ handler) {
+ /*
+ * It is (relatively) OK to attempt to install the SAME
+ * handler twice. This can easily happen with the
+ * PCI_Config space.
+ */
+ status = AE_SAME_HANDLER;
+ goto unlock_and_exit;
+ } else {
+ /* A handler is already installed */
+
+ status = AE_ALREADY_EXISTS;
+ }
+ goto unlock_and_exit;
+ }
+
+ /* Walk the linked list of handlers */
+
+ handler_obj = handler_obj->address_space.next;
+ }
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+ "Creating object on Device %p while installing handler\n",
+ node));
+
+ /* obj_desc does not exist, create one */
+
+ if (node->type == ACPI_TYPE_ANY) {
+ type = ACPI_TYPE_DEVICE;
+ } else {
+ type = node->type;
+ }
+
+ obj_desc = acpi_ut_create_internal_object(type);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /* Init new descriptor */
+
+ obj_desc->common.type = (u8)type;
+
+ /* Attach the new object to the Node */
+
+ status = acpi_ns_attach_object(node, obj_desc, type);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference(obj_desc);
+
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+ "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
+ acpi_ut_get_region_name(space_id), space_id,
+ acpi_ut_get_node_name(node), node, obj_desc));
+
+ /*
+ * Install the handler
+ *
+ * At this point there is no existing handler. Just allocate the object
+ * for the handler and link it into the list.
+ */
+ handler_obj =
+ acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
+ if (!handler_obj) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /* Init handler obj */
+
+ handler_obj->address_space.space_id = (u8)space_id;
+ handler_obj->address_space.handler_flags = flags;
+ handler_obj->address_space.region_list = NULL;
+ handler_obj->address_space.node = node;
+ handler_obj->address_space.handler = handler;
+ handler_obj->address_space.context = context;
+ handler_obj->address_space.setup = setup;
+
+ /* Install at head of Device.address_space list */
+
+ handler_obj->address_space.next = obj_desc->device.handler;
+
+ /*
+ * The Device object is the first reference on the handler_obj.
+ * Each region that uses the handler adds a reference.
+ */
+ obj_desc->device.handler = handler_obj;
+
+ /*
+ * Walk the namespace finding all of the regions this
+ * handler will manage.
+ *
+ * Start at the device and search the branch toward
+ * the leaf nodes until either the leaf is encountered or
+ * a device is detected that has an address handler of the
+ * same type.
+ *
+ * In either case, back up and search down the remainder
+ * of the branch
+ */
+ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
+ ACPI_NS_WALK_UNLOCK,
+ acpi_ev_install_handler, NULL,
+ handler_obj, NULL);
+
+ unlock_and_exit:
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index 51f537937c1f..c986b2336b81 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 0cc6a16fedc7..6555e350fc1f 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -1,11 +1,11 @@
/******************************************************************************
*
- * Module Name: evregion - ACPI address_space (op_region) handler dispatch
+ * Module Name: evregion - Operation Region support
*
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,10 +50,9 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evregion")
+extern u8 acpi_gbl_default_address_spaces[];
+
/* Local prototypes */
-static u8
-acpi_ev_has_default_handler(struct acpi_namespace_node *node,
- acpi_adr_space_type space_id);
static void acpi_ev_orphan_ec_reg_method(void);
@@ -61,135 +60,6 @@ static acpi_status
acpi_ev_reg_run(acpi_handle obj_handle,
u32 level, void *context, void **return_value);
-static acpi_status
-acpi_ev_install_handler(acpi_handle obj_handle,
- u32 level, void *context, void **return_value);
-
-/* These are the address spaces that will get default handlers */
-
-#define ACPI_NUM_DEFAULT_SPACES 4
-
-static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = {
- ACPI_ADR_SPACE_SYSTEM_MEMORY,
- ACPI_ADR_SPACE_SYSTEM_IO,
- ACPI_ADR_SPACE_PCI_CONFIG,
- ACPI_ADR_SPACE_DATA_TABLE
-};
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ev_install_region_handlers
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Installs the core subsystem default address space handlers.
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_install_region_handlers(void)
-{
- acpi_status status;
- u32 i;
-
- ACPI_FUNCTION_TRACE(ev_install_region_handlers);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /*
- * All address spaces (PCI Config, EC, SMBus) are scope dependent and
- * registration must occur for a specific device.
- *
- * In the case of the system memory and IO address spaces there is
- * currently no device associated with the address space. For these we
- * use the root.
- *
- * We install the default PCI config space handler at the root so that
- * this space is immediately available even though the we have not
- * enumerated all the PCI Root Buses yet. This is to conform to the ACPI
- * specification which states that the PCI config space must be always
- * available -- even though we are nowhere near ready to find the PCI root
- * buses at this point.
- *
- * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
- * has already been installed (via acpi_install_address_space_handler).
- * Similar for AE_SAME_HANDLER.
- */
- for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
- status = acpi_ev_install_space_handler(acpi_gbl_root_node,
- acpi_gbl_default_address_spaces
- [i],
- ACPI_DEFAULT_HANDLER,
- NULL, NULL);
- switch (status) {
- case AE_OK:
- case AE_SAME_HANDLER:
- case AE_ALREADY_EXISTS:
-
- /* These exceptions are all OK */
-
- status = AE_OK;
- break;
-
- default:
-
- goto unlock_and_exit;
- }
- }
-
- unlock_and_exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ev_has_default_handler
- *
- * PARAMETERS: node - Namespace node for the device
- * space_id - The address space ID
- *
- * RETURN: TRUE if default handler is installed, FALSE otherwise
- *
- * DESCRIPTION: Check if the default handler is installed for the requested
- * space ID.
- *
- ******************************************************************************/
-
-static u8
-acpi_ev_has_default_handler(struct acpi_namespace_node *node,
- acpi_adr_space_type space_id)
-{
- union acpi_operand_object *obj_desc;
- union acpi_operand_object *handler_obj;
-
- /* Must have an existing internal object */
-
- obj_desc = acpi_ns_get_attached_object(node);
- if (obj_desc) {
- handler_obj = obj_desc->device.handler;
-
- /* Walk the linked list of handlers for this object */
-
- while (handler_obj) {
- if (handler_obj->address_space.space_id == space_id) {
- if (handler_obj->address_space.handler_flags &
- ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
- return (TRUE);
- }
- }
-
- handler_obj = handler_obj->address_space.next;
- }
- }
-
- return (FALSE);
-}
-
/*******************************************************************************
*
* FUNCTION: acpi_ev_initialize_op_regions
@@ -241,91 +111,6 @@ acpi_status acpi_ev_initialize_op_regions(void)
/*******************************************************************************
*
- * FUNCTION: acpi_ev_execute_reg_method
- *
- * PARAMETERS: region_obj - Region object
- * function - Passed to _REG: On (1) or Off (0)
- *
- * RETURN: Status
- *
- * DESCRIPTION: Execute _REG method for a region
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
-{
- struct acpi_evaluate_info *info;
- union acpi_operand_object *args[3];
- union acpi_operand_object *region_obj2;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ev_execute_reg_method);
-
- region_obj2 = acpi_ns_get_secondary_object(region_obj);
- if (!region_obj2) {
- return_ACPI_STATUS(AE_NOT_EXIST);
- }
-
- if (region_obj2->extra.method_REG == NULL) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Allocate and initialize the evaluation information block */
-
- info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
- if (!info) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- info->prefix_node = region_obj2->extra.method_REG;
- info->pathname = NULL;
- info->parameters = args;
- info->flags = ACPI_IGNORE_RETURN_VALUE;
-
- /*
- * The _REG method has two arguments:
- *
- * arg0 - Integer:
- * Operation region space ID Same value as region_obj->Region.space_id
- *
- * arg1 - Integer:
- * connection status 1 for connecting the handler, 0 for disconnecting
- * the handler (Passed as a parameter)
- */
- args[0] =
- acpi_ut_create_integer_object((u64) region_obj->region.space_id);
- if (!args[0]) {
- status = AE_NO_MEMORY;
- goto cleanup1;
- }
-
- args[1] = acpi_ut_create_integer_object((u64) function);
- if (!args[1]) {
- status = AE_NO_MEMORY;
- goto cleanup2;
- }
-
- args[2] = NULL; /* Terminate list */
-
- /* Execute the method, no return value */
-
- ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
- (ACPI_TYPE_METHOD, info->prefix_node, NULL));
-
- status = acpi_ns_evaluate(info);
- acpi_ut_remove_reference(args[1]);
-
- cleanup2:
- acpi_ut_remove_reference(args[0]);
-
- cleanup1:
- ACPI_FREE(info);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ev_address_space_dispatch
*
* PARAMETERS: region_obj - Internal region object
@@ -709,351 +494,86 @@ acpi_ev_attach_region(union acpi_operand_object *handler_obj,
/*******************************************************************************
*
- * FUNCTION: acpi_ev_install_handler
- *
- * PARAMETERS: walk_namespace callback
- *
- * DESCRIPTION: This routine installs an address handler into objects that are
- * of type Region or Device.
- *
- * If the Object is a Device, and the device has a handler of
- * the same type then the search is terminated in that branch.
- *
- * This is because the existing handler is closer in proximity
- * to any more regions than the one we are trying to install.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ev_install_handler(acpi_handle obj_handle,
- u32 level, void *context, void **return_value)
-{
- union acpi_operand_object *handler_obj;
- union acpi_operand_object *next_handler_obj;
- union acpi_operand_object *obj_desc;
- struct acpi_namespace_node *node;
- acpi_status status;
-
- ACPI_FUNCTION_NAME(ev_install_handler);
-
- handler_obj = (union acpi_operand_object *)context;
-
- /* Parameter validation */
-
- if (!handler_obj) {
- return (AE_OK);
- }
-
- /* Convert and validate the device handle */
-
- node = acpi_ns_validate_handle(obj_handle);
- if (!node) {
- return (AE_BAD_PARAMETER);
- }
-
- /*
- * We only care about regions and objects that are allowed to have
- * address space handlers
- */
- if ((node->type != ACPI_TYPE_DEVICE) &&
- (node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
- return (AE_OK);
- }
-
- /* Check for an existing internal object */
-
- obj_desc = acpi_ns_get_attached_object(node);
- if (!obj_desc) {
-
- /* No object, just exit */
-
- return (AE_OK);
- }
-
- /* Devices are handled different than regions */
-
- if (obj_desc->common.type == ACPI_TYPE_DEVICE) {
-
- /* Check if this Device already has a handler for this address space */
-
- next_handler_obj = obj_desc->device.handler;
- while (next_handler_obj) {
-
- /* Found a handler, is it for the same address space? */
-
- if (next_handler_obj->address_space.space_id ==
- handler_obj->address_space.space_id) {
- ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
- "Found handler for region [%s] in device %p(%p) "
- "handler %p\n",
- acpi_ut_get_region_name
- (handler_obj->address_space.
- space_id), obj_desc,
- next_handler_obj,
- handler_obj));
-
- /*
- * Since the object we found it on was a device, then it
- * means that someone has already installed a handler for
- * the branch of the namespace from this device on. Just
- * bail out telling the walk routine to not traverse this
- * branch. This preserves the scoping rule for handlers.
- */
- return (AE_CTRL_DEPTH);
- }
-
- /* Walk the linked list of handlers attached to this device */
-
- next_handler_obj = next_handler_obj->address_space.next;
- }
-
- /*
- * As long as the device didn't have a handler for this space we
- * don't care about it. We just ignore it and proceed.
- */
- return (AE_OK);
- }
-
- /* Object is a Region */
-
- if (obj_desc->region.space_id != handler_obj->address_space.space_id) {
-
- /* This region is for a different address space, just ignore it */
-
- return (AE_OK);
- }
-
- /*
- * Now we have a region and it is for the handler's address space type.
- *
- * First disconnect region for any previous handler (if any)
- */
- acpi_ev_detach_region(obj_desc, FALSE);
-
- /* Connect the region to the new handler */
-
- status = acpi_ev_attach_region(handler_obj, obj_desc, FALSE);
- return (status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ev_install_space_handler
+ * FUNCTION: acpi_ev_execute_reg_method
*
- * PARAMETERS: node - Namespace node for the device
- * space_id - The address space ID
- * handler - Address of the handler
- * setup - Address of the setup function
- * context - Value passed to the handler on each access
+ * PARAMETERS: region_obj - Region object
+ * function - Passed to _REG: On (1) or Off (0)
*
* RETURN: Status
*
- * DESCRIPTION: Install a handler for all op_regions of a given space_id.
- * Assumes namespace is locked
+ * DESCRIPTION: Execute _REG method for a region
*
******************************************************************************/
acpi_status
-acpi_ev_install_space_handler(struct acpi_namespace_node * node,
- acpi_adr_space_type space_id,
- acpi_adr_space_handler handler,
- acpi_adr_space_setup setup, void *context)
+acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
{
- union acpi_operand_object *obj_desc;
- union acpi_operand_object *handler_obj;
+ struct acpi_evaluate_info *info;
+ union acpi_operand_object *args[3];
+ union acpi_operand_object *region_obj2;
acpi_status status;
- acpi_object_type type;
- u8 flags = 0;
- ACPI_FUNCTION_TRACE(ev_install_space_handler);
-
- /*
- * This registration is valid for only the types below and the root. This
- * is where the default handlers get placed.
- */
- if ((node->type != ACPI_TYPE_DEVICE) &&
- (node->type != ACPI_TYPE_PROCESSOR) &&
- (node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
+ ACPI_FUNCTION_TRACE(ev_execute_reg_method);
- if (handler == ACPI_DEFAULT_HANDLER) {
- flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;
-
- switch (space_id) {
- case ACPI_ADR_SPACE_SYSTEM_MEMORY:
- handler = acpi_ex_system_memory_space_handler;
- setup = acpi_ev_system_memory_region_setup;
- break;
-
- case ACPI_ADR_SPACE_SYSTEM_IO:
- handler = acpi_ex_system_io_space_handler;
- setup = acpi_ev_io_space_region_setup;
- break;
-
- case ACPI_ADR_SPACE_PCI_CONFIG:
- handler = acpi_ex_pci_config_space_handler;
- setup = acpi_ev_pci_config_region_setup;
- break;
-
- case ACPI_ADR_SPACE_CMOS:
- handler = acpi_ex_cmos_space_handler;
- setup = acpi_ev_cmos_region_setup;
- break;
-
- case ACPI_ADR_SPACE_PCI_BAR_TARGET:
- handler = acpi_ex_pci_bar_space_handler;
- setup = acpi_ev_pci_bar_region_setup;
- break;
-
- case ACPI_ADR_SPACE_DATA_TABLE:
- handler = acpi_ex_data_table_space_handler;
- setup = NULL;
- break;
-
- default:
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
+ region_obj2 = acpi_ns_get_secondary_object(region_obj);
+ if (!region_obj2) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
}
- /* If the caller hasn't specified a setup routine, use the default */
-
- if (!setup) {
- setup = acpi_ev_default_region_setup;
+ if (region_obj2->extra.method_REG == NULL) {
+ return_ACPI_STATUS(AE_OK);
}
- /* Check for an existing internal object */
-
- obj_desc = acpi_ns_get_attached_object(node);
- if (obj_desc) {
- /*
- * The attached device object already exists. Make sure the handler
- * is not already installed.
- */
- handler_obj = obj_desc->device.handler;
-
- /* Walk the handler list for this device */
-
- while (handler_obj) {
-
- /* Same space_id indicates a handler already installed */
-
- if (handler_obj->address_space.space_id == space_id) {
- if (handler_obj->address_space.handler ==
- handler) {
- /*
- * It is (relatively) OK to attempt to install the SAME
- * handler twice. This can easily happen with the
- * PCI_Config space.
- */
- status = AE_SAME_HANDLER;
- goto unlock_and_exit;
- } else {
- /* A handler is already installed */
-
- status = AE_ALREADY_EXISTS;
- }
- goto unlock_and_exit;
- }
-
- /* Walk the linked list of handlers */
-
- handler_obj = handler_obj->address_space.next;
- }
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
- "Creating object on Device %p while installing handler\n",
- node));
-
- /* obj_desc does not exist, create one */
-
- if (node->type == ACPI_TYPE_ANY) {
- type = ACPI_TYPE_DEVICE;
- } else {
- type = node->type;
- }
-
- obj_desc = acpi_ut_create_internal_object(type);
- if (!obj_desc) {
- status = AE_NO_MEMORY;
- goto unlock_and_exit;
- }
-
- /* Init new descriptor */
-
- obj_desc->common.type = (u8) type;
-
- /* Attach the new object to the Node */
-
- status = acpi_ns_attach_object(node, obj_desc, type);
-
- /* Remove local reference to the object */
-
- acpi_ut_remove_reference(obj_desc);
+ /* Allocate and initialize the evaluation information block */
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
- }
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
- "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
- acpi_ut_get_region_name(space_id), space_id,
- acpi_ut_get_node_name(node), node, obj_desc));
+ info->prefix_node = region_obj2->extra.method_REG;
+ info->pathname = NULL;
+ info->parameters = args;
+ info->flags = ACPI_IGNORE_RETURN_VALUE;
/*
- * Install the handler
+ * The _REG method has two arguments:
+ *
+ * arg0 - Integer:
+ * Operation region space ID Same value as region_obj->Region.space_id
*
- * At this point there is no existing handler. Just allocate the object
- * for the handler and link it into the list.
+ * arg1 - Integer:
+ * connection status 1 for connecting the handler, 0 for disconnecting
+ * the handler (Passed as a parameter)
*/
- handler_obj =
- acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
- if (!handler_obj) {
+ args[0] =
+ acpi_ut_create_integer_object((u64)region_obj->region.space_id);
+ if (!args[0]) {
status = AE_NO_MEMORY;
- goto unlock_and_exit;
+ goto cleanup1;
}
- /* Init handler obj */
+ args[1] = acpi_ut_create_integer_object((u64)function);
+ if (!args[1]) {
+ status = AE_NO_MEMORY;
+ goto cleanup2;
+ }
- handler_obj->address_space.space_id = (u8) space_id;
- handler_obj->address_space.handler_flags = flags;
- handler_obj->address_space.region_list = NULL;
- handler_obj->address_space.node = node;
- handler_obj->address_space.handler = handler;
- handler_obj->address_space.context = context;
- handler_obj->address_space.setup = setup;
+ args[2] = NULL; /* Terminate list */
- /* Install at head of Device.address_space list */
+ /* Execute the method, no return value */
- handler_obj->address_space.next = obj_desc->device.handler;
+ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+ (ACPI_TYPE_METHOD, info->prefix_node, NULL));
- /*
- * The Device object is the first reference on the handler_obj.
- * Each region that uses the handler adds a reference.
- */
- obj_desc->device.handler = handler_obj;
+ status = acpi_ns_evaluate(info);
+ acpi_ut_remove_reference(args[1]);
- /*
- * Walk the namespace finding all of the regions this
- * handler will manage.
- *
- * Start at the device and search the branch toward
- * the leaf nodes until either the leaf is encountered or
- * a device is detected that has an address handler of the
- * same type.
- *
- * In either case, back up and search down the remainder
- * of the branch
- */
- status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
- ACPI_NS_WALK_UNLOCK,
- acpi_ev_install_handler, NULL,
- handler_obj, NULL);
+ cleanup2:
+ acpi_ut_remove_reference(args[0]);
- unlock_and_exit:
+ cleanup1:
+ ACPI_FREE(info);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 1474241bfc7e..3bb616794b3b 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c
index f9661e2b46a9..f4b43bede015 100644
--- a/drivers/acpi/acpica/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -89,7 +89,7 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context)
*/
interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
- return_UINT32(interrupt_handled);
+ return_VALUE(interrupt_handled);
}
/*******************************************************************************
@@ -120,7 +120,7 @@ u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context)
interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
- return_UINT32(interrupt_handled);
+ return_VALUE(interrupt_handled);
}
/******************************************************************************
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index ae668f32cf16..ddffd6847914 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -56,13 +56,13 @@ ACPI_MODULE_NAME("evxface")
*
* FUNCTION: acpi_install_notify_handler
*
- * PARAMETERS: Device - The device for which notifies will be handled
+ * PARAMETERS: device - The device for which notifies will be handled
* handler_type - The type of handler:
* ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
* ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
* ACPI_ALL_NOTIFY: Both System and Device
- * Handler - Address of the handler
- * Context - Value passed to the handler on each GPE
+ * handler - Address of the handler
+ * context - Value passed to the handler on each GPE
*
* RETURN: Status
*
@@ -217,12 +217,12 @@ ACPI_EXPORT_SYMBOL(acpi_install_notify_handler)
*
* FUNCTION: acpi_remove_notify_handler
*
- * PARAMETERS: Device - The device for which the handler is installed
+ * PARAMETERS: device - The device for which the handler is installed
* handler_type - The type of handler:
* ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
* ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
* ACPI_ALL_NOTIFY: Both System and Device
- * Handler - Address of the handler
+ * handler - Address of the handler
*
* RETURN: Status
*
@@ -249,7 +249,8 @@ acpi_remove_notify_handler(acpi_handle device,
(handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Make sure all deferred tasks are completed */
+
+ /* Make sure all deferred notify tasks are completed */
acpi_os_wait_events_complete();
@@ -596,7 +597,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
return_ACPI_STATUS(status);
}
- /* Allocate memory for the handler object */
+ /* Allocate and init handler object (before lock) */
handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info));
if (!handler) {
@@ -622,16 +623,15 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
goto free_and_exit;
}
- /* Allocate and init handler object */
-
handler->address = address;
handler->context = context;
handler->method_node = gpe_event_info->dispatch.method_node;
- handler->original_flags = gpe_event_info->flags &
- (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
+ handler->original_flags = (u8)(gpe_event_info->flags &
+ (ACPI_GPE_XRUPT_TYPE_MASK |
+ ACPI_GPE_DISPATCH_MASK));
/*
- * If the GPE is associated with a method, it might have been enabled
+ * If the GPE is associated with a method, it may have been enabled
* automatically during initialization, in which case it has to be
* disabled now to avoid spurious execution of the handler.
*/
@@ -646,7 +646,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
gpe_event_info->dispatch.handler = handler;
- /* Setup up dispatch flags to indicate handler (vs. method) */
+ /* Setup up dispatch flags to indicate handler (vs. method/notify) */
gpe_event_info->flags &=
~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
@@ -697,7 +697,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Make sure all deferred tasks are completed */
+ /* Make sure all deferred GPE tasks are completed */
acpi_os_wait_events_complete();
@@ -747,10 +747,10 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
* enabled, it should be enabled at this point to restore the
* post-initialization configuration.
*/
-
- if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
- && handler->originally_enabled)
+ if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) &&
+ handler->originally_enabled) {
(void)acpi_ev_add_gpe_reference(gpe_event_info);
+ }
/* Now we can free the handler object */
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 35520c6eeefb..d6e4e42316db 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,7 +61,6 @@ ACPI_MODULE_NAME("evxfevnt")
* DESCRIPTION: Transfers the system into ACPI mode.
*
******************************************************************************/
-
acpi_status acpi_enable(void)
{
acpi_status status;
@@ -210,8 +209,8 @@ ACPI_EXPORT_SYMBOL(acpi_enable_event)
*
* FUNCTION: acpi_disable_event
*
- * PARAMETERS: Event - The fixed eventto be enabled
- * Flags - Reserved
+ * PARAMETERS: event - The fixed event to be disabled
+ * flags - Reserved
*
* RETURN: Status
*
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 3f30e753b652..aff4cc261211 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,7 +51,7 @@
ACPI_MODULE_NAME("evxfgpe")
#if (!ACPI_REDUCED_HARDWARE) /* Entire module */
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_update_all_gpes
*
@@ -172,6 +172,7 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return_ACPI_STATUS(status);
}
+
ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
@@ -225,7 +226,7 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
}
- /* Validate WakeDevice is of type Device */
+ /* Validate wake_device is of type Device */
if (device_node->type != ACPI_TYPE_DEVICE) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
@@ -432,8 +433,8 @@ ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
*
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
* gpe_number - GPE level within the GPE block
- * event_status - Where the current status of the event will
- * be returned
+ * event_status - Where the current status of the event
+ * will be returned
*
* RETURN: Status
*
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index 96b412d03950..96c9e5f355ae 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 16219bde48da..d93b70be60ad 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,7 @@
#include "actables.h"
#include "acdispat.h"
#include "acevents.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exconfig")
@@ -120,8 +121,11 @@ acpi_ex_add_table(u32 table_index,
acpi_ns_exec_module_code_list();
acpi_ex_enter_interpreter();
- /* Update GPEs for any new _Lxx/_Exx methods. Ignore errors */
-
+ /*
+ * Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is
+ * responsible for discovering any new wake GPEs by running _PRW methods
+ * that may have been loaded by this table.
+ */
status = acpi_tb_get_owner_id(table_index, &owner_id);
if (ACPI_SUCCESS(status)) {
acpi_ev_update_gpes(owner_id);
@@ -158,12 +162,12 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
ACPI_FUNCTION_TRACE(ex_load_table_op);
- /* Validate lengths for the signature_string, OEMIDString, OEMtable_iD */
+ /* Validate lengths for the Signature, oem_id, and oem_table_id strings */
if ((operand[0]->string.length > ACPI_NAME_SIZE) ||
(operand[1]->string.length > ACPI_OEM_ID_SIZE) ||
(operand[2]->string.length > ACPI_OEM_TABLE_ID_SIZE)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return_ACPI_STATUS(AE_AML_STRING_LIMIT);
}
/* Find the ACPI table in the RSDT/XSDT */
@@ -210,8 +214,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
/* parameter_path (optional parameter) */
if (operand[4]->string.length > 0) {
- if ((operand[4]->string.pointer[0] != '\\') &&
- (operand[4]->string.pointer[0] != '^')) {
+ if ((operand[4]->string.pointer[0] != AML_ROOT_PREFIX) &&
+ (operand[4]->string.pointer[0] != AML_PARENT_PREFIX)) {
/*
* Path is not absolute, so it will be relative to the node
* referenced by the root_path_string (or the NS root if omitted)
@@ -301,7 +305,7 @@ acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer)
acpi_ev_address_space_dispatch(obj_desc, NULL, ACPI_READ,
region_offset, 8, &value);
if (ACPI_FAILURE(status)) {
- return status;
+ return (status);
}
*buffer = (u8)value;
@@ -309,7 +313,7 @@ acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer)
region_offset++;
}
- return AE_OK;
+ return (AE_OK);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index 4492a4e03022..d2b9613bbf01 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -176,7 +176,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
/* Save the Result */
- acpi_ex_truncate_for32bit_table(return_desc);
+ (void)acpi_ex_truncate_for32bit_table(return_desc);
*result_desc = return_desc;
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c
index 66554bc6f9a8..26a13f67977e 100644
--- a/drivers/acpi/acpica/excreate.c
+++ b/drivers/acpi/acpica/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c
index d7c9f51608a7..7eb853cd279f 100644
--- a/drivers/acpi/acpica/exdebug.c
+++ b/drivers/acpi/acpica/exdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index 858b43a7dcf6..e5a3c249f7fa 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -464,9 +464,8 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
ACPI_FUNCTION_NAME(ex_dump_operand)
- if (!
- ((ACPI_LV_EXEC & acpi_dbg_level)
- && (_COMPONENT & acpi_dbg_layer))) {
+ /* Check if debug output enabled */
+ if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_EXEC, _COMPONENT)) {
return;
}
@@ -811,9 +810,10 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags)
ACPI_FUNCTION_ENTRY();
if (!flags) {
- if (!
- ((ACPI_LV_OBJECTS & acpi_dbg_level)
- && (_COMPONENT & acpi_dbg_layer))) {
+
+ /* Check if debug output enabled */
+
+ if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_OBJECTS, _COMPONENT)) {
return;
}
}
@@ -999,9 +999,10 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags)
}
if (!flags) {
- if (!
- ((ACPI_LV_OBJECTS & acpi_dbg_level)
- && (_COMPONENT & acpi_dbg_layer))) {
+
+ /* Check if debug output enabled */
+
+ if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_OBJECTS, _COMPONENT)) {
return_VOID;
}
}
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index ebc55fbf3ff7..7d4bae71e8c6 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index aa2ccfb7cb61..ec7f5690031b 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -329,7 +329,6 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
static u8
acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value)
{
- ACPI_FUNCTION_NAME(ex_register_overflow);
if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) {
/*
diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c
index 84058705ed12..72a2a13b6d36 100644
--- a/drivers/acpi/acpica/exmisc.c
+++ b/drivers/acpi/acpica/exmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c
index d1f449d93dcf..7be0205ad067 100644
--- a/drivers/acpi/acpica/exmutex.c
+++ b/drivers/acpi/acpica/exmutex.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -377,7 +377,8 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
}
- /* Must have a valid thread. */
+ /* Must have a valid thread ID */
+
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
"Cannot release Mutex [%4.4s], null thread info",
diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c
index 2ff578a16adc..14689dec4960 100644
--- a/drivers/acpi/acpica/exnames.c
+++ b/drivers/acpi/acpica/exnames.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index bbf01e9bf057..b60c877f5906 100644
--- a/drivers/acpi/acpica/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -948,13 +948,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
*/
return_desc =
acpi_ut_create_integer_object((u64)
- temp_desc->
- buffer.
- pointer
- [operand
- [0]->
- reference.
- value]);
+ temp_desc->buffer.pointer[operand[0]->reference.value]);
if (!return_desc) {
status = AE_NO_MEMORY;
goto cleanup;
diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c
index ee5634a074c4..e491e46f17df 100644
--- a/drivers/acpi/acpica/exoparg2.c
+++ b/drivers/acpi/acpica/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index 2c89b4651f08..2d7491f3126e 100644
--- a/drivers/acpi/acpica/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c
index 3e08695c3b30..b76b97002dff 100644
--- a/drivers/acpi/acpica/exoparg6.c
+++ b/drivers/acpi/acpica/exoparg6.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index ba9db4de7c89..d6eab81f54fb 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -276,7 +276,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
/* Invalid field access type */
ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access));
- return_UINT32(0);
+ return_VALUE(0);
}
if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
@@ -289,7 +289,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
}
*return_byte_alignment = byte_alignment;
- return_UINT32(bit_length);
+ return_VALUE(bit_length);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index 1db2c0bfde0b..182abaf045e1 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -142,9 +142,9 @@ acpi_ex_system_memory_space_handler(u32 function,
}
/*
- * Attempt to map from the requested address to the end of the region.
- * However, we will never map more than one page, nor will we cross
- * a page boundary.
+ * October 2009: Attempt to map from the requested address to the
+ * end of the region. However, we will never map more than one
+ * page, nor will we cross a page boundary.
*/
map_length = (acpi_size)
((mem_info->address + mem_info->length) - address);
@@ -154,12 +154,15 @@ acpi_ex_system_memory_space_handler(u32 function,
* a page boundary, just map up to the page boundary, do not cross.
* On some systems, crossing a page boundary while mapping regions
* can cause warnings if the pages have different attributes
- * due to resource management
+ * due to resource management.
+ *
+ * This has the added benefit of constraining a single mapping to
+ * one page, which is similar to the original code that used a 4k
+ * maximum window.
*/
page_boundary_map_length =
ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address;
-
- if (!page_boundary_map_length) {
+ if (page_boundary_map_length == 0) {
page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE;
}
@@ -236,19 +239,19 @@ acpi_ex_system_memory_space_handler(u32 function,
switch (bit_width) {
case 8:
- ACPI_SET8(logical_addr_ptr) = (u8) * value;
+ ACPI_SET8(logical_addr_ptr, *value);
break;
case 16:
- ACPI_SET16(logical_addr_ptr) = (u16) * value;
+ ACPI_SET16(logical_addr_ptr, *value);
break;
case 32:
- ACPI_SET32(logical_addr_ptr) = (u32) * value;
+ ACPI_SET32(logical_addr_ptr, *value);
break;
case 64:
- ACPI_SET64(logical_addr_ptr) = (u64) * value;
+ ACPI_SET64(logical_addr_ptr, *value);
break;
default:
diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c
index 6239956786eb..8565b6bd12bb 100644
--- a/drivers/acpi/acpica/exresnte.c
+++ b/drivers/acpi/acpica/exresnte.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c
index cc176b245e22..e4f9dfbb2a13 100644
--- a/drivers/acpi/acpica/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c
index b9ebff2f6a09..9fb9f5e9a4da 100644
--- a/drivers/acpi/acpica/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
index 90431f12f831..93c6049c2d75 100644
--- a/drivers/acpi/acpica/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -487,14 +487,33 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
default:
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Storing %s (%p) directly into node (%p) with no implicit conversion\n",
+ "Storing [%s] (%p) directly into node [%s] (%p)"
+ " with no implicit conversion\n",
acpi_ut_get_object_type_name(source_desc),
- source_desc, node));
+ source_desc,
+ acpi_ut_get_object_type_name(target_desc),
+ node));
- /* No conversions for all other types. Just attach the source object */
+ /*
+ * No conversions for all other types. Directly store a copy of
+ * the source object. NOTE: This is a departure from the ACPI
+ * spec, which states "If conversion is impossible, abort the
+ * running control method".
+ *
+ * This code implements "If conversion is impossible, treat the
+ * Store operation as a CopyObject".
+ */
+ status =
+ acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- status = acpi_ns_attach_object(node, source_desc,
- source_desc->common.type);
+ status =
+ acpi_ns_attach_object(node, new_desc,
+ new_desc->common.type);
+ acpi_ut_remove_reference(new_desc);
break;
}
diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c
index 87153bbc4b43..1cefe777068e 100644
--- a/drivers/acpi/acpica/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -253,7 +253,7 @@ acpi_ex_store_object_to_object(union acpi_operand_object *source_desc,
/* Truncate value if we are executing from a 32-bit ACPI table */
- acpi_ex_truncate_for32bit_table(dest_desc);
+ (void)acpi_ex_truncate_for32bit_table(dest_desc);
break;
case ACPI_TYPE_STRING:
diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c
index b5f339cb1305..26e371073b1a 100644
--- a/drivers/acpi/acpica/exstorob.c
+++ b/drivers/acpi/acpica/exstorob.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c
index c8a0ad5c1f55..6578dee2e51b 100644
--- a/drivers/acpi/acpica/exsystem.c
+++ b/drivers/acpi/acpica/exsystem.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index 264d22d8018c..b205cbb4b50c 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -202,35 +202,39 @@ void acpi_ex_relinquish_interpreter(void)
*
* PARAMETERS: obj_desc - Object to be truncated
*
- * RETURN: none
+ * RETURN: TRUE if a truncation was performed, FALSE otherwise.
*
* DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
* 32-bit, as determined by the revision of the DSDT.
*
******************************************************************************/
-void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
+u8 acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
{
ACPI_FUNCTION_ENTRY();
/*
* Object must be a valid number and we must be executing
- * a control method. NS node could be there for AML_INT_NAMEPATH_OP.
+ * a control method. Object could be NS node for AML_INT_NAMEPATH_OP.
*/
if ((!obj_desc) ||
(ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) ||
(obj_desc->common.type != ACPI_TYPE_INTEGER)) {
- return;
+ return (FALSE);
}
- if (acpi_gbl_integer_byte_width == 4) {
+ if ((acpi_gbl_integer_byte_width == 4) &&
+ (obj_desc->integer.value > (u64)ACPI_UINT32_MAX)) {
/*
- * We are running a method that exists in a 32-bit ACPI table.
+ * We are executing in a 32-bit ACPI table.
* Truncate the value to 32 bits by zeroing out the upper 32-bit field
*/
- obj_desc->integer.value &= (u64) ACPI_UINT32_MAX;
+ obj_desc->integer.value &= (u64)ACPI_UINT32_MAX;
+ return (TRUE);
}
+
+ return (FALSE);
}
/*******************************************************************************
@@ -336,7 +340,7 @@ static u32 acpi_ex_digits_needed(u64 value, u32 base)
/* u64 is unsigned, so we don't worry about a '-' prefix */
if (value == 0) {
- return_UINT32(1);
+ return_VALUE(1);
}
current_value = value;
@@ -350,7 +354,7 @@ static u32 acpi_ex_digits_needed(u64 value, u32 base)
num_digits++;
}
- return_UINT32(num_digits);
+ return_VALUE(num_digits);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index 90a9aea1cee9..deb3f61e2bd1 100644
--- a/drivers/acpi/acpica/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -108,8 +108,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
* enable bits to default
*/
status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
- (u32) acpi_gbl_FADT.acpi_disable,
- 8);
+ (u32)acpi_gbl_FADT.acpi_disable, 8);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Attempting to enable Legacy (non-ACPI) mode\n"));
break;
@@ -152,18 +151,18 @@ u32 acpi_hw_get_mode(void)
* system does not support mode transition.
*/
if (!acpi_gbl_FADT.smi_command) {
- return_UINT32(ACPI_SYS_MODE_ACPI);
+ return_VALUE(ACPI_SYS_MODE_ACPI);
}
status = acpi_read_bit_register(ACPI_BITREG_SCI_ENABLE, &value);
if (ACPI_FAILURE(status)) {
- return_UINT32(ACPI_SYS_MODE_LEGACY);
+ return_VALUE(ACPI_SYS_MODE_LEGACY);
}
if (value) {
- return_UINT32(ACPI_SYS_MODE_ACPI);
+ return_VALUE(ACPI_SYS_MODE_ACPI);
} else {
- return_UINT32(ACPI_SYS_MODE_LEGACY);
+ return_VALUE(ACPI_SYS_MODE_LEGACY);
}
}
diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
index 94996f9ae3ad..5e5f76230f5e 100644
--- a/drivers/acpi/acpica/hwesleep.c
+++ b/drivers/acpi/acpica/hwesleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -200,7 +200,6 @@ acpi_status acpi_hw_extended_wake_prep(u8 sleep_state)
* FUNCTION: acpi_hw_extended_wake
*
* PARAMETERS: sleep_state - Which sleep state we just exited
- * flags - Reserved, set to zero
*
* RETURN: Status
*
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 64560045052d..20d02e93c990 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -69,8 +69,10 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info)
{
- return (u32)1 << (gpe_event_info->gpe_number -
- gpe_event_info->register_info->base_gpe_number);
+
+ return ((u32)1 <<
+ (gpe_event_info->gpe_number -
+ gpe_event_info->register_info->base_gpe_number));
}
/******************************************************************************
@@ -133,7 +135,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
break;
default:
- ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u\n", action));
+ ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u", action));
return (AE_BAD_PARAMETER);
}
diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c
index 65bc3453a29c..0889a629505f 100644
--- a/drivers/acpi/acpica/hwpci.c
+++ b/drivers/acpi/acpica/hwpci.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index f4e57503576b..083d6551f0e2 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,6 @@
#include <acpi/acpi.h>
#include "accommon.h"
-#include "acnamesp.h"
#include "acevents.h"
#define _COMPONENT ACPI_HARDWARE
@@ -364,8 +363,7 @@ acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control)
* DESCRIPTION: Read from the specified ACPI register
*
******************************************************************************/
-acpi_status
-acpi_hw_register_read(u32 register_id, u32 * return_value)
+acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
{
u32 value = 0;
acpi_status status;
@@ -485,7 +483,7 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
&acpi_gbl_xpm1b_status);
break;
- case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access */
+ case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */
status = acpi_hw_write_multiple(value,
&acpi_gbl_xpm1a_enable,
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index 3fddde056a5e..e3828cc4361b 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,6 @@
#include <acpi/acpi.h>
#include <linux/acpi.h>
#include "accommon.h"
-#include <linux/module.h>
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwsleep")
@@ -178,7 +177,7 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
* to still read the right value. Ideally, this block would go
* away entirely.
*/
- acpi_os_stall(10000000);
+ acpi_os_stall(10 * ACPI_USEC_PER_SEC);
status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
sleep_enable_reg_info->
@@ -323,7 +322,8 @@ acpi_status acpi_hw_legacy_wake(u8 sleep_state)
* and use it to determine whether the system is rebooting or
* resuming. Clear WAK_STS for compatibility.
*/
- acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1);
+ (void)acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS,
+ ACPI_CLEAR_STATUS);
acpi_gbl_system_awake_and_running = TRUE;
/* Enable power button */
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index bfdce22f3798..0c1a8bbd05d6 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -176,10 +176,11 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
/*
* Compute Duration (Requires a 64-bit multiply and divide):
*
- * time_elapsed = (delta_ticks * 1000000) / PM_TIMER_FREQUENCY;
+ * time_elapsed (microseconds) =
+ * (delta_ticks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY;
*/
- status = acpi_ut_short_divide(((u64) delta_ticks) * 1000000,
- PM_TIMER_FREQUENCY, &quotient, NULL);
+ status = acpi_ut_short_divide(((u64)delta_ticks) * ACPI_USEC_PER_SEC,
+ ACPI_PM_TIMER_FREQUENCY, &quotient, NULL);
*time_elapsed = (u32) quotient;
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c
index b6aae58299dc..eab70d58852a 100644
--- a/drivers/acpi/acpica/hwvalid.c
+++ b/drivers/acpi/acpica/hwvalid.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -135,7 +135,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) {
ACPI_ERROR((AE_INFO,
"Bad BitWidth parameter: %8.8X", bit_width));
- return AE_BAD_PARAMETER;
+ return (AE_BAD_PARAMETER);
}
port_info = acpi_protected_ports;
@@ -234,11 +234,11 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
status = acpi_hw_validate_io_request(address, width);
if (ACPI_SUCCESS(status)) {
status = acpi_os_read_port(address, value, width);
- return status;
+ return (status);
}
if (status != AE_AML_ILLEGAL_ADDRESS) {
- return status;
+ return (status);
}
/*
@@ -253,7 +253,7 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
if (acpi_hw_validate_io_request(address, 8) == AE_OK) {
status = acpi_os_read_port(address, &one_byte, 8);
if (ACPI_FAILURE(status)) {
- return status;
+ return (status);
}
*value |= (one_byte << i);
@@ -262,7 +262,7 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
address++;
}
- return AE_OK;
+ return (AE_OK);
}
/******************************************************************************
@@ -297,11 +297,11 @@ acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width)
status = acpi_hw_validate_io_request(address, width);
if (ACPI_SUCCESS(status)) {
status = acpi_os_write_port(address, value, width);
- return status;
+ return (status);
}
if (status != AE_AML_ILLEGAL_ADDRESS) {
- return status;
+ return (status);
}
/*
@@ -317,12 +317,12 @@ acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width)
status =
acpi_os_write_port(address, (value >> i) & 0xFF, 8);
if (ACPI_FAILURE(status)) {
- return status;
+ return (status);
}
}
address++;
}
- return AE_OK;
+ return (AE_OK);
}
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index 05a154c3c9ac..04c2e16f2c0a 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -80,10 +80,10 @@ acpi_status acpi_reset(void)
if (reset_reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
/*
- * For I/O space, write directly to the OSL. This
- * bypasses the port validation mechanism, which may
- * block a valid write to the reset register. Spec
- * section 4.7.3.6 requires register width to be 8.
+ * For I/O space, write directly to the OSL. This bypasses the port
+ * validation mechanism, which may block a valid write to the reset
+ * register.
+ * Spec section 4.7.3.6 requires register width to be 8.
*/
status =
acpi_os_write_port((acpi_io_address) reset_reg->address,
@@ -333,7 +333,7 @@ ACPI_EXPORT_SYMBOL(acpi_read_bit_register)
* FUNCTION: acpi_write_bit_register
*
* PARAMETERS: register_id - ID of ACPI Bit Register to access
- * Value - Value to write to the register, in bit
+ * value - Value to write to the register, in bit
* position zero. The bit is automatically
* shifted to the correct position.
*
@@ -440,17 +440,41 @@ ACPI_EXPORT_SYMBOL(acpi_write_bit_register)
* *sleep_type_a - Where SLP_TYPa is returned
* *sleep_type_b - Where SLP_TYPb is returned
*
- * RETURN: status - ACPI status
+ * RETURN: Status
+ *
+ * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested
+ * sleep state via the appropriate \_Sx object.
+ *
+ * The sleep state package returned from the corresponding \_Sx_ object
+ * must contain at least one integer.
+ *
+ * March 2005:
+ * Added support for a package that contains two integers. This
+ * goes against the ACPI specification which defines this object as a
+ * package with one encoded DWORD integer. However, existing practice
+ * by many BIOS vendors is to return a package with 2 or more integer
+ * elements, at least one per sleep type (A/B).
*
- * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep
- * state.
+ * January 2013:
+ * Therefore, we must be prepared to accept a package with either a
+ * single integer or multiple integers.
+ *
+ * The single integer DWORD format is as follows:
+ * BYTE 0 - Value for the PM1A SLP_TYP register
+ * BYTE 1 - Value for the PM1B SLP_TYP register
+ * BYTE 2-3 - Reserved
+ *
+ * The dual integer format is as follows:
+ * Integer 0 - Value for the PM1A SLP_TYP register
+ * Integer 1 - Value for the PM1A SLP_TYP register
*
******************************************************************************/
acpi_status
acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
{
- acpi_status status = AE_OK;
+ acpi_status status;
struct acpi_evaluate_info *info;
+ union acpi_operand_object **elements;
ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data);
@@ -467,18 +491,14 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
return_ACPI_STATUS(AE_NO_MEMORY);
}
+ /*
+ * Evaluate the \_Sx namespace object containing the register values
+ * for this state
+ */
info->pathname =
ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
-
- /* Evaluate the namespace object containing the values for this state */
-
status = acpi_ns_evaluate(info);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "%s while evaluating SleepState [%s]\n",
- acpi_format_exception(status),
- info->pathname));
-
goto cleanup;
}
@@ -487,64 +507,67 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
if (!info->return_object) {
ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
info->pathname));
- status = AE_NOT_EXIST;
+ status = AE_AML_NO_RETURN_VALUE;
+ goto cleanup;
}
- /* It must be of type Package */
+ /* Return object must be of type Package */
- else if (info->return_object->common.type != ACPI_TYPE_PACKAGE) {
+ if (info->return_object->common.type != ACPI_TYPE_PACKAGE) {
ACPI_ERROR((AE_INFO,
"Sleep State return object is not a Package"));
status = AE_AML_OPERAND_TYPE;
+ goto cleanup1;
}
/*
- * The package must have at least two elements. NOTE (March 2005): This
- * goes against the current ACPI spec which defines this object as a
- * package with one encoded DWORD element. However, existing practice
- * by BIOS vendors seems to be to have 2 or more elements, at least
- * one per sleep type (A/B).
+ * Any warnings about the package length or the object types have
+ * already been issued by the predefined name module -- there is no
+ * need to repeat them here.
*/
- else if (info->return_object->package.count < 2) {
- ACPI_ERROR((AE_INFO,
- "Sleep State return package does not have at least two elements"));
- status = AE_AML_NO_OPERAND;
- }
+ elements = info->return_object->package.elements;
+ switch (info->return_object->package.count) {
+ case 0:
+ status = AE_AML_PACKAGE_LIMIT;
+ break;
+
+ case 1:
+ if (elements[0]->common.type != ACPI_TYPE_INTEGER) {
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
- /* The first two elements must both be of type Integer */
+ /* A valid _Sx_ package with one integer */
- else if (((info->return_object->package.elements[0])->common.type
- != ACPI_TYPE_INTEGER) ||
- ((info->return_object->package.elements[1])->common.type
- != ACPI_TYPE_INTEGER)) {
- ACPI_ERROR((AE_INFO,
- "Sleep State return package elements are not both Integers "
- "(%s, %s)",
- acpi_ut_get_object_type_name(info->return_object->
- package.elements[0]),
- acpi_ut_get_object_type_name(info->return_object->
- package.elements[1])));
- status = AE_AML_OPERAND_TYPE;
- } else {
- /* Valid _Sx_ package size, type, and value */
+ *sleep_type_a = (u8)elements[0]->integer.value;
+ *sleep_type_b = (u8)(elements[0]->integer.value >> 8);
+ break;
- *sleep_type_a = (u8)
- (info->return_object->package.elements[0])->integer.value;
- *sleep_type_b = (u8)
- (info->return_object->package.elements[1])->integer.value;
- }
+ case 2:
+ default:
+ if ((elements[0]->common.type != ACPI_TYPE_INTEGER) ||
+ (elements[1]->common.type != ACPI_TYPE_INTEGER)) {
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "While evaluating SleepState [%s], bad Sleep object %p type %s",
- info->pathname, info->return_object,
- acpi_ut_get_object_type_name(info->
- return_object)));
+ /* A valid _Sx_ package with two integers */
+
+ *sleep_type_a = (u8)elements[0]->integer.value;
+ *sleep_type_b = (u8)elements[1]->integer.value;
+ break;
}
+ cleanup1:
acpi_ut_remove_reference(info->return_object);
cleanup:
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "While evaluating Sleep State [%s]",
+ info->pathname));
+ }
+
ACPI_FREE(info);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
index ae443fe2ebf6..35eebdac0f9d 100644
--- a/drivers/acpi/acpica/hwxfsleep.c
+++ b/drivers/acpi/acpica/hwxfsleep.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -41,9 +41,9 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
+#include <linux/export.h>
#include <acpi/acpi.h>
#include "accommon.h"
-#include <linux/module.h>
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwxfsleep")
@@ -207,7 +207,7 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
(u32)acpi_gbl_FADT.s4_bios_request, 8);
do {
- acpi_os_stall(1000);
+ acpi_os_stall(ACPI_USEC_PER_MSEC);
status =
acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
if (ACPI_FAILURE(status)) {
@@ -350,7 +350,7 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
*
* RETURN: Status
*
- * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231)
+ * DESCRIPTION: Enter a system sleep state
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
*
******************************************************************************/
@@ -382,8 +382,9 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
* RETURN: Status
*
* DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
- * sleep.
- * Called with interrupts DISABLED.
+ * sleep. Called with interrupts DISABLED.
+ * We break wake/resume into 2 stages so that OSPM can handle
+ * various OS-specific tasks between the two steps.
*
******************************************************************************/
acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index d70eaf39dfdf..8769cf83b044 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index 15143c44f5e5..243737363fb8 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index 924b3c71473a..ce6e97326205 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"
+#include <acpi/acoutput.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsdump")
@@ -77,8 +78,9 @@ void acpi_ns_print_pathname(u32 num_segments, char *pathname)
ACPI_FUNCTION_NAME(ns_print_pathname);
- if (!(acpi_dbg_level & ACPI_LV_NAMES)
- || !(acpi_dbg_layer & ACPI_NAMESPACE)) {
+ /* Check if debug output enabled */
+
+ if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_NAMES, ACPI_NAMESPACE)) {
return;
}
@@ -127,7 +129,7 @@ acpi_ns_dump_pathname(acpi_handle handle, char *msg, u32 level, u32 component)
/* Do this only if the requested debug level and component are enabled */
- if (!(acpi_dbg_level & level) || !(acpi_dbg_layer & component)) {
+ if (!ACPI_IS_DEBUG_ENABLED(level, component)) {
return_VOID;
}
@@ -729,5 +731,5 @@ void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth)
ACPI_OWNER_ID_MAX, search_handle);
return_VOID;
}
-#endif /* _ACPI_ASL_COMPILER */
-#endif /* defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) */
+#endif
+#endif
diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index 944d4c8d9438..409ae80824d1 100644
--- a/drivers/acpi/acpica/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,6 @@
*/
#include <acpi/acpi.h>
-#include "accommon.h"
/* TBD: This entire module is apparently obsolete and should be removed */
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index 69074be498e8..1538f3eb2a8f 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 4328e2adfeb9..2a431ec50a25 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,6 @@
#include "acnamesp.h"
#include "acdispat.h"
#include "acinterp.h"
-#include <linux/nmi.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsinit")
@@ -87,7 +86,7 @@ acpi_status acpi_ns_initialize_objects(void)
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"**** Starting initialization of namespace objects ****\n"));
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "Completing Region/Field/Buffer/Package initialization:"));
+ "Completing Region/Field/Buffer/Package initialization:\n"));
/* Set all init info to zero */
@@ -103,7 +102,7 @@ acpi_status acpi_ns_initialize_objects(void)
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nInitialized %u/%u Regions %u/%u Fields %u/%u "
+ " Initialized %u/%u Regions %u/%u Fields %u/%u "
"Buffers %u/%u Packages (%u nodes)\n",
info.op_region_init, info.op_region_count,
info.field_init, info.field_count,
@@ -150,7 +149,7 @@ acpi_status acpi_ns_initialize_devices(void)
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
"Initializing Device/Processor/Thermal objects "
- "by executing _INI methods:"));
+ "and executing _INI/_STA methods:\n"));
/* Tree analysis: find all subtrees that contain _INI methods */
@@ -208,7 +207,7 @@ acpi_status acpi_ns_initialize_devices(void)
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nExecuted %u _INI methods requiring %u _STA executions "
+ " Executed %u _INI methods requiring %u _STA executions "
"(examined %u objects)\n",
info.num_INI, info.num_STA, info.device_count));
@@ -350,14 +349,6 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
}
/*
- * Print a dot for each object unless we are going to print the entire
- * pathname
- */
- if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "."));
- }
-
- /*
* We ignore errors from above, and always return OK, since we don't want
* to abort the walk on any single error.
*/
@@ -572,20 +563,10 @@ acpi_ns_init_one_device(acpi_handle obj_handle,
info->parameters = NULL;
info->flags = ACPI_IGNORE_RETURN_VALUE;
- /*
- * Some hardware relies on this being executed as atomically
- * as possible (without an NMI being received in the middle of
- * this) - so disable NMIs and initialize the device:
- */
status = acpi_ns_evaluate(info);
if (ACPI_SUCCESS(status)) {
walk_info->num_INI++;
-
- if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) &&
- (!(acpi_dbg_level & ACPI_LV_INFO))) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "."));
- }
}
#ifdef ACPI_DEBUG_OUTPUT
else if (status != AE_NOT_FOUND) {
diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c
index 911f99127b99..0a7badc3179f 100644
--- a/drivers/acpi/acpica/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c
index 55a175eadcc3..90a0380fb8a0 100644
--- a/drivers/acpi/acpica/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -126,7 +126,8 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node,
* the node, In external format (name segments separated by path
* separators.)
*
- * DESCRIPTION: Used for debug printing in acpi_ns_search_table().
+ * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually
+ * for error and debug statements.
*
******************************************************************************/
diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c
index e69f7fa2579d..7a736f4d1fd8 100644
--- a/drivers/acpi/acpica/nsobject.c
+++ b/drivers/acpi/acpica/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c
index 233f756d5cfa..35dde8151c0d 100644
--- a/drivers/acpi/acpica/nsparse.c
+++ b/drivers/acpi/acpica/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 2419f417ea33..224c30053401 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -1,12 +1,11 @@
/******************************************************************************
*
* Module Name: nspredef - Validation of ACPI predefined methods and objects
- * $Revision: 1.1 $
*
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -74,27 +73,6 @@ ACPI_MODULE_NAME("nspredef")
******************************************************************************/
/* Local prototypes */
static acpi_status
-acpi_ns_check_package(struct acpi_predefined_data *data,
- union acpi_operand_object **return_object_ptr);
-
-static acpi_status
-acpi_ns_check_package_list(struct acpi_predefined_data *data,
- const union acpi_predefined_info *package,
- union acpi_operand_object **elements, u32 count);
-
-static acpi_status
-acpi_ns_check_package_elements(struct acpi_predefined_data *data,
- union acpi_operand_object **elements,
- u8 type1,
- u32 count1,
- u8 type2, u32 count2, u32 start_index);
-
-static acpi_status
-acpi_ns_check_object_type(struct acpi_predefined_data *data,
- union acpi_operand_object **return_object_ptr,
- u32 expected_btypes, u32 package_index);
-
-static acpi_status
acpi_ns_check_reference(struct acpi_predefined_data *data,
union acpi_operand_object *return_object);
@@ -148,7 +126,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
pathname = acpi_ns_get_external_pathname(node);
if (!pathname) {
- return AE_OK; /* Could not get pathname, ignore */
+ return (AE_OK); /* Could not get pathname, ignore */
}
/*
@@ -408,564 +386,6 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
/*******************************************************************************
*
- * FUNCTION: acpi_ns_check_package
- *
- * PARAMETERS: data - Pointer to validation data structure
- * return_object_ptr - Pointer to the object returned from the
- * evaluation of a method or object
- *
- * RETURN: Status
- *
- * DESCRIPTION: Check a returned package object for the correct count and
- * correct type of all sub-objects.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ns_check_package(struct acpi_predefined_data *data,
- union acpi_operand_object **return_object_ptr)
-{
- union acpi_operand_object *return_object = *return_object_ptr;
- const union acpi_predefined_info *package;
- union acpi_operand_object **elements;
- acpi_status status = AE_OK;
- u32 expected_count;
- u32 count;
- u32 i;
-
- ACPI_FUNCTION_NAME(ns_check_package);
-
- /* The package info for this name is in the next table entry */
-
- package = data->predefined + 1;
-
- ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
- "%s Validating return Package of Type %X, Count %X\n",
- data->pathname, package->ret_info.type,
- return_object->package.count));
-
- /*
- * For variable-length Packages, we can safely remove all embedded
- * and trailing NULL package elements
- */
- acpi_ns_remove_null_elements(data, package->ret_info.type,
- return_object);
-
- /* Extract package count and elements array */
-
- elements = return_object->package.elements;
- count = return_object->package.count;
-
- /* The package must have at least one element, else invalid */
-
- if (!count) {
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
- "Return Package has no elements (empty)"));
-
- return (AE_AML_OPERAND_VALUE);
- }
-
- /*
- * Decode the type of the expected package contents
- *
- * PTYPE1 packages contain no subpackages
- * PTYPE2 packages contain sub-packages
- */
- switch (package->ret_info.type) {
- case ACPI_PTYPE1_FIXED:
-
- /*
- * The package count is fixed and there are no sub-packages
- *
- * If package is too small, exit.
- * If package is larger than expected, issue warning but continue
- */
- expected_count =
- package->ret_info.count1 + package->ret_info.count2;
- if (count < expected_count) {
- goto package_too_small;
- } else if (count > expected_count) {
- ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
- "%s: Return Package is larger than needed - "
- "found %u, expected %u\n",
- data->pathname, count,
- expected_count));
- }
-
- /* Validate all elements of the returned package */
-
- status = acpi_ns_check_package_elements(data, elements,
- package->ret_info.
- object_type1,
- package->ret_info.
- count1,
- package->ret_info.
- object_type2,
- package->ret_info.
- count2, 0);
- break;
-
- case ACPI_PTYPE1_VAR:
-
- /*
- * The package count is variable, there are no sub-packages, and all
- * elements must be of the same type
- */
- for (i = 0; i < count; i++) {
- status = acpi_ns_check_object_type(data, elements,
- package->ret_info.
- object_type1, i);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- elements++;
- }
- break;
-
- case ACPI_PTYPE1_OPTION:
-
- /*
- * The package count is variable, there are no sub-packages. There are
- * a fixed number of required elements, and a variable number of
- * optional elements.
- *
- * Check if package is at least as large as the minimum required
- */
- expected_count = package->ret_info3.count;
- if (count < expected_count) {
- goto package_too_small;
- }
-
- /* Variable number of sub-objects */
-
- for (i = 0; i < count; i++) {
- if (i < package->ret_info3.count) {
-
- /* These are the required package elements (0, 1, or 2) */
-
- status =
- acpi_ns_check_object_type(data, elements,
- package->
- ret_info3.
- object_type[i],
- i);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- } else {
- /* These are the optional package elements */
-
- status =
- acpi_ns_check_object_type(data, elements,
- package->
- ret_info3.
- tail_object_type,
- i);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- }
- elements++;
- }
- break;
-
- case ACPI_PTYPE2_REV_FIXED:
-
- /* First element is the (Integer) revision */
-
- status = acpi_ns_check_object_type(data, elements,
- ACPI_RTYPE_INTEGER, 0);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- elements++;
- count--;
-
- /* Examine the sub-packages */
-
- status =
- acpi_ns_check_package_list(data, package, elements, count);
- break;
-
- case ACPI_PTYPE2_PKG_COUNT:
-
- /* First element is the (Integer) count of sub-packages to follow */
-
- status = acpi_ns_check_object_type(data, elements,
- ACPI_RTYPE_INTEGER, 0);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- /*
- * Count cannot be larger than the parent package length, but allow it
- * to be smaller. The >= accounts for the Integer above.
- */
- expected_count = (u32) (*elements)->integer.value;
- if (expected_count >= count) {
- goto package_too_small;
- }
-
- count = expected_count;
- elements++;
-
- /* Examine the sub-packages */
-
- status =
- acpi_ns_check_package_list(data, package, elements, count);
- break;
-
- case ACPI_PTYPE2:
- case ACPI_PTYPE2_FIXED:
- case ACPI_PTYPE2_MIN:
- case ACPI_PTYPE2_COUNT:
- case ACPI_PTYPE2_FIX_VAR:
-
- /*
- * These types all return a single Package that consists of a
- * variable number of sub-Packages.
- *
- * First, ensure that the first element is a sub-Package. If not,
- * the BIOS may have incorrectly returned the object as a single
- * package instead of a Package of Packages (a common error if
- * there is only one entry). We may be able to repair this by
- * wrapping the returned Package with a new outer Package.
- */
- if (*elements
- && ((*elements)->common.type != ACPI_TYPE_PACKAGE)) {
-
- /* Create the new outer package and populate it */
-
- status =
- acpi_ns_wrap_with_package(data, return_object,
- return_object_ptr);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- /* Update locals to point to the new package (of 1 element) */
-
- return_object = *return_object_ptr;
- elements = return_object->package.elements;
- count = 1;
- }
-
- /* Examine the sub-packages */
-
- status =
- acpi_ns_check_package_list(data, package, elements, count);
- break;
-
- default:
-
- /* Should not get here if predefined info table is correct */
-
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
- "Invalid internal return type in table entry: %X",
- package->ret_info.type));
-
- return (AE_AML_INTERNAL);
- }
-
- return (status);
-
-package_too_small:
-
- /* Error exit for the case with an incorrect package count */
-
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
- "Return Package is too small - found %u elements, expected %u",
- count, expected_count));
-
- return (AE_AML_OPERAND_VALUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_check_package_list
- *
- * PARAMETERS: data - Pointer to validation data structure
- * package - Pointer to package-specific info for method
- * elements - Element list of parent package. All elements
- * of this list should be of type Package.
- * count - Count of subpackages
- *
- * RETURN: Status
- *
- * DESCRIPTION: Examine a list of subpackages
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ns_check_package_list(struct acpi_predefined_data *data,
- const union acpi_predefined_info *package,
- union acpi_operand_object **elements, u32 count)
-{
- union acpi_operand_object *sub_package;
- union acpi_operand_object **sub_elements;
- acpi_status status;
- u32 expected_count;
- u32 i;
- u32 j;
-
- /*
- * Validate each sub-Package in the parent Package
- *
- * NOTE: assumes list of sub-packages contains no NULL elements.
- * Any NULL elements should have been removed by earlier call
- * to acpi_ns_remove_null_elements.
- */
- for (i = 0; i < count; i++) {
- sub_package = *elements;
- sub_elements = sub_package->package.elements;
- data->parent_package = sub_package;
-
- /* Each sub-object must be of type Package */
-
- status = acpi_ns_check_object_type(data, &sub_package,
- ACPI_RTYPE_PACKAGE, i);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- /* Examine the different types of expected sub-packages */
-
- data->parent_package = sub_package;
- switch (package->ret_info.type) {
- case ACPI_PTYPE2:
- case ACPI_PTYPE2_PKG_COUNT:
- case ACPI_PTYPE2_REV_FIXED:
-
- /* Each subpackage has a fixed number of elements */
-
- expected_count =
- package->ret_info.count1 + package->ret_info.count2;
- if (sub_package->package.count < expected_count) {
- goto package_too_small;
- }
-
- status =
- acpi_ns_check_package_elements(data, sub_elements,
- package->ret_info.
- object_type1,
- package->ret_info.
- count1,
- package->ret_info.
- object_type2,
- package->ret_info.
- count2, 0);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- break;
-
- case ACPI_PTYPE2_FIX_VAR:
- /*
- * Each subpackage has a fixed number of elements and an
- * optional element
- */
- expected_count =
- package->ret_info.count1 + package->ret_info.count2;
- if (sub_package->package.count < expected_count) {
- goto package_too_small;
- }
-
- status =
- acpi_ns_check_package_elements(data, sub_elements,
- package->ret_info.
- object_type1,
- package->ret_info.
- count1,
- package->ret_info.
- object_type2,
- sub_package->package.
- count -
- package->ret_info.
- count1, 0);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- break;
-
- case ACPI_PTYPE2_FIXED:
-
- /* Each sub-package has a fixed length */
-
- expected_count = package->ret_info2.count;
- if (sub_package->package.count < expected_count) {
- goto package_too_small;
- }
-
- /* Check the type of each sub-package element */
-
- for (j = 0; j < expected_count; j++) {
- status =
- acpi_ns_check_object_type(data,
- &sub_elements[j],
- package->
- ret_info2.
- object_type[j],
- j);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- }
- break;
-
- case ACPI_PTYPE2_MIN:
-
- /* Each sub-package has a variable but minimum length */
-
- expected_count = package->ret_info.count1;
- if (sub_package->package.count < expected_count) {
- goto package_too_small;
- }
-
- /* Check the type of each sub-package element */
-
- status =
- acpi_ns_check_package_elements(data, sub_elements,
- package->ret_info.
- object_type1,
- sub_package->package.
- count, 0, 0, 0);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- break;
-
- case ACPI_PTYPE2_COUNT:
-
- /*
- * First element is the (Integer) count of elements, including
- * the count field (the ACPI name is num_elements)
- */
- status = acpi_ns_check_object_type(data, sub_elements,
- ACPI_RTYPE_INTEGER,
- 0);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- /*
- * Make sure package is large enough for the Count and is
- * is as large as the minimum size
- */
- expected_count = (u32)(*sub_elements)->integer.value;
- if (sub_package->package.count < expected_count) {
- goto package_too_small;
- }
- if (sub_package->package.count <
- package->ret_info.count1) {
- expected_count = package->ret_info.count1;
- goto package_too_small;
- }
- if (expected_count == 0) {
- /*
- * Either the num_entries element was originally zero or it was
- * a NULL element and repaired to an Integer of value zero.
- * In either case, repair it by setting num_entries to be the
- * actual size of the subpackage.
- */
- expected_count = sub_package->package.count;
- (*sub_elements)->integer.value = expected_count;
- }
-
- /* Check the type of each sub-package element */
-
- status =
- acpi_ns_check_package_elements(data,
- (sub_elements + 1),
- package->ret_info.
- object_type1,
- (expected_count - 1),
- 0, 0, 1);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- break;
-
- default: /* Should not get here, type was validated by caller */
-
- return (AE_AML_INTERNAL);
- }
-
- elements++;
- }
-
- return (AE_OK);
-
-package_too_small:
-
- /* The sub-package count was smaller than required */
-
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
- "Return Sub-Package[%u] is too small - found %u elements, expected %u",
- i, sub_package->package.count, expected_count));
-
- return (AE_AML_OPERAND_VALUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_check_package_elements
- *
- * PARAMETERS: data - Pointer to validation data structure
- * elements - Pointer to the package elements array
- * type1 - Object type for first group
- * count1 - Count for first group
- * type2 - Object type for second group
- * count2 - Count for second group
- * start_index - Start of the first group of elements
- *
- * RETURN: Status
- *
- * DESCRIPTION: Check that all elements of a package are of the correct object
- * type. Supports up to two groups of different object types.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ns_check_package_elements(struct acpi_predefined_data *data,
- union acpi_operand_object **elements,
- u8 type1,
- u32 count1,
- u8 type2, u32 count2, u32 start_index)
-{
- union acpi_operand_object **this_element = elements;
- acpi_status status;
- u32 i;
-
- /*
- * Up to two groups of package elements are supported by the data
- * structure. All elements in each group must be of the same type.
- * The second group can have a count of zero.
- */
- for (i = 0; i < count1; i++) {
- status = acpi_ns_check_object_type(data, this_element,
- type1, i + start_index);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- this_element++;
- }
-
- for (i = 0; i < count2; i++) {
- status = acpi_ns_check_object_type(data, this_element,
- type2,
- (i + count1 + start_index));
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- this_element++;
- }
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ns_check_object_type
*
* PARAMETERS: data - Pointer to validation data structure
@@ -983,7 +403,7 @@ acpi_ns_check_package_elements(struct acpi_predefined_data *data,
*
******************************************************************************/
-static acpi_status
+acpi_status
acpi_ns_check_object_type(struct acpi_predefined_data *data,
union acpi_operand_object **return_object_ptr,
u32 expected_btypes, u32 package_index)
diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c
new file mode 100644
index 000000000000..a40155467d2e
--- /dev/null
+++ b/drivers/acpi/acpica/nsprepkg.c
@@ -0,0 +1,621 @@
+/******************************************************************************
+ *
+ * Module Name: nsprepkg - Validation of package objects for predefined names
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acpredef.h"
+
+#define _COMPONENT ACPI_NAMESPACE
+ACPI_MODULE_NAME("nsprepkg")
+
+/* Local prototypes */
+static acpi_status
+acpi_ns_check_package_list(struct acpi_predefined_data *data,
+ const union acpi_predefined_info *package,
+ union acpi_operand_object **elements, u32 count);
+
+static acpi_status
+acpi_ns_check_package_elements(struct acpi_predefined_data *data,
+ union acpi_operand_object **elements,
+ u8 type1,
+ u32 count1,
+ u8 type2, u32 count2, u32 start_index);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_package
+ *
+ * PARAMETERS: data - Pointer to validation data structure
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check a returned package object for the correct count and
+ * correct type of all sub-objects.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_check_package(struct acpi_predefined_data *data,
+ union acpi_operand_object **return_object_ptr)
+{
+ union acpi_operand_object *return_object = *return_object_ptr;
+ const union acpi_predefined_info *package;
+ union acpi_operand_object **elements;
+ acpi_status status = AE_OK;
+ u32 expected_count;
+ u32 count;
+ u32 i;
+
+ ACPI_FUNCTION_NAME(ns_check_package);
+
+ /* The package info for this name is in the next table entry */
+
+ package = data->predefined + 1;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
+ "%s Validating return Package of Type %X, Count %X\n",
+ data->pathname, package->ret_info.type,
+ return_object->package.count));
+
+ /*
+ * For variable-length Packages, we can safely remove all embedded
+ * and trailing NULL package elements
+ */
+ acpi_ns_remove_null_elements(data, package->ret_info.type,
+ return_object);
+
+ /* Extract package count and elements array */
+
+ elements = return_object->package.elements;
+ count = return_object->package.count;
+
+ /* The package must have at least one element, else invalid */
+
+ if (!count) {
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return Package has no elements (empty)"));
+
+ return (AE_AML_OPERAND_VALUE);
+ }
+
+ /*
+ * Decode the type of the expected package contents
+ *
+ * PTYPE1 packages contain no subpackages
+ * PTYPE2 packages contain sub-packages
+ */
+ switch (package->ret_info.type) {
+ case ACPI_PTYPE1_FIXED:
+
+ /*
+ * The package count is fixed and there are no sub-packages
+ *
+ * If package is too small, exit.
+ * If package is larger than expected, issue warning but continue
+ */
+ expected_count =
+ package->ret_info.count1 + package->ret_info.count2;
+ if (count < expected_count) {
+ goto package_too_small;
+ } else if (count > expected_count) {
+ ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
+ "%s: Return Package is larger than needed - "
+ "found %u, expected %u\n",
+ data->pathname, count,
+ expected_count));
+ }
+
+ /* Validate all elements of the returned package */
+
+ status = acpi_ns_check_package_elements(data, elements,
+ package->ret_info.
+ object_type1,
+ package->ret_info.
+ count1,
+ package->ret_info.
+ object_type2,
+ package->ret_info.
+ count2, 0);
+ break;
+
+ case ACPI_PTYPE1_VAR:
+
+ /*
+ * The package count is variable, there are no sub-packages, and all
+ * elements must be of the same type
+ */
+ for (i = 0; i < count; i++) {
+ status = acpi_ns_check_object_type(data, elements,
+ package->ret_info.
+ object_type1, i);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ elements++;
+ }
+ break;
+
+ case ACPI_PTYPE1_OPTION:
+
+ /*
+ * The package count is variable, there are no sub-packages. There are
+ * a fixed number of required elements, and a variable number of
+ * optional elements.
+ *
+ * Check if package is at least as large as the minimum required
+ */
+ expected_count = package->ret_info3.count;
+ if (count < expected_count) {
+ goto package_too_small;
+ }
+
+ /* Variable number of sub-objects */
+
+ for (i = 0; i < count; i++) {
+ if (i < package->ret_info3.count) {
+
+ /* These are the required package elements (0, 1, or 2) */
+
+ status =
+ acpi_ns_check_object_type(data, elements,
+ package->
+ ret_info3.
+ object_type[i],
+ i);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ } else {
+ /* These are the optional package elements */
+
+ status =
+ acpi_ns_check_object_type(data, elements,
+ package->
+ ret_info3.
+ tail_object_type,
+ i);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+ elements++;
+ }
+ break;
+
+ case ACPI_PTYPE2_REV_FIXED:
+
+ /* First element is the (Integer) revision */
+
+ status = acpi_ns_check_object_type(data, elements,
+ ACPI_RTYPE_INTEGER, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ elements++;
+ count--;
+
+ /* Examine the sub-packages */
+
+ status =
+ acpi_ns_check_package_list(data, package, elements, count);
+ break;
+
+ case ACPI_PTYPE2_PKG_COUNT:
+
+ /* First element is the (Integer) count of sub-packages to follow */
+
+ status = acpi_ns_check_object_type(data, elements,
+ ACPI_RTYPE_INTEGER, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /*
+ * Count cannot be larger than the parent package length, but allow it
+ * to be smaller. The >= accounts for the Integer above.
+ */
+ expected_count = (u32)(*elements)->integer.value;
+ if (expected_count >= count) {
+ goto package_too_small;
+ }
+
+ count = expected_count;
+ elements++;
+
+ /* Examine the sub-packages */
+
+ status =
+ acpi_ns_check_package_list(data, package, elements, count);
+ break;
+
+ case ACPI_PTYPE2:
+ case ACPI_PTYPE2_FIXED:
+ case ACPI_PTYPE2_MIN:
+ case ACPI_PTYPE2_COUNT:
+ case ACPI_PTYPE2_FIX_VAR:
+
+ /*
+ * These types all return a single Package that consists of a
+ * variable number of sub-Packages.
+ *
+ * First, ensure that the first element is a sub-Package. If not,
+ * the BIOS may have incorrectly returned the object as a single
+ * package instead of a Package of Packages (a common error if
+ * there is only one entry). We may be able to repair this by
+ * wrapping the returned Package with a new outer Package.
+ */
+ if (*elements
+ && ((*elements)->common.type != ACPI_TYPE_PACKAGE)) {
+
+ /* Create the new outer package and populate it */
+
+ status =
+ acpi_ns_wrap_with_package(data, return_object,
+ return_object_ptr);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Update locals to point to the new package (of 1 element) */
+
+ return_object = *return_object_ptr;
+ elements = return_object->package.elements;
+ count = 1;
+ }
+
+ /* Examine the sub-packages */
+
+ status =
+ acpi_ns_check_package_list(data, package, elements, count);
+ break;
+
+ default:
+
+ /* Should not get here if predefined info table is correct */
+
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Invalid internal return type in table entry: %X",
+ package->ret_info.type));
+
+ return (AE_AML_INTERNAL);
+ }
+
+ return (status);
+
+ package_too_small:
+
+ /* Error exit for the case with an incorrect package count */
+
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return Package is too small - found %u elements, expected %u",
+ count, expected_count));
+
+ return (AE_AML_OPERAND_VALUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_package_list
+ *
+ * PARAMETERS: data - Pointer to validation data structure
+ * package - Pointer to package-specific info for method
+ * elements - Element list of parent package. All elements
+ * of this list should be of type Package.
+ * count - Count of subpackages
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Examine a list of subpackages
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_check_package_list(struct acpi_predefined_data *data,
+ const union acpi_predefined_info *package,
+ union acpi_operand_object **elements, u32 count)
+{
+ union acpi_operand_object *sub_package;
+ union acpi_operand_object **sub_elements;
+ acpi_status status;
+ u32 expected_count;
+ u32 i;
+ u32 j;
+
+ /*
+ * Validate each sub-Package in the parent Package
+ *
+ * NOTE: assumes list of sub-packages contains no NULL elements.
+ * Any NULL elements should have been removed by earlier call
+ * to acpi_ns_remove_null_elements.
+ */
+ for (i = 0; i < count; i++) {
+ sub_package = *elements;
+ sub_elements = sub_package->package.elements;
+ data->parent_package = sub_package;
+
+ /* Each sub-object must be of type Package */
+
+ status = acpi_ns_check_object_type(data, &sub_package,
+ ACPI_RTYPE_PACKAGE, i);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Examine the different types of expected sub-packages */
+
+ data->parent_package = sub_package;
+ switch (package->ret_info.type) {
+ case ACPI_PTYPE2:
+ case ACPI_PTYPE2_PKG_COUNT:
+ case ACPI_PTYPE2_REV_FIXED:
+
+ /* Each subpackage has a fixed number of elements */
+
+ expected_count =
+ package->ret_info.count1 + package->ret_info.count2;
+ if (sub_package->package.count < expected_count) {
+ goto package_too_small;
+ }
+
+ status =
+ acpi_ns_check_package_elements(data, sub_elements,
+ package->ret_info.
+ object_type1,
+ package->ret_info.
+ count1,
+ package->ret_info.
+ object_type2,
+ package->ret_info.
+ count2, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ case ACPI_PTYPE2_FIX_VAR:
+ /*
+ * Each subpackage has a fixed number of elements and an
+ * optional element
+ */
+ expected_count =
+ package->ret_info.count1 + package->ret_info.count2;
+ if (sub_package->package.count < expected_count) {
+ goto package_too_small;
+ }
+
+ status =
+ acpi_ns_check_package_elements(data, sub_elements,
+ package->ret_info.
+ object_type1,
+ package->ret_info.
+ count1,
+ package->ret_info.
+ object_type2,
+ sub_package->package.
+ count -
+ package->ret_info.
+ count1, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ case ACPI_PTYPE2_FIXED:
+
+ /* Each sub-package has a fixed length */
+
+ expected_count = package->ret_info2.count;
+ if (sub_package->package.count < expected_count) {
+ goto package_too_small;
+ }
+
+ /* Check the type of each sub-package element */
+
+ for (j = 0; j < expected_count; j++) {
+ status =
+ acpi_ns_check_object_type(data,
+ &sub_elements[j],
+ package->
+ ret_info2.
+ object_type[j],
+ j);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+ break;
+
+ case ACPI_PTYPE2_MIN:
+
+ /* Each sub-package has a variable but minimum length */
+
+ expected_count = package->ret_info.count1;
+ if (sub_package->package.count < expected_count) {
+ goto package_too_small;
+ }
+
+ /* Check the type of each sub-package element */
+
+ status =
+ acpi_ns_check_package_elements(data, sub_elements,
+ package->ret_info.
+ object_type1,
+ sub_package->package.
+ count, 0, 0, 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ case ACPI_PTYPE2_COUNT:
+
+ /*
+ * First element is the (Integer) count of elements, including
+ * the count field (the ACPI name is num_elements)
+ */
+ status = acpi_ns_check_object_type(data, sub_elements,
+ ACPI_RTYPE_INTEGER,
+ 0);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /*
+ * Make sure package is large enough for the Count and is
+ * is as large as the minimum size
+ */
+ expected_count = (u32)(*sub_elements)->integer.value;
+ if (sub_package->package.count < expected_count) {
+ goto package_too_small;
+ }
+ if (sub_package->package.count <
+ package->ret_info.count1) {
+ expected_count = package->ret_info.count1;
+ goto package_too_small;
+ }
+ if (expected_count == 0) {
+ /*
+ * Either the num_entries element was originally zero or it was
+ * a NULL element and repaired to an Integer of value zero.
+ * In either case, repair it by setting num_entries to be the
+ * actual size of the subpackage.
+ */
+ expected_count = sub_package->package.count;
+ (*sub_elements)->integer.value = expected_count;
+ }
+
+ /* Check the type of each sub-package element */
+
+ status =
+ acpi_ns_check_package_elements(data,
+ (sub_elements + 1),
+ package->ret_info.
+ object_type1,
+ (expected_count - 1),
+ 0, 0, 1);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ default: /* Should not get here, type was validated by caller */
+
+ return (AE_AML_INTERNAL);
+ }
+
+ elements++;
+ }
+
+ return (AE_OK);
+
+ package_too_small:
+
+ /* The sub-package count was smaller than required */
+
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Return Sub-Package[%u] is too small - found %u elements, expected %u",
+ i, sub_package->package.count, expected_count));
+
+ return (AE_AML_OPERAND_VALUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_package_elements
+ *
+ * PARAMETERS: data - Pointer to validation data structure
+ * elements - Pointer to the package elements array
+ * type1 - Object type for first group
+ * count1 - Count for first group
+ * type2 - Object type for second group
+ * count2 - Count for second group
+ * start_index - Start of the first group of elements
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check that all elements of a package are of the correct object
+ * type. Supports up to two groups of different object types.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_check_package_elements(struct acpi_predefined_data *data,
+ union acpi_operand_object **elements,
+ u8 type1,
+ u32 count1,
+ u8 type2, u32 count2, u32 start_index)
+{
+ union acpi_operand_object **this_element = elements;
+ acpi_status status;
+ u32 i;
+
+ /*
+ * Up to two groups of package elements are supported by the data
+ * structure. All elements in each group must be of the same type.
+ * The second group can have a count of zero.
+ */
+ for (i = 0; i < count1; i++) {
+ status = acpi_ns_check_object_type(data, this_element,
+ type1, i + start_index);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ this_element++;
+ }
+
+ for (i = 0; i < count2; i++) {
+ status = acpi_ns_check_object_type(data, this_element,
+ type2,
+ (i + count1 + start_index));
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ this_element++;
+ }
+
+ return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index 8c5f292860fc..9e833353c06a 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 90189251cdf0..ba4d98287c6a 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,7 +55,8 @@ ACPI_MODULE_NAME("nsrepair2")
*/
typedef
acpi_status(*acpi_repair_function) (struct acpi_predefined_data *data,
- union acpi_operand_object **return_object_ptr);
+ union acpi_operand_object
+ **return_object_ptr);
typedef struct acpi_repair_info {
char name[ACPI_NAME_SIZE];
diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c
index 1d2d8ffc1bc5..5d43efc53a61 100644
--- a/drivers/acpi/acpica/nssearch.c
+++ b/drivers/acpi/acpica/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -328,6 +328,11 @@ acpi_ns_search_and_enter(u32 target_name,
if ((status == AE_OK) && (flags & ACPI_NS_ERROR_IF_FOUND)) {
status = AE_ALREADY_EXISTS;
}
+#ifdef ACPI_ASL_COMPILER
+ if (*return_node && (*return_node)->type == ACPI_TYPE_ANY) {
+ (*return_node)->flags |= ANOBJ_IS_EXTERNAL;
+ }
+#endif
/* Either found it or there was an error: finished either way */
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index b5b4cb72a8a8..686420df684f 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,14 +46,11 @@
#include "accommon.h"
#include "acnamesp.h"
#include "amlcode.h"
-#include "actables.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsutils")
/* Local prototypes */
-static u8 acpi_ns_valid_path_separator(char sep);
-
#ifdef ACPI_OBSOLETE_FUNCTIONS
acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node *node_to_search);
#endif
@@ -99,42 +96,6 @@ acpi_ns_print_node_pathname(struct acpi_namespace_node *node,
/*******************************************************************************
*
- * FUNCTION: acpi_ns_valid_root_prefix
- *
- * PARAMETERS: prefix - Character to be checked
- *
- * RETURN: TRUE if a valid prefix
- *
- * DESCRIPTION: Check if a character is a valid ACPI Root prefix
- *
- ******************************************************************************/
-
-u8 acpi_ns_valid_root_prefix(char prefix)
-{
-
- return ((u8) (prefix == '\\'));
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_valid_path_separator
- *
- * PARAMETERS: sep - Character to be checked
- *
- * RETURN: TRUE if a valid path separator
- *
- * DESCRIPTION: Check if a character is a valid ACPI path separator
- *
- ******************************************************************************/
-
-static u8 acpi_ns_valid_path_separator(char sep)
-{
-
- return ((u8) (sep == '.'));
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ns_get_type
*
* PARAMETERS: node - Parent Node to be examined
@@ -151,10 +112,10 @@ acpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node)
if (!node) {
ACPI_WARNING((AE_INFO, "Null Node parameter"));
- return_UINT32(ACPI_TYPE_ANY);
+ return_VALUE(ACPI_TYPE_ANY);
}
- return_UINT32((acpi_object_type) node->type);
+ return_VALUE(node->type);
}
/*******************************************************************************
@@ -179,10 +140,10 @@ u32 acpi_ns_local(acpi_object_type type)
/* Type code out of range */
ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type));
- return_UINT32(ACPI_NS_NORMAL);
+ return_VALUE(ACPI_NS_NORMAL);
}
- return_UINT32((u32) acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);
+ return_VALUE(acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);
}
/*******************************************************************************
@@ -218,19 +179,19 @@ void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info)
*
* strlen() + 1 covers the first name_seg, which has no path separator
*/
- if (acpi_ns_valid_root_prefix(*next_external_char)) {
+ if (ACPI_IS_ROOT_PREFIX(*next_external_char)) {
info->fully_qualified = TRUE;
next_external_char++;
/* Skip redundant root_prefix, like \\_SB.PCI0.SBRG.EC0 */
- while (acpi_ns_valid_root_prefix(*next_external_char)) {
+ while (ACPI_IS_ROOT_PREFIX(*next_external_char)) {
next_external_char++;
}
} else {
/* Handle Carat prefixes */
- while (*next_external_char == '^') {
+ while (ACPI_IS_PARENT_PREFIX(*next_external_char)) {
info->num_carats++;
next_external_char++;
}
@@ -244,7 +205,7 @@ void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info)
if (*next_external_char) {
info->num_segments = 1;
for (i = 0; next_external_char[i]; i++) {
- if (acpi_ns_valid_path_separator(next_external_char[i])) {
+ if (ACPI_IS_PATH_SEPARATOR(next_external_char[i])) {
info->num_segments++;
}
}
@@ -282,7 +243,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)
/* Setup the correct prefixes, counts, and pointers */
if (info->fully_qualified) {
- internal_name[0] = '\\';
+ internal_name[0] = AML_ROOT_PREFIX;
if (num_segments <= 1) {
result = &internal_name[1];
@@ -302,7 +263,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)
i = 0;
if (info->num_carats) {
for (i = 0; i < info->num_carats; i++) {
- internal_name[i] = '^';
+ internal_name[i] = AML_PARENT_PREFIX;
}
}
@@ -322,7 +283,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)
for (; num_segments; num_segments--) {
for (i = 0; i < ACPI_NAME_SIZE; i++) {
- if (acpi_ns_valid_path_separator(*external_name) ||
+ if (ACPI_IS_PATH_SEPARATOR(*external_name) ||
(*external_name == 0)) {
/* Pad the segment with underscore(s) if segment is short */
@@ -339,7 +300,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)
/* Now we must have a path separator, or the pathname is bad */
- if (!acpi_ns_valid_path_separator(*external_name) &&
+ if (!ACPI_IS_PATH_SEPARATOR(*external_name) &&
(*external_name != 0)) {
return_ACPI_STATUS(AE_BAD_PATHNAME);
}
@@ -457,13 +418,13 @@ acpi_ns_externalize_name(u32 internal_name_length,
/* Check for a prefix (one '\' | one or more '^') */
switch (internal_name[0]) {
- case '\\':
+ case AML_ROOT_PREFIX:
prefix_length = 1;
break;
- case '^':
+ case AML_PARENT_PREFIX:
for (i = 0; i < internal_name_length; i++) {
- if (internal_name[i] == '^') {
+ if (ACPI_IS_PARENT_PREFIX(internal_name[i])) {
prefix_length = i + 1;
} else {
break;
@@ -664,17 +625,17 @@ void acpi_ns_terminate(void)
u32 acpi_ns_opens_scope(acpi_object_type type)
{
- ACPI_FUNCTION_TRACE_STR(ns_opens_scope, acpi_ut_get_type_name(type));
+ ACPI_FUNCTION_ENTRY();
- if (!acpi_ut_valid_object_type(type)) {
+ if (type > ACPI_TYPE_LOCAL_MAX) {
/* type code out of range */
ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type));
- return_UINT32(ACPI_NS_NORMAL);
+ return (ACPI_NS_NORMAL);
}
- return_UINT32(((u32) acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE);
+ return (((u32)acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE);
}
/*******************************************************************************
@@ -710,6 +671,8 @@ acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
ACPI_FUNCTION_TRACE_PTR(ns_get_node, ACPI_CAST_PTR(char, pathname));
+ /* Simplest case is a null pathname */
+
if (!pathname) {
*return_node = prefix_node;
if (!prefix_node) {
@@ -718,6 +681,13 @@ acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
return_ACPI_STATUS(AE_OK);
}
+ /* Quick check for a reference to the root */
+
+ if (ACPI_IS_ROOT_PREFIX(pathname[0]) && (!pathname[1])) {
+ *return_node = acpi_gbl_root_node;
+ return_ACPI_STATUS(AE_OK);
+ }
+
/* Convert path to internal representation */
status = acpi_ns_internalize_name(pathname, &internal_path);
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index 0483877f26b8..e70911a9e441 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -76,12 +76,12 @@ struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
/* It's really the parent's _scope_ that we want */
- return parent_node->child;
+ return (parent_node->child);
}
/* Otherwise just return the next peer */
- return child_node->peer;
+ return (child_node->peer);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index d6a9f77972b6..fc69949151bb 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -236,7 +236,7 @@ acpi_evaluate_object(acpi_handle handle,
* 2) No handle, not fully qualified pathname (error)
* 3) Valid handle
*/
- if ((pathname) && (acpi_ns_valid_root_prefix(pathname[0]))) {
+ if ((pathname) && (ACPI_IS_ROOT_PREFIX(pathname[0]))) {
/* The path is fully qualified, just evaluate by name */
@@ -492,7 +492,7 @@ acpi_walk_namespace(acpi_object_type type,
*/
status = acpi_ut_acquire_read_lock(&acpi_gbl_namespace_rw_lock);
if (ACPI_FAILURE(status)) {
- return status;
+ return_ACPI_STATUS(status);
}
/*
@@ -550,7 +550,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ return (status);
}
node = acpi_ns_validate_handle(obj_handle);
@@ -602,17 +602,22 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
/* Walk the CID list */
- found = 0;
+ found = FALSE;
for (i = 0; i < cid->count; i++) {
if (ACPI_STRCMP(cid->ids[i].string, info->hid)
== 0) {
- found = 1;
+
+ /* Found a matching CID */
+
+ found = TRUE;
break;
}
}
+
ACPI_FREE(cid);
- if (!found)
+ if (!found) {
return (AE_OK);
+ }
}
}
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index 811c6f13f476..f3a4d95899f7 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -107,7 +107,7 @@ acpi_get_handle(acpi_handle parent,
*
* Error for <null Parent + relative path>
*/
- if (acpi_ns_valid_root_prefix(pathname[0])) {
+ if (ACPI_IS_ROOT_PREFIX(pathname[0])) {
/* Pathname is fully qualified (starts with '\') */
@@ -290,7 +290,7 @@ acpi_get_object_info(acpi_handle handle,
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
- goto cleanup;
+ return (status);
}
node = acpi_ns_validate_handle(handle);
@@ -539,14 +539,14 @@ acpi_status acpi_install_method(u8 *buffer)
/* Parameter validation */
if (!buffer) {
- return AE_BAD_PARAMETER;
+ return (AE_BAD_PARAMETER);
}
/* Table must be a DSDT or SSDT */
if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) &&
!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) {
- return AE_BAD_HEADER;
+ return (AE_BAD_HEADER);
}
/* First AML opcode in the table must be a control method */
@@ -554,7 +554,7 @@ acpi_status acpi_install_method(u8 *buffer)
parser_state.aml = buffer + sizeof(struct acpi_table_header);
opcode = acpi_ps_peek_opcode(&parser_state);
if (opcode != AML_METHOD_OP) {
- return AE_BAD_PARAMETER;
+ return (AE_BAD_PARAMETER);
}
/* Extract method information from the raw AML */
@@ -572,13 +572,13 @@ acpi_status acpi_install_method(u8 *buffer)
*/
aml_buffer = ACPI_ALLOCATE(aml_length);
if (!aml_buffer) {
- return AE_NO_MEMORY;
+ return (AE_NO_MEMORY);
}
method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
if (!method_obj) {
ACPI_FREE(aml_buffer);
- return AE_NO_MEMORY;
+ return (AE_NO_MEMORY);
}
/* Lock namespace for acpi_ns_lookup, we may be creating a new node */
@@ -644,12 +644,12 @@ acpi_status acpi_install_method(u8 *buffer)
/* Remove local reference to the method object */
acpi_ut_remove_reference(method_obj);
- return status;
+ return (status);
error_exit:
ACPI_FREE(aml_buffer);
ACPI_FREE(method_obj);
- return status;
+ return (status);
}
ACPI_EXPORT_SYMBOL(acpi_install_method)
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c
index 9d029dac6b64..c0853ef294e4 100644
--- a/drivers/acpi/acpica/nsxfobj.c
+++ b/drivers/acpi/acpica/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index cb79e2d4d743..f51308cdbc65 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -108,7 +108,7 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state)
/* Byte 0 is a special case, either bits [0:3] or [0:5] are used */
package_length |= (aml[0] & byte_zero_mask);
- return_UINT32(package_length);
+ return_VALUE(package_length);
}
/*******************************************************************************
@@ -162,7 +162,7 @@ char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state)
/* Point past any namestring prefix characters (backslash or carat) */
- while (acpi_ps_is_prefix_char(*end)) {
+ while (ACPI_IS_ROOT_PREFIX(*end) || ACPI_IS_PARENT_PREFIX(*end)) {
end++;
}
@@ -798,7 +798,8 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
subop = acpi_ps_peek_opcode(parser_state);
if (subop == 0 ||
acpi_ps_is_leading_char(subop) ||
- acpi_ps_is_prefix_char(subop)) {
+ ACPI_IS_ROOT_PREFIX(subop) ||
+ ACPI_IS_PARENT_PREFIX(subop)) {
/* null_name or name_string */
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index 5607805aab26..63c455447481 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -58,352 +58,17 @@
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psloop")
-static u32 acpi_gbl_depth = 0;
-
/* Local prototypes */
-
-static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state);
-
-static acpi_status
-acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
- u8 * aml_op_start,
- union acpi_parse_object *unnamed_op,
- union acpi_parse_object **op);
-
-static acpi_status
-acpi_ps_create_op(struct acpi_walk_state *walk_state,
- u8 * aml_op_start, union acpi_parse_object **new_op);
-
static acpi_status
acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
u8 * aml_op_start, union acpi_parse_object *op);
-static acpi_status
-acpi_ps_complete_op(struct acpi_walk_state *walk_state,
- union acpi_parse_object **op, acpi_status status);
-
-static acpi_status
-acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
- union acpi_parse_object *op, acpi_status status);
-
static void
acpi_ps_link_module_code(union acpi_parse_object *parent_op,
u8 *aml_start, u32 aml_length, acpi_owner_id owner_id);
/*******************************************************************************
*
- * FUNCTION: acpi_ps_get_aml_opcode
- *
- * PARAMETERS: walk_state - Current state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Extract the next AML opcode from the input stream.
- *
- ******************************************************************************/
-
-static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state)
-{
-
- ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state);
-
- walk_state->aml_offset =
- (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
- walk_state->parser_state.aml_start);
- walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state));
-
- /*
- * First cut to determine what we have found:
- * 1) A valid AML opcode
- * 2) A name string
- * 3) An unknown/invalid opcode
- */
- walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
-
- switch (walk_state->op_info->class) {
- case AML_CLASS_ASCII:
- case AML_CLASS_PREFIX:
- /*
- * Starts with a valid prefix or ASCII char, this is a name
- * string. Convert the bare name string to a namepath.
- */
- walk_state->opcode = AML_INT_NAMEPATH_OP;
- walk_state->arg_types = ARGP_NAMESTRING;
- break;
-
- case AML_CLASS_UNKNOWN:
-
- /* The opcode is unrecognized. Complain and skip unknown opcodes */
-
- if (walk_state->pass_number == 2) {
- ACPI_ERROR((AE_INFO,
- "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring",
- walk_state->opcode,
- (u32)(walk_state->aml_offset +
- sizeof(struct acpi_table_header))));
-
- ACPI_DUMP_BUFFER(walk_state->parser_state.aml - 16, 48);
-
-#ifdef ACPI_ASL_COMPILER
- /*
- * This is executed for the disassembler only. Output goes
- * to the disassembled ASL output file.
- */
- acpi_os_printf
- ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n",
- walk_state->opcode,
- (u32)(walk_state->aml_offset +
- sizeof(struct acpi_table_header)));
-
- /* Dump the context surrounding the invalid opcode */
-
- acpi_ut_dump_buffer(((u8 *)walk_state->parser_state.
- aml - 16), 48, DB_BYTE_DISPLAY,
- walk_state->aml_offset +
- sizeof(struct acpi_table_header) -
- 16);
- acpi_os_printf(" */\n");
-#endif
- }
-
- /* Increment past one-byte or two-byte opcode */
-
- walk_state->parser_state.aml++;
- if (walk_state->opcode > 0xFF) { /* Can only happen if first byte is 0x5B */
- walk_state->parser_state.aml++;
- }
-
- return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
-
- default:
-
- /* Found opcode info, this is a normal opcode */
-
- walk_state->parser_state.aml +=
- acpi_ps_get_opcode_size(walk_state->opcode);
- walk_state->arg_types = walk_state->op_info->parse_args;
- break;
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_build_named_op
- *
- * PARAMETERS: walk_state - Current state
- * aml_op_start - Begin of named Op in AML
- * unnamed_op - Early Op (not a named Op)
- * op - Returned Op
- *
- * RETURN: Status
- *
- * DESCRIPTION: Parse a named Op
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
- u8 * aml_op_start,
- union acpi_parse_object *unnamed_op,
- union acpi_parse_object **op)
-{
- acpi_status status = AE_OK;
- union acpi_parse_object *arg = NULL;
-
- ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
-
- unnamed_op->common.value.arg = NULL;
- unnamed_op->common.arg_list_length = 0;
- unnamed_op->common.aml_opcode = walk_state->opcode;
-
- /*
- * Get and append arguments until we find the node that contains
- * the name (the type ARGP_NAME).
- */
- while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
- (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) {
- status =
- acpi_ps_get_next_arg(walk_state,
- &(walk_state->parser_state),
- GET_CURRENT_ARG_TYPE(walk_state->
- arg_types), &arg);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- acpi_ps_append_arg(unnamed_op, arg);
- INCREMENT_ARG_LIST(walk_state->arg_types);
- }
-
- /*
- * Make sure that we found a NAME and didn't run out of arguments
- */
- if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) {
- return_ACPI_STATUS(AE_AML_NO_OPERAND);
- }
-
- /* We know that this arg is a name, move to next arg */
-
- INCREMENT_ARG_LIST(walk_state->arg_types);
-
- /*
- * Find the object. This will either insert the object into
- * the namespace or simply look it up
- */
- walk_state->op = NULL;
-
- status = walk_state->descending_callback(walk_state, op);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
- return_ACPI_STATUS(status);
- }
-
- if (!*op) {
- return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
- }
-
- status = acpi_ps_next_parse_state(walk_state, *op, status);
- if (ACPI_FAILURE(status)) {
- if (status == AE_CTRL_PENDING) {
- return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
- }
- return_ACPI_STATUS(status);
- }
-
- acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
- acpi_gbl_depth++;
-
- if ((*op)->common.aml_opcode == AML_REGION_OP ||
- (*op)->common.aml_opcode == AML_DATA_REGION_OP) {
- /*
- * Defer final parsing of an operation_region body, because we don't
- * have enough info in the first pass to parse it correctly (i.e.,
- * there may be method calls within the term_arg elements of the body.)
- *
- * However, we must continue parsing because the opregion is not a
- * standalone package -- we don't know where the end is at this point.
- *
- * (Length is unknown until parse of the body complete)
- */
- (*op)->named.data = aml_op_start;
- (*op)->named.length = 0;
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_create_op
- *
- * PARAMETERS: walk_state - Current state
- * aml_op_start - Op start in AML
- * new_op - Returned Op
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get Op from AML
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ps_create_op(struct acpi_walk_state *walk_state,
- u8 * aml_op_start, union acpi_parse_object **new_op)
-{
- acpi_status status = AE_OK;
- union acpi_parse_object *op;
- union acpi_parse_object *named_op = NULL;
- union acpi_parse_object *parent_scope;
- u8 argument_count;
- const struct acpi_opcode_info *op_info;
-
- ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
-
- status = acpi_ps_get_aml_opcode(walk_state);
- if (status == AE_CTRL_PARSE_CONTINUE) {
- return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
- }
-
- /* Create Op structure and append to parent's argument list */
-
- walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
- op = acpi_ps_alloc_op(walk_state->opcode);
- if (!op) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- if (walk_state->op_info->flags & AML_NAMED) {
- status =
- acpi_ps_build_named_op(walk_state, aml_op_start, op,
- &named_op);
- acpi_ps_free_op(op);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- *new_op = named_op;
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Not a named opcode, just allocate Op and append to parent */
-
- if (walk_state->op_info->flags & AML_CREATE) {
- /*
- * Backup to beginning of create_XXXfield declaration
- * body_length is unknown until we parse the body
- */
- op->named.data = aml_op_start;
- op->named.length = 0;
- }
-
- if (walk_state->opcode == AML_BANK_FIELD_OP) {
- /*
- * Backup to beginning of bank_field declaration
- * body_length is unknown until we parse the body
- */
- op->named.data = aml_op_start;
- op->named.length = 0;
- }
-
- parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state));
- acpi_ps_append_arg(parent_scope, op);
-
- if (parent_scope) {
- op_info =
- acpi_ps_get_opcode_info(parent_scope->common.aml_opcode);
- if (op_info->flags & AML_HAS_TARGET) {
- argument_count =
- acpi_ps_get_argument_count(op_info->type);
- if (parent_scope->common.arg_list_length >
- argument_count) {
- op->common.flags |= ACPI_PARSEOP_TARGET;
- }
- } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) {
- op->common.flags |= ACPI_PARSEOP_TARGET;
- }
- }
-
- if (walk_state->descending_callback != NULL) {
- /*
- * Find the object. This will either insert the object into
- * the namespace or simply look it up
- */
- walk_state->op = *new_op = op;
-
- status = walk_state->descending_callback(walk_state, &op);
- status = acpi_ps_next_parse_state(walk_state, op, status);
- if (status == AE_CTRL_PENDING) {
- status = AE_CTRL_PARSE_PENDING;
- }
- }
-
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ps_get_arguments
*
* PARAMETERS: walk_state - Current state
@@ -711,288 +376,6 @@ acpi_ps_link_module_code(union acpi_parse_object *parent_op,
/*******************************************************************************
*
- * FUNCTION: acpi_ps_complete_op
- *
- * PARAMETERS: walk_state - Current state
- * op - Returned Op
- * status - Parse status before complete Op
- *
- * RETURN: Status
- *
- * DESCRIPTION: Complete Op
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ps_complete_op(struct acpi_walk_state *walk_state,
- union acpi_parse_object **op, acpi_status status)
-{
- acpi_status status2;
-
- ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state);
-
- /*
- * Finished one argument of the containing scope
- */
- walk_state->parser_state.scope->parse_scope.arg_count--;
-
- /* Close this Op (will result in parse subtree deletion) */
-
- status2 = acpi_ps_complete_this_op(walk_state, *op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
-
- *op = NULL;
-
- switch (status) {
- case AE_OK:
- break;
-
- case AE_CTRL_TRANSFER:
-
- /* We are about to transfer to a called method */
-
- walk_state->prev_op = NULL;
- walk_state->prev_arg_types = walk_state->arg_types;
- return_ACPI_STATUS(status);
-
- case AE_CTRL_END:
-
- acpi_ps_pop_scope(&(walk_state->parser_state), op,
- &walk_state->arg_types,
- &walk_state->arg_count);
-
- if (*op) {
- walk_state->op = *op;
- walk_state->op_info =
- acpi_ps_get_opcode_info((*op)->common.aml_opcode);
- walk_state->opcode = (*op)->common.aml_opcode;
-
- status = walk_state->ascending_callback(walk_state);
- status =
- acpi_ps_next_parse_state(walk_state, *op, status);
-
- status2 = acpi_ps_complete_this_op(walk_state, *op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- }
-
- status = AE_OK;
- break;
-
- case AE_CTRL_BREAK:
- case AE_CTRL_CONTINUE:
-
- /* Pop off scopes until we find the While */
-
- while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) {
- acpi_ps_pop_scope(&(walk_state->parser_state), op,
- &walk_state->arg_types,
- &walk_state->arg_count);
- }
-
- /* Close this iteration of the While loop */
-
- walk_state->op = *op;
- walk_state->op_info =
- acpi_ps_get_opcode_info((*op)->common.aml_opcode);
- walk_state->opcode = (*op)->common.aml_opcode;
-
- status = walk_state->ascending_callback(walk_state);
- status = acpi_ps_next_parse_state(walk_state, *op, status);
-
- status2 = acpi_ps_complete_this_op(walk_state, *op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
-
- status = AE_OK;
- break;
-
- case AE_CTRL_TERMINATE:
-
- /* Clean up */
- do {
- if (*op) {
- status2 =
- acpi_ps_complete_this_op(walk_state, *op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
-
- acpi_ut_delete_generic_state
- (acpi_ut_pop_generic_state
- (&walk_state->control_state));
- }
-
- acpi_ps_pop_scope(&(walk_state->parser_state), op,
- &walk_state->arg_types,
- &walk_state->arg_count);
-
- } while (*op);
-
- return_ACPI_STATUS(AE_OK);
-
- default: /* All other non-AE_OK status */
-
- do {
- if (*op) {
- status2 =
- acpi_ps_complete_this_op(walk_state, *op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- }
-
- acpi_ps_pop_scope(&(walk_state->parser_state), op,
- &walk_state->arg_types,
- &walk_state->arg_count);
-
- } while (*op);
-
-#if 0
- /*
- * TBD: Cleanup parse ops on error
- */
- if (*op == NULL) {
- acpi_ps_pop_scope(parser_state, op,
- &walk_state->arg_types,
- &walk_state->arg_count);
- }
-#endif
- walk_state->prev_op = NULL;
- walk_state->prev_arg_types = walk_state->arg_types;
- return_ACPI_STATUS(status);
- }
-
- /* This scope complete? */
-
- if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) {
- acpi_ps_pop_scope(&(walk_state->parser_state), op,
- &walk_state->arg_types,
- &walk_state->arg_count);
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op));
- } else {
- *op = NULL;
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_complete_final_op
- *
- * PARAMETERS: walk_state - Current state
- * op - Current Op
- * status - Current parse status before complete last
- * Op
- *
- * RETURN: Status
- *
- * DESCRIPTION: Complete last Op.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
- union acpi_parse_object *op, acpi_status status)
-{
- acpi_status status2;
-
- ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state);
-
- /*
- * Complete the last Op (if not completed), and clear the scope stack.
- * It is easily possible to end an AML "package" with an unbounded number
- * of open scopes (such as when several ASL blocks are closed with
- * sequential closing braces). We want to terminate each one cleanly.
- */
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
- op));
- do {
- if (op) {
- if (walk_state->ascending_callback != NULL) {
- walk_state->op = op;
- walk_state->op_info =
- acpi_ps_get_opcode_info(op->common.
- aml_opcode);
- walk_state->opcode = op->common.aml_opcode;
-
- status =
- walk_state->ascending_callback(walk_state);
- status =
- acpi_ps_next_parse_state(walk_state, op,
- status);
- if (status == AE_CTRL_PENDING) {
- status =
- acpi_ps_complete_op(walk_state, &op,
- AE_OK);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
- if (status == AE_CTRL_TERMINATE) {
- status = AE_OK;
-
- /* Clean up */
- do {
- if (op) {
- status2 =
- acpi_ps_complete_this_op
- (walk_state, op);
- if (ACPI_FAILURE
- (status2)) {
- return_ACPI_STATUS
- (status2);
- }
- }
-
- acpi_ps_pop_scope(&
- (walk_state->
- parser_state),
- &op,
- &walk_state->
- arg_types,
- &walk_state->
- arg_count);
-
- } while (op);
-
- return_ACPI_STATUS(status);
- }
-
- else if (ACPI_FAILURE(status)) {
-
- /* First error is most important */
-
- (void)
- acpi_ps_complete_this_op(walk_state,
- op);
- return_ACPI_STATUS(status);
- }
- }
-
- status2 = acpi_ps_complete_this_op(walk_state, op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- }
-
- acpi_ps_pop_scope(&(walk_state->parser_state), &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
-
- } while (op);
-
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ps_parse_loop
*
* PARAMETERS: walk_state - Current state
@@ -1177,10 +560,6 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
walk_state->op_info =
acpi_ps_get_opcode_info(op->common.aml_opcode);
if (walk_state->op_info->flags & AML_NAMED) {
- if (acpi_gbl_depth) {
- acpi_gbl_depth--;
- }
-
if (op->common.aml_opcode == AML_REGION_OP ||
op->common.aml_opcode == AML_DATA_REGION_OP) {
/*
diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c
new file mode 100644
index 000000000000..12c4028002b1
--- /dev/null
+++ b/drivers/acpi/acpica/psobject.c
@@ -0,0 +1,647 @@
+/******************************************************************************
+ *
+ * Module Name: psobject - Support for parse objects
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
+
+#define _COMPONENT ACPI_PARSER
+ACPI_MODULE_NAME("psobject")
+
+/* Local prototypes */
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_aml_opcode
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Extract the next AML opcode from the input stream.
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state)
+{
+
+ ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state);
+
+ walk_state->aml_offset =
+ (u32)ACPI_PTR_DIFF(walk_state->parser_state.aml,
+ walk_state->parser_state.aml_start);
+ walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state));
+
+ /*
+ * First cut to determine what we have found:
+ * 1) A valid AML opcode
+ * 2) A name string
+ * 3) An unknown/invalid opcode
+ */
+ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+
+ switch (walk_state->op_info->class) {
+ case AML_CLASS_ASCII:
+ case AML_CLASS_PREFIX:
+ /*
+ * Starts with a valid prefix or ASCII char, this is a name
+ * string. Convert the bare name string to a namepath.
+ */
+ walk_state->opcode = AML_INT_NAMEPATH_OP;
+ walk_state->arg_types = ARGP_NAMESTRING;
+ break;
+
+ case AML_CLASS_UNKNOWN:
+
+ /* The opcode is unrecognized. Complain and skip unknown opcodes */
+
+ if (walk_state->pass_number == 2) {
+ ACPI_ERROR((AE_INFO,
+ "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring",
+ walk_state->opcode,
+ (u32)(walk_state->aml_offset +
+ sizeof(struct acpi_table_header))));
+
+ ACPI_DUMP_BUFFER((walk_state->parser_state.aml - 16),
+ 48);
+
+#ifdef ACPI_ASL_COMPILER
+ /*
+ * This is executed for the disassembler only. Output goes
+ * to the disassembled ASL output file.
+ */
+ acpi_os_printf
+ ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n",
+ walk_state->opcode,
+ (u32)(walk_state->aml_offset +
+ sizeof(struct acpi_table_header)));
+
+ /* Dump the context surrounding the invalid opcode */
+
+ acpi_ut_dump_buffer(((u8 *)walk_state->parser_state.
+ aml - 16), 48, DB_BYTE_DISPLAY,
+ (walk_state->aml_offset +
+ sizeof(struct acpi_table_header) -
+ 16));
+ acpi_os_printf(" */\n");
+#endif
+ }
+
+ /* Increment past one-byte or two-byte opcode */
+
+ walk_state->parser_state.aml++;
+ if (walk_state->opcode > 0xFF) { /* Can only happen if first byte is 0x5B */
+ walk_state->parser_state.aml++;
+ }
+
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+
+ default:
+
+ /* Found opcode info, this is a normal opcode */
+
+ walk_state->parser_state.aml +=
+ acpi_ps_get_opcode_size(walk_state->opcode);
+ walk_state->arg_types = walk_state->op_info->parse_args;
+ break;
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_build_named_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Begin of named Op in AML
+ * unnamed_op - Early Op (not a named Op)
+ * op - Returned Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse a named Op
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+ u8 *aml_op_start,
+ union acpi_parse_object *unnamed_op,
+ union acpi_parse_object **op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *arg = NULL;
+
+ ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
+
+ unnamed_op->common.value.arg = NULL;
+ unnamed_op->common.arg_list_length = 0;
+ unnamed_op->common.aml_opcode = walk_state->opcode;
+
+ /*
+ * Get and append arguments until we find the node that contains
+ * the name (the type ARGP_NAME).
+ */
+ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
+ (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) {
+ status =
+ acpi_ps_get_next_arg(walk_state,
+ &(walk_state->parser_state),
+ GET_CURRENT_ARG_TYPE(walk_state->
+ arg_types), &arg);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ acpi_ps_append_arg(unnamed_op, arg);
+ INCREMENT_ARG_LIST(walk_state->arg_types);
+ }
+
+ /*
+ * Make sure that we found a NAME and didn't run out of arguments
+ */
+ if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) {
+ return_ACPI_STATUS(AE_AML_NO_OPERAND);
+ }
+
+ /* We know that this arg is a name, move to next arg */
+
+ INCREMENT_ARG_LIST(walk_state->arg_types);
+
+ /*
+ * Find the object. This will either insert the object into
+ * the namespace or simply look it up
+ */
+ walk_state->op = NULL;
+
+ status = walk_state->descending_callback(walk_state, op);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
+ return_ACPI_STATUS(status);
+ }
+
+ if (!*op) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+ }
+
+ status = acpi_ps_next_parse_state(walk_state, *op, status);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_CTRL_PENDING) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
+ }
+ return_ACPI_STATUS(status);
+ }
+
+ acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
+
+ if ((*op)->common.aml_opcode == AML_REGION_OP ||
+ (*op)->common.aml_opcode == AML_DATA_REGION_OP) {
+ /*
+ * Defer final parsing of an operation_region body, because we don't
+ * have enough info in the first pass to parse it correctly (i.e.,
+ * there may be method calls within the term_arg elements of the body.)
+ *
+ * However, we must continue parsing because the opregion is not a
+ * standalone package -- we don't know where the end is at this point.
+ *
+ * (Length is unknown until parse of the body complete)
+ */
+ (*op)->named.data = aml_op_start;
+ (*op)->named.length = 0;
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_create_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Op start in AML
+ * new_op - Returned Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get Op from AML
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+ u8 *aml_op_start, union acpi_parse_object **new_op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op;
+ union acpi_parse_object *named_op = NULL;
+ union acpi_parse_object *parent_scope;
+ u8 argument_count;
+ const struct acpi_opcode_info *op_info;
+
+ ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
+
+ status = acpi_ps_get_aml_opcode(walk_state);
+ if (status == AE_CTRL_PARSE_CONTINUE) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+ }
+
+ /* Create Op structure and append to parent's argument list */
+
+ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+ op = acpi_ps_alloc_op(walk_state->opcode);
+ if (!op) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ if (walk_state->op_info->flags & AML_NAMED) {
+ status =
+ acpi_ps_build_named_op(walk_state, aml_op_start, op,
+ &named_op);
+ acpi_ps_free_op(op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ *new_op = named_op;
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Not a named opcode, just allocate Op and append to parent */
+
+ if (walk_state->op_info->flags & AML_CREATE) {
+ /*
+ * Backup to beginning of create_XXXfield declaration
+ * body_length is unknown until we parse the body
+ */
+ op->named.data = aml_op_start;
+ op->named.length = 0;
+ }
+
+ if (walk_state->opcode == AML_BANK_FIELD_OP) {
+ /*
+ * Backup to beginning of bank_field declaration
+ * body_length is unknown until we parse the body
+ */
+ op->named.data = aml_op_start;
+ op->named.length = 0;
+ }
+
+ parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state));
+ acpi_ps_append_arg(parent_scope, op);
+
+ if (parent_scope) {
+ op_info =
+ acpi_ps_get_opcode_info(parent_scope->common.aml_opcode);
+ if (op_info->flags & AML_HAS_TARGET) {
+ argument_count =
+ acpi_ps_get_argument_count(op_info->type);
+ if (parent_scope->common.arg_list_length >
+ argument_count) {
+ op->common.flags |= ACPI_PARSEOP_TARGET;
+ }
+ } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) {
+ op->common.flags |= ACPI_PARSEOP_TARGET;
+ }
+ }
+
+ if (walk_state->descending_callback != NULL) {
+ /*
+ * Find the object. This will either insert the object into
+ * the namespace or simply look it up
+ */
+ walk_state->op = *new_op = op;
+
+ status = walk_state->descending_callback(walk_state, &op);
+ status = acpi_ps_next_parse_state(walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_CTRL_PARSE_PENDING;
+ }
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_complete_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * op - Returned Op
+ * status - Parse status before complete Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Complete Op
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **op, acpi_status status)
+{
+ acpi_status status2;
+
+ ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state);
+
+ /*
+ * Finished one argument of the containing scope
+ */
+ walk_state->parser_state.scope->parse_scope.arg_count--;
+
+ /* Close this Op (will result in parse subtree deletion) */
+
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
+
+ *op = NULL;
+
+ switch (status) {
+ case AE_OK:
+ break;
+
+ case AE_CTRL_TRANSFER:
+
+ /* We are about to transfer to a called method */
+
+ walk_state->prev_op = NULL;
+ walk_state->prev_arg_types = walk_state->arg_types;
+ return_ACPI_STATUS(status);
+
+ case AE_CTRL_END:
+
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+
+ if (*op) {
+ walk_state->op = *op;
+ walk_state->op_info =
+ acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+ walk_state->opcode = (*op)->common.aml_opcode;
+
+ status = walk_state->ascending_callback(walk_state);
+ status =
+ acpi_ps_next_parse_state(walk_state, *op, status);
+
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
+ }
+
+ status = AE_OK;
+ break;
+
+ case AE_CTRL_BREAK:
+ case AE_CTRL_CONTINUE:
+
+ /* Pop off scopes until we find the While */
+
+ while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) {
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+ }
+
+ /* Close this iteration of the While loop */
+
+ walk_state->op = *op;
+ walk_state->op_info =
+ acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+ walk_state->opcode = (*op)->common.aml_opcode;
+
+ status = walk_state->ascending_callback(walk_state);
+ status = acpi_ps_next_parse_state(walk_state, *op, status);
+
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
+
+ status = AE_OK;
+ break;
+
+ case AE_CTRL_TERMINATE:
+
+ /* Clean up */
+ do {
+ if (*op) {
+ status2 =
+ acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
+
+ acpi_ut_delete_generic_state
+ (acpi_ut_pop_generic_state
+ (&walk_state->control_state));
+ }
+
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+
+ } while (*op);
+
+ return_ACPI_STATUS(AE_OK);
+
+ default: /* All other non-AE_OK status */
+
+ do {
+ if (*op) {
+ status2 =
+ acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
+ }
+
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+
+ } while (*op);
+
+#if 0
+ /*
+ * TBD: Cleanup parse ops on error
+ */
+ if (*op == NULL) {
+ acpi_ps_pop_scope(parser_state, op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+ }
+#endif
+ walk_state->prev_op = NULL;
+ walk_state->prev_arg_types = walk_state->arg_types;
+ return_ACPI_STATUS(status);
+ }
+
+ /* This scope complete? */
+
+ if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) {
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op));
+ } else {
+ *op = NULL;
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_complete_final_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * op - Current Op
+ * status - Current parse status before complete last
+ * Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Complete last Op.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op, acpi_status status)
+{
+ acpi_status status2;
+
+ ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state);
+
+ /*
+ * Complete the last Op (if not completed), and clear the scope stack.
+ * It is easily possible to end an AML "package" with an unbounded number
+ * of open scopes (such as when several ASL blocks are closed with
+ * sequential closing braces). We want to terminate each one cleanly.
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
+ op));
+ do {
+ if (op) {
+ if (walk_state->ascending_callback != NULL) {
+ walk_state->op = op;
+ walk_state->op_info =
+ acpi_ps_get_opcode_info(op->common.
+ aml_opcode);
+ walk_state->opcode = op->common.aml_opcode;
+
+ status =
+ walk_state->ascending_callback(walk_state);
+ status =
+ acpi_ps_next_parse_state(walk_state, op,
+ status);
+ if (status == AE_CTRL_PENDING) {
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ AE_OK);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ if (status == AE_CTRL_TERMINATE) {
+ status = AE_OK;
+
+ /* Clean up */
+ do {
+ if (op) {
+ status2 =
+ acpi_ps_complete_this_op
+ (walk_state, op);
+ if (ACPI_FAILURE
+ (status2)) {
+ return_ACPI_STATUS
+ (status2);
+ }
+ }
+
+ acpi_ps_pop_scope(&
+ (walk_state->
+ parser_state),
+ &op,
+ &walk_state->
+ arg_types,
+ &walk_state->
+ arg_count);
+
+ } while (op);
+
+ return_ACPI_STATUS(status);
+ }
+
+ else if (ACPI_FAILURE(status)) {
+
+ /* First error is most important */
+
+ (void)
+ acpi_ps_complete_this_op(walk_state,
+ op);
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ status2 = acpi_ps_complete_this_op(walk_state, op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
+ }
+
+ acpi_ps_pop_scope(&(walk_state->parser_state), &op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+
+ } while (op);
+
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c
index 1793d934aa30..1b659e59710a 100644
--- a/drivers/acpi/acpica/psopcode.c
+++ b/drivers/acpi/acpica/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,16 +43,12 @@
#include <acpi/acpi.h>
#include "accommon.h"
-#include "acparser.h"
#include "acopcode.h"
#include "amlcode.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psopcode")
-static const u8 acpi_gbl_argument_count[] =
- { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 };
-
/*******************************************************************************
*
* NAME: acpi_gbl_aml_op_info
@@ -63,7 +59,6 @@ static const u8 acpi_gbl_argument_count[] =
* the operand type.
*
******************************************************************************/
-
/*
* Summary of opcode types/flags
*
@@ -181,7 +176,6 @@ static const u8 acpi_gbl_argument_count[] =
AML_CREATE_QWORD_FIELD_OP
******************************************************************************/
-
/*
* Master Opcode information table. A summary of everything we know about each
* opcode, all in one place.
@@ -656,169 +650,3 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = {
/*! [End] no source code translation !*/
};
-
-/*
- * This table is directly indexed by the opcodes, and returns an
- * index into the table above
- */
-static const u8 acpi_gbl_short_op_index[256] = {
-/* 0 1 2 3 4 5 6 7 */
-/* 8 9 A B C D E F */
-/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK,
-/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK,
-/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, _UNK, _UNK, _UNK,
-/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX,
-/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D,
-/* 0x38 */ 0x7F, 0x80, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
-/* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
-/* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
-/* 0x58 */ _ASC, _ASC, _ASC, _UNK, _PFX, _UNK, _PFX, _ASC,
-/* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
-/* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK,
-/* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
-/* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
-/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, 0x70, 0x71, 0x2f, 0x30,
-/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x72,
-/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74,
-/* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A,
-/* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61,
-/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xC8 */ _UNK, _UNK, _UNK, _UNK, 0x44, _UNK, _UNK, _UNK,
-/* 0xD0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xD8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xE0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xE8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45,
-};
-
-/*
- * This table is indexed by the second opcode of the extended opcode
- * pair. It returns an index into the opcode table (acpi_gbl_aml_op_info)
- */
-static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = {
-/* 0 1 2 3 4 5 6 7 */
-/* 8 9 A B C D E F */
-/* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK,
-/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B,
-/* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
-/* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x30 */ 0x55, 0x56, 0x57, 0x7e, _UNK, _UNK, _UNK, _UNK,
-/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x40 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x48 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x60 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x68 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
-/* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
-/* 0x88 */ 0x7C,
-};
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_get_opcode_info
- *
- * PARAMETERS: opcode - The AML opcode
- *
- * RETURN: A pointer to the info about the opcode.
- *
- * DESCRIPTION: Find AML opcode description based on the opcode.
- * NOTE: This procedure must ALWAYS return a valid pointer!
- *
- ******************************************************************************/
-
-const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode)
-{
- ACPI_FUNCTION_NAME(ps_get_opcode_info);
-
- /*
- * Detect normal 8-bit opcode or extended 16-bit opcode
- */
- if (!(opcode & 0xFF00)) {
-
- /* Simple (8-bit) opcode: 0-255, can't index beyond table */
-
- return (&acpi_gbl_aml_op_info
- [acpi_gbl_short_op_index[(u8) opcode]]);
- }
-
- if (((opcode & 0xFF00) == AML_EXTENDED_OPCODE) &&
- (((u8) opcode) <= MAX_EXTENDED_OPCODE)) {
-
- /* Valid extended (16-bit) opcode */
-
- return (&acpi_gbl_aml_op_info
- [acpi_gbl_long_op_index[(u8) opcode]]);
- }
-
- /* Unknown AML opcode */
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Unknown AML opcode [%4.4X]\n", opcode));
-
- return (&acpi_gbl_aml_op_info[_UNK]);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_get_opcode_name
- *
- * PARAMETERS: opcode - The AML opcode
- *
- * RETURN: A pointer to the name of the opcode (ASCII String)
- * Note: Never returns NULL.
- *
- * DESCRIPTION: Translate an opcode into a human-readable string
- *
- ******************************************************************************/
-
-char *acpi_ps_get_opcode_name(u16 opcode)
-{
-#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT)
-
- const struct acpi_opcode_info *op;
-
- op = acpi_ps_get_opcode_info(opcode);
-
- /* Always guaranteed to return a valid pointer */
-
- return (op->name);
-
-#else
- return ("OpcodeName unavailable");
-
-#endif
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_get_argument_count
- *
- * PARAMETERS: op_type - Type associated with the AML opcode
- *
- * RETURN: Argument count
- *
- * DESCRIPTION: Obtain the number of expected arguments for an AML opcode
- *
- ******************************************************************************/
-
-u8 acpi_ps_get_argument_count(u32 op_type)
-{
-
- if (op_type <= AML_TYPE_EXEC_6A_0T_1R) {
- return (acpi_gbl_argument_count[op_type]);
- }
-
- return (0);
-}
diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c
new file mode 100644
index 000000000000..9ba5301e5751
--- /dev/null
+++ b/drivers/acpi/acpica/psopinfo.c
@@ -0,0 +1,223 @@
+/******************************************************************************
+ *
+ * Module Name: psopinfo - AML opcode information functions and dispatch tables
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "acopcode.h"
+#include "amlcode.h"
+
+#define _COMPONENT ACPI_PARSER
+ACPI_MODULE_NAME("psopinfo")
+
+extern const u8 acpi_gbl_short_op_index[];
+extern const u8 acpi_gbl_long_op_index[];
+
+static const u8 acpi_gbl_argument_count[] =
+ { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 };
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_opcode_info
+ *
+ * PARAMETERS: opcode - The AML opcode
+ *
+ * RETURN: A pointer to the info about the opcode.
+ *
+ * DESCRIPTION: Find AML opcode description based on the opcode.
+ * NOTE: This procedure must ALWAYS return a valid pointer!
+ *
+ ******************************************************************************/
+
+const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode)
+{
+ ACPI_FUNCTION_NAME(ps_get_opcode_info);
+
+ /*
+ * Detect normal 8-bit opcode or extended 16-bit opcode
+ */
+ if (!(opcode & 0xFF00)) {
+
+ /* Simple (8-bit) opcode: 0-255, can't index beyond table */
+
+ return (&acpi_gbl_aml_op_info
+ [acpi_gbl_short_op_index[(u8)opcode]]);
+ }
+
+ if (((opcode & 0xFF00) == AML_EXTENDED_OPCODE) &&
+ (((u8)opcode) <= MAX_EXTENDED_OPCODE)) {
+
+ /* Valid extended (16-bit) opcode */
+
+ return (&acpi_gbl_aml_op_info
+ [acpi_gbl_long_op_index[(u8)opcode]]);
+ }
+
+ /* Unknown AML opcode */
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Unknown AML opcode [%4.4X]\n", opcode));
+
+ return (&acpi_gbl_aml_op_info[_UNK]);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_opcode_name
+ *
+ * PARAMETERS: opcode - The AML opcode
+ *
+ * RETURN: A pointer to the name of the opcode (ASCII String)
+ * Note: Never returns NULL.
+ *
+ * DESCRIPTION: Translate an opcode into a human-readable string
+ *
+ ******************************************************************************/
+
+char *acpi_ps_get_opcode_name(u16 opcode)
+{
+#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT)
+
+ const struct acpi_opcode_info *op;
+
+ op = acpi_ps_get_opcode_info(opcode);
+
+ /* Always guaranteed to return a valid pointer */
+
+ return (op->name);
+
+#else
+ return ("OpcodeName unavailable");
+
+#endif
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_argument_count
+ *
+ * PARAMETERS: op_type - Type associated with the AML opcode
+ *
+ * RETURN: Argument count
+ *
+ * DESCRIPTION: Obtain the number of expected arguments for an AML opcode
+ *
+ ******************************************************************************/
+
+u8 acpi_ps_get_argument_count(u32 op_type)
+{
+
+ if (op_type <= AML_TYPE_EXEC_6A_0T_1R) {
+ return (acpi_gbl_argument_count[op_type]);
+ }
+
+ return (0);
+}
+
+/*
+ * This table is directly indexed by the opcodes It returns
+ * an index into the opcode table (acpi_gbl_aml_op_info)
+ */
+const u8 acpi_gbl_short_op_index[256] = {
+/* 0 1 2 3 4 5 6 7 */
+/* 8 9 A B C D E F */
+/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK,
+/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK,
+/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, _UNK, _UNK, _UNK,
+/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX,
+/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D,
+/* 0x38 */ 0x7F, 0x80, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
+/* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
+/* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
+/* 0x58 */ _ASC, _ASC, _ASC, _UNK, _PFX, _UNK, _PFX, _ASC,
+/* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+/* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK,
+/* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+/* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, 0x70, 0x71, 0x2f, 0x30,
+/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x72,
+/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74,
+/* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A,
+/* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61,
+/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xC8 */ _UNK, _UNK, _UNK, _UNK, 0x44, _UNK, _UNK, _UNK,
+/* 0xD0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xD8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xE0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xE8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45,
+};
+
+/*
+ * This table is indexed by the second opcode of the extended opcode
+ * pair. It returns an index into the opcode table (acpi_gbl_aml_op_info)
+ */
+const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = {
+/* 0 1 2 3 4 5 6 7 */
+/* 8 9 A B C D E F */
+/* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK,
+/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B,
+/* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
+/* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x30 */ 0x55, 0x56, 0x57, 0x7e, _UNK, _UNK, _UNK, _UNK,
+/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x40 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x48 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x60 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x68 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+/* 0x88 */ 0x7C,
+};
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c
index 2494caf47755..abc4c48b2edd 100644
--- a/drivers/acpi/acpica/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c
index 608dc20dc173..6a4b6fb39f32 100644
--- a/drivers/acpi/acpica/psscope.c
+++ b/drivers/acpi/acpica/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c
index fdb2e71f3046..c1934bf04f0a 100644
--- a/drivers/acpi/acpica/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c
index 4137dcb352d1..91fa73a6e55e 100644
--- a/drivers/acpi/acpica/psutils.c
+++ b/drivers/acpi/acpica/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -202,14 +202,6 @@ u8 acpi_ps_is_leading_char(u32 c)
}
/*
- * Is "c" a namestring prefix character?
- */
-u8 acpi_ps_is_prefix_char(u32 c)
-{
- return ((u8) (c == '\\' || c == '^'));
-}
-
-/*
* Get op's name (4-byte name segment) or 0 if unnamed
*/
#ifdef ACPI_FUTURE_USAGE
diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c
index ab96cf47896d..abd65624754f 100644
--- a/drivers/acpi/acpica/pswalk.c
+++ b/drivers/acpi/acpica/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c
index 963e16225797..f68254268965 100644
--- a/drivers/acpi/acpica/psxface.c
+++ b/drivers/acpi/acpica/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c
index 856ff075b6ab..f3a9276ac665 100644
--- a/drivers/acpi/acpica/rsaddr.c
+++ b/drivers/acpi/acpica/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c
index 147feb6aa2a0..7816d4eef04e 100644
--- a/drivers/acpi/acpica/rscalc.c
+++ b/drivers/acpi/acpica/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -84,7 +84,7 @@ static u8 acpi_rs_count_set_bits(u16 bit_field)
bit_field &= (u16) (bit_field - 1);
}
- return bits_set;
+ return (bits_set);
}
/*******************************************************************************
@@ -407,7 +407,9 @@ acpi_rs_get_list_length(u8 * aml_buffer,
/* Validate the Resource Type and Resource Length */
- status = acpi_ut_validate_resource(aml_buffer, &resource_index);
+ status =
+ acpi_ut_validate_resource(NULL, aml_buffer,
+ &resource_index);
if (ACPI_FAILURE(status)) {
/*
* Exit on failure. Cannot continue because the descriptor length
diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c
index 311cbc4f05fa..f8b55b426c9d 100644
--- a/drivers/acpi/acpica/rscreate.c
+++ b/drivers/acpi/acpica/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -98,7 +98,7 @@ acpi_buffer_to_resource(u8 *aml_buffer,
/* Perform the AML-to-Resource conversion */
- status = acpi_ut_walk_aml_resources(aml_buffer, aml_buffer_length,
+ status = acpi_ut_walk_aml_resources(NULL, aml_buffer, aml_buffer_length,
acpi_rs_convert_aml_to_resources,
&current_resource_ptr);
if (status == AE_AML_NO_RESOURCE_END_TAG) {
@@ -174,7 +174,7 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
/* Do the conversion */
resource = output_buffer->pointer;
- status = acpi_ut_walk_aml_resources(aml_start, aml_buffer_length,
+ status = acpi_ut_walk_aml_resources(NULL, aml_start, aml_buffer_length,
acpi_rs_convert_aml_to_resources,
&resource);
if (ACPI_FAILURE(status)) {
@@ -480,8 +480,7 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer,
status = acpi_rs_get_aml_length(linked_list_buffer, &aml_size_needed);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n",
- (u32) aml_size_needed,
- acpi_format_exception(status)));
+ (u32)aml_size_needed, acpi_format_exception(status)));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index 4d11b072388c..cab51445189d 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,419 +77,16 @@ static void acpi_rs_dump_address_common(union acpi_resource_data *resource);
static void
acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table);
-#define ACPI_RSD_OFFSET(f) (u8) ACPI_OFFSET (union acpi_resource_data,f)
-#define ACPI_PRT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_pci_routing_table,f)
-#define ACPI_RSD_TABLE_SIZE(name) (sizeof(name) / sizeof (struct acpi_rsdump_info))
-
-/*******************************************************************************
- *
- * Resource Descriptor info tables
- *
- * Note: The first table entry must be a Title or Literal and must contain
- * the table length (number of table entries)
- *
- ******************************************************************************/
-
-struct acpi_rsdump_info acpi_rs_dump_irq[7] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.descriptor_length),
- "Descriptor Length", NULL},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering",
- acpi_gbl_he_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity",
- acpi_gbl_ll_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.sharable), "Sharing",
- acpi_gbl_shr_decode},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.interrupt_count),
- "Interrupt Count", NULL},
- {ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(irq.interrupts[0]),
- "Interrupt List", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_dma[6] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_dma), "DMA", NULL},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.type), "Speed",
- acpi_gbl_typ_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(dma.bus_master), "Mastering",
- acpi_gbl_bm_decode},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.transfer), "Transfer Type",
- acpi_gbl_siz_decode},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(dma.channel_count), "Channel Count",
- NULL},
- {ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(dma.channels[0]), "Channel List",
- NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_start_dpf[4] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_start_dpf),
- "Start-Dependent-Functions", NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(start_dpf.descriptor_length),
- "Descriptor Length", NULL},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.compatibility_priority),
- "Compatibility Priority", acpi_gbl_config_decode},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.performance_robustness),
- "Performance/Robustness", acpi_gbl_config_decode}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_end_dpf[1] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_dpf),
- "End-Dependent-Functions", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_io[6] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io), "I/O", NULL},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(io.io_decode), "Address Decoding",
- acpi_gbl_io_decode},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(io.minimum), "Address Minimum", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(io.maximum), "Address Maximum", NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(io.alignment), "Alignment", NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(io.address_length), "Address Length",
- NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_fixed_io[3] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_io),
- "Fixed I/O", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_io.address), "Address", NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_io.address_length),
- "Address Length", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_vendor[3] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_vendor),
- "Vendor Specific", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(vendor.byte_length), "Length", NULL},
- {ACPI_RSD_LONGLIST, ACPI_RSD_OFFSET(vendor.byte_data[0]), "Vendor Data",
- NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_end_tag[1] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_tag), "EndTag",
- NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_memory24[6] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory24),
- "24-Bit Memory Range", NULL},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory24.write_protect),
- "Write Protect", acpi_gbl_rw_decode},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.minimum), "Address Minimum",
- NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.maximum), "Address Maximum",
- NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.alignment), "Alignment",
- NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.address_length),
- "Address Length", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_memory32[6] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory32),
- "32-Bit Memory Range", NULL},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory32.write_protect),
- "Write Protect", acpi_gbl_rw_decode},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.minimum), "Address Minimum",
- NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.maximum), "Address Maximum",
- NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.alignment), "Alignment",
- NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.address_length),
- "Address Length", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[4] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_memory32),
- "32-Bit Fixed Memory Range", NULL},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(fixed_memory32.write_protect),
- "Write Protect", acpi_gbl_rw_decode},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address), "Address",
- NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address_length),
- "Address Length", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_address16[8] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address16),
- "16-Bit WORD Address Space", NULL},
- {ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.granularity), "Granularity",
- NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.minimum), "Address Minimum",
- NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.maximum), "Address Maximum",
- NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.translation_offset),
- "Translation Offset", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address_length),
- "Address Length", NULL},
- {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address16.resource_source), NULL, NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_address32[8] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address32),
- "32-Bit DWORD Address Space", NULL},
- {ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.granularity), "Granularity",
- NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.minimum), "Address Minimum",
- NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.maximum), "Address Maximum",
- NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.translation_offset),
- "Translation Offset", NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address_length),
- "Address Length", NULL},
- {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address32.resource_source), NULL, NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_address64[8] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address64),
- "64-Bit QWORD Address Space", NULL},
- {ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.granularity), "Granularity",
- NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.minimum), "Address Minimum",
- NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.maximum), "Address Maximum",
- NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.translation_offset),
- "Translation Offset", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address_length),
- "Address Length", NULL},
- {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address64.resource_source), NULL, NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_ext_address64[8] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_address64),
- "64-Bit Extended Address Space", NULL},
- {ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.granularity),
- "Granularity", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.minimum),
- "Address Minimum", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.maximum),
- "Address Maximum", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.translation_offset),
- "Translation Offset", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address_length),
- "Address Length", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.type_specific),
- "Type-Specific Attribute", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_ext_irq[8] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_irq),
- "Extended IRQ", NULL},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.producer_consumer),
- "Type", acpi_gbl_consume_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.triggering),
- "Triggering", acpi_gbl_he_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.polarity), "Polarity",
- acpi_gbl_ll_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.sharable), "Sharing",
- acpi_gbl_shr_decode},
- {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(extended_irq.resource_source), NULL,
- NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(extended_irq.interrupt_count),
- "Interrupt Count", NULL},
- {ACPI_RSD_DWORDLIST, ACPI_RSD_OFFSET(extended_irq.interrupts[0]),
- "Interrupt List", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_generic_reg[6] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_generic_reg),
- "Generic Register", NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.space_id), "Space ID",
- NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.bit_width), "Bit Width",
- NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.bit_offset), "Bit Offset",
- NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.access_size),
- "Access Size", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(generic_reg.address), "Address", NULL}
-};
-
-struct acpi_rsdump_info acpi_rs_dump_gpio[16] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_gpio), "GPIO", NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.revision_id), "RevisionId", NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.connection_type),
- "ConnectionType", acpi_gbl_ct_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.producer_consumer),
- "ProducerConsumer", acpi_gbl_consume_decode},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.pin_config), "PinConfig",
- acpi_gbl_ppc_decode},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.sharable), "Sharable",
- acpi_gbl_shr_decode},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.io_restriction),
- "IoRestriction", acpi_gbl_ior_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.triggering), "Triggering",
- acpi_gbl_he_decode},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.polarity), "Polarity",
- acpi_gbl_ll_decode},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.drive_strength), "DriveStrength",
- NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.debounce_timeout),
- "DebounceTimeout", NULL},
- {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(gpio.resource_source),
- "ResourceSource", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.pin_table_length),
- "PinTableLength", NULL},
- {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(gpio.pin_table), "PinTable", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.vendor_length), "VendorLength",
- NULL},
- {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(gpio.vendor_data), "VendorData",
- NULL},
-};
-
-struct acpi_rsdump_info acpi_rs_dump_fixed_dma[4] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_dma),
- "FixedDma", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.request_lines),
- "RequestLines", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.channels), "Channels",
- NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_dma.width), "TransferWidth",
- acpi_gbl_dts_decode},
-};
-
-#define ACPI_RS_DUMP_COMMON_SERIAL_BUS \
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.revision_id), "RevisionId", NULL}, \
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.type), "Type", acpi_gbl_sbt_decode}, \
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.producer_consumer), "ProducerConsumer", acpi_gbl_consume_decode}, \
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.slave_mode), "SlaveMode", acpi_gbl_sm_decode}, \
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.type_revision_id), "TypeRevisionId", NULL}, \
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (common_serial_bus.type_data_length), "TypeDataLength", NULL}, \
- {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (common_serial_bus.resource_source), "ResourceSource", NULL}, \
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (common_serial_bus.vendor_length), "VendorLength", NULL}, \
- {ACPI_RSD_SHORTLISTX,ACPI_RSD_OFFSET (common_serial_bus.vendor_data), "VendorData", NULL},
-
-struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[10] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_common_serial_bus),
- "Common Serial Bus", NULL},
- ACPI_RS_DUMP_COMMON_SERIAL_BUS
-};
-
-struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[13] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_i2c_serial_bus),
- "I2C Serial Bus", NULL},
- ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG,
- ACPI_RSD_OFFSET(i2c_serial_bus.
- access_mode),
- "AccessMode", acpi_gbl_am_decode},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(i2c_serial_bus.connection_speed),
- "ConnectionSpeed", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(i2c_serial_bus.slave_address),
- "SlaveAddress", NULL},
-};
-
-struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[17] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_spi_serial_bus),
- "Spi Serial Bus", NULL},
- ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG,
- ACPI_RSD_OFFSET(spi_serial_bus.
- wire_mode), "WireMode",
- acpi_gbl_wm_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(spi_serial_bus.device_polarity),
- "DevicePolarity", acpi_gbl_dp_decode},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.data_bit_length),
- "DataBitLength", NULL},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_phase),
- "ClockPhase", acpi_gbl_cph_decode},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_polarity),
- "ClockPolarity", acpi_gbl_cpo_decode},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(spi_serial_bus.device_selection),
- "DeviceSelection", NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(spi_serial_bus.connection_speed),
- "ConnectionSpeed", NULL},
-};
-
-struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[19] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_uart_serial_bus),
- "Uart Serial Bus", NULL},
- ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_2BITFLAG,
- ACPI_RSD_OFFSET(uart_serial_bus.
- flow_control),
- "FlowControl", acpi_gbl_fc_decode},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.stop_bits),
- "StopBits", acpi_gbl_sb_decode},
- {ACPI_RSD_3BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.data_bits),
- "DataBits", acpi_gbl_bpb_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.endian), "Endian",
- acpi_gbl_ed_decode},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.parity), "Parity",
- acpi_gbl_pt_decode},
- {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.lines_enabled),
- "LinesEnabled", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.rx_fifo_size),
- "RxFifoSize", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.tx_fifo_size),
- "TxFifoSize", NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(uart_serial_bus.default_baud_rate),
- "ConnectionSpeed", NULL},
-};
-
-/*
- * Tables used for common address descriptor flag fields
- */
-static struct acpi_rsdump_info acpi_rs_dump_general_flags[5] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_general_flags), NULL,
- NULL},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.producer_consumer),
- "Consumer/Producer", acpi_gbl_consume_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.decode), "Address Decode",
- acpi_gbl_dec_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.min_address_fixed),
- "Min Relocatability", acpi_gbl_min_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.max_address_fixed),
- "Max Relocatability", acpi_gbl_max_decode}
-};
-
-static struct acpi_rsdump_info acpi_rs_dump_memory_flags[5] = {
- {ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory_flags),
- "Resource Type", (void *)"Memory Range"},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.write_protect),
- "Write Protect", acpi_gbl_rw_decode},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.caching),
- "Caching", acpi_gbl_mem_decode},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.range_type),
- "Range Type", acpi_gbl_mtp_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.translation),
- "Translation", acpi_gbl_ttp_decode}
-};
-
-static struct acpi_rsdump_info acpi_rs_dump_io_flags[4] = {
- {ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io_flags),
- "Resource Type", (void *)"I/O Range"},
- {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.io.range_type),
- "Range Type", acpi_gbl_rng_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation),
- "Translation", acpi_gbl_ttp_decode},
- {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation_type),
- "Translation Type", acpi_gbl_trs_decode}
-};
-
-/*
- * Table used to dump _PRT contents
- */
-static struct acpi_rsdump_info acpi_rs_dump_prt[5] = {
- {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_prt), NULL, NULL},
- {ACPI_RSD_UINT64, ACPI_PRT_OFFSET(address), "Address", NULL},
- {ACPI_RSD_UINT32, ACPI_PRT_OFFSET(pin), "Pin", NULL},
- {ACPI_RSD_STRING, ACPI_PRT_OFFSET(source[0]), "Source", NULL},
- {ACPI_RSD_UINT32, ACPI_PRT_OFFSET(source_index), "Source Index", NULL}
-};
-
/*******************************************************************************
*
* FUNCTION: acpi_rs_dump_descriptor
*
- * PARAMETERS: Resource
+ * PARAMETERS: resource - Buffer containing the resource
+ * table - Table entry to decode the resource
*
* RETURN: None
*
- * DESCRIPTION:
+ * DESCRIPTION: Dump a resource descriptor based on a dump table entry.
*
******************************************************************************/
@@ -654,7 +251,8 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
/*
* Optional resource_source for Address resources
*/
- acpi_rs_dump_resource_source(ACPI_CAST_PTR(struct
+ acpi_rs_dump_resource_source(ACPI_CAST_PTR
+ (struct
acpi_resource_source,
target));
break;
@@ -765,8 +363,9 @@ void acpi_rs_dump_resource_list(struct acpi_resource *resource_list)
ACPI_FUNCTION_ENTRY();
- if (!(acpi_dbg_level & ACPI_LV_RESOURCES)
- || !(_COMPONENT & acpi_dbg_layer)) {
+ /* Check if debug output enabled */
+
+ if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_RESOURCES, _COMPONENT)) {
return;
}
@@ -827,8 +426,9 @@ void acpi_rs_dump_irq_list(u8 * route_table)
ACPI_FUNCTION_ENTRY();
- if (!(acpi_dbg_level & ACPI_LV_RESOURCES)
- || !(_COMPONENT & acpi_dbg_layer)) {
+ /* Check if debug output enabled */
+
+ if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_RESOURCES, _COMPONENT)) {
return;
}
diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c
new file mode 100644
index 000000000000..46192bd53653
--- /dev/null
+++ b/drivers/acpi/acpica/rsdumpinfo.c
@@ -0,0 +1,454 @@
+/*******************************************************************************
+ *
+ * Module Name: rsdumpinfo - Tables used to display resource descriptors.
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acresrc.h"
+
+#define _COMPONENT ACPI_RESOURCES
+ACPI_MODULE_NAME("rsdumpinfo")
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#define ACPI_RSD_OFFSET(f) (u8) ACPI_OFFSET (union acpi_resource_data,f)
+#define ACPI_PRT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_pci_routing_table,f)
+#define ACPI_RSD_TABLE_SIZE(name) (sizeof(name) / sizeof (struct acpi_rsdump_info))
+/*******************************************************************************
+ *
+ * Resource Descriptor info tables
+ *
+ * Note: The first table entry must be a Title or Literal and must contain
+ * the table length (number of table entries)
+ *
+ ******************************************************************************/
+struct acpi_rsdump_info acpi_rs_dump_irq[7] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.descriptor_length),
+ "Descriptor Length", NULL},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering",
+ acpi_gbl_he_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity",
+ acpi_gbl_ll_decode},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(irq.sharable), "Sharing",
+ acpi_gbl_shr_decode},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.interrupt_count),
+ "Interrupt Count", NULL},
+ {ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(irq.interrupts[0]),
+ "Interrupt List", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_dma[6] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_dma), "DMA", NULL},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.type), "Speed",
+ acpi_gbl_typ_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(dma.bus_master), "Mastering",
+ acpi_gbl_bm_decode},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(dma.transfer), "Transfer Type",
+ acpi_gbl_siz_decode},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(dma.channel_count), "Channel Count",
+ NULL},
+ {ACPI_RSD_SHORTLIST, ACPI_RSD_OFFSET(dma.channels[0]), "Channel List",
+ NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_start_dpf[4] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_start_dpf),
+ "Start-Dependent-Functions", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(start_dpf.descriptor_length),
+ "Descriptor Length", NULL},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.compatibility_priority),
+ "Compatibility Priority", acpi_gbl_config_decode},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.performance_robustness),
+ "Performance/Robustness", acpi_gbl_config_decode}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_end_dpf[1] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_dpf),
+ "End-Dependent-Functions", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_io[6] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io), "I/O", NULL},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(io.io_decode), "Address Decoding",
+ acpi_gbl_io_decode},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(io.minimum), "Address Minimum", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(io.maximum), "Address Maximum", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(io.alignment), "Alignment", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(io.address_length), "Address Length",
+ NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_fixed_io[3] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_io),
+ "Fixed I/O", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_io.address), "Address", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_io.address_length),
+ "Address Length", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_vendor[3] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_vendor),
+ "Vendor Specific", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(vendor.byte_length), "Length", NULL},
+ {ACPI_RSD_LONGLIST, ACPI_RSD_OFFSET(vendor.byte_data[0]), "Vendor Data",
+ NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_end_tag[1] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_end_tag), "EndTag",
+ NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_memory24[6] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory24),
+ "24-Bit Memory Range", NULL},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory24.write_protect),
+ "Write Protect", acpi_gbl_rw_decode},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.minimum), "Address Minimum",
+ NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.maximum), "Address Maximum",
+ NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.alignment), "Alignment",
+ NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(memory24.address_length),
+ "Address Length", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_memory32[6] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory32),
+ "32-Bit Memory Range", NULL},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(memory32.write_protect),
+ "Write Protect", acpi_gbl_rw_decode},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.minimum), "Address Minimum",
+ NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.maximum), "Address Maximum",
+ NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.alignment), "Alignment",
+ NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(memory32.address_length),
+ "Address Length", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[4] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_memory32),
+ "32-Bit Fixed Memory Range", NULL},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(fixed_memory32.write_protect),
+ "Write Protect", acpi_gbl_rw_decode},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address), "Address",
+ NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(fixed_memory32.address_length),
+ "Address Length", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_address16[8] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address16),
+ "16-Bit WORD Address Space", NULL},
+ {ACPI_RSD_ADDRESS, 0, NULL, NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.granularity), "Granularity",
+ NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.minimum), "Address Minimum",
+ NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.maximum), "Address Maximum",
+ NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.translation_offset),
+ "Translation Offset", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address_length),
+ "Address Length", NULL},
+ {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address16.resource_source), NULL, NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_address32[8] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address32),
+ "32-Bit DWORD Address Space", NULL},
+ {ACPI_RSD_ADDRESS, 0, NULL, NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.granularity), "Granularity",
+ NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.minimum), "Address Minimum",
+ NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.maximum), "Address Maximum",
+ NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.translation_offset),
+ "Translation Offset", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address_length),
+ "Address Length", NULL},
+ {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address32.resource_source), NULL, NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_address64[8] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address64),
+ "64-Bit QWORD Address Space", NULL},
+ {ACPI_RSD_ADDRESS, 0, NULL, NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.granularity), "Granularity",
+ NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.minimum), "Address Minimum",
+ NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.maximum), "Address Maximum",
+ NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.translation_offset),
+ "Translation Offset", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address_length),
+ "Address Length", NULL},
+ {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address64.resource_source), NULL, NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_ext_address64[8] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_address64),
+ "64-Bit Extended Address Space", NULL},
+ {ACPI_RSD_ADDRESS, 0, NULL, NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.granularity),
+ "Granularity", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.minimum),
+ "Address Minimum", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.maximum),
+ "Address Maximum", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.translation_offset),
+ "Translation Offset", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address_length),
+ "Address Length", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.type_specific),
+ "Type-Specific Attribute", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_ext_irq[8] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_irq),
+ "Extended IRQ", NULL},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.producer_consumer),
+ "Type", acpi_gbl_consume_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.triggering),
+ "Triggering", acpi_gbl_he_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(extended_irq.polarity), "Polarity",
+ acpi_gbl_ll_decode},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(extended_irq.sharable), "Sharing",
+ acpi_gbl_shr_decode},
+ {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(extended_irq.resource_source), NULL,
+ NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(extended_irq.interrupt_count),
+ "Interrupt Count", NULL},
+ {ACPI_RSD_DWORDLIST, ACPI_RSD_OFFSET(extended_irq.interrupts[0]),
+ "Interrupt List", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_generic_reg[6] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_generic_reg),
+ "Generic Register", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.space_id), "Space ID",
+ NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.bit_width), "Bit Width",
+ NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.bit_offset), "Bit Offset",
+ NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(generic_reg.access_size),
+ "Access Size", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(generic_reg.address), "Address", NULL}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_gpio[16] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_gpio), "GPIO", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.revision_id), "RevisionId", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.connection_type),
+ "ConnectionType", acpi_gbl_ct_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.producer_consumer),
+ "ProducerConsumer", acpi_gbl_consume_decode},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.pin_config), "PinConfig",
+ acpi_gbl_ppc_decode},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.sharable), "Sharing",
+ acpi_gbl_shr_decode},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.io_restriction),
+ "IoRestriction", acpi_gbl_ior_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.triggering), "Triggering",
+ acpi_gbl_he_decode},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.polarity), "Polarity",
+ acpi_gbl_ll_decode},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.drive_strength), "DriveStrength",
+ NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.debounce_timeout),
+ "DebounceTimeout", NULL},
+ {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(gpio.resource_source),
+ "ResourceSource", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.pin_table_length),
+ "PinTableLength", NULL},
+ {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(gpio.pin_table), "PinTable", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.vendor_length), "VendorLength",
+ NULL},
+ {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(gpio.vendor_data), "VendorData",
+ NULL},
+};
+
+struct acpi_rsdump_info acpi_rs_dump_fixed_dma[4] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_dma),
+ "FixedDma", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.request_lines),
+ "RequestLines", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.channels), "Channels",
+ NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_dma.width), "TransferWidth",
+ acpi_gbl_dts_decode},
+};
+
+#define ACPI_RS_DUMP_COMMON_SERIAL_BUS \
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.revision_id), "RevisionId", NULL}, \
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.type), "Type", acpi_gbl_sbt_decode}, \
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.producer_consumer), "ProducerConsumer", acpi_gbl_consume_decode}, \
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.slave_mode), "SlaveMode", acpi_gbl_sm_decode}, \
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.type_revision_id), "TypeRevisionId", NULL}, \
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (common_serial_bus.type_data_length), "TypeDataLength", NULL}, \
+ {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (common_serial_bus.resource_source), "ResourceSource", NULL}, \
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (common_serial_bus.vendor_length), "VendorLength", NULL}, \
+ {ACPI_RSD_SHORTLISTX,ACPI_RSD_OFFSET (common_serial_bus.vendor_data), "VendorData", NULL},
+
+struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[10] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_common_serial_bus),
+ "Common Serial Bus", NULL},
+ ACPI_RS_DUMP_COMMON_SERIAL_BUS
+};
+
+struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[13] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_i2c_serial_bus),
+ "I2C Serial Bus", NULL},
+ ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG,
+ ACPI_RSD_OFFSET(i2c_serial_bus.
+ access_mode),
+ "AccessMode", acpi_gbl_am_decode},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(i2c_serial_bus.connection_speed),
+ "ConnectionSpeed", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(i2c_serial_bus.slave_address),
+ "SlaveAddress", NULL},
+};
+
+struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[17] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_spi_serial_bus),
+ "Spi Serial Bus", NULL},
+ ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG,
+ ACPI_RSD_OFFSET(spi_serial_bus.
+ wire_mode), "WireMode",
+ acpi_gbl_wm_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(spi_serial_bus.device_polarity),
+ "DevicePolarity", acpi_gbl_dp_decode},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.data_bit_length),
+ "DataBitLength", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_phase),
+ "ClockPhase", acpi_gbl_cph_decode},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_polarity),
+ "ClockPolarity", acpi_gbl_cpo_decode},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(spi_serial_bus.device_selection),
+ "DeviceSelection", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(spi_serial_bus.connection_speed),
+ "ConnectionSpeed", NULL},
+};
+
+struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[19] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_uart_serial_bus),
+ "Uart Serial Bus", NULL},
+ ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_2BITFLAG,
+ ACPI_RSD_OFFSET(uart_serial_bus.
+ flow_control),
+ "FlowControl", acpi_gbl_fc_decode},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.stop_bits),
+ "StopBits", acpi_gbl_sb_decode},
+ {ACPI_RSD_3BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.data_bits),
+ "DataBits", acpi_gbl_bpb_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.endian), "Endian",
+ acpi_gbl_ed_decode},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.parity), "Parity",
+ acpi_gbl_pt_decode},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.lines_enabled),
+ "LinesEnabled", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.rx_fifo_size),
+ "RxFifoSize", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.tx_fifo_size),
+ "TxFifoSize", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(uart_serial_bus.default_baud_rate),
+ "ConnectionSpeed", NULL},
+};
+
+/*
+ * Tables used for common address descriptor flag fields
+ */
+struct acpi_rsdump_info acpi_rs_dump_general_flags[5] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_general_flags), NULL,
+ NULL},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.producer_consumer),
+ "Consumer/Producer", acpi_gbl_consume_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.decode), "Address Decode",
+ acpi_gbl_dec_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.min_address_fixed),
+ "Min Relocatability", acpi_gbl_min_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.max_address_fixed),
+ "Max Relocatability", acpi_gbl_max_decode}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_memory_flags[5] = {
+ {ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_memory_flags),
+ "Resource Type", (void *)"Memory Range"},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.write_protect),
+ "Write Protect", acpi_gbl_rw_decode},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.caching),
+ "Caching", acpi_gbl_mem_decode},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.mem.range_type),
+ "Range Type", acpi_gbl_mtp_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.mem.translation),
+ "Translation", acpi_gbl_ttp_decode}
+};
+
+struct acpi_rsdump_info acpi_rs_dump_io_flags[4] = {
+ {ACPI_RSD_LITERAL, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_io_flags),
+ "Resource Type", (void *)"I/O Range"},
+ {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(address.info.io.range_type),
+ "Range Type", acpi_gbl_rng_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation),
+ "Translation", acpi_gbl_ttp_decode},
+ {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(address.info.io.translation_type),
+ "Translation Type", acpi_gbl_trs_decode}
+};
+
+/*
+ * Table used to dump _PRT contents
+ */
+struct acpi_rsdump_info acpi_rs_dump_prt[5] = {
+ {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_prt), NULL, NULL},
+ {ACPI_RSD_UINT64, ACPI_PRT_OFFSET(address), "Address", NULL},
+ {ACPI_RSD_UINT32, ACPI_PRT_OFFSET(pin), "Pin", NULL},
+ {ACPI_RSD_STRING, ACPI_PRT_OFFSET(source[0]), "Source", NULL},
+ {ACPI_RSD_UINT32, ACPI_PRT_OFFSET(source_index), "Source Index", NULL}
+};
+
+#endif
diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c
index a9fa5158200b..41fed78e0de6 100644
--- a/drivers/acpi/acpica/rsinfo.c
+++ b/drivers/acpi/acpica/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c
index f6a081057a22..ca183755a6f9 100644
--- a/drivers/acpi/acpica/rsio.c
+++ b/drivers/acpi/acpica/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c
index e23a9ec248cb..364decc1028a 100644
--- a/drivers/acpi/acpica/rsirq.c
+++ b/drivers/acpi/acpica/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -53,7 +53,7 @@ ACPI_MODULE_NAME("rsirq")
* acpi_rs_get_irq
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_get_irq[8] = {
+struct acpi_rsconvert_info acpi_rs_get_irq[9] = {
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IRQ,
ACPI_RS_SIZE(struct acpi_resource_irq),
ACPI_RSC_TABLE_SIZE(acpi_rs_get_irq)},
@@ -80,7 +80,7 @@ struct acpi_rsconvert_info acpi_rs_get_irq[8] = {
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 3},
- /* Get flags: Triggering[0], Polarity[3], Sharing[4] */
+ /* Get flags: Triggering[0], Polarity[3], Sharing[4], Wake[5] */
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering),
AML_OFFSET(irq.flags),
@@ -92,7 +92,11 @@ struct acpi_rsconvert_info acpi_rs_get_irq[8] = {
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.sharable),
AML_OFFSET(irq.flags),
- 4}
+ 4},
+
+ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.wake_capable),
+ AML_OFFSET(irq.flags),
+ 5}
};
/*******************************************************************************
@@ -101,7 +105,7 @@ struct acpi_rsconvert_info acpi_rs_get_irq[8] = {
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_set_irq[13] = {
+struct acpi_rsconvert_info acpi_rs_set_irq[14] = {
/* Start with a default descriptor of length 3 */
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IRQ,
@@ -114,7 +118,7 @@ struct acpi_rsconvert_info acpi_rs_set_irq[13] = {
AML_OFFSET(irq.irq_mask),
ACPI_RS_OFFSET(data.irq.interrupt_count)},
- /* Set the flags byte */
+ /* Set flags: Triggering[0], Polarity[3], Sharing[4], Wake[5] */
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering),
AML_OFFSET(irq.flags),
@@ -128,6 +132,10 @@ struct acpi_rsconvert_info acpi_rs_set_irq[13] = {
AML_OFFSET(irq.flags),
4},
+ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.wake_capable),
+ AML_OFFSET(irq.flags),
+ 5},
+
/*
* All done if the output descriptor length is required to be 3
* (i.e., optimization to 2 bytes cannot be attempted)
@@ -181,7 +189,7 @@ struct acpi_rsconvert_info acpi_rs_set_irq[13] = {
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_convert_ext_irq[9] = {
+struct acpi_rsconvert_info acpi_rs_convert_ext_irq[10] = {
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_EXTENDED_IRQ,
ACPI_RS_SIZE(struct acpi_resource_extended_irq),
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_ext_irq)},
@@ -190,8 +198,10 @@ struct acpi_rsconvert_info acpi_rs_convert_ext_irq[9] = {
sizeof(struct aml_resource_extended_irq),
0},
- /* Flag bits */
-
+ /*
+ * Flags: Producer/Consumer[0], Triggering[1], Polarity[2],
+ * Sharing[3], Wake[4]
+ */
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.extended_irq.producer_consumer),
AML_OFFSET(extended_irq.flags),
0},
@@ -208,19 +218,21 @@ struct acpi_rsconvert_info acpi_rs_convert_ext_irq[9] = {
AML_OFFSET(extended_irq.flags),
3},
+ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.extended_irq.wake_capable),
+ AML_OFFSET(extended_irq.flags),
+ 4},
+
/* IRQ Table length (Byte4) */
{ACPI_RSC_COUNT, ACPI_RS_OFFSET(data.extended_irq.interrupt_count),
AML_OFFSET(extended_irq.interrupt_count),
- sizeof(u32)}
- ,
+ sizeof(u32)},
/* Copy every IRQ in the table, each is 32 bits */
{ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.extended_irq.interrupts[0]),
AML_OFFSET(extended_irq.interrupts[0]),
- 0}
- ,
+ 0},
/* Optional resource_source (Index and String) */
@@ -285,7 +297,6 @@ struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[4] = {
* request_lines
* Channels
*/
-
{ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.fixed_dma.request_lines),
AML_OFFSET(fixed_dma.request_lines),
2},
@@ -293,5 +304,4 @@ struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[4] = {
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.fixed_dma.width),
AML_OFFSET(fixed_dma.width),
1},
-
};
diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c
index 8b64db9a3fd2..ee2e206fc6c8 100644
--- a/drivers/acpi/acpica/rslist.c
+++ b/drivers/acpi/acpica/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -217,9 +217,10 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
/* Perform final sanity check on the new AML resource descriptor */
- status =
- acpi_ut_validate_resource(ACPI_CAST_PTR
- (union aml_resource, aml), NULL);
+ status = acpi_ut_validate_resource(NULL,
+ ACPI_CAST_PTR(union
+ aml_resource,
+ aml), NULL);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c
index 4fd611ad02b4..ebc773a1b350 100644
--- a/drivers/acpi/acpica/rsmemory.c
+++ b/drivers/acpi/acpica/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -156,8 +156,7 @@ struct acpi_rsconvert_info acpi_rs_get_vendor_small[3] = {
{ACPI_RSC_COUNT16, ACPI_RS_OFFSET(data.vendor.byte_length),
0,
- sizeof(u8)}
- ,
+ sizeof(u8)},
/* Vendor data */
@@ -181,8 +180,7 @@ struct acpi_rsconvert_info acpi_rs_get_vendor_large[3] = {
{ACPI_RSC_COUNT16, ACPI_RS_OFFSET(data.vendor.byte_length),
0,
- sizeof(u8)}
- ,
+ sizeof(u8)},
/* Vendor data */
diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c
index c6f291c2bc83..d5bf05a96096 100644
--- a/drivers/acpi/acpica/rsmisc.c
+++ b/drivers/acpi/acpica/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -136,30 +136,30 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
/*
* Mask and shift the flag bit
*/
- ACPI_SET8(destination) = (u8)
- ((ACPI_GET8(source) >> info->value) & 0x01);
+ ACPI_SET8(destination,
+ ((ACPI_GET8(source) >> info->value) & 0x01));
break;
case ACPI_RSC_2BITFLAG:
/*
* Mask and shift the flag bits
*/
- ACPI_SET8(destination) = (u8)
- ((ACPI_GET8(source) >> info->value) & 0x03);
+ ACPI_SET8(destination,
+ ((ACPI_GET8(source) >> info->value) & 0x03));
break;
case ACPI_RSC_3BITFLAG:
/*
* Mask and shift the flag bits
*/
- ACPI_SET8(destination) = (u8)
- ((ACPI_GET8(source) >> info->value) & 0x07);
+ ACPI_SET8(destination,
+ ((ACPI_GET8(source) >> info->value) & 0x07));
break;
case ACPI_RSC_COUNT:
item_count = ACPI_GET8(source);
- ACPI_SET8(destination) = (u8) item_count;
+ ACPI_SET8(destination, item_count);
resource->length = resource->length +
(info->value * (item_count - 1));
@@ -168,7 +168,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
case ACPI_RSC_COUNT16:
item_count = aml_resource_length;
- ACPI_SET16(destination) = item_count;
+ ACPI_SET16(destination, item_count);
resource->length = resource->length +
(info->value * (item_count - 1));
@@ -181,13 +181,13 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
resource->length = resource->length + item_count;
item_count = item_count / 2;
- ACPI_SET16(destination) = item_count;
+ ACPI_SET16(destination, item_count);
break;
case ACPI_RSC_COUNT_GPIO_VEN:
item_count = ACPI_GET8(source);
- ACPI_SET8(destination) = (u8)item_count;
+ ACPI_SET8(destination, item_count);
resource->length = resource->length +
(info->value * item_count);
@@ -216,7 +216,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
}
resource->length = resource->length + item_count;
- ACPI_SET16(destination) = item_count;
+ ACPI_SET16(destination, item_count);
break;
case ACPI_RSC_COUNT_SERIAL_VEN:
@@ -224,7 +224,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
item_count = ACPI_GET16(source) - info->value;
resource->length = resource->length + item_count;
- ACPI_SET16(destination) = item_count;
+ ACPI_SET16(destination, item_count);
break;
case ACPI_RSC_COUNT_SERIAL_RES:
@@ -234,7 +234,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
- ACPI_GET16(source) - info->value;
resource->length = resource->length + item_count;
- ACPI_SET16(destination) = item_count;
+ ACPI_SET16(destination, item_count);
break;
case ACPI_RSC_LENGTH:
@@ -385,7 +385,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
}
target = ACPI_ADD_PTR(char, resource, info->value);
- ACPI_SET8(target) = (u8) item_count;
+ ACPI_SET8(target, item_count);
break;
case ACPI_RSC_BITMASK16:
@@ -401,7 +401,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
}
target = ACPI_ADD_PTR(char, resource, info->value);
- ACPI_SET8(target) = (u8) item_count;
+ ACPI_SET8(target, item_count);
break;
case ACPI_RSC_EXIT_NE:
@@ -514,37 +514,40 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
/*
* Clear the flag byte
*/
- ACPI_SET8(destination) = 0;
+ ACPI_SET8(destination, 0);
break;
case ACPI_RSC_1BITFLAG:
/*
* Mask and shift the flag bit
*/
- ACPI_SET8(destination) |= (u8)
- ((ACPI_GET8(source) & 0x01) << info->value);
+ ACPI_SET_BIT(*ACPI_CAST8(destination), (u8)
+ ((ACPI_GET8(source) & 0x01) << info->
+ value));
break;
case ACPI_RSC_2BITFLAG:
/*
* Mask and shift the flag bits
*/
- ACPI_SET8(destination) |= (u8)
- ((ACPI_GET8(source) & 0x03) << info->value);
+ ACPI_SET_BIT(*ACPI_CAST8(destination), (u8)
+ ((ACPI_GET8(source) & 0x03) << info->
+ value));
break;
case ACPI_RSC_3BITFLAG:
/*
* Mask and shift the flag bits
*/
- ACPI_SET8(destination) |= (u8)
- ((ACPI_GET8(source) & 0x07) << info->value);
+ ACPI_SET_BIT(*ACPI_CAST8(destination), (u8)
+ ((ACPI_GET8(source) & 0x07) << info->
+ value));
break;
case ACPI_RSC_COUNT:
item_count = ACPI_GET8(source);
- ACPI_SET8(destination) = (u8) item_count;
+ ACPI_SET8(destination, item_count);
aml_length =
(u16) (aml_length +
@@ -561,18 +564,18 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
case ACPI_RSC_COUNT_GPIO_PIN:
item_count = ACPI_GET16(source);
- ACPI_SET16(destination) = (u16)aml_length;
+ ACPI_SET16(destination, aml_length);
aml_length = (u16)(aml_length + item_count * 2);
target = ACPI_ADD_PTR(void, aml, info->value);
- ACPI_SET16(target) = (u16)aml_length;
+ ACPI_SET16(target, aml_length);
acpi_rs_set_resource_length(aml_length, aml);
break;
case ACPI_RSC_COUNT_GPIO_VEN:
item_count = ACPI_GET16(source);
- ACPI_SET16(destination) = (u16)item_count;
+ ACPI_SET16(destination, item_count);
aml_length =
(u16)(aml_length + (info->value * item_count));
@@ -584,7 +587,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
/* Set resource source string length */
item_count = ACPI_GET16(source);
- ACPI_SET16(destination) = (u16)aml_length;
+ ACPI_SET16(destination, aml_length);
/* Compute offset for the Vendor Data */
@@ -594,7 +597,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
/* Set vendor offset only if there is vendor data */
if (resource->data.gpio.vendor_length) {
- ACPI_SET16(target) = (u16)aml_length;
+ ACPI_SET16(target, aml_length);
}
acpi_rs_set_resource_length(aml_length, aml);
@@ -603,7 +606,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
case ACPI_RSC_COUNT_SERIAL_VEN:
item_count = ACPI_GET16(source);
- ACPI_SET16(destination) = item_count + info->value;
+ ACPI_SET16(destination, item_count + info->value);
aml_length = (u16)(aml_length + item_count);
acpi_rs_set_resource_length(aml_length, aml);
break;
@@ -686,7 +689,8 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
* Optional resource_source (Index and String)
*/
aml_length =
- acpi_rs_set_resource_source(aml, (acpi_rs_length)
+ acpi_rs_set_resource_source(aml,
+ (acpi_rs_length)
aml_length, source);
acpi_rs_set_resource_length(aml_length, aml);
break;
@@ -706,10 +710,12 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
/*
* 8-bit encoded bitmask (DMA macro)
*/
- ACPI_SET8(destination) = (u8)
- acpi_rs_encode_bitmask(source,
- *ACPI_ADD_PTR(u8, resource,
- info->value));
+ ACPI_SET8(destination,
+ acpi_rs_encode_bitmask(source,
+ *ACPI_ADD_PTR(u8,
+ resource,
+ info->
+ value)));
break;
case ACPI_RSC_BITMASK16:
diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c
index 9aa5e689b444..fe49fc43e10f 100644
--- a/drivers/acpi/acpica/rsserial.c
+++ b/drivers/acpi/acpica/rsserial.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -53,7 +53,7 @@ ACPI_MODULE_NAME("rsserial")
* acpi_rs_convert_gpio
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_convert_gpio[17] = {
+struct acpi_rsconvert_info acpi_rs_convert_gpio[18] = {
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_GPIO,
ACPI_RS_SIZE(struct acpi_resource_gpio),
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_gpio)},
@@ -75,10 +75,14 @@ struct acpi_rsconvert_info acpi_rs_convert_gpio[17] = {
AML_OFFSET(gpio.flags),
0},
- {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.sharable),
+ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.sharable),
AML_OFFSET(gpio.int_flags),
3},
+ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.wake_capable),
+ AML_OFFSET(gpio.int_flags),
+ 4},
+
{ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.io_restriction),
AML_OFFSET(gpio.int_flags),
0},
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index 37d5241c0acf..a44953c6f75d 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -108,7 +108,7 @@ u16 acpi_rs_encode_bitmask(u8 * list, u8 count)
mask |= (0x1 << list[i]);
}
- return mask;
+ return (mask);
}
/*******************************************************************************
@@ -358,8 +358,10 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length,
*
* Zero the entire area of the buffer.
*/
- total_length = (u32)
- ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1;
+ total_length =
+ (u32)
+ ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) +
+ 1;
total_length = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(total_length);
ACPI_MEMSET(resource_source->string_ptr, 0, total_length);
@@ -675,7 +677,9 @@ acpi_rs_get_method_data(acpi_handle handle,
/* Execute the method, no parameters */
status =
- acpi_ut_evaluate_object(handle, path, ACPI_BTYPE_BUFFER, &obj_desc);
+ acpi_ut_evaluate_object(ACPI_CAST_PTR
+ (struct acpi_namespace_node, handle), path,
+ ACPI_BTYPE_BUFFER, &obj_desc);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index 5aad744b5b83..15d6eaef0e28 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -423,7 +423,7 @@ ACPI_EXPORT_SYMBOL(acpi_resource_to_address64)
*
* RETURN: Status
*
- * DESCRIPTION: Walk a resource template for the specified evice to find a
+ * DESCRIPTION: Walk a resource template for the specified device to find a
* vendor-defined resource that matches the supplied UUID and
* UUID subtype. Returns a struct acpi_resource of type Vendor.
*
@@ -522,57 +522,42 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context)
/*******************************************************************************
*
- * FUNCTION: acpi_walk_resources
+ * FUNCTION: acpi_walk_resource_buffer
*
- * PARAMETERS: device_handle - Handle to the device object for the
- * device we are querying
- * name - Method name of the resources we want.
- * (METHOD_NAME__CRS, METHOD_NAME__PRS, or
- * METHOD_NAME__AEI)
+ * PARAMETERS: buffer - Formatted buffer returned by one of the
+ * various Get*Resource functions
* user_function - Called for each resource
* context - Passed to user_function
*
* RETURN: Status
*
- * DESCRIPTION: Retrieves the current or possible resource list for the
- * specified device. The user_function is called once for
- * each resource in the list.
+ * DESCRIPTION: Walks the input resource template. The user_function is called
+ * once for each resource in the list.
*
******************************************************************************/
+
acpi_status
-acpi_walk_resources(acpi_handle device_handle,
- char *name,
- acpi_walk_resource_callback user_function, void *context)
+acpi_walk_resource_buffer(struct acpi_buffer * buffer,
+ acpi_walk_resource_callback user_function,
+ void *context)
{
- acpi_status status;
- struct acpi_buffer buffer;
+ acpi_status status = AE_OK;
struct acpi_resource *resource;
struct acpi_resource *resource_end;
- ACPI_FUNCTION_TRACE(acpi_walk_resources);
+ ACPI_FUNCTION_TRACE(acpi_walk_resource_buffer);
/* Parameter validation */
- if (!device_handle || !user_function || !name ||
- (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) &&
- !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS) &&
- !ACPI_COMPARE_NAME(name, METHOD_NAME__AEI))) {
+ if (!buffer || !buffer->pointer || !user_function) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Get the _CRS/_PRS/_AEI resource list */
-
- buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
- status = acpi_rs_get_method_data(device_handle, name, &buffer);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Buffer now contains the resource list */
+ /* Buffer contains the resource list and length */
- resource = ACPI_CAST_PTR(struct acpi_resource, buffer.pointer);
+ resource = ACPI_CAST_PTR(struct acpi_resource, buffer->pointer);
resource_end =
- ACPI_ADD_PTR(struct acpi_resource, buffer.pointer, buffer.length);
+ ACPI_ADD_PTR(struct acpi_resource, buffer->pointer, buffer->length);
/* Walk the resource list until the end_tag is found (or buffer end) */
@@ -606,11 +591,63 @@ acpi_walk_resources(acpi_handle device_handle,
/* Get the next resource descriptor */
- resource =
- ACPI_ADD_PTR(struct acpi_resource, resource,
- resource->length);
+ resource = ACPI_NEXT_RESOURCE(resource);
}
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_walk_resource_buffer)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_walk_resources
+ *
+ * PARAMETERS: device_handle - Handle to the device object for the
+ * device we are querying
+ * name - Method name of the resources we want.
+ * (METHOD_NAME__CRS, METHOD_NAME__PRS, or
+ * METHOD_NAME__AEI)
+ * user_function - Called for each resource
+ * context - Passed to user_function
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieves the current or possible resource list for the
+ * specified device. The user_function is called once for
+ * each resource in the list.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_walk_resources(acpi_handle device_handle,
+ char *name,
+ acpi_walk_resource_callback user_function, void *context)
+{
+ acpi_status status;
+ struct acpi_buffer buffer;
+
+ ACPI_FUNCTION_TRACE(acpi_walk_resources);
+
+ /* Parameter validation */
+
+ if (!device_handle || !user_function || !name ||
+ (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) &&
+ !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS) &&
+ !ACPI_COMPARE_NAME(name, METHOD_NAME__AEI))) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Get the _CRS/_PRS/_AEI resource list */
+
+ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+ status = acpi_rs_get_method_data(device_handle, name, &buffer);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Walk the resource list and cleanup */
+
+ status = acpi_walk_resource_buffer(&buffer, user_function, context);
ACPI_FREE(buffer.pointer);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 390651860bf0..74181bf181ec 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -172,6 +172,7 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = {
* FUNCTION: acpi_tb_init_generic_address
*
* PARAMETERS: generic_address - GAS struct to be initialized
+ * space_id - ACPI Space ID for this register
* byte_width - Width of this register
* address - Address of the register
*
@@ -407,8 +408,8 @@ static void acpi_tb_convert_fadt(void)
* should be zero are indeed zero. This will workaround BIOSs that
* inadvertently place values in these fields.
*
- * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at
- * offset 45, 55, 95, and the word located at offset 109, 110.
+ * The ACPI 1.0 reserved fields that will be zeroed are the bytes located
+ * at offset 45, 55, 95, and the word located at offset 109, 110.
*
* Note: The FADT revision value is unreliable. Only the length can be
* trusted.
diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c
index 77d1db29a725..e4f4f02d49e7 100644
--- a/drivers/acpi/acpica/tbfind.c
+++ b/drivers/acpi/acpica/tbfind.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index f540ae462925..e57cd38004e3 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 285e24b97382..ce3d5db39a9c 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -147,7 +147,7 @@ acpi_status acpi_tb_initialize_facs(void)
ACPI_CAST_INDIRECT_PTR(struct
acpi_table_header,
&acpi_gbl_FACS));
- return status;
+ return (status);
}
#endif /* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index f5632780421d..b35a5e6d653a 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,6 @@
#include <linux/export.h>
#include <acpi/acpi.h>
#include "accommon.h"
-#include "acnamesp.h"
#include "actables.h"
#define _COMPONENT ACPI_TABLES
@@ -437,7 +436,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
*
******************************************************************************/
acpi_status
-acpi_install_table_handler(acpi_tbl_handler handler, void *context)
+acpi_install_table_handler(acpi_table_handler handler, void *context)
{
acpi_status status;
@@ -483,7 +482,7 @@ ACPI_EXPORT_SYMBOL(acpi_install_table_handler)
* DESCRIPTION: Remove table event handler
*
******************************************************************************/
-acpi_status acpi_remove_table_handler(acpi_tbl_handler handler)
+acpi_status acpi_remove_table_handler(acpi_table_handler handler)
{
acpi_status status;
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c
index a5e1e4e47098..67e046ec8f0a 100644
--- a/drivers/acpi/acpica/tbxfload.c
+++ b/drivers/acpi/acpica/tbxfload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -192,7 +192,7 @@ static acpi_status acpi_tb_load_namespace(void)
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
+ ACPI_INFO((AE_INFO, "All ACPI Tables successfully acquired"));
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index 28f330230f99..7c2ecfb7c2c3 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c
index 64880306133d..698b9d385516 100644
--- a/drivers/acpi/acpica/utaddress.c
+++ b/drivers/acpi/acpica/utaddress.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -214,7 +214,7 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id,
if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
(space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
- return_UINT32(0);
+ return_VALUE(0);
}
range_info = acpi_gbl_address_range_list[space_id];
@@ -256,7 +256,7 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id,
range_info = range_info->next;
}
- return_UINT32(overlap_count);
+ return_VALUE(overlap_count);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c
index ed29d474095e..e0ffb580f4b0 100644
--- a/drivers/acpi/acpica/utalloc.c
+++ b/drivers/acpi/acpica/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c
index e1d40ed26390..e0e8579deaac 100644
--- a/drivers/acpi/acpica/utcache.c
+++ b/drivers/acpi/acpica/utcache.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c
index 294692ae76e9..e4c9291fc0a3 100644
--- a/drivers/acpi/acpica/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -785,7 +785,7 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
status = acpi_os_create_mutex(&dest_desc->mutex.os_mutex);
if (ACPI_FAILURE(status)) {
- return status;
+ return (status);
}
break;
@@ -795,7 +795,7 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
&dest_desc->event.
os_semaphore);
if (ACPI_FAILURE(status)) {
- return status;
+ return (status);
}
break;
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c
index 5d95166245ae..c57d9cc07ba9 100644
--- a/drivers/acpi/acpica/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -166,11 +166,9 @@ acpi_debug_print(u32 requested_debug_level,
acpi_thread_id thread_id;
va_list args;
- /*
- * Stay silent if the debug level or component ID is disabled
- */
- if (!(requested_debug_level & acpi_dbg_level) ||
- !(component_id & acpi_dbg_layer)) {
+ /* Check if debug output enabled */
+
+ if (!ACPI_IS_DEBUG_ENABLED(requested_debug_level, component_id)) {
return;
}
@@ -236,8 +234,9 @@ acpi_debug_print_raw(u32 requested_debug_level,
{
va_list args;
- if (!(requested_debug_level & acpi_dbg_level) ||
- !(component_id & acpi_dbg_layer)) {
+ /* Check if debug output enabled */
+
+ if (!ACPI_IS_DEBUG_ENABLED(requested_debug_level, component_id)) {
return;
}
@@ -272,9 +271,13 @@ acpi_ut_trace(u32 line_number,
acpi_gbl_nesting_level++;
acpi_ut_track_stack_ptr();
- acpi_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name, component_id,
- "%s\n", acpi_gbl_fn_entry_str);
+ /* Check if enabled up-front for performance */
+
+ if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name,
+ component_id, "%s\n", acpi_gbl_fn_entry_str);
+ }
}
ACPI_EXPORT_SYMBOL(acpi_ut_trace)
@@ -304,9 +307,14 @@ acpi_ut_trace_ptr(u32 line_number,
acpi_gbl_nesting_level++;
acpi_ut_track_stack_ptr();
- acpi_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name, component_id,
- "%s %p\n", acpi_gbl_fn_entry_str, pointer);
+ /* Check if enabled up-front for performance */
+
+ if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name,
+ component_id, "%s %p\n", acpi_gbl_fn_entry_str,
+ pointer);
+ }
}
/*******************************************************************************
@@ -335,9 +343,14 @@ acpi_ut_trace_str(u32 line_number,
acpi_gbl_nesting_level++;
acpi_ut_track_stack_ptr();
- acpi_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name, component_id,
- "%s %s\n", acpi_gbl_fn_entry_str, string);
+ /* Check if enabled up-front for performance */
+
+ if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name,
+ component_id, "%s %s\n", acpi_gbl_fn_entry_str,
+ string);
+ }
}
/*******************************************************************************
@@ -366,9 +379,14 @@ acpi_ut_trace_u32(u32 line_number,
acpi_gbl_nesting_level++;
acpi_ut_track_stack_ptr();
- acpi_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name, component_id,
- "%s %08X\n", acpi_gbl_fn_entry_str, integer);
+ /* Check if enabled up-front for performance */
+
+ if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name,
+ component_id, "%s %08X\n",
+ acpi_gbl_fn_entry_str, integer);
+ }
}
/*******************************************************************************
@@ -393,9 +411,13 @@ acpi_ut_exit(u32 line_number,
const char *module_name, u32 component_id)
{
- acpi_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name, component_id,
- "%s\n", acpi_gbl_fn_exit_str);
+ /* Check if enabled up-front for performance */
+
+ if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name,
+ component_id, "%s\n", acpi_gbl_fn_exit_str);
+ }
acpi_gbl_nesting_level--;
}
@@ -425,17 +447,23 @@ acpi_ut_status_exit(u32 line_number,
u32 component_id, acpi_status status)
{
- if (ACPI_SUCCESS(status)) {
- acpi_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s %s\n", acpi_gbl_fn_exit_str,
- acpi_format_exception(status));
- } else {
- acpi_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s ****Exception****: %s\n",
- acpi_gbl_fn_exit_str,
- acpi_format_exception(status));
+ /* Check if enabled up-front for performance */
+
+ if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+ if (ACPI_SUCCESS(status)) {
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name,
+ module_name, component_id, "%s %s\n",
+ acpi_gbl_fn_exit_str,
+ acpi_format_exception(status));
+ } else {
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name,
+ module_name, component_id,
+ "%s ****Exception****: %s\n",
+ acpi_gbl_fn_exit_str,
+ acpi_format_exception(status));
+ }
}
acpi_gbl_nesting_level--;
@@ -465,10 +493,15 @@ acpi_ut_value_exit(u32 line_number,
const char *module_name, u32 component_id, u64 value)
{
- acpi_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name, component_id,
- "%s %8.8X%8.8X\n", acpi_gbl_fn_exit_str,
- ACPI_FORMAT_UINT64(value));
+ /* Check if enabled up-front for performance */
+
+ if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name,
+ component_id, "%s %8.8X%8.8X\n",
+ acpi_gbl_fn_exit_str,
+ ACPI_FORMAT_UINT64(value));
+ }
acpi_gbl_nesting_level--;
}
@@ -497,9 +530,14 @@ acpi_ut_ptr_exit(u32 line_number,
const char *module_name, u32 component_id, u8 *ptr)
{
- acpi_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name, component_id,
- "%s %p\n", acpi_gbl_fn_exit_str, ptr);
+ /* Check if enabled up-front for performance */
+
+ if (ACPI_IS_DEBUG_ENABLED(ACPI_LV_FUNCTIONS, component_id)) {
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name,
+ component_id, "%s %p\n", acpi_gbl_fn_exit_str,
+ ptr);
+ }
acpi_gbl_nesting_level--;
}
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index 60a158472d82..11e2e02e1618 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index 798105443d0f..2541de420249 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -340,7 +340,7 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list)
{
union acpi_operand_object **internal_obj;
- ACPI_FUNCTION_TRACE(ut_delete_internal_object_list);
+ ACPI_FUNCTION_ENTRY();
/* Walk the null-terminated internal list */
@@ -351,7 +351,7 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list)
/* Free the combined parameter pointer list and object array */
ACPI_FREE(obj_list);
- return_VOID;
+ return;
}
/*******************************************************************************
@@ -484,7 +484,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
union acpi_generic_state *state;
u32 i;
- ACPI_FUNCTION_TRACE_PTR(ut_update_object_reference, object);
+ ACPI_FUNCTION_NAME(ut_update_object_reference);
while (object) {
@@ -493,7 +493,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
if (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED) {
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"Object %p is NS handle\n", object));
- return_ACPI_STATUS(AE_OK);
+ return (AE_OK);
}
/*
@@ -530,18 +530,42 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
*/
for (i = 0; i < object->package.count; i++) {
/*
- * Push each element onto the stack for later processing.
- * Note: There can be null elements within the package,
- * these are simply ignored
+ * Null package elements are legal and can be simply
+ * ignored.
*/
- status =
- acpi_ut_create_update_state_and_push
- (object->package.elements[i], action,
- &state_list);
- if (ACPI_FAILURE(status)) {
- goto error_exit;
+ next_object = object->package.elements[i];
+ if (!next_object) {
+ continue;
+ }
+
+ switch (next_object->common.type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+ /*
+ * For these very simple sub-objects, we can just
+ * update the reference count here and continue.
+ * Greatly increases performance of this operation.
+ */
+ acpi_ut_update_ref_count(next_object,
+ action);
+ break;
+
+ default:
+ /*
+ * For complex sub-objects, push them onto the stack
+ * for later processing (this eliminates recursion.)
+ */
+ status =
+ acpi_ut_create_update_state_and_push
+ (next_object, action, &state_list);
+ if (ACPI_FAILURE(status)) {
+ goto error_exit;
+ }
+ break;
}
}
+ next_object = NULL;
break;
case ACPI_TYPE_BUFFER_FIELD:
@@ -619,7 +643,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
}
}
- return_ACPI_STATUS(AE_OK);
+ return (AE_OK);
error_exit:
@@ -633,7 +657,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
acpi_ut_delete_generic_state(state);
}
- return_ACPI_STATUS(status);
+ return (status);
}
/*******************************************************************************
@@ -652,12 +676,12 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
void acpi_ut_add_reference(union acpi_operand_object *object)
{
- ACPI_FUNCTION_TRACE_PTR(ut_add_reference, object);
+ ACPI_FUNCTION_NAME(ut_add_reference);
/* Ensure that we have a valid object */
if (!acpi_ut_valid_internal_object(object)) {
- return_VOID;
+ return;
}
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
@@ -667,7 +691,7 @@ void acpi_ut_add_reference(union acpi_operand_object *object)
/* Increment the reference count */
(void)acpi_ut_update_object_reference(object, REF_INCREMENT);
- return_VOID;
+ return;
}
/*******************************************************************************
@@ -685,7 +709,7 @@ void acpi_ut_add_reference(union acpi_operand_object *object)
void acpi_ut_remove_reference(union acpi_operand_object *object)
{
- ACPI_FUNCTION_TRACE_PTR(ut_remove_reference, object);
+ ACPI_FUNCTION_NAME(ut_remove_reference);
/*
* Allow a NULL pointer to be passed in, just ignore it. This saves
@@ -694,13 +718,13 @@ void acpi_ut_remove_reference(union acpi_operand_object *object)
*/
if (!object ||
(ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED)) {
- return_VOID;
+ return;
}
/* Ensure that we have a valid object */
if (!acpi_ut_valid_internal_object(object)) {
- return_VOID;
+ return;
}
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
@@ -713,5 +737,5 @@ void acpi_ut_remove_reference(union acpi_operand_object *object)
* of all subobjects!)
*/
(void)acpi_ut_update_object_reference(object, REF_DECREMENT);
- return_VOID;
+ return;
}
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index a9c65fbea5f4..c3f3a7e7bdc7 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -68,7 +68,7 @@ ACPI_MODULE_NAME("uteval")
******************************************************************************/
acpi_status
-acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
+acpi_ut_evaluate_object(struct acpi_namespace_node * prefix_node,
char *path,
u32 expected_return_btypes,
union acpi_operand_object **return_desc)
diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c
index 23b98945f6b7..a0ab7c02e87c 100644
--- a/drivers/acpi/acpica/utexcep.c
+++ b/drivers/acpi/acpica/utexcep.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index ed1893155f8b..ffecf4b4f0dd 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -293,11 +293,11 @@ acpi_status acpi_ut_init_globals(void)
/* GPE support */
+ acpi_gbl_all_gpes_initialized = FALSE;
acpi_gbl_gpe_xrupt_list_head = NULL;
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
acpi_current_gpe_count = 0;
- acpi_gbl_all_gpes_initialized = FALSE;
acpi_gbl_global_event_handler = NULL;
@@ -357,17 +357,24 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_root_node_struct.peer = NULL;
acpi_gbl_root_node_struct.object = NULL;
+#ifdef ACPI_DISASSEMBLER
+ acpi_gbl_external_list = NULL;
+#endif
+
#ifdef ACPI_DEBUG_OUTPUT
acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX);
#endif
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
acpi_gbl_display_final_mem_stats = FALSE;
+ acpi_gbl_disable_mem_tracking = FALSE;
#endif
return_ACPI_STATUS(AE_OK);
}
+/* Public globals */
+
ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
index 774c3aefbf5d..43a170a74a61 100644
--- a/drivers/acpi/acpica/utids.c
+++ b/drivers/acpi/acpica/utids.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index 246798e4c938..c5d1ac44c07d 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c
index b1eb7f17e110..5c26ad420344 100644
--- a/drivers/acpi/acpica/utlock.c
+++ b/drivers/acpi/acpica/utlock.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,11 +66,11 @@ acpi_status acpi_ut_create_rw_lock(struct acpi_rw_lock *lock)
lock->num_readers = 0;
status = acpi_os_create_mutex(&lock->reader_mutex);
if (ACPI_FAILURE(status)) {
- return status;
+ return (status);
}
status = acpi_os_create_mutex(&lock->writer_mutex);
- return status;
+ return (status);
}
void acpi_ut_delete_rw_lock(struct acpi_rw_lock *lock)
@@ -108,7 +108,7 @@ acpi_status acpi_ut_acquire_read_lock(struct acpi_rw_lock *lock)
status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(status)) {
- return status;
+ return (status);
}
/* Acquire the write lock only for the first reader */
@@ -121,7 +121,7 @@ acpi_status acpi_ut_acquire_read_lock(struct acpi_rw_lock *lock)
}
acpi_os_release_mutex(lock->reader_mutex);
- return status;
+ return (status);
}
acpi_status acpi_ut_release_read_lock(struct acpi_rw_lock *lock)
@@ -130,7 +130,7 @@ acpi_status acpi_ut_release_read_lock(struct acpi_rw_lock *lock)
status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER);
if (ACPI_FAILURE(status)) {
- return status;
+ return (status);
}
/* Release the write lock only for the very last reader */
@@ -141,7 +141,7 @@ acpi_status acpi_ut_release_read_lock(struct acpi_rw_lock *lock)
}
acpi_os_release_mutex(lock->reader_mutex);
- return status;
+ return (status);
}
/*******************************************************************************
@@ -165,7 +165,7 @@ acpi_status acpi_ut_acquire_write_lock(struct acpi_rw_lock *lock)
acpi_status status;
status = acpi_os_acquire_mutex(lock->writer_mutex, ACPI_WAIT_FOREVER);
- return status;
+ return (status);
}
void acpi_ut_release_write_lock(struct acpi_rw_lock *lock)
diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c
index 49563674833a..909fe66e1934 100644
--- a/drivers/acpi/acpica/utmath.c
+++ b/drivers/acpi/acpica/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index 9286a69eb9aa..785fdd07ae56 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,36 +48,6 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utmisc")
-#if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP
-/*******************************************************************************
- *
- * FUNCTION: ut_convert_backslashes
- *
- * PARAMETERS: pathname - File pathname string to be converted
- *
- * RETURN: Modifies the input Pathname
- *
- * DESCRIPTION: Convert all backslashes (0x5C) to forward slashes (0x2F) within
- * the entire input file pathname string.
- *
- ******************************************************************************/
-void ut_convert_backslashes(char *pathname)
-{
-
- if (!pathname) {
- return;
- }
-
- while (*pathname) {
- if (*pathname == '\\') {
- *pathname = '/';
- }
-
- pathname++;
- }
-}
-#endif
-
/*******************************************************************************
*
* FUNCTION: acpi_ut_is_pci_root_bridge
@@ -89,7 +59,6 @@ void ut_convert_backslashes(char *pathname)
* DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
*
******************************************************************************/
-
u8 acpi_ut_is_pci_root_bridge(char *id)
{
@@ -136,362 +105,6 @@ u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
/*******************************************************************************
*
- * FUNCTION: acpi_ut_allocate_owner_id
- *
- * PARAMETERS: owner_id - Where the new owner ID is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Allocate a table or method owner ID. The owner ID is used to
- * track objects created by the table or method, to be deleted
- * when the method exits or the table is unloaded.
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id)
-{
- u32 i;
- u32 j;
- u32 k;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ut_allocate_owner_id);
-
- /* Guard against multiple allocations of ID to the same location */
-
- if (*owner_id) {
- ACPI_ERROR((AE_INFO, "Owner ID [0x%2.2X] already exists",
- *owner_id));
- return_ACPI_STATUS(AE_ALREADY_EXISTS);
- }
-
- /* Mutex for the global ID mask */
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /*
- * Find a free owner ID, cycle through all possible IDs on repeated
- * allocations. (ACPI_NUM_OWNERID_MASKS + 1) because first index may have
- * to be scanned twice.
- */
- for (i = 0, j = acpi_gbl_last_owner_id_index;
- i < (ACPI_NUM_OWNERID_MASKS + 1); i++, j++) {
- if (j >= ACPI_NUM_OWNERID_MASKS) {
- j = 0; /* Wraparound to start of mask array */
- }
-
- for (k = acpi_gbl_next_owner_id_offset; k < 32; k++) {
- if (acpi_gbl_owner_id_mask[j] == ACPI_UINT32_MAX) {
-
- /* There are no free IDs in this mask */
-
- break;
- }
-
- if (!(acpi_gbl_owner_id_mask[j] & (1 << k))) {
- /*
- * Found a free ID. The actual ID is the bit index plus one,
- * making zero an invalid Owner ID. Save this as the last ID
- * allocated and update the global ID mask.
- */
- acpi_gbl_owner_id_mask[j] |= (1 << k);
-
- acpi_gbl_last_owner_id_index = (u8)j;
- acpi_gbl_next_owner_id_offset = (u8)(k + 1);
-
- /*
- * Construct encoded ID from the index and bit position
- *
- * Note: Last [j].k (bit 255) is never used and is marked
- * permanently allocated (prevents +1 overflow)
- */
- *owner_id =
- (acpi_owner_id) ((k + 1) + ACPI_MUL_32(j));
-
- ACPI_DEBUG_PRINT((ACPI_DB_VALUES,
- "Allocated OwnerId: %2.2X\n",
- (unsigned int)*owner_id));
- goto exit;
- }
- }
-
- acpi_gbl_next_owner_id_offset = 0;
- }
-
- /*
- * All owner_ids have been allocated. This typically should
- * not happen since the IDs are reused after deallocation. The IDs are
- * allocated upon table load (one per table) and method execution, and
- * they are released when a table is unloaded or a method completes
- * execution.
- *
- * If this error happens, there may be very deep nesting of invoked control
- * methods, or there may be a bug where the IDs are not released.
- */
- status = AE_OWNER_ID_LIMIT;
- ACPI_ERROR((AE_INFO,
- "Could not allocate new OwnerId (255 max), AE_OWNER_ID_LIMIT"));
-
- exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_release_owner_id
- *
- * PARAMETERS: owner_id_ptr - Pointer to a previously allocated owner_ID
- *
- * RETURN: None. No error is returned because we are either exiting a
- * control method or unloading a table. Either way, we would
- * ignore any error anyway.
- *
- * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255
- *
- ******************************************************************************/
-
-void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr)
-{
- acpi_owner_id owner_id = *owner_id_ptr;
- acpi_status status;
- u32 index;
- u32 bit;
-
- ACPI_FUNCTION_TRACE_U32(ut_release_owner_id, owner_id);
-
- /* Always clear the input owner_id (zero is an invalid ID) */
-
- *owner_id_ptr = 0;
-
- /* Zero is not a valid owner_ID */
-
- if (owner_id == 0) {
- ACPI_ERROR((AE_INFO, "Invalid OwnerId: 0x%2.2X", owner_id));
- return_VOID;
- }
-
- /* Mutex for the global ID mask */
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
- if (ACPI_FAILURE(status)) {
- return_VOID;
- }
-
- /* Normalize the ID to zero */
-
- owner_id--;
-
- /* Decode ID to index/offset pair */
-
- index = ACPI_DIV_32(owner_id);
- bit = 1 << ACPI_MOD_32(owner_id);
-
- /* Free the owner ID only if it is valid */
-
- if (acpi_gbl_owner_id_mask[index] & bit) {
- acpi_gbl_owner_id_mask[index] ^= bit;
- } else {
- ACPI_ERROR((AE_INFO,
- "Release of non-allocated OwnerId: 0x%2.2X",
- owner_id + 1));
- }
-
- (void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
- return_VOID;
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_strupr (strupr)
- *
- * PARAMETERS: src_string - The source string to convert
- *
- * RETURN: None
- *
- * DESCRIPTION: Convert string to uppercase
- *
- * NOTE: This is not a POSIX function, so it appears here, not in utclib.c
- *
- ******************************************************************************/
-
-void acpi_ut_strupr(char *src_string)
-{
- char *string;
-
- ACPI_FUNCTION_ENTRY();
-
- if (!src_string) {
- return;
- }
-
- /* Walk entire string, uppercasing the letters */
-
- for (string = src_string; *string; string++) {
- *string = (char)ACPI_TOUPPER(*string);
- }
-
- return;
-}
-
-#ifdef ACPI_ASL_COMPILER
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_strlwr (strlwr)
- *
- * PARAMETERS: src_string - The source string to convert
- *
- * RETURN: None
- *
- * DESCRIPTION: Convert string to lowercase
- *
- * NOTE: This is not a POSIX function, so it appears here, not in utclib.c
- *
- ******************************************************************************/
-
-void acpi_ut_strlwr(char *src_string)
-{
- char *string;
-
- ACPI_FUNCTION_ENTRY();
-
- if (!src_string) {
- return;
- }
-
- /* Walk entire string, lowercasing the letters */
-
- for (string = src_string; *string; string++) {
- *string = (char)ACPI_TOLOWER(*string);
- }
-
- return;
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_ut_stricmp
- *
- * PARAMETERS: string1 - first string to compare
- * string2 - second string to compare
- *
- * RETURN: int that signifies string relationship. Zero means strings
- * are equal.
- *
- * DESCRIPTION: Implementation of the non-ANSI stricmp function (compare
- * strings with no case sensitivity)
- *
- ******************************************************************************/
-
-int acpi_ut_stricmp(char *string1, char *string2)
-{
- int c1;
- int c2;
-
- do {
- c1 = tolower((int)*string1);
- c2 = tolower((int)*string2);
-
- string1++;
- string2++;
- }
- while ((c1 == c2) && (c1));
-
- return (c1 - c2);
-}
-#endif
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_print_string
- *
- * PARAMETERS: string - Null terminated ASCII string
- * max_length - Maximum output length
- *
- * RETURN: None
- *
- * DESCRIPTION: Dump an ASCII string with support for ACPI-defined escape
- * sequences.
- *
- ******************************************************************************/
-
-void acpi_ut_print_string(char *string, u8 max_length)
-{
- u32 i;
-
- if (!string) {
- acpi_os_printf("<\"NULL STRING PTR\">");
- return;
- }
-
- acpi_os_printf("\"");
- for (i = 0; string[i] && (i < max_length); i++) {
-
- /* Escape sequences */
-
- switch (string[i]) {
- case 0x07:
- acpi_os_printf("\\a"); /* BELL */
- break;
-
- case 0x08:
- acpi_os_printf("\\b"); /* BACKSPACE */
- break;
-
- case 0x0C:
- acpi_os_printf("\\f"); /* FORMFEED */
- break;
-
- case 0x0A:
- acpi_os_printf("\\n"); /* LINEFEED */
- break;
-
- case 0x0D:
- acpi_os_printf("\\r"); /* CARRIAGE RETURN */
- break;
-
- case 0x09:
- acpi_os_printf("\\t"); /* HORIZONTAL TAB */
- break;
-
- case 0x0B:
- acpi_os_printf("\\v"); /* VERTICAL TAB */
- break;
-
- case '\'': /* Single Quote */
- case '\"': /* Double Quote */
- case '\\': /* Backslash */
- acpi_os_printf("\\%c", (int)string[i]);
- break;
-
- default:
-
- /* Check for printable character or hex escape */
-
- if (ACPI_IS_PRINT(string[i])) {
- /* This is a normal character */
-
- acpi_os_printf("%c", (int)string[i]);
- } else {
- /* All others will be Hex escapes */
-
- acpi_os_printf("\\x%2.2X", (s32) string[i]);
- }
- break;
- }
- }
- acpi_os_printf("\"");
-
- if (i == max_length && string[i]) {
- acpi_os_printf("...");
- }
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ut_dword_byte_swap
*
* PARAMETERS: value - Value to be converted
@@ -559,379 +172,6 @@ void acpi_ut_set_integer_width(u8 revision)
}
}
-#ifdef ACPI_DEBUG_OUTPUT
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_display_init_pathname
- *
- * PARAMETERS: type - Object type of the node
- * obj_handle - Handle whose pathname will be displayed
- * path - Additional path string to be appended.
- * (NULL if no extra path)
- *
- * RETURN: acpi_status
- *
- * DESCRIPTION: Display full pathname of an object, DEBUG ONLY
- *
- ******************************************************************************/
-
-void
-acpi_ut_display_init_pathname(u8 type,
- struct acpi_namespace_node *obj_handle,
- char *path)
-{
- acpi_status status;
- struct acpi_buffer buffer;
-
- ACPI_FUNCTION_ENTRY();
-
- /* Only print the path if the appropriate debug level is enabled */
-
- if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
- return;
- }
-
- /* Get the full pathname to the node */
-
- buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
- status = acpi_ns_handle_to_pathname(obj_handle, &buffer);
- if (ACPI_FAILURE(status)) {
- return;
- }
-
- /* Print what we're doing */
-
- switch (type) {
- case ACPI_TYPE_METHOD:
- acpi_os_printf("Executing ");
- break;
-
- default:
- acpi_os_printf("Initializing ");
- break;
- }
-
- /* Print the object type and pathname */
-
- acpi_os_printf("%-12s %s",
- acpi_ut_get_type_name(type), (char *)buffer.pointer);
-
- /* Extra path is used to append names like _STA, _INI, etc. */
-
- if (path) {
- acpi_os_printf(".%s", path);
- }
- acpi_os_printf("\n");
-
- ACPI_FREE(buffer.pointer);
-}
-#endif
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_valid_acpi_char
- *
- * PARAMETERS: char - The character to be examined
- * position - Byte position (0-3)
- *
- * RETURN: TRUE if the character is valid, FALSE otherwise
- *
- * DESCRIPTION: Check for a valid ACPI character. Must be one of:
- * 1) Upper case alpha
- * 2) numeric
- * 3) underscore
- *
- * We allow a '!' as the last character because of the ASF! table
- *
- ******************************************************************************/
-
-u8 acpi_ut_valid_acpi_char(char character, u32 position)
-{
-
- if (!((character >= 'A' && character <= 'Z') ||
- (character >= '0' && character <= '9') || (character == '_'))) {
-
- /* Allow a '!' in the last position */
-
- if (character == '!' && position == 3) {
- return (TRUE);
- }
-
- return (FALSE);
- }
-
- return (TRUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_valid_acpi_name
- *
- * PARAMETERS: name - The name to be examined
- *
- * RETURN: TRUE if the name is valid, FALSE otherwise
- *
- * DESCRIPTION: Check for a valid ACPI name. Each character must be one of:
- * 1) Upper case alpha
- * 2) numeric
- * 3) underscore
- *
- ******************************************************************************/
-
-u8 acpi_ut_valid_acpi_name(u32 name)
-{
- u32 i;
-
- ACPI_FUNCTION_ENTRY();
-
- for (i = 0; i < ACPI_NAME_SIZE; i++) {
- if (!acpi_ut_valid_acpi_char
- ((ACPI_CAST_PTR(char, &name))[i], i)) {
- return (FALSE);
- }
- }
-
- return (TRUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_repair_name
- *
- * PARAMETERS: name - The ACPI name to be repaired
- *
- * RETURN: Repaired version of the name
- *
- * DESCRIPTION: Repair an ACPI name: Change invalid characters to '*' and
- * return the new name. NOTE: the Name parameter must reside in
- * read/write memory, cannot be a const.
- *
- * An ACPI Name must consist of valid ACPI characters. We will repair the name
- * if necessary because we don't want to abort because of this, but we want
- * all namespace names to be printable. A warning message is appropriate.
- *
- * This issue came up because there are in fact machines that exhibit
- * this problem, and we want to be able to enable ACPI support for them,
- * even though there are a few bad names.
- *
- ******************************************************************************/
-
-void acpi_ut_repair_name(char *name)
-{
- u32 i;
- u8 found_bad_char = FALSE;
- u32 original_name;
-
- ACPI_FUNCTION_NAME(ut_repair_name);
-
- ACPI_MOVE_NAME(&original_name, name);
-
- /* Check each character in the name */
-
- for (i = 0; i < ACPI_NAME_SIZE; i++) {
- if (acpi_ut_valid_acpi_char(name[i], i)) {
- continue;
- }
-
- /*
- * Replace a bad character with something printable, yet technically
- * still invalid. This prevents any collisions with existing "good"
- * names in the namespace.
- */
- name[i] = '*';
- found_bad_char = TRUE;
- }
-
- if (found_bad_char) {
-
- /* Report warning only if in strict mode or debug mode */
-
- if (!acpi_gbl_enable_interpreter_slack) {
- ACPI_WARNING((AE_INFO,
- "Found bad character(s) in name, repaired: [%4.4s]\n",
- name));
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found bad character(s) in name, repaired: [%4.4s]\n",
- name));
- }
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_strtoul64
- *
- * PARAMETERS: string - Null terminated string
- * base - Radix of the string: 16 or ACPI_ANY_BASE;
- * ACPI_ANY_BASE means 'in behalf of to_integer'
- * ret_integer - Where the converted integer is returned
- *
- * RETURN: Status and Converted value
- *
- * DESCRIPTION: Convert a string into an unsigned value. Performs either a
- * 32-bit or 64-bit conversion, depending on the current mode
- * of the interpreter.
- * NOTE: Does not support Octal strings, not needed.
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
-{
- u32 this_digit = 0;
- u64 return_value = 0;
- u64 quotient;
- u64 dividend;
- u32 to_integer_op = (base == ACPI_ANY_BASE);
- u32 mode32 = (acpi_gbl_integer_byte_width == 4);
- u8 valid_digits = 0;
- u8 sign_of0x = 0;
- u8 term = 0;
-
- ACPI_FUNCTION_TRACE_STR(ut_stroul64, string);
-
- switch (base) {
- case ACPI_ANY_BASE:
- case 16:
- break;
-
- default:
- /* Invalid Base */
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- if (!string) {
- goto error_exit;
- }
-
- /* Skip over any white space in the buffer */
-
- while ((*string) && (ACPI_IS_SPACE(*string) || *string == '\t')) {
- string++;
- }
-
- if (to_integer_op) {
- /*
- * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'.
- * We need to determine if it is decimal or hexadecimal.
- */
- if ((*string == '0') && (ACPI_TOLOWER(*(string + 1)) == 'x')) {
- sign_of0x = 1;
- base = 16;
-
- /* Skip over the leading '0x' */
- string += 2;
- } else {
- base = 10;
- }
- }
-
- /* Any string left? Check that '0x' is not followed by white space. */
-
- if (!(*string) || ACPI_IS_SPACE(*string) || *string == '\t') {
- if (to_integer_op) {
- goto error_exit;
- } else {
- goto all_done;
- }
- }
-
- /*
- * Perform a 32-bit or 64-bit conversion, depending upon the current
- * execution mode of the interpreter
- */
- dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX;
-
- /* Main loop: convert the string to a 32- or 64-bit integer */
-
- while (*string) {
- if (ACPI_IS_DIGIT(*string)) {
-
- /* Convert ASCII 0-9 to Decimal value */
-
- this_digit = ((u8)*string) - '0';
- } else if (base == 10) {
-
- /* Digit is out of range; possible in to_integer case only */
-
- term = 1;
- } else {
- this_digit = (u8)ACPI_TOUPPER(*string);
- if (ACPI_IS_XDIGIT((char)this_digit)) {
-
- /* Convert ASCII Hex char to value */
-
- this_digit = this_digit - 'A' + 10;
- } else {
- term = 1;
- }
- }
-
- if (term) {
- if (to_integer_op) {
- goto error_exit;
- } else {
- break;
- }
- } else if ((valid_digits == 0) && (this_digit == 0)
- && !sign_of0x) {
-
- /* Skip zeros */
- string++;
- continue;
- }
-
- valid_digits++;
-
- if (sign_of0x
- && ((valid_digits > 16)
- || ((valid_digits > 8) && mode32))) {
- /*
- * This is to_integer operation case.
- * No any restrictions for string-to-integer conversion,
- * see ACPI spec.
- */
- goto error_exit;
- }
-
- /* Divide the digit into the correct position */
-
- (void)acpi_ut_short_divide((dividend - (u64)this_digit),
- base, &quotient, NULL);
-
- if (return_value > quotient) {
- if (to_integer_op) {
- goto error_exit;
- } else {
- break;
- }
- }
-
- return_value *= base;
- return_value += this_digit;
- string++;
- }
-
- /* All done, normal exit */
-
- all_done:
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n",
- ACPI_FORMAT_UINT64(return_value)));
-
- *ret_integer = return_value;
- return_ACPI_STATUS(AE_OK);
-
- error_exit:
- /* Base was set/validated above */
-
- if (base == 10) {
- return_ACPI_STATUS(AE_BAD_DECIMAL_CONSTANT);
- } else {
- return_ACPI_STATUS(AE_BAD_HEX_CONSTANT);
- }
-}
-
/*******************************************************************************
*
* FUNCTION: acpi_ut_create_update_state_and_push
@@ -1097,3 +337,71 @@ acpi_ut_walk_package_tree(union acpi_operand_object *source_object,
return_ACPI_STATUS(AE_AML_INTERNAL);
}
+
+#ifdef ACPI_DEBUG_OUTPUT
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_display_init_pathname
+ *
+ * PARAMETERS: type - Object type of the node
+ * obj_handle - Handle whose pathname will be displayed
+ * path - Additional path string to be appended.
+ * (NULL if no extra path)
+ *
+ * RETURN: acpi_status
+ *
+ * DESCRIPTION: Display full pathname of an object, DEBUG ONLY
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_display_init_pathname(u8 type,
+ struct acpi_namespace_node *obj_handle,
+ char *path)
+{
+ acpi_status status;
+ struct acpi_buffer buffer;
+
+ ACPI_FUNCTION_ENTRY();
+
+ /* Only print the path if the appropriate debug level is enabled */
+
+ if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
+ return;
+ }
+
+ /* Get the full pathname to the node */
+
+ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+ status = acpi_ns_handle_to_pathname(obj_handle, &buffer);
+ if (ACPI_FAILURE(status)) {
+ return;
+ }
+
+ /* Print what we're doing */
+
+ switch (type) {
+ case ACPI_TYPE_METHOD:
+ acpi_os_printf("Executing ");
+ break;
+
+ default:
+ acpi_os_printf("Initializing ");
+ break;
+ }
+
+ /* Print the object type and pathname */
+
+ acpi_os_printf("%-12s %s",
+ acpi_ut_get_type_name(type), (char *)buffer.pointer);
+
+ /* Extra path is used to append names like _STA, _INI, etc. */
+
+ if (path) {
+ acpi_os_printf(".%s", path);
+ }
+ acpi_os_printf("\n");
+
+ ACPI_FREE(buffer.pointer);
+}
+#endif
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index 5ccf57c0d87e..22feb99b8e35 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c
index 5c52ca78f6fa..1099f5c069f8 100644
--- a/drivers/acpi/acpica/utobject.c
+++ b/drivers/acpi/acpica/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -419,7 +419,7 @@ void acpi_ut_delete_object_desc(union acpi_operand_object *object)
{
ACPI_FUNCTION_TRACE_PTR(ut_delete_object_desc, object);
- /* Object must be a union acpi_operand_object */
+ /* Object must be of type union acpi_operand_object */
if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) {
ACPI_ERROR((AE_INFO,
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
index 676285d6116d..36a7d361d7cb 100644
--- a/drivers/acpi/acpica/utosi.c
+++ b/drivers/acpi/acpica/utosi.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c
new file mode 100644
index 000000000000..835340b26d37
--- /dev/null
+++ b/drivers/acpi/acpica/utownerid.c
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ *
+ * Module Name: utownerid - Support for Table/Method Owner IDs
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT ACPI_UTILITIES
+ACPI_MODULE_NAME("utownerid")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_allocate_owner_id
+ *
+ * PARAMETERS: owner_id - Where the new owner ID is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Allocate a table or method owner ID. The owner ID is used to
+ * track objects created by the table or method, to be deleted
+ * when the method exits or the table is unloaded.
+ *
+ ******************************************************************************/
+acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id)
+{
+ u32 i;
+ u32 j;
+ u32 k;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ut_allocate_owner_id);
+
+ /* Guard against multiple allocations of ID to the same location */
+
+ if (*owner_id) {
+ ACPI_ERROR((AE_INFO, "Owner ID [0x%2.2X] already exists",
+ *owner_id));
+ return_ACPI_STATUS(AE_ALREADY_EXISTS);
+ }
+
+ /* Mutex for the global ID mask */
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Find a free owner ID, cycle through all possible IDs on repeated
+ * allocations. (ACPI_NUM_OWNERID_MASKS + 1) because first index may have
+ * to be scanned twice.
+ */
+ for (i = 0, j = acpi_gbl_last_owner_id_index;
+ i < (ACPI_NUM_OWNERID_MASKS + 1); i++, j++) {
+ if (j >= ACPI_NUM_OWNERID_MASKS) {
+ j = 0; /* Wraparound to start of mask array */
+ }
+
+ for (k = acpi_gbl_next_owner_id_offset; k < 32; k++) {
+ if (acpi_gbl_owner_id_mask[j] == ACPI_UINT32_MAX) {
+
+ /* There are no free IDs in this mask */
+
+ break;
+ }
+
+ if (!(acpi_gbl_owner_id_mask[j] & (1 << k))) {
+ /*
+ * Found a free ID. The actual ID is the bit index plus one,
+ * making zero an invalid Owner ID. Save this as the last ID
+ * allocated and update the global ID mask.
+ */
+ acpi_gbl_owner_id_mask[j] |= (1 << k);
+
+ acpi_gbl_last_owner_id_index = (u8)j;
+ acpi_gbl_next_owner_id_offset = (u8)(k + 1);
+
+ /*
+ * Construct encoded ID from the index and bit position
+ *
+ * Note: Last [j].k (bit 255) is never used and is marked
+ * permanently allocated (prevents +1 overflow)
+ */
+ *owner_id =
+ (acpi_owner_id) ((k + 1) + ACPI_MUL_32(j));
+
+ ACPI_DEBUG_PRINT((ACPI_DB_VALUES,
+ "Allocated OwnerId: %2.2X\n",
+ (unsigned int)*owner_id));
+ goto exit;
+ }
+ }
+
+ acpi_gbl_next_owner_id_offset = 0;
+ }
+
+ /*
+ * All owner_ids have been allocated. This typically should
+ * not happen since the IDs are reused after deallocation. The IDs are
+ * allocated upon table load (one per table) and method execution, and
+ * they are released when a table is unloaded or a method completes
+ * execution.
+ *
+ * If this error happens, there may be very deep nesting of invoked control
+ * methods, or there may be a bug where the IDs are not released.
+ */
+ status = AE_OWNER_ID_LIMIT;
+ ACPI_ERROR((AE_INFO,
+ "Could not allocate new OwnerId (255 max), AE_OWNER_ID_LIMIT"));
+
+ exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_release_owner_id
+ *
+ * PARAMETERS: owner_id_ptr - Pointer to a previously allocated owner_ID
+ *
+ * RETURN: None. No error is returned because we are either exiting a
+ * control method or unloading a table. Either way, we would
+ * ignore any error anyway.
+ *
+ * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255
+ *
+ ******************************************************************************/
+
+void acpi_ut_release_owner_id(acpi_owner_id * owner_id_ptr)
+{
+ acpi_owner_id owner_id = *owner_id_ptr;
+ acpi_status status;
+ u32 index;
+ u32 bit;
+
+ ACPI_FUNCTION_TRACE_U32(ut_release_owner_id, owner_id);
+
+ /* Always clear the input owner_id (zero is an invalid ID) */
+
+ *owner_id_ptr = 0;
+
+ /* Zero is not a valid owner_ID */
+
+ if (owner_id == 0) {
+ ACPI_ERROR((AE_INFO, "Invalid OwnerId: 0x%2.2X", owner_id));
+ return_VOID;
+ }
+
+ /* Mutex for the global ID mask */
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
+ if (ACPI_FAILURE(status)) {
+ return_VOID;
+ }
+
+ /* Normalize the ID to zero */
+
+ owner_id--;
+
+ /* Decode ID to index/offset pair */
+
+ index = ACPI_DIV_32(owner_id);
+ bit = 1 << ACPI_MOD_32(owner_id);
+
+ /* Free the owner ID only if it is valid */
+
+ if (acpi_gbl_owner_id_mask[index] & bit) {
+ acpi_gbl_owner_id_mask[index] ^= bit;
+ } else {
+ ACPI_ERROR((AE_INFO,
+ "Release of non-allocated OwnerId: 0x%2.2X",
+ owner_id + 1));
+ }
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
+ return_VOID;
+}
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index e38bef4980bc..cb7fa491decf 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -127,7 +127,9 @@ const char *acpi_gbl_rw_decode[] = {
const char *acpi_gbl_shr_decode[] = {
"Exclusive",
- "Shared"
+ "Shared",
+ "ExclusiveAndWake", /* ACPI 5.0 */
+ "SharedAndWake" /* ACPI 5.0 */
};
const char *acpi_gbl_siz_decode[] = {
@@ -383,26 +385,16 @@ static const u8 acpi_gbl_resource_types[] = {
ACPI_VARIABLE_LENGTH /* 0E *serial_bus */
};
-/*
- * For the iASL compiler/disassembler, we don't want any error messages
- * because the disassembler uses the resource validation code to determine
- * if Buffer objects are actually Resource Templates.
- */
-#ifdef ACPI_ASL_COMPILER
-#define ACPI_RESOURCE_ERROR(plist)
-#else
-#define ACPI_RESOURCE_ERROR(plist) ACPI_ERROR(plist)
-#endif
-
/*******************************************************************************
*
* FUNCTION: acpi_ut_walk_aml_resources
*
- * PARAMETERS: aml - Pointer to the raw AML resource template
- * aml_length - Length of the entire template
- * user_function - Called once for each descriptor found. If
- * NULL, a pointer to the end_tag is returned
- * context - Passed to user_function
+ * PARAMETERS: walk_state - Current walk info
+ * PARAMETERS: aml - Pointer to the raw AML resource template
+ * aml_length - Length of the entire template
+ * user_function - Called once for each descriptor found. If
+ * NULL, a pointer to the end_tag is returned
+ * context - Passed to user_function
*
* RETURN: Status
*
@@ -412,7 +404,8 @@ static const u8 acpi_gbl_resource_types[] = {
******************************************************************************/
acpi_status
-acpi_ut_walk_aml_resources(u8 * aml,
+acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
+ u8 *aml,
acpi_size aml_length,
acpi_walk_aml_callback user_function, void **context)
{
@@ -441,7 +434,8 @@ acpi_ut_walk_aml_resources(u8 * aml,
/* Validate the Resource Type and Resource Length */
- status = acpi_ut_validate_resource(aml, &resource_index);
+ status =
+ acpi_ut_validate_resource(walk_state, aml, &resource_index);
if (ACPI_FAILURE(status)) {
/*
* Exit on failure. Cannot continue because the descriptor length
@@ -498,7 +492,8 @@ acpi_ut_walk_aml_resources(u8 * aml,
/* Insert an end_tag anyway. acpi_rs_get_list_length always leaves room */
- (void)acpi_ut_validate_resource(end_tag, &resource_index);
+ (void)acpi_ut_validate_resource(walk_state, end_tag,
+ &resource_index);
status =
user_function(end_tag, 2, offset, resource_index, context);
if (ACPI_FAILURE(status)) {
@@ -513,9 +508,10 @@ acpi_ut_walk_aml_resources(u8 * aml,
*
* FUNCTION: acpi_ut_validate_resource
*
- * PARAMETERS: aml - Pointer to the raw AML resource descriptor
- * return_index - Where the resource index is returned. NULL
- * if the index is not required.
+ * PARAMETERS: walk_state - Current walk info
+ * aml - Pointer to the raw AML resource descriptor
+ * return_index - Where the resource index is returned. NULL
+ * if the index is not required.
*
* RETURN: Status, and optionally the Index into the global resource tables
*
@@ -525,7 +521,9 @@ acpi_ut_walk_aml_resources(u8 * aml,
*
******************************************************************************/
-acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
+acpi_status
+acpi_ut_validate_resource(struct acpi_walk_state *walk_state,
+ void *aml, u8 *return_index)
{
union aml_resource *aml_resource;
u8 resource_type;
@@ -627,10 +625,12 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
if ((aml_resource->common_serial_bus.type == 0) ||
(aml_resource->common_serial_bus.type >
AML_RESOURCE_MAX_SERIALBUSTYPE)) {
- ACPI_RESOURCE_ERROR((AE_INFO,
- "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
- aml_resource->common_serial_bus.
- type));
+ if (walk_state) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
+ aml_resource->common_serial_bus.
+ type));
+ }
return (AE_AML_INVALID_RESOURCE_TYPE);
}
}
@@ -645,18 +645,22 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
invalid_resource:
- ACPI_RESOURCE_ERROR((AE_INFO,
- "Invalid/unsupported resource descriptor: Type 0x%2.2X",
- resource_type));
+ if (walk_state) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid/unsupported resource descriptor: Type 0x%2.2X",
+ resource_type));
+ }
return (AE_AML_INVALID_RESOURCE_TYPE);
bad_resource_length:
- ACPI_RESOURCE_ERROR((AE_INFO,
- "Invalid resource descriptor length: Type "
- "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
- resource_type, resource_length,
- minimum_resource_length));
+ if (walk_state) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid resource descriptor length: Type "
+ "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
+ resource_type, resource_length,
+ minimum_resource_length));
+ }
return (AE_AML_BAD_RESOURCE_LENGTH);
}
@@ -800,8 +804,7 @@ u32 acpi_ut_get_descriptor_length(void *aml)
******************************************************************************/
acpi_status
-acpi_ut_get_resource_end_tag(union acpi_operand_object * obj_desc,
- u8 ** end_tag)
+acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag)
{
acpi_status status;
@@ -816,7 +819,7 @@ acpi_ut_get_resource_end_tag(union acpi_operand_object * obj_desc,
/* Validate the template and get a pointer to the end_tag */
- status = acpi_ut_walk_aml_resources(obj_desc->buffer.pointer,
+ status = acpi_ut_walk_aml_resources(NULL, obj_desc->buffer.pointer,
obj_desc->buffer.length, NULL,
(void **)end_tag);
diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c
index cee0473ba813..a6b729d4c1dc 100644
--- a/drivers/acpi/acpica/utstate.c
+++ b/drivers/acpi/acpica/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,14 +97,13 @@ void
acpi_ut_push_generic_state(union acpi_generic_state **list_head,
union acpi_generic_state *state)
{
- ACPI_FUNCTION_TRACE(ut_push_generic_state);
+ ACPI_FUNCTION_ENTRY();
/* Push the state object onto the front of the list (stack) */
state->common.next = *list_head;
*list_head = state;
-
- return_VOID;
+ return;
}
/*******************************************************************************
@@ -124,7 +123,7 @@ union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE(ut_pop_generic_state);
+ ACPI_FUNCTION_ENTRY();
/* Remove the state object at the head of the list (stack) */
@@ -136,7 +135,7 @@ union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state
*list_head = state->common.next;
}
- return_PTR(state);
+ return (state);
}
/*******************************************************************************
@@ -186,13 +185,13 @@ struct acpi_thread_state *acpi_ut_create_thread_state(void)
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE(ut_create_thread_state);
+ ACPI_FUNCTION_ENTRY();
/* Create the generic state object */
state = acpi_ut_create_generic_state();
if (!state) {
- return_PTR(NULL);
+ return (NULL);
}
/* Init fields specific to the update struct */
@@ -207,7 +206,7 @@ struct acpi_thread_state *acpi_ut_create_thread_state(void)
state->thread.thread_id = (acpi_thread_id) 1;
}
- return_PTR((struct acpi_thread_state *)state);
+ return ((struct acpi_thread_state *)state);
}
/*******************************************************************************
@@ -230,13 +229,13 @@ union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE_PTR(ut_create_update_state, object);
+ ACPI_FUNCTION_ENTRY();
/* Create the generic state object */
state = acpi_ut_create_generic_state();
if (!state) {
- return_PTR(NULL);
+ return (NULL);
}
/* Init fields specific to the update struct */
@@ -244,8 +243,7 @@ union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_UPDATE;
state->update.object = object;
state->update.value = action;
-
- return_PTR(state);
+ return (state);
}
/*******************************************************************************
@@ -267,13 +265,13 @@ union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object,
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE_PTR(ut_create_pkg_state, internal_object);
+ ACPI_FUNCTION_ENTRY();
/* Create the generic state object */
state = acpi_ut_create_generic_state();
if (!state) {
- return_PTR(NULL);
+ return (NULL);
}
/* Init fields specific to the update struct */
@@ -283,8 +281,7 @@ union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object,
state->pkg.dest_object = external_object;
state->pkg.index = index;
state->pkg.num_packages = 1;
-
- return_PTR(state);
+ return (state);
}
/*******************************************************************************
@@ -304,21 +301,20 @@ union acpi_generic_state *acpi_ut_create_control_state(void)
{
union acpi_generic_state *state;
- ACPI_FUNCTION_TRACE(ut_create_control_state);
+ ACPI_FUNCTION_ENTRY();
/* Create the generic state object */
state = acpi_ut_create_generic_state();
if (!state) {
- return_PTR(NULL);
+ return (NULL);
}
/* Init fields specific to the control struct */
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_CONTROL;
state->common.state = ACPI_CONTROL_CONDITIONAL_EXECUTING;
-
- return_PTR(state);
+ return (state);
}
/*******************************************************************************
@@ -336,12 +332,12 @@ union acpi_generic_state *acpi_ut_create_control_state(void)
void acpi_ut_delete_generic_state(union acpi_generic_state *state)
{
- ACPI_FUNCTION_TRACE(ut_delete_generic_state);
+ ACPI_FUNCTION_ENTRY();
/* Ignore null state */
if (state) {
(void)acpi_os_release_object(acpi_gbl_state_cache, state);
}
- return_VOID;
+ return;
}
diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c
new file mode 100644
index 000000000000..b3e36a81aa4d
--- /dev/null
+++ b/drivers/acpi/acpica/utstring.c
@@ -0,0 +1,574 @@
+/*******************************************************************************
+ *
+ * Module Name: utstring - Common functions for strings and characters
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT ACPI_UTILITIES
+ACPI_MODULE_NAME("utstring")
+
+/*
+ * Non-ANSI C library functions - strlwr, strupr, stricmp, and a 64-bit
+ * version of strtoul.
+ */
+#ifdef ACPI_ASL_COMPILER
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_strlwr (strlwr)
+ *
+ * PARAMETERS: src_string - The source string to convert
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Convert string to lowercase
+ *
+ * NOTE: This is not a POSIX function, so it appears here, not in utclib.c
+ *
+ ******************************************************************************/
+void acpi_ut_strlwr(char *src_string)
+{
+ char *string;
+
+ ACPI_FUNCTION_ENTRY();
+
+ if (!src_string) {
+ return;
+ }
+
+ /* Walk entire string, lowercasing the letters */
+
+ for (string = src_string; *string; string++) {
+ *string = (char)ACPI_TOLOWER(*string);
+ }
+
+ return;
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ut_stricmp (stricmp)
+ *
+ * PARAMETERS: string1 - first string to compare
+ * string2 - second string to compare
+ *
+ * RETURN: int that signifies string relationship. Zero means strings
+ * are equal.
+ *
+ * DESCRIPTION: Implementation of the non-ANSI stricmp function (compare
+ * strings with no case sensitivity)
+ *
+ ******************************************************************************/
+
+int acpi_ut_stricmp(char *string1, char *string2)
+{
+ int c1;
+ int c2;
+
+ do {
+ c1 = tolower((int)*string1);
+ c2 = tolower((int)*string2);
+
+ string1++;
+ string2++;
+ }
+ while ((c1 == c2) && (c1));
+
+ return (c1 - c2);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_strupr (strupr)
+ *
+ * PARAMETERS: src_string - The source string to convert
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Convert string to uppercase
+ *
+ * NOTE: This is not a POSIX function, so it appears here, not in utclib.c
+ *
+ ******************************************************************************/
+
+void acpi_ut_strupr(char *src_string)
+{
+ char *string;
+
+ ACPI_FUNCTION_ENTRY();
+
+ if (!src_string) {
+ return;
+ }
+
+ /* Walk entire string, uppercasing the letters */
+
+ for (string = src_string; *string; string++) {
+ *string = (char)ACPI_TOUPPER(*string);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_strtoul64
+ *
+ * PARAMETERS: string - Null terminated string
+ * base - Radix of the string: 16 or ACPI_ANY_BASE;
+ * ACPI_ANY_BASE means 'in behalf of to_integer'
+ * ret_integer - Where the converted integer is returned
+ *
+ * RETURN: Status and Converted value
+ *
+ * DESCRIPTION: Convert a string into an unsigned value. Performs either a
+ * 32-bit or 64-bit conversion, depending on the current mode
+ * of the interpreter.
+ * NOTE: Does not support Octal strings, not needed.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
+{
+ u32 this_digit = 0;
+ u64 return_value = 0;
+ u64 quotient;
+ u64 dividend;
+ u32 to_integer_op = (base == ACPI_ANY_BASE);
+ u32 mode32 = (acpi_gbl_integer_byte_width == 4);
+ u8 valid_digits = 0;
+ u8 sign_of0x = 0;
+ u8 term = 0;
+
+ ACPI_FUNCTION_TRACE_STR(ut_stroul64, string);
+
+ switch (base) {
+ case ACPI_ANY_BASE:
+ case 16:
+ break;
+
+ default:
+ /* Invalid Base */
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ if (!string) {
+ goto error_exit;
+ }
+
+ /* Skip over any white space in the buffer */
+
+ while ((*string) && (ACPI_IS_SPACE(*string) || *string == '\t')) {
+ string++;
+ }
+
+ if (to_integer_op) {
+ /*
+ * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'.
+ * We need to determine if it is decimal or hexadecimal.
+ */
+ if ((*string == '0') && (ACPI_TOLOWER(*(string + 1)) == 'x')) {
+ sign_of0x = 1;
+ base = 16;
+
+ /* Skip over the leading '0x' */
+ string += 2;
+ } else {
+ base = 10;
+ }
+ }
+
+ /* Any string left? Check that '0x' is not followed by white space. */
+
+ if (!(*string) || ACPI_IS_SPACE(*string) || *string == '\t') {
+ if (to_integer_op) {
+ goto error_exit;
+ } else {
+ goto all_done;
+ }
+ }
+
+ /*
+ * Perform a 32-bit or 64-bit conversion, depending upon the current
+ * execution mode of the interpreter
+ */
+ dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX;
+
+ /* Main loop: convert the string to a 32- or 64-bit integer */
+
+ while (*string) {
+ if (ACPI_IS_DIGIT(*string)) {
+
+ /* Convert ASCII 0-9 to Decimal value */
+
+ this_digit = ((u8)*string) - '0';
+ } else if (base == 10) {
+
+ /* Digit is out of range; possible in to_integer case only */
+
+ term = 1;
+ } else {
+ this_digit = (u8)ACPI_TOUPPER(*string);
+ if (ACPI_IS_XDIGIT((char)this_digit)) {
+
+ /* Convert ASCII Hex char to value */
+
+ this_digit = this_digit - 'A' + 10;
+ } else {
+ term = 1;
+ }
+ }
+
+ if (term) {
+ if (to_integer_op) {
+ goto error_exit;
+ } else {
+ break;
+ }
+ } else if ((valid_digits == 0) && (this_digit == 0)
+ && !sign_of0x) {
+
+ /* Skip zeros */
+ string++;
+ continue;
+ }
+
+ valid_digits++;
+
+ if (sign_of0x
+ && ((valid_digits > 16)
+ || ((valid_digits > 8) && mode32))) {
+ /*
+ * This is to_integer operation case.
+ * No any restrictions for string-to-integer conversion,
+ * see ACPI spec.
+ */
+ goto error_exit;
+ }
+
+ /* Divide the digit into the correct position */
+
+ (void)acpi_ut_short_divide((dividend - (u64)this_digit),
+ base, &quotient, NULL);
+
+ if (return_value > quotient) {
+ if (to_integer_op) {
+ goto error_exit;
+ } else {
+ break;
+ }
+ }
+
+ return_value *= base;
+ return_value += this_digit;
+ string++;
+ }
+
+ /* All done, normal exit */
+
+ all_done:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64(return_value)));
+
+ *ret_integer = return_value;
+ return_ACPI_STATUS(AE_OK);
+
+ error_exit:
+ /* Base was set/validated above */
+
+ if (base == 10) {
+ return_ACPI_STATUS(AE_BAD_DECIMAL_CONSTANT);
+ } else {
+ return_ACPI_STATUS(AE_BAD_HEX_CONSTANT);
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_print_string
+ *
+ * PARAMETERS: string - Null terminated ASCII string
+ * max_length - Maximum output length
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Dump an ASCII string with support for ACPI-defined escape
+ * sequences.
+ *
+ ******************************************************************************/
+
+void acpi_ut_print_string(char *string, u8 max_length)
+{
+ u32 i;
+
+ if (!string) {
+ acpi_os_printf("<\"NULL STRING PTR\">");
+ return;
+ }
+
+ acpi_os_printf("\"");
+ for (i = 0; string[i] && (i < max_length); i++) {
+
+ /* Escape sequences */
+
+ switch (string[i]) {
+ case 0x07:
+ acpi_os_printf("\\a"); /* BELL */
+ break;
+
+ case 0x08:
+ acpi_os_printf("\\b"); /* BACKSPACE */
+ break;
+
+ case 0x0C:
+ acpi_os_printf("\\f"); /* FORMFEED */
+ break;
+
+ case 0x0A:
+ acpi_os_printf("\\n"); /* LINEFEED */
+ break;
+
+ case 0x0D:
+ acpi_os_printf("\\r"); /* CARRIAGE RETURN */
+ break;
+
+ case 0x09:
+ acpi_os_printf("\\t"); /* HORIZONTAL TAB */
+ break;
+
+ case 0x0B:
+ acpi_os_printf("\\v"); /* VERTICAL TAB */
+ break;
+
+ case '\'': /* Single Quote */
+ case '\"': /* Double Quote */
+ case '\\': /* Backslash */
+ acpi_os_printf("\\%c", (int)string[i]);
+ break;
+
+ default:
+
+ /* Check for printable character or hex escape */
+
+ if (ACPI_IS_PRINT(string[i])) {
+ /* This is a normal character */
+
+ acpi_os_printf("%c", (int)string[i]);
+ } else {
+ /* All others will be Hex escapes */
+
+ acpi_os_printf("\\x%2.2X", (s32) string[i]);
+ }
+ break;
+ }
+ }
+ acpi_os_printf("\"");
+
+ if (i == max_length && string[i]) {
+ acpi_os_printf("...");
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_valid_acpi_char
+ *
+ * PARAMETERS: char - The character to be examined
+ * position - Byte position (0-3)
+ *
+ * RETURN: TRUE if the character is valid, FALSE otherwise
+ *
+ * DESCRIPTION: Check for a valid ACPI character. Must be one of:
+ * 1) Upper case alpha
+ * 2) numeric
+ * 3) underscore
+ *
+ * We allow a '!' as the last character because of the ASF! table
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_valid_acpi_char(char character, u32 position)
+{
+
+ if (!((character >= 'A' && character <= 'Z') ||
+ (character >= '0' && character <= '9') || (character == '_'))) {
+
+ /* Allow a '!' in the last position */
+
+ if (character == '!' && position == 3) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_valid_acpi_name
+ *
+ * PARAMETERS: name - The name to be examined
+ *
+ * RETURN: TRUE if the name is valid, FALSE otherwise
+ *
+ * DESCRIPTION: Check for a valid ACPI name. Each character must be one of:
+ * 1) Upper case alpha
+ * 2) numeric
+ * 3) underscore
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_valid_acpi_name(u32 name)
+{
+ u32 i;
+
+ ACPI_FUNCTION_ENTRY();
+
+ for (i = 0; i < ACPI_NAME_SIZE; i++) {
+ if (!acpi_ut_valid_acpi_char
+ ((ACPI_CAST_PTR(char, &name))[i], i)) {
+ return (FALSE);
+ }
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_repair_name
+ *
+ * PARAMETERS: name - The ACPI name to be repaired
+ *
+ * RETURN: Repaired version of the name
+ *
+ * DESCRIPTION: Repair an ACPI name: Change invalid characters to '*' and
+ * return the new name. NOTE: the Name parameter must reside in
+ * read/write memory, cannot be a const.
+ *
+ * An ACPI Name must consist of valid ACPI characters. We will repair the name
+ * if necessary because we don't want to abort because of this, but we want
+ * all namespace names to be printable. A warning message is appropriate.
+ *
+ * This issue came up because there are in fact machines that exhibit
+ * this problem, and we want to be able to enable ACPI support for them,
+ * even though there are a few bad names.
+ *
+ ******************************************************************************/
+
+void acpi_ut_repair_name(char *name)
+{
+ u32 i;
+ u8 found_bad_char = FALSE;
+ u32 original_name;
+
+ ACPI_FUNCTION_NAME(ut_repair_name);
+
+ ACPI_MOVE_NAME(&original_name, name);
+
+ /* Check each character in the name */
+
+ for (i = 0; i < ACPI_NAME_SIZE; i++) {
+ if (acpi_ut_valid_acpi_char(name[i], i)) {
+ continue;
+ }
+
+ /*
+ * Replace a bad character with something printable, yet technically
+ * still invalid. This prevents any collisions with existing "good"
+ * names in the namespace.
+ */
+ name[i] = '*';
+ found_bad_char = TRUE;
+ }
+
+ if (found_bad_char) {
+
+ /* Report warning only if in strict mode or debug mode */
+
+ if (!acpi_gbl_enable_interpreter_slack) {
+ ACPI_WARNING((AE_INFO,
+ "Invalid character(s) in name (0x%.8X), repaired: [%4.4s]",
+ original_name, name));
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Invalid character(s) in name (0x%.8X), repaired: [%4.4s]",
+ original_name, name));
+ }
+ }
+}
+
+#if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP
+/*******************************************************************************
+ *
+ * FUNCTION: ut_convert_backslashes
+ *
+ * PARAMETERS: pathname - File pathname string to be converted
+ *
+ * RETURN: Modifies the input Pathname
+ *
+ * DESCRIPTION: Convert all backslashes (0x5C) to forward slashes (0x2F) within
+ * the entire input file pathname string.
+ *
+ ******************************************************************************/
+
+void ut_convert_backslashes(char *pathname)
+{
+
+ if (!pathname) {
+ return;
+ }
+
+ while (*pathname) {
+ if (*pathname == '\\') {
+ *pathname = '/';
+ }
+
+ pathname++;
+ }
+}
+#endif
diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c
index a424a9e3fea4..62774c7b76a8 100644
--- a/drivers/acpi/acpica/uttrack.c
+++ b/drivers/acpi/acpica/uttrack.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -436,10 +436,10 @@ acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation,
struct acpi_memory_list *mem_list;
acpi_status status;
- ACPI_FUNCTION_TRACE(ut_remove_allocation);
+ ACPI_FUNCTION_NAME(ut_remove_allocation);
if (acpi_gbl_disable_mem_tracking) {
- return_ACPI_STATUS(AE_OK);
+ return (AE_OK);
}
mem_list = acpi_gbl_global_list;
@@ -450,12 +450,12 @@ acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation,
ACPI_ERROR((module, line,
"Empty allocation list, nothing to free!"));
- return_ACPI_STATUS(AE_OK);
+ return (AE_OK);
}
status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ return (status);
}
/* Unlink */
@@ -470,15 +470,15 @@ acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation,
(allocation->next)->previous = allocation->previous;
}
+ ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n",
+ &allocation->user_space, allocation->size));
+
/* Mark the segment as deleted */
ACPI_MEMSET(&allocation->user_space, 0xEA, allocation->size);
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n",
- allocation->size));
-
status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);
- return_ACPI_STATUS(status);
+ return (status);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 390db0ca5e2e..48efb446258c 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,11 +44,7 @@
#include <linux/export.h>
#include <acpi/acpi.h>
#include "accommon.h"
-#include "acevents.h"
-#include "acnamesp.h"
#include "acdebug.h"
-#include "actables.h"
-#include "acinterp.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utxface")
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
index d4d3826140d8..976b6c734fce 100644
--- a/drivers/acpi/acpica/utxferror.c
+++ b/drivers/acpi/acpica/utxferror.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -297,9 +297,9 @@ ACPI_EXPORT_SYMBOL(acpi_bios_warning)
*
* PARAMETERS: module_name - Caller's module name (for error output)
* line_number - Caller's line number (for error output)
- * Pathname - Full pathname to the node
+ * pathname - Full pathname to the node
* node_flags - From Namespace node for the method/object
- * Format - Printf format string + additional args
+ * format - Printf format string + additional args
*
* RETURN: None
*
diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c
index 14f523627a5e..41ebaaf8bb1a 100644
--- a/drivers/acpi/acpica/utxfinit.c
+++ b/drivers/acpi/acpica/utxfinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c
index 0a40a851b354..312299721ba1 100644
--- a/drivers/acpi/acpica/utxfmutex.c
+++ b/drivers/acpi/acpica/utxfmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2012, Intel Corp.
+ * Copyright (C) 2000 - 2013, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
index e6defd86b424..1e5d8a40101e 100644
--- a/drivers/acpi/apei/cper.c
+++ b/drivers/acpi/apei/cper.c
@@ -29,6 +29,7 @@
#include <linux/time.h>
#include <linux/cper.h>
#include <linux/acpi.h>
+#include <linux/pci.h>
#include <linux/aer.h>
/*
@@ -249,6 +250,10 @@ static const char *cper_pcie_port_type_strs[] = {
static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
const struct acpi_hest_generic_data *gdata)
{
+#ifdef CONFIG_ACPI_APEI_PCIEAER
+ struct pci_dev *dev;
+#endif
+
if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ?
@@ -281,10 +286,18 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
pfx, pcie->bridge.secondary_status, pcie->bridge.control);
#ifdef CONFIG_ACPI_APEI_PCIEAER
- if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {
- struct aer_capability_regs *aer_regs = (void *)pcie->aer_info;
- cper_print_aer(pfx, gdata->error_severity, aer_regs);
+ dev = pci_get_domain_bus_and_slot(pcie->device_id.segment,
+ pcie->device_id.bus, pcie->device_id.function);
+ if (!dev) {
+ pr_err("PCI AER Cannot get PCI device %04x:%02x:%02x.%d\n",
+ pcie->device_id.segment, pcie->device_id.bus,
+ pcie->device_id.slot, pcie->device_id.function);
+ return;
}
+ if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO)
+ cper_print_aer(pfx, dev, gdata->error_severity,
+ (struct aer_capability_regs *) pcie->aer_info);
+ pci_dev_put(dev);
#endif
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 7efaeaa53b88..c5cd5b5513e6 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -1111,7 +1111,7 @@ fail:
return result;
}
-static int acpi_battery_remove(struct acpi_device *device, int type)
+static int acpi_battery_remove(struct acpi_device *device)
{
struct acpi_battery *battery = NULL;
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 1f0d457ecbcf..01708a165368 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -178,276 +178,6 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data)
}
EXPORT_SYMBOL(acpi_bus_get_private_data);
-/* --------------------------------------------------------------------------
- Power Management
- -------------------------------------------------------------------------- */
-
-static const char *state_string(int state)
-{
- switch (state) {
- case ACPI_STATE_D0:
- return "D0";
- case ACPI_STATE_D1:
- return "D1";
- case ACPI_STATE_D2:
- return "D2";
- case ACPI_STATE_D3_HOT:
- return "D3hot";
- case ACPI_STATE_D3_COLD:
- return "D3";
- default:
- return "(unknown)";
- }
-}
-
-static int __acpi_bus_get_power(struct acpi_device *device, int *state)
-{
- int result = ACPI_STATE_UNKNOWN;
-
- if (!device || !state)
- return -EINVAL;
-
- if (!device->flags.power_manageable) {
- /* TBD: Non-recursive algorithm for walking up hierarchy. */
- *state = device->parent ?
- device->parent->power.state : ACPI_STATE_D0;
- goto out;
- }
-
- /*
- * Get the device's power state either directly (via _PSC) or
- * indirectly (via power resources).
- */
- if (device->power.flags.explicit_get) {
- unsigned long long psc;
- acpi_status status = acpi_evaluate_integer(device->handle,
- "_PSC", NULL, &psc);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- result = psc;
- }
- /* The test below covers ACPI_STATE_UNKNOWN too. */
- if (result <= ACPI_STATE_D2) {
- ; /* Do nothing. */
- } else if (device->power.flags.power_resources) {
- int error = acpi_power_get_inferred_state(device, &result);
- if (error)
- return error;
- } else if (result == ACPI_STATE_D3_HOT) {
- result = ACPI_STATE_D3;
- }
-
- /*
- * If we were unsure about the device parent's power state up to this
- * point, the fact that the device is in D0 implies that the parent has
- * to be in D0 too.
- */
- if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN
- && result == ACPI_STATE_D0)
- device->parent->power.state = ACPI_STATE_D0;
-
- *state = result;
-
- out:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
- device->pnp.bus_id, state_string(*state)));
-
- return 0;
-}
-
-
-/**
- * acpi_device_set_power - Set power state of an ACPI device.
- * @device: Device to set the power state of.
- * @state: New power state to set.
- *
- * Callers must ensure that the device is power manageable before using this
- * function.
- */
-int acpi_device_set_power(struct acpi_device *device, int state)
-{
- int result = 0;
- acpi_status status = AE_OK;
- char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
-
- if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
- return -EINVAL;
-
- /* Make sure this is a valid target state */
-
- if (state == device->power.state) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
- state_string(state)));
- return 0;
- }
-
- if (!device->power.states[state].flags.valid) {
- printk(KERN_WARNING PREFIX "Device does not support %s\n",
- state_string(state));
- return -ENODEV;
- }
- if (device->parent && (state < device->parent->power.state)) {
- printk(KERN_WARNING PREFIX
- "Cannot set device to a higher-powered"
- " state than parent\n");
- return -ENODEV;
- }
-
- /* For D3cold we should execute _PS3, not _PS4. */
- if (state == ACPI_STATE_D3_COLD)
- object_name[3] = '3';
-
- /*
- * Transition Power
- * ----------------
- * On transitions to a high-powered state we first apply power (via
- * power resources) then evalute _PSx. Conversly for transitions to
- * a lower-powered state.
- */
- if (state < device->power.state) {
- if (device->power.state >= ACPI_STATE_D3_HOT &&
- state != ACPI_STATE_D0) {
- printk(KERN_WARNING PREFIX
- "Cannot transition to non-D0 state from D3\n");
- return -ENODEV;
- }
- if (device->power.flags.power_resources) {
- result = acpi_power_transition(device, state);
- if (result)
- goto end;
- }
- if (device->power.states[state].flags.explicit_set) {
- status = acpi_evaluate_object(device->handle,
- object_name, NULL, NULL);
- if (ACPI_FAILURE(status)) {
- result = -ENODEV;
- goto end;
- }
- }
- } else {
- if (device->power.states[state].flags.explicit_set) {
- status = acpi_evaluate_object(device->handle,
- object_name, NULL, NULL);
- if (ACPI_FAILURE(status)) {
- result = -ENODEV;
- goto end;
- }
- }
- if (device->power.flags.power_resources) {
- result = acpi_power_transition(device, state);
- if (result)
- goto end;
- }
- }
-
- end:
- if (result)
- printk(KERN_WARNING PREFIX
- "Device [%s] failed to transition to %s\n",
- device->pnp.bus_id, state_string(state));
- else {
- device->power.state = state;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Device [%s] transitioned to %s\n",
- device->pnp.bus_id, state_string(state)));
- }
-
- return result;
-}
-EXPORT_SYMBOL(acpi_device_set_power);
-
-
-int acpi_bus_set_power(acpi_handle handle, int state)
-{
- struct acpi_device *device;
- int result;
-
- result = acpi_bus_get_device(handle, &device);
- if (result)
- return result;
-
- if (!device->flags.power_manageable) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Device [%s] is not power manageable\n",
- dev_name(&device->dev)));
- return -ENODEV;
- }
-
- return acpi_device_set_power(device, state);
-}
-EXPORT_SYMBOL(acpi_bus_set_power);
-
-
-int acpi_bus_init_power(struct acpi_device *device)
-{
- int state;
- int result;
-
- if (!device)
- return -EINVAL;
-
- device->power.state = ACPI_STATE_UNKNOWN;
-
- result = __acpi_bus_get_power(device, &state);
- if (result)
- return result;
-
- if (device->power.flags.power_resources)
- result = acpi_power_on_resources(device, state);
-
- if (!result)
- device->power.state = state;
-
- return result;
-}
-
-
-int acpi_bus_update_power(acpi_handle handle, int *state_p)
-{
- struct acpi_device *device;
- int state;
- int result;
-
- result = acpi_bus_get_device(handle, &device);
- if (result)
- return result;
-
- result = __acpi_bus_get_power(device, &state);
- if (result)
- return result;
-
- result = acpi_device_set_power(device, state);
- if (!result && state_p)
- *state_p = state;
-
- return result;
-}
-EXPORT_SYMBOL_GPL(acpi_bus_update_power);
-
-
-bool acpi_bus_power_manageable(acpi_handle handle)
-{
- struct acpi_device *device;
- int result;
-
- result = acpi_bus_get_device(handle, &device);
- return result ? false : device->flags.power_manageable;
-}
-
-EXPORT_SYMBOL(acpi_bus_power_manageable);
-
-bool acpi_bus_can_wakeup(acpi_handle handle)
-{
- struct acpi_device *device;
- int result;
-
- result = acpi_bus_get_device(handle, &device);
- return result ? false : device->wakeup.flags.valid;
-}
-
-EXPORT_SYMBOL(acpi_bus_can_wakeup);
-
static void acpi_print_osc_error(acpi_handle handle,
struct acpi_osc_context *context, char *error)
{
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index f0d936b65e37..86c7d5445c38 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -75,7 +75,7 @@ static const struct acpi_device_id button_device_ids[] = {
MODULE_DEVICE_TABLE(acpi, button_device_ids);
static int acpi_button_add(struct acpi_device *device);
-static int acpi_button_remove(struct acpi_device *device, int type);
+static int acpi_button_remove(struct acpi_device *device);
static void acpi_button_notify(struct acpi_device *device, u32 event);
#ifdef CONFIG_PM_SLEEP
@@ -433,7 +433,7 @@ static int acpi_button_add(struct acpi_device *device)
return error;
}
-static int acpi_button_remove(struct acpi_device *device, int type)
+static int acpi_button_remove(struct acpi_device *device)
{
struct acpi_button *button = acpi_driver_data(device);
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 811910b50b75..5523ba7d764d 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -34,46 +34,34 @@
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
-#include <acpi/container.h>
#define PREFIX "ACPI: "
-#define ACPI_CONTAINER_DEVICE_NAME "ACPI container device"
-#define ACPI_CONTAINER_CLASS "container"
-
-#define INSTALL_NOTIFY_HANDLER 1
-#define UNINSTALL_NOTIFY_HANDLER 2
-
#define _COMPONENT ACPI_CONTAINER_COMPONENT
ACPI_MODULE_NAME("container");
-MODULE_AUTHOR("Anil S Keshavamurthy");
-MODULE_DESCRIPTION("ACPI container driver");
-MODULE_LICENSE("GPL");
-
-static int acpi_container_add(struct acpi_device *device);
-static int acpi_container_remove(struct acpi_device *device, int type);
-
static const struct acpi_device_id container_device_ids[] = {
{"ACPI0004", 0},
{"PNP0A05", 0},
{"PNP0A06", 0},
{"", 0},
};
-MODULE_DEVICE_TABLE(acpi, container_device_ids);
-static struct acpi_driver acpi_container_driver = {
- .name = "container",
- .class = ACPI_CONTAINER_CLASS,
+static int container_device_attach(struct acpi_device *device,
+ const struct acpi_device_id *not_used)
+{
+ /*
+ * FIXME: This is necessary, so that acpi_eject_store() doesn't return
+ * -ENODEV for containers.
+ */
+ return 1;
+}
+
+static struct acpi_scan_handler container_device_handler = {
.ids = container_device_ids,
- .ops = {
- .add = acpi_container_add,
- .remove = acpi_container_remove,
- },
+ .attach = container_device_attach,
};
-/*******************************************************************/
-
static int is_device_present(acpi_handle handle)
{
acpi_handle temp;
@@ -92,73 +80,6 @@ static int is_device_present(acpi_handle handle)
return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
}
-static bool is_container_device(const char *hid)
-{
- const struct acpi_device_id *container_id;
-
- for (container_id = container_device_ids;
- container_id->id[0]; container_id++) {
- if (!strcmp((char *)container_id->id, hid))
- return true;
- }
-
- return false;
-}
-
-/*******************************************************************/
-static int acpi_container_add(struct acpi_device *device)
-{
- struct acpi_container *container;
-
- container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL);
- if (!container)
- return -ENOMEM;
-
- container->handle = device->handle;
- strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
- device->driver_data = container;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n",
- acpi_device_name(device), acpi_device_bid(device)));
-
- return 0;
-}
-
-static int acpi_container_remove(struct acpi_device *device, int type)
-{
- acpi_status status = AE_OK;
- struct acpi_container *pc = NULL;
-
- pc = acpi_driver_data(device);
- kfree(pc);
- return status;
-}
-
-static int container_device_add(struct acpi_device **device, acpi_handle handle)
-{
- acpi_handle phandle;
- struct acpi_device *pdev;
- int result;
-
-
- if (acpi_get_parent(handle, &phandle)) {
- return -ENODEV;
- }
-
- if (acpi_bus_get_device(phandle, &pdev)) {
- return -ENODEV;
- }
-
- if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
- return -ENODEV;
- }
-
- result = acpi_bus_start(*device);
-
- return result;
-}
-
static void container_notify_cb(acpi_handle handle, u32 type, void *context)
{
struct acpi_device *device = NULL;
@@ -167,6 +88,8 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
acpi_status status;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+ acpi_scan_lock_acquire();
+
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* Fall through */
@@ -182,7 +105,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
/* device exist and this is a remove request */
device->flags.eject_pending = 1;
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- return;
+ goto out;
}
break;
}
@@ -190,11 +113,16 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
if (!ACPI_FAILURE(status) || device)
break;
- result = container_device_add(&device, handle);
+ result = acpi_bus_scan(handle);
if (result) {
acpi_handle_warn(handle, "Failed to add container\n");
break;
}
+ result = acpi_bus_get_device(handle, &device);
+ if (result) {
+ acpi_handle_warn(handle, "Missing device object\n");
+ break;
+ }
kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
ost_code = ACPI_OST_SC_SUCCESS;
@@ -204,98 +132,59 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
if (!acpi_bus_get_device(handle, &device) && device) {
device->flags.eject_pending = 1;
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- return;
+ goto out;
}
break;
default:
/* non-hotplug event; possibly handled by other handler */
- return;
+ goto out;
}
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
- return;
+
+ out:
+ acpi_scan_lock_release();
}
-static acpi_status
-container_walk_namespace_cb(acpi_handle handle,
- u32 lvl, void *context, void **rv)
+static bool is_container(acpi_handle handle)
{
- char *hid = NULL;
struct acpi_device_info *info;
- acpi_status status;
- int *action = context;
-
- status = acpi_get_object_info(handle, &info);
- if (ACPI_FAILURE(status)) {
- return AE_OK;
- }
+ bool ret = false;
- if (info->valid & ACPI_VALID_HID)
- hid = info->hardware_id.string;
+ if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+ return false;
- if (hid == NULL) {
- goto end;
- }
-
- if (!is_container_device(hid))
- goto end;
+ if (info->valid & ACPI_VALID_HID) {
+ const struct acpi_device_id *id;
- switch (*action) {
- case INSTALL_NOTIFY_HANDLER:
- acpi_install_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- container_notify_cb, NULL);
- break;
- case UNINSTALL_NOTIFY_HANDLER:
- acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- container_notify_cb);
- break;
- default:
- break;
+ for (id = container_device_ids; id->id[0]; id++) {
+ ret = !strcmp((char *)id->id, info->hardware_id.string);
+ if (ret)
+ break;
+ }
}
-
- end:
kfree(info);
-
- return AE_OK;
+ return ret;
}
-static int __init acpi_container_init(void)
+static acpi_status acpi_container_register_notify_handler(acpi_handle handle,
+ u32 lvl, void *ctxt,
+ void **retv)
{
- int result = 0;
- int action = INSTALL_NOTIFY_HANDLER;
-
- result = acpi_bus_register_driver(&acpi_container_driver);
- if (result < 0) {
- return (result);
- }
-
- /* register notify handler to every container device */
- acpi_walk_namespace(ACPI_TYPE_DEVICE,
- ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- container_walk_namespace_cb, NULL, &action, NULL);
+ if (is_container(handle))
+ acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ container_notify_cb, NULL);
- return (0);
+ return AE_OK;
}
-static void __exit acpi_container_exit(void)
+void __init acpi_container_init(void)
{
- int action = UNINSTALL_NOTIFY_HANDLER;
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+ acpi_container_register_notify_handler, NULL,
+ NULL, NULL);
-
- acpi_walk_namespace(ACPI_TYPE_DEVICE,
- ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- container_walk_namespace_cb, NULL, &action, NULL);
-
- acpi_bus_unregister_driver(&acpi_container_driver);
-
- return;
+ acpi_scan_add_handler(&container_device_handler);
}
-
-module_init(acpi_container_init);
-module_exit(acpi_container_exit);
diff --git a/drivers/acpi/csrt.c b/drivers/acpi/csrt.c
new file mode 100644
index 000000000000..5c15a91faf0b
--- /dev/null
+++ b/drivers/acpi/csrt.c
@@ -0,0 +1,159 @@
+/*
+ * Support for Core System Resources Table (CSRT)
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ * Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "ACPI: CSRT: " fmt
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sizes.h>
+
+ACPI_MODULE_NAME("CSRT");
+
+static int __init acpi_csrt_parse_shared_info(struct platform_device *pdev,
+ const struct acpi_csrt_group *grp)
+{
+ const struct acpi_csrt_shared_info *si;
+ struct resource res[3];
+ size_t nres;
+ int ret;
+
+ memset(res, 0, sizeof(res));
+ nres = 0;
+
+ si = (const struct acpi_csrt_shared_info *)&grp[1];
+ /*
+ * The peripherals that are listed on CSRT typically support only
+ * 32-bit addresses so we only use the low part of MMIO base for
+ * now.
+ */
+ if (!si->mmio_base_high && si->mmio_base_low) {
+ /*
+ * There is no size of the memory resource in shared_info
+ * so we assume that it is 4k here.
+ */
+ res[nres].start = si->mmio_base_low;
+ res[nres].end = res[0].start + SZ_4K - 1;
+ res[nres++].flags = IORESOURCE_MEM;
+ }
+
+ if (si->gsi_interrupt) {
+ int irq = acpi_register_gsi(NULL, si->gsi_interrupt,
+ si->interrupt_mode,
+ si->interrupt_polarity);
+ res[nres].start = irq;
+ res[nres].end = irq;
+ res[nres++].flags = IORESOURCE_IRQ;
+ }
+
+ if (si->base_request_line || si->num_handshake_signals) {
+ /*
+ * We pass the driver a DMA resource describing the range
+ * of request lines the device supports.
+ */
+ res[nres].start = si->base_request_line;
+ res[nres].end = res[nres].start + si->num_handshake_signals - 1;
+ res[nres++].flags = IORESOURCE_DMA;
+ }
+
+ ret = platform_device_add_resources(pdev, res, nres);
+ if (ret) {
+ if (si->gsi_interrupt)
+ acpi_unregister_gsi(si->gsi_interrupt);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __init
+acpi_csrt_parse_resource_group(const struct acpi_csrt_group *grp)
+{
+ struct platform_device *pdev;
+ char vendor[5], name[16];
+ int ret, i;
+
+ vendor[0] = grp->vendor_id;
+ vendor[1] = grp->vendor_id >> 8;
+ vendor[2] = grp->vendor_id >> 16;
+ vendor[3] = grp->vendor_id >> 24;
+ vendor[4] = '\0';
+
+ if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info))
+ return -ENODEV;
+
+ snprintf(name, sizeof(name), "%s%04X", vendor, grp->device_id);
+ pdev = platform_device_alloc(name, PLATFORM_DEVID_AUTO);
+ if (!pdev)
+ return -ENOMEM;
+
+ /* Add resources based on the shared info */
+ ret = acpi_csrt_parse_shared_info(pdev, grp);
+ if (ret)
+ goto fail;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto fail;
+
+ for (i = 0; i < pdev->num_resources; i++)
+ dev_dbg(&pdev->dev, "%pR\n", &pdev->resource[i]);
+
+ return 0;
+
+fail:
+ platform_device_put(pdev);
+ return ret;
+}
+
+/*
+ * CSRT or Core System Resources Table is a proprietary ACPI table
+ * introduced by Microsoft. This table can contain devices that are not in
+ * the system DSDT table. In particular DMA controllers might be described
+ * here.
+ *
+ * We present these devices as normal platform devices that don't have ACPI
+ * IDs or handle. The platform device name will be something like
+ * <VENDOR><DEVID>.<n>.auto for example: INTL9C06.0.auto.
+ */
+void __init acpi_csrt_init(void)
+{
+ struct acpi_csrt_group *grp, *end;
+ struct acpi_table_csrt *csrt;
+ acpi_status status;
+ int ret;
+
+ status = acpi_get_table(ACPI_SIG_CSRT, 0,
+ (struct acpi_table_header **)&csrt);
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND)
+ pr_warn("failed to get the CSRT table\n");
+ return;
+ }
+
+ pr_debug("parsing CSRT table for devices\n");
+
+ grp = (struct acpi_csrt_group *)(csrt + 1);
+ end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length);
+
+ while (grp < end) {
+ ret = acpi_csrt_parse_resource_group(grp);
+ if (ret) {
+ pr_warn("error in parsing resource group: %d\n", ret);
+ return;
+ }
+
+ grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
+ }
+}
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c
index 5d42c2414ae5..12b62f2cdb3f 100644
--- a/drivers/acpi/custom_method.c
+++ b/drivers/acpi/custom_method.c
@@ -1,5 +1,5 @@
/*
- * debugfs.c - ACPI debugfs interface to userspace.
+ * custom_method.c - debugfs interface for customizing ACPI control method
*/
#include <linux/init.h>
@@ -66,7 +66,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
buf = NULL;
if (ACPI_FAILURE(status))
return -EINVAL;
- add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
+ add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
}
return count;
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index c6ff606c6d5b..dd314ef9bff1 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -30,6 +30,12 @@
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#include "internal.h"
+
+#define _COMPONENT ACPI_POWER_COMPONENT
+ACPI_MODULE_NAME("device_pm");
static DEFINE_MUTEX(acpi_pm_notifier_lock);
@@ -94,6 +100,293 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
}
/**
+ * acpi_power_state_string - String representation of ACPI device power state.
+ * @state: ACPI device power state to return the string representation of.
+ */
+const char *acpi_power_state_string(int state)
+{
+ switch (state) {
+ case ACPI_STATE_D0:
+ return "D0";
+ case ACPI_STATE_D1:
+ return "D1";
+ case ACPI_STATE_D2:
+ return "D2";
+ case ACPI_STATE_D3_HOT:
+ return "D3hot";
+ case ACPI_STATE_D3_COLD:
+ return "D3cold";
+ default:
+ return "(unknown)";
+ }
+}
+
+/**
+ * acpi_device_get_power - Get power state of an ACPI device.
+ * @device: Device to get the power state of.
+ * @state: Place to store the power state of the device.
+ *
+ * This function does not update the device's power.state field, but it may
+ * update its parent's power.state field (when the parent's power state is
+ * unknown and the device's power state turns out to be D0).
+ */
+int acpi_device_get_power(struct acpi_device *device, int *state)
+{
+ int result = ACPI_STATE_UNKNOWN;
+
+ if (!device || !state)
+ return -EINVAL;
+
+ if (!device->flags.power_manageable) {
+ /* TBD: Non-recursive algorithm for walking up hierarchy. */
+ *state = device->parent ?
+ device->parent->power.state : ACPI_STATE_D0;
+ goto out;
+ }
+
+ /*
+ * Get the device's power state either directly (via _PSC) or
+ * indirectly (via power resources).
+ */
+ if (device->power.flags.explicit_get) {
+ unsigned long long psc;
+ acpi_status status = acpi_evaluate_integer(device->handle,
+ "_PSC", NULL, &psc);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ result = psc;
+ }
+ /* The test below covers ACPI_STATE_UNKNOWN too. */
+ if (result <= ACPI_STATE_D2) {
+ ; /* Do nothing. */
+ } else if (device->power.flags.power_resources) {
+ int error = acpi_power_get_inferred_state(device, &result);
+ if (error)
+ return error;
+ } else if (result == ACPI_STATE_D3_HOT) {
+ result = ACPI_STATE_D3;
+ }
+
+ /*
+ * If we were unsure about the device parent's power state up to this
+ * point, the fact that the device is in D0 implies that the parent has
+ * to be in D0 too.
+ */
+ if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN
+ && result == ACPI_STATE_D0)
+ device->parent->power.state = ACPI_STATE_D0;
+
+ *state = result;
+
+ out:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
+ device->pnp.bus_id, acpi_power_state_string(*state)));
+
+ return 0;
+}
+
+static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state)
+{
+ if (adev->power.states[state].flags.explicit_set) {
+ char method[5] = { '_', 'P', 'S', '0' + state, '\0' };
+ acpi_status status;
+
+ status = acpi_evaluate_object(adev->handle, method, NULL, NULL);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/**
+ * acpi_device_set_power - Set power state of an ACPI device.
+ * @device: Device to set the power state of.
+ * @state: New power state to set.
+ *
+ * Callers must ensure that the device is power manageable before using this
+ * function.
+ */
+int acpi_device_set_power(struct acpi_device *device, int state)
+{
+ int result = 0;
+ bool cut_power = false;
+
+ if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
+ return -EINVAL;
+
+ /* Make sure this is a valid target state */
+
+ if (state == device->power.state) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
+ acpi_power_state_string(state)));
+ return 0;
+ }
+
+ if (!device->power.states[state].flags.valid) {
+ printk(KERN_WARNING PREFIX "Device does not support %s\n",
+ acpi_power_state_string(state));
+ return -ENODEV;
+ }
+ if (device->parent && (state < device->parent->power.state)) {
+ printk(KERN_WARNING PREFIX
+ "Cannot set device to a higher-powered"
+ " state than parent\n");
+ return -ENODEV;
+ }
+
+ /* For D3cold we should first transition into D3hot. */
+ if (state == ACPI_STATE_D3_COLD
+ && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) {
+ state = ACPI_STATE_D3_HOT;
+ cut_power = true;
+ }
+
+ if (state < device->power.state && state != ACPI_STATE_D0
+ && device->power.state >= ACPI_STATE_D3_HOT) {
+ printk(KERN_WARNING PREFIX
+ "Cannot transition to non-D0 state from D3\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Transition Power
+ * ----------------
+ * In accordance with the ACPI specification first apply power (via
+ * power resources) and then evalute _PSx.
+ */
+ if (device->power.flags.power_resources) {
+ result = acpi_power_transition(device, state);
+ if (result)
+ goto end;
+ }
+ result = acpi_dev_pm_explicit_set(device, state);
+ if (result)
+ goto end;
+
+ if (cut_power) {
+ device->power.state = state;
+ state = ACPI_STATE_D3_COLD;
+ result = acpi_power_transition(device, state);
+ }
+
+ end:
+ if (result) {
+ printk(KERN_WARNING PREFIX
+ "Device [%s] failed to transition to %s\n",
+ device->pnp.bus_id,
+ acpi_power_state_string(state));
+ } else {
+ device->power.state = state;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Device [%s] transitioned to %s\n",
+ device->pnp.bus_id,
+ acpi_power_state_string(state)));
+ }
+
+ return result;
+}
+EXPORT_SYMBOL(acpi_device_set_power);
+
+int acpi_bus_set_power(acpi_handle handle, int state)
+{
+ struct acpi_device *device;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result)
+ return result;
+
+ if (!device->flags.power_manageable) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Device [%s] is not power manageable\n",
+ dev_name(&device->dev)));
+ return -ENODEV;
+ }
+
+ return acpi_device_set_power(device, state);
+}
+EXPORT_SYMBOL(acpi_bus_set_power);
+
+int acpi_bus_init_power(struct acpi_device *device)
+{
+ int state;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+
+ device->power.state = ACPI_STATE_UNKNOWN;
+
+ result = acpi_device_get_power(device, &state);
+ if (result)
+ return result;
+
+ if (state < ACPI_STATE_D3_COLD && device->power.flags.power_resources) {
+ result = acpi_power_on_resources(device, state);
+ if (result)
+ return result;
+
+ result = acpi_dev_pm_explicit_set(device, state);
+ if (result)
+ return result;
+ } else if (state == ACPI_STATE_UNKNOWN) {
+ /* No power resources and missing _PSC? Try to force D0. */
+ state = ACPI_STATE_D0;
+ result = acpi_dev_pm_explicit_set(device, state);
+ if (result)
+ return result;
+ }
+ device->power.state = state;
+ return 0;
+}
+
+int acpi_bus_update_power(acpi_handle handle, int *state_p)
+{
+ struct acpi_device *device;
+ int state;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result)
+ return result;
+
+ result = acpi_device_get_power(device, &state);
+ if (result)
+ return result;
+
+ if (state == ACPI_STATE_UNKNOWN)
+ state = ACPI_STATE_D0;
+
+ result = acpi_device_set_power(device, state);
+ if (!result && state_p)
+ *state_p = state;
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_update_power);
+
+bool acpi_bus_power_manageable(acpi_handle handle)
+{
+ struct acpi_device *device;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ return result ? false : device->flags.power_manageable;
+}
+EXPORT_SYMBOL(acpi_bus_power_manageable);
+
+bool acpi_bus_can_wakeup(acpi_handle handle)
+{
+ struct acpi_device *device;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ return result ? false : device->wakeup.flags.valid;
+}
+EXPORT_SYMBOL(acpi_bus_can_wakeup);
+
+/**
* acpi_device_power_state - Get preferred power state of ACPI device.
* @dev: Device whose preferred target power state to return.
* @adev: ACPI device node corresponding to @dev.
@@ -213,7 +506,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in)
acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
struct acpi_device *adev;
- if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
+ if (!handle || acpi_bus_get_device(handle, &adev)) {
dev_dbg(dev, "ACPI handle without context in %s!\n", __func__);
return -ENODEV;
}
@@ -290,7 +583,7 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
return -EINVAL;
handle = DEVICE_ACPI_HANDLE(phys_dev);
- if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
+ if (!handle || acpi_bus_get_device(handle, &adev)) {
dev_dbg(phys_dev, "ACPI handle without context in %s!\n",
__func__);
return -ENODEV;
@@ -304,7 +597,7 @@ static inline void acpi_wakeup_device(acpi_handle handle, u32 event,
void *context) {}
#endif /* CONFIG_PM_RUNTIME */
- #ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM_SLEEP
/**
* __acpi_device_sleep_wake - Enable or disable device to wake up the system.
* @dev: Device to enable/desible to wake up the system.
@@ -334,7 +627,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
return -EINVAL;
handle = DEVICE_ACPI_HANDLE(dev);
- if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
+ if (!handle || acpi_bus_get_device(handle, &adev)) {
dev_dbg(dev, "ACPI handle without context in %s!\n", __func__);
return -ENODEV;
}
@@ -353,7 +646,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
* acpi_dev_pm_get_node - Get ACPI device node for the given physical device.
* @dev: Device to get the ACPI node for.
*/
-static struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
+struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
{
acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
struct acpi_device *adev;
@@ -665,3 +958,59 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off)
}
}
EXPORT_SYMBOL_GPL(acpi_dev_pm_detach);
+
+/**
+ * acpi_dev_pm_add_dependent - Add physical device depending for PM.
+ * @handle: Handle of ACPI device node.
+ * @depdev: Device depending on that node for PM.
+ */
+void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev)
+{
+ struct acpi_device_physical_node *dep;
+ struct acpi_device *adev;
+
+ if (!depdev || acpi_bus_get_device(handle, &adev))
+ return;
+
+ mutex_lock(&adev->physical_node_lock);
+
+ list_for_each_entry(dep, &adev->power_dependent, node)
+ if (dep->dev == depdev)
+ goto out;
+
+ dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+ if (dep) {
+ dep->dev = depdev;
+ list_add_tail(&dep->node, &adev->power_dependent);
+ }
+
+ out:
+ mutex_unlock(&adev->physical_node_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_dev_pm_add_dependent);
+
+/**
+ * acpi_dev_pm_remove_dependent - Remove physical device depending for PM.
+ * @handle: Handle of ACPI device node.
+ * @depdev: Device depending on that node for PM.
+ */
+void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev)
+{
+ struct acpi_device_physical_node *dep;
+ struct acpi_device *adev;
+
+ if (!depdev || acpi_bus_get_device(handle, &adev))
+ return;
+
+ mutex_lock(&adev->physical_node_lock);
+
+ list_for_each_entry(dep, &adev->power_dependent, node)
+ if (dep->dev == depdev) {
+ list_del(&dep->node);
+ kfree(dep);
+ break;
+ }
+
+ mutex_unlock(&adev->physical_node_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index f32bd47b35e0..4fdea381ef21 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -310,8 +310,6 @@ static int dock_present(struct dock_station *ds)
static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
{
struct acpi_device *device;
- struct acpi_device *parent_device;
- acpi_handle parent;
int ret;
if (acpi_bus_get_device(handle, &device)) {
@@ -319,16 +317,11 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
* no device created for this object,
* so we should create one.
*/
- acpi_get_parent(handle, &parent);
- if (acpi_bus_get_device(parent, &parent_device))
- parent_device = NULL;
-
- ret = acpi_bus_add(&device, parent_device, handle,
- ACPI_BUS_TYPE_DEVICE);
- if (ret) {
+ ret = acpi_bus_scan(handle);
+ if (ret)
pr_debug("error adding bus, %x\n", -ret);
- return NULL;
- }
+
+ acpi_bus_get_device(handle, &device);
}
return device;
}
@@ -343,13 +336,9 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
static void dock_remove_acpi_device(acpi_handle handle)
{
struct acpi_device *device;
- int ret;
- if (!acpi_bus_get_device(handle, &device)) {
- ret = acpi_bus_trim(device, 1);
- if (ret)
- pr_debug("error removing bus, %x\n", -ret);
- }
+ if (!acpi_bus_get_device(handle, &device))
+ acpi_bus_trim(device);
}
/**
@@ -755,7 +744,9 @@ static void acpi_dock_deferred_cb(void *context)
{
struct dock_data *data = context;
+ acpi_scan_lock_acquire();
dock_notify(data->handle, data->event, data->ds);
+ acpi_scan_lock_release();
kfree(data);
}
@@ -768,20 +759,31 @@ static int acpi_dock_notifier_call(struct notifier_block *this,
if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
&& event != ACPI_NOTIFY_EJECT_REQUEST)
return 0;
+
+ acpi_scan_lock_acquire();
+
list_for_each_entry(dock_station, &dock_stations, sibling) {
if (dock_station->handle == handle) {
struct dock_data *dd;
+ acpi_status status;
dd = kmalloc(sizeof(*dd), GFP_KERNEL);
if (!dd)
- return 0;
+ break;
+
dd->handle = handle;
dd->event = event;
dd->ds = dock_station;
- acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
- return 0 ;
+ status = acpi_os_hotplug_execute(acpi_dock_deferred_cb,
+ dd);
+ if (ACPI_FAILURE(status))
+ kfree(dd);
+
+ break;
}
}
+
+ acpi_scan_lock_release();
return 0;
}
@@ -836,7 +838,7 @@ static ssize_t show_docked(struct device *dev,
struct dock_station *dock_station = dev->platform_data;
- if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp)))
+ if (!acpi_bus_get_device(dock_station->handle, &tmp))
return snprintf(buf, PAGE_SIZE, "1\n");
return snprintf(buf, PAGE_SIZE, "0\n");
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 354007d490d1..d45b2871d33b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -852,7 +852,7 @@ static int acpi_ec_add(struct acpi_device *device)
return ret;
}
-static int acpi_ec_remove(struct acpi_device *device, int type)
+static int acpi_ec_remove(struct acpi_device *device)
{
struct acpi_ec *ec;
struct acpi_ec_query_handler *handler, *tmp;
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 3bd6a54702d6..f815da82c765 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -45,7 +45,7 @@ MODULE_DESCRIPTION("ACPI Fan Driver");
MODULE_LICENSE("GPL");
static int acpi_fan_add(struct acpi_device *device);
-static int acpi_fan_remove(struct acpi_device *device, int type);
+static int acpi_fan_remove(struct acpi_device *device);
static const struct acpi_device_id fan_device_ids[] = {
{"PNP0C0B", 0},
@@ -172,7 +172,7 @@ static int acpi_fan_add(struct acpi_device *device)
return result;
}
-static int acpi_fan_remove(struct acpi_device *device, int type)
+static int acpi_fan_remove(struct acpi_device *device)
{
struct thermal_cooling_device *cdev = acpi_driver_data(device);
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 35da18113216..ef6f155469b5 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -68,6 +68,9 @@ static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
{
struct acpi_bus_type *tmp, *ret = NULL;
+ if (!type)
+ return NULL;
+
down_read(&bus_type_sem);
list_for_each_entry(tmp, &bus_type_list, list) {
if (tmp->bus == type) {
@@ -95,40 +98,31 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
return ret;
}
-/* Get device's handler per its address under its parent */
-struct acpi_find_child {
- acpi_handle handle;
- u64 address;
-};
-
-static acpi_status
-do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
+static acpi_status do_acpi_find_child(acpi_handle handle, u32 lvl_not_used,
+ void *addr_p, void **ret_p)
{
+ unsigned long long addr;
acpi_status status;
- struct acpi_device_info *info;
- struct acpi_find_child *find = context;
-
- status = acpi_get_object_info(handle, &info);
- if (ACPI_SUCCESS(status)) {
- if ((info->address == find->address)
- && (info->valid & ACPI_VALID_ADR))
- find->handle = handle;
- kfree(info);
+
+ status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
+ if (ACPI_SUCCESS(status) && addr == *((u64 *)addr_p)) {
+ *ret_p = handle;
+ return AE_CTRL_TERMINATE;
}
return AE_OK;
}
acpi_handle acpi_get_child(acpi_handle parent, u64 address)
{
- struct acpi_find_child find = { NULL, address };
+ void *ret = NULL;
if (!parent)
return NULL;
- acpi_walk_namespace(ACPI_TYPE_DEVICE, parent,
- 1, do_acpi_find_child, NULL, &find, NULL);
- return find.handle;
-}
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, NULL,
+ do_acpi_find_child, &address, &ret);
+ return (acpi_handle)ret;
+}
EXPORT_SYMBOL(acpi_get_child);
static int acpi_bind_one(struct device *dev, acpi_handle handle)
@@ -269,28 +263,39 @@ static int acpi_platform_notify(struct device *dev)
{
struct acpi_bus_type *type;
acpi_handle handle;
- int ret = -EINVAL;
+ int ret;
ret = acpi_bind_one(dev, NULL);
- if (!ret)
- goto out;
-
- if (!dev->bus || !dev->parent) {
+ if (ret && (!dev->bus || !dev->parent)) {
/* bridge devices genernally haven't bus or parent */
ret = acpi_find_bridge_device(dev, &handle);
- goto end;
+ if (!ret) {
+ ret = acpi_bind_one(dev, handle);
+ if (ret)
+ goto out;
+ }
}
+
type = acpi_get_bus_type(dev->bus);
- if (!type) {
- DBG("No ACPI bus support for %s\n", dev_name(dev));
- ret = -EINVAL;
- goto end;
+ if (ret) {
+ if (!type || !type->find_device) {
+ DBG("No ACPI bus support for %s\n", dev_name(dev));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = type->find_device(dev, &handle);
+ if (ret) {
+ DBG("Unable to get handle for %s\n", dev_name(dev));
+ goto out;
+ }
+ ret = acpi_bind_one(dev, handle);
+ if (ret)
+ goto out;
}
- if ((ret = type->find_device(dev, &handle)) != 0)
- DBG("Can't get handler for %s\n", dev_name(dev));
- end:
- if (!ret)
- acpi_bind_one(dev, handle);
+
+ if (type && type->setup)
+ type->setup(dev);
out:
#if ACPI_GLUE_DEBUG
@@ -309,6 +314,12 @@ static int acpi_platform_notify(struct device *dev)
static int acpi_platform_notify_remove(struct device *dev)
{
+ struct acpi_bus_type *type;
+
+ type = acpi_get_bus_type(dev->bus);
+ if (type && type->cleanup)
+ type->cleanup(dev);
+
acpi_unbind_one(dev);
return 0;
}
diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c
index a0cc796932f7..13b1d39d7cdf 100644
--- a/drivers/acpi/hed.c
+++ b/drivers/acpi/hed.c
@@ -70,7 +70,7 @@ static int acpi_hed_add(struct acpi_device *device)
return 0;
}
-static int acpi_hed_remove(struct acpi_device *device, int type)
+static int acpi_hed_remove(struct acpi_device *device)
{
hed_handle = NULL;
return 0;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 3c407cdc1ec1..79092328cf06 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -25,7 +25,16 @@
int init_acpi_device_notify(void);
int acpi_scan_init(void);
+void acpi_pci_root_init(void);
+void acpi_pci_link_init(void);
+void acpi_platform_init(void);
int acpi_sysfs_init(void);
+void acpi_csrt_init(void);
+#ifdef CONFIG_ACPI_CONTAINER
+void acpi_container_init(void);
+#else
+static inline void acpi_container_init(void) {}
+#endif
#ifdef CONFIG_DEBUG_FS
extern struct dentry *acpi_debugfs_dir;
@@ -35,15 +44,33 @@ static inline void acpi_debugfs_init(void) { return; }
#endif
/* --------------------------------------------------------------------------
+ Device Node Initialization / Removal
+ -------------------------------------------------------------------------- */
+#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
+ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING)
+
+int acpi_device_add(struct acpi_device *device,
+ void (*release)(struct device *));
+void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
+ int type, unsigned long long sta);
+void acpi_device_add_finalize(struct acpi_device *device);
+void acpi_free_ids(struct acpi_device *device);
+
+/* --------------------------------------------------------------------------
Power Resource
-------------------------------------------------------------------------- */
int acpi_power_init(void);
+void acpi_power_resources_list_free(struct list_head *list);
+int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
+ struct list_head *list);
+int acpi_add_power_resource(acpi_handle handle);
+void acpi_power_add_remove_device(struct acpi_device *adev, bool add);
+int acpi_power_min_system_level(struct list_head *list);
int acpi_device_sleep_wake(struct acpi_device *dev,
int enable, int sleep_state, int dev_state);
int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
int acpi_power_on_resources(struct acpi_device *device, int state);
int acpi_power_transition(struct acpi_device *device, int state);
-int acpi_bus_init_power(struct acpi_device *device);
int acpi_wakeup_device_init(void);
void acpi_early_processor_set_pdc(void);
@@ -98,6 +125,4 @@ static inline void suspend_nvs_restore(void) {}
-------------------------------------------------------------------------- */
struct platform_device;
-struct platform_device *acpi_create_platform_device(struct acpi_device *adev);
-
#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index cb31298ca684..59844ee149be 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -116,14 +116,16 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header)
struct acpi_srat_mem_affinity *p =
(struct acpi_srat_mem_affinity *)header;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s\n",
+ "SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s%s\n",
(unsigned long)p->base_address,
(unsigned long)p->length,
p->proximity_domain,
(p->flags & ACPI_SRAT_MEM_ENABLED)?
"enabled" : "disabled",
(p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
- " hot-pluggable" : ""));
+ " hot-pluggable" : "",
+ (p->flags & ACPI_SRAT_MEM_NON_VOLATILE)?
+ " non-volatile" : ""));
}
#endif /* ACPI_DEBUG_OUTPUT */
break;
@@ -273,17 +275,17 @@ static int __init acpi_parse_srat(struct acpi_table_header *table)
static int __init
acpi_table_parse_srat(enum acpi_srat_type id,
- acpi_table_entry_handler handler, unsigned int max_entries)
+ acpi_tbl_entry_handler handler, unsigned int max_entries)
{
return acpi_table_parse_entries(ACPI_SIG_SRAT,
sizeof(struct acpi_table_srat), id,
handler, max_entries);
}
-int __init acpi_numa_init(void)
-{
- int cnt = 0;
+static int srat_mem_cnt;
+void __init early_parse_srat(void)
+{
/*
* Should not limit number with cpu num that is from NR_CPUS or nr_cpus=
* SRAT cpu entries could have different order with that in MADT.
@@ -293,21 +295,24 @@ int __init acpi_numa_init(void)
/* SRAT: Static Resource Affinity Table */
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
- acpi_parse_x2apic_affinity, 0);
+ acpi_parse_x2apic_affinity, 0);
acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
- acpi_parse_processor_affinity, 0);
- cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
- acpi_parse_memory_affinity,
- NR_NODE_MEMBLKS);
+ acpi_parse_processor_affinity, 0);
+ srat_mem_cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
+ acpi_parse_memory_affinity,
+ NR_NODE_MEMBLKS);
}
+}
+int __init acpi_numa_init(void)
+{
/* SLIT: System Locality Information Table */
acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
acpi_numa_arch_fixup();
- if (cnt < 0)
- return cnt;
+ if (srat_mem_cnt < 0)
+ return srat_mem_cnt;
else if (!parsed_numa_memblks)
return -ENOENT;
return 0;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index bd22f8667eed..8080588f88cb 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -661,7 +661,7 @@ static void acpi_table_taint(struct acpi_table_header *table)
pr_warn(PREFIX
"Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n",
table->signature, table->oem_table_id);
- add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
+ add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
}
@@ -787,7 +787,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
acpi_irq_handler = handler;
acpi_irq_context = context;
- if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) {
+ if (request_irq(irq, acpi_irq, IRQF_SHARED | IRQF_NO_SUSPEND, "acpi", acpi_irq)) {
printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
acpi_irq_handler = NULL;
return AE_NOT_ACQUIRED;
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
deleted file mode 100644
index a1dee29beed3..000000000000
--- a/drivers/acpi/pci_bind.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * pci_bind.c - ACPI PCI Device Binding ($Revision: 2 $)
- *
- * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
- * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/pci-acpi.h>
-#include <linux/acpi.h>
-#include <linux/pm_runtime.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-
-#define _COMPONENT ACPI_PCI_COMPONENT
-ACPI_MODULE_NAME("pci_bind");
-
-static int acpi_pci_unbind(struct acpi_device *device)
-{
- struct pci_dev *dev;
-
- dev = acpi_get_pci_dev(device->handle);
- if (!dev)
- goto out;
-
- device_set_run_wake(&dev->dev, false);
- pci_acpi_remove_pm_notifier(device);
- acpi_power_resource_unregister_device(&dev->dev, device->handle);
-
- if (!dev->subordinate)
- goto out;
-
- acpi_pci_irq_del_prt(pci_domain_nr(dev->bus), dev->subordinate->number);
-
- device->ops.bind = NULL;
- device->ops.unbind = NULL;
-
-out:
- pci_dev_put(dev);
- return 0;
-}
-
-static int acpi_pci_bind(struct acpi_device *device)
-{
- acpi_status status;
- acpi_handle handle;
- unsigned char bus;
- struct pci_dev *dev;
-
- dev = acpi_get_pci_dev(device->handle);
- if (!dev)
- return 0;
-
- pci_acpi_add_pm_notifier(device, dev);
- acpi_power_resource_register_device(&dev->dev, device->handle);
- if (device->wakeup.flags.run_wake)
- device_set_run_wake(&dev->dev, true);
-
- /*
- * Install the 'bind' function to facilitate callbacks for
- * children of the P2P bridge.
- */
- if (dev->subordinate) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Device %04x:%02x:%02x.%d is a PCI bridge\n",
- pci_domain_nr(dev->bus), dev->bus->number,
- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)));
- device->ops.bind = acpi_pci_bind;
- device->ops.unbind = acpi_pci_unbind;
- }
-
- /*
- * Evaluate and parse _PRT, if exists. This code allows parsing of
- * _PRT objects within the scope of non-bridge devices. Note that
- * _PRTs within the scope of a PCI bridge assume the bridge's
- * subordinate bus number.
- *
- * TBD: Can _PRTs exist within the scope of non-bridge PCI devices?
- */
- status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
- if (ACPI_FAILURE(status))
- goto out;
-
- if (dev->subordinate)
- bus = dev->subordinate->number;
- else
- bus = dev->bus->number;
-
- acpi_pci_irq_add_prt(device->handle, pci_domain_nr(dev->bus), bus);
-
-out:
- pci_dev_put(dev);
- return 0;
-}
-
-int acpi_pci_bind_root(struct acpi_device *device)
-{
- device->ops.bind = acpi_pci_bind;
- device->ops.unbind = acpi_pci_unbind;
-
- return 0;
-}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index a12808259dfb..ab764ed34a50 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -53,23 +53,19 @@ ACPI_MODULE_NAME("pci_link");
#define ACPI_PCI_LINK_FILE_STATUS "state"
#define ACPI_PCI_LINK_MAX_POSSIBLE 16
-static int acpi_pci_link_add(struct acpi_device *device);
-static int acpi_pci_link_remove(struct acpi_device *device, int type);
+static int acpi_pci_link_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used);
+static void acpi_pci_link_remove(struct acpi_device *device);
static const struct acpi_device_id link_device_ids[] = {
{"PNP0C0F", 0},
{"", 0},
};
-MODULE_DEVICE_TABLE(acpi, link_device_ids);
-static struct acpi_driver acpi_pci_link_driver = {
- .name = "pci_link",
- .class = ACPI_PCI_LINK_CLASS,
+static struct acpi_scan_handler pci_link_handler = {
.ids = link_device_ids,
- .ops = {
- .add = acpi_pci_link_add,
- .remove = acpi_pci_link_remove,
- },
+ .attach = acpi_pci_link_add,
+ .detach = acpi_pci_link_remove,
};
/*
@@ -692,7 +688,8 @@ int acpi_pci_link_free_irq(acpi_handle handle)
Driver Interface
-------------------------------------------------------------------------- */
-static int acpi_pci_link_add(struct acpi_device *device)
+static int acpi_pci_link_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used)
{
int result;
struct acpi_pci_link *link;
@@ -746,7 +743,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
if (result)
kfree(link);
- return result;
+ return result < 0 ? result : 1;
}
static int acpi_pci_link_resume(struct acpi_pci_link *link)
@@ -766,7 +763,7 @@ static void irqrouter_resume(void)
}
}
-static int acpi_pci_link_remove(struct acpi_device *device, int type)
+static void acpi_pci_link_remove(struct acpi_device *device)
{
struct acpi_pci_link *link;
@@ -777,7 +774,6 @@ static int acpi_pci_link_remove(struct acpi_device *device, int type)
mutex_unlock(&acpi_link_lock);
kfree(link);
- return 0;
}
/*
@@ -874,20 +870,10 @@ static struct syscore_ops irqrouter_syscore_ops = {
.resume = irqrouter_resume,
};
-static int __init irqrouter_init_ops(void)
-{
- if (!acpi_disabled && !acpi_noirq)
- register_syscore_ops(&irqrouter_syscore_ops);
-
- return 0;
-}
-
-device_initcall(irqrouter_init_ops);
-
-static int __init acpi_pci_link_init(void)
+void __init acpi_pci_link_init(void)
{
if (acpi_noirq)
- return 0;
+ return;
if (acpi_irq_balance == -1) {
/* no command line switch: enable balancing in IOAPIC mode */
@@ -896,11 +882,6 @@ static int __init acpi_pci_link_init(void)
else
acpi_irq_balance = 0;
}
-
- if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0)
- return -ENODEV;
-
- return 0;
+ register_syscore_ops(&irqrouter_syscore_ops);
+ acpi_scan_add_handler(&pci_link_handler);
}
-
-subsys_initcall(acpi_pci_link_init);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 7928d4dc7056..b3cc69c5caf1 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -45,9 +45,9 @@
ACPI_MODULE_NAME("pci_root");
#define ACPI_PCI_ROOT_CLASS "pci_bridge"
#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge"
-static int acpi_pci_root_add(struct acpi_device *device);
-static int acpi_pci_root_remove(struct acpi_device *device, int type);
-static int acpi_pci_root_start(struct acpi_device *device);
+static int acpi_pci_root_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used);
+static void acpi_pci_root_remove(struct acpi_device *device);
#define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \
| OSC_ACTIVE_STATE_PWR_SUPPORT \
@@ -58,17 +58,11 @@ static const struct acpi_device_id root_device_ids[] = {
{"PNP0A03", 0},
{"", 0},
};
-MODULE_DEVICE_TABLE(acpi, root_device_ids);
-static struct acpi_driver acpi_pci_root_driver = {
- .name = "pci_root",
- .class = ACPI_PCI_ROOT_CLASS,
+static struct acpi_scan_handler pci_root_handler = {
.ids = root_device_ids,
- .ops = {
- .add = acpi_pci_root_add,
- .remove = acpi_pci_root_remove,
- .start = acpi_pci_root_start,
- },
+ .attach = acpi_pci_root_add,
+ .detach = acpi_pci_root_remove,
};
/* Lock to protect both acpi_pci_roots and acpi_pci_drivers lists */
@@ -188,21 +182,6 @@ static acpi_status try_get_root_bridge_busnr(acpi_handle handle,
return AE_OK;
}
-static void acpi_pci_bridge_scan(struct acpi_device *device)
-{
- int status;
- struct acpi_device *child = NULL;
-
- if (device->flags.bus_address)
- if (device->parent && device->parent->ops.bind) {
- status = device->parent->ops.bind(device);
- if (!status) {
- list_for_each_entry(child, &device->children, node)
- acpi_pci_bridge_scan(child);
- }
- }
-}
-
static u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766";
static acpi_status acpi_pci_run_osc(acpi_handle handle,
@@ -445,14 +424,15 @@ out:
}
EXPORT_SYMBOL(acpi_pci_osc_control_set);
-static int acpi_pci_root_add(struct acpi_device *device)
+static int acpi_pci_root_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used)
{
unsigned long long segment, bus;
acpi_status status;
int result;
struct acpi_pci_root *root;
acpi_handle handle;
- struct acpi_device *child;
+ struct acpi_pci_driver *driver;
u32 flags, base_flags;
bool is_osc_granted = false;
@@ -603,21 +583,6 @@ static int acpi_pci_root_add(struct acpi_device *device)
goto out_del_root;
}
- /*
- * Attach ACPI-PCI Context
- * -----------------------
- * Thus binding the ACPI and PCI devices.
- */
- result = acpi_pci_bind_root(device);
- if (result)
- goto out_del_root;
-
- /*
- * Scan and bind all _ADR-Based Devices
- */
- list_for_each_entry(child, &device->children, node)
- acpi_pci_bridge_scan(child);
-
/* ASPM setting */
if (is_osc_granted) {
if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM)
@@ -632,24 +597,6 @@ static int acpi_pci_root_add(struct acpi_device *device)
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);
- return 0;
-
-out_del_root:
- mutex_lock(&acpi_pci_root_lock);
- list_del(&root->node);
- mutex_unlock(&acpi_pci_root_lock);
-
- acpi_pci_irq_del_prt(root->segment, root->secondary.start);
-end:
- kfree(root);
- return result;
-}
-
-static int acpi_pci_root_start(struct acpi_device *device)
-{
- struct acpi_pci_root *root = acpi_driver_data(device);
- struct acpi_pci_driver *driver;
-
if (system_state != SYSTEM_BOOTING)
pci_assign_unassigned_bus_resources(root->bus);
@@ -664,11 +611,20 @@ static int acpi_pci_root_start(struct acpi_device *device)
pci_enable_bridges(root->bus);
pci_bus_add_devices(root->bus);
+ return 1;
- return 0;
+out_del_root:
+ mutex_lock(&acpi_pci_root_lock);
+ list_del(&root->node);
+ mutex_unlock(&acpi_pci_root_lock);
+
+ acpi_pci_irq_del_prt(root->segment, root->secondary.start);
+end:
+ kfree(root);
+ return result;
}
-static int acpi_pci_root_remove(struct acpi_device *device, int type)
+static void acpi_pci_root_remove(struct acpi_device *device)
{
acpi_status status;
acpi_handle handle;
@@ -696,21 +652,14 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
list_del(&root->node);
mutex_unlock(&acpi_pci_root_lock);
kfree(root);
- return 0;
}
-static int __init acpi_pci_root_init(void)
+void __init acpi_pci_root_init(void)
{
acpi_hest_init();
- if (acpi_pci_disabled)
- return 0;
-
- pci_acpi_crs_quirks();
- if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
- return -ENODEV;
-
- return 0;
+ if (!acpi_pci_disabled) {
+ pci_acpi_crs_quirks();
+ acpi_scan_add_handler(&pci_root_handler);
+ }
}
-
-subsys_initcall(acpi_pci_root_init);
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index d22585f21aeb..2c630c006c2f 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -50,13 +50,12 @@ module_param(debug, bool, 0644);
ACPI_MODULE_NAME("pci_slot");
#define MY_NAME "pci_slot"
-#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
+#define err(format, arg...) pr_err("%s: " format , MY_NAME , ## arg)
+#define info(format, arg...) pr_info("%s: " format , MY_NAME , ## arg)
#define dbg(format, arg...) \
do { \
if (debug) \
- printk(KERN_DEBUG "%s: " format, \
- MY_NAME , ## arg); \
+ pr_debug("%s: " format, MY_NAME , ## arg); \
} while (0)
#define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 6e7b9d523812..b820528a5fa3 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -41,6 +41,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+#include <linux/sysfs.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include "sleep.h"
@@ -58,88 +59,121 @@ ACPI_MODULE_NAME("power");
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
-static int acpi_power_add(struct acpi_device *device);
-static int acpi_power_remove(struct acpi_device *device, int type);
-
-static const struct acpi_device_id power_device_ids[] = {
- {ACPI_POWER_HID, 0},
- {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, power_device_ids);
-
-#ifdef CONFIG_PM_SLEEP
-static int acpi_power_resume(struct device *dev);
-#endif
-static SIMPLE_DEV_PM_OPS(acpi_power_pm, NULL, acpi_power_resume);
-
-static struct acpi_driver acpi_power_driver = {
- .name = "power",
- .class = ACPI_POWER_CLASS,
- .ids = power_device_ids,
- .ops = {
- .add = acpi_power_add,
- .remove = acpi_power_remove,
- },
- .drv.pm = &acpi_power_pm,
-};
-
-/*
- * A power managed device
- * A device may rely on multiple power resources.
- * */
-struct acpi_power_managed_device {
- struct device *dev; /* The physical device */
- acpi_handle *handle;
-};
-
-struct acpi_power_resource_device {
- struct acpi_power_managed_device *device;
- struct acpi_power_resource_device *next;
+struct acpi_power_dependent_device {
+ struct list_head node;
+ struct acpi_device *adev;
+ struct work_struct work;
};
struct acpi_power_resource {
- struct acpi_device * device;
- acpi_bus_id name;
+ struct acpi_device device;
+ struct list_head list_node;
+ struct list_head dependent;
+ char *name;
u32 system_level;
u32 order;
unsigned int ref_count;
struct mutex resource_lock;
+};
- /* List of devices relying on this power resource */
- struct acpi_power_resource_device *devices;
- struct mutex devices_lock;
+struct acpi_power_resource_entry {
+ struct list_head node;
+ struct acpi_power_resource *resource;
};
-static struct list_head acpi_power_resource_list;
+static LIST_HEAD(acpi_power_resource_list);
+static DEFINE_MUTEX(power_resource_list_lock);
/* --------------------------------------------------------------------------
Power Resource Management
-------------------------------------------------------------------------- */
-static int
-acpi_power_get_context(acpi_handle handle,
- struct acpi_power_resource **resource)
+static inline
+struct acpi_power_resource *to_power_resource(struct acpi_device *device)
{
- int result = 0;
- struct acpi_device *device = NULL;
+ return container_of(device, struct acpi_power_resource, device);
+}
+
+static struct acpi_power_resource *acpi_power_get_context(acpi_handle handle)
+{
+ struct acpi_device *device;
+ if (acpi_bus_get_device(handle, &device))
+ return NULL;
- if (!resource)
- return -ENODEV;
+ return to_power_resource(device);
+}
- result = acpi_bus_get_device(handle, &device);
- if (result) {
- printk(KERN_WARNING PREFIX "Getting context [%p]\n", handle);
- return result;
- }
+static int acpi_power_resources_list_add(acpi_handle handle,
+ struct list_head *list)
+{
+ struct acpi_power_resource *resource = acpi_power_get_context(handle);
+ struct acpi_power_resource_entry *entry;
- *resource = acpi_driver_data(device);
- if (!*resource)
- return -ENODEV;
+ if (!resource || !list)
+ return -EINVAL;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->resource = resource;
+ if (!list_empty(list)) {
+ struct acpi_power_resource_entry *e;
+ list_for_each_entry(e, list, node)
+ if (e->resource->order > resource->order) {
+ list_add_tail(&entry->node, &e->node);
+ return 0;
+ }
+ }
+ list_add_tail(&entry->node, list);
return 0;
}
+void acpi_power_resources_list_free(struct list_head *list)
+{
+ struct acpi_power_resource_entry *entry, *e;
+
+ list_for_each_entry_safe(entry, e, list, node) {
+ list_del(&entry->node);
+ kfree(entry);
+ }
+}
+
+int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
+ struct list_head *list)
+{
+ unsigned int i;
+ int err = 0;
+
+ for (i = start; i < package->package.count; i++) {
+ union acpi_object *element = &package->package.elements[i];
+ acpi_handle rhandle;
+
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
+ err = -ENODATA;
+ break;
+ }
+ rhandle = element->reference.handle;
+ if (!rhandle) {
+ err = -ENODEV;
+ break;
+ }
+ err = acpi_add_power_resource(rhandle);
+ if (err)
+ break;
+
+ err = acpi_power_resources_list_add(rhandle, list);
+ if (err)
+ break;
+ }
+ if (err)
+ acpi_power_resources_list_free(list);
+
+ return err;
+}
+
static int acpi_power_get_state(acpi_handle handle, int *state)
{
acpi_status status = AE_OK;
@@ -167,31 +201,23 @@ static int acpi_power_get_state(acpi_handle handle, int *state)
return 0;
}
-static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
+static int acpi_power_get_list_state(struct list_head *list, int *state)
{
+ struct acpi_power_resource_entry *entry;
int cur_state;
- int i = 0;
if (!list || !state)
return -EINVAL;
/* The state of the list is 'on' IFF all resources are 'on'. */
-
- for (i = 0; i < list->count; i++) {
- struct acpi_power_resource *resource;
- acpi_handle handle = list->handles[i];
+ list_for_each_entry(entry, list, node) {
+ struct acpi_power_resource *resource = entry->resource;
+ acpi_handle handle = resource->device.handle;
int result;
- result = acpi_power_get_context(handle, &resource);
- if (result)
- return result;
-
mutex_lock(&resource->resource_lock);
-
result = acpi_power_get_state(handle, &cur_state);
-
mutex_unlock(&resource->resource_lock);
-
if (result)
return result;
@@ -203,54 +229,52 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
cur_state ? "on" : "off"));
*state = cur_state;
-
return 0;
}
-/* Resume the device when all power resources in _PR0 are on */
-static void acpi_power_on_device(struct acpi_power_managed_device *device)
+static void acpi_power_resume_dependent(struct work_struct *work)
{
- struct acpi_device *acpi_dev;
- acpi_handle handle = device->handle;
+ struct acpi_power_dependent_device *dep;
+ struct acpi_device_physical_node *pn;
+ struct acpi_device *adev;
int state;
- if (acpi_bus_get_device(handle, &acpi_dev))
+ dep = container_of(work, struct acpi_power_dependent_device, work);
+ adev = dep->adev;
+ if (acpi_power_get_inferred_state(adev, &state))
return;
- if(acpi_power_get_inferred_state(acpi_dev, &state))
+ if (state > ACPI_STATE_D0)
return;
- if (state == ACPI_STATE_D0 && pm_runtime_suspended(device->dev))
- pm_request_resume(device->dev);
+ mutex_lock(&adev->physical_node_lock);
+
+ list_for_each_entry(pn, &adev->physical_node_list, node)
+ pm_request_resume(pn->dev);
+
+ list_for_each_entry(pn, &adev->power_dependent, node)
+ pm_request_resume(pn->dev);
+
+ mutex_unlock(&adev->physical_node_lock);
}
static int __acpi_power_on(struct acpi_power_resource *resource)
{
acpi_status status = AE_OK;
- status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
+ status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL);
if (ACPI_FAILURE(status))
return -ENODEV;
- /* Update the power resource's _device_ power state */
- resource->device->power.state = ACPI_STATE_D0;
-
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
resource->name));
return 0;
}
-static int acpi_power_on(acpi_handle handle)
+static int acpi_power_on(struct acpi_power_resource *resource)
{
- int result = 0;
- bool resume_device = false;
- struct acpi_power_resource *resource = NULL;
- struct acpi_power_resource_device *device_list;
-
- result = acpi_power_get_context(handle, &resource);
- if (result)
- return result;
+ int result = 0;;
mutex_lock(&resource->resource_lock);
@@ -260,39 +284,38 @@ static int acpi_power_on(acpi_handle handle)
resource->name));
} else {
result = __acpi_power_on(resource);
- if (result)
+ if (result) {
resource->ref_count--;
- else
- resume_device = true;
+ } else {
+ struct acpi_power_dependent_device *dep;
+
+ list_for_each_entry(dep, &resource->dependent, node)
+ schedule_work(&dep->work);
+ }
}
mutex_unlock(&resource->resource_lock);
- if (!resume_device)
- return result;
-
- mutex_lock(&resource->devices_lock);
+ return result;
+}
- device_list = resource->devices;
- while (device_list) {
- acpi_power_on_device(device_list->device);
- device_list = device_list->next;
- }
+static int __acpi_power_off(struct acpi_power_resource *resource)
+{
+ acpi_status status;
- mutex_unlock(&resource->devices_lock);
+ status = acpi_evaluate_object(resource->device.handle, "_OFF",
+ NULL, NULL);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
- return result;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned off\n",
+ resource->name));
+ return 0;
}
-static int acpi_power_off(acpi_handle handle)
+static int acpi_power_off(struct acpi_power_resource *resource)
{
int result = 0;
- acpi_status status = AE_OK;
- struct acpi_power_resource *resource = NULL;
-
- result = acpi_power_get_context(handle, &resource);
- if (result)
- return result;
mutex_lock(&resource->resource_lock);
@@ -307,19 +330,10 @@ static int acpi_power_off(acpi_handle handle)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Power resource [%s] still in use\n",
resource->name));
- goto unlock;
- }
-
- status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
- if (ACPI_FAILURE(status)) {
- result = -ENODEV;
} else {
- /* Update the power resource's _device_ power state */
- resource->device->power.state = ACPI_STATE_D3;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Power resource [%s] turned off\n",
- resource->name));
+ result = __acpi_power_off(resource);
+ if (result)
+ resource->ref_count++;
}
unlock:
@@ -328,148 +342,202 @@ static int acpi_power_off(acpi_handle handle)
return result;
}
-static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res)
+static int acpi_power_off_list(struct list_head *list)
{
- int i;
+ struct acpi_power_resource_entry *entry;
+ int result = 0;
- for (i = num_res - 1; i >= 0 ; i--)
- acpi_power_off(list->handles[i]);
-}
+ list_for_each_entry_reverse(entry, list, node) {
+ result = acpi_power_off(entry->resource);
+ if (result)
+ goto err;
+ }
+ return 0;
-static void acpi_power_off_list(struct acpi_handle_list *list)
-{
- __acpi_power_off_list(list, list->count);
+ err:
+ list_for_each_entry_continue(entry, list, node)
+ acpi_power_on(entry->resource);
+
+ return result;
}
-static int acpi_power_on_list(struct acpi_handle_list *list)
+static int acpi_power_on_list(struct list_head *list)
{
+ struct acpi_power_resource_entry *entry;
int result = 0;
- int i;
- for (i = 0; i < list->count; i++) {
- result = acpi_power_on(list->handles[i]);
- if (result) {
- __acpi_power_off_list(list, i);
- break;
- }
+ list_for_each_entry(entry, list, node) {
+ result = acpi_power_on(entry->resource);
+ if (result)
+ goto err;
}
+ return 0;
+
+ err:
+ list_for_each_entry_continue_reverse(entry, list, node)
+ acpi_power_off(entry->resource);
return result;
}
-static void __acpi_power_resource_unregister_device(struct device *dev,
- acpi_handle res_handle)
+static void acpi_power_add_dependent(struct acpi_power_resource *resource,
+ struct acpi_device *adev)
{
- struct acpi_power_resource *resource = NULL;
- struct acpi_power_resource_device *prev, *curr;
+ struct acpi_power_dependent_device *dep;
- if (acpi_power_get_context(res_handle, &resource))
- return;
+ mutex_lock(&resource->resource_lock);
+
+ list_for_each_entry(dep, &resource->dependent, node)
+ if (dep->adev == adev)
+ goto out;
+
+ dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+ if (!dep)
+ goto out;
+
+ dep->adev = adev;
+ INIT_WORK(&dep->work, acpi_power_resume_dependent);
+ list_add_tail(&dep->node, &resource->dependent);
- mutex_lock(&resource->devices_lock);
- prev = NULL;
- curr = resource->devices;
- while (curr) {
- if (curr->device->dev == dev) {
- if (!prev)
- resource->devices = curr->next;
- else
- prev->next = curr->next;
-
- kfree(curr);
+ out:
+ mutex_unlock(&resource->resource_lock);
+}
+
+static void acpi_power_remove_dependent(struct acpi_power_resource *resource,
+ struct acpi_device *adev)
+{
+ struct acpi_power_dependent_device *dep;
+ struct work_struct *work = NULL;
+
+ mutex_lock(&resource->resource_lock);
+
+ list_for_each_entry(dep, &resource->dependent, node)
+ if (dep->adev == adev) {
+ list_del(&dep->node);
+ work = &dep->work;
break;
}
- prev = curr;
- curr = curr->next;
+ mutex_unlock(&resource->resource_lock);
+
+ if (work) {
+ cancel_work_sync(work);
+ kfree(dep);
}
- mutex_unlock(&resource->devices_lock);
}
-/* Unlink dev from all power resources in _PR0 */
-void acpi_power_resource_unregister_device(struct device *dev, acpi_handle handle)
-{
- struct acpi_device *acpi_dev;
- struct acpi_handle_list *list;
- int i;
+static struct attribute *attrs[] = {
+ NULL,
+};
- if (!dev || !handle)
- return;
+static struct attribute_group attr_groups[] = {
+ [ACPI_STATE_D0] = {
+ .name = "power_resources_D0",
+ .attrs = attrs,
+ },
+ [ACPI_STATE_D1] = {
+ .name = "power_resources_D1",
+ .attrs = attrs,
+ },
+ [ACPI_STATE_D2] = {
+ .name = "power_resources_D2",
+ .attrs = attrs,
+ },
+ [ACPI_STATE_D3_HOT] = {
+ .name = "power_resources_D3hot",
+ .attrs = attrs,
+ },
+};
- if (acpi_bus_get_device(handle, &acpi_dev))
+static void acpi_power_hide_list(struct acpi_device *adev, int state)
+{
+ struct acpi_device_power_state *ps = &adev->power.states[state];
+ struct acpi_power_resource_entry *entry;
+
+ if (list_empty(&ps->resources))
return;
- list = &acpi_dev->power.states[ACPI_STATE_D0].resources;
+ list_for_each_entry_reverse(entry, &ps->resources, node) {
+ struct acpi_device *res_dev = &entry->resource->device;
- for (i = 0; i < list->count; i++)
- __acpi_power_resource_unregister_device(dev,
- list->handles[i]);
+ sysfs_remove_link_from_group(&adev->dev.kobj,
+ attr_groups[state].name,
+ dev_name(&res_dev->dev));
+ }
+ sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]);
}
-EXPORT_SYMBOL_GPL(acpi_power_resource_unregister_device);
-static int __acpi_power_resource_register_device(
- struct acpi_power_managed_device *powered_device, acpi_handle handle)
+static void acpi_power_expose_list(struct acpi_device *adev, int state)
{
- struct acpi_power_resource *resource = NULL;
- struct acpi_power_resource_device *power_resource_device;
- int result;
-
- result = acpi_power_get_context(handle, &resource);
- if (result)
- return result;
+ struct acpi_device_power_state *ps = &adev->power.states[state];
+ struct acpi_power_resource_entry *entry;
+ int ret;
- power_resource_device = kzalloc(
- sizeof(*power_resource_device), GFP_KERNEL);
- if (!power_resource_device)
- return -ENOMEM;
+ if (list_empty(&ps->resources))
+ return;
- power_resource_device->device = powered_device;
+ ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]);
+ if (ret)
+ return;
- mutex_lock(&resource->devices_lock);
- power_resource_device->next = resource->devices;
- resource->devices = power_resource_device;
- mutex_unlock(&resource->devices_lock);
+ list_for_each_entry(entry, &ps->resources, node) {
+ struct acpi_device *res_dev = &entry->resource->device;
- return 0;
+ ret = sysfs_add_link_to_group(&adev->dev.kobj,
+ attr_groups[state].name,
+ &res_dev->dev.kobj,
+ dev_name(&res_dev->dev));
+ if (ret) {
+ acpi_power_hide_list(adev, state);
+ break;
+ }
+ }
}
-/* Link dev to all power resources in _PR0 */
-int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
+void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
{
- struct acpi_device *acpi_dev;
- struct acpi_handle_list *list;
- struct acpi_power_managed_device *powered_device;
- int i, ret;
+ struct acpi_device_power_state *ps;
+ struct acpi_power_resource_entry *entry;
+ int state;
- if (!dev || !handle)
- return -ENODEV;
+ if (!adev->power.flags.power_resources)
+ return;
- ret = acpi_bus_get_device(handle, &acpi_dev);
- if (ret || !acpi_dev->power.flags.power_resources)
- return -ENODEV;
+ ps = &adev->power.states[ACPI_STATE_D0];
+ list_for_each_entry(entry, &ps->resources, node) {
+ struct acpi_power_resource *resource = entry->resource;
- powered_device = kzalloc(sizeof(*powered_device), GFP_KERNEL);
- if (!powered_device)
- return -ENOMEM;
+ if (add)
+ acpi_power_add_dependent(resource, adev);
+ else
+ acpi_power_remove_dependent(resource, adev);
+ }
- powered_device->dev = dev;
- powered_device->handle = handle;
+ for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) {
+ if (add)
+ acpi_power_expose_list(adev, state);
+ else
+ acpi_power_hide_list(adev, state);
+ }
+}
- list = &acpi_dev->power.states[ACPI_STATE_D0].resources;
+int acpi_power_min_system_level(struct list_head *list)
+{
+ struct acpi_power_resource_entry *entry;
+ int system_level = 5;
- for (i = 0; i < list->count; i++) {
- ret = __acpi_power_resource_register_device(powered_device,
- list->handles[i]);
+ list_for_each_entry(entry, list, node) {
+ struct acpi_power_resource *resource = entry->resource;
- if (ret) {
- acpi_power_resource_unregister_device(dev, handle);
- break;
- }
+ if (system_level > resource->system_level)
+ system_level = resource->system_level;
}
-
- return ret;
+ return system_level;
}
-EXPORT_SYMBOL_GPL(acpi_power_resource_register_device);
+
+/* --------------------------------------------------------------------------
+ Device Power Management
+ -------------------------------------------------------------------------- */
/**
* acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
@@ -542,7 +610,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
*/
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
{
- int i, err = 0;
+ int err = 0;
if (!dev || !dev->wakeup.flags.valid)
return -EINVAL;
@@ -552,24 +620,17 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
if (dev->wakeup.prepare_count++)
goto out;
- /* Open power resource */
- for (i = 0; i < dev->wakeup.resources.count; i++) {
- int ret = acpi_power_on(dev->wakeup.resources.handles[i]);
- if (ret) {
- printk(KERN_ERR PREFIX "Transition power state\n");
- dev->wakeup.flags.valid = 0;
- err = -ENODEV;
- goto err_out;
- }
+ err = acpi_power_on_list(&dev->wakeup.resources);
+ if (err) {
+ dev_err(&dev->dev, "Cannot turn wakeup power resources on\n");
+ dev->wakeup.flags.valid = 0;
+ } else {
+ /*
+ * Passing 3 as the third argument below means the device may be
+ * put into arbitrary power state afterward.
+ */
+ err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
}
-
- /*
- * Passing 3 as the third argument below means the device may be placed
- * in arbitrary power state afterwards.
- */
- err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
-
- err_out:
if (err)
dev->wakeup.prepare_count = 0;
@@ -586,7 +647,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
*/
int acpi_disable_wakeup_device_power(struct acpi_device *dev)
{
- int i, err = 0;
+ int err = 0;
if (!dev || !dev->wakeup.flags.valid)
return -EINVAL;
@@ -607,15 +668,10 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
if (err)
goto out;
- /* Close power resource */
- for (i = 0; i < dev->wakeup.resources.count; i++) {
- int ret = acpi_power_off(dev->wakeup.resources.handles[i]);
- if (ret) {
- printk(KERN_ERR PREFIX "Transition power state\n");
- dev->wakeup.flags.valid = 0;
- err = -ENODEV;
- goto out;
- }
+ err = acpi_power_off_list(&dev->wakeup.resources);
+ if (err) {
+ dev_err(&dev->dev, "Cannot turn wakeup power resources off\n");
+ dev->wakeup.flags.valid = 0;
}
out:
@@ -623,14 +679,9 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
return err;
}
-/* --------------------------------------------------------------------------
- Device Power Management
- -------------------------------------------------------------------------- */
-
int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
{
int result = 0;
- struct acpi_handle_list *list = NULL;
int list_state = 0;
int i = 0;
@@ -642,8 +693,9 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
* required for a given D-state are 'on'.
*/
for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
- list = &device->power.states[i].resources;
- if (list->count < 1)
+ struct list_head *list = &device->power.states[i].resources;
+
+ if (list_empty(list))
continue;
result = acpi_power_get_list_state(list, &list_state);
@@ -662,7 +714,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
int acpi_power_on_resources(struct acpi_device *device, int state)
{
- if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
+ if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3_HOT)
return -EINVAL;
return acpi_power_on_list(&device->power.states[state].resources);
@@ -675,7 +727,7 @@ int acpi_power_transition(struct acpi_device *device, int state)
if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
return -EINVAL;
- if (device->power.state == state)
+ if (device->power.state == state || !device->flags.power_manageable)
return 0;
if ((device->power.state < ACPI_STATE_D0)
@@ -703,118 +755,126 @@ int acpi_power_transition(struct acpi_device *device, int state)
return result;
}
-/* --------------------------------------------------------------------------
- Driver Interface
- -------------------------------------------------------------------------- */
+static void acpi_release_power_resource(struct device *dev)
+{
+ struct acpi_device *device = to_acpi_device(dev);
+ struct acpi_power_resource *resource;
+
+ resource = container_of(device, struct acpi_power_resource, device);
+
+ mutex_lock(&power_resource_list_lock);
+ list_del(&resource->list_node);
+ mutex_unlock(&power_resource_list_lock);
+
+ acpi_free_ids(device);
+ kfree(resource);
+}
-static int acpi_power_add(struct acpi_device *device)
+static ssize_t acpi_power_in_use_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+ struct acpi_power_resource *resource;
+
+ resource = to_power_resource(to_acpi_device(dev));
+ return sprintf(buf, "%u\n", !!resource->ref_count);
+}
+static DEVICE_ATTR(resource_in_use, 0444, acpi_power_in_use_show, NULL);
+
+static void acpi_power_sysfs_remove(struct acpi_device *device)
{
- int result = 0, state;
- acpi_status status = AE_OK;
- struct acpi_power_resource *resource = NULL;
+ device_remove_file(&device->dev, &dev_attr_resource_in_use);
+}
+
+int acpi_add_power_resource(acpi_handle handle)
+{
+ struct acpi_power_resource *resource;
+ struct acpi_device *device = NULL;
union acpi_object acpi_object;
struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
+ acpi_status status;
+ int state, result = -ENODEV;
+ acpi_bus_get_device(handle, &device);
+ if (device)
+ return 0;
- if (!device)
- return -EINVAL;
-
- resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
+ resource = kzalloc(sizeof(*resource), GFP_KERNEL);
if (!resource)
return -ENOMEM;
- resource->device = device;
+ device = &resource->device;
+ acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER,
+ ACPI_STA_DEFAULT);
mutex_init(&resource->resource_lock);
- mutex_init(&resource->devices_lock);
- strcpy(resource->name, device->pnp.bus_id);
+ INIT_LIST_HEAD(&resource->dependent);
+ resource->name = device->pnp.bus_id;
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
- device->driver_data = resource;
+ device->power.state = ACPI_STATE_UNKNOWN;
/* Evalute the object to get the system level and resource order. */
- status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- result = -ENODEV;
- goto end;
- }
+ status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ goto err;
+
resource->system_level = acpi_object.power_resource.system_level;
resource->order = acpi_object.power_resource.resource_order;
- result = acpi_power_get_state(device->handle, &state);
+ result = acpi_power_get_state(handle, &state);
if (result)
- goto end;
-
- switch (state) {
- case ACPI_POWER_RESOURCE_STATE_ON:
- device->power.state = ACPI_STATE_D0;
- break;
- case ACPI_POWER_RESOURCE_STATE_OFF:
- device->power.state = ACPI_STATE_D3;
- break;
- default:
- device->power.state = ACPI_STATE_UNKNOWN;
- break;
- }
+ goto err;
printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device),
acpi_device_bid(device), state ? "on" : "off");
- end:
+ device->flags.match_driver = true;
+ result = acpi_device_add(device, acpi_release_power_resource);
if (result)
- kfree(resource);
+ goto err;
- return result;
-}
-
-static int acpi_power_remove(struct acpi_device *device, int type)
-{
- struct acpi_power_resource *resource;
-
- if (!device)
- return -EINVAL;
-
- resource = acpi_driver_data(device);
- if (!resource)
- return -EINVAL;
-
- kfree(resource);
+ if (!device_create_file(&device->dev, &dev_attr_resource_in_use))
+ device->remove = acpi_power_sysfs_remove;
+ mutex_lock(&power_resource_list_lock);
+ list_add(&resource->list_node, &acpi_power_resource_list);
+ mutex_unlock(&power_resource_list_lock);
+ acpi_device_add_finalize(device);
return 0;
+
+ err:
+ acpi_release_power_resource(&device->dev);
+ return result;
}
-#ifdef CONFIG_PM_SLEEP
-static int acpi_power_resume(struct device *dev)
+#ifdef CONFIG_ACPI_SLEEP
+void acpi_resume_power_resources(void)
{
- int result = 0, state;
- struct acpi_device *device;
struct acpi_power_resource *resource;
- if (!dev)
- return -EINVAL;
+ mutex_lock(&power_resource_list_lock);
- device = to_acpi_device(dev);
- resource = acpi_driver_data(device);
- if (!resource)
- return -EINVAL;
+ list_for_each_entry(resource, &acpi_power_resource_list, list_node) {
+ int result, state;
- mutex_lock(&resource->resource_lock);
+ mutex_lock(&resource->resource_lock);
- result = acpi_power_get_state(device->handle, &state);
- if (result)
- goto unlock;
+ result = acpi_power_get_state(resource->device.handle, &state);
+ if (result)
+ continue;
- if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count)
- result = __acpi_power_on(resource);
+ if (state == ACPI_POWER_RESOURCE_STATE_OFF
+ && resource->ref_count) {
+ dev_info(&resource->device.dev, "Turning ON\n");
+ __acpi_power_on(resource);
+ } else if (state == ACPI_POWER_RESOURCE_STATE_ON
+ && !resource->ref_count) {
+ dev_info(&resource->device.dev, "Turning OFF\n");
+ __acpi_power_off(resource);
+ }
- unlock:
- mutex_unlock(&resource->resource_lock);
+ mutex_unlock(&resource->resource_lock);
+ }
- return result;
+ mutex_unlock(&power_resource_list_lock);
}
#endif
-
-int __init acpi_power_init(void)
-{
- INIT_LIST_HEAD(&acpi_power_resource_list);
- return acpi_bus_register_driver(&acpi_power_driver);
-}
diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c
index ef98796b3824..52ce76725c20 100644
--- a/drivers/acpi/proc.c
+++ b/drivers/acpi/proc.c
@@ -311,11 +311,12 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
dev->pnp.bus_id,
(u32) dev->wakeup.sleep_state);
- if (!dev->physical_node_count)
+ if (!dev->physical_node_count) {
seq_printf(seq, "%c%-8s\n",
- dev->wakeup.flags.run_wake ?
- '*' : ' ', "disabled");
- else {
+ dev->wakeup.flags.run_wake ? '*' : ' ',
+ device_may_wakeup(&dev->dev) ?
+ "enabled" : "disabled");
+ } else {
struct device *ldev;
list_for_each_entry(entry, &dev->physical_node_list,
node) {
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index e83311bf1ebd..df34bd04ae62 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -45,6 +45,7 @@
#include <linux/cpuidle.h>
#include <linux/slab.h>
#include <linux/acpi.h>
+#include <linux/memory_hotplug.h>
#include <asm/io.h>
#include <asm/cpu.h>
@@ -81,7 +82,7 @@ MODULE_DESCRIPTION("ACPI Processor Driver");
MODULE_LICENSE("GPL");
static int acpi_processor_add(struct acpi_device *device);
-static int acpi_processor_remove(struct acpi_device *device, int type);
+static int acpi_processor_remove(struct acpi_device *device);
static void acpi_processor_notify(struct acpi_device *device, u32 event);
static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr);
static int acpi_processor_handle_eject(struct acpi_processor *pr);
@@ -610,7 +611,7 @@ err_free_pr:
return result;
}
-static int acpi_processor_remove(struct acpi_device *device, int type)
+static int acpi_processor_remove(struct acpi_device *device)
{
struct acpi_processor *pr = NULL;
@@ -623,7 +624,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
if (pr->id >= nr_cpu_ids)
goto free;
- if (type == ACPI_BUS_REMOVAL_EJECT) {
+ if (device->removal_type == ACPI_BUS_REMOVAL_EJECT) {
if (acpi_processor_handle_eject(pr))
return -EINVAL;
}
@@ -641,6 +642,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
per_cpu(processors, pr->id) = NULL;
per_cpu(processor_device_array, pr->id) = NULL;
+ try_offline_node(cpu_to_node(pr->id));
free:
free_cpumask_var(pr->throttling.shared_cpu_map);
@@ -677,36 +679,17 @@ static int is_processor_present(acpi_handle handle)
return 0;
}
-static
-int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
-{
- acpi_handle phandle;
- struct acpi_device *pdev;
-
-
- if (acpi_get_parent(handle, &phandle)) {
- return -ENODEV;
- }
-
- if (acpi_bus_get_device(phandle, &pdev)) {
- return -ENODEV;
- }
-
- if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
- return -ENODEV;
- }
-
- return 0;
-}
-
static void acpi_processor_hotplug_notify(acpi_handle handle,
u32 event, void *data)
{
struct acpi_device *device = NULL;
struct acpi_eject_event *ej_event = NULL;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+ acpi_status status;
int result;
+ acpi_scan_lock_acquire();
+
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
@@ -721,12 +704,16 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
if (!acpi_bus_get_device(handle, &device))
break;
- result = acpi_processor_device_add(handle, &device);
+ result = acpi_bus_scan(handle);
if (result) {
acpi_handle_err(handle, "Unable to add the device\n");
break;
}
-
+ result = acpi_bus_get_device(handle, &device);
+ if (result) {
+ acpi_handle_err(handle, "Missing device object\n");
+ break;
+ }
ost_code = ACPI_OST_SC_SUCCESS;
break;
@@ -751,25 +738,32 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
break;
}
- ej_event->handle = handle;
+ get_device(&device->dev);
+ ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
- acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
- (void *)ej_event);
-
- /* eject is performed asynchronously */
- return;
+ /* The eject is carried out asynchronously. */
+ status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
+ ej_event);
+ if (ACPI_FAILURE(status)) {
+ put_device(&device->dev);
+ kfree(ej_event);
+ break;
+ }
+ goto out;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
/* non-hotplug event; possibly handled by other handler */
- return;
+ goto out;
}
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
- return;
+
+ out:
+ acpi_scan_lock_release();
}
static acpi_status is_processor_device(acpi_handle handle)
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index ed9a1cc690be..fc95308e9a11 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -28,19 +28,12 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h> /* need_resched() */
-#include <linux/pm_qos.h>
+#include <linux/sched.h> /* need_resched() */
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
-#include <linux/irqflags.h>
/*
* Include the apic definitions for x86 to have the APIC timer related defines
@@ -52,22 +45,14 @@
#include <asm/apic.h>
#endif
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
#include <acpi/acpi_bus.h>
#include <acpi/processor.h>
-#include <asm/processor.h>
#define PREFIX "ACPI: "
#define ACPI_PROCESSOR_CLASS "processor"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_idle");
-#define PM_TIMER_TICK_NS (1000000000ULL/PM_TIMER_FREQUENCY)
-#define C2_OVERHEAD 1 /* 1us */
-#define C3_OVERHEAD 1 /* 1us */
-#define PM_TIMER_TICKS_TO_US(p) (((p) * 1000)/(PM_TIMER_FREQUENCY/1000))
static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER;
module_param(max_cstate, uint, 0000);
@@ -81,10 +66,11 @@ module_param(latency_factor, uint, 0644);
static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device);
+static struct acpi_processor_cx *acpi_cstate[CPUIDLE_STATE_MAX];
+
static int disabled_by_idle_boot_param(void)
{
return boot_option_idle_override == IDLE_POLL ||
- boot_option_idle_override == IDLE_FORCE_MWAIT ||
boot_option_idle_override == IDLE_HALT;
}
@@ -736,8 +722,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
struct acpi_processor *pr;
- struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
- struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
+ struct acpi_processor_cx *cx = acpi_cstate[index];
pr = __this_cpu_read(processors);
@@ -760,8 +745,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
*/
static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
{
- struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
- struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
+ struct acpi_processor_cx *cx = acpi_cstate[index];
ACPI_FLUSH_CPU_CACHE();
@@ -791,8 +775,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
struct acpi_processor *pr;
- struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
- struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
+ struct acpi_processor_cx *cx = acpi_cstate[index];
pr = __this_cpu_read(processors);
@@ -850,8 +833,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
struct acpi_processor *pr;
- struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
- struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
+ struct acpi_processor_cx *cx = acpi_cstate[index];
pr = __this_cpu_read(processors);
@@ -943,13 +925,13 @@ struct cpuidle_driver acpi_idle_driver = {
* device i.e. per-cpu data
*
* @pr: the ACPI processor
+ * @dev : the cpuidle device
*/
-static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr)
+static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
+ struct cpuidle_device *dev)
{
int i, count = CPUIDLE_DRIVER_STATE_START;
struct acpi_processor_cx *cx;
- struct cpuidle_state_usage *state_usage;
- struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id);
if (!pr->flags.power_setup_done)
return -EINVAL;
@@ -968,7 +950,6 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr)
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
cx = &pr->power.states[i];
- state_usage = &dev->states_usage[count];
if (!cx->valid)
continue;
@@ -979,8 +960,7 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr)
!(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
continue;
#endif
-
- cpuidle_set_statedata(state_usage, cx);
+ acpi_cstate[count] = cx;
count++;
if (count == CPUIDLE_STATE_MAX)
@@ -1104,7 +1084,7 @@ int acpi_processor_hotplug(struct acpi_processor *pr)
cpuidle_disable_device(dev);
acpi_processor_get_power_info(pr);
if (pr->flags.power) {
- acpi_processor_setup_cpuidle_cx(pr);
+ acpi_processor_setup_cpuidle_cx(pr, dev);
ret = cpuidle_enable_device(dev);
}
cpuidle_resume_and_unlock();
@@ -1162,8 +1142,8 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
continue;
acpi_processor_get_power_info(_pr);
if (_pr->flags.power) {
- acpi_processor_setup_cpuidle_cx(_pr);
dev = per_cpu(acpi_cpuidle_device, cpu);
+ acpi_processor_setup_cpuidle_cx(_pr, dev);
cpuidle_enable_device(dev);
}
}
@@ -1232,7 +1212,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr)
return -ENOMEM;
per_cpu(acpi_cpuidle_device, pr->id) = dev;
- acpi_processor_setup_cpuidle_cx(pr);
+ acpi_processor_setup_cpuidle_cx(pr, dev);
/* Register per-cpu cpuidle_device. Cpuidle driver
* must already be registered before registering device
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index ff0740e0a9c2..e523245643ac 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -130,7 +130,7 @@ struct acpi_sbs {
#define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger)
-static int acpi_sbs_remove(struct acpi_device *device, int type);
+static int acpi_sbs_remove(struct acpi_device *device);
static int acpi_battery_get_state(struct acpi_battery *battery);
static inline int battery_scale(int log)
@@ -949,11 +949,11 @@ static int acpi_sbs_add(struct acpi_device *device)
acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs);
end:
if (result)
- acpi_sbs_remove(device, 0);
+ acpi_sbs_remove(device);
return result;
}
-static int acpi_sbs_remove(struct acpi_device *device, int type)
+static int acpi_sbs_remove(struct acpi_device *device)
{
struct acpi_sbs *sbs;
int id;
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index cf6129a8af7c..b78bc605837e 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -33,7 +33,7 @@ struct acpi_smb_hc {
};
static int acpi_smbus_hc_add(struct acpi_device *device);
-static int acpi_smbus_hc_remove(struct acpi_device *device, int type);
+static int acpi_smbus_hc_remove(struct acpi_device *device);
static const struct acpi_device_id sbs_device_ids[] = {
{"ACPI0001", 0},
@@ -296,7 +296,7 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
-static int acpi_smbus_hc_remove(struct acpi_device *device, int type)
+static int acpi_smbus_hc_remove(struct acpi_device *device)
{
struct acpi_smb_hc *hc;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index c88be6c37c30..daee7497efd3 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -29,29 +29,10 @@ extern struct acpi_device *acpi_root;
static const char *dummy_hid = "device";
-/*
- * The following ACPI IDs are known to be suitable for representing as
- * platform devices.
- */
-static const struct acpi_device_id acpi_platform_device_ids[] = {
-
- { "PNP0D40" },
-
- /* Haswell LPSS devices */
- { "INT33C0", 0 },
- { "INT33C1", 0 },
- { "INT33C2", 0 },
- { "INT33C3", 0 },
- { "INT33C4", 0 },
- { "INT33C5", 0 },
- { "INT33C6", 0 },
- { "INT33C7", 0 },
-
- { }
-};
-
static LIST_HEAD(acpi_device_list);
static LIST_HEAD(acpi_bus_id_list);
+static DEFINE_MUTEX(acpi_scan_lock);
+static LIST_HEAD(acpi_scan_handlers_list);
DEFINE_MUTEX(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
@@ -61,6 +42,27 @@ struct acpi_device_bus_id{
struct list_head node;
};
+void acpi_scan_lock_acquire(void)
+{
+ mutex_lock(&acpi_scan_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_scan_lock_acquire);
+
+void acpi_scan_lock_release(void)
+{
+ mutex_unlock(&acpi_scan_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_scan_lock_release);
+
+int acpi_scan_add_handler(struct acpi_scan_handler *handler)
+{
+ if (!handler || !handler->attach)
+ return -EINVAL;
+
+ list_add_tail(&handler->list_node, &acpi_scan_handlers_list);
+ return 0;
+}
+
/*
* Creates hid/cid(s) string needed for modalias and uevent
* e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
@@ -115,39 +117,32 @@ static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
*/
void acpi_bus_hot_remove_device(void *context)
{
- struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context;
- struct acpi_device *device;
- acpi_handle handle = ej_event->handle;
+ struct acpi_eject_event *ej_event = context;
+ struct acpi_device *device = ej_event->device;
+ acpi_handle handle = device->handle;
acpi_handle temp;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
- if (acpi_bus_get_device(handle, &device))
- goto err_out;
+ mutex_lock(&acpi_scan_lock);
- if (!device)
- goto err_out;
+ /* If there is no handle, the device node has been unregistered. */
+ if (!device->handle) {
+ dev_dbg(&device->dev, "ACPI handle missing\n");
+ put_device(&device->dev);
+ goto out;
+ }
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Hot-removing device %s...\n", dev_name(&device->dev)));
- if (acpi_bus_trim(device, 1)) {
- printk(KERN_ERR PREFIX
- "Removing device failed\n");
- goto err_out;
- }
-
- /* device has been freed */
+ acpi_bus_trim(device);
+ /* Device node has been unregistered. */
+ put_device(&device->dev);
device = NULL;
- /* power off device */
- status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
- printk(KERN_WARNING PREFIX
- "Power-off device failed\n");
-
if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
arg_list.count = 1;
arg_list.pointer = &arg;
@@ -167,23 +162,46 @@ void acpi_bus_hot_remove_device(void *context)
status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND)
- printk(KERN_WARNING PREFIX
- "Eject device failed\n");
- goto err_out;
- }
+ acpi_handle_warn(handle, "Eject failed\n");
- kfree(context);
- return;
+ /* Tell the firmware the hot-remove operation has failed. */
+ acpi_evaluate_hotplug_ost(handle, ej_event->event,
+ ost_code, NULL);
+ }
-err_out:
- /* Inform firmware the hot-remove operation has completed w/ error */
- (void) acpi_evaluate_hotplug_ost(handle,
- ej_event->event, ost_code, NULL);
+ out:
+ mutex_unlock(&acpi_scan_lock);
kfree(context);
return;
}
EXPORT_SYMBOL(acpi_bus_hot_remove_device);
+static ssize_t real_power_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct acpi_device *adev = to_acpi_device(dev);
+ int state;
+ int ret;
+
+ ret = acpi_device_get_power(adev, &state);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%s\n", acpi_power_state_string(state));
+}
+
+static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL);
+
+static ssize_t power_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct acpi_device *adev = to_acpi_device(dev);
+
+ return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state));
+}
+
+static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
+
static ssize_t
acpi_eject_store(struct device *d, struct device_attribute *attr,
const char *buf, size_t count)
@@ -197,12 +215,10 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
if ((!count) || (buf[0] != '1')) {
return -EINVAL;
}
-#ifndef FORCE_EJECT
- if (acpi_device->driver == NULL) {
+ if (!acpi_device->driver && !acpi_device->handler) {
ret = -ENODEV;
goto err;
}
-#endif
status = acpi_get_type(acpi_device->handle, &type);
if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
ret = -ENODEV;
@@ -215,7 +231,8 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
goto err;
}
- ej_event->handle = acpi_device->handle;
+ get_device(&acpi_device->dev);
+ ej_event->device = acpi_device;
if (acpi_device->flags.eject_pending) {
/* event originated from ACPI eject notification */
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
@@ -223,11 +240,15 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
} else {
/* event originated from user */
ej_event->event = ACPI_OST_EC_OSPM_EJECT;
- (void) acpi_evaluate_hotplug_ost(ej_event->handle,
+ (void) acpi_evaluate_hotplug_ost(acpi_device->handle,
ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
}
- acpi_os_hotplug_execute(acpi_bus_hot_remove_device, (void *)ej_event);
+ status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
+ if (ACPI_FAILURE(status)) {
+ put_device(&acpi_device->dev);
+ kfree(ej_event);
+ }
err:
return ret;
}
@@ -375,8 +396,22 @@ static int acpi_device_setup_files(struct acpi_device *dev)
* hot-removal function from userland.
*/
status = acpi_get_handle(dev->handle, "_EJ0", &temp);
- if (ACPI_SUCCESS(status))
+ if (ACPI_SUCCESS(status)) {
result = device_create_file(&dev->dev, &dev_attr_eject);
+ if (result)
+ return result;
+ }
+
+ if (dev->flags.power_manageable) {
+ result = device_create_file(&dev->dev, &dev_attr_power_state);
+ if (result)
+ return result;
+
+ if (dev->power.flags.power_resources)
+ result = device_create_file(&dev->dev,
+ &dev_attr_real_power_state);
+ }
+
end:
return result;
}
@@ -386,6 +421,13 @@ static void acpi_device_remove_files(struct acpi_device *dev)
acpi_status status;
acpi_handle temp;
+ if (dev->flags.power_manageable) {
+ device_remove_file(&dev->dev, &dev_attr_power_state);
+ if (dev->power.flags.power_resources)
+ device_remove_file(&dev->dev,
+ &dev_attr_real_power_state);
+ }
+
/*
* If device has _STR, remove 'description' file
*/
@@ -454,9 +496,9 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
const struct device *dev)
{
struct acpi_device *adev;
+ acpi_handle handle = ACPI_HANDLE(dev);
- if (!ids || !ACPI_HANDLE(dev)
- || ACPI_FAILURE(acpi_bus_get_device(ACPI_HANDLE(dev), &adev)))
+ if (!ids || !handle || acpi_bus_get_device(handle, &adev))
return NULL;
return __acpi_match_device(adev, ids);
@@ -470,7 +512,7 @@ int acpi_match_device_ids(struct acpi_device *device,
}
EXPORT_SYMBOL(acpi_match_device_ids);
-static void acpi_free_ids(struct acpi_device *device)
+void acpi_free_ids(struct acpi_device *device)
{
struct acpi_hardware_id *id, *tmp;
@@ -478,6 +520,23 @@ static void acpi_free_ids(struct acpi_device *device)
kfree(id->id);
kfree(id);
}
+ kfree(device->pnp.unique_id);
+}
+
+static void acpi_free_power_resources_lists(struct acpi_device *device)
+{
+ int i;
+
+ if (device->wakeup.flags.valid)
+ acpi_power_resources_list_free(&device->wakeup.resources);
+
+ if (!device->flags.power_manageable)
+ return;
+
+ for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
+ struct acpi_device_power_state *ps = &device->power.states[i];
+ acpi_power_resources_list_free(&ps->resources);
+ }
}
static void acpi_device_release(struct device *dev)
@@ -485,7 +544,7 @@ static void acpi_device_release(struct device *dev)
struct acpi_device *acpi_dev = to_acpi_device(dev);
acpi_free_ids(acpi_dev);
- kfree(acpi_dev->pnp.unique_id);
+ acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
}
@@ -494,7 +553,8 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
struct acpi_device *acpi_dev = to_acpi_device(dev);
struct acpi_driver *acpi_drv = to_acpi_driver(drv);
- return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
+ return acpi_dev->flags.match_driver
+ && !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
}
static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
@@ -570,7 +630,6 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device)
}
static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
-static int acpi_start_single_object(struct acpi_device *);
static int acpi_device_probe(struct device * dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
@@ -579,15 +638,13 @@ static int acpi_device_probe(struct device * dev)
ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
if (!ret) {
- if (acpi_dev->bus_ops.acpi_op_start)
- acpi_start_single_object(acpi_dev);
-
if (acpi_drv->ops.notify) {
ret = acpi_device_install_notify_handler(acpi_dev);
if (ret) {
if (acpi_drv->ops.remove)
- acpi_drv->ops.remove(acpi_dev,
- acpi_dev->removal_type);
+ acpi_drv->ops.remove(acpi_dev);
+ acpi_dev->driver = NULL;
+ acpi_dev->driver_data = NULL;
return ret;
}
}
@@ -609,7 +666,7 @@ static int acpi_device_remove(struct device * dev)
if (acpi_drv->ops.notify)
acpi_device_remove_notify_handler(acpi_dev);
if (acpi_drv->ops.remove)
- acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+ acpi_drv->ops.remove(acpi_dev);
}
acpi_dev->driver = NULL;
acpi_dev->driver_data = NULL;
@@ -626,12 +683,25 @@ struct bus_type acpi_bus_type = {
.uevent = acpi_device_uevent,
};
-static int acpi_device_register(struct acpi_device *device)
+int acpi_device_add(struct acpi_device *device,
+ void (*release)(struct device *))
{
int result;
struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
int found = 0;
+ if (device->handle) {
+ acpi_status status;
+
+ status = acpi_attach_data(device->handle, acpi_bus_data_handler,
+ device);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(device->handle,
+ "Unable to attach device data\n");
+ return -ENODEV;
+ }
+ }
+
/*
* Linkage
* -------
@@ -642,11 +712,13 @@ static int acpi_device_register(struct acpi_device *device)
INIT_LIST_HEAD(&device->wakeup_list);
INIT_LIST_HEAD(&device->physical_node_list);
mutex_init(&device->physical_node_lock);
+ INIT_LIST_HEAD(&device->power_dependent);
new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
if (!new_bus_id) {
- printk(KERN_ERR PREFIX "Memory allocation error\n");
- return -ENOMEM;
+ pr_err(PREFIX "Memory allocation error\n");
+ result = -ENOMEM;
+ goto err_detach;
}
mutex_lock(&acpi_device_lock);
@@ -681,11 +753,11 @@ static int acpi_device_register(struct acpi_device *device)
if (device->parent)
device->dev.parent = &device->parent->dev;
device->dev.bus = &acpi_bus_type;
- device->dev.release = &acpi_device_release;
- result = device_register(&device->dev);
+ device->dev.release = release;
+ result = device_add(&device->dev);
if (result) {
dev_err(&device->dev, "Error registering device\n");
- goto end;
+ goto err;
}
result = acpi_device_setup_files(device);
@@ -695,16 +767,20 @@ static int acpi_device_register(struct acpi_device *device)
device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
return 0;
-end:
+
+ err:
mutex_lock(&acpi_device_lock);
if (device->parent)
list_del(&device->node);
list_del(&device->wakeup_list);
mutex_unlock(&acpi_device_lock);
+
+ err_detach:
+ acpi_detach_data(device->handle, acpi_bus_data_handler);
return result;
}
-static void acpi_device_unregister(struct acpi_device *device, int type)
+static void acpi_device_unregister(struct acpi_device *device)
{
mutex_lock(&acpi_device_lock);
if (device->parent)
@@ -715,8 +791,20 @@ static void acpi_device_unregister(struct acpi_device *device, int type)
acpi_detach_data(device->handle, acpi_bus_data_handler);
+ acpi_power_add_remove_device(device, false);
acpi_device_remove_files(device);
- device_unregister(&device->dev);
+ if (device->remove)
+ device->remove(device);
+
+ device_del(&device->dev);
+ /*
+ * Transition the device to D3cold to drop the reference counts of all
+ * power resources the device depends on and turn off the ones that have
+ * no more references.
+ */
+ acpi_device_set_power(device, ACPI_STATE_D3_COLD);
+ device->handle = NULL;
+ put_device(&device->dev);
}
/* --------------------------------------------------------------------------
@@ -760,24 +848,6 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
return 0;
}
-static int acpi_start_single_object(struct acpi_device *device)
-{
- int result = 0;
- struct acpi_driver *driver;
-
-
- if (!(driver = device->driver))
- return 0;
-
- if (driver->ops.start) {
- result = driver->ops.start(device);
- if (result && driver->ops.remove)
- driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
- }
-
- return result;
-}
-
/**
* acpi_bus_register_driver - register a driver with the ACPI bus
* @driver: driver being registered
@@ -821,29 +891,23 @@ EXPORT_SYMBOL(acpi_bus_unregister_driver);
-------------------------------------------------------------------------- */
static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
{
+ struct acpi_device *device = NULL;
acpi_status status;
- int ret;
- struct acpi_device *device;
/*
* Fixed hardware devices do not appear in the namespace and do not
* have handles, but we fabricate acpi_devices for them, so we have
* to deal with them specially.
*/
- if (handle == NULL)
+ if (!handle)
return acpi_root;
do {
status = acpi_get_parent(handle, &handle);
- if (status == AE_NULL_ENTRY)
- return NULL;
if (ACPI_FAILURE(status))
- return acpi_root;
-
- ret = acpi_bus_get_device(handle, &device);
- if (ret == 0)
- return device;
- } while (1);
+ return status == AE_NULL_ENTRY ? NULL : acpi_root;
+ } while (acpi_bus_get_device(handle, &device));
+ return device;
}
acpi_status
@@ -877,52 +941,43 @@ void acpi_bus_data_handler(acpi_handle handle, void *context)
return;
}
-static int acpi_bus_get_perf_flags(struct acpi_device *device)
-{
- device->performance.state = ACPI_STATE_UNKNOWN;
- return 0;
-}
-
-static acpi_status
-acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
- struct acpi_device_wakeup *wakeup)
+static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
+ struct acpi_device_wakeup *wakeup)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL;
union acpi_object *element = NULL;
acpi_status status;
- int i = 0;
+ int err = -ENODATA;
if (!wakeup)
- return AE_BAD_PARAMETER;
+ return -EINVAL;
+
+ INIT_LIST_HEAD(&wakeup->resources);
/* _PRW */
status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
- return status;
+ return err;
}
package = (union acpi_object *)buffer.pointer;
- if (!package || (package->package.count < 2)) {
- status = AE_BAD_DATA;
+ if (!package || package->package.count < 2)
goto out;
- }
element = &(package->package.elements[0]);
- if (!element) {
- status = AE_BAD_DATA;
+ if (!element)
goto out;
- }
+
if (element->type == ACPI_TYPE_PACKAGE) {
if ((element->package.count < 2) ||
(element->package.elements[0].type !=
ACPI_TYPE_LOCAL_REFERENCE)
- || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) {
- status = AE_BAD_DATA;
+ || (element->package.elements[1].type != ACPI_TYPE_INTEGER))
goto out;
- }
+
wakeup->gpe_device =
element->package.elements[0].reference.handle;
wakeup->gpe_number =
@@ -931,38 +986,35 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
wakeup->gpe_device = NULL;
wakeup->gpe_number = element->integer.value;
} else {
- status = AE_BAD_DATA;
goto out;
}
element = &(package->package.elements[1]);
- if (element->type != ACPI_TYPE_INTEGER) {
- status = AE_BAD_DATA;
+ if (element->type != ACPI_TYPE_INTEGER)
goto out;
- }
+
wakeup->sleep_state = element->integer.value;
- if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
- status = AE_NO_MEMORY;
+ err = acpi_extract_power_resources(package, 2, &wakeup->resources);
+ if (err)
goto out;
- }
- wakeup->resources.count = package->package.count - 2;
- for (i = 0; i < wakeup->resources.count; i++) {
- element = &(package->package.elements[i + 2]);
- if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
- status = AE_BAD_DATA;
- goto out;
- }
- wakeup->resources.handles[i] = element->reference.handle;
- }
+ if (!list_empty(&wakeup->resources)) {
+ int sleep_state;
+ sleep_state = acpi_power_min_system_level(&wakeup->resources);
+ if (sleep_state < wakeup->sleep_state) {
+ acpi_handle_warn(handle, "Overriding _PRW sleep state "
+ "(S%d) by S%d from power resources\n",
+ (int)wakeup->sleep_state, sleep_state);
+ wakeup->sleep_state = sleep_state;
+ }
+ }
acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number);
out:
kfree(buffer.pointer);
-
- return status;
+ return err;
}
static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
@@ -1002,17 +1054,17 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
{
acpi_handle temp;
acpi_status status = 0;
- int psw_error;
+ int err;
/* Presence of _PRW indicates wake capable */
status = acpi_get_handle(device->handle, "_PRW", &temp);
if (ACPI_FAILURE(status))
return;
- status = acpi_bus_extract_wakeup_device_power_package(device->handle,
- &device->wakeup);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
+ err = acpi_bus_extract_wakeup_device_power_package(device->handle,
+ &device->wakeup);
+ if (err) {
+ dev_err(&device->dev, "_PRW evaluation error: %d\n", err);
return;
}
@@ -1025,20 +1077,73 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
* So it is necessary to call _DSW object first. Only when it is not
* present will the _PSW object used.
*/
- psw_error = acpi_device_sleep_wake(device, 0, 0, 0);
- if (psw_error)
+ err = acpi_device_sleep_wake(device, 0, 0, 0);
+ if (err)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"error in _DSW or _PSW evaluation\n"));
}
-static void acpi_bus_add_power_resource(acpi_handle handle);
+static void acpi_bus_init_power_state(struct acpi_device *device, int state)
+{
+ struct acpi_device_power_state *ps = &device->power.states[state];
+ char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' };
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_handle handle;
+ acpi_status status;
+
+ INIT_LIST_HEAD(&ps->resources);
+
+ /* Evaluate "_PRx" to get referenced power resources */
+ status = acpi_evaluate_object(device->handle, pathname, NULL, &buffer);
+ if (ACPI_SUCCESS(status)) {
+ union acpi_object *package = buffer.pointer;
+
+ if (buffer.length && package
+ && package->type == ACPI_TYPE_PACKAGE
+ && package->package.count) {
+ int err = acpi_extract_power_resources(package, 0,
+ &ps->resources);
+ if (!err)
+ device->power.flags.power_resources = 1;
+ }
+ ACPI_FREE(buffer.pointer);
+ }
+
+ /* Evaluate "_PSx" to see if we can do explicit sets */
+ pathname[2] = 'S';
+ status = acpi_get_handle(device->handle, pathname, &handle);
+ if (ACPI_SUCCESS(status))
+ ps->flags.explicit_set = 1;
+
+ /*
+ * State is valid if there are means to put the device into it.
+ * D3hot is only valid if _PR3 present.
+ */
+ if (!list_empty(&ps->resources)
+ || (ps->flags.explicit_set && state < ACPI_STATE_D3_HOT)) {
+ ps->flags.valid = 1;
+ ps->flags.os_accessible = 1;
+ }
+
+ ps->power = -1; /* Unknown - driver assigned */
+ ps->latency = -1; /* Unknown - driver assigned */
+}
-static int acpi_bus_get_power_flags(struct acpi_device *device)
+static void acpi_bus_get_power_flags(struct acpi_device *device)
{
- acpi_status status = 0;
- acpi_handle handle = NULL;
- u32 i = 0;
+ acpi_status status;
+ acpi_handle handle;
+ u32 i;
+
+ /* Presence of _PS0|_PR0 indicates 'power manageable' */
+ status = acpi_get_handle(device->handle, "_PS0", &handle);
+ if (ACPI_FAILURE(status)) {
+ status = acpi_get_handle(device->handle, "_PR0", &handle);
+ if (ACPI_FAILURE(status))
+ return;
+ }
+ device->flags.power_manageable = 1;
/*
* Power Management Flags
@@ -1053,40 +1158,10 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
/*
* Enumerate supported power management states
*/
- for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
- struct acpi_device_power_state *ps = &device->power.states[i];
- char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
-
- /* Evaluate "_PRx" to se if power resources are referenced */
- acpi_evaluate_reference(device->handle, object_name, NULL,
- &ps->resources);
- if (ps->resources.count) {
- int j;
-
- device->power.flags.power_resources = 1;
- for (j = 0; j < ps->resources.count; j++)
- acpi_bus_add_power_resource(ps->resources.handles[j]);
- }
+ for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++)
+ acpi_bus_init_power_state(device, i);
- /* Evaluate "_PSx" to see if we can do explicit sets */
- object_name[2] = 'S';
- status = acpi_get_handle(device->handle, object_name, &handle);
- if (ACPI_SUCCESS(status))
- ps->flags.explicit_set = 1;
-
- /*
- * State is valid if there are means to put the device into it.
- * D3hot is only valid if _PR3 present.
- */
- if (ps->resources.count ||
- (ps->flags.explicit_set && i < ACPI_STATE_D3_HOT)) {
- ps->flags.valid = 1;
- ps->flags.os_accessible = 1;
- }
-
- ps->power = -1; /* Unknown - driver assigned */
- ps->latency = -1; /* Unknown - driver assigned */
- }
+ INIT_LIST_HEAD(&device->power.states[ACPI_STATE_D3_COLD].resources);
/* Set defaults for D0 and D3 states (always valid) */
device->power.states[ACPI_STATE_D0].flags.valid = 1;
@@ -1103,17 +1178,17 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
device->power.flags.power_resources)
device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1;
- acpi_bus_init_power(device);
-
- return 0;
+ if (acpi_bus_init_power(device)) {
+ acpi_free_power_resources_lists(device);
+ device->flags.power_manageable = 0;
+ }
}
-static int acpi_bus_get_flags(struct acpi_device *device)
+static void acpi_bus_get_flags(struct acpi_device *device)
{
acpi_status status = AE_OK;
acpi_handle temp = NULL;
-
/* Presence of _STA indicates 'dynamic_status' */
status = acpi_get_handle(device->handle, "_STA", &temp);
if (ACPI_SUCCESS(status))
@@ -1133,21 +1208,6 @@ static int acpi_bus_get_flags(struct acpi_device *device)
if (ACPI_SUCCESS(status))
device->flags.ejectable = 1;
}
-
- /* Power resources cannot be power manageable. */
- if (device->device_type == ACPI_BUS_TYPE_POWER)
- return 0;
-
- /* Presence of _PS0|_PR0 indicates 'power manageable' */
- status = acpi_get_handle(device->handle, "_PS0", &temp);
- if (ACPI_FAILURE(status))
- status = acpi_get_handle(device->handle, "_PR0", &temp);
- if (ACPI_SUCCESS(status))
- device->flags.power_manageable = 1;
-
- /* TBD: Performance management */
-
- return 0;
}
static void acpi_device_get_busid(struct acpi_device *device)
@@ -1372,56 +1432,32 @@ static void acpi_device_set_id(struct acpi_device *device)
}
}
-static int acpi_device_set_context(struct acpi_device *device)
+void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
+ int type, unsigned long long sta)
{
- acpi_status status;
-
- /*
- * Context
- * -------
- * Attach this 'struct acpi_device' to the ACPI object. This makes
- * resolutions from handle->device very efficient. Fixed hardware
- * devices have no handles, so we skip them.
- */
- if (!device->handle)
- return 0;
-
- status = acpi_attach_data(device->handle,
- acpi_bus_data_handler, device);
- if (ACPI_SUCCESS(status))
- return 0;
-
- printk(KERN_ERR PREFIX "Error attaching device data\n");
- return -ENODEV;
+ INIT_LIST_HEAD(&device->pnp.ids);
+ device->device_type = type;
+ device->handle = handle;
+ device->parent = acpi_bus_get_parent(handle);
+ STRUCT_TO_INT(device->status) = sta;
+ acpi_device_get_busid(device);
+ acpi_device_set_id(device);
+ acpi_bus_get_flags(device);
+ device->flags.match_driver = false;
+ device_initialize(&device->dev);
+ dev_set_uevent_suppress(&device->dev, true);
}
-static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
+void acpi_device_add_finalize(struct acpi_device *device)
{
- if (!dev)
- return -EINVAL;
-
- dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
- device_release_driver(&dev->dev);
-
- if (!rmdevice)
- return 0;
-
- /*
- * unbind _ADR-Based Devices when hot removal
- */
- if (dev->flags.bus_address) {
- if ((dev->parent) && (dev->parent->ops.unbind))
- dev->parent->ops.unbind(dev);
- }
- acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
-
- return 0;
+ device->flags.match_driver = true;
+ dev_set_uevent_suppress(&device->dev, false);
+ kobject_uevent(&device->dev.kobj, KOBJ_ADD);
}
static int acpi_add_single_object(struct acpi_device **child,
acpi_handle handle, int type,
- unsigned long long sta,
- struct acpi_bus_ops *ops)
+ unsigned long long sta)
{
int result;
struct acpi_device *device;
@@ -1433,102 +1469,25 @@ static int acpi_add_single_object(struct acpi_device **child,
return -ENOMEM;
}
- INIT_LIST_HEAD(&device->pnp.ids);
- device->device_type = type;
- device->handle = handle;
- device->parent = acpi_bus_get_parent(handle);
- device->bus_ops = *ops; /* workround for not call .start */
- STRUCT_TO_INT(device->status) = sta;
-
- acpi_device_get_busid(device);
-
- /*
- * Flags
- * -----
- * Note that we only look for object handles -- cannot evaluate objects
- * until we know the device is present and properly initialized.
- */
- result = acpi_bus_get_flags(device);
- if (result)
- goto end;
-
- /*
- * Initialize Device
- * -----------------
- * TBD: Synch with Core's enumeration/initialization process.
- */
- acpi_device_set_id(device);
-
- /*
- * Power Management
- * ----------------
- */
- if (device->flags.power_manageable) {
- result = acpi_bus_get_power_flags(device);
- if (result)
- goto end;
- }
-
- /*
- * Wakeup device management
- *-----------------------
- */
+ acpi_init_device_object(device, handle, type, sta);
+ acpi_bus_get_power_flags(device);
acpi_bus_get_wakeup_device_flags(device);
- /*
- * Performance Management
- * ----------------------
- */
- if (device->flags.performance_manageable) {
- result = acpi_bus_get_perf_flags(device);
- if (result)
- goto end;
- }
-
- if ((result = acpi_device_set_context(device)))
- goto end;
-
- result = acpi_device_register(device);
-
- /*
- * Bind _ADR-Based Devices when hot add
- */
- if (device->flags.bus_address) {
- if (device->parent && device->parent->ops.bind)
- device->parent->ops.bind(device);
- }
-
-end:
- if (!result) {
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Adding %s [%s] parent %s\n", dev_name(&device->dev),
- (char *) buffer.pointer,
- device->parent ? dev_name(&device->parent->dev) :
- "(null)"));
- kfree(buffer.pointer);
- *child = device;
- } else
+ result = acpi_device_add(device, acpi_device_release);
+ if (result) {
acpi_device_release(&device->dev);
+ return result;
+ }
- return result;
-}
-
-#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
- ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING)
-
-static void acpi_bus_add_power_resource(acpi_handle handle)
-{
- struct acpi_bus_ops ops = {
- .acpi_op_add = 1,
- .acpi_op_start = 1,
- };
- struct acpi_device *device = NULL;
-
- acpi_bus_get_device(handle, &device);
- if (!device)
- acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER,
- ACPI_STA_DEFAULT, &ops);
+ acpi_power_add_remove_device(device, true);
+ acpi_device_add_finalize(device);
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Added %s [%s] parent %s\n",
+ dev_name(&device->dev), (char *) buffer.pointer,
+ device->parent ? dev_name(&device->parent->dev) : "(null)"));
+ kfree(buffer.pointer);
+ *child = device;
+ return 0;
}
static int acpi_bus_type_and_status(acpi_handle handle, int *type,
@@ -1570,218 +1529,248 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type,
return 0;
}
-static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
- void *context, void **return_value)
+static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
+ void *not_used, void **return_value)
{
- struct acpi_bus_ops *ops = context;
+ struct acpi_device *device = NULL;
int type;
unsigned long long sta;
- struct acpi_device *device;
acpi_status status;
int result;
+ acpi_bus_get_device(handle, &device);
+ if (device)
+ goto out;
+
result = acpi_bus_type_and_status(handle, &type, &sta);
if (result)
return AE_OK;
+ if (type == ACPI_BUS_TYPE_POWER) {
+ acpi_add_power_resource(handle);
+ return AE_OK;
+ }
+
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
struct acpi_device_wakeup wakeup;
acpi_handle temp;
status = acpi_get_handle(handle, "_PRW", &temp);
- if (ACPI_SUCCESS(status))
+ if (ACPI_SUCCESS(status)) {
acpi_bus_extract_wakeup_device_power_package(handle,
&wakeup);
+ acpi_power_resources_list_free(&wakeup.resources);
+ }
return AE_CTRL_DEPTH;
}
- /*
- * We may already have an acpi_device from a previous enumeration. If
- * so, we needn't add it again, but we may still have to start it.
- */
- device = NULL;
- acpi_bus_get_device(handle, &device);
- if (ops->acpi_op_add && !device) {
- acpi_add_single_object(&device, handle, type, sta, ops);
- /* Is the device a known good platform device? */
- if (device
- && !acpi_match_device_ids(device, acpi_platform_device_ids))
- acpi_create_platform_device(device);
- }
-
+ acpi_add_single_object(&device, handle, type, sta);
if (!device)
return AE_CTRL_DEPTH;
- if (ops->acpi_op_start && !(ops->acpi_op_add)) {
- status = acpi_start_single_object(device);
- if (ACPI_FAILURE(status))
- return AE_CTRL_DEPTH;
- }
-
+ out:
if (!*return_value)
*return_value = device;
+
return AE_OK;
}
-static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
- struct acpi_device **child)
+static int acpi_scan_do_attach_handler(struct acpi_device *device, char *id)
{
- acpi_status status;
- void *device = NULL;
+ struct acpi_scan_handler *handler;
- status = acpi_bus_check_add(handle, 0, ops, &device);
- if (ACPI_SUCCESS(status))
- acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
- acpi_bus_check_add, NULL, ops, &device);
+ list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
+ const struct acpi_device_id *devid;
- if (child)
- *child = device;
+ for (devid = handler->ids; devid->id[0]; devid++) {
+ int ret;
- if (device)
- return 0;
- else
- return -ENODEV;
-}
+ if (strcmp((char *)devid->id, id))
+ continue;
-/*
- * acpi_bus_add and acpi_bus_start
- *
- * scan a given ACPI tree and (probably recently hot-plugged)
- * create and add or starts found devices.
- *
- * If no devices were found -ENODEV is returned which does not
- * mean that this is a real error, there just have been no suitable
- * ACPI objects in the table trunk from which the kernel could create
- * a device and add/start an appropriate driver.
- */
+ ret = handler->attach(device, devid);
+ if (ret > 0) {
+ device->handler = handler;
+ return ret;
+ } else if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
-int
-acpi_bus_add(struct acpi_device **child,
- struct acpi_device *parent, acpi_handle handle, int type)
+static int acpi_scan_attach_handler(struct acpi_device *device)
{
- struct acpi_bus_ops ops;
+ struct acpi_hardware_id *hwid;
+ int ret = 0;
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
+ list_for_each_entry(hwid, &device->pnp.ids, list) {
+ ret = acpi_scan_do_attach_handler(device, hwid->id);
+ if (ret)
+ break;
- return acpi_bus_scan(handle, &ops, child);
+ }
+ return ret;
}
-EXPORT_SYMBOL(acpi_bus_add);
-int acpi_bus_start(struct acpi_device *device)
+static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
+ void *not_used, void **ret_not_used)
{
- struct acpi_bus_ops ops;
- int result;
-
- if (!device)
- return -EINVAL;
+ struct acpi_device *device;
+ unsigned long long sta_not_used;
+ int ret;
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_start = 1;
+ /*
+ * Ignore errors ignored by acpi_bus_check_add() to avoid terminating
+ * namespace walks prematurely.
+ */
+ if (acpi_bus_type_and_status(handle, &ret, &sta_not_used))
+ return AE_OK;
- result = acpi_bus_scan(device->handle, &ops, NULL);
+ if (acpi_bus_get_device(handle, &device))
+ return AE_CTRL_DEPTH;
- acpi_update_all_gpes();
+ ret = acpi_scan_attach_handler(device);
+ if (ret)
+ return ret > 0 ? AE_OK : AE_CTRL_DEPTH;
- return result;
+ ret = device_attach(&device->dev);
+ return ret >= 0 ? AE_OK : AE_CTRL_DEPTH;
}
-EXPORT_SYMBOL(acpi_bus_start);
-int acpi_bus_trim(struct acpi_device *start, int rmdevice)
+/**
+ * acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
+ * @handle: Root of the namespace scope to scan.
+ *
+ * Scan a given ACPI tree (probably recently hot-plugged) and create and add
+ * found devices.
+ *
+ * If no devices were found, -ENODEV is returned, but it does not mean that
+ * there has been a real error. There just have been no suitable ACPI objects
+ * in the table trunk from which the kernel could create a device and add an
+ * appropriate driver.
+ *
+ * Must be called under acpi_scan_lock.
+ */
+int acpi_bus_scan(acpi_handle handle)
{
- acpi_status status;
- struct acpi_device *parent, *child;
- acpi_handle phandle, chandle;
- acpi_object_type type;
- u32 level = 1;
- int err = 0;
+ void *device = NULL;
+ int error = 0;
- parent = start;
- phandle = start->handle;
- child = chandle = NULL;
+ if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device)))
+ acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+ acpi_bus_check_add, NULL, NULL, &device);
- while ((level > 0) && parent && (!err)) {
- status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
- chandle, &chandle);
+ if (!device)
+ error = -ENODEV;
+ else if (ACPI_SUCCESS(acpi_bus_device_attach(handle, 0, NULL, NULL)))
+ acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+ acpi_bus_device_attach, NULL, NULL, NULL);
- /*
- * If this scope is exhausted then move our way back up.
- */
- if (ACPI_FAILURE(status)) {
- level--;
- chandle = phandle;
- acpi_get_parent(phandle, &phandle);
- child = parent;
- parent = parent->parent;
-
- if (level == 0)
- err = acpi_bus_remove(child, rmdevice);
- else
- err = acpi_bus_remove(child, 1);
+ return error;
+}
+EXPORT_SYMBOL(acpi_bus_scan);
- continue;
- }
+static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
+ void *not_used, void **ret_not_used)
+{
+ struct acpi_device *device = NULL;
- status = acpi_get_type(chandle, &type);
- if (ACPI_FAILURE(status)) {
- continue;
- }
- /*
- * If there is a device corresponding to chandle then
- * parse it (depth-first).
- */
- if (acpi_bus_get_device(chandle, &child) == 0) {
- level++;
- phandle = chandle;
- chandle = NULL;
- parent = child;
+ if (!acpi_bus_get_device(handle, &device)) {
+ struct acpi_scan_handler *dev_handler = device->handler;
+
+ device->removal_type = ACPI_BUS_REMOVAL_EJECT;
+ if (dev_handler) {
+ if (dev_handler->detach)
+ dev_handler->detach(device);
+
+ device->handler = NULL;
+ } else {
+ device_release_driver(&device->dev);
}
- continue;
}
- return err;
+ return AE_OK;
+}
+
+static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
+ void *not_used, void **ret_not_used)
+{
+ struct acpi_device *device = NULL;
+
+ if (!acpi_bus_get_device(handle, &device))
+ acpi_device_unregister(device);
+
+ return AE_OK;
+}
+
+/**
+ * acpi_bus_trim - Remove ACPI device node and all of its descendants
+ * @start: Root of the ACPI device nodes subtree to remove.
+ *
+ * Must be called under acpi_scan_lock.
+ */
+void acpi_bus_trim(struct acpi_device *start)
+{
+ /*
+ * Execute acpi_bus_device_detach() as a post-order callback to detach
+ * all ACPI drivers from the device nodes being removed.
+ */
+ acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
+ acpi_bus_device_detach, NULL, NULL);
+ acpi_bus_device_detach(start->handle, 0, NULL, NULL);
+ /*
+ * Execute acpi_bus_remove() as a post-order callback to remove device
+ * nodes in the given namespace scope.
+ */
+ acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
+ acpi_bus_remove, NULL, NULL);
+ acpi_bus_remove(start->handle, 0, NULL, NULL);
}
EXPORT_SYMBOL_GPL(acpi_bus_trim);
static int acpi_bus_scan_fixed(void)
{
int result = 0;
- struct acpi_device *device = NULL;
- struct acpi_bus_ops ops;
-
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
- ops.acpi_op_start = 1;
/*
* Enumerate all fixed-feature devices.
*/
- if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) {
+ struct acpi_device *device = NULL;
+
result = acpi_add_single_object(&device, NULL,
ACPI_BUS_TYPE_POWER_BUTTON,
- ACPI_STA_DEFAULT,
- &ops);
+ ACPI_STA_DEFAULT);
+ if (result)
+ return result;
+
+ result = device_attach(&device->dev);
+ if (result < 0)
+ return result;
+
device_init_wakeup(&device->dev, true);
}
- if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON)) {
+ struct acpi_device *device = NULL;
+
result = acpi_add_single_object(&device, NULL,
ACPI_BUS_TYPE_SLEEP_BUTTON,
- ACPI_STA_DEFAULT,
- &ops);
+ ACPI_STA_DEFAULT);
+ if (result)
+ return result;
+
+ result = device_attach(&device->dev);
}
- return result;
+ return result < 0 ? result : 0;
}
int __init acpi_scan_init(void)
{
int result;
- struct acpi_bus_ops ops;
-
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
- ops.acpi_op_start = 1;
result = bus_register(&acpi_bus_type);
if (result) {
@@ -1789,20 +1778,33 @@ int __init acpi_scan_init(void)
printk(KERN_ERR PREFIX "Could not register bus type\n");
}
- acpi_power_init();
+ acpi_pci_root_init();
+ acpi_pci_link_init();
+ acpi_platform_init();
+ acpi_csrt_init();
+ acpi_container_init();
+ mutex_lock(&acpi_scan_lock);
/*
* Enumerate devices in the ACPI namespace.
*/
- result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root);
-
- if (!result)
- result = acpi_bus_scan_fixed();
+ result = acpi_bus_scan(ACPI_ROOT_OBJECT);
+ if (result)
+ goto out;
+ result = acpi_bus_get_device(ACPI_ROOT_OBJECT, &acpi_root);
if (result)
- acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
- else
- acpi_update_all_gpes();
+ goto out;
+
+ result = acpi_bus_scan_fixed();
+ if (result) {
+ acpi_device_unregister(acpi_root);
+ goto out;
+ }
+ acpi_update_all_gpes();
+
+ out:
+ mutex_unlock(&acpi_scan_lock);
return result;
}
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 2fcc67d34b11..6d3a06a629a1 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -177,6 +177,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
},
{
.callback = init_nvs_nosave,
+ .ident = "Sony Vaio VGN-FW41E_H",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW41E_H"),
+ },
+ },
+ {
+ .callback = init_nvs_nosave,
.ident = "Sony Vaio VGN-FW21E",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
@@ -386,6 +394,8 @@ static void acpi_pm_finish(void)
acpi_target_sleep_state = ACPI_STATE_S0;
+ acpi_resume_power_resources();
+
/* If we were woken with the fixed power button, provide a small
* hint to userspace in the form of a wakeup event on the fixed power
* button device (if it can be found).
@@ -577,7 +587,28 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = {
.end = acpi_pm_end,
.recover = acpi_pm_finish,
};
-#endif /* CONFIG_SUSPEND */
+
+static void acpi_sleep_suspend_setup(void)
+{
+ int i;
+
+ for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
+ acpi_status status;
+ u8 type_a, type_b;
+
+ status = acpi_get_sleep_type_data(i, &type_a, &type_b);
+ if (ACPI_SUCCESS(status)) {
+ sleep_states[i] = 1;
+ pr_cont(" S%d", i);
+ }
+ }
+
+ suspend_set_ops(old_suspend_ordering ?
+ &acpi_suspend_ops_old : &acpi_suspend_ops);
+}
+#else /* !CONFIG_SUSPEND */
+static inline void acpi_sleep_suspend_setup(void) {}
+#endif /* !CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATION
static unsigned long s4_hardware_signature;
@@ -698,7 +729,30 @@ static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
.restore_cleanup = acpi_pm_thaw,
.recover = acpi_pm_finish,
};
-#endif /* CONFIG_HIBERNATION */
+
+static void acpi_sleep_hibernate_setup(void)
+{
+ acpi_status status;
+ u8 type_a, type_b;
+
+ status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
+ if (ACPI_FAILURE(status))
+ return;
+
+ hibernation_set_ops(old_suspend_ordering ?
+ &acpi_hibernation_ops_old : &acpi_hibernation_ops);
+ sleep_states[ACPI_STATE_S4] = 1;
+ pr_cont(KERN_CONT " S4");
+ if (nosigcheck)
+ return;
+
+ acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
+ if (facs)
+ s4_hardware_signature = facs->hardware_signature;
+}
+#else /* !CONFIG_HIBERNATION */
+static inline void acpi_sleep_hibernate_setup(void) {}
+#endif /* !CONFIG_HIBERNATION */
int acpi_suspend(u32 acpi_state)
{
@@ -734,9 +788,6 @@ int __init acpi_sleep_init(void)
{
acpi_status status;
u8 type_a, type_b;
-#ifdef CONFIG_SUSPEND
- int i = 0;
-#endif
if (acpi_disabled)
return 0;
@@ -744,45 +795,19 @@ int __init acpi_sleep_init(void)
acpi_sleep_dmi_check();
sleep_states[ACPI_STATE_S0] = 1;
- printk(KERN_INFO PREFIX "(supports S0");
-
-#ifdef CONFIG_SUSPEND
- for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
- status = acpi_get_sleep_type_data(i, &type_a, &type_b);
- if (ACPI_SUCCESS(status)) {
- sleep_states[i] = 1;
- printk(KERN_CONT " S%d", i);
- }
- }
+ pr_info(PREFIX "(supports S0");
- suspend_set_ops(old_suspend_ordering ?
- &acpi_suspend_ops_old : &acpi_suspend_ops);
-#endif
+ acpi_sleep_suspend_setup();
+ acpi_sleep_hibernate_setup();
-#ifdef CONFIG_HIBERNATION
- status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
- if (ACPI_SUCCESS(status)) {
- hibernation_set_ops(old_suspend_ordering ?
- &acpi_hibernation_ops_old : &acpi_hibernation_ops);
- sleep_states[ACPI_STATE_S4] = 1;
- printk(KERN_CONT " S4");
- if (!nosigcheck) {
- acpi_get_table(ACPI_SIG_FACS, 1,
- (struct acpi_table_header **)&facs);
- if (facs)
- s4_hardware_signature =
- facs->hardware_signature;
- }
- }
-#endif
status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
if (ACPI_SUCCESS(status)) {
sleep_states[ACPI_STATE_S5] = 1;
- printk(KERN_CONT " S5");
+ pr_cont(" S5");
pm_power_off_prepare = acpi_power_off_prepare;
pm_power_off = acpi_power_off;
}
- printk(KERN_CONT ")\n");
+ pr_cont(")\n");
/*
* Register the tts_notifier to reboot notifier list so that the _TTS
* object can also be evaluated when the system enters S5.
diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h
index 74d59c8f4678..0143540a2519 100644
--- a/drivers/acpi/sleep.h
+++ b/drivers/acpi/sleep.h
@@ -6,3 +6,5 @@ extern void acpi_disable_wakeup_devices(u8 sleep_state);
extern struct list_head acpi_wakeup_device_list;
extern struct mutex acpi_device_lock;
+
+extern void acpi_resume_power_resources(void);
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index ea61ca9129cd..41c0504470db 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -498,7 +498,7 @@ static int get_status(u32 index, acpi_event_status *status,
result = acpi_get_gpe_device(index, handle);
if (result) {
ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND,
- "Invalid GPE 0x%x\n", index));
+ "Invalid GPE 0x%x", index));
goto end;
}
result = acpi_get_gpe_status(*handle, index, status);
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 2572d9715bda..d67a1fe07f0e 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -204,7 +204,7 @@ int __init
acpi_table_parse_entries(char *id,
unsigned long table_size,
int entry_id,
- acpi_table_entry_handler handler,
+ acpi_tbl_entry_handler handler,
unsigned int max_entries)
{
struct acpi_table_header *table_header = NULL;
@@ -269,7 +269,7 @@ err:
int __init
acpi_table_parse_madt(enum acpi_madt_type id,
- acpi_table_entry_handler handler, unsigned int max_entries)
+ acpi_tbl_entry_handler handler, unsigned int max_entries)
{
return acpi_table_parse_entries(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt), id,
@@ -285,7 +285,7 @@ acpi_table_parse_madt(enum acpi_madt_type id,
* Scan the ACPI System Descriptor Table (STD) for a table matching @id,
* run @handler on it. Return 0 if table found, return on if not.
*/
-int __init acpi_table_parse(char *id, acpi_table_handler handler)
+int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler)
{
struct acpi_table_header *table = NULL;
acpi_size tbl_size;
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 506fbd4b5733..8470771e5eae 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -97,7 +97,7 @@ module_param(psv, int, 0644);
MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
static int acpi_thermal_add(struct acpi_device *device);
-static int acpi_thermal_remove(struct acpi_device *device, int type);
+static int acpi_thermal_remove(struct acpi_device *device);
static void acpi_thermal_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id thermal_device_ids[] = {
@@ -288,7 +288,7 @@ do { \
if (flags != ACPI_TRIPS_INIT) \
ACPI_EXCEPTION((AE_INFO, AE_ERROR, \
"ACPI thermal trip point %s changed\n" \
- "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \
+ "Please send acpidump to linux-acpi@vger.kernel.org", str)); \
} while (0)
static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
@@ -531,6 +531,10 @@ static void acpi_thermal_check(void *data)
{
struct acpi_thermal *tz = data;
+ if (!tz->tz_enabled) {
+ pr_warn("thermal zone is disabled \n");
+ return;
+ }
thermal_zone_device_update(tz->thermal_zone);
}
@@ -1111,7 +1115,7 @@ end:
return result;
}
-static int acpi_thermal_remove(struct acpi_device *device, int type)
+static int acpi_thermal_remove(struct acpi_device *device)
{
struct acpi_thermal *tz = NULL;
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index ac9a69cd45f5..313f959413dc 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -88,7 +88,7 @@ module_param(use_bios_initial_backlight, bool, 0644);
static int register_count = 0;
static int acpi_video_bus_add(struct acpi_device *device);
-static int acpi_video_bus_remove(struct acpi_device *device, int type);
+static int acpi_video_bus_remove(struct acpi_device *device);
static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id video_device_ids[] = {
@@ -673,7 +673,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
br->levels[i] = br->levels[i - level_ac_battery];
count += level_ac_battery;
} else if (level_ac_battery > 2)
- ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package\n"));
+ ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package"));
/* Check if the _BCL package is in a reversed order */
if (max_level == br->levels[2]) {
@@ -682,7 +682,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
acpi_video_cmp_level, NULL);
} else if (max_level != br->levels[count - 1])
ACPI_ERROR((AE_INFO,
- "Found unordered _BCL package\n"));
+ "Found unordered _BCL package"));
br->count = count;
device->brightness = br;
@@ -1740,7 +1740,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
return error;
}
-static int acpi_video_bus_remove(struct acpi_device *device, int type)
+static int acpi_video_bus_remove(struct acpi_device *device)
{
struct acpi_video_bus *video = NULL;
diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c
index 536c166f4253..ab92785f54dc 100644
--- a/drivers/amba/tegra-ahb.c
+++ b/drivers/amba/tegra-ahb.c
@@ -20,6 +20,7 @@
*
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -257,9 +258,9 @@ static int tegra_ahb_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- ahb->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (!ahb->regs)
- return -EBUSY;
+ ahb->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ahb->regs))
+ return PTR_ERR(ahb->regs);
ahb->dev = &pdev->dev;
platform_set_drvdata(pdev, ahb);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index e08d322d01d7..3e751b74615e 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -14,7 +14,7 @@ menuconfig ATA
tristate "Serial ATA and Parallel ATA drivers"
depends on HAS_IOMEM
depends on BLOCK
- depends on !(M32R || M68K) || BROKEN
+ depends on !(M32R || M68K || S390) || BROKEN
select SCSI
---help---
If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
@@ -58,6 +58,19 @@ config ATA_ACPI
You can disable this at kernel boot time by using the
option libata.noacpi=1
+config SATA_ZPODD
+ bool "SATA Zero Power ODD Support"
+ depends on ATA_ACPI
+ default n
+ help
+ This option adds support for SATA ZPODD. It requires both
+ ODD and the platform support, and if enabled, will automatically
+ power on/off the ODD when certain condition is satisfied. This
+ does not impact user's experience of the ODD, only power is saved
+ when ODD is not in use(i.e. no disc inside).
+
+ If unsure, say N.
+
config SATA_PMP
bool "SATA Port Multiplier support"
default y
@@ -163,7 +176,7 @@ config SATA_QSTOR
config SATA_SX4
tristate "Promise SATA SX4 support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables support for Promise Serial ATA SX4.
@@ -247,6 +260,14 @@ config SATA_PROMISE
If unsure, say N.
+config SATA_RCAR
+ tristate "Renesas R-Car SATA support"
+ depends on ARCH_SHMOBILE && ARCH_R8A7779
+ help
+ This option enables support for Renesas R-Car Serial ATA.
+
+ If unsure, say N.
+
config SATA_SIL
tristate "Silicon Image SATA support"
depends on PCI
@@ -390,7 +411,7 @@ config PATA_CS5530
config PATA_CS5535
tristate "CS5535 PATA support (Experimental)"
- depends on PCI && X86 && !X86_64 && EXPERIMENTAL
+ depends on PCI && X86 && !X86_64
help
This option enables support for the NatSemi/AMD CS5535
companion chip used with the Geode processor family.
@@ -408,7 +429,7 @@ config PATA_CS5536
config PATA_CYPRESS
tristate "Cypress CY82C693 PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables support for the Cypress/Contaq CY82C693
chipset found in some Alpha systems
@@ -496,7 +517,7 @@ config PATA_IMX
config PATA_IT8213
tristate "IT8213 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables support for the ITE 821 PATA
controllers via the new ATA layer.
@@ -589,7 +610,7 @@ config PATA_OLDPIIX
config PATA_OPTIDMA
tristate "OPTI FireStar PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables DMA/PIO support for the later OPTi
controllers found on some old motherboards and in some
@@ -616,7 +637,7 @@ config PATA_PDC_OLD
config PATA_RADISYS
tristate "RADISYS 82600 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables support for the RADISYS 82600
PATA controllers via the new ATA layer
@@ -687,7 +708,7 @@ config PATA_SIS
config PATA_TOSHIBA
tristate "Toshiba Piccolo support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
Support for the Toshiba Piccolo controllers. Currently only the
primary channel is supported by this driver.
@@ -738,7 +759,7 @@ comment "PIO-only SFF controllers"
config PATA_AT32
tristate "Atmel AVR32 PATA support (Experimental)"
- depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
+ depends on AVR32 && PLATFORM_AT32AP
help
This option enables support for the IDE devices on the
Atmel AT32AP platform.
@@ -755,7 +776,7 @@ config PATA_AT91
config PATA_CMD640_PCI
tristate "CMD640 PCI PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables support for the CMD640 PCI IDE
interface chip. Only the primary channel is currently
@@ -801,7 +822,7 @@ config PATA_NS87410
config PATA_OPTI
tristate "OPTI621/6215 PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables full PIO support for the early Opti ATA
controllers found on some old motherboards.
@@ -881,7 +902,7 @@ config PATA_SAMSUNG_CF
config PATA_WINBOND_VLB
tristate "Winbond W83759A VLB PATA support (Experimental)"
- depends on ISA && EXPERIMENTAL
+ depends on ISA
select PATA_LEGACY
help
Support for the Winbond W83759A controller on Vesa Local Bus
@@ -909,7 +930,7 @@ config ATA_GENERIC
config PATA_LEGACY
tristate "Legacy ISA PATA support (Experimental)"
- depends on (ISA || PCI) && EXPERIMENTAL
+ depends on (ISA || PCI)
help
This option enables support for ISA/VLB/PCI bus legacy PATA
ports and allows them to be accessed via the new ATA layer.
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 9329dafba91b..c04d0fd038a3 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_ATA_PIIX) += ata_piix.o
obj-$(CONFIG_SATA_MV) += sata_mv.o
obj-$(CONFIG_SATA_NV) += sata_nv.o
obj-$(CONFIG_SATA_PROMISE) += sata_promise.o
+obj-$(CONFIG_SATA_RCAR) += sata_rcar.o
obj-$(CONFIG_SATA_SIL) += sata_sil.o
obj-$(CONFIG_SATA_SIS) += sata_sis.o
obj-$(CONFIG_SATA_SVW) += sata_svw.o
@@ -107,3 +108,4 @@ libata-y := libata-core.o libata-scsi.o libata-eh.o libata-transport.o
libata-$(CONFIG_ATA_SFF) += libata-sff.o
libata-$(CONFIG_SATA_PMP) += libata-pmp.o
libata-$(CONFIG_ATA_ACPI) += libata-acpi.o
+libata-$(CONFIG_SATA_ZPODD) += libata-zpodd.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 497912732566..a99112cfd8b1 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -265,6 +265,30 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x9c07), board_ahci }, /* Lynx Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0x9c0e), board_ahci }, /* Lynx Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0x9c0f), board_ahci }, /* Lynx Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */
+ { PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */
+ { PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f25), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f26), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f32), board_ahci }, /* Avoton AHCI */
+ { PCI_VDEVICE(INTEL, 0x1f33), board_ahci }, /* Avoton AHCI */
+ { PCI_VDEVICE(INTEL, 0x1f34), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f35), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f36), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f37), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
+ { PCI_VDEVICE(INTEL, 0x8d04), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d06), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d0e), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d62), board_ahci }, /* Wellsburg AHCI */
+ { PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -1061,6 +1085,86 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
{}
#endif
+int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+ int rc;
+ unsigned int maxvec;
+
+ if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) {
+ rc = pci_enable_msi_block_auto(pdev, &maxvec);
+ if (rc > 0) {
+ if ((rc == maxvec) || (rc == 1))
+ return rc;
+ /*
+ * Assume that advantage of multipe MSIs is negated,
+ * so fallback to single MSI mode to save resources
+ */
+ pci_disable_msi(pdev);
+ if (!pci_enable_msi(pdev))
+ return 1;
+ }
+ }
+
+ pci_intx(pdev, 1);
+ return 0;
+}
+
+/**
+ * ahci_host_activate - start AHCI host, request IRQs and register it
+ * @host: target ATA host
+ * @irq: base IRQ number to request
+ * @n_msis: number of MSIs allocated for this host
+ * @irq_handler: irq_handler used when requesting IRQs
+ * @irq_flags: irq_flags used when requesting IRQs
+ *
+ * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
+ * when multiple MSIs were allocated. That is one MSI per port, starting
+ * from @irq.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
+{
+ int i, rc;
+
+ /* Sharing Last Message among several ports is not supported */
+ if (n_msis < host->n_ports)
+ return -EINVAL;
+
+ rc = ata_host_start(host);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < host->n_ports; i++) {
+ rc = devm_request_threaded_irq(host->dev,
+ irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
+ dev_driver_string(host->dev), host->ports[i]);
+ if (rc)
+ goto out_free_irqs;
+ }
+
+ for (i = 0; i < host->n_ports; i++)
+ ata_port_desc(host->ports[i], "irq %d", irq + i);
+
+ rc = ata_host_register(host, &ahci_sht);
+ if (rc)
+ goto out_free_all_irqs;
+
+ return 0;
+
+out_free_all_irqs:
+ i = host->n_ports;
+out_free_irqs:
+ for (i--; i >= 0; i--)
+ devm_free_irq(host->dev, irq + i, host->ports[i]);
+
+ return rc;
+}
+
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
unsigned int board_id = ent->driver_data;
@@ -1069,7 +1173,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
struct ata_host *host;
- int n_ports, i, rc;
+ int n_ports, n_msis, i, rc;
int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
VPRINTK("ENTER\n");
@@ -1156,11 +1260,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ahci_sb600_enable_64bit(pdev))
hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
- if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
- pci_intx(pdev, 1);
-
hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
+ n_msis = ahci_init_interrupts(pdev, hpriv);
+ if (n_msis > 1)
+ hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
+
/* save initial config */
ahci_pci_save_initial_config(pdev, hpriv);
@@ -1256,6 +1361,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ahci_pci_print_info(host);
pci_set_master(pdev);
+
+ if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
+ return ahci_host_activate(host, pdev->irq, n_msis);
+
return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
&ahci_sht);
}
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 9be471200a07..b830e6c9fe49 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -231,6 +231,7 @@ enum {
AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on
port start (wait until
error-handling stage) */
+ AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */
/* ap->flags bits */
@@ -297,6 +298,8 @@ struct ahci_port_priv {
unsigned int ncq_saw_d2h:1;
unsigned int ncq_saw_dmas:1;
unsigned int ncq_saw_sdb:1;
+ u32 intr_status; /* interrupts to handle */
+ spinlock_t lock; /* protects parent ata_port */
u32 intr_mask; /* interrupts to enable */
bool fbs_supported; /* set iff FBS is supported */
bool fbs_enabled; /* set iff FBS is enabled */
@@ -359,7 +362,10 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv,
struct ata_port_info *pi);
int ahci_reset_em(struct ata_host *host);
irqreturn_t ahci_interrupt(int irq, void *dev_instance);
+irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance);
+irqreturn_t ahci_thread_fn(int irq, void *dev_instance);
void ahci_print_info(struct ata_host *host, const char *scc_s);
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis);
static inline void __iomem *__ahci_port_base(struct ata_host *host,
unsigned int port_no)
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 174eca609b42..d2ba439cfe54 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -317,6 +317,23 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x9c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
/* SATA Controller IDE (DH89xxCC) */
{ 0x8086, 0x2326, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Avoton) */
+ { 0x8086, 0x1f20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Avoton) */
+ { 0x8086, 0x1f21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Avoton) */
+ { 0x8086, 0x1f30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Avoton) */
+ { 0x8086, 0x1f31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Wellsburg) */
+ { 0x8086, 0x8d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Wellsburg) */
+ { 0x8086, 0x8d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Wellsburg) */
+ { 0x8086, 0x8d60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Wellsburg) */
+ { 0x8086, 0x8d68, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+
{ } /* terminate list */
};
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 6cd7805e47ca..34c82167b962 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1655,19 +1655,16 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
ata_port_abort(ap);
}
-static void ahci_port_intr(struct ata_port *ap)
+static void ahci_handle_port_interrupt(struct ata_port *ap,
+ void __iomem *port_mmio, u32 status)
{
- void __iomem *port_mmio = ahci_port_base(ap);
struct ata_eh_info *ehi = &ap->link.eh_info;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_host_priv *hpriv = ap->host->private_data;
int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
- u32 status, qc_active = 0;
+ u32 qc_active = 0;
int rc;
- status = readl(port_mmio + PORT_IRQ_STAT);
- writel(status, port_mmio + PORT_IRQ_STAT);
-
/* ignore BAD_PMP while resetting */
if (unlikely(resetting))
status &= ~PORT_IRQ_BAD_PMP;
@@ -1743,6 +1740,107 @@ static void ahci_port_intr(struct ata_port *ap)
}
}
+void ahci_port_intr(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 status;
+
+ status = readl(port_mmio + PORT_IRQ_STAT);
+ writel(status, port_mmio + PORT_IRQ_STAT);
+
+ ahci_handle_port_interrupt(ap, port_mmio, status);
+}
+
+irqreturn_t ahci_thread_fn(int irq, void *dev_instance)
+{
+ struct ata_port *ap = dev_instance;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ unsigned long flags;
+ u32 status;
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ status = pp->intr_status;
+ if (status)
+ pp->intr_status = 0;
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
+ spin_lock_bh(ap->lock);
+ ahci_handle_port_interrupt(ap, port_mmio, status);
+ spin_unlock_bh(ap->lock);
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(ahci_thread_fn);
+
+void ahci_hw_port_interrupt(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 status;
+
+ status = readl(port_mmio + PORT_IRQ_STAT);
+ writel(status, port_mmio + PORT_IRQ_STAT);
+
+ pp->intr_status |= status;
+}
+
+irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance)
+{
+ struct ata_port *ap_this = dev_instance;
+ struct ahci_port_priv *pp = ap_this->private_data;
+ struct ata_host *host = ap_this->host;
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ unsigned int i;
+ u32 irq_stat, irq_masked;
+
+ VPRINTK("ENTER\n");
+
+ spin_lock(&host->lock);
+
+ irq_stat = readl(mmio + HOST_IRQ_STAT);
+
+ if (!irq_stat) {
+ u32 status = pp->intr_status;
+
+ spin_unlock(&host->lock);
+
+ VPRINTK("EXIT\n");
+
+ return status ? IRQ_WAKE_THREAD : IRQ_NONE;
+ }
+
+ irq_masked = irq_stat & hpriv->port_map;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ if (!(irq_masked & (1 << i)))
+ continue;
+
+ ap = host->ports[i];
+ if (ap) {
+ ahci_hw_port_interrupt(ap);
+ VPRINTK("port %u\n", i);
+ } else {
+ VPRINTK("port %u (no irq)\n", i);
+ if (ata_ratelimit())
+ dev_warn(host->dev,
+ "interrupt on disabled port %u\n", i);
+ }
+ }
+
+ writel(irq_stat, mmio + HOST_IRQ_STAT);
+
+ spin_unlock(&host->lock);
+
+ VPRINTK("EXIT\n");
+
+ return IRQ_WAKE_THREAD;
+}
+EXPORT_SYMBOL_GPL(ahci_hw_interrupt);
+
irqreturn_t ahci_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
@@ -2196,6 +2294,14 @@ static int ahci_port_start(struct ata_port *ap)
*/
pp->intr_mask = DEF_PORT_IRQ;
+ /*
+ * Switch to per-port locking in case each port has its own MSI vector.
+ */
+ if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) {
+ spin_lock_init(&pp->lock);
+ ap->lock = &pp->lock;
+ }
+
ap->private_data = pp;
/* engage engines, captain */
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index ef01ac07502e..0ea1018280bd 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -17,6 +17,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
#include <scsi/scsi_device.h>
#include "libata.h"
@@ -835,50 +836,95 @@ void ata_acpi_on_resume(struct ata_port *ap)
}
}
-/**
- * ata_acpi_set_state - set the port power state
- * @ap: target ATA port
- * @state: state, on/off
- *
- * This function executes the _PS0/_PS3 ACPI method to set the power state.
- * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
- */
-void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+static int ata_acpi_choose_suspend_state(struct ata_device *dev, bool runtime)
{
+ int d_max_in = ACPI_STATE_D3_COLD;
+ if (!runtime)
+ goto out;
+
+ /*
+ * For ATAPI, runtime D3 cold is only allowed
+ * for ZPODD in zero power ready state
+ */
+ if (dev->class == ATA_DEV_ATAPI &&
+ !(zpodd_dev_enabled(dev) && zpodd_zpready(dev)))
+ d_max_in = ACPI_STATE_D3_HOT;
+
+out:
+ return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev,
+ NULL, d_max_in);
+}
+
+static void sata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+{
+ bool runtime = PMSG_IS_AUTO(state);
struct ata_device *dev;
acpi_handle handle;
int acpi_state;
- /* channel first and then drives for power on and vica versa
- for power off */
- handle = ata_ap_acpi_handle(ap);
- if (handle && state.event == PM_EVENT_ON)
- acpi_bus_set_power(handle, ACPI_STATE_D0);
-
ata_for_each_dev(dev, &ap->link, ENABLED) {
handle = ata_dev_acpi_handle(dev);
if (!handle)
continue;
- if (state.event != PM_EVENT_ON) {
- acpi_state = acpi_pm_device_sleep_state(
- &dev->sdev->sdev_gendev, NULL, ACPI_STATE_D3);
- if (acpi_state > 0)
- acpi_bus_set_power(handle, acpi_state);
- /* TBD: need to check if it's runtime pm request */
- acpi_pm_device_run_wake(
- &dev->sdev->sdev_gendev, true);
+ if (!(state.event & PM_EVENT_RESUME)) {
+ acpi_state = ata_acpi_choose_suspend_state(dev, runtime);
+ if (acpi_state == ACPI_STATE_D0)
+ continue;
+ if (runtime && zpodd_dev_enabled(dev) &&
+ acpi_state == ACPI_STATE_D3_COLD)
+ zpodd_enable_run_wake(dev);
+ acpi_bus_set_power(handle, acpi_state);
} else {
- /* Ditto */
- acpi_pm_device_run_wake(
- &dev->sdev->sdev_gendev, false);
+ if (runtime && zpodd_dev_enabled(dev))
+ zpodd_disable_run_wake(dev);
acpi_bus_set_power(handle, ACPI_STATE_D0);
}
}
+}
+
+/* ACPI spec requires _PS0 when IDE power on and _PS3 when power off */
+static void pata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+{
+ struct ata_device *dev;
+ acpi_handle port_handle;
+
+ port_handle = ata_ap_acpi_handle(ap);
+ if (!port_handle)
+ return;
+
+ /* channel first and then drives for power on and vica versa
+ for power off */
+ if (state.event & PM_EVENT_RESUME)
+ acpi_bus_set_power(port_handle, ACPI_STATE_D0);
+
+ ata_for_each_dev(dev, &ap->link, ENABLED) {
+ acpi_handle dev_handle = ata_dev_acpi_handle(dev);
+ if (!dev_handle)
+ continue;
+
+ acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ?
+ ACPI_STATE_D0 : ACPI_STATE_D3);
+ }
- handle = ata_ap_acpi_handle(ap);
- if (handle && state.event != PM_EVENT_ON)
- acpi_bus_set_power(handle, ACPI_STATE_D3);
+ if (!(state.event & PM_EVENT_RESUME))
+ acpi_bus_set_power(port_handle, ACPI_STATE_D3);
+}
+
+/**
+ * ata_acpi_set_state - set the port power state
+ * @ap: target ATA port
+ * @state: state, on/off
+ *
+ * This function sets a proper ACPI D state for the device on
+ * system and runtime PM operations.
+ */
+void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+{
+ if (ap->flags & ATA_FLAG_ACPI_SATA)
+ sata_acpi_set_state(ap, state);
+ else
+ pata_acpi_set_state(ap, state);
}
/**
@@ -974,96 +1020,35 @@ void ata_acpi_on_disable(struct ata_device *dev)
ata_acpi_clear_gtf(dev);
}
-static void ata_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
-{
- struct ata_device *ata_dev = context;
-
- if (event == ACPI_NOTIFY_DEVICE_WAKE && ata_dev &&
- pm_runtime_suspended(&ata_dev->sdev->sdev_gendev))
- scsi_autopm_get_device(ata_dev->sdev);
-}
-
-static void ata_acpi_add_pm_notifier(struct ata_device *dev)
-{
- struct acpi_device *acpi_dev;
- acpi_handle handle;
- acpi_status status;
-
- handle = ata_dev_acpi_handle(dev);
- if (!handle)
- return;
-
- status = acpi_bus_get_device(handle, &acpi_dev);
- if (ACPI_FAILURE(status))
- return;
-
- if (dev->sdev->can_power_off) {
- acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- ata_acpi_wake_dev, dev);
- device_set_run_wake(&dev->sdev->sdev_gendev, true);
- }
-}
-
-static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
-{
- struct acpi_device *acpi_dev;
- acpi_handle handle;
- acpi_status status;
-
- handle = ata_dev_acpi_handle(dev);
- if (!handle)
- return;
-
- status = acpi_bus_get_device(handle, &acpi_dev);
- if (ACPI_FAILURE(status))
- return;
-
- if (dev->sdev->can_power_off) {
- device_set_run_wake(&dev->sdev->sdev_gendev, false);
- acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- ata_acpi_wake_dev);
- }
-}
-
static void ata_acpi_register_power_resource(struct ata_device *dev)
{
struct scsi_device *sdev = dev->sdev;
acpi_handle handle;
- struct device *device;
handle = ata_dev_acpi_handle(dev);
- if (!handle)
- return;
-
- device = &sdev->sdev_gendev;
-
- acpi_power_resource_register_device(device, handle);
+ if (handle)
+ acpi_dev_pm_remove_dependent(handle, &sdev->sdev_gendev);
}
static void ata_acpi_unregister_power_resource(struct ata_device *dev)
{
struct scsi_device *sdev = dev->sdev;
acpi_handle handle;
- struct device *device;
handle = ata_dev_acpi_handle(dev);
- if (!handle)
- return;
-
- device = &sdev->sdev_gendev;
-
- acpi_power_resource_unregister_device(device, handle);
+ if (handle)
+ acpi_dev_pm_remove_dependent(handle, &sdev->sdev_gendev);
}
void ata_acpi_bind(struct ata_device *dev)
{
- ata_acpi_add_pm_notifier(dev);
ata_acpi_register_power_resource(dev);
+ if (zpodd_dev_enabled(dev))
+ dev_pm_qos_expose_flags(&dev->sdev->sdev_gendev, 0);
}
void ata_acpi_unbind(struct ata_device *dev)
{
- ata_acpi_remove_pm_notifier(dev);
ata_acpi_unregister_power_resource(dev);
}
@@ -1105,9 +1090,6 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev,
acpi_handle *handle)
{
struct ata_device *ata_dev;
- acpi_status status;
- struct acpi_device *acpi_dev;
- struct acpi_device_power_state *states;
if (ap->flags & ATA_FLAG_ACPI_SATA) {
if (!sata_pmp_attached(ap))
@@ -1124,21 +1106,6 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev,
if (!*handle)
return -ENODEV;
- status = acpi_bus_get_device(*handle, &acpi_dev);
- if (ACPI_FAILURE(status))
- return 0;
-
- /*
- * If firmware has _PS3 or _PR3 for this device,
- * and this ata ODD device support device attention,
- * it means this device can be powered off
- */
- states = acpi_dev->power.states;
- if ((states[ACPI_STATE_D3_HOT].flags.valid ||
- states[ACPI_STATE_D3_COLD].flags.explicit_set) &&
- ata_dev->flags & ATA_DFLAG_DA)
- sdev->can_power_off = 1;
-
return 0;
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 46cd3f4c6aaa..497adea1f0d6 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2400,8 +2400,10 @@ int ata_dev_configure(struct ata_device *dev)
dma_dir_string = ", DMADIR";
}
- if (ata_id_has_da(dev->id))
+ if (ata_id_has_da(dev->id)) {
dev->flags |= ATA_DFLAG_DA;
+ zpodd_init(dev);
+ }
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info)
@@ -5331,9 +5333,6 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
{
- unsigned int ehi_flags = ATA_EHI_QUIET;
- int rc;
-
/*
* On some hardware, device fails to respond after spun down
* for suspend. As the device won't be used before being
@@ -5342,11 +5341,9 @@ static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int
*
* http://thread.gmane.org/gmane.linux.ide/46764
*/
- if (mesg.event == PM_EVENT_SUSPEND)
- ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
-
- rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
- return rc;
+ unsigned int ehi_flags = ATA_EHI_QUIET | ATA_EHI_NO_AUTOPSY |
+ ATA_EHI_NO_RECOVERY;
+ return ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
}
static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
@@ -5367,40 +5364,38 @@ static int ata_port_suspend(struct device *dev)
static int ata_port_do_freeze(struct device *dev)
{
if (pm_runtime_suspended(dev))
- pm_runtime_resume(dev);
+ return 0;
return ata_port_suspend_common(dev, PMSG_FREEZE);
}
static int ata_port_poweroff(struct device *dev)
{
- if (pm_runtime_suspended(dev))
- return 0;
-
return ata_port_suspend_common(dev, PMSG_HIBERNATE);
}
-static int __ata_port_resume_common(struct ata_port *ap, int *async)
+static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg,
+ int *async)
{
int rc;
- rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
+ rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET,
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
return rc;
}
-static int ata_port_resume_common(struct device *dev)
+static int ata_port_resume_common(struct device *dev, pm_message_t mesg)
{
struct ata_port *ap = to_ata_port(dev);
- return __ata_port_resume_common(ap, NULL);
+ return __ata_port_resume_common(ap, mesg, NULL);
}
static int ata_port_resume(struct device *dev)
{
int rc;
- rc = ata_port_resume_common(dev);
+ rc = ata_port_resume_common(dev, PMSG_RESUME);
if (!rc) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
@@ -5410,11 +5405,40 @@ static int ata_port_resume(struct device *dev)
return rc;
}
+/*
+ * For ODDs, the upper layer will poll for media change every few seconds,
+ * which will make it enter and leave suspend state every few seconds. And
+ * as each suspend will cause a hard/soft reset, the gain of runtime suspend
+ * is very little and the ODD may malfunction after constantly being reset.
+ * So the idle callback here will not proceed to suspend if a non-ZPODD capable
+ * ODD is attached to the port.
+ */
static int ata_port_runtime_idle(struct device *dev)
{
+ struct ata_port *ap = to_ata_port(dev);
+ struct ata_link *link;
+ struct ata_device *adev;
+
+ ata_for_each_link(link, ap, HOST_FIRST) {
+ ata_for_each_dev(adev, link, ENABLED)
+ if (adev->class == ATA_DEV_ATAPI &&
+ !zpodd_dev_enabled(adev))
+ return -EBUSY;
+ }
+
return pm_runtime_suspend(dev);
}
+static int ata_port_runtime_suspend(struct device *dev)
+{
+ return ata_port_suspend_common(dev, PMSG_AUTO_SUSPEND);
+}
+
+static int ata_port_runtime_resume(struct device *dev)
+{
+ return ata_port_resume_common(dev, PMSG_AUTO_RESUME);
+}
+
static const struct dev_pm_ops ata_port_pm_ops = {
.suspend = ata_port_suspend,
.resume = ata_port_resume,
@@ -5423,8 +5447,8 @@ static const struct dev_pm_ops ata_port_pm_ops = {
.poweroff = ata_port_poweroff,
.restore = ata_port_resume,
- .runtime_suspend = ata_port_suspend,
- .runtime_resume = ata_port_resume_common,
+ .runtime_suspend = ata_port_runtime_suspend,
+ .runtime_resume = ata_port_runtime_resume,
.runtime_idle = ata_port_runtime_idle,
};
@@ -5441,7 +5465,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
int ata_sas_port_async_resume(struct ata_port *ap, int *async)
{
- return __ata_port_resume_common(ap, async);
+ return __ata_port_resume_common(ap, PMSG_RESUME, async);
}
EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index bcf4437214f5..f9476fb3ac43 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1591,7 +1591,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
* RETURNS:
* 0 on success, AC_ERR_* mask on failure.
*/
-static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
+unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
{
u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
struct ata_taskfile tf;
@@ -1624,7 +1624,7 @@ static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
* RETURNS:
* 0 on success, AC_ERR_* mask on failure
*/
-static unsigned int atapi_eh_request_sense(struct ata_device *dev,
+unsigned int atapi_eh_request_sense(struct ata_device *dev,
u8 *sense_buf, u8 dfl_sense_key)
{
u8 cdb[ATAPI_CDB_LEN] =
@@ -3857,6 +3857,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = atapi_eh_clear_ua(dev);
if (rc)
goto rest_fail;
+ if (zpodd_dev_enabled(dev))
+ zpodd_post_poweron(dev);
}
}
@@ -4022,11 +4024,12 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
{
unsigned long flags;
int rc = 0;
+ struct ata_device *dev;
/* are we suspending? */
spin_lock_irqsave(ap->lock, flags);
if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
- ap->pm_mesg.event == PM_EVENT_ON) {
+ ap->pm_mesg.event & PM_EVENT_RESUME) {
spin_unlock_irqrestore(ap->lock, flags);
return;
}
@@ -4034,6 +4037,18 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
+ /*
+ * If we have a ZPODD attached, check its zero
+ * power ready status before the port is frozen.
+ * Only needed for runtime suspend.
+ */
+ if (PMSG_IS_AUTO(ap->pm_mesg)) {
+ ata_for_each_dev(dev, &ap->link, ENABLED) {
+ if (zpodd_dev_enabled(dev))
+ zpodd_on_suspend(dev);
+ }
+ }
+
/* tell ACPI we're suspending */
rc = ata_acpi_on_suspend(ap);
if (rc)
@@ -4045,7 +4060,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
if (ap->ops->port_suspend)
rc = ap->ops->port_suspend(ap, ap->pm_mesg);
- ata_acpi_set_state(ap, PMSG_SUSPEND);
+ ata_acpi_set_state(ap, ap->pm_mesg);
out:
/* report result */
spin_lock_irqsave(ap->lock, flags);
@@ -4085,7 +4100,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
/* are we resuming? */
spin_lock_irqsave(ap->lock, flags);
if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
- ap->pm_mesg.event != PM_EVENT_ON) {
+ !(ap->pm_mesg.event & PM_EVENT_RESUME)) {
spin_unlock_irqrestore(ap->lock, flags);
return;
}
@@ -4104,7 +4119,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
ata_for_each_dev(dev, link, ALL)
ata_ering_clear(&dev->ering);
- ata_acpi_set_state(ap, PMSG_ON);
+ ata_acpi_set_state(ap, ap->pm_mesg);
if (ap->ops->port_resume)
rc = ap->ops->port_resume(ap);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 7c337e754dab..318b41358187 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -933,7 +933,11 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
* block specified for the ATA pass through commands. Regardless
* of whether the command errored or not, return a sense
* block. Copy all controller registers into the sense
- * block. Clear sense key, ASC & ASCQ if there is no error.
+ * block. If there was no error, we get the request from an ATA
+ * passthrough command, so we use the following sense data:
+ * sk = RECOVERED ERROR
+ * asc,ascq = ATA PASS-THROUGH INFORMATION AVAILABLE
+ *
*
* LOCKING:
* None.
@@ -959,6 +963,10 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature,
&sb[1], &sb[2], &sb[3], verbose);
sb[1] &= 0x0f;
+ } else {
+ sb[1] = RECOVERED_ERROR;
+ sb[2] = 0;
+ sb[3] = 0x1D;
}
/*
@@ -1733,10 +1741,12 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
/* For ATA pass thru (SAT) commands, generate a sense block if
* user mandated it or if there's an error. Note that if we
- * generate because the user forced us to, a check condition
- * is generated and the ATA register values are returned
+ * generate because the user forced us to [CK_COND =1], a check
+ * condition is generated and the ATA register values are returned
* whether the command completed successfully or not. If there
- * was no error, SK, ASC and ASCQ will all be zero.
+ * was no error, we use the following sense data:
+ * sk = RECOVERED ERROR
+ * asc,ascq = ATA PASS-THROUGH INFORMATION AVAILABLE
*/
if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
((cdb[2] & 0x20) || need_sense)) {
@@ -3755,6 +3765,8 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
mutex_lock(&ap->scsi_host->scan_mutex);
spin_lock_irqsave(ap->lock, flags);
+ if (zpodd_dev_enabled(dev))
+ zpodd_exit(dev);
ata_acpi_unbind(dev);
/* clearing dev->sdev is protected by host lock */
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c
new file mode 100644
index 000000000000..90b159b740b3
--- /dev/null
+++ b/drivers/ata/libata-zpodd.c
@@ -0,0 +1,299 @@
+#include <linux/libata.h>
+#include <linux/cdrom.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <scsi/scsi_device.h>
+
+#include "libata.h"
+
+static int zpodd_poweroff_delay = 30; /* 30 seconds for power off delay */
+module_param(zpodd_poweroff_delay, int, 0644);
+MODULE_PARM_DESC(zpodd_poweroff_delay, "Poweroff delay for ZPODD in seconds");
+
+enum odd_mech_type {
+ ODD_MECH_TYPE_SLOT,
+ ODD_MECH_TYPE_DRAWER,
+ ODD_MECH_TYPE_UNSUPPORTED,
+};
+
+struct zpodd {
+ enum odd_mech_type mech_type; /* init during probe, RO afterwards */
+ struct ata_device *dev;
+
+ /* The following fields are synchronized by PM core. */
+ bool from_notify; /* resumed as a result of
+ * acpi wake notification */
+ bool zp_ready; /* ZP ready state */
+ unsigned long last_ready; /* last ZP ready timestamp */
+ bool zp_sampled; /* ZP ready state sampled */
+ bool powered_off; /* ODD is powered off
+ * during suspend */
+};
+
+static int eject_tray(struct ata_device *dev)
+{
+ struct ata_taskfile tf = {};
+ const char cdb[] = { GPCMD_START_STOP_UNIT,
+ 0, 0, 0,
+ 0x02, /* LoEj */
+ 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.command = ATA_CMD_PACKET;
+ tf.protocol = ATAPI_PROT_NODATA;
+
+ return ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
+}
+
+/* Per the spec, only slot type and drawer type ODD can be supported */
+static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
+{
+ char buf[16];
+ unsigned int ret;
+ struct rm_feature_desc *desc = (void *)(buf + 8);
+ struct ata_taskfile tf = {};
+
+ char cdb[] = { GPCMD_GET_CONFIGURATION,
+ 2, /* only 1 feature descriptor requested */
+ 0, 3, /* 3, removable medium feature */
+ 0, 0, 0,/* reserved */
+ 0, sizeof(buf),
+ 0, 0, 0,
+ };
+
+ tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.command = ATA_CMD_PACKET;
+ tf.protocol = ATAPI_PROT_PIO;
+ tf.lbam = sizeof(buf);
+
+ ret = ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
+ buf, sizeof(buf), 0);
+ if (ret)
+ return ODD_MECH_TYPE_UNSUPPORTED;
+
+ if (be16_to_cpu(desc->feature_code) != 3)
+ return ODD_MECH_TYPE_UNSUPPORTED;
+
+ if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1)
+ return ODD_MECH_TYPE_SLOT;
+ else if (desc->mech_type == 1 && desc->load == 0 && desc->eject == 1)
+ return ODD_MECH_TYPE_DRAWER;
+ else
+ return ODD_MECH_TYPE_UNSUPPORTED;
+}
+
+static bool odd_can_poweroff(struct ata_device *ata_dev)
+{
+ acpi_handle handle;
+ acpi_status status;
+ struct acpi_device *acpi_dev;
+
+ handle = ata_dev_acpi_handle(ata_dev);
+ if (!handle)
+ return false;
+
+ status = acpi_bus_get_device(handle, &acpi_dev);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ return acpi_device_can_poweroff(acpi_dev);
+}
+
+/* Test if ODD is zero power ready by sense code */
+static bool zpready(struct ata_device *dev)
+{
+ u8 sense_key, *sense_buf;
+ unsigned int ret, asc, ascq, add_len;
+ struct zpodd *zpodd = dev->zpodd;
+
+ ret = atapi_eh_tur(dev, &sense_key);
+
+ if (!ret || sense_key != NOT_READY)
+ return false;
+
+ sense_buf = dev->link->ap->sector_buf;
+ ret = atapi_eh_request_sense(dev, sense_buf, sense_key);
+ if (ret)
+ return false;
+
+ /* sense valid */
+ if ((sense_buf[0] & 0x7f) != 0x70)
+ return false;
+
+ add_len = sense_buf[7];
+ /* has asc and ascq */
+ if (add_len < 6)
+ return false;
+
+ asc = sense_buf[12];
+ ascq = sense_buf[13];
+
+ if (zpodd->mech_type == ODD_MECH_TYPE_SLOT)
+ /* no media inside */
+ return asc == 0x3a;
+ else
+ /* no media inside and door closed */
+ return asc == 0x3a && ascq == 0x01;
+}
+
+/*
+ * Update the zpodd->zp_ready field. This field will only be set
+ * if the ODD has stayed in ZP ready state for zpodd_poweroff_delay
+ * time, and will be used to decide if power off is allowed. If it
+ * is set, it will be cleared during resume from powered off state.
+ */
+void zpodd_on_suspend(struct ata_device *dev)
+{
+ struct zpodd *zpodd = dev->zpodd;
+ unsigned long expires;
+
+ if (!zpready(dev)) {
+ zpodd->zp_sampled = false;
+ zpodd->zp_ready = false;
+ return;
+ }
+
+ if (!zpodd->zp_sampled) {
+ zpodd->zp_sampled = true;
+ zpodd->last_ready = jiffies;
+ return;
+ }
+
+ expires = zpodd->last_ready +
+ msecs_to_jiffies(zpodd_poweroff_delay * 1000);
+ if (time_before(jiffies, expires))
+ return;
+
+ zpodd->zp_ready = true;
+}
+
+bool zpodd_zpready(struct ata_device *dev)
+{
+ struct zpodd *zpodd = dev->zpodd;
+ return zpodd->zp_ready;
+}
+
+/*
+ * Enable runtime wake capability through ACPI and set the powered_off flag,
+ * this flag will be used during resume to decide what operations are needed
+ * to take.
+ *
+ * Also, media poll needs to be silenced, so that it doesn't bring the ODD
+ * back to full power state every few seconds.
+ */
+void zpodd_enable_run_wake(struct ata_device *dev)
+{
+ struct zpodd *zpodd = dev->zpodd;
+
+ sdev_disable_disk_events(dev->sdev);
+
+ zpodd->powered_off = true;
+ device_set_run_wake(&dev->sdev->sdev_gendev, true);
+ acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, true);
+}
+
+/* Disable runtime wake capability if it is enabled */
+void zpodd_disable_run_wake(struct ata_device *dev)
+{
+ struct zpodd *zpodd = dev->zpodd;
+
+ if (zpodd->powered_off) {
+ acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, false);
+ device_set_run_wake(&dev->sdev->sdev_gendev, false);
+ }
+}
+
+/*
+ * Post power on processing after the ODD has been recovered. If the
+ * ODD wasn't powered off during suspend, it doesn't do anything.
+ *
+ * For drawer type ODD, if it is powered on due to user pressed the
+ * eject button, the tray needs to be ejected. This can only be done
+ * after the ODD has been recovered, i.e. link is initialized and
+ * device is able to process NON_DATA PIO command, as eject needs to
+ * send command for the ODD to process.
+ *
+ * The from_notify flag set in wake notification handler function
+ * zpodd_wake_dev represents if power on is due to user's action.
+ *
+ * For both types of ODD, several fields need to be reset.
+ */
+void zpodd_post_poweron(struct ata_device *dev)
+{
+ struct zpodd *zpodd = dev->zpodd;
+
+ if (!zpodd->powered_off)
+ return;
+
+ zpodd->powered_off = false;
+
+ if (zpodd->from_notify) {
+ zpodd->from_notify = false;
+ if (zpodd->mech_type == ODD_MECH_TYPE_DRAWER)
+ eject_tray(dev);
+ }
+
+ zpodd->zp_sampled = false;
+ zpodd->zp_ready = false;
+
+ sdev_enable_disk_events(dev->sdev);
+}
+
+static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context)
+{
+ struct ata_device *ata_dev = context;
+ struct zpodd *zpodd = ata_dev->zpodd;
+ struct device *dev = &ata_dev->sdev->sdev_gendev;
+
+ if (event == ACPI_NOTIFY_DEVICE_WAKE && pm_runtime_suspended(dev)) {
+ zpodd->from_notify = true;
+ pm_runtime_resume(dev);
+ }
+}
+
+static void ata_acpi_add_pm_notifier(struct ata_device *dev)
+{
+ acpi_handle handle = ata_dev_acpi_handle(dev);
+ acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ zpodd_wake_dev, dev);
+}
+
+static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
+{
+ acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->sdev->sdev_gendev);
+ acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, zpodd_wake_dev);
+}
+
+void zpodd_init(struct ata_device *dev)
+{
+ enum odd_mech_type mech_type;
+ struct zpodd *zpodd;
+
+ if (dev->zpodd)
+ return;
+
+ if (!odd_can_poweroff(dev))
+ return;
+
+ mech_type = zpodd_get_mech_type(dev);
+ if (mech_type == ODD_MECH_TYPE_UNSUPPORTED)
+ return;
+
+ zpodd = kzalloc(sizeof(struct zpodd), GFP_KERNEL);
+ if (!zpodd)
+ return;
+
+ zpodd->mech_type = mech_type;
+
+ ata_acpi_add_pm_notifier(dev);
+ zpodd->dev = dev;
+ dev->zpodd = zpodd;
+}
+
+void zpodd_exit(struct ata_device *dev)
+{
+ ata_acpi_remove_pm_notifier(dev);
+ kfree(dev->zpodd);
+ dev->zpodd = NULL;
+}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 7148a58020b9..c949dd311b2e 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -182,6 +182,9 @@ extern void ata_eh_finish(struct ata_port *ap);
extern int ata_ering_map(struct ata_ering *ering,
int (*map_fn)(struct ata_ering_entry *, void *),
void *arg);
+extern unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key);
+extern unsigned int atapi_eh_request_sense(struct ata_device *dev,
+ u8 *sense_buf, u8 dfl_sense_key);
/* libata-pmp.c */
#ifdef CONFIG_SATA_PMP
@@ -230,4 +233,28 @@ static inline void ata_sff_exit(void)
{ }
#endif /* CONFIG_ATA_SFF */
+/* libata-zpodd.c */
+#ifdef CONFIG_SATA_ZPODD
+void zpodd_init(struct ata_device *dev);
+void zpodd_exit(struct ata_device *dev);
+static inline bool zpodd_dev_enabled(struct ata_device *dev)
+{
+ return dev->zpodd != NULL;
+}
+void zpodd_on_suspend(struct ata_device *dev);
+bool zpodd_zpready(struct ata_device *dev);
+void zpodd_enable_run_wake(struct ata_device *dev);
+void zpodd_disable_run_wake(struct ata_device *dev);
+void zpodd_post_poweron(struct ata_device *dev);
+#else /* CONFIG_SATA_ZPODD */
+static inline void zpodd_init(struct ata_device *dev) {}
+static inline void zpodd_exit(struct ata_device *dev) {}
+static inline bool zpodd_dev_enabled(struct ata_device *dev) { return false; }
+static inline void zpodd_on_suspend(struct ata_device *dev) {}
+static inline bool zpodd_zpready(struct ata_device *dev) { return false; }
+static inline void zpodd_enable_run_wake(struct ata_device *dev) {}
+static inline void zpodd_disable_run_wake(struct ata_device *dev) {}
+static inline void zpodd_post_poweron(struct ata_device *dev) {}
+#endif /* CONFIG_SATA_ZPODD */
+
#endif /* __LIBATA_H__ */
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
index 556222f04731..c1bfaf43d109 100644
--- a/drivers/ata/pata_ep93xx.c
+++ b/drivers/ata/pata_ep93xx.c
@@ -31,6 +31,7 @@
* Copyright (C) 2006 Tower Technologies
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -937,9 +938,9 @@ static int ep93xx_pata_probe(struct platform_device *pdev)
goto err_rel_gpio;
}
- ide_base = devm_request_and_ioremap(&pdev->dev, mem_res);
- if (!ide_base) {
- err = -ENXIO;
+ ide_base = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(ide_base)) {
+ err = PTR_ERR(ide_base);
goto err_rel_gpio;
}
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 652f57e83484..3a8fb28b71f2 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -26,9 +26,9 @@
#include <asm/prom.h>
#include <asm/mpc52xx.h>
-#include <sysdev/bestcomm/bestcomm.h>
-#include <sysdev/bestcomm/bestcomm_priv.h>
-#include <sysdev/bestcomm/ata.h>
+#include <linux/fsl/bestcomm/bestcomm.h>
+#include <linux/fsl/bestcomm/bestcomm_priv.h>
+#include <linux/fsl/bestcomm/ata.h>
#define DRV_NAME "mpc52xx_ata"
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
index 63ffb002ec67..70b0e01372b3 100644
--- a/drivers/ata/pata_samsung_cf.c
+++ b/drivers/ata/pata_samsung_cf.c
@@ -512,7 +512,7 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
return -ENOMEM;
}
- info->clk = clk_get(&pdev->dev, "cfcon");
+ info->clk = devm_clk_get(&pdev->dev, "cfcon");
if (IS_ERR(info->clk)) {
dev_err(dev, "failed to get access to cf controller clock\n");
ret = PTR_ERR(info->clk);
@@ -589,7 +589,6 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
stop_clk:
clk_disable(info->clk);
- clk_put(info->clk);
return ret;
}
@@ -601,7 +600,6 @@ static int __exit pata_s3c_remove(struct platform_device *pdev)
ata_host_detach(host);
clk_disable(info->clk);
- clk_put(info->clk);
return 0;
}
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
new file mode 100644
index 000000000000..caf33f620c35
--- /dev/null
+++ b/drivers/ata/sata_rcar.c
@@ -0,0 +1,910 @@
+/*
+ * Renesas R-Car SATA driver
+ *
+ * Author: Vladimir Barinov <source@cogentembedded.com>
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ * Copyright (C) 2013 Renesas Solutions 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/kernel.h>
+#include <linux/module.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#define DRV_NAME "sata_rcar"
+
+/* SH-Navi2G/ATAPI-ATA compatible task registers */
+#define DATA_REG 0x100
+#define SDEVCON_REG 0x138
+
+/* SH-Navi2G/ATAPI module compatible control registers */
+#define ATAPI_CONTROL1_REG 0x180
+#define ATAPI_STATUS_REG 0x184
+#define ATAPI_INT_ENABLE_REG 0x188
+#define ATAPI_DTB_ADR_REG 0x198
+#define ATAPI_DMA_START_ADR_REG 0x19C
+#define ATAPI_DMA_TRANS_CNT_REG 0x1A0
+#define ATAPI_CONTROL2_REG 0x1A4
+#define ATAPI_SIG_ST_REG 0x1B0
+#define ATAPI_BYTE_SWAP_REG 0x1BC
+
+/* ATAPI control 1 register (ATAPI_CONTROL1) bits */
+#define ATAPI_CONTROL1_ISM BIT(16)
+#define ATAPI_CONTROL1_DTA32M BIT(11)
+#define ATAPI_CONTROL1_RESET BIT(7)
+#define ATAPI_CONTROL1_DESE BIT(3)
+#define ATAPI_CONTROL1_RW BIT(2)
+#define ATAPI_CONTROL1_STOP BIT(1)
+#define ATAPI_CONTROL1_START BIT(0)
+
+/* ATAPI status register (ATAPI_STATUS) bits */
+#define ATAPI_STATUS_SATAINT BIT(11)
+#define ATAPI_STATUS_DNEND BIT(6)
+#define ATAPI_STATUS_DEVTRM BIT(5)
+#define ATAPI_STATUS_DEVINT BIT(4)
+#define ATAPI_STATUS_ERR BIT(2)
+#define ATAPI_STATUS_NEND BIT(1)
+#define ATAPI_STATUS_ACT BIT(0)
+
+/* Interrupt enable register (ATAPI_INT_ENABLE) bits */
+#define ATAPI_INT_ENABLE_SATAINT BIT(11)
+#define ATAPI_INT_ENABLE_DNEND BIT(6)
+#define ATAPI_INT_ENABLE_DEVTRM BIT(5)
+#define ATAPI_INT_ENABLE_DEVINT BIT(4)
+#define ATAPI_INT_ENABLE_ERR BIT(2)
+#define ATAPI_INT_ENABLE_NEND BIT(1)
+#define ATAPI_INT_ENABLE_ACT BIT(0)
+
+/* Access control registers for physical layer control register */
+#define SATAPHYADDR_REG 0x200
+#define SATAPHYWDATA_REG 0x204
+#define SATAPHYACCEN_REG 0x208
+#define SATAPHYRESET_REG 0x20C
+#define SATAPHYRDATA_REG 0x210
+#define SATAPHYACK_REG 0x214
+
+/* Physical layer control address command register (SATAPHYADDR) bits */
+#define SATAPHYADDR_PHYRATEMODE BIT(10)
+#define SATAPHYADDR_PHYCMD_READ BIT(9)
+#define SATAPHYADDR_PHYCMD_WRITE BIT(8)
+
+/* Physical layer control enable register (SATAPHYACCEN) bits */
+#define SATAPHYACCEN_PHYLANE BIT(0)
+
+/* Physical layer control reset register (SATAPHYRESET) bits */
+#define SATAPHYRESET_PHYRST BIT(1)
+#define SATAPHYRESET_PHYSRES BIT(0)
+
+/* Physical layer control acknowledge register (SATAPHYACK) bits */
+#define SATAPHYACK_PHYACK BIT(0)
+
+/* Serial-ATA HOST control registers */
+#define BISTCONF_REG 0x102C
+#define SDATA_REG 0x1100
+#define SSDEVCON_REG 0x1204
+
+#define SCRSSTS_REG 0x1400
+#define SCRSERR_REG 0x1404
+#define SCRSCON_REG 0x1408
+#define SCRSACT_REG 0x140C
+
+#define SATAINTSTAT_REG 0x1508
+#define SATAINTMASK_REG 0x150C
+
+/* SATA INT status register (SATAINTSTAT) bits */
+#define SATAINTSTAT_SERR BIT(3)
+#define SATAINTSTAT_ATA BIT(0)
+
+/* SATA INT mask register (SATAINTSTAT) bits */
+#define SATAINTMASK_SERRMSK BIT(3)
+#define SATAINTMASK_ERRMSK BIT(2)
+#define SATAINTMASK_ERRCRTMSK BIT(1)
+#define SATAINTMASK_ATAMSK BIT(0)
+
+#define SATA_RCAR_INT_MASK (SATAINTMASK_SERRMSK | \
+ SATAINTMASK_ATAMSK)
+
+/* Physical Layer Control Registers */
+#define SATAPCTLR1_REG 0x43
+#define SATAPCTLR2_REG 0x52
+#define SATAPCTLR3_REG 0x5A
+#define SATAPCTLR4_REG 0x60
+
+/* Descriptor table word 0 bit (when DTA32M = 1) */
+#define SATA_RCAR_DTEND BIT(0)
+
+struct sata_rcar_priv {
+ void __iomem *base;
+ struct clk *clk;
+};
+
+static void sata_rcar_phy_initialize(struct sata_rcar_priv *priv)
+{
+ /* idle state */
+ iowrite32(0, priv->base + SATAPHYADDR_REG);
+ /* reset */
+ iowrite32(SATAPHYRESET_PHYRST, priv->base + SATAPHYRESET_REG);
+ udelay(10);
+ /* deassert reset */
+ iowrite32(0, priv->base + SATAPHYRESET_REG);
+}
+
+static void sata_rcar_phy_write(struct sata_rcar_priv *priv, u16 reg, u32 val,
+ int group)
+{
+ int timeout;
+
+ /* deassert reset */
+ iowrite32(0, priv->base + SATAPHYRESET_REG);
+ /* lane 1 */
+ iowrite32(SATAPHYACCEN_PHYLANE, priv->base + SATAPHYACCEN_REG);
+ /* write phy register value */
+ iowrite32(val, priv->base + SATAPHYWDATA_REG);
+ /* set register group */
+ if (group)
+ reg |= SATAPHYADDR_PHYRATEMODE;
+ /* write command */
+ iowrite32(SATAPHYADDR_PHYCMD_WRITE | reg, priv->base + SATAPHYADDR_REG);
+ /* wait for ack */
+ for (timeout = 0; timeout < 100; timeout++) {
+ val = ioread32(priv->base + SATAPHYACK_REG);
+ if (val & SATAPHYACK_PHYACK)
+ break;
+ }
+ if (timeout >= 100)
+ pr_err("%s timeout\n", __func__);
+ /* idle state */
+ iowrite32(0, priv->base + SATAPHYADDR_REG);
+}
+
+static void sata_rcar_freeze(struct ata_port *ap)
+{
+ struct sata_rcar_priv *priv = ap->host->private_data;
+
+ /* mask */
+ iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+
+ ata_sff_freeze(ap);
+}
+
+static void sata_rcar_thaw(struct ata_port *ap)
+{
+ struct sata_rcar_priv *priv = ap->host->private_data;
+
+ /* ack */
+ iowrite32(~SATA_RCAR_INT_MASK, priv->base + SATAINTSTAT_REG);
+
+ ata_sff_thaw(ap);
+
+ /* unmask */
+ iowrite32(0x7ff & ~SATA_RCAR_INT_MASK, priv->base + SATAINTMASK_REG);
+}
+
+static void sata_rcar_ioread16_rep(void __iomem *reg, void *buffer, int count)
+{
+ u16 *ptr = buffer;
+
+ while (count--) {
+ u16 data = ioread32(reg);
+
+ *ptr++ = data;
+ }
+}
+
+static void sata_rcar_iowrite16_rep(void __iomem *reg, void *buffer, int count)
+{
+ const u16 *ptr = buffer;
+
+ while (count--)
+ iowrite32(*ptr++, reg);
+}
+
+static u8 sata_rcar_check_status(struct ata_port *ap)
+{
+ return ioread32(ap->ioaddr.status_addr);
+}
+
+static u8 sata_rcar_check_altstatus(struct ata_port *ap)
+{
+ return ioread32(ap->ioaddr.altstatus_addr);
+}
+
+static void sata_rcar_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ iowrite32(ctl, ap->ioaddr.ctl_addr);
+}
+
+static void sata_rcar_dev_select(struct ata_port *ap, unsigned int device)
+{
+ iowrite32(ATA_DEVICE_OBS, ap->ioaddr.device_addr);
+ ata_sff_pause(ap); /* needed; also flushes, for mmio */
+}
+
+static unsigned int sata_rcar_ata_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u8 nsect, lbal;
+
+ sata_rcar_dev_select(ap, device);
+
+ iowrite32(0x55, ioaddr->nsect_addr);
+ iowrite32(0xaa, ioaddr->lbal_addr);
+
+ iowrite32(0xaa, ioaddr->nsect_addr);
+ iowrite32(0x55, ioaddr->lbal_addr);
+
+ iowrite32(0x55, ioaddr->nsect_addr);
+ iowrite32(0xaa, ioaddr->lbal_addr);
+
+ nsect = ioread32(ioaddr->nsect_addr);
+ lbal = ioread32(ioaddr->lbal_addr);
+
+ if (nsect == 0x55 && lbal == 0xaa)
+ return 1; /* found a device */
+
+ return 0; /* nothing found */
+}
+
+static int sata_rcar_wait_after_reset(struct ata_link *link,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+
+ ata_msleep(ap, ATA_WAIT_AFTER_RESET);
+
+ return ata_sff_wait_ready(link, deadline);
+}
+
+static int sata_rcar_bus_softreset(struct ata_port *ap, unsigned long deadline)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
+
+ /* software reset. causes dev0 to be selected */
+ iowrite32(ap->ctl, ioaddr->ctl_addr);
+ udelay(20);
+ iowrite32(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+ udelay(20);
+ iowrite32(ap->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = ap->ctl;
+
+ /* wait the port to become ready */
+ return sata_rcar_wait_after_reset(&ap->link, deadline);
+}
+
+static int sata_rcar_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ /* determine if device 0 is present */
+ if (sata_rcar_ata_devchk(ap, 0))
+ devmask |= 1 << 0;
+
+ /* issue bus reset */
+ DPRINTK("about to softreset, devmask=%x\n", devmask);
+ rc = sata_rcar_bus_softreset(ap, deadline);
+ /* if link is occupied, -ENODEV too is an error */
+ if (rc && (rc != -ENODEV || sata_scr_valid(link))) {
+ ata_link_err(link, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&link->device[0], devmask, &err);
+
+ DPRINTK("classes[0]=%u\n", classes[0]);
+ return 0;
+}
+
+static void sata_rcar_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ iowrite32(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ iowrite32(tf->hob_feature, ioaddr->feature_addr);
+ iowrite32(tf->hob_nsect, ioaddr->nsect_addr);
+ iowrite32(tf->hob_lbal, ioaddr->lbal_addr);
+ iowrite32(tf->hob_lbam, ioaddr->lbam_addr);
+ iowrite32(tf->hob_lbah, ioaddr->lbah_addr);
+ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+
+ if (is_addr) {
+ iowrite32(tf->feature, ioaddr->feature_addr);
+ iowrite32(tf->nsect, ioaddr->nsect_addr);
+ iowrite32(tf->lbal, ioaddr->lbal_addr);
+ iowrite32(tf->lbam, ioaddr->lbam_addr);
+ iowrite32(tf->lbah, ioaddr->lbah_addr);
+ VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ iowrite32(tf->device, ioaddr->device_addr);
+ VPRINTK("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+static void sata_rcar_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = sata_rcar_check_status(ap);
+ tf->feature = ioread32(ioaddr->error_addr);
+ tf->nsect = ioread32(ioaddr->nsect_addr);
+ tf->lbal = ioread32(ioaddr->lbal_addr);
+ tf->lbam = ioread32(ioaddr->lbam_addr);
+ tf->lbah = ioread32(ioaddr->lbah_addr);
+ tf->device = ioread32(ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ iowrite32(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = ioread32(ioaddr->error_addr);
+ tf->hob_nsect = ioread32(ioaddr->nsect_addr);
+ tf->hob_lbal = ioread32(ioaddr->lbal_addr);
+ tf->hob_lbam = ioread32(ioaddr->lbam_addr);
+ tf->hob_lbah = ioread32(ioaddr->lbah_addr);
+ iowrite32(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+static void sata_rcar_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+ iowrite32(tf->command, ap->ioaddr.command_addr);
+ ata_sff_pause(ap);
+}
+
+static unsigned int sata_rcar_data_xfer(struct ata_device *dev,
+ unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 1;
+
+ /* Transfer multiple of 2 bytes */
+ if (rw == READ)
+ sata_rcar_ioread16_rep(data_addr, buf, words);
+ else
+ sata_rcar_iowrite16_rep(data_addr, buf, words);
+
+ /* Transfer trailing byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ unsigned char pad[2] = { };
+
+ /* Point buf to the tail of buffer */
+ buf += buflen - 1;
+
+ /*
+ * Use io*16_rep() accessors here as well to avoid pointlessly
+ * swapping bytes to and from on the big endian machines...
+ */
+ if (rw == READ) {
+ sata_rcar_ioread16_rep(data_addr, pad, 1);
+ *buf = pad[0];
+ } else {
+ pad[0] = *buf;
+ sata_rcar_iowrite16_rep(data_addr, pad, 1);
+ }
+ words++;
+ }
+
+ return words << 1;
+}
+
+static void sata_rcar_drain_fifo(struct ata_queued_cmd *qc)
+{
+ int count;
+ struct ata_port *ap;
+
+ /* We only need to flush incoming data when a command was running */
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+ return;
+
+ ap = qc->ap;
+ /* Drain up to 64K of data before we give up this recovery method */
+ for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ) &&
+ count < 65536; count += 2)
+ ioread32(ap->ioaddr.data_addr);
+
+ /* Can become DEBUG later */
+ if (count)
+ ata_port_dbg(ap, "drained %d bytes to clear DRQ\n", count);
+}
+
+static int sata_rcar_scr_read(struct ata_link *link, unsigned int sc_reg,
+ u32 *val)
+{
+ if (sc_reg > SCR_ACTIVE)
+ return -EINVAL;
+
+ *val = ioread32(link->ap->ioaddr.scr_addr + (sc_reg << 2));
+ return 0;
+}
+
+static int sata_rcar_scr_write(struct ata_link *link, unsigned int sc_reg,
+ u32 val)
+{
+ if (sc_reg > SCR_ACTIVE)
+ return -EINVAL;
+
+ iowrite32(val, link->ap->ioaddr.scr_addr + (sc_reg << 2));
+ return 0;
+}
+
+static void sata_rcar_bmdma_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_bmdma_prd *prd = ap->bmdma_prd;
+ struct scatterlist *sg;
+ unsigned int si, pi;
+
+ pi = 0;
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ u32 addr, sg_len, len;
+
+ /*
+ * Note: h/w doesn't support 64-bit, so we unconditionally
+ * truncate dma_addr_t to u32.
+ */
+ addr = (u32)sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ /* H/w transfer count is only 29 bits long, let's be careful */
+ while (sg_len) {
+ len = sg_len;
+ if (len > 0x1ffffffe)
+ len = 0x1ffffffe;
+
+ prd[pi].addr = cpu_to_le32(addr);
+ prd[pi].flags_len = cpu_to_le32(len);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
+
+ pi++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ /* end-of-table flag */
+ prd[pi - 1].addr |= cpu_to_le32(SATA_RCAR_DTEND);
+}
+
+static void sata_rcar_qc_prep(struct ata_queued_cmd *qc)
+{
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+
+ sata_rcar_bmdma_fill_sg(qc);
+}
+
+static void sata_rcar_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int rw = qc->tf.flags & ATA_TFLAG_WRITE;
+ u32 dmactl;
+ struct sata_rcar_priv *priv = ap->host->private_data;
+
+ /* load PRD table addr. */
+ mb(); /* make sure PRD table writes are visible to controller */
+ iowrite32(ap->bmdma_prd_dma, priv->base + ATAPI_DTB_ADR_REG);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ dmactl &= ~(ATAPI_CONTROL1_RW | ATAPI_CONTROL1_STOP);
+ if (dmactl & ATAPI_CONTROL1_START) {
+ dmactl &= ~ATAPI_CONTROL1_START;
+ dmactl |= ATAPI_CONTROL1_STOP;
+ }
+ if (!rw)
+ dmactl |= ATAPI_CONTROL1_RW;
+ iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG);
+
+ /* issue r/w command */
+ ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+static void sata_rcar_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ u32 dmactl;
+ struct sata_rcar_priv *priv = ap->host->private_data;
+
+ /* start host DMA transaction */
+ dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ dmactl |= ATAPI_CONTROL1_START;
+ iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG);
+}
+
+static void sata_rcar_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct sata_rcar_priv *priv = ap->host->private_data;
+ u32 dmactl;
+
+ /* force termination of DMA transfer if active */
+ dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ if (dmactl & ATAPI_CONTROL1_START) {
+ dmactl &= ~ATAPI_CONTROL1_START;
+ dmactl |= ATAPI_CONTROL1_STOP;
+ iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG);
+ }
+
+ /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+ ata_sff_dma_pause(ap);
+}
+
+static u8 sata_rcar_bmdma_status(struct ata_port *ap)
+{
+ struct sata_rcar_priv *priv = ap->host->private_data;
+ u32 status;
+ u8 host_stat = 0;
+
+ status = ioread32(priv->base + ATAPI_STATUS_REG);
+ if (status & ATAPI_STATUS_DEVINT)
+ host_stat |= ATA_DMA_INTR;
+ if (status & ATAPI_STATUS_ACT)
+ host_stat |= ATA_DMA_ACTIVE;
+
+ return host_stat;
+}
+
+static struct scsi_host_template sata_rcar_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations sata_rcar_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .freeze = sata_rcar_freeze,
+ .thaw = sata_rcar_thaw,
+ .softreset = sata_rcar_softreset,
+
+ .scr_read = sata_rcar_scr_read,
+ .scr_write = sata_rcar_scr_write,
+
+ .sff_dev_select = sata_rcar_dev_select,
+ .sff_set_devctl = sata_rcar_set_devctl,
+ .sff_check_status = sata_rcar_check_status,
+ .sff_check_altstatus = sata_rcar_check_altstatus,
+ .sff_tf_load = sata_rcar_tf_load,
+ .sff_tf_read = sata_rcar_tf_read,
+ .sff_exec_command = sata_rcar_exec_command,
+ .sff_data_xfer = sata_rcar_data_xfer,
+ .sff_drain_fifo = sata_rcar_drain_fifo,
+
+ .qc_prep = sata_rcar_qc_prep,
+
+ .bmdma_setup = sata_rcar_bmdma_setup,
+ .bmdma_start = sata_rcar_bmdma_start,
+ .bmdma_stop = sata_rcar_bmdma_stop,
+ .bmdma_status = sata_rcar_bmdma_status,
+};
+
+static int sata_rcar_serr_interrupt(struct ata_port *ap)
+{
+ struct sata_rcar_priv *priv = ap->host->private_data;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ int freeze = 0;
+ int handled = 0;
+ u32 serror;
+
+ serror = ioread32(priv->base + SCRSERR_REG);
+ if (!serror)
+ return 0;
+
+ DPRINTK("SError @host_intr: 0x%x\n", serror);
+
+ /* first, analyze and record host port events */
+ ata_ehi_clear_desc(ehi);
+
+ if (serror & (SERR_DEV_XCHG | SERR_PHYRDY_CHG)) {
+ /* Setup a soft-reset EH action */
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, "%s", "hotplug");
+
+ freeze = serror & SERR_COMM_WAKE ? 0 : 1;
+ handled = 1;
+ }
+
+ /* freeze or abort */
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+
+ return handled;
+}
+
+static int sata_rcar_ata_interrupt(struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc;
+ int handled = 0;
+
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc)
+ handled |= ata_bmdma_port_intr(ap, qc);
+
+ return handled;
+}
+
+static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct sata_rcar_priv *priv = host->private_data;
+ struct ata_port *ap;
+ unsigned int handled = 0;
+ u32 sataintstat;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ sataintstat = ioread32(priv->base + SATAINTSTAT_REG);
+ if (!sataintstat)
+ goto done;
+ /* ack */
+ iowrite32(sataintstat & ~SATA_RCAR_INT_MASK,
+ priv->base + SATAINTSTAT_REG);
+
+ ap = host->ports[0];
+
+ if (sataintstat & SATAINTSTAT_ATA)
+ handled |= sata_rcar_ata_interrupt(ap);
+
+ if (sataintstat & SATAINTSTAT_SERR)
+ handled |= sata_rcar_serr_interrupt(ap);
+
+done:
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+static void sata_rcar_setup_port(struct ata_host *host)
+{
+ struct ata_port *ap = host->ports[0];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ struct sata_rcar_priv *priv = host->private_data;
+
+ ap->ops = &sata_rcar_port_ops;
+ ap->pio_mask = ATA_PIO4;
+ ap->udma_mask = ATA_UDMA6;
+ ap->flags |= ATA_FLAG_SATA;
+
+ ioaddr->cmd_addr = priv->base + SDATA_REG;
+ ioaddr->ctl_addr = priv->base + SSDEVCON_REG;
+ ioaddr->scr_addr = priv->base + SCRSSTS_REG;
+ ioaddr->altstatus_addr = ioaddr->ctl_addr;
+
+ ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << 2);
+ ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << 2);
+ ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << 2);
+ ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << 2);
+ ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << 2);
+ ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << 2);
+ ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << 2);
+ ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << 2);
+ ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << 2);
+ ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << 2);
+}
+
+static void sata_rcar_init_controller(struct ata_host *host)
+{
+ struct sata_rcar_priv *priv = host->private_data;
+ u32 val;
+
+ /* reset and setup phy */
+ sata_rcar_phy_initialize(priv);
+ sata_rcar_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 0);
+ sata_rcar_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 1);
+ sata_rcar_phy_write(priv, SATAPCTLR3_REG, 0x0000A061, 0);
+ sata_rcar_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 0);
+ sata_rcar_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 1);
+ sata_rcar_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0);
+
+ /* SATA-IP reset state */
+ val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ val |= ATAPI_CONTROL1_RESET;
+ iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+
+ /* ISM mode, PRD mode, DTEND flag at bit 0 */
+ val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ val |= ATAPI_CONTROL1_ISM;
+ val |= ATAPI_CONTROL1_DESE;
+ val |= ATAPI_CONTROL1_DTA32M;
+ iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+
+ /* Release the SATA-IP from the reset state */
+ val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ val &= ~ATAPI_CONTROL1_RESET;
+ iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+
+ /* ack and mask */
+ iowrite32(0, priv->base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+ /* enable interrupts */
+ iowrite32(ATAPI_INT_ENABLE_SATAINT, priv->base + ATAPI_INT_ENABLE_REG);
+}
+
+static int sata_rcar_probe(struct platform_device *pdev)
+{
+ struct ata_host *host;
+ struct sata_rcar_priv *priv;
+ struct resource *mem;
+ int irq;
+ int ret = 0;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem == NULL)
+ return -EINVAL;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0)
+ return -EINVAL;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct sata_rcar_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "failed to get access to sata clock\n");
+ return PTR_ERR(priv->clk);
+ }
+ clk_enable(priv->clk);
+
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host) {
+ dev_err(&pdev->dev, "ata_host_alloc failed\n");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ host->private_data = priv;
+
+ priv->base = devm_request_and_ioremap(&pdev->dev, mem);
+ if (!priv->base) {
+ ret = -EADDRNOTAVAIL;
+ goto cleanup;
+ }
+
+ /* setup port */
+ sata_rcar_setup_port(host);
+
+ /* initialize host controller */
+ sata_rcar_init_controller(host);
+
+ ret = ata_host_activate(host, irq, sata_rcar_interrupt, 0,
+ &sata_rcar_sht);
+ if (!ret)
+ return 0;
+
+cleanup:
+ clk_disable(priv->clk);
+
+ return ret;
+}
+
+static int sata_rcar_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct sata_rcar_priv *priv = host->private_data;
+
+ ata_host_detach(host);
+
+ /* disable interrupts */
+ iowrite32(0, priv->base + ATAPI_INT_ENABLE_REG);
+ /* ack and mask */
+ iowrite32(0, priv->base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+
+ clk_disable(priv->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int sata_rcar_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_rcar_priv *priv = host->private_data;
+ int ret;
+
+ ret = ata_host_suspend(host, PMSG_SUSPEND);
+ if (!ret) {
+ /* disable interrupts */
+ iowrite32(0, priv->base + ATAPI_INT_ENABLE_REG);
+ /* mask */
+ iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+
+ clk_disable(priv->clk);
+ }
+
+ return ret;
+}
+
+static int sata_rcar_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_rcar_priv *priv = host->private_data;
+
+ clk_enable(priv->clk);
+
+ /* ack and mask */
+ iowrite32(0, priv->base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+ /* enable interrupts */
+ iowrite32(ATAPI_INT_ENABLE_SATAINT, priv->base + ATAPI_INT_ENABLE_REG);
+
+ ata_host_resume(host);
+
+ return 0;
+}
+
+static const struct dev_pm_ops sata_rcar_pm_ops = {
+ .suspend = sata_rcar_suspend,
+ .resume = sata_rcar_resume,
+};
+#endif
+
+static struct of_device_id sata_rcar_match[] = {
+ { .compatible = "renesas,rcar-sata", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sata_rcar_match);
+
+static struct platform_driver sata_rcar_driver = {
+ .probe = sata_rcar_probe,
+ .remove = sata_rcar_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = sata_rcar_match,
+#ifdef CONFIG_PM
+ .pm = &sata_rcar_pm_ops,
+#endif
+ },
+};
+
+module_platform_driver(sata_rcar_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("Renesas R-Car SATA controller low level driver");
diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h
index 6a0955e6d4fc..53ecac5a2161 100644
--- a/drivers/atm/iphase.h
+++ b/drivers/atm/iphase.h
@@ -636,82 +636,82 @@ struct rx_buf_desc {
#define SEG_BASE IPHASE5575_FRAG_CONTROL_REG_BASE
#define REASS_BASE IPHASE5575_REASS_CONTROL_REG_BASE
-typedef volatile u_int freg_t;
+typedef volatile u_int ffreg_t;
typedef u_int rreg_t;
typedef struct _ffredn_t {
- freg_t idlehead_high; /* Idle cell header (high) */
- freg_t idlehead_low; /* Idle cell header (low) */
- freg_t maxrate; /* Maximum rate */
- freg_t stparms; /* Traffic Management Parameters */
- freg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */
- freg_t rm_type; /* */
- u_int filler5[0x17 - 0x06];
- freg_t cmd_reg; /* Command register */
- u_int filler18[0x20 - 0x18];
- freg_t cbr_base; /* CBR Pointer Base */
- freg_t vbr_base; /* VBR Pointer Base */
- freg_t abr_base; /* ABR Pointer Base */
- freg_t ubr_base; /* UBR Pointer Base */
- u_int filler24;
- freg_t vbrwq_base; /* VBR Wait Queue Base */
- freg_t abrwq_base; /* ABR Wait Queue Base */
- freg_t ubrwq_base; /* UBR Wait Queue Base */
- freg_t vct_base; /* Main VC Table Base */
- freg_t vcte_base; /* Extended Main VC Table Base */
- u_int filler2a[0x2C - 0x2A];
- freg_t cbr_tab_beg; /* CBR Table Begin */
- freg_t cbr_tab_end; /* CBR Table End */
- freg_t cbr_pointer; /* CBR Pointer */
- u_int filler2f[0x30 - 0x2F];
- freg_t prq_st_adr; /* Packet Ready Queue Start Address */
- freg_t prq_ed_adr; /* Packet Ready Queue End Address */
- freg_t prq_rd_ptr; /* Packet Ready Queue read pointer */
- freg_t prq_wr_ptr; /* Packet Ready Queue write pointer */
- freg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/
- freg_t tcq_ed_adr; /* Transmit Complete Queue End Address */
- freg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */
- freg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/
- u_int filler38[0x40 - 0x38];
- freg_t queue_base; /* Base address for PRQ and TCQ */
- freg_t desc_base; /* Base address of descriptor table */
- u_int filler42[0x45 - 0x42];
- freg_t mode_reg_0; /* Mode register 0 */
- freg_t mode_reg_1; /* Mode register 1 */
- freg_t intr_status_reg;/* Interrupt Status register */
- freg_t mask_reg; /* Mask Register */
- freg_t cell_ctr_high1; /* Total cell transfer count (high) */
- freg_t cell_ctr_lo1; /* Total cell transfer count (low) */
- freg_t state_reg; /* Status register */
- u_int filler4c[0x58 - 0x4c];
- freg_t curr_desc_num; /* Contains the current descriptor num */
- freg_t next_desc; /* Next descriptor */
- freg_t next_vc; /* Next VC */
- u_int filler5b[0x5d - 0x5b];
- freg_t present_slot_cnt;/* Present slot count */
- u_int filler5e[0x6a - 0x5e];
- freg_t new_desc_num; /* New descriptor number */
- freg_t new_vc; /* New VC */
- freg_t sched_tbl_ptr; /* Schedule table pointer */
- freg_t vbrwq_wptr; /* VBR wait queue write pointer */
- freg_t vbrwq_rptr; /* VBR wait queue read pointer */
- freg_t abrwq_wptr; /* ABR wait queue write pointer */
- freg_t abrwq_rptr; /* ABR wait queue read pointer */
- freg_t ubrwq_wptr; /* UBR wait queue write pointer */
- freg_t ubrwq_rptr; /* UBR wait queue read pointer */
- freg_t cbr_vc; /* CBR VC */
- freg_t vbr_sb_vc; /* VBR SB VC */
- freg_t abr_sb_vc; /* ABR SB VC */
- freg_t ubr_sb_vc; /* UBR SB VC */
- freg_t vbr_next_link; /* VBR next link */
- freg_t abr_next_link; /* ABR next link */
- freg_t ubr_next_link; /* UBR next link */
- u_int filler7a[0x7c-0x7a];
- freg_t out_rate_head; /* Out of rate head */
- u_int filler7d[0xca-0x7d]; /* pad out to full address space */
- freg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */
- freg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */
- u_int fillercc[0x100-0xcc]; /* pad out to full address space */
+ ffreg_t idlehead_high; /* Idle cell header (high) */
+ ffreg_t idlehead_low; /* Idle cell header (low) */
+ ffreg_t maxrate; /* Maximum rate */
+ ffreg_t stparms; /* Traffic Management Parameters */
+ ffreg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */
+ ffreg_t rm_type; /* */
+ u_int filler5[0x17 - 0x06];
+ ffreg_t cmd_reg; /* Command register */
+ u_int filler18[0x20 - 0x18];
+ ffreg_t cbr_base; /* CBR Pointer Base */
+ ffreg_t vbr_base; /* VBR Pointer Base */
+ ffreg_t abr_base; /* ABR Pointer Base */
+ ffreg_t ubr_base; /* UBR Pointer Base */
+ u_int filler24;
+ ffreg_t vbrwq_base; /* VBR Wait Queue Base */
+ ffreg_t abrwq_base; /* ABR Wait Queue Base */
+ ffreg_t ubrwq_base; /* UBR Wait Queue Base */
+ ffreg_t vct_base; /* Main VC Table Base */
+ ffreg_t vcte_base; /* Extended Main VC Table Base */
+ u_int filler2a[0x2C - 0x2A];
+ ffreg_t cbr_tab_beg; /* CBR Table Begin */
+ ffreg_t cbr_tab_end; /* CBR Table End */
+ ffreg_t cbr_pointer; /* CBR Pointer */
+ u_int filler2f[0x30 - 0x2F];
+ ffreg_t prq_st_adr; /* Packet Ready Queue Start Address */
+ ffreg_t prq_ed_adr; /* Packet Ready Queue End Address */
+ ffreg_t prq_rd_ptr; /* Packet Ready Queue read pointer */
+ ffreg_t prq_wr_ptr; /* Packet Ready Queue write pointer */
+ ffreg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/
+ ffreg_t tcq_ed_adr; /* Transmit Complete Queue End Address */
+ ffreg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */
+ ffreg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/
+ u_int filler38[0x40 - 0x38];
+ ffreg_t queue_base; /* Base address for PRQ and TCQ */
+ ffreg_t desc_base; /* Base address of descriptor table */
+ u_int filler42[0x45 - 0x42];
+ ffreg_t mode_reg_0; /* Mode register 0 */
+ ffreg_t mode_reg_1; /* Mode register 1 */
+ ffreg_t intr_status_reg;/* Interrupt Status register */
+ ffreg_t mask_reg; /* Mask Register */
+ ffreg_t cell_ctr_high1; /* Total cell transfer count (high) */
+ ffreg_t cell_ctr_lo1; /* Total cell transfer count (low) */
+ ffreg_t state_reg; /* Status register */
+ u_int filler4c[0x58 - 0x4c];
+ ffreg_t curr_desc_num; /* Contains the current descriptor num */
+ ffreg_t next_desc; /* Next descriptor */
+ ffreg_t next_vc; /* Next VC */
+ u_int filler5b[0x5d - 0x5b];
+ ffreg_t present_slot_cnt;/* Present slot count */
+ u_int filler5e[0x6a - 0x5e];
+ ffreg_t new_desc_num; /* New descriptor number */
+ ffreg_t new_vc; /* New VC */
+ ffreg_t sched_tbl_ptr; /* Schedule table pointer */
+ ffreg_t vbrwq_wptr; /* VBR wait queue write pointer */
+ ffreg_t vbrwq_rptr; /* VBR wait queue read pointer */
+ ffreg_t abrwq_wptr; /* ABR wait queue write pointer */
+ ffreg_t abrwq_rptr; /* ABR wait queue read pointer */
+ ffreg_t ubrwq_wptr; /* UBR wait queue write pointer */
+ ffreg_t ubrwq_rptr; /* UBR wait queue read pointer */
+ ffreg_t cbr_vc; /* CBR VC */
+ ffreg_t vbr_sb_vc; /* VBR SB VC */
+ ffreg_t abr_sb_vc; /* ABR SB VC */
+ ffreg_t ubr_sb_vc; /* UBR SB VC */
+ ffreg_t vbr_next_link; /* VBR next link */
+ ffreg_t abr_next_link; /* ABR next link */
+ ffreg_t ubr_next_link; /* UBR next link */
+ u_int filler7a[0x7c-0x7a];
+ ffreg_t out_rate_head; /* Out of rate head */
+ u_int filler7d[0xca-0x7d]; /* pad out to full address space */
+ ffreg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */
+ ffreg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */
+ u_int fillercc[0x100-0xcc]; /* pad out to full address space */
} ffredn_t;
typedef struct _rfredn_t {
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index c8b453939da2..07abd9d76f7f 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -145,6 +145,17 @@ config EXTRA_FIRMWARE_DIR
this option you can point it elsewhere, such as /lib/firmware/ or
some other directory containing the firmware files.
+config FW_LOADER_USER_HELPER
+ bool "Fallback user-helper invocation for firmware loading"
+ depends on FW_LOADER
+ default y
+ help
+ This option enables / disables the invocation of user-helper
+ (e.g. udev) for loading firmware files as a fallback after the
+ direct file loading in kernel fails. The user-mode helper is
+ no longer required unless you have a special firmware file that
+ resides in a non-standard path.
+
config DEBUG_DRIVER
bool "Driver Core verbose debug messages"
depends on DEBUG_KERNEL
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 5aa2d703d19f..4e22ce3ed73d 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -21,6 +21,7 @@ endif
obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
obj-$(CONFIG_REGMAP) += regmap/
obj-$(CONFIG_SOC_BUS) += soc.o
+obj-$(CONFIG_PINCTRL) += pinctrl.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 24eb07868344..519865b53f76 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -290,7 +290,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start,
struct device *dev;
int error = 0;
- if (!bus)
+ if (!bus || !bus->p)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
@@ -324,7 +324,7 @@ struct device *bus_find_device(struct bus_type *bus,
struct klist_iter i;
struct device *dev;
- if (!bus)
+ if (!bus || !bus->p)
return NULL;
klist_iter_init_node(&bus->p->klist_devices, &i,
@@ -700,12 +700,12 @@ int bus_add_driver(struct device_driver *drv)
if (error)
goto out_unregister;
+ klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
- klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);
error = driver_create_file(drv, &driver_attr_uevent);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 03243d4002fd..3ce845471327 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -420,8 +420,8 @@ EXPORT_SYMBOL_GPL(class_for_each_device);
* code. There's no locking restriction.
*/
struct device *class_find_device(struct class *class, struct device *start,
- void *data,
- int (*match)(struct device *, void *))
+ const void *data,
+ int (*match)(struct device *, const void *))
{
struct class_dev_iter iter;
struct device *dev;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index a235085e343c..56536f4b0f6b 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1617,9 +1617,9 @@ struct device *device_create(struct class *class, struct device *parent,
}
EXPORT_SYMBOL_GPL(device_create);
-static int __match_devt(struct device *dev, void *data)
+static int __match_devt(struct device *dev, const void *data)
{
- dev_t *devt = data;
+ const dev_t *devt = data;
return dev->devt == *devt;
}
@@ -1685,8 +1685,6 @@ EXPORT_SYMBOL_GPL(device_destroy);
*/
int device_rename(struct device *dev, const char *new_name)
{
- char *old_class_name = NULL;
- char *new_class_name = NULL;
char *old_device_name = NULL;
int error;
@@ -1717,8 +1715,6 @@ int device_rename(struct device *dev, const char *new_name)
out:
put_device(dev);
- kfree(new_class_name);
- kfree(old_class_name);
kfree(old_device_name);
return error;
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index e3bbed8a617c..bb5645ea0282 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -24,6 +24,7 @@
#include <linux/wait.h>
#include <linux/async.h>
#include <linux/pm_runtime.h>
+#include <linux/pinctrl/devinfo.h>
#include "base.h"
#include "power/power.h"
@@ -172,6 +173,8 @@ static int deferred_probe_initcall(void)
driver_deferred_probe_enable = true;
driver_deferred_probe_trigger();
+ /* Sort as many dependencies as possible before exiting initcalls */
+ flush_workqueue(deferred_wq);
return 0;
}
late_initcall(deferred_probe_initcall);
@@ -269,6 +272,12 @@ static int really_probe(struct device *dev, struct device_driver *drv)
WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv;
+
+ /* If using pinctrl, bind pins now before probing */
+ ret = pinctrl_bind_pins(dev);
+ if (ret)
+ goto probe_failed;
+
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index a3f79c495a41..ff5b745c4705 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -134,15 +134,14 @@ EXPORT_SYMBOL_GPL(dma_buf_export);
*/
int dma_buf_fd(struct dma_buf *dmabuf, int flags)
{
- int error, fd;
+ int fd;
if (!dmabuf || !dmabuf->file)
return -EINVAL;
- error = get_unused_fd_flags(flags);
- if (error < 0)
- return error;
- fd = error;
+ fd = get_unused_fd_flags(flags);
+ if (fd < 0)
+ return fd;
fd_install(fd, dmabuf->file);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b392b353be39..4a223fedcd73 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -88,11 +88,6 @@ enum {
FW_STATUS_ABORT,
};
-enum fw_buf_fmt {
- VMALLOC_BUF, /* used in direct loading */
- PAGE_BUF, /* used in loading via userspace */
-};
-
static int loading_timeout = 60; /* In seconds */
static inline long firmware_loading_timeout(void)
@@ -128,12 +123,14 @@ struct firmware_buf {
struct completion completion;
struct firmware_cache *fwc;
unsigned long status;
- enum fw_buf_fmt fmt;
void *data;
size_t size;
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+ bool is_paged_buf;
struct page **pages;
int nr_pages;
int page_array_size;
+#endif
char fw_id[];
};
@@ -142,14 +139,6 @@ struct fw_cache_entry {
char name[];
};
-struct firmware_priv {
- struct delayed_work timeout_work;
- bool nowait;
- struct device dev;
- struct firmware_buf *buf;
- struct firmware *fw;
-};
-
struct fw_name_devm {
unsigned long magic;
char name[];
@@ -182,7 +171,6 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
strcpy(buf->fw_id, fw_name);
buf->fwc = fwc;
init_completion(&buf->completion);
- buf->fmt = VMALLOC_BUF;
pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf);
@@ -240,7 +228,6 @@ static void __fw_free_buf(struct kref *ref)
{
struct firmware_buf *buf = to_fwbuf(ref);
struct firmware_cache *fwc = buf->fwc;
- int i;
pr_debug("%s: fw-%s buf=%p data=%p size=%u\n",
__func__, buf->fw_id, buf, buf->data,
@@ -249,13 +236,15 @@ static void __fw_free_buf(struct kref *ref)
list_del(&buf->list);
spin_unlock(&fwc->lock);
-
- if (buf->fmt == PAGE_BUF) {
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+ if (buf->is_paged_buf) {
+ int i;
vunmap(buf->data);
for (i = 0; i < buf->nr_pages; i++)
__free_page(buf->pages[i]);
kfree(buf->pages);
} else
+#endif
vfree(buf->data);
kfree(buf);
}
@@ -319,7 +308,8 @@ static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf
return true;
}
-static bool fw_get_filesystem_firmware(struct firmware_buf *buf)
+static bool fw_get_filesystem_firmware(struct device *device,
+ struct firmware_buf *buf)
{
int i;
bool success = false;
@@ -343,9 +333,114 @@ static bool fw_get_filesystem_firmware(struct firmware_buf *buf)
break;
}
__putname(path);
+
+ if (success) {
+ dev_dbg(device, "firmware: direct-loading firmware %s\n",
+ buf->fw_id);
+ mutex_lock(&fw_lock);
+ set_bit(FW_STATUS_DONE, &buf->status);
+ complete_all(&buf->completion);
+ mutex_unlock(&fw_lock);
+ }
+
return success;
}
+/* firmware holds the ownership of pages */
+static void firmware_free_data(const struct firmware *fw)
+{
+ /* Loaded directly? */
+ if (!fw->priv) {
+ vfree(fw->data);
+ return;
+ }
+ fw_free_buf(fw->priv);
+}
+
+/* store the pages buffer info firmware from buf */
+static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw)
+{
+ fw->priv = buf;
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+ fw->pages = buf->pages;
+#endif
+ fw->size = buf->size;
+ fw->data = buf->data;
+
+ pr_debug("%s: fw-%s buf=%p data=%p size=%u\n",
+ __func__, buf->fw_id, buf, buf->data,
+ (unsigned int)buf->size);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void fw_name_devm_release(struct device *dev, void *res)
+{
+ struct fw_name_devm *fwn = res;
+
+ if (fwn->magic == (unsigned long)&fw_cache)
+ pr_debug("%s: fw_name-%s devm-%p released\n",
+ __func__, fwn->name, res);
+}
+
+static int fw_devm_match(struct device *dev, void *res,
+ void *match_data)
+{
+ struct fw_name_devm *fwn = res;
+
+ return (fwn->magic == (unsigned long)&fw_cache) &&
+ !strcmp(fwn->name, match_data);
+}
+
+static struct fw_name_devm *fw_find_devm_name(struct device *dev,
+ const char *name)
+{
+ struct fw_name_devm *fwn;
+
+ fwn = devres_find(dev, fw_name_devm_release,
+ fw_devm_match, (void *)name);
+ return fwn;
+}
+
+/* add firmware name into devres list */
+static int fw_add_devm_name(struct device *dev, const char *name)
+{
+ struct fw_name_devm *fwn;
+
+ fwn = fw_find_devm_name(dev, name);
+ if (fwn)
+ return 1;
+
+ fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) +
+ strlen(name) + 1, GFP_KERNEL);
+ if (!fwn)
+ return -ENOMEM;
+
+ fwn->magic = (unsigned long)&fw_cache;
+ strcpy(fwn->name, name);
+ devres_add(dev, fwn);
+
+ return 0;
+}
+#else
+static int fw_add_devm_name(struct device *dev, const char *name)
+{
+ return 0;
+}
+#endif
+
+
+/*
+ * user-mode helper code
+ */
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+struct firmware_priv {
+ struct delayed_work timeout_work;
+ bool nowait;
+ struct device dev;
+ struct firmware_buf *buf;
+ struct firmware *fw;
+};
+
static struct firmware_priv *to_firmware_priv(struct device *dev)
{
return container_of(dev, struct firmware_priv, dev);
@@ -359,6 +454,9 @@ static void fw_load_abort(struct firmware_priv *fw_priv)
complete_all(&buf->completion);
}
+#define is_fw_load_aborted(buf) \
+ test_bit(FW_STATUS_ABORT, &(buf)->status)
+
static ssize_t firmware_timeout_show(struct class *class,
struct class_attribute *attr,
char *buf)
@@ -435,17 +533,6 @@ static ssize_t firmware_loading_show(struct device *dev,
return sprintf(buf, "%d\n", loading);
}
-/* firmware holds the ownership of pages */
-static void firmware_free_data(const struct firmware *fw)
-{
- /* Loaded directly? */
- if (!fw->priv) {
- vfree(fw->data);
- return;
- }
- fw_free_buf(fw->priv);
-}
-
/* Some architectures don't have PAGE_KERNEL_RO */
#ifndef PAGE_KERNEL_RO
#define PAGE_KERNEL_RO PAGE_KERNEL
@@ -454,7 +541,7 @@ static void firmware_free_data(const struct firmware *fw)
/* one pages buffer should be mapped/unmapped only once */
static int fw_map_pages_buf(struct firmware_buf *buf)
{
- if (buf->fmt != PAGE_BUF)
+ if (!buf->is_paged_buf)
return 0;
if (buf->data)
@@ -727,171 +814,16 @@ exit:
return fw_priv;
}
-/* store the pages buffer info firmware from buf */
-static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw)
-{
- fw->priv = buf;
- fw->pages = buf->pages;
- fw->size = buf->size;
- fw->data = buf->data;
-
- pr_debug("%s: fw-%s buf=%p data=%p size=%u\n",
- __func__, buf->fw_id, buf, buf->data,
- (unsigned int)buf->size);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static void fw_name_devm_release(struct device *dev, void *res)
-{
- struct fw_name_devm *fwn = res;
-
- if (fwn->magic == (unsigned long)&fw_cache)
- pr_debug("%s: fw_name-%s devm-%p released\n",
- __func__, fwn->name, res);
-}
-
-static int fw_devm_match(struct device *dev, void *res,
- void *match_data)
-{
- struct fw_name_devm *fwn = res;
-
- return (fwn->magic == (unsigned long)&fw_cache) &&
- !strcmp(fwn->name, match_data);
-}
-
-static struct fw_name_devm *fw_find_devm_name(struct device *dev,
- const char *name)
-{
- struct fw_name_devm *fwn;
-
- fwn = devres_find(dev, fw_name_devm_release,
- fw_devm_match, (void *)name);
- return fwn;
-}
-
-/* add firmware name into devres list */
-static int fw_add_devm_name(struct device *dev, const char *name)
-{
- struct fw_name_devm *fwn;
-
- fwn = fw_find_devm_name(dev, name);
- if (fwn)
- return 1;
-
- fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) +
- strlen(name) + 1, GFP_KERNEL);
- if (!fwn)
- return -ENOMEM;
-
- fwn->magic = (unsigned long)&fw_cache;
- strcpy(fwn->name, name);
- devres_add(dev, fwn);
-
- return 0;
-}
-#else
-static int fw_add_devm_name(struct device *dev, const char *name)
-{
- return 0;
-}
-#endif
-
-static void _request_firmware_cleanup(const struct firmware **firmware_p)
-{
- release_firmware(*firmware_p);
- *firmware_p = NULL;
-}
-
-static struct firmware_priv *
-_request_firmware_prepare(const struct firmware **firmware_p, const char *name,
- struct device *device, bool uevent, bool nowait)
-{
- struct firmware *firmware;
- struct firmware_priv *fw_priv = NULL;
- struct firmware_buf *buf;
- int ret;
-
- if (!firmware_p)
- return ERR_PTR(-EINVAL);
-
- *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
- if (!firmware) {
- dev_err(device, "%s: kmalloc(struct firmware) failed\n",
- __func__);
- return ERR_PTR(-ENOMEM);
- }
-
- if (fw_get_builtin_firmware(firmware, name)) {
- dev_dbg(device, "firmware: using built-in firmware %s\n", name);
- return NULL;
- }
-
- ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf);
- if (!ret)
- fw_priv = fw_create_instance(firmware, name, device,
- uevent, nowait);
-
- if (IS_ERR(fw_priv) || ret < 0) {
- kfree(firmware);
- *firmware_p = NULL;
- return ERR_PTR(-ENOMEM);
- } else if (fw_priv) {
- fw_priv->buf = buf;
-
- /*
- * bind with 'buf' now to avoid warning in failure path
- * of requesting firmware.
- */
- firmware->priv = buf;
- return fw_priv;
- }
-
- /* share the cached buf, which is inprogessing or completed */
- check_status:
- mutex_lock(&fw_lock);
- if (test_bit(FW_STATUS_ABORT, &buf->status)) {
- fw_priv = ERR_PTR(-ENOENT);
- firmware->priv = buf;
- _request_firmware_cleanup(firmware_p);
- goto exit;
- } else if (test_bit(FW_STATUS_DONE, &buf->status)) {
- fw_priv = NULL;
- fw_set_page_data(buf, firmware);
- goto exit;
- }
- mutex_unlock(&fw_lock);
- wait_for_completion(&buf->completion);
- goto check_status;
-
-exit:
- mutex_unlock(&fw_lock);
- return fw_priv;
-}
-
+/* load a firmware via user helper */
static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
long timeout)
{
int retval = 0;
struct device *f_dev = &fw_priv->dev;
struct firmware_buf *buf = fw_priv->buf;
- struct firmware_cache *fwc = &fw_cache;
- int direct_load = 0;
-
- /* try direct loading from fs first */
- if (fw_get_filesystem_firmware(buf)) {
- dev_dbg(f_dev->parent, "firmware: direct-loading"
- " firmware %s\n", buf->fw_id);
-
- mutex_lock(&fw_lock);
- set_bit(FW_STATUS_DONE, &buf->status);
- mutex_unlock(&fw_lock);
- complete_all(&buf->completion);
- direct_load = 1;
- goto handle_fw;
- }
/* fall back on userspace loading */
- buf->fmt = PAGE_BUF;
+ buf->is_paged_buf = true;
dev_set_uevent_suppress(f_dev, true);
@@ -929,47 +861,196 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
cancel_delayed_work_sync(&fw_priv->timeout_work);
-handle_fw:
+ fw_priv->buf = NULL;
+
+ device_remove_file(f_dev, &dev_attr_loading);
+err_del_bin_attr:
+ device_remove_bin_file(f_dev, &firmware_attr_data);
+err_del_dev:
+ device_del(f_dev);
+err_put_dev:
+ put_device(f_dev);
+ return retval;
+}
+
+static int fw_load_from_user_helper(struct firmware *firmware,
+ const char *name, struct device *device,
+ bool uevent, bool nowait, long timeout)
+{
+ struct firmware_priv *fw_priv;
+
+ fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
+ if (IS_ERR(fw_priv))
+ return PTR_ERR(fw_priv);
+
+ fw_priv->buf = firmware->priv;
+ return _request_firmware_load(fw_priv, uevent, timeout);
+}
+#else /* CONFIG_FW_LOADER_USER_HELPER */
+static inline int
+fw_load_from_user_helper(struct firmware *firmware, const char *name,
+ struct device *device, bool uevent, bool nowait,
+ long timeout)
+{
+ return -ENOENT;
+}
+
+/* No abort during direct loading */
+#define is_fw_load_aborted(buf) false
+
+#endif /* CONFIG_FW_LOADER_USER_HELPER */
+
+
+/* wait until the shared firmware_buf becomes ready (or error) */
+static int sync_cached_firmware_buf(struct firmware_buf *buf)
+{
+ int ret = 0;
+
+ mutex_lock(&fw_lock);
+ while (!test_bit(FW_STATUS_DONE, &buf->status)) {
+ if (is_fw_load_aborted(buf)) {
+ ret = -ENOENT;
+ break;
+ }
+ mutex_unlock(&fw_lock);
+ wait_for_completion(&buf->completion);
+ mutex_lock(&fw_lock);
+ }
+ mutex_unlock(&fw_lock);
+ return ret;
+}
+
+/* prepare firmware and firmware_buf structs;
+ * return 0 if a firmware is already assigned, 1 if need to load one,
+ * or a negative error code
+ */
+static int
+_request_firmware_prepare(struct firmware **firmware_p, const char *name,
+ struct device *device)
+{
+ struct firmware *firmware;
+ struct firmware_buf *buf;
+ int ret;
+
+ *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
+ if (!firmware) {
+ dev_err(device, "%s: kmalloc(struct firmware) failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ if (fw_get_builtin_firmware(firmware, name)) {
+ dev_dbg(device, "firmware: using built-in firmware %s\n", name);
+ return 0; /* assigned */
+ }
+
+ ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf);
+
+ /*
+ * bind with 'buf' now to avoid warning in failure path
+ * of requesting firmware.
+ */
+ firmware->priv = buf;
+
+ if (ret > 0) {
+ ret = sync_cached_firmware_buf(buf);
+ if (!ret) {
+ fw_set_page_data(buf, firmware);
+ return 0; /* assigned */
+ }
+ }
+
+ if (ret < 0)
+ return ret;
+ return 1; /* need to load */
+}
+
+static int assign_firmware_buf(struct firmware *fw, struct device *device)
+{
+ struct firmware_buf *buf = fw->priv;
+
mutex_lock(&fw_lock);
- if (!buf->size || test_bit(FW_STATUS_ABORT, &buf->status))
- retval = -ENOENT;
+ if (!buf->size || is_fw_load_aborted(buf)) {
+ mutex_unlock(&fw_lock);
+ return -ENOENT;
+ }
/*
* add firmware name into devres list so that we can auto cache
* and uncache firmware for device.
*
- * f_dev->parent may has been deleted already, but the problem
+ * device may has been deleted already, but the problem
* should be fixed in devres or driver core.
*/
- if (!retval && f_dev->parent)
- fw_add_devm_name(f_dev->parent, buf->fw_id);
+ if (device)
+ fw_add_devm_name(device, buf->fw_id);
/*
* After caching firmware image is started, let it piggyback
* on request firmware.
*/
- if (!retval && fwc->state == FW_LOADER_START_CACHE) {
+ if (buf->fwc->state == FW_LOADER_START_CACHE) {
if (fw_cache_piggyback_on_request(buf->fw_id))
kref_get(&buf->ref);
}
/* pass the pages buffer to driver at the last minute */
- fw_set_page_data(buf, fw_priv->fw);
-
- fw_priv->buf = NULL;
+ fw_set_page_data(buf, fw);
mutex_unlock(&fw_lock);
+ return 0;
+}
- if (direct_load)
- goto err_put_dev;
+/* called from request_firmware() and request_firmware_work_func() */
+static int
+_request_firmware(const struct firmware **firmware_p, const char *name,
+ struct device *device, bool uevent, bool nowait)
+{
+ struct firmware *fw;
+ long timeout;
+ int ret;
- device_remove_file(f_dev, &dev_attr_loading);
-err_del_bin_attr:
- device_remove_bin_file(f_dev, &firmware_attr_data);
-err_del_dev:
- device_del(f_dev);
-err_put_dev:
- put_device(f_dev);
- return retval;
+ if (!firmware_p)
+ return -EINVAL;
+
+ ret = _request_firmware_prepare(&fw, name, device);
+ if (ret <= 0) /* error or already assigned */
+ goto out;
+
+ ret = 0;
+ timeout = firmware_loading_timeout();
+ if (nowait) {
+ timeout = usermodehelper_read_lock_wait(timeout);
+ if (!timeout) {
+ dev_dbg(device, "firmware: %s loading timed out\n",
+ name);
+ ret = -EBUSY;
+ goto out;
+ }
+ } else {
+ ret = usermodehelper_read_trylock();
+ if (WARN_ON(ret)) {
+ dev_err(device, "firmware: %s will not be loaded\n",
+ name);
+ goto out;
+ }
+ }
+
+ if (!fw_get_filesystem_firmware(device, fw->priv))
+ ret = fw_load_from_user_helper(fw, name, device,
+ uevent, nowait, timeout);
+ if (!ret)
+ ret = assign_firmware_buf(fw, device);
+
+ usermodehelper_read_unlock();
+
+ out:
+ if (ret < 0) {
+ release_firmware(fw);
+ fw = NULL;
+ }
+
+ *firmware_p = fw;
+ return ret;
}
/**
@@ -996,26 +1077,7 @@ int
request_firmware(const struct firmware **firmware_p, const char *name,
struct device *device)
{
- struct firmware_priv *fw_priv;
- int ret;
-
- fw_priv = _request_firmware_prepare(firmware_p, name, device, true,
- false);
- if (IS_ERR_OR_NULL(fw_priv))
- return PTR_RET(fw_priv);
-
- ret = usermodehelper_read_trylock();
- if (WARN_ON(ret)) {
- dev_err(device, "firmware: %s will not be loaded\n", name);
- } else {
- ret = _request_firmware_load(fw_priv, true,
- firmware_loading_timeout());
- usermodehelper_read_unlock();
- }
- if (ret)
- _request_firmware_cleanup(firmware_p);
-
- return ret;
+ return _request_firmware(firmware_p, name, device, true, false);
}
/**
@@ -1046,33 +1108,13 @@ static void request_firmware_work_func(struct work_struct *work)
{
struct firmware_work *fw_work;
const struct firmware *fw;
- struct firmware_priv *fw_priv;
- long timeout;
- int ret;
fw_work = container_of(work, struct firmware_work, work);
- fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
- fw_work->uevent, true);
- if (IS_ERR_OR_NULL(fw_priv)) {
- ret = PTR_RET(fw_priv);
- goto out;
- }
-
- timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
- if (timeout) {
- ret = _request_firmware_load(fw_priv, fw_work->uevent, timeout);
- usermodehelper_read_unlock();
- } else {
- dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
- fw_work->name);
- ret = -EAGAIN;
- }
- if (ret)
- _request_firmware_cleanup(&fw);
- out:
+ _request_firmware(&fw, fw_work->name, fw_work->device,
+ fw_work->uevent, true);
fw_work->cont(fw, fw_work->context);
- put_device(fw_work->device);
+ put_device(fw_work->device); /* taken in request_firmware_nowait() */
module_put(fw_work->module);
kfree(fw_work);
@@ -1474,7 +1516,11 @@ static void __init fw_cache_init(void)
static int __init firmware_class_init(void)
{
fw_cache_init();
+#ifdef CONFIG_FW_LOADER_USER_HELPER
return class_register(&firmware_class);
+#else
+ return 0;
+#endif
}
static void __exit firmware_class_exit(void)
@@ -1483,7 +1529,9 @@ static void __exit firmware_class_exit(void)
unregister_syscore_ops(&fw_syscore_ops);
unregister_pm_notifier(&fw_cache.pm_notify);
#endif
+#ifdef CONFIG_FW_LOADER_USER_HELPER
class_unregister(&firmware_class);
+#endif
}
fs_initcall(firmware_class_init);
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 987604d56c83..a51007b79032 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -494,8 +494,8 @@ store_hard_offline_page(struct device *dev,
return ret ? ret : count;
}
-static DEVICE_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page);
-static DEVICE_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page);
+static DEVICE_ATTR(soft_offline_page, S_IWUSR, NULL, store_soft_offline_page);
+static DEVICE_ATTR(hard_offline_page, S_IWUSR, NULL, store_hard_offline_page);
static __init int memory_fail_init(void)
{
@@ -693,6 +693,12 @@ int offline_memory_block(struct memory_block *mem)
return ret;
}
+/* return true if the memory block is offlined, otherwise, return false */
+bool is_memblock_offlined(struct memory_block *mem)
+{
+ return mem->state == MEM_OFFLINE;
+}
+
/*
* Initialize the sysfs support for memory devices...
*/
diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c
new file mode 100644
index 000000000000..67a274e86727
--- /dev/null
+++ b/drivers/base/pinctrl.c
@@ -0,0 +1,69 @@
+/*
+ * Driver core interface to the pinctrl subsystem.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * Based on bits of regulator core, gpio core and clk core
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/device.h>
+#include <linux/pinctrl/devinfo.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/slab.h>
+
+/**
+ * pinctrl_bind_pins() - called by the device core before probe
+ * @dev: the device that is just about to probe
+ */
+int pinctrl_bind_pins(struct device *dev)
+{
+ int ret;
+
+ dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
+ if (!dev->pins)
+ return -ENOMEM;
+
+ dev->pins->p = devm_pinctrl_get(dev);
+ if (IS_ERR(dev->pins->p)) {
+ dev_dbg(dev, "no pinctrl handle\n");
+ ret = PTR_ERR(dev->pins->p);
+ goto cleanup_alloc;
+ }
+
+ dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
+ PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(dev->pins->default_state)) {
+ dev_dbg(dev, "no default pinctrl state\n");
+ ret = 0;
+ goto cleanup_get;
+ }
+
+ ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state);
+ if (ret) {
+ dev_dbg(dev, "failed to activate default pinctrl state\n");
+ goto cleanup_get;
+ }
+
+ return 0;
+
+ /*
+ * If no pinctrl handle or default state was found for this device,
+ * let's explicitly free the pin container in the device, there is
+ * no point in keeping it around.
+ */
+cleanup_get:
+ devm_pinctrl_put(dev->pins->p);
+cleanup_alloc:
+ devm_kfree(dev, dev->pins);
+ dev->pins = NULL;
+
+ /* Only return deferrals */
+ if (ret != -EPROBE_DEFER)
+ ret = 0;
+
+ return ret;
+}
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index acc3a8ded29d..9a6b05a35603 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -433,8 +433,7 @@ static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
*/
void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
{
- if (!work_pending(&genpd->power_off_work))
- queue_work(pm_wq, &genpd->power_off_work);
+ queue_work(pm_wq, &genpd->power_off_work);
}
/**
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 50b2831e027d..32ee0fc7ea54 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -162,7 +162,7 @@ unsigned long opp_get_voltage(struct opp *opp)
return v;
}
-EXPORT_SYMBOL(opp_get_voltage);
+EXPORT_SYMBOL_GPL(opp_get_voltage);
/**
* opp_get_freq() - Gets the frequency corresponding to an available opp
@@ -192,7 +192,7 @@ unsigned long opp_get_freq(struct opp *opp)
return f;
}
-EXPORT_SYMBOL(opp_get_freq);
+EXPORT_SYMBOL_GPL(opp_get_freq);
/**
* opp_get_opp_count() - Get number of opps available in the opp list
@@ -225,7 +225,7 @@ int opp_get_opp_count(struct device *dev)
return count;
}
-EXPORT_SYMBOL(opp_get_opp_count);
+EXPORT_SYMBOL_GPL(opp_get_opp_count);
/**
* opp_find_freq_exact() - search for an exact frequency
@@ -276,7 +276,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
return opp;
}
-EXPORT_SYMBOL(opp_find_freq_exact);
+EXPORT_SYMBOL_GPL(opp_find_freq_exact);
/**
* opp_find_freq_ceil() - Search for an rounded ceil freq
@@ -323,7 +323,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
return opp;
}
-EXPORT_SYMBOL(opp_find_freq_ceil);
+EXPORT_SYMBOL_GPL(opp_find_freq_ceil);
/**
* opp_find_freq_floor() - Search for a rounded floor freq
@@ -374,7 +374,7 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
return opp;
}
-EXPORT_SYMBOL(opp_find_freq_floor);
+EXPORT_SYMBOL_GPL(opp_find_freq_floor);
/**
* opp_add() - Add an OPP table from a table definitions
@@ -568,7 +568,7 @@ int opp_enable(struct device *dev, unsigned long freq)
{
return opp_set_availability(dev, freq, true);
}
-EXPORT_SYMBOL(opp_enable);
+EXPORT_SYMBOL_GPL(opp_enable);
/**
* opp_disable() - Disable a specific OPP
@@ -590,7 +590,7 @@ int opp_disable(struct device *dev, unsigned long freq)
{
return opp_set_availability(dev, freq, false);
}
-EXPORT_SYMBOL(opp_disable);
+EXPORT_SYMBOL_GPL(opp_disable);
#ifdef CONFIG_CPU_FREQ
/**
@@ -661,6 +661,7 @@ int opp_init_cpufreq_table(struct device *dev,
return 0;
}
+EXPORT_SYMBOL_GPL(opp_init_cpufreq_table);
/**
* opp_free_cpufreq_table() - free the cpufreq table
@@ -678,6 +679,7 @@ void opp_free_cpufreq_table(struct device *dev,
kfree(*table);
*table = NULL;
}
+EXPORT_SYMBOL_GPL(opp_free_cpufreq_table);
#endif /* CONFIG_CPU_FREQ */
/**
@@ -738,4 +740,5 @@ int of_init_opp_table(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(of_init_opp_table);
#endif
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index d21349544ce5..3d4d1f8aac5c 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -91,6 +91,7 @@ enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
return ret;
}
+EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
/**
* __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 3148b10dc2e5..1244930e3d7a 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -124,6 +124,76 @@ unsigned long pm_runtime_autosuspend_expiration(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration);
+static int dev_memalloc_noio(struct device *dev, void *data)
+{
+ return dev->power.memalloc_noio;
+}
+
+/*
+ * pm_runtime_set_memalloc_noio - Set a device's memalloc_noio flag.
+ * @dev: Device to handle.
+ * @enable: True for setting the flag and False for clearing the flag.
+ *
+ * Set the flag for all devices in the path from the device to the
+ * root device in the device tree if @enable is true, otherwise clear
+ * the flag for devices in the path whose siblings don't set the flag.
+ *
+ * The function should only be called by block device, or network
+ * device driver for solving the deadlock problem during runtime
+ * resume/suspend:
+ *
+ * If memory allocation with GFP_KERNEL is called inside runtime
+ * resume/suspend callback of any one of its ancestors(or the
+ * block device itself), the deadlock may be triggered inside the
+ * memory allocation since it might not complete until the block
+ * device becomes active and the involed page I/O finishes. The
+ * situation is pointed out first by Alan Stern. Network device
+ * are involved in iSCSI kind of situation.
+ *
+ * The lock of dev_hotplug_mutex is held in the function for handling
+ * hotplug race because pm_runtime_set_memalloc_noio() may be called
+ * in async probe().
+ *
+ * The function should be called between device_add() and device_del()
+ * on the affected device(block/network device).
+ */
+void pm_runtime_set_memalloc_noio(struct device *dev, bool enable)
+{
+ static DEFINE_MUTEX(dev_hotplug_mutex);
+
+ mutex_lock(&dev_hotplug_mutex);
+ for (;;) {
+ bool enabled;
+
+ /* hold power lock since bitfield is not SMP-safe. */
+ spin_lock_irq(&dev->power.lock);
+ enabled = dev->power.memalloc_noio;
+ dev->power.memalloc_noio = enable;
+ spin_unlock_irq(&dev->power.lock);
+
+ /*
+ * not need to enable ancestors any more if the device
+ * has been enabled.
+ */
+ if (enabled && enable)
+ break;
+
+ dev = dev->parent;
+
+ /*
+ * clear flag of the parent device only if all the
+ * children don't set the flag because ancestor's
+ * flag was set by any one of the descendants.
+ */
+ if (!dev || (!enable &&
+ device_for_each_child(dev, NULL,
+ dev_memalloc_noio)))
+ break;
+ }
+ mutex_unlock(&dev_hotplug_mutex);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_set_memalloc_noio);
+
/**
* rpm_check_suspend_allowed - Test whether a device may be suspended.
* @dev: Device to test.
@@ -278,7 +348,24 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
if (!cb)
return -ENOSYS;
- retval = __rpm_callback(cb, dev);
+ if (dev->power.memalloc_noio) {
+ unsigned int noio_flag;
+
+ /*
+ * Deadlock might be caused if memory allocation with
+ * GFP_KERNEL happens inside runtime_suspend and
+ * runtime_resume callbacks of one block device's
+ * ancestor or the block device itself. Network
+ * device might be thought as part of iSCSI block
+ * device, so network device and its ancestor should
+ * be marked as memalloc_noio too.
+ */
+ noio_flag = memalloc_noio_save();
+ retval = __rpm_callback(cb, dev);
+ memalloc_noio_restore(noio_flag);
+ } else {
+ retval = __rpm_callback(cb, dev);
+ }
dev->power.runtime_error = retval;
return retval != -EACCES ? retval : -EIO;
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index e6ee5e80e546..79715e7fa43e 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -382,6 +382,12 @@ static void wakeup_source_activate(struct wakeup_source *ws)
{
unsigned int cec;
+ /*
+ * active wakeup source should bring the system
+ * out of PM_SUSPEND_FREEZE state
+ */
+ freeze_wake();
+
ws->active = true;
ws->active_count++;
ws->last_time = ktime_get();
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 5e75d1b683e2..cf129980abd0 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_REGMAP) += regmap.o regcache.o
-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o
+obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 401d1919635a..5a22bd33ce3d 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -16,6 +16,7 @@
#include <linux/regmap.h>
#include <linux/fs.h>
#include <linux/list.h>
+#include <linux/wait.h>
struct regmap;
struct regcache_ops;
@@ -25,6 +26,7 @@ struct regmap_debugfs_off_cache {
off_t min;
off_t max;
unsigned int base_reg;
+ unsigned int max_reg;
};
struct regmap_format {
@@ -39,6 +41,13 @@ struct regmap_format {
unsigned int (*parse_val)(void *buf);
};
+struct regmap_async {
+ struct list_head list;
+ struct work_struct cleanup;
+ struct regmap *map;
+ void *work_buf;
+};
+
struct regmap {
struct mutex mutex;
spinlock_t spinlock;
@@ -53,6 +62,11 @@ struct regmap {
void *bus_context;
const char *name;
+ spinlock_t async_lock;
+ wait_queue_head_t async_waitq;
+ struct list_head async_list;
+ int async_ret;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
const char *debugfs_name;
@@ -74,6 +88,11 @@ struct regmap {
const struct regmap_access_table *volatile_table;
const struct regmap_access_table *precious_table;
+ int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
+ int (*reg_write)(void *context, unsigned int reg, unsigned int val);
+
+ bool defer_caching;
+
u8 read_flag_mask;
u8 write_flag_mask;
@@ -175,7 +194,10 @@ bool regcache_set_val(void *base, unsigned int idx,
unsigned int val, unsigned int word_size);
int regcache_lookup_reg(struct regmap *map, unsigned int reg);
+void regmap_async_complete_cb(struct regmap_async *async, int ret);
+
extern struct regcache_ops regcache_rbtree_ops;
extern struct regcache_ops regcache_lzo_ops;
+extern struct regcache_ops regcache_flat_ops;
#endif
diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c
new file mode 100644
index 000000000000..d9762e41959b
--- /dev/null
+++ b/drivers/base/regmap/regcache-flat.c
@@ -0,0 +1,72 @@
+/*
+ * Register cache access API - flat caching support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/seq_file.h>
+
+#include "internal.h"
+
+static int regcache_flat_init(struct regmap *map)
+{
+ int i;
+ unsigned int *cache;
+
+ map->cache = kzalloc(sizeof(unsigned int) * (map->max_register + 1),
+ GFP_KERNEL);
+ if (!map->cache)
+ return -ENOMEM;
+
+ cache = map->cache;
+
+ for (i = 0; i < map->num_reg_defaults; i++)
+ cache[map->reg_defaults[i].reg] = map->reg_defaults[i].def;
+
+ return 0;
+}
+
+static int regcache_flat_exit(struct regmap *map)
+{
+ kfree(map->cache);
+ map->cache = NULL;
+
+ return 0;
+}
+
+static int regcache_flat_read(struct regmap *map,
+ unsigned int reg, unsigned int *value)
+{
+ unsigned int *cache = map->cache;
+
+ *value = cache[reg];
+
+ return 0;
+}
+
+static int regcache_flat_write(struct regmap *map, unsigned int reg,
+ unsigned int value)
+{
+ unsigned int *cache = map->cache;
+
+ cache[reg] = value;
+
+ return 0;
+}
+
+struct regcache_ops regcache_flat_ops = {
+ .type = REGCACHE_FLAT,
+ .name = "flat",
+ .init = regcache_flat_init,
+ .exit = regcache_flat_exit,
+ .read = regcache_flat_read,
+ .write = regcache_flat_write,
+};
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 835883bda977..e69ff3e4742c 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -22,6 +22,7 @@
static const struct regcache_ops *cache_types[] = {
&regcache_rbtree_ops,
&regcache_lzo_ops,
+ &regcache_flat_ops,
};
static int regcache_hw_init(struct regmap *map)
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index d9a6c94ce423..81d6f605c92e 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -81,6 +81,8 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
struct regmap_debugfs_off_cache *c = NULL;
loff_t p = 0;
unsigned int i, ret;
+ unsigned int fpos_offset;
+ unsigned int reg_offset;
/*
* If we don't have a cache build one so we don't have to do a
@@ -93,6 +95,9 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
regmap_precious(map, i)) {
if (c) {
c->max = p - 1;
+ fpos_offset = c->max - c->min;
+ reg_offset = fpos_offset / map->debugfs_tot_len;
+ c->max_reg = c->base_reg + reg_offset;
list_add_tail(&c->list,
&map->debugfs_off_cache);
c = NULL;
@@ -119,6 +124,9 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
/* Close the last entry off if we didn't scan beyond it */
if (c) {
c->max = p - 1;
+ fpos_offset = c->max - c->min;
+ reg_offset = fpos_offset / map->debugfs_tot_len;
+ c->max_reg = c->base_reg + reg_offset;
list_add_tail(&c->list,
&map->debugfs_off_cache);
}
@@ -128,25 +136,38 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
* allocate and we should never be in this code if there are
* no registers at all.
*/
- if (list_empty(&map->debugfs_off_cache)) {
- WARN_ON(list_empty(&map->debugfs_off_cache));
- return base;
- }
+ WARN_ON(list_empty(&map->debugfs_off_cache));
+ ret = base;
- /* Find the relevant block */
+ /* Find the relevant block:offset */
list_for_each_entry(c, &map->debugfs_off_cache, list) {
if (from >= c->min && from <= c->max) {
- *pos = c->min;
- return c->base_reg;
+ fpos_offset = from - c->min;
+ reg_offset = fpos_offset / map->debugfs_tot_len;
+ *pos = c->min + (reg_offset * map->debugfs_tot_len);
+ return c->base_reg + reg_offset;
}
- *pos = c->min;
- ret = c->base_reg;
+ *pos = c->max;
+ ret = c->max_reg;
}
return ret;
}
+static inline void regmap_calc_tot_len(struct regmap *map,
+ void *buf, size_t count)
+{
+ /* Calculate the length of a fixed format */
+ if (!map->debugfs_tot_len) {
+ map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
+ buf, count);
+ map->debugfs_val_len = 2 * map->format.val_bytes;
+ map->debugfs_tot_len = map->debugfs_reg_len +
+ map->debugfs_val_len + 3; /* : \n */
+ }
+}
+
static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
unsigned int to, char __user *user_buf,
size_t count, loff_t *ppos)
@@ -165,14 +186,7 @@ static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
if (!buf)
return -ENOMEM;
- /* Calculate the length of a fixed format */
- if (!map->debugfs_tot_len) {
- map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
- buf, count);
- map->debugfs_val_len = 2 * map->format.val_bytes;
- map->debugfs_tot_len = map->debugfs_reg_len +
- map->debugfs_val_len + 3; /* : \n */
- }
+ regmap_calc_tot_len(map, buf, count);
/* Work out which register we're starting at */
start_reg = regmap_debugfs_get_dump_start(map, from, *ppos, &p);
@@ -187,7 +201,7 @@ static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
/* If we're in the region the user is trying to read */
if (p >= *ppos) {
/* ...but not beyond it */
- if (buf_pos + 1 + map->debugfs_tot_len >= count)
+ if (buf_pos + map->debugfs_tot_len > count)
break;
/* Format the register */
@@ -265,7 +279,7 @@ static ssize_t regmap_map_write_file(struct file *file,
return -EINVAL;
/* Userspace has been fiddling around behind the kernel's back */
- add_taint(TAINT_USER);
+ add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE);
regmap_write(map, reg, value);
return buf_size;
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 5972ad958544..4706c63d0bc6 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -34,6 +34,7 @@ struct regmap_irq_chip_data {
int irq;
int wake_count;
+ void *status_reg_buf;
unsigned int *status_buf;
unsigned int *mask_buf;
unsigned int *mask_buf_def;
@@ -87,6 +88,23 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
if (ret != 0)
dev_err(d->map->dev, "Failed to sync masks in %x\n",
reg);
+
+ reg = d->chip->wake_base +
+ (i * map->reg_stride * d->irq_reg_stride);
+ if (d->wake_buf) {
+ if (d->chip->wake_invert)
+ ret = regmap_update_bits(d->map, reg,
+ d->mask_buf_def[i],
+ ~d->wake_buf[i]);
+ else
+ ret = regmap_update_bits(d->map, reg,
+ d->mask_buf_def[i],
+ d->wake_buf[i]);
+ if (ret != 0)
+ dev_err(d->map->dev,
+ "Failed to sync wakes in %x: %d\n",
+ reg, ret);
+ }
}
if (d->chip->runtime_pm)
@@ -129,16 +147,15 @@ static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
struct regmap *map = d->map;
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
- if (!d->chip->wake_base)
- return -EINVAL;
-
if (on) {
- d->wake_buf[irq_data->reg_offset / map->reg_stride]
- &= ~irq_data->mask;
+ if (d->wake_buf)
+ d->wake_buf[irq_data->reg_offset / map->reg_stride]
+ &= ~irq_data->mask;
d->wake_count++;
} else {
- d->wake_buf[irq_data->reg_offset / map->reg_stride]
- |= irq_data->mask;
+ if (d->wake_buf)
+ d->wake_buf[irq_data->reg_offset / map->reg_stride]
+ |= irq_data->mask;
d->wake_count--;
}
@@ -172,25 +189,69 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
}
/*
- * Ignore masked IRQs and ack if we need to; we ack early so
- * there is no race between handling and acknowleding the
- * interrupt. We assume that typically few of the interrupts
- * will fire simultaneously so don't worry about overhead from
- * doing a write per register.
+ * Read in the statuses, using a single bulk read if possible
+ * in order to reduce the I/O overheads.
*/
- for (i = 0; i < data->chip->num_regs; i++) {
- ret = regmap_read(map, chip->status_base + (i * map->reg_stride
- * data->irq_reg_stride),
- &data->status_buf[i]);
+ if (!map->use_single_rw && map->reg_stride == 1 &&
+ data->irq_reg_stride == 1) {
+ u8 *buf8 = data->status_reg_buf;
+ u16 *buf16 = data->status_reg_buf;
+ u32 *buf32 = data->status_reg_buf;
+ BUG_ON(!data->status_reg_buf);
+
+ ret = regmap_bulk_read(map, chip->status_base,
+ data->status_reg_buf,
+ chip->num_regs);
if (ret != 0) {
dev_err(map->dev, "Failed to read IRQ status: %d\n",
- ret);
- if (chip->runtime_pm)
- pm_runtime_put(map->dev);
+ ret);
return IRQ_NONE;
}
+ for (i = 0; i < data->chip->num_regs; i++) {
+ switch (map->format.val_bytes) {
+ case 1:
+ data->status_buf[i] = buf8[i];
+ break;
+ case 2:
+ data->status_buf[i] = buf16[i];
+ break;
+ case 4:
+ data->status_buf[i] = buf32[i];
+ break;
+ default:
+ BUG();
+ return IRQ_NONE;
+ }
+ }
+
+ } else {
+ for (i = 0; i < data->chip->num_regs; i++) {
+ ret = regmap_read(map, chip->status_base +
+ (i * map->reg_stride
+ * data->irq_reg_stride),
+ &data->status_buf[i]);
+
+ if (ret != 0) {
+ dev_err(map->dev,
+ "Failed to read IRQ status: %d\n",
+ ret);
+ if (chip->runtime_pm)
+ pm_runtime_put(map->dev);
+ return IRQ_NONE;
+ }
+ }
+ }
+
+ /*
+ * Ignore masked IRQs and ack if we need to; we ack early so
+ * there is no race between handling and acknowleding the
+ * interrupt. We assume that typically few of the interrupts
+ * will fire simultaneously so don't worry about overhead from
+ * doing a write per register.
+ */
+ for (i = 0; i < data->chip->num_regs; i++) {
data->status_buf[i] &= ~data->mask_buf[i];
if (data->status_buf[i] && chip->ack_base) {
@@ -316,11 +377,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
d->irq_chip = regmap_irq_chip;
d->irq_chip.name = chip->name;
- if (!chip->wake_base) {
- d->irq_chip.irq_set_wake = NULL;
- d->irq_chip.flags |= IRQCHIP_MASK_ON_SUSPEND |
- IRQCHIP_SKIP_SET_WAKE;
- }
d->irq = irq;
d->map = map;
d->chip = chip;
@@ -331,6 +387,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
else
d->irq_reg_stride = 1;
+ if (!map->use_single_rw && map->reg_stride == 1 &&
+ d->irq_reg_stride == 1) {
+ d->status_reg_buf = kmalloc(map->format.val_bytes *
+ chip->num_regs, GFP_KERNEL);
+ if (!d->status_reg_buf)
+ goto err_alloc;
+ }
+
mutex_init(&d->lock);
for (i = 0; i < chip->num_irqs; i++)
@@ -361,8 +425,15 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
d->wake_buf[i] = d->mask_buf_def[i];
reg = chip->wake_base +
(i * map->reg_stride * d->irq_reg_stride);
- ret = regmap_update_bits(map, reg, d->wake_buf[i],
- d->wake_buf[i]);
+
+ if (chip->wake_invert)
+ ret = regmap_update_bits(map, reg,
+ d->mask_buf_def[i],
+ 0);
+ else
+ ret = regmap_update_bits(map, reg,
+ d->mask_buf_def[i],
+ d->wake_buf[i]);
if (ret != 0) {
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
reg, ret);
@@ -401,6 +472,7 @@ err_alloc:
kfree(d->mask_buf_def);
kfree(d->mask_buf);
kfree(d->status_buf);
+ kfree(d->status_reg_buf);
kfree(d);
return ret;
}
@@ -422,6 +494,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
kfree(d->wake_buf);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
+ kfree(d->status_reg_buf);
kfree(d->status_buf);
kfree(d);
}
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index f05fc74dd84a..98745dd77e8c 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -26,6 +27,7 @@
struct regmap_mmio_context {
void __iomem *regs;
unsigned val_bytes;
+ struct clk *clk;
};
static int regmap_mmio_gather_write(void *context,
@@ -34,9 +36,16 @@ static int regmap_mmio_gather_write(void *context,
{
struct regmap_mmio_context *ctx = context;
u32 offset;
+ int ret;
BUG_ON(reg_size != 4);
+ if (ctx->clk) {
+ ret = clk_enable(ctx->clk);
+ if (ret < 0)
+ return ret;
+ }
+
offset = *(u32 *)reg;
while (val_size) {
@@ -64,6 +73,9 @@ static int regmap_mmio_gather_write(void *context,
offset += ctx->val_bytes;
}
+ if (ctx->clk)
+ clk_disable(ctx->clk);
+
return 0;
}
@@ -80,9 +92,16 @@ static int regmap_mmio_read(void *context,
{
struct regmap_mmio_context *ctx = context;
u32 offset;
+ int ret;
BUG_ON(reg_size != 4);
+ if (ctx->clk) {
+ ret = clk_enable(ctx->clk);
+ if (ret < 0)
+ return ret;
+ }
+
offset = *(u32 *)reg;
while (val_size) {
@@ -110,11 +129,20 @@ static int regmap_mmio_read(void *context,
offset += ctx->val_bytes;
}
+ if (ctx->clk)
+ clk_disable(ctx->clk);
+
return 0;
}
static void regmap_mmio_free_context(void *context)
{
+ struct regmap_mmio_context *ctx = context;
+
+ if (ctx->clk) {
+ clk_unprepare(ctx->clk);
+ clk_put(ctx->clk);
+ }
kfree(context);
}
@@ -128,11 +156,14 @@ static struct regmap_bus regmap_mmio = {
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
-static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
+static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
+ const char *clk_id,
+ void __iomem *regs,
const struct regmap_config *config)
{
struct regmap_mmio_context *ctx;
int min_stride;
+ int ret;
if (config->reg_bits != 32)
return ERR_PTR(-EINVAL);
@@ -179,37 +210,59 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
ctx->regs = regs;
ctx->val_bytes = config->val_bits / 8;
+ if (clk_id == NULL)
+ return ctx;
+
+ ctx->clk = clk_get(dev, clk_id);
+ if (IS_ERR(ctx->clk)) {
+ ret = PTR_ERR(ctx->clk);
+ goto err_free;
+ }
+
+ ret = clk_prepare(ctx->clk);
+ if (ret < 0) {
+ clk_put(ctx->clk);
+ goto err_free;
+ }
+
return ctx;
+
+err_free:
+ kfree(ctx);
+
+ return ERR_PTR(ret);
}
/**
- * regmap_init_mmio(): Initialise register map
+ * regmap_init_mmio_clk(): Initialise register map with register clock
*
* @dev: Device that will be interacted with
+ * @clk_id: register clock consumer ID
* @regs: Pointer to memory-mapped IO region
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
-struct regmap *regmap_init_mmio(struct device *dev,
- void __iomem *regs,
- const struct regmap_config *config)
+struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
+ void __iomem *regs,
+ const struct regmap_config *config)
{
struct regmap_mmio_context *ctx;
- ctx = regmap_mmio_gen_context(regs, config);
+ ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
if (IS_ERR(ctx))
return ERR_CAST(ctx);
return regmap_init(dev, &regmap_mmio, ctx, config);
}
-EXPORT_SYMBOL_GPL(regmap_init_mmio);
+EXPORT_SYMBOL_GPL(regmap_init_mmio_clk);
/**
- * devm_regmap_init_mmio(): Initialise managed register map
+ * devm_regmap_init_mmio_clk(): Initialise managed register map with clock
*
* @dev: Device that will be interacted with
+ * @clk_id: register clock consumer ID
* @regs: Pointer to memory-mapped IO region
* @config: Configuration for register map
*
@@ -217,18 +270,18 @@ EXPORT_SYMBOL_GPL(regmap_init_mmio);
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
-struct regmap *devm_regmap_init_mmio(struct device *dev,
- void __iomem *regs,
- const struct regmap_config *config)
+struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
+ void __iomem *regs,
+ const struct regmap_config *config)
{
struct regmap_mmio_context *ctx;
- ctx = regmap_mmio_gen_context(regs, config);
+ ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
if (IS_ERR(ctx))
return ERR_CAST(ctx);
return devm_regmap_init(dev, &regmap_mmio, ctx, config);
}
-EXPORT_SYMBOL_GPL(devm_regmap_init_mmio);
+EXPORT_SYMBOL_GPL(devm_regmap_init_mmio_clk);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index ffa46a92ad33..4c506bd940f3 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -15,6 +15,21 @@
#include <linux/init.h>
#include <linux/module.h>
+#include "internal.h"
+
+struct regmap_async_spi {
+ struct regmap_async core;
+ struct spi_message m;
+ struct spi_transfer t[2];
+};
+
+static void regmap_spi_complete(void *data)
+{
+ struct regmap_async_spi *async = data;
+
+ regmap_async_complete_cb(&async->core, async->m.status);
+}
+
static int regmap_spi_write(void *context, const void *data, size_t count)
{
struct device *dev = context;
@@ -40,6 +55,43 @@ static int regmap_spi_gather_write(void *context,
return spi_sync(spi, &m);
}
+static int regmap_spi_async_write(void *context,
+ const void *reg, size_t reg_len,
+ const void *val, size_t val_len,
+ struct regmap_async *a)
+{
+ struct regmap_async_spi *async = container_of(a,
+ struct regmap_async_spi,
+ core);
+ struct device *dev = context;
+ struct spi_device *spi = to_spi_device(dev);
+
+ async->t[0].tx_buf = reg;
+ async->t[0].len = reg_len;
+ async->t[1].tx_buf = val;
+ async->t[1].len = val_len;
+
+ spi_message_init(&async->m);
+ spi_message_add_tail(&async->t[0], &async->m);
+ spi_message_add_tail(&async->t[1], &async->m);
+
+ async->m.complete = regmap_spi_complete;
+ async->m.context = async;
+
+ return spi_async(spi, &async->m);
+}
+
+static struct regmap_async *regmap_spi_async_alloc(void)
+{
+ struct regmap_async_spi *async_spi;
+
+ async_spi = kzalloc(sizeof(*async_spi), GFP_KERNEL);
+ if (!async_spi)
+ return NULL;
+
+ return &async_spi->core;
+}
+
static int regmap_spi_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
@@ -53,6 +105,8 @@ static int regmap_spi_read(void *context,
static struct regmap_bus regmap_spi = {
.write = regmap_spi_write,
.gather_write = regmap_spi_gather_write,
+ .async_write = regmap_spi_async_write,
+ .async_alloc = regmap_spi_async_alloc,
.read = regmap_spi_read,
.read_flag_mask = 0x80,
};
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index f00b059c057a..3d2367501fd0 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -16,6 +16,7 @@
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/rbtree.h>
+#include <linux/sched.h>
#define CREATE_TRACE_POINTS
#include <trace/events/regmap.h>
@@ -34,6 +35,22 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change);
+static int _regmap_bus_read(void *context, unsigned int reg,
+ unsigned int *val);
+static int _regmap_bus_formatted_write(void *context, unsigned int reg,
+ unsigned int val);
+static int _regmap_bus_raw_write(void *context, unsigned int reg,
+ unsigned int val);
+
+static void async_cleanup(struct work_struct *work)
+{
+ struct regmap_async *async = container_of(work, struct regmap_async,
+ cleanup);
+
+ kfree(async->work_buf);
+ kfree(async);
+}
+
bool regmap_reg_in_ranges(unsigned int reg,
const struct regmap_range *ranges,
unsigned int nranges)
@@ -372,7 +389,7 @@ struct regmap *regmap_init(struct device *dev,
enum regmap_endian reg_endian, val_endian;
int i, j;
- if (!bus || !config)
+ if (!config)
goto err;
map = kzalloc(sizeof(*map), GFP_KERNEL);
@@ -386,7 +403,8 @@ struct regmap *regmap_init(struct device *dev,
map->unlock = config->unlock;
map->lock_arg = config->lock_arg;
} else {
- if (bus->fast_io) {
+ if ((bus && bus->fast_io) ||
+ config->fast_io) {
spin_lock_init(&map->spinlock);
map->lock = regmap_lock_spinlock;
map->unlock = regmap_unlock_spinlock;
@@ -423,13 +441,27 @@ struct regmap *regmap_init(struct device *dev,
map->cache_type = config->cache_type;
map->name = config->name;
+ spin_lock_init(&map->async_lock);
+ INIT_LIST_HEAD(&map->async_list);
+ init_waitqueue_head(&map->async_waitq);
+
if (config->read_flag_mask || config->write_flag_mask) {
map->read_flag_mask = config->read_flag_mask;
map->write_flag_mask = config->write_flag_mask;
- } else {
+ } else if (bus) {
map->read_flag_mask = bus->read_flag_mask;
}
+ if (!bus) {
+ map->reg_read = config->reg_read;
+ map->reg_write = config->reg_write;
+
+ map->defer_caching = false;
+ goto skip_format_initialization;
+ } else {
+ map->reg_read = _regmap_bus_read;
+ }
+
reg_endian = config->reg_format_endian;
if (reg_endian == REGMAP_ENDIAN_DEFAULT)
reg_endian = bus->reg_format_endian_default;
@@ -500,6 +532,12 @@ struct regmap *regmap_init(struct device *dev,
}
break;
+ case 24:
+ if (reg_endian != REGMAP_ENDIAN_BIG)
+ goto err_map;
+ map->format.format_reg = regmap_format_24;
+ break;
+
case 32:
switch (reg_endian) {
case REGMAP_ENDIAN_BIG:
@@ -575,6 +613,16 @@ struct regmap *regmap_init(struct device *dev,
goto err_map;
}
+ if (map->format.format_write) {
+ map->defer_caching = false;
+ map->reg_write = _regmap_bus_formatted_write;
+ } else if (map->format.format_val) {
+ map->defer_caching = true;
+ map->reg_write = _regmap_bus_raw_write;
+ }
+
+skip_format_initialization:
+
map->range_tree = RB_ROOT;
for (i = 0; i < config->num_ranges; i++) {
const struct regmap_range_cfg *range_cfg = &config->ranges[i];
@@ -776,7 +824,7 @@ void regmap_exit(struct regmap *map)
regcache_exit(map);
regmap_debugfs_exit(map);
regmap_range_exit(map);
- if (map->bus->free_context)
+ if (map->bus && map->bus->free_context)
map->bus->free_context(map->bus_context);
kfree(map->work_buf);
kfree(map);
@@ -870,15 +918,20 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
}
static int _regmap_raw_write(struct regmap *map, unsigned int reg,
- const void *val, size_t val_len)
+ const void *val, size_t val_len, bool async)
{
struct regmap_range_node *range;
+ unsigned long flags;
u8 *u8 = map->work_buf;
+ void *work_val = map->work_buf + map->format.reg_bytes +
+ map->format.pad_bytes;
void *buf;
int ret = -ENOTSUPP;
size_t len;
int i;
+ BUG_ON(!map->bus);
+
/* Check for unwritable registers before we start */
if (map->writeable_reg)
for (i = 0; i < val_len / map->format.val_bytes; i++)
@@ -918,7 +971,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
dev_dbg(map->dev, "Writing window %d/%zu\n",
win_residue, val_len / map->format.val_bytes);
ret = _regmap_raw_write(map, reg, val, win_residue *
- map->format.val_bytes);
+ map->format.val_bytes, async);
if (ret != 0)
return ret;
@@ -941,6 +994,50 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
u8[0] |= map->write_flag_mask;
+ if (async && map->bus->async_write) {
+ struct regmap_async *async = map->bus->async_alloc();
+ if (!async)
+ return -ENOMEM;
+
+ async->work_buf = kzalloc(map->format.buf_size,
+ GFP_KERNEL | GFP_DMA);
+ if (!async->work_buf) {
+ kfree(async);
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&async->cleanup, async_cleanup);
+ async->map = map;
+
+ /* If the caller supplied the value we can use it safely. */
+ memcpy(async->work_buf, map->work_buf, map->format.pad_bytes +
+ map->format.reg_bytes + map->format.val_bytes);
+ if (val == work_val)
+ val = async->work_buf + map->format.pad_bytes +
+ map->format.reg_bytes;
+
+ spin_lock_irqsave(&map->async_lock, flags);
+ list_add_tail(&async->list, &map->async_list);
+ spin_unlock_irqrestore(&map->async_lock, flags);
+
+ ret = map->bus->async_write(map->bus_context, async->work_buf,
+ map->format.reg_bytes +
+ map->format.pad_bytes,
+ val, val_len, async);
+
+ if (ret != 0) {
+ dev_err(map->dev, "Failed to schedule write: %d\n",
+ ret);
+
+ spin_lock_irqsave(&map->async_lock, flags);
+ list_del(&async->list);
+ spin_unlock_irqrestore(&map->async_lock, flags);
+
+ kfree(async->work_buf);
+ kfree(async);
+ }
+ }
+
trace_regmap_hw_write_start(map->dev, reg,
val_len / map->format.val_bytes);
@@ -948,8 +1045,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
* send the work_buf directly, otherwise try to do a gather
* write.
*/
- if (val == (map->work_buf + map->format.pad_bytes +
- map->format.reg_bytes))
+ if (val == work_val)
ret = map->bus->write(map->bus_context, map->work_buf,
map->format.reg_bytes +
map->format.pad_bytes +
@@ -981,14 +1077,62 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
return ret;
}
+static int _regmap_bus_formatted_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ int ret;
+ struct regmap_range_node *range;
+ struct regmap *map = context;
+
+ BUG_ON(!map->bus || !map->format.format_write);
+
+ range = _regmap_range_lookup(map, reg);
+ if (range) {
+ ret = _regmap_select_page(map, &reg, range, 1);
+ if (ret != 0)
+ return ret;
+ }
+
+ map->format.format_write(map, reg, val);
+
+ trace_regmap_hw_write_start(map->dev, reg, 1);
+
+ ret = map->bus->write(map->bus_context, map->work_buf,
+ map->format.buf_size);
+
+ trace_regmap_hw_write_done(map->dev, reg, 1);
+
+ return ret;
+}
+
+static int _regmap_bus_raw_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct regmap *map = context;
+
+ BUG_ON(!map->bus || !map->format.format_val);
+
+ map->format.format_val(map->work_buf + map->format.reg_bytes
+ + map->format.pad_bytes, val, 0);
+ return _regmap_raw_write(map, reg,
+ map->work_buf +
+ map->format.reg_bytes +
+ map->format.pad_bytes,
+ map->format.val_bytes, false);
+}
+
+static inline void *_regmap_map_get_context(struct regmap *map)
+{
+ return (map->bus) ? map : map->bus_context;
+}
+
int _regmap_write(struct regmap *map, unsigned int reg,
unsigned int val)
{
- struct regmap_range_node *range;
int ret;
- BUG_ON(!map->format.format_write && !map->format.format_val);
+ void *context = _regmap_map_get_context(map);
- if (!map->cache_bypass && map->format.format_write) {
+ if (!map->cache_bypass && !map->defer_caching) {
ret = regcache_write(map, reg, val);
if (ret != 0)
return ret;
@@ -1005,33 +1149,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
trace_regmap_reg_write(map->dev, reg, val);
- if (map->format.format_write) {
- range = _regmap_range_lookup(map, reg);
- if (range) {
- ret = _regmap_select_page(map, &reg, range, 1);
- if (ret != 0)
- return ret;
- }
-
- map->format.format_write(map, reg, val);
-
- trace_regmap_hw_write_start(map->dev, reg, 1);
-
- ret = map->bus->write(map->bus_context, map->work_buf,
- map->format.buf_size);
-
- trace_regmap_hw_write_done(map->dev, reg, 1);
-
- return ret;
- } else {
- map->format.format_val(map->work_buf + map->format.reg_bytes
- + map->format.pad_bytes, val, 0);
- return _regmap_raw_write(map, reg,
- map->work_buf +
- map->format.reg_bytes +
- map->format.pad_bytes,
- map->format.val_bytes);
- }
+ return map->reg_write(context, reg, val);
}
/**
@@ -1082,6 +1200,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
{
int ret;
+ if (!map->bus)
+ return -EINVAL;
if (val_len % map->format.val_bytes)
return -EINVAL;
if (reg % map->reg_stride)
@@ -1089,7 +1209,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
map->lock(map->lock_arg);
- ret = _regmap_raw_write(map, reg, val, val_len);
+ ret = _regmap_raw_write(map, reg, val, val_len, false);
map->unlock(map->lock_arg);
@@ -1118,6 +1238,8 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
size_t val_bytes = map->format.val_bytes;
void *wval;
+ if (!map->bus)
+ return -EINVAL;
if (!map->format.parse_val)
return -EINVAL;
if (reg % map->reg_stride)
@@ -1145,14 +1267,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (map->use_single_rw) {
for (i = 0; i < val_count; i++) {
ret = regmap_raw_write(map,
- reg + (i * map->reg_stride),
- val + (i * val_bytes),
- val_bytes);
+ reg + (i * map->reg_stride),
+ val + (i * val_bytes),
+ val_bytes);
if (ret != 0)
return ret;
}
} else {
- ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
+ ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count,
+ false);
}
if (val_bytes != 1)
@@ -1164,6 +1287,48 @@ out:
}
EXPORT_SYMBOL_GPL(regmap_bulk_write);
+/**
+ * regmap_raw_write_async(): Write raw values to one or more registers
+ * asynchronously
+ *
+ * @map: Register map to write to
+ * @reg: Initial register to write to
+ * @val: Block of data to be written, laid out for direct transmission to the
+ * device. Must be valid until regmap_async_complete() is called.
+ * @val_len: Length of data pointed to by val.
+ *
+ * This function is intended to be used for things like firmware
+ * download where a large block of data needs to be transferred to the
+ * device. No formatting will be done on the data provided.
+ *
+ * If supported by the underlying bus the write will be scheduled
+ * asynchronously, helping maximise I/O speed on higher speed buses
+ * like SPI. regmap_async_complete() can be called to ensure that all
+ * asynchrnous writes have been completed.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_raw_write_async(struct regmap *map, unsigned int reg,
+ const void *val, size_t val_len)
+{
+ int ret;
+
+ if (val_len % map->format.val_bytes)
+ return -EINVAL;
+ if (reg % map->reg_stride)
+ return -EINVAL;
+
+ map->lock(map->lock_arg);
+
+ ret = _regmap_raw_write(map, reg, val, val_len, true);
+
+ map->unlock(map->lock_arg);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_raw_write_async);
+
static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
unsigned int val_len)
{
@@ -1171,6 +1336,8 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
u8 *u8 = map->work_buf;
int ret;
+ BUG_ON(!map->bus);
+
range = _regmap_range_lookup(map, reg);
if (range) {
ret = _regmap_select_page(map, &reg, range,
@@ -1202,10 +1369,29 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
return ret;
}
+static int _regmap_bus_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ int ret;
+ struct regmap *map = context;
+
+ if (!map->format.parse_val)
+ return -EINVAL;
+
+ ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
+ if (ret == 0)
+ *val = map->format.parse_val(map->work_buf);
+
+ return ret;
+}
+
static int _regmap_read(struct regmap *map, unsigned int reg,
unsigned int *val)
{
int ret;
+ void *context = _regmap_map_get_context(map);
+
+ BUG_ON(!map->reg_read);
if (!map->cache_bypass) {
ret = regcache_read(map, reg, val);
@@ -1213,26 +1399,21 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
return 0;
}
- if (!map->format.parse_val)
- return -EINVAL;
-
if (map->cache_only)
return -EBUSY;
- ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
+ ret = map->reg_read(context, reg, val);
if (ret == 0) {
- *val = map->format.parse_val(map->work_buf);
-
#ifdef LOG_DEVICE
if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
dev_info(map->dev, "%x => %x\n", reg, *val);
#endif
trace_regmap_reg_read(map->dev, reg, *val);
- }
- if (ret == 0 && !map->cache_bypass)
- regcache_write(map, reg, *val);
+ if (!map->cache_bypass)
+ regcache_write(map, reg, *val);
+ }
return ret;
}
@@ -1283,6 +1464,8 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
unsigned int v;
int ret, i;
+ if (!map->bus)
+ return -EINVAL;
if (val_len % map->format.val_bytes)
return -EINVAL;
if (reg % map->reg_stride)
@@ -1334,6 +1517,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
size_t val_bytes = map->format.val_bytes;
bool vol = regmap_volatile_range(map, reg, val_count);
+ if (!map->bus)
+ return -EINVAL;
if (!map->format.parse_val)
return -EINVAL;
if (reg % map->reg_stride)
@@ -1450,6 +1635,68 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
}
EXPORT_SYMBOL_GPL(regmap_update_bits_check);
+void regmap_async_complete_cb(struct regmap_async *async, int ret)
+{
+ struct regmap *map = async->map;
+ bool wake;
+
+ spin_lock(&map->async_lock);
+
+ list_del(&async->list);
+ wake = list_empty(&map->async_list);
+
+ if (ret != 0)
+ map->async_ret = ret;
+
+ spin_unlock(&map->async_lock);
+
+ schedule_work(&async->cleanup);
+
+ if (wake)
+ wake_up(&map->async_waitq);
+}
+EXPORT_SYMBOL_GPL(regmap_async_complete_cb);
+
+static int regmap_async_is_done(struct regmap *map)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&map->async_lock, flags);
+ ret = list_empty(&map->async_list);
+ spin_unlock_irqrestore(&map->async_lock, flags);
+
+ return ret;
+}
+
+/**
+ * regmap_async_complete: Ensure all asynchronous I/O has completed.
+ *
+ * @map: Map to operate on.
+ *
+ * Blocks until any pending asynchronous I/O has completed. Returns
+ * an error code for any failed I/O operations.
+ */
+int regmap_async_complete(struct regmap *map)
+{
+ unsigned long flags;
+ int ret;
+
+ /* Nothing to do with no async support */
+ if (!map->bus->async_write)
+ return 0;
+
+ wait_event(map->async_waitq, regmap_async_is_done(map));
+
+ spin_lock_irqsave(&map->async_lock, flags);
+ ret = map->async_ret;
+ map->async_ret = 0;
+ spin_unlock_irqrestore(&map->async_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_async_complete);
+
/**
* regmap_register_patch: Register and apply register updates to be applied
* on device initialistion
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 19e3fbfd5757..79595a001204 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -31,6 +31,8 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
int bcma_bus_suspend(struct bcma_bus *bus);
int bcma_bus_resume(struct bcma_bus *bus);
#endif
+struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
+ u8 unit);
/* scan.c */
int bcma_bus_scan(struct bcma_bus *bus);
@@ -45,6 +47,7 @@ int bcma_sprom_get(struct bcma_bus *bus);
/* driver_chipcommon.c */
#ifdef CONFIG_BCMA_DRIVER_MIPS
void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+extern struct platform_device bcma_pflash_dev;
#endif /* CONFIG_BCMA_DRIVER_MIPS */
/* driver_chipcommon_pmu.c */
@@ -94,11 +97,16 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
#ifdef CONFIG_BCMA_DRIVER_GPIO
/* driver_gpio.c */
int bcma_gpio_init(struct bcma_drv_cc *cc);
+int bcma_gpio_unregister(struct bcma_drv_cc *cc);
#else
static inline int bcma_gpio_init(struct bcma_drv_cc *cc)
{
return -ENOTSUPP;
}
+static inline int bcma_gpio_unregister(struct bcma_drv_cc *cc)
+{
+ return 0;
+}
#endif /* CONFIG_BCMA_DRIVER_GPIO */
#endif
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index e461ad25fda4..28fa50ad87be 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -329,7 +329,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
return;
}
- irq = bcma_core_mips_irq(cc->core);
+ irq = bcma_core_irq(cc->core);
/* Determine the registers of the UARTs */
cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
diff --git a/drivers/bcma/driver_chipcommon_nflash.c b/drivers/bcma/driver_chipcommon_nflash.c
index dbda91e4dff5..d4f699aef8c4 100644
--- a/drivers/bcma/driver_chipcommon_nflash.c
+++ b/drivers/bcma/driver_chipcommon_nflash.c
@@ -5,11 +5,11 @@
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include "bcma_private.h"
+
#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
-#include "bcma_private.h"
-
struct platform_device bcma_nflash_dev = {
.name = "bcma_nflash",
.num_resources = 0,
@@ -21,7 +21,7 @@ int bcma_nflash_init(struct bcma_drv_cc *cc)
struct bcma_bus *bus = cc->core->bus;
if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
- cc->core->id.rev != 0x38) {
+ cc->core->id.rev != 38) {
bcma_err(bus, "NAND flash on unsupported board!\n");
return -ENOTSUPP;
}
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index c62c788b3289..932b101dee36 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -264,7 +264,7 @@ static u32 bcma_pmu_pll_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
}
/* query bus clock frequency for PMU-enabled chipcommon */
-static u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
+u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
@@ -293,6 +293,7 @@ static u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
}
return BCMA_CC_PMU_HT_CLOCK;
}
+EXPORT_SYMBOL_GPL(bcma_pmu_get_bus_clock);
/* query cpu clock frequency for PMU-enabled chipcommon */
u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc)
diff --git a/drivers/bcma/driver_chipcommon_sflash.c b/drivers/bcma/driver_chipcommon_sflash.c
index 1e694db4532d..e6ed4fe5dced 100644
--- a/drivers/bcma/driver_chipcommon_sflash.c
+++ b/drivers/bcma/driver_chipcommon_sflash.c
@@ -5,11 +5,11 @@
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include "bcma_private.h"
+
#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
-#include "bcma_private.h"
-
static struct resource bcma_sflash_resource = {
.name = "bcma_sflash",
.start = BCMA_SOC_FLASH2,
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
index 9a6f585da2d9..45f0996a3752 100644
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -73,6 +73,16 @@ static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio)
bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
}
+static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+
+ if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
+ return bcma_core_irq(cc->core);
+ else
+ return -EINVAL;
+}
+
int bcma_gpio_init(struct bcma_drv_cc *cc)
{
struct gpio_chip *chip = &cc->gpio;
@@ -85,6 +95,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
chip->set = bcma_gpio_set_value;
chip->direction_input = bcma_gpio_direction_input;
chip->direction_output = bcma_gpio_direction_output;
+ chip->to_irq = bcma_gpio_to_irq;
chip->ngpio = 16;
/* There is just one SoC in one device and its GPIO addresses should be
* deterministic to address them more easily. The other buses could get
@@ -96,3 +107,8 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
return gpiochip_add(chip);
}
+
+int bcma_gpio_unregister(struct bcma_drv_cc *cc)
+{
+ return gpiochip_remove(&cc->gpio);
+}
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 792daad28cbc..9a7f0e3ab5a3 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -14,11 +14,33 @@
#include <linux/bcma/bcma.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/time.h>
+static const char *part_probes[] = { "bcm47xxpart", NULL };
+
+static struct physmap_flash_data bcma_pflash_data = {
+ .part_probe_types = part_probes,
+};
+
+static struct resource bcma_pflash_resource = {
+ .name = "bcma_pflash",
+ .flags = IORESOURCE_MEM,
+};
+
+struct platform_device bcma_pflash_dev = {
+ .name = "physmap-flash",
+ .dev = {
+ .platform_data = &bcma_pflash_data,
+ },
+ .resource = &bcma_pflash_resource,
+ .num_resources = 1,
+};
+
/* The 47162a0 hangs when reading MIPS DMP registers registers */
static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
{
@@ -74,28 +96,41 @@ static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
return dev->core_index;
flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
- return flag & 0x1F;
+ if (flag)
+ return flag & 0x1F;
+ else
+ return 0x3f;
}
/* Get the MIPS IRQ assignment for a specified device.
* If unassigned, 0 is returned.
+ * If disabled, 5 is returned.
+ * If not supported, 6 is returned.
*/
-unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
{
struct bcma_device *mdev = dev->bus->drv_mips.core;
u32 irqflag;
unsigned int irq;
irqflag = bcma_core_mips_irqflag(dev);
+ if (irqflag == 0x3f)
+ return 6;
- for (irq = 1; irq <= 4; irq++)
+ for (irq = 0; irq <= 4; irq++)
if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
(1 << irqflag))
return irq;
- return 0;
+ return 5;
+}
+
+unsigned int bcma_core_irq(struct bcma_device *dev)
+{
+ unsigned int mips_irq = bcma_core_mips_irq(dev);
+ return mips_irq <= 4 ? mips_irq + 2 : 0;
}
-EXPORT_SYMBOL(bcma_core_mips_irq);
+EXPORT_SYMBOL(bcma_core_irq);
static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
{
@@ -114,7 +149,7 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
~(1 << irqflag));
- else
+ else if (oldirq != 5)
bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0);
/* assign the new one */
@@ -123,9 +158,9 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
(1 << irqflag));
} else {
- u32 oldirqflag = bcma_read32(mdev,
- BCMA_MIPS_MIPS74K_INTMASK(irq));
- if (oldirqflag) {
+ u32 irqinitmask = bcma_read32(mdev,
+ BCMA_MIPS_MIPS74K_INTMASK(irq));
+ if (irqinitmask) {
struct bcma_device *core;
/* backplane irq line is in use, find out who uses
@@ -133,7 +168,7 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
*/
list_for_each_entry(core, &bus->cores, list) {
if ((1 << bcma_core_mips_irqflag(core)) ==
- oldirqflag) {
+ irqinitmask) {
bcma_core_mips_set_irq(core, 0);
break;
}
@@ -143,15 +178,31 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
1 << irqflag);
}
- bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n",
- dev->id.id, oldirq + 2, irq + 2);
+ bcma_debug(bus, "set_irq: core 0x%04x, irq %d => %d\n",
+ dev->id.id, oldirq <= 4 ? oldirq + 2 : 0, irq + 2);
+}
+
+static void bcma_core_mips_set_irq_name(struct bcma_bus *bus, unsigned int irq,
+ u16 coreid, u8 unit)
+{
+ struct bcma_device *core;
+
+ core = bcma_find_core_unit(bus, coreid, unit);
+ if (!core) {
+ bcma_warn(bus,
+ "Can not find core (id: 0x%x, unit %i) for IRQ configuration.\n",
+ coreid, unit);
+ return;
+ }
+
+ bcma_core_mips_set_irq(core, irq);
}
static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
{
int i;
static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
- printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
+ printk(KERN_DEBUG KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
for (i = 0; i <= 6; i++)
printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
printk("\n");
@@ -182,6 +233,7 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
{
struct bcma_bus *bus = mcore->core->bus;
struct bcma_drv_cc *cc = &bus->drv_cc;
+ struct bcma_pflash *pflash = &cc->pflash;
switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER:
@@ -191,15 +243,20 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
break;
case BCMA_CC_FLASHT_PARA:
bcma_debug(bus, "Found parallel flash\n");
- cc->pflash.present = true;
- cc->pflash.window = BCMA_SOC_FLASH2;
- cc->pflash.window_size = BCMA_SOC_FLASH2_SZ;
+ pflash->present = true;
+ pflash->window = BCMA_SOC_FLASH2;
+ pflash->window_size = BCMA_SOC_FLASH2_SZ;
if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
BCMA_CC_FLASH_CFG_DS) == 0)
- cc->pflash.buswidth = 1;
+ pflash->buswidth = 1;
else
- cc->pflash.buswidth = 2;
+ pflash->buswidth = 2;
+
+ bcma_pflash_data.width = pflash->buswidth;
+ bcma_pflash_resource.start = pflash->window;
+ bcma_pflash_resource.end = pflash->window + pflash->window_size;
+
break;
default:
bcma_err(bus, "Flash type not supported\n");
@@ -227,6 +284,32 @@ void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
mcore->early_setup_done = true;
}
+static void bcma_fix_i2s_irqflag(struct bcma_bus *bus)
+{
+ struct bcma_device *cpu, *pcie, *i2s;
+
+ /* Fixup the interrupts in 4716/4748 for i2s core (2010 Broadcom SDK)
+ * (IRQ flags > 7 are ignored when setting the interrupt masks)
+ */
+ if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4716 &&
+ bus->chipinfo.id != BCMA_CHIP_ID_BCM4748)
+ return;
+
+ cpu = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
+ pcie = bcma_find_core(bus, BCMA_CORE_PCIE);
+ i2s = bcma_find_core(bus, BCMA_CORE_I2S);
+ if (cpu && pcie && i2s &&
+ bcma_aread32(cpu, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
+ bcma_aread32(pcie, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
+ bcma_aread32(i2s, BCMA_MIPS_OOBSELOUTA30) == 0x88) {
+ bcma_awrite32(cpu, BCMA_MIPS_OOBSELINA74, 0x07060504);
+ bcma_awrite32(pcie, BCMA_MIPS_OOBSELINA74, 0x07060504);
+ bcma_awrite32(i2s, BCMA_MIPS_OOBSELOUTA30, 0x87);
+ bcma_debug(bus,
+ "Moved i2s interrupt to oob line 7 instead of 8\n");
+ }
+}
+
void bcma_core_mips_init(struct bcma_drv_mips *mcore)
{
struct bcma_bus *bus;
@@ -236,43 +319,55 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
if (mcore->setup_done)
return;
- bcma_info(bus, "Initializing MIPS core...\n");
+ bcma_debug(bus, "Initializing MIPS core...\n");
bcma_core_mips_early_init(mcore);
- mcore->assigned_irqs = 1;
-
- /* Assign IRQs to all cores on the bus */
- list_for_each_entry(core, &bus->cores, list) {
- int mips_irq;
- if (core->irq)
- continue;
-
- mips_irq = bcma_core_mips_irq(core);
- if (mips_irq > 4)
- core->irq = 0;
- else
- core->irq = mips_irq + 2;
- if (core->irq > 5)
- continue;
- switch (core->id.id) {
- case BCMA_CORE_PCI:
- case BCMA_CORE_PCIE:
- case BCMA_CORE_ETHERNET:
- case BCMA_CORE_ETHERNET_GBIT:
- case BCMA_CORE_MAC_GBIT:
- case BCMA_CORE_80211:
- case BCMA_CORE_USB20_HOST:
- /* These devices get their own IRQ line if available,
- * the rest goes on IRQ0
- */
- if (mcore->assigned_irqs <= 4)
- bcma_core_mips_set_irq(core,
- mcore->assigned_irqs++);
- break;
+ bcma_fix_i2s_irqflag(bus);
+
+ switch (bus->chipinfo.id) {
+ case BCMA_CHIP_ID_BCM4716:
+ case BCMA_CHIP_ID_BCM4748:
+ bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
+ bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
+ bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
+ bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_PCIE, 0);
+ bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
+ bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
+ break;
+ case BCMA_CHIP_ID_BCM5356:
+ case BCMA_CHIP_ID_BCM47162:
+ case BCMA_CHIP_ID_BCM53572:
+ bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
+ bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
+ bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
+ break;
+ case BCMA_CHIP_ID_BCM5357:
+ case BCMA_CHIP_ID_BCM4749:
+ bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
+ bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
+ bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
+ bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
+ bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
+ break;
+ case BCMA_CHIP_ID_BCM4706:
+ bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_PCIE, 0);
+ bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_4706_MAC_GBIT,
+ 0);
+ bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_PCIE, 1);
+ bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_USB20_HOST, 0);
+ bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_4706_CHIPCOMMON,
+ 0);
+ break;
+ default:
+ list_for_each_entry(core, &bus->cores, list) {
+ core->irq = bcma_core_irq(core);
}
+ bcma_err(bus,
+ "Unknown device (0x%x) found, can not configure IRQs\n",
+ bus->chipinfo.id);
}
- bcma_info(bus, "IRQ reconfiguration done\n");
+ bcma_debug(bus, "IRQ reconfiguration done\n");
bcma_core_mips_dump_irq(bus);
mcore->setup_done = true;
diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c
index af0c9fabee54..d3bde6cec927 100644
--- a/drivers/bcma/driver_pci_host.c
+++ b/drivers/bcma/driver_pci_host.c
@@ -94,19 +94,19 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
if (dev == 0) {
/* we support only two functions on device 0 */
if (func > 1)
- return -EINVAL;
+ goto out;
/* accesses to config registers with offsets >= 256
* requires indirect access.
*/
if (off >= PCI_CONFIG_SPACE_SIZE) {
addr = (func << 12);
- addr |= (off & 0x0FFF);
+ addr |= (off & 0x0FFC);
val = bcma_pcie_read_config(pc, addr);
} else {
addr = BCMA_CORE_PCI_PCICFG0;
addr |= (func << 8);
- addr |= (off & 0xfc);
+ addr |= (off & 0xFC);
val = pcicore_read32(pc, addr);
}
} else {
@@ -119,11 +119,9 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
goto out;
if (mips_busprobe32(val, mmio)) {
- val = 0xffffffff;
+ val = 0xFFFFFFFF;
goto unmap;
}
-
- val = readl(mmio);
}
val >>= (8 * (off & 3));
@@ -151,7 +149,7 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
const void *buf, int len)
{
int err = -EINVAL;
- u32 addr = 0, val = 0;
+ u32 addr, val;
void __iomem *mmio = 0;
u16 chipid = pc->core->bus->chipinfo.id;
@@ -159,16 +157,22 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
if (unlikely(len != 1 && len != 2 && len != 4))
goto out;
if (dev == 0) {
+ /* we support only two functions on device 0 */
+ if (func > 1)
+ goto out;
+
/* accesses to config registers with offsets >= 256
* requires indirect access.
*/
- if (off < PCI_CONFIG_SPACE_SIZE) {
- addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
+ if (off >= PCI_CONFIG_SPACE_SIZE) {
+ addr = (func << 12);
+ addr |= (off & 0x0FFC);
+ val = bcma_pcie_read_config(pc, addr);
+ } else {
+ addr = BCMA_CORE_PCI_PCICFG0;
addr |= (func << 8);
- addr |= (off & 0xfc);
- mmio = ioremap_nocache(addr, sizeof(val));
- if (!mmio)
- goto out;
+ addr |= (off & 0xFC);
+ val = pcicore_read32(pc, addr);
}
} else {
addr = bcma_get_cfgspace_addr(pc, dev, func, off);
@@ -180,19 +184,17 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
goto out;
if (mips_busprobe32(val, mmio)) {
- val = 0xffffffff;
+ val = 0xFFFFFFFF;
goto unmap;
}
}
switch (len) {
case 1:
- val = readl(mmio);
val &= ~(0xFF << (8 * (off & 3)));
val |= *((const u8 *)buf) << (8 * (off & 3));
break;
case 2:
- val = readl(mmio);
val &= ~(0xFFFF << (8 * (off & 3)));
val |= *((const u16 *)buf) << (8 * (off & 3));
break;
@@ -200,13 +202,14 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
val = *((const u32 *)buf);
break;
}
- if (dev == 0 && !addr) {
+ if (dev == 0) {
/* accesses to config registers with offsets >= 256
* requires indirect access.
*/
- addr = (func << 12);
- addr |= (off & 0x0FFF);
- bcma_pcie_write_config(pc, addr, val);
+ if (off >= PCI_CONFIG_SPACE_SIZE)
+ bcma_pcie_write_config(pc, addr, val);
+ else
+ pcicore_write32(pc, addr, val);
} else {
writel(val, mmio);
@@ -276,7 +279,7 @@ static u8 bcma_find_pci_capability(struct bcma_drv_pci *pc, unsigned int dev,
/* check for Header type 0 */
bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val,
sizeof(u8));
- if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
+ if ((byte_val & 0x7F) != PCI_HEADER_TYPE_NORMAL)
return cap_ptr;
/* check if the capability pointer field exists */
@@ -426,7 +429,7 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
/* Reset RC */
usleep_range(3000, 5000);
pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
- usleep_range(1000, 2000);
+ msleep(50);
pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
BCMA_CORE_PCI_CTL_RST_OE);
@@ -488,6 +491,17 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
bcma_core_pci_enable_crs(pc);
+ if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706 ||
+ bus->chipinfo.id == BCMA_CHIP_ID_BCM4716) {
+ u16 val16;
+ bcma_extpci_read_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL,
+ &val16, sizeof(val16));
+ val16 |= (2 << 5); /* Max payload size of 512 */
+ val16 |= (2 << 12); /* MRRS 512 */
+ bcma_extpci_write_config(pc, 0, 0, BCMA_CORE_PCI_CFG_DEVCTRL,
+ &val16, sizeof(val16));
+ }
+
/* Enable PCI bridge BAR0 memory & master access */
tmp = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
bcma_extpci_write_config(pc, 0, 0, PCI_COMMAND, &tmp, sizeof(tmp));
@@ -576,7 +590,7 @@ int bcma_core_pci_plat_dev_init(struct pci_dev *dev)
pr_info("PCI: Fixing up device %s\n", pci_name(dev));
/* Fix up interrupt lines */
- dev->irq = bcma_core_mips_irq(pc_host->pdev->core) + 2;
+ dev->irq = bcma_core_irq(pc_host->pdev->core);
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
return 0;
@@ -595,6 +609,6 @@ int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev)
pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
pci_ops);
- return bcma_core_mips_irq(pc_host->pdev->core) + 2;
+ return bcma_core_irq(pc_host->pdev->core);
}
EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 4a92f647b58b..9a6188add590 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -81,8 +81,8 @@ struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
}
EXPORT_SYMBOL_GPL(bcma_find_core);
-static struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
- u8 unit)
+struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
+ u8 unit)
{
struct bcma_device *core;
@@ -149,6 +149,14 @@ static int bcma_register_cores(struct bcma_bus *bus)
dev_id++;
}
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+ if (bus->drv_cc.pflash.present) {
+ err = platform_device_register(&bcma_pflash_dev);
+ if (err)
+ bcma_err(bus, "Error registering parallel flash\n");
+ }
+#endif
+
#ifdef CONFIG_BCMA_SFLASH
if (bus->drv_cc.sflash.present) {
err = platform_device_register(&bcma_sflash_dev);
@@ -268,6 +276,13 @@ int bcma_bus_register(struct bcma_bus *bus)
void bcma_bus_unregister(struct bcma_bus *bus)
{
struct bcma_device *cores[3];
+ int err;
+
+ err = bcma_gpio_unregister(&bus->drv_cc);
+ if (err == -EBUSY)
+ bcma_err(bus, "Some GPIOs are still in use.\n");
+ else if (err)
+ bcma_err(bus, "Can not unregister GPIO driver: %i\n", err);
cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index f58a4a4b4dfb..2b8303ad63c9 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -168,7 +168,7 @@ static void wake_all_senders(struct drbd_tconn *tconn) {
}
/* must hold resource->req_lock */
-static void start_new_tl_epoch(struct drbd_tconn *tconn)
+void start_new_tl_epoch(struct drbd_tconn *tconn)
{
/* no point closing an epoch, if it is empty, anyways. */
if (tconn->current_tle_writes == 0)
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
index 016de6b8bb57..c08d22964d06 100644
--- a/drivers/block/drbd/drbd_req.h
+++ b/drivers/block/drbd/drbd_req.h
@@ -267,6 +267,7 @@ struct bio_and_error {
int error;
};
+extern void start_new_tl_epoch(struct drbd_tconn *tconn);
extern void drbd_req_destroy(struct kref *kref);
extern void _req_may_be_done(struct drbd_request *req,
struct bio_and_error *m);
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index 53bf6182bac4..0fe220cfb9e9 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -931,6 +931,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
enum drbd_state_rv rv = SS_SUCCESS;
enum sanitize_state_warnings ssw;
struct after_state_chg_work *ascw;
+ bool did_remote, should_do_remote;
os = drbd_read_state(mdev);
@@ -981,11 +982,17 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
(os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
atomic_inc(&mdev->local_cnt);
+ did_remote = drbd_should_do_remote(mdev->state);
mdev->state.i = ns.i;
+ should_do_remote = drbd_should_do_remote(mdev->state);
mdev->tconn->susp = ns.susp;
mdev->tconn->susp_nod = ns.susp_nod;
mdev->tconn->susp_fen = ns.susp_fen;
+ /* put replicated vs not-replicated requests in seperate epochs */
+ if (did_remote != should_do_remote)
+ start_new_tl_epoch(mdev->tconn);
+
if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING)
drbd_print_uuids(mdev, "attached to UUIDs");
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 9694dd99bbbc..3fd100990453 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -626,12 +626,13 @@ static void mtip_timeout_function(unsigned long int data)
}
}
- if (cmdto_cnt && !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
+ if (cmdto_cnt) {
print_tags(port->dd, "timed out", tagaccum, cmdto_cnt);
-
- mtip_restart_port(port);
+ if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
+ mtip_restart_port(port);
+ wake_up_interruptible(&port->svc_wait);
+ }
clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
- wake_up_interruptible(&port->svc_wait);
}
if (port->ic_pause_timer) {
@@ -3887,7 +3888,12 @@ static int mtip_block_remove(struct driver_data *dd)
* Delete our gendisk structure. This also removes the device
* from /dev
*/
- del_gendisk(dd->disk);
+ if (dd->disk) {
+ if (dd->disk->queue)
+ del_gendisk(dd->disk);
+ else
+ put_disk(dd->disk);
+ }
spin_lock(&rssd_index_lock);
ida_remove(&rssd_index_ida, dd->index);
@@ -3921,7 +3927,13 @@ static int mtip_block_shutdown(struct driver_data *dd)
"Shutting down %s ...\n", dd->disk->disk_name);
/* Delete our gendisk structure, and cleanup the blk queue. */
- del_gendisk(dd->disk);
+ if (dd->disk) {
+ if (dd->disk->queue)
+ del_gendisk(dd->disk);
+ else
+ put_disk(dd->disk);
+ }
+
spin_lock(&rssd_index_lock);
ida_remove(&rssd_index_ida, dd->index);
diff --git a/drivers/block/paride/Kconfig b/drivers/block/paride/Kconfig
index 28cf3082d442..efefb5ac3004 100644
--- a/drivers/block/paride/Kconfig
+++ b/drivers/block/paride/Kconfig
@@ -205,8 +205,8 @@ config PARIDE_EPAT
support.
config PARIDE_EPATC8
- bool "Support c7/c8 chips (EXPERIMENTAL)"
- depends on PARIDE_EPAT && EXPERIMENTAL
+ bool "Support c7/c8 chips"
+ depends on PARIDE_EPAT
help
This option enables support for the newer Shuttle EP1284 (aka c7 and
c8) chip. You need this if you are using any recent Imation SuperDisk
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 564156a8e572..5814deb6963d 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -461,7 +461,7 @@ static int generic_request(struct vdc_port *port, u8 op, void *buf, int len)
int op_len, err;
void *req_buf;
- if (!(((u64)1 << ((u64)op - 1)) & port->operations))
+ if (!(((u64)1 << (u64)op) & port->operations))
return -EOPNOTSUPP;
switch (op) {
diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 765fa2b3d337..8766a2257091 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -844,6 +844,7 @@ static int swim_floppy_init(struct swim_priv *swd)
swd->unit[drive].swd = swd;
}
+ spin_lock_init(&swd->lock);
swd->queue = blk_init_queue(do_fd_request, &swd->lock);
if (!swd->queue) {
err = -ENOMEM;
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index 74374fb762aa..5ac841ff6cc7 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -161,10 +161,12 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
static void make_response(struct xen_blkif *blkif, u64 id,
unsigned short op, int st);
-#define foreach_grant(pos, rbtree, node) \
- for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node); \
+#define foreach_grant_safe(pos, n, rbtree, node) \
+ for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node), \
+ (n) = rb_next(&(pos)->node); \
&(pos)->node != NULL; \
- (pos) = container_of(rb_next(&(pos)->node), typeof(*(pos)), node))
+ (pos) = container_of(n, typeof(*(pos)), node), \
+ (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL)
static void add_persistent_gnt(struct rb_root *root,
@@ -217,10 +219,11 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num)
struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
struct persistent_gnt *persistent_gnt;
+ struct rb_node *n;
int ret = 0;
int segs_to_unmap = 0;
- foreach_grant(persistent_gnt, root, node) {
+ foreach_grant_safe(persistent_gnt, n, root, node) {
BUG_ON(persistent_gnt->handle ==
BLKBACK_INVALID_HANDLE);
gnttab_set_unmap_op(&unmap[segs_to_unmap],
@@ -230,9 +233,6 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num)
persistent_gnt->handle);
pages[segs_to_unmap] = persistent_gnt->page;
- rb_erase(&persistent_gnt->node, root);
- kfree(persistent_gnt);
- num--;
if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST ||
!rb_next(&persistent_gnt->node)) {
@@ -241,6 +241,10 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num)
BUG_ON(ret);
segs_to_unmap = 0;
}
+
+ rb_erase(&persistent_gnt->node, root);
+ kfree(persistent_gnt);
+ num--;
}
BUG_ON(num != 0);
}
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 96e9b00db081..11043c18ac5a 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -792,6 +792,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)
{
struct llist_node *all_gnts;
struct grant *persistent_gnt;
+ struct llist_node *n;
/* Prevent new requests being issued until we fix things up. */
spin_lock_irq(&info->io_lock);
@@ -804,7 +805,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)
/* Remove all persistent grants */
if (info->persistent_gnts_c) {
all_gnts = llist_del_all(&info->persistent_gnts);
- llist_for_each_entry(persistent_gnt, all_gnts, node) {
+ llist_for_each_entry_safe(persistent_gnt, n, all_gnts, node) {
gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL);
__free_page(pfn_to_page(persistent_gnt->pfn));
kfree(persistent_gnt);
@@ -835,7 +836,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)
static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
struct blkif_response *bret)
{
- int i;
+ int i = 0;
struct bio_vec *bvec;
struct req_iterator iter;
unsigned long flags;
@@ -852,7 +853,8 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
*/
rq_for_each_segment(bvec, s->request, iter) {
BUG_ON((bvec->bv_offset + bvec->bv_len) > PAGE_SIZE);
- i = offset >> PAGE_SHIFT;
+ if (bvec->bv_offset < offset)
+ i++;
BUG_ON(i >= s->req.u.rw.nr_segments);
shared_data = kmap_atomic(
pfn_to_page(s->grants_used[i]->pfn));
@@ -861,7 +863,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
bvec->bv_len);
bvec_kunmap_irq(bvec_data, &flags);
kunmap_atomic(shared_data);
- offset += bvec->bv_len;
+ offset = bvec->bv_offset + bvec->bv_len;
}
}
/* Add the persistent grant into the list of free grants */
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index e9f203eadb1f..fdfd61a2d523 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -26,6 +26,7 @@ config BT_HCIBTSDIO
config BT_HCIUART
tristate "HCI UART driver"
+ depends on TTY
help
Bluetooth HCI UART driver.
This driver is required if you want to use Bluetooth devices with
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 33c9a44a9678..a8a41e07a221 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -349,7 +349,7 @@ static int ath3k_load_syscfg(struct usb_device *udev)
ret = ath3k_get_state(udev, &fw_state);
if (ret < 0) {
- BT_ERR("Can't get state to change to load configration err");
+ BT_ERR("Can't get state to change to load configuration err");
return -EBUSY;
}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 72bedad6bf8c..3bb6fa3930be 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -53,7 +53,7 @@ source "drivers/tty/serial/Kconfig"
config TTY_PRINTK
bool "TTY driver to output user messages via printk"
- depends on EXPERT
+ depends on EXPERT && TTY
default n
---help---
If you say Y here, the support for writing user messages (i.e.
@@ -159,7 +159,7 @@ source "drivers/tty/hvc/Kconfig"
config VIRTIO_CONSOLE
tristate "Virtio console"
- depends on VIRTIO
+ depends on VIRTIO && TTY
select HVC_DRIVER
help
Virtio console for use with lguest and other hypervisors.
@@ -392,6 +392,7 @@ config XILINX_HWICAP
config R3964
tristate "Siemens R3964 line discipline"
+ depends on TTY
---help---
This driver allows synchronous communication with devices using the
Siemens R3964 packet protocol. Unless you are dealing with special
@@ -439,7 +440,7 @@ source "drivers/char/pcmcia/Kconfig"
config MWAVE
tristate "ACP Modem (Mwave) support"
- depends on X86
+ depends on X86 && TTY
select SERIAL_8250
---help---
The ACP modem (Mwave) for Linux is a WinModem. It is composed of a
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index fe6d4be48296..e3f9a99b8522 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -1041,7 +1041,7 @@ static int hpet_acpi_add(struct acpi_device *device)
return hpet_alloc(&data);
}
-static int hpet_acpi_remove(struct acpi_device *device, int type)
+static int hpet_acpi_remove(struct acpi_device *device)
{
/* XXX need to unregister clocksource, dealloc mem, etc */
return -EINVAL;
diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c
index 48bbfeca4b5d..ac47631ab34f 100644
--- a/drivers/char/hw_random/exynos-rng.c
+++ b/drivers/char/hw_random/exynos-rng.c
@@ -104,6 +104,7 @@ static int exynos_read(struct hwrng *rng, void *buf,
static int exynos_rng_probe(struct platform_device *pdev)
{
struct exynos_rng *exynos_rng;
+ struct resource *res;
exynos_rng = devm_kzalloc(&pdev->dev, sizeof(struct exynos_rng),
GFP_KERNEL);
@@ -120,10 +121,10 @@ static int exynos_rng_probe(struct platform_device *pdev)
return -ENOENT;
}
- exynos_rng->mem = devm_request_and_ioremap(&pdev->dev,
- platform_get_resource(pdev, IORESOURCE_MEM, 0));
- if (!exynos_rng->mem)
- return -EBUSY;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ exynos_rng->mem = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(exynos_rng->mem))
+ return PTR_ERR(exynos_rng->mem);
platform_set_drvdata(pdev, exynos_rng);
@@ -162,7 +163,7 @@ static int exynos_rng_runtime_resume(struct device *dev)
}
-UNIVERSAL_DEV_PM_OPS(exynos_rng_pm_ops, exynos_rng_runtime_suspend,
+static UNIVERSAL_DEV_PM_OPS(exynos_rng_pm_ops, exynos_rng_runtime_suspend,
exynos_rng_runtime_resume, NULL);
static struct platform_driver exynos_rng_driver = {
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index d8c54e253761..749dc16ca2cc 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -124,9 +124,9 @@ static int omap_rng_probe(struct platform_device *pdev)
goto err_ioremap;
}
- priv->base = devm_request_and_ioremap(&pdev->dev, priv->mem_res);
- if (!priv->base) {
- ret = -ENOMEM;
+ priv->base = devm_ioremap_resource(&pdev->dev, priv->mem_res);
+ if (IS_ERR(priv->base)) {
+ ret = PTR_ERR(priv->base);
goto err_ioremap;
}
dev_set_drvdata(&pdev->dev, priv);
diff --git a/drivers/char/hw_random/tx4939-rng.c b/drivers/char/hw_random/tx4939-rng.c
index de473ef3882b..30991989d65b 100644
--- a/drivers/char/hw_random/tx4939-rng.c
+++ b/drivers/char/hw_random/tx4939-rng.c
@@ -7,6 +7,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -115,9 +116,9 @@ static int __init tx4939_rng_probe(struct platform_device *dev)
rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL);
if (!rngdev)
return -ENOMEM;
- rngdev->base = devm_request_and_ioremap(&dev->dev, r);
- if (!rngdev->base)
- return -EBUSY;
+ rngdev->base = devm_ioremap_resource(&dev->dev, r);
+ if (IS_ERR(rngdev->base))
+ return PTR_ERR(rngdev->base);
rngdev->rng.name = dev_name(&dev->dev);
rngdev->rng.data_present = tx4939_rng_data_present;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index c6fa3bc2baa8..6f6e92a3102d 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -399,7 +399,7 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
{
unsigned long p = *ppos;
ssize_t low_count, read, sz;
- char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
+ char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
int err = 0;
read = 0;
@@ -527,7 +527,7 @@ static ssize_t write_kmem(struct file *file, const char __user *buf,
unsigned long p = *ppos;
ssize_t wrote = 0;
ssize_t virtr = 0;
- char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
+ char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
int err = 0;
if (p < (unsigned long) high_memory) {
@@ -595,7 +595,7 @@ static ssize_t write_port(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long i = *ppos;
- const char __user * tmp = buf;
+ const char __user *tmp = buf;
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
@@ -729,7 +729,7 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
return ret;
}
-static int open_port(struct inode * inode, struct file * filp)
+static int open_port(struct inode *inode, struct file *filp)
{
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
@@ -898,7 +898,7 @@ static int __init chr_dev_init(void)
continue;
/*
- * Create /dev/port?
+ * Create /dev/port?
*/
if ((minor == DEVPORT_MINOR) && !arch_has_dev_port())
continue;
diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig
index 6614416a8623..2a166d56738a 100644
--- a/drivers/char/pcmcia/Kconfig
+++ b/drivers/char/pcmcia/Kconfig
@@ -7,7 +7,7 @@ menu "PCMCIA character devices"
config SYNCLINK_CS
tristate "SyncLink PC Card support"
- depends on PCMCIA
+ depends on PCMCIA && TTY
help
Enable support for the SyncLink PC Card serial adapter, running
asynchronous and HDLC communications up to 512Kbps. The port is
@@ -45,7 +45,7 @@ config CARDMAN_4040
config IPWIRELESS
tristate "IPWireless 3G UMTS PCMCIA card support"
- depends on PCMCIA && NETDEVICES
+ depends on PCMCIA && NETDEVICES && TTY
select PPP
help
This is a driver for 3G UMTS PCMCIA card from IPWireless company. In
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index b66eaa04f8cb..5c5cc00ebb07 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -102,8 +102,7 @@ static MGSL_PARAMS default_params = {
ASYNC_PARITY_NONE /* unsigned char parity; */
};
-typedef struct
-{
+typedef struct {
int count;
unsigned char status;
char data[1];
@@ -210,7 +209,7 @@ typedef struct _mgslpc_info {
char testing_irq;
unsigned int init_error; /* startup error (DIAGS) */
- char flag_buf[MAX_ASYNC_BUFFER_SIZE];
+ char *flag_buf;
bool drop_rts_on_tx_done;
struct _input_signal_events input_signal_events;
@@ -326,10 +325,10 @@ typedef struct _mgslpc_info {
#define write_reg16(info, reg, val) outw((val), (info)->io_base + (reg))
#define set_reg_bits(info, reg, mask) \
- write_reg(info, (reg), \
+ write_reg(info, (reg), \
(unsigned char) (read_reg(info, (reg)) | (mask)))
#define clear_reg_bits(info, reg, mask) \
- write_reg(info, (reg), \
+ write_reg(info, (reg), \
(unsigned char) (read_reg(info, (reg)) & ~(mask)))
/*
* interrupt enable/disable routines
@@ -356,10 +355,10 @@ static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short
}
#define port_irq_disable(info, mask) \
- { info->pim_value |= (mask); write_reg(info, PIM, info->pim_value); }
+ { info->pim_value |= (mask); write_reg(info, PIM, info->pim_value); }
#define port_irq_enable(info, mask) \
- { info->pim_value &= ~(mask); write_reg(info, PIM, info->pim_value); }
+ { info->pim_value &= ~(mask); write_reg(info, PIM, info->pim_value); }
static void rx_start(MGSLPC_INFO *info);
static void rx_stop(MGSLPC_INFO *info);
@@ -397,7 +396,7 @@ static int adapter_test(MGSLPC_INFO *info);
static int claim_resources(MGSLPC_INFO *info);
static void release_resources(MGSLPC_INFO *info);
-static void mgslpc_add_device(MGSLPC_INFO *info);
+static int mgslpc_add_device(MGSLPC_INFO *info);
static void mgslpc_remove_device(MGSLPC_INFO *info);
static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty);
@@ -514,49 +513,56 @@ static const struct tty_port_operations mgslpc_port_ops = {
static int mgslpc_probe(struct pcmcia_device *link)
{
- MGSLPC_INFO *info;
- int ret;
-
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgslpc_attach\n");
-
- info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
- if (!info) {
- printk("Error can't allocate device instance data\n");
- return -ENOMEM;
- }
-
- info->magic = MGSLPC_MAGIC;
- tty_port_init(&info->port);
- info->port.ops = &mgslpc_port_ops;
- INIT_WORK(&info->task, bh_handler);
- info->max_frame_size = 4096;
- info->port.close_delay = 5*HZ/10;
- info->port.closing_wait = 30*HZ;
- init_waitqueue_head(&info->status_event_wait_q);
- init_waitqueue_head(&info->event_wait_q);
- spin_lock_init(&info->lock);
- spin_lock_init(&info->netlock);
- memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
- info->idle_mode = HDLC_TXIDLE_FLAGS;
- info->imra_value = 0xffff;
- info->imrb_value = 0xffff;
- info->pim_value = 0xff;
-
- info->p_dev = link;
- link->priv = info;
-
- /* Initialize the struct pcmcia_device structure */
-
- ret = mgslpc_config(link);
- if (ret) {
- tty_port_destroy(&info->port);
- return ret;
- }
-
- mgslpc_add_device(info);
-
- return 0;
+ MGSLPC_INFO *info;
+ int ret;
+
+ if (debug_level >= DEBUG_LEVEL_INFO)
+ printk("mgslpc_attach\n");
+
+ info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
+ if (!info) {
+ printk("Error can't allocate device instance data\n");
+ return -ENOMEM;
+ }
+
+ info->magic = MGSLPC_MAGIC;
+ tty_port_init(&info->port);
+ info->port.ops = &mgslpc_port_ops;
+ INIT_WORK(&info->task, bh_handler);
+ info->max_frame_size = 4096;
+ info->port.close_delay = 5*HZ/10;
+ info->port.closing_wait = 30*HZ;
+ init_waitqueue_head(&info->status_event_wait_q);
+ init_waitqueue_head(&info->event_wait_q);
+ spin_lock_init(&info->lock);
+ spin_lock_init(&info->netlock);
+ memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
+ info->idle_mode = HDLC_TXIDLE_FLAGS;
+ info->imra_value = 0xffff;
+ info->imrb_value = 0xffff;
+ info->pim_value = 0xff;
+
+ info->p_dev = link;
+ link->priv = info;
+
+ /* Initialize the struct pcmcia_device structure */
+
+ ret = mgslpc_config(link);
+ if (ret != 0)
+ goto failed;
+
+ ret = mgslpc_add_device(info);
+ if (ret != 0)
+ goto failed_release;
+
+ return 0;
+
+failed_release:
+ mgslpc_release((u_long)link);
+failed:
+ tty_port_destroy(&info->port);
+ kfree(info);
+ return ret;
}
/* Card has been inserted.
@@ -569,35 +575,35 @@ static int mgslpc_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
static int mgslpc_config(struct pcmcia_device *link)
{
- MGSLPC_INFO *info = link->priv;
- int ret;
+ MGSLPC_INFO *info = link->priv;
+ int ret;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgslpc_config(0x%p)\n", link);
+ if (debug_level >= DEBUG_LEVEL_INFO)
+ printk("mgslpc_config(0x%p)\n", link);
- link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
- ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL);
- if (ret != 0)
- goto failed;
+ ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL);
+ if (ret != 0)
+ goto failed;
- link->config_index = 8;
- link->config_regs = PRESENT_OPTION;
+ link->config_index = 8;
+ link->config_regs = PRESENT_OPTION;
- ret = pcmcia_request_irq(link, mgslpc_isr);
- if (ret)
- goto failed;
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
+ ret = pcmcia_request_irq(link, mgslpc_isr);
+ if (ret)
+ goto failed;
+ ret = pcmcia_enable_device(link);
+ if (ret)
+ goto failed;
- info->io_base = link->resource[0]->start;
- info->irq_level = link->irq;
- return 0;
+ info->io_base = link->resource[0]->start;
+ info->irq_level = link->irq;
+ return 0;
failed:
- mgslpc_release((u_long)link);
- return -ENODEV;
+ mgslpc_release((u_long)link);
+ return -ENODEV;
}
/* Card has been removed.
@@ -703,12 +709,12 @@ static void tx_pause(struct tty_struct *tty)
if (mgslpc_paranoia_check(info, tty->name, "tx_pause"))
return;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("tx_pause(%s)\n",info->device_name);
+ printk("tx_pause(%s)\n", info->device_name);
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (info->tx_enabled)
- tx_stop(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ tx_stop(info);
+ spin_unlock_irqrestore(&info->lock, flags);
}
static void tx_release(struct tty_struct *tty)
@@ -719,12 +725,12 @@ static void tx_release(struct tty_struct *tty)
if (mgslpc_paranoia_check(info, tty->name, "tx_release"))
return;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("tx_release(%s)\n",info->device_name);
+ printk("tx_release(%s)\n", info->device_name);
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (!info->tx_enabled)
- tx_start(info, tty);
- spin_unlock_irqrestore(&info->lock,flags);
+ tx_start(info, tty);
+ spin_unlock_irqrestore(&info->lock, flags);
}
/* Return next bottom half action to perform.
@@ -735,7 +741,7 @@ static int bh_action(MGSLPC_INFO *info)
unsigned long flags;
int rc = 0;
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (info->pending_bh & BH_RECEIVE) {
info->pending_bh &= ~BH_RECEIVE;
@@ -754,7 +760,7 @@ static int bh_action(MGSLPC_INFO *info)
info->bh_requested = false;
}
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return rc;
}
@@ -765,11 +771,8 @@ static void bh_handler(struct work_struct *work)
struct tty_struct *tty;
int action;
- if (!info)
- return;
-
if (debug_level >= DEBUG_LEVEL_BH)
- printk( "%s(%d):bh_handler(%s) entry\n",
+ printk("%s(%d):bh_handler(%s) entry\n",
__FILE__,__LINE__,info->device_name);
info->bh_running = true;
@@ -778,8 +781,8 @@ static void bh_handler(struct work_struct *work)
while((action = bh_action(info)) != 0) {
/* Process work item */
- if ( debug_level >= DEBUG_LEVEL_BH )
- printk( "%s(%d):bh_handler() work item action=%d\n",
+ if (debug_level >= DEBUG_LEVEL_BH)
+ printk("%s(%d):bh_handler() work item action=%d\n",
__FILE__,__LINE__,action);
switch (action) {
@@ -802,7 +805,7 @@ static void bh_handler(struct work_struct *work)
tty_kref_put(tty);
if (debug_level >= DEBUG_LEVEL_BH)
- printk( "%s(%d):bh_handler(%s) exit\n",
+ printk("%s(%d):bh_handler(%s) exit\n",
__FILE__,__LINE__,info->device_name);
}
@@ -831,7 +834,7 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
RXBUF *buf = (RXBUF*)(info->rx_buf + (info->rx_put * info->rx_buf_size));
if (debug_level >= DEBUG_LEVEL_ISR)
- printk("%s(%d):rx_ready_hdlc(eom=%d)\n",__FILE__,__LINE__,eom);
+ printk("%s(%d):rx_ready_hdlc(eom=%d)\n", __FILE__, __LINE__, eom);
if (!info->rx_enabled)
return;
@@ -847,7 +850,8 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
if (eom) {
/* end of frame, get FIFO count from RBCL register */
- if (!(fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f)))
+ fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
+ if (fifo_count == 0)
fifo_count = 32;
} else
fifo_count = 32;
@@ -886,20 +890,13 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
issue_command(info, CHA, CMD_RXFIFO);
}
-static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
+static void rx_ready_async(MGSLPC_INFO *info, int tcd)
{
+ struct tty_port *port = &info->port;
unsigned char data, status, flag;
int fifo_count;
int work = 0;
- struct mgsl_icount *icount = &info->icount;
-
- if (!tty) {
- /* tty is not available anymore */
- issue_command(info, CHA, CMD_RXRESET);
- if (debug_level >= DEBUG_LEVEL_ISR)
- printk("%s(%d):rx_ready_async(tty=NULL)\n",__FILE__,__LINE__);
- return;
- }
+ struct mgsl_icount *icount = &info->icount;
if (tcd) {
/* early termination, get FIFO count from RBCL register */
@@ -913,7 +910,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
} else
fifo_count = 32;
- tty_buffer_request_room(tty, fifo_count);
+ tty_buffer_request_room(port, fifo_count);
/* Flush received async data to receive data buffer. */
while (fifo_count) {
data = read_reg(info, CHA + RXFIFO);
@@ -944,7 +941,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
else if (status & BIT6)
flag = TTY_FRAME;
}
- work += tty_insert_flip_char(tty, data, flag);
+ work += tty_insert_flip_char(port, data, flag);
}
issue_command(info, CHA, CMD_RXFIFO);
@@ -957,7 +954,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
}
if (work)
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(port);
}
@@ -1004,7 +1001,7 @@ static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty)
int c;
if (debug_level >= DEBUG_LEVEL_ISR)
- printk("%s(%d):tx_ready(%s)\n", __FILE__,__LINE__,info->device_name);
+ printk("%s(%d):tx_ready(%s)\n", __FILE__, __LINE__, info->device_name);
if (info->params.mode == MGSL_MODE_HDLC) {
if (!info->tx_active)
@@ -1217,7 +1214,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
if (info->params.mode == MGSL_MODE_HDLC)
rx_ready_hdlc(info, isr & IRQ_RXEOM);
else
- rx_ready_async(info, isr & IRQ_RXEOM, tty);
+ rx_ready_async(info, isr & IRQ_RXEOM);
}
/* transmit IRQs */
@@ -1249,7 +1246,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
*/
if (info->pending_bh && !info->bh_running && !info->bh_requested) {
- if ( debug_level >= DEBUG_LEVEL_ISR )
+ if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):%s queueing bh task.\n",
__FILE__,__LINE__,info->device_name);
schedule_work(&info->task);
@@ -1273,7 +1270,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
int retval = 0;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):startup(%s)\n",__FILE__,__LINE__,info->device_name);
+ printk("%s(%d):startup(%s)\n", __FILE__, __LINE__, info->device_name);
if (info->port.flags & ASYNC_INITIALIZED)
return 0;
@@ -1283,7 +1280,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
info->tx_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
if (!info->tx_buf) {
printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n",
- __FILE__,__LINE__,info->device_name);
+ __FILE__, __LINE__, info->device_name);
return -ENOMEM;
}
}
@@ -1298,15 +1295,15 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
retval = claim_resources(info);
/* perform existence check and diagnostics */
- if ( !retval )
+ if (!retval)
retval = adapter_test(info);
- if ( retval ) {
- if (capable(CAP_SYS_ADMIN) && tty)
+ if (retval) {
+ if (capable(CAP_SYS_ADMIN) && tty)
set_bit(TTY_IO_ERROR, &tty->flags);
release_resources(info);
- return retval;
- }
+ return retval;
+ }
/* program hardware for current parameters */
mgslpc_change_params(info, tty);
@@ -1330,7 +1327,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_shutdown(%s)\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
/* clear status wait queue because status changes */
/* can't happen after shutting down the hardware */
@@ -1344,7 +1341,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
info->tx_buf = NULL;
}
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
rx_stop(info);
tx_stop(info);
@@ -1352,12 +1349,12 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
/* TODO:disable interrupts instead of reset to preserve signal states */
reset_device(info);
- if (!tty || tty->termios.c_cflag & HUPCL) {
- info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
+ if (!tty || tty->termios.c_cflag & HUPCL) {
+ info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
set_signals(info);
}
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
release_resources(info);
@@ -1371,7 +1368,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
{
unsigned long flags;
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
rx_stop(info);
tx_stop(info);
@@ -1396,7 +1393,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
if (info->netcount || (tty && (tty->termios.c_cflag & CREAD)))
rx_start(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
}
/* Reconfigure adapter based on new parameters
@@ -1411,16 +1408,16 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_change_params(%s)\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
cflag = tty->termios.c_cflag;
- /* if B0 rate (hangup) specified then negate DTR and RTS */
- /* otherwise assert DTR and RTS */
- if (cflag & CBAUD)
- info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+ /* if B0 rate (hangup) specified then negate RTS and DTR */
+ /* otherwise assert RTS and DTR */
+ if (cflag & CBAUD)
+ info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
else
- info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+ info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
/* byte size and parity */
@@ -1463,7 +1460,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
info->params.data_rate = tty_get_baud_rate(tty);
}
- if ( info->params.data_rate ) {
+ if (info->params.data_rate) {
info->timeout = (32*HZ*bits_per_char) /
info->params.data_rate;
}
@@ -1498,8 +1495,8 @@ static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO) {
- printk( "%s(%d):mgslpc_put_char(%d) on %s\n",
- __FILE__,__LINE__,ch,info->device_name);
+ printk("%s(%d):mgslpc_put_char(%d) on %s\n",
+ __FILE__, __LINE__, ch, info->device_name);
}
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
@@ -1508,7 +1505,7 @@ static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
if (!info->tx_buf)
return 0;
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (info->params.mode == MGSL_MODE_ASYNC || !info->tx_active) {
if (info->tx_count < TXBUFSIZE - 1) {
@@ -1518,7 +1515,7 @@ static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
}
}
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return 1;
}
@@ -1531,8 +1528,8 @@ static void mgslpc_flush_chars(struct tty_struct *tty)
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk( "%s(%d):mgslpc_flush_chars() entry on %s tx_count=%d\n",
- __FILE__,__LINE__,info->device_name,info->tx_count);
+ printk("%s(%d):mgslpc_flush_chars() entry on %s tx_count=%d\n",
+ __FILE__, __LINE__, info->device_name, info->tx_count);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars"))
return;
@@ -1542,13 +1539,13 @@ static void mgslpc_flush_chars(struct tty_struct *tty)
return;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk( "%s(%d):mgslpc_flush_chars() entry on %s starting transmitter\n",
- __FILE__,__LINE__,info->device_name);
+ printk("%s(%d):mgslpc_flush_chars() entry on %s starting transmitter\n",
+ __FILE__, __LINE__, info->device_name);
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (!info->tx_active)
- tx_start(info, tty);
- spin_unlock_irqrestore(&info->lock,flags);
+ tx_start(info, tty);
+ spin_unlock_irqrestore(&info->lock, flags);
}
/* Send a block of data
@@ -1569,8 +1566,8 @@ static int mgslpc_write(struct tty_struct * tty,
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk( "%s(%d):mgslpc_write(%s) count=%d\n",
- __FILE__,__LINE__,info->device_name,count);
+ printk("%s(%d):mgslpc_write(%s) count=%d\n",
+ __FILE__, __LINE__, info->device_name, count);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") ||
!info->tx_buf)
@@ -1596,26 +1593,26 @@ static int mgslpc_write(struct tty_struct * tty,
memcpy(info->tx_buf + info->tx_put, buf, c);
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
info->tx_put = (info->tx_put + c) & (TXBUFSIZE-1);
info->tx_count += c;
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
buf += c;
count -= c;
ret += c;
}
start:
- if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
- spin_lock_irqsave(&info->lock,flags);
+ if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
+ spin_lock_irqsave(&info->lock, flags);
if (!info->tx_active)
- tx_start(info, tty);
- spin_unlock_irqrestore(&info->lock,flags);
- }
+ tx_start(info, tty);
+ spin_unlock_irqrestore(&info->lock, flags);
+ }
cleanup:
if (debug_level >= DEBUG_LEVEL_INFO)
- printk( "%s(%d):mgslpc_write(%s) returning=%d\n",
- __FILE__,__LINE__,info->device_name,ret);
+ printk("%s(%d):mgslpc_write(%s) returning=%d\n",
+ __FILE__, __LINE__, info->device_name, ret);
return ret;
}
@@ -1643,7 +1640,7 @@ static int mgslpc_write_room(struct tty_struct *tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_write_room(%s)=%d\n",
- __FILE__,__LINE__, info->device_name, ret);
+ __FILE__, __LINE__, info->device_name, ret);
return ret;
}
@@ -1656,7 +1653,7 @@ static int mgslpc_chars_in_buffer(struct tty_struct *tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_chars_in_buffer(%s)\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_chars_in_buffer"))
return 0;
@@ -1668,7 +1665,7 @@ static int mgslpc_chars_in_buffer(struct tty_struct *tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_chars_in_buffer(%s)=%d\n",
- __FILE__,__LINE__, info->device_name, rc);
+ __FILE__, __LINE__, info->device_name, rc);
return rc;
}
@@ -1682,15 +1679,15 @@ static void mgslpc_flush_buffer(struct tty_struct *tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_flush_buffer(%s) entry\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_buffer"))
return;
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
info->tx_count = info->tx_put = info->tx_get = 0;
del_timer(&info->tx_timer);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
@@ -1705,17 +1702,17 @@ static void mgslpc_send_xchar(struct tty_struct *tty, char ch)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_send_xchar(%s,%d)\n",
- __FILE__,__LINE__, info->device_name, ch );
+ __FILE__, __LINE__, info->device_name, ch);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_send_xchar"))
return;
info->x_char = ch;
if (ch) {
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (!info->tx_enabled)
- tx_start(info, tty);
- spin_unlock_irqrestore(&info->lock,flags);
+ tx_start(info, tty);
+ spin_unlock_irqrestore(&info->lock, flags);
}
}
@@ -1728,7 +1725,7 @@ static void mgslpc_throttle(struct tty_struct * tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_throttle(%s) entry\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_throttle"))
return;
@@ -1736,11 +1733,11 @@ static void mgslpc_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
mgslpc_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios.c_cflag & CRTSCTS) {
- spin_lock_irqsave(&info->lock,flags);
+ if (tty->termios.c_cflag & CRTSCTS) {
+ spin_lock_irqsave(&info->lock, flags);
info->serial_signals &= ~SerialSignal_RTS;
- set_signals(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
}
}
@@ -1753,7 +1750,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_unthrottle(%s) entry\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_unthrottle"))
return;
@@ -1765,11 +1762,11 @@ static void mgslpc_unthrottle(struct tty_struct * tty)
mgslpc_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios.c_cflag & CRTSCTS) {
- spin_lock_irqsave(&info->lock,flags);
+ if (tty->termios.c_cflag & CRTSCTS) {
+ spin_lock_irqsave(&info->lock, flags);
info->serial_signals |= SerialSignal_RTS;
- set_signals(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
}
}
@@ -1807,33 +1804,33 @@ static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params)
*
* Arguments:
*
- * info pointer to device instance data
- * new_params user buffer containing new serial params
+ * info pointer to device instance data
+ * new_params user buffer containing new serial params
*
* Returns: 0 if success, otherwise error code
*/
static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params, struct tty_struct *tty)
{
- unsigned long flags;
+ unsigned long flags;
MGSL_PARAMS tmp_params;
int err;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):set_params %s\n", __FILE__,__LINE__,
- info->device_name );
+ info->device_name);
COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS));
if (err) {
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):set_params(%s) user buffer copy failed\n",
- __FILE__,__LINE__,info->device_name);
+ if (debug_level >= DEBUG_LEVEL_INFO)
+ printk("%s(%d):set_params(%s) user buffer copy failed\n",
+ __FILE__, __LINE__, info->device_name);
return -EFAULT;
}
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
- mgslpc_change_params(info, tty);
+ mgslpc_change_params(info, tty);
return 0;
}
@@ -1851,13 +1848,13 @@ static int get_txidle(MGSLPC_INFO * info, int __user *idle_mode)
static int set_txidle(MGSLPC_INFO * info, int idle_mode)
{
- unsigned long flags;
+ unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("set_txidle(%s,%d)\n", info->device_name, idle_mode);
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
info->idle_mode = idle_mode;
tx_set_idle(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return 0;
}
@@ -1874,11 +1871,11 @@ static int get_interface(MGSLPC_INFO * info, int __user *if_mode)
static int set_interface(MGSLPC_INFO * info, int if_mode)
{
- unsigned long flags;
+ unsigned long flags;
unsigned char val;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("set_interface(%s,%d)\n", info->device_name, if_mode);
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
info->if_mode = if_mode;
val = read_reg(info, PVR) & 0x0f;
@@ -1890,18 +1887,18 @@ static int set_interface(MGSLPC_INFO * info, int if_mode)
}
write_reg(info, PVR, val);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return 0;
}
static int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty)
{
- unsigned long flags;
+ unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("set_txenable(%s,%d)\n", info->device_name, enable);
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (enable) {
if (!info->tx_enabled)
tx_start(info, tty);
@@ -1909,18 +1906,18 @@ static int set_txenable(MGSLPC_INFO * info, int enable, struct tty_struct *tty)
if (info->tx_enabled)
tx_stop(info);
}
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return 0;
}
static int tx_abort(MGSLPC_INFO * info)
{
- unsigned long flags;
+ unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("tx_abort(%s)\n", info->device_name);
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (info->tx_active && info->tx_count &&
info->params.mode == MGSL_MODE_HDLC) {
/* clear data count so FIFO is not filled on next IRQ.
@@ -1929,18 +1926,18 @@ static int tx_abort(MGSLPC_INFO * info)
info->tx_count = info->tx_put = info->tx_get = 0;
info->tx_aborting = true;
}
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return 0;
}
static int set_rxenable(MGSLPC_INFO * info, int enable)
{
- unsigned long flags;
+ unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("set_rxenable(%s,%d)\n", info->device_name, enable);
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (enable) {
if (!info->rx_enabled)
rx_start(info);
@@ -1948,21 +1945,21 @@ static int set_rxenable(MGSLPC_INFO * info, int enable)
if (info->rx_enabled)
rx_stop(info);
}
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return 0;
}
/* wait for specified event to occur
*
- * Arguments: info pointer to device instance data
- * mask pointer to bitmask of events to wait for
- * Return Value: 0 if successful and bit mask updated with
+ * Arguments: info pointer to device instance data
+ * mask pointer to bitmask of events to wait for
+ * Return Value: 0 if successful and bit mask updated with
* of events triggerred,
- * otherwise error code
+ * otherwise error code
*/
static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr)
{
- unsigned long flags;
+ unsigned long flags;
int s;
int rc=0;
struct mgsl_icount cprev, cnow;
@@ -1978,18 +1975,18 @@ static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("wait_events(%s,%d)\n", info->device_name, mask);
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
/* return immediately if state matches requested events */
get_signals(info);
s = info->serial_signals;
events = mask &
( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
- ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
+ ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) );
if (events) {
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
goto exit;
}
@@ -2004,7 +2001,7 @@ static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr)
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&info->event_wait_q, &wait);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
for(;;) {
@@ -2015,11 +2012,11 @@ static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr)
}
/* get current irq counts */
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
cnow = info->icount;
newsigs = info->input_signal_events;
set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
/* if no change, wait aborted for some reason */
if (newsigs.dsr_up == oldsigs.dsr_up &&
@@ -2058,10 +2055,10 @@ static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr)
set_current_state(TASK_RUNNING);
if (mask & MgslEvent_ExitHuntMode) {
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (!waitqueue_active(&info->event_wait_q))
irq_disable(info, CHA, IRQ_EXITHUNT);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
}
exit:
if (rc == 0)
@@ -2071,17 +2068,17 @@ exit:
static int modem_input_wait(MGSLPC_INFO *info,int arg)
{
- unsigned long flags;
+ unsigned long flags;
int rc;
struct mgsl_icount cprev, cnow;
DECLARE_WAITQUEUE(wait, current);
/* save current irq counts */
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
cprev = info->icount;
add_wait_queue(&info->status_event_wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
for(;;) {
schedule();
@@ -2091,10 +2088,10 @@ static int modem_input_wait(MGSLPC_INFO *info,int arg)
}
/* get new irq counts */
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
cnow = info->icount;
set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
/* if no change, wait aborted for some reason */
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
@@ -2125,11 +2122,11 @@ static int tiocmget(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned int result;
- unsigned long flags;
+ unsigned long flags;
- spin_lock_irqsave(&info->lock,flags);
- get_signals(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
+ get_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) +
((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) +
@@ -2140,7 +2137,7 @@ static int tiocmget(struct tty_struct *tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s tiocmget() value=%08X\n",
- __FILE__,__LINE__, info->device_name, result );
+ __FILE__, __LINE__, info->device_name, result);
return result;
}
@@ -2150,11 +2147,11 @@ static int tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
- unsigned long flags;
+ unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s tiocmset(%x,%x)\n",
- __FILE__,__LINE__,info->device_name, set, clear);
+ __FILE__, __LINE__, info->device_name, set, clear);
if (set & TIOCM_RTS)
info->serial_signals |= SerialSignal_RTS;
@@ -2165,9 +2162,9 @@ static int tiocmset(struct tty_struct *tty,
if (clear & TIOCM_DTR)
info->serial_signals &= ~SerialSignal_DTR;
- spin_lock_irqsave(&info->lock,flags);
- set_signals(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
return 0;
}
@@ -2184,17 +2181,17 @@ static int mgslpc_break(struct tty_struct *tty, int break_state)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_break(%s,%d)\n",
- __FILE__,__LINE__, info->device_name, break_state);
+ __FILE__, __LINE__, info->device_name, break_state);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_break"))
return -EINVAL;
- spin_lock_irqsave(&info->lock,flags);
- if (break_state == -1)
+ spin_lock_irqsave(&info->lock, flags);
+ if (break_state == -1)
set_reg_bits(info, CHA+DAFO, BIT6);
else
clear_reg_bits(info, CHA+DAFO, BIT6);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return 0;
}
@@ -2205,9 +2202,9 @@ static int mgslpc_get_icount(struct tty_struct *tty,
struct mgsl_icount cnow; /* kernel counter temps */
unsigned long flags;
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
cnow = info->icount;
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
icount->cts = cnow.cts;
icount->dsr = cnow.dsr;
@@ -2228,9 +2225,9 @@ static int mgslpc_get_icount(struct tty_struct *tty,
*
* Arguments:
*
- * tty pointer to tty instance data
- * cmd IOCTL command code
- * arg command argument/context
+ * tty pointer to tty instance data
+ * cmd IOCTL command code
+ * arg command argument/context
*
* Return Value: 0 if success, otherwise error code
*/
@@ -2241,8 +2238,8 @@ static int mgslpc_ioctl(struct tty_struct *tty,
void __user *argp = (void __user *)arg;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
- info->device_name, cmd );
+ printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__, __LINE__,
+ info->device_name, cmd);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_ioctl"))
return -ENODEV;
@@ -2288,8 +2285,8 @@ static int mgslpc_ioctl(struct tty_struct *tty,
*
* Arguments:
*
- * tty pointer to tty structure
- * termios pointer to buffer to hold returned old termios
+ * tty pointer to tty structure
+ * termios pointer to buffer to hold returned old termios
*/
static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
@@ -2297,8 +2294,8 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgslpc_set_termios %s\n", __FILE__,__LINE__,
- tty->driver->name );
+ printk("%s(%d):mgslpc_set_termios %s\n", __FILE__, __LINE__,
+ tty->driver->name);
/* just return if nothing has changed */
if ((tty->termios.c_cflag == old_termios->c_cflag)
@@ -2311,23 +2308,23 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
!(tty->termios.c_cflag & CBAUD)) {
- info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
- spin_lock_irqsave(&info->lock,flags);
- set_signals(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
+ spin_lock_irqsave(&info->lock, flags);
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
}
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
tty->termios.c_cflag & CBAUD) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios.c_cflag & CRTSCTS) ||
- !test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
+ !test_bit(TTY_THROTTLED, &tty->flags)) {
info->serial_signals |= SerialSignal_RTS;
- }
- spin_lock_irqsave(&info->lock,flags);
- set_signals(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ }
+ spin_lock_irqsave(&info->lock, flags);
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
}
/* Handle turning off CRTSCTS */
@@ -2348,15 +2345,15 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_close(%s) entry, count=%d\n",
- __FILE__,__LINE__, info->device_name, port->count);
+ __FILE__, __LINE__, info->device_name, port->count);
WARN_ON(!port->count);
if (tty_port_close_start(port, tty, filp) == 0)
goto cleanup;
- if (port->flags & ASYNC_INITIALIZED)
- mgslpc_wait_until_sent(tty, info->timeout);
+ if (port->flags & ASYNC_INITIALIZED)
+ mgslpc_wait_until_sent(tty, info->timeout);
mgslpc_flush_buffer(tty);
@@ -2367,7 +2364,7 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp)
tty_port_tty_set(port, NULL);
cleanup:
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__,__LINE__,
+ printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__, __LINE__,
tty->driver->name, port->count);
}
@@ -2378,12 +2375,12 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
unsigned long orig_jiffies, char_time;
- if (!info )
+ if (!info)
return;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_wait_until_sent(%s) entry\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent"))
return;
@@ -2399,8 +2396,8 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
* Note: use tight timings here to satisfy the NIST-PCTS.
*/
- if ( info->params.data_rate ) {
- char_time = info->timeout/(32 * 5);
+ if (info->params.data_rate) {
+ char_time = info->timeout/(32 * 5);
if (!char_time)
char_time++;
} else
@@ -2431,7 +2428,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
exit:
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_wait_until_sent(%s) exit\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
}
/* Called by tty_hangup() when a hangup is signaled.
@@ -2443,7 +2440,7 @@ static void mgslpc_hangup(struct tty_struct *tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_hangup(%s)\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_hangup"))
return;
@@ -2458,9 +2455,9 @@ static int carrier_raised(struct tty_port *port)
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
unsigned long flags;
- spin_lock_irqsave(&info->lock,flags);
- get_signals(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
+ get_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
if (info->serial_signals & SerialSignal_DCD)
return 1;
@@ -2472,13 +2469,13 @@ static void dtr_rts(struct tty_port *port, int onoff)
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
unsigned long flags;
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (onoff)
- info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+ info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
else
- info->serial_signals &= ~SerialSignal_RTS + SerialSignal_DTR;
+ info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
set_signals(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
}
@@ -2486,14 +2483,14 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
{
MGSLPC_INFO *info;
struct tty_port *port;
- int retval, line;
- unsigned long flags;
+ int retval, line;
+ unsigned long flags;
/* verify range of specified line number */
line = tty->index;
if (line >= mgslpc_device_count) {
printk("%s(%d):mgslpc_open with invalid line #%d.\n",
- __FILE__,__LINE__,line);
+ __FILE__, __LINE__, line);
return -ENODEV;
}
@@ -2510,7 +2507,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
- __FILE__,__LINE__,tty->driver->name, port->count);
+ __FILE__, __LINE__, tty->driver->name, port->count);
/* If port is closing, signal caller to try again */
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING){
@@ -2521,7 +2518,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
goto cleanup;
}
- tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
spin_lock_irqsave(&info->netlock, flags);
if (info->netcount) {
@@ -2545,13 +2542,13 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
if (retval) {
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready(%s) returned %d\n",
- __FILE__,__LINE__, info->device_name, retval);
+ __FILE__, __LINE__, info->device_name, retval);
goto cleanup;
}
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_open(%s) success\n",
- __FILE__,__LINE__, info->device_name);
+ __FILE__, __LINE__, info->device_name);
retval = 0;
cleanup:
@@ -2571,9 +2568,9 @@ static inline void line_info(struct seq_file *m, MGSLPC_INFO *info)
info->device_name, info->io_base, info->irq_level);
/* output current serial signal states */
- spin_lock_irqsave(&info->lock,flags);
- get_signals(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
+ get_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
stat_buf[0] = 0;
stat_buf[1] = 0;
@@ -2635,7 +2632,7 @@ static int mgslpc_proc_show(struct seq_file *m, void *v)
seq_printf(m, "synclink driver:%s\n", driver_version);
info = mgslpc_device_list;
- while( info ) {
+ while (info) {
line_info(m, info);
info = info->next_device;
}
@@ -2674,6 +2671,14 @@ static int rx_alloc_buffers(MGSLPC_INFO *info)
if (info->rx_buf == NULL)
return -ENOMEM;
+ /* unused flag buffer to satisfy receive_buf calling interface */
+ info->flag_buf = kzalloc(info->max_frame_size, GFP_KERNEL);
+ if (!info->flag_buf) {
+ kfree(info->rx_buf);
+ info->rx_buf = NULL;
+ return -ENOMEM;
+ }
+
rx_reset_buffers(info);
return 0;
}
@@ -2682,12 +2687,14 @@ static void rx_free_buffers(MGSLPC_INFO *info)
{
kfree(info->rx_buf);
info->rx_buf = NULL;
+ kfree(info->flag_buf);
+ info->flag_buf = NULL;
}
static int claim_resources(MGSLPC_INFO *info)
{
- if (rx_alloc_buffers(info) < 0 ) {
- printk( "Can't allocate rx buffer %s\n", info->device_name);
+ if (rx_alloc_buffers(info) < 0) {
+ printk("Can't allocate rx buffer %s\n", info->device_name);
release_resources(info);
return -ENODEV;
}
@@ -2706,8 +2713,12 @@ static void release_resources(MGSLPC_INFO *info)
*
* Arguments: info pointer to device instance data
*/
-static void mgslpc_add_device(MGSLPC_INFO *info)
+static int mgslpc_add_device(MGSLPC_INFO *info)
{
+ MGSLPC_INFO *current_dev = NULL;
+ struct device *tty_dev;
+ int ret;
+
info->next_device = NULL;
info->line = mgslpc_device_count;
sprintf(info->device_name,"ttySLP%d",info->line);
@@ -2722,8 +2733,8 @@ static void mgslpc_add_device(MGSLPC_INFO *info)
if (!mgslpc_device_list)
mgslpc_device_list = info;
else {
- MGSLPC_INFO *current_dev = mgslpc_device_list;
- while( current_dev->next_device )
+ current_dev = mgslpc_device_list;
+ while (current_dev->next_device)
current_dev = current_dev->next_device;
current_dev->next_device = info;
}
@@ -2733,14 +2744,34 @@ static void mgslpc_add_device(MGSLPC_INFO *info)
else if (info->max_frame_size > 65535)
info->max_frame_size = 65535;
- printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n",
+ printk("SyncLink PC Card %s:IO=%04X IRQ=%d\n",
info->device_name, info->io_base, info->irq_level);
#if SYNCLINK_GENERIC_HDLC
- hdlcdev_init(info);
+ ret = hdlcdev_init(info);
+ if (ret != 0)
+ goto failed;
#endif
- tty_port_register_device(&info->port, serial_driver, info->line,
+
+ tty_dev = tty_port_register_device(&info->port, serial_driver, info->line,
&info->p_dev->dev);
+ if (IS_ERR(tty_dev)) {
+ ret = PTR_ERR(tty_dev);
+#if SYNCLINK_GENERIC_HDLC
+ hdlcdev_exit(info);
+#endif
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ if (current_dev)
+ current_dev->next_device = NULL;
+ else
+ mgslpc_device_list = NULL;
+ mgslpc_device_count--;
+ return ret;
}
static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
@@ -3262,7 +3293,7 @@ static void rx_stop(MGSLPC_INFO *info)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):rx_stop(%s)\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
/* MODE:03 RAC Receiver Active, 0=inactive */
clear_reg_bits(info, CHA + MODE, BIT3);
@@ -3275,7 +3306,7 @@ static void rx_start(MGSLPC_INFO *info)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):rx_start(%s)\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
rx_reset_buffers(info);
info->rx_enabled = false;
@@ -3291,7 +3322,7 @@ static void tx_start(MGSLPC_INFO *info, struct tty_struct *tty)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):tx_start(%s)\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
if (info->tx_count) {
/* If auto RTS enabled and RTS is inactive, then assert */
@@ -3329,7 +3360,7 @@ static void tx_stop(MGSLPC_INFO *info)
{
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):tx_stop(%s)\n",
- __FILE__,__LINE__, info->device_name );
+ __FILE__, __LINE__, info->device_name);
del_timer(&info->tx_timer);
@@ -3575,8 +3606,8 @@ static void get_signals(MGSLPC_INFO *info)
{
unsigned char status = 0;
- /* preserve DTR and RTS */
- info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS;
+ /* preserve RTS and DTR */
+ info->serial_signals &= SerialSignal_RTS | SerialSignal_DTR;
if (read_reg(info, CHB + VSTR) & BIT7)
info->serial_signals |= SerialSignal_DCD;
@@ -3590,7 +3621,7 @@ static void get_signals(MGSLPC_INFO *info)
info->serial_signals |= SerialSignal_DSR;
}
-/* Set the state of DTR and RTS based on contents of
+/* Set the state of RTS and DTR based on contents of
* serial_signals member of device extension.
*/
static void set_signals(MGSLPC_INFO *info)
@@ -3681,7 +3712,7 @@ static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty)
if (debug_level >= DEBUG_LEVEL_BH)
printk("%s(%d):rx_get_frame(%s) status=%04X size=%d\n",
- __FILE__,__LINE__,info->device_name,status,framesize);
+ __FILE__, __LINE__, info->device_name, status, framesize);
if (debug_level >= DEBUG_LEVEL_DATA)
trace_block(info, buf->data, framesize, 0);
@@ -3709,13 +3740,13 @@ static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty)
}
}
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
buf->status = buf->count = 0;
info->rx_frame_count--;
info->rx_get++;
if (info->rx_get >= info->rx_buf_count)
info->rx_get = 0;
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return true;
}
@@ -3729,7 +3760,7 @@ static bool register_test(MGSLPC_INFO *info)
bool rc = true;
unsigned long flags;
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
reset_device(info);
for (i = 0; i < count; i++) {
@@ -3742,7 +3773,7 @@ static bool register_test(MGSLPC_INFO *info)
}
}
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return rc;
}
@@ -3751,7 +3782,7 @@ static bool irq_test(MGSLPC_INFO *info)
unsigned long end_time;
unsigned long flags;
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
reset_device(info);
info->testing_irq = true;
@@ -3765,7 +3796,7 @@ static bool irq_test(MGSLPC_INFO *info)
write_reg(info, CHA + TIMR, 0); /* 512 cycles */
issue_command(info, CHA, CMD_START_TIMER);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
end_time=100;
while(end_time-- && !info->irq_occurred) {
@@ -3774,9 +3805,9 @@ static bool irq_test(MGSLPC_INFO *info)
info->testing_irq = false;
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
reset_device(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return info->irq_occurred;
}
@@ -3785,21 +3816,21 @@ static int adapter_test(MGSLPC_INFO *info)
{
if (!register_test(info)) {
info->init_error = DiagStatus_AddressFailure;
- printk( "%s(%d):Register test failure for device %s Addr=%04X\n",
- __FILE__,__LINE__,info->device_name, (unsigned short)(info->io_base) );
+ printk("%s(%d):Register test failure for device %s Addr=%04X\n",
+ __FILE__, __LINE__, info->device_name, (unsigned short)(info->io_base));
return -ENODEV;
}
if (!irq_test(info)) {
info->init_error = DiagStatus_IrqFailure;
- printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n",
- __FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) );
+ printk("%s(%d):Interrupt test failure for device %s IRQ=%d\n",
+ __FILE__, __LINE__, info->device_name, (unsigned short)(info->irq_level));
return -ENODEV;
}
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):device %s passed diagnostics\n",
- __FILE__,__LINE__,info->device_name);
+ __FILE__, __LINE__, info->device_name);
return 0;
}
@@ -3808,9 +3839,9 @@ static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
int i;
int linecount;
if (xmit)
- printk("%s tx data:\n",info->device_name);
+ printk("%s tx data:\n", info->device_name);
else
- printk("%s rx data:\n",info->device_name);
+ printk("%s rx data:\n", info->device_name);
while(count) {
if (count > 16)
@@ -3819,12 +3850,12 @@ static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
linecount = count;
for(i=0;i<linecount;i++)
- printk("%02X ",(unsigned char)data[i]);
+ printk("%02X ", (unsigned char)data[i]);
for(;i<17;i++)
printk(" ");
for(i=0;i<linecount;i++) {
if (data[i]>=040 && data[i]<=0176)
- printk("%c",data[i]);
+ printk("%c", data[i]);
else
printk(".");
}
@@ -3843,18 +3874,18 @@ static void tx_timeout(unsigned long context)
MGSLPC_INFO *info = (MGSLPC_INFO*)context;
unsigned long flags;
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk( "%s(%d):tx_timeout(%s)\n",
- __FILE__,__LINE__,info->device_name);
- if(info->tx_active &&
- info->params.mode == MGSL_MODE_HDLC) {
+ if (debug_level >= DEBUG_LEVEL_INFO)
+ printk("%s(%d):tx_timeout(%s)\n",
+ __FILE__, __LINE__, info->device_name);
+ if (info->tx_active &&
+ info->params.mode == MGSL_MODE_HDLC) {
info->icount.txtimeout++;
}
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
info->tx_active = false;
info->tx_count = info->tx_put = info->tx_get = 0;
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
#if SYNCLINK_GENERIC_HDLC
if (info->netcount)
@@ -3936,7 +3967,7 @@ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name);
+ printk(KERN_INFO "%s:hdlc_xmit(%s)\n", __FILE__, dev->name);
/* stop sending until this frame completes */
netif_stop_queue(dev);
@@ -3957,13 +3988,13 @@ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
dev->trans_start = jiffies;
/* start hardware transmitter if necessary */
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
if (!info->tx_active) {
struct tty_struct *tty = tty_port_tty_get(&info->port);
- tx_start(info, tty);
- tty_kref_put(tty);
+ tx_start(info, tty);
+ tty_kref_put(tty);
}
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
return NETDEV_TX_OK;
}
@@ -3984,10 +4015,11 @@ static int hdlcdev_open(struct net_device *dev)
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name);
+ printk("%s:hdlcdev_open(%s)\n", __FILE__, dev->name);
/* generic HDLC layer open processing */
- if ((rc = hdlc_open(dev)))
+ rc = hdlc_open(dev);
+ if (rc != 0)
return rc;
/* arbitrate between network and tty opens */
@@ -4002,15 +4034,16 @@ static int hdlcdev_open(struct net_device *dev)
tty = tty_port_tty_get(&info->port);
/* claim resources and init adapter */
- if ((rc = startup(info, tty)) != 0) {
+ rc = startup(info, tty);
+ if (rc != 0) {
tty_kref_put(tty);
spin_lock_irqsave(&info->netlock, flags);
info->netcount=0;
spin_unlock_irqrestore(&info->netlock, flags);
return rc;
}
- /* assert DTR and RTS, apply hardware settings */
- info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
+ /* assert RTS and DTR, apply hardware settings */
+ info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
mgslpc_program_hw(info, tty);
tty_kref_put(tty);
@@ -4044,7 +4077,7 @@ static int hdlcdev_close(struct net_device *dev)
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name);
+ printk("%s:hdlcdev_close(%s)\n", __FILE__, dev->name);
netif_stop_queue(dev);
@@ -4078,7 +4111,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
unsigned int flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name);
+ printk("%s:hdlcdev_ioctl(%s)\n", __FILE__, dev->name);
/* return error if TTY interface open */
if (info->port.count)
@@ -4179,14 +4212,14 @@ static void hdlcdev_tx_timeout(struct net_device *dev)
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("hdlcdev_tx_timeout(%s)\n",dev->name);
+ printk("hdlcdev_tx_timeout(%s)\n", dev->name);
dev->stats.tx_errors++;
dev->stats.tx_aborted_errors++;
- spin_lock_irqsave(&info->lock,flags);
+ spin_lock_irqsave(&info->lock, flags);
tx_stop(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ spin_unlock_irqrestore(&info->lock, flags);
netif_wake_queue(dev);
}
@@ -4217,7 +4250,7 @@ static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size)
struct net_device *dev = info->netdev;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("hdlcdev_rx(%s)\n",dev->name);
+ printk("hdlcdev_rx(%s)\n", dev->name);
if (skb == NULL) {
printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name);
@@ -4260,8 +4293,9 @@ static int hdlcdev_init(MGSLPC_INFO *info)
/* allocate and initialize network and HDLC layer objects */
- if (!(dev = alloc_hdlcdev(info))) {
- printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__);
+ dev = alloc_hdlcdev(info);
+ if (dev == NULL) {
+ printk(KERN_ERR "%s:hdlc device allocation failure\n", __FILE__);
return -ENOMEM;
}
@@ -4280,8 +4314,9 @@ static int hdlcdev_init(MGSLPC_INFO *info)
hdlc->xmit = hdlcdev_xmit;
/* register objects with HDLC layer */
- if ((rc = register_hdlc_device(dev))) {
- printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
+ rc = register_hdlc_device(dev);
+ if (rc) {
+ printk(KERN_WARNING "%s:unable to register hdlc device\n", __FILE__);
free_netdev(dev);
return rc;
}
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 85e81ec1451e..594bda9dcfc8 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -445,7 +445,7 @@ static struct entropy_store input_pool = {
.poolinfo = &poolinfo_table[0],
.name = "input",
.limit = 1,
- .lock = __SPIN_LOCK_UNLOCKED(&input_pool.lock),
+ .lock = __SPIN_LOCK_UNLOCKED(input_pool.lock),
.pool = input_pool_data
};
@@ -454,7 +454,7 @@ static struct entropy_store blocking_pool = {
.name = "blocking",
.limit = 1,
.pull = &input_pool,
- .lock = __SPIN_LOCK_UNLOCKED(&blocking_pool.lock),
+ .lock = __SPIN_LOCK_UNLOCKED(blocking_pool.lock),
.pool = blocking_pool_data
};
@@ -462,7 +462,7 @@ static struct entropy_store nonblocking_pool = {
.poolinfo = &poolinfo_table[1],
.name = "nonblocking",
.pull = &input_pool,
- .lock = __SPIN_LOCK_UNLOCKED(&nonblocking_pool.lock),
+ .lock = __SPIN_LOCK_UNLOCKED(nonblocking_pool.lock),
.pool = nonblocking_pool_data
};
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index d780295a1473..6386a98e43c1 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -1142,7 +1142,7 @@ static int sonypi_acpi_add(struct acpi_device *device)
return 0;
}
-static int sonypi_acpi_remove(struct acpi_device *device, int type)
+static int sonypi_acpi_remove(struct acpi_device *device)
{
sonypi_acpi_device = NULL;
return 0;
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 915875e431d2..dbfd56446c31 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -75,10 +75,20 @@ config TCG_INFINEON
config TCG_IBMVTPM
tristate "IBM VTPM Interface"
- depends on PPC64
+ depends on PPC_PSERIES
---help---
If you have IBM virtual TPM (VTPM) support say Yes and it
will be accessible from within Linux. To compile this driver
as a module, choose M here; the module will be called tpm_ibmvtpm.
+config TCG_ST33_I2C
+ tristate "STMicroelectronics ST33 I2C TPM"
+ depends on I2C
+ depends on GPIOLIB
+ ---help---
+ If you have a TPM security chip from STMicroelectronics working with
+ an I2C bus say Yes and it will be accessible from within Linux.
+ To compile this driver as a module, choose M here; the module will be
+ called tpm_stm_st33_i2c.
+
endif # TCG_TPM
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 5b3fc8bc6c13..a3736c97c65a 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
+obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 93211df52aab..0d2e82f95577 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -40,8 +40,9 @@ enum tpm_duration {
};
#define TPM_MAX_ORDINAL 243
-#define TPM_MAX_PROTECTED_ORDINAL 12
-#define TPM_PROTECTED_ORDINAL_MASK 0xFF
+#define TSC_MAX_ORDINAL 12
+#define TPM_PROTECTED_COMMAND 0x00
+#define TPM_CONNECTION_COMMAND 0x40
/*
* Bug workaround - some TPM's don't flush the most
@@ -65,21 +66,6 @@ static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
* values of the SHORT, MEDIUM, and LONG durations are retrieved
* from the chip during initialization with a call to tpm_get_timeouts.
*/
-static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
- TPM_UNDEFINED, /* 0 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 5 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 10 */
- TPM_SHORT,
-};
-
static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
TPM_UNDEFINED, /* 0 */
TPM_UNDEFINED,
@@ -351,14 +337,11 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
{
int duration_idx = TPM_UNDEFINED;
int duration = 0;
+ u8 category = (ordinal >> 24) & 0xFF;
- if (ordinal < TPM_MAX_ORDINAL)
+ if ((category == TPM_PROTECTED_COMMAND && ordinal < TPM_MAX_ORDINAL) ||
+ (category == TPM_CONNECTION_COMMAND && ordinal < TSC_MAX_ORDINAL))
duration_idx = tpm_ordinal_duration[ordinal];
- else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
- TPM_MAX_PROTECTED_ORDINAL)
- duration_idx =
- tpm_protected_ordinal_duration[ordinal &
- TPM_PROTECTED_ORDINAL_MASK];
if (duration_idx != TPM_UNDEFINED)
duration = chip->vendor.duration[duration_idx];
@@ -410,7 +393,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
chip->vendor.req_complete_val)
goto out_recv;
- if ((status == chip->vendor.req_canceled)) {
+ if (chip->vendor.req_canceled(chip, status)) {
dev_err(chip->dev, "Operation Canceled\n");
rc = -ECANCELED;
goto out;
@@ -468,7 +451,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
return -EFAULT;
err = be32_to_cpu(cmd->header.out.return_code);
- if (err != 0)
+ if (err != 0 && desc)
dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
return err;
@@ -528,6 +511,25 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
}
EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
+#define TPM_ORD_STARTUP cpu_to_be32(153)
+#define TPM_ST_CLEAR cpu_to_be16(1)
+#define TPM_ST_STATE cpu_to_be16(2)
+#define TPM_ST_DEACTIVATED cpu_to_be16(3)
+static const struct tpm_input_header tpm_startup_header = {
+ .tag = TPM_TAG_RQU_COMMAND,
+ .length = cpu_to_be32(12),
+ .ordinal = TPM_ORD_STARTUP
+};
+
+static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
+{
+ struct tpm_cmd_t start_cmd;
+ start_cmd.header.in = tpm_startup_header;
+ start_cmd.params.startup_in.startup_type = startup_type;
+ return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+ "attempting to start the TPM");
+}
+
int tpm_get_timeouts(struct tpm_chip *chip)
{
struct tpm_cmd_t tpm_cmd;
@@ -541,11 +543,28 @@ int tpm_get_timeouts(struct tpm_chip *chip)
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+ rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
- rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
- "attempting to determine the timeouts");
- if (rc)
+ if (rc == TPM_ERR_INVALID_POSTINIT) {
+ /* The TPM is not started, we are the first to talk to it.
+ Execute a startup command. */
+ dev_info(chip->dev, "Issuing TPM_STARTUP");
+ if (tpm_startup(chip, TPM_ST_CLEAR))
+ return rc;
+
+ tpm_cmd.header.in = tpm_getcap_header;
+ tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+ tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+ tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+ rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+ NULL);
+ }
+ if (rc) {
+ dev_err(chip->dev,
+ "A TPM error (%zd) occurred attempting to determine the timeouts\n",
+ rc);
goto duration;
+ }
if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
be32_to_cpu(tpm_cmd.header.out.length)
@@ -824,7 +843,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
{
int rc;
unsigned int loops;
- unsigned int delay_msec = 1000;
+ unsigned int delay_msec = 100;
unsigned long duration;
struct tpm_cmd_t cmd;
@@ -845,6 +864,14 @@ int tpm_do_selftest(struct tpm_chip *chip)
cmd.header.in = pcrread_header;
cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0);
rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE);
+ /* Some buggy TPMs will not respond to tpm_tis_ready() for
+ * around 300ms while the self test is ongoing, keep trying
+ * until the self test duration expires. */
+ if (rc == -ETIME) {
+ dev_info(chip->dev, HW_ERR "TPM command timed out during continue self test");
+ msleep(delay_msec);
+ continue;
+ }
if (rc < TPM_HEADER_SIZE)
return -EFAULT;
@@ -1075,12 +1102,28 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
}
EXPORT_SYMBOL_GPL(tpm_store_cancel);
+static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, bool check_cancel,
+ bool *canceled)
+{
+ u8 status = chip->vendor.status(chip);
+
+ *canceled = false;
+ if ((status & mask) == mask)
+ return true;
+ if (check_cancel && chip->vendor.req_canceled(chip, status)) {
+ *canceled = true;
+ return true;
+ }
+ return false;
+}
+
int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
- wait_queue_head_t *queue)
+ wait_queue_head_t *queue, bool check_cancel)
{
unsigned long stop;
long rc;
u8 status;
+ bool canceled = false;
/* check current status */
status = chip->vendor.status(chip);
@@ -1095,11 +1138,14 @@ again:
if ((long)timeout <= 0)
return -ETIME;
rc = wait_event_interruptible_timeout(*queue,
- ((chip->vendor.status(chip)
- & mask) == mask),
- timeout);
- if (rc > 0)
+ wait_for_tpm_stat_cond(chip, mask, check_cancel,
+ &canceled),
+ timeout);
+ if (rc > 0) {
+ if (canceled)
+ return -ECANCELED;
return 0;
+ }
if (rc == -ERESTARTSYS && freezing(current)) {
clear_thread_flag(TIF_SIGPENDING);
goto again;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 8ef7649a50aa..81b52015f669 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -47,6 +47,7 @@ enum tpm_addr {
#define TPM_WARN_DOING_SELFTEST 0x802
#define TPM_ERR_DEACTIVATED 0x6
#define TPM_ERR_DISABLED 0x7
+#define TPM_ERR_INVALID_POSTINIT 38
#define TPM_HEADER_SIZE 10
extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
@@ -77,7 +78,7 @@ struct tpm_chip;
struct tpm_vendor_specific {
const u8 req_complete_mask;
const u8 req_complete_val;
- const u8 req_canceled;
+ bool (*req_canceled)(struct tpm_chip *chip, u8 status);
void __iomem *iobase; /* ioremapped address */
unsigned long base; /* TPM base address */
@@ -100,13 +101,19 @@ struct tpm_vendor_specific {
bool timeout_adjusted;
unsigned long duration[3]; /* jiffies */
bool duration_adjusted;
- void *data;
+ void *priv;
wait_queue_head_t read_queue;
wait_queue_head_t int_queue;
+
+ u16 manufacturer_id;
};
+#define TPM_VPRIV(c) (c)->vendor.priv
+
#define TPM_VID_INTEL 0x8086
+#define TPM_VID_WINBOND 0x1050
+#define TPM_VID_STM 0x104A
struct tpm_chip {
struct device *dev; /* Device stuff */
@@ -154,13 +161,13 @@ struct tpm_input_header {
__be16 tag;
__be32 length;
__be32 ordinal;
-}__attribute__((packed));
+} __packed;
struct tpm_output_header {
__be16 tag;
__be32 length;
__be32 return_code;
-}__attribute__((packed));
+} __packed;
struct stclear_flags_t {
__be16 tag;
@@ -169,14 +176,14 @@ struct stclear_flags_t {
u8 physicalPresence;
u8 physicalPresenceLock;
u8 bGlobalLock;
-}__attribute__((packed));
+} __packed;
struct tpm_version_t {
u8 Major;
u8 Minor;
u8 revMajor;
u8 revMinor;
-}__attribute__((packed));
+} __packed;
struct tpm_version_1_2_t {
__be16 tag;
@@ -184,20 +191,20 @@ struct tpm_version_1_2_t {
u8 Minor;
u8 revMajor;
u8 revMinor;
-}__attribute__((packed));
+} __packed;
struct timeout_t {
__be32 a;
__be32 b;
__be32 c;
__be32 d;
-}__attribute__((packed));
+} __packed;
struct duration_t {
__be32 tpm_short;
__be32 tpm_medium;
__be32 tpm_long;
-}__attribute__((packed));
+} __packed;
struct permanent_flags_t {
__be16 tag;
@@ -221,7 +228,7 @@ struct permanent_flags_t {
u8 tpmEstablished;
u8 maintenanceDone;
u8 disableFullDALogicInfo;
-}__attribute__((packed));
+} __packed;
typedef union {
struct permanent_flags_t perm_flags;
@@ -239,12 +246,12 @@ struct tpm_getcap_params_in {
__be32 cap;
__be32 subcap_size;
__be32 subcap;
-}__attribute__((packed));
+} __packed;
struct tpm_getcap_params_out {
__be32 cap_size;
cap_t cap;
-}__attribute__((packed));
+} __packed;
struct tpm_readpubek_params_out {
u8 algorithm[4];
@@ -255,7 +262,7 @@ struct tpm_readpubek_params_out {
__be32 keysize;
u8 modulus[256];
u8 checksum[20];
-}__attribute__((packed));
+} __packed;
typedef union {
struct tpm_input_header in;
@@ -265,16 +272,16 @@ typedef union {
#define TPM_DIGEST_SIZE 20
struct tpm_pcrread_out {
u8 pcr_result[TPM_DIGEST_SIZE];
-}__attribute__((packed));
+} __packed;
struct tpm_pcrread_in {
__be32 pcr_idx;
-}__attribute__((packed));
+} __packed;
struct tpm_pcrextend_in {
__be32 pcr_idx;
u8 hash[TPM_DIGEST_SIZE];
-}__attribute__((packed));
+} __packed;
/* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18
* bytes, but 128 is still a relatively large number of random bytes and
@@ -285,11 +292,15 @@ struct tpm_pcrextend_in {
struct tpm_getrandom_out {
__be32 rng_data_len;
u8 rng_data[TPM_MAX_RNG_DATA];
-}__attribute__((packed));
+} __packed;
struct tpm_getrandom_in {
__be32 num_bytes;
-}__attribute__((packed));
+} __packed;
+
+struct tpm_startup_in {
+ __be16 startup_type;
+} __packed;
typedef union {
struct tpm_getcap_params_out getcap_out;
@@ -301,12 +312,13 @@ typedef union {
struct tpm_pcrextend_in pcrextend_in;
struct tpm_getrandom_in getrandom_in;
struct tpm_getrandom_out getrandom_out;
+ struct tpm_startup_in startup_in;
} tpm_cmd_params;
struct tpm_cmd_t {
tpm_cmd_header header;
tpm_cmd_params params;
-}__attribute__((packed));
+} __packed;
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
@@ -326,7 +338,7 @@ extern void tpm_remove_hardware(struct device *);
extern int tpm_pm_suspend(struct device *);
extern int tpm_pm_resume(struct device *);
extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
- wait_queue_head_t *);
+ wait_queue_head_t *, bool);
#ifdef CONFIG_ACPI
extern int tpm_add_ppi(struct kobject *);
diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c
index 56051d0c97a2..64420b3396a2 100644
--- a/drivers/char/tpm/tpm_acpi.c
+++ b/drivers/char/tpm/tpm_acpi.c
@@ -33,13 +33,13 @@ struct acpi_tcpa {
u16 platform_class;
union {
struct client_hdr {
- u32 log_max_len __attribute__ ((packed));
- u64 log_start_addr __attribute__ ((packed));
+ u32 log_max_len __packed;
+ u64 log_start_addr __packed;
} client;
struct server_hdr {
u16 reserved;
- u64 log_max_len __attribute__ ((packed));
- u64 log_start_addr __attribute__ ((packed));
+ u64 log_max_len __packed;
+ u64 log_start_addr __packed;
} server;
};
};
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 678d57019dc4..99d6820c611d 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -116,6 +116,11 @@ static u8 tpm_atml_status(struct tpm_chip *chip)
return ioread8(chip->vendor.iobase + 1);
}
+static bool tpm_atml_req_canceled(struct tpm_chip *chip, u8 status)
+{
+ return (status == ATML_STATUS_READY);
+}
+
static const struct file_operations atmel_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -147,7 +152,7 @@ static const struct tpm_vendor_specific tpm_atmel = {
.status = tpm_atml_status,
.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
.req_complete_val = ATML_STATUS_DATA_AVAIL,
- .req_canceled = ATML_STATUS_READY,
+ .req_canceled = tpm_atml_req_canceled,
.attr_group = &atmel_attr_grp,
.miscdev = { .fops = &atmel_ops, },
};
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
index fb447bd0cb61..8fe7ac3d095b 100644
--- a/drivers/char/tpm/tpm_i2c_infineon.c
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
@@ -505,6 +505,11 @@ out_err:
return rc;
}
+static bool tpm_tis_i2c_req_canceled(struct tpm_chip *chip, u8 status)
+{
+ return (status == TPM_STS_COMMAND_READY);
+}
+
static const struct file_operations tis_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -550,7 +555,7 @@ static struct tpm_vendor_specific tpm_tis_i2c = {
.cancel = tpm_tis_i2c_ready,
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- .req_canceled = TPM_STS_COMMAND_READY,
+ .req_canceled = tpm_tis_i2c_req_canceled,
.attr_group = &tis_attr_grp,
.miscdev.fops = &tis_ops,
};
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
new file mode 100644
index 000000000000..1f5f71e14abe
--- /dev/null
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -0,0 +1,887 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
+ * Copyright (C) 2009, 2010 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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.
+ *
+ * STMicroelectronics version 1.2.0, Copyright (C) 2010
+ * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
+ * This is free software, and you are welcome to redistribute it
+ * under certain conditions.
+ *
+ * @Author: Christophe RICARD tpmsupport@st.com
+ *
+ * @File: tpm_stm_st33_i2c.c
+ *
+ * @Synopsis:
+ * 09/15/2010: First shot driver tpm_tis driver for
+ lpc is used as model.
+ */
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sysfs.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include "tpm.h"
+#include "tpm_i2c_stm_st33.h"
+
+enum stm33zp24_access {
+ TPM_ACCESS_VALID = 0x80,
+ TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
+ TPM_ACCESS_REQUEST_PENDING = 0x04,
+ TPM_ACCESS_REQUEST_USE = 0x02,
+};
+
+enum stm33zp24_status {
+ TPM_STS_VALID = 0x80,
+ TPM_STS_COMMAND_READY = 0x40,
+ TPM_STS_GO = 0x20,
+ TPM_STS_DATA_AVAIL = 0x10,
+ TPM_STS_DATA_EXPECT = 0x08,
+};
+
+enum stm33zp24_int_flags {
+ TPM_GLOBAL_INT_ENABLE = 0x80,
+ TPM_INTF_CMD_READY_INT = 0x080,
+ TPM_INTF_FIFO_AVALAIBLE_INT = 0x040,
+ TPM_INTF_WAKE_UP_READY_INT = 0x020,
+ TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
+ TPM_INTF_STS_VALID_INT = 0x002,
+ TPM_INTF_DATA_AVAIL_INT = 0x001,
+};
+
+enum tis_defaults {
+ TIS_SHORT_TIMEOUT = 750,
+ TIS_LONG_TIMEOUT = 2000,
+};
+
+/*
+ * write8_reg
+ * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
+ * @param: tpm_register, the tpm tis register where the data should be written
+ * @param: tpm_data, the tpm_data to write inside the tpm_register
+ * @param: tpm_size, The length of the data
+ * @return: Returns negative errno, or else the number of bytes written.
+ */
+static int write8_reg(struct i2c_client *client, u8 tpm_register,
+ u8 *tpm_data, u16 tpm_size)
+{
+ struct st33zp24_platform_data *pin_infos;
+
+ pin_infos = client->dev.platform_data;
+
+ pin_infos->tpm_i2c_buffer[0][0] = tpm_register;
+ memcpy(&pin_infos->tpm_i2c_buffer[0][1], tpm_data, tpm_size);
+ return i2c_master_send(client, pin_infos->tpm_i2c_buffer[0],
+ tpm_size + 1);
+} /* write8_reg() */
+
+/*
+ * read8_reg
+ * Recv byte from the TIS register according to the ST33ZP24 I2C protocol.
+ * @param: tpm_register, the tpm tis register where the data should be read
+ * @param: tpm_data, the TPM response
+ * @param: tpm_size, tpm TPM response size to read.
+ * @return: number of byte read successfully: should be one if success.
+ */
+static int read8_reg(struct i2c_client *client, u8 tpm_register,
+ u8 *tpm_data, int tpm_size)
+{
+ u8 status = 0;
+ u8 data;
+
+ data = TPM_DUMMY_BYTE;
+ status = write8_reg(client, tpm_register, &data, 1);
+ if (status == 2)
+ status = i2c_master_recv(client, tpm_data, tpm_size);
+ return status;
+} /* read8_reg() */
+
+/*
+ * I2C_WRITE_DATA
+ * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
+ * @param: client, the chip description
+ * @param: tpm_register, the tpm tis register where the data should be written
+ * @param: tpm_data, the tpm_data to write inside the tpm_register
+ * @param: tpm_size, The length of the data
+ * @return: number of byte written successfully: should be one if success.
+ */
+#define I2C_WRITE_DATA(client, tpm_register, tpm_data, tpm_size) \
+ (write8_reg(client, tpm_register | \
+ TPM_WRITE_DIRECTION, tpm_data, tpm_size))
+
+/*
+ * I2C_READ_DATA
+ * Recv byte from the TIS register according to the ST33ZP24 I2C protocol.
+ * @param: tpm, the chip description
+ * @param: tpm_register, the tpm tis register where the data should be read
+ * @param: tpm_data, the TPM response
+ * @param: tpm_size, tpm TPM response size to read.
+ * @return: number of byte read successfully: should be one if success.
+ */
+#define I2C_READ_DATA(client, tpm_register, tpm_data, tpm_size) \
+ (read8_reg(client, tpm_register, tpm_data, tpm_size))
+
+/*
+ * clear_interruption
+ * clear the TPM interrupt register.
+ * @param: tpm, the chip description
+ */
+static void clear_interruption(struct i2c_client *client)
+{
+ u8 interrupt;
+ I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1);
+ I2C_WRITE_DATA(client, TPM_INT_STATUS, &interrupt, 1);
+ I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1);
+} /* clear_interruption() */
+
+/*
+ * _wait_for_interrupt_serirq_timeout
+ * @param: tpm, the chip description
+ * @param: timeout, the timeout of the interrupt
+ * @return: the status of the interruption.
+ */
+static long _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
+ unsigned long timeout)
+{
+ long status;
+ struct i2c_client *client;
+ struct st33zp24_platform_data *pin_infos;
+
+ client = (struct i2c_client *) TPM_VPRIV(chip);
+ pin_infos = client->dev.platform_data;
+
+ status = wait_for_completion_interruptible_timeout(
+ &pin_infos->irq_detection,
+ timeout);
+ if (status > 0)
+ enable_irq(gpio_to_irq(pin_infos->io_serirq));
+ gpio_direction_input(pin_infos->io_serirq);
+
+ return status;
+} /* wait_for_interrupt_serirq_timeout() */
+
+static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition,
+ unsigned long timeout)
+{
+ int status = 2;
+ struct i2c_client *client;
+
+ client = (struct i2c_client *) TPM_VPRIV(chip);
+
+ status = _wait_for_interrupt_serirq_timeout(chip, timeout);
+ if (!status) {
+ status = -EBUSY;
+ } else{
+ clear_interruption(client);
+ if (condition)
+ status = 1;
+ }
+ return status;
+}
+
+/*
+ * tpm_stm_i2c_cancel, cancel is not implemented.
+ * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
+ */
+static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
+{
+ struct i2c_client *client;
+ u8 data;
+
+ client = (struct i2c_client *) TPM_VPRIV(chip);
+
+ data = TPM_STS_COMMAND_READY;
+ I2C_WRITE_DATA(client, TPM_STS, &data, 1);
+ if (chip->vendor.irq)
+ wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a);
+} /* tpm_stm_i2c_cancel() */
+
+/*
+ * tpm_stm_spi_status return the TPM_STS register
+ * @param: chip, the tpm chip description
+ * @return: the TPM_STS register value.
+ */
+static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
+{
+ struct i2c_client *client;
+ u8 data;
+ client = (struct i2c_client *) TPM_VPRIV(chip);
+
+ I2C_READ_DATA(client, TPM_STS, &data, 1);
+ return data;
+} /* tpm_stm_i2c_status() */
+
+
+/*
+ * check_locality if the locality is active
+ * @param: chip, the tpm chip description
+ * @return: the active locality or -EACCESS.
+ */
+static int check_locality(struct tpm_chip *chip)
+{
+ struct i2c_client *client;
+ u8 data;
+ u8 status;
+
+ client = (struct i2c_client *) TPM_VPRIV(chip);
+
+ status = I2C_READ_DATA(client, TPM_ACCESS, &data, 1);
+ if (status && (data &
+ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
+ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
+ return chip->vendor.locality;
+
+ return -EACCES;
+
+} /* check_locality() */
+
+/*
+ * request_locality request the TPM locality
+ * @param: chip, the chip description
+ * @return: the active locality or EACCESS.
+ */
+static int request_locality(struct tpm_chip *chip)
+{
+ unsigned long stop;
+ long rc;
+ struct i2c_client *client;
+ u8 data;
+
+ client = (struct i2c_client *) TPM_VPRIV(chip);
+
+ if (check_locality(chip) == chip->vendor.locality)
+ return chip->vendor.locality;
+
+ data = TPM_ACCESS_REQUEST_USE;
+ rc = I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
+ if (rc < 0)
+ goto end;
+
+ if (chip->vendor.irq) {
+ rc = wait_for_serirq_timeout(chip, (check_locality
+ (chip) >= 0),
+ chip->vendor.timeout_a);
+ if (rc > 0)
+ return chip->vendor.locality;
+ } else{
+ stop = jiffies + chip->vendor.timeout_a;
+ do {
+ if (check_locality(chip) >= 0)
+ return chip->vendor.locality;
+ msleep(TPM_TIMEOUT);
+ } while (time_before(jiffies, stop));
+ }
+ rc = -EACCES;
+end:
+ return rc;
+} /* request_locality() */
+
+/*
+ * release_locality release the active locality
+ * @param: chip, the tpm chip description.
+ */
+static void release_locality(struct tpm_chip *chip)
+{
+ struct i2c_client *client;
+ u8 data;
+
+ client = (struct i2c_client *) TPM_VPRIV(chip);
+ data = TPM_ACCESS_ACTIVE_LOCALITY;
+
+ I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
+}
+
+/*
+ * get_burstcount return the burstcount address 0x19 0x1A
+ * @param: chip, the chip description
+ * return: the burstcount.
+ */
+static int get_burstcount(struct tpm_chip *chip)
+{
+ unsigned long stop;
+ int burstcnt, status;
+ u8 tpm_reg, temp;
+
+ struct i2c_client *client = (struct i2c_client *) TPM_VPRIV(chip);
+
+ stop = jiffies + chip->vendor.timeout_d;
+ do {
+ tpm_reg = TPM_STS + 1;
+ status = I2C_READ_DATA(client, tpm_reg, &temp, 1);
+ if (status < 0)
+ goto end;
+
+ tpm_reg = tpm_reg + 1;
+ burstcnt = temp;
+ status = I2C_READ_DATA(client, tpm_reg, &temp, 1);
+ if (status < 0)
+ goto end;
+
+ burstcnt |= temp << 8;
+ if (burstcnt)
+ return burstcnt;
+ msleep(TPM_TIMEOUT);
+ } while (time_before(jiffies, stop));
+
+end:
+ return -EBUSY;
+} /* get_burstcount() */
+
+/*
+ * wait_for_stat wait for a TPM_STS value
+ * @param: chip, the tpm chip description
+ * @param: mask, the value mask to wait
+ * @param: timeout, the timeout
+ * @param: queue, the wait queue.
+ * @return: the tpm status, 0 if success, -ETIME if timeout is reached.
+ */
+static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
+ wait_queue_head_t *queue)
+{
+ unsigned long stop;
+ long rc;
+ u8 status;
+
+ if (chip->vendor.irq) {
+ rc = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status
+ (chip) & mask) ==
+ mask), timeout);
+ if (rc > 0)
+ return 0;
+ } else{
+ stop = jiffies + timeout;
+ do {
+ msleep(TPM_TIMEOUT);
+ status = tpm_stm_i2c_status(chip);
+ if ((status & mask) == mask)
+ return 0;
+ } while (time_before(jiffies, stop));
+ }
+ return -ETIME;
+} /* wait_for_stat() */
+
+/*
+ * recv_data receive data
+ * @param: chip, the tpm chip description
+ * @param: buf, the buffer where the data are received
+ * @param: count, the number of data to receive
+ * @return: the number of bytes read from TPM FIFO.
+ */
+static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+ int size = 0, burstcnt, len;
+ struct i2c_client *client;
+
+ client = (struct i2c_client *) TPM_VPRIV(chip);
+
+ while (size < count &&
+ wait_for_stat(chip,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ chip->vendor.timeout_c,
+ &chip->vendor.read_queue)
+ == 0) {
+ burstcnt = get_burstcount(chip);
+ len = min_t(int, burstcnt, count - size);
+ I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len);
+ size += len;
+ }
+ return size;
+}
+
+/*
+ * tpm_ioserirq_handler the serirq irq handler
+ * @param: irq, the tpm chip description
+ * @param: dev_id, the description of the chip
+ * @return: the status of the handler.
+ */
+static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
+{
+ struct tpm_chip *chip = dev_id;
+ struct i2c_client *client;
+ struct st33zp24_platform_data *pin_infos;
+
+ disable_irq_nosync(irq);
+
+ client = (struct i2c_client *) TPM_VPRIV(chip);
+ pin_infos = client->dev.platform_data;
+
+ complete(&pin_infos->irq_detection);
+ return IRQ_HANDLED;
+} /* tpm_ioserirq_handler() */
+
+
+/*
+ * tpm_stm_i2c_send send TPM commands through the I2C bus.
+ *
+ * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
+ * @param: buf, the buffer to send.
+ * @param: count, the number of bytes to send.
+ * @return: In case of success the number of bytes sent.
+ * In other case, a < 0 value describing the issue.
+ */
+static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
+ size_t len)
+{
+ u32 status,
+ burstcnt = 0, i, size;
+ int ret;
+ u8 data;
+ struct i2c_client *client;
+
+ if (chip == NULL)
+ return -EBUSY;
+ if (len < TPM_HEADER_SIZE)
+ return -EBUSY;
+
+ client = (struct i2c_client *)TPM_VPRIV(chip);
+
+ client->flags = 0;
+
+ ret = request_locality(chip);
+ if (ret < 0)
+ return ret;
+
+ status = tpm_stm_i2c_status(chip);
+ if ((status & TPM_STS_COMMAND_READY) == 0) {
+ tpm_stm_i2c_cancel(chip);
+ if (wait_for_stat
+ (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
+ &chip->vendor.int_queue) < 0) {
+ ret = -ETIME;
+ goto out_err;
+ }
+ }
+
+ for (i = 0 ; i < len - 1 ;) {
+ burstcnt = get_burstcount(chip);
+ size = min_t(int, len - i - 1, burstcnt);
+ ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);
+ if (ret < 0)
+ goto out_err;
+
+ i += size;
+ }
+
+ status = tpm_stm_i2c_status(chip);
+ if ((status & TPM_STS_DATA_EXPECT) == 0) {
+ ret = -EIO;
+ goto out_err;
+ }
+
+ ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf + len - 1, 1);
+ if (ret < 0)
+ goto out_err;
+
+ status = tpm_stm_i2c_status(chip);
+ if ((status & TPM_STS_DATA_EXPECT) != 0) {
+ ret = -EIO;
+ goto out_err;
+ }
+
+ data = TPM_STS_GO;
+ I2C_WRITE_DATA(client, TPM_STS, &data, 1);
+
+ return len;
+out_err:
+ tpm_stm_i2c_cancel(chip);
+ release_locality(chip);
+ return ret;
+}
+
+/*
+ * tpm_stm_i2c_recv received TPM response through the I2C bus.
+ * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h.
+ * @param: buf, the buffer to store datas.
+ * @param: count, the number of bytes to send.
+ * @return: In case of success the number of bytes received.
+ * In other case, a < 0 value describing the issue.
+ */
+static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
+ size_t count)
+{
+ int size = 0;
+ int expected;
+
+ if (chip == NULL)
+ return -EBUSY;
+
+ if (count < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
+
+ size = recv_data(chip, buf, TPM_HEADER_SIZE);
+ if (size < TPM_HEADER_SIZE) {
+ dev_err(chip->dev, "Unable to read header\n");
+ goto out;
+ }
+
+ expected = be32_to_cpu(*(__be32 *) (buf + 2));
+ if (expected > count) {
+ size = -EIO;
+ goto out;
+ }
+
+ size += recv_data(chip, &buf[TPM_HEADER_SIZE],
+ expected - TPM_HEADER_SIZE);
+ if (size < expected) {
+ dev_err(chip->dev, "Unable to read remainder of result\n");
+ size = -ETIME;
+ goto out;
+ }
+
+out:
+ chip->vendor.cancel(chip);
+ release_locality(chip);
+ return size;
+}
+
+static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status)
+{
+ return (status == TPM_STS_COMMAND_READY);
+}
+
+static const struct file_operations tpm_st33_i2c_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = tpm_read,
+ .write = tpm_write,
+ .open = tpm_open,
+ .release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
+static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
+static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
+static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute *stm_tpm_attrs[] = {
+ &dev_attr_pubek.attr,
+ &dev_attr_pcrs.attr,
+ &dev_attr_enabled.attr,
+ &dev_attr_active.attr,
+ &dev_attr_owned.attr,
+ &dev_attr_temp_deactivated.attr,
+ &dev_attr_caps.attr,
+ &dev_attr_cancel.attr, NULL,
+};
+
+static struct attribute_group stm_tpm_attr_grp = {
+ .attrs = stm_tpm_attrs
+};
+
+static struct tpm_vendor_specific st_i2c_tpm = {
+ .send = tpm_stm_i2c_send,
+ .recv = tpm_stm_i2c_recv,
+ .cancel = tpm_stm_i2c_cancel,
+ .status = tpm_stm_i2c_status,
+ .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ .req_canceled = tpm_st33_i2c_req_canceled,
+ .attr_group = &stm_tpm_attr_grp,
+ .miscdev = {.fops = &tpm_st33_i2c_fops,},
+};
+
+static int interrupts ;
+module_param(interrupts, int, 0444);
+MODULE_PARM_DESC(interrupts, "Enable interrupts");
+
+static int power_mgt = 1;
+module_param(power_mgt, int, 0444);
+MODULE_PARM_DESC(power_mgt, "Power Management");
+
+/*
+ * tpm_st33_i2c_probe initialize the TPM device
+ * @param: client, the i2c_client drescription (TPM I2C description).
+ * @param: id, the i2c_device_id struct.
+ * @return: 0 in case of success.
+ * -1 in other case.
+ */
+static int
+tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ int err;
+ u8 intmask;
+ struct tpm_chip *chip;
+ struct st33zp24_platform_data *platform_data;
+
+ if (client == NULL) {
+ pr_info("%s: i2c client is NULL. Device not accessible.\n",
+ __func__);
+ err = -ENODEV;
+ goto end;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_info(&client->dev, "client not i2c capable\n");
+ err = -ENODEV;
+ goto end;
+ }
+
+ chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
+ if (!chip) {
+ dev_info(&client->dev, "fail chip\n");
+ err = -ENODEV;
+ goto end;
+ }
+
+ platform_data = client->dev.platform_data;
+
+ if (!platform_data) {
+ dev_info(&client->dev, "chip not available\n");
+ err = -ENODEV;
+ goto _tpm_clean_answer;
+ }
+
+ platform_data->tpm_i2c_buffer[0] =
+ kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
+ if (platform_data->tpm_i2c_buffer[0] == NULL) {
+ err = -ENOMEM;
+ goto _tpm_clean_answer;
+ }
+ platform_data->tpm_i2c_buffer[1] =
+ kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
+ if (platform_data->tpm_i2c_buffer[1] == NULL) {
+ err = -ENOMEM;
+ goto _tpm_clean_response1;
+ }
+
+ TPM_VPRIV(chip) = client;
+
+ chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+ chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
+ chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+ chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+
+ chip->vendor.locality = LOCALITY0;
+
+ if (power_mgt) {
+ err = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD");
+ if (err)
+ goto _gpio_init1;
+ gpio_set_value(platform_data->io_lpcpd, 1);
+ }
+
+ if (interrupts) {
+ init_completion(&platform_data->irq_detection);
+ if (request_locality(chip) != LOCALITY0) {
+ err = -ENODEV;
+ goto _tpm_clean_response2;
+ }
+ err = gpio_request(platform_data->io_serirq, "TPM IO_SERIRQ");
+ if (err)
+ goto _gpio_init2;
+
+ clear_interruption(client);
+ err = request_irq(gpio_to_irq(platform_data->io_serirq),
+ &tpm_ioserirq_handler,
+ IRQF_TRIGGER_HIGH,
+ "TPM SERIRQ management", chip);
+ if (err < 0) {
+ dev_err(chip->dev , "TPM SERIRQ signals %d not available\n",
+ gpio_to_irq(platform_data->io_serirq));
+ goto _irq_set;
+ }
+
+ err = I2C_READ_DATA(client, TPM_INT_ENABLE, &intmask, 1);
+ if (err < 0)
+ goto _irq_set;
+
+ intmask |= TPM_INTF_CMD_READY_INT
+ | TPM_INTF_FIFO_AVALAIBLE_INT
+ | TPM_INTF_WAKE_UP_READY_INT
+ | TPM_INTF_LOCALITY_CHANGE_INT
+ | TPM_INTF_STS_VALID_INT
+ | TPM_INTF_DATA_AVAIL_INT;
+
+ err = I2C_WRITE_DATA(client, TPM_INT_ENABLE, &intmask, 1);
+ if (err < 0)
+ goto _irq_set;
+
+ intmask = TPM_GLOBAL_INT_ENABLE;
+ err = I2C_WRITE_DATA(client, (TPM_INT_ENABLE + 3), &intmask, 1);
+ if (err < 0)
+ goto _irq_set;
+
+ err = I2C_READ_DATA(client, TPM_INT_STATUS, &intmask, 1);
+ if (err < 0)
+ goto _irq_set;
+
+ chip->vendor.irq = interrupts;
+
+ tpm_gen_interrupt(chip);
+ }
+
+ tpm_get_timeouts(chip);
+
+ i2c_set_clientdata(client, chip);
+
+ dev_info(chip->dev, "TPM I2C Initialized\n");
+ return 0;
+_irq_set:
+ free_irq(gpio_to_irq(platform_data->io_serirq), (void *) chip);
+_gpio_init2:
+ if (interrupts)
+ gpio_free(platform_data->io_serirq);
+_gpio_init1:
+ if (power_mgt)
+ gpio_free(platform_data->io_lpcpd);
+_tpm_clean_response2:
+ kzfree(platform_data->tpm_i2c_buffer[1]);
+ platform_data->tpm_i2c_buffer[1] = NULL;
+_tpm_clean_response1:
+ kzfree(platform_data->tpm_i2c_buffer[0]);
+ platform_data->tpm_i2c_buffer[0] = NULL;
+_tpm_clean_answer:
+ tpm_remove_hardware(chip->dev);
+end:
+ pr_info("TPM I2C initialisation fail\n");
+ return err;
+}
+
+/*
+ * tpm_st33_i2c_remove remove the TPM device
+ * @param: client, the i2c_client drescription (TPM I2C description).
+ clear_bit(0, &chip->is_open);
+ * @return: 0 in case of success.
+ */
+static int tpm_st33_i2c_remove(struct i2c_client *client)
+{
+ struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
+ struct st33zp24_platform_data *pin_infos =
+ ((struct i2c_client *) TPM_VPRIV(chip))->dev.platform_data;
+
+ if (pin_infos != NULL) {
+ free_irq(pin_infos->io_serirq, chip);
+
+ gpio_free(pin_infos->io_serirq);
+ gpio_free(pin_infos->io_lpcpd);
+
+ tpm_remove_hardware(chip->dev);
+
+ if (pin_infos->tpm_i2c_buffer[1] != NULL) {
+ kzfree(pin_infos->tpm_i2c_buffer[1]);
+ pin_infos->tpm_i2c_buffer[1] = NULL;
+ }
+ if (pin_infos->tpm_i2c_buffer[0] != NULL) {
+ kzfree(pin_infos->tpm_i2c_buffer[0]);
+ pin_infos->tpm_i2c_buffer[0] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * tpm_st33_i2c_pm_suspend suspend the TPM device
+ * Added: Work around when suspend and no tpm application is running, suspend
+ * may fail because chip->data_buffer is not set (only set in tpm_open in Linux
+ * TPM core)
+ * @param: client, the i2c_client drescription (TPM I2C description).
+ * @param: mesg, the power management message.
+ * @return: 0 in case of success.
+ */
+static int tpm_st33_i2c_pm_suspend(struct device *dev)
+{
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ struct st33zp24_platform_data *pin_infos = dev->platform_data;
+ int ret = 0;
+
+ if (power_mgt)
+ gpio_set_value(pin_infos->io_lpcpd, 0);
+ else{
+ if (chip->data_buffer == NULL)
+ chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
+ ret = tpm_pm_suspend(dev);
+ }
+ return ret;
+} /* tpm_st33_i2c_suspend() */
+
+/*
+ * tpm_st33_i2c_pm_resume resume the TPM device
+ * @param: client, the i2c_client drescription (TPM I2C description).
+ * @return: 0 in case of success.
+ */
+static int tpm_st33_i2c_pm_resume(struct device *dev)
+{
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ struct st33zp24_platform_data *pin_infos = dev->platform_data;
+
+ int ret = 0;
+
+ if (power_mgt) {
+ gpio_set_value(pin_infos->io_lpcpd, 1);
+ ret = wait_for_serirq_timeout(chip,
+ (chip->vendor.status(chip) &
+ TPM_STS_VALID) == TPM_STS_VALID,
+ chip->vendor.timeout_b);
+ } else{
+ if (chip->data_buffer == NULL)
+ chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
+ ret = tpm_pm_resume(dev);
+ if (!ret)
+ tpm_do_selftest(chip);
+ }
+ return ret;
+} /* tpm_st33_i2c_pm_resume() */
+#endif
+
+static const struct i2c_device_id tpm_st33_i2c_id[] = {
+ {TPM_ST33_I2C, 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id);
+static SIMPLE_DEV_PM_OPS(tpm_st33_i2c_ops, tpm_st33_i2c_pm_suspend, tpm_st33_i2c_pm_resume);
+static struct i2c_driver tpm_st33_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = TPM_ST33_I2C,
+ .pm = &tpm_st33_i2c_ops,
+ },
+ .probe = tpm_st33_i2c_probe,
+ .remove = tpm_st33_i2c_remove,
+ .id_table = tpm_st33_i2c_id
+};
+
+module_i2c_driver(tpm_st33_i2c_driver);
+
+MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
+MODULE_DESCRIPTION("STM TPM I2C ST33 Driver");
+MODULE_VERSION("1.2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.h b/drivers/char/tpm/tpm_i2c_stm_st33.h
new file mode 100644
index 000000000000..439a43249aa6
--- /dev/null
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.h
@@ -0,0 +1,61 @@
+/*
+ * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
+ * Copyright (C) 2009, 2010 STMicroelectronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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.
+ *
+ * STMicroelectronics version 1.2.0, Copyright (C) 2010
+ * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
+ * This is free software, and you are welcome to redistribute it
+ * under certain conditions.
+ *
+ * @Author: Christophe RICARD tpmsupport@st.com
+ *
+ * @File: stm_st33_tpm_i2c.h
+ *
+ * @Date: 09/15/2010
+ */
+#ifndef __STM_ST33_TPM_I2C_MAIN_H__
+#define __STM_ST33_TPM_I2C_MAIN_H__
+
+#define TPM_ACCESS (0x0)
+#define TPM_STS (0x18)
+#define TPM_HASH_END (0x20)
+#define TPM_DATA_FIFO (0x24)
+#define TPM_HASH_DATA (0x24)
+#define TPM_HASH_START (0x28)
+#define TPM_INTF_CAPABILITY (0x14)
+#define TPM_INT_STATUS (0x10)
+#define TPM_INT_ENABLE (0x08)
+
+#define TPM_DUMMY_BYTE 0xAA
+#define TPM_WRITE_DIRECTION 0x80
+#define TPM_HEADER_SIZE 10
+#define TPM_BUFSIZE 2048
+
+#define LOCALITY0 0
+
+#define TPM_ST33_I2C "st33zp24_i2c"
+
+struct st33zp24_platform_data {
+ int io_serirq;
+ int io_lpcpd;
+ struct i2c_client *client;
+ u8 *tpm_i2c_buffer[2]; /* 0 Request 1 Response */
+ struct completion irq_detection;
+ struct mutex lock;
+};
+
+#endif /* __STM_ST33_TPM_I2C_MAIN_H__ */
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
index 9978609d93b2..56b07c35a13e 100644
--- a/drivers/char/tpm/tpm_ibmvtpm.c
+++ b/drivers/char/tpm/tpm_ibmvtpm.c
@@ -64,7 +64,7 @@ static struct ibmvtpm_dev *ibmvtpm_get_data(const struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
if (chip)
- return (struct ibmvtpm_dev *)chip->vendor.data;
+ return (struct ibmvtpm_dev *)TPM_VPRIV(chip);
return NULL;
}
@@ -83,7 +83,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
u16 len;
int sig;
- ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
+ ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
if (!ibmvtpm->rtce_buf) {
dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
@@ -127,7 +127,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
u64 *word = (u64 *) &crq;
int rc;
- ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
+ ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
if (!ibmvtpm->rtce_buf) {
dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
@@ -398,6 +398,11 @@ static int tpm_ibmvtpm_resume(struct device *dev)
return rc;
}
+static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status)
+{
+ return (status == 0);
+}
+
static const struct file_operations ibmvtpm_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -441,7 +446,7 @@ static const struct tpm_vendor_specific tpm_ibmvtpm = {
.status = tpm_ibmvtpm_status,
.req_complete_mask = 0,
.req_complete_val = 0,
- .req_canceled = 0,
+ .req_canceled = tpm_ibmvtpm_req_canceled,
.attr_group = &ibmvtpm_attr_grp,
.miscdev = { .fops = &ibmvtpm_ops, },
};
@@ -647,7 +652,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
ibmvtpm->dev = dev;
ibmvtpm->vdev = vio_dev;
- chip->vendor.data = (void *)ibmvtpm;
+ TPM_VPRIV(chip) = (void *)ibmvtpm;
spin_lock_init(&ibmvtpm->rtce_lock);
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 640c9a427b59..770c46f8eb30 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -227,6 +227,11 @@ static u8 tpm_nsc_status(struct tpm_chip *chip)
return inb(chip->vendor.base + NSC_STATUS);
}
+static bool tpm_nsc_req_canceled(struct tpm_chip *chip, u8 status)
+{
+ return (status == NSC_STATUS_RDY);
+}
+
static const struct file_operations nsc_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -258,7 +263,7 @@ static const struct tpm_vendor_specific tpm_nsc = {
.status = tpm_nsc_status,
.req_complete_mask = NSC_STATUS_OBF,
.req_complete_val = NSC_STATUS_OBF,
- .req_canceled = NSC_STATUS_RDY,
+ .req_canceled = tpm_nsc_req_canceled,
.attr_group = &nsc_attr_grp,
.miscdev = { .fops = &nsc_ops, },
};
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index ea31dafbcac2..8a41b6be23a0 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -84,6 +84,9 @@ static int is_itpm(struct pnp_dev *dev)
struct acpi_device *acpi = pnp_acpi_device(dev);
struct acpi_hardware_id *id;
+ if (!acpi)
+ return 0;
+
list_for_each_entry(id, &acpi->pnp.ids, list) {
if (!strcmp("INTC0102", id->id))
return 1;
@@ -98,6 +101,22 @@ static inline int is_itpm(struct pnp_dev *dev)
}
#endif
+/* Before we attempt to access the TPM we must see that the valid bit is set.
+ * The specification says that this bit is 0 at reset and remains 0 until the
+ * 'TPM has gone through its self test and initialization and has established
+ * correct values in the other bits.' */
+static int wait_startup(struct tpm_chip *chip, int l)
+{
+ unsigned long stop = jiffies + chip->vendor.timeout_a;
+ do {
+ if (ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
+ TPM_ACCESS_VALID)
+ return 0;
+ msleep(TPM_TIMEOUT);
+ } while (time_before(jiffies, stop));
+ return -1;
+}
+
static int check_locality(struct tpm_chip *chip, int l)
{
if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
@@ -198,7 +217,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
wait_for_tpm_stat(chip,
TPM_STS_DATA_AVAIL | TPM_STS_VALID,
chip->vendor.timeout_c,
- &chip->vendor.read_queue)
+ &chip->vendor.read_queue, true)
== 0) {
burstcnt = get_burstcount(chip);
for (; burstcnt > 0 && size < count; burstcnt--)
@@ -241,7 +260,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
}
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
- &chip->vendor.int_queue);
+ &chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
dev_err(chip->dev, "Error left over data\n");
@@ -277,7 +296,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
tpm_tis_ready(chip);
if (wait_for_tpm_stat
(chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
- &chip->vendor.int_queue) < 0) {
+ &chip->vendor.int_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
@@ -292,7 +311,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
}
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
- &chip->vendor.int_queue);
+ &chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
rc = -EIO;
@@ -304,7 +323,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
iowrite8(buf[count],
chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
- &chip->vendor.int_queue);
+ &chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if ((status & TPM_STS_DATA_EXPECT) != 0) {
rc = -EIO;
@@ -342,7 +361,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
if (wait_for_tpm_stat
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
tpm_calc_ordinal_duration(chip, ordinal),
- &chip->vendor.read_queue) < 0) {
+ &chip->vendor.read_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
@@ -374,7 +393,7 @@ static int probe_itpm(struct tpm_chip *chip)
if (vendor != TPM_VID_INTEL)
return 0;
- itpm = 0;
+ itpm = false;
rc = tpm_tis_send_data(chip, cmd_getticks, len);
if (rc == 0)
@@ -383,7 +402,7 @@ static int probe_itpm(struct tpm_chip *chip)
tpm_tis_ready(chip);
release_locality(chip, chip->vendor.locality, 0);
- itpm = 1;
+ itpm = true;
rc = tpm_tis_send_data(chip, cmd_getticks, len);
if (rc == 0) {
@@ -400,6 +419,19 @@ out:
return rc;
}
+static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
+{
+ switch (chip->vendor.manufacturer_id) {
+ case TPM_VID_WINBOND:
+ return ((status == TPM_STS_VALID) ||
+ (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY)));
+ case TPM_VID_STM:
+ return (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY));
+ default:
+ return (status == TPM_STS_COMMAND_READY);
+ }
+}
+
static const struct file_operations tis_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -445,7 +477,7 @@ static struct tpm_vendor_specific tpm_tis = {
.cancel = tpm_tis_ready,
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- .req_canceled = TPM_STS_COMMAND_READY,
+ .req_canceled = tpm_tis_req_canceled,
.attr_group = &tis_attr_grp,
.miscdev = {
.fops = &tis_ops,},
@@ -502,7 +534,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
return IRQ_HANDLED;
}
-static bool interrupts = 1;
+static bool interrupts = true;
module_param(interrupts, bool, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
@@ -528,12 +560,18 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+ if (wait_startup(chip, 0) != 0) {
+ rc = -ENODEV;
+ goto out_err;
+ }
+
if (request_locality(chip, 0) != 0) {
rc = -ENODEV;
goto out_err;
}
vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
+ chip->vendor.manufacturer_id = vendor;
dev_info(dev,
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
@@ -545,7 +583,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
rc = -ENODEV;
goto out_err;
}
- itpm = (probe == 0) ? 0 : 1;
+ itpm = !!probe;
}
if (itpm)
@@ -741,10 +779,10 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
if (pnp_irq_valid(pnp_dev, 0))
irq = pnp_irq(pnp_dev, 0);
else
- interrupts = 0;
+ interrupts = false;
if (is_itpm(pnp_dev))
- itpm = 1;
+ itpm = true;
return tpm_tis_init(&pnp_dev->dev, start, len, irq);
}
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 684b0d53764f..ee4dbeafb377 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -2062,7 +2062,8 @@ static void virtcons_remove(struct virtio_device *vdev)
/* Disable interrupts for vqs */
vdev->config->reset(vdev);
/* Finish up work that's lined up */
- cancel_work_sync(&portdev->control_work);
+ if (use_multiport(portdev))
+ cancel_work_sync(&portdev->control_work);
list_for_each_entry_safe(port, port2, &portdev->ports, list)
unplug_port(port);
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index ee90e87e7675..300d4775d926 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,8 +1,13 @@
# common clock types
obj-$(CONFIG_HAVE_CLK) += clk-devres.o
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
-obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
- clk-mux.o clk-divider.o clk-fixed-factor.o
+obj-$(CONFIG_COMMON_CLK) += clk.o
+obj-$(CONFIG_COMMON_CLK) += clk-divider.o
+obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
+obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
+obj-$(CONFIG_COMMON_CLK) += clk-gate.o
+obj-$(CONFIG_COMMON_CLK) += clk-mux.o
+
# SoCs specific
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
@@ -20,8 +25,10 @@ endif
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
-obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o
obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o
+obj-$(CONFIG_ARCH_TEGRA) += tegra/
+
+obj-$(CONFIG_X86) += x86/
# Chip specific
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c
index e69991aab43a..792bc57a9db7 100644
--- a/drivers/clk/clk-bcm2835.c
+++ b/drivers/clk/clk-bcm2835.c
@@ -20,6 +20,13 @@
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/bcm2835.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+
+static const __initconst struct of_device_id clk_match[] = {
+ { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+ { }
+};
/*
* These are fixed clocks. They're probably not all root clocks and it may
@@ -56,4 +63,6 @@ void __init bcm2835_init_clocks(void)
ret = clk_register_clkdev(clk, NULL, "20215000.uart");
if (ret)
pr_err("uart1_pclk alias not registered\n");
+
+ of_clk_init(clk_match);
}
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index a9204c69148d..68b402101170 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/string.h>
+#include <linux/log2.h>
/*
* DOC: basic adjustable divider clock that cannot gate
@@ -29,8 +30,7 @@
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
-#define div_mask(d) ((1 << (d->width)) - 1)
-#define is_power_of_two(i) !(i & ~i)
+#define div_mask(d) ((1 << ((d)->width)) - 1)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
{
@@ -137,7 +137,7 @@ static bool _is_valid_table_div(const struct clk_div_table *table,
static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
{
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
- return is_power_of_two(div);
+ return is_power_of_2(div);
if (divider->table)
return _is_valid_table_div(divider->table, div);
return true;
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index a4899855c0f6..1ef271e47594 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -28,8 +28,11 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
+ unsigned long long int rate;
- return parent_rate * fix->mult / fix->div;
+ rate = (unsigned long long int)parent_rate * fix->mult;
+ do_div(rate, fix->div);
+ return (unsigned long)rate;
}
static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index af78ed6b67ef..dc58fbd8516f 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -85,7 +85,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
/**
* of_fixed_clk_setup() - Setup function for simple fixed rate clock
*/
-void __init of_fixed_clk_setup(struct device_node *node)
+void of_fixed_clk_setup(struct device_node *node)
{
struct clk *clk;
const char *clk_name = node->name;
@@ -101,4 +101,5 @@ void __init of_fixed_clk_setup(struct device_node *node)
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
+CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
#endif
diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecadf004a..2e08cb001936 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
reg |= HB_PLL_EXT_ENA;
reg &= ~HB_PLL_EXT_BYPASS;
} else {
+ writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
reg &= ~HB_PLL_DIVQ_MASK;
reg |= divq << HB_PLL_DIVQ_SHIFT;
+ writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
}
writel(reg, hbclk->reg);
@@ -314,33 +316,23 @@ static void __init hb_pll_init(struct device_node *node)
{
hb_clk_init(node, &clk_pll_ops);
}
+CLK_OF_DECLARE(hb_pll, "calxeda,hb-pll-clock", hb_pll_init);
static void __init hb_a9periph_init(struct device_node *node)
{
hb_clk_init(node, &a9periphclk_ops);
}
+CLK_OF_DECLARE(hb_a9periph, "calxeda,hb-a9periph-clock", hb_a9periph_init);
static void __init hb_a9bus_init(struct device_node *node)
{
struct clk *clk = hb_clk_init(node, &a9bclk_ops);
clk_prepare_enable(clk);
}
+CLK_OF_DECLARE(hb_a9bus, "calxeda,hb-a9bus-clock", hb_a9bus_init);
static void __init hb_emmc_init(struct device_node *node)
{
hb_clk_init(node, &periclk_ops);
}
-
-static const __initconst struct of_device_id clk_match[] = {
- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
- { .compatible = "calxeda,hb-pll-clock", .data = hb_pll_init, },
- { .compatible = "calxeda,hb-a9periph-clock", .data = hb_a9periph_init, },
- { .compatible = "calxeda,hb-a9bus-clock", .data = hb_a9bus_init, },
- { .compatible = "calxeda,hb-emmc-clock", .data = hb_emmc_init, },
- {}
-};
-
-void __init highbank_clocks_init(void)
-{
- of_clk_init(clk_match);
-}
+CLK_OF_DECLARE(hb_emmc, "calxeda,hb-emmc-clock", hb_emmc_init);
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index d098f72e1d5f..9f57bc37cd60 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -44,33 +44,23 @@ struct max77686_clk {
struct clk_lookup *lookup;
};
-static struct max77686_clk *get_max77686_clk(struct clk_hw *hw)
+static struct max77686_clk *to_max77686_clk(struct clk_hw *hw)
{
return container_of(hw, struct max77686_clk, hw);
}
static int max77686_clk_prepare(struct clk_hw *hw)
{
- struct max77686_clk *max77686;
- int ret;
-
- max77686 = get_max77686_clk(hw);
- if (!max77686)
- return -ENOMEM;
-
- ret = regmap_update_bits(max77686->iodev->regmap,
- MAX77686_REG_32KHZ, max77686->mask, max77686->mask);
+ struct max77686_clk *max77686 = to_max77686_clk(hw);
- return ret;
+ return regmap_update_bits(max77686->iodev->regmap,
+ MAX77686_REG_32KHZ, max77686->mask,
+ max77686->mask);
}
static void max77686_clk_unprepare(struct clk_hw *hw)
{
- struct max77686_clk *max77686;
-
- max77686 = get_max77686_clk(hw);
- if (!max77686)
- return;
+ struct max77686_clk *max77686 = to_max77686_clk(hw);
regmap_update_bits(max77686->iodev->regmap,
MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
@@ -78,14 +68,10 @@ static void max77686_clk_unprepare(struct clk_hw *hw)
static int max77686_clk_is_enabled(struct clk_hw *hw)
{
- struct max77686_clk *max77686;
+ struct max77686_clk *max77686 = to_max77686_clk(hw);
int ret;
u32 val;
- max77686 = get_max77686_clk(hw);
- if (!max77686)
- return -ENOMEM;
-
ret = regmap_read(max77686->iodev->regmap,
MAX77686_REG_32KHZ, &val);
@@ -130,9 +116,8 @@ static int max77686_clk_register(struct device *dev,
if (IS_ERR(clk))
return -ENOMEM;
- max77686->lookup = devm_kzalloc(dev, sizeof(struct clk_lookup),
- GFP_KERNEL);
- if (IS_ERR(max77686->lookup))
+ max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
+ if (!max77686->lookup)
return -ENOMEM;
max77686->lookup->con_id = hw->init->name;
@@ -151,13 +136,13 @@ static int max77686_clk_probe(struct platform_device *pdev)
max77686_clks = devm_kzalloc(&pdev->dev, sizeof(struct max77686_clk *)
* MAX77686_CLKS_NUM, GFP_KERNEL);
- if (IS_ERR(max77686_clks))
+ if (!max77686_clks)
return -ENOMEM;
for (i = 0; i < MAX77686_CLKS_NUM; i++) {
max77686_clks[i] = devm_kzalloc(&pdev->dev,
sizeof(struct max77686_clk), GFP_KERNEL);
- if (IS_ERR(max77686_clks[i]))
+ if (!max77686_clks[i])
return -ENOMEM;
}
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c
index a203ecccdc4f..f8e9d0c27be2 100644
--- a/drivers/clk/clk-prima2.c
+++ b/drivers/clk/clk-prima2.c
@@ -1025,20 +1025,67 @@ static struct of_device_id rsc_ids[] = {
{},
};
+enum prima2_clk_index {
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ rtc, osc, pll1, pll2, pll3, mem, sys, security, dsp, gps,
+ mf, io, cpu, uart0, uart1, uart2, tsc, i2c0, i2c1, spi0,
+ spi1, pwmc, efuse, pulse, dmac0, dmac1, nand, audio, usp0, usp1,
+ usp2, vip, gfx, mm, lcd, vpp, mmc01, mmc23, mmc45, usbpll,
+ usb0, usb1, maxclk,
+};
+
+static __initdata struct clk_hw* prima2_clk_hw_array[maxclk] = {
+ NULL, /* dummy */
+ NULL,
+ &clk_pll1.hw,
+ &clk_pll2.hw,
+ &clk_pll3.hw,
+ &clk_mem.hw,
+ &clk_sys.hw,
+ &clk_security.hw,
+ &clk_dsp.hw,
+ &clk_gps.hw,
+ &clk_mf.hw,
+ &clk_io.hw,
+ &clk_cpu.hw,
+ &clk_uart0.hw,
+ &clk_uart1.hw,
+ &clk_uart2.hw,
+ &clk_tsc.hw,
+ &clk_i2c0.hw,
+ &clk_i2c1.hw,
+ &clk_spi0.hw,
+ &clk_spi1.hw,
+ &clk_pwmc.hw,
+ &clk_efuse.hw,
+ &clk_pulse.hw,
+ &clk_dmac0.hw,
+ &clk_dmac1.hw,
+ &clk_nand.hw,
+ &clk_audio.hw,
+ &clk_usp0.hw,
+ &clk_usp1.hw,
+ &clk_usp2.hw,
+ &clk_vip.hw,
+ &clk_gfx.hw,
+ &clk_mm.hw,
+ &clk_lcd.hw,
+ &clk_vpp.hw,
+ &clk_mmc01.hw,
+ &clk_mmc23.hw,
+ &clk_mmc45.hw,
+ &usb_pll_clk_hw,
+ &clk_usb0.hw,
+ &clk_usb1.hw,
+};
+
+static struct clk *prima2_clks[maxclk];
+static struct clk_onecell_data clk_data;
+
void __init sirfsoc_of_clk_init(void)
{
- struct clk *clk;
struct device_node *np;
-
- np = of_find_matching_node(NULL, clkc_ids);
- if (!np)
- panic("unable to find compatible clkc node in dtb\n");
-
- sirfsoc_clk_vbase = of_iomap(np, 0);
- if (!sirfsoc_clk_vbase)
- panic("unable to map clkc registers\n");
-
- of_node_put(np);
+ int i;
np = of_find_matching_node(NULL, rsc_ids);
if (!np)
@@ -1050,122 +1097,30 @@ void __init sirfsoc_of_clk_init(void)
of_node_put(np);
+ np = of_find_matching_node(NULL, clkc_ids);
+ if (!np)
+ return;
+
+ sirfsoc_clk_vbase = of_iomap(np, 0);
+ if (!sirfsoc_clk_vbase)
+ panic("unable to map clkc registers\n");
/* These are always available (RTC and 26MHz OSC)*/
- clk = clk_register_fixed_rate(NULL, "rtc", NULL,
+ prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL,
CLK_IS_ROOT, 32768);
- BUG_ON(IS_ERR(clk));
- clk = clk_register_fixed_rate(NULL, "osc", NULL,
+ prima2_clks[osc]= clk_register_fixed_rate(NULL, "osc", NULL,
CLK_IS_ROOT, 26000000);
- BUG_ON(IS_ERR(clk));
-
- clk = clk_register(NULL, &clk_pll1.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_pll2.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_pll3.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_mem.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_sys.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_security.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b8030000.security");
- clk = clk_register(NULL, &clk_dsp.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_gps.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "a8010000.gps");
- clk = clk_register(NULL, &clk_mf.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_io.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "io");
- clk = clk_register(NULL, &clk_cpu.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "cpu");
- clk = clk_register(NULL, &clk_uart0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0050000.uart");
- clk = clk_register(NULL, &clk_uart1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0060000.uart");
- clk = clk_register(NULL, &clk_uart2.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0070000.uart");
- clk = clk_register(NULL, &clk_tsc.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0110000.tsc");
- clk = clk_register(NULL, &clk_i2c0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00e0000.i2c");
- clk = clk_register(NULL, &clk_i2c1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00f0000.i2c");
- clk = clk_register(NULL, &clk_spi0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00d0000.spi");
- clk = clk_register(NULL, &clk_spi1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0170000.spi");
- clk = clk_register(NULL, &clk_pwmc.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0130000.pwm");
- clk = clk_register(NULL, &clk_efuse.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0140000.efusesys");
- clk = clk_register(NULL, &clk_pulse.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0150000.pulsec");
- clk = clk_register(NULL, &clk_dmac0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00b0000.dma-controller");
- clk = clk_register(NULL, &clk_dmac1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0160000.dma-controller");
- clk = clk_register(NULL, &clk_nand.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0030000.nand");
- clk = clk_register(NULL, &clk_audio.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0040000.audio");
- clk = clk_register(NULL, &clk_usp0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0080000.usp");
- clk = clk_register(NULL, &clk_usp1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0090000.usp");
- clk = clk_register(NULL, &clk_usp2.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00a0000.usp");
- clk = clk_register(NULL, &clk_vip.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00c0000.vip");
- clk = clk_register(NULL, &clk_gfx.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "98000000.graphics");
- clk = clk_register(NULL, &clk_mm.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "a0000000.multimedia");
- clk = clk_register(NULL, &clk_lcd.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "90010000.display");
- clk = clk_register(NULL, &clk_vpp.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "90020000.vpp");
- clk = clk_register(NULL, &clk_mmc01.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_mmc23.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_mmc45.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &usb_pll_clk_hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_usb0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00e0000.usb");
- clk = clk_register(NULL, &clk_usb1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00f0000.usb");
+
+ for (i = pll1; i < maxclk; i++) {
+ prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
+ BUG_ON(!prima2_clks[i]);
+ }
+ clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
+ clk_register_clkdev(prima2_clks[io], NULL, "io");
+ clk_register_clkdev(prima2_clks[mem], NULL, "mem");
+
+ clk_data.clks = prima2_clks;
+ clk_data.clk_num = maxclk;
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
}
diff --git a/drivers/clk/clk-sunxi.c b/drivers/clk/clk-sunxi.c
deleted file mode 100644
index 0e831b584ba7..000000000000
--- a/drivers/clk/clk-sunxi.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2012 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.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.
- */
-
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include <linux/clk/sunxi.h>
-#include <linux/of.h>
-
-static const __initconst struct of_device_id clk_match[] = {
- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
- {}
-};
-
-void __init sunxi_init_clocks(void)
-{
- of_clk_init(clk_match);
-}
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c
index fe25570874d6..b5538bba7a10 100644
--- a/drivers/clk/clk-vt8500.c
+++ b/drivers/clk/clk-vt8500.c
@@ -41,6 +41,7 @@ struct clk_device {
#define PLL_TYPE_VT8500 0
#define PLL_TYPE_WM8650 1
+#define PLL_TYPE_WM8750 2
struct clk_pll {
struct clk_hw hw;
@@ -121,7 +122,16 @@ static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_device *cdev = to_clk_device(hw);
- u32 divisor = *prate / rate;
+ u32 divisor;
+
+ if (rate == 0)
+ return 0;
+
+ divisor = *prate / rate;
+
+ /* If prate / rate would be decimal, incr the divisor */
+ if (rate * divisor < *prate)
+ divisor++;
/*
* If this is a request for SDMMC we have to adjust the divisor
@@ -138,9 +148,18 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_device *cdev = to_clk_device(hw);
- u32 divisor = parent_rate / rate;
+ u32 divisor;
unsigned long flags = 0;
+ if (rate == 0)
+ return 0;
+
+ divisor = parent_rate / rate;
+
+ /* If prate / rate would be decimal, incr the divisor */
+ if (rate * divisor < *prate)
+ divisor++;
+
if (divisor == cdev->div_mask + 1)
divisor = 0;
@@ -272,7 +291,7 @@ static __init void vtwm_device_clk_init(struct device_node *node)
rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
clk_register_clkdev(clk, clk_name, NULL);
}
-
+CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init);
/* PLL clock related functions */
@@ -298,6 +317,16 @@ static __init void vtwm_device_clk_init(struct device_node *node)
#define WM8650_BITS_TO_VAL(m, d1, d2) \
((d2 << 13) | (d1 << 10) | (m & 0x3FF))
+/* Helper macros for PLL_WM8750 */
+#define WM8750_PLL_MUL(x) (((x >> 16) & 0xFF) + 1)
+#define WM8750_PLL_DIV(x) ((((x >> 8) & 1) + 1) * (1 << (x & 7)))
+
+#define WM8750_BITS_TO_FREQ(r, m, d1, d2) \
+ (r * (m+1) / ((d1+1) * (1 << d2)))
+
+#define WM8750_BITS_TO_VAL(f, m, d1, d2) \
+ ((f << 24) | ((m - 1) << 16) | ((d1 - 1) << 8) | d2)
+
static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate,
u32 *multiplier, u32 *prediv)
@@ -361,16 +390,87 @@ static void wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate,
/* if we got here, it wasn't an exact match */
pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
rate - best_err);
- *multiplier = mul;
- *divisor1 = div1;
- *divisor2 = div2;
+ *multiplier = best_mul;
+ *divisor1 = best_div1;
+ *divisor2 = best_div2;
+}
+
+static u32 wm8750_get_filter(u32 parent_rate, u32 divisor1)
+{
+ /* calculate frequency (MHz) after pre-divisor */
+ u32 freq = (parent_rate / 1000000) / (divisor1 + 1);
+
+ if ((freq < 10) || (freq > 200))
+ pr_warn("%s: PLL recommended input frequency 10..200Mhz (requested %d Mhz)\n",
+ __func__, freq);
+
+ if (freq >= 166)
+ return 7;
+ else if (freq >= 104)
+ return 6;
+ else if (freq >= 65)
+ return 5;
+ else if (freq >= 42)
+ return 4;
+ else if (freq >= 26)
+ return 3;
+ else if (freq >= 16)
+ return 2;
+ else if (freq >= 10)
+ return 1;
+
+ return 0;
+}
+
+static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,
+ u32 *filter, u32 *multiplier, u32 *divisor1, u32 *divisor2)
+{
+ u32 mul, div1, div2;
+ u32 best_mul, best_div1, best_div2;
+ unsigned long tclk, rate_err, best_err;
+
+ best_err = (unsigned long)-1;
+
+ /* Find the closest match (lower or equal to requested) */
+ for (div1 = 1; div1 >= 0; div1--)
+ for (div2 = 7; div2 >= 0; div2--)
+ for (mul = 0; mul <= 255; mul++) {
+ tclk = parent_rate * (mul + 1) / ((div1 + 1) * (1 << div2));
+ if (tclk > rate)
+ continue;
+ /* error will always be +ve */
+ rate_err = rate - tclk;
+ if (rate_err == 0) {
+ *filter = wm8750_get_filter(parent_rate, div1);
+ *multiplier = mul;
+ *divisor1 = div1;
+ *divisor2 = div2;
+ return;
+ }
+
+ if (rate_err < best_err) {
+ best_err = rate_err;
+ best_mul = mul;
+ best_div1 = div1;
+ best_div2 = div2;
+ }
+ }
+
+ /* if we got here, it wasn't an exact match */
+ pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
+ rate - best_err);
+
+ *filter = wm8750_get_filter(parent_rate, best_div1);
+ *multiplier = best_mul;
+ *divisor1 = best_div1;
+ *divisor2 = best_div2;
}
static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_pll *pll = to_clk_pll(hw);
- u32 mul, div1, div2;
+ u32 filter, mul, div1, div2;
u32 pll_val;
unsigned long flags = 0;
@@ -385,6 +485,9 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
wm8650_find_pll_bits(rate, parent_rate, &mul, &div1, &div2);
pll_val = WM8650_BITS_TO_VAL(mul, div1, div2);
break;
+ case PLL_TYPE_WM8750:
+ wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2);
+ pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2);
default:
pr_err("%s: invalid pll type\n", __func__);
return 0;
@@ -405,7 +508,7 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_pll *pll = to_clk_pll(hw);
- u32 mul, div1, div2;
+ u32 filter, mul, div1, div2;
long round_rate;
switch (pll->type) {
@@ -417,6 +520,9 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
wm8650_find_pll_bits(rate, *prate, &mul, &div1, &div2);
round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2);
break;
+ case PLL_TYPE_WM8750:
+ wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);
+ round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);
default:
round_rate = 0;
}
@@ -440,6 +546,10 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw,
pll_freq = parent_rate * WM8650_PLL_MUL(pll_val);
pll_freq /= WM8650_PLL_DIV(pll_val);
break;
+ case PLL_TYPE_WM8750:
+ pll_freq = parent_rate * WM8750_PLL_MUL(pll_val);
+ pll_freq /= WM8750_PLL_DIV(pll_val);
+ break;
default:
pll_freq = 0;
}
@@ -502,20 +612,19 @@ static void __init vt8500_pll_init(struct device_node *node)
{
vtwm_pll_clk_init(node, PLL_TYPE_VT8500);
}
+CLK_OF_DECLARE(vt8500_pll, "via,vt8500-pll-clock", vt8500_pll_init);
static void __init wm8650_pll_init(struct device_node *node)
{
vtwm_pll_clk_init(node, PLL_TYPE_WM8650);
}
+CLK_OF_DECLARE(wm8650_pll, "wm,wm8650-pll-clock", wm8650_pll_init);
-static const __initconst struct of_device_id clk_match[] = {
- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
- { .compatible = "via,vt8500-pll-clock", .data = vt8500_pll_init, },
- { .compatible = "wm,wm8650-pll-clock", .data = wm8650_pll_init, },
- { .compatible = "via,vt8500-device-clock",
- .data = vtwm_device_clk_init, },
- { /* sentinel */ }
-};
+static void __init wm8750_pll_init(struct device_node *node)
+{
+ vtwm_pll_clk_init(node, PLL_TYPE_WM8750);
+}
+CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init);
void __init vtwm_clk_init(void __iomem *base)
{
@@ -524,5 +633,5 @@ void __init vtwm_clk_init(void __iomem *base)
pmc_base = base;
- of_clk_init(clk_match);
+ of_clk_init(NULL);
}
diff --git a/drivers/clk/clk-zynq.c b/drivers/clk/clk-zynq.c
index 37a30514fd66..b14a25f39255 100644
--- a/drivers/clk/clk-zynq.c
+++ b/drivers/clk/clk-zynq.c
@@ -81,6 +81,7 @@ static void __init zynq_pll_clk_setup(struct device_node *np)
if (WARN_ON(ret))
return;
}
+CLK_OF_DECLARE(zynq_pll, "xlnx,zynq-pll", zynq_pll_clk_setup);
struct zynq_periph_clk {
struct clk_hw hw;
@@ -187,6 +188,7 @@ static void __init zynq_periph_clk_setup(struct device_node *np)
if (WARN_ON(err))
return;
}
+CLK_OF_DECLARE(zynq_periph, "xlnx,zynq-periph-clock", zynq_periph_clk_setup);
/* CPU Clock domain is modelled as a mux with 4 children subclks, whose
* derivative rates depend on CLK_621_TRUE
@@ -366,18 +368,10 @@ static void __init zynq_cpu_clk_setup(struct device_node *np)
if (WARN_ON(err))
return;
}
-
-static const __initconst struct of_device_id zynq_clk_match[] = {
- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
- { .compatible = "xlnx,zynq-pll", .data = zynq_pll_clk_setup, },
- { .compatible = "xlnx,zynq-periph-clock",
- .data = zynq_periph_clk_setup, },
- { .compatible = "xlnx,zynq-cpu-clock", .data = zynq_cpu_clk_setup, },
- {}
-};
+CLK_OF_DECLARE(zynq_cpu, "xlnx,zynq-cpu-clock", zynq_cpu_clk_setup);
void __init xilinx_zynq_clocks_init(void __iomem *slcr)
{
slcr_base = slcr;
- of_clk_init(zynq_clk_match);
+ of_clk_init(NULL);
}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 251e45d6024d..fabbfe1a9253 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/device.h>
+#include <linux/init.h>
static DEFINE_SPINLOCK(enable_lock);
static DEFINE_MUTEX(prepare_lock);
@@ -35,6 +36,137 @@ static struct dentry *rootdir;
static struct dentry *orphandir;
static int inited = 0;
+static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
+{
+ if (!c)
+ return;
+
+ seq_printf(s, "%*s%-*s %-11d %-12d %-10lu",
+ level * 3 + 1, "",
+ 30 - level * 3, c->name,
+ c->enable_count, c->prepare_count, c->rate);
+ seq_printf(s, "\n");
+}
+
+static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
+ int level)
+{
+ struct clk *child;
+ struct hlist_node *tmp;
+
+ if (!c)
+ return;
+
+ clk_summary_show_one(s, c, level);
+
+ hlist_for_each_entry(child, tmp, &c->children, child_node)
+ clk_summary_show_subtree(s, child, level + 1);
+}
+
+static int clk_summary_show(struct seq_file *s, void *data)
+{
+ struct clk *c;
+ struct hlist_node *tmp;
+
+ seq_printf(s, " clock enable_cnt prepare_cnt rate\n");
+ seq_printf(s, "---------------------------------------------------------------------\n");
+
+ mutex_lock(&prepare_lock);
+
+ hlist_for_each_entry(c, tmp, &clk_root_list, child_node)
+ clk_summary_show_subtree(s, c, 0);
+
+ hlist_for_each_entry(c, tmp, &clk_orphan_list, child_node)
+ clk_summary_show_subtree(s, c, 0);
+
+ mutex_unlock(&prepare_lock);
+
+ return 0;
+}
+
+
+static int clk_summary_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clk_summary_show, inode->i_private);
+}
+
+static const struct file_operations clk_summary_fops = {
+ .open = clk_summary_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
+{
+ if (!c)
+ return;
+
+ seq_printf(s, "\"%s\": { ", c->name);
+ seq_printf(s, "\"enable_count\": %d,", c->enable_count);
+ seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
+ seq_printf(s, "\"rate\": %lu", c->rate);
+}
+
+static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
+{
+ struct clk *child;
+ struct hlist_node *tmp;
+
+ if (!c)
+ return;
+
+ clk_dump_one(s, c, level);
+
+ hlist_for_each_entry(child, tmp, &c->children, child_node) {
+ seq_printf(s, ",");
+ clk_dump_subtree(s, child, level + 1);
+ }
+
+ seq_printf(s, "}");
+}
+
+static int clk_dump(struct seq_file *s, void *data)
+{
+ struct clk *c;
+ struct hlist_node *tmp;
+ bool first_node = true;
+
+ seq_printf(s, "{");
+
+ mutex_lock(&prepare_lock);
+
+ hlist_for_each_entry(c, tmp, &clk_root_list, child_node) {
+ if (!first_node)
+ seq_printf(s, ",");
+ first_node = false;
+ clk_dump_subtree(s, c, 0);
+ }
+
+ hlist_for_each_entry(c, tmp, &clk_orphan_list, child_node) {
+ seq_printf(s, ",");
+ clk_dump_subtree(s, c, 0);
+ }
+
+ mutex_unlock(&prepare_lock);
+
+ seq_printf(s, "}");
+ return 0;
+}
+
+
+static int clk_dump_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clk_dump, inode->i_private);
+}
+
+static const struct file_operations clk_dump_fops = {
+ .open = clk_dump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/* caller must hold prepare_lock */
static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
{
@@ -168,12 +300,23 @@ static int __init clk_debug_init(void)
{
struct clk *clk;
struct hlist_node *tmp;
+ struct dentry *d;
rootdir = debugfs_create_dir("clk", NULL);
if (!rootdir)
return -ENOMEM;
+ d = debugfs_create_file("clk_summary", S_IRUGO, rootdir, NULL,
+ &clk_summary_fops);
+ if (!d)
+ return -ENOMEM;
+
+ d = debugfs_create_file("clk_dump", S_IRUGO, rootdir, NULL,
+ &clk_dump_fops);
+ if (!d)
+ return -ENOMEM;
+
orphandir = debugfs_create_dir("orphans", rootdir);
if (!orphandir)
@@ -259,32 +402,33 @@ late_initcall(clk_disable_unused);
/*** helper functions ***/
-inline const char *__clk_get_name(struct clk *clk)
+const char *__clk_get_name(struct clk *clk)
{
return !clk ? NULL : clk->name;
}
+EXPORT_SYMBOL_GPL(__clk_get_name);
-inline struct clk_hw *__clk_get_hw(struct clk *clk)
+struct clk_hw *__clk_get_hw(struct clk *clk)
{
return !clk ? NULL : clk->hw;
}
-inline u8 __clk_get_num_parents(struct clk *clk)
+u8 __clk_get_num_parents(struct clk *clk)
{
return !clk ? 0 : clk->num_parents;
}
-inline struct clk *__clk_get_parent(struct clk *clk)
+struct clk *__clk_get_parent(struct clk *clk)
{
return !clk ? NULL : clk->parent;
}
-inline unsigned int __clk_get_enable_count(struct clk *clk)
+unsigned int __clk_get_enable_count(struct clk *clk)
{
return !clk ? 0 : clk->enable_count;
}
-inline unsigned int __clk_get_prepare_count(struct clk *clk)
+unsigned int __clk_get_prepare_count(struct clk *clk)
{
return !clk ? 0 : clk->prepare_count;
}
@@ -310,7 +454,7 @@ out:
return ret;
}
-inline unsigned long __clk_get_flags(struct clk *clk)
+unsigned long __clk_get_flags(struct clk *clk)
{
return !clk ? 0 : clk->flags;
}
@@ -950,9 +1094,6 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
/* change the rates */
clk_change_rate(top);
- mutex_unlock(&prepare_lock);
-
- return 0;
out:
mutex_unlock(&prepare_lock);
@@ -1663,6 +1804,11 @@ struct of_clk_provider {
void *data;
};
+extern struct of_device_id __clk_of_table[];
+
+static const struct of_device_id __clk_of_table_sentinel
+ __used __section(__clk_of_table_end);
+
static LIST_HEAD(of_clk_providers);
static DEFINE_MUTEX(of_clk_lock);
@@ -1791,6 +1937,9 @@ void __init of_clk_init(const struct of_device_id *matches)
{
struct device_node *np;
+ if (!matches)
+ matches = __clk_of_table;
+
for_each_matching_node(np, matches) {
const struct of_device_id *match = of_match_node(matches, np);
of_clk_init_cb_t clk_init_cb = match->data;
diff --git a/drivers/clk/mvebu/clk-gating-ctrl.c b/drivers/clk/mvebu/clk-gating-ctrl.c
index 8fa5408b6c7d..ebf141d4374b 100644
--- a/drivers/clk/mvebu/clk-gating-ctrl.c
+++ b/drivers/clk/mvebu/clk-gating-ctrl.c
@@ -193,6 +193,7 @@ static const struct mvebu_soc_descr __initconst kirkwood_gating_descr[] = {
{ "runit", NULL, 7 },
{ "xor0", NULL, 8 },
{ "audio", NULL, 9 },
+ { "powersave", "cpuclk", 11 },
{ "sata0", NULL, 14 },
{ "sata1", NULL, 15 },
{ "xor1", NULL, 16 },
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index 8dd476e2a9c5..b5c06f9766f6 100644
--- a/drivers/clk/mxs/clk-imx23.c
+++ b/drivers/clk/mxs/clk-imx23.c
@@ -99,7 +99,7 @@ static enum imx23_clk clks_init_on[] __initdata = {
int __init mx23_clocks_init(void)
{
struct device_node *np;
- int i;
+ u32 i;
clk_misc_init();
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index db3af0874121..76ce6c6d1113 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -154,7 +154,7 @@ static enum imx28_clk clks_init_on[] __initdata = {
int __init mx28_clocks_init(void)
{
struct device_node *np;
- int i;
+ u32 i;
clk_misc_init();
@@ -238,7 +238,7 @@ int __init mx28_clocks_init(void)
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
}
- clk_register_clkdev(clks[clk32k], NULL, "timrot");
+ clk_register_clkdev(clks[xbus], NULL, "timrot");
clk_register_clkdev(clks[enet_out], NULL, "enet_out");
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
new file mode 100644
index 000000000000..2b41b0f4f731
--- /dev/null
+++ b/drivers/clk/tegra/Makefile
@@ -0,0 +1,11 @@
+obj-y += clk.o
+obj-y += clk-audio-sync.o
+obj-y += clk-divider.o
+obj-y += clk-periph.o
+obj-y += clk-periph-gate.o
+obj-y += clk-pll.o
+obj-y += clk-pll-out.o
+obj-y += clk-super.o
+
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
diff --git a/drivers/clk/tegra/clk-audio-sync.c b/drivers/clk/tegra/clk-audio-sync.c
new file mode 100644
index 000000000000..c0f7843e80e6
--- /dev/null
+++ b/drivers/clk/tegra/clk-audio-sync.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include "clk.h"
+
+static unsigned long clk_sync_source_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
+
+ return sync->rate;
+}
+
+static long clk_sync_source_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
+
+ if (rate > sync->max_rate)
+ return -EINVAL;
+ else
+ return rate;
+}
+
+static int clk_sync_source_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
+
+ sync->rate = rate;
+ return 0;
+}
+
+const struct clk_ops tegra_clk_sync_source_ops = {
+ .round_rate = clk_sync_source_round_rate,
+ .set_rate = clk_sync_source_set_rate,
+ .recalc_rate = clk_sync_source_recalc_rate,
+};
+
+struct clk *tegra_clk_register_sync_source(const char *name,
+ unsigned long rate, unsigned long max_rate)
+{
+ struct tegra_clk_sync_source *sync;
+ struct clk_init_data init;
+ struct clk *clk;
+
+ sync = kzalloc(sizeof(*sync), GFP_KERNEL);
+ if (!sync) {
+ pr_err("%s: could not allocate sync source clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ sync->rate = rate;
+ sync->max_rate = max_rate;
+
+ init.ops = &tegra_clk_sync_source_ops;
+ init.name = name;
+ init.flags = CLK_IS_ROOT;
+ init.parent_names = NULL;
+ init.num_parents = 0;
+
+ /* Data in .init is copied by clk_register(), so stack variable OK */
+ sync->hw.init = &init;
+
+ clk = clk_register(NULL, &sync->hw);
+ if (IS_ERR(clk))
+ kfree(sync);
+
+ return clk;
+}
diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
new file mode 100644
index 000000000000..4d75b1f37e3a
--- /dev/null
+++ b/drivers/clk/tegra/clk-divider.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+
+#include "clk.h"
+
+#define pll_out_override(p) (BIT((p->shift - 6)))
+#define div_mask(d) ((1 << (d->width)) - 1)
+#define get_mul(d) (1 << d->frac_width)
+#define get_max_div(d) div_mask(d)
+
+#define PERIPH_CLK_UART_DIV_ENB BIT(24)
+
+static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
+ unsigned long parent_rate)
+{
+ s64 divider_ux1 = parent_rate;
+ u8 flags = divider->flags;
+ int mul;
+
+ if (!rate)
+ return 0;
+
+ mul = get_mul(divider);
+
+ if (!(flags & TEGRA_DIVIDER_INT))
+ divider_ux1 *= mul;
+
+ if (flags & TEGRA_DIVIDER_ROUND_UP)
+ divider_ux1 += rate - 1;
+
+ do_div(divider_ux1, rate);
+
+ if (flags & TEGRA_DIVIDER_INT)
+ divider_ux1 *= mul;
+
+ divider_ux1 -= mul;
+
+ if (divider_ux1 < 0)
+ return 0;
+
+ if (divider_ux1 > get_max_div(divider))
+ return -EINVAL;
+
+ return divider_ux1;
+}
+
+static unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
+ u32 reg;
+ int div, mul;
+ u64 rate = parent_rate;
+
+ reg = readl_relaxed(divider->reg) >> divider->shift;
+ div = reg & div_mask(divider);
+
+ mul = get_mul(divider);
+ div += mul;
+
+ rate *= mul;
+ rate += div - 1;
+ do_div(rate, div);
+
+ return rate;
+}
+
+static long clk_frac_div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
+ int div, mul;
+ unsigned long output_rate = *prate;
+
+ if (!rate)
+ return output_rate;
+
+ div = get_div(divider, rate, output_rate);
+ if (div < 0)
+ return *prate;
+
+ mul = get_mul(divider);
+
+ return DIV_ROUND_UP(output_rate * mul, div + mul);
+}
+
+static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
+ int div;
+ unsigned long flags = 0;
+ u32 val;
+
+ div = get_div(divider, rate, parent_rate);
+ if (div < 0)
+ return div;
+
+ if (divider->lock)
+ spin_lock_irqsave(divider->lock, flags);
+
+ val = readl_relaxed(divider->reg);
+ val &= ~(div_mask(divider) << divider->shift);
+ val |= div << divider->shift;
+
+ if (divider->flags & TEGRA_DIVIDER_UART) {
+ if (div)
+ val |= PERIPH_CLK_UART_DIV_ENB;
+ else
+ val &= ~PERIPH_CLK_UART_DIV_ENB;
+ }
+
+ if (divider->flags & TEGRA_DIVIDER_FIXED)
+ val |= pll_out_override(divider);
+
+ writel_relaxed(val, divider->reg);
+
+ if (divider->lock)
+ spin_unlock_irqrestore(divider->lock, flags);
+
+ return 0;
+}
+
+const struct clk_ops tegra_clk_frac_div_ops = {
+ .recalc_rate = clk_frac_div_recalc_rate,
+ .set_rate = clk_frac_div_set_rate,
+ .round_rate = clk_frac_div_round_rate,
+};
+
+struct clk *tegra_clk_register_divider(const char *name,
+ const char *parent_name, void __iomem *reg,
+ unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width,
+ u8 frac_width, spinlock_t *lock)
+{
+ struct tegra_clk_frac_div *divider;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ divider = kzalloc(sizeof(*divider), GFP_KERNEL);
+ if (!divider) {
+ pr_err("%s: could not allocate fractional divider clk\n",
+ __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.ops = &tegra_clk_frac_div_ops;
+ init.flags = flags;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ divider->reg = reg;
+ divider->shift = shift;
+ divider->width = width;
+ divider->frac_width = frac_width;
+ divider->lock = lock;
+ divider->flags = clk_divider_flags;
+
+ /* Data in .init is copied by clk_register(), so stack variable OK */
+ divider->hw.init = &init;
+
+ clk = clk_register(NULL, &divider->hw);
+ if (IS_ERR(clk))
+ kfree(divider);
+
+ return clk;
+}
diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
new file mode 100644
index 000000000000..6dd533251e7b
--- /dev/null
+++ b/drivers/clk/tegra/clk-periph-gate.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/tegra-soc.h>
+
+#include "clk.h"
+
+static DEFINE_SPINLOCK(periph_ref_lock);
+
+/* Macros to assist peripheral gate clock */
+#define read_enb(gate) \
+ readl_relaxed(gate->clk_base + (gate->regs->enb_reg))
+#define write_enb_set(val, gate) \
+ writel_relaxed(val, gate->clk_base + (gate->regs->enb_set_reg))
+#define write_enb_clr(val, gate) \
+ writel_relaxed(val, gate->clk_base + (gate->regs->enb_clr_reg))
+
+#define read_rst(gate) \
+ readl_relaxed(gate->clk_base + (gate->regs->rst_reg))
+#define write_rst_set(val, gate) \
+ writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg))
+#define write_rst_clr(val, gate) \
+ writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg))
+
+#define periph_clk_to_bit(periph) (1 << (gate->clk_num % 32))
+
+/* Peripheral gate clock ops */
+static int clk_periph_is_enabled(struct clk_hw *hw)
+{
+ struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
+ int state = 1;
+
+ if (!(read_enb(gate) & periph_clk_to_bit(gate)))
+ state = 0;
+
+ if (!(gate->flags & TEGRA_PERIPH_NO_RESET))
+ if (read_rst(gate) & periph_clk_to_bit(gate))
+ state = 0;
+
+ return state;
+}
+
+static int clk_periph_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&periph_ref_lock, flags);
+
+ gate->enable_refcnt[gate->clk_num]++;
+ if (gate->enable_refcnt[gate->clk_num] > 1) {
+ spin_unlock_irqrestore(&periph_ref_lock, flags);
+ return 0;
+ }
+
+ write_enb_set(periph_clk_to_bit(gate), gate);
+ udelay(2);
+
+ if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
+ !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
+ if (read_rst(gate) & periph_clk_to_bit(gate)) {
+ udelay(5); /* reset propogation delay */
+ write_rst_clr(periph_clk_to_bit(gate), gate);
+ }
+ }
+
+ spin_unlock_irqrestore(&periph_ref_lock, flags);
+
+ return 0;
+}
+
+static void clk_periph_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&periph_ref_lock, flags);
+
+ gate->enable_refcnt[gate->clk_num]--;
+ if (gate->enable_refcnt[gate->clk_num] > 0) {
+ spin_unlock_irqrestore(&periph_ref_lock, flags);
+ return;
+ }
+
+ /*
+ * If peripheral is in the APB bus then read the APB bus to
+ * flush the write operation in apb bus. This will avoid the
+ * peripheral access after disabling clock
+ */
+ if (gate->flags & TEGRA_PERIPH_ON_APB)
+ tegra_read_chipid();
+
+ write_enb_clr(periph_clk_to_bit(gate), gate);
+
+ spin_unlock_irqrestore(&periph_ref_lock, flags);
+}
+
+void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert)
+{
+ if (gate->flags & TEGRA_PERIPH_NO_RESET)
+ return;
+
+ if (assert) {
+ /*
+ * If peripheral is in the APB bus then read the APB bus to
+ * flush the write operation in apb bus. This will avoid the
+ * peripheral access after disabling clock
+ */
+ if (gate->flags & TEGRA_PERIPH_ON_APB)
+ tegra_read_chipid();
+
+ write_rst_set(periph_clk_to_bit(gate), gate);
+ } else {
+ write_rst_clr(periph_clk_to_bit(gate), gate);
+ }
+}
+
+const struct clk_ops tegra_clk_periph_gate_ops = {
+ .is_enabled = clk_periph_is_enabled,
+ .enable = clk_periph_enable,
+ .disable = clk_periph_disable,
+};
+
+struct clk *tegra_clk_register_periph_gate(const char *name,
+ const char *parent_name, u8 gate_flags, void __iomem *clk_base,
+ unsigned long flags, int clk_num,
+ struct tegra_clk_periph_regs *pregs, int *enable_refcnt)
+{
+ struct tegra_clk_periph_gate *gate;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ pr_err("%s: could not allocate periph gate clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.flags = flags;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+ init.ops = &tegra_clk_periph_gate_ops;
+
+ gate->magic = TEGRA_CLK_PERIPH_GATE_MAGIC;
+ gate->clk_base = clk_base;
+ gate->clk_num = clk_num;
+ gate->flags = gate_flags;
+ gate->enable_refcnt = enable_refcnt;
+ gate->regs = pregs;
+
+ /* Data in .init is copied by clk_register(), so stack variable OK */
+ gate->hw.init = &init;
+
+ clk = clk_register(NULL, &gate->hw);
+ if (IS_ERR(clk))
+ kfree(gate);
+
+ return clk;
+}
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
new file mode 100644
index 000000000000..788486e6331a
--- /dev/null
+++ b/drivers/clk/tegra/clk-periph.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include "clk.h"
+
+static u8 clk_periph_get_parent(struct clk_hw *hw)
+{
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ const struct clk_ops *mux_ops = periph->mux_ops;
+ struct clk_hw *mux_hw = &periph->mux.hw;
+
+ mux_hw->clk = hw->clk;
+
+ return mux_ops->get_parent(mux_hw);
+}
+
+static int clk_periph_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ const struct clk_ops *mux_ops = periph->mux_ops;
+ struct clk_hw *mux_hw = &periph->mux.hw;
+
+ mux_hw->clk = hw->clk;
+
+ return mux_ops->set_parent(mux_hw, index);
+}
+
+static unsigned long clk_periph_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ const struct clk_ops *div_ops = periph->div_ops;
+ struct clk_hw *div_hw = &periph->divider.hw;
+
+ div_hw->clk = hw->clk;
+
+ return div_ops->recalc_rate(div_hw, parent_rate);
+}
+
+static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ const struct clk_ops *div_ops = periph->div_ops;
+ struct clk_hw *div_hw = &periph->divider.hw;
+
+ div_hw->clk = hw->clk;
+
+ return div_ops->round_rate(div_hw, rate, prate);
+}
+
+static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ const struct clk_ops *div_ops = periph->div_ops;
+ struct clk_hw *div_hw = &periph->divider.hw;
+
+ div_hw->clk = hw->clk;
+
+ return div_ops->set_rate(div_hw, rate, parent_rate);
+}
+
+static int clk_periph_is_enabled(struct clk_hw *hw)
+{
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ const struct clk_ops *gate_ops = periph->gate_ops;
+ struct clk_hw *gate_hw = &periph->gate.hw;
+
+ gate_hw->clk = hw->clk;
+
+ return gate_ops->is_enabled(gate_hw);
+}
+
+static int clk_periph_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ const struct clk_ops *gate_ops = periph->gate_ops;
+ struct clk_hw *gate_hw = &periph->gate.hw;
+
+ gate_hw->clk = hw->clk;
+
+ return gate_ops->enable(gate_hw);
+}
+
+static void clk_periph_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ const struct clk_ops *gate_ops = periph->gate_ops;
+ struct clk_hw *gate_hw = &periph->gate.hw;
+
+ gate_ops->disable(gate_hw);
+}
+
+void tegra_periph_reset_deassert(struct clk *c)
+{
+ struct clk_hw *hw = __clk_get_hw(c);
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ struct tegra_clk_periph_gate *gate;
+
+ if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) {
+ gate = to_clk_periph_gate(hw);
+ if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) {
+ WARN_ON(1);
+ return;
+ }
+ } else {
+ gate = &periph->gate;
+ }
+
+ tegra_periph_reset(gate, 0);
+}
+
+void tegra_periph_reset_assert(struct clk *c)
+{
+ struct clk_hw *hw = __clk_get_hw(c);
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ struct tegra_clk_periph_gate *gate;
+
+ if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) {
+ gate = to_clk_periph_gate(hw);
+ if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) {
+ WARN_ON(1);
+ return;
+ }
+ } else {
+ gate = &periph->gate;
+ }
+
+ tegra_periph_reset(gate, 1);
+}
+
+const struct clk_ops tegra_clk_periph_ops = {
+ .get_parent = clk_periph_get_parent,
+ .set_parent = clk_periph_set_parent,
+ .recalc_rate = clk_periph_recalc_rate,
+ .round_rate = clk_periph_round_rate,
+ .set_rate = clk_periph_set_rate,
+ .is_enabled = clk_periph_is_enabled,
+ .enable = clk_periph_enable,
+ .disable = clk_periph_disable,
+};
+
+const struct clk_ops tegra_clk_periph_nodiv_ops = {
+ .get_parent = clk_periph_get_parent,
+ .set_parent = clk_periph_set_parent,
+ .is_enabled = clk_periph_is_enabled,
+ .enable = clk_periph_enable,
+ .disable = clk_periph_disable,
+};
+
+static struct clk *_tegra_clk_register_periph(const char *name,
+ const char **parent_names, int num_parents,
+ struct tegra_clk_periph *periph,
+ void __iomem *clk_base, u32 offset, bool div)
+{
+ struct clk *clk;
+ struct clk_init_data init;
+
+ init.name = name;
+ init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops;
+ init.flags = div ? 0 : CLK_SET_RATE_PARENT;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+
+ /* Data in .init is copied by clk_register(), so stack variable OK */
+ periph->hw.init = &init;
+ periph->magic = TEGRA_CLK_PERIPH_MAGIC;
+ periph->mux.reg = clk_base + offset;
+ periph->divider.reg = div ? (clk_base + offset) : NULL;
+ periph->gate.clk_base = clk_base;
+
+ clk = clk_register(NULL, &periph->hw);
+ if (IS_ERR(clk))
+ return clk;
+
+ periph->mux.hw.clk = clk;
+ periph->divider.hw.clk = div ? clk : NULL;
+ periph->gate.hw.clk = clk;
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_periph(const char *name,
+ const char **parent_names, int num_parents,
+ struct tegra_clk_periph *periph, void __iomem *clk_base,
+ u32 offset)
+{
+ return _tegra_clk_register_periph(name, parent_names, num_parents,
+ periph, clk_base, offset, true);
+}
+
+struct clk *tegra_clk_register_periph_nodiv(const char *name,
+ const char **parent_names, int num_parents,
+ struct tegra_clk_periph *periph, void __iomem *clk_base,
+ u32 offset)
+{
+ return _tegra_clk_register_periph(name, parent_names, num_parents,
+ periph, clk_base, offset, false);
+}
diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c
new file mode 100644
index 000000000000..3598987a451d
--- /dev/null
+++ b/drivers/clk/tegra/clk-pll-out.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+
+#include "clk.h"
+
+#define pll_out_enb(p) (BIT(p->enb_bit_idx))
+#define pll_out_rst(p) (BIT(p->rst_bit_idx))
+
+static int clk_pll_out_is_enabled(struct clk_hw *hw)
+{
+ struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
+ u32 val = readl_relaxed(pll_out->reg);
+ int state;
+
+ state = (val & pll_out_enb(pll_out)) ? 1 : 0;
+ if (!(val & (pll_out_rst(pll_out))))
+ state = 0;
+ return state;
+}
+
+static int clk_pll_out_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (pll_out->lock)
+ spin_lock_irqsave(pll_out->lock, flags);
+
+ val = readl_relaxed(pll_out->reg);
+
+ val |= (pll_out_enb(pll_out) | pll_out_rst(pll_out));
+
+ writel_relaxed(val, pll_out->reg);
+ udelay(2);
+
+ if (pll_out->lock)
+ spin_unlock_irqrestore(pll_out->lock, flags);
+
+ return 0;
+}
+
+static void clk_pll_out_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (pll_out->lock)
+ spin_lock_irqsave(pll_out->lock, flags);
+
+ val = readl_relaxed(pll_out->reg);
+
+ val &= ~(pll_out_enb(pll_out) | pll_out_rst(pll_out));
+
+ writel_relaxed(val, pll_out->reg);
+ udelay(2);
+
+ if (pll_out->lock)
+ spin_unlock_irqrestore(pll_out->lock, flags);
+}
+
+const struct clk_ops tegra_clk_pll_out_ops = {
+ .is_enabled = clk_pll_out_is_enabled,
+ .enable = clk_pll_out_enable,
+ .disable = clk_pll_out_disable,
+};
+
+struct clk *tegra_clk_register_pll_out(const char *name,
+ const char *parent_name, void __iomem *reg, u8 enb_bit_idx,
+ u8 rst_bit_idx, unsigned long flags, u8 pll_out_flags,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll_out *pll_out;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll_out = kzalloc(sizeof(*pll_out), GFP_KERNEL);
+ if (!pll_out)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &tegra_clk_pll_out_ops;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+ init.flags = flags;
+
+ pll_out->reg = reg;
+ pll_out->enb_bit_idx = enb_bit_idx;
+ pll_out->rst_bit_idx = rst_bit_idx;
+ pll_out->flags = pll_out_flags;
+ pll_out->lock = lock;
+
+ /* Data in .init is copied by clk_register(), so stack variable OK */
+ pll_out->hw.init = &init;
+
+ clk = clk_register(NULL, &pll_out->hw);
+ if (IS_ERR(clk))
+ kfree(pll_out);
+
+ return clk;
+}
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
new file mode 100644
index 000000000000..165f24734c1b
--- /dev/null
+++ b/drivers/clk/tegra/clk-pll.c
@@ -0,0 +1,648 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+
+#include "clk.h"
+
+#define PLL_BASE_BYPASS BIT(31)
+#define PLL_BASE_ENABLE BIT(30)
+#define PLL_BASE_REF_ENABLE BIT(29)
+#define PLL_BASE_OVERRIDE BIT(28)
+
+#define PLL_BASE_DIVP_SHIFT 20
+#define PLL_BASE_DIVP_WIDTH 3
+#define PLL_BASE_DIVN_SHIFT 8
+#define PLL_BASE_DIVN_WIDTH 10
+#define PLL_BASE_DIVM_SHIFT 0
+#define PLL_BASE_DIVM_WIDTH 5
+#define PLLU_POST_DIVP_MASK 0x1
+
+#define PLL_MISC_DCCON_SHIFT 20
+#define PLL_MISC_CPCON_SHIFT 8
+#define PLL_MISC_CPCON_WIDTH 4
+#define PLL_MISC_CPCON_MASK ((1 << PLL_MISC_CPCON_WIDTH) - 1)
+#define PLL_MISC_LFCON_SHIFT 4
+#define PLL_MISC_LFCON_WIDTH 4
+#define PLL_MISC_LFCON_MASK ((1 << PLL_MISC_LFCON_WIDTH) - 1)
+#define PLL_MISC_VCOCON_SHIFT 0
+#define PLL_MISC_VCOCON_WIDTH 4
+#define PLL_MISC_VCOCON_MASK ((1 << PLL_MISC_VCOCON_WIDTH) - 1)
+
+#define OUT_OF_TABLE_CPCON 8
+
+#define PMC_PLLP_WB0_OVERRIDE 0xf8
+#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12)
+#define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE BIT(11)
+
+#define PLL_POST_LOCK_DELAY 50
+
+#define PLLDU_LFCON_SET_DIVN 600
+
+#define PLLE_BASE_DIVCML_SHIFT 24
+#define PLLE_BASE_DIVCML_WIDTH 4
+#define PLLE_BASE_DIVP_SHIFT 16
+#define PLLE_BASE_DIVP_WIDTH 7
+#define PLLE_BASE_DIVN_SHIFT 8
+#define PLLE_BASE_DIVN_WIDTH 8
+#define PLLE_BASE_DIVM_SHIFT 0
+#define PLLE_BASE_DIVM_WIDTH 8
+
+#define PLLE_MISC_SETUP_BASE_SHIFT 16
+#define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT)
+#define PLLE_MISC_LOCK_ENABLE BIT(9)
+#define PLLE_MISC_READY BIT(15)
+#define PLLE_MISC_SETUP_EX_SHIFT 2
+#define PLLE_MISC_SETUP_EX_MASK (3 << PLLE_MISC_SETUP_EX_SHIFT)
+#define PLLE_MISC_SETUP_MASK (PLLE_MISC_SETUP_BASE_MASK | \
+ PLLE_MISC_SETUP_EX_MASK)
+#define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT)
+
+#define PLLE_SS_CTRL 0x68
+#define PLLE_SS_DISABLE (7 << 10)
+
+#define PMC_SATA_PWRGT 0x1ac
+#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5)
+#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4)
+
+#define pll_readl(offset, p) readl_relaxed(p->clk_base + offset)
+#define pll_readl_base(p) pll_readl(p->params->base_reg, p)
+#define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
+
+#define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)
+#define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)
+#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
+
+#define mask(w) ((1 << (w)) - 1)
+#define divm_mask(p) mask(p->divm_width)
+#define divn_mask(p) mask(p->divn_width)
+#define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \
+ mask(p->divp_width))
+
+#define divm_max(p) (divm_mask(p))
+#define divn_max(p) (divn_mask(p))
+#define divp_max(p) (1 << (divp_mask(p)))
+
+static void clk_pll_enable_lock(struct tegra_clk_pll *pll)
+{
+ u32 val;
+
+ if (!(pll->flags & TEGRA_PLL_USE_LOCK))
+ return;
+
+ val = pll_readl_misc(pll);
+ val |= BIT(pll->params->lock_enable_bit_idx);
+ pll_writel_misc(val, pll);
+}
+
+static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll,
+ void __iomem *lock_addr, u32 lock_bit_idx)
+{
+ int i;
+ u32 val;
+
+ if (!(pll->flags & TEGRA_PLL_USE_LOCK)) {
+ udelay(pll->params->lock_delay);
+ return 0;
+ }
+
+ for (i = 0; i < pll->params->lock_delay; i++) {
+ val = readl_relaxed(lock_addr);
+ if (val & BIT(lock_bit_idx)) {
+ udelay(PLL_POST_LOCK_DELAY);
+ return 0;
+ }
+ udelay(2); /* timeout = 2 * lock time */
+ }
+
+ pr_err("%s: Timed out waiting for pll %s lock\n", __func__,
+ __clk_get_name(pll->hw.clk));
+
+ return -1;
+}
+
+static int clk_pll_is_enabled(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val;
+
+ if (pll->flags & TEGRA_PLLM) {
+ val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
+ if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)
+ return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0;
+ }
+
+ val = pll_readl_base(pll);
+
+ return val & PLL_BASE_ENABLE ? 1 : 0;
+}
+
+static int _clk_pll_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val;
+
+ clk_pll_enable_lock(pll);
+
+ val = pll_readl_base(pll);
+ val &= ~PLL_BASE_BYPASS;
+ val |= PLL_BASE_ENABLE;
+ pll_writel_base(val, pll);
+
+ if (pll->flags & TEGRA_PLLM) {
+ val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
+ val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+ writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
+ }
+
+ clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg,
+ pll->params->lock_bit_idx);
+
+ return 0;
+}
+
+static void _clk_pll_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val;
+
+ val = pll_readl_base(pll);
+ val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+ pll_writel_base(val, pll);
+
+ if (pll->flags & TEGRA_PLLM) {
+ val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
+ val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+ writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
+ }
+}
+
+static int clk_pll_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+ int ret;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ ret = _clk_pll_enable(hw);
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return ret;
+}
+
+static void clk_pll_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ _clk_pll_disable(hw);
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int _get_table_rate(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long parent_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_freq_table *sel;
+
+ for (sel = pll->freq_table; sel->input_rate != 0; sel++)
+ if (sel->input_rate == parent_rate &&
+ sel->output_rate == rate)
+ break;
+
+ if (sel->input_rate == 0)
+ return -EINVAL;
+
+ BUG_ON(sel->p < 1);
+
+ cfg->input_rate = sel->input_rate;
+ cfg->output_rate = sel->output_rate;
+ cfg->m = sel->m;
+ cfg->n = sel->n;
+ cfg->p = sel->p;
+ cfg->cpcon = sel->cpcon;
+
+ return 0;
+}
+
+static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long parent_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long cfreq;
+ u32 p_div = 0;
+
+ switch (parent_rate) {
+ case 12000000:
+ case 26000000:
+ cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
+ break;
+ case 13000000:
+ cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
+ break;
+ case 16800000:
+ case 19200000:
+ cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
+ break;
+ case 9600000:
+ case 28800000:
+ /*
+ * PLL_P_OUT1 rate is not listed in PLLA table
+ */
+ cfreq = parent_rate/(parent_rate/1000000);
+ break;
+ default:
+ pr_err("%s Unexpected reference rate %lu\n",
+ __func__, parent_rate);
+ BUG();
+ }
+
+ /* Raise VCO to guarantee 0.5% accuracy */
+ for (cfg->output_rate = rate; cfg->output_rate < 200 * cfreq;
+ cfg->output_rate <<= 1)
+ p_div++;
+
+ cfg->p = 1 << p_div;
+ cfg->m = parent_rate / cfreq;
+ cfg->n = cfg->output_rate / cfreq;
+ cfg->cpcon = OUT_OF_TABLE_CPCON;
+
+ if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) ||
+ cfg->p > divp_max(pll) || cfg->output_rate > pll->params->vco_max) {
+ pr_err("%s: Failed to set %s rate %lu\n",
+ __func__, __clk_get_name(hw->clk), rate);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+ u32 divp, val, old_base;
+ int state;
+
+ divp = __ffs(cfg->p);
+
+ if (pll->flags & TEGRA_PLLU)
+ divp ^= 1;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ old_base = val = pll_readl_base(pll);
+ val &= ~((divm_mask(pll) << pll->divm_shift) |
+ (divn_mask(pll) << pll->divn_shift) |
+ (divp_mask(pll) << pll->divp_shift));
+ val |= ((cfg->m << pll->divm_shift) |
+ (cfg->n << pll->divn_shift) |
+ (divp << pll->divp_shift));
+ if (val == old_base) {
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+ return 0;
+ }
+
+ state = clk_pll_is_enabled(hw);
+
+ if (state) {
+ _clk_pll_disable(hw);
+ val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+ }
+ pll_writel_base(val, pll);
+
+ if (pll->flags & TEGRA_PLL_HAS_CPCON) {
+ val = pll_readl_misc(pll);
+ val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT);
+ val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT;
+ if (pll->flags & TEGRA_PLL_SET_LFCON) {
+ val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT);
+ if (cfg->n >= PLLDU_LFCON_SET_DIVN)
+ val |= 0x1 << PLL_MISC_LFCON_SHIFT;
+ } else if (pll->flags & TEGRA_PLL_SET_DCCON) {
+ val &= ~(0x1 << PLL_MISC_DCCON_SHIFT);
+ if (rate >= (pll->params->vco_max >> 1))
+ val |= 0x1 << PLL_MISC_DCCON_SHIFT;
+ }
+ pll_writel_misc(val, pll);
+ }
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ if (state)
+ clk_pll_enable(hw);
+
+ return 0;
+}
+
+static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_freq_table cfg;
+
+ if (pll->flags & TEGRA_PLL_FIXED) {
+ if (rate != pll->fixed_rate) {
+ pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
+ __func__, __clk_get_name(hw->clk),
+ pll->fixed_rate, rate);
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
+ _calc_rate(hw, &cfg, rate, parent_rate))
+ return -EINVAL;
+
+ return _program_pll(hw, &cfg, rate);
+}
+
+static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_freq_table cfg;
+ u64 output_rate = *prate;
+
+ if (pll->flags & TEGRA_PLL_FIXED)
+ return pll->fixed_rate;
+
+ /* PLLM is used for memory; we do not change rate */
+ if (pll->flags & TEGRA_PLLM)
+ return __clk_get_rate(hw->clk);
+
+ if (_get_table_rate(hw, &cfg, rate, *prate) &&
+ _calc_rate(hw, &cfg, rate, *prate))
+ return -EINVAL;
+
+ output_rate *= cfg.n;
+ do_div(output_rate, cfg.m * cfg.p);
+
+ return output_rate;
+}
+
+static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val = pll_readl_base(pll);
+ u32 divn = 0, divm = 0, divp = 0;
+ u64 rate = parent_rate;
+
+ if (val & PLL_BASE_BYPASS)
+ return parent_rate;
+
+ if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) {
+ struct tegra_clk_pll_freq_table sel;
+ if (_get_table_rate(hw, &sel, pll->fixed_rate, parent_rate)) {
+ pr_err("Clock %s has unknown fixed frequency\n",
+ __clk_get_name(hw->clk));
+ BUG();
+ }
+ return pll->fixed_rate;
+ }
+
+ divp = (val >> pll->divp_shift) & (divp_mask(pll));
+ if (pll->flags & TEGRA_PLLU)
+ divp ^= 1;
+
+ divn = (val >> pll->divn_shift) & (divn_mask(pll));
+ divm = (val >> pll->divm_shift) & (divm_mask(pll));
+ divm *= (1 << divp);
+
+ rate *= divn;
+ do_div(rate, divm);
+ return rate;
+}
+
+static int clk_plle_training(struct tegra_clk_pll *pll)
+{
+ u32 val;
+ unsigned long timeout;
+
+ if (!pll->pmc)
+ return -ENOSYS;
+
+ /*
+ * PLLE is already disabled, and setup cleared;
+ * create falling edge on PLLE IDDQ input.
+ */
+ val = readl(pll->pmc + PMC_SATA_PWRGT);
+ val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
+ writel(val, pll->pmc + PMC_SATA_PWRGT);
+
+ val = readl(pll->pmc + PMC_SATA_PWRGT);
+ val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
+ writel(val, pll->pmc + PMC_SATA_PWRGT);
+
+ val = readl(pll->pmc + PMC_SATA_PWRGT);
+ val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
+ writel(val, pll->pmc + PMC_SATA_PWRGT);
+
+ val = pll_readl_misc(pll);
+
+ timeout = jiffies + msecs_to_jiffies(100);
+ while (1) {
+ val = pll_readl_misc(pll);
+ if (val & PLLE_MISC_READY)
+ break;
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: timeout waiting for PLLE\n", __func__);
+ return -EBUSY;
+ }
+ udelay(300);
+ }
+
+ return 0;
+}
+
+static int clk_plle_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+ struct tegra_clk_pll_freq_table sel;
+ u32 val;
+ int err;
+
+ if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate))
+ return -EINVAL;
+
+ clk_pll_disable(hw);
+
+ val = pll_readl_misc(pll);
+ val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
+ pll_writel_misc(val, pll);
+
+ val = pll_readl_misc(pll);
+ if (!(val & PLLE_MISC_READY)) {
+ err = clk_plle_training(pll);
+ if (err)
+ return err;
+ }
+
+ if (pll->flags & TEGRA_PLLE_CONFIGURE) {
+ /* configure dividers */
+ val = pll_readl_base(pll);
+ val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));
+ val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
+ val |= sel.m << pll->divm_shift;
+ val |= sel.n << pll->divn_shift;
+ val |= sel.p << pll->divp_shift;
+ val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
+ pll_writel_base(val, pll);
+ }
+
+ val = pll_readl_misc(pll);
+ val |= PLLE_MISC_SETUP_VALUE;
+ val |= PLLE_MISC_LOCK_ENABLE;
+ pll_writel_misc(val, pll);
+
+ val = readl(pll->clk_base + PLLE_SS_CTRL);
+ val |= PLLE_SS_DISABLE;
+ writel(val, pll->clk_base + PLLE_SS_CTRL);
+
+ val |= pll_readl_base(pll);
+ val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+ pll_writel_base(val, pll);
+
+ clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg,
+ pll->params->lock_bit_idx);
+ return 0;
+}
+
+static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val = pll_readl_base(pll);
+ u32 divn = 0, divm = 0, divp = 0;
+ u64 rate = parent_rate;
+
+ divp = (val >> pll->divp_shift) & (divp_mask(pll));
+ divn = (val >> pll->divn_shift) & (divn_mask(pll));
+ divm = (val >> pll->divm_shift) & (divm_mask(pll));
+ divm *= divp;
+
+ rate *= divn;
+ do_div(rate, divm);
+ return rate;
+}
+
+const struct clk_ops tegra_clk_pll_ops = {
+ .is_enabled = clk_pll_is_enabled,
+ .enable = clk_pll_enable,
+ .disable = clk_pll_disable,
+ .recalc_rate = clk_pll_recalc_rate,
+ .round_rate = clk_pll_round_rate,
+ .set_rate = clk_pll_set_rate,
+};
+
+const struct clk_ops tegra_clk_plle_ops = {
+ .recalc_rate = clk_plle_recalc_rate,
+ .is_enabled = clk_pll_is_enabled,
+ .disable = clk_pll_disable,
+ .enable = clk_plle_enable,
+};
+
+static struct clk *_tegra_clk_register_pll(const char *name,
+ const char *parent_name, void __iomem *clk_base,
+ void __iomem *pmc, unsigned long flags,
+ unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params, u8 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock,
+ const struct clk_ops *ops)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = ops;
+ init.flags = flags;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ pll->clk_base = clk_base;
+ pll->pmc = pmc;
+
+ pll->freq_table = freq_table;
+ pll->params = pll_params;
+ pll->fixed_rate = fixed_rate;
+ pll->flags = pll_flags;
+ pll->lock = lock;
+
+ pll->divp_shift = PLL_BASE_DIVP_SHIFT;
+ pll->divp_width = PLL_BASE_DIVP_WIDTH;
+ pll->divn_shift = PLL_BASE_DIVN_SHIFT;
+ pll->divn_width = PLL_BASE_DIVN_WIDTH;
+ pll->divm_shift = PLL_BASE_DIVM_SHIFT;
+ pll->divm_width = PLL_BASE_DIVM_WIDTH;
+
+ /* Data in .init is copied by clk_register(), so stack variable OK */
+ pll->hw.init = &init;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params, u8 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock)
+{
+ return _tegra_clk_register_pll(name, parent_name, clk_base, pmc,
+ flags, fixed_rate, pll_params, pll_flags, freq_table,
+ lock, &tegra_clk_pll_ops);
+}
+
+struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params, u8 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock)
+{
+ return _tegra_clk_register_pll(name, parent_name, clk_base, pmc,
+ flags, fixed_rate, pll_params, pll_flags, freq_table,
+ lock, &tegra_clk_plle_ops);
+}
diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
new file mode 100644
index 000000000000..2fd924d38606
--- /dev/null
+++ b/drivers/clk/tegra/clk-super.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+
+#include "clk.h"
+
+#define SUPER_STATE_IDLE 0
+#define SUPER_STATE_RUN 1
+#define SUPER_STATE_IRQ 2
+#define SUPER_STATE_FIQ 3
+
+#define SUPER_STATE_SHIFT 28
+#define SUPER_STATE_MASK ((BIT(SUPER_STATE_IDLE) | BIT(SUPER_STATE_RUN) | \
+ BIT(SUPER_STATE_IRQ) | BIT(SUPER_STATE_FIQ)) \
+ << SUPER_STATE_SHIFT)
+
+#define SUPER_LP_DIV2_BYPASS (1 << 16)
+
+#define super_state(s) (BIT(s) << SUPER_STATE_SHIFT)
+#define super_state_to_src_shift(m, s) ((m->width * s))
+#define super_state_to_src_mask(m) (((1 << m->width) - 1))
+
+static u8 clk_super_get_parent(struct clk_hw *hw)
+{
+ struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
+ u32 val, state;
+ u8 source, shift;
+
+ val = readl_relaxed(mux->reg);
+
+ state = val & SUPER_STATE_MASK;
+
+ BUG_ON((state != super_state(SUPER_STATE_RUN)) &&
+ (state != super_state(SUPER_STATE_IDLE)));
+ shift = (state == super_state(SUPER_STATE_IDLE)) ?
+ super_state_to_src_shift(mux, SUPER_STATE_IDLE) :
+ super_state_to_src_shift(mux, SUPER_STATE_RUN);
+
+ source = (val >> shift) & super_state_to_src_mask(mux);
+
+ /*
+ * If LP_DIV2_BYPASS is not set and PLLX is current parent then
+ * PLLX/2 is the input source to CCLKLP.
+ */
+ if ((mux->flags & TEGRA_DIVIDER_2) && !(val & SUPER_LP_DIV2_BYPASS) &&
+ (source == mux->pllx_index))
+ source = mux->div2_index;
+
+ return source;
+}
+
+static int clk_super_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
+ u32 val, state;
+ int err = 0;
+ u8 parent_index, shift;
+ unsigned long flags = 0;
+
+ if (mux->lock)
+ spin_lock_irqsave(mux->lock, flags);
+
+ val = readl_relaxed(mux->reg);
+ state = val & SUPER_STATE_MASK;
+ BUG_ON((state != super_state(SUPER_STATE_RUN)) &&
+ (state != super_state(SUPER_STATE_IDLE)));
+ shift = (state == super_state(SUPER_STATE_IDLE)) ?
+ super_state_to_src_shift(mux, SUPER_STATE_IDLE) :
+ super_state_to_src_shift(mux, SUPER_STATE_RUN);
+
+ /*
+ * For LP mode super-clock switch between PLLX direct
+ * and divided-by-2 outputs is allowed only when other
+ * than PLLX clock source is current parent.
+ */
+ if ((mux->flags & TEGRA_DIVIDER_2) && ((index == mux->div2_index) ||
+ (index == mux->pllx_index))) {
+ parent_index = clk_super_get_parent(hw);
+ if ((parent_index == mux->div2_index) ||
+ (parent_index == mux->pllx_index)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ val ^= SUPER_LP_DIV2_BYPASS;
+ writel_relaxed(val, mux->reg);
+ udelay(2);
+
+ if (index == mux->div2_index)
+ index = mux->pllx_index;
+ }
+ val &= ~((super_state_to_src_mask(mux)) << shift);
+ val |= (index & (super_state_to_src_mask(mux))) << shift;
+
+ writel_relaxed(val, mux->reg);
+ udelay(2);
+
+out:
+ if (mux->lock)
+ spin_unlock_irqrestore(mux->lock, flags);
+
+ return err;
+}
+
+const struct clk_ops tegra_clk_super_ops = {
+ .get_parent = clk_super_get_parent,
+ .set_parent = clk_super_set_parent,
+};
+
+struct clk *tegra_clk_register_super_mux(const char *name,
+ const char **parent_names, u8 num_parents,
+ unsigned long flags, void __iomem *reg, u8 clk_super_flags,
+ u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock)
+{
+ struct tegra_clk_super_mux *super;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ super = kzalloc(sizeof(*super), GFP_KERNEL);
+ if (!super) {
+ pr_err("%s: could not allocate super clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.ops = &tegra_clk_super_ops;
+ init.flags = flags;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+
+ super->reg = reg;
+ super->pllx_index = pllx_index;
+ super->div2_index = div2_index;
+ super->lock = lock;
+ super->width = width;
+ super->flags = clk_super_flags;
+
+ /* Data in .init is copied by clk_register(), so stack variable OK */
+ super->hw.init = &init;
+
+ clk = clk_register(NULL, &super->hw);
+ if (IS_ERR(clk))
+ kfree(super);
+
+ return clk;
+}
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
new file mode 100644
index 000000000000..143ce1f899ad
--- /dev/null
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -0,0 +1,1355 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/tegra.h>
+#include <linux/delay.h>
+
+#include "clk.h"
+
+#define RST_DEVICES_L 0x004
+#define RST_DEVICES_H 0x008
+#define RST_DEVICES_U 0x00c
+#define RST_DEVICES_SET_L 0x300
+#define RST_DEVICES_CLR_L 0x304
+#define RST_DEVICES_SET_H 0x308
+#define RST_DEVICES_CLR_H 0x30c
+#define RST_DEVICES_SET_U 0x310
+#define RST_DEVICES_CLR_U 0x314
+#define RST_DEVICES_NUM 3
+
+#define CLK_OUT_ENB_L 0x010
+#define CLK_OUT_ENB_H 0x014
+#define CLK_OUT_ENB_U 0x018
+#define CLK_OUT_ENB_SET_L 0x320
+#define CLK_OUT_ENB_CLR_L 0x324
+#define CLK_OUT_ENB_SET_H 0x328
+#define CLK_OUT_ENB_CLR_H 0x32c
+#define CLK_OUT_ENB_SET_U 0x330
+#define CLK_OUT_ENB_CLR_U 0x334
+#define CLK_OUT_ENB_NUM 3
+
+#define OSC_CTRL 0x50
+#define OSC_CTRL_OSC_FREQ_MASK (3<<30)
+#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
+#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30)
+#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30)
+#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30)
+#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
+
+#define OSC_CTRL_PLL_REF_DIV_MASK (3<<28)
+#define OSC_CTRL_PLL_REF_DIV_1 (0<<28)
+#define OSC_CTRL_PLL_REF_DIV_2 (1<<28)
+#define OSC_CTRL_PLL_REF_DIV_4 (2<<28)
+
+#define OSC_FREQ_DET 0x58
+#define OSC_FREQ_DET_TRIG (1<<31)
+
+#define OSC_FREQ_DET_STATUS 0x5c
+#define OSC_FREQ_DET_BUSY (1<<31)
+#define OSC_FREQ_DET_CNT_MASK 0xFFFF
+
+#define PLLS_BASE 0xf0
+#define PLLS_MISC 0xf4
+#define PLLC_BASE 0x80
+#define PLLC_MISC 0x8c
+#define PLLM_BASE 0x90
+#define PLLM_MISC 0x9c
+#define PLLP_BASE 0xa0
+#define PLLP_MISC 0xac
+#define PLLA_BASE 0xb0
+#define PLLA_MISC 0xbc
+#define PLLU_BASE 0xc0
+#define PLLU_MISC 0xcc
+#define PLLD_BASE 0xd0
+#define PLLD_MISC 0xdc
+#define PLLX_BASE 0xe0
+#define PLLX_MISC 0xe4
+#define PLLE_BASE 0xe8
+#define PLLE_MISC 0xec
+
+#define PLL_BASE_LOCK 27
+#define PLLE_MISC_LOCK 11
+
+#define PLL_MISC_LOCK_ENABLE 18
+#define PLLDU_MISC_LOCK_ENABLE 22
+#define PLLE_MISC_LOCK_ENABLE 9
+
+#define PLLC_OUT 0x84
+#define PLLM_OUT 0x94
+#define PLLP_OUTA 0xa4
+#define PLLP_OUTB 0xa8
+#define PLLA_OUT 0xb4
+
+#define CCLK_BURST_POLICY 0x20
+#define SUPER_CCLK_DIVIDER 0x24
+#define SCLK_BURST_POLICY 0x28
+#define SUPER_SCLK_DIVIDER 0x2c
+#define CLK_SYSTEM_RATE 0x30
+
+#define CCLK_BURST_POLICY_SHIFT 28
+#define CCLK_RUN_POLICY_SHIFT 4
+#define CCLK_IDLE_POLICY_SHIFT 0
+#define CCLK_IDLE_POLICY 1
+#define CCLK_RUN_POLICY 2
+#define CCLK_BURST_POLICY_PLLX 8
+
+#define CLK_SOURCE_I2S1 0x100
+#define CLK_SOURCE_I2S2 0x104
+#define CLK_SOURCE_SPDIF_OUT 0x108
+#define CLK_SOURCE_SPDIF_IN 0x10c
+#define CLK_SOURCE_PWM 0x110
+#define CLK_SOURCE_SPI 0x114
+#define CLK_SOURCE_SBC1 0x134
+#define CLK_SOURCE_SBC2 0x118
+#define CLK_SOURCE_SBC3 0x11c
+#define CLK_SOURCE_SBC4 0x1b4
+#define CLK_SOURCE_XIO 0x120
+#define CLK_SOURCE_TWC 0x12c
+#define CLK_SOURCE_IDE 0x144
+#define CLK_SOURCE_NDFLASH 0x160
+#define CLK_SOURCE_VFIR 0x168
+#define CLK_SOURCE_SDMMC1 0x150
+#define CLK_SOURCE_SDMMC2 0x154
+#define CLK_SOURCE_SDMMC3 0x1bc
+#define CLK_SOURCE_SDMMC4 0x164
+#define CLK_SOURCE_CVE 0x140
+#define CLK_SOURCE_TVO 0x188
+#define CLK_SOURCE_TVDAC 0x194
+#define CLK_SOURCE_HDMI 0x18c
+#define CLK_SOURCE_DISP1 0x138
+#define CLK_SOURCE_DISP2 0x13c
+#define CLK_SOURCE_CSITE 0x1d4
+#define CLK_SOURCE_LA 0x1f8
+#define CLK_SOURCE_OWR 0x1cc
+#define CLK_SOURCE_NOR 0x1d0
+#define CLK_SOURCE_MIPI 0x174
+#define CLK_SOURCE_I2C1 0x124
+#define CLK_SOURCE_I2C2 0x198
+#define CLK_SOURCE_I2C3 0x1b8
+#define CLK_SOURCE_DVC 0x128
+#define CLK_SOURCE_UARTA 0x178
+#define CLK_SOURCE_UARTB 0x17c
+#define CLK_SOURCE_UARTC 0x1a0
+#define CLK_SOURCE_UARTD 0x1c0
+#define CLK_SOURCE_UARTE 0x1c4
+#define CLK_SOURCE_3D 0x158
+#define CLK_SOURCE_2D 0x15c
+#define CLK_SOURCE_MPE 0x170
+#define CLK_SOURCE_EPP 0x16c
+#define CLK_SOURCE_HOST1X 0x180
+#define CLK_SOURCE_VDE 0x1c8
+#define CLK_SOURCE_VI 0x148
+#define CLK_SOURCE_VI_SENSOR 0x1a8
+#define CLK_SOURCE_EMC 0x19c
+
+#define AUDIO_SYNC_CLK 0x38
+
+#define PMC_CTRL 0x0
+#define PMC_CTRL_BLINK_ENB 7
+#define PMC_DPD_PADS_ORIDE 0x1c
+#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20
+#define PMC_BLINK_TIMER 0x40
+
+/* Tegra CPU clock and reset control regs */
+#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344
+
+#define CPU_CLOCK(cpu) (0x1 << (8 + cpu))
+#define CPU_RESET(cpu) (0x1111ul << (cpu))
+
+#ifdef CONFIG_PM_SLEEP
+static struct cpu_clk_suspend_context {
+ u32 pllx_misc;
+ u32 pllx_base;
+
+ u32 cpu_burst;
+ u32 clk_csite_src;
+ u32 cclk_divider;
+} tegra20_cpu_clk_sctx;
+#endif
+
+static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32];
+
+static void __iomem *clk_base;
+static void __iomem *pmc_base;
+
+static DEFINE_SPINLOCK(pll_div_lock);
+static DEFINE_SPINLOCK(sysrate_lock);
+
+#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \
+ 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, \
+ _regs, _clk_num, periph_clk_enb_refcnt, \
+ _gate_flags, _clk_id)
+
+#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \
+ 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \
+ _clk_num, periph_clk_enb_refcnt, _gate_flags, \
+ _clk_id)
+
+#define TEGRA_INIT_DATA_DIV16(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \
+ 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, _regs, \
+ _clk_num, periph_clk_enb_refcnt, _gate_flags, \
+ _clk_id)
+
+#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \
+ _mux_shift, _mux_width, _clk_num, _regs, \
+ _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \
+ _mux_shift, _mux_width, 0, 0, 0, 0, 0, _regs, \
+ _clk_num, periph_clk_enb_refcnt, _gate_flags, \
+ _clk_id)
+
+/* IDs assigned here must be in sync with DT bindings definition
+ * for Tegra20 clocks .
+ */
+enum tegra20_clk {
+ cpu, ac97 = 3, rtc, timer, uarta, gpio = 8, sdmmc2, i2s1 = 11, i2c1,
+ ndflash, sdmmc1, sdmmc4, twc, pwm, i2s2, epp, gr2d = 21, usbd, isp,
+ gr3d, ide, disp2, disp1, host1x, vcp, cache2 = 31, mem, ahbdma, apbdma,
+ kbc = 36, stat_mon, pmc, fuse, kfuse, sbc1, nor, spi, sbc2, xio, sbc3,
+ dvc, dsi, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2,
+ usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3,
+ pex, owr, afi, csite, pcie_xclk, avpucq = 75, la, irama = 84, iramb,
+ iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev1, cdev2,
+ uartb = 96, vfir, spdif_in, spdif_out, vi, vi_sensor, tvo, cve,
+ osc, clk_32k, clk_m, sclk, cclk, hclk, pclk, blink, pll_a, pll_a_out0,
+ pll_c, pll_c_out1, pll_d, pll_d_out0, pll_e, pll_m, pll_m_out1,
+ pll_p, pll_p_out1, pll_p_out2, pll_p_out3, pll_p_out4, pll_s, pll_u,
+ pll_x, cop, audio, pll_ref, twd, clk_max,
+};
+
+static struct clk *clks[clk_max];
+static struct clk_onecell_data clk_data;
+
+static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
+ { 12000000, 600000000, 600, 12, 1, 8 },
+ { 13000000, 600000000, 600, 13, 1, 8 },
+ { 19200000, 600000000, 500, 16, 1, 6 },
+ { 26000000, 600000000, 600, 26, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
+ { 12000000, 666000000, 666, 12, 1, 8},
+ { 13000000, 666000000, 666, 13, 1, 8},
+ { 19200000, 666000000, 555, 16, 1, 8},
+ { 26000000, 666000000, 666, 26, 1, 8},
+ { 12000000, 600000000, 600, 12, 1, 8},
+ { 13000000, 600000000, 600, 13, 1, 8},
+ { 19200000, 600000000, 375, 12, 1, 6},
+ { 26000000, 600000000, 600, 26, 1, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
+ { 12000000, 216000000, 432, 12, 2, 8},
+ { 13000000, 216000000, 432, 13, 2, 8},
+ { 19200000, 216000000, 90, 4, 2, 1},
+ { 26000000, 216000000, 432, 26, 2, 8},
+ { 12000000, 432000000, 432, 12, 1, 8},
+ { 13000000, 432000000, 432, 13, 1, 8},
+ { 19200000, 432000000, 90, 4, 1, 1},
+ { 26000000, 432000000, 432, 26, 1, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
+ { 28800000, 56448000, 49, 25, 1, 1},
+ { 28800000, 73728000, 64, 25, 1, 1},
+ { 28800000, 24000000, 5, 6, 1, 1},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
+ { 12000000, 216000000, 216, 12, 1, 4},
+ { 13000000, 216000000, 216, 13, 1, 4},
+ { 19200000, 216000000, 135, 12, 1, 3},
+ { 26000000, 216000000, 216, 26, 1, 4},
+
+ { 12000000, 594000000, 594, 12, 1, 8},
+ { 13000000, 594000000, 594, 13, 1, 8},
+ { 19200000, 594000000, 495, 16, 1, 8},
+ { 26000000, 594000000, 594, 26, 1, 8},
+
+ { 12000000, 1000000000, 1000, 12, 1, 12},
+ { 13000000, 1000000000, 1000, 13, 1, 12},
+ { 19200000, 1000000000, 625, 12, 1, 8},
+ { 26000000, 1000000000, 1000, 26, 1, 12},
+
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
+ { 12000000, 480000000, 960, 12, 2, 0},
+ { 13000000, 480000000, 960, 13, 2, 0},
+ { 19200000, 480000000, 200, 4, 2, 0},
+ { 26000000, 480000000, 960, 26, 2, 0},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
+ /* 1 GHz */
+ { 12000000, 1000000000, 1000, 12, 1, 12},
+ { 13000000, 1000000000, 1000, 13, 1, 12},
+ { 19200000, 1000000000, 625, 12, 1, 8},
+ { 26000000, 1000000000, 1000, 26, 1, 12},
+
+ /* 912 MHz */
+ { 12000000, 912000000, 912, 12, 1, 12},
+ { 13000000, 912000000, 912, 13, 1, 12},
+ { 19200000, 912000000, 760, 16, 1, 8},
+ { 26000000, 912000000, 912, 26, 1, 12},
+
+ /* 816 MHz */
+ { 12000000, 816000000, 816, 12, 1, 12},
+ { 13000000, 816000000, 816, 13, 1, 12},
+ { 19200000, 816000000, 680, 16, 1, 8},
+ { 26000000, 816000000, 816, 26, 1, 12},
+
+ /* 760 MHz */
+ { 12000000, 760000000, 760, 12, 1, 12},
+ { 13000000, 760000000, 760, 13, 1, 12},
+ { 19200000, 760000000, 950, 24, 1, 8},
+ { 26000000, 760000000, 760, 26, 1, 12},
+
+ /* 750 MHz */
+ { 12000000, 750000000, 750, 12, 1, 12},
+ { 13000000, 750000000, 750, 13, 1, 12},
+ { 19200000, 750000000, 625, 16, 1, 8},
+ { 26000000, 750000000, 750, 26, 1, 12},
+
+ /* 608 MHz */
+ { 12000000, 608000000, 608, 12, 1, 12},
+ { 13000000, 608000000, 608, 13, 1, 12},
+ { 19200000, 608000000, 380, 12, 1, 8},
+ { 26000000, 608000000, 608, 26, 1, 12},
+
+ /* 456 MHz */
+ { 12000000, 456000000, 456, 12, 1, 12},
+ { 13000000, 456000000, 456, 13, 1, 12},
+ { 19200000, 456000000, 380, 16, 1, 8},
+ { 26000000, 456000000, 456, 26, 1, 12},
+
+ /* 312 MHz */
+ { 12000000, 312000000, 312, 12, 1, 12},
+ { 13000000, 312000000, 312, 13, 1, 12},
+ { 19200000, 312000000, 260, 16, 1, 8},
+ { 26000000, 312000000, 312, 26, 1, 12},
+
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
+ { 12000000, 100000000, 200, 24, 1, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+/* PLL parameters */
+static struct tegra_clk_pll_params pll_c_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1400000000,
+ .base_reg = PLLC_BASE,
+ .misc_reg = PLLC_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_m_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLM_BASE,
+ .misc_reg = PLLM_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_p_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1400000000,
+ .base_reg = PLLP_BASE,
+ .misc_reg = PLLP_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_a_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1400000000,
+ .base_reg = PLLA_BASE,
+ .misc_reg = PLLA_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_d_params = {
+ .input_min = 2000000,
+ .input_max = 40000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 40000000,
+ .vco_max = 1000000000,
+ .base_reg = PLLD_BASE,
+ .misc_reg = PLLD_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+};
+
+static struct tegra_clk_pll_params pll_u_params = {
+ .input_min = 2000000,
+ .input_max = 40000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 48000000,
+ .vco_max = 960000000,
+ .base_reg = PLLU_BASE,
+ .misc_reg = PLLU_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+};
+
+static struct tegra_clk_pll_params pll_x_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLX_BASE,
+ .misc_reg = PLLX_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_e_params = {
+ .input_min = 12000000,
+ .input_max = 12000000,
+ .cf_min = 0,
+ .cf_max = 0,
+ .vco_min = 0,
+ .vco_max = 0,
+ .base_reg = PLLE_BASE,
+ .misc_reg = PLLE_MISC,
+ .lock_bit_idx = PLLE_MISC_LOCK,
+ .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
+ .lock_delay = 0,
+};
+
+/* Peripheral clock registers */
+static struct tegra_clk_periph_regs periph_l_regs = {
+ .enb_reg = CLK_OUT_ENB_L,
+ .enb_set_reg = CLK_OUT_ENB_SET_L,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_L,
+ .rst_reg = RST_DEVICES_L,
+ .rst_set_reg = RST_DEVICES_SET_L,
+ .rst_clr_reg = RST_DEVICES_CLR_L,
+};
+
+static struct tegra_clk_periph_regs periph_h_regs = {
+ .enb_reg = CLK_OUT_ENB_H,
+ .enb_set_reg = CLK_OUT_ENB_SET_H,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_H,
+ .rst_reg = RST_DEVICES_H,
+ .rst_set_reg = RST_DEVICES_SET_H,
+ .rst_clr_reg = RST_DEVICES_CLR_H,
+};
+
+static struct tegra_clk_periph_regs periph_u_regs = {
+ .enb_reg = CLK_OUT_ENB_U,
+ .enb_set_reg = CLK_OUT_ENB_SET_U,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_U,
+ .rst_reg = RST_DEVICES_U,
+ .rst_set_reg = RST_DEVICES_SET_U,
+ .rst_clr_reg = RST_DEVICES_CLR_U,
+};
+
+static unsigned long tegra20_clk_measure_input_freq(void)
+{
+ u32 osc_ctrl = readl_relaxed(clk_base + OSC_CTRL);
+ u32 auto_clk_control = osc_ctrl & OSC_CTRL_OSC_FREQ_MASK;
+ u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK;
+ unsigned long input_freq;
+
+ switch (auto_clk_control) {
+ case OSC_CTRL_OSC_FREQ_12MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ input_freq = 12000000;
+ break;
+ case OSC_CTRL_OSC_FREQ_13MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ input_freq = 13000000;
+ break;
+ case OSC_CTRL_OSC_FREQ_19_2MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ input_freq = 19200000;
+ break;
+ case OSC_CTRL_OSC_FREQ_26MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ input_freq = 26000000;
+ break;
+ default:
+ pr_err("Unexpected clock autodetect value %d",
+ auto_clk_control);
+ BUG();
+ return 0;
+ }
+
+ return input_freq;
+}
+
+static unsigned int tegra20_get_pll_ref_div(void)
+{
+ u32 pll_ref_div = readl_relaxed(clk_base + OSC_CTRL) &
+ OSC_CTRL_PLL_REF_DIV_MASK;
+
+ switch (pll_ref_div) {
+ case OSC_CTRL_PLL_REF_DIV_1:
+ return 1;
+ case OSC_CTRL_PLL_REF_DIV_2:
+ return 2;
+ case OSC_CTRL_PLL_REF_DIV_4:
+ return 4;
+ default:
+ pr_err("Invalied pll ref divider %d\n", pll_ref_div);
+ BUG();
+ }
+ return 0;
+}
+
+static void tegra20_pll_init(void)
+{
+ struct clk *clk;
+
+ /* PLLC */
+ clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, NULL, 0,
+ 0, &pll_c_params, TEGRA_PLL_HAS_CPCON,
+ pll_c_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_c", NULL);
+ clks[pll_c] = clk;
+
+ /* PLLC_OUT1 */
+ clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c",
+ clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div",
+ clk_base + PLLC_OUT, 1, 0, CLK_SET_RATE_PARENT,
+ 0, NULL);
+ clk_register_clkdev(clk, "pll_c_out1", NULL);
+ clks[pll_c_out1] = clk;
+
+ /* PLLP */
+ clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, NULL, 0,
+ 216000000, &pll_p_params, TEGRA_PLL_FIXED |
+ TEGRA_PLL_HAS_CPCON, pll_p_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_p", NULL);
+ clks[pll_p] = clk;
+
+ /* PLLP_OUT1 */
+ clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p",
+ clk_base + PLLP_OUTA, 0,
+ TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div",
+ clk_base + PLLP_OUTA, 1, 0,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out1", NULL);
+ clks[pll_p_out1] = clk;
+
+ /* PLLP_OUT2 */
+ clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p",
+ clk_base + PLLP_OUTA, 0,
+ TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP,
+ 24, 8, 1, &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div",
+ clk_base + PLLP_OUTA, 17, 16,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out2", NULL);
+ clks[pll_p_out2] = clk;
+
+ /* PLLP_OUT3 */
+ clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p",
+ clk_base + PLLP_OUTB, 0,
+ TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div",
+ clk_base + PLLP_OUTB, 1, 0,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out3", NULL);
+ clks[pll_p_out3] = clk;
+
+ /* PLLP_OUT4 */
+ clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p",
+ clk_base + PLLP_OUTB, 0,
+ TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP,
+ 24, 8, 1, &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div",
+ clk_base + PLLP_OUTB, 17, 16,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out4", NULL);
+ clks[pll_p_out4] = clk;
+
+ /* PLLM */
+ clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, NULL,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0,
+ &pll_m_params, TEGRA_PLL_HAS_CPCON,
+ pll_m_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_m", NULL);
+ clks[pll_m] = clk;
+
+ /* PLLM_OUT1 */
+ clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m",
+ clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div",
+ clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED |
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_m_out1", NULL);
+ clks[pll_m_out1] = clk;
+
+ /* PLLX */
+ clk = tegra_clk_register_pll("pll_x", "pll_ref", clk_base, NULL, 0,
+ 0, &pll_x_params, TEGRA_PLL_HAS_CPCON,
+ pll_x_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_x", NULL);
+ clks[pll_x] = clk;
+
+ /* PLLU */
+ clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, NULL, 0,
+ 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON,
+ pll_u_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_u", NULL);
+ clks[pll_u] = clk;
+
+ /* PLLD */
+ clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, NULL, 0,
+ 0, &pll_d_params, TEGRA_PLL_HAS_CPCON,
+ pll_d_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_d", NULL);
+ clks[pll_d] = clk;
+
+ /* PLLD_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll_d_out0", NULL);
+ clks[pll_d_out0] = clk;
+
+ /* PLLA */
+ clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, NULL, 0,
+ 0, &pll_a_params, TEGRA_PLL_HAS_CPCON,
+ pll_a_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_a", NULL);
+ clks[pll_a] = clk;
+
+ /* PLLA_OUT0 */
+ clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a",
+ clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div",
+ clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED |
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_a_out0", NULL);
+ clks[pll_a_out0] = clk;
+
+ /* PLLE */
+ clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, NULL,
+ 0, 100000000, &pll_e_params,
+ 0, pll_e_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_e", NULL);
+ clks[pll_e] = clk;
+}
+
+static const char *cclk_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
+ "pll_p_cclk", "pll_p_out4_cclk",
+ "pll_p_out3_cclk", "clk_d", "pll_x" };
+static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
+ "pll_p_out3", "pll_p_out2", "clk_d",
+ "clk_32k", "pll_m_out1" };
+
+static void tegra20_super_clk_init(void)
+{
+ struct clk *clk;
+
+ /*
+ * DIV_U71 dividers for CCLK, these dividers are used only
+ * if parent clock is fixed rate.
+ */
+
+ /*
+ * Clock input to cclk divided from pll_p using
+ * U71 divider of cclk.
+ */
+ clk = tegra_clk_register_divider("pll_p_cclk", "pll_p",
+ clk_base + SUPER_CCLK_DIVIDER, 0,
+ TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
+ clk_register_clkdev(clk, "pll_p_cclk", NULL);
+
+ /*
+ * Clock input to cclk divided from pll_p_out3 using
+ * U71 divider of cclk.
+ */
+ clk = tegra_clk_register_divider("pll_p_out3_cclk", "pll_p_out3",
+ clk_base + SUPER_CCLK_DIVIDER, 0,
+ TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
+ clk_register_clkdev(clk, "pll_p_out3_cclk", NULL);
+
+ /*
+ * Clock input to cclk divided from pll_p_out4 using
+ * U71 divider of cclk.
+ */
+ clk = tegra_clk_register_divider("pll_p_out4_cclk", "pll_p_out4",
+ clk_base + SUPER_CCLK_DIVIDER, 0,
+ TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
+ clk_register_clkdev(clk, "pll_p_out4_cclk", NULL);
+
+ /* CCLK */
+ clk = tegra_clk_register_super_mux("cclk", cclk_parents,
+ ARRAY_SIZE(cclk_parents), CLK_SET_RATE_PARENT,
+ clk_base + CCLK_BURST_POLICY, 0, 4, 0, 0, NULL);
+ clk_register_clkdev(clk, "cclk", NULL);
+ clks[cclk] = clk;
+
+ /* SCLK */
+ clk = tegra_clk_register_super_mux("sclk", sclk_parents,
+ ARRAY_SIZE(sclk_parents), CLK_SET_RATE_PARENT,
+ clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL);
+ clk_register_clkdev(clk, "sclk", NULL);
+ clks[sclk] = clk;
+
+ /* HCLK */
+ clk = clk_register_divider(NULL, "hclk_div", "sclk", 0,
+ clk_base + CLK_SYSTEM_RATE, 4, 2, 0,
+ &sysrate_lock);
+ clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT,
+ clk_base + CLK_SYSTEM_RATE, 7,
+ CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
+ clk_register_clkdev(clk, "hclk", NULL);
+ clks[hclk] = clk;
+
+ /* PCLK */
+ clk = clk_register_divider(NULL, "pclk_div", "hclk", 0,
+ clk_base + CLK_SYSTEM_RATE, 0, 2, 0,
+ &sysrate_lock);
+ clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT,
+ clk_base + CLK_SYSTEM_RATE, 3,
+ CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
+ clk_register_clkdev(clk, "pclk", NULL);
+ clks[pclk] = clk;
+
+ /* twd */
+ clk = clk_register_fixed_factor(NULL, "twd", "cclk", 0, 1, 4);
+ clk_register_clkdev(clk, "twd", NULL);
+ clks[twd] = clk;
+}
+
+static const char *audio_parents[] = {"spdif_in", "i2s1", "i2s2", "unused",
+ "pll_a_out0", "unused", "unused",
+ "unused"};
+
+static void __init tegra20_audio_clk_init(void)
+{
+ struct clk *clk;
+
+ /* audio */
+ clk = clk_register_mux(NULL, "audio_mux", audio_parents,
+ ARRAY_SIZE(audio_parents), 0,
+ clk_base + AUDIO_SYNC_CLK, 0, 3, 0, NULL);
+ clk = clk_register_gate(NULL, "audio", "audio_mux", 0,
+ clk_base + AUDIO_SYNC_CLK, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio", NULL);
+ clks[audio] = clk;
+
+ /* audio_2x */
+ clk = clk_register_fixed_factor(NULL, "audio_doubler", "audio",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_periph_gate("audio_2x", "audio_doubler",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 89, &periph_u_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio_2x", NULL);
+ clks[audio_2x] = clk;
+
+}
+
+static const char *i2s1_parents[] = {"pll_a_out0", "audio_2x", "pll_p",
+ "clk_m"};
+static const char *i2s2_parents[] = {"pll_a_out0", "audio_2x", "pll_p",
+ "clk_m"};
+static const char *spdif_out_parents[] = {"pll_a_out0", "audio_2x", "pll_p",
+ "clk_m"};
+static const char *spdif_in_parents[] = {"pll_p", "pll_c", "pll_m"};
+static const char *pwm_parents[] = {"pll_p", "pll_c", "audio", "clk_m",
+ "clk_32k"};
+static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"};
+static const char *mux_pllmcpa[] = {"pll_m", "pll_c", "pll_c", "pll_a"};
+static const char *mux_pllpdc_clkm[] = {"pll_p", "pll_d_out0", "pll_c",
+ "clk_m"};
+static const char *mux_pllmcp_clkm[] = {"pll_m", "pll_c", "pll_p", "clk_m"};
+
+static struct tegra_periph_init_data tegra_periph_clk_list[] = {
+ TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra20-i2s.0", i2s1_parents, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1),
+ TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra20-i2s.1", i2s2_parents, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2),
+ TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra20-spdif", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out),
+ TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra20-spdif", spdif_in_parents, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in),
+ TEGRA_INIT_DATA_MUX("sbc1", NULL, "spi_tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1),
+ TEGRA_INIT_DATA_MUX("sbc2", NULL, "spi_tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2),
+ TEGRA_INIT_DATA_MUX("sbc3", NULL, "spi_tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3),
+ TEGRA_INIT_DATA_MUX("sbc4", NULL, "spi_tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4),
+ TEGRA_INIT_DATA_MUX("spi", NULL, "spi", mux_pllpcm_clkm, CLK_SOURCE_SPI, 43, &periph_h_regs, TEGRA_PERIPH_ON_APB, spi),
+ TEGRA_INIT_DATA_MUX("xio", NULL, "xio", mux_pllpcm_clkm, CLK_SOURCE_XIO, 45, &periph_h_regs, 0, xio),
+ TEGRA_INIT_DATA_MUX("twc", NULL, "twc", mux_pllpcm_clkm, CLK_SOURCE_TWC, 16, &periph_l_regs, TEGRA_PERIPH_ON_APB, twc),
+ TEGRA_INIT_DATA_MUX("ide", NULL, "ide", mux_pllpcm_clkm, CLK_SOURCE_XIO, 25, &periph_l_regs, 0, ide),
+ TEGRA_INIT_DATA_MUX("ndflash", NULL, "tegra_nand", mux_pllpcm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_l_regs, 0, ndflash),
+ TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllpcm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir),
+ TEGRA_INIT_DATA_MUX("csite", NULL, "csite", mux_pllpcm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, 0, csite),
+ TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllpcm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, 0, la),
+ TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllpcm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr),
+ TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllpcm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi),
+ TEGRA_INIT_DATA_MUX("vde", NULL, "vde", mux_pllpcm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde),
+ TEGRA_INIT_DATA_MUX("vi", "vi", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi),
+ TEGRA_INIT_DATA_MUX("epp", NULL, "epp", mux_pllmcpa, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp),
+ TEGRA_INIT_DATA_MUX("mpe", NULL, "mpe", mux_pllmcpa, CLK_SOURCE_MPE, 60, &periph_h_regs, 0, mpe),
+ TEGRA_INIT_DATA_MUX("host1x", NULL, "host1x", mux_pllmcpa, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x),
+ TEGRA_INIT_DATA_MUX("3d", NULL, "3d", mux_pllmcpa, CLK_SOURCE_3D, 24, &periph_l_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d),
+ TEGRA_INIT_DATA_MUX("2d", NULL, "2d", mux_pllmcpa, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr2d),
+ TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllpcm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor),
+ TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1),
+ TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2),
+ TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3),
+ TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4),
+ TEGRA_INIT_DATA_MUX("cve", NULL, "cve", mux_pllpdc_clkm, CLK_SOURCE_CVE, 49, &periph_h_regs, 0, cve),
+ TEGRA_INIT_DATA_MUX("tvo", NULL, "tvo", mux_pllpdc_clkm, CLK_SOURCE_TVO, 49, &periph_h_regs, 0, tvo),
+ TEGRA_INIT_DATA_MUX("tvdac", NULL, "tvdac", mux_pllpdc_clkm, CLK_SOURCE_TVDAC, 53, &periph_h_regs, 0, tvdac),
+ TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor),
+ TEGRA_INIT_DATA_DIV16("i2c1", "div-clk", "tegra-i2c.0", mux_pllpcm_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2c1),
+ TEGRA_INIT_DATA_DIV16("i2c2", "div-clk", "tegra-i2c.1", mux_pllpcm_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c2),
+ TEGRA_INIT_DATA_DIV16("i2c3", "div-clk", "tegra-i2c.2", mux_pllpcm_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2c3),
+ TEGRA_INIT_DATA_DIV16("dvc", "div-clk", "tegra-i2c.3", mux_pllpcm_clkm, CLK_SOURCE_DVC, 47, &periph_h_regs, TEGRA_PERIPH_ON_APB, dvc),
+ TEGRA_INIT_DATA_MUX("hdmi", NULL, "hdmi", mux_pllpdc_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi),
+ TEGRA_INIT_DATA("pwm", NULL, "tegra-pwm", pwm_parents, CLK_SOURCE_PWM, 28, 3, 0, 0, 8, 1, 0, &periph_l_regs, 17, periph_clk_enb_refcnt, TEGRA_PERIPH_ON_APB, pwm),
+};
+
+static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = {
+ TEGRA_INIT_DATA_NODIV("uarta", NULL, "tegra_uart.0", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 30, 2, 6, &periph_l_regs, TEGRA_PERIPH_ON_APB, uarta),
+ TEGRA_INIT_DATA_NODIV("uartb", NULL, "tegra_uart.1", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 30, 2, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, uartb),
+ TEGRA_INIT_DATA_NODIV("uartc", NULL, "tegra_uart.2", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 30, 2, 55, &periph_h_regs, TEGRA_PERIPH_ON_APB, uartc),
+ TEGRA_INIT_DATA_NODIV("uartd", NULL, "tegra_uart.3", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 30, 2, 65, &periph_u_regs, TEGRA_PERIPH_ON_APB, uartd),
+ TEGRA_INIT_DATA_NODIV("uarte", NULL, "tegra_uart.4", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 30, 2, 66, &periph_u_regs, TEGRA_PERIPH_ON_APB, uarte),
+ TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllpdc_clkm, CLK_SOURCE_DISP1, 30, 2, 27, &periph_l_regs, 0, disp1),
+ TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllpdc_clkm, CLK_SOURCE_DISP2, 30, 2, 26, &periph_l_regs, 0, disp2),
+};
+
+static void __init tegra20_periph_clk_init(void)
+{
+ struct tegra_periph_init_data *data;
+ struct clk *clk;
+ int i;
+
+ /* apbdma */
+ clk = tegra_clk_register_periph_gate("apbdma", "pclk", 0, clk_base,
+ 0, 34, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "tegra-apbdma");
+ clks[apbdma] = clk;
+
+ /* rtc */
+ clk = tegra_clk_register_periph_gate("rtc", "clk_32k",
+ TEGRA_PERIPH_NO_RESET,
+ clk_base, 0, 4, &periph_l_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "rtc-tegra");
+ clks[rtc] = clk;
+
+ /* timer */
+ clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base,
+ 0, 5, &periph_l_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "timer");
+ clks[timer] = clk;
+
+ /* kbc */
+ clk = tegra_clk_register_periph_gate("kbc", "clk_32k",
+ TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 36, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "tegra-kbc");
+ clks[kbc] = clk;
+
+ /* csus */
+ clk = tegra_clk_register_periph_gate("csus", "clk_m",
+ TEGRA_PERIPH_NO_RESET,
+ clk_base, 0, 92, &periph_u_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "csus", "tengra_camera");
+ clks[csus] = clk;
+
+ /* vcp */
+ clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0,
+ clk_base, 0, 29, &periph_l_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "vcp", "tegra-avp");
+ clks[vcp] = clk;
+
+ /* bsea */
+ clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0,
+ clk_base, 0, 62, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "bsea", "tegra-avp");
+ clks[bsea] = clk;
+
+ /* bsev */
+ clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0,
+ clk_base, 0, 63, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "bsev", "tegra-aes");
+ clks[bsev] = clk;
+
+ /* emc */
+ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
+ ARRAY_SIZE(mux_pllmcp_clkm), 0,
+ clk_base + CLK_SOURCE_EMC,
+ 30, 2, 0, NULL);
+ clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
+ 57, &periph_h_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "emc", NULL);
+ clks[emc] = clk;
+
+ /* usbd */
+ clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, 0,
+ 22, &periph_l_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "fsl-tegra-udc");
+ clks[usbd] = clk;
+
+ /* usb2 */
+ clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, 0,
+ 58, &periph_h_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "tegra-ehci.1");
+ clks[usb2] = clk;
+
+ /* usb3 */
+ clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, 0,
+ 59, &periph_h_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "tegra-ehci.2");
+ clks[usb3] = clk;
+
+ /* dsi */
+ clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0,
+ 48, &periph_h_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "dsi");
+ clks[dsi] = clk;
+
+ /* csi */
+ clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base,
+ 0, 52, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "csi", "tegra_camera");
+ clks[csi] = clk;
+
+ /* isp */
+ clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, 23,
+ &periph_l_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "isp", "tegra_camera");
+ clks[isp] = clk;
+
+ /* pex */
+ clk = tegra_clk_register_periph_gate("pex", "clk_m", 0, clk_base, 0, 70,
+ &periph_u_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "pex", NULL);
+ clks[pex] = clk;
+
+ /* afi */
+ clk = tegra_clk_register_periph_gate("afi", "clk_m", 0, clk_base, 0, 72,
+ &periph_u_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "afi", NULL);
+ clks[afi] = clk;
+
+ /* pcie_xclk */
+ clk = tegra_clk_register_periph_gate("pcie_xclk", "clk_m", 0, clk_base,
+ 0, 74, &periph_u_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "pcie_xclk", NULL);
+ clks[pcie_xclk] = clk;
+
+ /* cdev1 */
+ clk = clk_register_fixed_rate(NULL, "cdev1_fixed", NULL, CLK_IS_ROOT,
+ 26000000);
+ clk = tegra_clk_register_periph_gate("cdev1", "cdev1_fixed", 0,
+ clk_base, 0, 94, &periph_u_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "cdev1", NULL);
+ clks[cdev1] = clk;
+
+ /* cdev2 */
+ clk = clk_register_fixed_rate(NULL, "cdev2_fixed", NULL, CLK_IS_ROOT,
+ 26000000);
+ clk = tegra_clk_register_periph_gate("cdev2", "cdev2_fixed", 0,
+ clk_base, 0, 93, &periph_u_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "cdev2", NULL);
+ clks[cdev2] = clk;
+
+ for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) {
+ data = &tegra_periph_clk_list[i];
+ clk = tegra_clk_register_periph(data->name, data->parent_names,
+ data->num_parents, &data->periph,
+ clk_base, data->offset);
+ clk_register_clkdev(clk, data->con_id, data->dev_id);
+ clks[data->clk_id] = clk;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) {
+ data = &tegra_periph_nodiv_clk_list[i];
+ clk = tegra_clk_register_periph_nodiv(data->name,
+ data->parent_names,
+ data->num_parents, &data->periph,
+ clk_base, data->offset);
+ clk_register_clkdev(clk, data->con_id, data->dev_id);
+ clks[data->clk_id] = clk;
+ }
+}
+
+
+static void __init tegra20_fixed_clk_init(void)
+{
+ struct clk *clk;
+
+ /* clk_32k */
+ clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT,
+ 32768);
+ clk_register_clkdev(clk, "clk_32k", NULL);
+ clks[clk_32k] = clk;
+}
+
+static void __init tegra20_pmc_clk_init(void)
+{
+ struct clk *clk;
+
+ /* blink */
+ writel_relaxed(0, pmc_base + PMC_BLINK_TIMER);
+ clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,
+ pmc_base + PMC_DPD_PADS_ORIDE,
+ PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL);
+ clk = clk_register_gate(NULL, "blink", "blink_override", 0,
+ pmc_base + PMC_CTRL,
+ PMC_CTRL_BLINK_ENB, 0, NULL);
+ clk_register_clkdev(clk, "blink", NULL);
+ clks[blink] = clk;
+}
+
+static void __init tegra20_osc_clk_init(void)
+{
+ struct clk *clk;
+ unsigned long input_freq;
+ unsigned int pll_ref_div;
+
+ input_freq = tegra20_clk_measure_input_freq();
+
+ /* clk_m */
+ clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT |
+ CLK_IGNORE_UNUSED, input_freq);
+ clk_register_clkdev(clk, "clk_m", NULL);
+ clks[clk_m] = clk;
+
+ /* pll_ref */
+ pll_ref_div = tegra20_get_pll_ref_div();
+ clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m",
+ CLK_SET_RATE_PARENT, 1, pll_ref_div);
+ clk_register_clkdev(clk, "pll_ref", NULL);
+ clks[pll_ref] = clk;
+}
+
+/* Tegra20 CPU clock and reset control functions */
+static void tegra20_wait_cpu_in_reset(u32 cpu)
+{
+ unsigned int reg;
+
+ do {
+ reg = readl(clk_base +
+ TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+ cpu_relax();
+ } while (!(reg & (1 << cpu))); /* check CPU been reset or not */
+
+ return;
+}
+
+static void tegra20_put_cpu_in_reset(u32 cpu)
+{
+ writel(CPU_RESET(cpu),
+ clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+ dmb();
+}
+
+static void tegra20_cpu_out_of_reset(u32 cpu)
+{
+ writel(CPU_RESET(cpu),
+ clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+ wmb();
+}
+
+static void tegra20_enable_cpu_clock(u32 cpu)
+{
+ unsigned int reg;
+
+ reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+ writel(reg & ~CPU_CLOCK(cpu),
+ clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+ barrier();
+ reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+}
+
+static void tegra20_disable_cpu_clock(u32 cpu)
+{
+ unsigned int reg;
+
+ reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+ writel(reg | CPU_CLOCK(cpu),
+ clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static bool tegra20_cpu_rail_off_ready(void)
+{
+ unsigned int cpu_rst_status;
+
+ cpu_rst_status = readl(clk_base +
+ TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+
+ return !!(cpu_rst_status & 0x2);
+}
+
+static void tegra20_cpu_clock_suspend(void)
+{
+ /* switch coresite to clk_m, save off original source */
+ tegra20_cpu_clk_sctx.clk_csite_src =
+ readl(clk_base + CLK_SOURCE_CSITE);
+ writel(3<<30, clk_base + CLK_SOURCE_CSITE);
+
+ tegra20_cpu_clk_sctx.cpu_burst =
+ readl(clk_base + CCLK_BURST_POLICY);
+ tegra20_cpu_clk_sctx.pllx_base =
+ readl(clk_base + PLLX_BASE);
+ tegra20_cpu_clk_sctx.pllx_misc =
+ readl(clk_base + PLLX_MISC);
+ tegra20_cpu_clk_sctx.cclk_divider =
+ readl(clk_base + SUPER_CCLK_DIVIDER);
+}
+
+static void tegra20_cpu_clock_resume(void)
+{
+ unsigned int reg, policy;
+
+ /* Is CPU complex already running on PLLX? */
+ reg = readl(clk_base + CCLK_BURST_POLICY);
+ policy = (reg >> CCLK_BURST_POLICY_SHIFT) & 0xF;
+
+ if (policy == CCLK_IDLE_POLICY)
+ reg = (reg >> CCLK_IDLE_POLICY_SHIFT) & 0xF;
+ else if (policy == CCLK_RUN_POLICY)
+ reg = (reg >> CCLK_RUN_POLICY_SHIFT) & 0xF;
+ else
+ BUG();
+
+ if (reg != CCLK_BURST_POLICY_PLLX) {
+ /* restore PLLX settings if CPU is on different PLL */
+ writel(tegra20_cpu_clk_sctx.pllx_misc,
+ clk_base + PLLX_MISC);
+ writel(tegra20_cpu_clk_sctx.pllx_base,
+ clk_base + PLLX_BASE);
+
+ /* wait for PLL stabilization if PLLX was enabled */
+ if (tegra20_cpu_clk_sctx.pllx_base & (1 << 30))
+ udelay(300);
+ }
+
+ /*
+ * Restore original burst policy setting for calls resulting from CPU
+ * LP2 in idle or system suspend.
+ */
+ writel(tegra20_cpu_clk_sctx.cclk_divider,
+ clk_base + SUPER_CCLK_DIVIDER);
+ writel(tegra20_cpu_clk_sctx.cpu_burst,
+ clk_base + CCLK_BURST_POLICY);
+
+ writel(tegra20_cpu_clk_sctx.clk_csite_src,
+ clk_base + CLK_SOURCE_CSITE);
+}
+#endif
+
+static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
+ .wait_for_reset = tegra20_wait_cpu_in_reset,
+ .put_in_reset = tegra20_put_cpu_in_reset,
+ .out_of_reset = tegra20_cpu_out_of_reset,
+ .enable_clock = tegra20_enable_cpu_clock,
+ .disable_clock = tegra20_disable_cpu_clock,
+#ifdef CONFIG_PM_SLEEP
+ .rail_off_ready = tegra20_cpu_rail_off_ready,
+ .suspend = tegra20_cpu_clock_suspend,
+ .resume = tegra20_cpu_clock_resume,
+#endif
+};
+
+static __initdata struct tegra_clk_init_table init_table[] = {
+ {pll_p, clk_max, 216000000, 1},
+ {pll_p_out1, clk_max, 28800000, 1},
+ {pll_p_out2, clk_max, 48000000, 1},
+ {pll_p_out3, clk_max, 72000000, 1},
+ {pll_p_out4, clk_max, 24000000, 1},
+ {pll_c, clk_max, 600000000, 1},
+ {pll_c_out1, clk_max, 120000000, 1},
+ {sclk, pll_c_out1, 0, 1},
+ {hclk, clk_max, 0, 1},
+ {pclk, clk_max, 60000000, 1},
+ {csite, clk_max, 0, 1},
+ {emc, clk_max, 0, 1},
+ {cclk, clk_max, 0, 1},
+ {uarta, pll_p, 0, 0},
+ {uartb, pll_p, 0, 0},
+ {uartc, pll_p, 0, 0},
+ {uartd, pll_p, 0, 0},
+ {uarte, pll_p, 0, 0},
+ {usbd, clk_max, 12000000, 0},
+ {usb2, clk_max, 12000000, 0},
+ {usb3, clk_max, 12000000, 0},
+ {pll_a, clk_max, 56448000, 1},
+ {pll_a_out0, clk_max, 11289600, 1},
+ {cdev1, clk_max, 0, 1},
+ {blink, clk_max, 32768, 1},
+ {i2s1, pll_a_out0, 11289600, 0},
+ {i2s2, pll_a_out0, 11289600, 0},
+ {sdmmc1, pll_p, 48000000, 0},
+ {sdmmc3, pll_p, 48000000, 0},
+ {sdmmc4, pll_p, 48000000, 0},
+ {spi, pll_p, 20000000, 0},
+ {sbc1, pll_p, 100000000, 0},
+ {sbc2, pll_p, 100000000, 0},
+ {sbc3, pll_p, 100000000, 0},
+ {sbc4, pll_p, 100000000, 0},
+ {host1x, pll_c, 150000000, 0},
+ {disp1, pll_p, 600000000, 0},
+ {disp2, pll_p, 600000000, 0},
+ {clk_max, clk_max, 0, 0}, /* This MUST be the last entry */
+};
+
+/*
+ * Some clocks may be used by different drivers depending on the board
+ * configuration. List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+static struct tegra_clk_duplicate tegra_clk_duplicates[] = {
+ TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL),
+ TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL),
+ TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL),
+ TEGRA_CLK_DUPLICATE(cclk, NULL, "cpu"),
+ TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL),
+ TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* Must be the last entry */
+};
+
+static const struct of_device_id pmc_match[] __initconst = {
+ { .compatible = "nvidia,tegra20-pmc" },
+ {},
+};
+
+void __init tegra20_clock_init(struct device_node *np)
+{
+ int i;
+ struct device_node *node;
+
+ clk_base = of_iomap(np, 0);
+ if (!clk_base) {
+ pr_err("Can't map CAR registers\n");
+ BUG();
+ }
+
+ node = of_find_matching_node(NULL, pmc_match);
+ if (!node) {
+ pr_err("Failed to find pmc node\n");
+ BUG();
+ }
+
+ pmc_base = of_iomap(node, 0);
+ if (!pmc_base) {
+ pr_err("Can't map pmc registers\n");
+ BUG();
+ }
+
+ tegra20_osc_clk_init();
+ tegra20_pmc_clk_init();
+ tegra20_fixed_clk_init();
+ tegra20_pll_init();
+ tegra20_super_clk_init();
+ tegra20_periph_clk_init();
+ tegra20_audio_clk_init();
+
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++) {
+ if (IS_ERR(clks[i])) {
+ pr_err("Tegra20 clk %d: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+ BUG();
+ }
+ if (!clks[i])
+ clks[i] = ERR_PTR(-EINVAL);
+ }
+
+ tegra_init_dup_clks(tegra_clk_duplicates, clks, clk_max);
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ tegra_init_from_table(init_table, clks, clk_max);
+
+ tegra_cpu_car_ops = &tegra20_cpu_car_ops;
+}
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
new file mode 100644
index 000000000000..32c61cb6d0bb
--- /dev/null
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -0,0 +1,1994 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/tegra.h>
+
+#include <mach/powergate.h>
+
+#include "clk.h"
+
+#define RST_DEVICES_L 0x004
+#define RST_DEVICES_H 0x008
+#define RST_DEVICES_U 0x00c
+#define RST_DEVICES_V 0x358
+#define RST_DEVICES_W 0x35c
+#define RST_DEVICES_SET_L 0x300
+#define RST_DEVICES_CLR_L 0x304
+#define RST_DEVICES_SET_H 0x308
+#define RST_DEVICES_CLR_H 0x30c
+#define RST_DEVICES_SET_U 0x310
+#define RST_DEVICES_CLR_U 0x314
+#define RST_DEVICES_SET_V 0x430
+#define RST_DEVICES_CLR_V 0x434
+#define RST_DEVICES_SET_W 0x438
+#define RST_DEVICES_CLR_W 0x43c
+#define RST_DEVICES_NUM 5
+
+#define CLK_OUT_ENB_L 0x010
+#define CLK_OUT_ENB_H 0x014
+#define CLK_OUT_ENB_U 0x018
+#define CLK_OUT_ENB_V 0x360
+#define CLK_OUT_ENB_W 0x364
+#define CLK_OUT_ENB_SET_L 0x320
+#define CLK_OUT_ENB_CLR_L 0x324
+#define CLK_OUT_ENB_SET_H 0x328
+#define CLK_OUT_ENB_CLR_H 0x32c
+#define CLK_OUT_ENB_SET_U 0x330
+#define CLK_OUT_ENB_CLR_U 0x334
+#define CLK_OUT_ENB_SET_V 0x440
+#define CLK_OUT_ENB_CLR_V 0x444
+#define CLK_OUT_ENB_SET_W 0x448
+#define CLK_OUT_ENB_CLR_W 0x44c
+#define CLK_OUT_ENB_NUM 5
+
+#define OSC_CTRL 0x50
+#define OSC_CTRL_OSC_FREQ_MASK (0xF<<28)
+#define OSC_CTRL_OSC_FREQ_13MHZ (0X0<<28)
+#define OSC_CTRL_OSC_FREQ_19_2MHZ (0X4<<28)
+#define OSC_CTRL_OSC_FREQ_12MHZ (0X8<<28)
+#define OSC_CTRL_OSC_FREQ_26MHZ (0XC<<28)
+#define OSC_CTRL_OSC_FREQ_16_8MHZ (0X1<<28)
+#define OSC_CTRL_OSC_FREQ_38_4MHZ (0X5<<28)
+#define OSC_CTRL_OSC_FREQ_48MHZ (0X9<<28)
+#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
+
+#define OSC_CTRL_PLL_REF_DIV_MASK (3<<26)
+#define OSC_CTRL_PLL_REF_DIV_1 (0<<26)
+#define OSC_CTRL_PLL_REF_DIV_2 (1<<26)
+#define OSC_CTRL_PLL_REF_DIV_4 (2<<26)
+
+#define OSC_FREQ_DET 0x58
+#define OSC_FREQ_DET_TRIG BIT(31)
+
+#define OSC_FREQ_DET_STATUS 0x5c
+#define OSC_FREQ_DET_BUSY BIT(31)
+#define OSC_FREQ_DET_CNT_MASK 0xffff
+
+#define CCLKG_BURST_POLICY 0x368
+#define SUPER_CCLKG_DIVIDER 0x36c
+#define CCLKLP_BURST_POLICY 0x370
+#define SUPER_CCLKLP_DIVIDER 0x374
+#define SCLK_BURST_POLICY 0x028
+#define SUPER_SCLK_DIVIDER 0x02c
+
+#define SYSTEM_CLK_RATE 0x030
+
+#define PLLC_BASE 0x80
+#define PLLC_MISC 0x8c
+#define PLLM_BASE 0x90
+#define PLLM_MISC 0x9c
+#define PLLP_BASE 0xa0
+#define PLLP_MISC 0xac
+#define PLLX_BASE 0xe0
+#define PLLX_MISC 0xe4
+#define PLLD_BASE 0xd0
+#define PLLD_MISC 0xdc
+#define PLLD2_BASE 0x4b8
+#define PLLD2_MISC 0x4bc
+#define PLLE_BASE 0xe8
+#define PLLE_MISC 0xec
+#define PLLA_BASE 0xb0
+#define PLLA_MISC 0xbc
+#define PLLU_BASE 0xc0
+#define PLLU_MISC 0xcc
+
+#define PLL_MISC_LOCK_ENABLE 18
+#define PLLDU_MISC_LOCK_ENABLE 22
+#define PLLE_MISC_LOCK_ENABLE 9
+
+#define PLL_BASE_LOCK 27
+#define PLLE_MISC_LOCK 11
+
+#define PLLE_AUX 0x48c
+#define PLLC_OUT 0x84
+#define PLLM_OUT 0x94
+#define PLLP_OUTA 0xa4
+#define PLLP_OUTB 0xa8
+#define PLLA_OUT 0xb4
+
+#define AUDIO_SYNC_CLK_I2S0 0x4a0
+#define AUDIO_SYNC_CLK_I2S1 0x4a4
+#define AUDIO_SYNC_CLK_I2S2 0x4a8
+#define AUDIO_SYNC_CLK_I2S3 0x4ac
+#define AUDIO_SYNC_CLK_I2S4 0x4b0
+#define AUDIO_SYNC_CLK_SPDIF 0x4b4
+
+#define PMC_CLK_OUT_CNTRL 0x1a8
+
+#define CLK_SOURCE_I2S0 0x1d8
+#define CLK_SOURCE_I2S1 0x100
+#define CLK_SOURCE_I2S2 0x104
+#define CLK_SOURCE_I2S3 0x3bc
+#define CLK_SOURCE_I2S4 0x3c0
+#define CLK_SOURCE_SPDIF_OUT 0x108
+#define CLK_SOURCE_SPDIF_IN 0x10c
+#define CLK_SOURCE_PWM 0x110
+#define CLK_SOURCE_D_AUDIO 0x3d0
+#define CLK_SOURCE_DAM0 0x3d8
+#define CLK_SOURCE_DAM1 0x3dc
+#define CLK_SOURCE_DAM2 0x3e0
+#define CLK_SOURCE_HDA 0x428
+#define CLK_SOURCE_HDA2CODEC_2X 0x3e4
+#define CLK_SOURCE_SBC1 0x134
+#define CLK_SOURCE_SBC2 0x118
+#define CLK_SOURCE_SBC3 0x11c
+#define CLK_SOURCE_SBC4 0x1b4
+#define CLK_SOURCE_SBC5 0x3c8
+#define CLK_SOURCE_SBC6 0x3cc
+#define CLK_SOURCE_SATA_OOB 0x420
+#define CLK_SOURCE_SATA 0x424
+#define CLK_SOURCE_NDFLASH 0x160
+#define CLK_SOURCE_NDSPEED 0x3f8
+#define CLK_SOURCE_VFIR 0x168
+#define CLK_SOURCE_SDMMC1 0x150
+#define CLK_SOURCE_SDMMC2 0x154
+#define CLK_SOURCE_SDMMC3 0x1bc
+#define CLK_SOURCE_SDMMC4 0x164
+#define CLK_SOURCE_VDE 0x1c8
+#define CLK_SOURCE_CSITE 0x1d4
+#define CLK_SOURCE_LA 0x1f8
+#define CLK_SOURCE_OWR 0x1cc
+#define CLK_SOURCE_NOR 0x1d0
+#define CLK_SOURCE_MIPI 0x174
+#define CLK_SOURCE_I2C1 0x124
+#define CLK_SOURCE_I2C2 0x198
+#define CLK_SOURCE_I2C3 0x1b8
+#define CLK_SOURCE_I2C4 0x3c4
+#define CLK_SOURCE_I2C5 0x128
+#define CLK_SOURCE_UARTA 0x178
+#define CLK_SOURCE_UARTB 0x17c
+#define CLK_SOURCE_UARTC 0x1a0
+#define CLK_SOURCE_UARTD 0x1c0
+#define CLK_SOURCE_UARTE 0x1c4
+#define CLK_SOURCE_VI 0x148
+#define CLK_SOURCE_VI_SENSOR 0x1a8
+#define CLK_SOURCE_3D 0x158
+#define CLK_SOURCE_3D2 0x3b0
+#define CLK_SOURCE_2D 0x15c
+#define CLK_SOURCE_EPP 0x16c
+#define CLK_SOURCE_MPE 0x170
+#define CLK_SOURCE_HOST1X 0x180
+#define CLK_SOURCE_CVE 0x140
+#define CLK_SOURCE_TVO 0x188
+#define CLK_SOURCE_DTV 0x1dc
+#define CLK_SOURCE_HDMI 0x18c
+#define CLK_SOURCE_TVDAC 0x194
+#define CLK_SOURCE_DISP1 0x138
+#define CLK_SOURCE_DISP2 0x13c
+#define CLK_SOURCE_DSIB 0xd0
+#define CLK_SOURCE_TSENSOR 0x3b8
+#define CLK_SOURCE_ACTMON 0x3e8
+#define CLK_SOURCE_EXTERN1 0x3ec
+#define CLK_SOURCE_EXTERN2 0x3f0
+#define CLK_SOURCE_EXTERN3 0x3f4
+#define CLK_SOURCE_I2CSLOW 0x3fc
+#define CLK_SOURCE_SE 0x42c
+#define CLK_SOURCE_MSELECT 0x3b4
+#define CLK_SOURCE_EMC 0x19c
+
+#define AUDIO_SYNC_DOUBLER 0x49c
+
+#define PMC_CTRL 0
+#define PMC_CTRL_BLINK_ENB 7
+
+#define PMC_DPD_PADS_ORIDE 0x1c
+#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20
+#define PMC_BLINK_TIMER 0x40
+
+#define UTMIP_PLL_CFG2 0x488
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6)
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4)
+
+#define UTMIP_PLL_CFG1 0x484
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16)
+
+/* Tegra CPU clock and reset control regs */
+#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340
+#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344
+#define TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR 0x34c
+#define TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470
+
+#define CPU_CLOCK(cpu) (0x1 << (8 + cpu))
+#define CPU_RESET(cpu) (0x1111ul << (cpu))
+
+#define CLK_RESET_CCLK_BURST 0x20
+#define CLK_RESET_CCLK_DIVIDER 0x24
+#define CLK_RESET_PLLX_BASE 0xe0
+#define CLK_RESET_PLLX_MISC 0xe4
+
+#define CLK_RESET_SOURCE_CSITE 0x1d4
+
+#define CLK_RESET_CCLK_BURST_POLICY_SHIFT 28
+#define CLK_RESET_CCLK_RUN_POLICY_SHIFT 4
+#define CLK_RESET_CCLK_IDLE_POLICY_SHIFT 0
+#define CLK_RESET_CCLK_IDLE_POLICY 1
+#define CLK_RESET_CCLK_RUN_POLICY 2
+#define CLK_RESET_CCLK_BURST_POLICY_PLLX 8
+
+#ifdef CONFIG_PM_SLEEP
+static struct cpu_clk_suspend_context {
+ u32 pllx_misc;
+ u32 pllx_base;
+
+ u32 cpu_burst;
+ u32 clk_csite_src;
+ u32 cclk_divider;
+} tegra30_cpu_clk_sctx;
+#endif
+
+static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32];
+
+static void __iomem *clk_base;
+static void __iomem *pmc_base;
+static unsigned long input_freq;
+
+static DEFINE_SPINLOCK(clk_doubler_lock);
+static DEFINE_SPINLOCK(clk_out_lock);
+static DEFINE_SPINLOCK(pll_div_lock);
+static DEFINE_SPINLOCK(cml_lock);
+static DEFINE_SPINLOCK(pll_d_lock);
+static DEFINE_SPINLOCK(sysrate_lock);
+
+#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \
+ 30, 2, 0, 0, 8, 1, 0, _regs, _clk_num, \
+ periph_clk_enb_refcnt, _gate_flags, _clk_id)
+
+#define TEGRA_INIT_DATA_DIV16(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \
+ 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, \
+ _regs, _clk_num, periph_clk_enb_refcnt, \
+ _gate_flags, _clk_id)
+
+#define TEGRA_INIT_DATA_MUX8(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \
+ 29, 3, 0, 0, 8, 1, 0, _regs, _clk_num, \
+ periph_clk_enb_refcnt, _gate_flags, _clk_id)
+
+#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \
+ 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \
+ _clk_num, periph_clk_enb_refcnt, _gate_flags, \
+ _clk_id)
+
+#define TEGRA_INIT_DATA_UART(_name, _con_id, _dev_id, _parents, _offset,\
+ _clk_num, _regs, _clk_id) \
+ TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \
+ 30, 2, 0, 0, 16, 1, TEGRA_DIVIDER_UART, _regs, \
+ _clk_num, periph_clk_enb_refcnt, 0, _clk_id)
+
+#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \
+ _mux_shift, _mux_width, _clk_num, _regs, \
+ _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \
+ _mux_shift, _mux_width, 0, 0, 0, 0, 0, _regs, \
+ _clk_num, periph_clk_enb_refcnt, _gate_flags, \
+ _clk_id)
+
+/*
+ * IDs assigned here must be in sync with DT bindings definition
+ * for Tegra30 clocks.
+ */
+enum tegra30_clk {
+ cpu, rtc = 4, timer, uarta, gpio = 8, sdmmc2, i2s1 = 11, i2c1, ndflash,
+ sdmmc1, sdmmc4, pwm = 17, i2s2, epp, gr2d = 21, usbd, isp, gr3d,
+ disp2 = 26, disp1, host1x, vcp, i2s0, cop_cache, mc, ahbdma, apbdma,
+ kbc = 36, statmon, pmc, kfuse = 40, sbc1, nor, sbc2 = 44, sbc3 = 46,
+ i2c5, dsia, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2,
+ usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3,
+ pcie, owr, afi, csite, pciex, avpucq, la, dtv = 79, ndspeed, i2cslow,
+ dsib, irama = 84, iramb, iramc, iramd, cram2, audio_2x = 90, csus = 92,
+ cdev1, cdev2, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4,
+ i2c4, sbc5, sbc6, d_audio, apbif, dam0, dam1, dam2, hda2codec_2x,
+ atomics, audio0_2x, audio1_2x, audio2_2x, audio3_2x, audio4_2x,
+ spdif_2x, actmon, extern1, extern2, extern3, sata_oob, sata, hda,
+ se = 127, hda2hdmi, sata_cold, uartb = 160, vfir, spdif_in, spdif_out,
+ vi, vi_sensor, fuse, fuse_burn, cve, tvo, clk_32k, clk_m, clk_m_div2,
+ clk_m_div4, pll_ref, pll_c, pll_c_out1, pll_m, pll_m_out1, pll_p,
+ pll_p_out1, pll_p_out2, pll_p_out3, pll_p_out4, pll_a, pll_a_out0,
+ pll_d, pll_d_out0, pll_d2, pll_d2_out0, pll_u, pll_x, pll_x_out0, pll_e,
+ spdif_in_sync, i2s0_sync, i2s1_sync, i2s2_sync, i2s3_sync, i2s4_sync,
+ vimclk_sync, audio0, audio1, audio2, audio3, audio4, spdif, clk_out_1,
+ clk_out_2, clk_out_3, sclk, blink, cclk_g, cclk_lp, twd, cml0, cml1,
+ hclk, pclk, clk_out_1_mux = 300, clk_max
+};
+
+static struct clk *clks[clk_max];
+static struct clk_onecell_data clk_data;
+
+/*
+ * Structure defining the fields for USB UTMI clocks Parameters.
+ */
+struct utmi_clk_param {
+ /* Oscillator Frequency in KHz */
+ u32 osc_frequency;
+ /* UTMIP PLL Enable Delay Count */
+ u8 enable_delay_count;
+ /* UTMIP PLL Stable count */
+ u8 stable_count;
+ /* UTMIP PLL Active delay count */
+ u8 active_delay_count;
+ /* UTMIP PLL Xtal frequency count */
+ u8 xtal_freq_count;
+};
+
+static const struct utmi_clk_param utmi_parameters[] = {
+/* OSC_FREQUENCY, ENABLE_DLY, STABLE_CNT, ACTIVE_DLY, XTAL_FREQ_CNT */
+ {13000000, 0x02, 0x33, 0x05, 0x7F},
+ {19200000, 0x03, 0x4B, 0x06, 0xBB},
+ {12000000, 0x02, 0x2F, 0x04, 0x76},
+ {26000000, 0x04, 0x66, 0x09, 0xFE},
+ {16800000, 0x03, 0x41, 0x0A, 0xA4},
+};
+
+static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
+ { 12000000, 1040000000, 520, 6, 1, 8},
+ { 13000000, 1040000000, 480, 6, 1, 8},
+ { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */
+ { 19200000, 1040000000, 325, 6, 1, 6},
+ { 26000000, 1040000000, 520, 13, 1, 8},
+
+ { 12000000, 832000000, 416, 6, 1, 8},
+ { 13000000, 832000000, 832, 13, 1, 8},
+ { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */
+ { 19200000, 832000000, 260, 6, 1, 8},
+ { 26000000, 832000000, 416, 13, 1, 8},
+
+ { 12000000, 624000000, 624, 12, 1, 8},
+ { 13000000, 624000000, 624, 13, 1, 8},
+ { 16800000, 600000000, 520, 14, 1, 8},
+ { 19200000, 624000000, 520, 16, 1, 8},
+ { 26000000, 624000000, 624, 26, 1, 8},
+
+ { 12000000, 600000000, 600, 12, 1, 8},
+ { 13000000, 600000000, 600, 13, 1, 8},
+ { 16800000, 600000000, 500, 14, 1, 8},
+ { 19200000, 600000000, 375, 12, 1, 6},
+ { 26000000, 600000000, 600, 26, 1, 8},
+
+ { 12000000, 520000000, 520, 12, 1, 8},
+ { 13000000, 520000000, 520, 13, 1, 8},
+ { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */
+ { 19200000, 520000000, 325, 12, 1, 6},
+ { 26000000, 520000000, 520, 26, 1, 8},
+
+ { 12000000, 416000000, 416, 12, 1, 8},
+ { 13000000, 416000000, 416, 13, 1, 8},
+ { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */
+ { 19200000, 416000000, 260, 12, 1, 6},
+ { 26000000, 416000000, 416, 26, 1, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
+ { 12000000, 666000000, 666, 12, 1, 8},
+ { 13000000, 666000000, 666, 13, 1, 8},
+ { 16800000, 666000000, 555, 14, 1, 8},
+ { 19200000, 666000000, 555, 16, 1, 8},
+ { 26000000, 666000000, 666, 26, 1, 8},
+ { 12000000, 600000000, 600, 12, 1, 8},
+ { 13000000, 600000000, 600, 13, 1, 8},
+ { 16800000, 600000000, 500, 14, 1, 8},
+ { 19200000, 600000000, 375, 12, 1, 6},
+ { 26000000, 600000000, 600, 26, 1, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
+ { 12000000, 216000000, 432, 12, 2, 8},
+ { 13000000, 216000000, 432, 13, 2, 8},
+ { 16800000, 216000000, 360, 14, 2, 8},
+ { 19200000, 216000000, 360, 16, 2, 8},
+ { 26000000, 216000000, 432, 26, 2, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
+ { 9600000, 564480000, 294, 5, 1, 4},
+ { 9600000, 552960000, 288, 5, 1, 4},
+ { 9600000, 24000000, 5, 2, 1, 1},
+
+ { 28800000, 56448000, 49, 25, 1, 1},
+ { 28800000, 73728000, 64, 25, 1, 1},
+ { 28800000, 24000000, 5, 6, 1, 1},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
+ { 12000000, 216000000, 216, 12, 1, 4},
+ { 13000000, 216000000, 216, 13, 1, 4},
+ { 16800000, 216000000, 180, 14, 1, 4},
+ { 19200000, 216000000, 180, 16, 1, 4},
+ { 26000000, 216000000, 216, 26, 1, 4},
+
+ { 12000000, 594000000, 594, 12, 1, 8},
+ { 13000000, 594000000, 594, 13, 1, 8},
+ { 16800000, 594000000, 495, 14, 1, 8},
+ { 19200000, 594000000, 495, 16, 1, 8},
+ { 26000000, 594000000, 594, 26, 1, 8},
+
+ { 12000000, 1000000000, 1000, 12, 1, 12},
+ { 13000000, 1000000000, 1000, 13, 1, 12},
+ { 19200000, 1000000000, 625, 12, 1, 8},
+ { 26000000, 1000000000, 1000, 26, 1, 12},
+
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
+ { 12000000, 480000000, 960, 12, 2, 12},
+ { 13000000, 480000000, 960, 13, 2, 12},
+ { 16800000, 480000000, 400, 7, 2, 5},
+ { 19200000, 480000000, 200, 4, 2, 3},
+ { 26000000, 480000000, 960, 26, 2, 12},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
+ /* 1.7 GHz */
+ { 12000000, 1700000000, 850, 6, 1, 8},
+ { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */
+ { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */
+ { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */
+ { 26000000, 1700000000, 850, 13, 1, 8},
+
+ /* 1.6 GHz */
+ { 12000000, 1600000000, 800, 6, 1, 8},
+ { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */
+ { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */
+ { 19200000, 1600000000, 500, 6, 1, 8},
+ { 26000000, 1600000000, 800, 13, 1, 8},
+
+ /* 1.5 GHz */
+ { 12000000, 1500000000, 750, 6, 1, 8},
+ { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */
+ { 16800000, 1500000000, 625, 7, 1, 8},
+ { 19200000, 1500000000, 625, 8, 1, 8},
+ { 26000000, 1500000000, 750, 13, 1, 8},
+
+ /* 1.4 GHz */
+ { 12000000, 1400000000, 700, 6, 1, 8},
+ { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */
+ { 16800000, 1400000000, 1000, 12, 1, 8},
+ { 19200000, 1400000000, 875, 12, 1, 8},
+ { 26000000, 1400000000, 700, 13, 1, 8},
+
+ /* 1.3 GHz */
+ { 12000000, 1300000000, 975, 9, 1, 8},
+ { 13000000, 1300000000, 1000, 10, 1, 8},
+ { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */
+ { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */
+ { 26000000, 1300000000, 650, 13, 1, 8},
+
+ /* 1.2 GHz */
+ { 12000000, 1200000000, 1000, 10, 1, 8},
+ { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */
+ { 16800000, 1200000000, 1000, 14, 1, 8},
+ { 19200000, 1200000000, 1000, 16, 1, 8},
+ { 26000000, 1200000000, 600, 13, 1, 8},
+
+ /* 1.1 GHz */
+ { 12000000, 1100000000, 825, 9, 1, 8},
+ { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */
+ { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */
+ { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */
+ { 26000000, 1100000000, 550, 13, 1, 8},
+
+ /* 1 GHz */
+ { 12000000, 1000000000, 1000, 12, 1, 8},
+ { 13000000, 1000000000, 1000, 13, 1, 8},
+ { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */
+ { 19200000, 1000000000, 625, 12, 1, 8},
+ { 26000000, 1000000000, 1000, 26, 1, 8},
+
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
+ /* PLLE special case: use cpcon field to store cml divider value */
+ { 12000000, 100000000, 150, 1, 18, 11},
+ { 216000000, 100000000, 200, 18, 24, 13},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+/* PLL parameters */
+static struct tegra_clk_pll_params pll_c_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1400000000,
+ .base_reg = PLLC_BASE,
+ .misc_reg = PLLC_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_m_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLM_BASE,
+ .misc_reg = PLLM_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_p_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1400000000,
+ .base_reg = PLLP_BASE,
+ .misc_reg = PLLP_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_a_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1400000000,
+ .base_reg = PLLA_BASE,
+ .misc_reg = PLLA_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_d_params = {
+ .input_min = 2000000,
+ .input_max = 40000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 40000000,
+ .vco_max = 1000000000,
+ .base_reg = PLLD_BASE,
+ .misc_reg = PLLD_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+};
+
+static struct tegra_clk_pll_params pll_d2_params = {
+ .input_min = 2000000,
+ .input_max = 40000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 40000000,
+ .vco_max = 1000000000,
+ .base_reg = PLLD2_BASE,
+ .misc_reg = PLLD2_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+};
+
+static struct tegra_clk_pll_params pll_u_params = {
+ .input_min = 2000000,
+ .input_max = 40000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 48000000,
+ .vco_max = 960000000,
+ .base_reg = PLLU_BASE,
+ .misc_reg = PLLU_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+};
+
+static struct tegra_clk_pll_params pll_x_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1700000000,
+ .base_reg = PLLX_BASE,
+ .misc_reg = PLLX_MISC,
+ .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_e_params = {
+ .input_min = 12000000,
+ .input_max = 216000000,
+ .cf_min = 12000000,
+ .cf_max = 12000000,
+ .vco_min = 1200000000,
+ .vco_max = 2400000000U,
+ .base_reg = PLLE_BASE,
+ .misc_reg = PLLE_MISC,
+ .lock_bit_idx = PLLE_MISC_LOCK,
+ .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+/* Peripheral clock registers */
+static struct tegra_clk_periph_regs periph_l_regs = {
+ .enb_reg = CLK_OUT_ENB_L,
+ .enb_set_reg = CLK_OUT_ENB_SET_L,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_L,
+ .rst_reg = RST_DEVICES_L,
+ .rst_set_reg = RST_DEVICES_SET_L,
+ .rst_clr_reg = RST_DEVICES_CLR_L,
+};
+
+static struct tegra_clk_periph_regs periph_h_regs = {
+ .enb_reg = CLK_OUT_ENB_H,
+ .enb_set_reg = CLK_OUT_ENB_SET_H,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_H,
+ .rst_reg = RST_DEVICES_H,
+ .rst_set_reg = RST_DEVICES_SET_H,
+ .rst_clr_reg = RST_DEVICES_CLR_H,
+};
+
+static struct tegra_clk_periph_regs periph_u_regs = {
+ .enb_reg = CLK_OUT_ENB_U,
+ .enb_set_reg = CLK_OUT_ENB_SET_U,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_U,
+ .rst_reg = RST_DEVICES_U,
+ .rst_set_reg = RST_DEVICES_SET_U,
+ .rst_clr_reg = RST_DEVICES_CLR_U,
+};
+
+static struct tegra_clk_periph_regs periph_v_regs = {
+ .enb_reg = CLK_OUT_ENB_V,
+ .enb_set_reg = CLK_OUT_ENB_SET_V,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_V,
+ .rst_reg = RST_DEVICES_V,
+ .rst_set_reg = RST_DEVICES_SET_V,
+ .rst_clr_reg = RST_DEVICES_CLR_V,
+};
+
+static struct tegra_clk_periph_regs periph_w_regs = {
+ .enb_reg = CLK_OUT_ENB_W,
+ .enb_set_reg = CLK_OUT_ENB_SET_W,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_W,
+ .rst_reg = RST_DEVICES_W,
+ .rst_set_reg = RST_DEVICES_SET_W,
+ .rst_clr_reg = RST_DEVICES_CLR_W,
+};
+
+static void tegra30_clk_measure_input_freq(void)
+{
+ u32 osc_ctrl = readl_relaxed(clk_base + OSC_CTRL);
+ u32 auto_clk_control = osc_ctrl & OSC_CTRL_OSC_FREQ_MASK;
+ u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK;
+
+ switch (auto_clk_control) {
+ case OSC_CTRL_OSC_FREQ_12MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ input_freq = 12000000;
+ break;
+ case OSC_CTRL_OSC_FREQ_13MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ input_freq = 13000000;
+ break;
+ case OSC_CTRL_OSC_FREQ_19_2MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ input_freq = 19200000;
+ break;
+ case OSC_CTRL_OSC_FREQ_26MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ input_freq = 26000000;
+ break;
+ case OSC_CTRL_OSC_FREQ_16_8MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ input_freq = 16800000;
+ break;
+ case OSC_CTRL_OSC_FREQ_38_4MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2);
+ input_freq = 38400000;
+ break;
+ case OSC_CTRL_OSC_FREQ_48MHZ:
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4);
+ input_freq = 48000000;
+ break;
+ default:
+ pr_err("Unexpected auto clock control value %d",
+ auto_clk_control);
+ BUG();
+ return;
+ }
+}
+
+static unsigned int tegra30_get_pll_ref_div(void)
+{
+ u32 pll_ref_div = readl_relaxed(clk_base + OSC_CTRL) &
+ OSC_CTRL_PLL_REF_DIV_MASK;
+
+ switch (pll_ref_div) {
+ case OSC_CTRL_PLL_REF_DIV_1:
+ return 1;
+ case OSC_CTRL_PLL_REF_DIV_2:
+ return 2;
+ case OSC_CTRL_PLL_REF_DIV_4:
+ return 4;
+ default:
+ pr_err("Invalid pll ref divider %d", pll_ref_div);
+ BUG();
+ }
+ return 0;
+}
+
+static void tegra30_utmi_param_configure(void)
+{
+ u32 reg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+ if (input_freq == utmi_parameters[i].osc_frequency)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(utmi_parameters)) {
+ pr_err("%s: Unexpected input rate %lu\n", __func__, input_freq);
+ return;
+ }
+
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL stable and active counts */
+ reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+ reg |= UTMIP_PLL_CFG2_STABLE_COUNT(
+ utmi_parameters[i].stable_count);
+
+ reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
+ utmi_parameters[i].active_delay_count);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL delay and oscillator frequency counts */
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+ reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
+ utmi_parameters[i].enable_delay_count);
+
+ reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+ reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
+ utmi_parameters[i].xtal_freq_count);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+}
+
+static const char *pll_e_parents[] = {"pll_ref", "pll_p"};
+
+static void __init tegra30_pll_init(void)
+{
+ struct clk *clk;
+
+ /* PLLC */
+ clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, pmc_base, 0,
+ 0, &pll_c_params,
+ TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
+ pll_c_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_c", NULL);
+ clks[pll_c] = clk;
+
+ /* PLLC_OUT1 */
+ clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c",
+ clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div",
+ clk_base + PLLC_OUT, 1, 0, CLK_SET_RATE_PARENT,
+ 0, NULL);
+ clk_register_clkdev(clk, "pll_c_out1", NULL);
+ clks[pll_c_out1] = clk;
+
+ /* PLLP */
+ clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, pmc_base, 0,
+ 408000000, &pll_p_params,
+ TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON |
+ TEGRA_PLL_USE_LOCK, pll_p_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_p", NULL);
+ clks[pll_p] = clk;
+
+ /* PLLP_OUT1 */
+ clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p",
+ clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED |
+ TEGRA_DIVIDER_ROUND_UP, 8, 8, 1,
+ &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div",
+ clk_base + PLLP_OUTA, 1, 0,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out1", NULL);
+ clks[pll_p_out1] = clk;
+
+ /* PLLP_OUT2 */
+ clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p",
+ clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED |
+ TEGRA_DIVIDER_ROUND_UP, 24, 8, 1,
+ &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div",
+ clk_base + PLLP_OUTA, 17, 16,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out2", NULL);
+ clks[pll_p_out2] = clk;
+
+ /* PLLP_OUT3 */
+ clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p",
+ clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED |
+ TEGRA_DIVIDER_ROUND_UP, 8, 8, 1,
+ &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div",
+ clk_base + PLLP_OUTB, 1, 0,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out3", NULL);
+ clks[pll_p_out3] = clk;
+
+ /* PLLP_OUT4 */
+ clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p",
+ clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED |
+ TEGRA_DIVIDER_ROUND_UP, 24, 8, 1,
+ &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div",
+ clk_base + PLLP_OUTB, 17, 16,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out4", NULL);
+ clks[pll_p_out4] = clk;
+
+ /* PLLM */
+ clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, pmc_base,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0,
+ &pll_m_params, TEGRA_PLLM | TEGRA_PLL_HAS_CPCON |
+ TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK,
+ pll_m_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_m", NULL);
+ clks[pll_m] = clk;
+
+ /* PLLM_OUT1 */
+ clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m",
+ clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div",
+ clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED |
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_m_out1", NULL);
+ clks[pll_m_out1] = clk;
+
+ /* PLLX */
+ clk = tegra_clk_register_pll("pll_x", "pll_ref", clk_base, pmc_base, 0,
+ 0, &pll_x_params, TEGRA_PLL_HAS_CPCON |
+ TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK,
+ pll_x_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_x", NULL);
+ clks[pll_x] = clk;
+
+ /* PLLX_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll_x_out0", NULL);
+ clks[pll_x_out0] = clk;
+
+ /* PLLU */
+ clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc_base, 0,
+ 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON |
+ TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK,
+ pll_u_freq_table,
+ NULL);
+ clk_register_clkdev(clk, "pll_u", NULL);
+ clks[pll_u] = clk;
+
+ tegra30_utmi_param_configure();
+
+ /* PLLD */
+ clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc_base, 0,
+ 0, &pll_d_params, TEGRA_PLL_HAS_CPCON |
+ TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK,
+ pll_d_freq_table, &pll_d_lock);
+ clk_register_clkdev(clk, "pll_d", NULL);
+ clks[pll_d] = clk;
+
+ /* PLLD_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll_d_out0", NULL);
+ clks[pll_d_out0] = clk;
+
+ /* PLLD2 */
+ clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base, 0,
+ 0, &pll_d2_params, TEGRA_PLL_HAS_CPCON |
+ TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK,
+ pll_d_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_d2", NULL);
+ clks[pll_d2] = clk;
+
+ /* PLLD2_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll_d2_out0", NULL);
+ clks[pll_d2_out0] = clk;
+
+ /* PLLA */
+ clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, pmc_base,
+ 0, 0, &pll_a_params, TEGRA_PLL_HAS_CPCON |
+ TEGRA_PLL_USE_LOCK, pll_a_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_a", NULL);
+ clks[pll_a] = clk;
+
+ /* PLLA_OUT0 */
+ clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a",
+ clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div",
+ clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED |
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_a_out0", NULL);
+ clks[pll_a_out0] = clk;
+
+ /* PLLE */
+ clk = clk_register_mux(NULL, "pll_e_mux", pll_e_parents,
+ ARRAY_SIZE(pll_e_parents), 0,
+ clk_base + PLLE_AUX, 2, 1, 0, NULL);
+ clk = tegra_clk_register_plle("pll_e", "pll_e_mux", clk_base, pmc_base,
+ CLK_GET_RATE_NOCACHE, 100000000, &pll_e_params,
+ TEGRA_PLLE_CONFIGURE, pll_e_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_e", NULL);
+ clks[pll_e] = clk;
+}
+
+static const char *mux_audio_sync_clk[] = { "spdif_in_sync", "i2s0_sync",
+ "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync",};
+static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
+ "clk_m_div4", "extern1", };
+static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
+ "clk_m_div4", "extern2", };
+static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
+ "clk_m_div4", "extern3", };
+
+static void __init tegra30_audio_clk_init(void)
+{
+ struct clk *clk;
+
+ /* spdif_in_sync */
+ clk = tegra_clk_register_sync_source("spdif_in_sync", 24000000,
+ 24000000);
+ clk_register_clkdev(clk, "spdif_in_sync", NULL);
+ clks[spdif_in_sync] = clk;
+
+ /* i2s0_sync */
+ clk = tegra_clk_register_sync_source("i2s0_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "i2s0_sync", NULL);
+ clks[i2s0_sync] = clk;
+
+ /* i2s1_sync */
+ clk = tegra_clk_register_sync_source("i2s1_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "i2s1_sync", NULL);
+ clks[i2s1_sync] = clk;
+
+ /* i2s2_sync */
+ clk = tegra_clk_register_sync_source("i2s2_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "i2s2_sync", NULL);
+ clks[i2s2_sync] = clk;
+
+ /* i2s3_sync */
+ clk = tegra_clk_register_sync_source("i2s3_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "i2s3_sync", NULL);
+ clks[i2s3_sync] = clk;
+
+ /* i2s4_sync */
+ clk = tegra_clk_register_sync_source("i2s4_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "i2s4_sync", NULL);
+ clks[i2s4_sync] = clk;
+
+ /* vimclk_sync */
+ clk = tegra_clk_register_sync_source("vimclk_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "vimclk_sync", NULL);
+ clks[vimclk_sync] = clk;
+
+ /* audio0 */
+ clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0, NULL);
+ clk = clk_register_gate(NULL, "audio0", "audio0_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_I2S0, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio0", NULL);
+ clks[audio0] = clk;
+
+ /* audio1 */
+ clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0, NULL);
+ clk = clk_register_gate(NULL, "audio1", "audio1_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_I2S1, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio1", NULL);
+ clks[audio1] = clk;
+
+ /* audio2 */
+ clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0, NULL);
+ clk = clk_register_gate(NULL, "audio2", "audio2_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_I2S2, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio2", NULL);
+ clks[audio2] = clk;
+
+ /* audio3 */
+ clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0, NULL);
+ clk = clk_register_gate(NULL, "audio3", "audio3_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_I2S3, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio3", NULL);
+ clks[audio3] = clk;
+
+ /* audio4 */
+ clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0, NULL);
+ clk = clk_register_gate(NULL, "audio4", "audio4_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_I2S4, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio4", NULL);
+ clks[audio4] = clk;
+
+ /* spdif */
+ clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0, NULL);
+ clk = clk_register_gate(NULL, "spdif", "spdif_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_SPDIF, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "spdif", NULL);
+ clks[spdif] = clk;
+
+ /* audio0_2x */
+ clk = clk_register_fixed_factor(NULL, "audio0_doubler", "audio0",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("audio0_div", "audio0_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 24, 1, 0,
+ &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("audio0_2x", "audio0_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 113, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio0_2x", NULL);
+ clks[audio0_2x] = clk;
+
+ /* audio1_2x */
+ clk = clk_register_fixed_factor(NULL, "audio1_doubler", "audio1",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("audio1_div", "audio1_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 25, 1, 0,
+ &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("audio1_2x", "audio1_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 114, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio1_2x", NULL);
+ clks[audio1_2x] = clk;
+
+ /* audio2_2x */
+ clk = clk_register_fixed_factor(NULL, "audio2_doubler", "audio2",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("audio2_div", "audio2_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 26, 1, 0,
+ &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("audio2_2x", "audio2_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 115, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio2_2x", NULL);
+ clks[audio2_2x] = clk;
+
+ /* audio3_2x */
+ clk = clk_register_fixed_factor(NULL, "audio3_doubler", "audio3",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("audio3_div", "audio3_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 27, 1, 0,
+ &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("audio3_2x", "audio3_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 116, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio3_2x", NULL);
+ clks[audio3_2x] = clk;
+
+ /* audio4_2x */
+ clk = clk_register_fixed_factor(NULL, "audio4_doubler", "audio4",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("audio4_div", "audio4_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 28, 1, 0,
+ &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("audio4_2x", "audio4_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 117, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio4_2x", NULL);
+ clks[audio4_2x] = clk;
+
+ /* spdif_2x */
+ clk = clk_register_fixed_factor(NULL, "spdif_doubler", "spdif",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("spdif_div", "spdif_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 29, 1, 0,
+ &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("spdif_2x", "spdif_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 118, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "spdif_2x", NULL);
+ clks[spdif_2x] = clk;
+}
+
+static void __init tegra30_pmc_clk_init(void)
+{
+ struct clk *clk;
+
+ /* clk_out_1 */
+ clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents,
+ ARRAY_SIZE(clk_out1_parents), 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0,
+ &clk_out_lock);
+ clks[clk_out_1_mux] = clk;
+ clk = clk_register_gate(NULL, "clk_out_1", "clk_out_1_mux", 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 2, 0,
+ &clk_out_lock);
+ clk_register_clkdev(clk, "extern1", "clk_out_1");
+ clks[clk_out_1] = clk;
+
+ /* clk_out_2 */
+ clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
+ ARRAY_SIZE(clk_out1_parents), 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
+ &clk_out_lock);
+ clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 10, 0,
+ &clk_out_lock);
+ clk_register_clkdev(clk, "extern2", "clk_out_2");
+ clks[clk_out_2] = clk;
+
+ /* clk_out_3 */
+ clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
+ ARRAY_SIZE(clk_out1_parents), 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
+ &clk_out_lock);
+ clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 18, 0,
+ &clk_out_lock);
+ clk_register_clkdev(clk, "extern3", "clk_out_3");
+ clks[clk_out_3] = clk;
+
+ /* blink */
+ writel_relaxed(0, pmc_base + PMC_BLINK_TIMER);
+ clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,
+ pmc_base + PMC_DPD_PADS_ORIDE,
+ PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL);
+ clk = clk_register_gate(NULL, "blink", "blink_override", 0,
+ pmc_base + PMC_CTRL,
+ PMC_CTRL_BLINK_ENB, 0, NULL);
+ clk_register_clkdev(clk, "blink", NULL);
+ clks[blink] = clk;
+
+}
+
+static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
+ "pll_p_cclkg", "pll_p_out4_cclkg",
+ "pll_p_out3_cclkg", "unused", "pll_x" };
+static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
+ "pll_p_cclklp", "pll_p_out4_cclklp",
+ "pll_p_out3_cclklp", "unused", "pll_x",
+ "pll_x_out0" };
+static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
+ "pll_p_out3", "pll_p_out2", "unused",
+ "clk_32k", "pll_m_out1" };
+
+static void __init tegra30_super_clk_init(void)
+{
+ struct clk *clk;
+
+ /*
+ * Clock input to cclk_g divided from pll_p using
+ * U71 divider of cclk_g.
+ */
+ clk = tegra_clk_register_divider("pll_p_cclkg", "pll_p",
+ clk_base + SUPER_CCLKG_DIVIDER, 0,
+ TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
+ clk_register_clkdev(clk, "pll_p_cclkg", NULL);
+
+ /*
+ * Clock input to cclk_g divided from pll_p_out3 using
+ * U71 divider of cclk_g.
+ */
+ clk = tegra_clk_register_divider("pll_p_out3_cclkg", "pll_p_out3",
+ clk_base + SUPER_CCLKG_DIVIDER, 0,
+ TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
+ clk_register_clkdev(clk, "pll_p_out3_cclkg", NULL);
+
+ /*
+ * Clock input to cclk_g divided from pll_p_out4 using
+ * U71 divider of cclk_g.
+ */
+ clk = tegra_clk_register_divider("pll_p_out4_cclkg", "pll_p_out4",
+ clk_base + SUPER_CCLKG_DIVIDER, 0,
+ TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
+ clk_register_clkdev(clk, "pll_p_out4_cclkg", NULL);
+
+ /* CCLKG */
+ clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents,
+ ARRAY_SIZE(cclk_g_parents),
+ CLK_SET_RATE_PARENT,
+ clk_base + CCLKG_BURST_POLICY,
+ 0, 4, 0, 0, NULL);
+ clk_register_clkdev(clk, "cclk_g", NULL);
+ clks[cclk_g] = clk;
+
+ /*
+ * Clock input to cclk_lp divided from pll_p using
+ * U71 divider of cclk_lp.
+ */
+ clk = tegra_clk_register_divider("pll_p_cclklp", "pll_p",
+ clk_base + SUPER_CCLKLP_DIVIDER, 0,
+ TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
+ clk_register_clkdev(clk, "pll_p_cclklp", NULL);
+
+ /*
+ * Clock input to cclk_lp divided from pll_p_out3 using
+ * U71 divider of cclk_lp.
+ */
+ clk = tegra_clk_register_divider("pll_p_out3_cclklp", "pll_p_out3",
+ clk_base + SUPER_CCLKG_DIVIDER, 0,
+ TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
+ clk_register_clkdev(clk, "pll_p_out3_cclklp", NULL);
+
+ /*
+ * Clock input to cclk_lp divided from pll_p_out4 using
+ * U71 divider of cclk_lp.
+ */
+ clk = tegra_clk_register_divider("pll_p_out4_cclklp", "pll_p_out4",
+ clk_base + SUPER_CCLKLP_DIVIDER, 0,
+ TEGRA_DIVIDER_INT, 16, 8, 1, NULL);
+ clk_register_clkdev(clk, "pll_p_out4_cclklp", NULL);
+
+ /* CCLKLP */
+ clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents,
+ ARRAY_SIZE(cclk_lp_parents),
+ CLK_SET_RATE_PARENT,
+ clk_base + CCLKLP_BURST_POLICY,
+ TEGRA_DIVIDER_2, 4, 8, 9,
+ NULL);
+ clk_register_clkdev(clk, "cclk_lp", NULL);
+ clks[cclk_lp] = clk;
+
+ /* SCLK */
+ clk = tegra_clk_register_super_mux("sclk", sclk_parents,
+ ARRAY_SIZE(sclk_parents),
+ CLK_SET_RATE_PARENT,
+ clk_base + SCLK_BURST_POLICY,
+ 0, 4, 0, 0, NULL);
+ clk_register_clkdev(clk, "sclk", NULL);
+ clks[sclk] = clk;
+
+ /* HCLK */
+ clk = clk_register_divider(NULL, "hclk_div", "sclk", 0,
+ clk_base + SYSTEM_CLK_RATE, 4, 2, 0,
+ &sysrate_lock);
+ clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT,
+ clk_base + SYSTEM_CLK_RATE, 7,
+ CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
+ clk_register_clkdev(clk, "hclk", NULL);
+ clks[hclk] = clk;
+
+ /* PCLK */
+ clk = clk_register_divider(NULL, "pclk_div", "hclk", 0,
+ clk_base + SYSTEM_CLK_RATE, 0, 2, 0,
+ &sysrate_lock);
+ clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT,
+ clk_base + SYSTEM_CLK_RATE, 3,
+ CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
+ clk_register_clkdev(clk, "pclk", NULL);
+ clks[pclk] = clk;
+
+ /* twd */
+ clk = clk_register_fixed_factor(NULL, "twd", "cclk_g",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "twd", NULL);
+ clks[twd] = clk;
+}
+
+static const char *mux_pllacp_clkm[] = { "pll_a_out0", "unused", "pll_p",
+ "clk_m" };
+static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" };
+static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" };
+static const char *i2s0_parents[] = { "pll_a_out0", "audio0_2x", "pll_p",
+ "clk_m" };
+static const char *i2s1_parents[] = { "pll_a_out0", "audio1_2x", "pll_p",
+ "clk_m" };
+static const char *i2s2_parents[] = { "pll_a_out0", "audio2_2x", "pll_p",
+ "clk_m" };
+static const char *i2s3_parents[] = { "pll_a_out0", "audio3_2x", "pll_p",
+ "clk_m" };
+static const char *i2s4_parents[] = { "pll_a_out0", "audio4_2x", "pll_p",
+ "clk_m" };
+static const char *spdif_out_parents[] = { "pll_a_out0", "spdif_2x", "pll_p",
+ "clk_m" };
+static const char *spdif_in_parents[] = { "pll_p", "pll_c", "pll_m" };
+static const char *mux_pllpc_clk32k_clkm[] = { "pll_p", "pll_c", "clk_32k",
+ "clk_m" };
+static const char *mux_pllpc_clkm_clk32k[] = { "pll_p", "pll_c", "clk_m",
+ "clk_32k" };
+static const char *mux_pllmcpa[] = { "pll_m", "pll_c", "pll_p", "pll_a_out0" };
+static const char *mux_pllpdc_clkm[] = { "pll_p", "pll_d_out0", "pll_c",
+ "clk_m" };
+static const char *mux_pllp_clkm[] = { "pll_p", "unused", "unused", "clk_m" };
+static const char *mux_pllpmdacd2_clkm[] = { "pll_p", "pll_m", "pll_d_out0",
+ "pll_a_out0", "pll_c",
+ "pll_d2_out0", "clk_m" };
+static const char *mux_plla_clk32k_pllp_clkm_plle[] = { "pll_a_out0",
+ "clk_32k", "pll_p",
+ "clk_m", "pll_e" };
+static const char *mux_plld_out0_plld2_out0[] = { "pll_d_out0",
+ "pll_d2_out0" };
+
+static struct tegra_periph_init_data tegra_periph_clk_list[] = {
+ TEGRA_INIT_DATA_MUX("i2s0", NULL, "tegra30-i2s.0", i2s0_parents, CLK_SOURCE_I2S0, 30, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s0),
+ TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra30-i2s.1", i2s1_parents, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1),
+ TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra30-i2s.2", i2s2_parents, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2),
+ TEGRA_INIT_DATA_MUX("i2s3", NULL, "tegra30-i2s.3", i2s3_parents, CLK_SOURCE_I2S3, 101, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s3),
+ TEGRA_INIT_DATA_MUX("i2s4", NULL, "tegra30-i2s.4", i2s4_parents, CLK_SOURCE_I2S4, 102, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s4),
+ TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra30-spdif", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out),
+ TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra30-spdif", spdif_in_parents, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in),
+ TEGRA_INIT_DATA_MUX("d_audio", "d_audio", "tegra30-ahub", mux_pllacp_clkm, CLK_SOURCE_D_AUDIO, 106, &periph_v_regs, 0, d_audio),
+ TEGRA_INIT_DATA_MUX("dam0", NULL, "tegra30-dam.0", mux_pllacp_clkm, CLK_SOURCE_DAM0, 108, &periph_v_regs, 0, dam0),
+ TEGRA_INIT_DATA_MUX("dam1", NULL, "tegra30-dam.1", mux_pllacp_clkm, CLK_SOURCE_DAM1, 109, &periph_v_regs, 0, dam1),
+ TEGRA_INIT_DATA_MUX("dam2", NULL, "tegra30-dam.2", mux_pllacp_clkm, CLK_SOURCE_DAM2, 110, &periph_v_regs, 0, dam2),
+ TEGRA_INIT_DATA_MUX("hda", "hda", "tegra30-hda", mux_pllpcm_clkm, CLK_SOURCE_HDA, 125, &periph_v_regs, 0, hda),
+ TEGRA_INIT_DATA_MUX("hda2codec_2x", "hda2codec", "tegra30-hda", mux_pllpcm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, &periph_v_regs, 0, hda2codec_2x),
+ TEGRA_INIT_DATA_MUX("sbc1", NULL, "spi_tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1),
+ TEGRA_INIT_DATA_MUX("sbc2", NULL, "spi_tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2),
+ TEGRA_INIT_DATA_MUX("sbc3", NULL, "spi_tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3),
+ TEGRA_INIT_DATA_MUX("sbc4", NULL, "spi_tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4),
+ TEGRA_INIT_DATA_MUX("sbc5", NULL, "spi_tegra.4", mux_pllpcm_clkm, CLK_SOURCE_SBC5, 104, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc5),
+ TEGRA_INIT_DATA_MUX("sbc6", NULL, "spi_tegra.5", mux_pllpcm_clkm, CLK_SOURCE_SBC6, 105, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc6),
+ TEGRA_INIT_DATA_MUX("sata_oob", NULL, "tegra_sata_oob", mux_pllpcm_clkm, CLK_SOURCE_SATA_OOB, 123, &periph_v_regs, TEGRA_PERIPH_ON_APB, sata_oob),
+ TEGRA_INIT_DATA_MUX("sata", NULL, "tegra_sata", mux_pllpcm_clkm, CLK_SOURCE_SATA, 124, &periph_v_regs, TEGRA_PERIPH_ON_APB, sata),
+ TEGRA_INIT_DATA_MUX("ndflash", NULL, "tegra_nand", mux_pllpcm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_l_regs, TEGRA_PERIPH_ON_APB, ndflash),
+ TEGRA_INIT_DATA_MUX("ndspeed", NULL, "tegra_nand_speed", mux_pllpcm_clkm, CLK_SOURCE_NDSPEED, 80, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed),
+ TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllpcm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir),
+ TEGRA_INIT_DATA_MUX("csite", NULL, "csite", mux_pllpcm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, TEGRA_PERIPH_ON_APB, csite),
+ TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllpcm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, TEGRA_PERIPH_ON_APB, la),
+ TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllpcm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr),
+ TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllpcm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi),
+ TEGRA_INIT_DATA_MUX("tsensor", NULL, "tegra-tsensor", mux_pllpc_clkm_clk32k, CLK_SOURCE_TSENSOR, 100, &periph_v_regs, TEGRA_PERIPH_ON_APB, tsensor),
+ TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllpc_clk32k_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow),
+ TEGRA_INIT_DATA_INT("vde", NULL, "vde", mux_pllpcm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde),
+ TEGRA_INIT_DATA_INT("vi", "vi", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi),
+ TEGRA_INIT_DATA_INT("epp", NULL, "epp", mux_pllmcpa, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp),
+ TEGRA_INIT_DATA_INT("mpe", NULL, "mpe", mux_pllmcpa, CLK_SOURCE_MPE, 60, &periph_h_regs, 0, mpe),
+ TEGRA_INIT_DATA_INT("host1x", NULL, "host1x", mux_pllmcpa, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x),
+ TEGRA_INIT_DATA_INT("3d", NULL, "3d", mux_pllmcpa, CLK_SOURCE_3D, 24, &periph_l_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d),
+ TEGRA_INIT_DATA_INT("3d2", NULL, "3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, &periph_v_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d2),
+ TEGRA_INIT_DATA_INT("2d", NULL, "2d", mux_pllmcpa, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr2d),
+ TEGRA_INIT_DATA_INT("se", NULL, "se", mux_pllpcm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, 0, se),
+ TEGRA_INIT_DATA_MUX("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect),
+ TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllpcm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor),
+ TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1),
+ TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2),
+ TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3),
+ TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4),
+ TEGRA_INIT_DATA_MUX("cve", NULL, "cve", mux_pllpdc_clkm, CLK_SOURCE_CVE, 49, &periph_h_regs, 0, cve),
+ TEGRA_INIT_DATA_MUX("tvo", NULL, "tvo", mux_pllpdc_clkm, CLK_SOURCE_TVO, 49, &periph_h_regs, 0, tvo),
+ TEGRA_INIT_DATA_MUX("tvdac", NULL, "tvdac", mux_pllpdc_clkm, CLK_SOURCE_TVDAC, 53, &periph_h_regs, 0, tvdac),
+ TEGRA_INIT_DATA_MUX("actmon", NULL, "actmon", mux_pllpc_clk32k_clkm, CLK_SOURCE_ACTMON, 119, &periph_v_regs, 0, actmon),
+ TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor),
+ TEGRA_INIT_DATA_DIV16("i2c1", "div-clk", "tegra-i2c.0", mux_pllp_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2c1),
+ TEGRA_INIT_DATA_DIV16("i2c2", "div-clk", "tegra-i2c.1", mux_pllp_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c2),
+ TEGRA_INIT_DATA_DIV16("i2c3", "div-clk", "tegra-i2c.2", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2c3),
+ TEGRA_INIT_DATA_DIV16("i2c4", "div-clk", "tegra-i2c.3", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2c4),
+ TEGRA_INIT_DATA_DIV16("i2c5", "div-clk", "tegra-i2c.4", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c5),
+ TEGRA_INIT_DATA_UART("uarta", NULL, "tegra_uart.0", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 6, &periph_l_regs, uarta),
+ TEGRA_INIT_DATA_UART("uartb", NULL, "tegra_uart.1", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 7, &periph_l_regs, uartb),
+ TEGRA_INIT_DATA_UART("uartc", NULL, "tegra_uart.2", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 55, &periph_h_regs, uartc),
+ TEGRA_INIT_DATA_UART("uartd", NULL, "tegra_uart.3", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 65, &periph_u_regs, uartd),
+ TEGRA_INIT_DATA_UART("uarte", NULL, "tegra_uart.4", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 66, &periph_u_regs, uarte),
+ TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllpmdacd2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi),
+ TEGRA_INIT_DATA_MUX8("extern1", NULL, "extern1", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, &periph_v_regs, 0, extern1),
+ TEGRA_INIT_DATA_MUX8("extern2", NULL, "extern2", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, &periph_v_regs, 0, extern2),
+ TEGRA_INIT_DATA_MUX8("extern3", NULL, "extern3", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, &periph_v_regs, 0, extern3),
+ TEGRA_INIT_DATA("pwm", NULL, "pwm", mux_pllpc_clk32k_clkm, CLK_SOURCE_PWM, 28, 2, 0, 0, 8, 1, 0, &periph_l_regs, 17, periph_clk_enb_refcnt, 0, pwm),
+};
+
+static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = {
+ TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllpmdacd2_clkm, CLK_SOURCE_DISP1, 29, 3, 27, &periph_l_regs, 0, disp1),
+ TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllpmdacd2_clkm, CLK_SOURCE_DISP2, 29, 3, 26, &periph_l_regs, 0, disp2),
+ TEGRA_INIT_DATA_NODIV("dsib", NULL, "tegradc.1", mux_plld_out0_plld2_out0, CLK_SOURCE_DSIB, 25, 1, 82, &periph_u_regs, 0, dsib),
+};
+
+static void __init tegra30_periph_clk_init(void)
+{
+ struct tegra_periph_init_data *data;
+ struct clk *clk;
+ int i;
+
+ /* apbdma */
+ clk = tegra_clk_register_periph_gate("apbdma", "clk_m", 0, clk_base, 0, 34,
+ &periph_h_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "tegra-apbdma");
+ clks[apbdma] = clk;
+
+ /* rtc */
+ clk = tegra_clk_register_periph_gate("rtc", "clk_32k",
+ TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 4, &periph_l_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "rtc-tegra");
+ clks[rtc] = clk;
+
+ /* timer */
+ clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, 0,
+ 5, &periph_l_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "timer");
+ clks[timer] = clk;
+
+ /* kbc */
+ clk = tegra_clk_register_periph_gate("kbc", "clk_32k",
+ TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 36, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "tegra-kbc");
+ clks[kbc] = clk;
+
+ /* csus */
+ clk = tegra_clk_register_periph_gate("csus", "clk_m",
+ TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 92, &periph_u_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "csus", "tengra_camera");
+ clks[csus] = clk;
+
+ /* vcp */
+ clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, clk_base, 0, 29,
+ &periph_l_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "vcp", "tegra-avp");
+ clks[vcp] = clk;
+
+ /* bsea */
+ clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, clk_base, 0,
+ 62, &periph_h_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "bsea", "tegra-avp");
+ clks[bsea] = clk;
+
+ /* bsev */
+ clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, clk_base, 0,
+ 63, &periph_h_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "bsev", "tegra-aes");
+ clks[bsev] = clk;
+
+ /* usbd */
+ clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, 0,
+ 22, &periph_l_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "fsl-tegra-udc");
+ clks[usbd] = clk;
+
+ /* usb2 */
+ clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, 0,
+ 58, &periph_h_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "tegra-ehci.1");
+ clks[usb2] = clk;
+
+ /* usb3 */
+ clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, 0,
+ 59, &periph_h_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "tegra-ehci.2");
+ clks[usb3] = clk;
+
+ /* dsia */
+ clk = tegra_clk_register_periph_gate("dsia", "pll_d_out0", 0, clk_base,
+ 0, 48, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "dsia", "tegradc.0");
+ clks[dsia] = clk;
+
+ /* csi */
+ clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base,
+ 0, 52, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "csi", "tegra_camera");
+ clks[csi] = clk;
+
+ /* isp */
+ clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, 23,
+ &periph_l_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "isp", "tegra_camera");
+ clks[isp] = clk;
+
+ /* pcie */
+ clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0,
+ 70, &periph_u_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "pcie", "tegra-pcie");
+ clks[pcie] = clk;
+
+ /* afi */
+ clk = tegra_clk_register_periph_gate("afi", "clk_m", 0, clk_base, 0, 72,
+ &periph_u_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "afi", "tegra-pcie");
+ clks[afi] = clk;
+
+ /* kfuse */
+ clk = tegra_clk_register_periph_gate("kfuse", "clk_m",
+ TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 40, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "kfuse-tegra");
+ clks[kfuse] = clk;
+
+ /* fuse */
+ clk = tegra_clk_register_periph_gate("fuse", "clk_m",
+ TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 39, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "fuse", "fuse-tegra");
+ clks[fuse] = clk;
+
+ /* fuse_burn */
+ clk = tegra_clk_register_periph_gate("fuse_burn", "clk_m",
+ TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 39, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "fuse_burn", "fuse-tegra");
+ clks[fuse_burn] = clk;
+
+ /* apbif */
+ clk = tegra_clk_register_periph_gate("apbif", "clk_m", 0,
+ clk_base, 0, 107, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "apbif", "tegra30-ahub");
+ clks[apbif] = clk;
+
+ /* hda2hdmi */
+ clk = tegra_clk_register_periph_gate("hda2hdmi", "clk_m",
+ TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 128, &periph_w_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "hda2hdmi", "tegra30-hda");
+ clks[hda2hdmi] = clk;
+
+ /* sata_cold */
+ clk = tegra_clk_register_periph_gate("sata_cold", "clk_m",
+ TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 129, &periph_w_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "tegra_sata_cold");
+ clks[sata_cold] = clk;
+
+ /* dtv */
+ clk = tegra_clk_register_periph_gate("dtv", "clk_m",
+ TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 79, &periph_u_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "dtv");
+ clks[dtv] = clk;
+
+ /* emc */
+ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
+ ARRAY_SIZE(mux_pllmcp_clkm), 0,
+ clk_base + CLK_SOURCE_EMC,
+ 30, 2, 0, NULL);
+ clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
+ 57, &periph_h_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "emc", NULL);
+ clks[emc] = clk;
+
+ for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) {
+ data = &tegra_periph_clk_list[i];
+ clk = tegra_clk_register_periph(data->name, data->parent_names,
+ data->num_parents, &data->periph,
+ clk_base, data->offset);
+ clk_register_clkdev(clk, data->con_id, data->dev_id);
+ clks[data->clk_id] = clk;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) {
+ data = &tegra_periph_nodiv_clk_list[i];
+ clk = tegra_clk_register_periph_nodiv(data->name,
+ data->parent_names,
+ data->num_parents, &data->periph,
+ clk_base, data->offset);
+ clk_register_clkdev(clk, data->con_id, data->dev_id);
+ clks[data->clk_id] = clk;
+ }
+}
+
+static void __init tegra30_fixed_clk_init(void)
+{
+ struct clk *clk;
+
+ /* clk_32k */
+ clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT,
+ 32768);
+ clk_register_clkdev(clk, "clk_32k", NULL);
+ clks[clk_32k] = clk;
+
+ /* clk_m_div2 */
+ clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "clk_m_div2", NULL);
+ clks[clk_m_div2] = clk;
+
+ /* clk_m_div4 */
+ clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m",
+ CLK_SET_RATE_PARENT, 1, 4);
+ clk_register_clkdev(clk, "clk_m_div4", NULL);
+ clks[clk_m_div4] = clk;
+
+ /* cml0 */
+ clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX,
+ 0, 0, &cml_lock);
+ clk_register_clkdev(clk, "cml0", NULL);
+ clks[cml0] = clk;
+
+ /* cml1 */
+ clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX,
+ 1, 0, &cml_lock);
+ clk_register_clkdev(clk, "cml1", NULL);
+ clks[cml1] = clk;
+
+ /* pciex */
+ clk = clk_register_fixed_rate(NULL, "pciex", "pll_e", 0, 100000000);
+ clk_register_clkdev(clk, "pciex", NULL);
+ clks[pciex] = clk;
+}
+
+static void __init tegra30_osc_clk_init(void)
+{
+ struct clk *clk;
+ unsigned int pll_ref_div;
+
+ tegra30_clk_measure_input_freq();
+
+ /* clk_m */
+ clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT,
+ input_freq);
+ clk_register_clkdev(clk, "clk_m", NULL);
+ clks[clk_m] = clk;
+
+ /* pll_ref */
+ pll_ref_div = tegra30_get_pll_ref_div();
+ clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m",
+ CLK_SET_RATE_PARENT, 1, pll_ref_div);
+ clk_register_clkdev(clk, "pll_ref", NULL);
+ clks[pll_ref] = clk;
+}
+
+/* Tegra30 CPU clock and reset control functions */
+static void tegra30_wait_cpu_in_reset(u32 cpu)
+{
+ unsigned int reg;
+
+ do {
+ reg = readl(clk_base +
+ TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
+ cpu_relax();
+ } while (!(reg & (1 << cpu))); /* check CPU been reset or not */
+
+ return;
+}
+
+static void tegra30_put_cpu_in_reset(u32 cpu)
+{
+ writel(CPU_RESET(cpu),
+ clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+ dmb();
+}
+
+static void tegra30_cpu_out_of_reset(u32 cpu)
+{
+ writel(CPU_RESET(cpu),
+ clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+ wmb();
+}
+
+
+static void tegra30_enable_cpu_clock(u32 cpu)
+{
+ unsigned int reg;
+
+ writel(CPU_CLOCK(cpu),
+ clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+ reg = readl(clk_base +
+ TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+}
+
+static void tegra30_disable_cpu_clock(u32 cpu)
+{
+
+ unsigned int reg;
+
+ reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+ writel(reg | CPU_CLOCK(cpu),
+ clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static bool tegra30_cpu_rail_off_ready(void)
+{
+ unsigned int cpu_rst_status;
+ int cpu_pwr_status;
+
+ cpu_rst_status = readl(clk_base +
+ TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
+ cpu_pwr_status = tegra_powergate_is_powered(TEGRA_POWERGATE_CPU1) ||
+ tegra_powergate_is_powered(TEGRA_POWERGATE_CPU2) ||
+ tegra_powergate_is_powered(TEGRA_POWERGATE_CPU3);
+
+ if (((cpu_rst_status & 0xE) != 0xE) || cpu_pwr_status)
+ return false;
+
+ return true;
+}
+
+static void tegra30_cpu_clock_suspend(void)
+{
+ /* switch coresite to clk_m, save off original source */
+ tegra30_cpu_clk_sctx.clk_csite_src =
+ readl(clk_base + CLK_RESET_SOURCE_CSITE);
+ writel(3<<30, clk_base + CLK_RESET_SOURCE_CSITE);
+
+ tegra30_cpu_clk_sctx.cpu_burst =
+ readl(clk_base + CLK_RESET_CCLK_BURST);
+ tegra30_cpu_clk_sctx.pllx_base =
+ readl(clk_base + CLK_RESET_PLLX_BASE);
+ tegra30_cpu_clk_sctx.pllx_misc =
+ readl(clk_base + CLK_RESET_PLLX_MISC);
+ tegra30_cpu_clk_sctx.cclk_divider =
+ readl(clk_base + CLK_RESET_CCLK_DIVIDER);
+}
+
+static void tegra30_cpu_clock_resume(void)
+{
+ unsigned int reg, policy;
+
+ /* Is CPU complex already running on PLLX? */
+ reg = readl(clk_base + CLK_RESET_CCLK_BURST);
+ policy = (reg >> CLK_RESET_CCLK_BURST_POLICY_SHIFT) & 0xF;
+
+ if (policy == CLK_RESET_CCLK_IDLE_POLICY)
+ reg = (reg >> CLK_RESET_CCLK_IDLE_POLICY_SHIFT) & 0xF;
+ else if (policy == CLK_RESET_CCLK_RUN_POLICY)
+ reg = (reg >> CLK_RESET_CCLK_RUN_POLICY_SHIFT) & 0xF;
+ else
+ BUG();
+
+ if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) {
+ /* restore PLLX settings if CPU is on different PLL */
+ writel(tegra30_cpu_clk_sctx.pllx_misc,
+ clk_base + CLK_RESET_PLLX_MISC);
+ writel(tegra30_cpu_clk_sctx.pllx_base,
+ clk_base + CLK_RESET_PLLX_BASE);
+
+ /* wait for PLL stabilization if PLLX was enabled */
+ if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30))
+ udelay(300);
+ }
+
+ /*
+ * Restore original burst policy setting for calls resulting from CPU
+ * LP2 in idle or system suspend.
+ */
+ writel(tegra30_cpu_clk_sctx.cclk_divider,
+ clk_base + CLK_RESET_CCLK_DIVIDER);
+ writel(tegra30_cpu_clk_sctx.cpu_burst,
+ clk_base + CLK_RESET_CCLK_BURST);
+
+ writel(tegra30_cpu_clk_sctx.clk_csite_src,
+ clk_base + CLK_RESET_SOURCE_CSITE);
+}
+#endif
+
+static struct tegra_cpu_car_ops tegra30_cpu_car_ops = {
+ .wait_for_reset = tegra30_wait_cpu_in_reset,
+ .put_in_reset = tegra30_put_cpu_in_reset,
+ .out_of_reset = tegra30_cpu_out_of_reset,
+ .enable_clock = tegra30_enable_cpu_clock,
+ .disable_clock = tegra30_disable_cpu_clock,
+#ifdef CONFIG_PM_SLEEP
+ .rail_off_ready = tegra30_cpu_rail_off_ready,
+ .suspend = tegra30_cpu_clock_suspend,
+ .resume = tegra30_cpu_clock_resume,
+#endif
+};
+
+static __initdata struct tegra_clk_init_table init_table[] = {
+ {uarta, pll_p, 408000000, 0},
+ {uartb, pll_p, 408000000, 0},
+ {uartc, pll_p, 408000000, 0},
+ {uartd, pll_p, 408000000, 0},
+ {uarte, pll_p, 408000000, 0},
+ {pll_a, clk_max, 564480000, 1},
+ {pll_a_out0, clk_max, 11289600, 1},
+ {extern1, pll_a_out0, 0, 1},
+ {clk_out_1_mux, extern1, 0, 0},
+ {clk_out_1, clk_max, 0, 1},
+ {blink, clk_max, 0, 1},
+ {i2s0, pll_a_out0, 11289600, 0},
+ {i2s1, pll_a_out0, 11289600, 0},
+ {i2s2, pll_a_out0, 11289600, 0},
+ {i2s3, pll_a_out0, 11289600, 0},
+ {i2s4, pll_a_out0, 11289600, 0},
+ {sdmmc1, pll_p, 48000000, 0},
+ {sdmmc2, pll_p, 48000000, 0},
+ {sdmmc3, pll_p, 48000000, 0},
+ {pll_m, clk_max, 0, 1},
+ {pclk, clk_max, 0, 1},
+ {csite, clk_max, 0, 1},
+ {emc, clk_max, 0, 1},
+ {mselect, clk_max, 0, 1},
+ {sbc1, pll_p, 100000000, 0},
+ {sbc2, pll_p, 100000000, 0},
+ {sbc3, pll_p, 100000000, 0},
+ {sbc4, pll_p, 100000000, 0},
+ {sbc5, pll_p, 100000000, 0},
+ {sbc6, pll_p, 100000000, 0},
+ {host1x, pll_c, 150000000, 0},
+ {disp1, pll_p, 600000000, 0},
+ {disp2, pll_p, 600000000, 0},
+ {twd, clk_max, 0, 1},
+ {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */
+};
+
+/*
+ * Some clocks may be used by different drivers depending on the board
+ * configuration. List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+static struct tegra_clk_duplicate tegra_clk_duplicates[] = {
+ TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL),
+ TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL),
+ TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL),
+ TEGRA_CLK_DUPLICATE(bsev, "tegra-avp", "bsev"),
+ TEGRA_CLK_DUPLICATE(bsev, "nvavp", "bsev"),
+ TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"),
+ TEGRA_CLK_DUPLICATE(bsea, "tegra-aes", "bsea"),
+ TEGRA_CLK_DUPLICATE(bsea, "nvavp", "bsea"),
+ TEGRA_CLK_DUPLICATE(cml1, "tegra_sata_cml", NULL),
+ TEGRA_CLK_DUPLICATE(cml0, "tegra_pcie", "cml"),
+ TEGRA_CLK_DUPLICATE(pciex, "tegra_pcie", "pciex"),
+ TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL),
+ TEGRA_CLK_DUPLICATE(vcp, "nvavp", "vcp"),
+ TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* MUST be the last entry */
+};
+
+static const struct of_device_id pmc_match[] __initconst = {
+ { .compatible = "nvidia,tegra30-pmc" },
+ {},
+};
+
+void __init tegra30_clock_init(struct device_node *np)
+{
+ struct device_node *node;
+ int i;
+
+ clk_base = of_iomap(np, 0);
+ if (!clk_base) {
+ pr_err("ioremap tegra30 CAR failed\n");
+ return;
+ }
+
+ node = of_find_matching_node(NULL, pmc_match);
+ if (!node) {
+ pr_err("Failed to find pmc node\n");
+ BUG();
+ }
+
+ pmc_base = of_iomap(node, 0);
+ if (!pmc_base) {
+ pr_err("Can't map pmc registers\n");
+ BUG();
+ }
+
+ tegra30_osc_clk_init();
+ tegra30_fixed_clk_init();
+ tegra30_pll_init();
+ tegra30_super_clk_init();
+ tegra30_periph_clk_init();
+ tegra30_audio_clk_init();
+ tegra30_pmc_clk_init();
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++) {
+ if (IS_ERR(clks[i])) {
+ pr_err("Tegra30 clk %d: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+ BUG();
+ }
+ if (!clks[i])
+ clks[i] = ERR_PTR(-EINVAL);
+ }
+
+ tegra_init_dup_clks(tegra_clk_duplicates, clks, clk_max);
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ tegra_init_from_table(init_table, clks, clk_max);
+
+ tegra_cpu_car_ops = &tegra30_cpu_car_ops;
+}
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
new file mode 100644
index 000000000000..a603b9af0ad3
--- /dev/null
+++ b/drivers/clk/tegra/clk.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/clk/tegra.h>
+
+#include "clk.h"
+
+/* Global data of Tegra CPU CAR ops */
+struct tegra_cpu_car_ops *tegra_cpu_car_ops;
+
+void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
+ struct clk *clks[], int clk_max)
+{
+ struct clk *clk;
+
+ for (; dup_list->clk_id < clk_max; dup_list++) {
+ clk = clks[dup_list->clk_id];
+ dup_list->lookup.clk = clk;
+ clkdev_add(&dup_list->lookup);
+ }
+}
+
+void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
+ struct clk *clks[], int clk_max)
+{
+ struct clk *clk;
+
+ for (; tbl->clk_id < clk_max; tbl++) {
+ clk = clks[tbl->clk_id];
+ if (IS_ERR_OR_NULL(clk))
+ return;
+
+ if (tbl->parent_id < clk_max) {
+ struct clk *parent = clks[tbl->parent_id];
+ if (clk_set_parent(clk, parent)) {
+ pr_err("%s: Failed to set parent %s of %s\n",
+ __func__, __clk_get_name(parent),
+ __clk_get_name(clk));
+ WARN_ON(1);
+ }
+ }
+
+ if (tbl->rate)
+ if (clk_set_rate(clk, tbl->rate)) {
+ pr_err("%s: Failed to set rate %lu of %s\n",
+ __func__, tbl->rate,
+ __clk_get_name(clk));
+ WARN_ON(1);
+ }
+
+ if (tbl->state)
+ if (clk_prepare_enable(clk)) {
+ pr_err("%s: Failed to enable %s\n", __func__,
+ __clk_get_name(clk));
+ WARN_ON(1);
+ }
+ }
+}
+
+static const struct of_device_id tegra_dt_clk_match[] = {
+ { .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init },
+ { .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init },
+ { }
+};
+
+void __init tegra_clocks_init(void)
+{
+ of_clk_init(tegra_dt_clk_match);
+}
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
new file mode 100644
index 000000000000..0744731c6229
--- /dev/null
+++ b/drivers/clk/tegra/clk.h
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TEGRA_CLK_H
+#define __TEGRA_CLK_H
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+/**
+ * struct tegra_clk_sync_source - external clock source from codec
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @rate: input frequency from source
+ * @max_rate: max rate allowed
+ */
+struct tegra_clk_sync_source {
+ struct clk_hw hw;
+ unsigned long rate;
+ unsigned long max_rate;
+};
+
+#define to_clk_sync_source(_hw) \
+ container_of(_hw, struct tegra_clk_sync_source, hw)
+
+extern const struct clk_ops tegra_clk_sync_source_ops;
+struct clk *tegra_clk_register_sync_source(const char *name,
+ unsigned long fixed_rate, unsigned long max_rate);
+
+/**
+ * struct tegra_clk_frac_div - fractional divider clock
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @reg: register containing divider
+ * @flags: hardware-specific flags
+ * @shift: shift to the divider bit field
+ * @width: width of the divider bit field
+ * @frac_width: width of the fractional bit field
+ * @lock: register lock
+ *
+ * Flags:
+ * TEGRA_DIVIDER_ROUND_UP - This flags indicates to round up the divider value.
+ * TEGRA_DIVIDER_FIXED - Fixed rate PLL dividers has addition override bit, this
+ * flag indicates that this divider is for fixed rate PLL.
+ * TEGRA_DIVIDER_INT - Some modules can not cope with the duty cycle when
+ * fraction bit is set. This flags indicates to calculate divider for which
+ * fracton bit will be zero.
+ * TEGRA_DIVIDER_UART - UART module divider has additional enable bit which is
+ * set when divider value is not 0. This flags indicates that the divider
+ * is for UART module.
+ */
+struct tegra_clk_frac_div {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u8 flags;
+ u8 shift;
+ u8 width;
+ u8 frac_width;
+ spinlock_t *lock;
+};
+
+#define to_clk_frac_div(_hw) container_of(_hw, struct tegra_clk_frac_div, hw)
+
+#define TEGRA_DIVIDER_ROUND_UP BIT(0)
+#define TEGRA_DIVIDER_FIXED BIT(1)
+#define TEGRA_DIVIDER_INT BIT(2)
+#define TEGRA_DIVIDER_UART BIT(3)
+
+extern const struct clk_ops tegra_clk_frac_div_ops;
+struct clk *tegra_clk_register_divider(const char *name,
+ const char *parent_name, void __iomem *reg,
+ unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width,
+ u8 frac_width, spinlock_t *lock);
+
+/*
+ * Tegra PLL:
+ *
+ * In general, there are 3 requirements for each PLL
+ * that SW needs to be comply with.
+ * (1) Input frequency range (REF).
+ * (2) Comparison frequency range (CF). CF = REF/DIVM.
+ * (3) VCO frequency range (VCO). VCO = CF * DIVN.
+ *
+ * The final PLL output frequency (FO) = VCO >> DIVP.
+ */
+
+/**
+ * struct tegra_clk_pll_freq_table - PLL frequecy table
+ *
+ * @input_rate: input rate from source
+ * @output_rate: output rate from PLL for the input rate
+ * @n: feedback divider
+ * @m: input divider
+ * @p: post divider
+ * @cpcon: charge pump current
+ */
+struct tegra_clk_pll_freq_table {
+ unsigned long input_rate;
+ unsigned long output_rate;
+ u16 n;
+ u16 m;
+ u8 p;
+ u8 cpcon;
+};
+
+/**
+ * struct clk_pll_params - PLL parameters
+ *
+ * @input_min: Minimum input frequency
+ * @input_max: Maximum input frequency
+ * @cf_min: Minimum comparison frequency
+ * @cf_max: Maximum comparison frequency
+ * @vco_min: Minimum VCO frequency
+ * @vco_max: Maximum VCO frequency
+ * @base_reg: PLL base reg offset
+ * @misc_reg: PLL misc reg offset
+ * @lock_reg: PLL lock reg offset
+ * @lock_bit_idx: Bit index for PLL lock status
+ * @lock_enable_bit_idx: Bit index to enable PLL lock
+ * @lock_delay: Delay in us if PLL lock is not used
+ */
+struct tegra_clk_pll_params {
+ unsigned long input_min;
+ unsigned long input_max;
+ unsigned long cf_min;
+ unsigned long cf_max;
+ unsigned long vco_min;
+ unsigned long vco_max;
+
+ u32 base_reg;
+ u32 misc_reg;
+ u32 lock_reg;
+ u32 lock_bit_idx;
+ u32 lock_enable_bit_idx;
+ int lock_delay;
+};
+
+/**
+ * struct tegra_clk_pll - Tegra PLL clock
+ *
+ * @hw: handle between common and hardware-specifix interfaces
+ * @clk_base: address of CAR controller
+ * @pmc: address of PMC, required to read override bits
+ * @freq_table: array of frequencies supported by PLL
+ * @params: PLL parameters
+ * @flags: PLL flags
+ * @fixed_rate: PLL rate if it is fixed
+ * @lock: register lock
+ * @divn_shift: shift to the feedback divider bit field
+ * @divn_width: width of the feedback divider bit field
+ * @divm_shift: shift to the input divider bit field
+ * @divm_width: width of the input divider bit field
+ * @divp_shift: shift to the post divider bit field
+ * @divp_width: width of the post divider bit field
+ *
+ * Flags:
+ * TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
+ * PLL locking. If not set it will use lock_delay value to wait.
+ * TEGRA_PLL_HAS_CPCON - This flag indicates that CPCON value needs
+ * to be programmed to change output frequency of the PLL.
+ * TEGRA_PLL_SET_LFCON - This flag indicates that LFCON value needs
+ * to be programmed to change output frequency of the PLL.
+ * TEGRA_PLL_SET_DCCON - This flag indicates that DCCON value needs
+ * to be programmed to change output frequency of the PLL.
+ * TEGRA_PLLU - PLLU has inverted post divider. This flags indicated
+ * that it is PLLU and invert post divider value.
+ * TEGRA_PLLM - PLLM has additional override settings in PMC. This
+ * flag indicates that it is PLLM and use override settings.
+ * TEGRA_PLL_FIXED - We are not supposed to change output frequency
+ * of some plls.
+ * TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling.
+ */
+struct tegra_clk_pll {
+ struct clk_hw hw;
+ void __iomem *clk_base;
+ void __iomem *pmc;
+ u8 flags;
+ unsigned long fixed_rate;
+ spinlock_t *lock;
+ u8 divn_shift;
+ u8 divn_width;
+ u8 divm_shift;
+ u8 divm_width;
+ u8 divp_shift;
+ u8 divp_width;
+ struct tegra_clk_pll_freq_table *freq_table;
+ struct tegra_clk_pll_params *params;
+};
+
+#define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
+
+#define TEGRA_PLL_USE_LOCK BIT(0)
+#define TEGRA_PLL_HAS_CPCON BIT(1)
+#define TEGRA_PLL_SET_LFCON BIT(2)
+#define TEGRA_PLL_SET_DCCON BIT(3)
+#define TEGRA_PLLU BIT(4)
+#define TEGRA_PLLM BIT(5)
+#define TEGRA_PLL_FIXED BIT(6)
+#define TEGRA_PLLE_CONFIGURE BIT(7)
+
+extern const struct clk_ops tegra_clk_pll_ops;
+extern const struct clk_ops tegra_clk_plle_ops;
+struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params, u8 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock);
+struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params, u8 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock);
+
+/**
+ * struct tegra_clk_pll_out - PLL divider down clock
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @reg: register containing the PLL divider
+ * @enb_bit_idx: bit to enable/disable PLL divider
+ * @rst_bit_idx: bit to reset PLL divider
+ * @lock: register lock
+ * @flags: hardware-specific flags
+ */
+struct tegra_clk_pll_out {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u8 enb_bit_idx;
+ u8 rst_bit_idx;
+ spinlock_t *lock;
+ u8 flags;
+};
+
+#define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw)
+
+extern const struct clk_ops tegra_clk_pll_out_ops;
+struct clk *tegra_clk_register_pll_out(const char *name,
+ const char *parent_name, void __iomem *reg, u8 enb_bit_idx,
+ u8 rst_bit_idx, unsigned long flags, u8 pll_div_flags,
+ spinlock_t *lock);
+
+/**
+ * struct tegra_clk_periph_regs - Registers controlling peripheral clock
+ *
+ * @enb_reg: read the enable status
+ * @enb_set_reg: write 1 to enable clock
+ * @enb_clr_reg: write 1 to disable clock
+ * @rst_reg: read the reset status
+ * @rst_set_reg: write 1 to assert the reset of peripheral
+ * @rst_clr_reg: write 1 to deassert the reset of peripheral
+ */
+struct tegra_clk_periph_regs {
+ u32 enb_reg;
+ u32 enb_set_reg;
+ u32 enb_clr_reg;
+ u32 rst_reg;
+ u32 rst_set_reg;
+ u32 rst_clr_reg;
+};
+
+/**
+ * struct tegra_clk_periph_gate - peripheral gate clock
+ *
+ * @magic: magic number to validate type
+ * @hw: handle between common and hardware-specific interfaces
+ * @clk_base: address of CAR controller
+ * @regs: Registers to control the peripheral
+ * @flags: hardware-specific flags
+ * @clk_num: Clock number
+ * @enable_refcnt: array to maintain reference count of the clock
+ *
+ * Flags:
+ * TEGRA_PERIPH_NO_RESET - This flag indicates that reset is not allowed
+ * for this module.
+ * TEGRA_PERIPH_MANUAL_RESET - This flag indicates not to reset module
+ * after clock enable and driver for the module is responsible for
+ * doing reset.
+ * TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the
+ * bus to flush the write operation in apb bus. This flag indicates
+ * that this peripheral is in apb bus.
+ */
+struct tegra_clk_periph_gate {
+ u32 magic;
+ struct clk_hw hw;
+ void __iomem *clk_base;
+ u8 flags;
+ int clk_num;
+ int *enable_refcnt;
+ struct tegra_clk_periph_regs *regs;
+};
+
+#define to_clk_periph_gate(_hw) \
+ container_of(_hw, struct tegra_clk_periph_gate, hw)
+
+#define TEGRA_CLK_PERIPH_GATE_MAGIC 0x17760309
+
+#define TEGRA_PERIPH_NO_RESET BIT(0)
+#define TEGRA_PERIPH_MANUAL_RESET BIT(1)
+#define TEGRA_PERIPH_ON_APB BIT(2)
+
+void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert);
+extern const struct clk_ops tegra_clk_periph_gate_ops;
+struct clk *tegra_clk_register_periph_gate(const char *name,
+ const char *parent_name, u8 gate_flags, void __iomem *clk_base,
+ unsigned long flags, int clk_num,
+ struct tegra_clk_periph_regs *pregs, int *enable_refcnt);
+
+/**
+ * struct clk-periph - peripheral clock
+ *
+ * @magic: magic number to validate type
+ * @hw: handle between common and hardware-specific interfaces
+ * @mux: mux clock
+ * @divider: divider clock
+ * @gate: gate clock
+ * @mux_ops: mux clock ops
+ * @div_ops: divider clock ops
+ * @gate_ops: gate clock ops
+ */
+struct tegra_clk_periph {
+ u32 magic;
+ struct clk_hw hw;
+ struct clk_mux mux;
+ struct tegra_clk_frac_div divider;
+ struct tegra_clk_periph_gate gate;
+
+ const struct clk_ops *mux_ops;
+ const struct clk_ops *div_ops;
+ const struct clk_ops *gate_ops;
+};
+
+#define to_clk_periph(_hw) container_of(_hw, struct tegra_clk_periph, hw)
+
+#define TEGRA_CLK_PERIPH_MAGIC 0x18221223
+
+extern const struct clk_ops tegra_clk_periph_ops;
+struct clk *tegra_clk_register_periph(const char *name,
+ const char **parent_names, int num_parents,
+ struct tegra_clk_periph *periph, void __iomem *clk_base,
+ u32 offset);
+struct clk *tegra_clk_register_periph_nodiv(const char *name,
+ const char **parent_names, int num_parents,
+ struct tegra_clk_periph *periph, void __iomem *clk_base,
+ u32 offset);
+
+#define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags, \
+ _div_shift, _div_width, _div_frac_width, \
+ _div_flags, _clk_num, _enb_refcnt, _regs, \
+ _gate_flags) \
+ { \
+ .mux = { \
+ .flags = _mux_flags, \
+ .shift = _mux_shift, \
+ .width = _mux_width, \
+ }, \
+ .divider = { \
+ .flags = _div_flags, \
+ .shift = _div_shift, \
+ .width = _div_width, \
+ .frac_width = _div_frac_width, \
+ }, \
+ .gate = { \
+ .flags = _gate_flags, \
+ .clk_num = _clk_num, \
+ .enable_refcnt = _enb_refcnt, \
+ .regs = _regs, \
+ }, \
+ .mux_ops = &clk_mux_ops, \
+ .div_ops = &tegra_clk_frac_div_ops, \
+ .gate_ops = &tegra_clk_periph_gate_ops, \
+ }
+
+struct tegra_periph_init_data {
+ const char *name;
+ int clk_id;
+ const char **parent_names;
+ int num_parents;
+ struct tegra_clk_periph periph;
+ u32 offset;
+ const char *con_id;
+ const char *dev_id;
+};
+
+#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \
+ _mux_shift, _mux_width, _mux_flags, _div_shift, \
+ _div_width, _div_frac_width, _div_flags, _regs, \
+ _clk_num, _enb_refcnt, _gate_flags, _clk_id) \
+ { \
+ .name = _name, \
+ .clk_id = _clk_id, \
+ .parent_names = _parent_names, \
+ .num_parents = ARRAY_SIZE(_parent_names), \
+ .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \
+ _mux_flags, _div_shift, \
+ _div_width, _div_frac_width, \
+ _div_flags, _clk_num, \
+ _enb_refcnt, _regs, \
+ _gate_flags), \
+ .offset = _offset, \
+ .con_id = _con_id, \
+ .dev_id = _dev_id, \
+ }
+
+/**
+ * struct clk_super_mux - super clock
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @reg: register controlling multiplexer
+ * @width: width of the multiplexer bit field
+ * @flags: hardware-specific flags
+ * @div2_index: bit controlling divide-by-2
+ * @pllx_index: PLLX index in the parent list
+ * @lock: register lock
+ *
+ * Flags:
+ * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
+ * that this is LP cluster clock.
+ */
+struct tegra_clk_super_mux {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u8 width;
+ u8 flags;
+ u8 div2_index;
+ u8 pllx_index;
+ spinlock_t *lock;
+};
+
+#define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
+
+#define TEGRA_DIVIDER_2 BIT(0)
+
+extern const struct clk_ops tegra_clk_super_ops;
+struct clk *tegra_clk_register_super_mux(const char *name,
+ const char **parent_names, u8 num_parents,
+ unsigned long flags, void __iomem *reg, u8 clk_super_flags,
+ u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock);
+
+/**
+ * struct clk_init_tabel - clock initialization table
+ * @clk_id: clock id as mentioned in device tree bindings
+ * @parent_id: parent clock id as mentioned in device tree bindings
+ * @rate: rate to set
+ * @state: enable/disable
+ */
+struct tegra_clk_init_table {
+ unsigned int clk_id;
+ unsigned int parent_id;
+ unsigned long rate;
+ int state;
+};
+
+/**
+ * struct clk_duplicate - duplicate clocks
+ * @clk_id: clock id as mentioned in device tree bindings
+ * @lookup: duplicate lookup entry for the clock
+ */
+struct tegra_clk_duplicate {
+ int clk_id;
+ struct clk_lookup lookup;
+};
+
+#define TEGRA_CLK_DUPLICATE(_clk_id, _dev, _con) \
+ { \
+ .clk_id = _clk_id, \
+ .lookup = { \
+ .dev_id = _dev, \
+ .con_id = _con, \
+ }, \
+ }
+
+void tegra_init_from_table(struct tegra_clk_init_table *tbl,
+ struct clk *clks[], int clk_max);
+
+void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
+ struct clk *clks[], int clk_max);
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+void tegra20_clock_init(struct device_node *np);
+#else
+static inline void tegra20_clock_init(struct device_node *np) {}
+#endif /* CONFIG_ARCH_TEGRA_2x_SOC */
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+void tegra30_clock_init(struct device_node *np);
+#else
+static inline void tegra30_clock_init(struct device_node *np) {}
+#endif /* CONFIG_ARCH_TEGRA_3x_SOC */
+
+#endif /* TEGRA_CLK_H */
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
index dcb6ae0a0425..256c8be74df8 100644
--- a/drivers/clk/versatile/clk-vexpress-osc.c
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -144,3 +144,4 @@ error:
vexpress_config_func_put(osc->func);
kfree(osc);
}
+CLK_OF_DECLARE(vexpress_soc, "arm,vexpress-osc", vexpress_osc_of_setup);
diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c
index c742ac7c60bb..82b45aad8ccf 100644
--- a/drivers/clk/versatile/clk-vexpress.c
+++ b/drivers/clk/versatile/clk-vexpress.c
@@ -11,6 +11,7 @@
* Copyright (C) 2012 ARM Limited
*/
+#include <linux/amba/sp810.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
@@ -18,8 +19,6 @@
#include <linux/of_address.h>
#include <linux/vexpress.h>
-#include <asm/hardware/sp810.h>
-
static struct clk *vexpress_sp810_timerclken[4];
static DEFINE_SPINLOCK(vexpress_sp810_lock);
@@ -99,19 +98,13 @@ struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data)
return vexpress_sp810_timerclken[clkspec->args[0]];
}
-static const __initconst struct of_device_id vexpress_fixed_clk_match[] = {
- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
- { .compatible = "arm,vexpress-osc", .data = vexpress_osc_of_setup, },
- {}
-};
-
void __init vexpress_clk_of_init(void)
{
struct device_node *node;
struct clk *clk;
struct clk *refclk, *timclk;
- of_clk_init(vexpress_fixed_clk_match);
+ of_clk_init(NULL);
node = of_find_compatible_node(NULL, NULL, "arm,sp810");
vexpress_sp810_init(of_iomap(node, 0));
diff --git a/drivers/clk/x86/Makefile b/drivers/clk/x86/Makefile
new file mode 100644
index 000000000000..f9ba4fab0ddc
--- /dev/null
+++ b/drivers/clk/x86/Makefile
@@ -0,0 +1,2 @@
+clk-x86-lpss-objs := clk-lpss.o clk-lpt.o
+obj-$(CONFIG_X86_INTEL_LPSS) += clk-x86-lpss.o
diff --git a/drivers/clk/x86/clk-lpss.c b/drivers/clk/x86/clk-lpss.c
new file mode 100644
index 000000000000..b5e229f3c3d9
--- /dev/null
+++ b/drivers/clk/x86/clk-lpss.c
@@ -0,0 +1,99 @@
+/*
+ * Intel Low Power Subsystem clocks.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ * Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+static int clk_lpss_is_mmio_resource(struct acpi_resource *res, void *data)
+{
+ struct resource r;
+ return !acpi_dev_resource_memory(res, &r);
+}
+
+static acpi_status clk_lpss_find_mmio(acpi_handle handle, u32 level,
+ void *data, void **retval)
+{
+ struct resource_list_entry *rentry;
+ struct list_head resource_list;
+ struct acpi_device *adev;
+ const char *uid = data;
+ int ret;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+
+ if (uid) {
+ if (!adev->pnp.unique_id)
+ return AE_OK;
+ if (strcmp(uid, adev->pnp.unique_id))
+ return AE_OK;
+ }
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ clk_lpss_is_mmio_resource, NULL);
+ if (ret < 0)
+ return AE_NO_MEMORY;
+
+ list_for_each_entry(rentry, &resource_list, node)
+ if (resource_type(&rentry->res) == IORESOURCE_MEM) {
+ *(struct resource *)retval = rentry->res;
+ break;
+ }
+
+ acpi_dev_free_resource_list(&resource_list);
+ return AE_OK;
+}
+
+/**
+ * clk_register_lpss_gate - register LPSS clock gate
+ * @name: name of this clock gate
+ * @parent_name: parent clock name
+ * @hid: ACPI _HID of the device
+ * @uid: ACPI _UID of the device (optional)
+ * @offset: LPSS PRV_CLOCK_PARAMS offset
+ *
+ * Creates and registers LPSS clock gate.
+ */
+struct clk *clk_register_lpss_gate(const char *name, const char *parent_name,
+ const char *hid, const char *uid,
+ unsigned offset)
+{
+ struct resource res = { };
+ void __iomem *mmio_base;
+ acpi_status status;
+ struct clk *clk;
+
+ /*
+ * First try to look the device and its mmio resource from the
+ * ACPI namespace.
+ */
+ status = acpi_get_devices(hid, clk_lpss_find_mmio, (void *)uid,
+ (void **)&res);
+ if (ACPI_FAILURE(status) || !res.start)
+ return ERR_PTR(-ENODEV);
+
+ mmio_base = ioremap(res.start, resource_size(&res));
+ if (!mmio_base)
+ return ERR_PTR(-ENOMEM);
+
+ clk = clk_register_gate(NULL, name, parent_name, 0, mmio_base + offset,
+ 0, 0, NULL);
+ if (IS_ERR(clk))
+ iounmap(mmio_base);
+
+ return clk;
+}
diff --git a/drivers/clk/x86/clk-lpss.h b/drivers/clk/x86/clk-lpss.h
new file mode 100644
index 000000000000..e9460f442297
--- /dev/null
+++ b/drivers/clk/x86/clk-lpss.h
@@ -0,0 +1,36 @@
+/*
+ * Intel Low Power Subsystem clock.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ * Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CLK_LPSS_H
+#define __CLK_LPSS_H
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+
+#ifdef CONFIG_ACPI
+extern struct clk *clk_register_lpss_gate(const char *name,
+ const char *parent_name,
+ const char *hid, const char *uid,
+ unsigned offset);
+#else
+static inline struct clk *clk_register_lpss_gate(const char *name,
+ const char *parent_name,
+ const char *hid,
+ const char *uid,
+ unsigned offset)
+{
+ return ERR_PTR(-ENODEV);
+}
+#endif
+
+#endif /* __CLK_LPSS_H */
diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c
new file mode 100644
index 000000000000..81298aeef7e3
--- /dev/null
+++ b/drivers/clk/x86/clk-lpt.c
@@ -0,0 +1,86 @@
+/*
+ * Intel Lynxpoint LPSS clocks.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ * Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "clk-lpss.h"
+
+#define PRV_CLOCK_PARAMS 0x800
+
+static int lpt_clk_probe(struct platform_device *pdev)
+{
+ struct clk *clk;
+
+ /* LPSS free running clock */
+ clk = clk_register_fixed_rate(&pdev->dev, "lpss_clk", NULL, CLK_IS_ROOT,
+ 100000000);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ /* Shared DMA clock */
+ clk_register_clkdev(clk, "hclk", "INTL9C60.0.auto");
+
+ /* SPI clocks */
+ clk = clk_register_lpss_gate("spi0_clk", "lpss_clk", "INT33C0", NULL,
+ PRV_CLOCK_PARAMS);
+ if (!IS_ERR(clk))
+ clk_register_clkdev(clk, NULL, "INT33C0:00");
+
+ clk = clk_register_lpss_gate("spi1_clk", "lpss_clk", "INT33C1", NULL,
+ PRV_CLOCK_PARAMS);
+ if (!IS_ERR(clk))
+ clk_register_clkdev(clk, NULL, "INT33C1:00");
+
+ /* I2C clocks */
+ clk = clk_register_lpss_gate("i2c0_clk", "lpss_clk", "INT33C2", NULL,
+ PRV_CLOCK_PARAMS);
+ if (!IS_ERR(clk))
+ clk_register_clkdev(clk, NULL, "INT33C2:00");
+
+ clk = clk_register_lpss_gate("i2c1_clk", "lpss_clk", "INT33C3", NULL,
+ PRV_CLOCK_PARAMS);
+ if (!IS_ERR(clk))
+ clk_register_clkdev(clk, NULL, "INT33C3:00");
+
+ /* UART clocks */
+ clk = clk_register_lpss_gate("uart0_clk", "lpss_clk", "INT33C4", NULL,
+ PRV_CLOCK_PARAMS);
+ if (!IS_ERR(clk))
+ clk_register_clkdev(clk, NULL, "INT33C4:00");
+
+ clk = clk_register_lpss_gate("uart1_clk", "lpss_clk", "INT33C5", NULL,
+ PRV_CLOCK_PARAMS);
+ if (!IS_ERR(clk))
+ clk_register_clkdev(clk, NULL, "INT33C5:00");
+
+ return 0;
+}
+
+static struct platform_driver lpt_clk_driver = {
+ .driver = {
+ .name = "clk-lpt",
+ .owner = THIS_MODULE,
+ },
+ .probe = lpt_clk_probe,
+};
+
+static int __init lpt_clk_init(void)
+{
+ return platform_driver_register(&lpt_clk_driver);
+}
+arch_initcall(lpt_clk_init);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 7fdcbd3f4da5..e920cbe519fa 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -1,3 +1,6 @@
+config CLKSRC_OF
+ bool
+
config CLKSRC_I8253
bool
@@ -25,6 +28,9 @@ config ARMADA_370_XP_TIMER
config SUNXI_TIMER
bool
+config VT8500_TIMER
+ bool
+
config CLKSRC_NOMADIK_MTU
bool
depends on (ARCH_NOMADIK || ARCH_U8500)
@@ -54,7 +60,5 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK
help
Use the always on PRCMU Timer as sched_clock
-config CLKSRC_ARM_GENERIC
- def_bool y if ARM64
- help
- This option enables support for the ARM generic timer.
+config ARM_ARCH_TIMER
+ bool
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index f93453d01673..7d671b85a98e 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o
obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
@@ -16,5 +17,7 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o
+obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
+obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
-obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o
+obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
new file mode 100644
index 000000000000..d7ad425ab9b3
--- /dev/null
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -0,0 +1,391 @@
+/*
+ * linux/drivers/clocksource/arm_arch_timer.c
+ *
+ * Copyright (C) 2011 ARM Ltd.
+ * 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>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+
+#include <asm/arch_timer.h>
+#include <asm/virt.h>
+
+#include <clocksource/arm_arch_timer.h>
+
+static u32 arch_timer_rate;
+
+enum ppi_nr {
+ PHYS_SECURE_PPI,
+ PHYS_NONSECURE_PPI,
+ VIRT_PPI,
+ HYP_PPI,
+ MAX_TIMER_PPI
+};
+
+static int arch_timer_ppi[MAX_TIMER_PPI];
+
+static struct clock_event_device __percpu *arch_timer_evt;
+
+static bool arch_timer_use_virtual = true;
+
+/*
+ * Architected system timer support.
+ */
+
+static inline irqreturn_t timer_handler(const int access,
+ struct clock_event_device *evt)
+{
+ unsigned long ctrl;
+ ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+ if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
+ ctrl |= ARCH_TIMER_CTRL_IT_MASK;
+ arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static irqreturn_t arch_timer_handler_virt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ return timer_handler(ARCH_TIMER_VIRT_ACCESS, evt);
+}
+
+static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt);
+}
+
+static inline void timer_set_mode(const int access, int mode)
+{
+ unsigned long ctrl;
+ switch (mode) {
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+ ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
+ arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+ break;
+ default:
+ break;
+ }
+}
+
+static void arch_timer_set_mode_virt(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+ timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode);
+}
+
+static void arch_timer_set_mode_phys(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+ timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode);
+}
+
+static inline void set_next_event(const int access, unsigned long evt)
+{
+ unsigned long ctrl;
+ ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+ ctrl |= ARCH_TIMER_CTRL_ENABLE;
+ ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
+ arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt);
+ arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+}
+
+static int arch_timer_set_next_event_virt(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ set_next_event(ARCH_TIMER_VIRT_ACCESS, evt);
+ return 0;
+}
+
+static int arch_timer_set_next_event_phys(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ set_next_event(ARCH_TIMER_PHYS_ACCESS, evt);
+ return 0;
+}
+
+static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
+{
+ clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
+ clk->name = "arch_sys_timer";
+ clk->rating = 450;
+ if (arch_timer_use_virtual) {
+ clk->irq = arch_timer_ppi[VIRT_PPI];
+ clk->set_mode = arch_timer_set_mode_virt;
+ clk->set_next_event = arch_timer_set_next_event_virt;
+ } else {
+ clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
+ clk->set_mode = arch_timer_set_mode_phys;
+ clk->set_next_event = arch_timer_set_next_event_phys;
+ }
+
+ clk->cpumask = cpumask_of(smp_processor_id());
+
+ clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL);
+
+ clockevents_config_and_register(clk, arch_timer_rate,
+ 0xf, 0x7fffffff);
+
+ if (arch_timer_use_virtual)
+ enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0);
+ else {
+ enable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], 0);
+ if (arch_timer_ppi[PHYS_NONSECURE_PPI])
+ enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0);
+ }
+
+ arch_counter_set_user_access();
+
+ return 0;
+}
+
+static int arch_timer_available(void)
+{
+ u32 freq;
+
+ if (arch_timer_rate == 0) {
+ freq = arch_timer_get_cntfrq();
+
+ /* Check the timer frequency. */
+ if (freq == 0) {
+ pr_warn("Architected timer frequency not available\n");
+ return -EINVAL;
+ }
+
+ arch_timer_rate = freq;
+ }
+
+ pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n",
+ (unsigned long)arch_timer_rate / 1000000,
+ (unsigned long)(arch_timer_rate / 10000) % 100,
+ arch_timer_use_virtual ? "virt" : "phys");
+ return 0;
+}
+
+u32 arch_timer_get_rate(void)
+{
+ return arch_timer_rate;
+}
+
+/*
+ * Some external users of arch_timer_read_counter (e.g. sched_clock) may try to
+ * call it before it has been initialised. Rather than incur a performance
+ * penalty checking for initialisation, provide a default implementation that
+ * won't lead to time appearing to jump backwards.
+ */
+static u64 arch_timer_read_zero(void)
+{
+ return 0;
+}
+
+u64 (*arch_timer_read_counter)(void) = arch_timer_read_zero;
+
+static cycle_t arch_counter_read(struct clocksource *cs)
+{
+ return arch_timer_read_counter();
+}
+
+static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
+{
+ return arch_timer_read_counter();
+}
+
+static struct clocksource clocksource_counter = {
+ .name = "arch_sys_counter",
+ .rating = 400,
+ .read = arch_counter_read,
+ .mask = CLOCKSOURCE_MASK(56),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static struct cyclecounter cyclecounter = {
+ .read = arch_counter_read_cc,
+ .mask = CLOCKSOURCE_MASK(56),
+};
+
+static struct timecounter timecounter;
+
+struct timecounter *arch_timer_get_timecounter(void)
+{
+ return &timecounter;
+}
+
+static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
+{
+ pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
+ clk->irq, smp_processor_id());
+
+ if (arch_timer_use_virtual)
+ disable_percpu_irq(arch_timer_ppi[VIRT_PPI]);
+ else {
+ disable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI]);
+ if (arch_timer_ppi[PHYS_NONSECURE_PPI])
+ disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
+ }
+
+ clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+}
+
+static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ struct clock_event_device *evt = this_cpu_ptr(arch_timer_evt);
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ arch_timer_setup(evt);
+ break;
+ case CPU_DYING:
+ arch_timer_stop(evt);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block arch_timer_cpu_nb __cpuinitdata = {
+ .notifier_call = arch_timer_cpu_notify,
+};
+
+static int __init arch_timer_register(void)
+{
+ int err;
+ int ppi;
+
+ err = arch_timer_available();
+ if (err)
+ goto out;
+
+ arch_timer_evt = alloc_percpu(struct clock_event_device);
+ if (!arch_timer_evt) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ clocksource_register_hz(&clocksource_counter, arch_timer_rate);
+ cyclecounter.mult = clocksource_counter.mult;
+ cyclecounter.shift = clocksource_counter.shift;
+ timecounter_init(&timecounter, &cyclecounter,
+ arch_counter_get_cntpct());
+
+ if (arch_timer_use_virtual) {
+ ppi = arch_timer_ppi[VIRT_PPI];
+ err = request_percpu_irq(ppi, arch_timer_handler_virt,
+ "arch_timer", arch_timer_evt);
+ } else {
+ ppi = arch_timer_ppi[PHYS_SECURE_PPI];
+ err = request_percpu_irq(ppi, arch_timer_handler_phys,
+ "arch_timer", arch_timer_evt);
+ if (!err && arch_timer_ppi[PHYS_NONSECURE_PPI]) {
+ ppi = arch_timer_ppi[PHYS_NONSECURE_PPI];
+ err = request_percpu_irq(ppi, arch_timer_handler_phys,
+ "arch_timer", arch_timer_evt);
+ if (err)
+ free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
+ arch_timer_evt);
+ }
+ }
+
+ if (err) {
+ pr_err("arch_timer: can't register interrupt %d (%d)\n",
+ ppi, err);
+ goto out_free;
+ }
+
+ err = register_cpu_notifier(&arch_timer_cpu_nb);
+ if (err)
+ goto out_free_irq;
+
+ /* Immediately configure the timer on the boot CPU */
+ arch_timer_setup(this_cpu_ptr(arch_timer_evt));
+
+ return 0;
+
+out_free_irq:
+ if (arch_timer_use_virtual)
+ free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt);
+ else {
+ free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI],
+ arch_timer_evt);
+ if (arch_timer_ppi[PHYS_NONSECURE_PPI])
+ free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],
+ arch_timer_evt);
+ }
+
+out_free:
+ free_percpu(arch_timer_evt);
+out:
+ return err;
+}
+
+static const struct of_device_id arch_timer_of_match[] __initconst = {
+ { .compatible = "arm,armv7-timer", },
+ { .compatible = "arm,armv8-timer", },
+ {},
+};
+
+int __init arch_timer_init(void)
+{
+ struct device_node *np;
+ u32 freq;
+ int i;
+
+ np = of_find_matching_node(NULL, arch_timer_of_match);
+ if (!np) {
+ pr_err("arch_timer: can't find DT node\n");
+ return -ENODEV;
+ }
+
+ /* Try to determine the frequency from the device tree or CNTFRQ */
+ if (!of_property_read_u32(np, "clock-frequency", &freq))
+ arch_timer_rate = freq;
+
+ for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
+ arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+
+ of_node_put(np);
+
+ /*
+ * If HYP mode is available, we know that the physical timer
+ * has been configured to be accessible from PL1. Use it, so
+ * that a guest can use the virtual timer instead.
+ *
+ * If no interrupt provided for virtual timer, we'll have to
+ * stick to the physical timer. It'd better be accessible...
+ */
+ if (is_hyp_mode_available() || !arch_timer_ppi[VIRT_PPI]) {
+ arch_timer_use_virtual = false;
+
+ if (!arch_timer_ppi[PHYS_SECURE_PPI] ||
+ !arch_timer_ppi[PHYS_NONSECURE_PPI]) {
+ pr_warn("arch_timer: No interrupt available, giving up\n");
+ return -EINVAL;
+ }
+ }
+
+ if (arch_timer_use_virtual)
+ arch_timer_read_counter = arch_counter_get_cntvct;
+ else
+ arch_timer_read_counter = arch_counter_get_cntpct;
+
+ return arch_timer_register();
+}
diff --git a/drivers/clocksource/arm_generic.c b/drivers/clocksource/arm_generic.c
deleted file mode 100644
index 8ae1a61523ff..000000000000
--- a/drivers/clocksource/arm_generic.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Generic timers support
- *
- * Copyright (C) 2012 ARM Ltd.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/smp.h>
-#include <linux/cpu.h>
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/clockchips.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
-
-#include <clocksource/arm_generic.h>
-
-#include <asm/arm_generic.h>
-
-static u32 arch_timer_rate;
-static u64 sched_clock_mult __read_mostly;
-static DEFINE_PER_CPU(struct clock_event_device, arch_timer_evt);
-static int arch_timer_ppi;
-
-static irqreturn_t arch_timer_handle_irq(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
- unsigned long ctrl;
-
- ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
- if (ctrl & ARCH_TIMER_CTRL_ISTATUS) {
- ctrl |= ARCH_TIMER_CTRL_IMASK;
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
- evt->event_handler(evt);
- return IRQ_HANDLED;
- }
-
- return IRQ_NONE;
-}
-
-static void arch_timer_stop(void)
-{
- unsigned long ctrl;
-
- ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
- ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
-}
-
-static void arch_timer_set_mode(enum clock_event_mode mode,
- struct clock_event_device *clk)
-{
- switch (mode) {
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- arch_timer_stop();
- break;
- default:
- break;
- }
-}
-
-static int arch_timer_set_next_event(unsigned long evt,
- struct clock_event_device *unused)
-{
- unsigned long ctrl;
-
- ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
- ctrl |= ARCH_TIMER_CTRL_ENABLE;
- ctrl &= ~ARCH_TIMER_CTRL_IMASK;
-
- arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt);
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
-
- return 0;
-}
-
-static void __cpuinit arch_timer_setup(struct clock_event_device *clk)
-{
- /* Let's make sure the timer is off before doing anything else */
- arch_timer_stop();
-
- clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
- clk->name = "arch_sys_timer";
- clk->rating = 400;
- clk->set_mode = arch_timer_set_mode;
- clk->set_next_event = arch_timer_set_next_event;
- clk->irq = arch_timer_ppi;
- clk->cpumask = cpumask_of(smp_processor_id());
-
- clockevents_config_and_register(clk, arch_timer_rate,
- 0xf, 0x7fffffff);
-
- enable_percpu_irq(clk->irq, 0);
-
- /* Ensure the virtual counter is visible to userspace for the vDSO. */
- arch_counter_enable_user_access();
-}
-
-static void __init arch_timer_calibrate(void)
-{
- if (arch_timer_rate == 0) {
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0);
- arch_timer_rate = arch_timer_reg_read(ARCH_TIMER_REG_FREQ);
-
- /* Check the timer frequency. */
- if (arch_timer_rate == 0)
- panic("Architected timer frequency is set to zero.\n"
- "You must set this in your .dts file\n");
- }
-
- /* Cache the sched_clock multiplier to save a divide in the hot path. */
-
- sched_clock_mult = DIV_ROUND_CLOSEST(NSEC_PER_SEC, arch_timer_rate);
-
- pr_info("Architected local timer running at %u.%02uMHz.\n",
- arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100);
-}
-
-static cycle_t arch_counter_read(struct clocksource *cs)
-{
- return arch_counter_get_cntpct();
-}
-
-static struct clocksource clocksource_counter = {
- .name = "arch_sys_counter",
- .rating = 400,
- .read = arch_counter_read,
- .mask = CLOCKSOURCE_MASK(56),
- .flags = (CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES),
-};
-
-int read_current_timer(unsigned long *timer_value)
-{
- *timer_value = arch_counter_get_cntpct();
- return 0;
-}
-
-unsigned long long notrace sched_clock(void)
-{
- return arch_counter_get_cntvct() * sched_clock_mult;
-}
-
-static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- int cpu = (long)hcpu;
- struct clock_event_device *clk = per_cpu_ptr(&arch_timer_evt, cpu);
-
- switch(action) {
- case CPU_STARTING:
- case CPU_STARTING_FROZEN:
- arch_timer_setup(clk);
- break;
-
- case CPU_DYING:
- case CPU_DYING_FROZEN:
- pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
- clk->irq, cpu);
- disable_percpu_irq(clk->irq);
- arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata arch_timer_cpu_nb = {
- .notifier_call = arch_timer_cpu_notify,
-};
-
-static const struct of_device_id arch_timer_of_match[] __initconst = {
- { .compatible = "arm,armv8-timer" },
- {},
-};
-
-int __init arm_generic_timer_init(void)
-{
- struct device_node *np;
- int err;
- u32 freq;
-
- np = of_find_matching_node(NULL, arch_timer_of_match);
- if (!np) {
- pr_err("arch_timer: can't find DT node\n");
- return -ENODEV;
- }
-
- /* Try to determine the frequency from the device tree or CNTFRQ */
- if (!of_property_read_u32(np, "clock-frequency", &freq))
- arch_timer_rate = freq;
- arch_timer_calibrate();
-
- arch_timer_ppi = irq_of_parse_and_map(np, 0);
- pr_info("arch_timer: found %s irq %d\n", np->name, arch_timer_ppi);
-
- err = request_percpu_irq(arch_timer_ppi, arch_timer_handle_irq,
- np->name, &arch_timer_evt);
- if (err) {
- pr_err("arch_timer: can't register interrupt %d (%d)\n",
- arch_timer_ppi, err);
- return err;
- }
-
- clocksource_register_hz(&clocksource_counter, arch_timer_rate);
-
- /* Calibrate the delay loop directly */
- lpj_fine = DIV_ROUND_CLOSEST(arch_timer_rate, HZ);
-
- /* Immediately configure the timer on the boot CPU */
- arch_timer_setup(this_cpu_ptr(&arch_timer_evt));
-
- register_cpu_notifier(&arch_timer_cpu_nb);
-
- return 0;
-}
diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c
index bc19f12c20ce..50c68fef944b 100644
--- a/drivers/clocksource/bcm2835_timer.c
+++ b/drivers/clocksource/bcm2835_timer.c
@@ -16,7 +16,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/bcm2835_timer.h>
#include <linux/bitops.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
@@ -101,7 +100,7 @@ static struct of_device_id bcm2835_time_match[] __initconst = {
{}
};
-static void __init bcm2835_time_init(void)
+static void __init bcm2835_timer_init(void)
{
struct device_node *node;
void __iomem *base;
@@ -155,7 +154,5 @@ static void __init bcm2835_time_init(void)
pr_info("bcm2835: system timer (irq = %d)\n", irq);
}
-
-struct sys_timer bcm2835_timer = {
- .init = bcm2835_time_init,
-};
+CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer",
+ bcm2835_timer_init);
diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c
new file mode 100644
index 000000000000..bdabdaa8d00f
--- /dev/null
+++ b/drivers/clocksource/clksrc-of.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/of.h>
+
+extern struct of_device_id __clksrc_of_table[];
+
+static const struct of_device_id __clksrc_of_table_sentinel
+ __used __section(__clksrc_of_table_end);
+
+void __init clocksource_of_init(void)
+{
+ struct device_node *np;
+ const struct of_device_id *match;
+ void (*init_func)(void);
+
+ for_each_matching_node_and_match(np, __clksrc_of_table, &match) {
+ init_func = match->data;
+ init_func();
+ }
+}
diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c
index d9279385304d..ea210482dd20 100644
--- a/drivers/clocksource/cs5535-clockevt.c
+++ b/drivers/clocksource/cs5535-clockevt.c
@@ -100,7 +100,6 @@ static struct clock_event_device cs5535_clockevent = {
.set_mode = mfgpt_set_mode,
.set_next_event = mfgpt_next_event,
.rating = 250,
- .shift = 32
};
static irqreturn_t mfgpt_tick(int irq, void *dev_id)
@@ -169,17 +168,11 @@ static int __init cs5535_mfgpt_init(void)
cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, val);
/* Set up the clock event */
- cs5535_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC,
- cs5535_clockevent.shift);
- cs5535_clockevent.min_delta_ns = clockevent_delta2ns(0xF,
- &cs5535_clockevent);
- cs5535_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE,
- &cs5535_clockevent);
-
printk(KERN_INFO DRV_NAME
": Registering MFGPT timer as a clock event, using IRQ %d\n",
timer_irq);
- clockevents_register_device(&cs5535_clockevent);
+ clockevents_config_and_register(&cs5535_clockevent, MFGPT_HZ,
+ 0xF, 0xFFFE);
return 0;
diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
index f7dba5b79b44..ab09ed3742ee 100644
--- a/drivers/clocksource/dw_apb_timer_of.c
+++ b/drivers/clocksource/dw_apb_timer_of.c
@@ -107,7 +107,7 @@ static const struct of_device_id osctimer_ids[] __initconst = {
{},
};
-static void __init timer_init(void)
+void __init dw_apb_timer_init(void)
{
struct device_node *event_timer, *source_timer;
@@ -125,7 +125,3 @@ static void __init timer_init(void)
init_sched_clock();
}
-
-struct sys_timer dw_apb_timer = {
- .init = timer_init,
-};
diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c
index 8914c3c1c88b..435e54d55bbd 100644
--- a/drivers/clocksource/nomadik-mtu.c
+++ b/drivers/clocksource/nomadik-mtu.c
@@ -15,6 +15,7 @@
#include <linux/clocksource.h>
#include <linux/clk.h>
#include <linux/jiffies.h>
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/platform_data/clocksource-nomadik-mtu.h>
#include <asm/mach/time.h>
@@ -64,6 +65,7 @@ static void __iomem *mtu_base;
static bool clkevt_periodic;
static u32 clk_prescale;
static u32 nmdk_cycle; /* write-once */
+static struct delay_timer mtu_delay_timer;
#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
/*
@@ -80,6 +82,11 @@ static u32 notrace nomadik_read_sched_clock(void)
}
#endif
+static unsigned long nmdk_timer_read_current_timer(void)
+{
+ return ~readl_relaxed(mtu_base + MTU_VAL(0));
+}
+
/* Clockevent device: use one-shot mode */
static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev)
{
@@ -134,12 +141,32 @@ static void nmdk_clkevt_mode(enum clock_event_mode mode,
}
}
+void nmdk_clksrc_reset(void)
+{
+ /* Disable */
+ writel(0, mtu_base + MTU_CR(0));
+
+ /* ClockSource: configure load and background-load, and fire it up */
+ writel(nmdk_cycle, mtu_base + MTU_LR(0));
+ writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
+
+ writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA,
+ mtu_base + MTU_CR(0));
+}
+
+static void nmdk_clkevt_resume(struct clock_event_device *cedev)
+{
+ nmdk_clkevt_reset();
+ nmdk_clksrc_reset();
+}
+
static struct clock_event_device nmdk_clkevt = {
.name = "mtu_1",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
.rating = 200,
.set_mode = nmdk_clkevt_mode,
.set_next_event = nmdk_clkevt_next,
+ .resume = nmdk_clkevt_resume,
};
/*
@@ -161,19 +188,6 @@ static struct irqaction nmdk_timer_irq = {
.dev_id = &nmdk_clkevt,
};
-void nmdk_clksrc_reset(void)
-{
- /* Disable */
- writel(0, mtu_base + MTU_CR(0));
-
- /* ClockSource: configure load and background-load, and fire it up */
- writel(nmdk_cycle, mtu_base + MTU_LR(0));
- writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
-
- writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA,
- mtu_base + MTU_CR(0));
-}
-
void __init nmdk_timer_init(void __iomem *base, int irq)
{
unsigned long rate;
@@ -227,4 +241,8 @@ void __init nmdk_timer_init(void __iomem *base, int irq)
setup_irq(irq, &nmdk_timer_irq);
nmdk_clkevt.cpumask = cpumask_of(0);
clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU);
+
+ mtu_delay_timer.read_current_timer = &nmdk_timer_read_current_timer;
+ mtu_delay_timer.freq = rate;
+ register_current_timer_delay(&mtu_delay_timer);
}
diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sunxi_timer.c
index 3cd1bd3d7aee..4086b9167159 100644
--- a/drivers/clocksource/sunxi_timer.c
+++ b/drivers/clocksource/sunxi_timer.c
@@ -23,7 +23,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sunxi_timer.h>
-#include <linux/clk/sunxi.h>
+#include <linux/clk-provider.h>
#define TIMER_CTL_REG 0x00
#define TIMER_CTL_ENABLE (1 << 0)
@@ -74,7 +74,6 @@ static int sunxi_clkevt_next_event(unsigned long evt,
static struct clock_event_device sunxi_clockevent = {
.name = "sunxi_tick",
- .shift = 32,
.rating = 300,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = sunxi_clkevt_mode,
@@ -104,7 +103,7 @@ static struct of_device_id sunxi_timer_dt_ids[] = {
{ }
};
-static void __init sunxi_timer_init(void)
+void __init sunxi_timer_init(void)
{
struct device_node *node;
unsigned long rate = 0;
@@ -124,7 +123,7 @@ static void __init sunxi_timer_init(void)
if (irq <= 0)
panic("Can't parse IRQ");
- sunxi_init_clocks();
+ of_clk_init(NULL);
clk = of_clk_get(node, 0);
if (IS_ERR(clk))
@@ -154,18 +153,8 @@ static void __init sunxi_timer_init(void)
val = readl(timer_base + TIMER_CTL_REG);
writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG);
- sunxi_clockevent.mult = div_sc(rate / TIMER_SCAL,
- NSEC_PER_SEC,
- sunxi_clockevent.shift);
- sunxi_clockevent.max_delta_ns = clockevent_delta2ns(0xff,
- &sunxi_clockevent);
- sunxi_clockevent.min_delta_ns = clockevent_delta2ns(0x1,
- &sunxi_clockevent);
sunxi_clockevent.cpumask = cpumask_of(0);
- clockevents_register_device(&sunxi_clockevent);
+ clockevents_config_and_register(&sunxi_clockevent, rate / TIMER_SCAL,
+ 0x1, 0xff);
}
-
-struct sys_timer sunxi_timer = {
- .init = sunxi_timer_init,
-};
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
index 32cb929b8eb6..8a6187225dd0 100644
--- a/drivers/clocksource/tcb_clksrc.c
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -157,7 +157,6 @@ static struct tc_clkevt_device clkevt = {
.name = "tc_clkevt",
.features = CLOCK_EVT_FEAT_PERIODIC
| CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
/* Should be lower than at91rm9200's system timer */
.rating = 125,
.set_next_event = tc_next_event,
@@ -196,13 +195,9 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
timer_clock = clk32k_divisor_idx;
- clkevt.clkevt.mult = div_sc(32768, NSEC_PER_SEC, clkevt.clkevt.shift);
- clkevt.clkevt.max_delta_ns
- = clockevent_delta2ns(0xffff, &clkevt.clkevt);
- clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1;
clkevt.clkevt.cpumask = cpumask_of(0);
- clockevents_register_device(&clkevt.clkevt);
+ clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff);
setup_irq(irq, &tc_irqaction);
}
diff --git a/arch/arm/mach-tegra/timer.c b/drivers/clocksource/tegra20_timer.c
index e4863f3e9ee7..0bde03feb095 100644
--- a/arch/arm/mach-tegra/timer.c
+++ b/drivers/clocksource/tegra20_timer.c
@@ -1,6 +1,4 @@
/*
- * arch/arch/mach-tegra/timer.c
- *
* Copyright (C) 2010 Google, Inc.
*
* Author:
@@ -33,8 +31,6 @@
#include <asm/smp_twd.h>
#include <asm/sched_clock.h>
-#include "board.h"
-
#define RTC_SECONDS 0x08
#define RTC_SHADOW_SECONDS 0x0c
#define RTC_MILLISECONDS 0x10
@@ -168,7 +164,7 @@ static const struct of_device_id rtc_match[] __initconst = {
{}
};
-static void __init tegra_init_timer(void)
+static void __init tegra20_init_timer(void)
{
struct device_node *np;
struct clk *clk;
@@ -183,7 +179,7 @@ static void __init tegra_init_timer(void)
timer_reg_base = of_iomap(np, 0);
if (!timer_reg_base) {
- pr_err("Can't map timer registers");
+ pr_err("Can't map timer registers\n");
BUG();
}
@@ -259,23 +255,16 @@ static void __init tegra_init_timer(void)
BUG();
}
- clockevents_calc_mult_shift(&tegra_clockevent, 1000000, 5);
- tegra_clockevent.max_delta_ns =
- clockevent_delta2ns(0x1fffffff, &tegra_clockevent);
- tegra_clockevent.min_delta_ns =
- clockevent_delta2ns(0x1, &tegra_clockevent);
tegra_clockevent.cpumask = cpu_all_mask;
tegra_clockevent.irq = tegra_timer_irq.irq;
- clockevents_register_device(&tegra_clockevent);
+ clockevents_config_and_register(&tegra_clockevent, 1000000,
+ 0x1, 0x1fffffff);
#ifdef CONFIG_HAVE_ARM_TWD
twd_local_timer_of_register();
#endif
register_persistent_clock(NULL, tegra_read_persistent_clock);
}
-
-struct sys_timer tegra_sys_timer = {
- .init = tegra_init_timer,
-};
+CLOCKSOURCE_OF_DECLARE(tegra20, "nvidia,tegra20-timer", tegra20_init_timer);
#ifdef CONFIG_PM
static u32 usec_config;
diff --git a/arch/arm/mach-vt8500/timer.c b/drivers/clocksource/vt8500_timer.c
index 3dd21a47881f..8efc86b5b5dd 100644
--- a/arch/arm/mach-vt8500/timer.c
+++ b/drivers/clocksource/vt8500_timer.c
@@ -134,7 +134,7 @@ static struct of_device_id vt8500_timer_ids[] = {
{ }
};
-void __init vt8500_timer_init(void)
+static void __init vt8500_timer_init(void)
{
struct device_node *np;
int timer_irq;
@@ -168,17 +168,13 @@ void __init vt8500_timer_init(void)
pr_err("%s: vt8500_timer_init: clocksource_register failed for %s\n",
__func__, clocksource.name);
- clockevents_calc_mult_shift(&clockevent, VT8500_TIMER_HZ, 4);
-
- /* copy-pasted from mach-msm; no idea */
- clockevent.max_delta_ns =
- clockevent_delta2ns(0xf0000000, &clockevent);
- clockevent.min_delta_ns = clockevent_delta2ns(4, &clockevent);
clockevent.cpumask = cpumask_of(0);
if (setup_irq(timer_irq, &irq))
pr_err("%s: setup_irq failed for %s\n", __func__,
clockevent.name);
- clockevents_register_device(&clockevent);
+ clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ,
+ 4, 0xf0000000);
}
+CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init)
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 7b695913cb30..f1b7e244bfc1 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -276,7 +276,7 @@ static int cn_init(void)
cn_already_initialized = 1;
- proc_net_fops_create(&init_net, "connector", S_IRUGO, &cn_file_ops);
+ proc_create("connector", S_IRUGO, init_net.proc_net, &cn_file_ops);
return 0;
}
@@ -287,7 +287,7 @@ static void cn_fini(void)
cn_already_initialized = 0;
- proc_net_remove(&init_net, "connector");
+ remove_proc_entry("connector", init_net.proc_net);
cn_queue_free_dev(dev->cbdev);
netlink_kernel_release(dev->nls);
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index e0a899f25e37..cbcb21e32771 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -185,7 +185,7 @@ config CPU_FREQ_GOV_CONSERVATIVE
If in doubt, say N.
config GENERIC_CPUFREQ_CPU0
- bool "Generic CPU0 cpufreq driver"
+ tristate "Generic CPU0 cpufreq driver"
depends on HAVE_CLK && REGULATOR && PM_OPP && OF
select CPU_FREQ_TABLE
help
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index a0b3661d90b0..030ddf6dd3f1 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -21,8 +21,8 @@ config ARM_S3C2416_CPUFREQ
If in doubt, say N.
config ARM_S3C2416_CPUFREQ_VCORESCALE
- bool "Allow voltage scaling for S3C2416 arm core (EXPERIMENTAL)"
- depends on ARM_S3C2416_CPUFREQ && REGULATOR && EXPERIMENTAL
+ bool "Allow voltage scaling for S3C2416 arm core"
+ depends on ARM_S3C2416_CPUFREQ && REGULATOR
help
Enable CPU voltage scaling when entering the dvs mode.
It uses information gathered through existing hardware and
@@ -77,9 +77,39 @@ config ARM_EXYNOS5250_CPUFREQ
This adds the CPUFreq driver for Samsung EXYNOS5250
SoC.
+config ARM_KIRKWOOD_CPUFREQ
+ def_bool ARCH_KIRKWOOD && OF
+ help
+ This adds the CPUFreq driver for Marvell Kirkwood
+ SoCs.
+
+config ARM_IMX6Q_CPUFREQ
+ tristate "Freescale i.MX6Q cpufreq support"
+ depends on SOC_IMX6Q
+ depends on REGULATOR_ANATOP
+ help
+ This adds cpufreq driver support for Freescale i.MX6Q SOC.
+
+ If in doubt, say N.
+
config ARM_SPEAR_CPUFREQ
bool "SPEAr CPUFreq support"
depends on PLAT_SPEAR
default y
help
This adds the CPUFreq driver support for SPEAr SOCs.
+
+config ARM_HIGHBANK_CPUFREQ
+ tristate "Calxeda Highbank-based"
+ depends on ARCH_HIGHBANK
+ select CPU_FREQ_TABLE
+ select GENERIC_CPUFREQ_CPU0
+ select PM_OPP
+ select REGULATOR
+
+ default m
+ help
+ This adds the CPUFreq driver for Calxeda Highbank SoC
+ based boards.
+
+ If in doubt, say N.
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index 7227cd734042..d7dc0ed6adb0 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -2,6 +2,19 @@
# x86 CPU Frequency scaling drivers
#
+config X86_INTEL_PSTATE
+ bool "Intel P state control"
+ depends on X86
+ help
+ This driver provides a P state for Intel core processors.
+ The driver implements an internal governor and will become
+ the scaling driver and governor for Sandy bridge processors.
+
+ When this driver is enabled it will become the perferred
+ scaling driver for Sandy bridge processors.
+
+ If in doubt, say N.
+
config X86_PCC_CPUFREQ
tristate "Processor Clocking Control interface driver"
depends on ACPI && ACPI_PROCESSOR
@@ -174,7 +187,7 @@ config X86_SPEEDSTEP_ICH
config X86_SPEEDSTEP_SMI
tristate "Intel SpeedStep on 440BX/ZX/MX chipsets (SMI interface)"
select CPU_FREQ_TABLE
- depends on X86_32 && EXPERIMENTAL
+ depends on X86_32
help
This adds the CPUFreq driver for certain mobile Intel Pentium III
(Coppermine), all mobile Intel Pentium III-M (Tualatin)
@@ -206,7 +219,7 @@ config X86_P4_CLOCKMOD
config X86_CPUFREQ_NFORCE2
tristate "nVidia nForce2 FSB changing"
- depends on X86_32 && EXPERIMENTAL
+ depends on X86_32
help
This adds the CPUFreq driver for FSB changing on nVidia nForce2
platforms.
@@ -242,7 +255,7 @@ config X86_LONGHAUL
config X86_E_POWERSAVER
tristate "VIA C7 Enhanced PowerSaver (DANGEROUS)"
select CPU_FREQ_TABLE
- depends on X86_32 && EXPERIMENTAL
+ depends on X86_32
help
This adds the CPUFreq driver for VIA C7 processors. However, this driver
does not have any safeguards to prevent operating the CPU out of spec
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index fadc4d496e2f..863fd1865d45 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -19,11 +19,12 @@ obj-$(CONFIG_GENERIC_CPUFREQ_CPU0) += cpufreq-cpu0.o
##################################################################################
# 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.
+# K8 systems. This is still the case but acpi-cpufreq errors out so that
+# powernow-k8 can load then. ACPI is preferred to all other hardware-specific drivers.
# speedstep-* is preferred over p4-clockmod.
-obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o
+obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.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
@@ -39,10 +40,11 @@ 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
+obj-$(CONFIG_X86_INTEL_PSTATE) += intel_pstate.o
##################################################################################
# ARM SoC drivers
-obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o
+obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
@@ -50,8 +52,11 @@ obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += exynos-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o
-obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
+obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
+obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
+obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
##################################################################################
# PowerPC platform drivers
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 7b0d49d78c61..937bc286591f 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -734,7 +734,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
#ifdef CONFIG_SMP
dmi_check_system(sw_any_bug_dmi_table);
- if (bios_with_sw_any_bug && cpumask_weight(policy->cpus) == 1) {
+ if (bios_with_sw_any_bug && !policy_is_shared(policy)) {
policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
cpumask_copy(policy->cpus, cpu_core_mask(cpu));
}
@@ -762,6 +762,12 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
switch (perf->control_register.space_id) {
case ACPI_ADR_SPACE_SYSTEM_IO:
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+ boot_cpu_data.x86 == 0xf) {
+ pr_debug("AMD K8 systems must use native drivers.\n");
+ result = -ENODEV;
+ goto err_unreg;
+ }
pr_debug("SYSTEM IO addr space\n");
data->cpu_feature = SYSTEM_IO_CAPABLE;
break;
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index debc5a7c8db6..4e5b7fb8927c 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -12,12 +12,12 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h>
-#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/opp.h>
+#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -146,7 +146,6 @@ static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
* share the clock and voltage and clock. Use cpufreq affected_cpus
* interface to have all CPUs scaled together.
*/
- policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
cpumask_setall(policy->cpus);
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
@@ -177,34 +176,32 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
.attr = cpu0_cpufreq_attr,
};
-static int cpu0_cpufreq_driver_init(void)
+static int cpu0_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *np;
int ret;
- np = of_find_node_by_path("/cpus/cpu@0");
+ for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+ if (of_get_property(np, "operating-points", NULL))
+ break;
+ }
+
if (!np) {
pr_err("failed to find cpu0 node\n");
return -ENOENT;
}
- cpu_dev = get_cpu_device(0);
- if (!cpu_dev) {
- pr_err("failed to get cpu0 device\n");
- ret = -ENODEV;
- goto out_put_node;
- }
-
+ cpu_dev = &pdev->dev;
cpu_dev->of_node = np;
- cpu_clk = clk_get(cpu_dev, NULL);
+ cpu_clk = devm_clk_get(cpu_dev, NULL);
if (IS_ERR(cpu_clk)) {
ret = PTR_ERR(cpu_clk);
pr_err("failed to get cpu0 clock: %d\n", ret);
goto out_put_node;
}
- cpu_reg = regulator_get(cpu_dev, "cpu0");
+ cpu_reg = devm_regulator_get(cpu_dev, "cpu0");
if (IS_ERR(cpu_reg)) {
pr_warn("failed to get cpu0 regulator\n");
cpu_reg = NULL;
@@ -267,7 +264,24 @@ out_put_node:
of_node_put(np);
return ret;
}
-late_initcall(cpu0_cpufreq_driver_init);
+
+static int cpu0_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_unregister_driver(&cpu0_cpufreq_driver);
+ opp_free_cpufreq_table(cpu_dev, &freq_table);
+
+ return 0;
+}
+
+static struct platform_driver cpu0_cpufreq_platdrv = {
+ .driver = {
+ .name = "cpufreq-cpu0",
+ .owner = THIS_MODULE,
+ },
+ .probe = cpu0_cpufreq_probe,
+ .remove = cpu0_cpufreq_remove,
+};
+module_platform_driver(cpu0_cpufreq_platdrv);
MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
MODULE_DESCRIPTION("Generic CPU0 cpufreq driver");
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 1f93dbd72355..b02824d092e7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -59,8 +59,6 @@ static DEFINE_SPINLOCK(cpufreq_driver_lock);
* mode before doing so.
*
* Additional rules:
- * - All holders of the lock should check to make sure that the CPU they
- * are concerned with are online after they get the lock.
* - Governor routines that can be called in cpufreq hotplug path should not
* take this sem as top level hotplug notifier handler takes this.
* - Lock should not be held across
@@ -70,38 +68,28 @@ static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
#define lock_policy_rwsem(mode, cpu) \
-static int lock_policy_rwsem_##mode \
-(int cpu) \
+static int lock_policy_rwsem_##mode(int cpu) \
{ \
int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \
BUG_ON(policy_cpu == -1); \
down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \
- if (unlikely(!cpu_online(cpu))) { \
- up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \
- return -1; \
- } \
\
return 0; \
}
lock_policy_rwsem(read, cpu);
-
lock_policy_rwsem(write, cpu);
-static void unlock_policy_rwsem_read(int cpu)
-{
- int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
- BUG_ON(policy_cpu == -1);
- up_read(&per_cpu(cpu_policy_rwsem, policy_cpu));
-}
-
-static void unlock_policy_rwsem_write(int cpu)
-{
- int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
- BUG_ON(policy_cpu == -1);
- up_write(&per_cpu(cpu_policy_rwsem, policy_cpu));
+#define unlock_policy_rwsem(mode, cpu) \
+static void unlock_policy_rwsem_##mode(int cpu) \
+{ \
+ int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \
+ BUG_ON(policy_cpu == -1); \
+ up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \
}
+unlock_policy_rwsem(read, cpu);
+unlock_policy_rwsem(write, cpu);
/* internal prototypes */
static int __cpufreq_governor(struct cpufreq_policy *policy,
@@ -180,6 +168,9 @@ err_out:
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
{
+ if (cpufreq_disabled())
+ return NULL;
+
return __cpufreq_cpu_get(cpu, false);
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
@@ -198,6 +189,9 @@ static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs)
void cpufreq_cpu_put(struct cpufreq_policy *data)
{
+ if (cpufreq_disabled())
+ return;
+
__cpufreq_cpu_put(data, false);
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
@@ -261,14 +255,21 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
{
struct cpufreq_policy *policy;
+ unsigned long flags;
BUG_ON(irqs_disabled());
+ if (cpufreq_disabled())
+ return;
+
freqs->flags = cpufreq_driver->flags;
pr_debug("notification %u of frequency transition to %u kHz\n",
state, freqs->new);
+ spin_lock_irqsave(&cpufreq_driver_lock, flags);
policy = per_cpu(cpufreq_cpu_data, freqs->cpu);
+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
switch (state) {
case CPUFREQ_PRECHANGE:
@@ -294,7 +295,6 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
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);
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
@@ -543,8 +543,6 @@ static ssize_t show_cpus(const struct cpumask *mask, char *buf)
*/
static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)
{
- if (cpumask_empty(policy->related_cpus))
- return show_cpus(policy->cpus, buf);
return show_cpus(policy->related_cpus, buf);
}
@@ -700,87 +698,6 @@ static struct kobj_type ktype_cpufreq = {
.release = cpufreq_sysfs_release,
};
-/*
- * Returns:
- * Negative: Failure
- * 0: Success
- * Positive: When we have a managed CPU and the sysfs got symlinked
- */
-static int cpufreq_add_dev_policy(unsigned int cpu,
- struct cpufreq_policy *policy,
- struct device *dev)
-{
- int ret = 0;
-#ifdef CONFIG_SMP
- unsigned long flags;
- unsigned int j;
-#ifdef CONFIG_HOTPLUG_CPU
- struct cpufreq_governor *gov;
-
- gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
- if (gov) {
- policy->governor = gov;
- pr_debug("Restoring governor %s for cpu %d\n",
- policy->governor->name, cpu);
- }
-#endif
-
- for_each_cpu(j, policy->cpus) {
- struct cpufreq_policy *managed_policy;
-
- if (cpu == j)
- continue;
-
- /* Check for existing affected CPUs.
- * They may not be aware of it due to CPU Hotplug.
- * cpufreq_cpu_put is called when the device is removed
- * in __cpufreq_remove_dev()
- */
- managed_policy = cpufreq_cpu_get(j);
- if (unlikely(managed_policy)) {
-
- /* Set proper policy_cpu */
- unlock_policy_rwsem_write(cpu);
- per_cpu(cpufreq_policy_cpu, cpu) = managed_policy->cpu;
-
- if (lock_policy_rwsem_write(cpu) < 0) {
- /* Should not go through policy unlock path */
- if (cpufreq_driver->exit)
- cpufreq_driver->exit(policy);
- cpufreq_cpu_put(managed_policy);
- return -EBUSY;
- }
-
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
- cpumask_copy(managed_policy->cpus, policy->cpus);
- per_cpu(cpufreq_cpu_data, cpu) = managed_policy;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
- pr_debug("CPU already managed, adding link\n");
- ret = sysfs_create_link(&dev->kobj,
- &managed_policy->kobj,
- "cpufreq");
- if (ret)
- cpufreq_cpu_put(managed_policy);
- /*
- * Success. We only needed to be added to the mask.
- * Call driver->exit() because only the cpu parent of
- * the kobj needed to call init().
- */
- if (cpufreq_driver->exit)
- cpufreq_driver->exit(policy);
-
- if (!ret)
- return 1;
- else
- return ret;
- }
- }
-#endif
- return ret;
-}
-
-
/* symlink affected CPUs */
static int cpufreq_add_dev_symlink(unsigned int cpu,
struct cpufreq_policy *policy)
@@ -794,8 +711,6 @@ static int cpufreq_add_dev_symlink(unsigned int cpu,
if (j == cpu)
continue;
- if (!cpu_online(j))
- continue;
pr_debug("CPU %u already managed, adding link\n", j);
managed_policy = cpufreq_cpu_get(cpu);
@@ -852,8 +767,6 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
spin_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus) {
- if (!cpu_online(j))
- continue;
per_cpu(cpufreq_cpu_data, j) = policy;
per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
}
@@ -885,6 +798,42 @@ err_out_kobj_put:
return ret;
}
+#ifdef CONFIG_HOTPLUG_CPU
+static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
+ struct device *dev)
+{
+ struct cpufreq_policy *policy;
+ int ret = 0;
+ unsigned long flags;
+
+ policy = cpufreq_cpu_get(sibling);
+ WARN_ON(!policy);
+
+ __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+
+ lock_policy_rwsem_write(sibling);
+
+ spin_lock_irqsave(&cpufreq_driver_lock, flags);
+
+ cpumask_set_cpu(cpu, policy->cpus);
+ per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu;
+ per_cpu(cpufreq_cpu_data, cpu) = policy;
+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ unlock_policy_rwsem_write(sibling);
+
+ __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+
+ ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
+ if (ret) {
+ cpufreq_cpu_put(policy);
+ return ret;
+ }
+
+ return 0;
+}
+#endif
/**
* cpufreq_add_dev - add a CPU device
@@ -897,12 +846,12 @@ err_out_kobj_put:
*/
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
- unsigned int cpu = dev->id;
- int ret = 0, found = 0;
+ unsigned int j, cpu = dev->id;
+ int ret = -ENOMEM;
struct cpufreq_policy *policy;
unsigned long flags;
- unsigned int j;
#ifdef CONFIG_HOTPLUG_CPU
+ struct cpufreq_governor *gov;
int sibling;
#endif
@@ -919,6 +868,19 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
cpufreq_cpu_put(policy);
return 0;
}
+
+#ifdef CONFIG_HOTPLUG_CPU
+ /* Check if this cpu was hot-unplugged earlier and has siblings */
+ spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ for_each_online_cpu(sibling) {
+ struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
+ if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ return cpufreq_add_policy_cpu(cpu, sibling, dev);
+ }
+ }
+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+#endif
#endif
if (!try_module_get(cpufreq_driver->owner)) {
@@ -926,7 +888,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
goto module_out;
}
- ret = -ENOMEM;
policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!policy)
goto nomem_out;
@@ -938,66 +899,58 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
goto err_free_cpumask;
policy->cpu = cpu;
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
cpumask_copy(policy->cpus, cpumask_of(cpu));
/* Initially set CPU itself as the policy_cpu */
per_cpu(cpufreq_policy_cpu, cpu) = cpu;
- ret = (lock_policy_rwsem_write(cpu) < 0);
- WARN_ON(ret);
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
- /* Set governor before ->init, so that driver could check it */
-#ifdef CONFIG_HOTPLUG_CPU
- for_each_online_cpu(sibling) {
- struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
- if (cp && cp->governor &&
- (cpumask_test_cpu(cpu, cp->related_cpus))) {
- policy->governor = cp->governor;
- found = 1;
- break;
- }
- }
-#endif
- if (!found)
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
/* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU
*/
ret = cpufreq_driver->init(policy);
if (ret) {
pr_debug("initialization failed\n");
- goto err_unlock_policy;
+ goto err_set_policy_cpu;
}
+
+ /* related cpus should atleast have policy->cpus */
+ cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
+
+ /*
+ * affected cpus must always be the one, which are online. We aren't
+ * managing offline cpus here.
+ */
+ cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
+
policy->user_policy.min = policy->min;
policy->user_policy.max = policy->max;
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_START, policy);
- ret = cpufreq_add_dev_policy(cpu, policy, dev);
- if (ret) {
- if (ret > 0)
- /* This is a managed cpu, symlink created,
- exit with 0 */
- ret = 0;
- goto err_unlock_policy;
+#ifdef CONFIG_HOTPLUG_CPU
+ gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
+ if (gov) {
+ policy->governor = gov;
+ pr_debug("Restoring governor %s for cpu %d\n",
+ policy->governor->name, cpu);
}
+#endif
ret = cpufreq_add_dev_interface(cpu, policy, dev);
if (ret)
goto err_out_unregister;
- unlock_policy_rwsem_write(cpu);
-
kobject_uevent(&policy->kobj, KOBJ_ADD);
module_put(cpufreq_driver->owner);
pr_debug("initialization complete\n");
return 0;
-
err_out_unregister:
spin_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus)
@@ -1007,8 +960,8 @@ err_out_unregister:
kobject_put(&policy->kobj);
wait_for_completion(&policy->kobj_unregister);
-err_unlock_policy:
- unlock_policy_rwsem_write(cpu);
+err_set_policy_cpu:
+ per_cpu(cpufreq_policy_cpu, cpu) = -1;
free_cpumask_var(policy->related_cpus);
err_free_cpumask:
free_cpumask_var(policy->cpus);
@@ -1020,6 +973,22 @@ module_out:
return ret;
}
+static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
+{
+ int j;
+
+ policy->last_cpu = policy->cpu;
+ policy->cpu = cpu;
+
+ for_each_cpu(j, policy->cpus)
+ per_cpu(cpufreq_policy_cpu, j) = cpu;
+
+#ifdef CONFIG_CPU_FREQ_TABLE
+ cpufreq_frequency_table_update_policy_cpu(policy);
+#endif
+ blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+ CPUFREQ_UPDATE_POLICY_CPU, policy);
+}
/**
* __cpufreq_remove_dev - remove a CPU device
@@ -1030,129 +999,103 @@ module_out:
*/
static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
{
- unsigned int cpu = dev->id;
+ unsigned int cpu = dev->id, ret, cpus;
unsigned long flags;
struct cpufreq_policy *data;
struct kobject *kobj;
struct completion *cmp;
-#ifdef CONFIG_SMP
struct device *cpu_dev;
- unsigned int j;
-#endif
- pr_debug("unregistering CPU %u\n", cpu);
+ pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
spin_lock_irqsave(&cpufreq_driver_lock, flags);
+
data = per_cpu(cpufreq_cpu_data, cpu);
+ per_cpu(cpufreq_cpu_data, cpu) = NULL;
+
+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (!data) {
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- unlock_policy_rwsem_write(cpu);
+ pr_debug("%s: No cpu_data found\n", __func__);
return -EINVAL;
}
- per_cpu(cpufreq_cpu_data, cpu) = NULL;
+ if (cpufreq_driver->target)
+ __cpufreq_governor(data, CPUFREQ_GOV_STOP);
-#ifdef CONFIG_SMP
- /* if this isn't the CPU which is the parent of the kobj, we
- * only need to unlink, put and exit
- */
- if (unlikely(cpu != data->cpu)) {
- pr_debug("removing link\n");
- cpumask_clear_cpu(cpu, data->cpus);
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- kobj = &dev->kobj;
- cpufreq_cpu_put(data);
- unlock_policy_rwsem_write(cpu);
- sysfs_remove_link(kobj, "cpufreq");
- return 0;
- }
+#ifdef CONFIG_HOTPLUG_CPU
+ if (!cpufreq_driver->setpolicy)
+ strncpy(per_cpu(cpufreq_cpu_governor, cpu),
+ data->governor->name, CPUFREQ_NAME_LEN);
#endif
-#ifdef CONFIG_SMP
+ WARN_ON(lock_policy_rwsem_write(cpu));
+ cpus = cpumask_weight(data->cpus);
+ cpumask_clear_cpu(cpu, data->cpus);
+ unlock_policy_rwsem_write(cpu);
-#ifdef CONFIG_HOTPLUG_CPU
- strncpy(per_cpu(cpufreq_cpu_governor, cpu), data->governor->name,
- CPUFREQ_NAME_LEN);
-#endif
+ if (cpu != data->cpu) {
+ sysfs_remove_link(&dev->kobj, "cpufreq");
+ } else if (cpus > 1) {
+ /* first sibling now owns the new sysfs dir */
+ cpu_dev = get_cpu_device(cpumask_first(data->cpus));
+ sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
+ ret = kobject_move(&data->kobj, &cpu_dev->kobj);
+ if (ret) {
+ pr_err("%s: Failed to move kobj: %d", __func__, ret);
- /* if we have other CPUs still registered, we need to unlink them,
- * or else wait_for_completion below will lock up. Clean the
- * per_cpu(cpufreq_cpu_data) while holding the lock, and remove
- * the sysfs links afterwards.
- */
- if (unlikely(cpumask_weight(data->cpus) > 1)) {
- for_each_cpu(j, data->cpus) {
- if (j == cpu)
- continue;
- per_cpu(cpufreq_cpu_data, j) = NULL;
- }
- }
+ WARN_ON(lock_policy_rwsem_write(cpu));
+ cpumask_set_cpu(cpu, data->cpus);
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ per_cpu(cpufreq_cpu_data, cpu) = data;
+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- if (unlikely(cpumask_weight(data->cpus) > 1)) {
- for_each_cpu(j, data->cpus) {
- if (j == cpu)
- continue;
- 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);
-#endif
- cpu_dev = get_cpu_device(j);
- kobj = &cpu_dev->kobj;
unlock_policy_rwsem_write(cpu);
- sysfs_remove_link(kobj, "cpufreq");
- lock_policy_rwsem_write(cpu);
- cpufreq_cpu_put(data);
- }
- }
-#else
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-#endif
- if (cpufreq_driver->target)
- __cpufreq_governor(data, CPUFREQ_GOV_STOP);
+ ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj,
+ "cpufreq");
+ return -EINVAL;
+ }
- kobj = &data->kobj;
- cmp = &data->kobj_unregister;
- unlock_policy_rwsem_write(cpu);
- kobject_put(kobj);
+ WARN_ON(lock_policy_rwsem_write(cpu));
+ update_policy_cpu(data, cpu_dev->id);
+ unlock_policy_rwsem_write(cpu);
+ pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
+ __func__, cpu_dev->id, cpu);
+ }
- /* we need to make sure that the underlying kobj is actually
- * not referenced anymore by anybody before we proceed with
- * unloading.
- */
- pr_debug("waiting for dropping of refcount\n");
- wait_for_completion(cmp);
- pr_debug("wait complete\n");
+ pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
+ cpufreq_cpu_put(data);
- lock_policy_rwsem_write(cpu);
- if (cpufreq_driver->exit)
- cpufreq_driver->exit(data);
- unlock_policy_rwsem_write(cpu);
+ /* If cpu is last user of policy, free policy */
+ if (cpus == 1) {
+ lock_policy_rwsem_read(cpu);
+ kobj = &data->kobj;
+ cmp = &data->kobj_unregister;
+ unlock_policy_rwsem_read(cpu);
+ kobject_put(kobj);
+
+ /* we need to make sure that the underlying kobj is actually
+ * not referenced anymore by anybody before we proceed with
+ * unloading.
+ */
+ pr_debug("waiting for dropping of refcount\n");
+ wait_for_completion(cmp);
+ pr_debug("wait complete\n");
-#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_device(cpumask_first(data->cpus)), NULL);
+ if (cpufreq_driver->exit)
+ cpufreq_driver->exit(data);
- /* finally remove our own symlink */
- lock_policy_rwsem_write(cpu);
- __cpufreq_remove_dev(dev, sif);
+ free_cpumask_var(data->related_cpus);
+ free_cpumask_var(data->cpus);
+ kfree(data);
+ } else if (cpufreq_driver->target) {
+ __cpufreq_governor(data, CPUFREQ_GOV_START);
+ __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
}
-#endif
-
- free_cpumask_var(data->related_cpus);
- free_cpumask_var(data->cpus);
- kfree(data);
+ per_cpu(cpufreq_policy_cpu, cpu) = -1;
return 0;
}
@@ -1165,9 +1108,6 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
if (cpu_is_offline(cpu))
return 0;
- if (unlikely(lock_policy_rwsem_write(cpu)))
- BUG();
-
retval = __cpufreq_remove_dev(dev, sif);
return retval;
}
@@ -1216,9 +1156,13 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
*/
unsigned int cpufreq_quick_get(unsigned int cpu)
{
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ struct cpufreq_policy *policy;
unsigned int ret_freq = 0;
+ if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get)
+ return cpufreq_driver->get(cpu);
+
+ policy = cpufreq_cpu_get(cpu);
if (policy) {
ret_freq = policy->cur;
cpufreq_cpu_put(policy);
@@ -1386,6 +1330,20 @@ static struct syscore_ops cpufreq_syscore_ops = {
.resume = cpufreq_bp_resume,
};
+/**
+ * cpufreq_get_current_driver - return current driver's name
+ *
+ * Return the name string of the currently loaded cpufreq driver
+ * or NULL, if none.
+ */
+const char *cpufreq_get_current_driver(void)
+{
+ if (cpufreq_driver)
+ return cpufreq_driver->name;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(cpufreq_get_current_driver);
/*********************************************************************
* NOTIFIER LISTS INTERFACE *
@@ -1408,6 +1366,9 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
{
int ret;
+ if (cpufreq_disabled())
+ return -EINVAL;
+
WARN_ON(!init_cpufreq_transition_notifier_list_called);
switch (list) {
@@ -1442,6 +1403,9 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
{
int ret;
+ if (cpufreq_disabled())
+ return -EINVAL;
+
switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER:
ret = srcu_notifier_chain_unregister(
@@ -1487,7 +1451,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
if (target_freq == policy->cur)
return 0;
- if (cpu_online(policy->cpu) && cpufreq_driver->target)
+ if (cpufreq_driver->target)
retval = cpufreq_driver->target(policy, target_freq, relation);
return retval;
@@ -1522,7 +1486,10 @@ int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
{
int ret = 0;
- if (!(cpu_online(cpu) && cpufreq_driver->getavg))
+ if (cpufreq_disabled())
+ return ret;
+
+ if (!cpufreq_driver->getavg)
return 0;
policy = cpufreq_cpu_get(policy->cpu);
@@ -1577,6 +1544,11 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
policy->cpu, event);
ret = policy->governor->governor(policy, event);
+ if (event == CPUFREQ_GOV_START)
+ policy->governor->initialized++;
+ else if (event == CPUFREQ_GOV_STOP)
+ policy->governor->initialized--;
+
/* we keep one module reference alive for
each CPU governed by this CPU */
if ((event != CPUFREQ_GOV_START) || ret)
@@ -1600,6 +1572,7 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
mutex_lock(&cpufreq_governor_mutex);
+ governor->initialized = 0;
err = -EBUSY;
if (__find_governor(governor->name) == NULL) {
err = 0;
@@ -1797,7 +1770,7 @@ int cpufreq_update_policy(unsigned int cpu)
pr_debug("Driver did not initialize current freq");
data->cur = policy.cur;
} else {
- if (data->cur != policy.cur)
+ if (data->cur != policy.cur && cpufreq_driver->target)
cpufreq_out_of_sync(cpu, data->cur,
policy.cur);
}
@@ -1829,9 +1802,6 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
break;
case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
- if (unlikely(lock_policy_rwsem_write(cpu)))
- BUG();
-
__cpufreq_remove_dev(dev, NULL);
break;
case CPU_DOWN_FAILED:
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 64ef737e7e72..4fd0006b1291 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -25,7 +25,7 @@
#include "cpufreq_governor.h"
-/* Conservative governor macors */
+/* Conservative governor macros */
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
#define DEF_SAMPLING_DOWN_FACTOR (1)
@@ -113,17 +113,20 @@ static void cs_check_cpu(int cpu, unsigned int load)
static void cs_dbs_timer(struct work_struct *work)
{
+ struct delayed_work *dw = to_delayed_work(work);
struct cs_cpu_dbs_info_s *dbs_info = container_of(work,
struct cs_cpu_dbs_info_s, cdbs.work.work);
- unsigned int cpu = dbs_info->cdbs.cpu;
+ unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
+ struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info,
+ cpu);
int delay = delay_for_sampling_rate(cs_tuners.sampling_rate);
- mutex_lock(&dbs_info->cdbs.timer_mutex);
+ mutex_lock(&core_dbs_info->cdbs.timer_mutex);
+ if (need_load_eval(&core_dbs_info->cdbs, cs_tuners.sampling_rate))
+ dbs_check_cpu(&cs_dbs_data, cpu);
- dbs_check_cpu(&cs_dbs_data, cpu);
-
- schedule_delayed_work_on(cpu, &dbs_info->cdbs.work, delay);
- mutex_unlock(&dbs_info->cdbs.timer_mutex);
+ schedule_delayed_work_on(smp_processor_id(), dw, delay);
+ mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
}
static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
@@ -141,7 +144,7 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
/*
* we only care if our internally tracked freq moves outside the 'valid'
- * ranges of freqency available to us otherwise we do not change it
+ * ranges of frequency available to us otherwise we do not change it
*/
if (dbs_info->requested_freq > policy->max
|| dbs_info->requested_freq < policy->min)
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 6c5f1d383cdc..5a76086ff09b 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -161,25 +161,48 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
}
EXPORT_SYMBOL_GPL(dbs_check_cpu);
-static inline void dbs_timer_init(struct dbs_data *dbs_data,
- struct cpu_dbs_common_info *cdbs, unsigned int sampling_rate)
+static inline void dbs_timer_init(struct dbs_data *dbs_data, int cpu,
+ unsigned int sampling_rate)
{
int delay = delay_for_sampling_rate(sampling_rate);
+ struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
- INIT_DEFERRABLE_WORK(&cdbs->work, dbs_data->gov_dbs_timer);
- schedule_delayed_work_on(cdbs->cpu, &cdbs->work, delay);
+ schedule_delayed_work_on(cpu, &cdbs->work, delay);
}
-static inline void dbs_timer_exit(struct cpu_dbs_common_info *cdbs)
+static inline void dbs_timer_exit(struct dbs_data *dbs_data, int cpu)
{
+ struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
+
cancel_delayed_work_sync(&cdbs->work);
}
+/* Will return if we need to evaluate cpu load again or not */
+bool need_load_eval(struct cpu_dbs_common_info *cdbs,
+ unsigned int sampling_rate)
+{
+ if (policy_is_shared(cdbs->cur_policy)) {
+ ktime_t time_now = ktime_get();
+ s64 delta_us = ktime_us_delta(time_now, cdbs->time_stamp);
+
+ /* Do nothing if we recently have sampled */
+ if (delta_us < (s64)(sampling_rate / 2))
+ return false;
+ else
+ cdbs->time_stamp = time_now;
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(need_load_eval);
+
int cpufreq_governor_dbs(struct dbs_data *dbs_data,
struct cpufreq_policy *policy, unsigned int event)
{
struct od_cpu_dbs_info_s *od_dbs_info = NULL;
struct cs_cpu_dbs_info_s *cs_dbs_info = NULL;
+ struct cs_ops *cs_ops = NULL;
+ struct od_ops *od_ops = NULL;
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
struct cpu_dbs_common_info *cpu_cdbs;
@@ -192,109 +215,111 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data,
cs_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu);
sampling_rate = &cs_tuners->sampling_rate;
ignore_nice = cs_tuners->ignore_nice;
+ cs_ops = dbs_data->gov_ops;
} else {
od_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu);
sampling_rate = &od_tuners->sampling_rate;
ignore_nice = od_tuners->ignore_nice;
+ od_ops = dbs_data->gov_ops;
}
switch (event) {
case CPUFREQ_GOV_START:
- if ((!cpu_online(cpu)) || (!policy->cur))
+ if (!policy->cur)
return -EINVAL;
mutex_lock(&dbs_data->mutex);
- dbs_data->enable++;
- cpu_cdbs->cpu = cpu;
for_each_cpu(j, policy->cpus) {
- struct cpu_dbs_common_info *j_cdbs;
- j_cdbs = dbs_data->get_cpu_cdbs(j);
+ struct cpu_dbs_common_info *j_cdbs =
+ dbs_data->get_cpu_cdbs(j);
+ j_cdbs->cpu = j;
j_cdbs->cur_policy = policy;
j_cdbs->prev_cpu_idle = get_cpu_idle_time(j,
&j_cdbs->prev_cpu_wall);
if (ignore_nice)
j_cdbs->prev_cpu_nice =
kcpustat_cpu(j).cpustat[CPUTIME_NICE];
- }
- /*
- * Start the timerschedule work, when this governor is used for
- * first time
- */
- if (dbs_data->enable != 1)
- goto second_time;
-
- rc = sysfs_create_group(cpufreq_global_kobject,
- dbs_data->attr_group);
- if (rc) {
- mutex_unlock(&dbs_data->mutex);
- return rc;
+ mutex_init(&j_cdbs->timer_mutex);
+ INIT_DEFERRABLE_WORK(&j_cdbs->work,
+ dbs_data->gov_dbs_timer);
}
- /* policy latency is in nS. Convert it to uS first */
- latency = policy->cpuinfo.transition_latency / 1000;
- if (latency == 0)
- latency = 1;
+ if (!policy->governor->initialized) {
+ rc = sysfs_create_group(cpufreq_global_kobject,
+ dbs_data->attr_group);
+ if (rc) {
+ mutex_unlock(&dbs_data->mutex);
+ return rc;
+ }
+ }
/*
* conservative does not implement micro like ondemand
* governor, thus we are bound to jiffes/HZ
*/
if (dbs_data->governor == GOV_CONSERVATIVE) {
- struct cs_ops *ops = dbs_data->gov_ops;
+ cs_dbs_info->down_skip = 0;
+ cs_dbs_info->enable = 1;
+ cs_dbs_info->requested_freq = policy->cur;
- cpufreq_register_notifier(ops->notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
+ if (!policy->governor->initialized) {
+ cpufreq_register_notifier(cs_ops->notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
- dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
- jiffies_to_usecs(10);
+ dbs_data->min_sampling_rate =
+ MIN_SAMPLING_RATE_RATIO *
+ jiffies_to_usecs(10);
+ }
} else {
- struct od_ops *ops = dbs_data->gov_ops;
+ od_dbs_info->rate_mult = 1;
+ od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
+ od_ops->powersave_bias_init_cpu(cpu);
- od_tuners->io_is_busy = ops->io_busy();
+ if (!policy->governor->initialized)
+ od_tuners->io_is_busy = od_ops->io_busy();
}
+ if (policy->governor->initialized)
+ goto unlock;
+
+ /* policy latency is in nS. Convert it to uS first */
+ latency = policy->cpuinfo.transition_latency / 1000;
+ if (latency == 0)
+ latency = 1;
+
/* Bring kernel and HW constraints together */
dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
MIN_LATENCY_MULTIPLIER * latency);
*sampling_rate = max(dbs_data->min_sampling_rate, latency *
LATENCY_MULTIPLIER);
-
-second_time:
- if (dbs_data->governor == GOV_CONSERVATIVE) {
- cs_dbs_info->down_skip = 0;
- cs_dbs_info->enable = 1;
- cs_dbs_info->requested_freq = policy->cur;
- } else {
- struct od_ops *ops = dbs_data->gov_ops;
- od_dbs_info->rate_mult = 1;
- od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
- ops->powersave_bias_init_cpu(cpu);
- }
+unlock:
mutex_unlock(&dbs_data->mutex);
- mutex_init(&cpu_cdbs->timer_mutex);
- dbs_timer_init(dbs_data, cpu_cdbs, *sampling_rate);
+ /* Initiate timer time stamp */
+ cpu_cdbs->time_stamp = ktime_get();
+
+ for_each_cpu(j, policy->cpus)
+ dbs_timer_init(dbs_data, j, *sampling_rate);
break;
case CPUFREQ_GOV_STOP:
if (dbs_data->governor == GOV_CONSERVATIVE)
cs_dbs_info->enable = 0;
- dbs_timer_exit(cpu_cdbs);
+ for_each_cpu(j, policy->cpus)
+ dbs_timer_exit(dbs_data, j);
mutex_lock(&dbs_data->mutex);
mutex_destroy(&cpu_cdbs->timer_mutex);
- dbs_data->enable--;
- if (!dbs_data->enable) {
- struct cs_ops *ops = dbs_data->gov_ops;
+ if (policy->governor->initialized == 1) {
sysfs_remove_group(cpufreq_global_kobject,
dbs_data->attr_group);
if (dbs_data->governor == GOV_CONSERVATIVE)
- cpufreq_unregister_notifier(ops->notifier_block,
+ cpufreq_unregister_notifier(cs_ops->notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
}
mutex_unlock(&dbs_data->mutex);
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index f6616540c53d..d2ac91150600 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -82,6 +82,7 @@ struct cpu_dbs_common_info {
* the governor or limits.
*/
struct mutex timer_mutex;
+ ktime_t time_stamp;
};
struct od_cpu_dbs_info_s {
@@ -108,7 +109,7 @@ struct od_dbs_tuners {
unsigned int sampling_rate;
unsigned int sampling_down_factor;
unsigned int up_threshold;
- unsigned int down_differential;
+ unsigned int adj_up_threshold;
unsigned int powersave_bias;
unsigned int io_is_busy;
};
@@ -129,7 +130,6 @@ struct dbs_data {
#define GOV_CONSERVATIVE 1
int governor;
unsigned int min_sampling_rate;
- unsigned int enable; /* number of CPUs using this policy */
struct attribute_group *attr_group;
void *tuners;
@@ -171,6 +171,8 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate)
u64 get_cpu_idle_time(unsigned int cpu, u64 *wall);
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
+bool need_load_eval(struct cpu_dbs_common_info *cdbs,
+ unsigned int sampling_rate);
int cpufreq_governor_dbs(struct dbs_data *dbs_data,
struct cpufreq_policy *policy, unsigned int event);
#endif /* _CPUFREQ_GOVERNER_H */
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 7731f7c7e79a..f3eb26cd848f 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -26,7 +26,7 @@
#include "cpufreq_governor.h"
-/* On-demand governor macors */
+/* On-demand governor macros */
#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10)
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define DEF_SAMPLING_DOWN_FACTOR (1)
@@ -47,7 +47,8 @@ static struct cpufreq_governor cpufreq_gov_ondemand;
static struct od_dbs_tuners od_tuners = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
- .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
+ .adj_up_threshold = DEF_FREQUENCY_UP_THRESHOLD -
+ DEF_FREQUENCY_DOWN_DIFFERENTIAL,
.ignore_nice = 0,
.powersave_bias = 0,
};
@@ -65,7 +66,7 @@ static void ondemand_powersave_bias_init_cpu(int cpu)
* efficient idling at a higher frequency/voltage is.
* Pavel Machek says this is not so for various generations of AMD and old
* Intel systems.
- * Mike Chan (androidlcom) calis this is also not true for ARM.
+ * Mike Chan (android.com) claims this is also not true for ARM.
* Because of this, whitelist specific known (series) of CPUs by default, and
* leave all others up to the user.
*/
@@ -73,7 +74,7 @@ static int should_io_be_busy(void)
{
#if defined(CONFIG_X86)
/*
- * For Intel, Core 2 (model 15) andl later have an efficient idle.
+ * For Intel, Core 2 (model 15) and later have an efficient idle.
*/
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
boot_cpu_data.x86 == 6 &&
@@ -158,8 +159,8 @@ static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
/*
* Every sampling_rate, we check, if current idle time is less than 20%
- * (default), then we try to increase frequency Every sampling_rate, we look for
- * a the lowest frequency which can sustain the load while keeping idle time
+ * (default), then we try to increase frequency. Every sampling_rate, we look
+ * for the lowest frequency which can sustain the load while keeping idle time
* over 30%. If such a frequency exist, we try to decrease to this frequency.
*
* Any frequency increase takes it to the maximum frequency. Frequency reduction
@@ -192,11 +193,9 @@ static void od_check_cpu(int cpu, unsigned int load_freq)
* support the current CPU usage without triggering the up policy. To be
* safe, we focus 10 points under the threshold.
*/
- if (load_freq < (od_tuners.up_threshold - od_tuners.down_differential) *
- policy->cur) {
+ if (load_freq < od_tuners.adj_up_threshold * policy->cur) {
unsigned int freq_next;
- freq_next = load_freq / (od_tuners.up_threshold -
- od_tuners.down_differential);
+ freq_next = load_freq / od_tuners.adj_up_threshold;
/* No longer fully busy, reset rate_mult */
dbs_info->rate_mult = 1;
@@ -218,33 +217,42 @@ static void od_check_cpu(int cpu, unsigned int load_freq)
static void od_dbs_timer(struct work_struct *work)
{
+ struct delayed_work *dw = to_delayed_work(work);
struct od_cpu_dbs_info_s *dbs_info =
container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work);
- unsigned int cpu = dbs_info->cdbs.cpu;
- int delay, sample_type = dbs_info->sample_type;
+ unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
+ struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info,
+ cpu);
+ int delay, sample_type = core_dbs_info->sample_type;
+ bool eval_load;
- mutex_lock(&dbs_info->cdbs.timer_mutex);
+ mutex_lock(&core_dbs_info->cdbs.timer_mutex);
+ eval_load = need_load_eval(&core_dbs_info->cdbs,
+ od_tuners.sampling_rate);
/* Common NORMAL_SAMPLE setup */
- dbs_info->sample_type = OD_NORMAL_SAMPLE;
+ core_dbs_info->sample_type = OD_NORMAL_SAMPLE;
if (sample_type == OD_SUB_SAMPLE) {
- delay = dbs_info->freq_lo_jiffies;
- __cpufreq_driver_target(dbs_info->cdbs.cur_policy,
- dbs_info->freq_lo, CPUFREQ_RELATION_H);
+ delay = core_dbs_info->freq_lo_jiffies;
+ if (eval_load)
+ __cpufreq_driver_target(core_dbs_info->cdbs.cur_policy,
+ core_dbs_info->freq_lo,
+ CPUFREQ_RELATION_H);
} else {
- dbs_check_cpu(&od_dbs_data, cpu);
- if (dbs_info->freq_lo) {
+ if (eval_load)
+ dbs_check_cpu(&od_dbs_data, cpu);
+ if (core_dbs_info->freq_lo) {
/* Setup timer for SUB_SAMPLE */
- dbs_info->sample_type = OD_SUB_SAMPLE;
- delay = dbs_info->freq_hi_jiffies;
+ core_dbs_info->sample_type = OD_SUB_SAMPLE;
+ delay = core_dbs_info->freq_hi_jiffies;
} else {
delay = delay_for_sampling_rate(od_tuners.sampling_rate
- * dbs_info->rate_mult);
+ * core_dbs_info->rate_mult);
}
}
- schedule_delayed_work_on(cpu, &dbs_info->cdbs.work, delay);
- mutex_unlock(&dbs_info->cdbs.timer_mutex);
+ schedule_delayed_work_on(smp_processor_id(), dw, delay);
+ mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
}
/************************** sysfs interface ************************/
@@ -259,7 +267,7 @@ static ssize_t show_sampling_rate_min(struct kobject *kobj,
* update_sampling_rate - update sampling rate effective immediately if needed.
* @new_rate: new sampling rate
*
- * If new rate is smaller than the old, simply updaing
+ * If new rate is smaller than the old, simply updating
* dbs_tuners_int.sampling_rate might not be appropriate. For example, if the
* original sampling_rate was 1 second and the requested new sampling rate is 10
* ms because the user needs immediate reaction from ondemand governor, but not
@@ -287,7 +295,7 @@ static void update_sampling_rate(unsigned int new_rate)
cpufreq_cpu_put(policy);
continue;
}
- dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu);
+ dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
cpufreq_cpu_put(policy);
mutex_lock(&dbs_info->cdbs.timer_mutex);
@@ -306,8 +314,7 @@ static void update_sampling_rate(unsigned int new_rate)
cancel_delayed_work_sync(&dbs_info->cdbs.work);
mutex_lock(&dbs_info->cdbs.timer_mutex);
- schedule_delayed_work_on(dbs_info->cdbs.cpu,
- &dbs_info->cdbs.work,
+ schedule_delayed_work_on(cpu, &dbs_info->cdbs.work,
usecs_to_jiffies(new_rate));
}
@@ -351,6 +358,10 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
input < MIN_FREQUENCY_UP_THRESHOLD) {
return -EINVAL;
}
+ /* Calculate the new adj_up_threshold */
+ od_tuners.adj_up_threshold += input;
+ od_tuners.adj_up_threshold -= od_tuners.up_threshold;
+
od_tuners.up_threshold = input;
return count;
}
@@ -507,7 +518,8 @@ static int __init cpufreq_gov_dbs_init(void)
if (idle_time != -1ULL) {
/* Idle micro accounting is supported. Use finer thresholds */
od_tuners.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
- od_tuners.down_differential = MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
+ od_tuners.adj_up_threshold = MICRO_FREQUENCY_UP_THRESHOLD -
+ MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
/*
* In nohz/micro accounting case we set the minimum frequency
* not depending on HZ, but fixed (very low). The deferred
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 9d7732b81044..2fd779eb1ed1 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -24,12 +24,6 @@
static spinlock_t cpufreq_stats_lock;
-#define CPUFREQ_STATDEVICE_ATTR(_name, _mode, _show) \
-static struct freq_attr _attr_##_name = {\
- .attr = {.name = __stringify(_name), .mode = _mode, }, \
- .show = _show,\
-};
-
struct cpufreq_stats {
unsigned int cpu;
unsigned int total_trans;
@@ -136,17 +130,17 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
return PAGE_SIZE;
return len;
}
-CPUFREQ_STATDEVICE_ATTR(trans_table, 0444, show_trans_table);
+cpufreq_freq_attr_ro(trans_table);
#endif
-CPUFREQ_STATDEVICE_ATTR(total_trans, 0444, show_total_trans);
-CPUFREQ_STATDEVICE_ATTR(time_in_state, 0444, show_time_in_state);
+cpufreq_freq_attr_ro(total_trans);
+cpufreq_freq_attr_ro(time_in_state);
static struct attribute *default_attrs[] = {
- &_attr_total_trans.attr,
- &_attr_time_in_state.attr,
+ &total_trans.attr,
+ &time_in_state.attr,
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
- &_attr_trans_table.attr,
+ &trans_table.attr,
#endif
NULL
};
@@ -170,11 +164,13 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
static void cpufreq_stats_free_table(unsigned int cpu)
{
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
+
if (stat) {
+ pr_debug("%s: Free stat table\n", __func__);
kfree(stat->time_in_state);
kfree(stat);
+ per_cpu(cpufreq_stats_table, cpu) = NULL;
}
- per_cpu(cpufreq_stats_table, cpu) = NULL;
}
/* must be called early in the CPU removal sequence (before
@@ -183,8 +179,14 @@ static void cpufreq_stats_free_table(unsigned int cpu)
static void cpufreq_stats_free_sysfs(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- if (policy && policy->cpu == cpu)
+
+ if (!cpufreq_frequency_get_table(cpu))
+ return;
+
+ if (policy && !policy_is_shared(policy)) {
+ pr_debug("%s: Free sysfs stat\n", __func__);
sysfs_remove_group(&policy->kobj, &stats_attr_group);
+ }
if (policy)
cpufreq_cpu_put(policy);
}
@@ -262,6 +264,19 @@ error_get_fail:
return ret;
}
+static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
+{
+ struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table,
+ policy->last_cpu);
+
+ pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n",
+ policy->cpu, policy->last_cpu);
+ per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table,
+ policy->last_cpu);
+ per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL;
+ stat->cpu = policy->cpu;
+}
+
static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
unsigned long val, void *data)
{
@@ -269,6 +284,12 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
struct cpufreq_policy *policy = data;
struct cpufreq_frequency_table *table;
unsigned int cpu = policy->cpu;
+
+ if (val == CPUFREQ_UPDATE_POLICY_CPU) {
+ cpufreq_stats_update_policy_cpu(policy);
+ return 0;
+ }
+
if (val != CPUFREQ_NOTIFY)
return 0;
table = cpufreq_frequency_get_table(cpu);
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index c8c3d293cc57..bbeb9c0720a6 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -118,8 +118,6 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
switch (event) {
case CPUFREQ_GOV_START:
- if (!cpu_online(cpu))
- return -EINVAL;
BUG_ON(!policy->cur);
mutex_lock(&userspace_mutex);
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c
index 4f154bc0ebe4..72f0c3efa76e 100644
--- a/drivers/cpufreq/db8500-cpufreq.c
+++ b/drivers/cpufreq/dbx500-cpufreq.c
@@ -1,13 +1,13 @@
/*
* Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
+ * Copyright (C) ST-Ericsson SA 2010-2012
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/cpufreq.h>
@@ -15,27 +15,27 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
-#include <mach/id.h>
static struct cpufreq_frequency_table *freq_table;
static struct clk *armss_clk;
-static struct freq_attr *db8500_cpufreq_attr[] = {
+static struct freq_attr *dbx500_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
-static int db8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
+static int dbx500_cpufreq_verify_speed(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy, freq_table);
}
-static int db8500_cpufreq_target(struct cpufreq_policy *policy,
+static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
struct cpufreq_freqs freqs;
unsigned int idx;
+ int ret;
/* scale the target frequency to one of the extremes supported */
if (target_freq < policy->cpuinfo.min_freq)
@@ -44,10 +44,9 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
target_freq = policy->cpuinfo.max_freq;
/* Lookup the next frequency */
- if (cpufreq_frequency_table_target
- (policy, freq_table, target_freq, relation, &idx)) {
+ if (cpufreq_frequency_table_target(policy, freq_table, target_freq,
+ relation, &idx))
return -EINVAL;
- }
freqs.old = policy->cur;
freqs.new = freq_table[idx].frequency;
@@ -60,9 +59,12 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* update armss clk frequency */
- if (clk_set_rate(armss_clk, freq_table[idx].frequency * 1000)) {
- pr_err("db8500-cpufreq: Failed to update armss clk\n");
- return -EINVAL;
+ ret = clk_set_rate(armss_clk, freqs.new * 1000);
+
+ if (ret) {
+ pr_err("dbx500-cpufreq: Failed to set armss_clk to %d Hz: error %d\n",
+ freqs.new * 1000, ret);
+ return ret;
}
/* post change notification */
@@ -72,7 +74,7 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
return 0;
}
-static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
+static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu)
{
int i = 0;
unsigned long freq = clk_get_rate(armss_clk) / 1000;
@@ -84,40 +86,26 @@ static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
}
/* We could not find a corresponding frequency. */
- pr_err("db8500-cpufreq: Failed to find cpufreq speed\n");
+ pr_err("dbx500-cpufreq: Failed to find cpufreq speed\n");
return 0;
}
-static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
+static int __cpuinit dbx500_cpufreq_init(struct cpufreq_policy *policy)
{
- int i = 0;
int res;
- armss_clk = clk_get(NULL, "armss");
- if (IS_ERR(armss_clk)) {
- pr_err("db8500-cpufreq : Failed to get armss clk\n");
- return PTR_ERR(armss_clk);
- }
-
- pr_info("db8500-cpufreq : Available frequencies:\n");
- while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
- pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
- i++;
- }
-
/* 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");
- clk_put(armss_clk);
+ pr_err("dbx500-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);
+ policy->cur = dbx500_cpufreq_getspeed(policy->cpu);
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
/*
@@ -128,52 +116,59 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */
/* policy sharing between dual CPUs */
- cpumask_copy(policy->cpus, cpu_present_mask);
-
- policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+ cpumask_setall(policy->cpus);
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 struct cpufreq_driver dbx500_cpufreq_driver = {
+ .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS,
+ .verify = dbx500_cpufreq_verify_speed,
+ .target = dbx500_cpufreq_target,
+ .get = dbx500_cpufreq_getspeed,
+ .init = dbx500_cpufreq_init,
+ .name = "DBX500",
+ .attr = dbx500_cpufreq_attr,
};
-static int db8500_cpufreq_probe(struct platform_device *pdev)
+static int dbx500_cpufreq_probe(struct platform_device *pdev)
{
- freq_table = dev_get_platdata(&pdev->dev);
+ int i = 0;
+ freq_table = dev_get_platdata(&pdev->dev);
if (!freq_table) {
- pr_err("db8500-cpufreq: Failed to fetch cpufreq table\n");
+ pr_err("dbx500-cpufreq: Failed to fetch cpufreq table\n");
return -ENODEV;
}
- return cpufreq_register_driver(&db8500_cpufreq_driver);
+ armss_clk = clk_get(&pdev->dev, "armss");
+ if (IS_ERR(armss_clk)) {
+ pr_err("dbx500-cpufreq: Failed to get armss clk\n");
+ return PTR_ERR(armss_clk);
+ }
+
+ pr_info("dbx500-cpufreq: Available frequencies:\n");
+ while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
+ pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
+ i++;
+ }
+
+ return cpufreq_register_driver(&dbx500_cpufreq_driver);
}
-static struct platform_driver db8500_cpufreq_plat_driver = {
+static struct platform_driver dbx500_cpufreq_plat_driver = {
.driver = {
- .name = "cpufreq-u8500",
+ .name = "cpufreq-ux500",
.owner = THIS_MODULE,
},
- .probe = db8500_cpufreq_probe,
+ .probe = dbx500_cpufreq_probe,
};
-static int __init db8500_cpufreq_register(void)
+static int __init dbx500_cpufreq_register(void)
{
- if (!cpu_is_u8500_family())
- return -ENODEV;
-
- pr_info("cpufreq for DB8500 started\n");
- return platform_driver_register(&db8500_cpufreq_plat_driver);
+ return platform_driver_register(&dbx500_cpufreq_plat_driver);
}
-device_initcall(db8500_cpufreq_register);
+device_initcall(dbx500_cpufreq_register);
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("cpufreq driver for DB8500");
+MODULE_DESCRIPTION("cpufreq driver for DBX500");
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 7012ea8bf1e7..78057a357ddb 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -18,10 +18,10 @@
#include <linux/cpufreq.h>
#include <linux/suspend.h>
-#include <mach/cpufreq.h>
-
#include <plat/cpu.h>
+#include "exynos-cpufreq.h"
+
static struct exynos_dvfs_info *exynos_info;
static struct regulator *arm_regulator;
@@ -42,51 +42,56 @@ static unsigned int exynos_getspeed(unsigned int cpu)
return clk_get_rate(exynos_info->cpu_clk) / 1000;
}
-static int exynos_target(struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
+static int exynos_cpufreq_get_index(unsigned int freq)
+{
+ struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
+ int index;
+
+ for (index = 0;
+ freq_table[index].frequency != CPUFREQ_TABLE_END; index++)
+ if (freq_table[index].frequency == freq)
+ break;
+
+ if (freq_table[index].frequency == CPUFREQ_TABLE_END)
+ return -EINVAL;
+
+ return index;
+}
+
+static int exynos_cpufreq_scale(unsigned int target_freq)
{
- unsigned int index, old_index;
- unsigned int arm_volt, safe_arm_volt = 0;
- int ret = 0;
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
unsigned int *volt_table = exynos_info->volt_table;
+ struct cpufreq_policy *policy = cpufreq_cpu_get(0);
+ unsigned int arm_volt, safe_arm_volt = 0;
unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
-
- mutex_lock(&cpufreq_lock);
+ int index, old_index;
+ int ret = 0;
freqs.old = policy->cur;
+ freqs.new = target_freq;
+ freqs.cpu = policy->cpu;
- if (frequency_locked && target_freq != locking_frequency) {
- ret = -EAGAIN;
+ if (freqs.new == freqs.old)
goto out;
- }
/*
* The policy max have been changed so that we cannot get proper
* old_index with cpufreq_frequency_table_target(). Thus, ignore
* policy and get the index from the raw freqeuncy table.
*/
- for (old_index = 0;
- freq_table[old_index].frequency != CPUFREQ_TABLE_END;
- old_index++)
- if (freq_table[old_index].frequency == freqs.old)
- break;
-
- if (freq_table[old_index].frequency == CPUFREQ_TABLE_END) {
- ret = -EINVAL;
+ old_index = exynos_cpufreq_get_index(freqs.old);
+ if (old_index < 0) {
+ ret = old_index;
goto out;
}
- if (cpufreq_frequency_table_target(policy, freq_table,
- target_freq, relation, &index)) {
- ret = -EINVAL;
+ index = exynos_cpufreq_get_index(target_freq);
+ if (index < 0) {
+ ret = index;
goto out;
}
- freqs.new = freq_table[index].frequency;
- freqs.cpu = policy->cpu;
-
/*
* ARM clock source will be changed APLL to MPLL temporary
* To support this level, need to control regulator for
@@ -106,15 +111,25 @@ static int exynos_target(struct cpufreq_policy *policy,
/* When the new frequency is higher than current frequency */
if ((freqs.new > freqs.old) && !safe_arm_volt) {
/* Firstly, voltage up to increase frequency */
- regulator_set_voltage(arm_regulator, arm_volt,
- arm_volt);
+ ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
+ if (ret) {
+ pr_err("%s: failed to set cpu voltage to %d\n",
+ __func__, arm_volt);
+ goto out;
+ }
}
- if (safe_arm_volt)
- regulator_set_voltage(arm_regulator, safe_arm_volt,
+ if (safe_arm_volt) {
+ ret = regulator_set_voltage(arm_regulator, safe_arm_volt,
safe_arm_volt);
- if (freqs.new != freqs.old)
- exynos_info->set_freq(old_index, index);
+ if (ret) {
+ pr_err("%s: failed to set cpu voltage to %d\n",
+ __func__, safe_arm_volt);
+ goto out;
+ }
+ }
+
+ exynos_info->set_freq(old_index, index);
for_each_cpu(freqs.cpu, policy->cpus)
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -125,8 +140,44 @@ static int exynos_target(struct cpufreq_policy *policy,
/* down the voltage after frequency change */
regulator_set_voltage(arm_regulator, arm_volt,
arm_volt);
+ if (ret) {
+ pr_err("%s: failed to set cpu voltage to %d\n",
+ __func__, arm_volt);
+ goto out;
+ }
+ }
+
+out:
+
+ cpufreq_cpu_put(policy);
+
+ return ret;
+}
+
+static int exynos_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
+ unsigned int index;
+ unsigned int new_freq;
+ int ret = 0;
+
+ mutex_lock(&cpufreq_lock);
+
+ if (frequency_locked)
+ goto out;
+
+ if (cpufreq_frequency_table_target(policy, freq_table,
+ target_freq, relation, &index)) {
+ ret = -EINVAL;
+ goto out;
}
+ new_freq = freq_table[index].frequency;
+
+ ret = exynos_cpufreq_scale(new_freq);
+
out:
mutex_unlock(&cpufreq_lock);
@@ -163,51 +214,26 @@ static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier,
unsigned long pm_event, void *v)
{
- struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */
- static unsigned int saved_frequency;
- unsigned int temp;
+ int ret;
- mutex_lock(&cpufreq_lock);
switch (pm_event) {
case PM_SUSPEND_PREPARE:
- if (frequency_locked)
- goto out;
-
+ mutex_lock(&cpufreq_lock);
frequency_locked = true;
+ mutex_unlock(&cpufreq_lock);
- if (locking_frequency) {
- saved_frequency = exynos_getspeed(0);
+ ret = exynos_cpufreq_scale(locking_frequency);
+ if (ret < 0)
+ return NOTIFY_BAD;
- mutex_unlock(&cpufreq_lock);
- exynos_target(policy, locking_frequency,
- CPUFREQ_RELATION_H);
- mutex_lock(&cpufreq_lock);
- }
break;
case PM_POST_SUSPEND:
- if (saved_frequency) {
- /*
- * While frequency_locked, only locking_frequency
- * is valid for target(). In order to use
- * saved_frequency while keeping frequency_locked,
- * we temporarly overwrite locking_frequency.
- */
- temp = locking_frequency;
- locking_frequency = saved_frequency;
-
- mutex_unlock(&cpufreq_lock);
- exynos_target(policy, locking_frequency,
- CPUFREQ_RELATION_H);
- mutex_lock(&cpufreq_lock);
-
- locking_frequency = temp;
- }
+ mutex_lock(&cpufreq_lock);
frequency_locked = false;
+ mutex_unlock(&cpufreq_lock);
break;
}
-out:
- mutex_unlock(&cpufreq_lock);
return NOTIFY_OK;
}
@@ -222,35 +248,34 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu);
- locking_frequency = exynos_getspeed(0);
-
/* set the transition latency value */
policy->cpuinfo.transition_latency = 100000;
- /*
- * EXYNOS4 multi-core processors has 2 cores
- * that the frequency cannot be set independently.
- * Each cpu is bound to the same speed.
- * So the affected cpu is all of the cpus.
- */
- if (num_online_cpus() == 1) {
- cpumask_copy(policy->related_cpus, cpu_possible_mask);
- cpumask_copy(policy->cpus, cpu_online_mask);
- } else {
- policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
- cpumask_setall(policy->cpus);
- }
+ cpumask_setall(policy->cpus);
return cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table);
}
+static int exynos_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static struct freq_attr *exynos_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
static struct cpufreq_driver exynos_driver = {
.flags = CPUFREQ_STICKY,
.verify = exynos_verify_speed,
.target = exynos_target,
.get = exynos_getspeed,
.init = exynos_cpufreq_cpu_init,
+ .exit = exynos_cpufreq_cpu_exit,
.name = "exynos_cpufreq",
+ .attr = exynos_cpufreq_attr,
#ifdef CONFIG_PM
.suspend = exynos_cpufreq_suspend,
.resume = exynos_cpufreq_resume,
@@ -288,6 +313,8 @@ static int __init exynos_cpufreq_init(void)
goto err_vdd_arm;
}
+ locking_frequency = exynos_getspeed(0);
+
register_pm_notifier(&exynos_cpufreq_nb);
if (cpufreq_register_driver(&exynos_driver)) {
@@ -299,8 +326,7 @@ static int __init exynos_cpufreq_init(void)
err_cpufreq:
unregister_pm_notifier(&exynos_cpufreq_nb);
- if (!IS_ERR(arm_regulator))
- regulator_put(arm_regulator);
+ regulator_put(arm_regulator);
err_vdd_arm:
kfree(exynos_info);
pr_debug("%s: failed initialization\n", __func__);
diff --git a/arch/arm/mach-exynos/include/mach/cpufreq.h b/drivers/cpufreq/exynos-cpufreq.h
index 7517c3f417af..92b852ee5ddc 100644
--- a/arch/arm/mach-exynos/include/mach/cpufreq.h
+++ b/drivers/cpufreq/exynos-cpufreq.h
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-exynos/include/mach/cpufreq.h
- *
+/*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
@@ -18,12 +17,25 @@ enum cpufreq_level_index {
L20,
};
+#define APLL_FREQ(f, a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, m, p, s) \
+ { \
+ .freq = (f) * 1000, \
+ .clk_div_cpu0 = ((a0) | (a1) << 4 | (a2) << 8 | (a3) << 12 | \
+ (a4) << 16 | (a5) << 20 | (a6) << 24 | (a7) << 28), \
+ .clk_div_cpu1 = (b0 << 0 | b1 << 4 | b2 << 8), \
+ .mps = ((m) << 16 | (p) << 8 | (s)), \
+ }
+
+struct apll_freq {
+ unsigned int freq;
+ u32 clk_div_cpu0;
+ u32 clk_div_cpu1;
+ u32 mps;
+};
+
struct exynos_dvfs_info {
unsigned long mpll_freq_khz;
unsigned int pll_safe_idx;
- unsigned int pm_lock_idx;
- unsigned int max_support_idx;
- unsigned int min_support_idx;
struct clk *cpu_clk;
unsigned int *volt_table;
struct cpufreq_frequency_table *freq_table;
diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c
index fb148fa27678..add7fbec4fc9 100644
--- a/drivers/cpufreq/exynos4210-cpufreq.c
+++ b/drivers/cpufreq/exynos4210-cpufreq.c
@@ -18,99 +18,40 @@
#include <linux/cpufreq.h>
#include <mach/regs-clock.h>
-#include <mach/cpufreq.h>
-#define CPUFREQ_LEVEL_END L5
-
-static int max_support_idx = L0;
-static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
+#include "exynos-cpufreq.h"
static struct clk *cpu_clk;
static struct clk *moutcore;
static struct clk *mout_mpll;
static struct clk *mout_apll;
-struct cpufreq_clkdiv {
- unsigned int index;
- unsigned int clkdiv;
-};
-
-static unsigned int exynos4210_volt_table[CPUFREQ_LEVEL_END] = {
+static unsigned int exynos4210_volt_table[] = {
1250000, 1150000, 1050000, 975000, 950000,
};
-
-static struct cpufreq_clkdiv exynos4210_clkdiv_table[CPUFREQ_LEVEL_END];
-
static struct cpufreq_frequency_table exynos4210_freq_table[] = {
- {L0, 1200*1000},
- {L1, 1000*1000},
- {L2, 800*1000},
- {L3, 500*1000},
- {L4, 200*1000},
+ {L0, 1200 * 1000},
+ {L1, 1000 * 1000},
+ {L2, 800 * 1000},
+ {L3, 500 * 1000},
+ {L4, 200 * 1000},
{0, CPUFREQ_TABLE_END},
};
-static unsigned int clkdiv_cpu0[CPUFREQ_LEVEL_END][7] = {
+static struct apll_freq apll_freq_4210[] = {
/*
- * Clock divider value for following
- * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
- * DIVATB, DIVPCLK_DBG, DIVAPLL }
+ * values:
+ * freq
+ * clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, RESERVED
+ * clock divider for COPY, HPM, RESERVED
+ * PLL M, P, S
*/
-
- /* ARM L0: 1200MHz */
- { 0, 3, 7, 3, 4, 1, 7 },
-
- /* ARM L1: 1000MHz */
- { 0, 3, 7, 3, 4, 1, 7 },
-
- /* ARM L2: 800MHz */
- { 0, 3, 7, 3, 3, 1, 7 },
-
- /* ARM L3: 500MHz */
- { 0, 3, 7, 3, 3, 1, 7 },
-
- /* ARM L4: 200MHz */
- { 0, 1, 3, 1, 3, 1, 0 },
-};
-
-static unsigned int clkdiv_cpu1[CPUFREQ_LEVEL_END][2] = {
- /*
- * Clock divider value for following
- * { DIVCOPY, DIVHPM }
- */
-
- /* ARM L0: 1200MHz */
- { 5, 0 },
-
- /* ARM L1: 1000MHz */
- { 4, 0 },
-
- /* ARM L2: 800MHz */
- { 3, 0 },
-
- /* ARM L3: 500MHz */
- { 3, 0 },
-
- /* ARM L4: 200MHz */
- { 3, 0 },
-};
-
-static unsigned int exynos4210_apll_pms_table[CPUFREQ_LEVEL_END] = {
- /* APLL FOUT L0: 1200MHz */
- ((150 << 16) | (3 << 8) | 1),
-
- /* APLL FOUT L1: 1000MHz */
- ((250 << 16) | (6 << 8) | 1),
-
- /* APLL FOUT L2: 800MHz */
- ((200 << 16) | (6 << 8) | 1),
-
- /* APLL FOUT L3: 500MHz */
- ((250 << 16) | (6 << 8) | 2),
-
- /* APLL FOUT L4: 200MHz */
- ((200 << 16) | (6 << 8) | 3),
+ APLL_FREQ(1200, 0, 3, 7, 3, 4, 1, 7, 0, 5, 0, 0, 150, 3, 1),
+ APLL_FREQ(1000, 0, 3, 7, 3, 4, 1, 7, 0, 4, 0, 0, 250, 6, 1),
+ APLL_FREQ(800, 0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 200, 6, 1),
+ APLL_FREQ(500, 0, 3, 7, 3, 3, 1, 7, 0, 3, 0, 0, 250, 6, 2),
+ APLL_FREQ(200, 0, 1, 3, 1, 3, 1, 0, 0, 3, 0, 0, 200, 6, 3),
};
static void exynos4210_set_clkdiv(unsigned int div_index)
@@ -119,7 +60,7 @@ static void exynos4210_set_clkdiv(unsigned int div_index)
/* Change Divider - CPU0 */
- tmp = exynos4210_clkdiv_table[div_index].clkdiv;
+ tmp = apll_freq_4210[div_index].clk_div_cpu0;
__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
@@ -129,12 +70,7 @@ static void exynos4210_set_clkdiv(unsigned int div_index)
/* Change Divider - CPU1 */
- tmp = __raw_readl(EXYNOS4_CLKDIV_CPU1);
-
- tmp &= ~((0x7 << 4) | 0x7);
-
- tmp |= ((clkdiv_cpu1[div_index][0] << 4) |
- (clkdiv_cpu1[div_index][1] << 0));
+ tmp = apll_freq_4210[div_index].clk_div_cpu1;
__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
@@ -162,7 +98,7 @@ static void exynos4210_set_apll(unsigned int index)
/* 3. Change PLL PMS values */
tmp = __raw_readl(EXYNOS4_APLL_CON0);
tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
- tmp |= exynos4210_apll_pms_table[index];
+ tmp |= apll_freq_4210[index].mps;
__raw_writel(tmp, EXYNOS4_APLL_CON0);
/* 4. wait_lock_time */
@@ -179,10 +115,10 @@ static void exynos4210_set_apll(unsigned int index)
} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
}
-bool exynos4210_pms_change(unsigned int old_index, unsigned int new_index)
+static bool exynos4210_pms_change(unsigned int old_index, unsigned int new_index)
{
- unsigned int old_pm = (exynos4210_apll_pms_table[old_index] >> 8);
- unsigned int new_pm = (exynos4210_apll_pms_table[new_index] >> 8);
+ unsigned int old_pm = apll_freq_4210[old_index].mps >> 8;
+ unsigned int new_pm = apll_freq_4210[new_index].mps >> 8;
return (old_pm == new_pm) ? 0 : 1;
}
@@ -200,7 +136,7 @@ static void exynos4210_set_frequency(unsigned int old_index,
/* 2. Change just s value in apll m,p,s value */
tmp = __raw_readl(EXYNOS4_APLL_CON0);
tmp &= ~(0x7 << 0);
- tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
+ tmp |= apll_freq_4210[new_index].mps & 0x7;
__raw_writel(tmp, EXYNOS4_APLL_CON0);
} else {
/* Clock Configuration Procedure */
@@ -214,7 +150,7 @@ static void exynos4210_set_frequency(unsigned int old_index,
/* 1. Change just s value in apll m,p,s value */
tmp = __raw_readl(EXYNOS4_APLL_CON0);
tmp &= ~(0x7 << 0);
- tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
+ tmp |= apll_freq_4210[new_index].mps & 0x7;
__raw_writel(tmp, EXYNOS4_APLL_CON0);
/* 2. Change the system clock divider values */
@@ -231,8 +167,6 @@ static void exynos4210_set_frequency(unsigned int old_index,
int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
{
- int i;
- unsigned int tmp;
unsigned long rate;
cpu_clk = clk_get(NULL, "armclk");
@@ -253,33 +187,9 @@ int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
if (IS_ERR(mout_apll))
goto err_mout_apll;
- tmp = __raw_readl(EXYNOS4_CLKDIV_CPU);
-
- for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
- tmp &= ~(EXYNOS4_CLKDIV_CPU0_CORE_MASK |
- EXYNOS4_CLKDIV_CPU0_COREM0_MASK |
- EXYNOS4_CLKDIV_CPU0_COREM1_MASK |
- EXYNOS4_CLKDIV_CPU0_PERIPH_MASK |
- EXYNOS4_CLKDIV_CPU0_ATB_MASK |
- EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK |
- EXYNOS4_CLKDIV_CPU0_APLL_MASK);
-
- tmp |= ((clkdiv_cpu0[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
- (clkdiv_cpu0[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
- (clkdiv_cpu0[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
- (clkdiv_cpu0[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
- (clkdiv_cpu0[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
- (clkdiv_cpu0[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
- (clkdiv_cpu0[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT));
-
- exynos4210_clkdiv_table[i].clkdiv = tmp;
- }
-
info->mpll_freq_khz = rate;
- info->pm_lock_idx = L2;
+ /* 800Mhz */
info->pll_safe_idx = L2;
- info->max_support_idx = max_support_idx;
- info->min_support_idx = min_support_idx;
info->cpu_clk = cpu_clk;
info->volt_table = exynos4210_volt_table;
info->freq_table = exynos4210_freq_table;
@@ -289,14 +199,11 @@ int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
return 0;
err_mout_apll:
- if (!IS_ERR(mout_mpll))
- clk_put(mout_mpll);
+ clk_put(mout_mpll);
err_mout_mpll:
- if (!IS_ERR(moutcore))
- clk_put(moutcore);
+ clk_put(moutcore);
err_moutcore:
- if (!IS_ERR(cpu_clk))
- clk_put(cpu_clk);
+ clk_put(cpu_clk);
pr_debug("%s: failed initialization\n", __func__);
return -EINVAL;
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
index 8c5a7afa5b0b..08b7477b0aa2 100644
--- a/drivers/cpufreq/exynos4x12-cpufreq.c
+++ b/drivers/cpufreq/exynos4x12-cpufreq.c
@@ -18,28 +18,21 @@
#include <linux/cpufreq.h>
#include <mach/regs-clock.h>
-#include <mach/cpufreq.h>
-#define CPUFREQ_LEVEL_END (L13 + 1)
-
-static int max_support_idx;
-static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
+#include "exynos-cpufreq.h"
static struct clk *cpu_clk;
static struct clk *moutcore;
static struct clk *mout_mpll;
static struct clk *mout_apll;
-struct cpufreq_clkdiv {
- unsigned int index;
- unsigned int clkdiv;
- unsigned int clkdiv1;
+static unsigned int exynos4x12_volt_table[] = {
+ 1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
+ 1000000, 987500, 975000, 950000, 925000, 900000, 900000
};
-static unsigned int exynos4x12_volt_table[CPUFREQ_LEVEL_END];
-
static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
- {L0, 1500 * 1000},
+ {L0, CPUFREQ_ENTRY_INVALID},
{L1, 1400 * 1000},
{L2, 1300 * 1000},
{L3, 1200 * 1000},
@@ -56,247 +49,54 @@ static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
{0, CPUFREQ_TABLE_END},
};
-static struct cpufreq_clkdiv exynos4x12_clkdiv_table[CPUFREQ_LEVEL_END];
+static struct apll_freq *apll_freq_4x12;
-static unsigned int clkdiv_cpu0_4212[CPUFREQ_LEVEL_END][8] = {
+static struct apll_freq apll_freq_4212[] = {
/*
- * Clock divider value for following
- * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
- * DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
+ * values:
+ * freq
+ * clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, CORE2
+ * clock divider for COPY, HPM, RESERVED
+ * PLL M, P, S
*/
- /* ARM L0: 1500 MHz */
- { 0, 3, 7, 0, 6, 1, 2, 0 },
-
- /* ARM L1: 1400 MHz */
- { 0, 3, 7, 0, 6, 1, 2, 0 },
-
- /* ARM L2: 1300 MHz */
- { 0, 3, 7, 0, 5, 1, 2, 0 },
-
- /* ARM L3: 1200 MHz */
- { 0, 3, 7, 0, 5, 1, 2, 0 },
-
- /* ARM L4: 1100 MHz */
- { 0, 3, 6, 0, 4, 1, 2, 0 },
-
- /* ARM L5: 1000 MHz */
- { 0, 2, 5, 0, 4, 1, 1, 0 },
-
- /* ARM L6: 900 MHz */
- { 0, 2, 5, 0, 3, 1, 1, 0 },
-
- /* ARM L7: 800 MHz */
- { 0, 2, 5, 0, 3, 1, 1, 0 },
-
- /* ARM L8: 700 MHz */
- { 0, 2, 4, 0, 3, 1, 1, 0 },
-
- /* ARM L9: 600 MHz */
- { 0, 2, 4, 0, 3, 1, 1, 0 },
-
- /* ARM L10: 500 MHz */
- { 0, 2, 4, 0, 3, 1, 1, 0 },
-
- /* ARM L11: 400 MHz */
- { 0, 2, 4, 0, 3, 1, 1, 0 },
-
- /* ARM L12: 300 MHz */
- { 0, 2, 4, 0, 2, 1, 1, 0 },
-
- /* ARM L13: 200 MHz */
- { 0, 1, 3, 0, 1, 1, 1, 0 },
+ APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 250, 4, 0),
+ APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 2, 0, 175, 3, 0),
+ APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 325, 6, 0),
+ APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 2, 0, 200, 4, 0),
+ APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 2, 0, 275, 6, 0),
+ APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 2, 0, 125, 3, 0),
+ APLL_FREQ(900, 0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 150, 4, 0),
+ APLL_FREQ(800, 0, 2, 5, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 0),
+ APLL_FREQ(700, 0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 175, 3, 1),
+ APLL_FREQ(600, 0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 200, 4, 1),
+ APLL_FREQ(500, 0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 125, 3, 1),
+ APLL_FREQ(400, 0, 2, 4, 0, 3, 1, 1, 0, 3, 2, 0, 100, 3, 1),
+ APLL_FREQ(300, 0, 2, 4, 0, 2, 1, 1, 0, 3, 2, 0, 200, 4, 2),
+ APLL_FREQ(200, 0, 1, 3, 0, 1, 1, 1, 0, 3, 2, 0, 100, 3, 2),
};
-static unsigned int clkdiv_cpu0_4412[CPUFREQ_LEVEL_END][8] = {
+static struct apll_freq apll_freq_4412[] = {
/*
- * Clock divider value for following
- * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
- * DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
- */
- /* ARM L0: 1500 MHz */
- { 0, 3, 7, 0, 6, 1, 2, 0 },
-
- /* ARM L1: 1400 MHz */
- { 0, 3, 7, 0, 6, 1, 2, 0 },
-
- /* ARM L2: 1300 MHz */
- { 0, 3, 7, 0, 5, 1, 2, 0 },
-
- /* ARM L3: 1200 MHz */
- { 0, 3, 7, 0, 5, 1, 2, 0 },
-
- /* ARM L4: 1100 MHz */
- { 0, 3, 6, 0, 4, 1, 2, 0 },
-
- /* ARM L5: 1000 MHz */
- { 0, 2, 5, 0, 4, 1, 1, 0 },
-
- /* ARM L6: 900 MHz */
- { 0, 2, 5, 0, 3, 1, 1, 0 },
-
- /* ARM L7: 800 MHz */
- { 0, 2, 5, 0, 3, 1, 1, 0 },
-
- /* ARM L8: 700 MHz */
- { 0, 2, 4, 0, 3, 1, 1, 0 },
-
- /* ARM L9: 600 MHz */
- { 0, 2, 4, 0, 3, 1, 1, 0 },
-
- /* ARM L10: 500 MHz */
- { 0, 2, 4, 0, 3, 1, 1, 0 },
-
- /* ARM L11: 400 MHz */
- { 0, 2, 4, 0, 3, 1, 1, 0 },
-
- /* ARM L12: 300 MHz */
- { 0, 2, 4, 0, 2, 1, 1, 0 },
-
- /* ARM L13: 200 MHz */
- { 0, 1, 3, 0, 1, 1, 1, 0 },
-};
-
-static unsigned int clkdiv_cpu1_4212[CPUFREQ_LEVEL_END][2] = {
- /* Clock divider value for following
- * { DIVCOPY, DIVHPM }
+ * values:
+ * freq
+ * clock divider for CORE, COREM0, COREM1, PERIPH, ATB, PCLK_DBG, APLL, CORE2
+ * clock divider for COPY, HPM, CORES
+ * PLL M, P, S
*/
- /* ARM L0: 1500 MHz */
- { 6, 0 },
-
- /* ARM L1: 1400 MHz */
- { 6, 0 },
-
- /* ARM L2: 1300 MHz */
- { 5, 0 },
-
- /* ARM L3: 1200 MHz */
- { 5, 0 },
-
- /* ARM L4: 1100 MHz */
- { 4, 0 },
-
- /* ARM L5: 1000 MHz */
- { 4, 0 },
-
- /* ARM L6: 900 MHz */
- { 3, 0 },
-
- /* ARM L7: 800 MHz */
- { 3, 0 },
-
- /* ARM L8: 700 MHz */
- { 3, 0 },
-
- /* ARM L9: 600 MHz */
- { 3, 0 },
-
- /* ARM L10: 500 MHz */
- { 3, 0 },
-
- /* ARM L11: 400 MHz */
- { 3, 0 },
-
- /* ARM L12: 300 MHz */
- { 3, 0 },
-
- /* ARM L13: 200 MHz */
- { 3, 0 },
-};
-
-static unsigned int clkdiv_cpu1_4412[CPUFREQ_LEVEL_END][3] = {
- /* Clock divider value for following
- * { DIVCOPY, DIVHPM, DIVCORES }
- */
- /* ARM L0: 1500 MHz */
- { 6, 0, 7 },
-
- /* ARM L1: 1400 MHz */
- { 6, 0, 6 },
-
- /* ARM L2: 1300 MHz */
- { 5, 0, 6 },
-
- /* ARM L3: 1200 MHz */
- { 5, 0, 5 },
-
- /* ARM L4: 1100 MHz */
- { 4, 0, 5 },
-
- /* ARM L5: 1000 MHz */
- { 4, 0, 4 },
-
- /* ARM L6: 900 MHz */
- { 3, 0, 4 },
-
- /* ARM L7: 800 MHz */
- { 3, 0, 3 },
-
- /* ARM L8: 700 MHz */
- { 3, 0, 3 },
-
- /* ARM L9: 600 MHz */
- { 3, 0, 2 },
-
- /* ARM L10: 500 MHz */
- { 3, 0, 2 },
-
- /* ARM L11: 400 MHz */
- { 3, 0, 1 },
-
- /* ARM L12: 300 MHz */
- { 3, 0, 1 },
-
- /* ARM L13: 200 MHz */
- { 3, 0, 0 },
-};
-
-static unsigned int exynos4x12_apll_pms_table[CPUFREQ_LEVEL_END] = {
- /* APLL FOUT L0: 1500 MHz */
- ((250 << 16) | (4 << 8) | (0x0)),
-
- /* APLL FOUT L1: 1400 MHz */
- ((175 << 16) | (3 << 8) | (0x0)),
-
- /* APLL FOUT L2: 1300 MHz */
- ((325 << 16) | (6 << 8) | (0x0)),
-
- /* APLL FOUT L3: 1200 MHz */
- ((200 << 16) | (4 << 8) | (0x0)),
-
- /* APLL FOUT L4: 1100 MHz */
- ((275 << 16) | (6 << 8) | (0x0)),
-
- /* APLL FOUT L5: 1000 MHz */
- ((125 << 16) | (3 << 8) | (0x0)),
-
- /* APLL FOUT L6: 900 MHz */
- ((150 << 16) | (4 << 8) | (0x0)),
-
- /* APLL FOUT L7: 800 MHz */
- ((100 << 16) | (3 << 8) | (0x0)),
-
- /* APLL FOUT L8: 700 MHz */
- ((175 << 16) | (3 << 8) | (0x1)),
-
- /* APLL FOUT L9: 600 MHz */
- ((200 << 16) | (4 << 8) | (0x1)),
-
- /* APLL FOUT L10: 500 MHz */
- ((125 << 16) | (3 << 8) | (0x1)),
-
- /* APLL FOUT L11 400 MHz */
- ((100 << 16) | (3 << 8) | (0x1)),
-
- /* APLL FOUT L12: 300 MHz */
- ((200 << 16) | (4 << 8) | (0x2)),
-
- /* APLL FOUT L13: 200 MHz */
- ((100 << 16) | (3 << 8) | (0x2)),
-};
-
-static const unsigned int asv_voltage_4x12[CPUFREQ_LEVEL_END] = {
- 1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
- 1000000, 987500, 975000, 950000, 925000, 900000, 900000
+ APLL_FREQ(1500, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 7, 250, 4, 0),
+ APLL_FREQ(1400, 0, 3, 7, 0, 6, 1, 2, 0, 6, 0, 6, 175, 3, 0),
+ APLL_FREQ(1300, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 6, 325, 6, 0),
+ APLL_FREQ(1200, 0, 3, 7, 0, 5, 1, 2, 0, 5, 0, 5, 200, 4, 0),
+ APLL_FREQ(1100, 0, 3, 6, 0, 4, 1, 2, 0, 4, 0, 5, 275, 6, 0),
+ APLL_FREQ(1000, 0, 2, 5, 0, 4, 1, 1, 0, 4, 0, 4, 125, 3, 0),
+ APLL_FREQ(900, 0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 4, 150, 4, 0),
+ APLL_FREQ(800, 0, 2, 5, 0, 3, 1, 1, 0, 3, 0, 3, 100, 3, 0),
+ APLL_FREQ(700, 0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 3, 175, 3, 1),
+ APLL_FREQ(600, 0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 200, 4, 1),
+ APLL_FREQ(500, 0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 2, 125, 3, 1),
+ APLL_FREQ(400, 0, 2, 4, 0, 3, 1, 1, 0, 3, 0, 1, 100, 3, 1),
+ APLL_FREQ(300, 0, 2, 4, 0, 2, 1, 1, 0, 3, 0, 1, 200, 4, 2),
+ APLL_FREQ(200, 0, 1, 3, 0, 1, 1, 1, 0, 3, 0, 0, 100, 3, 2),
};
static void exynos4x12_set_clkdiv(unsigned int div_index)
@@ -306,7 +106,7 @@ static void exynos4x12_set_clkdiv(unsigned int div_index)
/* Change Divider - CPU0 */
- tmp = exynos4x12_clkdiv_table[div_index].clkdiv;
+ tmp = apll_freq_4x12[div_index].clk_div_cpu0;
__raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
@@ -314,7 +114,7 @@ static void exynos4x12_set_clkdiv(unsigned int div_index)
cpu_relax();
/* Change Divider - CPU1 */
- tmp = exynos4x12_clkdiv_table[div_index].clkdiv1;
+ tmp = apll_freq_4x12[div_index].clk_div_cpu1;
__raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
if (soc_is_exynos4212())
@@ -341,14 +141,14 @@ static void exynos4x12_set_apll(unsigned int index)
} while (tmp != 0x2);
/* 2. Set APLL Lock time */
- pdiv = ((exynos4x12_apll_pms_table[index] >> 8) & 0x3f);
+ pdiv = ((apll_freq_4x12[index].mps >> 8) & 0x3f);
__raw_writel((pdiv * 250), EXYNOS4_APLL_LOCK);
/* 3. Change PLL PMS values */
tmp = __raw_readl(EXYNOS4_APLL_CON0);
tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
- tmp |= exynos4x12_apll_pms_table[index];
+ tmp |= apll_freq_4x12[index].mps;
__raw_writel(tmp, EXYNOS4_APLL_CON0);
/* 4. wait_lock_time */
@@ -367,10 +167,10 @@ static void exynos4x12_set_apll(unsigned int index)
} while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
}
-bool exynos4x12_pms_change(unsigned int old_index, unsigned int new_index)
+static bool exynos4x12_pms_change(unsigned int old_index, unsigned int new_index)
{
- unsigned int old_pm = exynos4x12_apll_pms_table[old_index] >> 8;
- unsigned int new_pm = exynos4x12_apll_pms_table[new_index] >> 8;
+ unsigned int old_pm = apll_freq_4x12[old_index].mps >> 8;
+ unsigned int new_pm = apll_freq_4x12[new_index].mps >> 8;
return (old_pm == new_pm) ? 0 : 1;
}
@@ -387,7 +187,7 @@ static void exynos4x12_set_frequency(unsigned int old_index,
/* 2. Change just s value in apll m,p,s value */
tmp = __raw_readl(EXYNOS4_APLL_CON0);
tmp &= ~(0x7 << 0);
- tmp |= (exynos4x12_apll_pms_table[new_index] & 0x7);
+ tmp |= apll_freq_4x12[new_index].mps & 0x7;
__raw_writel(tmp, EXYNOS4_APLL_CON0);
} else {
@@ -402,7 +202,7 @@ static void exynos4x12_set_frequency(unsigned int old_index,
/* 1. Change just s value in apll m,p,s value */
tmp = __raw_readl(EXYNOS4_APLL_CON0);
tmp &= ~(0x7 << 0);
- tmp |= (exynos4x12_apll_pms_table[new_index] & 0x7);
+ tmp |= apll_freq_4x12[new_index].mps & 0x7;
__raw_writel(tmp, EXYNOS4_APLL_CON0);
/* 2. Change the system clock divider values */
exynos4x12_set_clkdiv(new_index);
@@ -416,27 +216,10 @@ static void exynos4x12_set_frequency(unsigned int old_index,
}
}
-static void __init set_volt_table(void)
-{
- unsigned int i;
-
- max_support_idx = L1;
-
- /* Not supported */
- exynos4x12_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
-
- for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
- exynos4x12_volt_table[i] = asv_voltage_4x12[i];
-}
-
int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
{
- int i;
- unsigned int tmp;
unsigned long rate;
- set_volt_table();
-
cpu_clk = clk_get(NULL, "armclk");
if (IS_ERR(cpu_clk))
return PTR_ERR(cpu_clk);
@@ -455,66 +238,14 @@ int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
if (IS_ERR(mout_apll))
goto err_mout_apll;
- for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
-
- exynos4x12_clkdiv_table[i].index = i;
-
- tmp = __raw_readl(EXYNOS4_CLKDIV_CPU);
-
- tmp &= ~(EXYNOS4_CLKDIV_CPU0_CORE_MASK |
- EXYNOS4_CLKDIV_CPU0_COREM0_MASK |
- EXYNOS4_CLKDIV_CPU0_COREM1_MASK |
- EXYNOS4_CLKDIV_CPU0_PERIPH_MASK |
- EXYNOS4_CLKDIV_CPU0_ATB_MASK |
- EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK |
- EXYNOS4_CLKDIV_CPU0_APLL_MASK);
-
- if (soc_is_exynos4212()) {
- tmp |= ((clkdiv_cpu0_4212[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
- (clkdiv_cpu0_4212[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
- (clkdiv_cpu0_4212[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
- (clkdiv_cpu0_4212[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
- (clkdiv_cpu0_4212[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
- (clkdiv_cpu0_4212[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
- (clkdiv_cpu0_4212[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT));
- } else {
- tmp &= ~EXYNOS4_CLKDIV_CPU0_CORE2_MASK;
-
- tmp |= ((clkdiv_cpu0_4412[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
- (clkdiv_cpu0_4412[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
- (clkdiv_cpu0_4412[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
- (clkdiv_cpu0_4412[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
- (clkdiv_cpu0_4412[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
- (clkdiv_cpu0_4412[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
- (clkdiv_cpu0_4412[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT) |
- (clkdiv_cpu0_4412[i][7] << EXYNOS4_CLKDIV_CPU0_CORE2_SHIFT));
- }
-
- exynos4x12_clkdiv_table[i].clkdiv = tmp;
-
- tmp = __raw_readl(EXYNOS4_CLKDIV_CPU1);
-
- if (soc_is_exynos4212()) {
- tmp &= ~(EXYNOS4_CLKDIV_CPU1_COPY_MASK |
- EXYNOS4_CLKDIV_CPU1_HPM_MASK);
- tmp |= ((clkdiv_cpu1_4212[i][0] << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT) |
- (clkdiv_cpu1_4212[i][1] << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT));
- } else {
- tmp &= ~(EXYNOS4_CLKDIV_CPU1_COPY_MASK |
- EXYNOS4_CLKDIV_CPU1_HPM_MASK |
- EXYNOS4_CLKDIV_CPU1_CORES_MASK);
- tmp |= ((clkdiv_cpu1_4412[i][0] << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT) |
- (clkdiv_cpu1_4412[i][1] << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT) |
- (clkdiv_cpu1_4412[i][2] << EXYNOS4_CLKDIV_CPU1_CORES_SHIFT));
- }
- exynos4x12_clkdiv_table[i].clkdiv1 = tmp;
- }
+ if (soc_is_exynos4212())
+ apll_freq_4x12 = apll_freq_4212;
+ else
+ apll_freq_4x12 = apll_freq_4412;
info->mpll_freq_khz = rate;
- info->pm_lock_idx = L5;
+ /* 800Mhz */
info->pll_safe_idx = L7;
- info->max_support_idx = max_support_idx;
- info->min_support_idx = min_support_idx;
info->cpu_clk = cpu_clk;
info->volt_table = exynos4x12_volt_table;
info->freq_table = exynos4x12_freq_table;
diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c
index e64c253cb169..9fae466d7746 100644
--- a/drivers/cpufreq/exynos5250-cpufreq.c
+++ b/drivers/cpufreq/exynos5250-cpufreq.c
@@ -19,25 +19,21 @@
#include <mach/map.h>
#include <mach/regs-clock.h>
-#include <mach/cpufreq.h>
-#define CPUFREQ_LEVEL_END (L15 + 1)
+#include "exynos-cpufreq.h"
-static int max_support_idx;
-static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
static struct clk *cpu_clk;
static struct clk *moutcore;
static struct clk *mout_mpll;
static struct clk *mout_apll;
-struct cpufreq_clkdiv {
- unsigned int index;
- unsigned int clkdiv;
- unsigned int clkdiv1;
+static unsigned int exynos5250_volt_table[] = {
+ 1300000, 1250000, 1225000, 1200000, 1150000,
+ 1125000, 1100000, 1075000, 1050000, 1025000,
+ 1012500, 1000000, 975000, 950000, 937500,
+ 925000
};
-static unsigned int exynos5250_volt_table[CPUFREQ_LEVEL_END];
-
static struct cpufreq_frequency_table exynos5250_freq_table[] = {
{L0, 1700 * 1000},
{L1, 1600 * 1000},
@@ -47,8 +43,8 @@ static struct cpufreq_frequency_table exynos5250_freq_table[] = {
{L5, 1200 * 1000},
{L6, 1100 * 1000},
{L7, 1000 * 1000},
- {L8, 900 * 1000},
- {L9, 800 * 1000},
+ {L8, 900 * 1000},
+ {L9, 800 * 1000},
{L10, 700 * 1000},
{L11, 600 * 1000},
{L12, 500 * 1000},
@@ -58,78 +54,30 @@ static struct cpufreq_frequency_table exynos5250_freq_table[] = {
{0, CPUFREQ_TABLE_END},
};
-static struct cpufreq_clkdiv exynos5250_clkdiv_table[CPUFREQ_LEVEL_END];
-
-static unsigned int clkdiv_cpu0_5250[CPUFREQ_LEVEL_END][8] = {
+static struct apll_freq apll_freq_5250[] = {
/*
- * Clock divider value for following
- * { ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2 }
- */
- { 0, 3, 7, 7, 7, 3, 5, 0 }, /* 1700 MHz */
- { 0, 3, 7, 7, 7, 1, 4, 0 }, /* 1600 MHz */
- { 0, 2, 7, 7, 7, 1, 4, 0 }, /* 1500 MHz */
- { 0, 2, 7, 7, 6, 1, 4, 0 }, /* 1400 MHz */
- { 0, 2, 7, 7, 6, 1, 3, 0 }, /* 1300 MHz */
- { 0, 2, 7, 7, 5, 1, 3, 0 }, /* 1200 MHz */
- { 0, 3, 7, 7, 5, 1, 3, 0 }, /* 1100 MHz */
- { 0, 1, 7, 7, 4, 1, 2, 0 }, /* 1000 MHz */
- { 0, 1, 7, 7, 4, 1, 2, 0 }, /* 900 MHz */
- { 0, 1, 7, 7, 4, 1, 2, 0 }, /* 800 MHz */
- { 0, 1, 7, 7, 3, 1, 1, 0 }, /* 700 MHz */
- { 0, 1, 7, 7, 3, 1, 1, 0 }, /* 600 MHz */
- { 0, 1, 7, 7, 2, 1, 1, 0 }, /* 500 MHz */
- { 0, 1, 7, 7, 2, 1, 1, 0 }, /* 400 MHz */
- { 0, 1, 7, 7, 1, 1, 1, 0 }, /* 300 MHz */
- { 0, 1, 7, 7, 1, 1, 1, 0 }, /* 200 MHz */
-};
-
-static unsigned int clkdiv_cpu1_5250[CPUFREQ_LEVEL_END][2] = {
- /* Clock divider value for following
- * { COPY, HPM }
+ * values:
+ * freq
+ * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2
+ * clock divider for COPY, HPM, RESERVED
+ * PLL M, P, S
*/
- { 0, 2 }, /* 1700 MHz */
- { 0, 2 }, /* 1600 MHz */
- { 0, 2 }, /* 1500 MHz */
- { 0, 2 }, /* 1400 MHz */
- { 0, 2 }, /* 1300 MHz */
- { 0, 2 }, /* 1200 MHz */
- { 0, 2 }, /* 1100 MHz */
- { 0, 2 }, /* 1000 MHz */
- { 0, 2 }, /* 900 MHz */
- { 0, 2 }, /* 800 MHz */
- { 0, 2 }, /* 700 MHz */
- { 0, 2 }, /* 600 MHz */
- { 0, 2 }, /* 500 MHz */
- { 0, 2 }, /* 400 MHz */
- { 0, 2 }, /* 300 MHz */
- { 0, 2 }, /* 200 MHz */
-};
-
-static unsigned int exynos5_apll_pms_table[CPUFREQ_LEVEL_END] = {
- ((425 << 16) | (6 << 8) | 0), /* 1700 MHz */
- ((200 << 16) | (3 << 8) | 0), /* 1600 MHz */
- ((250 << 16) | (4 << 8) | 0), /* 1500 MHz */
- ((175 << 16) | (3 << 8) | 0), /* 1400 MHz */
- ((325 << 16) | (6 << 8) | 0), /* 1300 MHz */
- ((200 << 16) | (4 << 8) | 0), /* 1200 MHz */
- ((275 << 16) | (6 << 8) | 0), /* 1100 MHz */
- ((125 << 16) | (3 << 8) | 0), /* 1000 MHz */
- ((150 << 16) | (4 << 8) | 0), /* 900 MHz */
- ((100 << 16) | (3 << 8) | 0), /* 800 MHz */
- ((175 << 16) | (3 << 8) | 1), /* 700 MHz */
- ((200 << 16) | (4 << 8) | 1), /* 600 MHz */
- ((125 << 16) | (3 << 8) | 1), /* 500 MHz */
- ((100 << 16) | (3 << 8) | 1), /* 400 MHz */
- ((200 << 16) | (4 << 8) | 2), /* 300 MHz */
- ((100 << 16) | (3 << 8) | 2), /* 200 MHz */
-};
-
-/* ASV group voltage table */
-static const unsigned int asv_voltage_5250[CPUFREQ_LEVEL_END] = {
- 1300000, 1250000, 1225000, 1200000, 1150000,
- 1125000, 1100000, 1075000, 1050000, 1025000,
- 1012500, 1000000, 975000, 950000, 937500,
- 925000
+ APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0),
+ APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0),
+ APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0),
+ APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0),
+ APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0),
+ APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0),
+ APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0),
+ APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0),
+ APLL_FREQ(900, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0),
+ APLL_FREQ(800, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0),
+ APLL_FREQ(700, 0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1),
+ APLL_FREQ(600, 0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1),
+ APLL_FREQ(500, 0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1),
+ APLL_FREQ(400, 0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1),
+ APLL_FREQ(300, 0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2),
+ APLL_FREQ(200, 0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2),
};
static void set_clkdiv(unsigned int div_index)
@@ -138,7 +86,7 @@ static void set_clkdiv(unsigned int div_index)
/* Change Divider - CPU0 */
- tmp = exynos5250_clkdiv_table[div_index].clkdiv;
+ tmp = apll_freq_5250[div_index].clk_div_cpu0;
__raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
@@ -146,7 +94,7 @@ static void set_clkdiv(unsigned int div_index)
cpu_relax();
/* Change Divider - CPU1 */
- tmp = exynos5250_clkdiv_table[div_index].clkdiv1;
+ tmp = apll_freq_5250[div_index].clk_div_cpu1;
__raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
@@ -169,14 +117,14 @@ static void set_apll(unsigned int new_index,
} while (tmp != 0x2);
/* 2. Set APLL Lock time */
- pdiv = ((exynos5_apll_pms_table[new_index] >> 8) & 0x3f);
+ pdiv = ((apll_freq_5250[new_index].mps >> 8) & 0x3f);
__raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
/* 3. Change PLL PMS values */
tmp = __raw_readl(EXYNOS5_APLL_CON0);
tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
- tmp |= exynos5_apll_pms_table[new_index];
+ tmp |= apll_freq_5250[new_index].mps;
__raw_writel(tmp, EXYNOS5_APLL_CON0);
/* 4. wait_lock_time */
@@ -196,10 +144,10 @@ static void set_apll(unsigned int new_index,
}
-bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
+static bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
{
- unsigned int old_pm = (exynos5_apll_pms_table[old_index] >> 8);
- unsigned int new_pm = (exynos5_apll_pms_table[new_index] >> 8);
+ unsigned int old_pm = apll_freq_5250[old_index].mps >> 8;
+ unsigned int new_pm = apll_freq_5250[new_index].mps >> 8;
return (old_pm == new_pm) ? 0 : 1;
}
@@ -216,7 +164,7 @@ static void exynos5250_set_frequency(unsigned int old_index,
/* 2. Change just s value in apll m,p,s value */
tmp = __raw_readl(EXYNOS5_APLL_CON0);
tmp &= ~(0x7 << 0);
- tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
+ tmp |= apll_freq_5250[new_index].mps & 0x7;
__raw_writel(tmp, EXYNOS5_APLL_CON0);
} else {
@@ -231,7 +179,7 @@ static void exynos5250_set_frequency(unsigned int old_index,
/* 1. Change just s value in apll m,p,s value */
tmp = __raw_readl(EXYNOS5_APLL_CON0);
tmp &= ~(0x7 << 0);
- tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
+ tmp |= apll_freq_5250[new_index].mps & 0x7;
__raw_writel(tmp, EXYNOS5_APLL_CON0);
/* 2. Change the system clock divider values */
set_clkdiv(new_index);
@@ -245,24 +193,10 @@ static void exynos5250_set_frequency(unsigned int old_index,
}
}
-static void __init set_volt_table(void)
-{
- unsigned int i;
-
- max_support_idx = L0;
-
- for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
- exynos5250_volt_table[i] = asv_voltage_5250[i];
-}
-
int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
{
- int i;
- unsigned int tmp;
unsigned long rate;
- set_volt_table();
-
cpu_clk = clk_get(NULL, "armclk");
if (IS_ERR(cpu_clk))
return PTR_ERR(cpu_clk);
@@ -281,44 +215,9 @@ int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
if (IS_ERR(mout_apll))
goto err_mout_apll;
- for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
-
- exynos5250_clkdiv_table[i].index = i;
-
- tmp = __raw_readl(EXYNOS5_CLKDIV_CPU0);
-
- tmp &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) |
- (0x7 << 12) | (0x7 << 16) | (0x7 << 20) |
- (0x7 << 24) | (0x7 << 28));
-
- tmp |= ((clkdiv_cpu0_5250[i][0] << 0) |
- (clkdiv_cpu0_5250[i][1] << 4) |
- (clkdiv_cpu0_5250[i][2] << 8) |
- (clkdiv_cpu0_5250[i][3] << 12) |
- (clkdiv_cpu0_5250[i][4] << 16) |
- (clkdiv_cpu0_5250[i][5] << 20) |
- (clkdiv_cpu0_5250[i][6] << 24) |
- (clkdiv_cpu0_5250[i][7] << 28));
-
- exynos5250_clkdiv_table[i].clkdiv = tmp;
-
- tmp = __raw_readl(EXYNOS5_CLKDIV_CPU1);
-
- tmp &= ~((0x7 << 0) | (0x7 << 4));
-
- tmp |= ((clkdiv_cpu1_5250[i][0] << 0) |
- (clkdiv_cpu1_5250[i][1] << 4));
-
- exynos5250_clkdiv_table[i].clkdiv1 = tmp;
- }
-
info->mpll_freq_khz = rate;
- /* 1000Mhz */
- info->pm_lock_idx = L7;
/* 800Mhz */
info->pll_safe_idx = L9;
- info->max_support_idx = max_support_idx;
- info->min_support_idx = min_support_idx;
info->cpu_clk = cpu_clk;
info->volt_table = exynos5250_volt_table;
info->freq_table = exynos5250_freq_table;
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 49cda256efb2..d7a79662e24c 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -63,9 +63,6 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
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))
- return -EINVAL;
-
cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
@@ -121,9 +118,6 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
break;
}
- if (!cpu_online(policy->cpu))
- return -EINVAL;
-
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
@@ -227,6 +221,15 @@ void cpufreq_frequency_table_put_attr(unsigned int cpu)
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
+void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy)
+{
+ pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n",
+ policy->cpu, policy->last_cpu);
+ per_cpu(cpufreq_show_table, policy->cpu) = per_cpu(cpufreq_show_table,
+ policy->last_cpu);
+ per_cpu(cpufreq_show_table, policy->last_cpu) = NULL;
+}
+
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
{
return per_cpu(cpufreq_show_table, cpu);
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 000000000000..66e3a71b81a3
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver provides the clk notifier callbacks that are used when
+ * the cpufreq-cpu0 driver changes to frequency to alert the highbank
+ * EnergyCore Management Engine (ECME) about the need to change
+ * voltage. The ECME interfaces with the actual voltage regulators.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/mailbox.h>
+#include <linux/platform_device.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
+#define HB_CPUFREQ_IPC_LEN 7
+#define HB_CPUFREQ_VOLT_RETRIES 15
+
+static int hb_voltage_change(unsigned int freq)
+{
+ int i;
+ u32 msg[HB_CPUFREQ_IPC_LEN];
+
+ msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+ msg[1] = freq / 1000000;
+ for (i = 2; i < HB_CPUFREQ_IPC_LEN; i++)
+ msg[i] = 0;
+
+ return pl320_ipc_transmit(msg);
+}
+
+static int hb_cpufreq_clk_notify(struct notifier_block *nb,
+ unsigned long action, void *hclk)
+{
+ struct clk_notifier_data *clk_data = hclk;
+ int i = 0;
+
+ if (action == PRE_RATE_CHANGE) {
+ if (clk_data->new_rate > clk_data->old_rate)
+ while (hb_voltage_change(clk_data->new_rate))
+ if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+ return NOTIFY_BAD;
+ } else if (action == POST_RATE_CHANGE) {
+ if (clk_data->new_rate < clk_data->old_rate)
+ while (hb_voltage_change(clk_data->new_rate))
+ if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+ return NOTIFY_BAD;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block hb_cpufreq_clk_nb = {
+ .notifier_call = hb_cpufreq_clk_notify,
+};
+
+static int hb_cpufreq_driver_init(void)
+{
+ struct platform_device_info devinfo = { .name = "cpufreq-cpu0", };
+ struct device *cpu_dev;
+ struct clk *cpu_clk;
+ struct device_node *np;
+ int ret;
+
+ if (!of_machine_is_compatible("calxeda,highbank"))
+ return -ENODEV;
+
+ for_each_child_of_node(of_find_node_by_path("/cpus"), np)
+ if (of_get_property(np, "operating-points", NULL))
+ break;
+
+ if (!np) {
+ pr_err("failed to find highbank cpufreq node\n");
+ return -ENOENT;
+ }
+
+ cpu_dev = get_cpu_device(0);
+ if (!cpu_dev) {
+ pr_err("failed to get highbank cpufreq device\n");
+ ret = -ENODEV;
+ goto out_put_node;
+ }
+
+ cpu_dev->of_node = np;
+
+ cpu_clk = clk_get(cpu_dev, NULL);
+ if (IS_ERR(cpu_clk)) {
+ ret = PTR_ERR(cpu_clk);
+ pr_err("failed to get cpu0 clock: %d\n", ret);
+ goto out_put_node;
+ }
+
+ ret = clk_notifier_register(cpu_clk, &hb_cpufreq_clk_nb);
+ if (ret) {
+ pr_err("failed to register clk notifier: %d\n", ret);
+ goto out_put_node;
+ }
+
+ /* Instantiate cpufreq-cpu0 */
+ platform_device_register_full(&devinfo);
+
+out_put_node:
+ of_node_put(np);
+ return ret;
+}
+module_init(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
new file mode 100644
index 000000000000..d6b6ef350cb6
--- /dev/null
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2013 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 <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#define PU_SOC_VOLTAGE_NORMAL 1250000
+#define PU_SOC_VOLTAGE_HIGH 1275000
+#define FREQ_1P2_GHZ 1200000000
+
+static struct regulator *arm_reg;
+static struct regulator *pu_reg;
+static struct regulator *soc_reg;
+
+static struct clk *arm_clk;
+static struct clk *pll1_sys_clk;
+static struct clk *pll1_sw_clk;
+static struct clk *step_clk;
+static struct clk *pll2_pfd2_396m_clk;
+
+static struct device *cpu_dev;
+static struct cpufreq_frequency_table *freq_table;
+static unsigned int transition_latency;
+
+static int imx6q_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int imx6q_get_speed(unsigned int cpu)
+{
+ return clk_get_rate(arm_clk) / 1000;
+}
+
+static int imx6q_set_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ struct opp *opp;
+ unsigned long freq_hz, volt, volt_old;
+ unsigned int index, cpu;
+ int ret;
+
+ ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+ relation, &index);
+ if (ret) {
+ dev_err(cpu_dev, "failed to match target frequency %d: %d\n",
+ target_freq, ret);
+ return ret;
+ }
+
+ freqs.new = freq_table[index].frequency;
+ freq_hz = freqs.new * 1000;
+ freqs.old = clk_get_rate(arm_clk) / 1000;
+
+ if (freqs.old == freqs.new)
+ return 0;
+
+ for_each_online_cpu(cpu) {
+ freqs.cpu = cpu;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ }
+
+ rcu_read_lock();
+ opp = opp_find_freq_ceil(cpu_dev, &freq_hz);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
+ return PTR_ERR(opp);
+ }
+
+ volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+ volt_old = regulator_get_voltage(arm_reg);
+
+ dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
+ freqs.old / 1000, volt_old / 1000,
+ freqs.new / 1000, volt / 1000);
+
+ /* scaling up? scale voltage before frequency */
+ if (freqs.new > freqs.old) {
+ ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+ if (ret) {
+ dev_err(cpu_dev,
+ "failed to scale vddarm up: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Need to increase vddpu and vddsoc for safety
+ * if we are about to run at 1.2 GHz.
+ */
+ if (freqs.new == FREQ_1P2_GHZ / 1000) {
+ regulator_set_voltage_tol(pu_reg,
+ PU_SOC_VOLTAGE_HIGH, 0);
+ regulator_set_voltage_tol(soc_reg,
+ PU_SOC_VOLTAGE_HIGH, 0);
+ }
+ }
+
+ /*
+ * The setpoints are selected per PLL/PDF frequencies, so we need to
+ * reprogram PLL for frequency scaling. The procedure of reprogramming
+ * PLL1 is as below.
+ *
+ * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
+ * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
+ * - Disable pll2_pfd2_396m_clk
+ */
+ clk_prepare_enable(pll2_pfd2_396m_clk);
+ clk_set_parent(step_clk, pll2_pfd2_396m_clk);
+ clk_set_parent(pll1_sw_clk, step_clk);
+ if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
+ clk_set_rate(pll1_sys_clk, freqs.new * 1000);
+ /*
+ * If we are leaving 396 MHz set-point, we need to enable
+ * pll1_sys_clk and disable pll2_pfd2_396m_clk to keep
+ * their use count correct.
+ */
+ if (freqs.old * 1000 <= clk_get_rate(pll2_pfd2_396m_clk)) {
+ clk_prepare_enable(pll1_sys_clk);
+ clk_disable_unprepare(pll2_pfd2_396m_clk);
+ }
+ clk_set_parent(pll1_sw_clk, pll1_sys_clk);
+ clk_disable_unprepare(pll2_pfd2_396m_clk);
+ } else {
+ /*
+ * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
+ * to provide the frequency.
+ */
+ clk_disable_unprepare(pll1_sys_clk);
+ }
+
+ /* Ensure the arm clock divider is what we expect */
+ ret = clk_set_rate(arm_clk, freqs.new * 1000);
+ if (ret) {
+ dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
+ regulator_set_voltage_tol(arm_reg, volt_old, 0);
+ return ret;
+ }
+
+ /* scaling down? scale voltage after frequency */
+ if (freqs.new < freqs.old) {
+ ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+ if (ret)
+ dev_warn(cpu_dev,
+ "failed to scale vddarm down: %d\n", ret);
+
+ if (freqs.old == FREQ_1P2_GHZ / 1000) {
+ regulator_set_voltage_tol(pu_reg,
+ PU_SOC_VOLTAGE_NORMAL, 0);
+ regulator_set_voltage_tol(soc_reg,
+ PU_SOC_VOLTAGE_NORMAL, 0);
+ }
+ }
+
+ for_each_online_cpu(cpu) {
+ freqs.cpu = cpu;
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+
+ return 0;
+}
+
+static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
+{
+ int ret;
+
+ ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (ret) {
+ dev_err(cpu_dev, "invalid frequency table: %d\n", ret);
+ return ret;
+ }
+
+ policy->cpuinfo.transition_latency = transition_latency;
+ policy->cur = clk_get_rate(arm_clk) / 1000;
+ cpumask_setall(policy->cpus);
+ cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+ return 0;
+}
+
+static int imx6q_cpufreq_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static struct freq_attr *imx6q_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver imx6q_cpufreq_driver = {
+ .verify = imx6q_verify_speed,
+ .target = imx6q_set_target,
+ .get = imx6q_get_speed,
+ .init = imx6q_cpufreq_init,
+ .exit = imx6q_cpufreq_exit,
+ .name = "imx6q-cpufreq",
+ .attr = imx6q_cpufreq_attr,
+};
+
+static int imx6q_cpufreq_probe(struct platform_device *pdev)
+{
+ struct device_node *np;
+ struct opp *opp;
+ unsigned long min_volt, max_volt;
+ int num, ret;
+
+ cpu_dev = &pdev->dev;
+
+ np = of_find_node_by_path("/cpus/cpu@0");
+ if (!np) {
+ dev_err(cpu_dev, "failed to find cpu0 node\n");
+ return -ENOENT;
+ }
+
+ cpu_dev->of_node = np;
+
+ arm_clk = devm_clk_get(cpu_dev, "arm");
+ pll1_sys_clk = devm_clk_get(cpu_dev, "pll1_sys");
+ pll1_sw_clk = devm_clk_get(cpu_dev, "pll1_sw");
+ step_clk = devm_clk_get(cpu_dev, "step");
+ pll2_pfd2_396m_clk = devm_clk_get(cpu_dev, "pll2_pfd2_396m");
+ if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) ||
+ IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) {
+ dev_err(cpu_dev, "failed to get clocks\n");
+ ret = -ENOENT;
+ goto put_node;
+ }
+
+ arm_reg = devm_regulator_get(cpu_dev, "arm");
+ pu_reg = devm_regulator_get(cpu_dev, "pu");
+ soc_reg = devm_regulator_get(cpu_dev, "soc");
+ if (!arm_reg || !pu_reg || !soc_reg) {
+ dev_err(cpu_dev, "failed to get regulators\n");
+ ret = -ENOENT;
+ goto put_node;
+ }
+
+ /* We expect an OPP table supplied by platform */
+ num = opp_get_opp_count(cpu_dev);
+ if (num < 0) {
+ ret = num;
+ dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
+ goto put_node;
+ }
+
+ ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+ if (ret) {
+ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
+ goto put_node;
+ }
+
+ if (of_property_read_u32(np, "clock-latency", &transition_latency))
+ transition_latency = CPUFREQ_ETERNAL;
+
+ /*
+ * OPP is maintained in order of increasing frequency, and
+ * freq_table initialised from OPP is therefore sorted in the
+ * same order.
+ */
+ rcu_read_lock();
+ opp = opp_find_freq_exact(cpu_dev,
+ freq_table[0].frequency * 1000, true);
+ min_volt = opp_get_voltage(opp);
+ opp = opp_find_freq_exact(cpu_dev,
+ freq_table[--num].frequency * 1000, true);
+ max_volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+ ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
+ if (ret > 0)
+ transition_latency += ret * 1000;
+
+ /* Count vddpu and vddsoc latency in for 1.2 GHz support */
+ if (freq_table[num].frequency == FREQ_1P2_GHZ / 1000) {
+ ret = regulator_set_voltage_time(pu_reg, PU_SOC_VOLTAGE_NORMAL,
+ PU_SOC_VOLTAGE_HIGH);
+ if (ret > 0)
+ transition_latency += ret * 1000;
+ ret = regulator_set_voltage_time(soc_reg, PU_SOC_VOLTAGE_NORMAL,
+ PU_SOC_VOLTAGE_HIGH);
+ if (ret > 0)
+ transition_latency += ret * 1000;
+ }
+
+ ret = cpufreq_register_driver(&imx6q_cpufreq_driver);
+ if (ret) {
+ dev_err(cpu_dev, "failed register driver: %d\n", ret);
+ goto free_freq_table;
+ }
+
+ of_node_put(np);
+ return 0;
+
+free_freq_table:
+ opp_free_cpufreq_table(cpu_dev, &freq_table);
+put_node:
+ of_node_put(np);
+ return ret;
+}
+
+static int imx6q_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_unregister_driver(&imx6q_cpufreq_driver);
+ opp_free_cpufreq_table(cpu_dev, &freq_table);
+
+ return 0;
+}
+
+static struct platform_driver imx6q_cpufreq_platdrv = {
+ .driver = {
+ .name = "imx6q-cpufreq",
+ .owner = THIS_MODULE,
+ },
+ .probe = imx6q_cpufreq_probe,
+ .remove = imx6q_cpufreq_remove,
+};
+module_platform_driver(imx6q_cpufreq_platdrv);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Freescale i.MX6Q cpufreq driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
new file mode 100644
index 000000000000..096fde0ebcb5
--- /dev/null
+++ b/drivers/cpufreq/intel_pstate.c
@@ -0,0 +1,823 @@
+/*
+ * cpufreq_snb.c: Native P state management for Intel processors
+ *
+ * (C) Copyright 2012 Intel Corporation
+ * Author: Dirk Brandewie <dirk.j.brandewie@intel.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/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <trace/events/power.h>
+
+#include <asm/div64.h>
+#include <asm/msr.h>
+#include <asm/cpu_device_id.h>
+
+#define SAMPLE_COUNT 3
+
+#define FRAC_BITS 8
+#define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
+#define fp_toint(X) ((X) >> FRAC_BITS)
+
+static inline int32_t mul_fp(int32_t x, int32_t y)
+{
+ return ((int64_t)x * (int64_t)y) >> FRAC_BITS;
+}
+
+static inline int32_t div_fp(int32_t x, int32_t y)
+{
+ return div_s64((int64_t)x << FRAC_BITS, (int64_t)y);
+}
+
+struct sample {
+ ktime_t start_time;
+ ktime_t end_time;
+ int core_pct_busy;
+ int pstate_pct_busy;
+ u64 duration_us;
+ u64 idletime_us;
+ u64 aperf;
+ u64 mperf;
+ int freq;
+};
+
+struct pstate_data {
+ int current_pstate;
+ int min_pstate;
+ int max_pstate;
+ int turbo_pstate;
+};
+
+struct _pid {
+ int setpoint;
+ int32_t integral;
+ int32_t p_gain;
+ int32_t i_gain;
+ int32_t d_gain;
+ int deadband;
+ int last_err;
+};
+
+struct cpudata {
+ int cpu;
+
+ char name[64];
+
+ struct timer_list timer;
+
+ struct pstate_adjust_policy *pstate_policy;
+ struct pstate_data pstate;
+ struct _pid pid;
+ struct _pid idle_pid;
+
+ int min_pstate_count;
+ int idle_mode;
+
+ ktime_t prev_sample;
+ u64 prev_idle_time_us;
+ u64 prev_aperf;
+ u64 prev_mperf;
+ int sample_ptr;
+ struct sample samples[SAMPLE_COUNT];
+};
+
+static struct cpudata **all_cpu_data;
+struct pstate_adjust_policy {
+ int sample_rate_ms;
+ int deadband;
+ int setpoint;
+ int p_gain_pct;
+ int d_gain_pct;
+ int i_gain_pct;
+};
+
+static struct pstate_adjust_policy default_policy = {
+ .sample_rate_ms = 10,
+ .deadband = 0,
+ .setpoint = 109,
+ .p_gain_pct = 17,
+ .d_gain_pct = 0,
+ .i_gain_pct = 4,
+};
+
+struct perf_limits {
+ int no_turbo;
+ int max_perf_pct;
+ int min_perf_pct;
+ int32_t max_perf;
+ int32_t min_perf;
+};
+
+static struct perf_limits limits = {
+ .no_turbo = 0,
+ .max_perf_pct = 100,
+ .max_perf = int_tofp(1),
+ .min_perf_pct = 0,
+ .min_perf = 0,
+};
+
+static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
+ int deadband, int integral) {
+ pid->setpoint = setpoint;
+ pid->deadband = deadband;
+ pid->integral = int_tofp(integral);
+ pid->last_err = setpoint - busy;
+}
+
+static inline void pid_p_gain_set(struct _pid *pid, int percent)
+{
+ pid->p_gain = div_fp(int_tofp(percent), int_tofp(100));
+}
+
+static inline void pid_i_gain_set(struct _pid *pid, int percent)
+{
+ pid->i_gain = div_fp(int_tofp(percent), int_tofp(100));
+}
+
+static inline void pid_d_gain_set(struct _pid *pid, int percent)
+{
+
+ pid->d_gain = div_fp(int_tofp(percent), int_tofp(100));
+}
+
+static signed int pid_calc(struct _pid *pid, int busy)
+{
+ signed int err, result;
+ int32_t pterm, dterm, fp_error;
+ int32_t integral_limit;
+
+ err = pid->setpoint - busy;
+ fp_error = int_tofp(err);
+
+ if (abs(err) <= pid->deadband)
+ return 0;
+
+ pterm = mul_fp(pid->p_gain, fp_error);
+
+ pid->integral += fp_error;
+
+ /* limit the integral term */
+ integral_limit = int_tofp(30);
+ if (pid->integral > integral_limit)
+ pid->integral = integral_limit;
+ if (pid->integral < -integral_limit)
+ pid->integral = -integral_limit;
+
+ dterm = mul_fp(pid->d_gain, (err - pid->last_err));
+ pid->last_err = err;
+
+ result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm;
+
+ return (signed int)fp_toint(result);
+}
+
+static inline void intel_pstate_busy_pid_reset(struct cpudata *cpu)
+{
+ pid_p_gain_set(&cpu->pid, cpu->pstate_policy->p_gain_pct);
+ pid_d_gain_set(&cpu->pid, cpu->pstate_policy->d_gain_pct);
+ pid_i_gain_set(&cpu->pid, cpu->pstate_policy->i_gain_pct);
+
+ pid_reset(&cpu->pid,
+ cpu->pstate_policy->setpoint,
+ 100,
+ cpu->pstate_policy->deadband,
+ 0);
+}
+
+static inline void intel_pstate_idle_pid_reset(struct cpudata *cpu)
+{
+ pid_p_gain_set(&cpu->idle_pid, cpu->pstate_policy->p_gain_pct);
+ pid_d_gain_set(&cpu->idle_pid, cpu->pstate_policy->d_gain_pct);
+ pid_i_gain_set(&cpu->idle_pid, cpu->pstate_policy->i_gain_pct);
+
+ pid_reset(&cpu->idle_pid,
+ 75,
+ 50,
+ cpu->pstate_policy->deadband,
+ 0);
+}
+
+static inline void intel_pstate_reset_all_pid(void)
+{
+ unsigned int cpu;
+ for_each_online_cpu(cpu) {
+ if (all_cpu_data[cpu])
+ intel_pstate_busy_pid_reset(all_cpu_data[cpu]);
+ }
+}
+
+/************************** debugfs begin ************************/
+static int pid_param_set(void *data, u64 val)
+{
+ *(u32 *)data = val;
+ intel_pstate_reset_all_pid();
+ return 0;
+}
+static int pid_param_get(void *data, u64 *val)
+{
+ *val = *(u32 *)data;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_pid_param, pid_param_get,
+ pid_param_set, "%llu\n");
+
+struct pid_param {
+ char *name;
+ void *value;
+};
+
+static struct pid_param pid_files[] = {
+ {"sample_rate_ms", &default_policy.sample_rate_ms},
+ {"d_gain_pct", &default_policy.d_gain_pct},
+ {"i_gain_pct", &default_policy.i_gain_pct},
+ {"deadband", &default_policy.deadband},
+ {"setpoint", &default_policy.setpoint},
+ {"p_gain_pct", &default_policy.p_gain_pct},
+ {NULL, NULL}
+};
+
+static struct dentry *debugfs_parent;
+static void intel_pstate_debug_expose_params(void)
+{
+ int i = 0;
+
+ debugfs_parent = debugfs_create_dir("pstate_snb", NULL);
+ if (IS_ERR_OR_NULL(debugfs_parent))
+ return;
+ while (pid_files[i].name) {
+ debugfs_create_file(pid_files[i].name, 0660,
+ debugfs_parent, pid_files[i].value,
+ &fops_pid_param);
+ i++;
+ }
+}
+
+/************************** debugfs end ************************/
+
+/************************** sysfs begin ************************/
+#define show_one(file_name, object) \
+ static ssize_t show_##file_name \
+ (struct kobject *kobj, struct attribute *attr, char *buf) \
+ { \
+ return sprintf(buf, "%u\n", limits.object); \
+ }
+
+static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+ limits.no_turbo = clamp_t(int, input, 0 , 1);
+
+ return count;
+}
+
+static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ limits.max_perf_pct = clamp_t(int, input, 0 , 100);
+ limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
+ return count;
+}
+
+static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+ limits.min_perf_pct = clamp_t(int, input, 0 , 100);
+ limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
+
+ return count;
+}
+
+show_one(no_turbo, no_turbo);
+show_one(max_perf_pct, max_perf_pct);
+show_one(min_perf_pct, min_perf_pct);
+
+define_one_global_rw(no_turbo);
+define_one_global_rw(max_perf_pct);
+define_one_global_rw(min_perf_pct);
+
+static struct attribute *intel_pstate_attributes[] = {
+ &no_turbo.attr,
+ &max_perf_pct.attr,
+ &min_perf_pct.attr,
+ NULL
+};
+
+static struct attribute_group intel_pstate_attr_group = {
+ .attrs = intel_pstate_attributes,
+};
+static struct kobject *intel_pstate_kobject;
+
+static void intel_pstate_sysfs_expose_params(void)
+{
+ int rc;
+
+ intel_pstate_kobject = kobject_create_and_add("intel_pstate",
+ &cpu_subsys.dev_root->kobj);
+ BUG_ON(!intel_pstate_kobject);
+ rc = sysfs_create_group(intel_pstate_kobject,
+ &intel_pstate_attr_group);
+ BUG_ON(rc);
+}
+
+/************************** sysfs end ************************/
+
+static int intel_pstate_min_pstate(void)
+{
+ u64 value;
+ rdmsrl(0xCE, value);
+ return (value >> 40) & 0xFF;
+}
+
+static int intel_pstate_max_pstate(void)
+{
+ u64 value;
+ rdmsrl(0xCE, value);
+ return (value >> 8) & 0xFF;
+}
+
+static int intel_pstate_turbo_pstate(void)
+{
+ u64 value;
+ int nont, ret;
+ rdmsrl(0x1AD, value);
+ nont = intel_pstate_max_pstate();
+ ret = ((value) & 255);
+ if (ret <= nont)
+ ret = nont;
+ return ret;
+}
+
+static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
+{
+ int max_perf = cpu->pstate.turbo_pstate;
+ int min_perf;
+ if (limits.no_turbo)
+ max_perf = cpu->pstate.max_pstate;
+
+ max_perf = fp_toint(mul_fp(int_tofp(max_perf), limits.max_perf));
+ *max = clamp_t(int, max_perf,
+ cpu->pstate.min_pstate, cpu->pstate.turbo_pstate);
+
+ min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits.min_perf));
+ *min = clamp_t(int, min_perf,
+ cpu->pstate.min_pstate, max_perf);
+}
+
+static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
+{
+ int max_perf, min_perf;
+
+ intel_pstate_get_min_max(cpu, &min_perf, &max_perf);
+
+ pstate = clamp_t(int, pstate, min_perf, max_perf);
+
+ if (pstate == cpu->pstate.current_pstate)
+ return;
+
+#ifndef MODULE
+ trace_cpu_frequency(pstate * 100000, cpu->cpu);
+#endif
+ cpu->pstate.current_pstate = pstate;
+ wrmsrl(MSR_IA32_PERF_CTL, pstate << 8);
+
+}
+
+static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps)
+{
+ int target;
+ target = cpu->pstate.current_pstate + steps;
+
+ intel_pstate_set_pstate(cpu, target);
+}
+
+static inline void intel_pstate_pstate_decrease(struct cpudata *cpu, int steps)
+{
+ int target;
+ target = cpu->pstate.current_pstate - steps;
+ intel_pstate_set_pstate(cpu, target);
+}
+
+static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
+{
+ sprintf(cpu->name, "Intel 2nd generation core");
+
+ cpu->pstate.min_pstate = intel_pstate_min_pstate();
+ cpu->pstate.max_pstate = intel_pstate_max_pstate();
+ cpu->pstate.turbo_pstate = intel_pstate_turbo_pstate();
+
+ /*
+ * goto max pstate so we don't slow up boot if we are built-in if we are
+ * a module we will take care of it during normal operation
+ */
+ intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate);
+}
+
+static inline void intel_pstate_calc_busy(struct cpudata *cpu,
+ struct sample *sample)
+{
+ u64 core_pct;
+ sample->pstate_pct_busy = 100 - div64_u64(
+ sample->idletime_us * 100,
+ sample->duration_us);
+ core_pct = div64_u64(sample->aperf * 100, sample->mperf);
+ sample->freq = cpu->pstate.turbo_pstate * core_pct * 1000;
+
+ sample->core_pct_busy = div_s64((sample->pstate_pct_busy * core_pct),
+ 100);
+}
+
+static inline void intel_pstate_sample(struct cpudata *cpu)
+{
+ ktime_t now;
+ u64 idle_time_us;
+ u64 aperf, mperf;
+
+ now = ktime_get();
+ idle_time_us = get_cpu_idle_time_us(cpu->cpu, NULL);
+
+ rdmsrl(MSR_IA32_APERF, aperf);
+ rdmsrl(MSR_IA32_MPERF, mperf);
+ /* for the first sample, don't actually record a sample, just
+ * set the baseline */
+ if (cpu->prev_idle_time_us > 0) {
+ cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
+ cpu->samples[cpu->sample_ptr].start_time = cpu->prev_sample;
+ cpu->samples[cpu->sample_ptr].end_time = now;
+ cpu->samples[cpu->sample_ptr].duration_us =
+ ktime_us_delta(now, cpu->prev_sample);
+ cpu->samples[cpu->sample_ptr].idletime_us =
+ idle_time_us - cpu->prev_idle_time_us;
+
+ cpu->samples[cpu->sample_ptr].aperf = aperf;
+ cpu->samples[cpu->sample_ptr].mperf = mperf;
+ cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf;
+ cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf;
+
+ intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]);
+ }
+
+ cpu->prev_sample = now;
+ cpu->prev_idle_time_us = idle_time_us;
+ cpu->prev_aperf = aperf;
+ cpu->prev_mperf = mperf;
+}
+
+static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
+{
+ int sample_time, delay;
+
+ sample_time = cpu->pstate_policy->sample_rate_ms;
+ delay = msecs_to_jiffies(sample_time);
+ delay -= jiffies % delay;
+ mod_timer_pinned(&cpu->timer, jiffies + delay);
+}
+
+static inline void intel_pstate_idle_mode(struct cpudata *cpu)
+{
+ cpu->idle_mode = 1;
+}
+
+static inline void intel_pstate_normal_mode(struct cpudata *cpu)
+{
+ cpu->idle_mode = 0;
+}
+
+static inline int intel_pstate_get_scaled_busy(struct cpudata *cpu)
+{
+ int32_t busy_scaled;
+ int32_t core_busy, turbo_pstate, current_pstate;
+
+ core_busy = int_tofp(cpu->samples[cpu->sample_ptr].core_pct_busy);
+ turbo_pstate = int_tofp(cpu->pstate.turbo_pstate);
+ current_pstate = int_tofp(cpu->pstate.current_pstate);
+ busy_scaled = mul_fp(core_busy, div_fp(turbo_pstate, current_pstate));
+
+ return fp_toint(busy_scaled);
+}
+
+static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
+{
+ int busy_scaled;
+ struct _pid *pid;
+ signed int ctl = 0;
+ int steps;
+
+ pid = &cpu->pid;
+ busy_scaled = intel_pstate_get_scaled_busy(cpu);
+
+ ctl = pid_calc(pid, busy_scaled);
+
+ steps = abs(ctl);
+ if (ctl < 0)
+ intel_pstate_pstate_increase(cpu, steps);
+ else
+ intel_pstate_pstate_decrease(cpu, steps);
+}
+
+static inline void intel_pstate_adjust_idle_pstate(struct cpudata *cpu)
+{
+ int busy_scaled;
+ struct _pid *pid;
+ int ctl = 0;
+ int steps;
+
+ pid = &cpu->idle_pid;
+
+ busy_scaled = intel_pstate_get_scaled_busy(cpu);
+
+ ctl = pid_calc(pid, 100 - busy_scaled);
+
+ steps = abs(ctl);
+ if (ctl < 0)
+ intel_pstate_pstate_decrease(cpu, steps);
+ else
+ intel_pstate_pstate_increase(cpu, steps);
+
+ if (cpu->pstate.current_pstate == cpu->pstate.min_pstate)
+ intel_pstate_normal_mode(cpu);
+}
+
+static void intel_pstate_timer_func(unsigned long __data)
+{
+ struct cpudata *cpu = (struct cpudata *) __data;
+
+ intel_pstate_sample(cpu);
+
+ if (!cpu->idle_mode)
+ intel_pstate_adjust_busy_pstate(cpu);
+ else
+ intel_pstate_adjust_idle_pstate(cpu);
+
+#if defined(XPERF_FIX)
+ if (cpu->pstate.current_pstate == cpu->pstate.min_pstate) {
+ cpu->min_pstate_count++;
+ if (!(cpu->min_pstate_count % 5)) {
+ intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate);
+ intel_pstate_idle_mode(cpu);
+ }
+ } else
+ cpu->min_pstate_count = 0;
+#endif
+ intel_pstate_set_sample_time(cpu);
+}
+
+#define ICPU(model, policy) \
+ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&policy }
+
+static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
+ ICPU(0x2a, default_policy),
+ ICPU(0x2d, default_policy),
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
+
+static int intel_pstate_init_cpu(unsigned int cpunum)
+{
+
+ const struct x86_cpu_id *id;
+ struct cpudata *cpu;
+
+ id = x86_match_cpu(intel_pstate_cpu_ids);
+ if (!id)
+ return -ENODEV;
+
+ all_cpu_data[cpunum] = kzalloc(sizeof(struct cpudata), GFP_KERNEL);
+ if (!all_cpu_data[cpunum])
+ return -ENOMEM;
+
+ cpu = all_cpu_data[cpunum];
+
+ intel_pstate_get_cpu_pstates(cpu);
+
+ cpu->cpu = cpunum;
+ cpu->pstate_policy =
+ (struct pstate_adjust_policy *)id->driver_data;
+ init_timer_deferrable(&cpu->timer);
+ cpu->timer.function = intel_pstate_timer_func;
+ cpu->timer.data =
+ (unsigned long)cpu;
+ cpu->timer.expires = jiffies + HZ/100;
+ intel_pstate_busy_pid_reset(cpu);
+ intel_pstate_idle_pid_reset(cpu);
+ intel_pstate_sample(cpu);
+ intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate);
+
+ add_timer_on(&cpu->timer, cpunum);
+
+ pr_info("Intel pstate controlling: cpu %d\n", cpunum);
+
+ return 0;
+}
+
+static unsigned int intel_pstate_get(unsigned int cpu_num)
+{
+ struct sample *sample;
+ struct cpudata *cpu;
+
+ cpu = all_cpu_data[cpu_num];
+ if (!cpu)
+ return 0;
+ sample = &cpu->samples[cpu->sample_ptr];
+ return sample->freq;
+}
+
+static int intel_pstate_set_policy(struct cpufreq_policy *policy)
+{
+ struct cpudata *cpu;
+ int min, max;
+
+ cpu = all_cpu_data[policy->cpu];
+
+ intel_pstate_get_min_max(cpu, &min, &max);
+
+ limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
+ limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100);
+ limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
+
+ limits.max_perf_pct = policy->max * 100 / policy->cpuinfo.max_freq;
+ limits.max_perf_pct = clamp_t(int, limits.max_perf_pct, 0 , 100);
+ limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
+
+ if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
+ limits.min_perf_pct = 100;
+ limits.min_perf = int_tofp(1);
+ limits.max_perf_pct = 100;
+ limits.max_perf = int_tofp(1);
+ limits.no_turbo = 0;
+ }
+
+ return 0;
+}
+
+static int intel_pstate_verify_policy(struct cpufreq_policy *policy)
+{
+ cpufreq_verify_within_limits(policy,
+ policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+
+ if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) &&
+ (policy->policy != CPUFREQ_POLICY_PERFORMANCE))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int __cpuinit intel_pstate_cpu_exit(struct cpufreq_policy *policy)
+{
+ int cpu = policy->cpu;
+
+ del_timer(&all_cpu_data[cpu]->timer);
+ kfree(all_cpu_data[cpu]);
+ all_cpu_data[cpu] = NULL;
+ return 0;
+}
+
+static int __cpuinit intel_pstate_cpu_init(struct cpufreq_policy *policy)
+{
+ int rc, min_pstate, max_pstate;
+ struct cpudata *cpu;
+
+ rc = intel_pstate_init_cpu(policy->cpu);
+ if (rc)
+ return rc;
+
+ cpu = all_cpu_data[policy->cpu];
+
+ if (!limits.no_turbo &&
+ limits.min_perf_pct == 100 && limits.max_perf_pct == 100)
+ policy->policy = CPUFREQ_POLICY_PERFORMANCE;
+ else
+ policy->policy = CPUFREQ_POLICY_POWERSAVE;
+
+ intel_pstate_get_min_max(cpu, &min_pstate, &max_pstate);
+ policy->min = min_pstate * 100000;
+ policy->max = max_pstate * 100000;
+
+ /* cpuinfo and default policy values */
+ policy->cpuinfo.min_freq = cpu->pstate.min_pstate * 100000;
+ policy->cpuinfo.max_freq = cpu->pstate.turbo_pstate * 100000;
+ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+ cpumask_set_cpu(policy->cpu, policy->cpus);
+
+ return 0;
+}
+
+static struct cpufreq_driver intel_pstate_driver = {
+ .flags = CPUFREQ_CONST_LOOPS,
+ .verify = intel_pstate_verify_policy,
+ .setpolicy = intel_pstate_set_policy,
+ .get = intel_pstate_get,
+ .init = intel_pstate_cpu_init,
+ .exit = intel_pstate_cpu_exit,
+ .name = "intel_pstate",
+ .owner = THIS_MODULE,
+};
+
+static void intel_pstate_exit(void)
+{
+ int cpu;
+
+ sysfs_remove_group(intel_pstate_kobject,
+ &intel_pstate_attr_group);
+ debugfs_remove_recursive(debugfs_parent);
+
+ cpufreq_unregister_driver(&intel_pstate_driver);
+
+ if (!all_cpu_data)
+ return;
+
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (all_cpu_data[cpu]) {
+ del_timer_sync(&all_cpu_data[cpu]->timer);
+ kfree(all_cpu_data[cpu]);
+ }
+ }
+
+ put_online_cpus();
+ vfree(all_cpu_data);
+}
+module_exit(intel_pstate_exit);
+
+static int __initdata no_load;
+
+static int __init intel_pstate_init(void)
+{
+ int rc = 0;
+ const struct x86_cpu_id *id;
+
+ if (no_load)
+ return -ENODEV;
+
+ id = x86_match_cpu(intel_pstate_cpu_ids);
+ if (!id)
+ return -ENODEV;
+
+ pr_info("Intel P-state driver initializing.\n");
+
+ all_cpu_data = vmalloc(sizeof(void *) * num_possible_cpus());
+ if (!all_cpu_data)
+ return -ENOMEM;
+ memset(all_cpu_data, 0, sizeof(void *) * num_possible_cpus());
+
+ rc = cpufreq_register_driver(&intel_pstate_driver);
+ if (rc)
+ goto out;
+
+ intel_pstate_debug_expose_params();
+ intel_pstate_sysfs_expose_params();
+ return rc;
+out:
+ intel_pstate_exit();
+ return -ENODEV;
+}
+device_initcall(intel_pstate_init);
+
+static int __init intel_pstate_setup(char *str)
+{
+ if (!str)
+ return -EINVAL;
+
+ if (!strcmp(str, "disable"))
+ no_load = 1;
+ return 0;
+}
+early_param("intel_pstate", intel_pstate_setup);
+
+MODULE_AUTHOR("Dirk Brandewie <dirk.j.brandewie@intel.com>");
+MODULE_DESCRIPTION("'intel_pstate' - P state driver Intel Core processors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
new file mode 100644
index 000000000000..0e83e3c24f5b
--- /dev/null
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -0,0 +1,259 @@
+/*
+ * kirkwood_freq.c: cpufreq driver for the Marvell kirkwood
+ *
+ * Copyright (C) 2013 Andrew Lunn <andrew@lunn.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <asm/proc-fns.h>
+
+#define CPU_SW_INT_BLK BIT(28)
+
+static struct priv
+{
+ struct clk *cpu_clk;
+ struct clk *ddr_clk;
+ struct clk *powersave_clk;
+ struct device *dev;
+ void __iomem *base;
+} priv;
+
+#define STATE_CPU_FREQ 0x01
+#define STATE_DDR_FREQ 0x02
+
+/*
+ * Kirkwood can swap the clock to the CPU between two clocks:
+ *
+ * - cpu clk
+ * - ddr clk
+ *
+ * The frequencies are set at runtime before registering this *
+ * table.
+ */
+static struct cpufreq_frequency_table kirkwood_freq_table[] = {
+ {STATE_CPU_FREQ, 0}, /* CPU uses cpuclk */
+ {STATE_DDR_FREQ, 0}, /* CPU uses ddrclk */
+ {0, CPUFREQ_TABLE_END},
+};
+
+static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu)
+{
+ if (__clk_is_enabled(priv.powersave_clk))
+ return kirkwood_freq_table[1].frequency;
+ return kirkwood_freq_table[0].frequency;
+}
+
+static void kirkwood_cpufreq_set_cpu_state(unsigned int index)
+{
+ struct cpufreq_freqs freqs;
+ unsigned int state = kirkwood_freq_table[index].index;
+ unsigned long reg;
+
+ freqs.old = kirkwood_cpufreq_get_cpu_frequency(0);
+ freqs.new = kirkwood_freq_table[index].frequency;
+ freqs.cpu = 0; /* Kirkwood is UP */
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ dev_dbg(priv.dev, "Attempting to set frequency to %i KHz\n",
+ kirkwood_freq_table[index].frequency);
+ dev_dbg(priv.dev, "old frequency was %i KHz\n",
+ kirkwood_cpufreq_get_cpu_frequency(0));
+
+ if (freqs.old != freqs.new) {
+ local_irq_disable();
+
+ /* Disable interrupts to the CPU */
+ reg = readl_relaxed(priv.base);
+ reg |= CPU_SW_INT_BLK;
+ writel_relaxed(reg, priv.base);
+
+ switch (state) {
+ case STATE_CPU_FREQ:
+ clk_disable(priv.powersave_clk);
+ break;
+ case STATE_DDR_FREQ:
+ clk_enable(priv.powersave_clk);
+ break;
+ }
+
+ /* Wait-for-Interrupt, while the hardware changes frequency */
+ cpu_do_idle();
+
+ /* Enable interrupts to the CPU */
+ reg = readl_relaxed(priv.base);
+ reg &= ~CPU_SW_INT_BLK;
+ writel_relaxed(reg, priv.base);
+
+ local_irq_enable();
+ }
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+};
+
+static int kirkwood_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, kirkwood_freq_table);
+}
+
+static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int index = 0;
+
+ if (cpufreq_frequency_table_target(policy, kirkwood_freq_table,
+ target_freq, relation, &index))
+ return -EINVAL;
+
+ kirkwood_cpufreq_set_cpu_state(index);
+
+ return 0;
+}
+
+/* Module init and exit code */
+static int kirkwood_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ int result;
+
+ /* cpuinfo and default policy values */
+ policy->cpuinfo.transition_latency = 5000; /* 5uS */
+ policy->cur = kirkwood_cpufreq_get_cpu_frequency(0);
+
+ result = cpufreq_frequency_table_cpuinfo(policy, kirkwood_freq_table);
+ if (result)
+ return result;
+
+ cpufreq_frequency_table_get_attr(kirkwood_freq_table, policy->cpu);
+
+ return 0;
+}
+
+static int kirkwood_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static struct freq_attr *kirkwood_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver kirkwood_cpufreq_driver = {
+ .get = kirkwood_cpufreq_get_cpu_frequency,
+ .verify = kirkwood_cpufreq_verify,
+ .target = kirkwood_cpufreq_target,
+ .init = kirkwood_cpufreq_cpu_init,
+ .exit = kirkwood_cpufreq_cpu_exit,
+ .name = "kirkwood-cpufreq",
+ .owner = THIS_MODULE,
+ .attr = kirkwood_cpufreq_attr,
+};
+
+static int kirkwood_cpufreq_probe(struct platform_device *pdev)
+{
+ struct device_node *np;
+ struct resource *res;
+ int err;
+
+ priv.dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Cannot get memory resource\n");
+ return -ENODEV;
+ }
+ priv.base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!priv.base) {
+ dev_err(&pdev->dev, "Cannot ioremap\n");
+ return -EADDRNOTAVAIL;
+ }
+
+ np = of_find_node_by_path("/cpus/cpu@0");
+ if (!np)
+ return -ENODEV;
+
+ priv.cpu_clk = of_clk_get_by_name(np, "cpu_clk");
+ if (IS_ERR(priv.cpu_clk)) {
+ dev_err(priv.dev, "Unable to get cpuclk");
+ return PTR_ERR(priv.cpu_clk);
+ }
+
+ clk_prepare_enable(priv.cpu_clk);
+ kirkwood_freq_table[0].frequency = clk_get_rate(priv.cpu_clk) / 1000;
+
+ priv.ddr_clk = of_clk_get_by_name(np, "ddrclk");
+ if (IS_ERR(priv.ddr_clk)) {
+ dev_err(priv.dev, "Unable to get ddrclk");
+ err = PTR_ERR(priv.ddr_clk);
+ goto out_cpu;
+ }
+
+ clk_prepare_enable(priv.ddr_clk);
+ kirkwood_freq_table[1].frequency = clk_get_rate(priv.ddr_clk) / 1000;
+
+ priv.powersave_clk = of_clk_get_by_name(np, "powersave");
+ if (IS_ERR(priv.powersave_clk)) {
+ dev_err(priv.dev, "Unable to get powersave");
+ err = PTR_ERR(priv.powersave_clk);
+ goto out_ddr;
+ }
+ clk_prepare(priv.powersave_clk);
+
+ of_node_put(np);
+ np = NULL;
+
+ err = cpufreq_register_driver(&kirkwood_cpufreq_driver);
+ if (!err)
+ return 0;
+
+ dev_err(priv.dev, "Failed to register cpufreq driver");
+
+ clk_disable_unprepare(priv.powersave_clk);
+out_ddr:
+ clk_disable_unprepare(priv.ddr_clk);
+out_cpu:
+ clk_disable_unprepare(priv.cpu_clk);
+ of_node_put(np);
+
+ return err;
+}
+
+static int kirkwood_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_unregister_driver(&kirkwood_cpufreq_driver);
+
+ clk_disable_unprepare(priv.powersave_clk);
+ clk_disable_unprepare(priv.ddr_clk);
+ clk_disable_unprepare(priv.cpu_clk);
+
+ return 0;
+}
+
+static struct platform_driver kirkwood_cpufreq_platform_driver = {
+ .probe = kirkwood_cpufreq_probe,
+ .remove = kirkwood_cpufreq_remove,
+ .driver = {
+ .name = "kirkwood-cpufreq",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(kirkwood_cpufreq_platform_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch");
+MODULE_DESCRIPTION("cpufreq driver for Marvell's kirkwood CPU");
+MODULE_ALIAS("platform:kirkwood-cpufreq");
diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c
index 89b178a3f849..d4c4989823dc 100644
--- a/drivers/cpufreq/maple-cpufreq.c
+++ b/drivers/cpufreq/maple-cpufreq.c
@@ -181,7 +181,7 @@ static int maple_cpufreq_cpu_init(struct cpufreq_policy *policy)
/* secondary CPUs are tied to the primary one by the
* cpufreq core if in the secondary policy we tell it that
* it actually must be one policy together with all others. */
- cpumask_copy(policy->cpus, cpu_online_mask);
+ cpumask_setall(policy->cpus);
cpufreq_frequency_table_get_attr(maple_cpu_freqs, policy->cpu);
return cpufreq_frequency_table_cpuinfo(policy,
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 97102b05843f..9128c07bafba 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -214,10 +214,8 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
* interface to handle this scenario. Additional is_smp() check
* is to keep SMP_ON_UP build working.
*/
- if (is_smp()) {
- policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+ if (is_smp())
cpumask_setall(policy->cpus);
- }
/* FIXME: what's the actual transition time? */
policy->cpuinfo.transition_latency = 300 * 1000;
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index 056faf6af1a9..d13a13678b5f 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -1249,39 +1249,59 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
.attr = powernow_k8_attr,
};
+static void __request_acpi_cpufreq(void)
+{
+ const char *cur_drv, *drv = "acpi-cpufreq";
+
+ cur_drv = cpufreq_get_current_driver();
+ if (!cur_drv)
+ goto request;
+
+ if (strncmp(cur_drv, drv, min_t(size_t, strlen(cur_drv), strlen(drv))))
+ pr_warn(PFX "WTF driver: %s\n", cur_drv);
+
+ return;
+
+ request:
+ pr_warn(PFX "This CPU is not supported anymore, using acpi-cpufreq instead.\n");
+ request_module(drv);
+}
+
/* driver entry point for init */
static int __cpuinit powernowk8_init(void)
{
unsigned int i, supported_cpus = 0;
- int rv;
+ int ret;
if (static_cpu_has(X86_FEATURE_HW_PSTATE)) {
- pr_warn(PFX "this CPU is not supported anymore, using acpi-cpufreq instead.\n");
- request_module("acpi-cpufreq");
+ __request_acpi_cpufreq();
return -ENODEV;
}
if (!x86_match_cpu(powernow_k8_ids))
return -ENODEV;
+ get_online_cpus();
for_each_online_cpu(i) {
- int rc;
- smp_call_function_single(i, check_supported_cpu, &rc, 1);
- if (rc == 0)
+ smp_call_function_single(i, check_supported_cpu, &ret, 1);
+ if (!ret)
supported_cpus++;
}
- if (supported_cpus != num_online_cpus())
+ if (supported_cpus != num_online_cpus()) {
+ put_online_cpus();
return -ENODEV;
+ }
+ put_online_cpus();
- rv = cpufreq_register_driver(&cpufreq_amd64_driver);
+ ret = cpufreq_register_driver(&cpufreq_amd64_driver);
+ if (ret)
+ return ret;
- if (!rv)
- pr_info(PFX "Found %d %s (%d cpu cores) (" VERSION ")\n",
- num_online_nodes(), boot_cpu_data.x86_model_id,
- supported_cpus);
+ pr_info(PFX "Found %d %s (%d cpu cores) (" VERSION ")\n",
+ num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus);
- return rv;
+ return ret;
}
/* driver entry point for term */
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index 4575cfe41755..7e4d77327957 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -30,7 +30,7 @@ static struct {
u32 cnt;
} spear_cpufreq;
-int spear_cpufreq_verify(struct cpufreq_policy *policy)
+static int spear_cpufreq_verify(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy, spear_cpufreq.freq_tbl);
}
@@ -157,7 +157,9 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
freqs.new = newfreq / 1000;
freqs.new /= mult;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ for_each_cpu(freqs.cpu, policy->cpus)
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (mult == 2)
ret = spear1340_set_cpu_rate(srcclk, newfreq);
@@ -170,7 +172,8 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000;
}
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ for_each_cpu(freqs.cpu, policy->cpus)
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return ret;
}
@@ -188,8 +191,7 @@ static int spear_cpufreq_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = spear_cpufreq.transition_latency;
policy->cur = spear_cpufreq_get(0);
- cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
- cpumask_copy(policy->related_cpus, policy->cpus);
+ cpumask_setall(policy->cpus);
return 0;
}
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index c4cc27e5c8a5..071e2c3eec4f 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -39,4 +39,10 @@ config CPU_IDLE_CALXEDA
help
Select this to enable cpuidle on Calxeda processors.
+config CPU_IDLE_KIRKWOOD
+ bool "CPU Idle Driver for Kirkwood processors"
+ depends on ARCH_KIRKWOOD
+ help
+ Select this to enable cpuidle on Kirkwood processors.
+
endif
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 03ee87482c71..24c6e7d945ed 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -6,3 +6,4 @@ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
+obj-$(CONFIG_CPU_IDLE_KIRKWOOD) += cpuidle-kirkwood.o
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/drivers/cpuidle/cpuidle-kirkwood.c
index f7304670f2f8..670aa1e55cd6 100644
--- a/arch/arm/mach-kirkwood/cpuidle.c
+++ b/drivers/cpuidle/cpuidle-kirkwood.c
@@ -14,6 +14,7 @@
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/cpuidle.h>
@@ -21,16 +22,17 @@
#include <linux/export.h>
#include <asm/proc-fns.h>
#include <asm/cpuidle.h>
-#include <mach/kirkwood.h>
#define KIRKWOOD_MAX_STATES 2
+static void __iomem *ddr_operation_base;
+
/* Actual code that puts the SoC in different idle states */
static int kirkwood_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
+ struct cpuidle_driver *drv,
int index)
{
- writel(0x7, DDR_OPERATION_BASE);
+ writel(0x7, ddr_operation_base);
cpu_do_idle();
return index;
@@ -51,13 +53,22 @@ static struct cpuidle_driver kirkwood_idle_driver = {
},
.state_count = KIRKWOOD_MAX_STATES,
};
+static struct cpuidle_device *device;
static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
/* Initialize CPU idle by registering the idle states */
-static int kirkwood_init_cpuidle(void)
+static int kirkwood_cpuidle_probe(struct platform_device *pdev)
{
- struct cpuidle_device *device;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL)
+ return -EINVAL;
+
+ ddr_operation_base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!ddr_operation_base)
+ return -EADDRNOTAVAIL;
device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
device->state_count = KIRKWOOD_MAX_STATES;
@@ -70,4 +81,26 @@ static int kirkwood_init_cpuidle(void)
return 0;
}
-device_initcall(kirkwood_init_cpuidle);
+int kirkwood_cpuidle_remove(struct platform_device *pdev)
+{
+ cpuidle_unregister_device(device);
+ cpuidle_unregister_driver(&kirkwood_idle_driver);
+
+ return 0;
+}
+
+static struct platform_driver kirkwood_cpuidle_driver = {
+ .probe = kirkwood_cpuidle_probe,
+ .remove = kirkwood_cpuidle_remove,
+ .driver = {
+ .name = "kirkwood_cpuidle",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(kirkwood_cpuidle_driver);
+
+MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
+MODULE_DESCRIPTION("Kirkwood cpu idle driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kirkwood-cpuidle");
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index e1f6860e069c..eba69290e074 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -144,7 +144,6 @@ int cpuidle_idle_call(void)
return 0;
}
- trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu);
trace_cpu_idle_rcuidle(next_state, dev->cpu);
if (cpuidle_state_is_coupled(dev, drv, next_state))
@@ -153,7 +152,6 @@ int cpuidle_idle_call(void)
else
entered_state = cpuidle_enter_state(dev, drv, next_state);
- trace_power_end_rcuidle(dev->cpu);
trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
/* give the governor an opportunity to reflect on the outcome */
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index c9d9d5c16f94..6f22ba51f969 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -332,7 +332,7 @@ static int atmel_aes_crypt_cpu_start(struct atmel_aes_dev *dd)
return -EINVAL;
dd->nb_out_sg = atmel_aes_sg_length(dd->req, dd->out_sg);
- if (!dd->nb_in_sg)
+ if (!dd->nb_out_sg)
return -EINVAL;
dd->bufcnt = sg_copy_to_buffer(dd->in_sg, dd->nb_in_sg,
diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
index a22f1a9f895f..827913d7d33a 100644
--- a/drivers/crypto/bfin_crc.c
+++ b/drivers/crypto/bfin_crc.c
@@ -694,7 +694,7 @@ out_error_dma:
dma_free_coherent(&pdev->dev, PAGE_SIZE, crc->sg_cpu, crc->sg_dma);
free_dma(crc->dma_ch);
out_error_irq:
- free_irq(crc->irq, crc->dev);
+ free_irq(crc->irq, crc);
out_error_unmap:
iounmap((void *)crc->regs);
out_error_free_mem:
@@ -720,10 +720,10 @@ static int bfin_crypto_crc_remove(struct platform_device *pdev)
crypto_unregister_ahash(&algs);
tasklet_kill(&crc->done_task);
- iounmap((void *)crc->regs);
free_dma(crc->dma_ch);
if (crc->irq > 0)
- free_irq(crc->irq, crc->dev);
+ free_irq(crc->irq, crc);
+ iounmap((void *)crc->regs);
kfree(crc);
return 0;
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index e66e8ee5a9af..6aa425fe0ed5 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -5,6 +5,7 @@
*
* Copyright (c) 2010 Nokia Corporation
* Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
+ * Copyright (c) 2011 Texas Instruments Incorporated
*
* 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
@@ -19,28 +20,39 @@
#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/dmaengine.h>
+#include <linux/omap-dma.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/crypto.h>
#include <linux/interrupt.h>
#include <crypto/scatterwalk.h>
#include <crypto/aes.h>
-#include <linux/omap-dma.h>
+#define DST_MAXBURST 4
+#define DMA_MIN (DST_MAXBURST * sizeof(u32))
/* OMAP TRM gives bitfields as start:end, where start is the higher bit
number. For example 7:0 */
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
-#define AES_REG_KEY(x) (0x1C - ((x ^ 0x01) * 0x04))
-#define AES_REG_IV(x) (0x20 + ((x) * 0x04))
+#define AES_REG_KEY(dd, x) ((dd)->pdata->key_ofs - \
+ ((x ^ 0x01) * 0x04))
+#define AES_REG_IV(dd, x) ((dd)->pdata->iv_ofs + ((x) * 0x04))
-#define AES_REG_CTRL 0x30
-#define AES_REG_CTRL_CTR_WIDTH (1 << 7)
+#define AES_REG_CTRL(dd) ((dd)->pdata->ctrl_ofs)
+#define AES_REG_CTRL_CTR_WIDTH_MASK (3 << 7)
+#define AES_REG_CTRL_CTR_WIDTH_32 (0 << 7)
+#define AES_REG_CTRL_CTR_WIDTH_64 (1 << 7)
+#define AES_REG_CTRL_CTR_WIDTH_96 (2 << 7)
+#define AES_REG_CTRL_CTR_WIDTH_128 (3 << 7)
#define AES_REG_CTRL_CTR (1 << 6)
#define AES_REG_CTRL_CBC (1 << 5)
#define AES_REG_CTRL_KEY_SIZE (3 << 3)
@@ -48,14 +60,11 @@
#define AES_REG_CTRL_INPUT_READY (1 << 1)
#define AES_REG_CTRL_OUTPUT_READY (1 << 0)
-#define AES_REG_DATA 0x34
-#define AES_REG_DATA_N(x) (0x34 + ((x) * 0x04))
+#define AES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04))
-#define AES_REG_REV 0x44
-#define AES_REG_REV_MAJOR 0xF0
-#define AES_REG_REV_MINOR 0x0F
+#define AES_REG_REV(dd) ((dd)->pdata->rev_ofs)
-#define AES_REG_MASK 0x48
+#define AES_REG_MASK(dd) ((dd)->pdata->mask_ofs)
#define AES_REG_MASK_SIDLE (1 << 6)
#define AES_REG_MASK_START (1 << 5)
#define AES_REG_MASK_DMA_OUT_EN (1 << 3)
@@ -63,8 +72,7 @@
#define AES_REG_MASK_SOFTRESET (1 << 1)
#define AES_REG_AUTOIDLE (1 << 0)
-#define AES_REG_SYSSTATUS 0x4C
-#define AES_REG_SYSSTATUS_RESETDONE (1 << 0)
+#define AES_REG_LENGTH_N(x) (0x54 + ((x) * 0x04))
#define DEFAULT_TIMEOUT (5*HZ)
@@ -72,6 +80,7 @@
#define FLAGS_ENCRYPT BIT(0)
#define FLAGS_CBC BIT(1)
#define FLAGS_GIV BIT(2)
+#define FLAGS_CTR BIT(3)
#define FLAGS_INIT BIT(4)
#define FLAGS_FAST BIT(5)
@@ -92,11 +101,39 @@ struct omap_aes_reqctx {
#define OMAP_AES_QUEUE_LENGTH 1
#define OMAP_AES_CACHE_SIZE 0
+struct omap_aes_algs_info {
+ struct crypto_alg *algs_list;
+ unsigned int size;
+ unsigned int registered;
+};
+
+struct omap_aes_pdata {
+ struct omap_aes_algs_info *algs_info;
+ unsigned int algs_info_size;
+
+ void (*trigger)(struct omap_aes_dev *dd, int length);
+
+ u32 key_ofs;
+ u32 iv_ofs;
+ u32 ctrl_ofs;
+ u32 data_ofs;
+ u32 rev_ofs;
+ u32 mask_ofs;
+
+ u32 dma_enable_in;
+ u32 dma_enable_out;
+ u32 dma_start;
+
+ u32 major_mask;
+ u32 major_shift;
+ u32 minor_mask;
+ u32 minor_shift;
+};
+
struct omap_aes_dev {
struct list_head list;
unsigned long phys_base;
void __iomem *io_base;
- struct clk *iclk;
struct omap_aes_ctx *ctx;
struct device *dev;
unsigned long flags;
@@ -111,20 +148,24 @@ struct omap_aes_dev {
struct ablkcipher_request *req;
size_t total;
struct scatterlist *in_sg;
+ struct scatterlist in_sgl;
size_t in_offset;
struct scatterlist *out_sg;
+ struct scatterlist out_sgl;
size_t out_offset;
size_t buflen;
void *buf_in;
size_t dma_size;
int dma_in;
- int dma_lch_in;
+ struct dma_chan *dma_lch_in;
dma_addr_t dma_addr_in;
void *buf_out;
int dma_out;
- int dma_lch_out;
+ struct dma_chan *dma_lch_out;
dma_addr_t dma_addr_out;
+
+ const struct omap_aes_pdata *pdata;
};
/* keep registered devices data here */
@@ -160,19 +201,6 @@ static void omap_aes_write_n(struct omap_aes_dev *dd, u32 offset,
omap_aes_write(dd, offset, *value);
}
-static int omap_aes_wait(struct omap_aes_dev *dd, u32 offset, u32 bit)
-{
- unsigned long timeout = jiffies + DEFAULT_TIMEOUT;
-
- while (!(omap_aes_read(dd, offset) & bit)) {
- if (time_is_before_jiffies(timeout)) {
- dev_err(dd->dev, "omap-aes timeout\n");
- return -ETIMEDOUT;
- }
- }
- return 0;
-}
-
static int omap_aes_hw_init(struct omap_aes_dev *dd)
{
/*
@@ -180,23 +208,9 @@ static int omap_aes_hw_init(struct omap_aes_dev *dd)
* It may be long delays between requests.
* Device might go to off mode to save power.
*/
- clk_enable(dd->iclk);
+ pm_runtime_get_sync(dd->dev);
if (!(dd->flags & FLAGS_INIT)) {
- /* is it necessary to reset before every operation? */
- omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_SOFTRESET,
- AES_REG_MASK_SOFTRESET);
- /*
- * prevent OCP bus error (SRESP) in case an access to the module
- * is performed while the module is coming out of soft reset
- */
- __asm__ __volatile__("nop");
- __asm__ __volatile__("nop");
-
- if (omap_aes_wait(dd, AES_REG_SYSSTATUS,
- AES_REG_SYSSTATUS_RESETDONE))
- return -ETIMEDOUT;
-
dd->flags |= FLAGS_INIT;
dd->err = 0;
}
@@ -208,59 +222,75 @@ static int omap_aes_write_ctrl(struct omap_aes_dev *dd)
{
unsigned int key32;
int i, err;
- u32 val, mask;
+ u32 val, mask = 0;
err = omap_aes_hw_init(dd);
if (err)
return err;
- val = 0;
- if (dd->dma_lch_out >= 0)
- val |= AES_REG_MASK_DMA_OUT_EN;
- if (dd->dma_lch_in >= 0)
- val |= AES_REG_MASK_DMA_IN_EN;
-
- mask = AES_REG_MASK_DMA_IN_EN | AES_REG_MASK_DMA_OUT_EN;
-
- omap_aes_write_mask(dd, AES_REG_MASK, val, mask);
-
key32 = dd->ctx->keylen / sizeof(u32);
/* it seems a key should always be set even if it has not changed */
for (i = 0; i < key32; i++) {
- omap_aes_write(dd, AES_REG_KEY(i),
+ omap_aes_write(dd, AES_REG_KEY(dd, i),
__le32_to_cpu(dd->ctx->key[i]));
}
- if ((dd->flags & FLAGS_CBC) && dd->req->info)
- omap_aes_write_n(dd, AES_REG_IV(0), dd->req->info, 4);
+ if ((dd->flags & (FLAGS_CBC | FLAGS_CTR)) && dd->req->info)
+ omap_aes_write_n(dd, AES_REG_IV(dd, 0), dd->req->info, 4);
val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3);
if (dd->flags & FLAGS_CBC)
val |= AES_REG_CTRL_CBC;
+ if (dd->flags & FLAGS_CTR) {
+ val |= AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_32;
+ mask = AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_MASK;
+ }
if (dd->flags & FLAGS_ENCRYPT)
val |= AES_REG_CTRL_DIRECTION;
- mask = AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION |
+ mask |= AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION |
AES_REG_CTRL_KEY_SIZE;
- omap_aes_write_mask(dd, AES_REG_CTRL, val, mask);
+ omap_aes_write_mask(dd, AES_REG_CTRL(dd), val, mask);
- /* IN */
- omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT,
- dd->phys_base + AES_REG_DATA, 0, 4);
+ return 0;
+}
- omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
- omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
+static void omap_aes_dma_trigger_omap2(struct omap_aes_dev *dd, int length)
+{
+ u32 mask, val;
- /* OUT */
- omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT,
- dd->phys_base + AES_REG_DATA, 0, 4);
+ val = dd->pdata->dma_start;
- omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
- omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
+ if (dd->dma_lch_out != NULL)
+ val |= dd->pdata->dma_enable_out;
+ if (dd->dma_lch_in != NULL)
+ val |= dd->pdata->dma_enable_in;
+
+ mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in |
+ dd->pdata->dma_start;
+
+ omap_aes_write_mask(dd, AES_REG_MASK(dd), val, mask);
- return 0;
+}
+
+static void omap_aes_dma_trigger_omap4(struct omap_aes_dev *dd, int length)
+{
+ omap_aes_write(dd, AES_REG_LENGTH_N(0), length);
+ omap_aes_write(dd, AES_REG_LENGTH_N(1), 0);
+
+ omap_aes_dma_trigger_omap2(dd, length);
+}
+
+static void omap_aes_dma_stop(struct omap_aes_dev *dd)
+{
+ u32 mask;
+
+ mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in |
+ dd->pdata->dma_start;
+
+ omap_aes_write_mask(dd, AES_REG_MASK(dd), 0, mask);
}
static struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx)
@@ -284,18 +314,10 @@ static struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx)
return dd;
}
-static void omap_aes_dma_callback(int lch, u16 ch_status, void *data)
+static void omap_aes_dma_out_callback(void *data)
{
struct omap_aes_dev *dd = data;
- if (ch_status != OMAP_DMA_BLOCK_IRQ) {
- pr_err("omap-aes DMA error status: 0x%hx\n", ch_status);
- dd->err = -EIO;
- dd->flags &= ~FLAGS_INIT; /* request to re-initialize */
- } else if (lch == dd->dma_lch_in) {
- return;
- }
-
/* dma_lch_out - completed */
tasklet_schedule(&dd->done_task);
}
@@ -303,9 +325,10 @@ static void omap_aes_dma_callback(int lch, u16 ch_status, void *data)
static int omap_aes_dma_init(struct omap_aes_dev *dd)
{
int err = -ENOMEM;
+ dma_cap_mask_t mask;
- dd->dma_lch_out = -1;
- dd->dma_lch_in = -1;
+ dd->dma_lch_out = NULL;
+ dd->dma_lch_in = NULL;
dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE);
dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE);
@@ -334,23 +357,31 @@ static int omap_aes_dma_init(struct omap_aes_dev *dd)
goto err_map_out;
}
- err = omap_request_dma(dd->dma_in, "omap-aes-rx",
- omap_aes_dma_callback, dd, &dd->dma_lch_in);
- if (err) {
- dev_err(dd->dev, "Unable to request DMA channel\n");
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ dd->dma_lch_in = dma_request_slave_channel_compat(mask,
+ omap_dma_filter_fn,
+ &dd->dma_in,
+ dd->dev, "rx");
+ if (!dd->dma_lch_in) {
+ dev_err(dd->dev, "Unable to request in DMA channel\n");
goto err_dma_in;
}
- err = omap_request_dma(dd->dma_out, "omap-aes-tx",
- omap_aes_dma_callback, dd, &dd->dma_lch_out);
- if (err) {
- dev_err(dd->dev, "Unable to request DMA channel\n");
+
+ dd->dma_lch_out = dma_request_slave_channel_compat(mask,
+ omap_dma_filter_fn,
+ &dd->dma_out,
+ dd->dev, "tx");
+ if (!dd->dma_lch_out) {
+ dev_err(dd->dev, "Unable to request out DMA channel\n");
goto err_dma_out;
}
return 0;
err_dma_out:
- omap_free_dma(dd->dma_lch_in);
+ dma_release_channel(dd->dma_lch_in);
err_dma_in:
dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
DMA_FROM_DEVICE);
@@ -367,8 +398,8 @@ err_alloc:
static void omap_aes_dma_cleanup(struct omap_aes_dev *dd)
{
- omap_free_dma(dd->dma_lch_out);
- omap_free_dma(dd->dma_lch_in);
+ dma_release_channel(dd->dma_lch_out);
+ dma_release_channel(dd->dma_lch_in);
dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
DMA_FROM_DEVICE);
dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
@@ -426,12 +457,15 @@ static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf,
return off;
}
-static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
- dma_addr_t dma_addr_out, int length)
+static int omap_aes_crypt_dma(struct crypto_tfm *tfm,
+ struct scatterlist *in_sg, struct scatterlist *out_sg)
{
struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm);
struct omap_aes_dev *dd = ctx->dd;
- int len32;
+ struct dma_async_tx_descriptor *tx_in, *tx_out;
+ struct dma_slave_config cfg;
+ dma_addr_t dma_addr_in = sg_dma_address(in_sg);
+ int ret, length = sg_dma_len(in_sg);
pr_debug("len: %d\n", length);
@@ -441,30 +475,61 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
dma_sync_single_for_device(dd->dev, dma_addr_in, length,
DMA_TO_DEVICE);
- len32 = DIV_ROUND_UP(length, sizeof(u32));
+ memset(&cfg, 0, sizeof(cfg));
+
+ cfg.src_addr = dd->phys_base + AES_REG_DATA_N(dd, 0);
+ cfg.dst_addr = dd->phys_base + AES_REG_DATA_N(dd, 0);
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.src_maxburst = DST_MAXBURST;
+ cfg.dst_maxburst = DST_MAXBURST;
/* IN */
- omap_set_dma_transfer_params(dd->dma_lch_in, OMAP_DMA_DATA_TYPE_S32,
- len32, 1, OMAP_DMA_SYNC_PACKET, dd->dma_in,
- OMAP_DMA_DST_SYNC);
+ ret = dmaengine_slave_config(dd->dma_lch_in, &cfg);
+ if (ret) {
+ dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n",
+ ret);
+ return ret;
+ }
+
+ tx_in = dmaengine_prep_slave_sg(dd->dma_lch_in, in_sg, 1,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!tx_in) {
+ dev_err(dd->dev, "IN prep_slave_sg() failed\n");
+ return -EINVAL;
+ }
- omap_set_dma_src_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_POST_INC,
- dma_addr_in, 0, 0);
+ /* No callback necessary */
+ tx_in->callback_param = dd;
/* OUT */
- omap_set_dma_transfer_params(dd->dma_lch_out, OMAP_DMA_DATA_TYPE_S32,
- len32, 1, OMAP_DMA_SYNC_PACKET,
- dd->dma_out, OMAP_DMA_SRC_SYNC);
+ ret = dmaengine_slave_config(dd->dma_lch_out, &cfg);
+ if (ret) {
+ dev_err(dd->dev, "can't configure OUT dmaengine slave: %d\n",
+ ret);
+ return ret;
+ }
+
+ tx_out = dmaengine_prep_slave_sg(dd->dma_lch_out, out_sg, 1,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!tx_out) {
+ dev_err(dd->dev, "OUT prep_slave_sg() failed\n");
+ return -EINVAL;
+ }
- omap_set_dma_dest_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_POST_INC,
- dma_addr_out, 0, 0);
+ tx_out->callback = omap_aes_dma_out_callback;
+ tx_out->callback_param = dd;
- omap_start_dma(dd->dma_lch_in);
- omap_start_dma(dd->dma_lch_out);
+ dmaengine_submit(tx_in);
+ dmaengine_submit(tx_out);
- /* start DMA or disable idle mode */
- omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START,
- AES_REG_MASK_START);
+ dma_async_issue_pending(dd->dma_lch_in);
+ dma_async_issue_pending(dd->dma_lch_out);
+
+ /* start DMA */
+ dd->pdata->trigger(dd, length);
return 0;
}
@@ -476,6 +541,8 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd)
int err, fast = 0, in, out;
size_t count;
dma_addr_t addr_in, addr_out;
+ struct scatterlist *in_sg, *out_sg;
+ int len32;
pr_debug("total: %d\n", dd->total);
@@ -514,6 +581,9 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd)
addr_in = sg_dma_address(dd->in_sg);
addr_out = sg_dma_address(dd->out_sg);
+ in_sg = dd->in_sg;
+ out_sg = dd->out_sg;
+
dd->flags |= FLAGS_FAST;
} else {
@@ -521,6 +591,27 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd)
count = sg_copy(&dd->in_sg, &dd->in_offset, dd->buf_in,
dd->buflen, dd->total, 0);
+ len32 = DIV_ROUND_UP(count, DMA_MIN) * DMA_MIN;
+
+ /*
+ * The data going into the AES module has been copied
+ * to a local buffer and the data coming out will go
+ * into a local buffer so set up local SG entries for
+ * both.
+ */
+ sg_init_table(&dd->in_sgl, 1);
+ dd->in_sgl.offset = dd->in_offset;
+ sg_dma_len(&dd->in_sgl) = len32;
+ sg_dma_address(&dd->in_sgl) = dd->dma_addr_in;
+
+ sg_init_table(&dd->out_sgl, 1);
+ dd->out_sgl.offset = dd->out_offset;
+ sg_dma_len(&dd->out_sgl) = len32;
+ sg_dma_address(&dd->out_sgl) = dd->dma_addr_out;
+
+ in_sg = &dd->in_sgl;
+ out_sg = &dd->out_sgl;
+
addr_in = dd->dma_addr_in;
addr_out = dd->dma_addr_out;
@@ -530,7 +621,7 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd)
dd->total -= count;
- err = omap_aes_crypt_dma(tfm, addr_in, addr_out, count);
+ err = omap_aes_crypt_dma(tfm, in_sg, out_sg);
if (err) {
dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
@@ -545,7 +636,7 @@ static void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
pr_debug("err: %d\n", err);
- clk_disable(dd->iclk);
+ pm_runtime_put_sync(dd->dev);
dd->flags &= ~FLAGS_BUSY;
req->base.complete(&req->base, err);
@@ -558,10 +649,10 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
pr_debug("total: %d\n", dd->total);
- omap_aes_write_mask(dd, AES_REG_MASK, 0, AES_REG_MASK_START);
+ omap_aes_dma_stop(dd);
- omap_stop_dma(dd->dma_lch_in);
- omap_stop_dma(dd->dma_lch_out);
+ dmaengine_terminate_all(dd->dma_lch_in);
+ dmaengine_terminate_all(dd->dma_lch_out);
if (dd->flags & FLAGS_FAST) {
dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
@@ -734,6 +825,16 @@ static int omap_aes_cbc_decrypt(struct ablkcipher_request *req)
return omap_aes_crypt(req, FLAGS_CBC);
}
+static int omap_aes_ctr_encrypt(struct ablkcipher_request *req)
+{
+ return omap_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CTR);
+}
+
+static int omap_aes_ctr_decrypt(struct ablkcipher_request *req)
+{
+ return omap_aes_crypt(req, FLAGS_CTR);
+}
+
static int omap_aes_cra_init(struct crypto_tfm *tfm)
{
pr_debug("enter\n");
@@ -750,7 +851,7 @@ static void omap_aes_cra_exit(struct crypto_tfm *tfm)
/* ********************** ALGS ************************************ */
-static struct crypto_alg algs[] = {
+static struct crypto_alg algs_ecb_cbc[] = {
{
.cra_name = "ecb(aes)",
.cra_driver_name = "ecb-aes-omap",
@@ -798,11 +899,213 @@ static struct crypto_alg algs[] = {
}
};
+static struct crypto_alg algs_ctr[] = {
+{
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-omap",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_aes_cra_init,
+ .cra_exit = omap_aes_cra_exit,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .geniv = "eseqiv",
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = omap_aes_setkey,
+ .encrypt = omap_aes_ctr_encrypt,
+ .decrypt = omap_aes_ctr_decrypt,
+ }
+} ,
+};
+
+static struct omap_aes_algs_info omap_aes_algs_info_ecb_cbc[] = {
+ {
+ .algs_list = algs_ecb_cbc,
+ .size = ARRAY_SIZE(algs_ecb_cbc),
+ },
+};
+
+static const struct omap_aes_pdata omap_aes_pdata_omap2 = {
+ .algs_info = omap_aes_algs_info_ecb_cbc,
+ .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc),
+ .trigger = omap_aes_dma_trigger_omap2,
+ .key_ofs = 0x1c,
+ .iv_ofs = 0x20,
+ .ctrl_ofs = 0x30,
+ .data_ofs = 0x34,
+ .rev_ofs = 0x44,
+ .mask_ofs = 0x48,
+ .dma_enable_in = BIT(2),
+ .dma_enable_out = BIT(3),
+ .dma_start = BIT(5),
+ .major_mask = 0xf0,
+ .major_shift = 4,
+ .minor_mask = 0x0f,
+ .minor_shift = 0,
+};
+
+#ifdef CONFIG_OF
+static struct omap_aes_algs_info omap_aes_algs_info_ecb_cbc_ctr[] = {
+ {
+ .algs_list = algs_ecb_cbc,
+ .size = ARRAY_SIZE(algs_ecb_cbc),
+ },
+ {
+ .algs_list = algs_ctr,
+ .size = ARRAY_SIZE(algs_ctr),
+ },
+};
+
+static const struct omap_aes_pdata omap_aes_pdata_omap3 = {
+ .algs_info = omap_aes_algs_info_ecb_cbc_ctr,
+ .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc_ctr),
+ .trigger = omap_aes_dma_trigger_omap2,
+ .key_ofs = 0x1c,
+ .iv_ofs = 0x20,
+ .ctrl_ofs = 0x30,
+ .data_ofs = 0x34,
+ .rev_ofs = 0x44,
+ .mask_ofs = 0x48,
+ .dma_enable_in = BIT(2),
+ .dma_enable_out = BIT(3),
+ .dma_start = BIT(5),
+ .major_mask = 0xf0,
+ .major_shift = 4,
+ .minor_mask = 0x0f,
+ .minor_shift = 0,
+};
+
+static const struct omap_aes_pdata omap_aes_pdata_omap4 = {
+ .algs_info = omap_aes_algs_info_ecb_cbc_ctr,
+ .algs_info_size = ARRAY_SIZE(omap_aes_algs_info_ecb_cbc_ctr),
+ .trigger = omap_aes_dma_trigger_omap4,
+ .key_ofs = 0x3c,
+ .iv_ofs = 0x40,
+ .ctrl_ofs = 0x50,
+ .data_ofs = 0x60,
+ .rev_ofs = 0x80,
+ .mask_ofs = 0x84,
+ .dma_enable_in = BIT(5),
+ .dma_enable_out = BIT(6),
+ .major_mask = 0x0700,
+ .major_shift = 8,
+ .minor_mask = 0x003f,
+ .minor_shift = 0,
+};
+
+static const struct of_device_id omap_aes_of_match[] = {
+ {
+ .compatible = "ti,omap2-aes",
+ .data = &omap_aes_pdata_omap2,
+ },
+ {
+ .compatible = "ti,omap3-aes",
+ .data = &omap_aes_pdata_omap3,
+ },
+ {
+ .compatible = "ti,omap4-aes",
+ .data = &omap_aes_pdata_omap4,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, omap_aes_of_match);
+
+static int omap_aes_get_res_of(struct omap_aes_dev *dd,
+ struct device *dev, struct resource *res)
+{
+ struct device_node *node = dev->of_node;
+ const struct of_device_id *match;
+ int err = 0;
+
+ match = of_match_device(of_match_ptr(omap_aes_of_match), dev);
+ if (!match) {
+ dev_err(dev, "no compatible OF match\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ err = of_address_to_resource(node, 0, res);
+ if (err < 0) {
+ dev_err(dev, "can't translate OF node address\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ dd->dma_out = -1; /* Dummy value that's unused */
+ dd->dma_in = -1; /* Dummy value that's unused */
+
+ dd->pdata = match->data;
+
+err:
+ return err;
+}
+#else
+static const struct of_device_id omap_aes_of_match[] = {
+ {},
+};
+
+static int omap_aes_get_res_of(struct omap_aes_dev *dd,
+ struct device *dev, struct resource *res)
+{
+ return -EINVAL;
+}
+#endif
+
+static int omap_aes_get_res_pdev(struct omap_aes_dev *dd,
+ struct platform_device *pdev, struct resource *res)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *r;
+ int err = 0;
+
+ /* Get the base address */
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(dev, "no MEM resource info\n");
+ err = -ENODEV;
+ goto err;
+ }
+ memcpy(res, r, sizeof(*res));
+
+ /* Get the DMA out channel */
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!r) {
+ dev_err(dev, "no DMA out resource info\n");
+ err = -ENODEV;
+ goto err;
+ }
+ dd->dma_out = r->start;
+
+ /* Get the DMA in channel */
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!r) {
+ dev_err(dev, "no DMA in resource info\n");
+ err = -ENODEV;
+ goto err;
+ }
+ dd->dma_in = r->start;
+
+ /* Only OMAP2/3 can be non-DT */
+ dd->pdata = &omap_aes_pdata_omap2;
+
+err:
+ return err;
+}
+
static int omap_aes_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct omap_aes_dev *dd;
- struct resource *res;
+ struct crypto_alg *algp;
+ struct resource res;
int err = -ENOMEM, i, j;
u32 reg;
@@ -817,49 +1120,31 @@ static int omap_aes_probe(struct platform_device *pdev)
spin_lock_init(&dd->lock);
crypto_init_queue(&dd->queue, OMAP_AES_QUEUE_LENGTH);
- /* Get the base address */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "invalid resource type\n");
- err = -ENODEV;
- goto err_res;
- }
- dd->phys_base = res->start;
-
- /* Get the DMA */
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!res)
- dev_info(dev, "no DMA info\n");
- else
- dd->dma_out = res->start;
-
- /* Get the DMA */
- res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!res)
- dev_info(dev, "no DMA info\n");
- else
- dd->dma_in = res->start;
-
- /* Initializing the clock */
- dd->iclk = clk_get(dev, "ick");
- if (IS_ERR(dd->iclk)) {
- dev_err(dev, "clock intialization failed.\n");
- err = PTR_ERR(dd->iclk);
+ err = (dev->of_node) ? omap_aes_get_res_of(dd, dev, &res) :
+ omap_aes_get_res_pdev(dd, pdev, &res);
+ if (err)
goto err_res;
- }
- dd->io_base = ioremap(dd->phys_base, SZ_4K);
+ dd->io_base = devm_request_and_ioremap(dev, &res);
if (!dd->io_base) {
dev_err(dev, "can't ioremap\n");
err = -ENOMEM;
- goto err_io;
+ goto err_res;
}
+ dd->phys_base = res.start;
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
+ omap_aes_dma_stop(dd);
+
+ reg = omap_aes_read(dd, AES_REG_REV(dd));
+
+ pm_runtime_put_sync(dev);
- clk_enable(dd->iclk);
- reg = omap_aes_read(dd, AES_REG_REV);
dev_info(dev, "OMAP AES hw accel rev: %u.%u\n",
- (reg & AES_REG_REV_MAJOR) >> 4, reg & AES_REG_REV_MINOR);
- clk_disable(dd->iclk);
+ (reg & dd->pdata->major_mask) >> dd->pdata->major_shift,
+ (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift);
tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd);
tasklet_init(&dd->queue_task, omap_aes_queue_task, (unsigned long)dd);
@@ -873,26 +1158,32 @@ static int omap_aes_probe(struct platform_device *pdev)
list_add_tail(&dd->list, &dev_list);
spin_unlock(&list_lock);
- for (i = 0; i < ARRAY_SIZE(algs); i++) {
- pr_debug("i: %d\n", i);
- err = crypto_register_alg(&algs[i]);
- if (err)
- goto err_algs;
- }
+ for (i = 0; i < dd->pdata->algs_info_size; i++) {
+ for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
+ algp = &dd->pdata->algs_info[i].algs_list[j];
+
+ pr_debug("reg alg: %s\n", algp->cra_name);
+ INIT_LIST_HEAD(&algp->cra_list);
+
+ err = crypto_register_alg(algp);
+ if (err)
+ goto err_algs;
- pr_info("probe() done\n");
+ dd->pdata->algs_info[i].registered++;
+ }
+ }
return 0;
err_algs:
- for (j = 0; j < i; j++)
- crypto_unregister_alg(&algs[j]);
+ for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
+ for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
+ crypto_unregister_alg(
+ &dd->pdata->algs_info[i].algs_list[j]);
omap_aes_dma_cleanup(dd);
err_dma:
tasklet_kill(&dd->done_task);
tasklet_kill(&dd->queue_task);
- iounmap(dd->io_base);
-err_io:
- clk_put(dd->iclk);
+ pm_runtime_disable(dev);
err_res:
kfree(dd);
dd = NULL;
@@ -904,7 +1195,7 @@ err_data:
static int omap_aes_remove(struct platform_device *pdev)
{
struct omap_aes_dev *dd = platform_get_drvdata(pdev);
- int i;
+ int i, j;
if (!dd)
return -ENODEV;
@@ -913,33 +1204,52 @@ static int omap_aes_remove(struct platform_device *pdev)
list_del(&dd->list);
spin_unlock(&list_lock);
- for (i = 0; i < ARRAY_SIZE(algs); i++)
- crypto_unregister_alg(&algs[i]);
+ for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
+ for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
+ crypto_unregister_alg(
+ &dd->pdata->algs_info[i].algs_list[j]);
tasklet_kill(&dd->done_task);
tasklet_kill(&dd->queue_task);
omap_aes_dma_cleanup(dd);
- iounmap(dd->io_base);
- clk_put(dd->iclk);
+ pm_runtime_disable(dd->dev);
kfree(dd);
dd = NULL;
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int omap_aes_suspend(struct device *dev)
+{
+ pm_runtime_put_sync(dev);
+ return 0;
+}
+
+static int omap_aes_resume(struct device *dev)
+{
+ pm_runtime_get_sync(dev);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops omap_aes_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(omap_aes_suspend, omap_aes_resume)
+};
+
static struct platform_driver omap_aes_driver = {
.probe = omap_aes_probe,
.remove = omap_aes_remove,
.driver = {
.name = "omap-aes",
.owner = THIS_MODULE,
+ .pm = &omap_aes_pm_ops,
+ .of_match_table = omap_aes_of_match,
},
};
static int __init omap_aes_mod_init(void)
{
- pr_info("loading %s driver\n", "omap-aes");
-
return platform_driver_register(&omap_aes_driver);
}
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 90d34adc2a66..3d1611f5aecf 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -5,6 +5,7 @@
*
* Copyright (c) 2010 Nokia Corporation
* Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
+ * Copyright (c) 2011 Texas Instruments Incorporated
*
* 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
@@ -22,12 +23,18 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/omap-dma.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/delay.h>
#include <linux/crypto.h>
#include <linux/cryptohash.h>
@@ -37,16 +44,17 @@
#include <crypto/hash.h>
#include <crypto/internal/hash.h>
-#include <linux/omap-dma.h>
-#include <mach/irqs.h>
-
-#define SHA_REG_DIGEST(x) (0x00 + ((x) * 0x04))
-#define SHA_REG_DIN(x) (0x1C + ((x) * 0x04))
-
#define SHA1_MD5_BLOCK_SIZE SHA1_BLOCK_SIZE
#define MD5_DIGEST_SIZE 16
-#define SHA_REG_DIGCNT 0x14
+#define DST_MAXBURST 16
+#define DMA_MIN (DST_MAXBURST * sizeof(u32))
+
+#define SHA_REG_IDIGEST(dd, x) ((dd)->pdata->idigest_ofs + ((x)*0x04))
+#define SHA_REG_DIN(dd, x) ((dd)->pdata->din_ofs + ((x) * 0x04))
+#define SHA_REG_DIGCNT(dd) ((dd)->pdata->digcnt_ofs)
+
+#define SHA_REG_ODIGEST(x) (0x00 + ((x) * 0x04))
#define SHA_REG_CTRL 0x18
#define SHA_REG_CTRL_LENGTH (0xFFFFFFFF << 5)
@@ -56,19 +64,42 @@
#define SHA_REG_CTRL_INPUT_READY (1 << 1)
#define SHA_REG_CTRL_OUTPUT_READY (1 << 0)
-#define SHA_REG_REV 0x5C
-#define SHA_REG_REV_MAJOR 0xF0
-#define SHA_REG_REV_MINOR 0x0F
+#define SHA_REG_REV(dd) ((dd)->pdata->rev_ofs)
-#define SHA_REG_MASK 0x60
+#define SHA_REG_MASK(dd) ((dd)->pdata->mask_ofs)
#define SHA_REG_MASK_DMA_EN (1 << 3)
#define SHA_REG_MASK_IT_EN (1 << 2)
#define SHA_REG_MASK_SOFTRESET (1 << 1)
#define SHA_REG_AUTOIDLE (1 << 0)
-#define SHA_REG_SYSSTATUS 0x64
+#define SHA_REG_SYSSTATUS(dd) ((dd)->pdata->sysstatus_ofs)
#define SHA_REG_SYSSTATUS_RESETDONE (1 << 0)
+#define SHA_REG_MODE 0x44
+#define SHA_REG_MODE_HMAC_OUTER_HASH (1 << 7)
+#define SHA_REG_MODE_HMAC_KEY_PROC (1 << 5)
+#define SHA_REG_MODE_CLOSE_HASH (1 << 4)
+#define SHA_REG_MODE_ALGO_CONSTANT (1 << 3)
+#define SHA_REG_MODE_ALGO_MASK (3 << 1)
+#define SHA_REG_MODE_ALGO_MD5_128 (0 << 1)
+#define SHA_REG_MODE_ALGO_SHA1_160 (1 << 1)
+#define SHA_REG_MODE_ALGO_SHA2_224 (2 << 1)
+#define SHA_REG_MODE_ALGO_SHA2_256 (3 << 1)
+
+#define SHA_REG_LENGTH 0x48
+
+#define SHA_REG_IRQSTATUS 0x118
+#define SHA_REG_IRQSTATUS_CTX_RDY (1 << 3)
+#define SHA_REG_IRQSTATUS_PARTHASH_RDY (1 << 2)
+#define SHA_REG_IRQSTATUS_INPUT_RDY (1 << 1)
+#define SHA_REG_IRQSTATUS_OUTPUT_RDY (1 << 0)
+
+#define SHA_REG_IRQENA 0x11C
+#define SHA_REG_IRQENA_CTX_RDY (1 << 3)
+#define SHA_REG_IRQENA_PARTHASH_RDY (1 << 2)
+#define SHA_REG_IRQENA_INPUT_RDY (1 << 1)
+#define SHA_REG_IRQENA_OUTPUT_RDY (1 << 0)
+
#define DEFAULT_TIMEOUT_INTERVAL HZ
/* mostly device flags */
@@ -79,20 +110,33 @@
#define FLAGS_INIT 4
#define FLAGS_CPU 5
#define FLAGS_DMA_READY 6
+#define FLAGS_AUTO_XOR 7
+#define FLAGS_BE32_SHA1 8
/* context flags */
#define FLAGS_FINUP 16
#define FLAGS_SG 17
-#define FLAGS_SHA1 18
-#define FLAGS_HMAC 19
-#define FLAGS_ERROR 20
-#define OP_UPDATE 1
-#define OP_FINAL 2
+#define FLAGS_MODE_SHIFT 18
+#define FLAGS_MODE_MASK (SHA_REG_MODE_ALGO_MASK \
+ << (FLAGS_MODE_SHIFT - 1))
+#define FLAGS_MODE_MD5 (SHA_REG_MODE_ALGO_MD5_128 \
+ << (FLAGS_MODE_SHIFT - 1))
+#define FLAGS_MODE_SHA1 (SHA_REG_MODE_ALGO_SHA1_160 \
+ << (FLAGS_MODE_SHIFT - 1))
+#define FLAGS_MODE_SHA224 (SHA_REG_MODE_ALGO_SHA2_224 \
+ << (FLAGS_MODE_SHIFT - 1))
+#define FLAGS_MODE_SHA256 (SHA_REG_MODE_ALGO_SHA2_256 \
+ << (FLAGS_MODE_SHIFT - 1))
+#define FLAGS_HMAC 20
+#define FLAGS_ERROR 21
+
+#define OP_UPDATE 1
+#define OP_FINAL 2
#define OMAP_ALIGN_MASK (sizeof(u32)-1)
#define OMAP_ALIGNED __attribute__((aligned(sizeof(u32))))
-#define BUFLEN PAGE_SIZE
+#define BUFLEN PAGE_SIZE
struct omap_sham_dev;
@@ -101,7 +145,7 @@ struct omap_sham_reqctx {
unsigned long flags;
unsigned long op;
- u8 digest[SHA1_DIGEST_SIZE] OMAP_ALIGNED;
+ u8 digest[SHA256_DIGEST_SIZE] OMAP_ALIGNED;
size_t digcnt;
size_t bufcnt;
size_t buflen;
@@ -109,6 +153,7 @@ struct omap_sham_reqctx {
/* walk state */
struct scatterlist *sg;
+ struct scatterlist sgl;
unsigned int offset; /* offset in current sg */
unsigned int total; /* total request */
@@ -117,8 +162,8 @@ struct omap_sham_reqctx {
struct omap_sham_hmac_ctx {
struct crypto_shash *shash;
- u8 ipad[SHA1_MD5_BLOCK_SIZE];
- u8 opad[SHA1_MD5_BLOCK_SIZE];
+ u8 ipad[SHA1_MD5_BLOCK_SIZE] OMAP_ALIGNED;
+ u8 opad[SHA1_MD5_BLOCK_SIZE] OMAP_ALIGNED;
};
struct omap_sham_ctx {
@@ -134,22 +179,56 @@ struct omap_sham_ctx {
#define OMAP_SHAM_QUEUE_LENGTH 1
+struct omap_sham_algs_info {
+ struct ahash_alg *algs_list;
+ unsigned int size;
+ unsigned int registered;
+};
+
+struct omap_sham_pdata {
+ struct omap_sham_algs_info *algs_info;
+ unsigned int algs_info_size;
+ unsigned long flags;
+ int digest_size;
+
+ void (*copy_hash)(struct ahash_request *req, int out);
+ void (*write_ctrl)(struct omap_sham_dev *dd, size_t length,
+ int final, int dma);
+ void (*trigger)(struct omap_sham_dev *dd, size_t length);
+ int (*poll_irq)(struct omap_sham_dev *dd);
+ irqreturn_t (*intr_hdlr)(int irq, void *dev_id);
+
+ u32 odigest_ofs;
+ u32 idigest_ofs;
+ u32 din_ofs;
+ u32 digcnt_ofs;
+ u32 rev_ofs;
+ u32 mask_ofs;
+ u32 sysstatus_ofs;
+
+ u32 major_mask;
+ u32 major_shift;
+ u32 minor_mask;
+ u32 minor_shift;
+};
+
struct omap_sham_dev {
struct list_head list;
unsigned long phys_base;
struct device *dev;
void __iomem *io_base;
int irq;
- struct clk *iclk;
spinlock_t lock;
int err;
- int dma;
- int dma_lch;
+ unsigned int dma;
+ struct dma_chan *dma_lch;
struct tasklet_struct done_task;
unsigned long flags;
struct crypto_queue queue;
struct ahash_request *req;
+
+ const struct omap_sham_pdata *pdata;
};
struct omap_sham_drv {
@@ -197,21 +276,44 @@ static inline int omap_sham_wait(struct omap_sham_dev *dd, u32 offset, u32 bit)
return 0;
}
-static void omap_sham_copy_hash(struct ahash_request *req, int out)
+static void omap_sham_copy_hash_omap2(struct ahash_request *req, int out)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
+ struct omap_sham_dev *dd = ctx->dd;
u32 *hash = (u32 *)ctx->digest;
int i;
- /* MD5 is almost unused. So copy sha1 size to reduce code */
- for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) {
+ for (i = 0; i < dd->pdata->digest_size / sizeof(u32); i++) {
if (out)
- hash[i] = omap_sham_read(ctx->dd,
- SHA_REG_DIGEST(i));
+ hash[i] = omap_sham_read(dd, SHA_REG_IDIGEST(dd, i));
else
- omap_sham_write(ctx->dd,
- SHA_REG_DIGEST(i), hash[i]);
+ omap_sham_write(dd, SHA_REG_IDIGEST(dd, i), hash[i]);
+ }
+}
+
+static void omap_sham_copy_hash_omap4(struct ahash_request *req, int out)
+{
+ struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
+ struct omap_sham_dev *dd = ctx->dd;
+ int i;
+
+ if (ctx->flags & BIT(FLAGS_HMAC)) {
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(dd->req);
+ struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct omap_sham_hmac_ctx *bctx = tctx->base;
+ u32 *opad = (u32 *)bctx->opad;
+
+ for (i = 0; i < dd->pdata->digest_size / sizeof(u32); i++) {
+ if (out)
+ opad[i] = omap_sham_read(dd,
+ SHA_REG_ODIGEST(i));
+ else
+ omap_sham_write(dd, SHA_REG_ODIGEST(i),
+ opad[i]);
+ }
}
+
+ omap_sham_copy_hash_omap2(req, out);
}
static void omap_sham_copy_ready_hash(struct ahash_request *req)
@@ -219,34 +321,44 @@ static void omap_sham_copy_ready_hash(struct ahash_request *req)
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
u32 *in = (u32 *)ctx->digest;
u32 *hash = (u32 *)req->result;
- int i;
+ int i, d, big_endian = 0;
if (!hash)
return;
- if (likely(ctx->flags & BIT(FLAGS_SHA1))) {
- /* SHA1 results are in big endian */
- for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
+ switch (ctx->flags & FLAGS_MODE_MASK) {
+ case FLAGS_MODE_MD5:
+ d = MD5_DIGEST_SIZE / sizeof(u32);
+ break;
+ case FLAGS_MODE_SHA1:
+ /* OMAP2 SHA1 is big endian */
+ if (test_bit(FLAGS_BE32_SHA1, &ctx->dd->flags))
+ big_endian = 1;
+ d = SHA1_DIGEST_SIZE / sizeof(u32);
+ break;
+ case FLAGS_MODE_SHA224:
+ d = SHA224_DIGEST_SIZE / sizeof(u32);
+ break;
+ case FLAGS_MODE_SHA256:
+ d = SHA256_DIGEST_SIZE / sizeof(u32);
+ break;
+ default:
+ d = 0;
+ }
+
+ if (big_endian)
+ for (i = 0; i < d; i++)
hash[i] = be32_to_cpu(in[i]);
- } else {
- /* MD5 results are in little endian */
- for (i = 0; i < MD5_DIGEST_SIZE / sizeof(u32); i++)
+ else
+ for (i = 0; i < d; i++)
hash[i] = le32_to_cpu(in[i]);
- }
}
static int omap_sham_hw_init(struct omap_sham_dev *dd)
{
- clk_enable(dd->iclk);
+ pm_runtime_get_sync(dd->dev);
if (!test_bit(FLAGS_INIT, &dd->flags)) {
- omap_sham_write_mask(dd, SHA_REG_MASK,
- SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET);
-
- if (omap_sham_wait(dd, SHA_REG_SYSSTATUS,
- SHA_REG_SYSSTATUS_RESETDONE))
- return -ETIMEDOUT;
-
set_bit(FLAGS_INIT, &dd->flags);
dd->err = 0;
}
@@ -254,23 +366,23 @@ static int omap_sham_hw_init(struct omap_sham_dev *dd)
return 0;
}
-static void omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length,
+static void omap_sham_write_ctrl_omap2(struct omap_sham_dev *dd, size_t length,
int final, int dma)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
u32 val = length << 5, mask;
if (likely(ctx->digcnt))
- omap_sham_write(dd, SHA_REG_DIGCNT, ctx->digcnt);
+ omap_sham_write(dd, SHA_REG_DIGCNT(dd), ctx->digcnt);
- omap_sham_write_mask(dd, SHA_REG_MASK,
+ omap_sham_write_mask(dd, SHA_REG_MASK(dd),
SHA_REG_MASK_IT_EN | (dma ? SHA_REG_MASK_DMA_EN : 0),
SHA_REG_MASK_IT_EN | SHA_REG_MASK_DMA_EN);
/*
* Setting ALGO_CONST only for the first iteration
* and CLOSE_HASH only for the last one.
*/
- if (ctx->flags & BIT(FLAGS_SHA1))
+ if ((ctx->flags & FLAGS_MODE_MASK) == FLAGS_MODE_SHA1)
val |= SHA_REG_CTRL_ALGO;
if (!ctx->digcnt)
val |= SHA_REG_CTRL_ALGO_CONST;
@@ -283,6 +395,81 @@ static void omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length,
omap_sham_write_mask(dd, SHA_REG_CTRL, val, mask);
}
+static void omap_sham_trigger_omap2(struct omap_sham_dev *dd, size_t length)
+{
+}
+
+static int omap_sham_poll_irq_omap2(struct omap_sham_dev *dd)
+{
+ return omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY);
+}
+
+static void omap_sham_write_n(struct omap_sham_dev *dd, u32 offset,
+ u32 *value, int count)
+{
+ for (; count--; value++, offset += 4)
+ omap_sham_write(dd, offset, *value);
+}
+
+static void omap_sham_write_ctrl_omap4(struct omap_sham_dev *dd, size_t length,
+ int final, int dma)
+{
+ struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
+ u32 val, mask;
+
+ /*
+ * Setting ALGO_CONST only for the first iteration and
+ * CLOSE_HASH only for the last one. Note that flags mode bits
+ * correspond to algorithm encoding in mode register.
+ */
+ val = (ctx->flags & FLAGS_MODE_MASK) >> (FLAGS_MODE_SHIFT - 1);
+ if (!ctx->digcnt) {
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(dd->req);
+ struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
+ struct omap_sham_hmac_ctx *bctx = tctx->base;
+
+ val |= SHA_REG_MODE_ALGO_CONSTANT;
+
+ if (ctx->flags & BIT(FLAGS_HMAC)) {
+ val |= SHA_REG_MODE_HMAC_KEY_PROC;
+ omap_sham_write_n(dd, SHA_REG_ODIGEST(0),
+ (u32 *)bctx->ipad,
+ SHA1_BLOCK_SIZE / sizeof(u32));
+ ctx->digcnt += SHA1_BLOCK_SIZE;
+ }
+ }
+
+ if (final) {
+ val |= SHA_REG_MODE_CLOSE_HASH;
+
+ if (ctx->flags & BIT(FLAGS_HMAC))
+ val |= SHA_REG_MODE_HMAC_OUTER_HASH;
+ }
+
+ mask = SHA_REG_MODE_ALGO_CONSTANT | SHA_REG_MODE_CLOSE_HASH |
+ SHA_REG_MODE_ALGO_MASK | SHA_REG_MODE_HMAC_OUTER_HASH |
+ SHA_REG_MODE_HMAC_KEY_PROC;
+
+ dev_dbg(dd->dev, "ctrl: %08x, flags: %08lx\n", val, ctx->flags);
+ omap_sham_write_mask(dd, SHA_REG_MODE, val, mask);
+ omap_sham_write(dd, SHA_REG_IRQENA, SHA_REG_IRQENA_OUTPUT_RDY);
+ omap_sham_write_mask(dd, SHA_REG_MASK(dd),
+ SHA_REG_MASK_IT_EN |
+ (dma ? SHA_REG_MASK_DMA_EN : 0),
+ SHA_REG_MASK_IT_EN | SHA_REG_MASK_DMA_EN);
+}
+
+static void omap_sham_trigger_omap4(struct omap_sham_dev *dd, size_t length)
+{
+ omap_sham_write(dd, SHA_REG_LENGTH, length);
+}
+
+static int omap_sham_poll_irq_omap4(struct omap_sham_dev *dd)
+{
+ return omap_sham_wait(dd, SHA_REG_IRQSTATUS,
+ SHA_REG_IRQSTATUS_INPUT_RDY);
+}
+
static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
size_t length, int final)
{
@@ -293,12 +480,13 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
ctx->digcnt, length, final);
- omap_sham_write_ctrl(dd, length, final, 0);
+ dd->pdata->write_ctrl(dd, length, final, 0);
+ dd->pdata->trigger(dd, length);
/* should be non-zero before next lines to disable clocks later */
ctx->digcnt += length;
- if (omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY))
+ if (dd->pdata->poll_irq(dd))
return -ETIMEDOUT;
if (final)
@@ -309,30 +497,73 @@ static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf,
len32 = DIV_ROUND_UP(length, sizeof(u32));
for (count = 0; count < len32; count++)
- omap_sham_write(dd, SHA_REG_DIN(count), buffer[count]);
+ omap_sham_write(dd, SHA_REG_DIN(dd, count), buffer[count]);
return -EINPROGRESS;
}
+static void omap_sham_dma_callback(void *param)
+{
+ struct omap_sham_dev *dd = param;
+
+ set_bit(FLAGS_DMA_READY, &dd->flags);
+ tasklet_schedule(&dd->done_task);
+}
+
static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
- size_t length, int final)
+ size_t length, int final, int is_sg)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- int len32;
+ struct dma_async_tx_descriptor *tx;
+ struct dma_slave_config cfg;
+ int len32, ret;
dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n",
ctx->digcnt, length, final);
- len32 = DIV_ROUND_UP(length, sizeof(u32));
+ memset(&cfg, 0, sizeof(cfg));
+
+ cfg.dst_addr = dd->phys_base + SHA_REG_DIN(dd, 0);
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ cfg.dst_maxburst = DST_MAXBURST;
+
+ ret = dmaengine_slave_config(dd->dma_lch, &cfg);
+ if (ret) {
+ pr_err("omap-sham: can't configure dmaengine slave: %d\n", ret);
+ return ret;
+ }
- omap_set_dma_transfer_params(dd->dma_lch, OMAP_DMA_DATA_TYPE_S32, len32,
- 1, OMAP_DMA_SYNC_PACKET, dd->dma,
- OMAP_DMA_DST_SYNC_PREFETCH);
+ len32 = DIV_ROUND_UP(length, DMA_MIN) * DMA_MIN;
+
+ if (is_sg) {
+ /*
+ * The SG entry passed in may not have the 'length' member
+ * set correctly so use a local SG entry (sgl) with the
+ * proper value for 'length' instead. If this is not done,
+ * the dmaengine may try to DMA the incorrect amount of data.
+ */
+ sg_init_table(&ctx->sgl, 1);
+ ctx->sgl.page_link = ctx->sg->page_link;
+ ctx->sgl.offset = ctx->sg->offset;
+ sg_dma_len(&ctx->sgl) = len32;
+ sg_dma_address(&ctx->sgl) = sg_dma_address(ctx->sg);
+
+ tx = dmaengine_prep_slave_sg(dd->dma_lch, &ctx->sgl, 1,
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ } else {
+ tx = dmaengine_prep_slave_single(dd->dma_lch, dma_addr, len32,
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ }
+
+ if (!tx) {
+ dev_err(dd->dev, "prep_slave_sg/single() failed\n");
+ return -EINVAL;
+ }
- omap_set_dma_src_params(dd->dma_lch, 0, OMAP_DMA_AMODE_POST_INC,
- dma_addr, 0, 0);
+ tx->callback = omap_sham_dma_callback;
+ tx->callback_param = dd;
- omap_sham_write_ctrl(dd, length, final, 1);
+ dd->pdata->write_ctrl(dd, length, final, 1);
ctx->digcnt += length;
@@ -341,7 +572,10 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr,
set_bit(FLAGS_DMA_ACTIVE, &dd->flags);
- omap_start_dma(dd->dma_lch);
+ dmaengine_submit(tx);
+ dma_async_issue_pending(dd->dma_lch);
+
+ dd->pdata->trigger(dd, length);
return -EINPROGRESS;
}
@@ -388,6 +622,8 @@ static int omap_sham_xmit_dma_map(struct omap_sham_dev *dd,
struct omap_sham_reqctx *ctx,
size_t length, int final)
{
+ int ret;
+
ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen,
DMA_TO_DEVICE);
if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
@@ -397,8 +633,12 @@ static int omap_sham_xmit_dma_map(struct omap_sham_dev *dd,
ctx->flags &= ~BIT(FLAGS_SG);
- /* next call does not fail... so no unmap in the case of error */
- return omap_sham_xmit_dma(dd, ctx->dma_addr, length, final);
+ ret = omap_sham_xmit_dma(dd, ctx->dma_addr, length, final, 0);
+ if (ret != -EINPROGRESS)
+ dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen,
+ DMA_TO_DEVICE);
+
+ return ret;
}
static int omap_sham_update_dma_slow(struct omap_sham_dev *dd)
@@ -433,6 +673,7 @@ static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
unsigned int length, final, tail;
struct scatterlist *sg;
+ int ret;
if (!ctx->total)
return 0;
@@ -440,6 +681,15 @@ static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
if (ctx->bufcnt || ctx->offset)
return omap_sham_update_dma_slow(dd);
+ /*
+ * Don't use the sg interface when the transfer size is less
+ * than the number of elements in a DMA frame. Otherwise,
+ * the dmaengine infrastructure will calculate that it needs
+ * to transfer 0 frames which ultimately fails.
+ */
+ if (ctx->total < (DST_MAXBURST * sizeof(u32)))
+ return omap_sham_update_dma_slow(dd);
+
dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
ctx->digcnt, ctx->bufcnt, ctx->total);
@@ -477,8 +727,11 @@ static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
final = (ctx->flags & BIT(FLAGS_FINUP)) && !ctx->total;
- /* next call does not fail... so no unmap in the case of error */
- return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, final);
+ ret = omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, final, 1);
+ if (ret != -EINPROGRESS)
+ dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
+
+ return ret;
}
static int omap_sham_update_cpu(struct omap_sham_dev *dd)
@@ -497,7 +750,8 @@ static int omap_sham_update_dma_stop(struct omap_sham_dev *dd)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
- omap_stop_dma(dd->dma_lch);
+ dmaengine_terminate_all(dd->dma_lch);
+
if (ctx->flags & BIT(FLAGS_SG)) {
dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
if (ctx->sg->length == ctx->offset) {
@@ -539,18 +793,33 @@ static int omap_sham_init(struct ahash_request *req)
dev_dbg(dd->dev, "init: digest size: %d\n",
crypto_ahash_digestsize(tfm));
- if (crypto_ahash_digestsize(tfm) == SHA1_DIGEST_SIZE)
- ctx->flags |= BIT(FLAGS_SHA1);
+ switch (crypto_ahash_digestsize(tfm)) {
+ case MD5_DIGEST_SIZE:
+ ctx->flags |= FLAGS_MODE_MD5;
+ break;
+ case SHA1_DIGEST_SIZE:
+ ctx->flags |= FLAGS_MODE_SHA1;
+ break;
+ case SHA224_DIGEST_SIZE:
+ ctx->flags |= FLAGS_MODE_SHA224;
+ break;
+ case SHA256_DIGEST_SIZE:
+ ctx->flags |= FLAGS_MODE_SHA256;
+ break;
+ }
ctx->bufcnt = 0;
ctx->digcnt = 0;
ctx->buflen = BUFLEN;
if (tctx->flags & BIT(FLAGS_HMAC)) {
- struct omap_sham_hmac_ctx *bctx = tctx->base;
+ if (!test_bit(FLAGS_AUTO_XOR, &dd->flags)) {
+ struct omap_sham_hmac_ctx *bctx = tctx->base;
+
+ memcpy(ctx->buffer, bctx->ipad, SHA1_MD5_BLOCK_SIZE);
+ ctx->bufcnt = SHA1_MD5_BLOCK_SIZE;
+ }
- memcpy(ctx->buffer, bctx->ipad, SHA1_MD5_BLOCK_SIZE);
- ctx->bufcnt = SHA1_MD5_BLOCK_SIZE;
ctx->flags |= BIT(FLAGS_HMAC);
}
@@ -584,7 +853,7 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
int err = 0, use_dma = 1;
- if (ctx->bufcnt <= 64)
+ if (ctx->bufcnt <= DMA_MIN)
/* faster to handle last block with cpu */
use_dma = 0;
@@ -627,7 +896,8 @@ static int omap_sham_finish(struct ahash_request *req)
if (ctx->digcnt) {
omap_sham_copy_ready_hash(req);
- if (ctx->flags & BIT(FLAGS_HMAC))
+ if ((ctx->flags & BIT(FLAGS_HMAC)) &&
+ !test_bit(FLAGS_AUTO_XOR, &dd->flags))
err = omap_sham_finish_hmac(req);
}
@@ -642,7 +912,7 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)
struct omap_sham_dev *dd = ctx->dd;
if (!err) {
- omap_sham_copy_hash(req, 1);
+ dd->pdata->copy_hash(req, 1);
if (test_bit(FLAGS_FINAL, &dd->flags))
err = omap_sham_finish(req);
} else {
@@ -652,7 +922,8 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)
/* atomic operation is not needed here */
dd->flags &= ~(BIT(FLAGS_BUSY) | BIT(FLAGS_FINAL) | BIT(FLAGS_CPU) |
BIT(FLAGS_DMA_READY) | BIT(FLAGS_OUTPUT_READY));
- clk_disable(dd->iclk);
+
+ pm_runtime_put_sync(dd->dev);
if (req->base.complete)
req->base.complete(&req->base, err);
@@ -699,19 +970,9 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd,
if (err)
goto err1;
- omap_set_dma_dest_params(dd->dma_lch, 0,
- OMAP_DMA_AMODE_CONSTANT,
- dd->phys_base + SHA_REG_DIN(0), 0, 16);
-
- omap_set_dma_dest_burst_mode(dd->dma_lch,
- OMAP_DMA_DATA_BURST_16);
-
- omap_set_dma_src_burst_mode(dd->dma_lch,
- OMAP_DMA_DATA_BURST_4);
-
if (ctx->digcnt)
/* request has changed - restore hash */
- omap_sham_copy_hash(req, 0);
+ dd->pdata->copy_hash(req, 0);
if (ctx->op == OP_UPDATE) {
err = omap_sham_update_req(dd);
@@ -850,7 +1111,21 @@ static int omap_sham_setkey(struct crypto_ahash *tfm, const u8 *key,
struct omap_sham_hmac_ctx *bctx = tctx->base;
int bs = crypto_shash_blocksize(bctx->shash);
int ds = crypto_shash_digestsize(bctx->shash);
+ struct omap_sham_dev *dd = NULL, *tmp;
int err, i;
+
+ spin_lock_bh(&sham.lock);
+ if (!tctx->dd) {
+ list_for_each_entry(tmp, &sham.dev_list, list) {
+ dd = tmp;
+ break;
+ }
+ tctx->dd = dd;
+ } else {
+ dd = tctx->dd;
+ }
+ spin_unlock_bh(&sham.lock);
+
err = crypto_shash_setkey(tctx->fallback, key, keylen);
if (err)
return err;
@@ -867,11 +1142,14 @@ static int omap_sham_setkey(struct crypto_ahash *tfm, const u8 *key,
}
memset(bctx->ipad + keylen, 0, bs - keylen);
- memcpy(bctx->opad, bctx->ipad, bs);
- for (i = 0; i < bs; i++) {
- bctx->ipad[i] ^= 0x36;
- bctx->opad[i] ^= 0x5c;
+ if (!test_bit(FLAGS_AUTO_XOR, &dd->flags)) {
+ memcpy(bctx->opad, bctx->ipad, bs);
+
+ for (i = 0; i < bs; i++) {
+ bctx->ipad[i] ^= 0x36;
+ bctx->opad[i] ^= 0x5c;
+ }
}
return err;
@@ -921,6 +1199,16 @@ static int omap_sham_cra_sha1_init(struct crypto_tfm *tfm)
return omap_sham_cra_init_alg(tfm, "sha1");
}
+static int omap_sham_cra_sha224_init(struct crypto_tfm *tfm)
+{
+ return omap_sham_cra_init_alg(tfm, "sha224");
+}
+
+static int omap_sham_cra_sha256_init(struct crypto_tfm *tfm)
+{
+ return omap_sham_cra_init_alg(tfm, "sha256");
+}
+
static int omap_sham_cra_md5_init(struct crypto_tfm *tfm)
{
return omap_sham_cra_init_alg(tfm, "md5");
@@ -939,7 +1227,7 @@ static void omap_sham_cra_exit(struct crypto_tfm *tfm)
}
}
-static struct ahash_alg algs[] = {
+static struct ahash_alg algs_sha1_md5[] = {
{
.init = omap_sham_init,
.update = omap_sham_update,
@@ -1038,6 +1326,102 @@ static struct ahash_alg algs[] = {
}
};
+/* OMAP4 has some algs in addition to what OMAP2 has */
+static struct ahash_alg algs_sha224_sha256[] = {
+{
+ .init = omap_sham_init,
+ .update = omap_sham_update,
+ .final = omap_sham_final,
+ .finup = omap_sham_finup,
+ .digest = omap_sham_digest,
+ .halg.digestsize = SHA224_DIGEST_SIZE,
+ .halg.base = {
+ .cra_name = "sha224",
+ .cra_driver_name = "omap-sha224",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA224_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_sham_ctx),
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_sham_cra_init,
+ .cra_exit = omap_sham_cra_exit,
+ }
+},
+{
+ .init = omap_sham_init,
+ .update = omap_sham_update,
+ .final = omap_sham_final,
+ .finup = omap_sham_finup,
+ .digest = omap_sham_digest,
+ .halg.digestsize = SHA256_DIGEST_SIZE,
+ .halg.base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "omap-sha256",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_sham_ctx),
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_sham_cra_init,
+ .cra_exit = omap_sham_cra_exit,
+ }
+},
+{
+ .init = omap_sham_init,
+ .update = omap_sham_update,
+ .final = omap_sham_final,
+ .finup = omap_sham_finup,
+ .digest = omap_sham_digest,
+ .setkey = omap_sham_setkey,
+ .halg.digestsize = SHA224_DIGEST_SIZE,
+ .halg.base = {
+ .cra_name = "hmac(sha224)",
+ .cra_driver_name = "omap-hmac-sha224",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA224_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_sham_ctx) +
+ sizeof(struct omap_sham_hmac_ctx),
+ .cra_alignmask = OMAP_ALIGN_MASK,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_sham_cra_sha224_init,
+ .cra_exit = omap_sham_cra_exit,
+ }
+},
+{
+ .init = omap_sham_init,
+ .update = omap_sham_update,
+ .final = omap_sham_final,
+ .finup = omap_sham_finup,
+ .digest = omap_sham_digest,
+ .setkey = omap_sham_setkey,
+ .halg.digestsize = SHA256_DIGEST_SIZE,
+ .halg.base = {
+ .cra_name = "hmac(sha256)",
+ .cra_driver_name = "omap-hmac-sha256",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct omap_sham_ctx) +
+ sizeof(struct omap_sham_hmac_ctx),
+ .cra_alignmask = OMAP_ALIGN_MASK,
+ .cra_module = THIS_MODULE,
+ .cra_init = omap_sham_cra_sha256_init,
+ .cra_exit = omap_sham_cra_exit,
+ }
+},
+};
+
static void omap_sham_done_task(unsigned long data)
{
struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
@@ -1076,7 +1460,19 @@ finish:
omap_sham_finish_req(dd->req, err);
}
-static irqreturn_t omap_sham_irq(int irq, void *dev_id)
+static irqreturn_t omap_sham_irq_common(struct omap_sham_dev *dd)
+{
+ if (!test_bit(FLAGS_BUSY, &dd->flags)) {
+ dev_warn(dd->dev, "Interrupt when no active requests.\n");
+ } else {
+ set_bit(FLAGS_OUTPUT_READY, &dd->flags);
+ tasklet_schedule(&dd->done_task);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_sham_irq_omap2(int irq, void *dev_id)
{
struct omap_sham_dev *dd = dev_id;
@@ -1088,61 +1484,188 @@ static irqreturn_t omap_sham_irq(int irq, void *dev_id)
SHA_REG_CTRL_OUTPUT_READY);
omap_sham_read(dd, SHA_REG_CTRL);
- if (!test_bit(FLAGS_BUSY, &dd->flags)) {
- dev_warn(dd->dev, "Interrupt when no active requests.\n");
- return IRQ_HANDLED;
- }
+ return omap_sham_irq_common(dd);
+}
- set_bit(FLAGS_OUTPUT_READY, &dd->flags);
- tasklet_schedule(&dd->done_task);
+static irqreturn_t omap_sham_irq_omap4(int irq, void *dev_id)
+{
+ struct omap_sham_dev *dd = dev_id;
- return IRQ_HANDLED;
+ omap_sham_write_mask(dd, SHA_REG_MASK(dd), 0, SHA_REG_MASK_IT_EN);
+
+ return omap_sham_irq_common(dd);
}
-static void omap_sham_dma_callback(int lch, u16 ch_status, void *data)
+static struct omap_sham_algs_info omap_sham_algs_info_omap2[] = {
+ {
+ .algs_list = algs_sha1_md5,
+ .size = ARRAY_SIZE(algs_sha1_md5),
+ },
+};
+
+static const struct omap_sham_pdata omap_sham_pdata_omap2 = {
+ .algs_info = omap_sham_algs_info_omap2,
+ .algs_info_size = ARRAY_SIZE(omap_sham_algs_info_omap2),
+ .flags = BIT(FLAGS_BE32_SHA1),
+ .digest_size = SHA1_DIGEST_SIZE,
+ .copy_hash = omap_sham_copy_hash_omap2,
+ .write_ctrl = omap_sham_write_ctrl_omap2,
+ .trigger = omap_sham_trigger_omap2,
+ .poll_irq = omap_sham_poll_irq_omap2,
+ .intr_hdlr = omap_sham_irq_omap2,
+ .idigest_ofs = 0x00,
+ .din_ofs = 0x1c,
+ .digcnt_ofs = 0x14,
+ .rev_ofs = 0x5c,
+ .mask_ofs = 0x60,
+ .sysstatus_ofs = 0x64,
+ .major_mask = 0xf0,
+ .major_shift = 4,
+ .minor_mask = 0x0f,
+ .minor_shift = 0,
+};
+
+#ifdef CONFIG_OF
+static struct omap_sham_algs_info omap_sham_algs_info_omap4[] = {
+ {
+ .algs_list = algs_sha1_md5,
+ .size = ARRAY_SIZE(algs_sha1_md5),
+ },
+ {
+ .algs_list = algs_sha224_sha256,
+ .size = ARRAY_SIZE(algs_sha224_sha256),
+ },
+};
+
+static const struct omap_sham_pdata omap_sham_pdata_omap4 = {
+ .algs_info = omap_sham_algs_info_omap4,
+ .algs_info_size = ARRAY_SIZE(omap_sham_algs_info_omap4),
+ .flags = BIT(FLAGS_AUTO_XOR),
+ .digest_size = SHA256_DIGEST_SIZE,
+ .copy_hash = omap_sham_copy_hash_omap4,
+ .write_ctrl = omap_sham_write_ctrl_omap4,
+ .trigger = omap_sham_trigger_omap4,
+ .poll_irq = omap_sham_poll_irq_omap4,
+ .intr_hdlr = omap_sham_irq_omap4,
+ .idigest_ofs = 0x020,
+ .din_ofs = 0x080,
+ .digcnt_ofs = 0x040,
+ .rev_ofs = 0x100,
+ .mask_ofs = 0x110,
+ .sysstatus_ofs = 0x114,
+ .major_mask = 0x0700,
+ .major_shift = 8,
+ .minor_mask = 0x003f,
+ .minor_shift = 0,
+};
+
+static const struct of_device_id omap_sham_of_match[] = {
+ {
+ .compatible = "ti,omap2-sham",
+ .data = &omap_sham_pdata_omap2,
+ },
+ {
+ .compatible = "ti,omap4-sham",
+ .data = &omap_sham_pdata_omap4,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, omap_sham_of_match);
+
+static int omap_sham_get_res_of(struct omap_sham_dev *dd,
+ struct device *dev, struct resource *res)
{
- struct omap_sham_dev *dd = data;
+ struct device_node *node = dev->of_node;
+ const struct of_device_id *match;
+ int err = 0;
- if (ch_status != OMAP_DMA_BLOCK_IRQ) {
- pr_err("omap-sham DMA error status: 0x%hx\n", ch_status);
- dd->err = -EIO;
- clear_bit(FLAGS_INIT, &dd->flags);/* request to re-initialize */
+ match = of_match_device(of_match_ptr(omap_sham_of_match), dev);
+ if (!match) {
+ dev_err(dev, "no compatible OF match\n");
+ err = -EINVAL;
+ goto err;
}
- set_bit(FLAGS_DMA_READY, &dd->flags);
- tasklet_schedule(&dd->done_task);
+ err = of_address_to_resource(node, 0, res);
+ if (err < 0) {
+ dev_err(dev, "can't translate OF node address\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ dd->irq = of_irq_to_resource(node, 0, NULL);
+ if (!dd->irq) {
+ dev_err(dev, "can't translate OF irq value\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ dd->dma = -1; /* Dummy value that's unused */
+ dd->pdata = match->data;
+
+err:
+ return err;
}
+#else
+static const struct of_device_id omap_sham_of_match[] = {
+ {},
+};
-static int omap_sham_dma_init(struct omap_sham_dev *dd)
+static int omap_sham_get_res_of(struct omap_sham_dev *dd,
+ struct device *dev, struct resource *res)
{
- int err;
+ return -EINVAL;
+}
+#endif
- dd->dma_lch = -1;
+static int omap_sham_get_res_pdev(struct omap_sham_dev *dd,
+ struct platform_device *pdev, struct resource *res)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *r;
+ int err = 0;
- err = omap_request_dma(dd->dma, dev_name(dd->dev),
- omap_sham_dma_callback, dd, &dd->dma_lch);
- if (err) {
- dev_err(dd->dev, "Unable to request DMA channel\n");
- return err;
+ /* Get the base address */
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(dev, "no MEM resource info\n");
+ err = -ENODEV;
+ goto err;
}
+ memcpy(res, r, sizeof(*res));
- return 0;
-}
+ /* Get the IRQ */
+ dd->irq = platform_get_irq(pdev, 0);
+ if (dd->irq < 0) {
+ dev_err(dev, "no IRQ resource info\n");
+ err = dd->irq;
+ goto err;
+ }
-static void omap_sham_dma_cleanup(struct omap_sham_dev *dd)
-{
- if (dd->dma_lch >= 0) {
- omap_free_dma(dd->dma_lch);
- dd->dma_lch = -1;
+ /* Get the DMA */
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!r) {
+ dev_err(dev, "no DMA resource info\n");
+ err = -ENODEV;
+ goto err;
}
+ dd->dma = r->start;
+
+ /* Only OMAP2/3 can be non-DT */
+ dd->pdata = &omap_sham_pdata_omap2;
+
+err:
+ return err;
}
static int omap_sham_probe(struct platform_device *pdev)
{
struct omap_sham_dev *dd;
struct device *dev = &pdev->dev;
- struct resource *res;
+ struct resource res;
+ dma_cap_mask_t mask;
int err, i, j;
+ u32 rev;
dd = kzalloc(sizeof(struct omap_sham_dev), GFP_KERNEL);
if (dd == NULL) {
@@ -1158,89 +1681,75 @@ static int omap_sham_probe(struct platform_device *pdev)
tasklet_init(&dd->done_task, omap_sham_done_task, (unsigned long)dd);
crypto_init_queue(&dd->queue, OMAP_SHAM_QUEUE_LENGTH);
- dd->irq = -1;
-
- /* Get the base address */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "no MEM resource info\n");
- err = -ENODEV;
- goto res_err;
- }
- dd->phys_base = res->start;
-
- /* Get the DMA */
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!res) {
- dev_err(dev, "no DMA resource info\n");
- err = -ENODEV;
+ err = (dev->of_node) ? omap_sham_get_res_of(dd, dev, &res) :
+ omap_sham_get_res_pdev(dd, pdev, &res);
+ if (err)
goto res_err;
- }
- dd->dma = res->start;
- /* Get the IRQ */
- dd->irq = platform_get_irq(pdev, 0);
- if (dd->irq < 0) {
- dev_err(dev, "no IRQ resource info\n");
- err = dd->irq;
+ dd->io_base = devm_request_and_ioremap(dev, &res);
+ if (!dd->io_base) {
+ dev_err(dev, "can't ioremap\n");
+ err = -ENOMEM;
goto res_err;
}
+ dd->phys_base = res.start;
- err = request_irq(dd->irq, omap_sham_irq,
- IRQF_TRIGGER_LOW, dev_name(dev), dd);
+ err = request_irq(dd->irq, dd->pdata->intr_hdlr, IRQF_TRIGGER_LOW,
+ dev_name(dev), dd);
if (err) {
dev_err(dev, "unable to request irq.\n");
goto res_err;
}
- err = omap_sham_dma_init(dd);
- if (err)
- goto dma_err;
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
- /* Initializing the clock */
- dd->iclk = clk_get(dev, "ick");
- if (IS_ERR(dd->iclk)) {
- dev_err(dev, "clock intialization failed.\n");
- err = PTR_ERR(dd->iclk);
- goto clk_err;
+ dd->dma_lch = dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
+ &dd->dma, dev, "rx");
+ if (!dd->dma_lch) {
+ dev_err(dev, "unable to obtain RX DMA engine channel %u\n",
+ dd->dma);
+ err = -ENXIO;
+ goto dma_err;
}
- dd->io_base = ioremap(dd->phys_base, SZ_4K);
- if (!dd->io_base) {
- dev_err(dev, "can't ioremap\n");
- err = -ENOMEM;
- goto io_err;
- }
+ dd->flags |= dd->pdata->flags;
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ rev = omap_sham_read(dd, SHA_REG_REV(dd));
+ pm_runtime_put_sync(&pdev->dev);
- clk_enable(dd->iclk);
dev_info(dev, "hw accel on OMAP rev %u.%u\n",
- (omap_sham_read(dd, SHA_REG_REV) & SHA_REG_REV_MAJOR) >> 4,
- omap_sham_read(dd, SHA_REG_REV) & SHA_REG_REV_MINOR);
- clk_disable(dd->iclk);
+ (rev & dd->pdata->major_mask) >> dd->pdata->major_shift,
+ (rev & dd->pdata->minor_mask) >> dd->pdata->minor_shift);
spin_lock(&sham.lock);
list_add_tail(&dd->list, &sham.dev_list);
spin_unlock(&sham.lock);
- for (i = 0; i < ARRAY_SIZE(algs); i++) {
- err = crypto_register_ahash(&algs[i]);
- if (err)
- goto err_algs;
+ for (i = 0; i < dd->pdata->algs_info_size; i++) {
+ for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
+ err = crypto_register_ahash(
+ &dd->pdata->algs_info[i].algs_list[j]);
+ if (err)
+ goto err_algs;
+
+ dd->pdata->algs_info[i].registered++;
+ }
}
return 0;
err_algs:
- for (j = 0; j < i; j++)
- crypto_unregister_ahash(&algs[j]);
- iounmap(dd->io_base);
-io_err:
- clk_put(dd->iclk);
-clk_err:
- omap_sham_dma_cleanup(dd);
+ for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
+ for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
+ crypto_unregister_ahash(
+ &dd->pdata->algs_info[i].algs_list[j]);
+ pm_runtime_disable(dev);
+ dma_release_channel(dd->dma_lch);
dma_err:
- if (dd->irq >= 0)
- free_irq(dd->irq, dd);
+ free_irq(dd->irq, dd);
res_err:
kfree(dd);
dd = NULL;
@@ -1253,7 +1762,7 @@ data_err:
static int omap_sham_remove(struct platform_device *pdev)
{
static struct omap_sham_dev *dd;
- int i;
+ int i, j;
dd = platform_get_drvdata(pdev);
if (!dd)
@@ -1261,33 +1770,51 @@ static int omap_sham_remove(struct platform_device *pdev)
spin_lock(&sham.lock);
list_del(&dd->list);
spin_unlock(&sham.lock);
- for (i = 0; i < ARRAY_SIZE(algs); i++)
- crypto_unregister_ahash(&algs[i]);
+ for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
+ for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
+ crypto_unregister_ahash(
+ &dd->pdata->algs_info[i].algs_list[j]);
tasklet_kill(&dd->done_task);
- iounmap(dd->io_base);
- clk_put(dd->iclk);
- omap_sham_dma_cleanup(dd);
- if (dd->irq >= 0)
- free_irq(dd->irq, dd);
+ pm_runtime_disable(&pdev->dev);
+ dma_release_channel(dd->dma_lch);
+ free_irq(dd->irq, dd);
kfree(dd);
dd = NULL;
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int omap_sham_suspend(struct device *dev)
+{
+ pm_runtime_put_sync(dev);
+ return 0;
+}
+
+static int omap_sham_resume(struct device *dev)
+{
+ pm_runtime_get_sync(dev);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops omap_sham_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(omap_sham_suspend, omap_sham_resume)
+};
+
static struct platform_driver omap_sham_driver = {
.probe = omap_sham_probe,
.remove = omap_sham_remove,
.driver = {
.name = "omap-sham",
.owner = THIS_MODULE,
+ .pm = &omap_sham_pm_ops,
+ .of_match_table = omap_sham_of_match,
},
};
static int __init omap_sham_mod_init(void)
{
- pr_info("loading %s driver\n", "omap-sham");
-
return platform_driver_register(&omap_sham_driver);
}
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
index 49ad8cbade69..4b314326f48a 100644
--- a/drivers/crypto/s5p-sss.c
+++ b/drivers/crypto/s5p-sss.c
@@ -580,7 +580,7 @@ static int s5p_aes_probe(struct platform_device *pdev)
resource_size(res), pdev->name))
return -EBUSY;
- pdata->clk = clk_get(dev, "secss");
+ pdata->clk = devm_clk_get(dev, "secss");
if (IS_ERR(pdata->clk)) {
dev_err(dev, "failed to find secss clock source\n");
return -ENOENT;
@@ -645,7 +645,6 @@ static int s5p_aes_probe(struct platform_device *pdev)
err_irq:
clk_disable(pdata->clk);
- clk_put(pdata->clk);
s5p_dev = NULL;
platform_set_drvdata(pdev, NULL);
@@ -667,7 +666,6 @@ static int s5p_aes_remove(struct platform_device *pdev)
tasklet_kill(&pdata->tasklet);
clk_disable(pdata->clk);
- clk_put(pdata->clk);
s5p_dev = NULL;
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c
index 46d94e9e95b5..3f37f3b3f268 100644
--- a/drivers/devfreq/exynos4_bus.c
+++ b/drivers/devfreq/exynos4_bus.c
@@ -658,7 +658,7 @@ static int exynos4_bus_target(struct device *dev, unsigned long *_freq,
if (old_freq == freq)
return 0;
- dev_dbg(dev, "targetting %lukHz %luuV\n", freq, new_oppinfo.volt);
+ dev_dbg(dev, "targeting %lukHz %luuV\n", freq, new_oppinfo.volt);
mutex_lock(&data->lock);
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index d4c12180c654..40179e749f08 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -125,6 +125,8 @@ config MPC512X_DMA
---help---
Enable support for the Freescale MPC512x built-in DMA engine.
+source "drivers/dma/bestcomm/Kconfig"
+
config MV_XOR
bool "Marvell XOR engine support"
depends on PLAT_ORION
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 7428feaa8705..642d96736cf5 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioat/
obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
+obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
obj-$(CONFIG_MV_XOR) += mv_xor.o
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/drivers/dma/bestcomm/Kconfig
index 29e427085efb..29e427085efb 100644
--- a/arch/powerpc/sysdev/bestcomm/Kconfig
+++ b/drivers/dma/bestcomm/Kconfig
diff --git a/arch/powerpc/sysdev/bestcomm/Makefile b/drivers/dma/bestcomm/Makefile
index aed2df2a6580..aed2df2a6580 100644
--- a/arch/powerpc/sysdev/bestcomm/Makefile
+++ b/drivers/dma/bestcomm/Makefile
diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/drivers/dma/bestcomm/ata.c
index 901c9f91e5dd..2fd87f83cf90 100644
--- a/arch/powerpc/sysdev/bestcomm/ata.c
+++ b/drivers/dma/bestcomm/ata.c
@@ -18,9 +18,9 @@
#include <linux/types.h>
#include <asm/io.h>
-#include "bestcomm.h"
-#include "bestcomm_priv.h"
-#include "ata.h"
+#include <linux/fsl/bestcomm/bestcomm.h>
+#include <linux/fsl/bestcomm/bestcomm_priv.h>
+#include <linux/fsl/bestcomm/ata.h>
/* ======================================================================== */
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c b/drivers/dma/bestcomm/bcom_ata_task.c
index cc6049a4e469..cc6049a4e469 100644
--- a/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c
+++ b/drivers/dma/bestcomm/bcom_ata_task.c
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c b/drivers/dma/bestcomm/bcom_fec_rx_task.c
index a1ad6a02fcef..a1ad6a02fcef 100644
--- a/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c
+++ b/drivers/dma/bestcomm/bcom_fec_rx_task.c
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c b/drivers/dma/bestcomm/bcom_fec_tx_task.c
index b1c495c3a65a..b1c495c3a65a 100644
--- a/arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c
+++ b/drivers/dma/bestcomm/bcom_fec_tx_task.c
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c b/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c
index efee022b0256..efee022b0256 100644
--- a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
+++ b/drivers/dma/bestcomm/bcom_gen_bd_rx_task.c
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c b/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c
index c605aa42ecbb..c605aa42ecbb 100644
--- a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c
+++ b/drivers/dma/bestcomm/bcom_gen_bd_tx_task.c
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/drivers/dma/bestcomm/bestcomm.c
index d9130630f7ef..a8c2e2994d2e 100644
--- a/arch/powerpc/sysdev/bestcomm/bestcomm.c
+++ b/drivers/dma/bestcomm/bestcomm.c
@@ -23,9 +23,9 @@
#include <asm/irq.h>
#include <asm/mpc52xx.h>
-#include "sram.h"
-#include "bestcomm_priv.h"
-#include "bestcomm.h"
+#include <linux/fsl/bestcomm/sram.h>
+#include <linux/fsl/bestcomm/bestcomm_priv.h>
+#include "linux/fsl/bestcomm/bestcomm.h"
#define DRIVER_NAME "bestcomm-core"
@@ -414,7 +414,7 @@ static int mpc52xx_bcom_probe(struct platform_device *op)
goto error_sramclean;
}
- if (!request_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma),
+ if (!request_mem_region(res_bcom.start, resource_size(&res_bcom),
DRIVER_NAME)) {
printk(KERN_ERR DRIVER_NAME ": "
"Can't request registers region\n");
diff --git a/arch/powerpc/sysdev/bestcomm/fec.c b/drivers/dma/bestcomm/fec.c
index 957a988d23ea..7f1fb1c999e4 100644
--- a/arch/powerpc/sysdev/bestcomm/fec.c
+++ b/drivers/dma/bestcomm/fec.c
@@ -16,9 +16,9 @@
#include <linux/types.h>
#include <asm/io.h>
-#include "bestcomm.h"
-#include "bestcomm_priv.h"
-#include "fec.h"
+#include <linux/fsl/bestcomm/bestcomm.h>
+#include <linux/fsl/bestcomm/bestcomm_priv.h>
+#include <linux/fsl/bestcomm/fec.h>
/* ======================================================================== */
diff --git a/arch/powerpc/sysdev/bestcomm/gen_bd.c b/drivers/dma/bestcomm/gen_bd.c
index e0a53e3147b2..1a5b22d88127 100644
--- a/arch/powerpc/sysdev/bestcomm/gen_bd.c
+++ b/drivers/dma/bestcomm/gen_bd.c
@@ -21,9 +21,9 @@
#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
-#include "bestcomm.h"
-#include "bestcomm_priv.h"
-#include "gen_bd.h"
+#include <linux/fsl/bestcomm/bestcomm.h>
+#include <linux/fsl/bestcomm/bestcomm_priv.h>
+#include <linux/fsl/bestcomm/gen_bd.h>
/* ======================================================================== */
diff --git a/arch/powerpc/sysdev/bestcomm/sram.c b/drivers/dma/bestcomm/sram.c
index b6db23e085fb..5e2ed30ba2c4 100644
--- a/arch/powerpc/sysdev/bestcomm/sram.c
+++ b/drivers/dma/bestcomm/sram.c
@@ -23,7 +23,7 @@
#include <asm/io.h>
#include <asm/mmu.h>
-#include "sram.h"
+#include <linux/fsl/bestcomm/sram.h>
/* Struct keeping our 'state' */
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index aa384e53b7ac..a2f079aca550 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -21,11 +21,1241 @@
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
-#include <mach/coh901318.h>
+#include <linux/platform_data/dma-coh901318.h>
-#include "coh901318_lli.h"
+#include "coh901318.h"
#include "dmaengine.h"
+#define COH901318_MOD32_MASK (0x1F)
+#define COH901318_WORD_MASK (0xFFFFFFFF)
+/* INT_STATUS - Interrupt Status Registers 32bit (R/-) */
+#define COH901318_INT_STATUS1 (0x0000)
+#define COH901318_INT_STATUS2 (0x0004)
+/* TC_INT_STATUS - Terminal Count Interrupt Status Registers 32bit (R/-) */
+#define COH901318_TC_INT_STATUS1 (0x0008)
+#define COH901318_TC_INT_STATUS2 (0x000C)
+/* TC_INT_CLEAR - Terminal Count Interrupt Clear Registers 32bit (-/W) */
+#define COH901318_TC_INT_CLEAR1 (0x0010)
+#define COH901318_TC_INT_CLEAR2 (0x0014)
+/* RAW_TC_INT_STATUS - Raw Term Count Interrupt Status Registers 32bit (R/-) */
+#define COH901318_RAW_TC_INT_STATUS1 (0x0018)
+#define COH901318_RAW_TC_INT_STATUS2 (0x001C)
+/* BE_INT_STATUS - Bus Error Interrupt Status Registers 32bit (R/-) */
+#define COH901318_BE_INT_STATUS1 (0x0020)
+#define COH901318_BE_INT_STATUS2 (0x0024)
+/* BE_INT_CLEAR - Bus Error Interrupt Clear Registers 32bit (-/W) */
+#define COH901318_BE_INT_CLEAR1 (0x0028)
+#define COH901318_BE_INT_CLEAR2 (0x002C)
+/* RAW_BE_INT_STATUS - Raw Term Count Interrupt Status Registers 32bit (R/-) */
+#define COH901318_RAW_BE_INT_STATUS1 (0x0030)
+#define COH901318_RAW_BE_INT_STATUS2 (0x0034)
+
+/*
+ * CX_CFG - Channel Configuration Registers 32bit (R/W)
+ */
+#define COH901318_CX_CFG (0x0100)
+#define COH901318_CX_CFG_SPACING (0x04)
+/* Channel enable activates tha dma job */
+#define COH901318_CX_CFG_CH_ENABLE (0x00000001)
+#define COH901318_CX_CFG_CH_DISABLE (0x00000000)
+/* Request Mode */
+#define COH901318_CX_CFG_RM_MASK (0x00000006)
+#define COH901318_CX_CFG_RM_MEMORY_TO_MEMORY (0x0 << 1)
+#define COH901318_CX_CFG_RM_PRIMARY_TO_MEMORY (0x1 << 1)
+#define COH901318_CX_CFG_RM_MEMORY_TO_PRIMARY (0x1 << 1)
+#define COH901318_CX_CFG_RM_PRIMARY_TO_SECONDARY (0x3 << 1)
+#define COH901318_CX_CFG_RM_SECONDARY_TO_PRIMARY (0x3 << 1)
+/* Linked channel request field. RM must == 11 */
+#define COH901318_CX_CFG_LCRF_SHIFT 3
+#define COH901318_CX_CFG_LCRF_MASK (0x000001F8)
+#define COH901318_CX_CFG_LCR_DISABLE (0x00000000)
+/* Terminal Counter Interrupt Request Mask */
+#define COH901318_CX_CFG_TC_IRQ_ENABLE (0x00000200)
+#define COH901318_CX_CFG_TC_IRQ_DISABLE (0x00000000)
+/* Bus Error interrupt Mask */
+#define COH901318_CX_CFG_BE_IRQ_ENABLE (0x00000400)
+#define COH901318_CX_CFG_BE_IRQ_DISABLE (0x00000000)
+
+/*
+ * CX_STAT - Channel Status Registers 32bit (R/-)
+ */
+#define COH901318_CX_STAT (0x0200)
+#define COH901318_CX_STAT_SPACING (0x04)
+#define COH901318_CX_STAT_RBE_IRQ_IND (0x00000008)
+#define COH901318_CX_STAT_RTC_IRQ_IND (0x00000004)
+#define COH901318_CX_STAT_ACTIVE (0x00000002)
+#define COH901318_CX_STAT_ENABLED (0x00000001)
+
+/*
+ * CX_CTRL - Channel Control Registers 32bit (R/W)
+ */
+#define COH901318_CX_CTRL (0x0400)
+#define COH901318_CX_CTRL_SPACING (0x10)
+/* Transfer Count Enable */
+#define COH901318_CX_CTRL_TC_ENABLE (0x00001000)
+#define COH901318_CX_CTRL_TC_DISABLE (0x00000000)
+/* Transfer Count Value 0 - 4095 */
+#define COH901318_CX_CTRL_TC_VALUE_MASK (0x00000FFF)
+/* Burst count */
+#define COH901318_CX_CTRL_BURST_COUNT_MASK (0x0000E000)
+#define COH901318_CX_CTRL_BURST_COUNT_64_BYTES (0x7 << 13)
+#define COH901318_CX_CTRL_BURST_COUNT_48_BYTES (0x6 << 13)
+#define COH901318_CX_CTRL_BURST_COUNT_32_BYTES (0x5 << 13)
+#define COH901318_CX_CTRL_BURST_COUNT_16_BYTES (0x4 << 13)
+#define COH901318_CX_CTRL_BURST_COUNT_8_BYTES (0x3 << 13)
+#define COH901318_CX_CTRL_BURST_COUNT_4_BYTES (0x2 << 13)
+#define COH901318_CX_CTRL_BURST_COUNT_2_BYTES (0x1 << 13)
+#define COH901318_CX_CTRL_BURST_COUNT_1_BYTE (0x0 << 13)
+/* Source bus size */
+#define COH901318_CX_CTRL_SRC_BUS_SIZE_MASK (0x00030000)
+#define COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS (0x2 << 16)
+#define COH901318_CX_CTRL_SRC_BUS_SIZE_16_BITS (0x1 << 16)
+#define COH901318_CX_CTRL_SRC_BUS_SIZE_8_BITS (0x0 << 16)
+/* Source address increment */
+#define COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE (0x00040000)
+#define COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE (0x00000000)
+/* Destination Bus Size */
+#define COH901318_CX_CTRL_DST_BUS_SIZE_MASK (0x00180000)
+#define COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS (0x2 << 19)
+#define COH901318_CX_CTRL_DST_BUS_SIZE_16_BITS (0x1 << 19)
+#define COH901318_CX_CTRL_DST_BUS_SIZE_8_BITS (0x0 << 19)
+/* Destination address increment */
+#define COH901318_CX_CTRL_DST_ADDR_INC_ENABLE (0x00200000)
+#define COH901318_CX_CTRL_DST_ADDR_INC_DISABLE (0x00000000)
+/* Master Mode (Master2 is only connected to MSL) */
+#define COH901318_CX_CTRL_MASTER_MODE_MASK (0x00C00000)
+#define COH901318_CX_CTRL_MASTER_MODE_M2R_M1W (0x3 << 22)
+#define COH901318_CX_CTRL_MASTER_MODE_M1R_M2W (0x2 << 22)
+#define COH901318_CX_CTRL_MASTER_MODE_M2RW (0x1 << 22)
+#define COH901318_CX_CTRL_MASTER_MODE_M1RW (0x0 << 22)
+/* Terminal Count flag to PER enable */
+#define COH901318_CX_CTRL_TCP_ENABLE (0x01000000)
+#define COH901318_CX_CTRL_TCP_DISABLE (0x00000000)
+/* Terminal Count flags to CPU enable */
+#define COH901318_CX_CTRL_TC_IRQ_ENABLE (0x02000000)
+#define COH901318_CX_CTRL_TC_IRQ_DISABLE (0x00000000)
+/* Hand shake to peripheral */
+#define COH901318_CX_CTRL_HSP_ENABLE (0x04000000)
+#define COH901318_CX_CTRL_HSP_DISABLE (0x00000000)
+#define COH901318_CX_CTRL_HSS_ENABLE (0x08000000)
+#define COH901318_CX_CTRL_HSS_DISABLE (0x00000000)
+/* DMA mode */
+#define COH901318_CX_CTRL_DDMA_MASK (0x30000000)
+#define COH901318_CX_CTRL_DDMA_LEGACY (0x0 << 28)
+#define COH901318_CX_CTRL_DDMA_DEMAND_DMA1 (0x1 << 28)
+#define COH901318_CX_CTRL_DDMA_DEMAND_DMA2 (0x2 << 28)
+/* Primary Request Data Destination */
+#define COH901318_CX_CTRL_PRDD_MASK (0x40000000)
+#define COH901318_CX_CTRL_PRDD_DEST (0x1 << 30)
+#define COH901318_CX_CTRL_PRDD_SOURCE (0x0 << 30)
+
+/*
+ * CX_SRC_ADDR - Channel Source Address Registers 32bit (R/W)
+ */
+#define COH901318_CX_SRC_ADDR (0x0404)
+#define COH901318_CX_SRC_ADDR_SPACING (0x10)
+
+/*
+ * CX_DST_ADDR - Channel Destination Address Registers 32bit R/W
+ */
+#define COH901318_CX_DST_ADDR (0x0408)
+#define COH901318_CX_DST_ADDR_SPACING (0x10)
+
+/*
+ * CX_LNK_ADDR - Channel Link Address Registers 32bit (R/W)
+ */
+#define COH901318_CX_LNK_ADDR (0x040C)
+#define COH901318_CX_LNK_ADDR_SPACING (0x10)
+#define COH901318_CX_LNK_LINK_IMMEDIATE (0x00000001)
+
+/**
+ * struct coh901318_params - parameters for DMAC configuration
+ * @config: DMA config register
+ * @ctrl_lli_last: DMA control register for the last lli in the list
+ * @ctrl_lli: DMA control register for an lli
+ * @ctrl_lli_chained: DMA control register for a chained lli
+ */
+struct coh901318_params {
+ u32 config;
+ u32 ctrl_lli_last;
+ u32 ctrl_lli;
+ u32 ctrl_lli_chained;
+};
+
+/**
+ * struct coh_dma_channel - dma channel base
+ * @name: ascii name of dma channel
+ * @number: channel id number
+ * @desc_nbr_max: number of preallocated descriptors
+ * @priority_high: prio of channel, 0 low otherwise high.
+ * @param: configuration parameters
+ */
+struct coh_dma_channel {
+ const char name[32];
+ const int number;
+ const int desc_nbr_max;
+ const int priority_high;
+ const struct coh901318_params param;
+};
+
+/**
+ * struct powersave - DMA power save structure
+ * @lock: lock protecting data in this struct
+ * @started_channels: bit mask indicating active dma channels
+ */
+struct powersave {
+ spinlock_t lock;
+ u64 started_channels;
+};
+
+/* points out all dma slave channels.
+ * Syntax is [A1, B1, A2, B2, .... ,-1,-1]
+ * Select all channels from A to B, end of list is marked with -1,-1
+ */
+static int dma_slave_channels[] = {
+ U300_DMA_MSL_TX_0, U300_DMA_SPI_RX,
+ U300_DMA_UART1_TX, U300_DMA_UART1_RX, -1, -1};
+
+/* points out all dma memcpy channels. */
+static int dma_memcpy_channels[] = {
+ U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_8, -1, -1};
+
+#define flags_memcpy_config (COH901318_CX_CFG_CH_DISABLE | \
+ COH901318_CX_CFG_RM_MEMORY_TO_MEMORY | \
+ COH901318_CX_CFG_LCR_DISABLE | \
+ COH901318_CX_CFG_TC_IRQ_ENABLE | \
+ COH901318_CX_CFG_BE_IRQ_ENABLE)
+#define flags_memcpy_lli_chained (COH901318_CX_CTRL_TC_ENABLE | \
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \
+ COH901318_CX_CTRL_MASTER_MODE_M1RW | \
+ COH901318_CX_CTRL_TCP_DISABLE | \
+ COH901318_CX_CTRL_TC_IRQ_DISABLE | \
+ COH901318_CX_CTRL_HSP_DISABLE | \
+ COH901318_CX_CTRL_HSS_DISABLE | \
+ COH901318_CX_CTRL_DDMA_LEGACY | \
+ COH901318_CX_CTRL_PRDD_SOURCE)
+#define flags_memcpy_lli (COH901318_CX_CTRL_TC_ENABLE | \
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \
+ COH901318_CX_CTRL_MASTER_MODE_M1RW | \
+ COH901318_CX_CTRL_TCP_DISABLE | \
+ COH901318_CX_CTRL_TC_IRQ_DISABLE | \
+ COH901318_CX_CTRL_HSP_DISABLE | \
+ COH901318_CX_CTRL_HSS_DISABLE | \
+ COH901318_CX_CTRL_DDMA_LEGACY | \
+ COH901318_CX_CTRL_PRDD_SOURCE)
+#define flags_memcpy_lli_last (COH901318_CX_CTRL_TC_ENABLE | \
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES | \
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS | \
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE | \
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS | \
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE | \
+ COH901318_CX_CTRL_MASTER_MODE_M1RW | \
+ COH901318_CX_CTRL_TCP_DISABLE | \
+ COH901318_CX_CTRL_TC_IRQ_ENABLE | \
+ COH901318_CX_CTRL_HSP_DISABLE | \
+ COH901318_CX_CTRL_HSS_DISABLE | \
+ COH901318_CX_CTRL_DDMA_LEGACY | \
+ COH901318_CX_CTRL_PRDD_SOURCE)
+
+const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
+ {
+ .number = U300_DMA_MSL_TX_0,
+ .name = "MSL TX 0",
+ .priority_high = 0,
+ },
+ {
+ .number = U300_DMA_MSL_TX_1,
+ .name = "MSL TX 1",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ },
+ {
+ .number = U300_DMA_MSL_TX_2,
+ .name = "MSL TX 2",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .desc_nbr_max = 10,
+ },
+ {
+ .number = U300_DMA_MSL_TX_3,
+ .name = "MSL TX 3",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ },
+ {
+ .number = U300_DMA_MSL_TX_4,
+ .name = "MSL TX 4",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1R_M2W |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ },
+ {
+ .number = U300_DMA_MSL_TX_5,
+ .name = "MSL TX 5",
+ .priority_high = 0,
+ },
+ {
+ .number = U300_DMA_MSL_TX_6,
+ .name = "MSL TX 6",
+ .priority_high = 0,
+ },
+ {
+ .number = U300_DMA_MSL_RX_0,
+ .name = "MSL RX 0",
+ .priority_high = 0,
+ },
+ {
+ .number = U300_DMA_MSL_RX_1,
+ .name = "MSL RX 1",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli = 0,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ },
+ {
+ .number = U300_DMA_MSL_RX_2,
+ .name = "MSL RX 2",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ },
+ {
+ .number = U300_DMA_MSL_RX_3,
+ .name = "MSL RX 3",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ },
+ {
+ .number = U300_DMA_MSL_RX_4,
+ .name = "MSL RX 4",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ },
+ {
+ .number = U300_DMA_MSL_RX_5,
+ .name = "MSL RX 5",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M2R_M1W |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_DEMAND_DMA1 |
+ COH901318_CX_CTRL_PRDD_DEST,
+ },
+ {
+ .number = U300_DMA_MSL_RX_6,
+ .name = "MSL RX 6",
+ .priority_high = 0,
+ },
+ /*
+ * Don't set up device address, burst count or size of src
+ * or dst bus for this peripheral - handled by PrimeCell
+ * DMA extension.
+ */
+ {
+ .number = U300_DMA_MMCSD_RX_TX,
+ .name = "MMCSD RX TX",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+
+ },
+ {
+ .number = U300_DMA_MSPRO_TX,
+ .name = "MSPRO TX",
+ .priority_high = 0,
+ },
+ {
+ .number = U300_DMA_MSPRO_RX,
+ .name = "MSPRO RX",
+ .priority_high = 0,
+ },
+ /*
+ * Don't set up device address, burst count or size of src
+ * or dst bus for this peripheral - handled by PrimeCell
+ * DMA extension.
+ */
+ {
+ .number = U300_DMA_UART0_TX,
+ .name = "UART0 TX",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ },
+ {
+ .number = U300_DMA_UART0_RX,
+ .name = "UART0 RX",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ },
+ {
+ .number = U300_DMA_APEX_TX,
+ .name = "APEX TX",
+ .priority_high = 0,
+ },
+ {
+ .number = U300_DMA_APEX_RX,
+ .name = "APEX RX",
+ .priority_high = 0,
+ },
+ {
+ .number = U300_DMA_PCM_I2S0_TX,
+ .name = "PCM I2S0 TX",
+ .priority_high = 1,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ },
+ {
+ .number = U300_DMA_PCM_I2S0_RX,
+ .name = "PCM I2S0 RX",
+ .priority_high = 1,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_DEST,
+ },
+ {
+ .number = U300_DMA_PCM_I2S1_TX,
+ .name = "PCM I2S1 TX",
+ .priority_high = 1,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_SOURCE,
+ },
+ {
+ .number = U300_DMA_PCM_I2S1_RX,
+ .name = "PCM I2S1 RX",
+ .priority_high = 1,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_DEST,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_BURST_COUNT_16_BYTES |
+ COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_SRC_ADDR_INC_DISABLE |
+ COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
+ COH901318_CX_CTRL_DST_ADDR_INC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY |
+ COH901318_CX_CTRL_PRDD_DEST,
+ },
+ {
+ .number = U300_DMA_XGAM_CDI,
+ .name = "XGAM CDI",
+ .priority_high = 0,
+ },
+ {
+ .number = U300_DMA_XGAM_PDI,
+ .name = "XGAM PDI",
+ .priority_high = 0,
+ },
+ /*
+ * Don't set up device address, burst count or size of src
+ * or dst bus for this peripheral - handled by PrimeCell
+ * DMA extension.
+ */
+ {
+ .number = U300_DMA_SPI_TX,
+ .name = "SPI TX",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ },
+ {
+ .number = U300_DMA_SPI_RX,
+ .name = "SPI RX",
+ .priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+
+ },
+ {
+ .number = U300_DMA_GENERAL_PURPOSE_0,
+ .name = "GENERAL 00",
+ .priority_high = 0,
+
+ .param.config = flags_memcpy_config,
+ .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+ .param.ctrl_lli = flags_memcpy_lli,
+ .param.ctrl_lli_last = flags_memcpy_lli_last,
+ },
+ {
+ .number = U300_DMA_GENERAL_PURPOSE_1,
+ .name = "GENERAL 01",
+ .priority_high = 0,
+
+ .param.config = flags_memcpy_config,
+ .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+ .param.ctrl_lli = flags_memcpy_lli,
+ .param.ctrl_lli_last = flags_memcpy_lli_last,
+ },
+ {
+ .number = U300_DMA_GENERAL_PURPOSE_2,
+ .name = "GENERAL 02",
+ .priority_high = 0,
+
+ .param.config = flags_memcpy_config,
+ .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+ .param.ctrl_lli = flags_memcpy_lli,
+ .param.ctrl_lli_last = flags_memcpy_lli_last,
+ },
+ {
+ .number = U300_DMA_GENERAL_PURPOSE_3,
+ .name = "GENERAL 03",
+ .priority_high = 0,
+
+ .param.config = flags_memcpy_config,
+ .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+ .param.ctrl_lli = flags_memcpy_lli,
+ .param.ctrl_lli_last = flags_memcpy_lli_last,
+ },
+ {
+ .number = U300_DMA_GENERAL_PURPOSE_4,
+ .name = "GENERAL 04",
+ .priority_high = 0,
+
+ .param.config = flags_memcpy_config,
+ .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+ .param.ctrl_lli = flags_memcpy_lli,
+ .param.ctrl_lli_last = flags_memcpy_lli_last,
+ },
+ {
+ .number = U300_DMA_GENERAL_PURPOSE_5,
+ .name = "GENERAL 05",
+ .priority_high = 0,
+
+ .param.config = flags_memcpy_config,
+ .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+ .param.ctrl_lli = flags_memcpy_lli,
+ .param.ctrl_lli_last = flags_memcpy_lli_last,
+ },
+ {
+ .number = U300_DMA_GENERAL_PURPOSE_6,
+ .name = "GENERAL 06",
+ .priority_high = 0,
+
+ .param.config = flags_memcpy_config,
+ .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+ .param.ctrl_lli = flags_memcpy_lli,
+ .param.ctrl_lli_last = flags_memcpy_lli_last,
+ },
+ {
+ .number = U300_DMA_GENERAL_PURPOSE_7,
+ .name = "GENERAL 07",
+ .priority_high = 0,
+
+ .param.config = flags_memcpy_config,
+ .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+ .param.ctrl_lli = flags_memcpy_lli,
+ .param.ctrl_lli_last = flags_memcpy_lli_last,
+ },
+ {
+ .number = U300_DMA_GENERAL_PURPOSE_8,
+ .name = "GENERAL 08",
+ .priority_high = 0,
+
+ .param.config = flags_memcpy_config,
+ .param.ctrl_lli_chained = flags_memcpy_lli_chained,
+ .param.ctrl_lli = flags_memcpy_lli,
+ .param.ctrl_lli_last = flags_memcpy_lli_last,
+ },
+ {
+ .number = U300_DMA_UART1_TX,
+ .name = "UART1 TX",
+ .priority_high = 0,
+ },
+ {
+ .number = U300_DMA_UART1_RX,
+ .name = "UART1 RX",
+ .priority_high = 0,
+ }
+};
+
#define COHC_2_DEV(cohc) (&cohc->chan.dev->device)
#ifdef VERBOSE_DEBUG
@@ -54,7 +1284,6 @@ struct coh901318_base {
struct dma_device dma_slave;
struct dma_device dma_memcpy;
struct coh901318_chan *chans;
- struct coh901318_platform *platform;
};
struct coh901318_chan {
@@ -75,8 +1304,8 @@ struct coh901318_chan {
unsigned long nbr_active_done;
unsigned long busy;
- u32 runtime_addr;
- u32 runtime_ctrl;
+ u32 addr;
+ u32 ctrl;
struct coh901318_base *base;
};
@@ -122,7 +1351,7 @@ static int coh901318_debugfs_read(struct file *file, char __user *buf,
tmp += sprintf(tmp, "DMA -- enabled dma channels\n");
- for (i = 0; i < debugfs_dma_base->platform->max_channels; i++)
+ for (i = 0; i < U300_DMA_CHANNELS; i++)
if (started_channels & (1 << i))
tmp += sprintf(tmp, "channel %d\n", i);
@@ -187,25 +1416,16 @@ static inline struct coh901318_chan *to_coh901318_chan(struct dma_chan *chan)
return container_of(chan, struct coh901318_chan, chan);
}
-static inline dma_addr_t
-cohc_dev_addr(struct coh901318_chan *cohc)
-{
- /* Runtime supplied address will take precedence */
- if (cohc->runtime_addr)
- return cohc->runtime_addr;
- return cohc->base->platform->chan_conf[cohc->id].dev_addr;
-}
-
static inline const struct coh901318_params *
cohc_chan_param(struct coh901318_chan *cohc)
{
- return &cohc->base->platform->chan_conf[cohc->id].param;
+ return &chan_config[cohc->id].param;
}
static inline const struct coh_dma_channel *
cohc_chan_conf(struct coh901318_chan *cohc)
{
- return &cohc->base->platform->chan_conf[cohc->id];
+ return &chan_config[cohc->id];
}
static void enable_powersave(struct coh901318_chan *cohc)
@@ -217,12 +1437,6 @@ static void enable_powersave(struct coh901318_chan *cohc)
pm->started_channels &= ~(1ULL << cohc->id);
- if (!pm->started_channels) {
- /* DMA no longer intends to access memory */
- cohc->base->platform->access_memory_state(cohc->base->dev,
- false);
- }
-
spin_unlock_irqrestore(&pm->lock, flags);
}
static void disable_powersave(struct coh901318_chan *cohc)
@@ -232,12 +1446,6 @@ static void disable_powersave(struct coh901318_chan *cohc)
spin_lock_irqsave(&pm->lock, flags);
- if (!pm->started_channels) {
- /* DMA intends to access memory */
- cohc->base->platform->access_memory_state(cohc->base->dev,
- true);
- }
-
pm->started_channels |= (1ULL << cohc->id);
spin_unlock_irqrestore(&pm->lock, flags);
@@ -596,7 +1804,7 @@ static int coh901318_config(struct coh901318_chan *cohc,
if (param)
p = param;
else
- p = &cohc->base->platform->chan_conf[channel].param;
+ p = cohc_chan_param(cohc);
/* Clear any pending BE or TC interrupt */
if (channel < 32) {
@@ -1052,9 +2260,9 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
* sure the bits you set per peripheral channel are
* cleared in the default config from the platform.
*/
- ctrl_chained |= cohc->runtime_ctrl;
- ctrl_last |= cohc->runtime_ctrl;
- ctrl |= cohc->runtime_ctrl;
+ ctrl_chained |= cohc->ctrl;
+ ctrl_last |= cohc->ctrl;
+ ctrl |= cohc->ctrl;
if (direction == DMA_MEM_TO_DEV) {
u32 tx_flags = COH901318_CX_CTRL_PRDD_SOURCE |
@@ -1103,7 +2311,7 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
/* initiate allocated lli list */
ret = coh901318_lli_fill_sg(&cohc->base->pool, lli, sgl, sg_len,
- cohc_dev_addr(cohc),
+ cohc->addr,
ctrl_chained,
ctrl,
ctrl_last,
@@ -1244,7 +2452,7 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
dma_addr_t addr;
enum dma_slave_buswidth addr_width;
u32 maxburst;
- u32 runtime_ctrl = 0;
+ u32 ctrl = 0;
int i = 0;
/* We only support mem to per or per to mem transfers */
@@ -1265,7 +2473,7 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
addr_width);
switch (addr_width) {
case DMA_SLAVE_BUSWIDTH_1_BYTE:
- runtime_ctrl |=
+ ctrl |=
COH901318_CX_CTRL_SRC_BUS_SIZE_8_BITS |
COH901318_CX_CTRL_DST_BUS_SIZE_8_BITS;
@@ -1277,7 +2485,7 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
break;
case DMA_SLAVE_BUSWIDTH_2_BYTES:
- runtime_ctrl |=
+ ctrl |=
COH901318_CX_CTRL_SRC_BUS_SIZE_16_BITS |
COH901318_CX_CTRL_DST_BUS_SIZE_16_BITS;
@@ -1290,7 +2498,7 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
break;
case DMA_SLAVE_BUSWIDTH_4_BYTES:
/* Direction doesn't matter here, it's 32/32 bits */
- runtime_ctrl |=
+ ctrl |=
COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS;
@@ -1307,13 +2515,13 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
return;
}
- runtime_ctrl |= burst_sizes[i].reg;
+ ctrl |= burst_sizes[i].reg;
dev_dbg(COHC_2_DEV(cohc),
"selected burst size %d bytes for address width %d bytes, maxburst %d\n",
burst_sizes[i].burst_8bit, addr_width, maxburst);
- cohc->runtime_addr = addr;
- cohc->runtime_ctrl = runtime_ctrl;
+ cohc->addr = addr;
+ cohc->ctrl = ctrl;
}
static int
@@ -1431,7 +2639,6 @@ void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
static int __init coh901318_probe(struct platform_device *pdev)
{
int err = 0;
- struct coh901318_platform *pdata;
struct coh901318_base *base;
int irq;
struct resource *io;
@@ -1447,13 +2654,9 @@ static int __init coh901318_probe(struct platform_device *pdev)
pdev->dev.driver->name) == NULL)
return -ENOMEM;
- pdata = pdev->dev.platform_data;
- if (!pdata)
- return -ENODEV;
-
base = devm_kzalloc(&pdev->dev,
ALIGN(sizeof(struct coh901318_base), 4) +
- pdata->max_channels *
+ U300_DMA_CHANNELS *
sizeof(struct coh901318_chan),
GFP_KERNEL);
if (!base)
@@ -1466,7 +2669,6 @@ static int __init coh901318_probe(struct platform_device *pdev)
return -ENOMEM;
base->dev = &pdev->dev;
- base->platform = pdata;
spin_lock_init(&base->pm.lock);
base->pm.started_channels = 0;
@@ -1488,7 +2690,7 @@ static int __init coh901318_probe(struct platform_device *pdev)
return err;
/* init channels for device transfers */
- coh901318_base_init(&base->dma_slave, base->platform->chans_slave,
+ coh901318_base_init(&base->dma_slave, dma_slave_channels,
base);
dma_cap_zero(base->dma_slave.cap_mask);
@@ -1508,7 +2710,7 @@ static int __init coh901318_probe(struct platform_device *pdev)
goto err_register_slave;
/* init channels for memcpy */
- coh901318_base_init(&base->dma_memcpy, base->platform->chans_memcpy,
+ coh901318_base_init(&base->dma_memcpy, dma_memcpy_channels,
base);
dma_cap_zero(base->dma_memcpy.cap_mask);
diff --git a/drivers/dma/coh901318_lli.h b/drivers/dma/coh901318.h
index abff3714fdda..95ce1e2123ec 100644
--- a/drivers/dma/coh901318_lli.h
+++ b/drivers/dma/coh901318.h
@@ -1,16 +1,15 @@
/*
- * driver/dma/coh901318_lli.h
- *
- * Copyright (C) 2007-2009 ST-Ericsson
+ * Copyright (C) 2007-2013 ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
- * Support functions for handling lli for coh901318
+ * DMA driver for COH 901 318
* Author: Per Friden <per.friden@stericsson.com>
*/
-#ifndef COH901318_LLI_H
-#define COH901318_LLI_H
+#ifndef COH901318_H
+#define COH901318_H
-#include <mach/coh901318.h>
+#define MAX_DMA_PACKET_SIZE_SHIFT 11
+#define MAX_DMA_PACKET_SIZE (1 << MAX_DMA_PACKET_SIZE_SHIFT)
struct device;
@@ -24,7 +23,25 @@ struct coh901318_pool {
#endif
};
-struct device;
+/**
+ * struct coh901318_lli - linked list item for DMAC
+ * @control: control settings for DMAC
+ * @src_addr: transfer source address
+ * @dst_addr: transfer destination address
+ * @link_addr: physical address to next lli
+ * @virt_link_addr: virtual address of next lli (only used by pool_free)
+ * @phy_this: physical address of current lli (only used by pool_free)
+ */
+struct coh901318_lli {
+ u32 control;
+ dma_addr_t src_addr;
+ dma_addr_t dst_addr;
+ dma_addr_t link_addr;
+
+ void *virt_link_addr;
+ dma_addr_t phy_this;
+};
+
/**
* coh901318_pool_create() - Creates an dma pool for lli:s
* @pool: pool handle
@@ -121,4 +138,4 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool,
u32 ctrl, u32 ctrl_last,
enum dma_transfer_direction dir, u32 ctrl_irq_mask);
-#endif /* COH901318_LLI_H */
+#endif /* COH901318_H */
diff --git a/drivers/dma/coh901318_lli.c b/drivers/dma/coh901318_lli.c
index 780e0429b38c..3e96610e18e2 100644
--- a/drivers/dma/coh901318_lli.c
+++ b/drivers/dma/coh901318_lli.c
@@ -11,9 +11,9 @@
#include <linux/memory.h>
#include <linux/gfp.h>
#include <linux/dmapool.h>
-#include <mach/coh901318.h>
+#include <linux/dmaengine.h>
-#include "coh901318_lli.h"
+#include "coh901318.h"
#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
#define DEBUGFS_POOL_COUNTER_RESET(pool) (pool->debugfs_pool_counter = 0)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 3e8ba02ba292..b33d1f6e1333 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -14,6 +14,7 @@
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -1489,9 +1490,9 @@ static int dw_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- regs = devm_request_and_ioremap(&pdev->dev, io);
- if (!regs)
- return -EBUSY;
+ regs = devm_ioremap_resource(&pdev->dev, io);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
dw_params = dma_read_byaddr(regs, DW_PARAMS);
autocfg = dw_params >> DW_PARAMS_EN & 0x1;
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index a7dcf78b1ff8..70b8975d107e 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -14,6 +14,7 @@
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/mm.h>
@@ -1010,9 +1011,9 @@ static int __init imxdma_probe(struct platform_device *pdev)
imxdma->devtype = pdev->id_entry->driver_data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- imxdma->base = devm_request_and_ioremap(&pdev->dev, res);
- if (!imxdma->base)
- return -EADDRNOTAVAIL;
+ imxdma->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(imxdma->base))
+ return PTR_ERR(imxdma->base);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index c6d98c00f05c..dc7466563507 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -5,6 +5,7 @@
* 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/init.h>
#include <linux/types.h>
@@ -782,9 +783,9 @@ static int mmp_pdma_probe(struct platform_device *op)
if (!iores)
return -EINVAL;
- pdev->base = devm_request_and_ioremap(pdev->dev, iores);
- if (!pdev->base)
- return -EADDRNOTAVAIL;
+ pdev->base = devm_ioremap_resource(pdev->dev, iores);
+ if (IS_ERR(pdev->base))
+ return PTR_ERR(pdev->base);
of_id = of_match_device(mmp_pdma_dt_ids, pdev->dev);
if (of_id)
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index a9f1cd56689c..43d5a6c33297 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -9,6 +9,7 @@
*
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -547,9 +548,9 @@ static int mmp_tdma_probe(struct platform_device *pdev)
if (!iores)
return -EINVAL;
- tdev->base = devm_request_and_ioremap(&pdev->dev, iores);
- if (!tdev->base)
- return -EADDRNOTAVAIL;
+ tdev->base = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(tdev->base))
+ return PTR_ERR(tdev->base);
INIT_LIST_HEAD(&tdev->device.channels);
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index 5a31264f2bd1..c4b4fd2acc42 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -661,32 +661,14 @@ bool omap_dma_filter_fn(struct dma_chan *chan, void *param)
}
EXPORT_SYMBOL_GPL(omap_dma_filter_fn);
-static struct platform_device *pdev;
-
-static const struct platform_device_info omap_dma_dev_info = {
- .name = "omap-dma-engine",
- .id = -1,
- .dma_mask = DMA_BIT_MASK(32),
-};
-
static int omap_dma_init(void)
{
- int rc = platform_driver_register(&omap_dma_driver);
-
- if (rc == 0) {
- pdev = platform_device_register_full(&omap_dma_dev_info);
- if (IS_ERR(pdev)) {
- platform_driver_unregister(&omap_dma_driver);
- rc = PTR_ERR(pdev);
- }
- }
- return rc;
+ return platform_driver_register(&omap_dma_driver);
}
subsys_initcall(omap_dma_init);
static void __exit omap_dma_exit(void)
{
- platform_device_unregister(pdev);
platform_driver_unregister(&omap_dma_driver);
}
module_exit(omap_dma_exit);
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 3cad856fe67f..f6c018f1b453 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -21,6 +21,7 @@
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -31,8 +32,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <linux/clk/tegra.h>
-#include <mach/clk.h>
#include "dmaengine.h"
#define TEGRA_APBDMA_GENERAL 0x0
@@ -1240,12 +1241,9 @@ static int tegra_dma_probe(struct platform_device *pdev)
return -EINVAL;
}
- tdma->base_addr = devm_request_and_ioremap(&pdev->dev, res);
- if (!tdma->base_addr) {
- dev_err(&pdev->dev,
- "Cannot request memregion/iomap dma address\n");
- return -EADDRNOTAVAIL;
- }
+ tdma->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tdma->base_addr))
+ return PTR_ERR(tdma->base_addr);
tdma->dma_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(tdma->dma_clk)) {
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 66719925970f..acb709bfac0f 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -158,7 +158,7 @@ config EDAC_I3000
config EDAC_I3200
tristate "Intel 3200"
- depends on EDAC_MM_EDAC && PCI && X86 && EXPERIMENTAL
+ depends on EDAC_MM_EDAC && PCI && X86
help
Support for error detection and correction on the Intel
3200 and 3210 server chipsets.
@@ -224,7 +224,7 @@ config EDAC_I7300
config EDAC_SBRIDGE
tristate "Intel Sandy-Bridge Integrated MC"
depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL
- depends on PCI_MMCONFIG && EXPERIMENTAL
+ depends on PCI_MMCONFIG
help
Support for error detection and correction the Intel
Sandy Bridge Integrated Memory Controller.
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index ad8bf2aa629d..910b0116c128 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -31,7 +31,7 @@ static struct ecc_settings **ecc_stngs;
*
*FIXME: Produce a better mapping/linearisation.
*/
-struct scrubrate {
+static const struct scrubrate {
u32 scrubval; /* bit pattern for scrub rate */
u32 bandwidth; /* bandwidth consumed (bytes/sec) */
} scrubrates[] = {
@@ -239,7 +239,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
* DRAM base/limit associated with node_id
*/
static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr,
- unsigned nid)
+ u8 nid)
{
u64 addr;
@@ -265,7 +265,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
u64 sys_addr)
{
struct amd64_pvt *pvt;
- unsigned node_id;
+ u8 node_id;
u32 intlv_en, bits;
/*
@@ -602,111 +602,6 @@ static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
return input_addr;
}
-
-/*
- * @input_addr is an InputAddr associated with the node represented by mci.
- * Translate @input_addr to a DramAddr and return the result.
- */
-static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
-{
- struct amd64_pvt *pvt;
- unsigned node_id, intlv_shift;
- u64 bits, dram_addr;
- u32 intlv_sel;
-
- /*
- * Near the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
- * shows how to translate a DramAddr to an InputAddr. Here we reverse
- * this procedure. When translating from a DramAddr to an InputAddr, the
- * bits used for node interleaving are discarded. Here we recover these
- * bits from the IntlvSel field of the DRAM Limit register (section
- * 3.4.4.2) for the node that input_addr is associated with.
- */
- pvt = mci->pvt_info;
- node_id = pvt->mc_node_id;
-
- BUG_ON(node_id > 7);
-
- intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
- if (intlv_shift == 0) {
- edac_dbg(1, " InputAddr 0x%lx translates to DramAddr of same value\n",
- (unsigned long)input_addr);
-
- return input_addr;
- }
-
- bits = ((input_addr & GENMASK(12, 35)) << intlv_shift) +
- (input_addr & 0xfff);
-
- intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1);
- dram_addr = bits + (intlv_sel << 12);
-
- edac_dbg(1, "InputAddr 0x%lx translates to DramAddr 0x%lx (%d node interleave bits)\n",
- (unsigned long)input_addr,
- (unsigned long)dram_addr, intlv_shift);
-
- return dram_addr;
-}
-
-/*
- * @dram_addr is a DramAddr that maps to the node represented by mci. Convert
- * @dram_addr to a SysAddr.
- */
-static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
-{
- struct amd64_pvt *pvt = mci->pvt_info;
- u64 hole_base, hole_offset, hole_size, base, sys_addr;
- int ret = 0;
-
- ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
- &hole_size);
- if (!ret) {
- if ((dram_addr >= hole_base) &&
- (dram_addr < (hole_base + hole_size))) {
- sys_addr = dram_addr + hole_offset;
-
- edac_dbg(1, "using DHAR to translate DramAddr 0x%lx to SysAddr 0x%lx\n",
- (unsigned long)dram_addr,
- (unsigned long)sys_addr);
-
- return sys_addr;
- }
- }
-
- base = get_dram_base(pvt, pvt->mc_node_id);
- sys_addr = dram_addr + base;
-
- /*
- * The sys_addr we have computed up to this point is a 40-bit value
- * because the k8 deals with 40-bit values. However, the value we are
- * supposed to return is a full 64-bit physical address. The AMD
- * x86-64 architecture specifies that the most significant implemented
- * address bit through bit 63 of a physical address must be either all
- * 0s or all 1s. Therefore we sign-extend the 40-bit sys_addr to a
- * 64-bit value below. See section 3.4.2 of AMD publication 24592:
- * AMD x86-64 Architecture Programmer's Manual Volume 1 Application
- * Programming.
- */
- sys_addr |= ~((sys_addr & (1ull << 39)) - 1);
-
- edac_dbg(1, " Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
- pvt->mc_node_id, (unsigned long)dram_addr,
- (unsigned long)sys_addr);
-
- return sys_addr;
-}
-
-/*
- * @input_addr is an InputAddr associated with the node given by mci. Translate
- * @input_addr to a SysAddr.
- */
-static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci,
- u64 input_addr)
-{
- return dram_addr_to_sys_addr(mci,
- input_addr_to_dram_addr(mci, input_addr));
-}
-
/* Map the Error address to a PAGE and PAGE OFFSET. */
static inline void error_address_to_page_and_offset(u64 error_address,
struct err_info *err)
@@ -939,7 +834,8 @@ static u64 get_error_address(struct mce *m)
struct amd64_pvt *pvt;
u64 cc6_base, tmp_addr;
u32 tmp;
- u8 mce_nid, intlv_en;
+ u16 mce_nid;
+ u8 intlv_en;
if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7)
return addr;
@@ -979,10 +875,29 @@ static u64 get_error_address(struct mce *m)
return addr;
}
+static struct pci_dev *pci_get_related_function(unsigned int vendor,
+ unsigned int device,
+ struct pci_dev *related)
+{
+ struct pci_dev *dev = NULL;
+
+ while ((dev = pci_get_device(vendor, device, dev))) {
+ if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
+ (dev->bus->number == related->bus->number) &&
+ (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
+ break;
+ }
+
+ return dev;
+}
+
static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
{
+ struct amd_northbridge *nb;
+ struct pci_dev *misc, *f1 = NULL;
struct cpuinfo_x86 *c = &boot_cpu_data;
int off = range << 3;
+ u32 llim;
amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo);
amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
@@ -996,30 +911,32 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi);
amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
- /* Factor in CC6 save area by reading dst node's limit reg */
- if (c->x86 == 0x15) {
- struct pci_dev *f1 = NULL;
- u8 nid = dram_dst_node(pvt, range);
- u32 llim;
+ /* F15h: factor in CC6 save area by reading dst node's limit reg */
+ if (c->x86 != 0x15)
+ return;
- f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1));
- if (WARN_ON(!f1))
- return;
+ nb = node_to_amd_nb(dram_dst_node(pvt, range));
+ if (WARN_ON(!nb))
+ return;
+
+ misc = nb->misc;
+ f1 = pci_get_related_function(misc->vendor, PCI_DEVICE_ID_AMD_15H_NB_F1, misc);
+ if (WARN_ON(!f1))
+ return;
- amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
+ amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
- pvt->ranges[range].lim.lo &= GENMASK(0, 15);
+ pvt->ranges[range].lim.lo &= GENMASK(0, 15);
- /* {[39:27],111b} */
- pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
+ /* {[39:27],111b} */
+ pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
- pvt->ranges[range].lim.hi &= GENMASK(0, 7);
+ pvt->ranges[range].lim.hi &= GENMASK(0, 7);
- /* [47:40] */
- pvt->ranges[range].lim.hi |= llim >> 13;
+ /* [47:40] */
+ pvt->ranges[range].lim.hi |= llim >> 13;
- pci_dev_put(f1);
- }
+ pci_dev_put(f1);
}
static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
@@ -1305,7 +1222,7 @@ static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
}
/* Convert the sys_addr to the normalized DCT address */
-static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, unsigned range,
+static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
u64 sys_addr, bool hi_rng,
u32 dct_sel_base_addr)
{
@@ -1381,7 +1298,7 @@ static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
* -EINVAL: NOT FOUND
* 0..csrow = Chip-Select Row
*/
-static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
+static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
{
struct mem_ctl_info *mci;
struct amd64_pvt *pvt;
@@ -1672,23 +1589,6 @@ static struct amd64_family_type amd64_family_types[] = {
},
};
-static struct pci_dev *pci_get_related_function(unsigned int vendor,
- unsigned int device,
- struct pci_dev *related)
-{
- struct pci_dev *dev = NULL;
-
- dev = pci_get_device(vendor, device, dev);
- while (dev) {
- if ((dev->bus->number == related->bus->number) &&
- (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
- break;
- dev = pci_get_device(vendor, device, dev);
- }
-
- return dev;
-}
-
/*
* These are tables of eigenvectors (one per line) which can be used for the
* construction of the syndrome tables. The modified syndrome search algorithm
@@ -1696,7 +1596,7 @@ static struct pci_dev *pci_get_related_function(unsigned int vendor,
*
* Algorithm courtesy of Ross LaFetra from AMD.
*/
-static u16 x4_vectors[] = {
+static const u16 x4_vectors[] = {
0x2f57, 0x1afe, 0x66cc, 0xdd88,
0x11eb, 0x3396, 0x7f4c, 0xeac8,
0x0001, 0x0002, 0x0004, 0x0008,
@@ -1735,7 +1635,7 @@ static u16 x4_vectors[] = {
0x19a9, 0x2efe, 0xb5cc, 0x6f88,
};
-static u16 x8_vectors[] = {
+static const u16 x8_vectors[] = {
0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
@@ -1757,7 +1657,7 @@ static u16 x8_vectors[] = {
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
};
-static int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs,
+static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs,
unsigned v_dim)
{
unsigned int i, err_sym;
@@ -2181,7 +2081,7 @@ static int init_csrows(struct mem_ctl_info *mci)
}
/* get all cores on this DCT */
-static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
+static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
{
int cpu;
@@ -2191,7 +2091,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
}
/* check MCG_CTL on all the cpus on this node */
-static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
+static bool amd64_nb_mce_bank_enabled_on_node(u16 nid)
{
cpumask_var_t mask;
int cpu, nbe;
@@ -2224,7 +2124,7 @@ out:
return ret;
}
-static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
+static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on)
{
cpumask_var_t cmask;
int cpu;
@@ -2262,7 +2162,7 @@ static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
return 0;
}
-static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid,
struct pci_dev *F3)
{
bool ret = true;
@@ -2314,7 +2214,7 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
return ret;
}
-static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid,
struct pci_dev *F3)
{
u32 value, mask = 0x3; /* UECC/CECC enable */
@@ -2353,7 +2253,7 @@ static const char *ecc_msg =
"'ecc_enable_override'.\n"
" (Note that use of the override may cause unknown side effects.)\n";
-static bool ecc_enabled(struct pci_dev *F3, u8 nid)
+static bool ecc_enabled(struct pci_dev *F3, u16 nid)
{
u32 value;
u8 ecc_en = 0;
@@ -2474,7 +2374,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)
struct mem_ctl_info *mci = NULL;
struct edac_mc_layer layers[2];
int err = 0, ret;
- u8 nid = get_node_id(F2);
+ u16 nid = amd_get_node_id(F2);
ret = -ENOMEM;
pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
@@ -2566,7 +2466,7 @@ err_ret:
static int amd64_probe_one_instance(struct pci_dev *pdev,
const struct pci_device_id *mc_type)
{
- u8 nid = get_node_id(pdev);
+ u16 nid = amd_get_node_id(pdev);
struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
struct ecc_settings *s;
int ret = 0;
@@ -2616,7 +2516,7 @@ static void amd64_remove_one_instance(struct pci_dev *pdev)
{
struct mem_ctl_info *mci;
struct amd64_pvt *pvt;
- u8 nid = get_node_id(pdev);
+ u16 nid = amd_get_node_id(pdev);
struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
struct ecc_settings *s = ecc_stngs[nid];
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index e864f407806c..35637d83f235 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -292,12 +292,6 @@
/* MSRs */
#define MSR_MCGCTL_NBE BIT(4)
-/* AMD sets the first MC device at device ID 0x18. */
-static inline u8 get_node_id(struct pci_dev *pdev)
-{
- return PCI_SLOT(pdev->devfn) - 0x18;
-}
-
enum amd_families {
K8_CPUS = 0,
F10_CPUS,
@@ -340,7 +334,7 @@ struct amd64_pvt {
/* pci_device handles which we utilize */
struct pci_dev *F1, *F2, *F3;
- unsigned mc_node_id; /* MC index of this MC node */
+ u16 mc_node_id; /* MC index of this MC node */
int ext_model; /* extended model value of this node */
int channel_count;
@@ -393,7 +387,7 @@ struct err_info {
u32 offset;
};
-static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i)
+static inline u64 get_dram_base(struct amd64_pvt *pvt, u8 i)
{
u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8;
@@ -403,7 +397,7 @@ static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i)
return (((u64)pvt->ranges[i].base.hi & 0x000000ff) << 40) | addr;
}
-static inline u64 get_dram_limit(struct amd64_pvt *pvt, unsigned i)
+static inline u64 get_dram_limit(struct amd64_pvt *pvt, u8 i)
{
u64 lim = (((u64)pvt->ranges[i].lim.lo & 0xffff0000) << 8) | 0x00ffffff;
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index ad637572d8c7..f3f0c930d550 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -39,30 +39,28 @@ EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder);
*/
/* transaction type */
-const char * const tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
-EXPORT_SYMBOL_GPL(tt_msgs);
+static const char * const tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
/* cache level */
-const char * const ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
-EXPORT_SYMBOL_GPL(ll_msgs);
+static const char * const ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
/* memory transaction type */
-const char * const rrrr_msgs[] = {
+static const char * const rrrr_msgs[] = {
"GEN", "RD", "WR", "DRD", "DWR", "IRD", "PRF", "EV", "SNP"
};
-EXPORT_SYMBOL_GPL(rrrr_msgs);
/* participating processor */
const char * const pp_msgs[] = { "SRC", "RES", "OBS", "GEN" };
EXPORT_SYMBOL_GPL(pp_msgs);
/* request timeout */
-const char * const to_msgs[] = { "no timeout", "timed out" };
-EXPORT_SYMBOL_GPL(to_msgs);
+static const char * const to_msgs[] = { "no timeout", "timed out" };
/* memory or i/o */
-const char * const ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
-EXPORT_SYMBOL_GPL(ii_msgs);
+static const char * const ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
+
+/* internal error type */
+static const char * const uu_msgs[] = { "RESV", "RESV", "HWA", "RESV" };
static const char * const f15h_mc1_mce_desc[] = {
"UC during a demand linefill from L2",
@@ -176,7 +174,7 @@ static bool k8_mc0_mce(u16 ec, u8 xec)
return f10h_mc0_mce(ec, xec);
}
-static bool f14h_mc0_mce(u16 ec, u8 xec)
+static bool cat_mc0_mce(u16 ec, u8 xec)
{
u8 r4 = R4(ec);
bool ret = true;
@@ -330,22 +328,28 @@ static bool k8_mc1_mce(u16 ec, u8 xec)
return ret;
}
-static bool f14h_mc1_mce(u16 ec, u8 xec)
+static bool cat_mc1_mce(u16 ec, u8 xec)
{
u8 r4 = R4(ec);
bool ret = true;
- if (MEM_ERROR(ec)) {
- if (TT(ec) != 0 || LL(ec) != 1)
- ret = false;
+ if (!MEM_ERROR(ec))
+ return false;
+
+ if (TT(ec) != TT_INSTR)
+ return false;
+
+ if (r4 == R4_IRD)
+ pr_cont("Data/tag array parity error for a tag hit.\n");
+ else if (r4 == R4_SNOOP)
+ pr_cont("Tag error during snoop/victimization.\n");
+ else if (xec == 0x0)
+ pr_cont("Tag parity error from victim castout.\n");
+ else if (xec == 0x2)
+ pr_cont("Microcode patch RAM parity error.\n");
+ else
+ ret = false;
- if (r4 == R4_IRD)
- pr_cont("Data/tag array parity error for a tag hit.\n");
- else if (r4 == R4_SNOOP)
- pr_cont("Tag error during snoop/victimization.\n");
- else
- ret = false;
- }
return ret;
}
@@ -399,12 +403,9 @@ static void decode_mc1_mce(struct mce *m)
pr_emerg(HW_ERR "Corrupted MC1 MCE info?\n");
}
-static void decode_mc2_mce(struct mce *m)
+static bool k8_mc2_mce(u16 ec, u8 xec)
{
- u16 ec = EC(m->status);
- u8 xec = XEC(m->status, xec_mask);
-
- pr_emerg(HW_ERR "MC2 Error");
+ bool ret = true;
if (xec == 0x1)
pr_cont(" in the write data buffers.\n");
@@ -429,24 +430,18 @@ static void decode_mc2_mce(struct mce *m)
pr_cont(": %s parity/ECC error during data "
"access from L2.\n", R4_MSG(ec));
else
- goto wrong_mc2_mce;
+ ret = false;
} else
- goto wrong_mc2_mce;
+ ret = false;
} else
- goto wrong_mc2_mce;
-
- return;
+ ret = false;
- wrong_mc2_mce:
- pr_emerg(HW_ERR "Corrupted MC2 MCE info?\n");
+ return ret;
}
-static void decode_f15_mc2_mce(struct mce *m)
+static bool f15h_mc2_mce(u16 ec, u8 xec)
{
- u16 ec = EC(m->status);
- u8 xec = XEC(m->status, xec_mask);
-
- pr_emerg(HW_ERR "MC2 Error: ");
+ bool ret = true;
if (TLB_ERROR(ec)) {
if (xec == 0x0)
@@ -454,10 +449,10 @@ static void decode_f15_mc2_mce(struct mce *m)
else if (xec == 0x1)
pr_cont("Poison data provided for TLB fill.\n");
else
- goto wrong_f15_mc2_mce;
+ ret = false;
} else if (BUS_ERROR(ec)) {
if (xec > 2)
- goto wrong_f15_mc2_mce;
+ ret = false;
pr_cont("Error during attempted NB data read.\n");
} else if (MEM_ERROR(ec)) {
@@ -471,14 +466,63 @@ static void decode_f15_mc2_mce(struct mce *m)
break;
default:
- goto wrong_f15_mc2_mce;
+ ret = false;
}
}
- return;
+ return ret;
+}
- wrong_f15_mc2_mce:
- pr_emerg(HW_ERR "Corrupted MC2 MCE info?\n");
+static bool f16h_mc2_mce(u16 ec, u8 xec)
+{
+ u8 r4 = R4(ec);
+
+ if (!MEM_ERROR(ec))
+ return false;
+
+ switch (xec) {
+ case 0x04 ... 0x05:
+ pr_cont("%cBUFF parity error.\n", (r4 == R4_RD) ? 'I' : 'O');
+ break;
+
+ case 0x09 ... 0x0b:
+ case 0x0d ... 0x0f:
+ pr_cont("ECC error in L2 tag (%s).\n",
+ ((r4 == R4_GEN) ? "BankReq" :
+ ((r4 == R4_SNOOP) ? "Prb" : "Fill")));
+ break;
+
+ case 0x10 ... 0x19:
+ case 0x1b:
+ pr_cont("ECC error in L2 data array (%s).\n",
+ (((r4 == R4_RD) && !(xec & 0x3)) ? "Hit" :
+ ((r4 == R4_GEN) ? "Attr" :
+ ((r4 == R4_EVICT) ? "Vict" : "Fill"))));
+ break;
+
+ case 0x1c ... 0x1d:
+ case 0x1f:
+ pr_cont("Parity error in L2 attribute bits (%s).\n",
+ ((r4 == R4_RD) ? "Hit" :
+ ((r4 == R4_GEN) ? "Attr" : "Fill")));
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static void decode_mc2_mce(struct mce *m)
+{
+ u16 ec = EC(m->status);
+ u8 xec = XEC(m->status, xec_mask);
+
+ pr_emerg(HW_ERR "MC2 Error: ");
+
+ if (!fam_ops->mc2_mce(ec, xec))
+ pr_cont(HW_ERR "Corrupted MC2 MCE info?\n");
}
static void decode_mc3_mce(struct mce *m)
@@ -547,7 +591,7 @@ static void decode_mc4_mce(struct mce *m)
return;
case 0x19:
- if (boot_cpu_data.x86 == 0x15)
+ if (boot_cpu_data.x86 == 0x15 || boot_cpu_data.x86 == 0x16)
pr_cont("Compute Unit Data Error.\n");
else
goto wrong_mc4_mce;
@@ -633,6 +677,10 @@ static void decode_mc6_mce(struct mce *m)
static inline void amd_decode_err_code(u16 ec)
{
+ if (INT_ERROR(ec)) {
+ pr_emerg(HW_ERR "internal: %s\n", UU_MSG(ec));
+ return;
+ }
pr_emerg(HW_ERR "cache level: %s", LL_MSG(ec));
@@ -702,10 +750,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
break;
case 2:
- if (c->x86 == 0x15)
- decode_f15_mc2_mce(m);
- else
- decode_mc2_mce(m);
+ decode_mc2_mce(m);
break;
case 3:
@@ -740,7 +785,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
- if (c->x86 == 0x15)
+ if (c->x86 == 0x15 || c->x86 == 0x16)
pr_cont("|%s|%s",
((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
((m->status & MCI_STATUS_POISON) ? "Poison" : "-"));
@@ -772,7 +817,7 @@ static int __init mce_amd_init(void)
if (c->x86_vendor != X86_VENDOR_AMD)
return 0;
- if (c->x86 < 0xf || c->x86 > 0x15)
+ if (c->x86 < 0xf || c->x86 > 0x16)
return 0;
fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
@@ -783,33 +828,46 @@ static int __init mce_amd_init(void)
case 0xf:
fam_ops->mc0_mce = k8_mc0_mce;
fam_ops->mc1_mce = k8_mc1_mce;
+ fam_ops->mc2_mce = k8_mc2_mce;
break;
case 0x10:
fam_ops->mc0_mce = f10h_mc0_mce;
fam_ops->mc1_mce = k8_mc1_mce;
+ fam_ops->mc2_mce = k8_mc2_mce;
break;
case 0x11:
fam_ops->mc0_mce = k8_mc0_mce;
fam_ops->mc1_mce = k8_mc1_mce;
+ fam_ops->mc2_mce = k8_mc2_mce;
break;
case 0x12:
fam_ops->mc0_mce = f12h_mc0_mce;
fam_ops->mc1_mce = k8_mc1_mce;
+ fam_ops->mc2_mce = k8_mc2_mce;
break;
case 0x14:
nb_err_cpumask = 0x3;
- fam_ops->mc0_mce = f14h_mc0_mce;
- fam_ops->mc1_mce = f14h_mc1_mce;
+ fam_ops->mc0_mce = cat_mc0_mce;
+ fam_ops->mc1_mce = cat_mc1_mce;
+ fam_ops->mc2_mce = k8_mc2_mce;
break;
case 0x15:
xec_mask = 0x1f;
fam_ops->mc0_mce = f15h_mc0_mce;
fam_ops->mc1_mce = f15h_mc1_mce;
+ fam_ops->mc2_mce = f15h_mc2_mce;
+ break;
+
+ case 0x16:
+ xec_mask = 0x1f;
+ fam_ops->mc0_mce = cat_mc0_mce;
+ fam_ops->mc1_mce = cat_mc1_mce;
+ fam_ops->mc2_mce = f16h_mc2_mce;
break;
default:
diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h
index 679679951e23..51b7e3a36e37 100644
--- a/drivers/edac/mce_amd.h
+++ b/drivers/edac/mce_amd.h
@@ -14,6 +14,7 @@
#define TLB_ERROR(x) (((x) & 0xFFF0) == 0x0010)
#define MEM_ERROR(x) (((x) & 0xFF00) == 0x0100)
#define BUS_ERROR(x) (((x) & 0xF800) == 0x0800)
+#define INT_ERROR(x) (((x) & 0xF4FF) == 0x0400)
#define TT(x) (((x) >> 2) & 0x3)
#define TT_MSG(x) tt_msgs[TT(x)]
@@ -25,6 +26,8 @@
#define TO_MSG(x) to_msgs[TO(x)]
#define PP(x) (((x) >> 9) & 0x3)
#define PP_MSG(x) pp_msgs[PP(x)]
+#define UU(x) (((x) >> 8) & 0x3)
+#define UU_MSG(x) uu_msgs[UU(x)]
#define R4(x) (((x) >> 4) & 0xf)
#define R4_MSG(x) ((R4(x) < 9) ? rrrr_msgs[R4(x)] : "Wrong R4!")
@@ -32,6 +35,8 @@
#define MCI_STATUS_DEFERRED BIT_64(44)
#define MCI_STATUS_POISON BIT_64(43)
+extern const char * const pp_msgs[];
+
enum tt_ids {
TT_INSTR = 0,
TT_DATA,
@@ -65,19 +70,13 @@ enum rrrr_ids {
R4_SNOOP,
};
-extern const char * const tt_msgs[];
-extern const char * const ll_msgs[];
-extern const char * const rrrr_msgs[];
-extern const char * const pp_msgs[];
-extern const char * const to_msgs[];
-extern const char * const ii_msgs[];
-
/*
* per-family decoder ops
*/
struct amd_decoder_ops {
bool (*mc0_mce)(u16, u8);
bool (*mc1_mce)(u16, u8);
+ bool (*mc2_mce)(u16, u8);
};
void amd_report_gart_errors(bool);
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 42a840d530a5..3eb32f62d72a 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -301,7 +301,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
"[EDAC] PCI err", pci);
if (res < 0) {
printk(KERN_ERR
- "%s: Unable to requiest irq %d for "
+ "%s: Unable to request irq %d for "
"MPC85xx PCI err\n", __func__, pdata->irq);
irq_dispose_mapping(pdata->irq);
res = -ENODEV;
@@ -583,7 +583,7 @@ static int mpc85xx_l2_err_probe(struct platform_device *op)
"[EDAC] L2 err", edac_dev);
if (res < 0) {
printk(KERN_ERR
- "%s: Unable to requiest irq %d for "
+ "%s: Unable to request irq %d for "
"MPC85xx L2 err\n", __func__, pdata->irq);
irq_dispose_mapping(pdata->irq);
res = -ENODEV;
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 07122a9ef36e..5168a1324a65 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -29,7 +29,7 @@ config EXTCON_ADC_JACK
config EXTCON_MAX77693
tristate "MAX77693 EXTCON Support"
- depends on MFD_MAX77693
+ depends on MFD_MAX77693 && INPUT
select IRQ_DOMAIN
select REGMAP_I2C
help
@@ -47,7 +47,7 @@ config EXTCON_MAX8997
config EXTCON_ARIZONA
tristate "Wolfson Arizona EXTCON support"
- depends on MFD_ARIZONA && INPUT
+ depends on MFD_ARIZONA && INPUT && SND_SOC
help
Say Y here to enable support for external accessory detection
with Wolfson Arizona devices. These are audio CODECs with
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index eda2a1aa4adb..d0233cd18ffa 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -135,8 +135,7 @@ static int adc_jack_probe(struct platform_device *pdev)
;
data->num_conditions = i;
- data->chan = iio_channel_get(dev_name(&pdev->dev),
- pdata->consumer_channel);
+ data->chan = iio_channel_get(&pdev->dev, pdata->consumer_channel);
if (IS_ERR(data->chan)) {
err = PTR_ERR(data->chan);
goto out;
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 414aed50b1bc..dc357a4051f6 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -27,12 +27,18 @@
#include <linux/regulator/consumer.h>
#include <linux/extcon.h>
+#include <sound/soc.h>
+
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
#define ARIZONA_NUM_BUTTONS 6
+#define ARIZONA_ACCDET_MODE_MIC 0
+#define ARIZONA_ACCDET_MODE_HPL 1
+#define ARIZONA_ACCDET_MODE_HPR 2
+
struct arizona_extcon_info {
struct device *dev;
struct arizona *arizona;
@@ -45,17 +51,28 @@ struct arizona_extcon_info {
int micd_num_modes;
bool micd_reva;
+ bool micd_clamp;
+
+ struct delayed_work hpdet_work;
+
+ bool hpdet_active;
+ bool hpdet_done;
+
+ int num_hpdet_res;
+ unsigned int hpdet_res[3];
bool mic;
bool detecting;
int jack_flips;
+ int hpdet_ip;
+
struct extcon_dev edev;
};
static const struct arizona_micd_config micd_default_modes[] = {
- { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
{ 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
+ { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
};
static struct {
@@ -73,11 +90,13 @@ static struct {
#define ARIZONA_CABLE_MECHANICAL 0
#define ARIZONA_CABLE_MICROPHONE 1
#define ARIZONA_CABLE_HEADPHONE 2
+#define ARIZONA_CABLE_LINEOUT 3
static const char *arizona_cable[] = {
"Mechanical",
"Microphone",
"Headphone",
+ "Line-out",
NULL,
};
@@ -85,8 +104,9 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
{
struct arizona *arizona = info->arizona;
- gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
- info->micd_modes[mode].gpio);
+ if (arizona->pdata.micd_pol_gpio > 0)
+ gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
+ info->micd_modes[mode].gpio);
regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
ARIZONA_MICD_BIAS_SRC_MASK,
info->micd_modes[mode].bias);
@@ -98,19 +118,70 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
}
+static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
+{
+ switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) {
+ case 1:
+ return "MICBIAS1";
+ case 2:
+ return "MICBIAS2";
+ case 3:
+ return "MICBIAS3";
+ default:
+ return "MICVDD";
+ }
+}
+
+static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
+{
+ struct arizona *arizona = info->arizona;
+ const char *widget = arizona_extcon_get_micbias(info);
+ struct snd_soc_dapm_context *dapm = arizona->dapm;
+ int ret;
+
+ mutex_lock(&dapm->card->dapm_mutex);
+
+ ret = snd_soc_dapm_force_enable_pin(dapm, widget);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to enable %s: %d\n",
+ widget, ret);
+
+ mutex_unlock(&dapm->card->dapm_mutex);
+
+ snd_soc_dapm_sync(dapm);
+
+ if (!arizona->pdata.micd_force_micbias) {
+ mutex_lock(&dapm->card->dapm_mutex);
+
+ ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to disable %s: %d\n",
+ widget, ret);
+
+ mutex_unlock(&dapm->card->dapm_mutex);
+
+ snd_soc_dapm_sync(dapm);
+ }
+}
+
static void arizona_start_mic(struct arizona_extcon_info *info)
{
struct arizona *arizona = info->arizona;
bool change;
int ret;
- info->detecting = true;
- info->mic = false;
- info->jack_flips = 0;
-
/* Microphone detection can't use idle mode */
pm_runtime_get(info->dev);
+ if (info->detecting) {
+ ret = regulator_allow_bypass(info->micvdd, false);
+ if (ret != 0) {
+ dev_err(arizona->dev,
+ "Failed to regulate MICVDD: %d\n",
+ ret);
+ }
+ }
+
ret = regulator_enable(info->micvdd);
if (ret != 0) {
dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
@@ -123,6 +194,12 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
regmap_write(arizona->regmap, 0x80, 0x0);
}
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
+
+ arizona_extcon_pulse_micbias(info);
+
regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
&change);
@@ -135,18 +212,39 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
static void arizona_stop_mic(struct arizona_extcon_info *info)
{
struct arizona *arizona = info->arizona;
+ const char *widget = arizona_extcon_get_micbias(info);
+ struct snd_soc_dapm_context *dapm = arizona->dapm;
bool change;
+ int ret;
regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
ARIZONA_MICD_ENA, 0,
&change);
+ mutex_lock(&dapm->card->dapm_mutex);
+
+ ret = snd_soc_dapm_disable_pin(dapm, widget);
+ if (ret != 0)
+ dev_warn(arizona->dev,
+ "Failed to disable %s: %d\n",
+ widget, ret);
+
+ mutex_unlock(&dapm->card->dapm_mutex);
+
+ snd_soc_dapm_sync(dapm);
+
if (info->micd_reva) {
regmap_write(arizona->regmap, 0x80, 0x3);
regmap_write(arizona->regmap, 0x294, 2);
regmap_write(arizona->regmap, 0x80, 0x0);
}
+ ret = regulator_allow_bypass(info->micvdd, true);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
+ ret);
+ }
+
if (change) {
regulator_disable(info->micvdd);
pm_runtime_mark_last_busy(info->dev);
@@ -154,6 +252,478 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
}
}
+static struct {
+ unsigned int factor_a;
+ unsigned int factor_b;
+} arizona_hpdet_b_ranges[] = {
+ { 5528, 362464 },
+ { 11084, 6186851 },
+ { 11065, 65460395 },
+};
+
+static struct {
+ int min;
+ int max;
+} arizona_hpdet_c_ranges[] = {
+ { 0, 30 },
+ { 8, 100 },
+ { 100, 1000 },
+ { 1000, 10000 },
+};
+
+static int arizona_hpdet_read(struct arizona_extcon_info *info)
+{
+ struct arizona *arizona = info->arizona;
+ unsigned int val, range;
+ int ret;
+
+ ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
+ ret);
+ return ret;
+ }
+
+ switch (info->hpdet_ip) {
+ case 0:
+ if (!(val & ARIZONA_HP_DONE)) {
+ dev_err(arizona->dev, "HPDET did not complete: %x\n",
+ val);
+ return -EAGAIN;
+ }
+
+ val &= ARIZONA_HP_LVL_MASK;
+ break;
+
+ case 1:
+ if (!(val & ARIZONA_HP_DONE_B)) {
+ dev_err(arizona->dev, "HPDET did not complete: %x\n",
+ val);
+ return -EAGAIN;
+ }
+
+ ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to read HP value: %d\n",
+ ret);
+ return -EAGAIN;
+ }
+
+ regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+ &range);
+ range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
+ >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
+
+ if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
+ (val < 100 || val > 0x3fb)) {
+ range++;
+ dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
+ range);
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_IMPEDANCE_RANGE_MASK,
+ range <<
+ ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+ return -EAGAIN;
+ }
+
+ /* If we go out of range report top of range */
+ if (val < 100 || val > 0x3fb) {
+ dev_dbg(arizona->dev, "Measurement out of range\n");
+ return 10000;
+ }
+
+ dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
+ val, range);
+
+ val = arizona_hpdet_b_ranges[range].factor_b
+ / ((val * 100) -
+ arizona_hpdet_b_ranges[range].factor_a);
+ break;
+
+ default:
+ dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
+ info->hpdet_ip);
+ case 2:
+ if (!(val & ARIZONA_HP_DONE_B)) {
+ dev_err(arizona->dev, "HPDET did not complete: %x\n",
+ val);
+ return -EAGAIN;
+ }
+
+ val &= ARIZONA_HP_LVL_B_MASK;
+
+ regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+ &range);
+ range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
+ >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
+
+ /* Skip up or down a range? */
+ if (range && (val < arizona_hpdet_c_ranges[range].min)) {
+ range--;
+ dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
+ arizona_hpdet_c_ranges[range].min,
+ arizona_hpdet_c_ranges[range].max);
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_IMPEDANCE_RANGE_MASK,
+ range <<
+ ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+ return -EAGAIN;
+ }
+
+ if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
+ (val >= arizona_hpdet_c_ranges[range].max)) {
+ range++;
+ dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
+ arizona_hpdet_c_ranges[range].min,
+ arizona_hpdet_c_ranges[range].max);
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_IMPEDANCE_RANGE_MASK,
+ range <<
+ ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+ return -EAGAIN;
+ }
+ }
+
+ dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
+ return val;
+}
+
+static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
+{
+ struct arizona *arizona = info->arizona;
+ int id_gpio = arizona->pdata.hpdet_id_gpio;
+
+ /*
+ * If we're using HPDET for accessory identification we need
+ * to take multiple measurements, step through them in sequence.
+ */
+ if (arizona->pdata.hpdet_acc_id) {
+ info->hpdet_res[info->num_hpdet_res++] = *reading;
+
+ /*
+ * If the impedence is too high don't measure the
+ * second ground.
+ */
+ if (info->num_hpdet_res == 1 && *reading >= 45) {
+ dev_dbg(arizona->dev, "Skipping ground flip\n");
+ info->hpdet_res[info->num_hpdet_res++] = *reading;
+ }
+
+ if (info->num_hpdet_res == 1) {
+ dev_dbg(arizona->dev, "Flipping ground\n");
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_SRC,
+ ~info->micd_modes[0].src);
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+ return -EAGAIN;
+ }
+
+ /* Only check the mic directly if we didn't already ID it */
+ if (id_gpio && info->num_hpdet_res == 2 &&
+ !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) {
+ dev_dbg(arizona->dev, "Measuring mic\n");
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_MODE_MASK |
+ ARIZONA_ACCDET_SRC,
+ ARIZONA_ACCDET_MODE_HPR |
+ info->micd_modes[0].src);
+
+ gpio_set_value_cansleep(id_gpio, 1);
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+ return -EAGAIN;
+ }
+
+ /* OK, got both. Now, compare... */
+ dev_dbg(arizona->dev, "HPDET measured %d %d %d\n",
+ info->hpdet_res[0], info->hpdet_res[1],
+ info->hpdet_res[2]);
+
+
+ /* Take the headphone impedance for the main report */
+ *reading = info->hpdet_res[0];
+
+ /*
+ * Either the two grounds measure differently or we
+ * measure the mic as high impedance.
+ */
+ if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
+ (id_gpio && info->hpdet_res[2] > 10)) {
+ dev_dbg(arizona->dev, "Detected mic\n");
+ info->mic = true;
+ info->detecting = true;
+ } else {
+ dev_dbg(arizona->dev, "Detected headphone\n");
+ }
+
+ /* Make sure everything is reset back to the real polarity */
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_SRC,
+ info->micd_modes[0].src);
+ }
+
+ return 0;
+}
+
+static irqreturn_t arizona_hpdet_irq(int irq, void *data)
+{
+ struct arizona_extcon_info *info = data;
+ struct arizona *arizona = info->arizona;
+ int id_gpio = arizona->pdata.hpdet_id_gpio;
+ int report = ARIZONA_CABLE_HEADPHONE;
+ unsigned int val;
+ int ret, reading;
+
+ mutex_lock(&info->lock);
+
+ /* If we got a spurious IRQ for some reason then ignore it */
+ if (!info->hpdet_active) {
+ dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
+ mutex_unlock(&info->lock);
+ return IRQ_NONE;
+ }
+
+ /* If the cable was removed while measuring ignore the result */
+ ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
+ if (ret < 0) {
+ dev_err(arizona->dev, "Failed to check cable state: %d\n",
+ ret);
+ goto out;
+ } else if (!ret) {
+ dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
+ goto done;
+ }
+
+ ret = arizona_hpdet_read(info);
+ if (ret == -EAGAIN) {
+ goto out;
+ } else if (ret < 0) {
+ goto done;
+ }
+ reading = ret;
+
+ /* Reset back to starting range */
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
+ 0);
+
+ ret = arizona_hpdet_do_id(info, &reading);
+ if (ret == -EAGAIN) {
+ goto out;
+ } else if (ret < 0) {
+ goto done;
+ }
+
+ /* Report high impedence cables as line outputs */
+ if (reading >= 5000)
+ report = ARIZONA_CABLE_LINEOUT;
+ else
+ report = ARIZONA_CABLE_HEADPHONE;
+
+ ret = extcon_set_cable_state_(&info->edev, report, true);
+ if (ret != 0)
+ dev_err(arizona->dev, "Failed to report HP/line: %d\n",
+ ret);
+
+ mutex_lock(&arizona->dapm->card->dapm_mutex);
+
+ ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to read output enables: %d\n",
+ ret);
+ val = 0;
+ }
+
+ if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
+ ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to undo magic: %d\n",
+ ret);
+
+ ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to undo magic: %d\n",
+ ret);
+ }
+
+ mutex_unlock(&arizona->dapm->card->dapm_mutex);
+
+done:
+ if (id_gpio)
+ gpio_set_value_cansleep(id_gpio, 0);
+
+ /* Revert back to MICDET mode */
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
+
+ /* If we have a mic then reenable MICDET */
+ if (info->mic)
+ arizona_start_mic(info);
+
+ if (info->hpdet_active) {
+ pm_runtime_put_autosuspend(info->dev);
+ info->hpdet_active = false;
+ }
+
+ info->hpdet_done = true;
+
+out:
+ mutex_unlock(&info->lock);
+
+ return IRQ_HANDLED;
+}
+
+static void arizona_identify_headphone(struct arizona_extcon_info *info)
+{
+ struct arizona *arizona = info->arizona;
+ int ret;
+
+ if (info->hpdet_done)
+ return;
+
+ dev_dbg(arizona->dev, "Starting HPDET\n");
+
+ /* Make sure we keep the device enabled during the measurement */
+ pm_runtime_get(info->dev);
+
+ info->hpdet_active = true;
+
+ if (info->mic)
+ arizona_stop_mic(info);
+
+ ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
+
+ ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
+
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_MODE_MASK,
+ ARIZONA_ACCDET_MODE_HPL);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
+ ret);
+ goto err;
+ }
+
+ return;
+
+err:
+ regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
+
+ /* Just report headphone */
+ ret = extcon_update_state(&info->edev,
+ 1 << ARIZONA_CABLE_HEADPHONE,
+ 1 << ARIZONA_CABLE_HEADPHONE);
+ if (ret != 0)
+ dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
+
+ if (info->mic)
+ arizona_start_mic(info);
+
+ info->hpdet_active = false;
+}
+
+static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
+{
+ struct arizona *arizona = info->arizona;
+ unsigned int val;
+ int ret;
+
+ dev_dbg(arizona->dev, "Starting identification via HPDET\n");
+
+ /* Make sure we keep the device enabled during the measurement */
+ pm_runtime_get_sync(info->dev);
+
+ info->hpdet_active = true;
+
+ arizona_extcon_pulse_micbias(info);
+
+ mutex_lock(&arizona->dapm->card->dapm_mutex);
+
+ ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to read output enables: %d\n",
+ ret);
+ val = 0;
+ }
+
+ if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
+ ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
+ 0x4000);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to do magic: %d\n",
+ ret);
+
+ ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
+ 0x4000);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to do magic: %d\n",
+ ret);
+ }
+
+ mutex_unlock(&arizona->dapm->card->dapm_mutex);
+
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
+ info->micd_modes[0].src |
+ ARIZONA_ACCDET_MODE_HPL);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
+ ret);
+ goto err;
+ }
+
+ return;
+
+err:
+ regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
+ ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
+
+ /* Just report headphone */
+ ret = extcon_update_state(&info->edev,
+ 1 << ARIZONA_CABLE_HEADPHONE,
+ 1 << ARIZONA_CABLE_HEADPHONE);
+ if (ret != 0)
+ dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
+
+ info->hpdet_active = false;
+}
+
static irqreturn_t arizona_micdet(int irq, void *data)
{
struct arizona_extcon_info *info = data;
@@ -187,16 +757,23 @@ static irqreturn_t arizona_micdet(int irq, void *data)
/* If we got a high impedence we should have a headset, report it. */
if (info->detecting && (val & 0x400)) {
+ arizona_identify_headphone(info);
+
ret = extcon_update_state(&info->edev,
- 1 << ARIZONA_CABLE_MICROPHONE |
- 1 << ARIZONA_CABLE_HEADPHONE,
- 1 << ARIZONA_CABLE_MICROPHONE |
- 1 << ARIZONA_CABLE_HEADPHONE);
+ 1 << ARIZONA_CABLE_MICROPHONE,
+ 1 << ARIZONA_CABLE_MICROPHONE);
if (ret != 0)
dev_err(arizona->dev, "Headset report failed: %d\n",
ret);
+ /* Don't need to regulate for button detection */
+ ret = regulator_allow_bypass(info->micvdd, false);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
+ ret);
+ }
+
info->mic = true;
info->detecting = false;
goto handled;
@@ -209,20 +786,13 @@ static irqreturn_t arizona_micdet(int irq, void *data)
* impedence then give up and report headphones.
*/
if (info->detecting && (val & 0x3f8)) {
- info->jack_flips++;
-
if (info->jack_flips >= info->micd_num_modes) {
- dev_dbg(arizona->dev, "Detected headphone\n");
+ dev_dbg(arizona->dev, "Detected HP/line\n");
+ arizona_identify_headphone(info);
+
info->detecting = false;
- arizona_stop_mic(info);
- ret = extcon_set_cable_state_(&info->edev,
- ARIZONA_CABLE_HEADPHONE,
- true);
- if (ret != 0)
- dev_err(arizona->dev,
- "Headphone report failed: %d\n",
- ret);
+ arizona_stop_mic(info);
} else {
info->micd_mode++;
if (info->micd_mode == info->micd_num_modes)
@@ -258,13 +828,7 @@ static irqreturn_t arizona_micdet(int irq, void *data)
info->detecting = false;
arizona_stop_mic(info);
- ret = extcon_set_cable_state_(&info->edev,
- ARIZONA_CABLE_HEADPHONE,
- true);
- if (ret != 0)
- dev_err(arizona->dev,
- "Headphone report failed: %d\n",
- ret);
+ arizona_identify_headphone(info);
} else {
dev_warn(arizona->dev, "Button with no mic: %x\n",
val);
@@ -275,6 +839,7 @@ static irqreturn_t arizona_micdet(int irq, void *data)
input_report_key(info->input,
arizona_lvl_to_key[i].report, 0);
input_sync(info->input);
+ arizona_extcon_pulse_micbias(info);
}
handled:
@@ -284,17 +849,38 @@ handled:
return IRQ_HANDLED;
}
+static void arizona_hpdet_work(struct work_struct *work)
+{
+ struct arizona_extcon_info *info = container_of(work,
+ struct arizona_extcon_info,
+ hpdet_work.work);
+
+ mutex_lock(&info->lock);
+ arizona_start_hpdet_acc_id(info);
+ mutex_unlock(&info->lock);
+}
+
static irqreturn_t arizona_jackdet(int irq, void *data)
{
struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona;
- unsigned int val;
+ unsigned int val, present, mask;
int ret, i;
pm_runtime_get_sync(info->dev);
+ cancel_delayed_work_sync(&info->hpdet_work);
+
mutex_lock(&info->lock);
+ if (arizona->pdata.jd_gpio5) {
+ mask = ARIZONA_MICD_CLAMP_STS;
+ present = 0;
+ } else {
+ mask = ARIZONA_JD1_STS;
+ present = ARIZONA_JD1_STS;
+ }
+
ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
if (ret != 0) {
dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
@@ -304,7 +890,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
return IRQ_NONE;
}
- if (val & ARIZONA_JD1_STS) {
+ if ((val & mask) == present) {
dev_dbg(arizona->dev, "Detected jack\n");
ret = extcon_set_cable_state_(&info->edev,
ARIZONA_CABLE_MECHANICAL, true);
@@ -313,12 +899,31 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
dev_err(arizona->dev, "Mechanical report failed: %d\n",
ret);
- arizona_start_mic(info);
+ if (!arizona->pdata.hpdet_acc_id) {
+ info->detecting = true;
+ info->mic = false;
+ info->jack_flips = 0;
+
+ arizona_start_mic(info);
+ } else {
+ schedule_delayed_work(&info->hpdet_work,
+ msecs_to_jiffies(250));
+ }
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0);
} else {
dev_dbg(arizona->dev, "Detected jack removal\n");
arizona_stop_mic(info);
+ info->num_hpdet_res = 0;
+ for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
+ info->hpdet_res[i] = 0;
+ info->mic = false;
+ info->hpdet_done = false;
+
for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
input_report_key(info->input,
arizona_lvl_to_key[i].report, 0);
@@ -328,8 +933,20 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
if (ret != 0)
dev_err(arizona->dev, "Removal report failed: %d\n",
ret);
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
}
+ /* Clear trig_sts to make sure DCVDD is not forced up */
+ regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
+ ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
+ ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
+ ARIZONA_JD1_FALL_TRIG_STS |
+ ARIZONA_JD1_RISE_TRIG_STS);
+
mutex_unlock(&info->lock);
pm_runtime_mark_last_busy(info->dev);
@@ -343,8 +960,12 @@ static int arizona_extcon_probe(struct platform_device *pdev)
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
struct arizona_pdata *pdata;
struct arizona_extcon_info *info;
+ int jack_irq_fall, jack_irq_rise;
int ret, mode, i;
+ if (!arizona->dapm || !arizona->dapm->card)
+ return -EPROBE_DEFER;
+
pdata = dev_get_platdata(arizona->dev);
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
@@ -364,7 +985,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
mutex_init(&info->lock);
info->arizona = arizona;
info->dev = &pdev->dev;
- info->detecting = true;
+ INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
platform_set_drvdata(pdev, info);
switch (arizona->type) {
@@ -374,6 +995,8 @@ static int arizona_extcon_probe(struct platform_device *pdev)
info->micd_reva = true;
break;
default:
+ info->micd_clamp = true;
+ info->hpdet_ip = 1;
break;
}
break;
@@ -416,9 +1039,64 @@ static int arizona_extcon_probe(struct platform_device *pdev)
}
}
+ if (arizona->pdata.hpdet_id_gpio > 0) {
+ ret = devm_gpio_request_one(&pdev->dev,
+ arizona->pdata.hpdet_id_gpio,
+ GPIOF_OUT_INIT_LOW,
+ "HPDET");
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
+ arizona->pdata.hpdet_id_gpio, ret);
+ goto err_register;
+ }
+ }
+
+ if (arizona->pdata.micd_bias_start_time)
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_BIAS_STARTTIME_MASK,
+ arizona->pdata.micd_bias_start_time
+ << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
+
+ if (arizona->pdata.micd_rate)
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_RATE_MASK,
+ arizona->pdata.micd_rate
+ << ARIZONA_MICD_RATE_SHIFT);
+
+ if (arizona->pdata.micd_dbtime)
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+ ARIZONA_MICD_DBTIME_MASK,
+ arizona->pdata.micd_dbtime
+ << ARIZONA_MICD_DBTIME_SHIFT);
+
+ /*
+ * If we have a clamp use it, activating in conjunction with
+ * GPIO5 if that is connected for jack detect operation.
+ */
+ if (info->micd_clamp) {
+ if (arizona->pdata.jd_gpio5) {
+ /* Put the GPIO into input mode */
+ regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
+ 0xc101);
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_MICD_CLAMP_CONTROL,
+ ARIZONA_MICD_CLAMP_MODE_MASK, 0x9);
+ } else {
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_MICD_CLAMP_CONTROL,
+ ARIZONA_MICD_CLAMP_MODE_MASK, 0x4);
+ }
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB,
+ ARIZONA_MICD_CLAMP_DB);
+ }
+
arizona_extcon_set_mode(info, 0);
- info->input = input_allocate_device();
+ info->input = devm_input_allocate_device(&pdev->dev);
if (!info->input) {
dev_err(arizona->dev, "Can't allocate input dev\n");
ret = -ENOMEM;
@@ -436,7 +1114,15 @@ static int arizona_extcon_probe(struct platform_device *pdev)
pm_runtime_idle(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
- ret = arizona_request_irq(arizona, ARIZONA_IRQ_JD_RISE,
+ if (arizona->pdata.jd_gpio5) {
+ jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
+ jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
+ } else {
+ jack_irq_rise = ARIZONA_IRQ_JD_RISE;
+ jack_irq_fall = ARIZONA_IRQ_JD_FALL;
+ }
+
+ ret = arizona_request_irq(arizona, jack_irq_rise,
"JACKDET rise", arizona_jackdet, info);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
@@ -444,21 +1130,21 @@ static int arizona_extcon_probe(struct platform_device *pdev)
goto err_input;
}
- ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 1);
+ ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
ret);
goto err_rise;
}
- ret = arizona_request_irq(arizona, ARIZONA_IRQ_JD_FALL,
+ ret = arizona_request_irq(arizona, jack_irq_fall,
"JACKDET fall", arizona_jackdet, info);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
goto err_rise_wake;
}
- ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 1);
+ ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
ret);
@@ -472,11 +1158,12 @@ static int arizona_extcon_probe(struct platform_device *pdev)
goto err_fall_wake;
}
- regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
- ARIZONA_MICD_BIAS_STARTTIME_MASK |
- ARIZONA_MICD_RATE_MASK,
- 7 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT |
- 8 << ARIZONA_MICD_RATE_SHIFT);
+ ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
+ "HPDET", arizona_hpdet_irq, info);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
+ goto err_micdet;
+ }
arizona_clk32k_enable(arizona);
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
@@ -494,23 +1181,24 @@ static int arizona_extcon_probe(struct platform_device *pdev)
ret = input_register_device(info->input);
if (ret) {
dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
- goto err_micdet;
+ goto err_hpdet;
}
return 0;
+err_hpdet:
+ arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
err_micdet:
arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
err_fall_wake:
- arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0);
+ arizona_set_irq_wake(arizona, jack_irq_fall, 0);
err_fall:
- arizona_free_irq(arizona, ARIZONA_IRQ_JD_FALL, info);
+ arizona_free_irq(arizona, jack_irq_fall, info);
err_rise_wake:
- arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0);
+ arizona_set_irq_wake(arizona, jack_irq_rise, 0);
err_rise:
- arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
+ arizona_free_irq(arizona, jack_irq_rise, info);
err_input:
- input_free_device(info->input);
err_register:
pm_runtime_disable(&pdev->dev);
extcon_dev_unregister(&info->edev);
@@ -522,18 +1210,32 @@ static int arizona_extcon_remove(struct platform_device *pdev)
{
struct arizona_extcon_info *info = platform_get_drvdata(pdev);
struct arizona *arizona = info->arizona;
+ int jack_irq_rise, jack_irq_fall;
pm_runtime_disable(&pdev->dev);
- arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0);
- arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0);
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_MICD_CLAMP_CONTROL,
+ ARIZONA_MICD_CLAMP_MODE_MASK, 0);
+
+ if (arizona->pdata.jd_gpio5) {
+ jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
+ jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
+ } else {
+ jack_irq_rise = ARIZONA_IRQ_JD_RISE;
+ jack_irq_fall = ARIZONA_IRQ_JD_FALL;
+ }
+
+ arizona_set_irq_wake(arizona, jack_irq_rise, 0);
+ arizona_set_irq_wake(arizona, jack_irq_fall, 0);
+ arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
- arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info);
- arizona_free_irq(arizona, ARIZONA_IRQ_JD_FALL, info);
+ arizona_free_irq(arizona, jack_irq_rise, info);
+ arizona_free_irq(arizona, jack_irq_fall, info);
+ cancel_delayed_work_sync(&info->hpdet_work);
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
ARIZONA_JD1_ENA, 0);
arizona_clk32k_disable(arizona);
- input_unregister_device(info->input);
extcon_dev_unregister(&info->edev);
return 0;
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index 1b14bfcdc176..02bec32adde4 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -29,7 +29,7 @@
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/extcon.h>
-#include <linux/extcon/extcon_gpio.h>
+#include <linux/extcon/extcon-gpio.h>
struct gpio_extcon_data {
struct extcon_dev edev;
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 8c17b65eb74d..b70e3815c459 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
+#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/platform_device.h>
@@ -29,92 +30,7 @@
#include <linux/irqdomain.h>
#define DEV_NAME "max77693-muic"
-
-/* MAX77693 MUIC - STATUS1~3 Register */
-#define STATUS1_ADC_SHIFT (0)
-#define STATUS1_ADCLOW_SHIFT (5)
-#define STATUS1_ADCERR_SHIFT (6)
-#define STATUS1_ADC1K_SHIFT (7)
-#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT)
-#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT)
-#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT)
-#define STATUS1_ADC1K_MASK (0x1 << STATUS1_ADC1K_SHIFT)
-
-#define STATUS2_CHGTYP_SHIFT (0)
-#define STATUS2_CHGDETRUN_SHIFT (3)
-#define STATUS2_DCDTMR_SHIFT (4)
-#define STATUS2_DXOVP_SHIFT (5)
-#define STATUS2_VBVOLT_SHIFT (6)
-#define STATUS2_VIDRM_SHIFT (7)
-#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT)
-#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT)
-#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT)
-#define STATUS2_DXOVP_MASK (0x1 << STATUS2_DXOVP_SHIFT)
-#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT)
-#define STATUS2_VIDRM_MASK (0x1 << STATUS2_VIDRM_SHIFT)
-
-#define STATUS3_OVP_SHIFT (2)
-#define STATUS3_OVP_MASK (0x1 << STATUS3_OVP_SHIFT)
-
-/* MAX77693 CDETCTRL1~2 register */
-#define CDETCTRL1_CHGDETEN_SHIFT (0)
-#define CDETCTRL1_CHGTYPMAN_SHIFT (1)
-#define CDETCTRL1_DCDEN_SHIFT (2)
-#define CDETCTRL1_DCD2SCT_SHIFT (3)
-#define CDETCTRL1_CDDELAY_SHIFT (4)
-#define CDETCTRL1_DCDCPL_SHIFT (5)
-#define CDETCTRL1_CDPDET_SHIFT (7)
-#define CDETCTRL1_CHGDETEN_MASK (0x1 << CDETCTRL1_CHGDETEN_SHIFT)
-#define CDETCTRL1_CHGTYPMAN_MASK (0x1 << CDETCTRL1_CHGTYPMAN_SHIFT)
-#define CDETCTRL1_DCDEN_MASK (0x1 << CDETCTRL1_DCDEN_SHIFT)
-#define CDETCTRL1_DCD2SCT_MASK (0x1 << CDETCTRL1_DCD2SCT_SHIFT)
-#define CDETCTRL1_CDDELAY_MASK (0x1 << CDETCTRL1_CDDELAY_SHIFT)
-#define CDETCTRL1_DCDCPL_MASK (0x1 << CDETCTRL1_DCDCPL_SHIFT)
-#define CDETCTRL1_CDPDET_MASK (0x1 << CDETCTRL1_CDPDET_SHIFT)
-
-#define CDETCTRL2_VIDRMEN_SHIFT (1)
-#define CDETCTRL2_DXOVPEN_SHIFT (3)
-#define CDETCTRL2_VIDRMEN_MASK (0x1 << CDETCTRL2_VIDRMEN_SHIFT)
-#define CDETCTRL2_DXOVPEN_MASK (0x1 << CDETCTRL2_DXOVPEN_SHIFT)
-
-/* MAX77693 MUIC - CONTROL1~3 register */
-#define COMN1SW_SHIFT (0)
-#define COMP2SW_SHIFT (3)
-#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT)
-#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT)
-#define COMP_SW_MASK (COMP2SW_MASK | COMN1SW_MASK)
-#define CONTROL1_SW_USB ((1 << COMP2SW_SHIFT) \
- | (1 << COMN1SW_SHIFT))
-#define CONTROL1_SW_AUDIO ((2 << COMP2SW_SHIFT) \
- | (2 << COMN1SW_SHIFT))
-#define CONTROL1_SW_UART ((3 << COMP2SW_SHIFT) \
- | (3 << COMN1SW_SHIFT))
-#define CONTROL1_SW_OPEN ((0 << COMP2SW_SHIFT) \
- | (0 << COMN1SW_SHIFT))
-
-#define CONTROL2_LOWPWR_SHIFT (0)
-#define CONTROL2_ADCEN_SHIFT (1)
-#define CONTROL2_CPEN_SHIFT (2)
-#define CONTROL2_SFOUTASRT_SHIFT (3)
-#define CONTROL2_SFOUTORD_SHIFT (4)
-#define CONTROL2_ACCDET_SHIFT (5)
-#define CONTROL2_USBCPINT_SHIFT (6)
-#define CONTROL2_RCPS_SHIFT (7)
-#define CONTROL2_LOWPWR_MASK (0x1 << CONTROL2_LOWPWR_SHIFT)
-#define CONTROL2_ADCEN_MASK (0x1 << CONTROL2_ADCEN_SHIFT)
-#define CONTROL2_CPEN_MASK (0x1 << CONTROL2_CPEN_SHIFT)
-#define CONTROL2_SFOUTASRT_MASK (0x1 << CONTROL2_SFOUTASRT_SHIFT)
-#define CONTROL2_SFOUTORD_MASK (0x1 << CONTROL2_SFOUTORD_SHIFT)
-#define CONTROL2_ACCDET_MASK (0x1 << CONTROL2_ACCDET_SHIFT)
-#define CONTROL2_USBCPINT_MASK (0x1 << CONTROL2_USBCPINT_SHIFT)
-#define CONTROL2_RCPS_MASK (0x1 << CONTROL2_RCPS_SHIFT)
-
-#define CONTROL3_JIGSET_SHIFT (0)
-#define CONTROL3_BTLDSET_SHIFT (2)
-#define CONTROL3_ADCDBSET_SHIFT (4)
-#define CONTROL3_JIGSET_MASK (0x3 << CONTROL3_JIGSET_SHIFT)
-#define CONTROL3_BTLDSET_MASK (0x3 << CONTROL3_BTLDSET_SHIFT)
-#define CONTROL3_ADCDBSET_MASK (0x3 << CONTROL3_ADCDBSET_SHIFT)
+#define DELAY_MS_DEFAULT 20000 /* unit: millisecond */
enum max77693_muic_adc_debounce_time {
ADC_DEBOUNCE_TIME_5MS = 0,
@@ -127,14 +43,40 @@ struct max77693_muic_info {
struct device *dev;
struct max77693_dev *max77693;
struct extcon_dev *edev;
- int prev_adc;
- int prev_adc_gnd;
+ int prev_cable_type;
+ int prev_cable_type_gnd;
int prev_chg_type;
+ int prev_button_type;
u8 status[2];
int irq;
struct work_struct irq_work;
struct mutex mutex;
+
+ /*
+ * Use delayed workqueue to detect cable state and then
+ * notify cable state to notifiee/platform through uevent.
+ * After completing the booting of platform, the extcon provider
+ * driver should notify cable state to upper layer.
+ */
+ struct delayed_work wq_detcable;
+
+ /* Button of dock device */
+ struct input_dev *dock;
+
+ /*
+ * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
+ * h/w path of COMP2/COMN1 on CONTROL1 register.
+ */
+ int path_usb;
+ int path_uart;
+};
+
+enum max77693_muic_cable_group {
+ MAX77693_CABLE_GROUP_ADC = 0,
+ MAX77693_CABLE_GROUP_ADC_GND,
+ MAX77693_CABLE_GROUP_CHG,
+ MAX77693_CABLE_GROUP_VBVOLT,
};
enum max77693_muic_charger_type {
@@ -215,27 +157,59 @@ enum max77693_muic_acc_type {
/* The below accessories have same ADC value so ADCLow and
ADC1K bit is used to separate specific accessory */
- MAX77693_MUIC_GND_USB_OTG = 0x100, /* ADC:0x0, ADCLow:0, ADC1K:0 */
- MAX77693_MUIC_GND_AV_CABLE_LOAD = 0x102,/* ADC:0x0, ADCLow:1, ADC1K:0 */
- MAX77693_MUIC_GND_MHL_CABLE = 0x103, /* ADC:0x0, ADCLow:1, ADC1K:1 */
+ MAX77693_MUIC_GND_USB_OTG = 0x100, /* ADC:0x0, VBVolot:0, ADCLow:0, ADC1K:0 */
+ MAX77693_MUIC_GND_USB_OTG_VB = 0x104, /* ADC:0x0, VBVolot:1, ADCLow:0, ADC1K:0 */
+ MAX77693_MUIC_GND_AV_CABLE_LOAD = 0x102,/* ADC:0x0, VBVolot:0, ADCLow:1, ADC1K:0 */
+ MAX77693_MUIC_GND_MHL = 0x103, /* ADC:0x0, VBVolot:0, ADCLow:1, ADC1K:1 */
+ MAX77693_MUIC_GND_MHL_VB = 0x107, /* ADC:0x0, VBVolot:1, ADCLow:1, ADC1K:1 */
};
/* MAX77693 MUIC device support below list of accessories(external connector) */
-const char *max77693_extcon_cable[] = {
- [0] = "USB",
- [1] = "USB-Host",
- [2] = "TA",
- [3] = "Fast-charger",
- [4] = "Slow-charger",
- [5] = "Charge-downstream",
- [6] = "MHL",
- [7] = "Audio-video-load",
- [8] = "Audio-video-noload",
- [9] = "JIG",
+enum {
+ EXTCON_CABLE_USB = 0,
+ EXTCON_CABLE_USB_HOST,
+ EXTCON_CABLE_TA,
+ EXTCON_CABLE_FAST_CHARGER,
+ EXTCON_CABLE_SLOW_CHARGER,
+ EXTCON_CABLE_CHARGE_DOWNSTREAM,
+ EXTCON_CABLE_MHL,
+ EXTCON_CABLE_MHL_TA,
+ EXTCON_CABLE_JIG_USB_ON,
+ EXTCON_CABLE_JIG_USB_OFF,
+ EXTCON_CABLE_JIG_UART_OFF,
+ EXTCON_CABLE_JIG_UART_ON,
+ EXTCON_CABLE_DOCK_SMART,
+ EXTCON_CABLE_DOCK_DESK,
+ EXTCON_CABLE_DOCK_AUDIO,
+
+ _EXTCON_CABLE_NUM,
+};
+
+static const char *max77693_extcon_cable[] = {
+ [EXTCON_CABLE_USB] = "USB",
+ [EXTCON_CABLE_USB_HOST] = "USB-Host",
+ [EXTCON_CABLE_TA] = "TA",
+ [EXTCON_CABLE_FAST_CHARGER] = "Fast-charger",
+ [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
+ [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
+ [EXTCON_CABLE_MHL] = "MHL",
+ [EXTCON_CABLE_MHL_TA] = "MHL_TA",
+ [EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON",
+ [EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
+ [EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
+ [EXTCON_CABLE_JIG_UART_ON] = "Dock-Car",
+ [EXTCON_CABLE_DOCK_SMART] = "Dock-Smart",
+ [EXTCON_CABLE_DOCK_DESK] = "Dock-Desk",
+ [EXTCON_CABLE_DOCK_AUDIO] = "Dock-Audio",
NULL,
};
+/*
+ * max77693_muic_set_debounce_time - Set the debounce time of ADC
+ * @info: the instance including private data of max77693 MUIC
+ * @time: the debounce time of ADC
+ */
static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
enum max77693_muic_adc_debounce_time time)
{
@@ -250,18 +224,29 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
MAX77693_MUIC_REG_CTRL3,
time << CONTROL3_ADCDBSET_SHIFT,
CONTROL3_ADCDBSET_MASK);
- if (ret)
+ if (ret) {
dev_err(info->dev, "failed to set ADC debounce time\n");
+ return -EAGAIN;
+ }
break;
default:
dev_err(info->dev, "invalid ADC debounce time\n");
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- return ret;
+ return 0;
};
+/*
+ * max77693_muic_set_path - Set hardware line according to attached cable
+ * @info: the instance including private data of max77693 MUIC
+ * @value: the path according to attached cable
+ * @attached: the state of cable (true:attached, false:detached)
+ *
+ * The max77693 MUIC device share outside H/W line among a varity of cables
+ * so, this function set internal path of H/W line according to the type of
+ * attached cable.
+ */
static int max77693_muic_set_path(struct max77693_muic_info *info,
u8 val, bool attached)
{
@@ -277,7 +262,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info,
MAX77693_MUIC_REG_CTRL1, ctrl1, COMP_SW_MASK);
if (ret < 0) {
dev_err(info->dev, "failed to update MUIC register\n");
- goto out;
+ return -EAGAIN;
}
if (attached)
@@ -290,141 +275,457 @@ static int max77693_muic_set_path(struct max77693_muic_info *info,
CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);
if (ret < 0) {
dev_err(info->dev, "failed to update MUIC register\n");
- goto out;
+ return -EAGAIN;
}
dev_info(info->dev,
"CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
ctrl1, ctrl2, attached ? "attached" : "detached");
-out:
- return ret;
+
+ return 0;
}
-static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info,
- bool attached)
+/*
+ * max77693_muic_get_cable_type - Return cable type and check cable state
+ * @info: the instance including private data of max77693 MUIC
+ * @group: the path according to attached cable
+ * @attached: store cable state and return
+ *
+ * This function check the cable state either attached or detached,
+ * and then divide precise type of cable according to cable group.
+ * - MAX77693_CABLE_GROUP_ADC
+ * - MAX77693_CABLE_GROUP_ADC_GND
+ * - MAX77693_CABLE_GROUP_CHG
+ * - MAX77693_CABLE_GROUP_VBVOLT
+ */
+static int max77693_muic_get_cable_type(struct max77693_muic_info *info,
+ enum max77693_muic_cable_group group, bool *attached)
{
- int ret = 0;
- int type;
- int adc, adc1k, adclow;
+ int cable_type = 0;
+ int adc;
+ int adc1k;
+ int adclow;
+ int vbvolt;
+ int chg_type;
+
+ switch (group) {
+ case MAX77693_CABLE_GROUP_ADC:
+ /*
+ * Read ADC value to check cable type and decide cable state
+ * according to cable type
+ */
+ adc = info->status[0] & STATUS1_ADC_MASK;
+ adc >>= STATUS1_ADC_SHIFT;
+
+ /*
+ * Check current cable state/cable type and store cable type
+ * (info->prev_cable_type) for handling cable when cable is
+ * detached.
+ */
+ if (adc == MAX77693_MUIC_ADC_OPEN) {
+ *attached = false;
+
+ cable_type = info->prev_cable_type;
+ info->prev_cable_type = MAX77693_MUIC_ADC_OPEN;
+ } else {
+ *attached = true;
+
+ cable_type = info->prev_cable_type = adc;
+ }
+ break;
+ case MAX77693_CABLE_GROUP_ADC_GND:
+ /*
+ * Read ADC value to check cable type and decide cable state
+ * according to cable type
+ */
+ adc = info->status[0] & STATUS1_ADC_MASK;
+ adc >>= STATUS1_ADC_SHIFT;
+
+ /*
+ * Check current cable state/cable type and store cable type
+ * (info->prev_cable_type/_gnd) for handling cable when cable
+ * is detached.
+ */
+ if (adc == MAX77693_MUIC_ADC_OPEN) {
+ *attached = false;
+
+ cable_type = info->prev_cable_type_gnd;
+ info->prev_cable_type_gnd = MAX77693_MUIC_ADC_OPEN;
+ } else {
+ *attached = true;
+
+ adclow = info->status[0] & STATUS1_ADCLOW_MASK;
+ adclow >>= STATUS1_ADCLOW_SHIFT;
+ adc1k = info->status[0] & STATUS1_ADC1K_MASK;
+ adc1k >>= STATUS1_ADC1K_SHIFT;
+
+ vbvolt = info->status[1] & STATUS2_VBVOLT_MASK;
+ vbvolt >>= STATUS2_VBVOLT_SHIFT;
+
+ /**
+ * [0x1][VBVolt][ADCLow][ADC1K]
+ * [0x1 0 0 0 ] : USB_OTG
+ * [0x1 1 0 0 ] : USB_OTG_VB
+ * [0x1 0 1 0 ] : Audio Video Cable with load
+ * [0x1 0 1 1 ] : MHL without charging connector
+ * [0x1 1 1 1 ] : MHL with charging connector
+ */
+ cable_type = ((0x1 << 8)
+ | (vbvolt << 2)
+ | (adclow << 1)
+ | adc1k);
+
+ info->prev_cable_type = adc;
+ info->prev_cable_type_gnd = cable_type;
+ }
- if (attached) {
+ break;
+ case MAX77693_CABLE_GROUP_CHG:
+ /*
+ * Read charger type to check cable type and decide cable state
+ * according to type of charger cable.
+ */
+ chg_type = info->status[1] & STATUS2_CHGTYP_MASK;
+ chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+ if (chg_type == MAX77693_CHARGER_TYPE_NONE) {
+ *attached = false;
+
+ cable_type = info->prev_chg_type;
+ info->prev_chg_type = MAX77693_CHARGER_TYPE_NONE;
+ } else {
+ *attached = true;
+
+ /*
+ * Check current cable state/cable type and store cable
+ * type(info->prev_chg_type) for handling cable when
+ * charger cable is detached.
+ */
+ cable_type = info->prev_chg_type = chg_type;
+ }
+
+ break;
+ case MAX77693_CABLE_GROUP_VBVOLT:
+ /*
+ * Read ADC value to check cable type and decide cable state
+ * according to cable type
+ */
adc = info->status[0] & STATUS1_ADC_MASK;
- adclow = info->status[0] & STATUS1_ADCLOW_MASK;
- adclow >>= STATUS1_ADCLOW_SHIFT;
- adc1k = info->status[0] & STATUS1_ADC1K_MASK;
- adc1k >>= STATUS1_ADC1K_SHIFT;
-
- /**
- * [0x1][ADCLow][ADC1K]
- * [0x1 0 0 ] : USB_OTG
- * [0x1 1 0 ] : Audio Video Cable with load
- * [0x1 1 1 ] : MHL
+ adc >>= STATUS1_ADC_SHIFT;
+ chg_type = info->status[1] & STATUS2_CHGTYP_MASK;
+ chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+ if (adc == MAX77693_MUIC_ADC_OPEN
+ && chg_type == MAX77693_CHARGER_TYPE_NONE)
+ *attached = false;
+ else
+ *attached = true;
+
+ /*
+ * Read vbvolt field, if vbvolt is 1,
+ * this cable is used for charging.
+ */
+ vbvolt = info->status[1] & STATUS2_VBVOLT_MASK;
+ vbvolt >>= STATUS2_VBVOLT_SHIFT;
+
+ cable_type = vbvolt;
+ break;
+ default:
+ dev_err(info->dev, "Unknown cable group (%d)\n", group);
+ cable_type = -EINVAL;
+ break;
+ }
+
+ return cable_type;
+}
+
+static int max77693_muic_dock_handler(struct max77693_muic_info *info,
+ int cable_type, bool attached)
+{
+ int ret = 0;
+ int vbvolt;
+ bool cable_attached;
+ char dock_name[CABLE_NAME_MAX];
+
+ dev_info(info->dev,
+ "external connector is %s (adc:0x%02x)\n",
+ attached ? "attached" : "detached", cable_type);
+
+ switch (cable_type) {
+ case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */
+ /*
+ * Check power cable whether attached or detached state.
+ * The Dock-Smart device need surely external power supply.
+ * If power cable(USB/TA) isn't connected to Dock device,
+ * user can't use Dock-Smart for desktop mode.
+ */
+ vbvolt = max77693_muic_get_cable_type(info,
+ MAX77693_CABLE_GROUP_VBVOLT, &cable_attached);
+ if (attached && !vbvolt) {
+ dev_warn(info->dev,
+ "Cannot detect external power supply\n");
+ return 0;
+ }
+
+ /*
+ * Notify Dock-Smart/MHL state.
+ * - Dock-Smart device include three type of cable which
+ * are HDMI, USB for mouse/keyboard and micro-usb port
+ * for USB/TA cable. Dock-Smart device need always exteranl
+ * power supply(USB/TA cable through micro-usb cable). Dock-
+ * Smart device support screen output of target to separate
+ * monitor and mouse/keyboard for desktop mode.
+ *
+ * Features of 'USB/TA cable with Dock-Smart device'
+ * - Support MHL
+ * - Support external output feature of audio
+ * - Support charging through micro-usb port without data
+ * connection if TA cable is connected to target.
+ * - Support charging and data connection through micro-usb port
+ * if USB cable is connected between target and host
+ * device.
+ * - Support OTG device (Mouse/Keyboard)
*/
- type = ((0x1 << 8) | (adclow << 1) | adc1k);
+ ret = max77693_muic_set_path(info, info->path_usb, attached);
+ if (ret < 0)
+ return ret;
+
+ extcon_set_cable_state(info->edev, "Dock-Smart", attached);
+ extcon_set_cable_state(info->edev, "MHL", attached);
+ goto out;
+ case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* Dock-Car */
+ strcpy(dock_name, "Dock-Car");
+ break;
+ case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */
+ strcpy(dock_name, "Dock-Desk");
+ break;
+ case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
+ strcpy(dock_name, "Dock-Audio");
+ if (!attached)
+ extcon_set_cable_state(info->edev, "USB", false);
+ break;
+ default:
+ dev_err(info->dev, "failed to detect %s dock device\n",
+ attached ? "attached" : "detached");
+ return -EINVAL;
+ }
+
+ /* Dock-Car/Desk/Audio, PATH:AUDIO */
+ ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
+ if (ret < 0)
+ return ret;
+ extcon_set_cable_state(info->edev, dock_name, attached);
+
+out:
+ return 0;
+}
+
+static int max77693_muic_dock_button_handler(struct max77693_muic_info *info,
+ int button_type, bool attached)
+{
+ struct input_dev *dock = info->dock;
+ unsigned int code;
+
+ switch (button_type) {
+ case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON-1
+ ... MAX77693_MUIC_ADC_REMOTE_S3_BUTTON+1:
+ /* DOCK_KEY_PREV */
+ code = KEY_PREVIOUSSONG;
+ break;
+ case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON-1
+ ... MAX77693_MUIC_ADC_REMOTE_S7_BUTTON+1:
+ /* DOCK_KEY_NEXT */
+ code = KEY_NEXTSONG;
+ break;
+ case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON:
+ /* DOCK_VOL_DOWN */
+ code = KEY_VOLUMEDOWN;
+ break;
+ case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON:
+ /* DOCK_VOL_UP */
+ code = KEY_VOLUMEUP;
+ break;
+ case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON-1
+ ... MAX77693_MUIC_ADC_REMOTE_S12_BUTTON+1:
+ /* DOCK_KEY_PLAY_PAUSE */
+ code = KEY_PLAYPAUSE;
+ break;
+ default:
+ dev_err(info->dev,
+ "failed to detect %s key (adc:0x%x)\n",
+ attached ? "pressed" : "released", button_type);
+ return -EINVAL;
+ }
+
+ input_event(dock, EV_KEY, code, attached);
+ input_sync(dock);
+
+ return 0;
+}
- /* Store previous ADC value to handle accessory
- when accessory will be detached */
- info->prev_adc = adc;
- info->prev_adc_gnd = type;
- } else
- type = info->prev_adc_gnd;
+static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
+{
+ int cable_type_gnd;
+ int ret = 0;
+ bool attached;
- switch (type) {
+ cable_type_gnd = max77693_muic_get_cable_type(info,
+ MAX77693_CABLE_GROUP_ADC_GND, &attached);
+
+ switch (cable_type_gnd) {
case MAX77693_MUIC_GND_USB_OTG:
- /* USB_OTG */
+ case MAX77693_MUIC_GND_USB_OTG_VB:
+ /* USB_OTG, PATH: AP_USB */
ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached);
if (ret < 0)
- goto out;
+ return ret;
extcon_set_cable_state(info->edev, "USB-Host", attached);
break;
case MAX77693_MUIC_GND_AV_CABLE_LOAD:
- /* Audio Video Cable with load */
+ /* Audio Video Cable with load, PATH:AUDIO */
ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
if (ret < 0)
- goto out;
+ return ret;
extcon_set_cable_state(info->edev,
"Audio-video-load", attached);
break;
- case MAX77693_MUIC_GND_MHL_CABLE:
- /* MHL */
+ case MAX77693_MUIC_GND_MHL:
+ case MAX77693_MUIC_GND_MHL_VB:
+ /* MHL or MHL with USB/TA cable */
extcon_set_cable_state(info->edev, "MHL", attached);
break;
default:
- dev_err(info->dev, "failed to detect %s accessory\n",
+ dev_err(info->dev, "failed to detect %s cable of gnd type\n",
attached ? "attached" : "detached");
- dev_err(info->dev, "- adc:0x%x, adclow:0x%x, adc1k:0x%x\n",
- adc, adclow, adc1k);
- ret = -EINVAL;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int max77693_muic_jig_handler(struct max77693_muic_info *info,
+ int cable_type, bool attached)
+{
+ char cable_name[32];
+ int ret = 0;
+ u8 path = CONTROL1_SW_OPEN;
+
+ dev_info(info->dev,
+ "external connector is %s (adc:0x%02x)\n",
+ attached ? "attached" : "detached", cable_type);
+
+ switch (cable_type) {
+ case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */
+ /* PATH:AP_USB */
+ strcpy(cable_name, "JIG-USB-OFF");
+ path = CONTROL1_SW_USB;
+ break;
+ case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */
+ /* PATH:AP_USB */
+ strcpy(cable_name, "JIG-USB-ON");
+ path = CONTROL1_SW_USB;
break;
+ case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */
+ /* PATH:AP_UART */
+ strcpy(cable_name, "JIG-UART-OFF");
+ path = CONTROL1_SW_UART;
+ break;
+ default:
+ dev_err(info->dev, "failed to detect %s jig cable\n",
+ attached ? "attached" : "detached");
+ return -EINVAL;
}
-out:
- return ret;
+ ret = max77693_muic_set_path(info, path, attached);
+ if (ret < 0)
+ return ret;
+
+ extcon_set_cable_state(info->edev, cable_name, attached);
+
+ return 0;
}
-static int max77693_muic_adc_handler(struct max77693_muic_info *info,
- int curr_adc, bool attached)
+static int max77693_muic_adc_handler(struct max77693_muic_info *info)
{
+ int cable_type;
+ int button_type;
+ bool attached;
int ret = 0;
- int adc;
- if (attached) {
- /* Store ADC value to handle accessory
- when accessory will be detached */
- info->prev_adc = curr_adc;
- adc = curr_adc;
- } else
- adc = info->prev_adc;
+ /* Check accessory state which is either detached or attached */
+ cable_type = max77693_muic_get_cable_type(info,
+ MAX77693_CABLE_GROUP_ADC, &attached);
dev_info(info->dev,
"external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
- attached ? "attached" : "detached", curr_adc, info->prev_adc);
+ attached ? "attached" : "detached", cable_type,
+ info->prev_cable_type);
- switch (adc) {
+ switch (cable_type) {
case MAX77693_MUIC_ADC_GROUND:
/* USB_OTG/MHL/Audio */
- max77693_muic_adc_ground_handler(info, attached);
+ max77693_muic_adc_ground_handler(info);
break;
case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF:
case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON:
- /* USB */
- ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached);
- if (ret < 0)
- goto out;
- extcon_set_cable_state(info->edev, "USB", attached);
- break;
case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF:
- case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON:
/* JIG */
- ret = max77693_muic_set_path(info, CONTROL1_SW_UART, attached);
+ ret = max77693_muic_jig_handler(info, cable_type, attached);
if (ret < 0)
- goto out;
- extcon_set_cable_state(info->edev, "JIG", attached);
+ return ret;
break;
- case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE:
- /* Audio Video cable with no-load */
- ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
+ case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */
+ case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* Dock-Car */
+ case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */
+ case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
+ /*
+ * DOCK device
+ *
+ * The MAX77693 MUIC device can detect total 34 cable type
+ * except of charger cable and MUIC device didn't define
+ * specfic role of cable in the range of from 0x01 to 0x12
+ * of ADC value. So, can use/define cable with no role according
+ * to schema of hardware board.
+ */
+ ret = max77693_muic_dock_handler(info, cable_type, attached);
if (ret < 0)
- goto out;
- extcon_set_cable_state(info->edev,
- "Audio-video-noload", attached);
+ return ret;
+ break;
+ case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON: /* DOCK_KEY_PREV */
+ case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON: /* DOCK_KEY_NEXT */
+ case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON: /* DOCK_VOL_DOWN */
+ case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON: /* DOCK_VOL_UP */
+ case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON: /* DOCK_KEY_PLAY_PAUSE */
+ /*
+ * Button of DOCK device
+ * - the Prev/Next/Volume Up/Volume Down/Play-Pause button
+ *
+ * The MAX77693 MUIC device can detect total 34 cable type
+ * except of charger cable and MUIC device didn't define
+ * specfic role of cable in the range of from 0x01 to 0x12
+ * of ADC value. So, can use/define cable with no role according
+ * to schema of hardware board.
+ */
+ if (attached)
+ button_type = info->prev_button_type = cable_type;
+ else
+ button_type = info->prev_button_type;
+
+ ret = max77693_muic_dock_button_handler(info, button_type,
+ attached);
+ if (ret < 0)
+ return ret;
break;
case MAX77693_MUIC_ADC_SEND_END_BUTTON:
case MAX77693_MUIC_ADC_REMOTE_S1_BUTTON:
case MAX77693_MUIC_ADC_REMOTE_S2_BUTTON:
- case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON:
case MAX77693_MUIC_ADC_REMOTE_S4_BUTTON:
case MAX77693_MUIC_ADC_REMOTE_S5_BUTTON:
case MAX77693_MUIC_ADC_REMOTE_S6_BUTTON:
- case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON:
case MAX77693_MUIC_ADC_REMOTE_S8_BUTTON:
- case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON:
- case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON:
case MAX77693_MUIC_ADC_REMOTE_S11_BUTTON:
- case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON:
case MAX77693_MUIC_ADC_RESERVED_ACC_1:
case MAX77693_MUIC_ADC_RESERVED_ACC_2:
- case MAX77693_MUIC_ADC_RESERVED_ACC_3:
case MAX77693_MUIC_ADC_RESERVED_ACC_4:
case MAX77693_MUIC_ADC_RESERVED_ACC_5:
case MAX77693_MUIC_ADC_CEA936_AUDIO:
@@ -432,60 +733,164 @@ static int max77693_muic_adc_handler(struct max77693_muic_info *info,
case MAX77693_MUIC_ADC_TTY_CONVERTER:
case MAX77693_MUIC_ADC_UART_CABLE:
case MAX77693_MUIC_ADC_CEA936A_TYPE1_CHG:
- case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD:
case MAX77693_MUIC_ADC_CEA936A_TYPE2_CHG:
- /* This accessory isn't used in general case if it is specially
- needed to detect additional accessory, should implement
- proper operation when this accessory is attached/detached. */
+ /*
+ * This accessory isn't used in general case if it is specially
+ * needed to detect additional accessory, should implement
+ * proper operation when this accessory is attached/detached.
+ */
dev_info(info->dev,
"accessory is %s but it isn't used (adc:0x%x)\n",
- attached ? "attached" : "detached", adc);
- goto out;
+ attached ? "attached" : "detached", cable_type);
+ return -EAGAIN;
default:
dev_err(info->dev,
"failed to detect %s accessory (adc:0x%x)\n",
- attached ? "attached" : "detached", adc);
- ret = -EINVAL;
- goto out;
+ attached ? "attached" : "detached", cable_type);
+ return -EINVAL;
}
-out:
- return ret;
+ return 0;
}
-static int max77693_muic_chg_handler(struct max77693_muic_info *info,
- int curr_chg_type, bool attached)
+static int max77693_muic_chg_handler(struct max77693_muic_info *info)
{
- int ret = 0;
int chg_type;
+ int cable_type_gnd;
+ int cable_type;
+ bool attached;
+ bool cable_attached;
+ int ret = 0;
- if (attached) {
- /* Store previous charger type to control
- when charger accessory will be detached */
- info->prev_chg_type = curr_chg_type;
- chg_type = curr_chg_type;
- } else
- chg_type = info->prev_chg_type;
+ chg_type = max77693_muic_get_cable_type(info,
+ MAX77693_CABLE_GROUP_CHG, &attached);
dev_info(info->dev,
"external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
attached ? "attached" : "detached",
- curr_chg_type, info->prev_chg_type);
+ chg_type, info->prev_chg_type);
switch (chg_type) {
case MAX77693_CHARGER_TYPE_USB:
- ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached);
- if (ret < 0)
- goto out;
- extcon_set_cable_state(info->edev, "USB", attached);
+ case MAX77693_CHARGER_TYPE_DEDICATED_CHG:
+ case MAX77693_CHARGER_TYPE_NONE:
+ /* Check MAX77693_CABLE_GROUP_ADC_GND type */
+ cable_type_gnd = max77693_muic_get_cable_type(info,
+ MAX77693_CABLE_GROUP_ADC_GND,
+ &cable_attached);
+ switch (cable_type_gnd) {
+ case MAX77693_MUIC_GND_MHL:
+ case MAX77693_MUIC_GND_MHL_VB:
+ /*
+ * MHL cable with MHL_TA(USB/TA) cable
+ * - MHL cable include two port(HDMI line and separate micro-
+ * usb port. When the target connect MHL cable, extcon driver
+ * check whether MHL_TA(USB/TA) cable is connected. If MHL_TA
+ * cable is connected, extcon driver notify state to notifiee
+ * for charging battery.
+ *
+ * Features of 'MHL_TA(USB/TA) with MHL cable'
+ * - Support MHL
+ * - Support charging through micro-usb port without data connection
+ */
+ extcon_set_cable_state(info->edev, "MHL_TA", attached);
+ if (!cable_attached)
+ extcon_set_cable_state(info->edev, "MHL", cable_attached);
+ break;
+ }
+
+ /* Check MAX77693_CABLE_GROUP_ADC type */
+ cable_type = max77693_muic_get_cable_type(info,
+ MAX77693_CABLE_GROUP_ADC,
+ &cable_attached);
+ switch (cable_type) {
+ case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
+ /*
+ * Dock-Audio device with USB/TA cable
+ * - Dock device include two port(Dock-Audio and micro-usb
+ * port). When the target connect Dock-Audio device, extcon
+ * driver check whether USB/TA cable is connected. If USB/TA
+ * cable is connected, extcon driver notify state to notifiee
+ * for charging battery.
+ *
+ * Features of 'USB/TA cable with Dock-Audio device'
+ * - Support external output feature of audio.
+ * - Support charging through micro-usb port without data
+ * connection.
+ */
+ extcon_set_cable_state(info->edev, "USB", attached);
+
+ if (!cable_attached)
+ extcon_set_cable_state(info->edev, "Dock-Audio", cable_attached);
+ break;
+ case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */
+ /*
+ * Dock-Smart device with USB/TA cable
+ * - Dock-Desk device include three type of cable which
+ * are HDMI, USB for mouse/keyboard and micro-usb port
+ * for USB/TA cable. Dock-Smart device need always exteranl
+ * power supply(USB/TA cable through micro-usb cable). Dock-
+ * Smart device support screen output of target to separate
+ * monitor and mouse/keyboard for desktop mode.
+ *
+ * Features of 'USB/TA cable with Dock-Smart device'
+ * - Support MHL
+ * - Support external output feature of audio
+ * - Support charging through micro-usb port without data
+ * connection if TA cable is connected to target.
+ * - Support charging and data connection through micro-usb port
+ * if USB cable is connected between target and host
+ * device.
+ * - Support OTG device (Mouse/Keyboard)
+ */
+ ret = max77693_muic_set_path(info, info->path_usb, attached);
+ if (ret < 0)
+ return ret;
+
+ extcon_set_cable_state(info->edev, "Dock-Smart", attached);
+ extcon_set_cable_state(info->edev, "MHL", attached);
+
+ break;
+ }
+
+ /* Check MAX77693_CABLE_GROUP_CHG type */
+ switch (chg_type) {
+ case MAX77693_CHARGER_TYPE_NONE:
+ /*
+ * When MHL(with USB/TA cable) or Dock-Audio with USB/TA cable
+ * is attached, muic device happen below two interrupt.
+ * - 'MAX77693_MUIC_IRQ_INT1_ADC' for detecting MHL/Dock-Audio.
+ * - 'MAX77693_MUIC_IRQ_INT2_CHGTYP' for detecting USB/TA cable
+ * connected to MHL or Dock-Audio.
+ * Always, happen eariler MAX77693_MUIC_IRQ_INT1_ADC interrupt
+ * than MAX77693_MUIC_IRQ_INT2_CHGTYP interrupt.
+ *
+ * If user attach MHL (with USB/TA cable and immediately detach
+ * MHL with USB/TA cable before MAX77693_MUIC_IRQ_INT2_CHGTYP
+ * interrupt is happened, USB/TA cable remain connected state to
+ * target. But USB/TA cable isn't connected to target. The user
+ * be face with unusual action. So, driver should check this
+ * situation in spite of, that previous charger type is N/A.
+ */
+ break;
+ case MAX77693_CHARGER_TYPE_USB:
+ /* Only USB cable, PATH:AP_USB */
+ ret = max77693_muic_set_path(info, info->path_usb, attached);
+ if (ret < 0)
+ return ret;
+
+ extcon_set_cable_state(info->edev, "USB", attached);
+ break;
+ case MAX77693_CHARGER_TYPE_DEDICATED_CHG:
+ /* Only TA cable */
+ extcon_set_cable_state(info->edev, "TA", attached);
+ break;
+ }
break;
case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT:
extcon_set_cable_state(info->edev,
"Charge-downstream", attached);
break;
- case MAX77693_CHARGER_TYPE_DEDICATED_CHG:
- extcon_set_cable_state(info->edev, "TA", attached);
- break;
case MAX77693_CHARGER_TYPE_APPLE_500MA:
extcon_set_cable_state(info->edev, "Slow-charger", attached);
break;
@@ -498,22 +903,18 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info,
dev_err(info->dev,
"failed to detect %s accessory (chg_type:0x%x)\n",
attached ? "attached" : "detached", chg_type);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
-out:
- return ret;
+ return 0;
}
static void max77693_muic_irq_work(struct work_struct *work)
{
struct max77693_muic_info *info = container_of(work,
struct max77693_muic_info, irq_work);
- int curr_adc, curr_chg_type;
int irq_type = -1;
int i, ret = 0;
- bool attached = true;
if (!info->edev)
return;
@@ -539,14 +940,7 @@ static void max77693_muic_irq_work(struct work_struct *work)
case MAX77693_MUIC_IRQ_INT1_ADC1K:
/* Handle all of accessory except for
type of charger accessory */
- curr_adc = info->status[0] & STATUS1_ADC_MASK;
- curr_adc >>= STATUS1_ADC_SHIFT;
-
- /* Check accessory state which is either detached or attached */
- if (curr_adc == MAX77693_MUIC_ADC_OPEN)
- attached = false;
-
- ret = max77693_muic_adc_handler(info, curr_adc, attached);
+ ret = max77693_muic_adc_handler(info);
break;
case MAX77693_MUIC_IRQ_INT2_CHGTYP:
case MAX77693_MUIC_IRQ_INT2_CHGDETREUN:
@@ -555,15 +949,7 @@ static void max77693_muic_irq_work(struct work_struct *work)
case MAX77693_MUIC_IRQ_INT2_VBVOLT:
case MAX77693_MUIC_IRQ_INT2_VIDRM:
/* Handle charger accessory */
- curr_chg_type = info->status[1] & STATUS2_CHGTYP_MASK;
- curr_chg_type >>= STATUS2_CHGTYP_SHIFT;
-
- /* Check charger accessory state which
- is either detached or attached */
- if (curr_chg_type == MAX77693_CHARGER_TYPE_NONE)
- attached = false;
-
- ret = max77693_muic_chg_handler(info, curr_chg_type, attached);
+ ret = max77693_muic_chg_handler(info);
break;
case MAX77693_MUIC_IRQ_INT3_EOC:
case MAX77693_MUIC_IRQ_INT3_CGMBC:
@@ -575,7 +961,8 @@ static void max77693_muic_irq_work(struct work_struct *work)
default:
dev_err(info->dev, "muic interrupt: irq %d occurred\n",
irq_type);
- break;
+ mutex_unlock(&info->mutex);
+ return;
}
if (ret < 0)
@@ -604,7 +991,9 @@ static struct regmap_config max77693_muic_regmap_config = {
static int max77693_muic_detect_accessory(struct max77693_muic_info *info)
{
int ret = 0;
- int adc, chg_type;
+ int adc;
+ int chg_type;
+ bool attached;
mutex_lock(&info->mutex);
@@ -617,35 +1006,39 @@ static int max77693_muic_detect_accessory(struct max77693_muic_info *info)
return -EINVAL;
}
- adc = info->status[0] & STATUS1_ADC_MASK;
- adc >>= STATUS1_ADC_SHIFT;
-
- if (adc != MAX77693_MUIC_ADC_OPEN) {
- dev_info(info->dev,
- "external connector is attached (adc:0x%02x)\n", adc);
+ adc = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC,
+ &attached);
+ if (attached && adc != MAX77693_MUIC_ADC_OPEN) {
+ ret = max77693_muic_adc_handler(info);
+ if (ret < 0) {
+ dev_err(info->dev, "Cannot detect accessory\n");
+ mutex_unlock(&info->mutex);
+ return ret;
+ }
+ }
- ret = max77693_muic_adc_handler(info, adc, true);
- if (ret < 0)
- dev_err(info->dev, "failed to detect accessory\n");
- goto out;
+ chg_type = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_CHG,
+ &attached);
+ if (attached && chg_type != MAX77693_CHARGER_TYPE_NONE) {
+ ret = max77693_muic_chg_handler(info);
+ if (ret < 0) {
+ dev_err(info->dev, "Cannot detect charger accessory\n");
+ mutex_unlock(&info->mutex);
+ return ret;
+ }
}
- chg_type = info->status[1] & STATUS2_CHGTYP_MASK;
- chg_type >>= STATUS2_CHGTYP_SHIFT;
+ mutex_unlock(&info->mutex);
- if (chg_type != MAX77693_CHARGER_TYPE_NONE) {
- dev_info(info->dev,
- "external connector is attached (chg_type:0x%x)\n",
- chg_type);
+ return 0;
+}
- max77693_muic_chg_handler(info, chg_type, true);
- if (ret < 0)
- dev_err(info->dev, "failed to detect charger accessory\n");
- }
+static void max77693_muic_detect_cable_wq(struct work_struct *work)
+{
+ struct max77693_muic_info *info = container_of(to_delayed_work(work),
+ struct max77693_muic_info, wq_detcable);
-out:
- mutex_unlock(&info->mutex);
- return ret;
+ max77693_muic_detect_accessory(info);
}
static int max77693_muic_probe(struct platform_device *pdev)
@@ -654,7 +1047,9 @@ static int max77693_muic_probe(struct platform_device *pdev)
struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev);
struct max77693_muic_platform_data *muic_pdata = pdata->muic_data;
struct max77693_muic_info *info;
- int ret, i;
+ int delay_jiffies;
+ int ret;
+ int i;
u8 id;
info = devm_kzalloc(&pdev->dev, sizeof(struct max77693_muic_info),
@@ -678,6 +1073,32 @@ static int max77693_muic_probe(struct platform_device *pdev)
return ret;
}
}
+
+ /* Register input device for button of dock device */
+ info->dock = devm_input_allocate_device(&pdev->dev);
+ if (!info->dock) {
+ dev_err(&pdev->dev, "%s: failed to allocate input\n", __func__);
+ return -ENOMEM;
+ }
+ info->dock->name = "max77693-muic/dock";
+ info->dock->phys = "max77693-muic/extcon";
+ info->dock->dev.parent = &pdev->dev;
+
+ __set_bit(EV_REP, info->dock->evbit);
+
+ input_set_capability(info->dock, EV_KEY, KEY_VOLUMEUP);
+ input_set_capability(info->dock, EV_KEY, KEY_VOLUMEDOWN);
+ input_set_capability(info->dock, EV_KEY, KEY_PLAYPAUSE);
+ input_set_capability(info->dock, EV_KEY, KEY_PREVIOUSSONG);
+ input_set_capability(info->dock, EV_KEY, KEY_NEXTSONG);
+
+ ret = input_register_device(info->dock);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Cannot register input device error(%d)\n",
+ ret);
+ return ret;
+ }
+
platform_set_drvdata(pdev, info);
mutex_init(&info->mutex);
@@ -697,13 +1118,13 @@ static int max77693_muic_probe(struct platform_device *pdev)
ret = request_threaded_irq(virq, NULL,
max77693_muic_irq_handler,
- IRQF_ONESHOT, muic_irq->name, info);
+ IRQF_NO_SUSPEND,
+ muic_irq->name, info);
if (ret) {
dev_err(&pdev->dev,
"failed: irq request (IRQ: %d,"
" error :%d)\n",
muic_irq->irq, ret);
-
goto err_irq;
}
}
@@ -749,23 +1170,54 @@ static int max77693_muic_probe(struct platform_device *pdev)
= muic_pdata->init_data[i].data;
}
+ /*
+ * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
+ * h/w path of COMP2/COMN1 on CONTROL1 register.
+ */
+ if (muic_pdata->path_uart)
+ info->path_uart = muic_pdata->path_uart;
+ else
+ info->path_uart = CONTROL1_SW_UART;
+
+ if (muic_pdata->path_usb)
+ info->path_usb = muic_pdata->path_usb;
+ else
+ info->path_usb = CONTROL1_SW_USB;
+
+ /* Set initial path for UART */
+ max77693_muic_set_path(info, info->path_uart, true);
+
/* Check revision number of MUIC device*/
ret = max77693_read_reg(info->max77693->regmap_muic,
MAX77693_MUIC_REG_ID, &id);
if (ret < 0) {
dev_err(&pdev->dev, "failed to read revision number\n");
- goto err_irq;
+ goto err_extcon;
}
dev_info(info->dev, "device ID : 0x%x\n", id);
/* Set ADC debounce time */
max77693_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS);
- /* Detect accessory on boot */
- max77693_muic_detect_accessory(info);
+ /*
+ * Detect accessory after completing the initialization of platform
+ *
+ * - Use delayed workqueue to detect cable state and then
+ * notify cable state to notifiee/platform through uevent.
+ * After completing the booting of platform, the extcon provider
+ * driver should notify cable state to upper layer.
+ */
+ INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq);
+ if (muic_pdata->detcable_delay_ms)
+ delay_jiffies = msecs_to_jiffies(muic_pdata->detcable_delay_ms);
+ else
+ delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+ schedule_delayed_work(&info->wq_detcable, delay_jiffies);
return ret;
+err_extcon:
+ extcon_dev_unregister(info->edev);
err_irq:
while (--i >= 0)
free_irq(muic_irqs[i].virq, info);
@@ -780,6 +1232,7 @@ static int max77693_muic_remove(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
free_irq(muic_irqs[i].virq, info);
cancel_work_sync(&info->irq_work);
+ input_unregister_device(info->dock);
extcon_dev_unregister(info->edev);
return 0;
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
index 93009fe6ef05..e636d950ad6c 100644
--- a/drivers/extcon/extcon-max8997.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -29,51 +29,14 @@
#include <linux/irqdomain.h>
#define DEV_NAME "max8997-muic"
+#define DELAY_MS_DEFAULT 20000 /* unit: millisecond */
-/* MAX8997-MUIC STATUS1 register */
-#define STATUS1_ADC_SHIFT 0
-#define STATUS1_ADCLOW_SHIFT 5
-#define STATUS1_ADCERR_SHIFT 6
-#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT)
-#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT)
-#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT)
-
-/* MAX8997-MUIC STATUS2 register */
-#define STATUS2_CHGTYP_SHIFT 0
-#define STATUS2_CHGDETRUN_SHIFT 3
-#define STATUS2_DCDTMR_SHIFT 4
-#define STATUS2_DBCHG_SHIFT 5
-#define STATUS2_VBVOLT_SHIFT 6
-#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT)
-#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT)
-#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT)
-#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT)
-#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT)
-
-/* MAX8997-MUIC STATUS3 register */
-#define STATUS3_OVP_SHIFT 2
-#define STATUS3_OVP_MASK (0x1 << STATUS3_OVP_SHIFT)
-
-/* MAX8997-MUIC CONTROL1 register */
-#define COMN1SW_SHIFT 0
-#define COMP2SW_SHIFT 3
-#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT)
-#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT)
-#define SW_MASK (COMP2SW_MASK | COMN1SW_MASK)
-
-#define MAX8997_SW_USB ((1 << COMP2SW_SHIFT) | (1 << COMN1SW_SHIFT))
-#define MAX8997_SW_AUDIO ((2 << COMP2SW_SHIFT) | (2 << COMN1SW_SHIFT))
-#define MAX8997_SW_UART ((3 << COMP2SW_SHIFT) | (3 << COMN1SW_SHIFT))
-#define MAX8997_SW_OPEN ((0 << COMP2SW_SHIFT) | (0 << COMN1SW_SHIFT))
-
-#define MAX8997_ADC_GROUND 0x00
-#define MAX8997_ADC_MHL 0x01
-#define MAX8997_ADC_JIG_USB_1 0x18
-#define MAX8997_ADC_JIG_USB_2 0x19
-#define MAX8997_ADC_DESKDOCK 0x1a
-#define MAX8997_ADC_JIG_UART 0x1c
-#define MAX8997_ADC_CARDOCK 0x1d
-#define MAX8997_ADC_OPEN 0x1f
+enum max8997_muic_adc_debounce_time {
+ ADC_DEBOUNCE_TIME_0_5MS = 0, /* 0.5ms */
+ ADC_DEBOUNCE_TIME_10MS, /* 10ms */
+ ADC_DEBOUNCE_TIME_25MS, /* 25ms */
+ ADC_DEBOUNCE_TIME_38_62MS, /* 38.62ms */
+};
struct max8997_muic_irq {
unsigned int irq;
@@ -82,61 +45,303 @@ struct max8997_muic_irq {
};
static struct max8997_muic_irq muic_irqs[] = {
- { MAX8997_MUICIRQ_ADCError, "muic-ADC_error" },
- { MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" },
- { MAX8997_MUICIRQ_ADC, "muic-ADC" },
- { MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" },
- { MAX8997_MUICIRQ_DBChg, "muic-DB_charger" },
- { MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" },
- { MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" },
- { MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" },
- { MAX8997_MUICIRQ_OVP, "muic-over_voltage" },
+ { MAX8997_MUICIRQ_ADCError, "muic-ADCERROR" },
+ { MAX8997_MUICIRQ_ADCLow, "muic-ADCLOW" },
+ { MAX8997_MUICIRQ_ADC, "muic-ADC" },
+ { MAX8997_MUICIRQ_VBVolt, "muic-VBVOLT" },
+ { MAX8997_MUICIRQ_DBChg, "muic-DBCHG" },
+ { MAX8997_MUICIRQ_DCDTmr, "muic-DCDTMR" },
+ { MAX8997_MUICIRQ_ChgDetRun, "muic-CHGDETRUN" },
+ { MAX8997_MUICIRQ_ChgTyp, "muic-CHGTYP" },
+ { MAX8997_MUICIRQ_OVP, "muic-OVP" },
+};
+
+/* Define supported cable type */
+enum max8997_muic_acc_type {
+ MAX8997_MUIC_ADC_GROUND = 0x0,
+ MAX8997_MUIC_ADC_MHL, /* MHL*/
+ MAX8997_MUIC_ADC_REMOTE_S1_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S2_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S3_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S4_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S5_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S6_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S7_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S8_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S9_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S10_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S11_BUTTON,
+ MAX8997_MUIC_ADC_REMOTE_S12_BUTTON,
+ MAX8997_MUIC_ADC_RESERVED_ACC_1,
+ MAX8997_MUIC_ADC_RESERVED_ACC_2,
+ MAX8997_MUIC_ADC_RESERVED_ACC_3,
+ MAX8997_MUIC_ADC_RESERVED_ACC_4,
+ MAX8997_MUIC_ADC_RESERVED_ACC_5,
+ MAX8997_MUIC_ADC_CEA936_AUDIO,
+ MAX8997_MUIC_ADC_PHONE_POWERED_DEV,
+ MAX8997_MUIC_ADC_TTY_CONVERTER,
+ MAX8997_MUIC_ADC_UART_CABLE,
+ MAX8997_MUIC_ADC_CEA936A_TYPE1_CHG,
+ MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF, /* JIG-USB-OFF */
+ MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON, /* JIG-USB-ON */
+ MAX8997_MUIC_ADC_AV_CABLE_NOLOAD, /* DESKDOCK */
+ MAX8997_MUIC_ADC_CEA936A_TYPE2_CHG,
+ MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF, /* JIG-UART */
+ MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON, /* CARDOCK */
+ MAX8997_MUIC_ADC_AUDIO_MODE_REMOTE,
+ MAX8997_MUIC_ADC_OPEN, /* OPEN */
+};
+
+enum max8997_muic_cable_group {
+ MAX8997_CABLE_GROUP_ADC = 0,
+ MAX8997_CABLE_GROUP_ADC_GND,
+ MAX8997_CABLE_GROUP_CHG,
+ MAX8997_CABLE_GROUP_VBVOLT,
+};
+
+enum max8997_muic_usb_type {
+ MAX8997_USB_HOST,
+ MAX8997_USB_DEVICE,
+};
+
+enum max8997_muic_charger_type {
+ MAX8997_CHARGER_TYPE_NONE = 0,
+ MAX8997_CHARGER_TYPE_USB,
+ MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT,
+ MAX8997_CHARGER_TYPE_DEDICATED_CHG,
+ MAX8997_CHARGER_TYPE_500MA,
+ MAX8997_CHARGER_TYPE_1A,
+ MAX8997_CHARGER_TYPE_DEAD_BATTERY = 7,
};
struct max8997_muic_info {
struct device *dev;
struct i2c_client *muic;
- struct max8997_muic_platform_data *muic_pdata;
+ struct extcon_dev *edev;
+ int prev_cable_type;
+ int prev_chg_type;
+ u8 status[2];
int irq;
struct work_struct irq_work;
+ struct mutex mutex;
+ struct max8997_muic_platform_data *muic_pdata;
enum max8997_muic_charger_type pre_charger_type;
- int pre_adc;
- struct mutex mutex;
+ /*
+ * Use delayed workqueue to detect cable state and then
+ * notify cable state to notifiee/platform through uevent.
+ * After completing the booting of platform, the extcon provider
+ * driver should notify cable state to upper layer.
+ */
+ struct delayed_work wq_detcable;
+
+ /*
+ * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
+ * h/w path of COMP2/COMN1 on CONTROL1 register.
+ */
+ int path_usb;
+ int path_uart;
+};
- struct extcon_dev *edev;
+enum {
+ EXTCON_CABLE_USB = 0,
+ EXTCON_CABLE_USB_HOST,
+ EXTCON_CABLE_TA,
+ EXTCON_CABLE_FAST_CHARGER,
+ EXTCON_CABLE_SLOW_CHARGER,
+ EXTCON_CABLE_CHARGE_DOWNSTREAM,
+ EXTCON_CABLE_MHL,
+ EXTCON_CABLE_DOCK_DESK,
+ EXTCON_CABLE_DOCK_CARD,
+ EXTCON_CABLE_JIG,
+
+ _EXTCON_CABLE_NUM,
};
-const char *max8997_extcon_cable[] = {
- [0] = "USB",
- [1] = "USB-Host",
- [2] = "TA",
- [3] = "Fast-charger",
- [4] = "Slow-charger",
- [5] = "Charge-downstream",
- [6] = "MHL",
- [7] = "Dock-desk",
- [8] = "Dock-card",
- [9] = "JIG",
+static const char *max8997_extcon_cable[] = {
+ [EXTCON_CABLE_USB] = "USB",
+ [EXTCON_CABLE_USB_HOST] = "USB-Host",
+ [EXTCON_CABLE_TA] = "TA",
+ [EXTCON_CABLE_FAST_CHARGER] = "Fast-charger",
+ [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
+ [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
+ [EXTCON_CABLE_MHL] = "MHL",
+ [EXTCON_CABLE_DOCK_DESK] = "Dock-Desk",
+ [EXTCON_CABLE_DOCK_CARD] = "Dock-Card",
+ [EXTCON_CABLE_JIG] = "JIG",
NULL,
};
+/*
+ * max8997_muic_set_debounce_time - Set the debounce time of ADC
+ * @info: the instance including private data of max8997 MUIC
+ * @time: the debounce time of ADC
+ */
+static int max8997_muic_set_debounce_time(struct max8997_muic_info *info,
+ enum max8997_muic_adc_debounce_time time)
+{
+ int ret;
+
+ switch (time) {
+ case ADC_DEBOUNCE_TIME_0_5MS:
+ case ADC_DEBOUNCE_TIME_10MS:
+ case ADC_DEBOUNCE_TIME_25MS:
+ case ADC_DEBOUNCE_TIME_38_62MS:
+ ret = max8997_update_reg(info->muic,
+ MAX8997_MUIC_REG_CONTROL3,
+ time << CONTROL3_ADCDBSET_SHIFT,
+ CONTROL3_ADCDBSET_MASK);
+ if (ret) {
+ dev_err(info->dev, "failed to set ADC debounce time\n");
+ return -EAGAIN;
+ }
+ break;
+ default:
+ dev_err(info->dev, "invalid ADC debounce time\n");
+ return -EINVAL;
+ }
+
+ return 0;
+};
+
+/*
+ * max8997_muic_set_path - Set hardware line according to attached cable
+ * @info: the instance including private data of max8997 MUIC
+ * @value: the path according to attached cable
+ * @attached: the state of cable (true:attached, false:detached)
+ *
+ * The max8997 MUIC device share outside H/W line among a varity of cables,
+ * so this function set internal path of H/W line according to the type of
+ * attached cable.
+ */
+static int max8997_muic_set_path(struct max8997_muic_info *info,
+ u8 val, bool attached)
+{
+ int ret = 0;
+ u8 ctrl1, ctrl2 = 0;
+
+ if (attached)
+ ctrl1 = val;
+ else
+ ctrl1 = CONTROL1_SW_OPEN;
+
+ ret = max8997_update_reg(info->muic,
+ MAX8997_MUIC_REG_CONTROL1, ctrl1, COMP_SW_MASK);
+ if (ret < 0) {
+ dev_err(info->dev, "failed to update MUIC register\n");
+ return -EAGAIN;
+ }
+
+ if (attached)
+ ctrl2 |= CONTROL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */
+ else
+ ctrl2 |= CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */
+
+ ret = max8997_update_reg(info->muic,
+ MAX8997_MUIC_REG_CONTROL2, ctrl2,
+ CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);
+ if (ret < 0) {
+ dev_err(info->dev, "failed to update MUIC register\n");
+ return -EAGAIN;
+ }
+
+ dev_info(info->dev,
+ "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
+ ctrl1, ctrl2, attached ? "attached" : "detached");
+
+ return 0;
+}
+
+/*
+ * max8997_muic_get_cable_type - Return cable type and check cable state
+ * @info: the instance including private data of max8997 MUIC
+ * @group: the path according to attached cable
+ * @attached: store cable state and return
+ *
+ * This function check the cable state either attached or detached,
+ * and then divide precise type of cable according to cable group.
+ * - MAX8997_CABLE_GROUP_ADC
+ * - MAX8997_CABLE_GROUP_CHG
+ */
+static int max8997_muic_get_cable_type(struct max8997_muic_info *info,
+ enum max8997_muic_cable_group group, bool *attached)
+{
+ int cable_type = 0;
+ int adc;
+ int chg_type;
+
+ switch (group) {
+ case MAX8997_CABLE_GROUP_ADC:
+ /*
+ * Read ADC value to check cable type and decide cable state
+ * according to cable type
+ */
+ adc = info->status[0] & STATUS1_ADC_MASK;
+ adc >>= STATUS1_ADC_SHIFT;
+
+ /*
+ * Check current cable state/cable type and store cable type
+ * (info->prev_cable_type) for handling cable when cable is
+ * detached.
+ */
+ if (adc == MAX8997_MUIC_ADC_OPEN) {
+ *attached = false;
+
+ cable_type = info->prev_cable_type;
+ info->prev_cable_type = MAX8997_MUIC_ADC_OPEN;
+ } else {
+ *attached = true;
+
+ cable_type = info->prev_cable_type = adc;
+ }
+ break;
+ case MAX8997_CABLE_GROUP_CHG:
+ /*
+ * Read charger type to check cable type and decide cable state
+ * according to type of charger cable.
+ */
+ chg_type = info->status[1] & STATUS2_CHGTYP_MASK;
+ chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+ if (chg_type == MAX8997_CHARGER_TYPE_NONE) {
+ *attached = false;
+
+ cable_type = info->prev_chg_type;
+ info->prev_chg_type = MAX8997_CHARGER_TYPE_NONE;
+ } else {
+ *attached = true;
+
+ /*
+ * Check current cable state/cable type and store cable
+ * type(info->prev_chg_type) for handling cable when
+ * charger cable is detached.
+ */
+ cable_type = info->prev_chg_type = chg_type;
+ }
+
+ break;
+ default:
+ dev_err(info->dev, "Unknown cable group (%d)\n", group);
+ cable_type = -EINVAL;
+ break;
+ }
+
+ return cable_type;
+}
+
static int max8997_muic_handle_usb(struct max8997_muic_info *info,
enum max8997_muic_usb_type usb_type, bool attached)
{
int ret = 0;
if (usb_type == MAX8997_USB_HOST) {
- /* switch to USB */
- ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
- attached ? MAX8997_SW_USB : MAX8997_SW_OPEN,
- SW_MASK);
- if (ret) {
+ ret = max8997_muic_set_path(info, info->path_usb, attached);
+ if (ret < 0) {
dev_err(info->dev, "failed to update muic register\n");
- goto out;
+ return ret;
}
}
@@ -148,41 +353,39 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info,
extcon_set_cable_state(info->edev, "USB", attached);
break;
default:
- ret = -EINVAL;
- break;
+ dev_err(info->dev, "failed to detect %s usb cable\n",
+ attached ? "attached" : "detached");
+ return -EINVAL;
}
-out:
- return ret;
+ return 0;
}
static int max8997_muic_handle_dock(struct max8997_muic_info *info,
- int adc, bool attached)
+ int cable_type, bool attached)
{
int ret = 0;
- /* switch to AUDIO */
- ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
- attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN,
- SW_MASK);
+ ret = max8997_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
if (ret) {
dev_err(info->dev, "failed to update muic register\n");
- goto out;
+ return ret;
}
- switch (adc) {
- case MAX8997_ADC_DESKDOCK:
+ switch (cable_type) {
+ case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD:
extcon_set_cable_state(info->edev, "Dock-desk", attached);
break;
- case MAX8997_ADC_CARDOCK:
+ case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON:
extcon_set_cable_state(info->edev, "Dock-card", attached);
break;
default:
- ret = -EINVAL;
- break;
+ dev_err(info->dev, "failed to detect %s dock device\n",
+ attached ? "attached" : "detached");
+ return -EINVAL;
}
-out:
- return ret;
+
+ return 0;
}
static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
@@ -191,199 +394,188 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
int ret = 0;
/* switch to UART */
- ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
- attached ? MAX8997_SW_UART : MAX8997_SW_OPEN,
- SW_MASK);
+ ret = max8997_muic_set_path(info, info->path_uart, attached);
if (ret) {
dev_err(info->dev, "failed to update muic register\n");
- goto out;
+ return -EINVAL;
}
extcon_set_cable_state(info->edev, "JIG", attached);
-out:
- return ret;
-}
-
-static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info)
-{
- int ret = 0;
- switch (info->pre_adc) {
- case MAX8997_ADC_GROUND:
- ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false);
- break;
- case MAX8997_ADC_MHL:
- extcon_set_cable_state(info->edev, "MHL", false);
- break;
- case MAX8997_ADC_JIG_USB_1:
- case MAX8997_ADC_JIG_USB_2:
- ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false);
- break;
- case MAX8997_ADC_DESKDOCK:
- case MAX8997_ADC_CARDOCK:
- ret = max8997_muic_handle_dock(info, info->pre_adc, false);
- break;
- case MAX8997_ADC_JIG_UART:
- ret = max8997_muic_handle_jig_uart(info, false);
- break;
- default:
- break;
- }
-
- return ret;
+ return 0;
}
-static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
+static int max8997_muic_adc_handler(struct max8997_muic_info *info)
{
+ int cable_type;
+ bool attached;
int ret = 0;
- switch (adc) {
- case MAX8997_ADC_GROUND:
- ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true);
- break;
- case MAX8997_ADC_MHL:
- extcon_set_cable_state(info->edev, "MHL", true);
- break;
- case MAX8997_ADC_JIG_USB_1:
- case MAX8997_ADC_JIG_USB_2:
- ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true);
- break;
- case MAX8997_ADC_DESKDOCK:
- case MAX8997_ADC_CARDOCK:
- ret = max8997_muic_handle_dock(info, adc, true);
- break;
- case MAX8997_ADC_JIG_UART:
- ret = max8997_muic_handle_jig_uart(info, true);
- break;
- case MAX8997_ADC_OPEN:
- ret = max8997_muic_handle_adc_detach(info);
- break;
- default:
- ret = -EINVAL;
- goto out;
- }
-
- info->pre_adc = adc;
-out:
- return ret;
-}
-
-static int max8997_muic_handle_charger_type_detach(
- struct max8997_muic_info *info)
-{
- switch (info->pre_charger_type) {
- case MAX8997_CHARGER_TYPE_USB:
- extcon_set_cable_state(info->edev, "USB", false);
- break;
- case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
- extcon_set_cable_state(info->edev, "Charge-downstream", false);
- break;
- case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
- extcon_set_cable_state(info->edev, "TA", false);
- break;
- case MAX8997_CHARGER_TYPE_500MA:
- extcon_set_cable_state(info->edev, "Slow-charger", false);
- break;
- case MAX8997_CHARGER_TYPE_1A:
- extcon_set_cable_state(info->edev, "Fast-charger", false);
- break;
+ /* Check cable state which is either detached or attached */
+ cable_type = max8997_muic_get_cable_type(info,
+ MAX8997_CABLE_GROUP_ADC, &attached);
+
+ switch (cable_type) {
+ case MAX8997_MUIC_ADC_GROUND:
+ ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, attached);
+ if (ret < 0)
+ return ret;
+ break;
+ case MAX8997_MUIC_ADC_MHL:
+ extcon_set_cable_state(info->edev, "MHL", attached);
+ break;
+ case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF:
+ case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON:
+ ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, attached);
+ if (ret < 0)
+ return ret;
+ break;
+ case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD:
+ case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON:
+ ret = max8997_muic_handle_dock(info, cable_type, attached);
+ if (ret < 0)
+ return ret;
+ break;
+ case MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF:
+ ret = max8997_muic_handle_jig_uart(info, attached);
+ break;
+ case MAX8997_MUIC_ADC_REMOTE_S1_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S2_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S3_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S4_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S5_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S6_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S7_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S8_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S9_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S10_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S11_BUTTON:
+ case MAX8997_MUIC_ADC_REMOTE_S12_BUTTON:
+ case MAX8997_MUIC_ADC_RESERVED_ACC_1:
+ case MAX8997_MUIC_ADC_RESERVED_ACC_2:
+ case MAX8997_MUIC_ADC_RESERVED_ACC_3:
+ case MAX8997_MUIC_ADC_RESERVED_ACC_4:
+ case MAX8997_MUIC_ADC_RESERVED_ACC_5:
+ case MAX8997_MUIC_ADC_CEA936_AUDIO:
+ case MAX8997_MUIC_ADC_PHONE_POWERED_DEV:
+ case MAX8997_MUIC_ADC_TTY_CONVERTER:
+ case MAX8997_MUIC_ADC_UART_CABLE:
+ case MAX8997_MUIC_ADC_CEA936A_TYPE1_CHG:
+ case MAX8997_MUIC_ADC_CEA936A_TYPE2_CHG:
+ case MAX8997_MUIC_ADC_AUDIO_MODE_REMOTE:
+ /*
+ * This cable isn't used in general case if it is specially
+ * needed to detect additional cable, should implement
+ * proper operation when this cable is attached/detached.
+ */
+ dev_info(info->dev,
+ "cable is %s but it isn't used (type:0x%x)\n",
+ attached ? "attached" : "detached", cable_type);
+ return -EAGAIN;
default:
+ dev_err(info->dev,
+ "failed to detect %s unknown cable (type:0x%x)\n",
+ attached ? "attached" : "detached", cable_type);
return -EINVAL;
- break;
}
return 0;
}
-static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
- enum max8997_muic_charger_type charger_type)
+static int max8997_muic_chg_handler(struct max8997_muic_info *info)
{
- u8 adc;
- int ret;
+ int chg_type;
+ bool attached;
+ int adc;
- ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc);
- if (ret) {
- dev_err(info->dev, "failed to read muic register\n");
- goto out;
- }
+ chg_type = max8997_muic_get_cable_type(info,
+ MAX8997_CABLE_GROUP_CHG, &attached);
- switch (charger_type) {
+ switch (chg_type) {
case MAX8997_CHARGER_TYPE_NONE:
- ret = max8997_muic_handle_charger_type_detach(info);
break;
case MAX8997_CHARGER_TYPE_USB:
- if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) {
+ adc = info->status[0] & STATUS1_ADC_MASK;
+ adc >>= STATUS1_ADC_SHIFT;
+
+ if ((adc & STATUS1_ADC_MASK) == MAX8997_MUIC_ADC_OPEN) {
max8997_muic_handle_usb(info,
- MAX8997_USB_DEVICE, true);
+ MAX8997_USB_DEVICE, attached);
}
break;
case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
- extcon_set_cable_state(info->edev, "Charge-downstream", true);
+ extcon_set_cable_state(info->edev, "Charge-downstream", attached);
break;
case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
- extcon_set_cable_state(info->edev, "TA", true);
+ extcon_set_cable_state(info->edev, "TA", attached);
break;
case MAX8997_CHARGER_TYPE_500MA:
- extcon_set_cable_state(info->edev, "Slow-charger", true);
+ extcon_set_cable_state(info->edev, "Slow-charger", attached);
break;
case MAX8997_CHARGER_TYPE_1A:
- extcon_set_cable_state(info->edev, "Fast-charger", true);
+ extcon_set_cable_state(info->edev, "Fast-charger", attached);
break;
default:
- ret = -EINVAL;
- goto out;
+ dev_err(info->dev,
+ "failed to detect %s unknown chg cable (type:0x%x)\n",
+ attached ? "attached" : "detached", chg_type);
+ return -EINVAL;
}
- info->pre_charger_type = charger_type;
-out:
- return ret;
+ return 0;
}
static void max8997_muic_irq_work(struct work_struct *work)
{
struct max8997_muic_info *info = container_of(work,
struct max8997_muic_info, irq_work);
- u8 status[2];
- u8 adc, chg_type;
int irq_type = 0;
int i, ret;
+ if (!info->edev)
+ return;
+
mutex_lock(&info->mutex);
+ for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++)
+ if (info->irq == muic_irqs[i].virq)
+ irq_type = muic_irqs[i].irq;
+
ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
- 2, status);
+ 2, info->status);
if (ret) {
dev_err(info->dev, "failed to read muic register\n");
mutex_unlock(&info->mutex);
return;
}
- dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
- status[0], status[1]);
-
- for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++)
- if (info->irq == muic_irqs[i].virq)
- irq_type = muic_irqs[i].irq;
-
switch (irq_type) {
+ case MAX8997_MUICIRQ_ADCError:
+ case MAX8997_MUICIRQ_ADCLow:
case MAX8997_MUICIRQ_ADC:
- adc = status[0] & STATUS1_ADC_MASK;
- adc >>= STATUS1_ADC_SHIFT;
-
- max8997_muic_handle_adc(info, adc);
+ /* Handle all of cable except for charger cable */
+ ret = max8997_muic_adc_handler(info);
break;
+ case MAX8997_MUICIRQ_VBVolt:
+ case MAX8997_MUICIRQ_DBChg:
+ case MAX8997_MUICIRQ_DCDTmr:
+ case MAX8997_MUICIRQ_ChgDetRun:
case MAX8997_MUICIRQ_ChgTyp:
- chg_type = status[1] & STATUS2_CHGTYP_MASK;
- chg_type >>= STATUS2_CHGTYP_SHIFT;
-
- max8997_muic_handle_charger_type(info, chg_type);
+ /* Handle charger cable */
+ ret = max8997_muic_chg_handler(info);
+ break;
+ case MAX8997_MUICIRQ_OVP:
break;
default:
dev_info(info->dev, "misc interrupt: irq %d occurred\n",
irq_type);
- break;
+ mutex_unlock(&info->mutex);
+ return;
}
+ if (ret < 0)
+ dev_err(info->dev, "failed to handle MUIC interrupt\n");
+
mutex_unlock(&info->mutex);
return;
@@ -401,29 +593,60 @@ static irqreturn_t max8997_muic_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static void max8997_muic_detect_dev(struct max8997_muic_info *info)
+static int max8997_muic_detect_dev(struct max8997_muic_info *info)
{
- int ret;
- u8 status[2], adc, chg_type;
+ int ret = 0;
+ int adc;
+ int chg_type;
+ bool attached;
- ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
- 2, status);
+ mutex_lock(&info->mutex);
+
+ /* Read STATUSx register to detect accessory */
+ ret = max8997_bulk_read(info->muic,
+ MAX8997_MUIC_REG_STATUS1, 2, info->status);
if (ret) {
- dev_err(info->dev, "failed to read muic register\n");
- return;
+ dev_err(info->dev, "failed to read MUIC register\n");
+ mutex_unlock(&info->mutex);
+ return -EINVAL;
}
- dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n",
- status[0], status[1]);
+ adc = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_ADC,
+ &attached);
+ if (attached && adc != MAX8997_MUIC_ADC_OPEN) {
+ ret = max8997_muic_adc_handler(info);
+ if (ret < 0) {
+ dev_err(info->dev, "Cannot detect ADC cable\n");
+ mutex_unlock(&info->mutex);
+ return ret;
+ }
+ }
- adc = status[0] & STATUS1_ADC_MASK;
- adc >>= STATUS1_ADC_SHIFT;
+ chg_type = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_CHG,
+ &attached);
+ if (attached && chg_type != MAX8997_CHARGER_TYPE_NONE) {
+ ret = max8997_muic_chg_handler(info);
+ if (ret < 0) {
+ dev_err(info->dev, "Cannot detect charger cable\n");
+ mutex_unlock(&info->mutex);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&info->mutex);
+
+ return 0;
+}
- chg_type = status[1] & STATUS2_CHGTYP_MASK;
- chg_type >>= STATUS2_CHGTYP_SHIFT;
+static void max8997_muic_detect_cable_wq(struct work_struct *work)
+{
+ struct max8997_muic_info *info = container_of(to_delayed_work(work),
+ struct max8997_muic_info, wq_detcable);
+ int ret;
- max8997_muic_handle_adc(info, adc);
- max8997_muic_handle_charger_type(info, chg_type);
+ ret = max8997_muic_detect_dev(info);
+ if (ret < 0)
+ pr_err("failed to detect cable type\n");
}
static int max8997_muic_probe(struct platform_device *pdev)
@@ -431,6 +654,7 @@ static int max8997_muic_probe(struct platform_device *pdev)
struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev);
struct max8997_muic_info *info;
+ int delay_jiffies;
int ret, i;
info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_muic_info),
@@ -459,8 +683,10 @@ static int max8997_muic_probe(struct platform_device *pdev)
}
muic_irq->virq = virq;
- ret = request_threaded_irq(virq, NULL, max8997_muic_irq_handler,
- 0, muic_irq->name, info);
+ ret = request_threaded_irq(virq, NULL,
+ max8997_muic_irq_handler,
+ IRQF_NO_SUSPEND,
+ muic_irq->name, info);
if (ret) {
dev_err(&pdev->dev,
"failed: irq request (IRQ: %d,"
@@ -496,10 +722,42 @@ static int max8997_muic_probe(struct platform_device *pdev)
}
}
- /* Initial device detection */
- max8997_muic_detect_dev(info);
+ /*
+ * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
+ * h/w path of COMP2/COMN1 on CONTROL1 register.
+ */
+ if (pdata->muic_pdata->path_uart)
+ info->path_uart = pdata->muic_pdata->path_uart;
+ else
+ info->path_uart = CONTROL1_SW_UART;
+
+ if (pdata->muic_pdata->path_usb)
+ info->path_usb = pdata->muic_pdata->path_usb;
+ else
+ info->path_usb = CONTROL1_SW_USB;
+
+ /* Set initial path for UART */
+ max8997_muic_set_path(info, info->path_uart, true);
+
+ /* Set ADC debounce time */
+ max8997_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS);
+
+ /*
+ * Detect accessory after completing the initialization of platform
+ *
+ * - Use delayed workqueue to detect cable state and then
+ * notify cable state to notifiee/platform through uevent.
+ * After completing the booting of platform, the extcon provider
+ * driver should notify cable state to upper layer.
+ */
+ INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq);
+ if (pdata->muic_pdata->detcable_delay_ms)
+ delay_jiffies = msecs_to_jiffies(pdata->muic_pdata->detcable_delay_ms);
+ else
+ delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+ schedule_delayed_work(&info->wq_detcable, delay_jiffies);
- return ret;
+ return 0;
err_irq:
while (--i >= 0)
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index e7a711f53a6f..2b27bff2591a 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -270,7 +270,7 @@ static int fwnet_header_cache(const struct neighbour *neigh,
if (type == cpu_to_be16(ETH_P_802_3))
return -1;
net = neigh->dev;
- h = (struct fwnet_header *)((u8 *)hh->hh_data + 16 - sizeof(*h));
+ h = (struct fwnet_header *)((u8 *)hh->hh_data + HH_DATA_OFF(sizeof(*h)));
h->h_proto = type;
memcpy(h->h_dest, neigh->ha, net->addr_len);
hh->hh_len = FWNET_HLEN;
@@ -282,7 +282,7 @@ static int fwnet_header_cache(const struct neighbour *neigh,
static void fwnet_header_cache_update(struct hh_cache *hh,
const struct net_device *net, const unsigned char *haddr)
{
- memcpy((u8 *)hh->hh_data + 16 - FWNET_HLEN, haddr, net->addr_len);
+ memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len);
}
static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr)
@@ -398,11 +398,11 @@ static struct fwnet_partial_datagram *fwnet_pd_new(struct net_device *net,
new->datagram_label = datagram_label;
new->datagram_size = dg_size;
- new->skb = dev_alloc_skb(dg_size + net->hard_header_len + 15);
+ new->skb = dev_alloc_skb(dg_size + LL_RESERVED_SPACE(net));
if (new->skb == NULL)
goto fail_w_fi;
- skb_reserve(new->skb, (net->hard_header_len + 15) & ~15);
+ skb_reserve(new->skb, LL_RESERVED_SPACE(net));
new->pbuf = skb_put(new->skb, dg_size);
memcpy(new->pbuf + frag_off, frag_buf, frag_len);
list_add_tail(&new->pd_link, &peer->pd_list);
@@ -520,7 +520,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
dev = netdev_priv(net);
/* Write metadata, and then pass to the receive level */
skb->dev = net;
- skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
+ skb->ip_summed = CHECKSUM_NONE;
/*
* Parse the encapsulation header. This actually does the job of
@@ -690,14 +690,14 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
buf++;
len -= RFC2374_UNFRAG_HDR_SIZE;
- skb = dev_alloc_skb(len + net->hard_header_len + 15);
+ skb = dev_alloc_skb(len + LL_RESERVED_SPACE(net));
if (unlikely(!skb)) {
dev_err(&net->dev, "out of memory\n");
net->stats.rx_dropped++;
return -ENOMEM;
}
- skb_reserve(skb, (net->hard_header_len + 15) & ~15);
+ skb_reserve(skb, LL_RESERVED_SPACE(net));
memcpy(skb_put(skb, len), buf, len);
return fwnet_finish_incoming_packet(net, skb, source_node_id,
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 6ce6e07c38c1..45912e6e0ac2 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -329,7 +329,7 @@ module_param_named(quirks, param_quirks, int, 0644);
MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
", nonatomic cycle timer = " __stringify(QUIRK_CYCLE_TIMER)
", reset packet generation = " __stringify(QUIRK_RESET_PACKET)
- ", AR/selfID endianess = " __stringify(QUIRK_BE_HEADERS)
+ ", AR/selfID endianness = " __stringify(QUIRK_BE_HEADERS)
", no 1394a enhancements = " __stringify(QUIRK_NO_1394A)
", disable MSI = " __stringify(QUIRK_NO_MSI)
", TI SLLZ059 erratum = " __stringify(QUIRK_TI_SLLZ059)
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index f5596db0cf58..fed08b661711 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -158,6 +158,13 @@ efivar_create_sysfs_entry(struct efivars *efivars,
efi_char16_t *variable_name,
efi_guid_t *vendor_guid);
+/*
+ * Prototype for workqueue functions updating sysfs entry
+ */
+
+static void efivar_update_sysfs_entries(struct work_struct *);
+static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
+
/* Return the number of unicode characters in data */
static unsigned long
utf16_strnlen(efi_char16_t *s, size_t maxlength)
@@ -405,10 +412,11 @@ static efi_status_t
get_var_data(struct efivars *efivars, struct efi_variable *var)
{
efi_status_t status;
+ unsigned long flags;
- spin_lock(&efivars->lock);
+ spin_lock_irqsave(&efivars->lock, flags);
status = get_var_data_locked(efivars, var);
- spin_unlock(&efivars->lock);
+ spin_unlock_irqrestore(&efivars->lock, flags);
if (status != EFI_SUCCESS) {
printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n",
@@ -537,14 +545,14 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
return -EINVAL;
}
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
status = efivars->ops->set_variable(new_var->VariableName,
&new_var->VendorGuid,
new_var->Attributes,
new_var->DataSize,
new_var->Data);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
if (status != EFI_SUCCESS) {
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
@@ -713,7 +721,7 @@ static ssize_t efivarfs_file_write(struct file *file,
* amounts of memory. Pick a default size of 64K if
* QueryVariableInfo() isn't supported by the firmware.
*/
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
if (!efivars->ops->query_variable_info)
status = EFI_UNSUPPORTED;
@@ -723,7 +731,7 @@ static ssize_t efivarfs_file_write(struct file *file,
&remaining_size, &max_size);
}
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
if (status != EFI_SUCCESS) {
if (status != EFI_UNSUPPORTED)
@@ -754,7 +762,7 @@ static ssize_t efivarfs_file_write(struct file *file,
* set_variable call, and removal of the variable from the efivars
* list (in the case of an authenticated delete).
*/
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
status = efivars->ops->set_variable(var->var.VariableName,
&var->var.VendorGuid,
@@ -762,7 +770,7 @@ static ssize_t efivarfs_file_write(struct file *file,
data);
if (status != EFI_SUCCESS) {
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
kfree(data);
return efi_status_to_err(status);
@@ -783,21 +791,21 @@ static ssize_t efivarfs_file_write(struct file *file,
NULL);
if (status == EFI_BUFFER_TOO_SMALL) {
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
mutex_lock(&inode->i_mutex);
i_size_write(inode, newdatasize + sizeof(attributes));
mutex_unlock(&inode->i_mutex);
} else if (status == EFI_NOT_FOUND) {
list_del(&var->list);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
efivar_unregister(var);
drop_nlink(inode);
d_delete(file->f_dentry);
dput(file->f_dentry);
} else {
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
pr_warn("efivarfs: inconsistent EFI variable implementation? "
"status = %lx\n", status);
}
@@ -819,11 +827,11 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
void *data;
ssize_t size = 0;
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
status = efivars->ops->get_variable(var->var.VariableName,
&var->var.VendorGuid,
&attributes, &datasize, NULL);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
if (status != EFI_BUFFER_TOO_SMALL)
return efi_status_to_err(status);
@@ -833,12 +841,12 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
if (!data)
return -ENOMEM;
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
status = efivars->ops->get_variable(var->var.VariableName,
&var->var.VendorGuid,
&attributes, &datasize,
(data + sizeof(attributes)));
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
if (status != EFI_SUCCESS) {
size = efi_status_to_err(status);
@@ -966,9 +974,9 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
goto out;
kobject_uevent(&var->kobj, KOBJ_ADD);
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
list_add(&var->list, &efivars->list);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
d_instantiate(dentry, inode);
dget(dentry);
out:
@@ -985,7 +993,7 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
struct efivars *efivars = var->efivars;
efi_status_t status;
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
status = efivars->ops->set_variable(var->var.VariableName,
&var->var.VendorGuid,
@@ -993,14 +1001,14 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
if (status == EFI_SUCCESS || status == EFI_NOT_FOUND) {
list_del(&var->list);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
efivar_unregister(var);
drop_nlink(dentry->d_inode);
dput(dentry);
return 0;
}
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
return -EINVAL;
};
@@ -1066,13 +1074,13 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
/* copied by the above to local storage in the dentry. */
kfree(name);
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
efivars->ops->get_variable(entry->var.VariableName,
&entry->var.VendorGuid,
&entry->var.Attributes,
&size,
NULL);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
mutex_lock(&inode->i_mutex);
inode->i_private = entry;
@@ -1123,7 +1131,7 @@ static int efi_pstore_open(struct pstore_info *psi)
{
struct efivars *efivars = psi->data;
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
efivars->walk_entry = list_first_entry(&efivars->list,
struct efivar_entry, list);
return 0;
@@ -1133,7 +1141,7 @@ static int efi_pstore_close(struct pstore_info *psi)
{
struct efivars *efivars = psi->data;
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
return 0;
}
@@ -1209,8 +1217,18 @@ static int efi_pstore_write(enum pstore_type_id type,
int i, ret = 0;
u64 storage_space, remaining_space, max_variable_size;
efi_status_t status = EFI_NOT_FOUND;
-
- spin_lock(&efivars->lock);
+ unsigned long flags;
+
+ if (pstore_cannot_block_path(reason)) {
+ /*
+ * If the lock is taken by another cpu in non-blocking path,
+ * this driver returns without entering firmware to avoid
+ * hanging up.
+ */
+ if (!spin_trylock_irqsave(&efivars->lock, flags))
+ return -EBUSY;
+ } else
+ spin_lock_irqsave(&efivars->lock, flags);
/*
* Check if there is a space enough to log.
@@ -1222,7 +1240,7 @@ static int efi_pstore_write(enum pstore_type_id type,
&remaining_space,
&max_variable_size);
if (status || remaining_space < size + DUMP_NAME_LEN * 2) {
- spin_unlock(&efivars->lock);
+ spin_unlock_irqrestore(&efivars->lock, flags);
*id = part;
return -ENOSPC;
}
@@ -1236,13 +1254,10 @@ static int efi_pstore_write(enum pstore_type_id type,
efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES,
size, psi->buf);
- spin_unlock(&efivars->lock);
+ spin_unlock_irqrestore(&efivars->lock, flags);
- if (size)
- ret = efivar_create_sysfs_entry(efivars,
- utf16_strsize(efi_name,
- DUMP_NAME_LEN * 2),
- efi_name, &vendor);
+ if (reason == KMSG_DUMP_OOPS)
+ schedule_work(&efivar_work);
*id = part;
return ret;
@@ -1263,7 +1278,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count,
time.tv_sec);
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
for (i = 0; i < DUMP_NAME_LEN; i++)
efi_name[i] = name[i];
@@ -1307,7 +1322,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
if (found)
list_del(&found->list);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
if (found)
efivar_unregister(found);
@@ -1377,7 +1392,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
return -EINVAL;
}
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
/*
* Does this variable already exist?
@@ -1395,7 +1410,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
}
}
if (found) {
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
return -EINVAL;
}
@@ -1409,10 +1424,10 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
if (status != EFI_SUCCESS) {
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
status);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
return -EIO;
}
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
/* Create the entry in sysfs. Locking is not required here */
status = efivar_create_sysfs_entry(efivars,
@@ -1440,7 +1455,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
/*
* Does this variable already exist?
@@ -1458,7 +1473,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
}
}
if (!found) {
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
return -EINVAL;
}
/* force the Attributes/DataSize to 0 to ensure deletion */
@@ -1474,18 +1489,87 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
if (status != EFI_SUCCESS) {
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
status);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
return -EIO;
}
list_del(&search_efivar->list);
/* We need to release this lock before unregistering. */
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
efivar_unregister(search_efivar);
/* It's dead Jim.... */
return count;
}
+static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
+{
+ struct efivar_entry *entry, *n;
+ struct efivars *efivars = &__efivars;
+ unsigned long strsize1, strsize2;
+ bool found = false;
+
+ strsize1 = utf16_strsize(variable_name, 1024);
+ list_for_each_entry_safe(entry, n, &efivars->list, list) {
+ strsize2 = utf16_strsize(entry->var.VariableName, 1024);
+ if (strsize1 == strsize2 &&
+ !memcmp(variable_name, &(entry->var.VariableName),
+ strsize2) &&
+ !efi_guidcmp(entry->var.VendorGuid,
+ *vendor)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+static void efivar_update_sysfs_entries(struct work_struct *work)
+{
+ struct efivars *efivars = &__efivars;
+ efi_guid_t vendor;
+ efi_char16_t *variable_name;
+ unsigned long variable_name_size = 1024;
+ efi_status_t status = EFI_NOT_FOUND;
+ bool found;
+
+ /* Add new sysfs entries */
+ while (1) {
+ variable_name = kzalloc(variable_name_size, GFP_KERNEL);
+ if (!variable_name) {
+ pr_err("efivars: Memory allocation failed.\n");
+ return;
+ }
+
+ spin_lock_irq(&efivars->lock);
+ found = false;
+ while (1) {
+ variable_name_size = 1024;
+ status = efivars->ops->get_next_variable(
+ &variable_name_size,
+ variable_name,
+ &vendor);
+ if (status != EFI_SUCCESS) {
+ break;
+ } else {
+ if (!variable_is_present(variable_name,
+ &vendor)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ spin_unlock_irq(&efivars->lock);
+
+ if (!found) {
+ kfree(variable_name);
+ break;
+ } else
+ efivar_create_sysfs_entry(efivars,
+ variable_name_size,
+ variable_name, &vendor);
+ }
+}
+
/*
* Let's not leave out systab information that snuck into
* the efivars driver
@@ -1594,9 +1678,9 @@ efivar_create_sysfs_entry(struct efivars *efivars,
kfree(short_name);
short_name = NULL;
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
list_add(&new_efivar->list, &efivars->list);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
return 0;
}
@@ -1665,9 +1749,9 @@ void unregister_efivars(struct efivars *efivars)
struct efivar_entry *entry, *n;
list_for_each_entry_safe(entry, n, &efivars->list, list) {
- spin_lock(&efivars->lock);
+ spin_lock_irq(&efivars->lock);
list_del(&entry->list);
- spin_unlock(&efivars->lock);
+ spin_unlock_irq(&efivars->lock);
efivar_unregister(entry);
}
if (efivars->new_var)
@@ -1823,6 +1907,8 @@ err_put:
static void __exit
efivars_exit(void)
{
+ cancel_work_sync(&efivar_work);
+
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
unregister_efivars(&__efivars);
kobject_put(efi_kobj);
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c
index 90723e65b081..0b5b5f619c75 100644
--- a/drivers/firmware/memmap.c
+++ b/drivers/firmware/memmap.c
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/bootmem.h>
#include <linux/slab.h>
+#include <linux/mm.h>
/*
* Data types ------------------------------------------------------------------
@@ -52,6 +53,9 @@ static ssize_t start_show(struct firmware_map_entry *entry, char *buf);
static ssize_t end_show(struct firmware_map_entry *entry, char *buf);
static ssize_t type_show(struct firmware_map_entry *entry, char *buf);
+static struct firmware_map_entry * __meminit
+firmware_map_find_entry(u64 start, u64 end, const char *type);
+
/*
* Static data -----------------------------------------------------------------
*/
@@ -79,7 +83,52 @@ static const struct sysfs_ops memmap_attr_ops = {
.show = memmap_attr_show,
};
-static struct kobj_type memmap_ktype = {
+/* Firmware memory map entries. */
+static LIST_HEAD(map_entries);
+static DEFINE_SPINLOCK(map_entries_lock);
+
+/*
+ * For memory hotplug, there is no way to free memory map entries allocated
+ * by boot mem after the system is up. So when we hot-remove memory whose
+ * map entry is allocated by bootmem, we need to remember the storage and
+ * reuse it when the memory is hot-added again.
+ */
+static LIST_HEAD(map_entries_bootmem);
+static DEFINE_SPINLOCK(map_entries_bootmem_lock);
+
+
+static inline struct firmware_map_entry *
+to_memmap_entry(struct kobject *kobj)
+{
+ return container_of(kobj, struct firmware_map_entry, kobj);
+}
+
+static void __meminit release_firmware_map_entry(struct kobject *kobj)
+{
+ struct firmware_map_entry *entry = to_memmap_entry(kobj);
+
+ if (PageReserved(virt_to_page(entry))) {
+ /*
+ * Remember the storage allocated by bootmem, and reuse it when
+ * the memory is hot-added again. The entry will be added to
+ * map_entries_bootmem here, and deleted from &map_entries in
+ * firmware_map_remove_entry().
+ */
+ if (firmware_map_find_entry(entry->start, entry->end,
+ entry->type)) {
+ spin_lock(&map_entries_bootmem_lock);
+ list_add(&entry->list, &map_entries_bootmem);
+ spin_unlock(&map_entries_bootmem_lock);
+ }
+
+ return;
+ }
+
+ kfree(entry);
+}
+
+static struct kobj_type __refdata memmap_ktype = {
+ .release = release_firmware_map_entry,
.sysfs_ops = &memmap_attr_ops,
.default_attrs = def_attrs,
};
@@ -88,13 +137,6 @@ static struct kobj_type memmap_ktype = {
* Registration functions ------------------------------------------------------
*/
-/*
- * Firmware memory map entries. No locking is needed because the
- * firmware_map_add() and firmware_map_add_early() functions are called
- * in firmware initialisation code in one single thread of execution.
- */
-static LIST_HEAD(map_entries);
-
/**
* firmware_map_add_entry() - Does the real work to add a firmware memmap entry.
* @start: Start of the memory range.
@@ -118,11 +160,25 @@ static int firmware_map_add_entry(u64 start, u64 end,
INIT_LIST_HEAD(&entry->list);
kobject_init(&entry->kobj, &memmap_ktype);
+ spin_lock(&map_entries_lock);
list_add_tail(&entry->list, &map_entries);
+ spin_unlock(&map_entries_lock);
return 0;
}
+/**
+ * firmware_map_remove_entry() - Does the real work to remove a firmware
+ * memmap entry.
+ * @entry: removed entry.
+ *
+ * The caller must hold map_entries_lock, and release it properly.
+ **/
+static inline void firmware_map_remove_entry(struct firmware_map_entry *entry)
+{
+ list_del(&entry->list);
+}
+
/*
* Add memmap entry on sysfs
*/
@@ -144,6 +200,78 @@ static int add_sysfs_fw_map_entry(struct firmware_map_entry *entry)
return 0;
}
+/*
+ * Remove memmap entry on sysfs
+ */
+static inline void remove_sysfs_fw_map_entry(struct firmware_map_entry *entry)
+{
+ kobject_put(&entry->kobj);
+}
+
+/*
+ * firmware_map_find_entry_in_list() - Search memmap entry in a given list.
+ * @start: Start of the memory range.
+ * @end: End of the memory range (exclusive).
+ * @type: Type of the memory range.
+ * @list: In which to find the entry.
+ *
+ * This function is to find the memmap entey of a given memory range in a
+ * given list. The caller must hold map_entries_lock, and must not release
+ * the lock until the processing of the returned entry has completed.
+ *
+ * Return: Pointer to the entry to be found on success, or NULL on failure.
+ */
+static struct firmware_map_entry * __meminit
+firmware_map_find_entry_in_list(u64 start, u64 end, const char *type,
+ struct list_head *list)
+{
+ struct firmware_map_entry *entry;
+
+ list_for_each_entry(entry, list, list)
+ if ((entry->start == start) && (entry->end == end) &&
+ (!strcmp(entry->type, type))) {
+ return entry;
+ }
+
+ return NULL;
+}
+
+/*
+ * firmware_map_find_entry() - Search memmap entry in map_entries.
+ * @start: Start of the memory range.
+ * @end: End of the memory range (exclusive).
+ * @type: Type of the memory range.
+ *
+ * This function is to find the memmap entey of a given memory range.
+ * The caller must hold map_entries_lock, and must not release the lock
+ * until the processing of the returned entry has completed.
+ *
+ * Return: Pointer to the entry to be found on success, or NULL on failure.
+ */
+static struct firmware_map_entry * __meminit
+firmware_map_find_entry(u64 start, u64 end, const char *type)
+{
+ return firmware_map_find_entry_in_list(start, end, type, &map_entries);
+}
+
+/*
+ * firmware_map_find_entry_bootmem() - Search memmap entry in map_entries_bootmem.
+ * @start: Start of the memory range.
+ * @end: End of the memory range (exclusive).
+ * @type: Type of the memory range.
+ *
+ * This function is similar to firmware_map_find_entry except that it find the
+ * given entry in map_entries_bootmem.
+ *
+ * Return: Pointer to the entry to be found on success, or NULL on failure.
+ */
+static struct firmware_map_entry * __meminit
+firmware_map_find_entry_bootmem(u64 start, u64 end, const char *type)
+{
+ return firmware_map_find_entry_in_list(start, end, type,
+ &map_entries_bootmem);
+}
+
/**
* firmware_map_add_hotplug() - Adds a firmware mapping entry when we do
* memory hotplug.
@@ -161,9 +289,19 @@ int __meminit firmware_map_add_hotplug(u64 start, u64 end, const char *type)
{
struct firmware_map_entry *entry;
- entry = kzalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC);
- if (!entry)
- return -ENOMEM;
+ entry = firmware_map_find_entry_bootmem(start, end, type);
+ if (!entry) {
+ entry = kzalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC);
+ if (!entry)
+ return -ENOMEM;
+ } else {
+ /* Reuse storage allocated by bootmem. */
+ spin_lock(&map_entries_bootmem_lock);
+ list_del(&entry->list);
+ spin_unlock(&map_entries_bootmem_lock);
+
+ memset(entry, 0, sizeof(*entry));
+ }
firmware_map_add_entry(start, end, type, entry);
/* create the memmap entry */
@@ -196,6 +334,36 @@ int __init firmware_map_add_early(u64 start, u64 end, const char *type)
return firmware_map_add_entry(start, end, type, entry);
}
+/**
+ * firmware_map_remove() - remove a firmware mapping entry
+ * @start: Start of the memory range.
+ * @end: End of the memory range.
+ * @type: Type of the memory range.
+ *
+ * removes a firmware mapping entry.
+ *
+ * Returns 0 on success, or -EINVAL if no entry.
+ **/
+int __meminit firmware_map_remove(u64 start, u64 end, const char *type)
+{
+ struct firmware_map_entry *entry;
+
+ spin_lock(&map_entries_lock);
+ entry = firmware_map_find_entry(start, end - 1, type);
+ if (!entry) {
+ spin_unlock(&map_entries_lock);
+ return -EINVAL;
+ }
+
+ firmware_map_remove_entry(entry);
+ spin_unlock(&map_entries_lock);
+
+ /* remove the memmap entry */
+ remove_sysfs_fw_map_entry(entry);
+
+ return 0;
+}
+
/*
* Sysfs functions -------------------------------------------------------------
*/
@@ -217,8 +385,10 @@ static ssize_t type_show(struct firmware_map_entry *entry, char *buf)
return snprintf(buf, PAGE_SIZE, "%s\n", entry->type);
}
-#define to_memmap_attr(_attr) container_of(_attr, struct memmap_attribute, attr)
-#define to_memmap_entry(obj) container_of(obj, struct firmware_map_entry, kobj)
+static inline struct memmap_attribute *to_memmap_attr(struct attribute *attr)
+{
+ return container_of(attr, struct memmap_attribute, attr);
+}
static ssize_t memmap_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 682de754d63f..74e17f19cc33 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -66,7 +66,7 @@ config DEBUG_GPIO
config GPIO_SYSFS
bool "/sys/class/gpio/... (sysfs interface)"
- depends on SYSFS && EXPERIMENTAL
+ depends on SYSFS
help
Say Y here to add a sysfs interface for GPIOs.
@@ -277,7 +277,7 @@ config GPIO_ICH
config GPIO_VX855
tristate "VIA VX855/VX875 GPIO"
- depends on PCI
+ depends on PCI && GENERIC_HARDIRQS
select MFD_CORE
select MFD_VX855
help
@@ -599,7 +599,7 @@ config GPIO_TIMBERDALE
config GPIO_RDC321X
tristate "RDC R-321x GPIO support"
- depends on PCI
+ depends on PCI && GENERIC_HARDIRQS
select MFD_CORE
select MFD_RDC321X
help
@@ -657,11 +657,12 @@ config GPIO_JANZ_TTL
This driver provides support for driving the pins in output
mode only. Input mode is not supported.
-config GPIO_AB8500
- bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions"
- depends on AB8500_CORE && BROKEN
+config GPIO_PALMAS
+ bool "TI PALMAS series PMICs GPIO"
+ depends on MFD_PALMAS
help
- Select this to enable the AB8500 IC GPIO driver
+ Select this option to enable GPIO driver for the TI PALMAS
+ series chip family.
config GPIO_TPS6586X
bool "TPS6586X GPIO"
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c5aebd008dde..6dbcba2e5cac 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
-obj-$(CONFIG_GPIO_AB8500) += gpio-ab8500.o
obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
@@ -69,6 +68,7 @@ obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
+obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
diff --git a/drivers/gpio/gpio-ab8500.c b/drivers/gpio/gpio-ab8500.c
deleted file mode 100644
index 983ad425f0ac..000000000000
--- a/drivers/gpio/gpio-ab8500.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2011
- *
- * Author: BIBEK BASU <bibek.basu@stericsson.com>
- * License terms: GNU General Public License (GPL) version 2
- *
- * 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/types.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/ab8500.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500/gpio.h>
-
-/*
- * GPIO registers offset
- * Bank: 0x10
- */
-#define AB8500_GPIO_SEL1_REG 0x00
-#define AB8500_GPIO_SEL2_REG 0x01
-#define AB8500_GPIO_SEL3_REG 0x02
-#define AB8500_GPIO_SEL4_REG 0x03
-#define AB8500_GPIO_SEL5_REG 0x04
-#define AB8500_GPIO_SEL6_REG 0x05
-
-#define AB8500_GPIO_DIR1_REG 0x10
-#define AB8500_GPIO_DIR2_REG 0x11
-#define AB8500_GPIO_DIR3_REG 0x12
-#define AB8500_GPIO_DIR4_REG 0x13
-#define AB8500_GPIO_DIR5_REG 0x14
-#define AB8500_GPIO_DIR6_REG 0x15
-
-#define AB8500_GPIO_OUT1_REG 0x20
-#define AB8500_GPIO_OUT2_REG 0x21
-#define AB8500_GPIO_OUT3_REG 0x22
-#define AB8500_GPIO_OUT4_REG 0x23
-#define AB8500_GPIO_OUT5_REG 0x24
-#define AB8500_GPIO_OUT6_REG 0x25
-
-#define AB8500_GPIO_PUD1_REG 0x30
-#define AB8500_GPIO_PUD2_REG 0x31
-#define AB8500_GPIO_PUD3_REG 0x32
-#define AB8500_GPIO_PUD4_REG 0x33
-#define AB8500_GPIO_PUD5_REG 0x34
-#define AB8500_GPIO_PUD6_REG 0x35
-
-#define AB8500_GPIO_IN1_REG 0x40
-#define AB8500_GPIO_IN2_REG 0x41
-#define AB8500_GPIO_IN3_REG 0x42
-#define AB8500_GPIO_IN4_REG 0x43
-#define AB8500_GPIO_IN5_REG 0x44
-#define AB8500_GPIO_IN6_REG 0x45
-#define AB8500_GPIO_ALTFUN_REG 0x45
-#define ALTFUN_REG_INDEX 6
-#define AB8500_NUM_GPIO 42
-#define AB8500_NUM_VIR_GPIO_IRQ 16
-
-enum ab8500_gpio_action {
- NONE,
- STARTUP,
- SHUTDOWN,
- MASK,
- UNMASK
-};
-
-struct ab8500_gpio {
- struct gpio_chip chip;
- struct ab8500 *parent;
- struct device *dev;
- struct mutex lock;
- u32 irq_base;
- enum ab8500_gpio_action irq_action;
- u16 rising;
- u16 falling;
-};
-/**
- * to_ab8500_gpio() - get the pointer to ab8500_gpio
- * @chip: Member of the structure ab8500_gpio
- */
-static inline struct ab8500_gpio *to_ab8500_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct ab8500_gpio, chip);
-}
-
-static int ab8500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
- unsigned offset, int val)
-{
- struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
- u8 pos = offset % 8;
- int ret;
-
- reg = reg + (offset / 8);
- ret = abx500_mask_and_set_register_interruptible(ab8500_gpio->dev,
- AB8500_MISC, reg, 1 << pos, val << pos);
- if (ret < 0)
- dev_err(ab8500_gpio->dev, "%s write failed\n", __func__);
- return ret;
-}
-/**
- * ab8500_gpio_get() - Get the particular GPIO value
- * @chip: Gpio device
- * @offset: GPIO number to read
- */
-static int ab8500_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
- u8 mask = 1 << (offset % 8);
- u8 reg = AB8500_GPIO_OUT1_REG + (offset / 8);
- int ret;
- u8 data;
- ret = abx500_get_register_interruptible(ab8500_gpio->dev, AB8500_MISC,
- reg, &data);
- if (ret < 0) {
- dev_err(ab8500_gpio->dev, "%s read failed\n", __func__);
- return ret;
- }
- return (data & mask) >> (offset % 8);
-}
-
-static void ab8500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
-{
- struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
- int ret;
- /* Write the data */
- ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, 1);
- if (ret < 0)
- dev_err(ab8500_gpio->dev, "%s write failed\n", __func__);
-}
-
-static int ab8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
- int val)
-{
- int ret;
- /* set direction as output */
- ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
- if (ret < 0)
- return ret;
- /* disable pull down */
- ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
- if (ret < 0)
- return ret;
- /* set the output as 1 or 0 */
- return ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
-
-}
-
-static int ab8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- /* set the register as input */
- return ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
-}
-
-static int ab8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- /*
- * Only some GPIOs are interrupt capable, and they are
- * organized in discontiguous clusters:
- *
- * GPIO6 to GPIO13
- * GPIO24 and GPIO25
- * GPIO36 to GPIO41
- */
- static struct ab8500_gpio_irq_cluster {
- int start;
- int end;
- } clusters[] = {
- {.start = 6, .end = 13},
- {.start = 24, .end = 25},
- {.start = 36, .end = 41},
- };
- struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
- int base = ab8500_gpio->irq_base;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(clusters); i++) {
- struct ab8500_gpio_irq_cluster *cluster = &clusters[i];
-
- if (offset >= cluster->start && offset <= cluster->end)
- return base + offset - cluster->start;
-
- /* Advance by the number of gpios in this cluster */
- base += cluster->end - cluster->start + 1;
- }
-
- return -EINVAL;
-}
-
-static struct gpio_chip ab8500gpio_chip = {
- .label = "ab8500_gpio",
- .owner = THIS_MODULE,
- .direction_input = ab8500_gpio_direction_input,
- .get = ab8500_gpio_get,
- .direction_output = ab8500_gpio_direction_output,
- .set = ab8500_gpio_set,
- .to_irq = ab8500_gpio_to_irq,
-};
-
-static unsigned int irq_to_rising(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- int offset = irq - ab8500_gpio->irq_base;
- int new_irq = offset + AB8500_INT_GPIO6R
- + ab8500_gpio->parent->irq_base;
- return new_irq;
-}
-
-static unsigned int irq_to_falling(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- int offset = irq - ab8500_gpio->irq_base;
- int new_irq = offset + AB8500_INT_GPIO6F
- + ab8500_gpio->parent->irq_base;
- return new_irq;
-
-}
-
-static unsigned int rising_to_irq(unsigned int irq, void *dev)
-{
- struct ab8500_gpio *ab8500_gpio = dev;
- int offset = irq - AB8500_INT_GPIO6R
- - ab8500_gpio->parent->irq_base ;
- int new_irq = offset + ab8500_gpio->irq_base;
- return new_irq;
-}
-
-static unsigned int falling_to_irq(unsigned int irq, void *dev)
-{
- struct ab8500_gpio *ab8500_gpio = dev;
- int offset = irq - AB8500_INT_GPIO6F
- - ab8500_gpio->parent->irq_base ;
- int new_irq = offset + ab8500_gpio->irq_base;
- return new_irq;
-
-}
-
-/*
- * IRQ handler
- */
-
-static irqreturn_t handle_rising(int irq, void *dev)
-{
-
- handle_nested_irq(rising_to_irq(irq , dev));
- return IRQ_HANDLED;
-}
-
-static irqreturn_t handle_falling(int irq, void *dev)
-{
-
- handle_nested_irq(falling_to_irq(irq, dev));
- return IRQ_HANDLED;
-}
-
-static void ab8500_gpio_irq_lock(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- mutex_lock(&ab8500_gpio->lock);
-}
-
-static void ab8500_gpio_irq_sync_unlock(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- int offset = irq - ab8500_gpio->irq_base;
- bool rising = ab8500_gpio->rising & BIT(offset);
- bool falling = ab8500_gpio->falling & BIT(offset);
- int ret;
-
- switch (ab8500_gpio->irq_action) {
- case STARTUP:
- if (rising)
- ret = request_threaded_irq(irq_to_rising(irq),
- NULL, handle_rising,
- IRQF_TRIGGER_RISING,
- "ab8500-gpio-r", ab8500_gpio);
- if (falling)
- ret = request_threaded_irq(irq_to_falling(irq),
- NULL, handle_falling,
- IRQF_TRIGGER_FALLING,
- "ab8500-gpio-f", ab8500_gpio);
- break;
- case SHUTDOWN:
- if (rising)
- free_irq(irq_to_rising(irq), ab8500_gpio);
- if (falling)
- free_irq(irq_to_falling(irq), ab8500_gpio);
- break;
- case MASK:
- if (rising)
- disable_irq(irq_to_rising(irq));
- if (falling)
- disable_irq(irq_to_falling(irq));
- break;
- case UNMASK:
- if (rising)
- enable_irq(irq_to_rising(irq));
- if (falling)
- enable_irq(irq_to_falling(irq));
- break;
- case NONE:
- break;
- }
- ab8500_gpio->irq_action = NONE;
- ab8500_gpio->rising &= ~(BIT(offset));
- ab8500_gpio->falling &= ~(BIT(offset));
- mutex_unlock(&ab8500_gpio->lock);
-}
-
-
-static void ab8500_gpio_irq_mask(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- ab8500_gpio->irq_action = MASK;
-}
-
-static void ab8500_gpio_irq_unmask(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- ab8500_gpio->irq_action = UNMASK;
-}
-
-static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- int offset = irq - ab8500_gpio->irq_base;
-
- if (type == IRQ_TYPE_EDGE_BOTH) {
- ab8500_gpio->rising = BIT(offset);
- ab8500_gpio->falling = BIT(offset);
- } else if (type == IRQ_TYPE_EDGE_RISING) {
- ab8500_gpio->rising = BIT(offset);
- } else {
- ab8500_gpio->falling = BIT(offset);
- }
- return 0;
-}
-
-unsigned int ab8500_gpio_irq_startup(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- ab8500_gpio->irq_action = STARTUP;
- return 0;
-}
-
-void ab8500_gpio_irq_shutdown(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- ab8500_gpio->irq_action = SHUTDOWN;
-}
-
-static struct irq_chip ab8500_gpio_irq_chip = {
- .name = "ab8500-gpio",
- .startup = ab8500_gpio_irq_startup,
- .shutdown = ab8500_gpio_irq_shutdown,
- .bus_lock = ab8500_gpio_irq_lock,
- .bus_sync_unlock = ab8500_gpio_irq_sync_unlock,
- .mask = ab8500_gpio_irq_mask,
- .unmask = ab8500_gpio_irq_unmask,
- .set_type = ab8500_gpio_irq_set_type,
-};
-
-static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio)
-{
- u32 base = ab8500_gpio->irq_base;
- int irq;
-
- for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) {
- set_irq_chip_data(irq, ab8500_gpio);
- set_irq_chip_and_handler(irq, &ab8500_gpio_irq_chip,
- handle_simple_irq);
- set_irq_nested_thread(irq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- set_irq_noprobe(irq);
-#endif
- }
-
- return 0;
-}
-
-static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio)
-{
- int base = ab8500_gpio->irq_base;
- int irq;
-
- for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) {
-#ifdef CONFIG_ARM
- set_irq_flags(irq, 0);
-#endif
- set_irq_chip_and_handler(irq, NULL, NULL);
- set_irq_chip_data(irq, NULL);
- }
-}
-
-static int ab8500_gpio_probe(struct platform_device *pdev)
-{
- struct ab8500_platform_data *ab8500_pdata =
- dev_get_platdata(pdev->dev.parent);
- struct ab8500_gpio_platform_data *pdata;
- struct ab8500_gpio *ab8500_gpio;
- int ret;
- int i;
-
- pdata = ab8500_pdata->gpio;
- if (!pdata) {
- dev_err(&pdev->dev, "gpio platform data missing\n");
- return -ENODEV;
- }
-
- ab8500_gpio = kzalloc(sizeof(struct ab8500_gpio), GFP_KERNEL);
- if (ab8500_gpio == NULL) {
- dev_err(&pdev->dev, "failed to allocate memory\n");
- return -ENOMEM;
- }
- ab8500_gpio->dev = &pdev->dev;
- ab8500_gpio->parent = dev_get_drvdata(pdev->dev.parent);
- ab8500_gpio->chip = ab8500gpio_chip;
- ab8500_gpio->chip.ngpio = AB8500_NUM_GPIO;
- ab8500_gpio->chip.dev = &pdev->dev;
- ab8500_gpio->chip.base = pdata->gpio_base;
- ab8500_gpio->irq_base = pdata->irq_base;
- /* initialize the lock */
- mutex_init(&ab8500_gpio->lock);
- /*
- * AB8500 core will handle and clear the IRQ
- * configre GPIO based on config-reg value.
- * These values are for selecting the PINs as
- * GPIO or alternate function
- */
- for (i = AB8500_GPIO_SEL1_REG; i <= AB8500_GPIO_SEL6_REG; i++) {
- ret = abx500_set_register_interruptible(ab8500_gpio->dev,
- AB8500_MISC, i,
- pdata->config_reg[i]);
- if (ret < 0)
- goto out_free;
- }
- ret = abx500_set_register_interruptible(ab8500_gpio->dev, AB8500_MISC,
- AB8500_GPIO_ALTFUN_REG,
- pdata->config_reg[ALTFUN_REG_INDEX]);
- if (ret < 0)
- goto out_free;
-
- ret = ab8500_gpio_irq_init(ab8500_gpio);
- if (ret)
- goto out_free;
- ret = gpiochip_add(&ab8500_gpio->chip);
- if (ret) {
- dev_err(&pdev->dev, "unable to add gpiochip: %d\n",
- ret);
- goto out_rem_irq;
- }
- platform_set_drvdata(pdev, ab8500_gpio);
- return 0;
-
-out_rem_irq:
- ab8500_gpio_irq_remove(ab8500_gpio);
-out_free:
- mutex_destroy(&ab8500_gpio->lock);
- kfree(ab8500_gpio);
- return ret;
-}
-
-/*
- * ab8500_gpio_remove() - remove Ab8500-gpio driver
- * @pdev : Platform device registered
- */
-static int ab8500_gpio_remove(struct platform_device *pdev)
-{
- struct ab8500_gpio *ab8500_gpio = platform_get_drvdata(pdev);
- int ret;
-
- ret = gpiochip_remove(&ab8500_gpio->chip);
- if (ret < 0) {
- dev_err(ab8500_gpio->dev, "unable to remove gpiochip: %d\n",
- ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, NULL);
- mutex_destroy(&ab8500_gpio->lock);
- kfree(ab8500_gpio);
-
- return 0;
-}
-
-static struct platform_driver ab8500_gpio_driver = {
- .driver = {
- .name = "ab8500-gpio",
- .owner = THIS_MODULE,
- },
- .probe = ab8500_gpio_probe,
- .remove = ab8500_gpio_remove,
-};
-
-static int __init ab8500_gpio_init(void)
-{
- return platform_driver_register(&ab8500_gpio_driver);
-}
-arch_initcall(ab8500_gpio_init);
-
-static void __exit ab8500_gpio_exit(void)
-{
- platform_driver_unregister(&ab8500_gpio_driver);
-}
-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_ALIAS("platform:ab8500-gpio");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 6819d63cb167..7472182967ce 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -33,6 +33,7 @@
* interrupts.
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/irq.h>
@@ -544,11 +545,9 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
mvchip->chip.of_node = np;
spin_lock_init(&mvchip->lock);
- mvchip->membase = devm_request_and_ioremap(&pdev->dev, res);
- if (! mvchip->membase) {
- dev_err(&pdev->dev, "Cannot ioremap\n");
- return -ENOMEM;
- }
+ mvchip->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mvchip->membase))
+ return PTR_ERR(mvchip->membase);
/* The Armada XP has a second range of registers for the
* per-CPU registers */
@@ -559,11 +558,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
- mvchip->percpu_membase = devm_request_and_ioremap(&pdev->dev, res);
- if (! mvchip->percpu_membase) {
- dev_err(&pdev->dev, "Cannot ioremap\n");
- return -ENOMEM;
- }
+ mvchip->percpu_membase = devm_ioremap_resource(&pdev->dev,
+ res);
+ if (IS_ERR(mvchip->percpu_membase))
+ return PTR_ERR(mvchip->percpu_membase);
}
/*
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index fa2a63cad32e..45d97c46831a 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -20,6 +20,7 @@
* MA 02110-1301, USA.
*/
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -253,12 +254,14 @@ static int mxs_gpio_probe(struct platform_device *pdev)
parent = of_get_parent(np);
base = of_iomap(parent, 0);
of_node_put(parent);
+ if (!base)
+ return -EADDRNOTAVAIL;
} else {
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_request_and_ioremap(&pdev->dev, iores);
+ base = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
}
- if (!base)
- return -EADDRNOTAVAIL;
}
port->base = base;
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
new file mode 100644
index 000000000000..e3a4e56f5a42
--- /dev/null
+++ b/drivers/gpio/gpio-palmas.c
@@ -0,0 +1,184 @@
+/*
+ * TI Palma series PMIC's GPIO driver.
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/palmas.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct palmas_gpio {
+ struct gpio_chip gpio_chip;
+ struct palmas *palmas;
+};
+
+static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct palmas_gpio, gpio_chip);
+}
+
+static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+ struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas *palmas = pg->palmas;
+ unsigned int val;
+ int ret;
+
+ ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_IN, &val);
+ if (ret < 0) {
+ dev_err(gc->dev, "GPIO_DATA_IN read failed, err = %d\n", ret);
+ return ret;
+ }
+ return !!(val & BIT(offset));
+}
+
+static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas *palmas = pg->palmas;
+ int ret;
+
+ if (value)
+ ret = palmas_write(palmas, PALMAS_GPIO_BASE,
+ PALMAS_GPIO_SET_DATA_OUT, BIT(offset));
+ else
+ ret = palmas_write(palmas, PALMAS_GPIO_BASE,
+ PALMAS_GPIO_CLEAR_DATA_OUT, BIT(offset));
+ if (ret < 0)
+ dev_err(gc->dev, "%s write failed, err = %d\n",
+ (value) ? "GPIO_SET_DATA_OUT" : "GPIO_CLEAR_DATA_OUT",
+ ret);
+}
+
+static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas *palmas = pg->palmas;
+ int ret;
+
+ /* Set the initial value */
+ palmas_gpio_set(gc, offset, value);
+
+ ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE,
+ PALMAS_GPIO_DATA_DIR, BIT(offset), BIT(offset));
+ if (ret < 0)
+ dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret);
+ return ret;
+}
+
+static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+ struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas *palmas = pg->palmas;
+ int ret;
+
+ ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE,
+ PALMAS_GPIO_DATA_DIR, BIT(offset), 0);
+ if (ret < 0)
+ dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret);
+ return ret;
+}
+
+static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas *palmas = pg->palmas;
+
+ return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
+}
+
+static int palmas_gpio_probe(struct platform_device *pdev)
+{
+ struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
+ struct palmas_platform_data *palmas_pdata;
+ struct palmas_gpio *palmas_gpio;
+ int ret;
+
+ palmas_gpio = devm_kzalloc(&pdev->dev,
+ sizeof(*palmas_gpio), GFP_KERNEL);
+ if (!palmas_gpio) {
+ dev_err(&pdev->dev, "Could not allocate palmas_gpio\n");
+ return -ENOMEM;
+ }
+
+ palmas_gpio->palmas = palmas;
+ palmas_gpio->gpio_chip.owner = THIS_MODULE;
+ palmas_gpio->gpio_chip.label = dev_name(&pdev->dev);
+ palmas_gpio->gpio_chip.ngpio = 8;
+ palmas_gpio->gpio_chip.can_sleep = 1;
+ palmas_gpio->gpio_chip.direction_input = palmas_gpio_input;
+ palmas_gpio->gpio_chip.direction_output = palmas_gpio_output;
+ palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;
+ palmas_gpio->gpio_chip.set = palmas_gpio_set;
+ palmas_gpio->gpio_chip.get = palmas_gpio_get;
+ palmas_gpio->gpio_chip.dev = &pdev->dev;
+#ifdef CONFIG_OF_GPIO
+ palmas_gpio->gpio_chip.of_node = palmas->dev->of_node;
+#endif
+ palmas_pdata = dev_get_platdata(palmas->dev);
+ if (palmas_pdata && palmas_pdata->gpio_base)
+ palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base;
+ else
+ palmas_gpio->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&palmas_gpio->gpio_chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, palmas_gpio);
+ return ret;
+}
+
+static int palmas_gpio_remove(struct platform_device *pdev)
+{
+ struct palmas_gpio *palmas_gpio = platform_get_drvdata(pdev);
+
+ return gpiochip_remove(&palmas_gpio->gpio_chip);
+}
+
+static struct platform_driver palmas_gpio_driver = {
+ .driver.name = "palmas-gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = palmas_gpio_probe,
+ .remove = palmas_gpio_remove,
+};
+
+static int __init palmas_gpio_init(void)
+{
+ return platform_driver_register(&palmas_gpio_driver);
+}
+subsys_initcall(palmas_gpio_init);
+
+static void __exit palmas_gpio_exit(void)
+{
+ platform_driver_unregister(&palmas_gpio_driver);
+}
+module_exit(palmas_gpio_exit);
+
+MODULE_ALIAS("platform:palmas-gpio");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("GPIO driver for TI Palmas series PMICs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index 76be7eed79de..b3643ff007e4 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -38,7 +38,6 @@
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
#include <plat/gpio-cfg-helpers.h>
-#include <plat/gpio-fns.h>
#include <plat/pm.h>
int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip,
@@ -3023,9 +3022,9 @@ static __init int samsung_gpiolib_init(void)
*/
struct device_node *pctrl_np;
static const struct of_device_id exynos_pinctrl_ids[] = {
- { .compatible = "samsung,pinctrl-exynos4210", },
- { .compatible = "samsung,pinctrl-exynos4x12", },
- { .compatible = "samsung,pinctrl-exynos5440", },
+ { .compatible = "samsung,exynos4210-pinctrl", },
+ { .compatible = "samsung,exynos4x12-pinctrl", },
+ { .compatible = "samsung,exynos5440-pinctrl", },
};
for_each_matching_node(pctrl_np, exynos_pinctrl_ids)
if (pctrl_np && of_device_is_available(pctrl_np))
diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c
index 5f45fc4ed5d1..7a4bf7c0d98f 100644
--- a/drivers/gpio/gpio-spear-spics.c
+++ b/drivers/gpio/gpio-spear-spics.c
@@ -140,11 +140,9 @@ static int spics_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
}
- spics->base = devm_request_and_ioremap(&pdev->dev, res);
- if (!spics->base) {
- dev_err(&pdev->dev, "request and ioremap fail\n");
- return -ENOMEM;
- }
+ spics->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(spics->base))
+ return PTR_ERR(spics->base);
if (of_property_read_u32(np, "st-spics,peripcfg-reg",
&spics->perip_cfg))
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index 85841ee70b17..c20e05151212 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -214,11 +214,10 @@ static int xway_stp_probe(struct platform_device *pdev)
if (!chip)
return -ENOMEM;
- chip->virt = devm_request_and_ioremap(&pdev->dev, res);
- if (!chip->virt) {
- dev_err(&pdev->dev, "failed to remap STP memory\n");
- return -ENOMEM;
- }
+ chip->virt = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(chip->virt))
+ return PTR_ERR(chip->virt);
+
chip->gc.dev = &pdev->dev;
chip->gc.label = "stp-xway";
chip->gc.direction_output = xway_stp_dir_out;
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 63cb643d4b5a..414ad912232f 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -17,6 +17,7 @@
*
*/
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
@@ -450,11 +451,9 @@ static int tegra_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
- regs = devm_request_and_ioremap(&pdev->dev, res);
- if (!regs) {
- dev_err(&pdev->dev, "Couldn't ioremap regs\n");
- return -ENODEV;
- }
+ regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
for (i = 0; i < tegra_gpio_bank_count; i++) {
for (j = 0; j < 4; j++) {
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index d542a141811a..a71a54a3e3f7 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -89,41 +89,6 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
EXPORT_SYMBOL(of_get_named_gpio_flags);
/**
- * of_gpio_named_count - Count GPIOs for a device
- * @np: device node to count GPIOs for
- * @propname: property name containing gpio specifier(s)
- *
- * The function returns the count of GPIOs specified for a node.
- *
- * Note that the empty GPIO specifiers counts too. For example,
- *
- * gpios = <0
- * &pio1 1 2
- * 0
- * &pio2 3 4>;
- *
- * defines four GPIOs (so this function will return 4), two of which
- * are not specified.
- */
-unsigned int of_gpio_named_count(struct device_node *np, const char* propname)
-{
- unsigned int cnt = 0;
-
- do {
- int ret;
-
- ret = of_parse_phandle_with_args(np, propname, "#gpio-cells",
- cnt, NULL);
- /* A hole in the gpios = <> counts anyway. */
- if (ret < 0 && ret != -EEXIST)
- break;
- } while (++cnt);
-
- return cnt;
-}
-EXPORT_SYMBOL(of_gpio_named_count);
-
-/**
* of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
* @gc: pointer to the gpio_chip structure
* @np: device node of the GPIO chip
@@ -250,7 +215,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
* on the same GPIO chip.
*/
ret = gpiochip_add_pin_range(chip,
- pinctrl_dev_get_name(pctldev),
+ pinctrl_dev_get_devname(pctldev),
0, /* offset in gpiochip */
pinspec.args[0],
pinspec.args[1]);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 199fca15f270..5359ca78130f 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -806,7 +806,7 @@ fail_unlock:
}
EXPORT_SYMBOL_GPL(gpio_export);
-static int match_export(struct device *dev, void *data)
+static int match_export(struct device *dev, const void *data)
{
return dev_get_drvdata(dev) == data;
}
diff --git a/drivers/gpu/drm/ast/Kconfig b/drivers/gpu/drm/ast/Kconfig
index a277b1257888..da4a51eae824 100644
--- a/drivers/gpu/drm/ast/Kconfig
+++ b/drivers/gpu/drm/ast/Kconfig
@@ -1,6 +1,6 @@
config DRM_AST
tristate "AST server chips"
- depends on DRM && PCI && EXPERIMENTAL
+ depends on DRM && PCI
select DRM_TTM
select FB_SYS_COPYAREA
select FB_SYS_FILLRECT
diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig
index fc154dd75296..bf67b22723f9 100644
--- a/drivers/gpu/drm/cirrus/Kconfig
+++ b/drivers/gpu/drm/cirrus/Kconfig
@@ -1,6 +1,6 @@
config DRM_CIRRUS_QEMU
tristate "Cirrus driver for QEMU emulated device"
- depends on DRM && PCI && EXPERIMENTAL
+ depends on DRM && PCI
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 67a83e69544b..411f69b76e84 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -1785,11 +1785,9 @@ static int fimc_probe(struct platform_device *pdev)
/* resource memory */
ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ctx->regs = devm_request_and_ioremap(dev, ctx->regs_res);
- if (!ctx->regs) {
- dev_err(dev, "failed to map registers.\n");
- return -ENXIO;
- }
+ ctx->regs = devm_ioremap_resource(dev, ctx->regs_res);
+ if (IS_ERR(ctx->regs))
+ return PTR_ERR(ctx->regs);
/* resource irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 9537761931ee..36493ce71f9a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -913,11 +913,9 @@ static int fimd_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ctx->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (!ctx->regs) {
- dev_err(dev, "failed to map registers\n");
- return -ENXIO;
- }
+ ctx->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ctx->regs))
+ return PTR_ERR(ctx->regs);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 0fcfbe4660bb..3b0da0378acf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -1137,10 +1137,9 @@ static int g2d_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- g2d->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (!g2d->regs) {
- dev_err(dev, "failed to remap I/O memory\n");
- ret = -ENXIO;
+ g2d->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(g2d->regs)) {
+ ret = PTR_ERR(g2d->regs);
goto err_put_clk;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 8140753ec9c8..7841c3b8a20e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -1692,11 +1692,9 @@ static int gsc_probe(struct platform_device *pdev)
/* resource memory */
ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ctx->regs = devm_request_and_ioremap(dev, ctx->regs_res);
- if (!ctx->regs) {
- dev_err(dev, "failed to map registers.\n");
- return -ENXIO;
- }
+ ctx->regs = devm_ioremap_resource(dev, ctx->regs_res);
+ if (IS_ERR(ctx->regs))
+ return PTR_ERR(ctx->regs);
/* resource irq */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index f976e29def6e..a40b9fb60240 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -656,11 +656,9 @@ static int rotator_probe(struct platform_device *pdev)
platform_get_device_id(pdev)->driver_data;
rot->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rot->regs = devm_request_and_ioremap(dev, rot->regs_res);
- if (!rot->regs) {
- dev_err(dev, "failed to map register\n");
- return -ENXIO;
- }
+ rot->regs = devm_ioremap_resource(dev, rot->regs_res);
+ if (IS_ERR(rot->regs))
+ return PTR_ERR(rot->regs);
rot->irq = platform_get_irq(pdev, 0);
if (rot->irq < 0) {
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 6d63f9090f94..2c5f266154ad 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -2226,11 +2226,9 @@ static int hdmi_probe(struct platform_device *pdev)
return -ENOENT;
}
- hdata->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (!hdata->regs) {
- DRM_ERROR("failed to map registers\n");
- return -ENXIO;
- }
+ hdata->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hdata->regs))
+ return PTR_ERR(hdata->regs);
ret = devm_gpio_request(&pdev->dev, hdata->hpd_gpio, "HPD");
if (ret) {
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig
index 42e665c7e90a..1188f0fe7e4f 100644
--- a/drivers/gpu/drm/gma500/Kconfig
+++ b/drivers/gpu/drm/gma500/Kconfig
@@ -1,6 +1,6 @@
config DRM_GMA500
tristate "Intel GMA5/600 KMS Framebuffer"
- depends on DRM && PCI && X86 && EXPERIMENTAL
+ depends on DRM && PCI && X86
select FB_CFB_COPYAREA
select FB_CFB_FILLRECT
select FB_CFB_IMAGEBLIT
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
index 51044cc55cf2..88d9ef6b5b4a 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -27,6 +27,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 7c65ab83914a..aae31489c893 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1550,7 +1550,7 @@ static const char *swizzle_string(unsigned swizzle)
case I915_BIT_6_SWIZZLE_9_10_17:
return "bit9/bit10/bit17";
case I915_BIT_6_SWIZZLE_UNKNOWN:
- return "unkown";
+ return "unknown";
}
return "bug";
diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig
index d63013497f66..b487cdec5ee7 100644
--- a/drivers/gpu/drm/mgag200/Kconfig
+++ b/drivers/gpu/drm/mgag200/Kconfig
@@ -1,6 +1,6 @@
config DRM_MGAG200
tristate "Kernel modesetting driver for MGA G200 server engines"
- depends on DRM && PCI && EXPERIMENTAL
+ depends on DRM && PCI
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
diff --git a/drivers/gpu/drm/nouveau/core/core/falcon.c b/drivers/gpu/drm/nouveau/core/core/falcon.c
index 6b0843c33877..e05c15777588 100644
--- a/drivers/gpu/drm/nouveau/core/core/falcon.c
+++ b/drivers/gpu/drm/nouveau/core/core/falcon.c
@@ -73,8 +73,11 @@ _nouveau_falcon_init(struct nouveau_object *object)
nv_debug(falcon, "data limit: %d\n", falcon->data.limit);
/* wait for 'uc halted' to be signalled before continuing */
- if (falcon->secret) {
- nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
+ if (falcon->secret && falcon->version < 4) {
+ if (!falcon->version)
+ nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
+ else
+ nv_wait(falcon, 0x180, 0x80000000, 0);
nv_wo32(falcon, 0x004, 0x00000010);
}
diff --git a/drivers/gpu/drm/nouveau/core/core/subdev.c b/drivers/gpu/drm/nouveau/core/core/subdev.c
index f74c30aa33a0..48f06378d3f9 100644
--- a/drivers/gpu/drm/nouveau/core/core/subdev.c
+++ b/drivers/gpu/drm/nouveau/core/core/subdev.c
@@ -99,7 +99,7 @@ nouveau_subdev_create_(struct nouveau_object *parent,
if (ret)
return ret;
- mutex_init(&subdev->mutex);
+ __mutex_init(&subdev->mutex, subname, &oclass->lock_class_key);
subdev->name = subname;
if (parent) {
diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h
index 6a902672f6f4..62e68baef087 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/object.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/object.h
@@ -50,10 +50,13 @@ int nouveau_object_fini(struct nouveau_object *, bool suspend);
extern struct nouveau_ofuncs nouveau_object_ofuncs;
+/* Don't allocate dynamically, because lockdep needs lock_class_keys to be in
+ * ".data". */
struct nouveau_oclass {
u32 handle;
- struct nouveau_ofuncs *ofuncs;
- struct nouveau_omthds *omthds;
+ struct nouveau_ofuncs * const ofuncs;
+ struct nouveau_omthds * const omthds;
+ struct lock_class_key lock_class_key;
};
#define nv_oclass(o) nv_object(o)->oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
index d6d16007ec1a..d62045f454b2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
@@ -86,8 +86,8 @@ nouveau_fb_preinit(struct nouveau_fb *pfb)
return ret;
}
- if (!nouveau_mm_initialised(&pfb->tags) && tags) {
- ret = nouveau_mm_init(&pfb->tags, 0, ++tags, 1);
+ if (!nouveau_mm_initialised(&pfb->tags)) {
+ ret = nouveau_mm_init(&pfb->tags, 0, tags ? ++tags : 0, 1);
if (ret)
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
index a4338d92b02e..0772ec978165 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
@@ -101,7 +101,7 @@ nv50_fb_vram_init(struct nouveau_fb *pfb)
struct nouveau_bios *bios = nouveau_bios(device);
const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
- u32 size;
+ u32 size, tags = 0;
int ret;
pfb->ram.size = nv_rd32(pfb, 0x10020c);
@@ -142,10 +142,11 @@ nv50_fb_vram_init(struct nouveau_fb *pfb)
return ret;
pfb->ram.ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
+ tags = nv_rd32(pfb, 0x100320);
break;
}
- return nv_rd32(pfb, 0x100320);
+ return tags;
}
static int
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 8a03c58ae988..d1099365bfc1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -275,6 +275,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
return 0;
}
+static struct lock_class_key drm_client_lock_class_key;
+
static int
nouveau_drm_load(struct drm_device *dev, unsigned long flags)
{
@@ -286,6 +288,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
if (ret)
return ret;
+ lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key);
dev->dev_private = drm;
drm->dev = dev;
diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig
index b724a4131435..09f65dc3d2c8 100644
--- a/drivers/gpu/drm/omapdrm/Kconfig
+++ b/drivers/gpu/drm/omapdrm/Kconfig
@@ -3,8 +3,8 @@ config DRM_OMAP
tristate "OMAP DRM"
depends on DRM && !CONFIG_FB_OMAP2
depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM
+ depends on OMAP2_DSS
select DRM_KMS_HELPER
- select OMAP2_DSS
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c
index 44284fd981fc..c451c41a7a7d 100644
--- a/drivers/gpu/drm/omapdrm/omap_connector.c
+++ b/drivers/gpu/drm/omapdrm/omap_connector.c
@@ -261,10 +261,8 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
omap_dss_get_device(dssdev);
omap_connector = kzalloc(sizeof(struct omap_connector), GFP_KERNEL);
- if (!omap_connector) {
- dev_err(dev->dev, "could not allocate connector\n");
+ if (!omap_connector)
goto fail;
- }
omap_connector->dssdev = dssdev;
omap_connector->encoder = encoder;
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index ac2258f59805..bec66a490b8f 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -599,11 +599,8 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
DBG("%s", channel_names[channel]);
omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
-
- if (!omap_crtc) {
- dev_err(dev->dev, "could not allocate CRTC\n");
+ if (!omap_crtc)
goto fail;
- }
crtc = &omap_crtc->base;
diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
index 391021537105..9b794c933c81 100644
--- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
+++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
@@ -581,10 +581,8 @@ static int omap_dmm_probe(struct platform_device *dev)
struct resource *mem;
omap_dmm = kzalloc(sizeof(*omap_dmm), GFP_KERNEL);
- if (!omap_dmm) {
- dev_err(&dev->dev, "failed to allocate driver data section\n");
+ if (!omap_dmm)
goto fail;
- }
/* initialize lists */
INIT_LIST_HEAD(&omap_dmm->alloc_head);
@@ -681,11 +679,9 @@ static int omap_dmm_probe(struct platform_device *dev)
}
/* alloc engines */
- omap_dmm->engines = kzalloc(
- omap_dmm->num_engines * sizeof(struct refill_engine),
- GFP_KERNEL);
+ omap_dmm->engines = kcalloc(omap_dmm->num_engines,
+ sizeof(struct refill_engine), GFP_KERNEL);
if (!omap_dmm->engines) {
- dev_err(&dev->dev, "could not allocate engines\n");
ret = -ENOMEM;
goto fail;
}
@@ -702,10 +698,9 @@ static int omap_dmm_probe(struct platform_device *dev)
list_add(&omap_dmm->engines[i].idle_node, &omap_dmm->idle_head);
}
- omap_dmm->tcm = kzalloc(omap_dmm->num_lut * sizeof(*omap_dmm->tcm),
+ omap_dmm->tcm = kcalloc(omap_dmm->num_lut, sizeof(*omap_dmm->tcm),
GFP_KERNEL);
if (!omap_dmm->tcm) {
- dev_err(&dev->dev, "failed to allocate lut ptrs\n");
ret = -ENOMEM;
goto fail;
}
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 9083538bd16a..079c54c6f94c 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -335,10 +335,8 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
DBG("load: dev=%p", dev);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(dev->dev, "could not allocate priv\n");
+ if (!priv)
return -ENOMEM;
- }
priv->omaprev = pdata->omaprev;
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c
index 7e1f2ab65372..21d126d0317e 100644
--- a/drivers/gpu/drm/omapdrm/omap_encoder.c
+++ b/drivers/gpu/drm/omapdrm/omap_encoder.c
@@ -147,10 +147,8 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev,
struct omap_encoder *omap_encoder;
omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL);
- if (!omap_encoder) {
- dev_err(dev->dev, "could not allocate encoder\n");
+ if (!omap_encoder)
goto fail;
- }
omap_encoder->dssdev = dssdev;
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index 9d5f6f696c72..8031402e7951 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -418,7 +418,6 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL);
if (!omap_fb) {
- dev_err(dev->dev, "could not allocate fb\n");
ret = -ENOMEM;
goto fail;
}
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index f0033bd3e4ae..b11ce609fcc2 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -332,10 +332,8 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev)
int ret = 0;
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
- if (!fbdev) {
- dev_err(dev->dev, "could not allocate fbdev\n");
+ if (!fbdev)
goto fail;
- }
INIT_WORK(&fbdev->work, pan_worker);
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c
index e8302b02691d..ebbdf4132e9c 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -1402,10 +1402,8 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
}
omap_obj = kzalloc(sizeof(*omap_obj), GFP_KERNEL);
- if (!omap_obj) {
- dev_err(dev->dev, "could not allocate GEM object\n");
+ if (!omap_obj)
goto fail;
- }
list_add(&omap_obj->mm_list, &priv->obj_list);
@@ -1461,11 +1459,9 @@ void omap_gem_init(struct drm_device *dev)
return;
}
- usergart = kzalloc(3 * sizeof(*usergart), GFP_KERNEL);
- if (!usergart) {
- dev_warn(dev->dev, "could not allocate usergart\n");
+ usergart = kcalloc(3, sizeof(*usergart), GFP_KERNEL);
+ if (!usergart)
return;
- }
/* reserve 4k aligned/wide regions for userspace mappings: */
for (i = 0; i < ARRAY_SIZE(fmts); i++) {
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index dd68d14ce615..2882cda6ea19 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -390,10 +390,8 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
DBG("%s: priv=%d", plane_names[id], private_plane);
omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
- if (!omap_plane) {
- dev_err(dev->dev, "could not allocate plane\n");
+ if (!omap_plane)
goto fail;
- }
ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL);
if (ret) {
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index d8f5d5fcd303..99fb13286fd0 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -2711,7 +2711,7 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
switch (sub_cmd) {
/* tiled */
case 8:
- dst_offset = ib[idx+1];
+ dst_offset = radeon_get_ib_value(p, idx+1);
dst_offset <<= 8;
ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
@@ -2719,15 +2719,15 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
break;
/* linear */
case 0:
- dst_offset = ib[idx+1];
- dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32;
+ dst_offset = radeon_get_ib_value(p, idx+1);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
p->idx += count + 3;
break;
default:
- DRM_ERROR("bad DMA_PACKET_WRITE [%6d] 0x%08x sub cmd is not 0 or 8\n", idx, ib[idx+0]);
+ DRM_ERROR("bad DMA_PACKET_WRITE [%6d] 0x%08x sub cmd is not 0 or 8\n", idx, header);
return -EINVAL;
}
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
@@ -2751,10 +2751,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
/* Copy L2L, DW aligned */
case 0x00:
/* L2L, dw */
- src_offset = ib[idx+2];
- src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
- dst_offset = ib[idx+1];
- dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
+ src_offset = radeon_get_ib_value(p, idx+2);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+ dst_offset = radeon_get_ib_value(p, idx+1);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
dev_warn(p->dev, "DMA L2L, dw src buffer too small (%llu %lu)\n",
src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -2774,24 +2774,24 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
/* Copy L2T/T2L */
case 0x08:
/* detile bit */
- if (ib[idx + 2] & (1 << 31)) {
+ if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) {
/* tiled src, linear dst */
- src_offset = ib[idx+1];
+ src_offset = radeon_get_ib_value(p, idx+1);
src_offset <<= 8;
ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
dst_offset = radeon_get_ib_value(p, idx + 7);
- dst_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
} else {
/* linear src, tiled dst */
- src_offset = ib[idx+7];
- src_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+ src_offset = radeon_get_ib_value(p, idx+7);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
- dst_offset = ib[idx+1];
+ dst_offset = radeon_get_ib_value(p, idx+1);
dst_offset <<= 8;
ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
}
@@ -2810,10 +2810,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
/* Copy L2L, byte aligned */
case 0x40:
/* L2L, byte */
- src_offset = ib[idx+2];
- src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
- dst_offset = ib[idx+1];
- dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
+ src_offset = radeon_get_ib_value(p, idx+2);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+ dst_offset = radeon_get_ib_value(p, idx+1);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
if ((src_offset + count) > radeon_bo_size(src_reloc->robj)) {
dev_warn(p->dev, "DMA L2L, byte src buffer too small (%llu %lu)\n",
src_offset + count, radeon_bo_size(src_reloc->robj));
@@ -2852,12 +2852,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n");
return -EINVAL;
}
- dst_offset = ib[idx+1];
- dst_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
- dst2_offset = ib[idx+2];
- dst2_offset |= ((u64)(ib[idx+5] & 0xff)) << 32;
- src_offset = ib[idx+3];
- src_offset |= ((u64)(ib[idx+6] & 0xff)) << 32;
+ dst_offset = radeon_get_ib_value(p, idx+1);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+ dst2_offset = radeon_get_ib_value(p, idx+2);
+ dst2_offset |= ((u64)(radeon_get_ib_value(p, idx+5) & 0xff)) << 32;
+ src_offset = radeon_get_ib_value(p, idx+3);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
dev_warn(p->dev, "DMA L2L, dw, broadcast src buffer too small (%llu %lu)\n",
src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -2883,7 +2883,7 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
break;
/* Copy L2T Frame to Field */
case 0x48:
- if (ib[idx + 2] & (1 << 31)) {
+ if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) {
DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n");
return -EINVAL;
}
@@ -2892,12 +2892,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n");
return -EINVAL;
}
- dst_offset = ib[idx+1];
+ dst_offset = radeon_get_ib_value(p, idx+1);
dst_offset <<= 8;
- dst2_offset = ib[idx+2];
+ dst2_offset = radeon_get_ib_value(p, idx+2);
dst2_offset <<= 8;
- src_offset = ib[idx+8];
- src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32;
+ src_offset = radeon_get_ib_value(p, idx+8);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
dev_warn(p->dev, "DMA L2T, frame to fields src buffer too small (%llu %lu)\n",
src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -2927,7 +2927,7 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
return -EINVAL;
}
/* detile bit */
- if (ib[idx + 2 ] & (1 << 31)) {
+ if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) {
/* tiled src, linear dst */
ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
@@ -2945,7 +2945,7 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
/* Copy L2T broadcast */
case 0x4b:
/* L2T, broadcast */
- if (ib[idx + 2] & (1 << 31)) {
+ if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) {
DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
return -EINVAL;
}
@@ -2954,12 +2954,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
return -EINVAL;
}
- dst_offset = ib[idx+1];
+ dst_offset = radeon_get_ib_value(p, idx+1);
dst_offset <<= 8;
- dst2_offset = ib[idx+2];
+ dst2_offset = radeon_get_ib_value(p, idx+2);
dst2_offset <<= 8;
- src_offset = ib[idx+8];
- src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32;
+ src_offset = radeon_get_ib_value(p, idx+8);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n",
src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -2985,24 +2985,24 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
case 0x4c:
/* L2T, T2L */
/* detile bit */
- if (ib[idx + 2] & (1 << 31)) {
+ if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) {
/* tiled src, linear dst */
- src_offset = ib[idx+1];
+ src_offset = radeon_get_ib_value(p, idx+1);
src_offset <<= 8;
ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
- dst_offset = ib[idx+7];
- dst_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+ dst_offset = radeon_get_ib_value(p, idx+7);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
} else {
/* linear src, tiled dst */
- src_offset = ib[idx+7];
- src_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+ src_offset = radeon_get_ib_value(p, idx+7);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
- dst_offset = ib[idx+1];
+ dst_offset = radeon_get_ib_value(p, idx+1);
dst_offset <<= 8;
ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
}
@@ -3032,7 +3032,7 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
/* Copy L2T broadcast (tile units) */
case 0x4f:
/* L2T, broadcast */
- if (ib[idx + 2] & (1 << 31)) {
+ if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) {
DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
return -EINVAL;
}
@@ -3041,12 +3041,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
return -EINVAL;
}
- dst_offset = ib[idx+1];
+ dst_offset = radeon_get_ib_value(p, idx+1);
dst_offset <<= 8;
- dst2_offset = ib[idx+2];
+ dst2_offset = radeon_get_ib_value(p, idx+2);
dst2_offset <<= 8;
- src_offset = ib[idx+8];
- src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32;
+ src_offset = radeon_get_ib_value(p, idx+8);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n",
src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -3069,7 +3069,7 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
p->idx += 10;
break;
default:
- DRM_ERROR("bad DMA_PACKET_COPY [%6d] 0x%08x invalid sub cmd\n", idx, ib[idx+0]);
+ DRM_ERROR("bad DMA_PACKET_COPY [%6d] 0x%08x invalid sub cmd\n", idx, header);
return -EINVAL;
}
break;
@@ -3079,8 +3079,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n");
return -EINVAL;
}
- dst_offset = ib[idx+1];
- dst_offset |= ((u64)(ib[idx+3] & 0x00ff0000)) << 16;
+ dst_offset = radeon_get_ib_value(p, idx+1);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16;
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n",
dst_offset, radeon_bo_size(dst_reloc->robj));
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 931a70289033..01a3ec83f284 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -2491,14 +2491,14 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
return -EINVAL;
}
if (tiled) {
- dst_offset = ib[idx+1];
+ dst_offset = radeon_get_ib_value(p, idx+1);
dst_offset <<= 8;
ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
p->idx += count + 5;
} else {
- dst_offset = ib[idx+1];
- dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32;
+ dst_offset = radeon_get_ib_value(p, idx+1);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
@@ -2526,32 +2526,32 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
/* detile bit */
if (idx_value & (1 << 31)) {
/* tiled src, linear dst */
- src_offset = ib[idx+1];
+ src_offset = radeon_get_ib_value(p, idx+1);
src_offset <<= 8;
ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
- dst_offset = ib[idx+5];
- dst_offset |= ((u64)(ib[idx+6] & 0xff)) << 32;
+ dst_offset = radeon_get_ib_value(p, idx+5);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
ib[idx+5] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
ib[idx+6] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
} else {
/* linear src, tiled dst */
- src_offset = ib[idx+5];
- src_offset |= ((u64)(ib[idx+6] & 0xff)) << 32;
+ src_offset = radeon_get_ib_value(p, idx+5);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
ib[idx+5] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
- dst_offset = ib[idx+1];
+ dst_offset = radeon_get_ib_value(p, idx+1);
dst_offset <<= 8;
ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
}
p->idx += 7;
} else {
if (p->family >= CHIP_RV770) {
- src_offset = ib[idx+2];
- src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
- dst_offset = ib[idx+1];
- dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
+ src_offset = radeon_get_ib_value(p, idx+2);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+ dst_offset = radeon_get_ib_value(p, idx+1);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
@@ -2559,10 +2559,10 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
p->idx += 5;
} else {
- src_offset = ib[idx+2];
- src_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
- dst_offset = ib[idx+1];
- dst_offset |= ((u64)(ib[idx+3] & 0xff0000)) << 16;
+ src_offset = radeon_get_ib_value(p, idx+2);
+ src_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
+ dst_offset = radeon_get_ib_value(p, idx+1);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff0000)) << 16;
ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
@@ -2592,8 +2592,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
DRM_ERROR("bad DMA_PACKET_WRITE\n");
return -EINVAL;
}
- dst_offset = ib[idx+1];
- dst_offset |= ((u64)(ib[idx+3] & 0x00ff0000)) << 16;
+ dst_offset = radeon_get_ib_value(p, idx+1);
+ dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16;
if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n",
dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index bf8095c55bd1..de94707b9dbe 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -12,8 +12,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-
-#include <mach/clk.h>
+#include <linux/clk/tegra.h>
#include "drm.h"
#include "dc.h"
@@ -1127,11 +1126,9 @@ static int tegra_dc_probe(struct platform_device *pdev)
return -ENXIO;
}
- dc->regs = devm_request_and_ioremap(&pdev->dev, regs);
- if (!dc->regs) {
- dev_err(&pdev->dev, "failed to remap registers\n");
- return -ENXIO;
- }
+ dc->regs = devm_ioremap_resource(&pdev->dev, regs);
+ if (IS_ERR(dc->regs))
+ return PTR_ERR(dc->regs);
dc->irq = platform_get_irq(pdev, 0);
if (dc->irq < 0) {
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 181a370c56c1..9d452df5bcad 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -11,7 +11,6 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
-#include <mach/clk.h>
#include <linux/dma-mapping.h>
#include <asm/dma-iommu.h>
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index 0daee8e2578b..bb747f6cd1a4 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -15,8 +15,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
-
-#include <mach/clk.h>
+#include <linux/clk/tegra.h>
#include <drm/drm_edid.h>
@@ -1251,9 +1250,9 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
if (!regs)
return -ENXIO;
- hdmi->regs = devm_request_and_ioremap(&pdev->dev, regs);
- if (!hdmi->regs)
- return -EADDRNOTAVAIL;
+ hdmi->regs = devm_ioremap_resource(&pdev->dev, regs);
+ if (IS_ERR(hdmi->regs))
+ return PTR_ERR(hdmi->regs);
err = platform_get_irq(pdev, 0);
if (err < 0)
diff --git a/drivers/gpu/drm/tegra/host1x.c b/drivers/gpu/drm/tegra/host1x.c
index 5d17b113a6fc..92e25a7e00ea 100644
--- a/drivers/gpu/drm/tegra/host1x.c
+++ b/drivers/gpu/drm/tegra/host1x.c
@@ -139,9 +139,9 @@ static int tegra_host1x_probe(struct platform_device *pdev)
host1x->irq = err;
- host1x->regs = devm_request_and_ioremap(&pdev->dev, regs);
- if (!host1x->regs) {
- err = -EADDRNOTAVAIL;
+ host1x->regs = devm_ioremap_resource(&pdev->dev, regs);
+ if (IS_ERR(host1x->regs)) {
+ err = PTR_ERR(host1x->regs);
goto err;
}
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 44420fca7dfa..8be35c809c7b 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -429,7 +429,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_bo_driver *driver = bdev->driver;
- fbo = kzalloc(sizeof(*fbo), GFP_KERNEL);
+ fbo = kmalloc(sizeof(*fbo), GFP_KERNEL);
if (!fbo)
return -ENOMEM;
@@ -448,7 +448,12 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
fbo->vm_node = NULL;
atomic_set(&fbo->cpu_writers, 0);
- fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj);
+ spin_lock(&bdev->fence_lock);
+ if (bo->sync_obj)
+ fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj);
+ else
+ fbo->sync_obj = NULL;
+ spin_unlock(&bdev->fence_lock);
kref_init(&fbo->list_kref);
kref_init(&fbo->kref);
fbo->destroy = &ttm_transfered_destroy;
@@ -661,13 +666,11 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
*/
set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
-
- /* ttm_buffer_object_transfer accesses bo->sync_obj */
- ret = ttm_buffer_object_transfer(bo, &ghost_obj);
spin_unlock(&bdev->fence_lock);
if (tmp_obj)
driver->sync_obj_unref(&tmp_obj);
+ ret = ttm_buffer_object_transfer(bo, &ghost_obj);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/udl/Kconfig b/drivers/gpu/drm/udl/Kconfig
index 56e0bf31d425..6222af19f456 100644
--- a/drivers/gpu/drm/udl/Kconfig
+++ b/drivers/gpu/drm/udl/Kconfig
@@ -1,6 +1,6 @@
config DRM_UDL
tristate "DisplayLink"
- depends on DRM && EXPERIMENTAL
+ depends on DRM
depends on USB_ARCH_HAS_HCD
select DRM_USB
select FB_SYS_FILLRECT
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e7d6a13ec6a6..5f07d85c4189 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -320,7 +320,7 @@ config HID_LOGITECH_DJ
Say Y if you want support for Logitech Unifying receivers and devices.
Unifying receivers are capable of pairing up to 6 Logitech compliant
devices to the same receiver. Without this driver it will be handled by
- generic USB_HID driver and all incomming events will be multiplexed
+ generic USB_HID driver and all incoming events will be multiplexed
into a single mouse and a single keyboard device.
config LOGITECH_FF
@@ -596,6 +596,12 @@ config HID_SPEEDLINK
---help---
Support for Speedlink Vicious and Divine Cezanne mouse.
+config HID_STEELSERIES
+ tristate "Steelseries SRW-S1 steering wheel support"
+ depends on USB_HID
+ ---help---
+ Support for Steelseries SRW-S1 steering wheel
+
config HID_SUNPLUS
tristate "Sunplus wireless desktop"
depends on USB_HID
@@ -655,6 +661,16 @@ config HID_TOPSEED
Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic
CLLRCMCE remote control.
+config HID_THINGM
+ tristate "ThingM blink(1) USB RGB LED"
+ depends on USB_HID
+ depends on LEDS_CLASS
+ ---help---
+ Support for the ThingM blink(1) USB RGB LED. This driver registers a
+ Linux LED class instance, plus additional sysfs attributes to control
+ RGB colors, fade time and playing. The device is exposed through hidraw
+ to access other functions.
+
config HID_THRUSTMASTER
tristate "ThrustMaster devices support"
depends on USB_HID
@@ -719,7 +735,7 @@ config HID_ZYDACRON
config HID_SENSOR_HUB
tristate "HID Sensors framework support"
- depends on USB_HID
+ depends on USB_HID && GENERIC_HARDIRQS
select MFD_CORE
default n
-- help---
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index b62215716b2f..72d1b0bc0a97 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -101,8 +101,10 @@ obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
obj-$(CONFIG_HID_SONY) += hid-sony.o
obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o
+obj-$(CONFIG_HID_STEELSERIES) += hid-steelseries.o
obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
+obj-$(CONFIG_HID_THINGM) += hid-thingm.o
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
obj-$(CONFIG_HID_TIVO) += hid-tivo.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
index 0a239885e67c..7c5507e94820 100644
--- a/drivers/hid/hid-a4tech.c
+++ b/drivers/hid/hid-a4tech.c
@@ -146,17 +146,6 @@ static struct hid_driver a4_driver = {
.probe = a4_probe,
.remove = a4_remove,
};
+module_hid_driver(a4_driver);
-static int __init a4_init(void)
-{
- return hid_register_driver(&a4_driver);
-}
-
-static void __exit a4_exit(void)
-{
- hid_unregister_driver(&a4_driver);
-}
-
-module_init(a4_init);
-module_exit(a4_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index d0f7662aacca..320a958d4139 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -555,23 +555,6 @@ static struct hid_driver apple_driver = {
.input_mapping = apple_input_mapping,
.input_mapped = apple_input_mapped,
};
+module_hid_driver(apple_driver);
-static int __init apple_init(void)
-{
- int ret;
-
- ret = hid_register_driver(&apple_driver);
- if (ret)
- pr_err("can't register apple driver\n");
-
- return ret;
-}
-
-static void __exit apple_exit(void)
-{
- hid_unregister_driver(&apple_driver);
-}
-
-module_init(apple_init);
-module_exit(apple_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-aureal.c b/drivers/hid/hid-aureal.c
index 7968187ddf7b..340ba9d394a0 100644
--- a/drivers/hid/hid-aureal.c
+++ b/drivers/hid/hid-aureal.c
@@ -37,17 +37,6 @@ static struct hid_driver aureal_driver = {
.id_table = aureal_devices,
.report_fixup = aureal_report_fixup,
};
+module_hid_driver(aureal_driver);
-static int __init aureal_init(void)
-{
- return hid_register_driver(&aureal_driver);
-}
-
-static void __exit aureal_exit(void)
-{
- hid_unregister_driver(&aureal_driver);
-}
-
-module_init(aureal_init);
-module_exit(aureal_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c
index 5be858dd9a15..62f0cee032ba 100644
--- a/drivers/hid/hid-axff.c
+++ b/drivers/hid/hid-axff.c
@@ -192,19 +192,7 @@ static struct hid_driver ax_driver = {
.probe = ax_probe,
.remove = ax_remove,
};
-
-static int __init ax_init(void)
-{
- return hid_register_driver(&ax_driver);
-}
-
-static void __exit ax_exit(void)
-{
- hid_unregister_driver(&ax_driver);
-}
-
-module_init(ax_init);
-module_exit(ax_exit);
+module_hid_driver(ax_driver);
MODULE_AUTHOR("Sergei Kolzun");
MODULE_DESCRIPTION("Force feedback support for ACRUX game controllers");
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c
index a1a5a12c3a6b..cc4cf138bef5 100644
--- a/drivers/hid/hid-belkin.c
+++ b/drivers/hid/hid-belkin.c
@@ -86,17 +86,6 @@ static struct hid_driver belkin_driver = {
.input_mapping = belkin_input_mapping,
.probe = belkin_probe,
};
+module_hid_driver(belkin_driver);
-static int __init belkin_init(void)
-{
- return hid_register_driver(&belkin_driver);
-}
-
-static void __exit belkin_exit(void)
-{
- hid_unregister_driver(&belkin_driver);
-}
-
-module_init(belkin_init);
-module_exit(belkin_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
index af034d3d9256..1bdcccc54a1d 100644
--- a/drivers/hid/hid-cherry.c
+++ b/drivers/hid/hid-cherry.c
@@ -69,17 +69,6 @@ static struct hid_driver ch_driver = {
.report_fixup = ch_report_fixup,
.input_mapping = ch_input_mapping,
};
+module_hid_driver(ch_driver);
-static int __init ch_init(void)
-{
- return hid_register_driver(&ch_driver);
-}
-
-static void __exit ch_exit(void)
-{
- hid_unregister_driver(&ch_driver);
-}
-
-module_init(ch_init);
-module_exit(ch_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c
index a2abb8e15727..b613d5a79684 100644
--- a/drivers/hid/hid-chicony.c
+++ b/drivers/hid/hid-chicony.c
@@ -70,17 +70,6 @@ static struct hid_driver ch_driver = {
.id_table = ch_devices,
.input_mapping = ch_input_mapping,
};
+module_hid_driver(ch_driver);
-static int __init ch_init(void)
-{
- return hid_register_driver(&ch_driver);
-}
-
-static void __exit ch_exit(void)
-{
- hid_unregister_driver(&ch_driver);
-}
-
-module_init(ch_init);
-module_exit(ch_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index eb2ee11b6412..512b01c04ea7 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -729,7 +729,7 @@ static int hid_scan_report(struct hid_device *hid)
item.type == HID_ITEM_TYPE_MAIN &&
item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION &&
(item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL &&
- hid->bus == BUS_USB)
+ (hid->bus == BUS_USB || hid->bus == BUS_I2C))
hid->group = HID_GROUP_SENSOR_HUB;
}
@@ -1195,6 +1195,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
{
struct hid_report_enum *report_enum = hid->report_enum + type;
struct hid_report *report;
+ struct hid_driver *hdrv;
unsigned int a;
int rsize, csize = size;
u8 *cdata = data;
@@ -1231,6 +1232,9 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
if (hid->claimed != HID_CLAIMED_HIDRAW) {
for (a = 0; a < report->maxfield; a++)
hid_input_field(hid, report->field[a], cdata, interrupt);
+ hdrv = hid->driver;
+ if (hdrv && hdrv->report)
+ hdrv->report(hid, report);
}
if (hid->claimed & HID_CLAIMED_INPUT)
@@ -1599,6 +1603,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
@@ -1697,7 +1702,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ 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_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
@@ -2070,6 +2077,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ 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_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MASTERKIT, USB_DEVICE_ID_MASTERKIT_MA901RADIO) },
{ 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) },
@@ -2228,6 +2236,14 @@ bool hid_ignore(struct hid_device *hdev)
hdev->type != HID_TYPE_USBMOUSE)
return true;
break;
+ case USB_VENDOR_ID_VELLEMAN:
+ /* These are not HID devices. They are handled by comedi. */
+ if ((hdev->product >= USB_DEVICE_ID_VELLEMAN_K8055_FIRST &&
+ hdev->product <= USB_DEVICE_ID_VELLEMAN_K8055_LAST) ||
+ (hdev->product >= USB_DEVICE_ID_VELLEMAN_K8061_FIRST &&
+ hdev->product <= USB_DEVICE_ID_VELLEMAN_K8061_LAST))
+ return true;
+ break;
}
if (hdev->type == HID_TYPE_USBMOUSE &&
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
index 3e159a50dac7..c4ef3bc726e3 100644
--- a/drivers/hid/hid-cypress.c
+++ b/drivers/hid/hid-cypress.c
@@ -144,17 +144,6 @@ static struct hid_driver cp_driver = {
.event = cp_event,
.probe = cp_probe,
};
+module_hid_driver(cp_driver);
-static int __init cp_init(void)
-{
- return hid_register_driver(&cp_driver);
-}
-
-static void __exit cp_exit(void)
-{
- hid_unregister_driver(&cp_driver);
-}
-
-module_init(cp_init);
-module_exit(cp_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c
index e832f44ae383..0fe8f65ef01a 100644
--- a/drivers/hid/hid-dr.c
+++ b/drivers/hid/hid-dr.c
@@ -297,17 +297,6 @@ static struct hid_driver dr_driver = {
.report_fixup = dr_report_fixup,
.probe = dr_probe,
};
+module_hid_driver(dr_driver);
-static int __init dr_init(void)
-{
- return hid_register_driver(&dr_driver);
-}
-
-static void __exit dr_exit(void)
-{
- hid_unregister_driver(&dr_driver);
-}
-
-module_init(dr_init);
-module_exit(dr_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c
index 79d0c61e7214..d0bd13b62dc2 100644
--- a/drivers/hid/hid-elecom.c
+++ b/drivers/hid/hid-elecom.c
@@ -41,17 +41,6 @@ static struct hid_driver elecom_driver = {
.id_table = elecom_devices,
.report_fixup = elecom_report_fixup
};
+module_hid_driver(elecom_driver);
-static int __init elecom_init(void)
-{
- return hid_register_driver(&elecom_driver);
-}
-
-static void __exit elecom_exit(void)
-{
- hid_unregister_driver(&elecom_driver);
-}
-
-module_init(elecom_init);
-module_exit(elecom_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c
index 2630d483d262..2e093ab99b43 100644
--- a/drivers/hid/hid-emsff.c
+++ b/drivers/hid/hid-emsff.c
@@ -150,18 +150,7 @@ static struct hid_driver ems_driver = {
.id_table = ems_devices,
.probe = ems_probe,
};
+module_hid_driver(ems_driver);
-static int ems_init(void)
-{
- return hid_register_driver(&ems_driver);
-}
-
-static void ems_exit(void)
-{
- hid_unregister_driver(&ems_driver);
-}
-
-module_init(ems_init);
-module_exit(ems_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c
index 6540af2871a7..212ac6be2451 100644
--- a/drivers/hid/hid-ezkey.c
+++ b/drivers/hid/hid-ezkey.c
@@ -76,17 +76,6 @@ static struct hid_driver ez_driver = {
.input_mapping = ez_input_mapping,
.event = ez_event,
};
+module_hid_driver(ez_driver);
-static int __init ez_init(void)
-{
- return hid_register_driver(&ez_driver);
-}
-
-static void __exit ez_exit(void)
-{
- hid_unregister_driver(&ez_driver);
-}
-
-module_init(ez_init);
-module_exit(ez_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c
index f1e1bcf67427..04d2e6aca778 100644
--- a/drivers/hid/hid-gaff.c
+++ b/drivers/hid/hid-gaff.c
@@ -176,17 +176,6 @@ static struct hid_driver ga_driver = {
.id_table = ga_devices,
.probe = ga_probe,
};
+module_hid_driver(ga_driver);
-static int __init ga_init(void)
-{
- return hid_register_driver(&ga_driver);
-}
-
-static void __exit ga_exit(void)
-{
- hid_unregister_driver(&ga_driver);
-}
-
-module_init(ga_init);
-module_exit(ga_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c
index a8b3148e03a2..e288a4a06fe8 100644
--- a/drivers/hid/hid-generic.c
+++ b/drivers/hid/hid-generic.c
@@ -34,19 +34,7 @@ static struct hid_driver hid_generic = {
.name = "hid-generic",
.id_table = hid_table,
};
-
-static int __init hid_init(void)
-{
- return hid_register_driver(&hid_generic);
-}
-
-static void __exit hid_exit(void)
-{
- hid_unregister_driver(&hid_generic);
-}
-
-module_init(hid_init);
-module_exit(hid_exit);
+module_hid_driver(hid_generic);
MODULE_AUTHOR("Henrik Rydberg");
MODULE_DESCRIPTION("HID generic driver");
diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c
index 4442c30ef531..288d61c9748e 100644
--- a/drivers/hid/hid-gyration.c
+++ b/drivers/hid/hid-gyration.c
@@ -88,17 +88,6 @@ static struct hid_driver gyration_driver = {
.input_mapping = gyration_input_mapping,
.event = gyration_event,
};
+module_hid_driver(gyration_driver);
-static int __init gyration_init(void)
-{
- return hid_register_driver(&gyration_driver);
-}
-
-static void __exit gyration_exit(void)
-{
- hid_unregister_driver(&gyration_driver);
-}
-
-module_init(gyration_init);
-module_exit(gyration_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-holtek-kbd.c b/drivers/hid/hid-holtek-kbd.c
index e0a5d1739fc3..6e1a4a4fc0c1 100644
--- a/drivers/hid/hid-holtek-kbd.c
+++ b/drivers/hid/hid-holtek-kbd.c
@@ -167,17 +167,6 @@ static struct hid_driver holtek_kbd_driver = {
.report_fixup = holtek_kbd_report_fixup,
.probe = holtek_kbd_probe
};
+module_hid_driver(holtek_kbd_driver);
-static int __init holtek_kbd_init(void)
-{
- return hid_register_driver(&holtek_kbd_driver);
-}
-
-static void __exit holtek_kbd_exit(void)
-{
- hid_unregister_driver(&holtek_kbd_driver);
-}
-
-module_exit(holtek_kbd_exit);
-module_init(holtek_kbd_init);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-holtekff.c b/drivers/hid/hid-holtekff.c
index ff295e60059b..f34d1186a3e1 100644
--- a/drivers/hid/hid-holtekff.c
+++ b/drivers/hid/hid-holtekff.c
@@ -224,17 +224,4 @@ static struct hid_driver holtek_driver = {
.id_table = holtek_devices,
.probe = holtek_probe,
};
-
-static int __init holtek_init(void)
-{
- return hid_register_driver(&holtek_driver);
-}
-
-static void __exit holtek_exit(void)
-{
- hid_unregister_driver(&holtek_driver);
-}
-
-module_init(holtek_init);
-module_exit(holtek_exit);
-
+module_hid_driver(holtek_driver);
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 3d62781b8993..aa3fec0d9dc6 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -568,8 +568,7 @@ static int mousevsc_remove(struct hv_device *dev)
static const struct hv_vmbus_device_id id_table[] = {
/* Mouse guid */
- { VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
- 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
+ { HV_MOUSE_GUID, },
{ },
};
diff --git a/drivers/hid/hid-icade.c b/drivers/hid/hid-icade.c
index 1d6565e37ba3..09dcc04595f3 100644
--- a/drivers/hid/hid-icade.c
+++ b/drivers/hid/hid-icade.c
@@ -235,25 +235,8 @@ static struct hid_driver icade_driver = {
.input_mapped = icade_input_mapped,
.input_mapping = icade_input_mapping,
};
+module_hid_driver(icade_driver);
-static int __init icade_init(void)
-{
- int ret;
-
- ret = hid_register_driver(&icade_driver);
- if (ret)
- pr_err("can't register icade driver\n");
-
- return ret;
-}
-
-static void __exit icade_exit(void)
-{
- hid_unregister_driver(&icade_driver);
-}
-
-module_init(icade_init);
-module_exit(icade_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
MODULE_DESCRIPTION("ION iCade input driver");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 34e25471aeaa..92e47e5c9564 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -445,6 +445,9 @@
#define USB_VENDOR_ID_JESS 0x0c45
#define USB_DEVICE_ID_JESS_YUREX 0x1010
+#define USB_VENDOR_ID_JESS2 0x0f30
+#define USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD 0x0111
+
#define USB_VENDOR_ID_KBGEAR 0x084e
#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
@@ -525,8 +528,8 @@
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287
-#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
+#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
@@ -554,6 +557,9 @@
#define USB_VENDOR_ID_MADCATZ 0x0738
#define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540
+#define USB_VENDOR_ID_MASTERKIT 0x16c0
+#define USB_DEVICE_ID_MASTERKIT_MA901RADIO 0x05df
+
#define USB_VENDOR_ID_MCC 0x09db
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a
@@ -597,6 +603,9 @@
#define USB_VENDOR_ID_NEC 0x073e
#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
+#define USB_VENDOR_ID_NEXIO 0x1870
+#define USB_DEVICE_ID_NEXIO_MULTITOUCH_420 0x010d
+
#define USB_VENDOR_ID_NEXTWINDOW 0x1926
#define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003
@@ -709,6 +718,7 @@
#define USB_VENDOR_ID_SONY 0x054c
#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b
+#define USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE 0x0374
#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
@@ -726,6 +736,9 @@
#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403
#define USB_DEVICE_ID_MTP_SITRONIX 0x5001
+#define USB_VENDOR_ID_STEELSERIES 0x1038
+#define USB_DEVICE_ID_STEELSERIES_SRWS1 0x1410
+
#define USB_VENDOR_ID_SUN 0x0430
#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
@@ -747,6 +760,9 @@
#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010
#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013
+#define USB_VENDOR_ID_THINGM 0x27b8
+#define USB_DEVICE_ID_BLINK1 0x01ed
+
#define USB_VENDOR_ID_THRUSTMASTER 0x044f
#define USB_VENDOR_ID_TIVO 0x150a
@@ -794,6 +810,12 @@
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19 0x0a19
+#define USB_VENDOR_ID_VELLEMAN 0x10cf
+#define USB_DEVICE_ID_VELLEMAN_K8055_FIRST 0x5500
+#define USB_DEVICE_ID_VELLEMAN_K8055_LAST 0x5503
+#define USB_DEVICE_ID_VELLEMAN_K8061_FIRST 0x8061
+#define USB_DEVICE_ID_VELLEMAN_K8061_LAST 0x8068
+
#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-kensington.c b/drivers/hid/hid-kensington.c
index a5b4016e9bd7..fe9a99dd8d08 100644
--- a/drivers/hid/hid-kensington.c
+++ b/drivers/hid/hid-kensington.c
@@ -47,17 +47,6 @@ static struct hid_driver ks_driver = {
.id_table = ks_devices,
.input_mapping = ks_input_mapping,
};
+module_hid_driver(ks_driver);
-static int __init ks_init(void)
-{
- return hid_register_driver(&ks_driver);
-}
-
-static void __exit ks_exit(void)
-{
- hid_unregister_driver(&ks_driver);
-}
-
-module_init(ks_init);
-module_exit(ks_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-keytouch.c b/drivers/hid/hid-keytouch.c
index 07cd825f6f01..3074671b7d6a 100644
--- a/drivers/hid/hid-keytouch.c
+++ b/drivers/hid/hid-keytouch.c
@@ -49,18 +49,7 @@ static struct hid_driver keytouch_driver = {
.id_table = keytouch_devices,
.report_fixup = keytouch_report_fixup,
};
+module_hid_driver(keytouch_driver);
-static int __init keytouch_init(void)
-{
- return hid_register_driver(&keytouch_driver);
-}
-
-static void __exit keytouch_exit(void)
-{
- hid_unregister_driver(&keytouch_driver);
-}
-
-module_init(keytouch_init);
-module_exit(keytouch_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jiri Kosina");
diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c
index b4f0d8216fd0..ef72daecfa16 100644
--- a/drivers/hid/hid-kye.c
+++ b/drivers/hid/hid-kye.c
@@ -419,17 +419,6 @@ static struct hid_driver kye_driver = {
.probe = kye_probe,
.report_fixup = kye_report_fixup,
};
+module_hid_driver(kye_driver);
-static int __init kye_init(void)
-{
- return hid_register_driver(&kye_driver);
-}
-
-static void __exit kye_exit(void)
-{
- hid_unregister_driver(&kye_driver);
-}
-
-module_init(kye_init);
-module_exit(kye_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lcpower.c b/drivers/hid/hid-lcpower.c
index 22bc14abdfa3..6424cfdb7737 100644
--- a/drivers/hid/hid-lcpower.c
+++ b/drivers/hid/hid-lcpower.c
@@ -54,17 +54,6 @@ static struct hid_driver ts_driver = {
.id_table = ts_devices,
.input_mapping = ts_input_mapping,
};
+module_hid_driver(ts_driver);
-static int __init ts_init(void)
-{
- return hid_register_driver(&ts_driver);
-}
-
-static void __exit ts_exit(void)
-{
- hid_unregister_driver(&ts_driver);
-}
-
-module_init(ts_init);
-module_exit(ts_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c
index cea016e94f43..956c3b135f64 100644
--- a/drivers/hid/hid-lenovo-tpkbd.c
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -468,18 +468,6 @@ static struct hid_driver tpkbd_driver = {
.probe = tpkbd_probe,
.remove = tpkbd_remove,
};
-
-static int __init tpkbd_init(void)
-{
- return hid_register_driver(&tpkbd_driver);
-}
-
-static void __exit tpkbd_exit(void)
-{
- hid_unregister_driver(&tpkbd_driver);
-}
-
-module_init(tpkbd_init);
-module_exit(tpkbd_exit);
+module_hid_driver(tpkbd_driver);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index a2f8e88b9fa2..6f12ecd36c88 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -21,8 +21,10 @@
#include <linux/module.h>
#include <linux/random.h>
#include <linux/sched.h>
+#include <linux/usb.h>
#include <linux/wait.h>
+#include "usbhid/usbhid.h"
#include "hid-ids.h"
#include "hid-lg.h"
@@ -40,17 +42,86 @@
#define LG_FF3 0x1000
#define LG_FF4 0x2000
-/* Size of the original descriptor of the Driving Force Pro wheel */
+/* Size of the original descriptors of the Driving Force (and Pro) wheels */
+#define DF_RDESC_ORIG_SIZE 130
#define DFP_RDESC_ORIG_SIZE 97
+#define MOMO_RDESC_ORIG_SIZE 87
-/* Fixed report descriptor for Logitech Driving Force Pro wheel controller
+/* Fixed report descriptors for Logitech Driving Force (and Pro)
+ * wheel controllers
*
- * The original descriptor hides the separate throttle and brake axes in
+ * The original descriptors hide the separate throttle and brake axes in
* a custom vendor usage page, providing only a combined value as
* GenericDesktop.Y.
- * This descriptor removes the combined Y axis and instead reports
+ * These descriptors remove the combined Y axis and instead report
* separate throttle (Y) and brake (RZ).
*/
+static __u8 df_rdesc_fixed[] = {
+0x05, 0x01, /* Usage Page (Desktop), */
+0x09, 0x04, /* Usage (Joystik), */
+0xA1, 0x01, /* Collection (Application), */
+0xA1, 0x02, /* Collection (Logical), */
+0x95, 0x01, /* Report Count (1), */
+0x75, 0x0A, /* Report Size (10), */
+0x14, /* Logical Minimum (0), */
+0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+0x34, /* Physical Minimum (0), */
+0x46, 0xFF, 0x03, /* Physical Maximum (1023), */
+0x09, 0x30, /* Usage (X), */
+0x81, 0x02, /* Input (Variable), */
+0x95, 0x0C, /* Report Count (12), */
+0x75, 0x01, /* Report Size (1), */
+0x25, 0x01, /* Logical Maximum (1), */
+0x45, 0x01, /* Physical Maximum (1), */
+0x05, 0x09, /* Usage (Buttons), */
+0x19, 0x01, /* Usage Minimum (1), */
+0x29, 0x0c, /* Usage Maximum (12), */
+0x81, 0x02, /* Input (Variable), */
+0x95, 0x02, /* Report Count (2), */
+0x06, 0x00, 0xFF, /* Usage Page (Vendor: 65280), */
+0x09, 0x01, /* Usage (?: 1), */
+0x81, 0x02, /* Input (Variable), */
+0x05, 0x01, /* Usage Page (Desktop), */
+0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+0x46, 0xFF, 0x00, /* Physical Maximum (255), */
+0x95, 0x01, /* Report Count (1), */
+0x75, 0x08, /* Report Size (8), */
+0x81, 0x02, /* Input (Variable), */
+0x25, 0x07, /* Logical Maximum (7), */
+0x46, 0x3B, 0x01, /* Physical Maximum (315), */
+0x75, 0x04, /* Report Size (4), */
+0x65, 0x14, /* Unit (Degrees), */
+0x09, 0x39, /* Usage (Hat Switch), */
+0x81, 0x42, /* Input (Variable, Null State), */
+0x75, 0x01, /* Report Size (1), */
+0x95, 0x04, /* Report Count (4), */
+0x65, 0x00, /* Unit (none), */
+0x06, 0x00, 0xFF, /* Usage Page (Vendor: 65280), */
+0x09, 0x01, /* Usage (?: 1), */
+0x25, 0x01, /* Logical Maximum (1), */
+0x45, 0x01, /* Physical Maximum (1), */
+0x81, 0x02, /* Input (Variable), */
+0x05, 0x01, /* Usage Page (Desktop), */
+0x95, 0x01, /* Report Count (1), */
+0x75, 0x08, /* Report Size (8), */
+0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+0x46, 0xFF, 0x00, /* Physical Maximum (255), */
+0x09, 0x31, /* Usage (Y), */
+0x81, 0x02, /* Input (Variable), */
+0x09, 0x35, /* Usage (Rz), */
+0x81, 0x02, /* Input (Variable), */
+0xC0, /* End Collection, */
+0xA1, 0x02, /* Collection (Logical), */
+0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+0x46, 0xFF, 0x00, /* Physical Maximum (255), */
+0x95, 0x07, /* Report Count (7), */
+0x75, 0x08, /* Report Size (8), */
+0x09, 0x03, /* Usage (?: 3), */
+0x91, 0x02, /* Output (Variable), */
+0xC0, /* End Collection, */
+0xC0 /* End Collection */
+};
+
static __u8 dfp_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
@@ -99,6 +170,51 @@ static __u8 dfp_rdesc_fixed[] = {
0xC0 /* End Collection */
};
+static __u8 momo_rdesc_fixed[] = {
+0x05, 0x01, /* Usage Page (Desktop), */
+0x09, 0x04, /* Usage (Joystik), */
+0xA1, 0x01, /* Collection (Application), */
+0xA1, 0x02, /* Collection (Logical), */
+0x95, 0x01, /* Report Count (1), */
+0x75, 0x0A, /* Report Size (10), */
+0x15, 0x00, /* Logical Minimum (0), */
+0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+0x35, 0x00, /* Physical Minimum (0), */
+0x46, 0xFF, 0x03, /* Physical Maximum (1023), */
+0x09, 0x30, /* Usage (X), */
+0x81, 0x02, /* Input (Variable), */
+0x95, 0x08, /* Report Count (8), */
+0x75, 0x01, /* Report Size (1), */
+0x25, 0x01, /* Logical Maximum (1), */
+0x45, 0x01, /* Physical Maximum (1), */
+0x05, 0x09, /* Usage Page (Button), */
+0x19, 0x01, /* Usage Minimum (01h), */
+0x29, 0x08, /* Usage Maximum (08h), */
+0x81, 0x02, /* Input (Variable), */
+0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+0x75, 0x0E, /* Report Size (14), */
+0x95, 0x01, /* Report Count (1), */
+0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+0x46, 0xFF, 0x00, /* Physical Maximum (255), */
+0x09, 0x00, /* Usage (00h), */
+0x81, 0x02, /* Input (Variable), */
+0x05, 0x01, /* Usage Page (Desktop), */
+0x75, 0x08, /* Report Size (8), */
+0x09, 0x31, /* Usage (Y), */
+0x81, 0x02, /* Input (Variable), */
+0x09, 0x32, /* Usage (Z), */
+0x81, 0x02, /* Input (Variable), */
+0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+0x09, 0x01, /* Usage (01h), */
+0x81, 0x02, /* Input (Variable), */
+0xC0, /* End Collection, */
+0xA1, 0x02, /* Collection (Logical), */
+0x09, 0x02, /* Usage (02h), */
+0x95, 0x07, /* Report Count (7), */
+0x91, 0x02, /* Output (Variable), */
+0xC0, /* End Collection, */
+0xC0 /* End Collection */
+};
/*
* Certain Logitech keyboards send in report #3 keys which are far
@@ -109,6 +225,8 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
+ struct usb_device_descriptor *udesc;
+ __u16 bcdDevice, rev_maj, rev_min;
if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
rdesc[84] == 0x8c && rdesc[85] == 0x02) {
@@ -124,17 +242,39 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
"fixing up rel/abs in Logitech report descriptor\n");
rdesc[33] = rdesc[50] = 0x02;
}
- if ((drv_data->quirks & LG_FF4) && *rsize >= 101 &&
- rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
- rdesc[47] == 0x05 && rdesc[48] == 0x09) {
- hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n");
- rdesc[41] = 0x05;
- rdesc[42] = 0x09;
- rdesc[47] = 0x95;
- rdesc[48] = 0x0B;
- }
switch (hdev->product) {
+
+ /* Several wheels report as this id when operating in emulation mode. */
+ case USB_DEVICE_ID_LOGITECH_WHEEL:
+ udesc = &(hid_to_usb_dev(hdev)->descriptor);
+ if (!udesc) {
+ hid_err(hdev, "NULL USB device descriptor\n");
+ break;
+ }
+ bcdDevice = le16_to_cpu(udesc->bcdDevice);
+ rev_maj = bcdDevice >> 8;
+ rev_min = bcdDevice & 0xff;
+
+ /* Update the report descriptor for only the Driving Force wheel */
+ if (rev_maj == 1 && rev_min == 2 &&
+ *rsize == DF_RDESC_ORIG_SIZE) {
+ hid_info(hdev,
+ "fixing up Logitech Driving Force report descriptor\n");
+ rdesc = df_rdesc_fixed;
+ *rsize = sizeof(df_rdesc_fixed);
+ }
+ break;
+
+ case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
+ if (*rsize == MOMO_RDESC_ORIG_SIZE) {
+ hid_info(hdev,
+ "fixing up Logitech Momo Force (Red) report descriptor\n");
+ rdesc = momo_rdesc_fixed;
+ *rsize = sizeof(momo_rdesc_fixed);
+ }
+ break;
+
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
if (*rsize == DFP_RDESC_ORIG_SIZE) {
hid_info(hdev,
@@ -143,6 +283,17 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*rsize = sizeof(dfp_rdesc_fixed);
}
break;
+
+ case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
+ if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
+ rdesc[47] == 0x05 && rdesc[48] == 0x09) {
+ hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
+ rdesc[41] = 0x05;
+ rdesc[42] = 0x09;
+ rdesc[47] = 0x95;
+ rdesc[48] = 0x0B;
+ }
+ break;
}
return rdesc;
@@ -328,6 +479,26 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
usage->type == EV_REL || usage->type == EV_ABS))
clear_bit(usage->code, *bit);
+ /* Ensure that Logitech wheels are not given a default fuzz/flat value */
+ if (usage->type == EV_ABS && (usage->code == ABS_X ||
+ usage->code == ABS_Y || usage->code == ABS_Z ||
+ usage->code == ABS_RZ)) {
+ switch (hdev->product) {
+ case USB_DEVICE_ID_LOGITECH_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
+ case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
+ field->application = HID_GD_MULTIAXIS;
+ break;
+ default:
+ break;
+ }
+ }
+
return 0;
}
@@ -465,7 +636,7 @@ static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
- .driver_data = LG_FF4 },
+ .driver_data = LG_NOGET | LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
.driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
@@ -503,17 +674,6 @@ static struct hid_driver lg_driver = {
.probe = lg_probe,
.remove = lg_remove,
};
+module_hid_driver(lg_driver);
-static int __init lg_init(void)
-{
- return hid_register_driver(&lg_driver);
-}
-
-static void __exit lg_exit(void)
-{
- hid_unregister_driver(&lg_driver);
-}
-
-module_init(lg_init);
-module_exit(lg_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index d7947c701f30..65a6ec8d3742 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -43,11 +43,6 @@
#define G27_REV_MAJ 0x12
#define G27_REV_MIN 0x38
-#define DFP_X_MIN 0
-#define DFP_X_MAX 16383
-#define DFP_PEDAL_MIN 0
-#define DFP_PEDAL_MAX 255
-
#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
@@ -598,18 +593,6 @@ int lg4ff_init(struct hid_device *hid)
return error;
dbg_hid("sysfs interface created\n");
- /* Set default axes parameters */
- switch (lg4ff_devices[i].product_id) {
- case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
- dbg_hid("Setting axes parameters for Driving Force Pro\n");
- input_set_abs_params(dev, ABS_X, DFP_X_MIN, DFP_X_MAX, 0, 0);
- input_set_abs_params(dev, ABS_Y, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0);
- input_set_abs_params(dev, ABS_RZ, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0);
- break;
- default:
- break;
- }
-
/* Set the maximum range to start with */
entry->range = entry->max_range;
if (entry->set_range != NULL)
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 25ddf3e3aec6..f7f113ba083e 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -569,23 +569,6 @@ static struct hid_driver magicmouse_driver = {
.raw_event = magicmouse_raw_event,
.input_mapping = magicmouse_input_mapping,
};
+module_hid_driver(magicmouse_driver);
-static int __init magicmouse_init(void)
-{
- int ret;
-
- ret = hid_register_driver(&magicmouse_driver);
- if (ret)
- pr_err("can't register magicmouse driver\n");
-
- return ret;
-}
-
-static void __exit magicmouse_exit(void)
-{
- hid_unregister_driver(&magicmouse_driver);
-}
-
-module_init(magicmouse_init);
-module_exit(magicmouse_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 6fcd466d0825..29d27f65a118 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -221,17 +221,6 @@ static struct hid_driver ms_driver = {
.event = ms_event,
.probe = ms_probe,
};
+module_hid_driver(ms_driver);
-static int __init ms_init(void)
-{
- return hid_register_driver(&ms_driver);
-}
-
-static void __exit ms_exit(void)
-{
- hid_unregister_driver(&ms_driver);
-}
-
-module_init(ms_init);
-module_exit(ms_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
index cd3643e06fa6..9e14c00eb1b6 100644
--- a/drivers/hid/hid-monterey.c
+++ b/drivers/hid/hid-monterey.c
@@ -63,17 +63,6 @@ static struct hid_driver mr_driver = {
.report_fixup = mr_report_fixup,
.input_mapping = mr_input_mapping,
};
+module_hid_driver(mr_driver);
-static int __init mr_init(void)
-{
- return hid_register_driver(&mr_driver);
-}
-
-static void __exit mr_exit(void)
-{
- hid_unregister_driver(&mr_driver);
-}
-
-module_init(mr_init);
-module_exit(mr_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 61543c02ea0b..7a1ebb867cf4 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -54,6 +54,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_NO_AREA (1 << 9)
#define MT_QUIRK_IGNORE_DUPLICATES (1 << 10)
#define MT_QUIRK_HOVERING (1 << 11)
+#define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12)
struct mt_slot {
__s32 x, y, cx, cy, p, w, h;
@@ -83,8 +84,11 @@ struct mt_device {
struct mt_class mtclass; /* our mt device class */
struct mt_fields *fields; /* temporary placeholder for storing the
multitouch fields */
+ int cc_index; /* contact count field index in the report */
+ int cc_value_index; /* contact count value index in the field */
unsigned last_field_index; /* last field index of the report */
unsigned last_slot_field; /* the last field of a slot */
+ unsigned mt_report_id; /* the report ID of the multitouch device */
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */
__s8 inputmode_index; /* InputMode HID feature index in the report */
__s8 maxcontact_report_id; /* Maximum Contact Number HID feature,
@@ -111,6 +115,9 @@ struct mt_device {
#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007
#define MT_CLS_DUAL_NSMU_CONTACTID 0x0008
#define MT_CLS_INRANGE_CONTACTNUMBER 0x0009
+#define MT_CLS_NSMU 0x000a
+#define MT_CLS_DUAL_CONTACT_NUMBER 0x0010
+#define MT_CLS_DUAL_CONTACT_ID 0x0011
/* vendor specific classes */
#define MT_CLS_3M 0x0101
@@ -144,6 +151,9 @@ static int cypress_compute_slot(struct mt_device *td)
static struct mt_class mt_classes[] = {
{ .name = MT_CLS_DEFAULT,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_CONTACT_CNT_ACCURATE },
+ { .name = MT_CLS_NSMU,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
{ .name = MT_CLS_SERIAL,
.quirks = MT_QUIRK_ALWAYS_VALID},
@@ -170,6 +180,16 @@ static struct mt_class mt_classes[] = {
{ .name = MT_CLS_INRANGE_CONTACTNUMBER,
.quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTNUMBER },
+ { .name = MT_CLS_DUAL_CONTACT_NUMBER,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_CONTACT_CNT_ACCURATE |
+ MT_QUIRK_SLOT_IS_CONTACTNUMBER,
+ .maxcontacts = 2 },
+ { .name = MT_CLS_DUAL_CONTACT_ID,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_CONTACT_CNT_ACCURATE |
+ MT_QUIRK_SLOT_IS_CONTACTID,
+ .maxcontacts = 2 },
/*
* vendor specific classes
@@ -250,6 +270,9 @@ static ssize_t mt_set_quirks(struct device *dev,
td->mtclass.quirks = val;
+ if (td->cc_index < 0)
+ td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
+
return count;
}
@@ -301,6 +324,7 @@ static void mt_feature_mapping(struct hid_device *hdev,
*quirks |= MT_QUIRK_ALWAYS_VALID;
*quirks |= MT_QUIRK_IGNORE_DUPLICATES;
*quirks |= MT_QUIRK_HOVERING;
+ *quirks |= MT_QUIRK_CONTACT_CNT_ACCURATE;
*quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
*quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
*quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
@@ -428,6 +452,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
mt_store_field(usage, td, hi);
td->last_field_index = field->index;
td->touches_by_report++;
+ td->mt_report_id = field->report->id;
return 1;
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
@@ -459,6 +484,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTCOUNT:
+ td->cc_index = field->index;
+ td->cc_value_index = usage->usage_index;
td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTMAX:
@@ -523,6 +550,10 @@ static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
*/
static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
{
+ if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
+ td->num_received >= td->num_expected)
+ return;
+
if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
int slotnum = mt_compute_slot(td, input);
struct mt_slot *s = &td->curdata;
@@ -578,6 +609,16 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
static int mt_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
+ /* we will handle the hidinput part later, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
struct mt_device *td = hid_get_drvdata(hid);
__s32 quirks = td->mtclass.quirks;
@@ -623,20 +664,13 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
td->curdata.h = value;
break;
case HID_DG_CONTACTCOUNT:
- /*
- * Includes multi-packet support where subsequent
- * packets are sent with zero contactcount.
- */
- if (value)
- td->num_expected = value;
break;
case HID_DG_TOUCH:
/* do nothing */
break;
default:
- /* fallback to the generic hidinput handling */
- return 0;
+ return;
}
if (usage->usage_index + 1 == field->report_count) {
@@ -650,12 +684,43 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
}
}
+}
- /* 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);
+static void mt_report(struct hid_device *hid, struct hid_report *report)
+{
+ struct mt_device *td = hid_get_drvdata(hid);
+ struct hid_field *field;
+ unsigned count;
+ int r, n;
- return 1;
+ if (report->id != td->mt_report_id)
+ return;
+
+ if (!(hid->claimed & HID_CLAIMED_INPUT))
+ return;
+
+ /*
+ * Includes multi-packet support where subsequent
+ * packets are sent with zero contactcount.
+ */
+ if (td->cc_index >= 0) {
+ struct hid_field *field = report->field[td->cc_index];
+ int value = field->value[td->cc_value_index];
+ if (value)
+ td->num_expected = value;
+ }
+
+ for (r = 0; r < report->maxfield; r++) {
+ field = report->field[r];
+ count = field->report_count;
+
+ if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
+ continue;
+
+ for (n = 0; n < count; n++)
+ mt_process_mt_event(hid, field, &field->usage[n],
+ field->value[n]);
+ }
}
static void mt_set_input_mode(struct hid_device *hdev)
@@ -711,6 +776,7 @@ static void mt_post_parse_default_settings(struct mt_device *td)
quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
+ quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
td->mtclass.quirks = quirks;
@@ -719,11 +785,15 @@ static void mt_post_parse_default_settings(struct mt_device *td)
static void mt_post_parse(struct mt_device *td)
{
struct mt_fields *f = td->fields;
+ struct mt_class *cls = &td->mtclass;
if (td->touches_by_report > 0) {
int field_count_per_touch = f->length / td->touches_by_report;
td->last_slot_field = f->usages[field_count_per_touch - 1];
}
+
+ if (td->cc_index < 0)
+ cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
@@ -781,6 +851,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->mtclass = *mtclass;
td->inputmode = -1;
td->maxcontact_report_id = -1;
+ td->cc_index = -1;
hid_set_drvdata(hdev, td);
td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
@@ -875,7 +946,7 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_3M3266) },
/* ActionStar panels */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
USB_DEVICE_ID_ACTIONSTAR_1011) },
@@ -888,14 +959,14 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) },
/* Baanto multitouch devices */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_BAANTO,
USB_DEVICE_ID_BAANTO_MT_190W2) },
/* Cando panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
- { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+ { .driver_data = MT_CLS_DUAL_CONTACT_NUMBER,
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
@@ -906,12 +977,12 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
/* Chunghwa Telecom touch panels */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
/* CVTouch panels */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
USB_DEVICE_ID_CVTOUCH_SCREEN) },
@@ -982,7 +1053,7 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) },
/* Elo TouchSystems IntelliTouch Plus panel */
- { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
+ { .driver_data = MT_CLS_DUAL_CONTACT_ID,
MT_USB_DEVICE(USB_VENDOR_ID_ELO,
USB_DEVICE_ID_ELO_TS2515) },
@@ -1000,12 +1071,12 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) },
/* Gametel game controller */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL,
USB_DEVICE_ID_GAMETEL_MT_MODE) },
/* GoodTouch panels */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
USB_DEVICE_ID_GOODTOUCH_000f) },
@@ -1023,7 +1094,7 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_IDEACOM_IDC6651) },
/* Ilitek dual touch panel */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
USB_DEVICE_ID_ILITEK_MULTITOUCH) },
@@ -1056,6 +1127,11 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
+ /* Nexio panels */
+ { .driver_data = MT_CLS_DEFAULT,
+ MT_USB_DEVICE(USB_VENDOR_ID_NEXIO,
+ USB_DEVICE_ID_NEXIO_MULTITOUCH_420)},
+
/* Panasonic panels */
{ .driver_data = MT_CLS_PANASONIC,
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
@@ -1065,7 +1141,7 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_PANABOARD_UBT880) },
/* Novatek Panel */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK,
USB_DEVICE_ID_NOVATEK_PCT) },
@@ -1111,7 +1187,7 @@ static const struct hid_device_id mt_devices[] = {
{ .driver_data = MT_CLS_CONFIDENCE,
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
USB_DEVICE_ID_MTP_STM)},
- { .driver_data = MT_CLS_CONFIDENCE,
+ { .driver_data = MT_CLS_DEFAULT,
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
USB_DEVICE_ID_MTP_SITRONIX)},
@@ -1121,48 +1197,48 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_TOPSEED2_PERIPAD_701) },
/* Touch International panels */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
/* Unitec panels */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
/* XAT */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_XAT,
USB_DEVICE_ID_XAT_CSR) },
/* Xiroku */
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_SPX) },
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_MPX) },
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR) },
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_SPX1) },
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_MPX1) },
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR1) },
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_SPX2) },
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_MPX2) },
- { .driver_data = MT_CLS_DEFAULT,
+ { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR2) },
@@ -1193,21 +1269,10 @@ static struct hid_driver mt_driver = {
.feature_mapping = mt_feature_mapping,
.usage_table = mt_grabbed_usages,
.event = mt_event,
+ .report = mt_report,
#ifdef CONFIG_PM
.reset_resume = mt_reset_resume,
.resume = mt_resume,
#endif
};
-
-static int __init mt_init(void)
-{
- return hid_register_driver(&mt_driver);
-}
-
-static void __exit mt_exit(void)
-{
- hid_unregister_driver(&mt_driver);
-}
-
-module_init(mt_init);
-module_exit(mt_exit);
+module_hid_driver(mt_driver);
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 86a969f63292..7757e82416e7 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -858,12 +858,43 @@ not_claimed_input:
return 1;
}
+static void ntrig_input_configured(struct hid_device *hid,
+ struct hid_input *hidinput)
+
+{
+ struct input_dev *input = hidinput->input;
+
+ if (hidinput->report->maxfield < 1)
+ return;
+
+ switch (hidinput->report->field[0]->application) {
+ case HID_DG_PEN:
+ input->name = "N-Trig Pen";
+ break;
+ case HID_DG_TOUCHSCREEN:
+ /* These keys are redundant for fingers, clear them
+ * to prevent incorrect identification */
+ __clear_bit(BTN_TOOL_PEN, input->keybit);
+ __clear_bit(BTN_TOOL_FINGER, input->keybit);
+ __clear_bit(BTN_0, input->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
+ /*
+ * The physical touchscreen (single touch)
+ * input has a value for physical, whereas
+ * the multitouch only has logical input
+ * fields.
+ */
+ input->name = (hidinput->report->field[0]->physical) ?
+ "N-Trig Touchscreen" :
+ "N-Trig MultiTouch";
+ break;
+ }
+}
+
static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
struct ntrig_data *nd;
- struct hid_input *hidinput;
- struct input_dev *input;
struct hid_report *report;
if (id->driver_data)
@@ -901,38 +932,6 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
-
- list_for_each_entry(hidinput, &hdev->inputs, list) {
- if (hidinput->report->maxfield < 1)
- continue;
-
- input = hidinput->input;
- switch (hidinput->report->field[0]->application) {
- case HID_DG_PEN:
- input->name = "N-Trig Pen";
- break;
- case HID_DG_TOUCHSCREEN:
- /* These keys are redundant for fingers, clear them
- * to prevent incorrect identification */
- __clear_bit(BTN_TOOL_PEN, input->keybit);
- __clear_bit(BTN_TOOL_FINGER, input->keybit);
- __clear_bit(BTN_0, input->keybit);
- __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
- /*
- * The physical touchscreen (single touch)
- * input has a value for physical, whereas
- * the multitouch only has logical input
- * fields.
- */
- input->name =
- (hidinput->report->field[0]
- ->physical) ?
- "N-Trig Touchscreen" :
- "N-Trig MultiTouch";
- break;
- }
- }
-
/* This is needed for devices with more recent firmware versions */
report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0x0a];
if (report) {
@@ -1023,20 +1022,10 @@ static struct hid_driver ntrig_driver = {
.remove = ntrig_remove,
.input_mapping = ntrig_input_mapping,
.input_mapped = ntrig_input_mapped,
+ .input_configured = ntrig_input_configured,
.usage_table = ntrig_grabbed_usages,
.event = ntrig_event,
};
+module_hid_driver(ntrig_driver);
-static int __init ntrig_init(void)
-{
- return hid_register_driver(&ntrig_driver);
-}
-
-static void __exit ntrig_exit(void)
-{
- hid_unregister_driver(&ntrig_driver);
-}
-
-module_init(ntrig_init);
-module_exit(ntrig_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c
index 0ffa1d2d64f0..6620f15fec22 100644
--- a/drivers/hid/hid-ortek.c
+++ b/drivers/hid/hid-ortek.c
@@ -50,17 +50,6 @@ static struct hid_driver ortek_driver = {
.id_table = ortek_devices,
.report_fixup = ortek_report_fixup
};
+module_hid_driver(ortek_driver);
-static int __init ortek_init(void)
-{
- return hid_register_driver(&ortek_driver);
-}
-
-static void __exit ortek_exit(void)
-{
- hid_unregister_driver(&ortek_driver);
-}
-
-module_init(ortek_init);
-module_exit(ortek_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
index 4c521de4e7e6..736b2502df4f 100644
--- a/drivers/hid/hid-petalynx.c
+++ b/drivers/hid/hid-petalynx.c
@@ -103,17 +103,6 @@ static struct hid_driver pl_driver = {
.input_mapping = pl_input_mapping,
.probe = pl_probe,
};
+module_hid_driver(pl_driver);
-static int __init pl_init(void)
-{
- return hid_register_driver(&pl_driver);
-}
-
-static void __exit pl_exit(void)
-{
- hid_unregister_driver(&pl_driver);
-}
-
-module_init(pl_init);
-module_exit(pl_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c
index 86df26e58aba..31cd93fc3d4b 100644
--- a/drivers/hid/hid-picolcd_core.c
+++ b/drivers/hid/hid-picolcd_core.c
@@ -672,18 +672,7 @@ static struct hid_driver picolcd_driver = {
.reset_resume = picolcd_reset_resume,
#endif
};
+module_hid_driver(picolcd_driver);
-static int __init picolcd_init(void)
-{
- return hid_register_driver(&picolcd_driver);
-}
-
-static void __exit picolcd_exit(void)
-{
- hid_unregister_driver(&picolcd_driver);
-}
-
-module_init(picolcd_init);
-module_exit(picolcd_exit);
MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c
index 47ed74c46b6b..b0199d27787b 100644
--- a/drivers/hid/hid-pl.c
+++ b/drivers/hid/hid-pl.c
@@ -14,6 +14,8 @@
* 0e8f:0003 "GASIA USB Gamepad"
* - another version of the König gamepad
*
+ * 0f30:0111 "Saitek Color Rumble Pad"
+ *
* Copyright (c) 2007, 2009 Anssi Hannula <anssi.hannula@gmail.com>
*/
@@ -51,6 +53,7 @@
struct plff_device {
struct hid_report *report;
+ s32 maxval;
s32 *strong;
s32 *weak;
};
@@ -66,8 +69,8 @@ static int hid_plff_play(struct input_dev *dev, void *data,
right = effect->u.rumble.weak_magnitude;
debug("called with 0x%04x 0x%04x", left, right);
- left = left * 0x7f / 0xffff;
- right = right * 0x7f / 0xffff;
+ left = left * plff->maxval / 0xffff;
+ right = right * plff->maxval / 0xffff;
*plff->strong = left;
*plff->weak = right;
@@ -87,6 +90,7 @@ static int plff_init(struct hid_device *hid)
struct list_head *report_ptr = report_list;
struct input_dev *dev;
int error;
+ s32 maxval;
s32 *strong;
s32 *weak;
@@ -123,6 +127,7 @@ static int plff_init(struct hid_device *hid)
return -ENODEV;
}
+ maxval = 0x7f;
if (report->field[0]->report_count >= 4) {
report->field[0]->value[0] = 0x00;
report->field[0]->value[1] = 0x00;
@@ -135,6 +140,8 @@ static int plff_init(struct hid_device *hid)
report->field[1]->value[0] = 0x00;
strong = &report->field[2]->value[0];
weak = &report->field[3]->value[0];
+ if (hid->vendor == USB_VENDOR_ID_JESS2)
+ maxval = 0xff;
debug("detected 4-field device");
} else {
hid_err(hid, "not enough fields or values\n");
@@ -158,6 +165,7 @@ static int plff_init(struct hid_device *hid)
plff->report = report;
plff->strong = strong;
plff->weak = weak;
+ plff->maxval = maxval;
*strong = 0x00;
*weak = 0x00;
@@ -207,6 +215,7 @@ static const struct hid_device_id pl_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR),
.driver_data = 1 }, /* Twin USB Joystick */
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003), },
+ { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD), },
{ }
};
MODULE_DEVICE_TABLE(hid, pl_devices);
@@ -216,17 +225,6 @@ static struct hid_driver pl_driver = {
.id_table = pl_devices,
.probe = pl_probe,
};
+module_hid_driver(pl_driver);
-static int __init pl_init(void)
-{
- return hid_register_driver(&pl_driver);
-}
-
-static void __exit pl_exit(void)
-{
- hid_unregister_driver(&pl_driver);
-}
-
-module_init(pl_init);
-module_exit(pl_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-primax.c b/drivers/hid/hid-primax.c
index c15adb0c98a1..3a1c3c4c50dc 100644
--- a/drivers/hid/hid-primax.c
+++ b/drivers/hid/hid-primax.c
@@ -75,18 +75,7 @@ static struct hid_driver px_driver = {
.id_table = px_devices,
.raw_event = px_raw_event,
};
+module_hid_driver(px_driver);
-static int __init px_init(void)
-{
- return hid_register_driver(&px_driver);
-}
-
-static void __exit px_exit(void)
-{
- hid_unregister_driver(&px_driver);
-}
-
-module_init(px_init);
-module_exit(px_exit);
MODULE_AUTHOR("Terry Lambert <tlambert@google.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index ec8ca3336315..4e1c4bcbdc03 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -889,23 +889,6 @@ static struct hid_driver pk_driver = {
.probe = pk_probe,
.remove = pk_remove,
};
+module_hid_driver(pk_driver);
-static int pk_init(void)
-{
- int ret;
-
- ret = hid_register_driver(&pk_driver);
- if (ret)
- pr_err("can't register prodikeys driver\n");
-
- return ret;
-}
-
-static void pk_exit(void)
-{
- hid_unregister_driver(&pk_driver);
-}
-
-module_init(pk_init);
-module_exit(pk_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ps3remote.c b/drivers/hid/hid-ps3remote.c
index 03811e539d71..f1239d3c5b14 100644
--- a/drivers/hid/hid-ps3remote.c
+++ b/drivers/hid/hid-ps3remote.c
@@ -198,18 +198,7 @@ static struct hid_driver ps3remote_driver = {
.report_fixup = ps3remote_fixup,
.input_mapping = ps3remote_mapping,
};
+module_hid_driver(ps3remote_driver);
-static int __init ps3remote_init(void)
-{
- return hid_register_driver(&ps3remote_driver);
-}
-
-static void __exit ps3remote_exit(void)
-{
- hid_unregister_driver(&ps3remote_driver);
-}
-
-module_init(ps3remote_init);
-module_exit(ps3remote_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Dillow <dave@thedillows.org>, Antonio Ospite <ospite@studenti.unina.it>");
diff --git a/drivers/hid/hid-roccat-lua.c b/drivers/hid/hid-roccat-lua.c
index 5084fb4b7e91..6adc0fa08d96 100644
--- a/drivers/hid/hid-roccat-lua.c
+++ b/drivers/hid/hid-roccat-lua.c
@@ -208,19 +208,7 @@ static struct hid_driver lua_driver = {
.probe = lua_probe,
.remove = lua_remove
};
-
-static int __init lua_init(void)
-{
- return hid_register_driver(&lua_driver);
-}
-
-static void __exit lua_exit(void)
-{
- hid_unregister_driver(&lua_driver);
-}
-
-module_init(lua_init);
-module_exit(lua_exit);
+module_hid_driver(lua_driver);
MODULE_AUTHOR("Stefan Achatz");
MODULE_DESCRIPTION("USB Roccat Lua driver");
diff --git a/drivers/hid/hid-saitek.c b/drivers/hid/hid-saitek.c
index 45aea77bb611..37961c7e397d 100644
--- a/drivers/hid/hid-saitek.c
+++ b/drivers/hid/hid-saitek.c
@@ -54,17 +54,6 @@ static struct hid_driver saitek_driver = {
.id_table = saitek_devices,
.report_fixup = saitek_report_fixup
};
+module_hid_driver(saitek_driver);
-static int __init saitek_init(void)
-{
- return hid_register_driver(&saitek_driver);
-}
-
-static void __exit saitek_exit(void)
-{
- hid_unregister_driver(&saitek_driver);
-}
-
-module_init(saitek_init);
-module_exit(saitek_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
index a5821d317229..7cbb067d4a9e 100644
--- a/drivers/hid/hid-samsung.c
+++ b/drivers/hid/hid-samsung.c
@@ -196,17 +196,6 @@ static struct hid_driver samsung_driver = {
.input_mapping = samsung_input_mapping,
.probe = samsung_probe,
};
+module_hid_driver(samsung_driver);
-static int __init samsung_init(void)
-{
- return hid_register_driver(&samsung_driver);
-}
-
-static void __exit samsung_exit(void)
-{
- hid_unregister_driver(&samsung_driver);
-}
-
-module_init(samsung_init);
-module_exit(samsung_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 0bc58bd8d4f5..6679788bf75a 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -605,16 +605,12 @@ static void sensor_hub_remove(struct hid_device *hdev)
}
static const struct hid_device_id sensor_hub_devices[] = {
- { HID_DEVICE(BUS_USB, HID_GROUP_SENSOR_HUB, HID_ANY_ID, HID_ANY_ID) },
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
+ HID_ANY_ID) },
{ }
};
MODULE_DEVICE_TABLE(hid, sensor_hub_devices);
-static const struct hid_usage_id sensor_hub_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 sensor_hub_driver = {
.name = "hid-sensor-hub",
.id_table = sensor_hub_devices,
@@ -627,19 +623,7 @@ static struct hid_driver sensor_hub_driver = {
.reset_resume = sensor_hub_reset_resume,
#endif
};
-
-static int __init sensor_hub_init(void)
-{
- return hid_register_driver(&sensor_hub_driver);
-}
-
-static void __exit sensor_hub_exit(void)
-{
- hid_unregister_driver(&sensor_hub_driver);
-}
-
-module_init(sensor_hub_init);
-module_exit(sensor_hub_exit);
+module_hid_driver(sensor_hub_driver);
MODULE_DESCRIPTION("HID Sensor Hub driver");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
index 42257acfeb73..28f774003f03 100644
--- a/drivers/hid/hid-sjoy.c
+++ b/drivers/hid/hid-sjoy.c
@@ -177,19 +177,8 @@ static struct hid_driver sjoy_driver = {
.id_table = sjoy_devices,
.probe = sjoy_probe,
};
+module_hid_driver(sjoy_driver);
-static int __init sjoy_init(void)
-{
- return hid_register_driver(&sjoy_driver);
-}
-
-static void __exit sjoy_exit(void)
-{
- hid_unregister_driver(&sjoy_driver);
-}
-
-module_init(sjoy_init);
-module_exit(sjoy_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jussi Kivilinna");
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 7f33ebf299c2..312098e4af4f 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -33,6 +33,28 @@ static const u8 sixaxis_rdesc_fixup[] = {
0x03, 0x46, 0xFF, 0x03, 0x09, 0x01, 0x81, 0x02
};
+static const u8 sixaxis_rdesc_fixup2[] = {
+ 0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0xa1, 0x02,
+ 0x85, 0x01, 0x75, 0x08, 0x95, 0x01, 0x15, 0x00,
+ 0x26, 0xff, 0x00, 0x81, 0x03, 0x75, 0x01, 0x95,
+ 0x13, 0x15, 0x00, 0x25, 0x01, 0x35, 0x00, 0x45,
+ 0x01, 0x05, 0x09, 0x19, 0x01, 0x29, 0x13, 0x81,
+ 0x02, 0x75, 0x01, 0x95, 0x0d, 0x06, 0x00, 0xff,
+ 0x81, 0x03, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05,
+ 0x01, 0x09, 0x01, 0xa1, 0x00, 0x75, 0x08, 0x95,
+ 0x04, 0x35, 0x00, 0x46, 0xff, 0x00, 0x09, 0x30,
+ 0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x81, 0x02,
+ 0xc0, 0x05, 0x01, 0x95, 0x13, 0x09, 0x01, 0x81,
+ 0x02, 0x95, 0x0c, 0x81, 0x01, 0x75, 0x10, 0x95,
+ 0x04, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x09,
+ 0x01, 0x81, 0x02, 0xc0, 0xa1, 0x02, 0x85, 0x02,
+ 0x75, 0x08, 0x95, 0x30, 0x09, 0x01, 0xb1, 0x02,
+ 0xc0, 0xa1, 0x02, 0x85, 0xee, 0x75, 0x08, 0x95,
+ 0x30, 0x09, 0x01, 0xb1, 0x02, 0xc0, 0xa1, 0x02,
+ 0x85, 0xef, 0x75, 0x08, 0x95, 0x30, 0x09, 0x01,
+ 0xb1, 0x02, 0xc0, 0xc0,
+};
+
struct sony_sc {
unsigned long quirks;
};
@@ -43,9 +65,19 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
{
struct sony_sc *sc = hid_get_drvdata(hdev);
- if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
- *rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
- hid_info(hdev, "Fixing up Sony Vaio VGX report descriptor\n");
+ /*
+ * Some Sony RF receivers wrongly declare the mouse pointer as a
+ * a constant non-data variable.
+ */
+ if ((sc->quirks & VAIO_RDESC_CONSTANT) && *rsize >= 56 &&
+ /* usage page: generic desktop controls */
+ /* rdesc[0] == 0x05 && rdesc[1] == 0x01 && */
+ /* usage: mouse */
+ rdesc[2] == 0x09 && rdesc[3] == 0x02 &&
+ /* input (usage page for x,y axes): constant, variable, relative */
+ rdesc[54] == 0x81 && rdesc[55] == 0x07) {
+ hid_info(hdev, "Fixing up Sony RF Receiver report descriptor\n");
+ /* input: data, variable, relative */
rdesc[55] = 0x06;
}
@@ -56,6 +88,12 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
hid_info(hdev, "Fixing up Sony Sixaxis report descriptor\n");
memcpy((void *)&rdesc[83], (void *)&sixaxis_rdesc_fixup,
sizeof(sixaxis_rdesc_fixup));
+ } else if (sc->quirks & SIXAXIS_CONTROLLER_USB &&
+ *rsize > sizeof(sixaxis_rdesc_fixup2)) {
+ hid_info(hdev, "Sony Sixaxis clone detected. Using original report descriptor (size: %d clone; %d new)\n",
+ *rsize, (int)sizeof(sixaxis_rdesc_fixup2));
+ *rsize = sizeof(sixaxis_rdesc_fixup2);
+ memcpy(rdesc, &sixaxis_rdesc_fixup2, *rsize);
}
return rdesc;
}
@@ -217,6 +255,8 @@ static const struct hid_device_id sony_devices[] = {
.driver_data = SIXAXIS_CONTROLLER_BT },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
.driver_data = VAIO_RDESC_CONSTANT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE),
+ .driver_data = VAIO_RDESC_CONSTANT },
{ }
};
MODULE_DEVICE_TABLE(hid, sony_devices);
@@ -229,17 +269,6 @@ static struct hid_driver sony_driver = {
.report_fixup = sony_report_fixup,
.raw_event = sony_raw_event
};
+module_hid_driver(sony_driver);
-static int __init sony_init(void)
-{
- return hid_register_driver(&sony_driver);
-}
-
-static void __exit sony_exit(void)
-{
- hid_unregister_driver(&sony_driver);
-}
-
-module_init(sony_init);
-module_exit(sony_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-speedlink.c b/drivers/hid/hid-speedlink.c
index 602013741718..e94371a059cb 100644
--- a/drivers/hid/hid-speedlink.c
+++ b/drivers/hid/hid-speedlink.c
@@ -73,17 +73,6 @@ static struct hid_driver speedlink_driver = {
.input_mapping = speedlink_input_mapping,
.event = speedlink_event,
};
+module_hid_driver(speedlink_driver);
-static int __init speedlink_init(void)
-{
- return hid_register_driver(&speedlink_driver);
-}
-
-static void __exit speedlink_exit(void)
-{
- hid_unregister_driver(&speedlink_driver);
-}
-
-module_init(speedlink_init);
-module_exit(speedlink_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c
new file mode 100644
index 000000000000..2ed995cda44a
--- /dev/null
+++ b/drivers/hid/hid-steelseries.c
@@ -0,0 +1,393 @@
+/*
+ * HID driver for Steelseries SRW-S1
+ *
+ * Copyright (c) 2013 Simon Wood
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/usb.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "usbhid/usbhid.h"
+#include "hid-ids.h"
+
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+#define SRWS1_NUMBER_LEDS 15
+struct steelseries_srws1_data {
+ __u16 led_state;
+ /* the last element is used for setting all leds simultaneously */
+ struct led_classdev *led[SRWS1_NUMBER_LEDS + 1];
+};
+#endif
+
+/* Fixed report descriptor for Steelseries SRW-S1 wheel controller
+ *
+ * The original descriptor hides the sensitivity and assists dials
+ * a custom vendor usage page. This inserts a patch to make them
+ * appear in the 'Generic Desktop' usage.
+ */
+
+static __u8 steelseries_srws1_rdesc_fixed[] = {
+0x05, 0x01, /* Usage Page (Desktop) */
+0x09, 0x08, /* Usage (MultiAxis), Changed */
+0xA1, 0x01, /* Collection (Application), */
+0xA1, 0x02, /* Collection (Logical), */
+0x95, 0x01, /* Report Count (1), */
+0x05, 0x01, /* Changed Usage Page (Desktop), */
+0x09, 0x30, /* Changed Usage (X), */
+0x16, 0xF8, 0xF8, /* Logical Minimum (-1800), */
+0x26, 0x08, 0x07, /* Logical Maximum (1800), */
+0x65, 0x14, /* Unit (Degrees), */
+0x55, 0x0F, /* Unit Exponent (15), */
+0x75, 0x10, /* Report Size (16), */
+0x81, 0x02, /* Input (Variable), */
+0x09, 0x31, /* Changed Usage (Y), */
+0x15, 0x00, /* Logical Minimum (0), */
+0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+0x75, 0x0C, /* Report Size (12), */
+0x81, 0x02, /* Input (Variable), */
+0x09, 0x32, /* Changed Usage (Z), */
+0x15, 0x00, /* Logical Minimum (0), */
+0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+0x75, 0x0C, /* Report Size (12), */
+0x81, 0x02, /* Input (Variable), */
+0x05, 0x01, /* Usage Page (Desktop), */
+0x09, 0x39, /* Usage (Hat Switch), */
+0x25, 0x07, /* Logical Maximum (7), */
+0x35, 0x00, /* Physical Minimum (0), */
+0x46, 0x3B, 0x01, /* Physical Maximum (315), */
+0x65, 0x14, /* Unit (Degrees), */
+0x75, 0x04, /* Report Size (4), */
+0x95, 0x01, /* Report Count (1), */
+0x81, 0x02, /* Input (Variable), */
+0x25, 0x01, /* Logical Maximum (1), */
+0x45, 0x01, /* Physical Maximum (1), */
+0x65, 0x00, /* Unit, */
+0x75, 0x01, /* Report Size (1), */
+0x95, 0x03, /* Report Count (3), */
+0x81, 0x01, /* Input (Constant), */
+0x05, 0x09, /* Usage Page (Button), */
+0x19, 0x01, /* Usage Minimum (01h), */
+0x29, 0x11, /* Usage Maximum (11h), */
+0x95, 0x11, /* Report Count (17), */
+0x81, 0x02, /* Input (Variable), */
+ /* ---- Dial patch starts here ---- */
+0x05, 0x01, /* Usage Page (Desktop), */
+0x09, 0x33, /* Usage (RX), */
+0x75, 0x04, /* Report Size (4), */
+0x95, 0x02, /* Report Count (2), */
+0x15, 0x00, /* Logical Minimum (0), */
+0x25, 0x0b, /* Logical Maximum (b), */
+0x81, 0x02, /* Input (Variable), */
+0x09, 0x35, /* Usage (RZ), */
+0x75, 0x04, /* Report Size (4), */
+0x95, 0x01, /* Report Count (1), */
+0x25, 0x03, /* Logical Maximum (3), */
+0x81, 0x02, /* Input (Variable), */
+ /* ---- Dial patch ends here ---- */
+0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+0x09, 0x01, /* Usage (01h), */
+0x75, 0x04, /* Changed Report Size (4), */
+0x95, 0x0D, /* Changed Report Count (13), */
+0x81, 0x02, /* Input (Variable), */
+0xC0, /* End Collection, */
+0xA1, 0x02, /* Collection (Logical), */
+0x09, 0x02, /* Usage (02h), */
+0x75, 0x08, /* Report Size (8), */
+0x95, 0x10, /* Report Count (16), */
+0x91, 0x02, /* Output (Variable), */
+0xC0, /* End Collection, */
+0xC0 /* End Collection */
+};
+
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+static void steelseries_srws1_set_leds(struct hid_device *hdev, __u16 leds)
+{
+ struct list_head *report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+ __s32 *value = report->field[0]->value;
+
+ value[0] = 0x40;
+ value[1] = leds & 0xFF;
+ value[2] = leds >> 8;
+ value[3] = 0x00;
+ value[4] = 0x00;
+ value[5] = 0x00;
+ value[6] = 0x00;
+ value[7] = 0x00;
+ value[8] = 0x00;
+ value[9] = 0x00;
+ value[10] = 0x00;
+ value[11] = 0x00;
+ value[12] = 0x00;
+ value[13] = 0x00;
+ value[14] = 0x00;
+ value[15] = 0x00;
+
+ usbhid_submit_report(hdev, report, USB_DIR_OUT);
+
+ /* Note: LED change does not show on device until the device is read/polled */
+}
+
+static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct device *dev = led_cdev->dev->parent;
+ struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid);
+
+ if (!drv_data) {
+ hid_err(hid, "Device data not found.");
+ return;
+ }
+
+ if (value == LED_OFF)
+ drv_data->led_state = 0;
+ else
+ drv_data->led_state = (1 << (SRWS1_NUMBER_LEDS + 1)) - 1;
+
+ steelseries_srws1_set_leds(hid, drv_data->led_state);
+}
+
+static enum led_brightness steelseries_srws1_led_all_get_brightness(struct led_classdev *led_cdev)
+{
+ struct device *dev = led_cdev->dev->parent;
+ struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct steelseries_srws1_data *drv_data;
+
+ drv_data = hid_get_drvdata(hid);
+
+ if (!drv_data) {
+ hid_err(hid, "Device data not found.");
+ return LED_OFF;
+ }
+
+ return (drv_data->led_state >> SRWS1_NUMBER_LEDS) ? LED_FULL : LED_OFF;
+}
+
+static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct device *dev = led_cdev->dev->parent;
+ struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid);
+ int i, state = 0;
+
+ if (!drv_data) {
+ hid_err(hid, "Device data not found.");
+ return;
+ }
+
+ for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+ if (led_cdev != drv_data->led[i])
+ continue;
+
+ state = (drv_data->led_state >> i) & 1;
+ if (value == LED_OFF && state) {
+ drv_data->led_state &= ~(1 << i);
+ steelseries_srws1_set_leds(hid, drv_data->led_state);
+ } else if (value != LED_OFF && !state) {
+ drv_data->led_state |= 1 << i;
+ steelseries_srws1_set_leds(hid, drv_data->led_state);
+ }
+ break;
+ }
+}
+
+static enum led_brightness steelseries_srws1_led_get_brightness(struct led_classdev *led_cdev)
+{
+ struct device *dev = led_cdev->dev->parent;
+ struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct steelseries_srws1_data *drv_data;
+ int i, value = 0;
+
+ drv_data = hid_get_drvdata(hid);
+
+ if (!drv_data) {
+ hid_err(hid, "Device data not found.");
+ return LED_OFF;
+ }
+
+ for (i = 0; i < SRWS1_NUMBER_LEDS; i++)
+ if (led_cdev == drv_data->led[i]) {
+ value = (drv_data->led_state >> i) & 1;
+ break;
+ }
+
+ return value ? LED_FULL : LED_OFF;
+}
+
+static int steelseries_srws1_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret, i;
+ struct led_classdev *led;
+ size_t name_sz;
+ char *name;
+
+ struct steelseries_srws1_data *drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
+
+ if (drv_data == NULL) {
+ hid_err(hdev, "can't alloc SRW-S1 memory\n");
+ return -ENOMEM;
+ }
+
+ hid_set_drvdata(hdev, drv_data);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto err_free;
+ }
+
+ /* register led subsystem */
+ drv_data->led_state = 0;
+ for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++)
+ drv_data->led[i] = NULL;
+
+ steelseries_srws1_set_leds(hdev, 0);
+
+ name_sz = strlen(hdev->uniq) + 16;
+
+ /* 'ALL', for setting all LEDs simultaneously */
+ led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+ if (!led) {
+ hid_err(hdev, "can't allocate memory for LED ALL\n");
+ goto err_led;
+ }
+
+ name = (void *)(&led[1]);
+ snprintf(name, name_sz, "SRWS1::%s::RPMALL", hdev->uniq);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 1;
+ led->brightness_get = steelseries_srws1_led_all_get_brightness;
+ led->brightness_set = steelseries_srws1_led_all_set_brightness;
+
+ drv_data->led[SRWS1_NUMBER_LEDS] = led;
+ ret = led_classdev_register(&hdev->dev, led);
+ if (ret)
+ goto err_led;
+
+ /* Each individual LED */
+ for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+ led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+ if (!led) {
+ hid_err(hdev, "can't allocate memory for LED %d\n", i);
+ goto err_led;
+ }
+
+ name = (void *)(&led[1]);
+ snprintf(name, name_sz, "SRWS1::%s::RPM%d", hdev->uniq, i+1);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 1;
+ led->brightness_get = steelseries_srws1_led_get_brightness;
+ led->brightness_set = steelseries_srws1_led_set_brightness;
+
+ drv_data->led[i] = led;
+ ret = led_classdev_register(&hdev->dev, led);
+
+ if (ret) {
+ hid_err(hdev, "failed to register LED %d. Aborting.\n", i);
+err_led:
+ /* Deregister all LEDs (if any) */
+ for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) {
+ led = drv_data->led[i];
+ drv_data->led[i] = NULL;
+ if (!led)
+ continue;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+ goto out; /* but let the driver continue without LEDs */
+ }
+ }
+out:
+ return 0;
+err_free:
+ kfree(drv_data);
+ return ret;
+}
+
+static void steelseries_srws1_remove(struct hid_device *hdev)
+{
+ int i;
+ struct led_classdev *led;
+
+ struct steelseries_srws1_data *drv_data = hid_get_drvdata(hdev);
+
+ if (drv_data) {
+ /* Deregister LEDs (if any) */
+ for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) {
+ led = drv_data->led[i];
+ drv_data->led[i] = NULL;
+ if (!led)
+ continue;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+
+ }
+
+ hid_hw_stop(hdev);
+ kfree(drv_data);
+ return;
+}
+#endif
+
+static __u8 *steelseries_srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ if (*rsize >= 115 && rdesc[11] == 0x02 && rdesc[13] == 0xc8
+ && rdesc[29] == 0xbb && rdesc[40] == 0xc5) {
+ hid_info(hdev, "Fixing up Steelseries SRW-S1 report descriptor\n");
+ rdesc = steelseries_srws1_rdesc_fixed;
+ *rsize = sizeof(steelseries_srws1_rdesc_fixed);
+ }
+ return rdesc;
+}
+
+static const struct hid_device_id steelseries_srws1_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, steelseries_srws1_devices);
+
+static struct hid_driver steelseries_srws1_driver = {
+ .name = "steelseries_srws1",
+ .id_table = steelseries_srws1_devices,
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+ .probe = steelseries_srws1_probe,
+ .remove = steelseries_srws1_remove,
+#endif
+ .report_fixup = steelseries_srws1_report_fixup
+};
+
+static int __init steelseries_srws1_init(void)
+{
+ return hid_register_driver(&steelseries_srws1_driver);
+}
+
+static void __exit steelseries_srws1_exit(void)
+{
+ hid_unregister_driver(&steelseries_srws1_driver);
+}
+
+module_init(steelseries_srws1_init);
+module_exit(steelseries_srws1_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
index 45b4b066a262..87fc91e1c8de 100644
--- a/drivers/hid/hid-sunplus.c
+++ b/drivers/hid/hid-sunplus.c
@@ -63,17 +63,6 @@ static struct hid_driver sp_driver = {
.report_fixup = sp_report_fixup,
.input_mapping = sp_input_mapping,
};
+module_hid_driver(sp_driver);
-static int __init sp_init(void)
-{
- return hid_register_driver(&sp_driver);
-}
-
-static void __exit sp_exit(void)
-{
- hid_unregister_driver(&sp_driver);
-}
-
-module_init(sp_init);
-module_exit(sp_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
new file mode 100644
index 000000000000..2055a52e9a20
--- /dev/null
+++ b/drivers/hid/hid-thingm.c
@@ -0,0 +1,272 @@
+/*
+ * ThingM blink(1) USB RGB LED driver
+ *
+ * Copyright 2013 Savoir-faire Linux Inc.
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.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.
+ */
+
+#include <linux/hid.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#define BLINK1_CMD_SIZE 9
+
+#define blink1_rgb_to_r(rgb) ((rgb & 0xFF0000) >> 16)
+#define blink1_rgb_to_g(rgb) ((rgb & 0x00FF00) >> 8)
+#define blink1_rgb_to_b(rgb) ((rgb & 0x0000FF) >> 0)
+
+/**
+ * struct blink1_data - blink(1) device specific data
+ * @hdev: HID device.
+ * @led_cdev: LED class instance.
+ * @rgb: 8-bit per channel RGB notation.
+ * @fade: fade time in hundredths of a second.
+ * @brightness: brightness coefficient.
+ * @play: play/pause in-memory patterns.
+ */
+struct blink1_data {
+ struct hid_device *hdev;
+ struct led_classdev led_cdev;
+ u32 rgb;
+ u16 fade;
+ u8 brightness;
+ bool play;
+};
+
+static int blink1_send_command(struct blink1_data *data,
+ u8 buf[BLINK1_CMD_SIZE])
+{
+ int ret;
+
+ hid_dbg(data->hdev, "command: %d%c%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4],
+ buf[5], buf[6], buf[7], buf[8]);
+
+ ret = data->hdev->hid_output_raw_report(data->hdev, buf,
+ BLINK1_CMD_SIZE, HID_FEATURE_REPORT);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int blink1_update_color(struct blink1_data *data)
+{
+ u8 buf[BLINK1_CMD_SIZE] = { 1, 'n', 0, 0, 0, 0, 0, 0, 0 };
+
+ if (data->brightness) {
+ unsigned int coef = DIV_ROUND_CLOSEST(255, data->brightness);
+
+ buf[2] = DIV_ROUND_CLOSEST(blink1_rgb_to_r(data->rgb), coef);
+ buf[3] = DIV_ROUND_CLOSEST(blink1_rgb_to_g(data->rgb), coef);
+ buf[4] = DIV_ROUND_CLOSEST(blink1_rgb_to_b(data->rgb), coef);
+ }
+
+ if (data->fade) {
+ buf[1] = 'c';
+ buf[5] = (data->fade & 0xFF00) >> 8;
+ buf[6] = (data->fade & 0x00FF);
+ }
+
+ return blink1_send_command(data, buf);
+}
+
+static void blink1_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
+
+ data->brightness = brightness;
+ if (blink1_update_color(data))
+ hid_err(data->hdev, "failed to update color\n");
+}
+
+static enum led_brightness blink1_led_get(struct led_classdev *led_cdev)
+{
+ struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
+
+ return data->brightness;
+}
+
+static ssize_t blink1_show_rgb(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct blink1_data *data = dev_get_drvdata(dev->parent);
+
+ return sprintf(buf, "%.6X\n", data->rgb);
+}
+
+static ssize_t blink1_store_rgb(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct blink1_data *data = dev_get_drvdata(dev->parent);
+ long unsigned int rgb;
+ int ret;
+
+ ret = kstrtoul(buf, 16, &rgb);
+ if (ret)
+ return ret;
+
+ /* RGB triplet notation is 24-bit hexadecimal */
+ if (rgb > 0xFFFFFF)
+ return -EINVAL;
+
+ data->rgb = rgb;
+ ret = blink1_update_color(data);
+
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(rgb, S_IRUGO | S_IWUSR, blink1_show_rgb, blink1_store_rgb);
+
+static ssize_t blink1_show_fade(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct blink1_data *data = dev_get_drvdata(dev->parent);
+
+ return sprintf(buf, "%d\n", data->fade * 10);
+}
+
+static ssize_t blink1_store_fade(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct blink1_data *data = dev_get_drvdata(dev->parent);
+ long unsigned int fade;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &fade);
+ if (ret)
+ return ret;
+
+ /* blink(1) accepts 16-bit fade time, number of 10ms ticks */
+ fade = DIV_ROUND_CLOSEST(fade, 10);
+ if (fade > 65535)
+ return -EINVAL;
+
+ data->fade = fade;
+
+ return count;
+}
+
+static DEVICE_ATTR(fade, S_IRUGO | S_IWUSR,
+ blink1_show_fade, blink1_store_fade);
+
+static ssize_t blink1_show_play(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct blink1_data *data = dev_get_drvdata(dev->parent);
+
+ return sprintf(buf, "%d\n", data->play);
+}
+
+static ssize_t blink1_store_play(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct blink1_data *data = dev_get_drvdata(dev->parent);
+ u8 cmd[BLINK1_CMD_SIZE] = { 1, 'p', 0, 0, 0, 0, 0, 0, 0 };
+ long unsigned int play;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &play);
+ if (ret)
+ return ret;
+
+ data->play = !!play;
+ cmd[2] = data->play;
+ ret = blink1_send_command(data, cmd);
+
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(play, S_IRUGO | S_IWUSR,
+ blink1_show_play, blink1_store_play);
+
+static const struct attribute_group blink1_sysfs_group = {
+ .attrs = (struct attribute *[]) {
+ &dev_attr_rgb.attr,
+ &dev_attr_fade.attr,
+ &dev_attr_play.attr,
+ NULL
+ },
+};
+
+static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ struct blink1_data *data;
+ struct led_classdev *led;
+ char led_name[13];
+ int ret;
+
+ data = devm_kzalloc(&hdev->dev, sizeof(struct blink1_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ hid_set_drvdata(hdev, data);
+ data->hdev = hdev;
+ data->rgb = 0xFFFFFF; /* set a default white color */
+
+ ret = hid_parse(hdev);
+ if (ret)
+ goto error;
+
+ ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+ if (ret)
+ goto error;
+
+ /* blink(1) serial numbers range is 0x1A001000 to 0x1A002FFF */
+ led = &data->led_cdev;
+ snprintf(led_name, sizeof(led_name), "blink1::%s", hdev->uniq + 4);
+ led->name = led_name;
+ led->brightness_set = blink1_led_set;
+ led->brightness_get = blink1_led_get;
+ ret = led_classdev_register(&hdev->dev, led);
+ if (ret)
+ goto stop;
+
+ ret = sysfs_create_group(&led->dev->kobj, &blink1_sysfs_group);
+ if (ret)
+ goto remove_led;
+
+ return 0;
+
+remove_led:
+ led_classdev_unregister(led);
+stop:
+ hid_hw_stop(hdev);
+error:
+ return ret;
+}
+
+static void thingm_remove(struct hid_device *hdev)
+{
+ struct blink1_data *data = hid_get_drvdata(hdev);
+ struct led_classdev *led = &data->led_cdev;
+
+ sysfs_remove_group(&led->dev->kobj, &blink1_sysfs_group);
+ led_classdev_unregister(led);
+ hid_hw_stop(hdev);
+}
+
+static const struct hid_device_id thingm_table[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, thingm_table);
+
+static struct hid_driver thingm_driver = {
+ .name = "thingm",
+ .probe = thingm_probe,
+ .remove = thingm_remove,
+ .id_table = thingm_table,
+};
+
+module_hid_driver(thingm_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vivien Didelot <vivien.didelot@savoirfairelinux.com>");
+MODULE_DESCRIPTION("ThingM blink(1) USB RGB LED driver");
diff --git a/drivers/hid/hid-tivo.c b/drivers/hid/hid-tivo.c
index 9f85f827607f..d790d8d71f7f 100644
--- a/drivers/hid/hid-tivo.c
+++ b/drivers/hid/hid-tivo.c
@@ -73,18 +73,7 @@ static struct hid_driver tivo_driver = {
.id_table = tivo_devices,
.input_mapping = tivo_input_mapping,
};
+module_hid_driver(tivo_driver);
-static int __init tivo_init(void)
-{
- return hid_register_driver(&tivo_driver);
-}
-
-static void __exit tivo_exit(void)
-{
- hid_unregister_driver(&tivo_driver);
-}
-
-module_init(tivo_init);
-module_exit(tivo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c
index 83a933b9c2e9..e4fcf3f702a5 100644
--- a/drivers/hid/hid-tmff.c
+++ b/drivers/hid/hid-tmff.c
@@ -261,17 +261,6 @@ static struct hid_driver tm_driver = {
.id_table = tm_devices,
.probe = tm_probe,
};
+module_hid_driver(tm_driver);
-static int __init tm_init(void)
-{
- return hid_register_driver(&tm_driver);
-}
-
-static void __exit tm_exit(void)
-{
- hid_unregister_driver(&tm_driver);
-}
-
-module_init(tm_init);
-module_exit(tm_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c
index 613ff7b1d746..8a5b843e9dd6 100644
--- a/drivers/hid/hid-topseed.c
+++ b/drivers/hid/hid-topseed.c
@@ -76,17 +76,6 @@ static struct hid_driver ts_driver = {
.id_table = ts_devices,
.input_mapping = ts_input_mapping,
};
+module_hid_driver(ts_driver);
-static int __init ts_init(void)
-{
- return hid_register_driver(&ts_driver);
-}
-
-static void __exit ts_exit(void)
-{
- hid_unregister_driver(&ts_driver);
-}
-
-module_init(ts_init);
-module_exit(ts_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-twinhan.c b/drivers/hid/hid-twinhan.c
index f23456b1fd4b..c08c36443f83 100644
--- a/drivers/hid/hid-twinhan.c
+++ b/drivers/hid/hid-twinhan.c
@@ -131,17 +131,6 @@ static struct hid_driver twinhan_driver = {
.id_table = twinhan_devices,
.input_mapping = twinhan_input_mapping,
};
+module_hid_driver(twinhan_driver);
-static int __init twinhan_init(void)
-{
- return hid_register_driver(&twinhan_driver);
-}
-
-static void __exit twinhan_exit(void)
-{
- hid_unregister_driver(&twinhan_driver);
-}
-
-module_init(twinhan_init);
-module_exit(twinhan_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c
index 2e56a1fd2375..fb8b516ff0ed 100644
--- a/drivers/hid/hid-uclogic.c
+++ b/drivers/hid/hid-uclogic.c
@@ -650,17 +650,6 @@ static struct hid_driver uclogic_driver = {
.id_table = uclogic_devices,
.report_fixup = uclogic_report_fixup,
};
+module_hid_driver(uclogic_driver);
-static int __init uclogic_init(void)
-{
- return hid_register_driver(&uclogic_driver);
-}
-
-static void __exit uclogic_exit(void)
-{
- hid_unregister_driver(&uclogic_driver);
-}
-
-module_init(uclogic_init);
-module_exit(uclogic_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 2f60da9ed066..a4a8bb0da688 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -953,23 +953,7 @@ static struct hid_driver wacom_driver = {
.raw_event = wacom_raw_event,
.input_mapped = wacom_input_mapped,
};
+module_hid_driver(wacom_driver);
-static int __init wacom_init(void)
-{
- int ret;
-
- ret = hid_register_driver(&wacom_driver);
- if (ret)
- pr_err("can't register wacom driver\n");
- return ret;
-}
-
-static void __exit wacom_exit(void)
-{
- hid_unregister_driver(&wacom_driver);
-}
-
-module_init(wacom_init);
-module_exit(wacom_exit);
MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c
index bb536ab5941e..059931d7b392 100644
--- a/drivers/hid/hid-waltop.c
+++ b/drivers/hid/hid-waltop.c
@@ -779,17 +779,6 @@ static struct hid_driver waltop_driver = {
.report_fixup = waltop_report_fixup,
.raw_event = waltop_raw_event,
};
+module_hid_driver(waltop_driver);
-static int __init waltop_init(void)
-{
- return hid_register_driver(&waltop_driver);
-}
-
-static void __exit waltop_exit(void)
-{
- hid_unregister_driver(&waltop_driver);
-}
-
-module_init(waltop_init);
-module_exit(waltop_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index 84e2fbec5fbb..0fb8ab93db68 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -1294,25 +1294,8 @@ static struct hid_driver wiimote_hid_driver = {
.remove = wiimote_hid_remove,
.raw_event = wiimote_hid_event,
};
+module_hid_driver(wiimote_hid_driver);
-static int __init wiimote_init(void)
-{
- int ret;
-
- ret = hid_register_driver(&wiimote_hid_driver);
- if (ret)
- pr_err("Can't register wiimote hid driver\n");
-
- return ret;
-}
-
-static void __exit wiimote_exit(void)
-{
- hid_unregister_driver(&wiimote_hid_driver);
-}
-
-module_init(wiimote_init);
-module_exit(wiimote_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver");
diff --git a/drivers/hid/hid-wiimote-debug.c b/drivers/hid/hid-wiimote-debug.c
index eec329197c16..90124ffaa2a5 100644
--- a/drivers/hid/hid-wiimote-debug.c
+++ b/drivers/hid/hid-wiimote-debug.c
@@ -31,7 +31,7 @@ static ssize_t wiidebug_eeprom_read(struct file *f, char __user *u, size_t s,
unsigned long flags;
ssize_t ret;
char buf[16];
- __u16 size;
+ __u16 size = 0;
if (s == 0)
return -EINVAL;
diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c
index 38ae87772e96..0472191d4a72 100644
--- a/drivers/hid/hid-wiimote-ext.c
+++ b/drivers/hid/hid-wiimote-ext.c
@@ -403,14 +403,14 @@ static void handler_nunchuck(struct wiimote_ext *ext, const __u8 *payload)
if (ext->motionp) {
input_report_key(ext->input,
- wiiext_keymap[WIIEXT_KEY_Z], !!(payload[5] & 0x04));
+ wiiext_keymap[WIIEXT_KEY_Z], !(payload[5] & 0x04));
input_report_key(ext->input,
- wiiext_keymap[WIIEXT_KEY_C], !!(payload[5] & 0x08));
+ wiiext_keymap[WIIEXT_KEY_C], !(payload[5] & 0x08));
} else {
input_report_key(ext->input,
- wiiext_keymap[WIIEXT_KEY_Z], !!(payload[5] & 0x01));
+ wiiext_keymap[WIIEXT_KEY_Z], !(payload[5] & 0x01));
input_report_key(ext->input,
- wiiext_keymap[WIIEXT_KEY_C], !!(payload[5] & 0x02));
+ wiiext_keymap[WIIEXT_KEY_C], !(payload[5] & 0x02));
}
input_sync(ext->input);
diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c
index f6ba81df71bd..af66452592e9 100644
--- a/drivers/hid/hid-zpff.c
+++ b/drivers/hid/hid-zpff.c
@@ -152,17 +152,6 @@ static struct hid_driver zp_driver = {
.id_table = zp_devices,
.probe = zp_probe,
};
+module_hid_driver(zp_driver);
-static int __init zp_init(void)
-{
- return hid_register_driver(&zp_driver);
-}
-
-static void __exit zp_exit(void)
-{
- hid_unregister_driver(&zp_driver);
-}
-
-module_init(zp_init);
-module_exit(zp_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
index 1ad85f2257b4..e4cddeccd6b5 100644
--- a/drivers/hid/hid-zydacron.c
+++ b/drivers/hid/hid-zydacron.c
@@ -219,17 +219,6 @@ static struct hid_driver zc_driver = {
.probe = zc_probe,
.remove = zc_remove,
};
+module_hid_driver(zc_driver);
-static int __init zc_init(void)
-{
- return hid_register_driver(&zc_driver);
-}
-
-static void __exit zc_exit(void)
-{
- hid_unregister_driver(&zc_driver);
-}
-
-module_init(zc_init);
-module_exit(zc_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 413a73187d33..f3bbbce8353b 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -581,6 +581,7 @@ int __init hidraw_init(void)
if (result < 0)
goto error_class;
+ printk(KERN_INFO "hidraw: raw HID events driver (C) Jiri Kosina\n");
out:
return result;
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index e766b5614ef5..ec7930217a6d 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -34,6 +34,7 @@
#include <linux/kernel.h>
#include <linux/hid.h>
#include <linux/mutex.h>
+#include <linux/acpi.h>
#include <linux/i2c/i2c-hid.h>
@@ -139,6 +140,8 @@ struct i2c_hid {
unsigned long flags; /* device flags */
wait_queue_head_t wait; /* For waiting the interrupt */
+
+ struct i2c_hid_platform_data pdata;
};
static int __i2c_hid_command(struct i2c_client *client,
@@ -821,6 +824,70 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
return 0;
}
+#ifdef CONFIG_ACPI
+static int i2c_hid_acpi_pdata(struct i2c_client *client,
+ struct i2c_hid_platform_data *pdata)
+{
+ static u8 i2c_hid_guid[] = {
+ 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45,
+ 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
+ };
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object params[4], *obj;
+ struct acpi_object_list input;
+ struct acpi_device *adev;
+ acpi_handle handle;
+
+ handle = ACPI_HANDLE(&client->dev);
+ if (!handle || acpi_bus_get_device(handle, &adev))
+ return -ENODEV;
+
+ input.count = ARRAY_SIZE(params);
+ input.pointer = params;
+
+ params[0].type = ACPI_TYPE_BUFFER;
+ params[0].buffer.length = sizeof(i2c_hid_guid);
+ params[0].buffer.pointer = i2c_hid_guid;
+ params[1].type = ACPI_TYPE_INTEGER;
+ params[1].integer.value = 1;
+ params[2].type = ACPI_TYPE_INTEGER;
+ params[2].integer.value = 1; /* HID function */
+ params[3].type = ACPI_TYPE_INTEGER;
+ params[3].integer.value = 0;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf))) {
+ dev_err(&client->dev, "device _DSM execution failed\n");
+ return -ENODEV;
+ }
+
+ obj = (union acpi_object *)buf.pointer;
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ dev_err(&client->dev, "device _DSM returned invalid type: %d\n",
+ obj->type);
+ kfree(buf.pointer);
+ return -EINVAL;
+ }
+
+ pdata->hid_descriptor_address = obj->integer.value;
+
+ kfree(buf.pointer);
+ return 0;
+}
+
+static const struct acpi_device_id i2c_hid_acpi_match[] = {
+ {"ACPI0C50", 0 },
+ {"PNP0C50", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match);
+#else
+static inline int i2c_hid_acpi_pdata(struct i2c_client *client,
+ struct i2c_hid_platform_data *pdata)
+{
+ return -ENODEV;
+}
+#endif
+
static int i2c_hid_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
@@ -832,11 +899,6 @@ static int i2c_hid_probe(struct i2c_client *client,
dbg_hid("HID probe called for i2c 0x%02x\n", client->addr);
- if (!platform_data) {
- dev_err(&client->dev, "HID register address not provided\n");
- return -EINVAL;
- }
-
if (!client->irq) {
dev_err(&client->dev,
"HID over i2c has not been provided an Int IRQ\n");
@@ -847,11 +909,22 @@ static int i2c_hid_probe(struct i2c_client *client,
if (!ihid)
return -ENOMEM;
+ if (!platform_data) {
+ ret = i2c_hid_acpi_pdata(client, &ihid->pdata);
+ if (ret) {
+ dev_err(&client->dev,
+ "HID register address not provided\n");
+ goto err;
+ }
+ } else {
+ ihid->pdata = *platform_data;
+ }
+
i2c_set_clientdata(client, ihid);
ihid->client = client;
- hidRegister = platform_data->hid_descriptor_address;
+ hidRegister = ihid->pdata.hid_descriptor_address;
ihid->wHIDDescRegister = cpu_to_le16(hidRegister);
init_waitqueue_head(&ihid->wait);
@@ -884,6 +957,7 @@ static int i2c_hid_probe(struct i2c_client *client,
hid->hid_get_raw_report = i2c_hid_get_raw_report;
hid->hid_output_raw_report = i2c_hid_output_raw_report;
hid->dev.parent = &client->dev;
+ ACPI_HANDLE_SET(&hid->dev, ACPI_HANDLE(&client->dev));
hid->bus = BUS_I2C;
hid->version = le16_to_cpu(ihid->hdesc.bcdVersion);
hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID);
@@ -975,6 +1049,7 @@ static struct i2c_driver i2c_hid_driver = {
.name = "i2c_hid",
.owner = THIS_MODULE,
.pm = &i2c_hid_pm,
+ .acpi_match_table = ACPI_PTR(i2c_hid_acpi_match),
},
.probe = i2c_hid_probe,
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 714cd8cc9579..fc307e0422af 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -11,6 +11,7 @@
*/
#include <linux/atomic.h>
+#include <linux/compat.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/hid.h>
@@ -276,6 +277,94 @@ static struct hid_ll_driver uhid_hid_driver = {
.parse = uhid_hid_parse,
};
+#ifdef CONFIG_COMPAT
+
+/* Apparently we haven't stepped on these rakes enough times yet. */
+struct uhid_create_req_compat {
+ __u8 name[128];
+ __u8 phys[64];
+ __u8 uniq[64];
+
+ compat_uptr_t rd_data;
+ __u16 rd_size;
+
+ __u16 bus;
+ __u32 vendor;
+ __u32 product;
+ __u32 version;
+ __u32 country;
+} __attribute__((__packed__));
+
+static int uhid_event_from_user(const char __user *buffer, size_t len,
+ struct uhid_event *event)
+{
+ if (is_compat_task()) {
+ u32 type;
+
+ if (get_user(type, buffer))
+ return -EFAULT;
+
+ if (type == UHID_CREATE) {
+ /*
+ * This is our messed up request with compat pointer.
+ * It is largish (more than 256 bytes) so we better
+ * allocate it from the heap.
+ */
+ struct uhid_create_req_compat *compat;
+
+ compat = kmalloc(sizeof(*compat), GFP_KERNEL);
+ if (!compat)
+ return -ENOMEM;
+
+ buffer += sizeof(type);
+ len -= sizeof(type);
+ if (copy_from_user(compat, buffer,
+ min(len, sizeof(*compat)))) {
+ kfree(compat);
+ return -EFAULT;
+ }
+
+ /* Shuffle the data over to proper structure */
+ event->type = type;
+
+ memcpy(event->u.create.name, compat->name,
+ sizeof(compat->name));
+ memcpy(event->u.create.phys, compat->phys,
+ sizeof(compat->phys));
+ memcpy(event->u.create.uniq, compat->uniq,
+ sizeof(compat->uniq));
+
+ event->u.create.rd_data = compat_ptr(compat->rd_data);
+ event->u.create.rd_size = compat->rd_size;
+
+ event->u.create.bus = compat->bus;
+ event->u.create.vendor = compat->vendor;
+ event->u.create.product = compat->product;
+ event->u.create.version = compat->version;
+ event->u.create.country = compat->country;
+
+ kfree(compat);
+ return 0;
+ }
+ /* All others can be copied directly */
+ }
+
+ if (copy_from_user(event, buffer, min(len, sizeof(*event))))
+ return -EFAULT;
+
+ return 0;
+}
+#else
+static int uhid_event_from_user(const char __user *buffer, size_t len,
+ struct uhid_event *event)
+{
+ if (copy_from_user(event, buffer, min(len, sizeof(*event))))
+ return -EFAULT;
+
+ return 0;
+}
+#endif
+
static int uhid_dev_create(struct uhid_device *uhid,
const struct uhid_event *ev)
{
@@ -498,10 +587,10 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
memset(&uhid->input_buf, 0, sizeof(uhid->input_buf));
len = min(count, sizeof(uhid->input_buf));
- if (copy_from_user(&uhid->input_buf, buffer, len)) {
- ret = -EFAULT;
+
+ ret = uhid_event_from_user(buffer, len, &uhid->input_buf);
+ if (ret)
goto unlock;
- }
switch (uhid->input_buf.type) {
case UHID_CREATE:
diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig
index b38ef6d8d049..64630f15f181 100644
--- a/drivers/hv/Kconfig
+++ b/drivers/hv/Kconfig
@@ -2,7 +2,7 @@ menu "Microsoft Hyper-V guest support"
config HYPERV
tristate "Microsoft Hyper-V client drivers"
- depends on X86 && ACPI && PCI
+ depends on X86 && ACPI && PCI && X86_LOCAL_APIC
help
Select this option to run Linux as a Hyper-V client operating
system.
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 773a2f25a8f0..0b122f8c7005 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -55,7 +55,7 @@ static void vmbus_setevent(struct vmbus_channel *channel)
[channel->monitor_grp].pending);
} else {
- vmbus_set_event(channel->offermsg.child_relid);
+ vmbus_set_event(channel);
}
}
@@ -181,7 +181,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
open_msg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle;
open_msg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >>
PAGE_SHIFT;
- open_msg->server_contextarea_gpadlhandle = 0;
+ open_msg->target_vp = newchannel->target_vp;
if (userdatalen > MAX_USER_DEFINED_BYTES) {
err = -EINVAL;
@@ -564,6 +564,7 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
struct scatterlist bufferlist[3];
u64 aligned_data = 0;
int ret;
+ bool signal = false;
/* Setup the descriptor */
@@ -580,9 +581,9 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
sg_set_buf(&bufferlist[2], &aligned_data,
packetlen_aligned - packetlen);
- ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
- if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
+ if (ret == 0 && signal)
vmbus_setevent(channel);
return ret;
@@ -606,6 +607,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
u32 packetlen_aligned;
struct scatterlist bufferlist[3];
u64 aligned_data = 0;
+ bool signal = false;
if (pagecount > MAX_PAGE_BUFFER_COUNT)
return -EINVAL;
@@ -641,9 +643,9 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
sg_set_buf(&bufferlist[2], &aligned_data,
packetlen_aligned - packetlen);
- ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
- if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
+ if (ret == 0 && signal)
vmbus_setevent(channel);
return ret;
@@ -665,6 +667,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
u32 packetlen_aligned;
struct scatterlist bufferlist[3];
u64 aligned_data = 0;
+ bool signal = false;
u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
multi_pagebuffer->len);
@@ -703,9 +706,9 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
sg_set_buf(&bufferlist[2], &aligned_data,
packetlen_aligned - packetlen);
- ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
- if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
+ if (ret == 0 && signal)
vmbus_setevent(channel);
return ret;
@@ -732,6 +735,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
u32 packetlen;
u32 userlen;
int ret;
+ bool signal = false;
*buffer_actual_len = 0;
*requestid = 0;
@@ -758,8 +762,10 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
/* Copy over the packet to the user buffer */
ret = hv_ringbuffer_read(&channel->inbound, buffer, userlen,
- (desc.offset8 << 3));
+ (desc.offset8 << 3), &signal);
+ if (signal)
+ vmbus_setevent(channel);
return 0;
}
@@ -774,8 +780,8 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
{
struct vmpacket_descriptor desc;
u32 packetlen;
- u32 userlen;
int ret;
+ bool signal = false;
*buffer_actual_len = 0;
*requestid = 0;
@@ -788,7 +794,6 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
packetlen = desc.len8 << 3;
- userlen = packetlen - (desc.offset8 << 3);
*buffer_actual_len = packetlen;
@@ -802,7 +807,11 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
*requestid = desc.trans_id;
/* Copy over the entire packet to the user buffer */
- ret = hv_ringbuffer_read(&channel->inbound, buffer, packetlen, 0);
+ ret = hv_ringbuffer_read(&channel->inbound, buffer, packetlen, 0,
+ &signal);
+
+ if (signal)
+ vmbus_setevent(channel);
return 0;
}
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 2f84c5cff8d4..53a8600162a5 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -257,6 +257,70 @@ static void vmbus_process_offer(struct work_struct *work)
}
}
+enum {
+ IDE = 0,
+ SCSI,
+ NIC,
+ MAX_PERF_CHN,
+};
+
+/*
+ * This is an array of device_ids (device types) that are performance critical.
+ * We attempt to distribute the interrupt load for these devices across
+ * all available CPUs.
+ */
+static const struct hv_vmbus_device_id hp_devs[] = {
+ /* IDE */
+ { HV_IDE_GUID, },
+ /* Storage - SCSI */
+ { HV_SCSI_GUID, },
+ /* Network */
+ { HV_NIC_GUID, },
+};
+
+
+/*
+ * We use this state to statically distribute the channel interrupt load.
+ */
+static u32 next_vp;
+
+/*
+ * Starting with Win8, we can statically distribute the incoming
+ * channel interrupt load by binding a channel to VCPU. We
+ * implement here a simple round robin scheme for distributing
+ * the interrupt load.
+ * We will bind channels that are not performance critical to cpu 0 and
+ * performance critical channels (IDE, SCSI and Network) will be uniformly
+ * distributed across all available CPUs.
+ */
+static u32 get_vp_index(uuid_le *type_guid)
+{
+ u32 cur_cpu;
+ int i;
+ bool perf_chn = false;
+ u32 max_cpus = num_online_cpus();
+
+ for (i = IDE; i < MAX_PERF_CHN; i++) {
+ if (!memcmp(type_guid->b, hp_devs[i].guid,
+ sizeof(uuid_le))) {
+ perf_chn = true;
+ break;
+ }
+ }
+ if ((vmbus_proto_version == VERSION_WS2008) ||
+ (vmbus_proto_version == VERSION_WIN7) || (!perf_chn)) {
+ /*
+ * Prior to win8, all channel interrupts are
+ * delivered on cpu 0.
+ * Also if the channel is not a performance critical
+ * channel, bind it to cpu 0.
+ */
+ return 0;
+ }
+ cur_cpu = (++next_vp % max_cpus);
+ return 0;
+}
+
/*
* vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
*
@@ -275,6 +339,35 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
return;
}
+ /*
+ * By default we setup state to enable batched
+ * reading. A specific service can choose to
+ * disable this prior to opening the channel.
+ */
+ newchannel->batched_reading = true;
+
+ /*
+ * Setup state for signalling the host.
+ */
+ newchannel->sig_event = (struct hv_input_signal_event *)
+ (ALIGN((unsigned long)
+ &newchannel->sig_buf,
+ HV_HYPERCALL_PARAM_ALIGN));
+
+ newchannel->sig_event->connectionid.asu32 = 0;
+ newchannel->sig_event->connectionid.u.id = VMBUS_EVENT_CONNECTION_ID;
+ newchannel->sig_event->flag_number = 0;
+ newchannel->sig_event->rsvdz = 0;
+
+ if (vmbus_proto_version != VERSION_WS2008) {
+ newchannel->is_dedicated_interrupt =
+ (offer->is_dedicated_interrupt != 0);
+ newchannel->sig_event->connectionid.u.id =
+ offer->connection_id;
+ }
+
+ newchannel->target_vp = get_vp_index(&offer->offer.if_type);
+
memcpy(&newchannel->offermsg, offer,
sizeof(struct vmbus_channel_offer_channel));
newchannel->monitor_grp = (u8)offer->monitorid / 32;
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 650c9f0b6642..253a74ba245c 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -30,6 +30,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/hyperv.h>
+#include <linux/export.h>
#include <asm/hyperv.h>
#include "hyperv_vmbus.h"
@@ -40,15 +41,99 @@ struct vmbus_connection vmbus_connection = {
};
/*
+ * Negotiated protocol version with the host.
+ */
+__u32 vmbus_proto_version;
+EXPORT_SYMBOL_GPL(vmbus_proto_version);
+
+static __u32 vmbus_get_next_version(__u32 current_version)
+{
+ switch (current_version) {
+ case (VERSION_WIN7):
+ return VERSION_WS2008;
+
+ case (VERSION_WIN8):
+ return VERSION_WIN7;
+
+ case (VERSION_WS2008):
+ default:
+ return VERSION_INVAL;
+ }
+}
+
+static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
+ __u32 version)
+{
+ int ret = 0;
+ struct vmbus_channel_initiate_contact *msg;
+ unsigned long flags;
+ int t;
+
+ init_completion(&msginfo->waitevent);
+
+ msg = (struct vmbus_channel_initiate_contact *)msginfo->msg;
+
+ msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT;
+ msg->vmbus_version_requested = version;
+ msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
+ msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages);
+ msg->monitor_page2 = virt_to_phys(
+ (void *)((unsigned long)vmbus_connection.monitor_pages +
+ PAGE_SIZE));
+
+ /*
+ * Add to list before we send the request since we may
+ * receive the response before returning from this routine
+ */
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_add_tail(&msginfo->msglistentry,
+ &vmbus_connection.chn_msg_list);
+
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+
+ ret = vmbus_post_msg(msg,
+ sizeof(struct vmbus_channel_initiate_contact));
+ if (ret != 0) {
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_del(&msginfo->msglistentry);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
+ flags);
+ return ret;
+ }
+
+ /* Wait for the connection response */
+ t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
+ if (t == 0) {
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock,
+ flags);
+ list_del(&msginfo->msglistentry);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
+ flags);
+ return -ETIMEDOUT;
+ }
+
+ spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
+ list_del(&msginfo->msglistentry);
+ spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+
+ /* Check if successful */
+ if (msginfo->response.version_response.version_supported) {
+ vmbus_connection.conn_state = CONNECTED;
+ } else {
+ return -ECONNREFUSED;
+ }
+
+ return ret;
+}
+
+/*
* vmbus_connect - Sends a connect request on the partition service connection
*/
int vmbus_connect(void)
{
int ret = 0;
- int t;
struct vmbus_channel_msginfo *msginfo = NULL;
- struct vmbus_channel_initiate_contact *msg;
- unsigned long flags;
+ __u32 version;
/* Initialize the vmbus connection */
vmbus_connection.conn_state = CONNECTING;
@@ -99,69 +184,38 @@ int vmbus_connect(void)
goto cleanup;
}
- init_completion(&msginfo->waitevent);
-
- msg = (struct vmbus_channel_initiate_contact *)msginfo->msg;
-
- msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT;
- msg->vmbus_version_requested = VMBUS_REVISION_NUMBER;
- msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
- msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages);
- msg->monitor_page2 = virt_to_phys(
- (void *)((unsigned long)vmbus_connection.monitor_pages +
- PAGE_SIZE));
-
/*
- * Add to list before we send the request since we may
- * receive the response before returning from this routine
+ * Negotiate a compatible VMBUS version number with the
+ * host. We start with the highest number we can support
+ * and work our way down until we negotiate a compatible
+ * version.
*/
- spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
- list_add_tail(&msginfo->msglistentry,
- &vmbus_connection.chn_msg_list);
- spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+ version = VERSION_CURRENT;
- ret = vmbus_post_msg(msg,
- sizeof(struct vmbus_channel_initiate_contact));
- if (ret != 0) {
- spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
- list_del(&msginfo->msglistentry);
- spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
- flags);
- goto cleanup;
- }
+ do {
+ ret = vmbus_negotiate_version(msginfo, version);
+ if (ret == 0)
+ break;
- /* Wait for the connection response */
- t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
- if (t == 0) {
- spin_lock_irqsave(&vmbus_connection.channelmsg_lock,
- flags);
- list_del(&msginfo->msglistentry);
- spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
- flags);
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ version = vmbus_get_next_version(version);
+ } while (version != VERSION_INVAL);
- spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
- list_del(&msginfo->msglistentry);
- spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
-
- /* Check if successful */
- if (msginfo->response.version_response.version_supported) {
- vmbus_connection.conn_state = CONNECTED;
- } else {
- pr_err("Unable to connect, "
- "Version %d not supported by Hyper-V\n",
- VMBUS_REVISION_NUMBER);
- ret = -ECONNREFUSED;
+ if (version == VERSION_INVAL)
goto cleanup;
- }
+
+ vmbus_proto_version = version;
+ pr_info("Hyper-V Host Build:%d-%d.%d-%d-%d.%d; Vmbus version:%d.%d\n",
+ host_info_eax, host_info_ebx >> 16,
+ host_info_ebx & 0xFFFF, host_info_ecx,
+ host_info_edx >> 24, host_info_edx & 0xFFFFFF,
+ version >> 16, version & 0xFFFF);
kfree(msginfo);
return 0;
cleanup:
+ pr_err("Unable to connect to host\n");
vmbus_connection.conn_state = DISCONNECTED;
if (vmbus_connection.work_queue)
@@ -212,6 +266,9 @@ static void process_chn_event(u32 relid)
{
struct vmbus_channel *channel;
unsigned long flags;
+ void *arg;
+ bool read_state;
+ u32 bytes_to_read;
/*
* Find the channel based on this relid and invokes the
@@ -234,10 +291,29 @@ static void process_chn_event(u32 relid)
*/
spin_lock_irqsave(&channel->inbound_lock, flags);
- if (channel->onchannel_callback != NULL)
- channel->onchannel_callback(channel->channel_callback_context);
- else
+ if (channel->onchannel_callback != NULL) {
+ arg = channel->channel_callback_context;
+ read_state = channel->batched_reading;
+ /*
+ * This callback reads the messages sent by the host.
+ * We can optimize host to guest signaling by ensuring:
+ * 1. While reading the channel, we disable interrupts from
+ * host.
+ * 2. Ensure that we process all posted messages from the host
+ * before returning from this callback.
+ * 3. Once we return, enable signaling from the host. Once this
+ * state is set we check to see if additional packets are
+ * available to read. In this case we repeat the process.
+ */
+
+ do {
+ hv_begin_read(&channel->inbound);
+ channel->onchannel_callback(arg);
+ bytes_to_read = hv_end_read(&channel->inbound);
+ } while (read_state && (bytes_to_read != 0));
+ } else {
pr_err("no channel callback for relid - %u\n", relid);
+ }
spin_unlock_irqrestore(&channel->inbound_lock, flags);
}
@@ -248,10 +324,32 @@ static void process_chn_event(u32 relid)
void vmbus_on_event(unsigned long data)
{
u32 dword;
- u32 maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
+ u32 maxdword;
int bit;
u32 relid;
- u32 *recv_int_page = vmbus_connection.recv_int_page;
+ u32 *recv_int_page = NULL;
+ void *page_addr;
+ int cpu = smp_processor_id();
+ union hv_synic_event_flags *event;
+
+ if ((vmbus_proto_version == VERSION_WS2008) ||
+ (vmbus_proto_version == VERSION_WIN7)) {
+ maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
+ recv_int_page = vmbus_connection.recv_int_page;
+ } else {
+ /*
+ * When the host is win8 and beyond, the event page
+ * can be directly checked to get the id of the channel
+ * that has the interrupt pending.
+ */
+ maxdword = HV_EVENT_FLAGS_DWORD_COUNT;
+ page_addr = hv_context.synic_event_page[cpu];
+ event = (union hv_synic_event_flags *)page_addr +
+ VMBUS_MESSAGE_SINT;
+ recv_int_page = event->flags32;
+ }
+
+
/* Check events */
if (!recv_int_page)
@@ -307,12 +405,16 @@ int vmbus_post_msg(void *buffer, size_t buflen)
/*
* vmbus_set_event - Send an event notification to the parent
*/
-int vmbus_set_event(u32 child_relid)
+int vmbus_set_event(struct vmbus_channel *channel)
{
- /* Each u32 represents 32 channels */
- sync_set_bit(child_relid & 31,
- (unsigned long *)vmbus_connection.send_int_page +
- (child_relid >> 5));
+ u32 child_relid = channel->offermsg.child_relid;
+
+ if (!channel->is_dedicated_interrupt) {
+ /* Each u32 represents 32 channels */
+ sync_set_bit(child_relid & 31,
+ (unsigned long *)vmbus_connection.send_int_page +
+ (child_relid >> 5));
+ }
- return hv_signal_event();
+ return hv_signal_event(channel->sig_event);
}
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 3648f8f0f368..1c5481da6e4a 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -27,6 +27,7 @@
#include <linux/vmalloc.h>
#include <linux/hyperv.h>
#include <linux/version.h>
+#include <linux/interrupt.h>
#include <asm/hyperv.h>
#include "hyperv_vmbus.h"
@@ -34,13 +35,16 @@
struct hv_context hv_context = {
.synic_initialized = false,
.hypercall_page = NULL,
- .signal_event_param = NULL,
- .signal_event_buffer = NULL,
};
/*
* query_hypervisor_info - Get version info of the windows hypervisor
*/
+unsigned int host_info_eax;
+unsigned int host_info_ebx;
+unsigned int host_info_ecx;
+unsigned int host_info_edx;
+
static int query_hypervisor_info(void)
{
unsigned int eax;
@@ -70,13 +74,10 @@ static int query_hypervisor_info(void)
edx = 0;
op = HVCPUID_VERSION;
cpuid(op, &eax, &ebx, &ecx, &edx);
- pr_info("Hyper-V Host OS Build:%d-%d.%d-%d-%d.%d\n",
- eax,
- ebx >> 16,
- ebx & 0xFFFF,
- ecx,
- edx >> 24,
- edx & 0xFFFFFF);
+ host_info_eax = eax;
+ host_info_ebx = ebx;
+ host_info_ecx = ecx;
+ host_info_edx = edx;
}
return max_leaf;
}
@@ -137,6 +138,10 @@ int hv_init(void)
memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
memset(hv_context.synic_message_page, 0,
sizeof(void *) * NR_CPUS);
+ memset(hv_context.vp_index, 0,
+ sizeof(int) * NR_CPUS);
+ memset(hv_context.event_dpc, 0,
+ sizeof(void *) * NR_CPUS);
max_leaf = query_hypervisor_info();
@@ -168,24 +173,6 @@ int hv_init(void)
hv_context.hypercall_page = virtaddr;
- /* Setup the global signal event param for the signal event hypercall */
- hv_context.signal_event_buffer =
- kmalloc(sizeof(struct hv_input_signal_event_buffer),
- GFP_KERNEL);
- if (!hv_context.signal_event_buffer)
- goto cleanup;
-
- hv_context.signal_event_param =
- (struct hv_input_signal_event *)
- (ALIGN((unsigned long)
- hv_context.signal_event_buffer,
- HV_HYPERCALL_PARAM_ALIGN));
- hv_context.signal_event_param->connectionid.asu32 = 0;
- hv_context.signal_event_param->connectionid.u.id =
- VMBUS_EVENT_CONNECTION_ID;
- hv_context.signal_event_param->flag_number = 0;
- hv_context.signal_event_param->rsvdz = 0;
-
return 0;
cleanup:
@@ -213,10 +200,6 @@ void hv_cleanup(void)
/* Reset our OS id */
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
- kfree(hv_context.signal_event_buffer);
- hv_context.signal_event_buffer = NULL;
- hv_context.signal_event_param = NULL;
-
if (hv_context.hypercall_page) {
hypercall_msr.as_uint64 = 0;
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
@@ -273,13 +256,12 @@ int hv_post_message(union hv_connection_id connection_id,
*
* This involves a hypercall.
*/
-u16 hv_signal_event(void)
+u16 hv_signal_event(void *con_id)
{
u16 status;
- status = do_hypercall(HVCALL_SIGNAL_EVENT,
- hv_context.signal_event_param,
- NULL) & 0xFFFF;
+ status = (do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL) & 0xFFFF);
+
return status;
}
@@ -297,6 +279,7 @@ void hv_synic_init(void *irqarg)
union hv_synic_siefp siefp;
union hv_synic_sint shared_sint;
union hv_synic_scontrol sctrl;
+ u64 vp_index;
u32 irq_vector = *((u32 *)(irqarg));
int cpu = smp_processor_id();
@@ -307,6 +290,15 @@ void hv_synic_init(void *irqarg)
/* Check the version */
rdmsrl(HV_X64_MSR_SVERSION, version);
+ hv_context.event_dpc[cpu] = (struct tasklet_struct *)
+ kmalloc(sizeof(struct tasklet_struct),
+ GFP_ATOMIC);
+ if (hv_context.event_dpc[cpu] == NULL) {
+ pr_err("Unable to allocate event dpc\n");
+ goto cleanup;
+ }
+ tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
+
hv_context.synic_message_page[cpu] =
(void *)get_zeroed_page(GFP_ATOMIC);
@@ -345,7 +337,7 @@ void hv_synic_init(void *irqarg)
shared_sint.as_uint64 = 0;
shared_sint.vector = irq_vector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */
shared_sint.masked = false;
- shared_sint.auto_eoi = false;
+ shared_sint.auto_eoi = true;
wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
@@ -356,6 +348,14 @@ void hv_synic_init(void *irqarg)
wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
hv_context.synic_initialized = true;
+
+ /*
+ * Setup the mapping between Hyper-V's notion
+ * of cpuid and Linux' notion of cpuid.
+ * This array will be indexed using Linux cpuid.
+ */
+ rdmsrl(HV_X64_MSR_VP_INDEX, vp_index);
+ hv_context.vp_index[cpu] = (u32)vp_index;
return;
cleanup:
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index dd289fd179ca..37873213e24f 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -29,7 +29,6 @@
#include <linux/memory_hotplug.h>
#include <linux/memory.h>
#include <linux/notifier.h>
-#include <linux/mman.h>
#include <linux/percpu_counter.h>
#include <linux/hyperv.h>
@@ -415,10 +414,17 @@ struct dm_info_msg {
static bool hot_add;
static bool do_hot_add;
+/*
+ * Delay reporting memory pressure by
+ * the specified number of seconds.
+ */
+static uint pressure_report_delay = 30;
module_param(hot_add, bool, (S_IRUGO | S_IWUSR));
MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add");
+module_param(pressure_report_delay, uint, (S_IRUGO | S_IWUSR));
+MODULE_PARM_DESC(pressure_report_delay, "Delay in secs in reporting pressure");
static atomic_t trans_id = ATOMIC_INIT(0);
static int dm_ring_size = (5 * PAGE_SIZE);
@@ -517,6 +523,34 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)
}
}
+unsigned long compute_balloon_floor(void)
+{
+ unsigned long min_pages;
+#define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
+ /* Simple continuous piecewiese linear function:
+ * max MiB -> min MiB gradient
+ * 0 0
+ * 16 16
+ * 32 24
+ * 128 72 (1/2)
+ * 512 168 (1/4)
+ * 2048 360 (1/8)
+ * 8192 552 (1/32)
+ * 32768 1320
+ * 131072 4392
+ */
+ if (totalram_pages < MB2PAGES(128))
+ min_pages = MB2PAGES(8) + (totalram_pages >> 1);
+ else if (totalram_pages < MB2PAGES(512))
+ min_pages = MB2PAGES(40) + (totalram_pages >> 2);
+ else if (totalram_pages < MB2PAGES(2048))
+ min_pages = MB2PAGES(104) + (totalram_pages >> 3);
+ else
+ min_pages = MB2PAGES(296) + (totalram_pages >> 5);
+#undef MB2PAGES
+ return min_pages;
+}
+
/*
* Post our status as it relates memory pressure to the
* host. Host expects the guests to post this status
@@ -530,15 +564,30 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)
static void post_status(struct hv_dynmem_device *dm)
{
struct dm_status status;
+ struct sysinfo val;
-
+ if (pressure_report_delay > 0) {
+ --pressure_report_delay;
+ return;
+ }
+ si_meminfo(&val);
memset(&status, 0, sizeof(struct dm_status));
status.hdr.type = DM_STATUS_REPORT;
status.hdr.size = sizeof(struct dm_status);
status.hdr.trans_id = atomic_inc_return(&trans_id);
-
- status.num_committed = vm_memory_committed();
+ /*
+ * The host expects the guest to report free memory.
+ * Further, the host expects the pressure information to
+ * include the ballooned out pages.
+ * For a given amount of memory that we are managing, we
+ * need to compute a floor below which we should not balloon.
+ * Compute this and add it to the pressure report.
+ */
+ status.num_avail = val.freeram;
+ status.num_committed = vm_memory_committed() +
+ dm->num_pages_ballooned +
+ compute_balloon_floor();
vmbus_sendpacket(dm->dev->channel, &status,
sizeof(struct dm_status),
@@ -547,8 +596,6 @@ static void post_status(struct hv_dynmem_device *dm)
}
-
-
static void free_balloon_pages(struct hv_dynmem_device *dm,
union dm_mem_page_range *range_array)
{
@@ -1013,9 +1060,7 @@ static int balloon_remove(struct hv_device *dev)
static const struct hv_vmbus_device_id id_table[] = {
/* Dynamic Memory Class ID */
/* 525074DC-8985-46e2-8057-A307DC18A502 */
- { VMBUS_DEVICE(0xdc, 0x74, 0x50, 0X52, 0x85, 0x89, 0xe2, 0x46,
- 0x80, 0x57, 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02)
- },
+ { HV_DM_GUID, },
{ },
};
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index a0667de7a04c..1d4cbd8e8261 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -49,6 +49,16 @@ static struct hv_util_service util_kvp = {
.util_deinit = hv_kvp_deinit,
};
+static void perform_shutdown(struct work_struct *dummy)
+{
+ orderly_poweroff(true);
+}
+
+/*
+ * Perform the shutdown operation in a thread context.
+ */
+static DECLARE_WORK(shutdown_work, perform_shutdown);
+
static void shutdown_onchannelcallback(void *context)
{
struct vmbus_channel *channel = context;
@@ -106,7 +116,7 @@ static void shutdown_onchannelcallback(void *context)
}
if (execute_shutdown == true)
- orderly_poweroff(true);
+ schedule_work(&shutdown_work);
}
/*
@@ -274,6 +284,16 @@ static int util_probe(struct hv_device *dev,
}
}
+ /*
+ * The set of services managed by the util driver are not performance
+ * critical and do not need batched reading. Furthermore, some services
+ * such as KVP can only handle one message from the host at a time.
+ * Turn off batched reading for all util drivers before we open the
+ * channel.
+ */
+
+ set_channel_read_state(dev->channel, false);
+
ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
srv->util_cb, dev->channel);
if (ret)
@@ -304,21 +324,21 @@ static int util_remove(struct hv_device *dev)
static const struct hv_vmbus_device_id id_table[] = {
/* Shutdown guid */
- { VMBUS_DEVICE(0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
- 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB)
- .driver_data = (unsigned long)&util_shutdown },
+ { HV_SHUTDOWN_GUID,
+ .driver_data = (unsigned long)&util_shutdown
+ },
/* Time synch guid */
- { VMBUS_DEVICE(0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
- 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf)
- .driver_data = (unsigned long)&util_timesynch },
+ { HV_TS_GUID,
+ .driver_data = (unsigned long)&util_timesynch
+ },
/* Heartbeat guid */
- { VMBUS_DEVICE(0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
- 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d)
- .driver_data = (unsigned long)&util_heartbeat },
+ { HV_HEART_BEAT_GUID,
+ .driver_data = (unsigned long)&util_heartbeat
+ },
/* KVP guid */
- { VMBUS_DEVICE(0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
- 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6)
- .driver_data = (unsigned long)&util_kvp },
+ { HV_KVP_GUID,
+ .driver_data = (unsigned long)&util_kvp
+ },
{ },
};
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index d8d1fadb398a..12f2f9e989f7 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -101,15 +101,6 @@ enum hv_message_type {
/* Define invalid partition identifier. */
#define HV_PARTITION_ID_INVALID ((u64)0x0)
-/* Define connection identifier type. */
-union hv_connection_id {
- u32 asu32;
- struct {
- u32 id:24;
- u32 reserved:8;
- } u;
-};
-
/* Define port identifier type. */
union hv_port_id {
u32 asu32;
@@ -338,13 +329,6 @@ struct hv_input_post_message {
u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
};
-/* Definition of the hv_signal_event hypercall input structure. */
-struct hv_input_signal_event {
- union hv_connection_id connectionid;
- u16 flag_number;
- u16 rsvdz;
-};
-
/*
* Versioning definitions used for guests reporting themselves to the
* hypervisor, and visa versa.
@@ -498,11 +482,6 @@ static const uuid_le VMBUS_SERVICE_ID = {
-struct hv_input_signal_event_buffer {
- u64 align8;
- struct hv_input_signal_event event;
-};
-
struct hv_context {
/* We only support running on top of Hyper-V
* So at this point this really can only contain the Hyper-V ID
@@ -513,16 +492,24 @@ struct hv_context {
bool synic_initialized;
- /*
- * This is used as an input param to HvCallSignalEvent hypercall. The
- * input param is immutable in our usage and must be dynamic mem (vs
- * stack or global). */
- struct hv_input_signal_event_buffer *signal_event_buffer;
- /* 8-bytes aligned of the buffer above */
- struct hv_input_signal_event *signal_event_param;
-
void *synic_message_page[NR_CPUS];
void *synic_event_page[NR_CPUS];
+ /*
+ * Hypervisor's notion of virtual processor ID is different from
+ * Linux' notion of CPU ID. This information can only be retrieved
+ * in the context of the calling CPU. Setup a map for easy access
+ * to this information:
+ *
+ * vp_index[a] is the Hyper-V's processor ID corresponding to
+ * Linux cpuid 'a'.
+ */
+ u32 vp_index[NR_CPUS];
+ /*
+ * Starting with win8, we can take channel interrupts on any CPU;
+ * we will manage the tasklet that handles events on a per CPU
+ * basis.
+ */
+ struct tasklet_struct *event_dpc[NR_CPUS];
};
extern struct hv_context hv_context;
@@ -538,12 +525,19 @@ extern int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type,
void *payload, size_t payload_size);
-extern u16 hv_signal_event(void);
+extern u16 hv_signal_event(void *con_id);
extern void hv_synic_init(void *irqarg);
extern void hv_synic_cleanup(void *arg);
+/*
+ * Host version information.
+ */
+extern unsigned int host_info_eax;
+extern unsigned int host_info_ebx;
+extern unsigned int host_info_ecx;
+extern unsigned int host_info_edx;
/* Interface */
@@ -555,7 +549,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
struct scatterlist *sglist,
- u32 sgcount);
+ u32 sgcount, bool *signal);
int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
u32 buflen);
@@ -563,13 +557,16 @@ int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
int hv_ringbuffer_read(struct hv_ring_buffer_info *ring_info,
void *buffer,
u32 buflen,
- u32 offset);
+ u32 offset, bool *signal);
-u32 hv_get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *ring_info);
void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info);
+void hv_begin_read(struct hv_ring_buffer_info *rbi);
+
+u32 hv_end_read(struct hv_ring_buffer_info *rbi);
+
/*
* Maximum channels is determined by the size of the interrupt page
* which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt
@@ -657,7 +654,7 @@ int vmbus_connect(void);
int vmbus_post_msg(void *buffer, size_t buflen);
-int vmbus_set_event(u32 child_relid);
+int vmbus_set_event(struct vmbus_channel *channel);
void vmbus_on_event(unsigned long data);
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 7233c88f01b8..cafa72ffdc30 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -29,6 +29,105 @@
#include "hyperv_vmbus.h"
+void hv_begin_read(struct hv_ring_buffer_info *rbi)
+{
+ rbi->ring_buffer->interrupt_mask = 1;
+ smp_mb();
+}
+
+u32 hv_end_read(struct hv_ring_buffer_info *rbi)
+{
+ u32 read;
+ u32 write;
+
+ rbi->ring_buffer->interrupt_mask = 0;
+ smp_mb();
+
+ /*
+ * Now check to see if the ring buffer is still empty.
+ * If it is not, we raced and we need to process new
+ * incoming messages.
+ */
+ hv_get_ringbuffer_availbytes(rbi, &read, &write);
+
+ return read;
+}
+
+/*
+ * When we write to the ring buffer, check if the host needs to
+ * be signaled. Here is the details of this protocol:
+ *
+ * 1. The host guarantees that while it is draining the
+ * ring buffer, it will set the interrupt_mask to
+ * indicate it does not need to be interrupted when
+ * new data is placed.
+ *
+ * 2. The host guarantees that it will completely drain
+ * the ring buffer before exiting the read loop. Further,
+ * once the ring buffer is empty, it will clear the
+ * interrupt_mask and re-check to see if new data has
+ * arrived.
+ */
+
+static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi)
+{
+ if (rbi->ring_buffer->interrupt_mask)
+ return false;
+
+ /*
+ * This is the only case we need to signal when the
+ * ring transitions from being empty to non-empty.
+ */
+ if (old_write == rbi->ring_buffer->read_index)
+ return true;
+
+ return false;
+}
+
+/*
+ * To optimize the flow management on the send-side,
+ * when the sender is blocked because of lack of
+ * sufficient space in the ring buffer, potential the
+ * consumer of the ring buffer can signal the producer.
+ * This is controlled by the following parameters:
+ *
+ * 1. pending_send_sz: This is the size in bytes that the
+ * producer is trying to send.
+ * 2. The feature bit feat_pending_send_sz set to indicate if
+ * the consumer of the ring will signal when the ring
+ * state transitions from being full to a state where
+ * there is room for the producer to send the pending packet.
+ */
+
+static bool hv_need_to_signal_on_read(u32 old_rd,
+ struct hv_ring_buffer_info *rbi)
+{
+ u32 prev_write_sz;
+ u32 cur_write_sz;
+ u32 r_size;
+ u32 write_loc = rbi->ring_buffer->write_index;
+ u32 read_loc = rbi->ring_buffer->read_index;
+ u32 pending_sz = rbi->ring_buffer->pending_send_sz;
+
+ /*
+ * If the other end is not blocked on write don't bother.
+ */
+ if (pending_sz == 0)
+ return false;
+
+ r_size = rbi->ring_datasize;
+ cur_write_sz = write_loc >= read_loc ? r_size - (write_loc - read_loc) :
+ read_loc - write_loc;
+
+ prev_write_sz = write_loc >= old_rd ? r_size - (write_loc - old_rd) :
+ old_rd - write_loc;
+
+
+ if ((prev_write_sz < pending_sz) && (cur_write_sz >= pending_sz))
+ return true;
+
+ return false;
+}
/*
* hv_get_next_write_location()
@@ -239,19 +338,6 @@ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
}
}
-
-/*
- *
- * hv_get_ringbuffer_interrupt_mask()
- *
- * Get the interrupt mask for the specified ring buffer
- *
- */
-u32 hv_get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *rbi)
-{
- return rbi->ring_buffer->interrupt_mask;
-}
-
/*
*
* hv_ringbuffer_init()
@@ -298,7 +384,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
*
*/
int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
- struct scatterlist *sglist, u32 sgcount)
+ struct scatterlist *sglist, u32 sgcount, bool *signal)
{
int i = 0;
u32 bytes_avail_towrite;
@@ -307,6 +393,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
struct scatterlist *sg;
u32 next_write_location;
+ u32 old_write;
u64 prev_indices = 0;
unsigned long flags;
@@ -335,6 +422,8 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
/* Write to the ring buffer */
next_write_location = hv_get_next_write_location(outring_info);
+ old_write = next_write_location;
+
for_each_sg(sglist, sg, sgcount, i)
{
next_write_location = hv_copyto_ringbuffer(outring_info,
@@ -351,14 +440,16 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
&prev_indices,
sizeof(u64));
- /* Make sure we flush all writes before updating the writeIndex */
- smp_wmb();
+ /* Issue a full memory barrier before updating the write index */
+ smp_mb();
/* Now, update the write location */
hv_set_next_write_location(outring_info, next_write_location);
spin_unlock_irqrestore(&outring_info->ring_lock, flags);
+
+ *signal = hv_need_to_signal(old_write, outring_info);
return 0;
}
@@ -414,13 +505,14 @@ int hv_ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
*
*/
int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
- u32 buflen, u32 offset)
+ u32 buflen, u32 offset, bool *signal)
{
u32 bytes_avail_towrite;
u32 bytes_avail_toread;
u32 next_read_location = 0;
u64 prev_indices = 0;
unsigned long flags;
+ u32 old_read;
if (buflen <= 0)
return -EINVAL;
@@ -431,6 +523,8 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
&bytes_avail_toread,
&bytes_avail_towrite);
+ old_read = bytes_avail_toread;
+
/* Make sure there is something to read */
if (bytes_avail_toread < buflen) {
spin_unlock_irqrestore(&inring_info->ring_lock, flags);
@@ -461,5 +555,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
spin_unlock_irqrestore(&inring_info->ring_lock, flags);
+ *signal = hv_need_to_signal_on_read(old_read, inring_info);
+
return 0;
}
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 8e1a9ec53003..cf19dfa5ead1 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -33,6 +33,7 @@
#include <acpi/acpi_bus.h>
#include <linux/completion.h>
#include <linux/hyperv.h>
+#include <linux/kernel_stat.h>
#include <asm/hyperv.h>
#include <asm/hypervisor.h>
#include "hyperv_vmbus.h"
@@ -41,7 +42,6 @@
static struct acpi_device *hv_acpi_dev;
static struct tasklet_struct msg_dpc;
-static struct tasklet_struct event_dpc;
static struct completion probe_event;
static int irq;
@@ -454,21 +454,40 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
union hv_synic_event_flags *event;
bool handled = false;
+ page_addr = hv_context.synic_event_page[cpu];
+ if (page_addr == NULL)
+ return IRQ_NONE;
+
+ event = (union hv_synic_event_flags *)page_addr +
+ VMBUS_MESSAGE_SINT;
/*
* Check for events before checking for messages. This is the order
* in which events and messages are checked in Windows guests on
* Hyper-V, and the Windows team suggested we do the same.
*/
- page_addr = hv_context.synic_event_page[cpu];
- event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
+ if ((vmbus_proto_version == VERSION_WS2008) ||
+ (vmbus_proto_version == VERSION_WIN7)) {
- /* Since we are a child, we only need to check bit 0 */
- if (sync_test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) {
+ /* Since we are a child, we only need to check bit 0 */
+ if (sync_test_and_clear_bit(0,
+ (unsigned long *) &event->flags32[0])) {
+ handled = true;
+ }
+ } else {
+ /*
+ * Our host is win8 or above. The signaling mechanism
+ * has changed and we can directly look at the event page.
+ * If bit n is set then we have an interrup on the channel
+ * whose id is n.
+ */
handled = true;
- tasklet_schedule(&event_dpc);
}
+ if (handled)
+ tasklet_schedule(hv_context.event_dpc[cpu]);
+
+
page_addr = hv_context.synic_message_page[cpu];
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
@@ -485,6 +504,19 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
}
/*
+ * vmbus interrupt flow handler:
+ * vmbus interrupts can concurrently occur on multiple CPUs and
+ * can be handled concurrently.
+ */
+
+static void vmbus_flow_handler(unsigned int irq, struct irq_desc *desc)
+{
+ kstat_incr_irqs_this_cpu(irq, desc);
+
+ desc->action->handler(irq, desc->action->dev_id);
+}
+
+/*
* vmbus_bus_init -Main vmbus driver initialization routine.
*
* Here, we
@@ -506,7 +538,6 @@ static int vmbus_bus_init(int irq)
}
tasklet_init(&msg_dpc, vmbus_on_msg_dpc, 0);
- tasklet_init(&event_dpc, vmbus_on_event, 0);
ret = bus_register(&hv_bus);
if (ret)
@@ -520,6 +551,13 @@ static int vmbus_bus_init(int irq)
goto err_unregister;
}
+ /*
+ * Vmbus interrupts can be handled concurrently on
+ * different CPUs. Establish an appropriate interrupt flow
+ * handler that can support this model.
+ */
+ irq_set_handler(irq, vmbus_flow_handler);
+
vector = IRQ0_VECTOR + irq;
/*
@@ -575,8 +613,6 @@ int __vmbus_driver_register(struct hv_driver *hv_driver, struct module *owner, c
ret = driver_register(&hv_driver->driver);
- vmbus_request_offers();
-
return ret;
}
EXPORT_SYMBOL_GPL(__vmbus_driver_register);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 32f238f3caea..89ac1cb26f24 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -180,11 +180,11 @@ config SENSORS_ADM9240
will be called adm9240.
config SENSORS_ADT7410
- tristate "Analog Devices ADT7410"
+ tristate "Analog Devices ADT7410/ADT7420"
depends on I2C
help
If you say yes here you get support for the Analog Devices
- ADT7410 temperature monitoring chip.
+ ADT7410 and ADT7420 temperature monitoring chips.
This driver can also be built as a module. If so, the module
will be called adt7410.
@@ -506,7 +506,8 @@ config SENSORS_IT87
help
If you say yes here you get support for ITE IT8705F, IT8712F,
IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E,
- IT8782F, and IT8783E/F sensor chips, and the SiS950 clone.
+ IT8771E, IT8772E, IT8782F, and IT8783E/F sensor chips, and the
+ SiS950 clone.
This driver can also be built as a module. If so, the module
will be called it87.
@@ -529,8 +530,8 @@ config SENSORS_JC42
temperature sensors, which are used on many DDR3 memory modules for
mobile devices and servers. Support will include, but not be limited
to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805,
- MCP98242, MCP98243, MCP9843, SE97, SE98, STTS424(E), STTS2002,
- STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2.
+ MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98, STTS424(E),
+ STTS2002, STTS3000, TSE2002B3, TSE2002GB2, TS3000B3, and TS3000GB2.
This driver can also be built as a module. If so, the module
will be called jc42.
@@ -854,6 +855,17 @@ config SENSORS_MAX6650
This driver can also be built as a module. If so, the module
will be called max6650.
+config SENSORS_MAX6697
+ tristate "Maxim MAX6697 and compatibles"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX6581, MAX6602, MAX6622,
+ MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
+ temperature sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6697.
+
config SENSORS_MCP3021
tristate "Microchip MCP3021 and compatibles"
depends on I2C
@@ -1145,6 +1157,16 @@ config SENSORS_AMC6821
This driver can also be build as a module. If so, the module
will be called amc6821.
+config SENSORS_INA209
+ tristate "TI / Burr Brown INA209"
+ depends on I2C
+ help
+ If you say yes here you get support for the TI / Burr Brown INA209
+ voltage / current / power monitor I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ina209.
+
config SENSORS_INA2XX
tristate "Texas Instruments INA219 and compatibles"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 5da287443f6c..8d6d97ea7c1e 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
+obj-$(CONFIG_SENSORS_INA209) += ina209.o
obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_JC42) += jc42.o
@@ -99,6 +100,7 @@ obj-$(CONFIG_SENSORS_MAX197) += max197.o
obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
+obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 1672e2a5db46..6351aba8819c 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -911,7 +911,7 @@ exit:
return res;
}
-static int acpi_power_meter_remove(struct acpi_device *device, int type)
+static int acpi_power_meter_remove(struct acpi_device *device)
{
struct acpi_power_meter_resource *resource;
diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c
index f3a5d4764eb9..5d501adc3e54 100644
--- a/drivers/hwmon/ad7414.c
+++ b/drivers/hwmon/ad7414.c
@@ -137,7 +137,7 @@ static ssize_t set_max_min(struct device *dev,
if (ret < 0)
return ret;
- temp = SENSORS_LIMIT(temp, -40000, 85000);
+ temp = clamp_val(temp, -40000, 85000);
temp = (temp + (temp < 0 ? -500 : 500)) / 1000;
mutex_lock(&data->lock);
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index fd1d1b15854e..71bcba8abfc0 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -193,7 +193,7 @@ static ssize_t set_temp_max(struct device *dev,
temp /= 1000;
mutex_lock(&data->update_lock);
- data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127);
+ data->temp_max[index] = clamp_val(temp, -128, 127);
if (!read_only)
i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index),
data->temp_max[index]);
@@ -218,7 +218,7 @@ static ssize_t set_temp_min(struct device *dev,
temp /= 1000;
mutex_lock(&data->update_lock);
- data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127);
+ data->temp_min[index] = clamp_val(temp, -128, 127);
if (!read_only)
i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index),
data->temp_min[index]);
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 0f068e7297ee..ea09046e651d 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -197,7 +197,7 @@ static int adm1026_scaling[] = { /* .001 Volts */
};
#define NEG12_OFFSET 16000
#define SCALE(val, from, to) (((val)*(to) + ((from)/2))/(from))
-#define INS_TO_REG(n, val) (SENSORS_LIMIT(SCALE(val, adm1026_scaling[n], 192),\
+#define INS_TO_REG(n, val) (clamp_val(SCALE(val, adm1026_scaling[n], 192),\
0, 255))
#define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n]))
@@ -207,7 +207,7 @@ static int adm1026_scaling[] = { /* .001 Volts */
* 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000
*/
#define FAN_TO_REG(val, div) ((val) <= 0 ? 0xff : \
- SENSORS_LIMIT(1350000 / ((val) * (div)), \
+ clamp_val(1350000 / ((val) * (div)), \
1, 254))
#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 0xff ? 0 : \
1350000 / ((val) * (div)))
@@ -215,14 +215,14 @@ static int adm1026_scaling[] = { /* .001 Volts */
#define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0)
/* Temperature is reported in 1 degC increments */
-#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \
+#define TEMP_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \
/ 1000, -127, 127))
#define TEMP_FROM_REG(val) ((val) * 1000)
-#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \
+#define OFFSET_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \
/ 1000, -127, 127))
#define OFFSET_FROM_REG(val) ((val) * 1000)
-#define PWM_TO_REG(val) (SENSORS_LIMIT(val, 0, 255))
+#define PWM_TO_REG(val) (clamp_val(val, 0, 255))
#define PWM_FROM_REG(val) (val)
#define PWM_MIN_TO_REG(val) ((val) & 0xf0)
@@ -233,7 +233,7 @@ static int adm1026_scaling[] = { /* .001 Volts */
* indicates that the DAC could be used to drive the fans, but in our
* example board (Arima HDAMA) it isn't connected to the fans at all.
*/
-#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val) * 255) + 500) / 2500), 0, 255))
+#define DAC_TO_REG(val) (clamp_val(((((val) * 255) + 500) / 2500), 0, 255))
#define DAC_FROM_REG(val) (((val) * 2500) / 255)
/*
@@ -933,7 +933,7 @@ static void fixup_fan_min(struct device *dev, int fan, int old_div)
return;
new_min = data->fan_min[fan] * old_div / new_div;
- new_min = SENSORS_LIMIT(new_min, 1, 254);
+ new_min = clamp_val(new_min, 1, 254);
data->fan_min[fan] = new_min;
adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min);
}
@@ -1527,7 +1527,7 @@ static ssize_t set_auto_pwm_min(struct device *dev,
return err;
mutex_lock(&data->update_lock);
- data->pwm1.auto_pwm_min = SENSORS_LIMIT(val, 0, 255);
+ data->pwm1.auto_pwm_min = clamp_val(val, 0, 255);
if (data->pwm1.enable == 2) { /* apply immediately */
data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
PWM_MIN_TO_REG(data->pwm1.auto_pwm_min));
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index c6a4631e833f..253ea396106d 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -162,13 +162,13 @@ adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value)
static int FAN_TO_REG(int reg, int div)
{
int tmp;
- tmp = FAN_FROM_REG(SENSORS_LIMIT(reg, 0, 65535), div);
+ tmp = FAN_FROM_REG(clamp_val(reg, 0, 65535), div);
return tmp > 255 ? 255 : tmp;
}
#define FAN_DIV_FROM_REG(reg) (1<<(((reg)&0xc0)>>6))
-#define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255) >> 4)
+#define PWM_TO_REG(val) (clamp_val((val), 0, 255) >> 4)
#define PWM_FROM_REG(val) ((val) << 4)
#define FAN_CHAN_FROM_REG(reg) (((reg) >> 5) & 7)
@@ -675,7 +675,7 @@ static ssize_t set_temp_offset(struct device *dev,
if (ret)
return ret;
- val = SENSORS_LIMIT(val, -15000, 15000);
+ val = clamp_val(val, -15000, 15000);
mutex_lock(&data->update_lock);
data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val);
adm1031_write_value(client, ADM1031_REG_TEMP_OFFSET(nr),
@@ -696,7 +696,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
- val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
+ val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875);
mutex_lock(&data->update_lock);
data->temp_min[nr] = TEMP_TO_REG(val);
adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr),
@@ -717,7 +717,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
- val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
+ val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875);
mutex_lock(&data->update_lock);
data->temp_max[nr] = TEMP_TO_REG(val);
adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr),
@@ -738,7 +738,7 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
- val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
+ val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875);
mutex_lock(&data->update_lock);
data->temp_crit[nr] = TEMP_TO_REG(val);
adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr),
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index dafa477715e3..2416628e0ab1 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -98,13 +98,13 @@ static inline unsigned int IN_FROM_REG(u8 reg, int n)
static inline u8 IN_TO_REG(unsigned long val, int n)
{
- return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
+ return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255);
}
/* temperature range: -40..125, 127 disables temperature alarm */
static inline s8 TEMP_TO_REG(long val)
{
- return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127);
+ return clamp_val(SCALE(val, 1, 1000), -40, 127);
}
/* two fans, each with low fan speed limit */
@@ -122,7 +122,7 @@ static inline unsigned int FAN_FROM_REG(u8 reg, u8 div)
/* analog out 0..1250mV */
static inline u8 AOUT_TO_REG(unsigned long val)
{
- return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255);
+ return clamp_val(SCALE(val, 255, 1250), 0, 255);
}
static inline unsigned int AOUT_FROM_REG(u8 reg)
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index 409b5c16defb..ba962ac4b81f 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -163,9 +163,9 @@ static int ads7828_probe(struct i2c_client *client,
/* Bound Vref with min/max values if it was provided */
if (data->vref_mv)
- data->vref_mv = SENSORS_LIMIT(data->vref_mv,
- ADS7828_EXT_VREF_MV_MIN,
- ADS7828_EXT_VREF_MV_MAX);
+ data->vref_mv = clamp_val(data->vref_mv,
+ ADS7828_EXT_VREF_MV_MIN,
+ ADS7828_EXT_VREF_MV_MAX);
else
data->vref_mv = ADS7828_INT_VREF_MV;
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 030c8d7c33a5..99a7290da0a3 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -78,10 +78,6 @@ enum adt7410_type { /* keep sorted in alphabetical order */
adt7410,
};
-/* Addresses scanned */
-static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
- I2C_CLIENT_END };
-
static const u8 ADT7410_REG_TEMP[4] = {
ADT7410_TEMPERATURE, /* input */
ADT7410_T_ALARM_HIGH, /* high */
@@ -173,8 +169,8 @@ abort:
static s16 ADT7410_TEMP_TO_REG(long temp)
{
- return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, ADT7410_TEMP_MIN,
- ADT7410_TEMP_MAX) * 128, 1000);
+ return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
+ ADT7410_TEMP_MAX) * 128, 1000);
}
static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
@@ -269,9 +265,9 @@ static ssize_t adt7410_set_t_hyst(struct device *dev,
return ret;
/* convert absolute hysteresis value to a 4 bit delta value */
limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
- hyst = SENSORS_LIMIT(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
- data->hyst = SENSORS_LIMIT(DIV_ROUND_CLOSEST(limit - hyst, 1000),
- 0, ADT7410_T_HYST_MASK);
+ hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
+ data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
+ ADT7410_T_HYST_MASK);
ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
if (ret)
return ret;
@@ -364,6 +360,7 @@ static int adt7410_probe(struct i2c_client *client,
/*
* Set to 16 bit resolution, continous conversion and comparator mode.
*/
+ ret &= ~ADT7410_MODE_MASK;
data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
ADT7410_EVENT_MODE;
if (data->config != data->oldconfig) {
@@ -410,11 +407,12 @@ static int adt7410_remove(struct i2c_client *client)
static const struct i2c_device_id adt7410_ids[] = {
{ "adt7410", adt7410, },
+ { "adt7420", adt7410, },
{ /* LIST END */ }
};
MODULE_DEVICE_TABLE(i2c, adt7410_ids);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int adt7410_suspend(struct device *dev)
{
int ret;
@@ -436,10 +434,8 @@ static int adt7410_resume(struct device *dev)
return ret;
}
-static const struct dev_pm_ops adt7410_dev_pm_ops = {
- .suspend = adt7410_suspend,
- .resume = adt7410_resume,
-};
+static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
+
#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
#else
#define ADT7410_DEV_PM_OPS NULL
@@ -454,11 +450,11 @@ static struct i2c_driver adt7410_driver = {
.probe = adt7410_probe,
.remove = adt7410_remove,
.id_table = adt7410_ids,
- .address_list = normal_i2c,
+ .address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
};
module_i2c_driver(adt7410_driver);
MODULE_AUTHOR("Hartmut Knaack");
-MODULE_DESCRIPTION("ADT7410 driver");
+MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
index 98a7d81e25c5..69481d3a3d23 100644
--- a/drivers/hwmon/adt7462.c
+++ b/drivers/hwmon/adt7462.c
@@ -836,7 +836,7 @@ static ssize_t set_temp_min(struct device *dev,
return -EINVAL;
temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->temp_min[attr->index] = temp;
@@ -874,7 +874,7 @@ static ssize_t set_temp_max(struct device *dev,
return -EINVAL;
temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->temp_max[attr->index] = temp;
@@ -939,7 +939,7 @@ static ssize_t set_volt_max(struct device *dev,
temp *= 1000; /* convert mV to uV */
temp = DIV_ROUND_CLOSEST(temp, x);
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->volt_max[attr->index] = temp;
@@ -981,7 +981,7 @@ static ssize_t set_volt_min(struct device *dev,
temp *= 1000; /* convert mV to uV */
temp = DIV_ROUND_CLOSEST(temp, x);
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->volt_min[attr->index] = temp;
@@ -1071,7 +1071,7 @@ static ssize_t set_fan_min(struct device *dev,
temp = FAN_RPM_TO_PERIOD(temp);
temp >>= 8;
- temp = SENSORS_LIMIT(temp, 1, 255);
+ temp = clamp_val(temp, 1, 255);
mutex_lock(&data->lock);
data->fan_min[attr->index] = temp;
@@ -1149,7 +1149,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
if (kstrtol(buf, 10, &temp))
return -EINVAL;
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->pwm[attr->index] = temp;
@@ -1179,7 +1179,7 @@ static ssize_t set_pwm_max(struct device *dev,
if (kstrtol(buf, 10, &temp))
return -EINVAL;
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->pwm_max = temp;
@@ -1211,7 +1211,7 @@ static ssize_t set_pwm_min(struct device *dev,
if (kstrtol(buf, 10, &temp))
return -EINVAL;
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->pwm_min[attr->index] = temp;
@@ -1246,7 +1246,7 @@ static ssize_t set_pwm_hyst(struct device *dev,
return -EINVAL;
temp = DIV_ROUND_CLOSEST(temp, 1000);
- temp = SENSORS_LIMIT(temp, 0, 15);
+ temp = clamp_val(temp, 0, 15);
/* package things up */
temp &= ADT7462_PWM_HYST_MASK;
@@ -1333,7 +1333,7 @@ static ssize_t set_pwm_tmin(struct device *dev,
return -EINVAL;
temp = DIV_ROUND_CLOSEST(temp, 1000) + 64;
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->pwm_tmin[attr->index] = temp;
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 39ecb1a3b9ef..b83bf4bb95eb 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -452,7 +452,7 @@ static ssize_t set_auto_update_interval(struct device *dev,
if (kstrtol(buf, 10, &temp))
return -EINVAL;
- temp = SENSORS_LIMIT(temp, 0, 60000);
+ temp = clamp_val(temp, 0, 60000);
mutex_lock(&data->lock);
data->auto_update_interval = temp;
@@ -481,7 +481,7 @@ static ssize_t set_num_temp_sensors(struct device *dev,
if (kstrtol(buf, 10, &temp))
return -EINVAL;
- temp = SENSORS_LIMIT(temp, -1, 10);
+ temp = clamp_val(temp, -1, 10);
mutex_lock(&data->lock);
data->num_temp_sensors = temp;
@@ -515,7 +515,7 @@ static ssize_t set_temp_min(struct device *dev,
return -EINVAL;
temp = DIV_ROUND_CLOSEST(temp, 1000);
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->temp_min[attr->index] = temp;
@@ -549,7 +549,7 @@ static ssize_t set_temp_max(struct device *dev,
return -EINVAL;
temp = DIV_ROUND_CLOSEST(temp, 1000);
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->temp_max[attr->index] = temp;
@@ -604,7 +604,7 @@ static ssize_t set_fan_max(struct device *dev,
return -EINVAL;
temp = FAN_RPM_TO_PERIOD(temp);
- temp = SENSORS_LIMIT(temp, 1, 65534);
+ temp = clamp_val(temp, 1, 65534);
mutex_lock(&data->lock);
data->fan_max[attr->index] = temp;
@@ -641,7 +641,7 @@ static ssize_t set_fan_min(struct device *dev,
return -EINVAL;
temp = FAN_RPM_TO_PERIOD(temp);
- temp = SENSORS_LIMIT(temp, 1, 65534);
+ temp = clamp_val(temp, 1, 65534);
mutex_lock(&data->lock);
data->fan_min[attr->index] = temp;
@@ -717,7 +717,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
if (kstrtol(buf, 10, &temp))
return -EINVAL;
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->pwm[attr->index] = temp;
@@ -749,7 +749,7 @@ static ssize_t set_pwm_max(struct device *dev,
if (kstrtol(buf, 10, &temp))
return -EINVAL;
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->pwm_max[attr->index] = temp;
@@ -782,7 +782,7 @@ static ssize_t set_pwm_min(struct device *dev,
if (kstrtol(buf, 10, &temp))
return -EINVAL;
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->pwm_min[attr->index] = temp;
@@ -826,7 +826,7 @@ static ssize_t set_pwm_tmin(struct device *dev,
return -EINVAL;
temp = DIV_ROUND_CLOSEST(temp, 1000);
- temp = SENSORS_LIMIT(temp, 0, 255);
+ temp = clamp_val(temp, 0, 255);
mutex_lock(&data->lock);
data->pwm_tmin[attr->index] = temp;
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index 989e54c39252..22d008bbdc10 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -201,10 +201,10 @@ static inline u16 temp2reg(struct adt7475_data *data, long val)
u16 ret;
if (!(data->config5 & CONFIG5_TWOSCOMP)) {
- val = SENSORS_LIMIT(val, -64000, 191000);
+ val = clamp_val(val, -64000, 191000);
ret = (val + 64500) / 1000;
} else {
- val = SENSORS_LIMIT(val, -128000, 127000);
+ val = clamp_val(val, -128000, 127000);
if (val < -500)
ret = (256500 + val) / 1000;
else
@@ -240,7 +240,7 @@ static inline u16 rpm2tach(unsigned long rpm)
if (rpm == 0)
return 0;
- return SENSORS_LIMIT((90000 * 60) / rpm, 1, 0xFFFF);
+ return clamp_val((90000 * 60) / rpm, 1, 0xFFFF);
}
/* Scaling factors for voltage inputs, taken from the ADT7490 datasheet */
@@ -271,7 +271,7 @@ static inline u16 volt2reg(int channel, long volt, u8 bypass_attn)
reg = (volt * 1024) / 2250;
else
reg = (volt * r[1] * 1024) / ((r[0] + r[1]) * 2250);
- return SENSORS_LIMIT(reg, 0, 1023) & (0xff << 2);
+ return clamp_val(reg, 0, 1023) & (0xff << 2);
}
static u16 adt7475_read_word(struct i2c_client *client, int reg)
@@ -451,10 +451,10 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
switch (sattr->nr) {
case OFFSET:
if (data->config5 & CONFIG5_TEMPOFFSET) {
- val = SENSORS_LIMIT(val, -63000, 127000);
+ val = clamp_val(val, -63000, 127000);
out = data->temp[OFFSET][sattr->index] = val / 1000;
} else {
- val = SENSORS_LIMIT(val, -63000, 64000);
+ val = clamp_val(val, -63000, 64000);
out = data->temp[OFFSET][sattr->index] = val / 500;
}
break;
@@ -471,7 +471,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
adt7475_read_hystersis(client);
temp = reg2temp(data, data->temp[THERM][sattr->index]);
- val = SENSORS_LIMIT(val, temp - 15000, temp);
+ val = clamp_val(val, temp - 15000, temp);
val = (temp - val) / 1000;
if (sattr->index != 1) {
@@ -577,7 +577,7 @@ static ssize_t set_point2(struct device *dev, struct device_attribute *attr,
* to figure the range
*/
temp = reg2temp(data, data->temp[AUTOMIN][sattr->index]);
- val = SENSORS_LIMIT(val, temp + autorange_table[0],
+ val = clamp_val(val, temp + autorange_table[0],
temp + autorange_table[ARRAY_SIZE(autorange_table) - 1]);
val -= temp;
@@ -701,7 +701,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
break;
}
- data->pwm[sattr->nr][sattr->index] = SENSORS_LIMIT(val, 0, 0xFF);
+ data->pwm[sattr->nr][sattr->index] = clamp_val(val, 0, 0xFF);
i2c_smbus_write_byte_data(client, reg,
data->pwm[sattr->nr][sattr->index]);
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
index ae482e3afdac..4fe49d2bfe1d 100644
--- a/drivers/hwmon/amc6821.c
+++ b/drivers/hwmon/amc6821.c
@@ -241,7 +241,7 @@ static ssize_t set_temp(
int ret = kstrtol(buf, 10, &val);
if (ret)
return ret;
- val = SENSORS_LIMIT(val / 1000, -128, 127);
+ val = clamp_val(val / 1000, -128, 127);
mutex_lock(&data->update_lock);
data->temp[ix] = val;
@@ -332,7 +332,7 @@ static ssize_t set_pwm1(
return ret;
mutex_lock(&data->update_lock);
- data->pwm1 = SENSORS_LIMIT(val , 0, 255);
+ data->pwm1 = clamp_val(val , 0, 255);
i2c_smbus_write_byte_data(client, AMC6821_REG_DCY, data->pwm1);
mutex_unlock(&data->update_lock);
return count;
@@ -499,11 +499,11 @@ static ssize_t set_temp_auto_point_temp(
mutex_lock(&data->update_lock);
switch (ix) {
case 0:
- ptemp[0] = SENSORS_LIMIT(val / 1000, 0,
- data->temp1_auto_point_temp[1]);
- ptemp[0] = SENSORS_LIMIT(ptemp[0], 0,
- data->temp2_auto_point_temp[1]);
- ptemp[0] = SENSORS_LIMIT(ptemp[0], 0, 63);
+ ptemp[0] = clamp_val(val / 1000, 0,
+ data->temp1_auto_point_temp[1]);
+ ptemp[0] = clamp_val(ptemp[0], 0,
+ data->temp2_auto_point_temp[1]);
+ ptemp[0] = clamp_val(ptemp[0], 0, 63);
if (i2c_smbus_write_byte_data(
client,
AMC6821_REG_PSV_TEMP,
@@ -515,20 +515,12 @@ static ssize_t set_temp_auto_point_temp(
goto EXIT;
break;
case 1:
- ptemp[1] = SENSORS_LIMIT(
- val / 1000,
- (ptemp[0] & 0x7C) + 4,
- 124);
+ ptemp[1] = clamp_val(val / 1000, (ptemp[0] & 0x7C) + 4, 124);
ptemp[1] &= 0x7C;
- ptemp[2] = SENSORS_LIMIT(
- ptemp[2], ptemp[1] + 1,
- 255);
+ ptemp[2] = clamp_val(ptemp[2], ptemp[1] + 1, 255);
break;
case 2:
- ptemp[2] = SENSORS_LIMIT(
- val / 1000,
- ptemp[1]+1,
- 255);
+ ptemp[2] = clamp_val(val / 1000, ptemp[1]+1, 255);
break;
default:
dev_dbg(dev, "Unknown attr->index (%d).\n", ix);
@@ -561,7 +553,7 @@ static ssize_t set_pwm1_auto_point_pwm(
return ret;
mutex_lock(&data->update_lock);
- data->pwm1_auto_point_pwm[1] = SENSORS_LIMIT(val, 0, 254);
+ data->pwm1_auto_point_pwm[1] = clamp_val(val, 0, 254);
if (i2c_smbus_write_byte_data(client, AMC6821_REG_DCY_LOW_TEMP,
data->pwm1_auto_point_pwm[1])) {
dev_err(&client->dev, "Register write error, aborting.\n");
@@ -629,7 +621,7 @@ static ssize_t set_fan(
val = 1 > val ? 0xFFFF : 6000000/val;
mutex_lock(&data->update_lock);
- data->fan[ix] = (u16) SENSORS_LIMIT(val, 1, 0xFFFF);
+ data->fan[ix] = (u16) clamp_val(val, 1, 0xFFFF);
if (i2c_smbus_write_byte_data(client, fan_reg_low[ix],
data->fan[ix] & 0xFF)) {
dev_err(&client->dev, "Register write error, aborting.\n");
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 520e5bf4f76d..6ac612cabda1 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -114,7 +114,7 @@ static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19};
*/
static u8 IN_TO_REG(unsigned val)
{
- unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX);
+ unsigned nval = clamp_val(val, ASB100_IN_MIN, ASB100_IN_MAX);
return (nval + 8) / 16;
}
@@ -129,8 +129,8 @@ static u8 FAN_TO_REG(long rpm, int div)
return 0;
if (rpm == 0)
return 255;
- rpm = SENSORS_LIMIT(rpm, 1, 1000000);
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+ rpm = clamp_val(rpm, 1, 1000000);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
static int FAN_FROM_REG(u8 val, int div)
@@ -148,7 +148,7 @@ static int FAN_FROM_REG(u8 val, int div)
*/
static u8 TEMP_TO_REG(long temp)
{
- int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
+ int ntemp = clamp_val(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
ntemp += (ntemp < 0 ? -500 : 500);
return (u8)(ntemp / 1000);
}
@@ -164,7 +164,7 @@ static int TEMP_FROM_REG(u8 reg)
*/
static u8 ASB100_PWM_TO_REG(int pwm)
{
- pwm = SENSORS_LIMIT(pwm, 0, 255);
+ pwm = clamp_val(pwm, 0, 255);
return (u8)(pwm / 16);
}
diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c
index b867aab78049..da7f5b5d5db5 100644
--- a/drivers/hwmon/asc7621.c
+++ b/drivers/hwmon/asc7621.c
@@ -191,7 +191,7 @@ static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
if (kstrtol(buf, 10, &reqval))
return -EINVAL;
- reqval = SENSORS_LIMIT(reqval, 0, 255);
+ reqval = clamp_val(reqval, 0, 255);
mutex_lock(&data->update_lock);
data->reg[param->msb[0]] = reqval;
@@ -224,7 +224,7 @@ static ssize_t store_bitmask(struct device *dev,
if (kstrtol(buf, 10, &reqval))
return -EINVAL;
- reqval = SENSORS_LIMIT(reqval, 0, param->mask[0]);
+ reqval = clamp_val(reqval, 0, param->mask[0]);
reqval = (reqval & param->mask[0]) << param->shift[0];
@@ -274,7 +274,7 @@ static ssize_t store_fan16(struct device *dev,
* generating an alarm.
*/
reqval =
- (reqval <= 0 ? 0xffff : SENSORS_LIMIT(5400000 / reqval, 0, 0xfffe));
+ (reqval <= 0 ? 0xffff : clamp_val(5400000 / reqval, 0, 0xfffe));
mutex_lock(&data->update_lock);
data->reg[param->msb[0]] = (reqval >> 8) & 0xff;
@@ -343,11 +343,11 @@ static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
if (kstrtol(buf, 10, &reqval))
return -EINVAL;
- reqval = SENSORS_LIMIT(reqval, 0, 0xffff);
+ reqval = clamp_val(reqval, 0, 0xffff);
reqval = reqval * 0xc0 / asc7621_in_scaling[nr];
- reqval = SENSORS_LIMIT(reqval, 0, 0xff);
+ reqval = clamp_val(reqval, 0, 0xff);
mutex_lock(&data->update_lock);
data->reg[param->msb[0]] = reqval;
@@ -376,7 +376,7 @@ static ssize_t store_temp8(struct device *dev,
if (kstrtol(buf, 10, &reqval))
return -EINVAL;
- reqval = SENSORS_LIMIT(reqval, -127000, 127000);
+ reqval = clamp_val(reqval, -127000, 127000);
temp = reqval / 1000;
@@ -432,7 +432,7 @@ static ssize_t store_temp62(struct device *dev,
if (kstrtol(buf, 10, &reqval))
return -EINVAL;
- reqval = SENSORS_LIMIT(reqval, -32000, 31750);
+ reqval = clamp_val(reqval, -32000, 31750);
i = reqval / 1000;
f = reqval - (i * 1000);
temp = i << 2;
@@ -468,7 +468,7 @@ static ssize_t show_ap2_temp(struct device *dev,
auto_point1 = ((s8) data->reg[param->msb[1]]) * 1000;
regval =
((data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]);
- temp = auto_point1 + asc7621_range_map[SENSORS_LIMIT(regval, 0, 15)];
+ temp = auto_point1 + asc7621_range_map[clamp_val(regval, 0, 15)];
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", temp);
@@ -489,7 +489,7 @@ static ssize_t store_ap2_temp(struct device *dev,
mutex_lock(&data->update_lock);
auto_point1 = data->reg[param->msb[1]] * 1000;
- reqval = SENSORS_LIMIT(reqval, auto_point1 + 2000, auto_point1 + 80000);
+ reqval = clamp_val(reqval, auto_point1 + 2000, auto_point1 + 80000);
for (i = ARRAY_SIZE(asc7621_range_map) - 1; i >= 0; i--) {
if (reqval >= auto_point1 + asc7621_range_map[i]) {
@@ -523,7 +523,7 @@ static ssize_t show_pwm_ac(struct device *dev,
regval = config | (altbit << 3);
mutex_unlock(&data->update_lock);
- return sprintf(buf, "%u\n", map[SENSORS_LIMIT(regval, 0, 15)]);
+ return sprintf(buf, "%u\n", map[clamp_val(regval, 0, 15)]);
}
static ssize_t store_pwm_ac(struct device *dev,
@@ -663,7 +663,7 @@ static ssize_t show_pwm_freq(struct device *dev,
u8 regval =
(data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
- regval = SENSORS_LIMIT(regval, 0, 15);
+ regval = clamp_val(regval, 0, 15);
return sprintf(buf, "%u\n", asc7621_pwm_freq_map[regval]);
}
@@ -711,7 +711,7 @@ static ssize_t show_pwm_ast(struct device *dev,
u8 regval =
(data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
- regval = SENSORS_LIMIT(regval, 0, 7);
+ regval = clamp_val(regval, 0, 7);
return sprintf(buf, "%u\n", asc7621_pwm_auto_spinup_map[regval]);
@@ -759,7 +759,7 @@ static ssize_t show_temp_st(struct device *dev,
SETUP_SHOW_data_param(dev, attr);
u8 regval =
(data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
- regval = SENSORS_LIMIT(regval, 0, 7);
+ regval = clamp_val(regval, 0, 7);
return sprintf(buf, "%u\n", asc7621_temp_smoothing_time_map[regval]);
}
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index 56dbcfb3e301..b25c64302cbc 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -190,7 +190,7 @@ struct atk_acpi_input_buf {
};
static int atk_add(struct acpi_device *device);
-static int atk_remove(struct acpi_device *device, int type);
+static int atk_remove(struct acpi_device *device);
static void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
static int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
static void atk_free_sensors(struct atk_data *data);
@@ -1416,7 +1416,7 @@ out:
return err;
}
-static int atk_remove(struct acpi_device *device, int type)
+static int atk_remove(struct acpi_device *device)
{
struct atk_data *data = device->driver_data;
dev_dbg(&device->dev, "removing...\n");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index d64923d63537..3f1e297663ad 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -198,7 +198,7 @@ struct tjmax {
static const struct tjmax __cpuinitconst tjmax_table[] = {
{ "CPU 230", 100000 }, /* Model 0x1c, stepping 2 */
{ "CPU 330", 125000 }, /* Model 0x1c, stepping 2 */
- { "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 */
+ { "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 Sodaville */
{ "CPU CE4150", 110000 }, /* Model 0x1c, stepping 10 */
{ "CPU CE4170", 110000 }, /* Model 0x1c, stepping 10 */
};
@@ -212,7 +212,7 @@ struct tjmax_model {
#define ANY 0xff
static const struct tjmax_model __cpuinitconst tjmax_model_table[] = {
- { 0x1c, 10, 100000 }, /* D4xx, N4xx, D5xx, N5xx */
+ { 0x1c, 10, 100000 }, /* D4xx, K4xx, N4xx, D5xx, K5xx, N5xx */
{ 0x1c, ANY, 90000 }, /* Z5xx, N2xx, possibly others
* Note: Also matches 230 and 330,
* which are covered by tjmax_table
@@ -222,6 +222,7 @@ static const struct tjmax_model __cpuinitconst tjmax_model_table[] = {
* is undetectable by software
*/
{ 0x27, ANY, 90000 }, /* Atom Medfield (Z2460) */
+ { 0x35, ANY, 90000 }, /* Atom Clover Trail/Cloverview (Z2760) */
{ 0x36, ANY, 100000 }, /* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) */
};
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index 7430f70ae452..c347c94f2f73 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -277,7 +277,7 @@ static inline int IN_FROM_REG(int reg, int nominal, int res)
static inline int IN_TO_REG(int val, int nominal)
{
- return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255);
+ return clamp_val((val * 192 + nominal / 2) / nominal, 0, 255);
}
/*
@@ -293,8 +293,7 @@ static inline int TEMP_FROM_REG(int reg, int res)
static inline int TEMP_TO_REG(int val)
{
- return SENSORS_LIMIT((val < 0 ? val - 500 : val + 500) / 1000,
- -128, 127);
+ return clamp_val((val < 0 ? val - 500 : val + 500) / 1000, -128, 127);
}
/* Temperature range */
@@ -332,7 +331,7 @@ static inline int TEMP_HYST_FROM_REG(int reg, int ix)
static inline int TEMP_HYST_TO_REG(int val, int ix, int reg)
{
- int hyst = SENSORS_LIMIT((val + 500) / 1000, 0, 15);
+ int hyst = clamp_val((val + 500) / 1000, 0, 15);
return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);
}
@@ -349,10 +348,10 @@ static inline int FAN_FROM_REG(int reg, int tpc)
static inline int FAN_TO_REG(int val, int tpc)
{
if (tpc) {
- return SENSORS_LIMIT(val / tpc, 0, 0xffff);
+ return clamp_val(val / tpc, 0, 0xffff);
} else {
return (val <= 0) ? 0xffff :
- SENSORS_LIMIT(90000 * 60 / val, 0, 0xfffe);
+ clamp_val(90000 * 60 / val, 0, 0xfffe);
}
}
@@ -1282,7 +1281,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
switch (fn) {
case SYS_PWM:
- data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
+ data->pwm[ix] = clamp_val(val, 0, 255);
dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]);
break;
case SYS_PWM_FREQ:
@@ -1450,7 +1449,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
break;
case SYS_PWM_AUTO_POINT1_PWM:
/* Only valid for pwm[1-3] */
- data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
+ data->pwm_min[ix] = clamp_val(val, 0, 255);
dme1737_write(data, DME1737_REG_PWM_MIN(ix),
data->pwm_min[ix]);
break;
diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c
index 77f434c58236..b07305622087 100644
--- a/drivers/hwmon/emc2103.c
+++ b/drivers/hwmon/emc2103.c
@@ -405,7 +405,7 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute *da,
if (rpm_target == 0)
data->fan_target = 0x1fff;
else
- data->fan_target = SENSORS_LIMIT(
+ data->fan_target = clamp_val(
(FAN_RPM_FACTOR * data->fan_multiplier) / rpm_target,
0, 0x1fff);
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c
index 789bd4fb329b..936898f82f94 100644
--- a/drivers/hwmon/emc6w201.c
+++ b/drivers/hwmon/emc6w201.c
@@ -220,7 +220,7 @@ static ssize_t set_in(struct device *dev, struct device_attribute *devattr,
: EMC6W201_REG_IN_HIGH(nr);
mutex_lock(&data->update_lock);
- data->in[sf][nr] = SENSORS_LIMIT(val, 0, 255);
+ data->in[sf][nr] = clamp_val(val, 0, 255);
err = emc6w201_write8(client, reg, data->in[sf][nr]);
mutex_unlock(&data->update_lock);
@@ -257,7 +257,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
: EMC6W201_REG_TEMP_HIGH(nr);
mutex_lock(&data->update_lock);
- data->temp[sf][nr] = SENSORS_LIMIT(val, -127, 128);
+ data->temp[sf][nr] = clamp_val(val, -127, 128);
err = emc6w201_write8(client, reg, data->temp[sf][nr]);
mutex_unlock(&data->update_lock);
@@ -298,7 +298,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *devattr,
val = 0xFFFF;
} else {
val = DIV_ROUND_CLOSEST(5400000U, val);
- val = SENSORS_LIMIT(val, 0, 0xFFFE);
+ val = clamp_val(val, 0, 0xFFFE);
}
mutex_lock(&data->update_lock);
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index bb7275cc47f3..cfb02dd91aad 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -1350,7 +1350,7 @@ static ssize_t store_fan_full_speed(struct device *dev,
if (err)
return err;
- val = SENSORS_LIMIT(val, 23, 1500000);
+ val = clamp_val(val, 23, 1500000);
val = fan_to_reg(val);
mutex_lock(&data->update_lock);
@@ -1438,7 +1438,7 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute
return err;
val /= 8;
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
@@ -1542,7 +1542,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
return err;
val /= 1000;
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
@@ -1589,8 +1589,7 @@ static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
/* convert abs to relative and check */
data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
- val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
- data->temp_high[nr]);
+ val = clamp_val(val, data->temp_high[nr] - 15, data->temp_high[nr]);
val = data->temp_high[nr] - val;
/* convert value to register contents */
@@ -1627,7 +1626,7 @@ static ssize_t store_temp_crit(struct device *dev, struct device_attribute
return err;
val /= 1000;
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
@@ -1754,7 +1753,7 @@ static ssize_t store_pwm(struct device *dev,
if (err)
return err;
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
@@ -1805,7 +1804,7 @@ static ssize_t store_simple_pwm(struct device *dev,
if (err)
return err;
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
@@ -1932,7 +1931,7 @@ static ssize_t store_pwm_auto_point_pwm(struct device *dev,
if (err)
return err;
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
@@ -1991,8 +1990,8 @@ static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
mutex_lock(&data->update_lock);
data->pwm_auto_point_temp[nr][point] =
f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
- val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
- data->pwm_auto_point_temp[nr][point]);
+ val = clamp_val(val, data->pwm_auto_point_temp[nr][point] - 15,
+ data->pwm_auto_point_temp[nr][point]);
val = data->pwm_auto_point_temp[nr][point] - val;
reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
@@ -2126,9 +2125,9 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev,
val /= 1000;
if (data->auto_point_temp_signed)
- val = SENSORS_LIMIT(val, -128, 127);
+ val = clamp_val(val, -128, 127);
else
- val = SENSORS_LIMIT(val, 0, 127);
+ val = clamp_val(val, 0, 127);
mutex_lock(&data->update_lock);
f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index f7dba229395f..9e300e567f15 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -359,7 +359,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
return -EINVAL;
mutex_lock(&data->update_lock);
- data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+ data->pwm[nr] = clamp_val(val, 0, 255);
f75375_write_pwm(client, nr);
mutex_unlock(&data->update_lock);
return count;
@@ -556,7 +556,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
if (err < 0)
return err;
- val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+ val = clamp_val(VOLT_TO_REG(val), 0, 0xff);
mutex_lock(&data->update_lock);
data->in_max[nr] = val;
f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]);
@@ -577,7 +577,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
if (err < 0)
return err;
- val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+ val = clamp_val(VOLT_TO_REG(val), 0, 0xff);
mutex_lock(&data->update_lock);
data->in_min[nr] = val;
f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]);
@@ -625,7 +625,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
if (err < 0)
return err;
- val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+ val = clamp_val(TEMP_TO_REG(val), 0, 127);
mutex_lock(&data->update_lock);
data->temp_high[nr] = val;
f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]);
@@ -646,7 +646,7 @@ static ssize_t set_temp_max_hyst(struct device *dev,
if (err < 0)
return err;
- val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+ val = clamp_val(TEMP_TO_REG(val), 0, 127);
mutex_lock(&data->update_lock);
data->temp_max_hyst[nr] = val;
f75375_write8(client, F75375_REG_TEMP_HYST(nr),
@@ -822,7 +822,7 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data,
if (auto_mode_enabled(f75375s_pdata->pwm_enable[nr]) ||
!duty_mode_enabled(f75375s_pdata->pwm_enable[nr]))
continue;
- data->pwm[nr] = SENSORS_LIMIT(f75375s_pdata->pwm[nr], 0, 255);
+ data->pwm[nr] = clamp_val(f75375s_pdata->pwm[nr], 0, 255);
f75375_write_pwm(client, nr);
}
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index 519ce8b9c142..8af2755cdb87 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -379,7 +379,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
if (err)
return err;
- v = SENSORS_LIMIT(v / 1000, -128, 127) + 128;
+ v = clamp_val(v / 1000, -128, 127) + 128;
mutex_lock(&data->update_lock);
i2c_smbus_write_byte_data(to_i2c_client(dev),
@@ -540,7 +540,7 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
/* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
if (v || data->kind == fscsyl) {
- v = SENSORS_LIMIT(v, 128, 255);
+ v = clamp_val(v, 128, 255);
v = (v - 128) * 2 + 1;
}
diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c
index 8b2106f60eda..ea6480b80e7f 100644
--- a/drivers/hwmon/g760a.c
+++ b/drivers/hwmon/g760a.c
@@ -171,7 +171,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *da,
return -EINVAL;
mutex_lock(&data->update_lock);
- data->set_cnt = PWM_TO_CNT(SENSORS_LIMIT(val, 0, 255));
+ data->set_cnt = PWM_TO_CNT(clamp_val(val, 0, 255));
g760a_write_value(client, G760A_REG_SET_CNT, data->set_cnt);
mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 2c74673f48e5..e2e5909a34df 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -86,7 +86,7 @@ enum chips { gl518sm_r00, gl518sm_r80 };
#define BOOL_FROM_REG(val) ((val) ? 0 : 1)
#define BOOL_TO_REG(val) ((val) ? 0 : 1)
-#define TEMP_TO_REG(val) SENSORS_LIMIT(((((val) < 0 ? \
+#define TEMP_TO_REG(val) clamp_val(((((val) < 0 ? \
(val) - 500 : \
(val) + 500) / 1000) + 119), 0, 255)
#define TEMP_FROM_REG(val) (((val) - 119) * 1000)
@@ -96,15 +96,15 @@ static inline u8 FAN_TO_REG(long rpm, int div)
long rpmdiv;
if (rpm == 0)
return 0;
- rpmdiv = SENSORS_LIMIT(rpm, 1, 960000) * div;
- return SENSORS_LIMIT((480000 + rpmdiv / 2) / rpmdiv, 1, 255);
+ rpmdiv = clamp_val(rpm, 1, 960000) * div;
+ return clamp_val((480000 + rpmdiv / 2) / rpmdiv, 1, 255);
}
#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) * (div))))
-#define IN_TO_REG(val) SENSORS_LIMIT((((val) + 9) / 19), 0, 255)
+#define IN_TO_REG(val) clamp_val((((val) + 9) / 19), 0, 255)
#define IN_FROM_REG(val) ((val) * 19)
-#define VDD_TO_REG(val) SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255)
+#define VDD_TO_REG(val) clamp_val((((val) * 4 + 47) / 95), 0, 255)
#define VDD_FROM_REG(val) (((val) * 95 + 2) / 4)
#define DIV_FROM_REG(val) (1 << (val))
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index a21ff252f2f1..ed56e09c3dd7 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -144,10 +144,10 @@ static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL);
#define VDD_FROM_REG(val) (((val) * 95 + 2) / 4)
-#define VDD_TO_REG(val) SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255)
+#define VDD_TO_REG(val) clamp_val((((val) * 4 + 47) / 95), 0, 255)
#define IN_FROM_REG(val) ((val) * 19)
-#define IN_TO_REG(val) SENSORS_LIMIT((((val) + 9) / 19), 0, 255)
+#define IN_TO_REG(val) clamp_val((((val) + 9) / 19), 0, 255)
static ssize_t get_in_input(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -285,8 +285,7 @@ static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
#define DIV_FROM_REG(val) (1 << (val))
#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div))))
#define FAN_TO_REG(val, div) ((val) <= 0 ? 0 : \
- SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, \
- 255))
+ clamp_val((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255))
static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -450,7 +449,7 @@ static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR,
get_fan_off, set_fan_off);
#define TEMP_FROM_REG(val) (((val) - 130) * 1000)
-#define TEMP_TO_REG(val) SENSORS_LIMIT(((((val) < 0 ? \
+#define TEMP_TO_REG(val) clamp_val(((((val) < 0 ? \
(val) - 500 : (val) + 500) / 1000) + 130), 0, 255)
static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 4e04c1228e51..39781945a5d2 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -422,7 +422,7 @@ static int gpio_fan_get_of_pdata(struct device *dev,
/* Fill GPIO pin array */
pdata->num_ctrl = of_gpio_count(node);
- if (!pdata->num_ctrl) {
+ if (pdata->num_ctrl <= 0) {
dev_err(dev, "gpios DT property empty / missing");
return -ENODEV;
}
@@ -477,7 +477,7 @@ static int gpio_fan_get_of_pdata(struct device *dev,
pdata->speed = speed;
/* Alarm GPIO if one exists */
- if (of_gpio_named_count(node, "alarm-gpios")) {
+ if (of_gpio_named_count(node, "alarm-gpios") > 0) {
struct gpio_fan_alarm *alarm;
int val;
enum of_gpio_flags flags;
diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c
new file mode 100644
index 000000000000..c6fdd5bd395e
--- /dev/null
+++ b/drivers/hwmon/ina209.c
@@ -0,0 +1,636 @@
+/*
+ * Driver for the Texas Instruments / Burr Brown INA209
+ * Bidirectional Current/Power Monitor
+ *
+ * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from Ira W. Snyder's original driver submission
+ * Copyright (C) 2008 Paul Hays <Paul.Hays@cattail.ca>
+ * Copyright (C) 2008-2009 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * Aligned with ina2xx driver
+ * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ * Thanks to Jan Volkering
+ *
+ * This program is free software; 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.ti.com/lit/gpn/ina209
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/bug.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <linux/platform_data/ina2xx.h>
+
+/* register definitions */
+#define INA209_CONFIGURATION 0x00
+#define INA209_STATUS 0x01
+#define INA209_STATUS_MASK 0x02
+#define INA209_SHUNT_VOLTAGE 0x03
+#define INA209_BUS_VOLTAGE 0x04
+#define INA209_POWER 0x05
+#define INA209_CURRENT 0x06
+#define INA209_SHUNT_VOLTAGE_POS_PEAK 0x07
+#define INA209_SHUNT_VOLTAGE_NEG_PEAK 0x08
+#define INA209_BUS_VOLTAGE_MAX_PEAK 0x09
+#define INA209_BUS_VOLTAGE_MIN_PEAK 0x0a
+#define INA209_POWER_PEAK 0x0b
+#define INA209_SHUNT_VOLTAGE_POS_WARN 0x0c
+#define INA209_SHUNT_VOLTAGE_NEG_WARN 0x0d
+#define INA209_POWER_WARN 0x0e
+#define INA209_BUS_VOLTAGE_OVER_WARN 0x0f
+#define INA209_BUS_VOLTAGE_UNDER_WARN 0x10
+#define INA209_POWER_OVER_LIMIT 0x11
+#define INA209_BUS_VOLTAGE_OVER_LIMIT 0x12
+#define INA209_BUS_VOLTAGE_UNDER_LIMIT 0x13
+#define INA209_CRITICAL_DAC_POS 0x14
+#define INA209_CRITICAL_DAC_NEG 0x15
+#define INA209_CALIBRATION 0x16
+
+#define INA209_REGISTERS 0x17
+
+#define INA209_CONFIG_DEFAULT 0x3c47 /* PGA=8, full range */
+#define INA209_SHUNT_DEFAULT 10000 /* uOhm */
+
+struct ina209_data {
+ struct device *hwmon_dev;
+
+ struct mutex update_lock;
+ bool valid;
+ unsigned long last_updated; /* in jiffies */
+
+ u16 regs[INA209_REGISTERS]; /* All chip registers */
+
+ u16 config_orig; /* Original configuration */
+ u16 calibration_orig; /* Original calibration */
+ u16 update_interval;
+};
+
+static struct ina209_data *ina209_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina209_data *data = i2c_get_clientdata(client);
+ struct ina209_data *ret = data;
+ s32 val;
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (!data->valid ||
+ time_after(jiffies, data->last_updated + data->update_interval)) {
+ for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+ val = i2c_smbus_read_word_swapped(client, i);
+ if (val < 0) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->regs[i] = val;
+ }
+ data->last_updated = jiffies;
+ data->valid = true;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+/*
+ * Read a value from a device register and convert it to the
+ * appropriate sysfs units
+ */
+static long ina209_from_reg(const u8 reg, const u16 val)
+{
+ switch (reg) {
+ case INA209_SHUNT_VOLTAGE:
+ case INA209_SHUNT_VOLTAGE_POS_PEAK:
+ case INA209_SHUNT_VOLTAGE_NEG_PEAK:
+ case INA209_SHUNT_VOLTAGE_POS_WARN:
+ case INA209_SHUNT_VOLTAGE_NEG_WARN:
+ /* LSB=10 uV. Convert to mV. */
+ return DIV_ROUND_CLOSEST(val, 100);
+
+ case INA209_BUS_VOLTAGE:
+ case INA209_BUS_VOLTAGE_MAX_PEAK:
+ case INA209_BUS_VOLTAGE_MIN_PEAK:
+ case INA209_BUS_VOLTAGE_OVER_WARN:
+ case INA209_BUS_VOLTAGE_UNDER_WARN:
+ case INA209_BUS_VOLTAGE_OVER_LIMIT:
+ case INA209_BUS_VOLTAGE_UNDER_LIMIT:
+ /* LSB=4 mV, last 3 bits unused */
+ return (val >> 3) * 4;
+
+ case INA209_CRITICAL_DAC_POS:
+ /* LSB=1 mV, in the upper 8 bits */
+ return val >> 8;
+
+ case INA209_CRITICAL_DAC_NEG:
+ /* LSB=1 mV, in the upper 8 bits */
+ return -1 * (val >> 8);
+
+ case INA209_POWER:
+ case INA209_POWER_PEAK:
+ case INA209_POWER_WARN:
+ case INA209_POWER_OVER_LIMIT:
+ /* LSB=20 mW. Convert to uW */
+ return val * 20 * 1000L;
+
+ case INA209_CURRENT:
+ /* LSB=1 mA (selected). Is in mA */
+ return val;
+ }
+
+ /* programmer goofed */
+ WARN_ON_ONCE(1);
+ return 0;
+}
+
+/*
+ * Take a value and convert it to register format, clamping the value
+ * to the appropriate range.
+ */
+static int ina209_to_reg(u8 reg, u16 old, long val)
+{
+ switch (reg) {
+ case INA209_SHUNT_VOLTAGE_POS_WARN:
+ case INA209_SHUNT_VOLTAGE_NEG_WARN:
+ /* Limit to +- 320 mV, 10 uV LSB */
+ return clamp_val(val, -320, 320) * 100;
+
+ case INA209_BUS_VOLTAGE_OVER_WARN:
+ case INA209_BUS_VOLTAGE_UNDER_WARN:
+ case INA209_BUS_VOLTAGE_OVER_LIMIT:
+ case INA209_BUS_VOLTAGE_UNDER_LIMIT:
+ /*
+ * Limit to 0-32000 mV, 4 mV LSB
+ *
+ * The last three bits aren't part of the value, but we'll
+ * preserve them in their original state.
+ */
+ return (DIV_ROUND_CLOSEST(clamp_val(val, 0, 32000), 4) << 3)
+ | (old & 0x7);
+
+ case INA209_CRITICAL_DAC_NEG:
+ /*
+ * Limit to -255-0 mV, 1 mV LSB
+ * Convert the value to a positive value for the register
+ *
+ * The value lives in the top 8 bits only, be careful
+ * and keep original value of other bits.
+ */
+ return (clamp_val(-val, 0, 255) << 8) | (old & 0xff);
+
+ case INA209_CRITICAL_DAC_POS:
+ /*
+ * Limit to 0-255 mV, 1 mV LSB
+ *
+ * The value lives in the top 8 bits only, be careful
+ * and keep original value of other bits.
+ */
+ return (clamp_val(val, 0, 255) << 8) | (old & 0xff);
+
+ case INA209_POWER_WARN:
+ case INA209_POWER_OVER_LIMIT:
+ /* 20 mW LSB */
+ return DIV_ROUND_CLOSEST(val, 20 * 1000);
+ }
+
+ /* Other registers are read-only, return access error */
+ return -EACCES;
+}
+
+static int ina209_interval_from_reg(u16 reg)
+{
+ return 68 >> (15 - ((reg >> 3) & 0x0f));
+}
+
+static u16 ina209_reg_from_interval(u16 config, long interval)
+{
+ int i, adc;
+
+ if (interval <= 0) {
+ adc = 8;
+ } else {
+ adc = 15;
+ for (i = 34 + 34 / 2; i; i >>= 1) {
+ if (i < interval)
+ break;
+ adc--;
+ }
+ }
+ return (config & 0xf807) | (adc << 3) | (adc << 7);
+}
+
+static ssize_t ina209_set_interval(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina209_data *data = ina209_update_device(dev);
+ long val;
+ u16 regval;
+ int ret;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&data->update_lock);
+ regval = ina209_reg_from_interval(data->regs[INA209_CONFIGURATION],
+ val);
+ i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, regval);
+ data->regs[INA209_CONFIGURATION] = regval;
+ data->update_interval = ina209_interval_from_reg(regval);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t ina209_show_interval(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina209_data *data = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval);
+}
+
+/*
+ * History is reset by writing 1 into bit 0 of the respective peak register.
+ * Since more than one peak register may be affected by the scope of a
+ * reset_history attribute write, use a bit mask in attr->index to identify
+ * which registers are affected.
+ */
+static u16 ina209_reset_history_regs[] = {
+ INA209_SHUNT_VOLTAGE_POS_PEAK,
+ INA209_SHUNT_VOLTAGE_NEG_PEAK,
+ INA209_BUS_VOLTAGE_MAX_PEAK,
+ INA209_BUS_VOLTAGE_MIN_PEAK,
+ INA209_POWER_PEAK
+};
+
+static ssize_t ina209_reset_history(struct device *dev,
+ struct device_attribute *da,
+ const char *buf,
+ size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina209_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ u32 mask = attr->index;
+ long val;
+ int i, ret;
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&data->update_lock);
+ for (i = 0; i < ARRAY_SIZE(ina209_reset_history_regs); i++) {
+ if (mask & (1 << i))
+ i2c_smbus_write_word_swapped(client,
+ ina209_reset_history_regs[i], 1);
+ }
+ data->valid = false;
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t ina209_set_value(struct device *dev,
+ struct device_attribute *da,
+ const char *buf,
+ size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina209_data *data = ina209_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int reg = attr->index;
+ long val;
+ int ret;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&data->update_lock);
+ ret = ina209_to_reg(reg, data->regs[reg], val);
+ if (ret < 0) {
+ count = ret;
+ goto abort;
+ }
+ i2c_smbus_write_word_swapped(client, reg, ret);
+ data->regs[reg] = ret;
+abort:
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t ina209_show_value(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ina209_data *data = ina209_update_device(dev);
+ long val;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ val = ina209_from_reg(attr->index, data->regs[attr->index]);
+ return snprintf(buf, PAGE_SIZE, "%ld\n", val);
+}
+
+static ssize_t ina209_show_alarm(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ina209_data *data = ina209_update_device(dev);
+ const unsigned int mask = attr->index;
+ u16 status;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ status = data->regs[INA209_STATUS];
+
+ /*
+ * All alarms are in the INA209_STATUS register. To avoid a long
+ * switch statement, the mask is passed in attr->index
+ */
+ return snprintf(buf, PAGE_SIZE, "%u\n", !!(status & mask));
+}
+
+/* Shunt voltage, history, limits, alarms */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina209_show_value, NULL,
+ INA209_SHUNT_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in0_input_highest, S_IRUGO, ina209_show_value, NULL,
+ INA209_SHUNT_VOLTAGE_POS_PEAK);
+static SENSOR_DEVICE_ATTR(in0_input_lowest, S_IRUGO, ina209_show_value, NULL,
+ INA209_SHUNT_VOLTAGE_NEG_PEAK);
+static SENSOR_DEVICE_ATTR(in0_reset_history, S_IWUSR, NULL,
+ ina209_reset_history, (1 << 0) | (1 << 1));
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, ina209_show_value,
+ ina209_set_value, INA209_SHUNT_VOLTAGE_POS_WARN);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, ina209_show_value,
+ ina209_set_value, INA209_SHUNT_VOLTAGE_NEG_WARN);
+static SENSOR_DEVICE_ATTR(in0_crit_max, S_IRUGO | S_IWUSR, ina209_show_value,
+ ina209_set_value, INA209_CRITICAL_DAC_POS);
+static SENSOR_DEVICE_ATTR(in0_crit_min, S_IRUGO | S_IWUSR, ina209_show_value,
+ ina209_set_value, INA209_CRITICAL_DAC_NEG);
+
+static SENSOR_DEVICE_ATTR(in0_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+ 1 << 11);
+static SENSOR_DEVICE_ATTR(in0_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+ 1 << 12);
+static SENSOR_DEVICE_ATTR(in0_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+ 1 << 6);
+static SENSOR_DEVICE_ATTR(in0_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+ 1 << 7);
+
+/* Bus voltage, history, limits, alarms */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina209_show_value, NULL,
+ INA209_BUS_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in1_input_highest, S_IRUGO, ina209_show_value, NULL,
+ INA209_BUS_VOLTAGE_MAX_PEAK);
+static SENSOR_DEVICE_ATTR(in1_input_lowest, S_IRUGO, ina209_show_value, NULL,
+ INA209_BUS_VOLTAGE_MIN_PEAK);
+static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL,
+ ina209_reset_history, (1 << 2) | (1 << 3));
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ina209_show_value,
+ ina209_set_value, INA209_BUS_VOLTAGE_OVER_WARN);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ina209_show_value,
+ ina209_set_value, INA209_BUS_VOLTAGE_UNDER_WARN);
+static SENSOR_DEVICE_ATTR(in1_crit_max, S_IRUGO | S_IWUSR, ina209_show_value,
+ ina209_set_value, INA209_BUS_VOLTAGE_OVER_LIMIT);
+static SENSOR_DEVICE_ATTR(in1_crit_min, S_IRUGO | S_IWUSR, ina209_show_value,
+ ina209_set_value, INA209_BUS_VOLTAGE_UNDER_LIMIT);
+
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+ 1 << 14);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+ 1 << 15);
+static SENSOR_DEVICE_ATTR(in1_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
+ 1 << 9);
+static SENSOR_DEVICE_ATTR(in1_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+ 1 << 10);
+
+/* Power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina209_show_value, NULL,
+ INA209_POWER);
+static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ina209_show_value,
+ NULL, INA209_POWER_PEAK);
+static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL,
+ ina209_reset_history, 1 << 4);
+static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ina209_show_value,
+ ina209_set_value, INA209_POWER_WARN);
+static SENSOR_DEVICE_ATTR(power1_crit, S_IRUGO | S_IWUSR, ina209_show_value,
+ ina209_set_value, INA209_POWER_OVER_LIMIT);
+
+static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
+ 1 << 13);
+static SENSOR_DEVICE_ATTR(power1_crit_alarm, S_IRUGO, ina209_show_alarm, NULL,
+ 1 << 8);
+
+/* Current */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina209_show_value, NULL,
+ INA209_CURRENT);
+
+static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
+ ina209_show_interval, ina209_set_interval, 0);
+
+/*
+ * Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ina209_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_input_highest.dev_attr.attr,
+ &sensor_dev_attr_in0_input_lowest.dev_attr.attr,
+ &sensor_dev_attr_in0_reset_history.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_crit_max.dev_attr.attr,
+ &sensor_dev_attr_in0_crit_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in0_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in0_crit_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in0_crit_min_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input_highest.dev_attr.attr,
+ &sensor_dev_attr_in1_input_lowest.dev_attr.attr,
+ &sensor_dev_attr_in1_reset_history.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_crit_max.dev_attr.attr,
+ &sensor_dev_attr_in1_crit_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_crit_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_crit_min_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_power1_input.dev_attr.attr,
+ &sensor_dev_attr_power1_input_highest.dev_attr.attr,
+ &sensor_dev_attr_power1_reset_history.dev_attr.attr,
+ &sensor_dev_attr_power1_max.dev_attr.attr,
+ &sensor_dev_attr_power1_crit.dev_attr.attr,
+ &sensor_dev_attr_power1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_power1_crit_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+
+ &sensor_dev_attr_update_interval.dev_attr.attr,
+
+ NULL,
+};
+
+static const struct attribute_group ina209_group = {
+ .attrs = ina209_attributes,
+};
+
+static void ina209_restore_conf(struct i2c_client *client,
+ struct ina209_data *data)
+{
+ /* Restore initial configuration */
+ i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION,
+ data->config_orig);
+ i2c_smbus_write_word_swapped(client, INA209_CALIBRATION,
+ data->calibration_orig);
+}
+
+static int ina209_init_client(struct i2c_client *client,
+ struct ina209_data *data)
+{
+ struct ina2xx_platform_data *pdata = dev_get_platdata(&client->dev);
+ u32 shunt;
+ int reg;
+
+ reg = i2c_smbus_read_word_swapped(client, INA209_CALIBRATION);
+ if (reg < 0)
+ return reg;
+ data->calibration_orig = reg;
+
+ reg = i2c_smbus_read_word_swapped(client, INA209_CONFIGURATION);
+ if (reg < 0)
+ return reg;
+ data->config_orig = reg;
+
+ if (pdata) {
+ if (pdata->shunt_uohms <= 0)
+ return -EINVAL;
+ shunt = pdata->shunt_uohms;
+ } else if (!of_property_read_u32(client->dev.of_node, "shunt-resistor",
+ &shunt)) {
+ if (shunt == 0)
+ return -EINVAL;
+ } else {
+ shunt = data->calibration_orig ?
+ 40960000 / data->calibration_orig : INA209_SHUNT_DEFAULT;
+ }
+
+ i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION,
+ INA209_CONFIG_DEFAULT);
+ data->update_interval = ina209_interval_from_reg(INA209_CONFIG_DEFAULT);
+
+ /*
+ * Calibrate current LSB to 1mA. Shunt is in uOhms.
+ * See equation 13 in datasheet.
+ */
+ i2c_smbus_write_word_swapped(client, INA209_CALIBRATION,
+ clamp_val(40960000 / shunt, 1, 65535));
+
+ /* Clear status register */
+ i2c_smbus_read_word_swapped(client, INA209_STATUS);
+
+ return 0;
+}
+
+static int ina209_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct ina209_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ ret = ina209_init_client(client, data);
+ if (ret)
+ return ret;
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&client->dev.kobj, &ina209_group);
+ if (ret)
+ goto out_restore_conf;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto out_hwmon_device_register;
+ }
+
+ return 0;
+
+out_hwmon_device_register:
+ sysfs_remove_group(&client->dev.kobj, &ina209_group);
+out_restore_conf:
+ ina209_restore_conf(client, data);
+ return ret;
+}
+
+static int ina209_remove(struct i2c_client *client)
+{
+ struct ina209_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &ina209_group);
+ ina209_restore_conf(client, data);
+
+ return 0;
+}
+
+static const struct i2c_device_id ina209_id[] = {
+ { "ina209", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ina209_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ina209_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "ina209",
+ },
+ .probe = ina209_probe,
+ .remove = ina209_remove,
+ .id_table = ina209_id,
+};
+
+module_i2c_driver(ina209_driver);
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>, Paul Hays <Paul.Hays@cattail.ca>, Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("INA209 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 117d66fcded6..37fc980fde24 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -19,6 +19,8 @@
* IT8726F Super I/O chip w/LPC interface
* IT8728F Super I/O chip w/LPC interface
* IT8758E Super I/O chip w/LPC interface
+ * IT8771E Super I/O chip w/LPC interface
+ * IT8772E Super I/O chip w/LPC interface
* IT8782F Super I/O chip w/LPC interface
* IT8783E/F Super I/O chip w/LPC interface
* Sis950 A clone of the IT8705F
@@ -61,8 +63,8 @@
#define DRVNAME "it87"
-enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782,
- it8783 };
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771,
+ it8772, it8782, it8783 };
static unsigned short force_id;
module_param(force_id, ushort, 0);
@@ -140,6 +142,8 @@ static inline void superio_exit(void)
#define IT8721F_DEVID 0x8721
#define IT8726F_DEVID 0x8726
#define IT8728F_DEVID 0x8728
+#define IT8771E_DEVID 0x8771
+#define IT8772E_DEVID 0x8772
#define IT8782F_DEVID 0x8782
#define IT8783E_DEVID 0x8783
#define IT87_ACT_REG 0x30
@@ -281,6 +285,24 @@ static const struct it87_devices it87_devices[] = {
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
.peci_mask = 0x07,
},
+ [it8771] = {
+ .name = "it8771",
+ .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
+ /* PECI: guesswork */
+ /* 12mV ADC (OHM) */
+ /* 16 bit fans (OHM) */
+ .peci_mask = 0x07,
+ },
+ [it8772] = {
+ .name = "it8772",
+ .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
+ /* PECI (coreboot) */
+ /* 12mV ADC (HWSensors4, OHM) */
+ /* 16 bit fans (HWSensors4, OHM) */
+ .peci_mask = 0x07,
+ },
[it8782] = {
.name = "it8782",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
@@ -384,7 +406,7 @@ static int adc_lsb(const struct it87_data *data, int nr)
static u8 in_to_reg(const struct it87_data *data, int nr, long val)
{
val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr));
- return SENSORS_LIMIT(val, 0, 255);
+ return clamp_val(val, 0, 255);
}
static int in_from_reg(const struct it87_data *data, int nr, int val)
@@ -396,16 +418,15 @@ static inline u8 FAN_TO_REG(long rpm, int div)
{
if (rpm == 0)
return 255;
- rpm = SENSORS_LIMIT(rpm, 1, 1000000);
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
- 254);
+ rpm = clamp_val(rpm, 1, 1000000);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
static inline u16 FAN16_TO_REG(long rpm)
{
if (rpm == 0)
return 0xffff;
- return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
+ return clamp_val((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
}
#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 255 ? 0 : \
@@ -414,8 +435,8 @@ static inline u16 FAN16_TO_REG(long rpm)
#define FAN16_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
1350000 / ((val) * 2))
-#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (((val) - 500) / 1000) : \
- ((val) + 500) / 1000), -128, 127))
+#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (((val) - 500) / 1000) : \
+ ((val) + 500) / 1000), -128, 127))
#define TEMP_FROM_REG(val) ((val) * 1000)
static u8 pwm_to_reg(const struct it87_data *data, long val)
@@ -1709,6 +1730,12 @@ static int __init it87_find(unsigned short *address,
case IT8728F_DEVID:
sio_data->type = it8728;
break;
+ case IT8771E_DEVID:
+ sio_data->type = it8771;
+ break;
+ case IT8772E_DEVID:
+ sio_data->type = it8772;
+ break;
case IT8782F_DEVID:
sio_data->type = it8782;
break;
@@ -1826,10 +1853,11 @@ static int __init it87_find(unsigned short *address,
reg = superio_inb(IT87_SIO_GPIO3_REG);
if (sio_data->type == it8721 || sio_data->type == it8728 ||
+ sio_data->type == it8771 || sio_data->type == it8772 ||
sio_data->type == it8782) {
/*
* IT8721F/IT8758E, and IT8782F don't have VID pins
- * at all, not sure about the IT8728F.
+ * at all, not sure about the IT8728F and compatibles.
*/
sio_data->skip_vid = 1;
} else {
@@ -1883,7 +1911,9 @@ static int __init it87_find(unsigned short *address,
if (reg & (1 << 0))
sio_data->internal |= (1 << 0);
if ((reg & (1 << 1)) || sio_data->type == it8721 ||
- sio_data->type == it8728)
+ sio_data->type == it8728 ||
+ sio_data->type == it8771 ||
+ sio_data->type == it8772)
sio_data->internal |= (1 << 1);
/*
diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c
index e21e43c13156..4a58f130fd4e 100644
--- a/drivers/hwmon/jc42.c
+++ b/drivers/hwmon/jc42.c
@@ -103,6 +103,9 @@ static const unsigned short normal_i2c[] = {
#define MCP98243_DEVID 0x2100
#define MCP98243_DEVID_MASK 0xfffc
+#define MCP98244_DEVID 0x2200
+#define MCP98244_DEVID_MASK 0xfffc
+
#define MCP9843_DEVID 0x0000 /* Also matches mcp9805 */
#define MCP9843_DEVID_MASK 0xfffe
@@ -147,6 +150,7 @@ static struct jc42_chips jc42_chips[] = {
{ MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK },
{ MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK },
{ MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK },
+ { MCP_MANID, MCP98244_DEVID, MCP98244_DEVID_MASK },
{ MCP_MANID, MCP9843_DEVID, MCP9843_DEVID_MASK },
{ NXP_MANID, SE97_DEVID, SE97_DEVID_MASK },
{ ONS_MANID, CAT6095_DEVID, CAT6095_DEVID_MASK },
@@ -237,9 +241,9 @@ static struct i2c_driver jc42_driver = {
static u16 jc42_temp_to_reg(int temp, bool extended)
{
- int ntemp = SENSORS_LIMIT(temp,
- extended ? JC42_TEMP_MIN_EXTENDED :
- JC42_TEMP_MIN, JC42_TEMP_MAX);
+ int ntemp = clamp_val(temp,
+ extended ? JC42_TEMP_MIN_EXTENDED :
+ JC42_TEMP_MIN, JC42_TEMP_MAX);
/* convert from 0.001 to 0.0625 resolution */
return (ntemp * 2 / 125) & 0x1fff;
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index eed4d9401788..f644a2e57599 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -209,9 +209,9 @@ static inline int lut_temp_to_reg(struct lm63_data *data, long val)
{
val -= data->temp2_offset;
if (data->lut_temp_highres)
- return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127500), 500);
+ return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127500), 500);
else
- return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127000), 1000);
+ return DIV_ROUND_CLOSEST(clamp_val(val, 0, 127000), 1000);
}
/*
@@ -415,7 +415,7 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr,
return err;
reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE;
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
data->pwm1[nr] = data->pwm_highres ? val :
@@ -700,7 +700,7 @@ static ssize_t set_update_interval(struct device *dev,
return err;
mutex_lock(&data->update_lock);
- lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
+ lm63_set_convrate(client, data, clamp_val(val, 0, 100000));
mutex_unlock(&data->update_lock);
return count;
diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c
index 7272176a9ec7..9bde9644b102 100644
--- a/drivers/hwmon/lm73.c
+++ b/drivers/hwmon/lm73.c
@@ -8,6 +8,7 @@
* Guillaume Ligneul <guillaume.ligneul@gmail.com>
* Adrien Demarez <adrien.demarez@bolloretelecom.eu>
* Jeremy Laine <jeremy.laine@bolloretelecom.eu>
+ * Chris Verges <kg4ysn@gmail.com>
*
* This software program is licensed subject to the GNU General Public License
* (GPL).Version 2,June 1991, available at
@@ -36,11 +37,30 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c,
#define LM73_ID 0x9001 /* 0x0190, byte-swapped */
#define DRVNAME "lm73"
-#define LM73_TEMP_MIN (-40)
-#define LM73_TEMP_MAX 150
+#define LM73_TEMP_MIN (-256000 / 250)
+#define LM73_TEMP_MAX (255750 / 250)
-/*-----------------------------------------------------------------------*/
+#define LM73_CTRL_RES_SHIFT 5
+#define LM73_CTRL_RES_MASK (BIT(5) | BIT(6))
+#define LM73_CTRL_TO_MASK BIT(7)
+
+#define LM73_CTRL_HI_SHIFT 2
+#define LM73_CTRL_LO_SHIFT 1
+
+static const unsigned short lm73_convrates[] = {
+ 14, /* 11-bits (0.25000 C/LSB): RES1 Bit = 0, RES0 Bit = 0 */
+ 28, /* 12-bits (0.12500 C/LSB): RES1 Bit = 0, RES0 Bit = 1 */
+ 56, /* 13-bits (0.06250 C/LSB): RES1 Bit = 1, RES0 Bit = 0 */
+ 112, /* 14-bits (0.03125 C/LSB): RES1 Bit = 1, RES0 Bit = 1 */
+};
+struct lm73_data {
+ struct device *hwmon_dev;
+ struct mutex lock;
+ u8 ctrl; /* control register value */
+};
+
+/*-----------------------------------------------------------------------*/
static ssize_t set_temp(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
@@ -56,8 +76,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
return status;
/* Write value */
- value = (short) SENSORS_LIMIT(temp/250, (LM73_TEMP_MIN*4),
- (LM73_TEMP_MAX*4)) << 5;
+ value = clamp_val(temp / 250, LM73_TEMP_MIN, LM73_TEMP_MAX) << 5;
err = i2c_smbus_write_word_swapped(client, attr->index, value);
return (err < 0) ? err : count;
}
@@ -79,6 +98,73 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da,
return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
}
+static ssize_t set_convrate(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm73_data *data = i2c_get_clientdata(client);
+ unsigned long convrate;
+ s32 err;
+ int res = 0;
+
+ err = kstrtoul(buf, 10, &convrate);
+ if (err < 0)
+ return err;
+
+ /*
+ * Convert the desired conversion rate into register bits.
+ * res is already initialized, and everything past the second-to-last
+ * value in the array is treated as belonging to the last value
+ * in the array.
+ */
+ while (res < (ARRAY_SIZE(lm73_convrates) - 1) &&
+ convrate > lm73_convrates[res])
+ res++;
+
+ mutex_lock(&data->lock);
+ data->ctrl &= LM73_CTRL_TO_MASK;
+ data->ctrl |= res << LM73_CTRL_RES_SHIFT;
+ err = i2c_smbus_write_byte_data(client, LM73_REG_CTRL, data->ctrl);
+ mutex_unlock(&data->lock);
+
+ if (err < 0)
+ return err;
+
+ return count;
+}
+
+static ssize_t show_convrate(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm73_data *data = i2c_get_clientdata(client);
+ int res;
+
+ res = (data->ctrl & LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_SHIFT;
+ return scnprintf(buf, PAGE_SIZE, "%hu\n", lm73_convrates[res]);
+}
+
+static ssize_t show_maxmin_alarm(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct lm73_data *data = i2c_get_clientdata(client);
+ s32 ctrl;
+
+ mutex_lock(&data->lock);
+ ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL);
+ if (ctrl < 0)
+ goto abort;
+ data->ctrl = ctrl;
+ mutex_unlock(&data->lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (ctrl >> attr->index) & 1);
+
+abort:
+ mutex_unlock(&data->lock);
+ return ctrl;
+}
/*-----------------------------------------------------------------------*/
@@ -90,13 +176,20 @@ static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
show_temp, set_temp, LM73_REG_MIN);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
show_temp, NULL, LM73_REG_INPUT);
-
+static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
+ show_convrate, set_convrate, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
+ show_maxmin_alarm, NULL, LM73_CTRL_HI_SHIFT);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
+ show_maxmin_alarm, NULL, LM73_CTRL_LO_SHIFT);
static struct attribute *lm73_attributes[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
-
+ &sensor_dev_attr_update_interval.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
NULL
};
@@ -111,23 +204,36 @@ static const struct attribute_group lm73_group = {
static int
lm73_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
- struct device *hwmon_dev;
int status;
+ struct lm73_data *data;
+ int ctrl;
+
+ data = devm_kzalloc(&client->dev, sizeof(struct lm73_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->lock);
+
+ ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL);
+ if (ctrl < 0)
+ return ctrl;
+ data->ctrl = ctrl;
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &lm73_group);
if (status)
return status;
- hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(hwmon_dev)) {
- status = PTR_ERR(hwmon_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ status = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
- i2c_set_clientdata(client, hwmon_dev);
dev_info(&client->dev, "%s: sensor '%s'\n",
- dev_name(hwmon_dev), client->name);
+ dev_name(data->hwmon_dev), client->name);
return 0;
@@ -138,9 +244,9 @@ exit_remove:
static int lm73_remove(struct i2c_client *client)
{
- struct device *hwmon_dev = i2c_get_clientdata(client);
+ struct lm73_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(hwmon_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm73_group);
return 0;
}
diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h
index 89aa9098ba5b..668ff4721323 100644
--- a/drivers/hwmon/lm75.h
+++ b/drivers/hwmon/lm75.h
@@ -36,7 +36,7 @@
REG: (0.5C/bit, two's complement) << 7 */
static inline u16 LM75_TEMP_TO_REG(long temp)
{
- int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
+ int ntemp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
ntemp += (ntemp < 0 ? -250 : 250);
return (u16)((ntemp / 500) << 7);
}
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index f82acf67acf5..f17beb5e6dd6 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -101,7 +101,7 @@ static struct i2c_driver lm77_driver = {
*/
static inline s16 LM77_TEMP_TO_REG(int temp)
{
- int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX);
+ int ntemp = clamp_val(temp, LM77_TEMP_MIN, LM77_TEMP_MAX);
return (ntemp / 500) * 8;
}
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 53d6ee8ffa33..483538fa1bd5 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -85,7 +85,7 @@ enum chips { lm78, lm79 };
*/
static inline u8 IN_TO_REG(unsigned long val)
{
- unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
+ unsigned long nval = clamp_val(val, 0, 4080);
return (nval + 8) / 16;
}
#define IN_FROM_REG(val) ((val) * 16)
@@ -94,7 +94,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
{
if (rpm <= 0)
return 255;
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
static inline int FAN_FROM_REG(u8 val, int div)
@@ -108,7 +108,7 @@ static inline int FAN_FROM_REG(u8 val, int div)
*/
static inline s8 TEMP_TO_REG(int val)
{
- int nval = SENSORS_LIMIT(val, -128000, 127000) ;
+ int nval = clamp_val(val, -128000, 127000) ;
return nval < 0 ? (nval - 500) / 1000 : (nval + 500) / 1000;
}
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 28a8b71f4571..357fbb998728 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -72,15 +72,15 @@ static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
* Fixing this is just not worth it.
*/
-#define IN_TO_REG(val) (SENSORS_LIMIT(((val) + 5) / 10, 0, 255))
+#define IN_TO_REG(val) (clamp_val(((val) + 5) / 10, 0, 255))
#define IN_FROM_REG(val) ((val) * 10)
static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div)
{
if (rpm == 0)
return 255;
- rpm = SENSORS_LIMIT(rpm, 1, 1000000);
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+ rpm = clamp_val(rpm, 1, 1000000);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \
@@ -102,7 +102,7 @@ static inline long TEMP_FROM_REG(u16 temp)
#define TEMP_LIMIT_FROM_REG(val) (((val) > 0x80 ? \
(val) - 0x100 : (val)) * 1000)
-#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val) < 0 ? \
+#define TEMP_LIMIT_TO_REG(val) clamp_val((val) < 0 ? \
((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255)
#define DIV_FROM_REG(val) (1 << (val))
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 9f2dd77e1e0e..47ade8ba152d 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -139,7 +139,7 @@ static const int lm85_scaling[] = { /* .001 Volts */
#define SCALE(val, from, to) (((val) * (to) + ((from) / 2)) / (from))
#define INS_TO_REG(n, val) \
- SENSORS_LIMIT(SCALE(val, lm85_scaling[n], 192), 0, 255)
+ clamp_val(SCALE(val, lm85_scaling[n], 192), 0, 255)
#define INSEXT_FROM_REG(n, val, ext) \
SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n])
@@ -151,19 +151,19 @@ static inline u16 FAN_TO_REG(unsigned long val)
{
if (!val)
return 0xffff;
- return SENSORS_LIMIT(5400000 / val, 1, 0xfffe);
+ return clamp_val(5400000 / val, 1, 0xfffe);
}
#define FAN_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
5400000 / (val))
/* Temperature is reported in .001 degC increments */
#define TEMP_TO_REG(val) \
- SENSORS_LIMIT(SCALE(val, 1000, 1), -127, 127)
+ clamp_val(SCALE(val, 1000, 1), -127, 127)
#define TEMPEXT_FROM_REG(val, ext) \
SCALE(((val) << 4) + (ext), 16, 1000)
#define TEMP_FROM_REG(val) ((val) * 1000)
-#define PWM_TO_REG(val) SENSORS_LIMIT(val, 0, 255)
+#define PWM_TO_REG(val) clamp_val(val, 0, 255)
#define PWM_FROM_REG(val) (val)
@@ -258,7 +258,7 @@ static int ZONE_TO_REG(int zone)
return i << 5;
}
-#define HYST_TO_REG(val) SENSORS_LIMIT(((val) + 500) / 1000, 0, 15)
+#define HYST_TO_REG(val) clamp_val(((val) + 500) / 1000, 0, 15)
#define HYST_FROM_REG(val) ((val) * 1000)
/*
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 863412a02bdd..8eeb141c85ac 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -931,7 +931,7 @@ static ssize_t set_update_interval(struct device *dev,
return err;
mutex_lock(&data->update_lock);
- lm90_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
+ lm90_set_convrate(client, data, clamp_val(val, 0, 100000));
mutex_unlock(&data->update_lock);
return count;
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index 1a003f73e4e4..b40f34cdb3ca 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -371,8 +371,8 @@ static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
static u8 LM93_IN_TO_REG(int nr, unsigned val)
{
/* range limit */
- const long mV = SENSORS_LIMIT(val,
- lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
+ const long mV = clamp_val(val,
+ lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
/* try not to lose too much precision here */
const long uV = mV * 1000;
@@ -385,8 +385,8 @@ static u8 LM93_IN_TO_REG(int nr, unsigned val)
const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
u8 result = ((uV - intercept + (slope/2)) / slope);
- result = SENSORS_LIMIT(result,
- lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
+ result = clamp_val(result,
+ lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
return result;
}
@@ -411,10 +411,10 @@ static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
{
long uV_offset = vid * 1000 - val * 10000;
if (upper) {
- uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000);
+ uV_offset = clamp_val(uV_offset, 12500, 200000);
return (u8)((uV_offset / 12500 - 1) << 4);
} else {
- uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000);
+ uV_offset = clamp_val(uV_offset, -400000, -25000);
return (u8)((uV_offset / -25000 - 1) << 0);
}
}
@@ -437,7 +437,7 @@ static int LM93_TEMP_FROM_REG(u8 reg)
*/
static u8 LM93_TEMP_TO_REG(long temp)
{
- int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
+ int ntemp = clamp_val(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
ntemp += (ntemp < 0 ? -500 : 500);
return (u8)(ntemp / 1000);
}
@@ -472,7 +472,7 @@ static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode)
{
int factor = mode ? 5 : 10;
- off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN,
+ off = clamp_val(off, LM93_TEMP_OFFSET_MIN,
mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0);
return (u8)((off + factor/2) / factor);
}
@@ -620,8 +620,8 @@ static u16 LM93_FAN_TO_REG(long rpm)
if (rpm == 0) {
count = 0x3fff;
} else {
- rpm = SENSORS_LIMIT(rpm, 1, 1000000);
- count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe);
+ rpm = clamp_val(rpm, 1, 1000000);
+ count = clamp_val((1350000 + rpm) / rpm, 1, 0x3ffe);
}
regs = count << 2;
@@ -692,7 +692,7 @@ static int LM93_RAMP_FROM_REG(u8 reg)
*/
static u8 LM93_RAMP_TO_REG(int ramp)
{
- ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
+ ramp = clamp_val(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
return (u8)((ramp + 2) / 5);
}
@@ -702,7 +702,7 @@ static u8 LM93_RAMP_TO_REG(int ramp)
*/
static u8 LM93_PROCHOT_TO_REG(long prochot)
{
- prochot = SENSORS_LIMIT(prochot, 0, 255);
+ prochot = clamp_val(prochot, 0, 255);
return (u8)prochot;
}
@@ -2052,7 +2052,7 @@ static ssize_t store_pwm_auto_channels(struct device *dev,
return err;
mutex_lock(&data->update_lock);
- data->block9[nr][LM93_PWM_CTL1] = SENSORS_LIMIT(val, 0, 255);
+ data->block9[nr][LM93_PWM_CTL1] = clamp_val(val, 0, 255);
lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL1),
data->block9[nr][LM93_PWM_CTL1]);
mutex_unlock(&data->update_lock);
@@ -2397,7 +2397,7 @@ static ssize_t store_prochot_override_duty_cycle(struct device *dev,
mutex_lock(&data->update_lock);
data->prochot_override = (data->prochot_override & 0xf0) |
- SENSORS_LIMIT(val, 0, 15);
+ clamp_val(val, 0, 15);
lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
data->prochot_override);
mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
index 2915fd908364..a6c85f0ff8f3 100644
--- a/drivers/hwmon/lm95245.c
+++ b/drivers/hwmon/lm95245.c
@@ -259,7 +259,7 @@ static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
val /= 1000;
- val = SENSORS_LIMIT(val, 0, (index == 6 ? 127 : 255));
+ val = clamp_val(val, 0, (index == 6 ? 127 : 255));
mutex_lock(&data->update_lock);
@@ -284,7 +284,7 @@ static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
val /= 1000;
- val = SENSORS_LIMIT(val, 0, 31);
+ val = clamp_val(val, 0, 31);
mutex_lock(&data->update_lock);
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
index e0019c69d1bb..2fa2c02f5569 100644
--- a/drivers/hwmon/max16065.c
+++ b/drivers/hwmon/max16065.c
@@ -118,7 +118,7 @@ static inline int LIMIT_TO_MV(int limit, int range)
static inline int MV_TO_LIMIT(int mv, int range)
{
- return SENSORS_LIMIT(DIV_ROUND_CLOSEST(mv * 256, range), 0, 255);
+ return clamp_val(DIV_ROUND_CLOSEST(mv * 256, range), 0, 255);
}
static inline int ADC_TO_CURR(int adc, int gain)
diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c
index 666d9f6263eb..a7626358c95d 100644
--- a/drivers/hwmon/max1668.c
+++ b/drivers/hwmon/max1668.c
@@ -215,7 +215,7 @@ static ssize_t set_temp_max(struct device *dev,
return ret;
mutex_lock(&data->update_lock);
- data->temp_max[index] = SENSORS_LIMIT(temp/1000, -128, 127);
+ data->temp_max[index] = clamp_val(temp/1000, -128, 127);
if (i2c_smbus_write_byte_data(client,
MAX1668_REG_LIMH_WR(index),
data->temp_max[index]))
@@ -240,7 +240,7 @@ static ssize_t set_temp_min(struct device *dev,
return ret;
mutex_lock(&data->update_lock);
- data->temp_min[index] = SENSORS_LIMIT(temp/1000, -128, 127);
+ data->temp_min[index] = clamp_val(temp/1000, -128, 127);
if (i2c_smbus_write_byte_data(client,
MAX1668_REG_LIML_WR(index),
data->temp_max[index]))
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index 6e60036abfa7..3e7b4269f5b9 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -74,7 +74,7 @@ static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
#define FAN_FROM_REG(val, rpm_range) ((val) == 0 || (val) == 255 ? \
0 : (rpm_ranges[rpm_range] * 30) / (val))
-#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val) / 1000, 0, 255)
+#define TEMP_LIMIT_TO_REG(val) clamp_val((val) / 1000, 0, 255)
/*
* Client data (each client gets its own)
@@ -312,7 +312,7 @@ static ssize_t set_pwm(struct device *dev,
if (res)
return res;
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
data->pwm[attr->index] = (u8)(val * 120 / 255);
diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c
index 223461a6d70f..57d58cd32206 100644
--- a/drivers/hwmon/max6642.c
+++ b/drivers/hwmon/max6642.c
@@ -239,7 +239,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->temp_high[attr2->nr] = SENSORS_LIMIT(temp_to_reg(val), 0, 255);
+ data->temp_high[attr2->nr] = clamp_val(temp_to_reg(val), 0, 255);
i2c_smbus_write_byte_data(client, attr2->index,
data->temp_high[attr2->nr]);
mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index f739f83bafb9..3c16cbd4c002 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -245,7 +245,7 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
if (err)
return err;
- rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
+ rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
/*
* Divide the required speed by 60 to get from rpm to rps, then
@@ -313,7 +313,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
if (err)
return err;
- pwm = SENSORS_LIMIT(pwm, 0, 255);
+ pwm = clamp_val(pwm, 0, 255);
mutex_lock(&data->update_lock);
diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c
new file mode 100644
index 000000000000..bf4aa3777fc1
--- /dev/null
+++ b/drivers/hwmon/max6697.c
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2012 Guenter Roeck <linux@roeck-us.net>
+ *
+ * based on max1668.c
+ * Copyright (c) 2011 David George <david.george@ska.ac.za>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/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/of.h>
+
+#include <linux/platform_data/max6697.h>
+
+enum chips { max6581, max6602, max6622, max6636, max6689, max6693, max6694,
+ max6697, max6698, max6699 };
+
+/* Report local sensor as temp1 */
+
+static const u8 MAX6697_REG_TEMP[] = {
+ 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08 };
+static const u8 MAX6697_REG_TEMP_EXT[] = {
+ 0x57, 0x09, 0x52, 0x53, 0x54, 0x55, 0x56, 0 };
+static const u8 MAX6697_REG_MAX[] = {
+ 0x17, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18 };
+static const u8 MAX6697_REG_CRIT[] = {
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 };
+
+/*
+ * Map device tree / platform data register bit map to chip bit map.
+ * Applies to alert register and over-temperature register.
+ */
+#define MAX6697_MAP_BITS(reg) ((((reg) & 0x7e) >> 1) | \
+ (((reg) & 0x01) << 6) | ((reg) & 0x80))
+
+#define MAX6697_REG_STAT(n) (0x44 + (n))
+
+#define MAX6697_REG_CONFIG 0x41
+#define MAX6581_CONF_EXTENDED (1 << 1)
+#define MAX6693_CONF_BETA (1 << 2)
+#define MAX6697_CONF_RESISTANCE (1 << 3)
+#define MAX6697_CONF_TIMEOUT (1 << 5)
+#define MAX6697_REG_ALERT_MASK 0x42
+#define MAX6697_REG_OVERT_MASK 0x43
+
+#define MAX6581_REG_RESISTANCE 0x4a
+#define MAX6581_REG_IDEALITY 0x4b
+#define MAX6581_REG_IDEALITY_SELECT 0x4c
+#define MAX6581_REG_OFFSET 0x4d
+#define MAX6581_REG_OFFSET_SELECT 0x4e
+
+#define MAX6697_CONV_TIME 156 /* ms per channel, worst case */
+
+struct max6697_chip_data {
+ int channels;
+ u32 have_ext;
+ u32 have_crit;
+ u32 have_fault;
+ u8 valid_conf;
+ const u8 *alarm_map;
+};
+
+struct max6697_data {
+ struct device *hwmon_dev;
+
+ enum chips type;
+ const struct max6697_chip_data *chip;
+
+ int update_interval; /* in milli-seconds */
+ int temp_offset; /* in degrees C */
+
+ struct mutex update_lock;
+ unsigned long last_updated; /* In jiffies */
+ bool valid; /* true if following fields are valid */
+
+ /* 1x local and up to 7x remote */
+ u8 temp[8][4]; /* [nr][0]=temp [1]=ext [2]=max [3]=crit */
+#define MAX6697_TEMP_INPUT 0
+#define MAX6697_TEMP_EXT 1
+#define MAX6697_TEMP_MAX 2
+#define MAX6697_TEMP_CRIT 3
+ u32 alarms;
+};
+
+/* Diode fault status bits on MAX6581 are right shifted by one bit */
+static const u8 max6581_alarm_map[] = {
+ 0, 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23 };
+
+static const struct max6697_chip_data max6697_chip_data[] = {
+ [max6581] = {
+ .channels = 8,
+ .have_crit = 0xff,
+ .have_ext = 0x7f,
+ .have_fault = 0xfe,
+ .valid_conf = MAX6581_CONF_EXTENDED | MAX6697_CONF_TIMEOUT,
+ .alarm_map = max6581_alarm_map,
+ },
+ [max6602] = {
+ .channels = 5,
+ .have_crit = 0x12,
+ .have_ext = 0x02,
+ .have_fault = 0x1e,
+ .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+ },
+ [max6622] = {
+ .channels = 5,
+ .have_crit = 0x12,
+ .have_ext = 0x02,
+ .have_fault = 0x1e,
+ .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+ },
+ [max6636] = {
+ .channels = 7,
+ .have_crit = 0x72,
+ .have_ext = 0x02,
+ .have_fault = 0x7e,
+ .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+ },
+ [max6689] = {
+ .channels = 7,
+ .have_crit = 0x72,
+ .have_ext = 0x02,
+ .have_fault = 0x7e,
+ .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+ },
+ [max6693] = {
+ .channels = 7,
+ .have_crit = 0x72,
+ .have_ext = 0x02,
+ .have_fault = 0x7e,
+ .valid_conf = MAX6697_CONF_RESISTANCE | MAX6693_CONF_BETA |
+ MAX6697_CONF_TIMEOUT,
+ },
+ [max6694] = {
+ .channels = 5,
+ .have_crit = 0x12,
+ .have_ext = 0x02,
+ .have_fault = 0x1e,
+ .valid_conf = MAX6697_CONF_RESISTANCE | MAX6693_CONF_BETA |
+ MAX6697_CONF_TIMEOUT,
+ },
+ [max6697] = {
+ .channels = 7,
+ .have_crit = 0x72,
+ .have_ext = 0x02,
+ .have_fault = 0x7e,
+ .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+ },
+ [max6698] = {
+ .channels = 7,
+ .have_crit = 0x72,
+ .have_ext = 0x02,
+ .have_fault = 0x0e,
+ .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+ },
+ [max6699] = {
+ .channels = 5,
+ .have_crit = 0x12,
+ .have_ext = 0x02,
+ .have_fault = 0x1e,
+ .valid_conf = MAX6697_CONF_RESISTANCE | MAX6697_CONF_TIMEOUT,
+ },
+};
+
+static struct max6697_data *max6697_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6697_data *data = i2c_get_clientdata(client);
+ struct max6697_data *ret = data;
+ int val;
+ int i;
+ u32 alarms;
+
+ mutex_lock(&data->update_lock);
+
+ if (data->valid &&
+ !time_after(jiffies, data->last_updated
+ + msecs_to_jiffies(data->update_interval)))
+ goto abort;
+
+ for (i = 0; i < data->chip->channels; i++) {
+ if (data->chip->have_ext & (1 << i)) {
+ val = i2c_smbus_read_byte_data(client,
+ MAX6697_REG_TEMP_EXT[i]);
+ if (unlikely(val < 0)) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->temp[i][MAX6697_TEMP_EXT] = val;
+ }
+
+ val = i2c_smbus_read_byte_data(client, MAX6697_REG_TEMP[i]);
+ if (unlikely(val < 0)) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->temp[i][MAX6697_TEMP_INPUT] = val;
+
+ val = i2c_smbus_read_byte_data(client, MAX6697_REG_MAX[i]);
+ if (unlikely(val < 0)) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->temp[i][MAX6697_TEMP_MAX] = val;
+
+ if (data->chip->have_crit & (1 << i)) {
+ val = i2c_smbus_read_byte_data(client,
+ MAX6697_REG_CRIT[i]);
+ if (unlikely(val < 0)) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->temp[i][MAX6697_TEMP_CRIT] = val;
+ }
+ }
+
+ alarms = 0;
+ for (i = 0; i < 3; i++) {
+ val = i2c_smbus_read_byte_data(client, MAX6697_REG_STAT(i));
+ if (unlikely(val < 0)) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ alarms = (alarms << 8) | val;
+ }
+ data->alarms = alarms;
+ data->last_updated = jiffies;
+ data->valid = true;
+abort:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+static ssize_t show_temp_input(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct max6697_data *data = max6697_update_device(dev);
+ int temp;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ temp = (data->temp[index][MAX6697_TEMP_INPUT] - data->temp_offset) << 3;
+ temp |= data->temp[index][MAX6697_TEMP_EXT] >> 5;
+
+ return sprintf(buf, "%d\n", temp * 125);
+}
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+ int index = to_sensor_dev_attr_2(devattr)->index;
+ struct max6697_data *data = max6697_update_device(dev);
+ int temp;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ temp = data->temp[nr][index];
+ temp -= data->temp_offset;
+
+ return sprintf(buf, "%d\n", temp * 1000);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct max6697_data *data = max6697_update_device(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ if (data->chip->alarm_map)
+ index = data->chip->alarm_map[index];
+
+ return sprintf(buf, "%u\n", (data->alarms >> index) & 0x1);
+}
+
+static ssize_t set_temp(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+ int index = to_sensor_dev_attr_2(devattr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6697_data *data = i2c_get_clientdata(client);
+ long temp;
+ int ret;
+
+ ret = kstrtol(buf, 10, &temp);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&data->update_lock);
+ temp = DIV_ROUND_CLOSEST(temp, 1000) + data->temp_offset;
+ temp = clamp_val(temp, 0, data->type == max6581 ? 255 : 127);
+ data->temp[nr][index] = temp;
+ ret = i2c_smbus_write_byte_data(client,
+ index == 2 ? MAX6697_REG_MAX[nr]
+ : MAX6697_REG_CRIT[nr],
+ temp);
+ mutex_unlock(&data->update_lock);
+
+ return ret < 0 ? ret : count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 0, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 0, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 1, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 1, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 2, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 2, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3);
+static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 3, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 3, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4);
+static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 4, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 4, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5);
+static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 5, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 5, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp_input, NULL, 6);
+static SENSOR_DEVICE_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 6, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 6, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp_input, NULL, 7);
+static SENSOR_DEVICE_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 7, MAX6697_TEMP_MAX);
+static SENSOR_DEVICE_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 7, MAX6697_TEMP_CRIT);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 22);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(temp7_max_alarm, S_IRUGO, show_alarm, NULL, 21);
+static SENSOR_DEVICE_ATTR(temp8_max_alarm, S_IRUGO, show_alarm, NULL, 23);
+
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp7_crit_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp8_crit_alarm, S_IRUGO, show_alarm, NULL, 15);
+
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_alarm, NULL, 7);
+
+static struct attribute *max6697_attributes[8][7] = {
+ {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_crit.dev_attr.attr,
+ &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp6_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_max.dev_attr.attr,
+ &sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp6_crit.dev_attr.attr,
+ &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp6_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp7_input.dev_attr.attr,
+ &sensor_dev_attr_temp7_max.dev_attr.attr,
+ &sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp7_crit.dev_attr.attr,
+ &sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp7_fault.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp8_input.dev_attr.attr,
+ &sensor_dev_attr_temp8_max.dev_attr.attr,
+ &sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp8_crit.dev_attr.attr,
+ &sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp8_fault.dev_attr.attr,
+ NULL
+ }
+};
+
+static const struct attribute_group max6697_group[8] = {
+ { .attrs = max6697_attributes[0] },
+ { .attrs = max6697_attributes[1] },
+ { .attrs = max6697_attributes[2] },
+ { .attrs = max6697_attributes[3] },
+ { .attrs = max6697_attributes[4] },
+ { .attrs = max6697_attributes[5] },
+ { .attrs = max6697_attributes[6] },
+ { .attrs = max6697_attributes[7] },
+};
+
+static void max6697_get_config_of(struct device_node *node,
+ struct max6697_platform_data *pdata)
+{
+ int len;
+ const __be32 *prop;
+
+ prop = of_get_property(node, "smbus-timeout-disable", &len);
+ if (prop)
+ pdata->smbus_timeout_disable = true;
+ prop = of_get_property(node, "extended-range-enable", &len);
+ if (prop)
+ pdata->extended_range_enable = true;
+ prop = of_get_property(node, "beta-compensation-enable", &len);
+ if (prop)
+ pdata->beta_compensation = true;
+ prop = of_get_property(node, "alert-mask", &len);
+ if (prop && len == sizeof(u32))
+ pdata->alert_mask = be32_to_cpu(prop[0]);
+ prop = of_get_property(node, "over-temperature-mask", &len);
+ if (prop && len == sizeof(u32))
+ pdata->over_temperature_mask = be32_to_cpu(prop[0]);
+ prop = of_get_property(node, "resistance-cancellation", &len);
+ if (prop) {
+ if (len == sizeof(u32))
+ pdata->resistance_cancellation = be32_to_cpu(prop[0]);
+ else
+ pdata->resistance_cancellation = 0xfe;
+ }
+ prop = of_get_property(node, "transistor-ideality", &len);
+ if (prop && len == 2 * sizeof(u32)) {
+ pdata->ideality_mask = be32_to_cpu(prop[0]);
+ pdata->ideality_value = be32_to_cpu(prop[1]);
+ }
+}
+
+static int max6697_init_chip(struct i2c_client *client)
+{
+ struct max6697_data *data = i2c_get_clientdata(client);
+ struct max6697_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct max6697_platform_data p;
+ const struct max6697_chip_data *chip = data->chip;
+ int factor = chip->channels;
+ int ret, reg;
+
+ /*
+ * Don't touch configuration if neither platform data nor OF
+ * configuration was specified. If that is the case, use the
+ * current chip configuration.
+ */
+ if (!pdata && !client->dev.of_node) {
+ reg = i2c_smbus_read_byte_data(client, MAX6697_REG_CONFIG);
+ if (reg < 0)
+ return reg;
+ if (data->type == max6581) {
+ if (reg & MAX6581_CONF_EXTENDED)
+ data->temp_offset = 64;
+ reg = i2c_smbus_read_byte_data(client,
+ MAX6581_REG_RESISTANCE);
+ if (reg < 0)
+ return reg;
+ factor += hweight8(reg);
+ } else {
+ if (reg & MAX6697_CONF_RESISTANCE)
+ factor++;
+ }
+ goto done;
+ }
+
+ if (client->dev.of_node) {
+ memset(&p, 0, sizeof(p));
+ max6697_get_config_of(client->dev.of_node, &p);
+ pdata = &p;
+ }
+
+ reg = 0;
+ if (pdata->smbus_timeout_disable &&
+ (chip->valid_conf & MAX6697_CONF_TIMEOUT)) {
+ reg |= MAX6697_CONF_TIMEOUT;
+ }
+ if (pdata->extended_range_enable &&
+ (chip->valid_conf & MAX6581_CONF_EXTENDED)) {
+ reg |= MAX6581_CONF_EXTENDED;
+ data->temp_offset = 64;
+ }
+ if (pdata->resistance_cancellation &&
+ (chip->valid_conf & MAX6697_CONF_RESISTANCE)) {
+ reg |= MAX6697_CONF_RESISTANCE;
+ factor++;
+ }
+ if (pdata->beta_compensation &&
+ (chip->valid_conf & MAX6693_CONF_BETA)) {
+ reg |= MAX6693_CONF_BETA;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, MAX6697_REG_CONFIG, reg);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, MAX6697_REG_ALERT_MASK,
+ MAX6697_MAP_BITS(pdata->alert_mask));
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, MAX6697_REG_OVERT_MASK,
+ MAX6697_MAP_BITS(pdata->over_temperature_mask));
+ if (ret < 0)
+ return ret;
+
+ if (data->type == max6581) {
+ factor += hweight8(pdata->resistance_cancellation >> 1);
+ ret = i2c_smbus_write_byte_data(client, MAX6581_REG_RESISTANCE,
+ pdata->resistance_cancellation >> 1);
+ if (ret < 0)
+ return ret;
+ ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY,
+ pdata->ideality_mask >> 1);
+ if (ret < 0)
+ return ret;
+ ret = i2c_smbus_write_byte_data(client,
+ MAX6581_REG_IDEALITY_SELECT,
+ pdata->ideality_value);
+ if (ret < 0)
+ return ret;
+ }
+done:
+ data->update_interval = factor * MAX6697_CONV_TIME;
+ return 0;
+}
+
+static void max6697_remove_files(struct i2c_client *client)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(max6697_group); i++)
+ sysfs_remove_group(&client->dev.kobj, &max6697_group[i]);
+}
+
+static int max6697_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct device *dev = &client->dev;
+ struct max6697_data *data;
+ int i, err;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ data = devm_kzalloc(dev, sizeof(struct max6697_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->type = id->driver_data;
+ data->chip = &max6697_chip_data[data->type];
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ err = max6697_init_chip(client);
+ if (err)
+ return err;
+
+ for (i = 0; i < data->chip->channels; i++) {
+ err = sysfs_create_file(&dev->kobj,
+ max6697_attributes[i][0]);
+ if (err)
+ goto error;
+ err = sysfs_create_file(&dev->kobj,
+ max6697_attributes[i][1]);
+ if (err)
+ goto error;
+ err = sysfs_create_file(&dev->kobj,
+ max6697_attributes[i][2]);
+ if (err)
+ goto error;
+
+ if (data->chip->have_crit & (1 << i)) {
+ err = sysfs_create_file(&dev->kobj,
+ max6697_attributes[i][3]);
+ if (err)
+ goto error;
+ err = sysfs_create_file(&dev->kobj,
+ max6697_attributes[i][4]);
+ if (err)
+ goto error;
+ }
+ if (data->chip->have_fault & (1 << i)) {
+ err = sysfs_create_file(&dev->kobj,
+ max6697_attributes[i][5]);
+ if (err)
+ goto error;
+ }
+ }
+
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ max6697_remove_files(client);
+ return err;
+}
+
+static int max6697_remove(struct i2c_client *client)
+{
+ struct max6697_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ max6697_remove_files(client);
+
+ return 0;
+}
+
+static const struct i2c_device_id max6697_id[] = {
+ { "max6581", max6581 },
+ { "max6602", max6602 },
+ { "max6622", max6622 },
+ { "max6636", max6636 },
+ { "max6689", max6689 },
+ { "max6693", max6693 },
+ { "max6694", max6694 },
+ { "max6697", max6697 },
+ { "max6698", max6698 },
+ { "max6699", max6699 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max6697_id);
+
+static struct i2c_driver max6697_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "max6697",
+ },
+ .probe = max6697_probe,
+ .remove = max6697_remove,
+ .id_table = max6697_id,
+};
+
+module_i2c_driver(max6697_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("MAX6697 temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index a87eb8986e36..b5f63f9c0ce1 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -43,7 +43,7 @@ struct ntc_compensation {
* The following compensation tables are from the specification of Murata NTC
* Thermistors Datasheet
*/
-const struct ntc_compensation ncpXXwb473[] = {
+static const struct ntc_compensation ncpXXwb473[] = {
{ .temp_C = -40, .ohm = 1747920 },
{ .temp_C = -35, .ohm = 1245428 },
{ .temp_C = -30, .ohm = 898485 },
@@ -79,7 +79,7 @@ const struct ntc_compensation ncpXXwb473[] = {
{ .temp_C = 120, .ohm = 1615 },
{ .temp_C = 125, .ohm = 1406 },
};
-const struct ntc_compensation ncpXXwl333[] = {
+static const struct ntc_compensation ncpXXwl333[] = {
{ .temp_C = -40, .ohm = 1610154 },
{ .temp_C = -35, .ohm = 1130850 },
{ .temp_C = -30, .ohm = 802609 },
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 60745a535821..4f9eb0af5229 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -72,7 +72,7 @@ config SENSORS_MAX34440
default n
help
If you say yes here you get hardware monitoring support for Maxim
- MAX34440, MAX34441, and MAX34446.
+ MAX34440, MAX34441, MAX34446, MAX34460, and MAX34461.
This driver can also be built as a module. If so, the module will
be called max34440.
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c
index 2ada7b021fbe..7e930c3ce1ab 100644
--- a/drivers/hwmon/pmbus/max34440.c
+++ b/drivers/hwmon/pmbus/max34440.c
@@ -2,6 +2,7 @@
* Hardware monitoring driver for Maxim MAX34440/MAX34441
*
* Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
*
* This 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,7 +26,7 @@
#include <linux/i2c.h>
#include "pmbus.h"
-enum chips { max34440, max34441, max34446 };
+enum chips { max34440, max34441, max34446, max34460, max34461 };
#define MAX34440_MFR_VOUT_PEAK 0xd4
#define MAX34440_MFR_IOUT_PEAK 0xd5
@@ -87,7 +88,8 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
MAX34446_MFR_POUT_PEAK);
break;
case PMBUS_VIRT_READ_TEMP_AVG:
- if (data->id != max34446)
+ if (data->id != max34446 && data->id != max34460 &&
+ data->id != max34461)
return -ENXIO;
ret = pmbus_read_word_data(client, page,
MAX34446_MFR_TEMPERATURE_AVG);
@@ -322,6 +324,73 @@ static struct pmbus_driver_info max34440_info[] = {
.read_word_data = max34440_read_word_data,
.write_word_data = max34440_write_word_data,
},
+ [max34460] = {
+ .pages = 18,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .format[PSC_TEMPERATURE] = direct,
+ .m[PSC_VOLTAGE_OUT] = 1,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = 3,
+ .m[PSC_TEMPERATURE] = 1,
+ .b[PSC_TEMPERATURE] = 0,
+ .R[PSC_TEMPERATURE] = 2,
+ .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[14] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[15] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34440_read_byte_data,
+ .read_word_data = max34440_read_word_data,
+ .write_word_data = max34440_write_word_data,
+ },
+ [max34461] = {
+ .pages = 23,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .format[PSC_TEMPERATURE] = direct,
+ .m[PSC_VOLTAGE_OUT] = 1,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = 3,
+ .m[PSC_TEMPERATURE] = 1,
+ .b[PSC_TEMPERATURE] = 0,
+ .R[PSC_TEMPERATURE] = 2,
+ .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[6] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[7] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[8] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[9] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[10] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[11] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[12] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[13] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[14] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[15] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ /* page 16 is reserved */
+ .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[21] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34440_read_byte_data,
+ .read_word_data = max34440_read_word_data,
+ .write_word_data = max34440_write_word_data,
+ },
};
static int max34440_probe(struct i2c_client *client,
@@ -343,6 +412,8 @@ static const struct i2c_device_id max34440_id[] = {
{"max34440", max34440},
{"max34441", max34441},
{"max34446", max34446},
+ {"max34460", max34460},
+ {"max34461", max34461},
{}
};
MODULE_DEVICE_TABLE(i2c, max34440_id);
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 3fe03dc47eb7..fa9beb3eb60c 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -2,6 +2,7 @@
* pmbus.h - Common defines and structures for PMBus devices
*
* Copyright (c) 2010, 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -177,6 +178,13 @@
#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 28)
#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 29)
+#define PMBUS_VIRT_READ_VMON (PMBUS_VIRT_BASE + 30)
+#define PMBUS_VIRT_VMON_UV_WARN_LIMIT (PMBUS_VIRT_BASE + 31)
+#define PMBUS_VIRT_VMON_OV_WARN_LIMIT (PMBUS_VIRT_BASE + 32)
+#define PMBUS_VIRT_VMON_UV_FAULT_LIMIT (PMBUS_VIRT_BASE + 33)
+#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 34)
+#define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 35)
+
/*
* CAPABILITY
*/
@@ -317,6 +325,8 @@ enum pmbus_sensor_classes {
#define PMBUS_HAVE_STATUS_TEMP (1 << 15)
#define PMBUS_HAVE_STATUS_FAN12 (1 << 16)
#define PMBUS_HAVE_STATUS_FAN34 (1 << 17)
+#define PMBUS_HAVE_VMON (1 << 18)
+#define PMBUS_HAVE_STATUS_VMON (1 << 19)
enum pmbus_data_format { linear = 0, direct, vid };
@@ -359,6 +369,7 @@ struct pmbus_driver_info {
/* Function declarations */
+void pmbus_clear_cache(struct i2c_client *client);
int pmbus_set_page(struct i2c_client *client, u8 page);
int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 7d19b1bb9ce6..80eef50c50fd 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -2,6 +2,7 @@
* Hardware monitoring driver for PMBus devices
*
* Copyright (c) 2010, 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,45 +32,10 @@
#include "pmbus.h"
/*
- * Constants needed to determine number of sensors, booleans, and labels.
+ * Number of additional attribute pointers to allocate
+ * with each call to krealloc
*/
-#define PMBUS_MAX_INPUT_SENSORS 22 /* 10*volt, 7*curr, 5*power */
-#define PMBUS_VOUT_SENSORS_PER_PAGE 9 /* input, min, max, lcrit,
- crit, lowest, highest, avg,
- reset */
-#define PMBUS_IOUT_SENSORS_PER_PAGE 8 /* input, min, max, crit,
- lowest, highest, avg,
- reset */
-#define PMBUS_POUT_SENSORS_PER_PAGE 7 /* input, cap, max, crit,
- * highest, avg, reset
- */
-#define PMBUS_MAX_SENSORS_PER_FAN 1 /* input */
-#define PMBUS_MAX_SENSORS_PER_TEMP 9 /* input, min, max, lcrit,
- * crit, lowest, highest, avg,
- * reset
- */
-
-#define PMBUS_MAX_INPUT_BOOLEANS 7 /* v: min_alarm, max_alarm,
- lcrit_alarm, crit_alarm;
- c: alarm, crit_alarm;
- p: crit_alarm */
-#define PMBUS_VOUT_BOOLEANS_PER_PAGE 4 /* min_alarm, max_alarm,
- lcrit_alarm, crit_alarm */
-#define PMBUS_IOUT_BOOLEANS_PER_PAGE 3 /* alarm, lcrit_alarm,
- crit_alarm */
-#define PMBUS_POUT_BOOLEANS_PER_PAGE 3 /* cap_alarm, alarm, crit_alarm
- */
-#define PMBUS_MAX_BOOLEANS_PER_FAN 2 /* alarm, fault */
-#define PMBUS_MAX_BOOLEANS_PER_TEMP 4 /* min_alarm, max_alarm,
- lcrit_alarm, crit_alarm */
-
-#define PMBUS_MAX_INPUT_LABELS 4 /* vin, vcap, iin, pin */
-
-/*
- * status, status_vout, status_iout, status_fans, status_fan34, and status_temp
- * are paged. status_input is unpaged.
- */
-#define PB_NUM_STATUS_REG (PMBUS_PAGES * 6 + 1)
+#define PMBUS_ATTR_ALLOC_SIZE 32
/*
* Index into status register array, per status register group
@@ -79,14 +45,18 @@
#define PB_STATUS_IOUT_BASE (PB_STATUS_VOUT_BASE + PMBUS_PAGES)
#define PB_STATUS_FAN_BASE (PB_STATUS_IOUT_BASE + PMBUS_PAGES)
#define PB_STATUS_FAN34_BASE (PB_STATUS_FAN_BASE + PMBUS_PAGES)
-#define PB_STATUS_INPUT_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES)
-#define PB_STATUS_TEMP_BASE (PB_STATUS_INPUT_BASE + 1)
+#define PB_STATUS_TEMP_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES)
+#define PB_STATUS_INPUT_BASE (PB_STATUS_TEMP_BASE + PMBUS_PAGES)
+#define PB_STATUS_VMON_BASE (PB_STATUS_INPUT_BASE + 1)
+
+#define PB_NUM_STATUS_REG (PB_STATUS_VMON_BASE + 1)
#define PMBUS_NAME_SIZE 24
struct pmbus_sensor {
+ struct pmbus_sensor *next;
char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */
- struct sensor_device_attribute attribute;
+ struct device_attribute attribute;
u8 page; /* page number */
u16 reg; /* register */
enum pmbus_sensor_classes class; /* sensor class */
@@ -94,19 +64,28 @@ struct pmbus_sensor {
int data; /* Sensor data.
Negative if there was a read error */
};
+#define to_pmbus_sensor(_attr) \
+ container_of(_attr, struct pmbus_sensor, attribute)
struct pmbus_boolean {
char name[PMBUS_NAME_SIZE]; /* sysfs boolean name */
struct sensor_device_attribute attribute;
+ struct pmbus_sensor *s1;
+ struct pmbus_sensor *s2;
};
+#define to_pmbus_boolean(_attr) \
+ container_of(_attr, struct pmbus_boolean, attribute)
struct pmbus_label {
char name[PMBUS_NAME_SIZE]; /* sysfs label name */
- struct sensor_device_attribute attribute;
+ struct device_attribute attribute;
char label[PMBUS_NAME_SIZE]; /* label */
};
+#define to_pmbus_label(_attr) \
+ container_of(_attr, struct pmbus_label, attribute)
struct pmbus_data {
+ struct device *dev;
struct device *hwmon_dev;
u32 flags; /* from platform data */
@@ -117,29 +96,9 @@ struct pmbus_data {
int max_attributes;
int num_attributes;
- struct attribute **attributes;
struct attribute_group group;
- /*
- * Sensors cover both sensor and limit registers.
- */
- int max_sensors;
- int num_sensors;
struct pmbus_sensor *sensors;
- /*
- * Booleans are used for alarms.
- * Values are determined from status registers.
- */
- int max_booleans;
- int num_booleans;
- struct pmbus_boolean *booleans;
- /*
- * Labels are used to map generic names (e.g., "in1")
- * to PMBus specific names (e.g., "vin" or "vout1").
- */
- int max_labels;
- int num_labels;
- struct pmbus_label *labels;
struct mutex update_lock;
bool valid;
@@ -150,10 +109,19 @@ struct pmbus_data {
* so we keep them all together.
*/
u8 status[PB_NUM_STATUS_REG];
+ u8 status_register;
u8 currpage;
};
+void pmbus_clear_cache(struct i2c_client *client)
+{
+ struct pmbus_data *data = i2c_get_clientdata(client);
+
+ data->valid = false;
+}
+EXPORT_SYMBOL_GPL(pmbus_clear_cache);
+
int pmbus_set_page(struct i2c_client *client, u8 page)
{
struct pmbus_data *data = i2c_get_clientdata(client);
@@ -318,9 +286,10 @@ EXPORT_SYMBOL_GPL(pmbus_clear_faults);
static int pmbus_check_status_cml(struct i2c_client *client)
{
+ struct pmbus_data *data = i2c_get_clientdata(client);
int status, status2;
- status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE);
+ status = _pmbus_read_byte_data(client, -1, data->status_register);
if (status < 0 || (status & PB_STATUS_CML)) {
status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND))
@@ -329,29 +298,30 @@ static int pmbus_check_status_cml(struct i2c_client *client)
return 0;
}
-bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
+static bool pmbus_check_register(struct i2c_client *client,
+ int (*func)(struct i2c_client *client,
+ int page, int reg),
+ int page, int reg)
{
int rv;
struct pmbus_data *data = i2c_get_clientdata(client);
- rv = _pmbus_read_byte_data(client, page, reg);
+ rv = func(client, page, reg);
if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
rv = pmbus_check_status_cml(client);
pmbus_clear_fault_page(client, -1);
return rv >= 0;
}
+
+bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
+{
+ return pmbus_check_register(client, _pmbus_read_byte_data, page, reg);
+}
EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
{
- int rv;
- struct pmbus_data *data = i2c_get_clientdata(client);
-
- rv = _pmbus_read_word_data(client, page, reg);
- if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
- rv = pmbus_check_status_cml(client);
- pmbus_clear_fault_page(client, -1);
- return rv >= 0;
+ return pmbus_check_register(client, _pmbus_read_word_data, page, reg);
}
EXPORT_SYMBOL_GPL(pmbus_check_word_register);
@@ -363,53 +333,43 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
}
EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
+static struct _pmbus_status {
+ u32 func;
+ u16 base;
+ u16 reg;
+} pmbus_status[] = {
+ { PMBUS_HAVE_STATUS_VOUT, PB_STATUS_VOUT_BASE, PMBUS_STATUS_VOUT },
+ { PMBUS_HAVE_STATUS_IOUT, PB_STATUS_IOUT_BASE, PMBUS_STATUS_IOUT },
+ { PMBUS_HAVE_STATUS_TEMP, PB_STATUS_TEMP_BASE,
+ PMBUS_STATUS_TEMPERATURE },
+ { PMBUS_HAVE_STATUS_FAN12, PB_STATUS_FAN_BASE, PMBUS_STATUS_FAN_12 },
+ { PMBUS_HAVE_STATUS_FAN34, PB_STATUS_FAN34_BASE, PMBUS_STATUS_FAN_34 },
+};
+
static struct pmbus_data *pmbus_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pmbus_data *data = i2c_get_clientdata(client);
const struct pmbus_driver_info *info = data->info;
+ struct pmbus_sensor *sensor;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- int i;
+ int i, j;
- for (i = 0; i < info->pages; i++)
+ for (i = 0; i < info->pages; i++) {
data->status[PB_STATUS_BASE + i]
= _pmbus_read_byte_data(client, i,
- PMBUS_STATUS_BYTE);
- for (i = 0; i < info->pages; i++) {
- if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT))
- continue;
- data->status[PB_STATUS_VOUT_BASE + i]
- = _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_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_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_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_read_byte_data(client, i,
- PMBUS_STATUS_FAN_34);
+ data->status_register);
+ for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) {
+ struct _pmbus_status *s = &pmbus_status[j];
+
+ if (!(info->func[i] & s->func))
+ continue;
+ data->status[s->base + i]
+ = _pmbus_read_byte_data(client, i,
+ s->reg);
+ }
}
if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
@@ -417,9 +377,12 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
= _pmbus_read_byte_data(client, 0,
PMBUS_STATUS_INPUT);
- for (i = 0; i < data->num_sensors; i++) {
- struct pmbus_sensor *sensor = &data->sensors[i];
+ if (info->func[0] & PMBUS_HAVE_STATUS_VMON)
+ data->status[PB_STATUS_VMON_BASE]
+ = _pmbus_read_byte_data(client, 0,
+ PMBUS_VIRT_STATUS_VMON);
+ for (sensor = data->sensors; sensor; sensor = sensor->next) {
if (!data->valid || sensor->update)
sensor->data
= _pmbus_read_word_data(client,
@@ -657,7 +620,7 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
static u16 pmbus_data2reg_vid(struct pmbus_data *data,
enum pmbus_sensor_classes class, long val)
{
- val = SENSORS_LIMIT(val, 500, 1600);
+ val = clamp_val(val, 500, 1600);
return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625);
}
@@ -684,25 +647,20 @@ static u16 pmbus_data2reg(struct pmbus_data *data,
/*
* Return boolean calculated from converted data.
- * <index> defines a status register index and mask, and optionally
- * two sensor indexes.
- * The upper half-word references the two sensors,
- * two sensor indices.
- * The upper half-word references the two optional sensors,
- * the lower half word references status register and mask.
- * The function returns true if (status[reg] & mask) is true and,
- * if specified, if v1 >= v2.
- * To determine if an object exceeds upper limits, specify <v, limit>.
- * To determine if an object exceeds lower limits, specify <limit, v>.
+ * <index> defines a status register index and mask.
+ * The mask is in the lower 8 bits, the register index is in bits 8..23.
*
- * For booleans created with pmbus_add_boolean_reg(), only the lower 16 bits of
- * index are set. s1 and s2 (the sensor index values) are zero in this case.
- * The function returns true if (status[reg] & mask) is true.
+ * The associated pmbus_boolean structure contains optional pointers to two
+ * sensor attributes. If specified, those attributes are compared against each
+ * other to determine if a limit has been exceeded.
*
- * If the boolean was created with pmbus_add_boolean_cmp(), a comparison against
- * a specified limit has to be performed to determine the boolean result.
+ * If the sensor attribute pointers are NULL, the function returns true if
+ * (status[reg] & mask) is true.
+ *
+ * If sensor attribute pointers are provided, a comparison against a specified
+ * limit has to be performed to determine the boolean result.
* In this case, the function returns true if v1 >= v2 (where v1 and v2 are
- * sensor values referenced by sensor indices s1 and s2).
+ * sensor values referenced by sensor attribute pointers s1 and s2).
*
* To determine if an object exceeds upper limits, specify <s1,s2> = <v,limit>.
* To determine if an object exceeds lower limits, specify <s1,s2> = <limit,v>.
@@ -710,11 +668,12 @@ static u16 pmbus_data2reg(struct pmbus_data *data,
* If a negative value is stored in any of the referenced registers, this value
* reflects an error code which will be returned.
*/
-static int pmbus_get_boolean(struct pmbus_data *data, int index)
+static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b,
+ int index)
{
- u8 s1 = (index >> 24) & 0xff;
- u8 s2 = (index >> 16) & 0xff;
- u8 reg = (index >> 8) & 0xff;
+ struct pmbus_sensor *s1 = b->s1;
+ struct pmbus_sensor *s2 = b->s2;
+ u16 reg = (index >> 8) & 0xffff;
u8 mask = index & 0xff;
int ret, status;
u8 regval;
@@ -724,21 +683,21 @@ static int pmbus_get_boolean(struct pmbus_data *data, int index)
return status;
regval = status & mask;
- if (!s1 && !s2)
+ if (!s1 && !s2) {
ret = !!regval;
- else {
+ } else if (!s1 || !s2) {
+ BUG();
+ return 0;
+ } else {
long v1, v2;
- struct pmbus_sensor *sensor1, *sensor2;
- sensor1 = &data->sensors[s1];
- if (sensor1->data < 0)
- return sensor1->data;
- sensor2 = &data->sensors[s2];
- if (sensor2->data < 0)
- return sensor2->data;
+ if (s1->data < 0)
+ return s1->data;
+ if (s2->data < 0)
+ return s2->data;
- v1 = pmbus_reg2data(data, sensor1);
- v2 = pmbus_reg2data(data, sensor2);
+ v1 = pmbus_reg2data(data, s1);
+ v2 = pmbus_reg2data(data, s2);
ret = !!(regval && v1 >= v2);
}
return ret;
@@ -748,23 +707,22 @@ static ssize_t pmbus_show_boolean(struct device *dev,
struct device_attribute *da, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct pmbus_boolean *boolean = to_pmbus_boolean(attr);
struct pmbus_data *data = pmbus_update_device(dev);
int val;
- val = pmbus_get_boolean(data, attr->index);
+ val = pmbus_get_boolean(data, boolean, attr->index);
if (val < 0)
return val;
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t pmbus_show_sensor(struct device *dev,
- struct device_attribute *da, char *buf)
+ struct device_attribute *devattr, char *buf)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct pmbus_data *data = pmbus_update_device(dev);
- struct pmbus_sensor *sensor;
+ struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
- sensor = &data->sensors[attr->index];
if (sensor->data < 0)
return sensor->data;
@@ -775,10 +733,9 @@ static ssize_t pmbus_set_sensor(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pmbus_data *data = i2c_get_clientdata(client);
- struct pmbus_sensor *sensor = &data->sensors[attr->index];
+ struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
ssize_t rv = count;
long val = 0;
int ret;
@@ -793,7 +750,7 @@ static ssize_t pmbus_set_sensor(struct device *dev,
if (ret < 0)
rv = ret;
else
- data->sensors[attr->index].data = regval;
+ sensor->data = regval;
mutex_unlock(&data->update_lock);
return rv;
}
@@ -801,102 +758,130 @@ static ssize_t pmbus_set_sensor(struct device *dev,
static ssize_t pmbus_show_label(struct device *dev,
struct device_attribute *da, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct pmbus_data *data = i2c_get_clientdata(client);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct pmbus_label *label = to_pmbus_label(da);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- data->labels[attr->index].label);
+ return snprintf(buf, PAGE_SIZE, "%s\n", label->label);
}
-#define PMBUS_ADD_ATTR(data, _name, _idx, _mode, _type, _show, _set) \
-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; \
- a->dev_attr.store = _set; \
- a->index = _idx; \
- data->attributes[data->num_attributes] = &a->dev_attr.attr; \
- data->num_attributes++; \
-} while (0)
-
-#define PMBUS_ADD_GET_ATTR(data, _name, _type, _idx) \
- PMBUS_ADD_ATTR(data, _name, _idx, S_IRUGO, _type, \
- pmbus_show_##_type, NULL)
-
-#define PMBUS_ADD_SET_ATTR(data, _name, _type, _idx) \
- PMBUS_ADD_ATTR(data, _name, _idx, S_IWUSR | S_IRUGO, _type, \
- pmbus_show_##_type, pmbus_set_##_type)
-
-static void pmbus_add_boolean(struct pmbus_data *data,
- const char *name, const char *type, int seq,
- int idx)
+static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr)
{
- struct pmbus_boolean *boolean;
-
- BUG_ON(data->num_booleans >= data->max_booleans);
-
- boolean = &data->booleans[data->num_booleans];
+ if (data->num_attributes >= data->max_attributes - 1) {
+ data->max_attributes += PMBUS_ATTR_ALLOC_SIZE;
+ data->group.attrs = krealloc(data->group.attrs,
+ sizeof(struct attribute *) *
+ data->max_attributes, GFP_KERNEL);
+ if (data->group.attrs == NULL)
+ return -ENOMEM;
+ }
- snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s",
- name, seq, type);
- PMBUS_ADD_GET_ATTR(data, boolean->name, boolean, idx);
- data->num_booleans++;
+ data->group.attrs[data->num_attributes++] = attr;
+ data->group.attrs[data->num_attributes] = NULL;
+ return 0;
}
-static void pmbus_add_boolean_reg(struct pmbus_data *data,
- const char *name, const char *type,
- int seq, int reg, int bit)
+static void pmbus_dev_attr_init(struct device_attribute *dev_attr,
+ const char *name,
+ umode_t mode,
+ ssize_t (*show)(struct device *dev,
+ struct device_attribute *attr,
+ char *buf),
+ ssize_t (*store)(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count))
{
- pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit);
+ sysfs_attr_init(&dev_attr->attr);
+ dev_attr->attr.name = name;
+ dev_attr->attr.mode = mode;
+ dev_attr->show = show;
+ dev_attr->store = store;
}
-static void pmbus_add_boolean_cmp(struct pmbus_data *data,
- const char *name, const char *type,
- int seq, int i1, int i2, int reg, int mask)
+static void pmbus_attr_init(struct sensor_device_attribute *a,
+ const char *name,
+ umode_t mode,
+ ssize_t (*show)(struct device *dev,
+ struct device_attribute *attr,
+ char *buf),
+ ssize_t (*store)(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count),
+ int idx)
{
- pmbus_add_boolean(data, name, type, seq,
- (i1 << 24) | (i2 << 16) | (reg << 8) | mask);
+ pmbus_dev_attr_init(&a->dev_attr, name, mode, show, store);
+ a->index = idx;
}
-static void pmbus_add_sensor(struct pmbus_data *data,
+static int pmbus_add_boolean(struct pmbus_data *data,
const char *name, const char *type, int seq,
- int page, int reg, enum pmbus_sensor_classes class,
- bool update, bool readonly)
+ struct pmbus_sensor *s1,
+ struct pmbus_sensor *s2,
+ u16 reg, u8 mask)
+{
+ struct pmbus_boolean *boolean;
+ struct sensor_device_attribute *a;
+
+ boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL);
+ if (!boolean)
+ return -ENOMEM;
+
+ a = &boolean->attribute;
+
+ snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s",
+ name, seq, type);
+ boolean->s1 = s1;
+ boolean->s2 = s2;
+ pmbus_attr_init(a, boolean->name, S_IRUGO, pmbus_show_boolean, NULL,
+ (reg << 8) | mask);
+
+ return pmbus_add_attribute(data, &a->dev_attr.attr);
+}
+
+static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
+ const char *name, const char *type,
+ int seq, int page, int reg,
+ enum pmbus_sensor_classes class,
+ bool update, bool readonly)
{
struct pmbus_sensor *sensor;
+ struct device_attribute *a;
- BUG_ON(data->num_sensors >= data->max_sensors);
+ sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return NULL;
+ a = &sensor->attribute;
- sensor = &data->sensors[data->num_sensors];
snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s",
name, seq, type);
sensor->page = page;
sensor->reg = reg;
sensor->class = class;
sensor->update = update;
- if (readonly)
- PMBUS_ADD_GET_ATTR(data, sensor->name, sensor,
- data->num_sensors);
- else
- PMBUS_ADD_SET_ATTR(data, sensor->name, sensor,
- data->num_sensors);
- data->num_sensors++;
+ pmbus_dev_attr_init(a, sensor->name,
+ readonly ? S_IRUGO : S_IRUGO | S_IWUSR,
+ pmbus_show_sensor, pmbus_set_sensor);
+
+ if (pmbus_add_attribute(data, &a->attr))
+ return NULL;
+
+ sensor->next = data->sensors;
+ data->sensors = sensor;
+
+ return sensor;
}
-static void pmbus_add_label(struct pmbus_data *data,
- const char *name, int seq,
- const char *lstring, int index)
+static int pmbus_add_label(struct pmbus_data *data,
+ const char *name, int seq,
+ const char *lstring, int index)
{
struct pmbus_label *label;
+ struct device_attribute *a;
- BUG_ON(data->num_labels >= data->max_labels);
+ label = devm_kzalloc(data->dev, sizeof(*label), GFP_KERNEL);
+ if (!label)
+ return -ENOMEM;
+
+ a = &label->attribute;
- label = &data->labels[data->num_labels];
snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
if (!index)
strncpy(label->label, lstring, sizeof(label->label) - 1);
@@ -904,65 +889,8 @@ static void pmbus_add_label(struct pmbus_data *data,
snprintf(label->label, sizeof(label->label), "%s%d", lstring,
index);
- PMBUS_ADD_GET_ATTR(data, label->name, label, data->num_labels);
- data->num_labels++;
-}
-
-/*
- * Determine maximum number of sensors, booleans, and labels.
- * To keep things simple, only make a rough high estimate.
- */
-static void pmbus_find_max_attr(struct i2c_client *client,
- struct pmbus_data *data)
-{
- const struct pmbus_driver_info *info = data->info;
- int page, max_sensors, max_booleans, max_labels;
-
- max_sensors = PMBUS_MAX_INPUT_SENSORS;
- max_booleans = PMBUS_MAX_INPUT_BOOLEANS;
- max_labels = PMBUS_MAX_INPUT_LABELS;
-
- for (page = 0; page < info->pages; page++) {
- if (info->func[page] & PMBUS_HAVE_VOUT) {
- max_sensors += PMBUS_VOUT_SENSORS_PER_PAGE;
- max_booleans += PMBUS_VOUT_BOOLEANS_PER_PAGE;
- max_labels++;
- }
- if (info->func[page] & PMBUS_HAVE_IOUT) {
- max_sensors += PMBUS_IOUT_SENSORS_PER_PAGE;
- max_booleans += PMBUS_IOUT_BOOLEANS_PER_PAGE;
- max_labels++;
- }
- if (info->func[page] & PMBUS_HAVE_POUT) {
- max_sensors += PMBUS_POUT_SENSORS_PER_PAGE;
- max_booleans += PMBUS_POUT_BOOLEANS_PER_PAGE;
- max_labels++;
- }
- if (info->func[page] & PMBUS_HAVE_FAN12) {
- max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
- max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
- }
- if (info->func[page] & PMBUS_HAVE_FAN34) {
- max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
- max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
- }
- if (info->func[page] & PMBUS_HAVE_TEMP) {
- max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
- max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
- }
- if (info->func[page] & PMBUS_HAVE_TEMP2) {
- max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
- max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
- }
- if (info->func[page] & PMBUS_HAVE_TEMP3) {
- max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
- max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
- }
- }
- data->max_sensors = max_sensors;
- data->max_booleans = max_booleans;
- data->max_labels = max_labels;
- data->max_attributes = max_sensors + max_booleans + max_labels;
+ pmbus_dev_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL);
+ return pmbus_add_attribute(data, &a->attr);
}
/*
@@ -975,12 +903,12 @@ static void pmbus_find_max_attr(struct i2c_client *client,
*/
struct pmbus_limit_attr {
u16 reg; /* Limit register */
+ u16 sbit; /* Alarm attribute status bit */
bool update; /* True if register needs updates */
bool low; /* True if low limit; for limits with compare
functions only */
const char *attr; /* Attribute name */
const char *alarm; /* Alarm attribute name */
- u32 sbit; /* Alarm attribute status bit */
};
/*
@@ -988,7 +916,9 @@ struct pmbus_limit_attr {
* description includes a reference to the associated limit attributes.
*/
struct pmbus_sensor_attr {
- u8 reg; /* sensor register */
+ u16 reg; /* sensor register */
+ u8 gbit; /* generic status bit */
+ u8 nlimit; /* # of limit registers */
enum pmbus_sensor_classes class;/* sensor class */
const char *label; /* sensor label */
bool paged; /* true if paged sensor */
@@ -997,47 +927,47 @@ struct pmbus_sensor_attr {
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.
+ * returns 0 if no alarm register found, 1 if an alarm register was found,
+ * < 0 on errors.
*/
-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)
+static int 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,
+ struct pmbus_sensor *base,
+ 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;
+ int have_alarm = 0;
+ int i, ret;
+ struct pmbus_sensor *curr;
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 || l->update,
- false);
+ curr = pmbus_add_sensor(data, name, l->attr, index,
+ page, l->reg, attr->class,
+ attr->update || l->update,
+ false);
+ if (!curr)
+ return -ENOMEM;
if (l->sbit && (info->func[page] & attr->sfunc)) {
- if (attr->compare) {
- pmbus_add_boolean_cmp(data, name,
- l->alarm, index,
- l->low ? cindex : cbase,
- l->low ? 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;
+ ret = pmbus_add_boolean(data, name,
+ l->alarm, index,
+ attr->compare ? l->low ? curr : base
+ : NULL,
+ attr->compare ? l->low ? base : curr
+ : NULL,
+ attr->sbase + page, l->sbit);
+ if (ret)
+ return ret;
+ have_alarm = 1;
}
}
l++;
@@ -1045,45 +975,59 @@ static bool pmbus_add_limit_attrs(struct i2c_client *client,
return have_alarm;
}
-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)
+static int 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);
+ struct pmbus_sensor *base;
+ int ret;
+
+ if (attr->label) {
+ ret = pmbus_add_label(data, name, index, attr->label,
+ attr->paged ? page + 1 : 0);
+ if (ret)
+ return ret;
+ }
+ base = pmbus_add_sensor(data, name, "input", index, page, attr->reg,
+ attr->class, true, true);
+ if (!base)
+ return -ENOMEM;
if (attr->sfunc) {
- have_alarm = pmbus_add_limit_attrs(client, data, info, name,
- index, page, cbase, attr);
+ ret = pmbus_add_limit_attrs(client, data, info, name,
+ index, page, base, attr);
+ if (ret < 0)
+ return ret;
/*
* Add generic alarm attribute only if there are no individual
* alarm attributes, if there is a global alarm bit, and if
* the generic status register for this page is accessible.
*/
- if (!have_alarm && attr->gbit &&
- pmbus_check_byte_register(client, page, PMBUS_STATUS_BYTE))
- pmbus_add_boolean_reg(data, name, "alarm", index,
- PB_STATUS_BASE + page,
- attr->gbit);
+ if (!ret && attr->gbit &&
+ pmbus_check_byte_register(client, page,
+ data->status_register)) {
+ ret = pmbus_add_boolean(data, name, "alarm", index,
+ NULL, NULL,
+ PB_STATUS_BASE + page,
+ attr->gbit);
+ if (ret)
+ return ret;
+ }
}
+ return 0;
}
-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)
+static int 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;
+ int ret;
index = 1;
for (i = 0; i < nattrs; i++) {
@@ -1093,12 +1037,16 @@ static void pmbus_add_sensor_attrs(struct i2c_client *client,
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);
+ ret = pmbus_add_sensor_attrs_one(client, data, info,
+ name, index, page,
+ attrs);
+ if (ret)
+ return ret;
index++;
}
attrs++;
}
+ return 0;
}
static const struct pmbus_limit_attr vin_limit_attrs[] = {
@@ -1140,6 +1088,30 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = {
},
};
+static const struct pmbus_limit_attr vmon_limit_attrs[] = {
+ {
+ .reg = PMBUS_VIRT_VMON_UV_WARN_LIMIT,
+ .attr = "min",
+ .alarm = "min_alarm",
+ .sbit = PB_VOLTAGE_UV_WARNING,
+ }, {
+ .reg = PMBUS_VIRT_VMON_UV_FAULT_LIMIT,
+ .attr = "lcrit",
+ .alarm = "lcrit_alarm",
+ .sbit = PB_VOLTAGE_UV_FAULT,
+ }, {
+ .reg = PMBUS_VIRT_VMON_OV_WARN_LIMIT,
+ .attr = "max",
+ .alarm = "max_alarm",
+ .sbit = PB_VOLTAGE_OV_WARNING,
+ }, {
+ .reg = PMBUS_VIRT_VMON_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,
@@ -1191,6 +1163,15 @@ static const struct pmbus_sensor_attr voltage_attributes[] = {
.limit = vin_limit_attrs,
.nlimit = ARRAY_SIZE(vin_limit_attrs),
}, {
+ .reg = PMBUS_VIRT_READ_VMON,
+ .class = PSC_VOLTAGE_IN,
+ .label = "vmon",
+ .func = PMBUS_HAVE_VMON,
+ .sfunc = PMBUS_HAVE_STATUS_VMON,
+ .sbase = PB_STATUS_VMON_BASE,
+ .limit = vmon_limit_attrs,
+ .nlimit = ARRAY_SIZE(vmon_limit_attrs),
+ }, {
.reg = PMBUS_READ_VCAP,
.class = PSC_VOLTAGE_IN,
.label = "vcap",
@@ -1553,12 +1534,13 @@ static const u32 pmbus_fan_status_flags[] = {
};
/* Fans */
-static void pmbus_add_fan_attributes(struct i2c_client *client,
- struct pmbus_data *data)
+static int 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;
+ int ret;
for (page = 0; page < info->pages; page++) {
int f;
@@ -1584,9 +1566,10 @@ static void pmbus_add_fan_attributes(struct i2c_client *client,
(!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
continue;
- pmbus_add_sensor(data, "fan", "input", index, page,
- pmbus_fan_registers[f], PSC_FAN, true,
- true);
+ if (pmbus_add_sensor(data, "fan", "input", index,
+ page, pmbus_fan_registers[f],
+ PSC_FAN, true, true) == NULL)
+ return -ENOMEM;
/*
* Each fan status register covers multiple fans,
@@ -1601,39 +1584,55 @@ static void pmbus_add_fan_attributes(struct i2c_client *client,
base = PB_STATUS_FAN34_BASE + page;
else
base = PB_STATUS_FAN_BASE + page;
- pmbus_add_boolean_reg(data, "fan", "alarm",
- index, base,
+ ret = pmbus_add_boolean(data, "fan",
+ "alarm", index, NULL, NULL, base,
PB_FAN_FAN1_WARNING >> (f & 1));
- pmbus_add_boolean_reg(data, "fan", "fault",
- index, base,
+ if (ret)
+ return ret;
+ ret = pmbus_add_boolean(data, "fan",
+ "fault", index, NULL, NULL, base,
PB_FAN_FAN1_FAULT >> (f & 1));
+ if (ret)
+ return ret;
}
index++;
}
}
+ return 0;
}
-static void pmbus_find_attributes(struct i2c_client *client,
- struct pmbus_data *data)
+static int pmbus_find_attributes(struct i2c_client *client,
+ struct pmbus_data *data)
{
+ int ret;
+
/* Voltage sensors */
- pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
- ARRAY_SIZE(voltage_attributes));
+ ret = pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
+ ARRAY_SIZE(voltage_attributes));
+ if (ret)
+ return ret;
/* Current sensors */
- pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
- ARRAY_SIZE(current_attributes));
+ ret = pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
+ ARRAY_SIZE(current_attributes));
+ if (ret)
+ return ret;
/* Power sensors */
- pmbus_add_sensor_attrs(client, data, "power", power_attributes,
- ARRAY_SIZE(power_attributes));
+ ret = pmbus_add_sensor_attrs(client, data, "power", power_attributes,
+ ARRAY_SIZE(power_attributes));
+ if (ret)
+ return ret;
/* Temperature sensors */
- pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
- ARRAY_SIZE(temp_attributes));
+ ret = pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
+ ARRAY_SIZE(temp_attributes));
+ if (ret)
+ return ret;
/* Fans */
- pmbus_add_fan_attributes(client, data);
+ ret = pmbus_add_fan_attributes(client, data);
+ return ret;
}
/*
@@ -1672,127 +1671,119 @@ static int pmbus_identify_common(struct i2c_client *client,
}
}
- /* Determine maximum number of sensors, booleans, and labels */
- pmbus_find_max_attr(client, data);
pmbus_clear_fault_page(client, 0);
return 0;
}
-int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
- struct pmbus_driver_info *info)
+static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
+ struct pmbus_driver_info *info)
{
- const struct pmbus_platform_data *pdata = client->dev.platform_data;
- struct pmbus_data *data;
+ struct device *dev = &client->dev;
int ret;
- if (!info) {
- dev_err(&client->dev, "Missing chip information");
- return -ENODEV;
- }
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
- | I2C_FUNC_SMBUS_BYTE_DATA
- | I2C_FUNC_SMBUS_WORD_DATA))
- return -ENODEV;
-
- data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
- if (!data) {
- dev_err(&client->dev, "No memory to allocate driver data\n");
- return -ENOMEM;
- }
-
- i2c_set_clientdata(client, data);
- mutex_init(&data->update_lock);
-
- /* Bail out if PMBus status register does not exist. */
- if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) {
- dev_err(&client->dev, "PMBus status register not found\n");
- return -ENODEV;
+ /*
+ * Some PMBus chips don't support PMBUS_STATUS_BYTE, so try
+ * to use PMBUS_STATUS_WORD instead if that is the case.
+ * Bail out if both registers are not supported.
+ */
+ data->status_register = PMBUS_STATUS_BYTE;
+ ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE);
+ if (ret < 0 || ret == 0xff) {
+ data->status_register = PMBUS_STATUS_WORD;
+ ret = i2c_smbus_read_word_data(client, PMBUS_STATUS_WORD);
+ if (ret < 0 || ret == 0xffff) {
+ dev_err(dev, "PMBus status register not found\n");
+ return -ENODEV;
+ }
}
- if (pdata)
- data->flags = pdata->flags;
- data->info = info;
-
pmbus_clear_faults(client);
if (info->identify) {
ret = (*info->identify)(client, info);
if (ret < 0) {
- dev_err(&client->dev, "Chip identification failed\n");
+ dev_err(dev, "Chip identification failed\n");
return ret;
}
}
if (info->pages <= 0 || info->pages > PMBUS_PAGES) {
- dev_err(&client->dev, "Bad number of PMBus pages: %d\n",
- info->pages);
+ dev_err(dev, "Bad number of PMBus pages: %d\n", info->pages);
return -ENODEV;
}
ret = pmbus_identify_common(client, data);
if (ret < 0) {
- dev_err(&client->dev, "Failed to identify chip capabilities\n");
+ dev_err(dev, "Failed to identify chip capabilities\n");
return ret;
}
+ return 0;
+}
- ret = -ENOMEM;
- data->sensors = devm_kzalloc(&client->dev, sizeof(struct pmbus_sensor)
- * data->max_sensors, GFP_KERNEL);
- if (!data->sensors) {
- dev_err(&client->dev, "No memory to allocate sensor data\n");
- return -ENOMEM;
- }
+int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
+ struct pmbus_driver_info *info)
+{
+ struct device *dev = &client->dev;
+ const struct pmbus_platform_data *pdata = dev->platform_data;
+ struct pmbus_data *data;
+ int ret;
- data->booleans = devm_kzalloc(&client->dev, sizeof(struct pmbus_boolean)
- * data->max_booleans, GFP_KERNEL);
- if (!data->booleans) {
- dev_err(&client->dev, "No memory to allocate boolean data\n");
- return -ENOMEM;
- }
+ if (!info)
+ return -ENODEV;
- data->labels = devm_kzalloc(&client->dev, sizeof(struct pmbus_label)
- * data->max_labels, GFP_KERNEL);
- if (!data->labels) {
- dev_err(&client->dev, "No memory to allocate label data\n");
- return -ENOMEM;
- }
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
+ | I2C_FUNC_SMBUS_BYTE_DATA
+ | I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
- data->attributes = devm_kzalloc(&client->dev, sizeof(struct attribute *)
- * data->max_attributes, GFP_KERNEL);
- if (!data->attributes) {
- dev_err(&client->dev, "No memory to allocate attribute data\n");
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
return -ENOMEM;
- }
- pmbus_find_attributes(client, data);
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+ data->dev = dev;
+
+ if (pdata)
+ data->flags = pdata->flags;
+ data->info = info;
+
+ ret = pmbus_init_common(client, data, info);
+ if (ret < 0)
+ return ret;
+
+ ret = pmbus_find_attributes(client, data);
+ if (ret)
+ goto out_kfree;
/*
* If there are no attributes, something is wrong.
* Bail out instead of trying to register nothing.
*/
if (!data->num_attributes) {
- dev_err(&client->dev, "No attributes found\n");
- return -ENODEV;
+ dev_err(dev, "No attributes found\n");
+ ret = -ENODEV;
+ goto out_kfree;
}
/* Register sysfs hooks */
- data->group.attrs = data->attributes;
- ret = sysfs_create_group(&client->dev.kobj, &data->group);
+ ret = sysfs_create_group(&dev->kobj, &data->group);
if (ret) {
- dev_err(&client->dev, "Failed to create sysfs entries\n");
- return ret;
+ dev_err(dev, "Failed to create sysfs entries\n");
+ goto out_kfree;
}
- data->hwmon_dev = hwmon_device_register(&client->dev);
+ data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
ret = PTR_ERR(data->hwmon_dev);
- dev_err(&client->dev, "Failed to register hwmon device\n");
+ dev_err(dev, "Failed to register hwmon device\n");
goto out_hwmon_device_register;
}
return 0;
out_hwmon_device_register:
- sysfs_remove_group(&client->dev.kobj, &data->group);
+ sysfs_remove_group(&dev->kobj, &data->group);
+out_kfree:
+ kfree(data->group.attrs);
return ret;
}
EXPORT_SYMBOL_GPL(pmbus_do_probe);
@@ -1802,6 +1793,7 @@ int pmbus_do_remove(struct i2c_client *client)
struct pmbus_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->group);
+ kfree(data->group.attrs);
return 0;
}
EXPORT_SYMBOL_GPL(pmbus_do_remove);
diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c
index fc5eed8e85bb..819644121259 100644
--- a/drivers/hwmon/pmbus/zl6100.c
+++ b/drivers/hwmon/pmbus/zl6100.c
@@ -2,6 +2,7 @@
* Hardware monitoring driver for ZL6100 and compatibles
*
* Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2012 Guenter Roeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,12 +46,87 @@ struct zl6100_data {
#define ZL6100_MFR_XTEMP_ENABLE (1 << 7)
+#define MFR_VMON_OV_FAULT_LIMIT 0xf5
+#define MFR_VMON_UV_FAULT_LIMIT 0xf6
+#define MFR_READ_VMON 0xf7
+
+#define VMON_UV_WARNING (1 << 5)
+#define VMON_OV_WARNING (1 << 4)
+#define VMON_UV_FAULT (1 << 1)
+#define VMON_OV_FAULT (1 << 0)
+
#define ZL6100_WAIT_TIME 1000 /* uS */
static ushort delay = ZL6100_WAIT_TIME;
module_param(delay, ushort, 0644);
MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");
+/* Convert linear sensor value to milli-units */
+static long zl6100_l2d(s16 l)
+{
+ s16 exponent;
+ s32 mantissa;
+ long val;
+
+ exponent = l >> 11;
+ mantissa = ((s16)((l & 0x7ff) << 5)) >> 5;
+
+ val = mantissa;
+
+ /* scale result to milli-units */
+ val = val * 1000L;
+
+ if (exponent >= 0)
+ val <<= exponent;
+ else
+ val >>= -exponent;
+
+ return val;
+}
+
+#define MAX_MANTISSA (1023 * 1000)
+#define MIN_MANTISSA (511 * 1000)
+
+static u16 zl6100_d2l(long val)
+{
+ s16 exponent = 0, mantissa;
+ bool negative = false;
+
+ /* simple case */
+ if (val == 0)
+ return 0;
+
+ if (val < 0) {
+ negative = true;
+ val = -val;
+ }
+
+ /* Reduce large mantissa until it fits into 10 bit */
+ while (val >= MAX_MANTISSA && exponent < 15) {
+ exponent++;
+ val >>= 1;
+ }
+ /* Increase small mantissa to improve precision */
+ while (val < MIN_MANTISSA && exponent > -15) {
+ exponent--;
+ val <<= 1;
+ }
+
+ /* Convert mantissa from milli-units to units */
+ mantissa = DIV_ROUND_CLOSEST(val, 1000);
+
+ /* Ensure that resulting number is within range */
+ if (mantissa > 0x3ff)
+ mantissa = 0x3ff;
+
+ /* restore sign */
+ if (negative)
+ mantissa = -mantissa;
+
+ /* Convert to 5 bit exponent, 11 bit mantissa */
+ return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
+}
+
/* Some chips need a delay between accesses */
static inline void zl6100_wait(const struct zl6100_data *data)
{
@@ -65,9 +141,9 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct zl6100_data *data = to_zl6100_data(info);
- int ret;
+ int ret, vreg;
- if (page || reg >= PMBUS_VIRT_BASE)
+ if (page > 0)
return -ENXIO;
if (data->id == zl2005) {
@@ -83,9 +159,39 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
}
}
+ switch (reg) {
+ case PMBUS_VIRT_READ_VMON:
+ vreg = MFR_READ_VMON;
+ break;
+ case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+ case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
+ vreg = MFR_VMON_OV_FAULT_LIMIT;
+ break;
+ case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+ case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
+ vreg = MFR_VMON_UV_FAULT_LIMIT;
+ break;
+ default:
+ if (reg >= PMBUS_VIRT_BASE)
+ return -ENXIO;
+ vreg = reg;
+ break;
+ }
+
zl6100_wait(data);
- ret = pmbus_read_word_data(client, page, reg);
+ ret = pmbus_read_word_data(client, page, vreg);
data->access = ktime_get();
+ if (ret < 0)
+ return ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+ ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 9, 10));
+ break;
+ case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+ ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 11, 10));
+ break;
+ }
return ret;
}
@@ -94,13 +200,35 @@ static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct zl6100_data *data = to_zl6100_data(info);
- int ret;
+ int ret, status;
if (page > 0)
return -ENXIO;
zl6100_wait(data);
- ret = pmbus_read_byte_data(client, page, reg);
+
+ switch (reg) {
+ case PMBUS_VIRT_STATUS_VMON:
+ ret = pmbus_read_byte_data(client, 0,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (ret < 0)
+ break;
+
+ status = 0;
+ if (ret & VMON_UV_WARNING)
+ status |= PB_VOLTAGE_UV_WARNING;
+ if (ret & VMON_OV_WARNING)
+ status |= PB_VOLTAGE_OV_WARNING;
+ if (ret & VMON_UV_FAULT)
+ status |= PB_VOLTAGE_UV_FAULT;
+ if (ret & VMON_OV_FAULT)
+ status |= PB_VOLTAGE_OV_FAULT;
+ ret = status;
+ break;
+ default:
+ ret = pmbus_read_byte_data(client, page, reg);
+ break;
+ }
data->access = ktime_get();
return ret;
@@ -111,13 +239,38 @@ static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct zl6100_data *data = to_zl6100_data(info);
- int ret;
+ int ret, vreg;
- if (page || reg >= PMBUS_VIRT_BASE)
+ if (page > 0)
return -ENXIO;
+ switch (reg) {
+ case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+ word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 9));
+ vreg = MFR_VMON_OV_FAULT_LIMIT;
+ pmbus_clear_cache(client);
+ break;
+ case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:
+ vreg = MFR_VMON_OV_FAULT_LIMIT;
+ pmbus_clear_cache(client);
+ break;
+ case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+ word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 11));
+ vreg = MFR_VMON_UV_FAULT_LIMIT;
+ pmbus_clear_cache(client);
+ break;
+ case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:
+ vreg = MFR_VMON_UV_FAULT_LIMIT;
+ pmbus_clear_cache(client);
+ break;
+ default:
+ if (reg >= PMBUS_VIRT_BASE)
+ return -ENXIO;
+ vreg = reg;
+ }
+
zl6100_wait(data);
- ret = pmbus_write_word_data(client, page, reg, word);
+ ret = pmbus_write_word_data(client, page, vreg, word);
data->access = ktime_get();
return ret;
@@ -225,6 +378,13 @@ static int zl6100_probe(struct i2c_client *client,
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+ /*
+ * ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage
+ * (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as vmon.
+ */
+ if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117)
+ info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;
+
ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
if (ret < 0)
return ret;
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index 1c85d39df171..bfe326e896df 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -139,12 +139,12 @@ static const u8 sht15_crc8_table[] = {
* @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
+ * @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
+ * @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.
+ * @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 {
@@ -166,8 +166,8 @@ struct sht15_data {
struct device *hwmon_dev;
struct regulator *reg;
struct notifier_block nb;
- int supply_uV;
- bool supply_uV_valid;
+ int supply_uv;
+ bool supply_uv_valid;
struct work_struct update_supply_work;
atomic_t interrupt_handled;
};
@@ -212,11 +212,13 @@ static u8 sht15_crc8(struct sht15_data *data,
*
* This implements section 3.4 of the data sheet
*/
-static void sht15_connection_reset(struct sht15_data *data)
+static int sht15_connection_reset(struct sht15_data *data)
{
- int i;
+ int i, err;
- gpio_direction_output(data->pdata->gpio_data, 1);
+ err = gpio_direction_output(data->pdata->gpio_data, 1);
+ if (err)
+ return err;
ndelay(SHT15_TSCKL);
gpio_set_value(data->pdata->gpio_sck, 0);
ndelay(SHT15_TSCKL);
@@ -226,6 +228,7 @@ static void sht15_connection_reset(struct sht15_data *data)
gpio_set_value(data->pdata->gpio_sck, 0);
ndelay(SHT15_TSCKL);
}
+ return 0;
}
/**
@@ -251,10 +254,14 @@ static inline void sht15_send_bit(struct sht15_data *data, int val)
* conservative ones used in implementation. This implements
* figure 12 on the data sheet.
*/
-static void sht15_transmission_start(struct sht15_data *data)
+static int sht15_transmission_start(struct sht15_data *data)
{
+ int err;
+
/* ensure data is high and output */
- gpio_direction_output(data->pdata->gpio_data, 1);
+ err = gpio_direction_output(data->pdata->gpio_data, 1);
+ if (err)
+ return err;
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 0);
ndelay(SHT15_TSCKL);
@@ -270,6 +277,7 @@ static void sht15_transmission_start(struct sht15_data *data)
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 0);
ndelay(SHT15_TSCKL);
+ return 0;
}
/**
@@ -293,13 +301,19 @@ static void sht15_send_byte(struct sht15_data *data, u8 byte)
*/
static int sht15_wait_for_response(struct sht15_data *data)
{
- gpio_direction_input(data->pdata->gpio_data);
+ int err;
+
+ err = gpio_direction_input(data->pdata->gpio_data);
+ if (err)
+ return err;
gpio_set_value(data->pdata->gpio_sck, 1);
ndelay(SHT15_TSCKH);
if (gpio_get_value(data->pdata->gpio_data)) {
gpio_set_value(data->pdata->gpio_sck, 0);
dev_err(data->dev, "Command not acknowledged\n");
- sht15_connection_reset(data);
+ err = sht15_connection_reset(data);
+ if (err)
+ return err;
return -EIO;
}
gpio_set_value(data->pdata->gpio_sck, 0);
@@ -317,12 +331,13 @@ static int sht15_wait_for_response(struct sht15_data *data)
*/
static int sht15_send_cmd(struct sht15_data *data, u8 cmd)
{
- int ret = 0;
+ int err;
- sht15_transmission_start(data);
+ err = sht15_transmission_start(data);
+ if (err)
+ return err;
sht15_send_byte(data, cmd);
- ret = sht15_wait_for_response(data);
- return ret;
+ return sht15_wait_for_response(data);
}
/**
@@ -352,9 +367,13 @@ static int sht15_soft_reset(struct sht15_data *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)
+static int sht15_ack(struct sht15_data *data)
{
- gpio_direction_output(data->pdata->gpio_data, 0);
+ int err;
+
+ err = gpio_direction_output(data->pdata->gpio_data, 0);
+ if (err)
+ return err;
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 1);
ndelay(SHT15_TSU);
@@ -362,7 +381,7 @@ static void sht15_ack(struct sht15_data *data)
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_data, 1);
- gpio_direction_input(data->pdata->gpio_data);
+ return gpio_direction_input(data->pdata->gpio_data);
}
/**
@@ -371,14 +390,19 @@ static void sht15_ack(struct sht15_data *data)
*
* This is basically a NAK (single clock pulse, data high).
*/
-static void sht15_end_transmission(struct sht15_data *data)
+static int sht15_end_transmission(struct sht15_data *data)
{
- gpio_direction_output(data->pdata->gpio_data, 1);
+ int err;
+
+ err = gpio_direction_output(data->pdata->gpio_data, 1);
+ if (err)
+ return err;
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);
+ return 0;
}
/**
@@ -410,17 +434,19 @@ static u8 sht15_read_byte(struct sht15_data *data)
*/
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);
+ int err;
+
+ err = sht15_send_cmd(data, SHT15_WRITE_STATUS);
+ if (err)
+ return err;
+ err = gpio_direction_output(data->pdata->gpio_data, 1);
+ if (err)
+ return err;
ndelay(SHT15_TSU);
sht15_send_byte(data, status);
- ret = sht15_wait_for_response(data);
- if (ret)
- return ret;
+ err = sht15_wait_for_response(data);
+ if (err)
+ return err;
data->val_status = status;
return 0;
@@ -446,7 +472,7 @@ static int sht15_update_status(struct sht15_data *data)
|| !data->status_valid) {
ret = sht15_send_cmd(data, SHT15_READ_STATUS);
if (ret)
- goto error_ret;
+ goto unlock;
status = sht15_read_byte(data);
if (data->checksumming) {
@@ -458,7 +484,9 @@ static int sht15_update_status(struct sht15_data *data)
== dev_checksum);
}
- sht15_end_transmission(data);
+ ret = sht15_end_transmission(data);
+ if (ret)
+ goto unlock;
/*
* Perform checksum validation on the received data.
@@ -469,27 +497,27 @@ static int sht15_update_status(struct sht15_data *data)
previous_config = data->val_status & 0x07;
ret = sht15_soft_reset(data);
if (ret)
- goto error_ret;
+ goto unlock;
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;
+ goto unlock;
}
}
ret = -EAGAIN;
- goto error_ret;
+ goto unlock;
}
data->val_status = status;
data->status_valid = true;
data->last_status = jiffies;
}
-error_ret:
- mutex_unlock(&data->read_lock);
+unlock:
+ mutex_unlock(&data->read_lock);
return ret;
}
@@ -511,7 +539,9 @@ static int sht15_measurement(struct sht15_data *data,
if (ret)
return ret;
- gpio_direction_input(data->pdata->gpio_data);
+ ret = gpio_direction_input(data->pdata->gpio_data);
+ if (ret)
+ return ret;
atomic_set(&data->interrupt_handled, 0);
enable_irq(gpio_to_irq(data->pdata->gpio_data));
@@ -524,9 +554,14 @@ static int sht15_measurement(struct sht15_data *data,
ret = wait_event_timeout(data->wait_queue,
(data->state == SHT15_READING_NOTHING),
msecs_to_jiffies(timeout_msecs));
- if (ret == 0) {/* timeout occurred */
+ if (data->state != SHT15_READING_NOTHING) { /* I/O error occurred */
+ data->state = SHT15_READING_NOTHING;
+ return -EIO;
+ } else if (ret == 0) { /* timeout occurred */
disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
- sht15_connection_reset(data);
+ ret = sht15_connection_reset(data);
+ if (ret)
+ return ret;
return -ETIME;
}
@@ -570,17 +605,17 @@ static int sht15_update_measurements(struct sht15_data *data)
data->state = SHT15_READING_HUMID;
ret = sht15_measurement(data, SHT15_MEASURE_RH, 160);
if (ret)
- goto error_ret;
+ goto unlock;
data->state = SHT15_READING_TEMP;
ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400);
if (ret)
- goto error_ret;
+ goto unlock;
data->measurements_valid = true;
data->last_measurement = jiffies;
}
-error_ret:
- mutex_unlock(&data->read_lock);
+unlock:
+ mutex_unlock(&data->read_lock);
return ret;
}
@@ -598,8 +633,8 @@ static inline int sht15_calc_temp(struct sht15_data *data)
for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--)
/* Find pointer to interpolate */
- if (data->supply_uV > temppoints[i - 1].vdd) {
- d1 = (data->supply_uV - temppoints[i - 1].vdd)
+ if (data->supply_uv > temppoints[i - 1].vdd) {
+ d1 = (data->supply_uv - temppoints[i - 1].vdd)
* (temppoints[i].d1 - temppoints[i - 1].d1)
/ (temppoints[i].vdd - temppoints[i - 1].vdd)
+ temppoints[i - 1].d1;
@@ -818,7 +853,8 @@ static void sht15_bh_read_data(struct work_struct *work_s)
/* Read the data back from the device */
val = sht15_read_byte(data);
val <<= 8;
- sht15_ack(data);
+ if (sht15_ack(data))
+ goto wakeup;
val |= sht15_read_byte(data);
if (data->checksumming) {
@@ -826,7 +862,8 @@ static void sht15_bh_read_data(struct work_struct *work_s)
* Ask the device for a checksum and read it back.
* Note: the device sends the checksum byte reversed.
*/
- sht15_ack(data);
+ if (sht15_ack(data))
+ goto wakeup;
dev_checksum = sht15_reverse(sht15_read_byte(data));
checksum_vals[0] = (data->state == SHT15_READING_TEMP) ?
SHT15_MEASURE_TEMP : SHT15_MEASURE_RH;
@@ -837,7 +874,8 @@ static void sht15_bh_read_data(struct work_struct *work_s)
}
/* Tell the device we are done */
- sht15_end_transmission(data);
+ if (sht15_end_transmission(data))
+ goto wakeup;
switch (data->state) {
case SHT15_READING_TEMP:
@@ -851,6 +889,7 @@ static void sht15_bh_read_data(struct work_struct *work_s)
}
data->state = SHT15_READING_NOTHING;
+wakeup:
wake_up(&data->wait_queue);
}
@@ -859,7 +898,7 @@ static void sht15_update_voltage(struct work_struct *work_s)
struct sht15_data *data
= container_of(work_s, struct sht15_data,
update_supply_work);
- data->supply_uV = regulator_get_voltage(data->reg);
+ data->supply_uv = regulator_get_voltage(data->reg);
}
/**
@@ -878,7 +917,7 @@ static int sht15_invalidate_voltage(struct notifier_block *nb,
struct sht15_data *data = container_of(nb, struct sht15_data, nb);
if (event == REGULATOR_EVENT_VOLTAGE_CHANGE)
- data->supply_uV_valid = false;
+ data->supply_uv_valid = false;
schedule_work(&data->update_supply_work);
return NOTIFY_OK;
@@ -906,7 +945,7 @@ static int sht15_probe(struct platform_device *pdev)
return -EINVAL;
}
data->pdata = pdev->dev.platform_data;
- data->supply_uV = data->pdata->supply_mv * 1000;
+ data->supply_uv = data->pdata->supply_mv * 1000;
if (data->pdata->checksum)
data->checksumming = true;
if (data->pdata->no_otp_reload)
@@ -924,7 +963,7 @@ static int sht15_probe(struct platform_device *pdev)
voltage = regulator_get_voltage(data->reg);
if (voltage)
- data->supply_uV = voltage;
+ data->supply_uv = voltage;
regulator_enable(data->reg);
/*
@@ -942,17 +981,17 @@ static int sht15_probe(struct platform_device *pdev)
}
/* Try requesting the GPIOs */
- ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_sck, "SHT15 sck");
+ ret = devm_gpio_request_one(&pdev->dev, data->pdata->gpio_sck,
+ GPIOF_OUT_INIT_LOW, "SHT15 sck");
if (ret) {
- dev_err(&pdev->dev, "gpio request failed\n");
+ dev_err(&pdev->dev, "clock line GPIO request failed\n");
goto err_release_reg;
}
- gpio_direction_output(data->pdata->gpio_sck, 0);
ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
"SHT15 data");
if (ret) {
- dev_err(&pdev->dev, "gpio request failed\n");
+ dev_err(&pdev->dev, "data line GPIO request failed\n");
goto err_release_reg;
}
@@ -966,7 +1005,9 @@ static int sht15_probe(struct platform_device *pdev)
goto err_release_reg;
}
disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
- sht15_connection_reset(data);
+ ret = sht15_connection_reset(data);
+ if (ret)
+ goto err_release_reg;
ret = sht15_soft_reset(data);
if (ret)
goto err_release_reg;
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 06ce3c911db9..c35847a1a0a3 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -132,7 +132,7 @@ static struct platform_device *pdev;
*/
static inline u8 IN_TO_REG(unsigned long val)
{
- unsigned long nval = SENSORS_LIMIT(val, 0, 4080);
+ unsigned long nval = clamp_val(val, 0, 4080);
return (nval + 8) / 16;
}
#define IN_FROM_REG(val) ((val) * 16)
@@ -141,7 +141,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
{
if (rpm <= 0)
return 255;
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
static inline int FAN_FROM_REG(u8 val, int div)
@@ -159,7 +159,7 @@ static inline int TEMP_FROM_REG(s8 val)
}
static inline s8 TEMP_TO_REG(int val)
{
- int nval = SENSORS_LIMIT(val, -54120, 157530) ;
+ int nval = clamp_val(val, -54120, 157530) ;
return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830;
}
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index dba0c567e7a1..6d8255ccf07a 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -326,7 +326,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute
/* Preserve fan min */
tmp = 192 - (old_div * (192 - data->fan_preload[nr])
+ new_div / 2) / new_div;
- data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
+ data->fan_preload[nr] = clamp_val(tmp, 0, 191);
smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
data->fan_preload[nr]);
mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index 36a3478d0799..efee4c59239f 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -77,7 +77,7 @@ static inline unsigned int IN_FROM_REG(u8 reg, int n)
static inline u8 IN_TO_REG(unsigned long val, int n)
{
- return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
+ return clamp_val(SCALE(val, 192, nom_mv[n]), 0, 255);
}
/*
@@ -86,7 +86,7 @@ static inline u8 IN_TO_REG(unsigned long val, int n)
*/
static inline s8 TEMP_TO_REG(int val)
{
- return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000);
+ return clamp_val(SCALE(val, 1, 1000), -128000, 127000);
}
static inline int TEMP_FROM_REG(s8 val)
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
index 3c2c48d904e6..4b59eb53b18a 100644
--- a/drivers/hwmon/thmc50.c
+++ b/drivers/hwmon/thmc50.c
@@ -134,7 +134,7 @@ static ssize_t set_analog_out(struct device *dev,
return err;
mutex_lock(&data->update_lock);
- data->analog_out = SENSORS_LIMIT(tmp, 0, 255);
+ data->analog_out = clamp_val(tmp, 0, 255);
i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
data->analog_out);
@@ -187,7 +187,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
+ data->temp_min[nr] = clamp_val(val / 1000, -128, 127);
i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr],
data->temp_min[nr]);
mutex_unlock(&data->update_lock);
@@ -216,7 +216,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
+ data->temp_max[nr] = clamp_val(val / 1000, -128, 127);
i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr],
data->temp_max[nr]);
mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index b10c3d36ccbc..523dd89ba498 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -115,7 +115,7 @@ static ssize_t tmp102_set_temp(struct device *dev,
if (kstrtol(buf, 10, &val) < 0)
return -EINVAL;
- val = SENSORS_LIMIT(val, -256000, 255000);
+ val = clamp_val(val, -256000, 255000);
mutex_lock(&tmp102->lock);
tmp102->temp[sda->index] = val;
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
index e62054875164..c85f6967ccc3 100644
--- a/drivers/hwmon/tmp401.c
+++ b/drivers/hwmon/tmp401.c
@@ -142,10 +142,10 @@ static int tmp401_register_to_temp(u16 reg, u8 config)
static u16 tmp401_temp_to_register(long temp, u8 config)
{
if (config & TMP401_CONFIG_RANGE) {
- temp = SENSORS_LIMIT(temp, -64000, 191000);
+ temp = clamp_val(temp, -64000, 191000);
temp += 64000;
} else
- temp = SENSORS_LIMIT(temp, 0, 127000);
+ temp = clamp_val(temp, 0, 127000);
return (temp * 160 + 312) / 625;
}
@@ -163,10 +163,10 @@ static int tmp401_crit_register_to_temp(u8 reg, u8 config)
static u8 tmp401_crit_temp_to_register(long temp, u8 config)
{
if (config & TMP401_CONFIG_RANGE) {
- temp = SENSORS_LIMIT(temp, -64000, 191000);
+ temp = clamp_val(temp, -64000, 191000);
temp += 64000;
} else
- temp = SENSORS_LIMIT(temp, 0, 127000);
+ temp = clamp_val(temp, 0, 127000);
return (temp + 500) / 1000;
}
@@ -417,14 +417,14 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
return -EINVAL;
if (data->config & TMP401_CONFIG_RANGE)
- val = SENSORS_LIMIT(val, -64000, 191000);
+ val = clamp_val(val, -64000, 191000);
else
- val = SENSORS_LIMIT(val, 0, 127000);
+ val = clamp_val(val, 0, 127000);
mutex_lock(&data->update_lock);
temp = tmp401_crit_register_to_temp(data->temp_crit[index],
data->config);
- val = SENSORS_LIMIT(val, temp - 255000, temp);
+ val = clamp_val(val, temp - 255000, temp);
reg = ((temp - val) + 500) / 1000;
i2c_smbus_write_byte_data(to_i2c_client(dev),
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index e0e14a9f1658..3123b30208c5 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -135,17 +135,14 @@ static inline u8 IN_TO_REG(long val, int inNum)
* for the constants.
*/
if (inNum <= 1)
- return (u8)
- SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255);
+ return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
else if (inNum == 2)
- return (u8)
- SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255);
+ return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
else if (inNum == 3)
- return (u8)
- SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255);
+ return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
else
- return (u8)
- SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255);
+ return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
+ 255);
}
static inline long IN_FROM_REG(u8 val, int inNum)
@@ -175,8 +172,8 @@ static inline u8 FAN_TO_REG(long rpm, int div)
{
if (rpm == 0)
return 0;
- rpm = SENSORS_LIMIT(rpm, 1, 1000000);
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
+ rpm = clamp_val(rpm, 1, 1000000);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 255);
}
#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 751703059fae..dcc62f80f67b 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -158,7 +158,7 @@ struct vt1211_data {
#define IN_FROM_REG(ix, reg) ((reg) < 3 ? 0 : (ix) == 5 ? \
(((reg) - 3) * 15882 + 479) / 958 : \
(((reg) - 3) * 10000 + 479) / 958)
-#define IN_TO_REG(ix, val) (SENSORS_LIMIT((ix) == 5 ? \
+#define IN_TO_REG(ix, val) (clamp_val((ix) == 5 ? \
((val) * 958 + 7941) / 15882 + 3 : \
((val) * 958 + 5000) / 10000 + 3, 0, 255))
@@ -173,7 +173,7 @@ struct vt1211_data {
(ix) == 1 ? (reg) < 51 ? 0 : \
((reg) - 51) * 1000 : \
((253 - (reg)) * 2200 + 105) / 210)
-#define TEMP_TO_REG(ix, val) SENSORS_LIMIT( \
+#define TEMP_TO_REG(ix, val) clamp_val( \
((ix) == 0 ? ((val) + 500) / 1000 : \
(ix) == 1 ? ((val) + 500) / 1000 + 51 : \
253 - ((val) * 210 + 1100) / 2200), 0, 255)
@@ -183,7 +183,7 @@ struct vt1211_data {
#define RPM_FROM_REG(reg, div) (((reg) == 0) || ((reg) == 255) ? 0 : \
1310720 / (reg) / DIV_FROM_REG(div))
#define RPM_TO_REG(val, div) ((val) == 0 ? 255 : \
- SENSORS_LIMIT((1310720 / (val) / \
+ clamp_val((1310720 / (val) / \
DIV_FROM_REG(div)), 1, 254))
/* ---------------------------------------------------------------------
@@ -687,7 +687,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->fan_ctl));
break;
case SHOW_SET_PWM_FREQ:
- val = 135000 / SENSORS_LIMIT(val, 135000 >> 7, 135000);
+ val = 135000 / clamp_val(val, 135000 >> 7, 135000);
/* calculate tmp = log2(val) */
tmp = 0;
for (val >>= 1; val > 0; val >>= 1)
@@ -845,7 +845,7 @@ static ssize_t set_pwm_auto_point_pwm(struct device *dev,
return err;
mutex_lock(&data->update_lock);
- data->pwm_auto_pwm[ix][ap] = SENSORS_LIMIT(val, 0, 255);
+ data->pwm_auto_pwm[ix][ap] = clamp_val(val, 0, 255);
vt1211_write8(data, VT1211_REG_PWM_AUTO_PWM(ix, ap),
data->pwm_auto_pwm[ix][ap]);
mutex_unlock(&data->update_lock);
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index a56355cef184..988a2a796764 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -147,7 +147,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
{
if (rpm == 0)
return 0;
- return SENSORS_LIMIT(1310720 / (rpm * div), 1, 255);
+ return clamp_val(1310720 / (rpm * div), 1, 255);
}
#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div)))
@@ -236,7 +236,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
+ data->in_min[nr] = clamp_val(((val * 958) / 10000) + 3, 0, 255);
vt8231_write_value(data, regvoltmin[nr], data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -256,7 +256,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
+ data->in_max[nr] = clamp_val(((val * 958) / 10000) + 3, 0, 255);
vt8231_write_value(data, regvoltmax[nr], data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -302,8 +302,8 @@ static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
- 0, 255);
+ data->in_min[5] = clamp_val(((val * 958 * 34) / (10000 * 54)) + 3,
+ 0, 255);
vt8231_write_value(data, regvoltmin[5], data->in_min[5]);
mutex_unlock(&data->update_lock);
return count;
@@ -321,8 +321,8 @@ static ssize_t set_in5_max(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
- 0, 255);
+ data->in_max[5] = clamp_val(((val * 958 * 34) / (10000 * 54)) + 3,
+ 0, 255);
vt8231_write_value(data, regvoltmax[5], data->in_max[5]);
mutex_unlock(&data->update_lock);
return count;
@@ -380,7 +380,7 @@ static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
+ data->temp_max[0] = clamp_val((val + 500) / 1000, 0, 255);
vt8231_write_value(data, regtempmax[0], data->temp_max[0]);
mutex_unlock(&data->update_lock);
return count;
@@ -397,7 +397,7 @@ static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
+ data->temp_min[0] = clamp_val((val + 500) / 1000, 0, 255);
vt8231_write_value(data, regtempmin[0], data->temp_min[0]);
mutex_unlock(&data->update_lock);
return count;
@@ -444,7 +444,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
+ data->temp_max[nr] = clamp_val(TEMP_MAXMIN_TO_REG(val), 0, 255);
vt8231_write_value(data, regtempmax[nr], data->temp_max[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -463,7 +463,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
+ data->temp_min[nr] = clamp_val(TEMP_MAXMIN_TO_REG(val), 0, 255);
vt8231_write_value(data, regtempmin[nr], data->temp_min[nr]);
mutex_unlock(&data->update_lock);
return count;
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 0e8ffd6059a0..0a89211c25f6 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -354,8 +354,8 @@ static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
{
- return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
- (msec + 200) / 400), 1, 255);
+ return clamp_val((mode ? (msec + 50) / 100 : (msec + 200) / 400),
+ 1, 255);
}
static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
@@ -414,8 +414,7 @@ static inline long in_from_reg(u8 reg, u8 nr, const u16 *scale_in)
static inline u8 in_to_reg(u32 val, u8 nr, const u16 *scale_in)
{
- return SENSORS_LIMIT(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0,
- 255);
+ return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
}
/*
@@ -1267,7 +1266,7 @@ store_temp_offset(struct device *dev, struct device_attribute *attr,
if (err < 0)
return err;
- val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
mutex_lock(&data->update_lock);
data->temp_offset[nr] = val;
@@ -1435,7 +1434,7 @@ store_pwm(struct device *dev, struct device_attribute *attr,
if (err < 0)
return err;
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
data->pwm[nr] = val;
@@ -1514,7 +1513,7 @@ store_target_temp(struct device *dev, struct device_attribute *attr,
if (err < 0)
return err;
- val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
mutex_lock(&data->update_lock);
data->target_temp[nr] = val;
@@ -1540,7 +1539,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
return err;
/* Limit the temp to 0C - 15C */
- val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
mutex_lock(&data->update_lock);
if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
@@ -1639,7 +1638,7 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
err = kstrtoul(buf, 10, &val); \
if (err < 0) \
return err; \
- val = SENSORS_LIMIT(val, 1, 255); \
+ val = clamp_val(val, 1, 255); \
mutex_lock(&data->update_lock); \
data->reg[nr] = val; \
w83627ehf_write_value(data, data->REG_##REG[nr], val); \
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 81f486520cea..3b9ef2d23452 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -254,16 +254,15 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
* these macros are called: arguments may be evaluated more than once.
* Fixing this is just not worth it.
*/
-#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255))
+#define IN_TO_REG(val) (clamp_val((((val) + 8) / 16), 0, 255))
#define IN_FROM_REG(val) ((val) * 16)
static inline u8 FAN_TO_REG(long rpm, int div)
{
if (rpm == 0)
return 255;
- rpm = SENSORS_LIMIT(rpm, 1, 1000000);
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
- 254);
+ rpm = clamp_val(rpm, 1, 1000000);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
#define TEMP_MIN (-128000)
@@ -275,9 +274,9 @@ static inline u8 FAN_TO_REG(long rpm, int div)
*/
static u8 TEMP_TO_REG(long temp)
{
- int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
- ntemp += (ntemp<0 ? -500 : 500);
- return (u8)(ntemp / 1000);
+ int ntemp = clamp_val(temp, TEMP_MIN, TEMP_MAX);
+ ntemp += (ntemp < 0 ? -500 : 500);
+ return (u8)(ntemp / 1000);
}
static int TEMP_FROM_REG(u8 reg)
@@ -287,7 +286,7 @@ static int TEMP_FROM_REG(u8 reg)
#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
-#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
+#define PWM_TO_REG(val) (clamp_val((val), 0, 255))
static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
{
@@ -342,7 +341,7 @@ static inline u8 pwm_freq_to_reg(unsigned long val)
static inline u8 DIV_TO_REG(long val)
{
int i;
- val = SENSORS_LIMIT(val, 1, 128) >> 1;
+ val = clamp_val(val, 1, 128) >> 1;
for (i = 0; i < 7; i++) {
if (val == 0)
break;
@@ -614,8 +613,7 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
/* use VRM9 calculation */
data->in_min[0] =
- SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
- 255);
+ clamp_val(((val * 100) - 70000 + 244) / 488, 0, 255);
else
/* use VRM8 (standard) calculation */
data->in_min[0] = IN_TO_REG(val);
@@ -644,8 +642,7 @@ static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *a
/* use VRM9 calculation */
data->in_max[0] =
- SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
- 255);
+ clamp_val(((val * 100) - 70000 + 244) / 488, 0, 255);
else
/* use VRM8 (standard) calculation */
data->in_max[0] = IN_TO_REG(val);
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index 93bd28639595..aeec5b1d81c9 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -159,7 +159,7 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
#define W83781D_DEFAULT_BETA 3435
/* Conversions */
-#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
+#define IN_TO_REG(val) clamp_val(((val) + 8) / 16, 0, 255)
#define IN_FROM_REG(val) ((val) * 16)
static inline u8
@@ -167,8 +167,8 @@ FAN_TO_REG(long rpm, int div)
{
if (rpm == 0)
return 255;
- rpm = SENSORS_LIMIT(rpm, 1, 1000000);
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+ rpm = clamp_val(rpm, 1, 1000000);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
static inline long
@@ -181,7 +181,7 @@ FAN_FROM_REG(u8 val, int div)
return 1350000 / (val * div);
}
-#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)
+#define TEMP_TO_REG(val) clamp_val((val) / 1000, -127, 128)
#define TEMP_FROM_REG(val) ((val) * 1000)
#define BEEP_MASK_FROM_REG(val, type) ((type) == as99127f ? \
@@ -195,9 +195,8 @@ static inline u8
DIV_TO_REG(long val, enum chips type)
{
int i;
- val = SENSORS_LIMIT(val, 1,
- ((type == w83781d
- || type == as99127f) ? 8 : 128)) >> 1;
+ val = clamp_val(val, 1,
+ ((type == w83781d || type == as99127f) ? 8 : 128)) >> 1;
for (i = 0; i < 7; i++) {
if (val == 0)
break;
@@ -443,7 +442,7 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr,
err = kstrtoul(buf, 10, &val);
if (err)
return err;
- data->vrm = SENSORS_LIMIT(val, 0, 255);
+ data->vrm = clamp_val(val, 0, 255);
return count;
}
@@ -730,7 +729,7 @@ store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
return err;
mutex_lock(&data->update_lock);
- data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+ data->pwm[nr] = clamp_val(val, 0, 255);
w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
mutex_unlock(&data->update_lock);
return count;
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index ed397c645198..38dddddf8875 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -220,15 +220,15 @@ static inline int w83791d_write(struct i2c_client *client, u8 reg, u8 value)
* in mV as would be measured on the chip input pin, need to just
* multiply/divide by 16 to translate from/to register values.
*/
-#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8) / 16), 0, 255))
+#define IN_TO_REG(val) (clamp_val((((val) + 8) / 16), 0, 255))
#define IN_FROM_REG(val) ((val) * 16)
static u8 fan_to_reg(long rpm, int div)
{
if (rpm == 0)
return 255;
- rpm = SENSORS_LIMIT(rpm, 1, 1000000);
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+ rpm = clamp_val(rpm, 1, 1000000);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \
@@ -273,7 +273,7 @@ static u8 div_to_reg(int nr, long val)
int i;
/* fan divisors max out at 128 */
- val = SENSORS_LIMIT(val, 1, 128) >> 1;
+ val = clamp_val(val, 1, 128) >> 1;
for (i = 0; i < 7; i++) {
if (val == 0)
break;
@@ -747,7 +747,7 @@ static ssize_t store_pwm(struct device *dev, struct device_attribute *attr,
return -EINVAL;
mutex_lock(&data->update_lock);
- data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+ data->pwm[nr] = clamp_val(val, 0, 255);
w83791d_write(client, W83791D_REG_PWM[nr], data->pwm[nr]);
mutex_unlock(&data->update_lock);
return count;
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 301942d08453..5cb83ddf2cc6 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -235,8 +235,8 @@ FAN_TO_REG(long rpm, int div)
{
if (rpm == 0)
return 255;
- rpm = SENSORS_LIMIT(rpm, 1, 1000000);
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+ rpm = clamp_val(rpm, 1, 1000000);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \
@@ -244,16 +244,15 @@ FAN_TO_REG(long rpm, int div)
1350000 / ((val) * (div))))
/* for temp1 */
-#define TEMP1_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
- : (val)) / 1000, 0, 0xff))
+#define TEMP1_TO_REG(val) (clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \
+ : (val)) / 1000, 0, 0xff))
#define TEMP1_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
/* for temp2 and temp3, because they need additional resolution */
#define TEMP_ADD_FROM_REG(val1, val2) \
((((val1) & 0x80 ? (val1)-0x100 \
: (val1)) * 1000) + ((val2 & 0x80) ? 500 : 0))
#define TEMP_ADD_TO_REG_HIGH(val) \
- (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
- : (val)) / 1000, 0, 0xff))
+ (clamp_val(((val) < 0 ? (val) + 0x100 * 1000 : (val)) / 1000, 0, 0xff))
#define TEMP_ADD_TO_REG_LOW(val) ((val%1000) ? 0x80 : 0x00)
#define DIV_FROM_REG(val) (1 << (val))
@@ -262,7 +261,7 @@ static inline u8
DIV_TO_REG(long val)
{
int i;
- val = SENSORS_LIMIT(val, 1, 128) >> 1;
+ val = clamp_val(val, 1, 128) >> 1;
for (i = 0; i < 7; i++) {
if (val == 0)
break;
@@ -397,7 +396,7 @@ static ssize_t store_in_##reg(struct device *dev, \
if (err) \
return err; \
mutex_lock(&data->update_lock); \
- data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val) / 4, 0, 255); \
+ data->in_##reg[nr] = clamp_val(IN_TO_REG(nr, val) / 4, 0, 255); \
w83792d_write_value(client, W83792D_REG_IN_##REG[nr], \
data->in_##reg[nr]); \
mutex_unlock(&data->update_lock); \
@@ -645,7 +644,7 @@ store_pwm(struct device *dev, struct device_attribute *attr,
err = kstrtoul(buf, 10, &val);
if (err)
return err;
- val = SENSORS_LIMIT(val, 0, 255) >> 4;
+ val = clamp_val(val, 0, 255) >> 4;
mutex_lock(&data->update_lock);
val |= w83792d_read_value(client, W83792D_REG_PWM[nr]) & 0xf0;
@@ -799,7 +798,7 @@ store_thermal_cruise(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
target_mask = w83792d_read_value(client,
W83792D_REG_THERMAL[nr]) & 0x80;
- data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255);
+ data->thermal_cruise[nr] = clamp_val(target_tmp, 0, 255);
w83792d_write_value(client, W83792D_REG_THERMAL[nr],
(data->thermal_cruise[nr]) | target_mask);
mutex_unlock(&data->update_lock);
@@ -837,7 +836,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
tol_mask = w83792d_read_value(client,
W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0);
- tol_tmp = SENSORS_LIMIT(val, 0, 15);
+ tol_tmp = clamp_val(val, 0, 15);
tol_tmp &= 0x0f;
data->tolerance[nr] = tol_tmp;
if (nr == 1)
@@ -881,7 +880,7 @@ store_sf2_point(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127);
+ data->sf2_points[index][nr] = clamp_val(val, 0, 127);
mask_tmp = w83792d_read_value(client,
W83792D_REG_POINTS[index][nr]) & 0x80;
w83792d_write_value(client, W83792D_REG_POINTS[index][nr],
@@ -923,7 +922,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
return err;
mutex_lock(&data->update_lock);
- data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15);
+ data->sf2_levels[index][nr] = clamp_val((val * 15) / 100, 0, 15);
mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr])
& ((nr == 3) ? 0xf0 : 0x0f);
if (nr == 3)
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 99799fd1d917..660427520c53 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -191,7 +191,7 @@ static inline u16 FAN_TO_REG(long rpm)
{
if (rpm <= 0)
return 0x0fff;
- return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
+ return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
}
static inline unsigned long TIME_FROM_REG(u8 reg)
@@ -201,7 +201,7 @@ static inline unsigned long TIME_FROM_REG(u8 reg)
static inline u8 TIME_TO_REG(unsigned long val)
{
- return SENSORS_LIMIT((val + 50) / 100, 0, 0xff);
+ return clamp_val((val + 50) / 100, 0, 0xff);
}
static inline long TEMP_FROM_REG(s8 reg)
@@ -211,7 +211,7 @@ static inline long TEMP_FROM_REG(s8 reg)
static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
{
- return SENSORS_LIMIT((val + (val < 0 ? -500 : 500)) / 1000, min, max);
+ return clamp_val((val + (val < 0 ? -500 : 500)) / 1000, min, max);
}
struct w83793_data {
@@ -558,7 +558,7 @@ store_pwm(struct device *dev, struct device_attribute *attr,
w83793_write_value(client, W83793_REG_PWM_STOP_TIME(index),
val);
} else {
- val = SENSORS_LIMIT(val, 0, 0xff) >> 2;
+ val = clamp_val(val, 0, 0xff) >> 2;
data->pwm[index][nr] =
w83793_read_value(client, W83793_REG_PWM(index, nr)) & 0xc0;
data->pwm[index][nr] |= val;
@@ -739,7 +739,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
if (nr == SETUP_PWM_DEFAULT) {
data->pwm_default =
w83793_read_value(client, W83793_REG_PWM_DEFAULT) & 0xc0;
- data->pwm_default |= SENSORS_LIMIT(val, 0, 0xff) >> 2;
+ data->pwm_default |= clamp_val(val, 0, 0xff) >> 2;
w83793_write_value(client, W83793_REG_PWM_DEFAULT,
data->pwm_default);
} else if (nr == SETUP_PWM_UPTIME) {
@@ -838,7 +838,7 @@ store_sf_ctrl(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
if (nr == TEMP_FAN_MAP) {
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
w83793_write_value(client, W83793_REG_TEMP_FAN_MAP(index), val);
data->temp_fan_map[index] = val;
} else if (nr == TEMP_PWM_ENABLE) {
@@ -907,7 +907,7 @@ store_sf2_pwm(struct device *dev, struct device_attribute *attr,
err = kstrtoul(buf, 10, &val);
if (err)
return err;
- val = SENSORS_LIMIT(val, 0, 0xff) >> 2;
+ val = clamp_val(val, 0, 0xff) >> 2;
mutex_lock(&data->update_lock);
data->sf2_pwm[index][nr] =
@@ -1003,9 +1003,9 @@ store_in(struct device *dev, struct device_attribute *attr,
/* fix the limit values of 5VDD and 5VSB to ALARM mechanism */
if (nr == 1 || nr == 2)
val -= scale_in_add[index] / scale_in[index];
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
} else {
- val = SENSORS_LIMIT(val, 0, 0x3FF);
+ val = clamp_val(val, 0, 0x3FF);
data->in_low_bits[nr] =
w83793_read_value(client, W83793_REG_IN_LOW_BITS[nr]);
data->in_low_bits[nr] &= ~(0x03 << (2 * index));
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c
index 55a4f4894531..e226096148eb 100644
--- a/drivers/hwmon/w83795.c
+++ b/drivers/hwmon/w83795.c
@@ -262,7 +262,7 @@ static inline u16 fan_to_reg(long rpm)
{
if (rpm <= 0)
return 0x0fff;
- return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
+ return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
}
static inline unsigned long time_from_reg(u8 reg)
@@ -272,7 +272,7 @@ static inline unsigned long time_from_reg(u8 reg)
static inline u8 time_to_reg(unsigned long val)
{
- return SENSORS_LIMIT((val + 50) / 100, 0, 0xff);
+ return clamp_val((val + 50) / 100, 0, 0xff);
}
static inline long temp_from_reg(s8 reg)
@@ -282,7 +282,7 @@ static inline long temp_from_reg(s8 reg)
static inline s8 temp_to_reg(long val, s8 min, s8 max)
{
- return SENSORS_LIMIT(val / 1000, min, max);
+ return clamp_val(val / 1000, min, max);
}
static const u16 pwm_freq_cksel0[16] = {
@@ -319,7 +319,7 @@ static u8 pwm_freq_to_reg(unsigned long val, u16 clkin)
/* Best fit for cksel = 1 */
base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256);
- reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128);
+ reg1 = clamp_val(DIV_ROUND_CLOSEST(base_clock, val), 1, 128);
best1 = base_clock / reg1;
reg1 = 0x80 | (reg1 - 1);
@@ -889,7 +889,7 @@ store_pwm(struct device *dev, struct device_attribute *attr,
val = pwm_freq_to_reg(val, data->clkin);
break;
default:
- val = SENSORS_LIMIT(val, 0, 0xff);
+ val = clamp_val(val, 0, 0xff);
break;
}
w83795_write(client, W83795_REG_PWM(index, nr), val);
@@ -1126,7 +1126,7 @@ store_temp_pwm_enable(struct device *dev, struct device_attribute *attr,
break;
case TEMP_PWM_FAN_MAP:
mutex_lock(&data->update_lock);
- tmp = SENSORS_LIMIT(tmp, 0, 0xff);
+ tmp = clamp_val(tmp, 0, 0xff);
w83795_write(client, W83795_REG_TFMR(index), tmp);
data->pwm_tfmr[index] = tmp;
mutex_unlock(&data->update_lock);
@@ -1177,13 +1177,13 @@ store_fanin(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
switch (nr) {
case FANIN_TARGET:
- val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff));
+ val = fan_to_reg(clamp_val(val, 0, 0xfff));
w83795_write(client, W83795_REG_FTSH(index), val >> 4);
w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0);
data->target_speed[index] = val;
break;
case FANIN_TOL:
- val = SENSORS_LIMIT(val, 0, 0x3f);
+ val = clamp_val(val, 0, 0x3f);
w83795_write(client, W83795_REG_TFTS, val);
data->tol_speed = val;
break;
@@ -1227,22 +1227,22 @@ store_temp_pwm(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
switch (nr) {
case TEMP_PWM_TTTI:
- val = SENSORS_LIMIT(val, 0, 0x7f);
+ val = clamp_val(val, 0, 0x7f);
w83795_write(client, W83795_REG_TTTI(index), val);
break;
case TEMP_PWM_CTFS:
- val = SENSORS_LIMIT(val, 0, 0x7f);
+ val = clamp_val(val, 0, 0x7f);
w83795_write(client, W83795_REG_CTFS(index), val);
break;
case TEMP_PWM_HCT:
- val = SENSORS_LIMIT(val, 0, 0x0f);
+ val = clamp_val(val, 0, 0x0f);
tmp = w83795_read(client, W83795_REG_HT(index));
tmp &= 0x0f;
tmp |= (val << 4) & 0xf0;
w83795_write(client, W83795_REG_HT(index), tmp);
break;
case TEMP_PWM_HOT:
- val = SENSORS_LIMIT(val, 0, 0x0f);
+ val = clamp_val(val, 0, 0x0f);
tmp = w83795_read(client, W83795_REG_HT(index));
tmp &= 0xf0;
tmp |= val & 0x0f;
@@ -1541,7 +1541,7 @@ store_in(struct device *dev, struct device_attribute *attr,
if ((index >= 17) &&
!((data->has_gain >> (index - 17)) & 1))
val /= 8;
- val = SENSORS_LIMIT(val, 0, 0x3FF);
+ val = clamp_val(val, 0, 0x3FF);
mutex_lock(&data->update_lock);
lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
@@ -1596,7 +1596,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
switch (nr) {
case SETUP_PWM_DEFAULT:
- val = SENSORS_LIMIT(val, 0, 0xff);
+ val = clamp_val(val, 0, 0xff);
break;
case SETUP_PWM_UPTIME:
case SETUP_PWM_DOWNTIME:
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
index 79710bcac2f7..edb06cda5a68 100644
--- a/drivers/hwmon/w83l786ng.c
+++ b/drivers/hwmon/w83l786ng.c
@@ -86,8 +86,8 @@ FAN_TO_REG(long rpm, int div)
{
if (rpm == 0)
return 255;
- rpm = SENSORS_LIMIT(rpm, 1, 1000000);
- return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+ rpm = clamp_val(rpm, 1, 1000000);
+ return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \
@@ -95,9 +95,8 @@ FAN_TO_REG(long rpm, int div)
1350000 / ((val) * (div))))
/* for temp */
-#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? \
- (val) + 0x100 * 1000 \
- : (val)) / 1000, 0, 0xff))
+#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \
+ : (val)) / 1000, 0, 0xff))
#define TEMP_FROM_REG(val) (((val) & 0x80 ? \
(val) - 0x100 : (val)) * 1000)
@@ -106,7 +105,7 @@ FAN_TO_REG(long rpm, int div)
* in mV as would be measured on the chip input pin, need to just
* multiply/divide by 8 to translate from/to register values.
*/
-#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 4) / 8), 0, 255))
+#define IN_TO_REG(val) (clamp_val((((val) + 4) / 8), 0, 255))
#define IN_FROM_REG(val) ((val) * 8)
#define DIV_FROM_REG(val) (1 << (val))
@@ -115,7 +114,7 @@ static inline u8
DIV_TO_REG(long val)
{
int i;
- val = SENSORS_LIMIT(val, 1, 128) >> 1;
+ val = clamp_val(val, 1, 128) >> 1;
for (i = 0; i < 7; i++) {
if (val == 0)
break;
@@ -481,7 +480,7 @@ store_pwm(struct device *dev, struct device_attribute *attr,
err = kstrtoul(buf, 10, &val);
if (err)
return err;
- val = SENSORS_LIMIT(val, 0, 255);
+ val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
data->pwm[nr] = val;
@@ -564,7 +563,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
tol_mask = w83l786ng_read_value(client,
W83L786NG_REG_TOLERANCE) & ((nr == 1) ? 0x0f : 0xf0);
- tol_tmp = SENSORS_LIMIT(val, 0, 15);
+ tol_tmp = clamp_val(val, 0, 15);
tol_tmp &= 0x0f;
data->tolerance[nr] = tol_tmp;
if (nr == 1)
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 2f8c76becc6b..46cde098c11c 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -89,7 +89,7 @@ source drivers/i2c/busses/Kconfig
config I2C_STUB
tristate "I2C/SMBus Test Stub"
- depends on EXPERIMENTAL && m
+ depends on m
default 'n'
help
This module may be useful to developers of SMBus client drivers,
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index bdca5111eb9d..8bb810e1900b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -22,7 +22,7 @@ config I2C_ALI1535
config I2C_ALI1563
tristate "ALI 1563"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
If you say yes to this option, support will be included for the SMB
Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB
@@ -56,7 +56,7 @@ config I2C_AMD756
config I2C_AMD756_S4882
tristate "SMBus multiplexing on the Tyan S4882"
- depends on I2C_AMD756 && X86 && EXPERIMENTAL
+ depends on I2C_AMD756 && X86
help
Enabling this option will add specific SMBus support for the Tyan
S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
@@ -164,7 +164,7 @@ config I2C_NFORCE2
config I2C_NFORCE2_S4985
tristate "SMBus multiplexing on the Tyan S4985"
- depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
+ depends on I2C_NFORCE2 && X86
help
Enabling this option will add specific SMBus support for the Tyan
S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
@@ -215,7 +215,7 @@ config I2C_SIS96X
config I2C_VIA
tristate "VIA VT82C586B"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the VIA
@@ -267,7 +267,7 @@ comment "Mac SMBus host controller drivers"
config I2C_HYDRA
tristate "CHRP Apple Hydra Mac I/O I2C interface"
- depends on PCI && PPC_CHRP && EXPERIMENTAL
+ depends on PCI && PPC_CHRP
select I2C_ALGOBIT
help
This supports the use of the I2C interface in the Apple Hydra Mac
@@ -293,7 +293,7 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
config I2C_AT91
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
- depends on ARCH_AT91 && EXPERIMENTAL
+ depends on ARCH_AT91
help
This supports the use of the I2C interface on Atmel AT91
processors.
@@ -519,7 +519,6 @@ config I2C_NUC900
config I2C_OCORES
tristate "OpenCores I2C Controller"
- depends on EXPERIMENTAL
help
If you say yes to this option, support will be included for the
OpenCores I2C controller. For details see
@@ -712,7 +711,7 @@ config I2C_OCTEON
config I2C_XILINX
tristate "Xilinx I2C Controller"
- depends on EXPERIMENTAL && HAS_IOMEM
+ depends on HAS_IOMEM
help
If you say yes to this option, support will be included for the
Xilinx I2C controller.
@@ -803,7 +802,7 @@ config I2C_PARPORT_LIGHT
config I2C_TAOS_EVM
tristate "TAOS evaluation module"
- depends on EXPERIMENTAL
+ depends on TTY
select SERIO
select SERIO_SERPORT
default n
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 2bfc04d0a1b1..ebc224154695 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -723,9 +723,9 @@ static int at91_twi_probe(struct platform_device *pdev)
if (!dev->pdata)
return -ENODEV;
- dev->base = devm_request_and_ioremap(&pdev->dev, mem);
- if (!dev->base)
- return -EBUSY;
+ dev->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(dev->base))
+ return PTR_ERR(dev->base);
dev->irq = platform_get_irq(pdev, 0);
if (dev->irq < 0)
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index b9734747d610..a71ece63e917 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -511,9 +511,9 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
return -ENOENT;
}
- base = devm_request_and_ioremap(&pdev->dev, res);
- if (!base)
- return -EBUSY;
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
i2c_imx = devm_kzalloc(&pdev->dev, sizeof(struct imx_i2c_struct),
GFP_KERNEL);
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index a873d0ad1acb..a337d08a392d 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -12,6 +12,7 @@
* kind, whether express or implied.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -364,9 +365,9 @@ static int ocores_i2c_probe(struct platform_device *pdev)
if (!i2c)
return -ENOMEM;
- i2c->base = devm_request_and_ioremap(&pdev->dev, res);
- if (!i2c->base)
- return -EADDRNOTAVAIL;
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
pdata = pdev->dev.platform_data;
if (pdata) {
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 4cc2f0528c88..3ee188679cf1 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1103,11 +1103,9 @@ omap_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
}
- dev->base = devm_request_and_ioremap(&pdev->dev, mem);
- if (!dev->base) {
- dev_err(&pdev->dev, "I2C region already claimed\n");
- return -ENOMEM;
- }
+ dev->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(dev->base))
+ return PTR_ERR(dev->base);
match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev);
if (match) {
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 9bd4d73d29e3..4ba4a95b6b26 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -642,11 +642,9 @@ static int rcar_i2c_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- priv->io = devm_request_and_ioremap(dev, res);
- if (!priv->io) {
- dev_err(dev, "cannot ioremap\n");
- return -ENODEV;
- }
+ priv->io = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->io))
+ return PTR_ERR(priv->io);
priv->irq = platform_get_irq(pdev, 0);
init_waitqueue_head(&priv->wait);
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index a290d089ceaf..c807a6d14f0c 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -1042,11 +1042,10 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
goto err_clk;
}
- i2c->regs = devm_request_and_ioremap(&pdev->dev, res);
+ i2c->regs = devm_ioremap_resource(&pdev->dev, res);
- if (i2c->regs == NULL) {
- dev_err(&pdev->dev, "cannot map IO\n");
- ret = -ENXIO;
+ if (IS_ERR(i2c->regs)) {
+ ret = PTR_ERR(i2c->regs);
goto err_clk;
}
diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
index 6aafa3d88ff0..c447e8d40b78 100644
--- a/drivers/i2c/busses/i2c-scmi.c
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -406,7 +406,7 @@ err:
return -EIO;
}
-static int acpi_smbus_cmi_remove(struct acpi_device *device, int type)
+static int acpi_smbus_cmi_remove(struct acpi_device *device)
{
struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index e03381aee34f..5a7ad240bd26 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -309,10 +309,9 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
goto out;
}
- siic->base = devm_request_and_ioremap(&pdev->dev, mem_res);
- if (siic->base == NULL) {
- dev_err(&pdev->dev, "IO remap failed!\n");
- err = -ENOMEM;
+ siic->base = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(siic->base)) {
+ err = PTR_ERR(siic->base);
goto out;
}
diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c
index 580a0c04cb42..60195b590637 100644
--- a/drivers/i2c/busses/i2c-stu300.c
+++ b/drivers/i2c/busses/i2c-stu300.c
@@ -888,11 +888,11 @@ stu300_probe(struct platform_device *pdev)
if (!res)
return -ENOENT;
- dev->virtbase = devm_request_and_ioremap(&pdev->dev, res);
+ dev->virtbase = devm_ioremap_resource(&pdev->dev, res);
dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual "
"base %p\n", bus_nr, dev->virtbase);
- if (!dev->virtbase)
- return -ENOMEM;
+ if (IS_ERR(dev->virtbase))
+ return PTR_ERR(dev->virtbase);
dev->irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(&pdev->dev, dev->irq, stu300_irh, 0, NAME, dev);
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 7b38877ffec1..f0d9923323ea 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -29,11 +29,10 @@
#include <linux/of_i2c.h>
#include <linux/of_device.h>
#include <linux/module.h>
+#include <linux/clk/tegra.h>
#include <asm/unaligned.h>
-#include <mach/clk.h>
-
#define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000))
#define BYTES_PER_FIFO_WORD 4
@@ -669,11 +668,9 @@ static int tegra_i2c_probe(struct platform_device *pdev)
return -EINVAL;
}
- base = devm_request_and_ioremap(&pdev->dev, res);
- if (!base) {
- dev_err(&pdev->dev, "Cannot request/ioremap I2C registers\n");
- return -EADDRNOTAVAIL;
- }
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c
index a005265461da..93f029e98c0d 100644
--- a/drivers/i2c/busses/i2c-xlr.c
+++ b/drivers/i2c/busses/i2c-xlr.c
@@ -7,6 +7,7 @@
* warranty of any kind, whether express or implied.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -225,11 +226,9 @@ static int xlr_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->iobase = devm_request_and_ioremap(&pdev->dev, res);
- if (!priv->iobase) {
- dev_err(&pdev->dev, "devm_request_and_ioremap failed\n");
- return -EBUSY;
- }
+ priv->iobase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->iobase))
+ return PTR_ERR(priv->iobase);
priv->adap.dev.parent = &pdev->dev;
priv->adap.owner = THIS_MODULE;
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index a0edd9854218..0be5b83c08fa 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -19,7 +19,6 @@ config I2C_MUX_GPIO
config I2C_MUX_PCA9541
tristate "NXP PCA9541 I2C Master Selector"
- depends on EXPERIMENTAL
help
If you say yes here you get support for the NXP PCA9541
I2C Master Selector.
@@ -29,7 +28,6 @@ config I2C_MUX_PCA9541
config I2C_MUX_PCA954x
tristate "Philips PCA954x I2C Mux/switches"
- depends on EXPERIMENTAL
help
If you say yes here you get support for the Philips PCA954x
I2C mux/switch devices.
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 5a26584934ca..02906ca99b41 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -322,8 +322,7 @@ config BLK_DEV_GENERIC
which otherwise might not be supported.
config BLK_DEV_OPTI621
- tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "OPTi 82C621 chipset enhanced support"
select BLK_DEV_IDEPCI
help
This is a driver for the OPTi 82C621 EIDE controller.
@@ -417,7 +416,6 @@ config BLK_DEV_CY82C693
config BLK_DEV_CS5520
tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
- depends on EXPERIMENTAL
select BLK_DEV_IDEDMA_PCI
help
Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
@@ -702,11 +700,6 @@ config BLK_DEV_IDE_TX4939
depends on SOC_TX4939
select BLK_DEV_IDEDMA_SFF
-config BLK_DEV_IDE_AT91
- tristate "Atmel AT91 (SAM9, CAP9, AT572D940HF) IDE support"
- depends on ARM && ARCH_AT91 && !ARCH_AT91RM9200 && !ARCH_AT91X40
- select IDE_TIMINGS
-
config BLK_DEV_IDE_ICSIDE
tristate "ICS IDE interface support"
depends on ARM && ARCH_ACORN
@@ -761,8 +754,8 @@ config BLK_DEV_GAYLE
use Gayle IDE interfaces on the Zorro expansion bus.
config BLK_DEV_BUDDHA
- tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
- depends on ZORRO && EXPERIMENTAL
+ tristate "Buddha/Catweasel/X-Surf IDE interface support"
+ depends on ZORRO
help
This is the IDE driver for the IDE interfaces on the Buddha, Catweasel
and X-Surf expansion boards. It supports up to two interfaces on the
diff --git a/drivers/idle/Kconfig b/drivers/idle/Kconfig
index 8489eb58a52c..4732dfc15447 100644
--- a/drivers/idle/Kconfig
+++ b/drivers/idle/Kconfig
@@ -18,7 +18,6 @@ config I7300_IDLE_IOAT_CHANNEL
config I7300_IDLE
tristate "Intel chipset idle memory power saving driver"
select I7300_IDLE_IOAT_CHANNEL
- depends on EXPERIMENTAL
help
Enable memory power savings when idle with certain Intel server
chipsets. The chipset must have I/O AT support, such as the
diff --git a/drivers/idle/i7300_idle.c b/drivers/idle/i7300_idle.c
index fa080ebd568f..ffeebc7e9f1c 100644
--- a/drivers/idle/i7300_idle.c
+++ b/drivers/idle/i7300_idle.c
@@ -75,7 +75,7 @@ static unsigned long past_skip;
static struct pci_dev *fbd_dev;
-static spinlock_t i7300_idle_lock;
+static raw_spinlock_t i7300_idle_lock;
static int i7300_idle_active;
static u8 i7300_idle_thrtctl_saved;
@@ -457,7 +457,7 @@ static int i7300_idle_notifier(struct notifier_block *nb, unsigned long val,
idle_begin_time = ktime_get();
}
- spin_lock_irqsave(&i7300_idle_lock, flags);
+ raw_spin_lock_irqsave(&i7300_idle_lock, flags);
if (val == IDLE_START) {
cpumask_set_cpu(smp_processor_id(), idle_cpumask);
@@ -506,7 +506,7 @@ static int i7300_idle_notifier(struct notifier_block *nb, unsigned long val,
}
}
end:
- spin_unlock_irqrestore(&i7300_idle_lock, flags);
+ raw_spin_unlock_irqrestore(&i7300_idle_lock, flags);
return 0;
}
@@ -548,7 +548,7 @@ struct debugfs_file_info {
static int __init i7300_idle_init(void)
{
- spin_lock_init(&i7300_idle_lock);
+ raw_spin_lock_init(&i7300_idle_lock);
total_us = 0;
if (i7300_idle_platform_probe(&fbd_dev, &ioat_dev, forceload))
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 2df9414a72f7..5d6675013864 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -74,7 +74,7 @@ static struct cpuidle_driver intel_idle_driver = {
.en_core_tk_irqen = 1,
};
/* intel_idle.max_cstate=0 disables driver */
-static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1;
+static int max_cstate = CPUIDLE_STATE_MAX - 1;
static unsigned int mwait_substates;
@@ -90,6 +90,7 @@ struct idle_cpu {
* Indicate which enable bits to clear here.
*/
unsigned long auto_demotion_disable_flags;
+ bool disable_promotion_to_c1e;
};
static const struct idle_cpu *icpu;
@@ -109,162 +110,206 @@ static struct cpuidle_state *cpuidle_state_table;
#define CPUIDLE_FLAG_TLB_FLUSHED 0x10000
/*
+ * MWAIT takes an 8-bit "hint" in EAX "suggesting"
+ * the C-state (top nibble) and sub-state (bottom nibble)
+ * 0x00 means "MWAIT(C1)", 0x10 means "MWAIT(C2)" etc.
+ *
+ * We store the hint at the top of our "flags" for each state.
+ */
+#define flg2MWAIT(flags) (((flags) >> 24) & 0xFF)
+#define MWAIT2flg(eax) ((eax & 0xFF) << 24)
+
+/*
* States are indexed by the cstate number,
* which is also the index into the MWAIT hint array.
* Thus C0 is a dummy.
*/
-static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
- { /* MWAIT C0 */ },
- { /* MWAIT C1 */
+static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = {
+ {
.name = "C1-NHM",
.desc = "MWAIT 0x00",
- .flags = CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 3,
.target_residency = 6,
.enter = &intel_idle },
- { /* MWAIT C2 */
+ {
+ .name = "C1E-NHM",
+ .desc = "MWAIT 0x01",
+ .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 10,
+ .target_residency = 20,
+ .enter = &intel_idle },
+ {
.name = "C3-NHM",
.desc = "MWAIT 0x10",
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 20,
.target_residency = 80,
.enter = &intel_idle },
- { /* MWAIT C3 */
+ {
.name = "C6-NHM",
.desc = "MWAIT 0x20",
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 200,
.target_residency = 800,
.enter = &intel_idle },
+ {
+ .enter = NULL }
};
-static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
- { /* MWAIT C0 */ },
- { /* MWAIT C1 */
+static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = {
+ {
.name = "C1-SNB",
.desc = "MWAIT 0x00",
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .exit_latency = 1,
- .target_residency = 1,
+ .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 2,
+ .target_residency = 2,
.enter = &intel_idle },
- { /* MWAIT C2 */
+ {
+ .name = "C1E-SNB",
+ .desc = "MWAIT 0x01",
+ .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 10,
+ .target_residency = 20,
+ .enter = &intel_idle },
+ {
.name = "C3-SNB",
.desc = "MWAIT 0x10",
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 80,
.target_residency = 211,
.enter = &intel_idle },
- { /* MWAIT C3 */
+ {
.name = "C6-SNB",
.desc = "MWAIT 0x20",
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 104,
.target_residency = 345,
.enter = &intel_idle },
- { /* MWAIT C4 */
+ {
.name = "C7-SNB",
.desc = "MWAIT 0x30",
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 109,
.target_residency = 345,
.enter = &intel_idle },
+ {
+ .enter = NULL }
};
-static struct cpuidle_state ivb_cstates[MWAIT_MAX_NUM_CSTATES] = {
- { /* MWAIT C0 */ },
- { /* MWAIT C1 */
+static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = {
+ {
.name = "C1-IVB",
.desc = "MWAIT 0x00",
- .flags = CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 1,
.target_residency = 1,
.enter = &intel_idle },
- { /* MWAIT C2 */
+ {
+ .name = "C1E-IVB",
+ .desc = "MWAIT 0x01",
+ .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 10,
+ .target_residency = 20,
+ .enter = &intel_idle },
+ {
.name = "C3-IVB",
.desc = "MWAIT 0x10",
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 59,
.target_residency = 156,
.enter = &intel_idle },
- { /* MWAIT C3 */
+ {
.name = "C6-IVB",
.desc = "MWAIT 0x20",
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 80,
.target_residency = 300,
.enter = &intel_idle },
- { /* MWAIT C4 */
+ {
.name = "C7-IVB",
.desc = "MWAIT 0x30",
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 87,
.target_residency = 300,
.enter = &intel_idle },
+ {
+ .enter = NULL }
};
-static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
- { /* MWAIT C0 */ },
- { /* MWAIT C1 */
- .name = "C1-ATM",
+static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = {
+ {
+ .name = "C1-HSW",
.desc = "MWAIT 0x00",
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .exit_latency = 1,
- .target_residency = 4,
+ .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 2,
+ .target_residency = 2,
+ .enter = &intel_idle },
+ {
+ .name = "C1E-HSW",
+ .desc = "MWAIT 0x01",
+ .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 10,
+ .target_residency = 20,
+ .enter = &intel_idle },
+ {
+ .name = "C3-HSW",
+ .desc = "MWAIT 0x10",
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .exit_latency = 33,
+ .target_residency = 100,
+ .enter = &intel_idle },
+ {
+ .name = "C6-HSW",
+ .desc = "MWAIT 0x20",
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .exit_latency = 133,
+ .target_residency = 400,
+ .enter = &intel_idle },
+ {
+ .name = "C7s-HSW",
+ .desc = "MWAIT 0x32",
+ .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .exit_latency = 166,
+ .target_residency = 500,
+ .enter = &intel_idle },
+ {
+ .enter = NULL }
+};
+
+static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = {
+ {
+ .name = "C1E-ATM",
+ .desc = "MWAIT 0x00",
+ .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 10,
+ .target_residency = 20,
.enter = &intel_idle },
- { /* MWAIT C2 */
+ {
.name = "C2-ATM",
.desc = "MWAIT 0x10",
- .flags = CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 20,
.target_residency = 80,
.enter = &intel_idle },
- { /* MWAIT C3 */ },
- { /* MWAIT C4 */
+ {
.name = "C4-ATM",
.desc = "MWAIT 0x30",
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 100,
.target_residency = 400,
.enter = &intel_idle },
- { /* MWAIT C5 */ },
- { /* MWAIT C6 */
+ {
.name = "C6-ATM",
.desc = "MWAIT 0x52",
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 140,
.target_residency = 560,
.enter = &intel_idle },
+ {
+ .enter = NULL }
};
-static long get_driver_data(int cstate)
-{
- int driver_data;
- switch (cstate) {
-
- case 1: /* MWAIT C1 */
- driver_data = 0x00;
- break;
- case 2: /* MWAIT C2 */
- driver_data = 0x10;
- break;
- case 3: /* MWAIT C3 */
- driver_data = 0x20;
- break;
- case 4: /* MWAIT C4 */
- driver_data = 0x30;
- break;
- case 5: /* MWAIT C5 */
- driver_data = 0x40;
- break;
- case 6: /* MWAIT C6 */
- driver_data = 0x52;
- break;
- default:
- driver_data = 0x00;
- }
- return driver_data;
-}
-
/**
* intel_idle
* @dev: cpuidle_device
@@ -278,8 +323,7 @@ static int intel_idle(struct cpuidle_device *dev,
{
unsigned long ecx = 1; /* break on interrupt flag */
struct cpuidle_state *state = &drv->states[index];
- struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
- unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage);
+ unsigned long eax = flg2MWAIT(state->flags);
unsigned int cstate;
int cpu = smp_processor_id();
@@ -362,10 +406,19 @@ static void auto_demotion_disable(void *dummy)
msr_bits &= ~(icpu->auto_demotion_disable_flags);
wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
}
+static void c1e_promotion_disable(void *dummy)
+{
+ unsigned long long msr_bits;
+
+ rdmsrl(MSR_IA32_POWER_CTL, msr_bits);
+ msr_bits &= ~0x2;
+ wrmsrl(MSR_IA32_POWER_CTL, msr_bits);
+}
static const struct idle_cpu idle_cpu_nehalem = {
.state_table = nehalem_cstates,
.auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE,
+ .disable_promotion_to_c1e = true,
};
static const struct idle_cpu idle_cpu_atom = {
@@ -379,10 +432,17 @@ static const struct idle_cpu idle_cpu_lincroft = {
static const struct idle_cpu idle_cpu_snb = {
.state_table = snb_cstates,
+ .disable_promotion_to_c1e = true,
};
static const struct idle_cpu idle_cpu_ivb = {
.state_table = ivb_cstates,
+ .disable_promotion_to_c1e = true,
+};
+
+static const struct idle_cpu idle_cpu_hsw = {
+ .state_table = hsw_cstates,
+ .disable_promotion_to_c1e = true,
};
#define ICPU(model, cpu) \
@@ -402,6 +462,9 @@ static const struct x86_cpu_id intel_idle_ids[] = {
ICPU(0x2d, idle_cpu_snb),
ICPU(0x3a, idle_cpu_ivb),
ICPU(0x3e, idle_cpu_ivb),
+ ICPU(0x3c, idle_cpu_hsw),
+ ICPU(0x3f, idle_cpu_hsw),
+ ICPU(0x45, idle_cpu_hsw),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
@@ -484,32 +547,31 @@ static int intel_idle_cpuidle_driver_init(void)
drv->state_count = 1;
- for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
- int num_substates;
+ for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) {
+ int num_substates, mwait_hint, mwait_cstate, mwait_substate;
- if (cstate > max_cstate) {
+ if (cpuidle_state_table[cstate].enter == NULL)
+ break;
+
+ if (cstate + 1 > max_cstate) {
printk(PREFIX "max_cstate %d reached\n",
max_cstate);
break;
}
+ mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags);
+ mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint);
+ mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint);
+
/* does the state exist in CPUID.MWAIT? */
- num_substates = (mwait_substates >> ((cstate) * 4))
+ num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4))
& MWAIT_SUBSTATE_MASK;
- if (num_substates == 0)
- continue;
- /* is the state not enabled? */
- if (cpuidle_state_table[cstate].enter == NULL) {
- /* does the driver not know about the state? */
- if (*cpuidle_state_table[cstate].name == '\0')
- pr_debug(PREFIX "unaware of model 0x%x"
- " MWAIT %d please"
- " contact lenb@kernel.org\n",
- boot_cpu_data.x86_model, cstate);
+
+ /* if sub-state in table is not enumerated by CPUID */
+ if ((mwait_substate + 1) > num_substates)
continue;
- }
- if ((cstate > 2) &&
+ if (((mwait_cstate + 1) > 2) &&
!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
mark_tsc_unstable("TSC halts in idle"
" states deeper than C2");
@@ -523,6 +585,9 @@ static int intel_idle_cpuidle_driver_init(void)
if (icpu->auto_demotion_disable_flags)
on_each_cpu(auto_demotion_disable, NULL, 1);
+ if (icpu->disable_promotion_to_c1e) /* each-cpu is redundant */
+ on_each_cpu(c1e_promotion_disable, NULL, 1);
+
return 0;
}
@@ -541,25 +606,28 @@ static int intel_idle_cpu_init(int cpu)
dev->state_count = 1;
- for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
- int num_substates;
+ for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) {
+ int num_substates, mwait_hint, mwait_cstate, mwait_substate;
+
+ if (cpuidle_state_table[cstate].enter == NULL)
+ continue;
- if (cstate > max_cstate) {
+ if (cstate + 1 > max_cstate) {
printk(PREFIX "max_cstate %d reached\n", max_cstate);
break;
}
+ mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags);
+ mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint);
+ mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint);
+
/* does the state exist in CPUID.MWAIT? */
- num_substates = (mwait_substates >> ((cstate) * 4))
- & MWAIT_SUBSTATE_MASK;
- if (num_substates == 0)
- continue;
- /* is the state not enabled? */
- if (cpuidle_state_table[cstate].enter == NULL)
- continue;
+ num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4))
+ & MWAIT_SUBSTATE_MASK;
- dev->states_usage[dev->state_count].driver_data =
- (void *)get_driver_data(cstate);
+ /* if sub-state in table is not enumerated by CPUID */
+ if ((mwait_substate + 1) > num_substates)
+ continue;
dev->state_count += 1;
}
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 05e996fafc9d..bb594963f91e 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -14,4 +14,42 @@ config HID_SENSOR_ACCEL_3D
Say yes here to build support for the HID SENSOR
accelerometers 3D.
+config KXSD9
+ tristate "Kionix KXSD9 Accelerometer Driver"
+ depends on SPI
+ help
+ Say yes here to build support for the Kionix KXSD9 accelerometer.
+ Currently this only supports the device via an SPI interface.
+
+config IIO_ST_ACCEL_3AXIS
+ tristate "STMicroelectronics accelerometers 3-Axis Driver"
+ depends on (I2C || SPI_MASTER) && SYSFS
+ select IIO_ST_SENSORS_CORE
+ select IIO_ST_ACCEL_I2C_3AXIS if (I2C)
+ select IIO_ST_ACCEL_SPI_3AXIS if (SPI_MASTER)
+ select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
+ select IIO_ST_ACCEL_BUFFER if (IIO_TRIGGERED_BUFFER)
+ help
+ Say yes here to build support for STMicroelectronics accelerometers:
+ LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
+ LIS331DLH, LSM303DL, LSM303DLM, LSM330.
+
+ This driver can also be built as a module. If so, will be created
+ these modules:
+ - st_accel (core functions for the driver [it is mandatory]);
+ - st_accel_i2c (necessary for the I2C devices [optional*]);
+ - st_accel_spi (necessary for the SPI devices [optional*]);
+
+ (*) one of these is necessary to do something.
+
+config IIO_ST_ACCEL_I2C_3AXIS
+ tristate
+ depends on IIO_ST_ACCEL_3AXIS
+ depends on IIO_ST_SENSORS_I2C
+
+config IIO_ST_ACCEL_SPI_3AXIS
+ tristate
+ depends on IIO_ST_ACCEL_3AXIS
+ depends on IIO_ST_SENSORS_SPI
+
endmenu
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 5bc6855a973e..87d8fa264894 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -3,3 +3,12 @@
#
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
+
+obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
+st_accel-y := st_accel_core.o
+st_accel-$(CONFIG_IIO_BUFFER) += st_accel_buffer.o
+
+obj-$(CONFIG_IIO_ST_ACCEL_I2C_3AXIS) += st_accel_i2c.o
+obj-$(CONFIG_IIO_ST_ACCEL_SPI_3AXIS) += st_accel_spi.o
+
+obj-$(CONFIG_KXSD9) += kxsd9.o
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 0b0c3c66f6c0..dd8ea4284934 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -28,7 +28,6 @@
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-#include "../common/hid-sensors/hid-sensor-attributes.h"
#include "../common/hid-sensors/hid-sensor-trigger.h"
/*Format: HID-SENSOR-usage_id_in_hex*/
@@ -44,7 +43,7 @@ enum accel_3d_channel {
struct accel_3d_state {
struct hid_sensor_hub_callbacks callbacks;
- struct hid_sensor_iio_common common_attributes;
+ struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
u32 accel_val[ACCEL_3D_CHANNEL_MAX];
};
diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index 318331f08d9c..c2229a521ab9 100644
--- a/drivers/staging/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -94,7 +94,6 @@ error_ret:
static int kxsd9_read(struct iio_dev *indio_dev, u8 address)
{
- struct spi_message msg;
int ret;
struct kxsd9_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
@@ -112,10 +111,7 @@ static int kxsd9_read(struct iio_dev *indio_dev, u8 address)
mutex_lock(&st->buf_lock);
st->tx[0] = KXSD9_READ(address);
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
- ret = spi_sync(st->us, &msg);
+ ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret)
return ret;
return (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0);
@@ -226,7 +222,7 @@ static int kxsd9_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct kxsd9_state *st;
- int ret = 0;
+ int ret;
indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
@@ -245,14 +241,14 @@ static int kxsd9_probe(struct spi_device *spi)
indio_dev->info = &kxsd9_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_free_dev;
-
spi->mode = SPI_MODE_0;
spi_setup(spi);
kxsd9_power_up(st);
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_free_dev;
+
return 0;
error_free_dev:
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
new file mode 100644
index 000000000000..37949b94377d
--- /dev/null
+++ b/drivers/iio/accel/st_accel.h
@@ -0,0 +1,47 @@
+/*
+ * STMicroelectronics accelerometers driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ * v. 1.0.0
+ * Licensed under the GPL-2.
+ */
+
+#ifndef ST_ACCEL_H
+#define ST_ACCEL_H
+
+#include <linux/types.h>
+#include <linux/iio/common/st_sensors.h>
+
+#define LSM303DLHC_ACCEL_DEV_NAME "lsm303dlhc_accel"
+#define LIS3DH_ACCEL_DEV_NAME "lis3dh"
+#define LSM330D_ACCEL_DEV_NAME "lsm330d_accel"
+#define LSM330DL_ACCEL_DEV_NAME "lsm330dl_accel"
+#define LSM330DLC_ACCEL_DEV_NAME "lsm330dlc_accel"
+#define LIS331DLH_ACCEL_DEV_NAME "lis331dlh"
+#define LSM303DL_ACCEL_DEV_NAME "lsm303dl_accel"
+#define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel"
+#define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel"
+#define LSM330_ACCEL_DEV_NAME "lsm330_accel"
+
+int st_accel_common_probe(struct iio_dev *indio_dev);
+void st_accel_common_remove(struct iio_dev *indio_dev);
+
+#ifdef CONFIG_IIO_BUFFER
+int st_accel_allocate_ring(struct iio_dev *indio_dev);
+void st_accel_deallocate_ring(struct iio_dev *indio_dev);
+int st_accel_trig_set_state(struct iio_trigger *trig, bool state);
+#define ST_ACCEL_TRIGGER_SET_STATE (&st_accel_trig_set_state)
+#else /* CONFIG_IIO_BUFFER */
+static inline int st_accel_allocate_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+static inline void st_accel_deallocate_ring(struct iio_dev *indio_dev)
+{
+}
+#define ST_ACCEL_TRIGGER_SET_STATE NULL
+#endif /* CONFIG_IIO_BUFFER */
+
+#endif /* ST_ACCEL_H */
diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c
new file mode 100644
index 000000000000..6bd82c7f769c
--- /dev/null
+++ b/drivers/iio/accel/st_accel_buffer.c
@@ -0,0 +1,114 @@
+/*
+ * STMicroelectronics accelerometers driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include "st_accel.h"
+
+int st_accel_trig_set_state(struct iio_trigger *trig, bool state)
+{
+ struct iio_dev *indio_dev = trig->private_data;
+
+ return st_sensors_set_dataready_irq(indio_dev, state);
+}
+
+static int st_accel_buffer_preenable(struct iio_dev *indio_dev)
+{
+ int err;
+
+ err = st_sensors_set_enable(indio_dev, true);
+ if (err < 0)
+ goto st_accel_set_enable_error;
+
+ err = iio_sw_buffer_preenable(indio_dev);
+
+st_accel_set_enable_error:
+ return err;
+}
+
+static int st_accel_buffer_postenable(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *adata = iio_priv(indio_dev);
+
+ adata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+ if (adata->buffer_data == NULL) {
+ err = -ENOMEM;
+ goto allocate_memory_error;
+ }
+
+ err = st_sensors_set_axis_enable(indio_dev,
+ (u8)indio_dev->active_scan_mask[0]);
+ if (err < 0)
+ goto st_accel_buffer_postenable_error;
+
+ err = iio_triggered_buffer_postenable(indio_dev);
+ if (err < 0)
+ goto st_accel_buffer_postenable_error;
+
+ return err;
+
+st_accel_buffer_postenable_error:
+ kfree(adata->buffer_data);
+allocate_memory_error:
+ return err;
+}
+
+static int st_accel_buffer_predisable(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *adata = iio_priv(indio_dev);
+
+ err = iio_triggered_buffer_predisable(indio_dev);
+ if (err < 0)
+ goto st_accel_buffer_predisable_error;
+
+ err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
+ if (err < 0)
+ goto st_accel_buffer_predisable_error;
+
+ err = st_sensors_set_enable(indio_dev, false);
+
+st_accel_buffer_predisable_error:
+ kfree(adata->buffer_data);
+ return err;
+}
+
+static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = {
+ .preenable = &st_accel_buffer_preenable,
+ .postenable = &st_accel_buffer_postenable,
+ .predisable = &st_accel_buffer_predisable,
+};
+
+int st_accel_allocate_ring(struct iio_dev *indio_dev)
+{
+ return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ &st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
+}
+
+void st_accel_deallocate_ring(struct iio_dev *indio_dev)
+{
+ iio_triggered_buffer_cleanup(indio_dev);
+}
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics accelerometers buffer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
new file mode 100644
index 000000000000..e0f5a3ceba5e
--- /dev/null
+++ b/drivers/iio/accel/st_accel_core.c
@@ -0,0 +1,500 @@
+/*
+ * STMicroelectronics accelerometers driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/buffer.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include "st_accel.h"
+
+/* DEFAULT VALUE FOR SENSORS */
+#define ST_ACCEL_DEFAULT_OUT_X_L_ADDR 0x28
+#define ST_ACCEL_DEFAULT_OUT_Y_L_ADDR 0x2a
+#define ST_ACCEL_DEFAULT_OUT_Z_L_ADDR 0x2c
+
+/* FULLSCALE */
+#define ST_ACCEL_FS_AVL_2G 2
+#define ST_ACCEL_FS_AVL_4G 4
+#define ST_ACCEL_FS_AVL_6G 6
+#define ST_ACCEL_FS_AVL_8G 8
+#define ST_ACCEL_FS_AVL_16G 16
+
+/* CUSTOM VALUES FOR SENSOR 1 */
+#define ST_ACCEL_1_WAI_EXP 0x33
+#define ST_ACCEL_1_ODR_ADDR 0x20
+#define ST_ACCEL_1_ODR_MASK 0xf0
+#define ST_ACCEL_1_ODR_AVL_1HZ_VAL 0x01
+#define ST_ACCEL_1_ODR_AVL_10HZ_VAL 0x02
+#define ST_ACCEL_1_ODR_AVL_25HZ_VAL 0x03
+#define ST_ACCEL_1_ODR_AVL_50HZ_VAL 0x04
+#define ST_ACCEL_1_ODR_AVL_100HZ_VAL 0x05
+#define ST_ACCEL_1_ODR_AVL_200HZ_VAL 0x06
+#define ST_ACCEL_1_ODR_AVL_400HZ_VAL 0x07
+#define ST_ACCEL_1_ODR_AVL_1600HZ_VAL 0x08
+#define ST_ACCEL_1_FS_ADDR 0x23
+#define ST_ACCEL_1_FS_MASK 0x30
+#define ST_ACCEL_1_FS_AVL_2_VAL 0x00
+#define ST_ACCEL_1_FS_AVL_4_VAL 0x01
+#define ST_ACCEL_1_FS_AVL_8_VAL 0x02
+#define ST_ACCEL_1_FS_AVL_16_VAL 0x03
+#define ST_ACCEL_1_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1000)
+#define ST_ACCEL_1_FS_AVL_4_GAIN IIO_G_TO_M_S_2(2000)
+#define ST_ACCEL_1_FS_AVL_8_GAIN IIO_G_TO_M_S_2(4000)
+#define ST_ACCEL_1_FS_AVL_16_GAIN IIO_G_TO_M_S_2(12000)
+#define ST_ACCEL_1_BDU_ADDR 0x23
+#define ST_ACCEL_1_BDU_MASK 0x80
+#define ST_ACCEL_1_DRDY_IRQ_ADDR 0x22
+#define ST_ACCEL_1_DRDY_IRQ_MASK 0x10
+#define ST_ACCEL_1_MULTIREAD_BIT true
+
+/* CUSTOM VALUES FOR SENSOR 2 */
+#define ST_ACCEL_2_WAI_EXP 0x32
+#define ST_ACCEL_2_ODR_ADDR 0x20
+#define ST_ACCEL_2_ODR_MASK 0x18
+#define ST_ACCEL_2_ODR_AVL_50HZ_VAL 0x00
+#define ST_ACCEL_2_ODR_AVL_100HZ_VAL 0x01
+#define ST_ACCEL_2_ODR_AVL_400HZ_VAL 0x02
+#define ST_ACCEL_2_ODR_AVL_1000HZ_VAL 0x03
+#define ST_ACCEL_2_PW_ADDR 0x20
+#define ST_ACCEL_2_PW_MASK 0xe0
+#define ST_ACCEL_2_FS_ADDR 0x23
+#define ST_ACCEL_2_FS_MASK 0x30
+#define ST_ACCEL_2_FS_AVL_2_VAL 0X00
+#define ST_ACCEL_2_FS_AVL_4_VAL 0X01
+#define ST_ACCEL_2_FS_AVL_8_VAL 0x03
+#define ST_ACCEL_2_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1000)
+#define ST_ACCEL_2_FS_AVL_4_GAIN IIO_G_TO_M_S_2(2000)
+#define ST_ACCEL_2_FS_AVL_8_GAIN IIO_G_TO_M_S_2(3900)
+#define ST_ACCEL_2_BDU_ADDR 0x23
+#define ST_ACCEL_2_BDU_MASK 0x80
+#define ST_ACCEL_2_DRDY_IRQ_ADDR 0x22
+#define ST_ACCEL_2_DRDY_IRQ_MASK 0x02
+#define ST_ACCEL_2_MULTIREAD_BIT true
+
+/* CUSTOM VALUES FOR SENSOR 3 */
+#define ST_ACCEL_3_WAI_EXP 0x40
+#define ST_ACCEL_3_ODR_ADDR 0x20
+#define ST_ACCEL_3_ODR_MASK 0xf0
+#define ST_ACCEL_3_ODR_AVL_3HZ_VAL 0x01
+#define ST_ACCEL_3_ODR_AVL_6HZ_VAL 0x02
+#define ST_ACCEL_3_ODR_AVL_12HZ_VAL 0x03
+#define ST_ACCEL_3_ODR_AVL_25HZ_VAL 0x04
+#define ST_ACCEL_3_ODR_AVL_50HZ_VAL 0x05
+#define ST_ACCEL_3_ODR_AVL_100HZ_VAL 0x06
+#define ST_ACCEL_3_ODR_AVL_200HZ_VAL 0x07
+#define ST_ACCEL_3_ODR_AVL_400HZ_VAL 0x08
+#define ST_ACCEL_3_ODR_AVL_800HZ_VAL 0x09
+#define ST_ACCEL_3_ODR_AVL_1600HZ_VAL 0x0a
+#define ST_ACCEL_3_FS_ADDR 0x24
+#define ST_ACCEL_3_FS_MASK 0x38
+#define ST_ACCEL_3_FS_AVL_2_VAL 0X00
+#define ST_ACCEL_3_FS_AVL_4_VAL 0X01
+#define ST_ACCEL_3_FS_AVL_6_VAL 0x02
+#define ST_ACCEL_3_FS_AVL_8_VAL 0x03
+#define ST_ACCEL_3_FS_AVL_16_VAL 0x04
+#define ST_ACCEL_3_FS_AVL_2_GAIN IIO_G_TO_M_S_2(61)
+#define ST_ACCEL_3_FS_AVL_4_GAIN IIO_G_TO_M_S_2(122)
+#define ST_ACCEL_3_FS_AVL_6_GAIN IIO_G_TO_M_S_2(183)
+#define ST_ACCEL_3_FS_AVL_8_GAIN IIO_G_TO_M_S_2(244)
+#define ST_ACCEL_3_FS_AVL_16_GAIN IIO_G_TO_M_S_2(732)
+#define ST_ACCEL_3_BDU_ADDR 0x20
+#define ST_ACCEL_3_BDU_MASK 0x08
+#define ST_ACCEL_3_DRDY_IRQ_ADDR 0x23
+#define ST_ACCEL_3_DRDY_IRQ_MASK 0x80
+#define ST_ACCEL_3_IG1_EN_ADDR 0x23
+#define ST_ACCEL_3_IG1_EN_MASK 0x08
+#define ST_ACCEL_3_MULTIREAD_BIT false
+
+static const struct iio_chan_spec st_accel_12bit_channels[] = {
+ ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
+ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
+ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
+ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
+ IIO_CHAN_SOFT_TIMESTAMP(3)
+};
+
+static const struct iio_chan_spec st_accel_16bit_channels[] = {
+ ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
+ ST_SENSORS_DEFAULT_16_REALBITS, ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
+ ST_SENSORS_DEFAULT_16_REALBITS, ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
+ ST_SENSORS_DEFAULT_16_REALBITS, ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
+ IIO_CHAN_SOFT_TIMESTAMP(3)
+};
+
+static const struct st_sensors st_accel_sensors[] = {
+ {
+ .wai = ST_ACCEL_1_WAI_EXP,
+ .sensors_supported = {
+ [0] = LIS3DH_ACCEL_DEV_NAME,
+ [1] = LSM303DLHC_ACCEL_DEV_NAME,
+ [2] = LSM330D_ACCEL_DEV_NAME,
+ [3] = LSM330DL_ACCEL_DEV_NAME,
+ [4] = LSM330DLC_ACCEL_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_accel_12bit_channels,
+ .odr = {
+ .addr = ST_ACCEL_1_ODR_ADDR,
+ .mask = ST_ACCEL_1_ODR_MASK,
+ .odr_avl = {
+ { 1, ST_ACCEL_1_ODR_AVL_1HZ_VAL, },
+ { 10, ST_ACCEL_1_ODR_AVL_10HZ_VAL, },
+ { 25, ST_ACCEL_1_ODR_AVL_25HZ_VAL, },
+ { 50, ST_ACCEL_1_ODR_AVL_50HZ_VAL, },
+ { 100, ST_ACCEL_1_ODR_AVL_100HZ_VAL, },
+ { 200, ST_ACCEL_1_ODR_AVL_200HZ_VAL, },
+ { 400, ST_ACCEL_1_ODR_AVL_400HZ_VAL, },
+ { 1600, ST_ACCEL_1_ODR_AVL_1600HZ_VAL, },
+ },
+ },
+ .pw = {
+ .addr = ST_ACCEL_1_ODR_ADDR,
+ .mask = ST_ACCEL_1_ODR_MASK,
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .enable_axis = {
+ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+ },
+ .fs = {
+ .addr = ST_ACCEL_1_FS_ADDR,
+ .mask = ST_ACCEL_1_FS_MASK,
+ .fs_avl = {
+ [0] = {
+ .num = ST_ACCEL_FS_AVL_2G,
+ .value = ST_ACCEL_1_FS_AVL_2_VAL,
+ .gain = ST_ACCEL_1_FS_AVL_2_GAIN,
+ },
+ [1] = {
+ .num = ST_ACCEL_FS_AVL_4G,
+ .value = ST_ACCEL_1_FS_AVL_4_VAL,
+ .gain = ST_ACCEL_1_FS_AVL_4_GAIN,
+ },
+ [2] = {
+ .num = ST_ACCEL_FS_AVL_8G,
+ .value = ST_ACCEL_1_FS_AVL_8_VAL,
+ .gain = ST_ACCEL_1_FS_AVL_8_GAIN,
+ },
+ [3] = {
+ .num = ST_ACCEL_FS_AVL_16G,
+ .value = ST_ACCEL_1_FS_AVL_16_VAL,
+ .gain = ST_ACCEL_1_FS_AVL_16_GAIN,
+ },
+ },
+ },
+ .bdu = {
+ .addr = ST_ACCEL_1_BDU_ADDR,
+ .mask = ST_ACCEL_1_BDU_MASK,
+ },
+ .drdy_irq = {
+ .addr = ST_ACCEL_1_DRDY_IRQ_ADDR,
+ .mask = ST_ACCEL_1_DRDY_IRQ_MASK,
+ },
+ .multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
+ .bootime = 2,
+ },
+ {
+ .wai = ST_ACCEL_2_WAI_EXP,
+ .sensors_supported = {
+ [0] = LIS331DLH_ACCEL_DEV_NAME,
+ [1] = LSM303DL_ACCEL_DEV_NAME,
+ [2] = LSM303DLH_ACCEL_DEV_NAME,
+ [3] = LSM303DLM_ACCEL_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_accel_12bit_channels,
+ .odr = {
+ .addr = ST_ACCEL_2_ODR_ADDR,
+ .mask = ST_ACCEL_2_ODR_MASK,
+ .odr_avl = {
+ { 50, ST_ACCEL_2_ODR_AVL_50HZ_VAL, },
+ { 100, ST_ACCEL_2_ODR_AVL_100HZ_VAL, },
+ { 400, ST_ACCEL_2_ODR_AVL_400HZ_VAL, },
+ { 1000, ST_ACCEL_2_ODR_AVL_1000HZ_VAL, },
+ },
+ },
+ .pw = {
+ .addr = ST_ACCEL_2_PW_ADDR,
+ .mask = ST_ACCEL_2_PW_MASK,
+ .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .enable_axis = {
+ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+ },
+ .fs = {
+ .addr = ST_ACCEL_2_FS_ADDR,
+ .mask = ST_ACCEL_2_FS_MASK,
+ .fs_avl = {
+ [0] = {
+ .num = ST_ACCEL_FS_AVL_2G,
+ .value = ST_ACCEL_2_FS_AVL_2_VAL,
+ .gain = ST_ACCEL_2_FS_AVL_2_GAIN,
+ },
+ [1] = {
+ .num = ST_ACCEL_FS_AVL_4G,
+ .value = ST_ACCEL_2_FS_AVL_4_VAL,
+ .gain = ST_ACCEL_2_FS_AVL_4_GAIN,
+ },
+ [2] = {
+ .num = ST_ACCEL_FS_AVL_8G,
+ .value = ST_ACCEL_2_FS_AVL_8_VAL,
+ .gain = ST_ACCEL_2_FS_AVL_8_GAIN,
+ },
+ },
+ },
+ .bdu = {
+ .addr = ST_ACCEL_2_BDU_ADDR,
+ .mask = ST_ACCEL_2_BDU_MASK,
+ },
+ .drdy_irq = {
+ .addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
+ .mask = ST_ACCEL_2_DRDY_IRQ_MASK,
+ },
+ .multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
+ .bootime = 2,
+ },
+ {
+ .wai = ST_ACCEL_3_WAI_EXP,
+ .sensors_supported = {
+ [0] = LSM330_ACCEL_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_accel_16bit_channels,
+ .odr = {
+ .addr = ST_ACCEL_3_ODR_ADDR,
+ .mask = ST_ACCEL_3_ODR_MASK,
+ .odr_avl = {
+ { 3, ST_ACCEL_3_ODR_AVL_3HZ_VAL },
+ { 6, ST_ACCEL_3_ODR_AVL_6HZ_VAL, },
+ { 12, ST_ACCEL_3_ODR_AVL_12HZ_VAL, },
+ { 25, ST_ACCEL_3_ODR_AVL_25HZ_VAL, },
+ { 50, ST_ACCEL_3_ODR_AVL_50HZ_VAL, },
+ { 100, ST_ACCEL_3_ODR_AVL_100HZ_VAL, },
+ { 200, ST_ACCEL_3_ODR_AVL_200HZ_VAL, },
+ { 400, ST_ACCEL_3_ODR_AVL_400HZ_VAL, },
+ { 800, ST_ACCEL_3_ODR_AVL_800HZ_VAL, },
+ { 1600, ST_ACCEL_3_ODR_AVL_1600HZ_VAL, },
+ },
+ },
+ .pw = {
+ .addr = ST_ACCEL_3_ODR_ADDR,
+ .mask = ST_ACCEL_3_ODR_MASK,
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .enable_axis = {
+ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+ },
+ .fs = {
+ .addr = ST_ACCEL_3_FS_ADDR,
+ .mask = ST_ACCEL_3_FS_MASK,
+ .fs_avl = {
+ [0] = {
+ .num = ST_ACCEL_FS_AVL_2G,
+ .value = ST_ACCEL_3_FS_AVL_2_VAL,
+ .gain = ST_ACCEL_3_FS_AVL_2_GAIN,
+ },
+ [1] = {
+ .num = ST_ACCEL_FS_AVL_4G,
+ .value = ST_ACCEL_3_FS_AVL_4_VAL,
+ .gain = ST_ACCEL_3_FS_AVL_4_GAIN,
+ },
+ [2] = {
+ .num = ST_ACCEL_FS_AVL_6G,
+ .value = ST_ACCEL_3_FS_AVL_6_VAL,
+ .gain = ST_ACCEL_3_FS_AVL_6_GAIN,
+ },
+ [3] = {
+ .num = ST_ACCEL_FS_AVL_8G,
+ .value = ST_ACCEL_3_FS_AVL_8_VAL,
+ .gain = ST_ACCEL_3_FS_AVL_8_GAIN,
+ },
+ [4] = {
+ .num = ST_ACCEL_FS_AVL_16G,
+ .value = ST_ACCEL_3_FS_AVL_16_VAL,
+ .gain = ST_ACCEL_3_FS_AVL_16_GAIN,
+ },
+ },
+ },
+ .bdu = {
+ .addr = ST_ACCEL_3_BDU_ADDR,
+ .mask = ST_ACCEL_3_BDU_MASK,
+ },
+ .drdy_irq = {
+ .addr = ST_ACCEL_3_DRDY_IRQ_ADDR,
+ .mask = ST_ACCEL_3_DRDY_IRQ_MASK,
+ .ig1 = {
+ .en_addr = ST_ACCEL_3_IG1_EN_ADDR,
+ .en_mask = ST_ACCEL_3_IG1_EN_MASK,
+ },
+ },
+ .multi_read_bit = ST_ACCEL_3_MULTIREAD_BIT,
+ .bootime = 2,
+ },
+};
+
+static int st_accel_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *ch, int *val,
+ int *val2, long mask)
+{
+ int err;
+ struct st_sensor_data *adata = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ err = st_sensors_read_info_raw(indio_dev, ch, val);
+ if (err < 0)
+ goto read_error;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = adata->current_fullscale->gain;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+
+read_error:
+ return err;
+}
+
+static int st_accel_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+ int err;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
+static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
+static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_accel_scale_available);
+
+static struct attribute *st_accel_attributes[] = {
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_in_accel_scale_available.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group st_accel_attribute_group = {
+ .attrs = st_accel_attributes,
+};
+
+static const struct iio_info accel_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &st_accel_attribute_group,
+ .read_raw = &st_accel_read_raw,
+ .write_raw = &st_accel_write_raw,
+};
+
+#ifdef CONFIG_IIO_TRIGGER
+static const struct iio_trigger_ops st_accel_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = ST_ACCEL_TRIGGER_SET_STATE,
+};
+#define ST_ACCEL_TRIGGER_OPS (&st_accel_trigger_ops)
+#else
+#define ST_ACCEL_TRIGGER_OPS NULL
+#endif
+
+int st_accel_common_probe(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *adata = iio_priv(indio_dev);
+
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &accel_info;
+
+ err = st_sensors_check_device_support(indio_dev,
+ ARRAY_SIZE(st_accel_sensors), st_accel_sensors);
+ if (err < 0)
+ goto st_accel_common_probe_error;
+
+ adata->multiread_bit = adata->sensor->multi_read_bit;
+ indio_dev->channels = adata->sensor->ch;
+ indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
+
+ adata->current_fullscale = (struct st_sensor_fullscale_avl *)
+ &adata->sensor->fs.fs_avl[0];
+ adata->odr = adata->sensor->odr.odr_avl[0].hz;
+
+ err = st_sensors_init_sensor(indio_dev);
+ if (err < 0)
+ goto st_accel_common_probe_error;
+
+ if (adata->get_irq_data_ready(indio_dev) > 0) {
+ err = st_accel_allocate_ring(indio_dev);
+ if (err < 0)
+ goto st_accel_common_probe_error;
+
+ err = st_sensors_allocate_trigger(indio_dev,
+ ST_ACCEL_TRIGGER_OPS);
+ if (err < 0)
+ goto st_accel_probe_trigger_error;
+ }
+
+ err = iio_device_register(indio_dev);
+ if (err)
+ goto st_accel_device_register_error;
+
+ return err;
+
+st_accel_device_register_error:
+ if (adata->get_irq_data_ready(indio_dev) > 0)
+ st_sensors_deallocate_trigger(indio_dev);
+st_accel_probe_trigger_error:
+ if (adata->get_irq_data_ready(indio_dev) > 0)
+ st_accel_deallocate_ring(indio_dev);
+st_accel_common_probe_error:
+ return err;
+}
+EXPORT_SYMBOL(st_accel_common_probe);
+
+void st_accel_common_remove(struct iio_dev *indio_dev)
+{
+ struct st_sensor_data *adata = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ if (adata->get_irq_data_ready(indio_dev) > 0) {
+ st_sensors_deallocate_trigger(indio_dev);
+ st_accel_deallocate_ring(indio_dev);
+ }
+ iio_device_free(indio_dev);
+}
+EXPORT_SYMBOL(st_accel_common_remove);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics accelerometers driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
new file mode 100644
index 000000000000..ffc9d097e484
--- /dev/null
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -0,0 +1,86 @@
+/*
+ * STMicroelectronics accelerometers driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include <linux/iio/common/st_sensors_i2c.h>
+#include "st_accel.h"
+
+static int st_accel_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct st_sensor_data *adata;
+ int err;
+
+ indio_dev = iio_device_alloc(sizeof(*adata));
+ if (indio_dev == NULL) {
+ err = -ENOMEM;
+ goto iio_device_alloc_error;
+ }
+
+ adata = iio_priv(indio_dev);
+ adata->dev = &client->dev;
+
+ st_sensors_i2c_configure(indio_dev, client, adata);
+
+ err = st_accel_common_probe(indio_dev);
+ if (err < 0)
+ goto st_accel_common_probe_error;
+
+ return 0;
+
+st_accel_common_probe_error:
+ iio_device_free(indio_dev);
+iio_device_alloc_error:
+ return err;
+}
+
+static int st_accel_i2c_remove(struct i2c_client *client)
+{
+ st_accel_common_remove(i2c_get_clientdata(client));
+
+ return 0;
+}
+
+static const struct i2c_device_id st_accel_id_table[] = {
+ { LSM303DLH_ACCEL_DEV_NAME },
+ { LSM303DLHC_ACCEL_DEV_NAME },
+ { LIS3DH_ACCEL_DEV_NAME },
+ { LSM330D_ACCEL_DEV_NAME },
+ { LSM330DL_ACCEL_DEV_NAME },
+ { LSM330DLC_ACCEL_DEV_NAME },
+ { LIS331DLH_ACCEL_DEV_NAME },
+ { LSM303DL_ACCEL_DEV_NAME },
+ { LSM303DLM_ACCEL_DEV_NAME },
+ { LSM330_ACCEL_DEV_NAME },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
+
+static struct i2c_driver st_accel_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "st-accel-i2c",
+ },
+ .probe = st_accel_i2c_probe,
+ .remove = st_accel_i2c_remove,
+ .id_table = st_accel_id_table,
+};
+module_i2c_driver(st_accel_driver);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics accelerometers i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
new file mode 100644
index 000000000000..22b35bfea7d2
--- /dev/null
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -0,0 +1,85 @@
+/*
+ * STMicroelectronics accelerometers driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/iio/iio.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include <linux/iio/common/st_sensors_spi.h>
+#include "st_accel.h"
+
+static int st_accel_spi_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct st_sensor_data *adata;
+ int err;
+
+ indio_dev = iio_device_alloc(sizeof(*adata));
+ if (indio_dev == NULL) {
+ err = -ENOMEM;
+ goto iio_device_alloc_error;
+ }
+
+ adata = iio_priv(indio_dev);
+ adata->dev = &spi->dev;
+
+ st_sensors_spi_configure(indio_dev, spi, adata);
+
+ err = st_accel_common_probe(indio_dev);
+ if (err < 0)
+ goto st_accel_common_probe_error;
+
+ return 0;
+
+st_accel_common_probe_error:
+ iio_device_free(indio_dev);
+iio_device_alloc_error:
+ return err;
+}
+
+static int st_accel_spi_remove(struct spi_device *spi)
+{
+ st_accel_common_remove(spi_get_drvdata(spi));
+
+ return 0;
+}
+
+static const struct spi_device_id st_accel_id_table[] = {
+ { LSM303DLH_ACCEL_DEV_NAME },
+ { LSM303DLHC_ACCEL_DEV_NAME },
+ { LIS3DH_ACCEL_DEV_NAME },
+ { LSM330D_ACCEL_DEV_NAME },
+ { LSM330DL_ACCEL_DEV_NAME },
+ { LSM330DLC_ACCEL_DEV_NAME },
+ { LIS331DLH_ACCEL_DEV_NAME },
+ { LSM303DL_ACCEL_DEV_NAME },
+ { LSM303DLM_ACCEL_DEV_NAME },
+ { LSM330_ACCEL_DEV_NAME },
+ {},
+};
+MODULE_DEVICE_TABLE(spi, st_accel_id_table);
+
+static struct spi_driver st_accel_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "st-accel-spi",
+ },
+ .probe = st_accel_spi_probe,
+ .remove = st_accel_spi_remove,
+ .id_table = st_accel_id_table,
+};
+module_spi_driver(st_accel_driver);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics accelerometers spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index fe822a14d130..e372257a8494 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -100,10 +100,8 @@ config LP8788_ADC
config MAX1363
tristate "Maxim max1363 ADC driver"
depends on I2C
- select IIO_TRIGGER
- select MAX1363_RING_BUFFER
select IIO_BUFFER
- select IIO_KFIFO_BUF
+ select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for many Maxim i2c analog to digital
converters (ADC). (max1361, max1362, max1363, max1364, max1036,
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index a526c0e3aaa8..83c836ba600f 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -557,9 +557,9 @@ static int at91_adc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- st->reg_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!st->reg_base) {
- ret = -ENOMEM;
+ st->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(st->reg_base)) {
+ ret = PTR_ERR(st->reg_base);
goto error_free_device;
}
diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c
index 72955e45e9e0..763f57565ee4 100644
--- a/drivers/iio/adc/lp8788_adc.c
+++ b/drivers/iio/adc/lp8788_adc.c
@@ -179,7 +179,7 @@ static int lp8788_iio_map_register(struct iio_dev *indio_dev,
ret = iio_map_array_register(indio_dev, map);
if (ret) {
- dev_err(adc->lp->dev, "iio map err: %d\n", ret);
+ dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
return ret;
}
@@ -187,12 +187,6 @@ static int lp8788_iio_map_register(struct iio_dev *indio_dev,
return 0;
}
-static inline void lp8788_iio_map_unregister(struct iio_dev *indio_dev,
- struct lp8788_adc *adc)
-{
- iio_map_array_unregister(indio_dev, adc->map);
-}
-
static int lp8788_adc_probe(struct platform_device *pdev)
{
struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
@@ -208,13 +202,14 @@ static int lp8788_adc_probe(struct platform_device *pdev)
adc->lp = lp;
platform_set_drvdata(pdev, indio_dev);
+ indio_dev->dev.of_node = pdev->dev.of_node;
ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc);
if (ret)
goto err_iio_map;
mutex_init(&adc->lock);
- indio_dev->dev.parent = lp->dev;
+ indio_dev->dev.parent = &pdev->dev;
indio_dev->name = pdev->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &lp8788_adc_info;
@@ -223,14 +218,14 @@ static int lp8788_adc_probe(struct platform_device *pdev)
ret = iio_device_register(indio_dev);
if (ret) {
- dev_err(lp->dev, "iio dev register err: %d\n", ret);
+ dev_err(&pdev->dev, "iio dev register err: %d\n", ret);
goto err_iio_device;
}
return 0;
err_iio_device:
- lp8788_iio_map_unregister(indio_dev, adc);
+ iio_map_array_unregister(indio_dev);
err_iio_map:
iio_device_free(indio_dev);
return ret;
@@ -239,10 +234,9 @@ err_iio_map:
static int lp8788_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct lp8788_adc *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
- lp8788_iio_map_unregister(indio_dev, adc);
+ iio_map_array_unregister(indio_dev);
iio_device_free(indio_dev);
return 0;
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 03b25b3dc71e..6c1cfb74bdfc 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -39,6 +39,7 @@
#include <linux/iio/driver.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
#define MAX1363_SETUP_BYTE(a) ((a) | 0x80)
@@ -55,7 +56,7 @@
#define MAX1363_SETUP_POWER_UP_INT_REF 0x10
#define MAX1363_SETUP_POWER_DOWN_INT_REF 0x00
-/* think about includeing max11600 etc - more settings */
+/* think about including max11600 etc - more settings */
#define MAX1363_SETUP_EXT_CLOCK 0x08
#define MAX1363_SETUP_INT_CLOCK 0x00
#define MAX1363_SETUP_UNIPOLAR 0x00
@@ -86,7 +87,7 @@
/* max123{6-9} only */
#define MAX1236_SCAN_MID_TO_CHANNEL 0x40
-/* max1363 only - merely part of channel selects or don't care for others*/
+/* max1363 only - merely part of channel selects or don't care for others */
#define MAX1363_CONFIG_EN_MON_MODE_READ 0x18
#define MAX1363_CHANNEL_SEL(a) ((a) << 1)
@@ -133,7 +134,7 @@ enum max1363_modes {
* @mode_list: array of available scan modes
* @default_mode: the scan mode in which the chip starts up
* @int_vref_mv: the internal reference voltage
- * @num_channels: number of channels
+ * @num_modes: number of modes
* @bits: accuracy of the adc in bits
*/
struct max1363_chip_info {
@@ -152,7 +153,7 @@ struct max1363_chip_info {
* @client: i2c_client
* @setupbyte: cache of current device setup byte
* @configbyte: cache of current device config byte
- * @chip_info: chip model specific constants, available modes etc
+ * @chip_info: chip model specific constants, available modes, etc.
* @current_mode: the scan mode of this chip
* @requestedmask: a valid requested set of channels
* @reg: supply regulator
@@ -162,6 +163,8 @@ struct max1363_chip_info {
* @mask_low: bitmask for enabled low thresholds
* @thresh_high: high threshold values
* @thresh_low: low threshold values
+ * @vref: Reference voltage regulator
+ * @vref_uv: Actual (external or internal) reference voltage
*/
struct max1363_state {
struct i2c_client *client;
@@ -181,6 +184,8 @@ struct max1363_state {
/* 4x unipolar first then the fours bipolar ones */
s16 thresh_high[8];
s16 thresh_low[8];
+ struct regulator *vref;
+ u32 vref_uv;
};
#define MAX1363_MODE_SINGLE(_num, _mask) { \
@@ -293,7 +298,7 @@ static const struct max1363_mode max1363_mode_table[] = {
static const struct max1363_mode
*max1363_match_mode(const unsigned long *mask,
-const struct max1363_chip_info *ci)
+ const struct max1363_chip_info *ci)
{
int i;
if (mask)
@@ -334,7 +339,7 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev,
{
int ret = 0;
s32 data;
- char rxbuf[2];
+ u8 rxbuf[2];
struct max1363_state *st = iio_priv(indio_dev);
struct i2c_client *client = st->client;
@@ -366,7 +371,8 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev,
ret = data;
goto error_ret;
}
- data = (s32)(rxbuf[1]) | ((s32)(rxbuf[0] & 0x0F)) << 8;
+ data = (rxbuf[1] | rxbuf[0] << 8) &
+ ((1 << st->chip_info->bits) - 1);
} else {
/* Get reading */
data = i2c_master_recv(client, rxbuf, 1);
@@ -391,6 +397,8 @@ static int max1363_read_raw(struct iio_dev *indio_dev,
{
struct max1363_state *st = iio_priv(indio_dev);
int ret;
+ unsigned long scale_uv;
+
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = max1363_read_single_chan(indio_dev, chan, val, m);
@@ -398,16 +406,10 @@ static int max1363_read_raw(struct iio_dev *indio_dev,
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- if ((1 << (st->chip_info->bits + 1)) >
- st->chip_info->int_vref_mv) {
- *val = 0;
- *val2 = 500000;
- return IIO_VAL_INT_PLUS_MICRO;
- } else {
- *val = (st->chip_info->int_vref_mv)
- >> st->chip_info->bits;
- return IIO_VAL_INT;
- }
+ scale_uv = st->vref_uv >> st->chip_info->bits;
+ *val = scale_uv / 1000;
+ *val2 = (scale_uv % 1000) * 1000;
+ return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
@@ -1388,13 +1390,17 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
static int max1363_initial_setup(struct max1363_state *st)
{
- st->setupbyte = MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD
- | MAX1363_SETUP_POWER_UP_INT_REF
- | MAX1363_SETUP_INT_CLOCK
+ st->setupbyte = MAX1363_SETUP_INT_CLOCK
| MAX1363_SETUP_UNIPOLAR
| MAX1363_SETUP_NORESET;
- /* Set scan mode writes the config anyway so wait until then*/
+ if (st->vref)
+ st->setupbyte |= MAX1363_SETUP_AIN3_IS_REF_EXT_TO_REF;
+ else
+ st->setupbyte |= MAX1363_SETUP_POWER_UP_INT_REF
+ | MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_INT;
+
+ /* Set scan mode writes the config anyway so wait until then */
st->setupbyte = MAX1363_SETUP_BYTE(st->setupbyte);
st->current_mode = &max1363_mode_table[st->chip_info->default_mode];
st->configbyte = MAX1363_CONFIG_BYTE(st->configbyte);
@@ -1408,8 +1414,9 @@ static int max1363_alloc_scan_masks(struct iio_dev *indio_dev)
unsigned long *masks;
int i;
- masks = kzalloc(BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*sizeof(long)*
- (st->chip_info->num_modes + 1), GFP_KERNEL);
+ masks = devm_kzalloc(&indio_dev->dev,
+ BITS_TO_LONGS(MAX1363_MAX_CHANNELS) * sizeof(long) *
+ (st->chip_info->num_modes + 1), GFP_KERNEL);
if (!masks)
return -ENOMEM;
@@ -1423,7 +1430,6 @@ static int max1363_alloc_scan_masks(struct iio_dev *indio_dev)
return 0;
}
-
static irqreturn_t max1363_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@@ -1483,54 +1489,13 @@ static const struct iio_buffer_setup_ops max1363_buffered_setup_ops = {
.predisable = &iio_triggered_buffer_predisable,
};
-static int max1363_register_buffered_funcs_and_init(struct iio_dev *indio_dev)
-{
- struct max1363_state *st = iio_priv(indio_dev);
- int ret = 0;
-
- indio_dev->buffer = iio_kfifo_allocate(indio_dev);
- if (!indio_dev->buffer) {
- ret = -ENOMEM;
- goto error_ret;
- }
- indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
- &max1363_trigger_handler,
- IRQF_ONESHOT,
- indio_dev,
- "%s_consumer%d",
- st->client->name,
- indio_dev->id);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
- goto error_deallocate_sw_rb;
- }
- /* Buffer functions - here trigger setup related */
- indio_dev->setup_ops = &max1363_buffered_setup_ops;
-
- /* Flag that polled buffering is possible */
- indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-
- return 0;
-
-error_deallocate_sw_rb:
- iio_kfifo_free(indio_dev->buffer);
-error_ret:
- return ret;
-}
-
-static void max1363_buffer_cleanup(struct iio_dev *indio_dev)
-{
- /* ensure that the trigger has been detached */
- iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_kfifo_free(indio_dev->buffer);
-}
-
static int max1363_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct max1363_state *st;
struct iio_dev *indio_dev;
+ struct regulator *vref;
indio_dev = iio_device_alloc(sizeof(struct max1363_state));
if (indio_dev == NULL) {
@@ -1538,13 +1503,14 @@ static int max1363_probe(struct i2c_client *client,
goto error_out;
}
+ indio_dev->dev.of_node = client->dev.of_node;
ret = iio_map_array_register(indio_dev, client->dev.platform_data);
if (ret < 0)
goto error_free_device;
st = iio_priv(indio_dev);
- st->reg = regulator_get(&client->dev, "vcc");
+ st->reg = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(st->reg)) {
ret = PTR_ERR(st->reg);
goto error_unregister_map;
@@ -1552,7 +1518,7 @@ static int max1363_probe(struct i2c_client *client,
ret = regulator_enable(st->reg);
if (ret)
- goto error_put_reg;
+ goto error_unregister_map;
/* this is only used for device removal purposes */
i2c_set_clientdata(client, indio_dev);
@@ -1560,35 +1526,45 @@ static int max1363_probe(struct i2c_client *client,
st->chip_info = &max1363_chip_info_tbl[id->driver_data];
st->client = client;
+ st->vref_uv = st->chip_info->int_vref_mv * 1000;
+ vref = devm_regulator_get(&client->dev, "vref");
+ if (!IS_ERR(vref)) {
+ int vref_uv;
+
+ ret = regulator_enable(vref);
+ if (ret)
+ goto error_disable_reg;
+ st->vref = vref;
+ vref_uv = regulator_get_voltage(vref);
+ if (vref_uv <= 0) {
+ ret = -EINVAL;
+ goto error_disable_reg;
+ }
+ st->vref_uv = vref_uv;
+ }
+
ret = max1363_alloc_scan_masks(indio_dev);
if (ret)
goto error_disable_reg;
- /* Estabilish that the iio_dev is a child of the i2c device */
+ /* Establish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = st->chip_info->info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = st->chip_info->channels;
- indio_dev->num_channels = st->chip_info->num_channels;
ret = max1363_initial_setup(st);
if (ret < 0)
- goto error_free_available_scan_masks;
-
- ret = max1363_register_buffered_funcs_and_init(indio_dev);
- if (ret)
- goto error_free_available_scan_masks;
+ goto error_disable_reg;
- ret = iio_buffer_register(indio_dev,
- st->chip_info->channels,
- st->chip_info->num_channels);
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ &max1363_trigger_handler, &max1363_buffered_setup_ops);
if (ret)
- goto error_cleanup_buffer;
+ goto error_disable_reg;
if (client->irq) {
- ret = request_threaded_irq(st->client->irq,
+ ret = devm_request_threaded_irq(&client->dev, st->client->irq,
NULL,
&max1363_event_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@@ -1601,24 +1577,18 @@ static int max1363_probe(struct i2c_client *client,
ret = iio_device_register(indio_dev);
if (ret < 0)
- goto error_free_irq;
+ goto error_uninit_buffer;
return 0;
-error_free_irq:
- if (client->irq)
- free_irq(st->client->irq, indio_dev);
+
error_uninit_buffer:
- iio_buffer_unregister(indio_dev);
-error_cleanup_buffer:
- max1363_buffer_cleanup(indio_dev);
-error_free_available_scan_masks:
- kfree(indio_dev->available_scan_masks);
+ iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
+ if (st->vref)
+ regulator_disable(st->vref);
regulator_disable(st->reg);
-error_put_reg:
- regulator_put(st->reg);
error_unregister_map:
- iio_map_array_unregister(indio_dev, client->dev.platform_data);
+ iio_map_array_unregister(indio_dev);
error_free_device:
iio_device_free(indio_dev);
error_out:
@@ -1631,14 +1601,11 @@ static int max1363_remove(struct i2c_client *client)
struct max1363_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
- if (client->irq)
- free_irq(st->client->irq, indio_dev);
- iio_buffer_unregister(indio_dev);
- max1363_buffer_cleanup(indio_dev);
- kfree(indio_dev->available_scan_masks);
+ iio_triggered_buffer_cleanup(indio_dev);
+ if (st->vref)
+ regulator_disable(st->vref);
regulator_disable(st->reg);
- regulator_put(st->reg);
- iio_map_array_unregister(indio_dev, client->dev.platform_data);
+ iio_map_array_unregister(indio_dev);
iio_device_free(indio_dev);
return 0;
diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c
index 4d40e24f3721..9201022945e9 100644
--- a/drivers/iio/buffer_cb.c
+++ b/drivers/iio/buffer_cb.c
@@ -25,7 +25,7 @@ static struct iio_buffer_access_funcs iio_cb_access = {
.store_to = &iio_buffer_cb_store_to,
};
-struct iio_cb_buffer *iio_channel_get_all_cb(const char *name,
+struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
int (*cb)(u8 *data,
void *private),
void *private)
@@ -46,7 +46,7 @@ struct iio_cb_buffer *iio_channel_get_all_cb(const char *name,
cb_buff->buffer.access = &iio_cb_access;
INIT_LIST_HEAD(&cb_buff->buffer.demux_list);
- cb_buff->channels = iio_channel_get_all(name);
+ cb_buff->channels = iio_channel_get_all(dev);
if (IS_ERR(cb_buff->channels)) {
ret = PTR_ERR(cb_buff->channels);
goto error_free_cb_buff;
diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
index ed45ee54500c..0b6e97d18fa0 100644
--- a/drivers/iio/common/Kconfig
+++ b/drivers/iio/common/Kconfig
@@ -3,3 +3,4 @@
#
source "drivers/iio/common/hid-sensors/Kconfig"
+source "drivers/iio/common/st_sensors/Kconfig"
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
index 81584009b21b..c2352beb5d97 100644
--- a/drivers/iio/common/Makefile
+++ b/drivers/iio/common/Makefile
@@ -7,3 +7,4 @@
#
obj-y += hid-sensors/
+obj-y += st_sensors/
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
index 75374955caba..75b54730a963 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -25,7 +25,6 @@
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include "hid-sensor-attributes.h"
static int pow_10(unsigned power)
{
@@ -114,7 +113,7 @@ static u32 convert_to_vtf_format(int size, int exp, int val1, int val2)
return value;
}
-int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st,
+int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
int *val1, int *val2)
{
s32 value;
@@ -141,7 +140,7 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st,
}
EXPORT_SYMBOL(hid_sensor_read_samp_freq_value);
-int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st,
+int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
int val1, int val2)
{
s32 value;
@@ -169,7 +168,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st,
}
EXPORT_SYMBOL(hid_sensor_write_samp_freq_value);
-int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st,
+int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
int *val1, int *val2)
{
s32 value;
@@ -191,7 +190,7 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st,
}
EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value);
-int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st,
+int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
int val1, int val2)
{
s32 value;
@@ -212,7 +211,7 @@ EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
- struct hid_sensor_iio_common *st)
+ struct hid_sensor_common *st)
{
sensor_hub_input_get_attribute_info(hsdev,
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.h b/drivers/iio/common/hid-sensors/hid-sensor-attributes.h
deleted file mode 100644
index a4676a0c3de5..000000000000
--- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * HID Sensors Driver
- * Copyright (c) 2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-#ifndef _HID_SENSORS_ATTRIBUTES_H
-#define _HID_SENSORS_ATTRIBUTES_H
-
-/* Common hid sensor iio structure */
-struct hid_sensor_iio_common {
- struct hid_sensor_hub_device *hsdev;
- struct platform_device *pdev;
- unsigned usage_id;
- bool data_ready;
- struct hid_sensor_hub_attribute_info poll;
- struct hid_sensor_hub_attribute_info report_state;
- struct hid_sensor_hub_attribute_info power_state;
- struct hid_sensor_hub_attribute_info sensitivity;
-};
-
-/*Convert from hid unit expo to regular exponent*/
-static inline int hid_sensor_convert_exponent(int unit_expo)
-{
- if (unit_expo < 0x08)
- return unit_expo;
- else if (unit_expo <= 0x0f)
- return -(0x0f-unit_expo+1);
- else
- return 0;
-}
-
-int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
- u32 usage_id,
- struct hid_sensor_iio_common *st);
-int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st,
- int val1, int val2);
-int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st,
- int *val1, int *val2);
-int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st,
- int val1, int val2);
-int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st,
- int *val1, int *val2);
-
-#endif
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index d60198a6ca29..7a525a91105d 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -26,13 +26,12 @@
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/sysfs.h>
-#include "hid-sensor-attributes.h"
#include "hid-sensor-trigger.h"
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
- struct hid_sensor_iio_common *st = trig->private_data;
+ struct hid_sensor_common *st = trig->private_data;
int state_val;
state_val = state ? 1 : 0;
@@ -64,7 +63,7 @@ static const struct iio_trigger_ops hid_sensor_trigger_ops = {
};
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
- struct hid_sensor_iio_common *attrb)
+ struct hid_sensor_common *attrb)
{
int ret;
struct iio_trigger *trig;
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
index fd982971b1b8..9a8731478eda 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -20,7 +20,7 @@
#define _HID_SENSOR_TRIGGER_H
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
- struct hid_sensor_iio_common *attrb);
+ struct hid_sensor_common *attrb);
void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
#endif
diff --git a/drivers/iio/common/st_sensors/Kconfig b/drivers/iio/common/st_sensors/Kconfig
new file mode 100644
index 000000000000..865f1ca33eb9
--- /dev/null
+++ b/drivers/iio/common/st_sensors/Kconfig
@@ -0,0 +1,14 @@
+#
+# STMicroelectronics sensors common library
+#
+
+config IIO_ST_SENSORS_I2C
+ tristate
+
+config IIO_ST_SENSORS_SPI
+ tristate
+
+config IIO_ST_SENSORS_CORE
+ tristate
+ select IIO_ST_SENSORS_I2C if I2C
+ select IIO_ST_SENSORS_SPI if SPI_MASTER
diff --git a/drivers/iio/common/st_sensors/Makefile b/drivers/iio/common/st_sensors/Makefile
new file mode 100644
index 000000000000..9f3e24f3024b
--- /dev/null
+++ b/drivers/iio/common/st_sensors/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the STMicroelectronics sensor common modules.
+#
+
+obj-$(CONFIG_IIO_ST_SENSORS_I2C) += st_sensors_i2c.o
+obj-$(CONFIG_IIO_ST_SENSORS_SPI) += st_sensors_spi.o
+obj-$(CONFIG_IIO_ST_SENSORS_CORE) += st_sensors.o
+st_sensors-y := st_sensors_core.o
+st_sensors-$(CONFIG_IIO_BUFFER) += st_sensors_buffer.o
+st_sensors-$(CONFIG_IIO_TRIGGER) += st_sensors_trigger.o
diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c
new file mode 100644
index 000000000000..09b236d6ee89
--- /dev/null
+++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c
@@ -0,0 +1,116 @@
+/*
+ * STMicroelectronics sensors buffer library driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/interrupt.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/irqreturn.h>
+
+#include <linux/iio/common/st_sensors.h>
+
+
+int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
+{
+ int i, n = 0, len;
+ u8 addr[ST_SENSORS_NUMBER_DATA_CHANNELS];
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) {
+ if (test_bit(i, indio_dev->active_scan_mask)) {
+ addr[n] = indio_dev->channels[i].address;
+ n++;
+ }
+ }
+ switch (n) {
+ case 1:
+ len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
+ addr[0], ST_SENSORS_BYTE_FOR_CHANNEL, buf,
+ sdata->multiread_bit);
+ break;
+ case 2:
+ if ((addr[1] - addr[0]) == ST_SENSORS_BYTE_FOR_CHANNEL) {
+ len = sdata->tf->read_multiple_byte(&sdata->tb,
+ sdata->dev, addr[0],
+ ST_SENSORS_BYTE_FOR_CHANNEL*n,
+ buf, sdata->multiread_bit);
+ } else {
+ u8 rx_array[ST_SENSORS_BYTE_FOR_CHANNEL*
+ ST_SENSORS_NUMBER_DATA_CHANNELS];
+ len = sdata->tf->read_multiple_byte(&sdata->tb,
+ sdata->dev, addr[0],
+ ST_SENSORS_BYTE_FOR_CHANNEL*
+ ST_SENSORS_NUMBER_DATA_CHANNELS,
+ rx_array, sdata->multiread_bit);
+ if (len < 0)
+ goto read_data_channels_error;
+
+ for (i = 0; i < n * ST_SENSORS_NUMBER_DATA_CHANNELS;
+ i++) {
+ if (i < n)
+ buf[i] = rx_array[i];
+ else
+ buf[i] = rx_array[n + i];
+ }
+ len = ST_SENSORS_BYTE_FOR_CHANNEL*n;
+ }
+ break;
+ case 3:
+ len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
+ addr[0], ST_SENSORS_BYTE_FOR_CHANNEL*
+ ST_SENSORS_NUMBER_DATA_CHANNELS,
+ buf, sdata->multiread_bit);
+ break;
+ default:
+ len = -EINVAL;
+ goto read_data_channels_error;
+ }
+ if (len != ST_SENSORS_BYTE_FOR_CHANNEL*n) {
+ len = -EIO;
+ goto read_data_channels_error;
+ }
+
+read_data_channels_error:
+ return len;
+}
+EXPORT_SYMBOL(st_sensors_get_buffer_element);
+
+irqreturn_t st_sensors_trigger_handler(int irq, void *p)
+{
+ int len;
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
+ if (len < 0)
+ goto st_sensors_get_buffer_element_error;
+
+ if (indio_dev->scan_timestamp)
+ *(s64 *)((u8 *)sdata->buffer_data +
+ ALIGN(len, sizeof(s64))) = pf->timestamp;
+
+ iio_push_to_buffers(indio_dev, sdata->buffer_data);
+
+st_sensors_get_buffer_element_error:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(st_sensors_trigger_handler);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics ST-sensors buffer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
new file mode 100644
index 000000000000..0198324a8b0c
--- /dev/null
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -0,0 +1,446 @@
+/*
+ * STMicroelectronics sensors core library driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <asm/unaligned.h>
+
+#include <linux/iio/common/st_sensors.h>
+
+
+#define ST_SENSORS_WAI_ADDRESS 0x0f
+
+static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
+ u8 reg_addr, u8 mask, u8 data)
+{
+ int err;
+ u8 new_data;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data);
+ if (err < 0)
+ goto st_sensors_write_data_with_mask_error;
+
+ new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask));
+ err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data);
+
+st_sensors_write_data_with_mask_error:
+ return err;
+}
+
+static int st_sensors_match_odr(struct st_sensors *sensor,
+ unsigned int odr, struct st_sensor_odr_avl *odr_out)
+{
+ int i, ret = -EINVAL;
+
+ for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
+ if (sensor->odr.odr_avl[i].hz == 0)
+ goto st_sensors_match_odr_error;
+
+ if (sensor->odr.odr_avl[i].hz == odr) {
+ odr_out->hz = sensor->odr.odr_avl[i].hz;
+ odr_out->value = sensor->odr.odr_avl[i].value;
+ ret = 0;
+ break;
+ }
+ }
+
+st_sensors_match_odr_error:
+ return ret;
+}
+
+int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
+{
+ int err;
+ struct st_sensor_odr_avl odr_out;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ err = st_sensors_match_odr(sdata->sensor, odr, &odr_out);
+ if (err < 0)
+ goto st_sensors_match_odr_error;
+
+ if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
+ (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
+ if (sdata->enabled == true) {
+ err = st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor->odr.addr,
+ sdata->sensor->odr.mask,
+ odr_out.value);
+ } else {
+ err = 0;
+ }
+ } else {
+ err = st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor->odr.addr, sdata->sensor->odr.mask,
+ odr_out.value);
+ }
+ if (err >= 0)
+ sdata->odr = odr_out.hz;
+
+st_sensors_match_odr_error:
+ return err;
+}
+EXPORT_SYMBOL(st_sensors_set_odr);
+
+static int st_sensors_match_fs(struct st_sensors *sensor,
+ unsigned int fs, int *index_fs_avl)
+{
+ int i, ret = -EINVAL;
+
+ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
+ if (sensor->fs.fs_avl[i].num == 0)
+ goto st_sensors_match_odr_error;
+
+ if (sensor->fs.fs_avl[i].num == fs) {
+ *index_fs_avl = i;
+ ret = 0;
+ break;
+ }
+ }
+
+st_sensors_match_odr_error:
+ return ret;
+}
+
+static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
+{
+ int err, i;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ err = st_sensors_match_fs(sdata->sensor, fs, &i);
+ if (err < 0)
+ goto st_accel_set_fullscale_error;
+
+ err = st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor->fs.addr,
+ sdata->sensor->fs.mask,
+ sdata->sensor->fs.fs_avl[i].value);
+ if (err < 0)
+ goto st_accel_set_fullscale_error;
+
+ sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
+ &sdata->sensor->fs.fs_avl[i];
+ return err;
+
+st_accel_set_fullscale_error:
+ dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
+ return err;
+}
+
+int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
+{
+ bool found;
+ u8 tmp_value;
+ int err = -EINVAL;
+ struct st_sensor_odr_avl odr_out;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ if (enable) {
+ found = false;
+ tmp_value = sdata->sensor->pw.value_on;
+ if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
+ (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
+ err = st_sensors_match_odr(sdata->sensor,
+ sdata->odr, &odr_out);
+ if (err < 0)
+ goto set_enable_error;
+ tmp_value = odr_out.value;
+ found = true;
+ }
+ err = st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor->pw.addr,
+ sdata->sensor->pw.mask, tmp_value);
+ if (err < 0)
+ goto set_enable_error;
+
+ sdata->enabled = true;
+
+ if (found)
+ sdata->odr = odr_out.hz;
+ } else {
+ err = st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor->pw.addr,
+ sdata->sensor->pw.mask,
+ sdata->sensor->pw.value_off);
+ if (err < 0)
+ goto set_enable_error;
+
+ sdata->enabled = false;
+ }
+
+set_enable_error:
+ return err;
+}
+EXPORT_SYMBOL(st_sensors_set_enable);
+
+int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ return st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor->enable_axis.addr,
+ sdata->sensor->enable_axis.mask, axis_enable);
+}
+EXPORT_SYMBOL(st_sensors_set_axis_enable);
+
+int st_sensors_init_sensor(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ mutex_init(&sdata->tb.buf_lock);
+
+ err = st_sensors_set_enable(indio_dev, false);
+ if (err < 0)
+ goto init_error;
+
+ err = st_sensors_set_fullscale(indio_dev,
+ sdata->current_fullscale->num);
+ if (err < 0)
+ goto init_error;
+
+ err = st_sensors_set_odr(indio_dev, sdata->odr);
+ if (err < 0)
+ goto init_error;
+
+ /* set BDU */
+ err = st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);
+ if (err < 0)
+ goto init_error;
+
+ err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
+
+init_error:
+ return err;
+}
+EXPORT_SYMBOL(st_sensors_init_sensor);
+
+int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
+{
+ int err;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ /* Enable/Disable the interrupt generator 1. */
+ if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {
+ err = st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor->drdy_irq.ig1.en_addr,
+ sdata->sensor->drdy_irq.ig1.en_mask, (int)enable);
+ if (err < 0)
+ goto st_accel_set_dataready_irq_error;
+ }
+
+ /* Enable/Disable the interrupt generator for data ready. */
+ err = st_sensors_write_data_with_mask(indio_dev,
+ sdata->sensor->drdy_irq.addr,
+ sdata->sensor->drdy_irq.mask, (int)enable);
+
+st_accel_set_dataready_irq_error:
+ return err;
+}
+EXPORT_SYMBOL(st_sensors_set_dataready_irq);
+
+int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
+{
+ int err = -EINVAL, i;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
+ if ((sdata->sensor->fs.fs_avl[i].gain == scale) &&
+ (sdata->sensor->fs.fs_avl[i].gain != 0)) {
+ err = 0;
+ break;
+ }
+ }
+ if (err < 0)
+ goto st_sensors_match_scale_error;
+
+ err = st_sensors_set_fullscale(indio_dev,
+ sdata->sensor->fs.fs_avl[i].num);
+
+st_sensors_match_scale_error:
+ return err;
+}
+EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
+
+static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
+ u8 ch_addr, int *data)
+{
+ int err;
+ u8 outdata[ST_SENSORS_BYTE_FOR_CHANNEL];
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
+ ch_addr, ST_SENSORS_BYTE_FOR_CHANNEL,
+ outdata, sdata->multiread_bit);
+ if (err < 0)
+ goto read_error;
+
+ *data = (s16)get_unaligned_le16(outdata);
+
+read_error:
+ return err;
+}
+
+int st_sensors_read_info_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *ch, int *val)
+{
+ int err;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ mutex_lock(&indio_dev->mlock);
+ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
+ err = -EBUSY;
+ goto read_error;
+ } else {
+ err = st_sensors_set_enable(indio_dev, true);
+ if (err < 0)
+ goto read_error;
+
+ msleep((sdata->sensor->bootime * 1000) / sdata->odr);
+ err = st_sensors_read_axis_data(indio_dev, ch->address, val);
+ if (err < 0)
+ goto read_error;
+
+ *val = *val >> ch->scan_type.shift;
+ }
+ mutex_unlock(&indio_dev->mlock);
+
+ return err;
+
+read_error:
+ mutex_unlock(&indio_dev->mlock);
+ return err;
+}
+EXPORT_SYMBOL(st_sensors_read_info_raw);
+
+int st_sensors_check_device_support(struct iio_dev *indio_dev,
+ int num_sensors_list, const struct st_sensors *sensors)
+{
+ u8 wai;
+ int i, n, err;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
+ ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
+ if (err < 0) {
+ dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
+ goto read_wai_error;
+ }
+
+ for (i = 0; i < num_sensors_list; i++) {
+ if (sensors[i].wai == wai)
+ break;
+ }
+ if (i == num_sensors_list)
+ goto device_not_supported;
+
+ for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) {
+ if (strcmp(indio_dev->name,
+ &sensors[i].sensors_supported[n][0]) == 0)
+ break;
+ }
+ if (n == ARRAY_SIZE(sensors[i].sensors_supported)) {
+ dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n");
+ goto sensor_name_mismatch;
+ }
+
+ sdata->sensor = (struct st_sensors *)&sensors[i];
+
+ return i;
+
+device_not_supported:
+ dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
+sensor_name_mismatch:
+ err = -ENODEV;
+read_wai_error:
+ return err;
+}
+EXPORT_SYMBOL(st_sensors_check_device_support);
+
+ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev));
+
+ return sprintf(buf, "%d\n", adata->odr);
+}
+EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency);
+
+ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ int err;
+ unsigned int odr;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+
+ err = kstrtoint(buf, 10, &odr);
+ if (err < 0)
+ goto conversion_error;
+
+ mutex_lock(&indio_dev->mlock);
+ err = st_sensors_set_odr(indio_dev, odr);
+ mutex_unlock(&indio_dev->mlock);
+
+conversion_error:
+ return err < 0 ? err : size;
+}
+EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency);
+
+ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, len = 0;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ mutex_lock(&indio_dev->mlock);
+ for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
+ if (sdata->sensor->odr.odr_avl[i].hz == 0)
+ break;
+
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+ sdata->sensor->odr.odr_avl[i].hz);
+ }
+ mutex_unlock(&indio_dev->mlock);
+ buf[len - 1] = '\n';
+
+ return len;
+}
+EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
+
+ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, len = 0;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ mutex_lock(&indio_dev->mlock);
+ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
+ if (sdata->sensor->fs.fs_avl[i].num == 0)
+ break;
+
+ len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
+ sdata->sensor->fs.fs_avl[i].gain);
+ }
+ mutex_unlock(&indio_dev->mlock);
+ buf[len - 1] = '\n';
+
+ return len;
+}
+EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c
new file mode 100644
index 000000000000..38af9440c103
--- /dev/null
+++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c
@@ -0,0 +1,81 @@
+/*
+ * STMicroelectronics sensors i2c library driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/iio/iio.h>
+
+#include <linux/iio/common/st_sensors_i2c.h>
+
+
+#define ST_SENSORS_I2C_MULTIREAD 0x80
+
+static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ return to_i2c_client(sdata->dev)->irq;
+}
+
+static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb,
+ struct device *dev, u8 reg_addr, u8 *res_byte)
+{
+ int err;
+
+ err = i2c_smbus_read_byte_data(to_i2c_client(dev), reg_addr);
+ if (err < 0)
+ goto st_accel_i2c_read_byte_error;
+
+ *res_byte = err & 0xff;
+
+st_accel_i2c_read_byte_error:
+ return err < 0 ? err : 0;
+}
+
+static int st_sensors_i2c_read_multiple_byte(
+ struct st_sensor_transfer_buffer *tb, struct device *dev,
+ u8 reg_addr, int len, u8 *data, bool multiread_bit)
+{
+ if (multiread_bit)
+ reg_addr |= ST_SENSORS_I2C_MULTIREAD;
+
+ return i2c_smbus_read_i2c_block_data(to_i2c_client(dev),
+ reg_addr, len, data);
+}
+
+static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb,
+ struct device *dev, u8 reg_addr, u8 data)
+{
+ return i2c_smbus_write_byte_data(to_i2c_client(dev), reg_addr, data);
+}
+
+static const struct st_sensor_transfer_function st_sensors_tf_i2c = {
+ .read_byte = st_sensors_i2c_read_byte,
+ .write_byte = st_sensors_i2c_write_byte,
+ .read_multiple_byte = st_sensors_i2c_read_multiple_byte,
+};
+
+void st_sensors_i2c_configure(struct iio_dev *indio_dev,
+ struct i2c_client *client, struct st_sensor_data *sdata)
+{
+ i2c_set_clientdata(client, indio_dev);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = client->name;
+
+ sdata->tf = &st_sensors_tf_i2c;
+ sdata->get_irq_data_ready = st_sensors_i2c_get_irq;
+}
+EXPORT_SYMBOL(st_sensors_i2c_configure);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c
new file mode 100644
index 000000000000..f0aa2f105222
--- /dev/null
+++ b/drivers/iio/common/st_sensors/st_sensors_spi.c
@@ -0,0 +1,128 @@
+/*
+ * STMicroelectronics sensors spi library driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/iio/iio.h>
+
+#include <linux/iio/common/st_sensors_spi.h>
+
+
+#define ST_SENSORS_SPI_MULTIREAD 0xc0
+#define ST_SENSORS_SPI_READ 0x80
+
+static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ return to_spi_device(sdata->dev)->irq;
+}
+
+static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
+ struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit)
+{
+ struct spi_message msg;
+ int err;
+
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = tb->tx_buf,
+ .bits_per_word = 8,
+ .len = 1,
+ },
+ {
+ .rx_buf = tb->rx_buf,
+ .bits_per_word = 8,
+ .len = len,
+ }
+ };
+
+ mutex_lock(&tb->buf_lock);
+ if ((multiread_bit) && (len > 1))
+ tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD;
+ else
+ tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ err = spi_sync(to_spi_device(dev), &msg);
+ if (err)
+ goto acc_spi_read_error;
+
+ memcpy(data, tb->rx_buf, len*sizeof(u8));
+ mutex_unlock(&tb->buf_lock);
+ return len;
+
+acc_spi_read_error:
+ mutex_unlock(&tb->buf_lock);
+ return err;
+}
+
+static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb,
+ struct device *dev, u8 reg_addr, u8 *res_byte)
+{
+ return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false);
+}
+
+static int st_sensors_spi_read_multiple_byte(
+ struct st_sensor_transfer_buffer *tb, struct device *dev,
+ u8 reg_addr, int len, u8 *data, bool multiread_bit)
+{
+ return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit);
+}
+
+static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
+ struct device *dev, u8 reg_addr, u8 data)
+{
+ struct spi_message msg;
+ int err;
+
+ struct spi_transfer xfers = {
+ .tx_buf = tb->tx_buf,
+ .bits_per_word = 8,
+ .len = 2,
+ };
+
+ mutex_lock(&tb->buf_lock);
+ tb->tx_buf[0] = reg_addr;
+ tb->tx_buf[1] = data;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers, &msg);
+ err = spi_sync(to_spi_device(dev), &msg);
+ mutex_unlock(&tb->buf_lock);
+
+ return err;
+}
+
+static const struct st_sensor_transfer_function st_sensors_tf_spi = {
+ .read_byte = st_sensors_spi_read_byte,
+ .write_byte = st_sensors_spi_write_byte,
+ .read_multiple_byte = st_sensors_spi_read_multiple_byte,
+};
+
+void st_sensors_spi_configure(struct iio_dev *indio_dev,
+ struct spi_device *spi, struct st_sensor_data *sdata)
+{
+ spi_set_drvdata(spi, indio_dev);
+
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = spi->modalias;
+
+ sdata->tf = &st_sensors_tf_spi;
+ sdata->get_irq_data_ready = st_sensors_spi_get_irq;
+}
+EXPORT_SYMBOL(st_sensors_spi_configure);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics ST-sensors spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
new file mode 100644
index 000000000000..139ed030abb0
--- /dev/null
+++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
@@ -0,0 +1,77 @@
+/*
+ * STMicroelectronics sensors trigger library driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/interrupt.h>
+
+#include <linux/iio/common/st_sensors.h>
+
+
+int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
+ const struct iio_trigger_ops *trigger_ops)
+{
+ int err;
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
+ if (sdata->trig == NULL) {
+ err = -ENOMEM;
+ dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
+ goto iio_trigger_alloc_error;
+ }
+
+ err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
+ iio_trigger_generic_data_rdy_poll,
+ NULL,
+ IRQF_TRIGGER_RISING,
+ sdata->trig->name,
+ sdata->trig);
+ if (err)
+ goto request_irq_error;
+
+ sdata->trig->private_data = indio_dev;
+ sdata->trig->ops = trigger_ops;
+ sdata->trig->dev.parent = sdata->dev;
+
+ err = iio_trigger_register(sdata->trig);
+ if (err < 0) {
+ dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
+ goto iio_trigger_register_error;
+ }
+ indio_dev->trig = sdata->trig;
+
+ return 0;
+
+iio_trigger_register_error:
+ free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
+request_irq_error:
+ iio_trigger_free(sdata->trig);
+iio_trigger_alloc_error:
+ return err;
+}
+EXPORT_SYMBOL(st_sensors_allocate_trigger);
+
+void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+ iio_trigger_unregister(sdata->trig);
+ free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
+ iio_trigger_free(sdata->trig);
+}
+EXPORT_SYMBOL(st_sensors_deallocate_trigger);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c
index 54b46fd3aede..92771217f665 100644
--- a/drivers/iio/dac/ad5360.c
+++ b/drivers/iio/dac/ad5360.c
@@ -213,7 +213,6 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
unsigned int addr)
{
struct ad5360_state *st = iio_priv(indio_dev);
- struct spi_message m;
int ret;
struct spi_transfer t[] = {
{
@@ -226,10 +225,6 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
},
};
- spi_message_init(&m);
- spi_message_add_tail(&t[0], &m);
- spi_message_add_tail(&t[1], &m);
-
mutex_lock(&indio_dev->mlock);
st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) |
@@ -237,7 +232,7 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
AD5360_READBACK_TYPE(type) |
AD5360_READBACK_ADDR(addr));
- ret = spi_sync(st->spi, &m);
+ ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret >= 0)
ret = be32_to_cpu(st->data[1].d32) & 0xffff;
diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c
index 43be948db83e..6b86a638dad0 100644
--- a/drivers/iio/dac/ad5421.c
+++ b/drivers/iio/dac/ad5421.c
@@ -127,7 +127,6 @@ static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg,
static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg)
{
struct ad5421_state *st = iio_priv(indio_dev);
- struct spi_message m;
int ret;
struct spi_transfer t[] = {
{
@@ -140,15 +139,11 @@ static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg)
},
};
- spi_message_init(&m);
- spi_message_add_tail(&t[0], &m);
- spi_message_add_tail(&t[1], &m);
-
mutex_lock(&indio_dev->mlock);
st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
- ret = spi_sync(st->spi, &m);
+ ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret >= 0)
ret = be32_to_cpu(st->data[1].d32) & 0xffff;
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index 0661829f2773..e5e59749f109 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -85,11 +85,7 @@ static int ad5504_spi_read(struct spi_device *spi, u8 addr)
.rx_buf = &val,
.len = 2,
};
- struct spi_message m;
-
- spi_message_init(&m);
- spi_message_add_tail(&t, &m);
- ret = spi_sync(spi, &m);
+ ret = spi_sync_transfer(spi, &t, 1);
if (ret < 0)
return ret;
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index ca9609d7a15c..5e554af21703 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -117,18 +117,13 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
.len = 3,
},
};
- struct spi_message m;
int ret;
- spi_message_init(&m);
- spi_message_add_tail(&t[0], &m);
- spi_message_add_tail(&t[1], &m);
-
st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
AD5686_ADDR(addr));
st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
- ret = spi_sync(st->spi, &m);
+ ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret < 0)
return ret;
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c
index 0869bbd27d30..71faabc6b14e 100644
--- a/drivers/iio/dac/ad5755.c
+++ b/drivers/iio/dac/ad5755.c
@@ -153,7 +153,6 @@ static int ad5755_write_ctrl(struct iio_dev *indio_dev, unsigned int channel,
static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr)
{
struct ad5755_state *st = iio_priv(indio_dev);
- struct spi_message m;
int ret;
struct spi_transfer t[] = {
{
@@ -167,16 +166,12 @@ static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr)
},
};
- spi_message_init(&m);
- spi_message_add_tail(&t[0], &m);
- spi_message_add_tail(&t[1], &m);
-
mutex_lock(&indio_dev->mlock);
st->data[0].d32 = cpu_to_be32(AD5755_READ_FLAG | (addr << 16));
st->data[1].d32 = cpu_to_be32(AD5755_NOOP);
- ret = spi_sync(st->spi, &m);
+ ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret >= 0)
ret = be32_to_cpu(st->data[1].d32) & 0xffff;
diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c
index 7f9045e6daa4..5b7acd3a2c77 100644
--- a/drivers/iio/dac/ad5764.c
+++ b/drivers/iio/dac/ad5764.c
@@ -135,7 +135,6 @@ static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg,
unsigned int *val)
{
struct ad5764_state *st = iio_priv(indio_dev);
- struct spi_message m;
int ret;
struct spi_transfer t[] = {
{
@@ -148,15 +147,11 @@ static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg,
},
};
- spi_message_init(&m);
- spi_message_add_tail(&t[0], &m);
- spi_message_add_tail(&t[1], &m);
-
mutex_lock(&indio_dev->mlock);
st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
- ret = spi_sync(st->spi, &m);
+ ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret >= 0)
*val = be32_to_cpu(st->data[1].d32) & 0xffff;
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
index 6407b5407ddd..8dfd3da8a07b 100644
--- a/drivers/iio/dac/ad5791.c
+++ b/drivers/iio/dac/ad5791.c
@@ -125,7 +125,6 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val)
u8 d8[4];
} data[3];
int ret;
- struct spi_message msg;
struct spi_transfer xfers[] = {
{
.tx_buf = &data[0].d8[1],
@@ -144,10 +143,7 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val)
AD5791_ADDR(addr));
data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP));
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
- ret = spi_sync(spi, &msg);
+ ret = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers));
*val = be32_to_cpu(data[2].d32);
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 80307473e3a9..1ea132e239ea 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -287,7 +287,6 @@ struct ad9523_state {
static int ad9523_read(struct iio_dev *indio_dev, unsigned addr)
{
struct ad9523_state *st = iio_priv(indio_dev);
- struct spi_message m;
int ret;
/* We encode the register size 1..3 bytes into the register address.
@@ -305,15 +304,11 @@ static int ad9523_read(struct iio_dev *indio_dev, unsigned addr)
},
};
- spi_message_init(&m);
- spi_message_add_tail(&t[0], &m);
- spi_message_add_tail(&t[1], &m);
-
st->data[0].d32 = cpu_to_be32(AD9523_READ |
AD9523_CNT(AD9523_TRANSF_LEN(addr)) |
AD9523_ADDR(addr));
- ret = spi_sync(st->spi, &m);
+ ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret < 0)
dev_err(&indio_dev->dev, "read failed (%d)", ret);
else
@@ -326,7 +321,6 @@ static int ad9523_read(struct iio_dev *indio_dev, unsigned addr)
static int ad9523_write(struct iio_dev *indio_dev, unsigned addr, unsigned val)
{
struct ad9523_state *st = iio_priv(indio_dev);
- struct spi_message m;
int ret;
struct spi_transfer t[] = {
{
@@ -338,16 +332,12 @@ static int ad9523_write(struct iio_dev *indio_dev, unsigned addr, unsigned val)
},
};
- spi_message_init(&m);
- spi_message_add_tail(&t[0], &m);
- spi_message_add_tail(&t[1], &m);
-
st->data[0].d32 = cpu_to_be32(AD9523_WRITE |
AD9523_CNT(AD9523_TRANSF_LEN(addr)) |
AD9523_ADDR(addr));
st->data[1].d32 = cpu_to_be32(val);
- ret = spi_sync(st->spi, &m);
+ ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret < 0)
dev_err(&indio_dev->dev, "write failed (%d)", ret);
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
index 96b68f63a902..6be4628faffe 100644
--- a/drivers/iio/gyro/Kconfig
+++ b/drivers/iio/gyro/Kconfig
@@ -3,6 +3,13 @@
#
menu "Digital gyroscope sensors"
+config ADIS16080
+ tristate "Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices ADIS16080, ADIS16100 Yaw
+ Rate Gyroscope with SPI.
+
config ADIS16136
tristate "Analog devices ADIS16136 and similar gyroscopes driver"
depends on SPI_MASTER
@@ -12,6 +19,16 @@ config ADIS16136
Say yes here to build support for the Analog Devices ADIS16133, ADIS16135,
ADIS16136 gyroscope devices.
+config ADXRS450
+ tristate "Analog Devices ADXRS450/3 Digital Output Gyroscope SPI driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices ADXRS450 and ADXRS453
+ programmable digital output gyroscope.
+
+ This driver can also be built as a module. If so, the module
+ will be called adxrs450.
+
config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
@@ -23,4 +40,42 @@ config HID_SENSOR_GYRO_3D
Say yes here to build support for the HID SENSOR
Gyroscope 3D.
+config IIO_ST_GYRO_3AXIS
+ tristate "STMicroelectronics gyroscopes 3-Axis Driver"
+ depends on (I2C || SPI_MASTER) && SYSFS
+ select IIO_ST_SENSORS_CORE
+ select IIO_ST_GYRO_I2C_3AXIS if (I2C)
+ select IIO_ST_GYRO_SPI_3AXIS if (SPI_MASTER)
+ select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
+ select IIO_ST_GYRO_BUFFER if (IIO_TRIGGERED_BUFFER)
+ help
+ Say yes here to build support for STMicroelectronics gyroscopes:
+ L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330.
+
+ This driver can also be built as a module. If so, will be created
+ these modules:
+ - st_gyro (core functions for the driver [it is mandatory]);
+ - st_gyro_i2c (necessary for the I2C devices [optional*]);
+ - st_gyro_spi (necessary for the SPI devices [optional*]);
+
+ (*) one of these is necessary to do something.
+
+config IIO_ST_GYRO_I2C_3AXIS
+ tristate
+ depends on IIO_ST_GYRO_3AXIS
+ depends on IIO_ST_SENSORS_I2C
+
+config IIO_ST_GYRO_SPI_3AXIS
+ tristate
+ depends on IIO_ST_GYRO_3AXIS
+ depends on IIO_ST_SENSORS_SPI
+
+config ITG3200
+ tristate "InvenSense ITG3200 Digital 3-Axis Gyroscope I2C driver"
+ depends on I2C
+ select IIO_TRIGGERED_BUFFER if IIO_BUFFER
+ help
+ Say yes here to add support for the InvenSense ITG3200 digital
+ 3-axis gyroscope sensor.
+
endmenu
diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
index 702a058907e3..225d289082e6 100644
--- a/drivers/iio/gyro/Makefile
+++ b/drivers/iio/gyro/Makefile
@@ -2,5 +2,19 @@
# Makefile for industrial I/O gyroscope sensor drivers
#
+obj-$(CONFIG_ADIS16080) += adis16080.o
obj-$(CONFIG_ADIS16136) += adis16136.o
+obj-$(CONFIG_ADXRS450) += adxrs450.o
+
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
+
+itg3200-y := itg3200_core.o
+itg3200-$(CONFIG_IIO_BUFFER) += itg3200_buffer.o
+obj-$(CONFIG_ITG3200) += itg3200.o
+
+obj-$(CONFIG_IIO_ST_GYRO_3AXIS) += st_gyro.o
+st_gyro-y := st_gyro_core.o
+st_gyro-$(CONFIG_IIO_BUFFER) += st_gyro_buffer.o
+
+obj-$(CONFIG_IIO_ST_GYRO_I2C_3AXIS) += st_gyro_i2c.o
+obj-$(CONFIG_IIO_ST_GYRO_SPI_3AXIS) += st_gyro_spi.o
diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/iio/gyro/adis16080.c
index 41d7350d030f..1861287911f1 100644
--- a/drivers/staging/iio/gyro/adis16080_core.c
+++ b/drivers/iio/gyro/adis16080.c
@@ -29,48 +29,50 @@
#define ADIS16080_DIN_WRITE (1 << 15)
+struct adis16080_chip_info {
+ int scale_val;
+ int scale_val2;
+};
+
/**
* struct adis16080_state - device instance specific data
* @us: actual spi_device to write data
+ * @info: chip specific parameters
* @buf: transmit or receive buffer
- * @buf_lock: mutex to protect tx and rx
**/
struct adis16080_state {
struct spi_device *us;
- struct mutex buf_lock;
+ const struct adis16080_chip_info *info;
- u8 buf[2] ____cacheline_aligned;
+ __be16 buf ____cacheline_aligned;
};
-static int adis16080_spi_write(struct iio_dev *indio_dev,
- u16 val)
+static int adis16080_read_sample(struct iio_dev *indio_dev,
+ u16 addr, int *val)
{
- int ret;
struct adis16080_state *st = iio_priv(indio_dev);
-
- mutex_lock(&st->buf_lock);
- st->buf[0] = val >> 8;
- st->buf[1] = val;
-
- ret = spi_write(st->us, st->buf, 2);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-static int adis16080_spi_read(struct iio_dev *indio_dev,
- u16 *val)
-{
+ struct spi_message m;
int ret;
- struct adis16080_state *st = iio_priv(indio_dev);
+ struct spi_transfer t[] = {
+ {
+ .tx_buf = &st->buf,
+ .len = 2,
+ .cs_change = 1,
+ }, {
+ .rx_buf = &st->buf,
+ .len = 2,
+ },
+ };
- mutex_lock(&st->buf_lock);
+ st->buf = cpu_to_be16(addr | ADIS16080_DIN_WRITE);
- ret = spi_read(st->us, st->buf, 2);
+ spi_message_init(&m);
+ spi_message_add_tail(&t[0], &m);
+ spi_message_add_tail(&t[1], &m);
+ ret = spi_sync(st->us, &m);
if (ret == 0)
- *val = sign_extend32(((st->buf[0] & 0xF) << 8) | st->buf[1], 11);
- mutex_unlock(&st->buf_lock);
+ *val = sign_extend32(be16_to_cpu(st->buf), 11);
return ret;
}
@@ -81,28 +83,52 @@ static int adis16080_read_raw(struct iio_dev *indio_dev,
int *val2,
long mask)
{
- int ret = -EINVAL;
- u16 ut = 0;
- /* Take the iio_dev status lock */
+ struct adis16080_state *st = iio_priv(indio_dev);
+ int ret;
- mutex_lock(&indio_dev->mlock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = adis16080_spi_write(indio_dev,
- chan->address |
- ADIS16080_DIN_WRITE);
- if (ret < 0)
- break;
- ret = adis16080_spi_read(indio_dev, &ut);
- if (ret < 0)
- break;
- *val = ut;
- ret = IIO_VAL_INT;
+ mutex_lock(&indio_dev->mlock);
+ ret = adis16080_read_sample(indio_dev, chan->address, val);
+ mutex_unlock(&indio_dev->mlock);
+ return ret ? ret : IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ *val = st->info->scale_val;
+ *val2 = st->info->scale_val2;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_VOLTAGE:
+ /* VREF = 5V, 12 bits */
+ *val = 5000;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_TEMP:
+ /* 85 C = 585, 25 C = 0 */
+ *val = 85000 - 25000;
+ *val2 = 585;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ /* 2.5 V = 0 */
+ *val = 2048;
+ return IIO_VAL_INT;
+ case IIO_TEMP:
+ /* 85 C = 585, 25 C = 0 */
+ *val = DIV_ROUND_CLOSEST(25 * 585, 85 - 25);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
break;
}
- mutex_unlock(&indio_dev->mlock);
- return ret;
+ return -EINVAL;
}
static const struct iio_chan_spec adis16080_channels[] = {
@@ -110,25 +136,32 @@ static const struct iio_chan_spec adis16080_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = ADIS16080_DIN_GYRO,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = ADIS16080_DIN_AIN1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = ADIS16080_DIN_AIN2,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = ADIS16080_DIN_TEMP,
}
};
@@ -138,8 +171,27 @@ static const struct iio_info adis16080_info = {
.driver_module = THIS_MODULE,
};
+enum {
+ ID_ADIS16080,
+ ID_ADIS16100,
+};
+
+static const struct adis16080_chip_info adis16080_chip_info[] = {
+ [ID_ADIS16080] = {
+ /* 80 degree = 819, 819 rad = 46925 degree */
+ .scale_val = 80,
+ .scale_val2 = 46925,
+ },
+ [ID_ADIS16100] = {
+ /* 300 degree = 1230, 1230 rad = 70474 degree */
+ .scale_val = 300,
+ .scale_val2 = 70474,
+ },
+};
+
static int adis16080_probe(struct spi_device *spi)
{
+ const struct spi_device_id *id = spi_get_device_id(spi);
int ret;
struct adis16080_state *st;
struct iio_dev *indio_dev;
@@ -156,7 +208,7 @@ static int adis16080_probe(struct spi_device *spi)
/* Allocate the comms buffers */
st->us = spi;
- mutex_init(&st->buf_lock);
+ st->info = &adis16080_chip_info[id->driver_data];
indio_dev->name = spi->dev.driver->name;
indio_dev->channels = adis16080_channels;
@@ -176,7 +228,6 @@ error_ret:
return ret;
}
-/* fixme, confirm ordering in this function */
static int adis16080_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
@@ -185,6 +236,13 @@ static int adis16080_remove(struct spi_device *spi)
return 0;
}
+static const struct spi_device_id adis16080_ids[] = {
+ { "adis16080", ID_ADIS16080 },
+ { "adis16100", ID_ADIS16100 },
+ {},
+};
+MODULE_DEVICE_TABLE(spi, adis16080_ids);
+
static struct spi_driver adis16080_driver = {
.driver = {
.name = "adis16080",
@@ -192,10 +250,10 @@ static struct spi_driver adis16080_driver = {
},
.probe = adis16080_probe,
.remove = adis16080_remove,
+ .id_table = adis16080_ids,
};
module_spi_driver(adis16080_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope Driver");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:adis16080");
diff --git a/drivers/staging/iio/gyro/adxrs450_core.c b/drivers/iio/gyro/adxrs450.c
index f0ce81da8aca..5b79953f7011 100644
--- a/drivers/staging/iio/gyro/adxrs450_core.c
+++ b/drivers/iio/gyro/adxrs450.c
@@ -21,45 +21,110 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include "adxrs450.h"
+#define ADXRS450_STARTUP_DELAY 50 /* ms */
+
+/* The MSB for the spi commands */
+#define ADXRS450_SENSOR_DATA (0x20 << 24)
+#define ADXRS450_WRITE_DATA (0x40 << 24)
+#define ADXRS450_READ_DATA (0x80 << 24)
+
+#define ADXRS450_RATE1 0x00 /* Rate Registers */
+#define ADXRS450_TEMP1 0x02 /* Temperature Registers */
+#define ADXRS450_LOCST1 0x04 /* Low CST Memory Registers */
+#define ADXRS450_HICST1 0x06 /* High CST Memory Registers */
+#define ADXRS450_QUAD1 0x08 /* Quad Memory Registers */
+#define ADXRS450_FAULT1 0x0A /* Fault Registers */
+#define ADXRS450_PID1 0x0C /* Part ID Register 1 */
+#define ADXRS450_SNH 0x0E /* Serial Number Registers, 4 bytes */
+#define ADXRS450_SNL 0x10
+#define ADXRS450_DNC1 0x12 /* Dynamic Null Correction Registers */
+/* Check bits */
+#define ADXRS450_P 0x01
+#define ADXRS450_CHK 0x02
+#define ADXRS450_CST 0x04
+#define ADXRS450_PWR 0x08
+#define ADXRS450_POR 0x10
+#define ADXRS450_NVM 0x20
+#define ADXRS450_Q 0x40
+#define ADXRS450_PLL 0x80
+#define ADXRS450_UV 0x100
+#define ADXRS450_OV 0x200
+#define ADXRS450_AMP 0x400
+#define ADXRS450_FAIL 0x800
+
+#define ADXRS450_WRERR_MASK (0x7 << 29)
+
+#define ADXRS450_MAX_RX 4
+#define ADXRS450_MAX_TX 4
+
+#define ADXRS450_GET_ST(a) ((a >> 26) & 0x3)
+
+enum {
+ ID_ADXRS450,
+ ID_ADXRS453,
+};
+
+/**
+ * struct adxrs450_state - device instance specific data
+ * @us: actual spi_device
+ * @buf_lock: mutex to protect tx and rx
+ * @tx: transmit buffer
+ * @rx: receive buffer
+ **/
+struct adxrs450_state {
+ struct spi_device *us;
+ struct mutex buf_lock;
+ __be32 tx ____cacheline_aligned;
+ __be32 rx;
+
+};
/**
* adxrs450_spi_read_reg_16() - read 2 bytes from a register pair
- * @dev: device associated with child of actual iio_dev
- * @reg_address: the address of the lower of the two registers,which should be an even address,
- * Second register's address is reg_address + 1.
+ * @indio_dev: device associated with child of actual iio_dev
+ * @reg_address: the address of the lower of the two registers, which should be
+ * an even address, the second register's address is reg_address + 1.
* @val: somewhere to pass back the value read
**/
static int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev,
u8 reg_address,
u16 *val)
{
+ struct spi_message msg;
struct adxrs450_state *st = iio_priv(indio_dev);
+ u32 tx;
int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = &st->tx,
+ .bits_per_word = 8,
+ .len = sizeof(st->tx),
+ .cs_change = 1,
+ }, {
+ .rx_buf = &st->rx,
+ .bits_per_word = 8,
+ .len = sizeof(st->rx),
+ },
+ };
mutex_lock(&st->buf_lock);
- st->tx[0] = ADXRS450_READ_DATA | (reg_address >> 7);
- st->tx[1] = reg_address << 1;
- st->tx[2] = 0;
- st->tx[3] = 0;
+ tx = ADXRS450_READ_DATA | (reg_address << 17);
- if (!(hweight32(be32_to_cpu(*(u32 *)st->tx)) & 1))
- st->tx[3] |= ADXRS450_P;
+ if (!(hweight32(tx) & 1))
+ tx |= ADXRS450_P;
- ret = spi_write(st->us, st->tx, 4);
- if (ret) {
- dev_err(&st->us->dev, "problem while reading 16 bit register 0x%02x\n",
- reg_address);
- goto error_ret;
- }
- ret = spi_read(st->us, st->rx, 4);
+ st->tx = cpu_to_be32(tx);
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev, "problem while reading 16 bit register 0x%02x\n",
reg_address);
goto error_ret;
}
- *val = (be32_to_cpu(*(u32 *)st->rx) >> 5) & 0xFFFF;
+ *val = (be32_to_cpu(st->rx) >> 5) & 0xFFFF;
error_ret:
mutex_unlock(&st->buf_lock);
@@ -68,9 +133,9 @@ error_ret:
/**
* adxrs450_spi_write_reg_16() - write 2 bytes data to a register pair
- * @dev: device associated with child of actual actual iio_dev
- * @reg_address: the address of the lower of the two registers,which should be an even address,
- * Second register's address is reg_address + 1.
+ * @indio_dev: device associated with child of actual actual iio_dev
+ * @reg_address: the address of the lower of the two registers,which should be
+ * an even address, the second register's address is reg_address + 1.
* @val: value to be written.
**/
static int adxrs450_spi_write_reg_16(struct iio_dev *indio_dev,
@@ -78,55 +143,61 @@ static int adxrs450_spi_write_reg_16(struct iio_dev *indio_dev,
u16 val)
{
struct adxrs450_state *st = iio_priv(indio_dev);
+ u32 tx;
int ret;
mutex_lock(&st->buf_lock);
- st->tx[0] = ADXRS450_WRITE_DATA | reg_address >> 7;
- st->tx[1] = reg_address << 1 | val >> 15;
- st->tx[2] = val >> 7;
- st->tx[3] = val << 1;
+ tx = ADXRS450_WRITE_DATA | (reg_address << 17) | (val << 1);
- if (!(hweight32(be32_to_cpu(*(u32 *)st->tx)) & 1))
- st->tx[3] |= ADXRS450_P;
+ if (!(hweight32(tx) & 1))
+ tx |= ADXRS450_P;
- ret = spi_write(st->us, st->tx, 4);
+ st->tx = cpu_to_be32(tx);
+ ret = spi_write(st->us, &st->tx, sizeof(st->tx));
if (ret)
dev_err(&st->us->dev, "problem while writing 16 bit register 0x%02x\n",
reg_address);
- msleep(1); /* enforce sequential transfer delay 0.1ms */
+ usleep_range(100, 1000); /* enforce sequential transfer delay 0.1ms */
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adxrs450_spi_sensor_data() - read 2 bytes sensor data
- * @dev: device associated with child of actual iio_dev
+ * @indio_dev: device associated with child of actual iio_dev
* @val: somewhere to pass back the value read
**/
static int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val)
{
+ struct spi_message msg;
struct adxrs450_state *st = iio_priv(indio_dev);
int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = &st->tx,
+ .bits_per_word = 8,
+ .len = sizeof(st->tx),
+ .cs_change = 1,
+ }, {
+ .rx_buf = &st->rx,
+ .bits_per_word = 8,
+ .len = sizeof(st->rx),
+ },
+ };
mutex_lock(&st->buf_lock);
- st->tx[0] = ADXRS450_SENSOR_DATA;
- st->tx[1] = 0;
- st->tx[2] = 0;
- st->tx[3] = 0;
-
- ret = spi_write(st->us, st->tx, 4);
- if (ret) {
- dev_err(&st->us->dev, "Problem while reading sensor data\n");
- goto error_ret;
- }
+ st->tx = cpu_to_be32(ADXRS450_SENSOR_DATA);
- ret = spi_read(st->us, st->rx, 4);
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfers[0], &msg);
+ spi_message_add_tail(&xfers[1], &msg);
+ ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev, "Problem while reading sensor data\n");
goto error_ret;
}
- *val = (be32_to_cpu(*(u32 *)st->rx) >> 10) & 0xFFFF;
+ *val = (be32_to_cpu(st->rx) >> 10) & 0xFFFF;
error_ret:
mutex_unlock(&st->buf_lock);
@@ -137,35 +208,32 @@ error_ret:
* adxrs450_spi_initial() - use for initializing procedure.
* @st: device instance specific data
* @val: somewhere to pass back the value read
+ * @chk: Whether to perform fault check
**/
static int adxrs450_spi_initial(struct adxrs450_state *st,
u32 *val, char chk)
{
- struct spi_message msg;
int ret;
+ u32 tx;
struct spi_transfer xfers = {
- .tx_buf = st->tx,
- .rx_buf = st->rx,
+ .tx_buf = &st->tx,
+ .rx_buf = &st->rx,
.bits_per_word = 8,
- .len = 4,
+ .len = sizeof(st->tx),
};
mutex_lock(&st->buf_lock);
- st->tx[0] = ADXRS450_SENSOR_DATA;
- st->tx[1] = 0;
- st->tx[2] = 0;
- st->tx[3] = 0;
+ tx = ADXRS450_SENSOR_DATA;
if (chk)
- st->tx[3] |= (ADXRS450_CHK | ADXRS450_P);
- spi_message_init(&msg);
- spi_message_add_tail(&xfers, &msg);
- ret = spi_sync(st->us, &msg);
+ tx |= (ADXRS450_CHK | ADXRS450_P);
+ st->tx = cpu_to_be32(tx);
+ ret = spi_sync_transfer(st->us, &xfers, 1);
if (ret) {
dev_err(&st->us->dev, "Problem while reading initializing data\n");
goto error_ret;
}
- *val = be32_to_cpu(*(u32 *)st->rx);
+ *val = be32_to_cpu(st->rx);
error_ret:
mutex_unlock(&st->buf_lock);
@@ -185,8 +253,7 @@ static int adxrs450_initial_setup(struct iio_dev *indio_dev)
if (ret)
return ret;
if (t != 0x01)
- dev_warn(&st->us->dev, "The initial power on response "
- "is not correct! Restart without reset?\n");
+ dev_warn(&st->us->dev, "The initial power on response is not correct! Restart without reset?\n");
msleep(ADXRS450_STARTUP_DELAY);
ret = adxrs450_spi_initial(st, &t, 0);
@@ -217,20 +284,6 @@ static int adxrs450_initial_setup(struct iio_dev *indio_dev)
dev_err(&st->us->dev, "The device is not in normal status!\n");
return -EINVAL;
}
- ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_PID1, &data);
- if (ret)
- return ret;
- dev_info(&st->us->dev, "The Part ID is 0x%x\n", data);
-
- ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_SNL, &data);
- if (ret)
- return ret;
- t = data;
- ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_SNH, &data);
- if (ret)
- return ret;
- t |= data << 16;
- dev_info(&st->us->dev, "The Serial Number is 0x%x\n", t);
return 0;
}
@@ -244,9 +297,10 @@ static int adxrs450_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
+ if (val < -0x400 || val >= 0x400)
+ return -EINVAL;
ret = adxrs450_spi_write_reg_16(indio_dev,
- ADXRS450_DNC1,
- val & 0x3FF);
+ ADXRS450_DNC1, val);
break;
default:
ret = -EINVAL;
@@ -312,7 +366,7 @@ static int adxrs450_read_raw(struct iio_dev *indio_dev,
ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_DNC1, &t);
if (ret)
break;
- *val = t;
+ *val = sign_extend32(t, 9);
ret = IIO_VAL_INT;
break;
default:
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index 06e7cc35450c..fcfc83a9f861 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -28,7 +28,6 @@
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-#include "../common/hid-sensors/hid-sensor-attributes.h"
#include "../common/hid-sensors/hid-sensor-trigger.h"
/*Format: HID-SENSOR-usage_id_in_hex*/
@@ -44,7 +43,7 @@ enum gyro_3d_channel {
struct gyro_3d_state {
struct hid_sensor_hub_callbacks callbacks;
- struct hid_sensor_iio_common common_attributes;
+ struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX];
u32 gyro_val[GYRO_3D_CHANNEL_MAX];
};
diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c
new file mode 100644
index 000000000000..f667d2c8c00f
--- /dev/null
+++ b/drivers/iio/gyro/itg3200_buffer.c
@@ -0,0 +1,156 @@
+/*
+ * itg3200_buffer.c -- support InvenSense ITG3200
+ * Digital 3-Axis Gyroscope driver
+ *
+ * Copyright (c) 2011 Christian Strobel <christian.strobel@iis.fraunhofer.de>
+ * Copyright (c) 2011 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
+ * Copyright (c) 2012 Thorsten Nowak <thorsten.nowak@iis.fraunhofer.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/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/gyro/itg3200.h>
+
+
+static int itg3200_read_all_channels(struct i2c_client *i2c, __be16 *buf)
+{
+ u8 tx = 0x80 | ITG3200_REG_TEMP_OUT_H;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = i2c->addr,
+ .flags = i2c->flags,
+ .len = 1,
+ .buf = &tx,
+ },
+ {
+ .addr = i2c->addr,
+ .flags = i2c->flags | I2C_M_RD,
+ .len = ITG3200_SCAN_ELEMENTS * sizeof(s16),
+ .buf = (char *)&buf,
+ },
+ };
+
+ return i2c_transfer(i2c->adapter, msg, 2);
+}
+
+static irqreturn_t itg3200_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct itg3200 *st = iio_priv(indio_dev);
+ __be16 buf[ITG3200_SCAN_ELEMENTS + sizeof(s64)/sizeof(u16)];
+
+ int ret = itg3200_read_all_channels(st->i2c, buf);
+ if (ret < 0)
+ goto error_ret;
+
+ if (indio_dev->scan_timestamp)
+ memcpy(buf + indio_dev->scan_bytes - sizeof(s64),
+ &pf->timestamp, sizeof(pf->timestamp));
+
+ iio_push_to_buffers(indio_dev, (u8 *)buf);
+ iio_trigger_notify_done(indio_dev->trig);
+
+error_ret:
+ return IRQ_HANDLED;
+}
+
+int itg3200_buffer_configure(struct iio_dev *indio_dev)
+{
+ return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ itg3200_trigger_handler, NULL);
+}
+
+void itg3200_buffer_unconfigure(struct iio_dev *indio_dev)
+{
+ iio_triggered_buffer_cleanup(indio_dev);
+}
+
+
+static int itg3200_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct iio_dev *indio_dev = trig->private_data;
+ int ret;
+ u8 msc;
+
+ ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_IRQ_CONFIG, &msc);
+ if (ret)
+ goto error_ret;
+
+ if (state)
+ msc |= ITG3200_IRQ_DATA_RDY_ENABLE;
+ else
+ msc &= ~ITG3200_IRQ_DATA_RDY_ENABLE;
+
+ ret = itg3200_write_reg_8(indio_dev, ITG3200_REG_IRQ_CONFIG, msc);
+ if (ret)
+ goto error_ret;
+
+error_ret:
+ return ret;
+
+}
+
+static const struct iio_trigger_ops itg3200_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = &itg3200_data_rdy_trigger_set_state,
+};
+
+int itg3200_probe_trigger(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct itg3200 *st = iio_priv(indio_dev);
+
+ st->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
+ indio_dev->id);
+ if (!st->trig)
+ return -ENOMEM;
+
+ ret = request_irq(st->i2c->irq,
+ &iio_trigger_generic_data_rdy_poll,
+ IRQF_TRIGGER_RISING,
+ "itg3200_data_rdy",
+ st->trig);
+ if (ret)
+ goto error_free_trig;
+
+
+ st->trig->dev.parent = &st->i2c->dev;
+ st->trig->ops = &itg3200_trigger_ops;
+ st->trig->private_data = indio_dev;
+ ret = iio_trigger_register(st->trig);
+ if (ret)
+ goto error_free_irq;
+
+ /* select default trigger */
+ indio_dev->trig = st->trig;
+
+ return 0;
+
+error_free_irq:
+ free_irq(st->i2c->irq, st->trig);
+error_free_trig:
+ iio_trigger_free(st->trig);
+ return ret;
+}
+
+void itg3200_remove_trigger(struct iio_dev *indio_dev)
+{
+ struct itg3200 *st = iio_priv(indio_dev);
+
+ iio_trigger_unregister(st->trig);
+ free_irq(st->i2c->irq, st->trig);
+ iio_trigger_free(st->trig);
+}
diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c
new file mode 100644
index 000000000000..df2e6aa5d73b
--- /dev/null
+++ b/drivers/iio/gyro/itg3200_core.c
@@ -0,0 +1,401 @@
+/*
+ * itg3200_core.c -- support InvenSense ITG3200
+ * Digital 3-Axis Gyroscope driver
+ *
+ * Copyright (c) 2011 Christian Strobel <christian.strobel@iis.fraunhofer.de>
+ * Copyright (c) 2011 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
+ * Copyright (c) 2012 Thorsten Nowak <thorsten.nowak@iis.fraunhofer.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.
+ *
+ * TODO:
+ * - Support digital low pass filter
+ * - Support power management
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
+
+#include <linux/iio/gyro/itg3200.h>
+
+
+int itg3200_write_reg_8(struct iio_dev *indio_dev,
+ u8 reg_address, u8 val)
+{
+ struct itg3200 *st = iio_priv(indio_dev);
+
+ return i2c_smbus_write_byte_data(st->i2c, 0x80 | reg_address, val);
+}
+
+int itg3200_read_reg_8(struct iio_dev *indio_dev,
+ u8 reg_address, u8 *val)
+{
+ struct itg3200 *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(st->i2c, reg_address);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return 0;
+}
+
+static int itg3200_read_reg_s16(struct iio_dev *indio_dev, u8 lower_reg_address,
+ int *val)
+{
+ struct itg3200 *st = iio_priv(indio_dev);
+ struct i2c_client *client = st->i2c;
+ int ret;
+ s16 out;
+
+ struct i2c_msg msg[2] = {
+ {
+ .addr = client->addr,
+ .flags = client->flags,
+ .len = 1,
+ .buf = (char *)&lower_reg_address,
+ },
+ {
+ .addr = client->addr,
+ .flags = client->flags | I2C_M_RD,
+ .len = 2,
+ .buf = (char *)&out,
+ },
+ };
+
+ lower_reg_address |= 0x80;
+ ret = i2c_transfer(client->adapter, msg, 2);
+ be16_to_cpus(&out);
+ *val = out;
+
+ return (ret == 2) ? 0 : ret;
+}
+
+static int itg3200_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long info)
+{
+ int ret = 0;
+ u8 reg;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ reg = (u8)chan->address;
+ ret = itg3200_read_reg_s16(indio_dev, reg, val);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ if (chan->type == IIO_TEMP)
+ *val2 = 1000000000/280;
+ else
+ *val2 = 1214142; /* (1 / 14,375) * (PI / 180) */
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_OFFSET:
+ /* Only the temperature channel has an offset */
+ *val = 23000;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t itg3200_read_frequency(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ int ret, sps;
+ u8 val;
+
+ ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &val);
+ if (ret)
+ return ret;
+
+ sps = (val & ITG3200_DLPF_CFG_MASK) ? 1000 : 8000;
+
+ ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_SAMPLE_RATE_DIV, &val);
+ if (ret)
+ return ret;
+
+ sps /= val + 1;
+
+ return sprintf(buf, "%d\n", sps);
+}
+
+static ssize_t itg3200_write_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ unsigned val;
+ int ret;
+ u8 t;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &t);
+ if (ret)
+ goto err_ret;
+
+ if (val == 0) {
+ ret = -EINVAL;
+ goto err_ret;
+ }
+ t = ((t & ITG3200_DLPF_CFG_MASK) ? 1000u : 8000u) / val - 1;
+
+ ret = itg3200_write_reg_8(indio_dev, ITG3200_REG_SAMPLE_RATE_DIV, t);
+
+err_ret:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+
+/*
+ * Reset device and internal registers to the power-up-default settings
+ * Use the gyro clock as reference, as suggested by the datasheet
+ */
+static int itg3200_reset(struct iio_dev *indio_dev)
+{
+ struct itg3200 *st = iio_priv(indio_dev);
+ int ret;
+
+ dev_dbg(&st->i2c->dev, "reset device");
+
+ ret = itg3200_write_reg_8(indio_dev,
+ ITG3200_REG_POWER_MANAGEMENT,
+ ITG3200_RESET);
+ if (ret) {
+ dev_err(&st->i2c->dev, "error resetting device");
+ goto error_ret;
+ }
+
+ /* Wait for PLL (1ms according to datasheet) */
+ udelay(1500);
+
+ ret = itg3200_write_reg_8(indio_dev,
+ ITG3200_REG_IRQ_CONFIG,
+ ITG3200_IRQ_ACTIVE_HIGH |
+ ITG3200_IRQ_PUSH_PULL |
+ ITG3200_IRQ_LATCH_50US_PULSE |
+ ITG3200_IRQ_LATCH_CLEAR_ANY);
+
+ if (ret)
+ dev_err(&st->i2c->dev, "error init device");
+
+error_ret:
+ return ret;
+}
+
+/* itg3200_enable_full_scale() - Disables the digital low pass filter */
+static int itg3200_enable_full_scale(struct iio_dev *indio_dev)
+{
+ u8 val;
+ int ret;
+
+ ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &val);
+ if (ret)
+ goto err_ret;
+
+ val |= ITG3200_DLPF_FS_SEL_2000;
+ return itg3200_write_reg_8(indio_dev, ITG3200_REG_DLPF, val);
+
+err_ret:
+ return ret;
+}
+
+static int itg3200_initial_setup(struct iio_dev *indio_dev)
+{
+ struct itg3200 *st = iio_priv(indio_dev);
+ int ret;
+ u8 val;
+
+ ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_ADDRESS, &val);
+ if (ret)
+ goto err_ret;
+
+ if (((val >> 1) & 0x3f) != 0x34) {
+ dev_err(&st->i2c->dev, "invalid reg value 0x%02x", val);
+ ret = -ENXIO;
+ goto err_ret;
+ }
+
+ ret = itg3200_reset(indio_dev);
+ if (ret)
+ goto err_ret;
+
+ ret = itg3200_enable_full_scale(indio_dev);
+err_ret:
+ return ret;
+}
+
+#define ITG3200_TEMP_INFO_MASK (IIO_CHAN_INFO_OFFSET_SHARED_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT)
+#define ITG3200_GYRO_INFO_MASK (IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT)
+
+#define ITG3200_ST \
+ { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE }
+
+#define ITG3200_GYRO_CHAN(_mod) { \
+ .type = IIO_ANGL_VEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## _mod, \
+ .info_mask = ITG3200_GYRO_INFO_MASK, \
+ .address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \
+ .scan_index = ITG3200_SCAN_GYRO_ ## _mod, \
+ .scan_type = ITG3200_ST, \
+}
+
+static const struct iio_chan_spec itg3200_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .channel2 = IIO_NO_MOD,
+ .info_mask = ITG3200_TEMP_INFO_MASK,
+ .address = ITG3200_REG_TEMP_OUT_H,
+ .scan_index = ITG3200_SCAN_TEMP,
+ .scan_type = ITG3200_ST,
+ },
+ ITG3200_GYRO_CHAN(X),
+ ITG3200_GYRO_CHAN(Y),
+ ITG3200_GYRO_CHAN(Z),
+ IIO_CHAN_SOFT_TIMESTAMP(ITG3200_SCAN_ELEMENTS),
+};
+
+/* IIO device attributes */
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, itg3200_read_frequency,
+ itg3200_write_frequency);
+
+static struct attribute *itg3200_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group itg3200_attribute_group = {
+ .attrs = itg3200_attributes,
+};
+
+static const struct iio_info itg3200_info = {
+ .attrs = &itg3200_attribute_group,
+ .read_raw = &itg3200_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static const unsigned long itg3200_available_scan_masks[] = { 0xffffffff, 0x0 };
+
+static int itg3200_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct itg3200 *st;
+ struct iio_dev *indio_dev;
+
+ dev_dbg(&client->dev, "probe I2C dev with IRQ %i", client->irq);
+
+ indio_dev = iio_device_alloc(sizeof(*st));
+ if (indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ st = iio_priv(indio_dev);
+
+ i2c_set_clientdata(client, indio_dev);
+ st->i2c = client;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = client->dev.driver->name;
+ indio_dev->channels = itg3200_channels;
+ indio_dev->num_channels = ARRAY_SIZE(itg3200_channels);
+ indio_dev->available_scan_masks = itg3200_available_scan_masks;
+ indio_dev->info = &itg3200_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = itg3200_buffer_configure(indio_dev);
+ if (ret)
+ goto error_free_dev;
+
+ if (client->irq) {
+ ret = itg3200_probe_trigger(indio_dev);
+ if (ret)
+ goto error_unconfigure_buffer;
+ }
+
+ ret = itg3200_initial_setup(indio_dev);
+ if (ret)
+ goto error_remove_trigger;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_remove_trigger;
+
+ return 0;
+
+error_remove_trigger:
+ if (client->irq)
+ itg3200_remove_trigger(indio_dev);
+error_unconfigure_buffer:
+ itg3200_buffer_unconfigure(indio_dev);
+error_free_dev:
+ iio_device_free(indio_dev);
+error_ret:
+ return ret;
+}
+
+static int itg3200_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ iio_device_unregister(indio_dev);
+
+ if (client->irq)
+ itg3200_remove_trigger(indio_dev);
+
+ itg3200_buffer_unconfigure(indio_dev);
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id itg3200_id[] = {
+ { "itg3200", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, itg3200_id);
+
+static struct i2c_driver itg3200_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "itg3200",
+ },
+ .id_table = itg3200_id,
+ .probe = itg3200_probe,
+ .remove = itg3200_remove,
+};
+
+module_i2c_driver(itg3200_driver);
+
+MODULE_AUTHOR("Christian Strobel <christian.strobel@iis.fraunhofer.de>");
+MODULE_DESCRIPTION("ITG3200 Gyroscope I2C driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h
new file mode 100644
index 000000000000..3ad9907bb154
--- /dev/null
+++ b/drivers/iio/gyro/st_gyro.h
@@ -0,0 +1,45 @@
+/*
+ * STMicroelectronics gyroscopes driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ * v. 1.0.0
+ * Licensed under the GPL-2.
+ */
+
+#ifndef ST_GYRO_H
+#define ST_GYRO_H
+
+#include <linux/types.h>
+#include <linux/iio/common/st_sensors.h>
+
+#define L3G4200D_GYRO_DEV_NAME "l3g4200d"
+#define LSM330D_GYRO_DEV_NAME "lsm330d_gyro"
+#define LSM330DL_GYRO_DEV_NAME "lsm330dl_gyro"
+#define LSM330DLC_GYRO_DEV_NAME "lsm330dlc_gyro"
+#define L3GD20_GYRO_DEV_NAME "l3gd20"
+#define L3GD20H_GYRO_DEV_NAME "l3gd20h"
+#define L3G4IS_GYRO_DEV_NAME "l3g4is_ui"
+#define LSM330_GYRO_DEV_NAME "lsm330_gyro"
+
+int st_gyro_common_probe(struct iio_dev *indio_dev);
+void st_gyro_common_remove(struct iio_dev *indio_dev);
+
+#ifdef CONFIG_IIO_BUFFER
+int st_gyro_allocate_ring(struct iio_dev *indio_dev);
+void st_gyro_deallocate_ring(struct iio_dev *indio_dev);
+int st_gyro_trig_set_state(struct iio_trigger *trig, bool state);
+#define ST_GYRO_TRIGGER_SET_STATE (&st_gyro_trig_set_state)
+#else /* CONFIG_IIO_BUFFER */
+static inline int st_gyro_allocate_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+static inline void st_gyro_deallocate_ring(struct iio_dev *indio_dev)
+{
+}
+#define ST_GYRO_TRIGGER_SET_STATE NULL
+#endif /* CONFIG_IIO_BUFFER */
+
+#endif /* ST_GYRO_H */
diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c
new file mode 100644
index 000000000000..da4d122ec7dc
--- /dev/null
+++ b/drivers/iio/gyro/st_gyro_buffer.c
@@ -0,0 +1,114 @@
+/*
+ * STMicroelectronics gyroscopes driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include "st_gyro.h"
+
+int st_gyro_trig_set_state(struct iio_trigger *trig, bool state)
+{
+ struct iio_dev *indio_dev = trig->private_data;
+
+ return st_sensors_set_dataready_irq(indio_dev, state);
+}
+
+static int st_gyro_buffer_preenable(struct iio_dev *indio_dev)
+{
+ int err;
+
+ err = st_sensors_set_enable(indio_dev, true);
+ if (err < 0)
+ goto st_gyro_set_enable_error;
+
+ err = iio_sw_buffer_preenable(indio_dev);
+
+st_gyro_set_enable_error:
+ return err;
+}
+
+static int st_gyro_buffer_postenable(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *gdata = iio_priv(indio_dev);
+
+ gdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+ if (gdata->buffer_data == NULL) {
+ err = -ENOMEM;
+ goto allocate_memory_error;
+ }
+
+ err = st_sensors_set_axis_enable(indio_dev,
+ (u8)indio_dev->active_scan_mask[0]);
+ if (err < 0)
+ goto st_gyro_buffer_postenable_error;
+
+ err = iio_triggered_buffer_postenable(indio_dev);
+ if (err < 0)
+ goto st_gyro_buffer_postenable_error;
+
+ return err;
+
+st_gyro_buffer_postenable_error:
+ kfree(gdata->buffer_data);
+allocate_memory_error:
+ return err;
+}
+
+static int st_gyro_buffer_predisable(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *gdata = iio_priv(indio_dev);
+
+ err = iio_triggered_buffer_predisable(indio_dev);
+ if (err < 0)
+ goto st_gyro_buffer_predisable_error;
+
+ err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
+ if (err < 0)
+ goto st_gyro_buffer_predisable_error;
+
+ err = st_sensors_set_enable(indio_dev, false);
+
+st_gyro_buffer_predisable_error:
+ kfree(gdata->buffer_data);
+ return err;
+}
+
+static const struct iio_buffer_setup_ops st_gyro_buffer_setup_ops = {
+ .preenable = &st_gyro_buffer_preenable,
+ .postenable = &st_gyro_buffer_postenable,
+ .predisable = &st_gyro_buffer_predisable,
+};
+
+int st_gyro_allocate_ring(struct iio_dev *indio_dev)
+{
+ return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ &st_sensors_trigger_handler, &st_gyro_buffer_setup_ops);
+}
+
+void st_gyro_deallocate_ring(struct iio_dev *indio_dev)
+{
+ iio_triggered_buffer_cleanup(indio_dev);
+}
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics gyroscopes buffer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
new file mode 100644
index 000000000000..fa9b24219987
--- /dev/null
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -0,0 +1,368 @@
+/*
+ * STMicroelectronics gyroscopes driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/buffer.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include "st_gyro.h"
+
+/* DEFAULT VALUE FOR SENSORS */
+#define ST_GYRO_DEFAULT_OUT_X_L_ADDR 0x28
+#define ST_GYRO_DEFAULT_OUT_Y_L_ADDR 0x2a
+#define ST_GYRO_DEFAULT_OUT_Z_L_ADDR 0x2c
+
+/* FULLSCALE */
+#define ST_GYRO_FS_AVL_250DPS 250
+#define ST_GYRO_FS_AVL_500DPS 500
+#define ST_GYRO_FS_AVL_2000DPS 2000
+
+/* CUSTOM VALUES FOR SENSOR 1 */
+#define ST_GYRO_1_WAI_EXP 0xd3
+#define ST_GYRO_1_ODR_ADDR 0x20
+#define ST_GYRO_1_ODR_MASK 0xc0
+#define ST_GYRO_1_ODR_AVL_100HZ_VAL 0x00
+#define ST_GYRO_1_ODR_AVL_200HZ_VAL 0x01
+#define ST_GYRO_1_ODR_AVL_400HZ_VAL 0x02
+#define ST_GYRO_1_ODR_AVL_800HZ_VAL 0x03
+#define ST_GYRO_1_PW_ADDR 0x20
+#define ST_GYRO_1_PW_MASK 0x08
+#define ST_GYRO_1_FS_ADDR 0x23
+#define ST_GYRO_1_FS_MASK 0x30
+#define ST_GYRO_1_FS_AVL_250_VAL 0x00
+#define ST_GYRO_1_FS_AVL_500_VAL 0x01
+#define ST_GYRO_1_FS_AVL_2000_VAL 0x02
+#define ST_GYRO_1_FS_AVL_250_GAIN IIO_DEGREE_TO_RAD(8750)
+#define ST_GYRO_1_FS_AVL_500_GAIN IIO_DEGREE_TO_RAD(17500)
+#define ST_GYRO_1_FS_AVL_2000_GAIN IIO_DEGREE_TO_RAD(70000)
+#define ST_GYRO_1_BDU_ADDR 0x23
+#define ST_GYRO_1_BDU_MASK 0x80
+#define ST_GYRO_1_DRDY_IRQ_ADDR 0x22
+#define ST_GYRO_1_DRDY_IRQ_MASK 0x08
+#define ST_GYRO_1_MULTIREAD_BIT true
+
+/* CUSTOM VALUES FOR SENSOR 2 */
+#define ST_GYRO_2_WAI_EXP 0xd4
+#define ST_GYRO_2_ODR_ADDR 0x20
+#define ST_GYRO_2_ODR_MASK 0xc0
+#define ST_GYRO_2_ODR_AVL_95HZ_VAL 0x00
+#define ST_GYRO_2_ODR_AVL_190HZ_VAL 0x01
+#define ST_GYRO_2_ODR_AVL_380HZ_VAL 0x02
+#define ST_GYRO_2_ODR_AVL_760HZ_VAL 0x03
+#define ST_GYRO_2_PW_ADDR 0x20
+#define ST_GYRO_2_PW_MASK 0x08
+#define ST_GYRO_2_FS_ADDR 0x23
+#define ST_GYRO_2_FS_MASK 0x30
+#define ST_GYRO_2_FS_AVL_250_VAL 0x00
+#define ST_GYRO_2_FS_AVL_500_VAL 0x01
+#define ST_GYRO_2_FS_AVL_2000_VAL 0x02
+#define ST_GYRO_2_FS_AVL_250_GAIN IIO_DEGREE_TO_RAD(8750)
+#define ST_GYRO_2_FS_AVL_500_GAIN IIO_DEGREE_TO_RAD(17500)
+#define ST_GYRO_2_FS_AVL_2000_GAIN IIO_DEGREE_TO_RAD(70000)
+#define ST_GYRO_2_BDU_ADDR 0x23
+#define ST_GYRO_2_BDU_MASK 0x80
+#define ST_GYRO_2_DRDY_IRQ_ADDR 0x22
+#define ST_GYRO_2_DRDY_IRQ_MASK 0x08
+#define ST_GYRO_2_MULTIREAD_BIT true
+
+static const struct iio_chan_spec st_gyro_16bit_channels[] = {
+ ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, ST_SENSORS_SCAN_X,
+ IIO_MOD_X, IIO_LE, ST_SENSORS_DEFAULT_16_REALBITS,
+ ST_GYRO_DEFAULT_OUT_X_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, ST_SENSORS_SCAN_Y,
+ IIO_MOD_Y, IIO_LE, ST_SENSORS_DEFAULT_16_REALBITS,
+ ST_GYRO_DEFAULT_OUT_Y_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, ST_SENSORS_SCAN_Z,
+ IIO_MOD_Z, IIO_LE, ST_SENSORS_DEFAULT_16_REALBITS,
+ ST_GYRO_DEFAULT_OUT_Z_L_ADDR),
+ IIO_CHAN_SOFT_TIMESTAMP(3)
+};
+
+static const struct st_sensors st_gyro_sensors[] = {
+ {
+ .wai = ST_GYRO_1_WAI_EXP,
+ .sensors_supported = {
+ [0] = L3G4200D_GYRO_DEV_NAME,
+ [1] = LSM330DL_GYRO_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
+ .odr = {
+ .addr = ST_GYRO_1_ODR_ADDR,
+ .mask = ST_GYRO_1_ODR_MASK,
+ .odr_avl = {
+ { 100, ST_GYRO_1_ODR_AVL_100HZ_VAL, },
+ { 200, ST_GYRO_1_ODR_AVL_200HZ_VAL, },
+ { 400, ST_GYRO_1_ODR_AVL_400HZ_VAL, },
+ { 800, ST_GYRO_1_ODR_AVL_800HZ_VAL, },
+ },
+ },
+ .pw = {
+ .addr = ST_GYRO_1_PW_ADDR,
+ .mask = ST_GYRO_1_PW_MASK,
+ .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .enable_axis = {
+ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+ },
+ .fs = {
+ .addr = ST_GYRO_1_FS_ADDR,
+ .mask = ST_GYRO_1_FS_MASK,
+ .fs_avl = {
+ [0] = {
+ .num = ST_GYRO_FS_AVL_250DPS,
+ .value = ST_GYRO_1_FS_AVL_250_VAL,
+ .gain = ST_GYRO_1_FS_AVL_250_GAIN,
+ },
+ [1] = {
+ .num = ST_GYRO_FS_AVL_500DPS,
+ .value = ST_GYRO_1_FS_AVL_500_VAL,
+ .gain = ST_GYRO_1_FS_AVL_500_GAIN,
+ },
+ [2] = {
+ .num = ST_GYRO_FS_AVL_2000DPS,
+ .value = ST_GYRO_1_FS_AVL_2000_VAL,
+ .gain = ST_GYRO_1_FS_AVL_2000_GAIN,
+ },
+ },
+ },
+ .bdu = {
+ .addr = ST_GYRO_1_BDU_ADDR,
+ .mask = ST_GYRO_1_BDU_MASK,
+ },
+ .drdy_irq = {
+ .addr = ST_GYRO_1_DRDY_IRQ_ADDR,
+ .mask = ST_GYRO_1_DRDY_IRQ_MASK,
+ },
+ .multi_read_bit = ST_GYRO_1_MULTIREAD_BIT,
+ .bootime = 2,
+ },
+ {
+ .wai = ST_GYRO_2_WAI_EXP,
+ .sensors_supported = {
+ [0] = L3GD20_GYRO_DEV_NAME,
+ [1] = L3GD20H_GYRO_DEV_NAME,
+ [2] = LSM330D_GYRO_DEV_NAME,
+ [3] = LSM330DLC_GYRO_DEV_NAME,
+ [4] = L3G4IS_GYRO_DEV_NAME,
+ [5] = LSM330_GYRO_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
+ .odr = {
+ .addr = ST_GYRO_2_ODR_ADDR,
+ .mask = ST_GYRO_2_ODR_MASK,
+ .odr_avl = {
+ { 95, ST_GYRO_2_ODR_AVL_95HZ_VAL, },
+ { 190, ST_GYRO_2_ODR_AVL_190HZ_VAL, },
+ { 380, ST_GYRO_2_ODR_AVL_380HZ_VAL, },
+ { 760, ST_GYRO_2_ODR_AVL_760HZ_VAL, },
+ },
+ },
+ .pw = {
+ .addr = ST_GYRO_2_PW_ADDR,
+ .mask = ST_GYRO_2_PW_MASK,
+ .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .enable_axis = {
+ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+ },
+ .fs = {
+ .addr = ST_GYRO_2_FS_ADDR,
+ .mask = ST_GYRO_2_FS_MASK,
+ .fs_avl = {
+ [0] = {
+ .num = ST_GYRO_FS_AVL_250DPS,
+ .value = ST_GYRO_2_FS_AVL_250_VAL,
+ .gain = ST_GYRO_2_FS_AVL_250_GAIN,
+ },
+ [1] = {
+ .num = ST_GYRO_FS_AVL_500DPS,
+ .value = ST_GYRO_2_FS_AVL_500_VAL,
+ .gain = ST_GYRO_2_FS_AVL_500_GAIN,
+ },
+ [2] = {
+ .num = ST_GYRO_FS_AVL_2000DPS,
+ .value = ST_GYRO_2_FS_AVL_2000_VAL,
+ .gain = ST_GYRO_2_FS_AVL_2000_GAIN,
+ },
+ },
+ },
+ .bdu = {
+ .addr = ST_GYRO_2_BDU_ADDR,
+ .mask = ST_GYRO_2_BDU_MASK,
+ },
+ .drdy_irq = {
+ .addr = ST_GYRO_2_DRDY_IRQ_ADDR,
+ .mask = ST_GYRO_2_DRDY_IRQ_MASK,
+ },
+ .multi_read_bit = ST_GYRO_2_MULTIREAD_BIT,
+ .bootime = 2,
+ },
+};
+
+static int st_gyro_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *ch, int *val,
+ int *val2, long mask)
+{
+ int err;
+ struct st_sensor_data *gdata = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ err = st_sensors_read_info_raw(indio_dev, ch, val);
+ if (err < 0)
+ goto read_error;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = gdata->current_fullscale->gain;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+
+read_error:
+ return err;
+}
+
+static int st_gyro_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+ int err;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
+static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
+static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_anglvel_scale_available);
+
+static struct attribute *st_gyro_attributes[] = {
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group st_gyro_attribute_group = {
+ .attrs = st_gyro_attributes,
+};
+
+static const struct iio_info gyro_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &st_gyro_attribute_group,
+ .read_raw = &st_gyro_read_raw,
+ .write_raw = &st_gyro_write_raw,
+};
+
+#ifdef CONFIG_IIO_TRIGGER
+static const struct iio_trigger_ops st_gyro_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = ST_GYRO_TRIGGER_SET_STATE,
+};
+#define ST_GYRO_TRIGGER_OPS (&st_gyro_trigger_ops)
+#else
+#define ST_GYRO_TRIGGER_OPS NULL
+#endif
+
+int st_gyro_common_probe(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *gdata = iio_priv(indio_dev);
+
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &gyro_info;
+
+ err = st_sensors_check_device_support(indio_dev,
+ ARRAY_SIZE(st_gyro_sensors), st_gyro_sensors);
+ if (err < 0)
+ goto st_gyro_common_probe_error;
+
+ gdata->multiread_bit = gdata->sensor->multi_read_bit;
+ indio_dev->channels = gdata->sensor->ch;
+ indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
+
+ gdata->current_fullscale = (struct st_sensor_fullscale_avl *)
+ &gdata->sensor->fs.fs_avl[0];
+ gdata->odr = gdata->sensor->odr.odr_avl[0].hz;
+
+ err = st_sensors_init_sensor(indio_dev);
+ if (err < 0)
+ goto st_gyro_common_probe_error;
+
+ if (gdata->get_irq_data_ready(indio_dev) > 0) {
+ err = st_gyro_allocate_ring(indio_dev);
+ if (err < 0)
+ goto st_gyro_common_probe_error;
+
+ err = st_sensors_allocate_trigger(indio_dev,
+ ST_GYRO_TRIGGER_OPS);
+ if (err < 0)
+ goto st_gyro_probe_trigger_error;
+ }
+
+ err = iio_device_register(indio_dev);
+ if (err)
+ goto st_gyro_device_register_error;
+
+ return err;
+
+st_gyro_device_register_error:
+ if (gdata->get_irq_data_ready(indio_dev) > 0)
+ st_sensors_deallocate_trigger(indio_dev);
+st_gyro_probe_trigger_error:
+ if (gdata->get_irq_data_ready(indio_dev) > 0)
+ st_gyro_deallocate_ring(indio_dev);
+st_gyro_common_probe_error:
+ return err;
+}
+EXPORT_SYMBOL(st_gyro_common_probe);
+
+void st_gyro_common_remove(struct iio_dev *indio_dev)
+{
+ struct st_sensor_data *gdata = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ if (gdata->get_irq_data_ready(indio_dev) > 0) {
+ st_sensors_deallocate_trigger(indio_dev);
+ st_gyro_deallocate_ring(indio_dev);
+ }
+ iio_device_free(indio_dev);
+}
+EXPORT_SYMBOL(st_gyro_common_remove);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics gyroscopes driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
new file mode 100644
index 000000000000..8a310500573d
--- /dev/null
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -0,0 +1,84 @@
+/*
+ * STMicroelectronics gyroscopes driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include <linux/iio/common/st_sensors_i2c.h>
+#include "st_gyro.h"
+
+static int st_gyro_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct st_sensor_data *gdata;
+ int err;
+
+ indio_dev = iio_device_alloc(sizeof(*gdata));
+ if (indio_dev == NULL) {
+ err = -ENOMEM;
+ goto iio_device_alloc_error;
+ }
+
+ gdata = iio_priv(indio_dev);
+ gdata->dev = &client->dev;
+
+ st_sensors_i2c_configure(indio_dev, client, gdata);
+
+ err = st_gyro_common_probe(indio_dev);
+ if (err < 0)
+ goto st_gyro_common_probe_error;
+
+ return 0;
+
+st_gyro_common_probe_error:
+ iio_device_free(indio_dev);
+iio_device_alloc_error:
+ return err;
+}
+
+static int st_gyro_i2c_remove(struct i2c_client *client)
+{
+ st_gyro_common_remove(i2c_get_clientdata(client));
+
+ return 0;
+}
+
+static const struct i2c_device_id st_gyro_id_table[] = {
+ { L3G4200D_GYRO_DEV_NAME },
+ { LSM330D_GYRO_DEV_NAME },
+ { LSM330DL_GYRO_DEV_NAME },
+ { LSM330DLC_GYRO_DEV_NAME },
+ { L3GD20_GYRO_DEV_NAME },
+ { L3GD20H_GYRO_DEV_NAME },
+ { L3G4IS_GYRO_DEV_NAME },
+ { LSM330_GYRO_DEV_NAME },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, st_gyro_id_table);
+
+static struct i2c_driver st_gyro_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "st-gyro-i2c",
+ },
+ .probe = st_gyro_i2c_probe,
+ .remove = st_gyro_i2c_remove,
+ .id_table = st_gyro_id_table,
+};
+module_i2c_driver(st_gyro_driver);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics gyroscopes i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
new file mode 100644
index 000000000000..f3540390eb22
--- /dev/null
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -0,0 +1,83 @@
+/*
+ * STMicroelectronics gyroscopes driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/iio/iio.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include <linux/iio/common/st_sensors_spi.h>
+#include "st_gyro.h"
+
+static int st_gyro_spi_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct st_sensor_data *gdata;
+ int err;
+
+ indio_dev = iio_device_alloc(sizeof(*gdata));
+ if (indio_dev == NULL) {
+ err = -ENOMEM;
+ goto iio_device_alloc_error;
+ }
+
+ gdata = iio_priv(indio_dev);
+ gdata->dev = &spi->dev;
+
+ st_sensors_spi_configure(indio_dev, spi, gdata);
+
+ err = st_gyro_common_probe(indio_dev);
+ if (err < 0)
+ goto st_gyro_common_probe_error;
+
+ return 0;
+
+st_gyro_common_probe_error:
+ iio_device_free(indio_dev);
+iio_device_alloc_error:
+ return err;
+}
+
+static int st_gyro_spi_remove(struct spi_device *spi)
+{
+ st_gyro_common_remove(spi_get_drvdata(spi));
+
+ return 0;
+}
+
+static const struct spi_device_id st_gyro_id_table[] = {
+ { L3G4200D_GYRO_DEV_NAME },
+ { LSM330D_GYRO_DEV_NAME },
+ { LSM330DL_GYRO_DEV_NAME },
+ { LSM330DLC_GYRO_DEV_NAME },
+ { L3GD20_GYRO_DEV_NAME },
+ { L3GD20H_GYRO_DEV_NAME },
+ { L3G4IS_GYRO_DEV_NAME },
+ { LSM330_GYRO_DEV_NAME },
+ {},
+};
+MODULE_DEVICE_TABLE(spi, st_gyro_id_table);
+
+static struct spi_driver st_gyro_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "st-gyro-spi",
+ },
+ .probe = st_gyro_spi_probe,
+ .remove = st_gyro_spi_remove,
+ .id_table = st_gyro_id_table,
+};
+module_spi_driver(st_gyro_driver);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics gyroscopes spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 3d79a40e916b..4f40a10cb74f 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -3,6 +3,17 @@
#
menu "Inertial measurement units"
+config ADIS16400
+ tristate "Analog Devices ADIS16400 and similar IMU SPI driver"
+ depends on SPI
+ select IIO_ADIS_LIB
+ select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
+ help
+ Say yes here to build support for Analog Devices adis16300, adis16344,
+ adis16350, adis16354, adis16355, adis16360, adis16362, adis16364,
+ adis16365, adis16400 and adis16405 triaxial inertial sensors
+ (adis16400 series also have magnetometers).
+
config ADIS16480
tristate "Analog Devices ADIS16480 and similar IMU driver"
depends on SPI
@@ -25,3 +36,5 @@ config IIO_ADIS_LIB_BUFFER
help
A set of buffer helper functions for the Analog Devices ADIS* device
family.
+
+source "drivers/iio/imu/inv_mpu6050/Kconfig"
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index cfe57638f6f9..f2f56ceaed26 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -2,9 +2,14 @@
# Makefile for Inertial Measurement Units
#
+adis16400-y := adis16400_core.o
+adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o
+obj-$(CONFIG_ADIS16400) += adis16400.o
obj-$(CONFIG_ADIS16480) += adis16480.o
adis_lib-y += adis.o
adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o
adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
+
+obj-y += inv_mpu6050/
diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h
index 7a105e966464..2f8f9d632386 100644
--- a/drivers/staging/iio/imu/adis16400.h
+++ b/drivers/iio/imu/adis16400.h
@@ -17,12 +17,11 @@
#ifndef SPI_ADIS16400_H_
#define SPI_ADIS16400_H_
+#include <linux/iio/imu/adis.h>
+
#define ADIS16400_STARTUP_DELAY 290 /* ms */
#define ADIS16400_MTEST_DELAY 90 /* ms */
-#define ADIS16400_READ_REG(a) a
-#define ADIS16400_WRITE_REG(a) ((a) | 0x80)
-
#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */
#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */
#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */
@@ -45,6 +44,9 @@
#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */
#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */
+#define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */
+#define ADIS16448_TEMP_OUT 0x18 /* Temperature output */
+
/* Calibration parameters */
#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */
#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */
@@ -75,7 +77,10 @@
#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */
#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */
+#define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */
+#define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */
#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */
+#define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */
#define ADIS16400_ERROR_ACTIVE (1<<14)
#define ADIS16400_NEW_DATA (1<<14)
@@ -96,21 +101,21 @@
#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F
/* DIAG_STAT */
-#define ADIS16400_DIAG_STAT_ZACCL_FAIL (1<<15)
-#define ADIS16400_DIAG_STAT_YACCL_FAIL (1<<14)
-#define ADIS16400_DIAG_STAT_XACCL_FAIL (1<<13)
-#define ADIS16400_DIAG_STAT_XGYRO_FAIL (1<<12)
-#define ADIS16400_DIAG_STAT_YGYRO_FAIL (1<<11)
-#define ADIS16400_DIAG_STAT_ZGYRO_FAIL (1<<10)
-#define ADIS16400_DIAG_STAT_ALARM2 (1<<9)
-#define ADIS16400_DIAG_STAT_ALARM1 (1<<8)
-#define ADIS16400_DIAG_STAT_FLASH_CHK (1<<6)
-#define ADIS16400_DIAG_STAT_SELF_TEST (1<<5)
-#define ADIS16400_DIAG_STAT_OVERFLOW (1<<4)
-#define ADIS16400_DIAG_STAT_SPI_FAIL (1<<3)
-#define ADIS16400_DIAG_STAT_FLASH_UPT (1<<2)
-#define ADIS16400_DIAG_STAT_POWER_HIGH (1<<1)
-#define ADIS16400_DIAG_STAT_POWER_LOW (1<<0)
+#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15
+#define ADIS16400_DIAG_STAT_YACCL_FAIL 14
+#define ADIS16400_DIAG_STAT_XACCL_FAIL 13
+#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12
+#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11
+#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10
+#define ADIS16400_DIAG_STAT_ALARM2 9
+#define ADIS16400_DIAG_STAT_ALARM1 8
+#define ADIS16400_DIAG_STAT_FLASH_CHK 6
+#define ADIS16400_DIAG_STAT_SELF_TEST 5
+#define ADIS16400_DIAG_STAT_OVERFLOW 4
+#define ADIS16400_DIAG_STAT_SPI_FAIL 3
+#define ADIS16400_DIAG_STAT_FLASH_UPT 2
+#define ADIS16400_DIAG_STAT_POWER_HIGH 1
+#define ADIS16400_DIAG_STAT_POWER_LOW 0
/* GLOB_CMD */
#define ADIS16400_GLOB_CMD_SW_RESET (1<<7)
@@ -126,9 +131,6 @@
#define ADIS16334_RATE_DIV_SHIFT 8
#define ADIS16334_RATE_INT_CLK BIT(0)
-#define ADIS16400_MAX_TX 24
-#define ADIS16400_MAX_RX 24
-
#define ADIS16400_SPI_SLOW (u32)(300 * 1000)
#define ADIS16400_SPI_BURST (u32)(1000 * 1000)
#define ADIS16400_SPI_FAST (u32)(2000 * 1000)
@@ -136,6 +138,9 @@
#define ADIS16400_HAS_PROD_ID BIT(0)
#define ADIS16400_NO_BURST BIT(1)
#define ADIS16400_HAS_SLOW_MODE BIT(2)
+#define ADIS16400_HAS_SERIAL_NUMBER BIT(3)
+
+struct adis16400_state;
struct adis16400_chip_info {
const struct iio_chan_spec *channels;
@@ -145,95 +150,63 @@ struct adis16400_chip_info {
unsigned int accel_scale_micro;
int temp_scale_nano;
int temp_offset;
- unsigned long default_scan_mask;
- int (*set_freq)(struct iio_dev *indio_dev, unsigned int freq);
- int (*get_freq)(struct iio_dev *indio_dev);
+ int (*set_freq)(struct adis16400_state *st, unsigned int freq);
+ int (*get_freq)(struct adis16400_state *st);
};
/**
* struct adis16400_state - device instance specific data
- * @us: actual spi_device
- * @trig: data ready trigger registered with iio
- * @tx: transmit buffer
- * @rx: receive buffer
- * @buf_lock: mutex to protect tx and rx
- * @filt_int: integer part of requested filter frequency
+ * @variant: chip variant info
+ * @filt_int: integer part of requested filter frequency
+ * @adis: adis device
**/
struct adis16400_state {
- struct spi_device *us;
- struct iio_trigger *trig;
- struct mutex buf_lock;
struct adis16400_chip_info *variant;
int filt_int;
- u8 tx[ADIS16400_MAX_TX] ____cacheline_aligned;
- u8 rx[ADIS16400_MAX_RX] ____cacheline_aligned;
+ struct adis adis;
};
-int adis16400_set_irq(struct iio_dev *indio_dev, bool enable);
-
/* At the moment triggers are only used for ring buffer
* filling. This may change!
*/
-#define ADIS16400_SCAN_SUPPLY 0
-#define ADIS16400_SCAN_GYRO_X 1
-#define ADIS16400_SCAN_GYRO_Y 2
-#define ADIS16400_SCAN_GYRO_Z 3
-#define ADIS16400_SCAN_ACC_X 4
-#define ADIS16400_SCAN_ACC_Y 5
-#define ADIS16400_SCAN_ACC_Z 6
-#define ADIS16400_SCAN_MAGN_X 7
-#define ADIS16350_SCAN_TEMP_X 7
-#define ADIS16400_SCAN_MAGN_Y 8
-#define ADIS16350_SCAN_TEMP_Y 8
-#define ADIS16400_SCAN_MAGN_Z 9
-#define ADIS16350_SCAN_TEMP_Z 9
-#define ADIS16400_SCAN_TEMP 10
-#define ADIS16350_SCAN_ADC_0 10
-#define ADIS16400_SCAN_ADC_0 11
-#define ADIS16300_SCAN_INCLI_X 12
-#define ADIS16300_SCAN_INCLI_Y 13
+enum {
+ ADIS16400_SCAN_SUPPLY,
+ ADIS16400_SCAN_GYRO_X,
+ ADIS16400_SCAN_GYRO_Y,
+ ADIS16400_SCAN_GYRO_Z,
+ ADIS16400_SCAN_ACC_X,
+ ADIS16400_SCAN_ACC_Y,
+ ADIS16400_SCAN_ACC_Z,
+ ADIS16400_SCAN_MAGN_X,
+ ADIS16400_SCAN_MAGN_Y,
+ ADIS16400_SCAN_MAGN_Z,
+ ADIS16400_SCAN_BARO,
+ ADIS16350_SCAN_TEMP_X,
+ ADIS16350_SCAN_TEMP_Y,
+ ADIS16350_SCAN_TEMP_Z,
+ ADIS16300_SCAN_INCLI_X,
+ ADIS16300_SCAN_INCLI_Y,
+ ADIS16400_SCAN_ADC,
+};
#ifdef CONFIG_IIO_BUFFER
-void adis16400_remove_trigger(struct iio_dev *indio_dev);
-int adis16400_probe_trigger(struct iio_dev *indio_dev);
ssize_t adis16400_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf);
-int adis16400_configure_ring(struct iio_dev *indio_dev);
-void adis16400_unconfigure_ring(struct iio_dev *indio_dev);
+int adis16400_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask);
+irqreturn_t adis16400_trigger_handler(int irq, void *p);
#else /* CONFIG_IIO_BUFFER */
-static inline void adis16400_remove_trigger(struct iio_dev *indio_dev)
-{
-}
-
-static inline int adis16400_probe_trigger(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline ssize_t
-adis16400_read_data_from_ring(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-static int adis16400_configure_ring(struct iio_dev *indio_dev)
-{
- return 0;
-}
-
-static inline void adis16400_unconfigure_ring(struct iio_dev *indio_dev)
-{
-}
+#define adis16400_update_scan_mode NULL
+#define adis16400_trigger_handler NULL
#endif /* CONFIG_IIO_BUFFER */
+
#endif /* SPI_ADIS16400_H_ */
diff --git a/drivers/iio/imu/adis16400_buffer.c b/drivers/iio/imu/adis16400_buffer.c
new file mode 100644
index 000000000000..054c01d6e73c
--- /dev/null
+++ b/drivers/iio/imu/adis16400_buffer.c
@@ -0,0 +1,96 @@
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/export.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#include "adis16400.h"
+
+int adis16400_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ struct adis *adis = &st->adis;
+ uint16_t *tx, *rx;
+
+ if (st->variant->flags & ADIS16400_NO_BURST)
+ return adis_update_scan_mode(indio_dev, scan_mask);
+
+ kfree(adis->xfer);
+ kfree(adis->buffer);
+
+ adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL);
+ if (!adis->xfer)
+ return -ENOMEM;
+
+ adis->buffer = kzalloc(indio_dev->scan_bytes + sizeof(u16),
+ GFP_KERNEL);
+ if (!adis->buffer)
+ return -ENOMEM;
+
+ rx = adis->buffer;
+ tx = adis->buffer + indio_dev->scan_bytes;
+
+ tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD);
+ tx[1] = 0;
+
+ adis->xfer[0].tx_buf = tx;
+ adis->xfer[0].bits_per_word = 8;
+ adis->xfer[0].len = 2;
+ adis->xfer[1].tx_buf = tx;
+ adis->xfer[1].bits_per_word = 8;
+ adis->xfer[1].len = indio_dev->scan_bytes;
+
+ spi_message_init(&adis->msg);
+ spi_message_add_tail(&adis->xfer[0], &adis->msg);
+ spi_message_add_tail(&adis->xfer[1], &adis->msg);
+
+ return 0;
+}
+
+irqreturn_t adis16400_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct adis16400_state *st = iio_priv(indio_dev);
+ struct adis *adis = &st->adis;
+ u32 old_speed_hz = st->adis.spi->max_speed_hz;
+ int ret;
+
+ if (!adis->buffer)
+ return -ENOMEM;
+
+ if (!(st->variant->flags & ADIS16400_NO_BURST) &&
+ st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) {
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST;
+ spi_setup(st->adis.spi);
+ }
+
+ ret = spi_sync(adis->spi, &adis->msg);
+ if (ret)
+ dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret);
+
+ if (!(st->variant->flags & ADIS16400_NO_BURST)) {
+ st->adis.spi->max_speed_hz = old_speed_hz;
+ spi_setup(st->adis.spi);
+ }
+
+ /* Guaranteed to be aligned with 8 byte boundary */
+ if (indio_dev->scan_timestamp) {
+ void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64);
+ *(s64 *)b = pf->timestamp;
+ }
+
+ iio_push_to_buffers(indio_dev, adis->buffer);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c
new file mode 100644
index 000000000000..b7f215eab5de
--- /dev/null
+++ b/drivers/iio/imu/adis16400_core.c
@@ -0,0 +1,965 @@
+/*
+ * adis16400.c support Analog Devices ADIS16400/5
+ * 3d 2g Linear Accelerometers,
+ * 3d Gyroscopes,
+ * 3d Magnetometers via SPI
+ *
+ * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
+ * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+
+#include "adis16400.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+static ssize_t adis16400_show_serial_number(struct file *file,
+ char __user *userbuf, size_t count, loff_t *ppos)
+{
+ struct adis16400_state *st = file->private_data;
+ u16 lot1, lot2, serial_number;
+ char buf[16];
+ size_t len;
+ int ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID1, &lot1);
+ if (ret < 0)
+ return ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID2, &lot2);
+ if (ret < 0)
+ return ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16334_SERIAL_NUMBER,
+ &serial_number);
+ if (ret < 0)
+ return ret;
+
+ len = snprintf(buf, sizeof(buf), "%.4x-%.4x-%.4x\n", lot1, lot2,
+ serial_number);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations adis16400_serial_number_fops = {
+ .open = simple_open,
+ .read = adis16400_show_serial_number,
+ .llseek = default_llseek,
+ .owner = THIS_MODULE,
+};
+
+static int adis16400_show_product_id(void *arg, u64 *val)
+{
+ struct adis16400_state *st = arg;
+ uint16_t prod_id;
+ int ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16400_PRODUCT_ID, &prod_id);
+ if (ret < 0)
+ return ret;
+
+ *val = prod_id;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16400_product_id_fops,
+ adis16400_show_product_id, NULL, "%lld\n");
+
+static int adis16400_show_flash_count(void *arg, u64 *val)
+{
+ struct adis16400_state *st = arg;
+ uint16_t flash_count;
+ int ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16400_FLASH_CNT, &flash_count);
+ if (ret < 0)
+ return ret;
+
+ *val = flash_count;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16400_flash_count_fops,
+ adis16400_show_flash_count, NULL, "%lld\n");
+
+static int adis16400_debugfs_init(struct iio_dev *indio_dev)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+
+ if (st->variant->flags & ADIS16400_HAS_SERIAL_NUMBER)
+ debugfs_create_file("serial_number", 0400,
+ indio_dev->debugfs_dentry, st,
+ &adis16400_serial_number_fops);
+ if (st->variant->flags & ADIS16400_HAS_PROD_ID)
+ debugfs_create_file("product_id", 0400,
+ indio_dev->debugfs_dentry, st,
+ &adis16400_product_id_fops);
+ debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
+ st, &adis16400_flash_count_fops);
+
+ return 0;
+}
+
+#else
+
+static int adis16400_debugfs_init(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+#endif
+
+enum adis16400_chip_variant {
+ ADIS16300,
+ ADIS16334,
+ ADIS16350,
+ ADIS16360,
+ ADIS16362,
+ ADIS16364,
+ ADIS16400,
+ ADIS16448,
+};
+
+static int adis16334_get_freq(struct adis16400_state *st)
+{
+ int ret;
+ uint16_t t;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
+ if (ret < 0)
+ return ret;
+
+ t >>= ADIS16334_RATE_DIV_SHIFT;
+
+ return 819200 >> t;
+}
+
+static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq)
+{
+ unsigned int t;
+
+ if (freq < 819200)
+ t = ilog2(819200 / freq);
+ else
+ t = 0;
+
+ if (t > 0x31)
+ t = 0x31;
+
+ t <<= ADIS16334_RATE_DIV_SHIFT;
+ t |= ADIS16334_RATE_INT_CLK;
+
+ return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t);
+}
+
+static int adis16400_get_freq(struct adis16400_state *st)
+{
+ int sps, ret;
+ uint16_t t;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
+ if (ret < 0)
+ return ret;
+
+ sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 52851 : 1638404;
+ sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1;
+
+ return sps;
+}
+
+static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq)
+{
+ unsigned int t;
+ uint8_t val = 0;
+
+ t = 1638404 / freq;
+ if (t >= 128) {
+ val |= ADIS16400_SMPL_PRD_TIME_BASE;
+ t = 52851 / freq;
+ if (t >= 128)
+ t = 127;
+ } else if (t != 0) {
+ t--;
+ }
+
+ val |= t;
+
+ if (t >= 0x0A || (val & ADIS16400_SMPL_PRD_TIME_BASE))
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW;
+ else
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST;
+
+ return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val);
+}
+
+static ssize_t adis16400_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adis16400_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = st->variant->get_freq(st);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d.%.3d\n", ret / 1000, ret % 1000);
+}
+
+static const unsigned adis16400_3db_divisors[] = {
+ [0] = 2, /* Special case */
+ [1] = 6,
+ [2] = 12,
+ [3] = 25,
+ [4] = 50,
+ [5] = 100,
+ [6] = 200,
+ [7] = 200, /* Not a valid setting */
+};
+
+static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ uint16_t val16;
+ int i, ret;
+
+ for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 1; i--) {
+ if (sps / adis16400_3db_divisors[i] >= val)
+ break;
+ }
+
+ ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16);
+ if (ret < 0)
+ return ret;
+
+ ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG,
+ (val16 & ~0x07) | i);
+ return ret;
+}
+
+static ssize_t adis16400_write_frequency(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adis16400_state *st = iio_priv(indio_dev);
+ int i, f, val;
+ int ret;
+
+ ret = iio_str_to_fixpoint(buf, 100, &i, &f);
+ if (ret)
+ return ret;
+
+ val = i * 1000 + f;
+
+ if (val <= 0)
+ return -EINVAL;
+
+ mutex_lock(&indio_dev->mlock);
+ st->variant->set_freq(st, val);
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+
+/* Power down the device */
+static int adis16400_stop_device(struct iio_dev *indio_dev)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT,
+ ADIS16400_SLP_CNT_POWER_OFF);
+ if (ret)
+ dev_err(&indio_dev->dev,
+ "problem with turning device off: SLP_CNT");
+
+ return ret;
+}
+
+static int adis16400_initial_setup(struct iio_dev *indio_dev)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ uint16_t prod_id, smp_prd;
+ unsigned int device_id;
+ int ret;
+
+ /* use low spi speed for init if the device has a slow mode */
+ if (st->variant->flags & ADIS16400_HAS_SLOW_MODE)
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW;
+ else
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST;
+ st->adis.spi->mode = SPI_MODE_3;
+ spi_setup(st->adis.spi);
+
+ ret = adis_initial_startup(&st->adis);
+ if (ret)
+ return ret;
+
+ if (st->variant->flags & ADIS16400_HAS_PROD_ID) {
+ ret = adis_read_reg_16(&st->adis,
+ ADIS16400_PRODUCT_ID, &prod_id);
+ if (ret)
+ goto err_ret;
+
+ sscanf(indio_dev->name, "adis%u\n", &device_id);
+
+ if (prod_id != device_id)
+ dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
+ device_id, prod_id);
+
+ dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n",
+ indio_dev->name, prod_id,
+ st->adis.spi->chip_select, st->adis.spi->irq);
+ }
+ /* use high spi speed if possible */
+ if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) {
+ ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &smp_prd);
+ if (ret)
+ goto err_ret;
+
+ if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) {
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST;
+ spi_setup(st->adis.spi);
+ }
+ }
+
+err_ret:
+ return ret;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ adis16400_read_frequency,
+ adis16400_write_frequency);
+
+static const uint8_t adis16400_addresses[] = {
+ [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF,
+ [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF,
+ [ADIS16400_SCAN_GYRO_Z] = ADIS16400_ZGYRO_OFF,
+ [ADIS16400_SCAN_ACC_X] = ADIS16400_XACCL_OFF,
+ [ADIS16400_SCAN_ACC_Y] = ADIS16400_YACCL_OFF,
+ [ADIS16400_SCAN_ACC_Z] = ADIS16400_ZACCL_OFF,
+};
+
+static int adis16400_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long info)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ int ret, sps;
+
+ switch (info) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ mutex_lock(&indio_dev->mlock);
+ ret = adis_write_reg_16(&st->adis,
+ adis16400_addresses[chan->scan_index], val);
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ /*
+ * Need to cache values so we can update if the frequency
+ * changes.
+ */
+ mutex_lock(&indio_dev->mlock);
+ st->filt_int = val;
+ /* Work out update to current value */
+ sps = st->variant->get_freq(st);
+ if (sps < 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return sps;
+ }
+
+ ret = adis16400_set_filter(indio_dev, sps,
+ val * 1000 + val2 / 1000);
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adis16400_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2, long info)
+{
+ struct adis16400_state *st = iio_priv(indio_dev);
+ int16_t val16;
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ return adis_single_conversion(indio_dev, chan, 0, val);
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ *val = 0;
+ *val2 = st->variant->gyro_scale_micro;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_VOLTAGE:
+ *val = 0;
+ if (chan->channel == 0) {
+ *val = 2;
+ *val2 = 418000; /* 2.418 mV */
+ } else {
+ *val = 0;
+ *val2 = 805800; /* 805.8 uV */
+ }
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_ACCEL:
+ *val = 0;
+ *val2 = st->variant->accel_scale_micro;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_MAGN:
+ *val = 0;
+ *val2 = 500; /* 0.5 mgauss */
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_TEMP:
+ *val = st->variant->temp_scale_nano / 1000000;
+ *val2 = (st->variant->temp_scale_nano % 1000000);
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_CALIBBIAS:
+ mutex_lock(&indio_dev->mlock);
+ ret = adis_read_reg_16(&st->adis,
+ adis16400_addresses[chan->scan_index], &val16);
+ mutex_unlock(&indio_dev->mlock);
+ if (ret)
+ return ret;
+ val16 = ((val16 & 0xFFF) << 4) >> 4;
+ *val = val16;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_OFFSET:
+ /* currently only temperature */
+ *val = st->variant->temp_offset;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ mutex_lock(&indio_dev->mlock);
+ /* Need both the number of taps and the sampling frequency */
+ ret = adis_read_reg_16(&st->adis,
+ ADIS16400_SENS_AVG,
+ &val16);
+ if (ret < 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ }
+ ret = st->variant->get_freq(st);
+ if (ret >= 0) {
+ ret /= adis16400_3db_divisors[val16 & 0x07];
+ *val = ret / 1000;
+ *val2 = (ret % 1000) * 1000;
+ }
+ mutex_unlock(&indio_dev->mlock);
+ if (ret < 0)
+ return ret;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = 0, \
+ .extend_name = name, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = (addr), \
+ .scan_index = (si), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_SUPPLY_CHAN(addr, bits) \
+ ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY)
+
+#define ADIS16400_AUX_ADC_CHAN(addr, bits) \
+ ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC)
+
+#define ADIS16400_GYRO_CHAN(mod, addr, bits) { \
+ .type = IIO_ANGL_VEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .address = addr, \
+ .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .address = (addr), \
+ .scan_index = ADIS16400_SCAN_ACC_ ## mod, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_MAGN_CHAN(mod, addr, bits) { \
+ .type = IIO_MAGN, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .address = (addr), \
+ .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_MOD_TEMP_NAME_X "x"
+#define ADIS16400_MOD_TEMP_NAME_Y "y"
+#define ADIS16400_MOD_TEMP_NAME_Z "z"
+
+#define ADIS16400_MOD_TEMP_CHAN(mod, addr, bits) { \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .channel = 0, \
+ .extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .address = (addr), \
+ .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_TEMP_CHAN(addr, bits) { \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .channel = 0, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = (addr), \
+ .scan_index = ADIS16350_SCAN_TEMP_X, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define ADIS16400_INCLI_CHAN(mod, addr, bits) { \
+ .type = IIO_INCLI, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .address = (addr), \
+ .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+static const struct iio_chan_spec adis16400_channels[] = {
+ ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 14),
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14),
+ ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14),
+ ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14),
+ ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14),
+ ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12),
+ ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(12)
+};
+
+static const struct iio_chan_spec adis16448_channels[] = {
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16),
+ ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16),
+ ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16),
+ ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 16),
+ ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 16),
+ ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 16),
+ {
+ .type = IIO_PRESSURE,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = ADIS16448_BARO_OUT,
+ .scan_index = ADIS16400_SCAN_BARO,
+ .scan_type = IIO_ST('s', 16, 16, 0),
+ },
+ ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(11)
+};
+
+static const struct iio_chan_spec adis16350_channels[] = {
+ ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12),
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14),
+ ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14),
+ ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14),
+ ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14),
+ ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12),
+ ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12),
+ ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12),
+ ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(11)
+};
+
+static const struct iio_chan_spec adis16300_channels[] = {
+ ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12),
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14),
+ ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12),
+ ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12),
+ ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13),
+ ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13),
+ IIO_CHAN_SOFT_TIMESTAMP(14)
+};
+
+static const struct iio_chan_spec adis16334_channels[] = {
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14),
+ ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14),
+ ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(8)
+};
+
+static struct attribute *adis16400_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16400_attribute_group = {
+ .attrs = adis16400_attributes,
+};
+
+static struct adis16400_chip_info adis16400_chips[] = {
+ [ADIS16300] = {
+ .channels = adis16300_channels,
+ .num_channels = ARRAY_SIZE(adis16300_channels),
+ .flags = ADIS16400_HAS_SLOW_MODE,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = 5884,
+ .temp_scale_nano = 140000000, /* 0.14 C */
+ .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16334] = {
+ .channels = adis16334_channels,
+ .num_channels = ARRAY_SIZE(adis16334_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_NO_BURST |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
+ .temp_scale_nano = 67850000, /* 0.06785 C */
+ .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */
+ .set_freq = adis16334_set_freq,
+ .get_freq = adis16334_get_freq,
+ },
+ [ADIS16350] = {
+ .channels = adis16350_channels,
+ .num_channels = ARRAY_SIZE(adis16350_channels),
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */
+ .temp_scale_nano = 145300000, /* 0.1453 C */
+ .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */
+ .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE,
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16360] = {
+ .channels = adis16350_channels,
+ .num_channels = ARRAY_SIZE(adis16350_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
+ .temp_scale_nano = 136000000, /* 0.136 C */
+ .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16362] = {
+ .channels = adis16350_channels,
+ .num_channels = ARRAY_SIZE(adis16350_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */
+ .temp_scale_nano = 136000000, /* 0.136 C */
+ .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16364] = {
+ .channels = adis16350_channels,
+ .num_channels = ARRAY_SIZE(adis16350_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
+ .temp_scale_nano = 136000000, /* 0.136 C */
+ .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16400] = {
+ .channels = adis16400_channels,
+ .num_channels = ARRAY_SIZE(adis16400_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
+ .temp_scale_nano = 140000000, /* 0.14 C */
+ .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
+ [ADIS16448] = {
+ .channels = adis16448_channels,
+ .num_channels = ARRAY_SIZE(adis16448_channels),
+ .flags = ADIS16400_HAS_PROD_ID |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */
+ .temp_scale_nano = 73860000, /* 0.07386 C */
+ .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
+ .set_freq = adis16334_set_freq,
+ .get_freq = adis16334_get_freq,
+ }
+};
+
+static const struct iio_info adis16400_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &adis16400_read_raw,
+ .write_raw = &adis16400_write_raw,
+ .attrs = &adis16400_attribute_group,
+ .update_scan_mode = adis16400_update_scan_mode,
+ .debugfs_reg_access = adis_debugfs_reg_access,
+};
+
+static const unsigned long adis16400_burst_scan_mask[] = {
+ ~0UL,
+ 0,
+};
+
+static const char * const adis16400_status_error_msgs[] = {
+ [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
+ [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
+ [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
+ [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
+ [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
+ [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
+ [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active",
+ [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active",
+ [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error",
+ [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error",
+ [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange",
+ [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure",
+ [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed",
+ [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V",
+ [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V",
+};
+
+static const struct adis_data adis16400_data = {
+ .msc_ctrl_reg = ADIS16400_MSC_CTRL,
+ .glob_cmd_reg = ADIS16400_GLOB_CMD,
+ .diag_stat_reg = ADIS16400_DIAG_STAT,
+
+ .read_delay = 50,
+ .write_delay = 50,
+
+ .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST,
+ .startup_delay = ADIS16400_STARTUP_DELAY,
+
+ .status_error_msgs = adis16400_status_error_msgs,
+ .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_ALARM2) |
+ BIT(ADIS16400_DIAG_STAT_ALARM1) |
+ BIT(ADIS16400_DIAG_STAT_FLASH_CHK) |
+ BIT(ADIS16400_DIAG_STAT_SELF_TEST) |
+ BIT(ADIS16400_DIAG_STAT_OVERFLOW) |
+ BIT(ADIS16400_DIAG_STAT_SPI_FAIL) |
+ BIT(ADIS16400_DIAG_STAT_FLASH_UPT) |
+ BIT(ADIS16400_DIAG_STAT_POWER_HIGH) |
+ BIT(ADIS16400_DIAG_STAT_POWER_LOW),
+};
+
+static int adis16400_probe(struct spi_device *spi)
+{
+ struct adis16400_state *st;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = iio_device_alloc(sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ /* this is only used for removal purposes */
+ spi_set_drvdata(spi, indio_dev);
+
+ /* setup the industrialio driver allocated elements */
+ st->variant = &adis16400_chips[spi_get_device_id(spi)->driver_data];
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->channels = st->variant->channels;
+ indio_dev->num_channels = st->variant->num_channels;
+ indio_dev->info = &adis16400_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ if (!(st->variant->flags & ADIS16400_NO_BURST))
+ indio_dev->available_scan_masks = adis16400_burst_scan_mask;
+
+ ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data);
+ if (ret)
+ goto error_free_dev;
+
+ ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev,
+ adis16400_trigger_handler);
+ if (ret)
+ goto error_free_dev;
+
+ /* Get the device into a sane initial state */
+ ret = adis16400_initial_setup(indio_dev);
+ if (ret)
+ goto error_cleanup_buffer;
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_cleanup_buffer;
+
+ adis16400_debugfs_init(indio_dev);
+ return 0;
+
+error_cleanup_buffer:
+ adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
+error_free_dev:
+ iio_device_free(indio_dev);
+ return ret;
+}
+
+static int adis16400_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct adis16400_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ adis16400_stop_device(indio_dev);
+
+ adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id adis16400_id[] = {
+ {"adis16300", ADIS16300},
+ {"adis16334", ADIS16334},
+ {"adis16350", ADIS16350},
+ {"adis16354", ADIS16350},
+ {"adis16355", ADIS16350},
+ {"adis16360", ADIS16360},
+ {"adis16362", ADIS16362},
+ {"adis16364", ADIS16364},
+ {"adis16365", ADIS16360},
+ {"adis16400", ADIS16400},
+ {"adis16405", ADIS16400},
+ {"adis16448", ADIS16448},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, adis16400_id);
+
+static struct spi_driver adis16400_driver = {
+ .driver = {
+ .name = "adis16400",
+ .owner = THIS_MODULE,
+ },
+ .id_table = adis16400_id,
+ .probe = adis16400_probe,
+ .remove = adis16400_remove,
+};
+module_spi_driver(adis16400_driver);
+
+MODULE_AUTHOR("Manuel Stahl <manuel.stahl@iis.fraunhofer.de>");
+MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig
new file mode 100644
index 000000000000..b5cfa3a354cf
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/Kconfig
@@ -0,0 +1,13 @@
+#
+# inv-mpu6050 drivers for Invensense MPU devices and combos
+#
+
+config INV_MPU6050_IIO
+ tristate "Invensense MPU6050 devices"
+ depends on I2C && SYSFS
+ select IIO_TRIGGERED_BUFFER
+ help
+ This driver supports the Invensense MPU6050 devices.
+ It is a gyroscope/accelerometer combo device.
+ This driver can be built as a module. The module will be called
+ inv-mpu6050.
diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile
new file mode 100644
index 000000000000..3a677c778afb
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Invensense MPU6050 device.
+#
+
+obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
+inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
new file mode 100644
index 000000000000..37ca05b47e4b
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -0,0 +1,795 @@
+/*
+* Copyright (C) 2012 Invensense, Inc.
+*
+* 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/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <linux/spinlock.h>
+#include "inv_mpu_iio.h"
+
+/*
+ * this is the gyro scale translated from dynamic range plus/minus
+ * {250, 500, 1000, 2000} to rad/s
+ */
+static const int gyro_scale_6050[] = {133090, 266181, 532362, 1064724};
+
+/*
+ * this is the accel scale translated from dynamic range plus/minus
+ * {2, 4, 8, 16} to m/s^2
+ */
+static const int accel_scale[] = {598, 1196, 2392, 4785};
+
+static const struct inv_mpu6050_reg_map reg_set_6050 = {
+ .sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV,
+ .lpf = INV_MPU6050_REG_CONFIG,
+ .user_ctrl = INV_MPU6050_REG_USER_CTRL,
+ .fifo_en = INV_MPU6050_REG_FIFO_EN,
+ .gyro_config = INV_MPU6050_REG_GYRO_CONFIG,
+ .accl_config = INV_MPU6050_REG_ACCEL_CONFIG,
+ .fifo_count_h = INV_MPU6050_REG_FIFO_COUNT_H,
+ .fifo_r_w = INV_MPU6050_REG_FIFO_R_W,
+ .raw_gyro = INV_MPU6050_REG_RAW_GYRO,
+ .raw_accl = INV_MPU6050_REG_RAW_ACCEL,
+ .temperature = INV_MPU6050_REG_TEMPERATURE,
+ .int_enable = INV_MPU6050_REG_INT_ENABLE,
+ .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1,
+ .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2,
+};
+
+static const struct inv_mpu6050_chip_config chip_config_6050 = {
+ .fsr = INV_MPU6050_FSR_2000DPS,
+ .lpf = INV_MPU6050_FILTER_20HZ,
+ .fifo_rate = INV_MPU6050_INIT_FIFO_RATE,
+ .gyro_fifo_enable = false,
+ .accl_fifo_enable = false,
+ .accl_fs = INV_MPU6050_FS_02G,
+};
+
+static const struct inv_mpu6050_hw hw_info[INV_NUM_PARTS] = {
+ {
+ .num_reg = 117,
+ .name = "MPU6050",
+ .reg = &reg_set_6050,
+ .config = &chip_config_6050,
+ },
+};
+
+int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 d)
+{
+ return i2c_smbus_write_i2c_block_data(st->client, reg, 1, &d);
+}
+
+int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
+{
+ u8 d, mgmt_1;
+ int result;
+
+ /* switch clock needs to be careful. Only when gyro is on, can
+ clock source be switched to gyro. Otherwise, it must be set to
+ internal clock */
+ if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) {
+ result = i2c_smbus_read_i2c_block_data(st->client,
+ st->reg->pwr_mgmt_1, 1, &mgmt_1);
+ if (result != 1)
+ return result;
+
+ mgmt_1 &= ~INV_MPU6050_BIT_CLK_MASK;
+ }
+
+ if ((INV_MPU6050_BIT_PWR_GYRO_STBY == mask) && (!en)) {
+ /* turning off gyro requires switch to internal clock first.
+ Then turn off gyro engine */
+ mgmt_1 |= INV_CLK_INTERNAL;
+ result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, mgmt_1);
+ if (result)
+ return result;
+ }
+
+ result = i2c_smbus_read_i2c_block_data(st->client,
+ st->reg->pwr_mgmt_2, 1, &d);
+ if (result != 1)
+ return result;
+ if (en)
+ d &= ~mask;
+ else
+ d |= mask;
+ result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_2, d);
+ if (result)
+ return result;
+
+ if (en) {
+ /* Wait for output stablize */
+ msleep(INV_MPU6050_TEMP_UP_TIME);
+ if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) {
+ /* switch internal clock to PLL */
+ mgmt_1 |= INV_CLK_PLL;
+ result = inv_mpu6050_write_reg(st,
+ st->reg->pwr_mgmt_1, mgmt_1);
+ if (result)
+ return result;
+ }
+ }
+
+ return 0;
+}
+
+int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
+{
+ int result;
+
+ if (power_on)
+ result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, 0);
+ else
+ result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
+ INV_MPU6050_BIT_SLEEP);
+ if (result)
+ return result;
+
+ if (power_on)
+ msleep(INV_MPU6050_REG_UP_TIME);
+
+ return 0;
+}
+
+/**
+ * inv_mpu6050_init_config() - Initialize hardware, disable FIFO.
+ *
+ * Initial configuration:
+ * FSR: ± 2000DPS
+ * DLPF: 20Hz
+ * FIFO rate: 50Hz
+ * Clock source: Gyro PLL
+ */
+static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
+{
+ int result;
+ u8 d;
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ result = inv_mpu6050_set_power_itg(st, true);
+ if (result)
+ return result;
+ d = (INV_MPU6050_FSR_2000DPS << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
+ result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d);
+ if (result)
+ return result;
+
+ d = INV_MPU6050_FILTER_20HZ;
+ result = inv_mpu6050_write_reg(st, st->reg->lpf, d);
+ if (result)
+ return result;
+
+ d = INV_MPU6050_ONE_K_HZ / INV_MPU6050_INIT_FIFO_RATE - 1;
+ result = inv_mpu6050_write_reg(st, st->reg->sample_rate_div, d);
+ if (result)
+ return result;
+
+ d = (INV_MPU6050_FS_02G << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
+ result = inv_mpu6050_write_reg(st, st->reg->accl_config, d);
+ if (result)
+ return result;
+
+ memcpy(&st->chip_config, hw_info[st->chip_type].config,
+ sizeof(struct inv_mpu6050_chip_config));
+ result = inv_mpu6050_set_power_itg(st, false);
+
+ return result;
+}
+
+static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg,
+ int axis, int *val)
+{
+ int ind, result;
+ __be16 d;
+
+ ind = (axis - IIO_MOD_X) * 2;
+ result = i2c_smbus_read_i2c_block_data(st->client, reg + ind, 2,
+ (u8 *)&d);
+ if (result != 2)
+ return -EINVAL;
+ *val = (short)be16_to_cpup(&d);
+
+ return IIO_VAL_INT;
+}
+
+static int inv_mpu6050_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask) {
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ {
+ int ret, result;
+
+ ret = IIO_VAL_INT;
+ result = 0;
+ mutex_lock(&indio_dev->mlock);
+ if (!st->chip_config.enable) {
+ result = inv_mpu6050_set_power_itg(st, true);
+ if (result)
+ goto error_read_raw;
+ }
+ /* when enable is on, power is already on */
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ if (!st->chip_config.gyro_fifo_enable ||
+ !st->chip_config.enable) {
+ result = inv_mpu6050_switch_engine(st, true,
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
+ if (result)
+ goto error_read_raw;
+ }
+ ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
+ chan->channel2, val);
+ if (!st->chip_config.gyro_fifo_enable ||
+ !st->chip_config.enable) {
+ result = inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
+ if (result)
+ goto error_read_raw;
+ }
+ break;
+ case IIO_ACCEL:
+ if (!st->chip_config.accl_fifo_enable ||
+ !st->chip_config.enable) {
+ result = inv_mpu6050_switch_engine(st, true,
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
+ if (result)
+ goto error_read_raw;
+ }
+ ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
+ chan->channel2, val);
+ if (!st->chip_config.accl_fifo_enable ||
+ !st->chip_config.enable) {
+ result = inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
+ if (result)
+ goto error_read_raw;
+ }
+ break;
+ case IIO_TEMP:
+ /* wait for stablization */
+ msleep(INV_MPU6050_SENSOR_UP_TIME);
+ inv_mpu6050_sensor_show(st, st->reg->temperature,
+ IIO_MOD_X, val);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+error_read_raw:
+ if (!st->chip_config.enable)
+ result |= inv_mpu6050_set_power_itg(st, false);
+ mutex_unlock(&indio_dev->mlock);
+ if (result)
+ return result;
+
+ return ret;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ *val = 0;
+ *val2 = gyro_scale_6050[st->chip_config.fsr];
+
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_ACCEL:
+ *val = 0;
+ *val2 = accel_scale[st->chip_config.accl_fs];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_TEMP:
+ *val = 0;
+ *val2 = INV_MPU6050_TEMP_SCALE;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ switch (chan->type) {
+ case IIO_TEMP:
+ *val = INV_MPU6050_TEMP_OFFSET;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int inv_mpu6050_write_fsr(struct inv_mpu6050_state *st, int fsr)
+{
+ int result;
+ u8 d;
+
+ if (fsr < 0 || fsr > INV_MPU6050_MAX_GYRO_FS_PARAM)
+ return -EINVAL;
+ if (fsr == st->chip_config.fsr)
+ return 0;
+
+ d = (fsr << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
+ result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d);
+ if (result)
+ return result;
+ st->chip_config.fsr = fsr;
+
+ return 0;
+}
+
+static int inv_mpu6050_write_accel_fs(struct inv_mpu6050_state *st, int fs)
+{
+ int result;
+ u8 d;
+
+ if (fs < 0 || fs > INV_MPU6050_MAX_ACCL_FS_PARAM)
+ return -EINVAL;
+ if (fs == st->chip_config.accl_fs)
+ return 0;
+
+ d = (fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
+ result = inv_mpu6050_write_reg(st, st->reg->accl_config, d);
+ if (result)
+ return result;
+ st->chip_config.accl_fs = fs;
+
+ return 0;
+}
+
+static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask) {
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+ int result;
+
+ mutex_lock(&indio_dev->mlock);
+ /* we should only update scale when the chip is disabled, i.e.,
+ not running */
+ if (st->chip_config.enable) {
+ result = -EBUSY;
+ goto error_write_raw;
+ }
+ result = inv_mpu6050_set_power_itg(st, true);
+ if (result)
+ goto error_write_raw;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ result = inv_mpu6050_write_fsr(st, val);
+ break;
+ case IIO_ACCEL:
+ result = inv_mpu6050_write_accel_fs(st, val);
+ break;
+ default:
+ result = -EINVAL;
+ break;
+ }
+ break;
+ default:
+ result = -EINVAL;
+ break;
+ }
+
+error_write_raw:
+ result |= inv_mpu6050_set_power_itg(st, false);
+ mutex_unlock(&indio_dev->mlock);
+
+ return result;
+}
+
+/**
+ * inv_mpu6050_set_lpf() - set low pass filer based on fifo rate.
+ *
+ * Based on the Nyquist principle, the sampling rate must
+ * exceed twice of the bandwidth of the signal, or there
+ * would be alising. This function basically search for the
+ * correct low pass parameters based on the fifo rate, e.g,
+ * sampling frequency.
+ */
+static int inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate)
+{
+ const int hz[] = {188, 98, 42, 20, 10, 5};
+ const int d[] = {INV_MPU6050_FILTER_188HZ, INV_MPU6050_FILTER_98HZ,
+ INV_MPU6050_FILTER_42HZ, INV_MPU6050_FILTER_20HZ,
+ INV_MPU6050_FILTER_10HZ, INV_MPU6050_FILTER_5HZ};
+ int i, h, result;
+ u8 data;
+
+ h = (rate >> 1);
+ i = 0;
+ while ((h < hz[i]) && (i < ARRAY_SIZE(d) - 1))
+ i++;
+ data = d[i];
+ result = inv_mpu6050_write_reg(st, st->reg->lpf, data);
+ if (result)
+ return result;
+ st->chip_config.lpf = data;
+
+ return 0;
+}
+
+/**
+ * inv_mpu6050_fifo_rate_store() - Set fifo rate.
+ */
+static ssize_t inv_mpu6050_fifo_rate_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ s32 fifo_rate;
+ u8 d;
+ int result;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ if (kstrtoint(buf, 10, &fifo_rate))
+ return -EINVAL;
+ if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE ||
+ fifo_rate > INV_MPU6050_MAX_FIFO_RATE)
+ return -EINVAL;
+ if (fifo_rate == st->chip_config.fifo_rate)
+ return count;
+
+ mutex_lock(&indio_dev->mlock);
+ if (st->chip_config.enable) {
+ result = -EBUSY;
+ goto fifo_rate_fail;
+ }
+ result = inv_mpu6050_set_power_itg(st, true);
+ if (result)
+ goto fifo_rate_fail;
+
+ d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1;
+ result = inv_mpu6050_write_reg(st, st->reg->sample_rate_div, d);
+ if (result)
+ goto fifo_rate_fail;
+ st->chip_config.fifo_rate = fifo_rate;
+
+ result = inv_mpu6050_set_lpf(st, fifo_rate);
+ if (result)
+ goto fifo_rate_fail;
+
+fifo_rate_fail:
+ result |= inv_mpu6050_set_power_itg(st, false);
+ mutex_unlock(&indio_dev->mlock);
+ if (result)
+ return result;
+
+ return count;
+}
+
+/**
+ * inv_fifo_rate_show() - Get the current sampling rate.
+ */
+static ssize_t inv_fifo_rate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev));
+
+ return sprintf(buf, "%d\n", st->chip_config.fifo_rate);
+}
+
+/**
+ * inv_attr_show() - calling this function will show current
+ * parameters.
+ */
+static ssize_t inv_attr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev));
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ s8 *m;
+
+ switch (this_attr->address) {
+ /* In MPU6050, the two matrix are the same because gyro and accel
+ are integrated in one chip */
+ case ATTR_GYRO_MATRIX:
+ case ATTR_ACCL_MATRIX:
+ m = st->plat_data.orientation;
+
+ return sprintf(buf, "%d, %d, %d; %d, %d, %d; %d, %d, %d\n",
+ m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * inv_mpu6050_validate_trigger() - validate_trigger callback for invensense
+ * MPU6050 device.
+ * @indio_dev: The IIO device
+ * @trig: The new trigger
+ *
+ * Returns: 0 if the 'trig' matches the trigger registered by the MPU6050
+ * device, -EINVAL otherwise.
+ */
+static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
+ struct iio_trigger *trig)
+{
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ if (st->trig != trig)
+ return -EINVAL;
+
+ return 0;
+}
+
+#define INV_MPU6050_CHAN(_type, _channel2, _index) \
+ { \
+ .type = _type, \
+ .modified = 1, \
+ .channel2 = _channel2, \
+ .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT \
+ | IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .shift = 0 , \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+static const struct iio_chan_spec inv_mpu_channels[] = {
+ IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP),
+ /*
+ * Note that temperature should only be via polled reading only,
+ * not the final scan elements output.
+ */
+ {
+ .type = IIO_TEMP,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT
+ | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT
+ | IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .scan_index = -1,
+ },
+ INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
+ INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y),
+ INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z),
+
+ INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X),
+ INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y),
+ INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z),
+};
+
+/* constant IIO attribute */
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500");
+static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show,
+ inv_mpu6050_fifo_rate_store);
+static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL,
+ ATTR_GYRO_MATRIX);
+static IIO_DEVICE_ATTR(in_accel_matrix, S_IRUGO, inv_attr_show, NULL,
+ ATTR_ACCL_MATRIX);
+
+static struct attribute *inv_attributes[] = {
+ &iio_dev_attr_in_gyro_matrix.dev_attr.attr,
+ &iio_dev_attr_in_accel_matrix.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group inv_attribute_group = {
+ .attrs = inv_attributes
+};
+
+static const struct iio_info mpu_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &inv_mpu6050_read_raw,
+ .write_raw = &inv_mpu6050_write_raw,
+ .attrs = &inv_attribute_group,
+ .validate_trigger = inv_mpu6050_validate_trigger,
+};
+
+/**
+ * inv_check_and_setup_chip() - check and setup chip.
+ */
+static int inv_check_and_setup_chip(struct inv_mpu6050_state *st,
+ const struct i2c_device_id *id)
+{
+ int result;
+
+ st->chip_type = INV_MPU6050;
+ st->hw = &hw_info[st->chip_type];
+ st->reg = hw_info[st->chip_type].reg;
+
+ /* reset to make sure previous state are not there */
+ result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
+ INV_MPU6050_BIT_H_RESET);
+ if (result)
+ return result;
+ msleep(INV_MPU6050_POWER_UP_TIME);
+ /* toggle power state. After reset, the sleep bit could be on
+ or off depending on the OTP settings. Toggling power would
+ make it in a definite state as well as making the hardware
+ state align with the software state */
+ result = inv_mpu6050_set_power_itg(st, false);
+ if (result)
+ return result;
+ result = inv_mpu6050_set_power_itg(st, true);
+ if (result)
+ return result;
+
+ result = inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
+ if (result)
+ return result;
+ result = inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
+ if (result)
+ return result;
+
+ return 0;
+}
+
+/**
+ * inv_mpu_probe() - probe function.
+ * @client: i2c client.
+ * @id: i2c device id.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int inv_mpu_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct inv_mpu6050_state *st;
+ struct iio_dev *indio_dev;
+ int result;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK |
+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
+ result = -ENOSYS;
+ goto out_no_free;
+ }
+ indio_dev = iio_device_alloc(sizeof(*st));
+ if (indio_dev == NULL) {
+ result = -ENOMEM;
+ goto out_no_free;
+ }
+ st = iio_priv(indio_dev);
+ st->client = client;
+ st->plat_data = *(struct inv_mpu6050_platform_data
+ *)dev_get_platdata(&client->dev);
+ /* power is turned on inside check chip type*/
+ result = inv_check_and_setup_chip(st, id);
+ if (result)
+ goto out_free;
+
+ result = inv_mpu6050_init_config(indio_dev);
+ if (result) {
+ dev_err(&client->dev,
+ "Could not initialize device.\n");
+ goto out_free;
+ }
+
+ i2c_set_clientdata(client, indio_dev);
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = id->name;
+ indio_dev->channels = inv_mpu_channels;
+ indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
+
+ indio_dev->info = &mpu_info;
+ indio_dev->modes = INDIO_BUFFER_TRIGGERED;
+
+ result = iio_triggered_buffer_setup(indio_dev,
+ inv_mpu6050_irq_handler,
+ inv_mpu6050_read_fifo,
+ NULL);
+ if (result) {
+ dev_err(&st->client->dev, "configure buffer fail %d\n",
+ result);
+ goto out_free;
+ }
+ result = inv_mpu6050_probe_trigger(indio_dev);
+ if (result) {
+ dev_err(&st->client->dev, "trigger probe fail %d\n", result);
+ goto out_unreg_ring;
+ }
+
+ INIT_KFIFO(st->timestamps);
+ spin_lock_init(&st->time_stamp_lock);
+ result = iio_device_register(indio_dev);
+ if (result) {
+ dev_err(&st->client->dev, "IIO register fail %d\n", result);
+ goto out_remove_trigger;
+ }
+
+ return 0;
+
+out_remove_trigger:
+ inv_mpu6050_remove_trigger(st);
+out_unreg_ring:
+ iio_triggered_buffer_cleanup(indio_dev);
+out_free:
+ iio_device_free(indio_dev);
+out_no_free:
+
+ return result;
+}
+
+static int inv_mpu_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ inv_mpu6050_remove_trigger(st);
+ iio_triggered_buffer_cleanup(indio_dev);
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+#ifdef CONFIG_PM_SLEEP
+
+static int inv_mpu_resume(struct device *dev)
+{
+ return inv_mpu6050_set_power_itg(
+ iio_priv(i2c_get_clientdata(to_i2c_client(dev))), true);
+}
+
+static int inv_mpu_suspend(struct device *dev)
+{
+ return inv_mpu6050_set_power_itg(
+ iio_priv(i2c_get_clientdata(to_i2c_client(dev))), false);
+}
+static SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume);
+
+#define INV_MPU6050_PMOPS (&inv_mpu_pmops)
+#else
+#define INV_MPU6050_PMOPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+/*
+ * device id table is used to identify what device can be
+ * supported by this driver
+ */
+static const struct i2c_device_id inv_mpu_id[] = {
+ {"mpu6050", INV_MPU6050},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
+
+static struct i2c_driver inv_mpu_driver = {
+ .probe = inv_mpu_probe,
+ .remove = inv_mpu_remove,
+ .id_table = inv_mpu_id,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "inv-mpu6050",
+ .pm = INV_MPU6050_PMOPS,
+ },
+};
+
+module_i2c_driver(inv_mpu_driver);
+
+MODULE_AUTHOR("Invensense Corporation");
+MODULE_DESCRIPTION("Invensense device MPU6050 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
new file mode 100644
index 000000000000..f38395529a44
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -0,0 +1,246 @@
+/*
+* Copyright (C) 2012 Invensense, Inc.
+*
+* 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/i2c.h>
+#include <linux/kfifo.h>
+#include <linux/spinlock.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/platform_data/invensense_mpu6050.h>
+
+/**
+ * struct inv_mpu6050_reg_map - Notable registers.
+ * @sample_rate_div: Divider applied to gyro output rate.
+ * @lpf: Configures internal low pass filter.
+ * @user_ctrl: Enables/resets the FIFO.
+ * @fifo_en: Determines which data will appear in FIFO.
+ * @gyro_config: gyro config register.
+ * @accl_config: accel config register
+ * @fifo_count_h: Upper byte of FIFO count.
+ * @fifo_r_w: FIFO register.
+ * @raw_gyro: Address of first gyro register.
+ * @raw_accl: Address of first accel register.
+ * @temperature: temperature register
+ * @int_enable: Interrupt enable register.
+ * @pwr_mgmt_1: Controls chip's power state and clock source.
+ * @pwr_mgmt_2: Controls power state of individual sensors.
+ */
+struct inv_mpu6050_reg_map {
+ u8 sample_rate_div;
+ u8 lpf;
+ u8 user_ctrl;
+ u8 fifo_en;
+ u8 gyro_config;
+ u8 accl_config;
+ u8 fifo_count_h;
+ u8 fifo_r_w;
+ u8 raw_gyro;
+ u8 raw_accl;
+ u8 temperature;
+ u8 int_enable;
+ u8 pwr_mgmt_1;
+ u8 pwr_mgmt_2;
+};
+
+/*device enum */
+enum inv_devices {
+ INV_MPU6050,
+ INV_NUM_PARTS
+};
+
+/**
+ * struct inv_mpu6050_chip_config - Cached chip configuration data.
+ * @fsr: Full scale range.
+ * @lpf: Digital low pass filter frequency.
+ * @accl_fs: accel full scale range.
+ * @enable: master enable state.
+ * @accl_fifo_enable: enable accel data output
+ * @gyro_fifo_enable: enable gyro data output
+ * @fifo_rate: FIFO update rate.
+ */
+struct inv_mpu6050_chip_config {
+ unsigned int fsr:2;
+ unsigned int lpf:3;
+ unsigned int accl_fs:2;
+ unsigned int enable:1;
+ unsigned int accl_fifo_enable:1;
+ unsigned int gyro_fifo_enable:1;
+ u16 fifo_rate;
+};
+
+/**
+ * struct inv_mpu6050_hw - Other important hardware information.
+ * @num_reg: Number of registers on device.
+ * @name: name of the chip.
+ * @reg: register map of the chip.
+ * @config: configuration of the chip.
+ */
+struct inv_mpu6050_hw {
+ u8 num_reg;
+ u8 *name;
+ const struct inv_mpu6050_reg_map *reg;
+ const struct inv_mpu6050_chip_config *config;
+};
+
+/*
+ * struct inv_mpu6050_state - Driver state variables.
+ * @TIMESTAMP_FIFO_SIZE: fifo size for timestamp.
+ * @trig: IIO trigger.
+ * @chip_config: Cached attribute information.
+ * @reg: Map of important registers.
+ * @hw: Other hardware-specific information.
+ * @chip_type: chip type.
+ * @time_stamp_lock: spin lock to time stamp.
+ * @client: i2c client handle.
+ * @plat_data: platform data.
+ * @timestamps: kfifo queue to store time stamp.
+ */
+struct inv_mpu6050_state {
+#define TIMESTAMP_FIFO_SIZE 16
+ struct iio_trigger *trig;
+ struct inv_mpu6050_chip_config chip_config;
+ const struct inv_mpu6050_reg_map *reg;
+ const struct inv_mpu6050_hw *hw;
+ enum inv_devices chip_type;
+ spinlock_t time_stamp_lock;
+ struct i2c_client *client;
+ struct inv_mpu6050_platform_data plat_data;
+ DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
+};
+
+/*register and associated bit definition*/
+#define INV_MPU6050_REG_SAMPLE_RATE_DIV 0x19
+#define INV_MPU6050_REG_CONFIG 0x1A
+#define INV_MPU6050_REG_GYRO_CONFIG 0x1B
+#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C
+
+#define INV_MPU6050_REG_FIFO_EN 0x23
+#define INV_MPU6050_BIT_ACCEL_OUT 0x08
+#define INV_MPU6050_BITS_GYRO_OUT 0x70
+
+#define INV_MPU6050_REG_INT_ENABLE 0x38
+#define INV_MPU6050_BIT_DATA_RDY_EN 0x01
+#define INV_MPU6050_BIT_DMP_INT_EN 0x02
+
+#define INV_MPU6050_REG_RAW_ACCEL 0x3B
+#define INV_MPU6050_REG_TEMPERATURE 0x41
+#define INV_MPU6050_REG_RAW_GYRO 0x43
+
+#define INV_MPU6050_REG_USER_CTRL 0x6A
+#define INV_MPU6050_BIT_FIFO_RST 0x04
+#define INV_MPU6050_BIT_DMP_RST 0x08
+#define INV_MPU6050_BIT_I2C_MST_EN 0x20
+#define INV_MPU6050_BIT_FIFO_EN 0x40
+#define INV_MPU6050_BIT_DMP_EN 0x80
+
+#define INV_MPU6050_REG_PWR_MGMT_1 0x6B
+#define INV_MPU6050_BIT_H_RESET 0x80
+#define INV_MPU6050_BIT_SLEEP 0x40
+#define INV_MPU6050_BIT_CLK_MASK 0x7
+
+#define INV_MPU6050_REG_PWR_MGMT_2 0x6C
+#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38
+#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07
+
+#define INV_MPU6050_REG_FIFO_COUNT_H 0x72
+#define INV_MPU6050_REG_FIFO_R_W 0x74
+
+#define INV_MPU6050_BYTES_PER_3AXIS_SENSOR 6
+#define INV_MPU6050_FIFO_COUNT_BYTE 2
+#define INV_MPU6050_FIFO_THRESHOLD 500
+#define INV_MPU6050_POWER_UP_TIME 100
+#define INV_MPU6050_TEMP_UP_TIME 100
+#define INV_MPU6050_SENSOR_UP_TIME 30
+#define INV_MPU6050_REG_UP_TIME 5
+
+#define INV_MPU6050_TEMP_OFFSET 12421
+#define INV_MPU6050_TEMP_SCALE 2941
+#define INV_MPU6050_MAX_GYRO_FS_PARAM 3
+#define INV_MPU6050_MAX_ACCL_FS_PARAM 3
+#define INV_MPU6050_THREE_AXIS 3
+#define INV_MPU6050_GYRO_CONFIG_FSR_SHIFT 3
+#define INV_MPU6050_ACCL_CONFIG_FSR_SHIFT 3
+
+/* 6 + 6 round up and plus 8 */
+#define INV_MPU6050_OUTPUT_DATA_SIZE 24
+
+/* init parameters */
+#define INV_MPU6050_INIT_FIFO_RATE 50
+#define INV_MPU6050_TIME_STAMP_TOR 5
+#define INV_MPU6050_MAX_FIFO_RATE 1000
+#define INV_MPU6050_MIN_FIFO_RATE 4
+#define INV_MPU6050_ONE_K_HZ 1000
+
+/* scan element definition */
+enum inv_mpu6050_scan {
+ INV_MPU6050_SCAN_ACCL_X,
+ INV_MPU6050_SCAN_ACCL_Y,
+ INV_MPU6050_SCAN_ACCL_Z,
+ INV_MPU6050_SCAN_GYRO_X,
+ INV_MPU6050_SCAN_GYRO_Y,
+ INV_MPU6050_SCAN_GYRO_Z,
+ INV_MPU6050_SCAN_TIMESTAMP,
+};
+
+enum inv_mpu6050_filter_e {
+ INV_MPU6050_FILTER_256HZ_NOLPF2 = 0,
+ INV_MPU6050_FILTER_188HZ,
+ INV_MPU6050_FILTER_98HZ,
+ INV_MPU6050_FILTER_42HZ,
+ INV_MPU6050_FILTER_20HZ,
+ INV_MPU6050_FILTER_10HZ,
+ INV_MPU6050_FILTER_5HZ,
+ INV_MPU6050_FILTER_2100HZ_NOLPF,
+ NUM_MPU6050_FILTER
+};
+
+/* IIO attribute address */
+enum INV_MPU6050_IIO_ATTR_ADDR {
+ ATTR_GYRO_MATRIX,
+ ATTR_ACCL_MATRIX,
+};
+
+enum inv_mpu6050_accl_fs_e {
+ INV_MPU6050_FS_02G = 0,
+ INV_MPU6050_FS_04G,
+ INV_MPU6050_FS_08G,
+ INV_MPU6050_FS_16G,
+ NUM_ACCL_FSR
+};
+
+enum inv_mpu6050_fsr_e {
+ INV_MPU6050_FSR_250DPS = 0,
+ INV_MPU6050_FSR_500DPS,
+ INV_MPU6050_FSR_1000DPS,
+ INV_MPU6050_FSR_2000DPS,
+ NUM_MPU6050_FSR
+};
+
+enum inv_mpu6050_clock_sel_e {
+ INV_CLK_INTERNAL = 0,
+ INV_CLK_PLL,
+ NUM_CLK
+};
+
+irqreturn_t inv_mpu6050_irq_handler(int irq, void *p);
+irqreturn_t inv_mpu6050_read_fifo(int irq, void *p);
+int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev);
+void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st);
+int inv_reset_fifo(struct iio_dev *indio_dev);
+int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask);
+int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
+int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
new file mode 100644
index 000000000000..331781ffbb15
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
@@ -0,0 +1,196 @@
+/*
+* Copyright (C) 2012 Invensense, Inc.
+*
+* 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/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <linux/poll.h>
+#include "inv_mpu_iio.h"
+
+int inv_reset_fifo(struct iio_dev *indio_dev)
+{
+ int result;
+ u8 d;
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ /* disable interrupt */
+ result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0);
+ if (result) {
+ dev_err(&st->client->dev, "int_enable failed %d\n", result);
+ return result;
+ }
+ /* disable the sensor output to FIFO */
+ result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0);
+ if (result)
+ goto reset_fifo_fail;
+ /* disable fifo reading */
+ result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0);
+ if (result)
+ goto reset_fifo_fail;
+
+ /* reset FIFO*/
+ result = inv_mpu6050_write_reg(st, st->reg->user_ctrl,
+ INV_MPU6050_BIT_FIFO_RST);
+ if (result)
+ goto reset_fifo_fail;
+ /* enable interrupt */
+ if (st->chip_config.accl_fifo_enable ||
+ st->chip_config.gyro_fifo_enable) {
+ result = inv_mpu6050_write_reg(st, st->reg->int_enable,
+ INV_MPU6050_BIT_DATA_RDY_EN);
+ if (result)
+ return result;
+ }
+ /* enable FIFO reading and I2C master interface*/
+ result = inv_mpu6050_write_reg(st, st->reg->user_ctrl,
+ INV_MPU6050_BIT_FIFO_EN);
+ if (result)
+ goto reset_fifo_fail;
+ /* enable sensor output to FIFO */
+ d = 0;
+ if (st->chip_config.gyro_fifo_enable)
+ d |= INV_MPU6050_BITS_GYRO_OUT;
+ if (st->chip_config.accl_fifo_enable)
+ d |= INV_MPU6050_BIT_ACCEL_OUT;
+ result = inv_mpu6050_write_reg(st, st->reg->fifo_en, d);
+ if (result)
+ goto reset_fifo_fail;
+
+ return 0;
+
+reset_fifo_fail:
+ dev_err(&st->client->dev, "reset fifo failed %d\n", result);
+ result = inv_mpu6050_write_reg(st, st->reg->int_enable,
+ INV_MPU6050_BIT_DATA_RDY_EN);
+
+ return result;
+}
+
+static void inv_clear_kfifo(struct inv_mpu6050_state *st)
+{
+ unsigned long flags;
+
+ /* take the spin lock sem to avoid interrupt kick in */
+ spin_lock_irqsave(&st->time_stamp_lock, flags);
+ kfifo_reset(&st->timestamps);
+ spin_unlock_irqrestore(&st->time_stamp_lock, flags);
+}
+
+/**
+ * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt.
+ */
+irqreturn_t inv_mpu6050_irq_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+ s64 timestamp;
+
+ timestamp = iio_get_time_ns();
+ spin_lock(&st->time_stamp_lock);
+ kfifo_in(&st->timestamps, &timestamp, 1);
+ spin_unlock(&st->time_stamp_lock);
+
+ return IRQ_WAKE_THREAD;
+}
+
+/**
+ * inv_mpu6050_read_fifo() - Transfer data from hardware FIFO to KFIFO.
+ */
+irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+ size_t bytes_per_datum;
+ int result;
+ u8 data[INV_MPU6050_OUTPUT_DATA_SIZE];
+ u16 fifo_count;
+ s64 timestamp;
+ u64 *tmp;
+
+ mutex_lock(&indio_dev->mlock);
+ if (!(st->chip_config.accl_fifo_enable |
+ st->chip_config.gyro_fifo_enable))
+ goto end_session;
+ bytes_per_datum = 0;
+ if (st->chip_config.accl_fifo_enable)
+ bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
+
+ if (st->chip_config.gyro_fifo_enable)
+ bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
+
+ /*
+ * read fifo_count register to know how many bytes inside FIFO
+ * right now
+ */
+ result = i2c_smbus_read_i2c_block_data(st->client,
+ st->reg->fifo_count_h,
+ INV_MPU6050_FIFO_COUNT_BYTE, data);
+ if (result != INV_MPU6050_FIFO_COUNT_BYTE)
+ goto end_session;
+ fifo_count = be16_to_cpup((__be16 *)(&data[0]));
+ if (fifo_count < bytes_per_datum)
+ goto end_session;
+ /* fifo count can't be odd number, if it is odd, reset fifo*/
+ if (fifo_count & 1)
+ goto flush_fifo;
+ if (fifo_count > INV_MPU6050_FIFO_THRESHOLD)
+ goto flush_fifo;
+ /* Timestamp mismatch. */
+ if (kfifo_len(&st->timestamps) >
+ fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR)
+ goto flush_fifo;
+ while (fifo_count >= bytes_per_datum) {
+ result = i2c_smbus_read_i2c_block_data(st->client,
+ st->reg->fifo_r_w,
+ bytes_per_datum, data);
+ if (result != bytes_per_datum)
+ goto flush_fifo;
+
+ result = kfifo_out(&st->timestamps, &timestamp, 1);
+ /* when there is no timestamp, put timestamp as 0 */
+ if (0 == result)
+ timestamp = 0;
+
+ tmp = (u64 *)data;
+ tmp[DIV_ROUND_UP(bytes_per_datum, 8)] = timestamp;
+ result = iio_push_to_buffers(indio_dev, data);
+ if (result)
+ goto flush_fifo;
+ fifo_count -= bytes_per_datum;
+ }
+
+end_session:
+ mutex_unlock(&indio_dev->mlock);
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+
+flush_fifo:
+ /* Flush HW and SW FIFOs. */
+ inv_reset_fifo(indio_dev);
+ inv_clear_kfifo(st);
+ mutex_unlock(&indio_dev->mlock);
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
new file mode 100644
index 000000000000..e1d0869e0ad1
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -0,0 +1,155 @@
+/*
+* Copyright (C) 2012 Invensense, Inc.
+*
+* 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 "inv_mpu_iio.h"
+
+static void inv_scan_query(struct iio_dev *indio_dev)
+{
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ st->chip_config.gyro_fifo_enable =
+ test_bit(INV_MPU6050_SCAN_GYRO_X,
+ indio_dev->active_scan_mask) ||
+ test_bit(INV_MPU6050_SCAN_GYRO_Y,
+ indio_dev->active_scan_mask) ||
+ test_bit(INV_MPU6050_SCAN_GYRO_Z,
+ indio_dev->active_scan_mask);
+
+ st->chip_config.accl_fifo_enable =
+ test_bit(INV_MPU6050_SCAN_ACCL_X,
+ indio_dev->active_scan_mask) ||
+ test_bit(INV_MPU6050_SCAN_ACCL_Y,
+ indio_dev->active_scan_mask) ||
+ test_bit(INV_MPU6050_SCAN_ACCL_Z,
+ indio_dev->active_scan_mask);
+}
+
+/**
+ * inv_mpu6050_set_enable() - enable chip functions.
+ * @indio_dev: Device driver instance.
+ * @enable: enable/disable
+ */
+static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
+{
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+ int result;
+
+ if (enable) {
+ result = inv_mpu6050_set_power_itg(st, true);
+ if (result)
+ return result;
+ inv_scan_query(indio_dev);
+ if (st->chip_config.gyro_fifo_enable) {
+ result = inv_mpu6050_switch_engine(st, true,
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
+ if (result)
+ return result;
+ }
+ if (st->chip_config.accl_fifo_enable) {
+ result = inv_mpu6050_switch_engine(st, true,
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
+ if (result)
+ return result;
+ }
+ result = inv_reset_fifo(indio_dev);
+ if (result)
+ return result;
+ } else {
+ result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0);
+ if (result)
+ return result;
+
+ result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0);
+ if (result)
+ return result;
+
+ result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0);
+ if (result)
+ return result;
+
+ result = inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
+ if (result)
+ return result;
+
+ result = inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
+ if (result)
+ return result;
+ result = inv_mpu6050_set_power_itg(st, false);
+ if (result)
+ return result;
+ }
+ st->chip_config.enable = enable;
+
+ return 0;
+}
+
+/**
+ * inv_mpu_data_rdy_trigger_set_state() - set data ready interrupt state
+ * @trig: Trigger instance
+ * @state: Desired trigger state
+ */
+static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ return inv_mpu6050_set_enable(trig->private_data, state);
+}
+
+static const struct iio_trigger_ops inv_mpu_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = &inv_mpu_data_rdy_trigger_set_state,
+};
+
+int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ st->trig = iio_trigger_alloc("%s-dev%d",
+ indio_dev->name,
+ indio_dev->id);
+ if (st->trig == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll,
+ IRQF_TRIGGER_RISING,
+ "inv_mpu",
+ st->trig);
+ if (ret)
+ goto error_free_trig;
+ st->trig->dev.parent = &st->client->dev;
+ st->trig->private_data = indio_dev;
+ st->trig->ops = &inv_mpu_trigger_ops;
+ ret = iio_trigger_register(st->trig);
+ if (ret)
+ goto error_free_irq;
+ indio_dev->trig = st->trig;
+
+ return 0;
+
+error_free_irq:
+ free_irq(st->client->irq, st->trig);
+error_free_trig:
+ iio_trigger_free(st->trig);
+error_ret:
+ return ret;
+}
+
+void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st)
+{
+ iio_trigger_unregister(st->trig);
+ free_irq(st->client->irq, st->trig);
+ iio_trigger_free(st->trig);
+}
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 4fe0ead84213..4d6c7d84e155 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -160,7 +160,7 @@ void iio_trigger_notify_done(struct iio_trigger *trig)
trig->use_count--;
if (trig->use_count == 0 && trig->ops && trig->ops->try_reenable)
if (trig->ops->try_reenable(trig))
- /* Missed and interrupt so launch new poll now */
+ /* Missed an interrupt so launch new poll now */
iio_trigger_poll(trig, 0);
}
EXPORT_SYMBOL(iio_trigger_notify_done);
@@ -193,7 +193,7 @@ static void iio_trigger_put_irq(struct iio_trigger *trig, int irq)
* This is not currently handled. Alternative of not enabling trigger unless
* the relevant function is in there may be the best option.
*/
-/* Worth protecting against double additions?*/
+/* Worth protecting against double additions? */
static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
struct iio_poll_func *pf)
{
@@ -201,7 +201,7 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
bool notinuse
= bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
- /* Prevent the module being removed whilst attached to a trigger */
+ /* Prevent the module from being removed whilst attached to a trigger */
__module_get(pf->indio_dev->info->driver_module);
pf->irq = iio_trigger_get_irq(trig);
ret = request_threaded_irq(pf->irq, pf->h, pf->thread,
@@ -288,7 +288,7 @@ void iio_dealloc_pollfunc(struct iio_poll_func *pf)
EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc);
/**
- * iio_trigger_read_current() - trigger consumer sysfs query which trigger
+ * iio_trigger_read_current() - trigger consumer sysfs query current trigger
*
* For trigger consumers the current_trigger interface allows the trigger
* used by the device to be queried.
@@ -305,7 +305,7 @@ static ssize_t iio_trigger_read_current(struct device *dev,
}
/**
- * iio_trigger_write_current() trigger consumer sysfs set current trigger
+ * iio_trigger_write_current() - trigger consumer sysfs set current trigger
*
* For trigger consumers the current_trigger interface allows the trigger
* used for this device to be specified at run time based on the triggers
@@ -476,7 +476,7 @@ void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
{
- /* Clean up and associated but not attached triggers references */
+ /* Clean up an associated but not attached trigger reference */
if (indio_dev->trig)
iio_trigger_put(indio_dev->trig);
}
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index d55e98fb300e..b289915b8469 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -54,39 +54,25 @@ error_ret:
EXPORT_SYMBOL_GPL(iio_map_array_register);
-/* Assumes the exact same array (e.g. memory locations)
- * used at unregistration as used at registration rather than
- * more complex checking of contents.
+/*
+ * Remove all map entries associated with the given iio device
*/
-int iio_map_array_unregister(struct iio_dev *indio_dev,
- struct iio_map *maps)
+int iio_map_array_unregister(struct iio_dev *indio_dev)
{
- int i = 0, ret = 0;
- bool found_it;
+ int ret = -ENODEV;
struct iio_map_internal *mapi;
-
- if (maps == NULL)
- return 0;
+ struct list_head *pos, *tmp;
mutex_lock(&iio_map_list_lock);
- while (maps[i].consumer_dev_name != NULL) {
- found_it = false;
- list_for_each_entry(mapi, &iio_map_list, l)
- if (&maps[i] == mapi->map) {
- list_del(&mapi->l);
- kfree(mapi);
- found_it = true;
- break;
- }
- if (!found_it) {
- ret = -ENODEV;
- goto error_ret;
+ list_for_each_safe(pos, tmp, &iio_map_list) {
+ mapi = list_entry(pos, struct iio_map_internal, l);
+ if (indio_dev == mapi->indio_dev) {
+ list_del(&mapi->l);
+ kfree(mapi);
+ ret = 0;
}
- i++;
}
-error_ret:
mutex_unlock(&iio_map_list_lock);
-
return ret;
}
EXPORT_SYMBOL_GPL(iio_map_array_unregister);
@@ -107,7 +93,8 @@ static const struct iio_chan_spec
}
-struct iio_channel *iio_channel_get(const char *name, const char *channel_name)
+static struct iio_channel *iio_channel_get_sys(const char *name,
+ const char *channel_name)
{
struct iio_map_internal *c_i = NULL, *c = NULL;
struct iio_channel *channel;
@@ -158,6 +145,14 @@ error_no_mem:
iio_device_put(c->indio_dev);
return ERR_PTR(err);
}
+
+struct iio_channel *iio_channel_get(struct device *dev,
+ const char *channel_name)
+{
+ const char *name = dev ? dev_name(dev) : NULL;
+
+ return iio_channel_get_sys(name, channel_name);
+}
EXPORT_SYMBOL_GPL(iio_channel_get);
void iio_channel_release(struct iio_channel *channel)
@@ -167,16 +162,18 @@ void iio_channel_release(struct iio_channel *channel)
}
EXPORT_SYMBOL_GPL(iio_channel_release);
-struct iio_channel *iio_channel_get_all(const char *name)
+struct iio_channel *iio_channel_get_all(struct device *dev)
{
+ const char *name;
struct iio_channel *chans;
struct iio_map_internal *c = NULL;
int nummaps = 0;
int mapind = 0;
int i, ret;
- if (name == NULL)
+ if (dev == NULL)
return ERR_PTR(-EINVAL);
+ name = dev_name(dev);
mutex_lock(&iio_map_list_lock);
/* first count the matching maps */
diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
index 5bc5c860e9ca..a923c78d5cb4 100644
--- a/drivers/iio/kfifo_buf.c
+++ b/drivers/iio/kfifo_buf.c
@@ -22,7 +22,6 @@ static inline int __iio_allocate_kfifo(struct iio_kfifo *buf,
if ((length == 0) || (bytes_per_datum == 0))
return -EINVAL;
- __iio_update_buffer(&buf->buffer, bytes_per_datum, length);
return __kfifo_alloc((struct __kfifo *)&buf->kf, length,
bytes_per_datum, GFP_KERNEL);
}
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index dbf80abc834f..5ef1a396e0c9 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -32,6 +32,16 @@ config SENSORS_LM3533
changes. The ALS-control output values can be set per zone for the
three current output channels.
+config SENSORS_TSL2563
+ tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors"
+ depends on I2C
+ help
+ If you say yes here you get support for the Taos TSL2560,
+ TSL2561, TSL2562 and TSL2563 ambient light sensors.
+
+ This driver can also be built as a module. If so, the module
+ will be called tsl2563.
+
config VCNL4000
tristate "VCNL4000 combined ALS and proximity sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 21a8f0df1407..040d9c75f8e6 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -4,5 +4,6 @@
obj-$(CONFIG_ADJD_S311) += adjd_s311.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
+obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index e2d042f2a544..3d7e8c9b4beb 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -28,7 +28,6 @@
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-#include "../common/hid-sensors/hid-sensor-attributes.h"
#include "../common/hid-sensors/hid-sensor-trigger.h"
/*Format: HID-SENSOR-usage_id_in_hex*/
@@ -39,7 +38,7 @@
struct als_state {
struct hid_sensor_hub_callbacks callbacks;
- struct hid_sensor_iio_common common_attributes;
+ struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info als_illum;
u32 illum;
};
diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index 1a9adc020f64..fd8be69b7d05 100644
--- a/drivers/staging/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -1,5 +1,5 @@
/*
- * drivers/i2c/chips/tsl2563.c
+ * drivers/iio/light/tsl2563.c
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -38,52 +38,52 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
-#include "tsl2563.h"
+#include <linux/platform_data/tsl2563.h>
/* Use this many bits for fraction part. */
-#define ADC_FRAC_BITS (14)
+#define ADC_FRAC_BITS 14
/* Given number of 1/10000's in ADC_FRAC_BITS precision. */
#define FRAC10K(f) (((f) * (1L << (ADC_FRAC_BITS))) / (10000))
/* Bits used for fraction in calibration coefficients.*/
-#define CALIB_FRAC_BITS (10)
+#define CALIB_FRAC_BITS 10
/* 0.5 in CALIB_FRAC_BITS precision */
#define CALIB_FRAC_HALF (1 << (CALIB_FRAC_BITS - 1))
/* Make a fraction from a number n that was multiplied with b. */
#define CALIB_FRAC(n, b) (((n) << CALIB_FRAC_BITS) / (b))
/* Decimal 10^(digits in sysfs presentation) */
-#define CALIB_BASE_SYSFS (1000)
-
-#define TSL2563_CMD (0x80)
-#define TSL2563_CLEARINT (0x40)
-
-#define TSL2563_REG_CTRL (0x00)
-#define TSL2563_REG_TIMING (0x01)
-#define TSL2563_REG_LOWLOW (0x02) /* data0 low threshold, 2 bytes */
-#define TSL2563_REG_LOWHIGH (0x03)
-#define TSL2563_REG_HIGHLOW (0x04) /* data0 high threshold, 2 bytes */
-#define TSL2563_REG_HIGHHIGH (0x05)
-#define TSL2563_REG_INT (0x06)
-#define TSL2563_REG_ID (0x0a)
-#define TSL2563_REG_DATA0LOW (0x0c) /* broadband sensor value, 2 bytes */
-#define TSL2563_REG_DATA0HIGH (0x0d)
-#define TSL2563_REG_DATA1LOW (0x0e) /* infrared sensor value, 2 bytes */
-#define TSL2563_REG_DATA1HIGH (0x0f)
-
-#define TSL2563_CMD_POWER_ON (0x03)
-#define TSL2563_CMD_POWER_OFF (0x00)
-#define TSL2563_CTRL_POWER_MASK (0x03)
-
-#define TSL2563_TIMING_13MS (0x00)
-#define TSL2563_TIMING_100MS (0x01)
-#define TSL2563_TIMING_400MS (0x02)
-#define TSL2563_TIMING_MASK (0x03)
-#define TSL2563_TIMING_GAIN16 (0x10)
-#define TSL2563_TIMING_GAIN1 (0x00)
-
-#define TSL2563_INT_DISBLED (0x00)
-#define TSL2563_INT_LEVEL (0x10)
+#define CALIB_BASE_SYSFS 1000
+
+#define TSL2563_CMD 0x80
+#define TSL2563_CLEARINT 0x40
+
+#define TSL2563_REG_CTRL 0x00
+#define TSL2563_REG_TIMING 0x01
+#define TSL2563_REG_LOWLOW 0x02 /* data0 low threshold, 2 bytes */
+#define TSL2563_REG_LOWHIGH 0x03
+#define TSL2563_REG_HIGHLOW 0x04 /* data0 high threshold, 2 bytes */
+#define TSL2563_REG_HIGHHIGH 0x05
+#define TSL2563_REG_INT 0x06
+#define TSL2563_REG_ID 0x0a
+#define TSL2563_REG_DATA0LOW 0x0c /* broadband sensor value, 2 bytes */
+#define TSL2563_REG_DATA0HIGH 0x0d
+#define TSL2563_REG_DATA1LOW 0x0e /* infrared sensor value, 2 bytes */
+#define TSL2563_REG_DATA1HIGH 0x0f
+
+#define TSL2563_CMD_POWER_ON 0x03
+#define TSL2563_CMD_POWER_OFF 0x00
+#define TSL2563_CTRL_POWER_MASK 0x03
+
+#define TSL2563_TIMING_13MS 0x00
+#define TSL2563_TIMING_100MS 0x01
+#define TSL2563_TIMING_400MS 0x02
+#define TSL2563_TIMING_MASK 0x03
+#define TSL2563_TIMING_GAIN16 0x10
+#define TSL2563_TIMING_GAIN1 0x00
+
+#define TSL2563_INT_DISBLED 0x00
+#define TSL2563_INT_LEVEL 0x10
#define TSL2563_INT_PERSIST(n) ((n) & 0x0F)
struct tsl2563_gainlevel_coeff {
@@ -190,8 +190,10 @@ static int tsl2563_configure(struct tsl2563_chip *chip)
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_LOWHIGH,
(chip->low_thres >> 8) & 0xFF);
-/* Interrupt register is automatically written anyway if it is relevant
- so is not here */
+/*
+ * Interrupt register is automatically written anyway if it is relevant
+ * so is not here.
+ */
error_ret:
return ret;
}
@@ -423,9 +425,7 @@ static const struct tsl2563_lux_coeff lux_table[] = {
},
};
-/*
- * Convert normalized, scaled ADC values to lux.
- */
+/* Convert normalized, scaled ADC values to lux. */
static unsigned int adc_to_lux(u32 adc0, u32 adc1)
{
const struct tsl2563_lux_coeff *lp = lux_table;
@@ -441,11 +441,6 @@ static unsigned int adc_to_lux(u32 adc0, u32 adc1)
return (unsigned int) (lux >> ADC_FRAC_BITS);
}
-/*--------------------------------------------------------------*/
-/* Sysfs interface */
-/*--------------------------------------------------------------*/
-
-
/* Apply calibration coefficient to ADC count. */
static u32 calib_adc(u32 adc, u32 calib)
{
@@ -677,18 +672,11 @@ static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev,
TSL2563_CMD | TSL2563_REG_INT);
mutex_unlock(&chip->lock);
if (ret < 0)
- goto error_ret;
- ret = !!(ret & 0x30);
-error_ret:
+ return ret;
- return ret;
+ return !!(ret & 0x30);
}
-/*--------------------------------------------------------------*/
-/* Probe, Attach, Remove */
-/*--------------------------------------------------------------*/
-static struct i2c_driver tsl2563_i2c_driver;
-
static const struct iio_info tsl2563_info_no_irq = {
.driver_module = THIS_MODULE,
.read_raw = &tsl2563_read_raw,
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index ff11d68225cf..cd29be54f643 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -14,4 +14,34 @@ config HID_SENSOR_MAGNETOMETER_3D
Say yes here to build support for the HID SENSOR
Magnetometer 3D.
+config IIO_ST_MAGN_3AXIS
+ tristate "STMicroelectronics magnetometers 3-Axis Driver"
+ depends on (I2C || SPI_MASTER) && SYSFS
+ select IIO_ST_SENSORS_CORE
+ select IIO_ST_MAGN_I2C_3AXIS if (I2C)
+ select IIO_ST_MAGN_SPI_3AXIS if (SPI_MASTER)
+ select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
+ select IIO_ST_MAGN_BUFFER if (IIO_TRIGGERED_BUFFER)
+ help
+ Say yes here to build support for STMicroelectronics magnetometers:
+ LSM303DLHC, LSM303DLM, LIS3MDL.
+
+ This driver can also be built as a module. If so, will be created
+ these modules:
+ - st_magn (core functions for the driver [it is mandatory]);
+ - st_magn_i2c (necessary for the I2C devices [optional*]);
+ - st_magn_spi (necessary for the SPI devices [optional*]);
+
+ (*) one of these is necessary to do something.
+
+config IIO_ST_MAGN_I2C_3AXIS
+ tristate
+ depends on IIO_ST_MAGN_3AXIS
+ depends on IIO_ST_SENSORS_I2C
+
+config IIO_ST_MAGN_SPI_3AXIS
+ tristate
+ depends on IIO_ST_MAGN_3AXIS
+ depends on IIO_ST_SENSORS_SPI
+
endmenu
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index 60dc4f2b1963..e78672876dc2 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -3,3 +3,10 @@
#
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
+
+obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o
+st_magn-y := st_magn_core.o
+st_magn-$(CONFIG_IIO_BUFFER) += st_magn_buffer.o
+
+obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o
+obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index 7ac2c7483ba8..d8d01265220b 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -28,7 +28,6 @@
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-#include "../common/hid-sensors/hid-sensor-attributes.h"
#include "../common/hid-sensors/hid-sensor-trigger.h"
/*Format: HID-SENSOR-usage_id_in_hex*/
@@ -44,7 +43,7 @@ enum magn_3d_channel {
struct magn_3d_state {
struct hid_sensor_hub_callbacks callbacks;
- struct hid_sensor_iio_common common_attributes;
+ struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX];
u32 magn_val[MAGN_3D_CHANNEL_MAX];
};
diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h
new file mode 100644
index 000000000000..7e81d00ef0c3
--- /dev/null
+++ b/drivers/iio/magnetometer/st_magn.h
@@ -0,0 +1,45 @@
+/*
+ * STMicroelectronics magnetometers driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ * v. 1.0.0
+ * Licensed under the GPL-2.
+ */
+
+#ifndef ST_MAGN_H
+#define ST_MAGN_H
+
+#include <linux/types.h>
+#include <linux/iio/common/st_sensors.h>
+
+#define LSM303DLHC_MAGN_DEV_NAME "lsm303dlhc_magn"
+#define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn"
+#define LIS3MDL_MAGN_DEV_NAME "lis3mdl"
+
+int st_magn_common_probe(struct iio_dev *indio_dev);
+void st_magn_common_remove(struct iio_dev *indio_dev);
+
+#ifdef CONFIG_IIO_BUFFER
+int st_magn_allocate_ring(struct iio_dev *indio_dev);
+void st_magn_deallocate_ring(struct iio_dev *indio_dev);
+#else /* CONFIG_IIO_BUFFER */
+static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq)
+{
+ return 0;
+}
+static inline void st_magn_remove_trigger(struct iio_dev *indio_dev, int irq)
+{
+ return;
+}
+static inline int st_magn_allocate_ring(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+static inline void st_magn_deallocate_ring(struct iio_dev *indio_dev)
+{
+}
+#endif /* CONFIG_IIO_BUFFER */
+
+#endif /* ST_MAGN_H */
diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c
new file mode 100644
index 000000000000..708857bdb47d
--- /dev/null
+++ b/drivers/iio/magnetometer/st_magn_buffer.c
@@ -0,0 +1,98 @@
+/*
+ * STMicroelectronics magnetometers driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include "st_magn.h"
+
+static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
+{
+ int err;
+
+ err = st_sensors_set_enable(indio_dev, true);
+ if (err < 0)
+ goto st_magn_set_enable_error;
+
+ err = iio_sw_buffer_preenable(indio_dev);
+
+st_magn_set_enable_error:
+ return err;
+}
+
+static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *mdata = iio_priv(indio_dev);
+
+ mdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+ if (mdata->buffer_data == NULL) {
+ err = -ENOMEM;
+ goto allocate_memory_error;
+ }
+
+ err = iio_triggered_buffer_postenable(indio_dev);
+ if (err < 0)
+ goto st_magn_buffer_postenable_error;
+
+ return err;
+
+st_magn_buffer_postenable_error:
+ kfree(mdata->buffer_data);
+allocate_memory_error:
+ return err;
+}
+
+static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *mdata = iio_priv(indio_dev);
+
+ err = iio_triggered_buffer_predisable(indio_dev);
+ if (err < 0)
+ goto st_magn_buffer_predisable_error;
+
+ err = st_sensors_set_enable(indio_dev, false);
+
+st_magn_buffer_predisable_error:
+ kfree(mdata->buffer_data);
+ return err;
+}
+
+static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
+ .preenable = &st_magn_buffer_preenable,
+ .postenable = &st_magn_buffer_postenable,
+ .predisable = &st_magn_buffer_predisable,
+};
+
+int st_magn_allocate_ring(struct iio_dev *indio_dev)
+{
+ return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ &st_sensors_trigger_handler, &st_magn_buffer_setup_ops);
+}
+
+void st_magn_deallocate_ring(struct iio_dev *indio_dev)
+{
+ iio_triggered_buffer_cleanup(indio_dev);
+}
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics magnetometers buffer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
new file mode 100644
index 000000000000..16f0d6df239f
--- /dev/null
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -0,0 +1,400 @@
+/*
+ * STMicroelectronics magnetometers driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include "st_magn.h"
+
+/* DEFAULT VALUE FOR SENSORS */
+#define ST_MAGN_DEFAULT_OUT_X_L_ADDR 0X04
+#define ST_MAGN_DEFAULT_OUT_Y_L_ADDR 0X08
+#define ST_MAGN_DEFAULT_OUT_Z_L_ADDR 0X06
+
+/* FULLSCALE */
+#define ST_MAGN_FS_AVL_1300MG 1300
+#define ST_MAGN_FS_AVL_1900MG 1900
+#define ST_MAGN_FS_AVL_2500MG 2500
+#define ST_MAGN_FS_AVL_4000MG 4000
+#define ST_MAGN_FS_AVL_4700MG 4700
+#define ST_MAGN_FS_AVL_5600MG 5600
+#define ST_MAGN_FS_AVL_8000MG 8000
+#define ST_MAGN_FS_AVL_8100MG 8100
+#define ST_MAGN_FS_AVL_10000MG 10000
+
+/* CUSTOM VALUES FOR SENSOR 1 */
+#define ST_MAGN_1_WAI_EXP 0x3c
+#define ST_MAGN_1_ODR_ADDR 0x00
+#define ST_MAGN_1_ODR_MASK 0x1c
+#define ST_MAGN_1_ODR_AVL_1HZ_VAL 0x00
+#define ST_MAGN_1_ODR_AVL_2HZ_VAL 0x01
+#define ST_MAGN_1_ODR_AVL_3HZ_VAL 0x02
+#define ST_MAGN_1_ODR_AVL_8HZ_VAL 0x03
+#define ST_MAGN_1_ODR_AVL_15HZ_VAL 0x04
+#define ST_MAGN_1_ODR_AVL_30HZ_VAL 0x05
+#define ST_MAGN_1_ODR_AVL_75HZ_VAL 0x06
+#define ST_MAGN_1_ODR_AVL_220HZ_VAL 0x07
+#define ST_MAGN_1_PW_ADDR 0x02
+#define ST_MAGN_1_PW_MASK 0x03
+#define ST_MAGN_1_PW_ON 0x00
+#define ST_MAGN_1_PW_OFF 0x03
+#define ST_MAGN_1_FS_ADDR 0x01
+#define ST_MAGN_1_FS_MASK 0xe0
+#define ST_MAGN_1_FS_AVL_1300_VAL 0x01
+#define ST_MAGN_1_FS_AVL_1900_VAL 0x02
+#define ST_MAGN_1_FS_AVL_2500_VAL 0x03
+#define ST_MAGN_1_FS_AVL_4000_VAL 0x04
+#define ST_MAGN_1_FS_AVL_4700_VAL 0x05
+#define ST_MAGN_1_FS_AVL_5600_VAL 0x06
+#define ST_MAGN_1_FS_AVL_8100_VAL 0x07
+#define ST_MAGN_1_FS_AVL_1300_GAIN_XY 1100
+#define ST_MAGN_1_FS_AVL_1900_GAIN_XY 855
+#define ST_MAGN_1_FS_AVL_2500_GAIN_XY 670
+#define ST_MAGN_1_FS_AVL_4000_GAIN_XY 450
+#define ST_MAGN_1_FS_AVL_4700_GAIN_XY 400
+#define ST_MAGN_1_FS_AVL_5600_GAIN_XY 330
+#define ST_MAGN_1_FS_AVL_8100_GAIN_XY 230
+#define ST_MAGN_1_FS_AVL_1300_GAIN_Z 980
+#define ST_MAGN_1_FS_AVL_1900_GAIN_Z 760
+#define ST_MAGN_1_FS_AVL_2500_GAIN_Z 600
+#define ST_MAGN_1_FS_AVL_4000_GAIN_Z 400
+#define ST_MAGN_1_FS_AVL_4700_GAIN_Z 355
+#define ST_MAGN_1_FS_AVL_5600_GAIN_Z 295
+#define ST_MAGN_1_FS_AVL_8100_GAIN_Z 205
+#define ST_MAGN_1_MULTIREAD_BIT false
+
+/* CUSTOM VALUES FOR SENSOR 2 */
+#define ST_MAGN_2_WAI_EXP 0x3d
+#define ST_MAGN_2_ODR_ADDR 0x20
+#define ST_MAGN_2_ODR_MASK 0x1c
+#define ST_MAGN_2_ODR_AVL_1HZ_VAL 0x00
+#define ST_MAGN_2_ODR_AVL_2HZ_VAL 0x01
+#define ST_MAGN_2_ODR_AVL_3HZ_VAL 0x02
+#define ST_MAGN_2_ODR_AVL_5HZ_VAL 0x03
+#define ST_MAGN_2_ODR_AVL_10HZ_VAL 0x04
+#define ST_MAGN_2_ODR_AVL_20HZ_VAL 0x05
+#define ST_MAGN_2_ODR_AVL_40HZ_VAL 0x06
+#define ST_MAGN_2_ODR_AVL_80HZ_VAL 0x07
+#define ST_MAGN_2_PW_ADDR 0x22
+#define ST_MAGN_2_PW_MASK 0x03
+#define ST_MAGN_2_PW_ON 0x00
+#define ST_MAGN_2_PW_OFF 0x03
+#define ST_MAGN_2_FS_ADDR 0x21
+#define ST_MAGN_2_FS_MASK 0x60
+#define ST_MAGN_2_FS_AVL_4000_VAL 0x00
+#define ST_MAGN_2_FS_AVL_8000_VAL 0x01
+#define ST_MAGN_2_FS_AVL_10000_VAL 0x02
+#define ST_MAGN_2_FS_AVL_4000_GAIN 430
+#define ST_MAGN_2_FS_AVL_8000_GAIN 230
+#define ST_MAGN_2_FS_AVL_10000_GAIN 230
+#define ST_MAGN_2_MULTIREAD_BIT false
+#define ST_MAGN_2_OUT_X_L_ADDR 0x28
+#define ST_MAGN_2_OUT_Y_L_ADDR 0x2a
+#define ST_MAGN_2_OUT_Z_L_ADDR 0x2c
+
+static const struct iio_chan_spec st_magn_16bit_channels[] = {
+ ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
+ ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_DEFAULT_OUT_X_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
+ ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_DEFAULT_OUT_Y_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
+ ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_DEFAULT_OUT_Z_L_ADDR),
+ IIO_CHAN_SOFT_TIMESTAMP(3)
+};
+
+static const struct iio_chan_spec st_magn_2_16bit_channels[] = {
+ ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
+ ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_2_OUT_X_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
+ ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_2_OUT_Y_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
+ ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_2_OUT_Z_L_ADDR),
+ IIO_CHAN_SOFT_TIMESTAMP(3)
+};
+
+static const struct st_sensors st_magn_sensors[] = {
+ {
+ .wai = ST_MAGN_1_WAI_EXP,
+ .sensors_supported = {
+ [0] = LSM303DLHC_MAGN_DEV_NAME,
+ [1] = LSM303DLM_MAGN_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_magn_16bit_channels,
+ .odr = {
+ .addr = ST_MAGN_1_ODR_ADDR,
+ .mask = ST_MAGN_1_ODR_MASK,
+ .odr_avl = {
+ { 1, ST_MAGN_1_ODR_AVL_1HZ_VAL, },
+ { 2, ST_MAGN_1_ODR_AVL_2HZ_VAL, },
+ { 3, ST_MAGN_1_ODR_AVL_3HZ_VAL, },
+ { 8, ST_MAGN_1_ODR_AVL_8HZ_VAL, },
+ { 15, ST_MAGN_1_ODR_AVL_15HZ_VAL, },
+ { 30, ST_MAGN_1_ODR_AVL_30HZ_VAL, },
+ { 75, ST_MAGN_1_ODR_AVL_75HZ_VAL, },
+ { 220, ST_MAGN_1_ODR_AVL_220HZ_VAL, },
+ },
+ },
+ .pw = {
+ .addr = ST_MAGN_1_PW_ADDR,
+ .mask = ST_MAGN_1_PW_MASK,
+ .value_on = ST_MAGN_1_PW_ON,
+ .value_off = ST_MAGN_1_PW_OFF,
+ },
+ .fs = {
+ .addr = ST_MAGN_1_FS_ADDR,
+ .mask = ST_MAGN_1_FS_MASK,
+ .fs_avl = {
+ [0] = {
+ .num = ST_MAGN_FS_AVL_1300MG,
+ .value = ST_MAGN_1_FS_AVL_1300_VAL,
+ .gain = ST_MAGN_1_FS_AVL_1300_GAIN_XY,
+ .gain2 = ST_MAGN_1_FS_AVL_1300_GAIN_Z,
+ },
+ [1] = {
+ .num = ST_MAGN_FS_AVL_1900MG,
+ .value = ST_MAGN_1_FS_AVL_1900_VAL,
+ .gain = ST_MAGN_1_FS_AVL_1900_GAIN_XY,
+ .gain2 = ST_MAGN_1_FS_AVL_1900_GAIN_Z,
+ },
+ [2] = {
+ .num = ST_MAGN_FS_AVL_2500MG,
+ .value = ST_MAGN_1_FS_AVL_2500_VAL,
+ .gain = ST_MAGN_1_FS_AVL_2500_GAIN_XY,
+ .gain2 = ST_MAGN_1_FS_AVL_2500_GAIN_Z,
+ },
+ [3] = {
+ .num = ST_MAGN_FS_AVL_4000MG,
+ .value = ST_MAGN_1_FS_AVL_4000_VAL,
+ .gain = ST_MAGN_1_FS_AVL_4000_GAIN_XY,
+ .gain2 = ST_MAGN_1_FS_AVL_4000_GAIN_Z,
+ },
+ [4] = {
+ .num = ST_MAGN_FS_AVL_4700MG,
+ .value = ST_MAGN_1_FS_AVL_4700_VAL,
+ .gain = ST_MAGN_1_FS_AVL_4700_GAIN_XY,
+ .gain2 = ST_MAGN_1_FS_AVL_4700_GAIN_Z,
+ },
+ [5] = {
+ .num = ST_MAGN_FS_AVL_5600MG,
+ .value = ST_MAGN_1_FS_AVL_5600_VAL,
+ .gain = ST_MAGN_1_FS_AVL_5600_GAIN_XY,
+ .gain2 = ST_MAGN_1_FS_AVL_5600_GAIN_Z,
+ },
+ [6] = {
+ .num = ST_MAGN_FS_AVL_8100MG,
+ .value = ST_MAGN_1_FS_AVL_8100_VAL,
+ .gain = ST_MAGN_1_FS_AVL_8100_GAIN_XY,
+ .gain2 = ST_MAGN_1_FS_AVL_8100_GAIN_Z,
+ },
+ },
+ },
+ .multi_read_bit = ST_MAGN_1_MULTIREAD_BIT,
+ .bootime = 2,
+ },
+ {
+ .wai = ST_MAGN_2_WAI_EXP,
+ .sensors_supported = {
+ [0] = LIS3MDL_MAGN_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_magn_2_16bit_channels,
+ .odr = {
+ .addr = ST_MAGN_2_ODR_ADDR,
+ .mask = ST_MAGN_2_ODR_MASK,
+ .odr_avl = {
+ { 1, ST_MAGN_2_ODR_AVL_1HZ_VAL, },
+ { 2, ST_MAGN_2_ODR_AVL_2HZ_VAL, },
+ { 3, ST_MAGN_2_ODR_AVL_3HZ_VAL, },
+ { 5, ST_MAGN_2_ODR_AVL_5HZ_VAL, },
+ { 10, ST_MAGN_2_ODR_AVL_10HZ_VAL, },
+ { 20, ST_MAGN_2_ODR_AVL_20HZ_VAL, },
+ { 40, ST_MAGN_2_ODR_AVL_40HZ_VAL, },
+ { 80, ST_MAGN_2_ODR_AVL_80HZ_VAL, },
+ },
+ },
+ .pw = {
+ .addr = ST_MAGN_2_PW_ADDR,
+ .mask = ST_MAGN_2_PW_MASK,
+ .value_on = ST_MAGN_2_PW_ON,
+ .value_off = ST_MAGN_2_PW_OFF,
+ },
+ .fs = {
+ .addr = ST_MAGN_2_FS_ADDR,
+ .mask = ST_MAGN_2_FS_MASK,
+ .fs_avl = {
+ [0] = {
+ .num = ST_MAGN_FS_AVL_4000MG,
+ .value = ST_MAGN_2_FS_AVL_4000_VAL,
+ .gain = ST_MAGN_2_FS_AVL_4000_GAIN,
+ },
+ [1] = {
+ .num = ST_MAGN_FS_AVL_8000MG,
+ .value = ST_MAGN_2_FS_AVL_8000_VAL,
+ .gain = ST_MAGN_2_FS_AVL_8000_GAIN,
+ },
+ [2] = {
+ .num = ST_MAGN_FS_AVL_10000MG,
+ .value = ST_MAGN_2_FS_AVL_10000_VAL,
+ .gain = ST_MAGN_2_FS_AVL_10000_GAIN,
+ },
+ },
+ },
+ .multi_read_bit = ST_MAGN_2_MULTIREAD_BIT,
+ .bootime = 2,
+ },
+};
+
+static int st_magn_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *ch, int *val,
+ int *val2, long mask)
+{
+ int err;
+ struct st_sensor_data *mdata = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ err = st_sensors_read_info_raw(indio_dev, ch, val);
+ if (err < 0)
+ goto read_error;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ if ((ch->scan_index == ST_SENSORS_SCAN_Z) &&
+ (mdata->current_fullscale->gain2 != 0))
+ *val2 = mdata->current_fullscale->gain2;
+ else
+ *val2 = mdata->current_fullscale->gain;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+
+read_error:
+ return err;
+}
+
+static int st_magn_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+ int err;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
+static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
+static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_magn_scale_available);
+
+static struct attribute *st_magn_attributes[] = {
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_in_magn_scale_available.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group st_magn_attribute_group = {
+ .attrs = st_magn_attributes,
+};
+
+static const struct iio_info magn_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &st_magn_attribute_group,
+ .read_raw = &st_magn_read_raw,
+ .write_raw = &st_magn_write_raw,
+};
+
+int st_magn_common_probe(struct iio_dev *indio_dev)
+{
+ int err;
+ struct st_sensor_data *mdata = iio_priv(indio_dev);
+
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &magn_info;
+
+ err = st_sensors_check_device_support(indio_dev,
+ ARRAY_SIZE(st_magn_sensors), st_magn_sensors);
+ if (err < 0)
+ goto st_magn_common_probe_error;
+
+ mdata->multiread_bit = mdata->sensor->multi_read_bit;
+ indio_dev->channels = mdata->sensor->ch;
+ indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
+
+ mdata->current_fullscale = (struct st_sensor_fullscale_avl *)
+ &mdata->sensor->fs.fs_avl[0];
+ mdata->odr = mdata->sensor->odr.odr_avl[0].hz;
+
+ err = st_sensors_init_sensor(indio_dev);
+ if (err < 0)
+ goto st_magn_common_probe_error;
+
+ if (mdata->get_irq_data_ready(indio_dev) > 0) {
+ err = st_magn_allocate_ring(indio_dev);
+ if (err < 0)
+ goto st_magn_common_probe_error;
+ err = st_sensors_allocate_trigger(indio_dev, NULL);
+ if (err < 0)
+ goto st_magn_probe_trigger_error;
+ }
+
+ err = iio_device_register(indio_dev);
+ if (err)
+ goto st_magn_device_register_error;
+
+ return err;
+
+st_magn_device_register_error:
+ if (mdata->get_irq_data_ready(indio_dev) > 0)
+ st_sensors_deallocate_trigger(indio_dev);
+st_magn_probe_trigger_error:
+ if (mdata->get_irq_data_ready(indio_dev) > 0)
+ st_magn_deallocate_ring(indio_dev);
+st_magn_common_probe_error:
+ return err;
+}
+EXPORT_SYMBOL(st_magn_common_probe);
+
+void st_magn_common_remove(struct iio_dev *indio_dev)
+{
+ struct st_sensor_data *mdata = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ if (mdata->get_irq_data_ready(indio_dev) > 0) {
+ st_sensors_deallocate_trigger(indio_dev);
+ st_magn_deallocate_ring(indio_dev);
+ }
+ iio_device_free(indio_dev);
+}
+EXPORT_SYMBOL(st_magn_common_remove);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics magnetometers driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
new file mode 100644
index 000000000000..e6adc4a86425
--- /dev/null
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -0,0 +1,80 @@
+/*
+ * STMicroelectronics magnetometers driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include <linux/iio/common/st_sensors_i2c.h>
+#include "st_magn.h"
+
+static int st_magn_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct st_sensor_data *mdata;
+ int err;
+
+ indio_dev = iio_device_alloc(sizeof(*mdata));
+ if (indio_dev == NULL) {
+ err = -ENOMEM;
+ goto iio_device_alloc_error;
+ }
+
+ mdata = iio_priv(indio_dev);
+ mdata->dev = &client->dev;
+
+ st_sensors_i2c_configure(indio_dev, client, mdata);
+
+ err = st_magn_common_probe(indio_dev);
+ if (err < 0)
+ goto st_magn_common_probe_error;
+
+ return 0;
+
+st_magn_common_probe_error:
+ iio_device_free(indio_dev);
+iio_device_alloc_error:
+ return err;
+}
+
+static int st_magn_i2c_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ st_magn_common_remove(indio_dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id st_magn_id_table[] = {
+ { LSM303DLHC_MAGN_DEV_NAME },
+ { LSM303DLM_MAGN_DEV_NAME },
+ { LIS3MDL_MAGN_DEV_NAME },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
+
+static struct i2c_driver st_magn_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "st-magn-i2c",
+ },
+ .probe = st_magn_i2c_probe,
+ .remove = st_magn_i2c_remove,
+ .id_table = st_magn_id_table,
+};
+module_i2c_driver(st_magn_driver);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics magnetometers i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
new file mode 100644
index 000000000000..51adb797cb7d
--- /dev/null
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -0,0 +1,79 @@
+/*
+ * STMicroelectronics magnetometers driver
+ *
+ * Copyright 2012-2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/iio/iio.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include <linux/iio/common/st_sensors_spi.h>
+#include "st_magn.h"
+
+static int st_magn_spi_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct st_sensor_data *mdata;
+ int err;
+
+ indio_dev = iio_device_alloc(sizeof(*mdata));
+ if (indio_dev == NULL) {
+ err = -ENOMEM;
+ goto iio_device_alloc_error;
+ }
+
+ mdata = iio_priv(indio_dev);
+ mdata->dev = &spi->dev;
+
+ st_sensors_spi_configure(indio_dev, spi, mdata);
+
+ err = st_magn_common_probe(indio_dev);
+ if (err < 0)
+ goto st_magn_common_probe_error;
+
+ return 0;
+
+st_magn_common_probe_error:
+ iio_device_free(indio_dev);
+iio_device_alloc_error:
+ return err;
+}
+
+static int st_magn_spi_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ st_magn_common_remove(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id st_magn_id_table[] = {
+ { LSM303DLHC_MAGN_DEV_NAME },
+ { LSM303DLM_MAGN_DEV_NAME },
+ { LIS3MDL_MAGN_DEV_NAME },
+ {},
+};
+MODULE_DEVICE_TABLE(spi, st_magn_id_table);
+
+static struct spi_driver st_magn_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "st-magn-spi",
+ },
+ .probe = st_magn_spi_probe,
+ .remove = st_magn_spi_remove,
+ .id_table = st_magn_id_table,
+};
+module_spi_driver(st_magn_driver);
+
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics magnetometers spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index 0bdf09aa6f42..145d82a64d0a 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -783,8 +783,8 @@ static int iwch_dealloc_mw(struct ib_mw *mw)
mmid = (mw->rkey) >> 8;
cxio_deallocate_window(&rhp->rdev, mhp->attr.stag);
remove_handle(rhp, &rhp->mmidr, mmid);
- kfree(mhp);
PDBG("%s ib_mw %p mmid 0x%x ptr %p\n", __func__, mw, mmid, mhp);
+ kfree(mhp);
return 0;
}
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index 5b152a366dff..429141078eec 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -135,6 +135,7 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
struct net_device *event_netdev = ifa->ifa_dev->dev;
struct nes_device *nesdev;
struct net_device *netdev;
+ struct net_device *upper_dev;
struct nes_vnic *nesvnic;
unsigned int is_bonded;
@@ -145,8 +146,9 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
nesdev, nesdev->netdev[0]->name);
netdev = nesdev->netdev[0];
nesvnic = netdev_priv(netdev);
+ upper_dev = netdev_master_upper_dev_get(netdev);
is_bonded = netif_is_bond_slave(netdev) &&
- (netdev->master == event_netdev);
+ (upper_dev == event_netdev);
if ((netdev == event_netdev) || is_bonded) {
if (nesvnic->rdma_enabled == 0) {
nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
@@ -179,9 +181,9 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
/* fall through */
case NETDEV_CHANGEADDR:
/* Add the address to the IP table */
- if (netdev->master)
+ if (upper_dev)
nesvnic->local_ipaddr =
- ((struct in_device *)netdev->master->ip_ptr)->ifa_list->ifa_address;
+ ((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address;
else
nesvnic->local_ipaddr = ifa->ifa_address;
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 22ea67eea5dc..24b9f1a0107b 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -1340,7 +1340,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
}
if (netif_is_bond_slave(nesvnic->netdev))
- netdev = nesvnic->netdev->master;
+ netdev = netdev_master_upper_dev_get(nesvnic->netdev);
else
netdev = nesvnic->netdev;
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 9542e1644a5c..85cf4d1ac442 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -1317,11 +1317,13 @@ static void nes_netdev_get_drvinfo(struct net_device *netdev,
struct nes_vnic *nesvnic = netdev_priv(netdev);
struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
- strcpy(drvinfo->driver, DRV_NAME);
- strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev));
- sprintf(drvinfo->fw_version, "%u.%u", nesadapter->firmware_version>>16,
- nesadapter->firmware_version & 0x000000ff);
- strcpy(drvinfo->version, DRV_VERSION);
+ strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev),
+ sizeof(drvinfo->bus_info));
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+ "%u.%u", nesadapter->firmware_version >> 16,
+ nesadapter->firmware_version & 0x000000ff);
+ strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
drvinfo->testinfo_len = 0;
drvinfo->eedump_len = 0;
drvinfo->regdump_len = 0;
@@ -1703,7 +1705,6 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
netdev->dev_addr[3] = (u8)(u64temp>>16);
netdev->dev_addr[4] = (u8)(u64temp>>8);
netdev->dev_addr[5] = (u8)u64temp;
- memcpy(netdev->perm_addr, netdev->dev_addr, 6);
netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX;
if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV))
diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c
index 4850d03870c2..35275099cafd 100644
--- a/drivers/infiniband/hw/qib/qib_qp.c
+++ b/drivers/infiniband/hw/qib/qib_qp.c
@@ -263,20 +263,15 @@ static void remove_qp(struct qib_ibdev *dev, struct qib_qp *qp)
struct qib_qp __rcu **qpp;
qpp = &dev->qp_table[n];
- q = rcu_dereference_protected(*qpp,
- lockdep_is_held(&dev->qpt_lock));
- for (; q; qpp = &q->next) {
+ for (; (q = rcu_dereference_protected(*qpp,
+ lockdep_is_held(&dev->qpt_lock))) != NULL;
+ qpp = &q->next)
if (q == qp) {
atomic_dec(&qp->refcount);
*qpp = qp->next;
rcu_assign_pointer(qp->next, NULL);
- q = rcu_dereference_protected(*qpp,
- lockdep_is_held(&dev->qpt_lock));
break;
}
- q = rcu_dereference_protected(*qpp,
- lockdep_is_held(&dev->qpt_lock));
- }
}
spin_unlock_irqrestore(&dev->qpt_lock, flags);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 03103d2bd641..67b0c1d23678 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -741,6 +741,9 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
tx_req->mapping = addr;
+ skb_orphan(skb);
+ skb_dst_drop(skb);
+
rc = post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
addr, skb->len);
if (unlikely(rc)) {
@@ -752,9 +755,6 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
dev->trans_start = jiffies;
++tx->tx_head;
- skb_orphan(skb);
- skb_dst_drop(skb);
-
if (++priv->tx_outstanding == ipoib_sendq_size) {
ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n",
tx->qp->qp_num);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 29bc7b5724ac..ca131335417b 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -39,7 +39,7 @@
static void ipoib_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
- strncpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver) - 1);
+ strlcpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver));
}
static int ipoib_get_coalesce(struct net_device *dev,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index a1bca70e20aa..2cfa76f5d99e 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -600,6 +600,9 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
netif_stop_queue(dev);
}
+ skb_orphan(skb);
+ skb_dst_drop(skb);
+
rc = post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
address->ah, qpn, tx_req, phead, hlen);
if (unlikely(rc)) {
@@ -615,9 +618,6 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
address->last_send = priv->tx_head;
++priv->tx_head;
-
- skb_orphan(skb);
- skb_dst_drop(skb);
}
if (unlikely(priv->tx_outstanding > MAX_SEND_CQE))
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 55f7e57d4e42..38b523a1ece0 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -3,7 +3,7 @@
#
menu "Input device support"
- depends on !S390 && !UML
+ depends on !UML
config INPUT
tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index 47a6009dbf43..71db1930573f 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -18,6 +18,7 @@ static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
{
if (dev->absinfo && test_bit(src, dev->absbit)) {
dev->absinfo[dst] = dev->absinfo[src];
+ dev->absinfo[dst].fuzz = 0;
dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
}
}
diff --git a/drivers/input/input.c b/drivers/input/input.c
index ce01332f7b3a..c04469928925 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1785,12 +1785,13 @@ static void devm_input_device_release(struct device *dev, void *res)
* its driver (or binding fails). Once managed input device is allocated,
* it is ready to be set up and registered in the same fashion as regular
* input device. There are no special devm_input_device_[un]register()
- * variants, regular ones work with both managed and unmanaged devices.
+ * variants, regular ones work with both managed and unmanaged devices,
+ * should you need them. In most cases however, managed input device need
+ * not be explicitly unregistered or freed.
*
* NOTE: the owner device is set up as parent of input device and users
* should not override it.
*/
-
struct input_dev *devm_input_allocate_device(struct device *dev)
{
struct input_dev *input;
@@ -2004,6 +2005,17 @@ static void devm_input_device_unregister(struct device *dev, void *res)
* Once device has been successfully registered it can be unregistered
* with input_unregister_device(); input_free_device() should not be
* called in this case.
+ *
+ * Note that this function is also used to register managed input devices
+ * (ones allocated with devm_input_allocate_device()). Such managed input
+ * devices need not be explicitly unregistered or freed, their tear down
+ * is controlled by the devres infrastructure. It is also worth noting
+ * that tear down of managed input devices is internally a 2-step process:
+ * registered managed input device is first unregistered, but stays in
+ * memory and can still handle input_event() calls (although events will
+ * not be delivered anywhere). The freeing of managed input device will
+ * happen later, when devres stack is unwound to the point where device
+ * allocation was made.
*/
int input_register_device(struct input_dev *dev)
{
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 358cd7ee905b..7cd74e29cbc8 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -162,7 +162,7 @@ static unsigned int get_time_pit(void)
#define GET_TIME(x) do { x = get_cycles(); } while (0)
#define DELTA(x,y) ((y)-(x))
#define TIME_NAME "PCC"
-#elif defined(CONFIG_MN10300)
+#elif defined(CONFIG_MN10300) || defined(CONFIG_TILE)
#define GET_TIME(x) do { x = get_cycles(); } while (0)
#define DELTA(x, y) ((x) - (y))
#define TIME_NAME "TSC"
diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c
index f8f892b076e8..b76ac580703c 100644
--- a/drivers/input/joystick/walkera0701.c
+++ b/drivers/input/joystick/walkera0701.c
@@ -12,7 +12,7 @@
* the Free Software Foundation.
*/
-/* #define WK0701_DEBUG */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define RESERVE 20000
#define SYNC_PULSE 1306000
@@ -67,6 +67,7 @@ static inline void walkera0701_parse_frame(struct walkera_dev *w)
{
int i;
int val1, val2, val3, val4, val5, val6, val7, val8;
+ int magic, magic_bit;
int crc1, crc2;
for (crc1 = crc2 = i = 0; i < 10; i++) {
@@ -102,17 +103,12 @@ static inline void walkera0701_parse_frame(struct walkera_dev *w)
val8 = (w->buf[18] & 1) << 8 | (w->buf[19] << 4) | w->buf[20];
val8 *= (w->buf[18] & 2) - 1; /*sign */
-#ifdef WK0701_DEBUG
- {
- int magic, magic_bit;
- magic = (w->buf[21] << 4) | w->buf[22];
- magic_bit = (w->buf[24] & 8) >> 3;
- printk(KERN_DEBUG
- "walkera0701: %4d %4d %4d %4d %4d %4d %4d %4d (magic %2x %d)\n",
- val1, val2, val3, val4, val5, val6, val7, val8, magic,
- magic_bit);
- }
-#endif
+ magic = (w->buf[21] << 4) | w->buf[22];
+ magic_bit = (w->buf[24] & 8) >> 3;
+ pr_debug("%4d %4d %4d %4d %4d %4d %4d %4d (magic %2x %d)\n",
+ val1, val2, val3, val4, val5, val6, val7, val8,
+ magic, magic_bit);
+
input_report_abs(w->input_dev, ABS_X, val2);
input_report_abs(w->input_dev, ABS_Y, val1);
input_report_abs(w->input_dev, ABS_Z, val6);
@@ -187,6 +183,9 @@ static int walkera0701_open(struct input_dev *dev)
{
struct walkera_dev *w = input_get_drvdata(dev);
+ if (parport_claim(w->pardevice))
+ return -EBUSY;
+
parport_enable_irq(w->parport);
return 0;
}
@@ -197,40 +196,51 @@ static void walkera0701_close(struct input_dev *dev)
parport_disable_irq(w->parport);
hrtimer_cancel(&w->timer);
+
+ parport_release(w->pardevice);
}
static int walkera0701_connect(struct walkera_dev *w, int parport)
{
- int err = -ENODEV;
+ int error;
w->parport = parport_find_number(parport);
- if (w->parport == NULL)
+ if (!w->parport) {
+ pr_err("parport %d does not exist\n", parport);
return -ENODEV;
+ }
if (w->parport->irq == -1) {
- printk(KERN_ERR "walkera0701: parport without interrupt\n");
- goto init_err;
+ pr_err("parport %d does not have interrupt assigned\n",
+ parport);
+ error = -EINVAL;
+ goto err_put_parport;
}
- err = -EBUSY;
w->pardevice = parport_register_device(w->parport, "walkera0701",
NULL, NULL, walkera0701_irq_handler,
PARPORT_DEV_EXCL, w);
- if (!w->pardevice)
- goto init_err;
-
- if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT))
- goto init_err1;
+ if (!w->pardevice) {
+ pr_err("failed to register parport device\n");
+ error = -EIO;
+ goto err_put_parport;
+ }
- if (parport_claim(w->pardevice))
- goto init_err1;
+ if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT)) {
+ pr_err("failed to negotiate parport mode\n");
+ error = -EIO;
+ goto err_unregister_device;
+ }
hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
w->timer.function = timer_handler;
w->input_dev = input_allocate_device();
- if (!w->input_dev)
- goto init_err2;
+ if (!w->input_dev) {
+ pr_err("failed to allocate input device\n");
+ error = -ENOMEM;
+ goto err_unregister_device;
+ }
input_set_drvdata(w->input_dev, w);
w->input_dev->name = "Walkera WK-0701 TX";
@@ -241,6 +251,7 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
w->input_dev->id.vendor = 0x0001;
w->input_dev->id.product = 0x0001;
w->input_dev->id.version = 0x0100;
+ w->input_dev->dev.parent = w->parport->dev;
w->input_dev->open = walkera0701_open;
w->input_dev->close = walkera0701_close;
@@ -254,27 +265,26 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
input_set_abs_params(w->input_dev, ABS_RUDDER, -512, 512, 0, 0);
input_set_abs_params(w->input_dev, ABS_MISC, -512, 512, 0, 0);
- err = input_register_device(w->input_dev);
- if (err)
- goto init_err3;
+ error = input_register_device(w->input_dev);
+ if (error) {
+ pr_err("failed to register input device\n");
+ goto err_free_input_dev;
+ }
return 0;
- init_err3:
+err_free_input_dev:
input_free_device(w->input_dev);
- init_err2:
- parport_release(w->pardevice);
- init_err1:
+err_unregister_device:
parport_unregister_device(w->pardevice);
- init_err:
+err_put_parport:
parport_put_port(w->parport);
- return err;
+ return error;
}
static void walkera0701_disconnect(struct walkera_dev *w)
{
input_unregister_device(w->input_dev);
- parport_release(w->pardevice);
parport_unregister_device(w->pardevice);
parport_put_port(w->parport);
}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 5a240c60342d..ac0500667000 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -224,7 +224,7 @@ config KEYBOARD_TCA6416
config KEYBOARD_TCA8418
tristate "TCA8418 Keypad Support"
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
select INPUT_MATRIXKMAP
help
This driver implements basic keypad functionality
@@ -303,7 +303,7 @@ config KEYBOARD_HP7XX
config KEYBOARD_LM8323
tristate "LM8323 keypad chip"
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
depends on LEDS_CLASS
help
If you say yes here you get support for the National Semiconductor
@@ -420,7 +420,7 @@ config KEYBOARD_NOMADIK
config KEYBOARD_TEGRA
tristate "NVIDIA Tegra internal matrix keyboard controller support"
- depends on ARCH_TEGRA
+ depends on ARCH_TEGRA && OF
select INPUT_MATRIXKMAP
help
Say Y here if you want to use a matrix keyboard connected directly
@@ -479,6 +479,16 @@ config KEYBOARD_SAMSUNG
To compile this driver as a module, choose M here: the
module will be called samsung-keypad.
+config KEYBOARD_GOLDFISH_EVENTS
+ depends on GOLDFISH
+ tristate "Generic Input Event device for Goldfish"
+ help
+ Say Y here to get an input event device for the Goldfish virtual
+ device emulator.
+
+ To compile this driver as a module, choose M here: the
+ module will be called goldfish-events.
+
config KEYBOARD_STOWAWAY
tristate "Stowaway keyboard"
select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 44e76002f54b..49b16453d00e 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
+obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o
obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index add5ffd9fe26..2626773ff29b 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -676,6 +676,39 @@ static inline void atkbd_disable(struct atkbd *atkbd)
serio_continue_rx(atkbd->ps2dev.serio);
}
+static int atkbd_activate(struct atkbd *atkbd)
+{
+ struct ps2dev *ps2dev = &atkbd->ps2dev;
+
+/*
+ * Enable the keyboard to receive keystrokes.
+ */
+
+ if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
+ dev_err(&ps2dev->serio->dev,
+ "Failed to enable keyboard on %s\n",
+ ps2dev->serio->phys);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * atkbd_deactivate() resets and disables the keyboard from sending
+ * keystrokes.
+ */
+
+static void atkbd_deactivate(struct atkbd *atkbd)
+{
+ struct ps2dev *ps2dev = &atkbd->ps2dev;
+
+ if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS))
+ dev_err(&ps2dev->serio->dev,
+ "Failed to deactivate keyboard on %s\n",
+ ps2dev->serio->phys);
+}
+
/*
* atkbd_probe() probes for an AT keyboard on a serio port.
*/
@@ -726,11 +759,17 @@ static int atkbd_probe(struct atkbd *atkbd)
if (atkbd->id == 0xaca1 && atkbd->translated) {
dev_err(&ps2dev->serio->dev,
- "NCD terminal keyboards are only supported on non-translating controlelrs. "
+ "NCD terminal keyboards are only supported on non-translating controllers. "
"Use i8042.direct=1 to disable translation.\n");
return -1;
}
+/*
+ * Make sure nothing is coming from the keyboard and disturbs our
+ * internal state.
+ */
+ atkbd_deactivate(atkbd);
+
return 0;
}
@@ -825,24 +864,6 @@ static int atkbd_reset_state(struct atkbd *atkbd)
return 0;
}
-static int atkbd_activate(struct atkbd *atkbd)
-{
- struct ps2dev *ps2dev = &atkbd->ps2dev;
-
-/*
- * Enable the keyboard to receive keystrokes.
- */
-
- if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
- dev_err(&ps2dev->serio->dev,
- "Failed to enable keyboard on %s\n",
- ps2dev->serio->phys);
- return -1;
- }
-
- return 0;
-}
-
/*
* atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
* reboot.
@@ -1150,7 +1171,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
atkbd_reset_state(atkbd);
- atkbd_activate(atkbd);
} else {
atkbd->set = 2;
@@ -1165,6 +1185,8 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
goto fail3;
atkbd_enable(atkbd);
+ if (serio->write)
+ atkbd_activate(atkbd);
err = input_register_device(atkbd->dev);
if (err)
@@ -1208,8 +1230,6 @@ static int atkbd_reconnect(struct serio *serio)
if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
goto out;
- atkbd_activate(atkbd);
-
/*
* Restore LED state and repeat rate. While input core
* will do this for us at resume time reconnect may happen
@@ -1223,7 +1243,17 @@ static int atkbd_reconnect(struct serio *serio)
}
+ /*
+ * Reset our state machine in case reconnect happened in the middle
+ * of multi-byte scancode.
+ */
+ atkbd->xl_bit = 0;
+ atkbd->emul = 0;
+
atkbd_enable(atkbd);
+ if (atkbd->write)
+ atkbd_activate(atkbd);
+
retval = 0;
out:
diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c
new file mode 100644
index 000000000000..9f60a2ec88db
--- /dev/null
+++ b/drivers/input/keyboard/goldfish_events.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2012 Intel, Inc.
+ *
+ * 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+enum {
+ REG_READ = 0x00,
+ REG_SET_PAGE = 0x00,
+ REG_LEN = 0x04,
+ REG_DATA = 0x08,
+
+ PAGE_NAME = 0x00000,
+ PAGE_EVBITS = 0x10000,
+ PAGE_ABSDATA = 0x20000 | EV_ABS,
+};
+
+struct event_dev {
+ struct input_dev *input;
+ int irq;
+ void __iomem *addr;
+ char name[0];
+};
+
+static irqreturn_t events_interrupt(int irq, void *dev_id)
+{
+ struct event_dev *edev = dev_id;
+ unsigned type, code, value;
+
+ type = __raw_readl(edev->addr + REG_READ);
+ code = __raw_readl(edev->addr + REG_READ);
+ value = __raw_readl(edev->addr + REG_READ);
+
+ input_event(edev->input, type, code, value);
+ input_sync(edev->input);
+ return IRQ_HANDLED;
+}
+
+static void events_import_bits(struct event_dev *edev,
+ unsigned long bits[], unsigned type, size_t count)
+{
+ void __iomem *addr = edev->addr;
+ int i, j;
+ size_t size;
+ uint8_t val;
+
+ __raw_writel(PAGE_EVBITS | type, addr + REG_SET_PAGE);
+
+ size = __raw_readl(addr + REG_LEN) * 8;
+ if (size < count)
+ count = size;
+
+ addr += REG_DATA;
+ for (i = 0; i < count; i += 8) {
+ val = __raw_readb(addr++);
+ for (j = 0; j < 8; j++)
+ if (val & 1 << j)
+ set_bit(i + j, bits);
+ }
+}
+
+static void events_import_abs_params(struct event_dev *edev)
+{
+ struct input_dev *input_dev = edev->input;
+ void __iomem *addr = edev->addr;
+ u32 val[4];
+ int count;
+ int i, j;
+
+ __raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE);
+
+ count = __raw_readl(addr + REG_LEN) / sizeof(val);
+ if (count > ABS_MAX)
+ count = ABS_MAX;
+
+ for (i = 0; i < count; i++) {
+ if (!test_bit(i, input_dev->absbit))
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(val); j++) {
+ int offset = (i * ARRAY_SIZE(val) + j) * sizeof(u32);
+ val[j] = __raw_readl(edev->addr + REG_DATA + offset);
+ }
+
+ input_set_abs_params(input_dev, i,
+ val[0], val[1], val[2], val[3]);
+ }
+}
+
+static int events_probe(struct platform_device *pdev)
+{
+ struct input_dev *input_dev;
+ struct event_dev *edev;
+ struct resource *res;
+ unsigned keymapnamelen;
+ void __iomem *addr;
+ int irq;
+ int i;
+ int error;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -EINVAL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ addr = devm_ioremap(&pdev->dev, res->start, 4096);
+ if (!addr)
+ return -ENOMEM;
+
+ __raw_writel(PAGE_NAME, addr + REG_SET_PAGE);
+ keymapnamelen = __raw_readl(addr + REG_LEN);
+
+ edev = devm_kzalloc(&pdev->dev,
+ sizeof(struct event_dev) + keymapnamelen + 1,
+ GFP_KERNEL);
+ if (!edev)
+ return -ENOMEM;
+
+ input_dev = devm_input_allocate_device(&pdev->dev);
+ if (!input_dev)
+ return -ENOMEM;
+
+ edev->input = input_dev;
+ edev->addr = addr;
+ edev->irq = irq;
+
+ for (i = 0; i < keymapnamelen; i++)
+ edev->name[i] = __raw_readb(edev->addr + REG_DATA + i);
+
+ pr_debug("events_probe() keymap=%s\n", edev->name);
+
+ input_dev->name = edev->name;
+ input_dev->id.bustype = BUS_HOST;
+
+ events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX);
+ events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX);
+ events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX);
+ events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX);
+ events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX);
+ events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX);
+ events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX);
+ events_import_bits(edev, input_dev->ffbit, EV_FF, FF_MAX);
+ events_import_bits(edev, input_dev->swbit, EV_SW, SW_MAX);
+
+ events_import_abs_params(edev);
+
+ error = devm_request_irq(&pdev->dev, edev->irq, events_interrupt, 0,
+ "goldfish-events-keypad", edev);
+ if (error)
+ return error;
+
+ error = input_register_device(input_dev);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static struct platform_driver events_driver = {
+ .probe = events_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "goldfish_events",
+ },
+};
+
+module_platform_driver(events_driver);
+
+MODULE_AUTHOR("Brian Swetland");
+MODULE_DESCRIPTION("Goldfish Event Device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index 6d150e3e1f55..98f9113251d2 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -20,6 +20,7 @@
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/timer.h>
@@ -414,15 +415,23 @@ open_err:
return -EIO;
}
+#ifdef CONFIG_OF
+static struct of_device_id imx_keypad_of_match[] = {
+ { .compatible = "fsl,imx21-kpp", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_keypad_of_match);
+#endif
+
static int imx_keypad_probe(struct platform_device *pdev)
{
const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data;
struct imx_keypad *keypad;
struct input_dev *input_dev;
struct resource *res;
- int irq, error, i;
+ int irq, error, i, row, col;
- if (keymap_data == NULL) {
+ if (!keymap_data && !pdev->dev.of_node) {
dev_err(&pdev->dev, "no keymap defined\n");
return -EINVAL;
}
@@ -480,22 +489,6 @@ static int imx_keypad_probe(struct platform_device *pdev)
goto failed_unmap;
}
- /* Search for rows and cols enabled */
- for (i = 0; i < keymap_data->keymap_size; i++) {
- keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]);
- keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]);
- }
-
- if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
- keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
- dev_err(&pdev->dev,
- "invalid key data (too many rows or colums)\n");
- error = -EINVAL;
- goto failed_clock_put;
- }
- dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
- dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
-
/* Init the Input device */
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
@@ -512,6 +505,19 @@ static int imx_keypad_probe(struct platform_device *pdev)
goto failed_clock_put;
}
+ /* Search for rows and cols enabled */
+ for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) {
+ for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
+ i = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
+ if (keypad->keycodes[i] != KEY_RESERVED) {
+ keypad->rows_en_mask |= 1 << row;
+ keypad->cols_en_mask |= 1 << col;
+ }
+ }
+ }
+ dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
+ dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
+
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);
@@ -631,6 +637,7 @@ static struct platform_driver imx_keypad_driver = {
.name = "imx-keypad",
.owner = THIS_MODULE,
.pm = &imx_kbd_pm_ops,
+ .of_match_table = of_match_ptr(imx_keypad_of_match),
},
.probe = imx_keypad_probe,
.remove = imx_keypad_remove,
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index 93c812662134..0de23f41b2d3 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -398,7 +398,7 @@ static irqreturn_t lm8323_irq(int irq, void *_lm)
lm8323_configure(lm);
}
for (i = 0; i < LM8323_NUM_PWMS; i++) {
- if (ints & (1 << (INT_PWM1 + i))) {
+ if (ints & (INT_PWM1 << i)) {
dev_vdbg(&lm->client->dev,
"pwm%d engine completed\n", i);
pwm_done(&lm->pwm[i]);
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index f4ff0dda7597..71d77192ac1e 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -403,7 +403,7 @@ matrix_keypad_parse_dt(struct device *dev)
struct matrix_keypad_platform_data *pdata;
struct device_node *np = dev->of_node;
unsigned int *gpios;
- int i;
+ int i, nrow, ncol;
if (!np) {
dev_err(dev, "device lacks DT data\n");
@@ -416,9 +416,9 @@ matrix_keypad_parse_dt(struct device *dev)
return ERR_PTR(-ENOMEM);
}
- pdata->num_row_gpios = of_gpio_named_count(np, "row-gpios");
- pdata->num_col_gpios = of_gpio_named_count(np, "col-gpios");
- if (!pdata->num_row_gpios || !pdata->num_col_gpios) {
+ pdata->num_row_gpios = nrow = of_gpio_named_count(np, "row-gpios");
+ pdata->num_col_gpios = ncol = of_gpio_named_count(np, "col-gpios");
+ if (nrow <= 0 || ncol <= 0) {
dev_err(dev, "number of keypad rows/columns not specified\n");
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c
index 3dc2b0f27b0c..1c0ddad0a1cc 100644
--- a/drivers/input/keyboard/qt2160.c
+++ b/drivers/input/keyboard/qt2160.c
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/leds.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
@@ -39,6 +40,11 @@
#define QT2160_CMD_GPIOS 6
#define QT2160_CMD_SUBVER 7
#define QT2160_CMD_CALIBRATE 10
+#define QT2160_CMD_DRIVE_X 70
+#define QT2160_CMD_PWMEN_X 74
+#define QT2160_CMD_PWM_DUTY 76
+
+#define QT2160_NUM_LEDS_X 8
#define QT2160_CYCLE_INTERVAL (2*HZ)
@@ -49,6 +55,17 @@ static unsigned char qt2160_key2code[] = {
KEY_C, KEY_D, KEY_E, KEY_F,
};
+#ifdef CONFIG_LEDS_CLASS
+struct qt2160_led {
+ struct qt2160_data *qt2160;
+ struct led_classdev cdev;
+ struct work_struct work;
+ char name[32];
+ int id;
+ enum led_brightness new_brightness;
+};
+#endif
+
struct qt2160_data {
struct i2c_client *client;
struct input_dev *input;
@@ -56,8 +73,61 @@ struct qt2160_data {
spinlock_t lock; /* Protects canceling/rescheduling of dwork */
unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
u16 key_matrix;
+#ifdef CONFIG_LEDS_CLASS
+ struct qt2160_led leds[QT2160_NUM_LEDS_X];
+ struct mutex led_lock;
+#endif
};
+static int qt2160_read(struct i2c_client *client, u8 reg);
+static int qt2160_write(struct i2c_client *client, u8 reg, u8 data);
+
+#ifdef CONFIG_LEDS_CLASS
+
+static void qt2160_led_work(struct work_struct *work)
+{
+ struct qt2160_led *led = container_of(work, struct qt2160_led, work);
+ struct qt2160_data *qt2160 = led->qt2160;
+ struct i2c_client *client = qt2160->client;
+ int value = led->new_brightness;
+ u32 drive, pwmen;
+
+ mutex_lock(&qt2160->led_lock);
+
+ drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
+ pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
+ if (value != LED_OFF) {
+ drive |= (1 << led->id);
+ pwmen |= (1 << led->id);
+
+ } else {
+ drive &= ~(1 << led->id);
+ pwmen &= ~(1 << led->id);
+ }
+ qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
+ qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
+
+ /*
+ * Changing this register will change the brightness
+ * of every LED in the qt2160. It's a HW limitation.
+ */
+ if (value != LED_OFF)
+ qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
+
+ mutex_unlock(&qt2160->led_lock);
+}
+
+static void qt2160_led_set(struct led_classdev *cdev,
+ enum led_brightness value)
+{
+ struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);
+
+ led->new_brightness = value;
+ schedule_work(&led->work);
+}
+
+#endif /* CONFIG_LEDS_CLASS */
+
static int qt2160_read_block(struct i2c_client *client,
u8 inireg, u8 *buffer, unsigned int count)
{
@@ -216,6 +286,63 @@ static int qt2160_write(struct i2c_client *client, u8 reg, u8 data)
return ret;
}
+#ifdef CONFIG_LEDS_CLASS
+
+static int qt2160_register_leds(struct qt2160_data *qt2160)
+{
+ struct i2c_client *client = qt2160->client;
+ int ret;
+ int i;
+
+ mutex_init(&qt2160->led_lock);
+
+ for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
+ struct qt2160_led *led = &qt2160->leds[i];
+
+ snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
+ led->cdev.name = led->name;
+ led->cdev.brightness_set = qt2160_led_set;
+ led->cdev.brightness = LED_OFF;
+ led->id = i;
+ led->qt2160 = qt2160;
+
+ INIT_WORK(&led->work, qt2160_led_work);
+
+ ret = led_classdev_register(&client->dev, &led->cdev);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Tur off LEDs */
+ qt2160_write(client, QT2160_CMD_DRIVE_X, 0);
+ qt2160_write(client, QT2160_CMD_PWMEN_X, 0);
+ qt2160_write(client, QT2160_CMD_PWM_DUTY, 0);
+
+ return 0;
+}
+
+static void qt2160_unregister_leds(struct qt2160_data *qt2160)
+{
+ int i;
+
+ for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
+ led_classdev_unregister(&qt2160->leds[i].cdev);
+ cancel_work_sync(&qt2160->leds[i].work);
+ }
+}
+
+#else
+
+static inline int qt2160_register_leds(struct qt2160_data *qt2160)
+{
+ return 0;
+}
+
+static inline void qt2160_unregister_leds(struct qt2160_data *qt2160)
+{
+}
+
+#endif
static bool qt2160_identify(struct i2c_client *client)
{
@@ -249,7 +376,7 @@ static bool qt2160_identify(struct i2c_client *client)
}
static int qt2160_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct qt2160_data *qt2160;
struct input_dev *input;
@@ -314,11 +441,17 @@ static int qt2160_probe(struct i2c_client *client,
}
}
+ error = qt2160_register_leds(qt2160);
+ if (error) {
+ dev_err(&client->dev, "Failed to register leds\n");
+ goto err_free_irq;
+ }
+
error = input_register_device(qt2160->input);
if (error) {
dev_err(&client->dev,
"Failed to register input device\n");
- goto err_free_irq;
+ goto err_unregister_leds;
}
i2c_set_clientdata(client, qt2160);
@@ -326,6 +459,8 @@ static int qt2160_probe(struct i2c_client *client,
return 0;
+err_unregister_leds:
+ qt2160_unregister_leds(qt2160);
err_free_irq:
if (client->irq)
free_irq(client->irq, qt2160);
@@ -339,6 +474,8 @@ static int qt2160_remove(struct i2c_client *client)
{
struct qt2160_data *qt2160 = i2c_get_clientdata(client);
+ qt2160_unregister_leds(qt2160);
+
/* Release IRQ so no queue will be scheduled */
if (client->irq)
free_irq(client->irq, qt2160);
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 695d237417d6..cb1e8f614631 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -228,11 +228,9 @@ static int spear_kbd_probe(struct platform_device *pdev)
kbd->suspended_rate = pdata->suspended_rate;
}
- kbd->io_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!kbd->io_base) {
- dev_err(&pdev->dev, "request-ioremap failed for kbd_region\n");
- return -ENOMEM;
- }
+ kbd->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(kbd->io_base))
+ return PTR_ERR(kbd->io_base);
kbd->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(kbd->clk))
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index c76f96872d31..0e138ebcc768 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -29,8 +29,15 @@
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/slab.h>
-#include <linux/input/tegra_kbc.h>
-#include <mach/clk.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/clk/tegra.h>
+
+#define KBC_MAX_GPIO 24
+#define KBC_MAX_KPENT 8
+
+#define KBC_MAX_ROW 16
+#define KBC_MAX_COL 8
+#define KBC_MAX_KEY (KBC_MAX_ROW * KBC_MAX_COL)
#define KBC_MAX_DEBOUNCE_CNT 0x3ffu
@@ -67,10 +74,27 @@
#define KBC_ROW_SHIFT 3
+enum tegra_pin_type {
+ PIN_CFG_IGNORE,
+ PIN_CFG_COL,
+ PIN_CFG_ROW,
+};
+
+struct tegra_kbc_pin_cfg {
+ enum tegra_pin_type type;
+ unsigned char num;
+};
+
struct tegra_kbc {
+ struct device *dev;
+ unsigned int debounce_cnt;
+ unsigned int repeat_cnt;
+ struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
+ const struct matrix_keymap_data *keymap_data;
+ bool wakeup;
void __iomem *mmio;
struct input_dev *idev;
- unsigned int irq;
+ int irq;
spinlock_t lock;
unsigned int repoll_dly;
unsigned long cp_dly_jiffies;
@@ -78,7 +102,6 @@ struct tegra_kbc {
bool use_fn_map;
bool use_ghost_filter;
bool keypress_caused_wake;
- const struct tegra_kbc_platform_data *pdata;
unsigned short keycode[KBC_MAX_KEY * 2];
unsigned short current_keys[KBC_MAX_KPENT];
unsigned int num_pressed_keys;
@@ -87,147 +110,6 @@ struct tegra_kbc {
struct clk *clk;
};
-static const u32 tegra_kbc_default_keymap[] = {
- KEY(0, 2, KEY_W),
- KEY(0, 3, KEY_S),
- KEY(0, 4, KEY_A),
- KEY(0, 5, KEY_Z),
- KEY(0, 7, KEY_FN),
-
- KEY(1, 7, KEY_LEFTMETA),
-
- KEY(2, 6, KEY_RIGHTALT),
- KEY(2, 7, KEY_LEFTALT),
-
- KEY(3, 0, KEY_5),
- KEY(3, 1, KEY_4),
- KEY(3, 2, KEY_R),
- KEY(3, 3, KEY_E),
- KEY(3, 4, KEY_F),
- KEY(3, 5, KEY_D),
- KEY(3, 6, KEY_X),
-
- KEY(4, 0, KEY_7),
- KEY(4, 1, KEY_6),
- KEY(4, 2, KEY_T),
- KEY(4, 3, KEY_H),
- KEY(4, 4, KEY_G),
- KEY(4, 5, KEY_V),
- KEY(4, 6, KEY_C),
- KEY(4, 7, KEY_SPACE),
-
- KEY(5, 0, KEY_9),
- KEY(5, 1, KEY_8),
- KEY(5, 2, KEY_U),
- KEY(5, 3, KEY_Y),
- KEY(5, 4, KEY_J),
- KEY(5, 5, KEY_N),
- KEY(5, 6, KEY_B),
- KEY(5, 7, KEY_BACKSLASH),
-
- KEY(6, 0, KEY_MINUS),
- KEY(6, 1, KEY_0),
- KEY(6, 2, KEY_O),
- KEY(6, 3, KEY_I),
- KEY(6, 4, KEY_L),
- KEY(6, 5, KEY_K),
- KEY(6, 6, KEY_COMMA),
- KEY(6, 7, KEY_M),
-
- KEY(7, 1, KEY_EQUAL),
- KEY(7, 2, KEY_RIGHTBRACE),
- KEY(7, 3, KEY_ENTER),
- KEY(7, 7, KEY_MENU),
-
- KEY(8, 4, KEY_RIGHTSHIFT),
- KEY(8, 5, KEY_LEFTSHIFT),
-
- KEY(9, 5, KEY_RIGHTCTRL),
- KEY(9, 7, KEY_LEFTCTRL),
-
- KEY(11, 0, KEY_LEFTBRACE),
- KEY(11, 1, KEY_P),
- KEY(11, 2, KEY_APOSTROPHE),
- KEY(11, 3, KEY_SEMICOLON),
- KEY(11, 4, KEY_SLASH),
- KEY(11, 5, KEY_DOT),
-
- KEY(12, 0, KEY_F10),
- KEY(12, 1, KEY_F9),
- KEY(12, 2, KEY_BACKSPACE),
- KEY(12, 3, KEY_3),
- KEY(12, 4, KEY_2),
- KEY(12, 5, KEY_UP),
- KEY(12, 6, KEY_PRINT),
- KEY(12, 7, KEY_PAUSE),
-
- KEY(13, 0, KEY_INSERT),
- KEY(13, 1, KEY_DELETE),
- KEY(13, 3, KEY_PAGEUP),
- KEY(13, 4, KEY_PAGEDOWN),
- KEY(13, 5, KEY_RIGHT),
- KEY(13, 6, KEY_DOWN),
- KEY(13, 7, KEY_LEFT),
-
- KEY(14, 0, KEY_F11),
- KEY(14, 1, KEY_F12),
- KEY(14, 2, KEY_F8),
- KEY(14, 3, KEY_Q),
- KEY(14, 4, KEY_F4),
- KEY(14, 5, KEY_F3),
- KEY(14, 6, KEY_1),
- KEY(14, 7, KEY_F7),
-
- KEY(15, 0, KEY_ESC),
- KEY(15, 1, KEY_GRAVE),
- KEY(15, 2, KEY_F5),
- KEY(15, 3, KEY_TAB),
- KEY(15, 4, KEY_F1),
- KEY(15, 5, KEY_F2),
- KEY(15, 6, KEY_CAPSLOCK),
- KEY(15, 7, KEY_F6),
-
- /* Software Handled Function Keys */
- KEY(20, 0, KEY_KP7),
-
- KEY(21, 0, KEY_KP9),
- KEY(21, 1, KEY_KP8),
- KEY(21, 2, KEY_KP4),
- KEY(21, 4, KEY_KP1),
-
- KEY(22, 1, KEY_KPSLASH),
- KEY(22, 2, KEY_KP6),
- KEY(22, 3, KEY_KP5),
- KEY(22, 4, KEY_KP3),
- KEY(22, 5, KEY_KP2),
- KEY(22, 7, KEY_KP0),
-
- KEY(27, 1, KEY_KPASTERISK),
- KEY(27, 3, KEY_KPMINUS),
- KEY(27, 4, KEY_KPPLUS),
- KEY(27, 5, KEY_KPDOT),
-
- KEY(28, 5, KEY_VOLUMEUP),
-
- KEY(29, 3, KEY_HOME),
- KEY(29, 4, KEY_END),
- KEY(29, 5, KEY_BRIGHTNESSDOWN),
- KEY(29, 6, KEY_VOLUMEDOWN),
- KEY(29, 7, KEY_BRIGHTNESSUP),
-
- KEY(30, 0, KEY_NUMLOCK),
- KEY(30, 1, KEY_SCROLLLOCK),
- KEY(30, 2, KEY_MUTE),
-
- KEY(31, 4, KEY_HELP),
-};
-
-static const
-struct matrix_keymap_data tegra_kbc_default_keymap_data = {
- .keymap = tegra_kbc_default_keymap,
- .keymap_size = ARRAY_SIZE(tegra_kbc_default_keymap),
-};
-
static void tegra_kbc_report_released_keys(struct input_dev *input,
unsigned short old_keycodes[],
unsigned int old_num_keys,
@@ -357,18 +239,6 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
writel(val, kbc->mmio + KBC_CONTROL_0);
}
-static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable)
-{
- u32 val;
-
- val = readl(kbc->mmio + KBC_CONTROL_0);
- if (enable)
- val |= KBC_CONTROL_KEYPRESS_INT_EN;
- else
- val &= ~KBC_CONTROL_KEYPRESS_INT_EN;
- writel(val, kbc->mmio + KBC_CONTROL_0);
-}
-
static void tegra_kbc_keypress_timer(unsigned long data)
{
struct tegra_kbc *kbc = (struct tegra_kbc *)data;
@@ -439,12 +309,11 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args)
static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
{
- const struct tegra_kbc_platform_data *pdata = kbc->pdata;
int i;
unsigned int rst_val;
/* Either mask all keys or none. */
- rst_val = (filter && !pdata->wakeup) ? ~0 : 0;
+ rst_val = (filter && !kbc->wakeup) ? ~0 : 0;
for (i = 0; i < KBC_MAX_ROW; i++)
writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
@@ -452,7 +321,6 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
{
- const struct tegra_kbc_platform_data *pdata = kbc->pdata;
int i;
for (i = 0; i < KBC_MAX_GPIO; i++) {
@@ -468,13 +336,13 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
row_cfg &= ~r_mask;
col_cfg &= ~c_mask;
- switch (pdata->pin_cfg[i].type) {
+ switch (kbc->pin_cfg[i].type) {
case PIN_CFG_ROW:
- row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft;
+ row_cfg |= ((kbc->pin_cfg[i].num << 1) | 1) << r_shft;
break;
case PIN_CFG_COL:
- col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft;
+ col_cfg |= ((kbc->pin_cfg[i].num << 1) | 1) << c_shft;
break;
case PIN_CFG_IGNORE:
@@ -488,7 +356,6 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
static int tegra_kbc_start(struct tegra_kbc *kbc)
{
- const struct tegra_kbc_platform_data *pdata = kbc->pdata;
unsigned int debounce_cnt;
u32 val = 0;
@@ -503,10 +370,10 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
tegra_kbc_config_pins(kbc);
tegra_kbc_setup_wakekeys(kbc, false);
- writel(pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
+ writel(kbc->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
/* Keyboard debounce count is maximum of 12 bits. */
- debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
+ debounce_cnt = min(kbc->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
val = KBC_DEBOUNCE_CNT_SHIFT(debounce_cnt);
val |= KBC_FIFO_TH_CNT_SHIFT(1); /* set fifo interrupt threshold to 1 */
val |= KBC_CONTROL_FIFO_CNT_INT_EN; /* interrupt on FIFO threshold */
@@ -573,21 +440,20 @@ static void tegra_kbc_close(struct input_dev *dev)
return tegra_kbc_stop(kbc);
}
-static bool
-tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
- struct device *dev, unsigned int *num_rows)
+static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc *kbc,
+ unsigned int *num_rows)
{
int i;
*num_rows = 0;
for (i = 0; i < KBC_MAX_GPIO; i++) {
- const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i];
+ const struct tegra_kbc_pin_cfg *pin_cfg = &kbc->pin_cfg[i];
switch (pin_cfg->type) {
case PIN_CFG_ROW:
if (pin_cfg->num >= KBC_MAX_ROW) {
- dev_err(dev,
+ dev_err(kbc->dev,
"pin_cfg[%d]: invalid row number %d\n",
i, pin_cfg->num);
return false;
@@ -597,7 +463,7 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
case PIN_CFG_COL:
if (pin_cfg->num >= KBC_MAX_COL) {
- dev_err(dev,
+ dev_err(kbc->dev,
"pin_cfg[%d]: invalid column number %d\n",
i, pin_cfg->num);
return false;
@@ -608,7 +474,7 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
break;
default:
- dev_err(dev,
+ dev_err(kbc->dev,
"pin_cfg[%d]: invalid entry type %d\n",
pin_cfg->type, pin_cfg->num);
return false;
@@ -618,154 +484,140 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
return true;
}
-#ifdef CONFIG_OF
-static struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
- struct platform_device *pdev)
+static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
{
- struct tegra_kbc_platform_data *pdata;
- struct device_node *np = pdev->dev.of_node;
+ struct device_node *np = kbc->dev->of_node;
u32 prop;
int i;
-
- if (!np)
- return NULL;
-
- pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return NULL;
+ u32 num_rows = 0;
+ u32 num_cols = 0;
+ u32 cols_cfg[KBC_MAX_GPIO];
+ u32 rows_cfg[KBC_MAX_GPIO];
+ int proplen;
+ int ret;
if (!of_property_read_u32(np, "nvidia,debounce-delay-ms", &prop))
- pdata->debounce_cnt = prop;
+ kbc->debounce_cnt = prop;
if (!of_property_read_u32(np, "nvidia,repeat-delay-ms", &prop))
- pdata->repeat_cnt = prop;
+ kbc->repeat_cnt = prop;
if (of_find_property(np, "nvidia,needs-ghost-filter", NULL))
- pdata->use_ghost_filter = true;
+ kbc->use_ghost_filter = true;
if (of_find_property(np, "nvidia,wakeup-source", NULL))
- pdata->wakeup = true;
+ kbc->wakeup = true;
- /*
- * All currently known keymaps with device tree support use the same
- * pin_cfg, so set it up here.
- */
- for (i = 0; i < KBC_MAX_ROW; i++) {
- pdata->pin_cfg[i].num = i;
- pdata->pin_cfg[i].type = PIN_CFG_ROW;
+ if (!of_get_property(np, "nvidia,kbc-row-pins", &proplen)) {
+ dev_err(kbc->dev, "property nvidia,kbc-row-pins not found\n");
+ return -ENOENT;
}
+ num_rows = proplen / sizeof(u32);
- for (i = 0; i < KBC_MAX_COL; i++) {
- pdata->pin_cfg[KBC_MAX_ROW + i].num = i;
- pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
+ if (!of_get_property(np, "nvidia,kbc-col-pins", &proplen)) {
+ dev_err(kbc->dev, "property nvidia,kbc-col-pins not found\n");
+ return -ENOENT;
}
+ num_cols = proplen / sizeof(u32);
- return pdata;
-}
-#else
-static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
- struct platform_device *pdev)
-{
- return NULL;
-}
-#endif
+ if (!of_get_property(np, "linux,keymap", &proplen)) {
+ dev_err(kbc->dev, "property linux,keymap not found\n");
+ return -ENOENT;
+ }
-static int tegra_kbd_setup_keymap(struct tegra_kbc *kbc)
-{
- const struct tegra_kbc_platform_data *pdata = kbc->pdata;
- const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
- unsigned int keymap_rows = KBC_MAX_KEY;
- int retval;
+ if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) {
+ dev_err(kbc->dev,
+ "keypad rows/columns not porperly specified\n");
+ return -EINVAL;
+ }
- if (keymap_data && pdata->use_fn_map)
- keymap_rows *= 2;
+ /* Set all pins as non-configured */
+ for (i = 0; i < KBC_MAX_GPIO; i++)
+ kbc->pin_cfg[i].type = PIN_CFG_IGNORE;
- retval = matrix_keypad_build_keymap(keymap_data, NULL,
- keymap_rows, KBC_MAX_COL,
- kbc->keycode, kbc->idev);
- if (retval == -ENOSYS || retval == -ENOENT) {
- /*
- * If there is no OF support in kernel or keymap
- * property is missing, use default keymap.
- */
- retval = matrix_keypad_build_keymap(
- &tegra_kbc_default_keymap_data, NULL,
- keymap_rows, KBC_MAX_COL,
- kbc->keycode, kbc->idev);
+ ret = of_property_read_u32_array(np, "nvidia,kbc-row-pins",
+ rows_cfg, num_rows);
+ if (ret < 0) {
+ dev_err(kbc->dev, "Rows configurations are not proper\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_array(np, "nvidia,kbc-col-pins",
+ cols_cfg, num_cols);
+ if (ret < 0) {
+ dev_err(kbc->dev, "Cols configurations are not proper\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_rows; i++) {
+ kbc->pin_cfg[rows_cfg[i]].type = PIN_CFG_ROW;
+ kbc->pin_cfg[rows_cfg[i]].num = i;
}
- return retval;
+ for (i = 0; i < num_cols; i++) {
+ kbc->pin_cfg[cols_cfg[i]].type = PIN_CFG_COL;
+ kbc->pin_cfg[cols_cfg[i]].num = i;
+ }
+
+ return 0;
}
static int tegra_kbc_probe(struct platform_device *pdev)
{
- const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
struct tegra_kbc *kbc;
- struct input_dev *input_dev;
struct resource *res;
- int irq;
int err;
int num_rows = 0;
unsigned int debounce_cnt;
unsigned int scan_time_rows;
+ unsigned int keymap_rows = KBC_MAX_KEY;
- if (!pdata)
- pdata = tegra_kbc_dt_parse_pdata(pdev);
+ kbc = devm_kzalloc(&pdev->dev, sizeof(*kbc), GFP_KERNEL);
+ if (!kbc) {
+ dev_err(&pdev->dev, "failed to alloc memory for kbc\n");
+ return -ENOMEM;
+ }
- if (!pdata)
- return -EINVAL;
+ kbc->dev = &pdev->dev;
+ spin_lock_init(&kbc->lock);
- if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) {
- err = -EINVAL;
- goto err_free_pdata;
- }
+ err = tegra_kbc_parse_dt(kbc);
+ if (err)
+ return err;
+
+ if (!tegra_kbc_check_pin_cfg(kbc, &num_rows))
+ return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get I/O memory\n");
- err = -ENXIO;
- goto err_free_pdata;
+ return -ENXIO;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
+ kbc->irq = platform_get_irq(pdev, 0);
+ if (kbc->irq < 0) {
dev_err(&pdev->dev, "failed to get keyboard IRQ\n");
- err = -ENXIO;
- goto err_free_pdata;
+ return -ENXIO;
}
- kbc = kzalloc(sizeof(*kbc), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!kbc || !input_dev) {
- err = -ENOMEM;
- goto err_free_mem;
+ kbc->idev = devm_input_allocate_device(&pdev->dev);
+ if (!kbc->idev) {
+ dev_err(&pdev->dev, "failed to allocate input device\n");
+ return -ENOMEM;
}
- kbc->pdata = pdata;
- kbc->idev = input_dev;
- kbc->irq = irq;
- spin_lock_init(&kbc->lock);
setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
- res = request_mem_region(res->start, resource_size(res), pdev->name);
- if (!res) {
- dev_err(&pdev->dev, "failed to request I/O memory\n");
- err = -EBUSY;
- goto err_free_mem;
- }
-
- kbc->mmio = ioremap(res->start, resource_size(res));
+ kbc->mmio = devm_request_and_ioremap(&pdev->dev, res);
if (!kbc->mmio) {
- dev_err(&pdev->dev, "failed to remap I/O memory\n");
- err = -ENXIO;
- goto err_free_mem_region;
+ dev_err(&pdev->dev, "Cannot request memregion/iomap address\n");
+ return -EBUSY;
}
- kbc->clk = clk_get(&pdev->dev, NULL);
+ kbc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(kbc->clk)) {
dev_err(&pdev->dev, "failed to get keyboard clock\n");
- err = PTR_ERR(kbc->clk);
- goto err_iounmap;
+ return PTR_ERR(kbc->clk);
}
/*
@@ -774,37 +626,38 @@ static int tegra_kbc_probe(struct platform_device *pdev)
* the rows. There is an additional delay before the row scanning
* starts. The repoll delay is computed in milliseconds.
*/
- debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
+ debounce_cnt = min(kbc->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows;
- kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
+ kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + kbc->repeat_cnt;
kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS);
- kbc->wakeup_key = pdata->wakeup_key;
- kbc->use_fn_map = pdata->use_fn_map;
- kbc->use_ghost_filter = pdata->use_ghost_filter;
+ kbc->idev->name = pdev->name;
+ kbc->idev->id.bustype = BUS_HOST;
+ kbc->idev->dev.parent = &pdev->dev;
+ kbc->idev->open = tegra_kbc_open;
+ kbc->idev->close = tegra_kbc_close;
- input_dev->name = pdev->name;
- input_dev->id.bustype = BUS_HOST;
- input_dev->dev.parent = &pdev->dev;
- input_dev->open = tegra_kbc_open;
- input_dev->close = tegra_kbc_close;
+ if (kbc->keymap_data && kbc->use_fn_map)
+ keymap_rows *= 2;
- err = tegra_kbd_setup_keymap(kbc);
+ err = matrix_keypad_build_keymap(kbc->keymap_data, NULL,
+ keymap_rows, KBC_MAX_COL,
+ kbc->keycode, kbc->idev);
if (err) {
dev_err(&pdev->dev, "failed to setup keymap\n");
- goto err_put_clk;
+ return err;
}
- __set_bit(EV_REP, input_dev->evbit);
- input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+ __set_bit(EV_REP, kbc->idev->evbit);
+ input_set_capability(kbc->idev, EV_MSC, MSC_SCAN);
- input_set_drvdata(input_dev, kbc);
+ input_set_drvdata(kbc->idev, kbc);
- err = request_irq(kbc->irq, tegra_kbc_isr,
+ err = devm_request_irq(&pdev->dev, kbc->irq, tegra_kbc_isr,
IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH, pdev->name, kbc);
if (err) {
dev_err(&pdev->dev, "failed to request keyboard IRQ\n");
- goto err_put_clk;
+ return err;
}
disable_irq(kbc->irq);
@@ -812,60 +665,28 @@ static int tegra_kbc_probe(struct platform_device *pdev)
err = input_register_device(kbc->idev);
if (err) {
dev_err(&pdev->dev, "failed to register input device\n");
- goto err_free_irq;
+ return err;
}
platform_set_drvdata(pdev, kbc);
- device_init_wakeup(&pdev->dev, pdata->wakeup);
+ device_init_wakeup(&pdev->dev, kbc->wakeup);
return 0;
-
-err_free_irq:
- free_irq(kbc->irq, pdev);
-err_put_clk:
- clk_put(kbc->clk);
-err_iounmap:
- iounmap(kbc->mmio);
-err_free_mem_region:
- release_mem_region(res->start, resource_size(res));
-err_free_mem:
- input_free_device(input_dev);
- kfree(kbc);
-err_free_pdata:
- if (!pdev->dev.platform_data)
- kfree(pdata);
-
- return err;
}
-static int tegra_kbc_remove(struct platform_device *pdev)
+#ifdef CONFIG_PM_SLEEP
+static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable)
{
- struct tegra_kbc *kbc = platform_get_drvdata(pdev);
- struct resource *res;
-
- platform_set_drvdata(pdev, NULL);
-
- free_irq(kbc->irq, pdev);
- clk_put(kbc->clk);
-
- input_unregister_device(kbc->idev);
- iounmap(kbc->mmio);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- /*
- * If we do not have platform data attached to the device we
- * allocated it ourselves and thus need to free it.
- */
- if (!pdev->dev.platform_data)
- kfree(kbc->pdata);
-
- kfree(kbc);
+ u32 val;
- return 0;
+ val = readl(kbc->mmio + KBC_CONTROL_0);
+ if (enable)
+ val |= KBC_CONTROL_KEYPRESS_INT_EN;
+ else
+ val &= ~KBC_CONTROL_KEYPRESS_INT_EN;
+ writel(val, kbc->mmio + KBC_CONTROL_0);
}
-#ifdef CONFIG_PM_SLEEP
static int tegra_kbc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -954,7 +775,6 @@ MODULE_DEVICE_TABLE(of, tegra_kbc_of_match);
static struct platform_driver tegra_kbc_driver = {
.probe = tegra_kbc_probe,
- .remove = tegra_kbc_remove,
.driver = {
.name = "tegra-kbc",
.owner = THIS_MODULE,
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
index 1cf72fe513e6..0735de3a6468 100644
--- a/drivers/input/misc/adxl34x.c
+++ b/drivers/input/misc/adxl34x.c
@@ -232,7 +232,7 @@ static const struct adxl34x_platform_data adxl34x_default_init = {
.ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */
.power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
- .fifo_mode = FIFO_STREAM,
+ .fifo_mode = ADXL_FIFO_STREAM,
.watermark = 0,
};
@@ -732,7 +732,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
mutex_init(&ac->mutex);
input_dev->name = "ADXL34x accelerometer";
- revid = ac->bops->read(dev, DEVID);
+ revid = AC_READ(ac, DEVID);
switch (revid) {
case ID_ADXL345:
@@ -809,7 +809,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
ac->fifo_delay = false;
- ac->bops->write(dev, POWER_CTL, 0);
+ AC_WRITE(ac, POWER_CTL, 0);
err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
@@ -827,7 +827,6 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
if (err)
goto err_remove_attr;
- AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
AC_WRITE(ac, OFSX, pdata->x_axis_offset);
ac->hwcal.x = pdata->x_axis_offset;
AC_WRITE(ac, OFSY, pdata->y_axis_offset);
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index 26f13131639a..5d4402365a52 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -121,7 +121,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
return err;
}
-static int atlas_acpi_button_remove(struct acpi_device *device, int type)
+static int atlas_acpi_button_remove(struct acpi_device *device)
{
acpi_status status;
diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
index 08ffcabd7220..865c2f9d25b9 100644
--- a/drivers/input/misc/bma150.c
+++ b/drivers/input/misc/bma150.c
@@ -46,18 +46,6 @@
#define BMA150_POLL_MAX 200
#define BMA150_POLL_MIN 0
-#define BMA150_BW_25HZ 0
-#define BMA150_BW_50HZ 1
-#define BMA150_BW_100HZ 2
-#define BMA150_BW_190HZ 3
-#define BMA150_BW_375HZ 4
-#define BMA150_BW_750HZ 5
-#define BMA150_BW_1500HZ 6
-
-#define BMA150_RANGE_2G 0
-#define BMA150_RANGE_4G 1
-#define BMA150_RANGE_8G 2
-
#define BMA150_MODE_NORMAL 0
#define BMA150_MODE_SLEEP 2
#define BMA150_MODE_WAKE_UP 3
@@ -372,7 +360,7 @@ static int bma150_open(struct bma150_data *bma150)
int error;
error = pm_runtime_get_sync(&bma150->client->dev);
- if (error && error != -ENOSYS)
+ if (error < 0 && error != -ENOSYS)
return error;
/*
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c
index 369a39de4ff3..f9179b2585a9 100644
--- a/drivers/input/misc/max8925_onkey.c
+++ b/drivers/input/misc/max8925_onkey.c
@@ -100,9 +100,6 @@ static int max8925_onkey_probe(struct platform_device *pdev)
input->dev.parent = &pdev->dev;
input_set_capability(input, EV_KEY, KEY_POWER);
- irq[0] += chip->irq_base;
- irq[1] += chip->irq_base;
-
error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler,
IRQF_ONESHOT, "onkey-down", info);
if (error < 0) {
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index 78eb6b30580a..68a5f33152a8 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -43,7 +43,6 @@ struct vibra_info {
struct device *dev;
struct input_dev *input_dev;
- struct workqueue_struct *workqueue;
struct work_struct play_work;
bool enabled;
@@ -143,19 +142,7 @@ static int vibra_play(struct input_dev *input, void *data,
if (!info->speed)
info->speed = effect->u.rumble.weak_magnitude >> 9;
info->direction = effect->direction < EFFECT_DIR_180_DEG ? 0 : 1;
- queue_work(info->workqueue, &info->play_work);
- return 0;
-}
-
-static int twl4030_vibra_open(struct input_dev *input)
-{
- struct vibra_info *info = input_get_drvdata(input);
-
- info->workqueue = create_singlethread_workqueue("vibra");
- if (info->workqueue == NULL) {
- dev_err(&input->dev, "couldn't create workqueue\n");
- return -ENOMEM;
- }
+ schedule_work(&info->play_work);
return 0;
}
@@ -164,9 +151,6 @@ static void twl4030_vibra_close(struct input_dev *input)
struct vibra_info *info = input_get_drvdata(input);
cancel_work_sync(&info->play_work);
- INIT_WORK(&info->play_work, vibra_play_work); /* cleanup */
- destroy_workqueue(info->workqueue);
- info->workqueue = NULL;
if (info->enabled)
vibra_disable(info);
@@ -219,7 +203,7 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
return -EINVAL;
}
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -227,11 +211,10 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
info->coexist = twl4030_vibra_check_coexist(pdata, twl4030_core_node);
INIT_WORK(&info->play_work, vibra_play_work);
- info->input_dev = input_allocate_device();
+ info->input_dev = devm_input_allocate_device(&pdev->dev);
if (info->input_dev == NULL) {
dev_err(&pdev->dev, "couldn't allocate input device\n");
- ret = -ENOMEM;
- goto err_kzalloc;
+ return -ENOMEM;
}
input_set_drvdata(info->input_dev, info);
@@ -239,14 +222,13 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
info->input_dev->name = "twl4030:vibrator";
info->input_dev->id.version = 1;
info->input_dev->dev.parent = pdev->dev.parent;
- info->input_dev->open = twl4030_vibra_open;
info->input_dev->close = twl4030_vibra_close;
__set_bit(FF_RUMBLE, info->input_dev->ffbit);
ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
if (ret < 0) {
dev_dbg(&pdev->dev, "couldn't register vibrator to FF\n");
- goto err_ialloc;
+ return ret;
}
ret = input_register_device(info->input_dev);
@@ -262,28 +244,11 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
err_iff:
input_ff_destroy(info->input_dev);
-err_ialloc:
- input_free_device(info->input_dev);
-err_kzalloc:
- kfree(info);
return ret;
}
-static int twl4030_vibra_remove(struct platform_device *pdev)
-{
- struct vibra_info *info = platform_get_drvdata(pdev);
-
- /* this also free ff-memless and calls close if needed */
- input_unregister_device(info->input_dev);
- kfree(info);
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
static struct platform_driver twl4030_vibra_driver = {
.probe = twl4030_vibra_probe,
- .remove = twl4030_vibra_remove,
.driver = {
.name = "twl4030-vibra",
.owner = THIS_MODULE,
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index 71a28ee699f3..0c2dfc8e9691 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -275,7 +275,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
return -EINVAL;
}
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info) {
dev_err(&pdev->dev, "couldn't allocate memory\n");
return -ENOMEM;
@@ -309,53 +309,23 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
if ((!info->vibldrv_res && !info->viblmotor_res) ||
(!info->vibrdrv_res && !info->vibrmotor_res)) {
dev_err(info->dev, "invalid vibra driver/motor resistance\n");
- ret = -EINVAL;
- goto err_kzalloc;
+ return -EINVAL;
}
info->irq = platform_get_irq(pdev, 0);
if (info->irq < 0) {
dev_err(info->dev, "invalid irq\n");
- ret = -EINVAL;
- goto err_kzalloc;
+ return -EINVAL;
}
mutex_init(&info->mutex);
- info->input_dev = input_allocate_device();
- if (info->input_dev == NULL) {
- dev_err(info->dev, "couldn't allocate input device\n");
- ret = -ENOMEM;
- goto err_kzalloc;
- }
-
- input_set_drvdata(info->input_dev, info);
-
- info->input_dev->name = "twl6040:vibrator";
- info->input_dev->id.version = 1;
- info->input_dev->dev.parent = pdev->dev.parent;
- info->input_dev->close = twl6040_vibra_close;
- __set_bit(FF_RUMBLE, info->input_dev->ffbit);
-
- ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
- if (ret < 0) {
- dev_err(info->dev, "couldn't register vibrator to FF\n");
- goto err_ialloc;
- }
-
- ret = input_register_device(info->input_dev);
- if (ret < 0) {
- dev_err(info->dev, "couldn't register input device\n");
- goto err_iff;
- }
-
- platform_set_drvdata(pdev, info);
-
- ret = request_threaded_irq(info->irq, NULL, twl6040_vib_irq_handler, 0,
- "twl6040_irq_vib", info);
+ ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+ twl6040_vib_irq_handler, 0,
+ "twl6040_irq_vib", info);
if (ret) {
dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
- goto err_irq;
+ return ret;
}
info->supplies[0].supply = "vddvibl";
@@ -368,7 +338,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
ARRAY_SIZE(info->supplies), info->supplies);
if (ret) {
dev_err(info->dev, "couldn't get regulators %d\n", ret);
- goto err_regulator;
+ return ret;
}
if (vddvibl_uV) {
@@ -377,7 +347,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
if (ret) {
dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
ret);
- goto err_voltage;
+ goto err_regulator;
}
}
@@ -387,34 +357,49 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
if (ret) {
dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
ret);
- goto err_voltage;
+ goto err_regulator;
}
}
- info->workqueue = alloc_workqueue("twl6040-vibra", 0, 0);
- if (info->workqueue == NULL) {
- dev_err(info->dev, "couldn't create workqueue\n");
+ INIT_WORK(&info->play_work, vibra_play_work);
+
+ info->input_dev = input_allocate_device();
+ if (info->input_dev == NULL) {
+ dev_err(info->dev, "couldn't allocate input device\n");
ret = -ENOMEM;
- goto err_voltage;
+ goto err_regulator;
}
- INIT_WORK(&info->play_work, vibra_play_work);
+
+ input_set_drvdata(info->input_dev, info);
+
+ info->input_dev->name = "twl6040:vibrator";
+ info->input_dev->id.version = 1;
+ info->input_dev->dev.parent = pdev->dev.parent;
+ info->input_dev->close = twl6040_vibra_close;
+ __set_bit(FF_RUMBLE, info->input_dev->ffbit);
+
+ ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+ if (ret < 0) {
+ dev_err(info->dev, "couldn't register vibrator to FF\n");
+ goto err_ialloc;
+ }
+
+ ret = input_register_device(info->input_dev);
+ if (ret < 0) {
+ dev_err(info->dev, "couldn't register input device\n");
+ goto err_iff;
+ }
+
+ platform_set_drvdata(pdev, info);
return 0;
-err_voltage:
- regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
-err_regulator:
- free_irq(info->irq, info);
-err_irq:
- input_unregister_device(info->input_dev);
- info->input_dev = NULL;
err_iff:
- if (info->input_dev)
- input_ff_destroy(info->input_dev);
+ input_ff_destroy(info->input_dev);
err_ialloc:
input_free_device(info->input_dev);
-err_kzalloc:
- kfree(info);
+err_regulator:
+ regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
return ret;
}
@@ -423,10 +408,7 @@ static int twl6040_vibra_remove(struct platform_device *pdev)
struct vibra_info *info = platform_get_drvdata(pdev);
input_unregister_device(info->input_dev);
- free_irq(info->irq, info);
regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
- destroy_workqueue(info->workqueue);
- kfree(info);
return 0;
}
diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c
index 558767d8ebf4..caa2c4068f09 100644
--- a/drivers/input/misc/wm831x-on.c
+++ b/drivers/input/misc/wm831x-on.c
@@ -86,7 +86,7 @@ static int wm831x_on_probe(struct platform_device *pdev)
wm831x_on->wm831x = wm831x;
INIT_DELAYED_WORK(&wm831x_on->work, wm831x_poll_on);
- wm831x_on->dev = input_allocate_device();
+ wm831x_on->dev = devm_input_allocate_device(&pdev->dev);
if (!wm831x_on->dev) {
dev_err(&pdev->dev, "Can't allocate input dev\n");
ret = -ENOMEM;
@@ -119,7 +119,6 @@ static int wm831x_on_probe(struct platform_device *pdev)
err_irq:
free_irq(irq, wm831x_on);
err_input_dev:
- input_free_device(wm831x_on->dev);
err:
return ret;
}
@@ -131,7 +130,6 @@ static int wm831x_on_remove(struct platform_device *pdev)
free_irq(irq, wm831x_on);
cancel_delayed_work_sync(&wm831x_on->work);
- input_unregister_device(wm831x_on->dev);
return 0;
}
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index cd6268cf7cd5..802bd6a72d73 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -68,6 +68,16 @@ config MOUSE_PS2_SYNAPTICS
If unsure, say Y.
+config MOUSE_PS2_CYPRESS
+ bool "Cypress PS/2 mouse protocol extension" if EXPERT
+ default y
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have a Cypress PS/2 Trackpad connected to
+ your system.
+
+ If unsure, say Y.
+
config MOUSE_PS2_LIFEBOOK
bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT
default y
@@ -193,6 +203,18 @@ config MOUSE_BCM5974
To compile this driver as a module, choose M here: the
module will be called bcm5974.
+config MOUSE_CYAPA
+ tristate "Cypress APA I2C Trackpad support"
+ depends on I2C
+ help
+ This driver adds support for Cypress All Points Addressable (APA)
+ I2C Trackpads, including the ones used in 2012 Samsung Chromebooks.
+
+ Say Y here if you have a Cypress APA I2C Trackpad.
+
+ To compile this driver as a module, choose M here: the module will be
+ called cyapa.
+
config MOUSE_INPORT
tristate "InPort/MS/ATIXL busmouse"
depends on ISA
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 46ba7556fd4f..c25efdb3f288 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o
obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o
obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o
obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o
+obj-$(CONFIG_MOUSE_CYAPA) += cyapa.o
obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o
obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
@@ -32,3 +33,4 @@ psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o
psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
+psmouse-$(CONFIG_MOUSE_PS2_CYPRESS) += cypress_ps2.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index e229fa3cad96..7b99fc7c9438 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -27,14 +27,11 @@
/*
* Definitions for ALPS version 3 and 4 command mode protocol
*/
-#define ALPS_V3_X_MAX 2000
-#define ALPS_V3_Y_MAX 1400
-
-#define ALPS_BITMAP_X_BITS 15
-#define ALPS_BITMAP_Y_BITS 11
-
#define ALPS_CMD_NIBBLE_10 0x01f2
+#define ALPS_REG_BASE_RUSHMORE 0xc2c0
+#define ALPS_REG_BASE_PINNACLE 0x0000
+
static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
{ PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
{ PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
@@ -109,11 +106,14 @@ static const struct alps_model_info alps_model_data[] = {
{ { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
{ { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
- { { 0x73, 0x02, 0x64 }, 0x9b, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
- { { 0x73, 0x02, 0x64 }, 0x9d, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
{ { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 },
};
+static void alps_set_abs_params_st(struct alps_data *priv,
+ struct input_dev *dev1);
+static void alps_set_abs_params_mt(struct alps_data *priv,
+ struct input_dev *dev1);
+
/*
* XXX - this entry is suspicious. First byte has zero lower nibble,
* which is what a normal mouse would report. Also, the value 0x0e
@@ -122,10 +122,10 @@ static const struct alps_model_info alps_model_data[] = {
/* Packet formats are described in Documentation/input/alps.txt */
-static bool alps_is_valid_first_byte(const struct alps_model_info *model,
+static bool alps_is_valid_first_byte(struct alps_data *priv,
unsigned char data)
{
- return (data & model->mask0) == model->byte0;
+ return (data & priv->mask0) == priv->byte0;
}
static void alps_report_buttons(struct psmouse *psmouse,
@@ -158,14 +158,13 @@ static void alps_report_buttons(struct psmouse *psmouse,
static void alps_process_packet_v1_v2(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
- const struct alps_model_info *model = priv->i;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
struct input_dev *dev2 = priv->dev2;
int x, y, z, ges, fin, left, right, middle;
int back = 0, forward = 0;
- if (model->proto_version == ALPS_PROTO_V1) {
+ if (priv->proto_version == ALPS_PROTO_V1) {
left = packet[2] & 0x10;
right = packet[2] & 0x08;
middle = 0;
@@ -181,12 +180,12 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
z = packet[5];
}
- if (model->flags & ALPS_FW_BK_1) {
+ if (priv->flags & ALPS_FW_BK_1) {
back = packet[0] & 0x10;
forward = packet[2] & 4;
}
- if (model->flags & ALPS_FW_BK_2) {
+ if (priv->flags & ALPS_FW_BK_2) {
back = packet[3] & 4;
forward = packet[2] & 4;
if ((middle = forward && back))
@@ -196,7 +195,7 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
ges = packet[2] & 1;
fin = packet[2] & 2;
- if ((model->flags & ALPS_DUALPOINT) && z == 127) {
+ if ((priv->flags & ALPS_DUALPOINT) && z == 127) {
input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x));
input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
@@ -239,15 +238,15 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
input_report_abs(dev, ABS_PRESSURE, z);
input_report_key(dev, BTN_TOOL_FINGER, z > 0);
- if (model->flags & ALPS_WHEEL)
+ if (priv->flags & ALPS_WHEEL)
input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07));
- if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+ if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
input_report_key(dev, BTN_FORWARD, forward);
input_report_key(dev, BTN_BACK, back);
}
- if (model->flags & ALPS_FOUR_BUTTONS) {
+ if (priv->flags & ALPS_FOUR_BUTTONS) {
input_report_key(dev, BTN_0, packet[2] & 4);
input_report_key(dev, BTN_1, packet[0] & 0x10);
input_report_key(dev, BTN_2, packet[3] & 4);
@@ -267,7 +266,8 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
* These points are returned in x1, y1, x2, and y2 when the return value
* is greater than 0.
*/
-static int alps_process_bitmap(unsigned int x_map, unsigned int y_map,
+static int alps_process_bitmap(struct alps_data *priv,
+ unsigned int x_map, unsigned int y_map,
int *x1, int *y1, int *x2, int *y2)
{
struct alps_bitmap_point {
@@ -309,7 +309,7 @@ static int alps_process_bitmap(unsigned int x_map, unsigned int y_map,
* y bitmap is reversed for what we need (lower positions are in
* higher bits), so we process from the top end.
*/
- y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - ALPS_BITMAP_Y_BITS);
+ y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits);
prev_bit = 0;
point = &y_low;
for (i = 0; y_map != 0; i++, y_map <<= 1) {
@@ -355,16 +355,18 @@ static int alps_process_bitmap(unsigned int x_map, unsigned int y_map,
}
}
- *x1 = (ALPS_V3_X_MAX * (2 * x_low.start_bit + x_low.num_bits - 1)) /
- (2 * (ALPS_BITMAP_X_BITS - 1));
- *y1 = (ALPS_V3_Y_MAX * (2 * y_low.start_bit + y_low.num_bits - 1)) /
- (2 * (ALPS_BITMAP_Y_BITS - 1));
+ *x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
+ (2 * (priv->x_bits - 1));
+ *y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
+ (2 * (priv->y_bits - 1));
if (fingers > 1) {
- *x2 = (ALPS_V3_X_MAX * (2 * x_high.start_bit + x_high.num_bits - 1)) /
- (2 * (ALPS_BITMAP_X_BITS - 1));
- *y2 = (ALPS_V3_Y_MAX * (2 * y_high.start_bit + y_high.num_bits - 1)) /
- (2 * (ALPS_BITMAP_Y_BITS - 1));
+ *x2 = (priv->x_max *
+ (2 * x_high.start_bit + x_high.num_bits - 1)) /
+ (2 * (priv->x_bits - 1));
+ *y2 = (priv->y_max *
+ (2 * y_high.start_bit + y_high.num_bits - 1)) /
+ (2 * (priv->y_bits - 1));
}
return fingers;
@@ -448,17 +450,57 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
return;
}
+static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
+{
+ f->left = !!(p[3] & 0x01);
+ f->right = !!(p[3] & 0x02);
+ f->middle = !!(p[3] & 0x04);
+
+ f->ts_left = !!(p[3] & 0x10);
+ f->ts_right = !!(p[3] & 0x20);
+ f->ts_middle = !!(p[3] & 0x40);
+}
+
+static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
+{
+ f->first_mp = !!(p[4] & 0x40);
+ f->is_mp = !!(p[0] & 0x40);
+
+ f->fingers = (p[5] & 0x3) + 1;
+ f->x_map = ((p[4] & 0x7e) << 8) |
+ ((p[1] & 0x7f) << 2) |
+ ((p[0] & 0x30) >> 4);
+ f->y_map = ((p[3] & 0x70) << 4) |
+ ((p[2] & 0x7f) << 1) |
+ (p[4] & 0x01);
+
+ f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
+ ((p[0] & 0x30) >> 4);
+ f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
+ f->z = p[5] & 0x7f;
+
+ alps_decode_buttons_v3(f, p);
+}
+
+static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p)
+{
+ alps_decode_pinnacle(f, p);
+
+ f->x_map |= (p[5] & 0x10) << 11;
+ f->y_map |= (p[5] & 0x20) << 6;
+}
+
static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
struct input_dev *dev2 = priv->dev2;
- int x, y, z;
- int left, right, middle;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
int fingers = 0, bmap_fingers;
- unsigned int x_bitmap, y_bitmap;
+ struct alps_fields f;
+
+ priv->decode_fields(&f, packet);
/*
* There's no single feature of touchpad position and bitmap packets
@@ -473,16 +515,10 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
* packet. Check for this, and when it happens process the
* position packet as usual.
*/
- if (packet[0] & 0x40) {
- fingers = (packet[5] & 0x3) + 1;
- x_bitmap = ((packet[4] & 0x7e) << 8) |
- ((packet[1] & 0x7f) << 2) |
- ((packet[0] & 0x30) >> 4);
- y_bitmap = ((packet[3] & 0x70) << 4) |
- ((packet[2] & 0x7f) << 1) |
- (packet[4] & 0x01);
-
- bmap_fingers = alps_process_bitmap(x_bitmap, y_bitmap,
+ if (f.is_mp) {
+ fingers = f.fingers;
+ bmap_fingers = alps_process_bitmap(priv,
+ f.x_map, f.y_map,
&x1, &y1, &x2, &y2);
/*
@@ -493,7 +529,7 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
fingers = bmap_fingers;
/* Now process position packet */
- packet = priv->multi_data;
+ priv->decode_fields(&f, priv->multi_data);
} else {
priv->multi_packet = 0;
}
@@ -507,10 +543,10 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
* out misidentified bitmap packets, we reject anything with this
* bit set.
*/
- if (packet[0] & 0x40)
+ if (f.is_mp)
return;
- if (!priv->multi_packet && (packet[4] & 0x40)) {
+ if (!priv->multi_packet && f.first_mp) {
priv->multi_packet = 1;
memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
return;
@@ -518,22 +554,13 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
priv->multi_packet = 0;
- left = packet[3] & 0x01;
- right = packet[3] & 0x02;
- middle = packet[3] & 0x04;
-
- x = ((packet[1] & 0x7f) << 4) | ((packet[4] & 0x30) >> 2) |
- ((packet[0] & 0x30) >> 4);
- y = ((packet[2] & 0x7f) << 4) | (packet[4] & 0x0f);
- z = packet[5] & 0x7f;
-
/*
* Sometimes the hardware sends a single packet with z = 0
* in the middle of a stream. Real releases generate packets
* with x, y, and z all zero, so these seem to be flukes.
* Ignore them.
*/
- if (x && y && !z)
+ if (f.x && f.y && !f.z)
return;
/*
@@ -541,12 +568,12 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
* to rely on ST data.
*/
if (!fingers) {
- x1 = x;
- y1 = y;
- fingers = z > 0 ? 1 : 0;
+ x1 = f.x;
+ y1 = f.y;
+ fingers = f.z > 0 ? 1 : 0;
}
- if (z >= 64)
+ if (f.z >= 64)
input_report_key(dev, BTN_TOUCH, 1);
else
input_report_key(dev, BTN_TOUCH, 0);
@@ -555,26 +582,22 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
input_mt_report_finger_count(dev, fingers);
- input_report_key(dev, BTN_LEFT, left);
- input_report_key(dev, BTN_RIGHT, right);
- input_report_key(dev, BTN_MIDDLE, middle);
+ input_report_key(dev, BTN_LEFT, f.left);
+ input_report_key(dev, BTN_RIGHT, f.right);
+ input_report_key(dev, BTN_MIDDLE, f.middle);
- if (z > 0) {
- input_report_abs(dev, ABS_X, x);
- input_report_abs(dev, ABS_Y, y);
+ if (f.z > 0) {
+ input_report_abs(dev, ABS_X, f.x);
+ input_report_abs(dev, ABS_Y, f.y);
}
- input_report_abs(dev, ABS_PRESSURE, z);
+ input_report_abs(dev, ABS_PRESSURE, f.z);
input_sync(dev);
if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
- left = packet[3] & 0x10;
- right = packet[3] & 0x20;
- middle = packet[3] & 0x40;
-
- input_report_key(dev2, BTN_LEFT, left);
- input_report_key(dev2, BTN_RIGHT, right);
- input_report_key(dev2, BTN_MIDDLE, middle);
+ input_report_key(dev2, BTN_LEFT, f.ts_left);
+ input_report_key(dev2, BTN_RIGHT, f.ts_right);
+ input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
input_sync(dev2);
}
}
@@ -639,7 +662,7 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
((priv->multi_data[3] & 0x1f) << 5) |
(priv->multi_data[1] & 0x1f);
- fingers = alps_process_bitmap(x_bitmap, y_bitmap,
+ fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap,
&x1, &y1, &x2, &y2);
/* Store MT data.*/
@@ -696,25 +719,6 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
input_sync(dev);
}
-static void alps_process_packet(struct psmouse *psmouse)
-{
- struct alps_data *priv = psmouse->private;
- const struct alps_model_info *model = priv->i;
-
- switch (model->proto_version) {
- case ALPS_PROTO_V1:
- case ALPS_PROTO_V2:
- alps_process_packet_v1_v2(psmouse);
- break;
- case ALPS_PROTO_V3:
- alps_process_packet_v3(psmouse);
- break;
- case ALPS_PROTO_V4:
- alps_process_packet_v4(psmouse);
- break;
- }
-}
-
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
unsigned char packet[],
bool report_buttons)
@@ -765,14 +769,14 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
if (((psmouse->packet[3] |
psmouse->packet[4] |
psmouse->packet[5]) & 0x80) ||
- (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) {
+ (!alps_is_valid_first_byte(priv, psmouse->packet[6]))) {
psmouse_dbg(psmouse,
"refusing packet %4ph (suspected interleaved ps/2)\n",
psmouse->packet + 3);
return PSMOUSE_BAD_DATA;
}
- alps_process_packet(psmouse);
+ priv->process_packet(psmouse);
/* Continue with the next packet */
psmouse->packet[0] = psmouse->packet[6];
@@ -816,6 +820,7 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
static void alps_flush_packet(unsigned long data)
{
struct psmouse *psmouse = (struct psmouse *)data;
+ struct alps_data *priv = psmouse->private;
serio_pause_rx(psmouse->ps2dev.serio);
@@ -833,7 +838,7 @@ static void alps_flush_packet(unsigned long data)
"refusing packet %3ph (suspected interleaved ps/2)\n",
psmouse->packet + 3);
} else {
- alps_process_packet(psmouse);
+ priv->process_packet(psmouse);
}
psmouse->pktcnt = 0;
}
@@ -844,7 +849,6 @@ static void alps_flush_packet(unsigned long data)
static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
- const struct alps_model_info *model = priv->i;
if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
if (psmouse->pktcnt == 3) {
@@ -857,15 +861,15 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
/* Check for PS/2 packet stuffed in the middle of ALPS packet. */
- if ((model->flags & ALPS_PS2_INTERLEAVED) &&
+ if ((priv->flags & ALPS_PS2_INTERLEAVED) &&
psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) {
return alps_handle_interleaved_ps2(psmouse);
}
- if (!alps_is_valid_first_byte(model, psmouse->packet[0])) {
+ if (!alps_is_valid_first_byte(priv, psmouse->packet[0])) {
psmouse_dbg(psmouse,
"refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n",
- psmouse->packet[0], model->mask0, model->byte0);
+ psmouse->packet[0], priv->mask0, priv->byte0);
return PSMOUSE_BAD_DATA;
}
@@ -879,7 +883,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
}
if (psmouse->pktcnt == psmouse->pktsize) {
- alps_process_packet(psmouse);
+ priv->process_packet(psmouse);
return PSMOUSE_FULL_PACKET;
}
@@ -967,24 +971,42 @@ static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr,
return __alps_command_mode_write_reg(psmouse, value);
}
+static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
+ int repeated_command, unsigned char *param)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+ param[0] = 0;
+ if (init_command && ps2_command(ps2dev, param, init_command))
+ return -EIO;
+
+ if (ps2_command(ps2dev, NULL, repeated_command) ||
+ ps2_command(ps2dev, NULL, repeated_command) ||
+ ps2_command(ps2dev, NULL, repeated_command))
+ return -EIO;
+
+ param[0] = param[1] = param[2] = 0xff;
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+ return -EIO;
+
+ psmouse_dbg(psmouse, "%2.2X report: %2.2x %2.2x %2.2x\n",
+ repeated_command, param[0], param[1], param[2]);
+ return 0;
+}
+
static int alps_enter_command_mode(struct psmouse *psmouse,
unsigned char *resp)
{
unsigned char param[4];
- struct ps2dev *ps2dev = &psmouse->ps2dev;
- if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
- ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
+ if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_RESET_WRAP, param)) {
psmouse_err(psmouse, "failed to enter command mode\n");
return -1;
}
- if (param[0] != 0x88 && param[1] != 0x07) {
+ if (param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) {
psmouse_dbg(psmouse,
- "unknown response while entering command mode: %2.2x %2.2x %2.2x\n",
- param[0], param[1], param[2]);
+ "unknown response while entering command mode\n");
return -1;
}
@@ -1001,99 +1023,6 @@ static inline int alps_exit_command_mode(struct psmouse *psmouse)
return 0;
}
-static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
-{
- struct ps2dev *ps2dev = &psmouse->ps2dev;
- static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
- unsigned char param[4];
- const struct alps_model_info *model = NULL;
- int i;
-
- /*
- * First try "E6 report".
- * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
- * The bits 0-2 of the first byte will be 1s if some buttons are
- * pressed.
- */
- param[0] = 0;
- if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
- return NULL;
-
- param[0] = param[1] = param[2] = 0xff;
- if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
- return NULL;
-
- psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x",
- param[0], param[1], param[2]);
-
- if ((param[0] & 0xf8) != 0 || param[1] != 0 ||
- (param[2] != 10 && param[2] != 100))
- return NULL;
-
- /*
- * Now try "E7 report". Allowed responses are in
- * alps_model_data[].signature
- */
- param[0] = 0;
- if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21))
- return NULL;
-
- param[0] = param[1] = param[2] = 0xff;
- if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
- return NULL;
-
- psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x",
- param[0], param[1], param[2]);
-
- if (version) {
- for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++)
- /* empty */;
- *version = (param[0] << 8) | (param[1] << 4) | i;
- }
-
- for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
- if (!memcmp(param, alps_model_data[i].signature,
- sizeof(alps_model_data[i].signature))) {
- model = alps_model_data + i;
- break;
- }
- }
-
- if (model && model->proto_version > ALPS_PROTO_V2) {
- /*
- * Need to check command mode response to identify
- * model
- */
- model = NULL;
- if (alps_enter_command_mode(psmouse, param)) {
- psmouse_warn(psmouse,
- "touchpad failed to enter command mode\n");
- } else {
- for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
- if (alps_model_data[i].proto_version > ALPS_PROTO_V2 &&
- alps_model_data[i].command_mode_resp == param[0]) {
- model = alps_model_data + i;
- break;
- }
- }
- alps_exit_command_mode(psmouse);
-
- if (!model)
- psmouse_dbg(psmouse,
- "Unknown command mode response %2.2x\n",
- param[0]);
- }
- }
-
- return model;
-}
-
/*
* For DualPoint devices select the device that should respond to
* subsequent commands. It looks like glidepad is behind stickpointer,
@@ -1137,18 +1066,10 @@ static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)
static int alps_get_status(struct psmouse *psmouse, char *param)
{
- struct ps2dev *ps2dev = &psmouse->ps2dev;
-
/* Get status: 0xF5 0xF5 0xF5 0xE9 */
- if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
- ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+ if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_DISABLE, param))
return -1;
- psmouse_dbg(psmouse, "Status: %2.2x %2.2x %2.2x",
- param[0], param[1], param[2]);
-
return 0;
}
@@ -1190,16 +1111,16 @@ static int alps_poll(struct psmouse *psmouse)
unsigned char buf[sizeof(psmouse->packet)];
bool poll_failed;
- if (priv->i->flags & ALPS_PASS)
+ if (priv->flags & ALPS_PASS)
alps_passthrough_mode_v2(psmouse, true);
poll_failed = ps2_command(&psmouse->ps2dev, buf,
PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
- if (priv->i->flags & ALPS_PASS)
+ if (priv->flags & ALPS_PASS)
alps_passthrough_mode_v2(psmouse, false);
- if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
+ if (poll_failed || (buf[0] & priv->mask0) != priv->byte0)
return -1;
if ((psmouse->badbyte & 0xc8) == 0x08) {
@@ -1217,9 +1138,8 @@ static int alps_poll(struct psmouse *psmouse)
static int alps_hw_init_v1_v2(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
- const struct alps_model_info *model = priv->i;
- if ((model->flags & ALPS_PASS) &&
+ if ((priv->flags & ALPS_PASS) &&
alps_passthrough_mode_v2(psmouse, true)) {
return -1;
}
@@ -1234,7 +1154,7 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse)
return -1;
}
- if ((model->flags & ALPS_PASS) &&
+ if ((priv->flags & ALPS_PASS) &&
alps_passthrough_mode_v2(psmouse, false)) {
return -1;
}
@@ -1249,26 +1169,31 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse)
}
/*
- * Enable or disable passthrough mode to the trackstick. Must be in
- * command mode when calling this function.
+ * Enable or disable passthrough mode to the trackstick.
*/
-static int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable)
+static int alps_passthrough_mode_v3(struct psmouse *psmouse,
+ int reg_base, bool enable)
{
- int reg_val;
+ int reg_val, ret = -1;
- reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
- if (reg_val == -1)
+ if (alps_enter_command_mode(psmouse, NULL))
return -1;
+ reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x0008);
+ if (reg_val == -1)
+ goto error;
+
if (enable)
reg_val |= 0x01;
else
reg_val &= ~0x01;
- if (__alps_command_mode_write_reg(psmouse, reg_val))
- return -1;
+ ret = __alps_command_mode_write_reg(psmouse, reg_val);
- return 0;
+error:
+ if (alps_exit_command_mode(psmouse))
+ ret = -1;
+ return ret;
}
/* Must be in command mode when calling this function */
@@ -1287,73 +1212,102 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse)
return 0;
}
-static int alps_hw_init_v3(struct psmouse *psmouse)
+static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base)
{
- struct alps_data *priv = psmouse->private;
- struct ps2dev *ps2dev = &psmouse->ps2dev;
- int reg_val;
- unsigned char param[4];
-
- priv->nibble_commands = alps_v3_nibble_commands;
- priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+ int ret = -EIO, reg_val;
if (alps_enter_command_mode(psmouse, NULL))
goto error;
- /* Check for trackstick */
- reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
+ reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08);
if (reg_val == -1)
goto error;
- if (reg_val & 0x80) {
- if (alps_passthrough_mode_v3(psmouse, true))
- goto error;
- if (alps_exit_command_mode(psmouse))
- goto error;
+
+ /* bit 7: trackstick is present */
+ ret = reg_val & 0x80 ? 0 : -ENODEV;
+
+error:
+ alps_exit_command_mode(psmouse);
+ return ret;
+}
+
+static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ int ret = 0;
+ unsigned char param[4];
+
+ if (alps_passthrough_mode_v3(psmouse, reg_base, true))
+ return -EIO;
+
+ /*
+ * E7 report for the trackstick
+ *
+ * There have been reports of failures to seem to trace back
+ * to the above trackstick check failing. When these occur
+ * this E7 report fails, so when that happens we continue
+ * with the assumption that there isn't a trackstick after
+ * all.
+ */
+ if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) {
+ psmouse_warn(psmouse, "trackstick E7 report failed\n");
+ ret = -ENODEV;
+ } else {
+ psmouse_dbg(psmouse,
+ "trackstick E7 report: %2.2x %2.2x %2.2x\n",
+ param[0], param[1], param[2]);
/*
- * E7 report for the trackstick
- *
- * There have been reports of failures to seem to trace back
- * to the above trackstick check failing. When these occur
- * this E7 report fails, so when that happens we continue
- * with the assumption that there isn't a trackstick after
- * all.
+ * Not sure what this does, but it is absolutely
+ * essential. Without it, the touchpad does not
+ * work at all and the trackstick just emits normal
+ * PS/2 packets.
*/
- param[0] = 0x64;
- if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
- ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
- psmouse_warn(psmouse, "trackstick E7 report failed\n");
- } else {
- psmouse_dbg(psmouse,
- "trackstick E7 report: %2.2x %2.2x %2.2x\n",
- param[0], param[1], param[2]);
-
- /*
- * Not sure what this does, but it is absolutely
- * essential. Without it, the touchpad does not
- * work at all and the trackstick just emits normal
- * PS/2 packets.
- */
- if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
- alps_command_mode_send_nibble(psmouse, 0x9) ||
- alps_command_mode_send_nibble(psmouse, 0x4)) {
- psmouse_err(psmouse,
- "Error sending magic E6 sequence\n");
- goto error_passthrough;
- }
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ alps_command_mode_send_nibble(psmouse, 0x9) ||
+ alps_command_mode_send_nibble(psmouse, 0x4)) {
+ psmouse_err(psmouse,
+ "Error sending magic E6 sequence\n");
+ ret = -EIO;
+ goto error;
}
- if (alps_enter_command_mode(psmouse, NULL))
- goto error_passthrough;
- if (alps_passthrough_mode_v3(psmouse, false))
- goto error;
+ /*
+ * This ensures the trackstick packets are in the format
+ * supported by this driver. If bit 1 isn't set the packet
+ * format is different.
+ */
+ if (alps_enter_command_mode(psmouse, NULL) ||
+ alps_command_mode_write_reg(psmouse,
+ reg_base + 0x08, 0x82) ||
+ alps_exit_command_mode(psmouse))
+ ret = -EIO;
}
- if (alps_absolute_mode_v3(psmouse)) {
+error:
+ if (alps_passthrough_mode_v3(psmouse, reg_base, false))
+ ret = -EIO;
+
+ return ret;
+}
+
+static int alps_hw_init_v3(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ int reg_val;
+ unsigned char param[4];
+
+ reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE);
+ if (reg_val == -EIO)
+ goto error;
+ if (reg_val == 0 &&
+ alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
+ goto error;
+
+ if (alps_enter_command_mode(psmouse, NULL) ||
+ alps_absolute_mode_v3(psmouse)) {
psmouse_err(psmouse, "Failed to enter absolute mode\n");
goto error;
}
@@ -1390,14 +1344,6 @@ static int alps_hw_init_v3(struct psmouse *psmouse)
if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04))
goto error;
- /*
- * This ensures the trackstick packets are in the format
- * supported by this driver. If bit 1 isn't set the packet
- * format is different.
- */
- if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82))
- goto error;
-
alps_exit_command_mode(psmouse);
/* Set rate and enable data reporting */
@@ -1410,10 +1356,6 @@ static int alps_hw_init_v3(struct psmouse *psmouse)
return 0;
-error_passthrough:
- /* Something failed while in passthrough mode, so try to get out */
- if (!alps_enter_command_mode(psmouse, NULL))
- alps_passthrough_mode_v3(psmouse, false);
error:
/*
* Leaving the touchpad in command mode will essentially render
@@ -1424,6 +1366,50 @@ error:
return -1;
}
+static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ int reg_val, ret = -1;
+
+ if (priv->flags & ALPS_DUALPOINT) {
+ reg_val = alps_setup_trackstick_v3(psmouse,
+ ALPS_REG_BASE_RUSHMORE);
+ if (reg_val == -EIO)
+ goto error;
+ if (reg_val == -ENODEV)
+ priv->flags &= ~ALPS_DUALPOINT;
+ }
+
+ if (alps_enter_command_mode(psmouse, NULL) ||
+ alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 ||
+ alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
+ goto error;
+
+ reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6);
+ if (reg_val == -1)
+ goto error;
+ if (__alps_command_mode_write_reg(psmouse, reg_val & 0xfd))
+ goto error;
+
+ if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
+ goto error;
+
+ /* enter absolute mode */
+ reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
+ if (reg_val == -1)
+ goto error;
+ if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
+ goto error;
+
+ alps_exit_command_mode(psmouse);
+ return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+error:
+ alps_exit_command_mode(psmouse);
+ return ret;
+}
+
/* Must be in command mode when calling this function */
static int alps_absolute_mode_v4(struct psmouse *psmouse)
{
@@ -1442,13 +1428,9 @@ static int alps_absolute_mode_v4(struct psmouse *psmouse)
static int alps_hw_init_v4(struct psmouse *psmouse)
{
- struct alps_data *priv = psmouse->private;
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
- priv->nibble_commands = alps_v4_nibble_commands;
- priv->addr_command = PSMOUSE_CMD_DISABLE;
-
if (alps_enter_command_mode(psmouse, NULL))
goto error;
@@ -1517,39 +1499,140 @@ error:
return -1;
}
-static int alps_hw_init(struct psmouse *psmouse)
+static void alps_set_defaults(struct alps_data *priv)
{
- struct alps_data *priv = psmouse->private;
- const struct alps_model_info *model = priv->i;
- int ret = -1;
+ priv->byte0 = 0x8f;
+ priv->mask0 = 0x8f;
+ priv->flags = ALPS_DUALPOINT;
+
+ priv->x_max = 2000;
+ priv->y_max = 1400;
+ priv->x_bits = 15;
+ priv->y_bits = 11;
- switch (model->proto_version) {
+ switch (priv->proto_version) {
case ALPS_PROTO_V1:
case ALPS_PROTO_V2:
- ret = alps_hw_init_v1_v2(psmouse);
+ priv->hw_init = alps_hw_init_v1_v2;
+ priv->process_packet = alps_process_packet_v1_v2;
+ priv->set_abs_params = alps_set_abs_params_st;
break;
case ALPS_PROTO_V3:
- ret = alps_hw_init_v3(psmouse);
+ priv->hw_init = alps_hw_init_v3;
+ priv->process_packet = alps_process_packet_v3;
+ priv->set_abs_params = alps_set_abs_params_mt;
+ priv->decode_fields = alps_decode_pinnacle;
+ priv->nibble_commands = alps_v3_nibble_commands;
+ priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
break;
case ALPS_PROTO_V4:
- ret = alps_hw_init_v4(psmouse);
+ priv->hw_init = alps_hw_init_v4;
+ priv->process_packet = alps_process_packet_v4;
+ priv->set_abs_params = alps_set_abs_params_mt;
+ priv->nibble_commands = alps_v4_nibble_commands;
+ priv->addr_command = PSMOUSE_CMD_DISABLE;
break;
}
+}
- return ret;
+static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv,
+ unsigned char *e7, unsigned char *ec)
+{
+ const struct alps_model_info *model;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
+ model = &alps_model_data[i];
+
+ if (!memcmp(e7, model->signature, sizeof(model->signature)) &&
+ (!model->command_mode_resp ||
+ model->command_mode_resp == ec[2])) {
+
+ priv->proto_version = model->proto_version;
+ alps_set_defaults(priv);
+
+ priv->flags = model->flags;
+ priv->byte0 = model->byte0;
+ priv->mask0 = model->mask0;
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
+{
+ unsigned char e6[4], e7[4], ec[4];
+
+ /*
+ * First try "E6 report".
+ * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
+ * The bits 0-2 of the first byte will be 1s if some buttons are
+ * pressed.
+ */
+ if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
+ PSMOUSE_CMD_SETSCALE11, e6))
+ return -EIO;
+
+ if ((e6[0] & 0xf8) != 0 || e6[1] != 0 || (e6[2] != 10 && e6[2] != 100))
+ return -EINVAL;
+
+ /*
+ * Now get the "E7" and "EC" reports. These will uniquely identify
+ * most ALPS touchpads.
+ */
+ if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
+ PSMOUSE_CMD_SETSCALE21, e7) ||
+ alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
+ PSMOUSE_CMD_RESET_WRAP, ec) ||
+ alps_exit_command_mode(psmouse))
+ return -EIO;
+
+ if (alps_match_table(psmouse, priv, e7, ec) == 0) {
+ return 0;
+ } else if (ec[0] == 0x88 && ec[1] == 0x08) {
+ priv->proto_version = ALPS_PROTO_V3;
+ alps_set_defaults(priv);
+
+ priv->hw_init = alps_hw_init_rushmore_v3;
+ priv->decode_fields = alps_decode_rushmore;
+ priv->x_bits = 16;
+ priv->y_bits = 12;
+
+ /* hack to make addr_command, nibble_command available */
+ psmouse->private = priv;
+
+ if (alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_RUSHMORE))
+ priv->flags &= ~ALPS_DUALPOINT;
+
+ return 0;
+ } else if (ec[0] == 0x88 && ec[1] == 0x07 &&
+ ec[2] >= 0x90 && ec[2] <= 0x9d) {
+ priv->proto_version = ALPS_PROTO_V3;
+ alps_set_defaults(priv);
+
+ return 0;
+ }
+
+ psmouse_info(psmouse,
+ "Unknown ALPS touchpad: E7=%2.2x %2.2x %2.2x, EC=%2.2x %2.2x %2.2x\n",
+ e7[0], e7[1], e7[2], ec[0], ec[1], ec[2]);
+
+ return -EINVAL;
}
static int alps_reconnect(struct psmouse *psmouse)
{
- const struct alps_model_info *model;
+ struct alps_data *priv = psmouse->private;
psmouse_reset(psmouse);
- model = alps_get_model(psmouse, NULL);
- if (!model)
+ if (alps_identify(psmouse, priv) < 0)
return -1;
- return alps_hw_init(psmouse);
+ return priv->hw_init(psmouse);
}
static void alps_disconnect(struct psmouse *psmouse)
@@ -1562,12 +1645,33 @@ static void alps_disconnect(struct psmouse *psmouse)
kfree(priv);
}
+static void alps_set_abs_params_st(struct alps_data *priv,
+ struct input_dev *dev1)
+{
+ input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
+ input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
+}
+
+static void alps_set_abs_params_mt(struct alps_data *priv,
+ struct input_dev *dev1)
+{
+ set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
+ input_mt_init_slots(dev1, 2, 0);
+ input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
+ input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
+
+ set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
+ set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
+ set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
+
+ input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
+ input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
+}
+
int alps_init(struct psmouse *psmouse)
{
struct alps_data *priv;
- const struct alps_model_info *model;
struct input_dev *dev1 = psmouse->dev, *dev2;
- int version;
priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
dev2 = input_allocate_device();
@@ -1581,13 +1685,10 @@ int alps_init(struct psmouse *psmouse)
psmouse_reset(psmouse);
- model = alps_get_model(psmouse, &version);
- if (!model)
+ if (alps_identify(psmouse, priv) < 0)
goto init_fail;
- priv->i = model;
-
- if (alps_hw_init(psmouse))
+ if (priv->hw_init(psmouse))
goto init_fail;
/*
@@ -1609,41 +1710,20 @@ int alps_init(struct psmouse *psmouse)
dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
- switch (model->proto_version) {
- case ALPS_PROTO_V1:
- case ALPS_PROTO_V2:
- input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
- input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
- break;
- case ALPS_PROTO_V3:
- case ALPS_PROTO_V4:
- set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
- input_mt_init_slots(dev1, 2, 0);
- input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
- input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);
-
- set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
- set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
- set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
-
- input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
- input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
- break;
- }
-
+ priv->set_abs_params(priv, dev1);
input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
- if (model->flags & ALPS_WHEEL) {
+ if (priv->flags & ALPS_WHEEL) {
dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL);
}
- if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+ if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD);
dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK);
}
- if (model->flags & ALPS_FOUR_BUTTONS) {
+ if (priv->flags & ALPS_FOUR_BUTTONS) {
dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0);
dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
@@ -1654,7 +1734,8 @@ int alps_init(struct psmouse *psmouse)
snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
dev2->phys = priv->phys;
- dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse";
+ dev2->name = (priv->flags & ALPS_DUALPOINT) ?
+ "DualPoint Stick" : "PS/2 Mouse";
dev2->id.bustype = BUS_I8042;
dev2->id.vendor = 0x0002;
dev2->id.product = PSMOUSE_ALPS;
@@ -1673,7 +1754,7 @@ int alps_init(struct psmouse *psmouse)
psmouse->poll = alps_poll;
psmouse->disconnect = alps_disconnect;
psmouse->reconnect = alps_reconnect;
- psmouse->pktsize = model->proto_version == ALPS_PROTO_V4 ? 8 : 6;
+ psmouse->pktsize = priv->proto_version == ALPS_PROTO_V4 ? 8 : 6;
/* We are having trouble resyncing ALPS touchpads so disable it for now */
psmouse->resync_time = 0;
@@ -1690,18 +1771,16 @@ init_fail:
int alps_detect(struct psmouse *psmouse, bool set_properties)
{
- int version;
- const struct alps_model_info *model;
+ struct alps_data dummy;
- model = alps_get_model(psmouse, &version);
- if (!model)
+ if (alps_identify(psmouse, &dummy) < 0)
return -1;
if (set_properties) {
psmouse->vendor = "ALPS";
- psmouse->name = model->flags & ALPS_DUALPOINT ?
+ psmouse->name = dummy.flags & ALPS_DUALPOINT ?
"DualPoint TouchPad" : "GlidePoint";
- psmouse->model = version;
+ psmouse->model = dummy.proto_version << 8;
}
return 0;
}
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index ae1ac354c778..970480551b6e 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -12,35 +12,146 @@
#ifndef _ALPS_H
#define _ALPS_H
-#define ALPS_PROTO_V1 0
-#define ALPS_PROTO_V2 1
-#define ALPS_PROTO_V3 2
-#define ALPS_PROTO_V4 3
+#define ALPS_PROTO_V1 1
+#define ALPS_PROTO_V2 2
+#define ALPS_PROTO_V3 3
+#define ALPS_PROTO_V4 4
+/**
+ * struct alps_model_info - touchpad ID table
+ * @signature: E7 response string to match.
+ * @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response
+ * (aka command mode response) identifies the firmware minor version. This
+ * can be used to distinguish different hardware models which are not
+ * uniquely identifiable through their E7 responses.
+ * @proto_version: Indicates V1/V2/V3/...
+ * @byte0: Helps figure out whether a position report packet matches the
+ * known format for this model. The first byte of the report, ANDed with
+ * mask0, should match byte0.
+ * @mask0: The mask used to check the first byte of the report.
+ * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
+ *
+ * Many (but not all) ALPS touchpads can be identified by looking at the
+ * values returned in the "E7 report" and/or the "EC report." This table
+ * lists a number of such touchpads.
+ */
struct alps_model_info {
- unsigned char signature[3];
- unsigned char command_mode_resp; /* v3/v4 only */
+ unsigned char signature[3];
+ unsigned char command_mode_resp;
unsigned char proto_version;
- unsigned char byte0, mask0;
- unsigned char flags;
+ unsigned char byte0, mask0;
+ unsigned char flags;
};
+/**
+ * struct alps_nibble_commands - encodings for register accesses
+ * @command: PS/2 command used for the nibble
+ * @data: Data supplied as an argument to the PS/2 command, if applicable
+ *
+ * The ALPS protocol uses magic sequences to transmit binary data to the
+ * touchpad, as it is generally not OK to send arbitrary bytes out the
+ * PS/2 port. Each of the sequences in this table sends one nibble of the
+ * register address or (write) data. Different versions of the ALPS protocol
+ * use slightly different encodings.
+ */
struct alps_nibble_commands {
int command;
unsigned char data;
};
+/**
+ * struct alps_fields - decoded version of the report packet
+ * @x_map: Bitmap of active X positions for MT.
+ * @y_map: Bitmap of active Y positions for MT.
+ * @fingers: Number of fingers for MT.
+ * @x: X position for ST.
+ * @y: Y position for ST.
+ * @z: Z position for ST.
+ * @first_mp: Packet is the first of a multi-packet report.
+ * @is_mp: Packet is part of a multi-packet report.
+ * @left: Left touchpad button is active.
+ * @right: Right touchpad button is active.
+ * @middle: Middle touchpad button is active.
+ * @ts_left: Left trackstick button is active.
+ * @ts_right: Right trackstick button is active.
+ * @ts_middle: Middle trackstick button is active.
+ */
+struct alps_fields {
+ unsigned int x_map;
+ unsigned int y_map;
+ unsigned int fingers;
+ unsigned int x;
+ unsigned int y;
+ unsigned int z;
+ unsigned int first_mp:1;
+ unsigned int is_mp:1;
+
+ unsigned int left:1;
+ unsigned int right:1;
+ unsigned int middle:1;
+
+ unsigned int ts_left:1;
+ unsigned int ts_right:1;
+ unsigned int ts_middle:1;
+};
+
+/**
+ * struct alps_data - private data structure for the ALPS driver
+ * @dev2: "Relative" device used to report trackstick or mouse activity.
+ * @phys: Physical path for the relative device.
+ * @nibble_commands: Command mapping used for touchpad register accesses.
+ * @addr_command: Command used to tell the touchpad that a register address
+ * follows.
+ * @proto_version: Indicates V1/V2/V3/...
+ * @byte0: Helps figure out whether a position report packet matches the
+ * known format for this model. The first byte of the report, ANDed with
+ * mask0, should match byte0.
+ * @mask0: The mask used to check the first byte of the report.
+ * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
+ * @x_max: Largest possible X position value.
+ * @y_max: Largest possible Y position value.
+ * @x_bits: Number of X bits in the MT bitmap.
+ * @y_bits: Number of Y bits in the MT bitmap.
+ * @hw_init: Protocol-specific hardware init function.
+ * @process_packet: Protocol-specific function to process a report packet.
+ * @decode_fields: Protocol-specific function to read packet bitfields.
+ * @set_abs_params: Protocol-specific function to configure the input_dev.
+ * @prev_fin: Finger bit from previous packet.
+ * @multi_packet: Multi-packet data in progress.
+ * @multi_data: Saved multi-packet data.
+ * @x1: First X coordinate from last MT report.
+ * @x2: Second X coordinate from last MT report.
+ * @y1: First Y coordinate from last MT report.
+ * @y2: Second Y coordinate from last MT report.
+ * @fingers: Number of fingers from last MT report.
+ * @quirks: Bitmap of ALPS_QUIRK_*.
+ * @timer: Timer for flushing out the final report packet in the stream.
+ */
struct alps_data {
- struct input_dev *dev2; /* Relative device */
- char phys[32]; /* Phys */
- const struct alps_model_info *i;/* Info */
+ struct input_dev *dev2;
+ char phys[32];
+
+ /* these are autodetected when the device is identified */
const struct alps_nibble_commands *nibble_commands;
- int addr_command; /* Command to set register address */
- int prev_fin; /* Finger bit from previous packet */
- int multi_packet; /* Multi-packet data in progress */
- unsigned char multi_data[6]; /* Saved multi-packet data */
- int x1, x2, y1, y2; /* Coordinates from last MT report */
- int fingers; /* Number of fingers from MT report */
+ int addr_command;
+ unsigned char proto_version;
+ unsigned char byte0, mask0;
+ unsigned char flags;
+ int x_max;
+ int y_max;
+ int x_bits;
+ int y_bits;
+
+ int (*hw_init)(struct psmouse *psmouse);
+ void (*process_packet)(struct psmouse *psmouse);
+ void (*decode_fields)(struct alps_fields *f, unsigned char *p);
+ void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
+
+ int prev_fin;
+ int multi_packet;
+ unsigned char multi_data[6];
+ int x1, x2, y1, y2;
+ int fingers;
u8 quirks;
struct timer_list timer;
};
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
new file mode 100644
index 000000000000..b409c3d7d4fb
--- /dev/null
+++ b/drivers/input/mouse/cyapa.c
@@ -0,0 +1,973 @@
+/*
+ * Cypress APA trackpad with I2C interface
+ *
+ * Author: Dudley Du <dudl@cypress.com>
+ * Further cleanup and restructuring by:
+ * Daniel Kurtz <djkurtz@chromium.org>
+ * Benson Leung <bleung@chromium.org>
+ *
+ * Copyright (C) 2011-2012 Cypress Semiconductor, Inc.
+ * Copyright (C) 2011-2012 Google, 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 for
+ * more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+/* APA trackpad firmware generation */
+#define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */
+
+#define CYAPA_NAME "Cypress APA Trackpad (cyapa)"
+
+/* commands for read/write registers of Cypress trackpad */
+#define CYAPA_CMD_SOFT_RESET 0x00
+#define CYAPA_CMD_POWER_MODE 0x01
+#define CYAPA_CMD_DEV_STATUS 0x02
+#define CYAPA_CMD_GROUP_DATA 0x03
+#define CYAPA_CMD_GROUP_CMD 0x04
+#define CYAPA_CMD_GROUP_QUERY 0x05
+#define CYAPA_CMD_BL_STATUS 0x06
+#define CYAPA_CMD_BL_HEAD 0x07
+#define CYAPA_CMD_BL_CMD 0x08
+#define CYAPA_CMD_BL_DATA 0x09
+#define CYAPA_CMD_BL_ALL 0x0a
+#define CYAPA_CMD_BLK_PRODUCT_ID 0x0b
+#define CYAPA_CMD_BLK_HEAD 0x0c
+
+/* report data start reg offset address. */
+#define DATA_REG_START_OFFSET 0x0000
+
+#define BL_HEAD_OFFSET 0x00
+#define BL_DATA_OFFSET 0x10
+
+/*
+ * Operational Device Status Register
+ *
+ * bit 7: Valid interrupt source
+ * bit 6 - 4: Reserved
+ * bit 3 - 2: Power status
+ * bit 1 - 0: Device status
+ */
+#define REG_OP_STATUS 0x00
+#define OP_STATUS_SRC 0x80
+#define OP_STATUS_POWER 0x0c
+#define OP_STATUS_DEV 0x03
+#define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV)
+
+/*
+ * Operational Finger Count/Button Flags Register
+ *
+ * bit 7 - 4: Number of touched finger
+ * bit 3: Valid data
+ * bit 2: Middle Physical Button
+ * bit 1: Right Physical Button
+ * bit 0: Left physical Button
+ */
+#define REG_OP_DATA1 0x01
+#define OP_DATA_VALID 0x08
+#define OP_DATA_MIDDLE_BTN 0x04
+#define OP_DATA_RIGHT_BTN 0x02
+#define OP_DATA_LEFT_BTN 0x01
+#define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \
+ OP_DATA_LEFT_BTN)
+
+/*
+ * Bootloader Status Register
+ *
+ * bit 7: Busy
+ * bit 6 - 5: Reserved
+ * bit 4: Bootloader running
+ * bit 3 - 1: Reserved
+ * bit 0: Checksum valid
+ */
+#define REG_BL_STATUS 0x01
+#define BL_STATUS_BUSY 0x80
+#define BL_STATUS_RUNNING 0x10
+#define BL_STATUS_DATA_VALID 0x08
+#define BL_STATUS_CSUM_VALID 0x01
+
+/*
+ * Bootloader Error Register
+ *
+ * bit 7: Invalid
+ * bit 6: Invalid security key
+ * bit 5: Bootloading
+ * bit 4: Command checksum
+ * bit 3: Flash protection error
+ * bit 2: Flash checksum error
+ * bit 1 - 0: Reserved
+ */
+#define REG_BL_ERROR 0x02
+#define BL_ERROR_INVALID 0x80
+#define BL_ERROR_INVALID_KEY 0x40
+#define BL_ERROR_BOOTLOADING 0x20
+#define BL_ERROR_CMD_CSUM 0x10
+#define BL_ERROR_FLASH_PROT 0x08
+#define BL_ERROR_FLASH_CSUM 0x04
+
+#define BL_STATUS_SIZE 3 /* length of bootloader status registers */
+#define BLK_HEAD_BYTES 32
+
+#define PRODUCT_ID_SIZE 16
+#define QUERY_DATA_SIZE 27
+#define REG_PROTOCOL_GEN_QUERY_OFFSET 20
+
+#define REG_OFFSET_DATA_BASE 0x0000
+#define REG_OFFSET_COMMAND_BASE 0x0028
+#define REG_OFFSET_QUERY_BASE 0x002a
+
+#define CAPABILITY_LEFT_BTN_MASK (0x01 << 3)
+#define CAPABILITY_RIGHT_BTN_MASK (0x01 << 4)
+#define CAPABILITY_MIDDLE_BTN_MASK (0x01 << 5)
+#define CAPABILITY_BTN_MASK (CAPABILITY_LEFT_BTN_MASK | \
+ CAPABILITY_RIGHT_BTN_MASK | \
+ CAPABILITY_MIDDLE_BTN_MASK)
+
+#define CYAPA_OFFSET_SOFT_RESET REG_OFFSET_COMMAND_BASE
+
+#define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1)
+
+#define PWR_MODE_MASK 0xfc
+#define PWR_MODE_FULL_ACTIVE (0x3f << 2)
+#define PWR_MODE_IDLE (0x05 << 2) /* default sleep time is 50 ms. */
+#define PWR_MODE_OFF (0x00 << 2)
+
+#define PWR_STATUS_MASK 0x0c
+#define PWR_STATUS_ACTIVE (0x03 << 2)
+#define PWR_STATUS_IDLE (0x02 << 2)
+#define PWR_STATUS_OFF (0x00 << 2)
+
+/*
+ * CYAPA trackpad device states.
+ * Used in register 0x00, bit1-0, DeviceStatus field.
+ * Other values indicate device is in an abnormal state and must be reset.
+ */
+#define CYAPA_DEV_NORMAL 0x03
+#define CYAPA_DEV_BUSY 0x01
+
+enum cyapa_state {
+ CYAPA_STATE_OP,
+ CYAPA_STATE_BL_IDLE,
+ CYAPA_STATE_BL_ACTIVE,
+ CYAPA_STATE_BL_BUSY,
+ CYAPA_STATE_NO_DEVICE,
+};
+
+
+struct cyapa_touch {
+ /*
+ * high bits or x/y position value
+ * bit 7 - 4: high 4 bits of x position value
+ * bit 3 - 0: high 4 bits of y position value
+ */
+ u8 xy_hi;
+ u8 x_lo; /* low 8 bits of x position value. */
+ u8 y_lo; /* low 8 bits of y position value. */
+ u8 pressure;
+ /* id range is 1 - 15. It is incremented with every new touch. */
+ u8 id;
+} __packed;
+
+/* The touch.id is used as the MT slot id, thus max MT slot is 15 */
+#define CYAPA_MAX_MT_SLOTS 15
+
+struct cyapa_reg_data {
+ /*
+ * bit 0 - 1: device status
+ * bit 3 - 2: power mode
+ * bit 6 - 4: reserved
+ * bit 7: interrupt valid bit
+ */
+ u8 device_status;
+ /*
+ * bit 7 - 4: number of fingers currently touching pad
+ * bit 3: valid data check bit
+ * bit 2: middle mechanism button state if exists
+ * bit 1: right mechanism button state if exists
+ * bit 0: left mechanism button state if exists
+ */
+ u8 finger_btn;
+ /* CYAPA reports up to 5 touches per packet. */
+ struct cyapa_touch touches[5];
+} __packed;
+
+/* The main device structure */
+struct cyapa {
+ enum cyapa_state state;
+
+ struct i2c_client *client;
+ struct input_dev *input;
+ char phys[32]; /* device physical location */
+ int irq;
+ bool irq_wake; /* irq wake is enabled */
+ bool smbus;
+
+ /* read from query data region. */
+ char product_id[16];
+ u8 btn_capability;
+ u8 gen;
+ int max_abs_x;
+ int max_abs_y;
+ int physical_size_x;
+ int physical_size_y;
+};
+
+static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07 };
+static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07 };
+
+struct cyapa_cmd_len {
+ u8 cmd;
+ u8 len;
+};
+
+#define CYAPA_ADAPTER_FUNC_NONE 0
+#define CYAPA_ADAPTER_FUNC_I2C 1
+#define CYAPA_ADAPTER_FUNC_SMBUS 2
+#define CYAPA_ADAPTER_FUNC_BOTH 3
+
+/*
+ * macros for SMBus communication
+ */
+#define SMBUS_READ 0x01
+#define SMBUS_WRITE 0x00
+#define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1))
+#define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01))
+#define SMBUS_BYTE_BLOCK_CMD_MASK 0x80
+#define SMBUS_GROUP_BLOCK_CMD_MASK 0x40
+
+ /* for byte read/write command */
+#define CMD_RESET 0
+#define CMD_POWER_MODE 1
+#define CMD_DEV_STATUS 2
+#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1)
+#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET)
+#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE)
+#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS)
+
+ /* for group registers read/write command */
+#define REG_GROUP_DATA 0
+#define REG_GROUP_CMD 2
+#define REG_GROUP_QUERY 3
+#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3))
+#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA)
+#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD)
+#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY)
+
+ /* for register block read/write command */
+#define CMD_BL_STATUS 0
+#define CMD_BL_HEAD 1
+#define CMD_BL_CMD 2
+#define CMD_BL_DATA 3
+#define CMD_BL_ALL 4
+#define CMD_BLK_PRODUCT_ID 5
+#define CMD_BLK_HEAD 6
+#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1))
+
+/* register block read/write command in bootloader mode */
+#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS)
+#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD)
+#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD)
+#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA)
+#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL)
+
+/* register block read/write command in operational mode */
+#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID)
+#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD)
+
+static const struct cyapa_cmd_len cyapa_i2c_cmds[] = {
+ { CYAPA_OFFSET_SOFT_RESET, 1 },
+ { REG_OFFSET_COMMAND_BASE + 1, 1 },
+ { REG_OFFSET_DATA_BASE, 1 },
+ { REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) },
+ { REG_OFFSET_COMMAND_BASE, 0 },
+ { REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE },
+ { BL_HEAD_OFFSET, 3 },
+ { BL_HEAD_OFFSET, 16 },
+ { BL_HEAD_OFFSET, 16 },
+ { BL_DATA_OFFSET, 16 },
+ { BL_HEAD_OFFSET, 32 },
+ { REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE },
+ { REG_OFFSET_DATA_BASE, 32 }
+};
+
+static const struct cyapa_cmd_len cyapa_smbus_cmds[] = {
+ { CYAPA_SMBUS_RESET, 1 },
+ { CYAPA_SMBUS_POWER_MODE, 1 },
+ { CYAPA_SMBUS_DEV_STATUS, 1 },
+ { CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) },
+ { CYAPA_SMBUS_GROUP_CMD, 2 },
+ { CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE },
+ { CYAPA_SMBUS_BL_STATUS, 3 },
+ { CYAPA_SMBUS_BL_HEAD, 16 },
+ { CYAPA_SMBUS_BL_CMD, 16 },
+ { CYAPA_SMBUS_BL_DATA, 16 },
+ { CYAPA_SMBUS_BL_ALL, 32 },
+ { CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE },
+ { CYAPA_SMBUS_BLK_HEAD, 16 },
+};
+
+static ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len,
+ u8 *values)
+{
+ return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values);
+}
+
+static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg,
+ size_t len, const u8 *values)
+{
+ return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values);
+}
+
+/*
+ * cyapa_smbus_read_block - perform smbus block read command
+ * @cyapa - private data structure of the driver
+ * @cmd - the properly encoded smbus command
+ * @len - expected length of smbus command result
+ * @values - buffer to store smbus command result
+ *
+ * Returns negative errno, else the number of bytes written.
+ *
+ * Note:
+ * In trackpad device, the memory block allocated for I2C register map
+ * is 256 bytes, so the max read block for I2C bus is 256 bytes.
+ */
+static ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len,
+ u8 *values)
+{
+ ssize_t ret;
+ u8 index;
+ u8 smbus_cmd;
+ u8 *buf;
+ struct i2c_client *client = cyapa->client;
+
+ if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd))
+ return -EINVAL;
+
+ if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) {
+ /* read specific block registers command. */
+ smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
+ ret = i2c_smbus_read_block_data(client, smbus_cmd, values);
+ goto out;
+ }
+
+ ret = 0;
+ for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) {
+ smbus_cmd = SMBUS_ENCODE_IDX(cmd, index);
+ smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ);
+ buf = values + I2C_SMBUS_BLOCK_MAX * index;
+ ret = i2c_smbus_read_block_data(client, smbus_cmd, buf);
+ if (ret < 0)
+ goto out;
+ }
+
+out:
+ return ret > 0 ? len : ret;
+}
+
+static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx)
+{
+ u8 cmd;
+
+ if (cyapa->smbus) {
+ cmd = cyapa_smbus_cmds[cmd_idx].cmd;
+ cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
+ } else {
+ cmd = cyapa_i2c_cmds[cmd_idx].cmd;
+ }
+ return i2c_smbus_read_byte_data(cyapa->client, cmd);
+}
+
+static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value)
+{
+ u8 cmd;
+
+ if (cyapa->smbus) {
+ cmd = cyapa_smbus_cmds[cmd_idx].cmd;
+ cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE);
+ } else {
+ cmd = cyapa_i2c_cmds[cmd_idx].cmd;
+ }
+ return i2c_smbus_write_byte_data(cyapa->client, cmd, value);
+}
+
+static ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values)
+{
+ u8 cmd;
+ size_t len;
+
+ if (cyapa->smbus) {
+ cmd = cyapa_smbus_cmds[cmd_idx].cmd;
+ len = cyapa_smbus_cmds[cmd_idx].len;
+ return cyapa_smbus_read_block(cyapa, cmd, len, values);
+ } else {
+ cmd = cyapa_i2c_cmds[cmd_idx].cmd;
+ len = cyapa_i2c_cmds[cmd_idx].len;
+ return cyapa_i2c_reg_read_block(cyapa, cmd, len, values);
+ }
+}
+
+/*
+ * Query device for its current operating state.
+ *
+ */
+static int cyapa_get_state(struct cyapa *cyapa)
+{
+ int ret;
+ u8 status[BL_STATUS_SIZE];
+
+ cyapa->state = CYAPA_STATE_NO_DEVICE;
+
+ /*
+ * Get trackpad status by reading 3 registers starting from 0.
+ * If the device is in the bootloader, this will be BL_HEAD.
+ * If the device is in operation mode, this will be the DATA regs.
+ *
+ */
+ ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE,
+ status);
+
+ /*
+ * On smbus systems in OP mode, the i2c_reg_read will fail with
+ * -ETIMEDOUT. In this case, try again using the smbus equivalent
+ * command. This should return a BL_HEAD indicating CYAPA_STATE_OP.
+ */
+ if (cyapa->smbus && (ret == -ETIMEDOUT || ret == -ENXIO))
+ ret = cyapa_read_block(cyapa, CYAPA_CMD_BL_STATUS, status);
+
+ if (ret != BL_STATUS_SIZE)
+ goto error;
+
+ if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) {
+ switch (status[REG_OP_STATUS] & OP_STATUS_DEV) {
+ case CYAPA_DEV_NORMAL:
+ case CYAPA_DEV_BUSY:
+ cyapa->state = CYAPA_STATE_OP;
+ break;
+ default:
+ ret = -EAGAIN;
+ goto error;
+ }
+ } else {
+ if (status[REG_BL_STATUS] & BL_STATUS_BUSY)
+ cyapa->state = CYAPA_STATE_BL_BUSY;
+ else if (status[REG_BL_ERROR] & BL_ERROR_BOOTLOADING)
+ cyapa->state = CYAPA_STATE_BL_ACTIVE;
+ else
+ cyapa->state = CYAPA_STATE_BL_IDLE;
+ }
+
+ return 0;
+error:
+ return (ret < 0) ? ret : -EAGAIN;
+}
+
+/*
+ * Poll device for its status in a loop, waiting up to timeout for a response.
+ *
+ * When the device switches state, it usually takes ~300 ms.
+ * However, when running a new firmware image, the device must calibrate its
+ * sensors, which can take as long as 2 seconds.
+ *
+ * Note: The timeout has granularity of the polling rate, which is 100 ms.
+ *
+ * Returns:
+ * 0 when the device eventually responds with a valid non-busy state.
+ * -ETIMEDOUT if device never responds (too many -EAGAIN)
+ * < 0 other errors
+ */
+static int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout)
+{
+ int ret;
+ int tries = timeout / 100;
+
+ ret = cyapa_get_state(cyapa);
+ while ((ret || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) {
+ msleep(100);
+ ret = cyapa_get_state(cyapa);
+ }
+ return (ret == -EAGAIN || ret == -ETIMEDOUT) ? -ETIMEDOUT : ret;
+}
+
+static int cyapa_bl_deactivate(struct cyapa *cyapa)
+{
+ int ret;
+
+ ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate),
+ bl_deactivate);
+ if (ret < 0)
+ return ret;
+
+ /* wait for bootloader to switch to idle state; should take < 100ms */
+ msleep(100);
+ ret = cyapa_poll_state(cyapa, 500);
+ if (ret < 0)
+ return ret;
+ if (cyapa->state != CYAPA_STATE_BL_IDLE)
+ return -EAGAIN;
+ return 0;
+}
+
+/*
+ * Exit bootloader
+ *
+ * Send bl_exit command, then wait 50 - 100 ms to let device transition to
+ * operational mode. If this is the first time the device's firmware is
+ * running, it can take up to 2 seconds to calibrate its sensors. So, poll
+ * the device's new state for up to 2 seconds.
+ *
+ * Returns:
+ * -EIO failure while reading from device
+ * -EAGAIN device is stuck in bootloader, b/c it has invalid firmware
+ * 0 device is supported and in operational mode
+ */
+static int cyapa_bl_exit(struct cyapa *cyapa)
+{
+ int ret;
+
+ ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Wait for bootloader to exit, and operation mode to start.
+ * Normally, this takes at least 50 ms.
+ */
+ usleep_range(50000, 100000);
+ /*
+ * In addition, when a device boots for the first time after being
+ * updated to new firmware, it must first calibrate its sensors, which
+ * can take up to an additional 2 seconds.
+ */
+ ret = cyapa_poll_state(cyapa, 2000);
+ if (ret < 0)
+ return ret;
+ if (cyapa->state != CYAPA_STATE_OP)
+ return -EAGAIN;
+
+ return 0;
+}
+
+/*
+ * Set device power mode
+ *
+ */
+static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode)
+{
+ struct device *dev = &cyapa->client->dev;
+ int ret;
+ u8 power;
+
+ if (cyapa->state != CYAPA_STATE_OP)
+ return 0;
+
+ ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE);
+ if (ret < 0)
+ return ret;
+
+ power = ret & ~PWR_MODE_MASK;
+ power |= power_mode & PWR_MODE_MASK;
+ ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power);
+ if (ret < 0)
+ dev_err(dev, "failed to set power_mode 0x%02x err = %d\n",
+ power_mode, ret);
+ return ret;
+}
+
+static int cyapa_get_query_data(struct cyapa *cyapa)
+{
+ u8 query_data[QUERY_DATA_SIZE];
+ int ret;
+
+ if (cyapa->state != CYAPA_STATE_OP)
+ return -EBUSY;
+
+ ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data);
+ if (ret < 0)
+ return ret;
+ if (ret != QUERY_DATA_SIZE)
+ return -EIO;
+
+ memcpy(&cyapa->product_id[0], &query_data[0], 5);
+ cyapa->product_id[5] = '-';
+ memcpy(&cyapa->product_id[6], &query_data[5], 6);
+ cyapa->product_id[12] = '-';
+ memcpy(&cyapa->product_id[13], &query_data[11], 2);
+ cyapa->product_id[15] = '\0';
+
+ cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK;
+
+ cyapa->gen = query_data[20] & 0x0f;
+
+ cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22];
+ cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23];
+
+ cyapa->physical_size_x =
+ ((query_data[24] & 0xf0) << 4) | query_data[25];
+ cyapa->physical_size_y =
+ ((query_data[24] & 0x0f) << 8) | query_data[26];
+
+ return 0;
+}
+
+/*
+ * Check if device is operational.
+ *
+ * An operational device is responding, has exited bootloader, and has
+ * firmware supported by this driver.
+ *
+ * Returns:
+ * -EBUSY no device or in bootloader
+ * -EIO failure while reading from device
+ * -EAGAIN device is still in bootloader
+ * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware
+ * -EINVAL device is in operational mode, but not supported by this driver
+ * 0 device is supported
+ */
+static int cyapa_check_is_operational(struct cyapa *cyapa)
+{
+ struct device *dev = &cyapa->client->dev;
+ static const char unique_str[] = "CYTRA";
+ int ret;
+
+ ret = cyapa_poll_state(cyapa, 2000);
+ if (ret < 0)
+ return ret;
+ switch (cyapa->state) {
+ case CYAPA_STATE_BL_ACTIVE:
+ ret = cyapa_bl_deactivate(cyapa);
+ if (ret)
+ return ret;
+
+ /* Fallthrough state */
+ case CYAPA_STATE_BL_IDLE:
+ ret = cyapa_bl_exit(cyapa);
+ if (ret)
+ return ret;
+
+ /* Fallthrough state */
+ case CYAPA_STATE_OP:
+ ret = cyapa_get_query_data(cyapa);
+ if (ret < 0)
+ return ret;
+
+ /* only support firmware protocol gen3 */
+ if (cyapa->gen != CYAPA_GEN3) {
+ dev_err(dev, "unsupported protocol version (%d)",
+ cyapa->gen);
+ return -EINVAL;
+ }
+
+ /* only support product ID starting with CYTRA */
+ if (memcmp(cyapa->product_id, unique_str,
+ sizeof(unique_str) - 1) != 0) {
+ dev_err(dev, "unsupported product ID (%s)\n",
+ cyapa->product_id);
+ return -EINVAL;
+ }
+ return 0;
+
+ default:
+ return -EIO;
+ }
+ return 0;
+}
+
+static irqreturn_t cyapa_irq(int irq, void *dev_id)
+{
+ struct cyapa *cyapa = dev_id;
+ struct device *dev = &cyapa->client->dev;
+ struct input_dev *input = cyapa->input;
+ struct cyapa_reg_data data;
+ int i;
+ int ret;
+ int num_fingers;
+
+ if (device_may_wakeup(dev))
+ pm_wakeup_event(dev, 0);
+
+ ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
+ if (ret != sizeof(data))
+ goto out;
+
+ if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
+ (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
+ (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) {
+ goto out;
+ }
+
+ num_fingers = (data.finger_btn >> 4) & 0x0f;
+ for (i = 0; i < num_fingers; i++) {
+ const struct cyapa_touch *touch = &data.touches[i];
+ /* Note: touch->id range is 1 to 15; slots are 0 to 14. */
+ int slot = touch->id - 1;
+
+ input_mt_slot(input, slot);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+ input_report_abs(input, ABS_MT_POSITION_X,
+ ((touch->xy_hi & 0xf0) << 4) | touch->x_lo);
+ input_report_abs(input, ABS_MT_POSITION_Y,
+ ((touch->xy_hi & 0x0f) << 8) | touch->y_lo);
+ input_report_abs(input, ABS_MT_PRESSURE, touch->pressure);
+ }
+
+ input_mt_sync_frame(input);
+
+ if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
+ input_report_key(input, BTN_LEFT,
+ data.finger_btn & OP_DATA_LEFT_BTN);
+
+ if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
+ input_report_key(input, BTN_MIDDLE,
+ data.finger_btn & OP_DATA_MIDDLE_BTN);
+
+ if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
+ input_report_key(input, BTN_RIGHT,
+ data.finger_btn & OP_DATA_RIGHT_BTN);
+
+ input_sync(input);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static u8 cyapa_check_adapter_functionality(struct i2c_client *client)
+{
+ u8 ret = CYAPA_ADAPTER_FUNC_NONE;
+
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ ret |= CYAPA_ADAPTER_FUNC_I2C;
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK))
+ ret |= CYAPA_ADAPTER_FUNC_SMBUS;
+ return ret;
+}
+
+static int cyapa_create_input_dev(struct cyapa *cyapa)
+{
+ struct device *dev = &cyapa->client->dev;
+ int ret;
+ struct input_dev *input;
+
+ if (!cyapa->physical_size_x || !cyapa->physical_size_y)
+ return -EINVAL;
+
+ input = cyapa->input = input_allocate_device();
+ if (!input) {
+ dev_err(dev, "allocate memory for input device failed\n");
+ return -ENOMEM;
+ }
+
+ input->name = CYAPA_NAME;
+ input->phys = cyapa->phys;
+ input->id.bustype = BUS_I2C;
+ input->id.version = 1;
+ input->id.product = 0; /* means any product in eventcomm. */
+ input->dev.parent = &cyapa->client->dev;
+
+ input_set_drvdata(input, cyapa);
+
+ __set_bit(EV_ABS, input->evbit);
+
+ /* finger position */
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0,
+ 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0,
+ 0);
+ input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
+
+ input_abs_set_res(input, ABS_MT_POSITION_X,
+ cyapa->max_abs_x / cyapa->physical_size_x);
+ input_abs_set_res(input, ABS_MT_POSITION_Y,
+ cyapa->max_abs_y / cyapa->physical_size_y);
+
+ if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
+ __set_bit(BTN_LEFT, input->keybit);
+ if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
+ __set_bit(BTN_MIDDLE, input->keybit);
+ if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
+ __set_bit(BTN_RIGHT, input->keybit);
+
+ if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK)
+ __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+
+ /* handle pointer emulation and unused slots in core */
+ ret = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS,
+ INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
+ if (ret) {
+ dev_err(dev, "allocate memory for MT slots failed, %d\n", ret);
+ goto err_free_device;
+ }
+
+ /* Register the device in input subsystem */
+ ret = input_register_device(input);
+ if (ret) {
+ dev_err(dev, "input device register failed, %d\n", ret);
+ goto err_free_device;
+ }
+ return 0;
+
+err_free_device:
+ input_free_device(input);
+ cyapa->input = NULL;
+ return ret;
+}
+
+static int cyapa_probe(struct i2c_client *client,
+ const struct i2c_device_id *dev_id)
+{
+ int ret;
+ u8 adapter_func;
+ struct cyapa *cyapa;
+ struct device *dev = &client->dev;
+
+ adapter_func = cyapa_check_adapter_functionality(client);
+ if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) {
+ dev_err(dev, "not a supported I2C/SMBus adapter\n");
+ return -EIO;
+ }
+
+ cyapa = kzalloc(sizeof(struct cyapa), GFP_KERNEL);
+ if (!cyapa) {
+ dev_err(dev, "allocate memory for cyapa failed\n");
+ return -ENOMEM;
+ }
+
+ cyapa->gen = CYAPA_GEN3;
+ cyapa->client = client;
+ i2c_set_clientdata(client, cyapa);
+ sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr,
+ client->addr);
+
+ /* i2c isn't supported, use smbus */
+ if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
+ cyapa->smbus = true;
+ cyapa->state = CYAPA_STATE_NO_DEVICE;
+ ret = cyapa_check_is_operational(cyapa);
+ if (ret) {
+ dev_err(dev, "device not operational, %d\n", ret);
+ goto err_mem_free;
+ }
+
+ ret = cyapa_create_input_dev(cyapa);
+ if (ret) {
+ dev_err(dev, "create input_dev instance failed, %d\n", ret);
+ goto err_mem_free;
+ }
+
+ ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
+ if (ret) {
+ dev_err(dev, "set active power failed, %d\n", ret);
+ goto err_unregister_device;
+ }
+
+ cyapa->irq = client->irq;
+ ret = request_threaded_irq(cyapa->irq,
+ NULL,
+ cyapa_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "cyapa",
+ cyapa);
+ if (ret) {
+ dev_err(dev, "IRQ request failed: %d\n, ", ret);
+ goto err_unregister_device;
+ }
+
+ return 0;
+
+err_unregister_device:
+ input_unregister_device(cyapa->input);
+err_mem_free:
+ kfree(cyapa);
+
+ return ret;
+}
+
+static int cyapa_remove(struct i2c_client *client)
+{
+ struct cyapa *cyapa = i2c_get_clientdata(client);
+
+ free_irq(cyapa->irq, cyapa);
+ input_unregister_device(cyapa->input);
+ cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
+ kfree(cyapa);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int cyapa_suspend(struct device *dev)
+{
+ int ret;
+ u8 power_mode;
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+
+ disable_irq(cyapa->irq);
+
+ /*
+ * Set trackpad device to idle mode if wakeup is allowed,
+ * otherwise turn off.
+ */
+ power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE
+ : PWR_MODE_OFF;
+ ret = cyapa_set_power_mode(cyapa, power_mode);
+ if (ret < 0)
+ dev_err(dev, "set power mode failed, %d\n", ret);
+
+ if (device_may_wakeup(dev))
+ cyapa->irq_wake = (enable_irq_wake(cyapa->irq) == 0);
+ return 0;
+}
+
+static int cyapa_resume(struct device *dev)
+{
+ int ret;
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev) && cyapa->irq_wake)
+ disable_irq_wake(cyapa->irq);
+
+ ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
+ if (ret)
+ dev_warn(dev, "resume active power failed, %d\n", ret);
+
+ enable_irq(cyapa->irq);
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(cyapa_pm_ops, cyapa_suspend, cyapa_resume);
+
+static const struct i2c_device_id cyapa_id_table[] = {
+ { "cyapa", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
+
+static struct i2c_driver cyapa_driver = {
+ .driver = {
+ .name = "cyapa",
+ .owner = THIS_MODULE,
+ .pm = &cyapa_pm_ops,
+ },
+
+ .probe = cyapa_probe,
+ .remove = cyapa_remove,
+ .id_table = cyapa_id_table,
+};
+
+module_i2c_driver(cyapa_driver);
+
+MODULE_DESCRIPTION("Cypress APA I2C Trackpad Driver");
+MODULE_AUTHOR("Dudley Du <dudl@cypress.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
new file mode 100644
index 000000000000..1673dc6c8092
--- /dev/null
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -0,0 +1,725 @@
+/*
+ * Cypress Trackpad PS/2 mouse driver
+ *
+ * Copyright (c) 2012 Cypress Semiconductor Corporation.
+ *
+ * Author:
+ * Dudley Du <dudl@cypress.com>
+ *
+ * Additional contributors include:
+ * Kamal Mostafa <kamal@canonical.com>
+ * Kyle Fazzari <git@status.e4ward.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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include "cypress_ps2.h"
+
+#undef CYTP_DEBUG_VERBOSE /* define this and DEBUG for more verbose dump */
+
+static void cypress_set_packet_size(struct psmouse *psmouse, unsigned int n)
+{
+ struct cytp_data *cytp = psmouse->private;
+ cytp->pkt_size = n;
+}
+
+static const unsigned char cytp_rate[] = {10, 20, 40, 60, 100, 200};
+static const unsigned char cytp_resolution[] = {0x00, 0x01, 0x02, 0x03};
+
+static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+ if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) {
+ psmouse_dbg(psmouse,
+ "sending command 0x%02x failed, resp 0x%02x\n",
+ value & 0xff, ps2dev->nak);
+ if (ps2dev->nak == CYTP_PS2_RETRY)
+ return CYTP_PS2_RETRY;
+ else
+ return CYTP_PS2_ERROR;
+ }
+
+#ifdef CYTP_DEBUG_VERBOSE
+ psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n",
+ value & 0xff);
+#endif
+
+ return 0;
+}
+
+static int cypress_ps2_ext_cmd(struct psmouse *psmouse, unsigned short cmd,
+ unsigned char data)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ int tries = CYTP_PS2_CMD_TRIES;
+ int rc;
+
+ ps2_begin_command(ps2dev);
+
+ do {
+ /*
+ * Send extension command byte (0xE8 or 0xF3).
+ * If sending the command fails, send recovery command
+ * to make the device return to the ready state.
+ */
+ rc = cypress_ps2_sendbyte(psmouse, cmd & 0xff);
+ if (rc == CYTP_PS2_RETRY) {
+ rc = cypress_ps2_sendbyte(psmouse, 0x00);
+ if (rc == CYTP_PS2_RETRY)
+ rc = cypress_ps2_sendbyte(psmouse, 0x0a);
+ }
+ if (rc == CYTP_PS2_ERROR)
+ continue;
+
+ rc = cypress_ps2_sendbyte(psmouse, data);
+ if (rc == CYTP_PS2_RETRY)
+ rc = cypress_ps2_sendbyte(psmouse, data);
+ if (rc == CYTP_PS2_ERROR)
+ continue;
+ else
+ break;
+ } while (--tries > 0);
+
+ ps2_end_command(ps2dev);
+
+ return rc;
+}
+
+static int cypress_ps2_read_cmd_status(struct psmouse *psmouse,
+ unsigned char cmd,
+ unsigned char *param)
+{
+ int rc;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ enum psmouse_state old_state;
+ int pktsize;
+
+ ps2_begin_command(&psmouse->ps2dev);
+
+ old_state = psmouse->state;
+ psmouse->state = PSMOUSE_CMD_MODE;
+ psmouse->pktcnt = 0;
+
+ pktsize = (cmd == CYTP_CMD_READ_TP_METRICS) ? 8 : 3;
+ memset(param, 0, pktsize);
+
+ rc = cypress_ps2_sendbyte(psmouse, 0xe9);
+ if (rc < 0)
+ goto out;
+
+ wait_event_timeout(ps2dev->wait,
+ (psmouse->pktcnt >= pktsize),
+ msecs_to_jiffies(CYTP_CMD_TIMEOUT));
+
+ memcpy(param, psmouse->packet, pktsize);
+
+ psmouse_dbg(psmouse, "Command 0x%02x response data (0x): %*ph\n",
+ cmd, pktsize, param);
+
+out:
+ psmouse->state = old_state;
+ psmouse->pktcnt = 0;
+
+ ps2_end_command(&psmouse->ps2dev);
+
+ return rc;
+}
+
+static bool cypress_verify_cmd_state(struct psmouse *psmouse,
+ unsigned char cmd, unsigned char *param)
+{
+ bool rate_match = false;
+ bool resolution_match = false;
+ int i;
+
+ /* callers will do further checking. */
+ if (cmd == CYTP_CMD_READ_CYPRESS_ID ||
+ cmd == CYTP_CMD_STANDARD_MODE ||
+ cmd == CYTP_CMD_READ_TP_METRICS)
+ return true;
+
+ if ((~param[0] & DFLT_RESP_BITS_VALID) == DFLT_RESP_BITS_VALID &&
+ (param[0] & DFLT_RESP_BIT_MODE) == DFLT_RESP_STREAM_MODE) {
+ for (i = 0; i < sizeof(cytp_resolution); i++)
+ if (cytp_resolution[i] == param[1])
+ resolution_match = true;
+
+ for (i = 0; i < sizeof(cytp_rate); i++)
+ if (cytp_rate[i] == param[2])
+ rate_match = true;
+
+ if (resolution_match && rate_match)
+ return true;
+ }
+
+ psmouse_dbg(psmouse, "verify cmd state failed.\n");
+ return false;
+}
+
+static int cypress_send_ext_cmd(struct psmouse *psmouse, unsigned char cmd,
+ unsigned char *param)
+{
+ int tries = CYTP_PS2_CMD_TRIES;
+ int rc;
+
+ psmouse_dbg(psmouse, "send extension cmd 0x%02x, [%d %d %d %d]\n",
+ cmd, DECODE_CMD_AA(cmd), DECODE_CMD_BB(cmd),
+ DECODE_CMD_CC(cmd), DECODE_CMD_DD(cmd));
+
+ do {
+ cypress_ps2_ext_cmd(psmouse,
+ PSMOUSE_CMD_SETRES, DECODE_CMD_DD(cmd));
+ cypress_ps2_ext_cmd(psmouse,
+ PSMOUSE_CMD_SETRES, DECODE_CMD_CC(cmd));
+ cypress_ps2_ext_cmd(psmouse,
+ PSMOUSE_CMD_SETRES, DECODE_CMD_BB(cmd));
+ cypress_ps2_ext_cmd(psmouse,
+ PSMOUSE_CMD_SETRES, DECODE_CMD_AA(cmd));
+
+ rc = cypress_ps2_read_cmd_status(psmouse, cmd, param);
+ if (rc)
+ continue;
+
+ if (cypress_verify_cmd_state(psmouse, cmd, param))
+ return 0;
+
+ } while (--tries > 0);
+
+ return -EIO;
+}
+
+int cypress_detect(struct psmouse *psmouse, bool set_properties)
+{
+ unsigned char param[3];
+
+ if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
+ return -ENODEV;
+
+ /* Check for Cypress Trackpad signature bytes: 0x33 0xCC */
+ if (param[0] != 0x33 || param[1] != 0xCC)
+ return -ENODEV;
+
+ if (set_properties) {
+ psmouse->vendor = "Cypress";
+ psmouse->name = "Trackpad";
+ }
+
+ return 0;
+}
+
+static int cypress_read_fw_version(struct psmouse *psmouse)
+{
+ struct cytp_data *cytp = psmouse->private;
+ unsigned char param[3];
+
+ if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
+ return -ENODEV;
+
+ /* Check for Cypress Trackpad signature bytes: 0x33 0xCC */
+ if (param[0] != 0x33 || param[1] != 0xCC)
+ return -ENODEV;
+
+ cytp->fw_version = param[2] & FW_VERSION_MASX;
+ cytp->tp_metrics_supported = (param[2] & TP_METRICS_MASK) ? 1 : 0;
+
+ psmouse_dbg(psmouse, "cytp->fw_version = %d\n", cytp->fw_version);
+ psmouse_dbg(psmouse, "cytp->tp_metrics_supported = %d\n",
+ cytp->tp_metrics_supported);
+
+ return 0;
+}
+
+static int cypress_read_tp_metrics(struct psmouse *psmouse)
+{
+ struct cytp_data *cytp = psmouse->private;
+ unsigned char param[8];
+
+ /* set default values for tp metrics. */
+ cytp->tp_width = CYTP_DEFAULT_WIDTH;
+ cytp->tp_high = CYTP_DEFAULT_HIGH;
+ cytp->tp_max_abs_x = CYTP_ABS_MAX_X;
+ cytp->tp_max_abs_y = CYTP_ABS_MAX_Y;
+ cytp->tp_min_pressure = CYTP_MIN_PRESSURE;
+ cytp->tp_max_pressure = CYTP_MAX_PRESSURE;
+ cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
+ cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
+
+ memset(param, 0, sizeof(param));
+ if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_TP_METRICS, param) == 0) {
+ /* Update trackpad parameters. */
+ cytp->tp_max_abs_x = (param[1] << 8) | param[0];
+ cytp->tp_max_abs_y = (param[3] << 8) | param[2];
+ cytp->tp_min_pressure = param[4];
+ cytp->tp_max_pressure = param[5];
+ }
+
+ if (!cytp->tp_max_pressure ||
+ cytp->tp_max_pressure < cytp->tp_min_pressure ||
+ !cytp->tp_width || !cytp->tp_high ||
+ !cytp->tp_max_abs_x ||
+ cytp->tp_max_abs_x < cytp->tp_width ||
+ !cytp->tp_max_abs_y ||
+ cytp->tp_max_abs_y < cytp->tp_high)
+ return -EINVAL;
+
+ cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
+ cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
+
+#ifdef CYTP_DEBUG_VERBOSE
+ psmouse_dbg(psmouse, "Dump trackpad hardware configuration as below:\n");
+ psmouse_dbg(psmouse, "cytp->tp_width = %d\n", cytp->tp_width);
+ psmouse_dbg(psmouse, "cytp->tp_high = %d\n", cytp->tp_high);
+ psmouse_dbg(psmouse, "cytp->tp_max_abs_x = %d\n", cytp->tp_max_abs_x);
+ psmouse_dbg(psmouse, "cytp->tp_max_abs_y = %d\n", cytp->tp_max_abs_y);
+ psmouse_dbg(psmouse, "cytp->tp_min_pressure = %d\n", cytp->tp_min_pressure);
+ psmouse_dbg(psmouse, "cytp->tp_max_pressure = %d\n", cytp->tp_max_pressure);
+ psmouse_dbg(psmouse, "cytp->tp_res_x = %d\n", cytp->tp_res_x);
+ psmouse_dbg(psmouse, "cytp->tp_res_y = %d\n", cytp->tp_res_y);
+
+ psmouse_dbg(psmouse, "tp_type_APA = %d\n",
+ (param[6] & TP_METRICS_BIT_APA) ? 1 : 0);
+ psmouse_dbg(psmouse, "tp_type_MTG = %d\n",
+ (param[6] & TP_METRICS_BIT_MTG) ? 1 : 0);
+ psmouse_dbg(psmouse, "tp_palm = %d\n",
+ (param[6] & TP_METRICS_BIT_PALM) ? 1 : 0);
+ psmouse_dbg(psmouse, "tp_stubborn = %d\n",
+ (param[6] & TP_METRICS_BIT_STUBBORN) ? 1 : 0);
+ psmouse_dbg(psmouse, "tp_1f_jitter = %d\n",
+ (param[6] & TP_METRICS_BIT_1F_JITTER) >> 2);
+ psmouse_dbg(psmouse, "tp_2f_jitter = %d\n",
+ (param[6] & TP_METRICS_BIT_2F_JITTER) >> 4);
+ psmouse_dbg(psmouse, "tp_1f_spike = %d\n",
+ param[7] & TP_METRICS_BIT_1F_SPIKE);
+ psmouse_dbg(psmouse, "tp_2f_spike = %d\n",
+ (param[7] & TP_METRICS_BIT_2F_SPIKE) >> 2);
+ psmouse_dbg(psmouse, "tp_abs_packet_format_set = %d\n",
+ (param[7] & TP_METRICS_BIT_ABS_PKT_FORMAT_SET) >> 4);
+#endif
+
+ return 0;
+}
+
+static int cypress_query_hardware(struct psmouse *psmouse)
+{
+ struct cytp_data *cytp = psmouse->private;
+ int ret;
+
+ ret = cypress_read_fw_version(psmouse);
+ if (ret)
+ return ret;
+
+ if (cytp->tp_metrics_supported) {
+ ret = cypress_read_tp_metrics(psmouse);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cypress_set_absolute_mode(struct psmouse *psmouse)
+{
+ struct cytp_data *cytp = psmouse->private;
+ unsigned char param[3];
+
+ if (cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE, param) < 0)
+ return -1;
+
+ cytp->mode = (cytp->mode & ~CYTP_BIT_ABS_REL_MASK)
+ | CYTP_BIT_ABS_PRESSURE;
+ cypress_set_packet_size(psmouse, 5);
+
+ return 0;
+}
+
+/*
+ * Reset trackpad device.
+ * This is also the default mode when trackpad powered on.
+ */
+static void cypress_reset(struct psmouse *psmouse)
+{
+ struct cytp_data *cytp = psmouse->private;
+
+ cytp->mode = 0;
+
+ psmouse_reset(psmouse);
+}
+
+static int cypress_set_input_params(struct input_dev *input,
+ struct cytp_data *cytp)
+{
+ int ret;
+
+ if (!cytp->tp_res_x || !cytp->tp_res_y)
+ return -EINVAL;
+
+ __set_bit(EV_ABS, input->evbit);
+ input_set_abs_params(input, ABS_X, 0, cytp->tp_max_abs_x, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, cytp->tp_max_abs_y, 0, 0);
+ input_set_abs_params(input, ABS_PRESSURE,
+ cytp->tp_min_pressure, cytp->tp_max_pressure, 0, 0);
+ input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 255, 0, 0);
+
+ /* finger position */
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, cytp->tp_max_abs_x, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cytp->tp_max_abs_y, 0, 0);
+ input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
+
+ ret = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS,
+ INPUT_MT_DROP_UNUSED|INPUT_MT_TRACK);
+ if (ret < 0)
+ return ret;
+
+ __set_bit(INPUT_PROP_SEMI_MT, input->propbit);
+
+ input_abs_set_res(input, ABS_X, cytp->tp_res_x);
+ input_abs_set_res(input, ABS_Y, cytp->tp_res_y);
+
+ input_abs_set_res(input, ABS_MT_POSITION_X, cytp->tp_res_x);
+ input_abs_set_res(input, ABS_MT_POSITION_Y, cytp->tp_res_y);
+
+ __set_bit(BTN_TOUCH, input->keybit);
+ __set_bit(BTN_TOOL_FINGER, input->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
+ __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
+ __set_bit(BTN_TOOL_QUADTAP, input->keybit);
+ __set_bit(BTN_TOOL_QUINTTAP, input->keybit);
+
+ __clear_bit(EV_REL, input->evbit);
+ __clear_bit(REL_X, input->relbit);
+ __clear_bit(REL_Y, input->relbit);
+
+ __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(BTN_LEFT, input->keybit);
+ __set_bit(BTN_RIGHT, input->keybit);
+ __set_bit(BTN_MIDDLE, input->keybit);
+
+ input_set_drvdata(input, cytp);
+
+ return 0;
+}
+
+static int cypress_get_finger_count(unsigned char header_byte)
+{
+ unsigned char bits6_7;
+ int finger_count;
+
+ bits6_7 = header_byte >> 6;
+ finger_count = bits6_7 & 0x03;
+
+ if (finger_count == 1)
+ return 1;
+
+ if (header_byte & ABS_HSCROLL_BIT) {
+ /* HSCROLL gets added on to 0 finger count. */
+ switch (finger_count) {
+ case 0: return 4;
+ case 2: return 5;
+ default:
+ /* Invalid contact (e.g. palm). Ignore it. */
+ return -1;
+ }
+ }
+
+ return finger_count;
+}
+
+
+static int cypress_parse_packet(struct psmouse *psmouse,
+ struct cytp_data *cytp, struct cytp_report_data *report_data)
+{
+ unsigned char *packet = psmouse->packet;
+ unsigned char header_byte = packet[0];
+ int contact_cnt;
+
+ memset(report_data, 0, sizeof(struct cytp_report_data));
+
+ contact_cnt = cypress_get_finger_count(header_byte);
+
+ if (contact_cnt < 0) /* e.g. palm detect */
+ return -EINVAL;
+
+ report_data->contact_cnt = contact_cnt;
+
+ report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0;
+
+ if (report_data->contact_cnt == 1) {
+ report_data->contacts[0].x =
+ ((packet[1] & 0x70) << 4) | packet[2];
+ report_data->contacts[0].y =
+ ((packet[1] & 0x07) << 8) | packet[3];
+ if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
+ report_data->contacts[0].z = packet[4];
+
+ } else if (report_data->contact_cnt >= 2) {
+ report_data->contacts[0].x =
+ ((packet[1] & 0x70) << 4) | packet[2];
+ report_data->contacts[0].y =
+ ((packet[1] & 0x07) << 8) | packet[3];
+ if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
+ report_data->contacts[0].z = packet[4];
+
+ report_data->contacts[1].x =
+ ((packet[5] & 0xf0) << 4) | packet[6];
+ report_data->contacts[1].y =
+ ((packet[5] & 0x0f) << 8) | packet[7];
+ if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
+ report_data->contacts[1].z = report_data->contacts[0].z;
+ }
+
+ report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0;
+ report_data->right = (header_byte & BTN_RIGHT_BIT) ? 1 : 0;
+
+ /*
+ * This is only true if one of the mouse buttons were tapped. Make
+ * sure it doesn't turn into a click. The regular tap-to-click
+ * functionality will handle that on its own. If we don't do this,
+ * disabling tap-to-click won't affect the mouse button zones.
+ */
+ if (report_data->tap)
+ report_data->left = 0;
+
+#ifdef CYTP_DEBUG_VERBOSE
+ {
+ int i;
+ int n = report_data->contact_cnt;
+ psmouse_dbg(psmouse, "Dump parsed report data as below:\n");
+ psmouse_dbg(psmouse, "contact_cnt = %d\n",
+ report_data->contact_cnt);
+ if (n > CYTP_MAX_MT_SLOTS)
+ n = CYTP_MAX_MT_SLOTS;
+ for (i = 0; i < n; i++)
+ psmouse_dbg(psmouse, "contacts[%d] = {%d, %d, %d}\n", i,
+ report_data->contacts[i].x,
+ report_data->contacts[i].y,
+ report_data->contacts[i].z);
+ psmouse_dbg(psmouse, "left = %d\n", report_data->left);
+ psmouse_dbg(psmouse, "right = %d\n", report_data->right);
+ psmouse_dbg(psmouse, "middle = %d\n", report_data->middle);
+ }
+#endif
+
+ return 0;
+}
+
+static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
+{
+ int i;
+ struct input_dev *input = psmouse->dev;
+ struct cytp_data *cytp = psmouse->private;
+ struct cytp_report_data report_data;
+ struct cytp_contact *contact;
+ struct input_mt_pos pos[CYTP_MAX_MT_SLOTS];
+ int slots[CYTP_MAX_MT_SLOTS];
+ int n;
+
+ if (cypress_parse_packet(psmouse, cytp, &report_data))
+ return;
+
+ n = report_data.contact_cnt;
+
+ if (n > CYTP_MAX_MT_SLOTS)
+ n = CYTP_MAX_MT_SLOTS;
+
+ for (i = 0; i < n; i++) {
+ contact = &report_data.contacts[i];
+ pos[i].x = contact->x;
+ pos[i].y = contact->y;
+ }
+
+ input_mt_assign_slots(input, slots, pos, n);
+
+ for (i = 0; i < n; i++) {
+ contact = &report_data.contacts[i];
+ input_mt_slot(input, slots[i]);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+ input_report_abs(input, ABS_MT_POSITION_X, contact->x);
+ input_report_abs(input, ABS_MT_POSITION_Y, contact->y);
+ input_report_abs(input, ABS_MT_PRESSURE, contact->z);
+ }
+
+ input_mt_sync_frame(input);
+
+ input_mt_report_finger_count(input, report_data.contact_cnt);
+
+ input_report_key(input, BTN_LEFT, report_data.left);
+ input_report_key(input, BTN_RIGHT, report_data.right);
+ input_report_key(input, BTN_MIDDLE, report_data.middle);
+
+ input_sync(input);
+}
+
+static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)
+{
+ int contact_cnt;
+ int index = psmouse->pktcnt - 1;
+ unsigned char *packet = psmouse->packet;
+ struct cytp_data *cytp = psmouse->private;
+
+ if (index < 0 || index > cytp->pkt_size)
+ return PSMOUSE_BAD_DATA;
+
+ if (index == 0 && (packet[0] & 0xfc) == 0) {
+ /* call packet process for reporting finger leave. */
+ cypress_process_packet(psmouse, 1);
+ return PSMOUSE_FULL_PACKET;
+ }
+
+ /*
+ * Perform validation (and adjust packet size) based only on the
+ * first byte; allow all further bytes through.
+ */
+ if (index != 0)
+ return PSMOUSE_GOOD_DATA;
+
+ /*
+ * If absolute/relative mode bit has not been set yet, just pass
+ * the byte through.
+ */
+ if ((cytp->mode & CYTP_BIT_ABS_REL_MASK) == 0)
+ return PSMOUSE_GOOD_DATA;
+
+ if ((packet[0] & 0x08) == 0x08)
+ return PSMOUSE_BAD_DATA;
+
+ contact_cnt = cypress_get_finger_count(packet[0]);
+
+ if (contact_cnt < 0)
+ return PSMOUSE_BAD_DATA;
+
+ if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE)
+ cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4);
+ else
+ cypress_set_packet_size(psmouse, contact_cnt == 2 ? 8 : 5);
+
+ return PSMOUSE_GOOD_DATA;
+}
+
+static psmouse_ret_t cypress_protocol_handler(struct psmouse *psmouse)
+{
+ struct cytp_data *cytp = psmouse->private;
+
+ if (psmouse->pktcnt >= cytp->pkt_size) {
+ cypress_process_packet(psmouse, 0);
+ return PSMOUSE_FULL_PACKET;
+ }
+
+ return cypress_validate_byte(psmouse);
+}
+
+static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate)
+{
+ struct cytp_data *cytp = psmouse->private;
+
+ if (rate >= 80) {
+ psmouse->rate = 80;
+ cytp->mode |= CYTP_BIT_HIGH_RATE;
+ } else {
+ psmouse->rate = 40;
+ cytp->mode &= ~CYTP_BIT_HIGH_RATE;
+ }
+
+ ps2_command(&psmouse->ps2dev, (unsigned char *)&psmouse->rate,
+ PSMOUSE_CMD_SETRATE);
+}
+
+static void cypress_disconnect(struct psmouse *psmouse)
+{
+ cypress_reset(psmouse);
+ kfree(psmouse->private);
+ psmouse->private = NULL;
+}
+
+static int cypress_reconnect(struct psmouse *psmouse)
+{
+ int tries = CYTP_PS2_CMD_TRIES;
+ int rc;
+
+ do {
+ cypress_reset(psmouse);
+ rc = cypress_detect(psmouse, false);
+ } while (rc && (--tries > 0));
+
+ if (rc) {
+ psmouse_err(psmouse, "Reconnect: unable to detect trackpad.\n");
+ return -1;
+ }
+
+ if (cypress_set_absolute_mode(psmouse)) {
+ psmouse_err(psmouse, "Reconnect: Unable to initialize Cypress absolute mode.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int cypress_init(struct psmouse *psmouse)
+{
+ struct cytp_data *cytp;
+
+ cytp = (struct cytp_data *)kzalloc(sizeof(struct cytp_data), GFP_KERNEL);
+ psmouse->private = (void *)cytp;
+ if (cytp == NULL)
+ return -ENOMEM;
+
+ cypress_reset(psmouse);
+
+ psmouse->pktsize = 8;
+
+ if (cypress_query_hardware(psmouse)) {
+ psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");
+ goto err_exit;
+ }
+
+ if (cypress_set_absolute_mode(psmouse)) {
+ psmouse_err(psmouse, "init: Unable to initialize Cypress absolute mode.\n");
+ goto err_exit;
+ }
+
+ if (cypress_set_input_params(psmouse->dev, cytp) < 0) {
+ psmouse_err(psmouse, "init: Unable to set input params.\n");
+ goto err_exit;
+ }
+
+ psmouse->model = 1;
+ psmouse->protocol_handler = cypress_protocol_handler;
+ psmouse->set_rate = cypress_set_rate;
+ psmouse->disconnect = cypress_disconnect;
+ psmouse->reconnect = cypress_reconnect;
+ psmouse->cleanup = cypress_reset;
+ psmouse->resync_time = 0;
+
+ return 0;
+
+err_exit:
+ /*
+ * Reset Cypress Trackpad as a standard mouse. Then
+ * let psmouse driver commmunicating with it as default PS2 mouse.
+ */
+ cypress_reset(psmouse);
+
+ psmouse->private = NULL;
+ kfree(cytp);
+
+ return -1;
+}
+
+bool cypress_supported(void)
+{
+ return true;
+}
diff --git a/drivers/input/mouse/cypress_ps2.h b/drivers/input/mouse/cypress_ps2.h
new file mode 100644
index 000000000000..4720f21d2d70
--- /dev/null
+++ b/drivers/input/mouse/cypress_ps2.h
@@ -0,0 +1,191 @@
+#ifndef _CYPRESS_PS2_H
+#define _CYPRESS_PS2_H
+
+#include "psmouse.h"
+
+#define CMD_BITS_MASK 0x03
+#define COMPOSIT(x, s) (((x) & CMD_BITS_MASK) << (s))
+
+#define ENCODE_CMD(aa, bb, cc, dd) \
+ (COMPOSIT((aa), 6) | COMPOSIT((bb), 4) | COMPOSIT((cc), 2) | COMPOSIT((dd), 0))
+#define CYTP_CMD_ABS_NO_PRESSURE_MODE ENCODE_CMD(0, 1, 0, 0)
+#define CYTP_CMD_ABS_WITH_PRESSURE_MODE ENCODE_CMD(0, 1, 0, 1)
+#define CYTP_CMD_SMBUS_MODE ENCODE_CMD(0, 1, 1, 0)
+#define CYTP_CMD_STANDARD_MODE ENCODE_CMD(0, 2, 0, 0) /* not implemented yet. */
+#define CYTP_CMD_CYPRESS_REL_MODE ENCODE_CMD(1, 1, 1, 1) /* not implemented yet. */
+#define CYTP_CMD_READ_CYPRESS_ID ENCODE_CMD(0, 0, 0, 0)
+#define CYTP_CMD_READ_TP_METRICS ENCODE_CMD(0, 0, 0, 1)
+#define CYTP_CMD_SET_HSCROLL_WIDTH(w) ENCODE_CMD(1, 1, 0, (w))
+#define CYTP_CMD_SET_HSCROLL_MASK ENCODE_CMD(1, 1, 0, 0)
+#define CYTP_CMD_SET_VSCROLL_WIDTH(w) ENCODE_CMD(1, 2, 0, (w))
+#define CYTP_CMD_SET_VSCROLL_MASK ENCODE_CMD(1, 2, 0, 0)
+#define CYTP_CMD_SET_PALM_GEOMETRY(e) ENCODE_CMD(1, 2, 1, (e))
+#define CYTP_CMD_PALM_GEMMETRY_MASK ENCODE_CMD(1, 2, 1, 0)
+#define CYTP_CMD_SET_PALM_SENSITIVITY(s) ENCODE_CMD(1, 2, 2, (s))
+#define CYTP_CMD_PALM_SENSITIVITY_MASK ENCODE_CMD(1, 2, 2, 0)
+#define CYTP_CMD_SET_MOUSE_SENSITIVITY(s) ENCODE_CMD(1, 3, ((s) >> 2), (s))
+#define CYTP_CMD_MOUSE_SENSITIVITY_MASK ENCODE_CMD(1, 3, 0, 0)
+#define CYTP_CMD_REQUEST_BASELINE_STATUS ENCODE_CMD(2, 0, 0, 1)
+#define CYTP_CMD_REQUEST_RECALIBRATION ENCODE_CMD(2, 0, 0, 3)
+
+#define DECODE_CMD_AA(x) (((x) >> 6) & CMD_BITS_MASK)
+#define DECODE_CMD_BB(x) (((x) >> 4) & CMD_BITS_MASK)
+#define DECODE_CMD_CC(x) (((x) >> 2) & CMD_BITS_MASK)
+#define DECODE_CMD_DD(x) ((x) & CMD_BITS_MASK)
+
+/* Cypress trackpad working mode. */
+#define CYTP_BIT_ABS_PRESSURE (1 << 3)
+#define CYTP_BIT_ABS_NO_PRESSURE (1 << 2)
+#define CYTP_BIT_CYPRESS_REL (1 << 1)
+#define CYTP_BIT_STANDARD_REL (1 << 0)
+#define CYTP_BIT_REL_MASK (CYTP_BIT_CYPRESS_REL | CYTP_BIT_STANDARD_REL)
+#define CYTP_BIT_ABS_MASK (CYTP_BIT_ABS_PRESSURE | CYTP_BIT_ABS_NO_PRESSURE)
+#define CYTP_BIT_ABS_REL_MASK (CYTP_BIT_ABS_MASK | CYTP_BIT_REL_MASK)
+
+#define CYTP_BIT_HIGH_RATE (1 << 4)
+/*
+ * report mode bit is set, firmware working in Remote Mode.
+ * report mode bit is cleared, firmware working in Stream Mode.
+ */
+#define CYTP_BIT_REPORT_MODE (1 << 5)
+
+/* scrolling width values for set HSCROLL and VSCROLL width command. */
+#define SCROLL_WIDTH_NARROW 1
+#define SCROLL_WIDTH_NORMAL 2
+#define SCROLL_WIDTH_WIDE 3
+
+#define PALM_GEOMETRY_ENABLE 1
+#define PALM_GEOMETRY_DISABLE 0
+
+#define TP_METRICS_MASK 0x80
+#define FW_VERSION_MASX 0x7f
+#define FW_VER_HIGH_MASK 0x70
+#define FW_VER_LOW_MASK 0x0f
+
+/* Times to retry a ps2_command and millisecond delay between tries. */
+#define CYTP_PS2_CMD_TRIES 3
+#define CYTP_PS2_CMD_DELAY 500
+
+/* time out for PS/2 command only in milliseconds. */
+#define CYTP_CMD_TIMEOUT 200
+#define CYTP_DATA_TIMEOUT 30
+
+#define CYTP_EXT_CMD 0xe8
+#define CYTP_PS2_RETRY 0xfe
+#define CYTP_PS2_ERROR 0xfc
+
+#define CYTP_RESP_RETRY 0x01
+#define CYTP_RESP_ERROR 0xfe
+
+
+#define CYTP_105001_WIDTH 97 /* Dell XPS 13 */
+#define CYTP_105001_HIGH 59
+#define CYTP_DEFAULT_WIDTH (CYTP_105001_WIDTH)
+#define CYTP_DEFAULT_HIGH (CYTP_105001_HIGH)
+
+#define CYTP_ABS_MAX_X 1600
+#define CYTP_ABS_MAX_Y 900
+#define CYTP_MAX_PRESSURE 255
+#define CYTP_MIN_PRESSURE 0
+
+/* header byte bits of relative package. */
+#define BTN_LEFT_BIT 0x01
+#define BTN_RIGHT_BIT 0x02
+#define BTN_MIDDLE_BIT 0x04
+#define REL_X_SIGN_BIT 0x10
+#define REL_Y_SIGN_BIT 0x20
+
+/* header byte bits of absolute package. */
+#define ABS_VSCROLL_BIT 0x10
+#define ABS_HSCROLL_BIT 0x20
+#define ABS_MULTIFINGER_TAP 0x04
+#define ABS_EDGE_MOTION_MASK 0x80
+
+#define DFLT_RESP_BITS_VALID 0x88 /* SMBus bit should not be set. */
+#define DFLT_RESP_SMBUS_BIT 0x80
+#define DFLT_SMBUS_MODE 0x80
+#define DFLT_PS2_MODE 0x00
+#define DFLT_RESP_BIT_MODE 0x40
+#define DFLT_RESP_REMOTE_MODE 0x40
+#define DFLT_RESP_STREAM_MODE 0x00
+#define DFLT_RESP_BIT_REPORTING 0x20
+#define DFLT_RESP_BIT_SCALING 0x10
+
+#define TP_METRICS_BIT_PALM 0x80
+#define TP_METRICS_BIT_STUBBORN 0x40
+#define TP_METRICS_BIT_2F_JITTER 0x30
+#define TP_METRICS_BIT_1F_JITTER 0x0c
+#define TP_METRICS_BIT_APA 0x02
+#define TP_METRICS_BIT_MTG 0x01
+#define TP_METRICS_BIT_ABS_PKT_FORMAT_SET 0xf0
+#define TP_METRICS_BIT_2F_SPIKE 0x0c
+#define TP_METRICS_BIT_1F_SPIKE 0x03
+
+/* bits of first byte response of E9h-Status Request command. */
+#define RESP_BTN_RIGHT_BIT 0x01
+#define RESP_BTN_MIDDLE_BIT 0x02
+#define RESP_BTN_LEFT_BIT 0x04
+#define RESP_SCALING_BIT 0x10
+#define RESP_ENABLE_BIT 0x20
+#define RESP_REMOTE_BIT 0x40
+#define RESP_SMBUS_BIT 0x80
+
+#define CYTP_MAX_MT_SLOTS 2
+
+struct cytp_contact {
+ int x;
+ int y;
+ int z; /* also named as touch pressure. */
+};
+
+/* The structure of Cypress Trackpad event data. */
+struct cytp_report_data {
+ int contact_cnt;
+ struct cytp_contact contacts[CYTP_MAX_MT_SLOTS];
+ unsigned int left:1;
+ unsigned int right:1;
+ unsigned int middle:1;
+ unsigned int tap:1; /* multi-finger tap detected. */
+};
+
+/* The structure of Cypress Trackpad device private data. */
+struct cytp_data {
+ int fw_version;
+
+ int pkt_size;
+ int mode;
+
+ int tp_min_pressure;
+ int tp_max_pressure;
+ int tp_width; /* X direction physical size in mm. */
+ int tp_high; /* Y direction physical size in mm. */
+ int tp_max_abs_x; /* Max X absolute units that can be reported. */
+ int tp_max_abs_y; /* Max Y absolute units that can be reported. */
+
+ int tp_res_x; /* X resolution in units/mm. */
+ int tp_res_y; /* Y resolution in units/mm. */
+
+ int tp_metrics_supported;
+};
+
+
+#ifdef CONFIG_MOUSE_PS2_CYPRESS
+int cypress_detect(struct psmouse *psmouse, bool set_properties);
+int cypress_init(struct psmouse *psmouse);
+bool cypress_supported(void);
+#else
+inline int cypress_detect(struct psmouse *psmouse, bool set_properties)
+{
+ return -ENOSYS;
+}
+inline int cypress_init(struct psmouse *psmouse)
+{
+ return -ENOSYS;
+}
+inline bool cypress_supported(void)
+{
+ return 0;
+}
+#endif /* CONFIG_MOUSE_PS2_CYPRESS */
+
+#endif /* _CYPRESS_PS2_H */
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 22fe2547e169..cff065f6261c 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -34,6 +34,7 @@
#include "touchkit_ps2.h"
#include "elantech.h"
#include "sentelic.h"
+#include "cypress_ps2.h"
#define DRIVER_DESC "PS/2 mouse driver"
@@ -759,6 +760,28 @@ static int psmouse_extensions(struct psmouse *psmouse,
}
/*
+ * Try Cypress Trackpad.
+ * Must try it before Finger Sensing Pad because Finger Sensing Pad probe
+ * upsets some modules of Cypress Trackpads.
+ */
+ if (max_proto > PSMOUSE_IMEX &&
+ cypress_detect(psmouse, set_properties) == 0) {
+ if (cypress_supported()) {
+ if (cypress_init(psmouse) == 0)
+ return PSMOUSE_CYPRESS;
+
+ /*
+ * Finger Sensing Pad probe upsets some modules of
+ * Cypress Trackpad, must avoid Finger Sensing Pad
+ * probe if Cypress Trackpad device detected.
+ */
+ return PSMOUSE_PS2;
+ }
+
+ max_proto = PSMOUSE_IMEX;
+ }
+
+/*
* Try ALPS TouchPad
*/
if (max_proto > PSMOUSE_IMEX) {
@@ -896,6 +919,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.alias = "thinkps",
.detect = thinking_detect,
},
+#ifdef CONFIG_MOUSE_PS2_CYPRESS
+ {
+ .type = PSMOUSE_CYPRESS,
+ .name = "CyPS/2",
+ .alias = "cypress",
+ .detect = cypress_detect,
+ .init = cypress_init,
+ },
+#endif
{
.type = PSMOUSE_GENPS,
.name = "GenPS/2",
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index fe1df231ba4c..2f0b39d59a9b 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -95,6 +95,7 @@ enum psmouse_type {
PSMOUSE_ELANTECH,
PSMOUSE_FSP,
PSMOUSE_SYNAPTICS_RELATIVE,
+ PSMOUSE_CYPRESS,
PSMOUSE_AUTO /* This one should always be last */
};
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 12d12ca3fee0..2f78538e09d0 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -722,11 +722,13 @@ static void synaptics_report_mt_data(struct psmouse *psmouse,
default:
/*
* If the finger slot contained in SGM is valid, and either
- * hasn't changed, or is new, then report SGM in MTB slot 0.
+ * hasn't changed, or is new, or the old SGM has now moved to
+ * AGM, then report SGM in MTB slot 0.
* Otherwise, empty MTB slot 0.
*/
if (mt_state->sgm != -1 &&
- (mt_state->sgm == old->sgm || old->sgm == -1))
+ (mt_state->sgm == old->sgm ||
+ old->sgm == -1 || mt_state->agm == old->sgm))
synaptics_report_slot(dev, 0, sgm);
else
synaptics_report_slot(dev, 0, NULL);
@@ -735,9 +737,31 @@ static void synaptics_report_mt_data(struct psmouse *psmouse,
* If the finger slot contained in AGM is valid, and either
* hasn't changed, or is new, then report AGM in MTB slot 1.
* Otherwise, empty MTB slot 1.
+ *
+ * However, in the case where the AGM is new, make sure that
+ * that it is either the same as the old SGM, or there was no
+ * SGM.
+ *
+ * Otherwise, if the SGM was just 1, and the new AGM is 2, then
+ * the new AGM will keep the old SGM's tracking ID, which can
+ * cause apparent drumroll. This happens if in the following
+ * valid finger sequence:
+ *
+ * Action SGM AGM (MTB slot:Contact)
+ * 1. Touch contact 0 (0:0)
+ * 2. Touch contact 1 (0:0, 1:1)
+ * 3. Lift contact 0 (1:1)
+ * 4. Touch contacts 2,3 (0:2, 1:3)
+ *
+ * In step 4, contact 3, in AGM must not be given the same
+ * tracking ID as contact 1 had in step 3. To avoid this,
+ * the first agm with contact 3 is dropped and slot 1 is
+ * invalidated (tracking ID = -1).
*/
if (mt_state->agm != -1 &&
- (mt_state->agm == old->agm || old->agm == -1))
+ (mt_state->agm == old->agm ||
+ (old->agm == -1 &&
+ (old->sgm == -1 || mt_state->agm == old->sgm))))
synaptics_report_slot(dev, 1, agm);
else
synaptics_report_slot(dev, 1, NULL);
@@ -1247,11 +1271,11 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
- input_mt_init_slots(dev, 2, 0);
set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
ABS_MT_POSITION_Y);
/* Image sensors can report per-contact pressure */
input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
+ input_mt_init_slots(dev, 2, INPUT_MT_POINTER);
/* Image sensors can signal 4 and 5 finger clicks */
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 4a4e182c33e7..6e9cc765e0dc 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -36,6 +36,7 @@ config SERIO_I8042
config SERIO_SERPORT
tristate "Serial port line discipline"
default y
+ depends on TTY
help
Say Y here if you plan to use an input device (mouse, joystick,
tablet, 6dof) that communicates over the RS232 serial (COM) port.
@@ -236,6 +237,7 @@ config SERIO_PS2MULT
config SERIO_ARC_PS2
tristate "ARC PS/2 support"
+ depends on GENERIC_HARDIRQS
help
Say Y here if you have an ARC FPGA platform with a PS/2
controller in it.
diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c
index b571eb3e4efc..c52e3e589f72 100644
--- a/drivers/input/serio/arc_ps2.c
+++ b/drivers/input/serio/arc_ps2.c
@@ -8,6 +8,7 @@
* Driver is originally developed by Pavel Sokolov <psokolov@synopsys.com>
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/input.h>
@@ -206,9 +207,9 @@ static int arc_ps2_probe(struct platform_device *pdev)
return -ENOMEM;
}
- arc_ps2->addr = devm_request_and_ioremap(&pdev->dev, res);
- if (!arc_ps2->addr)
- return -EBUSY;
+ arc_ps2->addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(arc_ps2->addr))
+ return PTR_ERR(arc_ps2->addr);
dev_info(&pdev->dev, "irq = %d, address = 0x%p, ports = %i\n",
irq, arc_ps2->addr, ARC_PS2_PORTS);
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index f92d34f45a1c..aaf23aeae2ea 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -553,10 +553,10 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int
if (!rep_data)
return error;
- rep_data[0] = report_id;
- rep_data[1] = mode;
-
do {
+ rep_data[0] = report_id;
+ rep_data[1] = mode;
+
error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
report_id, rep_data, length, 1);
if (error >= 0)
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 264138f3217e..41b6fbf60112 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -359,6 +359,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
case 0x802: /* Intuos4 General Pen */
case 0x804: /* Intuos4 Marker Pen */
case 0x40802: /* Intuos4 Classic Pen */
+ case 0x18803: /* DTH2242 Grip Pen */
case 0x022:
wacom->tool[idx] = BTN_TOOL_PEN;
break;
@@ -538,6 +539,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
input_report_key(input, wacom->tool[1], 0);
input_report_abs(input, ABS_MISC, 0);
}
+ } else if (features->type == DTK) {
+ input_report_key(input, BTN_0, (data[6] & 0x01));
+ input_report_key(input, BTN_1, (data[6] & 0x02));
+ input_report_key(input, BTN_2, (data[6] & 0x04));
+ input_report_key(input, BTN_3, (data[6] & 0x08));
+ input_report_key(input, BTN_4, (data[6] & 0x10));
+ input_report_key(input, BTN_5, (data[6] & 0x20));
} else if (features->type == WACOM_24HD) {
input_report_key(input, BTN_0, (data[6] & 0x01));
input_report_key(input, BTN_1, (data[6] & 0x02));
@@ -785,25 +793,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
return 1;
}
-static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid)
-{
- int touch_max = wacom->features.touch_max;
- int i;
-
- if (!wacom->slots)
- return -1;
-
- for (i = 0; i < touch_max; ++i) {
- if (wacom->slots[i] == contactid)
- return i;
- }
- for (i = 0; i < touch_max; ++i) {
- if (wacom->slots[i] == -1)
- return i;
- }
- return -1;
-}
-
static int int_dist(int x1, int y1, int x2, int y2)
{
int x = x2 - x1;
@@ -833,8 +822,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
for (i = 0; i < contacts_to_send; i++) {
int offset = (WACOM_BYTES_PER_24HDT_PACKET * i) + 1;
bool touch = data[offset] & 0x1 && !wacom->shared->stylus_in_proximity;
- int id = data[offset + 1];
- int slot = find_slot_from_contactid(wacom, id);
+ int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
if (slot < 0)
continue;
@@ -856,9 +844,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
input_report_abs(input, ABS_MT_ORIENTATION, w > h);
}
- wacom->slots[slot] = touch ? id : -1;
}
-
input_mt_report_pointer_emulation(input, true);
wacom->num_contacts_left -= contacts_to_send;
@@ -895,7 +881,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
bool touch = data[offset] & 0x1;
int id = le16_to_cpup((__le16 *)&data[offset + 1]);
- int slot = find_slot_from_contactid(wacom, id);
+ int slot = input_mt_get_slot_by_key(input, id);
if (slot < 0)
continue;
@@ -908,9 +894,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
}
- wacom->slots[slot] = touch ? id : -1;
}
-
input_mt_report_pointer_emulation(input, true);
wacom->num_contacts_left -= contacts_to_send;
@@ -942,12 +926,11 @@ static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
contact_with_no_pen_down_count++;
}
}
+ input_mt_report_pointer_emulation(input, true);
/* keep touch state for pen event */
wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
- input_mt_report_pointer_emulation(input, true);
-
return 1;
}
@@ -1104,12 +1087,15 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
{
struct input_dev *input = wacom->input;
- int slot_id = data[0] - 2; /* data[0] is between 2 and 17 */
bool touch = data[1] & 0x80;
+ int slot = input_mt_get_slot_by_key(input, data[0]);
+
+ if (slot < 0)
+ return;
touch = touch && !wacom->shared->stylus_in_proximity;
- input_mt_slot(input, slot_id);
+ input_mt_slot(input, slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
if (touch) {
@@ -1162,7 +1148,6 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
wacom_bpt3_button_msg(wacom, data + offset);
}
-
input_mt_report_pointer_emulation(input, true);
input_sync(input);
@@ -1319,6 +1304,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
case WACOM_21UX2:
case WACOM_22HD:
case WACOM_24HD:
+ case DTK:
sync = wacom_intuos_irq(wacom_wac);
break;
@@ -1444,39 +1430,64 @@ static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
return (logical_max * 100) / physical_max;
}
-int wacom_setup_input_capabilities(struct input_dev *input_dev,
- struct wacom_wac *wacom_wac)
+static void wacom_abs_set_axis(struct input_dev *input_dev,
+ struct wacom_wac *wacom_wac)
{
struct wacom_features *features = &wacom_wac->features;
- int i;
-
- input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-
- __set_bit(BTN_TOUCH, input_dev->keybit);
-
- input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
- features->x_fuzz, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
- features->y_fuzz, 0);
if (features->device_type == BTN_TOOL_PEN) {
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
- features->pressure_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
+ features->x_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
+ features->y_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0,
+ features->pressure_max, features->pressure_fuzz, 0);
/* penabled devices have fixed resolution for each model */
input_abs_set_res(input_dev, ABS_X, features->x_resolution);
input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
} else {
- input_abs_set_res(input_dev, ABS_X,
- wacom_calculate_touch_res(features->x_max,
- features->x_phy));
- input_abs_set_res(input_dev, ABS_Y,
- wacom_calculate_touch_res(features->y_max,
- features->y_phy));
+ if (features->touch_max <= 2) {
+ input_set_abs_params(input_dev, ABS_X, 0,
+ features->x_max, features->x_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0,
+ features->y_max, features->y_fuzz, 0);
+ input_abs_set_res(input_dev, ABS_X,
+ wacom_calculate_touch_res(features->x_max,
+ features->x_phy));
+ input_abs_set_res(input_dev, ABS_Y,
+ wacom_calculate_touch_res(features->y_max,
+ features->y_phy));
+ }
+
+ if (features->touch_max > 1) {
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+ features->x_max, features->x_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+ features->y_max, features->y_fuzz, 0);
+ input_abs_set_res(input_dev, ABS_MT_POSITION_X,
+ wacom_calculate_touch_res(features->x_max,
+ features->x_phy));
+ input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
+ wacom_calculate_touch_res(features->y_max,
+ features->y_phy));
+ }
}
+}
+int wacom_setup_input_capabilities(struct input_dev *input_dev,
+ struct wacom_wac *wacom_wac)
+{
+ struct wacom_features *features = &wacom_wac->features;
+ int i;
+
+ input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+
+ __set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(ABS_MISC, input_dev->absbit);
+ wacom_abs_set_axis(input_dev, wacom_wac);
+
switch (wacom_wac->features.type) {
case WACOM_MO:
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
@@ -1513,12 +1524,17 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_Y, input_dev->keybit);
__set_bit(BTN_Z, input_dev->keybit);
- for (i = 0; i < 10; i++)
+ for (i = 6; i < 10; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
__set_bit(KEY_PROG1, input_dev->keybit);
__set_bit(KEY_PROG2, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit);
+ /* fall through */
+
+ case DTK:
+ for (i = 0; i < 6; i++)
+ __set_bit(BTN_0 + i, input_dev->keybit);
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
@@ -1614,24 +1630,11 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
} else if (features->device_type == BTN_TOOL_FINGER) {
__clear_bit(ABS_MISC, input_dev->absbit);
- __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
- __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
- __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
- __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
-
- input_mt_init_slots(input_dev, features->touch_max, 0);
-
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, features->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
0, features->y_max, 0, 0);
-
- input_set_abs_params(input_dev, ABS_MT_POSITION_X,
- 0, features->x_max,
- features->x_fuzz, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
- 0, features->y_max,
- features->y_fuzz, 0);
+ input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
}
break;
@@ -1662,27 +1665,14 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
case MTSCREEN:
case MTTPC:
- if (features->device_type == BTN_TOOL_FINGER) {
- wacom_wac->slots = kmalloc(features->touch_max *
- sizeof(int),
- GFP_KERNEL);
- if (!wacom_wac->slots)
- return -ENOMEM;
-
- for (i = 0; i < features->touch_max; i++)
- wacom_wac->slots[i] = -1;
- }
- /* fall through */
-
case TABLETPC2FG:
if (features->device_type == BTN_TOOL_FINGER) {
- input_mt_init_slots(input_dev, features->touch_max, 0);
- input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
- 0, MT_TOOL_MAX, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_X,
- 0, features->x_max, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
- 0, features->y_max, 0, 0);
+ unsigned int flags = INPUT_MT_DIRECT;
+
+ if (wacom_wac->features.type == TABLETPC2FG)
+ flags = 0;
+
+ input_mt_init_slots(input_dev, features->touch_max, flags);
}
/* fall through */
@@ -1725,35 +1715,26 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
if (features->device_type == BTN_TOOL_FINGER) {
+ unsigned int flags = INPUT_MT_POINTER;
+
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
__set_bit(BTN_BACK, input_dev->keybit);
__set_bit(BTN_RIGHT, input_dev->keybit);
- __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
- __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
- input_mt_init_slots(input_dev, features->touch_max, 0);
-
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
- __set_bit(BTN_TOOL_TRIPLETAP,
- input_dev->keybit);
- __set_bit(BTN_TOOL_QUADTAP,
- input_dev->keybit);
-
input_set_abs_params(input_dev,
ABS_MT_TOUCH_MAJOR,
0, features->x_max, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_TOUCH_MINOR,
0, features->y_max, 0, 0);
+ } else {
+ __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+ flags = 0;
}
-
- input_set_abs_params(input_dev, ABS_MT_POSITION_X,
- 0, features->x_max,
- features->x_fuzz, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
- 0, features->y_max,
- features->y_fuzz, 0);
+ input_mt_init_slots(input_dev, features->touch_max, flags);
} else if (features->device_type == BTN_TOOL_PEN) {
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
@@ -1978,6 +1959,13 @@ static const struct wacom_features wacom_features_0xCE =
static const struct wacom_features wacom_features_0xF0 =
{ "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511,
0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x59 = /* Pen */
+ { "Wacom DTH2242", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
+ 63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
+static const struct wacom_features wacom_features_0x5D = /* Touch */
+ { "Wacom DTH2242", .type = WACOM_24HDT,
+ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10 };
static const struct wacom_features wacom_features_0xCC =
{ "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047,
63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
@@ -2152,6 +2140,8 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x43) },
{ USB_DEVICE_WACOM(0x44) },
{ USB_DEVICE_WACOM(0x45) },
+ { USB_DEVICE_WACOM(0x59) },
+ { USB_DEVICE_WACOM(0x5D) },
{ USB_DEVICE_WACOM(0xB0) },
{ USB_DEVICE_WACOM(0xB1) },
{ USB_DEVICE_WACOM(0xB2) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 9396d7769f86..5f9a7721e16c 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -78,6 +78,7 @@ enum {
INTUOS5L,
WACOM_21UX2,
WACOM_22HD,
+ DTK,
WACOM_24HD,
CINTIQ,
WACOM_BEE,
@@ -135,7 +136,6 @@ struct wacom_wac {
int pid;
int battery_capacity;
int num_contacts_left;
- int *slots;
};
#endif
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 515cfe790543..f9a5fd89bc02 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -359,7 +359,7 @@ config TOUCHSCREEN_MCS5000
config TOUCHSCREEN_MMS114
tristate "MELFAS MMS114 touchscreen"
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
help
Say Y here if you have the MELFAS MMS114 touchscreen controller
chip in your system.
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
index 638e20310f12..861b7f77605b 100644
--- a/drivers/input/touchscreen/cyttsp_spi.c
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -193,7 +193,6 @@ static struct spi_driver cyttsp_spi_driver = {
module_spi_driver(cyttsp_spi_driver);
-MODULE_ALIAS("spi:cyttsp");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c
index 98841d8aa635..4a29ddf6bf1e 100644
--- a/drivers/input/touchscreen/mms114.c
+++ b/drivers/input/touchscreen/mms114.c
@@ -429,12 +429,12 @@ static int mms114_probe(struct i2c_client *client,
return -ENODEV;
}
- data = kzalloc(sizeof(struct mms114_data), GFP_KERNEL);
- input_dev = input_allocate_device();
+ data = devm_kzalloc(&client->dev, sizeof(struct mms114_data),
+ GFP_KERNEL);
+ input_dev = devm_input_allocate_device(&client->dev);
if (!data || !input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
- error = -ENOMEM;
- goto err_free_mem;
+ return -ENOMEM;
}
data->client = client;
@@ -466,57 +466,36 @@ static int mms114_probe(struct i2c_client *client,
input_set_drvdata(input_dev, data);
i2c_set_clientdata(client, data);
- data->core_reg = regulator_get(&client->dev, "avdd");
+ data->core_reg = devm_regulator_get(&client->dev, "avdd");
if (IS_ERR(data->core_reg)) {
error = PTR_ERR(data->core_reg);
dev_err(&client->dev,
"Unable to get the Core regulator (%d)\n", error);
- goto err_free_mem;
+ return error;
}
- data->io_reg = regulator_get(&client->dev, "vdd");
+ data->io_reg = devm_regulator_get(&client->dev, "vdd");
if (IS_ERR(data->io_reg)) {
error = PTR_ERR(data->io_reg);
dev_err(&client->dev,
"Unable to get the IO regulator (%d)\n", error);
- goto err_core_reg;
+ return error;
}
- error = request_threaded_irq(client->irq, NULL, mms114_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mms114", data);
+ error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ mms114_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(&client->dev), data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
- goto err_io_reg;
+ return error;
}
disable_irq(client->irq);
error = input_register_device(data->input_dev);
- if (error)
- goto err_free_irq;
-
- return 0;
-
-err_free_irq:
- free_irq(client->irq, data);
-err_io_reg:
- regulator_put(data->io_reg);
-err_core_reg:
- regulator_put(data->core_reg);
-err_free_mem:
- input_free_device(input_dev);
- kfree(data);
- return error;
-}
-
-static int mms114_remove(struct i2c_client *client)
-{
- struct mms114_data *data = i2c_get_clientdata(client);
-
- free_irq(client->irq, data);
- regulator_put(data->io_reg);
- regulator_put(data->core_reg);
- input_unregister_device(data->input_dev);
- kfree(data);
+ if (error) {
+ dev_err(&client->dev, "Failed to register input device\n");
+ return error;
+ }
return 0;
}
@@ -590,7 +569,6 @@ static struct i2c_driver mms114_driver = {
.of_match_table = of_match_ptr(mms114_dt_match),
},
.probe = mms114_probe,
- .remove = mms114_remove,
.id_table = mms114_id,
};
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index 84d884b4ec3e..59e81b00f244 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -120,6 +120,7 @@ static void stmpe_work(struct work_struct *work)
__stmpe_reset_fifo(ts->stmpe);
input_report_abs(ts->idev, ABS_PRESSURE, 0);
+ input_report_key(ts->idev, BTN_TOUCH, 0);
input_sync(ts->idev);
}
@@ -153,6 +154,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data)
input_report_abs(ts->idev, ABS_X, x);
input_report_abs(ts->idev, ABS_Y, y);
input_report_abs(ts->idev, ABS_PRESSURE, z);
+ input_report_key(ts->idev, BTN_TOUCH, 1);
input_sync(ts->idev);
/* flush the FIFO after we have read out our values. */
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index 9c0cdc7ea449..7213e8b07e79 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -753,3 +753,4 @@ module_spi_driver(tsc2005_driver);
MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
MODULE_DESCRIPTION("TSC2005 Touchscreen Driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:tsc2005");
diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
index f88fab56178c..6be2eb6a153a 100644
--- a/drivers/input/touchscreen/wm831x-ts.c
+++ b/drivers/input/touchscreen/wm831x-ts.c
@@ -247,7 +247,7 @@ static int wm831x_ts_probe(struct platform_device *pdev)
wm831x_ts = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ts),
GFP_KERNEL);
- input_dev = input_allocate_device();
+ input_dev = devm_input_allocate_device(&pdev->dev);
if (!wm831x_ts || !input_dev) {
error = -ENOMEM;
goto err_alloc;
@@ -376,7 +376,6 @@ err_pd_irq:
err_data_irq:
free_irq(wm831x_ts->data_irq, wm831x_ts);
err_alloc:
- input_free_device(input_dev);
return error;
}
@@ -387,7 +386,6 @@ static int wm831x_ts_remove(struct platform_device *pdev)
free_irq(wm831x_ts->pd_irq, wm831x_ts);
free_irq(wm831x_ts->data_irq, wm831x_ts);
- input_unregister_device(wm831x_ts->input_dev);
return 0;
}
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index e39f9dbf297b..01068987809d 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -65,8 +65,8 @@ config AMD_IOMMU_STATS
If unsure, say N.
config AMD_IOMMU_V2
- tristate "AMD IOMMU Version 2 driver (EXPERIMENTAL)"
- depends on AMD_IOMMU && PROFILING && EXPERIMENTAL
+ tristate "AMD IOMMU Version 2 driver"
+ depends on AMD_IOMMU && PROFILING
select MMU_NOTIFIER
---help---
This option enables support for the AMD IOMMUv2 features of the IOMMU
@@ -119,8 +119,8 @@ config INTEL_IOMMU_FLOPPY_WA
16MiB to make floppy (an ISA device) work.
config IRQ_REMAP
- bool "Support for Interrupt Remapping (EXPERIMENTAL)"
- depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL
+ bool "Support for Interrupt Remapping"
+ depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI
select DMAR_TABLE
---help---
Supports Interrupt remapping for IO-APIC and MSI devices.
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index c1c74e030a58..d33eaaf783ad 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -4017,10 +4017,10 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count)
index -= count - 1;
+ cfg->remapped = 1;
irte_info = &cfg->irq_2_iommu;
irte_info->sub_handle = devid;
irte_info->irte_index = index;
- irte_info->iommu = (void *)cfg;
goto out;
}
@@ -4127,9 +4127,9 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
index = attr->ioapic_pin;
/* Setup IRQ remapping info */
+ cfg->remapped = 1;
irte_info->sub_handle = devid;
irte_info->irte_index = index;
- irte_info->iommu = (void *)cfg;
/* Setup IRTE for IOMMU */
irte.val = 0;
@@ -4288,9 +4288,9 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
devid = get_device_id(&pdev->dev);
irte_info = &cfg->irq_2_iommu;
+ cfg->remapped = 1;
irte_info->sub_handle = devid;
irte_info->irte_index = index + offset;
- irte_info->iommu = (void *)cfg;
return 0;
}
@@ -4314,9 +4314,9 @@ static int setup_hpet_msi(unsigned int irq, unsigned int id)
if (index < 0)
return index;
+ cfg->remapped = 1;
irte_info->sub_handle = devid;
irte_info->irte_index = index;
- irte_info->iommu = (void *)cfg;
return 0;
}
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 86e2f4a62b9a..174bb654453d 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -41,6 +41,8 @@
#include <asm/irq_remapping.h>
#include <asm/iommu_table.h>
+#include "irq_remapping.h"
+
/* No locks are needed as DMA remapping hardware unit
* list is constructed at boot time and hotplug of
* these units are not supported by the architecture.
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index f1e7b86a7c37..0099667a397e 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -46,6 +46,8 @@
#include <asm/cacheflush.h>
#include <asm/iommu.h>
+#include "irq_remapping.h"
+
#define ROOT_SIZE VTD_PAGE_SIZE
#define CONTEXT_SIZE VTD_PAGE_SIZE
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index af8904de1d44..f3b8f23b5d8f 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -68,6 +68,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
{
struct ir_table *table = iommu->ir_table;
struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
+ struct irq_cfg *cfg = irq_get_chip_data(irq);
u16 index, start_index;
unsigned int mask = 0;
unsigned long flags;
@@ -115,6 +116,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
for (i = index; i < index + count; i++)
table->base[i].present = 1;
+ cfg->remapped = 1;
irq_iommu->iommu = iommu;
irq_iommu->irte_index = index;
irq_iommu->sub_handle = 0;
@@ -155,6 +157,7 @@ static int map_irq_to_irte_handle(int irq, u16 *sub_handle)
static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
{
struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
+ struct irq_cfg *cfg = irq_get_chip_data(irq);
unsigned long flags;
if (!irq_iommu)
@@ -162,6 +165,7 @@ static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subha
raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
+ cfg->remapped = 1;
irq_iommu->iommu = iommu;
irq_iommu->irte_index = index;
irq_iommu->sub_handle = subhandle;
@@ -425,11 +429,22 @@ static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode)
/* Enable interrupt-remapping */
iommu->gcmd |= DMA_GCMD_IRE;
+ iommu->gcmd &= ~DMA_GCMD_CFI; /* Block compatibility-format MSIs */
writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
readl, (sts & DMA_GSTS_IRES), sts);
+ /*
+ * With CFI clear in the Global Command register, we should be
+ * protected from dangerous (i.e. compatibility) interrupts
+ * regardless of x2apic status. Check just to be sure.
+ */
+ if (sts & DMA_GSTS_CFIS)
+ WARN(1, KERN_WARNING
+ "Compatibility-format IRQs enabled despite intr remapping;\n"
+ "you are vulnerable to IRQ injection.\n");
+
raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
}
@@ -526,20 +541,24 @@ static int __init intel_irq_remapping_supported(void)
static int __init intel_enable_irq_remapping(void)
{
struct dmar_drhd_unit *drhd;
+ bool x2apic_present;
int setup = 0;
int eim = 0;
+ x2apic_present = x2apic_supported();
+
if (parse_ioapics_under_ir() != 1) {
printk(KERN_INFO "Not enable interrupt remapping\n");
- return -1;
+ goto error;
}
- if (x2apic_supported()) {
+ if (x2apic_present) {
eim = !dmar_x2apic_optout();
- WARN(!eim, KERN_WARNING
- "Your BIOS is broken and requested that x2apic be disabled\n"
- "This will leave your machine vulnerable to irq-injection attacks\n"
- "Use 'intremap=no_x2apic_optout' to override BIOS request\n");
+ if (!eim)
+ printk(KERN_WARNING
+ "Your BIOS is broken and requested that x2apic be disabled.\n"
+ "This will slightly decrease performance.\n"
+ "Use 'intremap=no_x2apic_optout' to override BIOS request.\n");
}
for_each_drhd_unit(drhd) {
@@ -578,7 +597,7 @@ static int __init intel_enable_irq_remapping(void)
if (eim && !ecap_eim_support(iommu->ecap)) {
printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
" ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
- return -1;
+ goto error;
}
}
@@ -594,7 +613,7 @@ static int __init intel_enable_irq_remapping(void)
printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
" invalidation, ecap %Lx, ret %d\n",
drhd->reg_base_addr, iommu->ecap, ret);
- return -1;
+ goto error;
}
}
@@ -617,6 +636,14 @@ static int __init intel_enable_irq_remapping(void)
goto error;
irq_remapping_enabled = 1;
+
+ /*
+ * VT-d has a different layout for IO-APIC entries when
+ * interrupt remapping is enabled. So it needs a special routine
+ * to print IO-APIC entries for debugging purposes too.
+ */
+ x86_io_apic_ops.print_entries = intel_ir_io_apic_print_entries;
+
pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");
return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
@@ -625,6 +652,11 @@ error:
/*
* handle error condition gracefully here!
*/
+
+ if (x2apic_present)
+ WARN(1, KERN_WARNING
+ "Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n");
+
return -1;
}
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index faf85d6e33fe..d56f8c17c5fe 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -1,11 +1,18 @@
+#include <linux/seq_file.h>
+#include <linux/cpumask.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/cpumask.h>
#include <linux/errno.h>
#include <linux/msi.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
#include <asm/hw_irq.h>
#include <asm/irq_remapping.h>
+#include <asm/processor.h>
+#include <asm/x86_init.h>
+#include <asm/apic.h>
#include "irq_remapping.h"
@@ -17,6 +24,152 @@ int no_x2apic_optout;
static struct irq_remap_ops *remap_ops;
+static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
+static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
+ int index, int sub_handle);
+static int set_remapped_irq_affinity(struct irq_data *data,
+ const struct cpumask *mask,
+ bool force);
+
+static bool irq_remapped(struct irq_cfg *cfg)
+{
+ return (cfg->remapped == 1);
+}
+
+static void irq_remapping_disable_io_apic(void)
+{
+ /*
+ * With interrupt-remapping, for now we will use virtual wire A
+ * mode, as virtual wire B is little complex (need to configure
+ * both IOAPIC RTE as well as interrupt-remapping table entry).
+ * As this gets called during crash dump, keep this simple for
+ * now.
+ */
+ if (cpu_has_apic || apic_from_smp_config())
+ disconnect_bsp_APIC(0);
+}
+
+static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
+{
+ int node, ret, sub_handle, index = 0;
+ unsigned int irq;
+ struct msi_desc *msidesc;
+
+ nvec = __roundup_pow_of_two(nvec);
+
+ WARN_ON(!list_is_singular(&dev->msi_list));
+ msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
+ WARN_ON(msidesc->irq);
+ WARN_ON(msidesc->msi_attrib.multiple);
+
+ node = dev_to_node(&dev->dev);
+ irq = __create_irqs(get_nr_irqs_gsi(), nvec, node);
+ if (irq == 0)
+ return -ENOSPC;
+
+ msidesc->msi_attrib.multiple = ilog2(nvec);
+ for (sub_handle = 0; sub_handle < nvec; sub_handle++) {
+ if (!sub_handle) {
+ index = msi_alloc_remapped_irq(dev, irq, nvec);
+ if (index < 0) {
+ ret = index;
+ goto error;
+ }
+ } else {
+ ret = msi_setup_remapped_irq(dev, irq + sub_handle,
+ index, sub_handle);
+ if (ret < 0)
+ goto error;
+ }
+ ret = setup_msi_irq(dev, msidesc, irq, sub_handle);
+ if (ret < 0)
+ goto error;
+ }
+ return 0;
+
+error:
+ destroy_irqs(irq, nvec);
+
+ /*
+ * Restore altered MSI descriptor fields and prevent just destroyed
+ * IRQs from tearing down again in default_teardown_msi_irqs()
+ */
+ msidesc->irq = 0;
+ msidesc->msi_attrib.multiple = 0;
+
+ return ret;
+}
+
+static int do_setup_msix_irqs(struct pci_dev *dev, int nvec)
+{
+ int node, ret, sub_handle, index = 0;
+ struct msi_desc *msidesc;
+ unsigned int irq;
+
+ node = dev_to_node(&dev->dev);
+ irq = get_nr_irqs_gsi();
+ sub_handle = 0;
+
+ list_for_each_entry(msidesc, &dev->msi_list, list) {
+
+ irq = create_irq_nr(irq, node);
+ if (irq == 0)
+ return -1;
+
+ if (sub_handle == 0)
+ ret = index = msi_alloc_remapped_irq(dev, irq, nvec);
+ else
+ ret = msi_setup_remapped_irq(dev, irq, index, sub_handle);
+
+ if (ret < 0)
+ goto error;
+
+ ret = setup_msi_irq(dev, msidesc, irq, 0);
+ if (ret < 0)
+ goto error;
+
+ sub_handle += 1;
+ irq += 1;
+ }
+
+ return 0;
+
+error:
+ destroy_irq(irq);
+ return ret;
+}
+
+static int irq_remapping_setup_msi_irqs(struct pci_dev *dev,
+ int nvec, int type)
+{
+ if (type == PCI_CAP_ID_MSI)
+ return do_setup_msi_irqs(dev, nvec);
+ else
+ return do_setup_msix_irqs(dev, nvec);
+}
+
+void eoi_ioapic_pin_remapped(int apic, int pin, int vector)
+{
+ /*
+ * Intr-remapping uses pin number as the virtual vector
+ * in the RTE. Actual vector is programmed in
+ * intr-remapping table entry. Hence for the io-apic
+ * EOI we use the pin number.
+ */
+ io_apic_eoi(apic, pin);
+}
+
+static void __init irq_remapping_modify_x86_ops(void)
+{
+ x86_io_apic_ops.disable = irq_remapping_disable_io_apic;
+ x86_io_apic_ops.set_affinity = set_remapped_irq_affinity;
+ x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry;
+ x86_io_apic_ops.eoi_ioapic_pin = eoi_ioapic_pin_remapped;
+ x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs;
+ x86_msi.setup_hpet_msi = setup_hpet_msi_remapped;
+ x86_msi.compose_msi_msg = compose_remapped_msi_msg;
+}
+
static __init int setup_nointremap(char *str)
{
disable_irq_remap = 1;
@@ -79,15 +232,24 @@ int __init irq_remapping_prepare(void)
int __init irq_remapping_enable(void)
{
+ int ret;
+
if (!remap_ops || !remap_ops->enable)
return -ENODEV;
- return remap_ops->enable();
+ ret = remap_ops->enable();
+
+ if (irq_remapping_enabled)
+ irq_remapping_modify_x86_ops();
+
+ return ret;
}
void irq_remapping_disable(void)
{
- if (!remap_ops || !remap_ops->disable)
+ if (!irq_remapping_enabled ||
+ !remap_ops ||
+ !remap_ops->disable)
return;
remap_ops->disable();
@@ -95,7 +257,9 @@ void irq_remapping_disable(void)
int irq_remapping_reenable(int mode)
{
- if (!remap_ops || !remap_ops->reenable)
+ if (!irq_remapping_enabled ||
+ !remap_ops ||
+ !remap_ops->reenable)
return 0;
return remap_ops->reenable(mode);
@@ -103,6 +267,9 @@ int irq_remapping_reenable(int mode)
int __init irq_remap_enable_fault_handling(void)
{
+ if (!irq_remapping_enabled)
+ return 0;
+
if (!remap_ops || !remap_ops->enable_faulting)
return -ENODEV;
@@ -133,23 +300,28 @@ int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask,
void free_remapped_irq(int irq)
{
+ struct irq_cfg *cfg = irq_get_chip_data(irq);
+
if (!remap_ops || !remap_ops->free_irq)
return;
- remap_ops->free_irq(irq);
+ if (irq_remapped(cfg))
+ remap_ops->free_irq(irq);
}
void compose_remapped_msi_msg(struct pci_dev *pdev,
unsigned int irq, unsigned int dest,
struct msi_msg *msg, u8 hpet_id)
{
- if (!remap_ops || !remap_ops->compose_msi_msg)
- return;
+ struct irq_cfg *cfg = irq_get_chip_data(irq);
- remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+ if (!irq_remapped(cfg))
+ native_compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+ else if (remap_ops && remap_ops->compose_msi_msg)
+ remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
}
-int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
+static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
{
if (!remap_ops || !remap_ops->msi_alloc_irq)
return -ENODEV;
@@ -157,8 +329,8 @@ int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
return remap_ops->msi_alloc_irq(pdev, irq, nvec);
}
-int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
- int index, int sub_handle)
+static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
+ int index, int sub_handle)
{
if (!remap_ops || !remap_ops->msi_setup_irq)
return -ENODEV;
@@ -173,3 +345,42 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
return remap_ops->setup_hpet_msi(irq, id);
}
+
+void panic_if_irq_remap(const char *msg)
+{
+ if (irq_remapping_enabled)
+ panic(msg);
+}
+
+static void ir_ack_apic_edge(struct irq_data *data)
+{
+ ack_APIC_irq();
+}
+
+static void ir_ack_apic_level(struct irq_data *data)
+{
+ ack_APIC_irq();
+ eoi_ioapic_irq(data->irq, data->chip_data);
+}
+
+static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
+{
+ seq_printf(p, " IR-%s", data->chip->name);
+}
+
+void irq_remap_modify_chip_defaults(struct irq_chip *chip)
+{
+ chip->irq_print_chip = ir_print_prefix;
+ chip->irq_ack = ir_ack_apic_edge;
+ chip->irq_eoi = ir_ack_apic_level;
+ chip->irq_set_affinity = x86_io_apic_ops.set_affinity;
+}
+
+bool setup_remapped_irq(int irq, struct irq_cfg *cfg, struct irq_chip *chip)
+{
+ if (!irq_remapped(cfg))
+ return false;
+ irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
+ irq_remap_modify_chip_defaults(chip);
+ return true;
+}
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h
index 95363acb583f..ecb637670405 100644
--- a/drivers/iommu/irq_remapping.h
+++ b/drivers/iommu/irq_remapping.h
@@ -34,6 +34,7 @@ struct msi_msg;
extern int disable_irq_remap;
extern int disable_sourceid_checking;
extern int no_x2apic_optout;
+extern int irq_remapping_enabled;
struct irq_remap_ops {
/* Check whether Interrupt Remapping is supported */
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index fc178893789a..f08dbcd2f175 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -19,6 +19,7 @@
#define pr_fmt(fmt) "%s(): " fmt, __func__
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@@ -1176,9 +1177,9 @@ static int tegra_smmu_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res)
return -ENODEV;
- smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
- if (!smmu->regs[i])
- return -EBUSY;
+ smmu->regs[i] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(smmu->regs[i]))
+ return PTR_ERR(smmu->regs[i]);
}
err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
diff --git a/drivers/ipack/devices/Kconfig b/drivers/ipack/devices/Kconfig
index 0b82fdc198c0..907a8cb48f2a 100644
--- a/drivers/ipack/devices/Kconfig
+++ b/drivers/ipack/devices/Kconfig
@@ -1,6 +1,6 @@
config SERIAL_IPOCTAL
tristate "IndustryPack IP-OCTAL uart support"
- depends on IPACK_BUS
+ depends on IPACK_BUS && TTY
help
This driver supports the IPOCTAL serial port device for the IndustryPack bus.
default n
diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c
index 576d53d92677..141094e7c06e 100644
--- a/drivers/ipack/devices/ipoctal.c
+++ b/drivers/ipack/devices/ipoctal.c
@@ -20,7 +20,6 @@
#include <linux/serial.h>
#include <linux/tty_flip.h>
#include <linux/slab.h>
-#include <linux/atomic.h>
#include <linux/io.h>
#include <linux/ipack.h>
#include "ipoctal.h"
@@ -38,21 +37,19 @@ struct ipoctal_channel {
spinlock_t lock;
unsigned int pointer_read;
unsigned int pointer_write;
- atomic_t open;
struct tty_port tty_port;
union scc2698_channel __iomem *regs;
union scc2698_block __iomem *block_regs;
unsigned int board_id;
- unsigned char *board_write;
u8 isr_rx_rdy_mask;
u8 isr_tx_rdy_mask;
+ unsigned int rx_enable;
};
struct ipoctal {
struct ipack_device *dev;
unsigned int board_id;
struct ipoctal_channel channel[NR_CHANNELS];
- unsigned char write;
struct tty_driver *tty_drv;
u8 __iomem *mem8_space;
u8 __iomem *int_space;
@@ -64,28 +61,23 @@ static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
channel = dev_get_drvdata(tty->dev);
+ /*
+ * Enable RX. TX will be enabled when
+ * there is something to send
+ */
iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
+ channel->rx_enable = 1;
return 0;
}
static int ipoctal_open(struct tty_struct *tty, struct file *file)
{
- int res;
struct ipoctal_channel *channel;
channel = dev_get_drvdata(tty->dev);
-
- if (atomic_read(&channel->open))
- return -EBUSY;
-
tty->driver_data = channel;
- res = tty_port_open(&channel->tty_port, tty, file);
- if (res)
- return res;
-
- atomic_inc(&channel->open);
- return 0;
+ return tty_port_open(&channel->tty_port, tty, file);
}
static void ipoctal_reset_stats(struct ipoctal_stats *stats)
@@ -111,9 +103,7 @@ static void ipoctal_close(struct tty_struct *tty, struct file *filp)
struct ipoctal_channel *channel = tty->driver_data;
tty_port_close(&channel->tty_port, tty, filp);
-
- if (atomic_dec_and_test(&channel->open))
- ipoctal_free_channel(channel);
+ ipoctal_free_channel(channel);
}
static int ipoctal_get_icount(struct tty_struct *tty,
@@ -133,15 +123,16 @@ static int ipoctal_get_icount(struct tty_struct *tty,
return 0;
}
-static void ipoctal_irq_rx(struct ipoctal_channel *channel,
- struct tty_struct *tty, u8 sr)
+static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr)
{
+ struct tty_port *port = &channel->tty_port;
unsigned char value;
- unsigned char flag = TTY_NORMAL;
+ unsigned char flag;
u8 isr;
do {
value = ioread8(&channel->regs->r.rhr);
+ flag = TTY_NORMAL;
/* Error: count statistics */
if (sr & SR_ERROR) {
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
@@ -149,7 +140,7 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel,
if (sr & SR_OVERRUN_ERROR) {
channel->stats.overrun_err++;
/* Overrun doesn't affect the current character*/
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_insert_flip_char(port, 0, TTY_OVERRUN);
}
if (sr & SR_PARITY_ERROR) {
channel->stats.parity_err++;
@@ -165,7 +156,7 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel,
flag = TTY_BREAK;
}
}
- tty_insert_flip_char(tty, value, flag);
+ tty_insert_flip_char(port, value, flag);
/* Check if there are more characters in RX FIFO
* If there are more, the isr register for this channel
@@ -175,7 +166,7 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel,
sr = ioread8(&channel->regs->r.sr);
} while (isr & channel->isr_rx_rdy_mask);
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(port);
}
static void ipoctal_irq_tx(struct ipoctal_channel *channel)
@@ -183,10 +174,8 @@ static void ipoctal_irq_tx(struct ipoctal_channel *channel)
unsigned char value;
unsigned int *pointer_write = &channel->pointer_write;
- if (channel->nb_bytes <= 0) {
- channel->nb_bytes = 0;
+ if (channel->nb_bytes == 0)
return;
- }
value = channel->tty_port.xmit_buf[*pointer_write];
iowrite8(value, &channel->regs->w.thr);
@@ -194,55 +183,38 @@ static void ipoctal_irq_tx(struct ipoctal_channel *channel)
(*pointer_write)++;
*pointer_write = *pointer_write % PAGE_SIZE;
channel->nb_bytes--;
-
- if ((channel->nb_bytes == 0) &&
- (waitqueue_active(&channel->queue))) {
-
- if (channel->board_id != IPACK1_DEVICE_ID_SBS_OCTAL_485) {
- *channel->board_write = 1;
- wake_up_interruptible(&channel->queue);
- }
- }
}
static void ipoctal_irq_channel(struct ipoctal_channel *channel)
{
u8 isr, sr;
- struct tty_struct *tty;
- /* If there is no client, skip the check */
- if (!atomic_read(&channel->open))
- return;
-
- tty = tty_port_tty_get(&channel->tty_port);
- if (!tty)
- return;
+ spin_lock(&channel->lock);
/* The HW is organized in pair of channels. See which register we need
* to read from */
isr = ioread8(&channel->block_regs->r.isr);
sr = ioread8(&channel->regs->r.sr);
- /* In case of RS-485, change from TX to RX when finishing TX.
- * Half-duplex. */
- if ((channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) &&
- (sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) {
+ if ((sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) {
iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
- iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr);
- iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
- *channel->board_write = 1;
- wake_up_interruptible(&channel->queue);
+ /* In case of RS-485, change from TX to RX when finishing TX.
+ * Half-duplex. */
+ if (channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) {
+ iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr);
+ iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
+ channel->rx_enable = 1;
+ }
}
/* RX data */
if ((isr & channel->isr_rx_rdy_mask) && (sr & SR_RX_READY))
- ipoctal_irq_rx(channel, tty, sr);
+ ipoctal_irq_rx(channel, sr);
/* TX of each character */
if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY))
ipoctal_irq_tx(channel);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ spin_unlock(&channel->lock);
}
static irqreturn_t ipoctal_irq_handler(void *arg)
@@ -250,14 +222,14 @@ static irqreturn_t ipoctal_irq_handler(void *arg)
unsigned int i;
struct ipoctal *ipoctal = (struct ipoctal *) arg;
- /* Check all channels */
- for (i = 0; i < NR_CHANNELS; i++)
- ipoctal_irq_channel(&ipoctal->channel[i]);
-
/* Clear the IPack device interrupt */
readw(ipoctal->int_space + ACK_INT_REQ0);
readw(ipoctal->int_space + ACK_INT_REQ1);
+ /* Check all channels */
+ for (i = 0; i < NR_CHANNELS; i++)
+ ipoctal_irq_channel(&ipoctal->channel[i]);
+
return IRQ_HANDLED;
}
@@ -311,7 +283,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
ipoctal->mem8_space =
devm_ioremap_nocache(&ipoctal->dev->dev,
region->start, 0x8000);
- if (!addr) {
+ if (!ipoctal->mem8_space) {
dev_err(&ipoctal->dev->dev,
"Unable to map slot [%d:%d] MEM8 space!\n",
bus_nr, slot);
@@ -324,7 +296,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
struct ipoctal_channel *channel = &ipoctal->channel[i];
channel->regs = chan_regs + i;
channel->block_regs = block_regs + (i >> 1);
- channel->board_write = &ipoctal->write;
channel->board_id = ipoctal->board_id;
if (i & 1) {
channel->isr_tx_rdy_mask = ISR_TxRDY_B;
@@ -335,6 +306,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
}
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
+ channel->rx_enable = 0;
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY,
@@ -407,8 +379,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
ipoctal_reset_stats(&channel->stats);
channel->nb_bytes = 0;
- init_waitqueue_head(&channel->queue);
-
spin_lock_init(&channel->lock);
channel->pointer_read = 0;
channel->pointer_write = 0;
@@ -419,12 +389,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
continue;
}
dev_set_drvdata(tty_dev, channel);
-
- /*
- * Enable again the RX. TX will be enabled when
- * there is something to send
- */
- iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
}
return 0;
@@ -464,6 +428,7 @@ static int ipoctal_write_tty(struct tty_struct *tty,
/* As the IP-OCTAL 485 only supports half duplex, do it manually */
if (channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) {
iowrite8(CR_DISABLE_RX, &channel->regs->w.cr);
+ channel->rx_enable = 0;
iowrite8(CR_CMD_ASSERT_RTSN, &channel->regs->w.cr);
}
@@ -472,10 +437,6 @@ static int ipoctal_write_tty(struct tty_struct *tty,
* operations
*/
iowrite8(CR_ENABLE_TX, &channel->regs->w.cr);
- wait_event_interruptible(channel->queue, *channel->board_write);
- iowrite8(CR_DISABLE_TX, &channel->regs->w.cr);
-
- *channel->board_write = 0;
return char_copied;
}
@@ -627,8 +588,9 @@ static void ipoctal_set_termios(struct tty_struct *tty,
iowrite8(mr2, &channel->regs->w.mr);
iowrite8(csr, &channel->regs->w.csr);
- /* Enable again the RX */
- iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
+ /* Enable again the RX, if it was before */
+ if (channel->rx_enable)
+ iowrite8(CR_ENABLE_RX, &channel->regs->w.cr);
}
static void ipoctal_hangup(struct tty_struct *tty)
@@ -648,6 +610,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
tty_port_hangup(&channel->tty_port);
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
+ channel->rx_enable = 0;
iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
@@ -657,6 +620,22 @@ static void ipoctal_hangup(struct tty_struct *tty)
wake_up_interruptible(&channel->tty_port.open_wait);
}
+static void ipoctal_shutdown(struct tty_struct *tty)
+{
+ struct ipoctal_channel *channel = tty->driver_data;
+
+ if (channel == NULL)
+ return;
+
+ iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
+ channel->rx_enable = 0;
+ iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
+ iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
+ iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr);
+ iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr);
+ clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags);
+}
+
static const struct tty_operations ipoctal_fops = {
.ioctl = NULL,
.open = ipoctal_open,
@@ -667,6 +646,7 @@ static const struct tty_operations ipoctal_fops = {
.chars_in_buffer = ipoctal_chars_in_buffer,
.get_icount = ipoctal_get_icount,
.hangup = ipoctal_hangup,
+ .shutdown = ipoctal_shutdown,
};
static int ipoctal_probe(struct ipack_device *dev)
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 62ca575701d3..a350969e5efe 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -1,3 +1,30 @@
+config IRQCHIP
+ def_bool y
+ depends on OF_IRQ
+
+config ARM_GIC
+ bool
+ select IRQ_DOMAIN
+ select MULTI_IRQ_HANDLER
+
+config GIC_NON_BANKED
+ bool
+
+config ARM_VIC
+ bool
+ select IRQ_DOMAIN
+ select MULTI_IRQ_HANDLER
+
+config ARM_VIC_NR
+ int
+ default 4 if ARCH_S5PV210
+ default 3 if ARCH_S5PC100
+ default 2
+ depends on ARM_VIC
+ help
+ The maximum number of VICs available in the system, for
+ power management.
+
config VERSATILE_FPGA_IRQ
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index bf4609a5bd9d..e65fbf2cdf71 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -1,4 +1,9 @@
+obj-$(CONFIG_IRQCHIP) += irqchip.o
+
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
+obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o
-obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
+obj-$(CONFIG_ARM_GIC) += irq-gic.o
+obj-$(CONFIG_ARM_VIC) += irq-vic.o
+obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c
new file mode 100644
index 000000000000..04d86a9803f4
--- /dev/null
+++ b/drivers/irqchip/exynos-combiner.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Combiner irqchip for EXYNOS
+ *
+ * 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/export.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/mach/irq.h>
+
+#include <plat/cpu.h>
+
+#include "irqchip.h"
+
+#define COMBINER_ENABLE_SET 0x0
+#define COMBINER_ENABLE_CLEAR 0x4
+#define COMBINER_INT_STATUS 0xC
+
+static DEFINE_SPINLOCK(irq_controller_lock);
+
+struct combiner_chip_data {
+ unsigned int irq_offset;
+ unsigned int irq_mask;
+ void __iomem *base;
+};
+
+static struct irq_domain *combiner_irq_domain;
+static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
+
+static inline void __iomem *combiner_base(struct irq_data *data)
+{
+ struct combiner_chip_data *combiner_data =
+ irq_data_get_irq_chip_data(data);
+
+ return combiner_data->base;
+}
+
+static void combiner_mask_irq(struct irq_data *data)
+{
+ u32 mask = 1 << (data->hwirq % 32);
+
+ __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
+}
+
+static void combiner_unmask_irq(struct irq_data *data)
+{
+ u32 mask = 1 << (data->hwirq % 32);
+
+ __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
+}
+
+static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
+{
+ struct combiner_chip_data *chip_data = irq_get_handler_data(irq);
+ struct irq_chip *chip = irq_get_chip(irq);
+ unsigned int cascade_irq, combiner_irq;
+ unsigned long status;
+
+ chained_irq_enter(chip, desc);
+
+ spin_lock(&irq_controller_lock);
+ status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
+ spin_unlock(&irq_controller_lock);
+ status &= chip_data->irq_mask;
+
+ if (status == 0)
+ goto out;
+
+ combiner_irq = __ffs(status);
+
+ cascade_irq = combiner_irq + (chip_data->irq_offset & ~31);
+ if (unlikely(cascade_irq >= NR_IRQS))
+ do_bad_IRQ(cascade_irq, desc);
+ else
+ generic_handle_irq(cascade_irq);
+
+ out:
+ chained_irq_exit(chip, desc);
+}
+
+static struct irq_chip combiner_chip = {
+ .name = "COMBINER",
+ .irq_mask = combiner_mask_irq,
+ .irq_unmask = combiner_unmask_irq,
+};
+
+static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
+{
+ unsigned int max_nr;
+
+ if (soc_is_exynos5250())
+ max_nr = EXYNOS5_MAX_COMBINER_NR;
+ else
+ max_nr = EXYNOS4_MAX_COMBINER_NR;
+
+ if (combiner_nr >= max_nr)
+ BUG();
+ if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
+ BUG();
+ irq_set_chained_handler(irq, combiner_handle_cascade_irq);
+}
+
+static void __init combiner_init_one(unsigned int combiner_nr,
+ void __iomem *base)
+{
+ combiner_data[combiner_nr].base = base;
+ combiner_data[combiner_nr].irq_offset = irq_find_mapping(
+ combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
+ combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
+
+ /* Disable all interrupts */
+ __raw_writel(combiner_data[combiner_nr].irq_mask,
+ base + COMBINER_ENABLE_CLEAR);
+}
+
+#ifdef CONFIG_OF
+static int combiner_irq_domain_xlate(struct irq_domain *d,
+ struct device_node *controller,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq,
+ unsigned int *out_type)
+{
+ if (d->of_node != controller)
+ return -EINVAL;
+
+ if (intsize < 2)
+ return -EINVAL;
+
+ *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
+ *out_type = 0;
+
+ return 0;
+}
+#else
+static int combiner_irq_domain_xlate(struct irq_domain *d,
+ struct device_node *controller,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq,
+ unsigned int *out_type)
+{
+ return -EINVAL;
+}
+#endif
+
+static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
+ irq_set_chip_data(irq, &combiner_data[hw >> 3]);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+
+ return 0;
+}
+
+static struct irq_domain_ops combiner_irq_domain_ops = {
+ .xlate = combiner_irq_domain_xlate,
+ .map = combiner_irq_domain_map,
+};
+
+void __init combiner_init(void __iomem *combiner_base,
+ struct device_node *np)
+{
+ int i, irq, irq_base;
+ unsigned int max_nr, nr_irq;
+
+ if (np) {
+ if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
+ pr_warning("%s: number of combiners not specified, "
+ "setting default as %d.\n",
+ __func__, EXYNOS4_MAX_COMBINER_NR);
+ max_nr = EXYNOS4_MAX_COMBINER_NR;
+ }
+ } else {
+ max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
+ EXYNOS4_MAX_COMBINER_NR;
+ }
+ nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
+
+ irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
+ if (IS_ERR_VALUE(irq_base)) {
+ irq_base = COMBINER_IRQ(0, 0);
+ pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base);
+ }
+
+ combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
+ &combiner_irq_domain_ops, &combiner_data);
+ if (WARN_ON(!combiner_irq_domain)) {
+ pr_warning("%s: irq domain init failed\n", __func__);
+ return;
+ }
+
+ for (i = 0; i < max_nr; i++) {
+ combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
+ irq = IRQ_SPI(i);
+#ifdef CONFIG_OF
+ if (np)
+ irq = irq_of_parse_and_map(np, i);
+#endif
+ combiner_cascade_irq(i, irq);
+ }
+}
+
+#ifdef CONFIG_OF
+static int __init combiner_of_init(struct device_node *np,
+ struct device_node *parent)
+{
+ void __iomem *combiner_base;
+
+ combiner_base = of_iomap(np, 0);
+ if (!combiner_base) {
+ pr_err("%s: failed to map combiner registers\n", __func__);
+ return -ENXIO;
+ }
+
+ combiner_init(combiner_base, np);
+
+ return 0;
+}
+IRQCHIP_DECLARE(exynos4210_combiner, "samsung,exynos4210-combiner",
+ combiner_of_init);
+#endif
diff --git a/arch/arm/common/gic.c b/drivers/irqchip/irq-gic.c
index 36ae03a3f5d1..644d72468423 100644
--- a/arch/arm/common/gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -38,12 +38,14 @@
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <linux/slab.h>
+#include <linux/irqchip/arm-gic.h>
#include <asm/irq.h>
#include <asm/exception.h>
#include <asm/smp_plat.h>
#include <asm/mach/irq.h>
-#include <asm/hardware/gic.h>
+
+#include "irqchip.h"
union gic_base {
void __iomem *common_base;
@@ -276,7 +278,7 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
#define gic_set_wake NULL
#endif
-asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
u32 irqstat, irqnr;
struct gic_chip_data *gic = &gic_data[0];
@@ -351,6 +353,25 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
irq_set_chained_handler(irq, gic_handle_cascade_irq);
}
+static u8 gic_get_cpumask(struct gic_chip_data *gic)
+{
+ void __iomem *base = gic_data_dist_base(gic);
+ u32 mask, i;
+
+ for (i = mask = 0; i < 32; i += 4) {
+ mask = readl_relaxed(base + GIC_DIST_TARGET + i);
+ mask |= mask >> 16;
+ mask |= mask >> 8;
+ if (mask)
+ break;
+ }
+
+ if (!mask)
+ pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
+
+ return mask;
+}
+
static void __init gic_dist_init(struct gic_chip_data *gic)
{
unsigned int i;
@@ -369,7 +390,9 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
/*
* Set all global interrupts to this CPU only.
*/
- cpumask = readl_relaxed(base + GIC_DIST_TARGET + 0);
+ cpumask = gic_get_cpumask(gic);
+ cpumask |= cpumask << 8;
+ cpumask |= cpumask << 16;
for (i = 32; i < gic_irqs; i += 4)
writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
@@ -400,7 +423,7 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
* Get what the GIC says our CPU mask is.
*/
BUG_ON(cpu >= NR_GIC_CPU_IF);
- cpu_mask = readl_relaxed(dist_base + GIC_DIST_TARGET + 0);
+ cpu_mask = gic_get_cpumask(gic);
gic_cpu_map[cpu] = cpu_mask;
/*
@@ -617,6 +640,27 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
}
#endif
+#ifdef CONFIG_SMP
+void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
+{
+ int cpu;
+ unsigned long map = 0;
+
+ /* Convert our logical CPU mask into a physical one. */
+ for_each_cpu(cpu, mask)
+ map |= 1 << cpu_logical_map(cpu);
+
+ /*
+ * Ensure that stores to Normal memory are visible to the
+ * other CPUs before issuing the IPI.
+ */
+ dsb();
+
+ /* this always happens on GIC0 */
+ writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+}
+#endif
+
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
@@ -743,6 +787,12 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
if (WARN_ON(!gic->domain))
return;
+#ifdef CONFIG_SMP
+ set_smp_cross_call(gic_raise_softirq);
+#endif
+
+ set_handle_irq(gic_handle_irq);
+
gic_chip.flags |= gic_arch_extn.flags;
gic_dist_init(gic);
gic_cpu_init(gic);
@@ -756,27 +806,6 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr)
gic_cpu_init(&gic_data[gic_nr]);
}
-#ifdef CONFIG_SMP
-void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
-{
- int cpu;
- unsigned long map = 0;
-
- /* Convert our logical CPU mask into a physical one. */
- for_each_cpu(cpu, mask)
- map |= gic_cpu_map[cpu];
-
- /*
- * Ensure that stores to Normal memory are visible to the
- * other CPUs before issuing the IPI.
- */
- dsb();
-
- /* this always happens on GIC0 */
- writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-}
-#endif
-
#ifdef CONFIG_OF
static int gic_cnt __initdata = 0;
@@ -808,4 +837,9 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
gic_cnt++;
return 0;
}
+IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
+IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
+IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
+IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
+
#endif
diff --git a/arch/arm/common/vic.c b/drivers/irqchip/irq-vic.c
index 8f324b99416e..3cf97aaebe40 100644
--- a/arch/arm/common/vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -30,10 +30,29 @@
#include <linux/syscore_ops.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
+#include <linux/irqchip/arm-vic.h>
#include <asm/exception.h>
#include <asm/mach/irq.h>
-#include <asm/hardware/vic.h>
+
+#include "irqchip.h"
+
+#define VIC_IRQ_STATUS 0x00
+#define VIC_FIQ_STATUS 0x04
+#define VIC_INT_SELECT 0x0c /* 1 = FIQ, 0 = IRQ */
+#define VIC_INT_SOFT 0x18
+#define VIC_INT_SOFT_CLEAR 0x1c
+#define VIC_PROTECT 0x20
+#define VIC_PL190_VECT_ADDR 0x30 /* PL190 only */
+#define VIC_PL190_DEF_VECT_ADDR 0x34 /* PL190 only */
+
+#define VIC_VECT_ADDR0 0x100 /* 0 to 15 (0..31 PL192) */
+#define VIC_VECT_CNTL0 0x200 /* 0 to 15 (0..31 PL192) */
+#define VIC_ITCR 0x300 /* VIC test control register */
+
+#define VIC_VECT_CNTL_ENABLE (1 << 5)
+
+#define VIC_PL192_VECT_ADDR 0xF00
/**
* struct vic_device - VIC PM device
@@ -66,6 +85,8 @@ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
static int vic_id;
+static void vic_handle_irq(struct pt_regs *regs);
+
/**
* vic_init2 - common initialisation code
* @base: Base of the VIC.
@@ -182,6 +203,40 @@ static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq,
return 0;
}
+/*
+ * Handle each interrupt in a single VIC. Returns non-zero if we've
+ * handled at least one interrupt. This reads the status register
+ * before handling each interrupt, which is necessary given that
+ * handle_IRQ may briefly re-enable interrupts for soft IRQ handling.
+ */
+static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
+{
+ u32 stat, irq;
+ int handled = 0;
+
+ while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
+ irq = ffs(stat) - 1;
+ handle_IRQ(irq_find_mapping(vic->domain, irq), regs);
+ handled = 1;
+ }
+
+ return handled;
+}
+
+/*
+ * Keep iterating over all registered VIC's until there are no pending
+ * interrupts.
+ */
+static asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
+{
+ int i, handled;
+
+ do {
+ for (i = 0, handled = 0; i < vic_id; ++i)
+ handled |= handle_one_vic(&vic_devices[i], regs);
+ } while (handled);
+}
+
static struct irq_domain_ops vic_irqdomain_ops = {
.map = vic_irqdomain_map,
.xlate = irq_domain_xlate_onetwocell,
@@ -218,6 +273,7 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
v->valid_sources = valid_sources;
v->resume_sources = resume_sources;
v->irq = irq;
+ set_handle_irq(vic_handle_irq);
vic_id++;
v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
&vic_irqdomain_ops, v);
@@ -427,38 +483,7 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
return 0;
}
+IRQCHIP_DECLARE(arm_pl190_vic, "arm,pl190-vic", vic_of_init);
+IRQCHIP_DECLARE(arm_pl192_vic, "arm,pl192-vic", vic_of_init);
+IRQCHIP_DECLARE(arm_versatile_vic, "arm,versatile-vic", vic_of_init);
#endif /* CONFIG OF */
-
-/*
- * Handle each interrupt in a single VIC. Returns non-zero if we've
- * handled at least one interrupt. This reads the status register
- * before handling each interrupt, which is necessary given that
- * handle_IRQ may briefly re-enable interrupts for soft IRQ handling.
- */
-static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
-{
- u32 stat, irq;
- int handled = 0;
-
- while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
- irq = ffs(stat) - 1;
- handle_IRQ(irq_find_mapping(vic->domain, irq), regs);
- handled = 1;
- }
-
- return handled;
-}
-
-/*
- * Keep iterating over all registered VIC's until there are no pending
- * interrupts.
- */
-asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
-{
- int i, handled;
-
- do {
- for (i = 0, handled = 0; i < vic_id; ++i)
- handled |= handle_one_vic(&vic_devices[i], regs);
- } while (handled);
-}
diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c
new file mode 100644
index 000000000000..f496afce29de
--- /dev/null
+++ b/drivers/irqchip/irqchip.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 Thomas Petazzoni
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/of_irq.h>
+
+#include "irqchip.h"
+
+/*
+ * This special of_device_id is the sentinel at the end of the
+ * of_device_id[] array of all irqchips. It is automatically placed at
+ * the end of the array by the linker, thanks to being part of a
+ * special section.
+ */
+static const struct of_device_id
+irqchip_of_match_end __used __section(__irqchip_of_end);
+
+extern struct of_device_id __irqchip_begin[];
+
+void __init irqchip_init(void)
+{
+ of_irq_init(__irqchip_begin);
+}
diff --git a/drivers/irqchip/irqchip.h b/drivers/irqchip/irqchip.h
new file mode 100644
index 000000000000..e445ba2d6add
--- /dev/null
+++ b/drivers/irqchip/irqchip.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 Thomas Petazzoni
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ */
+
+#ifndef _IRQCHIP_H
+#define _IRQCHIP_H
+
+/*
+ * This macro must be used by the different irqchip drivers to declare
+ * the association between their DT compatible string and their
+ * initialization function.
+ *
+ * @name: name that must be unique accross all IRQCHIP_DECLARE of the
+ * same file.
+ * @compstr: compatible string of the irqchip driver
+ * @fn: initialization function
+ */
+#define IRQCHIP_DECLARE(name,compstr,fn) \
+ static const struct of_device_id irqchip_of_match_##name \
+ __used __section(__irqchip_of_table) \
+ = { .compatible = compstr, .data = fn }
+
+#endif
diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c
index 80e1d2fd9d4c..8527743b5cef 100644
--- a/drivers/irqchip/spear-shirq.c
+++ b/drivers/irqchip/spear-shirq.c
@@ -25,6 +25,8 @@
#include <linux/of_irq.h>
#include <linux/spinlock.h>
+#include "irqchip.h"
+
static DEFINE_SPINLOCK(lock);
/* spear300 shared irq registers offsets and masks */
@@ -300,6 +302,7 @@ int __init spear300_shirq_of_init(struct device_node *np,
return shirq_init(spear300_shirq_blocks,
ARRAY_SIZE(spear300_shirq_blocks), np);
}
+IRQCHIP_DECLARE(spear300_shirq, "st,spear300-shirq", spear300_shirq_of_init);
int __init spear310_shirq_of_init(struct device_node *np,
struct device_node *parent)
@@ -307,6 +310,7 @@ int __init spear310_shirq_of_init(struct device_node *np,
return shirq_init(spear310_shirq_blocks,
ARRAY_SIZE(spear310_shirq_blocks), np);
}
+IRQCHIP_DECLARE(spear310_shirq, "st,spear310-shirq", spear310_shirq_of_init);
int __init spear320_shirq_of_init(struct device_node *np,
struct device_node *parent)
@@ -314,3 +318,4 @@ int __init spear320_shirq_of_init(struct device_node *np,
return shirq_init(spear320_shirq_blocks,
ARRAY_SIZE(spear320_shirq_blocks), np);
}
+IRQCHIP_DECLARE(spear320_shirq, "st,spear320-shirq", spear320_shirq_of_init);
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
index 86cd75a0e84d..ef661acdda17 100644
--- a/drivers/isdn/Kconfig
+++ b/drivers/isdn/Kconfig
@@ -22,6 +22,7 @@ if ISDN
menuconfig ISDN_I4L
tristate "Old ISDN4Linux (deprecated)"
+ depends on TTY
---help---
This driver allows you to use an ISDN adapter for networking
connections and as dialin/out device. The isdn-tty's have a built
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index 15c3ffd9d860..f04686580040 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -18,6 +18,7 @@ config CAPI_TRACE
config ISDN_CAPI_MIDDLEWARE
bool "CAPI2.0 Middleware support"
+ depends on TTY
help
This option will enhance the capabilities of the /dev/capi20
interface. It will provide a means of moving a data connection,
diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c
index 5374c25f036c..267dede13bfd 100644
--- a/drivers/isdn/divert/divert_init.c
+++ b/drivers/isdn/divert/divert_init.c
@@ -22,13 +22,13 @@ MODULE_LICENSE("GPL");
/****************************************/
/* structure containing interface to hl */
/****************************************/
-isdn_divert_if divert_if =
-{ DIVERT_IF_MAGIC, /* magic value */
- DIVERT_CMD_REG, /* register cmd */
- ll_callback, /* callback routine from ll */
- NULL, /* command still not specified */
- NULL, /* drv_to_name */
- NULL, /* name_to_drv */
+isdn_divert_if divert_if = {
+ DIVERT_IF_MAGIC, /* magic value */
+ DIVERT_CMD_REG, /* register cmd */
+ ll_callback, /* callback routine from ll */
+ NULL, /* command still not specified */
+ NULL, /* drv_to_name */
+ NULL, /* name_to_drv */
};
/*************************/
@@ -36,14 +36,15 @@ isdn_divert_if divert_if =
/* no cmd line parms */
/*************************/
static int __init divert_init(void)
-{ int i;
+{
+ int i;
- if (divert_dev_init())
- { printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
+ if (divert_dev_init()) {
+ printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
return (-EIO);
}
- if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
- { divert_dev_deinit();
+ if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
+ divert_dev_deinit();
printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n", i);
return (-EIO);
}
@@ -61,13 +62,13 @@ static void __exit divert_exit(void)
spin_lock_irqsave(&divert_lock, flags);
divert_if.cmd = DIVERT_CMD_REL; /* release */
- if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
- { printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i);
+ if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) {
+ printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i);
spin_unlock_irqrestore(&divert_lock, flags);
return;
}
- if (divert_dev_deinit())
- { printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
+ if (divert_dev_deinit()) {
+ printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
spin_unlock_irqrestore(&divert_lock, flags);
return;
}
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
index e61e55f1f193..db432e635496 100644
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -19,8 +19,8 @@
/**********************************/
/* structure keeping calling info */
/**********************************/
-struct call_struc
-{ isdn_ctrl ics; /* delivered setup + driver parameters */
+struct call_struc {
+ isdn_ctrl ics; /* delivered setup + driver parameters */
ulong divert_id; /* Id delivered to user */
unsigned char akt_state; /* actual state */
char deflect_dest[35]; /* deflection destination */
@@ -34,8 +34,8 @@ struct call_struc
/********************************************/
/* structure keeping deflection table entry */
/********************************************/
-struct deflect_struc
-{ struct deflect_struc *next, *prev;
+struct deflect_struc {
+ struct deflect_struc *next, *prev;
divert_rule rule; /* used rule */
};
@@ -64,16 +64,16 @@ static void deflect_timer_expire(ulong arg)
del_timer(&cs->timer); /* delete active timer */
spin_unlock_irqrestore(&divert_lock, flags);
- switch (cs->akt_state)
- { case DEFLECT_PROCEED:
- cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
- divert_if.ll_cmd(&cs->ics);
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- break;
+ switch (cs->akt_state) {
+ case DEFLECT_PROCEED:
+ cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
+ divert_if.ll_cmd(&cs->ics);
+ spin_lock_irqsave(&divert_lock, flags);
+ cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+ add_timer(&cs->timer);
+ spin_unlock_irqrestore(&divert_lock, flags);
+ break;
case DEFLECT_ALERT:
cs->ics.command = ISDN_CMD_REDIR; /* protocol */
@@ -111,7 +111,8 @@ static void deflect_timer_expire(ulong arg)
int cf_command(int drvid, int mode,
u_char proc, char *msn,
u_char service, char *fwd_nr, ulong *procid)
-{ unsigned long flags;
+{
+ unsigned long flags;
int retval, msnlen;
int fwd_len;
char *p, *ielenp, tmp[60];
@@ -130,8 +131,8 @@ int cf_command(int drvid, int mode,
*p++ = 1; /* length */
*p++ = service; /* service to handle */
- if (mode == 1)
- { if (!*fwd_nr) return (-EINVAL); /* destination missing */
+ if (mode == 1) {
+ if (!*fwd_nr) return (-EINVAL); /* destination missing */
if (strchr(fwd_nr, '.')) return (-EINVAL); /* subaddress not allowed */
fwd_len = strlen(fwd_nr);
*p++ = 0x30; /* number enumeration */
@@ -144,12 +145,12 @@ int cf_command(int drvid, int mode,
msnlen = strlen(msn);
*p++ = 0x80; /* msn number */
- if (msnlen > 1)
- { *p++ = msnlen; /* length */
+ if (msnlen > 1) {
+ *p++ = msnlen; /* length */
strcpy(p, msn);
p += msnlen;
- }
- else *p++ = 0;
+ } else
+ *p++ = 0;
*ielenp = p - ielenp - 1; /* set total IE length */
@@ -186,14 +187,13 @@ int cf_command(int drvid, int mode,
retval = divert_if.ll_cmd(&cs->ics); /* execute command */
- if (!retval)
- { cs->prev = NULL;
+ if (!retval) {
+ cs->prev = NULL;
spin_lock_irqsave(&divert_lock, flags);
cs->next = divert_head;
divert_head = cs;
spin_unlock_irqrestore(&divert_lock, flags);
- }
- else
+ } else
kfree(cs);
return (retval);
} /* cf_command */
@@ -203,15 +203,16 @@ int cf_command(int drvid, int mode,
/* handle a external deflection command */
/****************************************/
int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
-{ struct call_struc *cs;
+{
+ struct call_struc *cs;
isdn_ctrl ic;
unsigned long flags;
int i;
if ((cmd & 0x7F) > 2) return (-EINVAL); /* invalid command */
cs = divert_head; /* start of parameter list */
- while (cs)
- { if (cs->divert_id == callid) break; /* found */
+ while (cs) {
+ if (cs->divert_id == callid) break; /* found */
cs = cs->next;
} /* search entry */
if (!cs) return (-EINVAL); /* invalid callid */
@@ -220,32 +221,30 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
ic.arg = cs->ics.arg;
i = -EINVAL;
if (cs->akt_state == DEFLECT_AUTODEL) return (i); /* no valid call */
- switch (cmd & 0x7F)
- { case 0: /* hangup */
- del_timer(&cs->timer);
- ic.command = ISDN_CMD_HANGUP;
- i = divert_if.ll_cmd(&ic);
- spin_lock_irqsave(&divert_lock, flags);
- cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
- cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
- add_timer(&cs->timer);
- spin_unlock_irqrestore(&divert_lock, flags);
- break;
+ switch (cmd & 0x7F) {
+ case 0: /* hangup */
+ del_timer(&cs->timer);
+ ic.command = ISDN_CMD_HANGUP;
+ i = divert_if.ll_cmd(&ic);
+ spin_lock_irqsave(&divert_lock, flags);
+ cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
+ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
+ add_timer(&cs->timer);
+ spin_unlock_irqrestore(&divert_lock, flags);
+ break;
case 1: /* alert */
if (cs->akt_state == DEFLECT_ALERT) return (0);
cmd &= 0x7F; /* never wait */
del_timer(&cs->timer);
ic.command = ISDN_CMD_ALERT;
- if ((i = divert_if.ll_cmd(&ic)))
- {
+ if ((i = divert_if.ll_cmd(&ic))) {
spin_lock_irqsave(&divert_lock, flags);
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
spin_unlock_irqrestore(&divert_lock, flags);
- }
- else
+ } else
cs->akt_state = DEFLECT_ALERT;
break;
@@ -254,15 +253,13 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone));
strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
ic.command = ISDN_CMD_REDIR;
- if ((i = divert_if.ll_cmd(&ic)))
- {
+ if ((i = divert_if.ll_cmd(&ic))) {
spin_lock_irqsave(&divert_lock, flags);
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
spin_unlock_irqrestore(&divert_lock, flags);
- }
- else
+ } else
cs->akt_state = DEFLECT_ALERT;
break;
@@ -274,19 +271,19 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
/* insert a new rule before idx */
/********************************/
int insertrule(int idx, divert_rule *newrule)
-{ struct deflect_struc *ds, *ds1 = NULL;
+{
+ struct deflect_struc *ds, *ds1 = NULL;
unsigned long flags;
- if (!(ds = kmalloc(sizeof(struct deflect_struc),
- GFP_KERNEL)))
+ if (!(ds = kmalloc(sizeof(struct deflect_struc), GFP_KERNEL)))
return (-ENOMEM); /* no memory */
ds->rule = *newrule; /* set rule */
spin_lock_irqsave(&divert_lock, flags);
- if (idx >= 0)
- { ds1 = table_head;
+ if (idx >= 0) {
+ ds1 = table_head;
while ((ds1) && (idx > 0))
{ idx--;
ds1 = ds1->next;
@@ -294,17 +291,16 @@ int insertrule(int idx, divert_rule *newrule)
if (!ds1) idx = -1;
}
- if (idx < 0)
- { ds->prev = table_tail; /* previous entry */
+ if (idx < 0) {
+ ds->prev = table_tail; /* previous entry */
ds->next = NULL; /* end of chain */
if (ds->prev)
ds->prev->next = ds; /* last forward */
else
table_head = ds; /* is first entry */
table_tail = ds; /* end of queue */
- }
- else
- { ds->next = ds1; /* next entry */
+ } else {
+ ds->next = ds1; /* next entry */
ds->prev = ds1->prev; /* prev entry */
ds1->prev = ds; /* backward chain old element */
if (!ds->prev)
@@ -319,17 +315,18 @@ int insertrule(int idx, divert_rule *newrule)
/* delete the rule at position idx */
/***********************************/
int deleterule(int idx)
-{ struct deflect_struc *ds, *ds1;
+{
+ struct deflect_struc *ds, *ds1;
unsigned long flags;
- if (idx < 0)
- { spin_lock_irqsave(&divert_lock, flags);
+ if (idx < 0) {
+ spin_lock_irqsave(&divert_lock, flags);
ds = table_head;
table_head = NULL;
table_tail = NULL;
spin_unlock_irqrestore(&divert_lock, flags);
- while (ds)
- { ds1 = ds;
+ while (ds) {
+ ds1 = ds;
ds = ds->next;
kfree(ds1);
}
@@ -339,13 +336,12 @@ int deleterule(int idx)
spin_lock_irqsave(&divert_lock, flags);
ds = table_head;
- while ((ds) && (idx > 0))
- { idx--;
+ while ((ds) && (idx > 0)) {
+ idx--;
ds = ds->next;
}
- if (!ds)
- {
+ if (!ds) {
spin_unlock_irqrestore(&divert_lock, flags);
return (-EINVAL);
}
@@ -369,12 +365,13 @@ int deleterule(int idx)
/* get a pointer to a specific rule number */
/*******************************************/
divert_rule *getruleptr(int idx)
-{ struct deflect_struc *ds = table_head;
+{
+ struct deflect_struc *ds = table_head;
if (idx < 0) return (NULL);
- while ((ds) && (idx >= 0))
- { if (!(idx--))
- { return (&ds->rule);
+ while ((ds) && (idx >= 0)) {
+ if (!(idx--)) {
+ return (&ds->rule);
break;
}
ds = ds->next;
@@ -386,7 +383,8 @@ divert_rule *getruleptr(int idx)
/* called from common module on an incoming call */
/*************************************************/
static int isdn_divert_icall(isdn_ctrl *ic)
-{ int retval = 0;
+{
+ int retval = 0;
unsigned long flags;
struct call_struc *cs = NULL;
struct deflect_struc *dv;
@@ -394,8 +392,8 @@ static int isdn_divert_icall(isdn_ctrl *ic)
u_char accept;
/* first check the internal deflection table */
- for (dv = table_head; dv; dv = dv->next)
- { /* scan table */
+ for (dv = table_head; dv; dv = dv->next) {
+ /* scan table */
if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
continue; /* call option check */
@@ -409,10 +407,10 @@ static int isdn_divert_icall(isdn_ctrl *ic)
p = dv->rule.my_msn;
p1 = ic->parm.setup.eazmsn;
accept = 0;
- while (*p)
- { /* complete compare */
- if (*p == '-')
- { accept = 1; /* call accepted */
+ while (*p) {
+ /* complete compare */
+ if (*p == '-') {
+ accept = 1; /* call accepted */
break;
}
if (*p++ != *p1++)
@@ -422,14 +420,15 @@ static int isdn_divert_icall(isdn_ctrl *ic)
} /* complete compare */
if (!accept) continue; /* not accepted */
- if ((strcmp(dv->rule.caller, "0")) || (ic->parm.setup.phone[0]))
- { p = dv->rule.caller;
+ if ((strcmp(dv->rule.caller, "0")) ||
+ (ic->parm.setup.phone[0])) {
+ p = dv->rule.caller;
p1 = ic->parm.setup.phone;
accept = 0;
- while (*p)
- { /* complete compare */
- if (*p == '-')
- { accept = 1; /* call accepted */
+ while (*p) {
+ /* complete compare */
+ if (*p == '-') {
+ accept = 1; /* call accepted */
break;
}
if (*p++ != *p1++)
@@ -440,10 +439,10 @@ static int isdn_divert_icall(isdn_ctrl *ic)
if (!accept) continue; /* not accepted */
}
- switch (dv->rule.action)
- { case DEFLECT_IGNORE:
- return (0);
- break;
+ switch (dv->rule.action) {
+ case DEFLECT_IGNORE:
+ return (0);
+ break;
case DEFLECT_ALERT:
case DEFLECT_PROCEED:
@@ -465,31 +464,29 @@ static int isdn_divert_icall(isdn_ctrl *ic)
cs->ics.parm.setup.screen = dv->rule.screen;
if (dv->rule.waittime)
cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
+ else if (dv->rule.action == DEFLECT_PROCEED)
+ cs->timer.expires = jiffies + (HZ * extern_wait_max);
else
- if (dv->rule.action == DEFLECT_PROCEED)
- cs->timer.expires = jiffies + (HZ * extern_wait_max);
- else
- cs->timer.expires = 0;
+ cs->timer.expires = 0;
cs->akt_state = dv->rule.action;
spin_lock_irqsave(&divert_lock, flags);
cs->divert_id = next_id++; /* new sequence number */
spin_unlock_irqrestore(&divert_lock, flags);
cs->prev = NULL;
- if (cs->akt_state == DEFLECT_ALERT)
- { strcpy(cs->deflect_dest, dv->rule.to_nr);
- if (!cs->timer.expires)
- { strcpy(ic->parm.setup.eazmsn, "Testtext direct");
+ if (cs->akt_state == DEFLECT_ALERT) {
+ strcpy(cs->deflect_dest, dv->rule.to_nr);
+ if (!cs->timer.expires) {
+ strcpy(ic->parm.setup.eazmsn,
+ "Testtext direct");
ic->parm.setup.screen = dv->rule.screen;
strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone));
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
retval = 5;
- }
- else
+ } else
retval = 1; /* alerting */
- }
- else
- { cs->deflect_dest[0] = '\0';
+ } else {
+ cs->deflect_dest[0] = '\0';
retval = 4; /* only proceed */
}
sprintf(cs->info, "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
@@ -505,8 +502,8 @@ static int isdn_divert_icall(isdn_ctrl *ic)
dv->rule.waittime,
cs->deflect_dest);
if ((dv->rule.action == DEFLECT_REPORT) ||
- (dv->rule.action == DEFLECT_REJECT))
- { put_info_buffer(cs->info);
+ (dv->rule.action == DEFLECT_REJECT)) {
+ put_info_buffer(cs->info);
kfree(cs); /* remove */
return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */
}
@@ -519,8 +516,8 @@ static int isdn_divert_icall(isdn_ctrl *ic)
break;
} /* scan_table */
- if (cs)
- { cs->prev = NULL;
+ if (cs) {
+ cs->prev = NULL;
spin_lock_irqsave(&divert_lock, flags);
cs->next = divert_head;
divert_head = cs;
@@ -529,21 +526,21 @@ static int isdn_divert_icall(isdn_ctrl *ic)
put_info_buffer(cs->info);
return (retval);
- }
- else
+ } else
return (0);
} /* isdn_divert_icall */
void deleteprocs(void)
-{ struct call_struc *cs, *cs1;
+{
+ struct call_struc *cs, *cs1;
unsigned long flags;
spin_lock_irqsave(&divert_lock, flags);
cs = divert_head;
divert_head = NULL;
- while (cs)
- { del_timer(&cs->timer);
+ while (cs) {
+ del_timer(&cs->timer);
cs1 = cs;
cs = cs->next;
kfree(cs1);
@@ -555,12 +552,13 @@ void deleteprocs(void)
/* put a address including address type into buffer */
/****************************************************/
static int put_address(char *st, u_char *p, int len)
-{ u_char retval = 0;
+{
+ u_char retval = 0;
u_char adr_typ = 0; /* network standard */
if (len < 2) return (retval);
- if (*p == 0xA1)
- { retval = *(++p) + 2; /* total length */
+ if (*p == 0xA1) {
+ retval = *(++p) + 2; /* total length */
if (retval > len) return (0); /* too short */
len = retval - 2; /* remaining length */
if (len < 3) return (0);
@@ -572,16 +570,13 @@ static int put_address(char *st, u_char *p, int len)
if (*p++ != 0x12) return (0);
if (*p > len) return (0); /* check number length */
len = *p++;
- }
- else
- if (*p == 0x80)
- { retval = *(++p) + 2; /* total length */
- if (retval > len) return (0);
- len = retval - 2;
- p++;
- }
- else
- return (0); /* invalid address information */
+ } else if (*p == 0x80) {
+ retval = *(++p) + 2; /* total length */
+ if (retval > len) return (0);
+ len = retval - 2;
+ p++;
+ } else
+ return (0); /* invalid address information */
sprintf(st, "%d ", adr_typ);
st += strlen(st);
@@ -598,7 +593,8 @@ static int put_address(char *st, u_char *p, int len)
/* report a successful interrogation */
/*************************************/
static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
-{ char *src = ic->parm.dss1_io.data;
+{
+ char *src = ic->parm.dss1_io.data;
int restlen = ic->parm.dss1_io.datalen;
int cnt = 1;
u_char n, n1;
@@ -608,50 +604,44 @@ static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
if (*src++ != 0x30) return (-101);
if ((n = *src++) > 0x81) return (-102); /* invalid length field */
restlen -= 2; /* remaining bytes */
- if (n == 0x80)
- { if (restlen < 2) return (-103);
+ if (n == 0x80) {
+ if (restlen < 2) return (-103);
if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-104);
restlen -= 2;
- }
+ } else if (n == 0x81) {
+ n = *src++;
+ restlen--;
+ if (n > restlen) return (-105);
+ restlen = n;
+ } else if (n > restlen)
+ return (-106);
else
- if (n == 0x81)
- { n = *src++;
- restlen--;
- if (n > restlen) return (-105);
- restlen = n;
- }
- else
- if (n > restlen) return (-106);
- else
- restlen = n; /* standard format */
+ restlen = n; /* standard format */
if (restlen < 3) return (-107); /* no procedure */
if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return (-108);
restlen -= 3;
if (restlen < 2) return (-109); /* list missing */
- if (*src == 0x31)
- { src++;
+ if (*src == 0x31) {
+ src++;
if ((n = *src++) > 0x81) return (-110); /* invalid length field */
restlen -= 2; /* remaining bytes */
- if (n == 0x80)
- { if (restlen < 2) return (-111);
+ if (n == 0x80) {
+ if (restlen < 2) return (-111);
if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-112);
restlen -= 2;
- }
+ } else if (n == 0x81) {
+ n = *src++;
+ restlen--;
+ if (n > restlen) return (-113);
+ restlen = n;
+ } else if (n > restlen)
+ return (-114);
else
- if (n == 0x81)
- { n = *src++;
- restlen--;
- if (n > restlen) return (-113);
- restlen = n;
- }
- else
- if (n > restlen) return (-114);
- else
- restlen = n; /* standard format */
+ restlen = n; /* standard format */
} /* result list header */
- while (restlen >= 2)
- { stp = st;
+ while (restlen >= 2) {
+ stp = st;
sprintf(stp, "%d 0x%lx %d %s ", DIVERT_REPORT, ic->parm.dss1_io.ll_id,
cnt++, divert_if.drv_to_name(ic->driver));
stp += strlen(stp);
@@ -674,8 +664,8 @@ static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
sprintf(stp, "%d ", (*p++) & 0xFF);
stp += strlen(stp);
n -= 6;
- if (n > 2)
- { if (*p++ != 0x30) continue;
+ if (n > 2) {
+ if (*p++ != 0x30) continue;
if (*p > (n - 2)) continue;
n = *p++;
if (!(n1 = put_address(stp, p, n & 0xFF))) continue;
@@ -692,58 +682,58 @@ static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
/* callback for protocol specific extensions */
/*********************************************/
static int prot_stat_callback(isdn_ctrl *ic)
-{ struct call_struc *cs, *cs1;
+{
+ struct call_struc *cs, *cs1;
int i;
unsigned long flags;
cs = divert_head; /* start of list */
cs1 = NULL;
- while (cs)
- { if (ic->driver == cs->ics.driver)
- { switch (cs->ics.arg)
- { case DSS1_CMD_INVOKE:
- if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
- (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id))
- { switch (ic->arg)
- { case DSS1_STAT_INVOKE_ERR:
- sprintf(cs->info, "128 0x%lx 0x%x\n",
- ic->parm.dss1_io.ll_id,
- ic->parm.dss1_io.timeout);
- put_info_buffer(cs->info);
- break;
-
- case DSS1_STAT_INVOKE_RES:
- switch (cs->ics.parm.dss1_io.proc)
- { case 7:
- case 8:
- put_info_buffer(cs->info);
- break;
-
- case 11:
- i = interrogate_success(ic, cs);
- if (i)
- sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT,
- ic->parm.dss1_io.ll_id, i);
- put_info_buffer(cs->info);
- break;
-
- default:
- printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc);
- break;
- }
-
+ while (cs) {
+ if (ic->driver == cs->ics.driver) {
+ switch (cs->ics.arg) {
+ case DSS1_CMD_INVOKE:
+ if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
+ (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) {
+ switch (ic->arg) {
+ case DSS1_STAT_INVOKE_ERR:
+ sprintf(cs->info, "128 0x%lx 0x%x\n",
+ ic->parm.dss1_io.ll_id,
+ ic->parm.dss1_io.timeout);
+ put_info_buffer(cs->info);
+ break;
+
+ case DSS1_STAT_INVOKE_RES:
+ switch (cs->ics.parm.dss1_io.proc) {
+ case 7:
+ case 8:
+ put_info_buffer(cs->info);
+ break;
+ case 11:
+ i = interrogate_success(ic, cs);
+ if (i)
+ sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT,
+ ic->parm.dss1_io.ll_id, i);
+ put_info_buffer(cs->info);
break;
default:
- printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg);
+ printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc);
break;
}
- cs1 = cs; /* remember structure */
- cs = NULL;
- continue; /* abort search */
- } /* id found */
- break;
+
+ break;
+
+ default:
+ printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg);
+ break;
+ }
+ cs1 = cs; /* remember structure */
+ cs = NULL;
+ continue; /* abort search */
+ } /* id found */
+ break;
case DSS1_CMD_INVOKE_ABORT:
printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
@@ -757,13 +747,12 @@ static int prot_stat_callback(isdn_ctrl *ic)
} /* driver ok */
}
- if (!cs1)
- { printk(KERN_WARNING "dss1_divert unhandled process\n");
+ if (!cs1) {
+ printk(KERN_WARNING "dss1_divert unhandled process\n");
return (0);
}
- if (cs1->ics.driver == -1)
- {
+ if (cs1->ics.driver == -1) {
spin_lock_irqsave(&divert_lock, flags);
del_timer(&cs1->timer);
if (cs1->prev)
@@ -784,20 +773,22 @@ static int prot_stat_callback(isdn_ctrl *ic)
/* status callback from HL */
/***************************/
static int isdn_divert_stat_callback(isdn_ctrl *ic)
-{ struct call_struc *cs, *cs1;
+{
+ struct call_struc *cs, *cs1;
unsigned long flags;
int retval;
retval = -1;
cs = divert_head; /* start of list */
- while (cs)
- { if ((ic->driver == cs->ics.driver) && (ic->arg == cs->ics.arg))
- { switch (ic->command)
- { case ISDN_STAT_DHUP:
- sprintf(cs->info, "129 0x%lx\n", cs->divert_id);
- del_timer(&cs->timer);
- cs->ics.driver = -1;
- break;
+ while (cs) {
+ if ((ic->driver == cs->ics.driver) &&
+ (ic->arg == cs->ics.arg)) {
+ switch (ic->command) {
+ case ISDN_STAT_DHUP:
+ sprintf(cs->info, "129 0x%lx\n", cs->divert_id);
+ del_timer(&cs->timer);
+ cs->ics.driver = -1;
+ break;
case ISDN_STAT_CAUSE:
sprintf(cs->info, "130 0x%lx %s\n", cs->divert_id, ic->parm.num);
@@ -818,8 +809,7 @@ static int isdn_divert_stat_callback(isdn_ctrl *ic)
}
cs1 = cs;
cs = cs->next;
- if (cs1->ics.driver == -1)
- {
+ if (cs1->ics.driver == -1) {
spin_lock_irqsave(&divert_lock, flags);
if (cs1->prev)
cs1->prev->next = cs1->next; /* forward link */
@@ -840,20 +830,19 @@ static int isdn_divert_stat_callback(isdn_ctrl *ic)
/********************/
int ll_callback(isdn_ctrl *ic)
{
- switch (ic->command)
- { case ISDN_STAT_ICALL:
+ switch (ic->command) {
+ case ISDN_STAT_ICALL:
case ISDN_STAT_ICALLW:
return (isdn_divert_icall(ic));
break;
case ISDN_STAT_PROT:
- if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO)
- { if (ic->arg != DSS1_STAT_INVOKE_BRD)
+ if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) {
+ if (ic->arg != DSS1_STAT_INVOKE_BRD)
return (prot_stat_callback(ic));
else
return (0); /* DSS1 invoke broadcast */
- }
- else
+ } else
return (-1); /* protocol not euro */
default:
diff --git a/drivers/isdn/divert/isdn_divert.h b/drivers/isdn/divert/isdn_divert.h
index 42f289320d2d..55033dd872c0 100644
--- a/drivers/isdn/divert/isdn_divert.h
+++ b/drivers/isdn/divert/isdn_divert.h
@@ -43,8 +43,8 @@
#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */
-typedef struct
-{ ulong drvid; /* driver ids, bit mapped */
+typedef struct {
+ ulong drvid; /* driver ids, bit mapped */
char my_msn[35]; /* desired msn, subaddr allowed */
char caller[35]; /* caller id, partial string with * + subaddr allowed */
char to_nr[35]; /* deflected to number incl. subaddress */
@@ -65,18 +65,18 @@ typedef struct
u_char waittime; /* maximum wait time for proceeding */
} divert_rule;
-typedef union
-{ int drv_version; /* return of driver version */
- struct
- { int drvid; /* id of driver */
+typedef union {
+ int drv_version; /* return of driver version */
+ struct {
+ int drvid; /* id of driver */
char drvnam[30]; /* name of driver */
} getid;
- struct
- { int ruleidx; /* index of rule */
+ struct {
+ int ruleidx; /* index of rule */
divert_rule rule; /* rule parms */
} getsetrule;
- struct
- { u_char subcmd; /* 0 = hangup/reject,
+ struct {
+ u_char subcmd; /* 0 = hangup/reject,
1 = alert,
2 = deflect */
ulong callid; /* id of call delivered by ascii output */
@@ -84,8 +84,8 @@ typedef union
else uus1 string (maxlen 31),
data from rule used if empty */
} fwd_ctrl;
- struct
- { int drvid; /* id of driver */
+ struct {
+ int drvid; /* id of driver */
u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */
ulong procid; /* process id returned when no error */
u_char service; /* basically coded service, 0 = all */
@@ -104,8 +104,8 @@ typedef union
/**************************************************/
/* structure keeping ascii info for device output */
/**************************************************/
-struct divert_info
-{ struct divert_info *next;
+struct divert_info {
+ struct divert_info *next;
ulong usage_cnt; /* number of files still to work */
char info_start[2]; /* info string start */
};
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index b18a92c32184..dde5e09e6267 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -1,5 +1,6 @@
menuconfig ISDN_DRV_GIGASET
tristate "Siemens Gigaset support"
+ depends on TTY
select CRC_CCITT
select BITREVERSE
help
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 6849a11a1b24..7c7814497e3e 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -467,11 +467,6 @@ void gigaset_freecs(struct cardstate *cs)
mutex_lock(&cs->mutex);
- if (!cs->bcs)
- goto f_cs;
- if (!cs->inbuf)
- goto f_bcs;
-
spin_lock_irqsave(&cs->lock, flags);
cs->running = 0;
spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are
@@ -507,17 +502,16 @@ void gigaset_freecs(struct cardstate *cs)
gig_dbg(DEBUG_INIT, "clearing at_state");
clear_at_state(&cs->at_state);
dealloc_temp_at_states(cs);
+ clear_events(cs);
tty_port_destroy(&cs->port);
/* fall through */
case 0: /* error in basic setup */
- clear_events(cs);
gig_dbg(DEBUG_INIT, "freeing inbuf");
kfree(cs->inbuf);
+ kfree(cs->bcs);
}
-f_bcs: gig_dbg(DEBUG_INIT, "freeing bcs[]");
- kfree(cs->bcs);
-f_cs: gig_dbg(DEBUG_INIT, "freeing cs");
+
mutex_unlock(&cs->mutex);
free_cs(cs);
}
@@ -687,19 +681,6 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
return NULL;
}
- gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
- cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
- if (!cs->bcs) {
- pr_err("out of memory\n");
- goto error;
- }
- gig_dbg(DEBUG_INIT, "allocating inbuf");
- cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
- if (!cs->inbuf) {
- pr_err("out of memory\n");
- goto error;
- }
-
cs->cs_init = 0;
cs->channels = channels;
cs->onechannel = onechannel;
@@ -729,6 +710,12 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
cs->mode = M_UNKNOWN;
cs->mstate = MS_UNINITIALIZED;
+ cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
+ cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
+ if (!cs->bcs || !cs->inbuf) {
+ pr_err("out of memory\n");
+ goto error;
+ }
++cs->cs_init;
gig_dbg(DEBUG_INIT, "setting up at_state");
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index 2e6963dc740e..7459b127ddd5 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -351,10 +351,11 @@ struct reply_t gigaset_tab_cid[] =
static const struct resp_type_t {
- unsigned char *response;
- int resp_code;
- int type;
-} resp_type[] =
+ char *response;
+ int resp_code;
+ int type;
+}
+resp_type[] =
{
{"OK", RSP_OK, RT_NOTHING},
{"ERROR", RSP_ERROR, RT_NOTHING},
@@ -374,11 +375,12 @@ static const struct resp_type_t {
};
static const struct zsau_resp_t {
- unsigned char *str;
- int code;
-} zsau_resp[] =
+ char *str;
+ int code;
+}
+zsau_resp[] =
{
- {"OUTGOING_CALL_PROCEEDING", ZSAU_OUTGOING_CALL_PROCEEDING},
+ {"OUTGOING_CALL_PROCEEDING", ZSAU_PROCEEDING},
{"CALL_DELIVERED", ZSAU_CALL_DELIVERED},
{"ACTIVE", ZSAU_ACTIVE},
{"DISCONNECT_IND", ZSAU_DISCONNECT_IND},
@@ -434,7 +436,7 @@ void gigaset_handle_modem_response(struct cardstate *cs)
len = cs->cbytes;
if (!len) {
/* ignore additional LFs/CRs (M10x config mode or cx100) */
- gig_dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[len]);
+ gig_dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[0]);
return;
}
cs->respdata[len] = 0;
@@ -707,27 +709,29 @@ static void schedule_init(struct cardstate *cs, int state)
cs->commands_pending = 1;
}
-/* Add "AT" to a command, add the cid, dle encode it, send the result to the
- hardware. */
-static void send_command(struct cardstate *cs, const char *cmd, int cid,
- int dle, gfp_t kmallocflags)
+/* send an AT command
+ * adding the "AT" prefix, cid and DLE encapsulation as appropriate
+ */
+static void send_command(struct cardstate *cs, const char *cmd,
+ struct at_state_t *at_state)
{
+ int cid = at_state->cid;
struct cmdbuf_t *cb;
size_t buflen;
buflen = strlen(cmd) + 12; /* DLE ( A T 1 2 3 4 5 <cmd> DLE ) \0 */
- cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, kmallocflags);
+ cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, GFP_ATOMIC);
if (!cb) {
dev_err(cs->dev, "%s: out of memory\n", __func__);
return;
}
if (cid > 0 && cid <= 65535)
cb->len = snprintf(cb->buf, buflen,
- dle ? "\020(AT%d%s\020)" : "AT%d%s",
+ cs->dle ? "\020(AT%d%s\020)" : "AT%d%s",
cid, cmd);
else
cb->len = snprintf(cb->buf, buflen,
- dle ? "\020(AT%s\020)" : "AT%s",
+ cs->dle ? "\020(AT%s\020)" : "AT%s",
cmd);
cb->offset = 0;
cb->next = NULL;
@@ -886,7 +890,7 @@ static void finish_shutdown(struct cardstate *cs)
gigaset_isdn_stop(cs);
}
- /* The rest is done by cleanup_cs () in user mode. */
+ /* The rest is done by cleanup_cs() in process context. */
cs->cmd_result = -ENODEV;
cs->waiting = 0;
@@ -976,10 +980,9 @@ exit:
}
static void handle_icall(struct cardstate *cs, struct bc_state *bcs,
- struct at_state_t **p_at_state)
+ struct at_state_t *at_state)
{
int retval;
- struct at_state_t *at_state = *p_at_state;
retval = gigaset_isdn_icall(at_state);
switch (retval) {
@@ -1176,7 +1179,7 @@ static void do_action(int action, struct cardstate *cs,
spin_unlock_irqrestore(&cs->lock, flags);
break;
case ACT_ICALL:
- handle_icall(cs, bcs, p_at_state);
+ handle_icall(cs, bcs, at_state);
break;
case ACT_FAILSDOWN:
dev_warn(cs->dev, "Could not shut down the device.\n");
@@ -1264,7 +1267,7 @@ static void do_action(int action, struct cardstate *cs,
cs->commands_pending = 1;
break;
}
- /* fall through */
+ /* bad cid: fall through */
case ACT_FAILCID:
cs->cur_at_seq = SEQ_NONE;
channel = cs->curchannel;
@@ -1339,7 +1342,6 @@ static void do_action(int action, struct cardstate *cs,
*p_resp_code = RSP_ERROR;
break;
}
- /*at_state->getstring = 1;*/
cs->gotfwver = 0;
break;
case ACT_GOTVER:
@@ -1471,7 +1473,6 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
int rcode;
int genresp = 0;
int resp_code = RSP_ERROR;
- int sendcid;
struct at_state_t *at_state;
int index;
int curact;
@@ -1499,7 +1500,6 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
at_state->ConState, ev->type);
bcs = at_state->bcs;
- sendcid = at_state->cid;
/* Setting the pointer to the dial array */
rep = at_state->replystruct;
@@ -1510,10 +1510,12 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
|| !at_state->timer_active) {
ev->type = RSP_NONE; /* old timeout */
gig_dbg(DEBUG_EVENT, "old timeout");
- } else if (!at_state->waiting)
- gig_dbg(DEBUG_EVENT, "timeout occurred");
- else
- gig_dbg(DEBUG_EVENT, "stopped waiting");
+ } else {
+ if (at_state->waiting)
+ gig_dbg(DEBUG_EVENT, "stopped waiting");
+ else
+ gig_dbg(DEBUG_EVENT, "timeout occurred");
+ }
}
spin_unlock_irqrestore(&cs->lock, flags);
@@ -1561,45 +1563,40 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
do_action(rep->action[curact], cs, bcs, &at_state, &p_command,
&genresp, &resp_code, ev);
if (!at_state)
- break; /* may be freed after disconnect */
+ /* at_state destroyed by disconnect */
+ return;
}
- if (at_state) {
- /* Jump to the next con-state regarding the array */
- if (rep->new_ConState >= 0)
- at_state->ConState = rep->new_ConState;
+ /* Jump to the next con-state regarding the array */
+ if (rep->new_ConState >= 0)
+ at_state->ConState = rep->new_ConState;
- if (genresp) {
- spin_lock_irqsave(&cs->lock, flags);
+ if (genresp) {
+ spin_lock_irqsave(&cs->lock, flags);
+ at_state->timer_expires = 0;
+ at_state->timer_active = 0;
+ spin_unlock_irqrestore(&cs->lock, flags);
+ gigaset_add_event(cs, at_state, resp_code, NULL, 0, NULL);
+ } else {
+ /* Send command to modem if not NULL... */
+ if (p_command) {
+ if (cs->connected)
+ send_command(cs, p_command, at_state);
+ else
+ gigaset_add_event(cs, at_state, RSP_NODEV,
+ NULL, 0, NULL);
+ }
+
+ spin_lock_irqsave(&cs->lock, flags);
+ if (!rep->timeout) {
at_state->timer_expires = 0;
at_state->timer_active = 0;
- spin_unlock_irqrestore(&cs->lock, flags);
- gigaset_add_event(cs, at_state, resp_code,
- NULL, 0, NULL);
- } else {
- /* Send command to modem if not NULL... */
- if (p_command) {
- if (cs->connected)
- send_command(cs, p_command,
- sendcid, cs->dle,
- GFP_ATOMIC);
- else
- gigaset_add_event(cs, at_state,
- RSP_NODEV,
- NULL, 0, NULL);
- }
-
- spin_lock_irqsave(&cs->lock, flags);
- if (!rep->timeout) {
- at_state->timer_expires = 0;
- at_state->timer_active = 0;
- } else if (rep->timeout > 0) { /* new timeout */
- at_state->timer_expires = rep->timeout * 10;
- at_state->timer_active = 1;
- ++at_state->timer_index;
- }
- spin_unlock_irqrestore(&cs->lock, flags);
+ } else if (rep->timeout > 0) { /* new timeout */
+ at_state->timer_expires = rep->timeout * 10;
+ at_state->timer_active = 1;
+ ++at_state->timer_index;
}
+ spin_unlock_irqrestore(&cs->lock, flags);
}
}
@@ -1693,6 +1690,11 @@ static void process_command_flags(struct cardstate *cs)
for (i = 0; i < cs->channels; ++i) {
bcs = cs->bcs + i;
if (bcs->at_state.pending_commands & PC_HUP) {
+ if (cs->dle) {
+ cs->curchannel = bcs->channel;
+ schedule_sequence(cs, &cs->at_state, SEQ_DLE0);
+ return;
+ }
bcs->at_state.pending_commands &= ~PC_HUP;
if (bcs->at_state.pending_commands & PC_CID) {
/* not yet dialing: PC_NOCID is sufficient */
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 8e2fc8f31d16..eb63a0f7a02a 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -111,11 +111,10 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
/* connection state */
#define ZSAU_NONE 0
-#define ZSAU_DISCONNECT_IND 4
-#define ZSAU_OUTGOING_CALL_PROCEEDING 1
#define ZSAU_PROCEEDING 1
#define ZSAU_CALL_DELIVERED 2
#define ZSAU_ACTIVE 3
+#define ZSAU_DISCONNECT_IND 4
#define ZSAU_NULL 5
#define ZSAU_DISCONNECT_REQ 6
#define ZSAU_UNKNOWN -1
@@ -183,18 +182,22 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define AT_NUM 7
/* variables in struct at_state_t */
+/* - numeric */
#define VAR_ZSAU 0
#define VAR_ZDLE 1
#define VAR_ZCTP 2
+/* total number */
#define VAR_NUM 3
-
+/* - string */
#define STR_NMBR 0
#define STR_ZCPN 1
#define STR_ZCON 2
#define STR_ZBC 3
#define STR_ZHLC 4
+/* total number */
#define STR_NUM 5
+/* event types */
#define EV_TIMEOUT -105
#define EV_IF_VER -106
#define EV_PROC_CIDMODE -107
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index 67abf3ff45e8..e2b539675b66 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -112,36 +112,6 @@ static int if_config(struct cardstate *cs, int *arg)
}
/*** the terminal driver ***/
-/* stolen from usbserial and some other tty drivers */
-
-static int if_open(struct tty_struct *tty, struct file *filp);
-static void if_close(struct tty_struct *tty, struct file *filp);
-static int if_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
-static int if_write_room(struct tty_struct *tty);
-static int if_chars_in_buffer(struct tty_struct *tty);
-static void if_throttle(struct tty_struct *tty);
-static void if_unthrottle(struct tty_struct *tty);
-static void if_set_termios(struct tty_struct *tty, struct ktermios *old);
-static int if_tiocmget(struct tty_struct *tty);
-static int if_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear);
-static int if_write(struct tty_struct *tty,
- const unsigned char *buf, int count);
-
-static const struct tty_operations if_ops = {
- .open = if_open,
- .close = if_close,
- .ioctl = if_ioctl,
- .write = if_write,
- .write_room = if_write_room,
- .chars_in_buffer = if_chars_in_buffer,
- .set_termios = if_set_termios,
- .throttle = if_throttle,
- .unthrottle = if_unthrottle,
- .tiocmget = if_tiocmget,
- .tiocmset = if_tiocmset,
-};
static int if_open(struct tty_struct *tty, struct file *filp)
{
@@ -164,7 +134,7 @@ static int if_open(struct tty_struct *tty, struct file *filp)
if (cs->port.count == 1) {
tty_port_tty_set(&cs->port, tty);
- tty->low_latency = 1;
+ cs->port.low_latency = 1;
}
mutex_unlock(&cs->mutex);
@@ -355,7 +325,7 @@ done:
static int if_write_room(struct tty_struct *tty)
{
struct cardstate *cs = tty->driver_data;
- int retval = -ENODEV;
+ int retval;
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
@@ -498,6 +468,20 @@ out:
mutex_unlock(&cs->mutex);
}
+static const struct tty_operations if_ops = {
+ .open = if_open,
+ .close = if_close,
+ .ioctl = if_ioctl,
+ .write = if_write,
+ .write_room = if_write_room,
+ .chars_in_buffer = if_chars_in_buffer,
+ .set_termios = if_set_termios,
+ .throttle = if_throttle,
+ .unthrottle = if_unthrottle,
+ .tiocmget = if_tiocmget,
+ .tiocmset = if_tiocmset,
+};
+
/* wakeup tasklet for the write operation */
static void if_wake(unsigned long data)
@@ -562,16 +546,8 @@ void gigaset_if_free(struct cardstate *cs)
void gigaset_if_receive(struct cardstate *cs,
unsigned char *buffer, size_t len)
{
- struct tty_struct *tty = tty_port_tty_get(&cs->port);
-
- if (tty == NULL) {
- gig_dbg(DEBUG_IF, "receive on closed device");
- return;
- }
-
- tty_insert_flip_string(tty, buffer, len);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_insert_flip_string(&cs->port, buffer, len);
+ tty_flip_buffer_push(&cs->port);
}
EXPORT_SYMBOL_GPL(gigaset_if_receive);
diff --git a/drivers/isdn/hardware/eicon/divacapi.h b/drivers/isdn/hardware/eicon/divacapi.h
index 3942efbbfb58..a315a2914d70 100644
--- a/drivers/isdn/hardware/eicon/divacapi.h
+++ b/drivers/isdn/hardware/eicon/divacapi.h
@@ -422,11 +422,11 @@ struct _DIVA_CAPI_ADAPTER {
#define LAPD 6 /* lapd (Q.921) */
#define X25_L2 7 /* x.25 layer-2 */
#define V120_L2 8 /* V.120 layer-2 protocol */
-#define V42_IN 9 /* V.42 layer-2 protocol, incomming */
+#define V42_IN 9 /* V.42 layer-2 protocol, incoming */
#define V42 10 /* V.42 layer-2 protocol */
#define MDM_ATP 11 /* AT Parser built in the L2 */
#define X75_V42BIS 12 /* ISO7776 (X.75 SLP) modified to support V.42 bis compression */
-#define RTPL2_IN 13 /* RTP layer-2 protocol, incomming */
+#define RTPL2_IN 13 /* RTP layer-2 protocol, incoming */
#define RTPL2 14 /* RTP layer-2 protocol */
#define V120_V42BIS 15 /* V.120 layer-2 protocol supporting V.42 bis compression */
@@ -1125,7 +1125,7 @@ extern word li_total_channels;
| Direction | word | Enable compression/decompression for |
| | | 0: All direction |
| | | 1: disable outgoing data |
- | | | 2: disable incomming data |
+ | | | 2: disable incoming data |
| | | 3: disable both direction (default) |
+---------------------+------+-----------------------------------------+
| Number of code | word | Parameter P1 of V.42bis in accordance |
diff --git a/drivers/isdn/hardware/eicon/pc.h b/drivers/isdn/hardware/eicon/pc.h
index 889dc984bbca..329c0c26abfb 100644
--- a/drivers/isdn/hardware/eicon/pc.h
+++ b/drivers/isdn/hardware/eicon/pc.h
@@ -419,11 +419,11 @@ struct dual
#define LAPD 6 /* lapd (Q.921) */
#define X25_L2 7 /* x.25 layer-2 */
#define V120_L2 8 /* V.120 layer-2 protocol */
-#define V42_IN 9 /* V.42 layer-2 protocol, incomming */
+#define V42_IN 9 /* V.42 layer-2 protocol, incoming */
#define V42 10 /* V.42 layer-2 protocol */
#define MDM_ATP 11 /* AT Parser built in the L2 */
#define X75_V42BIS 12 /* x.75 with V.42bis */
-#define RTPL2_IN 13 /* RTP layer-2 protocol, incomming */
+#define RTPL2_IN 13 /* RTP layer-2 protocol, incoming */
#define RTPL2 14 /* RTP layer-2 protocol */
#define V120_V42BIS 15 /* V.120 asynchronous mode supporting V.42bis compression */
#define LISTENER 27 /* Layer 2 to listen line */
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig
index eadc1cd34a20..b8611e3e5e74 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -76,6 +76,7 @@ config MISDN_NETJET
tristate "Support for NETJet cards"
depends on MISDN
depends on PCI
+ depends on TTY
select MISDN_IPAC
select ISDN_HDLC
select ISDN_I4L
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 70ecd0c19500..5313c9ea44dc 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -389,8 +389,8 @@ config HISAX_TELES_CS
comment "HiSax sub driver modules"
config HISAX_ST5481
- tristate "ST5481 USB ISDN modem (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
+ tristate "ST5481 USB ISDN modem"
+ depends on USB
select ISDN_HDLC
select CRC_CCITT
select BITREVERSE
@@ -399,20 +399,19 @@ config HISAX_ST5481
e.g. the BeWan Gazel 128 USB
config HISAX_HFCUSB
- tristate "HFC USB based ISDN modems (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
+ tristate "HFC USB based ISDN modems"
+ depends on USB
help
This enables the driver for HFC USB based ISDN modems.
config HISAX_HFC4S8S
- tristate "HFC-4S/8S based ISDN cards (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "HFC-4S/8S based ISDN cards"
help
This enables the driver for HFC-4S/8S based ISDN cards.
config HISAX_FRITZ_PCIPNP
- tristate "AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "AVM Fritz!Card PCI/PCIv2/PnP support"
+ depends on PCI
help
This enables the driver for the AVM Fritz!Card PCI,
Fritz!Card PCI v2 and Fritz!Card PnP.
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index e2a945ee9f05..b87d9e577be2 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -876,7 +876,7 @@ isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue
* of the mapping (di,ch)<->minor, happen during the sleep? --he
*/
int
-isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
+isdn_readbchan_tty(int di, int channel, struct tty_port *port, int cisco_hack)
{
int count;
int count_pull;
@@ -891,7 +891,7 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
return 0;
- len = tty_buffer_request_room(tty, dev->drv[di]->rcvcount[channel]);
+ len = tty_buffer_request_room(port, dev->drv[di]->rcvcount[channel]);
if (len == 0)
return len;
@@ -912,7 +912,7 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
while ((count_pull < skb->len) && (len > 0)) {
/* push every character but the last to the tty buffer directly */
if (count_put)
- tty_insert_flip_char(tty, last, TTY_NORMAL);
+ tty_insert_flip_char(port, last, TTY_NORMAL);
len--;
if (dev->drv[di]->DLEflag & DLEmask) {
last = DLE;
@@ -940,7 +940,7 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
}
count_put = count_pull;
if (count_put > 1)
- tty_insert_flip_string(tty, skb->data, count_put - 1);
+ tty_insert_flip_string(port, skb->data, count_put - 1);
last = skb->data[count_put - 1];
len -= count_put;
#ifdef CONFIG_ISDN_AUDIO
@@ -952,16 +952,16 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
* Now we can dequeue it.
*/
if (cisco_hack)
- tty_insert_flip_char(tty, last, 0xFF);
+ tty_insert_flip_char(port, last, 0xFF);
else
- tty_insert_flip_char(tty, last, TTY_NORMAL);
+ tty_insert_flip_char(port, last, TTY_NORMAL);
#ifdef CONFIG_ISDN_AUDIO
ISDN_AUDIO_SKB_LOCK(skb) = 0;
#endif
skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
dev_kfree_skb(skb);
} else {
- tty_insert_flip_char(tty, last, TTY_NORMAL);
+ tty_insert_flip_char(port, last, TTY_NORMAL);
/* Not yet emptied this buff, so it
* must stay in the queue, for further calls
* but we pull off the data we got until now.
diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h
index 9a471f62e1d4..2260ef07ab9c 100644
--- a/drivers/isdn/i4l/isdn_common.h
+++ b/drivers/isdn/i4l/isdn_common.h
@@ -37,7 +37,7 @@ extern void isdn_timer_ctrl(int tf, int onoff);
extern void isdn_unexclusive_channel(int di, int ch);
extern int isdn_getnum(char **);
extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
-extern int isdn_readbchan_tty(int, int, struct tty_struct *, int);
+extern int isdn_readbchan_tty(int, int, struct tty_port *, int);
extern int isdn_get_free_channel(int, int, int, int, int, char *);
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
extern int register_isdn(isdn_if *i);
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index e09dc8a5e743..d8a7d8323414 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -60,18 +60,14 @@ static int si2bit[8] =
static int
isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
{
+ struct tty_port *port = &info->port;
int c;
int len;
- struct tty_struct *tty;
char last;
if (!info->online)
return 0;
- tty = info->port.tty;
- if (!tty)
- return 0;
-
if (!(info->mcr & UART_MCR_RTS))
return 0;
@@ -81,7 +77,7 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
#endif
;
- c = tty_buffer_request_room(tty, len);
+ c = tty_buffer_request_room(port, len);
if (c < len)
return 0;
@@ -91,25 +87,25 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
unsigned char *dp = skb->data;
while (--l) {
if (*dp == DLE)
- tty_insert_flip_char(tty, DLE, 0);
- tty_insert_flip_char(tty, *dp++, 0);
+ tty_insert_flip_char(port, DLE, 0);
+ tty_insert_flip_char(port, *dp++, 0);
}
if (*dp == DLE)
- tty_insert_flip_char(tty, DLE, 0);
+ tty_insert_flip_char(port, DLE, 0);
last = *dp;
} else {
#endif
if (len > 1)
- tty_insert_flip_string(tty, skb->data, len - 1);
+ tty_insert_flip_string(port, skb->data, len - 1);
last = skb->data[len - 1];
#ifdef CONFIG_ISDN_AUDIO
}
#endif
if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
- tty_insert_flip_char(tty, last, 0xFF);
+ tty_insert_flip_char(port, last, 0xFF);
else
- tty_insert_flip_char(tty, last, TTY_NORMAL);
- tty_flip_buffer_push(tty);
+ tty_insert_flip_char(port, last, TTY_NORMAL);
+ tty_flip_buffer_push(port);
kfree_skb(skb);
return 1;
@@ -126,7 +122,6 @@ isdn_tty_readmodem(void)
int midx;
int i;
int r;
- struct tty_struct *tty;
modem_info *info;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
@@ -144,20 +139,21 @@ isdn_tty_readmodem(void)
if ((info->vonline & 1) && (info->emu.vpar[1]))
isdn_audio_eval_silence(info);
#endif
- tty = info->port.tty;
- if (tty) {
- if (info->mcr & UART_MCR_RTS) {
- /* CISCO AsyncPPP Hack */
- if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
- r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
- else
- r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
- if (r)
- tty_flip_buffer_push(tty);
- } else
- r = 1;
+ if (info->mcr & UART_MCR_RTS) {
+ /* CISCO AsyncPPP Hack */
+ if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
+ r = isdn_readbchan_tty(info->isdn_driver,
+ info->isdn_channel,
+ &info->port, 0);
+ else
+ r = isdn_readbchan_tty(info->isdn_driver,
+ info->isdn_channel,
+ &info->port, 1);
+ if (r)
+ tty_flip_buffer_push(&info->port);
} else
r = 1;
+
if (r) {
info->rcvsched = 0;
resched = 1;
@@ -2229,7 +2225,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
void
isdn_tty_at_cout(char *msg, modem_info *info)
{
- struct tty_struct *tty;
+ struct tty_port *port = &info->port;
atemu *m = &info->emu;
char *p;
char c;
@@ -2246,15 +2242,14 @@ isdn_tty_at_cout(char *msg, modem_info *info)
l = strlen(msg);
spin_lock_irqsave(&info->readlock, flags);
- tty = info->port.tty;
- if ((info->port.flags & ASYNC_CLOSING) || (!tty)) {
+ if (port->flags & ASYNC_CLOSING) {
spin_unlock_irqrestore(&info->readlock, flags);
return;
}
/* use queue instead of direct, if online and */
/* data is in queue or buffer is full */
- if (info->online && ((tty_buffer_request_room(tty, l) < l) ||
+ if (info->online && ((tty_buffer_request_room(port, l) < l) ||
!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) {
skb = alloc_skb(l, GFP_ATOMIC);
if (!skb) {
@@ -2285,7 +2280,7 @@ isdn_tty_at_cout(char *msg, modem_info *info)
if (skb) {
*sp++ = c;
} else {
- if (tty_insert_flip_char(tty, c, TTY_NORMAL) == 0)
+ if (tty_insert_flip_char(port, c, TTY_NORMAL) == 0)
break;
}
}
@@ -2299,7 +2294,7 @@ isdn_tty_at_cout(char *msg, modem_info *info)
} else {
spin_unlock_irqrestore(&info->readlock, flags);
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(port);
}
}
diff --git a/drivers/isdn/i4l/isdn_x25iface.h b/drivers/isdn/i4l/isdn_x25iface.h
index 0b26e3b336e7..ca08e082cf7c 100644
--- a/drivers/isdn/i4l/isdn_x25iface.h
+++ b/drivers/isdn/i4l/isdn_x25iface.h
@@ -19,7 +19,6 @@
#endif
#include <linux/skbuff.h>
-#include <linux/wanrouter.h>
#include <linux/isdn.h>
#include <linux/concap.h>
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
index 3e245712bba7..da30c5cb9609 100644
--- a/drivers/isdn/mISDN/core.c
+++ b/drivers/isdn/mISDN/core.c
@@ -168,13 +168,13 @@ static struct class mISDN_class = {
};
static int
-_get_mdevice(struct device *dev, void *id)
+_get_mdevice(struct device *dev, const void *id)
{
struct mISDNdevice *mdev = dev_to_mISDN(dev);
if (!mdev)
return 0;
- if (mdev->id != *(u_int *)id)
+ if (mdev->id != *(const u_int *)id)
return 0;
return 1;
}
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index f8e405c383a0..2c0d2c2bf946 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -689,7 +689,7 @@ l1oip_socket_thread(void *data)
hc->sin_remote.sin_addr.s_addr = htonl(hc->remoteip);
hc->sin_remote.sin_port = htons((unsigned short)hc->remoteport);
- /* bind to incomming port */
+ /* bind to incoming port */
if (socket->ops->bind(socket, (struct sockaddr *)&hc->sin_local,
sizeof(hc->sin_local))) {
printk(KERN_ERR "%s: Failed to bind socket to port %d.\n",
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c
index 5f21f629b7ae..deda591f70b9 100644
--- a/drivers/isdn/mISDN/stack.c
+++ b/drivers/isdn/mISDN/stack.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/mISDNif.h>
#include <linux/kthread.h>
+#include <linux/sched.h>
#include "core.h"
static u_int *debug;
@@ -202,6 +203,9 @@ static int
mISDNStackd(void *data)
{
struct mISDNstack *st = data;
+#ifdef MISDN_MSG_STATS
+ cputime_t utime, stime;
+#endif
int err = 0;
sigfillset(&current->blocked);
@@ -303,9 +307,10 @@ mISDNStackd(void *data)
"msg %d sleep %d stopped\n",
dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt,
st->stopped_cnt);
+ task_cputime(st->thread, &utime, &stime);
printk(KERN_DEBUG
"mISDNStackd daemon for %s utime(%ld) stime(%ld)\n",
- dev_name(&st->dev->dev), st->thread->utime, st->thread->stime);
+ dev_name(&st->dev->dev), utime, stime);
printk(KERN_DEBUG
"mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n",
dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw);
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index b58bc8a14b9c..4469b441b785 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -154,7 +154,7 @@ config LEDS_HP6XX
config LEDS_PCA9532
tristate "LED driver for PCA9532 dimmer"
depends on LEDS_CLASS
- depends on I2C && INPUT && EXPERIMENTAL
+ depends on I2C && INPUT
help
This option enables support for NXP pca9532
LED controller. It is generally only useful
diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig
index 34ae49dc557c..89875ea19ade 100644
--- a/drivers/lguest/Kconfig
+++ b/drivers/lguest/Kconfig
@@ -1,6 +1,6 @@
config LGUEST
tristate "Linux hypervisor example code"
- depends on X86_32 && EXPERIMENTAL && EVENTFD
+ depends on X86_32 && EVENTFD && TTY
select HVC_DRIVER
---help---
This is a very simple module which allows you to run
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index a555da64224e..696238b9f0f7 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -278,7 +278,7 @@ config PMAC_RACKMETER
config SENSORS_AMS
tristate "Apple Motion Sensor driver"
- depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
+ depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C)
select INPUT_POLLDEV
help
Support for the motion sensor included in PowerBooks. Includes
diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c
index 35ef6e2582b8..3024685e4cca 100644
--- a/drivers/macintosh/windfarm_pm112.c
+++ b/drivers/macintosh/windfarm_pm112.c
@@ -681,7 +681,7 @@ static int __init wf_pm112_init(void)
/* Count the number of CPU cores */
nr_cores = 0;
- for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+ for_each_node_by_type(cpu, "cpu")
++nr_cores;
printk(KERN_INFO "windfarm: initializing for dual-core desktop G5\n");
diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c
index 6e5585357cd3..2f506b9d5a52 100644
--- a/drivers/macintosh/windfarm_pm72.c
+++ b/drivers/macintosh/windfarm_pm72.c
@@ -804,7 +804,7 @@ static int __init wf_pm72_init(void)
/* Count the number of CPU cores */
nr_chips = 0;
- for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+ for_each_node_by_type(cpu, "cpu")
++nr_chips;
if (nr_chips > NR_CHIPS)
nr_chips = NR_CHIPS;
diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c
index 844003fb4ef0..0b9a79b2f48a 100644
--- a/drivers/macintosh/windfarm_rm31.c
+++ b/drivers/macintosh/windfarm_rm31.c
@@ -696,7 +696,7 @@ static int __init wf_rm31_init(void)
/* Count the number of CPU cores */
nr_chips = 0;
- for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+ for_each_node_by_type(cpu, "cpu")
++nr_chips;
if (nr_chips > NR_CHIPS)
nr_chips = NR_CHIPS;
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
new file mode 100644
index 000000000000..9545c9f03809
--- /dev/null
+++ b/drivers/mailbox/Kconfig
@@ -0,0 +1,19 @@
+menuconfig MAILBOX
+ bool "Mailbox Hardware Support"
+ help
+ Mailbox is a framework to control hardware communication between
+ on-chip processors through queued messages and interrupt driven
+ signals. Say Y if your platform supports hardware mailboxes.
+
+if MAILBOX
+config PL320_MBOX
+ bool "ARM PL320 Mailbox"
+ depends on ARM_AMBA
+ help
+ An implementation of the ARM PL320 Interprocessor Communication
+ Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
+ send short messages between Highbank's A9 cores and the EnergyCore
+ Management Engine, primarily for cpufreq. Say Y here if you want
+ to use the PL320 IPCM support.
+
+endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
new file mode 100644
index 000000000000..543ad6a79505
--- /dev/null
+++ b/drivers/mailbox/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
new file mode 100644
index 000000000000..c45b3aedafba
--- /dev/null
+++ b/drivers/mailbox/pl320-ipc.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <linux/mailbox.h>
+
+#define IPCMxSOURCE(m) ((m) * 0x40)
+#define IPCMxDSET(m) (((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m) (((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m) (((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m) (((m) * 0x40) + 0x010)
+#define IPCMxMSET(m) (((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m) (((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m) (((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m) (((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr) (((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq) (((irq) * 8) + 0x800)
+#define IPCMRIS(irq) (((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n) (1 << (n))
+#define IPC_TX_MBOX 1
+#define IPC_RX_MBOX 2
+
+#define CHAN_MASK(n) (1 << (n))
+#define A9_SOURCE 1
+#define M3_SOURCE 0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+ __raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+ __raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+ __raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+ __raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+ int i;
+ for (i = 0; i < 7; i++)
+ __raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+ __raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+ int i;
+ for (i = 0; i < 7; i++)
+ data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+ return data[1];
+}
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int pl320_ipc_transmit(u32 *data)
+{
+ int ret;
+
+ mutex_lock(&ipc_m1_lock);
+
+ init_completion(&ipc_completion);
+ __ipc_send(IPC_TX_MBOX, data);
+ ret = wait_for_completion_timeout(&ipc_completion,
+ msecs_to_jiffies(1000));
+ if (ret == 0) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ ret = __ipc_rcv(IPC_TX_MBOX, data);
+out:
+ mutex_unlock(&ipc_m1_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pl320_ipc_transmit);
+
+static irqreturn_t ipc_handler(int irq, void *dev)
+{
+ u32 irq_stat;
+ u32 data[7];
+
+ irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+ if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
+ __raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+ complete(&ipc_completion);
+ }
+ if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+ __ipc_rcv(IPC_RX_MBOX, data);
+ atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+ __raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+ }
+
+ return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(pl320_ipc_register_notifier);
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(pl320_ipc_unregister_notifier);
+
+static int __init pl320_probe(struct amba_device *adev,
+ const struct amba_id *id)
+{
+ int ret;
+
+ ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+ if (ipc_base == NULL)
+ return -ENOMEM;
+
+ __raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+
+ ipc_irq = adev->irq[0];
+ ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+ if (ret < 0)
+ goto err;
+
+ /* Init slow mailbox */
+ __raw_writel(CHAN_MASK(A9_SOURCE),
+ ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+ __raw_writel(CHAN_MASK(M3_SOURCE),
+ ipc_base + IPCMxDSET(IPC_TX_MBOX));
+ __raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+ ipc_base + IPCMxMSET(IPC_TX_MBOX));
+
+ /* Init receive mailbox */
+ __raw_writel(CHAN_MASK(M3_SOURCE),
+ ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+ __raw_writel(CHAN_MASK(A9_SOURCE),
+ ipc_base + IPCMxDSET(IPC_RX_MBOX));
+ __raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+ ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+ return 0;
+err:
+ iounmap(ipc_base);
+ return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+ {
+ .id = 0x00041320,
+ .mask = 0x000fffff,
+ },
+ { 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+ .drv = {
+ .name = "pl320",
+ },
+ .id_table = pl320_ids,
+ .probe = pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+ return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c
index d247a35da3c6..7b17a1fdeaf9 100644
--- a/drivers/md/persistent-data/dm-transaction-manager.c
+++ b/drivers/md/persistent-data/dm-transaction-manager.c
@@ -25,8 +25,8 @@ struct shadow_info {
/*
* It would be nice if we scaled with the size of transaction.
*/
-#define HASH_SIZE 256
-#define HASH_MASK (HASH_SIZE - 1)
+#define DM_HASH_SIZE 256
+#define DM_HASH_MASK (DM_HASH_SIZE - 1)
struct dm_transaction_manager {
int is_clone;
@@ -36,7 +36,7 @@ struct dm_transaction_manager {
struct dm_space_map *sm;
spinlock_t lock;
- struct hlist_head buckets[HASH_SIZE];
+ struct hlist_head buckets[DM_HASH_SIZE];
};
/*----------------------------------------------------------------*/
@@ -44,7 +44,7 @@ struct dm_transaction_manager {
static int is_shadow(struct dm_transaction_manager *tm, dm_block_t b)
{
int r = 0;
- unsigned bucket = dm_hash_block(b, HASH_MASK);
+ unsigned bucket = dm_hash_block(b, DM_HASH_MASK);
struct shadow_info *si;
struct hlist_node *n;
@@ -71,7 +71,7 @@ static void insert_shadow(struct dm_transaction_manager *tm, dm_block_t b)
si = kmalloc(sizeof(*si), GFP_NOIO);
if (si) {
si->where = b;
- bucket = dm_hash_block(b, HASH_MASK);
+ bucket = dm_hash_block(b, DM_HASH_MASK);
spin_lock(&tm->lock);
hlist_add_head(&si->hlist, tm->buckets + bucket);
spin_unlock(&tm->lock);
@@ -86,7 +86,7 @@ static void wipe_shadow_table(struct dm_transaction_manager *tm)
int i;
spin_lock(&tm->lock);
- for (i = 0; i < HASH_SIZE; i++) {
+ for (i = 0; i < DM_HASH_SIZE; i++) {
bucket = tm->buckets + i;
hlist_for_each_entry_safe(si, n, tmp, bucket, hlist)
kfree(si);
@@ -115,7 +115,7 @@ static struct dm_transaction_manager *dm_tm_create(struct dm_block_manager *bm,
tm->sm = sm;
spin_lock_init(&tm->lock);
- for (i = 0; i < HASH_SIZE; i++)
+ for (i = 0; i < DM_HASH_SIZE; i++)
INIT_HLIST_HEAD(tm->buckets + i);
return tm;
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 4ef0d80b57f4..7f5a7cac6dc7 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -79,8 +79,7 @@ config MEDIA_RC_SUPPORT
#
config MEDIA_CONTROLLER
- bool "Media Controller API (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "Media Controller API"
depends on MEDIA_CAMERA_SUPPORT
---help---
Enable the media controller API used to query media devices internal
@@ -100,8 +99,8 @@ config VIDEO_DEV
default y
config VIDEO_V4L2_SUBDEV_API
- bool "V4L2 sub-device userspace API (EXPERIMENTAL)"
- depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL
+ bool "V4L2 sub-device userspace API"
+ depends on VIDEO_DEV && MEDIA_CONTROLLER
---help---
Enables the V4L2 sub-device pad-level userspace API used to configure
video format, size and frame rate between hardware blocks.
@@ -135,6 +134,12 @@ config DVB_NET
You may want to disable the network support on embedded devices. If
unsure say Y.
+# This Kconfig option is used by both PCI and USB drivers
+config TTPCI_EEPROM
+ tristate
+ depends on I2C
+ default n
+
source "drivers/media/dvb-core/Kconfig"
comment "Media drivers"
@@ -158,17 +163,20 @@ source "drivers/media/firewire/Kconfig"
# Common driver options
source "drivers/media/common/Kconfig"
+comment "Media ancillary drivers (tuners, sensors, i2c, frontends)"
+
#
# Ancillary drivers (tuners, i2c, frontends)
#
config MEDIA_SUBDRV_AUTOSELECT
- bool "Autoselect tuners and i2c modules to build"
+ bool "Autoselect ancillary drivers (tuners, sensors, i2c, frontends)"
depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT
default y
help
- By default, a media driver auto-selects all possible i2c
- devices that are used by any of the supported devices.
+ By default, a media driver auto-selects all possible ancillary
+ devices such as tuners, sensors, video encoders/decoders and
+ frontends, that are used by any of the supported devices.
This is generally the right thing to do, except when there
are strict constraints with regards to the kernel size,
@@ -177,12 +185,10 @@ config MEDIA_SUBDRV_AUTOSELECT
Use this option with care, as deselecting ancillary drivers which
are, in fact, necessary will result in the lack of the needed
functionality for your device (it may not tune or may not have
- the need demodulers).
+ the needed demodulators).
If unsure say Y.
-comment "Media ancillary drivers (tuners, sensors, i2c, frontends)"
-
source "drivers/media/i2c/Kconfig"
source "drivers/media/tuners/Kconfig"
source "drivers/media/dvb-frontends/Kconfig"
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index d2a436ce77f8..56c25e6299e9 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -5,6 +5,17 @@ config MEDIA_COMMON_OPTIONS
comment "common driver options"
depends on MEDIA_COMMON_OPTIONS
+config VIDEO_CX2341X
+ tristate
+
+config VIDEO_BTCX
+ depends on PCI
+ tristate
+
+config VIDEO_TVEEPROM
+ tristate
+ depends on I2C
+
source "drivers/media/common/b2c2/Kconfig"
source "drivers/media/common/saa7146/Kconfig"
source "drivers/media/common/siano/Kconfig"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index b8e2e3a33a31..8f8d18755d15 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1 +1,4 @@
obj-y += b2c2/ saa7146/ siano/
+obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
+obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
+obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
diff --git a/drivers/media/i2c/btcx-risc.c b/drivers/media/common/btcx-risc.c
index ac1b2687a20d..ac1b2687a20d 100644
--- a/drivers/media/i2c/btcx-risc.c
+++ b/drivers/media/common/btcx-risc.c
diff --git a/drivers/media/i2c/btcx-risc.h b/drivers/media/common/btcx-risc.h
index f8bc6e8e7b51..f8bc6e8e7b51 100644
--- a/drivers/media/i2c/btcx-risc.h
+++ b/drivers/media/common/btcx-risc.h
diff --git a/drivers/media/i2c/cx2341x.c b/drivers/media/common/cx2341x.c
index 103ef6bad2e2..103ef6bad2e2 100644
--- a/drivers/media/i2c/cx2341x.c
+++ b/drivers/media/common/cx2341x.c
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index b3890bd49df6..eda01bc68ab2 100644
--- a/drivers/media/common/saa7146/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -105,7 +105,7 @@ void saa7146_buffer_finish(struct saa7146_dev *dev,
}
q->curr->vb.state = state;
- do_gettimeofday(&q->curr->vb.ts);
+ v4l2_get_timestamp(&q->curr->vb.ts);
wake_up(&q->curr->vb.done);
q->curr = NULL;
@@ -265,8 +265,7 @@ static int fops_release(struct file *file)
DEB_EE("file:%p\n", file);
- if (mutex_lock_interruptible(vdev->lock))
- return -ERESTARTSYS;
+ mutex_lock(vdev->lock);
if (vdev->vfl_type == VFL_TYPE_VBI) {
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
diff --git a/drivers/media/i2c/tveeprom.c b/drivers/media/common/tveeprom.c
index 3b6cf034976a..cc1e172dfece 100644
--- a/drivers/media/i2c/tveeprom.c
+++ b/drivers/media/common/tveeprom.c
@@ -96,170 +96,170 @@ static struct HAUPPAUGE_TUNER
hauppauge_tuner[] =
{
/* 0-9 */
- { TUNER_ABSENT, "None" },
- { TUNER_ABSENT, "External" },
- { TUNER_ABSENT, "Unspecified" },
- { TUNER_PHILIPS_PAL, "Philips FI1216" },
- { TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
- { TUNER_PHILIPS_NTSC, "Philips FI1236" },
- { TUNER_PHILIPS_PAL_I, "Philips FI1246" },
+ { TUNER_ABSENT, "None" },
+ { TUNER_ABSENT, "External" },
+ { TUNER_ABSENT, "Unspecified" },
+ { TUNER_PHILIPS_PAL, "Philips FI1216" },
+ { TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
+ { TUNER_PHILIPS_NTSC, "Philips FI1236" },
+ { TUNER_PHILIPS_PAL_I, "Philips FI1246" },
{ TUNER_PHILIPS_PAL_DK, "Philips FI1256" },
- { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" },
- { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
+ { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" },
+ { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
/* 10-19 */
- { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" },
- { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
+ { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" },
+ { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
{ TUNER_PHILIPS_PAL_DK, "Philips FI1256 MK2" },
- { TUNER_TEMIC_NTSC, "Temic 4032FY5" },
- { TUNER_TEMIC_PAL, "Temic 4002FH5" },
- { TUNER_TEMIC_PAL_I, "Temic 4062FY5" },
- { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" },
- { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
- { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" },
- { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
+ { TUNER_TEMIC_NTSC, "Temic 4032FY5" },
+ { TUNER_TEMIC_PAL, "Temic 4002FH5" },
+ { TUNER_TEMIC_PAL_I, "Temic 4062FY5" },
+ { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" },
+ { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
+ { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" },
+ { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
/* 20-29 */
{ TUNER_PHILIPS_PAL_DK, "Philips FR1256 MK2" },
- { TUNER_PHILIPS_PAL, "Philips FM1216" },
- { TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
- { TUNER_PHILIPS_NTSC, "Philips FM1236" },
- { TUNER_PHILIPS_PAL_I, "Philips FM1246" },
+ { TUNER_PHILIPS_PAL, "Philips FM1216" },
+ { TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
+ { TUNER_PHILIPS_NTSC, "Philips FM1236" },
+ { TUNER_PHILIPS_PAL_I, "Philips FM1246" },
{ TUNER_PHILIPS_PAL_DK, "Philips FM1256" },
- { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
- { TUNER_ABSENT, "Samsung TCPN9082D" },
- { TUNER_ABSENT, "Samsung TCPM9092P" },
- { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
+ { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
+ { TUNER_ABSENT, "Samsung TCPN9082D" },
+ { TUNER_ABSENT, "Samsung TCPM9092P" },
+ { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
/* 30-39 */
- { TUNER_ABSENT, "Samsung TCPN9085D" },
- { TUNER_ABSENT, "Samsung TCPB9085P" },
- { TUNER_ABSENT, "Samsung TCPL9091P" },
- { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
- { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" },
- { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
- { TUNER_PHILIPS_NTSC, "Philips TD1536" },
- { TUNER_PHILIPS_NTSC, "Philips TD1536D" },
- { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */
- { TUNER_ABSENT, "Philips FI1256MP" },
+ { TUNER_ABSENT, "Samsung TCPN9085D" },
+ { TUNER_ABSENT, "Samsung TCPB9085P" },
+ { TUNER_ABSENT, "Samsung TCPL9091P" },
+ { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
+ { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" },
+ { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
+ { TUNER_PHILIPS_NTSC, "Philips TD1536" },
+ { TUNER_PHILIPS_NTSC, "Philips TD1536D" },
+ { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */
+ { TUNER_ABSENT, "Philips FI1256MP" },
/* 40-49 */
- { TUNER_ABSENT, "Samsung TCPQ9091P" },
- { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
- { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
- { TUNER_TEMIC_4046FM5, "Temic 4046FM5" },
+ { TUNER_ABSENT, "Samsung TCPQ9091P" },
+ { TUNER_TEMIC_4006FN5_MULTI_PAL,"Temic 4006FN5" },
+ { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
+ { TUNER_TEMIC_4046FM5, "Temic 4046FM5" },
{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
- { TUNER_ABSENT, "Philips TD1536D FH 44"},
- { TUNER_LG_NTSC_FM, "LG TP18NSR01F"},
- { TUNER_LG_PAL_FM, "LG TP18PSB01D"},
- { TUNER_LG_PAL, "LG TP18PSB11D"},
- { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"},
+ { TUNER_ABSENT, "Philips TD1536D FH 44"},
+ { TUNER_LG_NTSC_FM, "LG TP18NSR01F"},
+ { TUNER_LG_PAL_FM, "LG TP18PSB01D"},
+ { TUNER_LG_PAL, "LG TP18PSB11D"},
+ { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"},
/* 50-59 */
- { TUNER_LG_PAL_I, "LG TAPC-I701D"},
- { TUNER_ABSENT, "Temic 4042FI5"},
- { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"},
- { TUNER_ABSENT, "LG TPI8NSR11F"},
- { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"},
- { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"},
- { TUNER_ABSENT, "Philips FI1236 MK3"},
- { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"},
- { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"},
- { TUNER_ABSENT, "Philips FM1216MP MK3"},
+ { TUNER_LG_PAL_I, "LG TAPC-I701D"},
+ { TUNER_ABSENT, "Temic 4042FI5"},
+ { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"},
+ { TUNER_ABSENT, "LG TPI8NSR11F"},
+ { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"},
+ { TUNER_ABSENT, "Philips FI1236 MK3"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"},
+ { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"},
+ { TUNER_ABSENT, "Philips FM1216MP MK3"},
/* 60-69 */
- { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"},
- { TUNER_ABSENT, "LG M001D MK3"},
- { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"},
- { TUNER_ABSENT, "LG M701D MK3"},
- { TUNER_ABSENT, "Temic 4146FM5"},
- { TUNER_ABSENT, "Temic 4136FY5"},
- { TUNER_ABSENT, "Temic 4106FH5"},
- { TUNER_ABSENT, "Philips FQ1216LMP MK3"},
- { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"},
- { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"},
+ { TUNER_ABSENT, "LG M001D MK3"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"},
+ { TUNER_ABSENT, "LG M701D MK3"},
+ { TUNER_ABSENT, "Temic 4146FM5"},
+ { TUNER_ABSENT, "Temic 4136FY5"},
+ { TUNER_ABSENT, "Temic 4106FH5"},
+ { TUNER_ABSENT, "Philips FQ1216LMP MK3"},
+ { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"},
+ { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"},
/* 70-79 */
- { TUNER_ABSENT, "LG TALN H200T"},
- { TUNER_ABSENT, "LG TALN H250T"},
- { TUNER_ABSENT, "LG TALN M200T"},
- { TUNER_ABSENT, "LG TALN Z200T"},
- { TUNER_ABSENT, "LG TALN S200T"},
- { TUNER_ABSENT, "Thompson DTT7595"},
- { TUNER_ABSENT, "Thompson DTT7592"},
- { TUNER_ABSENT, "Silicon TDA8275C1 8290"},
- { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"},
- { TUNER_ABSENT, "Thompson DTT757"},
+ { TUNER_ABSENT, "LG TALN H200T"},
+ { TUNER_ABSENT, "LG TALN H250T"},
+ { TUNER_ABSENT, "LG TALN M200T"},
+ { TUNER_ABSENT, "LG TALN Z200T"},
+ { TUNER_ABSENT, "LG TALN S200T"},
+ { TUNER_ABSENT, "Thompson DTT7595"},
+ { TUNER_ABSENT, "Thompson DTT7592"},
+ { TUNER_ABSENT, "Silicon TDA8275C1 8290"},
+ { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"},
+ { TUNER_ABSENT, "Thompson DTT757"},
/* 80-89 */
- { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK3"},
- { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
- { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
- { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
- { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
- { TUNER_TCL_2002N, "TCL 2002N 6A"},
- { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
- { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"},
- { TUNER_ABSENT, "Samsung TCPE 4121P30A"},
- { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
+ { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK3"},
+ { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
+ { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
+ { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
+ { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
+ { TUNER_TCL_2002N, "TCL 2002N 6A"},
+ { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
+ { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"},
+ { TUNER_ABSENT, "Samsung TCPE 4121P30A"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
/* 90-99 */
- { TUNER_ABSENT, "LG TALN H202T"},
- { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"},
- { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"},
- { TUNER_ABSENT, "Philips FQ1286A MK4"},
- { TUNER_ABSENT, "Philips FQ1216ME MK5"},
- { TUNER_ABSENT, "Philips FQ1236 MK5"},
- { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
- { TUNER_TCL_2002MB, "TCL 2002MB_3H"},
- { TUNER_ABSENT, "TCL 2002MI_3H"},
- { TUNER_TCL_2002N, "TCL 2002N 5H"},
+ { TUNER_ABSENT, "LG TALN H202T"},
+ { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"},
+ { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"},
+ { TUNER_ABSENT, "Philips FQ1286A MK4"},
+ { TUNER_ABSENT, "Philips FQ1216ME MK5"},
+ { TUNER_ABSENT, "Philips FQ1236 MK5"},
+ { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
+ { TUNER_TCL_2002MB, "TCL 2002MB_3H"},
+ { TUNER_ABSENT, "TCL 2002MI_3H"},
+ { TUNER_TCL_2002N, "TCL 2002N 5H"},
/* 100-109 */
- { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"},
- { TUNER_TEA5767, "Philips TEA5768HL FM Radio"},
- { TUNER_ABSENT, "Panasonic ENV57H12D5"},
- { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"},
+ { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"},
+ { TUNER_TEA5767, "Philips TEA5768HL FM Radio"},
+ { TUNER_ABSENT, "Panasonic ENV57H12D5"},
+ { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"},
{ TUNER_PHILIPS_FM1236_MK3, "TCL MNM05-4"},
- { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
- { TUNER_ABSENT, "TCL MQNM05-4"},
- { TUNER_ABSENT, "LG TAPC-W701D"},
- { TUNER_ABSENT, "TCL 9886P-WM"},
- { TUNER_ABSENT, "TCL 1676NM-WM"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
+ { TUNER_ABSENT, "TCL MQNM05-4"},
+ { TUNER_ABSENT, "LG TAPC-W701D"},
+ { TUNER_ABSENT, "TCL 9886P-WM"},
+ { TUNER_ABSENT, "TCL 1676NM-WM"},
/* 110-119 */
- { TUNER_ABSENT, "Thompson DTT75105"},
- { TUNER_ABSENT, "Conexant_CX24109"},
- { TUNER_TCL_2002N, "TCL M2523_5N_E"},
- { TUNER_TCL_2002MB, "TCL M2523_3DB_E"},
- { TUNER_ABSENT, "Philips 8275A"},
- { TUNER_ABSENT, "Microtune MT2060"},
- { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"},
- { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"},
- { TUNER_ABSENT, "TCL M2523_3DI_E"},
- { TUNER_ABSENT, "Samsung THPD5222FG30A"},
+ { TUNER_ABSENT, "Thompson DTT75105"},
+ { TUNER_ABSENT, "Conexant_CX24109"},
+ { TUNER_TCL_2002N, "TCL M2523_5N_E"},
+ { TUNER_TCL_2002MB, "TCL M2523_3DB_E"},
+ { TUNER_ABSENT, "Philips 8275A"},
+ { TUNER_ABSENT, "Microtune MT2060"},
+ { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"},
+ { TUNER_ABSENT, "TCL M2523_3DI_E"},
+ { TUNER_ABSENT, "Samsung THPD5222FG30A"},
/* 120-129 */
- { TUNER_XC2028, "Xceive XC3028"},
+ { TUNER_XC2028, "Xceive XC3028"},
{ TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK5"},
- { TUNER_ABSENT, "Philips FQD1216LME"},
- { TUNER_ABSENT, "Conexant CX24118A"},
- { TUNER_ABSENT, "TCL DMF11WIP"},
- { TUNER_ABSENT, "TCL MFNM05_4H_E"},
- { TUNER_ABSENT, "TCL MNM05_4H_E"},
- { TUNER_ABSENT, "TCL MPE05_2H_E"},
- { TUNER_ABSENT, "TCL MQNM05_4_U"},
- { TUNER_ABSENT, "TCL M2523_5NH_E"},
+ { TUNER_ABSENT, "Philips FQD1216LME"},
+ { TUNER_ABSENT, "Conexant CX24118A"},
+ { TUNER_ABSENT, "TCL DMF11WIP"},
+ { TUNER_ABSENT, "TCL MFNM05_4H_E"},
+ { TUNER_ABSENT, "TCL MNM05_4H_E"},
+ { TUNER_ABSENT, "TCL MPE05_2H_E"},
+ { TUNER_ABSENT, "TCL MQNM05_4_U"},
+ { TUNER_ABSENT, "TCL M2523_5NH_E"},
/* 130-139 */
- { TUNER_ABSENT, "TCL M2523_3DBH_E"},
- { TUNER_ABSENT, "TCL M2523_3DIH_E"},
- { TUNER_ABSENT, "TCL MFPE05_2_U"},
+ { TUNER_ABSENT, "TCL M2523_3DBH_E"},
+ { TUNER_ABSENT, "TCL M2523_3DIH_E"},
+ { TUNER_ABSENT, "TCL MFPE05_2_U"},
{ TUNER_PHILIPS_FMD1216MEX_MK3, "Philips FMD1216MEX"},
- { TUNER_ABSENT, "Philips FRH2036B"},
- { TUNER_ABSENT, "Panasonic ENGF75_01GF"},
- { TUNER_ABSENT, "MaxLinear MXL5005"},
- { TUNER_ABSENT, "MaxLinear MXL5003"},
- { TUNER_ABSENT, "Xceive XC2028"},
- { TUNER_ABSENT, "Microtune MT2131"},
+ { TUNER_ABSENT, "Philips FRH2036B"},
+ { TUNER_ABSENT, "Panasonic ENGF75_01GF"},
+ { TUNER_ABSENT, "MaxLinear MXL5005"},
+ { TUNER_ABSENT, "MaxLinear MXL5003"},
+ { TUNER_ABSENT, "Xceive XC2028"},
+ { TUNER_ABSENT, "Microtune MT2131"},
/* 140-149 */
- { TUNER_ABSENT, "Philips 8275A_8295"},
- { TUNER_ABSENT, "TCL MF02GIP_5N_E"},
- { TUNER_ABSENT, "TCL MF02GIP_3DB_E"},
- { TUNER_ABSENT, "TCL MF02GIP_3DI_E"},
- { TUNER_ABSENT, "Microtune MT2266"},
- { TUNER_ABSENT, "TCL MF10WPP_4N_E"},
- { TUNER_ABSENT, "LG TAPQ_H702F"},
- { TUNER_ABSENT, "TCL M09WPP_4N_E"},
- { TUNER_ABSENT, "MaxLinear MXL5005_v2"},
- { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"},
+ { TUNER_ABSENT, "Philips 8275A_8295"},
+ { TUNER_ABSENT, "TCL MF02GIP_5N_E"},
+ { TUNER_ABSENT, "TCL MF02GIP_3DB_E"},
+ { TUNER_ABSENT, "TCL MF02GIP_3DI_E"},
+ { TUNER_ABSENT, "Microtune MT2266"},
+ { TUNER_ABSENT, "TCL MF10WPP_4N_E"},
+ { TUNER_ABSENT, "LG TAPQ_H702F"},
+ { TUNER_ABSENT, "TCL M09WPP_4N_E"},
+ { TUNER_ABSENT, "MaxLinear MXL5005_v2"},
+ { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"},
/* 150-159 */
{ TUNER_XC5000, "Xceive XC5000"},
{ TUNER_ABSENT, "Xceive XC3028L"},
@@ -784,9 +784,3 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
return 0;
}
EXPORT_SYMBOL(tveeprom_read);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 388c2eb4d747..399e1042d351 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -172,6 +172,7 @@
#define USB_PID_TWINHAN_VP7045_WARM 0x3206
#define USB_PID_TWINHAN_VP7021_COLD 0x3207
#define USB_PID_TWINHAN_VP7021_WARM 0x3208
+#define USB_PID_TWINHAN_VP7049 0x3219
#define USB_PID_TINYTWIN 0x3226
#define USB_PID_TINYTWIN_2 0xe402
#define USB_PID_TINYTWIN_3 0x9016
@@ -233,10 +234,15 @@
#define USB_PID_AVERMEDIA_A815M 0x815a
#define USB_PID_AVERMEDIA_A835 0xa835
#define USB_PID_AVERMEDIA_B835 0xb835
+#define USB_PID_AVERMEDIA_A835B_1835 0x1835
+#define USB_PID_AVERMEDIA_A835B_2835 0x2835
+#define USB_PID_AVERMEDIA_A835B_3835 0x3835
+#define USB_PID_AVERMEDIA_A835B_4835 0x4835
#define USB_PID_AVERMEDIA_1867 0x1867
#define USB_PID_AVERMEDIA_A867 0xa867
#define USB_PID_AVERMEDIA_TWINSTAR 0x0825
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
+#define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009
#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index 9be65a3b931f..0aac3096728e 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -156,6 +156,9 @@ struct dvb_ca_private {
/* Slot to start looking for data to read from in the next user-space read operation */
int next_read_slot;
+
+ /* mutex serializing ioctls */
+ struct mutex ioctl_mutex;
};
static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
@@ -1191,6 +1194,9 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
dprintk("%s\n", __func__);
+ if (mutex_lock_interruptible(&ca->ioctl_mutex))
+ return -ERESTARTSYS;
+
switch (cmd) {
case CA_RESET:
for (slot = 0; slot < ca->slot_count; slot++) {
@@ -1221,8 +1227,10 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
case CA_GET_SLOT_INFO: {
struct ca_slot_info *info = parg;
- if ((info->num > ca->slot_count) || (info->num < 0))
- return -EINVAL;
+ if ((info->num > ca->slot_count) || (info->num < 0)) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
info->type = CA_CI_LINK;
info->flags = 0;
@@ -1241,6 +1249,8 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
break;
}
+out_unlock:
+ mutex_unlock(&ca->ioctl_mutex);
return err;
}
@@ -1695,6 +1705,8 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
mutex_init(&ca->slot_info[i].slot_lock);
}
+ mutex_init(&ca->ioctl_mutex);
+
if (signal_pending(current)) {
ret = -EINTR;
goto error;
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 49d95040096a..6e50a7581568 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -603,6 +603,7 @@ static int dvb_frontend_thread(void *data)
enum dvbfe_algo algo;
bool re_tune = false;
+ bool semheld = false;
dev_dbg(fe->dvb->device, "%s:\n", __func__);
@@ -626,6 +627,8 @@ restart:
if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
/* got signal or quitting */
+ if (!down_interruptible(&fepriv->sem))
+ semheld = true;
fepriv->exit = DVB_FE_NORMAL_EXIT;
break;
}
@@ -741,6 +744,8 @@ restart:
fepriv->exit = DVB_FE_NO_EXIT;
mb();
+ if (semheld)
+ up(&fepriv->sem);
dvb_frontend_wakeup(fe);
return 0;
}
@@ -1048,6 +1053,16 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
_DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
+
+ /* Statistics API */
+ _DTV_CMD(DTV_STAT_SIGNAL_STRENGTH, 0, 0),
+ _DTV_CMD(DTV_STAT_CNR, 0, 0),
+ _DTV_CMD(DTV_STAT_PRE_ERROR_BIT_COUNT, 0, 0),
+ _DTV_CMD(DTV_STAT_PRE_TOTAL_BIT_COUNT, 0, 0),
+ _DTV_CMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0, 0),
+ _DTV_CMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0, 0),
+ _DTV_CMD(DTV_STAT_ERROR_BLOCK_COUNT, 0, 0),
+ _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0),
};
static void dtv_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp)
@@ -1438,7 +1453,35 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
tvp->u.data = c->lna;
break;
+ /* Fill quality measures */
+ case DTV_STAT_SIGNAL_STRENGTH:
+ tvp->u.st = c->strength;
+ break;
+ case DTV_STAT_CNR:
+ tvp->u.st = c->cnr;
+ break;
+ case DTV_STAT_PRE_ERROR_BIT_COUNT:
+ tvp->u.st = c->pre_bit_error;
+ break;
+ case DTV_STAT_PRE_TOTAL_BIT_COUNT:
+ tvp->u.st = c->pre_bit_count;
+ break;
+ case DTV_STAT_POST_ERROR_BIT_COUNT:
+ tvp->u.st = c->post_bit_error;
+ break;
+ case DTV_STAT_POST_TOTAL_BIT_COUNT:
+ tvp->u.st = c->post_bit_count;
+ break;
+ case DTV_STAT_ERROR_BLOCK_COUNT:
+ tvp->u.st = c->block_error;
+ break;
+ case DTV_STAT_TOTAL_BLOCK_COUNT:
+ tvp->u.st = c->block_count;
+ break;
default:
+ dev_dbg(fe->dvb->device,
+ "%s: FE property %d doesn't exist\n",
+ __func__, tvp->cmd);
return -EINVAL;
}
@@ -1820,19 +1863,23 @@ static int dvb_frontend_ioctl(struct file *file,
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 = -ENOTTY;
+ int err = -EOPNOTSUPP;
dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd));
- if (fepriv->exit != DVB_FE_NO_EXIT)
+ if (down_interruptible(&fepriv->sem))
+ return -ERESTARTSYS;
+
+ if (fepriv->exit != DVB_FE_NO_EXIT) {
+ up(&fepriv->sem);
return -ENODEV;
+ }
if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
(_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
- cmd == FE_DISEQC_RECV_SLAVE_REPLY))
+ cmd == FE_DISEQC_RECV_SLAVE_REPLY)) {
+ up(&fepriv->sem);
return -EPERM;
-
- if (down_interruptible (&fepriv->sem))
- return -ERESTARTSYS;
+ }
if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
err = dvb_frontend_ioctl_properties(file, cmd, parg);
@@ -1938,7 +1985,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
}
} else
- err = -ENOTTY;
+ err = -EOPNOTSUPP;
out:
kfree(tvp);
@@ -2071,7 +2118,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
struct dvb_frontend *fe = dvbdev->priv;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int err = -ENOTTY;
+ int err = -EOPNOTSUPP;
switch (cmd) {
case FE_GET_INFO: {
@@ -2246,7 +2293,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
printk("%s switch command: 0x%04lx\n", __func__, swcmd);
do_gettimeofday(&nexttime);
if (dvb_frontend_debug)
- memcpy(&tv[0], &nexttime, sizeof(struct timeval));
+ tv[0] = nexttime;
/* before sending a command, initialize by sending
* a 32ms 18V to the switch
*/
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
index 97112cd88a17..b34922a08156 100644
--- a/drivers/media/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb-core/dvb_frontend.h
@@ -393,6 +393,16 @@ struct dtv_frontend_properties {
u8 atscmh_sccc_code_mode_d;
u32 lna;
+
+ /* statistics data */
+ struct dtv_fe_stats strength;
+ struct dtv_fe_stats cnr;
+ struct dtv_fe_stats pre_bit_error;
+ struct dtv_fe_stats pre_bit_count;
+ struct dtv_fe_stats post_bit_error;
+ struct dtv_fe_stats post_bit_count;
+ struct dtv_fe_stats block_error;
+ struct dtv_fe_stats block_count;
};
struct dvb_frontend {
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index c2117688aa23..44225b186f6d 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -1345,26 +1345,35 @@ static int dvb_net_do_ioctl(struct file *file,
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_net *dvbnet = dvbdev->priv;
+ int ret = 0;
if (((file->f_flags&O_ACCMODE)==O_RDONLY))
return -EPERM;
+ if (mutex_lock_interruptible(&dvbnet->ioctl_mutex))
+ return -ERESTARTSYS;
+
switch (cmd) {
case NET_ADD_IF:
{
struct dvb_net_if *dvbnetif = parg;
int result;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
+ if (!capable(CAP_SYS_ADMIN)) {
+ ret = -EPERM;
+ goto ioctl_error;
+ }
- if (!try_module_get(dvbdev->adapter->module))
- return -EPERM;
+ if (!try_module_get(dvbdev->adapter->module)) {
+ ret = -EPERM;
+ goto ioctl_error;
+ }
result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype);
if (result<0) {
module_put(dvbdev->adapter->module);
- return result;
+ ret = result;
+ goto ioctl_error;
}
dvbnetif->if_num=result;
break;
@@ -1376,8 +1385,10 @@ static int dvb_net_do_ioctl(struct file *file,
struct dvb_net_if *dvbnetif = parg;
if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
- !dvbnet->state[dvbnetif->if_num])
- return -EINVAL;
+ !dvbnet->state[dvbnetif->if_num]) {
+ ret = -EINVAL;
+ goto ioctl_error;
+ }
netdev = dvbnet->device[dvbnetif->if_num];
@@ -1388,16 +1399,18 @@ static int dvb_net_do_ioctl(struct file *file,
}
case NET_REMOVE_IF:
{
- int ret;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if ((unsigned long) parg >= DVB_NET_DEVICES_MAX)
- return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN)) {
+ ret = -EPERM;
+ goto ioctl_error;
+ }
+ if ((unsigned long) parg >= DVB_NET_DEVICES_MAX) {
+ ret = -EINVAL;
+ goto ioctl_error;
+ }
ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
if (!ret)
module_put(dvbdev->adapter->module);
- return ret;
+ break;
}
/* binary compatibility cruft */
@@ -1406,16 +1419,21 @@ static int dvb_net_do_ioctl(struct file *file,
struct __dvb_net_if_old *dvbnetif = parg;
int result;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
+ if (!capable(CAP_SYS_ADMIN)) {
+ ret = -EPERM;
+ goto ioctl_error;
+ }
- if (!try_module_get(dvbdev->adapter->module))
- return -EPERM;
+ if (!try_module_get(dvbdev->adapter->module)) {
+ ret = -EPERM;
+ goto ioctl_error;
+ }
result=dvb_net_add_if(dvbnet, dvbnetif->pid, DVB_NET_FEEDTYPE_MPE);
if (result<0) {
module_put(dvbdev->adapter->module);
- return result;
+ ret = result;
+ goto ioctl_error;
}
dvbnetif->if_num=result;
break;
@@ -1427,8 +1445,10 @@ static int dvb_net_do_ioctl(struct file *file,
struct __dvb_net_if_old *dvbnetif = parg;
if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
- !dvbnet->state[dvbnetif->if_num])
- return -EINVAL;
+ !dvbnet->state[dvbnetif->if_num]) {
+ ret = -EINVAL;
+ goto ioctl_error;
+ }
netdev = dvbnet->device[dvbnetif->if_num];
@@ -1437,9 +1457,13 @@ static int dvb_net_do_ioctl(struct file *file,
break;
}
default:
- return -ENOTTY;
+ ret = -ENOTTY;
+ break;
}
- return 0;
+
+ioctl_error:
+ mutex_unlock(&dvbnet->ioctl_mutex);
+ return ret;
}
static long dvb_net_ioctl(struct file *file,
@@ -1505,6 +1529,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
{
int i;
+ mutex_init(&dvbnet->ioctl_mutex);
dvbnet->demux = dmx;
for (i=0; i<DVB_NET_DEVICES_MAX; i++)
diff --git a/drivers/media/dvb-core/dvb_net.h b/drivers/media/dvb-core/dvb_net.h
index 1e53acd50cf4..ede78e8c8aa8 100644
--- a/drivers/media/dvb-core/dvb_net.h
+++ b/drivers/media/dvb-core/dvb_net.h
@@ -40,6 +40,7 @@ struct dvb_net {
int state[DVB_NET_DEVICES_MAX];
unsigned int exit:1;
struct dmx_demux *demux;
+ struct mutex ioctl_mutex;
};
void dvb_net_release(struct dvb_net *);
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index d33101aaf0b5..401ef64f92c6 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -418,10 +418,8 @@ int dvb_usercopy(struct file *file,
}
/* call driver */
- mutex_lock(&dvbdev_mutex);
if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
err = -ENOTTY;
- mutex_unlock(&dvbdev_mutex);
if (err < 0)
goto out;
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 5efec73a32d2..6f809a70c78e 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -207,6 +207,13 @@ config DVB_SI21XX
help
A DVB-S tuner module. Say Y when you want to support this frontend.
+config DVB_TS2020
+ tristate "Montage Tehnology TS2020 based tuners"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S/S2 silicon tuner. Say Y when you want to support this tuner.
+
config DVB_DS3000
tristate "Montage Tehnology DS3000 based"
depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 7eb73bbd2e26..cebc0faffab5 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -88,6 +88,7 @@ obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
+obj-$(CONFIG_DVB_TS2020) += ts2020.o
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c
index 464ad878490b..c9cad989b8b9 100644
--- a/drivers/media/dvb-frontends/af9033.c
+++ b/drivers/media/dvb-frontends/af9033.c
@@ -318,6 +318,10 @@ static int af9033_init(struct dvb_frontend *fe)
len = ARRAY_SIZE(tuner_init_fc2580);
init = tuner_init_fc2580;
break;
+ case AF9033_TUNER_FC0012:
+ len = ARRAY_SIZE(tuner_init_fc0012);
+ init = tuner_init_fc0012;
+ break;
default:
dev_dbg(&state->i2c->dev, "%s: unsupported tuner ID=%d\n",
__func__, state->cfg.tuner);
@@ -331,6 +335,20 @@ static int af9033_init(struct dvb_frontend *fe)
goto err;
}
+ if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+ ret = af9033_wr_reg_mask(state, 0x00d91c, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg_mask(state, 0x00d916, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+ }
+
state->bandwidth_hz = 0; /* force to program all parameters */
return 0;
diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h
index bfa4313fde21..82bd8c1513b6 100644
--- a/drivers/media/dvb-frontends/af9033.h
+++ b/drivers/media/dvb-frontends/af9033.h
@@ -40,6 +40,7 @@ struct af9033_config {
*/
#define AF9033_TUNER_TUA9001 0x27 /* Infineon TUA 9001 */
#define AF9033_TUNER_FC0011 0x28 /* Fitipower FC0011 */
+#define AF9033_TUNER_FC0012 0x2e /* Fitipower FC0012 */
#define AF9033_TUNER_MXL5007T 0xa0 /* MaxLinear MxL5007T */
#define AF9033_TUNER_TDA18218 0xa1 /* NXP TDA 18218HN */
#define AF9033_TUNER_FC2580 0x32 /* FCI FC2580 */
diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h
index 34dddcd77538..e9bd78265543 100644
--- a/drivers/media/dvb-frontends/af9033_priv.h
+++ b/drivers/media/dvb-frontends/af9033_priv.h
@@ -199,10 +199,9 @@ static const struct reg_val ofsm_init[] = {
{ 0x8000a6, 0x01 },
{ 0x8000a9, 0x00 },
{ 0x8000aa, 0x01 },
- { 0x8000ab, 0x01 },
{ 0x8000b0, 0x01 },
- { 0x8000c0, 0x05 },
- { 0x8000c4, 0x19 },
+ { 0x8000c4, 0x05 },
+ { 0x8000c8, 0x19 },
{ 0x80f000, 0x0f },
{ 0x80f016, 0x10 },
{ 0x80f017, 0x04 },
@@ -322,8 +321,9 @@ static const struct reg_val tuner_init_tua9001[] = {
{ 0x80009b, 0x05 },
{ 0x80009c, 0x80 },
{ 0x8000b3, 0x00 },
- { 0x8000c1, 0x01 },
- { 0x8000c2, 0x00 },
+ { 0x8000c5, 0x01 },
+ { 0x8000c6, 0x00 },
+ { 0x8000c9, 0x5d },
{ 0x80f007, 0x00 },
{ 0x80f01f, 0x82 },
{ 0x80f020, 0x00 },
@@ -339,14 +339,14 @@ static const struct reg_val tuner_init_tua9001[] = {
/* Fitipower fc0011 tuner init
AF9033_TUNER_FC0011 = 0x28 */
static const struct reg_val tuner_init_fc0011[] = {
- { 0x800046, AF9033_TUNER_FC0011 },
+ { 0x800046, 0x28 },
{ 0x800057, 0x00 },
{ 0x800058, 0x01 },
{ 0x80005f, 0x00 },
{ 0x800060, 0x00 },
{ 0x800068, 0xa5 },
{ 0x80006e, 0x01 },
- { 0x800071, 0x0A },
+ { 0x800071, 0x0a },
{ 0x800072, 0x02 },
{ 0x800074, 0x01 },
{ 0x800079, 0x01 },
@@ -354,7 +354,7 @@ static const struct reg_val tuner_init_fc0011[] = {
{ 0x800094, 0x00 },
{ 0x800095, 0x00 },
{ 0x800096, 0x00 },
- { 0x80009b, 0x2D },
+ { 0x80009b, 0x2d },
{ 0x80009c, 0x60 },
{ 0x80009d, 0x23 },
{ 0x8000a4, 0x50 },
@@ -362,39 +362,82 @@ static const struct reg_val tuner_init_fc0011[] = {
{ 0x8000b3, 0x01 },
{ 0x8000b7, 0x88 },
{ 0x8000b8, 0xa6 },
- { 0x8000c3, 0x01 },
- { 0x8000c4, 0x01 },
- { 0x8000c7, 0x69 },
- { 0x80F007, 0x00 },
- { 0x80F00A, 0x1B },
- { 0x80F00B, 0x1B },
- { 0x80F00C, 0x1B },
- { 0x80F00D, 0x1B },
- { 0x80F00E, 0xFF },
- { 0x80F00F, 0x01 },
- { 0x80F010, 0x00 },
- { 0x80F011, 0x02 },
- { 0x80F012, 0xFF },
- { 0x80F013, 0x01 },
- { 0x80F014, 0x00 },
- { 0x80F015, 0x02 },
- { 0x80F01B, 0xEF },
- { 0x80F01C, 0x01 },
- { 0x80F01D, 0x0f },
- { 0x80F01E, 0x02 },
- { 0x80F01F, 0x6E },
- { 0x80F020, 0x00 },
- { 0x80F025, 0xDE },
- { 0x80F026, 0x00 },
- { 0x80F027, 0x0A },
- { 0x80F028, 0x03 },
- { 0x80F029, 0x6E },
- { 0x80F02A, 0x00 },
- { 0x80F047, 0x00 },
- { 0x80F054, 0x00 },
- { 0x80F055, 0x00 },
- { 0x80F077, 0x01 },
- { 0x80F1E6, 0x00 },
+ { 0x8000c5, 0x01 },
+ { 0x8000c6, 0x01 },
+ { 0x8000c9, 0x69 },
+ { 0x80f007, 0x00 },
+ { 0x80f00a, 0x1b },
+ { 0x80f00b, 0x1b },
+ { 0x80f00c, 0x1b },
+ { 0x80f00d, 0x1b },
+ { 0x80f00e, 0xff },
+ { 0x80f00f, 0x01 },
+ { 0x80f010, 0x00 },
+ { 0x80f011, 0x02 },
+ { 0x80f012, 0xff },
+ { 0x80f013, 0x01 },
+ { 0x80f014, 0x00 },
+ { 0x80f015, 0x02 },
+ { 0x80f01b, 0xef },
+ { 0x80f01c, 0x01 },
+ { 0x80f01d, 0x0f },
+ { 0x80f01e, 0x02 },
+ { 0x80f01f, 0x6e },
+ { 0x80f020, 0x00 },
+ { 0x80f025, 0xde },
+ { 0x80f026, 0x00 },
+ { 0x80f027, 0x0a },
+ { 0x80f028, 0x03 },
+ { 0x80f029, 0x6e },
+ { 0x80f02a, 0x00 },
+ { 0x80f047, 0x00 },
+ { 0x80f054, 0x00 },
+ { 0x80f055, 0x00 },
+ { 0x80f077, 0x01 },
+ { 0x80f1e6, 0x00 },
+};
+
+/* Fitipower FC0012 tuner init
+ AF9033_TUNER_FC0012 = 0x2e */
+static const struct reg_val tuner_init_fc0012[] = {
+ { 0x800046, 0x2e },
+ { 0x800057, 0x00 },
+ { 0x800058, 0x01 },
+ { 0x800059, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x80006d, 0x00 },
+ { 0x800071, 0x05 },
+ { 0x800072, 0x02 },
+ { 0x800074, 0x01 },
+ { 0x800075, 0x03 },
+ { 0x800076, 0x02 },
+ { 0x800077, 0x01 },
+ { 0x800078, 0x00 },
+ { 0x800079, 0x00 },
+ { 0x80007a, 0x90 },
+ { 0x80007b, 0x90 },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x01 },
+ { 0x800095, 0x02 },
+ { 0x800096, 0x01 },
+ { 0x800098, 0x0a },
+ { 0x80009b, 0x05 },
+ { 0x80009c, 0x80 },
+ { 0x8000b3, 0x00 },
+ { 0x8000c5, 0x01 },
+ { 0x8000c6, 0x00 },
+ { 0x8000c9, 0x5d },
+ { 0x80f007, 0x00 },
+ { 0x80f01f, 0xa0 },
+ { 0x80f020, 0x00 },
+ { 0x80f029, 0x82 },
+ { 0x80f02a, 0x00 },
+ { 0x80f047, 0x00 },
+ { 0x80f054, 0x00 },
+ { 0x80f055, 0x00 },
+ { 0x80f077, 0x01 },
+ { 0x80f1e6, 0x00 },
};
/* MaxLinear MxL5007T tuner init
@@ -482,11 +525,12 @@ static const struct reg_val tuner_init_fc2580[] = {
{ 0x800095, 0x00 },
{ 0x800096, 0x05 },
{ 0x8000b3, 0x01 },
- { 0x8000c3, 0x01 },
- { 0x8000c4, 0x00 },
+ { 0x8000c5, 0x01 },
+ { 0x8000c6, 0x00 },
+ { 0x8000d1, 0x01 },
{ 0x80f007, 0x00 },
{ 0x80f00c, 0x19 },
- { 0x80f00d, 0x1A },
+ { 0x80f00d, 0x1a },
{ 0x80f00e, 0x00 },
{ 0x80f00f, 0x02 },
{ 0x80f010, 0x00 },
diff --git a/drivers/media/dvb-frontends/bcm3510.h b/drivers/media/dvb-frontends/bcm3510.h
index f4575c0cc446..5bd56b1623bf 100644
--- a/drivers/media/dvb-frontends/bcm3510.h
+++ b/drivers/media/dvb-frontends/bcm3510.h
@@ -34,7 +34,7 @@ struct bcm3510_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
-#if defined(CONFIG_DVB_BCM3510) || (defined(CONFIG_DVB_BCM3510_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_BCM3510)
extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/cx22700.h b/drivers/media/dvb-frontends/cx22700.h
index 4757a930ca05..382a7b1f3618 100644
--- a/drivers/media/dvb-frontends/cx22700.h
+++ b/drivers/media/dvb-frontends/cx22700.h
@@ -31,7 +31,7 @@ struct cx22700_config
u8 demod_address;
};
-#if defined(CONFIG_DVB_CX22700) || (defined(CONFIG_DVB_CX22700_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_CX22700)
extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/cx24110.h b/drivers/media/dvb-frontends/cx24110.h
index fdcceee91f3a..527aff1f2723 100644
--- a/drivers/media/dvb-frontends/cx24110.h
+++ b/drivers/media/dvb-frontends/cx24110.h
@@ -46,7 +46,7 @@ static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val)
return 0;
}
-#if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_CX24110)
extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c
index b48879186537..2916d7c74a1d 100644
--- a/drivers/media/dvb-frontends/cx24116.c
+++ b/drivers/media/dvb-frontends/cx24116.c
@@ -819,7 +819,7 @@ static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
static void cx24116_clone_params(struct dvb_frontend *fe)
{
struct cx24116_state *state = fe->demodulator_priv;
- memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
+ state->dcur = state->dnxt;
}
/* Wait for LNB */
diff --git a/drivers/media/dvb-frontends/dib0070.h b/drivers/media/dvb-frontends/dib0070.h
index 45c31fae3967..0c6befcc9143 100644
--- a/drivers/media/dvb-frontends/dib0070.h
+++ b/drivers/media/dvb-frontends/dib0070.h
@@ -48,7 +48,7 @@ struct dib0070_config {
u8 vga_filter;
};
-#if defined(CONFIG_DVB_TUNER_DIB0070) || (defined(CONFIG_DVB_TUNER_DIB0070_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TUNER_DIB0070)
extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
extern u16 dib0070_wbd_offset(struct dvb_frontend *);
extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open);
diff --git a/drivers/media/dvb-frontends/dib0090.h b/drivers/media/dvb-frontends/dib0090.h
index 781dc49de45b..6a090954fa10 100644
--- a/drivers/media/dvb-frontends/dib0090.h
+++ b/drivers/media/dvb-frontends/dib0090.h
@@ -75,7 +75,7 @@ struct dib0090_config {
u8 force_crystal_mode;
};
-#if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TUNER_DIB0090)
extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast);
diff --git a/drivers/media/dvb-frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h
index 404f63a6f26b..9b6c3bbc983a 100644
--- a/drivers/media/dvb-frontends/dib3000.h
+++ b/drivers/media/dvb-frontends/dib3000.h
@@ -41,7 +41,7 @@ struct dib_fe_xfer_ops
int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl);
};
-#if defined(CONFIG_DVB_DIB3000MB) || (defined(CONFIG_DVB_DIB3000MB_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB3000MB)
extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
#else
diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h
index 39591bb172c1..9e7a2b170d55 100644
--- a/drivers/media/dvb-frontends/dib8000.h
+++ b/drivers/media/dvb-frontends/dib8000.h
@@ -37,7 +37,7 @@ struct dib8000_config {
#define DEFAULT_DIB8000_I2C_ADDRESS 18
-#if defined(CONFIG_DVB_DIB8000) || (defined(CONFIG_DVB_DIB8000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB8000)
extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
diff --git a/drivers/media/dvb-frontends/dib9000.h b/drivers/media/dvb-frontends/dib9000.h
index de1cc91fd833..f3639f045ff0 100644
--- a/drivers/media/dvb-frontends/dib9000.h
+++ b/drivers/media/dvb-frontends/dib9000.h
@@ -27,7 +27,7 @@ struct dib9000_config {
#define DEFAULT_DIB9000_I2C_ADDRESS 18
-#if defined(CONFIG_DVB_DIB9000) || (defined(CONFIG_DVB_DIB9000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB9000)
extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg);
extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr);
extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c
index e71cc60851e7..9a2134792cfa 100644
--- a/drivers/media/dvb-frontends/drxd_hard.c
+++ b/drivers/media/dvb-frontends/drxd_hard.c
@@ -2965,7 +2965,7 @@ struct dvb_frontend *drxd_attach(const struct drxd_config *config,
return NULL;
memset(state, 0, sizeof(*state));
- memcpy(&state->ops, &drxd_ops, sizeof(struct dvb_frontend_ops));
+ state->ops = drxd_ops;
state->dev = dev;
state->config = *config;
state->i2c = i2c;
@@ -2976,10 +2976,13 @@ struct dvb_frontend *drxd_attach(const struct drxd_config *config,
if (Read16(state, 0, 0, 0) < 0)
goto error;
- memcpy(&state->frontend.ops, &drxd_ops,
- sizeof(struct dvb_frontend_ops));
+ state->frontend.ops = drxd_ops;
state->frontend.demodulator_priv = state;
ConfigureMPEGOutput(state, 0);
+ /* add few initialization to allow gate control */
+ CDRXD(state, state->config.IF ? state->config.IF : 36000000);
+ InitHI(state);
+
return &state->frontend;
error:
diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c
index 60a529e3833f..1e344b033277 100644
--- a/drivers/media/dvb-frontends/ds3000.c
+++ b/drivers/media/dvb-frontends/ds3000.c
@@ -1,8 +1,8 @@
/*
- Montage Technology DS3000/TS2020 - DVBS/S2 Demodulator/Tuner driver
- Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+ Montage Technology DS3000 - DVBS/S2 Demodulator driver
+ Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
- Copyright (C) 2009 TurboSight.com
+ Copyright (C) 2009-2012 TurboSight.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
@@ -27,6 +27,7 @@
#include <linux/firmware.h>
#include "dvb_frontend.h"
+#include "ts2020.h"
#include "ds3000.h"
static int debug;
@@ -42,7 +43,6 @@ static int debug;
#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds3000.fw"
#define DS3000_SAMPLE_RATE 96000 /* in kHz */
-#define DS3000_XTAL_FREQ 27000 /* in kHz */
/* Register values to initialise the demod in DVB-S mode */
static u8 ds3000_dvbs_init_tab[] = {
@@ -256,22 +256,14 @@ static int ds3000_writereg(struct ds3000_state *state, int reg, int data)
return 0;
}
-static int ds3000_tuner_writereg(struct ds3000_state *state, int reg, int data)
+static int ds3000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
- u8 buf[] = { reg, data };
- struct i2c_msg msg = { .addr = 0x60,
- .flags = 0, .buf = buf, .len = 2 };
- int err;
-
- dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data);
+ struct ds3000_state *state = fe->demodulator_priv;
- ds3000_writereg(state, 0x03, 0x11);
- err = i2c_transfer(state->i2c, &msg, 1);
- if (err != 1) {
- printk("%s: writereg error(err == %i, reg == 0x%02x,"
- " value == 0x%02x)\n", __func__, err, reg, data);
- return -EREMOTEIO;
- }
+ if (enable)
+ ds3000_writereg(state, 0x03, 0x12);
+ else
+ ds3000_writereg(state, 0x03, 0x02);
return 0;
}
@@ -280,15 +272,14 @@ static int ds3000_tuner_writereg(struct ds3000_state *state, int reg, int data)
static int ds3000_writeFW(struct ds3000_state *state, int reg,
const u8 *data, u16 len)
{
- int i, ret = -EREMOTEIO;
+ int i, ret = 0;
struct i2c_msg msg;
u8 *buf;
buf = kmalloc(33, GFP_KERNEL);
if (buf == NULL) {
printk(KERN_ERR "Unable to kmalloc\n");
- ret = -ENOMEM;
- goto error;
+ return -ENOMEM;
}
*(buf) = reg;
@@ -308,8 +299,10 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg,
printk(KERN_ERR "%s: write error(err == %i, "
"reg == 0x%02x\n", __func__, ret, reg);
ret = -EREMOTEIO;
+ goto error;
}
}
+ ret = 0;
error:
kfree(buf);
@@ -348,38 +341,6 @@ static int ds3000_readreg(struct ds3000_state *state, u8 reg)
return b1[0];
}
-static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg)
-{
- int ret;
- u8 b0[] = { reg };
- u8 b1[] = { 0 };
- struct i2c_msg msg[] = {
- {
- .addr = 0x60,
- .flags = 0,
- .buf = b0,
- .len = 1
- }, {
- .addr = 0x60,
- .flags = I2C_M_RD,
- .buf = b1,
- .len = 1
- }
- };
-
- ds3000_writereg(state, 0x03, 0x12);
- ret = i2c_transfer(state->i2c, msg, 2);
-
- if (ret != 2) {
- printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret);
- return ret;
- }
-
- dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]);
-
- return b1[0];
-}
-
static int ds3000_load_firmware(struct dvb_frontend *fe,
const struct firmware *fw);
@@ -424,6 +385,7 @@ static int ds3000_load_firmware(struct dvb_frontend *fe,
const struct firmware *fw)
{
struct ds3000_state *state = fe->demodulator_priv;
+ int ret = 0;
dprintk("%s\n", __func__);
dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
@@ -436,10 +398,10 @@ static int ds3000_load_firmware(struct dvb_frontend *fe,
/* Begin the firmware load process */
ds3000_writereg(state, 0xb2, 0x01);
/* write the entire firmware */
- ds3000_writeFW(state, 0xb0, fw->data, fw->size);
+ ret = ds3000_writeFW(state, 0xb0, fw->data, fw->size);
ds3000_writereg(state, 0xb2, 0x00);
- return 0;
+ return ret;
}
static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
@@ -498,6 +460,9 @@ static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
return 1;
}
+ if (state->config->set_lock_led)
+ state->config->set_lock_led(fe, *status == 0 ? 0 : 1);
+
dprintk("%s: status = 0x%02x\n", __func__, lock);
return 0;
@@ -568,33 +533,11 @@ static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
return 0;
}
-/* read TS2020 signal strength */
static int ds3000_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
- struct ds3000_state *state = fe->demodulator_priv;
- u16 sig_reading, sig_strength;
- u8 rfgain, bbgain;
-
- dprintk("%s()\n", __func__);
-
- rfgain = ds3000_tuner_readreg(state, 0x3d) & 0x1f;
- bbgain = ds3000_tuner_readreg(state, 0x21) & 0x1f;
-
- if (rfgain > 15)
- rfgain = 15;
- if (bbgain > 13)
- bbgain = 13;
-
- sig_reading = rfgain * 2 + bbgain * 3;
-
- sig_strength = 40 + (64 - sig_reading) * 50 / 64 ;
-
- /* cook the value to be suitable for szap-s2 human readable output */
- *signal_strength = sig_strength * 1000;
-
- dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__,
- sig_reading, *signal_strength);
+ if (fe->ops.tuner_ops.get_rf_strength)
+ fe->ops.tuner_ops.get_rf_strength(fe, signal_strength);
return 0;
}
@@ -878,6 +821,10 @@ static int ds3000_diseqc_send_burst(struct dvb_frontend *fe,
static void ds3000_release(struct dvb_frontend *fe)
{
struct ds3000_state *state = fe->demodulator_priv;
+
+ if (state->config->set_lock_led)
+ state->config->set_lock_led(fe, 0);
+
dprintk("%s\n", __func__);
kfree(state);
}
@@ -952,133 +899,17 @@ static int ds3000_set_frontend(struct dvb_frontend *fe)
int i;
fe_status_t status;
- u8 mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4;
s32 offset_khz;
- u16 value, ndiv;
- u32 f3db;
+ u32 frequency;
+ u16 value;
dprintk("%s() ", __func__);
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
/* Tune */
- /* unknown */
- ds3000_tuner_writereg(state, 0x07, 0x02);
- ds3000_tuner_writereg(state, 0x10, 0x00);
- ds3000_tuner_writereg(state, 0x60, 0x79);
- ds3000_tuner_writereg(state, 0x08, 0x01);
- ds3000_tuner_writereg(state, 0x00, 0x01);
- div4 = 0;
-
- /* calculate and set freq divider */
- if (c->frequency < 1146000) {
- ds3000_tuner_writereg(state, 0x10, 0x11);
- div4 = 1;
- ndiv = ((c->frequency * (6 + 8) * 4) +
- (DS3000_XTAL_FREQ / 2)) /
- DS3000_XTAL_FREQ - 1024;
- } else {
- ds3000_tuner_writereg(state, 0x10, 0x01);
- ndiv = ((c->frequency * (6 + 8) * 2) +
- (DS3000_XTAL_FREQ / 2)) /
- DS3000_XTAL_FREQ - 1024;
- }
-
- ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
- ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
-
- /* set pll */
- ds3000_tuner_writereg(state, 0x03, 0x06);
- ds3000_tuner_writereg(state, 0x51, 0x0f);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x10);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- /* unknown */
- ds3000_tuner_writereg(state, 0x51, 0x17);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x08);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- value = ds3000_tuner_readreg(state, 0x3d);
- value &= 0x0f;
- if ((value > 4) && (value < 15)) {
- value -= 3;
- if (value < 4)
- value = 4;
- value = ((value << 3) | 0x01) & 0x79;
- }
-
- ds3000_tuner_writereg(state, 0x60, value);
- ds3000_tuner_writereg(state, 0x51, 0x17);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x08);
- ds3000_tuner_writereg(state, 0x50, 0x00);
-
- /* set low-pass filter period */
- ds3000_tuner_writereg(state, 0x04, 0x2e);
- ds3000_tuner_writereg(state, 0x51, 0x1b);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x04);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- f3db = ((c->symbol_rate / 1000) << 2) / 5 + 2000;
- if ((c->symbol_rate / 1000) < 5000)
- f3db += 3000;
- if (f3db < 7000)
- f3db = 7000;
- if (f3db > 40000)
- f3db = 40000;
-
- /* set low-pass filter baseband */
- value = ds3000_tuner_readreg(state, 0x26);
- mlpf = 0x2e * 207 / ((value << 1) + 151);
- mlpf_max = mlpf * 135 / 100;
- mlpf_min = mlpf * 78 / 100;
- if (mlpf_max > 63)
- mlpf_max = 63;
-
- /* rounded to the closest integer */
- nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
- / (2766 * DS3000_XTAL_FREQ);
- if (nlpf > 23)
- nlpf = 23;
- if (nlpf < 1)
- nlpf = 1;
-
- /* rounded to the closest integer */
- mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
- (1000 * f3db / 2)) / (1000 * f3db);
-
- if (mlpf_new < mlpf_min) {
- nlpf++;
- mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
- (1000 * f3db / 2)) / (1000 * f3db);
- }
-
- if (mlpf_new > mlpf_max)
- mlpf_new = mlpf_max;
-
- ds3000_tuner_writereg(state, 0x04, mlpf_new);
- ds3000_tuner_writereg(state, 0x06, nlpf);
- ds3000_tuner_writereg(state, 0x51, 0x1b);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x04);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- /* unknown */
- ds3000_tuner_writereg(state, 0x51, 0x1e);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x01);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(60);
-
- offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ
- / (6 + 8) / (div4 + 1) / 2 - c->frequency;
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe);
/* ds3000 global reset */
ds3000_writereg(state, 0x07, 0x80);
@@ -1186,7 +1017,11 @@ static int ds3000_set_frontend(struct dvb_frontend *fe)
/* start ds3000 build-in uC */
ds3000_writereg(state, 0xb2, 0x00);
- ds3000_set_carrier_offset(fe, offset_khz);
+ if (fe->ops.tuner_ops.get_frequency) {
+ fe->ops.tuner_ops.get_frequency(fe, &frequency);
+ offset_khz = frequency - c->frequency;
+ ds3000_set_carrier_offset(fe, offset_khz);
+ }
for (i = 0; i < 30 ; i++) {
ds3000_read_status(fe, &status);
@@ -1218,6 +1053,11 @@ static int ds3000_tune(struct dvb_frontend *fe,
static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
{
+ struct ds3000_state *state = fe->demodulator_priv;
+
+ if (state->config->set_lock_led)
+ state->config->set_lock_led(fe, 0);
+
dprintk("%s()\n", __func__);
return DVBFE_ALGO_HW;
}
@@ -1237,10 +1077,6 @@ static int ds3000_initfe(struct dvb_frontend *fe)
ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08));
msleep(1);
- /* TS2020 init */
- ds3000_tuner_writereg(state, 0x42, 0x73);
- ds3000_tuner_writereg(state, 0x05, 0x01);
- ds3000_tuner_writereg(state, 0x62, 0xf5);
/* Load the firmware if required */
ret = ds3000_firmware_ondemand(fe);
if (ret != 0) {
@@ -1251,17 +1087,10 @@ static int ds3000_initfe(struct dvb_frontend *fe)
return 0;
}
-/* Put device to sleep */
-static int ds3000_sleep(struct dvb_frontend *fe)
-{
- dprintk("%s()\n", __func__);
- return 0;
-}
-
static struct dvb_frontend_ops ds3000_ops = {
- .delsys = { SYS_DVBS, SYS_DVBS2},
+ .delsys = { SYS_DVBS, SYS_DVBS2 },
.info = {
- .name = "Montage Technology DS3000/TS2020",
+ .name = "Montage Technology DS3000",
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1011, /* kHz for QPSK frontends */
@@ -1279,7 +1108,7 @@ static struct dvb_frontend_ops ds3000_ops = {
.release = ds3000_release,
.init = ds3000_initfe,
- .sleep = ds3000_sleep,
+ .i2c_gate_ctrl = ds3000_i2c_gate_ctrl,
.read_status = ds3000_read_status,
.read_ber = ds3000_read_ber,
.read_signal_strength = ds3000_read_signal_strength,
@@ -1299,7 +1128,7 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
MODULE_DESCRIPTION("DVB Frontend module for Montage Technology "
- "DS3000/TS2020 hardware");
-MODULE_AUTHOR("Konstantin Dimitrov");
+ "DS3000 hardware");
+MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(DS3000_DEFAULT_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/ds3000.h b/drivers/media/dvb-frontends/ds3000.h
index 1b736888ea37..478ad66c63d7 100644
--- a/drivers/media/dvb-frontends/ds3000.h
+++ b/drivers/media/dvb-frontends/ds3000.h
@@ -1,8 +1,8 @@
/*
- Montage Technology DS3000/TS2020 - DVBS/S2 Satellite demod/tuner driver
- Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+ Montage Technology DS3000 - DVBS/S2 Demodulator driver
+ Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
- Copyright (C) 2009 TurboSight.com
+ Copyright (C) 2009-2012 TurboSight.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
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
+ */
#ifndef DS3000_H
#define DS3000_H
@@ -30,6 +30,8 @@ struct ds3000_config {
u8 ci_mode;
/* Set device param to start dma */
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+ /* Hook for Lock LED */
+ void (*set_lock_led)(struct dvb_frontend *fe, int offon);
};
#if defined(CONFIG_DVB_DS3000) || \
diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h
index 4de754f76ce9..f4b5a0601c3a 100644
--- a/drivers/media/dvb-frontends/dvb-pll.h
+++ b/drivers/media/dvb-frontends/dvb-pll.h
@@ -38,7 +38,7 @@
* @param pll_desc_id dvb_pll_desc to use.
* @return Frontend pointer on success, NULL on failure
*/
-#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_PLL)
extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
int pll_addr,
struct i2c_adapter *i2c,
diff --git a/drivers/media/dvb-frontends/isl6405.h b/drivers/media/dvb-frontends/isl6405.h
index 1c793d37576b..8abb70c26fd9 100644
--- a/drivers/media/dvb-frontends/isl6405.h
+++ b/drivers/media/dvb-frontends/isl6405.h
@@ -55,7 +55,7 @@
#define ISL6405_ENT2 0x20
#define ISL6405_ISEL2 0x40
-#if defined(CONFIG_DVB_ISL6405) || (defined(CONFIG_DVB_ISL6405_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_ISL6405)
/* override_set and override_clear control which system register bits (above)
* to always set & clear
*/
diff --git a/drivers/media/dvb-frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h
index 47e4518a042d..e7ca7d12b50a 100644
--- a/drivers/media/dvb-frontends/isl6421.h
+++ b/drivers/media/dvb-frontends/isl6421.h
@@ -39,7 +39,7 @@
#define ISL6421_ISEL1 0x20
#define ISL6421_DCL 0x40
-#if defined(CONFIG_DVB_ISL6421) || (defined(CONFIG_DVB_ISL6421_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_ISL6421)
/* override_set and override_clear control which system register bits (above) to always set & clear */
extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
u8 override_set, u8 override_clear);
diff --git a/drivers/media/dvb-frontends/isl6423.h b/drivers/media/dvb-frontends/isl6423.h
index e1a37fba01ca..80dfd9cc4f41 100644
--- a/drivers/media/dvb-frontends/isl6423.h
+++ b/drivers/media/dvb-frontends/isl6423.h
@@ -42,7 +42,7 @@ struct isl6423_config {
u8 mod_extern;
};
-#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_ISL6423)
extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb-frontends/itd1000.h b/drivers/media/dvb-frontends/itd1000.h
index 5e18df071b88..edae0902f4fd 100644
--- a/drivers/media/dvb-frontends/itd1000.h
+++ b/drivers/media/dvb-frontends/itd1000.h
@@ -29,7 +29,7 @@ struct itd1000_config {
u8 i2c_address;
};
-#if defined(CONFIG_DVB_TUNER_ITD1000) || (defined(CONFIG_DVB_TUNER_ITD1000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TUNER_ITD1000)
extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg);
#else
static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
diff --git a/drivers/media/dvb-frontends/ix2505v.c b/drivers/media/dvb-frontends/ix2505v.c
index bc5a82082aaa..0e3387e00952 100644
--- a/drivers/media/dvb-frontends/ix2505v.c
+++ b/drivers/media/dvb-frontends/ix2505v.c
@@ -212,7 +212,7 @@ static int ix2505v_set_params(struct dvb_frontend *fe)
lpf = 0xb;
deb_info("Osc=%x b_w=%x lpf=%x\n", local_osc, b_w, lpf);
- deb_info("Data 0=[%x%x%x%x]\n", data[0], data[1], data[2], data[3]);
+ deb_info("Data 0=[%4phN]\n", data);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
diff --git a/drivers/media/dvb-frontends/l64781.h b/drivers/media/dvb-frontends/l64781.h
index 1305a9e7fb0b..6813b08a774d 100644
--- a/drivers/media/dvb-frontends/l64781.h
+++ b/drivers/media/dvb-frontends/l64781.h
@@ -31,7 +31,7 @@ struct l64781_config
u8 demod_address;
};
-#if defined(CONFIG_DVB_L64781) || (defined(CONFIG_DVB_L64781_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_L64781)
extern struct dvb_frontend* l64781_attach(const struct l64781_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/lgdt330x.h b/drivers/media/dvb-frontends/lgdt330x.h
index 9012504f0f2d..ca0eab562e1e 100644
--- a/drivers/media/dvb-frontends/lgdt330x.h
+++ b/drivers/media/dvb-frontends/lgdt330x.h
@@ -52,7 +52,7 @@ struct lgdt330x_config
int clock_polarity_flip;
};
-#if defined(CONFIG_DVB_LGDT330X) || (defined(CONFIG_DVB_LGDT330X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_LGDT330X)
extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c
index 633815ed90ca..4da5272075cb 100644
--- a/drivers/media/dvb-frontends/m88rs2000.c
+++ b/drivers/media/dvb-frontends/m88rs2000.c
@@ -60,15 +60,13 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
#define info(format, arg...) \
printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg)
-static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
+static int m88rs2000_writereg(struct m88rs2000_state *state,
u8 reg, u8 data)
{
int ret;
- u8 addr = (tuner == 0) ? state->config->tuner_addr :
- state->config->demod_addr;
u8 buf[] = { reg, data };
struct i2c_msg msg = {
- .addr = addr,
+ .addr = state->config->demod_addr,
.flags = 0,
.buf = buf,
.len = 2
@@ -83,44 +81,20 @@ static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
return (ret != 1) ? -EREMOTEIO : 0;
}
-static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data)
-{
- return m88rs2000_writereg(state, 1, reg, data);
-}
-
-static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data)
-{
- m88rs2000_demod_write(state, 0x81, 0x84);
- udelay(10);
- return m88rs2000_writereg(state, 0, reg, data);
-
-}
-
-static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len)
-{
- struct m88rs2000_state *state = fe->demodulator_priv;
-
- if (len != 2)
- return -EINVAL;
-
- return m88rs2000_writereg(state, 1, buf[0], buf[1]);
-}
-
-static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
+static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 reg)
{
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
- u8 addr = (tuner == 0) ? state->config->tuner_addr :
- state->config->demod_addr;
+
struct i2c_msg msg[] = {
{
- .addr = addr,
+ .addr = state->config->demod_addr,
.flags = 0,
.buf = b0,
.len = 1
}, {
- .addr = addr,
+ .addr = state->config->demod_addr,
.flags = I2C_M_RD,
.buf = b1,
.len = 1
@@ -136,18 +110,6 @@ static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
return b1[0];
}
-static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg)
-{
- return m88rs2000_readreg(state, 1, reg);
-}
-
-static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg)
-{
- m88rs2000_demod_write(state, 0x81, 0x85);
- udelay(10);
- return m88rs2000_readreg(state, 0, reg);
-}
-
static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
{
struct m88rs2000_state *state = fe->demodulator_priv;
@@ -166,9 +128,9 @@ static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
b[0] = (u8) (temp >> 16) & 0xff;
b[1] = (u8) (temp >> 8) & 0xff;
b[2] = (u8) temp & 0xff;
- ret = m88rs2000_demod_write(state, 0x93, b[2]);
- ret |= m88rs2000_demod_write(state, 0x94, b[1]);
- ret |= m88rs2000_demod_write(state, 0x95, b[0]);
+ ret = m88rs2000_writereg(state, 0x93, b[2]);
+ ret |= m88rs2000_writereg(state, 0x94, b[1]);
+ ret |= m88rs2000_writereg(state, 0x95, b[0]);
deb_info("m88rs2000: m88rs2000_set_symbolrate\n");
return ret;
@@ -182,37 +144,37 @@ static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe,
int i;
u8 reg;
deb_info("%s\n", __func__);
- m88rs2000_demod_write(state, 0x9a, 0x30);
- reg = m88rs2000_demod_read(state, 0xb2);
+ m88rs2000_writereg(state, 0x9a, 0x30);
+ reg = m88rs2000_readreg(state, 0xb2);
reg &= 0x3f;
- m88rs2000_demod_write(state, 0xb2, reg);
+ m88rs2000_writereg(state, 0xb2, reg);
for (i = 0; i < m->msg_len; i++)
- m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]);
+ m88rs2000_writereg(state, 0xb3 + i, m->msg[i]);
- reg = m88rs2000_demod_read(state, 0xb1);
+ reg = m88rs2000_readreg(state, 0xb1);
reg &= 0x87;
reg |= ((m->msg_len - 1) << 3) | 0x07;
reg &= 0x7f;
- m88rs2000_demod_write(state, 0xb1, reg);
+ m88rs2000_writereg(state, 0xb1, reg);
for (i = 0; i < 15; i++) {
- if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0)
+ if ((m88rs2000_readreg(state, 0xb1) & 0x40) == 0x0)
break;
msleep(20);
}
- reg = m88rs2000_demod_read(state, 0xb1);
+ reg = m88rs2000_readreg(state, 0xb1);
if ((reg & 0x40) > 0x0) {
reg &= 0x7f;
reg |= 0x40;
- m88rs2000_demod_write(state, 0xb1, reg);
+ m88rs2000_writereg(state, 0xb1, reg);
}
- reg = m88rs2000_demod_read(state, 0xb2);
+ reg = m88rs2000_readreg(state, 0xb2);
reg &= 0x3f;
reg |= 0x80;
- m88rs2000_demod_write(state, 0xb2, reg);
- m88rs2000_demod_write(state, 0x9a, 0xb0);
+ m88rs2000_writereg(state, 0xb2, reg);
+ m88rs2000_writereg(state, 0x9a, 0xb0);
return 0;
@@ -224,14 +186,14 @@ static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe,
struct m88rs2000_state *state = fe->demodulator_priv;
u8 reg0, reg1;
deb_info("%s\n", __func__);
- m88rs2000_demod_write(state, 0x9a, 0x30);
+ m88rs2000_writereg(state, 0x9a, 0x30);
msleep(50);
- reg0 = m88rs2000_demod_read(state, 0xb1);
- reg1 = m88rs2000_demod_read(state, 0xb2);
+ reg0 = m88rs2000_readreg(state, 0xb1);
+ reg1 = m88rs2000_readreg(state, 0xb2);
/* TODO complete this section */
- m88rs2000_demod_write(state, 0xb2, reg1);
- m88rs2000_demod_write(state, 0xb1, reg0);
- m88rs2000_demod_write(state, 0x9a, 0xb0);
+ m88rs2000_writereg(state, 0xb2, reg1);
+ m88rs2000_writereg(state, 0xb1, reg0);
+ m88rs2000_writereg(state, 0x9a, 0xb0);
return 0;
}
@@ -240,9 +202,9 @@ static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
{
struct m88rs2000_state *state = fe->demodulator_priv;
u8 reg0, reg1;
- m88rs2000_demod_write(state, 0x9a, 0x30);
- reg0 = m88rs2000_demod_read(state, 0xb1);
- reg1 = m88rs2000_demod_read(state, 0xb2);
+ m88rs2000_writereg(state, 0x9a, 0x30);
+ reg0 = m88rs2000_readreg(state, 0xb1);
+ reg1 = m88rs2000_readreg(state, 0xb2);
reg1 &= 0x3f;
@@ -257,9 +219,9 @@ static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
default:
break;
}
- m88rs2000_demod_write(state, 0xb2, reg1);
- m88rs2000_demod_write(state, 0xb1, reg0);
- m88rs2000_demod_write(state, 0x9a, 0xb0);
+ m88rs2000_writereg(state, 0xb2, reg1);
+ m88rs2000_writereg(state, 0xb1, reg0);
+ m88rs2000_writereg(state, 0x9a, 0xb0);
return 0;
}
@@ -276,14 +238,6 @@ struct inittab m88rs2000_setup[] = {
{DEMOD_WRITE, 0x00, 0x00},
{DEMOD_WRITE, 0x9a, 0xb0},
{DEMOD_WRITE, 0x81, 0xc1},
- {TUNER_WRITE, 0x42, 0x73},
- {TUNER_WRITE, 0x05, 0x07},
- {TUNER_WRITE, 0x20, 0x27},
- {TUNER_WRITE, 0x07, 0x02},
- {TUNER_WRITE, 0x11, 0xff},
- {TUNER_WRITE, 0x60, 0xf9},
- {TUNER_WRITE, 0x08, 0x01},
- {TUNER_WRITE, 0x00, 0x41},
{DEMOD_WRITE, 0x81, 0x81},
{DEMOD_WRITE, 0x86, 0xc6},
{DEMOD_WRITE, 0x9a, 0x30},
@@ -301,23 +255,10 @@ struct inittab m88rs2000_shutdown[] = {
{DEMOD_WRITE, 0xf1, 0x89},
{DEMOD_WRITE, 0x00, 0x01},
{DEMOD_WRITE, 0x9a, 0xb0},
- {TUNER_WRITE, 0x00, 0x40},
{DEMOD_WRITE, 0x81, 0x81},
{0xff, 0xaa, 0xff}
};
-struct inittab tuner_reset[] = {
- {TUNER_WRITE, 0x42, 0x73},
- {TUNER_WRITE, 0x05, 0x07},
- {TUNER_WRITE, 0x20, 0x27},
- {TUNER_WRITE, 0x07, 0x02},
- {TUNER_WRITE, 0x11, 0xff},
- {TUNER_WRITE, 0x60, 0xf9},
- {TUNER_WRITE, 0x08, 0x01},
- {TUNER_WRITE, 0x00, 0x41},
- {0xff, 0xaa, 0xff}
-};
-
struct inittab fe_reset[] = {
{DEMOD_WRITE, 0x00, 0x01},
{DEMOD_WRITE, 0xf1, 0xbf},
@@ -389,11 +330,7 @@ static int m88rs2000_tab_set(struct m88rs2000_state *state,
for (i = 0; i < 255; i++) {
switch (tab[i].cmd) {
case 0x01:
- ret = m88rs2000_demod_write(state, tab[i].reg,
- tab[i].val);
- break;
- case 0x02:
- ret = m88rs2000_tuner_write(state, tab[i].reg,
+ ret = m88rs2000_writereg(state, tab[i].reg,
tab[i].val);
break;
case 0x10:
@@ -419,7 +356,7 @@ static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
struct m88rs2000_state *state = fe->demodulator_priv;
u8 data;
- data = m88rs2000_demod_read(state, 0xb2);
+ data = m88rs2000_readreg(state, 0xb2);
data |= 0x03; /* bit0 V/H, bit1 off/on */
switch (volt) {
@@ -434,23 +371,11 @@ static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
break;
}
- m88rs2000_demod_write(state, 0xb2, data);
+ m88rs2000_writereg(state, 0xb2, data);
return 0;
}
-static int m88rs2000_startup(struct m88rs2000_state *state)
-{
- int ret = 0;
- u8 reg;
-
- reg = m88rs2000_tuner_read(state, 0x00);
- if ((reg & 0x40) == 0)
- ret = -ENODEV;
-
- return ret;
-}
-
static int m88rs2000_init(struct dvb_frontend *fe)
{
struct m88rs2000_state *state = fe->demodulator_priv;
@@ -458,7 +383,11 @@ static int m88rs2000_init(struct dvb_frontend *fe)
deb_info("m88rs2000: init chip\n");
/* Setup frontend from shutdown/cold */
- ret = m88rs2000_tab_set(state, m88rs2000_setup);
+ if (state->config->inittab)
+ ret = m88rs2000_tab_set(state,
+ (struct inittab *)state->config->inittab);
+ else
+ ret = m88rs2000_tab_set(state, m88rs2000_setup);
return ret;
}
@@ -475,7 +404,7 @@ static int m88rs2000_sleep(struct dvb_frontend *fe)
static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct m88rs2000_state *state = fe->demodulator_priv;
- u8 reg = m88rs2000_demod_read(state, 0x8c);
+ u8 reg = m88rs2000_readreg(state, 0x8c);
*status = 0;
@@ -488,183 +417,64 @@ static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
return 0;
}
-/* Extact code for these unknown but lmedm04 driver uses interupt callbacks */
-
static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber)
{
- deb_info("m88rs2000_read_ber %d\n", *ber);
- *ber = 0;
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ u8 tmp0, tmp1;
+
+ m88rs2000_writereg(state, 0x9a, 0x30);
+ tmp0 = m88rs2000_readreg(state, 0xd8);
+ if ((tmp0 & 0x10) != 0) {
+ m88rs2000_writereg(state, 0x9a, 0xb0);
+ *ber = 0xffffffff;
+ return 0;
+ }
+
+ *ber = (m88rs2000_readreg(state, 0xd7) << 8) |
+ m88rs2000_readreg(state, 0xd6);
+
+ tmp1 = m88rs2000_readreg(state, 0xd9);
+ m88rs2000_writereg(state, 0xd9, (tmp1 & ~7) | 4);
+ /* needs twice */
+ m88rs2000_writereg(state, 0xd8, (tmp0 & ~8) | 0x30);
+ m88rs2000_writereg(state, 0xd8, (tmp0 & ~8) | 0x30);
+ m88rs2000_writereg(state, 0x9a, 0xb0);
+
return 0;
}
static int m88rs2000_read_signal_strength(struct dvb_frontend *fe,
u16 *strength)
{
- *strength = 0;
- return 0;
-}
+ if (fe->ops.tuner_ops.get_rf_strength)
+ fe->ops.tuner_ops.get_rf_strength(fe, strength);
-static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- deb_info("m88rs2000_read_snr %d\n", *snr);
- *snr = 0;
return 0;
}
-static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
- deb_info("m88rs2000_read_ber %d\n", *ucblocks);
- *ucblocks = 0;
- return 0;
-}
-
-static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset)
-{
- int ret;
- ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset);
- ret |= m88rs2000_tuner_write(state, 0x51, 0x1f);
- ret |= m88rs2000_tuner_write(state, 0x50, offset);
- ret |= m88rs2000_tuner_write(state, 0x50, 0x00);
- msleep(20);
- return ret;
-}
-
-static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe)
+static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct m88rs2000_state *state = fe->demodulator_priv;
- int reg;
- reg = m88rs2000_tuner_read(state, 0x3d);
- reg &= 0x7f;
- if (reg < 0x16)
- reg = 0xa1;
- else if (reg == 0x16)
- reg = 0x99;
- else
- reg = 0xf9;
- m88rs2000_tuner_write(state, 0x60, reg);
- reg = m88rs2000_tuner_gate_ctrl(state, 0x08);
+ *snr = 512 * m88rs2000_readreg(state, 0x65);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- return reg;
+ return 0;
}
-static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset)
+static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct m88rs2000_state *state = fe->demodulator_priv;
- int ret;
- u32 frequency = c->frequency;
- s32 offset_khz;
- s32 tmp;
- u32 symbol_rate = (c->symbol_rate / 1000);
- u32 f3db, gdiv28;
- u16 value, ndiv, lpf_coeff;
- u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
- u8 lo = 0x01, div4 = 0x0;
-
- /* Reset Tuner */
- ret = m88rs2000_tab_set(state, tuner_reset);
-
- /* Calculate frequency divider */
- if (frequency < 1060000) {
- lo |= 0x10;
- div4 = 0x1;
- ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ;
- } else
- ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ;
- ndiv = ndiv + ndiv % 2;
- ndiv = ndiv - 1024;
-
- ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo);
-
- /* Set frequency divider */
- ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf);
- ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff);
-
- ret |= m88rs2000_tuner_write(state, 0x03, 0x06);
- ret |= m88rs2000_tuner_gate_ctrl(state, 0x10);
- if (ret < 0)
- return -ENODEV;
-
- /* Tuner Frequency Range */
- ret = m88rs2000_tuner_write(state, 0x10, lo);
-
- ret |= m88rs2000_tuner_gate_ctrl(state, 0x08);
-
- /* Tuner RF */
- ret |= m88rs2000_set_tuner_rf(fe);
-
- gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
- ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff);
- ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
- if (ret < 0)
- return -ENODEV;
-
- value = m88rs2000_tuner_read(state, 0x26);
-
- f3db = (symbol_rate * 135) / 200 + 2000;
- f3db += FREQ_OFFSET_LOW_SYM_RATE;
- if (f3db < 7000)
- f3db = 7000;
- if (f3db > 40000)
- f3db = 40000;
-
- gdiv28 = gdiv28 * 207 / (value * 2 + 151);
- mlpf_max = gdiv28 * 135 / 100;
- mlpf_min = gdiv28 * 78 / 100;
- if (mlpf_max > 63)
- mlpf_max = 63;
-
- lpf_coeff = 2766;
-
- nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
- (FE_CRYSTAL_KHZ / 1000) + 1) / 2;
- if (nlpf > 23)
- nlpf = 23;
- if (nlpf < 1)
- nlpf = 1;
-
- lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
- * lpf_coeff * 2 / f3db + 1) / 2;
-
- if (lpf_mxdiv < mlpf_min) {
- nlpf++;
- lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
- * lpf_coeff * 2 / f3db + 1) / 2;
- }
-
- if (lpf_mxdiv > mlpf_max)
- lpf_mxdiv = mlpf_max;
-
- ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv);
- ret |= m88rs2000_tuner_write(state, 0x06, nlpf);
-
- ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
-
- ret |= m88rs2000_tuner_gate_ctrl(state, 0x01);
-
- msleep(80);
- /* calculate offset assuming 96000kHz*/
- offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ
- / 14 / (div4 + 1) / 2;
+ u8 tmp;
- offset_khz -= frequency;
+ *ucblocks = (m88rs2000_readreg(state, 0xd5) << 8) |
+ m88rs2000_readreg(state, 0xd4);
+ tmp = m88rs2000_readreg(state, 0xd8);
+ m88rs2000_writereg(state, 0xd8, tmp & ~0x20);
+ /* needs two times */
+ m88rs2000_writereg(state, 0xd8, tmp | 0x20);
+ m88rs2000_writereg(state, 0xd8, tmp | 0x20);
- tmp = offset_khz;
- tmp *= 65536;
-
- tmp = (2 * tmp + 96000) / (2 * 96000);
- if (tmp < 0)
- tmp += 65536;
-
- *offset = tmp & 0xffff;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- return (ret < 0) ? -EINVAL : 0;
+ return 0;
}
static int m88rs2000_set_fec(struct m88rs2000_state *state,
@@ -692,7 +502,7 @@ static int m88rs2000_set_fec(struct m88rs2000_state *state,
default:
fec_set = 0x08;
}
- m88rs2000_demod_write(state, 0x76, fec_set);
+ m88rs2000_writereg(state, 0x76, fec_set);
return 0;
}
@@ -701,9 +511,9 @@ static int m88rs2000_set_fec(struct m88rs2000_state *state,
static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
{
u8 reg;
- m88rs2000_demod_write(state, 0x9a, 0x30);
- reg = m88rs2000_demod_read(state, 0x76);
- m88rs2000_demod_write(state, 0x9a, 0xb0);
+ m88rs2000_writereg(state, 0x9a, 0x30);
+ reg = m88rs2000_readreg(state, 0x76);
+ m88rs2000_writereg(state, 0x9a, 0xb0);
switch (reg) {
case 0x88:
@@ -729,7 +539,9 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
struct m88rs2000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
fe_status_t status;
- int i, ret;
+ int i, ret = 0;
+ s32 tmp;
+ u32 tuner_freq;
u16 offset = 0;
u8 reg;
@@ -743,17 +555,37 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
}
/* Set Tuner */
- ret = m88rs2000_set_tuner(fe, &offset);
+ if (fe->ops.tuner_ops.set_params)
+ ret = fe->ops.tuner_ops.set_params(fe);
+
+ if (ret < 0)
+ return -ENODEV;
+
+ if (fe->ops.tuner_ops.get_frequency)
+ ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_freq);
+
if (ret < 0)
return -ENODEV;
- ret = m88rs2000_demod_write(state, 0x9a, 0x30);
+ offset = tuner_freq - c->frequency;
+
+ /* calculate offset assuming 96000kHz*/
+ tmp = offset;
+ tmp *= 65536;
+
+ tmp = (2 * tmp + 96000) / (2 * 96000);
+ if (tmp < 0)
+ tmp += 65536;
+
+ offset = tmp & 0xffff;
+
+ ret = m88rs2000_writereg(state, 0x9a, 0x30);
/* Unknown usually 0xc6 sometimes 0xc1 */
- reg = m88rs2000_demod_read(state, 0x86);
- ret |= m88rs2000_demod_write(state, 0x86, reg);
+ reg = m88rs2000_readreg(state, 0x86);
+ ret |= m88rs2000_writereg(state, 0x86, reg);
/* Offset lower nibble always 0 */
- ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8));
- ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0);
+ ret |= m88rs2000_writereg(state, 0x9c, (offset >> 8));
+ ret |= m88rs2000_writereg(state, 0x9d, offset & 0xf0);
/* Reset Demod */
@@ -762,16 +594,16 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
return -ENODEV;
/* Unknown */
- reg = m88rs2000_demod_read(state, 0x70);
- ret = m88rs2000_demod_write(state, 0x70, reg);
+ reg = m88rs2000_readreg(state, 0x70);
+ ret = m88rs2000_writereg(state, 0x70, reg);
/* Set FEC */
ret |= m88rs2000_set_fec(state, c->fec_inner);
- ret |= m88rs2000_demod_write(state, 0x85, 0x1);
- ret |= m88rs2000_demod_write(state, 0x8a, 0xbf);
- ret |= m88rs2000_demod_write(state, 0x8d, 0x1e);
- ret |= m88rs2000_demod_write(state, 0x90, 0xf1);
- ret |= m88rs2000_demod_write(state, 0x91, 0x08);
+ ret |= m88rs2000_writereg(state, 0x85, 0x1);
+ ret |= m88rs2000_writereg(state, 0x8a, 0xbf);
+ ret |= m88rs2000_writereg(state, 0x8d, 0x1e);
+ ret |= m88rs2000_writereg(state, 0x90, 0xf1);
+ ret |= m88rs2000_writereg(state, 0x91, 0x08);
if (ret < 0)
return -ENODEV;
@@ -787,27 +619,25 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
return -ENODEV;
for (i = 0; i < 25; i++) {
- reg = m88rs2000_demod_read(state, 0x8c);
+ reg = m88rs2000_readreg(state, 0x8c);
if ((reg & 0x7) == 0x7) {
status = FE_HAS_LOCK;
break;
}
state->no_lock_count++;
if (state->no_lock_count == 15) {
- reg = m88rs2000_demod_read(state, 0x70);
+ reg = m88rs2000_readreg(state, 0x70);
reg ^= 0x4;
- m88rs2000_demod_write(state, 0x70, reg);
+ m88rs2000_writereg(state, 0x70, reg);
state->no_lock_count = 0;
}
- if (state->no_lock_count == 20)
- m88rs2000_set_tuner_rf(fe);
msleep(20);
}
if (status & FE_HAS_LOCK) {
state->fec_inner = m88rs2000_get_fec(state);
/* Uknown suspect SNR level */
- reg = m88rs2000_demod_read(state, 0x65);
+ reg = m88rs2000_readreg(state, 0x65);
}
state->tuner_frequency = c->frequency;
@@ -830,9 +660,9 @@ static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
struct m88rs2000_state *state = fe->demodulator_priv;
if (enable)
- m88rs2000_demod_write(state, 0x81, 0x84);
+ m88rs2000_writereg(state, 0x81, 0x84);
else
- m88rs2000_demod_write(state, 0x81, 0x81);
+ m88rs2000_writereg(state, 0x81, 0x81);
udelay(10);
return 0;
}
@@ -863,7 +693,6 @@ static struct dvb_frontend_ops m88rs2000_ops = {
.release = m88rs2000_release,
.init = m88rs2000_init,
.sleep = m88rs2000_sleep,
- .write = m88rs2000_write,
.i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl,
.read_status = m88rs2000_read_status,
.read_ber = m88rs2000_read_ber,
@@ -896,9 +725,6 @@ struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config,
state->symbol_rate = 0;
state->fec_inner = 0;
- if (m88rs2000_startup(state) < 0)
- goto error;
-
/* create dvb_frontend */
memcpy(&state->frontend.ops, &m88rs2000_ops,
sizeof(struct dvb_frontend_ops));
diff --git a/drivers/media/dvb-frontends/m88rs2000.h b/drivers/media/dvb-frontends/m88rs2000.h
index 59acdb696873..5a8023e5a4b8 100644
--- a/drivers/media/dvb-frontends/m88rs2000.h
+++ b/drivers/media/dvb-frontends/m88rs2000.h
@@ -26,8 +26,6 @@
struct m88rs2000_config {
/* Demodulator i2c address */
u8 demod_addr;
- /* Tuner address */
- u8 tuner_addr;
u8 *inittab;
@@ -55,12 +53,8 @@ static inline struct dvb_frontend *m88rs2000_attach(
}
#endif /* CONFIG_DVB_M88RS2000 */
-#define FE_CRYSTAL_KHZ 27000
-#define FREQ_OFFSET_LOW_SYM_RATE 3000
-
enum {
DEMOD_WRITE = 0x1,
- TUNER_WRITE,
WRITE_DELAY = 0x10,
};
#endif /* M88RS2000_H */
diff --git a/drivers/media/dvb-frontends/mb86a16.h b/drivers/media/dvb-frontends/mb86a16.h
index 6ea8c376394f..277ce061acf9 100644
--- a/drivers/media/dvb-frontends/mb86a16.h
+++ b/drivers/media/dvb-frontends/mb86a16.h
@@ -33,7 +33,7 @@ struct mb86a16_config {
-#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_MB86A16)
extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
struct i2c_adapter *i2c_adap);
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index fade566927c3..f19cd7367040 100644
--- a/drivers/media/dvb-frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -1,11 +1,9 @@
/*
* Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver
*
- * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010-2013 Mauro Carvalho Chehab <mchehab@redhat.com>
* Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
*
- * FIXME: Need to port to DVB v5.2 API
- *
* This program is free software; 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.
@@ -26,24 +24,15 @@ static int debug = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-#define rc(args...) do { \
- printk(KERN_ERR "mb86a20s: " args); \
-} while (0)
-
-#define dprintk(args...) \
- do { \
- if (debug) { \
- printk(KERN_DEBUG "mb86a20s: %s: ", __func__); \
- printk(args); \
- } \
- } while (0)
-
struct mb86a20s_state {
struct i2c_adapter *i2c;
const struct mb86a20s_config *config;
+ u32 last_frequency;
struct dvb_frontend frontend;
+ u32 estimated_rate[3];
+
bool need_init;
};
@@ -52,6 +41,8 @@ struct regdata {
u8 data;
};
+#define BER_SAMPLING_RATE 1 /* Seconds */
+
/*
* Initialization sequence: Use whatevere default values that PV SBTVD
* does on its initialisation, obtained via USB snoop
@@ -94,41 +85,68 @@ static struct regdata mb86a20s_init[] = {
{ 0x04, 0x13 }, { 0x05, 0xff },
{ 0x04, 0x15 }, { 0x05, 0x4e },
{ 0x04, 0x16 }, { 0x05, 0x20 },
- { 0x52, 0x01 },
- { 0x50, 0xa7 }, { 0x51, 0xff },
+
+ /*
+ * On this demod, when the bit count reaches the count below,
+ * it collects the bit error count. The bit counters are initialized
+ * to 65535 here. This warrants that all of them will be quickly
+ * calculated when device gets locked. As TMCC is parsed, the values
+ * will be adjusted later in the driver's code.
+ */
+ { 0x52, 0x01 }, /* Turn on BER before Viterbi */
+ { 0x50, 0xa7 }, { 0x51, 0x00 },
{ 0x50, 0xa8 }, { 0x51, 0xff },
{ 0x50, 0xa9 }, { 0x51, 0xff },
- { 0x50, 0xaa }, { 0x51, 0xff },
+ { 0x50, 0xaa }, { 0x51, 0x00 },
{ 0x50, 0xab }, { 0x51, 0xff },
{ 0x50, 0xac }, { 0x51, 0xff },
- { 0x50, 0xad }, { 0x51, 0xff },
+ { 0x50, 0xad }, { 0x51, 0x00 },
{ 0x50, 0xae }, { 0x51, 0xff },
{ 0x50, 0xaf }, { 0x51, 0xff },
- { 0x5e, 0x07 },
- { 0x50, 0xdc }, { 0x51, 0x01 },
- { 0x50, 0xdd }, { 0x51, 0xf4 },
- { 0x50, 0xde }, { 0x51, 0x01 },
- { 0x50, 0xdf }, { 0x51, 0xf4 },
- { 0x50, 0xe0 }, { 0x51, 0x01 },
- { 0x50, 0xe1 }, { 0x51, 0xf4 },
- { 0x50, 0xb0 }, { 0x51, 0x07 },
- { 0x50, 0xb2 }, { 0x51, 0xff },
- { 0x50, 0xb3 }, { 0x51, 0xff },
- { 0x50, 0xb4 }, { 0x51, 0xff },
- { 0x50, 0xb5 }, { 0x51, 0xff },
- { 0x50, 0xb6 }, { 0x51, 0xff },
- { 0x50, 0xb7 }, { 0x51, 0xff },
- { 0x50, 0x50 }, { 0x51, 0x02 },
- { 0x50, 0x51 }, { 0x51, 0x04 },
- { 0x45, 0x04 },
- { 0x48, 0x04 },
+
+ /*
+ * On this demod, post BER counts blocks. When the count reaches the
+ * value below, it collects the block error count. The block counters
+ * are initialized to 127 here. This warrants that all of them will be
+ * quickly calculated when device gets locked. As TMCC is parsed, the
+ * values will be adjusted later in the driver's code.
+ */
+ { 0x5e, 0x07 }, /* Turn on BER after Viterbi */
+ { 0x50, 0xdc }, { 0x51, 0x00 },
+ { 0x50, 0xdd }, { 0x51, 0x7f },
+ { 0x50, 0xde }, { 0x51, 0x00 },
+ { 0x50, 0xdf }, { 0x51, 0x7f },
+ { 0x50, 0xe0 }, { 0x51, 0x00 },
+ { 0x50, 0xe1 }, { 0x51, 0x7f },
+
+ /*
+ * On this demod, when the block count reaches the count below,
+ * it collects the block error count. The block counters are initialized
+ * to 127 here. This warrants that all of them will be quickly
+ * calculated when device gets locked. As TMCC is parsed, the values
+ * will be adjusted later in the driver's code.
+ */
+ { 0x50, 0xb0 }, { 0x51, 0x07 }, /* Enable PER */
+ { 0x50, 0xb2 }, { 0x51, 0x00 },
+ { 0x50, 0xb3 }, { 0x51, 0x7f },
+ { 0x50, 0xb4 }, { 0x51, 0x00 },
+ { 0x50, 0xb5 }, { 0x51, 0x7f },
+ { 0x50, 0xb6 }, { 0x51, 0x00 },
+ { 0x50, 0xb7 }, { 0x51, 0x7f },
+
+ { 0x50, 0x50 }, { 0x51, 0x02 }, /* MER manual mode */
+ { 0x50, 0x51 }, { 0x51, 0x04 }, /* MER symbol 4 */
+ { 0x45, 0x04 }, /* CN symbol 4 */
+ { 0x48, 0x04 }, /* CN manual mode */
+
{ 0x50, 0xd5 }, { 0x51, 0x01 }, /* Serial */
{ 0x50, 0xd6 }, { 0x51, 0x1f },
{ 0x50, 0xd2 }, { 0x51, 0x03 },
{ 0x50, 0xd7 }, { 0x51, 0x3f },
{ 0x28, 0x74 }, { 0x29, 0x00 }, { 0x28, 0x74 }, { 0x29, 0x40 },
{ 0x28, 0x46 }, { 0x29, 0x2c }, { 0x28, 0x46 }, { 0x29, 0x0c },
- { 0x04, 0x40 }, { 0x05, 0x01 },
+
+ { 0x04, 0x40 }, { 0x05, 0x00 },
{ 0x28, 0x00 }, { 0x29, 0x10 },
{ 0x28, 0x05 }, { 0x29, 0x02 },
{ 0x1c, 0x01 },
@@ -176,8 +194,24 @@ static struct regdata mb86a20s_reset_reception[] = {
{ 0x08, 0x00 },
};
+static struct regdata mb86a20s_per_ber_reset[] = {
+ { 0x53, 0x00 }, /* pre BER Counter reset */
+ { 0x53, 0x07 },
+
+ { 0x5f, 0x00 }, /* post BER Counter reset */
+ { 0x5f, 0x07 },
+
+ { 0x50, 0xb1 }, /* PER Counter reset */
+ { 0x51, 0x07 },
+ { 0x51, 0x00 },
+};
+
+/*
+ * I2C read/write functions and macros
+ */
+
static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
- u8 i2c_addr, int reg, int data)
+ u8 i2c_addr, u8 reg, u8 data)
{
u8 buf[] = { reg, data };
struct i2c_msg msg = {
@@ -187,8 +221,9 @@ static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
rc = i2c_transfer(state->i2c, &msg, 1);
if (rc != 1) {
- printk("%s: writereg error (rc == %i, reg == 0x%02x,"
- " data == 0x%02x)\n", __func__, rc, reg, data);
+ dev_err(&state->i2c->dev,
+ "%s: writereg error (rc == %i, reg == 0x%02x, data == 0x%02x)\n",
+ __func__, rc, reg, data);
return rc;
}
@@ -222,8 +257,9 @@ static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
rc = i2c_transfer(state->i2c, msg, 2);
if (rc != 2) {
- rc("%s: reg=0x%x (error=%d)\n", __func__, reg, rc);
- return rc;
+ dev_err(&state->i2c->dev, "%s: reg=0x%x (error=%d)\n",
+ __func__, reg, rc);
+ return (rc < 0) ? rc : -EIO;
}
return val;
@@ -237,100 +273,22 @@ static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
mb86a20s_i2c_writeregdata(state, state->config->demod_address, \
regdata, ARRAY_SIZE(regdata))
-static int mb86a20s_initfe(struct dvb_frontend *fe)
-{
- struct mb86a20s_state *state = fe->demodulator_priv;
- int rc;
- u8 regD5 = 1;
-
- dprintk("\n");
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- /* Initialize the frontend */
- rc = mb86a20s_writeregdata(state, mb86a20s_init);
- if (rc < 0)
- goto err;
-
- if (!state->config->is_serial) {
- regD5 &= ~1;
-
- rc = mb86a20s_writereg(state, 0x50, 0xd5);
- if (rc < 0)
- goto err;
- rc = mb86a20s_writereg(state, 0x51, regD5);
- if (rc < 0)
- goto err;
- }
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
-err:
- if (rc < 0) {
- state->need_init = true;
- printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n");
- } else {
- state->need_init = false;
- dprintk("Initialization succeeded.\n");
- }
- return rc;
-}
-
-static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
- struct mb86a20s_state *state = fe->demodulator_priv;
- unsigned rf_max, rf_min, rf;
- u8 val;
-
- dprintk("\n");
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- /* Does a binary search to get RF strength */
- rf_max = 0xfff;
- rf_min = 0;
- do {
- rf = (rf_max + rf_min) / 2;
- mb86a20s_writereg(state, 0x04, 0x1f);
- mb86a20s_writereg(state, 0x05, rf >> 8);
- mb86a20s_writereg(state, 0x04, 0x20);
- mb86a20s_writereg(state, 0x04, rf);
-
- val = mb86a20s_readreg(state, 0x02);
- if (val & 0x08)
- rf_min = (rf_max + rf_min) / 2;
- else
- rf_max = (rf_max + rf_min) / 2;
- if (rf_max - rf_min < 4) {
- *strength = (((rf_max + rf_min) / 2) * 65535) / 4095;
- break;
- }
- } while (1);
-
- dprintk("signal strength = %d\n", *strength);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- return 0;
-}
+/*
+ * Ancillary internal routines (likely compiled inlined)
+ *
+ * The functions below assume that gateway lock has already obtained
+ */
static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct mb86a20s_state *state = fe->demodulator_priv;
- u8 val;
+ int val;
- dprintk("\n");
*status = 0;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
val = mb86a20s_readreg(state, 0x0a) & 0xf;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
+ if (val < 0)
+ return val;
if (val >= 2)
*status |= FE_HAS_SIGNAL;
@@ -347,49 +305,56 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
if (val >= 8) /* Maybe 9? */
*status |= FE_HAS_LOCK;
- dprintk("val = %d, status = 0x%02x\n", val, *status);
+ dev_dbg(&state->i2c->dev, "%s: Status = 0x%02x (state = %d)\n",
+ __func__, *status, val);
return 0;
}
-static int mb86a20s_set_frontend(struct dvb_frontend *fe)
+static int mb86a20s_read_signal_strength(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
int rc;
-#if 0
- /*
- * FIXME: Properly implement the set frontend properties
- */
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-#endif
-
- dprintk("\n");
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- dprintk("Calling tuner set parameters\n");
- fe->ops.tuner_ops.set_params(fe);
+ unsigned rf_max, rf_min, rf;
- /*
- * Make it more reliable: if, for some reason, the initial
- * device initialization doesn't happen, initialize it when
- * a SBTVD parameters are adjusted.
- *
- * Unfortunately, due to a hard to track bug at tda829x/tda18271,
- * the agc callback logic is not called during DVB attach time,
- * causing mb86a20s to not be initialized with Kworld SBTVD.
- * So, this hack is needed, in order to make Kworld SBTVD to work.
- */
- if (state->need_init)
- mb86a20s_initfe(fe);
+ /* Does a binary search to get RF strength */
+ rf_max = 0xfff;
+ rf_min = 0;
+ do {
+ rf = (rf_max + rf_min) / 2;
+ rc = mb86a20s_writereg(state, 0x04, 0x1f);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x05, rf >> 8);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x04, 0x20);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x04, rf);
+ if (rc < 0)
+ return rc;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
+ rc = mb86a20s_readreg(state, 0x02);
+ if (rc < 0)
+ return rc;
+ if (rc & 0x08)
+ rf_min = (rf_max + rf_min) / 2;
+ else
+ rf_max = (rf_max + rf_min) / 2;
+ if (rf_max - rf_min < 4) {
+ rf = (rf_max + rf_min) / 2;
+
+ /* Rescale it from 2^12 (4096) to 2^16 */
+ rf <<= (16 - 12);
+ dev_dbg(&state->i2c->dev,
+ "%s: signal strength = %d (%d < RF=%d < %d)\n",
+ __func__, rf, rf_min, rf >> 4, rf_max);
+ return rf;
+ }
+ } while (1);
- return rc;
+ return 0;
}
static int mb86a20s_get_modulation(struct mb86a20s_state *state,
@@ -410,7 +375,7 @@ static int mb86a20s_get_modulation(struct mb86a20s_state *state,
rc = mb86a20s_readreg(state, 0x6e);
if (rc < 0)
return rc;
- switch ((rc & 0x70) >> 4) {
+ switch ((rc >> 4) & 0x07) {
case 0:
return DQPSK;
case 1:
@@ -443,7 +408,7 @@ static int mb86a20s_get_fec(struct mb86a20s_state *state,
rc = mb86a20s_readreg(state, 0x6e);
if (rc < 0)
return rc;
- switch (rc) {
+ switch ((rc >> 4) & 0x07) {
case 0:
return FEC_1_2;
case 1:
@@ -478,24 +443,38 @@ static int mb86a20s_get_interleaving(struct mb86a20s_state *state,
rc = mb86a20s_readreg(state, 0x6e);
if (rc < 0)
return rc;
- if (rc > 3)
- return -EINVAL; /* Not used */
- return rc;
+
+ switch ((rc >> 4) & 0x07) {
+ case 1:
+ return GUARD_INTERVAL_1_4;
+ case 2:
+ return GUARD_INTERVAL_1_8;
+ case 3:
+ return GUARD_INTERVAL_1_16;
+ case 4:
+ return GUARD_INTERVAL_1_32;
+
+ default:
+ case 0:
+ return GUARD_INTERVAL_AUTO;
+ }
}
static int mb86a20s_get_segment_count(struct mb86a20s_state *state,
unsigned layer)
{
int rc, count;
-
static unsigned char reg[] = {
[0] = 0x89, /* Layer A */
[1] = 0x8d, /* Layer B */
[2] = 0x91, /* Layer C */
};
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
if (layer >= ARRAY_SIZE(reg))
return -EINVAL;
+
rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
if (rc < 0)
return rc;
@@ -504,113 +483,1451 @@ static int mb86a20s_get_segment_count(struct mb86a20s_state *state,
return rc;
count = (rc >> 4) & 0x0f;
+ dev_dbg(&state->i2c->dev, "%s: segments: %d.\n", __func__, count);
+
return count;
}
+static void mb86a20s_reset_frontend_cache(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ /* Fixed parameters */
+ c->delivery_system = SYS_ISDBT;
+ c->bandwidth_hz = 6000000;
+
+ /* Initialize values that will be later autodetected */
+ c->isdbt_layer_enabled = 0;
+ c->transmission_mode = TRANSMISSION_MODE_AUTO;
+ c->guard_interval = GUARD_INTERVAL_AUTO;
+ c->isdbt_sb_mode = 0;
+ c->isdbt_sb_segment_count = 0;
+}
+
+/*
+ * Estimates the bit rate using the per-segment bit rate given by
+ * ABNT/NBR 15601 spec (table 4).
+ */
+static u32 isdbt_rate[3][5][4] = {
+ { /* DQPSK/QPSK */
+ { 280850, 312060, 330420, 340430 }, /* 1/2 */
+ { 374470, 416080, 440560, 453910 }, /* 2/3 */
+ { 421280, 468090, 495630, 510650 }, /* 3/4 */
+ { 468090, 520100, 550700, 567390 }, /* 5/6 */
+ { 491500, 546110, 578230, 595760 }, /* 7/8 */
+ }, { /* QAM16 */
+ { 561710, 624130, 660840, 680870 }, /* 1/2 */
+ { 748950, 832170, 881120, 907820 }, /* 2/3 */
+ { 842570, 936190, 991260, 1021300 }, /* 3/4 */
+ { 936190, 1040210, 1101400, 1134780 }, /* 5/6 */
+ { 983000, 1092220, 1156470, 1191520 }, /* 7/8 */
+ }, { /* QAM64 */
+ { 842570, 936190, 991260, 1021300 }, /* 1/2 */
+ { 1123430, 1248260, 1321680, 1361740 }, /* 2/3 */
+ { 1263860, 1404290, 1486900, 1531950 }, /* 3/4 */
+ { 1404290, 1560320, 1652110, 1702170 }, /* 5/6 */
+ { 1474500, 1638340, 1734710, 1787280 }, /* 7/8 */
+ }
+};
+
+static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
+ u32 modulation, u32 fec, u32 interleaving,
+ u32 segment)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ u32 rate;
+ int m, f, i;
+
+ /*
+ * If modulation/fec/interleaving is not detected, the default is
+ * to consider the lowest bit rate, to avoid taking too long time
+ * to get BER.
+ */
+ switch (modulation) {
+ case DQPSK:
+ case QPSK:
+ default:
+ m = 0;
+ break;
+ case QAM_16:
+ m = 1;
+ break;
+ case QAM_64:
+ m = 2;
+ break;
+ }
+
+ switch (fec) {
+ default:
+ case FEC_1_2:
+ case FEC_AUTO:
+ f = 0;
+ break;
+ case FEC_2_3:
+ f = 1;
+ break;
+ case FEC_3_4:
+ f = 2;
+ break;
+ case FEC_5_6:
+ f = 3;
+ break;
+ case FEC_7_8:
+ f = 4;
+ break;
+ }
+
+ switch (interleaving) {
+ default:
+ case GUARD_INTERVAL_1_4:
+ i = 0;
+ break;
+ case GUARD_INTERVAL_1_8:
+ i = 1;
+ break;
+ case GUARD_INTERVAL_1_16:
+ i = 2;
+ break;
+ case GUARD_INTERVAL_1_32:
+ i = 3;
+ break;
+ }
+
+ /* Samples BER at BER_SAMPLING_RATE seconds */
+ rate = isdbt_rate[m][f][i] * segment * BER_SAMPLING_RATE;
+
+ /* Avoids sampling too quickly or to overflow the register */
+ if (rate < 256)
+ rate = 256;
+ else if (rate > (1 << 24) - 1)
+ rate = (1 << 24) - 1;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: layer %c bitrate: %d kbps; counter = %d (0x%06x)\n",
+ __func__, 'A' + layer, segment * isdbt_rate[m][f][i]/1000,
+ rate, rate);
+
+ state->estimated_rate[i] = rate;
+}
+
+
static int mb86a20s_get_frontend(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int i, rc;
- /* Fixed parameters */
- p->delivery_system = SYS_ISDBT;
- p->bandwidth_hz = 6000000;
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ /* Reset frontend cache to default values */
+ mb86a20s_reset_frontend_cache(fe);
/* Check for partial reception */
rc = mb86a20s_writereg(state, 0x6d, 0x85);
- if (rc >= 0)
- rc = mb86a20s_readreg(state, 0x6e);
- if (rc >= 0)
- p->isdbt_partial_reception = (rc & 0x10) ? 1 : 0;
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x6e);
+ if (rc < 0)
+ return rc;
+ c->isdbt_partial_reception = (rc & 0x10) ? 1 : 0;
/* Get per-layer data */
- p->isdbt_layer_enabled = 0;
+
for (i = 0; i < 3; i++) {
+ dev_dbg(&state->i2c->dev, "%s: getting data for layer %c.\n",
+ __func__, 'A' + i);
+
rc = mb86a20s_get_segment_count(state, i);
- if (rc >= 0 && rc < 14)
- p->layer[i].segment_count = rc;
- if (rc == 0x0f)
+ if (rc < 0)
+ goto noperlayer_error;
+ if (rc >= 0 && rc < 14) {
+ c->layer[i].segment_count = rc;
+ } else {
+ c->layer[i].segment_count = 0;
+ state->estimated_rate[i] = 0;
continue;
- p->isdbt_layer_enabled |= 1 << i;
+ }
+ c->isdbt_layer_enabled |= 1 << i;
rc = mb86a20s_get_modulation(state, i);
- if (rc >= 0)
- p->layer[i].modulation = rc;
+ if (rc < 0)
+ goto noperlayer_error;
+ dev_dbg(&state->i2c->dev, "%s: modulation %d.\n",
+ __func__, rc);
+ c->layer[i].modulation = rc;
rc = mb86a20s_get_fec(state, i);
- if (rc >= 0)
- p->layer[i].fec = rc;
+ if (rc < 0)
+ goto noperlayer_error;
+ dev_dbg(&state->i2c->dev, "%s: FEC %d.\n",
+ __func__, rc);
+ c->layer[i].fec = rc;
rc = mb86a20s_get_interleaving(state, i);
- if (rc >= 0)
- p->layer[i].interleaving = rc;
+ if (rc < 0)
+ goto noperlayer_error;
+ dev_dbg(&state->i2c->dev, "%s: interleaving %d.\n",
+ __func__, rc);
+ c->layer[i].interleaving = rc;
+ mb86a20s_layer_bitrate(fe, i, c->layer[i].modulation,
+ c->layer[i].fec,
+ c->layer[i].interleaving,
+ c->layer[i].segment_count);
}
- p->isdbt_sb_mode = 0;
rc = mb86a20s_writereg(state, 0x6d, 0x84);
- if ((rc >= 0) && ((rc & 0x60) == 0x20)) {
- p->isdbt_sb_mode = 1;
+ if (rc < 0)
+ return rc;
+ if ((rc & 0x60) == 0x20) {
+ c->isdbt_sb_mode = 1;
/* At least, one segment should exist */
- if (!p->isdbt_sb_segment_count)
- p->isdbt_sb_segment_count = 1;
- } else
- p->isdbt_sb_segment_count = 0;
+ if (!c->isdbt_sb_segment_count)
+ c->isdbt_sb_segment_count = 1;
+ }
/* Get transmission mode and guard interval */
- p->transmission_mode = TRANSMISSION_MODE_AUTO;
- p->guard_interval = GUARD_INTERVAL_AUTO;
rc = mb86a20s_readreg(state, 0x07);
- if (rc >= 0) {
- if ((rc & 0x60) == 0x20) {
- switch (rc & 0x0c >> 2) {
- case 0:
- p->transmission_mode = TRANSMISSION_MODE_2K;
- break;
- case 1:
- p->transmission_mode = TRANSMISSION_MODE_4K;
- break;
- case 2:
- p->transmission_mode = TRANSMISSION_MODE_8K;
- break;
- }
+ if (rc < 0)
+ return rc;
+ if ((rc & 0x60) == 0x20) {
+ switch (rc & 0x0c >> 2) {
+ case 0:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ c->transmission_mode = TRANSMISSION_MODE_4K;
+ break;
+ case 2:
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ }
+ }
+ if (!(rc & 0x10)) {
+ switch (rc & 0x3) {
+ case 0:
+ c->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ case 1:
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 2:
+ c->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ }
+ }
+ return 0;
+
+noperlayer_error:
+
+ /* per-layer info is incomplete; discard all per-layer */
+ c->isdbt_layer_enabled = 0;
+
+ return rc;
+}
+
+static int mb86a20s_reset_counters(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc, val;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ /* Reset the counters, if the channel changed */
+ if (state->last_frequency != c->frequency) {
+ memset(&c->strength, 0, sizeof(c->strength));
+ memset(&c->cnr, 0, sizeof(c->cnr));
+ memset(&c->pre_bit_error, 0, sizeof(c->pre_bit_error));
+ memset(&c->pre_bit_count, 0, sizeof(c->pre_bit_count));
+ memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
+ memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
+ memset(&c->block_error, 0, sizeof(c->block_error));
+ memset(&c->block_count, 0, sizeof(c->block_count));
+
+ state->last_frequency = c->frequency;
+ }
+
+ /* Clear status for most stats */
+
+ /* BER/PER counter reset */
+ rc = mb86a20s_writeregdata(state, mb86a20s_per_ber_reset);
+ if (rc < 0)
+ goto err;
+
+ /* CNR counter reset */
+ rc = mb86a20s_readreg(state, 0x45);
+ if (rc < 0)
+ goto err;
+ val = rc;
+ rc = mb86a20s_writereg(state, 0x45, val | 0x10);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x45, val & 0x6f);
+ if (rc < 0)
+ goto err;
+
+ /* MER counter reset */
+ rc = mb86a20s_writereg(state, 0x50, 0x50);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ goto err;
+ val = rc;
+ rc = mb86a20s_writereg(state, 0x51, val | 0x01);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x51, val & 0x06);
+ if (rc < 0)
+ goto err;
+
+ goto ok;
+err:
+ dev_err(&state->i2c->dev,
+ "%s: Can't reset FE statistics (error %d).\n",
+ __func__, rc);
+ok:
+ return rc;
+}
+
+static int mb86a20s_get_pre_ber(struct dvb_frontend *fe,
+ unsigned layer,
+ u32 *error, u32 *count)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc, val;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ if (layer >= 3)
+ return -EINVAL;
+
+ /* Check if the BER measures are already available */
+ rc = mb86a20s_readreg(state, 0x54);
+ if (rc < 0)
+ return rc;
+
+ /* Check if data is available for that layer */
+ if (!(rc & (1 << layer))) {
+ dev_dbg(&state->i2c->dev,
+ "%s: preBER for layer %c is not available yet.\n",
+ __func__, 'A' + layer);
+ return -EBUSY;
+ }
+
+ /* Read Bit Error Count */
+ rc = mb86a20s_readreg(state, 0x55 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error = rc << 16;
+ rc = mb86a20s_readreg(state, 0x56 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error |= rc << 8;
+ rc = mb86a20s_readreg(state, 0x57 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error |= rc;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: bit error before Viterbi for layer %c: %d.\n",
+ __func__, 'A' + layer, *error);
+
+ /* Read Bit Count */
+ rc = mb86a20s_writereg(state, 0x50, 0xa7 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *count = rc << 16;
+ rc = mb86a20s_writereg(state, 0x50, 0xa8 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *count |= rc << 8;
+ rc = mb86a20s_writereg(state, 0x50, 0xa9 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *count |= rc;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: bit count before Viterbi for layer %c: %d.\n",
+ __func__, 'A' + layer, *count);
+
+
+ /*
+ * As we get TMCC data from the frontend, we can better estimate the
+ * BER bit counters, in order to do the BER measure during a longer
+ * time. Use those data, if available, to update the bit count
+ * measure.
+ */
+
+ if (state->estimated_rate[layer]
+ && state->estimated_rate[layer] != *count) {
+ dev_dbg(&state->i2c->dev,
+ "%s: updating layer %c preBER counter to %d.\n",
+ __func__, 'A' + layer, state->estimated_rate[layer]);
+
+ /* Turn off BER before Viterbi */
+ rc = mb86a20s_writereg(state, 0x52, 0x00);
+
+ /* Update counter for this layer */
+ rc = mb86a20s_writereg(state, 0x50, 0xa7 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51,
+ state->estimated_rate[layer] >> 16);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x50, 0xa8 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51,
+ state->estimated_rate[layer] >> 8);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x50, 0xa9 + layer * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51,
+ state->estimated_rate[layer]);
+ if (rc < 0)
+ return rc;
+
+ /* Turn on BER before Viterbi */
+ rc = mb86a20s_writereg(state, 0x52, 0x01);
+
+ /* Reset all preBER counters */
+ rc = mb86a20s_writereg(state, 0x53, 0x00);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x53, 0x07);
+ } else {
+ /* Reset counter to collect new data */
+ rc = mb86a20s_readreg(state, 0x53);
+ if (rc < 0)
+ return rc;
+ val = rc;
+ rc = mb86a20s_writereg(state, 0x53, val & ~(1 << layer));
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x53, val | (1 << layer));
+ }
+
+ return rc;
+}
+
+static int mb86a20s_get_post_ber(struct dvb_frontend *fe,
+ unsigned layer,
+ u32 *error, u32 *count)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ u32 counter, collect_rate;
+ int rc, val;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ if (layer >= 3)
+ return -EINVAL;
+
+ /* Check if the BER measures are already available */
+ rc = mb86a20s_readreg(state, 0x60);
+ if (rc < 0)
+ return rc;
+
+ /* Check if data is available for that layer */
+ if (!(rc & (1 << layer))) {
+ dev_dbg(&state->i2c->dev,
+ "%s: post BER for layer %c is not available yet.\n",
+ __func__, 'A' + layer);
+ return -EBUSY;
+ }
+
+ /* Read Bit Error Count */
+ rc = mb86a20s_readreg(state, 0x64 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error = rc << 16;
+ rc = mb86a20s_readreg(state, 0x65 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error |= rc << 8;
+ rc = mb86a20s_readreg(state, 0x66 + layer * 3);
+ if (rc < 0)
+ return rc;
+ *error |= rc;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: post bit error for layer %c: %d.\n",
+ __func__, 'A' + layer, *error);
+
+ /* Read Bit Count */
+ rc = mb86a20s_writereg(state, 0x50, 0xdc + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ counter = rc << 8;
+ rc = mb86a20s_writereg(state, 0x50, 0xdd + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ counter |= rc;
+ *count = counter * 204 * 8;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: post bit count for layer %c: %d.\n",
+ __func__, 'A' + layer, *count);
+
+ /*
+ * As we get TMCC data from the frontend, we can better estimate the
+ * BER bit counters, in order to do the BER measure during a longer
+ * time. Use those data, if available, to update the bit count
+ * measure.
+ */
+
+ if (!state->estimated_rate[layer])
+ goto reset_measurement;
+
+ collect_rate = state->estimated_rate[layer] / 204 / 8;
+ if (collect_rate < 32)
+ collect_rate = 32;
+ if (collect_rate > 65535)
+ collect_rate = 65535;
+ if (collect_rate != counter) {
+ dev_dbg(&state->i2c->dev,
+ "%s: updating postBER counter on layer %c to %d.\n",
+ __func__, 'A' + layer, collect_rate);
+
+ /* Turn off BER after Viterbi */
+ rc = mb86a20s_writereg(state, 0x5e, 0x00);
+
+ /* Update counter for this layer */
+ rc = mb86a20s_writereg(state, 0x50, 0xdc + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, collect_rate >> 8);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x50, 0xdd + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, collect_rate & 0xff);
+ if (rc < 0)
+ return rc;
+
+ /* Turn on BER after Viterbi */
+ rc = mb86a20s_writereg(state, 0x5e, 0x07);
+
+ /* Reset all preBER counters */
+ rc = mb86a20s_writereg(state, 0x5f, 0x00);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x5f, 0x07);
+
+ return rc;
+ }
+
+reset_measurement:
+ /* Reset counter to collect new data */
+ rc = mb86a20s_readreg(state, 0x5f);
+ if (rc < 0)
+ return rc;
+ val = rc;
+ rc = mb86a20s_writereg(state, 0x5f, val & ~(1 << layer));
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x5f, val | (1 << layer));
+
+ return rc;
+}
+
+static int mb86a20s_get_blk_error(struct dvb_frontend *fe,
+ unsigned layer,
+ u32 *error, u32 *count)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc, val;
+ u32 collect_rate;
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ if (layer >= 3)
+ return -EINVAL;
+
+ /* Check if the PER measures are already available */
+ rc = mb86a20s_writereg(state, 0x50, 0xb8);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+
+ /* Check if data is available for that layer */
+
+ if (!(rc & (1 << layer))) {
+ dev_dbg(&state->i2c->dev,
+ "%s: block counts for layer %c aren't available yet.\n",
+ __func__, 'A' + layer);
+ return -EBUSY;
+ }
+
+ /* Read Packet error Count */
+ rc = mb86a20s_writereg(state, 0x50, 0xb9 + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *error = rc << 8;
+ rc = mb86a20s_writereg(state, 0x50, 0xba + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *error |= rc;
+ dev_err(&state->i2c->dev, "%s: block error for layer %c: %d.\n",
+ __func__, 'A' + layer, *error);
+
+ /* Read Bit Count */
+ rc = mb86a20s_writereg(state, 0x50, 0xb2 + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *count = rc << 8;
+ rc = mb86a20s_writereg(state, 0x50, 0xb3 + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ *count |= rc;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: block count for layer %c: %d.\n",
+ __func__, 'A' + layer, *count);
+
+ /*
+ * As we get TMCC data from the frontend, we can better estimate the
+ * BER bit counters, in order to do the BER measure during a longer
+ * time. Use those data, if available, to update the bit count
+ * measure.
+ */
+
+ if (!state->estimated_rate[layer])
+ goto reset_measurement;
+
+ collect_rate = state->estimated_rate[layer] / 204 / 8;
+ if (collect_rate < 32)
+ collect_rate = 32;
+ if (collect_rate > 65535)
+ collect_rate = 65535;
+
+ if (collect_rate != *count) {
+ dev_dbg(&state->i2c->dev,
+ "%s: updating PER counter on layer %c to %d.\n",
+ __func__, 'A' + layer, collect_rate);
+
+ /* Stop PER measurement */
+ rc = mb86a20s_writereg(state, 0x50, 0xb0);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, 0x00);
+ if (rc < 0)
+ return rc;
+
+ /* Update this layer's counter */
+ rc = mb86a20s_writereg(state, 0x50, 0xb2 + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, collect_rate >> 8);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x50, 0xb3 + layer * 2);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, collect_rate & 0xff);
+ if (rc < 0)
+ return rc;
+
+ /* start PER measurement */
+ rc = mb86a20s_writereg(state, 0x50, 0xb0);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, 0x07);
+ if (rc < 0)
+ return rc;
+
+ /* Reset all counters to collect new data */
+ rc = mb86a20s_writereg(state, 0x50, 0xb1);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, 0x07);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, 0x00);
+
+ return rc;
+ }
+
+reset_measurement:
+ /* Reset counter to collect new data */
+ rc = mb86a20s_writereg(state, 0x50, 0xb1);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ val = rc;
+ rc = mb86a20s_writereg(state, 0x51, val | (1 << layer));
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, val & ~(1 << layer));
+
+ return rc;
+}
+
+struct linear_segments {
+ unsigned x, y;
+};
+
+/*
+ * All tables below return a dB/1000 measurement
+ */
+
+static struct linear_segments cnr_to_db_table[] = {
+ { 19648, 0},
+ { 18187, 1000},
+ { 16534, 2000},
+ { 14823, 3000},
+ { 13161, 4000},
+ { 11622, 5000},
+ { 10279, 6000},
+ { 9089, 7000},
+ { 8042, 8000},
+ { 7137, 9000},
+ { 6342, 10000},
+ { 5641, 11000},
+ { 5030, 12000},
+ { 4474, 13000},
+ { 3988, 14000},
+ { 3556, 15000},
+ { 3180, 16000},
+ { 2841, 17000},
+ { 2541, 18000},
+ { 2276, 19000},
+ { 2038, 20000},
+ { 1800, 21000},
+ { 1625, 22000},
+ { 1462, 23000},
+ { 1324, 24000},
+ { 1175, 25000},
+ { 1063, 26000},
+ { 980, 27000},
+ { 907, 28000},
+ { 840, 29000},
+ { 788, 30000},
+};
+
+static struct linear_segments cnr_64qam_table[] = {
+ { 3922688, 0},
+ { 3920384, 1000},
+ { 3902720, 2000},
+ { 3894784, 3000},
+ { 3882496, 4000},
+ { 3872768, 5000},
+ { 3858944, 6000},
+ { 3851520, 7000},
+ { 3838976, 8000},
+ { 3829248, 9000},
+ { 3818240, 10000},
+ { 3806976, 11000},
+ { 3791872, 12000},
+ { 3767040, 13000},
+ { 3720960, 14000},
+ { 3637504, 15000},
+ { 3498496, 16000},
+ { 3296000, 17000},
+ { 3031040, 18000},
+ { 2715392, 19000},
+ { 2362624, 20000},
+ { 1963264, 21000},
+ { 1649664, 22000},
+ { 1366784, 23000},
+ { 1120768, 24000},
+ { 890880, 25000},
+ { 723456, 26000},
+ { 612096, 27000},
+ { 518912, 28000},
+ { 448256, 29000},
+ { 388864, 30000},
+};
+
+static struct linear_segments cnr_16qam_table[] = {
+ { 5314816, 0},
+ { 5219072, 1000},
+ { 5118720, 2000},
+ { 4998912, 3000},
+ { 4875520, 4000},
+ { 4736000, 5000},
+ { 4604160, 6000},
+ { 4458752, 7000},
+ { 4300288, 8000},
+ { 4092928, 9000},
+ { 3836160, 10000},
+ { 3521024, 11000},
+ { 3155968, 12000},
+ { 2756864, 13000},
+ { 2347008, 14000},
+ { 1955072, 15000},
+ { 1593600, 16000},
+ { 1297920, 17000},
+ { 1043968, 18000},
+ { 839680, 19000},
+ { 672256, 20000},
+ { 523008, 21000},
+ { 424704, 22000},
+ { 345088, 23000},
+ { 280064, 24000},
+ { 221440, 25000},
+ { 179712, 26000},
+ { 151040, 27000},
+ { 128512, 28000},
+ { 110080, 29000},
+ { 95744, 30000},
+};
+
+struct linear_segments cnr_qpsk_table[] = {
+ { 2834176, 0},
+ { 2683648, 1000},
+ { 2536960, 2000},
+ { 2391808, 3000},
+ { 2133248, 4000},
+ { 1906176, 5000},
+ { 1666560, 6000},
+ { 1422080, 7000},
+ { 1189632, 8000},
+ { 976384, 9000},
+ { 790272, 10000},
+ { 633344, 11000},
+ { 505600, 12000},
+ { 402944, 13000},
+ { 320768, 14000},
+ { 255488, 15000},
+ { 204032, 16000},
+ { 163072, 17000},
+ { 130304, 18000},
+ { 105216, 19000},
+ { 83456, 20000},
+ { 65024, 21000},
+ { 52480, 22000},
+ { 42752, 23000},
+ { 34560, 24000},
+ { 27136, 25000},
+ { 22016, 26000},
+ { 18432, 27000},
+ { 15616, 28000},
+ { 13312, 29000},
+ { 11520, 30000},
+};
+
+static u32 interpolate_value(u32 value, struct linear_segments *segments,
+ unsigned len)
+{
+ u64 tmp64;
+ u32 dx, dy;
+ int i, ret;
+
+ if (value >= segments[0].x)
+ return segments[0].y;
+ if (value < segments[len-1].x)
+ return segments[len-1].y;
+
+ for (i = 1; i < len - 1; i++) {
+ /* If value is identical, no need to interpolate */
+ if (value == segments[i].x)
+ return segments[i].y;
+ if (value > segments[i].x)
+ break;
+ }
+
+ /* Linear interpolation between the two (x,y) points */
+ dy = segments[i].y - segments[i - 1].y;
+ dx = segments[i - 1].x - segments[i].x;
+ tmp64 = value - segments[i].x;
+ tmp64 *= dy;
+ do_div(tmp64, dx);
+ ret = segments[i].y - tmp64;
+
+ return ret;
+}
+
+static int mb86a20s_get_main_CNR(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 cnr_linear, cnr;
+ int rc, val;
+
+ /* Check if CNR is available */
+ rc = mb86a20s_readreg(state, 0x45);
+ if (rc < 0)
+ return rc;
+
+ if (!(rc & 0x40)) {
+ dev_info(&state->i2c->dev, "%s: CNR is not available yet.\n",
+ __func__);
+ return -EBUSY;
+ }
+ val = rc;
+
+ rc = mb86a20s_readreg(state, 0x46);
+ if (rc < 0)
+ return rc;
+ cnr_linear = rc << 8;
+
+ rc = mb86a20s_readreg(state, 0x46);
+ if (rc < 0)
+ return rc;
+ cnr_linear |= rc;
+
+ cnr = interpolate_value(cnr_linear,
+ cnr_to_db_table, ARRAY_SIZE(cnr_to_db_table));
+
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[0].svalue = cnr;
+
+ dev_dbg(&state->i2c->dev, "%s: CNR is %d.%03d dB (%d)\n",
+ __func__, cnr / 1000, cnr % 1000, cnr_linear);
+
+ /* CNR counter reset */
+ rc = mb86a20s_writereg(state, 0x45, val | 0x10);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x45, val & 0x6f);
+
+ return rc;
+}
+
+static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 mer, cnr;
+ int rc, val, i;
+ struct linear_segments *segs;
+ unsigned segs_len;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ /* Check if the measures are already available */
+ rc = mb86a20s_writereg(state, 0x50, 0x5b);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+
+ /* Check if data is available */
+ if (!(rc & 0x01)) {
+ dev_info(&state->i2c->dev,
+ "%s: MER measures aren't available yet.\n", __func__);
+ return -EBUSY;
+ }
+
+ /* Read all layers */
+ for (i = 0; i < 3; i++) {
+ if (!(c->isdbt_layer_enabled & (1 << i))) {
+ c->cnr.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ continue;
+ }
+
+ rc = mb86a20s_writereg(state, 0x50, 0x52 + i * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ mer = rc << 16;
+ rc = mb86a20s_writereg(state, 0x50, 0x53 + i * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ mer |= rc << 8;
+ rc = mb86a20s_writereg(state, 0x50, 0x54 + i * 3);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ mer |= rc;
+
+ switch (c->layer[i].modulation) {
+ case DQPSK:
+ case QPSK:
+ segs = cnr_qpsk_table;
+ segs_len = ARRAY_SIZE(cnr_qpsk_table);
+ break;
+ case QAM_16:
+ segs = cnr_16qam_table;
+ segs_len = ARRAY_SIZE(cnr_16qam_table);
+ break;
+ default:
+ case QAM_64:
+ segs = cnr_64qam_table;
+ segs_len = ARRAY_SIZE(cnr_64qam_table);
+ break;
}
- if (!(rc & 0x10)) {
- switch (rc & 0x3) {
- case 0:
- p->guard_interval = GUARD_INTERVAL_1_4;
- break;
- case 1:
- p->guard_interval = GUARD_INTERVAL_1_8;
- break;
- case 2:
- p->guard_interval = GUARD_INTERVAL_1_16;
- break;
+ cnr = interpolate_value(mer, segs, segs_len);
+
+ c->cnr.stat[1 + i].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[1 + i].svalue = cnr;
+
+ dev_dbg(&state->i2c->dev,
+ "%s: CNR for layer %c is %d.%03d dB (MER = %d).\n",
+ __func__, 'A' + i, cnr / 1000, cnr % 1000, mer);
+
+ }
+
+ /* Start a new MER measurement */
+ /* MER counter reset */
+ rc = mb86a20s_writereg(state, 0x50, 0x50);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_readreg(state, 0x51);
+ if (rc < 0)
+ return rc;
+ val = rc;
+
+ rc = mb86a20s_writereg(state, 0x51, val | 0x01);
+ if (rc < 0)
+ return rc;
+ rc = mb86a20s_writereg(state, 0x51, val & 0x06);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static void mb86a20s_stats_not_ready(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int i;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ /* Fill the length of each status counter */
+
+ /* Only global stats */
+ c->strength.len = 1;
+
+ /* Per-layer stats - 3 layers + global */
+ c->cnr.len = 4;
+ c->pre_bit_error.len = 4;
+ c->pre_bit_count.len = 4;
+ c->post_bit_error.len = 4;
+ c->post_bit_count.len = 4;
+ c->block_error.len = 4;
+ c->block_count.len = 4;
+
+ /* Signal is always available */
+ c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ c->strength.stat[0].uvalue = 0;
+
+ /* Put all of them at FE_SCALE_NOT_AVAILABLE */
+ for (i = 0; i < 4; i++) {
+ c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+}
+
+static int mb86a20s_get_stats(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc = 0, i;
+ u32 bit_error = 0, bit_count = 0;
+ u32 t_pre_bit_error = 0, t_pre_bit_count = 0;
+ u32 t_post_bit_error = 0, t_post_bit_count = 0;
+ u32 block_error = 0, block_count = 0;
+ u32 t_block_error = 0, t_block_count = 0;
+ int active_layers = 0, pre_ber_layers = 0, post_ber_layers = 0;
+ int per_layers = 0;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ mb86a20s_get_main_CNR(fe);
+
+ /* Get per-layer stats */
+ mb86a20s_get_blk_error_layer_CNR(fe);
+
+ for (i = 0; i < 3; i++) {
+ if (c->isdbt_layer_enabled & (1 << i)) {
+ /* Layer is active and has rc segments */
+ active_layers++;
+
+ /* Handle BER before vterbi */
+ rc = mb86a20s_get_pre_ber(fe, i,
+ &bit_error, &bit_count);
+ if (rc >= 0) {
+ c->pre_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[1 + i].uvalue += bit_error;
+ c->pre_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[1 + i].uvalue += bit_count;
+ } else if (rc != -EBUSY) {
+ /*
+ * If an I/O error happened,
+ * measures are now unavailable
+ */
+ c->pre_bit_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ dev_err(&state->i2c->dev,
+ "%s: Can't get BER for layer %c (error %d).\n",
+ __func__, 'A' + i, rc);
}
+ if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
+ pre_ber_layers++;
+
+ /* Handle BER post vterbi */
+ rc = mb86a20s_get_post_ber(fe, i,
+ &bit_error, &bit_count);
+ if (rc >= 0) {
+ c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[1 + i].uvalue += bit_error;
+ c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[1 + i].uvalue += bit_count;
+ } else if (rc != -EBUSY) {
+ /*
+ * If an I/O error happened,
+ * measures are now unavailable
+ */
+ c->post_bit_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ dev_err(&state->i2c->dev,
+ "%s: Can't get BER for layer %c (error %d).\n",
+ __func__, 'A' + i, rc);
+ }
+ if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
+ post_ber_layers++;
+
+ /* Handle Block errors for PER/UCB reports */
+ rc = mb86a20s_get_blk_error(fe, i,
+ &block_error,
+ &block_count);
+ if (rc >= 0) {
+ c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[1 + i].uvalue += block_error;
+ c->block_count.stat[1 + i].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[1 + i].uvalue += block_count;
+ } else if (rc != -EBUSY) {
+ /*
+ * If an I/O error happened,
+ * measures are now unavailable
+ */
+ c->block_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ dev_err(&state->i2c->dev,
+ "%s: Can't get PER for layer %c (error %d).\n",
+ __func__, 'A' + i, rc);
+
+ }
+ if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
+ per_layers++;
+
+ /* Update total preBER */
+ t_pre_bit_error += c->pre_bit_error.stat[1 + i].uvalue;
+ t_pre_bit_count += c->pre_bit_count.stat[1 + i].uvalue;
+
+ /* Update total postBER */
+ t_post_bit_error += c->post_bit_error.stat[1 + i].uvalue;
+ t_post_bit_count += c->post_bit_count.stat[1 + i].uvalue;
+
+ /* Update total PER */
+ t_block_error += c->block_error.stat[1 + i].uvalue;
+ t_block_count += c->block_count.stat[1 + i].uvalue;
}
}
+ /*
+ * Start showing global count if at least one error count is
+ * available.
+ */
+ if (pre_ber_layers) {
+ /*
+ * At least one per-layer BER measure was read. We can now
+ * calculate the total BER
+ *
+ * Total Bit Error/Count is calculated as the sum of the
+ * bit errors on all active layers.
+ */
+ c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[0].uvalue = t_pre_bit_error;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[0].uvalue = t_pre_bit_count;
+ } else {
+ c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ }
+
+ /*
+ * Start showing global count if at least one error count is
+ * available.
+ */
+ if (post_ber_layers) {
+ /*
+ * At least one per-layer BER measure was read. We can now
+ * calculate the total BER
+ *
+ * Total Bit Error/Count is calculated as the sum of the
+ * bit errors on all active layers.
+ */
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue = t_post_bit_error;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].uvalue = t_post_bit_count;
+ } else {
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ }
+
+ if (per_layers) {
+ /*
+ * At least one per-layer UCB measure was read. We can now
+ * calculate the total UCB
+ *
+ * Total block Error/Count is calculated as the sum of the
+ * block errors on all active layers.
+ */
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue = t_block_error;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].uvalue = t_block_count;
+ } else {
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ }
+
+ return rc;
+}
+
+/*
+ * The functions below are called via DVB callbacks, so they need to
+ * properly use the I2C gate control
+ */
+
+static int mb86a20s_initfe(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc;
+ u8 regD5 = 1;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ /* Initialize the frontend */
+ rc = mb86a20s_writeregdata(state, mb86a20s_init);
+ if (rc < 0)
+ goto err;
+
+ if (!state->config->is_serial) {
+ regD5 &= ~1;
+
+ rc = mb86a20s_writereg(state, 0x50, 0xd5);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x51, regD5);
+ if (rc < 0)
+ goto err;
+ }
+
+err:
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
+ if (rc < 0) {
+ state->need_init = true;
+ dev_info(&state->i2c->dev,
+ "mb86a20s: Init failed. Will try again later\n");
+ } else {
+ state->need_init = false;
+ dev_dbg(&state->i2c->dev, "Initialization succeeded.\n");
+ }
+ return rc;
+}
+
+static int mb86a20s_set_frontend(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc;
+#if 0
+ /*
+ * FIXME: Properly implement the set frontend properties
+ */
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+#endif
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ /*
+ * Gate should already be opened, but it doesn't hurt to
+ * double-check
+ */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ fe->ops.tuner_ops.set_params(fe);
+
+ /*
+ * Make it more reliable: if, for some reason, the initial
+ * device initialization doesn't happen, initialize it when
+ * a SBTVD parameters are adjusted.
+ *
+ * Unfortunately, due to a hard to track bug at tda829x/tda18271,
+ * the agc callback logic is not called during DVB attach time,
+ * causing mb86a20s to not be initialized with Kworld SBTVD.
+ * So, this hack is needed, in order to make Kworld SBTVD to work.
+ */
+ if (state->need_init)
+ mb86a20s_initfe(fe);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
+ mb86a20s_reset_counters(fe);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ return rc;
+}
+
+static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe,
+ fe_status_t *status)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc;
+
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ /* Get lock */
+ rc = mb86a20s_read_status(fe, status);
+ if (!(*status & FE_HAS_LOCK)) {
+ mb86a20s_stats_not_ready(fe);
+ mb86a20s_reset_frontend_cache(fe);
+ }
+ if (rc < 0) {
+ dev_err(&state->i2c->dev,
+ "%s: Can't read frontend lock status\n", __func__);
+ goto error;
+ }
+
+ /* Get signal strength */
+ rc = mb86a20s_read_signal_strength(fe);
+ if (rc < 0) {
+ dev_err(&state->i2c->dev,
+ "%s: Can't reset VBER registers.\n", __func__);
+ mb86a20s_stats_not_ready(fe);
+ mb86a20s_reset_frontend_cache(fe);
+
+ rc = 0; /* Status is OK */
+ goto error;
+ }
+ /* Fill signal strength */
+ c->strength.stat[0].uvalue = rc;
+
+ if (*status & FE_HAS_LOCK) {
+ /* Get TMCC info*/
+ rc = mb86a20s_get_frontend(fe);
+ if (rc < 0) {
+ dev_err(&state->i2c->dev,
+ "%s: Can't get FE TMCC data.\n", __func__);
+ rc = 0; /* Status is OK */
+ goto error;
+ }
+
+ /* Get statistics */
+ rc = mb86a20s_get_stats(fe);
+ if (rc < 0 && rc != -EBUSY) {
+ dev_err(&state->i2c->dev,
+ "%s: Can't get FE statistics.\n", __func__);
+ rc = 0;
+ goto error;
+ }
+ rc = 0; /* Don't return EBUSY to userspace */
+ }
+ goto ok;
+
+error:
+ mb86a20s_stats_not_ready(fe);
+
+ok:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ return rc;
+}
+
+static int mb86a20s_read_signal_strength_from_cache(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+
+ *strength = c->strength.stat[0].uvalue;
+
return 0;
}
+static int mb86a20s_get_frontend_dummy(struct dvb_frontend *fe)
+{
+ /*
+ * get_frontend is now handled together with other stats
+ * retrival, when read_status() is called, as some statistics
+ * will depend on the layers detection.
+ */
+ return 0;
+};
+
static int mb86a20s_tune(struct dvb_frontend *fe,
bool re_tune,
unsigned int mode_flags,
unsigned int *delay,
fe_status_t *status)
{
+ struct mb86a20s_state *state = fe->demodulator_priv;
int rc = 0;
- dprintk("\n");
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
if (re_tune)
rc = mb86a20s_set_frontend(fe);
if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
- mb86a20s_read_status(fe, status);
+ mb86a20s_read_status_and_stats(fe, status);
return rc;
}
@@ -619,7 +1936,7 @@ static void mb86a20s_release(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
- dprintk("\n");
+ dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
kfree(state);
}
@@ -629,15 +1946,16 @@ static struct dvb_frontend_ops mb86a20s_ops;
struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
struct i2c_adapter *i2c)
{
+ struct mb86a20s_state *state;
u8 rev;
- /* allocate memory for the internal state */
- struct mb86a20s_state *state =
- kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
+ dev_dbg(&i2c->dev, "%s called.\n", __func__);
- dprintk("\n");
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
if (state == NULL) {
- rc("Unable to kzalloc\n");
+ dev_err(&i2c->dev,
+ "%s: unable to allocate memory for state\n", __func__);
goto error;
}
@@ -654,9 +1972,11 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
rev = mb86a20s_readreg(state, 0);
if (rev == 0x13) {
- printk(KERN_INFO "Detected a Fujitsu mb86a20s frontend\n");
+ dev_info(&i2c->dev,
+ "Detected a Fujitsu mb86a20s frontend\n");
} else {
- printk(KERN_ERR "Frontend revision %d is unknown - aborting.\n",
+ dev_dbg(&i2c->dev,
+ "Frontend revision %d is unknown - aborting.\n",
rev);
goto error;
}
@@ -690,9 +2010,9 @@ static struct dvb_frontend_ops mb86a20s_ops = {
.init = mb86a20s_initfe,
.set_frontend = mb86a20s_set_frontend,
- .get_frontend = mb86a20s_get_frontend,
- .read_status = mb86a20s_read_status,
- .read_signal_strength = mb86a20s_read_signal_strength,
+ .get_frontend = mb86a20s_get_frontend_dummy,
+ .read_status = mb86a20s_read_status_and_stats,
+ .read_signal_strength = mb86a20s_read_signal_strength_from_cache,
.tune = mb86a20s_tune,
};
diff --git a/drivers/media/dvb-frontends/mt312.h b/drivers/media/dvb-frontends/mt312.h
index 29e3bb5496b8..5706621ad79d 100644
--- a/drivers/media/dvb-frontends/mt312.h
+++ b/drivers/media/dvb-frontends/mt312.h
@@ -36,7 +36,7 @@ struct mt312_config {
unsigned int voltage_inverted:1;
};
-#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_MT312)
struct dvb_frontend *mt312_attach(const struct mt312_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/mt352.h b/drivers/media/dvb-frontends/mt352.h
index ca2562d6f289..451d904e1500 100644
--- a/drivers/media/dvb-frontends/mt352.h
+++ b/drivers/media/dvb-frontends/mt352.h
@@ -51,7 +51,7 @@ struct mt352_config
int (*demod_init)(struct dvb_frontend* fe);
};
-#if defined(CONFIG_DVB_MT352) || (defined(CONFIG_DVB_MT352_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_MT352)
extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/nxt200x.h b/drivers/media/dvb-frontends/nxt200x.h
index f3c84583770f..b518d545609e 100644
--- a/drivers/media/dvb-frontends/nxt200x.h
+++ b/drivers/media/dvb-frontends/nxt200x.h
@@ -42,7 +42,7 @@ struct nxt200x_config
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
-#if defined(CONFIG_DVB_NXT200X) || (defined(CONFIG_DVB_NXT200X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_NXT200X)
extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/nxt6000.h b/drivers/media/dvb-frontends/nxt6000.h
index 878eb38a075e..b5867c2ae681 100644
--- a/drivers/media/dvb-frontends/nxt6000.h
+++ b/drivers/media/dvb-frontends/nxt6000.h
@@ -33,7 +33,7 @@ struct nxt6000_config
u8 clock_inversion:1;
};
-#if defined(CONFIG_DVB_NXT6000) || (defined(CONFIG_DVB_NXT6000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_NXT6000)
extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/or51132.h b/drivers/media/dvb-frontends/or51132.h
index 1b8e04d973c8..938958386cb1 100644
--- a/drivers/media/dvb-frontends/or51132.h
+++ b/drivers/media/dvb-frontends/or51132.h
@@ -34,7 +34,7 @@ struct or51132_config
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
-#if defined(CONFIG_DVB_OR51132) || (defined(CONFIG_DVB_OR51132_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_OR51132)
extern struct dvb_frontend* or51132_attach(const struct or51132_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c
index c625b57b4333..10cfc0579168 100644
--- a/drivers/media/dvb-frontends/or51211.c
+++ b/drivers/media/dvb-frontends/or51211.c
@@ -22,6 +22,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
/*
* This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
@@ -44,9 +46,7 @@
static int debug;
#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG "or51211: " args); \
- } while (0)
+ do { if (debug) pr_debug(args); } while (0)
static u8 run_buf[] = {0x7f,0x01};
static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
@@ -80,8 +80,7 @@ static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf,
msg.buf = (u8 *)buf;
if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
- printk(KERN_WARNING "or51211: i2c_writebytes error "
- "(addr %02x, err == %i)\n", reg, err);
+ pr_warn("error (addr %02x, err == %i)\n", reg, err);
return -EREMOTEIO;
}
@@ -98,8 +97,7 @@ static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len)
msg.buf = buf;
if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
- printk(KERN_WARNING "or51211: i2c_readbytes error "
- "(addr %02x, err == %i)\n", reg, err);
+ pr_warn("error (addr %02x, err == %i)\n", reg, err);
return -EREMOTEIO;
}
@@ -118,11 +116,11 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
/* Get eprom data */
tudata[0] = 17;
if (i2c_writebytes(state,0x50,tudata,1)) {
- printk(KERN_WARNING "or51211:load_firmware error eprom addr\n");
+ pr_warn("error eprom addr\n");
return -1;
}
if (i2c_readbytes(state,0x50,&tudata[145],192)) {
- printk(KERN_WARNING "or51211: load_firmware error eprom\n");
+ pr_warn("error eprom\n");
return -1;
}
@@ -136,32 +134,32 @@ static int or51211_load_firmware (struct dvb_frontend* fe,
state->config->reset(fe);
if (i2c_writebytes(state,state->config->demod_address,tudata,585)) {
- printk(KERN_WARNING "or51211: load_firmware error 1\n");
+ pr_warn("error 1\n");
return -1;
}
msleep(1);
if (i2c_writebytes(state,state->config->demod_address,
&fw->data[393],8125)) {
- printk(KERN_WARNING "or51211: load_firmware error 2\n");
+ pr_warn("error 2\n");
return -1;
}
msleep(1);
if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
- printk(KERN_WARNING "or51211: load_firmware error 3\n");
+ pr_warn("error 3\n");
return -1;
}
/* Wait at least 5 msec */
msleep(10);
if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
- printk(KERN_WARNING "or51211: load_firmware error 4\n");
+ pr_warn("error 4\n");
return -1;
}
msleep(10);
- printk("or51211: Done.\n");
+ pr_info("Done.\n");
return 0;
};
@@ -173,14 +171,14 @@ static int or51211_setmode(struct dvb_frontend* fe, int mode)
state->config->setmode(fe, mode);
if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
- printk(KERN_WARNING "or51211: setmode error 1\n");
+ pr_warn("error 1\n");
return -1;
}
/* Wait at least 5 msec */
msleep(10);
if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) {
- printk(KERN_WARNING "or51211: setmode error 2\n");
+ pr_warn("error 2\n");
return -1;
}
@@ -196,7 +194,7 @@ static int or51211_setmode(struct dvb_frontend* fe, int mode)
* normal +/-150kHz Carrier acquisition range
*/
if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) {
- printk(KERN_WARNING "or51211: setmode error 3\n");
+ pr_warn("error 3\n");
return -1;
}
@@ -206,14 +204,14 @@ static int or51211_setmode(struct dvb_frontend* fe, int mode)
rec_buf[3] = 0x00;
msleep(20);
if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) {
- printk(KERN_WARNING "or51211: setmode error 5\n");
+ pr_warn("error 5\n");
}
msleep(3);
if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) {
- printk(KERN_WARNING "or51211: setmode error 6");
+ pr_warn("error 6\n");
return -1;
}
- dprintk("setmode rec status %02x %02x\n",rec_buf[10],rec_buf[11]);
+ dprintk("rec status %02x %02x\n", rec_buf[10], rec_buf[11]);
return 0;
}
@@ -248,15 +246,15 @@ static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status)
/* Receiver Status */
if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
- printk(KERN_WARNING "or51132: read_status write error\n");
+ pr_warn("write error\n");
return -1;
}
msleep(3);
if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
- printk(KERN_WARNING "or51132: read_status read error\n");
+ pr_warn("read error\n");
return -1;
}
- dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]);
+ dprintk("%x %x\n", rec_buf[0], rec_buf[1]);
if (rec_buf[0] & 0x01) { /* Receiver Lock */
*status |= FE_HAS_SIGNAL;
@@ -306,20 +304,18 @@ static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
snd_buf[2] = 0x04;
if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
- printk(KERN_WARNING "%s: error writing snr reg\n",
- __func__);
+ pr_warn("error writing snr reg\n");
return -1;
}
if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
- printk(KERN_WARNING "%s: read_status read error\n",
- __func__);
+ pr_warn("read_status read error\n");
return -1;
}
state->snr = calculate_snr(rec_buf[0], 89599047);
*snr = (state->snr) >> 16;
- dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __func__, rec_buf[0],
+ dprintk("noise = 0x%02x, snr = %d.%02d dB\n", rec_buf[0],
state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
return 0;
@@ -375,25 +371,24 @@ static int or51211_init(struct dvb_frontend* fe)
if (!state->initialized) {
/* Request the firmware, this will block until it uploads */
- printk(KERN_INFO "or51211: Waiting for firmware upload "
- "(%s)...\n", OR51211_DEFAULT_FIRMWARE);
+ pr_info("Waiting for firmware upload (%s)...\n",
+ OR51211_DEFAULT_FIRMWARE);
ret = config->request_firmware(fe, &fw,
OR51211_DEFAULT_FIRMWARE);
- printk(KERN_INFO "or51211:Got Hotplug firmware\n");
+ pr_info("Got Hotplug firmware\n");
if (ret) {
- printk(KERN_WARNING "or51211: No firmware uploaded "
- "(timeout or file not found?)\n");
+ pr_warn("No firmware uploaded "
+ "(timeout or file not found?)\n");
return ret;
}
ret = or51211_load_firmware(fe, fw);
release_firmware(fw);
if (ret) {
- printk(KERN_WARNING "or51211: Writing firmware to "
- "device failed!\n");
+ pr_warn("Writing firmware to device failed!\n");
return ret;
}
- printk(KERN_INFO "or51211: Firmware upload complete.\n");
+ pr_info("Firmware upload complete.\n");
/* Set operation mode in Receiver 1 register;
* type 1:
@@ -406,7 +401,7 @@ static int or51211_init(struct dvb_frontend* fe)
*/
if (i2c_writebytes(state,state->config->demod_address,
cmd_buf,3)) {
- printk(KERN_WARNING "or51211: Load DVR Error 5\n");
+ pr_warn("Load DVR Error 5\n");
return -1;
}
@@ -419,13 +414,13 @@ static int or51211_init(struct dvb_frontend* fe)
msleep(30);
if (i2c_writebytes(state,state->config->demod_address,
rec_buf,3)) {
- printk(KERN_WARNING "or51211: Load DVR Error A\n");
+ pr_warn("Load DVR Error A\n");
return -1;
}
msleep(3);
if (i2c_readbytes(state,state->config->demod_address,
&rec_buf[10],2)) {
- printk(KERN_WARNING "or51211: Load DVR Error B\n");
+ pr_warn("Load DVR Error B\n");
return -1;
}
@@ -436,13 +431,13 @@ static int or51211_init(struct dvb_frontend* fe)
msleep(20);
if (i2c_writebytes(state,state->config->demod_address,
rec_buf,3)) {
- printk(KERN_WARNING "or51211: Load DVR Error C\n");
+ pr_warn("Load DVR Error C\n");
return -1;
}
msleep(3);
if (i2c_readbytes(state,state->config->demod_address,
&rec_buf[12],2)) {
- printk(KERN_WARNING "or51211: Load DVR Error D\n");
+ pr_warn("Load DVR Error D\n");
return -1;
}
@@ -454,16 +449,14 @@ static int or51211_init(struct dvb_frontend* fe)
get_ver_buf[4] = i+1;
if (i2c_writebytes(state,state->config->demod_address,
get_ver_buf,5)) {
- printk(KERN_WARNING "or51211:Load DVR Error 6"
- " - %d\n",i);
+ pr_warn("Load DVR Error 6 - %d\n", i);
return -1;
}
msleep(3);
if (i2c_readbytes(state,state->config->demod_address,
&rec_buf[i*2],2)) {
- printk(KERN_WARNING "or51211:Load DVR Error 7"
- " - %d\n",i);
+ pr_warn("Load DVR Error 7 - %d\n", i);
return -1;
}
/* If we didn't receive the right index, try again */
@@ -471,15 +464,11 @@ static int or51211_init(struct dvb_frontend* fe)
i--;
}
}
- dprintk("read_fwbits %x %x %x %x %x %x %x %x %x %x\n",
- rec_buf[0], rec_buf[1], rec_buf[2], rec_buf[3],
- rec_buf[4], rec_buf[5], rec_buf[6], rec_buf[7],
- rec_buf[8], rec_buf[9]);
+ dprintk("read_fwbits %10ph\n", rec_buf);
- printk(KERN_INFO "or51211: ver TU%02x%02x%02x VSB mode %02x"
- " Status %02x\n",
- rec_buf[2], rec_buf[4],rec_buf[6],
- rec_buf[12],rec_buf[10]);
+ pr_info("ver TU%02x%02x%02x VSB mode %02x Status %02x\n",
+ rec_buf[2], rec_buf[4], rec_buf[6], rec_buf[12],
+ rec_buf[10]);
rec_buf[0] = 0x04;
rec_buf[1] = 0x00;
@@ -488,13 +477,13 @@ static int or51211_init(struct dvb_frontend* fe)
msleep(20);
if (i2c_writebytes(state,state->config->demod_address,
rec_buf,3)) {
- printk(KERN_WARNING "or51211: Load DVR Error 8\n");
+ pr_warn("Load DVR Error 8\n");
return -1;
}
msleep(20);
if (i2c_readbytes(state,state->config->demod_address,
&rec_buf[8],2)) {
- printk(KERN_WARNING "or51211: Load DVR Error 9\n");
+ pr_warn("Load DVR Error 9\n");
return -1;
}
state->initialized = 1;
diff --git a/drivers/media/dvb-frontends/or51211.h b/drivers/media/dvb-frontends/or51211.h
index 3ce0508b898e..9a8ae936b62d 100644
--- a/drivers/media/dvb-frontends/or51211.h
+++ b/drivers/media/dvb-frontends/or51211.h
@@ -37,7 +37,7 @@ struct or51211_config
void (*sleep)(struct dvb_frontend * fe);
};
-#if defined(CONFIG_DVB_OR51211) || (defined(CONFIG_DVB_OR51211_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_OR51211)
extern struct dvb_frontend* or51211_attach(const struct or51211_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/s5h1420.h b/drivers/media/dvb-frontends/s5h1420.h
index ff308136d865..210049b5cf30 100644
--- a/drivers/media/dvb-frontends/s5h1420.h
+++ b/drivers/media/dvb-frontends/s5h1420.h
@@ -40,7 +40,7 @@ struct s5h1420_config
u8 serial_mpeg:1;
};
-#if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_S5H1420)
extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
struct i2c_adapter *i2c);
extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb-frontends/sp8870.h b/drivers/media/dvb-frontends/sp8870.h
index a764a793c7d8..065ec67d4e30 100644
--- a/drivers/media/dvb-frontends/sp8870.h
+++ b/drivers/media/dvb-frontends/sp8870.h
@@ -35,7 +35,7 @@ struct sp8870_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
-#if defined(CONFIG_DVB_SP8870) || (defined(CONFIG_DVB_SP8870_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_SP8870)
extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/sp887x.h b/drivers/media/dvb-frontends/sp887x.h
index 04eff6e0eef3..2cdc4e8bc9cd 100644
--- a/drivers/media/dvb-frontends/sp887x.h
+++ b/drivers/media/dvb-frontends/sp887x.h
@@ -17,7 +17,7 @@ struct sp887x_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
-#if defined(CONFIG_DVB_SP887X) || (defined(CONFIG_DVB_SP887X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_SP887X)
extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/stb0899_drv.h b/drivers/media/dvb-frontends/stb0899_drv.h
index 98b200ce0c34..8d26ff6eb1db 100644
--- a/drivers/media/dvb-frontends/stb0899_drv.h
+++ b/drivers/media/dvb-frontends/stb0899_drv.h
@@ -142,7 +142,7 @@ struct stb0899_config {
int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain);
};
-#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STB0899)
extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/stb6100.h b/drivers/media/dvb-frontends/stb6100.h
index 2ab096614b3f..3a1e40f3b8be 100644
--- a/drivers/media/dvb-frontends/stb6100.h
+++ b/drivers/media/dvb-frontends/stb6100.h
@@ -94,7 +94,7 @@ struct stb6100_state {
u32 reference;
};
-#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STB6100)
extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
const struct stb6100_config *config,
diff --git a/drivers/media/dvb-frontends/stv0297.h b/drivers/media/dvb-frontends/stv0297.h
index 3f8f9468f387..c8ff3639ce00 100644
--- a/drivers/media/dvb-frontends/stv0297.h
+++ b/drivers/media/dvb-frontends/stv0297.h
@@ -42,7 +42,7 @@ struct stv0297_config
u8 stop_during_read:1;
};
-#if defined(CONFIG_DVB_STV0297) || (defined(CONFIG_DVB_STV0297_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV0297)
extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c
index 92a6075cd82f..b57ecf42e75a 100644
--- a/drivers/media/dvb-frontends/stv0299.c
+++ b/drivers/media/dvb-frontends/stv0299.c
@@ -420,7 +420,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long
do_gettimeofday (&nexttime);
if (debug_legacy_dish_switch)
- memcpy (&tv[0], &nexttime, sizeof (struct timeval));
+ tv[0] = nexttime;
stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
dvb_frontend_sleep_until(&nexttime, 32000);
diff --git a/drivers/media/dvb-frontends/stv0299.h b/drivers/media/dvb-frontends/stv0299.h
index ba219b767a69..06f70fc8327b 100644
--- a/drivers/media/dvb-frontends/stv0299.h
+++ b/drivers/media/dvb-frontends/stv0299.h
@@ -95,7 +95,7 @@ struct stv0299_config
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
};
-#if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV0299)
extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c
index b551ca350e00..e5a87b57d855 100644
--- a/drivers/media/dvb-frontends/stv0900_core.c
+++ b/drivers/media/dvb-frontends/stv0900_core.c
@@ -524,11 +524,8 @@ void stv0900_set_tuner(struct dvb_frontend *fe, u32 frequency,
struct dvb_frontend_ops *frontend_ops = NULL;
struct dvb_tuner_ops *tuner_ops = NULL;
- if (&fe->ops)
- frontend_ops = &fe->ops;
-
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+ frontend_ops = &fe->ops;
+ tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->set_frequency) {
if ((tuner_ops->set_frequency(fe, frequency)) < 0)
@@ -552,11 +549,8 @@ void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
struct dvb_frontend_ops *frontend_ops = NULL;
struct dvb_tuner_ops *tuner_ops = NULL;
- if (&fe->ops)
- frontend_ops = &fe->ops;
-
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+ frontend_ops = &fe->ops;
+ tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->set_bandwidth) {
if ((tuner_ops->set_bandwidth(fe, bandwidth)) < 0)
@@ -1558,6 +1552,27 @@ static int stv0900_status(struct stv0900_internal *intp,
return locked;
}
+static int stv0900_set_mis(struct stv0900_internal *intp,
+ enum fe_stv0900_demod_num demod, int mis)
+{
+ enum fe_stv0900_error error = STV0900_NO_ERROR;
+
+ dprintk("%s\n", __func__);
+
+ if (mis < 0 || mis > 255) {
+ dprintk("Disable MIS filtering\n");
+ stv0900_write_bits(intp, FILTER_EN, 0);
+ } else {
+ dprintk("Enable MIS filtering - %d\n", mis);
+ stv0900_write_bits(intp, FILTER_EN, 1);
+ stv0900_write_reg(intp, ISIENTRY, mis);
+ stv0900_write_reg(intp, ISIBITENA, 0xff);
+ }
+
+ return error;
+}
+
+
static enum dvbfe_search stv0900_search(struct dvb_frontend *fe)
{
struct stv0900_state *state = fe->demodulator_priv;
@@ -1578,6 +1593,8 @@ static enum dvbfe_search stv0900_search(struct dvb_frontend *fe)
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
+ stv0900_set_mis(intp, demod, c->stream_id);
+
p_result.locked = FALSE;
p_search.path = demod;
p_search.frequency = c->frequency;
@@ -1935,6 +1952,9 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
if (err_stv0900)
goto error;
+ if (state->internal->chip_id >= 0x30)
+ state->frontend.ops.info.caps |= FE_CAN_MULTISTREAM;
+
break;
default:
goto error;
diff --git a/drivers/media/dvb-frontends/stv0900_reg.h b/drivers/media/dvb-frontends/stv0900_reg.h
index 731afe93a823..511ed2a2d987 100644
--- a/drivers/media/dvb-frontends/stv0900_reg.h
+++ b/drivers/media/dvb-frontends/stv0900_reg.h
@@ -3446,8 +3446,11 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
#define R0900_P1_PDELCTRL1 0xf550
#define PDELCTRL1 REGx(R0900_P1_PDELCTRL1)
#define F0900_P1_INV_MISMASK 0xf5500080
+#define INV_MISMASK FLDx(F0900_P1_INV_MISMASK)
#define F0900_P1_FILTER_EN 0xf5500020
+#define FILTER_EN FLDx(F0900_P1_FILTER_EN)
#define F0900_P1_EN_MIS00 0xf5500002
+#define EN_MIS00 FLDx(F0900_P1_EN_MIS00)
#define F0900_P1_ALGOSWRST 0xf5500001
#define ALGOSWRST FLDx(F0900_P1_ALGOSWRST)
diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c
index 4af20780fb9c..0a40edfad739 100644
--- a/drivers/media/dvb-frontends/stv0900_sw.c
+++ b/drivers/media/dvb-frontends/stv0900_sw.c
@@ -1167,11 +1167,8 @@ static u32 stv0900_get_tuner_freq(struct dvb_frontend *fe)
struct dvb_tuner_ops *tuner_ops = NULL;
u32 freq = 0;
- if (&fe->ops)
- frontend_ops = &fe->ops;
-
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+ frontend_ops = &fe->ops;
+ tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_frequency) {
if ((tuner_ops->get_frequency(fe, &freq)) < 0)
diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
index 13caec013902..f36eeefb76a6 100644
--- a/drivers/media/dvb-frontends/stv090x.c
+++ b/drivers/media/dvb-frontends/stv090x.c
@@ -4267,7 +4267,7 @@ err:
return -1;
}
-static int stv090x_set_tspath(struct stv090x_state *state)
+static int stv0900_set_tspath(struct stv090x_state *state)
{
u32 reg;
@@ -4538,6 +4538,121 @@ err:
return -1;
}
+static int stv0903_set_tspath(struct stv090x_state *state)
+{
+ u32 reg;
+
+ if (state->internal->dev_ver >= 0x20) {
+ switch (state->config->ts1_mode) {
+ case STV090x_TSMODE_PARALLEL_PUNCTURED:
+ case STV090x_TSMODE_DVBCI:
+ stv090x_write_reg(state, STV090x_TSGENERAL, 0x00);
+ break;
+
+ case STV090x_TSMODE_SERIAL_PUNCTURED:
+ case STV090x_TSMODE_SERIAL_CONTINUOUS:
+ default:
+ stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c);
+ break;
+ }
+ } else {
+ switch (state->config->ts1_mode) {
+ case STV090x_TSMODE_PARALLEL_PUNCTURED:
+ case STV090x_TSMODE_DVBCI:
+ stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x10);
+ break;
+
+ case STV090x_TSMODE_SERIAL_PUNCTURED:
+ case STV090x_TSMODE_SERIAL_CONTINUOUS:
+ default:
+ stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x14);
+ break;
+ }
+ }
+
+ switch (state->config->ts1_mode) {
+ case STV090x_TSMODE_PARALLEL_PUNCTURED:
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+ STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+ STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+ break;
+
+ case STV090x_TSMODE_DVBCI:
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+ STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+ STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+ break;
+
+ case STV090x_TSMODE_SERIAL_PUNCTURED:
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+ STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+ STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+ break;
+
+ case STV090x_TSMODE_SERIAL_CONTINUOUS:
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+ STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+ STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+ break;
+
+ default:
+ break;
+ }
+
+ if (state->config->ts1_clk > 0) {
+ u32 speed;
+
+ switch (state->config->ts1_mode) {
+ case STV090x_TSMODE_PARALLEL_PUNCTURED:
+ case STV090x_TSMODE_DVBCI:
+ default:
+ speed = state->internal->mclk /
+ (state->config->ts1_clk / 4);
+ if (speed < 0x08)
+ speed = 0x08;
+ if (speed > 0xFF)
+ speed = 0xFF;
+ break;
+ case STV090x_TSMODE_SERIAL_PUNCTURED:
+ case STV090x_TSMODE_SERIAL_CONTINUOUS:
+ speed = state->internal->mclk /
+ (state->config->ts1_clk / 32);
+ if (speed < 0x20)
+ speed = 0x20;
+ if (speed > 0xFF)
+ speed = 0xFF;
+ break;
+ }
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+ STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+ goto err;
+ if (stv090x_write_reg(state, STV090x_P1_TSSPEED, speed) < 0)
+ goto err;
+ }
+
+ reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+ STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+ STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
+ if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(FE_ERROR, 1, "I/O error");
+ return -1;
+}
+
static int stv090x_init(struct dvb_frontend *fe)
{
struct stv090x_state *state = fe->demodulator_priv;
@@ -4600,8 +4715,13 @@ static int stv090x_init(struct dvb_frontend *fe)
if (stv090x_i2c_gate_ctrl(state, 0) < 0)
goto err;
- if (stv090x_set_tspath(state) < 0)
- goto err;
+ if (state->device == STV0900) {
+ if (stv0900_set_tspath(state) < 0)
+ goto err;
+ } else {
+ if (stv0903_set_tspath(state) < 0)
+ goto err;
+ }
return 0;
@@ -4642,23 +4762,26 @@ static int stv090x_setup(struct dvb_frontend *fe)
/* Stop Demod */
if (stv090x_write_reg(state, STV090x_P1_DMDISTATE, 0x5c) < 0)
goto err;
- if (stv090x_write_reg(state, STV090x_P2_DMDISTATE, 0x5c) < 0)
- goto err;
+ if (state->device == STV0900)
+ if (stv090x_write_reg(state, STV090x_P2_DMDISTATE, 0x5c) < 0)
+ goto err;
msleep(5);
/* Set No Tuner Mode */
if (stv090x_write_reg(state, STV090x_P1_TNRCFG, 0x6c) < 0)
goto err;
- if (stv090x_write_reg(state, STV090x_P2_TNRCFG, 0x6c) < 0)
- goto err;
+ if (state->device == STV0900)
+ if (stv090x_write_reg(state, STV090x_P2_TNRCFG, 0x6c) < 0)
+ goto err;
/* I2C repeater OFF */
STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level);
if (stv090x_write_reg(state, STV090x_P1_I2CRPT, reg) < 0)
goto err;
- if (stv090x_write_reg(state, STV090x_P2_I2CRPT, reg) < 0)
- goto err;
+ if (state->device == STV0900)
+ if (stv090x_write_reg(state, STV090x_P2_I2CRPT, reg) < 0)
+ goto err;
if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */
goto err;
diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h
index 29cdc2b71314..0bd6adcfee8a 100644
--- a/drivers/media/dvb-frontends/stv090x.h
+++ b/drivers/media/dvb-frontends/stv090x.h
@@ -103,7 +103,7 @@ struct stv090x_config {
void (*tuner_i2c_lock) (struct dvb_frontend *fe, int lock);
};
-#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV090x)
extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
struct i2c_adapter *i2c,
diff --git a/drivers/media/dvb-frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h
index 47516753929a..bc4766db29c5 100644
--- a/drivers/media/dvb-frontends/stv6110x.h
+++ b/drivers/media/dvb-frontends/stv6110x.h
@@ -53,7 +53,7 @@ struct stv6110x_devctl {
};
-#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV6110x)
extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
diff --git a/drivers/media/dvb-frontends/tda1002x.h b/drivers/media/dvb-frontends/tda1002x.h
index 04d19418bf20..e404b6e44802 100644
--- a/drivers/media/dvb-frontends/tda1002x.h
+++ b/drivers/media/dvb-frontends/tda1002x.h
@@ -57,7 +57,7 @@ struct tda10023_config {
u16 deltaf;
};
-#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA10021)
extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
struct i2c_adapter* i2c, u8 pwm);
#else
@@ -69,8 +69,7 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config*
}
#endif // CONFIG_DVB_TDA10021
-#if defined(CONFIG_DVB_TDA10023) || \
- (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA10023)
extern struct dvb_frontend *tda10023_attach(
const struct tda10023_config *config,
struct i2c_adapter *i2c, u8 pwm);
diff --git a/drivers/media/dvb-frontends/tda1004x.h b/drivers/media/dvb-frontends/tda1004x.h
index 4e27ffb0f14e..dd283fbb61c0 100644
--- a/drivers/media/dvb-frontends/tda1004x.h
+++ b/drivers/media/dvb-frontends/tda1004x.h
@@ -117,7 +117,7 @@ struct tda1004x_state {
enum tda1004x_demod demod_type;
};
-#if defined(CONFIG_DVB_TDA1004X) || (defined(CONFIG_DVB_TDA1004X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA1004X)
extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
struct i2c_adapter* i2c);
diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c
index 16a4bc54dbe7..2521f7e23018 100644
--- a/drivers/media/dvb-frontends/tda10071.c
+++ b/drivers/media/dvb-frontends/tda10071.c
@@ -30,7 +30,7 @@ static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
u8 buf[len+1];
struct i2c_msg msg[1] = {
{
- .addr = priv->cfg.i2c_address,
+ .addr = priv->cfg.demod_i2c_addr,
.flags = 0,
.len = sizeof(buf),
.buf = buf,
@@ -59,12 +59,12 @@ static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
u8 buf[len];
struct i2c_msg msg[2] = {
{
- .addr = priv->cfg.i2c_address,
+ .addr = priv->cfg.demod_i2c_addr,
.flags = 0,
.len = 1,
.buf = &reg,
}, {
- .addr = priv->cfg.i2c_address,
+ .addr = priv->cfg.demod_i2c_addr,
.flags = I2C_M_RD,
.len = sizeof(buf),
.buf = buf,
@@ -1064,7 +1064,7 @@ static int tda10071_init(struct dvb_frontend *fe)
cmd.args[2] = 0x00;
cmd.args[3] = 0x00;
cmd.args[4] = 0x00;
- cmd.args[5] = 0x14;
+ cmd.args[5] = (priv->cfg.tuner_i2c_addr) ? priv->cfg.tuner_i2c_addr : 0x14;
cmd.args[6] = 0x00;
cmd.args[7] = 0x03;
cmd.args[8] = 0x02;
@@ -1202,6 +1202,20 @@ struct dvb_frontend *tda10071_attach(const struct tda10071_config *config,
goto error;
}
+ /* make sure demod i2c address is specified */
+ if (!config->demod_i2c_addr) {
+ dev_dbg(&i2c->dev, "%s: invalid demod i2c address!\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* make sure tuner i2c address is specified */
+ if (!config->tuner_i2c_addr) {
+ dev_dbg(&i2c->dev, "%s: invalid tuner i2c address!\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+
/* setup the priv */
priv->i2c = i2c;
memcpy(&priv->cfg, config, sizeof(struct tda10071_config));
diff --git a/drivers/media/dvb-frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h
index 21163c4b555c..bff1c38df802 100644
--- a/drivers/media/dvb-frontends/tda10071.h
+++ b/drivers/media/dvb-frontends/tda10071.h
@@ -28,7 +28,13 @@ struct tda10071_config {
* Default: none, must set
* Values: 0x55,
*/
- u8 i2c_address;
+ u8 demod_i2c_addr;
+
+ /* Tuner I2C address.
+ * Default: none, must set
+ * Values: 0x14, 0x54, ...
+ */
+ u8 tuner_i2c_addr;
/* Max bytes I2C provider can write at once.
* Note: Buffer is taken from the stack currently!
diff --git a/drivers/media/dvb-frontends/tda10086.h b/drivers/media/dvb-frontends/tda10086.h
index 61148c558d8d..458fe91c1b88 100644
--- a/drivers/media/dvb-frontends/tda10086.h
+++ b/drivers/media/dvb-frontends/tda10086.h
@@ -46,7 +46,7 @@ struct tda10086_config
enum tda10086_xtal xtal_freq;
};
-#if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA10086)
extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/tda665x.h b/drivers/media/dvb-frontends/tda665x.h
index ec7927aa75ae..03a0da6d5cf2 100644
--- a/drivers/media/dvb-frontends/tda665x.h
+++ b/drivers/media/dvb-frontends/tda665x.h
@@ -31,7 +31,7 @@ struct tda665x_config {
u32 ref_divider;
};
-#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA665x)
extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
const struct tda665x_config *config,
diff --git a/drivers/media/dvb-frontends/tda8083.h b/drivers/media/dvb-frontends/tda8083.h
index 5a03c14a10e8..de6b1860dfdd 100644
--- a/drivers/media/dvb-frontends/tda8083.h
+++ b/drivers/media/dvb-frontends/tda8083.h
@@ -35,7 +35,7 @@ struct tda8083_config
u8 demod_address;
};
-#if defined(CONFIG_DVB_TDA8083) || (defined(CONFIG_DVB_TDA8083_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA8083)
extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/tda8261.h b/drivers/media/dvb-frontends/tda8261.h
index 006e45351b94..55cf4ffcbfdf 100644
--- a/drivers/media/dvb-frontends/tda8261.h
+++ b/drivers/media/dvb-frontends/tda8261.h
@@ -34,7 +34,7 @@ struct tda8261_config {
enum tda8261_step step_size;
};
-#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA8261)
extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
const struct tda8261_config *config,
diff --git a/drivers/media/dvb-frontends/tda8261_cfg.h b/drivers/media/dvb-frontends/tda8261_cfg.h
index 1af1ee49b542..46710744173b 100644
--- a/drivers/media/dvb-frontends/tda8261_cfg.h
+++ b/drivers/media/dvb-frontends/tda8261_cfg.h
@@ -78,7 +78,7 @@ static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
return err;
}
*bandwidth = t_state.bandwidth;
+ printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
}
- printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
return 0;
}
diff --git a/drivers/media/dvb-frontends/tda826x.h b/drivers/media/dvb-frontends/tda826x.h
index 89e97926ab23..5f0f20e7e4f8 100644
--- a/drivers/media/dvb-frontends/tda826x.h
+++ b/drivers/media/dvb-frontends/tda826x.h
@@ -35,7 +35,7 @@
* @param has_loopthrough Set to 1 if the card has a loopthrough RF connector.
* @return FE pointer on success, NULL on failure.
*/
-#if defined(CONFIG_DVB_TDA826X) || (defined(CONFIG_DVB_TDA826X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA826X)
extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr,
struct i2c_adapter *i2c,
int has_loopthrough);
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
new file mode 100644
index 000000000000..ad7ad857ab2a
--- /dev/null
+++ b/drivers/media/dvb-frontends/ts2020.c
@@ -0,0 +1,373 @@
+/*
+ Montage Technology TS2020 - Silicon Tuner driver
+ Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+ Copyright (C) 2009-2012 TurboSight.com
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dvb_frontend.h"
+#include "ts2020.h"
+
+#define TS2020_XTAL_FREQ 27000 /* in kHz */
+#define FREQ_OFFSET_LOW_SYM_RATE 3000
+
+struct ts2020_priv {
+ /* i2c details */
+ int i2c_address;
+ struct i2c_adapter *i2c;
+ u8 clk_out_div;
+ u32 frequency;
+};
+
+static int ts2020_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int ts2020_writereg(struct dvb_frontend *fe, int reg, int data)
+{
+ struct ts2020_priv *priv = fe->tuner_priv;
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg[] = {
+ {
+ .addr = priv->i2c_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ }
+ };
+ int err;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ err = i2c_transfer(priv->i2c, msg, 1);
+ if (err != 1) {
+ printk(KERN_ERR
+ "%s: writereg error(err == %i, reg == 0x%02x, value == 0x%02x)\n",
+ __func__, err, reg, data);
+ return -EREMOTEIO;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return 0;
+}
+
+static int ts2020_readreg(struct dvb_frontend *fe, u8 reg)
+{
+ struct ts2020_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+ struct i2c_msg msg[] = {
+ {
+ .addr = priv->i2c_address,
+ .flags = 0,
+ .buf = b0,
+ .len = 1
+ }, {
+ .addr = priv->i2c_address,
+ .flags = I2C_M_RD,
+ .buf = b1,
+ .len = 1
+ }
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+
+ if (ret != 2) {
+ printk(KERN_ERR "%s: reg=0x%x(error=%d)\n",
+ __func__, reg, ret);
+ return ret;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return b1[0];
+}
+
+static int ts2020_sleep(struct dvb_frontend *fe)
+{
+ struct ts2020_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 buf[] = { 10, 0 };
+ struct i2c_msg msg = {
+ .addr = priv->i2c_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = i2c_transfer(priv->i2c, &msg, 1);
+ if (ret != 1)
+ printk(KERN_ERR "%s: i2c error\n", __func__);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return (ret == 1) ? 0 : ret;
+}
+
+static int ts2020_init(struct dvb_frontend *fe)
+{
+ struct ts2020_priv *priv = fe->tuner_priv;
+
+ ts2020_writereg(fe, 0x42, 0x73);
+ ts2020_writereg(fe, 0x05, priv->clk_out_div);
+ ts2020_writereg(fe, 0x20, 0x27);
+ ts2020_writereg(fe, 0x07, 0x02);
+ ts2020_writereg(fe, 0x11, 0xff);
+ ts2020_writereg(fe, 0x60, 0xf9);
+ ts2020_writereg(fe, 0x08, 0x01);
+ ts2020_writereg(fe, 0x00, 0x41);
+
+ return 0;
+}
+
+static int ts2020_tuner_gate_ctrl(struct dvb_frontend *fe, u8 offset)
+{
+ int ret;
+ ret = ts2020_writereg(fe, 0x51, 0x1f - offset);
+ ret |= ts2020_writereg(fe, 0x51, 0x1f);
+ ret |= ts2020_writereg(fe, 0x50, offset);
+ ret |= ts2020_writereg(fe, 0x50, 0x00);
+ msleep(20);
+ return ret;
+}
+
+static int ts2020_set_tuner_rf(struct dvb_frontend *fe)
+{
+ int reg;
+
+ reg = ts2020_readreg(fe, 0x3d);
+ reg &= 0x7f;
+ if (reg < 0x16)
+ reg = 0xa1;
+ else if (reg == 0x16)
+ reg = 0x99;
+ else
+ reg = 0xf9;
+
+ ts2020_writereg(fe, 0x60, reg);
+ reg = ts2020_tuner_gate_ctrl(fe, 0x08);
+
+ return reg;
+}
+
+static int ts2020_set_params(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct ts2020_priv *priv = fe->tuner_priv;
+ int ret;
+ u32 frequency = c->frequency;
+ s32 offset_khz;
+ u32 symbol_rate = (c->symbol_rate / 1000);
+ u32 f3db, gdiv28;
+ u16 value, ndiv, lpf_coeff;
+ u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
+ u8 lo = 0x01, div4 = 0x0;
+
+ /* Calculate frequency divider */
+ if (frequency < 1060000) {
+ lo |= 0x10;
+ div4 = 0x1;
+ ndiv = (frequency * 14 * 4) / TS2020_XTAL_FREQ;
+ } else
+ ndiv = (frequency * 14 * 2) / TS2020_XTAL_FREQ;
+ ndiv = ndiv + ndiv % 2;
+ ndiv = ndiv - 1024;
+
+ ret = ts2020_writereg(fe, 0x10, 0x80 | lo);
+
+ /* Set frequency divider */
+ ret |= ts2020_writereg(fe, 0x01, (ndiv >> 8) & 0xf);
+ ret |= ts2020_writereg(fe, 0x02, ndiv & 0xff);
+
+ ret |= ts2020_writereg(fe, 0x03, 0x06);
+ ret |= ts2020_tuner_gate_ctrl(fe, 0x10);
+ if (ret < 0)
+ return -ENODEV;
+
+ /* Tuner Frequency Range */
+ ret = ts2020_writereg(fe, 0x10, lo);
+
+ ret |= ts2020_tuner_gate_ctrl(fe, 0x08);
+
+ /* Tuner RF */
+ ret |= ts2020_set_tuner_rf(fe);
+
+ gdiv28 = (TS2020_XTAL_FREQ / 1000 * 1694 + 500) / 1000;
+ ret |= ts2020_writereg(fe, 0x04, gdiv28 & 0xff);
+ ret |= ts2020_tuner_gate_ctrl(fe, 0x04);
+ if (ret < 0)
+ return -ENODEV;
+
+ value = ts2020_readreg(fe, 0x26);
+
+ f3db = (symbol_rate * 135) / 200 + 2000;
+ f3db += FREQ_OFFSET_LOW_SYM_RATE;
+ if (f3db < 7000)
+ f3db = 7000;
+ if (f3db > 40000)
+ f3db = 40000;
+
+ gdiv28 = gdiv28 * 207 / (value * 2 + 151);
+ mlpf_max = gdiv28 * 135 / 100;
+ mlpf_min = gdiv28 * 78 / 100;
+ if (mlpf_max > 63)
+ mlpf_max = 63;
+
+ lpf_coeff = 2766;
+
+ nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
+ (TS2020_XTAL_FREQ / 1000) + 1) / 2;
+ if (nlpf > 23)
+ nlpf = 23;
+ if (nlpf < 1)
+ nlpf = 1;
+
+ lpf_mxdiv = (nlpf * (TS2020_XTAL_FREQ / 1000)
+ * lpf_coeff * 2 / f3db + 1) / 2;
+
+ if (lpf_mxdiv < mlpf_min) {
+ nlpf++;
+ lpf_mxdiv = (nlpf * (TS2020_XTAL_FREQ / 1000)
+ * lpf_coeff * 2 / f3db + 1) / 2;
+ }
+
+ if (lpf_mxdiv > mlpf_max)
+ lpf_mxdiv = mlpf_max;
+
+ ret = ts2020_writereg(fe, 0x04, lpf_mxdiv);
+ ret |= ts2020_writereg(fe, 0x06, nlpf);
+
+ ret |= ts2020_tuner_gate_ctrl(fe, 0x04);
+
+ ret |= ts2020_tuner_gate_ctrl(fe, 0x01);
+
+ msleep(80);
+ /* calculate offset assuming 96000kHz*/
+ offset_khz = (ndiv - ndiv % 2 + 1024) * TS2020_XTAL_FREQ
+ / (6 + 8) / (div4 + 1) / 2;
+
+ priv->frequency = offset_khz;
+
+ return (ret < 0) ? -EINVAL : 0;
+}
+
+static int ts2020_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct ts2020_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+/* read TS2020 signal strength */
+static int ts2020_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
+{
+ u16 sig_reading, sig_strength;
+ u8 rfgain, bbgain;
+
+ rfgain = ts2020_readreg(fe, 0x3d) & 0x1f;
+ bbgain = ts2020_readreg(fe, 0x21) & 0x1f;
+
+ if (rfgain > 15)
+ rfgain = 15;
+ if (bbgain > 13)
+ bbgain = 13;
+
+ sig_reading = rfgain * 2 + bbgain * 3;
+
+ sig_strength = 40 + (64 - sig_reading) * 50 / 64 ;
+
+ /* cook the value to be suitable for szap-s2 human readable output */
+ *signal_strength = sig_strength * 1000;
+
+ return 0;
+}
+
+static struct dvb_tuner_ops ts2020_tuner_ops = {
+ .info = {
+ .name = "TS2020",
+ .frequency_min = 950000,
+ .frequency_max = 2150000
+ },
+ .init = ts2020_init,
+ .release = ts2020_release,
+ .sleep = ts2020_sleep,
+ .set_params = ts2020_set_params,
+ .get_frequency = ts2020_get_frequency,
+ .get_rf_strength = ts2020_read_signal_strength,
+};
+
+struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
+ const struct ts2020_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct ts2020_priv *priv = NULL;
+ u8 buf;
+
+ priv = kzalloc(sizeof(struct ts2020_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->i2c_address = config->tuner_address;
+ priv->i2c = i2c;
+ priv->clk_out_div = config->clk_out_div;
+ fe->tuner_priv = priv;
+
+ /* Wake Up the tuner */
+ if ((0x03 & ts2020_readreg(fe, 0x00)) == 0x00) {
+ ts2020_writereg(fe, 0x00, 0x01);
+ msleep(2);
+ }
+
+ ts2020_writereg(fe, 0x00, 0x03);
+ msleep(2);
+
+ /* Check the tuner version */
+ buf = ts2020_readreg(fe, 0x00);
+ if ((buf == 0x01) || (buf == 0x41) || (buf == 0x81))
+ printk(KERN_INFO "%s: Find tuner TS2020!\n", __func__);
+ else {
+ printk(KERN_ERR "%s: Read tuner reg[0] = %d\n", __func__, buf);
+ kfree(priv);
+ return NULL;
+ }
+
+ memcpy(&fe->ops.tuner_ops, &ts2020_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ return fe;
+}
+EXPORT_SYMBOL(ts2020_attach);
+
+MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>");
+MODULE_DESCRIPTION("Montage Technology TS2020 - Silicon tuner driver module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/ts2020.h b/drivers/media/dvb-frontends/ts2020.h
new file mode 100644
index 000000000000..c7e64afa614a
--- /dev/null
+++ b/drivers/media/dvb-frontends/ts2020.h
@@ -0,0 +1,50 @@
+/*
+ Montage Technology TS2020 - Silicon Tuner driver
+ Copyright (C) 2009-2012 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
+
+ Copyright (C) 2009-2012 TurboSight.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 TS2020_H
+#define TS2020_H
+
+#include <linux/dvb/frontend.h>
+
+struct ts2020_config {
+ u8 tuner_address;
+ u8 clk_out_div;
+};
+
+#if defined(CONFIG_DVB_TS2020) || \
+ (defined(CONFIG_DVB_TS2020_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *ts2020_attach(
+ struct dvb_frontend *fe,
+ const struct ts2020_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *ts2020_attach(
+ struct dvb_frontend *fe,
+ const struct ts2020_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* TS2020_H */
diff --git a/drivers/media/dvb-frontends/tua6100.h b/drivers/media/dvb-frontends/tua6100.h
index f83dbd5e42ae..83a9c30e67ca 100644
--- a/drivers/media/dvb-frontends/tua6100.h
+++ b/drivers/media/dvb-frontends/tua6100.h
@@ -34,7 +34,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_DVB_TUA6100) || (defined(CONFIG_DVB_TUA6100_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TUA6100)
extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
diff --git a/drivers/media/dvb-frontends/ves1820.h b/drivers/media/dvb-frontends/ves1820.h
index e902ed634ec3..c073f353ac38 100644
--- a/drivers/media/dvb-frontends/ves1820.h
+++ b/drivers/media/dvb-frontends/ves1820.h
@@ -41,7 +41,7 @@ struct ves1820_config
u8 selagc:1;
};
-#if defined(CONFIG_DVB_VES1820) || (defined(CONFIG_DVB_VES1820_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_VES1820)
extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
struct i2c_adapter* i2c, u8 pwm);
#else
diff --git a/drivers/media/dvb-frontends/ves1x93.h b/drivers/media/dvb-frontends/ves1x93.h
index 8a5a49e808f6..2307caea6aec 100644
--- a/drivers/media/dvb-frontends/ves1x93.h
+++ b/drivers/media/dvb-frontends/ves1x93.h
@@ -40,7 +40,7 @@ struct ves1x93_config
u8 invert_pwm:1;
};
-#if defined(CONFIG_DVB_VES1X93) || (defined(CONFIG_DVB_VES1X93_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_VES1X93)
extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
struct i2c_adapter* i2c);
#else
diff --git a/drivers/media/dvb-frontends/zl10353.h b/drivers/media/dvb-frontends/zl10353.h
index 6e3ca9eed048..50c1004aef36 100644
--- a/drivers/media/dvb-frontends/zl10353.h
+++ b/drivers/media/dvb-frontends/zl10353.h
@@ -47,7 +47,7 @@ struct zl10353_config
u8 pll_0; /* default: 0x15 */
};
-#if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_ZL10353)
extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 24d78e28e493..7b771baa2212 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -1,16 +1,4 @@
#
-# Generic video config states
-#
-
-config VIDEO_BTCX
- depends on PCI
- tristate
-
-config VIDEO_TVEEPROM
- tristate
- depends on I2C
-
-#
# Multimedia Video device configuration
#
@@ -317,20 +305,6 @@ config VIDEO_SAA717X
source "drivers/media/i2c/cx25840/Kconfig"
-comment "MPEG video encoders"
-
-config VIDEO_CX2341X
- tristate "Conexant CX2341x MPEG encoders"
- depends on VIDEO_V4L2
- ---help---
- Support for the Conexant CX23416 MPEG encoders
- and CX23415 MPEG encoder/decoders.
-
- This module currently supports the encoding functions only.
-
- To compile this driver as a module, choose M here: the
- module will be called cx2341x.
-
comment "Video encoders"
config VIDEO_SAA7127
@@ -421,6 +395,13 @@ config VIDEO_OV7670
OV7670 VGA camera. It currently only works with the M88ALP01
controller.
+config VIDEO_OV9650
+ tristate "OmniVision OV9650/OV9652 sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ ---help---
+ This is a V4L2 sensor-level driver for the Omnivision
+ OV9650 and OV9652 camera sensors.
+
config VIDEO_VS6624
tristate "ST VS6624 sensor support"
depends on VIDEO_V4L2 && I2C
@@ -477,7 +458,7 @@ config VIDEO_MT9V032
config VIDEO_TCM825X
tristate "TCM825x camera sensor support"
- depends on I2C && VIDEO_V4L2
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_INT_DEVICE
depends on MEDIA_CAMERA_SUPPORT
---help---
This is a driver for the Toshiba TCM825x VGA camera sensor.
@@ -516,6 +497,13 @@ config VIDEO_S5K4ECGX
source "drivers/media/i2c/smiapp/Kconfig"
+config VIDEO_S5C73M3
+ tristate "Samsung S5C73M3 sensor support"
+ depends on I2C && SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ ---help---
+ This is a V4L2 sensor-level driver for Samsung S5C73M3
+ 8 Mpixel camera.
+
comment "Flash devices"
config VIDEO_ADP1653
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index b1d62dfd49b8..cfefd30cc1bc 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -47,8 +47,8 @@ obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
-obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
@@ -58,10 +58,9 @@ obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o
obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o
+obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/
obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o
obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
-obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
-obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 64d71fb87a96..34f39d3b3e3e 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -402,9 +402,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
.g_chip_ident = adv7180_g_chip_ident,
.s_std = adv7180_s_std,
- .queryctrl = v4l2_subdev_queryctrl,
- .g_ctrl = v4l2_subdev_g_ctrl,
- .s_ctrl = v4l2_subdev_s_ctrl,
};
static const struct v4l2_subdev_ops adv7180_ops = {
diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c
index 2b5aa676a84e..9fc2b985df0e 100644
--- a/drivers/media/i2c/adv7343.c
+++ b/drivers/media/i2c/adv7343.c
@@ -43,6 +43,7 @@ MODULE_PARM_DESC(debug, "Debug level 0-1");
struct adv7343_state {
struct v4l2_subdev sd;
struct v4l2_ctrl_handler hdl;
+ const struct adv7343_platform_data *pdata;
u8 reg00;
u8 reg01;
u8 reg02;
@@ -215,12 +216,23 @@ static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
/* Enable Appropriate DAC */
val = state->reg00 & 0x03;
- if (output_type == ADV7343_COMPOSITE_ID)
- val |= ADV7343_COMPOSITE_POWER_VALUE;
- else if (output_type == ADV7343_COMPONENT_ID)
- val |= ADV7343_COMPONENT_POWER_VALUE;
+ /* configure default configuration */
+ if (!state->pdata)
+ if (output_type == ADV7343_COMPOSITE_ID)
+ val |= ADV7343_COMPOSITE_POWER_VALUE;
+ else if (output_type == ADV7343_COMPONENT_ID)
+ val |= ADV7343_COMPONENT_POWER_VALUE;
+ else
+ val |= ADV7343_SVIDEO_POWER_VALUE;
else
- val |= ADV7343_SVIDEO_POWER_VALUE;
+ val = state->pdata->mode_config.sleep_mode << 0 |
+ state->pdata->mode_config.pll_control << 1 |
+ state->pdata->mode_config.dac_3 << 2 |
+ state->pdata->mode_config.dac_2 << 3 |
+ state->pdata->mode_config.dac_1 << 4 |
+ state->pdata->mode_config.dac_6 << 5 |
+ state->pdata->mode_config.dac_5 << 6 |
+ state->pdata->mode_config.dac_4 << 7;
err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);
if (err < 0)
@@ -238,6 +250,17 @@ static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
/* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */
val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);
+
+ if (state->pdata && state->pdata->sd_config.sd_dac_out1)
+ val = val | (state->pdata->sd_config.sd_dac_out1 << 1);
+ else if (state->pdata && !state->pdata->sd_config.sd_dac_out1)
+ val = val & ~(state->pdata->sd_config.sd_dac_out1 << 1);
+
+ if (state->pdata && state->pdata->sd_config.sd_dac_out2)
+ val = val | (state->pdata->sd_config.sd_dac_out2 << 2);
+ else if (state->pdata && !state->pdata->sd_config.sd_dac_out2)
+ val = val & ~(state->pdata->sd_config.sd_dac_out2 << 2);
+
err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);
if (err < 0)
goto setoutput_exit;
@@ -397,10 +420,14 @@ static int adv7343_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL);
+ state = devm_kzalloc(&client->dev, sizeof(struct adv7343_state),
+ GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
+ /* Copy board specific information here */
+ state->pdata = client->dev.platform_data;
+
state->reg00 = 0x80;
state->reg01 = 0x00;
state->reg02 = 0x20;
@@ -431,16 +458,13 @@ static int adv7343_probe(struct i2c_client *client,
int err = state->hdl.error;
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return err;
}
v4l2_ctrl_handler_setup(&state->hdl);
err = adv7343_initialize(&state->sd);
- if (err) {
+ if (err)
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
- }
return err;
}
@@ -451,7 +475,6 @@ static int adv7343_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&state->hdl);
- kfree(state);
return 0;
}
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index 38ce76ed1924..9ae977b5983a 100644
--- a/drivers/media/i2c/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -1251,13 +1251,11 @@ int cx25840_ir_probe(struct v4l2_subdev *sd)
cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0);
mutex_init(&ir_state->rx_params_lock);
- memcpy(&default_params, &default_rx_params,
- sizeof(struct v4l2_subdev_ir_parameters));
+ default_params = default_rx_params;
v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params);
mutex_init(&ir_state->tx_params_lock);
- memcpy(&default_params, &default_tx_params,
- sizeof(struct v4l2_subdev_ir_parameters));
+ default_params = default_tx_params;
v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
return 0;
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index 6bf01ad62765..73b7688cbebd 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -13,6 +13,7 @@
#include <asm/div64.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
#include <media/mt9v011.h>
MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
@@ -48,68 +49,9 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
#define MT9V011_VERSION 0x8232
#define MT9V011_REV_B_VERSION 0x8243
-/* supported controls */
-static struct v4l2_queryctrl mt9v011_qctrl[] = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = (1 << 12) - 1 - 0x0020,
- .step = 1,
- .default_value = 0x0020,
- .flags = 0,
- }, {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 0,
- .maximum = 2047,
- .step = 1,
- .default_value = 0x01fc,
- .flags = 0,
- }, {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red Balance",
- .minimum = -1 << 9,
- .maximum = (1 << 9) - 1,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- }, {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue Balance",
- .minimum = -1 << 9,
- .maximum = (1 << 9) - 1,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- }, {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mirror",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- }, {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Vflip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- }, {
- }
-};
-
struct mt9v011 {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler ctrls;
unsigned width, height;
unsigned xtal;
unsigned hflip:1;
@@ -381,99 +323,6 @@ static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
set_read_mode(sd);
return 0;
-};
-
-static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct mt9v011 *core = to_mt9v011(sd);
-
- v4l2_dbg(1, debug, sd, "g_ctrl called\n");
-
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- ctrl->value = core->global_gain;
- return 0;
- case V4L2_CID_EXPOSURE:
- ctrl->value = core->exposure;
- return 0;
- case V4L2_CID_RED_BALANCE:
- ctrl->value = core->red_bal;
- return 0;
- case V4L2_CID_BLUE_BALANCE:
- ctrl->value = core->blue_bal;
- return 0;
- case V4L2_CID_HFLIP:
- ctrl->value = core->hflip ? 1 : 0;
- return 0;
- case V4L2_CID_VFLIP:
- ctrl->value = core->vflip ? 1 : 0;
- return 0;
- }
- return -EINVAL;
-}
-
-static int mt9v011_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- int i;
-
- v4l2_dbg(1, debug, sd, "queryctrl called\n");
-
- for (i = 0; i < ARRAY_SIZE(mt9v011_qctrl); i++)
- if (qc->id && qc->id == mt9v011_qctrl[i].id) {
- memcpy(qc, &(mt9v011_qctrl[i]),
- sizeof(*qc));
- return 0;
- }
-
- return -EINVAL;
-}
-
-
-static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct mt9v011 *core = to_mt9v011(sd);
- u8 i, n;
- n = ARRAY_SIZE(mt9v011_qctrl);
-
- for (i = 0; i < n; i++) {
- if (ctrl->id != mt9v011_qctrl[i].id)
- continue;
- if (ctrl->value < mt9v011_qctrl[i].minimum ||
- ctrl->value > mt9v011_qctrl[i].maximum)
- return -ERANGE;
- v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n",
- ctrl->id, ctrl->value);
- break;
- }
-
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- core->global_gain = ctrl->value;
- break;
- case V4L2_CID_EXPOSURE:
- core->exposure = ctrl->value;
- break;
- case V4L2_CID_RED_BALANCE:
- core->red_bal = ctrl->value;
- break;
- case V4L2_CID_BLUE_BALANCE:
- core->blue_bal = ctrl->value;
- break;
- case V4L2_CID_HFLIP:
- core->hflip = ctrl->value;
- set_read_mode(sd);
- return 0;
- case V4L2_CID_VFLIP:
- core->vflip = ctrl->value;
- set_read_mode(sd);
- return 0;
- default:
- return -EINVAL;
- }
-
- set_balance(sd);
-
- return 0;
}
static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
@@ -599,10 +448,46 @@ static int mt9v011_g_chip_ident(struct v4l2_subdev *sd,
version);
}
-static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
- .queryctrl = mt9v011_queryctrl,
- .g_ctrl = mt9v011_g_ctrl,
+static int mt9v011_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9v011 *core =
+ container_of(ctrl->handler, struct mt9v011, ctrls);
+ struct v4l2_subdev *sd = &core->sd;
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ core->global_gain = ctrl->val;
+ break;
+ case V4L2_CID_EXPOSURE:
+ core->exposure = ctrl->val;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ core->red_bal = ctrl->val;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ core->blue_bal = ctrl->val;
+ break;
+ case V4L2_CID_HFLIP:
+ core->hflip = ctrl->val;
+ set_read_mode(sd);
+ return 0;
+ case V4L2_CID_VFLIP:
+ core->vflip = ctrl->val;
+ set_read_mode(sd);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ set_balance(sd);
+ return 0;
+}
+
+static struct v4l2_ctrl_ops mt9v011_ctrl_ops = {
.s_ctrl = mt9v011_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
.reset = mt9v011_reset,
.g_chip_ident = mt9v011_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -658,6 +543,30 @@ static int mt9v011_probe(struct i2c_client *c,
return -EINVAL;
}
+ v4l2_ctrl_handler_init(&core->ctrls, 5);
+ v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
+ V4L2_CID_GAIN, 0, (1 << 12) - 1 - 0x20, 1, 0x20);
+ v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 2047, 1, 0x01fc);
+ v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
+ V4L2_CID_RED_BALANCE, -(1 << 9), (1 << 9) - 1, 1, 0);
+ v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, -(1 << 9), (1 << 9) - 1, 1, 0);
+ v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ if (core->ctrls.error) {
+ int ret = core->ctrls.error;
+
+ v4l2_err(sd, "control initialization error %d\n", ret);
+ v4l2_ctrl_handler_free(&core->ctrls);
+ kfree(core);
+ return ret;
+ }
+ core->sd.ctrl_handler = &core->ctrls;
+
core->global_gain = 0x0024;
core->exposure = 0x01fc;
core->width = 640;
@@ -681,12 +590,14 @@ static int mt9v011_probe(struct i2c_client *c,
static int mt9v011_remove(struct i2c_client *c)
{
struct v4l2_subdev *sd = i2c_get_clientdata(c);
+ struct mt9v011 *core = to_mt9v011(sd);
v4l2_dbg(1, debug, sd,
"mt9v011.c: removing mt9v011 adapter on address 0x%x\n",
c->addr << 1);
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&core->ctrls);
kfree(to_mt9v011(sd));
return 0;
}
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index 440c12962bae..8554b47f993a 100644
--- a/drivers/media/i2c/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
@@ -660,13 +660,6 @@ static const struct v4l2_ctrl_ops noon010_ctrl_ops = {
static const struct v4l2_subdev_core_ops noon010_core_ops = {
.s_power = noon010_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 = noon010_log_status,
};
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index e7c82b297514..05ed5b8e7f88 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -18,6 +18,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-mediabus.h>
#include <media/ov7670.h>
@@ -47,6 +48,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
*/
#define OV7670_I2C_ADDR 0x42
+#define PLL_FACTOR 4
+
/* Registers */
#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
#define REG_BLUE 0x01 /* blue gain */
@@ -164,6 +167,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
#define REG_GFIX 0x69 /* Fix gain control */
+#define REG_DBLV 0x6b /* PLL control an debugging */
+#define DBLV_BYPASS 0x00 /* Bypass PLL */
+#define DBLV_X4 0x01 /* clock x4 */
+#define DBLV_X6 0x10 /* clock x6 */
+#define DBLV_X8 0x11 /* clock x8 */
+
#define REG_REG76 0x76 /* OV's name */
#define R76_BLKPCOR 0x80 /* Black pixel correction enable */
#define R76_WHTPCOR 0x40 /* White pixel correction enable */
@@ -183,6 +192,30 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
#define REG_BD60MAX 0xab /* 60hz banding step limit */
+enum ov7670_model {
+ MODEL_OV7670 = 0,
+ MODEL_OV7675,
+};
+
+struct ov7670_win_size {
+ int width;
+ int height;
+ unsigned char com7_bit;
+ int hstart; /* Start/stop values for the camera. Note */
+ int hstop; /* that they do not always make complete */
+ int vstart; /* sense to humans, but evidently the sensor */
+ int vstop; /* will do the right thing... */
+ struct regval_list *regs; /* Regs to tweak */
+};
+
+struct ov7670_devtype {
+ /* formats supported for each model */
+ struct ov7670_win_size *win_sizes;
+ unsigned int n_win_sizes;
+ /* callbacks for frame rate control */
+ int (*set_framerate)(struct v4l2_subdev *, struct v4l2_fract *);
+ void (*get_framerate)(struct v4l2_subdev *, struct v4l2_fract *);
+};
/*
* Information we maintain about a known sensor.
@@ -190,14 +223,31 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
struct ov7670_format_struct; /* coming later */
struct ov7670_info {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ struct {
+ /* gain cluster */
+ struct v4l2_ctrl *auto_gain;
+ struct v4l2_ctrl *gain;
+ };
+ struct {
+ /* exposure cluster */
+ struct v4l2_ctrl *auto_exposure;
+ struct v4l2_ctrl *exposure;
+ };
+ struct {
+ /* saturation/hue cluster */
+ struct v4l2_ctrl *saturation;
+ struct v4l2_ctrl *hue;
+ };
struct ov7670_format_struct *fmt; /* Current format */
- unsigned char sat; /* Saturation value */
- int hue; /* Hue value */
int min_width; /* Filter out smaller sizes */
int min_height; /* Filter out smaller sizes */
int clock_speed; /* External clock speed (MHz) */
u8 clkrc; /* Clock divider value */
bool use_smbus; /* Use smbus I/O instead of I2C */
+ bool pll_bypass;
+ bool pclk_hb_disable;
+ const struct ov7670_devtype *devtype; /* Device specifics */
};
static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
@@ -205,6 +255,11 @@ static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct ov7670_info, sd);
}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct ov7670_info, hdl)->sd;
+}
+
/*
@@ -353,7 +408,7 @@ static struct regval_list ov7670_fmt_yuv422[] = {
{ REG_RGB444, 0 }, /* No RGB444 please */
{ REG_COM1, 0 }, /* CCIR601 */
{ REG_COM15, COM15_R00FF },
- { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */
+ { REG_COM9, 0x48 }, /* 32x gain ceiling; 0x8 is reserved bit */
{ 0x4f, 0x80 }, /* "matrix coefficient 1" */
{ 0x50, 0x80 }, /* "matrix coefficient 2" */
{ 0x51, 0 }, /* vb */
@@ -652,65 +707,178 @@ static struct regval_list ov7670_qcif_regs[] = {
{ 0xff, 0xff },
};
-static struct ov7670_win_size {
- int width;
- int height;
- unsigned char com7_bit;
- int hstart; /* Start/stop values for the camera. Note */
- int hstop; /* that they do not always make complete */
- int vstart; /* sense to humans, but evidently the sensor */
- int vstop; /* will do the right thing... */
- struct regval_list *regs; /* Regs to tweak */
-/* h/vref stuff */
-} ov7670_win_sizes[] = {
+static struct ov7670_win_size ov7670_win_sizes[] = {
/* VGA */
{
.width = VGA_WIDTH,
.height = VGA_HEIGHT,
.com7_bit = COM7_FMT_VGA,
- .hstart = 158, /* These values from */
- .hstop = 14, /* Omnivision */
+ .hstart = 158, /* These values from */
+ .hstop = 14, /* Omnivision */
.vstart = 10,
.vstop = 490,
- .regs = NULL,
+ .regs = NULL,
},
/* CIF */
{
.width = CIF_WIDTH,
.height = CIF_HEIGHT,
.com7_bit = COM7_FMT_CIF,
- .hstart = 170, /* Empirically determined */
+ .hstart = 170, /* Empirically determined */
.hstop = 90,
.vstart = 14,
.vstop = 494,
- .regs = NULL,
+ .regs = NULL,
},
/* QVGA */
{
.width = QVGA_WIDTH,
.height = QVGA_HEIGHT,
.com7_bit = COM7_FMT_QVGA,
- .hstart = 168, /* Empirically determined */
+ .hstart = 168, /* Empirically determined */
.hstop = 24,
.vstart = 12,
.vstop = 492,
- .regs = NULL,
+ .regs = NULL,
},
/* QCIF */
{
.width = QCIF_WIDTH,
.height = QCIF_HEIGHT,
.com7_bit = COM7_FMT_VGA, /* see comment above */
- .hstart = 456, /* Empirically determined */
+ .hstart = 456, /* Empirically determined */
.hstop = 24,
.vstart = 14,
.vstop = 494,
- .regs = ov7670_qcif_regs,
- },
+ .regs = ov7670_qcif_regs,
+ }
+};
+
+static struct ov7670_win_size ov7675_win_sizes[] = {
+ /*
+ * Currently, only VGA is supported. Theoretically it could be possible
+ * to support CIF, QVGA and QCIF too. Taking values for ov7670 as a
+ * base and tweak them empirically could be required.
+ */
+ {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .com7_bit = COM7_FMT_VGA,
+ .hstart = 158, /* These values from */
+ .hstop = 14, /* Omnivision */
+ .vstart = 14, /* Empirically determined */
+ .vstop = 494,
+ .regs = NULL,
+ }
};
-#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))
+static void ov7675_get_framerate(struct v4l2_subdev *sd,
+ struct v4l2_fract *tpf)
+{
+ struct ov7670_info *info = to_state(sd);
+ u32 clkrc = info->clkrc;
+ int pll_factor;
+
+ if (info->pll_bypass)
+ pll_factor = 1;
+ else
+ pll_factor = PLL_FACTOR;
+
+ clkrc++;
+ if (info->fmt->mbus_code == V4L2_MBUS_FMT_SBGGR8_1X8)
+ clkrc = (clkrc >> 1);
+
+ tpf->numerator = 1;
+ tpf->denominator = (5 * pll_factor * info->clock_speed) /
+ (4 * clkrc);
+}
+
+static int ov7675_set_framerate(struct v4l2_subdev *sd,
+ struct v4l2_fract *tpf)
+{
+ struct ov7670_info *info = to_state(sd);
+ u32 clkrc;
+ int pll_factor;
+ int ret;
+
+ /*
+ * The formula is fps = 5/4*pixclk for YUV/RGB and
+ * fps = 5/2*pixclk for RAW.
+ *
+ * pixclk = clock_speed / (clkrc + 1) * PLLfactor
+ *
+ */
+ if (info->pll_bypass) {
+ pll_factor = 1;
+ ret = ov7670_write(sd, REG_DBLV, DBLV_BYPASS);
+ } else {
+ pll_factor = PLL_FACTOR;
+ ret = ov7670_write(sd, REG_DBLV, DBLV_X4);
+ }
+ if (ret < 0)
+ return ret;
+
+ if (tpf->numerator == 0 || tpf->denominator == 0) {
+ clkrc = 0;
+ } else {
+ clkrc = (5 * pll_factor * info->clock_speed * tpf->numerator) /
+ (4 * tpf->denominator);
+ if (info->fmt->mbus_code == V4L2_MBUS_FMT_SBGGR8_1X8)
+ clkrc = (clkrc << 1);
+ clkrc--;
+ }
+
+ /*
+ * The datasheet claims that clkrc = 0 will divide the input clock by 1
+ * but we've checked with an oscilloscope that it divides by 2 instead.
+ * So, if clkrc = 0 just bypass the divider.
+ */
+ if (clkrc <= 0)
+ clkrc = CLK_EXT;
+ else if (clkrc > CLK_SCALE)
+ clkrc = CLK_SCALE;
+ info->clkrc = clkrc;
+
+ /* Recalculate frame rate */
+ ov7675_get_framerate(sd, tpf);
+
+ ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
+ if (ret < 0)
+ return ret;
+
+ return ov7670_write(sd, REG_DBLV, DBLV_X4);
+}
+
+static void ov7670_get_framerate_legacy(struct v4l2_subdev *sd,
+ struct v4l2_fract *tpf)
+{
+ struct ov7670_info *info = to_state(sd);
+
+ tpf->numerator = 1;
+ tpf->denominator = info->clock_speed;
+ if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1)
+ tpf->denominator /= (info->clkrc & CLK_SCALE);
+}
+
+static int ov7670_set_framerate_legacy(struct v4l2_subdev *sd,
+ struct v4l2_fract *tpf)
+{
+ struct ov7670_info *info = to_state(sd);
+ int div;
+ if (tpf->numerator == 0 || tpf->denominator == 0)
+ div = 1; /* Reset to full rate */
+ else
+ div = (tpf->numerator * info->clock_speed) / tpf->denominator;
+ if (div == 0)
+ div = 1;
+ else if (div > CLK_SCALE)
+ div = CLK_SCALE;
+ info->clkrc = (info->clkrc & 0x80) | div;
+ tpf->numerator = 1;
+ tpf->denominator = info->clock_speed / div;
+ return ov7670_write(sd, REG_CLKRC, info->clkrc);
+}
/*
* Store a set of start/stop values into the camera.
@@ -759,8 +927,11 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
struct ov7670_format_struct **ret_fmt,
struct ov7670_win_size **ret_wsize)
{
- int index;
+ int index, i;
struct ov7670_win_size *wsize;
+ struct ov7670_info *info = to_state(sd);
+ unsigned int n_win_sizes = info->devtype->n_win_sizes;
+ unsigned int win_sizes_limit = n_win_sizes;
for (index = 0; index < N_OV7670_FMTS; index++)
if (ov7670_formats[index].mbus_code == fmt->code)
@@ -776,15 +947,30 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
* Fields: the OV devices claim to be progressive.
*/
fmt->field = V4L2_FIELD_NONE;
+
+ /*
+ * Don't consider values that don't match min_height and min_width
+ * constraints.
+ */
+ if (info->min_width || info->min_height)
+ for (i = 0; i < n_win_sizes; i++) {
+ wsize = info->devtype->win_sizes + i;
+
+ if (wsize->width < info->min_width ||
+ wsize->height < info->min_height) {
+ win_sizes_limit = i;
+ break;
+ }
+ }
/*
* Round requested image size down to the nearest
* we support, but not below the smallest.
*/
- for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES;
- wsize++)
+ for (wsize = info->devtype->win_sizes;
+ wsize < info->devtype->win_sizes + win_sizes_limit; wsize++)
if (fmt->width >= wsize->width && fmt->height >= wsize->height)
break;
- if (wsize >= ov7670_win_sizes + N_WIN_SIZES)
+ if (wsize >= info->devtype->win_sizes + win_sizes_limit)
wsize--; /* Take the smallest one */
if (ret_wsize != NULL)
*ret_wsize = wsize;
@@ -868,10 +1054,8 @@ static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
memset(cp, 0, sizeof(struct v4l2_captureparm));
cp->capability = V4L2_CAP_TIMEPERFRAME;
- cp->timeperframe.numerator = 1;
- cp->timeperframe.denominator = info->clock_speed;
- if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1)
- cp->timeperframe.denominator /= (info->clkrc & CLK_SCALE);
+ info->devtype->get_framerate(sd, &cp->timeperframe);
+
return 0;
}
@@ -880,25 +1064,13 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
struct v4l2_captureparm *cp = &parms->parm.capture;
struct v4l2_fract *tpf = &cp->timeperframe;
struct ov7670_info *info = to_state(sd);
- int div;
if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (cp->extendedmode != 0)
return -EINVAL;
- if (tpf->numerator == 0 || tpf->denominator == 0)
- div = 1; /* Reset to full rate */
- else
- div = (tpf->numerator * info->clock_speed) / tpf->denominator;
- if (div == 0)
- div = 1;
- else if (div > CLK_SCALE)
- div = CLK_SCALE;
- info->clkrc = (info->clkrc & 0x80) | div;
- tpf->numerator = 1;
- tpf->denominator = info->clock_speed / div;
- return ov7670_write(sd, REG_CLKRC, info->clkrc);
+ return info->devtype->set_framerate(sd, tpf);
}
@@ -931,13 +1103,14 @@ static int ov7670_enum_framesizes(struct v4l2_subdev *sd,
int i;
int num_valid = -1;
__u32 index = fsize->index;
+ unsigned int n_win_sizes = info->devtype->n_win_sizes;
/*
* If a minimum width/height was requested, filter out the capture
* windows that fall outside that.
*/
- for (i = 0; i < N_WIN_SIZES; i++) {
- struct ov7670_win_size *win = &ov7670_win_sizes[index];
+ for (i = 0; i < n_win_sizes; i++) {
+ struct ov7670_win_size *win = &info->devtype->win_sizes[index];
if (info->min_width && win->width < info->min_width)
continue;
if (info->min_height && win->height < info->min_height)
@@ -1042,23 +1215,23 @@ static int ov7670_cosine(int theta)
static void ov7670_calc_cmatrix(struct ov7670_info *info,
- int matrix[CMATRIX_LEN])
+ int matrix[CMATRIX_LEN], int sat, int hue)
{
int i;
/*
* Apply the current saturation setting first.
*/
for (i = 0; i < CMATRIX_LEN; i++)
- matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7;
+ matrix[i] = (info->fmt->cmatrix[i] * sat) >> 7;
/*
* Then, if need be, rotate the hue value.
*/
- if (info->hue != 0) {
+ if (hue != 0) {
int sinth, costh, tmpmatrix[CMATRIX_LEN];
memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int));
- sinth = ov7670_sine(info->hue);
- costh = ov7670_cosine(info->hue);
+ sinth = ov7670_sine(hue);
+ costh = ov7670_cosine(hue);
matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000;
matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000;
@@ -1071,60 +1244,21 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info,
-static int ov7670_s_sat(struct v4l2_subdev *sd, int value)
-{
- struct ov7670_info *info = to_state(sd);
- int matrix[CMATRIX_LEN];
- int ret;
-
- info->sat = value;
- ov7670_calc_cmatrix(info, matrix);
- ret = ov7670_store_cmatrix(sd, matrix);
- return ret;
-}
-
-static int ov7670_g_sat(struct v4l2_subdev *sd, __s32 *value)
-{
- struct ov7670_info *info = to_state(sd);
-
- *value = info->sat;
- return 0;
-}
-
-static int ov7670_s_hue(struct v4l2_subdev *sd, int value)
+static int ov7670_s_sat_hue(struct v4l2_subdev *sd, int sat, int hue)
{
struct ov7670_info *info = to_state(sd);
int matrix[CMATRIX_LEN];
int ret;
- if (value < -180 || value > 180)
- return -EINVAL;
- info->hue = value;
- ov7670_calc_cmatrix(info, matrix);
+ ov7670_calc_cmatrix(info, matrix, sat, hue);
ret = ov7670_store_cmatrix(sd, matrix);
return ret;
}
-static int ov7670_g_hue(struct v4l2_subdev *sd, __s32 *value)
-{
- struct ov7670_info *info = to_state(sd);
-
- *value = info->hue;
- return 0;
-}
-
-
/*
* Some weird registers seem to store values in a sign/magnitude format!
*/
-static unsigned char ov7670_sm_to_abs(unsigned char v)
-{
- if ((v & 0x80) == 0)
- return v + 128;
- return 128 - (v & 0x7f);
-}
-
static unsigned char ov7670_abs_to_sm(unsigned char v)
{
@@ -1146,40 +1280,11 @@ static int ov7670_s_brightness(struct v4l2_subdev *sd, int value)
return ret;
}
-static int ov7670_g_brightness(struct v4l2_subdev *sd, __s32 *value)
-{
- unsigned char v = 0;
- int ret = ov7670_read(sd, REG_BRIGHT, &v);
-
- *value = ov7670_sm_to_abs(v);
- return ret;
-}
-
static int ov7670_s_contrast(struct v4l2_subdev *sd, int value)
{
return ov7670_write(sd, REG_CONTRAS, (unsigned char) value);
}
-static int ov7670_g_contrast(struct v4l2_subdev *sd, __s32 *value)
-{
- unsigned char v = 0;
- int ret = ov7670_read(sd, REG_CONTRAS, &v);
-
- *value = v;
- return ret;
-}
-
-static int ov7670_g_hflip(struct v4l2_subdev *sd, __s32 *value)
-{
- int ret;
- unsigned char v = 0;
-
- ret = ov7670_read(sd, REG_MVFP, &v);
- *value = (v & MVFP_MIRROR) == MVFP_MIRROR;
- return ret;
-}
-
-
static int ov7670_s_hflip(struct v4l2_subdev *sd, int value)
{
unsigned char v = 0;
@@ -1195,19 +1300,6 @@ static int ov7670_s_hflip(struct v4l2_subdev *sd, int value)
return ret;
}
-
-
-static int ov7670_g_vflip(struct v4l2_subdev *sd, __s32 *value)
-{
- int ret;
- unsigned char v = 0;
-
- ret = ov7670_read(sd, REG_MVFP, &v);
- *value = (v & MVFP_FLIP) == MVFP_FLIP;
- return ret;
-}
-
-
static int ov7670_s_vflip(struct v4l2_subdev *sd, int value)
{
unsigned char v = 0;
@@ -1256,16 +1348,6 @@ static int ov7670_s_gain(struct v4l2_subdev *sd, int value)
/*
* Tweak autogain.
*/
-static int ov7670_g_autogain(struct v4l2_subdev *sd, __s32 *value)
-{
- int ret;
- unsigned char com8;
-
- ret = ov7670_read(sd, REG_COM8, &com8);
- *value = (com8 & COM8_AGC) != 0;
- return ret;
-}
-
static int ov7670_s_autogain(struct v4l2_subdev *sd, int value)
{
int ret;
@@ -1282,22 +1364,6 @@ static int ov7670_s_autogain(struct v4l2_subdev *sd, int value)
return ret;
}
-/*
- * Exposure is spread all over the place: top 6 bits in AECHH, middle
- * 8 in AECH, and two stashed in COM1 just for the hell of it.
- */
-static int ov7670_g_exp(struct v4l2_subdev *sd, __s32 *value)
-{
- int ret;
- unsigned char com1, aech, aechh;
-
- ret = ov7670_read(sd, REG_COM1, &com1) +
- ov7670_read(sd, REG_AECH, &aech) +
- ov7670_read(sd, REG_AECHH, &aechh);
- *value = ((aechh & 0x3f) << 10) | (aech << 2) | (com1 & 0x03);
- return ret;
-}
-
static int ov7670_s_exp(struct v4l2_subdev *sd, int value)
{
int ret;
@@ -1324,20 +1390,6 @@ static int ov7670_s_exp(struct v4l2_subdev *sd, int value)
/*
* Tweak autoexposure.
*/
-static int ov7670_g_autoexp(struct v4l2_subdev *sd, __s32 *value)
-{
- int ret;
- unsigned char com8;
- enum v4l2_exposure_auto_type *atype = (enum v4l2_exposure_auto_type *) value;
-
- ret = ov7670_read(sd, REG_COM8, &com8);
- if (com8 & COM8_AEC)
- *atype = V4L2_EXPOSURE_AUTO;
- else
- *atype = V4L2_EXPOSURE_MANUAL;
- return ret;
-}
-
static int ov7670_s_autoexp(struct v4l2_subdev *sd,
enum v4l2_exposure_auto_type value)
{
@@ -1356,90 +1408,60 @@ static int ov7670_s_autoexp(struct v4l2_subdev *sd,
}
-
-static int ov7670_queryctrl(struct v4l2_subdev *sd,
- struct v4l2_queryctrl *qc)
+static int ov7670_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
- /* Fill in min, max, step and default value for these controls. */
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
- case V4L2_CID_VFLIP:
- case V4L2_CID_HFLIP:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0);
- case V4L2_CID_GAIN:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
- case V4L2_CID_AUTOGAIN:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_EXPOSURE:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 1, 500);
- case V4L2_CID_EXPOSURE_AUTO:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
- }
- return -EINVAL;
-}
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct ov7670_info *info = to_state(sd);
-static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- return ov7670_g_brightness(sd, &ctrl->value);
- case V4L2_CID_CONTRAST:
- return ov7670_g_contrast(sd, &ctrl->value);
- case V4L2_CID_SATURATION:
- return ov7670_g_sat(sd, &ctrl->value);
- case V4L2_CID_HUE:
- return ov7670_g_hue(sd, &ctrl->value);
- case V4L2_CID_VFLIP:
- return ov7670_g_vflip(sd, &ctrl->value);
- case V4L2_CID_HFLIP:
- return ov7670_g_hflip(sd, &ctrl->value);
- case V4L2_CID_GAIN:
- return ov7670_g_gain(sd, &ctrl->value);
case V4L2_CID_AUTOGAIN:
- return ov7670_g_autogain(sd, &ctrl->value);
- case V4L2_CID_EXPOSURE:
- return ov7670_g_exp(sd, &ctrl->value);
- case V4L2_CID_EXPOSURE_AUTO:
- return ov7670_g_autoexp(sd, &ctrl->value);
+ return ov7670_g_gain(sd, &info->gain->val);
}
return -EINVAL;
}
-static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int ov7670_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct ov7670_info *info = to_state(sd);
+
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- return ov7670_s_brightness(sd, ctrl->value);
+ return ov7670_s_brightness(sd, ctrl->val);
case V4L2_CID_CONTRAST:
- return ov7670_s_contrast(sd, ctrl->value);
+ return ov7670_s_contrast(sd, ctrl->val);
case V4L2_CID_SATURATION:
- return ov7670_s_sat(sd, ctrl->value);
- case V4L2_CID_HUE:
- return ov7670_s_hue(sd, ctrl->value);
+ return ov7670_s_sat_hue(sd,
+ info->saturation->val, info->hue->val);
case V4L2_CID_VFLIP:
- return ov7670_s_vflip(sd, ctrl->value);
+ return ov7670_s_vflip(sd, ctrl->val);
case V4L2_CID_HFLIP:
- return ov7670_s_hflip(sd, ctrl->value);
- case V4L2_CID_GAIN:
- return ov7670_s_gain(sd, ctrl->value);
+ return ov7670_s_hflip(sd, ctrl->val);
case V4L2_CID_AUTOGAIN:
- return ov7670_s_autogain(sd, ctrl->value);
- case V4L2_CID_EXPOSURE:
- return ov7670_s_exp(sd, ctrl->value);
+ /* Only set manual gain if auto gain is not explicitly
+ turned on. */
+ if (!ctrl->val) {
+ /* ov7670_s_gain turns off auto gain */
+ return ov7670_s_gain(sd, info->gain->val);
+ }
+ return ov7670_s_autogain(sd, ctrl->val);
case V4L2_CID_EXPOSURE_AUTO:
- return ov7670_s_autoexp(sd,
- (enum v4l2_exposure_auto_type) ctrl->value);
+ /* Only set manual exposure if auto exposure is not explicitly
+ turned on. */
+ if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
+ /* ov7670_s_exp turns off auto exposure */
+ return ov7670_s_exp(sd, info->exposure->val);
+ }
+ return ov7670_s_autoexp(sd, ctrl->val);
}
return -EINVAL;
}
+static const struct v4l2_ctrl_ops ov7670_ctrl_ops = {
+ .s_ctrl = ov7670_s_ctrl,
+ .g_volatile_ctrl = ov7670_g_volatile_ctrl,
+};
+
static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *chip)
{
@@ -1482,9 +1504,6 @@ static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
static const struct v4l2_subdev_core_ops ov7670_core_ops = {
.g_chip_ident = ov7670_g_chip_ident,
- .g_ctrl = ov7670_g_ctrl,
- .s_ctrl = ov7670_s_ctrl,
- .queryctrl = ov7670_queryctrl,
.reset = ov7670_reset,
.init = ov7670_init,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1510,9 +1529,25 @@ static const struct v4l2_subdev_ops ov7670_ops = {
/* ----------------------------------------------------------------------- */
+static const struct ov7670_devtype ov7670_devdata[] = {
+ [MODEL_OV7670] = {
+ .win_sizes = ov7670_win_sizes,
+ .n_win_sizes = ARRAY_SIZE(ov7670_win_sizes),
+ .set_framerate = ov7670_set_framerate_legacy,
+ .get_framerate = ov7670_get_framerate_legacy,
+ },
+ [MODEL_OV7675] = {
+ .win_sizes = ov7675_win_sizes,
+ .n_win_sizes = ARRAY_SIZE(ov7675_win_sizes),
+ .set_framerate = ov7675_set_framerate,
+ .get_framerate = ov7675_get_framerate,
+ },
+};
+
static int ov7670_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct v4l2_fract tpf;
struct v4l2_subdev *sd;
struct ov7670_info *info;
int ret;
@@ -1537,6 +1572,16 @@ static int ov7670_probe(struct i2c_client *client,
if (config->clock_speed)
info->clock_speed = config->clock_speed;
+
+ /*
+ * It should be allowed for ov7670 too when it is migrated to
+ * the new frame rate formula.
+ */
+ if (config->pll_bypass && id->driver_data != MODEL_OV7670)
+ info->pll_bypass = true;
+
+ if (config->pclk_hb_disable)
+ info->pclk_hb_disable = true;
}
/* Make sure it's an ov7670 */
@@ -1551,9 +1596,58 @@ static int ov7670_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
+ info->devtype = &ov7670_devdata[id->driver_data];
info->fmt = &ov7670_formats[0];
- info->sat = 128; /* Review this */
- info->clkrc = info->clock_speed / 30;
+ info->clkrc = 0;
+
+ /* Set default frame rate to 30 fps */
+ tpf.numerator = 1;
+ tpf.denominator = 30;
+ info->devtype->set_framerate(sd, &tpf);
+
+ if (info->pclk_hb_disable)
+ ov7670_write(sd, REG_COM10, COM10_PCLK_HB);
+
+ v4l2_ctrl_handler_init(&info->hdl, 10);
+ v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 127, 1, 64);
+ v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ info->saturation = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 256, 1, 128);
+ info->hue = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+ V4L2_CID_HUE, -180, 180, 5, 0);
+ info->gain = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+ V4L2_CID_GAIN, 0, 255, 1, 128);
+ info->auto_gain = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 65535, 1, 500);
+ info->auto_exposure = v4l2_ctrl_new_std_menu(&info->hdl, &ov7670_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
+ V4L2_EXPOSURE_AUTO);
+ sd->ctrl_handler = &info->hdl;
+ if (info->hdl.error) {
+ int err = info->hdl.error;
+
+ v4l2_ctrl_handler_free(&info->hdl);
+ kfree(info);
+ return err;
+ }
+ /*
+ * We have checked empirically that hw allows to read back the gain
+ * value chosen by auto gain but that's not the case for auto exposure.
+ */
+ v4l2_ctrl_auto_cluster(2, &info->auto_gain, 0, true);
+ v4l2_ctrl_auto_cluster(2, &info->auto_exposure,
+ V4L2_EXPOSURE_MANUAL, false);
+ v4l2_ctrl_cluster(2, &info->saturation);
+ v4l2_ctrl_handler_setup(&info->hdl);
+
return 0;
}
@@ -1561,14 +1655,17 @@ static int ov7670_probe(struct i2c_client *client,
static int ov7670_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov7670_info *info = to_state(sd);
v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
+ v4l2_ctrl_handler_free(&info->hdl);
+ kfree(info);
return 0;
}
static const struct i2c_device_id ov7670_id[] = {
- { "ov7670", 0 },
+ { "ov7670", MODEL_OV7670 },
+ { "ov7675", MODEL_OV7675 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ov7670_id);
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
new file mode 100644
index 000000000000..1dbb8118a285
--- /dev/null
+++ b/drivers/media/i2c/ov9650.c
@@ -0,0 +1,1562 @@
+/*
+ * Omnivision OV9650/OV9652 CMOS Image Sensor driver
+ *
+ * Copyright (C) 2013, Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
+ *
+ * Register definitions and initial settings based on a driver written
+ * by Vladimir Fonov.
+ * Copyright (c) 2010, Vladimir Fonov
+ *
+ * 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/gpio.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/media.h>
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-mediabus.h>
+#include <media/ov9650.h>
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+#define DRIVER_NAME "OV9650"
+
+/*
+ * OV9650/OV9652 register definitions
+ */
+#define REG_GAIN 0x00 /* Gain control, AGC[7:0] */
+#define REG_BLUE 0x01 /* AWB - Blue chanel gain */
+#define REG_RED 0x02 /* AWB - Red chanel gain */
+#define REG_VREF 0x03 /* [7:6] - AGC[9:8], [5:3]/[2:0] */
+#define VREF_GAIN_MASK 0xc0 /* - VREF end/start low 3 bits */
+#define REG_COM1 0x04
+#define COM1_CCIR656 0x40
+#define REG_B_AVE 0x05
+#define REG_GB_AVE 0x06
+#define REG_GR_AVE 0x07
+#define REG_R_AVE 0x08
+#define REG_COM2 0x09
+#define REG_PID 0x0a /* Product ID MSB */
+#define REG_VER 0x0b /* Product ID LSB */
+#define REG_COM3 0x0c
+#define COM3_SWAP 0x40
+#define COM3_VARIOPIXEL1 0x04
+#define REG_COM4 0x0d /* Vario Pixels */
+#define COM4_VARIOPIXEL2 0x80
+#define REG_COM5 0x0e /* System clock options */
+#define COM5_SLAVE_MODE 0x10
+#define COM5_SYSTEMCLOCK48MHZ 0x80
+#define REG_COM6 0x0f /* HREF & ADBLC options */
+#define REG_AECH 0x10 /* Exposure value, AEC[9:2] */
+#define REG_CLKRC 0x11 /* Clock control */
+#define CLK_EXT 0x40 /* Use external clock directly */
+#define CLK_SCALE 0x3f /* Mask for internal clock scale */
+#define REG_COM7 0x12 /* SCCB reset, output format */
+#define COM7_RESET 0x80
+#define COM7_FMT_MASK 0x38
+#define COM7_FMT_VGA 0x40
+#define COM7_FMT_CIF 0x20
+#define COM7_FMT_QVGA 0x10
+#define COM7_FMT_QCIF 0x08
+#define COM7_RGB 0x04
+#define COM7_YUV 0x00
+#define COM7_BAYER 0x01
+#define COM7_PBAYER 0x05
+#define REG_COM8 0x13 /* AGC/AEC options */
+#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
+#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */
+#define COM8_BFILT 0x20 /* Band filter enable */
+#define COM8_AGC 0x04 /* Auto gain enable */
+#define COM8_AWB 0x02 /* White balance enable */
+#define COM8_AEC 0x01 /* Auto exposure enable */
+#define REG_COM9 0x14 /* Gain ceiling */
+#define COM9_GAIN_CEIL_MASK 0x70 /* */
+#define REG_COM10 0x15 /* PCLK, HREF, HSYNC signals polarity */
+#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */
+#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */
+#define COM10_HREF_REV 0x08 /* Reverse HREF */
+#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */
+#define COM10_VS_NEG 0x02 /* VSYNC negative */
+#define COM10_HS_NEG 0x01 /* HSYNC negative */
+#define REG_HSTART 0x17 /* Horiz start high bits */
+#define REG_HSTOP 0x18 /* Horiz stop high bits */
+#define REG_VSTART 0x19 /* Vert start high bits */
+#define REG_VSTOP 0x1a /* Vert stop high bits */
+#define REG_PSHFT 0x1b /* Pixel delay after HREF */
+#define REG_MIDH 0x1c /* Manufacturer ID MSB */
+#define REG_MIDL 0x1d /* Manufufacturer ID LSB */
+#define REG_MVFP 0x1e /* Image mirror/flip */
+#define MVFP_MIRROR 0x20 /* Mirror image */
+#define MVFP_FLIP 0x10 /* Vertical flip */
+#define REG_BOS 0x20 /* B channel Offset */
+#define REG_GBOS 0x21 /* Gb channel Offset */
+#define REG_GROS 0x22 /* Gr channel Offset */
+#define REG_ROS 0x23 /* R channel Offset */
+#define REG_AEW 0x24 /* AGC upper limit */
+#define REG_AEB 0x25 /* AGC lower limit */
+#define REG_VPT 0x26 /* AGC/AEC fast mode op region */
+#define REG_BBIAS 0x27 /* B channel output bias */
+#define REG_GBBIAS 0x28 /* Gb channel output bias */
+#define REG_GRCOM 0x29 /* Analog BLC & regulator */
+#define REG_EXHCH 0x2a /* Dummy pixel insert MSB */
+#define REG_EXHCL 0x2b /* Dummy pixel insert LSB */
+#define REG_RBIAS 0x2c /* R channel output bias */
+#define REG_ADVFL 0x2d /* LSB of dummy line insert */
+#define REG_ADVFH 0x2e /* MSB of dummy line insert */
+#define REG_YAVE 0x2f /* Y/G channel average value */
+#define REG_HSYST 0x30 /* HSYNC rising edge delay LSB*/
+#define REG_HSYEN 0x31 /* HSYNC falling edge delay LSB*/
+#define REG_HREF 0x32 /* HREF pieces */
+#define REG_CHLF 0x33 /* reserved */
+#define REG_ADC 0x37 /* reserved */
+#define REG_ACOM 0x38 /* reserved */
+#define REG_OFON 0x39 /* Power down register */
+#define OFON_PWRDN 0x08 /* Power down bit */
+#define REG_TSLB 0x3a /* YUVU format */
+#define TSLB_YUYV_MASK 0x0c /* UYVY or VYUY - see com13 */
+#define REG_COM11 0x3b /* Night mode, banding filter enable */
+#define COM11_NIGHT 0x80 /* Night mode enable */
+#define COM11_NMFR 0x60 /* Two bit NM frame rate */
+#define COM11_BANDING 0x01 /* Banding filter */
+#define COM11_AEC_REF_MASK 0x18 /* AEC reference area selection */
+#define REG_COM12 0x3c /* HREF option, UV average */
+#define COM12_HREF 0x80 /* HREF always */
+#define REG_COM13 0x3d /* Gamma selection, Color matrix en. */
+#define COM13_GAMMA 0x80 /* Gamma enable */
+#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */
+#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */
+#define REG_COM14 0x3e /* Edge enhancement options */
+#define COM14_EDGE_EN 0x02
+#define COM14_EEF_X2 0x01
+#define REG_EDGE 0x3f /* Edge enhancement factor */
+#define EDGE_FACTOR_MASK 0x0f
+#define REG_COM15 0x40 /* Output range, RGB 555/565 */
+#define COM15_R10F0 0x00 /* Data range 10 to F0 */
+#define COM15_R01FE 0x80 /* 01 to FE */
+#define COM15_R00FF 0xc0 /* 00 to FF */
+#define COM15_RGB565 0x10 /* RGB565 output */
+#define COM15_RGB555 0x30 /* RGB555 output */
+#define COM15_SWAPRB 0x04 /* Swap R&B */
+#define REG_COM16 0x41 /* Color matrix coeff options */
+#define REG_COM17 0x42 /* Single frame out, banding filter */
+/* n = 1...9, 0x4f..0x57 */
+#define REG_MTX(__n) (0x4f + (__n) - 1)
+#define REG_MTXS 0x58
+/* Lens Correction Option 1...5, __n = 0...5 */
+#define REG_LCC(__n) (0x62 + (__n) - 1)
+#define LCC5_LCC_ENABLE 0x01 /* LCC5, enable lens correction */
+#define LCC5_LCC_COLOR 0x04
+#define REG_MANU 0x67 /* Manual U value */
+#define REG_MANV 0x68 /* Manual V value */
+#define REG_HV 0x69 /* Manual banding filter MSB */
+#define REG_MBD 0x6a /* Manual banding filter value */
+#define REG_DBLV 0x6b /* reserved */
+#define REG_GSP 0x6c /* Gamma curve */
+#define GSP_LEN 15
+#define REG_GST 0x7c /* Gamma curve */
+#define GST_LEN 15
+#define REG_COM21 0x8b
+#define REG_COM22 0x8c /* Edge enhancement, denoising */
+#define COM22_WHTPCOR 0x02 /* White pixel correction enable */
+#define COM22_WHTPCOROPT 0x01 /* White pixel correction option */
+#define COM22_DENOISE 0x10 /* White pixel correction option */
+#define REG_COM23 0x8d /* Color bar test, color gain */
+#define COM23_TEST_MODE 0x10
+#define REG_DBLC1 0x8f /* Digital BLC */
+#define REG_DBLC_B 0x90 /* Digital BLC B channel offset */
+#define REG_DBLC_R 0x91 /* Digital BLC R channel offset */
+#define REG_DM_LNL 0x92 /* Dummy line low 8 bits */
+#define REG_DM_LNH 0x93 /* Dummy line high 8 bits */
+#define REG_LCCFB 0x9d /* Lens Correction B channel */
+#define REG_LCCFR 0x9e /* Lens Correction R channel */
+#define REG_DBLC_GB 0x9f /* Digital BLC GB chan offset */
+#define REG_DBLC_GR 0xa0 /* Digital BLC GR chan offset */
+#define REG_AECHM 0xa1 /* Exposure value - bits AEC[15:10] */
+#define REG_BD50ST 0xa2 /* Banding filter value for 50Hz */
+#define REG_BD60ST 0xa3 /* Banding filter value for 60Hz */
+#define REG_NULL 0xff /* Array end token */
+
+#define DEF_CLKRC 0x80
+
+#define OV965X_ID(_msb, _lsb) ((_msb) << 8 | (_lsb))
+#define OV9650_ID 0x9650
+#define OV9652_ID 0x9652
+
+struct ov965x_ctrls {
+ struct v4l2_ctrl_handler handler;
+ struct {
+ struct v4l2_ctrl *auto_exp;
+ struct v4l2_ctrl *exposure;
+ };
+ struct {
+ struct v4l2_ctrl *auto_wb;
+ struct v4l2_ctrl *blue_balance;
+ struct v4l2_ctrl *red_balance;
+ };
+ struct {
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ };
+ struct {
+ struct v4l2_ctrl *auto_gain;
+ struct v4l2_ctrl *gain;
+ };
+ struct v4l2_ctrl *brightness;
+ struct v4l2_ctrl *saturation;
+ struct v4l2_ctrl *sharpness;
+ struct v4l2_ctrl *light_freq;
+ u8 update;
+};
+
+struct ov965x_framesize {
+ u16 width;
+ u16 height;
+ u16 max_exp_lines;
+ const u8 *regs;
+};
+
+struct ov965x_interval {
+ struct v4l2_fract interval;
+ /* Maximum resolution for this interval */
+ struct v4l2_frmsize_discrete size;
+ u8 clkrc_div;
+};
+
+enum gpio_id {
+ GPIO_PWDN,
+ GPIO_RST,
+ NUM_GPIOS,
+};
+
+struct ov965x {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ enum v4l2_mbus_type bus_type;
+ int gpios[NUM_GPIOS];
+ /* External master clock frequency */
+ unsigned long mclk_frequency;
+
+ /* Protects the struct fields below */
+ struct mutex lock;
+
+ struct i2c_client *client;
+
+ /* Exposure row interval in us */
+ unsigned int exp_row_interval;
+
+ unsigned short id;
+ const struct ov965x_framesize *frame_size;
+ /* YUYV sequence (pixel format) control register */
+ u8 tslb_reg;
+ struct v4l2_mbus_framefmt format;
+
+ struct ov965x_ctrls ctrls;
+ /* Pointer to frame rate control data structure */
+ const struct ov965x_interval *fiv;
+
+ int streaming;
+ int power;
+
+ u8 apply_frame_fmt;
+};
+
+struct i2c_rv {
+ u8 addr;
+ u8 value;
+};
+
+static const struct i2c_rv ov965x_init_regs[] = {
+ { REG_COM2, 0x10 }, /* Set soft sleep mode */
+ { REG_COM5, 0x00 }, /* System clock options */
+ { REG_COM2, 0x01 }, /* Output drive, soft sleep mode */
+ { REG_COM10, 0x00 }, /* Slave mode, HREF vs HSYNC, signals negate */
+ { REG_EDGE, 0xa6 }, /* Edge enhancement treshhold and factor */
+ { REG_COM16, 0x02 }, /* Color matrix coeff double option */
+ { REG_COM17, 0x08 }, /* Single frame out, banding filter */
+ { 0x16, 0x06 },
+ { REG_CHLF, 0xc0 }, /* Reserved */
+ { 0x34, 0xbf },
+ { 0xa8, 0x80 },
+ { 0x96, 0x04 },
+ { 0x8e, 0x00 },
+ { REG_COM12, 0x77 }, /* HREF option, UV average */
+ { 0x8b, 0x06 },
+ { 0x35, 0x91 },
+ { 0x94, 0x88 },
+ { 0x95, 0x88 },
+ { REG_COM15, 0xc1 }, /* Output range, RGB 555/565 */
+ { REG_GRCOM, 0x2f }, /* Analog BLC & regulator */
+ { REG_COM6, 0x43 }, /* HREF & ADBLC options */
+ { REG_COM8, 0xe5 }, /* AGC/AEC options */
+ { REG_COM13, 0x90 }, /* Gamma selection, colour matrix, UV delay */
+ { REG_HV, 0x80 }, /* Manual banding filter MSB */
+ { 0x5c, 0x96 }, /* Reserved up to 0xa5 */
+ { 0x5d, 0x96 },
+ { 0x5e, 0x10 },
+ { 0x59, 0xeb },
+ { 0x5a, 0x9c },
+ { 0x5b, 0x55 },
+ { 0x43, 0xf0 },
+ { 0x44, 0x10 },
+ { 0x45, 0x55 },
+ { 0x46, 0x86 },
+ { 0x47, 0x64 },
+ { 0x48, 0x86 },
+ { 0x5f, 0xe0 },
+ { 0x60, 0x8c },
+ { 0x61, 0x20 },
+ { 0xa5, 0xd9 },
+ { 0xa4, 0x74 }, /* reserved */
+ { REG_COM23, 0x02 }, /* Color gain analog/_digital_ */
+ { REG_COM8, 0xe7 }, /* Enable AEC, AWB, AEC */
+ { REG_COM22, 0x23 }, /* Edge enhancement, denoising */
+ { 0xa9, 0xb8 },
+ { 0xaa, 0x92 },
+ { 0xab, 0x0a },
+ { REG_DBLC1, 0xdf }, /* Digital BLC */
+ { REG_DBLC_B, 0x00 }, /* Digital BLC B chan offset */
+ { REG_DBLC_R, 0x00 }, /* Digital BLC R chan offset */
+ { REG_DBLC_GB, 0x00 }, /* Digital BLC GB chan offset */
+ { REG_DBLC_GR, 0x00 },
+ { REG_COM9, 0x3a }, /* Gain ceiling 16x */
+ { REG_NULL, 0 }
+};
+
+#define NUM_FMT_REGS 14
+/*
+ * COM7, COM3, COM4, HSTART, HSTOP, HREF, VSTART, VSTOP, VREF,
+ * EXHCH, EXHCL, ADC, OCOM, OFON
+ */
+static const u8 frame_size_reg_addr[NUM_FMT_REGS] = {
+ 0x12, 0x0c, 0x0d, 0x17, 0x18, 0x32, 0x19, 0x1a, 0x03,
+ 0x2a, 0x2b, 0x37, 0x38, 0x39,
+};
+
+static const u8 ov965x_sxga_regs[NUM_FMT_REGS] = {
+ 0x00, 0x00, 0x00, 0x1e, 0xbe, 0xbf, 0x01, 0x81, 0x12,
+ 0x10, 0x34, 0x81, 0x93, 0x51,
+};
+
+static const u8 ov965x_vga_regs[NUM_FMT_REGS] = {
+ 0x40, 0x04, 0x80, 0x26, 0xc6, 0xed, 0x01, 0x3d, 0x00,
+ 0x10, 0x40, 0x91, 0x12, 0x43,
+};
+
+/* Determined empirically. */
+static const u8 ov965x_qvga_regs[NUM_FMT_REGS] = {
+ 0x10, 0x04, 0x80, 0x25, 0xc5, 0xbf, 0x00, 0x80, 0x12,
+ 0x10, 0x40, 0x91, 0x12, 0x43,
+};
+
+static const struct ov965x_framesize ov965x_framesizes[] = {
+ {
+ .width = SXGA_WIDTH,
+ .height = SXGA_HEIGHT,
+ .regs = ov965x_sxga_regs,
+ .max_exp_lines = 1048,
+ }, {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .regs = ov965x_vga_regs,
+ .max_exp_lines = 498,
+ }, {
+ .width = QVGA_WIDTH,
+ .height = QVGA_HEIGHT,
+ .regs = ov965x_qvga_regs,
+ .max_exp_lines = 248,
+ },
+};
+
+struct ov965x_pixfmt {
+ enum v4l2_mbus_pixelcode code;
+ u32 colorspace;
+ /* REG_TSLB value, only bits [3:2] may be set. */
+ u8 tslb_reg;
+};
+
+static const struct ov965x_pixfmt ov965x_formats[] = {
+ { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 0x00},
+ { V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG, 0x04},
+ { V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG, 0x0c},
+ { V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG, 0x08},
+};
+
+/*
+ * This table specifies possible frame resolution and interval
+ * combinations. Default CLKRC[5:0] divider values are valid
+ * only for 24 MHz external clock frequency.
+ */
+static struct ov965x_interval ov965x_intervals[] = {
+ {{ 100, 625 }, { SXGA_WIDTH, SXGA_HEIGHT }, 0 }, /* 6.25 fps */
+ {{ 10, 125 }, { VGA_WIDTH, VGA_HEIGHT }, 1 }, /* 12.5 fps */
+ {{ 10, 125 }, { QVGA_WIDTH, QVGA_HEIGHT }, 3 }, /* 12.5 fps */
+ {{ 1, 25 }, { VGA_WIDTH, VGA_HEIGHT }, 0 }, /* 25 fps */
+ {{ 1, 25 }, { QVGA_WIDTH, QVGA_HEIGHT }, 1 }, /* 25 fps */
+};
+
+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct ov965x, ctrls.handler)->sd;
+}
+
+static inline struct ov965x *to_ov965x(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ov965x, sd);
+}
+
+static int ov965x_read(struct i2c_client *client, u8 addr, u8 *val)
+{
+ u8 buf = addr;
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &buf
+ };
+ int ret;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret == 1) {
+ msg.flags = I2C_M_RD;
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ if (ret == 1)
+ *val = buf;
+ }
+
+ v4l2_dbg(2, debug, client, "%s: 0x%02x @ 0x%02x. (%d)\n",
+ __func__, *val, addr, ret);
+
+ return ret == 1 ? 0 : ret;
+}
+
+static int ov965x_write(struct i2c_client *client, u8 addr, u8 val)
+{
+ u8 buf[2] = { addr, val };
+
+ int ret = i2c_master_send(client, buf, 2);
+
+ v4l2_dbg(2, debug, client, "%s: 0x%02x @ 0x%02X (%d)\n",
+ __func__, val, addr, ret);
+
+ return ret == 2 ? 0 : ret;
+}
+
+static int ov965x_write_array(struct i2c_client *client,
+ const struct i2c_rv *regs)
+{
+ int i, ret = 0;
+
+ for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
+ ret = ov965x_write(client, regs[i].addr, regs[i].value);
+
+ return ret;
+}
+
+static int ov965x_set_default_gamma_curve(struct ov965x *ov965x)
+{
+ static const u8 gamma_curve[] = {
+ /* Values taken from OV application note. */
+ 0x40, 0x30, 0x4b, 0x60, 0x70, 0x70, 0x70, 0x70,
+ 0x60, 0x60, 0x50, 0x48, 0x3a, 0x2e, 0x28, 0x22,
+ 0x04, 0x07, 0x10, 0x28, 0x36, 0x44, 0x52, 0x60,
+ 0x6c, 0x78, 0x8c, 0x9e, 0xbb, 0xd2, 0xe6
+ };
+ u8 addr = REG_GSP;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(gamma_curve); i++) {
+ int ret = ov965x_write(ov965x->client, addr, gamma_curve[i]);
+ if (ret < 0)
+ return ret;
+ addr++;
+ }
+
+ return 0;
+};
+
+static int ov965x_set_color_matrix(struct ov965x *ov965x)
+{
+ static const u8 mtx[] = {
+ /* MTX1..MTX9, MTXS */
+ 0x3a, 0x3d, 0x03, 0x12, 0x26, 0x38, 0x40, 0x40, 0x40, 0x0d
+ };
+ u8 addr = REG_MTX(1);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(mtx); i++) {
+ int ret = ov965x_write(ov965x->client, addr, mtx[i]);
+ if (ret < 0)
+ return ret;
+ addr++;
+ }
+
+ return 0;
+}
+
+static void ov965x_gpio_set(int gpio, int val)
+{
+ if (gpio_is_valid(gpio))
+ gpio_set_value(gpio, val);
+}
+
+static void __ov965x_set_power(struct ov965x *ov965x, int on)
+{
+ if (on) {
+ ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 0);
+ ov965x_gpio_set(ov965x->gpios[GPIO_RST], 0);
+ usleep_range(25000, 26000);
+ } else {
+ ov965x_gpio_set(ov965x->gpios[GPIO_RST], 1);
+ ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 1);
+ }
+
+ ov965x->streaming = 0;
+}
+
+static int ov965x_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct ov965x *ov965x = to_ov965x(sd);
+ struct i2c_client *client = ov965x->client;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, client, "%s: on: %d\n", __func__, on);
+
+ mutex_lock(&ov965x->lock);
+ if (ov965x->power == !on) {
+ __ov965x_set_power(ov965x, on);
+ if (on) {
+ ret = ov965x_write_array(client,
+ ov965x_init_regs);
+ ov965x->apply_frame_fmt = 1;
+ ov965x->ctrls.update = 1;
+ }
+ }
+ if (!ret)
+ ov965x->power += on ? 1 : -1;
+
+ WARN_ON(ov965x->power < 0);
+ mutex_unlock(&ov965x->lock);
+ return ret;
+}
+
+/*
+ * V4L2 controls
+ */
+
+static void ov965x_update_exposure_ctrl(struct ov965x *ov965x)
+{
+ struct v4l2_ctrl *ctrl = ov965x->ctrls.exposure;
+ unsigned long fint, trow;
+ int min, max, def;
+ u8 clkrc;
+
+ mutex_lock(&ov965x->lock);
+ if (WARN_ON(!ctrl || !ov965x->frame_size)) {
+ mutex_unlock(&ov965x->lock);
+ return;
+ }
+ clkrc = DEF_CLKRC + ov965x->fiv->clkrc_div;
+ /* Calculate internal clock frequency */
+ fint = ov965x->mclk_frequency * ((clkrc >> 7) + 1) /
+ ((2 * ((clkrc & 0x3f) + 1)));
+ /* and the row interval (in us). */
+ trow = (2 * 1520 * 1000000UL) / fint;
+ max = ov965x->frame_size->max_exp_lines * trow;
+ ov965x->exp_row_interval = trow;
+ mutex_unlock(&ov965x->lock);
+
+ v4l2_dbg(1, debug, &ov965x->sd, "clkrc: %#x, fi: %lu, tr: %lu, %d\n",
+ clkrc, fint, trow, max);
+
+ /* Update exposure time range to match current frame format. */
+ min = (trow + 100) / 100;
+ max = (max - 100) / 100;
+ def = min + (max - min) / 2;
+
+ if (v4l2_ctrl_modify_range(ctrl, min, max, 1, def))
+ v4l2_err(&ov965x->sd, "Exposure ctrl range update failed\n");
+}
+
+static int ov965x_set_banding_filter(struct ov965x *ov965x, int value)
+{
+ unsigned long mbd, light_freq;
+ int ret;
+ u8 reg;
+
+ ret = ov965x_read(ov965x->client, REG_COM8, &reg);
+ if (!ret) {
+ if (value == V4L2_CID_POWER_LINE_FREQUENCY_DISABLED)
+ reg &= ~COM8_BFILT;
+ else
+ reg |= COM8_BFILT;
+ ret = ov965x_write(ov965x->client, REG_COM8, reg);
+ }
+ if (value == V4L2_CID_POWER_LINE_FREQUENCY_DISABLED)
+ return 0;
+ if (WARN_ON(ov965x->fiv == NULL))
+ return -EINVAL;
+ /* Set minimal exposure time for 50/60 HZ lighting */
+ if (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ)
+ light_freq = 50;
+ else
+ light_freq = 60;
+ mbd = (1000UL * ov965x->fiv->interval.denominator *
+ ov965x->frame_size->max_exp_lines) /
+ ov965x->fiv->interval.numerator;
+ mbd = ((mbd / (light_freq * 2)) + 500) / 1000UL;
+
+ return ov965x_write(ov965x->client, REG_MBD, mbd);
+}
+
+static int ov965x_set_white_balance(struct ov965x *ov965x, int awb)
+{
+ int ret;
+ u8 reg;
+
+ ret = ov965x_read(ov965x->client, REG_COM8, &reg);
+ if (!ret) {
+ reg = awb ? reg | REG_COM8 : reg & ~REG_COM8;
+ ret = ov965x_write(ov965x->client, REG_COM8, reg);
+ }
+ if (!ret && !awb) {
+ ret = ov965x_write(ov965x->client, REG_BLUE,
+ ov965x->ctrls.blue_balance->val);
+ if (ret < 0)
+ return ret;
+ ret = ov965x_write(ov965x->client, REG_RED,
+ ov965x->ctrls.red_balance->val);
+ }
+ return ret;
+}
+
+#define NUM_BR_LEVELS 7
+#define NUM_BR_REGS 3
+
+static int ov965x_set_brightness(struct ov965x *ov965x, int val)
+{
+ static const u8 regs[NUM_BR_LEVELS + 1][NUM_BR_REGS] = {
+ { REG_AEW, REG_AEB, REG_VPT },
+ { 0x1c, 0x12, 0x50 }, /* -3 */
+ { 0x3d, 0x30, 0x71 }, /* -2 */
+ { 0x50, 0x44, 0x92 }, /* -1 */
+ { 0x70, 0x64, 0xc3 }, /* 0 */
+ { 0x90, 0x84, 0xd4 }, /* +1 */
+ { 0xc4, 0xbf, 0xf9 }, /* +2 */
+ { 0xd8, 0xd0, 0xfa }, /* +3 */
+ };
+ int i, ret = 0;
+
+ val += (NUM_BR_LEVELS / 2 + 1);
+ if (val > NUM_BR_LEVELS)
+ return -EINVAL;
+
+ for (i = 0; i < NUM_BR_REGS && !ret; i++)
+ ret = ov965x_write(ov965x->client, regs[0][i],
+ regs[val][i]);
+ return ret;
+}
+
+static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain)
+{
+ struct i2c_client *client = ov965x->client;
+ struct ov965x_ctrls *ctrls = &ov965x->ctrls;
+ int ret = 0;
+ u8 reg;
+ /*
+ * For manual mode we need to disable AGC first, so
+ * gain value in REG_VREF, REG_GAIN is not overwritten.
+ */
+ if (ctrls->auto_gain->is_new) {
+ ret = ov965x_read(client, REG_COM8, &reg);
+ if (ret < 0)
+ return ret;
+ if (ctrls->auto_gain->val)
+ reg |= COM8_AGC;
+ else
+ reg &= ~COM8_AGC;
+ ret = ov965x_write(client, REG_COM8, reg);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (ctrls->gain->is_new && !auto_gain) {
+ unsigned int gain = ctrls->gain->val;
+ unsigned int rgain;
+ int m;
+ /*
+ * Convert gain control value to the sensor's gain
+ * registers (VREF[7:6], GAIN[7:0]) format.
+ */
+ for (m = 6; m >= 0; m--)
+ if (gain >= (1 << m) * 16)
+ break;
+ rgain = (gain - ((1 << m) * 16)) / (1 << m);
+ rgain |= (((1 << m) - 1) << 4);
+
+ ret = ov965x_write(client, REG_GAIN, rgain & 0xff);
+ if (ret < 0)
+ return ret;
+ ret = ov965x_read(client, REG_VREF, &reg);
+ if (ret < 0)
+ return ret;
+ reg &= ~VREF_GAIN_MASK;
+ reg |= (((rgain >> 8) & 0x3) << 6);
+ ret = ov965x_write(client, REG_VREF, reg);
+ if (ret < 0)
+ return ret;
+ /* Return updated control's value to userspace */
+ ctrls->gain->val = (1 << m) * (16 + (rgain & 0xf));
+ }
+
+ return ret;
+}
+
+static int ov965x_set_sharpness(struct ov965x *ov965x, unsigned int value)
+{
+ u8 com14, edge;
+ int ret;
+
+ ret = ov965x_read(ov965x->client, REG_COM14, &com14);
+ if (ret < 0)
+ return ret;
+ ret = ov965x_read(ov965x->client, REG_EDGE, &edge);
+ if (ret < 0)
+ return ret;
+ com14 = value ? com14 | COM14_EDGE_EN : com14 & ~COM14_EDGE_EN;
+ value--;
+ if (value > 0x0f) {
+ com14 |= COM14_EEF_X2;
+ value >>= 1;
+ } else {
+ com14 &= ~COM14_EEF_X2;
+ }
+ ret = ov965x_write(ov965x->client, REG_COM14, com14);
+ if (ret < 0)
+ return ret;
+
+ edge &= ~EDGE_FACTOR_MASK;
+ edge |= ((u8)value & 0x0f);
+
+ return ov965x_write(ov965x->client, REG_EDGE, edge);
+}
+
+static int ov965x_set_exposure(struct ov965x *ov965x, int exp)
+{
+ struct i2c_client *client = ov965x->client;
+ struct ov965x_ctrls *ctrls = &ov965x->ctrls;
+ bool auto_exposure = (exp == V4L2_EXPOSURE_AUTO);
+ int ret;
+ u8 reg;
+
+ if (ctrls->auto_exp->is_new) {
+ ret = ov965x_read(client, REG_COM8, &reg);
+ if (ret < 0)
+ return ret;
+ if (auto_exposure)
+ reg |= (COM8_AEC | COM8_AGC);
+ else
+ reg &= ~(COM8_AEC | COM8_AGC);
+ ret = ov965x_write(client, REG_COM8, reg);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (!auto_exposure && ctrls->exposure->is_new) {
+ unsigned int exposure = (ctrls->exposure->val * 100)
+ / ov965x->exp_row_interval;
+ /*
+ * Manual exposure value
+ * [b15:b0] - AECHM (b15:b10), AECH (b9:b2), COM1 (b1:b0)
+ */
+ ret = ov965x_write(client, REG_COM1, exposure & 0x3);
+ if (!ret)
+ ret = ov965x_write(client, REG_AECH,
+ (exposure >> 2) & 0xff);
+ if (!ret)
+ ret = ov965x_write(client, REG_AECHM,
+ (exposure >> 10) & 0x3f);
+ /* Update the value to minimize rounding errors */
+ ctrls->exposure->val = ((exposure * ov965x->exp_row_interval)
+ + 50) / 100;
+ if (ret < 0)
+ return ret;
+ }
+
+ v4l2_ctrl_activate(ov965x->ctrls.brightness, !exp);
+ return 0;
+}
+
+static int ov965x_set_flip(struct ov965x *ov965x)
+{
+ u8 mvfp = 0;
+
+ if (ov965x->ctrls.hflip->val)
+ mvfp |= MVFP_MIRROR;
+
+ if (ov965x->ctrls.vflip->val)
+ mvfp |= MVFP_FLIP;
+
+ return ov965x_write(ov965x->client, REG_MVFP, mvfp);
+}
+
+#define NUM_SAT_LEVELS 5
+#define NUM_SAT_REGS 6
+
+static int ov965x_set_saturation(struct ov965x *ov965x, int val)
+{
+ static const u8 regs[NUM_SAT_LEVELS][NUM_SAT_REGS] = {
+ /* MTX(1)...MTX(6) */
+ { 0x1d, 0x1f, 0x02, 0x09, 0x13, 0x1c }, /* -2 */
+ { 0x2e, 0x31, 0x02, 0x0e, 0x1e, 0x2d }, /* -1 */
+ { 0x3a, 0x3d, 0x03, 0x12, 0x26, 0x38 }, /* 0 */
+ { 0x46, 0x49, 0x04, 0x16, 0x2e, 0x43 }, /* +1 */
+ { 0x57, 0x5c, 0x05, 0x1b, 0x39, 0x54 }, /* +2 */
+ };
+ u8 addr = REG_MTX(1);
+ int i, ret = 0;
+
+ val += (NUM_SAT_LEVELS / 2);
+ if (val >= NUM_SAT_LEVELS)
+ return -EINVAL;
+
+ for (i = 0; i < NUM_SAT_REGS && !ret; i++)
+ ret = ov965x_write(ov965x->client, addr + i, regs[val][i]);
+
+ return ret;
+}
+
+static int ov965x_set_test_pattern(struct ov965x *ov965x, int value)
+{
+ int ret;
+ u8 reg;
+
+ ret = ov965x_read(ov965x->client, REG_COM23, &reg);
+ if (ret < 0)
+ return ret;
+ reg = value ? reg | COM23_TEST_MODE : reg & ~COM23_TEST_MODE;
+ return ov965x_write(ov965x->client, REG_COM23, reg);
+}
+
+static int __g_volatile_ctrl(struct ov965x *ov965x, struct v4l2_ctrl *ctrl)
+{
+ struct i2c_client *client = ov965x->client;
+ unsigned int exposure, gain, m;
+ u8 reg0, reg1, reg2;
+ int ret;
+
+ if (!ov965x->power)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ if (!ctrl->val)
+ return 0;
+ ret = ov965x_read(client, REG_GAIN, &reg0);
+ if (ret < 0)
+ return ret;
+ ret = ov965x_read(client, REG_VREF, &reg1);
+ if (ret < 0)
+ return ret;
+ gain = ((reg1 >> 6) << 8) | reg0;
+ m = 0x01 << fls(gain >> 4);
+ ov965x->ctrls.gain->val = m * (16 + (gain & 0xf));
+ break;
+
+ case V4L2_CID_EXPOSURE_AUTO:
+ if (ctrl->val == V4L2_EXPOSURE_MANUAL)
+ return 0;
+ ret = ov965x_read(client, REG_COM1, &reg0);
+ if (!ret)
+ ret = ov965x_read(client, REG_AECH, &reg1);
+ if (!ret)
+ ret = ov965x_read(client, REG_AECHM, &reg2);
+ if (ret < 0)
+ return ret;
+ exposure = ((reg2 & 0x3f) << 10) | (reg1 << 2) |
+ (reg0 & 0x3);
+ ov965x->ctrls.exposure->val = ((exposure *
+ ov965x->exp_row_interval) + 50) / 100;
+ break;
+ }
+
+ return 0;
+}
+
+static int ov965x_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+ struct ov965x *ov965x = to_ov965x(sd);
+ int ret;
+
+ v4l2_dbg(1, debug, sd, "g_ctrl: %s\n", ctrl->name);
+
+ mutex_lock(&ov965x->lock);
+ ret = __g_volatile_ctrl(ov965x, ctrl);
+ mutex_unlock(&ov965x->lock);
+ return ret;
+}
+
+static int ov965x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+ struct ov965x *ov965x = to_ov965x(sd);
+ int ret = -EINVAL;
+
+ v4l2_dbg(1, debug, sd, "s_ctrl: %s, value: %d. power: %d\n",
+ ctrl->name, ctrl->val, ov965x->power);
+
+ mutex_lock(&ov965x->lock);
+ /*
+ * If the device is not powered up now postpone applying control's
+ * value to the hardware, until it is ready to accept commands.
+ */
+ if (ov965x->power == 0) {
+ mutex_unlock(&ov965x->lock);
+ return 0;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = ov965x_set_white_balance(ov965x, ctrl->val);
+ break;
+
+ case V4L2_CID_BRIGHTNESS:
+ ret = ov965x_set_brightness(ov965x, ctrl->val);
+ break;
+
+ case V4L2_CID_EXPOSURE_AUTO:
+ ret = ov965x_set_exposure(ov965x, ctrl->val);
+ break;
+
+ case V4L2_CID_AUTOGAIN:
+ ret = ov965x_set_gain(ov965x, ctrl->val);
+ break;
+
+ case V4L2_CID_HFLIP:
+ ret = ov965x_set_flip(ov965x);
+ break;
+
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ ret = ov965x_set_banding_filter(ov965x, ctrl->val);
+ break;
+
+ case V4L2_CID_SATURATION:
+ ret = ov965x_set_saturation(ov965x, ctrl->val);
+ break;
+
+ case V4L2_CID_SHARPNESS:
+ ret = ov965x_set_sharpness(ov965x, ctrl->val);
+ break;
+
+ case V4L2_CID_TEST_PATTERN:
+ ret = ov965x_set_test_pattern(ov965x, ctrl->val);
+ break;
+ }
+
+ mutex_unlock(&ov965x->lock);
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov965x_ctrl_ops = {
+ .g_volatile_ctrl = ov965x_g_volatile_ctrl,
+ .s_ctrl = ov965x_s_ctrl,
+};
+
+static const char * const test_pattern_menu[] = {
+ "Disabled",
+ "Color bars",
+ NULL
+};
+
+static int ov965x_initialize_controls(struct ov965x *ov965x)
+{
+ const struct v4l2_ctrl_ops *ops = &ov965x_ctrl_ops;
+ struct ov965x_ctrls *ctrls = &ov965x->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+ int ret;
+
+ ret = v4l2_ctrl_handler_init(hdl, 16);
+ if (ret < 0)
+ return ret;
+
+ /* Auto/manual white balance */
+ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 1);
+ ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
+ 0, 0xff, 1, 0x80);
+ ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
+ 0, 0xff, 1, 0x80);
+ /* Auto/manual exposure */
+ ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
+ V4L2_CID_EXPOSURE_AUTO,
+ V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
+ /* Exposure time, in 100 us units. min/max is updated dynamically. */
+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_EXPOSURE_ABSOLUTE,
+ 2, 1500, 1, 500);
+ /* Auto/manual gain */
+ ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
+ 0, 1, 1, 1);
+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
+ 16, 64 * (16 + 15), 1, 64 * 16);
+
+ ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
+ -2, 2, 1, 0);
+ ctrls->brightness = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS,
+ -3, 3, 1, 0);
+ ctrls->sharpness = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS,
+ 0, 32, 1, 6);
+
+ ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+ ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ ctrls->light_freq = v4l2_ctrl_new_std_menu(hdl, ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, ~0x7,
+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
+
+ v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(test_pattern_menu) - 1, 0, 0,
+ test_pattern_menu);
+ if (hdl->error) {
+ ret = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+ }
+
+ ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_gain, 0, true);
+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 1, true);
+ v4l2_ctrl_cluster(2, &ctrls->hflip);
+
+ ov965x->sd.ctrl_handler = hdl;
+ return 0;
+}
+
+/*
+ * V4L2 subdev video and pad level operations
+ */
+static void ov965x_get_default_format(struct v4l2_mbus_framefmt *mf)
+{
+ mf->width = ov965x_framesizes[0].width;
+ mf->height = ov965x_framesizes[0].height;
+ mf->colorspace = ov965x_formats[0].colorspace;
+ mf->code = ov965x_formats[0].code;
+ mf->field = V4L2_FIELD_NONE;
+}
+
+static int ov965x_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(ov965x_formats))
+ return -EINVAL;
+
+ code->code = ov965x_formats[code->index].code;
+ return 0;
+}
+
+static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ int i = ARRAY_SIZE(ov965x_formats);
+
+ if (fse->index > ARRAY_SIZE(ov965x_framesizes))
+ return -EINVAL;
+
+ while (--i)
+ if (fse->code == ov965x_formats[i].code)
+ break;
+
+ fse->code = ov965x_formats[i].code;
+
+ fse->min_width = ov965x_framesizes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->max_height = ov965x_framesizes[fse->index].height;
+ fse->min_height = fse->max_height;
+
+ return 0;
+}
+
+static int ov965x_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct ov965x *ov965x = to_ov965x(sd);
+
+ mutex_lock(&ov965x->lock);
+ fi->interval = ov965x->fiv->interval;
+ mutex_unlock(&ov965x->lock);
+
+ return 0;
+}
+
+static int __ov965x_set_frame_interval(struct ov965x *ov965x,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct v4l2_mbus_framefmt *mbus_fmt = &ov965x->format;
+ const struct ov965x_interval *fiv = &ov965x_intervals[0];
+ u64 req_int, err, min_err = ~0ULL;
+ unsigned int i;
+
+
+ if (fi->interval.denominator == 0)
+ return -EINVAL;
+
+ req_int = (u64)(fi->interval.numerator * 10000) /
+ fi->interval.denominator;
+
+ for (i = 0; i < ARRAY_SIZE(ov965x_intervals); i++) {
+ const struct ov965x_interval *iv = &ov965x_intervals[i];
+
+ if (mbus_fmt->width != iv->size.width ||
+ mbus_fmt->height != iv->size.height)
+ continue;
+ err = abs64((u64)(iv->interval.numerator * 10000) /
+ iv->interval.denominator - req_int);
+ if (err < min_err) {
+ fiv = iv;
+ min_err = err;
+ }
+ }
+ ov965x->fiv = fiv;
+
+ v4l2_dbg(1, debug, &ov965x->sd, "Changed frame interval to %u us\n",
+ fiv->interval.numerator * 1000000 / fiv->interval.denominator);
+
+ return 0;
+}
+
+static int ov965x_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct ov965x *ov965x = to_ov965x(sd);
+ int ret;
+
+ v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n",
+ fi->interval.numerator, fi->interval.denominator);
+
+ mutex_lock(&ov965x->lock);
+ ret = __ov965x_set_frame_interval(ov965x, fi);
+ ov965x->apply_frame_fmt = 1;
+ mutex_unlock(&ov965x->lock);
+ return ret;
+}
+
+static int ov965x_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov965x *ov965x = to_ov965x(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(fh, 0);
+ fmt->format = *mf;
+ return 0;
+ }
+
+ mutex_lock(&ov965x->lock);
+ fmt->format = ov965x->format;
+ mutex_unlock(&ov965x->lock);
+
+ return 0;
+}
+
+static void __ov965x_try_frame_size(struct v4l2_mbus_framefmt *mf,
+ const struct ov965x_framesize **size)
+{
+ const struct ov965x_framesize *fsize = &ov965x_framesizes[0],
+ *match = NULL;
+ int i = ARRAY_SIZE(ov965x_framesizes);
+ unsigned int min_err = UINT_MAX;
+
+ while (i--) {
+ int err = abs(fsize->width - mf->width)
+ + abs(fsize->height - mf->height);
+ if (err < min_err) {
+ min_err = err;
+ match = fsize;
+ }
+ fsize++;
+ }
+ if (!match)
+ match = &ov965x_framesizes[0];
+ mf->width = match->width;
+ mf->height = match->height;
+ if (size)
+ *size = match;
+}
+
+static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ unsigned int index = ARRAY_SIZE(ov965x_formats);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+ struct ov965x *ov965x = to_ov965x(sd);
+ const struct ov965x_framesize *size = NULL;
+ int ret = 0;
+
+ __ov965x_try_frame_size(mf, &size);
+
+ while (--index)
+ if (ov965x_formats[index].code == mf->code)
+ break;
+
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ mf->code = ov965x_formats[index].code;
+ mf->field = V4L2_FIELD_NONE;
+
+ mutex_lock(&ov965x->lock);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ if (fh != NULL) {
+ mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ *mf = fmt->format;
+ }
+ } else {
+ if (ov965x->streaming) {
+ ret = -EBUSY;
+ } else {
+ ov965x->frame_size = size;
+ ov965x->format = fmt->format;
+ ov965x->tslb_reg = ov965x_formats[index].tslb_reg;
+ ov965x->apply_frame_fmt = 1;
+ }
+ }
+
+ if (!ret && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ struct v4l2_subdev_frame_interval fiv = {
+ .interval = { 0, 1 }
+ };
+ /* Reset to minimum possible frame interval */
+ __ov965x_set_frame_interval(ov965x, &fiv);
+ }
+ mutex_unlock(&ov965x->lock);
+
+ if (!ret)
+ ov965x_update_exposure_ctrl(ov965x);
+
+ return ret;
+}
+
+static int ov965x_set_frame_size(struct ov965x *ov965x)
+{
+ int i, ret = 0;
+
+ for (i = 0; ret == 0 && i < NUM_FMT_REGS; i++)
+ ret = ov965x_write(ov965x->client, frame_size_reg_addr[i],
+ ov965x->frame_size->regs[i]);
+ return ret;
+}
+
+static int __ov965x_set_params(struct ov965x *ov965x)
+{
+ struct i2c_client *client = ov965x->client;
+ struct ov965x_ctrls *ctrls = &ov965x->ctrls;
+ int ret = 0;
+ u8 reg;
+
+ if (ov965x->apply_frame_fmt) {
+ reg = DEF_CLKRC + ov965x->fiv->clkrc_div;
+ ret = ov965x_write(client, REG_CLKRC, reg);
+ if (ret < 0)
+ return ret;
+ ret = ov965x_set_frame_size(ov965x);
+ if (ret < 0)
+ return ret;
+ ret = ov965x_read(client, REG_TSLB, &reg);
+ if (ret < 0)
+ return ret;
+ reg &= ~TSLB_YUYV_MASK;
+ reg |= ov965x->tslb_reg;
+ ret = ov965x_write(client, REG_TSLB, reg);
+ if (ret < 0)
+ return ret;
+ }
+ ret = ov965x_set_default_gamma_curve(ov965x);
+ if (ret < 0)
+ return ret;
+ ret = ov965x_set_color_matrix(ov965x);
+ if (ret < 0)
+ return ret;
+ /*
+ * Select manual banding filter, the filter will
+ * be enabled further if required.
+ */
+ ret = ov965x_read(client, REG_COM11, &reg);
+ if (!ret)
+ reg |= COM11_BANDING;
+ ret = ov965x_write(client, REG_COM11, reg);
+ if (ret < 0)
+ return ret;
+ /*
+ * Banding filter (REG_MBD value) needs to match selected
+ * resolution and frame rate, so it's always updated here.
+ */
+ return ov965x_set_banding_filter(ov965x, ctrls->light_freq->val);
+}
+
+static int ov965x_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov965x *ov965x = to_ov965x(sd);
+ struct ov965x_ctrls *ctrls = &ov965x->ctrls;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, client, "%s: on: %d\n", __func__, on);
+
+ mutex_lock(&ov965x->lock);
+ if (ov965x->streaming == !on) {
+ if (on)
+ ret = __ov965x_set_params(ov965x);
+
+ if (!ret && ctrls->update) {
+ /*
+ * ov965x_s_ctrl callback takes the mutex
+ * so it needs to be released here.
+ */
+ mutex_unlock(&ov965x->lock);
+ ret = v4l2_ctrl_handler_setup(&ctrls->handler);
+
+ mutex_lock(&ov965x->lock);
+ if (!ret)
+ ctrls->update = 0;
+ }
+ if (!ret)
+ ret = ov965x_write(client, REG_COM2,
+ on ? 0x01 : 0x11);
+ }
+ if (!ret)
+ ov965x->streaming += on ? 1 : -1;
+
+ WARN_ON(ov965x->streaming < 0);
+ mutex_unlock(&ov965x->lock);
+
+ return ret;
+}
+
+/*
+ * V4L2 subdev internal operations
+ */
+static int ov965x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0);
+
+ ov965x_get_default_format(mf);
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops ov965x_pad_ops = {
+ .enum_mbus_code = ov965x_enum_mbus_code,
+ .enum_frame_size = ov965x_enum_frame_sizes,
+ .get_fmt = ov965x_get_fmt,
+ .set_fmt = ov965x_set_fmt,
+};
+
+static const struct v4l2_subdev_video_ops ov965x_video_ops = {
+ .s_stream = ov965x_s_stream,
+ .g_frame_interval = ov965x_g_frame_interval,
+ .s_frame_interval = ov965x_s_frame_interval,
+
+};
+
+static const struct v4l2_subdev_internal_ops ov965x_sd_internal_ops = {
+ .open = ov965x_open,
+};
+
+static const struct v4l2_subdev_core_ops ov965x_core_ops = {
+ .s_power = ov965x_s_power,
+ .log_status = v4l2_ctrl_subdev_log_status,
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_ops ov965x_subdev_ops = {
+ .core = &ov965x_core_ops,
+ .pad = &ov965x_pad_ops,
+ .video = &ov965x_video_ops,
+};
+
+/*
+ * Reset and power down GPIOs configuration
+ */
+static int ov965x_configure_gpios(struct ov965x *ov965x,
+ const struct ov9650_platform_data *pdata)
+{
+ int ret, i;
+
+ ov965x->gpios[GPIO_PWDN] = pdata->gpio_pwdn;
+ ov965x->gpios[GPIO_RST] = pdata->gpio_reset;
+
+ for (i = 0; i < ARRAY_SIZE(ov965x->gpios); i++) {
+ int gpio = ov965x->gpios[i];
+
+ if (!gpio_is_valid(gpio))
+ continue;
+ ret = devm_gpio_request_one(&ov965x->client->dev, gpio,
+ GPIOF_OUT_INIT_HIGH, "OV965X");
+ if (ret < 0)
+ return ret;
+ v4l2_dbg(1, debug, &ov965x->sd, "set gpio %d to 1\n", gpio);
+
+ gpio_set_value(gpio, 1);
+ gpio_export(gpio, 0);
+ ov965x->gpios[i] = gpio;
+ }
+
+ return 0;
+}
+
+static int ov965x_detect_sensor(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov965x *ov965x = to_ov965x(sd);
+ u8 pid, ver;
+ int ret;
+
+ mutex_lock(&ov965x->lock);
+ __ov965x_set_power(ov965x, 1);
+ usleep_range(25000, 26000);
+
+ /* Check sensor revision */
+ ret = ov965x_read(client, REG_PID, &pid);
+ if (!ret)
+ ret = ov965x_read(client, REG_VER, &ver);
+
+ __ov965x_set_power(ov965x, 0);
+
+ if (!ret) {
+ ov965x->id = OV965X_ID(pid, ver);
+ if (ov965x->id == OV9650_ID || ov965x->id == OV9652_ID) {
+ v4l2_info(sd, "Found OV%04X sensor\n", ov965x->id);
+ } else {
+ v4l2_err(sd, "Sensor detection failed (%04X, %d)\n",
+ ov965x->id, ret);
+ ret = -ENODEV;
+ }
+ }
+ mutex_unlock(&ov965x->lock);
+
+ return ret;
+}
+
+static int ov965x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct ov9650_platform_data *pdata = client->dev.platform_data;
+ struct v4l2_subdev *sd;
+ struct ov965x *ov965x;
+ int ret;
+
+ if (pdata == NULL) {
+ dev_err(&client->dev, "platform data not specified\n");
+ return -EINVAL;
+ }
+
+ if (pdata->mclk_frequency == 0) {
+ dev_err(&client->dev, "MCLK frequency not specified\n");
+ return -EINVAL;
+ }
+
+ ov965x = devm_kzalloc(&client->dev, sizeof(*ov965x), GFP_KERNEL);
+ if (!ov965x)
+ return -ENOMEM;
+
+ mutex_init(&ov965x->lock);
+ ov965x->client = client;
+ ov965x->mclk_frequency = pdata->mclk_frequency;
+
+ sd = &ov965x->sd;
+ v4l2_i2c_subdev_init(sd, client, &ov965x_subdev_ops);
+ strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
+
+ sd->internal_ops = &ov965x_sd_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+
+ ret = ov965x_configure_gpios(ov965x, pdata);
+ if (ret < 0)
+ return ret;
+
+ ov965x->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+ ret = media_entity_init(&sd->entity, 1, &ov965x->pad, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = ov965x_initialize_controls(ov965x);
+ if (ret < 0)
+ goto err_me;
+
+ ov965x_get_default_format(&ov965x->format);
+ ov965x->frame_size = &ov965x_framesizes[0];
+ ov965x->fiv = &ov965x_intervals[0];
+
+ ret = ov965x_detect_sensor(sd);
+ if (ret < 0)
+ goto err_ctrls;
+
+ /* Update exposure time min/max to match frame format */
+ ov965x_update_exposure_ctrl(ov965x);
+
+ return 0;
+err_ctrls:
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+err_me:
+ media_entity_cleanup(&sd->entity);
+ return ret;
+}
+
+static int ov965x_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+ media_entity_cleanup(&sd->entity);
+
+ return 0;
+}
+
+static const struct i2c_device_id ov965x_id[] = {
+ { "OV9650", 0 },
+ { "OV9652", 0 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, ov965x_id);
+
+static struct i2c_driver ov965x_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = ov965x_probe,
+ .remove = ov965x_remove,
+ .id_table = ov965x_id,
+};
+
+module_i2c_driver(ov965x_i2c_driver);
+
+MODULE_AUTHOR("Sylwester Nawrocki <sylvester.nawrocki@gmail.com>");
+MODULE_DESCRIPTION("OV9650/OV9652 CMOS Image Sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/s5c73m3/Makefile b/drivers/media/i2c/s5c73m3/Makefile
new file mode 100644
index 000000000000..fa4df342d1f1
--- /dev/null
+++ b/drivers/media/i2c/s5c73m3/Makefile
@@ -0,0 +1,2 @@
+s5c73m3-objs := s5c73m3-core.o s5c73m3-spi.o s5c73m3-ctrls.o
+obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3.o
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
new file mode 100644
index 000000000000..5dbb65e1f6b7
--- /dev/null
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -0,0 +1,1704 @@
+/*
+ * Samsung LSI S5C73M3 8M pixel camera driver
+ *
+ * Copyright (C) 2012, Samsung Electronics, Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Andrzej Hajda <a.hajda@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/sizes.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/media.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/videodev2.h>
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5c73m3.h>
+
+#include "s5c73m3.h"
+
+int s5c73m3_dbg;
+module_param_named(debug, s5c73m3_dbg, int, 0644);
+
+static int boot_from_rom = 1;
+module_param(boot_from_rom, int, 0644);
+
+static int update_fw;
+module_param(update_fw, int, 0644);
+
+#define S5C73M3_EMBEDDED_DATA_MAXLEN SZ_4K
+
+static const char * const s5c73m3_supply_names[S5C73M3_MAX_SUPPLIES] = {
+ "vdd-int", /* Digital Core supply (1.2V), CAM_ISP_CORE_1.2V */
+ "vdda", /* Analog Core supply (1.2V), CAM_SENSOR_CORE_1.2V */
+ "vdd-reg", /* Regulator input supply (2.8V), CAM_SENSOR_A2.8V */
+ "vddio-host", /* Digital Host I/O power supply (1.8V...2.8V),
+ CAM_ISP_SENSOR_1.8V */
+ "vddio-cis", /* Digital CIS I/O power (1.2V...1.8V),
+ CAM_ISP_MIPI_1.2V */
+ "vdd-af", /* Lens, CAM_AF_2.8V */
+};
+
+static const struct s5c73m3_frame_size s5c73m3_isp_resolutions[] = {
+ { 320, 240, COMM_CHG_MODE_YUV_320_240 },
+ { 352, 288, COMM_CHG_MODE_YUV_352_288 },
+ { 640, 480, COMM_CHG_MODE_YUV_640_480 },
+ { 880, 720, COMM_CHG_MODE_YUV_880_720 },
+ { 960, 720, COMM_CHG_MODE_YUV_960_720 },
+ { 1008, 672, COMM_CHG_MODE_YUV_1008_672 },
+ { 1184, 666, COMM_CHG_MODE_YUV_1184_666 },
+ { 1280, 720, COMM_CHG_MODE_YUV_1280_720 },
+ { 1536, 864, COMM_CHG_MODE_YUV_1536_864 },
+ { 1600, 1200, COMM_CHG_MODE_YUV_1600_1200 },
+ { 1632, 1224, COMM_CHG_MODE_YUV_1632_1224 },
+ { 1920, 1080, COMM_CHG_MODE_YUV_1920_1080 },
+ { 1920, 1440, COMM_CHG_MODE_YUV_1920_1440 },
+ { 2304, 1296, COMM_CHG_MODE_YUV_2304_1296 },
+ { 3264, 2448, COMM_CHG_MODE_YUV_3264_2448 },
+};
+
+static const struct s5c73m3_frame_size s5c73m3_jpeg_resolutions[] = {
+ { 640, 480, COMM_CHG_MODE_JPEG_640_480 },
+ { 800, 450, COMM_CHG_MODE_JPEG_800_450 },
+ { 800, 600, COMM_CHG_MODE_JPEG_800_600 },
+ { 1024, 768, COMM_CHG_MODE_JPEG_1024_768 },
+ { 1280, 720, COMM_CHG_MODE_JPEG_1280_720 },
+ { 1280, 960, COMM_CHG_MODE_JPEG_1280_960 },
+ { 1600, 900, COMM_CHG_MODE_JPEG_1600_900 },
+ { 1600, 1200, COMM_CHG_MODE_JPEG_1600_1200 },
+ { 2048, 1152, COMM_CHG_MODE_JPEG_2048_1152 },
+ { 2048, 1536, COMM_CHG_MODE_JPEG_2048_1536 },
+ { 2560, 1440, COMM_CHG_MODE_JPEG_2560_1440 },
+ { 2560, 1920, COMM_CHG_MODE_JPEG_2560_1920 },
+ { 3264, 1836, COMM_CHG_MODE_JPEG_3264_1836 },
+ { 3264, 2176, COMM_CHG_MODE_JPEG_3264_2176 },
+ { 3264, 2448, COMM_CHG_MODE_JPEG_3264_2448 },
+};
+
+static const struct s5c73m3_frame_size * const s5c73m3_resolutions[] = {
+ [RES_ISP] = s5c73m3_isp_resolutions,
+ [RES_JPEG] = s5c73m3_jpeg_resolutions
+};
+
+static const int s5c73m3_resolutions_len[] = {
+ [RES_ISP] = ARRAY_SIZE(s5c73m3_isp_resolutions),
+ [RES_JPEG] = ARRAY_SIZE(s5c73m3_jpeg_resolutions)
+};
+
+static const struct s5c73m3_interval s5c73m3_intervals[] = {
+ { COMM_FRAME_RATE_FIXED_7FPS, {142857, 1000000}, {3264, 2448} },
+ { COMM_FRAME_RATE_FIXED_15FPS, {66667, 1000000}, {3264, 2448} },
+ { COMM_FRAME_RATE_FIXED_20FPS, {50000, 1000000}, {2304, 1296} },
+ { COMM_FRAME_RATE_FIXED_30FPS, {33333, 1000000}, {2304, 1296} },
+};
+
+#define S5C73M3_DEFAULT_FRAME_INTERVAL 3 /* 30 fps */
+
+static void s5c73m3_fill_mbus_fmt(struct v4l2_mbus_framefmt *mf,
+ const struct s5c73m3_frame_size *fs,
+ u32 code)
+{
+ mf->width = fs->width;
+ mf->height = fs->height;
+ mf->code = code;
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ mf->field = V4L2_FIELD_NONE;
+}
+
+static int s5c73m3_i2c_write(struct i2c_client *client, u16 addr, u16 data)
+{
+ u8 buf[4] = { addr >> 8, addr & 0xff, data >> 8, data & 0xff };
+
+ int ret = i2c_master_send(client, buf, sizeof(buf));
+
+ v4l_dbg(4, s5c73m3_dbg, client, "%s: addr 0x%04x, data 0x%04x\n",
+ __func__, addr, data);
+
+ if (ret == 4)
+ return 0;
+
+ return ret < 0 ? ret : -EREMOTEIO;
+}
+
+static int s5c73m3_i2c_read(struct i2c_client *client, u16 addr, u16 *data)
+{
+ int ret;
+ u8 rbuf[2], wbuf[2] = { addr >> 8, addr & 0xff };
+ struct i2c_msg msg[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = sizeof(wbuf),
+ .buf = wbuf
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = sizeof(rbuf),
+ .buf = rbuf
+ }
+ };
+ /*
+ * Issue repeated START after writing 2 address bytes and
+ * just one STOP only after reading the data bytes.
+ */
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret == 2) {
+ *data = be16_to_cpup((u16 *)rbuf);
+ v4l2_dbg(4, s5c73m3_dbg, client,
+ "%s: addr: 0x%04x, data: 0x%04x\n",
+ __func__, addr, *data);
+ return 0;
+ }
+
+ v4l2_err(client, "I2C read failed: addr: %04x, (%d)\n", addr, ret);
+
+ return ret >= 0 ? -EREMOTEIO : ret;
+}
+
+int s5c73m3_write(struct s5c73m3 *state, u32 addr, u16 data)
+{
+ struct i2c_client *client = state->i2c_client;
+ int ret;
+
+ if ((addr ^ state->i2c_write_address) & 0xffff0000) {
+ ret = s5c73m3_i2c_write(client, REG_CMDWR_ADDRH, addr >> 16);
+ if (ret < 0) {
+ state->i2c_write_address = 0;
+ return ret;
+ }
+ }
+
+ if ((addr ^ state->i2c_write_address) & 0xffff) {
+ ret = s5c73m3_i2c_write(client, REG_CMDWR_ADDRL, addr & 0xffff);
+ if (ret < 0) {
+ state->i2c_write_address = 0;
+ return ret;
+ }
+ }
+
+ state->i2c_write_address = addr;
+
+ ret = s5c73m3_i2c_write(client, REG_CMDBUF_ADDR, data);
+ if (ret < 0)
+ return ret;
+
+ state->i2c_write_address += 2;
+
+ return ret;
+}
+
+int s5c73m3_read(struct s5c73m3 *state, u32 addr, u16 *data)
+{
+ struct i2c_client *client = state->i2c_client;
+ int ret;
+
+ if ((addr ^ state->i2c_read_address) & 0xffff0000) {
+ ret = s5c73m3_i2c_write(client, REG_CMDRD_ADDRH, addr >> 16);
+ if (ret < 0) {
+ state->i2c_read_address = 0;
+ return ret;
+ }
+ }
+
+ if ((addr ^ state->i2c_read_address) & 0xffff) {
+ ret = s5c73m3_i2c_write(client, REG_CMDRD_ADDRL, addr & 0xffff);
+ if (ret < 0) {
+ state->i2c_read_address = 0;
+ return ret;
+ }
+ }
+
+ state->i2c_read_address = addr;
+
+ ret = s5c73m3_i2c_read(client, REG_CMDBUF_ADDR, data);
+ if (ret < 0)
+ return ret;
+
+ state->i2c_read_address += 2;
+
+ return ret;
+}
+
+static int s5c73m3_check_status(struct s5c73m3 *state, unsigned int value)
+{
+ unsigned long start = jiffies;
+ unsigned long end = start + msecs_to_jiffies(2000);
+ int ret = 0;
+ u16 status;
+ int count = 0;
+
+ while (time_is_after_jiffies(end)) {
+ ret = s5c73m3_read(state, REG_STATUS, &status);
+ if (ret < 0 || status == value)
+ break;
+ usleep_range(500, 1000);
+ ++count;
+ }
+
+ if (count > 0)
+ v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd,
+ "status check took %dms\n",
+ jiffies_to_msecs(jiffies - start));
+
+ if (ret == 0 && status != value) {
+ u16 i2c_status = 0;
+ u16 i2c_seq_status = 0;
+
+ s5c73m3_read(state, REG_I2C_STATUS, &i2c_status);
+ s5c73m3_read(state, REG_I2C_SEQ_STATUS, &i2c_seq_status);
+
+ v4l2_err(&state->sensor_sd,
+ "wrong status %#x, expected: %#x, i2c_status: %#x/%#x\n",
+ status, value, i2c_status, i2c_seq_status);
+
+ return -ETIMEDOUT;
+ }
+
+ return ret;
+}
+
+int s5c73m3_isp_command(struct s5c73m3 *state, u16 command, u16 data)
+{
+ int ret;
+
+ ret = s5c73m3_check_status(state, REG_STATUS_ISP_COMMAND_COMPLETED);
+ if (ret < 0)
+ return ret;
+
+ ret = s5c73m3_write(state, 0x00095000, command);
+ if (ret < 0)
+ return ret;
+
+ ret = s5c73m3_write(state, 0x00095002, data);
+ if (ret < 0)
+ return ret;
+
+ return s5c73m3_write(state, REG_STATUS, 0x0001);
+}
+
+static int s5c73m3_isp_comm_result(struct s5c73m3 *state, u16 command,
+ u16 *data)
+{
+ return s5c73m3_read(state, COMM_RESULT_OFFSET + command, data);
+}
+
+static int s5c73m3_set_af_softlanding(struct s5c73m3 *state)
+{
+ unsigned long start = jiffies;
+ u16 af_softlanding;
+ int count = 0;
+ int ret;
+ const char *msg;
+
+ ret = s5c73m3_isp_command(state, COMM_AF_SOFTLANDING,
+ COMM_AF_SOFTLANDING_ON);
+ if (ret < 0) {
+ v4l2_info(&state->sensor_sd, "AF soft-landing failed\n");
+ return ret;
+ }
+
+ for (;;) {
+ ret = s5c73m3_isp_comm_result(state, COMM_AF_SOFTLANDING,
+ &af_softlanding);
+ if (ret < 0) {
+ msg = "failed";
+ break;
+ }
+ if (af_softlanding == COMM_AF_SOFTLANDING_RES_COMPLETE) {
+ msg = "succeeded";
+ break;
+ }
+ if (++count > 100) {
+ ret = -ETIME;
+ msg = "timed out";
+ break;
+ }
+ msleep(25);
+ }
+
+ v4l2_info(&state->sensor_sd, "AF soft-landing %s after %dms\n",
+ msg, jiffies_to_msecs(jiffies - start));
+
+ return ret;
+}
+
+static int s5c73m3_load_fw(struct v4l2_subdev *sd)
+{
+ struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
+ struct i2c_client *client = state->i2c_client;
+ const struct firmware *fw;
+ int ret;
+ char fw_name[20];
+
+ snprintf(fw_name, sizeof(fw_name), "SlimISP_%.2s.bin",
+ state->fw_file_version);
+ ret = request_firmware(&fw, fw_name, &client->dev);
+ if (ret < 0) {
+ v4l2_err(sd, "Firmware request failed (%s)\n", fw_name);
+ return -EINVAL;
+ }
+
+ v4l2_info(sd, "Loading firmware (%s, %d B)\n", fw_name, fw->size);
+
+ ret = s5c73m3_spi_write(state, fw->data, fw->size, 64);
+
+ if (ret >= 0)
+ state->isp_ready = 1;
+ else
+ v4l2_err(sd, "SPI write failed\n");
+
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int s5c73m3_set_frame_size(struct s5c73m3 *state)
+{
+ const struct s5c73m3_frame_size *prev_size =
+ state->sensor_pix_size[RES_ISP];
+ const struct s5c73m3_frame_size *cap_size =
+ state->sensor_pix_size[RES_JPEG];
+ unsigned int chg_mode;
+
+ v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd,
+ "Preview size: %dx%d, reg_val: 0x%x\n",
+ prev_size->width, prev_size->height, prev_size->reg_val);
+
+ chg_mode = prev_size->reg_val | COMM_CHG_MODE_NEW;
+
+ if (state->mbus_code == S5C73M3_JPEG_FMT) {
+ v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd,
+ "Capture size: %dx%d, reg_val: 0x%x\n",
+ cap_size->width, cap_size->height, cap_size->reg_val);
+ chg_mode |= cap_size->reg_val;
+ }
+
+ return s5c73m3_isp_command(state, COMM_CHG_MODE, chg_mode);
+}
+
+static int s5c73m3_set_frame_rate(struct s5c73m3 *state)
+{
+ int ret;
+
+ if (state->ctrls.stabilization->val)
+ return 0;
+
+ if (WARN_ON(state->fiv == NULL))
+ return -EINVAL;
+
+ ret = s5c73m3_isp_command(state, COMM_FRAME_RATE, state->fiv->fps_reg);
+ if (!ret)
+ state->apply_fiv = 0;
+
+ return ret;
+}
+
+static int __s5c73m3_s_stream(struct s5c73m3 *state, struct v4l2_subdev *sd,
+ int on)
+{
+ u16 mode;
+ int ret;
+
+ if (on && state->apply_fmt) {
+ if (state->mbus_code == S5C73M3_JPEG_FMT)
+ mode = COMM_IMG_OUTPUT_INTERLEAVED;
+ else
+ mode = COMM_IMG_OUTPUT_YUV;
+
+ ret = s5c73m3_isp_command(state, COMM_IMG_OUTPUT, mode);
+ if (!ret)
+ ret = s5c73m3_set_frame_size(state);
+ if (ret)
+ return ret;
+ state->apply_fmt = 0;
+ }
+
+ ret = s5c73m3_isp_command(state, COMM_SENSOR_STREAMING, !!on);
+ if (ret)
+ return ret;
+
+ state->streaming = !!on;
+
+ if (!on)
+ return ret;
+
+ if (state->apply_fiv) {
+ ret = s5c73m3_set_frame_rate(state);
+ if (ret < 0)
+ v4l2_err(sd, "Error setting frame rate(%d)\n", ret);
+ }
+
+ return s5c73m3_check_status(state, REG_STATUS_ISP_COMMAND_COMPLETED);
+}
+
+static int s5c73m3_oif_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ int ret;
+
+ mutex_lock(&state->lock);
+ ret = __s5c73m3_s_stream(state, sd, on);
+ mutex_unlock(&state->lock);
+
+ return ret;
+}
+
+static int s5c73m3_system_status_wait(struct s5c73m3 *state, u32 value,
+ unsigned int delay, unsigned int steps)
+{
+ u16 reg = 0;
+
+ while (steps-- > 0) {
+ int ret = s5c73m3_read(state, 0x30100010, &reg);
+ if (ret < 0)
+ return ret;
+ if (reg == value)
+ return 0;
+ usleep_range(delay, delay + 25);
+ }
+ return -ETIMEDOUT;
+}
+
+static int s5c73m3_read_fw_version(struct s5c73m3 *state)
+{
+ struct v4l2_subdev *sd = &state->sensor_sd;
+ int i, ret;
+ u16 data[2];
+ int offset;
+
+ offset = state->isp_ready ? 0x60 : 0;
+
+ for (i = 0; i < S5C73M3_SENSOR_FW_LEN / 2; i++) {
+ ret = s5c73m3_read(state, offset + i * 2, data);
+ if (ret < 0)
+ return ret;
+ state->sensor_fw[i * 2] = (char)(*data & 0xff);
+ state->sensor_fw[i * 2 + 1] = (char)(*data >> 8);
+ }
+ state->sensor_fw[S5C73M3_SENSOR_FW_LEN] = '\0';
+
+
+ for (i = 0; i < S5C73M3_SENSOR_TYPE_LEN / 2; i++) {
+ ret = s5c73m3_read(state, offset + 6 + i * 2, data);
+ if (ret < 0)
+ return ret;
+ state->sensor_type[i * 2] = (char)(*data & 0xff);
+ state->sensor_type[i * 2 + 1] = (char)(*data >> 8);
+ }
+ state->sensor_type[S5C73M3_SENSOR_TYPE_LEN] = '\0';
+
+ ret = s5c73m3_read(state, offset + 0x14, data);
+ if (ret >= 0) {
+ ret = s5c73m3_read(state, offset + 0x16, data + 1);
+ if (ret >= 0)
+ state->fw_size = data[0] + (data[1] << 16);
+ }
+
+ v4l2_info(sd, "Sensor type: %s, FW version: %s\n",
+ state->sensor_type, state->sensor_fw);
+ return ret;
+}
+
+static int s5c73m3_fw_update_from(struct s5c73m3 *state)
+{
+ struct v4l2_subdev *sd = &state->sensor_sd;
+ u16 status = COMM_FW_UPDATE_NOT_READY;
+ int ret;
+ int count = 0;
+
+ v4l2_warn(sd, "Updating F-ROM firmware.\n");
+ do {
+ if (status == COMM_FW_UPDATE_NOT_READY) {
+ ret = s5c73m3_isp_command(state, COMM_FW_UPDATE, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = s5c73m3_read(state, 0x00095906, &status);
+ if (ret < 0)
+ return ret;
+ switch (status) {
+ case COMM_FW_UPDATE_FAIL:
+ v4l2_warn(sd, "Updating F-ROM firmware failed.\n");
+ return -EIO;
+ case COMM_FW_UPDATE_SUCCESS:
+ v4l2_warn(sd, "Updating F-ROM firmware finished.\n");
+ return 0;
+ }
+ ++count;
+ msleep(20);
+ } while (count < 500);
+
+ v4l2_warn(sd, "Updating F-ROM firmware timed-out.\n");
+ return -ETIMEDOUT;
+}
+
+static int s5c73m3_spi_boot(struct s5c73m3 *state, bool load_fw)
+{
+ struct v4l2_subdev *sd = &state->sensor_sd;
+ int ret;
+
+ /* Run ARM MCU */
+ ret = s5c73m3_write(state, 0x30000004, 0xffff);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(400, 500);
+
+ /* Check booting status */
+ ret = s5c73m3_system_status_wait(state, 0x0c, 100, 3);
+ if (ret < 0) {
+ v4l2_err(sd, "booting failed: %d\n", ret);
+ return ret;
+ }
+
+ /* P,M,S and Boot Mode */
+ ret = s5c73m3_write(state, 0x30100014, 0x2146);
+ if (ret < 0)
+ return ret;
+
+ ret = s5c73m3_write(state, 0x30100010, 0x210c);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(200, 250);
+
+ /* Check SPI status */
+ ret = s5c73m3_system_status_wait(state, 0x210d, 100, 300);
+ if (ret < 0)
+ v4l2_err(sd, "SPI not ready: %d\n", ret);
+
+ /* Firmware download over SPI */
+ if (load_fw)
+ s5c73m3_load_fw(sd);
+
+ /* MCU reset */
+ ret = s5c73m3_write(state, 0x30000004, 0xfffd);
+ if (ret < 0)
+ return ret;
+
+ /* Remap */
+ ret = s5c73m3_write(state, 0x301000a4, 0x0183);
+ if (ret < 0)
+ return ret;
+
+ /* MCU restart */
+ ret = s5c73m3_write(state, 0x30000004, 0xffff);
+ if (ret < 0 || !load_fw)
+ return ret;
+
+ ret = s5c73m3_read_fw_version(state);
+ if (ret < 0)
+ return ret;
+
+ if (load_fw && update_fw) {
+ ret = s5c73m3_fw_update_from(state);
+ update_fw = 0;
+ }
+
+ return ret;
+}
+
+static int s5c73m3_set_timing_register_for_vdd(struct s5c73m3 *state)
+{
+ static const u32 regs[][2] = {
+ { 0x30100018, 0x0618 },
+ { 0x3010001c, 0x10c1 },
+ { 0x30100020, 0x249e }
+ };
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ ret = s5c73m3_write(state, regs[i][0], regs[i][1]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void s5c73m3_set_fw_file_version(struct s5c73m3 *state)
+{
+ switch (state->sensor_fw[0]) {
+ case 'G':
+ case 'O':
+ state->fw_file_version[0] = 'G';
+ break;
+ case 'S':
+ case 'Z':
+ state->fw_file_version[0] = 'Z';
+ break;
+ }
+
+ switch (state->sensor_fw[1]) {
+ case 'C'...'F':
+ state->fw_file_version[1] = state->sensor_fw[1];
+ break;
+ }
+}
+
+static int s5c73m3_get_fw_version(struct s5c73m3 *state)
+{
+ struct v4l2_subdev *sd = &state->sensor_sd;
+ int ret;
+
+ /* Run ARM MCU */
+ ret = s5c73m3_write(state, 0x30000004, 0xffff);
+ if (ret < 0)
+ return ret;
+ usleep_range(400, 500);
+
+ /* Check booting status */
+ ret = s5c73m3_system_status_wait(state, 0x0c, 100, 3);
+ if (ret < 0) {
+
+ v4l2_err(sd, "%s: booting failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ /* Change I/O Driver Current in order to read from F-ROM */
+ ret = s5c73m3_write(state, 0x30100120, 0x0820);
+ ret = s5c73m3_write(state, 0x30100124, 0x0820);
+
+ /* Offset Setting */
+ ret = s5c73m3_write(state, 0x00010418, 0x0008);
+
+ /* P,M,S and Boot Mode */
+ ret = s5c73m3_write(state, 0x30100014, 0x2146);
+ if (ret < 0)
+ return ret;
+ ret = s5c73m3_write(state, 0x30100010, 0x230c);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(200, 250);
+
+ /* Check SPI status */
+ ret = s5c73m3_system_status_wait(state, 0x230e, 100, 300);
+ if (ret < 0)
+ v4l2_err(sd, "SPI not ready: %d\n", ret);
+
+ /* ARM reset */
+ ret = s5c73m3_write(state, 0x30000004, 0xfffd);
+ if (ret < 0)
+ return ret;
+
+ /* Remap */
+ ret = s5c73m3_write(state, 0x301000a4, 0x0183);
+ if (ret < 0)
+ return ret;
+
+ s5c73m3_set_timing_register_for_vdd(state);
+
+ ret = s5c73m3_read_fw_version(state);
+
+ s5c73m3_set_fw_file_version(state);
+
+ return ret;
+}
+
+static int s5c73m3_rom_boot(struct s5c73m3 *state, bool load_fw)
+{
+ static const u32 boot_regs[][2] = {
+ { 0x3100010c, 0x0044 },
+ { 0x31000108, 0x000d },
+ { 0x31000304, 0x0001 },
+ { 0x00010000, 0x5800 },
+ { 0x00010002, 0x0002 },
+ { 0x31000000, 0x0001 },
+ { 0x30100014, 0x1b85 },
+ { 0x30100010, 0x230c }
+ };
+ struct v4l2_subdev *sd = &state->sensor_sd;
+ int i, ret;
+
+ /* Run ARM MCU */
+ ret = s5c73m3_write(state, 0x30000004, 0xffff);
+ if (ret < 0)
+ return ret;
+ usleep_range(400, 450);
+
+ /* Check booting status */
+ ret = s5c73m3_system_status_wait(state, 0x0c, 100, 4);
+ if (ret < 0) {
+ v4l2_err(sd, "Booting failed: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(boot_regs); i++) {
+ ret = s5c73m3_write(state, boot_regs[i][0], boot_regs[i][1]);
+ if (ret < 0)
+ return ret;
+ }
+ msleep(200);
+
+ /* Check the binary read status */
+ ret = s5c73m3_system_status_wait(state, 0x230e, 1000, 150);
+ if (ret < 0) {
+ v4l2_err(sd, "Binary read failed: %d\n", ret);
+ return ret;
+ }
+
+ /* ARM reset */
+ ret = s5c73m3_write(state, 0x30000004, 0xfffd);
+ if (ret < 0)
+ return ret;
+ /* Remap */
+ ret = s5c73m3_write(state, 0x301000a4, 0x0183);
+ if (ret < 0)
+ return ret;
+ /* MCU re-start */
+ ret = s5c73m3_write(state, 0x30000004, 0xffff);
+ if (ret < 0)
+ return ret;
+
+ state->isp_ready = 1;
+
+ return s5c73m3_read_fw_version(state);
+}
+
+static int s5c73m3_isp_init(struct s5c73m3 *state)
+{
+ int ret;
+
+ state->i2c_read_address = 0;
+ state->i2c_write_address = 0;
+
+ ret = s5c73m3_i2c_write(state->i2c_client, AHB_MSB_ADDR_PTR, 0x3310);
+ if (ret < 0)
+ return ret;
+
+ if (boot_from_rom)
+ return s5c73m3_rom_boot(state, true);
+ else
+ return s5c73m3_spi_boot(state, true);
+}
+
+static const struct s5c73m3_frame_size *s5c73m3_find_frame_size(
+ struct v4l2_mbus_framefmt *fmt,
+ enum s5c73m3_resolution_types idx)
+{
+ const struct s5c73m3_frame_size *fs;
+ const struct s5c73m3_frame_size *best_fs;
+ int best_dist = INT_MAX;
+ int i;
+
+ fs = s5c73m3_resolutions[idx];
+ best_fs = NULL;
+ for (i = 0; i < s5c73m3_resolutions_len[idx]; ++i) {
+ int dist = abs(fs->width - fmt->width) +
+ abs(fs->height - fmt->height);
+ if (dist < best_dist) {
+ best_dist = dist;
+ best_fs = fs;
+ }
+ ++fs;
+ }
+
+ return best_fs;
+}
+
+static void s5c73m3_oif_try_format(struct s5c73m3 *state,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt,
+ const struct s5c73m3_frame_size **fs)
+{
+ u32 code;
+
+ switch (fmt->pad) {
+ case OIF_ISP_PAD:
+ *fs = s5c73m3_find_frame_size(&fmt->format, RES_ISP);
+ code = S5C73M3_ISP_FMT;
+ break;
+ case OIF_JPEG_PAD:
+ *fs = s5c73m3_find_frame_size(&fmt->format, RES_JPEG);
+ code = S5C73M3_JPEG_FMT;
+ break;
+ case OIF_SOURCE_PAD:
+ default:
+ if (fmt->format.code == S5C73M3_JPEG_FMT)
+ code = S5C73M3_JPEG_FMT;
+ else
+ code = S5C73M3_ISP_FMT;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ *fs = state->oif_pix_size[RES_ISP];
+ else
+ *fs = s5c73m3_find_frame_size(
+ v4l2_subdev_get_try_format(fh,
+ OIF_ISP_PAD),
+ RES_ISP);
+ break;
+ }
+
+ s5c73m3_fill_mbus_fmt(&fmt->format, *fs, code);
+}
+
+static void s5c73m3_try_format(struct s5c73m3 *state,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt,
+ const struct s5c73m3_frame_size **fs)
+{
+ u32 code;
+
+ if (fmt->pad == S5C73M3_ISP_PAD) {
+ *fs = s5c73m3_find_frame_size(&fmt->format, RES_ISP);
+ code = S5C73M3_ISP_FMT;
+ } else {
+ *fs = s5c73m3_find_frame_size(&fmt->format, RES_JPEG);
+ code = S5C73M3_JPEG_FMT;
+ }
+
+ s5c73m3_fill_mbus_fmt(&fmt->format, *fs, code);
+}
+
+static int s5c73m3_oif_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+
+ if (fi->pad != OIF_SOURCE_PAD)
+ return -EINVAL;
+
+ mutex_lock(&state->lock);
+ fi->interval = state->fiv->interval;
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static int __s5c73m3_set_frame_interval(struct s5c73m3 *state,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ const struct s5c73m3_frame_size *prev_size =
+ state->sensor_pix_size[RES_ISP];
+ const struct s5c73m3_interval *fiv = &s5c73m3_intervals[0];
+ unsigned int ret, min_err = UINT_MAX;
+ unsigned int i, fr_time;
+
+ if (fi->interval.denominator == 0)
+ return -EINVAL;
+
+ fr_time = fi->interval.numerator * 1000 / fi->interval.denominator;
+
+ for (i = 0; i < ARRAY_SIZE(s5c73m3_intervals); i++) {
+ const struct s5c73m3_interval *iv = &s5c73m3_intervals[i];
+
+ if (prev_size->width > iv->size.width ||
+ prev_size->height > iv->size.height)
+ continue;
+
+ ret = abs(iv->interval.numerator / 1000 - fr_time);
+ if (ret < min_err) {
+ fiv = iv;
+ min_err = ret;
+ }
+ }
+ state->fiv = fiv;
+
+ v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd,
+ "Changed frame interval to %u us\n", fiv->interval.numerator);
+ return 0;
+}
+
+static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ int ret;
+
+ if (fi->pad != OIF_SOURCE_PAD)
+ return -EINVAL;
+
+ v4l2_dbg(1, s5c73m3_dbg, sd, "Setting %d/%d frame interval\n",
+ fi->interval.numerator, fi->interval.denominator);
+
+ mutex_lock(&state->lock);
+
+ ret = __s5c73m3_set_frame_interval(state, fi);
+ if (!ret) {
+ if (state->streaming)
+ ret = s5c73m3_set_frame_rate(state);
+ else
+ state->apply_fiv = 1;
+ }
+ mutex_unlock(&state->lock);
+ return ret;
+}
+
+static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ const struct s5c73m3_interval *fi;
+ int ret = 0;
+
+ if (fie->pad != OIF_SOURCE_PAD)
+ return -EINVAL;
+ if (fie->index > ARRAY_SIZE(s5c73m3_intervals))
+ return -EINVAL;
+
+ mutex_lock(&state->lock);
+ fi = &s5c73m3_intervals[fie->index];
+ if (fie->width > fi->size.width || fie->height > fi->size.height)
+ ret = -EINVAL;
+ else
+ fie->interval = fi->interval;
+ mutex_unlock(&state->lock);
+
+ return ret;
+}
+
+static int s5c73m3_oif_get_pad_code(int pad, int index)
+{
+ if (pad == OIF_SOURCE_PAD) {
+ if (index > 1)
+ return -EINVAL;
+ return (index == 0) ? S5C73M3_ISP_FMT : S5C73M3_JPEG_FMT;
+ }
+
+ if (index > 0)
+ return -EINVAL;
+
+ return (pad == OIF_ISP_PAD) ? S5C73M3_ISP_FMT : S5C73M3_JPEG_FMT;
+}
+
+static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
+ const struct s5c73m3_frame_size *fs;
+ u32 code;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+ return 0;
+ }
+
+ mutex_lock(&state->lock);
+
+ switch (fmt->pad) {
+ case S5C73M3_ISP_PAD:
+ code = S5C73M3_ISP_FMT;
+ fs = state->sensor_pix_size[RES_ISP];
+ break;
+ case S5C73M3_JPEG_PAD:
+ code = S5C73M3_JPEG_FMT;
+ fs = state->sensor_pix_size[RES_JPEG];
+ break;
+ default:
+ mutex_unlock(&state->lock);
+ return -EINVAL;
+ }
+ s5c73m3_fill_mbus_fmt(&fmt->format, fs, code);
+
+ mutex_unlock(&state->lock);
+ return 0;
+}
+
+static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ const struct s5c73m3_frame_size *fs;
+ u32 code;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+ return 0;
+ }
+
+ mutex_lock(&state->lock);
+
+ switch (fmt->pad) {
+ case OIF_ISP_PAD:
+ code = S5C73M3_ISP_FMT;
+ fs = state->oif_pix_size[RES_ISP];
+ break;
+ case OIF_JPEG_PAD:
+ code = S5C73M3_JPEG_FMT;
+ fs = state->oif_pix_size[RES_JPEG];
+ break;
+ case OIF_SOURCE_PAD:
+ code = state->mbus_code;
+ fs = state->oif_pix_size[RES_ISP];
+ break;
+ default:
+ mutex_unlock(&state->lock);
+ return -EINVAL;
+ }
+ s5c73m3_fill_mbus_fmt(&fmt->format, fs, code);
+
+ mutex_unlock(&state->lock);
+ return 0;
+}
+
+static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ const struct s5c73m3_frame_size *frame_size = NULL;
+ struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
+ struct v4l2_mbus_framefmt *mf;
+ int ret = 0;
+
+ mutex_lock(&state->lock);
+
+ s5c73m3_try_format(state, fh, fmt, &frame_size);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ *mf = fmt->format;
+ } else {
+ switch (fmt->pad) {
+ case S5C73M3_ISP_PAD:
+ state->sensor_pix_size[RES_ISP] = frame_size;
+ break;
+ case S5C73M3_JPEG_PAD:
+ state->sensor_pix_size[RES_JPEG] = frame_size;
+ break;
+ default:
+ ret = -EBUSY;
+ }
+
+ if (state->streaming)
+ ret = -EBUSY;
+ else
+ state->apply_fmt = 1;
+ }
+
+ mutex_unlock(&state->lock);
+
+ return ret;
+}
+
+static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ const struct s5c73m3_frame_size *frame_size = NULL;
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ struct v4l2_mbus_framefmt *mf;
+ int ret = 0;
+
+ mutex_lock(&state->lock);
+
+ s5c73m3_oif_try_format(state, fh, fmt, &frame_size);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ *mf = fmt->format;
+ } else {
+ switch (fmt->pad) {
+ case OIF_ISP_PAD:
+ state->oif_pix_size[RES_ISP] = frame_size;
+ break;
+ case OIF_JPEG_PAD:
+ state->oif_pix_size[RES_JPEG] = frame_size;
+ break;
+ case OIF_SOURCE_PAD:
+ state->mbus_code = fmt->format.code;
+ break;
+ default:
+ ret = -EBUSY;
+ }
+
+ if (state->streaming)
+ ret = -EBUSY;
+ else
+ state->apply_fmt = 1;
+ }
+
+ mutex_unlock(&state->lock);
+
+ return ret;
+}
+
+static int s5c73m3_oif_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ int i;
+
+ if (pad != OIF_SOURCE_PAD || fd == NULL)
+ return -EINVAL;
+
+ mutex_lock(&state->lock);
+ fd->num_entries = 2;
+ for (i = 0; i < fd->num_entries; i++)
+ fd->entry[i] = state->frame_desc.entry[i];
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static int s5c73m3_oif_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ struct v4l2_mbus_frame_desc *frame_desc = &state->frame_desc;
+ int i;
+
+ if (pad != OIF_SOURCE_PAD || fd == NULL)
+ return -EINVAL;
+
+ fd->entry[0].length = 10 * SZ_1M;
+ fd->entry[1].length = max_t(u32, fd->entry[1].length,
+ S5C73M3_EMBEDDED_DATA_MAXLEN);
+ fd->num_entries = 2;
+
+ mutex_lock(&state->lock);
+ for (i = 0; i < fd->num_entries; i++)
+ frame_desc->entry[i] = fd->entry[i];
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ static const int codes[] = {
+ [S5C73M3_ISP_PAD] = S5C73M3_ISP_FMT,
+ [S5C73M3_JPEG_PAD] = S5C73M3_JPEG_FMT};
+
+ if (code->index > 0 || code->pad >= S5C73M3_NUM_PADS)
+ return -EINVAL;
+
+ code->code = codes[code->pad];
+
+ return 0;
+}
+
+static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ int ret;
+
+ ret = s5c73m3_oif_get_pad_code(code->pad, code->index);
+ if (ret < 0)
+ return ret;
+
+ code->code = ret;
+
+ return 0;
+}
+
+static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ int idx;
+
+ if (fse->pad == S5C73M3_ISP_PAD) {
+ if (fse->code != S5C73M3_ISP_FMT)
+ return -EINVAL;
+ idx = RES_ISP;
+ } else{
+ if (fse->code != S5C73M3_JPEG_FMT)
+ return -EINVAL;
+ idx = RES_JPEG;
+ }
+
+ if (fse->index >= s5c73m3_resolutions_len[idx])
+ return -EINVAL;
+
+ fse->min_width = s5c73m3_resolutions[idx][fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->max_height = s5c73m3_resolutions[idx][fse->index].height;
+ fse->min_height = fse->max_height;
+
+ return 0;
+}
+
+static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ int idx;
+
+ if (fse->pad == OIF_SOURCE_PAD) {
+ if (fse->index > 0)
+ return -EINVAL;
+
+ switch (fse->code) {
+ case S5C73M3_JPEG_FMT:
+ case S5C73M3_ISP_FMT: {
+ struct v4l2_mbus_framefmt *mf =
+ v4l2_subdev_get_try_format(fh, OIF_ISP_PAD);
+
+ fse->max_width = fse->min_width = mf->width;
+ fse->max_height = fse->min_height = mf->height;
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (fse->code != s5c73m3_oif_get_pad_code(fse->pad, 0))
+ return -EINVAL;
+
+ if (fse->pad == OIF_JPEG_PAD)
+ idx = RES_JPEG;
+ else
+ idx = RES_ISP;
+
+ if (fse->index >= s5c73m3_resolutions_len[idx])
+ return -EINVAL;
+
+ fse->min_width = s5c73m3_resolutions[idx][fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->max_height = s5c73m3_resolutions[idx][fse->index].height;
+ fse->min_height = fse->max_height;
+
+ return 0;
+}
+
+static int s5c73m3_oif_log_status(struct v4l2_subdev *sd)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+
+ v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
+
+ v4l2_info(sd, "power: %d, apply_fmt: %d\n", state->power,
+ state->apply_fmt);
+
+ return 0;
+}
+
+static int s5c73m3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *mf;
+
+ mf = v4l2_subdev_get_try_format(fh, S5C73M3_ISP_PAD);
+ s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
+ S5C73M3_ISP_FMT);
+
+ mf = v4l2_subdev_get_try_format(fh, S5C73M3_JPEG_PAD);
+ s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1],
+ S5C73M3_JPEG_FMT);
+
+ return 0;
+}
+
+static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *mf;
+
+ mf = v4l2_subdev_get_try_format(fh, OIF_ISP_PAD);
+ s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
+ S5C73M3_ISP_FMT);
+
+ mf = v4l2_subdev_get_try_format(fh, OIF_JPEG_PAD);
+ s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1],
+ S5C73M3_JPEG_FMT);
+
+ mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD);
+ s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
+ S5C73M3_ISP_FMT);
+ return 0;
+}
+
+static int s5c73m3_gpio_set_value(struct s5c73m3 *priv, int id, u32 val)
+{
+ if (!gpio_is_valid(priv->gpio[id].gpio))
+ return 0;
+ gpio_set_value(priv->gpio[id].gpio, !!val);
+ return 1;
+}
+
+static int s5c73m3_gpio_assert(struct s5c73m3 *priv, int id)
+{
+ return s5c73m3_gpio_set_value(priv, id, priv->gpio[id].level);
+}
+
+static int s5c73m3_gpio_deassert(struct s5c73m3 *priv, int id)
+{
+ return s5c73m3_gpio_set_value(priv, id, !priv->gpio[id].level);
+}
+
+static int __s5c73m3_power_on(struct s5c73m3 *state)
+{
+ int i, ret;
+
+ for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++) {
+ ret = regulator_enable(state->supplies[i].consumer);
+ if (ret)
+ goto err;
+ }
+
+ s5c73m3_gpio_deassert(state, STBY);
+ usleep_range(100, 200);
+
+ s5c73m3_gpio_deassert(state, RST);
+ usleep_range(50, 100);
+
+ return 0;
+err:
+ for (--i; i >= 0; i--)
+ regulator_disable(state->supplies[i].consumer);
+ return ret;
+}
+
+static int __s5c73m3_power_off(struct s5c73m3 *state)
+{
+ int i, ret;
+
+ if (s5c73m3_gpio_assert(state, RST))
+ usleep_range(10, 50);
+
+ if (s5c73m3_gpio_assert(state, STBY))
+ usleep_range(100, 200);
+ state->streaming = 0;
+ state->isp_ready = 0;
+
+ for (i = S5C73M3_MAX_SUPPLIES - 1; i >= 0; i--) {
+ ret = regulator_disable(state->supplies[i].consumer);
+ if (ret)
+ goto err;
+ }
+ return 0;
+err:
+ for (++i; i < S5C73M3_MAX_SUPPLIES; i++)
+ regulator_enable(state->supplies[i].consumer);
+
+ return ret;
+}
+
+static int s5c73m3_oif_set_power(struct v4l2_subdev *sd, int on)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ int ret = 0;
+
+ mutex_lock(&state->lock);
+
+ if (on && !state->power) {
+ ret = __s5c73m3_power_on(state);
+ if (!ret)
+ ret = s5c73m3_isp_init(state);
+ if (!ret) {
+ state->apply_fiv = 1;
+ state->apply_fmt = 1;
+ }
+ } else if (!on == state->power) {
+ ret = s5c73m3_set_af_softlanding(state);
+ if (!ret)
+ ret = __s5c73m3_power_off(state);
+ else
+ v4l2_err(sd, "Soft landing lens failed\n");
+ }
+ if (!ret)
+ state->power += on ? 1 : -1;
+
+ v4l2_dbg(1, s5c73m3_dbg, sd, "%s: power: %d\n",
+ __func__, state->power);
+
+ mutex_unlock(&state->lock);
+ return ret;
+}
+
+static int s5c73m3_oif_registered(struct v4l2_subdev *sd)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ int ret;
+
+ ret = v4l2_device_register_subdev(sd->v4l2_dev, &state->sensor_sd);
+ if (ret) {
+ v4l2_err(sd->v4l2_dev, "Failed to register %s\n",
+ state->oif_sd.name);
+ return ret;
+ }
+
+ ret = media_entity_create_link(&state->sensor_sd.entity,
+ S5C73M3_ISP_PAD, &state->oif_sd.entity, OIF_ISP_PAD,
+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+
+ ret = media_entity_create_link(&state->sensor_sd.entity,
+ S5C73M3_JPEG_PAD, &state->oif_sd.entity, OIF_JPEG_PAD,
+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+
+ mutex_lock(&state->lock);
+ ret = __s5c73m3_power_on(state);
+ if (ret == 0)
+ s5c73m3_get_fw_version(state);
+
+ __s5c73m3_power_off(state);
+ mutex_unlock(&state->lock);
+
+ v4l2_dbg(1, s5c73m3_dbg, sd, "%s: Booting %s (%d)\n",
+ __func__, ret ? "failed" : "succeded", ret);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_internal_ops s5c73m3_internal_ops = {
+ .open = s5c73m3_open,
+};
+
+static const struct v4l2_subdev_pad_ops s5c73m3_pad_ops = {
+ .enum_mbus_code = s5c73m3_enum_mbus_code,
+ .enum_frame_size = s5c73m3_enum_frame_size,
+ .get_fmt = s5c73m3_get_fmt,
+ .set_fmt = s5c73m3_set_fmt,
+};
+
+static const struct v4l2_subdev_ops s5c73m3_subdev_ops = {
+ .pad = &s5c73m3_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops oif_internal_ops = {
+ .registered = s5c73m3_oif_registered,
+ .open = s5c73m3_oif_open,
+};
+
+static const struct v4l2_subdev_pad_ops s5c73m3_oif_pad_ops = {
+ .enum_mbus_code = s5c73m3_oif_enum_mbus_code,
+ .enum_frame_size = s5c73m3_oif_enum_frame_size,
+ .enum_frame_interval = s5c73m3_oif_enum_frame_interval,
+ .get_fmt = s5c73m3_oif_get_fmt,
+ .set_fmt = s5c73m3_oif_set_fmt,
+ .get_frame_desc = s5c73m3_oif_get_frame_desc,
+ .set_frame_desc = s5c73m3_oif_set_frame_desc,
+};
+
+static const struct v4l2_subdev_core_ops s5c73m3_oif_core_ops = {
+ .s_power = s5c73m3_oif_set_power,
+ .log_status = s5c73m3_oif_log_status,
+};
+
+static const struct v4l2_subdev_video_ops s5c73m3_oif_video_ops = {
+ .s_stream = s5c73m3_oif_s_stream,
+ .g_frame_interval = s5c73m3_oif_g_frame_interval,
+ .s_frame_interval = s5c73m3_oif_s_frame_interval,
+};
+
+static const struct v4l2_subdev_ops oif_subdev_ops = {
+ .core = &s5c73m3_oif_core_ops,
+ .pad = &s5c73m3_oif_pad_ops,
+ .video = &s5c73m3_oif_video_ops,
+};
+
+static int s5c73m3_configure_gpio(int nr, int val, const char *name)
+{
+ unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ int ret;
+
+ if (!gpio_is_valid(nr))
+ return 0;
+ ret = gpio_request_one(nr, flags, name);
+ if (!ret)
+ gpio_export(nr, 0);
+ return ret;
+}
+
+static int s5c73m3_free_gpios(struct s5c73m3 *state)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(state->gpio); i++) {
+ if (!gpio_is_valid(state->gpio[i].gpio))
+ continue;
+ gpio_free(state->gpio[i].gpio);
+ state->gpio[i].gpio = -EINVAL;
+ }
+ return 0;
+}
+
+static int s5c73m3_configure_gpios(struct s5c73m3 *state,
+ const struct s5c73m3_platform_data *pdata)
+{
+ const struct s5c73m3_gpio *gpio = &pdata->gpio_stby;
+ int ret;
+
+ state->gpio[STBY].gpio = -EINVAL;
+ state->gpio[RST].gpio = -EINVAL;
+
+ ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_STBY");
+ if (ret) {
+ s5c73m3_free_gpios(state);
+ return ret;
+ }
+ state->gpio[STBY] = *gpio;
+ if (gpio_is_valid(gpio->gpio))
+ gpio_set_value(gpio->gpio, 0);
+
+ gpio = &pdata->gpio_reset;
+ ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_RST");
+ if (ret) {
+ s5c73m3_free_gpios(state);
+ return ret;
+ }
+ state->gpio[RST] = *gpio;
+ if (gpio_is_valid(gpio->gpio))
+ gpio_set_value(gpio->gpio, 0);
+
+ return 0;
+}
+
+static int s5c73m3_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ const struct s5c73m3_platform_data *pdata = client->dev.platform_data;
+ struct v4l2_subdev *sd;
+ struct v4l2_subdev *oif_sd;
+ struct s5c73m3 *state;
+ int ret, i;
+
+ if (pdata == NULL) {
+ dev_err(&client->dev, "Platform data not specified\n");
+ return -EINVAL;
+ }
+
+ state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ mutex_init(&state->lock);
+ sd = &state->sensor_sd;
+ oif_sd = &state->oif_sd;
+
+ v4l2_subdev_init(sd, &s5c73m3_subdev_ops);
+ sd->owner = client->driver->driver.owner;
+ v4l2_set_subdevdata(sd, state);
+ strlcpy(sd->name, "S5C73M3", sizeof(sd->name));
+
+ sd->internal_ops = &s5c73m3_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ state->sensor_pads[S5C73M3_JPEG_PAD].flags = MEDIA_PAD_FL_SOURCE;
+ state->sensor_pads[S5C73M3_ISP_PAD].flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+
+ ret = media_entity_init(&sd->entity, S5C73M3_NUM_PADS,
+ state->sensor_pads, 0);
+ if (ret < 0)
+ return ret;
+
+ v4l2_i2c_subdev_init(oif_sd, client, &oif_subdev_ops);
+ strcpy(oif_sd->name, "S5C73M3-OIF");
+
+ oif_sd->internal_ops = &oif_internal_ops;
+ oif_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ state->oif_pads[OIF_ISP_PAD].flags = MEDIA_PAD_FL_SINK;
+ state->oif_pads[OIF_JPEG_PAD].flags = MEDIA_PAD_FL_SINK;
+ state->oif_pads[OIF_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE;
+ oif_sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+
+ ret = media_entity_init(&oif_sd->entity, OIF_NUM_PADS,
+ state->oif_pads, 0);
+ if (ret < 0)
+ return ret;
+
+ state->mclk_frequency = pdata->mclk_frequency;
+ state->bus_type = pdata->bus_type;
+
+ ret = s5c73m3_configure_gpios(state, pdata);
+ if (ret)
+ goto out_err1;
+
+ for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++)
+ state->supplies[i].supply = s5c73m3_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, S5C73M3_MAX_SUPPLIES,
+ state->supplies);
+ if (ret) {
+ dev_err(dev, "failed to get regulators\n");
+ goto out_err2;
+ }
+
+ ret = s5c73m3_init_controls(state);
+ if (ret)
+ goto out_err2;
+
+ state->sensor_pix_size[RES_ISP] = &s5c73m3_isp_resolutions[1];
+ state->sensor_pix_size[RES_JPEG] = &s5c73m3_jpeg_resolutions[1];
+ state->oif_pix_size[RES_ISP] = state->sensor_pix_size[RES_ISP];
+ state->oif_pix_size[RES_JPEG] = state->sensor_pix_size[RES_JPEG];
+
+ state->mbus_code = S5C73M3_ISP_FMT;
+
+ state->fiv = &s5c73m3_intervals[S5C73M3_DEFAULT_FRAME_INTERVAL];
+
+ state->fw_file_version[0] = 'G';
+ state->fw_file_version[1] = 'C';
+
+ ret = s5c73m3_register_spi_driver(state);
+ if (ret < 0)
+ goto out_err2;
+
+ state->i2c_client = client;
+
+ v4l2_info(sd, "%s: completed succesfully\n", __func__);
+ return 0;
+
+out_err2:
+ s5c73m3_free_gpios(state);
+out_err1:
+ media_entity_cleanup(&sd->entity);
+ return ret;
+}
+
+static int s5c73m3_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
+
+ v4l2_device_unregister_subdev(sd);
+
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+ media_entity_cleanup(&sd->entity);
+
+ s5c73m3_unregister_spi_driver(state);
+ s5c73m3_free_gpios(state);
+
+ return 0;
+}
+
+static const struct i2c_device_id s5c73m3_id[] = {
+ { DRIVER_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, s5c73m3_id);
+
+static struct i2c_driver s5c73m3_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = s5c73m3_probe,
+ .remove = s5c73m3_remove,
+ .id_table = s5c73m3_id,
+};
+
+module_i2c_driver(s5c73m3_i2c_driver);
+
+MODULE_DESCRIPTION("Samsung S5C73M3 camera driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
new file mode 100644
index 000000000000..8001cde1db1e
--- /dev/null
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
@@ -0,0 +1,563 @@
+/*
+ * Samsung LSI S5C73M3 8M pixel camera driver
+ *
+ * Copyright (C) 2012, Samsung Electronics, Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Andrzej Hajda <a.hajda@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/sizes.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/media.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/videodev2.h>
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5c73m3.h>
+
+#include "s5c73m3.h"
+
+static int s5c73m3_get_af_status(struct s5c73m3 *state, struct v4l2_ctrl *ctrl)
+{
+ u16 reg = REG_AF_STATUS_UNFOCUSED;
+
+ int ret = s5c73m3_read(state, REG_AF_STATUS, &reg);
+
+ switch (reg) {
+ case REG_CAF_STATUS_FIND_SEARCH_DIR:
+ case REG_AF_STATUS_FOCUSING:
+ case REG_CAF_STATUS_FOCUSING:
+ ctrl->val = V4L2_AUTO_FOCUS_STATUS_BUSY;
+ break;
+ case REG_CAF_STATUS_FOCUSED:
+ case REG_AF_STATUS_FOCUSED:
+ ctrl->val = V4L2_AUTO_FOCUS_STATUS_REACHED;
+ break;
+ default:
+ v4l2_info(&state->sensor_sd, "Unknown AF status %#x\n", reg);
+ /* Fall through */
+ case REG_CAF_STATUS_UNFOCUSED:
+ case REG_AF_STATUS_UNFOCUSED:
+ case REG_AF_STATUS_INVALID:
+ ctrl->val = V4L2_AUTO_FOCUS_STATUS_FAILED;
+ break;
+ }
+
+ return ret;
+}
+
+static int s5c73m3_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = ctrl_to_sensor_sd(ctrl);
+ struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
+ int ret;
+
+ if (state->power == 0)
+ return -EBUSY;
+
+ switch (ctrl->id) {
+ case V4L2_CID_FOCUS_AUTO:
+ ret = s5c73m3_get_af_status(state, state->ctrls.af_status);
+ if (ret)
+ return ret;
+ break;
+ }
+
+ return 0;
+}
+
+static int s5c73m3_set_colorfx(struct s5c73m3 *state, int val)
+{
+ static const unsigned short colorfx[][2] = {
+ { V4L2_COLORFX_NONE, COMM_IMAGE_EFFECT_NONE },
+ { V4L2_COLORFX_BW, COMM_IMAGE_EFFECT_MONO },
+ { V4L2_COLORFX_SEPIA, COMM_IMAGE_EFFECT_SEPIA },
+ { V4L2_COLORFX_NEGATIVE, COMM_IMAGE_EFFECT_NEGATIVE },
+ { V4L2_COLORFX_AQUA, COMM_IMAGE_EFFECT_AQUA },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
+ if (colorfx[i][0] != val)
+ continue;
+
+ v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd,
+ "Setting %s color effect\n",
+ v4l2_ctrl_get_menu(state->ctrls.colorfx->id)[i]);
+
+ return s5c73m3_isp_command(state, COMM_IMAGE_EFFECT,
+ colorfx[i][1]);
+ }
+ return -EINVAL;
+}
+
+/* Set exposure metering/exposure bias */
+static int s5c73m3_set_exposure(struct s5c73m3 *state, int auto_exp)
+{
+ struct v4l2_subdev *sd = &state->sensor_sd;
+ struct s5c73m3_ctrls *ctrls = &state->ctrls;
+ int ret = 0;
+
+ if (ctrls->exposure_metering->is_new) {
+ u16 metering;
+
+ switch (ctrls->exposure_metering->val) {
+ case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
+ metering = COMM_METERING_CENTER;
+ break;
+ case V4L2_EXPOSURE_METERING_SPOT:
+ metering = COMM_METERING_SPOT;
+ break;
+ default:
+ metering = COMM_METERING_AVERAGE;
+ break;
+ }
+
+ ret = s5c73m3_isp_command(state, COMM_METERING, metering);
+ }
+
+ if (!ret && ctrls->exposure_bias->is_new) {
+ u16 exp_bias = ctrls->exposure_bias->val;
+ ret = s5c73m3_isp_command(state, COMM_EV, exp_bias);
+ }
+
+ v4l2_dbg(1, s5c73m3_dbg, sd,
+ "%s: exposure bias: %#x, metering: %#x (%d)\n", __func__,
+ ctrls->exposure_bias->val, ctrls->exposure_metering->val, ret);
+
+ return ret;
+}
+
+static int s5c73m3_set_white_balance(struct s5c73m3 *state, int val)
+{
+ static const unsigned short wb[][2] = {
+ { V4L2_WHITE_BALANCE_INCANDESCENT, COMM_AWB_MODE_INCANDESCENT},
+ { V4L2_WHITE_BALANCE_FLUORESCENT, COMM_AWB_MODE_FLUORESCENT1},
+ { V4L2_WHITE_BALANCE_FLUORESCENT_H, COMM_AWB_MODE_FLUORESCENT2},
+ { V4L2_WHITE_BALANCE_CLOUDY, COMM_AWB_MODE_CLOUDY},
+ { V4L2_WHITE_BALANCE_DAYLIGHT, COMM_AWB_MODE_DAYLIGHT},
+ { V4L2_WHITE_BALANCE_AUTO, COMM_AWB_MODE_AUTO},
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wb); i++) {
+ if (wb[i][0] != val)
+ continue;
+
+ v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd,
+ "Setting white balance to: %s\n",
+ v4l2_ctrl_get_menu(state->ctrls.auto_wb->id)[i]);
+
+ return s5c73m3_isp_command(state, COMM_AWB_MODE, wb[i][1]);
+ }
+
+ return -EINVAL;
+}
+
+static int s5c73m3_af_run(struct s5c73m3 *state, bool on)
+{
+ struct s5c73m3_ctrls *c = &state->ctrls;
+
+ if (!on)
+ return s5c73m3_isp_command(state, COMM_AF_CON,
+ COMM_AF_CON_STOP);
+
+ if (c->focus_auto->val)
+ return s5c73m3_isp_command(state, COMM_AF_MODE,
+ COMM_AF_MODE_PREVIEW_CAF_START);
+
+ return s5c73m3_isp_command(state, COMM_AF_CON, COMM_AF_CON_START);
+}
+
+static int s5c73m3_3a_lock(struct s5c73m3 *state, struct v4l2_ctrl *ctrl)
+{
+ bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
+ bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
+ bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
+ int ret = 0;
+
+ if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
+ ret = s5c73m3_isp_command(state, COMM_AE_CON,
+ ae_lock ? COMM_AE_STOP : COMM_AE_START);
+ if (ret)
+ return ret;
+ }
+
+ if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
+ && state->ctrls.auto_wb->val) {
+ ret = s5c73m3_isp_command(state, COMM_AWB_CON,
+ awb_lock ? COMM_AWB_STOP : COMM_AWB_START);
+ if (ret)
+ return ret;
+ }
+
+ if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
+ ret = s5c73m3_af_run(state, ~af_lock);
+
+ return ret;
+}
+
+static int s5c73m3_set_auto_focus(struct s5c73m3 *state, int caf)
+{
+ struct s5c73m3_ctrls *c = &state->ctrls;
+ int ret = 1;
+
+ if (c->af_distance->is_new) {
+ u16 mode = (c->af_distance->val == V4L2_AUTO_FOCUS_RANGE_MACRO)
+ ? COMM_AF_MODE_MACRO : COMM_AF_MODE_NORMAL;
+ ret = s5c73m3_isp_command(state, COMM_AF_MODE, mode);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (!ret || (c->focus_auto->is_new && c->focus_auto->val) ||
+ c->af_start->is_new)
+ ret = s5c73m3_af_run(state, 1);
+ else if ((c->focus_auto->is_new && !c->focus_auto->val) ||
+ c->af_stop->is_new)
+ ret = s5c73m3_af_run(state, 0);
+ else
+ ret = 0;
+
+ return ret;
+}
+
+static int s5c73m3_set_contrast(struct s5c73m3 *state, int val)
+{
+ u16 reg = (val < 0) ? -val + 2 : val;
+ return s5c73m3_isp_command(state, COMM_CONTRAST, reg);
+}
+
+static int s5c73m3_set_saturation(struct s5c73m3 *state, int val)
+{
+ u16 reg = (val < 0) ? -val + 2 : val;
+ return s5c73m3_isp_command(state, COMM_SATURATION, reg);
+}
+
+static int s5c73m3_set_sharpness(struct s5c73m3 *state, int val)
+{
+ u16 reg = (val < 0) ? -val + 2 : val;
+ return s5c73m3_isp_command(state, COMM_SHARPNESS, reg);
+}
+
+static int s5c73m3_set_iso(struct s5c73m3 *state, int val)
+{
+ u32 iso;
+
+ if (val == V4L2_ISO_SENSITIVITY_MANUAL)
+ iso = state->ctrls.iso->val + 1;
+ else
+ iso = 0;
+
+ return s5c73m3_isp_command(state, COMM_ISO, iso);
+}
+
+static int s5c73m3_set_stabilization(struct s5c73m3 *state, int val)
+{
+ struct v4l2_subdev *sd = &state->sensor_sd;
+
+ v4l2_dbg(1, s5c73m3_dbg, sd, "Image stabilization: %d\n", val);
+
+ return s5c73m3_isp_command(state, COMM_FRAME_RATE, val ?
+ COMM_FRAME_RATE_ANTI_SHAKE : COMM_FRAME_RATE_AUTO_SET);
+}
+
+static int s5c73m3_set_jpeg_quality(struct s5c73m3 *state, int quality)
+{
+ int reg;
+
+ if (quality <= 65)
+ reg = COMM_IMAGE_QUALITY_NORMAL;
+ else if (quality <= 75)
+ reg = COMM_IMAGE_QUALITY_FINE;
+ else
+ reg = COMM_IMAGE_QUALITY_SUPERFINE;
+
+ return s5c73m3_isp_command(state, COMM_IMAGE_QUALITY, reg);
+}
+
+static int s5c73m3_set_scene_program(struct s5c73m3 *state, int val)
+{
+ static const unsigned short scene_lookup[] = {
+ COMM_SCENE_MODE_NONE, /* V4L2_SCENE_MODE_NONE */
+ COMM_SCENE_MODE_AGAINST_LIGHT,/* V4L2_SCENE_MODE_BACKLIGHT */
+ COMM_SCENE_MODE_BEACH, /* V4L2_SCENE_MODE_BEACH_SNOW */
+ COMM_SCENE_MODE_CANDLE, /* V4L2_SCENE_MODE_CANDLE_LIGHT */
+ COMM_SCENE_MODE_DAWN, /* V4L2_SCENE_MODE_DAWN_DUSK */
+ COMM_SCENE_MODE_FALL, /* V4L2_SCENE_MODE_FALL_COLORS */
+ COMM_SCENE_MODE_FIRE, /* V4L2_SCENE_MODE_FIREWORKS */
+ COMM_SCENE_MODE_LANDSCAPE, /* V4L2_SCENE_MODE_LANDSCAPE */
+ COMM_SCENE_MODE_NIGHT, /* V4L2_SCENE_MODE_NIGHT */
+ COMM_SCENE_MODE_INDOOR, /* V4L2_SCENE_MODE_PARTY_INDOOR */
+ COMM_SCENE_MODE_PORTRAIT, /* V4L2_SCENE_MODE_PORTRAIT */
+ COMM_SCENE_MODE_SPORTS, /* V4L2_SCENE_MODE_SPORTS */
+ COMM_SCENE_MODE_SUNSET, /* V4L2_SCENE_MODE_SUNSET */
+ COMM_SCENE_MODE_TEXT, /* V4L2_SCENE_MODE_TEXT */
+ };
+
+ v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, "Setting %s scene mode\n",
+ v4l2_ctrl_get_menu(state->ctrls.scene_mode->id)[val]);
+
+ return s5c73m3_isp_command(state, COMM_SCENE_MODE, scene_lookup[val]);
+}
+
+static int s5c73m3_set_power_line_freq(struct s5c73m3 *state, int val)
+{
+ unsigned int pwr_line_freq = COMM_FLICKER_NONE;
+
+ switch (val) {
+ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
+ pwr_line_freq = COMM_FLICKER_NONE;
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
+ pwr_line_freq = COMM_FLICKER_AUTO_50HZ;
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
+ pwr_line_freq = COMM_FLICKER_AUTO_60HZ;
+ break;
+ default:
+ case V4L2_CID_POWER_LINE_FREQUENCY_AUTO:
+ pwr_line_freq = COMM_FLICKER_NONE;
+ }
+
+ return s5c73m3_isp_command(state, COMM_FLICKER_MODE, pwr_line_freq);
+}
+
+static int s5c73m3_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = ctrl_to_sensor_sd(ctrl);
+ struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
+ int ret = 0;
+
+ v4l2_dbg(1, s5c73m3_dbg, sd, "set_ctrl: %s, value: %d\n",
+ ctrl->name, ctrl->val);
+
+ mutex_lock(&state->lock);
+ /*
+ * If the device is not powered up by the host driver do
+ * not apply any controls to H/W at this time. Instead
+ * the controls will be restored right after power-up.
+ */
+ if (state->power == 0)
+ goto unlock;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_3A_LOCK:
+ ret = s5c73m3_3a_lock(state, ctrl);
+ break;
+
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ ret = s5c73m3_set_white_balance(state, ctrl->val);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ ret = s5c73m3_set_contrast(state, ctrl->val);
+ break;
+
+ case V4L2_CID_COLORFX:
+ ret = s5c73m3_set_colorfx(state, ctrl->val);
+ break;
+
+ case V4L2_CID_EXPOSURE_AUTO:
+ ret = s5c73m3_set_exposure(state, ctrl->val);
+ break;
+
+ case V4L2_CID_FOCUS_AUTO:
+ ret = s5c73m3_set_auto_focus(state, ctrl->val);
+ break;
+
+ case V4L2_CID_IMAGE_STABILIZATION:
+ ret = s5c73m3_set_stabilization(state, ctrl->val);
+ break;
+
+ case V4L2_CID_ISO_SENSITIVITY:
+ ret = s5c73m3_set_iso(state, ctrl->val);
+ break;
+
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ ret = s5c73m3_set_jpeg_quality(state, ctrl->val);
+ break;
+
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ ret = s5c73m3_set_power_line_freq(state, ctrl->val);
+ break;
+
+ case V4L2_CID_SATURATION:
+ ret = s5c73m3_set_saturation(state, ctrl->val);
+ break;
+
+ case V4L2_CID_SCENE_MODE:
+ ret = s5c73m3_set_scene_program(state, ctrl->val);
+ break;
+
+ case V4L2_CID_SHARPNESS:
+ ret = s5c73m3_set_sharpness(state, ctrl->val);
+ break;
+
+ case V4L2_CID_WIDE_DYNAMIC_RANGE:
+ ret = s5c73m3_isp_command(state, COMM_WDR, !!ctrl->val);
+ break;
+
+ case V4L2_CID_ZOOM_ABSOLUTE:
+ ret = s5c73m3_isp_command(state, COMM_ZOOM_STEP, ctrl->val);
+ break;
+ }
+unlock:
+ mutex_unlock(&state->lock);
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops s5c73m3_ctrl_ops = {
+ .g_volatile_ctrl = s5c73m3_g_volatile_ctrl,
+ .s_ctrl = s5c73m3_s_ctrl,
+};
+
+/* Supported manual ISO values */
+static const s64 iso_qmenu[] = {
+ /* COMM_ISO: 0x0001...0x0004 */
+ 100, 200, 400, 800,
+};
+
+/* Supported exposure bias values (-2.0EV...+2.0EV) */
+static const s64 ev_bias_qmenu[] = {
+ /* COMM_EV: 0x0000...0x0008 */
+ -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000
+};
+
+int s5c73m3_init_controls(struct s5c73m3 *state)
+{
+ const struct v4l2_ctrl_ops *ops = &s5c73m3_ctrl_ops;
+ struct s5c73m3_ctrls *ctrls = &state->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+
+ int ret = v4l2_ctrl_handler_init(hdl, 22);
+ if (ret)
+ return ret;
+
+ /* White balance */
+ ctrls->auto_wb = v4l2_ctrl_new_std_menu(hdl, ops,
+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+ 9, ~0x15e, V4L2_WHITE_BALANCE_AUTO);
+
+ /* Exposure (only automatic exposure) */
+ ctrls->auto_exposure = v4l2_ctrl_new_std_menu(hdl, ops,
+ V4L2_CID_EXPOSURE_AUTO, 0, ~0x01, V4L2_EXPOSURE_AUTO);
+
+ ctrls->exposure_bias = v4l2_ctrl_new_int_menu(hdl, ops,
+ V4L2_CID_AUTO_EXPOSURE_BIAS,
+ ARRAY_SIZE(ev_bias_qmenu) - 1,
+ ARRAY_SIZE(ev_bias_qmenu)/2 - 1,
+ ev_bias_qmenu);
+
+ ctrls->exposure_metering = v4l2_ctrl_new_std_menu(hdl, ops,
+ V4L2_CID_EXPOSURE_METERING,
+ 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE);
+
+ /* Auto focus */
+ ctrls->focus_auto = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_FOCUS_AUTO, 0, 1, 1, 0);
+
+ ctrls->af_start = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_AUTO_FOCUS_START, 0, 1, 1, 0);
+
+ ctrls->af_stop = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_AUTO_FOCUS_STOP, 0, 1, 1, 0);
+
+ ctrls->af_status = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_AUTO_FOCUS_STATUS, 0,
+ (V4L2_AUTO_FOCUS_STATUS_BUSY |
+ V4L2_AUTO_FOCUS_STATUS_REACHED |
+ V4L2_AUTO_FOCUS_STATUS_FAILED),
+ 0, V4L2_AUTO_FOCUS_STATUS_IDLE);
+
+ ctrls->af_distance = v4l2_ctrl_new_std_menu(hdl, ops,
+ V4L2_CID_AUTO_FOCUS_RANGE,
+ V4L2_AUTO_FOCUS_RANGE_MACRO,
+ ~(1 << V4L2_AUTO_FOCUS_RANGE_NORMAL |
+ 1 << V4L2_AUTO_FOCUS_RANGE_MACRO),
+ V4L2_AUTO_FOCUS_RANGE_NORMAL);
+ /* ISO sensitivity */
+ ctrls->auto_iso = v4l2_ctrl_new_std_menu(hdl, ops,
+ V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0,
+ V4L2_ISO_SENSITIVITY_AUTO);
+
+ ctrls->iso = v4l2_ctrl_new_int_menu(hdl, ops,
+ V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
+ ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
+
+ ctrls->contrast = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_CONTRAST, -2, 2, 1, 0);
+
+ ctrls->saturation = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_SATURATION, -2, 2, 1, 0);
+
+ ctrls->sharpness = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_SHARPNESS, -2, 2, 1, 0);
+
+ ctrls->zoom = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_ZOOM_ABSOLUTE, 0, 30, 1, 0);
+
+ ctrls->colorfx = v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX,
+ V4L2_COLORFX_AQUA, ~0x40f, V4L2_COLORFX_NONE);
+
+ ctrls->wdr = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0);
+
+ ctrls->stabilization = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
+
+ ctrls->jpeg_quality = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80);
+
+ ctrls->scene_mode = v4l2_ctrl_new_std_menu(hdl, ops,
+ V4L2_CID_SCENE_MODE, V4L2_SCENE_MODE_TEXT, ~0x3fff,
+ V4L2_SCENE_MODE_NONE);
+
+ ctrls->aaa_lock = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_3A_LOCK, 0, 0x7, 0, 0);
+
+ if (hdl->error) {
+ ret = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+ }
+
+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_exposure, 0, false);
+ ctrls->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE |
+ V4L2_CTRL_FLAG_UPDATE;
+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, 0, false);
+ ctrls->af_status->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ v4l2_ctrl_cluster(6, &ctrls->focus_auto);
+
+ state->sensor_sd.ctrl_handler = hdl;
+
+ return 0;
+}
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
new file mode 100644
index 000000000000..6f3a9c00fe65
--- /dev/null
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
@@ -0,0 +1,156 @@
+/*
+ * Samsung LSI S5C73M3 8M pixel camera driver
+ *
+ * Copyright (C) 2012, Samsung Electronics, Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Andrzej Hajda <a.hajda@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/sizes.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/media.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include "s5c73m3.h"
+
+#define S5C73M3_SPI_DRV_NAME "S5C73M3-SPI"
+
+enum spi_direction {
+ SPI_DIR_RX,
+ SPI_DIR_TX
+};
+
+static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len,
+ enum spi_direction dir)
+{
+ struct spi_message msg;
+ int r;
+ struct spi_transfer xfer = {
+ .len = len,
+ };
+
+ if (dir == SPI_DIR_TX)
+ xfer.tx_buf = addr;
+ else
+ xfer.rx_buf = addr;
+
+ if (spi_dev == NULL) {
+ dev_err(&spi_dev->dev, "SPI device is uninitialized\n");
+ return -ENODEV;
+ }
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ r = spi_sync(spi_dev, &msg);
+ if (r < 0)
+ dev_err(&spi_dev->dev, "%s spi_sync failed %d\n", __func__, r);
+
+ return r;
+}
+
+int s5c73m3_spi_write(struct s5c73m3 *state, const void *addr,
+ const unsigned int len, const unsigned int tx_size)
+{
+ struct spi_device *spi_dev = state->spi_dev;
+ u32 count = len / tx_size;
+ u32 extra = len % tx_size;
+ unsigned int i, j = 0;
+ u8 padding[32];
+ int r = 0;
+
+ memset(padding, 0, sizeof(padding));
+
+ for (i = 0; i < count ; i++) {
+ r = spi_xmit(spi_dev, (void *)addr + j, tx_size, SPI_DIR_TX);
+ if (r < 0)
+ return r;
+ j += tx_size;
+ }
+
+ if (extra > 0) {
+ r = spi_xmit(spi_dev, (void *)addr + j, extra, SPI_DIR_TX);
+ if (r < 0)
+ return r;
+ }
+
+ return spi_xmit(spi_dev, padding, sizeof(padding), SPI_DIR_TX);
+}
+
+int s5c73m3_spi_read(struct s5c73m3 *state, void *addr,
+ const unsigned int len, const unsigned int tx_size)
+{
+ struct spi_device *spi_dev = state->spi_dev;
+ u32 count = len / tx_size;
+ u32 extra = len % tx_size;
+ unsigned int i, j = 0;
+ int r = 0;
+
+ for (i = 0; i < count ; i++) {
+ r = spi_xmit(spi_dev, addr + j, tx_size, SPI_DIR_RX);
+ if (r < 0)
+ return r;
+ j += tx_size;
+ }
+
+ if (extra > 0)
+ return spi_xmit(spi_dev, addr + j, extra, SPI_DIR_RX);
+
+ return 0;
+}
+
+static int s5c73m3_spi_probe(struct spi_device *spi)
+{
+ int r;
+ struct s5c73m3 *state = container_of(spi->dev.driver, struct s5c73m3,
+ spidrv.driver);
+ spi->bits_per_word = 32;
+
+ r = spi_setup(spi);
+ if (r < 0) {
+ dev_err(&spi->dev, "spi_setup() failed\n");
+ return r;
+ }
+
+ mutex_lock(&state->lock);
+ state->spi_dev = spi;
+ mutex_unlock(&state->lock);
+
+ v4l2_info(&state->sensor_sd, "S5C73M3 SPI probed successfully\n");
+ return 0;
+}
+
+static int s5c73m3_spi_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+int s5c73m3_register_spi_driver(struct s5c73m3 *state)
+{
+ struct spi_driver *spidrv = &state->spidrv;
+
+ spidrv->remove = s5c73m3_spi_remove;
+ spidrv->probe = s5c73m3_spi_probe;
+ spidrv->driver.name = S5C73M3_SPI_DRV_NAME;
+ spidrv->driver.bus = &spi_bus_type;
+ spidrv->driver.owner = THIS_MODULE;
+
+ return spi_register_driver(spidrv);
+}
+
+void s5c73m3_unregister_spi_driver(struct s5c73m3 *state)
+{
+ spi_unregister_driver(&state->spidrv);
+}
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h
new file mode 100644
index 000000000000..9d2c08652246
--- /dev/null
+++ b/drivers/media/i2c/s5c73m3/s5c73m3.h
@@ -0,0 +1,459 @@
+/*
+ * Samsung LSI S5C73M3 8M pixel camera driver
+ *
+ * Copyright (C) 2012, Samsung Electronics, Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Andrzej Hajda <a.hajda@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 S5C73M3_H_
+#define S5C73M3_H_
+
+#include <linux/kernel.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <media/s5c73m3.h>
+
+#define DRIVER_NAME "S5C73M3"
+
+#define S5C73M3_ISP_FMT V4L2_MBUS_FMT_VYUY8_2X8
+#define S5C73M3_JPEG_FMT V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8
+
+/* Subdevs pad index definitions */
+enum s5c73m3_pads {
+ S5C73M3_ISP_PAD,
+ S5C73M3_JPEG_PAD,
+ S5C73M3_NUM_PADS
+};
+
+enum s5c73m3_oif_pads {
+ OIF_ISP_PAD,
+ OIF_JPEG_PAD,
+ OIF_SOURCE_PAD,
+ OIF_NUM_PADS
+};
+
+#define S5C73M3_SENSOR_FW_LEN 6
+#define S5C73M3_SENSOR_TYPE_LEN 12
+
+#define S5C73M3_REG(_addrh, _addrl) (((_addrh) << 16) | _addrl)
+
+#define AHB_MSB_ADDR_PTR 0xfcfc
+#define REG_CMDWR_ADDRH 0x0050
+#define REG_CMDWR_ADDRL 0x0054
+#define REG_CMDRD_ADDRH 0x0058
+#define REG_CMDRD_ADDRL 0x005c
+#define REG_CMDBUF_ADDR 0x0f14
+
+#define REG_I2C_SEQ_STATUS S5C73M3_REG(0x0009, 0x59A6)
+#define SEQ_END_PLL (1<<0x0)
+#define SEQ_END_SENSOR (1<<0x1)
+#define SEQ_END_GPIO (1<<0x2)
+#define SEQ_END_FROM (1<<0x3)
+#define SEQ_END_STABLE_AE_AWB (1<<0x4)
+#define SEQ_END_READY_I2C_CMD (1<<0x5)
+
+#define REG_I2C_STATUS S5C73M3_REG(0x0009, 0x599E)
+#define I2C_STATUS_CIS_I2C (1<<0x0)
+#define I2C_STATUS_AF_INIT (1<<0x1)
+#define I2C_STATUS_CAL_DATA (1<<0x2)
+#define I2C_STATUS_FRAME_COUNT (1<<0x3)
+#define I2C_STATUS_FROM_INIT (1<<0x4)
+#define I2C_STATUS_I2C_CIS_STREAM_OFF (1<<0x5)
+#define I2C_STATUS_I2C_N_CMD_OVER (1<<0x6)
+#define I2C_STATUS_I2C_N_CMD_MISMATCH (1<<0x7)
+#define I2C_STATUS_CHECK_BIN_CRC (1<<0x8)
+#define I2C_STATUS_EXCEPTION (1<<0x9)
+#define I2C_STATUS_INIF_INIT_STATE (0x8)
+
+#define REG_STATUS S5C73M3_REG(0x0009, 0x5080)
+#define REG_STATUS_BOOT_SUB_MAIN_ENTER 0xff01
+#define REG_STATUS_BOOT_SRAM_TIMING_OK 0xff02
+#define REG_STATUS_BOOT_INTERRUPTS_EN 0xff03
+#define REG_STATUS_BOOT_R_PLL_DONE 0xff04
+#define REG_STATUS_BOOT_R_PLL_LOCKTIME_DONE 0xff05
+#define REG_STATUS_BOOT_DELAY_COUNT_DONE 0xff06
+#define REG_STATUS_BOOT_I_PLL_DONE 0xff07
+#define REG_STATUS_BOOT_I_PLL_LOCKTIME_DONE 0xff08
+#define REG_STATUS_BOOT_PLL_INIT_OK 0xff09
+#define REG_STATUS_BOOT_SENSOR_INIT_OK 0xff0a
+#define REG_STATUS_BOOT_GPIO_SETTING_OK 0xff0b
+#define REG_STATUS_BOOT_READ_CAL_DATA_OK 0xff0c
+#define REG_STATUS_BOOT_STABLE_AE_AWB_OK 0xff0d
+#define REG_STATUS_ISP_COMMAND_COMPLETED 0xffff
+#define REG_STATUS_EXCEPTION_OCCURED 0xdead
+
+#define COMM_RESULT_OFFSET S5C73M3_REG(0x0009, 0x5000)
+
+#define COMM_IMG_OUTPUT 0x0902
+#define COMM_IMG_OUTPUT_HDR 0x0008
+#define COMM_IMG_OUTPUT_YUV 0x0009
+#define COMM_IMG_OUTPUT_INTERLEAVED 0x000d
+
+#define COMM_STILL_PRE_FLASH 0x0a00
+#define COMM_STILL_PRE_FLASH_FIRE 0x0000
+#define COMM_STILL_PRE_FLASH_NON_FIRED 0x0000
+#define COMM_STILL_PRE_FLASH_FIRED 0x0001
+
+#define COMM_STILL_MAIN_FLASH 0x0a02
+#define COMM_STILL_MAIN_FLASH_CANCEL 0x0001
+#define COMM_STILL_MAIN_FLASH_FIRE 0x0002
+
+#define COMM_ZOOM_STEP 0x0b00
+
+#define COMM_IMAGE_EFFECT 0x0b0a
+#define COMM_IMAGE_EFFECT_NONE 0x0001
+#define COMM_IMAGE_EFFECT_NEGATIVE 0x0002
+#define COMM_IMAGE_EFFECT_AQUA 0x0003
+#define COMM_IMAGE_EFFECT_SEPIA 0x0004
+#define COMM_IMAGE_EFFECT_MONO 0x0005
+
+#define COMM_IMAGE_QUALITY 0x0b0c
+#define COMM_IMAGE_QUALITY_SUPERFINE 0x0000
+#define COMM_IMAGE_QUALITY_FINE 0x0001
+#define COMM_IMAGE_QUALITY_NORMAL 0x0002
+
+#define COMM_FLASH_MODE 0x0b0e
+#define COMM_FLASH_MODE_OFF 0x0000
+#define COMM_FLASH_MODE_ON 0x0001
+#define COMM_FLASH_MODE_AUTO 0x0002
+
+#define COMM_FLASH_STATUS 0x0b80
+#define COMM_FLASH_STATUS_OFF 0x0001
+#define COMM_FLASH_STATUS_ON 0x0002
+#define COMM_FLASH_STATUS_AUTO 0x0003
+
+#define COMM_FLASH_TORCH 0x0b12
+#define COMM_FLASH_TORCH_OFF 0x0000
+#define COMM_FLASH_TORCH_ON 0x0001
+
+#define COMM_AE_NEEDS_FLASH 0x0cba
+#define COMM_AE_NEEDS_FLASH_OFF 0x0000
+#define COMM_AE_NEEDS_FLASH_ON 0x0001
+
+#define COMM_CHG_MODE 0x0b10
+#define COMM_CHG_MODE_NEW 0x8000
+#define COMM_CHG_MODE_SUBSAMPLING_HALF 0x2000
+#define COMM_CHG_MODE_SUBSAMPLING_QUARTER 0x4000
+
+#define COMM_CHG_MODE_YUV_320_240 0x0001
+#define COMM_CHG_MODE_YUV_640_480 0x0002
+#define COMM_CHG_MODE_YUV_880_720 0x0003
+#define COMM_CHG_MODE_YUV_960_720 0x0004
+#define COMM_CHG_MODE_YUV_1184_666 0x0005
+#define COMM_CHG_MODE_YUV_1280_720 0x0006
+#define COMM_CHG_MODE_YUV_1536_864 0x0007
+#define COMM_CHG_MODE_YUV_1600_1200 0x0008
+#define COMM_CHG_MODE_YUV_1632_1224 0x0009
+#define COMM_CHG_MODE_YUV_1920_1080 0x000a
+#define COMM_CHG_MODE_YUV_1920_1440 0x000b
+#define COMM_CHG_MODE_YUV_2304_1296 0x000c
+#define COMM_CHG_MODE_YUV_3264_2448 0x000d
+#define COMM_CHG_MODE_YUV_352_288 0x000e
+#define COMM_CHG_MODE_YUV_1008_672 0x000f
+
+#define COMM_CHG_MODE_JPEG_640_480 0x0010
+#define COMM_CHG_MODE_JPEG_800_450 0x0020
+#define COMM_CHG_MODE_JPEG_800_600 0x0030
+#define COMM_CHG_MODE_JPEG_1280_720 0x0040
+#define COMM_CHG_MODE_JPEG_1280_960 0x0050
+#define COMM_CHG_MODE_JPEG_1600_900 0x0060
+#define COMM_CHG_MODE_JPEG_1600_1200 0x0070
+#define COMM_CHG_MODE_JPEG_2048_1152 0x0080
+#define COMM_CHG_MODE_JPEG_2048_1536 0x0090
+#define COMM_CHG_MODE_JPEG_2560_1440 0x00a0
+#define COMM_CHG_MODE_JPEG_2560_1920 0x00b0
+#define COMM_CHG_MODE_JPEG_3264_2176 0x00c0
+#define COMM_CHG_MODE_JPEG_1024_768 0x00d0
+#define COMM_CHG_MODE_JPEG_3264_1836 0x00e0
+#define COMM_CHG_MODE_JPEG_3264_2448 0x00f0
+
+#define COMM_AF_CON 0x0e00
+#define COMM_AF_CON_STOP 0x0000
+#define COMM_AF_CON_SCAN 0x0001 /* Full Search */
+#define COMM_AF_CON_START 0x0002 /* Fast Search */
+
+#define COMM_AF_CAL 0x0e06
+#define COMM_AF_TOUCH_AF 0x0e0a
+
+#define REG_AF_STATUS S5C73M3_REG(0x0009, 0x5e80)
+#define REG_CAF_STATUS_FIND_SEARCH_DIR 0x0001
+#define REG_CAF_STATUS_FOCUSING 0x0002
+#define REG_CAF_STATUS_FOCUSED 0x0003
+#define REG_CAF_STATUS_UNFOCUSED 0x0004
+#define REG_AF_STATUS_INVALID 0x0010
+#define REG_AF_STATUS_FOCUSING 0x0020
+#define REG_AF_STATUS_FOCUSED 0x0030
+#define REG_AF_STATUS_UNFOCUSED 0x0040
+
+#define REG_AF_TOUCH_POSITION S5C73M3_REG(0x0009, 0x5e8e)
+#define COMM_AF_FACE_ZOOM 0x0e10
+
+#define COMM_AF_MODE 0x0e02
+#define COMM_AF_MODE_NORMAL 0x0000
+#define COMM_AF_MODE_MACRO 0x0001
+#define COMM_AF_MODE_MOVIE_CAF_START 0x0002
+#define COMM_AF_MODE_MOVIE_CAF_STOP 0x0003
+#define COMM_AF_MODE_PREVIEW_CAF_START 0x0004
+#define COMM_AF_MODE_PREVIEW_CAF_STOP 0x0005
+
+#define COMM_AF_SOFTLANDING 0x0e16
+#define COMM_AF_SOFTLANDING_ON 0x0000
+#define COMM_AF_SOFTLANDING_RES_COMPLETE 0x0001
+
+#define COMM_FACE_DET 0x0e0c
+#define COMM_FACE_DET_OFF 0x0000
+#define COMM_FACE_DET_ON 0x0001
+
+#define COMM_FACE_DET_OSD 0x0e0e
+#define COMM_FACE_DET_OSD_OFF 0x0000
+#define COMM_FACE_DET_OSD_ON 0x0001
+
+#define COMM_AE_CON 0x0c00
+#define COMM_AE_STOP 0x0000 /* lock */
+#define COMM_AE_START 0x0001 /* unlock */
+
+#define COMM_ISO 0x0c02
+#define COMM_ISO_AUTO 0x0000
+#define COMM_ISO_100 0x0001
+#define COMM_ISO_200 0x0002
+#define COMM_ISO_400 0x0003
+#define COMM_ISO_800 0x0004
+#define COMM_ISO_SPORTS 0x0005
+#define COMM_ISO_NIGHT 0x0006
+#define COMM_ISO_INDOOR 0x0007
+
+/* 0x00000 (-2.0 EV)...0x0008 (2.0 EV), 0.5EV step */
+#define COMM_EV 0x0c04
+
+#define COMM_METERING 0x0c06
+#define COMM_METERING_CENTER 0x0000
+#define COMM_METERING_SPOT 0x0001
+#define COMM_METERING_AVERAGE 0x0002
+#define COMM_METERING_SMART 0x0003
+
+#define COMM_WDR 0x0c08
+#define COMM_WDR_OFF 0x0000
+#define COMM_WDR_ON 0x0001
+
+#define COMM_FLICKER_MODE 0x0c12
+#define COMM_FLICKER_NONE 0x0000
+#define COMM_FLICKER_MANUAL_50HZ 0x0001
+#define COMM_FLICKER_MANUAL_60HZ 0x0002
+#define COMM_FLICKER_AUTO 0x0003
+#define COMM_FLICKER_AUTO_50HZ 0x0004
+#define COMM_FLICKER_AUTO_60HZ 0x0005
+
+#define COMM_FRAME_RATE 0x0c1e
+#define COMM_FRAME_RATE_AUTO_SET 0x0000
+#define COMM_FRAME_RATE_FIXED_30FPS 0x0002
+#define COMM_FRAME_RATE_FIXED_20FPS 0x0003
+#define COMM_FRAME_RATE_FIXED_15FPS 0x0004
+#define COMM_FRAME_RATE_FIXED_60FPS 0x0007
+#define COMM_FRAME_RATE_FIXED_120FPS 0x0008
+#define COMM_FRAME_RATE_FIXED_7FPS 0x0009
+#define COMM_FRAME_RATE_FIXED_10FPS 0x000a
+#define COMM_FRAME_RATE_FIXED_90FPS 0x000b
+#define COMM_FRAME_RATE_ANTI_SHAKE 0x0013
+
+/* 0x0000...0x0004 -> sharpness: 0, 1, 2, -1, -2 */
+#define COMM_SHARPNESS 0x0c14
+
+/* 0x0000...0x0004 -> saturation: 0, 1, 2, -1, -2 */
+#define COMM_SATURATION 0x0c16
+
+/* 0x0000...0x0004 -> contrast: 0, 1, 2, -1, -2 */
+#define COMM_CONTRAST 0x0c18
+
+#define COMM_SCENE_MODE 0x0c1a
+#define COMM_SCENE_MODE_NONE 0x0000
+#define COMM_SCENE_MODE_PORTRAIT 0x0001
+#define COMM_SCENE_MODE_LANDSCAPE 0x0002
+#define COMM_SCENE_MODE_SPORTS 0x0003
+#define COMM_SCENE_MODE_INDOOR 0x0004
+#define COMM_SCENE_MODE_BEACH 0x0005
+#define COMM_SCENE_MODE_SUNSET 0x0006
+#define COMM_SCENE_MODE_DAWN 0x0007
+#define COMM_SCENE_MODE_FALL 0x0008
+#define COMM_SCENE_MODE_NIGHT 0x0009
+#define COMM_SCENE_MODE_AGAINST_LIGHT 0x000a
+#define COMM_SCENE_MODE_FIRE 0x000b
+#define COMM_SCENE_MODE_TEXT 0x000c
+#define COMM_SCENE_MODE_CANDLE 0x000d
+
+#define COMM_AE_AUTO_BRACKET 0x0b14
+#define COMM_AE_AUTO_BRAKET_EV05 0x0080
+#define COMM_AE_AUTO_BRAKET_EV10 0x0100
+#define COMM_AE_AUTO_BRAKET_EV15 0x0180
+#define COMM_AE_AUTO_BRAKET_EV20 0x0200
+
+#define COMM_SENSOR_STREAMING 0x090a
+#define COMM_SENSOR_STREAMING_OFF 0x0000
+#define COMM_SENSOR_STREAMING_ON 0x0001
+
+#define COMM_AWB_MODE 0x0d02
+#define COMM_AWB_MODE_INCANDESCENT 0x0000
+#define COMM_AWB_MODE_FLUORESCENT1 0x0001
+#define COMM_AWB_MODE_FLUORESCENT2 0x0002
+#define COMM_AWB_MODE_DAYLIGHT 0x0003
+#define COMM_AWB_MODE_CLOUDY 0x0004
+#define COMM_AWB_MODE_AUTO 0x0005
+
+#define COMM_AWB_CON 0x0d00
+#define COMM_AWB_STOP 0x0000 /* lock */
+#define COMM_AWB_START 0x0001 /* unlock */
+
+#define COMM_FW_UPDATE 0x0906
+#define COMM_FW_UPDATE_NOT_READY 0x0000
+#define COMM_FW_UPDATE_SUCCESS 0x0005
+#define COMM_FW_UPDATE_FAIL 0x0007
+#define COMM_FW_UPDATE_BUSY 0xffff
+
+
+#define S5C73M3_MAX_SUPPLIES 6
+
+struct s5c73m3_ctrls {
+ struct v4l2_ctrl_handler handler;
+ struct {
+ /* exposure/exposure bias cluster */
+ struct v4l2_ctrl *auto_exposure;
+ struct v4l2_ctrl *exposure_bias;
+ struct v4l2_ctrl *exposure_metering;
+ };
+ struct {
+ /* iso/auto iso cluster */
+ struct v4l2_ctrl *auto_iso;
+ struct v4l2_ctrl *iso;
+ };
+ struct v4l2_ctrl *auto_wb;
+ struct {
+ /* continuous auto focus/auto focus cluster */
+ struct v4l2_ctrl *focus_auto;
+ struct v4l2_ctrl *af_start;
+ struct v4l2_ctrl *af_stop;
+ struct v4l2_ctrl *af_status;
+ struct v4l2_ctrl *af_distance;
+ };
+
+ struct v4l2_ctrl *aaa_lock;
+ struct v4l2_ctrl *colorfx;
+ struct v4l2_ctrl *contrast;
+ struct v4l2_ctrl *saturation;
+ struct v4l2_ctrl *sharpness;
+ struct v4l2_ctrl *zoom;
+ struct v4l2_ctrl *wdr;
+ struct v4l2_ctrl *stabilization;
+ struct v4l2_ctrl *jpeg_quality;
+ struct v4l2_ctrl *scene_mode;
+};
+
+enum s5c73m3_gpio_id {
+ STBY,
+ RST,
+ GPIO_NUM,
+};
+
+enum s5c73m3_resolution_types {
+ RES_ISP,
+ RES_JPEG,
+};
+
+struct s5c73m3_interval {
+ u16 fps_reg;
+ struct v4l2_fract interval;
+ /* Maximum rectangle for the interval */
+ struct v4l2_frmsize_discrete size;
+};
+
+struct s5c73m3 {
+ struct v4l2_subdev sensor_sd;
+ struct media_pad sensor_pads[S5C73M3_NUM_PADS];
+
+ struct v4l2_subdev oif_sd;
+ struct media_pad oif_pads[OIF_NUM_PADS];
+
+ struct spi_driver spidrv;
+ struct spi_device *spi_dev;
+ struct i2c_client *i2c_client;
+ u32 i2c_write_address;
+ u32 i2c_read_address;
+
+ struct regulator_bulk_data supplies[S5C73M3_MAX_SUPPLIES];
+ struct s5c73m3_gpio gpio[GPIO_NUM];
+
+ /* External master clock frequency */
+ u32 mclk_frequency;
+ /* Video bus type - MIPI-CSI2/paralell */
+ enum v4l2_mbus_type bus_type;
+
+ const struct s5c73m3_frame_size *sensor_pix_size[2];
+ const struct s5c73m3_frame_size *oif_pix_size[2];
+ enum v4l2_mbus_pixelcode mbus_code;
+
+ const struct s5c73m3_interval *fiv;
+
+ struct v4l2_mbus_frame_desc frame_desc;
+ /* protects the struct members below */
+ struct mutex lock;
+
+ struct s5c73m3_ctrls ctrls;
+
+ u8 streaming:1;
+ u8 apply_fmt:1;
+ u8 apply_fiv:1;
+ u8 isp_ready:1;
+
+ short power;
+
+ char sensor_fw[S5C73M3_SENSOR_FW_LEN + 2];
+ char sensor_type[S5C73M3_SENSOR_TYPE_LEN + 2];
+ char fw_file_version[2];
+ unsigned int fw_size;
+};
+
+struct s5c73m3_frame_size {
+ u32 width;
+ u32 height;
+ u8 reg_val;
+};
+
+extern int s5c73m3_dbg;
+
+int s5c73m3_register_spi_driver(struct s5c73m3 *state);
+void s5c73m3_unregister_spi_driver(struct s5c73m3 *state);
+int s5c73m3_spi_write(struct s5c73m3 *state, const void *addr,
+ const unsigned int len, const unsigned int tx_size);
+int s5c73m3_spi_read(struct s5c73m3 *state, void *addr,
+ const unsigned int len, const unsigned int tx_size);
+
+int s5c73m3_read(struct s5c73m3 *state, u32 addr, u16 *data);
+int s5c73m3_write(struct s5c73m3 *state, u32 addr, u16 data);
+int s5c73m3_isp_command(struct s5c73m3 *state, u16 command, u16 data);
+int s5c73m3_init_controls(struct s5c73m3 *state);
+
+static inline struct v4l2_subdev *ctrl_to_sensor_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct s5c73m3,
+ ctrls.handler)->sensor_sd;
+}
+
+static inline struct s5c73m3 *sensor_sd_to_s5c73m3(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct s5c73m3, sensor_sd);
+}
+
+static inline struct s5c73m3 *oif_sd_to_s5c73m3(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct s5c73m3, oif_sd);
+}
+#endif /* S5C73M3_H_ */
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index 57cd4fa0193d..bdf5e3db31d1 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -1598,7 +1598,7 @@ static int s5k6aa_probe(struct i2c_client *client,
for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++)
s5k6aa->supplies[i].supply = s5k6aa_supply_names[i];
- ret = regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES,
+ ret = devm_regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES,
s5k6aa->supplies);
if (ret) {
dev_err(&client->dev, "Failed to get regulators\n");
@@ -1607,7 +1607,7 @@ static int s5k6aa_probe(struct i2c_client *client,
ret = s5k6aa_initialize_ctrls(s5k6aa);
if (ret)
- goto out_err4;
+ goto out_err3;
s5k6aa_presets_data_init(s5k6aa);
@@ -1618,8 +1618,6 @@ static int s5k6aa_probe(struct i2c_client *client,
return 0;
-out_err4:
- regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
out_err3:
s5k6aa_free_gpios(s5k6aa);
out_err2:
@@ -1635,7 +1633,6 @@ static int s5k6aa_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(sd->ctrl_handler);
media_entity_cleanup(&sd->entity);
- regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies);
s5k6aa_free_gpios(s5k6aa);
return 0;
diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c
index f8534eec9de9..a2a5cbbdbe28 100644
--- a/drivers/media/i2c/soc_camera/imx074.c
+++ b/drivers/media/i2c/soc_camera/imx074.c
@@ -271,9 +271,9 @@ static int imx074_g_chip_ident(struct v4l2_subdev *sd,
static int imx074_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, ssdd, on);
}
static int imx074_g_mbus_config(struct v4l2_subdev *sd,
@@ -430,10 +430,9 @@ static int imx074_probe(struct i2c_client *client,
{
struct imx074 *priv;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- if (!icl) {
+ if (!ssdd) {
dev_err(&client->dev, "IMX074: missing platform data!\n");
return -EINVAL;
}
@@ -444,7 +443,7 @@ static int imx074_probe(struct i2c_client *client,
return -EIO;
}
- priv = kzalloc(sizeof(struct imx074), GFP_KERNEL);
+ priv = devm_kzalloc(&client->dev, sizeof(struct imx074), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -452,23 +451,15 @@ static int imx074_probe(struct i2c_client *client,
priv->fmt = &imx074_colour_fmts[0];
- ret = imx074_video_probe(client);
- if (ret < 0) {
- kfree(priv);
- return ret;
- }
-
- return ret;
+ return imx074_video_probe(client);
}
static int imx074_remove(struct i2c_client *client)
{
- struct imx074 *priv = to_imx074(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- if (icl->free_bus)
- icl->free_bus(icl);
- kfree(priv);
+ if (ssdd->free_bus)
+ ssdd->free_bus(ssdd);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c
index 19f8a07764f9..bcdc86175549 100644
--- a/drivers/media/i2c/soc_camera/mt9m001.c
+++ b/drivers/media/i2c/soc_camera/mt9m001.c
@@ -23,7 +23,7 @@
/*
* mt9m001 i2c address 0x5d
* The platform has to define struct i2c_board_info objects and link to them
- * from struct soc_camera_link
+ * from struct soc_camera_host_desc
*/
/* mt9m001 selected register addresses */
@@ -380,9 +380,9 @@ static int mt9m001_s_register(struct v4l2_subdev *sd,
static int mt9m001_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, ssdd, on);
}
static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -482,7 +482,7 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one
*/
-static int mt9m001_video_probe(struct soc_camera_link *icl,
+static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd,
struct i2c_client *client)
{
struct mt9m001 *mt9m001 = to_mt9m001(client);
@@ -526,8 +526,8 @@ static int mt9m001_video_probe(struct soc_camera_link *icl,
* The platform may support different bus widths due to
* different routing of the data lines.
*/
- if (icl->query_bus_param)
- flags = icl->query_bus_param(icl);
+ if (ssdd->query_bus_param)
+ flags = ssdd->query_bus_param(ssdd);
else
flags = SOCAM_DATAWIDTH_10;
@@ -558,10 +558,10 @@ done:
return ret;
}
-static void mt9m001_video_remove(struct soc_camera_link *icl)
+static void mt9m001_video_remove(struct soc_camera_subdev_desc *ssdd)
{
- if (icl->free_bus)
- icl->free_bus(icl);
+ if (ssdd->free_bus)
+ ssdd->free_bus(ssdd);
}
static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
@@ -605,14 +605,14 @@ static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
/* MT9M001 has all capture_format parameters fixed */
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -621,12 +621,12 @@ static int mt9m001_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
const struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct mt9m001 *mt9m001 = to_mt9m001(client);
unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample;
- if (icl->set_bus_param)
- return icl->set_bus_param(icl, 1 << (bps - 1));
+ if (ssdd->set_bus_param)
+ return ssdd->set_bus_param(ssdd, 1 << (bps - 1));
/*
* Without board specific bus width settings we only support the
@@ -663,10 +663,10 @@ static int mt9m001_probe(struct i2c_client *client,
{
struct mt9m001 *mt9m001;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
- if (!icl) {
+ if (!ssdd) {
dev_err(&client->dev, "MT9M001 driver needs platform data\n");
return -EINVAL;
}
@@ -677,7 +677,7 @@ static int mt9m001_probe(struct i2c_client *client,
return -EIO;
}
- mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL);
+ mt9m001 = devm_kzalloc(&client->dev, sizeof(struct mt9m001), GFP_KERNEL);
if (!mt9m001)
return -ENOMEM;
@@ -697,12 +697,9 @@ static int mt9m001_probe(struct i2c_client *client,
&mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
V4L2_EXPOSURE_AUTO);
mt9m001->subdev.ctrl_handler = &mt9m001->hdl;
- if (mt9m001->hdl.error) {
- int err = mt9m001->hdl.error;
+ if (mt9m001->hdl.error)
+ return mt9m001->hdl.error;
- kfree(mt9m001);
- return err;
- }
v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure,
V4L2_EXPOSURE_MANUAL, true);
@@ -713,11 +710,9 @@ static int mt9m001_probe(struct i2c_client *client,
mt9m001->rect.width = MT9M001_MAX_WIDTH;
mt9m001->rect.height = MT9M001_MAX_HEIGHT;
- ret = mt9m001_video_probe(icl, client);
- if (ret) {
+ ret = mt9m001_video_probe(ssdd, client);
+ if (ret)
v4l2_ctrl_handler_free(&mt9m001->hdl);
- kfree(mt9m001);
- }
return ret;
}
@@ -725,12 +720,11 @@ static int mt9m001_probe(struct i2c_client *client,
static int mt9m001_remove(struct i2c_client *client)
{
struct mt9m001 *mt9m001 = to_mt9m001(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
v4l2_device_unregister_subdev(&mt9m001->subdev);
v4l2_ctrl_handler_free(&mt9m001->hdl);
- mt9m001_video_remove(icl);
- kfree(mt9m001);
+ mt9m001_video_remove(ssdd);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c
index 62fd94af599b..bbc4ff99603c 100644
--- a/drivers/media/i2c/soc_camera/mt9m111.c
+++ b/drivers/media/i2c/soc_camera/mt9m111.c
@@ -24,7 +24,8 @@
/*
* MT9M111, MT9M112 and MT9M131:
* i2c address is 0x48 or 0x5d (depending on SADDR pin)
- * The platform has to define i2c_board_info and call i2c_register_board_info()
+ * The platform has to define struct i2c_board_info objects and link to them
+ * from struct soc_camera_host_desc
*/
/*
@@ -799,17 +800,17 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
static int mt9m111_power_on(struct mt9m111 *mt9m111)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
- ret = soc_camera_power_on(&client->dev, icl);
+ ret = soc_camera_power_on(&client->dev, ssdd);
if (ret < 0)
return ret;
ret = mt9m111_resume(mt9m111);
if (ret < 0) {
dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret);
- soc_camera_power_off(&client->dev, icl);
+ soc_camera_power_off(&client->dev, ssdd);
}
return ret;
@@ -818,10 +819,10 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111)
static void mt9m111_power_off(struct mt9m111 *mt9m111)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
mt9m111_suspend(mt9m111);
- soc_camera_power_off(&client->dev, icl);
+ soc_camera_power_off(&client->dev, ssdd);
}
static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
@@ -879,13 +880,13 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -956,10 +957,10 @@ static int mt9m111_probe(struct i2c_client *client,
{
struct mt9m111 *mt9m111;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
- if (!icl) {
+ if (!ssdd) {
dev_err(&client->dev, "mt9m111: driver needs platform data\n");
return -EINVAL;
}
@@ -970,7 +971,7 @@ static int mt9m111_probe(struct i2c_client *client,
return -EIO;
}
- mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL);
+ mt9m111 = devm_kzalloc(&client->dev, sizeof(struct mt9m111), GFP_KERNEL);
if (!mt9m111)
return -ENOMEM;
@@ -988,12 +989,8 @@ static int mt9m111_probe(struct i2c_client *client,
&mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
V4L2_EXPOSURE_AUTO);
mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
- if (mt9m111->hdl.error) {
- int err = mt9m111->hdl.error;
-
- kfree(mt9m111);
- return err;
- }
+ if (mt9m111->hdl.error)
+ return mt9m111->hdl.error;
/* Second stage probe - when a capture adapter is there */
mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
@@ -1005,10 +1002,8 @@ static int mt9m111_probe(struct i2c_client *client,
mutex_init(&mt9m111->power_lock);
ret = mt9m111_video_probe(client);
- if (ret) {
+ if (ret)
v4l2_ctrl_handler_free(&mt9m111->hdl);
- kfree(mt9m111);
- }
return ret;
}
@@ -1019,7 +1014,6 @@ static int mt9m111_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(&mt9m111->subdev);
v4l2_ctrl_handler_free(&mt9m111->hdl);
- kfree(mt9m111);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c
index 40800b10a080..d80d044ebf15 100644
--- a/drivers/media/i2c/soc_camera/mt9t031.c
+++ b/drivers/media/i2c/soc_camera/mt9t031.c
@@ -31,8 +31,8 @@
/*
* mt9t031 i2c address 0x5d
- * The platform has to define i2c_board_info and link to it from
- * struct soc_camera_link
+ * The platform has to define struct i2c_board_info objects and link to them
+ * from struct soc_camera_host_desc
*/
/* mt9t031 selected register addresses */
@@ -608,18 +608,18 @@ static struct device_type mt9t031_dev_type = {
static int mt9t031_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct video_device *vdev = soc_camera_i2c_to_vdev(client);
int ret;
if (on) {
- ret = soc_camera_power_on(&client->dev, icl);
+ ret = soc_camera_power_on(&client->dev, ssdd);
if (ret < 0)
return ret;
vdev->dev.type = &mt9t031_dev_type;
} else {
vdev->dev.type = NULL;
- soc_camera_power_off(&client->dev, icl);
+ soc_camera_power_off(&client->dev, ssdd);
}
return 0;
@@ -707,13 +707,13 @@ static int mt9t031_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -722,9 +722,9 @@ static int mt9t031_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- if (soc_camera_apply_board_flags(icl, cfg) &
+ if (soc_camera_apply_board_flags(ssdd, cfg) &
V4L2_MBUS_PCLK_SAMPLE_FALLING)
return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
else
@@ -758,11 +758,11 @@ static int mt9t031_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9t031 *mt9t031;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret;
- if (!icl) {
+ if (!ssdd) {
dev_err(&client->dev, "MT9T031 driver needs platform data\n");
return -EINVAL;
}
@@ -773,7 +773,7 @@ static int mt9t031_probe(struct i2c_client *client,
return -EIO;
}
- mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL);
+ mt9t031 = devm_kzalloc(&client->dev, sizeof(struct mt9t031), GFP_KERNEL);
if (!mt9t031)
return -ENOMEM;
@@ -797,12 +797,9 @@ static int mt9t031_probe(struct i2c_client *client,
V4L2_CID_EXPOSURE, 1, 255, 1, 255);
mt9t031->subdev.ctrl_handler = &mt9t031->hdl;
- if (mt9t031->hdl.error) {
- int err = mt9t031->hdl.error;
+ if (mt9t031->hdl.error)
+ return mt9t031->hdl.error;
- kfree(mt9t031);
- return err;
- }
v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure,
V4L2_EXPOSURE_MANUAL, true);
@@ -816,10 +813,8 @@ static int mt9t031_probe(struct i2c_client *client,
mt9t031->yskip = 1;
ret = mt9t031_video_probe(client);
- if (ret) {
+ if (ret)
v4l2_ctrl_handler_free(&mt9t031->hdl);
- kfree(mt9t031);
- }
return ret;
}
@@ -830,7 +825,6 @@ static int mt9t031_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(&mt9t031->subdev);
v4l2_ctrl_handler_free(&mt9t031->hdl);
- kfree(mt9t031);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
index de7cd836b0a2..188e29b03273 100644
--- a/drivers/media/i2c/soc_camera/mt9t112.c
+++ b/drivers/media/i2c/soc_camera/mt9t112.c
@@ -92,6 +92,7 @@ struct mt9t112_priv {
struct v4l2_rect frame;
const struct mt9t112_format *format;
int model;
+ int num_formats;
u32 flags;
/* for flags */
#define INIT_DONE (1 << 0)
@@ -779,9 +780,9 @@ static int mt9t112_s_register(struct v4l2_subdev *sd,
static int mt9t112_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, ssdd, on);
}
static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
@@ -859,11 +860,11 @@ static int mt9t112_set_params(struct mt9t112_priv *priv,
/*
* get color format
*/
- for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++)
+ for (i = 0; i < priv->num_formats; i++)
if (mt9t112_cfmts[i].code == code)
break;
- if (i == ARRAY_SIZE(mt9t112_cfmts))
+ if (i == priv->num_formats)
return -EINVAL;
priv->frame = *rect;
@@ -955,14 +956,16 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd,
static int mt9t112_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
unsigned int top, left;
int i;
- for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++)
+ for (i = 0; i < priv->num_formats; i++)
if (mt9t112_cfmts[i].code == mf->code)
break;
- if (i == ARRAY_SIZE(mt9t112_cfmts)) {
+ if (i == priv->num_formats) {
mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;
} else {
@@ -979,7 +982,10 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd,
static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if (index >= ARRAY_SIZE(mt9t112_cfmts))
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ if (index >= priv->num_formats)
return -EINVAL;
*code = mt9t112_cfmts[index].code;
@@ -991,13 +997,13 @@ static int mt9t112_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH |
V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -1006,10 +1012,10 @@ static int mt9t112_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct mt9t112_priv *priv = to_mt9t112(client);
- if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ if (soc_camera_apply_board_flags(ssdd, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING)
priv->flags |= PCLK_RISING;
return 0;
@@ -1056,10 +1062,12 @@ static int mt9t112_camera_probe(struct i2c_client *client)
case 0x2680:
devname = "mt9t111";
priv->model = V4L2_IDENT_MT9T111;
+ priv->num_formats = 1;
break;
case 0x2682:
devname = "mt9t112";
priv->model = V4L2_IDENT_MT9T112;
+ priv->num_formats = ARRAY_SIZE(mt9t112_cfmts);
break;
default:
dev_err(&client->dev, "Product ID error %04x\n", chipid);
@@ -1078,7 +1086,7 @@ static int mt9t112_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9t112_priv *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct v4l2_rect rect = {
.width = VGA_WIDTH,
.height = VGA_HEIGHT,
@@ -1087,24 +1095,22 @@ static int mt9t112_probe(struct i2c_client *client,
};
int ret;
- if (!icl || !icl->priv) {
+ if (!ssdd || !ssdd->drv_priv) {
dev_err(&client->dev, "mt9t112: missing platform data!\n");
return -EINVAL;
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->info = icl->priv;
+ priv->info = ssdd->drv_priv;
v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
ret = mt9t112_camera_probe(client);
- if (ret) {
- kfree(priv);
+ if (ret)
return ret;
- }
/* Cannot fail: using the default supported pixel code */
mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
@@ -1114,9 +1120,6 @@ static int mt9t112_probe(struct i2c_client *client,
static int mt9t112_remove(struct i2c_client *client)
{
- struct mt9t112_priv *priv = to_mt9t112(client);
-
- kfree(priv);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index d40a8858be01..a5e65d6a0781 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -25,7 +25,7 @@
/*
* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
* The platform has to define struct i2c_board_info objects and link to them
- * from struct soc_camera_link
+ * from struct soc_camera_host_desc
*/
static char *sensor_type;
@@ -508,9 +508,9 @@ static int mt9v022_s_register(struct v4l2_subdev *sd,
static int mt9v022_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, ssdd, on);
}
static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -655,7 +655,7 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
static int mt9v022_video_probe(struct i2c_client *client)
{
struct mt9v022 *mt9v022 = to_mt9v022(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
s32 data;
int ret;
unsigned long flags;
@@ -715,8 +715,8 @@ static int mt9v022_video_probe(struct i2c_client *client)
* The platform may support different bus widths due to
* different routing of the data lines.
*/
- if (icl->query_bus_param)
- flags = icl->query_bus_param(icl);
+ if (ssdd->query_bus_param)
+ flags = ssdd->query_bus_param(ssdd);
else
flags = SOCAM_DATAWIDTH_10;
@@ -784,7 +784,7 @@ static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
@@ -792,7 +792,7 @@ static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -801,15 +801,15 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct mt9v022 *mt9v022 = to_mt9v022(client);
- unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
+ unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg);
unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample;
int ret;
u16 pixclk = 0;
- if (icl->set_bus_param) {
- ret = icl->set_bus_param(icl, 1 << (bps - 1));
+ if (ssdd->set_bus_param) {
+ ret = ssdd->set_bus_param(ssdd, 1 << (bps - 1));
if (ret)
return ret;
} else if (bps != 10) {
@@ -873,12 +873,12 @@ static int mt9v022_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9v022 *mt9v022;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct mt9v022_platform_data *pdata = icl->priv;
+ struct mt9v022_platform_data *pdata;
int ret;
- if (!icl) {
+ if (!ssdd) {
dev_err(&client->dev, "MT9V022 driver needs platform data\n");
return -EINVAL;
}
@@ -889,10 +889,11 @@ static int mt9v022_probe(struct i2c_client *client,
return -EIO;
}
- mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL);
+ mt9v022 = devm_kzalloc(&client->dev, sizeof(struct mt9v022), GFP_KERNEL);
if (!mt9v022)
return -ENOMEM;
+ pdata = ssdd->drv_priv;
v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
v4l2_ctrl_handler_init(&mt9v022->hdl, 6);
v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
@@ -929,7 +930,6 @@ static int mt9v022_probe(struct i2c_client *client,
int err = mt9v022->hdl.error;
dev_err(&client->dev, "control initialisation err %d\n", err);
- kfree(mt9v022);
return err;
}
v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure,
@@ -949,10 +949,8 @@ static int mt9v022_probe(struct i2c_client *client,
mt9v022->rect.height = MT9V022_MAX_HEIGHT;
ret = mt9v022_video_probe(client);
- if (ret) {
+ if (ret)
v4l2_ctrl_handler_free(&mt9v022->hdl);
- kfree(mt9v022);
- }
return ret;
}
@@ -960,13 +958,12 @@ static int mt9v022_probe(struct i2c_client *client,
static int mt9v022_remove(struct i2c_client *client)
{
struct mt9v022 *mt9v022 = to_mt9v022(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
v4l2_device_unregister_subdev(&mt9v022->subdev);
- if (icl->free_bus)
- icl->free_bus(icl);
+ if (ssdd->free_bus)
+ ssdd->free_bus(ssdd);
v4l2_ctrl_handler_free(&mt9v022->hdl);
- kfree(mt9v022);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c
index 66698a83bda2..0f520f693b6e 100644
--- a/drivers/media/i2c/soc_camera/ov2640.c
+++ b/drivers/media/i2c/soc_camera/ov2640.c
@@ -771,9 +771,9 @@ static int ov2640_s_register(struct v4l2_subdev *sd,
static int ov2640_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, ssdd, on);
}
/* Select the nearest higher resolution for capture */
@@ -1046,13 +1046,13 @@ static int ov2640_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -1080,11 +1080,11 @@ static int ov2640_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov2640_priv *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret;
- if (!icl) {
+ if (!ssdd) {
dev_err(&adapter->dev,
"OV2640: Missing platform_data for driver\n");
return -EINVAL;
@@ -1096,7 +1096,7 @@ static int ov2640_probe(struct i2c_client *client,
return -EIO;
}
- priv = kzalloc(sizeof(struct ov2640_priv), GFP_KERNEL);
+ priv = devm_kzalloc(&client->dev, sizeof(struct ov2640_priv), GFP_KERNEL);
if (!priv) {
dev_err(&adapter->dev,
"Failed to allocate memory for private data!\n");
@@ -1110,20 +1110,14 @@ static int ov2640_probe(struct i2c_client *client,
v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error) {
- int err = priv->hdl.error;
-
- kfree(priv);
- return err;
- }
+ if (priv->hdl.error)
+ return priv->hdl.error;
ret = ov2640_video_probe(client);
- if (ret) {
+ if (ret)
v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- } else {
+ else
dev_info(&adapter->dev, "OV2640 Probed\n");
- }
return ret;
}
@@ -1134,7 +1128,6 @@ static int ov2640_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c
index 8577e0cfb7fe..9d53309619d2 100644
--- a/drivers/media/i2c/soc_camera/ov5642.c
+++ b/drivers/media/i2c/soc_camera/ov5642.c
@@ -934,13 +934,13 @@ static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
static int ov5642_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
if (!on)
- return soc_camera_power_off(&client->dev, icl);
+ return soc_camera_power_off(&client->dev, ssdd);
- ret = soc_camera_power_on(&client->dev, icl);
+ ret = soc_camera_power_on(&client->dev, ssdd);
if (ret < 0)
return ret;
@@ -1020,15 +1020,14 @@ static int ov5642_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov5642 *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- if (!icl) {
+ if (!ssdd) {
dev_err(&client->dev, "OV5642: missing platform data!\n");
return -EINVAL;
}
- priv = kzalloc(sizeof(struct ov5642), GFP_KERNEL);
+ priv = devm_kzalloc(&client->dev, sizeof(struct ov5642), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -1043,25 +1042,15 @@ static int ov5642_probe(struct i2c_client *client,
priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
priv->total_height = BLANKING_MIN_HEIGHT;
- ret = ov5642_video_probe(client);
- if (ret < 0)
- goto error;
-
- return 0;
-
-error:
- kfree(priv);
- return ret;
+ return ov5642_video_probe(client);
}
static int ov5642_remove(struct i2c_client *client)
{
- struct ov5642 *priv = to_ov5642(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- if (icl->free_bus)
- icl->free_bus(icl);
- kfree(priv);
+ if (ssdd->free_bus)
+ ssdd->free_bus(ssdd);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c
index e87feb0881e3..dbe4f564e6b2 100644
--- a/drivers/media/i2c/soc_camera/ov6650.c
+++ b/drivers/media/i2c/soc_camera/ov6650.c
@@ -435,9 +435,9 @@ static int ov6650_set_register(struct v4l2_subdev *sd,
static int ov6650_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, ssdd, on);
}
static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
@@ -892,7 +892,7 @@ static int ov6650_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_MASTER |
V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
@@ -900,7 +900,7 @@ static int ov6650_g_mbus_config(struct v4l2_subdev *sd,
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -910,8 +910,8 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+ unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg);
int ret;
if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
@@ -963,15 +963,15 @@ static int ov6650_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov6650 *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
- if (!icl) {
+ if (!ssdd) {
dev_err(&client->dev, "Missing platform_data for driver\n");
return -EINVAL;
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&client->dev,
"Failed to allocate memory for private data!\n");
@@ -1009,12 +1009,9 @@ static int ov6650_probe(struct i2c_client *client,
V4L2_CID_GAMMA, 0, 0xff, 1, 0x12);
priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error) {
- int err = priv->hdl.error;
+ if (priv->hdl.error)
+ return priv->hdl.error;
- kfree(priv);
- return err;
- }
v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true);
v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true);
v4l2_ctrl_auto_cluster(2, &priv->autoexposure,
@@ -1029,10 +1026,8 @@ static int ov6650_probe(struct i2c_client *client,
priv->colorspace = V4L2_COLORSPACE_JPEG;
ret = ov6650_video_probe(client);
- if (ret) {
+ if (ret)
v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- }
return ret;
}
@@ -1043,7 +1038,6 @@ static int ov6650_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
index e4a10751894d..fbeb5b2f3ae5 100644
--- a/drivers/media/i2c/soc_camera/ov772x.c
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -667,9 +667,9 @@ static int ov772x_s_register(struct v4l2_subdev *sd,
static int ov772x_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, ssdd, on);
}
static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
@@ -1019,13 +1019,13 @@ static int ov772x_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -1054,11 +1054,11 @@ static int ov772x_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov772x_priv *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret;
- if (!icl || !icl->priv) {
+ if (!ssdd || !ssdd->drv_priv) {
dev_err(&client->dev, "OV772X: missing platform data!\n");
return -EINVAL;
}
@@ -1070,11 +1070,11 @@ static int ov772x_probe(struct i2c_client *client,
return -EIO;
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->info = icl->priv;
+ priv->info = ssdd->drv_priv;
v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
v4l2_ctrl_handler_init(&priv->hdl, 3);
@@ -1085,22 +1085,15 @@ static int ov772x_probe(struct i2c_client *client,
v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error) {
- ret = priv->hdl.error;
- goto done;
- }
+ if (priv->hdl.error)
+ return priv->hdl.error;
ret = ov772x_video_probe(priv);
- if (ret < 0)
- goto done;
-
- priv->cfmt = &ov772x_cfmts[0];
- priv->win = &ov772x_win_sizes[0];
-
-done:
- if (ret) {
+ if (ret < 0) {
v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
+ } else {
+ priv->cfmt = &ov772x_cfmts[0];
+ priv->win = &ov772x_win_sizes[0];
}
return ret;
}
@@ -1111,7 +1104,6 @@ static int ov772x_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c
index b323684eaf77..05993041be31 100644
--- a/drivers/media/i2c/soc_camera/ov9640.c
+++ b/drivers/media/i2c/soc_camera/ov9640.c
@@ -336,9 +336,9 @@ static int ov9640_set_register(struct v4l2_subdev *sd,
static int ov9640_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, ssdd, on);
}
/* select nearest higher resolution for capture */
@@ -657,13 +657,13 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -690,15 +690,15 @@ static int ov9640_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov9640_priv *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
- if (!icl) {
+ if (!ssdd) {
dev_err(&client->dev, "Missing platform_data for driver\n");
return -EINVAL;
}
- priv = kzalloc(sizeof(struct ov9640_priv), GFP_KERNEL);
+ priv = devm_kzalloc(&client->dev, sizeof(struct ov9640_priv), GFP_KERNEL);
if (!priv) {
dev_err(&client->dev,
"Failed to allocate memory for private data!\n");
@@ -713,19 +713,13 @@ static int ov9640_probe(struct i2c_client *client,
v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error) {
- int err = priv->hdl.error;
-
- kfree(priv);
- return err;
- }
+ if (priv->hdl.error)
+ return priv->hdl.error;
ret = ov9640_video_probe(client);
- if (ret) {
+ if (ret)
v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- }
return ret;
}
@@ -737,7 +731,6 @@ static int ov9640_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c
index 7a55889e397b..2f236da80165 100644
--- a/drivers/media/i2c/soc_camera/ov9740.c
+++ b/drivers/media/i2c/soc_camera/ov9740.c
@@ -787,12 +787,12 @@ static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
static int ov9740_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct ov9740_priv *priv = to_ov9740(sd);
int ret;
if (on) {
- ret = soc_camera_power_on(&client->dev, icl);
+ ret = soc_camera_power_on(&client->dev, ssdd);
if (ret < 0)
return ret;
@@ -806,7 +806,7 @@ static int ov9740_s_power(struct v4l2_subdev *sd, int on)
priv->current_enable = true;
}
- soc_camera_power_off(&client->dev, icl);
+ soc_camera_power_off(&client->dev, ssdd);
}
return 0;
@@ -905,13 +905,13 @@ static int ov9740_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -951,15 +951,15 @@ static int ov9740_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov9740_priv *priv;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
- if (!icl) {
+ if (!ssdd) {
dev_err(&client->dev, "Missing platform_data for driver\n");
return -EINVAL;
}
- priv = kzalloc(sizeof(struct ov9740_priv), GFP_KERNEL);
+ priv = devm_kzalloc(&client->dev, sizeof(struct ov9740_priv), GFP_KERNEL);
if (!priv) {
dev_err(&client->dev, "Failed to allocate private data!\n");
return -ENOMEM;
@@ -972,18 +972,12 @@ static int ov9740_probe(struct i2c_client *client,
v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
priv->subdev.ctrl_handler = &priv->hdl;
- if (priv->hdl.error) {
- int err = priv->hdl.error;
-
- kfree(priv);
- return err;
- }
+ if (priv->hdl.error)
+ return priv->hdl.error;
ret = ov9740_video_probe(client);
- if (ret < 0) {
+ if (ret < 0)
v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
- }
return ret;
}
@@ -994,7 +988,6 @@ static int ov9740_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
- kfree(priv);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
index 02f0400051d9..5c92679bfefb 100644
--- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c
+++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
@@ -1183,9 +1183,9 @@ static int rj54n1_s_register(struct v4l2_subdev *sd,
static int rj54n1_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, ssdd, on);
}
static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -1245,14 +1245,14 @@ static int rj54n1_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags =
V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -1261,10 +1261,10 @@ static int rj54n1_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
/* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */
- if (soc_camera_apply_board_flags(icl, cfg) &
+ if (soc_camera_apply_board_flags(ssdd, cfg) &
V4L2_MBUS_PCLK_SAMPLE_RISING)
return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4);
else
@@ -1334,17 +1334,17 @@ static int rj54n1_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct rj54n1 *rj54n1;
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct rj54n1_pdata *rj54n1_priv;
int ret;
- if (!icl || !icl->priv) {
+ if (!ssdd || !ssdd->drv_priv) {
dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n");
return -EINVAL;
}
- rj54n1_priv = icl->priv;
+ rj54n1_priv = ssdd->drv_priv;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_warn(&adapter->dev,
@@ -1352,7 +1352,7 @@ static int rj54n1_probe(struct i2c_client *client,
return -EIO;
}
- rj54n1 = kzalloc(sizeof(struct rj54n1), GFP_KERNEL);
+ rj54n1 = devm_kzalloc(&client->dev, sizeof(struct rj54n1), GFP_KERNEL);
if (!rj54n1)
return -ENOMEM;
@@ -1367,12 +1367,8 @@ static int rj54n1_probe(struct i2c_client *client,
v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
rj54n1->subdev.ctrl_handler = &rj54n1->hdl;
- if (rj54n1->hdl.error) {
- int err = rj54n1->hdl.error;
-
- kfree(rj54n1);
- return err;
- }
+ if (rj54n1->hdl.error)
+ return rj54n1->hdl.error;
rj54n1->clk_div = clk_div;
rj54n1->rect.left = RJ54N1_COLUMN_SKIP;
@@ -1387,10 +1383,8 @@ static int rj54n1_probe(struct i2c_client *client,
(clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
ret = rj54n1_video_probe(client, rj54n1_priv);
- if (ret < 0) {
+ if (ret < 0)
v4l2_ctrl_handler_free(&rj54n1->hdl);
- kfree(rj54n1);
- }
return ret;
}
@@ -1398,13 +1392,12 @@ static int rj54n1_probe(struct i2c_client *client,
static int rj54n1_remove(struct i2c_client *client)
{
struct rj54n1 *rj54n1 = to_rj54n1(client);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
v4l2_device_unregister_subdev(&rj54n1->subdev);
- if (icl->free_bus)
- icl->free_bus(icl);
+ if (ssdd->free_bus)
+ ssdd->free_bus(ssdd);
v4l2_ctrl_handler_free(&rj54n1->hdl);
- kfree(rj54n1);
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c
index 140716e71a15..7d2074601881 100644
--- a/drivers/media/i2c/soc_camera/tw9910.c
+++ b/drivers/media/i2c/soc_camera/tw9910.c
@@ -569,9 +569,9 @@ static int tw9910_s_register(struct v4l2_subdev *sd,
static int tw9910_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- return soc_camera_set_power(&client->dev, icl, on);
+ return soc_camera_set_power(&client->dev, ssdd, on);
}
static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
@@ -847,14 +847,14 @@ static int tw9910_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
V4L2_MBUS_DATA_ACTIVE_HIGH;
cfg->type = V4L2_MBUS_PARALLEL;
- cfg->flags = soc_camera_apply_board_flags(icl, cfg);
+ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
return 0;
}
@@ -863,9 +863,9 @@ static int tw9910_s_mbus_config(struct v4l2_subdev *sd,
const struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
u8 val = VSSL_VVALID | HSSL_DVALID;
- unsigned long flags = soc_camera_apply_board_flags(icl, cfg);
+ unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg);
/*
* set OUTCTR1
@@ -911,15 +911,14 @@ static int tw9910_probe(struct i2c_client *client,
struct tw9910_video_info *info;
struct i2c_adapter *adapter =
to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = soc_camera_i2c_to_link(client);
- int ret;
+ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
- if (!icl || !icl->priv) {
+ if (!ssdd || !ssdd->drv_priv) {
dev_err(&client->dev, "TW9910: missing platform data!\n");
return -EINVAL;
}
- info = icl->priv;
+ info = ssdd->drv_priv;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev,
@@ -928,7 +927,7 @@ static int tw9910_probe(struct i2c_client *client,
return -EIO;
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -936,18 +935,11 @@ static int tw9910_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
- ret = tw9910_video_probe(client);
- if (ret)
- kfree(priv);
-
- return ret;
+ return tw9910_video_probe(client);
}
static int tw9910_remove(struct i2c_client *client)
{
- struct tw9910_priv *priv = to_tw9910(client);
-
- kfree(priv);
return 0;
}
diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c
index c31cc04fffd2..e747524ba6ed 100644
--- a/drivers/media/i2c/ths7303.c
+++ b/drivers/media/i2c/ths7303.c
@@ -175,7 +175,7 @@ static int ths7303_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ sd = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev), GFP_KERNEL);
if (sd == NULL)
return -ENOMEM;
@@ -189,7 +189,6 @@ static int ths7303_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
- kfree(sd);
return 0;
}
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
index 3b24d3fc1866..e3b33b78dd21 100644
--- a/drivers/media/i2c/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
@@ -39,6 +39,7 @@
#include <media/tvaudio.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
#include <media/i2c-addr.h>
@@ -91,13 +92,13 @@ struct CHIPDESC {
audiocmd init;
/* which register has which value */
- int leftreg,rightreg,treblereg,bassreg;
+ int leftreg, rightreg, treblereg, bassreg;
- /* initialize with (defaults to 65535/65535/32768/32768 */
- int leftinit,rightinit,trebleinit,bassinit;
+ /* initialize with (defaults to 65535/32768/32768 */
+ int volinit, trebleinit, bassinit;
/* functions to convert the values (v4l -> chip) */
- getvalue volfunc,treblefunc,bassfunc;
+ getvalue volfunc, treblefunc, bassfunc;
/* get/set mode */
getrxsubchans getrxsubchans;
@@ -113,6 +114,12 @@ struct CHIPDESC {
/* current state of the chip */
struct CHIPSTATE {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ struct {
+ /* volume/balance cluster */
+ struct v4l2_ctrl *volume;
+ struct v4l2_ctrl *balance;
+ };
/* chip-specific description - should point to
an entry at CHIPDESC table */
@@ -122,7 +129,7 @@ struct CHIPSTATE {
audiocmd shadow;
/* current settings */
- __u16 left, right, treble, bass, muted;
+ u16 muted;
int prevmode;
int radio;
int input;
@@ -138,6 +145,11 @@ static inline struct CHIPSTATE *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct CHIPSTATE, sd);
}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct CHIPSTATE, hdl)->sd;
+}
+
/* ---------------------------------------------------------------------- */
/* i2c I/O functions */
@@ -1523,8 +1535,7 @@ static struct CHIPDESC chiplist[] = {
.rightreg = TDA9875_MVR,
.bassreg = TDA9875_MBA,
.treblereg = TDA9875_MTR,
- .leftinit = 58880,
- .rightinit = 58880,
+ .volinit = 58880,
},
{
.name = "tda9850",
@@ -1618,7 +1629,8 @@ static struct CHIPDESC chiplist[] = {
.inputreg = -1,
.inputmap = { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC },
- .inputmute = TEA6300_S_GMU,
+ .inputmute = TEA6420_S_GMU,
+ .inputmask = 0x07,
},
{
.name = "tda8425",
@@ -1679,121 +1691,39 @@ static struct CHIPDESC chiplist[] = {
/* ---------------------------------------------------------------------- */
-static int tvaudio_g_ctrl(struct v4l2_subdev *sd,
- struct v4l2_control *ctrl)
+static int tvaudio_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct v4l2_subdev *sd = to_sd(ctrl);
struct CHIPSTATE *chip = to_state(sd);
struct CHIPDESC *desc = chip->desc;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- if (!(desc->flags & CHIP_HAS_INPUTSEL))
- break;
- ctrl->value=chip->muted;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- if (!(desc->flags & CHIP_HAS_VOLUME))
- break;
- ctrl->value = max(chip->left,chip->right);
- return 0;
- case V4L2_CID_AUDIO_BALANCE:
- {
- int volume;
- if (!(desc->flags & CHIP_HAS_VOLUME))
- break;
- volume = max(chip->left,chip->right);
- if (volume)
- ctrl->value=(32768*min(chip->left,chip->right))/volume;
- else
- ctrl->value=32768;
- return 0;
- }
- case V4L2_CID_AUDIO_BASS:
- if (!(desc->flags & CHIP_HAS_BASSTREBLE))
- break;
- ctrl->value = chip->bass;
- return 0;
- case V4L2_CID_AUDIO_TREBLE:
- if (!(desc->flags & CHIP_HAS_BASSTREBLE))
- break;
- ctrl->value = chip->treble;
- return 0;
- }
- return -EINVAL;
-}
-
-static int tvaudio_s_ctrl(struct v4l2_subdev *sd,
- struct v4l2_control *ctrl)
-{
- struct CHIPSTATE *chip = to_state(sd);
- struct CHIPDESC *desc = chip->desc;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (!(desc->flags & CHIP_HAS_INPUTSEL))
- break;
-
- if (ctrl->value < 0 || ctrl->value >= 2)
- return -ERANGE;
- chip->muted = ctrl->value;
+ chip->muted = ctrl->val;
if (chip->muted)
chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask);
else
chip_write_masked(chip,desc->inputreg,
desc->inputmap[chip->input],desc->inputmask);
return 0;
- case V4L2_CID_AUDIO_VOLUME:
- {
- int volume,balance;
-
- if (!(desc->flags & CHIP_HAS_VOLUME))
- break;
-
- volume = max(chip->left,chip->right);
- if (volume)
- balance=(32768*min(chip->left,chip->right))/volume;
- else
- balance=32768;
-
- volume=ctrl->value;
- chip->left = (min(65536 - balance,32768) * volume) / 32768;
- chip->right = (min(balance,volume *(__u16)32768)) / 32768;
-
- chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
- chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
-
- return 0;
- }
- case V4L2_CID_AUDIO_BALANCE:
- {
- int volume, balance;
-
- if (!(desc->flags & CHIP_HAS_VOLUME))
- break;
-
- volume = max(chip->left, chip->right);
- balance = ctrl->value;
- chip->left = (min(65536 - balance, 32768) * volume) / 32768;
- chip->right = (min(balance, volume * (__u16)32768)) / 32768;
+ case V4L2_CID_AUDIO_VOLUME: {
+ u32 volume, balance;
+ u32 left, right;
- chip_write(chip, desc->leftreg, desc->volfunc(chip->left));
- chip_write(chip, desc->rightreg, desc->volfunc(chip->right));
+ volume = chip->volume->val;
+ balance = chip->balance->val;
+ left = (min(65536U - balance, 32768U) * volume) / 32768U;
+ right = (min(balance, 32768U) * volume) / 32768U;
+ chip_write(chip, desc->leftreg, desc->volfunc(left));
+ chip_write(chip, desc->rightreg, desc->volfunc(right));
return 0;
}
case V4L2_CID_AUDIO_BASS:
- if (!(desc->flags & CHIP_HAS_BASSTREBLE))
- break;
- chip->bass = ctrl->value;
- chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
-
+ chip_write(chip, desc->bassreg, desc->bassfunc(ctrl->val));
return 0;
case V4L2_CID_AUDIO_TREBLE:
- if (!(desc->flags & CHIP_HAS_BASSTREBLE))
- break;
- chip->treble = ctrl->value;
- chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
-
+ chip_write(chip, desc->treblereg, desc->treblefunc(ctrl->val));
return 0;
}
return -EINVAL;
@@ -1812,35 +1742,6 @@ static int tvaudio_s_radio(struct v4l2_subdev *sd)
return 0;
}
-static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- struct CHIPSTATE *chip = to_state(sd);
- struct CHIPDESC *desc = chip->desc;
-
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (desc->flags & CHIP_HAS_INPUTSEL)
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
- break;
- case V4L2_CID_AUDIO_VOLUME:
- if (desc->flags & CHIP_HAS_VOLUME)
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
- break;
- case V4L2_CID_AUDIO_BALANCE:
- if (desc->flags & CHIP_HAS_VOLUME)
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
- break;
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- if (desc->flags & CHIP_HAS_BASSTREBLE)
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
- break;
- default:
- break;
- }
- return -EINVAL;
-}
-
static int tvaudio_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
@@ -1944,13 +1845,32 @@ static int tvaudio_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVAUDIO, 0);
}
+static int tvaudio_log_status(struct v4l2_subdev *sd)
+{
+ struct CHIPSTATE *chip = to_state(sd);
+ struct CHIPDESC *desc = chip->desc;
+
+ v4l2_info(sd, "Chip: %s\n", desc->name);
+ v4l2_ctrl_handler_log_status(&chip->hdl, sd->name);
+ return 0;
+}
+
/* ----------------------------------------------------------------------- */
+static const struct v4l2_ctrl_ops tvaudio_ctrl_ops = {
+ .s_ctrl = tvaudio_s_ctrl,
+};
+
static const struct v4l2_subdev_core_ops tvaudio_core_ops = {
+ .log_status = tvaudio_log_status,
.g_chip_ident = tvaudio_g_chip_ident,
- .queryctrl = tvaudio_queryctrl,
- .g_ctrl = tvaudio_g_ctrl,
- .s_ctrl = tvaudio_s_ctrl,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
.s_std = tvaudio_s_std,
};
@@ -2035,6 +1955,10 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
else
chip_cmd(chip, "init", &desc->init);
+ v4l2_ctrl_handler_init(&chip->hdl, 5);
+ if (desc->flags & CHIP_HAS_INPUTSEL)
+ v4l2_ctrl_new_std(&chip->hdl, &tvaudio_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
if (desc->flags & CHIP_HAS_VOLUME) {
if (!desc->volfunc) {
/* This shouldn't be happen. Warn user, but keep working
@@ -2043,12 +1967,14 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
v4l2_info(sd, "volume callback undefined!\n");
desc->flags &= ~CHIP_HAS_VOLUME;
} else {
- chip->left = desc->leftinit ? desc->leftinit : 65535;
- chip->right = desc->rightinit ? desc->rightinit : 65535;
- chip_write(chip, desc->leftreg,
- desc->volfunc(chip->left));
- chip_write(chip, desc->rightreg,
- desc->volfunc(chip->right));
+ chip->volume = v4l2_ctrl_new_std(&chip->hdl,
+ &tvaudio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
+ 0, 65535, 65535 / 100,
+ desc->volinit ? desc->volinit : 65535);
+ chip->balance = v4l2_ctrl_new_std(&chip->hdl,
+ &tvaudio_ctrl_ops, V4L2_CID_AUDIO_BALANCE,
+ 0, 65535, 65535 / 100, 32768);
+ v4l2_ctrl_cluster(2, &chip->volume);
}
}
if (desc->flags & CHIP_HAS_BASSTREBLE) {
@@ -2059,17 +1985,28 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
v4l2_info(sd, "bass/treble callbacks undefined!\n");
desc->flags &= ~CHIP_HAS_BASSTREBLE;
} else {
- chip->treble = desc->trebleinit ?
- desc->trebleinit : 32768;
- chip->bass = desc->bassinit ?
- desc->bassinit : 32768;
- chip_write(chip, desc->bassreg,
- desc->bassfunc(chip->bass));
- chip_write(chip, desc->treblereg,
- desc->treblefunc(chip->treble));
+ v4l2_ctrl_new_std(&chip->hdl,
+ &tvaudio_ctrl_ops, V4L2_CID_AUDIO_BASS,
+ 0, 65535, 65535 / 100,
+ desc->bassinit ? desc->bassinit : 32768);
+ v4l2_ctrl_new_std(&chip->hdl,
+ &tvaudio_ctrl_ops, V4L2_CID_AUDIO_TREBLE,
+ 0, 65535, 65535 / 100,
+ desc->trebleinit ? desc->trebleinit : 32768);
}
}
+ sd->ctrl_handler = &chip->hdl;
+ if (chip->hdl.error) {
+ int err = chip->hdl.error;
+
+ v4l2_ctrl_handler_free(&chip->hdl);
+ kfree(chip);
+ return err;
+ }
+ /* set controls to the default values */
+ v4l2_ctrl_handler_setup(&chip->hdl);
+
chip->thread = NULL;
init_timer(&chip->wt);
if (desc->flags & CHIP_NEED_CHECKMODE) {
@@ -2105,6 +2042,7 @@ static int tvaudio_remove(struct i2c_client *client)
}
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&chip->hdl);
kfree(chip);
return 0;
}
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index d5e10215a28f..aa94ebc2d755 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -951,7 +951,7 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
return -ENODEV;
}
- decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+ decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
if (!decoder)
return -ENOMEM;
@@ -998,7 +998,6 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
int err = decoder->hdl.error;
v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(decoder);
return err;
}
v4l2_ctrl_handler_setup(&decoder->hdl);
@@ -1023,7 +1022,6 @@ static int tvp514x_remove(struct i2c_client *client)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&decoder->hdl);
- kfree(decoder);
return 0;
}
/* TVP5146 Init/Power on Sequence */
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 31104a960652..5967e1a0c809 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1096,13 +1096,6 @@ static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
.log_status = tvp5150_log_status,
- .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
- .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
- .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
- .g_ctrl = v4l2_subdev_g_ctrl,
- .s_ctrl = v4l2_subdev_s_ctrl,
- .queryctrl = v4l2_subdev_queryctrl,
- .querymenu = v4l2_subdev_querymenu,
.s_std = tvp5150_s_std,
.reset = tvp5150_reset,
.g_chip_ident = tvp5150_g_chip_ident,
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index fb6a5b57eb83..537f6b4d4918 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -1036,7 +1036,7 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
return -ENODEV;
}
- device = kzalloc(sizeof(struct tvp7002), GFP_KERNEL);
+ device = devm_kzalloc(&c->dev, sizeof(struct tvp7002), GFP_KERNEL);
if (!device)
return -ENOMEM;
@@ -1052,7 +1052,7 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
error = tvp7002_read(sd, TVP7002_CHIP_REV, &revision);
if (error < 0)
- goto found_error;
+ return error;
/* Get revision number */
v4l2_info(sd, "Rev. %02x detected.\n", revision);
@@ -1063,21 +1063,21 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
error = tvp7002_write_inittab(sd, tvp7002_init_default);
if (error < 0)
- goto found_error;
+ return error;
/* Set polarity information after registers have been set */
polarity_a = 0x20 | device->pdata->hs_polarity << 5
| device->pdata->vs_polarity << 2;
error = tvp7002_write(sd, TVP7002_SYNC_CTL_1, polarity_a);
if (error < 0)
- goto found_error;
+ return error;
polarity_b = 0x01 | device->pdata->fid_polarity << 2
| device->pdata->sog_polarity << 1
| device->pdata->clk_polarity;
error = tvp7002_write(sd, TVP7002_MISC_CTL_3, polarity_b);
if (error < 0)
- goto found_error;
+ return error;
/* Set registers according to default video mode */
preset.preset = device->current_preset->preset;
@@ -1091,16 +1091,11 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
int err = device->hdl.error;
v4l2_ctrl_handler_free(&device->hdl);
- kfree(device);
return err;
}
v4l2_ctrl_handler_setup(&device->hdl);
-found_error:
- if (error < 0)
- kfree(device);
-
- return error;
+ return 0;
}
/*
@@ -1120,7 +1115,6 @@ static int tvp7002_remove(struct i2c_client *c)
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(&device->hdl);
- kfree(device);
return 0;
}
diff --git a/drivers/media/parport/Kconfig b/drivers/media/parport/Kconfig
index ece13dcff07d..948c981d9f05 100644
--- a/drivers/media/parport/Kconfig
+++ b/drivers/media/parport/Kconfig
@@ -9,6 +9,7 @@ if MEDIA_PARPORT_SUPPORT
config VIDEO_BWQCAM
tristate "Quickcam BW Video For Linux"
depends on PARPORT && VIDEO_V4L2
+ select VIDEOBUF2_VMALLOC
help
Say Y have if you the black and white version of the QuickCam
camera. See the next option for the color version.
diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c
index 5b75a64b199b..06231b85e1a9 100644
--- a/drivers/media/parport/bw-qcam.c
+++ b/drivers/media/parport/bw-qcam.c
@@ -80,6 +80,7 @@ OTHER DEALINGS IN THE SOFTWARE.
#include <media/v4l2-fh.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
+#include <media/videobuf2-vmalloc.h>
/* One from column A... */
#define QC_NOTSET 0
@@ -107,9 +108,11 @@ struct qcam {
struct v4l2_device v4l2_dev;
struct video_device vdev;
struct v4l2_ctrl_handler hdl;
+ struct vb2_queue vb_vidq;
struct pardevice *pdev;
struct parport *pport;
struct mutex lock;
+ struct mutex queue_lock;
int width, height;
int bpp;
int mode;
@@ -418,8 +421,6 @@ static void qc_set(struct qcam *q)
int val;
int val2;
- qc_reset(q);
-
/* Set the brightness. Yes, this is repetitive, but it works.
* Shorter versions seem to fail subtly. Feel free to try :-). */
/* I think the problem was in qc_command, not here -- bls */
@@ -558,7 +559,7 @@ static inline int qc_readbytes(struct qcam *q, char buffer[])
* n=2^(bit depth)-1. Ask me for more details if you don't understand
* this. */
-static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
+static long qc_capture(struct qcam *q, u8 *buf, unsigned long len)
{
int i, j, k, yield;
int bytes;
@@ -609,7 +610,7 @@ static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
if (o < len) {
u8 ch = invert - buffer[k];
got++;
- put_user(ch << shift, buf + o);
+ buf[o] = ch << shift;
}
}
pixels_read += bytes;
@@ -639,6 +640,67 @@ static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
return len;
}
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct qcam *dev = vb2_get_drv_priv(vq);
+
+ if (0 == *nbuffers)
+ *nbuffers = 3;
+ *nplanes = 1;
+ mutex_lock(&dev->lock);
+ if (fmt)
+ sizes[0] = fmt->fmt.pix.width * fmt->fmt.pix.height;
+ else
+ sizes[0] = (dev->width / dev->transfer_scale) *
+ (dev->height / dev->transfer_scale);
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+}
+
+static int buffer_finish(struct vb2_buffer *vb)
+{
+ struct qcam *qcam = vb2_get_drv_priv(vb->vb2_queue);
+ void *vbuf = vb2_plane_vaddr(vb, 0);
+ int size = vb->vb2_queue->plane_sizes[0];
+ int len;
+
+ mutex_lock(&qcam->lock);
+ parport_claim_or_block(qcam->pdev);
+
+ qc_reset(qcam);
+
+ /* Update the camera parameters if we need to */
+ if (qcam->status & QC_PARAM_CHANGE)
+ qc_set(qcam);
+
+ len = qc_capture(qcam, vbuf, size);
+
+ parport_release(qcam->pdev);
+ mutex_unlock(&qcam->lock);
+ if (len != size)
+ vb->state = VB2_BUF_STATE_ERROR;
+ vb2_set_plane_payload(vb, 0, len);
+ return 0;
+}
+
+static struct vb2_ops qcam_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_queue = buffer_queue,
+ .buf_finish = buffer_finish,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
/*
* Video4linux interfacing
*/
@@ -651,7 +713,8 @@ static int qcam_querycap(struct file *file, void *priv,
strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card));
strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info));
- vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -693,6 +756,7 @@ static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
pix->sizeimage = pix->width * pix->height;
/* Just a guess */
pix->colorspace = V4L2_COLORSPACE_SRGB;
+ pix->priv = 0;
return 0;
}
@@ -718,6 +782,7 @@ static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format
pix->sizeimage = pix->width * pix->height;
/* Just a guess */
pix->colorspace = V4L2_COLORSPACE_SRGB;
+ pix->priv = 0;
return 0;
}
@@ -729,6 +794,8 @@ static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
if (ret)
return ret;
+ if (vb2_is_busy(&qcam->vb_vidq))
+ return -EBUSY;
qcam->width = 320;
qcam->height = 240;
if (pix->height == 60)
@@ -742,12 +809,10 @@ static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
else
qcam->bpp = 4;
- mutex_lock(&qcam->lock);
qc_setscanmode(qcam);
/* We must update the camera before we grab. We could
just have changed the grab size */
qcam->status |= QC_PARAM_CHANGE;
- mutex_unlock(&qcam->lock);
return 0;
}
@@ -792,41 +857,12 @@ static int qcam_enum_framesizes(struct file *file, void *fh,
return 0;
}
-static ssize_t qcam_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct qcam *qcam = video_drvdata(file);
- int len;
- parport_claim_or_block(qcam->pdev);
-
- mutex_lock(&qcam->lock);
-
- qc_reset(qcam);
-
- /* Update the camera parameters if we need to */
- if (qcam->status & QC_PARAM_CHANGE)
- qc_set(qcam);
-
- len = qc_capture(qcam, buf, count);
-
- mutex_unlock(&qcam->lock);
-
- parport_release(qcam->pdev);
- return len;
-}
-
-static unsigned int qcam_poll(struct file *filp, poll_table *wait)
-{
- return v4l2_ctrl_poll(filp, wait) | POLLIN | POLLRDNORM;
-}
-
static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct qcam *qcam =
container_of(ctrl->handler, struct qcam, hdl);
int ret = 0;
- mutex_lock(&qcam->lock);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
qcam->brightness = ctrl->val;
@@ -841,21 +877,19 @@ static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
ret = -EINVAL;
break;
}
- if (ret == 0) {
- qc_setscanmode(qcam);
+ if (ret == 0)
qcam->status |= QC_PARAM_CHANGE;
- }
- mutex_unlock(&qcam->lock);
return ret;
}
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
- .release = v4l2_fh_release,
- .poll = qcam_poll,
+ .release = vb2_fop_release,
+ .poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2,
- .read = qcam_read,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
};
static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
@@ -868,6 +902,14 @@ static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
.vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_log_status = v4l2_ctrl_log_status,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
@@ -884,6 +926,8 @@ static struct qcam *qcam_init(struct parport *port)
{
struct qcam *qcam;
struct v4l2_device *v4l2_dev;
+ struct vb2_queue *q;
+ int err;
qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL);
if (qcam == NULL)
@@ -907,31 +951,45 @@ static struct qcam *qcam_init(struct parport *port)
V4L2_CID_GAMMA, 0, 255, 1, 105);
if (qcam->hdl.error) {
v4l2_err(v4l2_dev, "couldn't register controls\n");
- v4l2_ctrl_handler_free(&qcam->hdl);
- kfree(qcam);
- return NULL;
+ goto exit;
+ }
+
+ mutex_init(&qcam->lock);
+ mutex_init(&qcam->queue_lock);
+
+ /* initialize queue */
+ q = &qcam->vb_vidq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ q->drv_priv = qcam;
+ q->ops = &qcam_video_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+ err = vb2_queue_init(q);
+ if (err < 0) {
+ v4l2_err(v4l2_dev, "couldn't init vb2_queue for %s.\n", port->name);
+ goto exit;
}
+ qcam->vdev.queue = q;
+ qcam->vdev.queue->lock = &qcam->queue_lock;
+
qcam->pport = port;
qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL,
NULL, 0, NULL);
if (qcam->pdev == NULL) {
v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
- v4l2_ctrl_handler_free(&qcam->hdl);
- kfree(qcam);
- return NULL;
+ goto exit;
}
strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
qcam->vdev.v4l2_dev = v4l2_dev;
qcam->vdev.ctrl_handler = &qcam->hdl;
qcam->vdev.fops = &qcam_fops;
+ qcam->vdev.lock = &qcam->lock;
qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
qcam->vdev.release = video_device_release_empty;
video_set_drvdata(&qcam->vdev, qcam);
- mutex_init(&qcam->lock);
-
qcam->port_mode = (QC_ANY | QC_NOTSET);
qcam->width = 320;
qcam->height = 240;
@@ -945,6 +1003,11 @@ static struct qcam *qcam_init(struct parport *port)
qcam->mode = -1;
qcam->status = QC_PARAM_CHANGE;
return qcam;
+
+exit:
+ v4l2_ctrl_handler_free(&qcam->hdl);
+ kfree(qcam);
+ return NULL;
}
static int qc_calibrate(struct qcam *q)
diff --git a/drivers/media/pci/bt8xx/Makefile b/drivers/media/pci/bt8xx/Makefile
index 5f06597c6a6e..f9fe7c4e7d53 100644
--- a/drivers/media/pci/bt8xx/Makefile
+++ b/drivers/media/pci/bt8xx/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
ccflags-y += -Idrivers/media/dvb-core
ccflags-y += -Idrivers/media/dvb-frontends
ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/common
ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 45e5d0661b60..ccd18e4ee789 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -3835,7 +3835,7 @@ bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
{
struct timeval ts;
- do_gettimeofday(&ts);
+ v4l2_get_timestamp(&ts);
if (wakeup->top == wakeup->bottom) {
if (NULL != wakeup->top && curr->top != wakeup->top) {
@@ -3878,7 +3878,7 @@ bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
if (NULL == wakeup)
return;
- do_gettimeofday(&ts);
+ v4l2_get_timestamp(&ts);
wakeup->vb.ts = ts;
wakeup->vb.field_count = btv->field_count;
wakeup->vb.state = state;
@@ -3949,7 +3949,7 @@ bttv_irq_wakeup_top(struct bttv *btv)
btv->curr.top = NULL;
bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
- do_gettimeofday(&wakeup->vb.ts);
+ v4l2_get_timestamp(&wakeup->vb.ts);
wakeup->vb.field_count = btv->field_count;
wakeup->vb.state = VIDEOBUF_DONE;
wake_up(&wakeup->vb.done);
diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c
index 5039b8826e0a..c63c643ed1f8 100644
--- a/drivers/media/pci/bt8xx/bttv-i2c.c
+++ b/drivers/media/pci/bt8xx/bttv-i2c.c
@@ -173,7 +173,7 @@ bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
if (i2c_debug)
pr_cont(" %02x", msg->buf[cnt]);
}
- if (!(xmit & BT878_I2C_NOSTOP))
+ if (i2c_debug && !(xmit & BT878_I2C_NOSTOP))
pr_cont(">\n");
return msg->len;
@@ -366,8 +366,7 @@ int init_bttv_i2c(struct bttv *btv)
strlcpy(btv->c.i2c_adap.name, "bttv",
sizeof(btv->c.i2c_adap.name));
- memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
- sizeof(bttv_i2c_algo_bit_template));
+ btv->i2c_algo = bttv_i2c_algo_bit_template;
btv->i2c_algo.udelay = i2c_udelay;
btv->i2c_algo.data = btv;
btv->c.i2c_adap.algo_data = &btv->i2c_algo;
diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c
index 7d96fab7d246..0e788fca992c 100644
--- a/drivers/media/pci/bt8xx/dst_ca.c
+++ b/drivers/media/pci/bt8xx/dst_ca.c
@@ -180,11 +180,11 @@ static int ca_get_app_info(struct dst_state *state)
put_command_and_length(&state->messages[0], CA_APP_INFO, length);
// Copy application_type, application_manufacturer and manufacturer_code
- memcpy(&state->messages[4], &state->messages[7], 5);
+ memmove(&state->messages[4], &state->messages[7], 5);
// Set string length and copy string
state->messages[9] = str_length;
- memcpy(&state->messages[10], &state->messages[12], str_length);
+ memmove(&state->messages[10], &state->messages[12], str_length);
return 0;
}
diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c
index 8e971ff60588..b2c8c3439fea 100644
--- a/drivers/media/pci/cx18/cx18-alsa-main.c
+++ b/drivers/media/pci/cx18/cx18-alsa-main.c
@@ -197,7 +197,7 @@ err_exit:
return ret;
}
-static int __init cx18_alsa_load(struct cx18 *cx)
+static int cx18_alsa_load(struct cx18 *cx)
{
struct v4l2_device *v4l2_dev = &cx->v4l2_dev;
struct cx18_stream *s;
diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.h b/drivers/media/pci/cx18/cx18-alsa-pcm.h
index d26e51f94577..e2b2c5b01215 100644
--- a/drivers/media/pci/cx18/cx18-alsa-pcm.h
+++ b/drivers/media/pci/cx18/cx18-alsa-pcm.h
@@ -20,7 +20,7 @@
* 02111-1307 USA
*/
-int __init snd_cx18_pcm_create(struct snd_cx18_card *cxsc);
+int snd_cx18_pcm_create(struct snd_cx18_card *cxsc);
/* Used by cx18-mailbox to announce the PCM data to the module */
void cx18_alsa_announce_pcm_data(struct snd_cx18_card *card, u8 *pcm_data,
diff --git a/drivers/media/pci/cx18/cx18-i2c.c b/drivers/media/pci/cx18/cx18-i2c.c
index 4908eb7bcf6c..4af8cd6df95d 100644
--- a/drivers/media/pci/cx18/cx18-i2c.c
+++ b/drivers/media/pci/cx18/cx18-i2c.c
@@ -116,9 +116,6 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
const char *type = hw_devicenames[idx];
u32 hw = 1 << idx;
- if (idx >= ARRAY_SIZE(hw_addrs))
- return -1;
-
if (hw == CX18_HW_TUNER) {
/* special tuner group handling */
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
@@ -240,15 +237,13 @@ int init_cx18_i2c(struct cx18 *cx)
for (i = 0; i < 2; i++) {
/* Setup algorithm for adapter */
- memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template,
- sizeof(struct i2c_algo_bit_data));
+ cx->i2c_algo[i] = cx18_i2c_algo_template;
cx->i2c_algo_cb_data[i].cx = cx;
cx->i2c_algo_cb_data[i].bus_index = i;
cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
/* Setup adapter */
- memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
- sizeof(struct i2c_adapter));
+ cx->i2c_adap[i] = cx18_i2c_adap_template;
cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
" #%d-%d", cx->instance, i);
diff --git a/drivers/media/pci/cx18/cx18-vbi.c b/drivers/media/pci/cx18/cx18-vbi.c
index 6d3121ff45a2..add99642f1e2 100644
--- a/drivers/media/pci/cx18/cx18-vbi.c
+++ b/drivers/media/pci/cx18/cx18-vbi.c
@@ -84,7 +84,7 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
(the max size of the VBI data is 36 * 43 + 4 bytes).
So in this case we use the magic number 'ITV0'. */
memcpy(dst + sd, "ITV0", 4);
- memcpy(dst + sd + 4, dst + sd + 12, line * 43);
+ memmove(dst + sd + 4, dst + sd + 12, line * 43);
size = 4 + ((43 * line + 3) & ~3);
} else {
memcpy(dst + sd, "itv0", 4);
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
index eafa1144b17d..b3688aa8acc3 100644
--- a/drivers/media/pci/cx23885/Kconfig
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -25,7 +25,10 @@ config VIDEO_CX23885
select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10071 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/pci/cx23885/Makefile b/drivers/media/pci/cx23885/Makefile
index a2cbdcf15a8c..2a2cafb8cf5b 100644
--- a/drivers/media/pci/cx23885/Makefile
+++ b/drivers/media/pci/cx23885/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o
ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/common
ccflags-y += -Idrivers/media/tuners
ccflags-y += -Idrivers/media/dvb-core
ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
index 6277e145f0b8..7e923f8dd2f5 100644
--- a/drivers/media/pci/cx23885/cx23885-cards.c
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -572,6 +572,39 @@ struct cx23885_board cx23885_boards[] = {
[CX23885_BOARD_PROF_8000] = {
.name = "Prof Revolution DVB-S2 8000",
.portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR4400] = {
+ .name = "Hauppauge WinTV-HVR4400",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_AVERMEDIA_HC81R] = {
+ .name = "AVerTV Hybrid Express Slim HC81R",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61, /* 0xc2 >> 1 */
+ .tuner_bus = 1,
+ .porta = CX23885_ANALOG_VIDEO,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN2_CH1 |
+ CX25840_VIN5_CH2 |
+ CX25840_NONE0_CH3 |
+ CX25840_NONE1_CH3,
+ .amux = CX25840_AUDIO8,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN8_CH1 |
+ CX25840_NONE_CH2 |
+ CX25840_VIN7_CH3 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO6,
+ }, {
+ .type = CX23885_VMUX_COMPONENT,
+ .vmux = CX25840_VIN1_CH1 |
+ CX25840_NONE_CH2 |
+ CX25840_NONE0_CH3 |
+ CX25840_NONE1_CH3,
+ .amux = CX25840_AUDIO6,
+ } },
}
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -788,6 +821,26 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x8000,
.subdevice = 0x3034,
.card = CX23885_BOARD_PROF_8000,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0xc108,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR4400,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0xc138,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR4400,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0xc12a,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR4400,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0xc1f8,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR4400,
+ }, {
+ .subvendor = 0x1461,
+ .subdevice = 0xd939,
+ .card = CX23885_BOARD_AVERMEDIA_HC81R,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1012,6 +1065,10 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
altera_ci_tuner_reset(dev, port->nr);
break;
+ case CX23885_BOARD_AVERMEDIA_HC81R:
+ /* XC3028L Reset Command */
+ bitmask = 1 << 2;
+ break;
}
if (bitmask) {
@@ -1301,6 +1358,42 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
/* enable irq */
cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR4400:
+ /* GPIO-8 tda10071 demod reset */
+
+ /* Put the parts into reset and back */
+ cx23885_gpio_enable(dev, GPIO_8, 1);
+ cx23885_gpio_clear(dev, GPIO_8);
+ mdelay(100);
+ cx23885_gpio_set(dev, GPIO_8);
+ mdelay(100);
+ break;
+ case CX23885_BOARD_AVERMEDIA_HC81R:
+ cx_clear(MC417_CTL, 1);
+ /* GPIO-0,1,2 setup direction as output */
+ cx_set(GP0_IO, 0x00070000);
+ mdelay(10);
+ /* AF9013 demod reset */
+ cx_set(GP0_IO, 0x00010001);
+ mdelay(10);
+ cx_clear(GP0_IO, 0x00010001);
+ mdelay(10);
+ cx_set(GP0_IO, 0x00010001);
+ mdelay(10);
+ /* demod tune? */
+ cx_clear(GP0_IO, 0x00030003);
+ mdelay(10);
+ cx_set(GP0_IO, 0x00020002);
+ mdelay(10);
+ cx_set(GP0_IO, 0x00010001);
+ mdelay(10);
+ cx_clear(GP0_IO, 0x00020002);
+ /* XC3028L tuner reset */
+ cx_set(GP0_IO, 0x00040004);
+ cx_clear(GP0_IO, 0x00040004);
+ cx_set(GP0_IO, 0x00040004);
+ mdelay(60);
+ break;
}
}
@@ -1378,6 +1471,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
break;
case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_MYGICA_X8507:
if (!enable_885_ir)
break;
dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
@@ -1420,6 +1514,7 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
case CX23885_BOARD_TEVII_S470:
case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_MYGICA_X8507:
cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
/* sd_ir is a duplicate pointer to the AV Core, just clear it */
dev->sd_ir = NULL;
@@ -1464,6 +1559,7 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
case CX23885_BOARD_TEVII_S470:
case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_MYGICA_X8507:
if (dev->sd_ir)
cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
break;
@@ -1509,12 +1605,24 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1210:
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_HAUPPAUGE_HVR4400:
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0xc0);
break;
}
switch (dev->board) {
+ case CX23885_BOARD_AVERMEDIA_HC81R:
+ /* Defaults for VID B */
+ ts1->gen_ctrl_val = 0x4; /* Parallel */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ /* Defaults for VID C */
+ /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */
+ ts2->gen_ctrl_val = 0x10e;
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
@@ -1581,6 +1689,11 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR4400:
+ ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -1636,6 +1749,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_MPX885:
case CX23885_BOARD_MYGICA_X8507:
case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+ case CX23885_BOARD_AVERMEDIA_HC81R:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
"cx25840", 0x88 >> 1, NULL);
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index f0416a668b4c..268654ac9a9f 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -439,7 +439,7 @@ void cx23885_wakeup(struct cx23885_tsport *port,
if ((s16) (count - buf->count) < 0)
break;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
count, buf->count);
buf->vb.state = VIDEOBUF_DONE;
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 2f5b902e63ae..9c5ed10b2c5e 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -57,6 +57,7 @@
#include "netup-init.h"
#include "lgdt3305.h"
#include "atbm8830.h"
+#include "ts2020.h"
#include "ds3000.h"
#include "cx23885-f300.h"
#include "altera-ci.h"
@@ -66,6 +67,8 @@
#include "stv090x.h"
#include "stb6100.h"
#include "stb6100_cfg.h"
+#include "tda10071.h"
+#include "a8293.h"
static unsigned int debug;
@@ -469,6 +472,11 @@ static struct ds3000_config tevii_ds3000_config = {
.demod_address = 0x68,
};
+static struct ts2020_config tevii_ts2020_config = {
+ .tuner_address = 0x60,
+ .clk_out_div = 1,
+};
+
static struct cx24116_config dvbworld_cx24116_config = {
.demod_address = 0x05,
};
@@ -493,20 +501,20 @@ static struct xc5000_config mygica_x8506_xc5000_config = {
};
static struct stv090x_config prof_8000_stv090x_config = {
- .device = STV0903,
- .demod_mode = STV090x_SINGLE,
- .clk_mode = STV090x_CLK_EXT,
- .xtal = 27000000,
- .address = 0x6A,
- .ts1_mode = STV090x_TSMODE_PARALLEL_PUNCTURED,
- .repeater_level = STV090x_RPTLEVEL_64,
- .adc1_range = STV090x_ADC_2Vpp,
- .diseqc_envelope_mode = false,
-
- .tuner_get_frequency = stb6100_get_frequency,
- .tuner_set_frequency = stb6100_set_frequency,
- .tuner_set_bandwidth = stb6100_set_bandwidth,
- .tuner_get_bandwidth = stb6100_get_bandwidth,
+ .device = STV0903,
+ .demod_mode = STV090x_SINGLE,
+ .clk_mode = STV090x_CLK_EXT,
+ .xtal = 27000000,
+ .address = 0x6A,
+ .ts1_mode = STV090x_TSMODE_PARALLEL_PUNCTURED,
+ .repeater_level = STV090x_RPTLEVEL_64,
+ .adc1_range = STV090x_ADC_2Vpp,
+ .diseqc_envelope_mode = false,
+
+ .tuner_get_frequency = stb6100_get_frequency,
+ .tuner_set_frequency = stb6100_set_frequency,
+ .tuner_set_bandwidth = stb6100_set_bandwidth,
+ .tuner_get_bandwidth = stb6100_get_bandwidth,
};
static struct stb6100_config prof_8000_stb6100_config = {
@@ -659,6 +667,20 @@ static struct mt2063_config terratec_mt2063_config[] = {
},
};
+static const struct tda10071_config hauppauge_tda10071_config = {
+ .demod_i2c_addr = 0x05,
+ .tuner_i2c_addr = 0x54,
+ .i2c_wr_max = 64,
+ .ts_mode = TDA10071_TS_SERIAL,
+ .spec_inv = 0,
+ .xtal = 40444000, /* 40.444 MHz */
+ .pll_multiplier = 20,
+};
+
+static const struct a8293_config hauppauge_a8293_config = {
+ .i2c_addr = 0x0b,
+};
+
static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
{
struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -1011,8 +1033,11 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(ds3000_attach,
&tevii_ds3000_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL)
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(ts2020_attach, fe0->dvb.frontend,
+ &tevii_ts2020_config, &i2c_bus->i2c_adap);
fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
+ }
break;
case CX23885_BOARD_DVBWORLD_2005:
@@ -1242,6 +1267,17 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend->ops.set_voltage = p8000_set_voltage;
}
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR4400:
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(tda10071_attach,
+ &hauppauge_tda10071_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(a8293_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_a8293_config);
+ }
+ break;
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 4f1055a194b5..7875dfbe09ff 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -89,6 +89,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
case CX23885_BOARD_TEVII_S470:
case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_MYGICA_X8507:
/*
* The only boards we handle right now. However other boards
* using the CX2388x integrated IR controller should be similar
@@ -140,6 +141,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_MYGICA_X8507:
/*
* The IR controller on this board only returns pulse widths.
* Any other mode setting will fail to set up the device.
@@ -289,6 +291,13 @@ int cx23885_input_init(struct cx23885_dev *dev)
/* A guess at the remote */
rc_map = RC_MAP_TEVII_NEC;
break;
+ case CX23885_BOARD_MYGICA_X8507:
+ /* Integrated CX23885 IR controller */
+ driver_type = RC_DRIVER_IR_RAW;
+ allowed_protos = RC_BIT_ALL;
+ /* A guess at the remote */
+ rc_map = RC_MAP_TOTAL_MEDIA_IN_HAND_02;
+ break;
default:
return -ENODEV;
}
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 1a21926ca412..5991bc8dc158 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -300,7 +300,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
if ((s16) (count - buf->count) < 0)
break;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
count, buf->count);
buf->vb.state = VIDEOBUF_DONE;
@@ -509,7 +509,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
- (dev->board == CX23885_BOARD_MYGICA_X8507)) {
+ (dev->board == CX23885_BOARD_MYGICA_X8507) ||
+ (dev->board == CX23885_BOARD_AVERMEDIA_HC81R)) {
/* Configure audio routing */
v4l2_subdev_call(dev->sd_cx25840, audio, s_routing,
INPUT(input)->amux, 0, 0);
@@ -1818,8 +1819,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
spin_lock_init(&dev->slock);
/* Initialize VBI template */
- memcpy(&cx23885_vbi_template, &cx23885_video_template,
- sizeof(cx23885_vbi_template));
+ cx23885_vbi_template = cx23885_video_template;
strcpy(cx23885_vbi_template.name, "cx23885-vbi");
dev->tvnorm = cx23885_video_template.current_norm;
@@ -1878,6 +1878,18 @@ int cx23885_video_register(struct cx23885_dev *dev)
};
v4l2_subdev_call(sd, tuner, s_config, &cfg);
}
+
+ if (dev->board == CX23885_BOARD_AVERMEDIA_HC81R) {
+ struct xc2028_ctrl ctrl = {
+ .fname = "xc3028L-v36.fw",
+ .max_len = 64
+ };
+ struct v4l2_priv_tun_config cfg = {
+ .tuner = dev->tuner_type,
+ .priv = &ctrl
+ };
+ v4l2_subdev_call(sd, tuner, s_config, &cfg);
+ }
}
}
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index 67f40d31450b..59c322d870f2 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -91,6 +91,8 @@
#define CX23885_BOARD_TEVII_S471 35
#define CX23885_BOARD_HAUPPAUGE_HVR1255_22111 36
#define CX23885_BOARD_PROF_8000 37
+#define CX23885_BOARD_HAUPPAUGE_HVR4400 38
+#define CX23885_BOARD_AVERMEDIA_HC81R 39
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index c4bd1e95d33f..d51eed051d59 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -1237,13 +1237,11 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
cx23888_ir_write4(dev, CX23888_IR_IRQEN_REG, 0);
mutex_init(&state->rx_params_lock);
- memcpy(&default_params, &default_rx_params,
- sizeof(struct v4l2_subdev_ir_parameters));
+ default_params = default_rx_params;
v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params);
mutex_init(&state->tx_params_lock);
- memcpy(&default_params, &default_tx_params,
- sizeof(struct v4l2_subdev_ir_parameters));
+ default_params = default_tx_params;
v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
} else {
kfifo_free(&state->rx_kfifo);
diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig
index 5f6b54213713..4017c9420348 100644
--- a/drivers/media/pci/cx25821/Kconfig
+++ b/drivers/media/pci/cx25821/Kconfig
@@ -18,7 +18,7 @@ config VIDEO_CX25821
config VIDEO_CX25821_ALSA
tristate "Conexant 25821 DMA audio support"
- depends on VIDEO_CX25821 && SND && EXPERIMENTAL
+ depends on VIDEO_CX25821 && SND
select SND_PCM
---help---
This is a video4linux driver for direct (DMA) audio on
diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile
index 5bf3ea4c1556..caa32b7b51f8 100644
--- a/drivers/media/pci/cx25821/Makefile
+++ b/drivers/media/pci/cx25821/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/common
ccflags-y += -Idrivers/media/tuners
ccflags-y += -Idrivers/media/dvb-core
ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
index 53b16dd70320..d4de021dc844 100644
--- a/drivers/media/pci/cx25821/cx25821-video.c
+++ b/drivers/media/pci/cx25821/cx25821-video.c
@@ -130,7 +130,7 @@ void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
if ((s16) (count - buf->count) < 0)
break;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
buf->vb.state = VIDEOBUF_DONE;
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
diff --git a/drivers/media/pci/cx88/Kconfig b/drivers/media/pci/cx88/Kconfig
index d27fccbf03c4..bb05eca2da29 100644
--- a/drivers/media/pci/cx88/Kconfig
+++ b/drivers/media/pci/cx88/Kconfig
@@ -62,6 +62,8 @@ config VIDEO_CX88_DVB
select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
---help---
This adds support for DVB/ATSC cards based on the
diff --git a/drivers/media/pci/cx88/Makefile b/drivers/media/pci/cx88/Makefile
index d3679c3ee248..8619c1becee2 100644
--- a/drivers/media/pci/cx88/Makefile
+++ b/drivers/media/pci/cx88/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
ccflags-y += -Idrivers/media/i2c
+ccflags-y += -Idrivers/media/common
ccflags-y += -Idrivers/media/tuners
ccflags-y += -Idrivers/media/dvb-core
ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index 0c255248cbcd..e2e0b8faf7a4 100644
--- a/drivers/media/pci/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -3743,7 +3743,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
cx88_card_list(core, pci);
}
- memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
+ core->board = cx88_boards[core->boardnr];
if (!core->board.num_frontends && (core->board.mpeg & CX88_MPEG_DVB))
core->board.num_frontends = 1;
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index 19a58754c6e1..39f095c37ffd 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -549,7 +549,7 @@ void cx88_wakeup(struct cx88_core *core,
* up to 32767 buffers in flight... */
if ((s16) (count - buf->count) < 0)
break;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
count, buf->count);
buf->vb.state = VIDEOBUF_DONE;
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
index 666f83b2f3c0..672b267a2d3e 100644
--- a/drivers/media/pci/cx88/cx88-dvb.c
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -58,6 +58,7 @@
#include "stb6100.h"
#include "stb6100_proc.h"
#include "mb86a16.h"
+#include "ts2020.h"
#include "ds3000.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
@@ -264,7 +265,7 @@ static struct mb86a16_config twinhan_vp1027 = {
.demod_address = 0x08,
};
-#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054)
static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
{
static const u8 clock_config [] = { 0x89, 0x38, 0x38 };
@@ -700,6 +701,11 @@ static struct ds3000_config tevii_ds3000_config = {
.set_ts_params = ds3000_set_ts_param,
};
+static struct ts2020_config tevii_ts2020_config = {
+ .tuner_address = 0x60,
+ .clk_out_div = 1,
+};
+
static const struct stv0900_config prof_7301_stv0900_config = {
.demod_address = 0x6a,
/* demod_mode = 0,*/
@@ -1121,7 +1127,7 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054)
/* MT352 is on a secondary I2C bus made from some GPIO lines */
fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
&dev->vp3054->adap);
@@ -1466,9 +1472,12 @@ static int dvb_register(struct cx8802_dev *dev)
fe0->dvb.frontend = dvb_attach(ds3000_attach,
&tevii_ds3000_config,
&core->i2c_adap);
- if (fe0->dvb.frontend != NULL)
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(ts2020_attach, fe0->dvb.frontend,
+ &tevii_ts2020_config, &core->i2c_adap);
fe0->dvb.frontend->ops.set_voltage =
tevii_dvbs_set_voltage;
+ }
break;
case CX88_BOARD_OMICOM_SS4_PCI:
case CX88_BOARD_TBS_8920:
diff --git a/drivers/media/pci/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c
index de0f1af74e41..cf2d69615838 100644
--- a/drivers/media/pci/cx88/cx88-i2c.c
+++ b/drivers/media/pci/cx88/cx88-i2c.c
@@ -139,8 +139,7 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
if (i2c_udelay<5)
i2c_udelay=5;
- memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
- sizeof(core->i2c_algo));
+ core->i2c_algo = cx8800_i2c_algo_template;
core->i2c_adap.dev.parent = &pci->dev;
diff --git a/drivers/media/pci/cx88/cx88-vp3054-i2c.c b/drivers/media/pci/cx88/cx88-vp3054-i2c.c
index d77f8ecab9d7..deede6e25d94 100644
--- a/drivers/media/pci/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.c
@@ -118,8 +118,7 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
return -ENOMEM;
dev->vp3054 = vp3054_i2c;
- memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
- sizeof(vp3054_i2c->algo));
+ vp3054_i2c->algo = vp3054_i2c_algo_template;
vp3054_i2c->adap.dev.parent = &dev->pci->dev;
strlcpy(vp3054_i2c->adap.name, core->name,
diff --git a/drivers/media/pci/cx88/cx88-vp3054-i2c.h b/drivers/media/pci/cx88/cx88-vp3054-i2c.h
index be99c931dc3e..95d0c60a35e1 100644
--- a/drivers/media/pci/cx88/cx88-vp3054-i2c.h
+++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.h
@@ -30,7 +30,7 @@ struct vp3054_i2c_state {
};
/* ----------------------------------------------------------------------- */
-#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054)
int vp3054_i2c_probe(struct cx8802_dev *dev);
void vp3054_i2c_remove(struct cx8802_dev *dev);
#else
diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h
index ba0dba4a4d22..feff53c0a251 100644
--- a/drivers/media/pci/cx88/cx88.h
+++ b/drivers/media/pci/cx88/cx88.h
@@ -363,7 +363,7 @@ struct cx88_core {
unsigned int tuner_formats;
/* config info -- dvb */
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
+#if IS_ENABLED(CONFIG_VIDEO_CX88_DVB)
int (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
#endif
void (*gate_ctrl)(struct cx88_core *core, int open);
@@ -562,8 +562,7 @@ struct cx8802_dev {
/* for blackbird only */
struct list_head devlist;
-#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \
- defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE)
+#if IS_ENABLED(CONFIG_VIDEO_CX88_BLACKBIRD)
struct video_device *mpeg_dev;
u32 mailbox;
int width;
@@ -574,13 +573,12 @@ struct cx8802_dev {
struct cx2341x_handler cxhdl;
#endif
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
+#if IS_ENABLED(CONFIG_VIDEO_CX88_DVB)
/* for dvb only */
struct videobuf_dvb_frontends frontends;
#endif
-#if defined(CONFIG_VIDEO_CX88_VP3054) || \
- defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+#if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054)
/* For VP3045 secondary I2C bus support */
struct vp3054_i2c_state *vp3054;
#endif
diff --git a/drivers/media/pci/dm1105/Kconfig b/drivers/media/pci/dm1105/Kconfig
index 013df4e015cd..173daf0c0847 100644
--- a/drivers/media/pci/dm1105/Kconfig
+++ b/drivers/media/pci/dm1105/Kconfig
@@ -8,6 +8,7 @@ config DVB_DM1105
select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
select DVB_SI21XX if MEDIA_SUBDRV_AUTOSELECT
select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
depends on RC_CORE
help
Support for cards based on the SDMC DM1105 PCI chip like
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index 904c3ea350f5..026767bed5cd 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -45,6 +45,7 @@
#include "si21xx.h"
#include "cx24116.h"
#include "z0194a.h"
+#include "ts2020.h"
#include "ds3000.h"
#define MODULE_NAME "dm1105"
@@ -849,6 +850,11 @@ static struct ds3000_config dvbworld_ds3000_config = {
.demod_address = 0x68,
};
+static struct ts2020_config dvbworld_ts2020_config = {
+ .tuner_address = 0x60,
+ .clk_out_div = 1,
+};
+
static int frontend_init(struct dm1105_dev *dev)
{
int ret;
@@ -898,8 +904,11 @@ static int frontend_init(struct dm1105_dev *dev)
dev->fe = dvb_attach(
ds3000_attach, &dvbworld_ds3000_config,
&dev->i2c_adap);
- if (dev->fe)
+ if (dev->fe) {
+ dvb_attach(ts2020_attach, dev->fe,
+ &dvbworld_ts2020_config, &dev->i2c_adap);
dev->fe->ops.set_voltage = dm1105_set_voltage;
+ }
break;
case DM1105_BOARD_DVBWORLD_2002:
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c
index 4a221c693995..e970cface70e 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-main.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c
@@ -205,7 +205,7 @@ err_exit:
return ret;
}
-static int __init ivtv_alsa_load(struct ivtv *itv)
+static int ivtv_alsa_load(struct ivtv *itv)
{
struct v4l2_device *v4l2_dev = &itv->v4l2_dev;
struct ivtv_stream *s;
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.h b/drivers/media/pci/ivtv/ivtv-alsa-pcm.h
index 23dfe0d12400..186814e0b2d4 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.h
+++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.h
@@ -20,4 +20,4 @@
* 02111-1307 USA
*/
-int __init snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc);
+int snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc);
diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c
index df88dc4ab555..2928e7287da8 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.c
+++ b/drivers/media/pci/ivtv/ivtv-driver.c
@@ -304,7 +304,7 @@ static void request_modules(struct ivtv *dev)
static void flush_request_modules(struct ivtv *dev)
{
- flush_work_sync(&dev->request_module_wk);
+ flush_work(&dev->request_module_wk);
}
#else
#define request_modules(dev)
diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c
index 46e262becb67..ceed2d87abfd 100644
--- a/drivers/media/pci/ivtv/ivtv-i2c.c
+++ b/drivers/media/pci/ivtv/ivtv-i2c.c
@@ -267,8 +267,6 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
const char *type = hw_devicenames[idx];
u32 hw = 1 << idx;
- if (idx >= ARRAY_SIZE(hw_addrs))
- return -1;
if (hw == IVTV_HW_TUNER) {
/* special tuner handling */
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
@@ -719,13 +717,10 @@ int init_ivtv_i2c(struct ivtv *itv)
return -ENODEV;
}
if (itv->options.newi2c > 0) {
- memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template,
- sizeof(struct i2c_adapter));
+ itv->i2c_adap = ivtv_i2c_adap_hw_template;
} else {
- memcpy(&itv->i2c_adap, &ivtv_i2c_adap_template,
- sizeof(struct i2c_adapter));
- memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template,
- sizeof(struct i2c_algo_bit_data));
+ itv->i2c_adap = ivtv_i2c_adap_template;
+ itv->i2c_algo = ivtv_i2c_algo_template;
}
itv->i2c_algo.udelay = itv->options.i2c_clock_period / 2;
itv->i2c_algo.data = itv;
@@ -735,8 +730,7 @@ int init_ivtv_i2c(struct ivtv *itv)
itv->instance);
i2c_set_adapdata(&itv->i2c_adap, &itv->v4l2_dev);
- memcpy(&itv->i2c_client, &ivtv_i2c_client_template,
- sizeof(struct i2c_client));
+ itv->i2c_client = ivtv_i2c_client_template;
itv->i2c_client.adapter = &itv->i2c_adap;
itv->i2c_adap.dev.parent = &itv->pdev->dev;
diff --git a/drivers/media/pci/ivtv/ivtv-vbi.c b/drivers/media/pci/ivtv/ivtv-vbi.c
index 293db806d936..3c156bc70fb4 100644
--- a/drivers/media/pci/ivtv/ivtv-vbi.c
+++ b/drivers/media/pci/ivtv/ivtv-vbi.c
@@ -224,7 +224,7 @@ static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
(the max size of the VBI data is 36 * 43 + 4 bytes).
So in this case we use the magic number 'ITV0'. */
memcpy(dst + sd, "ITV0", 4);
- memcpy(dst + sd + 4, dst + sd + 12, line * 43);
+ memmove(dst + sd + 4, dst + sd + 12, line * 43);
size = 4 + ((43 * line + 3) & ~3);
} else {
memcpy(dst + sd, "itv0", 4);
@@ -532,7 +532,7 @@ void ivtv_vbi_work_handler(struct ivtv *itv)
while (vi->cc_payload_idx) {
cc = vi->cc_payload[0];
- memcpy(vi->cc_payload, vi->cc_payload + 1,
+ memmove(vi->cc_payload, vi->cc_payload + 1,
sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0]));
vi->cc_payload_idx--;
if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80)
diff --git a/drivers/media/pci/mantis/mantis_ca.c b/drivers/media/pci/mantis/mantis_ca.c
index 3d7046909009..60c6c2f24066 100644
--- a/drivers/media/pci/mantis/mantis_ca.c
+++ b/drivers/media/pci/mantis/mantis_ca.c
@@ -198,11 +198,12 @@ void mantis_ca_exit(struct mantis_pci *mantis)
struct mantis_ca *ca = mantis->mantis_ca;
dprintk(MANTIS_DEBUG, 1, "Mantis CA exit");
+ if (!ca)
+ return;
mantis_evmgr_exit(ca);
dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device");
- if (ca)
- dvb_ca_en50221_release(&ca->en50221);
+ dvb_ca_en50221_release(&ca->en50221);
kfree(ca);
}
diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c
index 049e18667cd0..7859c43479d7 100644
--- a/drivers/media/pci/meye/meye.c
+++ b/drivers/media/pci/meye/meye.c
@@ -35,6 +35,8 @@
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/delay.h>
@@ -811,7 +813,7 @@ again:
mchip_hsize() * mchip_vsize() * 2);
meye.grab_buffer[reqnr].size = mchip_hsize() * mchip_vsize() * 2;
meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
- do_gettimeofday(&meye.grab_buffer[reqnr].timestamp);
+ v4l2_get_timestamp(&meye.grab_buffer[reqnr].timestamp);
meye.grab_buffer[reqnr].sequence = sequence++;
kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr,
sizeof(int), &meye.doneq_lock);
@@ -832,7 +834,7 @@ again:
size);
meye.grab_buffer[reqnr].size = size;
meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
- do_gettimeofday(&meye.grab_buffer[reqnr].timestamp);
+ v4l2_get_timestamp(&meye.grab_buffer[reqnr].timestamp);
meye.grab_buffer[reqnr].sequence = sequence++;
kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr,
sizeof(int), &meye.doneq_lock);
@@ -865,7 +867,7 @@ static int meye_open(struct file *file)
meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
kfifo_reset(&meye.grabq);
kfifo_reset(&meye.doneq);
- return 0;
+ return v4l2_fh_open(file);
}
static int meye_release(struct file *file)
@@ -873,7 +875,7 @@ static int meye_release(struct file *file)
mchip_hic_stop();
mchip_dma_free();
clear_bit(0, &meye.in_use);
- return 0;
+ return v4l2_fh_release(file);
}
static int meyeioc_g_params(struct meye_params *p)
@@ -1032,8 +1034,9 @@ static int vidioc_querycap(struct file *file, void *fh,
cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
MEYE_DRIVER_MINORVERSION;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1063,191 +1066,50 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *fh,
- struct v4l2_queryctrl *c)
-{
- switch (c->id) {
-
- case V4L2_CID_BRIGHTNESS:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Brightness");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_HUE:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Hue");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_CONTRAST:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Contrast");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_SATURATION:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Saturation");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_AGC:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Agc");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 48;
- c->flags = 0;
- break;
- case V4L2_CID_MEYE_SHARPNESS:
- case V4L2_CID_SHARPNESS:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Sharpness");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
-
- /* Continue to report legacy private SHARPNESS ctrl but
- * say it is disabled in preference to ctrl in the spec
- */
- c->flags = (c->id == V4L2_CID_SHARPNESS) ? 0 :
- V4L2_CTRL_FLAG_DISABLED;
- break;
- case V4L2_CID_PICTURE:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Picture");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 0;
- c->flags = 0;
- break;
- case V4L2_CID_JPEGQUAL:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "JPEG quality");
- c->minimum = 0;
- c->maximum = 10;
- c->step = 1;
- c->default_value = 8;
- c->flags = 0;
- break;
- case V4L2_CID_FRAMERATE:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Framerate");
- c->minimum = 0;
- c->maximum = 31;
- c->step = 1;
- c->default_value = 0;
- c->flags = 0;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+static int meye_s_ctrl(struct v4l2_ctrl *ctrl)
{
mutex_lock(&meye.lock);
- switch (c->id) {
+ switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
- meye.brightness = c->value << 10;
+ SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, ctrl->val);
+ meye.brightness = ctrl->val << 10;
break;
case V4L2_CID_HUE:
sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
- meye.hue = c->value << 10;
+ SONY_PIC_COMMAND_SETCAMERAHUE, ctrl->val);
+ meye.hue = ctrl->val << 10;
break;
case V4L2_CID_CONTRAST:
sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
- meye.contrast = c->value << 10;
+ SONY_PIC_COMMAND_SETCAMERACONTRAST, ctrl->val);
+ meye.contrast = ctrl->val << 10;
break;
case V4L2_CID_SATURATION:
sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
- meye.colour = c->value << 10;
+ SONY_PIC_COMMAND_SETCAMERACOLOR, ctrl->val);
+ meye.colour = ctrl->val << 10;
break;
- case V4L2_CID_AGC:
+ case V4L2_CID_MEYE_AGC:
sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
- meye.params.agc = c->value;
+ SONY_PIC_COMMAND_SETCAMERAAGC, ctrl->val);
+ meye.params.agc = ctrl->val;
break;
case V4L2_CID_SHARPNESS:
- case V4L2_CID_MEYE_SHARPNESS:
sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
- meye.params.sharpness = c->value;
+ SONY_PIC_COMMAND_SETCAMERASHARPNESS, ctrl->val);
+ meye.params.sharpness = ctrl->val;
break;
- case V4L2_CID_PICTURE:
+ case V4L2_CID_MEYE_PICTURE:
sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
- meye.params.picture = c->value;
+ SONY_PIC_COMMAND_SETCAMERAPICTURE, ctrl->val);
+ meye.params.picture = ctrl->val;
break;
- case V4L2_CID_JPEGQUAL:
- meye.params.quality = c->value;
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ meye.params.quality = ctrl->val;
break;
- case V4L2_CID_FRAMERATE:
- meye.params.framerate = c->value;
- break;
- default:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- mutex_unlock(&meye.lock);
-
- return 0;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
-{
- mutex_lock(&meye.lock);
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- c->value = meye.brightness >> 10;
- break;
- case V4L2_CID_HUE:
- c->value = meye.hue >> 10;
- break;
- case V4L2_CID_CONTRAST:
- c->value = meye.contrast >> 10;
- break;
- case V4L2_CID_SATURATION:
- c->value = meye.colour >> 10;
- break;
- case V4L2_CID_AGC:
- c->value = meye.params.agc;
- break;
- case V4L2_CID_SHARPNESS:
- case V4L2_CID_MEYE_SHARPNESS:
- c->value = meye.params.sharpness;
- break;
- case V4L2_CID_PICTURE:
- c->value = meye.params.picture;
- break;
- case V4L2_CID_JPEGQUAL:
- c->value = meye.params.quality;
- break;
- case V4L2_CID_FRAMERATE:
- c->value = meye.params.framerate;
+ case V4L2_CID_MEYE_FRAMERATE:
+ meye.params.framerate = ctrl->val;
break;
default:
mutex_unlock(&meye.lock);
@@ -1426,7 +1288,7 @@ static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
return -EINVAL;
buf->bytesused = meye.grab_buffer[index].size;
- buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
if (meye.grab_buffer[index].state == MEYE_BUF_USING)
buf->flags |= V4L2_BUF_FLAG_QUEUED;
@@ -1499,7 +1361,7 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
buf->index = reqnr;
buf->bytesused = meye.grab_buffer[reqnr].size;
- buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
buf->field = V4L2_FIELD_NONE;
buf->timestamp = meye.grab_buffer[reqnr].timestamp;
buf->sequence = meye.grab_buffer[reqnr].sequence;
@@ -1577,12 +1439,12 @@ static long vidioc_default(struct file *file, void *fh, bool valid_prio,
static unsigned int meye_poll(struct file *file, poll_table *wait)
{
- unsigned int res = 0;
+ unsigned int res = v4l2_ctrl_poll(file, wait);
mutex_lock(&meye.lock);
poll_wait(file, &meye.proc_list, wait);
if (kfifo_len(&meye.doneq))
- res = POLLIN | POLLRDNORM;
+ res |= POLLIN | POLLRDNORM;
mutex_unlock(&meye.lock);
return res;
}
@@ -1669,9 +1531,6 @@ static const struct v4l2_ioctl_ops meye_ioctl_ops = {
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
@@ -1682,6 +1541,9 @@ static const struct v4l2_ioctl_ops meye_ioctl_ops = {
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
.vidioc_default = vidioc_default,
};
@@ -1692,6 +1554,10 @@ static struct video_device meye_template = {
.release = video_device_release,
};
+static const struct v4l2_ctrl_ops meye_ctrl_ops = {
+ .s_ctrl = meye_s_ctrl,
+};
+
#ifdef CONFIG_PM
static int meye_suspend(struct pci_dev *pdev, pm_message_t state)
{
@@ -1730,6 +1596,32 @@ static int meye_resume(struct pci_dev *pdev)
static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
{
+ static const struct v4l2_ctrl_config ctrl_agc = {
+ .id = V4L2_CID_MEYE_AGC,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .ops = &meye_ctrl_ops,
+ .name = "AGC",
+ .max = 63,
+ .step = 1,
+ .def = 48,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ };
+ static const struct v4l2_ctrl_config ctrl_picture = {
+ .id = V4L2_CID_MEYE_PICTURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .ops = &meye_ctrl_ops,
+ .name = "Picture",
+ .max = 63,
+ .step = 1,
+ };
+ static const struct v4l2_ctrl_config ctrl_framerate = {
+ .id = V4L2_CID_MEYE_FRAMERATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .ops = &meye_ctrl_ops,
+ .name = "Framerate",
+ .max = 31,
+ .step = 1,
+ };
struct v4l2_device *v4l2_dev = &meye.v4l2_dev;
int ret = -EBUSY;
unsigned long mchip_adr;
@@ -1833,24 +1725,31 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
mutex_init(&meye.lock);
init_waitqueue_head(&meye.proc_list);
- meye.brightness = 32 << 10;
- meye.hue = 32 << 10;
- meye.colour = 32 << 10;
- meye.contrast = 32 << 10;
- meye.params.subsample = 0;
- meye.params.quality = 8;
- meye.params.sharpness = 32;
- meye.params.agc = 48;
- meye.params.picture = 0;
- meye.params.framerate = 0;
-
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, 32);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, 32);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, 32);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, 32);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, 32);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
+
+ v4l2_ctrl_handler_init(&meye.hdl, 3);
+ v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 63, 1, 32);
+ v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
+ V4L2_CID_HUE, 0, 63, 1, 32);
+ v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 63, 1, 32);
+ v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 63, 1, 32);
+ v4l2_ctrl_new_custom(&meye.hdl, &ctrl_agc, NULL);
+ v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0, 63, 1, 32);
+ v4l2_ctrl_new_custom(&meye.hdl, &ctrl_picture, NULL);
+ v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 0, 10, 1, 8);
+ v4l2_ctrl_new_custom(&meye.hdl, &ctrl_framerate, NULL);
+ if (meye.hdl.error) {
+ v4l2_err(v4l2_dev, "couldn't register controls\n");
+ goto outvideoreg;
+ }
+
+ v4l2_ctrl_handler_setup(&meye.hdl);
+ meye.vdev->ctrl_handler = &meye.hdl;
+ set_bit(V4L2_FL_USE_FH_PRIO, &meye.vdev->flags);
if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
video_nr) < 0) {
@@ -1866,6 +1765,7 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
return 0;
outvideoreg:
+ v4l2_ctrl_handler_free(&meye.hdl);
free_irq(meye.mchip_irq, meye_irq);
outreqirq:
iounmap(meye.mchip_mmregs);
diff --git a/drivers/media/pci/meye/meye.h b/drivers/media/pci/meye/meye.h
index 4bdeb03f1644..6fed9274cfa5 100644
--- a/drivers/media/pci/meye/meye.h
+++ b/drivers/media/pci/meye/meye.h
@@ -39,6 +39,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/kfifo.h>
+#include <media/v4l2-ctrls.h>
/****************************************************************************/
/* Motion JPEG chip registers */
@@ -290,6 +291,7 @@ struct meye_grab_buffer {
/* Motion Eye device structure */
struct meye {
struct v4l2_device v4l2_dev; /* Main v4l2_device struct */
+ struct v4l2_ctrl_handler hdl;
struct pci_dev *mchip_dev; /* pci device */
u8 mchip_irq; /* irq */
u8 mchip_mode; /* actual mchip mode: HIC_MODE... */
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c
index fad214113669..9e82d2105d53 100644
--- a/drivers/media/pci/ngene/ngene-cards.c
+++ b/drivers/media/pci/ngene/ngene-cards.c
@@ -327,6 +327,14 @@ static int demod_attach_drxd(struct ngene_channel *chan)
pr_err("No DRXD found!\n");
return -ENODEV;
}
+ return 0;
+}
+
+static int tuner_attach_dtt7520x(struct ngene_channel *chan)
+{
+ struct drxd_config *feconf;
+
+ feconf = chan->dev->card_info->fe_config[chan->number];
if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address,
&chan->i2c_adapter,
@@ -724,6 +732,7 @@ static struct ngene_info ngene_info_terratec = {
.name = "Terratec Integra/Cinergy2400i Dual DVB-T",
.io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},
.demod_attach = {demod_attach_drxd, demod_attach_drxd},
+ .tuner_attach = {tuner_attach_dtt7520x, tuner_attach_dtt7520x},
.fe_config = {&fe_terratec_dvbt_0, &fe_terratec_dvbt_1},
.i2c_access = 1,
};
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
index bc08f1dbc293..dc68cf1070f7 100644
--- a/drivers/media/pci/saa7134/saa7134-cards.c
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -5773,6 +5773,23 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x0000000,
},
},
+ [SAA7134_BOARD_HAWELL_HW_9004V1] = {
+ /* Hawell HW-9004V1 */
+ /* Vadim Frolov <fralik@gmail.com> */
+ .name = "Hawell HW-9004V1",
+ .audio_clock = 0x00200000,
+ .tuner_type = UNSET,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x618E700,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x6010000,
+ } },
+ },
};
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index e359d200d698..8fd24e7c9403 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -308,7 +308,7 @@ void saa7134_buffer_finish(struct saa7134_dev *dev,
/* finish current buffer */
q->curr->vb.state = state;
- do_gettimeofday(&q->curr->vb.ts);
+ v4l2_get_timestamp(&q->curr->vb.ts);
wake_up(&q->curr->vb.done);
q->curr = NULL;
}
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c
index b209de40a4f8..27915e501db9 100644
--- a/drivers/media/pci/saa7134/saa7134-dvb.c
+++ b/drivers/media/pci/saa7134/saa7134-dvb.c
@@ -607,6 +607,9 @@ static int configure_tda827x_fe(struct saa7134_dev *dev,
/* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
+
fe0->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
if (fe0->dvb.frontend) {
if (cdec_conf->i2c_gate)
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 3abf52711e13..7c503fb68526 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -2248,6 +2248,17 @@ static int saa7134_streamon(struct file *file, void *priv,
if (!res_get(dev, fh, res))
return -EBUSY;
+ /* The SAA7134 has a 1K FIFO; the datasheet suggests that when
+ * configured conservatively, there's 22 usec of buffering for video.
+ * We therefore request a DMA latency of 20 usec, giving us 2 usec of
+ * margin in case the FIFO is configured differently to the datasheet.
+ * Unfortunately, I lack register-level documentation to check the
+ * Linux FIFO setup and confirm the perfect value.
+ */
+ pm_qos_add_request(&fh->qos_request,
+ PM_QOS_CPU_DMA_LATENCY,
+ 20);
+
return videobuf_streamon(saa7134_queue(fh));
}
@@ -2259,6 +2270,8 @@ static int saa7134_streamoff(struct file *file, void *priv,
struct saa7134_dev *dev = fh->dev;
int res = saa7134_resource(fh);
+ pm_qos_remove_request(&fh->qos_request);
+
err = videobuf_streamoff(saa7134_queue(fh));
if (err < 0)
return err;
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 075908fae4d9..71eefef5e324 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -29,6 +29,7 @@
#include <linux/notifier.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/pm_qos.h>
#include <asm/io.h>
@@ -41,7 +42,7 @@
#include <media/videobuf-dma-sg.h>
#include <sound/core.h>
#include <sound/pcm.h>
-#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
+#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
#include <media/videobuf-dvb.h>
#endif
@@ -332,6 +333,7 @@ struct saa7134_card_ir {
#define SAA7134_BOARD_SENSORAY811_911 188
#define SAA7134_BOARD_KWORLD_PC150U 189
#define SAA7134_BOARD_ASUSTeK_PS3_100 190
+#define SAA7134_BOARD_HAWELL_HW_9004V1 191
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
@@ -469,6 +471,7 @@ struct saa7134_fh {
enum v4l2_buf_type type;
unsigned int resources;
enum v4l2_priority prio;
+ struct pm_qos_request qos_request;
/* video overlay */
struct v4l2_window win;
@@ -642,7 +645,7 @@ struct saa7134_dev {
struct work_struct empress_workqueue;
int empress_started;
-#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
+#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb_frontends frontends;
int (*original_demod_sleep)(struct dvb_frontend *fe);
diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c
index 994018e2d0d6..9bb0903ee5f1 100644
--- a/drivers/media/pci/saa7164/saa7164-encoder.c
+++ b/drivers/media/pci/saa7164/saa7164-encoder.c
@@ -1298,6 +1298,7 @@ static int saa7164_g_chip_ident(struct file *file, void *fh,
return 0;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
static int saa7164_g_register(struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
@@ -1323,6 +1324,7 @@ static int saa7164_s_register(struct file *file, void *fh,
return 0;
}
+#endif
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_s_std = vidioc_s_std,
diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig
index 6749f67cab8a..a94ccad02066 100644
--- a/drivers/media/pci/sta2x11/Kconfig
+++ b/drivers/media/pci/sta2x11/Kconfig
@@ -2,7 +2,7 @@ config STA2X11_VIP
tristate "STA2X11 VIP Video For Linux"
depends on STA2X11
select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
- select VIDEOBUF_DMA_CONTIG
+ select VIDEOBUF2_DMA_CONTIG
depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
help
Say Y for support for STA2X11 VIP (Video Input Port) capture
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 27ae48842656..4b703fe8c953 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -1,7 +1,11 @@
/*
* This is the driver for the STA2x11 Video Input Port.
*
+ * Copyright (C) 2012 ST Microelectronics
+ * author: Federico Vaga <federico.vaga@gmail.com>
* Copyright (C) 2010 WindRiver Systems, Inc.
+ * authors: Andreas Kies <andreas.kies@windriver.com>
+ * Vlad Lungu <vlad.lungu@windriver.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -19,36 +23,30 @@
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
- * Author: Andreas Kies <andreas.kies@windriver.com>
- * Vlad Lungu <vlad.lungu@windriver.com>
- *
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/vmalloc.h>
-
#include <linux/videodev2.h>
-
#include <linux/kmod.h>
-
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-ioctl.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
#include "sta2x11_vip.h"
-#define DRV_NAME "sta2x11_vip"
#define DRV_VERSION "1.3"
#ifndef PCI_DEVICE_ID_STMICRO_VIP
@@ -63,8 +61,8 @@
#define DVP_TFS 0x08
#define DVP_BFO 0x0C
#define DVP_BFS 0x10
-#define DVP_VTP 0x14
-#define DVP_VBP 0x18
+#define DVP_VTP 0x14
+#define DVP_VBP 0x18
#define DVP_VMP 0x1C
#define DVP_ITM 0x98
#define DVP_ITS 0x9C
@@ -84,13 +82,21 @@
#define DVP_HLFLN_SD 0x00000001
-#define REG_WRITE(vip, reg, value) iowrite32((value), (vip->iomem)+(reg))
-#define REG_READ(vip, reg) ioread32((vip->iomem)+(reg))
-
#define SAVE_COUNT 8
#define AUX_COUNT 3
#define IRQ_COUNT 1
+
+struct vip_buffer {
+ struct vb2_buffer vb;
+ struct list_head list;
+ dma_addr_t dma;
+};
+static inline struct vip_buffer *to_vip_buffer(struct vb2_buffer *vb2)
+{
+ return container_of(vb2, struct vip_buffer, vb);
+}
+
/**
* struct sta2x11_vip - All internal data for one instance of device
* @v4l2_dev: device registered in v4l layer
@@ -99,29 +105,26 @@
* @adapter: contains I2C adapter information
* @register_save_area: All relevant register are saved here during suspend
* @decoder: contains information about video DAC
+ * @ctrl_hdl: handler for control framework
* @format: pixel format, fixed UYVY
* @std: video standard (e.g. PAL/NTSC)
* @input: input line for video signal ( 0 or 1 )
- * @users: Number of open of device ( max. 1 )
* @disabled: Device is in power down state
- * @mutex: ensures exclusive opening of device
* @slock: for excluse acces of registers
- * @vb_vidq: queue maintained by videobuf layer
- * @capture: linked list of capture buffer
- * @active: struct videobuf_buffer currently beingg filled
- * @started: device is ready to capture frame
- * @closing: device will be shut down
+ * @alloc_ctx: context for videobuf2
+ * @vb_vidq: queue maintained by videobuf2 layer
+ * @buffer_list: list of buffer in use
+ * @sequence: sequence number of acquired buffer
+ * @active: current active buffer
+ * @lock: used in videobuf2 callback
* @tcount: Number of top frames
* @bcount: Number of bottom frames
* @overflow: Number of FIFO overflows
- * @mem_spare: small buffer of unused frame
- * @dma_spare: dma addres of mem_spare
* @iomem: hardware base address
* @config: I2C and gpio config from platform
*
* All non-local data is accessed via this structure.
*/
-
struct sta2x11_vip {
struct v4l2_device v4l2_dev;
struct video_device *video_dev;
@@ -129,21 +132,27 @@ struct sta2x11_vip {
struct i2c_adapter *adapter;
unsigned int register_save_area[IRQ_COUNT + SAVE_COUNT + AUX_COUNT];
struct v4l2_subdev *decoder;
+ struct v4l2_ctrl_handler ctrl_hdl;
+
+
struct v4l2_pix_format format;
v4l2_std_id std;
unsigned int input;
- int users;
int disabled;
- struct mutex mutex; /* exclusive access during open */
- spinlock_t slock; /* spin lock for hardware and queue access */
- struct videobuf_queue vb_vidq;
- struct list_head capture;
- struct videobuf_buffer *active;
- int started, closing, tcount, bcount;
+ spinlock_t slock;
+
+ struct vb2_alloc_ctx *alloc_ctx;
+ struct vb2_queue vb_vidq;
+ struct list_head buffer_list;
+ unsigned int sequence;
+ struct vip_buffer *active; /* current active buffer */
+ spinlock_t lock; /* Used in videobuf2 callback */
+
+ /* Interrupt counters */
+ int tcount, bcount;
int overflow;
- void *mem_spare;
- dma_addr_t dma_spare;
- void *iomem;
+
+ void *iomem; /* I/O Memory */
struct vip_config *config;
};
@@ -206,318 +215,195 @@ static struct v4l2_pix_format formats_60[] = {
.colorspace = V4L2_COLORSPACE_SMPTE170M},
};
-/**
- * buf_setup - Get size and number of video buffer
- * @vq: queue in videobuf
- * @count: Number of buffers (1..MAX_FRAMES).
- * 0 use default value.
- * @size: size of buffer in bytes
- *
- * returns size and number of buffers
- * a preset value of 0 returns the default number.
- * return value: 0, always succesfull.
- */
-static int buf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
+/* Write VIP register */
+static inline void reg_write(struct sta2x11_vip *vip, unsigned int reg, u32 val)
{
- struct sta2x11_vip *vip = vq->priv_data;
-
- *size = vip->format.width * vip->format.height * 2;
- if (0 == *count || MAX_FRAMES < *count)
- *count = MAX_FRAMES;
- return 0;
-};
-
-/**
- * buf_prepare - prepare buffer for usage
- * @vq: queue in videobuf layer
- * @vb: buffer to be prepared
- * @field: type of video data (interlaced/non-interlaced)
- *
- * Allocate or realloc buffer
- * return value: 0, successful.
- *
- * -EINVAL, supplied buffer is too small.
- *
- * other, buffer could not be locked.
- */
-static int buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
+ iowrite32((val), (vip->iomem)+(reg));
+}
+/* Read VIP register */
+static inline u32 reg_read(struct sta2x11_vip *vip, unsigned int reg)
{
- struct sta2x11_vip *vip = vq->priv_data;
- int ret;
-
- vb->size = vip->format.width * vip->format.height * 2;
- if ((0 != vb->baddr) && (vb->bsize < vb->size))
- return -EINVAL;
- vb->width = vip->format.width;
- vb->height = vip->format.height;
- vb->field = field;
-
- if (VIDEOBUF_NEEDS_INIT == vb->state) {
- ret = videobuf_iolock(vq, vb, NULL);
- if (ret)
- goto fail;
- }
- vb->state = VIDEOBUF_PREPARED;
- return 0;
-fail:
- videobuf_dma_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
- return ret;
+ return ioread32((vip->iomem)+(reg));
}
-
-/**
- * buf_queu - queue buffer for filling
- * @vq: queue in videobuf layer
- * @vb: buffer to be queued
- *
- * if capturing is already running, the buffer will be queued. Otherwise
- * capture is started and the buffer is used directly.
- */
-static void buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+/* Start DMA acquisition */
+static void start_dma(struct sta2x11_vip *vip, struct vip_buffer *vip_buf)
{
- struct sta2x11_vip *vip = vq->priv_data;
- u32 dma;
+ unsigned long offset = 0;
+
+ if (vip->format.field == V4L2_FIELD_INTERLACED)
+ offset = vip->format.width * 2;
- vb->state = VIDEOBUF_QUEUED;
+ spin_lock_irq(&vip->slock);
+ /* Enable acquisition */
+ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) | DVP_CTL_ENA);
+ /* Set Top and Bottom Field memory address */
+ reg_write(vip, DVP_VTP, (u32)vip_buf->dma);
+ reg_write(vip, DVP_VBP, (u32)vip_buf->dma + offset);
+ spin_unlock_irq(&vip->slock);
+}
- if (vip->active) {
- list_add_tail(&vb->queue, &vip->capture);
+/* Fetch the next buffer to activate */
+static void vip_active_buf_next(struct sta2x11_vip *vip)
+{
+ /* Get the next buffer */
+ spin_lock(&vip->lock);
+ if (list_empty(&vip->buffer_list)) {/* No available buffer */
+ spin_unlock(&vip->lock);
return;
}
-
- vip->started = 1;
+ vip->active = list_first_entry(&vip->buffer_list,
+ struct vip_buffer,
+ list);
+ /* Reset Top and Bottom counter */
vip->tcount = 0;
vip->bcount = 0;
- vip->active = vb;
- vb->state = VIDEOBUF_ACTIVE;
+ spin_unlock(&vip->lock);
+ if (vb2_is_streaming(&vip->vb_vidq)) { /* streaming is on */
+ start_dma(vip, vip->active); /* start dma capture */
+ }
+}
- dma = videobuf_to_dma_contig(vb);
- REG_WRITE(vip, DVP_TFO, (0 << 16) | (0));
- /* despite of interlace mode, upper and lower frames start at zero */
- REG_WRITE(vip, DVP_BFO, (0 << 16) | (0));
+/* Videobuf2 Operations */
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vq);
- switch (vip->format.field) {
- case V4L2_FIELD_INTERLACED:
- REG_WRITE(vip, DVP_TFS,
- ((vip->format.height / 2 - 1) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_BFS, ((vip->format.height / 2 - 1) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
- REG_WRITE(vip, DVP_VMP, 4 * vip->format.width);
- break;
- case V4L2_FIELD_TOP:
- REG_WRITE(vip, DVP_TFS,
- ((vip->format.height - 1) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_BFS, ((0) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma);
- REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
- break;
- case V4L2_FIELD_BOTTOM:
- REG_WRITE(vip, DVP_TFS, ((0) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_BFS,
- ((vip->format.height) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma);
- REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
- break;
+ if (!(*nbuffers) || *nbuffers < MAX_FRAMES)
+ *nbuffers = MAX_FRAMES;
- default:
- pr_warning("VIP: unknown field format\n");
- return;
- }
+ *nplanes = 1;
+ sizes[0] = vip->format.sizeimage;
+ alloc_ctxs[0] = vip->alloc_ctx;
- REG_WRITE(vip, DVP_CTL, DVP_CTL_ENA);
-}
+ vip->sequence = 0;
+ vip->active = NULL;
+ vip->tcount = 0;
+ vip->bcount = 0;
-/**
- * buff_release - release buffer
- * @vq: queue in videobuf layer
- * @vb: buffer to be released
- *
- * release buffer in videobuf layer
- */
-static void buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ return 0;
+};
+static int buffer_init(struct vb2_buffer *vb)
{
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
- videobuf_dma_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
+ vip_buf->dma = vb2_dma_contig_plane_dma_addr(vb, 0);
+ INIT_LIST_HEAD(&vip_buf->list);
+ return 0;
}
-static struct videobuf_queue_ops vip_qops = {
- .buf_setup = buf_setup,
- .buf_prepare = buf_prepare,
- .buf_queue = buf_queue,
- .buf_release = buf_release,
-};
-
-/**
- * vip_open - open video device
- * @file: descriptor of device
- *
- * open device, make sure it is only opened once.
- * return value: 0, no error.
- *
- * -EBUSY, device is already opened
- *
- * -ENOMEM, no memory for auxiliary DMA buffer
- */
-static int vip_open(struct file *file)
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct video_device *dev = video_devdata(file);
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue);
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
+ unsigned long size;
+
+ size = vip->format.sizeimage;
+ if (vb2_plane_size(vb, 0) < size) {
+ v4l2_err(&vip->v4l2_dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
- mutex_lock(&vip->mutex);
- vip->users++;
+ vb2_set_plane_payload(&vip_buf->vb, 0, size);
- if (vip->users > 1) {
- vip->users--;
- mutex_unlock(&vip->mutex);
- return -EBUSY;
+ return 0;
+}
+static void buffer_queue(struct vb2_buffer *vb)
+{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue);
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
+
+ spin_lock(&vip->lock);
+ list_add_tail(&vip_buf->list, &vip->buffer_list);
+ if (!vip->active) { /* No active buffer, active the first one */
+ vip->active = list_first_entry(&vip->buffer_list,
+ struct vip_buffer,
+ list);
+ if (vb2_is_streaming(&vip->vb_vidq)) /* streaming is on */
+ start_dma(vip, vip_buf); /* start dma capture */
}
+ spin_unlock(&vip->lock);
+}
+static int buffer_finish(struct vb2_buffer *vb)
+{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue);
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
- file->private_data = dev;
- vip->overflow = 0;
- vip->started = 0;
- vip->closing = 0;
- vip->active = NULL;
+ /* Buffer handled, remove it from the list */
+ spin_lock(&vip->lock);
+ list_del_init(&vip_buf->list);
+ spin_unlock(&vip->lock);
- INIT_LIST_HEAD(&vip->capture);
- vip->mem_spare = dma_alloc_coherent(&vip->pdev->dev, 64,
- &vip->dma_spare, GFP_KERNEL);
- if (!vip->mem_spare) {
- vip->users--;
- mutex_unlock(&vip->mutex);
- return -ENOMEM;
- }
+ vip_active_buf_next(vip);
- mutex_unlock(&vip->mutex);
- videobuf_queue_dma_contig_init_cached(&vip->vb_vidq,
- &vip_qops,
- &vip->pdev->dev,
- &vip->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct videobuf_buffer),
- vip, NULL);
- REG_READ(vip, DVP_ITS);
- REG_WRITE(vip, DVP_HLFLN, DVP_HLFLN_SD);
- REG_WRITE(vip, DVP_ITM, DVP_IT_VSB | DVP_IT_VST);
- REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
- REG_WRITE(vip, DVP_CTL, 0);
- REG_READ(vip, DVP_ITS);
return 0;
}
-/**
- * vip_close - close video device
- * @file: descriptor of device
- *
- * close video device, wait until all pending operations are finished
- * ( maximum FRAME_MAX buffers pending )
- * Turn off interrupts.
- *
- * return value: 0, always succesful.
- */
-static int vip_close(struct file *file)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct video_device *dev = video_devdata(file);
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vq);
- vip->closing = 1;
- if (vip->active)
- videobuf_waiton(&vip->vb_vidq, vip->active, 0, 0);
spin_lock_irq(&vip->slock);
-
- REG_WRITE(vip, DVP_ITM, 0);
- REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
- REG_WRITE(vip, DVP_CTL, 0);
- REG_READ(vip, DVP_ITS);
-
- vip->started = 0;
- vip->active = NULL;
-
+ /* Enable interrupt VSYNC Top and Bottom*/
+ reg_write(vip, DVP_ITM, DVP_IT_VSB | DVP_IT_VST);
spin_unlock_irq(&vip->slock);
- videobuf_stop(&vip->vb_vidq);
- videobuf_mmap_free(&vip->vb_vidq);
+ if (count)
+ start_dma(vip, vip->active);
- dma_free_coherent(&vip->pdev->dev, 64, vip->mem_spare, vip->dma_spare);
- file->private_data = NULL;
- mutex_lock(&vip->mutex);
- vip->users--;
- mutex_unlock(&vip->mutex);
return 0;
}
-/**
- * vip_read - read from video input
- * @file: descriptor of device
- * @data: user buffer
- * @count: number of bytes to be read
- * @ppos: position within stream
- *
- * read video data from video device.
- * handling is done in generic videobuf layer
- * return value: provided by videobuf layer
- */
-static ssize_t vip_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
{
- struct video_device *dev = file->private_data;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_read_stream(&vip->vb_vidq, data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vq);
+ struct vip_buffer *vip_buf, *node;
+
+ /* Disable acquisition */
+ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA);
+ /* Disable all interrupts */
+ reg_write(vip, DVP_ITM, 0);
+
+ /* Release all active buffers */
+ spin_lock(&vip->lock);
+ list_for_each_entry_safe(vip_buf, node, &vip->buffer_list, list) {
+ vb2_buffer_done(&vip_buf->vb, VB2_BUF_STATE_ERROR);
+ list_del(&vip_buf->list);
+ }
+ spin_unlock(&vip->lock);
+ return 0;
}
-/**
- * vip_mmap - map user buffer
- * @file: descriptor of device
- * @vma: user buffer
- *
- * map user space buffer into kernel mode, including DMA address.
- * handling is done in generic videobuf layer.
- * return value: provided by videobuf layer
- */
-static int vip_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *dev = file->private_data;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+static struct vb2_ops vip_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_init = buffer_init,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+};
- return videobuf_mmap_mapper(&vip->vb_vidq, vma);
-}
-/**
- * vip_poll - poll for event
- * @file: descriptor of device
- * @wait: contains events to be waited for
- *
- * wait for event related to video device.
- * handling is done in generic videobuf layer.
- * return value: provided by videobuf layer
- */
-static unsigned int vip_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct video_device *dev = file->private_data;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+/* File Operations */
+static const struct v4l2_file_operations vip_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll
+};
- return videobuf_poll_stream(file, &vip->vb_vidq, wait);
-}
/**
* vidioc_querycap - return capabilities of device
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
+ * @file: descriptor of device
* @cap: contains return values
*
* the capabilities of the device are returned
@@ -527,25 +413,22 @@ static unsigned int vip_poll(struct file *file, struct poll_table_struct *wait)
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
- memset(cap, 0, sizeof(struct v4l2_capability));
- strcpy(cap->driver, DRV_NAME);
- strcpy(cap->card, DRV_NAME);
- cap->version = 0;
+ strcpy(cap->driver, KBUILD_MODNAME);
+ strcpy(cap->card, KBUILD_MODNAME);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(vip->pdev));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
/**
* vidioc_s_std - set video standard
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
+ * @file: descriptor of device
* @std: contains standard to be set
*
* the video standard is set
@@ -558,8 +441,7 @@ static int vidioc_querycap(struct file *file, void *priv,
*/
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
v4l2_std_id oldstd = vip->std, newstd;
int status;
@@ -592,8 +474,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
/**
* vidioc_g_std - get video standard
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
+ * @file: descriptor of device
* @std: contains return values
*
* the current video standard is returned
@@ -602,8 +483,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
*/
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
*std = vip->std;
return 0;
@@ -611,8 +491,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
/**
* vidioc_querystd - get possible video standards
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
+ * @file: descriptor of device
* @std: contains return values
*
* all possible video standards are returned
@@ -621,79 +500,11 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
*/
static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
return v4l2_subdev_call(vip->decoder, video, querystd, std);
-
}
-/**
- * vidioc_queryctl - get possible control settings
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @ctrl: contains return values
- *
- * return possible values for a control
- * return value: delivered by video DAC routine.
- */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *ctrl)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return v4l2_subdev_call(vip->decoder, core, queryctrl, ctrl);
-}
-
-/**
- * vidioc_g_ctl - get control value
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @ctrl: contains return values
- *
- * return setting for a control value
- * return value: delivered by video DAC routine.
- */
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return v4l2_subdev_call(vip->decoder, core, g_ctrl, ctrl);
-}
-
-/**
- * vidioc_s_ctl - set control value
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @ctrl: contains value to be set
- *
- * set value for a specific control
- * return value: delivered by video DAC routine.
- */
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return v4l2_subdev_call(vip->decoder, core, s_ctrl, ctrl);
-}
-
-/**
- * vidioc_enum_input - return name of input line
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @inp: contains return values
- *
- * the user friendly name of the input line is returned
- *
- * return value: 0, no error.
- *
- * -EINVAL, input line number out of range
- */
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
@@ -709,8 +520,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
/**
* vidioc_s_input - set input line
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
+ * @file: descriptor of device
* @i: new input line number
*
* the current active input line is set
@@ -721,8 +531,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
*/
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
int ret;
if (i > 1)
@@ -737,8 +546,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
/**
* vidioc_g_input - return input line
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
+ * @file: descriptor of device
* @i: returned input line number
*
* the current active input line is returned
@@ -747,8 +555,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
*/
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
*i = vip->input;
return 0;
@@ -756,8 +563,6 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
/**
* vidioc_enum_fmt_vid_cap - return video capture format
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
* @f: returned format information
*
* returns name and format of video capture
@@ -780,8 +585,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
/**
* vidioc_try_fmt_vid_cap - set video capture format
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
+ * @file: descriptor of device
* @f: new format
*
* new video format is set which includes width and
@@ -797,12 +601,13 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
int interlace_lim;
- if (V4L2_PIX_FMT_UYVY != f->fmt.pix.pixelformat)
+ if (V4L2_PIX_FMT_UYVY != f->fmt.pix.pixelformat) {
+ v4l2_warn(&vip->v4l2_dev, "Invalid format, only UYVY supported\n");
return -EINVAL;
+ }
if (V4L2_STD_525_60 & vip->std)
interlace_lim = 240;
@@ -810,6 +615,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
interlace_lim = 288;
switch (f->fmt.pix.field) {
+ default:
case V4L2_FIELD_ANY:
if (interlace_lim < f->fmt.pix.height)
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
@@ -823,10 +629,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
break;
case V4L2_FIELD_INTERLACED:
break;
- default:
- return -EINVAL;
}
+ /* It is the only supported format */
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
f->fmt.pix.height &= ~1;
if (2 * interlace_lim < f->fmt.pix.height)
f->fmt.pix.height = 2 * interlace_lim;
@@ -842,8 +648,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
/**
* vidioc_s_fmt_vid_cap - set current video format parameters
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
+ * @file: descriptor of device
* @f: returned format information
*
* set new capture format
@@ -854,22 +659,63 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
+ unsigned int t_stop, b_stop, pitch;
int ret;
ret = vidioc_try_fmt_vid_cap(file, priv, f);
if (ret)
return ret;
- memcpy(&vip->format, &f->fmt.pix, sizeof(struct v4l2_pix_format));
+ if (vb2_is_busy(&vip->vb_vidq)) {
+ /* Can't change format during acquisition */
+ v4l2_err(&vip->v4l2_dev, "device busy\n");
+ return -EBUSY;
+ }
+ vip->format = f->fmt.pix;
+ switch (vip->format.field) {
+ case V4L2_FIELD_INTERLACED:
+ t_stop = ((vip->format.height / 2 - 1) << 16) |
+ (2 * vip->format.width - 1);
+ b_stop = t_stop;
+ pitch = 4 * vip->format.width;
+ break;
+ case V4L2_FIELD_TOP:
+ t_stop = ((vip->format.height - 1) << 16) |
+ (2 * vip->format.width - 1);
+ b_stop = (0 << 16) | (2 * vip->format.width - 1);
+ pitch = 2 * vip->format.width;
+ break;
+ case V4L2_FIELD_BOTTOM:
+ t_stop = (0 << 16) | (2 * vip->format.width - 1);
+ b_stop = (vip->format.height << 16) |
+ (2 * vip->format.width - 1);
+ pitch = 2 * vip->format.width;
+ break;
+ default:
+ v4l2_err(&vip->v4l2_dev, "unknown field format\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irq(&vip->slock);
+ /* Y-X Top Field Offset */
+ reg_write(vip, DVP_TFO, 0);
+ /* Y-X Bottom Field Offset */
+ reg_write(vip, DVP_BFO, 0);
+ /* Y-X Top Field Stop*/
+ reg_write(vip, DVP_TFS, t_stop);
+ /* Y-X Bottom Field Stop */
+ reg_write(vip, DVP_BFS, b_stop);
+ /* Video Memory Pitch */
+ reg_write(vip, DVP_VMP, pitch);
+ spin_unlock_irq(&vip->slock);
+
return 0;
}
/**
* vidioc_g_fmt_vid_cap - get current video format parameters
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
+ * @file: descriptor of device
* @f: contains format information
*
* returns current video format parameters
@@ -879,150 +725,47 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- memcpy(&f->fmt.pix, &vip->format, sizeof(struct v4l2_pix_format));
- return 0;
-}
-
-/**
- * vidioc_reqfs - request buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_reqbufs(&vip->vb_vidq, p);
-}
-
-/**
- * vidioc_querybuf - query buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * query buffer state.
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
- return videobuf_querybuf(&vip->vb_vidq, p);
-}
+ f->fmt.pix = vip->format;
-/**
- * vidioc_qbuf - queue a buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_qbuf(&vip->vb_vidq, p);
-}
-
-/**
- * vidioc_dqbuf - dequeue a buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_dqbuf(&vip->vb_vidq, p, file->f_flags & O_NONBLOCK);
-}
-
-/**
- * vidioc_streamon - turn on streaming
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @type: type of capture
- *
- * turn on streaming.
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_streamon(&vip->vb_vidq);
-}
-
-/**
- * vidioc_streamoff - turn off streaming
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @type: type of capture
- *
- * turn off streaming.
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_streamoff(&vip->vb_vidq);
+ return 0;
}
-static const struct v4l2_file_operations vip_fops = {
- .owner = THIS_MODULE,
- .open = vip_open,
- .release = vip_close,
- .ioctl = video_ioctl2,
- .read = vip_read,
- .mmap = vip_mmap,
- .poll = vip_poll
-};
-
static const struct v4l2_ioctl_ops vip_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_s_std = vidioc_s_std,
+ /* FMT handling */
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ /* Buffer handlers */
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ /* Stream on/off */
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ /* Standard handling */
.vidioc_g_std = vidioc_g_std,
+ .vidioc_s_std = vidioc_s_std,
.vidioc_querystd = vidioc_querystd,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
+ /* Input handling */
.vidioc_enum_input = vidioc_enum_input,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_input = vidioc_s_input,
.vidioc_g_input = vidioc_g_input,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_s_input = vidioc_s_input,
+ /* Log status ioctl */
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ /* Event handling */
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device video_dev_template = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.release = video_device_release,
.fops = &vip_fops,
.ioctl_ops = &vip_ioctl_ops,
@@ -1036,9 +779,7 @@ static struct video_device video_dev_template = {
*
* check for both frame interrupts set ( top and bottom ).
* check FIFO overflow, but limit number of log messages after open.
- * signal a complete buffer if done.
- * dequeue a new buffer if available.
- * disable VIP if no buffer available.
+ * signal a complete buffer if done
*
* return value: IRQ_NONE, interrupt was not generated by VIP
*
@@ -1046,88 +787,122 @@ static struct video_device video_dev_template = {
*/
static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip)
{
- u32 status, dma;
- unsigned long flags;
- struct videobuf_buffer *vb;
+ unsigned int status;
- status = REG_READ(vip, DVP_ITS);
+ status = reg_read(vip, DVP_ITS);
- if (!status) {
- pr_debug("VIP: irq ignored\n");
+ if (!status) /* No interrupt to handle */
return IRQ_NONE;
- }
-
- if (!vip->started)
- return IRQ_HANDLED;
- if (status & DVP_IT_VSB)
- vip->bcount++;
-
- if (status & DVP_IT_VST)
- vip->tcount++;
+ if (status & DVP_IT_FIFO)
+ if (vip->overflow++ > 5)
+ pr_info("VIP: fifo overflow\n");
- if ((DVP_IT_VSB | DVP_IT_VST) == (status & (DVP_IT_VST | DVP_IT_VSB))) {
+ if ((status & DVP_IT_VST) && (status & DVP_IT_VSB)) {
/* this is bad, we are too slow, hope the condition is gone
* on the next frame */
- pr_info("VIP: both irqs\n");
return IRQ_HANDLED;
}
- if (status & DVP_IT_FIFO) {
- if (5 > vip->overflow++)
- pr_info("VIP: fifo overflow\n");
+ if (status & DVP_IT_VST)
+ if ((++vip->tcount) < 2)
+ return IRQ_HANDLED;
+ if (status & DVP_IT_VSB) {
+ vip->bcount++;
+ return IRQ_HANDLED;
}
- if (2 > vip->tcount)
- return IRQ_HANDLED;
+ if (vip->active) { /* Acquisition is over on this buffer */
+ /* Disable acquisition */
+ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA);
+ /* Remove the active buffer from the list */
+ do_gettimeofday(&vip->active->vb.v4l2_buf.timestamp);
+ vip->active->vb.v4l2_buf.sequence = vip->sequence++;
+ vb2_buffer_done(&vip->active->vb, VB2_BUF_STATE_DONE);
+ }
- if (status & DVP_IT_VSB)
- return IRQ_HANDLED;
+ return IRQ_HANDLED;
+}
- spin_lock_irqsave(&vip->slock, flags);
+static void sta2x11_vip_init_register(struct sta2x11_vip *vip)
+{
+ /* Register initialization */
+ spin_lock_irq(&vip->slock);
+ /* Clean interrupt */
+ reg_read(vip, DVP_ITS);
+ /* Enable Half Line per vertical */
+ reg_write(vip, DVP_HLFLN, DVP_HLFLN_SD);
+ /* Reset VIP control */
+ reg_write(vip, DVP_CTL, DVP_CTL_RST);
+ /* Clear VIP control */
+ reg_write(vip, DVP_CTL, 0);
+ spin_unlock_irq(&vip->slock);
+}
+static void sta2x11_vip_clear_register(struct sta2x11_vip *vip)
+{
+ spin_lock_irq(&vip->slock);
+ /* Disable interrupt */
+ reg_write(vip, DVP_ITM, 0);
+ /* Reset VIP Control */
+ reg_write(vip, DVP_CTL, DVP_CTL_RST);
+ /* Clear VIP Control */
+ reg_write(vip, DVP_CTL, 0);
+ /* Clean VIP Interrupt */
+ reg_read(vip, DVP_ITS);
+ spin_unlock_irq(&vip->slock);
+}
+static int sta2x11_vip_init_buffer(struct sta2x11_vip *vip)
+{
+ int err;
- REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) & ~DVP_CTL_ENA);
- if (vip->active) {
- do_gettimeofday(&vip->active->ts);
- vip->active->field_count++;
- vip->active->state = VIDEOBUF_DONE;
- wake_up(&vip->active->done);
- vip->active = NULL;
+ err = dma_set_coherent_mask(&vip->pdev->dev, DMA_BIT_MASK(29));
+ if (err) {
+ v4l2_err(&vip->v4l2_dev, "Cannot configure coherent mask");
+ return err;
}
- if (!vip->closing) {
- if (list_empty(&vip->capture))
- goto done;
-
- vb = list_first_entry(&vip->capture, struct videobuf_buffer,
- queue);
- if (NULL == vb) {
- pr_info("VIP: no buffer\n");
- goto done;
- }
- vb->state = VIDEOBUF_ACTIVE;
- list_del(&vb->queue);
- vip->active = vb;
- dma = videobuf_to_dma_contig(vb);
- switch (vip->format.field) {
- case V4L2_FIELD_INTERLACED:
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
- break;
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma);
- break;
- default:
- pr_warning("VIP: unknown field format\n");
- goto done;
- break;
- }
- REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) | DVP_CTL_ENA);
+ memset(&vip->vb_vidq, 0, sizeof(struct vb2_queue));
+ vip->vb_vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vip->vb_vidq.io_modes = VB2_MMAP | VB2_READ;
+ vip->vb_vidq.drv_priv = vip;
+ vip->vb_vidq.buf_struct_size = sizeof(struct vip_buffer);
+ vip->vb_vidq.ops = &vip_video_qops;
+ vip->vb_vidq.mem_ops = &vb2_dma_contig_memops;
+ err = vb2_queue_init(&vip->vb_vidq);
+ if (err)
+ return err;
+ INIT_LIST_HEAD(&vip->buffer_list);
+ spin_lock_init(&vip->lock);
+
+
+ vip->alloc_ctx = vb2_dma_contig_init_ctx(&vip->pdev->dev);
+ if (IS_ERR(vip->alloc_ctx)) {
+ v4l2_err(&vip->v4l2_dev, "Can't allocate buffer context");
+ return PTR_ERR(vip->alloc_ctx);
}
-done:
- spin_unlock_irqrestore(&vip->slock, flags);
- return IRQ_HANDLED;
+
+ return 0;
+}
+static void sta2x11_vip_release_buffer(struct sta2x11_vip *vip)
+{
+ vb2_dma_contig_cleanup_ctx(vip->alloc_ctx);
+}
+static int sta2x11_vip_init_controls(struct sta2x11_vip *vip)
+{
+ /*
+ * Inititialize an empty control so VIP can inerithing controls
+ * from ADV7180
+ */
+ v4l2_ctrl_handler_init(&vip->ctrl_hdl, 0);
+
+ vip->v4l2_dev.ctrl_handler = &vip->ctrl_hdl;
+ if (vip->ctrl_hdl.error) {
+ int err = vip->ctrl_hdl.error;
+
+ v4l2_ctrl_handler_free(&vip->ctrl_hdl);
+ return err;
+ }
+
+ return 0;
}
/**
@@ -1212,10 +987,17 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
struct sta2x11_vip *vip;
struct vip_config *config;
+ /* Check if hardware support 26-bit DMA */
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(26))) {
+ dev_err(&pdev->dev, "26-bit DMA addressing not available\n");
+ return -EINVAL;
+ }
+ /* Enable PCI */
ret = pci_enable_device(pdev);
if (ret)
return ret;
+ /* Get VIP platform data */
config = dev_get_platdata(&pdev->dev);
if (!config) {
dev_info(&pdev->dev, "VIP slot disabled\n");
@@ -1223,6 +1005,7 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
goto disable;
}
+ /* Power configuration */
ret = vip_gpio_reserve(&pdev->dev, config->pwr_pin, 0,
config->pwr_name);
if (ret)
@@ -1237,7 +1020,6 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
goto disable;
}
}
-
if (config->pwr_pin != -1) {
/* Datasheet says 5ms between PWR and RST */
usleep_range(5000, 25000);
@@ -1251,17 +1033,20 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
}
usleep_range(5000, 25000);
+ /* Allocate a new VIP instance */
vip = kzalloc(sizeof(struct sta2x11_vip), GFP_KERNEL);
if (!vip) {
ret = -ENOMEM;
goto release_gpios;
}
-
vip->pdev = pdev;
vip->std = V4L2_STD_PAL;
vip->format = formats_50[0];
vip->config = config;
+ ret = sta2x11_vip_init_controls(vip);
+ if (ret)
+ goto free_mem;
if (v4l2_device_register(&pdev->dev, &vip->v4l2_dev))
goto free_mem;
@@ -1271,46 +1056,52 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
pci_set_master(pdev);
- ret = pci_request_regions(pdev, DRV_NAME);
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
if (ret)
goto unreg;
vip->iomem = pci_iomap(pdev, 0, 0x100);
if (!vip->iomem) {
- ret = -ENOMEM; /* FIXME */
+ ret = -ENOMEM;
goto release;
}
pci_enable_msi(pdev);
- INIT_LIST_HEAD(&vip->capture);
+ /* Initialize buffer */
+ ret = sta2x11_vip_init_buffer(vip);
+ if (ret)
+ goto unmap;
+
spin_lock_init(&vip->slock);
- mutex_init(&vip->mutex);
- vip->started = 0;
- vip->disabled = 0;
ret = request_irq(pdev->irq,
(irq_handler_t) vip_irq,
- IRQF_SHARED, DRV_NAME, vip);
+ IRQF_SHARED, KBUILD_MODNAME, vip);
if (ret) {
dev_err(&pdev->dev, "request_irq failed\n");
ret = -ENODEV;
- goto unmap;
+ goto release_buf;
}
+ /* Alloc, initialize and register video device */
vip->video_dev = video_device_alloc();
if (!vip->video_dev) {
ret = -ENOMEM;
goto release_irq;
}
- *(vip->video_dev) = video_dev_template;
+ vip->video_dev = &video_dev_template;
+ vip->video_dev->v4l2_dev = &vip->v4l2_dev;
+ vip->video_dev->queue = &vip->vb_vidq;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vip->video_dev->flags);
video_set_drvdata(vip->video_dev, vip);
ret = video_register_device(vip->video_dev, VFL_TYPE_GRABBER, -1);
if (ret)
goto vrelease;
+ /* Get ADV7180 subdevice */
vip->adapter = i2c_get_adapter(vip->config->i2c_id);
if (!vip->adapter) {
ret = -ENODEV;
@@ -1328,10 +1119,11 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
}
i2c_put_adapter(vip->adapter);
-
v4l2_subdev_call(vip->decoder, core, init, 0);
- pr_info("STA2X11 Video Input Port (VIP) loaded\n");
+ sta2x11_vip_init_register(vip);
+
+ dev_info(&pdev->dev, "STA2X11 Video Input Port (VIP) loaded\n");
return 0;
vunreg:
@@ -1343,10 +1135,12 @@ vrelease:
video_device_release(vip->video_dev);
release_irq:
free_irq(pdev->irq, vip);
+release_buf:
+ sta2x11_vip_release_buffer(vip);
pci_disable_msi(pdev);
unmap:
+ vb2_queue_release(&vip->vb_vidq);
pci_iounmap(pdev, vip->iomem);
- mutex_destroy(&vip->mutex);
release:
pci_release_regions(pdev);
unreg:
@@ -1382,16 +1176,18 @@ static void sta2x11_vip_remove_one(struct pci_dev *pdev)
struct sta2x11_vip *vip =
container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+ sta2x11_vip_clear_register(vip);
+
video_set_drvdata(vip->video_dev, NULL);
video_unregister_device(vip->video_dev);
/*do not call video_device_release() here, is already done */
free_irq(pdev->irq, vip);
pci_disable_msi(pdev);
+ vb2_queue_release(&vip->vb_vidq);
pci_iounmap(pdev, vip->iomem);
pci_release_regions(pdev);
v4l2_device_unregister(&vip->v4l2_dev);
- mutex_destroy(&vip->mutex);
vip_gpio_release(&pdev->dev, vip->config->pwr_pin,
vip->config->pwr_name);
@@ -1416,9 +1212,6 @@ static void sta2x11_vip_remove_one(struct pci_dev *pdev)
*
* return value: 0 always indicate success,
* even if device could not be disabled. (workaround for hardware problem)
- *
- * reurn value : 0, always succesful, even if hardware does not not support
- * power down mode.
*/
static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
{
@@ -1429,15 +1222,15 @@ static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
int i;
spin_lock_irqsave(&vip->slock, flags);
- vip->register_save_area[0] = REG_READ(vip, DVP_CTL);
- REG_WRITE(vip, DVP_CTL, vip->register_save_area[0] & DVP_CTL_DIS);
- vip->register_save_area[SAVE_COUNT] = REG_READ(vip, DVP_ITM);
- REG_WRITE(vip, DVP_ITM, 0);
+ vip->register_save_area[0] = reg_read(vip, DVP_CTL);
+ reg_write(vip, DVP_CTL, vip->register_save_area[0] & DVP_CTL_DIS);
+ vip->register_save_area[SAVE_COUNT] = reg_read(vip, DVP_ITM);
+ reg_write(vip, DVP_ITM, 0);
for (i = 1; i < SAVE_COUNT; i++)
- vip->register_save_area[i] = REG_READ(vip, 4 * i);
+ vip->register_save_area[i] = reg_read(vip, 4 * i);
for (i = 0; i < AUX_COUNT; i++)
vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i] =
- REG_READ(vip, registers_to_save[i]);
+ reg_read(vip, registers_to_save[i]);
spin_unlock_irqrestore(&vip->slock, flags);
/* save pci state */
pci_save_state(pdev);
@@ -1477,7 +1270,7 @@ static int sta2x11_vip_resume(struct pci_dev *pdev)
if (vip->disabled) {
ret = pci_enable_device(pdev);
if (ret) {
- pr_warning("VIP: Can't enable device.\n");
+ pr_warn("VIP: Can't enable device.\n");
return ret;
}
vip->disabled = 0;
@@ -1488,7 +1281,7 @@ static int sta2x11_vip_resume(struct pci_dev *pdev)
* do not call pci_disable_device on sta2x11 because it
* break all other Bus masters on this EP
*/
- pr_warning("VIP: Can't enable device.\n");
+ pr_warn("VIP: Can't enable device.\n");
vip->disabled = 1;
return ret;
}
@@ -1497,12 +1290,12 @@ static int sta2x11_vip_resume(struct pci_dev *pdev)
spin_lock_irqsave(&vip->slock, flags);
for (i = 1; i < SAVE_COUNT; i++)
- REG_WRITE(vip, 4 * i, vip->register_save_area[i]);
+ reg_write(vip, 4 * i, vip->register_save_area[i]);
for (i = 0; i < AUX_COUNT; i++)
- REG_WRITE(vip, registers_to_save[i],
+ reg_write(vip, registers_to_save[i],
vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i]);
- REG_WRITE(vip, DVP_CTL, vip->register_save_area[0]);
- REG_WRITE(vip, DVP_ITM, vip->register_save_area[SAVE_COUNT]);
+ reg_write(vip, DVP_CTL, vip->register_save_area[0]);
+ reg_write(vip, DVP_ITM, vip->register_save_area[SAVE_COUNT]);
spin_unlock_irqrestore(&vip->slock, flags);
return 0;
}
@@ -1515,7 +1308,7 @@ static DEFINE_PCI_DEVICE_TABLE(sta2x11_vip_pci_tbl) = {
};
static struct pci_driver sta2x11_vip_driver = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.probe = sta2x11_vip_init_one,
.remove = sta2x11_vip_remove_one,
.id_table = sta2x11_vip_pci_tbl,
diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig
index 314e417addae..0dcb8cd77676 100644
--- a/drivers/media/pci/ttpci/Kconfig
+++ b/drivers/media/pci/ttpci/Kconfig
@@ -1,8 +1,3 @@
-config TTPCI_EEPROM
- tristate
- depends on I2C
- default n
-
config DVB_AV7110
tristate "AV7110 cards"
depends on DVB_CORE && PCI && I2C
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index 4656d4a10af0..3dc7aa9b6f40 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -235,7 +235,7 @@ static void recover_arm(struct av7110 *av7110)
restart_feeds(av7110);
-#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+#if IS_ENABLED(CONFIG_INPUT_EVDEV)
av7110_check_ir_config(av7110, true);
#endif
}
@@ -268,7 +268,7 @@ static int arm_thread(void *data)
if (!av7110->arm_ready)
continue;
-#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+#if IS_ENABLED(CONFIG_INPUT_EVDEV)
av7110_check_ir_config(av7110, false);
#endif
@@ -1730,7 +1730,7 @@ static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe)
static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
{
-#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
+#if IS_ENABLED(CONFIG_DVB_SP8870)
struct av7110* av7110 = fe->dvb->priv;
return request_firmware(fw, name, &av7110->dev->pci->dev);
@@ -2723,7 +2723,9 @@ static int av7110_attach(struct saa7146_dev* dev,
if (ret < 0)
goto err_av7110_exit_v4l_12;
-#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+ mutex_init(&av7110->ioctl_mutex);
+
+#if IS_ENABLED(CONFIG_INPUT_EVDEV)
av7110_ir_init(av7110);
#endif
printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
@@ -2766,7 +2768,7 @@ static int av7110_detach(struct saa7146_dev* saa)
struct av7110 *av7110 = saa->ext_priv;
dprintk(4, "%p\n", av7110);
-#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+#if IS_ENABLED(CONFIG_INPUT_EVDEV)
av7110_ir_exit(av7110);
#endif
if (budgetpatch || av7110->full_ts) {
diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h
index a378662b1dcf..ef3d9606b269 100644
--- a/drivers/media/pci/ttpci/av7110.h
+++ b/drivers/media/pci/ttpci/av7110.h
@@ -271,6 +271,8 @@ struct av7110 {
struct dvb_frontend* fe;
fe_status_t fe_status;
+ struct mutex ioctl_mutex;
+
/* crash recovery */
void (*recover)(struct av7110* av7110);
fe_sec_voltage_t saved_voltage;
diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c
index 952b33dbac4f..301029ca4535 100644
--- a/drivers/media/pci/ttpci/av7110_av.c
+++ b/drivers/media/pci/ttpci/av7110_av.c
@@ -1109,6 +1109,9 @@ static int dvb_video_ioctl(struct file *file,
}
}
+ if (mutex_lock_interruptible(&av7110->ioctl_mutex))
+ return -ERESTARTSYS;
+
switch (cmd) {
case VIDEO_STOP:
av7110->videostate.play_state = VIDEO_STOPPED;
@@ -1297,6 +1300,7 @@ static int dvb_video_ioctl(struct file *file,
break;
}
+ mutex_unlock(&av7110->ioctl_mutex);
return ret;
}
@@ -1314,6 +1318,9 @@ static int dvb_audio_ioctl(struct file *file,
(cmd != AUDIO_GET_STATUS))
return -EPERM;
+ if (mutex_lock_interruptible(&av7110->ioctl_mutex))
+ return -ERESTARTSYS;
+
switch (cmd) {
case AUDIO_STOP:
if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
@@ -1442,6 +1449,7 @@ static int dvb_audio_ioctl(struct file *file,
ret = -ENOIOCTLCMD;
}
+ mutex_unlock(&av7110->ioctl_mutex);
return ret;
}
diff --git a/drivers/media/pci/ttpci/av7110_ca.c b/drivers/media/pci/ttpci/av7110_ca.c
index 9fc1dd0ba4c3..a6079b90252a 100644
--- a/drivers/media/pci/ttpci/av7110_ca.c
+++ b/drivers/media/pci/ttpci/av7110_ca.c
@@ -253,12 +253,17 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
unsigned long arg = (unsigned long) parg;
+ int ret = 0;
dprintk(8, "av7110:%p\n",av7110);
+ if (mutex_lock_interruptible(&av7110->ioctl_mutex))
+ return -ERESTARTSYS;
+
switch (cmd) {
case CA_RESET:
- return ci_ll_reset(&av7110->ci_wbuffer, file, arg, &av7110->ci_slot[0]);
+ ret = ci_ll_reset(&av7110->ci_wbuffer, file, arg,
+ &av7110->ci_slot[0]);
break;
case CA_GET_CAP:
{
@@ -277,8 +282,10 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
{
ca_slot_info_t *info=(ca_slot_info_t *)parg;
- if (info->num < 0 || info->num > 1)
+ if (info->num < 0 || info->num > 1) {
+ mutex_unlock(&av7110->ioctl_mutex);
return -EINVAL;
+ }
av7110->ci_slot[info->num].num = info->num;
av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
CA_CI_LINK : CA_CI;
@@ -306,10 +313,10 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
{
ca_descr_t *descr = (ca_descr_t*) parg;
- if (descr->index >= 16)
- return -EINVAL;
- if (descr->parity > 1)
+ if (descr->index >= 16 || descr->parity > 1) {
+ mutex_unlock(&av7110->ioctl_mutex);
return -EINVAL;
+ }
av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5,
(descr->index<<8)|descr->parity,
(descr->cw[0]<<8)|descr->cw[1],
@@ -320,9 +327,12 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
}
default:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
- return 0;
+
+ mutex_unlock(&av7110->ioctl_mutex);
+ return ret;
}
static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c
index a90a3b9b09bf..bb53d2488ad0 100644
--- a/drivers/media/pci/zoran/zoran_card.c
+++ b/drivers/media/pci/zoran/zoran_card.c
@@ -708,8 +708,7 @@ static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
static int
zoran_register_i2c (struct zoran *zr)
{
- memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
- sizeof(struct i2c_algo_bit_data));
+ zr->i2c_algo = zoran_i2c_bit_data_template;
zr->i2c_algo.data = zr;
strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
sizeof(zr->i2c_adapter.name));
diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c
index a4cd504b8eee..519164c572c8 100644
--- a/drivers/media/pci/zoran/zoran_device.c
+++ b/drivers/media/pci/zoran/zoran_device.c
@@ -1169,7 +1169,7 @@ zoran_reap_stat_com (struct zoran *zr)
}
frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
buffer = &zr->jpg_buffers.buffer[frame];
- do_gettimeofday(&buffer->bs.timestamp);
+ v4l2_get_timestamp(&buffer->bs.timestamp);
if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
buffer->bs.length = (stat_com & 0x7fffff) >> 1;
@@ -1407,7 +1407,7 @@ zoran_irq (int irq,
zr->v4l_buffers.buffer[zr->v4l_grab_frame].state = BUZ_STATE_DONE;
zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.seq = zr->v4l_grab_seq;
- do_gettimeofday(&zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.timestamp);
+ v4l2_get_timestamp(&zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.timestamp);
zr->v4l_grab_frame = NO_GRAB_ACTIVE;
zr->v4l_pend_tail++;
}
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
index e60ae41e2319..2e8f518f298f 100644
--- a/drivers/media/pci/zoran/zoran_driver.c
+++ b/drivers/media/pci/zoran/zoran_driver.c
@@ -1334,7 +1334,7 @@ static int zoran_v4l2_buffer_status(struct zoran_fh *fh,
struct zoran *zr = fh->zr;
unsigned long flags;
- buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
switch (fh->map_mode) {
case ZORAN_MAP_MODE_RAW:
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 3dcfea612c42..05d7b6333461 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -92,14 +92,14 @@ config VIDEO_M32R_AR_M64278
config VIDEO_OMAP2
tristate "OMAP2 Camera Capture Interface driver"
- depends on VIDEO_DEV && ARCH_OMAP2
+ depends on VIDEO_DEV && ARCH_OMAP2 && VIDEO_V4L2_INT_DEVICE
select VIDEOBUF_DMA_SG
---help---
This is a v4l2 driver for the TI OMAP2 camera capture interface
config VIDEO_OMAP3
- tristate "OMAP 3 Camera support (EXPERIMENTAL)"
- depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL
+ tristate "OMAP 3 Camera support"
+ depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3
---help---
Driver for an OMAP 3 camera controller.
@@ -169,8 +169,8 @@ config VIDEO_SAMSUNG_S5P_G2D
2d graphics accelerator.
config VIDEO_SAMSUNG_S5P_JPEG
- tristate "Samsung S5P/Exynos4 JPEG codec driver (EXPERIMENTAL)"
- depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P && EXPERIMENTAL
+ tristate "Samsung S5P/Exynos4 JPEG codec driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
---help---
@@ -202,6 +202,15 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
help
This is a v4l2 driver for Samsung EXYNOS5 SoC G-Scaler.
+config VIDEO_SH_VEU
+ tristate "SuperH VEU mem2mem video processing driver"
+ depends on VIDEO_DEV && VIDEO_V4L2
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ help
+ Support for the Video Engine Unit (VEU) on SuperH and
+ SH-Mobile SoCs.
+
endif # V4L_MEM2MEM_DRIVERS
menuconfig V4L_TEST_DRIVERS
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 4817d2802171..42089ba3600f 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -25,6 +25,8 @@ obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
obj-$(CONFIG_VIDEO_CODA) += coda.o
+obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o
+
obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o
obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif/
diff --git a/drivers/media/platform/blackfin/Kconfig b/drivers/media/platform/blackfin/Kconfig
index ecd5323768b7..cc239972fa2c 100644
--- a/drivers/media/platform/blackfin/Kconfig
+++ b/drivers/media/platform/blackfin/Kconfig
@@ -7,4 +7,9 @@ config VIDEO_BLACKFIN_CAPTURE
Choose PPI or EPPI as its interface.
To compile this driver as a module, choose M here: the
- module will be called bfin_video_capture.
+ module will be called bfin_capture.
+
+config VIDEO_BLACKFIN_PPI
+ tristate
+ depends on VIDEO_BLACKFIN_CAPTURE
+ default VIDEO_BLACKFIN_CAPTURE
diff --git a/drivers/media/platform/blackfin/Makefile b/drivers/media/platform/blackfin/Makefile
index aa3a0a216387..30421bc23080 100644
--- a/drivers/media/platform/blackfin/Makefile
+++ b/drivers/media/platform/blackfin/Makefile
@@ -1,2 +1,2 @@
-bfin_video_capture-objs := bfin_capture.o ppi.o
-obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_video_capture.o
+obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_capture.o
+obj-$(CONFIG_VIDEO_BLACKFIN_PPI) += ppi.o
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
index 1aad2a65d2f3..5f209d5810dc 100644
--- a/drivers/media/platform/blackfin/bfin_capture.c
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -52,6 +52,7 @@ struct bcap_format {
u32 pixelformat;
enum v4l2_mbus_pixelcode mbus_code;
int bpp; /* bits per pixel */
+ int dlen; /* data length for ppi in bits */
};
struct bcap_buffer {
@@ -76,18 +77,20 @@ struct bcap_device {
unsigned int cur_input;
/* current selected standard */
v4l2_std_id std;
+ /* current selected dv_timings */
+ struct v4l2_dv_timings dv_timings;
/* used to store pixel format */
struct v4l2_pix_format fmt;
/* bits per pixel*/
int bpp;
+ /* data length for ppi in bits */
+ int dlen;
/* used to store sensor supported format */
struct bcap_format *sensor_formats;
/* number of sensor formats array */
int num_sensor_formats;
/* pointing to current video buffer */
struct bcap_buffer *cur_frm;
- /* pointing to next video buffer */
- struct bcap_buffer *next_frm;
/* buffer queue used in videobuf2 */
struct vb2_queue buffer_queue;
/* allocator-specific contexts for each plane */
@@ -116,24 +119,35 @@ static const struct bcap_format bcap_formats[] = {
.pixelformat = V4L2_PIX_FMT_UYVY,
.mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
.bpp = 16,
+ .dlen = 8,
},
{
.desc = "YCbCr 4:2:2 Interleaved YUYV",
.pixelformat = V4L2_PIX_FMT_YUYV,
.mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
.bpp = 16,
+ .dlen = 8,
+ },
+ {
+ .desc = "YCbCr 4:2:2 Interleaved UYVY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_1X16,
+ .bpp = 16,
+ .dlen = 16,
},
{
.desc = "RGB 565",
.pixelformat = V4L2_PIX_FMT_RGB565,
.mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
.bpp = 16,
+ .dlen = 8,
},
{
.desc = "RGB 444",
.pixelformat = V4L2_PIX_FMT_RGB444,
.mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
.bpp = 16,
+ .dlen = 8,
},
};
@@ -366,9 +380,39 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
params.width = bcap_dev->fmt.width;
params.height = bcap_dev->fmt.height;
params.bpp = bcap_dev->bpp;
+ params.dlen = bcap_dev->dlen;
params.ppi_control = bcap_dev->cfg->ppi_control;
params.int_mask = bcap_dev->cfg->int_mask;
- params.blank_clocks = bcap_dev->cfg->blank_clocks;
+ if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities
+ & V4L2_IN_CAP_CUSTOM_TIMINGS) {
+ struct v4l2_bt_timings *bt = &bcap_dev->dv_timings.bt;
+
+ params.hdelay = bt->hsync + bt->hbackporch;
+ params.vdelay = bt->vsync + bt->vbackporch;
+ params.line = bt->hfrontporch + bt->hsync
+ + bt->hbackporch + bt->width;
+ params.frame = bt->vfrontporch + bt->vsync
+ + bt->vbackporch + bt->height;
+ if (bt->interlaced)
+ params.frame += bt->il_vfrontporch + bt->il_vsync
+ + bt->il_vbackporch;
+ } else if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities
+ & V4L2_IN_CAP_STD) {
+ params.hdelay = 0;
+ params.vdelay = 0;
+ if (bcap_dev->std & V4L2_STD_525_60) {
+ params.line = 858;
+ params.frame = 525;
+ } else {
+ params.line = 864;
+ params.frame = 625;
+ }
+ } else {
+ params.hdelay = 0;
+ params.vdelay = 0;
+ params.line = params.width + bcap_dev->cfg->blank_pixels;
+ params.frame = params.height;
+ }
ret = ppi->ops->set_params(ppi, &params);
if (ret < 0) {
v4l2_err(&bcap_dev->v4l2_dev,
@@ -409,10 +453,10 @@ static int bcap_stop_streaming(struct vb2_queue *vq)
/* release all active buffers */
while (!list_empty(&bcap_dev->dma_queue)) {
- bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+ bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next,
struct bcap_buffer, list);
- list_del(&bcap_dev->next_frm->list);
- vb2_buffer_done(&bcap_dev->next_frm->vb, VB2_BUF_STATE_ERROR);
+ list_del(&bcap_dev->cur_frm->list);
+ vb2_buffer_done(&bcap_dev->cur_frm->vb, VB2_BUF_STATE_ERROR);
}
return 0;
}
@@ -484,17 +528,26 @@ static irqreturn_t bcap_isr(int irq, void *dev_id)
{
struct ppi_if *ppi = dev_id;
struct bcap_device *bcap_dev = ppi->priv;
- struct timeval timevalue;
struct vb2_buffer *vb = &bcap_dev->cur_frm->vb;
dma_addr_t addr;
spin_lock(&bcap_dev->lock);
- if (bcap_dev->cur_frm != bcap_dev->next_frm) {
- do_gettimeofday(&timevalue);
- vb->v4l2_buf.timestamp = timevalue;
- vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
- bcap_dev->cur_frm = bcap_dev->next_frm;
+ if (!list_empty(&bcap_dev->dma_queue)) {
+ v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
+ if (ppi->err) {
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ ppi->err = false;
+ } else {
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ }
+ bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next,
+ struct bcap_buffer, list);
+ list_del(&bcap_dev->cur_frm->list);
+ } else {
+ /* clear error flag, we will get a new frame */
+ if (ppi->err)
+ ppi->err = false;
}
ppi->ops->stop(ppi);
@@ -502,13 +555,8 @@ static irqreturn_t bcap_isr(int irq, void *dev_id)
if (bcap_dev->stop) {
complete(&bcap_dev->comp);
} else {
- if (!list_empty(&bcap_dev->dma_queue)) {
- bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
- struct bcap_buffer, list);
- list_del(&bcap_dev->next_frm->list);
- addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->next_frm->vb, 0);
- ppi->ops->update_addr(ppi, (unsigned long)addr);
- }
+ addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0);
+ ppi->ops->update_addr(ppi, (unsigned long)addr);
ppi->ops->start(ppi);
}
@@ -542,9 +590,8 @@ static int bcap_streamon(struct file *file, void *priv,
}
/* get the next frame from the dma queue */
- bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+ bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next,
struct bcap_buffer, list);
- bcap_dev->cur_frm = bcap_dev->next_frm;
/* remove buffer from the dma queue */
list_del(&bcap_dev->cur_frm->list);
addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0);
@@ -602,6 +649,37 @@ static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std)
return 0;
}
+static int bcap_g_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ int ret;
+
+ ret = v4l2_subdev_call(bcap_dev->sd, video,
+ g_dv_timings, timings);
+ if (ret < 0)
+ return ret;
+
+ bcap_dev->dv_timings = *timings;
+ return 0;
+}
+
+static int bcap_s_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct bcap_device *bcap_dev = video_drvdata(file);
+ int ret;
+ if (vb2_is_busy(&bcap_dev->buffer_queue))
+ return -EBUSY;
+
+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_dv_timings, timings);
+ if (ret < 0)
+ return ret;
+
+ bcap_dev->dv_timings = *timings;
+ return 0;
+}
+
static int bcap_enum_input(struct file *file, void *priv,
struct v4l2_input *input)
{
@@ -650,13 +728,15 @@ static int bcap_s_input(struct file *file, void *priv, unsigned int index)
return ret;
}
bcap_dev->cur_input = index;
+ /* if this route has specific config, update ppi control */
+ if (route->ppi_control)
+ config->ppi_control = route->ppi_control;
return 0;
}
static int bcap_try_format(struct bcap_device *bcap,
struct v4l2_pix_format *pixfmt,
- enum v4l2_mbus_pixelcode *mbus_code,
- int *bpp)
+ struct bcap_format *bcap_fmt)
{
struct bcap_format *sf = bcap->sensor_formats;
struct bcap_format *fmt = NULL;
@@ -671,16 +751,20 @@ static int bcap_try_format(struct bcap_device *bcap,
if (i == bcap->num_sensor_formats)
fmt = &sf[0];
- if (mbus_code)
- *mbus_code = fmt->mbus_code;
- if (bpp)
- *bpp = fmt->bpp;
v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code);
ret = v4l2_subdev_call(bcap->sd, video,
try_mbus_fmt, &mbus_fmt);
if (ret < 0)
return ret;
v4l2_fill_pix_format(pixfmt, &mbus_fmt);
+ if (bcap_fmt) {
+ for (i = 0; i < bcap->num_sensor_formats; i++) {
+ fmt = &sf[i];
+ if (mbus_fmt.code == fmt->mbus_code)
+ break;
+ }
+ *bcap_fmt = *fmt;
+ }
pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8;
pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
return 0;
@@ -709,7 +793,7 @@ static int bcap_try_fmt_vid_cap(struct file *file, void *priv,
struct bcap_device *bcap_dev = video_drvdata(file);
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
- return bcap_try_format(bcap_dev, pixfmt, NULL, NULL);
+ return bcap_try_format(bcap_dev, pixfmt, NULL);
}
static int bcap_g_fmt_vid_cap(struct file *file, void *priv,
@@ -726,24 +810,25 @@ static int bcap_s_fmt_vid_cap(struct file *file, void *priv,
{
struct bcap_device *bcap_dev = video_drvdata(file);
struct v4l2_mbus_framefmt mbus_fmt;
- enum v4l2_mbus_pixelcode mbus_code;
+ struct bcap_format bcap_fmt;
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
- int ret, bpp;
+ int ret;
if (vb2_is_busy(&bcap_dev->buffer_queue))
return -EBUSY;
/* see if format works */
- ret = bcap_try_format(bcap_dev, pixfmt, &mbus_code, &bpp);
+ ret = bcap_try_format(bcap_dev, pixfmt, &bcap_fmt);
if (ret < 0)
return ret;
- v4l2_fill_mbus_format(&mbus_fmt, pixfmt, mbus_code);
+ v4l2_fill_mbus_format(&mbus_fmt, pixfmt, bcap_fmt.mbus_code);
ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt);
if (ret < 0)
return ret;
bcap_dev->fmt = *pixfmt;
- bcap_dev->bpp = bpp;
+ bcap_dev->bpp = bcap_fmt.bpp;
+ bcap_dev->dlen = bcap_fmt.dlen;
return 0;
}
@@ -834,6 +919,8 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
.vidioc_querystd = bcap_querystd,
.vidioc_s_std = bcap_s_std,
.vidioc_g_std = bcap_g_std,
+ .vidioc_s_dv_timings = bcap_s_dv_timings,
+ .vidioc_g_dv_timings = bcap_g_dv_timings,
.vidioc_reqbufs = bcap_reqbufs,
.vidioc_querybuf = bcap_querybuf,
.vidioc_qbuf = bcap_qbuf,
@@ -869,6 +956,7 @@ static int bcap_probe(struct platform_device *pdev)
struct i2c_adapter *i2c_adap;
struct bfin_capture_config *config;
struct vb2_queue *q;
+ struct bcap_route *route;
int ret;
config = pdev->dev.platform_data;
@@ -978,6 +1066,12 @@ static int bcap_probe(struct platform_device *pdev)
NULL);
if (bcap_dev->sd) {
int i;
+ if (!config->num_inputs) {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "Unable to work without input\n");
+ goto err_unreg_vdev;
+ }
+
/* update tvnorms from the sub devices */
for (i = 0; i < config->num_inputs; i++)
vfd->tvnorms |= config->inputs[i].std;
@@ -989,8 +1083,24 @@ static int bcap_probe(struct platform_device *pdev)
v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n");
+ /*
+ * explicitly set input, otherwise some boards
+ * may not work at the state as we expected
+ */
+ route = &config->routes[0];
+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing,
+ route->input, route->output, 0);
+ if ((ret < 0) && (ret != -ENOIOCTLCMD)) {
+ v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n");
+ goto err_unreg_vdev;
+ }
+ bcap_dev->cur_input = 0;
+ /* if this route has specific config, update ppi control */
+ if (route->ppi_control)
+ config->ppi_control = route->ppi_control;
+
/* now we can probe the default state */
- if (vfd->tvnorms) {
+ if (config->inputs[0].capabilities & V4L2_IN_CAP_STD) {
v4l2_std_id std;
ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std);
if (ret) {
@@ -1000,6 +1110,17 @@ static int bcap_probe(struct platform_device *pdev)
}
bcap_dev->std = std;
}
+ if (config->inputs[0].capabilities & V4L2_IN_CAP_CUSTOM_TIMINGS) {
+ struct v4l2_dv_timings dv_timings;
+ ret = v4l2_subdev_call(bcap_dev->sd, video,
+ g_dv_timings, &dv_timings);
+ if (ret) {
+ v4l2_err(&bcap_dev->v4l2_dev,
+ "Unable to get dv timings\n");
+ goto err_unreg_vdev;
+ }
+ bcap_dev->dv_timings = dv_timings;
+ }
ret = bcap_init_sensor_formats(bcap_dev);
if (ret) {
v4l2_err(&bcap_dev->v4l2_dev,
diff --git a/drivers/media/platform/blackfin/ppi.c b/drivers/media/platform/blackfin/ppi.c
index d29592186b02..01b5b501347e 100644
--- a/drivers/media/platform/blackfin/ppi.c
+++ b/drivers/media/platform/blackfin/ppi.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/module.h>
#include <linux/slab.h>
#include <asm/bfin_ppi.h>
@@ -58,15 +59,33 @@ static irqreturn_t ppi_irq_err(int irq, void *dev_id)
* others are W1C
*/
status = bfin_read16(&reg->status);
+ if (status & 0x3000)
+ ppi->err = true;
bfin_write16(&reg->status, 0xff00);
break;
}
case PPI_TYPE_EPPI:
{
struct bfin_eppi_regs *reg = info->base;
+ unsigned short status;
+
+ status = bfin_read16(&reg->status);
+ if (status & 0x2)
+ ppi->err = true;
bfin_write16(&reg->status, 0xffff);
break;
}
+ case PPI_TYPE_EPPI3:
+ {
+ struct bfin_eppi3_regs *reg = info->base;
+ unsigned long stat;
+
+ stat = bfin_read32(&reg->stat);
+ if (stat & 0x2)
+ ppi->err = true;
+ bfin_write32(&reg->stat, 0xc0ff);
+ break;
+ }
default:
break;
}
@@ -128,6 +147,12 @@ static int ppi_start(struct ppi_if *ppi)
bfin_write32(&reg->control, ppi->ppi_control);
break;
}
+ case PPI_TYPE_EPPI3:
+ {
+ struct bfin_eppi3_regs *reg = info->base;
+ bfin_write32(&reg->ctl, ppi->ppi_control);
+ break;
+ }
default:
return -EINVAL;
}
@@ -155,6 +180,12 @@ static int ppi_stop(struct ppi_if *ppi)
bfin_write32(&reg->control, ppi->ppi_control);
break;
}
+ case PPI_TYPE_EPPI3:
+ {
+ struct bfin_eppi3_regs *reg = info->base;
+ bfin_write32(&reg->ctl, ppi->ppi_control);
+ break;
+ }
default:
return -EINVAL;
}
@@ -171,17 +202,23 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
{
const struct ppi_info *info = ppi->info;
int dma32 = 0;
- int dma_config, bytes_per_line, lines_per_frame;
+ int dma_config, bytes_per_line;
+ int hcount, hdelay, samples_per_line;
bytes_per_line = params->width * params->bpp / 8;
- lines_per_frame = params->height;
+ /* convert parameters unit from pixels to samples */
+ hcount = params->width * params->bpp / params->dlen;
+ hdelay = params->hdelay * params->bpp / params->dlen;
+ samples_per_line = params->line * params->bpp / params->dlen;
if (params->int_mask == 0xFFFFFFFF)
ppi->err_int = false;
else
ppi->err_int = true;
- dma_config = (DMA_FLOW_STOP | WNR | RESTART | DMA2D | DI_EN);
+ dma_config = (DMA_FLOW_STOP | RESTART | DMA2D | DI_EN_Y);
ppi->ppi_control = params->ppi_control & ~PORT_EN;
+ if (!(ppi->ppi_control & PORT_DIR))
+ dma_config |= WNR;
switch (info->type) {
case PPI_TYPE_PPI:
{
@@ -191,8 +228,8 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
dma32 = 1;
bfin_write16(&reg->control, ppi->ppi_control);
- bfin_write16(&reg->count, bytes_per_line - 1);
- bfin_write16(&reg->frame, lines_per_frame);
+ bfin_write16(&reg->count, samples_per_line - 1);
+ bfin_write16(&reg->frame, params->frame);
break;
}
case PPI_TYPE_EPPI:
@@ -204,12 +241,31 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
dma32 = 1;
bfin_write32(&reg->control, ppi->ppi_control);
- bfin_write16(&reg->line, bytes_per_line + params->blank_clocks);
- bfin_write16(&reg->frame, lines_per_frame);
- bfin_write16(&reg->hdelay, 0);
- bfin_write16(&reg->vdelay, 0);
- bfin_write16(&reg->hcount, bytes_per_line);
- bfin_write16(&reg->vcount, lines_per_frame);
+ bfin_write16(&reg->line, samples_per_line);
+ bfin_write16(&reg->frame, params->frame);
+ bfin_write16(&reg->hdelay, hdelay);
+ bfin_write16(&reg->vdelay, params->vdelay);
+ bfin_write16(&reg->hcount, hcount);
+ bfin_write16(&reg->vcount, params->height);
+ break;
+ }
+ case PPI_TYPE_EPPI3:
+ {
+ struct bfin_eppi3_regs *reg = info->base;
+
+ if ((params->ppi_control & PACK_EN)
+ || (params->ppi_control & 0x70000) > DLEN_16)
+ dma32 = 1;
+
+ bfin_write32(&reg->ctl, ppi->ppi_control);
+ bfin_write32(&reg->line, samples_per_line);
+ bfin_write32(&reg->frame, params->frame);
+ bfin_write32(&reg->hdly, hdelay);
+ bfin_write32(&reg->vdly, params->vdelay);
+ bfin_write32(&reg->hcnt, hcount);
+ bfin_write32(&reg->vcnt, params->height);
+ if (params->int_mask)
+ bfin_write32(&reg->imsk, params->int_mask & 0xFF);
break;
}
default:
@@ -217,17 +273,17 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
}
if (dma32) {
- dma_config |= WDSIZE_32;
+ dma_config |= WDSIZE_32 | PSIZE_32;
set_dma_x_count(info->dma_ch, bytes_per_line >> 2);
set_dma_x_modify(info->dma_ch, 4);
set_dma_y_modify(info->dma_ch, 4);
} else {
- dma_config |= WDSIZE_16;
+ dma_config |= WDSIZE_16 | PSIZE_16;
set_dma_x_count(info->dma_ch, bytes_per_line >> 1);
set_dma_x_modify(info->dma_ch, 2);
set_dma_y_modify(info->dma_ch, 2);
}
- set_dma_y_count(info->dma_ch, lines_per_frame);
+ set_dma_y_count(info->dma_ch, params->height);
set_dma_config(info->dma_ch, dma_config);
SSYNC();
@@ -263,9 +319,15 @@ struct ppi_if *ppi_create_instance(const struct ppi_info *info)
pr_info("ppi probe success\n");
return ppi;
}
+EXPORT_SYMBOL(ppi_create_instance);
void ppi_delete_instance(struct ppi_if *ppi)
{
peripheral_free_list(ppi->info->pin_req);
kfree(ppi);
}
+EXPORT_SYMBOL(ppi_delete_instance);
+
+MODULE_DESCRIPTION("Analog Devices PPI driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
index 4a980e029ca7..20827ba168fc 100644
--- a/drivers/media/platform/coda.c
+++ b/drivers/media/platform/coda.c
@@ -178,6 +178,10 @@ struct coda_ctx {
int idx;
};
+static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 };
+static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 };
+
static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg)
{
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
@@ -944,6 +948,24 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_d
return 0;
}
+static int coda_h264_padding(int size, char *p)
+{
+ int nal_size;
+ int diff;
+
+ diff = size - (size & ~0x7);
+ if (diff == 0)
+ return 0;
+
+ nal_size = coda_filler_size[diff];
+ memcpy(p, coda_filler_nal, nal_size);
+
+ /* Add rbsp stop bit and trailing at the end */
+ *(p + nal_size - 1) = 0x80;
+
+ return nal_size;
+}
+
static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct coda_ctx *ctx = vb2_get_drv_priv(q);
@@ -1171,7 +1193,15 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
ctx->vpu_header_size[1]);
- ctx->vpu_header_size[2] = 0;
+ /*
+ * Length of H.264 headers is variable and thus it might not be
+ * aligned for the coda to append the encoded frame. In that is
+ * the case a filler NAL must be added to header 2.
+ */
+ ctx->vpu_header_size[2] = coda_h264_padding(
+ (ctx->vpu_header_size[0] +
+ ctx->vpu_header_size[1]),
+ ctx->vpu_header[2]);
break;
case V4L2_PIX_FMT_MPEG4:
/*
diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig
index 3c56037c82fc..ccfde4eb626a 100644
--- a/drivers/media/platform/davinci/Kconfig
+++ b/drivers/media/platform/davinci/Kconfig
@@ -97,25 +97,15 @@ config VIDEO_ISIF
To compile this driver as a module, choose M here: the
module will be called vpfe.
-config VIDEO_DM644X_VPBE
- tristate "DM644X VPBE HW module"
- depends on ARCH_DAVINCI_DM644x
+config VIDEO_DAVINCI_VPBE_DISPLAY
+ tristate "DM644X/DM365/DM355 VPBE HW module"
+ depends on ARCH_DAVINCI_DM644x || ARCH_DAVINCI_DM355 || ARCH_DAVINCI_DM365
select VIDEO_VPSS_SYSTEM
select VIDEOBUF2_DMA_CONTIG
help
- Enables VPBE modules used for display on a DM644x
- SoC.
+ Enables Davinci VPBE module used for display devices.
+ This module is common for following DM644x/DM365/DM355
+ based display devices.
To compile this driver as a module, choose M here: the
module will be called vpbe.
-
-
-config VIDEO_VPBE_DISPLAY
- tristate "VPBE V4L2 Display driver"
- depends on ARCH_DAVINCI_DM644x
- select VIDEO_DM644X_VPBE
- help
- Enables VPBE V4L2 Display driver on a DM644x device
-
- To compile this driver as a module, choose M here: the
- module will be called vpbe_display.
diff --git a/drivers/media/platform/davinci/Makefile b/drivers/media/platform/davinci/Makefile
index 74ed92d09257..f40f5219ca50 100644
--- a/drivers/media/platform/davinci/Makefile
+++ b/drivers/media/platform/davinci/Makefile
@@ -16,5 +16,5 @@ obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o
obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o
obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
obj-$(CONFIG_VIDEO_ISIF) += isif.o
-obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o
-obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o
+obj-$(CONFIG_VIDEO_DAVINCI_VPBE_DISPLAY) += vpbe.o vpbe_osd.o \
+ vpbe_venc.o vpbe_display.o
diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c
index f263cabade7a..4277e4ad810c 100644
--- a/drivers/media/platform/davinci/dm355_ccdc.c
+++ b/drivers/media/platform/davinci/dm355_ccdc.c
@@ -557,7 +557,7 @@ static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
*/
static void ccdc_config_csc(struct ccdc_csc *csc)
{
- u32 val1, val2;
+ u32 val1 = 0, val2;
int i;
if (!csc->enable)
diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c
index 841b91a3d255..4ca0f9a2ad8a 100644
--- a/drivers/media/platform/davinci/vpbe.c
+++ b/drivers/media/platform/davinci/vpbe.c
@@ -558,9 +558,9 @@ static int platform_device_get(struct device *dev, void *data)
struct platform_device *pdev = to_platform_device(dev);
struct vpbe_device *vpbe_dev = data;
- if (strcmp("vpbe-osd", pdev->name) == 0)
+ if (strstr(pdev->name, "vpbe-osd") != NULL)
vpbe_dev->osd_device = platform_get_drvdata(pdev);
- if (strcmp("vpbe-venc", pdev->name) == 0)
+ if (strstr(pdev->name, "vpbe-venc") != NULL)
vpbe_dev->venc_device = dev_get_platdata(&pdev->dev);
return 0;
@@ -584,7 +584,6 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
struct v4l2_subdev **enc_subdev;
struct osd_state *osd_device;
struct i2c_adapter *i2c_adap;
- int output_index;
int num_encoders;
int ret = 0;
int err;
@@ -632,8 +631,10 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
err = bus_for_each_dev(&platform_bus_type, NULL, vpbe_dev,
platform_device_get);
- if (err < 0)
- return err;
+ if (err < 0) {
+ ret = err;
+ goto fail_dev_unregister;
+ }
vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev,
vpbe_dev->cfg->venc.module_name);
@@ -731,7 +732,6 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
/* set the current encoder and output to that of venc by default */
vpbe_dev->current_sd_index = 0;
vpbe_dev->current_out_index = 0;
- output_index = 0;
mutex_unlock(&vpbe_dev->lock);
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index e707a6f2325b..5e6b0cab514b 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -791,7 +791,6 @@ static int vpbe_display_g_crop(struct file *file, void *priv,
struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
struct osd_state *osd_device = fh->disp_dev->osd_device;
struct v4l2_rect *rect = &crop->c;
- int ret;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
"VIDIOC_G_CROP, layer id = %d\n",
@@ -799,7 +798,7 @@ static int vpbe_display_g_crop(struct file *file, void *priv,
if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
- ret = -EINVAL;
+ return -EINVAL;
}
osd_device->ops.get_layer_config(osd_device,
layer->layer_info.id, cfg);
@@ -1393,9 +1392,9 @@ static int vpbe_display_reqbufs(struct file *file, void *priv,
}
/* Initialize videobuf queue as per the buffer type */
layer->alloc_ctx = vb2_dma_contig_init_ctx(vpbe_dev->pdev);
- if (!layer->alloc_ctx) {
+ if (IS_ERR(layer->alloc_ctx)) {
v4l2_err(&vpbe_dev->v4l2_dev, "Failed to get the context\n");
- return -EINVAL;
+ return PTR_ERR(layer->alloc_ctx);
}
q = &layer->buffer_queue;
memset(q, 0, sizeof(*q));
@@ -1656,7 +1655,7 @@ static int vpbe_device_get(struct device *dev, void *data)
if (strcmp("vpbe_controller", pdev->name) == 0)
vpbe_disp->vpbe_dev = platform_get_drvdata(pdev);
- if (strcmp("vpbe-osd", pdev->name) == 0)
+ if (strstr(pdev->name, "vpbe-osd") != NULL)
vpbe_disp->osd_device = platform_get_drvdata(pdev);
return 0;
diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c
index 707f243f810d..12ad17c52ef3 100644
--- a/drivers/media/platform/davinci/vpbe_osd.c
+++ b/drivers/media/platform/davinci/vpbe_osd.c
@@ -39,7 +39,22 @@
#include <linux/io.h>
#include "vpbe_osd_regs.h"
-#define MODULE_NAME VPBE_OSD_SUBDEV_NAME
+#define MODULE_NAME "davinci-vpbe-osd"
+
+static struct platform_device_id vpbe_osd_devtype[] = {
+ {
+ .name = DM644X_VPBE_OSD_SUBDEV_NAME,
+ .driver_data = VPBE_VERSION_1,
+ }, {
+ .name = DM365_VPBE_OSD_SUBDEV_NAME,
+ .driver_data = VPBE_VERSION_2,
+ }, {
+ .name = DM355_VPBE_OSD_SUBDEV_NAME,
+ .driver_data = VPBE_VERSION_3,
+ },
+};
+
+MODULE_DEVICE_TABLE(platform, vpbe_osd_devtype);
/* register access routines */
static inline u32 osd_read(struct osd_state *sd, u32 offset)
@@ -129,7 +144,7 @@ static int _osd_dm6446_vid0_pingpong(struct osd_state *sd,
struct osd_platform_data *pdata;
pdata = (struct osd_platform_data *)sd->dev->platform_data;
- if (pdata->field_inv_wa_enable) {
+ if (pdata != NULL && pdata->field_inv_wa_enable) {
if (!field_inversion || !lconfig->interlaced) {
osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
@@ -1526,7 +1541,7 @@ static const struct vpbe_osd_ops osd_ops = {
static int osd_probe(struct platform_device *pdev)
{
- struct osd_platform_data *pdata;
+ const struct platform_device_id *pdev_id;
struct osd_state *osd;
struct resource *res;
int ret = 0;
@@ -1535,16 +1550,15 @@ static int osd_probe(struct platform_device *pdev)
if (osd == NULL)
return -ENOMEM;
- osd->dev = &pdev->dev;
- pdata = (struct osd_platform_data *)pdev->dev.platform_data;
- osd->vpbe_type = (enum vpbe_version)pdata->vpbe_type;
- if (NULL == pdev->dev.platform_data) {
- dev_err(osd->dev, "No platform data defined for OSD"
- " sub device\n");
- ret = -ENOENT;
+ pdev_id = platform_get_device_id(pdev);
+ if (!pdev_id) {
+ ret = -EINVAL;
goto free_mem;
}
+ osd->dev = &pdev->dev;
+ osd->vpbe_type = pdev_id->driver_data;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(osd->dev, "Unable to get OSD register address map\n");
@@ -1595,6 +1609,7 @@ static struct platform_driver osd_driver = {
.name = MODULE_NAME,
.owner = THIS_MODULE,
},
+ .id_table = vpbe_osd_devtype
};
module_platform_driver(osd_driver);
diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c
index aed7369b962a..bdbebd59df98 100644
--- a/drivers/media/platform/davinci/vpbe_venc.c
+++ b/drivers/media/platform/davinci/vpbe_venc.c
@@ -38,7 +38,22 @@
#include "vpbe_venc_regs.h"
-#define MODULE_NAME VPBE_VENC_SUBDEV_NAME
+#define MODULE_NAME "davinci-vpbe-venc"
+
+static struct platform_device_id vpbe_venc_devtype[] = {
+ {
+ .name = DM644X_VPBE_VENC_SUBDEV_NAME,
+ .driver_data = VPBE_VERSION_1,
+ }, {
+ .name = DM365_VPBE_VENC_SUBDEV_NAME,
+ .driver_data = VPBE_VERSION_2,
+ }, {
+ .name = DM355_VPBE_VENC_SUBDEV_NAME,
+ .driver_data = VPBE_VERSION_3,
+ },
+};
+
+MODULE_DEVICE_TABLE(platform, vpbe_venc_devtype);
static int debug = 2;
module_param(debug, int, 0644);
@@ -54,6 +69,7 @@ struct venc_state {
spinlock_t lock;
void __iomem *venc_base;
void __iomem *vdaccfg_reg;
+ enum vpbe_version venc_type;
};
static inline struct venc_state *to_state(struct v4l2_subdev *sd)
@@ -127,7 +143,7 @@ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
{
struct venc_state *venc = to_state(sd);
- struct venc_platform_data *pdata = venc->pdata;
+
v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n");
if (benable) {
@@ -159,7 +175,7 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
/* Disable LCD output control (accepting default polarity) */
venc_write(sd, VENC_LCDOUT, 0);
- if (pdata->venc_type != VPBE_VERSION_3)
+ if (venc->venc_type != VPBE_VERSION_3)
venc_write(sd, VENC_CMPNT, 0x100);
venc_write(sd, VENC_HSPLS, 0);
venc_write(sd, VENC_HINT, 0);
@@ -203,11 +219,11 @@ static int venc_set_ntsc(struct v4l2_subdev *sd)
venc_enabledigitaloutput(sd, 0);
- if (pdata->venc_type == VPBE_VERSION_3) {
+ if (venc->venc_type == VPBE_VERSION_3) {
venc_write(sd, VENC_CLKCTL, 0x01);
venc_write(sd, VENC_VIDCTL, 0);
val = vdaccfg_write(sd, VDAC_CONFIG_SD_V3);
- } else if (pdata->venc_type == VPBE_VERSION_2) {
+ } else if (venc->venc_type == VPBE_VERSION_2) {
venc_write(sd, VENC_CLKCTL, 0x01);
venc_write(sd, VENC_VIDCTL, 0);
vdaccfg_write(sd, VDAC_CONFIG_SD_V2);
@@ -238,7 +254,6 @@ static int venc_set_ntsc(struct v4l2_subdev *sd)
static int venc_set_pal(struct v4l2_subdev *sd)
{
struct venc_state *venc = to_state(sd);
- struct venc_platform_data *pdata = venc->pdata;
v4l2_dbg(debug, 2, sd, "venc_set_pal\n");
@@ -249,11 +264,11 @@ static int venc_set_pal(struct v4l2_subdev *sd)
venc_enabledigitaloutput(sd, 0);
- if (pdata->venc_type == VPBE_VERSION_3) {
+ if (venc->venc_type == VPBE_VERSION_3) {
venc_write(sd, VENC_CLKCTL, 0x1);
venc_write(sd, VENC_VIDCTL, 0);
vdaccfg_write(sd, VDAC_CONFIG_SD_V3);
- } else if (pdata->venc_type == VPBE_VERSION_2) {
+ } else if (venc->venc_type == VPBE_VERSION_2) {
venc_write(sd, VENC_CLKCTL, 0x1);
venc_write(sd, VENC_VIDCTL, 0);
vdaccfg_write(sd, VDAC_CONFIG_SD_V2);
@@ -293,8 +308,8 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd)
struct venc_platform_data *pdata = venc->pdata;
v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n");
- if ((pdata->venc_type != VPBE_VERSION_1) &&
- (pdata->venc_type != VPBE_VERSION_2))
+ if (venc->venc_type != VPBE_VERSION_1 &&
+ venc->venc_type != VPBE_VERSION_2)
return -EINVAL;
/* Setup clock at VPSS & VENC for SD */
@@ -303,12 +318,12 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd)
venc_enabledigitaloutput(sd, 0);
- if (pdata->venc_type == VPBE_VERSION_2)
+ if (venc->venc_type == VPBE_VERSION_2)
vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
venc_write(sd, VENC_OSDCLK0, 0);
venc_write(sd, VENC_OSDCLK1, 1);
- if (pdata->venc_type == VPBE_VERSION_1) {
+ if (venc->venc_type == VPBE_VERSION_1) {
venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
VENC_VDPRO_DAFRQ);
venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
@@ -341,8 +356,8 @@ static int venc_set_576p50(struct v4l2_subdev *sd)
v4l2_dbg(debug, 2, sd, "venc_set_576p50\n");
- if ((pdata->venc_type != VPBE_VERSION_1) &&
- (pdata->venc_type != VPBE_VERSION_2))
+ if (venc->venc_type != VPBE_VERSION_1 &&
+ venc->venc_type != VPBE_VERSION_2)
return -EINVAL;
/* Setup clock at VPSS & VENC for SD */
if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0)
@@ -350,13 +365,13 @@ static int venc_set_576p50(struct v4l2_subdev *sd)
venc_enabledigitaloutput(sd, 0);
- if (pdata->venc_type == VPBE_VERSION_2)
+ if (venc->venc_type == VPBE_VERSION_2)
vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
venc_write(sd, VENC_OSDCLK0, 0);
venc_write(sd, VENC_OSDCLK1, 1);
- if (pdata->venc_type == VPBE_VERSION_1) {
+ if (venc->venc_type == VPBE_VERSION_1) {
venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
VENC_VDPRO_DAFRQ);
venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
@@ -460,14 +475,14 @@ static int venc_s_dv_timings(struct v4l2_subdev *sd,
else if (height == 480)
return venc_set_480p59_94(sd);
else if ((height == 720) &&
- (venc->pdata->venc_type == VPBE_VERSION_2)) {
+ (venc->venc_type == VPBE_VERSION_2)) {
/* TBD setup internal 720p mode here */
ret = venc_set_720p60_internal(sd);
/* for DM365 VPBE, there is DAC inside */
vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
return ret;
} else if ((height == 1080) &&
- (venc->pdata->venc_type == VPBE_VERSION_2)) {
+ (venc->venc_type == VPBE_VERSION_2)) {
/* TBD setup internal 1080i mode here */
ret = venc_set_1080i30_internal(sd);
/* for DM365 VPBE, there is DAC inside */
@@ -556,7 +571,7 @@ static int venc_device_get(struct device *dev, void *data)
struct platform_device *pdev = to_platform_device(dev);
struct venc_state **venc = data;
- if (strcmp(MODULE_NAME, pdev->name) == 0)
+ if (strstr(pdev->name, "vpbe-venc") != NULL)
*venc = platform_get_drvdata(pdev);
return 0;
@@ -593,6 +608,7 @@ EXPORT_SYMBOL(venc_sub_dev_init);
static int venc_probe(struct platform_device *pdev)
{
+ const struct platform_device_id *pdev_id;
struct venc_state *venc;
struct resource *res;
int ret;
@@ -601,6 +617,12 @@ static int venc_probe(struct platform_device *pdev)
if (venc == NULL)
return -ENOMEM;
+ pdev_id = platform_get_device_id(pdev);
+ if (!pdev_id) {
+ ret = -EINVAL;
+ goto free_mem;
+ }
+ venc->venc_type = pdev_id->driver_data;
venc->pdev = &pdev->dev;
venc->pdata = pdev->dev.platform_data;
if (NULL == venc->pdata) {
@@ -630,7 +652,7 @@ static int venc_probe(struct platform_device *pdev)
goto release_venc_mem_region;
}
- if (venc->pdata->venc_type != VPBE_VERSION_1) {
+ if (venc->venc_type != VPBE_VERSION_1) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(venc->pdev,
@@ -681,7 +703,7 @@ static int venc_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
iounmap((void *)venc->venc_base);
release_mem_region(res->start, resource_size(res));
- if (venc->pdata->venc_type != VPBE_VERSION_1) {
+ if (venc->venc_type != VPBE_VERSION_1) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
iounmap((void *)venc->vdaccfg_reg);
release_mem_region(res->start, resource_size(res));
@@ -698,6 +720,7 @@ static struct platform_driver venc_driver = {
.name = MODULE_NAME,
.owner = THIS_MODULE,
},
+ .id_table = vpbe_venc_devtype
};
module_platform_driver(venc_driver);
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index be9d3e1b4868..28d019da4c01 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -560,10 +560,7 @@ static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev)
static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev)
{
- struct timeval timevalue;
-
- do_gettimeofday(&timevalue);
- vpfe_dev->cur_frm->ts = timevalue;
+ v4l2_get_timestamp(&vpfe_dev->cur_frm->ts);
vpfe_dev->cur_frm->state = VIDEOBUF_DONE;
vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage;
wake_up_interruptible(&vpfe_dev->cur_frm->done);
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index a409ccefb380..5892d2bc8eee 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -411,7 +411,7 @@ static struct vb2_ops video_qops = {
*/
static void vpif_process_buffer_complete(struct common_obj *common)
{
- do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp);
+ v4l2_get_timestamp(&common->cur_frm->vb.v4l2_buf.timestamp);
vb2_buffer_done(&common->cur_frm->vb,
VB2_BUF_STATE_DONE);
/* Make curFrm pointing to nextFrm */
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index 9f2b603be9c9..dd249c96126d 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -402,7 +402,7 @@ static void process_interlaced_mode(int fid, struct common_obj *common)
/* one frame is displayed If next frame is
* available, release cur_frm and move on */
/* Copy frame display time */
- do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp);
+ v4l2_get_timestamp(&common->cur_frm->vb.v4l2_buf.timestamp);
/* Change status of the cur_frm */
vb2_buffer_done(&common->cur_frm->vb,
VB2_BUF_STATE_DONE);
@@ -462,8 +462,8 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
if (!channel_first_int[i][channel_id]) {
/* Mark status of the cur_frm to
* done and unlock semaphore on it */
- do_gettimeofday(&common->cur_frm->vb.
- v4l2_buf.timestamp);
+ v4l2_get_timestamp(&common->cur_frm->vb.
+ v4l2_buf.timestamp);
vb2_buffer_done(&common->cur_frm->vb,
VB2_BUF_STATE_DONE);
/* Make cur_frm pointing to next_frm */
diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c
index cdbff88e0f1e..a19c552232d1 100644
--- a/drivers/media/platform/davinci/vpss.c
+++ b/drivers/media/platform/davinci/vpss.c
@@ -25,7 +25,6 @@
#include <linux/spinlock.h>
#include <linux/compiler.h>
#include <linux/io.h>
-#include <mach/hardware.h>
#include <media/davinci/vpss.h>
MODULE_LICENSE("GPL");
@@ -51,13 +50,29 @@ MODULE_AUTHOR("Texas Instruments");
/* VENCINT - vpss_int8 */
#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4
-#define DM365_ISP5_PCCR 0x04
+#define DM365_ISP5_PCCR 0x04
+#define DM365_ISP5_PCCR_BL_CLK_ENABLE BIT(0)
+#define DM365_ISP5_PCCR_ISIF_CLK_ENABLE BIT(1)
+#define DM365_ISP5_PCCR_H3A_CLK_ENABLE BIT(2)
+#define DM365_ISP5_PCCR_RSZ_CLK_ENABLE BIT(3)
+#define DM365_ISP5_PCCR_IPIPE_CLK_ENABLE BIT(4)
+#define DM365_ISP5_PCCR_IPIPEIF_CLK_ENABLE BIT(5)
+#define DM365_ISP5_PCCR_RSV BIT(6)
+
+#define DM365_ISP5_BCR 0x08
+#define DM365_ISP5_BCR_ISIF_OUT_ENABLE BIT(1)
+
#define DM365_ISP5_INTSEL1 0x10
#define DM365_ISP5_INTSEL2 0x14
#define DM365_ISP5_INTSEL3 0x18
#define DM365_ISP5_CCDCMUX 0x20
#define DM365_ISP5_PG_FRAME_SIZE 0x28
#define DM365_VPBE_CLK_CTRL 0x00
+
+#define VPSS_CLK_CTRL 0x01c40044
+#define VPSS_CLK_CTRL_VENCCLKEN BIT(3)
+#define VPSS_CLK_CTRL_DACCLKEN BIT(4)
+
/*
* vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1,
* AF - vpss_int3
@@ -95,12 +110,19 @@ struct vpss_hw_ops {
void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel);
/* clear wbl overflow bit */
int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel);
+ /* set sync polarity */
+ void (*set_sync_pol)(struct vpss_sync_pol);
+ /* set the PG_FRAME_SIZE register*/
+ void (*set_pg_frame_size)(struct vpss_pg_frame_size);
+ /* check and clear interrupt if occured */
+ int (*dma_complete_interrupt)(void);
};
/* vpss configuration */
struct vpss_oper_config {
__iomem void *vpss_regs_base0;
__iomem void *vpss_regs_base1;
+ resource_size_t *vpss_regs_base2;
enum vpss_platform_type platform;
spinlock_t vpss_lock;
struct vpss_hw_ops hw_ops;
@@ -158,6 +180,14 @@ static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX);
}
+int vpss_dma_complete_interrupt(void)
+{
+ if (!oper_cfg.hw_ops.dma_complete_interrupt)
+ return 2;
+ return oper_cfg.hw_ops.dma_complete_interrupt();
+}
+EXPORT_SYMBOL(vpss_dma_complete_interrupt);
+
int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
{
if (!oper_cfg.hw_ops.select_ccdc_source)
@@ -183,6 +213,15 @@ static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
return 0;
}
+void vpss_set_sync_pol(struct vpss_sync_pol sync)
+{
+ if (!oper_cfg.hw_ops.set_sync_pol)
+ return;
+
+ oper_cfg.hw_ops.set_sync_pol(sync);
+}
+EXPORT_SYMBOL(vpss_set_sync_pol);
+
int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
{
if (!oper_cfg.hw_ops.clear_wbl_overflow)
@@ -348,6 +387,15 @@ void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync)
}
EXPORT_SYMBOL(dm365_vpss_set_sync_pol);
+void vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
+{
+ if (!oper_cfg.hw_ops.set_pg_frame_size)
+ return;
+
+ oper_cfg.hw_ops.set_pg_frame_size(frame_size);
+}
+EXPORT_SYMBOL(vpss_set_pg_frame_size);
+
void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
{
int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16;
@@ -426,6 +474,16 @@ static int vpss_probe(struct platform_device *pdev)
oper_cfg.hw_ops.enable_clock = dm365_enable_clock;
oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source;
/* Setup vpss interrupts */
+ isp5_write((isp5_read(DM365_ISP5_PCCR) |
+ DM365_ISP5_PCCR_BL_CLK_ENABLE |
+ DM365_ISP5_PCCR_ISIF_CLK_ENABLE |
+ DM365_ISP5_PCCR_H3A_CLK_ENABLE |
+ DM365_ISP5_PCCR_RSZ_CLK_ENABLE |
+ DM365_ISP5_PCCR_IPIPE_CLK_ENABLE |
+ DM365_ISP5_PCCR_IPIPEIF_CLK_ENABLE |
+ DM365_ISP5_PCCR_RSV), DM365_ISP5_PCCR);
+ isp5_write((isp5_read(DM365_ISP5_BCR) |
+ DM365_ISP5_BCR_ISIF_OUT_ENABLE), DM365_ISP5_BCR);
isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1);
isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2);
isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3);
@@ -471,11 +529,20 @@ static struct platform_driver vpss_driver = {
static void vpss_exit(void)
{
+ iounmap(oper_cfg.vpss_regs_base2);
+ release_mem_region(VPSS_CLK_CTRL, 4);
platform_driver_unregister(&vpss_driver);
}
static int __init vpss_init(void)
{
+ if (!request_mem_region(VPSS_CLK_CTRL, 4, "vpss_clock_control"))
+ return -EBUSY;
+
+ oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4);
+ writel(VPSS_CLK_CTRL_VENCCLKEN |
+ VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2);
+
return platform_driver_register(&vpss_driver);
}
subsys_initcall(vpss_init);
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 2b1b9f30e1f9..82d9f6ac12f3 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -185,6 +185,15 @@ static const struct gsc_fmt gsc_formats[] = {
.corder = GSC_CRCB,
.num_planes = 3,
.num_comp = 3,
+ }, {
+ .name = "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
+ .pixelformat = V4L2_PIX_FMT_NV12MT_16X16,
+ .depth = { 8, 4 },
+ .color = GSC_YUV420,
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CBCR,
+ .num_planes = 2,
+ .num_comp = 2,
}
};
@@ -935,8 +944,8 @@ static struct gsc_variant gsc_v_100_variant = {
.pix_max = &gsc_v_100_max,
.pix_min = &gsc_v_100_min,
.pix_align = &gsc_v_100_align,
- .in_buf_cnt = 8,
- .out_buf_cnt = 16,
+ .in_buf_cnt = 32,
+ .out_buf_cnt = 32,
.sc_up_max = 8,
.sc_down_max = 16,
.poly_sc_down_max = 4,
@@ -993,12 +1002,8 @@ static void *gsc_get_drv_data(struct platform_device *pdev)
static void gsc_clk_put(struct gsc_dev *gsc)
{
- if (IS_ERR_OR_NULL(gsc->clock))
- return;
-
- clk_unprepare(gsc->clock);
- clk_put(gsc->clock);
- gsc->clock = NULL;
+ if (!IS_ERR(gsc->clock))
+ clk_unprepare(gsc->clock);
}
static int gsc_clk_get(struct gsc_dev *gsc)
@@ -1007,27 +1012,22 @@ static int gsc_clk_get(struct gsc_dev *gsc)
dev_dbg(&gsc->pdev->dev, "gsc_clk_get Called\n");
- gsc->clock = clk_get(&gsc->pdev->dev, GSC_CLOCK_GATE_NAME);
- if (IS_ERR(gsc->clock))
- goto err_print;
+ gsc->clock = devm_clk_get(&gsc->pdev->dev, GSC_CLOCK_GATE_NAME);
+ if (IS_ERR(gsc->clock)) {
+ dev_err(&gsc->pdev->dev, "failed to get clock~~~: %s\n",
+ GSC_CLOCK_GATE_NAME);
+ return PTR_ERR(gsc->clock);
+ }
ret = clk_prepare(gsc->clock);
if (ret < 0) {
- clk_put(gsc->clock);
- gsc->clock = NULL;
- goto err;
+ dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
+ GSC_CLOCK_GATE_NAME);
+ gsc->clock = ERR_PTR(-EINVAL);
+ return ret;
}
return 0;
-
-err:
- dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
- GSC_CLOCK_GATE_NAME);
- gsc_clk_put(gsc);
-err_print:
- dev_err(&gsc->pdev->dev, "failed to get clock~~~: %s\n",
- GSC_CLOCK_GATE_NAME);
- return -ENXIO;
}
static int gsc_m2m_suspend(struct gsc_dev *gsc)
@@ -1096,13 +1096,12 @@ static int gsc_probe(struct platform_device *pdev)
init_waitqueue_head(&gsc->irq_queue);
spin_lock_init(&gsc->slock);
mutex_init(&gsc->lock);
+ gsc->clock = ERR_PTR(-EINVAL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- gsc->regs = devm_request_and_ioremap(dev, res);
- if (!gsc->regs) {
- dev_err(dev, "failed to map registers\n");
- return -ENOENT;
- }
+ gsc->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(gsc->regs))
+ return PTR_ERR(gsc->regs);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
@@ -1159,6 +1158,7 @@ static int gsc_remove(struct platform_device *pdev)
vb2_dma_contig_cleanup_ctx(gsc->alloc_ctx);
pm_runtime_disable(&pdev->dev);
+ gsc_clk_put(gsc);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h
index 5f157efd24f0..cc19bba09bd1 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.h
+++ b/drivers/media/platform/exynos-gsc/gsc-core.h
@@ -427,6 +427,11 @@ static inline void gsc_ctx_state_lock_clear(u32 state, struct gsc_ctx *ctx)
spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags);
}
+static inline int is_tiled(const struct gsc_fmt *fmt)
+{
+ return fmt->pixelformat == V4L2_PIX_FMT_NV12MT_16X16;
+}
+
static inline void gsc_hw_enable_control(struct gsc_dev *dev, bool on)
{
u32 cfg = readl(dev->regs + GSC_ENABLE);
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index c267c57c76fd..386c0a7a3a52 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -99,22 +99,28 @@ static void gsc_m2m_job_abort(void *priv)
gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
}
-static int gsc_fill_addr(struct gsc_ctx *ctx)
+static int gsc_get_bufs(struct gsc_ctx *ctx)
{
struct gsc_frame *s_frame, *d_frame;
- struct vb2_buffer *vb = NULL;
+ struct vb2_buffer *src_vb, *dst_vb;
int ret;
s_frame = &ctx->s_frame;
d_frame = &ctx->d_frame;
- vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
- ret = gsc_prepare_addr(ctx, vb, s_frame, &s_frame->addr);
+ src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ ret = gsc_prepare_addr(ctx, src_vb, s_frame, &s_frame->addr);
if (ret)
return ret;
- vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
- return gsc_prepare_addr(ctx, vb, d_frame, &d_frame->addr);
+ dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ ret = gsc_prepare_addr(ctx, dst_vb, d_frame, &d_frame->addr);
+ if (ret)
+ return ret;
+
+ dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp;
+
+ return 0;
}
static void gsc_m2m_device_run(void *priv)
@@ -148,7 +154,7 @@ static void gsc_m2m_device_run(void *priv)
goto put_device;
}
- ret = gsc_fill_addr(ctx);
+ ret = gsc_get_bufs(ctx);
if (ret) {
pr_err("Wrong address");
goto put_device;
@@ -367,6 +373,13 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh,
return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
}
+static int gsc_m2m_expbuf(struct file *file, void *fh,
+ struct v4l2_exportbuffer *eb)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+ return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
+}
+
static int gsc_m2m_querybuf(struct file *file, void *fh,
struct v4l2_buffer *buf)
{
@@ -548,6 +561,7 @@ static const struct v4l2_ioctl_ops gsc_m2m_ioctl_ops = {
.vidioc_s_fmt_vid_cap_mplane = gsc_m2m_s_fmt_mplane,
.vidioc_s_fmt_vid_out_mplane = gsc_m2m_s_fmt_mplane,
.vidioc_reqbufs = gsc_m2m_reqbufs,
+ .vidioc_expbuf = gsc_m2m_expbuf,
.vidioc_querybuf = gsc_m2m_querybuf,
.vidioc_qbuf = gsc_m2m_qbuf,
.vidioc_dqbuf = gsc_m2m_dqbuf,
@@ -565,7 +579,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
memset(src_vq, 0, sizeof(*src_vq));
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->ops = &gsc_m2m_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
@@ -577,7 +591,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
memset(dst_vq, 0, sizeof(*dst_vq));
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->ops = &gsc_m2m_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
@@ -597,7 +611,7 @@ static int gsc_m2m_open(struct file *file)
if (mutex_lock_interruptible(&gsc->lock))
return -ERESTARTSYS;
- ctx = kzalloc(sizeof (*ctx), GFP_KERNEL);
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
ret = -ENOMEM;
goto unlock;
diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c
index 0146b354dc22..6f5b5a486cf3 100644
--- a/drivers/media/platform/exynos-gsc/gsc-regs.c
+++ b/drivers/media/platform/exynos-gsc/gsc-regs.c
@@ -214,6 +214,9 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
break;
}
+ if (is_tiled(frame->fmt))
+ cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE;
+
writel(cfg, dev->regs + GSC_IN_CON);
}
@@ -334,6 +337,9 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
break;
}
+ if (is_tiled(frame->fmt))
+ cfg |= GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE;
+
end_set:
writel(cfg, dev->regs + GSC_OUT_CON);
}
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index 9115a2c8d075..5f7db3f1f6f5 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -1181,7 +1181,7 @@ static void viu_capture_intr(struct viu_dev *dev, u32 status)
if (waitqueue_active(&buf->vb.done)) {
list_del(&buf->vb.queue);
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
wake_up(&buf->vb.done);
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 05c560f2ef06..6c4db9b98989 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -28,7 +28,7 @@ MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.1");
-static bool debug = true;
+static bool debug;
module_param(debug, bool, 0644);
/* Flags that indicate a format can be used for capture/output */
@@ -917,10 +917,8 @@ static int deinterlace_open(struct file *file)
ctx->xt = kzalloc(sizeof(struct dma_async_tx_descriptor) +
sizeof(struct data_chunk), GFP_KERNEL);
if (!ctx->xt) {
- int ret = PTR_ERR(ctx->xt);
-
kfree(ctx);
- return ret;
+ return -ENOMEM;
}
ctx->colorspace = V4L2_COLORSPACE_REC709;
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index ce2b7b4788d6..92a33f081852 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -22,6 +22,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-chip-ident.h>
#include <media/ov7670.h>
#include <media/videobuf2-vmalloc.h>
@@ -30,13 +31,6 @@
#include "mcam-core.h"
-/*
- * Basic frame stats - to be deleted shortly
- */
-static int frames;
-static int singles;
-static int delivered;
-
#ifdef MCAM_MODE_VMALLOC
/*
* Internal DMA buffer management. Since the controller cannot do S/G I/O,
@@ -367,10 +361,10 @@ static void mcam_frame_tasklet(unsigned long data)
if (!test_bit(bufno, &cam->flags))
continue;
if (list_empty(&cam->buffers)) {
- singles++;
+ cam->frame_state.singles++;
break; /* Leave it valid, hope for better later */
}
- delivered++;
+ cam->frame_state.delivered++;
clear_bit(bufno, &cam->flags);
buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer,
queue);
@@ -452,7 +446,7 @@ static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame)
mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0));
set_bit(CF_SINGLE_BUFFER, &cam->flags);
- singles++;
+ cam->frame_state.singles++;
return;
}
/*
@@ -485,7 +479,7 @@ static void mcam_dma_contig_done(struct mcam_camera *cam, int frame)
struct mcam_vb_buffer *buf = cam->vb_bufs[frame];
if (!test_bit(CF_SINGLE_BUFFER, &cam->flags)) {
- delivered++;
+ cam->frame_state.delivered++;
mcam_buffer_done(cam, frame, &buf->vb_buf);
}
mcam_set_contig_buffer(cam, frame);
@@ -578,13 +572,13 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
*/
} else {
set_bit(CF_SG_RESTART, &cam->flags);
- singles++;
+ cam->frame_state.singles++;
cam->vb_bufs[0] = NULL;
}
/*
* Now we can give the completed frame back to user space.
*/
- delivered++;
+ cam->frame_state.delivered++;
mcam_buffer_done(cam, frame, &buf->vb_buf);
}
@@ -1232,47 +1226,6 @@ static int mcam_vidioc_dqbuf(struct file *filp, void *priv,
return ret;
}
-
-
-static int mcam_vidioc_queryctrl(struct file *filp, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct mcam_camera *cam = priv;
- int ret;
-
- mutex_lock(&cam->s_mutex);
- ret = sensor_call(cam, core, queryctrl, qc);
- mutex_unlock(&cam->s_mutex);
- return ret;
-}
-
-
-static int mcam_vidioc_g_ctrl(struct file *filp, void *priv,
- struct v4l2_control *ctrl)
-{
- struct mcam_camera *cam = priv;
- int ret;
-
- mutex_lock(&cam->s_mutex);
- ret = sensor_call(cam, core, g_ctrl, ctrl);
- mutex_unlock(&cam->s_mutex);
- return ret;
-}
-
-
-static int mcam_vidioc_s_ctrl(struct file *filp, void *priv,
- struct v4l2_control *ctrl)
-{
- struct mcam_camera *cam = priv;
- int ret;
-
- mutex_lock(&cam->s_mutex);
- ret = sensor_call(cam, core, s_ctrl, ctrl);
- mutex_unlock(&cam->s_mutex);
- return ret;
-}
-
-
static int mcam_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -1520,9 +1473,6 @@ static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = {
.vidioc_dqbuf = mcam_vidioc_dqbuf,
.vidioc_streamon = mcam_vidioc_streamon,
.vidioc_streamoff = mcam_vidioc_streamoff,
- .vidioc_queryctrl = mcam_vidioc_queryctrl,
- .vidioc_g_ctrl = mcam_vidioc_g_ctrl,
- .vidioc_s_ctrl = mcam_vidioc_s_ctrl,
.vidioc_g_parm = mcam_vidioc_g_parm,
.vidioc_s_parm = mcam_vidioc_s_parm,
.vidioc_enum_framesizes = mcam_vidioc_enum_framesizes,
@@ -1545,7 +1495,9 @@ static int mcam_v4l_open(struct file *filp)
filp->private_data = cam;
- frames = singles = delivered = 0;
+ cam->frame_state.frames = 0;
+ cam->frame_state.singles = 0;
+ cam->frame_state.delivered = 0;
mutex_lock(&cam->s_mutex);
if (cam->users == 0) {
ret = mcam_setup_vb2(cam);
@@ -1566,8 +1518,9 @@ static int mcam_v4l_release(struct file *filp)
{
struct mcam_camera *cam = filp->private_data;
- cam_dbg(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
- singles, delivered);
+ cam_dbg(cam, "Release, %d frames, %d singles, %d delivered\n",
+ cam->frame_state.frames, cam->frame_state.singles,
+ cam->frame_state.delivered);
mutex_lock(&cam->s_mutex);
(cam->users)--;
if (cam->users == 0) {
@@ -1660,7 +1613,7 @@ static void mcam_frame_complete(struct mcam_camera *cam, int frame)
clear_bit(CF_DMA_ACTIVE, &cam->flags);
cam->next_buf = frame;
cam->buf_seq[frame] = ++(cam->sequence);
- frames++;
+ cam->frame_state.frames++;
/*
* "This should never happen"
*/
@@ -1786,14 +1739,19 @@ int mccic_register(struct mcam_camera *cam)
/*
* Get the v4l2 setup done.
*/
+ ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10);
+ if (ret)
+ goto out_unregister;
+ cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler;
+
mutex_lock(&cam->s_mutex);
cam->vdev = mcam_v4l_template;
cam->vdev.debug = 0;
cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ video_set_drvdata(&cam->vdev, cam);
ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
if (ret)
goto out;
- video_set_drvdata(&cam->vdev, cam);
/*
* If so requested, try to get our DMA buffers now.
@@ -1805,6 +1763,7 @@ int mccic_register(struct mcam_camera *cam)
}
out:
+ v4l2_ctrl_handler_free(&cam->ctrl_handler);
mutex_unlock(&cam->s_mutex);
return ret;
out_unregister:
@@ -1829,6 +1788,7 @@ void mccic_shutdown(struct mcam_camera *cam)
if (cam->buffer_mode == B_vmalloc)
mcam_free_dma_bufs(cam);
video_unregister_device(&cam->vdev);
+ v4l2_ctrl_handler_free(&cam->ctrl_handler);
v4l2_device_unregister(&cam->v4l2_dev);
}
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h
index bd6acba9fb37..01dec9e5fc2b 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.h
+++ b/drivers/media/platform/marvell-ccic/mcam-core.h
@@ -8,6 +8,7 @@
#include <linux/list.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-dev.h>
#include <media/videobuf2-core.h>
@@ -15,15 +16,15 @@
* Create our own symbols for the supported buffer modes, but, for now,
* base them entirely on which videobuf2 options have been selected.
*/
-#if defined(CONFIG_VIDEOBUF2_VMALLOC) || defined(CONFIG_VIDEOBUF2_VMALLOC_MODULE)
+#if IS_ENABLED(CONFIG_VIDEOBUF2_VMALLOC)
#define MCAM_MODE_VMALLOC 1
#endif
-#if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) || defined(CONFIG_VIDEOBUF2_DMA_CONTIG_MODULE)
+#if IS_ENABLED(CONFIG_VIDEOBUF2_DMA_CONTIG)
#define MCAM_MODE_DMA_CONTIG 1
#endif
-#if defined(CONFIG_VIDEOBUF2_DMA_SG) || defined(CONFIG_VIDEOBUF2_DMA_SG_MODULE)
+#if IS_ENABLED(CONFIG_VIDEOBUF2_DMA_SG)
#define MCAM_MODE_DMA_SG 1
#endif
@@ -73,6 +74,14 @@ static inline int mcam_buffer_mode_supported(enum mcam_buffer_mode mode)
}
}
+/*
+ * Basic frame states
+ */
+struct mcam_frame_state {
+ unsigned int frames;
+ unsigned int singles;
+ unsigned int delivered;
+};
/*
* A description of one of our devices.
@@ -104,10 +113,12 @@ struct mcam_camera {
* should not be touched by the platform code.
*/
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
enum mcam_state state;
unsigned long flags; /* Buffer status, mainly (dev_lock) */
int users; /* How many open FDs */
+ struct mcam_frame_state frame_state; /* Frame state counter */
/*
* Subsystem structures.
*/
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index 6b155d7be8e0..4b9e0a28616a 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -941,9 +941,9 @@ static int emmaprp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pcdev);
- pcdev->base_emma = devm_request_and_ioremap(&pdev->dev, res_emma);
- if (!pcdev->base_emma) {
- ret = -ENXIO;
+ pcdev->base_emma = devm_ioremap_resource(&pdev->dev, res_emma);
+ if (IS_ERR(pcdev->base_emma)) {
+ ret = PTR_ERR(pcdev->base_emma);
goto rel_vdev;
}
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index 390ab094f9f2..37ad446b35b3 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -6,7 +6,7 @@ config VIDEO_OMAP2_VOUT
depends on ARCH_OMAP2 || ARCH_OMAP3
select VIDEOBUF_GEN
select VIDEOBUF_DMA_CONTIG
- select OMAP2_DSS
+ select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
default n
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index 35cc526e6c93..96c4a17e4280 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -205,19 +205,21 @@ static u32 omap_vout_uservirt_to_phys(u32 virtp)
struct vm_area_struct *vma;
struct mm_struct *mm = current->mm;
- vma = find_vma(mm, virtp);
/* For kernel direct-mapped memory, take the easy way */
- if (virtp >= PAGE_OFFSET) {
- physp = virt_to_phys((void *) virtp);
- } else if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
+ if (virtp >= PAGE_OFFSET)
+ return virt_to_phys((void *) virtp);
+
+ down_read(&current->mm->mmap_sem);
+ vma = find_vma(mm, virtp);
+ if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
/* this will catch, kernel-allocated, mmaped-to-usermode
addresses */
physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
+ up_read(&current->mm->mmap_sem);
} else {
/* otherwise, use get_user_pages() for general userland pages */
int res, nr_pages = 1;
struct page *pages;
- down_read(&current->mm->mmap_sem);
res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
0, &pages, NULL);
@@ -595,7 +597,7 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus)
return;
spin_lock(&vout->vbq_lock);
- do_gettimeofday(&timevalue);
+ v4l2_get_timestamp(&timevalue);
switch (cur_display->type) {
case OMAP_DISPLAY_TYPE_DSI:
@@ -1230,21 +1232,6 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
return ret;
}
-static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh,
- struct v4l2_fmtdesc *fmt)
-{
- int index = fmt->index;
-
- if (index >= NUM_OUTPUT_FORMATS)
- return -EINVAL;
-
- fmt->flags = omap_formats[index].flags;
- strlcpy(fmt->description, omap_formats[index].description,
- sizeof(fmt->description));
- fmt->pixelformat = omap_formats[index].pixelformat;
- return 0;
-}
-
static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
struct v4l2_format *f)
{
@@ -1858,10 +1845,9 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = {
.vidioc_s_fbuf = vidioc_s_fbuf,
.vidioc_g_fbuf = vidioc_g_fbuf,
.vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
- .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
- .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
- .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
+ .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_overlay,
+ .vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_overlay,
+ .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_overlay,
.vidioc_cropcap = vidioc_cropcap,
.vidioc_g_crop = vidioc_g_crop,
.vidioc_s_crop = vidioc_s_crop,
diff --git a/drivers/media/platform/omap24xxcam.c b/drivers/media/platform/omap24xxcam.c
index 8b7ccea982e7..debb44ceb185 100644
--- a/drivers/media/platform/omap24xxcam.c
+++ b/drivers/media/platform/omap24xxcam.c
@@ -402,7 +402,7 @@ static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma,
omap24xxcam_core_disable(cam);
spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
- do_gettimeofday(&vb->ts);
+ v4l2_get_timestamp(&vb->ts);
vb->field_count = atomic_add_return(2, &fh->field_count);
if (csr & csr_error) {
vb->state = VIDEOBUF_ERROR;
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index e4aaee91201d..383a727b8aa0 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -1406,28 +1406,15 @@ static const char *isp_clocks[] = {
"l3_ick",
};
-static void isp_put_clocks(struct isp_device *isp)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
- if (isp->clock[i]) {
- clk_put(isp->clock[i]);
- isp->clock[i] = NULL;
- }
- }
-}
-
static int isp_get_clocks(struct isp_device *isp)
{
struct clk *clk;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
- clk = clk_get(isp->dev, isp_clocks[i]);
+ clk = devm_clk_get(isp->dev, isp_clocks[i]);
if (IS_ERR(clk)) {
dev_err(isp->dev, "clk_get %s failed\n", isp_clocks[i]);
- isp_put_clocks(isp);
return PTR_ERR(clk);
}
@@ -1993,7 +1980,6 @@ error_csiphy:
static int isp_remove(struct platform_device *pdev)
{
struct isp_device *isp = platform_get_drvdata(pdev);
- int i;
isp_unregister_entities(isp);
isp_cleanup_modules(isp);
@@ -2004,26 +1990,6 @@ static int isp_remove(struct platform_device *pdev)
isp->domain = NULL;
omap3isp_put(isp);
- free_irq(isp->irq_num, isp);
- isp_put_clocks(isp);
-
- for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
- if (isp->mmio_base[i]) {
- iounmap(isp->mmio_base[i]);
- isp->mmio_base[i] = NULL;
- }
-
- if (isp->mmio_base_phys[i]) {
- release_mem_region(isp->mmio_base_phys[i],
- isp->mmio_size[i]);
- isp->mmio_base_phys[i] = 0;
- }
- }
-
- regulator_put(isp->isp_csiphy1.vdd);
- regulator_put(isp->isp_csiphy2.vdd);
- kfree(isp);
-
return 0;
}
@@ -2041,7 +2007,8 @@ static int isp_map_mem_resource(struct platform_device *pdev,
return -ENODEV;
}
- if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
+ if (!devm_request_mem_region(isp->dev, mem->start, resource_size(mem),
+ pdev->name)) {
dev_err(isp->dev,
"cannot reserve camera register I/O region\n");
return -ENODEV;
@@ -2050,8 +2017,9 @@ static int isp_map_mem_resource(struct platform_device *pdev,
isp->mmio_size[res] = resource_size(mem);
/* map the region */
- isp->mmio_base[res] = ioremap_nocache(isp->mmio_base_phys[res],
- isp->mmio_size[res]);
+ isp->mmio_base[res] = devm_ioremap_nocache(isp->dev,
+ isp->mmio_base_phys[res],
+ isp->mmio_size[res]);
if (!isp->mmio_base[res]) {
dev_err(isp->dev, "cannot map camera register I/O region\n");
return -ENODEV;
@@ -2081,7 +2049,7 @@ static int isp_probe(struct platform_device *pdev)
if (pdata == NULL)
return -EINVAL;
- isp = kzalloc(sizeof(*isp), GFP_KERNEL);
+ isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL);
if (!isp) {
dev_err(&pdev->dev, "could not allocate memory\n");
return -ENOMEM;
@@ -2104,8 +2072,8 @@ static int isp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, isp);
/* Regulators */
- isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1");
- isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2");
+ isp->isp_csiphy1.vdd = devm_regulator_get(&pdev->dev, "VDD_CSIPHY1");
+ isp->isp_csiphy2.vdd = devm_regulator_get(&pdev->dev, "VDD_CSIPHY2");
/* Clocks
*
@@ -2180,7 +2148,8 @@ static int isp_probe(struct platform_device *pdev)
goto detach_dev;
}
- if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) {
+ if (devm_request_irq(isp->dev, isp->irq_num, isp_isr, IRQF_SHARED,
+ "OMAP3 ISP", isp)) {
dev_err(isp->dev, "Unable to request IRQ\n");
ret = -EINVAL;
goto detach_dev;
@@ -2189,7 +2158,7 @@ static int isp_probe(struct platform_device *pdev)
/* Entities */
ret = isp_initialize_modules(isp);
if (ret < 0)
- goto error_irq;
+ goto detach_dev;
ret = isp_register_entities(isp);
if (ret < 0)
@@ -2202,8 +2171,6 @@ static int isp_probe(struct platform_device *pdev)
error_modules:
isp_cleanup_modules(isp);
-error_irq:
- free_irq(isp->irq_num, isp);
detach_dev:
iommu_detach_device(isp->domain, &pdev->dev);
free_domain:
@@ -2211,26 +2178,9 @@ free_domain:
error_isp:
omap3isp_put(isp);
error:
- isp_put_clocks(isp);
-
- for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
- if (isp->mmio_base[i]) {
- iounmap(isp->mmio_base[i]);
- isp->mmio_base[i] = NULL;
- }
-
- if (isp->mmio_base_phys[i]) {
- release_mem_region(isp->mmio_base_phys[i],
- isp->mmio_size[i]);
- isp->mmio_base_phys[i] = 0;
- }
- }
- regulator_put(isp->isp_csiphy2.vdd);
- regulator_put(isp->isp_csiphy1.vdd);
platform_set_drvdata(pdev, NULL);
mutex_destroy(&isp->isp_mutex);
- kfree(isp);
return ret;
}
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index 85f0de85f37c..c5d84c977e29 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -1136,7 +1136,7 @@ int omap3isp_ccp2_init(struct isp_device *isp)
* TODO: Don't hardcode the usage of PHY1 (shared with CSI2c).
*/
if (isp->revision == ISP_REVISION_2_0) {
- ccp2->vdds_csib = regulator_get(isp->dev, "vdds_csib");
+ ccp2->vdds_csib = devm_regulator_get(isp->dev, "vdds_csib");
if (IS_ERR(ccp2->vdds_csib)) {
dev_dbg(isp->dev,
"Could not get regulator vdds_csib\n");
@@ -1147,10 +1147,8 @@ int omap3isp_ccp2_init(struct isp_device *isp)
}
ret = ccp2_init_entities(ccp2);
- if (ret < 0) {
- regulator_put(ccp2->vdds_csib);
+ if (ret < 0)
return ret;
- }
ccp2_reset(ccp2);
return 0;
@@ -1166,6 +1164,4 @@ void omap3isp_ccp2_cleanup(struct isp_device *isp)
omap3isp_video_cleanup(&ccp2->video_in);
media_entity_cleanup(&ccp2->subdev.entity);
-
- regulator_put(ccp2->vdds_csib);
}
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c
index 3d56b33f85e8..c09de32f986a 100644
--- a/drivers/media/platform/omap3isp/ispcsiphy.c
+++ b/drivers/media/platform/omap3isp/ispcsiphy.c
@@ -32,7 +32,8 @@
#include "ispreg.h"
#include "ispcsiphy.h"
-static void csiphy_routing_cfg_3630(struct isp_csiphy *phy, u32 iface,
+static void csiphy_routing_cfg_3630(struct isp_csiphy *phy,
+ enum isp_interface_type iface,
bool ccp2_strobe)
{
u32 reg = isp_reg_readl(
@@ -40,6 +41,8 @@ static void csiphy_routing_cfg_3630(struct isp_csiphy *phy, u32 iface,
u32 shift, mode;
switch (iface) {
+ default:
+ /* Should not happen in practice, but let's keep the compiler happy. */
case ISP_INTERFACE_CCP2B_PHY1:
reg &= ~OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2;
shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT;
@@ -59,9 +62,8 @@ static void csiphy_routing_cfg_3630(struct isp_csiphy *phy, u32 iface,
}
/* Select data/clock or data/strobe mode for CCP2 */
- switch (iface) {
- case ISP_INTERFACE_CCP2B_PHY1:
- case ISP_INTERFACE_CCP2B_PHY2:
+ if (iface == ISP_INTERFACE_CCP2B_PHY1 ||
+ iface == ISP_INTERFACE_CCP2B_PHY2) {
if (ccp2_strobe)
mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_STROBE;
else
@@ -110,7 +112,8 @@ static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on,
* and 3630, so they will not hold their contents in off-mode. This isn't an
* issue since the MPU power domain is forced on whilst the ISP is in use.
*/
-static void csiphy_routing_cfg(struct isp_csiphy *phy, u32 iface, bool on,
+static void csiphy_routing_cfg(struct isp_csiphy *phy,
+ enum isp_interface_type iface, bool on,
bool ccp2_strobe)
{
if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL]
diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c
index 036e9961d027..75fd82b152ba 100644
--- a/drivers/media/platform/omap3isp/isph3a_aewb.c
+++ b/drivers/media/platform/omap3isp/isph3a_aewb.c
@@ -300,13 +300,11 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp)
struct ispstat *aewb = &isp->isp_aewb;
struct omap3isp_h3a_aewb_config *aewb_cfg;
struct omap3isp_h3a_aewb_config *aewb_recover_cfg;
- int ret;
- aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL);
+ aewb_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_cfg), GFP_KERNEL);
if (!aewb_cfg)
return -ENOMEM;
- memset(aewb, 0, sizeof(*aewb));
aewb->ops = &h3a_aewb_ops;
aewb->priv = aewb_cfg;
aewb->dma_ch = -1;
@@ -314,12 +312,12 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp)
aewb->isp = isp;
/* Set recover state configuration */
- aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL);
+ aewb_recover_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_recover_cfg),
+ GFP_KERNEL);
if (!aewb_recover_cfg) {
dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for "
"recover configuration.\n");
- ret = -ENOMEM;
- goto err_recover_alloc;
+ return -ENOMEM;
}
aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM;
@@ -336,25 +334,13 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp)
if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) {
dev_err(aewb->isp->dev, "AEWB: recover configuration is "
"invalid.\n");
- ret = -EINVAL;
- goto err_conf;
+ return -EINVAL;
}
aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg);
aewb->recover_priv = aewb_recover_cfg;
- ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
- if (ret)
- goto err_conf;
-
- return 0;
-
-err_conf:
- kfree(aewb_recover_cfg);
-err_recover_alloc:
- kfree(aewb_cfg);
-
- return ret;
+ return omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
}
/*
@@ -362,7 +348,5 @@ err_recover_alloc:
*/
void omap3isp_h3a_aewb_cleanup(struct isp_device *isp)
{
- kfree(isp->isp_aewb.priv);
- kfree(isp->isp_aewb.recover_priv);
omap3isp_stat_cleanup(&isp->isp_aewb);
}
diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c
index 42ccce318d5d..a0bf5af32438 100644
--- a/drivers/media/platform/omap3isp/isph3a_af.c
+++ b/drivers/media/platform/omap3isp/isph3a_af.c
@@ -363,13 +363,11 @@ int omap3isp_h3a_af_init(struct isp_device *isp)
struct ispstat *af = &isp->isp_af;
struct omap3isp_h3a_af_config *af_cfg;
struct omap3isp_h3a_af_config *af_recover_cfg;
- int ret;
- af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL);
+ af_cfg = devm_kzalloc(isp->dev, sizeof(*af_cfg), GFP_KERNEL);
if (af_cfg == NULL)
return -ENOMEM;
- memset(af, 0, sizeof(*af));
af->ops = &h3a_af_ops;
af->priv = af_cfg;
af->dma_ch = -1;
@@ -377,12 +375,12 @@ int omap3isp_h3a_af_init(struct isp_device *isp)
af->isp = isp;
/* Set recover state configuration */
- af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL);
+ af_recover_cfg = devm_kzalloc(isp->dev, sizeof(*af_recover_cfg),
+ GFP_KERNEL);
if (!af_recover_cfg) {
dev_err(af->isp->dev, "AF: cannot allocate memory for recover "
"configuration.\n");
- ret = -ENOMEM;
- goto err_recover_alloc;
+ return -ENOMEM;
}
af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN;
@@ -394,30 +392,16 @@ int omap3isp_h3a_af_init(struct isp_device *isp)
if (h3a_af_validate_params(af, af_recover_cfg)) {
dev_err(af->isp->dev, "AF: recover configuration is "
"invalid.\n");
- ret = -EINVAL;
- goto err_conf;
+ return -EINVAL;
}
af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg);
af->recover_priv = af_recover_cfg;
- ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops);
- if (ret)
- goto err_conf;
-
- return 0;
-
-err_conf:
- kfree(af_recover_cfg);
-err_recover_alloc:
- kfree(af_cfg);
-
- return ret;
+ return omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops);
}
void omap3isp_h3a_af_cleanup(struct isp_device *isp)
{
- kfree(isp->isp_af.priv);
- kfree(isp->isp_af.recover_priv);
omap3isp_stat_cleanup(&isp->isp_af);
}
diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c
index 2d759c56f37c..e070c24048ef 100644
--- a/drivers/media/platform/omap3isp/isphist.c
+++ b/drivers/media/platform/omap3isp/isphist.c
@@ -114,14 +114,14 @@ static void hist_setup_regs(struct ispstat *hist, void *priv)
/* Regions size and position */
for (c = 0; c < OMAP3ISP_HIST_MAX_REGIONS; c++) {
if (c < conf->num_regions) {
- reg_hor[c] = conf->region[c].h_start <<
- ISPHIST_REG_START_SHIFT;
- reg_hor[c] = conf->region[c].h_end <<
- ISPHIST_REG_END_SHIFT;
- reg_ver[c] = conf->region[c].v_start <<
- ISPHIST_REG_START_SHIFT;
- reg_ver[c] = conf->region[c].v_end <<
- ISPHIST_REG_END_SHIFT;
+ reg_hor[c] = (conf->region[c].h_start <<
+ ISPHIST_REG_START_SHIFT)
+ | (conf->region[c].h_end <<
+ ISPHIST_REG_END_SHIFT);
+ reg_ver[c] = (conf->region[c].v_start <<
+ ISPHIST_REG_START_SHIFT)
+ | (conf->region[c].v_end <<
+ ISPHIST_REG_END_SHIFT);
} else {
reg_hor[c] = 0;
reg_ver[c] = 0;
@@ -477,11 +477,10 @@ int omap3isp_hist_init(struct isp_device *isp)
struct omap3isp_hist_config *hist_cfg;
int ret = -1;
- hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL);
+ hist_cfg = devm_kzalloc(isp->dev, sizeof(*hist_cfg), GFP_KERNEL);
if (hist_cfg == NULL)
return -ENOMEM;
- memset(hist, 0, sizeof(*hist));
hist->isp = isp;
if (HIST_CONFIG_DMA)
@@ -504,7 +503,6 @@ int omap3isp_hist_init(struct isp_device *isp)
ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops);
if (ret) {
- kfree(hist_cfg);
if (HIST_USING_DMA(hist))
omap_free_dma(hist->dma_ch);
}
@@ -519,6 +517,5 @@ void omap3isp_hist_cleanup(struct isp_device *isp)
{
if (HIST_USING_DMA(&isp->isp_hist))
omap_free_dma(isp->isp_hist.dma_ch);
- kfree(isp->isp_hist.priv);
omap3isp_stat_cleanup(&isp->isp_hist);
}
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 691b92a3c3e7..cd8831aebdeb 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -82,8 +82,9 @@ static struct omap3isp_prev_csc flr_prev_csc = {
* The preview engine crops several rows and columns internally depending on
* which filters are enabled. To avoid format changes when the filters are
* enabled or disabled (which would prevent them from being turned on or off
- * during streaming), the driver assumes all the filters are enabled when
- * computing sink crop and source format limits.
+ * during streaming), the driver assumes all filters that can be configured
+ * during streaming are enabled when computing sink crop and source format
+ * limits.
*
* If a filter is disabled, additional cropping is automatically added at the
* preview engine input by the driver to avoid overflow at line and frame end.
@@ -92,25 +93,23 @@ static struct omap3isp_prev_csc flr_prev_csc = {
* Median filter 4 pixels
* Noise filter,
* Faulty pixels correction 4 pixels, 4 lines
- * CFA filter 4 pixels, 4 lines in Bayer mode
- * 2 lines in other modes
* Color suppression 2 pixels
* or luma enhancement
* -------------------------------------------------------------
- * Maximum total 14 pixels, 8 lines
+ * Maximum total 10 pixels, 4 lines
*
* The color suppression and luma enhancement filters are applied after bayer to
* YUV conversion. They thus can crop one pixel on the left and one pixel on the
* right side of the image without changing the color pattern. When both those
* filters are disabled, the driver must crop the two pixels on the same side of
* the image to avoid changing the bayer pattern. The left margin is thus set to
- * 8 pixels and the right margin to 6 pixels.
+ * 6 pixels and the right margin to 4 pixels.
*/
-#define PREV_MARGIN_LEFT 8
-#define PREV_MARGIN_RIGHT 6
-#define PREV_MARGIN_TOP 4
-#define PREV_MARGIN_BOTTOM 4
+#define PREV_MARGIN_LEFT 6
+#define PREV_MARGIN_RIGHT 4
+#define PREV_MARGIN_TOP 2
+#define PREV_MARGIN_BOTTOM 2
#define PREV_MIN_IN_WIDTH 64
#define PREV_MIN_IN_HEIGHT 8
@@ -1080,7 +1079,6 @@ static void preview_config_input_format(struct isp_prev_device *prev,
*/
static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
{
- const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
struct isp_device *isp = to_isp_device(prev);
unsigned int sph = prev->crop.left;
unsigned int eph = prev->crop.left + prev->crop.width - 1;
@@ -1088,14 +1086,6 @@ static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
unsigned int elv = prev->crop.top + prev->crop.height - 1;
u32 features;
- if (format->code != V4L2_MBUS_FMT_Y8_1X8 &&
- format->code != V4L2_MBUS_FMT_Y10_1X10) {
- sph -= 2;
- eph += 2;
- slv -= 2;
- elv += 2;
- }
-
features = (prev->params.params[0].features & active)
| (prev->params.params[1].features & ~active);
@@ -1849,6 +1839,18 @@ static void preview_try_crop(struct isp_prev_device *prev,
right -= 2;
}
+ /* The CFA filter crops 4 lines and 4 columns in Bayer mode, and 2 lines
+ * and no columns in other modes. Increase the margins based on the sink
+ * format.
+ */
+ if (sink->code != V4L2_MBUS_FMT_Y8_1X8 &&
+ sink->code != V4L2_MBUS_FMT_Y10_1X10) {
+ left += 2;
+ right -= 2;
+ top += 2;
+ bottom -= 2;
+ }
+
/* Restrict left/top to even values to keep the Bayer pattern. */
crop->left &= ~1;
crop->top &= ~1;
diff --git a/drivers/media/platform/omap3isp/ispqueue.c b/drivers/media/platform/omap3isp/ispqueue.c
index 15bf3eab2224..e15f01342058 100644
--- a/drivers/media/platform/omap3isp/ispqueue.c
+++ b/drivers/media/platform/omap3isp/ispqueue.c
@@ -366,7 +366,7 @@ static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf)
unsigned long this_pfn;
unsigned long start;
unsigned long end;
- dma_addr_t pa;
+ dma_addr_t pa = 0;
int ret = -EFAULT;
start = buf->vbuf.m.userptr;
@@ -419,7 +419,7 @@ done:
static int isp_video_buffer_prepare_vm_flags(struct isp_video_buffer *buf)
{
struct vm_area_struct *vma;
- pgprot_t vm_page_prot;
+ pgprot_t uninitialized_var(vm_page_prot);
unsigned long start;
unsigned long end;
int ret = -EFAULT;
@@ -674,6 +674,7 @@ static int isp_video_queue_alloc(struct isp_video_queue *queue,
buf->vbuf.index = i;
buf->vbuf.length = size;
buf->vbuf.type = queue->type;
+ buf->vbuf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
buf->vbuf.field = V4L2_FIELD_NONE;
buf->vbuf.memory = memory;
diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c
index e2716c35f8f1..0d0fab1a7b5e 100644
--- a/drivers/media/platform/s3c-camif/camif-core.c
+++ b/drivers/media/platform/s3c-camif/camif-core.c
@@ -27,6 +27,7 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/version.h>
#include <media/media-device.h>
#include <media/v4l2-ctrls.h>
@@ -433,11 +434,9 @@ static int s3c_camif_probe(struct platform_device *pdev)
mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- camif->io_base = devm_request_and_ioremap(dev, mres);
- if (!camif->io_base) {
- dev_err(dev, "failed to obtain I/O memory\n");
- return -ENOENT;
- }
+ camif->io_base = devm_ioremap_resource(dev, mres);
+ if (IS_ERR(camif->io_base))
+ return PTR_ERR(camif->io_base);
ret = camif_request_irqs(pdev, camif);
if (ret < 0)
diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig
index c16b20d86ed2..f997a5203b7c 100644
--- a/drivers/media/platform/s5p-fimc/Kconfig
+++ b/drivers/media/platform/s5p-fimc/Kconfig
@@ -2,7 +2,6 @@
config VIDEO_SAMSUNG_S5P_FIMC
bool "Samsung S5P/EXYNOS SoC camera interface driver (experimental)"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME
- depends on EXPERIMENTAL
help
Say Y here to enable camera host interface devices for
Samsung S5P and EXYNOS SoC series.
diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c
index fdb6740248a7..f553cc2a8ee8 100644
--- a/drivers/media/platform/s5p-fimc/fimc-capture.c
+++ b/drivers/media/platform/s5p-fimc/fimc-capture.c
@@ -486,6 +486,7 @@ static struct vb2_ops fimc_capture_qops = {
int fimc_capture_ctrls_create(struct fimc_dev *fimc)
{
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR];
int ret;
if (WARN_ON(vid_cap->ctx == NULL))
@@ -494,11 +495,13 @@ int fimc_capture_ctrls_create(struct fimc_dev *fimc)
return 0;
ret = fimc_ctrls_create(vid_cap->ctx);
- if (ret || vid_cap->user_subdev_api || !vid_cap->ctx->ctrls.ready)
+
+ if (ret || vid_cap->user_subdev_api || !sensor ||
+ !vid_cap->ctx->ctrls.ready)
return ret;
return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrls.handler,
- fimc->pipeline.subdevs[IDX_SENSOR]->ctrl_handler, NULL);
+ sensor->ctrl_handler, NULL);
}
static int fimc_capture_set_default_format(struct fimc_dev *fimc);
@@ -510,8 +513,8 @@ static int fimc_capture_open(struct file *file)
dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
- if (mutex_lock_interruptible(&fimc->lock))
- return -ERESTARTSYS;
+ fimc_md_graph_lock(fimc);
+ mutex_lock(&fimc->lock);
if (fimc_m2m_active(fimc))
goto unlock;
@@ -546,6 +549,7 @@ static int fimc_capture_open(struct file *file)
}
unlock:
mutex_unlock(&fimc->lock);
+ fimc_md_graph_unlock(fimc);
return ret;
}
@@ -626,8 +630,8 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
{
bool rotation = ctx->rotation == 90 || ctx->rotation == 270;
struct fimc_dev *fimc = ctx->fimc_dev;
- struct fimc_variant *var = fimc->variant;
- struct fimc_pix_limit *pl = var->pix_limit;
+ const struct fimc_variant *var = fimc->variant;
+ const struct fimc_pix_limit *pl = var->pix_limit;
struct fimc_frame *dst = &ctx->d_frame;
u32 depth, min_w, max_w, min_h, align_h = 3;
u32 mask = FMT_FLAGS_CAM;
@@ -699,8 +703,8 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx,
{
bool rotate = ctx->rotation == 90 || ctx->rotation == 270;
struct fimc_dev *fimc = ctx->fimc_dev;
- struct fimc_variant *var = fimc->variant;
- struct fimc_pix_limit *pl = var->pix_limit;
+ const struct fimc_variant *var = fimc->variant;
+ const struct fimc_pix_limit *pl = var->pix_limit;
struct fimc_frame *sink = &ctx->s_frame;
u32 max_w, max_h, min_w = 0, min_h = 0, min_sz;
u32 align_sz = 0, align_h = 4;
@@ -793,6 +797,21 @@ static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv,
return 0;
}
+static struct media_entity *fimc_pipeline_get_head(struct media_entity *me)
+{
+ struct media_pad *pad = &me->pads[0];
+
+ while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) {
+ pad = media_entity_remote_source(pad);
+ if (!pad)
+ break;
+ me = pad->entity;
+ pad = &me->pads[0];
+ }
+
+ return me;
+}
+
/**
* fimc_pipeline_try_format - negotiate and/or set formats at pipeline
* elements
@@ -808,19 +827,23 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
{
struct fimc_dev *fimc = ctx->fimc_dev;
struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
- struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS];
struct v4l2_subdev_format sfmt;
struct v4l2_mbus_framefmt *mf = &sfmt.format;
- struct fimc_fmt *ffmt = NULL;
- int ret, i = 0;
+ struct media_entity *me;
+ struct fimc_fmt *ffmt;
+ struct media_pad *pad;
+ int ret, i = 1;
+ u32 fcc;
if (WARN_ON(!sd || !tfmt))
return -EINVAL;
memset(&sfmt, 0, sizeof(sfmt));
sfmt.format = *tfmt;
-
sfmt.which = set ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY;
+
+ me = fimc_pipeline_get_head(&sd->entity);
+
while (1) {
ffmt = fimc_find_format(NULL, mf->code != 0 ? &mf->code : NULL,
FMT_FLAGS_CAM, i++);
@@ -833,40 +856,52 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
}
mf->code = tfmt->code = ffmt->mbus_code;
- ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sfmt);
- if (ret)
- return ret;
- if (mf->code != tfmt->code) {
- mf->code = 0;
- continue;
+ /* set format on all pipeline subdevs */
+ while (me != &fimc->vid_cap.subdev.entity) {
+ sd = media_entity_to_v4l2_subdev(me);
+
+ sfmt.pad = 0;
+ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sfmt);
+ if (ret)
+ return ret;
+
+ if (me->pads[0].flags & MEDIA_PAD_FL_SINK) {
+ sfmt.pad = me->num_pads - 1;
+ mf->code = tfmt->code;
+ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL,
+ &sfmt);
+ if (ret)
+ return ret;
+ }
+
+ pad = media_entity_remote_source(&me->pads[sfmt.pad]);
+ if (!pad)
+ return -EINVAL;
+ me = pad->entity;
}
- if (mf->width != tfmt->width || mf->height != tfmt->height) {
- u32 fcc = ffmt->fourcc;
- tfmt->width = mf->width;
- tfmt->height = mf->height;
- ffmt = fimc_capture_try_format(ctx,
- &tfmt->width, &tfmt->height,
- NULL, &fcc, FIMC_SD_PAD_SOURCE);
- if (ffmt && ffmt->mbus_code)
- mf->code = ffmt->mbus_code;
- if (mf->width != tfmt->width ||
- mf->height != tfmt->height)
- continue;
- tfmt->code = mf->code;
- }
- if (csis)
- ret = v4l2_subdev_call(csis, pad, set_fmt, NULL, &sfmt);
- if (mf->code == tfmt->code &&
- mf->width == tfmt->width && mf->height == tfmt->height)
- break;
+ if (mf->code != tfmt->code)
+ continue;
+
+ fcc = ffmt->fourcc;
+ tfmt->width = mf->width;
+ tfmt->height = mf->height;
+ ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height,
+ NULL, &fcc, FIMC_SD_PAD_SINK);
+ ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height,
+ NULL, &fcc, FIMC_SD_PAD_SOURCE);
+ if (ffmt && ffmt->mbus_code)
+ mf->code = ffmt->mbus_code;
+ if (mf->width != tfmt->width || mf->height != tfmt->height)
+ continue;
+ tfmt->code = mf->code;
+ break;
}
if (fmt_id && ffmt)
*fmt_id = ffmt;
*tfmt = *mf;
- dbg("code: 0x%x, %dx%d, %p", mf->code, mf->width, mf->height, ffmt);
return 0;
}
@@ -884,14 +919,16 @@ static int fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor,
{
struct v4l2_mbus_frame_desc fd;
int i, ret;
+ int pad;
for (i = 0; i < num_planes; i++)
fd.entry[i].length = plane_fmt[i].sizeimage;
+ pad = sensor->entity.num_pads - 1;
if (try)
- ret = v4l2_subdev_call(sensor, pad, set_frame_desc, 0, &fd);
+ ret = v4l2_subdev_call(sensor, pad, set_frame_desc, pad, &fd);
else
- ret = v4l2_subdev_call(sensor, pad, get_frame_desc, 0, &fd);
+ ret = v4l2_subdev_call(sensor, pad, get_frame_desc, pad, &fd);
if (ret < 0)
return ret;
@@ -916,9 +953,9 @@ static int fimc_cap_g_fmt_mplane(struct file *file, void *fh,
struct v4l2_format *f)
{
struct fimc_dev *fimc = video_drvdata(file);
- struct fimc_ctx *ctx = fimc->vid_cap.ctx;
- return fimc_fill_format(&ctx->d_frame, f);
+ __fimc_get_format(&fimc->vid_cap.ctx->d_frame, f);
+ return 0;
}
static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
@@ -929,6 +966,10 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
struct v4l2_mbus_framefmt mf;
struct fimc_fmt *ffmt = NULL;
+ int ret = 0;
+
+ fimc_md_graph_lock(fimc);
+ mutex_lock(&fimc->lock);
if (fimc_jpeg_fourcc(pix->pixelformat)) {
fimc_capture_try_format(ctx, &pix->width, &pix->height,
@@ -940,16 +981,16 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
NULL, &pix->pixelformat,
FIMC_SD_PAD_SOURCE);
- if (!ffmt)
- return -EINVAL;
+ if (!ffmt) {
+ ret = -EINVAL;
+ goto unlock;
+ }
if (!fimc->vid_cap.user_subdev_api) {
mf.width = pix->width;
mf.height = pix->height;
mf.code = ffmt->mbus_code;
- fimc_md_graph_lock(fimc);
fimc_pipeline_try_format(ctx, &mf, &ffmt, false);
- fimc_md_graph_unlock(fimc);
pix->width = mf.width;
pix->height = mf.height;
if (ffmt)
@@ -961,8 +1002,11 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
if (ffmt->flags & FMT_FLAGS_COMPRESSED)
fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR],
pix->plane_fmt, ffmt->memplanes, true);
+unlock:
+ mutex_unlock(&fimc->lock);
+ fimc_md_graph_unlock(fimc);
- return 0;
+ return ret;
}
static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx,
@@ -979,7 +1023,8 @@ static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx,
clear_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state);
}
-static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
+static int __fimc_capture_set_format(struct fimc_dev *fimc,
+ struct v4l2_format *f)
{
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
@@ -1014,12 +1059,10 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
mf->code = ff->fmt->mbus_code;
mf->width = pix->width;
mf->height = pix->height;
-
- fimc_md_graph_lock(fimc);
ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true);
- fimc_md_graph_unlock(fimc);
if (ret)
return ret;
+
pix->width = mf->width;
pix->height = mf->height;
}
@@ -1034,8 +1077,10 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
return ret;
}
- for (i = 0; i < ff->fmt->memplanes; i++)
+ for (i = 0; i < ff->fmt->memplanes; i++) {
+ ff->bytesperline[i] = pix->plane_fmt[i].bytesperline;
ff->payload[i] = pix->plane_fmt[i].sizeimage;
+ }
set_frame_bounds(ff, pix->width, pix->height);
/* Reset the composition rectangle if not yet configured */
@@ -1058,8 +1103,23 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
struct v4l2_format *f)
{
struct fimc_dev *fimc = video_drvdata(file);
+ int ret;
+
+ fimc_md_graph_lock(fimc);
+ mutex_lock(&fimc->lock);
+ /*
+ * The graph is walked within __fimc_capture_set_format() to set
+ * the format at subdevs thus the graph mutex needs to be held at
+ * this point and acquired before the video mutex, to avoid AB-BA
+ * deadlock when fimc_md_link_notify() is called by other thread.
+ * Ideally the graph walking and setting format at the whole pipeline
+ * should be removed from this driver and handled in userspace only.
+ */
+ ret = __fimc_capture_set_format(fimc, f);
- return fimc_capture_set_format(fimc, f);
+ mutex_unlock(&fimc->lock);
+ fimc_md_graph_unlock(fimc);
+ return ret;
}
static int fimc_cap_enum_input(struct file *file, void *priv,
@@ -1528,6 +1588,10 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
*mf = fmt->format;
return 0;
}
+ /* There must be a bug in the driver if this happens */
+ if (WARN_ON(ffmt == NULL))
+ return -EINVAL;
+
/* Update RGB Alpha control state and value range */
fimc_alpha_ctrl_update(ctx);
@@ -1624,16 +1688,6 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP);
switch (sel->target) {
- case V4L2_SEL_TGT_COMPOSE_BOUNDS:
- f = &ctx->d_frame;
- case V4L2_SEL_TGT_CROP_BOUNDS:
- r->width = f->o_width;
- r->height = f->o_height;
- r->left = 0;
- r->top = 0;
- mutex_unlock(&fimc->lock);
- return 0;
-
case V4L2_SEL_TGT_CROP:
try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
break;
@@ -1652,9 +1706,9 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
spin_lock_irqsave(&fimc->slock, flags);
set_frame_crop(f, r->left, r->top, r->width, r->height);
set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
- spin_unlock_irqrestore(&fimc->slock, flags);
if (sel->target == V4L2_SEL_TGT_COMPOSE)
ctx->state |= FIMC_COMPOSE;
+ spin_unlock_irqrestore(&fimc->slock, flags);
}
dbg("target %#x: (%d,%d)/%dx%d", sel->target, r->left, r->top,
@@ -1690,7 +1744,7 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc)
},
};
- return fimc_capture_set_format(fimc, &fmt);
+ return __fimc_capture_set_format(fimc, &fmt);
}
/* fimc->lock must be already initialized */
@@ -1752,6 +1806,12 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0);
if (ret)
goto err_ent;
+ /*
+ * For proper order of acquiring/releasing the video
+ * and the graph mutex.
+ */
+ v4l2_disable_ioctl_locking(vfd, VIDIOC_TRY_FMT);
+ v4l2_disable_ioctl_locking(vfd, VIDIOC_S_FMT);
ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret)
diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c
index 545b46ae12a1..e3916bde45cf 100644
--- a/drivers/media/platform/s5p-fimc/fimc-core.c
+++ b/drivers/media/platform/s5p-fimc/fimc-core.c
@@ -241,7 +241,7 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
int fimc_set_scaler_info(struct fimc_ctx *ctx)
{
- struct fimc_variant *variant = ctx->fimc_dev->variant;
+ const struct fimc_variant *variant = ctx->fimc_dev->variant;
struct device *dev = &ctx->fimc_dev->pdev->dev;
struct fimc_scaler *sc = &ctx->scaler;
struct fimc_frame *s_frame = &ctx->s_frame;
@@ -257,14 +257,14 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx)
ty = d_frame->height;
}
if (tx <= 0 || ty <= 0) {
- dev_err(dev, "Invalid target size: %dx%d", tx, ty);
+ dev_err(dev, "Invalid target size: %dx%d\n", tx, ty);
return -EINVAL;
}
sx = s_frame->width;
sy = s_frame->height;
if (sx <= 0 || sy <= 0) {
- dev_err(dev, "Invalid source size: %dx%d", sx, sy);
+ dev_err(dev, "Invalid source size: %dx%d\n", sx, sy);
return -EINVAL;
}
sc->real_width = sx;
@@ -440,7 +440,7 @@ void fimc_set_yuv_order(struct fimc_ctx *ctx)
void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
{
- struct fimc_variant *variant = ctx->fimc_dev->variant;
+ const struct fimc_variant *variant = ctx->fimc_dev->variant;
u32 i, depth = 0;
for (i = 0; i < f->fmt->colplanes; i++)
@@ -524,8 +524,7 @@ static int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx
static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
{
struct fimc_dev *fimc = ctx->fimc_dev;
- struct fimc_variant *variant = fimc->variant;
- unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT;
+ const struct fimc_variant *variant = fimc->variant;
int ret = 0;
if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
@@ -541,8 +540,7 @@ static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_ROTATE:
- if (fimc_capture_pending(fimc) ||
- (ctx->state & flags) == flags) {
+ if (fimc_capture_pending(fimc)) {
ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
ctx->s_frame.height, ctx->d_frame.width,
ctx->d_frame.height, ctrl->val);
@@ -591,7 +589,7 @@ static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
int fimc_ctrls_create(struct fimc_ctx *ctx)
{
- struct fimc_variant *variant = ctx->fimc_dev->variant;
+ const struct fimc_variant *variant = ctx->fimc_dev->variant;
unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
struct fimc_ctrls *ctrls = &ctx->ctrls;
struct v4l2_ctrl_handler *handler = &ctrls->handler;
@@ -691,7 +689,7 @@ void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
v4l2_ctrl_unlock(ctrl);
}
-int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f)
+void __fimc_get_format(struct fimc_frame *frame, struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
int i;
@@ -704,35 +702,9 @@ int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f)
pixm->num_planes = frame->fmt->memplanes;
for (i = 0; i < pixm->num_planes; ++i) {
- int bpl = frame->f_width;
- if (frame->fmt->colplanes == 1) /* packed formats */
- bpl = (bpl * frame->fmt->depth[0]) / 8;
- pixm->plane_fmt[i].bytesperline = bpl;
-
- if (frame->fmt->flags & FMT_FLAGS_COMPRESSED) {
- pixm->plane_fmt[i].sizeimage = frame->payload[i];
- continue;
- }
- pixm->plane_fmt[i].sizeimage = (frame->o_width *
- frame->o_height * frame->fmt->depth[i]) / 8;
+ pixm->plane_fmt[i].bytesperline = frame->bytesperline[i];
+ pixm->plane_fmt[i].sizeimage = frame->payload[i];
}
- return 0;
-}
-
-void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f)
-{
- struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
-
- frame->f_width = pixm->plane_fmt[0].bytesperline;
- if (frame->fmt->colplanes == 1)
- frame->f_width = (frame->f_width * 8) / frame->fmt->depth[0];
- frame->f_height = pixm->height;
- frame->width = pixm->width;
- frame->height = pixm->height;
- frame->o_width = pixm->width;
- frame->o_height = pixm->height;
- frame->offs_h = 0;
- frame->offs_v = 0;
}
/**
@@ -765,9 +737,16 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
if (fmt->colplanes == 1 && /* Packed */
(bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
bpl = (pix->width * fmt->depth[0]) / 8;
-
- if (i == 0) /* Same bytesperline for each plane. */
+ /*
+ * Currently bytesperline for each plane is same, except
+ * V4L2_PIX_FMT_YUV420M format. This calculation may need
+ * to be changed when other multi-planar formats are added
+ * to the fimc_formats[] array.
+ */
+ if (i == 0)
bytesperline = bpl;
+ else if (i == 1 && fmt->memplanes == 3)
+ bytesperline /= 2;
plane_fmt->bytesperline = bytesperline;
plane_fmt->sizeimage = max((pix->width * pix->height *
@@ -811,11 +790,11 @@ static void fimc_clk_put(struct fimc_dev *fimc)
{
int i;
for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
- if (IS_ERR_OR_NULL(fimc->clock[i]))
+ if (IS_ERR(fimc->clock[i]))
continue;
clk_unprepare(fimc->clock[i]);
clk_put(fimc->clock[i]);
- fimc->clock[i] = NULL;
+ fimc->clock[i] = ERR_PTR(-EINVAL);
}
}
@@ -823,14 +802,19 @@ static int fimc_clk_get(struct fimc_dev *fimc)
{
int i, ret;
+ for (i = 0; i < MAX_FIMC_CLOCKS; i++)
+ fimc->clock[i] = ERR_PTR(-EINVAL);
+
for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
- if (IS_ERR(fimc->clock[i]))
+ if (IS_ERR(fimc->clock[i])) {
+ ret = PTR_ERR(fimc->clock[i]);
goto err;
+ }
ret = clk_prepare(fimc->clock[i]);
if (ret < 0) {
clk_put(fimc->clock[i]);
- fimc->clock[i] = NULL;
+ fimc->clock[i] = ERR_PTR(-EINVAL);
goto err;
}
}
@@ -881,7 +865,7 @@ static int fimc_m2m_resume(struct fimc_dev *fimc)
static int fimc_probe(struct platform_device *pdev)
{
- struct fimc_drvdata *drv_data = fimc_get_drvdata(pdev);
+ const struct fimc_drvdata *drv_data = fimc_get_drvdata(pdev);
struct s5p_platform_fimc *pdata;
struct fimc_dev *fimc;
struct resource *res;
@@ -909,11 +893,9 @@ static int fimc_probe(struct platform_device *pdev)
mutex_init(&fimc->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (fimc->regs == NULL) {
- dev_err(&pdev->dev, "Failed to obtain io memory\n");
- return -ENOENT;
- }
+ fimc->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(fimc->regs))
+ return PTR_ERR(fimc->regs);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
@@ -924,8 +906,14 @@ static int fimc_probe(struct platform_device *pdev)
ret = fimc_clk_get(fimc);
if (ret)
return ret;
- clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
- clk_enable(fimc->clock[CLK_BUS]);
+
+ ret = clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(fimc->clock[CLK_BUS]);
+ if (ret < 0)
+ return ret;
ret = devm_request_irq(&pdev->dev, res->start, fimc_irq_handler,
0, dev_name(&pdev->dev), fimc);
@@ -959,6 +947,7 @@ err_pm:
err_sd:
fimc_unregister_capture_subdev(fimc);
err_clk:
+ clk_disable(fimc->clock[CLK_BUS]);
fimc_clk_put(fimc);
return ret;
}
@@ -1053,7 +1042,7 @@ static int fimc_remove(struct platform_device *pdev)
}
/* Image pixel limits, similar across several FIMC HW revisions. */
-static struct fimc_pix_limit s5p_pix_limit[4] = {
+static const struct fimc_pix_limit s5p_pix_limit[4] = {
[0] = {
.scaler_en_w = 3264,
.scaler_dis_w = 8192,
@@ -1088,7 +1077,7 @@ static struct fimc_pix_limit s5p_pix_limit[4] = {
},
};
-static struct fimc_variant fimc0_variant_s5p = {
+static const struct fimc_variant fimc0_variant_s5p = {
.has_inp_rot = 1,
.has_out_rot = 1,
.has_cam_if = 1,
@@ -1100,7 +1089,7 @@ static struct fimc_variant fimc0_variant_s5p = {
.pix_limit = &s5p_pix_limit[0],
};
-static struct fimc_variant fimc2_variant_s5p = {
+static const struct fimc_variant fimc2_variant_s5p = {
.has_cam_if = 1,
.min_inp_pixsize = 16,
.min_out_pixsize = 16,
@@ -1110,7 +1099,7 @@ static struct fimc_variant fimc2_variant_s5p = {
.pix_limit = &s5p_pix_limit[1],
};
-static struct fimc_variant fimc0_variant_s5pv210 = {
+static const struct fimc_variant fimc0_variant_s5pv210 = {
.pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
@@ -1123,7 +1112,7 @@ static struct fimc_variant fimc0_variant_s5pv210 = {
.pix_limit = &s5p_pix_limit[1],
};
-static struct fimc_variant fimc1_variant_s5pv210 = {
+static const struct fimc_variant fimc1_variant_s5pv210 = {
.pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
@@ -1137,7 +1126,7 @@ static struct fimc_variant fimc1_variant_s5pv210 = {
.pix_limit = &s5p_pix_limit[2],
};
-static struct fimc_variant fimc2_variant_s5pv210 = {
+static const struct fimc_variant fimc2_variant_s5pv210 = {
.has_cam_if = 1,
.pix_hoff = 1,
.min_inp_pixsize = 16,
@@ -1148,7 +1137,7 @@ static struct fimc_variant fimc2_variant_s5pv210 = {
.pix_limit = &s5p_pix_limit[2],
};
-static struct fimc_variant fimc0_variant_exynos4 = {
+static const struct fimc_variant fimc0_variant_exynos4210 = {
.pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
@@ -1164,9 +1153,8 @@ static struct fimc_variant fimc0_variant_exynos4 = {
.pix_limit = &s5p_pix_limit[1],
};
-static struct fimc_variant fimc3_variant_exynos4 = {
+static const struct fimc_variant fimc3_variant_exynos4210 = {
.pix_hoff = 1,
- .has_cam_if = 1,
.has_cistatus2 = 1,
.has_mainscaler_ext = 1,
.has_alpha = 1,
@@ -1178,8 +1166,38 @@ static struct fimc_variant fimc3_variant_exynos4 = {
.pix_limit = &s5p_pix_limit[3],
};
+static const struct fimc_variant fimc0_variant_exynos4x12 = {
+ .pix_hoff = 1,
+ .has_inp_rot = 1,
+ .has_out_rot = 1,
+ .has_cam_if = 1,
+ .has_isp_wb = 1,
+ .has_cistatus2 = 1,
+ .has_mainscaler_ext = 1,
+ .has_alpha = 1,
+ .min_inp_pixsize = 16,
+ .min_out_pixsize = 16,
+ .hor_offs_align = 2,
+ .min_vsize_align = 1,
+ .out_buf_count = 32,
+ .pix_limit = &s5p_pix_limit[1],
+};
+
+static const struct fimc_variant fimc3_variant_exynos4x12 = {
+ .pix_hoff = 1,
+ .has_cistatus2 = 1,
+ .has_mainscaler_ext = 1,
+ .has_alpha = 1,
+ .min_inp_pixsize = 16,
+ .min_out_pixsize = 16,
+ .hor_offs_align = 2,
+ .min_vsize_align = 1,
+ .out_buf_count = 32,
+ .pix_limit = &s5p_pix_limit[3],
+};
+
/* S5PC100 */
-static struct fimc_drvdata fimc_drvdata_s5p = {
+static const struct fimc_drvdata fimc_drvdata_s5p = {
.variant = {
[0] = &fimc0_variant_s5p,
[1] = &fimc0_variant_s5p,
@@ -1190,7 +1208,7 @@ static struct fimc_drvdata fimc_drvdata_s5p = {
};
/* S5PV210, S5PC110 */
-static struct fimc_drvdata fimc_drvdata_s5pv210 = {
+static const struct fimc_drvdata fimc_drvdata_s5pv210 = {
.variant = {
[0] = &fimc0_variant_s5pv210,
[1] = &fimc1_variant_s5pv210,
@@ -1201,18 +1219,30 @@ static struct fimc_drvdata fimc_drvdata_s5pv210 = {
};
/* EXYNOS4210, S5PV310, S5PC210 */
-static struct fimc_drvdata fimc_drvdata_exynos4 = {
+static const struct fimc_drvdata fimc_drvdata_exynos4210 = {
+ .variant = {
+ [0] = &fimc0_variant_exynos4210,
+ [1] = &fimc0_variant_exynos4210,
+ [2] = &fimc0_variant_exynos4210,
+ [3] = &fimc3_variant_exynos4210,
+ },
+ .num_entities = 4,
+ .lclk_frequency = 166000000UL,
+};
+
+/* EXYNOS4212, EXYNOS4412 */
+static const struct fimc_drvdata fimc_drvdata_exynos4x12 = {
.variant = {
- [0] = &fimc0_variant_exynos4,
- [1] = &fimc0_variant_exynos4,
- [2] = &fimc0_variant_exynos4,
- [3] = &fimc3_variant_exynos4,
+ [0] = &fimc0_variant_exynos4x12,
+ [1] = &fimc0_variant_exynos4x12,
+ [2] = &fimc0_variant_exynos4x12,
+ [3] = &fimc3_variant_exynos4x12,
},
.num_entities = 4,
.lclk_frequency = 166000000UL,
};
-static struct platform_device_id fimc_driver_ids[] = {
+static const struct platform_device_id fimc_driver_ids[] = {
{
.name = "s5p-fimc",
.driver_data = (unsigned long)&fimc_drvdata_s5p,
@@ -1221,7 +1251,10 @@ static struct platform_device_id fimc_driver_ids[] = {
.driver_data = (unsigned long)&fimc_drvdata_s5pv210,
}, {
.name = "exynos4-fimc",
- .driver_data = (unsigned long)&fimc_drvdata_exynos4,
+ .driver_data = (unsigned long)&fimc_drvdata_exynos4210,
+ }, {
+ .name = "exynos4x12-fimc",
+ .driver_data = (unsigned long)&fimc_drvdata_exynos4x12,
},
{},
};
diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h
index c0040d792499..412d50708f75 100644
--- a/drivers/media/platform/s5p-fimc/fimc-core.h
+++ b/drivers/media/platform/s5p-fimc/fimc-core.h
@@ -112,9 +112,7 @@ enum fimc_color_fmt {
/* The hardware context state. */
#define FIMC_PARAMS (1 << 0)
-#define FIMC_SRC_FMT (1 << 3)
-#define FIMC_DST_FMT (1 << 4)
-#define FIMC_COMPOSE (1 << 5)
+#define FIMC_COMPOSE (1 << 1)
#define FIMC_CTX_M2M (1 << 16)
#define FIMC_CTX_CAP (1 << 17)
#define FIMC_CTX_SHUT (1 << 18)
@@ -265,6 +263,7 @@ struct fimc_vid_buffer {
* @width: image pixel width
* @height: image pixel weight
* @payload: image size in bytes (w x h x bpp)
+ * @bytesperline: bytesperline value for each plane
* @paddr: image frame buffer physical addresses
* @dma_offset: DMA offset in bytes
* @fmt: fimc color format pointer
@@ -279,6 +278,7 @@ struct fimc_frame {
u32 width;
u32 height;
unsigned int payload[VIDEO_MAX_PLANES];
+ unsigned int bytesperline[VIDEO_MAX_PLANES];
struct fimc_addr paddr;
struct fimc_dma_offset dma_offset;
struct fimc_fmt *fmt;
@@ -372,6 +372,7 @@ struct fimc_pix_limit {
* @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register
* are present in this IP revision
* @has_cam_if: set if this instance has a camera input interface
+ * @has_isp_wb: set if this instance has ISP writeback input
* @pix_limit: pixel size constraints for the scaler
* @min_inp_pixsize: minimum input pixel size
* @min_out_pixsize: minimum output pixel size
@@ -386,8 +387,9 @@ struct fimc_variant {
unsigned int has_cistatus2:1;
unsigned int has_mainscaler_ext:1;
unsigned int has_cam_if:1;
+ unsigned int has_isp_wb:1;
unsigned int has_alpha:1;
- struct fimc_pix_limit *pix_limit;
+ const struct fimc_pix_limit *pix_limit;
u16 min_inp_pixsize;
u16 min_out_pixsize;
u16 hor_offs_align;
@@ -402,7 +404,7 @@ struct fimc_variant {
* @lclk_frequency: local bus clock frequency
*/
struct fimc_drvdata {
- struct fimc_variant *variant[FIMC_MAX_DEVS];
+ const struct fimc_variant *variant[FIMC_MAX_DEVS];
int num_entities;
unsigned long lclk_frequency;
};
@@ -435,7 +437,7 @@ struct fimc_dev {
struct mutex lock;
struct platform_device *pdev;
struct s5p_platform_fimc *pdata;
- struct fimc_variant *variant;
+ const struct fimc_variant *variant;
u16 id;
struct clk *clock[MAX_FIMC_CLOCKS];
void __iomem *regs;
@@ -635,7 +637,7 @@ int fimc_ctrls_create(struct fimc_ctx *ctx);
void fimc_ctrls_delete(struct fimc_ctx *ctx);
void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
void fimc_alpha_ctrl_update(struct fimc_ctx *ctx);
-int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f);
+void __fimc_get_format(struct fimc_frame *frame, struct v4l2_format *f);
void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
struct v4l2_pix_format_mplane *pix);
struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code,
@@ -650,7 +652,6 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
struct fimc_frame *frame, struct fimc_addr *paddr);
void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f);
void fimc_set_yuv_order(struct fimc_ctx *ctx);
-void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f);
void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf);
int fimc_register_m2m_device(struct fimc_dev *fimc,
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c
index a22d7eb05c82..f0af0754a7b4 100644
--- a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c
+++ b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c
@@ -65,7 +65,7 @@ void flite_hw_set_interrupt_mask(struct fimc_lite *dev)
u32 cfg, intsrc;
/* Select interrupts to be enabled for each output mode */
- if (dev->out_path == FIMC_IO_DMA) {
+ if (atomic_read(&dev->out_path) == FIMC_IO_DMA) {
intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
FLITE_REG_CIGCTRL_IRQ_LASTEN |
FLITE_REG_CIGCTRL_IRQ_STARTEN;
@@ -187,12 +187,12 @@ static void flite_hw_set_camera_port(struct fimc_lite *dev, int id)
/* Select serial or parallel bus, camera port (A,B) and set signals polarity */
void flite_hw_set_camera_bus(struct fimc_lite *dev,
- struct s5p_fimc_isp_info *s_info)
+ struct fimc_source_info *si)
{
u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
- unsigned int flags = s_info->flags;
+ unsigned int flags = si->flags;
- if (s_info->bus_type != FIMC_MIPI_CSI2) {
+ if (si->sensor_bus_type != FIMC_BUS_TYPE_MIPI_CSI2) {
cfg &= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI |
FLITE_REG_CIGCTRL_INVPOLPCLK |
FLITE_REG_CIGCTRL_INVPOLVSYNC |
@@ -212,7 +212,7 @@ void flite_hw_set_camera_bus(struct fimc_lite *dev,
writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
- flite_hw_set_camera_port(dev, s_info->mux_id);
+ flite_hw_set_camera_port(dev, si->mux_id);
}
static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
@@ -292,9 +292,11 @@ void flite_hw_dump_regs(struct fimc_lite *dev, const char *label)
};
u32 i;
- pr_info("--- %s ---\n", label);
+ v4l2_info(&dev->subdev, "--- %s ---\n", label);
+
for (i = 0; i < ARRAY_SIZE(registers); i++) {
u32 cfg = readl(dev->regs + registers[i].offset);
- pr_info("%s: %s:\t0x%08x\n", __func__, registers[i].name, cfg);
+ v4l2_info(&dev->subdev, "%9s: 0x%08x\n",
+ registers[i].name, cfg);
}
}
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.h b/drivers/media/platform/s5p-fimc/fimc-lite-reg.h
index adb9e9e6f3c2..0e345844c13a 100644
--- a/drivers/media/platform/s5p-fimc/fimc-lite-reg.h
+++ b/drivers/media/platform/s5p-fimc/fimc-lite-reg.h
@@ -131,9 +131,9 @@ void flite_hw_set_interrupt_mask(struct fimc_lite *dev);
void flite_hw_capture_start(struct fimc_lite *dev);
void flite_hw_capture_stop(struct fimc_lite *dev);
void flite_hw_set_camera_bus(struct fimc_lite *dev,
- struct s5p_fimc_isp_info *s_info);
+ struct fimc_source_info *s_info);
void flite_hw_set_camera_polarity(struct fimc_lite *dev,
- struct s5p_fimc_isp_info *cam);
+ struct fimc_source_info *cam);
void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f);
void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f);
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c
index ed67220d0a64..bfc4206935c8 100644
--- a/drivers/media/platform/s5p-fimc/fimc-lite.c
+++ b/drivers/media/platform/s5p-fimc/fimc-lite.c
@@ -120,25 +120,29 @@ static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
return def_fmt;
}
-static int fimc_lite_hw_init(struct fimc_lite *fimc)
+static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output)
{
struct fimc_pipeline *pipeline = &fimc->pipeline;
- struct fimc_sensor_info *sensor;
+ struct v4l2_subdev *sensor;
+ struct fimc_sensor_info *si;
unsigned long flags;
- if (pipeline->subdevs[IDX_SENSOR] == NULL)
+ sensor = isp_output ? fimc->sensor : pipeline->subdevs[IDX_SENSOR];
+
+ if (sensor == NULL)
return -ENXIO;
if (fimc->fmt == NULL)
return -EINVAL;
- sensor = v4l2_get_subdev_hostdata(pipeline->subdevs[IDX_SENSOR]);
+ /* Get sensor configuration data from the sensor subdev */
+ si = v4l2_get_subdev_hostdata(sensor);
spin_lock_irqsave(&fimc->slock, flags);
- flite_hw_set_camera_bus(fimc, &sensor->pdata);
+ flite_hw_set_camera_bus(fimc, &si->pdata);
flite_hw_set_source_format(fimc, &fimc->inp_frame);
flite_hw_set_window_offset(fimc, &fimc->inp_frame);
- flite_hw_set_output_dma(fimc, &fimc->out_frame, true);
+ flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output);
flite_hw_set_interrupt_mask(fimc);
flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
@@ -256,7 +260,7 @@ static irqreturn_t flite_irq_handler(int irq, void *priv)
wake_up(&fimc->irq_queue);
}
- if (fimc->out_path != FIMC_IO_DMA)
+ if (atomic_read(&fimc->out_path) != FIMC_IO_DMA)
goto done;
if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) &&
@@ -296,7 +300,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
fimc->frame_count = 0;
- ret = fimc_lite_hw_init(fimc);
+ ret = fimc_lite_hw_init(fimc, false);
if (ret) {
fimc_lite_reinit(fimc, false);
return ret;
@@ -455,10 +459,16 @@ static void fimc_lite_clear_event_counters(struct fimc_lite *fimc)
static int fimc_lite_open(struct file *file)
{
struct fimc_lite *fimc = video_drvdata(file);
+ struct media_entity *me = &fimc->vfd.entity;
int ret;
- if (mutex_lock_interruptible(&fimc->lock))
- return -ERESTARTSYS;
+ mutex_lock(&me->parent->graph_mutex);
+
+ mutex_lock(&fimc->lock);
+ if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) {
+ ret = -EBUSY;
+ goto done;
+ }
set_bit(ST_FLITE_IN_USE, &fimc->state);
ret = pm_runtime_get_sync(&fimc->pdev->dev);
@@ -469,7 +479,8 @@ static int fimc_lite_open(struct file *file)
if (ret < 0)
goto done;
- if (++fimc->ref_count == 1 && fimc->out_path == FIMC_IO_DMA) {
+ if (++fimc->ref_count == 1 &&
+ atomic_read(&fimc->out_path) == FIMC_IO_DMA) {
ret = fimc_pipeline_call(fimc, open, &fimc->pipeline,
&fimc->vfd.entity, true);
if (ret < 0) {
@@ -483,6 +494,7 @@ static int fimc_lite_open(struct file *file)
}
done:
mutex_unlock(&fimc->lock);
+ mutex_unlock(&me->parent->graph_mutex);
return ret;
}
@@ -493,7 +505,8 @@ static int fimc_lite_close(struct file *file)
mutex_lock(&fimc->lock);
- if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) {
+ if (--fimc->ref_count == 0 &&
+ atomic_read(&fimc->out_path) == FIMC_IO_DMA) {
clear_bit(ST_FLITE_IN_USE, &fimc->state);
fimc_lite_stop_capture(fimc, false);
fimc_pipeline_call(fimc, close, &fimc->pipeline);
@@ -598,7 +611,7 @@ static void fimc_lite_try_crop(struct fimc_lite *fimc, struct v4l2_rect *r)
r->left = round_down(r->left, fimc->variant->win_hor_offs_align);
r->top = clamp_t(u32, r->top, 0, frame->f_height - r->height);
- v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, sink fmt: %dx%d",
+ v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, sink fmt: %dx%d\n",
r->left, r->top, r->width, r->height,
frame->f_width, frame->f_height);
}
@@ -618,7 +631,7 @@ static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r)
r->left = round_down(r->left, fimc->variant->out_hor_offs_align);
r->top = clamp_t(u32, r->top, 0, fimc->out_frame.f_height - r->height);
- v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, source fmt: %dx%d",
+ v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, source fmt: %dx%d\n",
r->left, r->top, r->width, r->height,
frame->f_width, frame->f_height);
}
@@ -962,6 +975,29 @@ static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = {
.vidioc_streamoff = fimc_lite_streamoff,
};
+/* Called with the media graph mutex held */
+static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me)
+{
+ struct media_pad *pad = &me->pads[0];
+ struct v4l2_subdev *sd;
+
+ while (pad->flags & MEDIA_PAD_FL_SINK) {
+ /* source pad */
+ pad = media_entity_remote_source(pad);
+ if (pad == NULL ||
+ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR)
+ return sd;
+ /* sink pad */
+ pad = &sd->entity.pads[0];
+ }
+ return NULL;
+}
+
/* Capture subdev media entity operations */
static int fimc_lite_link_setup(struct media_entity *entity,
const struct media_pad *local,
@@ -970,46 +1006,60 @@ static int fimc_lite_link_setup(struct media_entity *entity,
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
unsigned int remote_ent_type = media_entity_type(remote->entity);
+ int ret = 0;
if (WARN_ON(fimc == NULL))
return 0;
- v4l2_dbg(1, debug, sd, "%s: %s --> %s, flags: 0x%x. source_id: 0x%x",
- __func__, local->entity->name, remote->entity->name,
+ v4l2_dbg(1, debug, sd, "%s: %s --> %s, flags: 0x%x. source_id: 0x%x\n",
+ __func__, remote->entity->name, local->entity->name,
flags, fimc->source_subdev_grp_id);
- switch (local->index) {
- case FIMC_SD_PAD_SINK:
- if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV)
- return -EINVAL;
+ mutex_lock(&fimc->lock);
+ switch (local->index) {
+ case FLITE_SD_PAD_SINK:
+ if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV) {
+ ret = -EINVAL;
+ break;
+ }
if (flags & MEDIA_LNK_FL_ENABLED) {
- if (fimc->source_subdev_grp_id != 0)
- return -EBUSY;
- fimc->source_subdev_grp_id = sd->grp_id;
- return 0;
+ if (fimc->source_subdev_grp_id == 0)
+ fimc->source_subdev_grp_id = sd->grp_id;
+ else
+ ret = -EBUSY;
+ } else {
+ fimc->source_subdev_grp_id = 0;
+ fimc->sensor = NULL;
}
+ break;
- fimc->source_subdev_grp_id = 0;
+ case FLITE_SD_PAD_SOURCE_DMA:
+ if (!(flags & MEDIA_LNK_FL_ENABLED))
+ atomic_set(&fimc->out_path, FIMC_IO_NONE);
+ else if (remote_ent_type == MEDIA_ENT_T_DEVNODE)
+ atomic_set(&fimc->out_path, FIMC_IO_DMA);
+ else
+ ret = -EINVAL;
break;
- case FIMC_SD_PAD_SOURCE:
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- fimc->out_path = FIMC_IO_NONE;
- return 0;
- }
- if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV)
- fimc->out_path = FIMC_IO_ISP;
+ case FLITE_SD_PAD_SOURCE_ISP:
+ if (!(flags & MEDIA_LNK_FL_ENABLED))
+ atomic_set(&fimc->out_path, FIMC_IO_NONE);
+ else if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV)
+ atomic_set(&fimc->out_path, FIMC_IO_ISP);
else
- fimc->out_path = FIMC_IO_DMA;
+ ret = -EINVAL;
break;
default:
v4l2_err(sd, "Invalid pad index\n");
- return -EINVAL;
+ ret = -EINVAL;
}
+ mb();
- return 0;
+ mutex_unlock(&fimc->lock);
+ return ret;
}
static const struct media_entity_operations fimc_lite_subdev_media_ops = {
@@ -1070,14 +1120,16 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
struct flite_frame *source = &fimc->out_frame;
const struct fimc_fmt *ffmt;
- v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d",
+ v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d\n",
fmt->pad, mf->code, mf->width, mf->height);
mf->colorspace = V4L2_COLORSPACE_JPEG;
mutex_lock(&fimc->lock);
- if ((fimc->out_path == FIMC_IO_ISP && sd->entity.stream_count > 0) ||
- (fimc->out_path == FIMC_IO_DMA && vb2_is_busy(&fimc->vb_queue))) {
+ if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP &&
+ sd->entity.stream_count > 0) ||
+ (atomic_read(&fimc->out_path) == FIMC_IO_DMA &&
+ vb2_is_busy(&fimc->vb_queue))) {
mutex_unlock(&fimc->lock);
return -EBUSY;
}
@@ -1144,7 +1196,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
}
mutex_unlock(&fimc->lock);
- v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d",
+ v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d\n",
__func__, f->rect.left, f->rect.top, f->rect.width,
f->rect.height, f->f_width, f->f_height);
@@ -1178,7 +1230,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
}
mutex_unlock(&fimc->lock);
- v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d",
+ v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d\n",
__func__, f->rect.left, f->rect.top, f->rect.width,
f->rect.height, f->f_width, f->f_height);
@@ -1188,25 +1240,47 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on)
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+ unsigned long flags;
+ int ret;
- if (fimc->out_path == FIMC_IO_DMA)
- return -ENOIOCTLCMD;
-
- /* TODO: */
+ /*
+ * Find sensor subdev linked to FIMC-LITE directly or through
+ * MIPI-CSIS. This is required for configuration where FIMC-LITE
+ * is used as a subdev only and feeds data internally to FIMC-IS.
+ * The pipeline links are protected through entity.stream_count
+ * so there is no need to take the media graph mutex here.
+ */
+ fimc->sensor = __find_remote_sensor(&sd->entity);
- return 0;
-}
+ if (atomic_read(&fimc->out_path) != FIMC_IO_ISP)
+ return -ENOIOCTLCMD;
-static int fimc_lite_subdev_s_power(struct v4l2_subdev *sd, int on)
-{
- struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+ mutex_lock(&fimc->lock);
+ if (on) {
+ flite_hw_reset(fimc);
+ ret = fimc_lite_hw_init(fimc, true);
+ if (!ret) {
+ spin_lock_irqsave(&fimc->slock, flags);
+ flite_hw_capture_start(fimc);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ }
+ } else {
+ set_bit(ST_FLITE_OFF, &fimc->state);
- if (fimc->out_path == FIMC_IO_DMA)
- return -ENOIOCTLCMD;
+ spin_lock_irqsave(&fimc->slock, flags);
+ flite_hw_capture_stop(fimc);
+ spin_unlock_irqrestore(&fimc->slock, flags);
- /* TODO: */
+ ret = wait_event_timeout(fimc->irq_queue,
+ !test_bit(ST_FLITE_OFF, &fimc->state),
+ msecs_to_jiffies(200));
+ if (ret == 0)
+ v4l2_err(sd, "s_stream(0) timeout\n");
+ clear_bit(ST_FLITE_RUN, &fimc->state);
+ }
- return 0;
+ mutex_unlock(&fimc->lock);
+ return ret;
}
static int fimc_lite_log_status(struct v4l2_subdev *sd)
@@ -1227,7 +1301,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
memset(vfd, 0, sizeof(*vfd));
fimc->fmt = &fimc_lite_formats[0];
- fimc->out_path = FIMC_IO_DMA;
+ atomic_set(&fimc->out_path, FIMC_IO_DMA);
snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture",
fimc->index);
@@ -1308,7 +1382,6 @@ static const struct v4l2_subdev_video_ops fimc_lite_subdev_video_ops = {
};
static const struct v4l2_subdev_core_ops fimc_lite_core_ops = {
- .s_power = fimc_lite_subdev_s_power,
.log_status = fimc_lite_log_status,
};
@@ -1347,9 +1420,10 @@ static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "FIMC-LITE.%d", fimc->index);
- fimc->subdev_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- fimc->subdev_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
+ fimc->subdev_pads[FLITE_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ fimc->subdev_pads[FLITE_SD_PAD_SOURCE_DMA].flags = MEDIA_PAD_FL_SOURCE;
+ fimc->subdev_pads[FLITE_SD_PAD_SOURCE_ISP].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&sd->entity, FLITE_SD_PADS_NUM,
fimc->subdev_pads, 0);
if (ret)
return ret;
@@ -1426,11 +1500,9 @@ static int fimc_lite_probe(struct platform_device *pdev)
mutex_init(&fimc->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (fimc->regs == NULL) {
- dev_err(&pdev->dev, "Failed to obtain io memory\n");
- return -ENOENT;
- }
+ fimc->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(fimc->regs))
+ return PTR_ERR(fimc->regs);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
@@ -1518,7 +1590,7 @@ static int fimc_lite_resume(struct device *dev)
INIT_LIST_HEAD(&fimc->active_buf_q);
fimc_pipeline_call(fimc, open, &fimc->pipeline,
&fimc->vfd.entity, false);
- fimc_lite_hw_init(fimc);
+ fimc_lite_hw_init(fimc, atomic_read(&fimc->out_path) == FIMC_IO_ISP);
clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
for (i = 0; i < fimc->reqbufs_count; i++) {
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.h b/drivers/media/platform/s5p-fimc/fimc-lite.h
index 3081db35c5b0..7085761f8c4b 100644
--- a/drivers/media/platform/s5p-fimc/fimc-lite.h
+++ b/drivers/media/platform/s5p-fimc/fimc-lite.h
@@ -45,8 +45,9 @@ enum {
};
#define FLITE_SD_PAD_SINK 0
-#define FLITE_SD_PAD_SOURCE 1
-#define FLITE_SD_PADS_NUM 2
+#define FLITE_SD_PAD_SOURCE_DMA 1
+#define FLITE_SD_PAD_SOURCE_ISP 2
+#define FLITE_SD_PADS_NUM 3
struct flite_variant {
unsigned short max_width;
@@ -104,6 +105,7 @@ struct flite_buffer {
* @subdev: FIMC-LITE subdev
* @vd_pad: media (sink) pad for the capture video node
* @subdev_pads: the subdev media pads
+ * @sensor: sensor subdev attached to FIMC-LITE directly or through MIPI-CSIS
* @ctrl_handler: v4l2 control handler
* @test_pattern: test pattern controls
* @index: FIMC-LITE platform device index
@@ -139,6 +141,7 @@ struct fimc_lite {
struct v4l2_subdev subdev;
struct media_pad vd_pad;
struct media_pad subdev_pads[FLITE_SD_PADS_NUM];
+ struct v4l2_subdev *sensor;
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *test_pattern;
u32 index;
@@ -156,7 +159,7 @@ struct fimc_lite {
unsigned long payload[FLITE_MAX_PLANES];
struct flite_frame inp_frame;
struct flite_frame out_frame;
- enum fimc_datapath out_path;
+ atomic_t out_path;
unsigned int source_subdev_grp_id;
unsigned long state;
diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c
index 1d21da4bd24b..f3d535cdd87f 100644
--- a/drivers/media/platform/s5p-fimc/fimc-m2m.c
+++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c
@@ -1,8 +1,8 @@
/*
* Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver
*
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
+ * 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 as published
@@ -160,8 +160,7 @@ static void fimc_device_run(void *priv)
fimc_hw_set_output_addr(fimc, &df->paddr, -1);
fimc_activate_capture(ctx);
- ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP |
- FIMC_SRC_FMT | FIMC_DST_FMT);
+ ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
fimc_hw_activate_input_dma(fimc, true);
dma_unlock:
@@ -294,13 +293,14 @@ static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
if (IS_ERR(frame))
return PTR_ERR(frame);
- return fimc_fill_format(frame, f);
+ __fimc_get_format(frame, f);
+ return 0;
}
static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
{
struct fimc_dev *fimc = ctx->fimc_dev;
- struct fimc_variant *variant = fimc->variant;
+ const struct fimc_variant *variant = fimc->variant;
struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
struct fimc_fmt *fmt;
u32 max_w, mod_x, mod_y;
@@ -308,8 +308,6 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
if (!IS_M2M(f->type))
return -EINVAL;
- dbg("w: %d, h: %d", pix->width, pix->height);
-
fmt = fimc_find_format(&pix->pixelformat, NULL,
get_m2m_fmt_flags(f->type), 0);
if (WARN(fmt == NULL, "Pixel format lookup failed"))
@@ -349,19 +347,39 @@ static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
struct v4l2_format *f)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
-
return fimc_try_fmt_mplane(ctx, f);
}
+static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt,
+ struct v4l2_pix_format_mplane *pixm)
+{
+ int i;
+
+ for (i = 0; i < fmt->colplanes; i++) {
+ frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline;
+ frame->payload[i] = pixm->plane_fmt[i].sizeimage;
+ }
+
+ frame->f_width = pixm->width;
+ frame->f_height = pixm->height;
+ frame->o_width = pixm->width;
+ frame->o_height = pixm->height;
+ frame->width = pixm->width;
+ frame->height = pixm->height;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+ frame->fmt = fmt;
+}
+
static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
struct v4l2_format *f)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_fmt *fmt;
struct vb2_queue *vq;
struct fimc_frame *frame;
- struct v4l2_pix_format_mplane *pix;
- int i, ret = 0;
+ int ret;
ret = fimc_try_fmt_mplane(ctx, f);
if (ret)
@@ -379,31 +397,16 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
else
frame = &ctx->d_frame;
- pix = &f->fmt.pix_mp;
- frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
- get_m2m_fmt_flags(f->type), 0);
- if (!frame->fmt)
+ fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL,
+ get_m2m_fmt_flags(f->type), 0);
+ if (!fmt)
return -EINVAL;
+ __set_frame_format(frame, fmt, &f->fmt.pix_mp);
+
/* Update RGB Alpha control state and value range */
fimc_alpha_ctrl_update(ctx);
- for (i = 0; i < frame->fmt->colplanes; i++) {
- frame->payload[i] =
- (pix->width * pix->height * frame->fmt->depth[i]) / 8;
- }
-
- fimc_fill_frame(frame, f);
-
- ctx->scaler.enabled = 1;
-
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- fimc_ctx_state_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
- else
- fimc_ctx_state_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx);
-
- dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
-
return 0;
}
@@ -411,7 +414,6 @@ static int fimc_m2m_reqbufs(struct file *file, void *fh,
struct v4l2_requestbuffers *reqbufs)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
-
return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
}
@@ -419,7 +421,6 @@ static int fimc_m2m_querybuf(struct file *file, void *fh,
struct v4l2_buffer *buf)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
-
return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
}
@@ -427,7 +428,6 @@ static int fimc_m2m_qbuf(struct file *file, void *fh,
struct v4l2_buffer *buf)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
-
return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
}
@@ -435,7 +435,6 @@ static int fimc_m2m_dqbuf(struct file *file, void *fh,
struct v4l2_buffer *buf)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
-
return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
}
@@ -443,7 +442,6 @@ static int fimc_m2m_expbuf(struct file *file, void *fh,
struct v4l2_exportbuffer *eb)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
-
return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
}
@@ -452,15 +450,6 @@ static int fimc_m2m_streamon(struct file *file, void *fh,
enum v4l2_buf_type type)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
-
- /* The source and target color format need to be set */
- if (V4L2_TYPE_IS_OUTPUT(type)) {
- if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx))
- return -EINVAL;
- } else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) {
- return -EINVAL;
- }
-
return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
}
@@ -468,7 +457,6 @@ static int fimc_m2m_streamoff(struct file *file, void *fh,
enum v4l2_buf_type type)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
-
return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
}
@@ -576,20 +564,18 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *
&ctx->s_frame : &ctx->d_frame;
/* Check to see if scaling ratio is within supported range */
- if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
- if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- ret = fimc_check_scaler_ratio(ctx, cr.c.width,
- cr.c.height, ctx->d_frame.width,
- ctx->d_frame.height, ctx->rotation);
- } else {
- ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
- ctx->s_frame.height, cr.c.width,
- cr.c.height, ctx->rotation);
- }
- if (ret) {
- v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n");
- return -EINVAL;
- }
+ if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = fimc_check_scaler_ratio(ctx, cr.c.width,
+ cr.c.height, ctx->d_frame.width,
+ ctx->d_frame.height, ctx->rotation);
+ } else {
+ ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
+ ctx->s_frame.height, cr.c.width,
+ cr.c.height, ctx->rotation);
+ }
+ if (ret) {
+ v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n");
+ return -EINVAL;
}
f->offs_h = cr.c.left;
@@ -652,6 +638,29 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
return vb2_queue_init(dst_vq);
}
+static int fimc_m2m_set_default_format(struct fimc_ctx *ctx)
+{
+ struct v4l2_pix_format_mplane pixm = {
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .width = 800,
+ .height = 600,
+ .plane_fmt[0] = {
+ .bytesperline = 800 * 4,
+ .sizeimage = 800 * 4 * 600,
+ },
+ };
+ struct fimc_fmt *fmt;
+
+ fmt = fimc_find_format(&pixm.pixelformat, NULL, FMT_FLAGS_M2M, 0);
+ if (!fmt)
+ return -EINVAL;
+
+ __set_frame_format(&ctx->s_frame, fmt, &pixm);
+ __set_frame_format(&ctx->d_frame, fmt, &pixm);
+
+ return 0;
+}
+
static int fimc_m2m_open(struct file *file)
{
struct fimc_dev *fimc = video_drvdata(file);
@@ -696,6 +705,7 @@ static int fimc_m2m_open(struct file *file)
ctx->flags = 0;
ctx->in_path = FIMC_IO_DMA;
ctx->out_path = FIMC_IO_DMA;
+ ctx->scaler.enabled = 1;
ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
if (IS_ERR(ctx->m2m_ctx)) {
@@ -706,9 +716,15 @@ static int fimc_m2m_open(struct file *file)
if (fimc->m2m.refcnt++ == 0)
set_bit(ST_M2M_RUN, &fimc->state);
+ ret = fimc_m2m_set_default_format(ctx);
+ if (ret < 0)
+ goto error_m2m_ctx;
+
mutex_unlock(&fimc->lock);
return 0;
+error_m2m_ctx:
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
error_c:
fimc_ctrls_delete(ctx);
error_fh:
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
index b4a68ecf0ca7..a17fcb2d5d41 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
@@ -1,8 +1,8 @@
/*
* S5P/EXYNOS4 SoC series camera host interface media device driver
*
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
+ * 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 as published
@@ -62,16 +62,17 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
sd = media_entity_to_v4l2_subdev(pad->entity);
switch (sd->grp_id) {
- case SENSOR_GROUP_ID:
+ case GRP_ID_FIMC_IS_SENSOR:
+ case GRP_ID_SENSOR:
p->subdevs[IDX_SENSOR] = sd;
break;
- case CSIS_GROUP_ID:
+ case GRP_ID_CSIS:
p->subdevs[IDX_CSIS] = sd;
break;
- case FLITE_GROUP_ID:
+ case GRP_ID_FLITE:
p->subdevs[IDX_FLITE] = sd;
break;
- case FIMC_GROUP_ID:
+ case GRP_ID_FIMC:
/* No need to control FIMC subdev through subdev ops */
break;
default:
@@ -141,7 +142,7 @@ static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state)
* @me: media entity to start graph walk with
* @prep: true to acquire sensor (and csis) subdevs
*
- * This function must be called with the graph mutex held.
+ * Called with the graph mutex held.
*/
static int __fimc_pipeline_open(struct fimc_pipeline *p,
struct media_entity *me, bool prep)
@@ -161,30 +162,19 @@ static int __fimc_pipeline_open(struct fimc_pipeline *p,
return fimc_pipeline_s_power(p, 1);
}
-static int fimc_pipeline_open(struct fimc_pipeline *p,
- struct media_entity *me, bool prep)
-{
- int ret;
-
- mutex_lock(&me->parent->graph_mutex);
- ret = __fimc_pipeline_open(p, me, prep);
- mutex_unlock(&me->parent->graph_mutex);
-
- return ret;
-}
-
/**
* __fimc_pipeline_close - disable the sensor clock and pipeline power
* @fimc: fimc device terminating the pipeline
*
- * Disable power of all subdevs in the pipeline and turn off the external
- * sensor clock.
- * Called with the graph mutex held.
+ * Disable power of all subdevs and turn the external sensor clock off.
*/
static int __fimc_pipeline_close(struct fimc_pipeline *p)
{
int ret = 0;
+ if (!p || !p->subdevs[IDX_SENSOR])
+ return -EINVAL;
+
if (p->subdevs[IDX_SENSOR]) {
ret = fimc_pipeline_s_power(p, 0);
fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false);
@@ -192,28 +182,12 @@ static int __fimc_pipeline_close(struct fimc_pipeline *p)
return ret == -ENXIO ? 0 : ret;
}
-static int fimc_pipeline_close(struct fimc_pipeline *p)
-{
- struct media_entity *me;
- int ret;
-
- if (!p || !p->subdevs[IDX_SENSOR])
- return -EINVAL;
-
- me = &p->subdevs[IDX_SENSOR]->entity;
- mutex_lock(&me->parent->graph_mutex);
- ret = __fimc_pipeline_close(p);
- mutex_unlock(&me->parent->graph_mutex);
-
- return ret;
-}
-
/**
- * fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs
+ * __fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs
* @pipeline: video pipeline structure
* @on: passed as the s_stream call argument
*/
-static int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on)
+static int __fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on)
{
int i, ret;
@@ -235,9 +209,9 @@ static int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on)
/* Media pipeline operations for the FIMC/FIMC-LITE video device driver */
static const struct fimc_pipeline_ops fimc_pipeline_ops = {
- .open = fimc_pipeline_open,
- .close = fimc_pipeline_close,
- .set_stream = fimc_pipeline_s_stream,
+ .open = __fimc_pipeline_open,
+ .close = __fimc_pipeline_close,
+ .set_stream = __fimc_pipeline_s_stream,
};
/*
@@ -269,7 +243,7 @@ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd,
return ERR_PTR(-EPROBE_DEFER);
}
v4l2_set_subdev_hostdata(sd, s_info);
- sd->grp_id = SENSOR_GROUP_ID;
+ sd->grp_id = GRP_ID_SENSOR;
v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n",
s_info->pdata.board_info->type);
@@ -316,7 +290,7 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
for (i = 0; i < num_clients; i++) {
struct v4l2_subdev *sd;
- fmd->sensor[i].pdata = pdata->isp_info[i];
+ fmd->sensor[i].pdata = pdata->source_info[i];
ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true);
if (ret)
break;
@@ -338,138 +312,149 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
}
/*
- * MIPI CSIS and FIMC platform devices registration.
+ * MIPI-CSIS, FIMC and FIMC-LITE platform devices registration.
*/
-static int fimc_register_callback(struct device *dev, void *p)
+
+static int register_fimc_lite_entity(struct fimc_md *fmd,
+ struct fimc_lite *fimc_lite)
{
- struct fimc_dev *fimc = dev_get_drvdata(dev);
struct v4l2_subdev *sd;
- struct fimc_md *fmd = p;
int ret;
- if (fimc == NULL || fimc->id >= FIMC_MAX_DEVS)
- return 0;
+ if (WARN_ON(fimc_lite->index >= FIMC_LITE_MAX_DEVS ||
+ fmd->fimc_lite[fimc_lite->index]))
+ return -EBUSY;
- sd = &fimc->vid_cap.subdev;
- sd->grp_id = FIMC_GROUP_ID;
+ sd = &fimc_lite->subdev;
+ sd->grp_id = GRP_ID_FLITE;
v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops);
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
- if (ret) {
- v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n",
- fimc->id, ret);
- return ret;
- }
-
- fmd->fimc[fimc->id] = fimc;
- return 0;
+ if (!ret)
+ fmd->fimc_lite[fimc_lite->index] = fimc_lite;
+ else
+ v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.LITE%d\n",
+ fimc_lite->index);
+ return ret;
}
-static int fimc_lite_register_callback(struct device *dev, void *p)
+static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc)
{
- struct fimc_lite *fimc = dev_get_drvdata(dev);
- struct fimc_md *fmd = p;
+ struct v4l2_subdev *sd;
int ret;
- if (fimc == NULL || fimc->index >= FIMC_LITE_MAX_DEVS)
- return 0;
+ if (WARN_ON(fimc->id >= FIMC_MAX_DEVS || fmd->fimc[fimc->id]))
+ return -EBUSY;
- fimc->subdev.grp_id = FLITE_GROUP_ID;
- v4l2_set_subdev_hostdata(&fimc->subdev, (void *)&fimc_pipeline_ops);
+ sd = &fimc->vid_cap.subdev;
+ sd->grp_id = GRP_ID_FIMC;
+ v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops);
- ret = v4l2_device_register_subdev(&fmd->v4l2_dev, &fimc->subdev);
- if (ret) {
- v4l2_err(&fmd->v4l2_dev,
- "Failed to register FIMC-LITE.%d (%d)\n",
- fimc->index, ret);
- return ret;
+ ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+ if (!ret) {
+ fmd->fimc[fimc->id] = fimc;
+ fimc->vid_cap.user_subdev_api = fmd->user_subdev_api;
+ } else {
+ v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n",
+ fimc->id, ret);
}
-
- fmd->fimc_lite[fimc->index] = fimc;
- return 0;
+ return ret;
}
-static int csis_register_callback(struct device *dev, void *p)
+static int register_csis_entity(struct fimc_md *fmd,
+ struct platform_device *pdev,
+ struct v4l2_subdev *sd)
{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct platform_device *pdev;
- struct fimc_md *fmd = p;
+ struct device_node *node = pdev->dev.of_node;
int id, ret;
- if (!sd)
- return 0;
- pdev = v4l2_get_subdevdata(sd);
- if (!pdev || pdev->id < 0 || pdev->id >= CSIS_MAX_ENTITIES)
- return 0;
- v4l2_info(sd, "csis%d sd: %s\n", pdev->id, sd->name);
+ id = node ? of_alias_get_id(node, "csis") : max(0, pdev->id);
+
+ if (WARN_ON(id >= CSIS_MAX_ENTITIES || fmd->csis[id].sd))
+ return -EBUSY;
- id = pdev->id < 0 ? 0 : pdev->id;
- sd->grp_id = CSIS_GROUP_ID;
+ if (WARN_ON(id >= CSIS_MAX_ENTITIES))
+ return 0;
+ sd->grp_id = GRP_ID_CSIS;
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
if (!ret)
fmd->csis[id].sd = sd;
else
v4l2_err(&fmd->v4l2_dev,
- "Failed to register CSIS subdevice: %d\n", ret);
+ "Failed to register MIPI-CSIS.%d (%d)\n", id, ret);
return ret;
}
-/**
- * fimc_md_register_platform_entities - register FIMC and CSIS media entities
- */
-static int fimc_md_register_platform_entities(struct fimc_md *fmd)
+static int fimc_md_register_platform_entity(struct fimc_md *fmd,
+ struct platform_device *pdev,
+ int plat_entity)
{
- struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data;
- struct device_driver *driver;
- int ret, i;
-
- driver = driver_find(FIMC_MODULE_NAME, &platform_bus_type);
- if (!driver) {
- v4l2_warn(&fmd->v4l2_dev,
- "%s driver not found, deffering probe\n",
- FIMC_MODULE_NAME);
- return -EPROBE_DEFER;
- }
-
- ret = driver_for_each_device(driver, NULL, fmd,
- fimc_register_callback);
- if (ret)
- return ret;
-
- driver = driver_find(FIMC_LITE_DRV_NAME, &platform_bus_type);
- if (driver && try_module_get(driver->owner)) {
- ret = driver_for_each_device(driver, NULL, fmd,
- fimc_lite_register_callback);
- if (ret)
- return ret;
- module_put(driver->owner);
- }
- /*
- * Check if there is any sensor on the MIPI-CSI2 bus and
- * if not skip the s5p-csis module loading.
- */
- if (pdata == NULL)
- return 0;
- for (i = 0; i < pdata->num_clients; i++) {
- if (pdata->isp_info[i].bus_type == FIMC_MIPI_CSI2) {
- ret = 1;
+ struct device *dev = &pdev->dev;
+ int ret = -EPROBE_DEFER;
+ void *drvdata;
+
+ /* Lock to ensure dev->driver won't change. */
+ device_lock(dev);
+
+ if (!dev->driver || !try_module_get(dev->driver->owner))
+ goto dev_unlock;
+
+ drvdata = dev_get_drvdata(dev);
+ /* Some subdev didn't probe succesfully id drvdata is NULL */
+ if (drvdata) {
+ switch (plat_entity) {
+ case IDX_FIMC:
+ ret = register_fimc_entity(fmd, drvdata);
break;
+ case IDX_FLITE:
+ ret = register_fimc_lite_entity(fmd, drvdata);
+ break;
+ case IDX_CSIS:
+ ret = register_csis_entity(fmd, pdev, drvdata);
+ break;
+ default:
+ ret = -ENODEV;
}
}
- if (!ret)
- return 0;
- driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
- if (!driver || !try_module_get(driver->owner)) {
- v4l2_warn(&fmd->v4l2_dev,
- "%s driver not found, deffering probe\n",
- CSIS_DRIVER_NAME);
- return -EPROBE_DEFER;
+ module_put(dev->driver->owner);
+dev_unlock:
+ device_unlock(dev);
+ if (ret == -EPROBE_DEFER)
+ dev_info(&fmd->pdev->dev, "deferring %s device registration\n",
+ dev_name(dev));
+ else if (ret < 0)
+ dev_err(&fmd->pdev->dev, "%s device registration failed (%d)\n",
+ dev_name(dev), ret);
+ return ret;
+}
+
+static int fimc_md_pdev_match(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int plat_entity = -1;
+ int ret;
+ char *p;
+
+ if (!get_device(dev))
+ return -ENODEV;
+
+ if (!strcmp(pdev->name, CSIS_DRIVER_NAME)) {
+ plat_entity = IDX_CSIS;
+ } else if (!strcmp(pdev->name, FIMC_LITE_DRV_NAME)) {
+ plat_entity = IDX_FLITE;
+ } else {
+ p = strstr(pdev->name, "fimc");
+ if (p && *(p + 4) == 0)
+ plat_entity = IDX_FIMC;
}
- return driver_for_each_device(driver, NULL, fmd,
- csis_register_callback);
+ if (plat_entity >= 0)
+ ret = fimc_md_register_platform_entity(data, pdev,
+ plat_entity);
+ put_device(dev);
+ return 0;
}
static void fimc_md_unregister_entities(struct fimc_md *fmd)
@@ -487,7 +472,7 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
if (fmd->fimc_lite[i] == NULL)
continue;
v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev);
- fmd->fimc[i]->pipeline_ops = NULL;
+ fmd->fimc_lite[i]->pipeline_ops = NULL;
fmd->fimc_lite[i] = NULL;
}
for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
@@ -503,6 +488,7 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
fimc_md_unregister_sensor(fmd->sensor[i].subdev);
fmd->sensor[i].subdev = NULL;
}
+ v4l2_info(&fmd->v4l2_dev, "Unregistered all entities\n");
}
/**
@@ -518,7 +504,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
struct v4l2_subdev *sensor,
int pad, int link_mask)
{
- struct fimc_sensor_info *s_info;
+ struct fimc_sensor_info *s_info = NULL;
struct media_entity *sink;
unsigned int flags = 0;
int ret, i;
@@ -582,7 +568,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
if (ret)
break;
- v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
+ v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n",
source->name, flags ? '=' : '-', sink->name);
}
return 0;
@@ -602,7 +588,7 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
source = &fimc->subdev.entity;
sink = &fimc->vfd.entity;
/* FIMC-LITE's subdev and video node */
- ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
+ ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA,
sink, 0, flags);
if (ret)
break;
@@ -626,9 +612,9 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
*/
static int fimc_md_create_links(struct fimc_md *fmd)
{
- struct v4l2_subdev *csi_sensors[2] = { NULL };
+ struct v4l2_subdev *csi_sensors[CSIS_MAX_ENTITIES] = { NULL };
struct v4l2_subdev *sensor, *csis;
- struct s5p_fimc_isp_info *pdata;
+ struct fimc_source_info *pdata;
struct fimc_sensor_info *s_info;
struct media_entity *source, *sink;
int i, pad, fimc_id = 0, ret = 0;
@@ -646,8 +632,8 @@ static int fimc_md_create_links(struct fimc_md *fmd)
source = NULL;
pdata = &s_info->pdata;
- switch (pdata->bus_type) {
- case FIMC_MIPI_CSI2:
+ switch (pdata->sensor_bus_type) {
+ case FIMC_BUS_TYPE_MIPI_CSI2:
if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES,
"Wrong CSI channel id: %d\n", pdata->mux_id))
return -EINVAL;
@@ -658,28 +644,29 @@ static int fimc_md_create_links(struct fimc_md *fmd)
"but s5p-csis module is not loaded!\n"))
return -EINVAL;
- ret = media_entity_create_link(&sensor->entity, 0,
+ pad = sensor->entity.num_pads - 1;
+ ret = media_entity_create_link(&sensor->entity, pad,
&csis->entity, CSIS_PAD_SINK,
MEDIA_LNK_FL_IMMUTABLE |
MEDIA_LNK_FL_ENABLED);
if (ret)
return ret;
- v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]",
+ v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]\n",
sensor->entity.name, csis->entity.name);
source = NULL;
csi_sensors[pdata->mux_id] = sensor;
break;
- case FIMC_ITU_601...FIMC_ITU_656:
+ case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656:
source = &sensor->entity;
pad = 0;
break;
default:
v4l2_err(&fmd->v4l2_dev, "Wrong bus_type: %x\n",
- pdata->bus_type);
+ pdata->sensor_bus_type);
return -EINVAL;
}
if (source == NULL)
@@ -690,7 +677,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
pad, link_mask);
}
- for (i = 0; i < ARRAY_SIZE(fmd->csis); i++) {
+ for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
if (fmd->csis[i].sd == NULL)
continue;
source = &fmd->csis[i].sd->entity;
@@ -721,42 +708,61 @@ static int fimc_md_create_links(struct fimc_md *fmd)
/*
* The peripheral sensor clock management.
*/
+static void fimc_md_put_clocks(struct fimc_md *fmd)
+{
+ int i = FIMC_MAX_CAMCLKS;
+
+ while (--i >= 0) {
+ if (IS_ERR(fmd->camclk[i].clock))
+ continue;
+ clk_unprepare(fmd->camclk[i].clock);
+ clk_put(fmd->camclk[i].clock);
+ fmd->camclk[i].clock = ERR_PTR(-EINVAL);
+ }
+}
+
static int fimc_md_get_clocks(struct fimc_md *fmd)
{
+ struct device *dev = NULL;
char clk_name[32];
struct clk *clock;
- int i;
+ int ret, i;
+
+ for (i = 0; i < FIMC_MAX_CAMCLKS; i++)
+ fmd->camclk[i].clock = ERR_PTR(-EINVAL);
+
+ if (fmd->pdev->dev.of_node)
+ dev = &fmd->pdev->dev;
for (i = 0; i < FIMC_MAX_CAMCLKS; i++) {
snprintf(clk_name, sizeof(clk_name), "sclk_cam%u", i);
- clock = clk_get(NULL, clk_name);
- if (IS_ERR_OR_NULL(clock)) {
- v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s",
- clk_name);
- return -ENXIO;
+ clock = clk_get(dev, clk_name);
+
+ if (IS_ERR(clock)) {
+ dev_err(&fmd->pdev->dev, "Failed to get clock: %s\n",
+ clk_name);
+ ret = PTR_ERR(clock);
+ break;
+ }
+ ret = clk_prepare(clock);
+ if (ret < 0) {
+ clk_put(clock);
+ fmd->camclk[i].clock = ERR_PTR(-EINVAL);
+ break;
}
fmd->camclk[i].clock = clock;
}
- return 0;
-}
-
-static void fimc_md_put_clocks(struct fimc_md *fmd)
-{
- int i = FIMC_MAX_CAMCLKS;
+ if (ret)
+ fimc_md_put_clocks(fmd);
- while (--i >= 0) {
- if (IS_ERR_OR_NULL(fmd->camclk[i].clock))
- continue;
- clk_put(fmd->camclk[i].clock);
- fmd->camclk[i].clock = NULL;
- }
+ return ret;
}
static int __fimc_md_set_camclk(struct fimc_md *fmd,
struct fimc_sensor_info *s_info,
bool on)
{
- struct s5p_fimc_isp_info *pdata = &s_info->pdata;
+ struct fimc_source_info *pdata = &s_info->pdata;
struct fimc_camclk_info *camclk;
int ret = 0;
@@ -820,7 +826,9 @@ static int fimc_md_link_notify(struct media_pad *source,
struct fimc_dev *fimc = NULL;
struct fimc_pipeline *pipeline;
struct v4l2_subdev *sd;
+ struct mutex *lock;
int ret = 0;
+ int ref_count;
if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
return 0;
@@ -828,28 +836,33 @@ static int fimc_md_link_notify(struct media_pad *source,
sd = media_entity_to_v4l2_subdev(sink->entity);
switch (sd->grp_id) {
- case FLITE_GROUP_ID:
+ case GRP_ID_FLITE:
fimc_lite = v4l2_get_subdevdata(sd);
+ if (WARN_ON(fimc_lite == NULL))
+ return 0;
pipeline = &fimc_lite->pipeline;
+ lock = &fimc_lite->lock;
break;
- case FIMC_GROUP_ID:
+ case GRP_ID_FIMC:
fimc = v4l2_get_subdevdata(sd);
+ if (WARN_ON(fimc == NULL))
+ return 0;
pipeline = &fimc->pipeline;
+ lock = &fimc->lock;
break;
default:
return 0;
}
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+ int i;
+ mutex_lock(lock);
ret = __fimc_pipeline_close(pipeline);
- pipeline->subdevs[IDX_SENSOR] = NULL;
- pipeline->subdevs[IDX_CSIS] = NULL;
-
- if (fimc) {
- mutex_lock(&fimc->lock);
+ for (i = 0; i < IDX_MAX; i++)
+ pipeline->subdevs[i] = NULL;
+ if (fimc)
fimc_ctrls_delete(fimc->vid_cap.ctx);
- mutex_unlock(&fimc->lock);
- }
+ mutex_unlock(lock);
return ret;
}
/*
@@ -857,23 +870,15 @@ static int fimc_md_link_notify(struct media_pad *source,
* pipeline is already in use, i.e. its video node is opened.
* Recreate the controls destroyed during the link deactivation.
*/
- if (fimc) {
- mutex_lock(&fimc->lock);
- if (fimc->vid_cap.refcnt > 0) {
- ret = __fimc_pipeline_open(pipeline,
- source->entity, true);
- if (!ret)
- ret = fimc_capture_ctrls_create(fimc);
- }
- mutex_unlock(&fimc->lock);
- } else {
- mutex_lock(&fimc_lite->lock);
- if (fimc_lite->ref_count > 0) {
- ret = __fimc_pipeline_open(pipeline,
- source->entity, true);
- }
- mutex_unlock(&fimc_lite->lock);
- }
+ mutex_lock(lock);
+
+ ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count;
+ if (ref_count > 0)
+ ret = __fimc_pipeline_open(pipeline, source->entity, true);
+ if (!ret && fimc)
+ ret = fimc_capture_ctrls_create(fimc);
+
+ mutex_unlock(lock);
return ret ? -EPIPE : ret;
}
@@ -965,7 +970,8 @@ static int fimc_md_probe(struct platform_device *pdev)
/* Protect the media graph while we're registering entities */
mutex_lock(&fmd->media_dev.graph_mutex);
- ret = fimc_md_register_platform_entities(fmd);
+ ret = bus_for_each_dev(&platform_bus_type, NULL, fmd,
+ fimc_md_pdev_match);
if (ret)
goto err_unlock;
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h
index 2d8d41d82620..06b0d8276fd2 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h
@@ -22,11 +22,13 @@
#include "mipi-csis.h"
/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */
-#define SENSOR_GROUP_ID (1 << 8)
-#define CSIS_GROUP_ID (1 << 9)
-#define WRITEBACK_GROUP_ID (1 << 10)
-#define FIMC_GROUP_ID (1 << 11)
-#define FLITE_GROUP_ID (1 << 12)
+#define GRP_ID_SENSOR (1 << 8)
+#define GRP_ID_FIMC_IS_SENSOR (1 << 9)
+#define GRP_ID_WRITEBACK (1 << 10)
+#define GRP_ID_CSIS (1 << 11)
+#define GRP_ID_FIMC (1 << 12)
+#define GRP_ID_FLITE (1 << 13)
+#define GRP_ID_FIMC_IS (1 << 14)
#define FIMC_MAX_SENSORS 8
#define FIMC_MAX_CAMCLKS 2
@@ -51,7 +53,7 @@ struct fimc_camclk_info {
* This data structure applies to image sensor and the writeback subdevs.
*/
struct fimc_sensor_info {
- struct s5p_fimc_isp_info pdata;
+ struct fimc_source_info pdata;
struct v4l2_subdev *subdev;
struct fimc_dev *host;
};
diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.c b/drivers/media/platform/s5p-fimc/fimc-reg.c
index 2c9d0c06c9e8..50b97c75b956 100644
--- a/drivers/media/platform/s5p-fimc/fimc-reg.c
+++ b/drivers/media/platform/s5p-fimc/fimc-reg.c
@@ -44,9 +44,9 @@ static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
u32 flip = FIMC_REG_MSCTRL_FLIP_NORMAL;
if (ctx->hflip)
- flip = FIMC_REG_MSCTRL_FLIP_X_MIRROR;
- if (ctx->vflip)
flip = FIMC_REG_MSCTRL_FLIP_Y_MIRROR;
+ if (ctx->vflip)
+ flip = FIMC_REG_MSCTRL_FLIP_X_MIRROR;
if (ctx->rotation <= 90)
return flip;
@@ -59,9 +59,9 @@ static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
u32 flip = FIMC_REG_CITRGFMT_FLIP_NORMAL;
if (ctx->hflip)
- flip |= FIMC_REG_CITRGFMT_FLIP_X_MIRROR;
- if (ctx->vflip)
flip |= FIMC_REG_CITRGFMT_FLIP_Y_MIRROR;
+ if (ctx->vflip)
+ flip |= FIMC_REG_CITRGFMT_FLIP_X_MIRROR;
if (ctx->rotation <= 90)
return flip;
@@ -312,7 +312,7 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
void fimc_hw_set_mainscaler(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
- struct fimc_variant *variant = dev->variant;
+ const struct fimc_variant *variant = dev->variant;
struct fimc_scaler *sc = &ctx->scaler;
u32 cfg;
@@ -344,30 +344,31 @@ void fimc_hw_set_mainscaler(struct fimc_ctx *ctx)
}
}
-void fimc_hw_en_capture(struct fimc_ctx *ctx)
+void fimc_hw_enable_capture(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
+ u32 cfg;
- u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
-
- if (ctx->out_path == FIMC_IO_DMA) {
- /* one shot mode */
- cfg |= FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE |
- FIMC_REG_CIIMGCPT_IMGCPTEN;
- } else {
- /* Continuous frame capture mode (freerun). */
- cfg &= ~(FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE |
- FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT);
- cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN;
- }
+ cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
+ cfg |= FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE;
if (ctx->scaler.enabled)
cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN_SC;
+ else
+ cfg &= FIMC_REG_CIIMGCPT_IMGCPTEN_SC;
cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN;
writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
}
+void fimc_hw_disable_capture(struct fimc_dev *dev)
+{
+ u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
+ cfg &= ~(FIMC_REG_CIIMGCPT_IMGCPTEN |
+ FIMC_REG_CIIMGCPT_IMGCPTEN_SC);
+ writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
+}
+
void fimc_hw_set_effect(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
@@ -553,7 +554,7 @@ void fimc_hw_set_output_addr(struct fimc_dev *dev,
}
int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
- struct s5p_fimc_isp_info *cam)
+ struct fimc_source_info *cam)
{
u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
@@ -595,14 +596,15 @@ static const struct mbus_pixfmt_desc pix_desc[] = {
};
int fimc_hw_set_camera_source(struct fimc_dev *fimc,
- struct s5p_fimc_isp_info *cam)
+ struct fimc_source_info *source)
{
struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
- u32 cfg = 0;
- u32 bus_width;
+ u32 bus_width, cfg = 0;
int i;
- if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
+ switch (source->fimc_bus_type) {
+ case FIMC_BUS_TYPE_ITU_601:
+ case FIMC_BUS_TYPE_ITU_656:
for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
cfg = pix_desc[i].cisrcfmt;
@@ -618,15 +620,17 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
return -EINVAL;
}
- if (cam->bus_type == FIMC_ITU_601) {
+ if (source->fimc_bus_type == FIMC_BUS_TYPE_ITU_601) {
if (bus_width == 8)
cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
else if (bus_width == 16)
cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT;
} /* else defaults to ITU-R BT.656 8-bit */
- } else if (cam->bus_type == FIMC_MIPI_CSI2) {
+ break;
+ case FIMC_BUS_TYPE_MIPI_CSI2:
if (fimc_fmt_is_user_defined(f->fmt->color))
cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
+ break;
}
cfg |= (f->o_width << 16) | f->o_height;
@@ -654,7 +658,7 @@ void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
}
int fimc_hw_set_camera_type(struct fimc_dev *fimc,
- struct s5p_fimc_isp_info *cam)
+ struct fimc_source_info *source)
{
u32 cfg, tmp;
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
@@ -667,11 +671,11 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB |
FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG);
- switch (cam->bus_type) {
- case FIMC_MIPI_CSI2:
+ switch (source->fimc_bus_type) {
+ case FIMC_BUS_TYPE_MIPI_CSI2:
cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI;
- if (cam->mux_id == 0)
+ if (source->mux_id == 0)
cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A;
/* TODO: add remaining supported formats. */
@@ -694,15 +698,16 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT);
break;
- case FIMC_ITU_601...FIMC_ITU_656:
- if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
+ case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656:
+ if (source->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A;
break;
- case FIMC_LCD_WB:
+ case FIMC_BUS_TYPE_LCD_WRITEBACK_A:
cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
break;
default:
- v4l2_err(&vid_cap->vfd, "Invalid camera bus type selected\n");
+ v4l2_err(&vid_cap->vfd, "Invalid FIMC bus type selected: %d\n",
+ source->fimc_bus_type);
return -EINVAL;
}
writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
@@ -737,13 +742,6 @@ void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
writel(cfg, dev->regs + FIMC_REG_MSCTRL);
}
-void fimc_hw_dis_capture(struct fimc_dev *dev)
-{
- u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
- cfg &= ~(FIMC_REG_CIIMGCPT_IMGCPTEN | FIMC_REG_CIIMGCPT_IMGCPTEN_SC);
- writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
-}
-
/* Return an index to the buffer actually being written. */
s32 fimc_hw_get_frame_index(struct fimc_dev *dev)
{
@@ -776,13 +774,13 @@ s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev)
void fimc_activate_capture(struct fimc_ctx *ctx)
{
fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
- fimc_hw_en_capture(ctx);
+ fimc_hw_enable_capture(ctx);
}
void fimc_deactivate_capture(struct fimc_dev *fimc)
{
fimc_hw_en_lastirq(fimc, true);
- fimc_hw_dis_capture(fimc);
+ fimc_hw_disable_capture(fimc);
fimc_hw_enable_scaler(fimc, false);
fimc_hw_en_lastirq(fimc, false);
}
diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.h b/drivers/media/platform/s5p-fimc/fimc-reg.h
index b6abfc7b72ac..1a40df6d1a80 100644
--- a/drivers/media/platform/s5p-fimc/fimc-reg.h
+++ b/drivers/media/platform/s5p-fimc/fimc-reg.h
@@ -287,7 +287,7 @@ void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
-void fimc_hw_en_capture(struct fimc_ctx *ctx);
+void fimc_hw_enable_capture(struct fimc_ctx *ctx);
void fimc_hw_set_effect(struct fimc_ctx *ctx);
void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx);
void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
@@ -297,16 +297,16 @@ void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
int index);
int fimc_hw_set_camera_source(struct fimc_dev *fimc,
- struct s5p_fimc_isp_info *cam);
+ struct fimc_source_info *cam);
void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
- struct s5p_fimc_isp_info *cam);
+ struct fimc_source_info *cam);
int fimc_hw_set_camera_type(struct fimc_dev *fimc,
- struct s5p_fimc_isp_info *cam);
+ struct fimc_source_info *cam);
void fimc_hw_clear_irq(struct fimc_dev *dev);
void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on);
void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on);
-void fimc_hw_dis_capture(struct fimc_dev *dev);
+void fimc_hw_disable_capture(struct fimc_dev *dev);
s32 fimc_hw_get_frame_index(struct fimc_dev *dev);
s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev);
void fimc_activate_capture(struct fimc_ctx *ctx);
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c
index ec3fa7d75306..981863d05aaa 100644
--- a/drivers/media/platform/s5p-fimc/mipi-csis.c
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.c
@@ -187,7 +187,7 @@ struct csis_state {
const struct csis_pix_format *csis_fmt;
struct v4l2_mbus_framefmt format;
- struct spinlock slock;
+ spinlock_t slock;
struct csis_pktbuf pkt_buf;
struct s5pcsis_event events[S5PCSIS_NUM_EVENTS];
};
@@ -220,6 +220,18 @@ static const struct csis_pix_format s5pcsis_formats[] = {
.code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8,
.fmt_reg = S5PCSIS_CFG_FMT_USER(1),
.data_alignment = 32,
+ }, {
+ .code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ .fmt_reg = S5PCSIS_CFG_FMT_RAW8,
+ .data_alignment = 24,
+ }, {
+ .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .fmt_reg = S5PCSIS_CFG_FMT_RAW10,
+ .data_alignment = 24,
+ }, {
+ .code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ .fmt_reg = S5PCSIS_CFG_FMT_RAW12,
+ .data_alignment = 24,
}
};
@@ -261,7 +273,8 @@ static void s5pcsis_reset(struct csis_state *state)
static void s5pcsis_system_enable(struct csis_state *state, int on)
{
- u32 val;
+ struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
+ u32 val, mask;
val = s5pcsis_read(state, S5PCSIS_CTRL);
if (on)
@@ -271,10 +284,11 @@ static void s5pcsis_system_enable(struct csis_state *state, int on)
s5pcsis_write(state, S5PCSIS_CTRL, val);
val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
- if (on)
- val |= S5PCSIS_DPHYCTRL_ENABLE;
- else
- val &= ~S5PCSIS_DPHYCTRL_ENABLE;
+ val &= ~S5PCSIS_DPHYCTRL_ENABLE;
+ if (on) {
+ mask = (1 << (pdata->lanes + 1)) - 1;
+ val |= (mask & S5PCSIS_DPHYCTRL_ENABLE);
+ }
s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
}
@@ -338,11 +352,11 @@ 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]))
+ if (IS_ERR(state->clock[i]))
continue;
clk_unprepare(state->clock[i]);
clk_put(state->clock[i]);
- state->clock[i] = NULL;
+ state->clock[i] = ERR_PTR(-EINVAL);
}
}
@@ -351,14 +365,19 @@ static int s5pcsis_clk_get(struct csis_state *state)
struct device *dev = &state->pdev->dev;
int i, ret;
+ for (i = 0; i < NUM_CSIS_CLOCKS; i++)
+ state->clock[i] = ERR_PTR(-EINVAL);
+
for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
state->clock[i] = clk_get(dev, csi_clock_name[i]);
- if (IS_ERR(state->clock[i]))
+ if (IS_ERR(state->clock[i])) {
+ ret = PTR_ERR(state->clock[i]);
goto err;
+ }
ret = clk_prepare(state->clock[i]);
if (ret < 0) {
clk_put(state->clock[i]);
- state->clock[i] = NULL;
+ state->clock[i] = ERR_PTR(-EINVAL);
goto err;
}
}
@@ -366,7 +385,31 @@ static int s5pcsis_clk_get(struct csis_state *state)
err:
s5pcsis_clk_put(state);
dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]);
- return -ENXIO;
+ return ret;
+}
+
+static void dump_regs(struct csis_state *state, const char *label)
+{
+ struct {
+ u32 offset;
+ const char * const name;
+ } registers[] = {
+ { 0x00, "CTRL" },
+ { 0x04, "DPHYCTRL" },
+ { 0x08, "CONFIG" },
+ { 0x0c, "DPHYSTS" },
+ { 0x10, "INTMSK" },
+ { 0x2c, "RESOL" },
+ { 0x38, "SDW_CONFIG" },
+ };
+ u32 i;
+
+ v4l2_info(&state->sd, "--- %s ---\n", label);
+
+ for (i = 0; i < ARRAY_SIZE(registers); i++) {
+ u32 cfg = s5pcsis_read(state, registers[i].offset);
+ v4l2_info(&state->sd, "%10s: 0x%08x\n", registers[i].name, cfg);
+ }
}
static void s5pcsis_start_stream(struct csis_state *state)
@@ -401,12 +444,12 @@ static void s5pcsis_log_counters(struct csis_state *state, bool non_errors)
spin_lock_irqsave(&state->slock, flags);
- for (i--; i >= 0; i--)
- if (state->events[i].counter >= 0)
+ for (i--; i >= 0; i--) {
+ if (state->events[i].counter > 0 || debug)
v4l2_info(&state->sd, "%s events: %d\n",
state->events[i].name,
state->events[i].counter);
-
+ }
spin_unlock_irqrestore(&state->slock, flags);
}
@@ -569,7 +612,11 @@ static int s5pcsis_log_status(struct v4l2_subdev *sd)
{
struct csis_state *state = sd_to_csis_state(sd);
+ mutex_lock(&state->lock);
s5pcsis_log_counters(state, true);
+ if (debug && (state->flags & ST_POWERED))
+ dump_regs(state, __func__);
+ mutex_unlock(&state->lock);
return 0;
}
@@ -686,11 +733,9 @@ static int s5pcsis_probe(struct platform_device *pdev)
}
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- state->regs = devm_request_and_ioremap(&pdev->dev, mem_res);
- if (state->regs == NULL) {
- dev_err(&pdev->dev, "Failed to request and remap io memory\n");
- return -ENXIO;
- }
+ state->regs = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(state->regs))
+ return PTR_ERR(state->regs);
state->irq = platform_get_irq(pdev, 0);
if (state->irq < 0) {
@@ -701,26 +746,32 @@ static int s5pcsis_probe(struct platform_device *pdev)
for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
state->supplies[i].supply = csis_supply_name[i];
- ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
+ ret = devm_regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
state->supplies);
if (ret)
return ret;
ret = s5pcsis_clk_get(state);
- if (ret)
- goto e_clkput;
+ if (ret < 0)
+ return ret;
- clk_enable(state->clock[CSIS_CLK_MUX]);
if (pdata->clk_rate)
- clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
+ ret = clk_set_rate(state->clock[CSIS_CLK_MUX],
+ pdata->clk_rate);
else
dev_WARN(&pdev->dev, "No clock frequency specified!\n");
+ if (ret < 0)
+ goto e_clkput;
+
+ ret = clk_enable(state->clock[CSIS_CLK_MUX]);
+ if (ret < 0)
+ goto e_clkput;
ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler,
0, dev_name(&pdev->dev), state);
if (ret) {
dev_err(&pdev->dev, "Interrupt request failed\n");
- goto e_regput;
+ goto e_clkdis;
}
v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
@@ -738,7 +789,7 @@ static int s5pcsis_probe(struct platform_device *pdev)
ret = media_entity_init(&state->sd.entity,
CSIS_PADS_NUM, state->pads, 0);
if (ret < 0)
- goto e_clkput;
+ goto e_clkdis;
/* This allows to retrieve the platform device id by the host driver */
v4l2_set_subdevdata(&state->sd, pdev);
@@ -751,10 +802,9 @@ static int s5pcsis_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
return 0;
-e_regput:
- regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
-e_clkput:
+e_clkdis:
clk_disable(state->clock[CSIS_CLK_MUX]);
+e_clkput:
s5pcsis_clk_put(state);
return ret;
}
@@ -861,7 +911,6 @@ static int s5pcsis_remove(struct platform_device *pdev)
clk_disable(state->clock[CSIS_CLK_MUX]);
pm_runtime_set_suspended(&pdev->dev);
s5pcsis_clk_put(state);
- regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
media_entity_cleanup(&state->sd.entity);
diff --git a/drivers/media/platform/s5p-g2d/g2d-hw.c b/drivers/media/platform/s5p-g2d/g2d-hw.c
index 5b86cbe408e2..e87bd93811d4 100644
--- a/drivers/media/platform/s5p-g2d/g2d-hw.c
+++ b/drivers/media/platform/s5p-g2d/g2d-hw.c
@@ -28,6 +28,7 @@ void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f)
{
u32 n;
+ w(0, SRC_SELECT_REG);
w(f->stride & 0xFFFF, SRC_STRIDE_REG);
n = f->o_height & 0xFFF;
@@ -52,6 +53,7 @@ void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f)
{
u32 n;
+ w(0, DST_SELECT_REG);
w(f->stride & 0xFFFF, DST_STRIDE_REG);
n = f->o_height & 0xFFF;
@@ -82,10 +84,14 @@ void g2d_set_flip(struct g2d_dev *d, u32 r)
w(r, SRC_MSK_DIRECT_REG);
}
-u32 g2d_cmd_stretch(u32 e)
+void g2d_set_v41_stretch(struct g2d_dev *d, struct g2d_frame *src,
+ struct g2d_frame *dst)
{
- e &= 1;
- return e << 4;
+ w(DEFAULT_SCALE_MODE, SRC_SCALE_CTRL_REG);
+
+ /* inversed scaling factor: src is numerator */
+ w((src->c_width << 16) / dst->c_width, SRC_XSCALE_REG);
+ w((src->c_height << 16) / dst->c_height, SRC_YSCALE_REG);
}
void g2d_set_cmd(struct g2d_dev *d, u32 c)
@@ -96,7 +102,9 @@ void g2d_set_cmd(struct g2d_dev *d, u32 c)
void g2d_start(struct g2d_dev *d)
{
/* Clear cache */
- w(0x7, CACHECTL_REG);
+ if (d->variant->hw_rev == TYPE_G2D_3X)
+ w(0x7, CACHECTL_REG);
+
/* Enable interrupt */
w(1, INTEN_REG);
/* Start G2D engine */
diff --git a/drivers/media/platform/s5p-g2d/g2d-regs.h b/drivers/media/platform/s5p-g2d/g2d-regs.h
index 02e1cf50da4e..9bf31ad35d47 100644
--- a/drivers/media/platform/s5p-g2d/g2d-regs.h
+++ b/drivers/media/platform/s5p-g2d/g2d-regs.h
@@ -35,6 +35,9 @@
#define SRC_COLOR_MODE_REG 0x030C /* Src Image Color Mode reg */
#define SRC_LEFT_TOP_REG 0x0310 /* Src Left Top Coordinate reg */
#define SRC_RIGHT_BOTTOM_REG 0x0314 /* Src Right Bottom Coordinate reg */
+#define SRC_SCALE_CTRL_REG 0x0328 /* Src Scaling type select */
+#define SRC_XSCALE_REG 0x032c /* Src X Scaling ratio */
+#define SRC_YSCALE_REG 0x0330 /* Src Y Scaling ratio */
/* Parameter Setting Registers (Dest) */
#define DST_SELECT_REG 0x0400 /* Dest Image Selection reg */
@@ -113,3 +116,7 @@
#define DEFAULT_WIDTH 100
#define DEFAULT_HEIGHT 100
+#define DEFAULT_SCALE_MODE (2 << 0)
+
+/* Command mode register values */
+#define CMD_V3_ENABLE_STRETCH (1 << 4)
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index 1bfbc325836b..aaaf276a5a6c 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -604,8 +604,13 @@ static void device_run(void *prv)
g2d_set_flip(dev, ctx->flip);
if (ctx->in.c_width != ctx->out.c_width ||
- ctx->in.c_height != ctx->out.c_height)
- cmd |= g2d_cmd_stretch(1);
+ ctx->in.c_height != ctx->out.c_height) {
+ if (dev->variant->hw_rev == TYPE_G2D_3X)
+ cmd |= CMD_V3_ENABLE_STRETCH;
+ else
+ g2d_set_v41_stretch(dev, &ctx->in, &ctx->out);
+ }
+
g2d_set_cmd(dev, cmd);
g2d_start(dev);
@@ -708,14 +713,12 @@ static int g2d_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dev->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (dev->regs == NULL) {
- dev_err(&pdev->dev, "Failed to obtain io memory\n");
- return -ENOENT;
- }
+ dev->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dev->regs))
+ return PTR_ERR(dev->regs);
dev->clk = clk_get(&pdev->dev, "sclk_fimg2d");
- if (IS_ERR_OR_NULL(dev->clk)) {
+ if (IS_ERR(dev->clk)) {
dev_err(&pdev->dev, "failed to get g2d clock\n");
return -ENXIO;
}
@@ -727,7 +730,7 @@ static int g2d_probe(struct platform_device *pdev)
}
dev->gate = clk_get(&pdev->dev, "fimg2d");
- if (IS_ERR_OR_NULL(dev->gate)) {
+ if (IS_ERR(dev->gate)) {
dev_err(&pdev->dev, "failed to get g2d clock gate\n");
ret = -ENXIO;
goto unprep_clk;
@@ -791,6 +794,7 @@ static int g2d_probe(struct platform_device *pdev)
}
def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
+ dev->variant = g2d_get_drv_data(pdev);
return 0;
@@ -830,9 +834,30 @@ static int g2d_remove(struct platform_device *pdev)
return 0;
}
+static struct g2d_variant g2d_drvdata_v3x = {
+ .hw_rev = TYPE_G2D_3X,
+};
+
+static struct g2d_variant g2d_drvdata_v4x = {
+ .hw_rev = TYPE_G2D_4X, /* Revision 4.1 for Exynos4X12 and Exynos5 */
+};
+
+static struct platform_device_id g2d_driver_ids[] = {
+ {
+ .name = "s5p-g2d",
+ .driver_data = (unsigned long)&g2d_drvdata_v3x,
+ }, {
+ .name = "s5p-g2d-v4x",
+ .driver_data = (unsigned long)&g2d_drvdata_v4x,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, g2d_driver_ids);
+
static struct platform_driver g2d_pdrv = {
.probe = g2d_probe,
.remove = g2d_remove,
+ .id_table = g2d_driver_ids,
.driver = {
.name = G2D_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/media/platform/s5p-g2d/g2d.h b/drivers/media/platform/s5p-g2d/g2d.h
index 6b765b0216c5..300ca05ba404 100644
--- a/drivers/media/platform/s5p-g2d/g2d.h
+++ b/drivers/media/platform/s5p-g2d/g2d.h
@@ -10,10 +10,13 @@
* License, or (at your option) any later version
*/
+#include <linux/platform_device.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#define G2D_NAME "s5p-g2d"
+#define TYPE_G2D_3X 3
+#define TYPE_G2D_4X 4
struct g2d_dev {
struct v4l2_device v4l2_dev;
@@ -27,6 +30,7 @@ struct g2d_dev {
struct clk *clk;
struct clk *gate;
struct g2d_ctx *curr;
+ struct g2d_variant *variant;
int irq;
wait_queue_head_t irq_queue;
};
@@ -53,7 +57,7 @@ struct g2d_frame {
struct g2d_ctx {
struct v4l2_fh fh;
struct g2d_dev *dev;
- struct v4l2_m2m_ctx *m2m_ctx;
+ struct v4l2_m2m_ctx *m2m_ctx;
struct g2d_frame in;
struct g2d_frame out;
struct v4l2_ctrl *ctrl_hflip;
@@ -70,6 +74,9 @@ struct g2d_fmt {
u32 hw;
};
+struct g2d_variant {
+ unsigned short hw_rev;
+};
void g2d_reset(struct g2d_dev *d);
void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f);
@@ -80,7 +87,11 @@ void g2d_start(struct g2d_dev *d);
void g2d_clear_int(struct g2d_dev *d);
void g2d_set_rop4(struct g2d_dev *d, u32 r);
void g2d_set_flip(struct g2d_dev *d, u32 r);
-u32 g2d_cmd_stretch(u32 e);
+void g2d_set_v41_stretch(struct g2d_dev *d,
+ struct g2d_frame *src, struct g2d_frame *dst);
void g2d_set_cmd(struct g2d_dev *d, u32 c);
-
+static inline struct g2d_variant *g2d_get_drv_data(struct platform_device *pdev)
+{
+ return (struct g2d_variant *)platform_get_device_id(pdev)->driver_data;
+}
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 17983c4c9a9a..3b023752bcb4 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1325,11 +1325,9 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
/* memory-mapped registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- jpeg->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (jpeg->regs == NULL) {
- dev_err(&pdev->dev, "Failed to obtain io memory\n");
- return -ENOENT;
- }
+ jpeg->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(jpeg->regs))
+ return PTR_ERR(jpeg->regs);
/* interrupt service routine registration */
jpeg->irq = ret = platform_get_irq(pdev, 0);
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
index 022b9b9baff9..8a4013e3aee7 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -62,7 +62,7 @@
*/
struct s5p_jpeg {
struct mutex lock;
- struct spinlock slock;
+ spinlock_t slock;
struct v4l2_device v4l2_dev;
struct video_device *vfd_encoder;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index 681bc6ba149d..e84703c314ce 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -21,6 +21,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-event.h>
#include <linux/workqueue.h>
+#include <linux/of.h>
#include <media/videobuf2-core.h>
#include "s5p_mfc_common.h"
#include "s5p_mfc_ctrl.h"
@@ -273,7 +274,6 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
struct s5p_mfc_buf *dst_buf;
size_t dspl_y_addr;
unsigned int frame_type;
- unsigned int index;
dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev);
frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev);
@@ -310,7 +310,6 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
vb2_buffer_done(dst_buf->b,
err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
- index = dst_buf->b->v4l2_buf.index;
break;
}
}
@@ -326,8 +325,6 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
unsigned long flags;
unsigned int res_change;
- unsigned int index;
-
dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev)
& S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
res_change = (s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev)
@@ -387,7 +384,6 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
mfc_debug(2, "Running again the same buffer\n");
ctx->after_packed_pb = 1;
} else {
- index = src_buf->b->v4l2_buf.index;
mfc_debug(2, "MFC needs next buffer\n");
ctx->consumed_stream = 0;
list_del(&src_buf->list);
@@ -586,8 +582,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx,
clear_work_bit(ctx);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- WARN_ON(1);
+ WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
wake_up(&ctx->queue);
@@ -676,6 +671,12 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
s5p_mfc_handle_stream_complete(ctx, reason, err);
break;
+ case S5P_MFC_R2H_CMD_DPB_FLUSH_RET:
+ clear_work_bit(ctx);
+ ctx->state = MFCINST_RUNNING;
+ wake_up(&ctx->queue);
+ goto irq_cleanup_hw;
+
default:
mfc_debug(2, "Unknown int reason\n");
s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
@@ -777,14 +778,16 @@ static int s5p_mfc_open(struct file *file)
goto err_pwr_enable;
}
s5p_mfc_clock_on();
- ret = s5p_mfc_alloc_and_load_firmware(dev);
- if (ret)
- goto err_alloc_fw;
+ ret = s5p_mfc_load_firmware(dev);
+ if (ret) {
+ s5p_mfc_clock_off();
+ goto err_load_fw;
+ }
/* Init the FW */
ret = s5p_mfc_init_hw(dev);
+ s5p_mfc_clock_off();
if (ret)
goto err_init_hw;
- s5p_mfc_clock_off();
}
/* Init videobuf2 queue for CAPTURE */
q = &ctx->vq_dst;
@@ -833,21 +836,20 @@ static int s5p_mfc_open(struct file *file)
return ret;
/* Deinit when failure occured */
err_queue_init:
+ if (dev->num_inst == 1)
+ s5p_mfc_deinit_hw(dev);
err_init_hw:
- s5p_mfc_release_firmware(dev);
-err_alloc_fw:
- dev->ctx[ctx->num] = NULL;
- del_timer_sync(&dev->watchdog_timer);
- s5p_mfc_clock_off();
+err_load_fw:
err_pwr_enable:
if (dev->num_inst == 1) {
if (s5p_mfc_power_off() < 0)
mfc_err("power off failed\n");
- s5p_mfc_release_firmware(dev);
+ del_timer_sync(&dev->watchdog_timer);
}
err_ctrls_setup:
s5p_mfc_dec_ctrls_delete(ctx);
err_bad_node:
+ dev->ctx[ctx->num] = NULL;
err_no_ctx:
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
@@ -901,11 +903,8 @@ static int s5p_mfc_release(struct file *file)
clear_bit(0, &dev->hw_lock);
dev->num_inst--;
if (dev->num_inst == 0) {
- mfc_debug(2, "Last instance - release firmware\n");
- /* reset <-> F/W release */
- s5p_mfc_reset(dev);
+ mfc_debug(2, "Last instance\n");
s5p_mfc_deinit_hw(dev);
- s5p_mfc_release_firmware(dev);
del_timer_sync(&dev->watchdog_timer);
if (s5p_mfc_power_off() < 0)
mfc_err("Power off failed\n");
@@ -1013,6 +1012,48 @@ static int match_child(struct device *dev, void *data)
return !strcmp(dev_name(dev), (char *)data);
}
+static void *mfc_get_drv_data(struct platform_device *pdev);
+
+static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev)
+{
+ unsigned int mem_info[2];
+
+ dev->mem_dev_l = devm_kzalloc(&dev->plat_dev->dev,
+ sizeof(struct device), GFP_KERNEL);
+ if (!dev->mem_dev_l) {
+ mfc_err("Not enough memory\n");
+ return -ENOMEM;
+ }
+ device_initialize(dev->mem_dev_l);
+ of_property_read_u32_array(dev->plat_dev->dev.of_node,
+ "samsung,mfc-l", mem_info, 2);
+ if (dma_declare_coherent_memory(dev->mem_dev_l, mem_info[0],
+ mem_info[0], mem_info[1],
+ DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) {
+ mfc_err("Failed to declare coherent memory for\n"
+ "MFC device\n");
+ return -ENOMEM;
+ }
+
+ dev->mem_dev_r = devm_kzalloc(&dev->plat_dev->dev,
+ sizeof(struct device), GFP_KERNEL);
+ if (!dev->mem_dev_r) {
+ mfc_err("Not enough memory\n");
+ return -ENOMEM;
+ }
+ device_initialize(dev->mem_dev_r);
+ of_property_read_u32_array(dev->plat_dev->dev.of_node,
+ "samsung,mfc-r", mem_info, 2);
+ if (dma_declare_coherent_memory(dev->mem_dev_r, mem_info[0],
+ mem_info[0], mem_info[1],
+ DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) {
+ pr_err("Failed to declare coherent memory for\n"
+ "MFC device\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
/* MFC probe function */
static int s5p_mfc_probe(struct platform_device *pdev)
{
@@ -1036,8 +1077,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
return -ENODEV;
}
- dev->variant = (struct s5p_mfc_variant *)
- platform_get_device_id(pdev)->driver_data;
+ dev->variant = mfc_get_drv_data(pdev);
ret = s5p_mfc_init_pm(dev);
if (ret < 0) {
@@ -1047,11 +1087,9 @@ static int s5p_mfc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dev->regs_base = devm_request_and_ioremap(&pdev->dev, res);
- if (dev->regs_base == NULL) {
- dev_err(&pdev->dev, "Failed to obtain io memory\n");
- return -ENOENT;
- }
+ dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dev->regs_base))
+ return PTR_ERR(dev->regs_base);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
@@ -1067,35 +1105,43 @@ static int s5p_mfc_probe(struct platform_device *pdev)
goto err_res;
}
- dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, "s5p-mfc-l",
- match_child);
- if (!dev->mem_dev_l) {
- mfc_err("Mem child (L) device get failed\n");
- ret = -ENODEV;
- goto err_res;
- }
-
- dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r",
- match_child);
- if (!dev->mem_dev_r) {
- mfc_err("Mem child (R) device get failed\n");
- ret = -ENODEV;
- goto err_res;
+ if (pdev->dev.of_node) {
+ if (s5p_mfc_alloc_memdevs(dev) < 0)
+ goto err_res;
+ } else {
+ dev->mem_dev_l = device_find_child(&dev->plat_dev->dev,
+ "s5p-mfc-l", match_child);
+ if (!dev->mem_dev_l) {
+ mfc_err("Mem child (L) device get failed\n");
+ ret = -ENODEV;
+ goto err_res;
+ }
+ dev->mem_dev_r = device_find_child(&dev->plat_dev->dev,
+ "s5p-mfc-r", match_child);
+ if (!dev->mem_dev_r) {
+ mfc_err("Mem child (R) device get failed\n");
+ ret = -ENODEV;
+ goto err_res;
+ }
}
dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l);
- if (IS_ERR_OR_NULL(dev->alloc_ctx[0])) {
+ if (IS_ERR(dev->alloc_ctx[0])) {
ret = PTR_ERR(dev->alloc_ctx[0]);
goto err_res;
}
dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r);
- if (IS_ERR_OR_NULL(dev->alloc_ctx[1])) {
+ if (IS_ERR(dev->alloc_ctx[1])) {
ret = PTR_ERR(dev->alloc_ctx[1]);
goto err_mem_init_ctx_1;
}
mutex_init(&dev->mfc_mutex);
+ ret = s5p_mfc_alloc_firmware(dev);
+ if (ret)
+ goto err_alloc_fw;
+
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret)
goto err_v4l2_dev_reg;
@@ -1177,6 +1223,8 @@ err_dec_reg:
err_dec_alloc:
v4l2_device_unregister(&dev->v4l2_dev);
err_v4l2_dev_reg:
+ s5p_mfc_release_firmware(dev);
+err_alloc_fw:
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
err_mem_init_ctx_1:
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
@@ -1202,8 +1250,13 @@ static int s5p_mfc_remove(struct platform_device *pdev)
video_unregister_device(dev->vfd_enc);
video_unregister_device(dev->vfd_dec);
v4l2_device_unregister(&dev->v4l2_dev);
+ s5p_mfc_release_firmware(dev);
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
+ if (pdev->dev.of_node) {
+ put_device(dev->mem_dev_l);
+ put_device(dev->mem_dev_r);
+ }
s5p_mfc_final_pm(dev);
return 0;
@@ -1352,6 +1405,35 @@ static struct platform_device_id mfc_driver_ids[] = {
};
MODULE_DEVICE_TABLE(platform, mfc_driver_ids);
+static const struct of_device_id exynos_mfc_match[] = {
+ {
+ .compatible = "samsung,mfc-v5",
+ .data = &mfc_drvdata_v5,
+ }, {
+ .compatible = "samsung,mfc-v6",
+ .data = &mfc_drvdata_v6,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_mfc_match);
+
+static void *mfc_get_drv_data(struct platform_device *pdev)
+{
+ struct s5p_mfc_variant *driver_data = NULL;
+
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(of_match_ptr(exynos_mfc_match),
+ pdev->dev.of_node);
+ if (match)
+ driver_data = (struct s5p_mfc_variant *)match->data;
+ } else {
+ driver_data = (struct s5p_mfc_variant *)
+ platform_get_device_id(pdev)->driver_data;
+ }
+ return driver_data;
+}
+
static struct platform_driver s5p_mfc_driver = {
.probe = s5p_mfc_probe,
.remove = s5p_mfc_remove,
@@ -1359,7 +1441,8 @@ static struct platform_driver s5p_mfc_driver = {
.driver = {
.name = S5P_MFC_NAME,
.owner = THIS_MODULE,
- .pm = &s5p_mfc_pm_ops
+ .pm = &s5p_mfc_pm_ops,
+ .of_match_table = exynos_mfc_match,
},
};
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index f02e0497ca98..202d1d7a37a8 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -145,6 +145,7 @@ enum s5p_mfc_inst_state {
MFCINST_RETURN_INST,
MFCINST_ERROR,
MFCINST_ABORT,
+ MFCINST_FLUSH,
MFCINST_RES_CHANGE_INIT,
MFCINST_RES_CHANGE_FLUSH,
MFCINST_RES_CHANGE_END,
@@ -277,8 +278,9 @@ struct s5p_mfc_priv_buf {
* @int_err: error number for last interrupt
* @queue: waitqueue for waiting for completion of device commands
* @fw_size: size of firmware
- * @bank1: address of the beggining of bank 1 memory
- * @bank2: address of the beggining of bank 2 memory
+ * @fw_virt_addr: virtual firmware address
+ * @bank1: address of the beginning of bank 1 memory
+ * @bank2: address of the beginning of bank 2 memory
* @hw_lock: used for hardware locking
* @ctx: array of driver contexts
* @curr_ctx: number of the currently running context
@@ -317,8 +319,9 @@ struct s5p_mfc_dev {
unsigned int int_err;
wait_queue_head_t queue;
size_t fw_size;
- size_t bank1;
- size_t bank2;
+ void *fw_virt_addr;
+ dma_addr_t bank1;
+ dma_addr_t bank2;
unsigned long hw_lock;
struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS];
int curr_ctx;
@@ -493,15 +496,9 @@ struct s5p_mfc_codec_ops {
* flushed
* @head_processed: flag mentioning whether the header data is processed
* completely or not
- * @bank1_buf: handle to memory allocated for temporary buffers from
+ * @bank1: handle to memory allocated for temporary buffers from
* memory bank 1
- * @bank1_phys: address of the temporary buffers from memory bank 1
- * @bank1_size: size of the memory allocated for temporary buffers from
- * memory bank 1
- * @bank2_buf: handle to memory allocated for temporary buffers from
- * memory bank 2
- * @bank2_phys: address of the temporary buffers from memory bank 2
- * @bank2_size: size of the memory allocated for temporary buffers from
+ * @bank2: handle to memory allocated for temporary buffers from
* memory bank 2
* @capture_state: state of the capture buffers queue
* @output_state: state of the output buffers queue
@@ -581,14 +578,8 @@ struct s5p_mfc_ctx {
unsigned int dpb_flush_flag;
unsigned int head_processed;
- /* Buffers */
- void *bank1_buf;
- size_t bank1_phys;
- size_t bank1_size;
-
- void *bank2_buf;
- size_t bank2_phys;
- size_t bank2_size;
+ struct s5p_mfc_priv_buf bank1;
+ struct s5p_mfc_priv_buf bank2;
enum s5p_mfc_queue_state capture_state;
enum s5p_mfc_queue_state output_state;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
index 585b7b0ed8ec..2e5f30b40dea 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -22,16 +22,64 @@
#include "s5p_mfc_opr.h"
#include "s5p_mfc_pm.h"
-static void *s5p_mfc_bitproc_buf;
-static size_t s5p_mfc_bitproc_phys;
-static unsigned char *s5p_mfc_bitproc_virt;
+/* Allocate memory for firmware */
+int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
+{
+ void *bank2_virt;
+ dma_addr_t bank2_dma_addr;
+
+ dev->fw_size = dev->variant->buf_size->fw;
+
+ if (dev->fw_virt_addr) {
+ mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
+ return -ENOMEM;
+ }
+
+ dev->fw_virt_addr = dma_alloc_coherent(dev->mem_dev_l, dev->fw_size,
+ &dev->bank1, GFP_KERNEL);
+
+ if (IS_ERR(dev->fw_virt_addr)) {
+ dev->fw_virt_addr = NULL;
+ mfc_err("Allocating bitprocessor buffer failed\n");
+ return -ENOMEM;
+ }
+
+ dev->bank1 = dev->bank1;
+
+ if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) {
+ bank2_virt = dma_alloc_coherent(dev->mem_dev_r, 1 << MFC_BASE_ALIGN_ORDER,
+ &bank2_dma_addr, GFP_KERNEL);
+
+ if (IS_ERR(dev->fw_virt_addr)) {
+ mfc_err("Allocating bank2 base failed\n");
+ dma_free_coherent(dev->mem_dev_l, dev->fw_size,
+ dev->fw_virt_addr, dev->bank1);
+ dev->fw_virt_addr = NULL;
+ return -ENOMEM;
+ }
+
+ /* Valid buffers passed to MFC encoder with LAST_FRAME command
+ * should not have address of bank2 - MFC will treat it as a null frame.
+ * To avoid such situation we set bank2 address below the pool address.
+ */
+ dev->bank2 = bank2_dma_addr - (1 << MFC_BASE_ALIGN_ORDER);
+
+ dma_free_coherent(dev->mem_dev_r, 1 << MFC_BASE_ALIGN_ORDER,
+ bank2_virt, bank2_dma_addr);
+
+ } else {
+ /* In this case bank2 can point to the same address as bank1.
+ * Firmware will always occupy the beggining of this area so it is
+ * impossible having a video frame buffer with zero address. */
+ dev->bank2 = dev->bank1;
+ }
+ return 0;
+}
-/* Allocate and load firmware */
-int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
+/* Load firmware */
+int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
{
struct firmware *fw_blob;
- size_t bank2_base_phys;
- void *b_base;
int err;
/* Firmare has to be present as a separate file or compiled
@@ -44,77 +92,17 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
return -EINVAL;
}
- dev->fw_size = dev->variant->buf_size->fw;
if (fw_blob->size > dev->fw_size) {
mfc_err("MFC firmware is too big to be loaded\n");
release_firmware(fw_blob);
return -ENOMEM;
}
- if (s5p_mfc_bitproc_buf) {
- mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
- release_firmware(fw_blob);
- return -ENOMEM;
- }
- s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size);
- if (IS_ERR(s5p_mfc_bitproc_buf)) {
- s5p_mfc_bitproc_buf = NULL;
- mfc_err("Allocating bitprocessor buffer failed\n");
+ if (!dev->fw_virt_addr) {
+ mfc_err("MFC firmware is not allocated\n");
release_firmware(fw_blob);
- return -ENOMEM;
- }
- s5p_mfc_bitproc_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], s5p_mfc_bitproc_buf);
- if (s5p_mfc_bitproc_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
- mfc_err("The base memory for bank 1 is not aligned to 128KB\n");
- vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = NULL;
- release_firmware(fw_blob);
- return -EIO;
- }
- s5p_mfc_bitproc_virt = vb2_dma_contig_memops.vaddr(s5p_mfc_bitproc_buf);
- if (!s5p_mfc_bitproc_virt) {
- mfc_err("Bitprocessor memory remap failed\n");
- vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = NULL;
- release_firmware(fw_blob);
- return -EIO;
- }
- dev->bank1 = s5p_mfc_bitproc_phys;
- if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) {
- b_base = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK2_ALLOC_CTX],
- 1 << MFC_BASE_ALIGN_ORDER);
- if (IS_ERR(b_base)) {
- vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = NULL;
- mfc_err("Allocating bank2 base failed\n");
- release_firmware(fw_blob);
- return -ENOMEM;
- }
- bank2_base_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base);
- vb2_dma_contig_memops.put(b_base);
- if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
- mfc_err("The base memory for bank 2 is not aligned to 128KB\n");
- vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = NULL;
- release_firmware(fw_blob);
- return -EIO;
- }
- /* Valid buffers passed to MFC encoder with LAST_FRAME command
- * should not have address of bank2 - MFC will treat it as a null frame.
- * To avoid such situation we set bank2 address below the pool address.
- */
- dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER);
- } else {
- dev->bank2 = dev->bank1;
+ return -EINVAL;
}
- memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+ memcpy(dev->fw_virt_addr, fw_blob->data, fw_blob->size);
wmb();
release_firmware(fw_blob);
mfc_debug_leave();
@@ -142,12 +130,12 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev)
release_firmware(fw_blob);
return -ENOMEM;
}
- if (s5p_mfc_bitproc_buf == NULL || s5p_mfc_bitproc_phys == 0) {
- mfc_err("MFC firmware is not allocated or was not mapped correctly\n");
+ if (!dev->fw_virt_addr) {
+ mfc_err("MFC firmware is not allocated\n");
release_firmware(fw_blob);
return -EINVAL;
}
- memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+ memcpy(dev->fw_virt_addr, fw_blob->data, fw_blob->size);
wmb();
release_firmware(fw_blob);
mfc_debug_leave();
@@ -159,12 +147,11 @@ int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
{
/* Before calling this function one has to make sure
* that MFC is no longer processing */
- if (!s5p_mfc_bitproc_buf)
+ if (!dev->fw_virt_addr)
return -EINVAL;
- vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_virt = NULL;
- s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = NULL;
+ dma_free_coherent(dev->mem_dev_l, dev->fw_size, dev->fw_virt_addr,
+ dev->bank1);
+ dev->fw_virt_addr = NULL;
return 0;
}
@@ -257,8 +244,10 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
int ret;
mfc_debug_enter();
- if (!s5p_mfc_bitproc_buf)
+ if (!dev->fw_virt_addr) {
+ mfc_err("Firmware memory is not allocated.\n");
return -EINVAL;
+ }
/* 0. MFC reset */
mfc_debug(2, "MFC reset..\n");
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
index 90aa9b9886d5..6a9b6f8606bb 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
@@ -16,7 +16,8 @@
#include "s5p_mfc_common.h"
int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev);
-int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev);
int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev);
int s5p_mfc_init_hw(struct s5p_mfc_dev *dev);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 6dad9a74f61c..4582473978ca 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -991,24 +991,35 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q)
S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0);
aborted = 1;
}
- spin_lock_irqsave(&dev->irqlock, flags);
if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ spin_lock_irqsave(&dev->irqlock, flags);
s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
&ctx->vq_dst);
INIT_LIST_HEAD(&ctx->dst_queue);
ctx->dst_queue_cnt = 0;
ctx->dpb_flush_flag = 1;
ctx->dec_dst_flag = 0;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ if (IS_MFCV6(dev) && (ctx->state == MFCINST_RUNNING)) {
+ ctx->state = MFCINST_FLUSH;
+ set_work_bit_irqsave(ctx);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0))
+ mfc_err("Err flushing buffers\n");
+ }
}
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ spin_lock_irqsave(&dev->irqlock, flags);
s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
&ctx->vq_src);
INIT_LIST_HEAD(&ctx->src_queue);
ctx->src_queue_cnt = 0;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
}
if (aborted)
ctx->state = MFCINST_RUNNING;
- spin_unlock_irqrestore(&dev->irqlock, flags);
return 0;
}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index f92f6ddd739f..2356fd52a169 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -1534,6 +1534,8 @@ int vidioc_encoder_cmd(struct file *file, void *priv,
if (list_empty(&ctx->src_queue)) {
mfc_debug(2, "EOS: empty src queue, entering finishing state");
ctx->state = MFCINST_FINISHING;
+ if (s5p_mfc_ctx_ready(ctx))
+ set_work_bit_irqsave(ctx);
spin_unlock_irqrestore(&dev->irqlock, flags);
s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
} else {
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
index 6932e90d4065..10f8ac37cecd 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
@@ -12,6 +12,7 @@
* published by the Free Software Foundation.
*/
+#include "s5p_mfc_debug.h"
#include "s5p_mfc_opr.h"
#include "s5p_mfc_opr_v5.h"
#include "s5p_mfc_opr_v6.h"
@@ -29,3 +30,32 @@ void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev)
}
dev->mfc_ops = s5p_mfc_ops;
}
+
+int s5p_mfc_alloc_priv_buf(struct device *dev,
+ struct s5p_mfc_priv_buf *b)
+{
+
+ mfc_debug(3, "Allocating priv: %d\n", b->size);
+
+ b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL);
+
+ if (!b->virt) {
+ mfc_err("Allocating private buffer failed\n");
+ return -ENOMEM;
+ }
+
+ mfc_debug(3, "Allocated addr %p %08x\n", b->virt, b->dma);
+ return 0;
+}
+
+void s5p_mfc_release_priv_buf(struct device *dev,
+ struct s5p_mfc_priv_buf *b)
+{
+ if (b->virt) {
+ dma_free_coherent(dev, b->size, b->virt, b->dma);
+ b->virt = NULL;
+ b->dma = 0;
+ b->size = 0;
+ }
+}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
index 420abecafec0..754c540e7a7e 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
@@ -80,5 +80,10 @@ struct s5p_mfc_hw_ops {
};
void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev);
+int s5p_mfc_alloc_priv_buf(struct device *dev,
+ struct s5p_mfc_priv_buf *b);
+void s5p_mfc_release_priv_buf(struct device *dev,
+ struct s5p_mfc_priv_buf *b);
+
#endif /* S5P_MFC_OPR_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index bf7d010a4107..f61dba837899 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -38,39 +38,26 @@ int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv;
+ int ret;
- ctx->dsc.alloc = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX],
- buf_size->dsc);
- if (IS_ERR_VALUE((int)ctx->dsc.alloc)) {
- ctx->dsc.alloc = NULL;
- mfc_err("Allocating DESC buffer failed\n");
- return -ENOMEM;
+ ctx->dsc.size = buf_size->dsc;
+ ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &ctx->dsc);
+ if (ret) {
+ mfc_err("Failed to allocate temporary buffer\n");
+ return ret;
}
- ctx->dsc.dma = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->dsc.alloc);
+
BUG_ON(ctx->dsc.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
- ctx->dsc.virt = vb2_dma_contig_memops.vaddr(ctx->dsc.alloc);
- if (ctx->dsc.virt == NULL) {
- vb2_dma_contig_memops.put(ctx->dsc.alloc);
- ctx->dsc.dma = 0;
- ctx->dsc.alloc = NULL;
- mfc_err("Remapping DESC buffer failed\n");
- return -ENOMEM;
- }
- memset(ctx->dsc.virt, 0, buf_size->dsc);
+ memset(ctx->dsc.virt, 0, ctx->dsc.size);
wmb();
return 0;
}
+
/* Release temporary buffers for decoding */
void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx)
{
- if (ctx->dsc.dma) {
- vb2_dma_contig_memops.put(ctx->dsc.alloc);
- ctx->dsc.alloc = NULL;
- ctx->dsc.dma = 0;
- }
+ s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->dsc);
}
/* Allocate codec buffers */
@@ -80,6 +67,7 @@ int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx)
unsigned int enc_ref_y_size = 0;
unsigned int enc_ref_c_size = 0;
unsigned int guard_width, guard_height;
+ int ret;
if (ctx->type == MFCINST_DECODER) {
mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n",
@@ -113,100 +101,93 @@ int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx)
/* Codecs have different memory requirements */
switch (ctx->codec_mode) {
case S5P_MFC_CODEC_H264_DEC:
- ctx->bank1_size =
+ ctx->bank1.size =
ALIGN(S5P_FIMV_DEC_NB_IP_SIZE +
S5P_FIMV_DEC_VERT_NB_MV_SIZE,
S5P_FIMV_DEC_BUF_ALIGN);
- ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size;
+ ctx->bank2.size = ctx->total_dpb_count * ctx->mv_size;
break;
case S5P_MFC_CODEC_MPEG4_DEC:
- ctx->bank1_size =
+ ctx->bank1.size =
ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE +
S5P_FIMV_DEC_UPNB_MV_SIZE +
S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
S5P_FIMV_DEC_STX_PARSER_SIZE +
S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE,
S5P_FIMV_DEC_BUF_ALIGN);
- ctx->bank2_size = 0;
+ ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_VC1RCV_DEC:
case S5P_MFC_CODEC_VC1_DEC:
- ctx->bank1_size =
+ ctx->bank1.size =
ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
S5P_FIMV_DEC_UPNB_MV_SIZE +
S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
S5P_FIMV_DEC_NB_DCAC_SIZE +
3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE,
S5P_FIMV_DEC_BUF_ALIGN);
- ctx->bank2_size = 0;
+ ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_MPEG2_DEC:
- ctx->bank1_size = 0;
- ctx->bank2_size = 0;
+ ctx->bank1.size = 0;
+ ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_H263_DEC:
- ctx->bank1_size =
+ ctx->bank1.size =
ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
S5P_FIMV_DEC_UPNB_MV_SIZE +
S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
S5P_FIMV_DEC_NB_DCAC_SIZE,
S5P_FIMV_DEC_BUF_ALIGN);
- ctx->bank2_size = 0;
+ ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_H264_ENC:
- ctx->bank1_size = (enc_ref_y_size * 2) +
+ ctx->bank1.size = (enc_ref_y_size * 2) +
S5P_FIMV_ENC_UPMV_SIZE +
S5P_FIMV_ENC_COLFLG_SIZE +
S5P_FIMV_ENC_INTRAMD_SIZE +
S5P_FIMV_ENC_NBORINFO_SIZE;
- ctx->bank2_size = (enc_ref_y_size * 2) +
+ ctx->bank2.size = (enc_ref_y_size * 2) +
(enc_ref_c_size * 4) +
S5P_FIMV_ENC_INTRAPRED_SIZE;
break;
case S5P_MFC_CODEC_MPEG4_ENC:
- ctx->bank1_size = (enc_ref_y_size * 2) +
+ ctx->bank1.size = (enc_ref_y_size * 2) +
S5P_FIMV_ENC_UPMV_SIZE +
S5P_FIMV_ENC_COLFLG_SIZE +
S5P_FIMV_ENC_ACDCCOEF_SIZE;
- ctx->bank2_size = (enc_ref_y_size * 2) +
+ ctx->bank2.size = (enc_ref_y_size * 2) +
(enc_ref_c_size * 4);
break;
case S5P_MFC_CODEC_H263_ENC:
- ctx->bank1_size = (enc_ref_y_size * 2) +
+ ctx->bank1.size = (enc_ref_y_size * 2) +
S5P_FIMV_ENC_UPMV_SIZE +
S5P_FIMV_ENC_ACDCCOEF_SIZE;
- ctx->bank2_size = (enc_ref_y_size * 2) +
+ ctx->bank2.size = (enc_ref_y_size * 2) +
(enc_ref_c_size * 4);
break;
default:
break;
}
/* Allocate only if memory from bank 1 is necessary */
- if (ctx->bank1_size > 0) {
- ctx->bank1_buf = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size);
- if (IS_ERR(ctx->bank1_buf)) {
- ctx->bank1_buf = NULL;
- printk(KERN_ERR
- "Buf alloc for decoding failed (port A)\n");
- return -ENOMEM;
+ if (ctx->bank1.size > 0) {
+
+ ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &ctx->bank1);
+ if (ret) {
+ mfc_err("Failed to allocate Bank1 temporary buffer\n");
+ return ret;
}
- ctx->bank1_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf);
- BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+ BUG_ON(ctx->bank1.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
}
/* Allocate only if memory from bank 2 is necessary */
- if (ctx->bank2_size > 0) {
- ctx->bank2_buf = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size);
- if (IS_ERR(ctx->bank2_buf)) {
- ctx->bank2_buf = NULL;
- mfc_err("Buf alloc for decoding failed (port B)\n");
- return -ENOMEM;
+ if (ctx->bank2.size > 0) {
+ ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_r, &ctx->bank2);
+ if (ret) {
+ mfc_err("Failed to allocate Bank2 temporary buffer\n");
+ s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1);
+ return ret;
}
- ctx->bank2_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf);
- BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1));
+ BUG_ON(ctx->bank2.dma & ((1 << MFC_BANK2_ALIGN_ORDER) - 1));
}
return 0;
}
@@ -214,18 +195,8 @@ int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx)
/* Release buffers allocated for codec */
void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx)
{
- if (ctx->bank1_buf) {
- vb2_dma_contig_memops.put(ctx->bank1_buf);
- ctx->bank1_buf = NULL;
- ctx->bank1_phys = 0;
- ctx->bank1_size = 0;
- }
- if (ctx->bank2_buf) {
- vb2_dma_contig_memops.put(ctx->bank2_buf);
- ctx->bank2_buf = NULL;
- ctx->bank2_phys = 0;
- ctx->bank2_size = 0;
- }
+ s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1);
+ s5p_mfc_release_priv_buf(ctx->dev->mem_dev_r, &ctx->bank2);
}
/* Allocate memory for instance data buffer */
@@ -233,58 +204,38 @@ int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv;
+ int ret;
if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
ctx->codec_mode == S5P_MFC_CODEC_H264_ENC)
ctx->ctx.size = buf_size->h264_ctx;
else
ctx->ctx.size = buf_size->non_h264_ctx;
- ctx->ctx.alloc = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.size);
- if (IS_ERR(ctx->ctx.alloc)) {
- mfc_err("Allocating context buffer failed\n");
- ctx->ctx.alloc = NULL;
- return -ENOMEM;
+
+ ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &ctx->ctx);
+ if (ret) {
+ mfc_err("Failed to allocate instance buffer\n");
+ return ret;
}
- ctx->ctx.dma = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.alloc);
- BUG_ON(ctx->ctx.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
ctx->ctx.ofs = OFFSETA(ctx->ctx.dma);
- ctx->ctx.virt = vb2_dma_contig_memops.vaddr(ctx->ctx.alloc);
- if (!ctx->ctx.virt) {
- mfc_err("Remapping instance buffer failed\n");
- vb2_dma_contig_memops.put(ctx->ctx.alloc);
- ctx->ctx.alloc = NULL;
- ctx->ctx.ofs = 0;
- ctx->ctx.dma = 0;
- return -ENOMEM;
- }
+
/* Zero content of the allocated memory */
memset(ctx->ctx.virt, 0, ctx->ctx.size);
wmb();
/* Initialize shared memory */
- ctx->shm.alloc = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], buf_size->shm);
- if (IS_ERR(ctx->shm.alloc)) {
- mfc_err("failed to allocate shared memory\n");
- return PTR_ERR(ctx->shm.alloc);
+ ctx->shm.size = buf_size->shm;
+ ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &ctx->shm);
+ if (ret) {
+ mfc_err("Failed to allocate shared memory buffer\n");
+ return ret;
}
+
/* shared memory offset only keeps the offset from base (port a) */
- ctx->shm.ofs = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->shm.alloc)
- - dev->bank1;
+ ctx->shm.ofs = ctx->shm.dma - dev->bank1;
BUG_ON(ctx->shm.ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
- ctx->shm.virt = vb2_dma_contig_memops.vaddr(ctx->shm.alloc);
- if (!ctx->shm.virt) {
- vb2_dma_contig_memops.put(ctx->shm.alloc);
- ctx->shm.alloc = NULL;
- ctx->shm.ofs = 0;
- mfc_err("failed to virt addr of shared memory\n");
- return -ENOMEM;
- }
- memset((void *)ctx->shm.virt, 0, buf_size->shm);
+ memset(ctx->shm.virt, 0, buf_size->shm);
wmb();
return 0;
}
@@ -292,19 +243,8 @@ int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx)
/* Release instance buffer */
void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx)
{
- if (ctx->ctx.alloc) {
- vb2_dma_contig_memops.put(ctx->ctx.alloc);
- ctx->ctx.alloc = NULL;
- ctx->ctx.ofs = 0;
- ctx->ctx.virt = NULL;
- ctx->ctx.dma = 0;
- }
- if (ctx->shm.alloc) {
- vb2_dma_contig_memops.put(ctx->shm.alloc);
- ctx->shm.alloc = NULL;
- ctx->shm.ofs = 0;
- ctx->shm.virt = NULL;
- }
+ s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->ctx);
+ s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->shm);
}
int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev)
@@ -443,10 +383,10 @@ int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
size_t buf_addr1, buf_addr2;
int buf_size1, buf_size2;
- buf_addr1 = ctx->bank1_phys;
- buf_size1 = ctx->bank1_size;
- buf_addr2 = ctx->bank2_phys;
- buf_size2 = ctx->bank2_size;
+ buf_addr1 = ctx->bank1.dma;
+ buf_size1 = ctx->bank1.size;
+ buf_addr2 = ctx->bank2.dma;
+ buf_size2 = ctx->bank2.size;
dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
~S5P_FIMV_DPB_COUNT_MASK;
mfc_write(dev, ctx->total_dpb_count | dpb,
@@ -523,7 +463,6 @@ int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
mfc_err("Unknown codec for decoding (%x)\n",
ctx->codec_mode);
return -EINVAL;
- break;
}
frame_size = ctx->luma_size;
frame_size_ch = ctx->chroma_size;
@@ -607,10 +546,10 @@ int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
unsigned int guard_width, guard_height;
int i;
- buf_addr1 = ctx->bank1_phys;
- buf_size1 = ctx->bank1_size;
- buf_addr2 = ctx->bank2_phys;
- buf_size2 = ctx->bank2_size;
+ buf_addr1 = ctx->bank1.dma;
+ buf_size1 = ctx->bank1.size;
+ buf_addr2 = ctx->bank2.dma;
+ buf_size2 = ctx->bank2.size;
enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
* ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index 3a8cfd9fc1bd..beb6dbacebd9 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -73,6 +73,7 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
unsigned int mb_width, mb_height;
+ int ret;
mb_width = MB_WIDTH(ctx->img_width);
mb_height = MB_HEIGHT(ctx->img_height);
@@ -112,7 +113,7 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
- ctx->bank1_size =
+ ctx->bank1.size =
ctx->scratch_buf_size +
(ctx->mv_count * ctx->mv_size);
break;
@@ -123,7 +124,7 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
- ctx->bank1_size = ctx->scratch_buf_size;
+ ctx->bank1.size = ctx->scratch_buf_size;
break;
case S5P_MFC_CODEC_VC1RCV_DEC:
case S5P_MFC_CODEC_VC1_DEC:
@@ -133,11 +134,11 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
- ctx->bank1_size = ctx->scratch_buf_size;
+ ctx->bank1.size = ctx->scratch_buf_size;
break;
case S5P_MFC_CODEC_MPEG2_DEC:
- ctx->bank1_size = 0;
- ctx->bank2_size = 0;
+ ctx->bank1.size = 0;
+ ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_H263_DEC:
ctx->scratch_buf_size =
@@ -146,7 +147,7 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
- ctx->bank1_size = ctx->scratch_buf_size;
+ ctx->bank1.size = ctx->scratch_buf_size;
break;
case S5P_MFC_CODEC_VP8_DEC:
ctx->scratch_buf_size =
@@ -155,7 +156,7 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
- ctx->bank1_size = ctx->scratch_buf_size;
+ ctx->bank1.size = ctx->scratch_buf_size;
break;
case S5P_MFC_CODEC_H264_ENC:
ctx->scratch_buf_size =
@@ -164,11 +165,11 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
- ctx->bank1_size =
+ ctx->bank1.size =
ctx->scratch_buf_size + ctx->tmv_buffer_size +
(ctx->dpb_count * (ctx->luma_dpb_size +
ctx->chroma_dpb_size + ctx->me_buffer_size));
- ctx->bank2_size = 0;
+ ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_MPEG4_ENC:
case S5P_MFC_CODEC_H263_ENC:
@@ -178,28 +179,24 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
- ctx->bank1_size =
+ ctx->bank1.size =
ctx->scratch_buf_size + ctx->tmv_buffer_size +
(ctx->dpb_count * (ctx->luma_dpb_size +
ctx->chroma_dpb_size + ctx->me_buffer_size));
- ctx->bank2_size = 0;
+ ctx->bank2.size = 0;
break;
default:
break;
}
/* Allocate only if memory from bank 1 is necessary */
- if (ctx->bank1_size > 0) {
- ctx->bank1_buf = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size);
- if (IS_ERR(ctx->bank1_buf)) {
- ctx->bank1_buf = 0;
- pr_err("Buf alloc for decoding failed (port A)\n");
- return -ENOMEM;
+ if (ctx->bank1.size > 0) {
+ ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &ctx->bank1);
+ if (ret) {
+ mfc_err("Failed to allocate Bank1 memory\n");
+ return ret;
}
- ctx->bank1_phys = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf);
- BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+ BUG_ON(ctx->bank1.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
}
return 0;
@@ -208,12 +205,7 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
/* Release buffers allocated for codec */
void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
{
- if (ctx->bank1_buf) {
- vb2_dma_contig_memops.put(ctx->bank1_buf);
- ctx->bank1_buf = 0;
- ctx->bank1_phys = 0;
- ctx->bank1_size = 0;
- }
+ s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1);
}
/* Allocate memory for instance data buffer */
@@ -221,6 +213,7 @@ int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv;
+ int ret;
mfc_debug_enter();
@@ -250,25 +243,10 @@ int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
break;
}
- ctx->ctx.alloc = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.size);
- if (IS_ERR(ctx->ctx.alloc)) {
- mfc_err("Allocating context buffer failed.\n");
- return PTR_ERR(ctx->ctx.alloc);
- }
-
- ctx->ctx.dma = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.alloc);
-
- ctx->ctx.virt = vb2_dma_contig_memops.vaddr(ctx->ctx.alloc);
- if (!ctx->ctx.virt) {
- vb2_dma_contig_memops.put(ctx->ctx.alloc);
- ctx->ctx.alloc = NULL;
- ctx->ctx.dma = 0;
- ctx->ctx.virt = NULL;
-
- mfc_err("Remapping context buffer failed.\n");
- return -ENOMEM;
+ ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &ctx->ctx);
+ if (ret) {
+ mfc_err("Failed to allocate instance buffer\n");
+ return ret;
}
memset(ctx->ctx.virt, 0, ctx->ctx.size);
@@ -282,44 +260,22 @@ int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
/* Release instance buffer */
void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
{
- mfc_debug_enter();
-
- if (ctx->ctx.alloc) {
- vb2_dma_contig_memops.put(ctx->ctx.alloc);
- ctx->ctx.alloc = NULL;
- ctx->ctx.dma = 0;
- ctx->ctx.virt = NULL;
- }
-
- mfc_debug_leave();
+ s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->ctx);
}
/* Allocate context buffers for SYS_INIT */
int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv;
+ int ret;
mfc_debug_enter();
- dev->ctx_buf.alloc = vb2_dma_contig_memops.alloc(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], buf_size->dev_ctx);
- if (IS_ERR(dev->ctx_buf.alloc)) {
- mfc_err("Allocating DESC buffer failed.\n");
- return PTR_ERR(dev->ctx_buf.alloc);
- }
-
- dev->ctx_buf.dma = s5p_mfc_mem_cookie(
- dev->alloc_ctx[MFC_BANK1_ALLOC_CTX],
- dev->ctx_buf.alloc);
-
- dev->ctx_buf.virt = vb2_dma_contig_memops.vaddr(dev->ctx_buf.alloc);
- if (!dev->ctx_buf.virt) {
- vb2_dma_contig_memops.put(dev->ctx_buf.alloc);
- dev->ctx_buf.alloc = NULL;
- dev->ctx_buf.dma = 0;
-
- mfc_err("Remapping DESC buffer failed.\n");
- return -ENOMEM;
+ dev->ctx_buf.size = buf_size->dev_ctx;
+ ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &dev->ctx_buf);
+ if (ret) {
+ mfc_err("Failed to allocate device context buffer\n");
+ return ret;
}
memset(dev->ctx_buf.virt, 0, buf_size->dev_ctx);
@@ -333,12 +289,7 @@ int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev)
/* Release context buffers for SYS_INIT */
void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev)
{
- if (dev->ctx_buf.alloc) {
- vb2_dma_contig_memops.put(dev->ctx_buf.alloc);
- dev->ctx_buf.alloc = NULL;
- dev->ctx_buf.dma = 0;
- dev->ctx_buf.virt = NULL;
- }
+ s5p_mfc_release_priv_buf(dev->mem_dev_l, &dev->ctx_buf);
}
static int calc_plane(int width, int height)
@@ -417,8 +368,8 @@ int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
int buf_size1;
int align_gap;
- buf_addr1 = ctx->bank1_phys;
- buf_size1 = ctx->bank1_size;
+ buf_addr1 = ctx->bank1.dma;
+ buf_size1 = ctx->bank1.size;
mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1);
mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count);
@@ -535,13 +486,13 @@ void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
- size_t buf_addr1, buf_size1;
- int i;
+ size_t buf_addr1;
+ int i, buf_size1;
mfc_debug_enter();
- buf_addr1 = ctx->bank1_phys;
- buf_size1 = ctx->bank1_size;
+ buf_addr1 = ctx->bank1.dma;
+ buf_size1 = ctx->bank1.size;
mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1);
@@ -1253,12 +1204,14 @@ int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
{
struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int dpb;
- if (flush)
- dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (1 << 14);
- else
- dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & ~(1 << 14);
- WRITEL(dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+
+ if (flush) {
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6);
+ s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+ S5P_FIMV_H2R_CMD_FLUSH_V6, NULL);
+ }
}
/* Decode a single frame */
@@ -1408,7 +1361,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
struct s5p_mfc_buf *temp_vb;
unsigned long flags;
int last_frame = 0;
- unsigned int index;
spin_lock_irqsave(&dev->irqlock, flags);
@@ -1427,8 +1379,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
temp_vb->b->v4l2_planes[0].bytesused);
spin_unlock_irqrestore(&dev->irqlock, flags);
- index = temp_vb->b->v4l2_buf.index;
-
dev->curr_ctx = ctx->num;
s5p_mfc_clean_ctx_int_flags(ctx);
if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
@@ -1452,7 +1402,6 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
unsigned int src_y_size, src_c_size;
*/
unsigned int dst_size;
- unsigned int index;
spin_lock_irqsave(&dev->irqlock, flags);
@@ -1487,8 +1436,6 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
spin_unlock_irqrestore(&dev->irqlock, flags);
- index = src_mb->b->v4l2_buf.index;
-
dev->curr_ctx = ctx->num;
s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_encode_one_frame_v6(ctx);
@@ -1656,6 +1603,9 @@ void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev)
case MFCINST_HEAD_PARSED:
ret = s5p_mfc_run_init_dec_buffers(ctx);
break;
+ case MFCINST_FLUSH:
+ s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag);
+ break;
case MFCINST_RES_CHANGE_INIT:
s5p_mfc_run_dec_last_frames(ctx);
break;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
index 2895333866fc..6aa38a56aaf2 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -46,7 +46,7 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
ret = clk_prepare(pm->clock_gate);
if (ret) {
- mfc_err("Failed to preapre clock-gating control\n");
+ mfc_err("Failed to prepare clock-gating control\n");
goto err_p_ip_clk;
}
diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig
index ea11a513033f..7b659bd09bfd 100644
--- a/drivers/media/platform/s5p-tv/Kconfig
+++ b/drivers/media/platform/s5p-tv/Kconfig
@@ -7,9 +7,8 @@
# Licensed under GPL
config VIDEO_SAMSUNG_S5P_TV
- bool "Samsung TV driver for S5P platform (experimental)"
+ bool "Samsung TV driver for S5P platform"
depends on PLAT_S5P && PM_RUNTIME
- depends on EXPERIMENTAL
default n
---help---
Say Y here to enable selecting the TV output devices for
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
index 7c1116c73bf3..8de1b3dce459 100644
--- a/drivers/media/platform/s5p-tv/hdmi_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -656,7 +656,7 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
dev_dbg(hdev->dev, "%s\n", __func__);
if (!hdev->cur_conf)
return -EINVAL;
- memset(fmt, 0, sizeof *fmt);
+ memset(fmt, 0, sizeof(*fmt));
fmt->width = t->hact.end - t->hact.beg;
fmt->height = t->vact[0].end - t->vact[0].beg;
fmt->code = V4L2_MBUS_FMT_FIXED; /* means RGB888 */
@@ -760,7 +760,7 @@ static void hdmi_resources_cleanup(struct hdmi_device *hdev)
clk_put(res->sclk_hdmi);
if (!IS_ERR_OR_NULL(res->hdmi))
clk_put(res->hdmi);
- memset(res, 0, sizeof *res);
+ memset(res, 0, sizeof(*res));
}
static int hdmi_resources_init(struct hdmi_device *hdev)
@@ -777,31 +777,31 @@ static int hdmi_resources_init(struct hdmi_device *hdev)
dev_dbg(dev, "HDMI resource init\n");
- memset(res, 0, sizeof *res);
+ memset(res, 0, sizeof(*res));
/* get clocks, power */
res->hdmi = clk_get(dev, "hdmi");
- if (IS_ERR_OR_NULL(res->hdmi)) {
+ if (IS_ERR(res->hdmi)) {
dev_err(dev, "failed to get clock 'hdmi'\n");
goto fail;
}
res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
- if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+ if (IS_ERR(res->sclk_hdmi)) {
dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
goto fail;
}
res->sclk_pixel = clk_get(dev, "sclk_pixel");
- if (IS_ERR_OR_NULL(res->sclk_pixel)) {
+ if (IS_ERR(res->sclk_pixel)) {
dev_err(dev, "failed to get clock 'sclk_pixel'\n");
goto fail;
}
res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
- if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
+ if (IS_ERR(res->sclk_hdmiphy)) {
dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
goto fail;
}
res->hdmiphy = clk_get(dev, "hdmiphy");
- if (IS_ERR_OR_NULL(res->hdmiphy)) {
+ if (IS_ERR(res->hdmiphy)) {
dev_err(dev, "failed to get clock 'hdmiphy'\n");
goto fail;
}
@@ -955,7 +955,7 @@ static int hdmi_probe(struct platform_device *pdev)
v4l2_subdev_init(sd, &hdmi_sd_ops);
sd->owner = THIS_MODULE;
- strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
+ strlcpy(sd->name, "s5p-hdmi", sizeof(sd->name));
hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
/* FIXME: missing fail preset is not supported */
hdmi_dev->cur_conf = hdmi_preset2timings(hdmi_dev->cur_preset);
diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
index 06b5d2dbb2d9..80717cec76ae 100644
--- a/drivers/media/platform/s5p-tv/hdmiphy_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
@@ -284,7 +284,7 @@ static int hdmiphy_probe(struct i2c_client *client,
{
struct hdmiphy_ctx *ctx;
- ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
diff --git a/drivers/media/platform/s5p-tv/mixer.h b/drivers/media/platform/s5p-tv/mixer.h
index b671e20e9318..04e6490a45be 100644
--- a/drivers/media/platform/s5p-tv/mixer.h
+++ b/drivers/media/platform/s5p-tv/mixer.h
@@ -19,6 +19,7 @@
#endif
#include <linux/fb.h>
+#include <linux/irqreturn.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c
index 02faea03aa7d..5733033a6ead 100644
--- a/drivers/media/platform/s5p-tv/mixer_drv.c
+++ b/drivers/media/platform/s5p-tv/mixer_drv.c
@@ -240,27 +240,27 @@ static int mxr_acquire_clocks(struct mxr_device *mdev)
struct device *dev = mdev->dev;
res->mixer = clk_get(dev, "mixer");
- if (IS_ERR_OR_NULL(res->mixer)) {
+ if (IS_ERR(res->mixer)) {
mxr_err(mdev, "failed to get clock 'mixer'\n");
goto fail;
}
res->vp = clk_get(dev, "vp");
- if (IS_ERR_OR_NULL(res->vp)) {
+ if (IS_ERR(res->vp)) {
mxr_err(mdev, "failed to get clock 'vp'\n");
goto fail;
}
res->sclk_mixer = clk_get(dev, "sclk_mixer");
- if (IS_ERR_OR_NULL(res->sclk_mixer)) {
+ if (IS_ERR(res->sclk_mixer)) {
mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
goto fail;
}
res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
- if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+ if (IS_ERR(res->sclk_hdmi)) {
mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
goto fail;
}
res->sclk_dac = clk_get(dev, "sclk_dac");
- if (IS_ERR_OR_NULL(res->sclk_dac)) {
+ if (IS_ERR(res->sclk_dac)) {
mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
goto fail;
}
@@ -298,7 +298,7 @@ static void mxr_release_resources(struct mxr_device *mdev)
{
mxr_release_clocks(mdev);
mxr_release_plat_resources(mdev);
- memset(&mdev->res, 0, sizeof mdev->res);
+ memset(&mdev->res, 0, sizeof(mdev->res));
}
static void mxr_release_layers(struct mxr_device *mdev)
@@ -382,7 +382,7 @@ static int mxr_probe(struct platform_device *pdev)
/* mdev does not exist yet so no mxr_dbg is used */
dev_info(dev, "probe start\n");
- mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+ mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev) {
dev_err(dev, "not enough memory.\n");
ret = -ENOMEM;
diff --git a/drivers/media/platform/s5p-tv/mixer_reg.c b/drivers/media/platform/s5p-tv/mixer_reg.c
index 3b1670a045f4..b713403024ef 100644
--- a/drivers/media/platform/s5p-tv/mixer_reg.c
+++ b/drivers/media/platform/s5p-tv/mixer_reg.c
@@ -470,11 +470,11 @@ static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev,
static void mxr_reg_vp_default_filter(struct mxr_device *mdev)
{
mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL,
- filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
+ filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL,
- filter_y_vert_tap4, sizeof filter_y_vert_tap4);
+ filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL,
- filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
+ filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
}
static void mxr_reg_mxr_dump(struct mxr_device *mdev)
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
index 1f3b7436511c..82142a2d6d93 100644
--- a/drivers/media/platform/s5p-tv/mixer_video.c
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -19,6 +19,7 @@
#include <linux/videodev2.h>
#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/timer.h>
#include <media/videobuf2-dma-contig.h>
@@ -95,7 +96,7 @@ int mxr_acquire_video(struct mxr_device *mdev,
/* trying to register next output */
if (sd == NULL)
continue;
- out = kzalloc(sizeof *out, GFP_KERNEL);
+ out = kzalloc(sizeof(*out), GFP_KERNEL);
if (out == NULL) {
mxr_err(mdev, "no memory for '%s'\n",
conf->output_name);
@@ -127,7 +128,7 @@ fail_output:
/* kfree is NULL-safe */
for (i = 0; i < mdev->output_cnt; ++i)
kfree(mdev->output[i]);
- memset(mdev->output, 0, sizeof mdev->output);
+ memset(mdev->output, 0, sizeof(mdev->output));
fail_vb2_allocator:
/* freeing allocator context */
@@ -160,8 +161,8 @@ static int mxr_querycap(struct file *file, void *priv,
mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
- strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
- strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
+ strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, layer->vfd.name, sizeof(cap->card));
sprintf(cap->bus_info, "%d", layer->idx);
cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -192,7 +193,7 @@ static void mxr_layer_default_geo(struct mxr_layer *layer)
struct mxr_device *mdev = layer->mdev;
struct v4l2_mbus_framefmt mbus_fmt;
- memset(&layer->geo, 0, sizeof layer->geo);
+ memset(&layer->geo, 0, sizeof(layer->geo));
mxr_get_mbus_fmt(mdev, &mbus_fmt);
@@ -425,7 +426,7 @@ static int mxr_s_selection(struct file *file, void *fh,
struct mxr_geometry tmp;
struct v4l2_rect res;
- memset(&res, 0, sizeof res);
+ memset(&res, 0, sizeof(res));
mxr_dbg(layer->mdev, "%s: rect: %dx%d@%d,%d\n", __func__,
s->r.width, s->r.height, s->r.left, s->r.top);
@@ -464,7 +465,7 @@ static int mxr_s_selection(struct file *file, void *fh,
/* apply change and update geometry if needed */
if (target) {
/* backup current geometry if setup fails */
- memcpy(&tmp, geo, sizeof tmp);
+ memcpy(&tmp, geo, sizeof(tmp));
/* apply requested selection */
target->x_offset = s->r.left;
@@ -496,7 +497,7 @@ static int mxr_s_selection(struct file *file, void *fh,
fail:
/* restore old geometry, which is not touched if target is NULL */
if (target)
- memcpy(geo, &tmp, sizeof tmp);
+ memcpy(geo, &tmp, sizeof(tmp));
return -ERANGE;
}
@@ -1071,7 +1072,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
{
struct mxr_layer *layer;
- layer = kzalloc(sizeof *layer, GFP_KERNEL);
+ layer = kzalloc(sizeof(*layer), GFP_KERNEL);
if (layer == NULL) {
mxr_err(mdev, "not enough memory for layer.\n");
goto fail;
diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c
index 91a6939a270a..ab6f9ef89423 100644
--- a/drivers/media/platform/s5p-tv/sdo_drv.c
+++ b/drivers/media/platform/s5p-tv/sdo_drv.c
@@ -301,7 +301,7 @@ static int sdo_probe(struct platform_device *pdev)
struct clk *sclk_vpll;
dev_info(dev, "probe start\n");
- sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL);
+ sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
if (!sdev) {
dev_err(dev, "not enough memory.\n");
ret = -ENOMEM;
@@ -341,47 +341,50 @@ static int sdo_probe(struct platform_device *pdev)
/* acquire clocks */
sdev->sclk_dac = clk_get(dev, "sclk_dac");
- if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
+ if (IS_ERR(sdev->sclk_dac)) {
dev_err(dev, "failed to get clock 'sclk_dac'\n");
- ret = -ENXIO;
+ ret = PTR_ERR(sdev->sclk_dac);
goto fail;
}
sdev->dac = clk_get(dev, "dac");
- if (IS_ERR_OR_NULL(sdev->dac)) {
+ if (IS_ERR(sdev->dac)) {
dev_err(dev, "failed to get clock 'dac'\n");
- ret = -ENXIO;
+ ret = PTR_ERR(sdev->dac);
goto fail_sclk_dac;
}
sdev->dacphy = clk_get(dev, "dacphy");
- if (IS_ERR_OR_NULL(sdev->dacphy)) {
+ if (IS_ERR(sdev->dacphy)) {
dev_err(dev, "failed to get clock 'dacphy'\n");
- ret = -ENXIO;
+ ret = PTR_ERR(sdev->dacphy);
goto fail_dac;
}
sclk_vpll = clk_get(dev, "sclk_vpll");
- if (IS_ERR_OR_NULL(sclk_vpll)) {
+ if (IS_ERR(sclk_vpll)) {
dev_err(dev, "failed to get clock 'sclk_vpll'\n");
- ret = -ENXIO;
+ ret = PTR_ERR(sclk_vpll);
goto fail_dacphy;
}
clk_set_parent(sdev->sclk_dac, sclk_vpll);
clk_put(sclk_vpll);
sdev->fout_vpll = clk_get(dev, "fout_vpll");
- if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
+ if (IS_ERR(sdev->fout_vpll)) {
dev_err(dev, "failed to get clock 'fout_vpll'\n");
+ ret = PTR_ERR(sdev->fout_vpll);
goto fail_dacphy;
}
dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
/* acquire regulator */
sdev->vdac = devm_regulator_get(dev, "vdd33a_dac");
- if (IS_ERR_OR_NULL(sdev->vdac)) {
+ if (IS_ERR(sdev->vdac)) {
dev_err(dev, "failed to get regulator 'vdac'\n");
+ ret = PTR_ERR(sdev->vdac);
goto fail_fout_vpll;
}
sdev->vdet = devm_regulator_get(dev, "vdet");
- if (IS_ERR_OR_NULL(sdev->vdet)) {
+ if (IS_ERR(sdev->vdet)) {
dev_err(dev, "failed to get regulator 'vdet'\n");
+ ret = PTR_ERR(sdev->vdet);
goto fail_fout_vpll;
}
@@ -394,7 +397,7 @@ static int sdo_probe(struct platform_device *pdev)
/* configuration of interface subdevice */
v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
sdev->sd.owner = THIS_MODULE;
- strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
+ strlcpy(sdev->sd.name, "s5p-sdo", sizeof(sdev->sd.name));
/* set default format */
sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c
index 49191aac9634..d90d2286090b 100644
--- a/drivers/media/platform/s5p-tv/sii9234_drv.c
+++ b/drivers/media/platform/s5p-tv/sii9234_drv.c
@@ -338,7 +338,7 @@ static int sii9234_probe(struct i2c_client *client,
}
ctx->gpio_n_reset = pdata->gpio_n_reset;
- ret = gpio_request(ctx->gpio_n_reset, "MHL_RST");
+ ret = devm_gpio_request(dev, ctx->gpio_n_reset, "MHL_RST");
if (ret) {
dev_err(dev, "failed to acquire MHL_RST gpio\n");
return ret;
@@ -370,7 +370,6 @@ fail_pm_get:
fail_pm:
pm_runtime_disable(dev);
- gpio_free(ctx->gpio_n_reset);
fail:
dev_err(dev, "probe failed\n");
@@ -381,11 +380,8 @@ fail:
static int sii9234_remove(struct i2c_client *client)
{
struct device *dev = &client->dev;
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct sii9234_context *ctx = sd_to_context(sd);
pm_runtime_disable(dev);
- gpio_free(ctx->gpio_n_reset);
dev_info(dev, "remove successful\n");
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
new file mode 100644
index 000000000000..cb54c69d5748
--- /dev/null
+++ b/drivers/media/platform/sh_veu.c
@@ -0,0 +1,1266 @@
+/*
+ * sh-mobile VEU mem2mem driver
+ *
+ * Copyright (C) 2012 Renesas Electronics Corporation
+ * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License as
+ * published by the Free Software Foundation
+ */
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define VEU_STR 0x00 /* start register */
+#define VEU_SWR 0x10 /* src: line length */
+#define VEU_SSR 0x14 /* src: image size */
+#define VEU_SAYR 0x18 /* src: y/rgb plane address */
+#define VEU_SACR 0x1c /* src: c plane address */
+#define VEU_BSSR 0x20 /* bundle mode register */
+#define VEU_EDWR 0x30 /* dst: line length */
+#define VEU_DAYR 0x34 /* dst: y/rgb plane address */
+#define VEU_DACR 0x38 /* dst: c plane address */
+#define VEU_TRCR 0x50 /* transform control */
+#define VEU_RFCR 0x54 /* resize scale */
+#define VEU_RFSR 0x58 /* resize clip */
+#define VEU_ENHR 0x5c /* enhance */
+#define VEU_FMCR 0x70 /* filter mode */
+#define VEU_VTCR 0x74 /* lowpass vertical */
+#define VEU_HTCR 0x78 /* lowpass horizontal */
+#define VEU_APCR 0x80 /* color match */
+#define VEU_ECCR 0x84 /* color replace */
+#define VEU_AFXR 0x90 /* fixed mode */
+#define VEU_SWPR 0x94 /* swap */
+#define VEU_EIER 0xa0 /* interrupt mask */
+#define VEU_EVTR 0xa4 /* interrupt event */
+#define VEU_STAR 0xb0 /* status */
+#define VEU_BSRR 0xb4 /* reset */
+
+#define VEU_MCR00 0x200 /* color conversion matrix coefficient 00 */
+#define VEU_MCR01 0x204 /* color conversion matrix coefficient 01 */
+#define VEU_MCR02 0x208 /* color conversion matrix coefficient 02 */
+#define VEU_MCR10 0x20c /* color conversion matrix coefficient 10 */
+#define VEU_MCR11 0x210 /* color conversion matrix coefficient 11 */
+#define VEU_MCR12 0x214 /* color conversion matrix coefficient 12 */
+#define VEU_MCR20 0x218 /* color conversion matrix coefficient 20 */
+#define VEU_MCR21 0x21c /* color conversion matrix coefficient 21 */
+#define VEU_MCR22 0x220 /* color conversion matrix coefficient 22 */
+#define VEU_COFFR 0x224 /* color conversion offset */
+#define VEU_CBR 0x228 /* color conversion clip */
+
+/*
+ * 4092x4092 max size is the normal case. In some cases it can be reduced to
+ * 2048x2048, in other cases it can be 4092x8188 or even 8188x8188.
+ */
+#define MAX_W 4092
+#define MAX_H 4092
+#define MIN_W 8
+#define MIN_H 8
+#define ALIGN_W 4
+
+/* 3 buffers of 2048 x 1536 - 3 megapixels @ 16bpp */
+#define VIDEO_MEM_LIMIT ALIGN(2048 * 1536 * 2 * 3, 1024 * 1024)
+
+#define MEM2MEM_DEF_TRANSLEN 1
+
+struct sh_veu_dev;
+
+struct sh_veu_file {
+ struct sh_veu_dev *veu_dev;
+ bool cfg_needed;
+};
+
+struct sh_veu_format {
+ char *name;
+ u32 fourcc;
+ unsigned int depth;
+ unsigned int ydepth;
+};
+
+/* video data format */
+struct sh_veu_vfmt {
+ /* Replace with v4l2_rect */
+ struct v4l2_rect frame;
+ unsigned int bytesperline;
+ unsigned int offset_y;
+ unsigned int offset_c;
+ const struct sh_veu_format *fmt;
+};
+
+struct sh_veu_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct device *dev;
+ struct v4l2_m2m_ctx *m2m_ctx;
+ struct sh_veu_vfmt vfmt_out;
+ struct sh_veu_vfmt vfmt_in;
+ /* Only single user per direction so far */
+ struct sh_veu_file *capture;
+ struct sh_veu_file *output;
+ struct mutex fop_lock;
+ void __iomem *base;
+ struct vb2_alloc_ctx *alloc_ctx;
+ spinlock_t lock;
+ bool is_2h;
+ unsigned int xaction;
+ bool aborting;
+};
+
+enum sh_veu_fmt_idx {
+ SH_VEU_FMT_NV12,
+ SH_VEU_FMT_NV16,
+ SH_VEU_FMT_NV24,
+ SH_VEU_FMT_RGB332,
+ SH_VEU_FMT_RGB444,
+ SH_VEU_FMT_RGB565,
+ SH_VEU_FMT_RGB666,
+ SH_VEU_FMT_RGB24,
+};
+
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 480
+
+#define DEFAULT_IN_WIDTH VGA_WIDTH
+#define DEFAULT_IN_HEIGHT VGA_HEIGHT
+#define DEFAULT_IN_FMTIDX SH_VEU_FMT_NV12
+#define DEFAULT_OUT_WIDTH VGA_WIDTH
+#define DEFAULT_OUT_HEIGHT VGA_HEIGHT
+#define DEFAULT_OUT_FMTIDX SH_VEU_FMT_RGB565
+
+/*
+ * Alignment: Y-plane should be 4-byte aligned for NV12 and NV16, and 8-byte
+ * aligned for NV24.
+ */
+static const struct sh_veu_format sh_veu_fmt[] = {
+ [SH_VEU_FMT_NV12] = { .ydepth = 8, .depth = 12, .name = "NV12", .fourcc = V4L2_PIX_FMT_NV12 },
+ [SH_VEU_FMT_NV16] = { .ydepth = 8, .depth = 16, .name = "NV16", .fourcc = V4L2_PIX_FMT_NV16 },
+ [SH_VEU_FMT_NV24] = { .ydepth = 8, .depth = 24, .name = "NV24", .fourcc = V4L2_PIX_FMT_NV24 },
+ [SH_VEU_FMT_RGB332] = { .ydepth = 8, .depth = 8, .name = "RGB332", .fourcc = V4L2_PIX_FMT_RGB332 },
+ [SH_VEU_FMT_RGB444] = { .ydepth = 16, .depth = 16, .name = "RGB444", .fourcc = V4L2_PIX_FMT_RGB444 },
+ [SH_VEU_FMT_RGB565] = { .ydepth = 16, .depth = 16, .name = "RGB565", .fourcc = V4L2_PIX_FMT_RGB565 },
+ [SH_VEU_FMT_RGB666] = { .ydepth = 32, .depth = 32, .name = "BGR666", .fourcc = V4L2_PIX_FMT_BGR666 },
+ [SH_VEU_FMT_RGB24] = { .ydepth = 24, .depth = 24, .name = "RGB24", .fourcc = V4L2_PIX_FMT_RGB24 },
+};
+
+#define DEFAULT_IN_VFMT (struct sh_veu_vfmt){ \
+ .frame = { \
+ .width = VGA_WIDTH, \
+ .height = VGA_HEIGHT, \
+ }, \
+ .bytesperline = (VGA_WIDTH * sh_veu_fmt[DEFAULT_IN_FMTIDX].ydepth) >> 3, \
+ .fmt = &sh_veu_fmt[DEFAULT_IN_FMTIDX], \
+}
+
+#define DEFAULT_OUT_VFMT (struct sh_veu_vfmt){ \
+ .frame = { \
+ .width = VGA_WIDTH, \
+ .height = VGA_HEIGHT, \
+ }, \
+ .bytesperline = (VGA_WIDTH * sh_veu_fmt[DEFAULT_OUT_FMTIDX].ydepth) >> 3, \
+ .fmt = &sh_veu_fmt[DEFAULT_OUT_FMTIDX], \
+}
+
+/*
+ * TODO: add support for further output formats:
+ * SH_VEU_FMT_NV12,
+ * SH_VEU_FMT_NV16,
+ * SH_VEU_FMT_NV24,
+ * SH_VEU_FMT_RGB332,
+ * SH_VEU_FMT_RGB444,
+ * SH_VEU_FMT_RGB666,
+ * SH_VEU_FMT_RGB24,
+ */
+
+static const int sh_veu_fmt_out[] = {
+ SH_VEU_FMT_RGB565,
+};
+
+/*
+ * TODO: add support for further input formats:
+ * SH_VEU_FMT_NV16,
+ * SH_VEU_FMT_NV24,
+ * SH_VEU_FMT_RGB565,
+ * SH_VEU_FMT_RGB666,
+ * SH_VEU_FMT_RGB24,
+ */
+static const int sh_veu_fmt_in[] = {
+ SH_VEU_FMT_NV12,
+};
+
+static enum v4l2_colorspace sh_veu_4cc2cspace(u32 fourcc)
+{
+ switch (fourcc) {
+ default:
+ BUG();
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV24:
+ return V4L2_COLORSPACE_JPEG;
+ case V4L2_PIX_FMT_RGB332:
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_BGR666:
+ case V4L2_PIX_FMT_RGB24:
+ return V4L2_COLORSPACE_SRGB;
+ }
+}
+
+static u32 sh_veu_reg_read(struct sh_veu_dev *veu, unsigned int reg)
+{
+ return ioread32(veu->base + reg);
+}
+
+static void sh_veu_reg_write(struct sh_veu_dev *veu, unsigned int reg,
+ u32 value)
+{
+ iowrite32(value, veu->base + reg);
+}
+
+ /* ========== mem2mem callbacks ========== */
+
+static void sh_veu_job_abort(void *priv)
+{
+ struct sh_veu_dev *veu = priv;
+
+ /* Will cancel the transaction in the next interrupt handler */
+ veu->aborting = true;
+}
+
+static void sh_veu_lock(void *priv)
+{
+ struct sh_veu_dev *veu = priv;
+
+ mutex_lock(&veu->fop_lock);
+}
+
+static void sh_veu_unlock(void *priv)
+{
+ struct sh_veu_dev *veu = priv;
+
+ mutex_unlock(&veu->fop_lock);
+}
+
+static void sh_veu_process(struct sh_veu_dev *veu,
+ struct vb2_buffer *src_buf,
+ struct vb2_buffer *dst_buf)
+{
+ dma_addr_t addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+
+ sh_veu_reg_write(veu, VEU_DAYR, addr + veu->vfmt_out.offset_y);
+ sh_veu_reg_write(veu, VEU_DACR, veu->vfmt_out.offset_c ?
+ addr + veu->vfmt_out.offset_c : 0);
+ dev_dbg(veu->dev, "%s(): dst base %lx, y: %x, c: %x\n", __func__,
+ (unsigned long)addr,
+ veu->vfmt_out.offset_y, veu->vfmt_out.offset_c);
+
+ addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ sh_veu_reg_write(veu, VEU_SAYR, addr + veu->vfmt_in.offset_y);
+ sh_veu_reg_write(veu, VEU_SACR, veu->vfmt_in.offset_c ?
+ addr + veu->vfmt_in.offset_c : 0);
+ dev_dbg(veu->dev, "%s(): src base %lx, y: %x, c: %x\n", __func__,
+ (unsigned long)addr,
+ veu->vfmt_in.offset_y, veu->vfmt_in.offset_c);
+
+ sh_veu_reg_write(veu, VEU_STR, 1);
+
+ sh_veu_reg_write(veu, VEU_EIER, 1); /* enable interrupt in VEU */
+}
+
+/**
+ * sh_veu_device_run() - prepares and starts the device
+ *
+ * This will be called by the framework when it decides to schedule a particular
+ * instance.
+ */
+static void sh_veu_device_run(void *priv)
+{
+ struct sh_veu_dev *veu = priv;
+ struct vb2_buffer *src_buf, *dst_buf;
+
+ src_buf = v4l2_m2m_next_src_buf(veu->m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(veu->m2m_ctx);
+
+ if (src_buf && dst_buf)
+ sh_veu_process(veu, src_buf, dst_buf);
+}
+
+ /* ========== video ioctls ========== */
+
+static bool sh_veu_is_streamer(struct sh_veu_dev *veu, struct sh_veu_file *veu_file,
+ enum v4l2_buf_type type)
+{
+ return (type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ veu_file == veu->capture) ||
+ (type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ veu_file == veu->output);
+}
+
+static int sh_veu_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq);
+
+/*
+ * It is not unusual to have video nodes open()ed multiple times. While some
+ * V4L2 operations are non-intrusive, like querying formats and various
+ * parameters, others, like setting formats, starting and stopping streaming,
+ * queuing and dequeuing buffers, directly affect hardware configuration and /
+ * or execution. This function verifies availability of the requested interface
+ * and, if available, reserves it for the requesting user.
+ */
+static int sh_veu_stream_init(struct sh_veu_dev *veu, struct sh_veu_file *veu_file,
+ enum v4l2_buf_type type)
+{
+ struct sh_veu_file **stream;
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ stream = &veu->capture;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ stream = &veu->output;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (*stream == veu_file)
+ return 0;
+
+ if (*stream)
+ return -EBUSY;
+
+ *stream = veu_file;
+
+ return 0;
+}
+
+static int sh_veu_context_init(struct sh_veu_dev *veu)
+{
+ if (veu->m2m_ctx)
+ return 0;
+
+ veu->m2m_ctx = v4l2_m2m_ctx_init(veu->m2m_dev, veu,
+ sh_veu_queue_init);
+
+ if (IS_ERR(veu->m2m_ctx))
+ return PTR_ERR(veu->m2m_ctx);
+
+ return 0;
+}
+
+static int sh_veu_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strlcpy(cap->driver, "sh-veu", sizeof(cap->driver));
+ strlcpy(cap->card, "sh-mobile VEU", sizeof(cap->card));
+ strlcpy(cap->bus_info, "platform:sh-veu", sizeof(cap->bus_info));
+ cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+static int sh_veu_enum_fmt(struct v4l2_fmtdesc *f, const int *fmt, int fmt_num)
+{
+ if (f->index >= fmt_num)
+ return -EINVAL;
+
+ strlcpy(f->description, sh_veu_fmt[fmt[f->index]].name, sizeof(f->description));
+ f->pixelformat = sh_veu_fmt[fmt[f->index]].fourcc;
+ return 0;
+}
+
+static int sh_veu_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return sh_veu_enum_fmt(f, sh_veu_fmt_out, ARRAY_SIZE(sh_veu_fmt_out));
+}
+
+static int sh_veu_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return sh_veu_enum_fmt(f, sh_veu_fmt_in, ARRAY_SIZE(sh_veu_fmt_in));
+}
+
+static struct sh_veu_vfmt *sh_veu_get_vfmt(struct sh_veu_dev *veu,
+ enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return &veu->vfmt_out;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ return &veu->vfmt_in;
+ default:
+ return NULL;
+ }
+}
+
+static int sh_veu_g_fmt(struct sh_veu_file *veu_file, struct v4l2_format *f)
+{
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct sh_veu_dev *veu = veu_file->veu_dev;
+ struct sh_veu_vfmt *vfmt;
+
+ vfmt = sh_veu_get_vfmt(veu, f->type);
+
+ pix->width = vfmt->frame.width;
+ pix->height = vfmt->frame.height;
+ pix->field = V4L2_FIELD_NONE;
+ pix->pixelformat = vfmt->fmt->fourcc;
+ pix->colorspace = sh_veu_4cc2cspace(pix->pixelformat);
+ pix->bytesperline = vfmt->bytesperline;
+ pix->sizeimage = vfmt->bytesperline * pix->height *
+ vfmt->fmt->depth / vfmt->fmt->ydepth;
+ pix->priv = 0;
+ dev_dbg(veu->dev, "%s(): type: %d, size %u @ %ux%u, fmt %x\n", __func__,
+ f->type, pix->sizeimage, pix->width, pix->height, pix->pixelformat);
+
+ return 0;
+}
+
+static int sh_veu_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return sh_veu_g_fmt(priv, f);
+}
+
+static int sh_veu_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return sh_veu_g_fmt(priv, f);
+}
+
+static int sh_veu_try_fmt(struct v4l2_format *f, const struct sh_veu_format *fmt)
+{
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ unsigned int y_bytes_used;
+
+ /*
+ * V4L2 specification suggests, that the driver should correct the
+ * format struct if any of the dimensions is unsupported
+ */
+ switch (pix->field) {
+ default:
+ case V4L2_FIELD_ANY:
+ pix->field = V4L2_FIELD_NONE;
+ /* fall through: continue handling V4L2_FIELD_NONE */
+ case V4L2_FIELD_NONE:
+ break;
+ }
+
+ v4l_bound_align_image(&pix->width, MIN_W, MAX_W, ALIGN_W,
+ &pix->height, MIN_H, MAX_H, 0, 0);
+
+ y_bytes_used = (pix->width * fmt->ydepth) >> 3;
+
+ if (pix->bytesperline < y_bytes_used)
+ pix->bytesperline = y_bytes_used;
+ pix->sizeimage = pix->height * pix->bytesperline * fmt->depth / fmt->ydepth;
+
+ pix->pixelformat = fmt->fourcc;
+ pix->colorspace = sh_veu_4cc2cspace(pix->pixelformat);
+ pix->priv = 0;
+
+ pr_debug("%s(): type: %d, size %u\n", __func__, f->type, pix->sizeimage);
+
+ return 0;
+}
+
+static const struct sh_veu_format *sh_veu_find_fmt(const struct v4l2_format *f)
+{
+ const int *fmt;
+ int i, n, dflt;
+
+ pr_debug("%s(%d;%d)\n", __func__, f->type, f->fmt.pix.field);
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ fmt = sh_veu_fmt_out;
+ n = ARRAY_SIZE(sh_veu_fmt_out);
+ dflt = DEFAULT_OUT_FMTIDX;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ default:
+ fmt = sh_veu_fmt_in;
+ n = ARRAY_SIZE(sh_veu_fmt_in);
+ dflt = DEFAULT_IN_FMTIDX;
+ break;
+ }
+
+ for (i = 0; i < n; i++)
+ if (sh_veu_fmt[fmt[i]].fourcc == f->fmt.pix.pixelformat)
+ return &sh_veu_fmt[fmt[i]];
+
+ return &sh_veu_fmt[dflt];
+}
+
+static int sh_veu_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ const struct sh_veu_format *fmt;
+
+ fmt = sh_veu_find_fmt(f);
+ if (!fmt)
+ /* wrong buffer type */
+ return -EINVAL;
+
+ return sh_veu_try_fmt(f, fmt);
+}
+
+static int sh_veu_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ const struct sh_veu_format *fmt;
+
+ fmt = sh_veu_find_fmt(f);
+ if (!fmt)
+ /* wrong buffer type */
+ return -EINVAL;
+
+ return sh_veu_try_fmt(f, fmt);
+}
+
+static void sh_veu_colour_offset(struct sh_veu_dev *veu, struct sh_veu_vfmt *vfmt)
+{
+ /* dst_left and dst_top validity will be verified in CROP / COMPOSE */
+ unsigned int left = vfmt->frame.left & ~0x03;
+ unsigned int top = vfmt->frame.top;
+ dma_addr_t offset = ((left * veu->vfmt_out.fmt->depth) >> 3) +
+ top * veu->vfmt_out.bytesperline;
+ unsigned int y_line;
+
+ vfmt->offset_y = offset;
+
+ switch (vfmt->fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV24:
+ y_line = ALIGN(vfmt->frame.width, 16);
+ vfmt->offset_c = offset + y_line * vfmt->frame.height;
+ break;
+ case V4L2_PIX_FMT_RGB332:
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_BGR666:
+ case V4L2_PIX_FMT_RGB24:
+ vfmt->offset_c = 0;
+ break;
+ default:
+ BUG();
+ }
+}
+
+static int sh_veu_s_fmt(struct sh_veu_file *veu_file, struct v4l2_format *f)
+{
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct sh_veu_dev *veu = veu_file->veu_dev;
+ struct sh_veu_vfmt *vfmt;
+ struct vb2_queue *vq;
+ int ret = sh_veu_context_init(veu);
+ if (ret < 0)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(veu->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&veu_file->veu_dev->v4l2_dev, "%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ vfmt = sh_veu_get_vfmt(veu, f->type);
+ /* called after try_fmt(), hence vfmt != NULL. Implicit BUG_ON() below */
+
+ vfmt->fmt = sh_veu_find_fmt(f);
+ /* vfmt->fmt != NULL following the same argument as above */
+ vfmt->frame.width = pix->width;
+ vfmt->frame.height = pix->height;
+ vfmt->bytesperline = pix->bytesperline;
+
+ sh_veu_colour_offset(veu, vfmt);
+
+ /*
+ * We could also verify and require configuration only if any parameters
+ * actually have changed, but it is unlikely, that the user requests the
+ * same configuration several times without closing the device.
+ */
+ veu_file->cfg_needed = true;
+
+ dev_dbg(veu->dev,
+ "Setting format for type %d, wxh: %dx%d, fmt: %x\n",
+ f->type, pix->width, pix->height, vfmt->fmt->fourcc);
+
+ return 0;
+}
+
+static int sh_veu_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret = sh_veu_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ return sh_veu_s_fmt(priv, f);
+}
+
+static int sh_veu_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret = sh_veu_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ return sh_veu_s_fmt(priv, f);
+}
+
+static int sh_veu_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct sh_veu_file *veu_file = priv;
+ struct sh_veu_dev *veu = veu_file->veu_dev;
+ int ret = sh_veu_context_init(veu);
+ if (ret < 0)
+ return ret;
+
+ ret = sh_veu_stream_init(veu, veu_file, reqbufs->type);
+ if (ret < 0)
+ return ret;
+
+ return v4l2_m2m_reqbufs(file, veu->m2m_ctx, reqbufs);
+}
+
+static int sh_veu_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct sh_veu_file *veu_file = priv;
+
+ if (!sh_veu_is_streamer(veu_file->veu_dev, veu_file, buf->type))
+ return -EBUSY;
+
+ return v4l2_m2m_querybuf(file, veu_file->veu_dev->m2m_ctx, buf);
+}
+
+static int sh_veu_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct sh_veu_file *veu_file = priv;
+
+ dev_dbg(veu_file->veu_dev->dev, "%s(%d)\n", __func__, buf->type);
+ if (!sh_veu_is_streamer(veu_file->veu_dev, veu_file, buf->type))
+ return -EBUSY;
+
+ return v4l2_m2m_qbuf(file, veu_file->veu_dev->m2m_ctx, buf);
+}
+
+static int sh_veu_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct sh_veu_file *veu_file = priv;
+
+ dev_dbg(veu_file->veu_dev->dev, "%s(%d)\n", __func__, buf->type);
+ if (!sh_veu_is_streamer(veu_file->veu_dev, veu_file, buf->type))
+ return -EBUSY;
+
+ return v4l2_m2m_dqbuf(file, veu_file->veu_dev->m2m_ctx, buf);
+}
+
+static void sh_veu_calc_scale(struct sh_veu_dev *veu,
+ int size_in, int size_out, int crop_out,
+ u32 *mant, u32 *frac, u32 *rep)
+{
+ u32 fixpoint;
+
+ /* calculate FRAC and MANT */
+ *rep = *mant = *frac = 0;
+
+ if (size_in == size_out) {
+ if (crop_out != size_out)
+ *mant = 1; /* needed for cropping */
+ return;
+ }
+
+ /* VEU2H special upscale */
+ if (veu->is_2h && size_out > size_in) {
+ u32 fixpoint = (4096 * size_in) / size_out;
+ *mant = fixpoint / 4096;
+ *frac = (fixpoint - (*mant * 4096)) & ~0x07;
+
+ switch (*frac) {
+ case 0x800:
+ *rep = 1;
+ break;
+ case 0x400:
+ *rep = 3;
+ break;
+ case 0x200:
+ *rep = 7;
+ break;
+ }
+ if (*rep)
+ return;
+ }
+
+ fixpoint = (4096 * (size_in - 1)) / (size_out + 1);
+ *mant = fixpoint / 4096;
+ *frac = fixpoint - (*mant * 4096);
+
+ if (*frac & 0x07) {
+ /*
+ * FIXME: do we really have to round down twice in the
+ * up-scaling case?
+ */
+ *frac &= ~0x07;
+ if (size_out > size_in)
+ *frac -= 8; /* round down if scaling up */
+ else
+ *frac += 8; /* round up if scaling down */
+ }
+}
+
+static unsigned long sh_veu_scale_v(struct sh_veu_dev *veu,
+ int size_in, int size_out, int crop_out)
+{
+ u32 mant, frac, value, rep;
+
+ sh_veu_calc_scale(veu, size_in, size_out, crop_out, &mant, &frac, &rep);
+
+ /* set scale */
+ value = (sh_veu_reg_read(veu, VEU_RFCR) & ~0xffff0000) |
+ (((mant << 12) | frac) << 16);
+
+ sh_veu_reg_write(veu, VEU_RFCR, value);
+
+ /* set clip */
+ value = (sh_veu_reg_read(veu, VEU_RFSR) & ~0xffff0000) |
+ (((rep << 12) | crop_out) << 16);
+
+ sh_veu_reg_write(veu, VEU_RFSR, value);
+
+ return ALIGN((size_in * crop_out) / size_out, 4);
+}
+
+static unsigned long sh_veu_scale_h(struct sh_veu_dev *veu,
+ int size_in, int size_out, int crop_out)
+{
+ u32 mant, frac, value, rep;
+
+ sh_veu_calc_scale(veu, size_in, size_out, crop_out, &mant, &frac, &rep);
+
+ /* set scale */
+ value = (sh_veu_reg_read(veu, VEU_RFCR) & ~0xffff) |
+ (mant << 12) | frac;
+
+ sh_veu_reg_write(veu, VEU_RFCR, value);
+
+ /* set clip */
+ value = (sh_veu_reg_read(veu, VEU_RFSR) & ~0xffff) |
+ (rep << 12) | crop_out;
+
+ sh_veu_reg_write(veu, VEU_RFSR, value);
+
+ return ALIGN((size_in * crop_out) / size_out, 4);
+}
+
+static void sh_veu_configure(struct sh_veu_dev *veu)
+{
+ u32 src_width, src_stride, src_height;
+ u32 dst_width, dst_stride, dst_height;
+ u32 real_w, real_h;
+
+ /* reset VEU */
+ sh_veu_reg_write(veu, VEU_BSRR, 0x100);
+
+ src_width = veu->vfmt_in.frame.width;
+ src_height = veu->vfmt_in.frame.height;
+ src_stride = ALIGN(veu->vfmt_in.frame.width, 16);
+
+ dst_width = real_w = veu->vfmt_out.frame.width;
+ dst_height = real_h = veu->vfmt_out.frame.height;
+ /* Datasheet is unclear - whether it's always number of bytes or not */
+ dst_stride = veu->vfmt_out.bytesperline;
+
+ /*
+ * So far real_w == dst_width && real_h == dst_height, but it wasn't
+ * necessarily the case in the original vidix driver, so, it may change
+ * here in the future too.
+ */
+ src_width = sh_veu_scale_h(veu, src_width, real_w, dst_width);
+ src_height = sh_veu_scale_v(veu, src_height, real_h, dst_height);
+
+ sh_veu_reg_write(veu, VEU_SWR, src_stride);
+ sh_veu_reg_write(veu, VEU_SSR, src_width | (src_height << 16));
+ sh_veu_reg_write(veu, VEU_BSSR, 0); /* not using bundle mode */
+
+ sh_veu_reg_write(veu, VEU_EDWR, dst_stride);
+ sh_veu_reg_write(veu, VEU_DACR, 0); /* unused for RGB */
+
+ sh_veu_reg_write(veu, VEU_SWPR, 0x67);
+ sh_veu_reg_write(veu, VEU_TRCR, (6 << 16) | (0 << 14) | 2 | 4);
+
+ if (veu->is_2h) {
+ sh_veu_reg_write(veu, VEU_MCR00, 0x0cc5);
+ sh_veu_reg_write(veu, VEU_MCR01, 0x0950);
+ sh_veu_reg_write(veu, VEU_MCR02, 0x0000);
+
+ sh_veu_reg_write(veu, VEU_MCR10, 0x397f);
+ sh_veu_reg_write(veu, VEU_MCR11, 0x0950);
+ sh_veu_reg_write(veu, VEU_MCR12, 0x3ccd);
+
+ sh_veu_reg_write(veu, VEU_MCR20, 0x0000);
+ sh_veu_reg_write(veu, VEU_MCR21, 0x0950);
+ sh_veu_reg_write(veu, VEU_MCR22, 0x1023);
+
+ sh_veu_reg_write(veu, VEU_COFFR, 0x00800010);
+ }
+}
+
+static int sh_veu_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct sh_veu_file *veu_file = priv;
+
+ if (!sh_veu_is_streamer(veu_file->veu_dev, veu_file, type))
+ return -EBUSY;
+
+ if (veu_file->cfg_needed) {
+ struct sh_veu_dev *veu = veu_file->veu_dev;
+ veu_file->cfg_needed = false;
+ sh_veu_configure(veu_file->veu_dev);
+ veu->xaction = 0;
+ veu->aborting = false;
+ }
+
+ return v4l2_m2m_streamon(file, veu_file->veu_dev->m2m_ctx, type);
+}
+
+static int sh_veu_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct sh_veu_file *veu_file = priv;
+
+ if (!sh_veu_is_streamer(veu_file->veu_dev, veu_file, type))
+ return -EBUSY;
+
+ return v4l2_m2m_streamoff(file, veu_file->veu_dev->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops sh_veu_ioctl_ops = {
+ .vidioc_querycap = sh_veu_querycap,
+
+ .vidioc_enum_fmt_vid_cap = sh_veu_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = sh_veu_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = sh_veu_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = sh_veu_s_fmt_vid_cap,
+
+ .vidioc_enum_fmt_vid_out = sh_veu_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = sh_veu_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = sh_veu_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = sh_veu_s_fmt_vid_out,
+
+ .vidioc_reqbufs = sh_veu_reqbufs,
+ .vidioc_querybuf = sh_veu_querybuf,
+
+ .vidioc_qbuf = sh_veu_qbuf,
+ .vidioc_dqbuf = sh_veu_dqbuf,
+
+ .vidioc_streamon = sh_veu_streamon,
+ .vidioc_streamoff = sh_veu_streamoff,
+};
+
+ /* ========== Queue operations ========== */
+
+static int sh_veu_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *f,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct sh_veu_dev *veu = vb2_get_drv_priv(vq);
+ struct sh_veu_vfmt *vfmt;
+ unsigned int size, count = *nbuffers;
+
+ if (f) {
+ const struct v4l2_pix_format *pix = &f->fmt.pix;
+ const struct sh_veu_format *fmt = sh_veu_find_fmt(f);
+ struct v4l2_format ftmp = *f;
+
+ if (fmt->fourcc != pix->pixelformat)
+ return -EINVAL;
+ sh_veu_try_fmt(&ftmp, fmt);
+ if (ftmp.fmt.pix.width != pix->width ||
+ ftmp.fmt.pix.height != pix->height)
+ return -EINVAL;
+ size = pix->bytesperline ? pix->bytesperline * pix->height :
+ pix->width * pix->height * fmt->depth >> 3;
+ } else {
+ vfmt = sh_veu_get_vfmt(veu, vq->type);
+ size = vfmt->bytesperline * vfmt->frame.height;
+ }
+
+ if (count < 2)
+ *nbuffers = count = 2;
+
+ if (size * count > VIDEO_MEM_LIMIT) {
+ count = VIDEO_MEM_LIMIT / size;
+ *nbuffers = count;
+ }
+
+ *nplanes = 1;
+ sizes[0] = size;
+ alloc_ctxs[0] = veu->alloc_ctx;
+
+ dev_dbg(veu->dev, "get %d buffer(s) of size %d each.\n", count, size);
+
+ return 0;
+}
+
+static int sh_veu_buf_prepare(struct vb2_buffer *vb)
+{
+ struct sh_veu_dev *veu = vb2_get_drv_priv(vb->vb2_queue);
+ struct sh_veu_vfmt *vfmt;
+ unsigned int sizeimage;
+
+ vfmt = sh_veu_get_vfmt(veu, vb->vb2_queue->type);
+ sizeimage = vfmt->bytesperline * vfmt->frame.height *
+ vfmt->fmt->depth / vfmt->fmt->ydepth;
+
+ if (vb2_plane_size(vb, 0) < sizeimage) {
+ dev_dbg(veu->dev, "%s data will not fit into plane (%lu < %u)\n",
+ __func__, vb2_plane_size(vb, 0), sizeimage);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, sizeimage);
+
+ return 0;
+}
+
+static void sh_veu_buf_queue(struct vb2_buffer *vb)
+{
+ struct sh_veu_dev *veu = vb2_get_drv_priv(vb->vb2_queue);
+ dev_dbg(veu->dev, "%s(%d)\n", __func__, vb->v4l2_buf.type);
+ v4l2_m2m_buf_queue(veu->m2m_ctx, vb);
+}
+
+static void sh_veu_wait_prepare(struct vb2_queue *q)
+{
+ sh_veu_unlock(vb2_get_drv_priv(q));
+}
+
+static void sh_veu_wait_finish(struct vb2_queue *q)
+{
+ sh_veu_lock(vb2_get_drv_priv(q));
+}
+
+static const struct vb2_ops sh_veu_qops = {
+ .queue_setup = sh_veu_queue_setup,
+ .buf_prepare = sh_veu_buf_prepare,
+ .buf_queue = sh_veu_buf_queue,
+ .wait_prepare = sh_veu_wait_prepare,
+ .wait_finish = sh_veu_wait_finish,
+};
+
+static int sh_veu_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->drv_priv = priv;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &sh_veu_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret < 0)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->drv_priv = priv;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &sh_veu_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+ return vb2_queue_init(dst_vq);
+}
+
+ /* ========== File operations ========== */
+
+static int sh_veu_open(struct file *file)
+{
+ struct sh_veu_dev *veu = video_drvdata(file);
+ struct sh_veu_file *veu_file;
+
+ veu_file = kzalloc(sizeof(*veu_file), GFP_KERNEL);
+ if (!veu_file)
+ return -ENOMEM;
+
+ veu_file->veu_dev = veu;
+ veu_file->cfg_needed = true;
+
+ file->private_data = veu_file;
+
+ pm_runtime_get_sync(veu->dev);
+
+ dev_dbg(veu->dev, "Created instance %p\n", veu_file);
+
+ return 0;
+}
+
+static int sh_veu_release(struct file *file)
+{
+ struct sh_veu_dev *veu = video_drvdata(file);
+ struct sh_veu_file *veu_file = file->private_data;
+
+ dev_dbg(veu->dev, "Releasing instance %p\n", veu_file);
+
+ pm_runtime_put(veu->dev);
+
+ if (veu_file == veu->capture) {
+ veu->capture = NULL;
+ vb2_queue_release(v4l2_m2m_get_vq(veu->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE));
+ }
+
+ if (veu_file == veu->output) {
+ veu->output = NULL;
+ vb2_queue_release(v4l2_m2m_get_vq(veu->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT));
+ }
+
+ if (!veu->output && !veu->capture && veu->m2m_ctx) {
+ v4l2_m2m_ctx_release(veu->m2m_ctx);
+ veu->m2m_ctx = NULL;
+ }
+
+ kfree(veu_file);
+
+ return 0;
+}
+
+static unsigned int sh_veu_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct sh_veu_file *veu_file = file->private_data;
+
+ return v4l2_m2m_poll(file, veu_file->veu_dev->m2m_ctx, wait);
+}
+
+static int sh_veu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct sh_veu_file *veu_file = file->private_data;
+
+ return v4l2_m2m_mmap(file, veu_file->veu_dev->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations sh_veu_fops = {
+ .owner = THIS_MODULE,
+ .open = sh_veu_open,
+ .release = sh_veu_release,
+ .poll = sh_veu_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = sh_veu_mmap,
+};
+
+static const struct video_device sh_veu_videodev = {
+ .name = "sh-veu",
+ .fops = &sh_veu_fops,
+ .ioctl_ops = &sh_veu_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release_empty,
+ .vfl_dir = VFL_DIR_M2M,
+};
+
+static const struct v4l2_m2m_ops sh_veu_m2m_ops = {
+ .device_run = sh_veu_device_run,
+ .job_abort = sh_veu_job_abort,
+};
+
+static irqreturn_t sh_veu_bh(int irq, void *dev_id)
+{
+ struct sh_veu_dev *veu = dev_id;
+
+ if (veu->xaction == MEM2MEM_DEF_TRANSLEN || veu->aborting) {
+ v4l2_m2m_job_finish(veu->m2m_dev, veu->m2m_ctx);
+ veu->xaction = 0;
+ } else {
+ sh_veu_device_run(veu);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sh_veu_isr(int irq, void *dev_id)
+{
+ struct sh_veu_dev *veu = dev_id;
+ struct vb2_buffer *dst;
+ struct vb2_buffer *src;
+ u32 status = sh_veu_reg_read(veu, VEU_EVTR);
+
+ /* bundle read mode not used */
+ if (!(status & 1))
+ return IRQ_NONE;
+
+ /* disable interrupt in VEU */
+ sh_veu_reg_write(veu, VEU_EIER, 0);
+ /* halt operation */
+ sh_veu_reg_write(veu, VEU_STR, 0);
+ /* ack int, write 0 to clear bits */
+ sh_veu_reg_write(veu, VEU_EVTR, status & ~1);
+
+ /* conversion completed */
+ dst = v4l2_m2m_dst_buf_remove(veu->m2m_ctx);
+ src = v4l2_m2m_src_buf_remove(veu->m2m_ctx);
+ if (!src || !dst)
+ return IRQ_NONE;
+
+ spin_lock(&veu->lock);
+ v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
+ spin_unlock(&veu->lock);
+
+ veu->xaction++;
+
+ if (!veu->aborting)
+ return IRQ_WAKE_THREAD;
+
+ return IRQ_HANDLED;
+}
+
+static int sh_veu_probe(struct platform_device *pdev)
+{
+ struct sh_veu_dev *veu;
+ struct resource *reg_res;
+ struct video_device *vdev;
+ int irq, ret;
+
+ reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+
+ if (!reg_res || irq <= 0) {
+ dev_err(&pdev->dev, "Insufficient VEU platform information.\n");
+ return -ENODEV;
+ }
+
+ veu = devm_kzalloc(&pdev->dev, sizeof(*veu), GFP_KERNEL);
+ if (!veu)
+ return -ENOMEM;
+
+ veu->is_2h = resource_size(reg_res) == 0x22c;
+
+ veu->base = devm_request_and_ioremap(&pdev->dev, reg_res);
+ if (!veu->base)
+ return -ENOMEM;
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, sh_veu_isr, sh_veu_bh,
+ 0, "veu", veu);
+ if (ret < 0)
+ return ret;
+
+ ret = v4l2_device_register(&pdev->dev, &veu->v4l2_dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error registering v4l2 device\n");
+ return ret;
+ }
+
+ vdev = &veu->vdev;
+
+ veu->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(veu->alloc_ctx)) {
+ ret = PTR_ERR(veu->alloc_ctx);
+ goto einitctx;
+ }
+
+ *vdev = sh_veu_videodev;
+ spin_lock_init(&veu->lock);
+ mutex_init(&veu->fop_lock);
+ vdev->lock = &veu->fop_lock;
+
+ video_set_drvdata(vdev, veu);
+
+ veu->dev = &pdev->dev;
+ veu->vfmt_out = DEFAULT_OUT_VFMT;
+ veu->vfmt_in = DEFAULT_IN_VFMT;
+
+ veu->m2m_dev = v4l2_m2m_init(&sh_veu_m2m_ops);
+ if (IS_ERR(veu->m2m_dev)) {
+ ret = PTR_ERR(veu->m2m_dev);
+ v4l2_err(&veu->v4l2_dev, "Failed to init mem2mem device: %d\n", ret);
+ goto em2minit;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_resume(&pdev->dev);
+
+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ pm_runtime_suspend(&pdev->dev);
+ if (ret < 0)
+ goto evidreg;
+
+ return ret;
+
+evidreg:
+ pm_runtime_disable(&pdev->dev);
+ v4l2_m2m_release(veu->m2m_dev);
+em2minit:
+ vb2_dma_contig_cleanup_ctx(veu->alloc_ctx);
+einitctx:
+ v4l2_device_unregister(&veu->v4l2_dev);
+ return ret;
+}
+
+static int sh_veu_remove(struct platform_device *pdev)
+{
+ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+ struct sh_veu_dev *veu = container_of(v4l2_dev,
+ struct sh_veu_dev, v4l2_dev);
+
+ video_unregister_device(&veu->vdev);
+ pm_runtime_disable(&pdev->dev);
+ v4l2_m2m_release(veu->m2m_dev);
+ vb2_dma_contig_cleanup_ctx(veu->alloc_ctx);
+ v4l2_device_unregister(&veu->v4l2_dev);
+
+ return 0;
+}
+
+static struct platform_driver __refdata sh_veu_pdrv = {
+ .remove = sh_veu_remove,
+ .driver = {
+ .name = "sh_veu",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sh_veu_init(void)
+{
+ return platform_driver_probe(&sh_veu_pdrv, sh_veu_probe);
+}
+
+static void __exit sh_veu_exit(void)
+{
+ platform_driver_unregister(&sh_veu_pdrv);
+}
+
+module_init(sh_veu_init);
+module_exit(sh_veu_exit);
+
+MODULE_DESCRIPTION("sh-mobile VEU mem2mem driver");
+MODULE_AUTHOR("Guennadi Liakhovetski, <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index f3c4571ac01e..66c8da18df84 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -207,6 +207,7 @@ static void sh_vou_stream_start(struct sh_vou_device *vou_dev,
#endif
switch (vou_dev->pix.pixelformat) {
+ default:
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV16:
row_coeff = 1;
@@ -253,7 +254,8 @@ static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
if (PAGE_ALIGN(*size) * *count > 4 * 1024 * 1024)
*count = 4 * 1024 * 1024 / PAGE_ALIGN(*size);
- dev_dbg(vq->dev, "%s(): count=%d, size=%d\n", __func__, *count, *size);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s(): count=%d, size=%d\n", __func__,
+ *count, *size);
return 0;
}
@@ -269,7 +271,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq,
int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8;
int ret;
- dev_dbg(vq->dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
if (vb->width != pix->width ||
vb->height != pix->height ||
@@ -299,7 +301,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq,
vb->state = VIDEOBUF_PREPARED;
}
- dev_dbg(vq->dev,
+ dev_dbg(vou_dev->v4l2_dev.dev,
"%s(): fmt #%d, %u bytes per line, phys 0x%x, type %d, state %d\n",
__func__, vou_dev->pix_idx, bytes_per_line,
videobuf_to_dma_contig(vb), vb->memory, vb->state);
@@ -314,7 +316,7 @@ static void sh_vou_buf_queue(struct videobuf_queue *vq,
struct video_device *vdev = vq->priv_data;
struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- dev_dbg(vq->dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
vb->state = VIDEOBUF_QUEUED;
list_add_tail(&vb->queue, &vou_dev->queue);
@@ -325,8 +327,8 @@ static void sh_vou_buf_queue(struct videobuf_queue *vq,
vou_dev->active = vb;
/* Start from side A: we use mirror addresses, so, set B */
sh_vou_reg_a_write(vou_dev, VOURPR, 1);
- dev_dbg(vq->dev, "%s: first buffer status 0x%x\n", __func__,
- sh_vou_reg_a_read(vou_dev, VOUSTR));
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s: first buffer status 0x%x\n",
+ __func__, sh_vou_reg_a_read(vou_dev, VOUSTR));
sh_vou_schedule_next(vou_dev, vb);
/* Only activate VOU after the second buffer */
} else if (vou_dev->active->queue.next == &vb->queue) {
@@ -336,8 +338,8 @@ static void sh_vou_buf_queue(struct videobuf_queue *vq,
/* Register side switching with frame VSYNC */
sh_vou_reg_a_write(vou_dev, VOURCR, 5);
- dev_dbg(vq->dev, "%s: second buffer status 0x%x\n", __func__,
- sh_vou_reg_a_read(vou_dev, VOUSTR));
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s: second buffer status 0x%x\n",
+ __func__, sh_vou_reg_a_read(vou_dev, VOUSTR));
/* Enable End-of-Frame (VSYNC) interrupts */
sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004);
@@ -355,7 +357,7 @@ static void sh_vou_buf_release(struct videobuf_queue *vq,
struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
unsigned long flags;
- dev_dbg(vq->dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
spin_lock_irqsave(&vou_dev->lock, flags);
@@ -388,9 +390,9 @@ static struct videobuf_queue_ops sh_vou_video_qops = {
static int sh_vou_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct sh_vou_file *vou_file = priv;
+ struct sh_vou_device *vou_dev = video_drvdata(file);
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
strlcpy(cap->card, "SuperH VOU", sizeof(cap->card));
cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
@@ -401,12 +403,12 @@ static int sh_vou_querycap(struct file *file, void *priv,
static int sh_vou_enum_fmt_vid_out(struct file *file, void *priv,
struct v4l2_fmtdesc *fmt)
{
- struct sh_vou_file *vou_file = priv;
+ struct sh_vou_device *vou_dev = video_drvdata(file);
if (fmt->index >= ARRAY_SIZE(vou_fmt))
return -EINVAL;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
strlcpy(fmt->description, vou_fmt[fmt->index].desc,
@@ -419,8 +421,7 @@ static int sh_vou_enum_fmt_vid_out(struct file *file, void *priv,
static int sh_vou_g_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
@@ -595,9 +596,9 @@ static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
*/
static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
{
- unsigned int best_err = UINT_MAX, best, width_max, height_max,
- img_height_max;
- int i, idx;
+ unsigned int best_err = UINT_MAX, best = geo->in_width,
+ width_max, height_max, img_height_max;
+ int i, idx = 0;
if (std & V4L2_STD_525_60) {
width_max = 858;
@@ -671,8 +672,7 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct v4l2_pix_format *pix = &fmt->fmt.pix;
unsigned int img_height_max;
int pix_idx;
@@ -764,11 +764,11 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
static int sh_vou_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct sh_vou_file *vou_file = priv;
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct v4l2_pix_format *pix = &fmt->fmt.pix;
int i;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
pix->field = V4L2_FIELD_NONE;
@@ -788,9 +788,10 @@ static int sh_vou_try_fmt_vid_out(struct file *file, void *priv,
static int sh_vou_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *req)
{
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct sh_vou_file *vou_file = priv;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
@@ -801,27 +802,30 @@ static int sh_vou_reqbufs(struct file *file, void *priv,
static int sh_vou_querybuf(struct file *file, void *priv,
struct v4l2_buffer *b)
{
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct sh_vou_file *vou_file = priv;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
return videobuf_querybuf(&vou_file->vbq, b);
}
static int sh_vou_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct sh_vou_file *vou_file = priv;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
return videobuf_qbuf(&vou_file->vbq, b);
}
static int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct sh_vou_file *vou_file = priv;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
return videobuf_dqbuf(&vou_file->vbq, b, file->f_flags & O_NONBLOCK);
}
@@ -829,12 +833,11 @@ static int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
static int sh_vou_streamon(struct file *file, void *priv,
enum v4l2_buf_type buftype)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct sh_vou_file *vou_file = priv;
int ret;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0,
video, s_stream, 1);
@@ -848,11 +851,10 @@ static int sh_vou_streamon(struct file *file, void *priv,
static int sh_vou_streamoff(struct file *file, void *priv,
enum v4l2_buf_type buftype)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct sh_vou_file *vou_file = priv;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
/*
* This calls buf_release from host driver's videobuf_queue_ops for all
@@ -881,13 +883,12 @@ static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt)
static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
int ret;
dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, *std_id);
- if (*std_id & ~vdev->tvnorms)
+ if (*std_id & ~vou_dev->vdev->tvnorms)
return -EINVAL;
ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
@@ -909,8 +910,7 @@ static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
@@ -921,8 +921,7 @@ static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std)
static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
@@ -936,8 +935,7 @@ static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a)
{
struct v4l2_crop a_writable = *a;
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct v4l2_rect *rect = &a_writable.c;
struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT};
struct v4l2_pix_format *pix = &vou_dev->pix;
@@ -1028,9 +1026,9 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a)
static int sh_vou_cropcap(struct file *file, void *priv,
struct v4l2_cropcap *a)
{
- struct sh_vou_file *vou_file = priv;
+ struct sh_vou_device *vou_dev = video_drvdata(file);
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
a->bounds.left = 0;
@@ -1091,7 +1089,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id)
list_del(&vb->queue);
vb->state = VIDEOBUF_DONE;
- do_gettimeofday(&vb->ts);
+ v4l2_get_timestamp(&vb->ts);
vb->field_count++;
wake_up(&vb->done);
@@ -1160,8 +1158,7 @@ static int sh_vou_hw_init(struct sh_vou_device *vou_dev)
/* File operations */
static int sh_vou_open(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct sh_vou_file *vou_file = kzalloc(sizeof(struct sh_vou_file),
GFP_KERNEL);
@@ -1178,11 +1175,11 @@ static int sh_vou_open(struct file *file)
int ret;
/* First open */
vou_dev->status = SH_VOU_INITIALISING;
- pm_runtime_get_sync(vdev->v4l2_dev->dev);
+ pm_runtime_get_sync(vou_dev->v4l2_dev.dev);
ret = sh_vou_hw_init(vou_dev);
if (ret < 0) {
atomic_dec(&vou_dev->use_count);
- pm_runtime_put(vdev->v4l2_dev->dev);
+ pm_runtime_put(vou_dev->v4l2_dev.dev);
vou_dev->status = SH_VOU_IDLE;
mutex_unlock(&vou_dev->fop_lock);
return ret;
@@ -1193,8 +1190,8 @@ static int sh_vou_open(struct file *file)
vou_dev->v4l2_dev.dev, &vou_dev->lock,
V4L2_BUF_TYPE_VIDEO_OUTPUT,
V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), vdev,
- &vou_dev->fop_lock);
+ sizeof(struct videobuf_buffer),
+ vou_dev->vdev, &vou_dev->fop_lock);
mutex_unlock(&vou_dev->fop_lock);
return 0;
@@ -1202,18 +1199,17 @@ static int sh_vou_open(struct file *file)
static int sh_vou_release(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct sh_vou_file *vou_file = file->private_data;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
if (!atomic_dec_return(&vou_dev->use_count)) {
mutex_lock(&vou_dev->fop_lock);
/* Last close */
vou_dev->status = SH_VOU_IDLE;
sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101);
- pm_runtime_put(vdev->v4l2_dev->dev);
+ pm_runtime_put(vou_dev->v4l2_dev.dev);
mutex_unlock(&vou_dev->fop_lock);
}
@@ -1225,12 +1221,11 @@ static int sh_vou_release(struct file *file)
static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct sh_vou_file *vou_file = file->private_data;
int ret;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
if (mutex_lock_interruptible(&vou_dev->fop_lock))
return -ERESTARTSYS;
@@ -1241,12 +1236,11 @@ static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma)
static unsigned int sh_vou_poll(struct file *file, poll_table *wait)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
struct sh_vou_file *vou_file = file->private_data;
unsigned int res;
- dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
mutex_lock(&vou_dev->fop_lock);
res = videobuf_poll_stream(file, &vou_file->vbq, wait);
@@ -1257,8 +1251,7 @@ static unsigned int sh_vou_poll(struct file *file, poll_table *wait)
static int sh_vou_g_chip_ident(struct file *file, void *fh,
struct v4l2_dbg_chip_ident *id)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_chip_ident, id);
}
@@ -1267,8 +1260,7 @@ static int sh_vou_g_chip_ident(struct file *file, void *fh,
static int sh_vou_g_register(struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, g_register, reg);
}
@@ -1276,8 +1268,7 @@ static int sh_vou_g_register(struct file *file, void *fh,
static int sh_vou_s_register(struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
- struct video_device *vdev = video_devdata(file);
- struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
+ struct sh_vou_device *vou_dev = video_drvdata(file);
return v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, core, s_register, reg);
}
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig
index cb6791e62bd4..b139b525bb16 100644
--- a/drivers/media/platform/soc_camera/Kconfig
+++ b/drivers/media/platform/soc_camera/Kconfig
@@ -70,13 +70,12 @@ config VIDEO_MX2_HOSTSUPPORT
bool
config VIDEO_MX2
- tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
- depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || (ARCH_MX25 && BROKEN))
+ tristate "i.MX27 Camera Sensor Interface driver"
+ depends on VIDEO_DEV && SOC_CAMERA && MACH_MX27
select VIDEOBUF2_DMA_CONTIG
select VIDEO_MX2_HOSTSUPPORT
---help---
- This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
- Interface
+ This is a v4l2 driver for the i.MX27 Camera Sensor Interface
config VIDEO_ATMEL_ISI
tristate "ATMEL Image Sensor Interface (ISI) support"
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index d96c8c7e01d9..82dbf99d347c 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -166,7 +166,7 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
struct frame_buffer *buf = isi->active;
list_del_init(&buf->list);
- do_gettimeofday(&vb->v4l2_buf.timestamp);
+ v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
vb->v4l2_buf.sequence = isi->sequence++;
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
}
@@ -745,7 +745,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd,
return formats;
}
-/* Called with .video_lock held */
+/* Called with .host_lock held */
static int isi_camera_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -770,7 +770,7 @@ static int isi_camera_add_device(struct soc_camera_device *icd)
icd->devnum);
return 0;
}
-/* Called with .video_lock held */
+/* Called with .host_lock held */
static void isi_camera_remove_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c
index 032b8c9097f9..25b2a285dc86 100644
--- a/drivers/media/platform/soc_camera/mx1_camera.c
+++ b/drivers/media/platform/soc_camera/mx1_camera.c
@@ -26,7 +26,6 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -307,7 +306,7 @@ static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev,
/* _init is used to debug races, see comment in mx1_camera_reqbufs() */
list_del_init(&vb->queue);
vb->state = VIDEOBUF_DONE;
- do_gettimeofday(&vb->ts);
+ v4l2_get_timestamp(&vb->ts);
vb->field_count++;
wake_up(&vb->done);
@@ -373,7 +372,7 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q,
videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->parent,
&pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_NONE,
- sizeof(struct mx1_buffer), icd, &icd->video_lock);
+ sizeof(struct mx1_buffer), icd, &ici->host_lock);
}
static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
index 8bda2c908aba..ffba7d91f413 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -1,5 +1,5 @@
/*
- * V4L2 Driver for i.MX27/i.MX25 camera host
+ * V4L2 Driver for i.MX27 camera host
*
* Copyright (C) 2008, Sascha Hauer, Pengutronix
* Copyright (C) 2010, Baruch Siach, Orex Computed Radiography
@@ -28,7 +28,6 @@
#include <linux/time.h>
#include <linux/device.h>
#include <linux/platform_device.h>
-#include <linux/mutex.h>
#include <linux/clk.h>
#include <media/v4l2-common.h>
@@ -64,9 +63,7 @@
#define CSICR1_RF_OR_INTEN (1 << 24)
#define CSICR1_STATFF_LEVEL (3 << 22)
#define CSICR1_STATFF_INTEN (1 << 21)
-#define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19) /* MX27 */
-#define CSICR1_FB2_DMA_INTEN (1 << 20) /* MX25 */
-#define CSICR1_FB1_DMA_INTEN (1 << 19) /* MX25 */
+#define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19)
#define CSICR1_RXFF_INTEN (1 << 18)
#define CSICR1_SOF_POL (1 << 17)
#define CSICR1_SOF_INTEN (1 << 16)
@@ -88,45 +85,15 @@
#define SHIFT_RXFF_LEVEL 19
#define SHIFT_MCLKDIV 12
-/* control reg 3 */
-#define CSICR3_FRMCNT (0xFFFF << 16)
-#define CSICR3_FRMCNT_RST (1 << 15)
-#define CSICR3_DMA_REFLASH_RFF (1 << 14)
-#define CSICR3_DMA_REFLASH_SFF (1 << 13)
-#define CSICR3_DMA_REQ_EN_RFF (1 << 12)
-#define CSICR3_DMA_REQ_EN_SFF (1 << 11)
-#define CSICR3_RXFF_LEVEL(l) (((l) & 7) << 4) /* MX25 */
-#define CSICR3_CSI_SUP (1 << 3)
-#define CSICR3_ZERO_PACK_EN (1 << 2)
-#define CSICR3_ECC_INT_EN (1 << 1)
-#define CSICR3_ECC_AUTO_EN (1 << 0)
-
#define SHIFT_FRMCNT 16
-/* csi status reg */
-#define CSISR_SFF_OR_INT (1 << 25)
-#define CSISR_RFF_OR_INT (1 << 24)
-#define CSISR_STATFF_INT (1 << 21)
-#define CSISR_DMA_TSF_FB2_INT (1 << 20) /* MX25 */
-#define CSISR_DMA_TSF_FB1_INT (1 << 19) /* MX25 */
-#define CSISR_RXFF_INT (1 << 18)
-#define CSISR_EOF_INT (1 << 17)
-#define CSISR_SOF_INT (1 << 16)
-#define CSISR_F2_INT (1 << 15)
-#define CSISR_F1_INT (1 << 14)
-#define CSISR_COF_INT (1 << 13)
-#define CSISR_ECC_INT (1 << 1)
-#define CSISR_DRDY (1 << 0)
-
#define CSICR1 0x00
#define CSICR2 0x04
-#define CSISR_IMX25 0x18
-#define CSISR_IMX27 0x08
+#define CSISR 0x08
#define CSISTATFIFO 0x0c
#define CSIRFIFO 0x10
#define CSIRXCNT 0x14
-#define CSICR3_IMX25 0x08
-#define CSICR3_IMX27 0x1c
+#define CSICR3 0x1c
#define CSIDMASA_STATFIFO 0x20
#define CSIDMATA_STATFIFO 0x24
#define CSIDMASA_FB1 0x28
@@ -249,12 +216,6 @@ struct mx2_fmt_cfg {
struct mx2_prp_cfg cfg;
};
-enum mx2_buffer_state {
- MX2_STATE_QUEUED,
- MX2_STATE_ACTIVE,
- MX2_STATE_DONE,
-};
-
struct mx2_buf_internal {
struct list_head queue;
int bufnum;
@@ -265,12 +226,10 @@ struct mx2_buf_internal {
struct mx2_buffer {
/* common v4l buffer stuff -- must be first */
struct vb2_buffer vb;
- enum mx2_buffer_state state;
struct mx2_buf_internal internal;
};
enum mx2_camera_type {
- IMX25_CAMERA,
IMX27_CAMERA,
};
@@ -298,8 +257,6 @@ struct mx2_camera_dev {
struct mx2_buffer *fb2_active;
u32 csicr1;
- u32 reg_csisr;
- u32 reg_csicr3;
enum mx2_camera_type devtype;
struct mx2_buf_internal buf_discard[2];
@@ -315,9 +272,6 @@ struct mx2_camera_dev {
static struct platform_device_id mx2_camera_devtype[] = {
{
- .name = "imx25-camera",
- .driver_data = IMX25_CAMERA,
- }, {
.name = "imx27-camera",
.driver_data = IMX27_CAMERA,
}, {
@@ -326,16 +280,6 @@ static struct platform_device_id mx2_camera_devtype[] = {
};
MODULE_DEVICE_TABLE(platform, mx2_camera_devtype);
-static inline int is_imx25_camera(struct mx2_camera_dev *pcdev)
-{
- return pcdev->devtype == IMX25_CAMERA;
-}
-
-static inline int is_imx27_camera(struct mx2_camera_dev *pcdev)
-{
- return pcdev->devtype == IMX27_CAMERA;
-}
-
static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf)
{
return container_of(int_buf, struct mx2_buffer, internal);
@@ -345,7 +289,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
/*
* This is a generic configuration which is valid for most
* prp input-output format combinations.
- * We set the incomming and outgoing pixelformat to a
+ * We set the incoming and outgoing pixelformat to a
* 16 Bit wide format and adjust the bytesperline
* accordingly. With this configuration the inputdata
* will not be changed by the emma and could be any type
@@ -463,21 +407,10 @@ static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev,
static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
{
- unsigned long flags;
-
clk_disable_unprepare(pcdev->clk_csi_ahb);
clk_disable_unprepare(pcdev->clk_csi_per);
writel(0, pcdev->base_csi + CSICR1);
- if (is_imx27_camera(pcdev)) {
- writel(0, pcdev->base_emma + PRP_CNTL);
- } else if (is_imx25_camera(pcdev)) {
- spin_lock_irqsave(&pcdev->lock, flags);
- pcdev->fb1_active = NULL;
- pcdev->fb2_active = NULL;
- writel(0, pcdev->base_csi + CSIDMASA_FB1);
- writel(0, pcdev->base_csi + CSIDMASA_FB2);
- spin_unlock_irqrestore(&pcdev->lock, flags);
- }
+ writel(0, pcdev->base_emma + PRP_CNTL);
}
/*
@@ -502,11 +435,8 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
if (ret < 0)
goto exit_csi_ahb;
- csicr1 = CSICR1_MCLKEN;
-
- if (is_imx27_camera(pcdev))
- csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
- CSICR1_RXFF_LEVEL(0);
+ csicr1 = CSICR1_MCLKEN | CSICR1_PRP_IF_EN | CSICR1_FCC |
+ CSICR1_RXFF_LEVEL(0);
pcdev->csicr1 = csicr1;
writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
@@ -540,65 +470,6 @@ static void mx2_camera_remove_device(struct soc_camera_device *icd)
pcdev->icd = NULL;
}
-static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
- int state)
-{
- struct vb2_buffer *vb;
- struct mx2_buffer *buf;
- struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
- &pcdev->fb2_active;
- u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2;
- unsigned long flags;
-
- spin_lock_irqsave(&pcdev->lock, flags);
-
- if (*fb_active == NULL)
- goto out;
-
- vb = &(*fb_active)->vb;
- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
- vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
-
- do_gettimeofday(&vb->v4l2_buf.timestamp);
- vb->v4l2_buf.sequence++;
- vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-
- if (list_empty(&pcdev->capture)) {
- buf = NULL;
- writel(0, pcdev->base_csi + fb_reg);
- } else {
- buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
- internal.queue);
- vb = &buf->vb;
- list_del(&buf->internal.queue);
- buf->state = MX2_STATE_ACTIVE;
- writel(vb2_dma_contig_plane_dma_addr(vb, 0),
- pcdev->base_csi + fb_reg);
- }
-
- *fb_active = buf;
-
-out:
- spin_unlock_irqrestore(&pcdev->lock, flags);
-}
-
-static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
-{
- struct mx2_camera_dev *pcdev = data;
- u32 status = readl(pcdev->base_csi + pcdev->reg_csisr);
-
- if (status & CSISR_DMA_TSF_FB1_INT)
- mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE);
- else if (status & CSISR_DMA_TSF_FB2_INT)
- mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE);
-
- /* FIXME: handle CSISR_RFF_OR_INT */
-
- writel(status, pcdev->base_csi + pcdev->reg_csisr);
-
- return IRQ_HANDLED;
-}
-
/*
* Videobuf operations
*/
@@ -676,97 +547,8 @@ static void mx2_videobuf_queue(struct vb2_buffer *vb)
spin_lock_irqsave(&pcdev->lock, flags);
- buf->state = MX2_STATE_QUEUED;
list_add_tail(&buf->internal.queue, &pcdev->capture);
- if (is_imx25_camera(pcdev)) {
- u32 csicr3, dma_inten = 0;
-
- if (pcdev->fb1_active == NULL) {
- writel(vb2_dma_contig_plane_dma_addr(vb, 0),
- pcdev->base_csi + CSIDMASA_FB1);
- pcdev->fb1_active = buf;
- dma_inten = CSICR1_FB1_DMA_INTEN;
- } else if (pcdev->fb2_active == NULL) {
- writel(vb2_dma_contig_plane_dma_addr(vb, 0),
- pcdev->base_csi + CSIDMASA_FB2);
- pcdev->fb2_active = buf;
- dma_inten = CSICR1_FB2_DMA_INTEN;
- }
-
- if (dma_inten) {
- list_del(&buf->internal.queue);
- buf->state = MX2_STATE_ACTIVE;
-
- csicr3 = readl(pcdev->base_csi + pcdev->reg_csicr3);
-
- /* Reflash DMA */
- writel(csicr3 | CSICR3_DMA_REFLASH_RFF,
- pcdev->base_csi + pcdev->reg_csicr3);
-
- /* clear & enable interrupts */
- writel(dma_inten, pcdev->base_csi + pcdev->reg_csisr);
- pcdev->csicr1 |= dma_inten;
- writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
-
- /* enable DMA */
- csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1);
- writel(csicr3, pcdev->base_csi + pcdev->reg_csicr3);
- }
- }
-
- spin_unlock_irqrestore(&pcdev->lock, flags);
-}
-
-static void mx2_videobuf_release(struct vb2_buffer *vb)
-{
- struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx2_camera_dev *pcdev = ici->priv;
- struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
- unsigned long flags;
-
-#ifdef DEBUG
- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
- vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
-
- switch (buf->state) {
- case MX2_STATE_ACTIVE:
- dev_info(icd->parent, "%s (active)\n", __func__);
- break;
- case MX2_STATE_QUEUED:
- dev_info(icd->parent, "%s (queued)\n", __func__);
- break;
- default:
- dev_info(icd->parent, "%s (unknown) %d\n", __func__,
- buf->state);
- break;
- }
-#endif
-
- /*
- * Terminate only queued but inactive buffers. Active buffers are
- * released when they become inactive after videobuf_waiton().
- *
- * FIXME: implement forced termination of active buffers for mx27 and
- * mx27 eMMA, so that the user won't get stuck in an uninterruptible
- * state. This requires a specific handling for each of the these DMA
- * types.
- */
-
- spin_lock_irqsave(&pcdev->lock, flags);
- if (is_imx25_camera(pcdev) && buf->state == MX2_STATE_ACTIVE) {
- if (pcdev->fb1_active == buf) {
- pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
- writel(0, pcdev->base_csi + CSIDMASA_FB1);
- pcdev->fb1_active = NULL;
- } else if (pcdev->fb2_active == buf) {
- pcdev->csicr1 &= ~CSICR1_FB2_DMA_INTEN;
- writel(0, pcdev->base_csi + CSIDMASA_FB2);
- pcdev->fb2_active = NULL;
- }
- writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
- }
spin_unlock_irqrestore(&pcdev->lock, flags);
}
@@ -877,91 +659,87 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
struct mx2_buffer *buf;
unsigned long phys;
int bytesperline;
+ unsigned long flags;
- if (is_imx27_camera(pcdev)) {
- unsigned long flags;
- if (count < 2)
- return -EINVAL;
+ if (count < 2)
+ return -EINVAL;
- spin_lock_irqsave(&pcdev->lock, flags);
+ spin_lock_irqsave(&pcdev->lock, flags);
- buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
- internal.queue);
- buf->internal.bufnum = 0;
- vb = &buf->vb;
- buf->state = MX2_STATE_ACTIVE;
+ buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+ internal.queue);
+ buf->internal.bufnum = 0;
+ vb = &buf->vb;
- phys = vb2_dma_contig_plane_dma_addr(vb, 0);
- mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
- list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
+ list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
- buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
- internal.queue);
- buf->internal.bufnum = 1;
- vb = &buf->vb;
- buf->state = MX2_STATE_ACTIVE;
+ buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+ internal.queue);
+ buf->internal.bufnum = 1;
+ vb = &buf->vb;
- phys = vb2_dma_contig_plane_dma_addr(vb, 0);
- mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
- list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
-
- bytesperline = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
- if (bytesperline < 0) {
- spin_unlock_irqrestore(&pcdev->lock, flags);
- return bytesperline;
- }
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
+ list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
- /*
- * I didn't manage to properly enable/disable the prp
- * on a per frame basis during running transfers,
- * thus we allocate a buffer here and use it to
- * discard frames when no buffer is available.
- * Feel free to work on this ;)
- */
- pcdev->discard_size = icd->user_height * bytesperline;
- pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
- pcdev->discard_size, &pcdev->discard_buffer_dma,
- GFP_KERNEL);
- if (!pcdev->discard_buffer) {
- spin_unlock_irqrestore(&pcdev->lock, flags);
- return -ENOMEM;
- }
+ bytesperline = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ if (bytesperline < 0) {
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+ return bytesperline;
+ }
- pcdev->buf_discard[0].discard = true;
- list_add_tail(&pcdev->buf_discard[0].queue,
- &pcdev->discard);
+ /*
+ * I didn't manage to properly enable/disable the prp
+ * on a per frame basis during running transfers,
+ * thus we allocate a buffer here and use it to
+ * discard frames when no buffer is available.
+ * Feel free to work on this ;)
+ */
+ pcdev->discard_size = icd->user_height * bytesperline;
+ pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
+ pcdev->discard_size,
+ &pcdev->discard_buffer_dma, GFP_ATOMIC);
+ if (!pcdev->discard_buffer) {
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+ return -ENOMEM;
+ }
- pcdev->buf_discard[1].discard = true;
- list_add_tail(&pcdev->buf_discard[1].queue,
- &pcdev->discard);
+ pcdev->buf_discard[0].discard = true;
+ list_add_tail(&pcdev->buf_discard[0].queue,
+ &pcdev->discard);
- mx2_prp_resize_commit(pcdev);
+ pcdev->buf_discard[1].discard = true;
+ list_add_tail(&pcdev->buf_discard[1].queue,
+ &pcdev->discard);
- mx27_camera_emma_buf_init(icd, bytesperline);
+ mx2_prp_resize_commit(pcdev);
- if (prp->cfg.channel == 1) {
- writel(PRP_CNTL_CH1EN |
- PRP_CNTL_CSIEN |
- prp->cfg.in_fmt |
- prp->cfg.out_fmt |
- PRP_CNTL_CH1_LEN |
- PRP_CNTL_CH1BYP |
- PRP_CNTL_CH1_TSKIP(0) |
- PRP_CNTL_IN_TSKIP(0),
- pcdev->base_emma + PRP_CNTL);
- } else {
- writel(PRP_CNTL_CH2EN |
- PRP_CNTL_CSIEN |
- prp->cfg.in_fmt |
- prp->cfg.out_fmt |
- PRP_CNTL_CH2_LEN |
- PRP_CNTL_CH2_TSKIP(0) |
- PRP_CNTL_IN_TSKIP(0),
- pcdev->base_emma + PRP_CNTL);
- }
- spin_unlock_irqrestore(&pcdev->lock, flags);
+ mx27_camera_emma_buf_init(icd, bytesperline);
+
+ if (prp->cfg.channel == 1) {
+ writel(PRP_CNTL_CH1EN |
+ PRP_CNTL_CSIEN |
+ prp->cfg.in_fmt |
+ prp->cfg.out_fmt |
+ PRP_CNTL_CH1_LEN |
+ PRP_CNTL_CH1BYP |
+ PRP_CNTL_CH1_TSKIP(0) |
+ PRP_CNTL_IN_TSKIP(0),
+ pcdev->base_emma + PRP_CNTL);
+ } else {
+ writel(PRP_CNTL_CH2EN |
+ PRP_CNTL_CSIEN |
+ prp->cfg.in_fmt |
+ prp->cfg.out_fmt |
+ PRP_CNTL_CH2_LEN |
+ PRP_CNTL_CH2_TSKIP(0) |
+ PRP_CNTL_IN_TSKIP(0),
+ pcdev->base_emma + PRP_CNTL);
}
+ spin_unlock_irqrestore(&pcdev->lock, flags);
return 0;
}
@@ -977,29 +755,27 @@ static int mx2_stop_streaming(struct vb2_queue *q)
void *b;
u32 cntl;
- if (is_imx27_camera(pcdev)) {
- spin_lock_irqsave(&pcdev->lock, flags);
+ spin_lock_irqsave(&pcdev->lock, flags);
- cntl = readl(pcdev->base_emma + PRP_CNTL);
- if (prp->cfg.channel == 1) {
- writel(cntl & ~PRP_CNTL_CH1EN,
- pcdev->base_emma + PRP_CNTL);
- } else {
- writel(cntl & ~PRP_CNTL_CH2EN,
- pcdev->base_emma + PRP_CNTL);
- }
- INIT_LIST_HEAD(&pcdev->capture);
- INIT_LIST_HEAD(&pcdev->active_bufs);
- INIT_LIST_HEAD(&pcdev->discard);
+ cntl = readl(pcdev->base_emma + PRP_CNTL);
+ if (prp->cfg.channel == 1) {
+ writel(cntl & ~PRP_CNTL_CH1EN,
+ pcdev->base_emma + PRP_CNTL);
+ } else {
+ writel(cntl & ~PRP_CNTL_CH2EN,
+ pcdev->base_emma + PRP_CNTL);
+ }
+ INIT_LIST_HEAD(&pcdev->capture);
+ INIT_LIST_HEAD(&pcdev->active_bufs);
+ INIT_LIST_HEAD(&pcdev->discard);
- b = pcdev->discard_buffer;
- pcdev->discard_buffer = NULL;
+ b = pcdev->discard_buffer;
+ pcdev->discard_buffer = NULL;
- spin_unlock_irqrestore(&pcdev->lock, flags);
+ spin_unlock_irqrestore(&pcdev->lock, flags);
- dma_free_coherent(ici->v4l2_dev.dev,
- pcdev->discard_size, b, pcdev->discard_buffer_dma);
- }
+ dma_free_coherent(ici->v4l2_dev.dev,
+ pcdev->discard_size, b, pcdev->discard_buffer_dma);
return 0;
}
@@ -1008,7 +784,6 @@ static struct vb2_ops mx2_videobuf_ops = {
.queue_setup = mx2_videobuf_setup,
.buf_prepare = mx2_videobuf_prepare,
.buf_queue = mx2_videobuf_queue,
- .buf_cleanup = mx2_videobuf_release,
.start_streaming = mx2_start_streaming,
.stop_streaming = mx2_stop_streaming,
};
@@ -1129,16 +904,9 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
if (bytesperline < 0)
return bytesperline;
- if (is_imx27_camera(pcdev)) {
- ret = mx27_camera_emma_prp_reset(pcdev);
- if (ret)
- return ret;
- } else if (is_imx25_camera(pcdev)) {
- writel((bytesperline * icd->user_height) >> 2,
- pcdev->base_csi + CSIRXCNT);
- writel((bytesperline << 16) | icd->user_height,
- pcdev->base_csi + CSIIMAG_PARA);
- }
+ ret = mx27_camera_emma_prp_reset(pcdev);
+ if (ret)
+ return ret;
writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
@@ -1425,7 +1193,6 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx2_camera_dev *pcdev = ici->priv;
struct mx2_fmt_cfg *emma_prp;
- unsigned int width_limit;
int ret;
dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
@@ -1437,40 +1204,11 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
return -EINVAL;
}
- /* FIXME: implement MX27 limits */
-
- /* limit to MX25 hardware capabilities */
- if (is_imx25_camera(pcdev)) {
- if (xlate->host_fmt->bits_per_sample <= 8)
- width_limit = 0xffff * 4;
- else
- width_limit = 0xffff * 2;
- /* CSIIMAG_PARA limit */
- if (pix->width > width_limit)
- pix->width = width_limit;
- if (pix->height > 0xffff)
- pix->height = 0xffff;
-
- pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
- xlate->host_fmt);
- if (pix->bytesperline < 0)
- return pix->bytesperline;
- pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
- pix->bytesperline, pix->height);
- /* Check against the CSIRXCNT limit */
- if (pix->sizeimage > 4 * 0x3ffff) {
- /* Adjust geometry, preserve aspect ratio */
- unsigned int new_height = int_sqrt(div_u64(0x3ffffULL *
- 4 * pix->height, pix->bytesperline));
- pix->width = new_height * pix->width / pix->height;
- pix->height = new_height;
- pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
- xlate->host_fmt);
- BUG_ON(pix->bytesperline < 0);
- pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
- pix->bytesperline, pix->height);
- }
- }
+ /*
+ * limit to MX27 hardware capabilities: width must be a multiple of 8 as
+ * requested by the CSI. (Table 39-2 in the i.MX27 Reference Manual).
+ */
+ pix->width &= ~0x7;
/* limit to sensor capabilities */
mf.width = pix->width;
@@ -1488,7 +1226,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
/* If the sensor does not support image size try PrP resizing */
emma_prp = mx27_emma_prp_get_format(xlate->code,
- xlate->host_fmt->fourcc);
+ xlate->host_fmt->fourcc);
if ((mf.width != pix->width || mf.height != pix->height) &&
emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
@@ -1600,7 +1338,7 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
vb2_get_plane_payload(vb, 0));
list_del_init(&buf->internal.queue);
- do_gettimeofday(&vb->v4l2_buf.timestamp);
+ v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
vb->v4l2_buf.sequence = pcdev->frame_count;
if (err)
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
@@ -1634,7 +1372,6 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
vb = &buf->vb;
- buf->state = MX2_STATE_ACTIVE;
phys = vb2_dma_contig_plane_dma_addr(vb, 0);
mx27_update_emma_buf(pcdev, phys, bufnum);
@@ -1707,9 +1444,9 @@ static int mx27_camera_emma_init(struct platform_device *pdev)
goto out;
}
- pcdev->base_emma = devm_request_and_ioremap(pcdev->dev, res_emma);
- if (!pcdev->base_emma) {
- err = -EADDRNOTAVAIL;
+ pcdev->base_emma = devm_ioremap_resource(pcdev->dev, res_emma);
+ if (IS_ERR(pcdev->base_emma)) {
+ err = PTR_ERR(pcdev->base_emma);
goto out;
}
@@ -1774,20 +1511,6 @@ static int mx2_camera_probe(struct platform_device *pdev)
goto exit;
}
- pcdev->devtype = pdev->id_entry->driver_data;
- switch (pcdev->devtype) {
- case IMX25_CAMERA:
- pcdev->reg_csisr = CSISR_IMX25;
- pcdev->reg_csicr3 = CSICR3_IMX25;
- break;
- case IMX27_CAMERA:
- pcdev->reg_csisr = CSISR_IMX27;
- pcdev->reg_csicr3 = CSICR3_IMX27;
- break;
- default:
- break;
- }
-
pcdev->clk_csi_ahb = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(pcdev->clk_csi_ahb)) {
dev_err(&pdev->dev, "Could not get csi ahb clock\n");
@@ -1824,29 +1547,18 @@ static int mx2_camera_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&pcdev->discard);
spin_lock_init(&pcdev->lock);
- pcdev->base_csi = devm_request_and_ioremap(&pdev->dev, res_csi);
- if (!pcdev->base_csi) {
- err = -EADDRNOTAVAIL;
+ pcdev->base_csi = devm_ioremap_resource(&pdev->dev, res_csi);
+ if (IS_ERR(pcdev->base_csi)) {
+ err = PTR_ERR(pcdev->base_csi);
goto exit;
}
pcdev->dev = &pdev->dev;
platform_set_drvdata(pdev, pcdev);
- if (is_imx25_camera(pcdev)) {
- err = devm_request_irq(&pdev->dev, irq_csi, mx25_camera_irq, 0,
- MX2_CAM_DRV_NAME, pcdev);
- if (err) {
- dev_err(pcdev->dev, "Camera interrupt register failed \n");
- goto exit;
- }
- }
-
- if (is_imx27_camera(pcdev)) {
- err = mx27_camera_emma_init(pdev);
- if (err)
- goto exit;
- }
+ err = mx27_camera_emma_init(pdev);
+ if (err)
+ goto exit;
/*
* We're done with drvdata here. Clear the pointer so that
@@ -1859,8 +1571,6 @@ static int mx2_camera_probe(struct platform_device *pdev)
pcdev->soc_host.priv = pcdev;
pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
pcdev->soc_host.nr = pdev->id;
- if (is_imx25_camera(pcdev))
- pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE;
pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(pcdev->alloc_ctx)) {
@@ -1879,10 +1589,8 @@ static int mx2_camera_probe(struct platform_device *pdev)
exit_free_emma:
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
eallocctx:
- if (is_imx27_camera(pcdev)) {
- clk_disable_unprepare(pcdev->clk_emma_ipg);
- clk_disable_unprepare(pcdev->clk_emma_ahb);
- }
+ clk_disable_unprepare(pcdev->clk_emma_ipg);
+ clk_disable_unprepare(pcdev->clk_emma_ahb);
exit:
return err;
}
@@ -1897,10 +1605,8 @@ static int mx2_camera_remove(struct platform_device *pdev)
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
- if (is_imx27_camera(pcdev)) {
- clk_disable_unprepare(pcdev->clk_emma_ipg);
- clk_disable_unprepare(pcdev->clk_emma_ahb);
- }
+ clk_disable_unprepare(pcdev->clk_emma_ipg);
+ clk_disable_unprepare(pcdev->clk_emma_ahb);
dev_info(&pdev->dev, "MX2 Camera driver unloaded\n");
@@ -1913,23 +1619,12 @@ static struct platform_driver mx2_camera_driver = {
},
.id_table = mx2_camera_devtype,
.remove = mx2_camera_remove,
+ .probe = mx2_camera_probe,
};
+module_platform_driver(mx2_camera_driver);
-static int __init mx2_camera_init(void)
-{
- return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe);
-}
-
-static void __exit mx2_camera_exit(void)
-{
- return platform_driver_unregister(&mx2_camera_driver);
-}
-
-module_init(mx2_camera_init);
-module_exit(mx2_camera_exit);
-
-MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver");
+MODULE_DESCRIPTION("i.MX27 SoC Camera Host driver");
MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
MODULE_LICENSE("GPL");
MODULE_VERSION(MX2_CAM_VERSION);
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index 45aef1053a49..f5cbb92db545 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -156,7 +156,7 @@ static void mx3_cam_dma_done(void *arg)
struct mx3_camera_buffer *buf = to_mx3_vb(vb);
list_del_init(&buf->queue);
- do_gettimeofday(&vb->v4l2_buf.timestamp);
+ v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
vb->v4l2_buf.field = mx3_cam->field;
vb->v4l2_buf.sequence = mx3_cam->sequence++;
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -510,7 +510,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
clk_set_rate(mx3_cam->clk, rate);
}
-/* Called with .video_lock held */
+/* Called with .host_lock held */
static int mx3_camera_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -530,7 +530,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd)
return 0;
}
-/* Called with .video_lock held */
+/* Called with .host_lock held */
static void mx3_camera_remove_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c
index 39a77f0b8860..2547bf88f79f 100644
--- a/drivers/media/platform/soc_camera/omap1_camera.c
+++ b/drivers/media/platform/soc_camera/omap1_camera.c
@@ -592,7 +592,7 @@ static void videobuf_done(struct omap1_cam_dev *pcdev,
suspend_capture(pcdev);
}
vb->state = result;
- do_gettimeofday(&vb->ts);
+ v4l2_get_timestamp(&vb->ts);
if (result != VIDEOBUF_ERROR)
vb->field_count++;
wake_up(&vb->done);
@@ -1383,12 +1383,12 @@ static void omap1_cam_init_videobuf(struct videobuf_queue *q,
videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops,
icd->parent, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
+ sizeof(struct omap1_cam_buf), icd, &ici->host_lock);
else
videobuf_queue_sg_init(q, &omap1_videobuf_ops,
icd->parent, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
+ sizeof(struct omap1_cam_buf), icd, &ici->host_lock);
/* use videobuf mode (auto)selected with the module parameter */
pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG;
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index 523330d00dee..395e2e043615 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -681,7 +681,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
/* _init is used to debug races, see comment in pxa_camera_reqbufs() */
list_del_init(&vb->queue);
vb->state = VIDEOBUF_DONE;
- do_gettimeofday(&vb->ts);
+ v4l2_get_timestamp(&vb->ts);
vb->field_count++;
wake_up(&vb->done);
dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s dequeud buffer (vb=0x%p)\n",
@@ -842,7 +842,7 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
*/
videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct pxa_buffer), icd, &icd->video_lock);
+ sizeof(struct pxa_buffer), icd, &ici->host_lock);
}
static u32 mclk_get_divisor(struct platform_device *pdev,
@@ -958,7 +958,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
/*
* The following two functions absolutely depend on the fact, that
* there can be only one camera on PXA quick capture interface
- * Called with .video_lock held
+ * Called with .host_lock held
*/
static int pxa_camera_add_device(struct soc_camera_device *icd)
{
@@ -978,7 +978,7 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
return 0;
}
-/* Called with .video_lock held */
+/* Called with .host_lock held */
static void pxa_camera_remove_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -1661,23 +1661,18 @@ static int pxa_camera_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!res || irq < 0) {
- err = -ENODEV;
- goto exit;
- }
+ if (!res || irq < 0)
+ return -ENODEV;
- pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+ pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
if (!pcdev) {
dev_err(&pdev->dev, "Could not allocate pcdev\n");
- err = -ENOMEM;
- goto exit;
+ return -ENOMEM;
}
- pcdev->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(pcdev->clk)) {
- err = PTR_ERR(pcdev->clk);
- goto exit_kfree;
- }
+ pcdev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pcdev->clk))
+ return PTR_ERR(pcdev->clk);
pcdev->res = res;
@@ -1715,17 +1710,9 @@ static int pxa_camera_probe(struct platform_device *pdev)
/*
* Request the regions.
*/
- if (!request_mem_region(res->start, resource_size(res),
- PXA_CAM_DRV_NAME)) {
- err = -EBUSY;
- goto exit_clk;
- }
-
- base = ioremap(res->start, resource_size(res));
- if (!base) {
- err = -ENOMEM;
- goto exit_release;
- }
+ base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!base)
+ return -ENOMEM;
pcdev->irq = irq;
pcdev->base = base;
@@ -1734,7 +1721,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
pxa_camera_dma_irq_y, pcdev);
if (err < 0) {
dev_err(&pdev->dev, "Can't request DMA for Y\n");
- goto exit_iounmap;
+ return err;
}
pcdev->dma_chans[0] = err;
dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
@@ -1762,10 +1749,10 @@ static int pxa_camera_probe(struct platform_device *pdev)
DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;
/* request irq */
- err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME,
- pcdev);
+ err = devm_request_irq(&pdev->dev, pcdev->irq, pxa_camera_irq, 0,
+ PXA_CAM_DRV_NAME, pcdev);
if (err) {
- dev_err(&pdev->dev, "Camera interrupt register failed \n");
+ dev_err(&pdev->dev, "Camera interrupt register failed\n");
goto exit_free_dma;
}
@@ -1777,27 +1764,16 @@ static int pxa_camera_probe(struct platform_device *pdev)
err = soc_camera_host_register(&pcdev->soc_host);
if (err)
- goto exit_free_irq;
+ goto exit_free_dma;
return 0;
-exit_free_irq:
- free_irq(pcdev->irq, pcdev);
exit_free_dma:
pxa_free_dma(pcdev->dma_chans[2]);
exit_free_dma_u:
pxa_free_dma(pcdev->dma_chans[1]);
exit_free_dma_y:
pxa_free_dma(pcdev->dma_chans[0]);
-exit_iounmap:
- iounmap(base);
-exit_release:
- release_mem_region(res->start, resource_size(res));
-exit_clk:
- clk_put(pcdev->clk);
-exit_kfree:
- kfree(pcdev);
-exit:
return err;
}
@@ -1806,24 +1782,13 @@ static int pxa_camera_remove(struct platform_device *pdev)
struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
struct pxa_camera_dev *pcdev = container_of(soc_host,
struct pxa_camera_dev, soc_host);
- struct resource *res;
-
- clk_put(pcdev->clk);
pxa_free_dma(pcdev->dma_chans[0]);
pxa_free_dma(pcdev->dma_chans[1]);
pxa_free_dma(pcdev->dma_chans[2]);
- free_irq(pcdev->irq, pcdev);
soc_camera_host_unregister(soc_host);
- iounmap(pcdev->base);
-
- res = pcdev->res;
- release_mem_region(res->start, resource_size(res));
-
- kfree(pcdev);
-
dev_info(&pdev->dev, "PXA Camera driver unloaded\n");
return 0;
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index ebbc126e71a6..bb08a46432f4 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -516,7 +516,7 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
pcdev->active = NULL;
ret = sh_mobile_ceu_capture(pcdev);
- do_gettimeofday(&vb->v4l2_buf.timestamp);
+ v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
if (!ret) {
vb->v4l2_buf.field = pcdev->field;
vb->v4l2_buf.sequence = pcdev->sequence++;
@@ -543,7 +543,7 @@ static struct v4l2_subdev *find_csi2(struct sh_mobile_ceu_dev *pcdev)
return NULL;
}
-/* Called with .video_lock held */
+/* Called with .host_lock held */
static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -572,7 +572,7 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
ret = v4l2_subdev_call(csi2_sd, core, s_power, 1);
if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) {
- pm_runtime_put_sync(ici->v4l2_dev.dev);
+ pm_runtime_put(ici->v4l2_dev.dev);
return ret;
}
@@ -587,7 +587,7 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
return 0;
}
-/* Called with .video_lock held */
+/* Called with .host_lock held */
static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -612,7 +612,7 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
}
spin_unlock_irq(&pcdev->lock);
- pm_runtime_put_sync(ici->v4l2_dev.dev);
+ pm_runtime_put(ici->v4l2_dev.dev);
dev_info(icd->parent,
"SuperH Mobile CEU driver detached from camera %d\n",
@@ -1064,7 +1064,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
/* Add our control */
v4l2_ctrl_new_std(&icd->ctrl_handler, &sh_mobile_ceu_ctrl_ops,
- V4L2_CID_SHARPNESS, 0, 1, 1, 0);
+ V4L2_CID_SHARPNESS, 0, 1, 1, 1);
if (icd->ctrl_handler.error)
return icd->ctrl_handler.error;
@@ -2088,15 +2088,13 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (!res || (int)irq <= 0) {
dev_err(&pdev->dev, "Not enough CEU platform resources.\n");
- err = -ENODEV;
- goto exit;
+ return -ENODEV;
}
- pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+ pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
if (!pcdev) {
dev_err(&pdev->dev, "Could not allocate pcdev\n");
- err = -ENOMEM;
- goto exit;
+ return -ENOMEM;
}
INIT_LIST_HEAD(&pcdev->capture);
@@ -2105,19 +2103,17 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
pcdev->pdata = pdev->dev.platform_data;
if (!pcdev->pdata) {
- err = -EINVAL;
dev_err(&pdev->dev, "CEU platform data not set.\n");
- goto exit_kfree;
+ return -EINVAL;
}
pcdev->max_width = pcdev->pdata->max_width ? : 2560;
pcdev->max_height = pcdev->pdata->max_height ? : 1920;
- base = ioremap_nocache(res->start, resource_size(res));
+ base = devm_request_and_ioremap(&pdev->dev, res);
if (!base) {
- err = -ENXIO;
dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n");
- goto exit_kfree;
+ return -ENXIO;
}
pcdev->irq = irq;
@@ -2133,16 +2129,15 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
DMA_MEMORY_EXCLUSIVE);
if (!err) {
dev_err(&pdev->dev, "Unable to declare CEU memory.\n");
- err = -ENXIO;
- goto exit_iounmap;
+ return -ENXIO;
}
pcdev->video_limit = resource_size(res);
}
/* request irq */
- err = request_irq(pcdev->irq, sh_mobile_ceu_irq, IRQF_DISABLED,
- dev_name(&pdev->dev), pcdev);
+ err = devm_request_irq(&pdev->dev, pcdev->irq, sh_mobile_ceu_irq,
+ IRQF_DISABLED, dev_name(&pdev->dev), pcdev);
if (err) {
dev_err(&pdev->dev, "Unable to register CEU interrupt.\n");
goto exit_release_mem;
@@ -2246,15 +2241,9 @@ exit_free_ctx:
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
exit_free_clk:
pm_runtime_disable(&pdev->dev);
- free_irq(pcdev->irq, pcdev);
exit_release_mem:
if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
dma_release_declared_memory(&pdev->dev);
-exit_iounmap:
- iounmap(base);
-exit_kfree:
- kfree(pcdev);
-exit:
return err;
}
@@ -2267,10 +2256,8 @@ static int sh_mobile_ceu_remove(struct platform_device *pdev)
soc_camera_host_unregister(soc_host);
pm_runtime_disable(&pdev->dev);
- free_irq(pcdev->irq, pcdev);
if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
dma_release_declared_memory(&pdev->dev);
- iounmap(pcdev->base);
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
if (csi2_pdev && csi2_pdev->dev.driver) {
struct module *csi2_drv = csi2_pdev->dev.driver->owner;
@@ -2279,7 +2266,6 @@ static int sh_mobile_ceu_remove(struct platform_device *pdev)
platform_device_put(csi2_pdev);
module_put(csi2_drv);
}
- kfree(pcdev);
return 0;
}
diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
index a17aba9a0104..42c559eb4937 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
@@ -318,23 +318,16 @@ static int sh_csi2_probe(struct platform_device *pdev)
return -EINVAL;
}
- priv = kzalloc(sizeof(struct sh_csi2), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_csi2), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->irq = irq;
- if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
- dev_err(&pdev->dev, "CSI2 register region already claimed\n");
- ret = -EBUSY;
- goto ereqreg;
- }
-
- priv->base = ioremap(res->start, resource_size(res));
+ priv->base = devm_request_and_ioremap(&pdev->dev, res);
if (!priv->base) {
- ret = -ENXIO;
dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n");
- goto eremap;
+ return -ENXIO;
}
priv->pdev = pdev;
@@ -357,11 +350,7 @@ static int sh_csi2_probe(struct platform_device *pdev)
return 0;
esdreg:
- iounmap(priv->base);
-eremap:
- release_mem_region(res->start, resource_size(res));
-ereqreg:
- kfree(priv);
+ platform_set_drvdata(pdev, NULL);
return ret;
}
@@ -369,14 +358,10 @@ ereqreg:
static int sh_csi2_remove(struct platform_device *pdev)
{
struct sh_csi2 *priv = platform_get_drvdata(pdev);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
v4l2_device_unregister_subdev(&priv->subdev);
pm_runtime_disable(&pdev->dev);
- iounmap(priv->base);
- release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL);
- kfree(priv);
return 0;
}
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 2ec90eae6ba0..8ec98051ea73 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -50,22 +50,22 @@ static LIST_HEAD(hosts);
static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
-int soc_camera_power_on(struct device *dev, struct soc_camera_link *icl)
+int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd)
{
- int ret = regulator_bulk_enable(icl->num_regulators,
- icl->regulators);
+ int ret = regulator_bulk_enable(ssdd->num_regulators,
+ ssdd->regulators);
if (ret < 0) {
dev_err(dev, "Cannot enable regulators\n");
return ret;
}
- if (icl->power) {
- ret = icl->power(dev, 1);
+ if (ssdd->power) {
+ ret = ssdd->power(dev, 1);
if (ret < 0) {
dev_err(dev,
"Platform failed to power-on the camera.\n");
- regulator_bulk_disable(icl->num_regulators,
- icl->regulators);
+ regulator_bulk_disable(ssdd->num_regulators,
+ ssdd->regulators);
}
}
@@ -73,13 +73,13 @@ int soc_camera_power_on(struct device *dev, struct soc_camera_link *icl)
}
EXPORT_SYMBOL(soc_camera_power_on);
-int soc_camera_power_off(struct device *dev, struct soc_camera_link *icl)
+int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd)
{
int ret = 0;
int err;
- if (icl->power) {
- err = icl->power(dev, 0);
+ if (ssdd->power) {
+ err = ssdd->power(dev, 0);
if (err < 0) {
dev_err(dev,
"Platform failed to power-off the camera.\n");
@@ -87,8 +87,8 @@ int soc_camera_power_off(struct device *dev, struct soc_camera_link *icl)
}
}
- err = regulator_bulk_disable(icl->num_regulators,
- icl->regulators);
+ err = regulator_bulk_disable(ssdd->num_regulators,
+ ssdd->regulators);
if (err < 0) {
dev_err(dev, "Cannot disable regulators\n");
ret = ret ? : err;
@@ -136,29 +136,29 @@ EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
/**
* soc_camera_apply_board_flags() - apply platform SOCAM_SENSOR_INVERT_* flags
- * @icl: camera platform parameters
+ * @ssdd: camera platform parameters
* @cfg: media bus configuration
* @return: resulting flags
*/
-unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl,
+unsigned long soc_camera_apply_board_flags(struct soc_camera_subdev_desc *ssdd,
const struct v4l2_mbus_config *cfg)
{
unsigned long f, flags = cfg->flags;
/* If only one of the two polarities is supported, switch to the opposite */
- if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) {
+ if (ssdd->flags & SOCAM_SENSOR_INVERT_HSYNC) {
f = flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW);
if (f == V4L2_MBUS_HSYNC_ACTIVE_HIGH || f == V4L2_MBUS_HSYNC_ACTIVE_LOW)
flags ^= V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW;
}
- if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) {
+ if (ssdd->flags & SOCAM_SENSOR_INVERT_VSYNC) {
f = flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW);
if (f == V4L2_MBUS_VSYNC_ACTIVE_HIGH || f == V4L2_MBUS_VSYNC_ACTIVE_LOW)
flags ^= V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW;
}
- if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) {
+ if (ssdd->flags & SOCAM_SENSOR_INVERT_PCLK) {
f = flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING);
if (f == V4L2_MBUS_PCLK_SAMPLE_RISING || f == V4L2_MBUS_PCLK_SAMPLE_FALLING)
flags ^= V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
@@ -383,7 +383,7 @@ static int soc_camera_prepare_buf(struct file *file, void *priv,
return vb2_prepare_buf(&icd->vb2_vidq, b);
}
-/* Always entered with .video_lock held */
+/* Always entered with .host_lock held */
static int soc_camera_init_user_formats(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -450,7 +450,7 @@ egfmt:
return ret;
}
-/* Always entered with .video_lock held */
+/* Always entered with .host_lock held */
static void soc_camera_free_user_formats(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -509,7 +509,7 @@ static int soc_camera_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
- struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
struct soc_camera_host *ici;
int ret;
@@ -517,9 +517,16 @@ static int soc_camera_open(struct file *file)
/* No device driver attached */
return -ENODEV;
+ /*
+ * Don't mess with the host during probe: wait until the loop in
+ * scan_add_host() completes
+ */
+ if (mutex_lock_interruptible(&list_lock))
+ return -ERESTARTSYS;
ici = to_soc_camera_host(icd->parent);
+ mutex_unlock(&list_lock);
- if (mutex_lock_interruptible(&icd->video_lock))
+ if (mutex_lock_interruptible(&ici->host_lock))
return -ERESTARTSYS;
if (!try_module_get(ici->ops->owner)) {
dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
@@ -545,13 +552,10 @@ static int soc_camera_open(struct file *file)
};
/* The camera could have been already on, try to reset */
- if (icl->reset)
- icl->reset(icd->pdev);
+ if (sdesc->subdev_desc.reset)
+ sdesc->subdev_desc.reset(icd->pdev);
- /* Don't mess with the host during probe */
- mutex_lock(&ici->host_lock);
ret = ici->ops->add(icd);
- mutex_unlock(&ici->host_lock);
if (ret < 0) {
dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
goto eiciadd;
@@ -570,7 +574,7 @@ static int soc_camera_open(struct file *file)
* Try to configure with default parameters. Notice: this is the
* very first open, so, we cannot race against other calls,
* apart from someone else calling open() simultaneously, but
- * .video_lock is protecting us against it.
+ * .host_lock is protecting us against it.
*/
ret = soc_camera_set_fmt(icd, &f);
if (ret < 0)
@@ -585,7 +589,7 @@ static int soc_camera_open(struct file *file)
}
v4l2_ctrl_handler_setup(&icd->ctrl_handler);
}
- mutex_unlock(&icd->video_lock);
+ mutex_unlock(&ici->host_lock);
file->private_data = icd;
dev_dbg(icd->pdev, "camera device open\n");
@@ -593,7 +597,7 @@ static int soc_camera_open(struct file *file)
return 0;
/*
- * First four errors are entered with the .video_lock held
+ * First four errors are entered with the .host_lock held
* and use_count == 1
*/
einitvb:
@@ -607,7 +611,7 @@ eiciadd:
icd->use_count--;
module_put(ici->ops->owner);
emodule:
- mutex_unlock(&icd->video_lock);
+ mutex_unlock(&ici->host_lock);
return ret;
}
@@ -617,7 +621,7 @@ static int soc_camera_close(struct file *file)
struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- mutex_lock(&icd->video_lock);
+ mutex_lock(&ici->host_lock);
icd->use_count--;
if (!icd->use_count) {
pm_runtime_suspend(&icd->vdev->dev);
@@ -632,7 +636,7 @@ static int soc_camera_close(struct file *file)
if (icd->streamer == file)
icd->streamer = NULL;
- mutex_unlock(&icd->video_lock);
+ mutex_unlock(&ici->host_lock);
module_put(ici->ops->owner);
@@ -669,13 +673,13 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
if (icd->streamer != file)
return -EBUSY;
- if (mutex_lock_interruptible(&icd->video_lock))
+ if (mutex_lock_interruptible(&ici->host_lock))
return -ERESTARTSYS;
if (ici->ops->init_videobuf)
err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
else
err = vb2_mmap(&icd->vb2_vidq, vma);
- mutex_unlock(&icd->video_lock);
+ mutex_unlock(&ici->host_lock);
dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n",
(unsigned long)vma->vm_start,
@@ -694,26 +698,28 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
if (icd->streamer != file)
return POLLERR;
- mutex_lock(&icd->video_lock);
+ mutex_lock(&ici->host_lock);
if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream))
dev_err(icd->pdev, "Trying to poll with no queued buffers!\n");
else
res = ici->ops->poll(file, pt);
- mutex_unlock(&icd->video_lock);
+ mutex_unlock(&ici->host_lock);
return res;
}
void soc_camera_lock(struct vb2_queue *vq)
{
struct soc_camera_device *icd = vb2_get_drv_priv(vq);
- mutex_lock(&icd->video_lock);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ mutex_lock(&ici->host_lock);
}
EXPORT_SYMBOL(soc_camera_lock);
void soc_camera_unlock(struct vb2_queue *vq)
{
struct soc_camera_device *icd = vb2_get_drv_priv(vq);
- mutex_unlock(&icd->video_lock);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ mutex_unlock(&ici->host_lock);
}
EXPORT_SYMBOL(soc_camera_unlock);
@@ -908,6 +914,8 @@ static int soc_camera_s_crop(struct file *file, void *fh,
dev_dbg(icd->pdev, "S_CROP(%ux%u@%u:%u)\n",
rect->width, rect->height, rect->left, rect->top);
+ current_crop.type = a->type;
+
/* If get_crop fails, we'll let host and / or client drivers decide */
ret = ici->ops->get_crop(icd, &current_crop);
@@ -1050,7 +1058,7 @@ static void scan_add_host(struct soc_camera_host *ici)
{
struct soc_camera_device *icd;
- mutex_lock(&ici->host_lock);
+ mutex_lock(&list_lock);
list_for_each_entry(icd, &devices, list) {
if (icd->iface == ici->nr) {
@@ -1059,28 +1067,29 @@ static void scan_add_host(struct soc_camera_host *ici)
}
}
- mutex_unlock(&ici->host_lock);
+ mutex_unlock(&list_lock);
}
#ifdef CONFIG_I2C_BOARDINFO
static int soc_camera_init_i2c(struct soc_camera_device *icd,
- struct soc_camera_link *icl)
+ struct soc_camera_desc *sdesc)
{
struct i2c_client *client;
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
+ struct soc_camera_host_desc *shd = &sdesc->host_desc;
+ struct i2c_adapter *adap = i2c_get_adapter(shd->i2c_adapter_id);
struct v4l2_subdev *subdev;
if (!adap) {
dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n",
- icl->i2c_adapter_id);
+ shd->i2c_adapter_id);
goto ei2cga;
}
- icl->board_info->platform_data = icl;
+ shd->board_info->platform_data = &sdesc->subdev_desc;
subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
- icl->board_info, NULL);
+ shd->board_info, NULL);
if (!subdev)
goto ei2cnd;
@@ -1108,7 +1117,7 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd)
i2c_put_adapter(adap);
}
#else
-#define soc_camera_init_i2c(icd, icl) (-ENODEV)
+#define soc_camera_init_i2c(icd, sdesc) (-ENODEV)
#define soc_camera_free_i2c(icd) do {} while (0)
#endif
@@ -1118,7 +1127,9 @@ static int video_dev_create(struct soc_camera_device *icd);
static int soc_camera_probe(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
+ struct soc_camera_host_desc *shd = &sdesc->host_desc;
+ struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
struct device *control = NULL;
struct v4l2_subdev *sd;
struct v4l2_mbus_framefmt mf;
@@ -1137,16 +1148,13 @@ static int soc_camera_probe(struct soc_camera_device *icd)
if (ret < 0)
return ret;
- ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
- icl->regulators);
- if (ret < 0)
- goto ereg;
-
/* The camera could have been already on, try to reset */
- if (icl->reset)
- icl->reset(icd->pdev);
+ if (ssdd->reset)
+ ssdd->reset(icd->pdev);
+ mutex_lock(&ici->host_lock);
ret = ici->ops->add(icd);
+ mutex_unlock(&ici->host_lock);
if (ret < 0)
goto eadd;
@@ -1156,18 +1164,18 @@ static int soc_camera_probe(struct soc_camera_device *icd)
goto evdc;
/* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
- if (icl->board_info) {
- ret = soc_camera_init_i2c(icd, icl);
+ if (shd->board_info) {
+ ret = soc_camera_init_i2c(icd, sdesc);
if (ret < 0)
goto eadddev;
- } else if (!icl->add_device || !icl->del_device) {
+ } else if (!shd->add_device || !shd->del_device) {
ret = -EINVAL;
goto eadddev;
} else {
- if (icl->module_name)
- ret = request_module(icl->module_name);
+ if (shd->module_name)
+ ret = request_module(shd->module_name);
- ret = icl->add_device(icd);
+ ret = shd->add_device(icd);
if (ret < 0)
goto eadddev;
@@ -1178,7 +1186,7 @@ static int soc_camera_probe(struct soc_camera_device *icd)
control = to_soc_camera_control(icd);
if (!control || !control->driver || !dev_get_drvdata(control) ||
!try_module_get(control->driver->owner)) {
- icl->del_device(icd);
+ shd->del_device(icd);
ret = -ENODEV;
goto enodrv;
}
@@ -1204,7 +1212,7 @@ static int soc_camera_probe(struct soc_camera_device *icd)
* itself is protected against concurrent open() calls, but we also have
* to protect our data.
*/
- mutex_lock(&icd->video_lock);
+ mutex_lock(&ici->host_lock);
ret = soc_camera_video_start(icd);
if (ret < 0)
@@ -1220,19 +1228,19 @@ static int soc_camera_probe(struct soc_camera_device *icd)
ici->ops->remove(icd);
- mutex_unlock(&icd->video_lock);
+ mutex_unlock(&ici->host_lock);
return 0;
evidstart:
- mutex_unlock(&icd->video_lock);
+ mutex_unlock(&ici->host_lock);
soc_camera_free_user_formats(icd);
eiufmt:
ectrl:
- if (icl->board_info) {
+ if (shd->board_info) {
soc_camera_free_i2c(icd);
} else {
- icl->del_device(icd);
+ shd->del_device(icd);
module_put(control->driver->owner);
}
enodrv:
@@ -1240,10 +1248,10 @@ eadddev:
video_device_release(icd->vdev);
icd->vdev = NULL;
evdc:
+ mutex_lock(&ici->host_lock);
ici->ops->remove(icd);
+ mutex_unlock(&ici->host_lock);
eadd:
- regulator_bulk_free(icl->num_regulators, icl->regulators);
-ereg:
v4l2_ctrl_handler_free(&icd->ctrl_handler);
return ret;
}
@@ -1254,7 +1262,7 @@ ereg:
*/
static int soc_camera_remove(struct soc_camera_device *icd)
{
- struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
struct video_device *vdev = icd->vdev;
BUG_ON(!icd->parent);
@@ -1265,19 +1273,17 @@ static int soc_camera_remove(struct soc_camera_device *icd)
icd->vdev = NULL;
}
- if (icl->board_info) {
+ if (sdesc->host_desc.board_info) {
soc_camera_free_i2c(icd);
} else {
struct device_driver *drv = to_soc_camera_control(icd)->driver;
if (drv) {
- icl->del_device(icd);
+ sdesc->host_desc.del_device(icd);
module_put(drv->owner);
}
}
soc_camera_free_user_formats(icd);
- regulator_bulk_free(icl->num_regulators, icl->regulators);
-
return 0;
}
@@ -1442,7 +1448,6 @@ static int soc_camera_device_register(struct soc_camera_device *icd)
icd->devnum = num;
icd->use_count = 0;
icd->host_priv = NULL;
- mutex_init(&icd->video_lock);
list_add_tail(&icd->list, &devices);
@@ -1500,7 +1505,7 @@ static int video_dev_create(struct soc_camera_device *icd)
vdev->release = video_device_release;
vdev->tvnorms = V4L2_STD_UNKNOWN;
vdev->ctrl_handler = &icd->ctrl_handler;
- vdev->lock = &icd->video_lock;
+ vdev->lock = &ici->host_lock;
icd->vdev = vdev;
@@ -1508,7 +1513,7 @@ static int video_dev_create(struct soc_camera_device *icd)
}
/*
- * Called from soc_camera_probe() above (with .video_lock held???)
+ * Called from soc_camera_probe() above with .host_lock held
*/
static int soc_camera_video_start(struct soc_camera_device *icd)
{
@@ -1532,18 +1537,25 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
static int soc_camera_pdrv_probe(struct platform_device *pdev)
{
- struct soc_camera_link *icl = pdev->dev.platform_data;
+ struct soc_camera_desc *sdesc = pdev->dev.platform_data;
+ struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
struct soc_camera_device *icd;
+ int ret;
- if (!icl)
+ if (!sdesc)
return -EINVAL;
icd = devm_kzalloc(&pdev->dev, sizeof(*icd), GFP_KERNEL);
if (!icd)
return -ENOMEM;
- icd->iface = icl->bus_id;
- icd->link = icl;
+ ret = devm_regulator_bulk_get(&pdev->dev, ssdd->num_regulators,
+ ssdd->regulators);
+ if (ret < 0)
+ return ret;
+
+ icd->iface = sdesc->host_desc.bus_id;
+ icd->sdesc = sdesc;
icd->pdev = &pdev->dev;
platform_set_drvdata(pdev, icd);
diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c
index 7cf7fd16481f..ce3b1d6a4734 100644
--- a/drivers/media/platform/soc_camera/soc_camera_platform.c
+++ b/drivers/media/platform/soc_camera/soc_camera_platform.c
@@ -54,7 +54,7 @@ static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on)
{
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
- return soc_camera_set_power(p->icd->control, p->icd->link, on);
+ return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, on);
}
static struct v4l2_subdev_core_ops platform_subdev_core_ops = {
@@ -148,7 +148,7 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
return -EINVAL;
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -173,7 +173,6 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
evdrs:
platform_set_drvdata(pdev, NULL);
- kfree(priv);
return ret;
}
@@ -185,7 +184,6 @@ static int soc_camera_platform_remove(struct platform_device *pdev)
p->icd->control = NULL;
v4l2_device_unregister_subdev(&priv->subdev);
platform_set_drvdata(pdev, NULL);
- kfree(priv);
return 0;
}
diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c
index a397812635d6..89dce097a827 100644
--- a/drivers/media/platform/soc_camera/soc_mediabus.c
+++ b/drivers/media/platform/soc_camera/soc_mediabus.c
@@ -378,9 +378,6 @@ EXPORT_SYMBOL(soc_mbus_samples_per_pixel);
s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
{
- if (mf->fourcc == V4L2_PIX_FMT_JPEG)
- return 0;
-
if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
return width * mf->bits_per_sample / 8;
@@ -403,9 +400,6 @@ EXPORT_SYMBOL(soc_mbus_bytes_per_line);
s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
u32 bytes_per_line, u32 height)
{
- if (mf->fourcc == V4L2_PIX_FMT_JPEG)
- return 0;
-
if (mf->layout == SOC_MBUS_LAYOUT_PACKED)
return bytes_per_line * height;
diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c
index d854d08a6c7f..c3a2a4484401 100644
--- a/drivers/media/platform/timblogiw.c
+++ b/drivers/media/platform/timblogiw.c
@@ -130,7 +130,7 @@ static void timblogiw_dma_cb(void *data)
if (vb->state != VIDEOBUF_ERROR) {
list_del(&vb->queue);
- do_gettimeofday(&vb->ts);
+ v4l2_get_timestamp(&vb->ts);
vb->field_count = fh->frame_count * 2;
vb->state = VIDEOBUF_DONE;
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index 63e8c3461239..b051c4a28554 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -18,6 +18,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
#include <media/ov7670.h>
#include <media/videobuf-dma-sg.h>
#include <linux/delay.h>
@@ -63,6 +64,7 @@ enum viacam_opstate { S_IDLE = 0, S_RUNNING = 1 };
struct via_camera {
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
struct video_device vdev;
struct v4l2_subdev *sensor;
struct platform_device *platdev;
@@ -818,47 +820,6 @@ static int viacam_g_chip_ident(struct file *file, void *priv,
}
/*
- * Control ops are passed through to the sensor.
- */
-static int viacam_queryctrl(struct file *filp, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct via_camera *cam = priv;
- int ret;
-
- mutex_lock(&cam->lock);
- ret = sensor_call(cam, core, queryctrl, qc);
- mutex_unlock(&cam->lock);
- return ret;
-}
-
-
-static int viacam_g_ctrl(struct file *filp, void *priv,
- struct v4l2_control *ctrl)
-{
- struct via_camera *cam = priv;
- int ret;
-
- mutex_lock(&cam->lock);
- ret = sensor_call(cam, core, g_ctrl, ctrl);
- mutex_unlock(&cam->lock);
- return ret;
-}
-
-
-static int viacam_s_ctrl(struct file *filp, void *priv,
- struct v4l2_control *ctrl)
-{
- struct via_camera *cam = priv;
- int ret;
-
- mutex_lock(&cam->lock);
- ret = sensor_call(cam, core, s_ctrl, ctrl);
- mutex_unlock(&cam->lock);
- return ret;
-}
-
-/*
* Only one input.
*/
static int viacam_enum_input(struct file *filp, void *priv,
@@ -1214,9 +1175,6 @@ static int viacam_enum_frameintervals(struct file *filp, void *priv,
static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
.vidioc_g_chip_ident = viacam_g_chip_ident,
- .vidioc_queryctrl = viacam_queryctrl,
- .vidioc_g_ctrl = viacam_g_ctrl,
- .vidioc_s_ctrl = viacam_s_ctrl,
.vidioc_enum_input = viacam_enum_input,
.vidioc_g_input = viacam_g_input,
.vidioc_s_input = viacam_s_input,
@@ -1418,8 +1376,12 @@ static int viacam_probe(struct platform_device *pdev)
ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
if (ret) {
dev_err(&pdev->dev, "Unable to register v4l2 device\n");
- return ret;
+ goto out_free;
}
+ ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10);
+ if (ret)
+ goto out_unregister;
+ cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler;
/*
* Convince the system that we can do DMA.
*/
@@ -1436,7 +1398,7 @@ static int viacam_probe(struct platform_device *pdev)
*/
ret = via_sensor_power_setup(cam);
if (ret)
- goto out_unregister;
+ goto out_ctrl_hdl_free;
via_sensor_power_up(cam);
/*
@@ -1485,8 +1447,12 @@ out_irq:
free_irq(viadev->pdev->irq, cam);
out_power_down:
via_sensor_power_release(cam);
+out_ctrl_hdl_free:
+ v4l2_ctrl_handler_free(&cam->ctrl_handler);
out_unregister:
v4l2_device_unregister(&cam->v4l2_dev);
+out_free:
+ kfree(cam);
return ret;
}
@@ -1499,6 +1465,8 @@ static int viacam_remove(struct platform_device *pdev)
v4l2_device_unregister(&cam->v4l2_dev);
free_irq(viadev->pdev->irq, cam);
via_sensor_power_release(cam);
+ v4l2_ctrl_handler_free(&cam->ctrl_handler);
+ kfree(cam);
via_cam_info = NULL;
return 0;
}
diff --git a/drivers/media/platform/vino.c b/drivers/media/platform/vino.c
index 70b0bf4b2900..eb5d6f955709 100644
--- a/drivers/media/platform/vino.c
+++ b/drivers/media/platform/vino.c
@@ -2474,8 +2474,8 @@ static irqreturn_t vino_interrupt(int irq, void *dev_id)
if ((!handled_a) && (done_a || skip_a)) {
if (!skip_a) {
- do_gettimeofday(&vino_drvdata->
- a.int_data.timestamp);
+ v4l2_get_timestamp(
+ &vino_drvdata->a.int_data.timestamp);
vino_drvdata->a.int_data.frame_counter = fc_a;
}
vino_drvdata->a.int_data.skip = skip_a;
@@ -2489,8 +2489,8 @@ static irqreturn_t vino_interrupt(int irq, void *dev_id)
if ((!handled_b) && (done_b || skip_b)) {
if (!skip_b) {
- do_gettimeofday(&vino_drvdata->
- b.int_data.timestamp);
+ v4l2_get_timestamp(
+ &vino_drvdata->b.int_data.timestamp);
vino_drvdata->b.int_data.frame_counter = fc_b;
}
vino_drvdata->b.int_data.skip = skip_b;
@@ -3410,6 +3410,9 @@ static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs,
if (fb->map_count > 0)
b->flags |= V4L2_BUF_FLAG_MAPPED;
+ b->flags &= ~V4L2_BUF_FLAG_TIMESTAMP_MASK;
+ b->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+
b->index = fb->id;
b->memory = (vcs->fb_queue.type == VINO_MEMORY_MMAP) ?
V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
index 0d59b9db83cb..8a33a712f480 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -36,9 +36,17 @@
#define VIVI_MODULE_NAME "vivi"
-/* Wake up at about 30 fps */
-#define WAKE_NUMERATOR 30
-#define WAKE_DENOMINATOR 1001
+/* Maximum allowed frame rate
+ *
+ * Vivi will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range.
+ *
+ * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that
+ * might hit application errors when they manipulate these values.
+ *
+ * Besides, for tpf < 1ms image-generation logic should be changed, to avoid
+ * producing frames with equal content.
+ */
+#define FPS_MAX 1000
#define MAX_WIDTH 1920
#define MAX_HEIGHT 1200
@@ -69,6 +77,12 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
/* Global font descriptor */
static const u8 *font8x16;
+/* timeperframe: min/max and default */
+static const struct v4l2_fract
+ tpf_min = {.numerator = 1, .denominator = FPS_MAX},
+ tpf_max = {.numerator = FPS_MAX, .denominator = 1},
+ tpf_default = {.numerator = 1001, .denominator = 30000}; /* NTSC */
+
#define dprintk(dev, level, fmt, arg...) \
v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
@@ -77,13 +91,13 @@ static const u8 *font8x16;
------------------------------------------------------------------*/
struct vivi_fmt {
- char *name;
+ const char *name;
u32 fourcc; /* v4l2 format id */
u8 depth;
bool is_yuv;
};
-static struct vivi_fmt formats[] = {
+static const struct vivi_fmt formats[] = {
{
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
@@ -150,14 +164,14 @@ static struct vivi_fmt formats[] = {
},
};
-static struct vivi_fmt *get_format(struct v4l2_format *f)
+static const struct vivi_fmt *__get_format(u32 pixelformat)
{
- struct vivi_fmt *fmt;
+ const struct vivi_fmt *fmt;
unsigned int k;
for (k = 0; k < ARRAY_SIZE(formats); k++) {
fmt = &formats[k];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
+ if (fmt->fourcc == pixelformat)
break;
}
@@ -167,12 +181,17 @@ static struct vivi_fmt *get_format(struct v4l2_format *f)
return &formats[k];
}
+static const struct vivi_fmt *get_format(struct v4l2_format *f)
+{
+ return __get_format(f->fmt.pix.pixelformat);
+}
+
/* buffer for one video frame */
struct vivi_buffer {
/* common v4l buffer stuff -- must be first */
struct vb2_buffer vb;
struct list_head list;
- struct vivi_fmt *fmt;
+ const struct vivi_fmt *fmt;
};
struct vivi_dmaqueue {
@@ -231,15 +250,17 @@ struct vivi_dev {
int input;
/* video capture */
- struct vivi_fmt *fmt;
+ const struct vivi_fmt *fmt;
+ struct v4l2_fract timeperframe;
unsigned int width, height;
struct vb2_queue vb_vidq;
unsigned int field_count;
u8 bars[9][3];
- u8 line[MAX_WIDTH * 8];
+ u8 line[MAX_WIDTH * 8] __attribute__((__aligned__(4)));
unsigned int pixelsize;
u8 alpha_component;
+ u32 textfg, textbg;
};
/* ------------------------------------------------------------------
@@ -276,7 +297,7 @@ struct bar_std {
/* Maximum number of bars are 10 - otherwise, the input print code
should be modified */
-static struct bar_std bars[] = {
+static const struct bar_std bars[] = {
{ /* Standard ITU-R color bar sequence */
{ COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN,
COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
@@ -511,66 +532,100 @@ static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
static void precalculate_line(struct vivi_dev *dev)
{
- int w;
-
- for (w = 0; w < dev->width * 2; w++) {
- int colorpos = w / (dev->width / 8) % 8;
-
- gen_twopix(dev, dev->line + w * dev->pixelsize, colorpos, w & 1);
+ unsigned pixsize = dev->pixelsize;
+ unsigned pixsize2 = 2*pixsize;
+ int colorpos;
+ u8 *pos;
+
+ for (colorpos = 0; colorpos < 16; ++colorpos) {
+ u8 pix[8];
+ int wstart = colorpos * dev->width / 8;
+ int wend = (colorpos+1) * dev->width / 8;
+ int w;
+
+ gen_twopix(dev, &pix[0], colorpos % 8, 0);
+ gen_twopix(dev, &pix[pixsize], colorpos % 8, 1);
+
+ for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize2)
+ memcpy(pos, pix, pixsize2);
}
}
+/* need this to do rgb24 rendering */
+typedef struct { u16 __; u8 _; } __attribute__((packed)) x24;
+
static void gen_text(struct vivi_dev *dev, char *basep,
int y, int x, char *text)
{
int line;
+ unsigned int width = dev->width;
/* Checks if it is possible to show string */
- if (y + 16 >= dev->height || x + strlen(text) * 8 >= dev->width)
+ if (y + 16 >= dev->height || x + strlen(text) * 8 >= width)
return;
/* Print stream time */
- for (line = y; line < y + 16; line++) {
- int j = 0;
- char *pos = basep + line * dev->width * dev->pixelsize + x * dev->pixelsize;
- char *s;
-
- for (s = text; *s; s++) {
- u8 chr = font8x16[*s * 16 + line - y];
- int i;
-
- for (i = 0; i < 7; i++, j++) {
- /* Draw white font on black background */
- if (chr & (1 << (7 - i)))
- gen_twopix(dev, pos + j * dev->pixelsize, WHITE, (x+y) & 1);
- else
- gen_twopix(dev, pos + j * dev->pixelsize, TEXT_BLACK, (x+y) & 1);
- }
- }
+#define PRINTSTR(PIXTYPE) do { \
+ PIXTYPE fg; \
+ PIXTYPE bg; \
+ memcpy(&fg, &dev->textfg, sizeof(PIXTYPE)); \
+ memcpy(&bg, &dev->textbg, sizeof(PIXTYPE)); \
+ \
+ for (line = 0; line < 16; line++) { \
+ PIXTYPE *pos = (PIXTYPE *)( basep + ((y + line) * width + x) * sizeof(PIXTYPE) ); \
+ u8 *s; \
+ \
+ for (s = text; *s; s++) { \
+ u8 chr = font8x16[*s * 16 + line]; \
+ \
+ pos[0] = (chr & (0x01 << 7) ? fg : bg); \
+ pos[1] = (chr & (0x01 << 6) ? fg : bg); \
+ pos[2] = (chr & (0x01 << 5) ? fg : bg); \
+ pos[3] = (chr & (0x01 << 4) ? fg : bg); \
+ pos[4] = (chr & (0x01 << 3) ? fg : bg); \
+ pos[5] = (chr & (0x01 << 2) ? fg : bg); \
+ pos[6] = (chr & (0x01 << 1) ? fg : bg); \
+ pos[7] = (chr & (0x01 << 0) ? fg : bg); \
+ \
+ pos += 8; \
+ } \
+ } \
+} while (0)
+
+ switch (dev->pixelsize) {
+ case 2:
+ PRINTSTR(u16); break;
+ case 4:
+ PRINTSTR(u32); break;
+ case 3:
+ PRINTSTR(x24); break;
}
}
static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
{
- int wmax = dev->width;
+ int stride = dev->width * dev->pixelsize;
int hmax = dev->height;
- struct timeval ts;
void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
unsigned ms;
char str[100];
int h, line = 1;
+ u8 *linestart;
s32 gain;
if (!vbuf)
return;
+ linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize;
+
for (h = 0; h < hmax; h++)
- memcpy(vbuf + h * wmax * dev->pixelsize,
- dev->line + (dev->mv_count % wmax) * dev->pixelsize,
- wmax * dev->pixelsize);
+ memcpy(vbuf + h * stride, linestart, stride);
/* Updates stream time */
+ gen_twopix(dev, (u8 *)&dev->textbg, TEXT_BLACK, /*odd=*/ 0);
+ gen_twopix(dev, (u8 *)&dev->textfg, WHITE, /*odd=*/ 0);
+
dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
dev->jiffies = jiffies;
ms = dev->ms;
@@ -622,8 +677,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
dev->field_count++;
buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
- do_gettimeofday(&ts);
- buf->vb.v4l2_buf.timestamp = ts;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
}
static void vivi_thread_tick(struct vivi_dev *dev)
@@ -645,7 +699,7 @@ static void vivi_thread_tick(struct vivi_dev *dev)
list_del(&buf->list);
spin_unlock_irqrestore(&dev->slock, flags);
- do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
/* Fill buffer */
vivi_fillbuff(dev, buf);
@@ -655,8 +709,8 @@ static void vivi_thread_tick(struct vivi_dev *dev)
dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
}
-#define frames_to_ms(frames) \
- ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
+#define frames_to_ms(dev, frames) \
+ ((frames * dev->timeperframe.numerator * 1000) / dev->timeperframe.denominator)
static void vivi_sleep(struct vivi_dev *dev)
{
@@ -672,7 +726,7 @@ static void vivi_sleep(struct vivi_dev *dev)
goto stop_task;
/* Calculate time to wake up */
- timeout = msecs_to_jiffies(frames_to_ms(1));
+ timeout = msecs_to_jiffies(frames_to_ms(dev, 1));
vivi_thread_tick(dev);
@@ -872,7 +926,7 @@ static void vivi_unlock(struct vb2_queue *vq)
}
-static struct vb2_ops vivi_video_qops = {
+static const struct vb2_ops vivi_video_qops = {
.queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
@@ -903,7 +957,7 @@ static int vidioc_querycap(struct file *file, void *priv,
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- struct vivi_fmt *fmt;
+ const struct vivi_fmt *fmt;
if (f->index >= ARRAY_SIZE(formats))
return -EINVAL;
@@ -939,7 +993,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_dev *dev = video_drvdata(file);
- struct vivi_fmt *fmt;
+ const struct vivi_fmt *fmt;
fmt = get_format(f);
if (!fmt) {
@@ -1044,6 +1098,70 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
+/* timeperframe is arbitrary and continous */
+static int vidioc_enum_frameintervals(struct file *file, void *priv,
+ struct v4l2_frmivalenum *fival)
+{
+ const struct vivi_fmt *fmt;
+
+ if (fival->index)
+ return -EINVAL;
+
+ fmt = __get_format(fival->pixel_format);
+ if (!fmt)
+ return -EINVAL;
+
+ /* regarding width & height - we support any */
+
+ fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
+
+ /* fill in stepwise (step=1.0 is requred by V4L2 spec) */
+ fival->stepwise.min = tpf_min;
+ fival->stepwise.max = tpf_max;
+ fival->stepwise.step = (struct v4l2_fract) {1, 1};
+
+ return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct vivi_dev *dev = video_drvdata(file);
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.timeperframe = dev->timeperframe;
+ parm->parm.capture.readbuffers = 1;
+ return 0;
+}
+
+#define FRACT_CMP(a, OP, b) \
+ ((u64)(a).numerator * (b).denominator OP (u64)(b).numerator * (a).denominator)
+
+static int vidioc_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct vivi_dev *dev = video_drvdata(file);
+ struct v4l2_fract tpf;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ tpf = parm->parm.capture.timeperframe;
+
+ /* tpf: {*, 0} resets timing; clip to [min, max]*/
+ tpf = tpf.denominator ? tpf : tpf_default;
+ tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
+ tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
+
+ dev->timeperframe = tpf;
+ parm->parm.capture.timeperframe = tpf;
+ parm->parm.capture.readbuffers = 1;
+ return 0;
+}
+
/* --- controls ---------------------------------------------- */
static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -1202,6 +1320,9 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
+ .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_s_parm = vidioc_s_parm,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_log_status = v4l2_ctrl_log_status,
@@ -1209,7 +1330,7 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
-static struct video_device vivi_template = {
+static const struct video_device vivi_template = {
.name = "vivi",
.fops = &vivi_fops,
.ioctl_ops = &vivi_ioctl_ops,
@@ -1260,6 +1381,7 @@ static int __init vivi_create_instance(int inst)
goto free_dev;
dev->fmt = &formats[0];
+ dev->timeperframe = tpf_default;
dev->width = 640;
dev->height = 480;
dev->pixelsize = dev->fmt->depth / 8;
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 8090b87b3066..24e64a09884c 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -124,6 +124,18 @@ config USB_KEENE
To compile this driver as a module, choose M here: the
module will be called radio-keene.
+config USB_MA901
+ tristate "Masterkit MA901 USB FM radio support"
+ depends on USB && VIDEO_V4L2
+ ---help---
+ Say Y here if you want to connect this type of radio to your
+ computer's USB port. Note that the audio is not digital, and
+ you must connect the line out connector to a sound card or a
+ set of speakers or headphones.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-ma901.
+
config RADIO_TEA5764
tristate "TEA5764 I2C FM radio support"
depends on I2C && VIDEO_V4L2
@@ -180,7 +192,7 @@ config RADIO_TIMBERDALE
config RADIO_WL1273
tristate "Texas Instruments WL1273 I2C FM Radio"
- depends on I2C && VIDEO_V4L2
+ depends on I2C && VIDEO_V4L2 && GENERIC_HARDIRQS
select MFD_CORE
select MFD_WL1273_CORE
select FW_LOADER
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index c03ce4fe74e9..303eaebdb85a 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_RADIO_SI470X) += si470x/
obj-$(CONFIG_USB_MR800) += radio-mr800.o
obj-$(CONFIG_USB_KEENE) += radio-keene.o
+obj-$(CONFIG_USB_MA901) += radio-ma901.o
obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c
new file mode 100644
index 000000000000..c61f590029ad
--- /dev/null
+++ b/drivers/media/radio/radio-ma901.c
@@ -0,0 +1,460 @@
+/*
+ * Driver for the MasterKit MA901 USB FM radio. This device plugs
+ * into the USB port and an analog audio input or headphones, so this thing
+ * only deals with initialization, frequency setting, volume.
+ *
+ * Copyright (c) 2012 Alexey Klimov <klimov.linux@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+
+#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
+#define DRIVER_DESC "Masterkit MA901 USB FM radio driver"
+#define DRIVER_VERSION "0.0.1"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+#define USB_MA901_VENDOR 0x16c0
+#define USB_MA901_PRODUCT 0x05df
+
+/* dev_warn macro with driver name */
+#define MA901_DRIVER_NAME "radio-ma901"
+#define ma901radio_dev_warn(dev, fmt, arg...) \
+ dev_warn(dev, MA901_DRIVER_NAME " - " fmt, ##arg)
+
+#define ma901radio_dev_err(dev, fmt, arg...) \
+ dev_err(dev, MA901_DRIVER_NAME " - " fmt, ##arg)
+
+/* Probably USB_TIMEOUT should be modified in module parameter */
+#define BUFFER_LENGTH 8
+#define USB_TIMEOUT 500
+
+#define FREQ_MIN 87.5
+#define FREQ_MAX 108.0
+#define FREQ_MUL 16000
+
+#define MA901_VOLUME_MAX 16
+#define MA901_VOLUME_MIN 0
+
+/* Commands that device should understand
+ * List isn't full and will be updated with implementation of new functions
+ */
+#define MA901_RADIO_SET_FREQ 0x03
+#define MA901_RADIO_SET_VOLUME 0x04
+#define MA901_RADIO_SET_MONO_STEREO 0x05
+
+/* Comfortable defines for ma901radio_set_stereo */
+#define MA901_WANT_STEREO 0x50
+#define MA901_WANT_MONO 0xd0
+
+/* module parameter */
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "Radio file number");
+
+/* Data for one (physical) device */
+struct ma901radio_device {
+ /* reference to USB and video device */
+ struct usb_device *usbdev;
+ struct usb_interface *intf;
+ struct video_device vdev;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler hdl;
+
+ u8 *buffer;
+ struct mutex lock; /* buffer locking */
+ int curfreq;
+ u16 volume;
+ int stereo;
+ bool muted;
+};
+
+static inline struct ma901radio_device *to_ma901radio_dev(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct ma901radio_device, v4l2_dev);
+}
+
+/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static int ma901radio_set_freq(struct ma901radio_device *radio, int freq)
+{
+ unsigned int freq_send = 0x300 + (freq >> 5) / 25;
+ int retval;
+
+ radio->buffer[0] = 0x0a;
+ radio->buffer[1] = MA901_RADIO_SET_FREQ;
+ radio->buffer[2] = ((freq_send >> 8) & 0xff) + 0x80;
+ radio->buffer[3] = freq_send & 0xff;
+ radio->buffer[4] = 0x00;
+ radio->buffer[5] = 0x00;
+ radio->buffer[6] = 0x00;
+ radio->buffer[7] = 0x00;
+
+ retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+ 9, 0x21, 0x0300, 0,
+ radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
+ if (retval < 0)
+ return retval;
+
+ radio->curfreq = freq;
+ return 0;
+}
+
+static int ma901radio_set_volume(struct ma901radio_device *radio, u16 vol_to_set)
+{
+ int retval;
+
+ radio->buffer[0] = 0x0a;
+ radio->buffer[1] = MA901_RADIO_SET_VOLUME;
+ radio->buffer[2] = 0xc2;
+ radio->buffer[3] = vol_to_set + 0x20;
+ radio->buffer[4] = 0x00;
+ radio->buffer[5] = 0x00;
+ radio->buffer[6] = 0x00;
+ radio->buffer[7] = 0x00;
+
+ retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+ 9, 0x21, 0x0300, 0,
+ radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
+ if (retval < 0)
+ return retval;
+
+ radio->volume = vol_to_set;
+ return retval;
+}
+
+static int ma901_set_stereo(struct ma901radio_device *radio, u8 stereo)
+{
+ int retval;
+
+ radio->buffer[0] = 0x0a;
+ radio->buffer[1] = MA901_RADIO_SET_MONO_STEREO;
+ radio->buffer[2] = stereo;
+ radio->buffer[3] = 0x00;
+ radio->buffer[4] = 0x00;
+ radio->buffer[5] = 0x00;
+ radio->buffer[6] = 0x00;
+ radio->buffer[7] = 0x00;
+
+ retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+ 9, 0x21, 0x0300, 0,
+ radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
+
+ if (retval < 0)
+ return retval;
+
+ if (stereo == MA901_WANT_STEREO)
+ radio->stereo = V4L2_TUNER_MODE_STEREO;
+ else
+ radio->stereo = V4L2_TUNER_MODE_MONO;
+
+ return retval;
+}
+
+/* Handle unplugging the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_ma901radio_device_release.
+ */
+static void usb_ma901radio_disconnect(struct usb_interface *intf)
+{
+ struct ma901radio_device *radio = to_ma901radio_dev(usb_get_intfdata(intf));
+
+ mutex_lock(&radio->lock);
+ video_unregister_device(&radio->vdev);
+ usb_set_intfdata(intf, NULL);
+ v4l2_device_disconnect(&radio->v4l2_dev);
+ mutex_unlock(&radio->lock);
+ v4l2_device_put(&radio->v4l2_dev);
+}
+
+/* vidioc_querycap - query device capabilities */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
+{
+ struct ma901radio_device *radio = video_drvdata(file);
+
+ strlcpy(v->driver, "radio-ma901", sizeof(v->driver));
+ strlcpy(v->card, "Masterkit MA901 USB FM Radio", sizeof(v->card));
+ usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
+ v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+/* vidioc_g_tuner - get tuner attributes */
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ struct ma901radio_device *radio = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+ v->signal = 0;
+
+ /* TODO: the same words like in _probe() goes here.
+ * When receiving of stats will be implemented then we can call
+ * ma901radio_get_stat().
+ * retval = ma901radio_get_stat(radio, &is_stereo, &v->signal);
+ */
+
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+ v->rangelow = FREQ_MIN * FREQ_MUL;
+ v->rangehigh = FREQ_MAX * FREQ_MUL;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ /* v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; */
+ v->audmode = radio->stereo ?
+ V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+ return 0;
+}
+
+/* vidioc_s_tuner - set tuner attributes */
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ struct ma901radio_device *radio = video_drvdata(file);
+
+ if (v->index > 0)
+ return -EINVAL;
+
+ /* mono/stereo selector */
+ switch (v->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ return ma901_set_stereo(radio, MA901_WANT_MONO);
+ default:
+ return ma901_set_stereo(radio, MA901_WANT_STEREO);
+ }
+}
+
+/* vidioc_s_frequency - set tuner radio frequency */
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct ma901radio_device *radio = video_drvdata(file);
+
+ if (f->tuner != 0)
+ return -EINVAL;
+
+ return ma901radio_set_freq(radio, clamp_t(unsigned, f->frequency,
+ FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL));
+}
+
+/* vidioc_g_frequency - get tuner radio frequency */
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct ma901radio_device *radio = video_drvdata(file);
+
+ if (f->tuner != 0)
+ return -EINVAL;
+ f->frequency = radio->curfreq;
+
+ return 0;
+}
+
+static int usb_ma901radio_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ma901radio_device *radio =
+ container_of(ctrl->handler, struct ma901radio_device, hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME: /* set volume */
+ return ma901radio_set_volume(radio, (u16)ctrl->val);
+ }
+
+ return -EINVAL;
+}
+
+/* TODO: Should we really need to implement suspend and resume functions?
+ * Radio has it's own memory and will continue playing if power is present
+ * on usb port and on resume it will start to play again based on freq, volume
+ * values in device memory.
+ */
+static int usb_ma901radio_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ return 0;
+}
+
+static int usb_ma901radio_resume(struct usb_interface *intf)
+{
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops usb_ma901radio_ctrl_ops = {
+ .s_ctrl = usb_ma901radio_s_ctrl,
+};
+
+/* File system interface */
+static const struct v4l2_file_operations usb_ma901radio_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops usb_ma901radio_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static void usb_ma901radio_release(struct v4l2_device *v4l2_dev)
+{
+ struct ma901radio_device *radio = to_ma901radio_dev(v4l2_dev);
+
+ v4l2_ctrl_handler_free(&radio->hdl);
+ v4l2_device_unregister(&radio->v4l2_dev);
+ kfree(radio->buffer);
+ kfree(radio);
+}
+
+/* check if the device is present and register with v4l and usb if it is */
+static int usb_ma901radio_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct ma901radio_device *radio;
+ int retval = 0;
+
+ radio = kzalloc(sizeof(struct ma901radio_device), GFP_KERNEL);
+ if (!radio) {
+ dev_err(&intf->dev, "kzalloc for ma901radio_device failed\n");
+ retval = -ENOMEM;
+ goto err;
+ }
+
+ radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+ if (!radio->buffer) {
+ dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
+ retval = -ENOMEM;
+ goto err_nobuf;
+ }
+
+ retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
+ if (retval < 0) {
+ dev_err(&intf->dev, "couldn't register v4l2_device\n");
+ goto err_v4l2;
+ }
+
+ v4l2_ctrl_handler_init(&radio->hdl, 1);
+
+ /* TODO:It looks like this radio doesn't have mute/unmute control
+ * and windows program just emulate it using volume control.
+ * Let's plan to do the same in this driver.
+ *
+ * v4l2_ctrl_new_std(&radio->hdl, &usb_ma901radio_ctrl_ops,
+ * V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ */
+
+ v4l2_ctrl_new_std(&radio->hdl, &usb_ma901radio_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, MA901_VOLUME_MIN,
+ MA901_VOLUME_MAX, 1, MA901_VOLUME_MAX);
+
+ if (radio->hdl.error) {
+ retval = radio->hdl.error;
+ dev_err(&intf->dev, "couldn't register control\n");
+ goto err_ctrl;
+ }
+ mutex_init(&radio->lock);
+
+ radio->v4l2_dev.ctrl_handler = &radio->hdl;
+ radio->v4l2_dev.release = usb_ma901radio_release;
+ strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+ sizeof(radio->vdev.name));
+ radio->vdev.v4l2_dev = &radio->v4l2_dev;
+ radio->vdev.fops = &usb_ma901radio_fops;
+ radio->vdev.ioctl_ops = &usb_ma901radio_ioctl_ops;
+ radio->vdev.release = video_device_release_empty;
+ radio->vdev.lock = &radio->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
+
+ radio->usbdev = interface_to_usbdev(intf);
+ radio->intf = intf;
+ usb_set_intfdata(intf, &radio->v4l2_dev);
+ radio->curfreq = 95.21 * FREQ_MUL;
+
+ video_set_drvdata(&radio->vdev, radio);
+
+ /* TODO: we can get some statistics (freq, volume) from device
+ * but it's not implemented yet. After insertion in usb-port radio
+ * setups frequency and starts playing without any initialization.
+ * So we don't call usb_ma901radio_init/get_stat() here.
+ * retval = usb_ma901radio_init(radio);
+ */
+
+ retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO,
+ radio_nr);
+ if (retval < 0) {
+ dev_err(&intf->dev, "could not register video device\n");
+ goto err_vdev;
+ }
+
+ return 0;
+
+err_vdev:
+ v4l2_ctrl_handler_free(&radio->hdl);
+err_ctrl:
+ v4l2_device_unregister(&radio->v4l2_dev);
+err_v4l2:
+ kfree(radio->buffer);
+err_nobuf:
+ kfree(radio);
+err:
+ return retval;
+}
+
+/* USB Device ID List */
+static struct usb_device_id usb_ma901radio_device_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(USB_MA901_VENDOR, USB_MA901_PRODUCT,
+ USB_CLASS_HID, 0, 0) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_ma901radio_device_table);
+
+/* USB subsystem interface */
+static struct usb_driver usb_ma901radio_driver = {
+ .name = MA901_DRIVER_NAME,
+ .probe = usb_ma901radio_probe,
+ .disconnect = usb_ma901radio_disconnect,
+ .suspend = usb_ma901radio_suspend,
+ .resume = usb_ma901radio_resume,
+ .reset_resume = usb_ma901radio_resume,
+ .id_table = usb_ma901radio_device_table,
+};
+
+module_usb_driver(usb_ma901radio_driver);
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index 11f76ed4c6fb..3d0ff4404d12 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -17,49 +17,36 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
#include <sound/aci.h>
static int radio_nr = -1;
module_param(radio_nr, int, 0);
MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");
-static bool mono;
-module_param(mono, bool, 0);
-MODULE_PARM_DESC(mono, "Force tuner into mono mode.");
-
struct pcm20 {
struct v4l2_device v4l2_dev;
struct video_device vdev;
+ struct v4l2_ctrl_handler ctrl_handler;
unsigned long freq;
- int muted;
+ u32 audmode;
struct snd_miro_aci *aci;
struct mutex lock;
};
static struct pcm20 pcm20_card = {
- .freq = 87*16000,
- .muted = 1,
+ .freq = 87 * 16000,
+ .audmode = V4L2_TUNER_MODE_STEREO,
};
-static int pcm20_mute(struct pcm20 *dev, unsigned char mute)
-{
- dev->muted = mute;
- return snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, mute, -1);
-}
-
-static int pcm20_stereo(struct pcm20 *dev, unsigned char stereo)
-{
- return snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, !stereo, -1);
-}
-
static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
{
unsigned char freql;
unsigned char freqh;
struct snd_miro_aci *aci = dev->aci;
- dev->freq = freq;
-
freq /= 160;
if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0))
freq /= 10; /* I don't know exactly which version
@@ -67,46 +54,66 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
freql = freq & 0xff;
freqh = freq >> 8;
- pcm20_stereo(dev, !mono);
return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh);
}
static const struct v4l2_file_operations pcm20_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .poll = v4l2_ctrl_poll,
+ .release = v4l2_fh_release,
.unlocked_ioctl = video_ioctl2,
};
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
+ struct pcm20 *dev = video_drvdata(file);
+
strlcpy(v->driver, "Miro PCM20", sizeof(v->driver));
strlcpy(v->card, "Miro PCM20", sizeof(v->card));
- strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->version = 0x1;
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name);
+ v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
- if (v->index) /* Only 1 tuner */
+ struct pcm20 *dev = video_drvdata(file);
+ int res;
+
+ if (v->index)
return -EINVAL;
strlcpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
v->rangelow = 87*16000;
v->rangehigh = 108*16000;
- v->signal = 0xffff;
- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- v->capability = V4L2_TUNER_CAP_LOW;
- v->audmode = V4L2_TUNER_MODE_MONO;
+ res = snd_aci_cmd(dev->aci, ACI_READ_TUNERSTATION, -1, -1);
+ v->signal = (res & 0x80) ? 0 : 0xffff;
+ /* Note: stereo detection does not work if the audio is muted,
+ it will default to mono in that case. */
+ res = snd_aci_cmd(dev->aci, ACI_READ_TUNERSTEREO, -1, -1);
+ v->rxsubchans = (res & 0x40) ? V4L2_TUNER_SUB_MONO :
+ V4L2_TUNER_SUB_STEREO;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ v->audmode = dev->audmode;
return 0;
}
static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
- return v->index ? -EINVAL : 0;
+ struct pcm20 *dev = video_drvdata(file);
+
+ if (v->index)
+ return -EINVAL;
+ if (v->audmode > V4L2_TUNER_MODE_STEREO)
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO,
+ v->audmode == V4L2_TUNER_MODE_MONO, -1);
+ return 0;
}
static int vidioc_g_frequency(struct file *file, void *priv,
@@ -131,75 +138,21 @@ static int vidioc_s_frequency(struct file *file, void *priv,
if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
return -EINVAL;
- dev->freq = f->frequency;
- pcm20_setfreq(dev, f->frequency);
- 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 pcm20 *dev = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = dev->muted;
- break;
- default:
- return -EINVAL;
- }
+ dev->freq = clamp(f->frequency, 87 * 16000U, 108 * 16000U);
+ pcm20_setfreq(dev, dev->freq);
return 0;
}
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int pcm20_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct pcm20 *dev = video_drvdata(file);
+ struct pcm20 *dev = container_of(ctrl->handler, struct pcm20, ctrl_handler);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- pcm20_mute(dev, ctrl->value);
- break;
- default:
- return -EINVAL;
+ snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, ctrl->val, -1);
+ return 0;
}
- return 0;
-}
-
-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,
- const struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
+ return -EINVAL;
}
static const struct v4l2_ioctl_ops pcm20_ioctl_ops = {
@@ -208,19 +161,20 @@ static const struct v4l2_ioctl_ops pcm20_ioctl_ops = {
.vidioc_s_tuner = vidioc_s_tuner,
.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,
- .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_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops pcm20_ctrl_ops = {
+ .s_ctrl = pcm20_s_ctrl,
};
static int __init pcm20_init(void)
{
struct pcm20 *dev = &pcm20_card;
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+ struct v4l2_ctrl_handler *hdl;
int res;
dev->aci = snd_aci_get_aci();
@@ -229,7 +183,7 @@ static int __init pcm20_init(void)
"you must load the snd-miro driver first!\n");
return -ENODEV;
}
- strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name));
+ strlcpy(v4l2_dev->name, "radio-miropcm20", sizeof(v4l2_dev->name));
mutex_init(&dev->lock);
res = v4l2_device_register(NULL, v4l2_dev);
@@ -238,20 +192,35 @@ static int __init pcm20_init(void)
return -EINVAL;
}
+ hdl = &dev->ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 1);
+ v4l2_ctrl_new_std(hdl, &pcm20_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ v4l2_dev->ctrl_handler = hdl;
+ if (hdl->error) {
+ res = hdl->error;
+ v4l2_err(v4l2_dev, "Could not register control\n");
+ goto err_hdl;
+ }
strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
dev->vdev.v4l2_dev = v4l2_dev;
dev->vdev.fops = &pcm20_fops;
dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
dev->vdev.release = video_device_release_empty;
dev->vdev.lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
video_set_drvdata(&dev->vdev, dev);
+ snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO,
+ dev->audmode == V4L2_TUNER_MODE_MONO, -1);
+ pcm20_setfreq(dev, dev->freq);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
- goto fail;
+ goto err_hdl;
v4l2_info(v4l2_dev, "Mirosound PCM20 Radio tuner\n");
return 0;
-fail:
+err_hdl:
+ v4l2_ctrl_handler_free(hdl);
v4l2_device_unregister(v4l2_dev);
return -EINVAL;
}
@@ -265,6 +234,8 @@ static void __exit pcm20_cleanup(void)
struct pcm20 *dev = &pcm20_card;
video_unregister_device(&dev->vdev);
+ snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, 1, -1);
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
v4l2_device_unregister(&dev->v4l2_dev);
}
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index cabbe3adf435..02151e0e6e63 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -2085,8 +2085,7 @@ static int wl1273_fm_radio_probe(struct platform_device *pdev)
}
/* V4L2 configuration */
- memcpy(&radio->videodev, &wl1273_viddev_template,
- sizeof(wl1273_viddev_template));
+ radio->videodev = wl1273_viddev_template;
radio->videodev.v4l2_dev = &radio->v4l2dev;
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
index 2f089b4252df..467e95575488 100644
--- a/drivers/media/radio/si470x/radio-si470x.h
+++ b/drivers/media/radio/si470x/radio-si470x.h
@@ -163,7 +163,7 @@ struct si470x_device {
struct completion completion;
bool status_rssi_auto_update; /* Does RSSI get updated automatic? */
-#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
+#if IS_ENABLED(CONFIG_USB_SI470X)
/* reference to USB and video device */
struct usb_device *usbdev;
struct usb_interface *intf;
@@ -179,7 +179,7 @@ struct si470x_device {
unsigned char hardware_version;
#endif
-#if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
+#if IS_ENABLED(CONFIG_I2C_SI470X)
struct i2c_client *client;
#endif
};
diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig
index ea1e6545df36..f359be7e9dd9 100644
--- a/drivers/media/radio/wl128x/Kconfig
+++ b/drivers/media/radio/wl128x/Kconfig
@@ -4,7 +4,7 @@
menu "Texas Instruments WL128x FM driver (ST based)"
config RADIO_WL128X
tristate "Texas Instruments WL128x FM Radio"
- depends on VIDEO_V4L2 && RFKILL && GPIOLIB
+ depends on VIDEO_V4L2 && RFKILL && GPIOLIB && TTY
select TI_ST if NET
help
Choose Y here if you have this FM radio chip.
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index 602ef7ac8c24..a002234ed5de 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -1563,8 +1563,7 @@ int fmc_prepare(struct fmdev *fmdev)
fmdev->irq_info.mask = FM_MAL_EVENT;
/* Region info */
- memcpy(&fmdev->rx.region, &region_configs[default_radio_region],
- sizeof(struct region_info));
+ fmdev->rx.region = region_configs[default_radio_region];
fmdev->rx.mute_mode = FM_MUTE_OFF;
fmdev->rx.rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF;
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 79ba242fe263..19f3563c61da 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -291,7 +291,7 @@ config IR_TTUSBIR
config IR_RX51
tristate "Nokia N900 IR transmitter diode"
- depends on OMAP_DM_TIMER && LIRC
+ depends on OMAP_DM_TIMER && LIRC && !ARCH_MULTIPLATFORM
---help---
Say Y or M here if you want to enable support for the IR
transmitter diode built in the Nokia N900 (RX51) device.
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 2d6fb26a0170..4d6a63fe6c5e 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -872,11 +872,11 @@ static int ati_remote_probe(struct usb_interface *interface,
ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
rc_dev = rc_allocate_device();
if (!ati_remote || !rc_dev)
- goto fail1;
+ goto exit_free_dev_rdev;
/* Allocate URB buffers, URBs */
if (ati_remote_alloc_buffers(udev, ati_remote))
- goto fail2;
+ goto exit_free_buffers;
ati_remote->endpoint_in = endpoint_in;
ati_remote->endpoint_out = endpoint_out;
@@ -924,12 +924,12 @@ static int ati_remote_probe(struct usb_interface *interface,
/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
err = ati_remote_initialize(ati_remote);
if (err)
- goto fail3;
+ goto exit_kill_urbs;
/* Set up and register rc device */
err = rc_register_device(ati_remote->rdev);
if (err)
- goto fail3;
+ goto exit_kill_urbs;
/* use our delay for rc_dev */
ati_remote->rdev->input_dev->rep[REP_DELAY] = repeat_delay;
@@ -939,7 +939,7 @@ static int ati_remote_probe(struct usb_interface *interface,
input_dev = input_allocate_device();
if (!input_dev) {
err = -ENOMEM;
- goto fail4;
+ goto exit_unregister_device;
}
ati_remote->idev = input_dev;
@@ -947,19 +947,24 @@ static int ati_remote_probe(struct usb_interface *interface,
err = input_register_device(input_dev);
if (err)
- goto fail5;
+ goto exit_free_input_device;
}
usb_set_intfdata(interface, ati_remote);
return 0;
- fail5: input_free_device(input_dev);
- fail4: rc_unregister_device(rc_dev);
+ exit_free_input_device:
+ input_free_device(input_dev);
+ exit_unregister_device:
+ rc_unregister_device(rc_dev);
rc_dev = NULL;
- fail3: usb_kill_urb(ati_remote->irq_urb);
+ exit_kill_urbs:
+ usb_kill_urb(ati_remote->irq_urb);
usb_kill_urb(ati_remote->out_urb);
- fail2: ati_remote_free_buffers(ati_remote);
- fail1: rc_free_device(rc_dev);
+ exit_free_buffers:
+ ati_remote_free_buffers(ati_remote);
+ exit_free_dev_rdev:
+ rc_free_device(rc_dev);
kfree(ati_remote);
return err;
}
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index cef04786b52f..ee6c984cade2 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -1003,7 +1003,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
rdev = rc_allocate_device();
if (!dev || !rdev)
- goto failure;
+ goto exit_free_dev_rdev;
/* validate resources */
error = -ENODEV;
@@ -1014,10 +1014,10 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
if (!pnp_port_valid(pnp_dev, 0) ||
pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE)
- goto failure;
+ goto exit_free_dev_rdev;
if (!pnp_irq_valid(pnp_dev, 0))
- goto failure;
+ goto exit_free_dev_rdev;
spin_lock_init(&dev->hw_lock);
@@ -1033,7 +1033,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
/* detect hardware version and features */
error = ene_hw_detect(dev);
if (error)
- goto failure;
+ goto exit_free_dev_rdev;
if (!dev->hw_learning_and_tx_capable && txsim) {
dev->hw_learning_and_tx_capable = true;
@@ -1075,30 +1075,30 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
device_set_wakeup_capable(&pnp_dev->dev, true);
device_set_wakeup_enable(&pnp_dev->dev, true);
+ error = rc_register_device(rdev);
+ if (error < 0)
+ goto exit_free_dev_rdev;
+
/* claim the resources */
error = -EBUSY;
if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) {
- goto failure;
+ goto exit_unregister_device;
}
dev->irq = pnp_irq(pnp_dev, 0);
if (request_irq(dev->irq, ene_isr,
IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) {
- goto failure2;
+ goto exit_release_hw_io;
}
- error = rc_register_device(rdev);
- if (error < 0)
- goto failure3;
-
pr_notice("driver has been successfully loaded\n");
return 0;
-failure3:
- free_irq(dev->irq, dev);
-failure2:
+exit_release_hw_io:
release_region(dev->hw_io, ENE_IO_SIZE);
-failure:
+exit_unregister_device:
+ rc_unregister_device(rdev);
+exit_free_dev_rdev:
rc_free_device(rdev);
kfree(dev);
return error;
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 1df410e13688..d6fa441655d2 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -500,18 +500,18 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
/* input device for IR remote (and tx) */
rdev = rc_allocate_device();
if (!rdev)
- goto failure;
+ goto exit_free_dev_rdev;
ret = -ENODEV;
/* validate pnp resources */
if (!pnp_port_valid(pdev, 0)) {
dev_err(&pdev->dev, "IR PNP Port not valid!\n");
- goto failure;
+ goto exit_free_dev_rdev;
}
if (!pnp_irq_valid(pdev, 0)) {
dev_err(&pdev->dev, "IR PNP IRQ not valid!\n");
- goto failure;
+ goto exit_free_dev_rdev;
}
fintek->cir_addr = pnp_port_start(pdev, 0);
@@ -528,7 +528,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
ret = fintek_hw_detect(fintek);
if (ret)
- goto failure;
+ goto exit_free_dev_rdev;
/* Initialize CIR & CIR Wake Logical Devices */
fintek_config_mode_enable(fintek);
@@ -557,33 +557,35 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
/* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD);
+ fintek->rdev = rdev;
+
ret = -EBUSY;
/* now claim resources */
if (!request_region(fintek->cir_addr,
fintek->cir_port_len, FINTEK_DRIVER_NAME))
- goto failure;
+ goto exit_free_dev_rdev;
if (request_irq(fintek->cir_irq, fintek_cir_isr, IRQF_SHARED,
FINTEK_DRIVER_NAME, (void *)fintek))
- goto failure2;
+ goto exit_free_cir_addr;
ret = rc_register_device(rdev);
if (ret)
- goto failure3;
+ goto exit_free_irq;
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;
-failure3:
+exit_free_irq:
free_irq(fintek->cir_irq, fintek);
-failure2:
+exit_free_cir_addr:
release_region(fintek->cir_addr, fintek->cir_port_len);
-failure:
+exit_free_dev_rdev:
rc_free_device(rdev);
kfree(fintek);
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 4f71a7d1f019..8b82ae9bd686 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/slab.h>
+#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <media/rc-core.h>
@@ -30,6 +31,45 @@ struct gpio_rc_dev {
bool active_low;
};
+#ifdef CONFIG_OF
+/*
+ * Translate OpenFirmware node properties into platform_data
+ */
+static int gpio_ir_recv_get_devtree_pdata(struct device *dev,
+ struct gpio_ir_recv_platform_data *pdata)
+{
+ struct device_node *np = dev->of_node;
+ enum of_gpio_flags flags;
+ int gpio;
+
+ gpio = of_get_gpio_flags(np, 0, &flags);
+ if (gpio < 0) {
+ if (gpio != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get gpio flags (%d)\n", gpio);
+ return gpio;
+ }
+
+ pdata->gpio_nr = gpio;
+ pdata->active_low = (flags & OF_GPIO_ACTIVE_LOW);
+ /* probe() takes care of map_name == NULL or allowed_protos == 0 */
+ pdata->map_name = of_get_property(np, "linux,rc-map-name", NULL);
+ pdata->allowed_protos = 0;
+
+ return 0;
+}
+
+static struct of_device_id gpio_ir_recv_of_match[] = {
+ { .compatible = "gpio-ir-receiver", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match);
+
+#else /* !CONFIG_OF */
+
+#define gpio_ir_recv_get_devtree_pdata(dev, pdata) (-ENOSYS)
+
+#endif
+
static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
{
struct gpio_rc_dev *gpio_dev = dev_id;
@@ -66,6 +106,17 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
pdev->dev.platform_data;
int rc;
+ if (pdev->dev.of_node) {
+ struct gpio_ir_recv_platform_data *dtpdata =
+ devm_kzalloc(&pdev->dev, sizeof(*dtpdata), GFP_KERNEL);
+ if (!dtpdata)
+ return -ENOMEM;
+ rc = gpio_ir_recv_get_devtree_pdata(&pdev->dev, dtpdata);
+ if (rc)
+ return rc;
+ pdata = dtpdata;
+ }
+
if (!pdata)
return -EINVAL;
@@ -129,12 +180,12 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
err_request_irq:
platform_set_drvdata(pdev, NULL);
rc_unregister_device(rcdev);
+ rcdev = NULL;
err_register_rc_device:
err_gpio_direction_input:
gpio_free(pdata->gpio_nr);
err_gpio_request:
rc_free_device(rcdev);
- rcdev = NULL;
err_allocate_device:
kfree(gpio_dev);
return rc;
@@ -148,7 +199,6 @@ static int gpio_ir_recv_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
rc_unregister_device(gpio_dev->rcdev);
gpio_free(gpio_dev->gpio_nr);
- rc_free_device(gpio_dev->rcdev);
kfree(gpio_dev);
return 0;
}
@@ -192,6 +242,7 @@ static struct platform_driver gpio_ir_recv_driver = {
.driver = {
.name = GPIO_IR_DRIVER_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(gpio_ir_recv_of_match),
#ifdef CONFIG_PM
.pm = &gpio_ir_recv_pm_ops,
#endif
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index b99b096d8a8f..a4ab2e6b3f82 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -58,6 +58,7 @@ struct iguanair {
char phys[64];
};
+#define CMD_NOP 0x00
#define CMD_GET_VERSION 0x01
#define CMD_GET_BUFSIZE 0x11
#define CMD_GET_FEATURES 0x10
@@ -196,6 +197,10 @@ static void iguanair_irq_out(struct urb *urb)
if (urb->status)
dev_dbg(ir->dev, "Error: out urb status = %d\n", urb->status);
+
+ /* if we sent an nop packet, do not expect a response */
+ if (urb->status == 0 && ir->packet->header.cmd == CMD_NOP)
+ complete(&ir->completion);
}
static int iguanair_send(struct iguanair *ir, unsigned size)
@@ -219,10 +224,17 @@ static int iguanair_get_features(struct iguanair *ir)
{
int rc;
+ /*
+ * On cold boot, the iguanair initializes on the first packet
+ * received but does not process that packet. Send an empty
+ * packet.
+ */
ir->packet->header.start = 0;
ir->packet->header.direction = DIR_OUT;
- ir->packet->header.cmd = CMD_GET_VERSION;
+ ir->packet->header.cmd = CMD_NOP;
+ iguanair_send(ir, sizeof(ir->packet->header));
+ ir->packet->header.cmd = CMD_GET_VERSION;
rc = iguanair_send(ir, sizeof(ir->packet->header));
if (rc) {
dev_info(ir->dev, "failed to get version\n");
@@ -255,19 +267,14 @@ static int iguanair_get_features(struct iguanair *ir)
ir->packet->header.cmd = CMD_GET_FEATURES;
rc = iguanair_send(ir, sizeof(ir->packet->header));
- if (rc) {
+ if (rc)
dev_info(ir->dev, "failed to get features\n");
- goto out;
- }
-
out:
return rc;
}
static int iguanair_receiver(struct iguanair *ir, bool enable)
{
- int rc;
-
ir->packet->header.start = 0;
ir->packet->header.direction = DIR_OUT;
ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF;
@@ -275,9 +282,7 @@ static int iguanair_receiver(struct iguanair *ir, bool enable)
if (enable)
ir_raw_event_reset(ir->rc);
- rc = iguanair_send(ir, sizeof(ir->packet->header));
-
- return rc;
+ return iguanair_send(ir, sizeof(ir->packet->header));
}
/*
@@ -512,6 +517,7 @@ static int iguanair_probe(struct usb_interface *intf,
rc->rx_resolution = RX_RESOLUTION;
iguanair_set_tx_carrier(rc, 38000);
+ iguanair_set_tx_mask(rc, 0);
ret = rc_register_device(rc);
if (ret < 0) {
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 78d109b978dd..dec203bb06f6 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1221,7 +1221,7 @@ static u32 imon_panel_key_lookup(u64 code)
static bool imon_mouse_event(struct imon_context *ictx,
unsigned char *buf, int len)
{
- char rel_x = 0x00, rel_y = 0x00;
+ signed char rel_x = 0x00, rel_y = 0x00;
u8 right_shift = 1;
bool mouse_input = true;
int dir = 0;
@@ -1297,7 +1297,7 @@ static void imon_touch_event(struct imon_context *ictx, unsigned char *buf)
static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
{
int dir = 0;
- char rel_x = 0x00, rel_y = 0x00;
+ signed char rel_x = 0x00, rel_y = 0x00;
u16 timeout, threshold;
u32 scancode = KEY_RESERVED;
unsigned long flags;
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 97dc8d13b06b..17c94be9f24c 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -31,11 +31,6 @@ static DEFINE_MUTEX(ir_raw_handler_lock);
static LIST_HEAD(ir_raw_handler_list);
static u64 available_protocols;
-#ifdef MODULE
-/* Used to load the decoders */
-static struct work_struct wq_load;
-#endif
-
static int ir_raw_event_thread(void *data)
{
struct ir_raw_event ev;
@@ -347,8 +342,7 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
}
EXPORT_SYMBOL(ir_raw_handler_unregister);
-#ifdef MODULE
-static void init_decoders(struct work_struct *work)
+void ir_raw_init(void)
{
/* Load the decoder modules */
@@ -365,12 +359,3 @@ static void init_decoders(struct work_struct *work)
it is needed to change the CONFIG_MODULE test at rc-core.h
*/
}
-#endif
-
-void ir_raw_init(void)
-{
-#ifdef MODULE
- INIT_WORK(&wq_load, init_decoders);
- schedule_work(&wq_load);
-#endif
-}
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 1b8669b6d042..dd8237324c09 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1472,7 +1472,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
/* input device for IR remote (and tx) */
rdev = rc_allocate_device();
if (!rdev)
- goto failure;
+ goto exit_free_dev_rdev;
itdev->rdev = rdev;
ret = -ENODEV;
@@ -1498,12 +1498,12 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
if (!pnp_port_valid(pdev, io_rsrc_no) ||
pnp_port_len(pdev, io_rsrc_no) != dev_desc->io_region_size) {
dev_err(&pdev->dev, "IR PNP Port not valid!\n");
- goto failure;
+ goto exit_free_dev_rdev;
}
if (!pnp_irq_valid(pdev, 0)) {
dev_err(&pdev->dev, "PNP IRQ not valid!\n");
- goto failure;
+ goto exit_free_dev_rdev;
}
/* store resource values */
@@ -1591,29 +1591,29 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
rdev->driver_name = ITE_DRIVER_NAME;
rdev->map_name = RC_MAP_RC6_MCE;
+ ret = rc_register_device(rdev);
+ if (ret)
+ goto exit_free_dev_rdev;
+
ret = -EBUSY;
/* now claim resources */
if (!request_region(itdev->cir_addr,
dev_desc->io_region_size, ITE_DRIVER_NAME))
- goto failure;
+ goto exit_unregister_device;
if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED,
ITE_DRIVER_NAME, (void *)itdev))
- goto failure2;
-
- ret = rc_register_device(rdev);
- if (ret)
- goto failure3;
+ goto exit_release_cir_addr;
ite_pr(KERN_NOTICE, "driver has been successfully loaded\n");
return 0;
-failure3:
- free_irq(itdev->cir_irq, itdev);
-failure2:
+exit_release_cir_addr:
release_region(itdev->cir_addr, itdev->params.io_region_size);
-failure:
+exit_unregister_device:
+ rc_unregister_device(rdev);
+exit_free_dev_rdev:
rc_free_device(rdev);
kfree(itdev);
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index ab84d66c67c1..778661971aed 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -88,6 +88,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-tevii-nec.o \
rc-tivo.o \
rc-total-media-in-hand.o \
+ rc-total-media-in-hand-02.o \
rc-trekstor.o \
rc-tt-1500.o \
rc-twinhan1027.o \
diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c
new file mode 100644
index 000000000000..47270f72ebf0
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c
@@ -0,0 +1,86 @@
+/*
+ * Total Media In Hand_02 remote controller keytable for Mygica X8507
+ *
+ * Copyright (C) 2012 Alfredo J. Delaiti <alfredodelaiti@netscape.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+
+static struct rc_map_table total_media_in_hand_02[] = {
+ { 0x0000, KEY_0 },
+ { 0x0001, KEY_1 },
+ { 0x0002, KEY_2 },
+ { 0x0003, KEY_3 },
+ { 0x0004, KEY_4 },
+ { 0x0005, KEY_5 },
+ { 0x0006, KEY_6 },
+ { 0x0007, KEY_7 },
+ { 0x0008, KEY_8 },
+ { 0x0009, KEY_9 },
+ { 0x000a, KEY_MUTE },
+ { 0x000b, KEY_STOP }, /* Stop */
+ { 0x000c, KEY_POWER2 }, /* Turn on/off application */
+ { 0x000d, KEY_OK }, /* OK */
+ { 0x000e, KEY_CAMERA }, /* Snapshot */
+ { 0x000f, KEY_ZOOM }, /* Full Screen/Restore */
+ { 0x0010, KEY_RIGHT }, /* Right arrow */
+ { 0x0011, KEY_LEFT }, /* Left arrow */
+ { 0x0012, KEY_CHANNELUP },
+ { 0x0013, KEY_CHANNELDOWN },
+ { 0x0014, KEY_SHUFFLE },
+ { 0x0016, KEY_PAUSE },
+ { 0x0017, KEY_PLAY }, /* Play */
+ { 0x001e, KEY_TIME }, /* Time Shift */
+ { 0x001f, KEY_RECORD },
+ { 0x0020, KEY_UP },
+ { 0x0021, KEY_DOWN },
+ { 0x0025, KEY_POWER }, /* Turn off computer */
+ { 0x0026, KEY_REWIND }, /* FR << */
+ { 0x0027, KEY_FASTFORWARD }, /* FF >> */
+ { 0x0029, KEY_ESC },
+ { 0x002b, KEY_VOLUMEUP },
+ { 0x002c, KEY_VOLUMEDOWN },
+ { 0x002d, KEY_CHANNEL }, /* CH Surfing */
+ { 0x0038, KEY_VIDEO }, /* TV/AV/S-Video/YPbPr */
+};
+
+static struct rc_map_list total_media_in_hand_02_map = {
+ .map = {
+ .scan = total_media_in_hand_02,
+ .size = ARRAY_SIZE(total_media_in_hand_02),
+ .rc_type = RC_TYPE_RC5,
+ .name = RC_MAP_TOTAL_MEDIA_IN_HAND_02,
+ }
+};
+
+static int __init init_rc_map_total_media_in_hand_02(void)
+{
+ return rc_map_register(&total_media_in_hand_02_map);
+}
+
+static void __exit exit_rc_map_total_media_in_hand_02(void)
+{
+ rc_map_unregister(&total_media_in_hand_02_map);
+}
+
+module_init(init_rc_map_total_media_in_hand_02)
+module_exit(exit_rc_map_total_media_in_hand_02)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(" Alfredo J. Delaiti <alfredodelaiti@netscape.net>");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 9afb9331217d..5b5b6e6f79e8 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -62,7 +62,6 @@
#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */
#define MCE_IRDATA_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
#define MCE_IRDATA_TRAILER 0x80 /* End of IR data */
-#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
#define MCE_DEFAULT_TX_MASK 0x03 /* Vals: TX1=0x01, TX2=0x02, ALL=0x03 */
#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */
@@ -291,7 +290,8 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Philips/Spinel plus IR transceiver for ASUS */
{ USB_DEVICE(VENDOR_PHILIPS, 0x2088) },
/* Philips IR transceiver (Dell branded) */
- { USB_DEVICE(VENDOR_PHILIPS, 0x2093) },
+ { USB_DEVICE(VENDOR_PHILIPS, 0x2093),
+ .driver_info = MCE_GEN2_TX_INV },
/* Realtek MCE IR Receiver and card reader */
{ USB_DEVICE(VENDOR_REALTEK, 0x0161),
.driver_info = MULTIFUNCTION },
@@ -365,7 +365,8 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Formosa Industrial Computing */
{ USB_DEVICE(VENDOR_FORMOSA, 0xe042) },
/* Fintek eHome Infrared Transceiver (HP branded) */
- { USB_DEVICE(VENDOR_FINTEK, 0x5168) },
+ { USB_DEVICE(VENDOR_FINTEK, 0x5168),
+ .driver_info = MCE_GEN2_TX_INV },
/* Fintek eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_FINTEK, 0x0602) },
/* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
@@ -788,19 +789,19 @@ static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size)
static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
{
struct mceusb_dev *ir = dev->priv;
- int i, ret = 0;
+ int i, length, ret = 0;
int cmdcount = 0;
- unsigned char *cmdbuf; /* MCE command buffer */
-
- cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL);
- if (!cmdbuf)
- return -ENOMEM;
+ unsigned char cmdbuf[MCE_CMDBUF_SIZE];
/* MCE tx init header */
cmdbuf[cmdcount++] = MCE_CMD_PORT_IR;
cmdbuf[cmdcount++] = MCE_CMD_SETIRTXPORTS;
cmdbuf[cmdcount++] = ir->tx_mask;
+ /* Send the set TX ports command */
+ mce_async_out(ir, cmdbuf, cmdcount);
+ cmdcount = 0;
+
/* Generate mce packet data */
for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
@@ -809,8 +810,7 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
/* Insert mce packet header every 4th entry */
if ((cmdcount < MCE_CMDBUF_SIZE) &&
- (cmdcount - MCE_TX_HEADER_LENGTH) %
- MCE_CODE_LENGTH == 0)
+ (cmdcount % MCE_CODE_LENGTH) == 0)
cmdbuf[cmdcount++] = MCE_IRDATA_HEADER;
/* Insert mce packet data */
@@ -828,17 +828,16 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
(txbuf[i] -= MCE_MAX_PULSE_LENGTH));
}
- /* Fix packet length in last header */
- cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
- MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) %
- MCE_CODE_LENGTH - 1;
-
/* Check if we have room for the empty packet at the end */
if (cmdcount >= MCE_CMDBUF_SIZE) {
ret = -EINVAL;
goto out;
}
+ /* Fix packet length in last header */
+ length = cmdcount % MCE_CODE_LENGTH;
+ cmdbuf[cmdcount - length] -= MCE_CODE_LENGTH - length;
+
/* All mce commands end with an empty packet (0x80) */
cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER;
@@ -846,7 +845,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
mce_async_out(ir, cmdbuf, cmdcount);
out:
- kfree(cmdbuf);
return ret ? ret : count;
}
@@ -1121,16 +1119,13 @@ static void mceusb_gen1_init(struct mceusb_dev *ir)
mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
kfree(data);
-};
+}
static void mceusb_gen2_init(struct mceusb_dev *ir)
{
/* device resume */
mce_async_out(ir, DEVICE_RESUME, sizeof(DEVICE_RESUME));
- /* get hw/sw revision? */
- mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
-
/* get wake version (protocol, key, address) */
mce_async_out(ir, GET_WAKEVERSION, sizeof(GET_WAKEVERSION));
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index b8aa9abb31ff..40125d779049 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -986,25 +986,25 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
/* input device for IR remote (and tx) */
rdev = rc_allocate_device();
if (!rdev)
- goto failure;
+ goto exit_free_dev_rdev;
ret = -ENODEV;
/* validate pnp resources */
if (!pnp_port_valid(pdev, 0) ||
pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) {
dev_err(&pdev->dev, "IR PNP Port not valid!\n");
- goto failure;
+ goto exit_free_dev_rdev;
}
if (!pnp_irq_valid(pdev, 0)) {
dev_err(&pdev->dev, "PNP IRQ not valid!\n");
- goto failure;
+ goto exit_free_dev_rdev;
}
if (!pnp_port_valid(pdev, 1) ||
pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) {
dev_err(&pdev->dev, "Wake PNP Port not valid!\n");
- goto failure;
+ goto exit_free_dev_rdev;
}
nvt->cir_addr = pnp_port_start(pdev, 0);
@@ -1027,7 +1027,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
ret = nvt_hw_detect(nvt);
if (ret)
- goto failure;
+ goto exit_free_dev_rdev;
/* Initialize CIR & CIR Wake Logical Devices */
nvt_efm_enable(nvt);
@@ -1065,31 +1065,32 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
/* tx bits */
rdev->tx_resolution = XYZ;
#endif
+ nvt->rdev = rdev;
+
+ ret = rc_register_device(rdev);
+ if (ret)
+ goto exit_free_dev_rdev;
ret = -EBUSY;
/* now claim resources */
if (!request_region(nvt->cir_addr,
CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
- goto failure;
+ goto exit_unregister_device;
if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
NVT_DRIVER_NAME, (void *)nvt))
- goto failure2;
+ goto exit_release_cir_addr;
if (!request_region(nvt->cir_wake_addr,
CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
- goto failure3;
+ goto exit_free_irq;
if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED,
NVT_DRIVER_NAME, (void *)nvt))
- goto failure4;
-
- ret = rc_register_device(rdev);
- if (ret)
- goto failure5;
+ goto exit_release_cir_wake_addr;
device_init_wakeup(&pdev->dev, true);
- nvt->rdev = rdev;
+
nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n");
if (debug) {
cir_dump_regs(nvt);
@@ -1098,15 +1099,15 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
return 0;
-failure5:
- free_irq(nvt->cir_wake_irq, nvt);
-failure4:
+exit_release_cir_wake_addr:
release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
-failure3:
+exit_free_irq:
free_irq(nvt->cir_irq, nvt);
-failure2:
+exit_release_cir_addr:
release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
-failure:
+exit_unregister_device:
+ rc_unregister_device(rdev);
+exit_free_dev_rdev:
rc_free_device(rdev);
kfree(nvt);
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 96f0a8bb39ea..5d87287ed372 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -165,56 +165,56 @@ void ir_raw_init(void);
/* from ir-nec-decoder.c */
#ifdef CONFIG_IR_NEC_DECODER_MODULE
-#define load_nec_decode() request_module("ir-nec-decoder")
+#define load_nec_decode() request_module_nowait("ir-nec-decoder")
#else
static inline void load_nec_decode(void) { }
#endif
/* from ir-rc5-decoder.c */
#ifdef CONFIG_IR_RC5_DECODER_MODULE
-#define load_rc5_decode() request_module("ir-rc5-decoder")
+#define load_rc5_decode() request_module_nowait("ir-rc5-decoder")
#else
static inline void load_rc5_decode(void) { }
#endif
/* from ir-rc6-decoder.c */
#ifdef CONFIG_IR_RC6_DECODER_MODULE
-#define load_rc6_decode() request_module("ir-rc6-decoder")
+#define load_rc6_decode() request_module_nowait("ir-rc6-decoder")
#else
static inline void load_rc6_decode(void) { }
#endif
/* from ir-jvc-decoder.c */
#ifdef CONFIG_IR_JVC_DECODER_MODULE
-#define load_jvc_decode() request_module("ir-jvc-decoder")
+#define load_jvc_decode() request_module_nowait("ir-jvc-decoder")
#else
static inline void load_jvc_decode(void) { }
#endif
/* from ir-sony-decoder.c */
#ifdef CONFIG_IR_SONY_DECODER_MODULE
-#define load_sony_decode() request_module("ir-sony-decoder")
+#define load_sony_decode() request_module_nowait("ir-sony-decoder")
#else
static inline void load_sony_decode(void) { }
#endif
/* from ir-sanyo-decoder.c */
#ifdef CONFIG_IR_SANYO_DECODER_MODULE
-#define load_sanyo_decode() request_module("ir-sanyo-decoder")
+#define load_sanyo_decode() request_module_nowait("ir-sanyo-decoder")
#else
static inline void load_sanyo_decode(void) { }
#endif
/* from ir-mce_kbd-decoder.c */
#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE
-#define load_mce_kbd_decode() request_module("ir-mce_kbd-decoder")
+#define load_mce_kbd_decode() request_module_nowait("ir-mce_kbd-decoder")
#else
static inline void load_mce_kbd_decode(void) { }
#endif
/* from ir-lirc-codec.c */
#ifdef CONFIG_IR_LIRC_CODEC_MODULE
-#define load_lirc_codec() request_module("ir-lirc-codec")
+#define load_lirc_codec() request_module_nowait("ir-lirc-codec")
#else
static inline void load_lirc_codec(void) { }
#endif
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 601d1ac1c688..759a40a42eaa 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -789,8 +789,10 @@ static ssize_t show_protocols(struct device *device,
} else if (dev->raw) {
enabled = dev->raw->enabled_protocols;
allowed = ir_raw_get_allowed_protocols();
- } else
+ } else {
+ mutex_unlock(&dev->lock);
return -ENODEV;
+ }
IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
(long long)allowed,
@@ -890,7 +892,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++;
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 1800326f93e6..1b37fe2779f8 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -195,9 +195,6 @@ struct redrat3_dev {
dma_addr_t dma_in;
dma_addr_t dma_out;
- /* locks this structure */
- struct mutex lock;
-
/* rx signal timeout timer */
struct timer_list rx_timeout;
u32 hw_timeout;
@@ -922,8 +919,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
return -EAGAIN;
}
- if (count > (RR3_DRIVER_MAXLENS * 2))
- return -EINVAL;
+ count = min_t(unsigned, count, RR3_MAX_SIG_SIZE - RR3_TX_TRAILER_LEN);
/* rr3 will disable rc detector on transmit */
rr3->det_enabled = false;
@@ -936,24 +932,22 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
}
for (i = 0; i < count; i++) {
+ cur_sample_len = redrat3_us_to_len(txbuf[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) {
+ if (curlencheck < RR3_DRIVER_MAXLENS) {
/* 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;
+ count = i - 1;
+ break;
}
}
}
@@ -1087,6 +1081,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
rc->tx_ir = redrat3_transmit_ir;
rc->s_tx_carrier = redrat3_set_tx_carrier;
rc->driver_name = DRIVER_NAME;
+ rc->rx_resolution = US_TO_NS(2);
rc->map_name = RC_MAP_HAUPPAUGE;
ret = rc_register_device(rc);
@@ -1202,7 +1197,6 @@ static int redrat3_dev_probe(struct usb_interface *intf,
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);
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index 78be8a914225..cf0d47f57fb2 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -213,19 +213,20 @@ static int ttusbir_probe(struct usb_interface *intf,
/* find the correct alt setting */
for (i = 0; i < intf->num_altsetting && altsetting == -1; i++) {
- int bulk_out_endp = -1, iso_in_endp = -1;
+ int max_packet, bulk_out_endp = -1, iso_in_endp = -1;
idesc = &intf->altsetting[i].desc;
for (j = 0; j < idesc->bNumEndpoints; j++) {
desc = &intf->altsetting[i].endpoint[j].desc;
+ max_packet = le16_to_cpu(desc->wMaxPacketSize);
if (usb_endpoint_dir_in(desc) &&
usb_endpoint_xfer_isoc(desc) &&
- desc->wMaxPacketSize == 0x10)
+ max_packet == 0x10)
iso_in_endp = j;
else if (usb_endpoint_dir_out(desc) &&
usb_endpoint_xfer_bulk(desc) &&
- desc->wMaxPacketSize == 0x20)
+ max_packet == 0x20)
bulk_out_endp = j;
if (bulk_out_endp != -1 && iso_in_endp != -1) {
@@ -408,9 +409,8 @@ static int ttusbir_resume(struct usb_interface *intf)
struct ttusbir *tt = usb_get_intfdata(intf);
int i, rc;
- led_classdev_resume(&tt->led);
tt->is_led_on = true;
- ttusbir_set_led(tt);
+ led_classdev_resume(&tt->led);
for (i = 0; i < NUM_URBS; i++) {
rc = usb_submit_urb(tt->urb[i], GFP_KERNEL);
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 930c61499037..535a18dccbd0 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -154,6 +154,8 @@
#define WBCIR_CNTR_R 0x02
/* Invert TX */
#define WBCIR_IRTX_INV 0x04
+/* Receiver oversampling */
+#define WBCIR_RX_T_OV 0x40
/* Valid banks for the SP3 UART */
enum wbcir_bank {
@@ -394,7 +396,8 @@ wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
if (data->rxstate == WBCIR_RXSTATE_ERROR)
continue;
- duration = ((irdata & 0x7F) + 1) * 2;
+ duration = ((irdata & 0x7F) + 1) *
+ (data->carrier_report_enabled ? 2 : 10);
rawir.pulse = irdata & 0x80 ? false : true;
rawir.duration = US_TO_NS(duration);
@@ -550,6 +553,17 @@ wbcir_set_carrier_report(struct rc_dev *dev, int enable)
wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL,
WBCIR_CNTR_EN, WBCIR_CNTR_EN | WBCIR_CNTR_R);
+ /* Set a higher sampling resolution if carrier reports are enabled */
+ wbcir_select_bank(data, WBCIR_BANK_2);
+ data->dev->rx_resolution = US_TO_NS(enable ? 2 : 10);
+ outb(enable ? 0x03 : 0x0f, data->sbase + WBCIR_REG_SP3_BGDL);
+ outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
+
+ /* Enable oversampling if carrier reports are enabled */
+ wbcir_select_bank(data, WBCIR_BANK_7);
+ wbcir_set_bits(data->sbase + WBCIR_REG_SP3_RCCFG,
+ enable ? WBCIR_RX_T_OV : 0, WBCIR_RX_T_OV);
+
data->carrier_report_enabled = enable;
spin_unlock_irqrestore(&data->spinlock, flags);
@@ -931,8 +945,8 @@ wbcir_init_hw(struct wbcir_data *data)
/* prescaler 1.0, tx/rx fifo lvl 16 */
outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
- /* Set baud divisor to sample every 2 ns */
- outb(0x03, data->sbase + WBCIR_REG_SP3_BGDL);
+ /* Set baud divisor to sample every 10 us */
+ outb(0x0f, data->sbase + WBCIR_REG_SP3_BGDL);
outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
/* Set CEIR mode */
@@ -941,12 +955,9 @@ wbcir_init_hw(struct wbcir_data *data)
inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
- /*
- * Disable RX demod, enable run-length enc/dec, set freq span and
- * enable over-sampling
- */
+ /* Disable RX demod, enable run-length enc/dec, set freq span */
wbcir_select_bank(data, WBCIR_BANK_7);
- outb(0xd0, data->sbase + WBCIR_REG_SP3_RCCFG);
+ outb(0x90, data->sbase + WBCIR_REG_SP3_RCCFG);
/* Disable timer */
wbcir_select_bank(data, WBCIR_BANK_4);
@@ -1093,11 +1104,15 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
data->dev->rx_resolution = US_TO_NS(2);
data->dev->allowed_protos = RC_BIT_ALL;
+ err = rc_register_device(data->dev);
+ if (err)
+ goto exit_free_rc;
+
if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) {
dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
data->wbase, data->wbase + WAKEUP_IOMEM_LEN - 1);
err = -EBUSY;
- goto exit_free_rc;
+ goto exit_unregister_device;
}
if (!request_region(data->ebase, EHFUNC_IOMEM_LEN, DRVNAME)) {
@@ -1122,24 +1137,20 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
goto exit_release_sbase;
}
- err = rc_register_device(data->dev);
- if (err)
- goto exit_free_irq;
-
device_init_wakeup(&device->dev, 1);
wbcir_init_hw(data);
return 0;
-exit_free_irq:
- free_irq(data->irq, device);
exit_release_sbase:
release_region(data->sbase, SP_IOMEM_LEN);
exit_release_ebase:
release_region(data->ebase, EHFUNC_IOMEM_LEN);
exit_release_wbase:
release_region(data->wbase, WAKEUP_IOMEM_LEN);
+exit_unregister_device:
+ rc_unregister_device(data->dev);
exit_free_rc:
rc_free_device(data->dev);
exit_unregister_led:
diff --git a/drivers/media/tuners/fc0011.c b/drivers/media/tuners/fc0011.c
index e4882546c283..3932aa81e18c 100644
--- a/drivers/media/tuners/fc0011.c
+++ b/drivers/media/tuners/fc0011.c
@@ -183,8 +183,7 @@ static int fc0011_set_params(struct dvb_frontend *fe)
unsigned int i, vco_retries;
u32 freq = p->frequency / 1000;
u32 bandwidth = p->bandwidth_hz / 1000;
- u32 fvco, xin, xdiv, xdivr;
- u16 frac;
+ u32 fvco, xin, frac, xdiv, xdivr;
u8 fa, fp, vco_sel, vco_cal;
u8 regs[FC11_NR_REGS] = { };
@@ -221,18 +220,15 @@ static int fc0011_set_params(struct dvb_frontend *fe)
/* Calc XIN. The PLL reference frequency is 18 MHz. */
xdiv = fvco / 18000;
+ WARN_ON(xdiv > 0xFF);
frac = fvco - xdiv * 18000;
frac = (frac << 15) / 18000;
if (frac >= 16384)
frac += 32786;
if (!frac)
xin = 0;
- else if (frac < 511)
- xin = 512;
- else if (frac < 65026)
- xin = frac;
else
- xin = 65024;
+ xin = clamp_t(u32, frac, 512, 65024);
regs[FC11_REG_XINHI] = xin >> 8;
regs[FC11_REG_XINLO] = xin;
@@ -247,8 +243,8 @@ static int fc0011_set_params(struct dvb_frontend *fe)
fa += 8;
}
if (fp > 0x1F) {
- fp &= 0x1F;
- fa &= 0xF;
+ fp = 0x1F;
+ fa = 0xF;
}
if (fa >= fp) {
dev_warn(&priv->i2c->dev,
@@ -351,6 +347,8 @@ static int fc0011_set_params(struct dvb_frontend *fe)
vco_cal &= FC11_VCOCAL_VALUEMASK;
switch (vco_sel) {
+ default:
+ WARN_ON(1);
case 0:
if (vco_cal < 8) {
regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
@@ -432,7 +430,8 @@ static int fc0011_set_params(struct dvb_frontend *fe)
err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
if (err)
return err;
- err = fc0011_writereg(priv, FC11_REG_16, 0xB);
+ regs[FC11_REG_16] = 0xB;
+ err = fc0011_writereg(priv, FC11_REG_16, regs[FC11_REG_16]);
if (err)
return err;
diff --git a/drivers/media/tuners/fc0012-priv.h b/drivers/media/tuners/fc0012-priv.h
index 4577c917e616..1a86ce1d3fcf 100644
--- a/drivers/media/tuners/fc0012-priv.h
+++ b/drivers/media/tuners/fc0012-priv.h
@@ -21,20 +21,9 @@
#ifndef _FC0012_PRIV_H_
#define _FC0012_PRIV_H_
-#define LOG_PREFIX "fc0012"
-
-#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 fc0012_priv {
struct i2c_adapter *i2c;
- u8 addr;
- u8 dual_master;
- u8 xtal_freq;
+ const struct fc0012_config *cfg;
u32 frequency;
u32 bandwidth;
diff --git a/drivers/media/tuners/fc0012.c b/drivers/media/tuners/fc0012.c
index 308135abd54c..f4d0e797a6cc 100644
--- a/drivers/media/tuners/fc0012.c
+++ b/drivers/media/tuners/fc0012.c
@@ -25,11 +25,13 @@ static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
{
u8 buf[2] = {reg, val};
struct i2c_msg msg = {
- .addr = priv->addr, .flags = 0, .buf = buf, .len = 2
+ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
};
if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
- err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
+ dev_err(&priv->i2c->dev,
+ "%s: I2C write reg failed, reg: %02x, val: %02x\n",
+ KBUILD_MODNAME, reg, val);
return -EREMOTEIO;
}
return 0;
@@ -38,12 +40,16 @@ static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
{
struct i2c_msg msg[2] = {
- { .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
- { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
+ { .addr = priv->cfg->i2c_address, .flags = 0,
+ .buf = &reg, .len = 1 },
+ { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
+ .buf = val, .len = 1 },
};
if (i2c_transfer(priv->i2c, msg, 2) != 2) {
- err("I2C read reg failed, reg: %02x", reg);
+ dev_err(&priv->i2c->dev,
+ "%s: I2C read reg failed, reg: %02x\n",
+ KBUILD_MODNAME, reg);
return -EREMOTEIO;
}
return 0;
@@ -88,7 +94,7 @@ static int fc0012_init(struct dvb_frontend *fe)
0x04, /* reg. 0x15: Enable LNA COMPS */
};
- switch (priv->xtal_freq) {
+ switch (priv->cfg->xtal_freq) {
case FC_XTAL_27_MHZ:
case FC_XTAL_28_8_MHZ:
reg[0x07] |= 0x20;
@@ -98,9 +104,12 @@ static int fc0012_init(struct dvb_frontend *fe)
break;
}
- if (priv->dual_master)
+ if (priv->cfg->dual_master)
reg[0x0c] |= 0x02;
+ if (priv->cfg->loop_through)
+ reg[0x09] |= 0x01;
+
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
@@ -114,17 +123,12 @@ static int fc0012_init(struct dvb_frontend *fe)
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
if (ret)
- err("fc0012_writereg failed: %d", ret);
+ dev_err(&priv->i2c->dev, "%s: fc0012_writereg failed: %d\n",
+ KBUILD_MODNAME, ret);
return ret;
}
-static int fc0012_sleep(struct dvb_frontend *fe)
-{
- /* nothing to do here */
- return 0;
-}
-
static int fc0012_set_params(struct dvb_frontend *fe)
{
struct fc0012_priv *priv = fe->tuner_priv;
@@ -144,7 +148,7 @@ static int fc0012_set_params(struct dvb_frontend *fe)
goto exit;
}
- switch (priv->xtal_freq) {
+ switch (priv->cfg->xtal_freq) {
case FC_XTAL_27_MHZ:
xtal_freq_khz_2 = 27000 / 2;
break;
@@ -256,7 +260,8 @@ static int fc0012_set_params(struct dvb_frontend *fe)
break;
}
} else {
- err("%s: modulation type not supported!", __func__);
+ dev_err(&priv->i2c->dev, "%s: modulation type not supported!\n",
+ KBUILD_MODNAME);
return -EINVAL;
}
@@ -318,7 +323,8 @@ exit:
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
if (ret)
- warn("%s: failed: %d", __func__, ret);
+ dev_warn(&priv->i2c->dev, "%s: %s failed: %d\n",
+ KBUILD_MODNAME, __func__, ret);
return ret;
}
@@ -331,8 +337,7 @@ static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
- /* CHECK: always ? */
- *frequency = 0;
+ *frequency = 0; /* Zero-IF */
return 0;
}
@@ -408,7 +413,8 @@ err:
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
exit:
if (ret)
- warn("%s: failed: %d", __func__, ret);
+ dev_warn(&priv->i2c->dev, "%s: %s failed: %d\n",
+ KBUILD_MODNAME, __func__, ret);
return ret;
}
@@ -424,7 +430,6 @@ static const struct dvb_tuner_ops fc0012_tuner_ops = {
.release = fc0012_release,
.init = fc0012_init,
- .sleep = fc0012_sleep,
.set_params = fc0012_set_params,
@@ -436,27 +441,73 @@ static const struct dvb_tuner_ops fc0012_tuner_ops = {
};
struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
- enum fc001x_xtal_freq xtal_freq)
+ struct i2c_adapter *i2c, const struct fc0012_config *cfg)
{
- struct fc0012_priv *priv = NULL;
+ struct fc0012_priv *priv;
+ int ret;
+ u8 chip_id;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
+ if (!priv) {
+ ret = -ENOMEM;
+ dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+ goto err;
+ }
+ priv->cfg = cfg;
priv->i2c = i2c;
- priv->dual_master = dual_master;
- priv->addr = i2c_address;
- priv->xtal_freq = xtal_freq;
- info("Fitipower FC0012 successfully attached.");
+ /* check if the tuner is there */
+ ret = fc0012_readreg(priv, 0x00, &chip_id);
+ if (ret < 0)
+ goto err;
- fe->tuner_priv = priv;
+ dev_dbg(&i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id);
+
+ switch (chip_id) {
+ case 0xa1:
+ break;
+ default:
+ ret = -ENODEV;
+ goto err;
+ }
+
+ dev_info(&i2c->dev, "%s: Fitipower FC0012 successfully identified\n",
+ KBUILD_MODNAME);
+
+ if (priv->cfg->loop_through) {
+ ret = fc0012_writereg(priv, 0x09, 0x6f);
+ if (ret < 0)
+ goto err;
+ }
+
+ /*
+ * TODO: Clock out en or div?
+ * For dual tuner configuration clearing bit [0] is required.
+ */
+ if (priv->cfg->clock_out) {
+ ret = fc0012_writereg(priv, 0x0b, 0x82);
+ if (ret < 0)
+ goto err;
+ }
+ fe->tuner_priv = priv;
memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
sizeof(struct dvb_tuner_ops));
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (ret) {
+ dev_dbg(&i2c->dev, "%s: failed: %d\n", __func__, ret);
+ kfree(priv);
+ return NULL;
+ }
+
return fe;
}
EXPORT_SYMBOL(fc0012_attach);
diff --git a/drivers/media/tuners/fc0012.h b/drivers/media/tuners/fc0012.h
index 4dbd5efe8845..54508fcc3469 100644
--- a/drivers/media/tuners/fc0012.h
+++ b/drivers/media/tuners/fc0012.h
@@ -24,19 +24,41 @@
#include "dvb_frontend.h"
#include "fc001x-common.h"
+struct fc0012_config {
+ /*
+ * I2C address
+ */
+ u8 i2c_address;
+
+ /*
+ * clock
+ */
+ enum fc001x_xtal_freq xtal_freq;
+
+ bool dual_master;
+
+ /*
+ * RF loop-through
+ */
+ bool loop_through;
+
+ /*
+ * clock output
+ */
+ bool clock_out;
+};
+
#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
(defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- u8 i2c_address, int dual_master,
- enum fc001x_xtal_freq xtal_freq);
+ const struct fc0012_config *cfg);
#else
static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- u8 i2c_address, int dual_master,
- enum fc001x_xtal_freq xtal_freq)
+ const struct fc0012_config *cfg)
{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ pr_warn("%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
diff --git a/drivers/media/tuners/mt2060.h b/drivers/media/tuners/mt2060.h
index cb60caffb6b6..c64fc19cb278 100644
--- a/drivers/media/tuners/mt2060.h
+++ b/drivers/media/tuners/mt2060.h
@@ -30,7 +30,7 @@ struct mt2060_config {
u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
};
-#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2060)
extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1);
#else
static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
diff --git a/drivers/media/tuners/mt2063.h b/drivers/media/tuners/mt2063.h
index ab24170c1571..e1acfc8e7ae3 100644
--- a/drivers/media/tuners/mt2063.h
+++ b/drivers/media/tuners/mt2063.h
@@ -8,7 +8,7 @@ struct mt2063_config {
u32 refclock;
};
-#if defined(CONFIG_MEDIA_TUNER_MT2063) || (defined(CONFIG_MEDIA_TUNER_MT2063_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2063)
struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
struct mt2063_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/tuners/mt20xx.h b/drivers/media/tuners/mt20xx.h
index 259553a24903..f56241ccaa00 100644
--- a/drivers/media/tuners/mt20xx.h
+++ b/drivers/media/tuners/mt20xx.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT20XX)
extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
struct i2c_adapter* i2c_adap,
u8 i2c_addr);
diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h
index 6632de640df0..09ceaf68e47c 100644
--- a/drivers/media/tuners/mt2131.h
+++ b/drivers/media/tuners/mt2131.h
@@ -30,7 +30,7 @@ struct mt2131_config {
u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
};
-#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2131)
extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct mt2131_config *cfg,
diff --git a/drivers/media/tuners/mt2266.h b/drivers/media/tuners/mt2266.h
index 4d083882d044..fad6dd657d77 100644
--- a/drivers/media/tuners/mt2266.h
+++ b/drivers/media/tuners/mt2266.h
@@ -24,7 +24,7 @@ struct mt2266_config {
u8 i2c_address;
};
-#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2266)
extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg);
#else
static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h
index aa3eea0b5262..37b0942e2385 100644
--- a/drivers/media/tuners/mxl5007t.h
+++ b/drivers/media/tuners/mxl5007t.h
@@ -77,7 +77,7 @@ struct mxl5007t_config {
unsigned int clk_out_enable:1;
};
-#if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_MXL5007T)
extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, u8 addr,
struct mxl5007t_config *cfg);
diff --git a/drivers/media/tuners/qt1010.h b/drivers/media/tuners/qt1010.h
index 807fb7b6146b..8ab5d479749f 100644
--- a/drivers/media/tuners/qt1010.h
+++ b/drivers/media/tuners/qt1010.h
@@ -36,7 +36,7 @@ struct qt1010_config {
* @param cfg tuner hw based configuration
* @return fe pointer on success, NULL on failure
*/
-#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_QT1010)
extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct qt1010_config *cfg);
diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c
index 5d9f02842501..e4a84ee231cf 100644
--- a/drivers/media/tuners/tda18212.c
+++ b/drivers/media/tuners/tda18212.c
@@ -277,7 +277,7 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
{
struct tda18212_priv *priv = NULL;
int ret;
- u8 uninitialized_var(val);
+ u8 val;
priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
if (priv == NULL)
@@ -296,8 +296,8 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
- dev_dbg(&priv->i2c->dev, "%s: ret=%d chip id=%02x\n", __func__, ret,
- val);
+ if (!ret)
+ dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val);
if (ret || val != 0xc7) {
kfree(priv);
return NULL;
diff --git a/drivers/media/tuners/tda18218.c b/drivers/media/tuners/tda18218.c
index 18198537be9f..2d31aeb6b088 100644
--- a/drivers/media/tuners/tda18218.c
+++ b/drivers/media/tuners/tda18218.c
@@ -277,7 +277,7 @@ struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tda18218_config *cfg)
{
struct tda18218_priv *priv = NULL;
- u8 uninitialized_var(val);
+ u8 val;
int ret;
/* chip default registers values */
static u8 def_regs[] = {
@@ -302,8 +302,8 @@ struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
/* check if the tuner is there */
ret = tda18218_rd_reg(priv, R00_ID, &val);
- dev_dbg(&priv->i2c->dev, "%s: ret=%d chip id=%02x\n", __func__, ret,
- val);
+ if (!ret)
+ dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val);
if (ret || val != def_regs[R00_ID]) {
kfree(priv);
return NULL;
diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c
index 72c26fd77922..e7786862dab2 100644
--- a/drivers/media/tuners/tda18271-fe.c
+++ b/drivers/media/tuners/tda18271-fe.c
@@ -1122,6 +1122,7 @@ static int tda18271_dump_std_map(struct dvb_frontend *fe)
tda18271_dump_std_item(dvbt_7, "dvbt 7");
tda18271_dump_std_item(dvbt_8, "dvbt 8");
tda18271_dump_std_item(qam_6, "qam 6 ");
+ tda18271_dump_std_item(qam_7, "qam 7 ");
tda18271_dump_std_item(qam_8, "qam 8 ");
return 0;
@@ -1149,6 +1150,7 @@ static int tda18271_update_std_map(struct dvb_frontend *fe,
tda18271_update_std(dvbt_7, "dvbt 7");
tda18271_update_std(dvbt_8, "dvbt 8");
tda18271_update_std(qam_6, "qam 6");
+ tda18271_update_std(qam_7, "qam 7");
tda18271_update_std(qam_8, "qam 8");
return 0;
diff --git a/drivers/media/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c
index fb881c667c94..b62e925f643f 100644
--- a/drivers/media/tuners/tda18271-maps.c
+++ b/drivers/media/tuners/tda18271-maps.c
@@ -1290,13 +1290,11 @@ int tda18271_assign_map_layout(struct dvb_frontend *fe)
switch (priv->id) {
case TDA18271HDC1:
priv->maps = &tda18271c1_map_layout;
- memcpy(&priv->std, &tda18271c1_std_map,
- sizeof(struct tda18271_std_map));
+ priv->std = tda18271c1_std_map;
break;
case TDA18271HDC2:
priv->maps = &tda18271c2_map_layout;
- memcpy(&priv->std, &tda18271c2_std_map,
- sizeof(struct tda18271_std_map));
+ priv->std = tda18271c2_std_map;
break;
default:
ret = -EINVAL;
diff --git a/drivers/media/tuners/tda18271.h b/drivers/media/tuners/tda18271.h
index 89b6c6d93fec..4c418d63f540 100644
--- a/drivers/media/tuners/tda18271.h
+++ b/drivers/media/tuners/tda18271.h
@@ -121,7 +121,7 @@ enum tda18271_mode {
TDA18271_DIGITAL,
};
-#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18271)
extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
struct i2c_adapter *i2c,
struct tda18271_config *cfg);
diff --git a/drivers/media/tuners/tda827x.h b/drivers/media/tuners/tda827x.h
index 7d72ce0a0c2d..9432b5b6121b 100644
--- a/drivers/media/tuners/tda827x.h
+++ b/drivers/media/tuners/tda827x.h
@@ -50,7 +50,7 @@ struct tda827x_config
* @param cfg optional callback function pointers.
* @return FE pointer on success, NULL on failure.
*/
-#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA827X)
extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr,
struct i2c_adapter *i2c,
struct tda827x_config *cfg);
diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h
index 7e288b26fcc3..e12ecbaa35a4 100644
--- a/drivers/media/tuners/tda8290.h
+++ b/drivers/media/tuners/tda8290.h
@@ -28,7 +28,7 @@ struct tda829x_config {
#define TDA829X_DONT_PROBE 1
};
-#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA8290)
extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/tuners/tda9887.h b/drivers/media/tuners/tda9887.h
index acc419e8c4fc..37a4a1123e0c 100644
--- a/drivers/media/tuners/tda9887.h
+++ b/drivers/media/tuners/tda9887.h
@@ -21,7 +21,7 @@
#include "dvb_frontend.h"
/* ------------------------------------------------------------------------ */
-#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA9887)
extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr);
diff --git a/drivers/media/tuners/tea5761.h b/drivers/media/tuners/tea5761.h
index 2e2ff82c95a4..933228ffb509 100644
--- a/drivers/media/tuners/tea5761.h
+++ b/drivers/media/tuners/tea5761.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761)
extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/tuners/tea5767.h b/drivers/media/tuners/tea5767.h
index d30ab1b483de..c39101199383 100644
--- a/drivers/media/tuners/tea5767.h
+++ b/drivers/media/tuners/tea5767.h
@@ -39,7 +39,7 @@ struct tea5767_ctrl {
enum tea5767_xtal xtal_freq;
};
-#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5767)
extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/tuners/tuner-simple.h b/drivers/media/tuners/tuner-simple.h
index 381fa5d35a9b..ffd12cfe650b 100644
--- a/drivers/media/tuners/tuner-simple.h
+++ b/drivers/media/tuners/tuner-simple.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_SIMPLE)
extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr,
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
index 7bcb6b0ff1df..09451737c77e 100644
--- a/drivers/media/tuners/tuner-xc2028.c
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -870,7 +870,7 @@ check_device:
}
read_not_reliable:
- memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
+ priv->cur_fw = new_fw;
/*
* By setting BASE in cur_fw.type only after successfully loading all
diff --git a/drivers/media/tuners/tuner-xc2028.h b/drivers/media/tuners/tuner-xc2028.h
index 9ebfb2d0ff14..181d087faec4 100644
--- a/drivers/media/tuners/tuner-xc2028.h
+++ b/drivers/media/tuners/tuner-xc2028.h
@@ -56,7 +56,7 @@ struct xc2028_config {
#define XC2028_RESET_CLK 1
#define XC2028_I2C_FLUSH 2
-#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC2028)
extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
struct xc2028_config *cfg);
#else
diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c
index 5c0fd787cc8f..2018befabb5a 100644
--- a/drivers/media/tuners/xc4000.c
+++ b/drivers/media/tuners/xc4000.c
@@ -1066,7 +1066,7 @@ check_device:
goto fail;
}
- memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
+ priv->cur_fw = new_fw;
/*
* By setting BASE in cur_fw.type only after successfully loading all
diff --git a/drivers/media/tuners/xc4000.h b/drivers/media/tuners/xc4000.h
index e6a44d151cbd..97c23de5296c 100644
--- a/drivers/media/tuners/xc4000.h
+++ b/drivers/media/tuners/xc4000.h
@@ -50,7 +50,7 @@ struct xc4000_config {
* it's passed back to a bridge during tuner_callback().
*/
-#if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC4000)
extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct xc4000_config *cfg);
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c
index dc93cf338f36..d6be1b613c52 100644
--- a/drivers/media/tuners/xc5000.c
+++ b/drivers/media/tuners/xc5000.c
@@ -785,6 +785,7 @@ static int xc5000_set_params(struct dvb_frontend *fe)
return -EINVAL;
}
priv->rf_mode = XC_RF_MODE_AIR;
+ break;
case SYS_DVBC_ANNEX_A:
case SYS_DVBC_ANNEX_C:
dprintk(1, "%s() QAM modulation\n", __func__);
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig
index 6746994d03fe..0a7d520636a9 100644
--- a/drivers/media/usb/Kconfig
+++ b/drivers/media/usb/Kconfig
@@ -21,7 +21,6 @@ endif
if MEDIA_ANALOG_TV_SUPPORT
comment "Analog TV USB devices"
-source "drivers/media/usb/au0828/Kconfig"
source "drivers/media/usb/pvrusb2/Kconfig"
source "drivers/media/usb/hdpvr/Kconfig"
source "drivers/media/usb/tlg2300/Kconfig"
@@ -31,6 +30,7 @@ endif
if (MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT)
comment "Analog/digital TV USB devices"
+source "drivers/media/usb/au0828/Kconfig"
source "drivers/media/usb/cx231xx/Kconfig"
source "drivers/media/usb/tm6000/Kconfig"
endif
diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig
index 1766c0ce93be..953a37c613b1 100644
--- a/drivers/media/usb/au0828/Kconfig
+++ b/drivers/media/usb/au0828/Kconfig
@@ -1,17 +1,28 @@
config VIDEO_AU0828
tristate "Auvitek AU0828 support"
- depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
+ depends on I2C && INPUT && DVB_CORE && USB
select I2C_ALGOBIT
select VIDEO_TVEEPROM
select VIDEOBUF_VMALLOC
select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT
- select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
---help---
- This is a video4linux driver for Auvitek's USB device.
+ This is a hybrid analog/digital tv capture driver for
+ Auvitek's AU0828 USB device.
To compile this driver as a module, choose M here: the
module will be called au0828
+
+config VIDEO_AU0828_V4L2
+ bool "Auvitek AU0828 v4l2 analog video support"
+ depends on VIDEO_AU0828 && VIDEO_V4L2
+ select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT
+ default y
+ ---help---
+ This is a video4linux driver for Auvitek's USB device.
+
+ Choose Y here to include support for v4l2 analog video
+ capture within the au0828 driver.
diff --git a/drivers/media/usb/au0828/Makefile b/drivers/media/usb/au0828/Makefile
index 98cc20cc0ffb..be3bdf698022 100644
--- a/drivers/media/usb/au0828/Makefile
+++ b/drivers/media/usb/au0828/Makefile
@@ -1,4 +1,8 @@
-au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o
+au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
+
+ifeq ($(CONFIG_VIDEO_AU0828_V4L2),y)
+ au0828-objs += au0828-video.o au0828-vbi.o
+endif
obj-$(CONFIG_VIDEO_AU0828) += au0828.o
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
index 0cb7c28dcb17..dd32decb237d 100644
--- a/drivers/media/usb/au0828/au0828-cards.c
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -169,7 +169,9 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
- case 72261: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
+ case 72261: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
+ case 72271: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
+ case 72281: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
break;
@@ -183,16 +185,15 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
__func__, tv.model);
}
+void au0828_card_analog_fe_setup(struct au0828_dev *dev);
+
void au0828_card_setup(struct au0828_dev *dev)
{
static u8 eeprom[256];
- struct tuner_setup tun_setup;
- struct v4l2_subdev *sd;
- unsigned int mode_mask = T_ANALOG_TV;
dprintk(1, "%s()\n", __func__);
- memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board));
+ dev->board = au0828_boards[dev->boardnr];
if (dev->i2c_rc == 0) {
dev->i2c_client.addr = 0xa0 >> 1;
@@ -209,6 +210,16 @@ void au0828_card_setup(struct au0828_dev *dev)
break;
}
+ au0828_card_analog_fe_setup(dev);
+}
+
+void au0828_card_analog_fe_setup(struct au0828_dev *dev)
+{
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+ struct tuner_setup tun_setup;
+ struct v4l2_subdev *sd;
+ unsigned int mode_mask = T_ANALOG_TV;
+
if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
/* Load the analog demodulator driver (note this would need to
be abstracted out if we ever need to support a different
@@ -234,6 +245,7 @@ void au0828_card_setup(struct au0828_dev *dev)
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
&tun_setup);
}
+#endif
}
/*
@@ -333,6 +345,8 @@ struct usb_device_id au0828_usb_id_table[] = {
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
{ USB_DEVICE(0x2040, 0x7213),
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7270),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
{ },
};
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 745a80a798c8..1e6f40ef1c6b 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -134,13 +134,17 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
/* Digital TV */
au0828_dvb_unregister(dev);
+#ifdef CONFIG_VIDEO_AU0828_V4L2
if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
au0828_analog_unregister(dev);
+#endif
/* I2C */
au0828_i2c_unregister(dev);
+#ifdef CONFIG_VIDEO_AU0828_V4L2
v4l2_device_unregister(&dev->v4l2_dev);
+#endif
usb_set_intfdata(interface, NULL);
@@ -155,7 +159,10 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
static int au0828_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
- int ifnum, retval;
+ int ifnum;
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+ int retval;
+#endif
struct au0828_dev *dev;
struct usb_device *usbdev = interface_to_usbdev(interface);
@@ -194,6 +201,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
dev->usbdev = usbdev;
dev->boardnr = id->driver_info;
+#ifdef CONFIG_VIDEO_AU0828_V4L2
/* Create the v4l2_device */
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
@@ -203,6 +211,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
kfree(dev);
return -EIO;
}
+#endif
/* Power Up the bridge */
au0828_write(dev, REG_600, 1 << 4);
@@ -216,9 +225,11 @@ static int au0828_usb_probe(struct usb_interface *interface,
/* Setup */
au0828_card_setup(dev);
+#ifdef CONFIG_VIDEO_AU0828_V4L2
/* Analog TV */
if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
au0828_analog_register(dev, interface);
+#endif
/* Digital TV */
au0828_dvb_register(dev);
diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c
index 4ded17fe1957..17ec3651b10e 100644
--- a/drivers/media/usb/au0828/au0828-i2c.c
+++ b/drivers/media/usb/au0828/au0828-i2c.c
@@ -364,12 +364,9 @@ int au0828_i2c_register(struct au0828_dev *dev)
{
dprintk(1, "%s()\n", __func__);
- memcpy(&dev->i2c_adap, &au0828_i2c_adap_template,
- sizeof(dev->i2c_adap));
- memcpy(&dev->i2c_algo, &au0828_i2c_algo_template,
- sizeof(dev->i2c_algo));
- memcpy(&dev->i2c_client, &au0828_i2c_client_template,
- sizeof(dev->i2c_client));
+ dev->i2c_adap = au0828_i2c_adap_template;
+ dev->i2c_algo = au0828_i2c_algo_template;
+ dev->i2c_client = au0828_i2c_client_template;
dev->i2c_adap.dev.parent = &dev->usbdev->dev;
@@ -378,7 +375,11 @@ int au0828_i2c_register(struct au0828_dev *dev)
dev->i2c_adap.algo = &dev->i2c_algo;
dev->i2c_adap.algo_data = dev;
+#ifdef CONFIG_VIDEO_AU0828_V4L2
i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+#else
+ i2c_set_adapdata(&dev->i2c_adap, dev);
+#endif
i2c_add_adapter(&dev->i2c_adap);
dev->i2c_client.adapter = &dev->i2c_adap;
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 45387aab10c7..8b9e8268e911 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -304,7 +304,7 @@ static inline void buffer_filled(struct au0828_dev *dev,
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
dev->isoc_ctl.buf = NULL;
@@ -321,7 +321,7 @@ static inline void vbi_buffer_filled(struct au0828_dev *dev,
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
dev->isoc_ctl.vbi_buf = NULL;
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index 66a56ef7bbe4..e579ff69ca4a 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -199,8 +199,10 @@ struct au0828_dev {
struct au0828_dvb dvb;
struct work_struct restart_streaming;
+#ifdef CONFIG_VIDEO_AU0828_V4L2
/* Analog */
struct v4l2_device v4l2_dev;
+#endif
int users;
unsigned int resources; /* resources in use */
struct video_device *vdev;
diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c
index 95b5d6e7cdc4..be1719283609 100644
--- a/drivers/media/usb/cpia2/cpia2_usb.c
+++ b/drivers/media/usb/cpia2/cpia2_usb.c
@@ -328,7 +328,7 @@ static void cpia2_usb_complete(struct urb *urb)
continue;
}
DBG("Start of frame pattern found\n");
- do_gettimeofday(&cam->workbuff->timestamp);
+ v4l2_get_timestamp(&cam->workbuff->timestamp);
cam->workbuff->seq = cam->frame_count++;
cam->workbuff->data[0] = 0xFF;
cam->workbuff->data[1] = 0xD8;
diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
index aeb9d2275725..d5d42b6e94be 100644
--- a/drivers/media/usb/cpia2/cpia2_v4l.c
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -825,6 +825,8 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
else
buf->flags = 0;
+ buf->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+
switch (cam->buffers[buf->index].status) {
case FRAME_EMPTY:
case FRAME_ERROR:
@@ -943,7 +945,8 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
buf->index = frame;
buf->bytesused = cam->buffers[buf->index].length;
- buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+ buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE
+ | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
buf->field = V4L2_FIELD_NONE;
buf->timestamp = cam->buffers[buf->index].timestamp;
buf->sequence = cam->buffers[buf->index].seq;
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index b024e5197a75..28688dbcb609 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1291,7 +1291,7 @@ static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *ur
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
dma_q->mpeg_buffer_completed = 0;
@@ -1327,7 +1327,7 @@ static void buffer_filled(char *data, int len, struct urb *urb,
memcpy(vbuf, data, len);
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index bbed1e40eeda..8d529565f163 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -603,6 +603,33 @@ struct cx231xx_board cx231xx_boards[] = {
.gpio = NULL,
} },
},
+ [CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2] = {
+ .name = "Elgato Video Capture V2",
+ .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 = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .norm = V4L2_STD_NTSC,
+ .no_alt_vanc = 1,
+ .external_av = 1,
+ .dont_use_port_3 = 1,
+ .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);
@@ -642,6 +669,8 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_KWORLD_UB430_USB_HYBRID},
{USB_DEVICE(0x1f4d, 0x0237),
.driver_info = CX231XX_BOARD_ICONBIT_U100},
+ {USB_DEVICE(0x0fd9, 0x0037),
+ .driver_info = CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2},
{},
};
@@ -707,7 +736,7 @@ static void cx231xx_sleep_s5h1432(struct cx231xx *dev)
static inline void cx231xx_set_model(struct cx231xx *dev)
{
- memcpy(&dev->board, &cx231xx_boards[dev->model], sizeof(dev->board));
+ dev->board = cx231xx_boards[dev->model];
}
/* Since cx231xx_pre_card_setup() requires a proper dev->model,
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index ac7db52f404f..46e3892557c2 100644
--- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -530,7 +530,7 @@ static inline void vbi_buffer_filled(struct cx231xx *dev,
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
dev->vbi_mode.bulk_ctl.buf = NULL;
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index fedf7852a355..06376d904c9f 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -235,7 +235,7 @@ static inline void buffer_filled(struct cx231xx *dev,
cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
if (dev->USE_ISO)
dev->video_mode.isoc_ctl.buf = NULL;
@@ -1751,6 +1751,7 @@ static int vidioc_s_register(struct file *file, void *priv,
0x02,
(u16)reg->reg, 1,
value, 1, 2);
+ break;
case 0x322:
ret =
cx231xx_write_i2c_master(dev,
@@ -2627,8 +2628,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
dev->name, video_device_node_name(dev->vdev));
/* Initialize VBI template */
- memcpy(&cx231xx_vbi_template, &cx231xx_video_template,
- sizeof(cx231xx_vbi_template));
+ cx231xx_vbi_template = cx231xx_video_template;
strcpy(cx231xx_vbi_template.name, "cx231xx-vbi");
/* Allocate and fill vbi video_device struct */
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index a89d020de948..3e11462be0d0 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -68,6 +68,7 @@
#define CX231XX_BOARD_ICONBIT_U100 13
#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL 14
#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC 15
+#define CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2 16
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 834bfecbed73..692224d97d06 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -1,6 +1,6 @@
config DVB_USB_V2
tristate "Support for various USB DVB devices v2"
- depends on DVB_CORE && USB && I2C && RC_CORE
+ depends on DVB_CORE && USB && I2C
help
By enabling this you will be able to choose the various supported
USB1.1 and USB2.0 DVB devices.
@@ -113,6 +113,7 @@ config DVB_USB_IT913X
config DVB_USB_LME2510
tristate "LME DM04/QQBOX DVB-S USB2.0 support"
depends on DVB_USB_V2
+ depends on RC_CORE
select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
@@ -120,6 +121,7 @@ config DVB_USB_LME2510
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
select DVB_M88RS2000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to support the LME DM04/QQBOX DVB-S USB2.0
@@ -134,7 +136,7 @@ config DVB_USB_MXL111SF
config DVB_USB_RTL28XXU
tristate "Realtek RTL28xxU DVB USB support"
- depends on DVB_USB_V2 && EXPERIMENTAL
+ depends on DVB_USB_V2
select DVB_RTL2830
select DVB_RTL2832
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index 943d93423705..b86d0f27a398 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -1156,6 +1156,7 @@ error:
return ret;
}
+#if IS_ENABLED(CONFIG_RC_CORE)
struct af9015_rc_setup {
unsigned int id;
char *rc_codes;
@@ -1312,6 +1313,9 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
return 0;
}
+#else
+ #define af9015_get_rc_config NULL
+#endif
/* interface 0 is used by DVB-T receiver and
interface 1 is for remote controller (HID) */
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 61ae7f9d0b27..f11cc42454f0 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -209,10 +209,15 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
if (msg[0].len > 40 || msg[1].len > 40) {
/* TODO: correct limits > 40 */
ret = -EOPNOTSUPP;
- } else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
- /* integrated demod */
+ } else if ((msg[0].addr == state->af9033_config[0].i2c_addr) ||
+ (msg[0].addr == state->af9033_config[1].i2c_addr)) {
+ /* demod access via firmware interface */
u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
msg[0].buf[2];
+
+ if (msg[0].addr == state->af9033_config[1].i2c_addr)
+ reg |= 0x100000;
+
ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
msg[1].len);
} else {
@@ -220,6 +225,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
u8 buf[5 + msg[0].len];
struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
buf, msg[1].len, msg[1].buf };
+ req.mbox |= ((msg[0].addr & 0x80) >> 3);
buf[0] = msg[1].len;
buf[1] = msg[0].addr << 1;
buf[2] = 0x00; /* reg addr len */
@@ -232,10 +238,15 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
if (msg[0].len > 40) {
/* TODO: correct limits > 40 */
ret = -EOPNOTSUPP;
- } else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
- /* integrated demod */
+ } else if ((msg[0].addr == state->af9033_config[0].i2c_addr) ||
+ (msg[0].addr == state->af9033_config[1].i2c_addr)) {
+ /* demod access via firmware interface */
u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
msg[0].buf[2];
+
+ if (msg[0].addr == state->af9033_config[1].i2c_addr)
+ reg |= 0x100000;
+
ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
msg[0].len - 3);
} else {
@@ -243,6 +254,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
u8 buf[5 + msg[0].len];
struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf,
0, NULL };
+ req.mbox |= ((msg[0].addr & 0x80) >> 3);
buf[0] = msg[0].len;
buf[1] = msg[0].addr << 1;
buf[2] = 0x00; /* reg addr len */
@@ -313,12 +325,57 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL };
struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
- u8 hdr_core;
+ u8 hdr_core, tmp;
u16 hdr_addr, hdr_data_len, hdr_checksum;
#define MAX_DATA 58
#define HDR_SIZE 7
/*
+ * In case of dual tuner configuration we need to do some extra
+ * initialization in order to download firmware to slave demod too,
+ * which is done by master demod.
+ * Master feeds also clock and controls power via GPIO.
+ */
+ ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
+ if (ret < 0)
+ goto err;
+
+ if (tmp) {
+ /* configure gpioh1, reset & power slave demod */
+ ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0x00d8b1, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0x00d8af, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(10000, 50000);
+
+ ret = af9035_wr_reg_mask(d, 0x00d8af, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ /* tell the slave I2C address */
+ ret = af9035_rd_reg(d, EEPROM_2ND_DEMOD_ADDR, &tmp);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x00417f, tmp);
+ if (ret < 0)
+ goto err;
+
+ /* enable clock out */
+ ret = af9035_wr_reg_mask(d, 0x00d81a, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+ }
+
+ /*
* Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info!
*
* byte 0: MCS 51 core
@@ -380,6 +437,10 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
__func__, fw->size - i);
}
+ /* print warn if firmware is bad, continue and see what happens */
+ if (i)
+ dev_warn(&d->udev->dev, "%s: bad firmware\n", KBUILD_MODNAME);
+
/* firmware loaded, request boot */
req.cmd = CMD_FW_BOOT;
ret = af9035_ctrl_msg(d, &req);
@@ -489,14 +550,28 @@ static int af9035_read_config(struct dvb_usb_device *d)
u8 tmp;
u16 tmp16;
+ /* demod I2C "address" */
+ state->af9033_config[0].i2c_addr = 0x38;
+
/* check if there is dual tuners */
ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
if (ret < 0)
goto err;
state->dual_mode = tmp;
- dev_dbg(&d->udev->dev, "%s: dual mode=%d\n",
- __func__, state->dual_mode);
+ dev_dbg(&d->udev->dev, "%s: dual mode=%d\n", __func__,
+ state->dual_mode);
+
+ if (state->dual_mode) {
+ /* read 2nd demodulator I2C address */
+ ret = af9035_rd_reg(d, EEPROM_2ND_DEMOD_ADDR, &tmp);
+ if (ret < 0)
+ goto err;
+
+ state->af9033_config[1].i2c_addr = tmp;
+ dev_dbg(&d->udev->dev, "%s: 2nd demod I2C addr=%02x\n",
+ __func__, tmp);
+ }
for (i = 0; i < state->dual_mode + 1; i++) {
/* tuner */
@@ -514,6 +589,7 @@ static int af9035_read_config(struct dvb_usb_device *d)
case AF9033_TUNER_MXL5007T:
case AF9033_TUNER_TDA18218:
case AF9033_TUNER_FC2580:
+ case AF9033_TUNER_FC0012:
state->af9033_config[i].spec_inv = 1;
break;
default:
@@ -522,6 +598,18 @@ static int af9035_read_config(struct dvb_usb_device *d)
KBUILD_MODNAME, tmp);
}
+ /* disable dual mode if driver does not support it */
+ if (i == 1)
+ switch (tmp) {
+ case AF9033_TUNER_FC0012:
+ break;
+ default:
+ state->dual_mode = false;
+ dev_info(&d->udev->dev, "%s: driver does not " \
+ "support 2nd tuner and will " \
+ "disable it", KBUILD_MODNAME);
+ }
+
/* tuner IF frequency */
ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp);
if (ret < 0)
@@ -730,6 +818,12 @@ static int af9035_frontend_callback(void *adapter_priv, int component,
return 0;
}
+static int af9035_get_adapter_count(struct dvb_usb_device *d)
+{
+ struct state *state = d_to_priv(d);
+ return state->dual_mode + 1;
+}
+
static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
{
struct state *state = adap_to_priv(adap);
@@ -751,15 +845,14 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
if (ret < 0)
goto err;
- ret = af9035_wr_reg(d, 0x00d81a,
- state->dual_mode);
+ ret = af9035_wr_reg(d, 0x00d81a, state->dual_mode);
if (ret < 0)
goto err;
}
/* attach demodulator */
- adap->fe[0] = dvb_attach(af9033_attach,
- &state->af9033_config[adap->id], &d->i2c_adap);
+ adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id],
+ &d->i2c_adap);
if (adap->fe[0] == NULL) {
ret = -ENODEV;
goto err;
@@ -785,13 +878,22 @@ static const struct fc0011_config af9035_fc0011_config = {
.i2c_address = 0x60,
};
-static struct mxl5007t_config af9035_mxl5007t_config = {
- .xtal_freq_hz = MxL_XTAL_24_MHZ,
- .if_freq_hz = MxL_IF_4_57_MHZ,
- .invert_if = 0,
- .loop_thru_enable = 0,
- .clk_out_enable = 0,
- .clk_out_amp = MxL_CLKOUT_AMP_0_94V,
+static struct mxl5007t_config af9035_mxl5007t_config[] = {
+ {
+ .xtal_freq_hz = MxL_XTAL_24_MHZ,
+ .if_freq_hz = MxL_IF_4_57_MHZ,
+ .invert_if = 0,
+ .loop_thru_enable = 0,
+ .clk_out_enable = 0,
+ .clk_out_amp = MxL_CLKOUT_AMP_0_94V,
+ }, {
+ .xtal_freq_hz = MxL_XTAL_24_MHZ,
+ .if_freq_hz = MxL_IF_4_57_MHZ,
+ .invert_if = 0,
+ .loop_thru_enable = 1,
+ .clk_out_enable = 1,
+ .clk_out_amp = MxL_CLKOUT_AMP_0_94V,
+ }
};
static struct tda18218_config af9035_tda18218_config = {
@@ -804,12 +906,32 @@ static const struct fc2580_config af9035_fc2580_config = {
.clock = 16384000,
};
+static const struct fc0012_config af9035_fc0012_config[] = {
+ {
+ .i2c_address = 0x63,
+ .xtal_freq = FC_XTAL_36_MHZ,
+ .dual_master = true,
+ .loop_through = true,
+ .clock_out = true,
+ }, {
+ .i2c_address = 0x63 | 0x80, /* I2C bus select hack */
+ .xtal_freq = FC_XTAL_36_MHZ,
+ .dual_master = true,
+ }
+};
+
static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
{
struct state *state = adap_to_priv(adap);
struct dvb_usb_device *d = adap_to_d(adap);
int ret;
struct dvb_frontend *fe;
+ struct i2c_msg msg[1];
+ u8 tuner_addr;
+ /*
+ * XXX: Hack used in that function: we abuse unused I2C address bit [7]
+ * to carry info about used I2C bus for dual tuner configuration.
+ */
switch (state->af9033_config[adap->id].tuner) {
case AF9033_TUNER_TUA9001:
@@ -842,46 +964,59 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
&d->i2c_adap, &af9035_fc0011_config);
break;
case AF9033_TUNER_MXL5007T:
- ret = af9035_wr_reg(d, 0x00d8e0, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(d, 0x00d8e1, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(d, 0x00d8df, 0);
- if (ret < 0)
- goto err;
+ if (adap->id == 0) {
+ ret = af9035_wr_reg(d, 0x00d8e0, 1);
+ if (ret < 0)
+ goto err;
- msleep(30);
+ ret = af9035_wr_reg(d, 0x00d8e1, 1);
+ if (ret < 0)
+ goto err;
- ret = af9035_wr_reg(d, 0x00d8df, 1);
- if (ret < 0)
- goto err;
+ ret = af9035_wr_reg(d, 0x00d8df, 0);
+ if (ret < 0)
+ goto err;
- msleep(300);
+ msleep(30);
- ret = af9035_wr_reg(d, 0x00d8c0, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(d, 0x00d8c1, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(d, 0x00d8bf, 0);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(d, 0x00d8b4, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(d, 0x00d8b5, 1);
- if (ret < 0)
- goto err;
- ret = af9035_wr_reg(d, 0x00d8b3, 1);
- if (ret < 0)
- goto err;
+ ret = af9035_wr_reg(d, 0x00d8df, 1);
+ if (ret < 0)
+ goto err;
+
+ msleep(300);
+
+ ret = af9035_wr_reg(d, 0x00d8c0, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x00d8c1, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x00d8bf, 0);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x00d8b4, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x00d8b5, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x00d8b3, 1);
+ if (ret < 0)
+ goto err;
+
+ tuner_addr = 0x60;
+ } else {
+ tuner_addr = 0x60 | 0x80; /* I2C bus hack */
+ }
/* attach tuner */
- fe = dvb_attach(mxl5007t_attach, adap->fe[0],
- &d->i2c_adap, 0x60, &af9035_mxl5007t_config);
+ fe = dvb_attach(mxl5007t_attach, adap->fe[0], &d->i2c_adap,
+ tuner_addr, &af9035_mxl5007t_config[adap->id]);
break;
case AF9033_TUNER_TDA18218:
/* attach tuner */
@@ -907,6 +1042,46 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
fe = dvb_attach(fc2580_attach, adap->fe[0],
&d->i2c_adap, &af9035_fc2580_config);
break;
+ case AF9033_TUNER_FC0012:
+ /*
+ * AF9035 gpiot2 = FC0012 enable
+ * XXX: there seems to be something on gpioh8 too, but on my
+ * my test I didn't find any difference.
+ */
+
+ if (adap->id == 0) {
+ /* configure gpiot2 as output and high */
+ ret = af9035_wr_reg_mask(d, 0xd8eb, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0xd8ec, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0xd8ed, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+ } else {
+ /*
+ * FIXME: That belongs for the FC0012 driver.
+ * Write 02 to FC0012 master tuner register 0d directly
+ * in order to make slave tuner working.
+ */
+ msg[0].addr = 0x63;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = "\x0d\x02";
+ ret = i2c_transfer(&d->i2c_adap, msg, 1);
+ if (ret < 0)
+ goto err;
+ }
+
+ usleep_range(10000, 50000);
+
+ fe = dvb_attach(fc0012_attach, adap->fe[0], &d->i2c_adap,
+ &af9035_fc0012_config[adap->id]);
+ break;
default:
fe = NULL;
}
@@ -945,8 +1120,8 @@ static int af9035_init(struct dvb_usb_device *d)
{ 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
{ 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
{ 0x00dd0d, packet_size, 0xff },
- { 0x80f9a3, 0x00, 0x01 },
- { 0x80f9cd, 0x00, 0x01 },
+ { 0x80f9a3, state->dual_mode, 0x01 },
+ { 0x80f9cd, state->dual_mode, 0x01 },
{ 0x80f99d, 0x00, 0x01 },
{ 0x80f9a4, 0x00, 0x01 },
};
@@ -971,6 +1146,7 @@ err:
return ret;
}
+#if IS_ENABLED(CONFIG_RC_CORE)
static int af9035_rc_query(struct dvb_usb_device *d)
{
unsigned int key;
@@ -1045,6 +1221,9 @@ err:
return ret;
}
+#else
+ #define af9035_get_rc_config NULL
+#endif
/* interface 0 is used by DVB-T receiver and
interface 1 is for remote controller (HID) */
@@ -1068,7 +1247,7 @@ static const struct dvb_usb_device_properties af9035_props = {
.init = af9035_init,
.get_rc_config = af9035_get_rc_config,
- .num_adapters = 1,
+ .get_adapter_count = af9035_get_adapter_count,
.adapter = {
{
.stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
index 75ef1ec13fbf..29f3eec22c2c 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.h
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -26,6 +26,7 @@
#include "af9033.h"
#include "tua9001.h"
#include "fc0011.h"
+#include "fc0012.h"
#include "mxl5007t.h"
#include "tda18218.h"
#include "fc2580.h"
@@ -53,7 +54,6 @@ struct usb_req {
struct state {
u8 seq; /* packet sequence number */
bool dual_mode;
-
struct af9033_config af9033_config[2];
};
@@ -91,6 +91,7 @@ u32 clock_lut_it9135[] = {
/* EEPROM locations */
#define EEPROM_IR_MODE 0x430d
#define EEPROM_DUAL_MODE 0x4326
+#define EEPROM_2ND_DEMOD_ADDR 0x4327
#define EEPROM_IR_TYPE 0x4329
#define EEPROM_1_IFFREQ_L 0x432d
#define EEPROM_1_IFFREQ_H 0x432e
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index d05c5b563dac..a20d691d0b63 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -1019,6 +1019,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
return ret;
}
+#if IS_ENABLED(CONFIG_RC_CORE)
static int anysee_rc_query(struct dvb_usb_device *d)
{
u8 buf[] = {CMD_GET_IR_CODE};
@@ -1054,6 +1055,9 @@ static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
return 0;
}
+#else
+ #define anysee_get_rc_config NULL
+#endif
static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
int addr)
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index d75dbf27e99e..70ec80d8be71 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -189,6 +189,7 @@ static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff)
return az6007_write(d, 0xbc, onoff, 0, NULL, 0);
}
+#if IS_ENABLED(CONFIG_RC_CORE)
/* remote control stuff (does not work with my box) */
static int az6007_rc_query(struct dvb_usb_device *d)
{
@@ -215,6 +216,20 @@ static int az6007_rc_query(struct dvb_usb_device *d)
return 0;
}
+static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+ pr_debug("Getting az6007 Remote Control properties\n");
+
+ rc->allowed_protos = RC_BIT_NEC;
+ rc->query = az6007_rc_query;
+ rc->interval = 400;
+
+ return 0;
+}
+#else
+ #define az6007_get_rc_config NULL
+#endif
+
static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
int slot,
int address)
@@ -822,17 +837,6 @@ static void az6007_usb_disconnect(struct usb_interface *intf)
dvb_usbv2_disconnect(intf);
}
-static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
-{
- pr_debug("Getting az6007 Remote Control properties\n");
-
- rc->allowed_protos = RC_BIT_NEC;
- rc->query = az6007_rc_query;
- rc->interval = 400;
-
- return 0;
-}
-
static int az6007_download_firmware(struct dvb_usb_device *d,
const struct firmware *fw)
{
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
index 059291b892b8..3cac8bd0b116 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -347,6 +347,7 @@ struct dvb_usb_adapter {
* @props: device properties
* @name: device name
* @rc_map: name of rc codes table
+ * @rc_polling_active: set when RC polling is active
* @udev: pointer to the device's struct usb_device
* @intf: pointer to the device's usb interface
* @rc: remote controller configuration
@@ -364,7 +365,7 @@ struct dvb_usb_device {
const struct dvb_usb_device_properties *props;
const char *name;
const char *rc_map;
-
+ bool rc_polling_active;
struct usb_device *udev;
struct usb_interface *intf;
struct dvb_usb_rc rc;
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 671b4fa232b4..086792055912 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -102,6 +102,7 @@ static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d)
return 0;
}
+#if IS_ENABLED(CONFIG_RC_CORE)
static void dvb_usb_read_remote_control(struct work_struct *work)
{
struct dvb_usb_device *d = container_of(work,
@@ -112,13 +113,16 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
* When the parameter has been set to 1 via sysfs while the
* driver was running, or when bulk mode is enabled after IR init.
*/
- if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode)
+ if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) {
+ d->rc_polling_active = false;
return;
+ }
ret = d->rc.query(d);
if (ret < 0) {
dev_err(&d->udev->dev, "%s: rc.query() failed=%d\n",
KBUILD_MODNAME, ret);
+ d->rc_polling_active = false;
return; /* stop polling */
}
@@ -182,6 +186,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
d->rc.interval);
schedule_delayed_work(&d->rc_query_work,
msecs_to_jiffies(d->rc.interval));
+ d->rc_polling_active = true;
}
return 0;
@@ -202,6 +207,10 @@ static int dvb_usbv2_remote_exit(struct dvb_usb_device *d)
return 0;
}
+#else
+ #define dvb_usbv2_remote_init(args...) 0
+ #define dvb_usbv2_remote_exit(args...)
+#endif
static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf,
size_t len)
@@ -959,7 +968,7 @@ int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg)
dev_dbg(&d->udev->dev, "%s:\n", __func__);
/* stop remote controller poll */
- if (d->rc.query && !d->rc.bulk_mode)
+ if (d->rc_polling_active)
cancel_delayed_work_sync(&d->rc_query_work);
for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) {
@@ -1006,7 +1015,7 @@ static int dvb_usbv2_resume_common(struct dvb_usb_device *d)
}
/* start remote controller poll */
- if (d->rc.query && !d->rc.bulk_mode)
+ if (d->rc_polling_active)
schedule_delayed_work(&d->rc_query_work,
msecs_to_jiffies(d->rc.interval));
diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c
index 47204280b8b3..833847995c65 100644
--- a/drivers/media/usb/dvb-usb-v2/it913x.c
+++ b/drivers/media/usb/dvb-usb-v2/it913x.c
@@ -308,7 +308,7 @@ static struct i2c_algorithm it913x_i2c_algo = {
};
/* Callbacks for DVB USB */
-#define IT913X_POLL 250
+#if IS_ENABLED(CONFIG_RC_CORE)
static int it913x_rc_query(struct dvb_usb_device *d)
{
u8 ibuf[4];
@@ -334,6 +334,25 @@ static int it913x_rc_query(struct dvb_usb_device *d)
return ret;
}
+static int it913x_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+ struct it913x_state *st = d->priv;
+
+ if (st->proprietary_ir == false) {
+ rc->map_name = NULL;
+ return 0;
+ }
+
+ rc->allowed_protos = RC_BIT_NEC;
+ rc->query = it913x_rc_query;
+ rc->interval = 250;
+
+ return 0;
+}
+#else
+ #define it913x_get_rc_config NULL
+#endif
+
/* Firmware sets raw */
static const char fw_it9135_v1[] = FW_IT9135_V1;
static const char fw_it9135_v2[] = FW_IT9135_V2;
@@ -643,7 +662,8 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
struct it913x_state *st = d->priv;
int ret = 0;
u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
- u16 ep_size = adap->stream.buf_size / 4;
+ u16 ep_size = (adap->pid_filtering) ? TS_BUFFER_SIZE_PID / 4 :
+ TS_BUFFER_SIZE_MAX / 4;
u8 pkt_size = 0x80;
if (d->udev->speed != USB_SPEED_HIGH)
@@ -695,22 +715,6 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
}
/* DVB USB Driver */
-static int it913x_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
-{
- struct it913x_state *st = d->priv;
-
- if (st->proprietary_ir == false) {
- rc->map_name = NULL;
- return 0;
- }
-
- rc->allowed_protos = RC_BIT_NEC;
- rc->query = it913x_rc_query;
- rc->interval = 250;
-
- return 0;
-}
-
static int it913x_get_adapter_count(struct dvb_usb_device *d)
{
struct it913x_state *st = d->priv;
@@ -779,6 +783,18 @@ static const struct usb_device_id it913x_id_table[] = {
{ DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006,
&it913x_properties, "ITE 9135(9006) Generic",
RC_MAP_IT913X_V1) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_1835,
+ &it913x_properties, "Avermedia A835B(1835)",
+ RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_2835,
+ &it913x_properties, "Avermedia A835B(2835)",
+ RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_3835,
+ &it913x_properties, "Avermedia A835B(3835)",
+ RC_MAP_IT913X_V2) },
+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835,
+ &it913x_properties, "Avermedia A835B(4835)",
+ RC_MAP_IT913X_V2) },
{} /* Terminating entry */
};
@@ -797,7 +813,7 @@ module_usb_driver(it913x_driver);
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
MODULE_DESCRIPTION("it913x USB 2 Driver");
-MODULE_VERSION("1.32");
+MODULE_VERSION("1.33");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FW_IT9135_V1);
MODULE_FIRMWARE(FW_IT9135_V2);
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index 6427ac359f21..f30c58cecbba 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -81,6 +81,7 @@
#include "dvb-pll.h"
#include "z0194a.h"
#include "m88rs2000.h"
+#include "ts2020.h"
#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw";
@@ -626,8 +627,8 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
gate = 5;
for (i = 0; i < num; i++) {
- read_o = 1 & (msg[i].flags & I2C_M_RD);
- read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+ read_o = msg[i].flags & I2C_M_RD;
+ read = i + 1 < num && msg[i + 1].flags & I2C_M_RD;
read |= read_o;
gate = (msg[i].addr == st->i2c_tuner_addr)
? (read) ? st->i2c_tuner_gate_r
@@ -640,7 +641,8 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
else
obuf[1] = msg[i].len + read + 1;
- obuf[2] = msg[i].addr;
+ obuf[2] = msg[i].addr << 1;
+
if (read) {
if (read_o)
len = 3;
@@ -894,27 +896,27 @@ static int lme2510_kill_urb(struct usb_data_stream *stream)
}
static struct tda10086_config tda10086_config = {
- .demod_address = 0x1c,
+ .demod_address = 0x0e,
.invert = 0,
.diseqc_tone = 1,
.xtal_freq = TDA10086_XTAL_16M,
};
static struct stv0288_config lme_config = {
- .demod_address = 0xd0,
+ .demod_address = 0x68,
.min_delay_ms = 15,
.inittab = s7395_inittab,
};
static struct ix2505v_config lme_tuner = {
- .tuner_address = 0xc0,
+ .tuner_address = 0x60,
.min_delay_ms = 100,
.tuner_gain = 0x0,
.tuner_chargepump = 0x3,
};
static struct stv0299_config sharp_z0194_config = {
- .demod_address = 0xd0,
+ .demod_address = 0x68,
.inittab = sharp_z0194a_inittab,
.mclk = 88000000UL,
.invert = 0,
@@ -943,11 +945,15 @@ static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe,
}
static struct m88rs2000_config m88rs2000_config = {
- .demod_addr = 0xd0,
- .tuner_addr = 0xc0,
+ .demod_addr = 0x68,
.set_ts_params = dm04_rs2000_set_ts_param,
};
+static struct ts2020_config ts2020_config = {
+ .tuner_address = 0x60,
+ .clk_out_div = 7,
+};
+
static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
fe_sec_voltage_t voltage)
{
@@ -1049,7 +1055,7 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
info("TUN Found Frontend TDA10086");
st->i2c_tuner_gate_w = 4;
st->i2c_tuner_gate_r = 4;
- st->i2c_tuner_addr = 0xc0;
+ st->i2c_tuner_addr = 0x60;
st->tuner_config = TUNER_LG;
if (st->dvb_usb_lme2510_firmware != TUNER_LG) {
st->dvb_usb_lme2510_firmware = TUNER_LG;
@@ -1065,7 +1071,7 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
info("FE Found Stv0299");
st->i2c_tuner_gate_w = 4;
st->i2c_tuner_gate_r = 5;
- st->i2c_tuner_addr = 0xc0;
+ st->i2c_tuner_addr = 0x60;
st->tuner_config = TUNER_S0194;
if (st->dvb_usb_lme2510_firmware != TUNER_S0194) {
st->dvb_usb_lme2510_firmware = TUNER_S0194;
@@ -1082,7 +1088,7 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
info("FE Found Stv0288");
st->i2c_tuner_gate_w = 4;
st->i2c_tuner_gate_r = 5;
- st->i2c_tuner_addr = 0xc0;
+ st->i2c_tuner_addr = 0x60;
st->tuner_config = TUNER_S7395;
if (st->dvb_usb_lme2510_firmware != TUNER_S7395) {
st->dvb_usb_lme2510_firmware = TUNER_S7395;
@@ -1097,9 +1103,11 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
if (adap->fe[0]) {
info("FE Found M88RS2000");
+ dvb_attach(ts2020_attach, adap->fe[0], &ts2020_config,
+ &d->i2c_adap);
st->i2c_tuner_gate_w = 5;
st->i2c_tuner_gate_r = 5;
- st->i2c_tuner_addr = 0xc0;
+ st->i2c_tuner_addr = 0x60;
st->tuner_config = TUNER_RS2000;
st->fe_set_voltage =
adap->fe[0]->ops.set_voltage;
@@ -1144,7 +1152,7 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
switch (st->tuner_config) {
case TUNER_LG:
- if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0,
+ if (dvb_attach(tda826x_attach, adap->fe[0], 0x60,
&d->i2c_adap, 1))
ret = st->tuner_config;
break;
@@ -1154,7 +1162,7 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
ret = st->tuner_config;
break;
case TUNER_S0194:
- if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0,
+ if (dvb_attach(dvb_pll_attach , adap->fe[0], 0x60,
&d->i2c_adap, DVB_PLL_OPERA1))
ret = st->tuner_config;
break;
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index a4c302d0aa37..d98387a3c95e 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -835,6 +835,11 @@ static struct tua9001_config rtl2832u_tua9001_config = {
.i2c_addr = 0x60,
};
+static const struct fc0012_config rtl2832u_fc0012_config = {
+ .i2c_address = 0x63, /* 0xc6 >> 1 */
+ .xtal_freq = FC_XTAL_28_8_MHZ,
+};
+
static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
{
int ret;
@@ -847,7 +852,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
switch (priv->tuner) {
case TUNER_RTL2832_FC0012:
fe = dvb_attach(fc0012_attach, adap->fe[0],
- &d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
+ &d->i2c_adap, &rtl2832u_fc0012_config);
/* since fc0012 includs reading the signal strength delegate
* that to the tuner driver */
@@ -1120,7 +1125,7 @@ err:
return ret;
}
-
+#if IS_ENABLED(CONFIG_RC_CORE)
static int rtl2831u_rc_query(struct dvb_usb_device *d)
{
int ret, i;
@@ -1203,7 +1208,11 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d,
return 0;
}
+#else
+ #define rtl2831u_get_rc_config NULL
+#endif
+#if IS_ENABLED(CONFIG_RC_CORE)
static int rtl2832u_rc_query(struct dvb_usb_device *d)
{
int ret, i;
@@ -1275,6 +1284,9 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
return 0;
}
+#else
+ #define rtl2832u_get_rc_config NULL
+#endif
static const struct dvb_usb_device_properties rtl2831u_props = {
.driver_name = KBUILD_MODNAME,
@@ -1333,13 +1345,13 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
{ DVB_USB_DEVICE(USB_VID_REALTEK, 0x2838,
&rtl2832u_props, "Realtek RTL2832U reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1,
- &rtl2832u_props, "Terratec Cinergy T Stick Black", NULL) },
+ &rtl2832u_props, "TerraTec Cinergy T Stick Black", NULL) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT,
&rtl2832u_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK,
- &rtl2832u_props, "NOXON DAB/DAB+ USB dongle", NULL) },
+ &rtl2832u_props, "TerraTec NOXON DAB Stick", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV2,
- &rtl2832u_props, "NOXON DAB/DAB+ USB dongle (rev 2)", NULL) },
+ &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 2)", NULL) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TREKSTOR_TERRES_2_0,
&rtl2832u_props, "Trekstor DVB-T Stick Terres 2.0", NULL) },
{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1101,
@@ -1352,6 +1364,14 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "Dexatek DK mini DVB-T Dongle", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d7,
&rtl2832u_props, "TerraTec Cinergy T Stick+", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd3a8,
+ &rtl2832u_props, "ASUS My Cinema-U3100Mini Plus V2", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd393,
+ &rtl2832u_props, "GIGABYTE U7300", NULL) },
+ { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1104,
+ &rtl2832u_props, "Digivox Micro Hd", NULL) },
+ { DVB_USB_DEVICE(USB_VID_COMPRO, 0x0620,
+ &rtl2832u_props, "Compro VideoMate U620F", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
index fa0b2931d305..c5d95662e2e1 100644
--- a/drivers/media/usb/dvb-usb/Kconfig
+++ b/drivers/media/usb/dvb-usb/Kconfig
@@ -202,8 +202,12 @@ config DVB_USB_TTUSB2
select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT
select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT
help
- Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The
+ Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver and
+ the TechnoTrend CT-3650 CI DVB-C/T USB2.0 receiver. The
firmware protocol used by this module is similar to the one used by the
old ttusb-driver - that's why the module is called dvb-usb-ttusb2.
@@ -267,9 +271,11 @@ config DVB_USB_DW2102
select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT
select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT
select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_M88RS2000 if MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0
receivers.
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
index 19b5ed2825d7..bf2a908d74cf 100644
--- a/drivers/media/usb/dvb-usb/dib0700_core.c
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -561,10 +561,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
}
- if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
- err("could not acquire lock");
- return -EINTR;
- }
+ mutex_lock(&adap->dev->usb_mutex);
st->buf[0] = REQUEST_ENABLE_VIDEO;
/* this bit gives a kind of command,
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c
index 169196ec2d4e..1adf325012f7 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c
@@ -38,41 +38,41 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
- for (o = 0; o < adap->props.num_frontends; o++) {
- struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o];
- /* speed - when running at FULL speed we need a HW PID filter */
- if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
- err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
- return -ENODEV;
- }
+ for (o = 0; o < adap->props.num_frontends; o++) {
+ struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o];
+ /* speed - when running at FULL speed we need a HW PID filter */
+ if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
+ err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
+ return -ENODEV;
+ }
- if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
- (props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
- info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count);
- adap->fe_adap[o].pid_filtering = 1;
- adap->fe_adap[o].max_feed_count = props->pid_filter_count;
- } else {
- info("will pass the complete MPEG2 transport stream to the software demuxer.");
- adap->fe_adap[o].pid_filtering = 0;
- adap->fe_adap[o].max_feed_count = 255;
- }
+ if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
+ (props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
+ info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count);
+ adap->fe_adap[o].pid_filtering = 1;
+ adap->fe_adap[o].max_feed_count = props->pid_filter_count;
+ } else {
+ info("will pass the complete MPEG2 transport stream to the software demuxer.");
+ adap->fe_adap[o].pid_filtering = 0;
+ adap->fe_adap[o].max_feed_count = 255;
+ }
- if (!adap->fe_adap[o].pid_filtering &&
- dvb_usb_force_pid_filter_usage &&
- props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
- info("pid filter enabled by module option.");
- adap->fe_adap[o].pid_filtering = 1;
- adap->fe_adap[o].max_feed_count = props->pid_filter_count;
- }
+ if (!adap->fe_adap[o].pid_filtering &&
+ dvb_usb_force_pid_filter_usage &&
+ props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
+ info("pid filter enabled by module option.");
+ adap->fe_adap[o].pid_filtering = 1;
+ adap->fe_adap[o].max_feed_count = props->pid_filter_count;
+ }
- if (props->size_of_priv > 0) {
- adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL);
- if (adap->fe_adap[o].priv == NULL) {
- err("no memory for priv for adapter %d fe %d.", n, o);
- return -ENOMEM;
+ if (props->size_of_priv > 0) {
+ adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL);
+ if (adap->fe_adap[o].priv == NULL) {
+ err("no memory for priv for adapter %d fe %d.", n, o);
+ return -ENOMEM;
+ }
}
}
- }
if (adap->props.size_of_priv > 0) {
adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 9382895b1b88..9578a6761f1b 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -1,9 +1,9 @@
/* DVB USB framework compliant Linux driver for the
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
- * TeVii S600, S630, S650, S660, S480,
+ * TeVii S600, S630, S650, S660, S480, S421, S632
* Prof 1100, 7500,
* Geniatech SU3000 Cards
- * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by)
+ * Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -22,11 +22,14 @@
#include "tda1002x.h"
#include "mt312.h"
#include "zl10039.h"
+#include "ts2020.h"
#include "ds3000.h"
#include "stv0900.h"
#include "stv6110.h"
#include "stb6100.h"
#include "stb6100_proc.h"
+#include "m88rs2000.h"
+#include "ts2020.h"
#ifndef USB_PID_DW2102
#define USB_PID_DW2102 0x2102
@@ -68,6 +71,14 @@
#define USB_PID_PROF_1100 0xb012
#endif
+#ifndef USB_PID_TEVII_S421
+#define USB_PID_TEVII_S421 0xd421
+#endif
+
+#ifndef USB_PID_TEVII_S632
+#define USB_PID_TEVII_S632 0xd632
+#endif
+
#define DW210X_READ_MSG 0
#define DW210X_WRITE_MSG 1
@@ -80,6 +91,15 @@
#define DW2102_RC_QUERY (0x1a00)
#define DW2102_LED_CTRL (0x1b00)
+#define DW2101_FIRMWARE "dvb-usb-dw2101.fw"
+#define DW2102_FIRMWARE "dvb-usb-dw2102.fw"
+#define DW2104_FIRMWARE "dvb-usb-dw2104.fw"
+#define DW3101_FIRMWARE "dvb-usb-dw3101.fw"
+#define S630_FIRMWARE "dvb-usb-s630.fw"
+#define S660_FIRMWARE "dvb-usb-s660.fw"
+#define P1100_FIRMWARE "dvb-usb-p1100.fw"
+#define P7500_FIRMWARE "dvb-usb-p7500.fw"
+
#define err_str "did not find the firmware file. (%s) " \
"Please see linux/Documentation/dvb/ for more details " \
"on firmware-problems."
@@ -534,7 +554,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
}
/*case 0x55: cx24116
case 0x6a: stv0903
- case 0x68: ds3000, stv0903
+ case 0x68: ds3000, stv0903, rs2000
case 0x60: ts2020, stv6110, stb6100
case 0xa0: eeprom */
default: {
@@ -932,6 +952,17 @@ static struct ds3000_config dw2104_ds3000_config = {
.demod_address = 0x68,
};
+static struct ts2020_config dw2104_ts2020_config = {
+ .tuner_address = 0x60,
+ .clk_out_div = 1,
+};
+
+static struct ds3000_config s660_ds3000_config = {
+ .demod_address = 0x68,
+ .ci_mode = 1,
+ .set_lock_led = dw210x_led_ctrl,
+};
+
static struct stv0900_config dw2104a_stv0900_config = {
.demod_address = 0x6a,
.demod_mode = 0,
@@ -981,6 +1012,30 @@ static struct stv0900_config prof_7500_stv0900_config = {
static struct ds3000_config su3000_ds3000_config = {
.demod_address = 0x68,
.ci_mode = 1,
+ .set_lock_led = dw210x_led_ctrl,
+};
+
+static u8 m88rs2000_inittab[] = {
+ DEMOD_WRITE, 0x9a, 0x30,
+ DEMOD_WRITE, 0x00, 0x01,
+ WRITE_DELAY, 0x19, 0x00,
+ DEMOD_WRITE, 0x00, 0x00,
+ DEMOD_WRITE, 0x9a, 0xb0,
+ DEMOD_WRITE, 0x81, 0xc1,
+ DEMOD_WRITE, 0x81, 0x81,
+ DEMOD_WRITE, 0x86, 0xc6,
+ DEMOD_WRITE, 0x9a, 0x30,
+ DEMOD_WRITE, 0xf0, 0x80,
+ DEMOD_WRITE, 0xf1, 0xbf,
+ DEMOD_WRITE, 0xb0, 0x45,
+ DEMOD_WRITE, 0xb2, 0x01,
+ DEMOD_WRITE, 0x9a, 0xb0,
+ 0xff, 0xaa, 0xff
+};
+
+static struct m88rs2000_config s421_m88rs2000_config = {
+ .demod_addr = 0x68,
+ .inittab = m88rs2000_inittab,
};
static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
@@ -1033,6 +1088,8 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
&d->dev->i2c_adap);
if (d->fe_adap[0].fe != NULL) {
+ dvb_attach(ts2020_attach, d->fe_adap[0].fe,
+ &dw2104_ts2020_config, &d->dev->i2c_adap);
d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
info("Attached DS3000!\n");
return 0;
@@ -1139,12 +1196,15 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
u8 obuf[] = {7, 1};
- d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
+ d->fe_adap[0].fe = dvb_attach(ds3000_attach, &s660_ds3000_config,
&d->dev->i2c_adap);
if (d->fe_adap[0].fe == NULL)
return -EIO;
+ dvb_attach(ts2020_attach, d->fe_adap[0].fe, &dw2104_ts2020_config,
+ &d->dev->i2c_adap);
+
st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage;
d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage;
@@ -1182,6 +1242,14 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
err("command 0x0e transfer failed.");
obuf[0] = 0xe;
+ obuf[1] = 0x02;
+ obuf[2] = 1;
+
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+ err("command 0x0e transfer failed.");
+ msleep(300);
+
+ obuf[0] = 0xe;
obuf[1] = 0x83;
obuf[2] = 0;
@@ -1205,9 +1273,40 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
if (d->fe_adap[0].fe == NULL)
return -EIO;
- info("Attached DS3000!\n");
+ if (dvb_attach(ts2020_attach, d->fe_adap[0].fe,
+ &dw2104_ts2020_config,
+ &d->dev->i2c_adap)) {
+ info("Attached DS3000/TS2020!\n");
+ return 0;
+ }
- return 0;
+ info("Failed to attach DS3000/TS2020!\n");
+ return -EIO;
+}
+
+static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d)
+{
+ u8 obuf[] = { 0x51 };
+ u8 ibuf[] = { 0 };
+
+ if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+ err("command 0x51 transfer failed.");
+
+ d->fe_adap[0].fe = dvb_attach(m88rs2000_attach, &s421_m88rs2000_config,
+ &d->dev->i2c_adap);
+
+ if (d->fe_adap[0].fe == NULL)
+ return -EIO;
+
+ if (dvb_attach(ts2020_attach, d->fe_adap[0].fe,
+ &dw2104_ts2020_config,
+ &d->dev->i2c_adap)) {
+ info("Attached RS2000/TS2020!\n");
+ return 0;
+ }
+
+ info("Failed to attach RS2000/TS2020!\n");
+ return -EIO;
}
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
@@ -1447,6 +1546,8 @@ enum dw2102_table_entry {
TEVII_S480_1,
TEVII_S480_2,
X3M_SPC1400HD,
+ TEVII_S421,
+ TEVII_S632,
};
static struct usb_device_id dw2102_table[] = {
@@ -1465,6 +1566,8 @@ static struct usb_device_id dw2102_table[] = {
[TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
[TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
+ [TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)},
+ [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)},
{ }
};
@@ -1478,13 +1581,12 @@ static int dw2102_load_firmware(struct usb_device *dev,
u8 reset;
u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
const struct firmware *fw;
- const char *fw_2101 = "dvb-usb-dw2101.fw";
switch (dev->descriptor.idProduct) {
case 0x2101:
- ret = request_firmware(&fw, fw_2101, &dev->dev);
+ ret = request_firmware(&fw, DW2101_FIRMWARE, &dev->dev);
if (ret != 0) {
- err(err_str, fw_2101);
+ err(err_str, DW2101_FIRMWARE);
return ret;
}
break;
@@ -1586,7 +1688,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
static struct dvb_usb_device_properties dw2102_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
- .firmware = "dvb-usb-dw2102.fw",
+ .firmware = DW2102_FIRMWARE,
.no_reconnect = 1,
.i2c_algo = &dw2102_serit_i2c_algo,
@@ -1641,7 +1743,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
static struct dvb_usb_device_properties dw2104_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
- .firmware = "dvb-usb-dw2104.fw",
+ .firmware = DW2104_FIRMWARE,
.no_reconnect = 1,
.i2c_algo = &dw2104_i2c_algo,
@@ -1691,7 +1793,7 @@ static struct dvb_usb_device_properties dw2104_properties = {
static struct dvb_usb_device_properties dw3101_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
- .firmware = "dvb-usb-dw3101.fw",
+ .firmware = DW3101_FIRMWARE,
.no_reconnect = 1,
.i2c_algo = &dw3101_i2c_algo,
@@ -1739,7 +1841,7 @@ static struct dvb_usb_device_properties s6x0_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
.size_of_priv = sizeof(struct s6x0_state),
- .firmware = "dvb-usb-s630.fw",
+ .firmware = S630_FIRMWARE,
.no_reconnect = 1,
.i2c_algo = &s6x0_i2c_algo,
@@ -1814,6 +1916,19 @@ static struct dvb_usb_device_description d7500 = {
{NULL},
};
+struct dvb_usb_device_properties *s421;
+static struct dvb_usb_device_description d421 = {
+ "TeVii S421 PCI",
+ {&dw2102_table[TEVII_S421], NULL},
+ {NULL},
+};
+
+static struct dvb_usb_device_description d632 = {
+ "TeVii S632 USB",
+ {&dw2102_table[TEVII_S632], NULL},
+ {NULL},
+};
+
static struct dvb_usb_device_properties su3000_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
@@ -1879,7 +1994,7 @@ static int dw2102_probe(struct usb_interface *intf,
return -ENOMEM;
/* copy default structure */
/* fill only different fields */
- p1100->firmware = "dvb-usb-p1100.fw";
+ p1100->firmware = P1100_FIRMWARE;
p1100->devices[0] = d1100;
p1100->rc.legacy.rc_map_table = rc_map_tbs_table;
p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
@@ -1891,7 +2006,7 @@ static int dw2102_probe(struct usb_interface *intf,
kfree(p1100);
return -ENOMEM;
}
- s660->firmware = "dvb-usb-s660.fw";
+ s660->firmware = S660_FIRMWARE;
s660->num_device_descs = 3;
s660->devices[0] = d660;
s660->devices[1] = d480_1;
@@ -1905,12 +2020,26 @@ static int dw2102_probe(struct usb_interface *intf,
kfree(s660);
return -ENOMEM;
}
- p7500->firmware = "dvb-usb-p7500.fw";
+ p7500->firmware = P7500_FIRMWARE;
p7500->devices[0] = d7500;
p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach;
+
+ s421 = kmemdup(&su3000_properties,
+ sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+ if (!s421) {
+ kfree(p1100);
+ kfree(s660);
+ kfree(p7500);
+ return -ENOMEM;
+ }
+ s421->num_device_descs = 2;
+ s421->devices[0] = d421;
+ s421->devices[1] = d632;
+ s421->adapter->fe[0].frontend_attach = m88rs2000_frontend_attach;
+
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &dw2104_properties,
@@ -1925,6 +2054,8 @@ static int dw2102_probe(struct usb_interface *intf,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, p7500,
THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, s421,
+ THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &su3000_properties,
THIS_MODULE, NULL, adapter_nr))
return 0;
@@ -1943,9 +2074,17 @@ module_usb_driver(dw2102_driver);
MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
- " DVB-C 3101 USB2.0,"
- " TeVii S600, S630, S650, S660, S480,"
- " Prof 1100, 7500 USB2.0,"
- " Geniatech SU3000 devices");
+ " DVB-C 3101 USB2.0,"
+ " TeVii S600, S630, S650, S660, S480, S421, S632"
+ " Prof 1100, 7500 USB2.0,"
+ " Geniatech SU3000 devices");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(DW2101_FIRMWARE);
+MODULE_FIRMWARE(DW2102_FIRMWARE);
+MODULE_FIRMWARE(DW2104_FIRMWARE);
+MODULE_FIRMWARE(DW3101_FIRMWARE);
+MODULE_FIRMWARE(S630_FIRMWARE);
+MODULE_FIRMWARE(S660_FIRMWARE);
+MODULE_FIRMWARE(P1100_FIRMWARE);
+MODULE_FIRMWARE(P7500_FIRMWARE);
diff --git a/drivers/media/usb/dvb-usb/friio-fe.c b/drivers/media/usb/dvb-usb/friio-fe.c
index 90a70c66a96e..d56f927fc31a 100644
--- a/drivers/media/usb/dvb-usb/friio-fe.c
+++ b/drivers/media/usb/dvb-usb/friio-fe.c
@@ -421,11 +421,10 @@ struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d)
/* setup the state */
state->i2c = &d->i2c_adap;
- memcpy(&state->config, &friio_fe_config, sizeof(friio_fe_config));
+ state->config = friio_fe_config;
/* create dvb_frontend */
- memcpy(&state->frontend.ops, &jdvbt90502_ops,
- sizeof(jdvbt90502_ops));
+ state->frontend.ops = jdvbt90502_ops;
state->frontend.demodulator_priv = state;
if (jdvbt90502_init(&state->frontend) < 0)
diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
index 661bb75be955..92afeb20650f 100644
--- a/drivers/media/usb/dvb-usb/m920x.c
+++ b/drivers/media/usb/dvb-usb/m920x.c
@@ -16,6 +16,7 @@
#include "qt1010.h"
#include "tda1004x.h"
#include "tda827x.h"
+#include "mt2060.h"
#include <media/tuner.h>
#include "tuner-simple.h"
@@ -63,23 +64,33 @@ static inline int m920x_write(struct usb_device *udev, u8 request,
return ret;
}
+static inline int m920x_write_seq(struct usb_device *udev, u8 request,
+ struct m920x_inits *seq)
+{
+ int ret;
+ while (seq->address) {
+ ret = m920x_write(udev, request, seq->data, seq->address);
+ if (ret != 0)
+ return ret;
+
+ seq++;
+ }
+
+ return ret;
+}
+
static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
{
int ret = 0, i, epi, flags = 0;
int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
/* Remote controller init. */
- if (d->props.rc.legacy.rc_query) {
+ if (d->props.rc.legacy.rc_query || d->props.rc.core.rc_query) {
deb("Initialising remote control\n");
- while (rc_seq->address) {
- if ((ret = m920x_write(d->udev, M9206_CORE,
- rc_seq->data,
- rc_seq->address)) != 0) {
- deb("Initialising remote control failed\n");
- return ret;
- }
-
- rc_seq++;
+ ret = m920x_write_seq(d->udev, M9206_CORE, rc_seq);
+ if (ret != 0) {
+ deb("Initialising remote control failed\n");
+ return ret;
}
deb("Initialising remote control success\n");
@@ -130,9 +141,50 @@ static int m920x_init_ep(struct usb_interface *intf)
alt->desc.bAlternateSetting);
}
-static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static inline void m920x_parse_rc_state(struct dvb_usb_device *d, u8 rc_state,
+ int *state)
{
struct m920x_state *m = d->priv;
+
+ switch (rc_state) {
+ case 0x80:
+ *state = REMOTE_NO_KEY_PRESSED;
+ break;
+
+ case 0x88: /* framing error or "invalid code" */
+ case 0x99:
+ case 0xc0:
+ case 0xd8:
+ *state = REMOTE_NO_KEY_PRESSED;
+ m->rep_count = 0;
+ break;
+
+ case 0x93:
+ case 0x92:
+ case 0x83: /* pinnacle PCTV310e */
+ case 0x82:
+ m->rep_count = 0;
+ *state = REMOTE_KEY_PRESSED;
+ break;
+
+ case 0x91:
+ case 0x81: /* pinnacle PCTV310e */
+ /* prevent immediate auto-repeat */
+ if (++m->rep_count > 2)
+ *state = REMOTE_KEY_REPEAT;
+ else
+ *state = REMOTE_NO_KEY_PRESSED;
+ break;
+
+ default:
+ deb("Unexpected rc state %02x\n", rc_state);
+ *state = REMOTE_NO_KEY_PRESSED;
+ break;
+ }
+}
+
+static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
int i, ret = 0;
u8 *rc_state;
@@ -140,51 +192,22 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
if (!rc_state)
return -ENOMEM;
- if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
+ ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE,
+ rc_state, 1);
+ if (ret != 0)
goto out;
- if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
+ ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY,
+ rc_state + 1, 1);
+ if (ret != 0)
goto out;
+ m920x_parse_rc_state(d, rc_state[0], state);
+
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]) {
*event = d->props.rc.legacy.rc_map_table[i].keycode;
-
- switch(rc_state[0]) {
- case 0x80:
- *state = REMOTE_NO_KEY_PRESSED;
- goto out;
-
- case 0x88: /* framing error or "invalid code" */
- case 0x99:
- case 0xc0:
- case 0xd8:
- *state = REMOTE_NO_KEY_PRESSED;
- m->rep_count = 0;
- goto out;
-
- case 0x93:
- case 0x92:
- case 0x83: /* pinnacle PCTV310e */
- case 0x82:
- m->rep_count = 0;
- *state = REMOTE_KEY_PRESSED;
- goto out;
-
- case 0x91:
- case 0x81: /* pinnacle PCTV310e */
- /* prevent immediate auto-repeat */
- if (++m->rep_count > 2)
- *state = REMOTE_KEY_REPEAT;
- else
- *state = REMOTE_NO_KEY_PRESSED;
- goto out;
-
- default:
- deb("Unexpected rc state %02x\n", rc_state[0]);
- *state = REMOTE_NO_KEY_PRESSED;
- goto out;
- }
+ goto out;
}
if (rc_state[1] != 0)
@@ -197,6 +220,38 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return ret;
}
+static int m920x_rc_core_query(struct dvb_usb_device *d)
+{
+ int ret = 0;
+ u8 *rc_state;
+ int 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[0], 1)) != 0)
+ goto out;
+
+ if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, &rc_state[1], 1)) != 0)
+ goto out;
+
+ deb("state=0x%02x keycode=0x%02x\n", rc_state[0], rc_state[1]);
+
+ m920x_parse_rc_state(d, rc_state[0], &state);
+
+ if (state == REMOTE_NO_KEY_PRESSED)
+ rc_keyup(d->rc_dev);
+ else if (state == REMOTE_KEY_REPEAT)
+ rc_repeat(d->rc_dev);
+ else
+ rc_keydown(d->rc_dev, rc_state[1], 0);
+
+out:
+ kfree(rc_state);
+ return ret;
+}
+
/* I2C */
static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
{
@@ -496,6 +551,12 @@ static struct qt1010_config m920x_qt1010_config = {
.i2c_address = 0x62
};
+static struct mt2060_config m920x_mt2060_config = {
+ .i2c_address = 0x60, /* 0xc0 */
+ .clock_out = 0,
+};
+
+
/* Callbacks for DVB USB */
static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap)
{
@@ -510,6 +571,37 @@ static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap)
return 0;
}
+static int m920x_mt352_frontend_attach_vp7049(struct dvb_usb_adapter *adap)
+{
+ struct m920x_inits vp7049_fe_init_seq[] = {
+ /* XXX without these commands the frontend cannot be detected,
+ * they must be sent BEFORE the frontend is attached */
+ { 0xff28, 0x00 },
+ { 0xff23, 0x00 },
+ { 0xff28, 0x00 },
+ { 0xff23, 0x00 },
+ { 0xff21, 0x20 },
+ { 0xff21, 0x60 },
+ { 0xff28, 0x00 },
+ { 0xff22, 0x00 },
+ { 0xff20, 0x30 },
+ { 0xff20, 0x20 },
+ { 0xff20, 0x30 },
+ { } /* terminating entry */
+ };
+ int ret;
+
+ deb("%s\n", __func__);
+
+ ret = m920x_write_seq(adap->dev->udev, M9206_CORE, vp7049_fe_init_seq);
+ if (ret != 0) {
+ deb("Initialization of vp7049 frontend failed.");
+ return ret;
+ }
+
+ return m920x_mt352_frontend_attach(adap);
+}
+
static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap)
{
deb("%s\n",__func__);
@@ -574,6 +666,18 @@ static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
+static int m920x_mt2060_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ deb("%s\n", __func__);
+
+ if (dvb_attach(mt2060_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
+ &m920x_mt2060_config, 1220) == NULL)
+ return -ENODEV;
+
+ return 0;
+}
+
+
/* device-specific initialization */
static struct m920x_inits megasky_rc_init [] = {
{ M9206_RC_INIT2, 0xa8 },
@@ -591,7 +695,7 @@ static struct m920x_inits tvwalkertwin_rc_init [] = {
};
static struct m920x_inits pinnacle310e_init[] = {
- /* without these the tuner don't work */
+ /* without these the tuner doesn't work */
{ 0xff20, 0x9b },
{ 0xff22, 0x70 },
@@ -602,6 +706,15 @@ static struct m920x_inits pinnacle310e_init[] = {
{ } /* terminating entry */
};
+static struct m920x_inits vp7049_rc_init[] = {
+ { 0xff28, 0x00 },
+ { 0xff23, 0x00 },
+ { 0xff21, 0x70 },
+ { M9206_RC_INIT2, 0x00 },
+ { M9206_RC_INIT1, 0xff },
+ { } /* terminating entry */
+};
+
/* ir keymaps */
static struct rc_map_table rc_map_megasky_table[] = {
{ 0x0012, KEY_POWER },
@@ -704,6 +817,7 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties;
static struct dvb_usb_device_properties tvwalkertwin_properties;
static struct dvb_usb_device_properties dposh_properties;
static struct dvb_usb_device_properties pinnacle_pctv310e_properties;
+static struct dvb_usb_device_properties vp7049_properties;
static int m920x_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -756,6 +870,13 @@ static int m920x_probe(struct usb_interface *intf,
goto found;
}
+ ret = dvb_usb_device_init(intf, &vp7049_properties,
+ THIS_MODULE, &d, adapter_nr);
+ if (ret == 0) {
+ rc_init_seq = vp7049_rc_init;
+ goto found;
+ }
+
return ret;
} else {
/* Another interface on a multi-tuner device */
@@ -787,6 +908,7 @@ static struct usb_device_id m920x_table [] = {
{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) },
{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) },
{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) },
+ { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_TWINHAN_VP7049) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, m920x_table);
@@ -1079,6 +1201,61 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
}
};
+static struct dvb_usb_device_properties vp7049_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .firmware = "dvb-usb-vp7049-0.95.fw",
+ .download_firmware = m920x_firmware_download,
+
+ .rc.core = {
+ .rc_interval = 150,
+ .rc_codes = RC_MAP_TWINHAN_VP1027_DVBS,
+ .rc_query = m920x_rc_core_query,
+ .allowed_protos = RC_TYPE_UNKNOWN,
+ },
+
+ .size_of_priv = sizeof(struct m920x_state),
+
+ .identify_state = m920x_identify_state,
+ .num_adapters = 1,
+ .adapter = {{
+ .num_frontends = 1,
+ .fe = {{
+
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+ .pid_filter_count = 8,
+ .pid_filter = m920x_pid_filter,
+ .pid_filter_ctrl = m920x_pid_filter_ctrl,
+
+ .frontend_attach = m920x_mt352_frontend_attach_vp7049,
+ .tuner_attach = m920x_mt2060_tuner_attach,
+
+ .stream = {
+ .type = USB_BULK,
+ .count = 8,
+ .endpoint = 0x81,
+ .u = {
+ .bulk = {
+ .buffersize = 512,
+ }
+ }
+ },
+ } },
+ } },
+ .i2c_algo = &m920x_i2c_algo,
+
+ .num_device_descs = 1,
+ .devices = {
+ { "DTV-DVB UDTT7049",
+ { &m920x_table[7], NULL },
+ { NULL },
+ }
+ }
+};
+
static struct usb_driver m920x_driver = {
.name = "dvb_usb_m920x",
.probe = m920x_probe,
diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c
index bcdac225ebe1..2ce3d19c58ef 100644
--- a/drivers/media/usb/dvb-usb/ttusb2.c
+++ b/drivers/media/usb/dvb-usb/ttusb2.c
@@ -620,6 +620,8 @@ static struct usb_device_id ttusb2_table [] = {
USB_PID_TECHNOTREND_CONNECT_S2400) },
{ USB_DEVICE(USB_VID_TECHNOTREND,
USB_PID_TECHNOTREND_CONNECT_CT3650) },
+ { USB_DEVICE(USB_VID_TECHNOTREND,
+ USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, ttusb2_table);
@@ -721,12 +723,16 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
.generic_bulk_ctrl_endpoint = 0x01,
- .num_device_descs = 1,
+ .num_device_descs = 2,
.devices = {
{ "Technotrend TT-connect S-2400",
{ &ttusb2_table[2], NULL },
{ NULL },
},
+ { "Technotrend TT-connect S-2400 (8kB EEPROM)",
+ { &ttusb2_table[4], NULL },
+ { NULL },
+ },
}
};
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index 7a5bd61bd3bb..c754a80a8d8b 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -3,7 +3,7 @@ config VIDEO_EM28XX
depends on VIDEO_DEV && I2C
select VIDEO_TUNER
select VIDEO_TVEEPROM
- select VIDEOBUF_VMALLOC
+ select VIDEOBUF2_VMALLOC
select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
@@ -34,6 +34,7 @@ config VIDEO_EM28XX_DVB
tristate "DVB/ATSC Support for em28xx based TV cards"
depends on VIDEO_EM28XX && DVB_CORE
select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT
select DVB_S921 if MEDIA_SUBDRV_AUTOSELECT
@@ -43,7 +44,10 @@ config VIDEO_EM28XX_DVB
select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA10071 if MEDIA_SUBDRV_AUTOSELECT
select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
- select VIDEOBUF_DVB
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
---help---
This adds support for DVB cards based on the
Empiatech em28xx chips.
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 619bffbab3bc..54a03b20de6e 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -6,6 +6,7 @@
Markus Rechberger <mrechberger@gmail.com>
Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
+ Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -56,10 +57,16 @@ module_param(disable_usb_speed_check, int, 0444);
MODULE_PARM_DESC(disable_usb_speed_check,
"override min bandwidth requirement of 480M bps");
-static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "card type");
+static int usb_xfer_mode = -1;
+module_param(usb_xfer_mode, int, 0444);
+MODULE_PARM_DESC(usb_xfer_mode,
+ "USB transfer mode for frame data (-1 = auto, 0 = prefer isoc, 1 = prefer bulk)");
+
+
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */
static unsigned long em28xx_devused;
@@ -486,7 +493,7 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = EM28XX_AMUX_LINE_IN,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
@@ -2073,6 +2080,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2884_BOARD_TERRATEC_H5 },
{ USB_DEVICE(0x0ccd, 0x10ad), /* H5 Rev. 2 */
.driver_info = EM2884_BOARD_TERRATEC_H5 },
+ { USB_DEVICE(0x0ccd, 0x10b6), /* H5 Rev. 3 */
+ .driver_info = EM2884_BOARD_TERRATEC_H5 },
{ USB_DEVICE(0x0ccd, 0x0084),
.driver_info = EM2860_BOARD_TERRATEC_AV350 },
{ USB_DEVICE(0x0ccd, 0x0096),
@@ -2905,7 +2914,7 @@ static void request_module_async(struct work_struct *work)
if (dev->board.has_dvb)
request_module("em28xx-dvb");
- if (dev->board.ir_codes && !disable_ir)
+ if ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir)
request_module("em28xx-rc");
#endif /* CONFIG_MODULES */
}
@@ -2934,6 +2943,8 @@ void em28xx_release_resources(struct em28xx *dev)
em28xx_i2c_unregister(dev);
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+
v4l2_device_unregister(&dev->v4l2_dev);
usb_put_dev(dev->udev);
@@ -2950,9 +2961,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
struct usb_interface *interface,
int minor)
{
+ struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
int retval;
+ static const char *default_chip_name = "em28xx";
+ const char *chip_name = default_chip_name;
dev->udev = udev;
+ mutex_init(&dev->vb_queue_lock);
+ mutex_init(&dev->vb_vbi_queue_lock);
mutex_init(&dev->ctrl_urb_lock);
spin_lock_init(&dev->slock);
@@ -2978,51 +2994,62 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
switch (dev->chip_id) {
case CHIP_ID_EM2800:
- em28xx_info("chip ID is em2800\n");
+ chip_name = "em2800";
break;
case CHIP_ID_EM2710:
- em28xx_info("chip ID is em2710\n");
+ chip_name = "em2710";
break;
case CHIP_ID_EM2750:
- em28xx_info("chip ID is em2750\n");
+ chip_name = "em2750";
break;
case CHIP_ID_EM2820:
- em28xx_info("chip ID is em2820 (or em2710)\n");
+ chip_name = "em2710/2820";
break;
case CHIP_ID_EM2840:
- em28xx_info("chip ID is em2840\n");
+ chip_name = "em2840";
break;
case CHIP_ID_EM2860:
- em28xx_info("chip ID is em2860\n");
+ chip_name = "em2860";
break;
case CHIP_ID_EM2870:
- em28xx_info("chip ID is em2870\n");
+ chip_name = "em2870";
dev->wait_after_write = 0;
break;
case CHIP_ID_EM2874:
- em28xx_info("chip ID is em2874\n");
+ chip_name = "em2874";
dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
break;
case CHIP_ID_EM28174:
- em28xx_info("chip ID is em28174\n");
+ chip_name = "em28174";
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");
+ chip_name = "em2882/3";
dev->wait_after_write = 0;
break;
case CHIP_ID_EM2884:
- em28xx_info("chip ID is em2884\n");
+ chip_name = "em2884";
dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
break;
default:
- em28xx_info("em28xx chip ID = %d\n", dev->chip_id);
+ printk(KERN_INFO DRIVER_NAME
+ ": unknown em28xx chip ID (%d)\n", dev->chip_id);
}
}
+ if (chip_name != default_chip_name)
+ printk(KERN_INFO DRIVER_NAME
+ ": chip ID is %s\n", chip_name);
+
+ /*
+ * For em2820/em2710, the name may change latter, after checking
+ * if the device has a sensor (so, it is em2710) or not.
+ */
+ snprintf(dev->name, sizeof(dev->name), "%s #%d", chip_name, dev->devno);
+
if (dev->is_audio_only) {
retval = em28xx_audio_setup(dev);
if (retval)
@@ -3039,6 +3066,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
em28xx_pre_card_setup(dev);
+ if (dev->chip_id == CHIP_ID_EM2820) {
+ if (dev->board.is_webcam)
+ chip_name = "em2710";
+ else
+ chip_name = "em2820";
+ snprintf(dev->name, sizeof(dev->name), "%s #%d", chip_name, dev->devno);
+ }
+
if (!dev->board.is_em2800) {
/* Resets I2C speed */
retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
@@ -3056,6 +3091,9 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
return retval;
}
+ v4l2_ctrl_handler_init(hdl, 4);
+ dev->v4l2_dev.ctrl_handler = hdl;
+
/* register i2c bus */
retval = em28xx_i2c_register(dev);
if (retval < 0) {
@@ -3081,6 +3119,18 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
__func__, retval);
goto fail;
}
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
+ } else {
+ /* install the em28xx notify callback */
+ v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
+ em28xx_ctrl_notify, dev);
+ v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
+ em28xx_ctrl_notify, dev);
+ }
/* wake i2c devices */
em28xx_wake_i2c(dev);
@@ -3110,6 +3160,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
msleep(3);
}
+ v4l2_ctrl_handler_setup(&dev->ctrl_handler);
+ retval = dev->ctrl_handler.error;
+ if (retval)
+ goto fail;
+
retval = em28xx_register_analog_devices(dev);
if (retval < 0) {
goto fail;
@@ -3122,6 +3177,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
fail:
em28xx_i2c_unregister(dev);
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
unregister_dev:
v4l2_device_unregister(&dev->v4l2_dev);
@@ -3143,7 +3199,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
struct em28xx *dev = NULL;
int retval;
bool has_audio = false, has_video = false, has_dvb = false;
- int i, nr;
+ int i, nr, try_bulk;
const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
char *speed;
@@ -3183,9 +3239,10 @@ static int em28xx_usb_probe(struct usb_interface *interface,
}
/* compute alternate max packet sizes */
- dev->alt_max_pkt_size = kmalloc(sizeof(dev->alt_max_pkt_size[0]) *
+ dev->alt_max_pkt_size_isoc =
+ kmalloc(sizeof(dev->alt_max_pkt_size_isoc[0]) *
interface->num_altsetting, GFP_KERNEL);
- if (dev->alt_max_pkt_size == NULL) {
+ if (dev->alt_max_pkt_size_isoc == NULL) {
em28xx_errdev("out of memory!\n");
kfree(dev);
retval = -ENOMEM;
@@ -3208,25 +3265,67 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if (udev->speed == USB_SPEED_HIGH)
size = size * hb_mult(sizedescr);
- if (usb_endpoint_xfer_isoc(e) &&
- usb_endpoint_dir_in(e)) {
+ if (usb_endpoint_dir_in(e)) {
switch (e->bEndpointAddress) {
- case EM28XX_EP_AUDIO:
- has_audio = true;
- break;
- case EM28XX_EP_ANALOG:
+ case 0x82:
has_video = true;
- dev->alt_max_pkt_size[i] = size;
+ if (usb_endpoint_xfer_isoc(e)) {
+ dev->analog_ep_isoc =
+ e->bEndpointAddress;
+ dev->alt_max_pkt_size_isoc[i] = size;
+ } else if (usb_endpoint_xfer_bulk(e)) {
+ dev->analog_ep_bulk =
+ e->bEndpointAddress;
+ }
break;
- case EM28XX_EP_DIGITAL:
- has_dvb = true;
- if (size > dev->dvb_max_pkt_size) {
- dev->dvb_max_pkt_size = size;
- dev->dvb_alt = i;
+ case 0x83:
+ if (usb_endpoint_xfer_isoc(e)) {
+ has_audio = true;
+ } else {
+ printk(KERN_INFO DRIVER_NAME
+ ": error: skipping audio endpoint 0x83, because it uses bulk transfers !\n");
+ }
+ break;
+ case 0x84:
+ if (has_video &&
+ (usb_endpoint_xfer_bulk(e))) {
+ dev->analog_ep_bulk =
+ e->bEndpointAddress;
+ } else {
+ has_dvb = true;
+ if (usb_endpoint_xfer_isoc(e)) {
+ dev->dvb_ep_isoc = e->bEndpointAddress;
+ if (size > dev->dvb_max_pkt_size_isoc) {
+ dev->dvb_max_pkt_size_isoc = size;
+ dev->dvb_alt_isoc = i;
+ }
+ } else {
+ dev->dvb_ep_bulk = e->bEndpointAddress;
+ }
}
break;
}
}
+ /* NOTE:
+ * Old logic with support for isoc transfers only was:
+ * 0x82 isoc => analog
+ * 0x83 isoc => audio
+ * 0x84 isoc => digital
+ *
+ * New logic with support for bulk transfers
+ * 0x82 isoc => analog
+ * 0x82 bulk => analog
+ * 0x83 isoc* => audio
+ * 0x84 isoc => digital
+ * 0x84 bulk => analog or digital**
+ * (*: audio should always be isoc)
+ * (**: analog, if ep 0x82 is isoc, otherwise digital)
+ *
+ * The new logic preserves backwards compatibility and
+ * reflects the endpoint configurations we have seen
+ * so far. But there might be devices for which this
+ * logic is not sufficient...
+ */
}
}
@@ -3261,19 +3360,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
ifnum,
interface->altsetting->desc.bInterfaceNumber);
- if (has_audio)
- printk(KERN_INFO DRIVER_NAME
- ": Audio Vendor Class interface %i found\n",
- ifnum);
- if (has_video)
- printk(KERN_INFO DRIVER_NAME
- ": Video interface %i found\n",
- ifnum);
- if (has_dvb)
- printk(KERN_INFO DRIVER_NAME
- ": DVB interface %i found\n",
- ifnum);
-
/*
* Make sure we have 480 Mbps of bandwidth, otherwise things like
* video stream wouldn't likely work, since 12 Mbps is generally
@@ -3287,7 +3373,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
goto err_free;
}
- snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr);
dev->devno = nr;
dev->model = id->driver_info;
dev->alt = -1;
@@ -3304,6 +3389,24 @@ static int em28xx_usb_probe(struct usb_interface *interface,
}
}
+ if (has_audio)
+ printk(KERN_INFO DRIVER_NAME
+ ": Audio interface %i found %s\n",
+ ifnum,
+ dev->has_audio_class ? "(USB Audio Class)" : "(Vendor Class)");
+ if (has_video)
+ printk(KERN_INFO DRIVER_NAME
+ ": Video interface %i found:%s%s\n",
+ ifnum,
+ dev->analog_ep_bulk ? " bulk" : "",
+ dev->analog_ep_isoc ? " isoc" : "");
+ if (has_dvb)
+ printk(KERN_INFO DRIVER_NAME
+ ": DVB interface %i found:%s%s\n",
+ ifnum,
+ dev->dvb_ep_bulk ? " bulk" : "",
+ dev->dvb_ep_isoc ? " isoc" : "");
+
dev->num_alt = interface->num_altsetting;
if ((unsigned)card[nr] < em28xx_bcount)
@@ -3312,6 +3415,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
+ /* initialize videobuf2 stuff */
+ em28xx_vb2_setup(dev);
+
/* allocate device struct */
mutex_init(&dev->lock);
mutex_lock(&dev->lock);
@@ -3320,13 +3426,46 @@ static int em28xx_usb_probe(struct usb_interface *interface,
goto unlock_and_free;
}
+ if (usb_xfer_mode < 0) {
+ if (dev->board.is_webcam)
+ try_bulk = 1;
+ else
+ try_bulk = 0;
+ } else {
+ try_bulk = usb_xfer_mode > 0;
+ }
+
+ /* Select USB transfer types to use */
+ if (has_video) {
+ if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk))
+ dev->analog_xfer_bulk = 1;
+ em28xx_info("analog set to %s mode.\n",
+ dev->analog_xfer_bulk ? "bulk" : "isoc");
+ }
if (has_dvb) {
- /* pre-allocate DVB isoc transfer buffers */
- retval = em28xx_alloc_isoc(dev, EM28XX_DIGITAL_MODE,
- EM28XX_DVB_MAX_PACKETS,
- EM28XX_DVB_NUM_BUFS,
- dev->dvb_max_pkt_size);
+ if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk))
+ dev->dvb_xfer_bulk = 1;
+
+ em28xx_info("dvb set to %s mode.\n",
+ dev->dvb_xfer_bulk ? "bulk" : "isoc");
+
+ /* pre-allocate DVB usb transfer buffers */
+ if (dev->dvb_xfer_bulk) {
+ retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
+ dev->dvb_xfer_bulk,
+ EM28XX_DVB_NUM_BUFS,
+ 512,
+ EM28XX_DVB_BULK_PACKET_MULTIPLIER);
+ } else {
+ retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
+ dev->dvb_xfer_bulk,
+ EM28XX_DVB_NUM_BUFS,
+ dev->dvb_max_pkt_size_isoc,
+ EM28XX_DVB_NUM_ISOC_PACKETS);
+ }
if (retval) {
+ printk(DRIVER_NAME
+ ": Failed to pre-allocate USB transfer buffers for DVB.\n");
goto unlock_and_free;
}
}
@@ -3344,7 +3483,7 @@ unlock_and_free:
mutex_unlock(&dev->lock);
err_free:
- kfree(dev->alt_max_pkt_size);
+ kfree(dev->alt_max_pkt_size_isoc);
kfree(dev);
err:
@@ -3370,6 +3509,8 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
if (!dev)
return;
+ dev->disconnected = 1;
+
if (dev->is_audio_only) {
mutex_lock(&dev->lock);
em28xx_close_extension(dev);
@@ -3381,35 +3522,28 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
flush_request_modules(dev);
- /* wait until all current v4l2 io is finished then deallocate
- resources */
mutex_lock(&dev->lock);
v4l2_device_disconnect(&dev->v4l2_dev);
if (dev->users) {
- em28xx_warn
- ("device %s is open! Deregistration and memory "
- "deallocation are deferred on close.\n",
- video_device_node_name(dev->vdev));
-
- dev->state |= DEV_MISCONFIGURED;
- em28xx_uninit_isoc(dev, dev->mode);
- dev->state |= DEV_DISCONNECTED;
- } else {
- dev->state |= DEV_DISCONNECTED;
- em28xx_release_resources(dev);
+ em28xx_warn("device %s is open! Deregistration and memory deallocation are deferred on close.\n",
+ video_device_node_name(dev->vdev));
+
+ em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
+ em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
}
- /* free DVB isoc buffers */
- em28xx_uninit_isoc(dev, EM28XX_DIGITAL_MODE);
+ em28xx_close_extension(dev);
+ /* NOTE: must be called BEFORE the resources are released */
- mutex_unlock(&dev->lock);
+ if (!dev->users)
+ em28xx_release_resources(dev);
- em28xx_close_extension(dev);
+ mutex_unlock(&dev->lock);
if (!dev->users) {
- kfree(dev->alt_max_pkt_size);
+ kfree(dev->alt_max_pkt_size_isoc);
kfree(dev);
}
}
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index bed07a6c33f8..aaedd11791f2 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -5,6 +5,7 @@
Markus Rechberger <mrechberger@gmail.com>
Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
+ Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -76,7 +77,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
int ret;
int pipe = usb_rcvctrlpipe(dev->udev, 0);
- if (dev->state & DEV_DISCONNECTED)
+ if (dev->disconnected)
return -ENODEV;
if (len > URB_MAX_CTRL_SIZE)
@@ -100,7 +101,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
if (reg_debug)
printk(" failed!\n");
mutex_unlock(&dev->ctrl_urb_lock);
- return ret;
+ return usb_translate_errors(ret);
}
if (len)
@@ -152,7 +153,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
int ret;
int pipe = usb_sndctrlpipe(dev->udev, 0);
- if (dev->state & DEV_DISCONNECTED)
+ if (dev->disconnected)
return -ENODEV;
if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
@@ -181,6 +182,9 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
0x0000, reg, dev->urb_buf, len, HZ);
mutex_unlock(&dev->ctrl_urb_lock);
+ if (ret < 0)
+ return usb_translate_errors(ret);
+
if (dev->wait_after_write)
msleep(dev->wait_after_write);
@@ -729,22 +733,24 @@ static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
}
-static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
u16 width, u16 height)
{
- u8 cwidth = width;
- u8 cheight = height;
- u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
+ u8 cwidth = width >> 2;
+ u8 cheight = height >> 2;
+ u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
+ /* NOTE: size limit: 2047x1023 = 2MPix */
- em28xx_coredbg("em28xx Area Set: (%d,%d)\n",
- (width | (overflow & 2) << 7),
- (height | (overflow & 1) << 8));
+ em28xx_coredbg("capture area set to (%d,%d): %dx%d\n",
+ hstart, vstart,
+ ((overflow & 2) << 9 | cwidth << 2),
+ ((overflow & 1) << 10 | cheight << 2));
em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
- return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
+ em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
}
static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
@@ -797,28 +803,30 @@ int em28xx_resolution_set(struct em28xx *dev)
it out, we end up with the same format as the rest of the VBI
region */
if (em28xx_vbi_supported(dev) == 1)
- em28xx_capture_area_set(dev, 0, 2, width >> 2, height >> 2);
+ em28xx_capture_area_set(dev, 0, 2, width, height);
else
- em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
+ em28xx_capture_area_set(dev, 0, 0, width, height);
return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
}
+/* Set USB alternate setting for analog video */
int em28xx_set_alternate(struct em28xx *dev)
{
- int errCode, prev_alt = dev->alt;
+ int errCode;
int i;
unsigned int min_pkt_size = dev->width * 2 + 4;
- /*
- * alt = 0 is used only for control messages, so, only values
- * greater than 0 can be used for streaming.
- */
- if (alt && alt < dev->num_alt) {
+ /* NOTE: for isoc transfers, only alt settings > 0 are allowed
+ bulk transfers seem to work only with alt=0 ! */
+ dev->alt = 0;
+ if ((alt > 0) && (alt < dev->num_alt)) {
em28xx_coredbg("alternate forced to %d\n", dev->alt);
dev->alt = alt;
goto set_alt;
}
+ if (dev->analog_xfer_bulk)
+ goto set_alt;
/* When image size is bigger than a certain value,
the frame size should be increased, otherwise, only
@@ -829,30 +837,38 @@ int em28xx_set_alternate(struct em28xx *dev)
for (i = 0; i < dev->num_alt; i++) {
/* stop when the selected alt setting offers enough bandwidth */
- if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
+ if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
dev->alt = i;
break;
/* otherwise make sure that we end up with the maximum bandwidth
because the min_pkt_size equation might be wrong...
*/
- } else if (dev->alt_max_pkt_size[i] >
- dev->alt_max_pkt_size[dev->alt])
+ } else if (dev->alt_max_pkt_size_isoc[i] >
+ dev->alt_max_pkt_size_isoc[dev->alt])
dev->alt = i;
}
set_alt:
- if (dev->alt != prev_alt) {
+ /* NOTE: for bulk transfers, we need to call usb_set_interface()
+ * even if the previous settings were the same. Otherwise streaming
+ * fails with all urbs having status = -EOVERFLOW ! */
+ if (dev->analog_xfer_bulk) {
+ dev->max_pkt_size = 512; /* USB 2.0 spec */
+ dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
+ } else { /* isoc */
em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
- min_pkt_size, dev->alt);
- dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
- em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
- dev->alt, dev->max_pkt_size);
- errCode = usb_set_interface(dev->udev, 0, dev->alt);
- if (errCode < 0) {
- em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
- dev->alt, errCode);
- return errCode;
- }
+ min_pkt_size, dev->alt);
+ dev->max_pkt_size =
+ dev->alt_max_pkt_size_isoc[dev->alt];
+ dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
+ }
+ em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
+ dev->alt, dev->max_pkt_size);
+ errCode = usb_set_interface(dev->udev, 0, dev->alt);
+ if (errCode < 0) {
+ em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
+ dev->alt, errCode);
+ return errCode;
}
return 0;
}
@@ -919,7 +935,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode);
------------------------------------------------------------------*/
/*
- * IRQ callback, called by URB callback
+ * URB completion handler for isoc/bulk transfers
*/
static void em28xx_irq_callback(struct urb *urb)
{
@@ -941,11 +957,12 @@ static void em28xx_irq_callback(struct urb *urb)
/* Copy data from URB */
spin_lock(&dev->slock);
- dev->isoc_ctl.isoc_copy(dev, urb);
+ dev->usb_ctl.urb_data_copy(dev, urb);
spin_unlock(&dev->slock);
/* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
+ /* isoc only (bulk: number_of_packets = 0) */
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
}
@@ -961,49 +978,50 @@ static void em28xx_irq_callback(struct urb *urb)
/*
* Stop and Deallocate URBs
*/
-void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode)
+void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode)
{
struct urb *urb;
- struct em28xx_usb_isoc_bufs *isoc_bufs;
+ struct em28xx_usb_bufs *usb_bufs;
int i;
- em28xx_isocdbg("em28xx: called em28xx_uninit_isoc in mode %d\n", mode);
+ em28xx_isocdbg("em28xx: called em28xx_uninit_usb_xfer in mode %d\n",
+ mode);
if (mode == EM28XX_DIGITAL_MODE)
- isoc_bufs = &dev->isoc_ctl.digital_bufs;
+ usb_bufs = &dev->usb_ctl.digital_bufs;
else
- isoc_bufs = &dev->isoc_ctl.analog_bufs;
+ usb_bufs = &dev->usb_ctl.analog_bufs;
- for (i = 0; i < isoc_bufs->num_bufs; i++) {
- urb = isoc_bufs->urb[i];
+ for (i = 0; i < usb_bufs->num_bufs; i++) {
+ urb = usb_bufs->urb[i];
if (urb) {
if (!irqs_disabled())
usb_kill_urb(urb);
else
usb_unlink_urb(urb);
- if (isoc_bufs->transfer_buffer[i]) {
+ if (usb_bufs->transfer_buffer[i]) {
usb_free_coherent(dev->udev,
urb->transfer_buffer_length,
- isoc_bufs->transfer_buffer[i],
+ usb_bufs->transfer_buffer[i],
urb->transfer_dma);
}
usb_free_urb(urb);
- isoc_bufs->urb[i] = NULL;
+ usb_bufs->urb[i] = NULL;
}
- isoc_bufs->transfer_buffer[i] = NULL;
+ usb_bufs->transfer_buffer[i] = NULL;
}
- kfree(isoc_bufs->urb);
- kfree(isoc_bufs->transfer_buffer);
+ kfree(usb_bufs->urb);
+ kfree(usb_bufs->transfer_buffer);
- isoc_bufs->urb = NULL;
- isoc_bufs->transfer_buffer = NULL;
- isoc_bufs->num_bufs = 0;
+ usb_bufs->urb = NULL;
+ usb_bufs->transfer_buffer = NULL;
+ usb_bufs->num_bufs = 0;
em28xx_capture_start(dev, 0);
}
-EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
+EXPORT_SYMBOL_GPL(em28xx_uninit_usb_xfer);
/*
* Stop URBs
@@ -1012,7 +1030,7 @@ void em28xx_stop_urbs(struct em28xx *dev)
{
int i;
struct urb *urb;
- struct em28xx_usb_isoc_bufs *isoc_bufs = &dev->isoc_ctl.digital_bufs;
+ struct em28xx_usb_bufs *isoc_bufs = &dev->usb_ctl.digital_bufs;
em28xx_isocdbg("em28xx: called em28xx_stop_urbs\n");
@@ -1033,10 +1051,10 @@ EXPORT_SYMBOL_GPL(em28xx_stop_urbs);
/*
* Allocate URBs
*/
-int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
- int max_packets, int num_bufs, int max_pkt_size)
+int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
+ int num_bufs, int max_pkt_size, int packet_multiplier)
{
- struct em28xx_usb_isoc_bufs *isoc_bufs;
+ struct em28xx_usb_bufs *usb_bufs;
int i;
int sb_size, pipe;
struct urb *urb;
@@ -1044,140 +1062,180 @@ int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode);
- if (mode == EM28XX_DIGITAL_MODE)
- isoc_bufs = &dev->isoc_ctl.digital_bufs;
- else
- isoc_bufs = &dev->isoc_ctl.analog_bufs;
+ /* Check mode and if we have an endpoint for the selected
+ transfer type, select buffer */
+ if (mode == EM28XX_DIGITAL_MODE) {
+ if ((xfer_bulk && !dev->dvb_ep_bulk) ||
+ (!xfer_bulk && !dev->dvb_ep_isoc)) {
+ em28xx_errdev("no endpoint for DVB mode and transfer type %d\n",
+ xfer_bulk > 0);
+ return -EINVAL;
+ }
+ usb_bufs = &dev->usb_ctl.digital_bufs;
+ } else if (mode == EM28XX_ANALOG_MODE) {
+ if ((xfer_bulk && !dev->analog_ep_bulk) ||
+ (!xfer_bulk && !dev->analog_ep_isoc)) {
+ em28xx_errdev("no endpoint for analog mode and transfer type %d\n",
+ xfer_bulk > 0);
+ return -EINVAL;
+ }
+ usb_bufs = &dev->usb_ctl.analog_bufs;
+ } else {
+ em28xx_errdev("invalid mode selected\n");
+ return -EINVAL;
+ }
/* De-allocates all pending stuff */
- em28xx_uninit_isoc(dev, mode);
+ em28xx_uninit_usb_xfer(dev, mode);
- isoc_bufs->num_bufs = num_bufs;
+ usb_bufs->num_bufs = num_bufs;
- isoc_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
- if (!isoc_bufs->urb) {
+ usb_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!usb_bufs->urb) {
em28xx_errdev("cannot alloc memory for usb buffers\n");
return -ENOMEM;
}
- isoc_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+ usb_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
GFP_KERNEL);
- if (!isoc_bufs->transfer_buffer) {
+ if (!usb_bufs->transfer_buffer) {
em28xx_errdev("cannot allocate memory for usb transfer\n");
- kfree(isoc_bufs->urb);
+ kfree(usb_bufs->urb);
return -ENOMEM;
}
- isoc_bufs->max_pkt_size = max_pkt_size;
- isoc_bufs->num_packets = max_packets;
- dev->isoc_ctl.vid_buf = NULL;
- dev->isoc_ctl.vbi_buf = NULL;
+ usb_bufs->max_pkt_size = max_pkt_size;
+ if (xfer_bulk)
+ usb_bufs->num_packets = 0;
+ else
+ usb_bufs->num_packets = packet_multiplier;
+ dev->usb_ctl.vid_buf = NULL;
+ dev->usb_ctl.vbi_buf = NULL;
- sb_size = isoc_bufs->num_packets * isoc_bufs->max_pkt_size;
+ sb_size = packet_multiplier * usb_bufs->max_pkt_size;
/* allocate urbs and transfer buffers */
- for (i = 0; i < isoc_bufs->num_bufs; i++) {
- urb = usb_alloc_urb(isoc_bufs->num_packets, GFP_KERNEL);
+ for (i = 0; i < usb_bufs->num_bufs; i++) {
+ urb = usb_alloc_urb(usb_bufs->num_packets, GFP_KERNEL);
if (!urb) {
- em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
- em28xx_uninit_isoc(dev, mode);
+ em28xx_err("cannot alloc usb_ctl.urb %i\n", i);
+ em28xx_uninit_usb_xfer(dev, mode);
return -ENOMEM;
}
- isoc_bufs->urb[i] = urb;
+ usb_bufs->urb[i] = urb;
- isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+ usb_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev,
sb_size, GFP_KERNEL, &urb->transfer_dma);
- if (!isoc_bufs->transfer_buffer[i]) {
+ if (!usb_bufs->transfer_buffer[i]) {
em28xx_err("unable to allocate %i bytes for transfer"
" buffer %i%s\n",
sb_size, i,
in_interrupt() ? " while in int" : "");
- em28xx_uninit_isoc(dev, mode);
+ em28xx_uninit_usb_xfer(dev, mode);
return -ENOMEM;
}
- memset(isoc_bufs->transfer_buffer[i], 0, sb_size);
-
- /* FIXME: this is a hack - should be
- 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
- should also be using 'desc.bInterval'
- */
- pipe = usb_rcvisocpipe(dev->udev,
- mode == EM28XX_ANALOG_MODE ?
- EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL);
-
- usb_fill_int_urb(urb, dev->udev, pipe,
- isoc_bufs->transfer_buffer[i], sb_size,
- em28xx_irq_callback, dev, 1);
-
- urb->number_of_packets = isoc_bufs->num_packets;
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-
- k = 0;
- for (j = 0; j < isoc_bufs->num_packets; j++) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length =
- isoc_bufs->max_pkt_size;
- k += isoc_bufs->max_pkt_size;
+ memset(usb_bufs->transfer_buffer[i], 0, sb_size);
+
+ if (xfer_bulk) { /* bulk */
+ pipe = usb_rcvbulkpipe(dev->udev,
+ mode == EM28XX_ANALOG_MODE ?
+ dev->analog_ep_bulk :
+ dev->dvb_ep_bulk);
+ usb_fill_bulk_urb(urb, dev->udev, pipe,
+ usb_bufs->transfer_buffer[i], sb_size,
+ em28xx_irq_callback, dev);
+ urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ } else { /* isoc */
+ pipe = usb_rcvisocpipe(dev->udev,
+ mode == EM28XX_ANALOG_MODE ?
+ dev->analog_ep_isoc :
+ dev->dvb_ep_isoc);
+ usb_fill_int_urb(urb, dev->udev, pipe,
+ usb_bufs->transfer_buffer[i], sb_size,
+ em28xx_irq_callback, dev, 1);
+ urb->transfer_flags = URB_ISO_ASAP |
+ URB_NO_TRANSFER_DMA_MAP;
+ k = 0;
+ for (j = 0; j < usb_bufs->num_packets; j++) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length =
+ usb_bufs->max_pkt_size;
+ k += usb_bufs->max_pkt_size;
+ }
}
+
+ urb->number_of_packets = usb_bufs->num_packets;
}
return 0;
}
-EXPORT_SYMBOL_GPL(em28xx_alloc_isoc);
+EXPORT_SYMBOL_GPL(em28xx_alloc_urbs);
/*
* Allocate URBs and start IRQ
*/
-int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
- int max_packets, int num_bufs, int max_pkt_size,
- int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
+ int xfer_bulk, int num_bufs, int max_pkt_size,
+ int packet_multiplier,
+ int (*urb_data_copy) (struct em28xx *dev, struct urb *urb))
{
struct em28xx_dmaqueue *dma_q = &dev->vidq;
struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
- struct em28xx_usb_isoc_bufs *isoc_bufs;
+ struct em28xx_usb_bufs *usb_bufs;
int i;
int rc;
int alloc;
- em28xx_isocdbg("em28xx: called em28xx_init_isoc in mode %d\n", mode);
+ em28xx_isocdbg("em28xx: called em28xx_init_usb_xfer in mode %d\n",
+ mode);
- dev->isoc_ctl.isoc_copy = isoc_copy;
+ dev->usb_ctl.urb_data_copy = urb_data_copy;
if (mode == EM28XX_DIGITAL_MODE) {
- isoc_bufs = &dev->isoc_ctl.digital_bufs;
- /* no need to free/alloc isoc buffers in digital mode */
+ usb_bufs = &dev->usb_ctl.digital_bufs;
+ /* no need to free/alloc usb buffers in digital mode */
alloc = 0;
} else {
- isoc_bufs = &dev->isoc_ctl.analog_bufs;
+ usb_bufs = &dev->usb_ctl.analog_bufs;
alloc = 1;
}
if (alloc) {
- rc = em28xx_alloc_isoc(dev, mode, max_packets,
- num_bufs, max_pkt_size);
+ rc = em28xx_alloc_urbs(dev, mode, xfer_bulk, num_bufs,
+ max_pkt_size, packet_multiplier);
if (rc)
return rc;
}
+ if (xfer_bulk) {
+ rc = usb_clear_halt(dev->udev, usb_bufs->urb[0]->pipe);
+ if (rc < 0) {
+ em28xx_err("failed to clear USB bulk endpoint stall/halt condition (error=%i)\n",
+ rc);
+ em28xx_uninit_usb_xfer(dev, mode);
+ return rc;
+ }
+ }
+
init_waitqueue_head(&dma_q->wq);
init_waitqueue_head(&vbi_dma_q->wq);
em28xx_capture_start(dev, 1);
/* submit urbs and enables IRQ */
- for (i = 0; i < isoc_bufs->num_bufs; i++) {
- rc = usb_submit_urb(isoc_bufs->urb[i], GFP_ATOMIC);
+ for (i = 0; i < usb_bufs->num_bufs; i++) {
+ rc = usb_submit_urb(usb_bufs->urb[i], GFP_ATOMIC);
if (rc) {
em28xx_err("submit of urb %i failed (error=%i)\n", i,
rc);
- em28xx_uninit_isoc(dev, mode);
+ em28xx_uninit_usb_xfer(dev, mode);
return rc;
}
}
return 0;
}
-EXPORT_SYMBOL_GPL(em28xx_init_isoc);
+EXPORT_SYMBOL_GPL(em28xx_init_usb_xfer);
/*
* em28xx_wake_i2c()
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 63f2e7070c00..a81ec2e8cc9b 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -10,6 +10,8 @@
(c) 2008 Aidan Thornton <makosoft@googlemail.com>
+ (c) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
+
Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
(c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
(c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
@@ -25,7 +27,9 @@
#include "em28xx.h"
#include <media/v4l2-common.h>
-#include <media/videobuf-vmalloc.h>
+#include <dvb_demux.h>
+#include <dvb_net.h>
+#include <dmxdev.h>
#include <media/tuner.h>
#include "tuner-simple.h"
#include <linux/gpio.h>
@@ -124,34 +128,47 @@ static inline void print_err_status(struct em28xx *dev,
}
}
-static inline int em28xx_dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
+static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb)
{
- int i;
+ int xfer_bulk, num_packets, i;
if (!dev)
return 0;
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ if (dev->disconnected)
return 0;
- if (urb->status < 0) {
+ if (urb->status < 0)
print_err_status(dev, -1, urb->status);
- if (urb->status == -ENOENT)
- return 0;
- }
- for (i = 0; i < urb->number_of_packets; i++) {
- int status = urb->iso_frame_desc[i].status;
+ xfer_bulk = usb_pipebulk(urb->pipe);
- if (status < 0) {
- print_err_status(dev, i, status);
- if (urb->iso_frame_desc[i].status != -EPROTO)
- continue;
- }
+ if (xfer_bulk) /* bulk */
+ num_packets = 1;
+ else /* isoc */
+ num_packets = urb->number_of_packets;
- dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
- urb->iso_frame_desc[i].offset,
- urb->iso_frame_desc[i].actual_length);
+ for (i = 0; i < num_packets; i++) {
+ if (xfer_bulk) {
+ if (urb->status < 0) {
+ print_err_status(dev, i, urb->status);
+ if (urb->status != -EPROTO)
+ continue;
+ }
+ dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
+ urb->actual_length);
+ } else {
+ if (urb->iso_frame_desc[i].status < 0) {
+ print_err_status(dev, i,
+ urb->iso_frame_desc[i].status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+ dvb_dmx_swfilter(&dev->dvb->demux,
+ urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+ }
}
return 0;
@@ -161,24 +178,40 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
{
int rc;
struct em28xx *dev = dvb->adapter.priv;
- int max_dvb_packet_size;
+ int dvb_max_packet_size, packet_multiplier, dvb_alt;
+
+ if (dev->dvb_xfer_bulk) {
+ if (!dev->dvb_ep_bulk)
+ return -ENODEV;
+ dvb_max_packet_size = 512; /* USB 2.0 spec */
+ packet_multiplier = EM28XX_DVB_BULK_PACKET_MULTIPLIER;
+ dvb_alt = 0;
+ } else { /* isoc */
+ if (!dev->dvb_ep_isoc)
+ return -ENODEV;
+ dvb_max_packet_size = dev->dvb_max_pkt_size_isoc;
+ if (dvb_max_packet_size < 0)
+ return dvb_max_packet_size;
+ packet_multiplier = EM28XX_DVB_NUM_ISOC_PACKETS;
+ dvb_alt = dev->dvb_alt_isoc;
+ }
- usb_set_interface(dev->udev, 0, dev->dvb_alt);
+ usb_set_interface(dev->udev, 0, dvb_alt);
rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
if (rc < 0)
return rc;
- max_dvb_packet_size = dev->dvb_max_pkt_size;
- if (max_dvb_packet_size < 0)
- return max_dvb_packet_size;
dprintk(1, "Using %d buffers each with %d x %d bytes\n",
EM28XX_DVB_NUM_BUFS,
- EM28XX_DVB_MAX_PACKETS,
- max_dvb_packet_size);
-
- return em28xx_init_isoc(dev, EM28XX_DIGITAL_MODE,
- EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS,
- max_dvb_packet_size, em28xx_dvb_isoc_copy);
+ packet_multiplier,
+ dvb_max_packet_size);
+
+ return em28xx_init_usb_xfer(dev, EM28XX_DIGITAL_MODE,
+ dev->dvb_xfer_bulk,
+ EM28XX_DVB_NUM_BUFS,
+ dvb_max_packet_size,
+ packet_multiplier,
+ em28xx_dvb_urb_data_copy);
}
static int em28xx_stop_streaming(struct em28xx_dvb *dvb)
@@ -714,7 +747,8 @@ static struct tda18271_config em28xx_cxd2820r_tda18271_config = {
};
static const struct tda10071_config em28xx_tda10071_config = {
- .i2c_address = 0x55, /* (0xaa >> 1) */
+ .demod_i2c_addr = 0x55, /* (0xaa >> 1) */
+ .tuner_i2c_addr = 0x14,
.i2c_wr_max = 64,
.ts_mode = TDA10071_TS_SERIAL,
.spec_inv = 0,
@@ -1288,7 +1322,7 @@ static int em28xx_dvb_fini(struct em28xx *dev)
if (dev->dvb) {
struct em28xx_dvb *dvb = dev->dvb;
- if (dev->state & DEV_DISCONNECTED) {
+ if (dev->disconnected) {
/* We cannot tell the device to sleep
* once it has been unplugged. */
if (dvb->fe[0])
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 1683bd9d51ee..8532c1d4fd46 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -50,15 +50,18 @@ do { \
} while (0)
/*
- * em2800_i2c_send_max4()
- * send up to 4 bytes to the i2c device
+ * em2800_i2c_send_bytes()
+ * send up to 4 bytes to the em2800 i2c device
*/
-static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
- char *buf, int len)
+static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
{
int ret;
int write_timeout;
- unsigned char b2[6];
+ u8 b2[6];
+
+ if (len < 1 || len > 4)
+ return -EOPNOTSUPP;
+
BUG_ON(len < 1 || len > 4);
b2[5] = 0x80 + len - 1;
b2[4] = addr;
@@ -70,165 +73,212 @@ static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
if (len > 3)
b2[0] = buf[3];
+ /* trigger write */
ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
if (ret != 2 + len) {
- em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
- return -EIO;
+ em28xx_warn("failed to trigger write to i2c address 0x%x "
+ "(error=%i)\n", addr, ret);
+ return (ret < 0) ? ret : -EIO;
}
- for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+ /* wait for completion */
+ for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
write_timeout -= 5) {
ret = dev->em28xx_read_reg(dev, 0x05);
- if (ret == 0x80 + len - 1)
+ if (ret == 0x80 + len - 1) {
return len;
+ } else if (ret == 0x94 + len - 1) {
+ return -ENODEV;
+ } else if (ret < 0) {
+ em28xx_warn("failed to get i2c transfer status from "
+ "bridge register (error=%i)\n", ret);
+ return ret;
+ }
msleep(5);
}
- em28xx_warn("i2c write timed out\n");
+ em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
return -EIO;
}
/*
- * em2800_i2c_send_bytes()
- */
-static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
- short len)
-{
- char *bufPtr = buf;
- int ret;
- int wrcount = 0;
- int count;
- int maxLen = 4;
- struct em28xx *dev = (struct em28xx *)data;
- while (len > 0) {
- count = (len > maxLen) ? maxLen : len;
- ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
- if (ret > 0) {
- len -= count;
- bufPtr += count;
- wrcount += count;
- } else
- return (ret < 0) ? ret : -EFAULT;
- }
- return wrcount;
-}
-
-/*
- * em2800_i2c_check_for_device()
- * check if there is a i2c_device at the supplied address
+ * em2800_i2c_recv_bytes()
+ * read up to 4 bytes from the em2800 i2c device
*/
-static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
{
- char msg;
+ u8 buf2[4];
int ret;
- int write_timeout;
- msg = addr;
- ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
- if (ret < 0) {
- em28xx_warn("setting i2c device address failed (error=%i)\n",
- ret);
- return ret;
- }
- msg = 0x84;
- ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
- if (ret < 0) {
- em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
- return ret;
+ int read_timeout;
+ int i;
+
+ if (len < 1 || len > 4)
+ return -EOPNOTSUPP;
+
+ /* trigger read */
+ buf2[1] = 0x84 + len - 1;
+ buf2[0] = addr;
+ ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2);
+ if (ret != 2) {
+ em28xx_warn("failed to trigger read from i2c address 0x%x "
+ "(error=%i)\n", addr, ret);
+ return (ret < 0) ? ret : -EIO;
}
- for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
- write_timeout -= 5) {
- unsigned reg = dev->em28xx_read_reg(dev, 0x5);
- if (reg == 0x94)
+ /* wait for completion */
+ for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
+ read_timeout -= 5) {
+ ret = dev->em28xx_read_reg(dev, 0x05);
+ if (ret == 0x84 + len - 1) {
+ break;
+ } else if (ret == 0x94 + len - 1) {
return -ENODEV;
- else if (reg == 0x84)
- return 0;
+ } else if (ret < 0) {
+ em28xx_warn("failed to get i2c transfer status from "
+ "bridge register (error=%i)\n", ret);
+ return ret;
+ }
msleep(5);
}
- return -ENODEV;
+ if (ret != 0x84 + len - 1)
+ em28xx_warn("read from i2c device at 0x%x timed out\n", addr);
+
+ /* get the received message */
+ ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
+ if (ret != len) {
+ em28xx_warn("reading from i2c device at 0x%x failed: "
+ "couldn't get the received message from the bridge "
+ "(error=%i)\n", addr, ret);
+ return (ret < 0) ? ret : -EIO;
+ }
+ for (i = 0; i < len; i++)
+ buf[i] = buf2[len - 1 - i];
+
+ return ret;
}
/*
- * em2800_i2c_recv_bytes()
- * read from the i2c device
+ * em2800_i2c_check_for_device()
+ * check if there is an i2c device at the supplied address
*/
-static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
- char *buf, int len)
+static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
{
+ u8 buf;
int ret;
- /* check for the device and set i2c read address */
- ret = em2800_i2c_check_for_device(dev, addr);
- if (ret) {
- em28xx_warn
- ("preparing read at i2c address 0x%x failed (error=%i)\n",
- addr, ret);
- return ret;
- }
- ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
- if (ret < 0) {
- em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
- addr, ret);
- return ret;
- }
- return ret;
+
+ ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
+ if (ret == 1)
+ return 0;
+ return (ret < 0) ? ret : -EIO;
}
/*
* em28xx_i2c_send_bytes()
*/
-static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
- short len, int stop)
+static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
+ u16 len, int stop)
{
- int wrcount = 0;
- struct em28xx *dev = (struct em28xx *)data;
int write_timeout, ret;
- wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
+ if (len < 1 || len > 64)
+ return -EOPNOTSUPP;
+ /* NOTE: limited by the USB ctrl message constraints
+ * Zero length reads always succeed, even if no device is connected */
+
+ /* Write to i2c device */
+ ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
+ if (ret != len) {
+ if (ret < 0) {
+ em28xx_warn("writing to i2c device at 0x%x failed "
+ "(error=%i)\n", addr, ret);
+ return ret;
+ } else {
+ em28xx_warn("%i bytes write to i2c device at 0x%x "
+ "requested, but %i bytes written\n",
+ len, addr, ret);
+ return -EIO;
+ }
+ }
- /* Seems to be required after a write */
- for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+ /* Check success of the i2c operation */
+ for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
write_timeout -= 5) {
ret = dev->em28xx_read_reg(dev, 0x05);
- if (!ret)
- break;
+ if (ret == 0) { /* success */
+ return len;
+ } else if (ret == 0x10) {
+ return -ENODEV;
+ } else if (ret < 0) {
+ em28xx_warn("failed to read i2c transfer status from "
+ "bridge (error=%i)\n", ret);
+ return ret;
+ }
msleep(5);
+ /* NOTE: do we really have to wait for success ?
+ Never seen anything else than 0x00 or 0x10
+ (even with high payload) ... */
}
-
- return wrcount;
+ em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
+ return -EIO;
}
/*
* em28xx_i2c_recv_bytes()
* read a byte from the i2c device
*/
-static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
- char *buf, int len)
+static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
{
int ret;
+
+ if (len < 1 || len > 64)
+ return -EOPNOTSUPP;
+ /* NOTE: limited by the USB ctrl message constraints
+ * Zero length reads always succeed, even if no device is connected */
+
+ /* Read data from i2c device */
ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
+ if (ret != len) {
+ if (ret < 0) {
+ em28xx_warn("reading from i2c device at 0x%x failed "
+ "(error=%i)\n", addr, ret);
+ return ret;
+ } else {
+ em28xx_warn("%i bytes requested from i2c device at "
+ "0x%x, but %i bytes received\n",
+ len, addr, ret);
+ return -EIO;
+ }
+ }
+
+ /* Check success of the i2c operation */
+ ret = dev->em28xx_read_reg(dev, 0x05);
if (ret < 0) {
- em28xx_warn("reading i2c device failed (error=%i)\n", ret);
+ em28xx_warn("failed to read i2c transfer status from "
+ "bridge (error=%i)\n", ret);
return ret;
}
- if (dev->em28xx_read_reg(dev, 0x5) != 0)
- return -ENODEV;
- return ret;
+ if (ret > 0) {
+ if (ret == 0x10) {
+ return -ENODEV;
+ } else {
+ em28xx_warn("unknown i2c error (status=%i)\n", ret);
+ return -EIO;
+ }
+ }
+ return len;
}
/*
* em28xx_i2c_check_for_device()
* check if there is a i2c_device at the supplied address
*/
-static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
{
int ret;
+ u8 buf;
- ret = dev->em28xx_read_reg_req(dev, 2, addr);
- if (ret < 0) {
- em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
- return ret;
- }
- if (dev->em28xx_read_reg(dev, 0x5) != 0)
- return -ENODEV;
- return 0;
+ ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
+ if (ret == 1)
+ return 0;
+ return (ret < 0) ? ret : -EIO;
}
/*
@@ -253,11 +303,11 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
rc = em2800_i2c_check_for_device(dev, addr);
else
rc = em28xx_i2c_check_for_device(dev, addr);
- if (rc < 0) {
- dprintk2(2, " no device\n");
+ if (rc == -ENODEV) {
+ if (i2c_debug >= 2)
+ printk(" no device\n");
return rc;
}
-
} else if (msgs[i].flags & I2C_M_RD) {
/* read bytes */
if (dev->board.is_em2800)
@@ -288,16 +338,16 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
msgs[i].len,
i == num - 1);
}
- if (rc < 0)
- goto err;
+ if (rc < 0) {
+ if (i2c_debug >= 2)
+ printk(" ERROR: %i\n", rc);
+ return rc;
+ }
if (i2c_debug >= 2)
printk("\n");
}
return num;
-err:
- dprintk2(2, " ERROR: %i\n", rc);
- return rc;
}
/* based on linux/sunrpc/svcauth.h and linux/hash.h
@@ -329,7 +379,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
{
unsigned char buf, *p = eedata;
struct em28xx_eeprom *em_eeprom = (void *)eedata;
- int i, err, size = len, block;
+ int i, err, size = len, block, block_max;
if (dev->chip_id == CHIP_ID_EM2874 ||
dev->chip_id == CHIP_ID_EM28174 ||
@@ -362,9 +412,15 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
dev->name, err);
return err;
}
+
+ if (dev->board.is_em2800)
+ block_max = 4;
+ else
+ block_max = 64;
+
while (size > 0) {
- if (size > 16)
- block = 16;
+ if (size > block_max)
+ block = block_max;
else
block = size;
@@ -449,7 +505,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
*/
static u32 functionality(struct i2c_adapter *adap)
{
- return I2C_FUNC_SMBUS_EMUL;
+ struct em28xx *dev = adap->algo_data;
+ u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ if (dev->board.is_em2800)
+ func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
+ return func_flags;
}
static struct i2c_algorithm em28xx_algo = {
@@ -474,6 +534,7 @@ static struct i2c_client em28xx_client_template = {
* incomplete list of known devices
*/
static char *i2c_devs[128] = {
+ [0x3e >> 1] = "remote IR sensor",
[0x4a >> 1] = "saa7113h",
[0x52 >> 1] = "drxk",
[0x60 >> 1] = "remote IR sensor",
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 660bf803c9e4..1bef990b3f18 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -40,11 +40,6 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
#define MODULE_NAME "em28xx"
-#define i2cdprintk(fmt, arg...) \
- if (ir_debug) { \
- printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
- }
-
#define dprintk(fmt, arg...) \
if (ir_debug) { \
printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
@@ -57,8 +52,8 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
struct em28xx_ir_poll_result {
unsigned int toggle_bit:1;
unsigned int read_count:7;
- u8 rc_address;
- u8 rc_data[4]; /* 1 byte on em2860/2880, 4 on em2874 */
+
+ u32 scancode;
};
struct em28xx_IR {
@@ -67,12 +62,17 @@ struct em28xx_IR {
char name[32];
char phys[32];
- /* poll external decoder */
+ /* poll decoder */
int polling;
struct delayed_work work;
unsigned int full_code:1;
unsigned int last_readcount;
+ u64 rc_type;
+ /* i2c slave address of external device (if used) */
+ u16 i2c_dev_addr;
+
+ int (*get_key_i2c)(struct i2c_client *, u32 *);
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
};
@@ -80,21 +80,16 @@ struct em28xx_IR {
I2C IR based get keycodes - should be used with ir-kbd-i2c
**********************************************************/
-static int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, u32 *ir_key)
{
unsigned char b;
/* poll IR chip */
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
- i2cdprintk("read error\n");
+ if (1 != i2c_master_recv(i2c_dev, &b, 1))
return -EIO;
- }
/* it seems that 0xFE indicates that a button is still hold
- down, while 0xff indicates that no button is hold
- down. 0xfe sequences are sometimes interrupted by 0xFF */
-
- i2cdprintk("key %02x\n", b);
+ down, while 0xff indicates that no button is hold down. */
if (b == 0xff)
return 0;
@@ -104,18 +99,17 @@ static int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
*ir_key = b;
- *ir_raw = b;
return 1;
}
-static int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev, u32 *ir_key)
{
unsigned char buf[2];
u16 code;
int size;
/* poll IR chip */
- size = i2c_master_recv(ir->c, buf, sizeof(buf));
+ size = i2c_master_recv(i2c_dev, buf, sizeof(buf));
if (size != 2)
return -EIO;
@@ -124,8 +118,6 @@ static int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
if (buf[1] == 0xff)
return 0;
- ir->old = buf[1];
-
/*
* Rearranges bits to the right order.
* The bit order were determined experimentally by using
@@ -148,65 +140,51 @@ static int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
((buf[1] & 0x40) ? 0x0200 : 0) | /* 0000 0010 */
((buf[1] & 0x80) ? 0x0100 : 0); /* 0000 0001 */
- i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x%02x)\n",
- code, buf[1], buf[0]);
-
/* return key */
*ir_key = code;
- *ir_raw = code;
return 1;
}
-static int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
- u32 *ir_raw)
+static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
+ u32 *ir_key)
{
unsigned char buf[3];
/* poll IR chip */
- if (3 != i2c_master_recv(ir->c, buf, 3)) {
- i2cdprintk("read error\n");
+ if (3 != i2c_master_recv(i2c_dev, buf, 3))
return -EIO;
- }
- i2cdprintk("key %02x\n", buf[2]&0x3f);
if (buf[0] != 0x00)
return 0;
*ir_key = buf[2]&0x3f;
- *ir_raw = buf[2]&0x3f;
return 1;
}
-static int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key,
- u32 *ir_raw)
+static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
+ u32 *ir_key)
{
unsigned char subaddr, keydetect, key;
- struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, .buf = &subaddr, .len = 1},
-
- { .addr = ir->c->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} };
+ struct i2c_msg msg[] = { { .addr = i2c_dev->addr, .flags = 0, .buf = &subaddr, .len = 1},
+ { .addr = i2c_dev->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} };
subaddr = 0x10;
- if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
- i2cdprintk("read error\n");
+ if (2 != i2c_transfer(i2c_dev->adapter, msg, 2))
return -EIO;
- }
if (keydetect == 0x00)
return 0;
subaddr = 0x00;
msg[1].buf = &key;
- if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
- i2cdprintk("read error\n");
- return -EIO;
- }
+ if (2 != i2c_transfer(i2c_dev->adapter, msg, 2))
+ return -EIO;
if (key == 0x00)
return 0;
*ir_key = key;
- *ir_raw = key;
return 1;
}
@@ -236,11 +214,8 @@ static int default_polling_getkey(struct em28xx_IR *ir,
/* Infrared read count (Reg 0x45[6:0] */
poll_result->read_count = (msg[0] & 0x7f);
- /* Remote Control Address (Reg 0x46) */
- poll_result->rc_address = msg[1];
-
- /* Remote Control Data (Reg 0x47) */
- poll_result->rc_data[0] = msg[2];
+ /* Remote Control Address/Data (Regs 0x46/0x47) */
+ poll_result->scancode = msg[1] << 8 | msg[2];
return 0;
}
@@ -266,13 +241,35 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
/* Infrared read count (Reg 0x51[6:0] */
poll_result->read_count = (msg[0] & 0x7f);
- /* Remote Control Address (Reg 0x52) */
- poll_result->rc_address = msg[1];
-
- /* Remote Control Data (Reg 0x53-55) */
- poll_result->rc_data[0] = msg[2];
- poll_result->rc_data[1] = msg[3];
- poll_result->rc_data[2] = msg[4];
+ /*
+ * Remote Control Address (Reg 0x52)
+ * Remote Control Data (Reg 0x53-0x55)
+ */
+ switch (ir->rc_type) {
+ case RC_BIT_RC5:
+ poll_result->scancode = msg[1] << 8 | msg[2];
+ break;
+ case RC_BIT_NEC:
+ if ((msg[3] ^ msg[4]) != 0xff) /* 32 bits NEC */
+ poll_result->scancode = (msg[1] << 24) |
+ (msg[2] << 16) |
+ (msg[3] << 8) |
+ msg[4];
+ else if ((msg[1] ^ msg[2]) != 0xff) /* 24 bits NEC */
+ poll_result->scancode = (msg[1] << 16) |
+ (msg[2] << 8) |
+ msg[3];
+ else /* Normal NEC */
+ poll_result->scancode = msg[1] << 8 | msg[3];
+ break;
+ case RC_BIT_RC6_0:
+ poll_result->scancode = msg[1] << 8 | msg[2];
+ break;
+ default:
+ poll_result->scancode = (msg[1] << 24) | (msg[2] << 16) |
+ (msg[3] << 8) | msg[4];
+ break;
+ }
return 0;
}
@@ -281,6 +278,28 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
Polling code for em28xx
**********************************************************/
+static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
+{
+ static u32 ir_key;
+ int rc;
+ struct i2c_client client;
+
+ client.adapter = &ir->dev->i2c_adap;
+ client.addr = ir->i2c_dev_addr;
+
+ rc = ir->get_key_i2c(&client, &ir_key);
+ if (rc < 0) {
+ dprintk("ir->get_key_i2c() failed: %d\n", rc);
+ return rc;
+ }
+
+ if (rc) {
+ dprintk("%s: keycode = 0x%04x\n", __func__, ir_key);
+ rc_keydown(ir->rc, ir_key, 0);
+ }
+ return 0;
+}
+
static void em28xx_ir_handle_key(struct em28xx_IR *ir)
{
int result;
@@ -289,22 +308,21 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
/* read the registers containing the IR status */
result = ir->get_key(ir, &poll_result);
if (unlikely(result < 0)) {
- dprintk("ir->get_key() failed %d\n", result);
+ dprintk("ir->get_key() failed: %d\n", result);
return;
}
if (unlikely(poll_result.read_count != ir->last_readcount)) {
- dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__,
+ dprintk("%s: toggle: %d, count: %d, key 0x%04x\n", __func__,
poll_result.toggle_bit, poll_result.read_count,
- poll_result.rc_address, poll_result.rc_data[0]);
+ poll_result.scancode);
if (ir->full_code)
rc_keydown(ir->rc,
- poll_result.rc_address << 8 |
- poll_result.rc_data[0],
+ poll_result.scancode,
poll_result.toggle_bit);
else
rc_keydown(ir->rc,
- poll_result.rc_data[0],
+ poll_result.scancode & 0xff,
poll_result.toggle_bit);
if (ir->dev->chip_id == CHIP_ID_EM2874 ||
@@ -324,7 +342,10 @@ static void em28xx_ir_work(struct work_struct *work)
{
struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
- em28xx_ir_handle_key(ir);
+ if (ir->i2c_dev_addr) /* external i2c device */
+ em28xx_i2c_ir_handle_key(ir);
+ else /* internal device */
+ em28xx_ir_handle_key(ir);
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
}
@@ -345,93 +366,107 @@ static void em28xx_ir_stop(struct rc_dev *rc)
cancel_delayed_work_sync(&ir->work);
}
-static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
+static int em2860_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
{
- int rc = 0;
struct em28xx_IR *ir = rc_dev->priv;
struct em28xx *dev = ir->dev;
- u8 ir_config = EM2874_IR_RC5;
-
- /* Adjust xclk based o IR table for RC5/NEC tables */
+ /* Adjust xclk based on IR table for RC5/NEC tables */
if (*rc_type & RC_BIT_RC5) {
dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
ir->full_code = 1;
*rc_type = RC_BIT_RC5;
} else if (*rc_type & RC_BIT_NEC) {
dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
- ir_config = EM2874_IR_NEC;
ir->full_code = 1;
*rc_type = RC_BIT_NEC;
- } else if (*rc_type != RC_BIT_UNKNOWN)
- rc = -EINVAL;
+ } else if (*rc_type & RC_BIT_UNKNOWN) {
+ *rc_type = RC_BIT_UNKNOWN;
+ } else {
+ *rc_type = ir->rc_type;
+ return -EINVAL;
+ }
+ em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
+ EM28XX_XCLK_IR_RC5_MODE);
+
+ ir->rc_type = *rc_type;
+ return 0;
+}
+
+static int em2874_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
+{
+ struct em28xx_IR *ir = rc_dev->priv;
+ struct em28xx *dev = ir->dev;
+ u8 ir_config = EM2874_IR_RC5;
+
+ /* Adjust xclk and set type based on IR table for RC5/NEC/RC6 tables */
+ if (*rc_type & RC_BIT_RC5) {
+ dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
+ ir->full_code = 1;
+ *rc_type = RC_BIT_RC5;
+ } else if (*rc_type & RC_BIT_NEC) {
+ dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
+ ir_config = EM2874_IR_NEC | EM2874_IR_NEC_NO_PARITY;
+ ir->full_code = 1;
+ *rc_type = RC_BIT_NEC;
+ } else if (*rc_type & RC_BIT_RC6_0) {
+ dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
+ ir_config = EM2874_IR_RC6_MODE_0;
+ ir->full_code = 1;
+ *rc_type = RC_BIT_RC6_0;
+ } else if (*rc_type & RC_BIT_UNKNOWN) {
+ *rc_type = RC_BIT_UNKNOWN;
+ } else {
+ *rc_type = ir->rc_type;
+ return -EINVAL;
+ }
+ em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
EM28XX_XCLK_IR_RC5_MODE);
+ ir->rc_type = *rc_type;
+
+ return 0;
+}
+static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
+{
+ struct em28xx_IR *ir = rc_dev->priv;
+ struct em28xx *dev = ir->dev;
+
/* Setup the proper handler based on the chip */
switch (dev->chip_id) {
case CHIP_ID_EM2860:
case CHIP_ID_EM2883:
- ir->get_key = default_polling_getkey;
- break;
+ return em2860_ir_change_protocol(rc_dev, rc_type);
case CHIP_ID_EM2884:
case CHIP_ID_EM2874:
case CHIP_ID_EM28174:
- ir->get_key = em2874_polling_getkey;
- em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
- break;
+ return em2874_ir_change_protocol(rc_dev, rc_type);
default:
printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n",
dev->chip_id);
- rc = -EINVAL;
+ return -EINVAL;
}
-
- return rc;
}
-static void em28xx_register_i2c_ir(struct em28xx *dev)
+static int em28xx_probe_i2c_ir(struct em28xx *dev)
{
+ int i = 0;
/* Leadtek winfast tv USBII deluxe can find a non working IR-device */
/* at address 0x18, so if that address is needed for another board in */
/* the future, please put it after 0x1f. */
- struct i2c_board_info info;
const unsigned short addr_list[] = {
0x1f, 0x30, 0x47, I2C_CLIENT_END
};
- memset(&info, 0, sizeof(struct i2c_board_info));
- memset(&dev->init_data, 0, sizeof(dev->init_data));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-
- /* detect & configure */
- switch (dev->model) {
- case EM2800_BOARD_TERRATEC_CINERGY_200:
- case EM2820_BOARD_TERRATEC_CINERGY_250:
- dev->init_data.ir_codes = RC_MAP_EM_TERRATEC;
- dev->init_data.get_key = em28xx_get_key_terratec;
- dev->init_data.name = "i2c IR (EM28XX Terratec)";
- break;
- case EM2820_BOARD_PINNACLE_USB_2:
- dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
- dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
- dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
- break;
- case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
- dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
- dev->init_data.get_key = em28xx_get_key_em_haup;
- dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
- break;
- case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
- dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
- dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
- dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
- break;
+ while (addr_list[i] != I2C_CLIENT_END) {
+ if (i2c_probe_func_quick_read(&dev->i2c_adap, addr_list[i]) == 1)
+ return addr_list[i];
+ i++;
}
- if (dev->init_data.name)
- info.platform_data = &dev->init_data;
- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL);
+ return -ENODEV;
}
/**********************************************************
@@ -527,8 +562,21 @@ static int em28xx_ir_init(struct em28xx *dev)
struct rc_dev *rc;
int err = -ENOMEM;
u64 rc_type;
+ u16 i2c_rc_dev_addr = 0;
+
+ if (dev->board.has_snapshot_button)
+ em28xx_register_snapshot_button(dev);
+
+ if (dev->board.has_ir_i2c) {
+ i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev);
+ if (!i2c_rc_dev_addr) {
+ dev->board.has_ir_i2c = 0;
+ em28xx_warn("No i2c IR remote control device found.\n");
+ return -ENODEV;
+ }
+ }
- if (dev->board.ir_codes == NULL) {
+ if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) {
/* No remote control support */
em28xx_warn("Remote control support is not available for "
"this card.\n");
@@ -538,35 +586,77 @@ static int em28xx_ir_init(struct em28xx *dev)
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
rc = rc_allocate_device();
if (!ir || !rc)
- goto err_out_free;
+ goto error;
/* record handles to ourself */
ir->dev = dev;
dev->ir = ir;
ir->rc = rc;
- /*
- * em2874 supports more protocols. For now, let's just announce
- * the two protocols that were already tested
- */
- rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
rc->priv = ir;
- rc->change_protocol = em28xx_ir_change_protocol;
rc->open = em28xx_ir_start;
rc->close = em28xx_ir_stop;
- /* By default, keep protocol field untouched */
- rc_type = RC_BIT_UNKNOWN;
- err = em28xx_ir_change_protocol(rc, &rc_type);
- if (err)
- goto err_out_free;
+ if (dev->board.has_ir_i2c) { /* external i2c device */
+ switch (dev->model) {
+ case EM2800_BOARD_TERRATEC_CINERGY_200:
+ case EM2820_BOARD_TERRATEC_CINERGY_250:
+ rc->map_name = RC_MAP_EM_TERRATEC;
+ ir->get_key_i2c = em28xx_get_key_terratec;
+ break;
+ case EM2820_BOARD_PINNACLE_USB_2:
+ rc->map_name = RC_MAP_PINNACLE_GREY;
+ ir->get_key_i2c = em28xx_get_key_pinnacle_usb_grey;
+ break;
+ case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+ rc->map_name = RC_MAP_HAUPPAUGE;
+ ir->get_key_i2c = em28xx_get_key_em_haup;
+ rc->allowed_protos = RC_BIT_RC5;
+ break;
+ case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
+ rc->map_name = RC_MAP_WINFAST_USBII_DELUXE;
+ ir->get_key_i2c = em28xx_get_key_winfast_usbii_deluxe;
+ break;
+ default:
+ err = -ENODEV;
+ goto error;
+ }
+
+ ir->i2c_dev_addr = i2c_rc_dev_addr;
+ } else { /* internal device */
+ switch (dev->chip_id) {
+ case CHIP_ID_EM2860:
+ case CHIP_ID_EM2883:
+ rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
+ ir->get_key = default_polling_getkey;
+ break;
+ case CHIP_ID_EM2884:
+ case CHIP_ID_EM2874:
+ case CHIP_ID_EM28174:
+ ir->get_key = em2874_polling_getkey;
+ rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC |
+ RC_BIT_RC6_0;
+ break;
+ default:
+ err = -ENODEV;
+ goto error;
+ }
+
+ rc->change_protocol = em28xx_ir_change_protocol;
+ rc->map_name = dev->board.ir_codes;
+
+ /* By default, keep protocol field untouched */
+ rc_type = RC_BIT_UNKNOWN;
+ err = em28xx_ir_change_protocol(rc, &rc_type);
+ if (err)
+ goto error;
+ }
/* This is how often we ask the chip for IR information */
ir->polling = 100; /* ms */
/* init input device */
- snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)",
- dev->name);
+ snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", dev->name);
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
@@ -578,28 +668,17 @@ static int em28xx_ir_init(struct em28xx *dev)
rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
rc->dev.parent = &dev->udev->dev;
- rc->map_name = dev->board.ir_codes;
rc->driver_name = MODULE_NAME;
/* all done */
err = rc_register_device(rc);
if (err)
- goto err_out_stop;
-
- em28xx_register_i2c_ir(dev);
-
-#if defined(CONFIG_MODULES) && defined(MODULE)
- if (dev->board.has_ir_i2c)
- request_module("ir-kbd-i2c");
-#endif
- if (dev->board.has_snapshot_button)
- em28xx_register_snapshot_button(dev);
+ goto error;
return 0;
- err_out_stop:
+error:
dev->ir = NULL;
- err_out_free:
rc_free_device(rc);
kfree(ir);
return err;
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
index 6ff368297f6e..885089e22bcd 100644
--- a/drivers/media/usb/em28xx/em28xx-reg.h
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
@@ -13,9 +13,9 @@
#define EM_GPO_3 (1 << 3)
/* em28xx endpoints */
-#define EM28XX_EP_ANALOG 0x82
+/* 0x82: (always ?) analog */
#define EM28XX_EP_AUDIO 0x83
-#define EM28XX_EP_DIGITAL 0x84
+/* 0x84: digital or analog */
/* em2800 registers */
#define EM2800_R08_AUDIOSRC 0x08
@@ -177,6 +177,7 @@
/* em2874 IR config register (0x50) */
#define EM2874_IR_NEC 0x00
+#define EM2874_IR_NEC_NO_PARITY 0x01
#define EM2874_IR_RC5 0x04
#define EM2874_IR_RC6_MODE_0 0x08
#define EM2874_IR_RC6_MODE_6A 0x0b
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index 2b4c9cba2d67..39f39c527c13 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -41,105 +41,72 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
/* ------------------------------------------------------------------ */
-static void
-free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx *dev = fh->dev;
- unsigned long flags = 0;
- if (in_interrupt())
- BUG();
-
- /* We used to wait for the buffer to finish here, but this didn't work
- because, as we were keeping the state as VIDEOBUF_QUEUED,
- videobuf_queue_cancel marked it as finished for us.
- (Also, it could wedge forever if the hardware was misconfigured.)
-
- This should be safe; by the time we get here, the buffer isn't
- queued anymore. If we ever start marking the buffers as
- VIDEOBUF_ACTIVE, it won't be, though.
- */
- spin_lock_irqsave(&dev->slock, flags);
- if (dev->isoc_ctl.vbi_buf == buf)
- dev->isoc_ctl.vbi_buf = NULL;
- spin_unlock_irqrestore(&dev->slock, flags);
+ struct em28xx *dev = vb2_get_drv_priv(vq);
+ unsigned long size;
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
+ if (fmt)
+ size = fmt->fmt.pix.sizeimage;
+ else
+ size = dev->vbi_width * dev->vbi_height * 2;
-static int
-vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
-{
- struct em28xx_fh *fh = q->priv_data;
- struct em28xx *dev = fh->dev;
+ if (0 == *nbuffers)
+ *nbuffers = 32;
+ if (*nbuffers < 2)
+ *nbuffers = 2;
+ if (*nbuffers > 32)
+ *nbuffers = 32;
- *size = dev->vbi_width * dev->vbi_height * 2;
+ *nplanes = 1;
+ sizes[0] = size;
- if (0 == *count)
- *count = vbibufs;
- if (*count < 2)
- *count = 2;
- if (*count > 32)
- *count = 32;
return 0;
}
-static int
-vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int vbi_buffer_prepare(struct vb2_buffer *vb)
{
- struct em28xx_fh *fh = q->priv_data;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
- int rc = 0;
+ unsigned long size;
- buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
+ size = dev->vbi_width * dev->vbi_height * 2;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ if (vb2_plane_size(vb, 0) < size) {
+ printk(KERN_INFO "%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), size);
return -EINVAL;
-
- buf->vb.width = dev->vbi_width;
- buf->vb.height = dev->vbi_height;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(q, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
}
+ vb2_set_plane_payload(&buf->vb, 0, size);
- buf->vb.state = VIDEOBUF_PREPARED;
return 0;
-
-fail:
- free_buffer(q, buf);
- return rc;
}
static void
-vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct em28xx_buffer *buf = container_of(vb,
- struct em28xx_buffer,
- vb);
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx *dev = fh->dev;
- struct em28xx_dmaqueue *vbiq = &dev->vbiq;
-
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vbiq->active);
-}
-
-static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+vbi_buffer_queue(struct vb2_buffer *vb)
{
+ struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
- free_buffer(q, buf);
+ struct em28xx_dmaqueue *vbiq = &dev->vbiq;
+ unsigned long flags = 0;
+
+ buf->mem = vb2_plane_vaddr(vb, 0);
+ buf->length = vb2_plane_size(vb, 0);
+
+ spin_lock_irqsave(&dev->slock, flags);
+ list_add_tail(&buf->list, &vbiq->active);
+ spin_unlock_irqrestore(&dev->slock, flags);
}
-struct videobuf_queue_ops em28xx_vbi_qops = {
- .buf_setup = vbi_setup,
- .buf_prepare = vbi_prepare,
- .buf_queue = vbi_queue,
- .buf_release = vbi_release,
+
+struct vb2_ops em28xx_vbi_qops = {
+ .queue_setup = vbi_queue_setup,
+ .buf_prepare = vbi_buffer_prepare,
+ .buf_queue = vbi_buffer_queue,
+ .start_streaming = em28xx_start_analog_streaming,
+ .stop_streaming = em28xx_stop_vbi_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 1e553d357380..32bd7de5dec1 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -6,6 +6,7 @@
Markus Rechberger <mrechberger@gmail.com>
Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
+ Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
Some parts based on SN9C10x PC Camera Controllers GPL driver made
by Luca Risolia <luca.risolia@studio.unibo.it>
@@ -39,6 +40,7 @@
#include "em28xx.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-chip-ident.h>
#include <media/msp3400.h>
#include <media/tuner.h>
@@ -74,9 +76,9 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(EM28XX_VERSION);
-static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
+static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
+static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
module_param_array(video_nr, int, NULL, 0444);
module_param_array(vbi_nr, int, NULL, 0444);
@@ -124,101 +126,50 @@ static struct em28xx_fmt format[] = {
},
};
-/* supported controls */
-/* Common to all boards */
-static struct v4l2_queryctrl ac97_qctrl[] = {
- {
- .id = V4L2_CID_AUDIO_VOLUME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Volume",
- .minimum = 0x0,
- .maximum = 0x1f,
- .step = 0x1,
- .default_value = 0x1f,
- .flags = V4L2_CTRL_FLAG_SLIDER,
- }, {
- .id = V4L2_CID_AUDIO_MUTE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- }
-};
-
/* ------------------------------------------------------------------
DMA and thread functions
------------------------------------------------------------------*/
/*
- * Announces that a buffer were filled and request the next
+ * Finish the current buffer
*/
-static inline void buffer_filled(struct em28xx *dev,
- struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer *buf)
+static inline void finish_buffer(struct em28xx *dev,
+ struct em28xx_buffer *buf)
{
- /* Advice that buffer was filled */
- em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
+ em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
- dev->isoc_ctl.vid_buf = NULL;
+ buf->vb.v4l2_buf.sequence = dev->field_count++;
+ buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
-}
-
-static inline void vbi_buffer_filled(struct em28xx *dev,
- struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer *buf)
-{
- /* Advice that buffer was filled */
- em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
-
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
-
- dev->isoc_ctl.vbi_buf = NULL;
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
}
/*
- * Identify the buffer header type and properly handles
+ * Copy picture data from USB buffer to videobuf buffer
*/
static void em28xx_copy_video(struct em28xx *dev,
- struct em28xx_dmaqueue *dma_q,
struct em28xx_buffer *buf,
- unsigned char *p,
- unsigned char *outp, unsigned long len)
+ unsigned char *usb_buf,
+ unsigned long len)
{
void *fieldstart, *startwrite, *startread;
int linesdone, currlinedone, offset, lencopy, remain;
int bytesperline = dev->width << 1;
- if (dma_q->pos + len > buf->vb.size)
- len = buf->vb.size - dma_q->pos;
+ if (buf->pos + len > buf->length)
+ len = buf->length - buf->pos;
- startread = p;
+ startread = usb_buf;
remain = len;
- if (dev->progressive)
- fieldstart = outp;
- else {
- /* Interlaces two half frames */
- if (buf->top_field)
- fieldstart = outp;
- else
- fieldstart = outp + bytesperline;
- }
+ if (dev->progressive || buf->top_field)
+ fieldstart = buf->vb_buf;
+ else /* interlaced mode, even nr. of lines */
+ fieldstart = buf->vb_buf + bytesperline;
- linesdone = dma_q->pos / bytesperline;
- currlinedone = dma_q->pos % bytesperline;
+ linesdone = buf->pos / bytesperline;
+ currlinedone = buf->pos % bytesperline;
if (dev->progressive)
offset = linesdone * bytesperline + currlinedone;
@@ -229,11 +180,12 @@ static void em28xx_copy_video(struct em28xx *dev,
lencopy = bytesperline - currlinedone;
lencopy = lencopy > remain ? remain : lencopy;
- if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) {
em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
- ((char *)startwrite + lencopy) -
- ((char *)outp + buf->vb.size));
- remain = (char *)outp + buf->vb.size - (char *)startwrite;
+ ((char *)startwrite + lencopy) -
+ ((char *)buf->vb_buf + buf->length));
+ remain = (char *)buf->vb_buf + buf->length -
+ (char *)startwrite;
lencopy = remain;
}
if (lencopy <= 0)
@@ -243,21 +195,24 @@ static void em28xx_copy_video(struct em28xx *dev,
remain -= lencopy;
while (remain > 0) {
- startwrite += lencopy + bytesperline;
+ if (dev->progressive)
+ startwrite += lencopy;
+ else
+ startwrite += lencopy + bytesperline;
startread += lencopy;
if (bytesperline > remain)
lencopy = remain;
else
lencopy = bytesperline;
- if ((char *)startwrite + lencopy > (char *)outp +
- buf->vb.size) {
+ if ((char *)startwrite + lencopy > (char *)buf->vb_buf +
+ buf->length) {
em28xx_isocdbg("Overflow of %zi bytes past buffer end"
"(2)\n",
((char *)startwrite + lencopy) -
- ((char *)outp + buf->vb.size));
- lencopy = remain = (char *)outp + buf->vb.size -
- (char *)startwrite;
+ ((char *)buf->vb_buf + buf->length));
+ lencopy = remain = (char *)buf->vb_buf + buf->length -
+ (char *)startwrite;
}
if (lencopy <= 0)
break;
@@ -267,57 +222,29 @@ static void em28xx_copy_video(struct em28xx *dev,
remain -= lencopy;
}
- dma_q->pos += len;
+ buf->pos += len;
}
+/*
+ * Copy VBI data from USB buffer to videobuf buffer
+ */
static void em28xx_copy_vbi(struct em28xx *dev,
- struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer *buf,
- unsigned char *p,
- unsigned char *outp, unsigned long len)
+ struct em28xx_buffer *buf,
+ unsigned char *usb_buf,
+ unsigned long len)
{
- void *startwrite, *startread;
- int offset;
- int bytesperline;
-
- if (dev == NULL) {
- em28xx_isocdbg("dev is null\n");
- return;
- }
- bytesperline = dev->vbi_width;
+ unsigned int offset;
- if (dma_q == NULL) {
- em28xx_isocdbg("dma_q is null\n");
- return;
- }
- if (buf == NULL) {
- return;
- }
- if (p == NULL) {
- em28xx_isocdbg("p is null\n");
- return;
- }
- if (outp == NULL) {
- em28xx_isocdbg("outp is null\n");
- return;
- }
-
- if (dma_q->pos + len > buf->vb.size)
- len = buf->vb.size - dma_q->pos;
-
- startread = p;
-
- startwrite = outp + dma_q->pos;
- offset = dma_q->pos;
+ if (buf->pos + len > buf->length)
+ len = buf->length - buf->pos;
+ offset = buf->pos;
/* Make sure the bottom field populates the second half of the frame */
- if (buf->top_field == 0) {
- startwrite += bytesperline * dev->vbi_height;
- offset += bytesperline * dev->vbi_height;
- }
+ if (buf->top_field == 0)
+ offset += dev->vbi_width * dev->vbi_height;
- memcpy(startwrite, startread, len);
- dma_q->pos += len;
+ memcpy(buf->vb_buf + offset, usb_buf, len);
+ buf->pos += len;
}
static inline void print_err_status(struct em28xx *dev,
@@ -360,470 +287,444 @@ static inline void print_err_status(struct em28xx *dev,
}
/*
- * video-buf generic routine to get the next available buffer
+ * get the next available buffer from dma queue
*/
-static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer **buf)
+static inline struct em28xx_buffer *get_next_buf(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q)
{
- struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
- char *outp;
+ struct em28xx_buffer *buf;
if (list_empty(&dma_q->active)) {
em28xx_isocdbg("No active queue to serve\n");
- dev->isoc_ctl.vid_buf = NULL;
- *buf = NULL;
- return;
+ return NULL;
}
/* Get the next buffer */
- *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
-
+ buf = list_entry(dma_q->active.next, struct em28xx_buffer, list);
/* Cleans up buffer - Useful for testing for frame/URB loss */
- outp = videobuf_to_vmalloc(&(*buf)->vb);
- memset(outp, 0, (*buf)->vb.size);
+ list_del(&buf->list);
+ buf->pos = 0;
+ buf->vb_buf = buf->mem;
- dev->isoc_ctl.vid_buf = *buf;
-
- return;
+ return buf;
}
/*
- * video-buf generic routine to get the next available VBI buffer
+ * Finish the current buffer if completed and prepare for the next field
*/
-static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q,
- struct em28xx_buffer **buf)
-{
- struct em28xx *dev = container_of(dma_q, struct em28xx, vbiq);
- char *outp;
-
- if (list_empty(&dma_q->active)) {
- em28xx_isocdbg("No active queue to serve\n");
- dev->isoc_ctl.vbi_buf = NULL;
- *buf = NULL;
- return;
+static struct em28xx_buffer *
+finish_field_prepare_next(struct em28xx *dev,
+ struct em28xx_buffer *buf,
+ struct em28xx_dmaqueue *dma_q)
+{
+ if (dev->progressive || dev->top_field) { /* Brand new frame */
+ if (buf != NULL)
+ finish_buffer(dev, buf);
+ buf = get_next_buf(dev, dma_q);
+ }
+ if (buf != NULL) {
+ buf->top_field = dev->top_field;
+ buf->pos = 0;
}
- /* Get the next buffer */
- *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
- /* Cleans up buffer - Useful for testing for frame/URB loss */
- outp = videobuf_to_vmalloc(&(*buf)->vb);
- memset(outp, 0x00, (*buf)->vb.size);
-
- dev->isoc_ctl.vbi_buf = *buf;
-
- return;
+ return buf;
}
/*
- * Controls the isoc copy of each urb packet
+ * Process data packet according to the em2710/em2750/em28xx frame data format
*/
-static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
+static inline void process_frame_data_em28xx(struct em28xx *dev,
+ unsigned char *data_pkt,
+ unsigned int data_len)
{
- struct em28xx_buffer *buf;
+ struct em28xx_buffer *buf = dev->usb_ctl.vid_buf;
+ struct em28xx_buffer *vbi_buf = dev->usb_ctl.vbi_buf;
struct em28xx_dmaqueue *dma_q = &dev->vidq;
- unsigned char *outp = NULL;
- int i, len = 0, rc = 1;
- unsigned char *p;
-
- if (!dev)
- return 0;
-
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
- return 0;
-
- if (urb->status < 0) {
- print_err_status(dev, -1, urb->status);
- if (urb->status == -ENOENT)
- return 0;
- }
-
- buf = dev->isoc_ctl.vid_buf;
- if (buf != NULL)
- outp = videobuf_to_vmalloc(&buf->vb);
-
- for (i = 0; i < urb->number_of_packets; i++) {
- int status = urb->iso_frame_desc[i].status;
+ struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
- if (status < 0) {
- print_err_status(dev, i, status);
- if (urb->iso_frame_desc[i].status != -EPROTO)
- continue;
+ /* capture type 0 = vbi start
+ capture type 1 = vbi in progress
+ capture type 2 = video start
+ capture type 3 = video in progress */
+ if (data_len >= 4) {
+ /* NOTE: Headers are always 4 bytes and
+ * never split across packets */
+ if (data_pkt[0] == 0x88 && data_pkt[1] == 0x88 &&
+ data_pkt[2] == 0x88 && data_pkt[3] == 0x88) {
+ /* Continuation */
+ data_pkt += 4;
+ data_len -= 4;
+ } else if (data_pkt[0] == 0x33 && data_pkt[1] == 0x95) {
+ /* Field start (VBI mode) */
+ dev->capture_type = 0;
+ dev->vbi_read = 0;
+ em28xx_isocdbg("VBI START HEADER !!!\n");
+ dev->top_field = !(data_pkt[2] & 1);
+ data_pkt += 4;
+ data_len -= 4;
+ } else if (data_pkt[0] == 0x22 && data_pkt[1] == 0x5a) {
+ /* Field start (VBI disabled) */
+ dev->capture_type = 2;
+ em28xx_isocdbg("VIDEO START HEADER !!!\n");
+ dev->top_field = !(data_pkt[2] & 1);
+ data_pkt += 4;
+ data_len -= 4;
}
+ }
+ /* NOTE: With bulk transfers, intermediate data packets
+ * have no continuation header */
- len = urb->iso_frame_desc[i].actual_length - 4;
+ if (dev->capture_type == 0) {
+ vbi_buf = finish_field_prepare_next(dev, vbi_buf, vbi_dma_q);
+ dev->usb_ctl.vbi_buf = vbi_buf;
+ dev->capture_type = 1;
+ }
- if (urb->iso_frame_desc[i].actual_length <= 0) {
- /* em28xx_isocdbg("packet %d is empty",i); - spammy */
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length >
- dev->max_pkt_size) {
- em28xx_isocdbg("packet bigger than packet size");
- continue;
- }
+ if (dev->capture_type == 1) {
+ int vbi_size = dev->vbi_width * dev->vbi_height;
+ int vbi_data_len = ((dev->vbi_read + data_len) > vbi_size) ?
+ (vbi_size - dev->vbi_read) : data_len;
- p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ /* Copy VBI data */
+ if (vbi_buf != NULL)
+ em28xx_copy_vbi(dev, vbi_buf, data_pkt, vbi_data_len);
+ dev->vbi_read += vbi_data_len;
- /* FIXME: incomplete buffer checks where removed to make
- logic simpler. Impacts of those changes should be evaluated
- */
- if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
- em28xx_isocdbg("VBI HEADER!!!\n");
- /* FIXME: Should add vbi copy */
- continue;
+ if (vbi_data_len < data_len) {
+ /* Continue with copying video data */
+ dev->capture_type = 2;
+ data_pkt += vbi_data_len;
+ data_len -= vbi_data_len;
}
- if (p[0] == 0x22 && p[1] == 0x5a) {
- em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
- len, (p[2] & 1) ? "odd" : "even");
-
- if (dev->progressive || !(p[2] & 1)) {
- if (buf != NULL)
- buffer_filled(dev, dma_q, buf);
- get_next_buf(dma_q, &buf);
- if (buf == NULL)
- outp = NULL;
- else
- outp = videobuf_to_vmalloc(&buf->vb);
- }
-
- if (buf != NULL) {
- if (p[2] & 1)
- buf->top_field = 0;
- else
- buf->top_field = 1;
- }
+ }
- dma_q->pos = 0;
- }
- if (buf != NULL) {
- if (p[0] != 0x88 && p[0] != 0x22) {
- em28xx_isocdbg("frame is not complete\n");
- len += 4;
- } else {
- p += 4;
- }
- em28xx_copy_video(dev, dma_q, buf, p, outp, len);
- }
+ if (dev->capture_type == 2) {
+ buf = finish_field_prepare_next(dev, buf, dma_q);
+ dev->usb_ctl.vid_buf = buf;
+ dev->capture_type = 3;
}
- return rc;
+
+ if (dev->capture_type == 3 && buf != NULL && data_len > 0)
+ em28xx_copy_video(dev, buf, data_pkt, data_len);
}
-/* Version of isoc handler that takes into account a mixture of video and
- VBI data */
-static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
+/* Processes and copies the URB data content (video and VBI data) */
+static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
{
- struct em28xx_buffer *buf, *vbi_buf;
- struct em28xx_dmaqueue *dma_q = &dev->vidq;
- struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
- unsigned char *outp = NULL;
- unsigned char *vbioutp = NULL;
- int i, len = 0, rc = 1;
- unsigned char *p;
- int vbi_size;
+ int xfer_bulk, num_packets, i;
+ unsigned char *usb_data_pkt;
+ unsigned int usb_data_len;
if (!dev)
return 0;
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ if (dev->disconnected)
return 0;
- if (urb->status < 0) {
+ if (urb->status < 0)
print_err_status(dev, -1, urb->status);
- if (urb->status == -ENOENT)
- return 0;
- }
- buf = dev->isoc_ctl.vid_buf;
- if (buf != NULL)
- outp = videobuf_to_vmalloc(&buf->vb);
+ xfer_bulk = usb_pipebulk(urb->pipe);
- vbi_buf = dev->isoc_ctl.vbi_buf;
- if (vbi_buf != NULL)
- vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+ if (xfer_bulk) /* bulk */
+ num_packets = 1;
+ else /* isoc */
+ num_packets = urb->number_of_packets;
- for (i = 0; i < urb->number_of_packets; i++) {
- int status = urb->iso_frame_desc[i].status;
+ for (i = 0; i < num_packets; i++) {
+ if (xfer_bulk) { /* bulk */
+ usb_data_len = urb->actual_length;
- if (status < 0) {
- print_err_status(dev, i, status);
- if (urb->iso_frame_desc[i].status != -EPROTO)
+ usb_data_pkt = urb->transfer_buffer;
+ } else { /* isoc */
+ if (urb->iso_frame_desc[i].status < 0) {
+ print_err_status(dev, i,
+ urb->iso_frame_desc[i].status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ usb_data_len = urb->iso_frame_desc[i].actual_length;
+ if (usb_data_len > dev->max_pkt_size) {
+ em28xx_isocdbg("packet bigger than packet size");
continue;
- }
+ }
- len = urb->iso_frame_desc[i].actual_length;
- if (urb->iso_frame_desc[i].actual_length <= 0) {
- /* em28xx_isocdbg("packet %d is empty",i); - spammy */
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length >
- dev->max_pkt_size) {
- em28xx_isocdbg("packet bigger than packet size");
- continue;
+ usb_data_pkt = urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset;
}
- p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- /* capture type 0 = vbi start
- capture type 1 = video start
- capture type 2 = video in progress */
- if (p[0] == 0x33 && p[1] == 0x95) {
- dev->capture_type = 0;
- dev->vbi_read = 0;
- em28xx_isocdbg("VBI START HEADER!!!\n");
- dev->cur_field = p[2];
- p += 4;
- len -= 4;
- } else if (p[0] == 0x88 && p[1] == 0x88 &&
- p[2] == 0x88 && p[3] == 0x88) {
- /* continuation */
- p += 4;
- len -= 4;
- } else if (p[0] == 0x22 && p[1] == 0x5a) {
- /* start video */
- p += 4;
- len -= 4;
+ if (usb_data_len == 0) {
+ /* NOTE: happens very often with isoc transfers */
+ /* em28xx_usbdbg("packet %d is empty",i); - spammy */
+ continue;
}
- vbi_size = dev->vbi_width * dev->vbi_height;
-
- if (dev->capture_type == 0) {
- if (dev->vbi_read >= vbi_size) {
- /* We've already read all the VBI data, so
- treat the rest as video */
- em28xx_isocdbg("dev->vbi_read > vbi_size\n");
- } else if ((dev->vbi_read + len) < vbi_size) {
- /* This entire frame is VBI data */
- if (dev->vbi_read == 0 &&
- (!(dev->cur_field & 1))) {
- /* Brand new frame */
- if (vbi_buf != NULL)
- vbi_buffer_filled(dev,
- vbi_dma_q,
- vbi_buf);
- vbi_get_next_buf(vbi_dma_q, &vbi_buf);
- if (vbi_buf == NULL)
- vbioutp = NULL;
- else
- vbioutp = videobuf_to_vmalloc(
- &vbi_buf->vb);
- }
-
- if (dev->vbi_read == 0) {
- vbi_dma_q->pos = 0;
- if (vbi_buf != NULL) {
- if (dev->cur_field & 1)
- vbi_buf->top_field = 0;
- else
- vbi_buf->top_field = 1;
- }
- }
-
- dev->vbi_read += len;
- em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
- vbioutp, len);
- } else {
- /* Some of this frame is VBI data and some is
- video data */
- int vbi_data_len = vbi_size - dev->vbi_read;
- dev->vbi_read += vbi_data_len;
- em28xx_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
- vbioutp, vbi_data_len);
- dev->capture_type = 1;
- p += vbi_data_len;
- len -= vbi_data_len;
- }
- }
+ process_frame_data_em28xx(dev, usb_data_pkt, usb_data_len);
+ }
+ return 1;
+}
- if (dev->capture_type == 1) {
- dev->capture_type = 2;
- if (dev->progressive || !(dev->cur_field & 1)) {
- if (buf != NULL)
- buffer_filled(dev, dma_q, buf);
- get_next_buf(dma_q, &buf);
- if (buf == NULL)
- outp = NULL;
- else
- outp = videobuf_to_vmalloc(&buf->vb);
- }
- if (buf != NULL) {
- if (dev->cur_field & 1)
- buf->top_field = 0;
- else
- buf->top_field = 1;
- }
- dma_q->pos = 0;
- }
+static int get_ressource(enum v4l2_buf_type f_type)
+{
+ switch (f_type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return EM28XX_RESOURCE_VIDEO;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return EM28XX_RESOURCE_VBI;
+ default:
+ BUG();
+ return 0;
+ }
+}
- if (buf != NULL && dev->capture_type == 2) {
- if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 &&
- p[2] == 0x88 && p[3] == 0x88) {
- p += 4;
- len -= 4;
- }
- if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) {
- em28xx_isocdbg("Video frame %d, len=%i, %s\n",
- p[2], len, (p[2] & 1) ?
- "odd" : "even");
- p += 4;
- len -= 4;
- }
+/* Usage lock check functions */
+static int res_get(struct em28xx *dev, enum v4l2_buf_type f_type)
+{
+ int res_type = get_ressource(f_type);
- if (len > 0)
- em28xx_copy_video(dev, dma_q, buf, p, outp,
- len);
- }
+ /* is it free? */
+ if (dev->resources & res_type) {
+ /* no, someone else uses it */
+ return -EBUSY;
}
- return rc;
+
+ /* it's free, grab it */
+ dev->resources |= res_type;
+ em28xx_videodbg("res: get %d\n", res_type);
+ return 0;
}
+static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type)
+{
+ int res_type = get_ressource(f_type);
+
+ dev->resources &= ~res_type;
+ em28xx_videodbg("res: put %d\n", res_type);
+}
/* ------------------------------------------------------------------
- Videobuf operations
+ Videobuf2 operations
------------------------------------------------------------------*/
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx *dev = fh->dev;
- struct v4l2_frequency f;
+ struct em28xx *dev = vb2_get_drv_priv(vq);
+ unsigned long size;
- *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)
- >> 3;
-
- if (0 == *count)
- *count = EM28XX_DEF_BUF;
+ if (fmt)
+ size = fmt->fmt.pix.sizeimage;
+ else
+ size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
- if (*count < EM28XX_MIN_BUF)
- *count = EM28XX_MIN_BUF;
+ if (size == 0)
+ return -EINVAL;
- /* Ask tuner to go to analog or radio mode */
- memset(&f, 0, sizeof(f));
- f.frequency = dev->ctl_freq;
- f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ if (0 == *nbuffers)
+ *nbuffers = 32;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+ *nplanes = 1;
+ sizes[0] = size;
return 0;
}
-/* This is called *without* dev->slock held; please keep it that way */
-static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+static int
+buffer_prepare(struct vb2_buffer *vb)
{
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx *dev = fh->dev;
- unsigned long flags = 0;
- if (in_interrupt())
- BUG();
+ struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ unsigned long size;
- /* We used to wait for the buffer to finish here, but this didn't work
- because, as we were keeping the state as VIDEOBUF_QUEUED,
- videobuf_queue_cancel marked it as finished for us.
- (Also, it could wedge forever if the hardware was misconfigured.)
+ em28xx_videodbg("%s, field=%d\n", __func__, vb->v4l2_buf.field);
- This should be safe; by the time we get here, the buffer isn't
- queued anymore. If we ever start marking the buffers as
- VIDEOBUF_ACTIVE, it won't be, though.
- */
- spin_lock_irqsave(&dev->slock, flags);
- if (dev->isoc_ctl.vid_buf == buf)
- dev->isoc_ctl.vid_buf = NULL;
- spin_unlock_irqrestore(&dev->slock, flags);
+ size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ if (vb2_plane_size(vb, 0) < size) {
+ em28xx_videodbg("%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(&buf->vb, 0, size);
+
+ return 0;
}
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
+int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
- struct em28xx *dev = fh->dev;
- int rc = 0, urb_init = 0;
+ struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct v4l2_frequency f;
+ int rc = 0;
- buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
- + 7) >> 3;
+ em28xx_videodbg("%s\n", __func__);
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
+ /* Make sure streaming is not already in progress for this type
+ of filehandle (e.g. video, vbi) */
+ rc = res_get(dev, vq->type);
+ if (rc)
+ return rc;
+
+ if (dev->streaming_users++ == 0) {
+ /* First active streaming user, so allocate all the URBs */
- buf->vb.width = dev->width;
- buf->vb.height = dev->height;
- buf->vb.field = field;
+ /* Allocate the USB bandwidth */
+ em28xx_set_alternate(dev);
+
+ /* Needed, since GPIO might have disabled power of
+ some i2c device
+ */
+ em28xx_wake_i2c(dev);
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
+ dev->capture_type = -1;
+ rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE,
+ dev->analog_xfer_bulk,
+ EM28XX_NUM_BUFS,
+ dev->max_pkt_size,
+ dev->packet_multiplier,
+ em28xx_urb_data_copy);
if (rc < 0)
goto fail;
- }
- if (!dev->isoc_ctl.analog_bufs.num_bufs)
- urb_init = 1;
+ /*
+ * djh: it's not clear whether this code is still needed. I'm
+ * leaving it in here for now entirely out of concern for
+ * backward compatibility (the old code did it)
+ */
- if (urb_init) {
- if (em28xx_vbi_supported(dev) == 1)
- rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
- EM28XX_NUM_PACKETS,
- EM28XX_NUM_BUFS,
- dev->max_pkt_size,
- em28xx_isoc_copy_vbi);
+ /* Ask tuner to go to analog or radio mode */
+ memset(&f, 0, sizeof(f));
+ f.frequency = dev->ctl_freq;
+ if (vq->owner && vq->owner->vdev->vfl_type == VFL_TYPE_RADIO)
+ f.type = V4L2_TUNER_RADIO;
else
- rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
- EM28XX_NUM_PACKETS,
- EM28XX_NUM_BUFS,
- dev->max_pkt_size,
- em28xx_isoc_copy);
- if (rc < 0)
- goto fail;
+ f.type = V4L2_TUNER_ANALOG_TV;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
}
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-
fail:
- free_buffer(vq, buf);
return rc;
}
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static int em28xx_stop_streaming(struct vb2_queue *vq)
{
- struct em28xx_buffer *buf = container_of(vb,
- struct em28xx_buffer,
- vb);
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx *dev = fh->dev;
- struct em28xx_dmaqueue *vidq = &dev->vidq;
+ struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_dmaqueue *vidq = &dev->vidq;
+ unsigned long flags = 0;
+
+ em28xx_videodbg("%s\n", __func__);
+
+ res_free(dev, vq->type);
+
+ if (dev->streaming_users-- == 1) {
+ /* Last active user, so shutdown all the URBS */
+ em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
+ }
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&vidq->active)) {
+ struct em28xx_buffer *buf;
+ buf = list_entry(vidq->active.next, struct em28xx_buffer, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ dev->usb_ctl.vid_buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+ return 0;
}
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
+int em28xx_stop_vbi_streaming(struct vb2_queue *vq)
{
- struct em28xx_buffer *buf = container_of(vb,
- struct em28xx_buffer,
- vb);
- struct em28xx_fh *fh = vq->priv_data;
- struct em28xx *dev = (struct em28xx *)fh->dev;
+ struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_dmaqueue *vbiq = &dev->vbiq;
+ unsigned long flags = 0;
+
+ em28xx_videodbg("%s\n", __func__);
- em28xx_isocdbg("em28xx: called buffer_release\n");
+ res_free(dev, vq->type);
- free_buffer(vq, buf);
+ if (dev->streaming_users-- == 1) {
+ /* Last active user, so shutdown all the URBS */
+ em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
+ }
+
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&vbiq->active)) {
+ struct em28xx_buffer *buf;
+ buf = list_entry(vbiq->active.next, struct em28xx_buffer, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ dev->usb_ctl.vbi_buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ return 0;
}
-static struct videobuf_queue_ops em28xx_video_qops = {
- .buf_setup = buffer_setup,
+static void
+buffer_queue(struct vb2_buffer *vb)
+{
+ struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx_dmaqueue *vidq = &dev->vidq;
+ unsigned long flags = 0;
+
+ em28xx_videodbg("%s\n", __func__);
+ buf->mem = vb2_plane_vaddr(vb, 0);
+ buf->length = vb2_plane_size(vb, 0);
+
+ spin_lock_irqsave(&dev->slock, flags);
+ list_add_tail(&buf->list, &vidq->active);
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+static struct vb2_ops em28xx_video_qops = {
+ .queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
- .buf_release = buffer_release,
+ .start_streaming = em28xx_start_analog_streaming,
+ .stop_streaming = em28xx_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
+int em28xx_vb2_setup(struct em28xx *dev)
+{
+ int rc;
+ struct vb2_queue *q;
+
+ /* Setup Videobuf2 for Video capture */
+ q = &dev->vb_vidq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct em28xx_buffer);
+ q->ops = &em28xx_video_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+
+ rc = vb2_queue_init(q);
+ if (rc < 0)
+ return rc;
+
+ /* Setup Videobuf2 for VBI capture */
+ q = &dev->vb_vbiq;
+ q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct em28xx_buffer);
+ q->ops = &em28xx_vbi_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+
+ rc = vb2_queue_init(q);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
/********************* v4l2 interface **************************************/
static void video_mux(struct em28xx *dev, int index)
@@ -856,143 +757,54 @@ static void video_mux(struct em28xx *dev, int index)
em28xx_audio_analog_set(dev);
}
-/* Usage lock check functions */
-static int res_get(struct em28xx_fh *fh, unsigned int bit)
-{
- struct em28xx *dev = fh->dev;
-
- if (fh->resources & bit)
- /* have it already allocated */
- return 1;
-
- /* is it free? */
- if (dev->resources & bit) {
- /* no, someone else uses it */
- return 0;
- }
- /* it's free, grab it */
- fh->resources |= bit;
- dev->resources |= bit;
- em28xx_videodbg("res: get %d\n", bit);
- return 1;
-}
-
-static int res_check(struct em28xx_fh *fh, unsigned int bit)
-{
- return fh->resources & bit;
-}
-
-static int res_locked(struct em28xx *dev, unsigned int bit)
-{
- return dev->resources & bit;
-}
-
-static void res_free(struct em28xx_fh *fh, unsigned int bits)
+void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
{
- struct em28xx *dev = fh->dev;
-
- BUG_ON((fh->resources & bits) != bits);
-
- fh->resources &= ~bits;
- dev->resources &= ~bits;
- em28xx_videodbg("res: put %d\n", bits);
-}
-
-static int get_ressource(struct em28xx_fh *fh)
-{
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- return EM28XX_RESOURCE_VIDEO;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- return EM28XX_RESOURCE_VBI;
- default:
- BUG();
- return 0;
- }
-}
-
-/*
- * ac97_queryctrl()
- * return the ac97 supported controls
- */
-static int ac97_queryctrl(struct v4l2_queryctrl *qc)
-{
- int i;
+ struct em28xx *dev = priv;
- for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
- if (qc->id && qc->id == ac97_qctrl[i].id) {
- memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
- return 0;
- }
- }
-
- /* Control is not ac97 related */
- return 1;
-}
-
-/*
- * ac97_get_ctrl()
- * return the current values for ac97 mute and volume
- */
-static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
-{
+ /*
+ * In the case of non-AC97 volume controls, we still need
+ * to do some setups at em28xx, in order to mute/unmute
+ * and to adjust audio volume. However, the value ranges
+ * should be checked by the corresponding V4L subdriver.
+ */
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- ctrl->value = dev->mute;
- return 0;
+ dev->mute = ctrl->val;
+ em28xx_audio_analog_set(dev);
+ break;
case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = dev->volume;
- return 0;
- default:
- /* Control is not ac97 related */
- return 1;
+ dev->volume = ctrl->val;
+ em28xx_audio_analog_set(dev);
+ break;
}
}
-/*
- * ac97_set_ctrl()
- * set values for ac97 mute and volume
- */
-static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
- if (ctrl->id == ac97_qctrl[i].id)
- goto handle;
-
- /* Announce that hasn't handle it */
- return 1;
-
-handle:
- if (ctrl->value < ac97_qctrl[i].minimum ||
- ctrl->value > ac97_qctrl[i].maximum)
- return -ERANGE;
+ struct em28xx *dev = container_of(ctrl->handler, struct em28xx, ctrl_handler);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- dev->mute = ctrl->value;
+ dev->mute = ctrl->val;
break;
case V4L2_CID_AUDIO_VOLUME:
- dev->volume = ctrl->value;
+ dev->volume = ctrl->val;
break;
}
return em28xx_audio_analog_set(dev);
}
+const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
+ .s_ctrl = em28xx_s_ctrl,
+};
+
static int check_dev(struct em28xx *dev)
{
- if (dev->state & DEV_DISCONNECTED) {
+ if (dev->disconnected) {
em28xx_errdev("v4l2 ioctl: device not present\n");
return -ENODEV;
}
-
- if (dev->state & DEV_MISCONFIGURED) {
- em28xx_errdev("v4l2 ioctl: device is misconfigured; "
- "close and open it again\n");
- return -EIO;
- }
return 0;
}
@@ -1072,8 +884,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
/* the em2800 can only scale down to 50% */
height = height > (3 * maxh / 4) ? maxh : maxh / 2;
width = width > (3 * maxw / 4) ? maxw : maxw / 2;
- /* MaxPacketSize for em2800 is too small to capture at full resolution
- * use half of maxw as the scaler can only scale to 50% */
+ /*
+ * MaxPacketSize for em2800 is too small to capture at full
+ * resolution use half of maxw as the scaler can only scale
+ * to 50%
+ */
if (width == maxw && height == maxh)
width /= 2;
} else {
@@ -1091,7 +906,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = width;
f->fmt.pix.height = height;
f->fmt.pix.pixelformat = fmt->fourcc;
- f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+ f->fmt.pix.bytesperline = (width * fmt->depth + 7) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
if (dev->progressive)
@@ -1119,7 +934,6 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
/* set new image size */
get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
- em28xx_set_alternate(dev);
em28xx_resolution_set(dev);
return 0;
@@ -1128,21 +942,13 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
+ struct em28xx *dev = video_drvdata(file);
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
+ if (dev->streaming_users > 0)
+ return -EBUSY;
vidioc_try_fmt_vid_cap(file, priv, f);
- if (videobuf_queue_is_busy(&fh->vb_vidq)) {
- em28xx_errdev("%s queue busy\n", __func__);
- return -EBUSY;
- }
-
return em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
f->fmt.pix.width, f->fmt.pix.height);
}
@@ -1153,6 +959,8 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
struct em28xx *dev = fh->dev;
int rc;
+ if (dev->board.is_webcam)
+ return -ENOTTY;
rc = check_dev(dev);
if (rc < 0)
return rc;
@@ -1168,6 +976,8 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
struct em28xx *dev = fh->dev;
int rc;
+ if (dev->board.is_webcam)
+ return -ENOTTY;
rc = check_dev(dev);
if (rc < 0)
return rc;
@@ -1184,15 +994,22 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
struct v4l2_format f;
int rc;
+ if (dev->board.is_webcam)
+ return -ENOTTY;
+ if (*norm == dev->norm)
+ return 0;
rc = check_dev(dev);
if (rc < 0)
return rc;
+ if (dev->streaming_users > 0)
+ return -EBUSY;
+
dev->norm = *norm;
/* Adjusts width/height, if needed */
- f.fmt.pix.width = dev->width;
- f.fmt.pix.height = dev->height;
+ f.fmt.pix.width = 720;
+ f.fmt.pix.height = (*norm & V4L2_STD_525_60) ? 480 : 576;
vidioc_try_fmt_vid_cap(file, priv, &f);
/* set new image size */
@@ -1216,6 +1033,7 @@ static int vidioc_g_parm(struct file *file, void *priv,
if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ p->parm.capture.readbuffers = EM28XX_MIN_BUF;
if (dev->board.is_webcam)
rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
video, g_parm, p);
@@ -1233,11 +1051,12 @@ static int vidioc_s_parm(struct file *file, void *priv,
struct em28xx *dev = fh->dev;
if (!dev->board.is_webcam)
- return -EINVAL;
+ return -ENOTTY;
if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ p->parm.capture.readbuffers = EM28XX_MIN_BUF;
return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
}
@@ -1276,6 +1095,9 @@ static int vidioc_enum_input(struct file *file, void *priv,
i->type = V4L2_INPUT_TYPE_TUNER;
i->std = dev->vdev->tvnorms;
+ /* webcams do not have the STD API */
+ if (dev->board.is_webcam)
+ i->capabilities = 0;
return 0;
}
@@ -1375,131 +1197,6 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int id = qc->id;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- memset(qc, 0, sizeof(*qc));
-
- qc->id = id;
-
- /* enumerate AC97 controls */
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
- rc = ac97_queryctrl(qc);
- if (!rc)
- return 0;
- }
-
- /* enumerate V4L2 device controls */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
-
- if (qc->type)
- return 0;
- else
- return -EINVAL;
-}
-
-/*
- * FIXME: This is an indirect way to check if a control exists at a
- * subdev. Instead of that hack, maybe the better would be to change all
- * subdevs to return -ENOIOCTLCMD, if an ioctl is not supported.
- */
-static int check_subdev_ctrl(struct em28xx *dev, int id)
-{
- struct v4l2_queryctrl qc;
-
- memset(&qc, 0, sizeof(qc));
- qc.id = id;
-
- /* enumerate V4L2 device controls */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc);
-
- if (qc.type)
- return 0;
- else
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
- rc = 0;
-
- /* Set an AC97 control */
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
- rc = ac97_get_ctrl(dev, ctrl);
- else
- rc = 1;
-
- /* It were not an AC97 control. Sends it to the v4l2 dev interface */
- if (rc == 1) {
- if (check_subdev_ctrl(dev, ctrl->id))
- return -EINVAL;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
- rc = 0;
- }
-
- return rc;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- /* Set an AC97 control */
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
- rc = ac97_set_ctrl(dev, ctrl);
- else
- rc = 1;
-
- /* It isn't an AC97 control. Sends it to the v4l2 dev interface */
- if (rc == 1) {
- rc = check_subdev_ctrl(dev, ctrl->id);
- if (!rc)
- v4l2_device_call_all(&dev->v4l2_dev, 0,
- core, s_ctrl, ctrl);
- /*
- * In the case of non-AC97 volume controls, we still need
- * to do some setups at em28xx, in order to mute/unmute
- * and to adjust audio volume. However, the value ranges
- * should be checked by the corresponding V4L subdriver.
- */
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- dev->mute = ctrl->value;
- rc = em28xx_audio_analog_set(dev);
- break;
- case V4L2_CID_AUDIO_VOLUME:
- dev->volume = ctrl->value;
- rc = em28xx_audio_analog_set(dev);
- }
- }
- return (rc < 0) ? rc : 0;
-}
-
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
@@ -1515,7 +1212,6 @@ static int vidioc_g_tuner(struct file *file, void *priv,
return -EINVAL;
strcpy(t->name, "Tuner");
- t->type = V4L2_TUNER_ANALOG_TV;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
return 0;
@@ -1545,7 +1241,9 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ if (0 != f->tuner)
+ return -EINVAL;
+
f->frequency = dev->ctl_freq;
return 0;
}
@@ -1564,13 +1262,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
if (0 != f->tuner)
return -EINVAL;
- if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
- return -EINVAL;
- if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
- return -EINVAL;
-
- dev->ctl_freq = f->frequency;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
+ dev->ctl_freq = f->frequency;
return 0;
}
@@ -1596,6 +1290,14 @@ static int vidioc_g_chip_ident(struct file *file, void *priv,
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
+ if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(&chip->match))
+ chip->ident = V4L2_IDENT_NONE;
+ return 0;
+ }
+ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_chip_ident, chip);
@@ -1704,72 +1406,10 @@ static int vidioc_cropcap(struct file *file, void *priv,
return 0;
}
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc = -EINVAL;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (unlikely(type != fh->type))
- return -EINVAL;
-
- em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
- fh, type, fh->resources, dev->resources);
-
- if (unlikely(!res_get(fh, get_ressource(fh))))
- return -EBUSY;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_streamon(&fh->vb_vidq);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_streamon(&fh->vb_vbiq);
-
- return rc;
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
- return -EINVAL;
- if (type != fh->type)
- return -EINVAL;
-
- em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
- fh, type, fh->resources, dev->resources);
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh, EM28XX_RESOURCE_VIDEO);
- }
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (res_check(fh, EM28XX_RESOURCE_VBI)) {
- videobuf_streamoff(&fh->vb_vbiq);
- res_free(fh, EM28XX_RESOURCE_VBI);
- }
- }
-
- return 0;
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
+ struct video_device *vdev = video_devdata(file);
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
@@ -1777,20 +1417,26 @@ static int vidioc_querycap(struct file *file, void *priv,
strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->capabilities =
- V4L2_CAP_SLICED_VBI_CAPTURE |
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-
- if (dev->vbi_dev)
- cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ cap->device_caps = V4L2_CAP_READWRITE |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ else if (vdev->vfl_type == VFL_TYPE_RADIO)
+ cap->device_caps = V4L2_CAP_RADIO;
+ else
+ cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
if (dev->audio_mode.has_audio)
- cap->capabilities |= V4L2_CAP_AUDIO;
+ cap->device_caps |= V4L2_CAP_AUDIO;
if (dev->tuner_type != TUNER_ABSENT)
- cap->capabilities |= V4L2_CAP_TUNER;
+ cap->device_caps |= V4L2_CAP_TUNER;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
+ V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ if (dev->vbi_dev)
+ cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
+ if (dev->radio_dev)
+ cap->capabilities |= V4L2_CAP_RADIO;
return 0;
}
@@ -1845,46 +1491,6 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
return 0;
}
-/* Sliced VBI ioctls */
-static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- f->fmt.sliced.service_set = 0;
- v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
-
- if (f->fmt.sliced.service_set == 0)
- rc = -EINVAL;
-
- return rc;
-}
-
-static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
-
- if (f->fmt.sliced.service_set == 0)
- return -EINVAL;
-
- return 0;
-}
-
/* RAW VBI ioctls */
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
@@ -1900,6 +1506,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
format->fmt.vbi.count[0] = dev->vbi_height;
format->fmt.vbi.count[1] = dev->vbi_height;
+ memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
/* Varies by video standard (NTSC, PAL, etc.) */
if (dev->norm & V4L2_STD_525_60) {
@@ -1928,6 +1535,7 @@ static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
format->fmt.vbi.count[0] = dev->vbi_height;
format->fmt.vbi.count[1] = dev->vbi_height;
+ memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
/* Varies by video standard (NTSC, PAL, etc.) */
if (dev->norm & V4L2_STD_525_60) {
@@ -1943,100 +1551,10 @@ static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *rb)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_reqbufs(&fh->vb_vidq, rb);
- else
- return videobuf_reqbufs(&fh->vb_vbiq, rb);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_querybuf(&fh->vb_vidq, b);
- else {
- /* FIXME: I'm not sure yet whether this is a bug in zvbi or
- the videobuf framework, but we probably shouldn't be
- returning a buffer larger than that which was asked for.
- At a minimum, it causes a crash in zvbi since it does
- a memcpy based on the source buffer length */
- int result = videobuf_querybuf(&fh->vb_vbiq, b);
- b->length = dev->vbi_width * dev->vbi_height * 2;
-
- return result;
- }
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_qbuf(&fh->vb_vidq, b);
- else
- return videobuf_qbuf(&fh->vb_vbiq, b);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags &
- O_NONBLOCK);
- else
- return videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags &
- O_NONBLOCK);
-}
-
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
-static int radio_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
-
- strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
- strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
- cap->capabilities = V4L2_CAP_TUNER;
- return 0;
-}
-
static int radio_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
@@ -2053,26 +1571,6 @@ static int radio_g_tuner(struct file *file, void *priv,
return 0;
}
-static int radio_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- if (i->index != 0)
- return -EINVAL;
- strcpy(i->name, "Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
-
- return 0;
-}
-
-static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- if (unlikely(a->index))
- return -EINVAL;
-
- strcpy(a->name, "Radio");
- return 0;
-}
-
static int radio_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
@@ -2086,48 +1584,16 @@ static int radio_s_tuner(struct file *file, void *priv,
return 0;
}
-static int radio_s_audio(struct file *file, void *fh,
- const struct v4l2_audio *a)
-{
- return 0;
-}
-
-static int radio_s_input(struct file *file, void *fh, unsigned int i)
-{
- return 0;
-}
-
-static int radio_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- int i;
-
- if (qc->id < V4L2_CID_BASE ||
- qc->id >= V4L2_CID_LASTP1)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
- if (qc->id && qc->id == ac97_qctrl[i].id) {
- memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
/*
* em28xx_v4l2_open()
* inits the device and starts isoc transfer
*/
static int em28xx_v4l2_open(struct file *filp)
{
- int errCode = 0, radio = 0;
struct video_device *vdev = video_devdata(filp);
struct em28xx *dev = video_drvdata(filp);
enum v4l2_buf_type fh_type = 0;
struct em28xx_fh *fh;
- enum v4l2_field field;
switch (vdev->vfl_type) {
case VFL_TYPE_GRABBER:
@@ -2136,9 +1602,6 @@ static int em28xx_v4l2_open(struct file *filp)
case VFL_TYPE_VBI:
fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
break;
- case VFL_TYPE_RADIO:
- radio = 1;
- break;
}
em28xx_videodbg("open dev=%s type=%s users=%d\n",
@@ -2154,14 +1617,13 @@ static int em28xx_v4l2_open(struct file *filp)
mutex_unlock(&dev->lock);
return -ENOMEM;
}
+ v4l2_fh_init(&fh->fh, vdev);
fh->dev = dev;
- fh->radio = radio;
fh->type = fh_type;
filp->private_data = fh;
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
- em28xx_set_alternate(dev);
em28xx_resolution_set(dev);
/* Needed, since GPIO might have disabled power of
@@ -2170,31 +1632,18 @@ static int em28xx_v4l2_open(struct file *filp)
em28xx_wake_i2c(dev);
}
- if (fh->radio) {
+
+ if (vdev->vfl_type == VFL_TYPE_RADIO) {
em28xx_videodbg("video_open: setting radio device\n");
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
}
dev->users++;
- if (dev->progressive)
- field = V4L2_FIELD_NONE;
- else
- field = V4L2_FIELD_INTERLACED;
-
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
- NULL, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
- sizeof(struct em28xx_buffer), fh, &dev->lock);
-
- videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
- NULL, &dev->slock,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_FIELD_SEQ_TB,
- sizeof(struct em28xx_buffer), fh, &dev->lock);
mutex_unlock(&dev->lock);
+ v4l2_fh_add(&fh->fh);
- return errCode;
+ return 0;
}
/*
@@ -2248,25 +1697,16 @@ static int em28xx_v4l2_close(struct file *filp)
em28xx_videodbg("users=%d\n", dev->users);
mutex_lock(&dev->lock);
- if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
- videobuf_stop(&fh->vb_vidq);
- res_free(fh, EM28XX_RESOURCE_VIDEO);
- }
-
- if (res_check(fh, EM28XX_RESOURCE_VBI)) {
- videobuf_stop(&fh->vb_vbiq);
- res_free(fh, EM28XX_RESOURCE_VBI);
- }
+ vb2_fop_release(filp);
if (dev->users == 1) {
/* the device is already disconnect,
free the remaining resources */
- if (dev->state & DEV_DISCONNECTED) {
+ if (dev->disconnected) {
em28xx_release_resources(dev);
- kfree(dev->alt_max_pkt_size);
+ kfree(dev->alt_max_pkt_size_isoc);
mutex_unlock(&dev->lock);
kfree(dev);
- kfree(fh);
return 0;
}
@@ -2274,7 +1714,6 @@ static int em28xx_v4l2_close(struct file *filp)
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
/* do this before setting alternate! */
- em28xx_uninit_isoc(dev, EM28XX_ANALOG_MODE);
em28xx_set_mode(dev, EM28XX_SUSPEND);
/* set alternate 0 */
@@ -2287,129 +1726,18 @@ static int em28xx_v4l2_close(struct file *filp)
}
}
- videobuf_mmap_free(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vbiq);
- kfree(fh);
dev->users--;
mutex_unlock(&dev->lock);
return 0;
}
-/*
- * em28xx_v4l2_read()
- * will allocate buffers when called for the first time
- */
-static ssize_t
-em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
- loff_t *pos)
-{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- /* FIXME: read() is not prepared to allow changing the video
- resolution while streaming. Seems a bug at em28xx_set_fmt
- */
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
- rc = -EBUSY;
- else
- rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (!res_get(fh, EM28XX_RESOURCE_VBI))
- rc = -EBUSY;
- else
- rc = videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- }
- mutex_unlock(&dev->lock);
-
- return rc;
-}
-
-/*
- * em28xx_poll()
- * will allocate buffers when called for the first time
- */
-static unsigned int em28xx_poll(struct file *filp, poll_table *wait)
-{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
- return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (!res_get(fh, EM28XX_RESOURCE_VBI))
- return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
- } else {
- return POLLERR;
- }
-}
-
-static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
-{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
- unsigned int res;
-
- mutex_lock(&dev->lock);
- res = em28xx_poll(filp, wait);
- mutex_unlock(&dev->lock);
- return res;
-}
-
-/*
- * em28xx_v4l2_mmap()
- */
-static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
- mutex_unlock(&dev->lock);
-
- em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
- rc);
-
- return rc;
-}
-
static const struct v4l2_file_operations em28xx_v4l_fops = {
.owner = THIS_MODULE,
.open = em28xx_v4l2_open,
.release = em28xx_v4l2_close,
- .read = em28xx_v4l2_read,
- .poll = em28xx_v4l2_poll,
- .mmap = em28xx_v4l2_mmap,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
.unlocked_ioctl = video_ioctl2,
};
@@ -2420,19 +1748,20 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_cropcap = vidioc_cropcap,
- .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
- .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
- .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
-
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+
.vidioc_g_std = vidioc_g_std,
.vidioc_querystd = vidioc_querystd,
.vidioc_s_std = vidioc_s_std,
@@ -2441,15 +1770,14 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
@@ -2459,11 +1787,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
static const struct video_device em28xx_video_template = {
.fops = &em28xx_v4l_fops,
- .release = video_device_release,
+ .release = video_device_release_empty,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
- .current_norm = V4L2_STD_PAL,
};
static const struct v4l2_file_operations radio_fops = {
@@ -2474,18 +1801,13 @@ static const struct v4l2_file_operations radio_fops = {
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
- .vidioc_querycap = radio_querycap,
+ .vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = radio_g_tuner,
- .vidioc_enum_input = radio_enum_input,
- .vidioc_g_audio = radio_g_audio,
.vidioc_s_tuner = radio_s_tuner,
- .vidioc_s_audio = radio_s_audio,
- .vidioc_s_input = radio_s_input,
- .vidioc_queryctrl = radio_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
@@ -2514,9 +1836,11 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->release = video_device_release;
vfd->debug = video_debug;
vfd->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+ if (dev->board.is_webcam)
+ vfd->tvnorms = 0;
snprintf(vfd->name, sizeof(vfd->name), "%s %s",
dev->name, type_name);
@@ -2527,7 +1851,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
int em28xx_register_analog_devices(struct em28xx *dev)
{
- u8 val;
+ u8 val;
int ret;
unsigned int maxw;
@@ -2535,7 +1859,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
dev->name, EM28XX_VERSION);
/* set default norm */
- dev->norm = em28xx_video_template.current_norm;
+ dev->norm = V4L2_STD_PAL;
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
dev->interlaced = EM28XX_INTERLACED_DEFAULT;
@@ -2543,10 +1867,10 @@ int em28xx_register_analog_devices(struct em28xx *dev)
dev->format = &format[0];
maxw = norm_maxw(dev);
- /* MaxPacketSize for em2800 is too small to capture at full resolution
- * use half of maxw as the scaler can only scale to 50% */
- if (dev->board.is_em2800)
- maxw /= 2;
+ /* MaxPacketSize for em2800 is too small to capture at full resolution
+ * use half of maxw as the scaler can only scale to 50% */
+ if (dev->board.is_em2800)
+ maxw /= 2;
em28xx_set_video_format(dev, format[0].fourcc,
maxw, norm_maxh(dev));
@@ -2572,6 +1896,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
em28xx_errdev("cannot allocate video_device.\n");
return -ENODEV;
}
+ dev->vdev->queue = &dev->vb_vidq;
+ dev->vdev->queue->lock = &dev->vb_queue_lock;
/* register v4l2 video video_device */
ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
@@ -2587,6 +1913,9 @@ int em28xx_register_analog_devices(struct em28xx *dev)
dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
"vbi");
+ dev->vbi_dev->queue = &dev->vb_vbiq;
+ dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock;
+
/* register v4l2 vbi video_device */
ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 86e90d86da6d..5f0b2c59e846 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -4,6 +4,7 @@
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
Mauro Carvalho Chehab <mchehab@infradead.org>
+ Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
@@ -30,13 +31,12 @@
#include <linux/mutex.h>
#include <linux/videodev2.h>
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
#include <media/ir-kbd-i2c.h>
#include <media/rc-core.h>
-#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
-#include <media/videobuf-dvb.h>
-#endif
#include "tuner-xc2028.h"
#include "xc5000.h"
#include "em28xx-reg.h"
@@ -157,12 +157,18 @@
#define EM28XX_NUM_BUFS 5
#define EM28XX_DVB_NUM_BUFS 5
-/* number of packets for each buffer
+/* isoc transfers: number of packets for each buffer
windows requests only 64 packets .. so we better do the same
this is what I found out for all alternate numbers there!
*/
-#define EM28XX_NUM_PACKETS 64
-#define EM28XX_DVB_MAX_PACKETS 64
+#define EM28XX_NUM_ISOC_PACKETS 64
+#define EM28XX_DVB_NUM_ISOC_PACKETS 64
+
+/* bulk transfers: transfer buffer size = packet size * packet multiplier
+ USB 2.0 spec says bulk packet size is always 512 bytes
+ */
+#define EM28XX_BULK_PACKET_MULTIPLIER 384
+#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384
#define EM28XX_INTERLACED_DEFAULT 1
@@ -187,12 +193,8 @@
Interval: 125us
*/
-/* time to wait when stopping the isoc transfer */
-#define EM28XX_URB_TIMEOUT \
- msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS)
-
/* time in msecs to wait for i2c writes to finish */
-#define EM2800_I2C_WRITE_TIMEOUT 20
+#define EM2800_I2C_XFER_TIMEOUT 20
enum em28xx_mode {
EM28XX_SUSPEND,
@@ -203,7 +205,7 @@ enum em28xx_mode {
struct em28xx;
-struct em28xx_usb_isoc_bufs {
+struct em28xx_usb_bufs {
/* max packet size of isoc transaction */
int max_pkt_size;
@@ -213,26 +215,26 @@ struct em28xx_usb_isoc_bufs {
/* number of allocated urbs */
int num_bufs;
- /* urb for isoc transfers */
+ /* urb for isoc/bulk transfers */
struct urb **urb;
- /* transfer buffers for isoc transfer */
+ /* transfer buffers for isoc/bulk transfer */
char **transfer_buffer;
};
-struct em28xx_usb_isoc_ctl {
- /* isoc transfer buffers for analog mode */
- struct em28xx_usb_isoc_bufs analog_bufs;
+struct em28xx_usb_ctl {
+ /* isoc/bulk transfer buffers for analog mode */
+ struct em28xx_usb_bufs analog_bufs;
- /* isoc transfer buffers for digital mode */
- struct em28xx_usb_isoc_bufs digital_bufs;
+ /* isoc/bulk transfer buffers for digital mode */
+ struct em28xx_usb_bufs digital_bufs;
/* Stores already requested buffers */
struct em28xx_buffer *vid_buf;
struct em28xx_buffer *vbi_buf;
- /* isoc urb callback */
- int (*isoc_copy) (struct em28xx *dev, struct urb *urb);
+ /* copy data from URB */
+ int (*urb_data_copy) (struct em28xx *dev, struct urb *urb);
};
@@ -247,19 +249,26 @@ struct em28xx_fmt {
/* buffer for one video frame */
struct em28xx_buffer {
/* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
+ struct vb2_buffer vb;
+ struct list_head list;
- struct list_head frame;
+ void *mem;
+ unsigned int length;
int top_field;
+
+ /* counter to control buffer fill */
+ unsigned int pos;
+ /* NOTE; in interlaced mode, this value is reset to zero at
+ * the start of each new field (not frame !) */
+
+ /* pointer to vmalloc memory address in vb */
+ char *vb_buf;
};
struct em28xx_dmaqueue {
struct list_head active;
wait_queue_head_t wq;
-
- /* Counters to control buffer fill */
- int pos;
};
/* inputs */
@@ -430,13 +439,6 @@ struct em28xx_eeprom {
u8 string_idx_table;
};
-/* device states */
-enum em28xx_dev_state {
- DEV_INITIALIZED = 0x01,
- DEV_DISCONNECTED = 0x02,
- DEV_MISCONFIGURED = 0x04,
-};
-
#define EM28XX_AUDIO_BUFS 5
#define EM28XX_NUM_AUDIO_PACKETS 64
#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
@@ -469,12 +471,8 @@ struct em28xx_audio {
struct em28xx;
struct em28xx_fh {
+ struct v4l2_fh fh;
struct em28xx *dev;
- int radio;
- unsigned int resources;
-
- struct videobuf_queue vb_vidq;
- struct videobuf_queue vb_vbiq;
enum v4l2_buf_type type;
};
@@ -487,9 +485,14 @@ struct em28xx {
int devno; /* marks the number of this device */
enum em28xx_chip_id chip_id;
+ unsigned char disconnected:1; /* device has been diconnected */
+
int audio_ifnum;
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
+ /* provides ac97 mute and volume overrides */
+ struct v4l2_ctrl_handler ac97_ctrl_handler;
struct em28xx_board board;
/* Webcam specific fields */
@@ -497,7 +500,7 @@ struct em28xx {
int sensor_xres, sensor_yres;
int sensor_xtal;
- /* Allows progressive (e. g. non-interlaced) mode */
+ /* Progressive (non-interlaced) mode */
int progressive;
/* Vinmode/Vinctl used at the driver */
@@ -532,6 +535,7 @@ struct em28xx {
struct i2c_client i2c_client;
/* video for linux */
int users; /* user count for exclusive use */
+ int streaming_users; /* Number of actively streaming users */
struct video_device *vdev; /* video for linux device struct */
v4l2_std_id norm; /* selected tv norm */
int ctl_freq; /* selected frequency */
@@ -554,13 +558,10 @@ struct em28xx {
struct em28xx_audio adev;
- /* states */
- enum em28xx_dev_state state;
-
- /* vbi related state tracking */
+ /* capture state tracking */
int capture_type;
+ unsigned char top_field:1;
int vbi_read;
- unsigned char cur_field;
unsigned int vbi_width;
unsigned int vbi_height; /* lines per field */
@@ -574,6 +575,12 @@ struct em28xx {
struct video_device *vbi_dev;
struct video_device *radio_dev;
+ /* Videobuf2 */
+ struct vb2_queue vb_vidq;
+ struct vb2_queue vb_vbiq;
+ struct mutex vb_queue_lock;
+ struct mutex vb_vbi_queue_lock;
+
/* resources in use */
unsigned int resources;
@@ -582,17 +589,31 @@ struct em28xx {
/* Isoc control struct */
struct em28xx_dmaqueue vidq;
struct em28xx_dmaqueue vbiq;
- struct em28xx_usb_isoc_ctl isoc_ctl;
+ struct em28xx_usb_ctl usb_ctl;
spinlock_t slock;
+ unsigned int field_count;
+ unsigned int vbi_field_count;
+
/* usb transfer */
struct usb_device *udev; /* the usb device */
- int alt; /* alternate */
- int max_pkt_size; /* max packet size of isoc transaction */
- int num_alt; /* Number of alternative settings */
- unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
- int dvb_alt; /* alternate for DVB */
- unsigned int dvb_max_pkt_size; /* wMaxPacketSize for DVB */
+ u8 analog_ep_isoc; /* address of isoc endpoint for analog */
+ u8 analog_ep_bulk; /* address of bulk endpoint for analog */
+ u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */
+ u8 dvb_ep_bulk; /* address of bulk endpoint for DVC */
+ int alt; /* alternate setting */
+ int max_pkt_size; /* max packet size of the selected ep at alt */
+ int packet_multiplier; /* multiplier for wMaxPacketSize, used for
+ URB buffer size definition */
+ int num_alt; /* number of alternative settings */
+ unsigned int *alt_max_pkt_size_isoc; /* array of isoc wMaxPacketSize */
+ unsigned int analog_xfer_bulk:1; /* use bulk instead of isoc
+ transfers for analog */
+ int dvb_alt_isoc; /* alternate setting for DVB isoc transfers */
+ unsigned int dvb_max_pkt_size_isoc; /* isoc max packet size of the
+ selected DVB ep at dvb_alt */
+ unsigned int dvb_xfer_bulk:1; /* use bulk instead of isoc
+ transfers for DVB */
char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
/* helper funcs that call usb_control_msg */
@@ -619,9 +640,6 @@ struct em28xx {
struct delayed_work sbutton_query_work;
struct em28xx_dvb *dvb;
-
- /* I2C keyboard data */
- struct IR_i2c_init_data init_data;
};
struct em28xx_ops {
@@ -666,12 +684,14 @@ int em28xx_vbi_supported(struct em28xx *dev);
int em28xx_set_outfmt(struct em28xx *dev);
int em28xx_resolution_set(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
-int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
- int max_packets, int num_bufs, int max_pkt_size);
-int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
- int max_packets, int num_bufs, int max_pkt_size,
- int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
-void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode);
+int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
+ int num_bufs, int max_pkt_size, int packet_multiplier);
+int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
+ int xfer_bulk,
+ int num_bufs, int max_pkt_size, int packet_multiplier,
+ int (*urb_data_copy)
+ (struct em28xx *dev, struct urb *urb));
+void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode);
void em28xx_stop_urbs(struct em28xx *dev);
int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
@@ -683,8 +703,13 @@ void em28xx_init_extension(struct em28xx *dev);
void em28xx_close_extension(struct em28xx *dev);
/* Provided by em28xx-video.c */
+int em28xx_vb2_setup(struct em28xx *dev);
int em28xx_register_analog_devices(struct em28xx *dev);
void em28xx_release_analog_resources(struct em28xx *dev);
+void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
+int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
+int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
+extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
/* Provided by em28xx-cards.c */
extern int em2800_variant_detect(struct usb_device *udev, int model);
@@ -695,7 +720,7 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
void em28xx_release_resources(struct em28xx *dev);
/* Provided by em28xx-vbi.c */
-extern struct videobuf_queue_ops em28xx_vbi_qops;
+extern struct vb2_ops em28xx_vbi_qops;
/* printk macros */
diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c
index b3ba47d4d6a2..1dcdd9f95f1c 100644
--- a/drivers/media/usb/gspca/cpia1.c
+++ b/drivers/media/usb/gspca/cpia1.c
@@ -541,7 +541,7 @@ static int do_command(struct gspca_dev *gspca_dev, u16 command,
/* test button press */
a = ((gspca_dev->usb_buf[1] & 0x02) == 0);
if (a != sd->params.qx3.button) {
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
input_report_key(gspca_dev->input_dev, KEY_CAMERA, a);
input_sync(gspca_dev->input_dev);
#endif
@@ -1640,7 +1640,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
/* Update the camera status */
do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
/* If the last button state is pressed, release it now! */
if (sd->params.qx3.button) {
/* The camera latch will hold the pressed state until we reset
@@ -1869,7 +1869,7 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.dq_callback = sd_dq_callback,
.pkt_scan = sd_pkt_scan,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.other_input = 1,
#endif
};
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index e0a431bb0d42..3564bdbb2ea3 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -44,7 +44,7 @@
#include "gspca.h"
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
#include <linux/input.h>
#include <linux/usb/input.h>
#endif
@@ -118,7 +118,7 @@ static const struct vm_operations_struct gspca_vm_ops = {
/*
* Input and interrupt endpoint handling functions
*/
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static void int_irq(struct urb *urb)
{
struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
@@ -2303,7 +2303,7 @@ int gspca_dev_probe2(struct usb_interface *intf,
return 0;
out:
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
if (gspca_dev->input_dev)
input_unregister_device(gspca_dev->input_dev);
#endif
@@ -2348,7 +2348,7 @@ EXPORT_SYMBOL(gspca_dev_probe);
void gspca_disconnect(struct usb_interface *intf)
{
struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
struct input_dev *input_dev;
#endif
@@ -2360,7 +2360,7 @@ void gspca_disconnect(struct usb_interface *intf)
gspca_dev->present = 0;
destroy_urbs(gspca_dev);
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
gspca_input_destroy_urb(gspca_dev);
input_dev = gspca_dev->input_dev;
if (input_dev) {
diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h
index 352317d7acdb..5559932bf2f5 100644
--- a/drivers/media/usb/gspca/gspca.h
+++ b/drivers/media/usb/gspca/gspca.h
@@ -138,7 +138,7 @@ struct sd_desc {
cam_reg_op get_register;
#endif
cam_ident_op get_chip_ident;
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
cam_int_pkt_op int_pkt_scan;
/* other_input makes the gspca core create gspca_dev->input even when
int_pkt_scan is NULL, for cams with non interrupt driven buttons */
@@ -167,7 +167,7 @@ struct gspca_dev {
struct usb_device *dev;
struct file *capt_file; /* file doing video capture */
/* protected by queue_lock */
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
struct input_dev *input_dev;
char phys[64]; /* physical device path */
#endif
@@ -190,7 +190,7 @@ struct gspca_dev {
#define USB_BUF_SZ 64
__u8 *usb_buf; /* buffer for USB exchanges */
struct urb *urb[MAX_NURBS];
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
struct urb *int_urb;
#endif
diff --git a/drivers/media/usb/gspca/jl2005bcd.c b/drivers/media/usb/gspca/jl2005bcd.c
index 62ba80d9b998..fdaeeb14453f 100644
--- a/drivers/media/usb/gspca/jl2005bcd.c
+++ b/drivers/media/usb/gspca/jl2005bcd.c
@@ -536,20 +536,4 @@ static struct usb_driver sd_driver = {
#endif
};
-/* -- module insert / remove -- */
-static int __init sd_mod_init(void)
-{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- return 0;
-}
-static void __exit sd_mod_exit(void)
-{
- usb_deregister(&sd_driver);
-}
-
-module_init(sd_mod_init);
-module_exit(sd_mod_exit);
+module_usb_driver(sd_driver);
diff --git a/drivers/media/usb/gspca/konica.c b/drivers/media/usb/gspca/konica.c
index bbf91e07e38b..61e25dbf2447 100644
--- a/drivers/media/usb/gspca/konica.c
+++ b/drivers/media/usb/gspca/konica.c
@@ -246,7 +246,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
konica_stream_off(gspca_dev);
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
/* Don't keep the button in the pressed state "forever" if it was
pressed when streaming is stopped */
if (sd->snapshot_pressed) {
@@ -345,7 +345,7 @@ static void sd_isoc_irq(struct urb *urb)
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
} else {
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
u8 button_state = st & 0x40 ? 1 : 0;
if (sd->snapshot_pressed != button_state) {
input_report_key(gspca_dev->input_dev,
@@ -452,7 +452,7 @@ static const struct sd_desc sd_desc = {
.init_controls = sd_init_controls,
.start = sd_start,
.stopN = sd_stopN,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.other_input = 1,
#endif
};
diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c
index 9aa09f845ce4..9ad19a7ef81b 100644
--- a/drivers/media/usb/gspca/ov519.c
+++ b/drivers/media/usb/gspca/ov519.c
@@ -4238,7 +4238,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
if (sd->bridge == BRIDGE_W9968CF)
w9968cf_stop0(sd);
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
/* If the last button state is pressed, release it now! */
if (sd->snapshot_pressed) {
input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
@@ -4255,7 +4255,7 @@ static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state)
struct sd *sd = (struct sd *) gspca_dev;
if (sd->snapshot_pressed != state) {
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
input_report_key(gspca_dev->input_dev, KEY_CAMERA, state);
input_sync(gspca_dev->input_dev);
#endif
@@ -4924,7 +4924,7 @@ static const struct sd_desc sd_desc = {
.dq_callback = sd_reset_snapshot,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.other_input = 1,
#endif
};
diff --git a/drivers/media/usb/gspca/pac207.c b/drivers/media/usb/gspca/pac207.c
index d236d1791f78..3b75097dd34e 100644
--- a/drivers/media/usb/gspca/pac207.c
+++ b/drivers/media/usb/gspca/pac207.c
@@ -55,6 +55,11 @@ MODULE_LICENSE("GPL");
#define PAC207_AUTOGAIN_DEADZONE 30
+/* global parameters */
+static int led_invert;
+module_param(led_invert, int, 0644);
+MODULE_PARM_DESC(led_invert, "Invert led");
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
@@ -187,10 +192,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- pac207_write_reg(gspca_dev, 0x41, 0x00);
- /* Bit_0=Image Format,
- * Bit_1=LED,
- * Bit_2=Compression test mode enable */
+ u8 mode;
+
+ /* mode: Image Format (Bit 0), LED (1), Compr. test mode (2) */
+ if (led_invert)
+ mode = 0x02;
+ else
+ mode = 0x00;
+ pac207_write_reg(gspca_dev, 0x41, mode);
pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
return gspca_dev->usb_err;
@@ -303,7 +312,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
pac207_write_reg(gspca_dev, 0x02,
v4l2_ctrl_g_ctrl(gspca_dev->exposure)); /* PXCK = 12MHz /n */
- mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
+ /* mode: Image Format (Bit 0), LED (1), Compr. test mode (2) */
+ if (led_invert)
+ mode = 0x00;
+ else
+ mode = 0x02;
if (gspca_dev->width == 176) { /* 176x144 */
mode |= 0x01;
PDEBUG(D_STREAM, "pac207_start mode 176x144");
@@ -325,8 +338,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(struct gspca_dev *gspca_dev)
{
+ u8 mode;
+
+ /* mode: Image Format (Bit 0), LED (1), Compr. test mode (2) */
+ if (led_invert)
+ mode = 0x02;
+ else
+ mode = 0x00;
pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
- pac207_write_reg(gspca_dev, 0x41, 0x00); /* Turn of LED */
+ pac207_write_reg(gspca_dev, 0x41, mode); /* Turn off LED */
pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
}
@@ -393,7 +413,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrput packet length */
@@ -422,7 +442,7 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.dq_callback = pac207_do_auto_gain,
.pkt_scan = sd_pkt_scan,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c
index 4f5869a98082..add6f725ba50 100644
--- a/drivers/media/usb/gspca/pac7302.c
+++ b/drivers/media/usb/gspca/pac7302.c
@@ -890,7 +890,7 @@ static int sd_chip_ident(struct gspca_dev *gspca_dev,
}
#endif
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrput packet length */
@@ -936,7 +936,7 @@ static const struct sd_desc sd_desc = {
.set_register = sd_dbg_s_register,
.get_chip_ident = sd_chip_ident,
#endif
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
diff --git a/drivers/media/usb/gspca/pac7311.c b/drivers/media/usb/gspca/pac7311.c
index ba3558d3f017..a12dfbf6e051 100644
--- a/drivers/media/usb/gspca/pac7311.c
+++ b/drivers/media/usb/gspca/pac7311.c
@@ -621,7 +621,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrupt packet length */
@@ -661,7 +661,7 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
diff --git a/drivers/media/usb/gspca/se401.c b/drivers/media/usb/gspca/se401.c
index a33cb78a839c..5f729b8aa2bd 100644
--- a/drivers/media/usb/gspca/se401.c
+++ b/drivers/media/usb/gspca/se401.c
@@ -594,7 +594,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len)
sd_pkt_scan_janggu(gspca_dev, data, len);
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len)
{
struct sd *sd = (struct sd *)gspca_dev;
@@ -688,7 +688,7 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.dq_callback = sd_dq_callback,
.pkt_scan = sd_pkt_scan,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index 41f769fe340c..4ec544f4a845 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -2205,7 +2205,7 @@ static void qual_upd(struct work_struct *work)
mutex_unlock(&gspca_dev->usb_lock);
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet */
int len) /* interrupt packet length */
@@ -2349,7 +2349,7 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
#endif
.dq_callback = sd_dqcallback,
diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c
index 1220340e7602..104ae25275b4 100644
--- a/drivers/media/usb/gspca/sonixb.c
+++ b/drivers/media/usb/gspca/sonixb.c
@@ -1400,7 +1400,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrupt packet length */
@@ -1430,7 +1430,7 @@ static const struct sd_desc sd_desc = {
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
.dq_callback = do_autogain,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
@@ -1448,7 +1448,7 @@ static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
{USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
{USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+#if !IS_ENABLED(CONFIG_USB_SN9C102)
{USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
{USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
#endif
diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c
index 36307a9028a9..671d0c6dece3 100644
--- a/drivers/media/usb/gspca/sonixj.c
+++ b/drivers/media/usb/gspca/sonixj.c
@@ -3077,7 +3077,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrupt packet length */
@@ -3109,7 +3109,7 @@ static const struct sd_desc sd_desc = {
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
.querymenu = sd_querymenu,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
diff --git a/drivers/media/usb/gspca/spca561.c b/drivers/media/usb/gspca/spca561.c
index cfe71dd6747d..d1db3d8f6522 100644
--- a/drivers/media/usb/gspca/spca561.c
+++ b/drivers/media/usb/gspca/spca561.c
@@ -741,7 +741,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
return;
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
if (data[0] & 0x20) {
input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
input_sync(gspca_dev->input_dev);
@@ -866,7 +866,7 @@ static const struct sd_desc sd_desc_12a = {
.start = sd_start_12a,
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.other_input = 1,
#endif
};
@@ -879,7 +879,7 @@ static const struct sd_desc sd_desc_72a = {
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.other_input = 1,
#endif
};
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c
index 999ec7764449..657160b4a1f7 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c
@@ -492,7 +492,7 @@ frame_data:
}
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrupt packet length */
@@ -529,7 +529,7 @@ static const struct sd_desc sd_desc = {
.pkt_scan = stv06xx_pkt_scan,
.isoc_init = stv06xx_isoc_init,
.isoc_nego = stv06xx_isoc_nego,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
index 748e1421d6d8..e95fa8997d22 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
@@ -52,9 +52,13 @@ static int vv6410_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_HFLIP:
+ if (!gspca_dev->streaming)
+ return 0;
err = vv6410_set_hflip(gspca_dev, ctrl->val);
break;
case V4L2_CID_VFLIP:
+ if (!gspca_dev->streaming)
+ return 0;
err = vv6410_set_vflip(gspca_dev, ctrl->val);
break;
case V4L2_CID_GAIN:
@@ -94,11 +98,14 @@ static int vv6410_init_controls(struct sd *sd)
{
struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
- v4l2_ctrl_handler_init(hdl, 4);
- v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_handler_init(hdl, 2);
+ /* Disable the hardware VFLIP and HFLIP as we currently lack a
+ mechanism to adjust the image offset in such a way that
+ we don't need to renegotiate the announced format */
+ /* v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, */
+ /* V4L2_CID_HFLIP, 0, 1, 1, 0); */
+ /* v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, */
+ /* V4L2_CID_VFLIP, 0, 1, 1, 0); */
v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
V4L2_CID_EXPOSURE, 0, 32768, 1, 20000);
v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
diff --git a/drivers/media/usb/gspca/t613.c b/drivers/media/usb/gspca/t613.c
index 8bc6c3ceec2c..e2cc4e5a0ccb 100644
--- a/drivers/media/usb/gspca/t613.c
+++ b/drivers/media/usb/gspca/t613.c
@@ -494,7 +494,7 @@ static void setcolors(struct gspca_dev *gspca_dev, s32 val)
static void setgamma(struct gspca_dev *gspca_dev, s32 val)
{
- PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
+ PDEBUG(D_CONF, "Gamma: %d", val);
reg_w_ixbuf(gspca_dev, 0x90,
gamma_table[val], sizeof gamma_table[0]);
}
@@ -823,7 +823,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
msleep(20);
reg_w(gspca_dev, 0x0309);
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
/* If the last button state is pressed, release it now! */
if (sd->button_pressed) {
input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
@@ -841,7 +841,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
int pkt_type;
if (data[0] == 0x5a) {
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
if (len > 20) {
u8 state = (data[20] & 0x80) ? 1 : 0;
if (sd->button_pressed != state) {
@@ -1019,7 +1019,7 @@ static const struct sd_desc sd_desc = {
.start = sd_start,
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.other_input = 1,
#endif
};
diff --git a/drivers/media/usb/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c
index d4b23c9bf90c..7eaf64eb867c 100644
--- a/drivers/media/usb/gspca/xirlink_cit.c
+++ b/drivers/media/usb/gspca/xirlink_cit.c
@@ -2759,7 +2759,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
break;
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
/* If the last button state is pressed, release it now! */
if (sd->button_state) {
input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
@@ -2914,7 +2914,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static void cit_check_button(struct gspca_dev *gspca_dev)
{
int new_button_state;
@@ -3062,7 +3062,7 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.dq_callback = cit_check_button,
.other_input = 1,
#endif
@@ -3079,7 +3079,7 @@ static const struct sd_desc sd_desc_isoc_nego = {
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.dq_callback = cit_check_button,
.other_input = 1,
#endif
diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c
index 77c57755e7b4..a8dc421f9f1f 100644
--- a/drivers/media/usb/gspca/zc3xx.c
+++ b/drivers/media/usb/gspca/zc3xx.c
@@ -6902,7 +6902,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
return 0;
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrput packet length */
@@ -6929,7 +6929,7 @@ static const struct sd_desc sd_desc = {
.pkt_scan = sd_pkt_scan,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index 84dc26fe80ee..5c6193536399 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -391,7 +391,7 @@ static int hdpvr_probe(struct usb_interface *interface,
goto error;
}
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
retval = hdpvr_register_i2c_adapter(dev);
if (retval < 0) {
v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n");
@@ -419,7 +419,7 @@ static int hdpvr_probe(struct usb_interface *interface,
return 0;
reg_fail:
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_adapter(&dev->i2c_adapter);
#endif
error:
@@ -451,7 +451,7 @@ static void hdpvr_disconnect(struct usb_interface *interface)
mutex_lock(&dev->io_mutex);
hdpvr_cancel_queue(dev);
mutex_unlock(&dev->io_mutex);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_adapter(&dev->i2c_adapter);
#endif
video_unregister_device(dev->video_dev);
diff --git a/drivers/media/usb/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c
index 031cf024304c..a38f58c4c6bf 100644
--- a/drivers/media/usb/hdpvr/hdpvr-i2c.c
+++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c
@@ -13,7 +13,7 @@
*
*/
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
#include <linux/i2c.h>
#include <linux/slab.h>
@@ -217,8 +217,7 @@ int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
hdpvr_activate_ir(dev);
- memcpy(&dev->i2c_adapter, &hdpvr_i2c_adapter_template,
- sizeof(struct i2c_adapter));
+ dev->i2c_adapter = hdpvr_i2c_adapter_template;
dev->i2c_adapter.dev.parent = &dev->udev->dev;
i2c_set_adapdata(&dev->i2c_adapter, dev);
diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig
index 32b11c15bb1a..60a2604e4cb3 100644
--- a/drivers/media/usb/pvrusb2/Kconfig
+++ b/drivers/media/usb/pvrusb2/Kconfig
@@ -17,9 +17,9 @@ config VIDEO_PVRUSB2
module will be called pvrusb2
config VIDEO_PVRUSB2_SYSFS
- bool "pvrusb2 sysfs support (EXPERIMENTAL)"
+ bool "pvrusb2 sysfs support"
default y
- depends on VIDEO_PVRUSB2 && SYSFS && EXPERIMENTAL
+ depends on VIDEO_PVRUSB2 && SYSFS
---help---
This option enables the operation of a sysfs based
interface for query and control of the pvrusb2 driver.
@@ -33,9 +33,9 @@ config VIDEO_PVRUSB2_SYSFS
Note: This feature is experimental and subject to change.
config VIDEO_PVRUSB2_DVB
- bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)"
+ bool "pvrusb2 ATSC/DVB support"
default y
- depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
+ depends on VIDEO_PVRUSB2 && DVB_CORE
select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
index e046fdaec5ae..f7702aeeda3f 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
@@ -422,8 +422,7 @@ int pvr2_encoder_adjust(struct pvr2_hdw *hdw)
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Error from cx2341x module code=%d",ret);
} else {
- memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
- sizeof(struct cx2341x_mpeg_params));
+ hdw->enc_cur_state = hdw->enc_ctl_state;
hdw->enc_cur_valid = !0;
}
return ret;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
index 9ab596c78a4e..b5e929f1bf82 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
@@ -649,8 +649,8 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
}
// Configure the adapter and set up everything else related to it.
- memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
- memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));
+ hdw->i2c_adap = pvr2_i2c_adap_template;
+ hdw->i2c_algo = pvr2_i2c_algo_template;
strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
hdw->i2c_adap.algo = &hdw->i2c_algo;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index 6930676051e7..34c3b6e80e86 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -1339,7 +1339,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
return;
}
- memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
+ dip->devbase = vdev_template;
dip->devbase.release = pvr2_video_device_release;
dip->devbase.ioctl_ops = &pvr2_ioctl_ops;
{
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index 5210239cbaee..5ec15cb1ed26 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -316,7 +316,8 @@ static void pwc_isoc_handler(struct urb *urb)
struct pwc_frame_buf *fbuf = pdev->fill_buf;
if (pdev->vsync == 1) {
- do_gettimeofday(&fbuf->vb.v4l2_buf.timestamp);
+ v4l2_get_timestamp(
+ &fbuf->vb.v4l2_buf.timestamp);
pdev->vsync = 2;
}
@@ -1007,7 +1008,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
}
/* Init video_device structure */
- memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
+ pdev->vdev = pwc_template;
strcpy(pdev->vdev.name, name);
pdev->vdev.queue = &pdev->vb_queue;
pdev->vdev.queue->lock = &pdev->vb_queue_lock;
diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c
index 545e9bbdeede..aa7449eaca08 100644
--- a/drivers/media/usb/pwc/pwc-v4l.c
+++ b/drivers/media/usb/pwc/pwc-v4l.c
@@ -434,19 +434,18 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
case V4L2_PIX_FMT_PWC1:
if (DEVICE_USE_CODEC23(pdev->type)) {
PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
- return -EINVAL;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
}
break;
case V4L2_PIX_FMT_PWC2:
if (DEVICE_USE_CODEC1(pdev->type)) {
PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
- return -EINVAL;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
}
break;
default:
PWC_DEBUG_IOCTL("Unsupported pixel format\n");
- return -EINVAL;
-
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
}
size = pwc_get_size(pdev, f->fmt.pix.width, f->fmt.pix.height);
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 8ebec0d7bf59..498c57ea5d32 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -593,7 +593,7 @@ static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
buf = list_entry(dma_q->active.next,
struct s2255_buffer, vb.queue);
list_del(&buf->vb.queue);
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
s2255_fillbuff(channel, buf, jpgsize);
wake_up(&buf->vb.done);
dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
@@ -629,7 +629,6 @@ static void s2255_fillbuff(struct s2255_channel *channel,
struct s2255_buffer *buf, int jpgsize)
{
int pos = 0;
- struct timeval ts;
const char *tmpbuf;
char *vbuf = videobuf_to_vmalloc(&buf->vb);
unsigned long last_frame;
@@ -674,8 +673,7 @@ static void s2255_fillbuff(struct s2255_channel *channel,
/* tell v4l buffer was filled */
buf->vb.field_count = channel->frame_count * 2;
- do_gettimeofday(&ts);
- buf->vb.ts = ts;
+ v4l2_get_timestamp(&buf->vb.ts);
buf->vb.state = VIDEOBUF_DONE;
}
diff --git a/drivers/media/usb/sn9c102/sn9c102_core.c b/drivers/media/usb/sn9c102/sn9c102_core.c
index 73605864fffa..c957e9aa6077 100644
--- a/drivers/media/usb/sn9c102/sn9c102_core.c
+++ b/drivers/media/usb/sn9c102/sn9c102_core.c
@@ -173,7 +173,7 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
cam->frame[i].buf.sequence = 0;
cam->frame[i].buf.field = V4L2_FIELD_NONE;
cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
- cam->frame[i].buf.flags = 0;
+ cam->frame[i].buf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
}
return cam->nbuffers;
@@ -773,7 +773,8 @@ end_of_frame:
img);
if ((*f)->buf.bytesused == 0)
- do_gettimeofday(&(*f)->buf.timestamp);
+ v4l2_get_timestamp(
+ &(*f)->buf.timestamp);
(*f)->buf.bytesused += img;
@@ -2826,7 +2827,7 @@ sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
b.index >= cam->nbuffers || cam->io != IO_MMAP)
return -EINVAL;
- memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+ b = cam->frame[b.index].buf;
if (cam->frame[b.index].vma_use_count)
b.flags |= V4L2_BUF_FLAG_MAPPED;
@@ -2929,7 +2930,7 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
f->state = F_UNUSED;
- memcpy(&b, &f->buf, sizeof(b));
+ b = f->buf;
if (f->vma_use_count)
b.flags |= V4L2_BUF_FLAG_MAPPED;
diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c
index fa3671de02aa..39f1aae209bc 100644
--- a/drivers/media/usb/stk1160/stk1160-video.c
+++ b/drivers/media/usb/stk1160/stk1160-video.c
@@ -78,7 +78,7 @@ struct stk1160_buffer *stk1160_next_buffer(struct stk1160 *dev)
unsigned long flags = 0;
/* Current buffer must be NULL when this functions gets called */
- BUG_ON(dev->isoc_ctl.buf);
+ WARN_ON(dev->isoc_ctl.buf);
spin_lock_irqsave(&dev->buf_lock, flags);
if (!list_empty(&dev->avail_bufs)) {
@@ -101,7 +101,7 @@ void stk1160_buffer_done(struct stk1160 *dev)
buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
buf->vb.v4l2_buf.bytesused = buf->bytesused;
- do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
vb2_set_plane_payload(&buf->vb, 0, buf->bytesused);
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c
index 5d3c032d733c..4cbab085e348 100644
--- a/drivers/media/usb/stkwebcam/stk-webcam.c
+++ b/drivers/media/usb/stkwebcam/stk-webcam.c
@@ -28,6 +28,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
+#include <linux/dmi.h>
#include <linux/usb.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
@@ -38,12 +39,12 @@
#include "stk-webcam.h"
-static bool hflip;
-module_param(hflip, bool, 0444);
+static int hflip = -1;
+module_param(hflip, int, 0444);
MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 0");
-static bool vflip;
-module_param(vflip, bool, 0444);
+static int vflip = -1;
+module_param(vflip, int, 0444);
MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 0");
static int debug;
@@ -62,6 +63,19 @@ static struct usb_device_id stkwebcam_table[] = {
};
MODULE_DEVICE_TABLE(usb, stkwebcam_table);
+/* The stk webcam laptop module is mounted upside down in some laptops :( */
+static const struct dmi_system_id stk_upside_down_dmi_table[] = {
+ {
+ .ident = "ASUS G1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "G1")
+ }
+ },
+ {}
+};
+
+
/*
* Basic stuff
*/
@@ -466,6 +480,7 @@ static int stk_setup_siobuf(struct stk_camera *dev, int index)
buf->dev = dev;
buf->v4lbuf.index = index;
buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->v4lbuf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
buf->v4lbuf.field = V4L2_FIELD_NONE;
buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
@@ -816,10 +831,16 @@ static int stk_vidioc_g_ctrl(struct file *filp,
c->value = dev->vsettings.brightness;
break;
case V4L2_CID_HFLIP:
- c->value = dev->vsettings.hflip;
+ if (dmi_check_system(stk_upside_down_dmi_table))
+ c->value = !dev->vsettings.hflip;
+ else
+ c->value = dev->vsettings.hflip;
break;
case V4L2_CID_VFLIP:
- c->value = dev->vsettings.vflip;
+ if (dmi_check_system(stk_upside_down_dmi_table))
+ c->value = !dev->vsettings.vflip;
+ else
+ c->value = dev->vsettings.vflip;
break;
default:
return -EINVAL;
@@ -836,10 +857,16 @@ static int stk_vidioc_s_ctrl(struct file *filp,
dev->vsettings.brightness = c->value;
return stk_sensor_set_brightness(dev, c->value >> 8);
case V4L2_CID_HFLIP:
- dev->vsettings.hflip = c->value;
+ if (dmi_check_system(stk_upside_down_dmi_table))
+ dev->vsettings.hflip = !c->value;
+ else
+ dev->vsettings.hflip = c->value;
return 0;
case V4L2_CID_VFLIP:
- dev->vsettings.vflip = c->value;
+ if (dmi_check_system(stk_upside_down_dmi_table))
+ dev->vsettings.vflip = !c->value;
+ else
+ dev->vsettings.vflip = c->value;
return 0;
default:
return -EINVAL;
@@ -1113,7 +1140,7 @@ static int stk_vidioc_dqbuf(struct file *filp,
sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
sbuf->v4lbuf.sequence = ++dev->sequence;
- do_gettimeofday(&sbuf->v4lbuf.timestamp);
+ v4l2_get_timestamp(&sbuf->v4lbuf.timestamp);
*buf = sbuf->v4lbuf;
return 0;
@@ -1275,8 +1302,18 @@ static int stk_camera_probe(struct usb_interface *interface,
dev->interface = interface;
usb_get_intf(interface);
- dev->vsettings.vflip = vflip;
- dev->vsettings.hflip = hflip;
+ if (hflip != -1)
+ dev->vsettings.hflip = hflip;
+ else if (dmi_check_system(stk_upside_down_dmi_table))
+ dev->vsettings.hflip = 1;
+ else
+ dev->vsettings.hflip = 0;
+ if (vflip != -1)
+ dev->vsettings.vflip = vflip;
+ else if (dmi_check_system(stk_upside_down_dmi_table))
+ dev->vsettings.vflip = 1;
+ else
+ dev->vsettings.vflip = 0;
dev->n_sbufs = 0;
set_present(dev);
diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c
index 3082bfa9b2c5..21723378bb8f 100644
--- a/drivers/media/usb/tlg2300/pd-video.c
+++ b/drivers/media/usb/tlg2300/pd-video.c
@@ -212,7 +212,7 @@ static void submit_frame(struct front_face *front)
front->curr_frame = NULL;
vb->state = VIDEOBUF_DONE;
vb->field_count++;
- do_gettimeofday(&vb->ts);
+ v4l2_get_timestamp(&vb->ts);
wake_up(&vb->done);
}
diff --git a/drivers/media/usb/tm6000/tm6000-core.c b/drivers/media/usb/tm6000/tm6000-core.c
index 22cc0116deb6..7c32353c59db 100644
--- a/drivers/media/usb/tm6000/tm6000-core.c
+++ b/drivers/media/usb/tm6000/tm6000-core.c
@@ -40,10 +40,13 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
u8 *data = NULL;
int delay = 5000;
- mutex_lock(&dev->usb_lock);
-
- if (len)
+ if (len) {
data = kzalloc(len, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ }
+
+ mutex_lock(&dev->usb_lock);
if (req_type & USB_DIR_IN)
pipe = usb_rcvctrlpipe(dev->udev, 0);
diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c
index e1f3f66e1e63..9fc1e940a82b 100644
--- a/drivers/media/usb/tm6000/tm6000-dvb.c
+++ b/drivers/media/usb/tm6000/tm6000-dvb.c
@@ -360,8 +360,8 @@ dvb_dmx_err:
dvb_dmx_release(&dvb->demux);
frontend_err:
if (dvb->frontend) {
- dvb_frontend_detach(dvb->frontend);
dvb_unregister_frontend(dvb->frontend);
+ dvb_frontend_detach(dvb->frontend);
}
adapter_err:
dvb_unregister_adapter(&dvb->adapter);
@@ -384,8 +384,8 @@ static void unregister_dvb(struct tm6000_core *dev)
/* mutex_lock(&tm6000_driver.open_close_mutex); */
if (dvb->frontend) {
- dvb_frontend_detach(dvb->frontend);
dvb_unregister_frontend(dvb->frontend);
+ dvb_frontend_detach(dvb->frontend);
}
dvb_dmxdev_release(&dvb->dmxdev);
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index f656fd7a39a2..1a6857929c15 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -34,6 +34,7 @@
#include <linux/usb.h>
#include <linux/videodev2.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include <media/tuner.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
@@ -49,82 +50,20 @@
#define TM6000_MIN_BUF 4
#define TM6000_DEF_BUF 8
+#define TM6000_NUM_URB_BUF 8
+
#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */
/* Declare static vars that will be used as parameters */
static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */
+static bool keep_urb; /* keep urb buffers allocated */
/* Debug level */
int tm6000_debug;
EXPORT_SYMBOL_GPL(tm6000_debug);
-static const struct v4l2_queryctrl no_ctrl = {
- .name = "42",
- .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-/* supported controls */
-static struct v4l2_queryctrl tm6000_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 54,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 255,
- .step = 0x1,
- .default_value = 119,
- .flags = 0,
- }, {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 255,
- .step = 0x1,
- .default_value = 112,
- .flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 0x1,
- .default_value = 0,
- .flags = 0,
- },
- /* --- audio --- */
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- }, {
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = -15,
- .maximum = 15,
- .step = 1,
- .default_value = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }
-};
-
-static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl);
-static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
-
static struct tm6000_fmt format[] = {
{
.name = "4:2:2, packed, YVY2",
@@ -141,16 +80,6 @@ static struct tm6000_fmt format[] = {
}
};
-static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
-{
- unsigned int i;
-
- for (i = 0; i < CTRLS; i++)
- if (tm6000_qctrl[i].id == id)
- return tm6000_qctrl+i;
- return NULL;
-}
-
/* ------------------------------------------------------------------
* DMA and thread functions
* ------------------------------------------------------------------
@@ -191,7 +120,7 @@ static inline void buffer_filled(struct tm6000_core *dev,
dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i);
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
@@ -538,6 +467,71 @@ static void tm6000_irq_callback(struct urb *urb)
}
/*
+ * Allocate URB buffers
+ */
+static int tm6000_alloc_urb_buffers(struct tm6000_core *dev)
+{
+ int num_bufs = TM6000_NUM_URB_BUF;
+ int i;
+
+ if (dev->urb_buffer != NULL)
+ return 0;
+
+ dev->urb_buffer = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!dev->urb_buffer) {
+ tm6000_err("cannot allocate memory for urb buffers\n");
+ return -ENOMEM;
+ }
+
+ dev->urb_dma = kmalloc(sizeof(dma_addr_t *)*num_bufs, GFP_KERNEL);
+ if (!dev->urb_dma) {
+ tm6000_err("cannot allocate memory for urb dma pointers\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num_bufs; i++) {
+ dev->urb_buffer[i] = usb_alloc_coherent(
+ dev->udev, dev->urb_size,
+ GFP_KERNEL, &dev->urb_dma[i]);
+ if (!dev->urb_buffer[i]) {
+ tm6000_err("unable to allocate %i bytes for transfer buffer %i\n",
+ dev->urb_size, i);
+ return -ENOMEM;
+ }
+ memset(dev->urb_buffer[i], 0, dev->urb_size);
+ }
+
+ return 0;
+}
+
+/*
+ * Free URB buffers
+ */
+static int tm6000_free_urb_buffers(struct tm6000_core *dev)
+{
+ int i;
+
+ if (dev->urb_buffer == NULL)
+ return 0;
+
+ for (i = 0; i < TM6000_NUM_URB_BUF; i++) {
+ if (dev->urb_buffer[i]) {
+ usb_free_coherent(dev->udev,
+ dev->urb_size,
+ dev->urb_buffer[i],
+ dev->urb_dma[i]);
+ dev->urb_buffer[i] = NULL;
+ }
+ }
+ kfree(dev->urb_buffer);
+ kfree(dev->urb_dma);
+ dev->urb_buffer = NULL;
+ dev->urb_dma = NULL;
+
+ return 0;
+}
+
+/*
* Stop and Deallocate URBs
*/
static void tm6000_uninit_isoc(struct tm6000_core *dev)
@@ -551,18 +545,15 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
if (urb) {
usb_kill_urb(urb);
usb_unlink_urb(urb);
- if (dev->isoc_ctl.transfer_buffer[i]) {
- usb_free_coherent(dev->udev,
- urb->transfer_buffer_length,
- dev->isoc_ctl.transfer_buffer[i],
- urb->transfer_dma);
- }
usb_free_urb(urb);
dev->isoc_ctl.urb[i] = NULL;
}
dev->isoc_ctl.transfer_buffer[i] = NULL;
}
+ if (!keep_urb)
+ tm6000_free_urb_buffers(dev);
+
kfree(dev->isoc_ctl.urb);
kfree(dev->isoc_ctl.transfer_buffer);
@@ -572,12 +563,13 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
}
/*
- * Allocate URBs and start IRQ
+ * Assign URBs and start IRQ
*/
static int tm6000_prepare_isoc(struct tm6000_core *dev)
{
struct tm6000_dmaqueue *dma_q = &dev->vidq;
- int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
+ int i, j, sb_size, pipe, size, max_packets;
+ int num_bufs = TM6000_NUM_URB_BUF;
struct urb *urb;
/* De-allocates all pending stuff */
@@ -605,6 +597,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev)
max_packets = TM6000_MAX_ISO_PACKETS;
sb_size = max_packets * size;
+ dev->urb_size = sb_size;
dev->isoc_ctl.num_bufs = num_bufs;
@@ -627,6 +620,17 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev)
max_packets, num_bufs, sb_size,
dev->isoc_in.maxsize, size);
+
+ if (!dev->urb_buffer && tm6000_alloc_urb_buffers(dev) < 0) {
+ tm6000_err("cannot allocate memory for urb buffers\n");
+
+ /* call free, as some buffers might have been allocated */
+ tm6000_free_urb_buffers(dev);
+ kfree(dev->isoc_ctl.urb);
+ kfree(dev->isoc_ctl.transfer_buffer);
+ return -ENOMEM;
+ }
+
/* allocate urbs and transfer buffers */
for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
urb = usb_alloc_urb(max_packets, GFP_KERNEL);
@@ -638,17 +642,8 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev)
}
dev->isoc_ctl.urb[i] = urb;
- dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
- sb_size, GFP_KERNEL, &urb->transfer_dma);
- if (!dev->isoc_ctl.transfer_buffer[i]) {
- tm6000_err("unable to allocate %i bytes for transfer"
- " buffer %i%s\n",
- sb_size, i,
- in_interrupt() ? " while in int" : "");
- tm6000_uninit_isoc(dev);
- return -ENOMEM;
- }
- memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+ urb->transfer_dma = dev->urb_dma[i];
+ dev->isoc_ctl.transfer_buffer[i] = dev->urb_buffer[i];
usb_fill_bulk_urb(urb, dev->udev, pipe,
dev->isoc_ctl.transfer_buffer[i], sb_size,
@@ -879,16 +874,21 @@ static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
+ struct video_device *vdev = video_devdata(file);
strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE;
-
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
if (dev->tuner_type != TUNER_ABSENT)
- cap->capabilities |= V4L2_CAP_TUNER;
+ cap->device_caps |= V4L2_CAP_TUNER;
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ else
+ cap->device_caps |= V4L2_CAP_RADIO;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
+ V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
return 0;
}
@@ -896,7 +896,7 @@ static int vidioc_querycap(struct file *file, void *priv,
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- if (unlikely(f->index >= ARRAY_SIZE(format)))
+ if (f->index >= ARRAY_SIZE(format))
return -EINVAL;
strlcpy(f->description, format[f->index].name, sizeof(f->description));
@@ -913,10 +913,12 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.height = fh->height;
f->fmt.pix.field = fh->vb_vidq.field;
f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fh->fmt->depth) >> 3;
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -947,12 +949,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
field = f->fmt.pix.field;
- if (field == V4L2_FIELD_ANY)
- field = V4L2_FIELD_SEQ_TB;
- else if (V4L2_FIELD_INTERLACED != field) {
- dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
- return -EINVAL;
- }
+ field = V4L2_FIELD_INTERLACED;
tm6000_get_std_res(dev);
@@ -962,11 +959,13 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width &= ~0x01;
f->fmt.pix.field = field;
+ f->fmt.pix.priv = 0;
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
@@ -1141,79 +1140,40 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
}
/* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
- if (qc->id && qc->id == tm6000_qctrl[i].id) {
- memcpy(qc, &(tm6000_qctrl[i]),
- sizeof(*qc));
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int tm6000_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
- int val;
+ struct tm6000_core *dev = container_of(ctrl->handler, struct tm6000_core, ctrl_handler);
+ u8 val = ctrl->val;
- /* FIXME: Probably, those won't work! Maybe we need shadow regs */
switch (ctrl->id) {
case V4L2_CID_CONTRAST:
- val = tm6000_get_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0);
- break;
+ tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
+ return 0;
case V4L2_CID_BRIGHTNESS:
- val = tm6000_get_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0);
+ tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
return 0;
case V4L2_CID_SATURATION:
- val = tm6000_get_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0);
+ tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
return 0;
case V4L2_CID_HUE:
- val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0);
- return 0;
- case V4L2_CID_AUDIO_MUTE:
- val = dev->ctl_mute;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- val = dev->ctl_volume;
+ tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
return 0;
- default:
- return -EINVAL;
}
+ return -EINVAL;
+}
- if (val < 0)
- return val;
-
- ctrl->value = val;
+static const struct v4l2_ctrl_ops tm6000_ctrl_ops = {
+ .s_ctrl = tm6000_s_ctrl,
+};
- return 0;
-}
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int tm6000_radio_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
- u8 val = ctrl->value;
+ struct tm6000_core *dev = container_of(ctrl->handler,
+ struct tm6000_core, radio_ctrl_handler);
+ u8 val = ctrl->val;
switch (ctrl->id) {
- case V4L2_CID_CONTRAST:
- tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
- return 0;
- case V4L2_CID_BRIGHTNESS:
- tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
- return 0;
- case V4L2_CID_SATURATION:
- tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
- return 0;
- case V4L2_CID_HUE:
- tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
- return 0;
case V4L2_CID_AUDIO_MUTE:
dev->ctl_mute = val;
tm6000_tvaudio_set_mute(dev, val);
@@ -1226,20 +1186,24 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
return -EINVAL;
}
+static const struct v4l2_ctrl_ops tm6000_radio_ctrl_ops = {
+ .s_ctrl = tm6000_radio_s_ctrl,
+};
+
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
- if (unlikely(UNSET == dev->tuner_type))
- return -EINVAL;
+ if (UNSET == dev->tuner_type)
+ return -ENOTTY;
if (0 != t->index)
return -EINVAL;
strcpy(t->name, "Television");
t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM;
+ t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
t->rangehigh = 0xffffffffUL;
t->rxsubchans = V4L2_TUNER_SUB_STEREO;
@@ -1257,11 +1221,14 @@ static int vidioc_s_tuner(struct file *file, void *priv,
struct tm6000_core *dev = fh->dev;
if (UNSET == dev->tuner_type)
- return -EINVAL;
+ return -ENOTTY;
if (0 != t->index)
return -EINVAL;
- dev->amode = t->audmode;
+ if (t->audmode > V4L2_TUNER_MODE_STEREO)
+ dev->amode = V4L2_TUNER_MODE_STEREO;
+ else
+ dev->amode = t->audmode;
dprintk(dev, 3, "audio mode: %x\n", t->audmode);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
@@ -1275,10 +1242,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
- if (unlikely(UNSET == dev->tuner_type))
+ if (UNSET == dev->tuner_type)
+ return -ENOTTY;
+ if (f->tuner)
return -EINVAL;
- f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
f->frequency = dev->freq;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
@@ -1292,13 +1260,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
- if (unlikely(UNSET == dev->tuner_type))
- return -EINVAL;
- if (unlikely(f->tuner != 0))
- return -EINVAL;
- if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
- return -EINVAL;
- if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+ if (UNSET == dev->tuner_type)
+ return -ENOTTY;
+ if (f->tuner != 0)
return -EINVAL;
dev->freq = f->frequency;
@@ -1307,27 +1271,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return 0;
}
-static int radio_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
-
- strcpy(cap->driver, "tm6000");
- strlcpy(cap->card, dev->name, sizeof(dev->name));
- sprintf(cap->bus_info, "USB%04x:%04x",
- le16_to_cpu(dev->udev->descriptor.idVendor),
- le16_to_cpu(dev->udev->descriptor.idProduct));
- cap->version = dev->dev_type;
- cap->capabilities = V4L2_CAP_TUNER |
- V4L2_CAP_AUDIO |
- V4L2_CAP_RADIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
-
- return 0;
-}
-
static int radio_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
@@ -1340,7 +1283,9 @@ static int radio_g_tuner(struct file *file, void *priv,
memset(t, 0, sizeof(*t));
strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO;
+ t->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ t->audmode = V4L2_TUNER_MODE_STEREO;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
@@ -1355,95 +1300,14 @@ static int radio_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
+ if (t->audmode > V4L2_TUNER_MODE_STEREO)
+ t->audmode = V4L2_TUNER_MODE_STEREO;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
return 0;
}
-static int radio_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (i->index != 0)
- return -EINVAL;
-
- if (!dev->rinput.type)
- return -EINVAL;
-
- strcpy(i->name, "Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
-
- return 0;
-}
-
-static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (dev->input != 5)
- return -EINVAL;
-
- *i = dev->input - 5;
-
- return 0;
-}
-
-static int radio_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- memset(a, 0, sizeof(*a));
- strcpy(a->name, "Radio");
- return 0;
-}
-
-static int radio_s_audio(struct file *file, void *priv,
- const struct v4l2_audio *a)
-{
- return 0;
-}
-
-static int radio_s_input(struct file *filp, void *priv, unsigned int i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (i)
- return -EINVAL;
-
- if (!dev->rinput.type)
- return -EINVAL;
-
- dev->input = i + 5;
-
- return 0;
-}
-
-static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
-{
- return 0;
-}
-
-static int radio_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- const struct v4l2_queryctrl *ctrl;
-
- if (c->id < V4L2_CID_BASE ||
- c->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- if (c->id == V4L2_CID_AUDIO_MUTE) {
- ctrl = ctrl_by_id(c->id);
- *c = *ctrl;
- } else
- *c = no_ctrl;
-
- return 0;
-}
-
/* ------------------------------------------------------------------
File operations for the device
------------------------------------------------------------------*/
@@ -1454,7 +1318,7 @@ static int __tm6000_open(struct file *file)
struct tm6000_core *dev = video_drvdata(file);
struct tm6000_fh *fh;
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- int i, rc;
+ int rc;
int radio = 0;
dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n",
@@ -1486,6 +1350,7 @@ static int __tm6000_open(struct file *file)
return -ENOMEM;
}
+ v4l2_fh_init(&fh->fh, vdev);
file->private_data = fh;
fh->dev = dev;
fh->radio = radio;
@@ -1514,13 +1379,7 @@ static int __tm6000_open(struct file *file)
if (rc < 0)
return rc;
- if (dev->mode != TM6000_MODE_ANALOG) {
- /* Put all controls at a sane state */
- for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
- qctl_regs[i] = tm6000_qctrl[i].default_value;
-
- dev->mode = TM6000_MODE_ANALOG;
- }
+ dev->mode = TM6000_MODE_ANALOG;
if (!fh->radio) {
videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
@@ -1530,12 +1389,12 @@ static int __tm6000_open(struct file *file)
sizeof(struct tm6000_buffer), fh, &dev->lock);
} else {
dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n");
- dev->input = 5;
tm6000_set_audio_rinput(dev);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
tm6000_prepare_isoc(dev);
tm6000_start_thread(dev);
}
+ v4l2_fh_add(&fh->fh);
return 0;
}
@@ -1576,29 +1435,35 @@ tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
static unsigned int
__tm6000_poll(struct file *file, struct poll_table_struct *wait)
{
+ unsigned long req_events = poll_requested_events(wait);
struct tm6000_fh *fh = file->private_data;
struct tm6000_buffer *buf;
+ int res = 0;
+ if (v4l2_event_pending(&fh->fh))
+ res = POLLPRI;
+ else if (req_events & POLLPRI)
+ poll_wait(file, &fh->fh.wait, wait);
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
- return POLLERR;
+ return res | POLLERR;
if (!!is_res_streaming(fh->dev, fh))
- return POLLERR;
+ return res | POLLERR;
if (!is_res_read(fh->dev, fh)) {
/* streaming capture */
if (list_empty(&fh->vb_vidq.stream))
- return POLLERR;
+ return res | POLLERR;
buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream);
- } else {
+ poll_wait(file, &buf->vb.done, wait);
+ if (buf->vb.state == VIDEOBUF_DONE ||
+ buf->vb.state == VIDEOBUF_ERROR)
+ return res | POLLIN | POLLRDNORM;
+ } else if (req_events & (POLLIN | POLLRDNORM)) {
/* read() capture */
- return videobuf_poll_stream(file, &fh->vb_vidq, wait);
+ return res | videobuf_poll_stream(file, &fh->vb_vidq, wait);
}
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE ||
- buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
- return 0;
+ return res;
}
static unsigned int tm6000_poll(struct file *file, struct poll_table_struct *wait)
@@ -1648,7 +1513,8 @@ static int tm6000_release(struct file *file)
if (!fh->radio)
videobuf_mmap_free(&fh->vb_vidq);
}
-
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
kfree(fh);
mutex_unlock(&dev->lock);
@@ -1688,9 +1554,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
@@ -1701,6 +1564,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device tm6000_template = {
@@ -1715,25 +1580,19 @@ static struct video_device tm6000_template = {
static const struct v4l2_file_operations radio_fops = {
.owner = THIS_MODULE,
.open = tm6000_open,
+ .poll = v4l2_ctrl_poll,
.release = tm6000_release,
.unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
- .vidioc_querycap = radio_querycap,
+ .vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = radio_g_tuner,
- .vidioc_enum_input = radio_enum_input,
- .vidioc_g_audio = radio_g_audio,
.vidioc_s_tuner = radio_s_tuner,
- .vidioc_s_audio = radio_s_audio,
- .vidioc_s_input = radio_s_input,
- .vidioc_s_std = radio_s_std,
- .vidioc_queryctrl = radio_queryctrl,
- .vidioc_g_input = radio_g_input,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device tm6000_radio_template = {
@@ -1762,6 +1621,7 @@ static struct video_device *vdev_init(struct tm6000_core *dev,
vfd->release = video_device_release;
vfd->debug = tm6000_debug;
vfd->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
@@ -1771,15 +1631,41 @@ static struct video_device *vdev_init(struct tm6000_core *dev,
int tm6000_v4l2_register(struct tm6000_core *dev)
{
- int ret = -1;
+ int ret = 0;
+
+ v4l2_ctrl_handler_init(&dev->ctrl_handler, 6);
+ v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 2);
+ v4l2_ctrl_new_std(&dev->radio_ctrl_handler, &tm6000_radio_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&dev->radio_ctrl_handler, &tm6000_radio_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, -15, 15, 1, 0);
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 54);
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 119);
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 112);
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ v4l2_ctrl_add_handler(&dev->ctrl_handler,
+ &dev->radio_ctrl_handler, NULL);
+
+ if (dev->radio_ctrl_handler.error)
+ ret = dev->radio_ctrl_handler.error;
+ if (!ret && dev->ctrl_handler.error)
+ ret = dev->ctrl_handler.error;
+ if (ret)
+ goto free_ctrl;
dev->vfd = vdev_init(dev, &tm6000_template, "video");
if (!dev->vfd) {
printk(KERN_INFO "%s: can't register video device\n",
dev->name);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_ctrl;
}
+ dev->vfd->ctrl_handler = &dev->ctrl_handler;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
@@ -1790,7 +1676,9 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
if (ret < 0) {
printk(KERN_INFO "%s: can't register video device\n",
dev->name);
- return ret;
+ video_device_release(dev->vfd);
+ dev->vfd = NULL;
+ goto free_ctrl;
}
printk(KERN_INFO "%s: registered device %s\n",
@@ -1803,15 +1691,17 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
printk(KERN_INFO "%s: can't register radio device\n",
dev->name);
ret = -ENXIO;
- return ret; /* FIXME release resource */
+ goto unreg_video;
}
+ dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
radio_nr);
if (ret < 0) {
printk(KERN_INFO "%s: can't register radio device\n",
dev->name);
- return ret; /* FIXME release resource */
+ video_device_release(dev->radio_dev);
+ goto unreg_video;
}
printk(KERN_INFO "%s: registered device %s\n",
@@ -1820,12 +1710,22 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
return ret;
+
+unreg_video:
+ video_unregister_device(dev->vfd);
+free_ctrl:
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
+ return ret;
}
int tm6000_v4l2_unregister(struct tm6000_core *dev)
{
video_unregister_device(dev->vfd);
+ /* if URB buffers are still allocated free them now */
+ tm6000_free_urb_buffers(dev);
+
if (dev->radio_dev) {
if (video_is_registered(dev->radio_dev))
video_unregister_device(dev->radio_dev);
@@ -1851,3 +1751,5 @@ MODULE_PARM_DESC(debug, "activates debug info");
module_param(vid_limit, int, 0644);
MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+module_param(keep_urb, bool, 0);
+MODULE_PARM_DESC(keep_urb, "Keep urb buffers allocated even when the device is closed by the user");
diff --git a/drivers/media/usb/tm6000/tm6000.h b/drivers/media/usb/tm6000/tm6000.h
index 6df418658c9c..08bd0740dd23 100644
--- a/drivers/media/usb/tm6000/tm6000.h
+++ b/drivers/media/usb/tm6000/tm6000.h
@@ -27,6 +27,8 @@
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
#include <linux/dvb/frontend.h>
#include "dvb_demux.h"
@@ -222,6 +224,8 @@ struct tm6000_core {
struct video_device *radio_dev;
struct tm6000_dmaqueue vidq;
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl_handler radio_ctrl_handler;
int input;
struct tm6000_input vinput[3]; /* video input */
@@ -264,6 +268,11 @@ struct tm6000_core {
spinlock_t slock;
+ /* urb dma buffers */
+ char **urb_buffer;
+ dma_addr_t *urb_dma;
+ unsigned int urb_size;
+
unsigned long quirks;
};
@@ -282,6 +291,7 @@ struct tm6000_ops {
};
struct tm6000_fh {
+ struct v4l2_fh fh;
struct tm6000_core *dev;
unsigned int radio;
diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
index 5b682cc4c814..e40718552850 100644
--- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
@@ -561,6 +561,13 @@ static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
{
u16 csum = 0, cc;
int i;
+
+ if (len < 4 || len & 0x1) {
+ pr_warn("%s: muxpack has invalid len %d\n", __func__, len);
+ numinvalid++;
+ return;
+ }
+
for (i = 0; i < len; i += 2)
csum ^= le16_to_cpup((__le16 *) (muxpack + i));
if (csum) {
diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c
index c9b2042f8bdf..816b1cffab7d 100644
--- a/drivers/media/usb/usbvision/usbvision-core.c
+++ b/drivers/media/usb/usbvision/usbvision-core.c
@@ -1169,7 +1169,7 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision)
if (newstate == parse_state_next_frame) {
frame->grabstate = frame_state_done;
- do_gettimeofday(&(frame->timestamp));
+ v4l2_get_timestamp(&(frame->timestamp));
frame->sequence = usbvision->frame_num;
spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
diff --git a/drivers/media/usb/usbvision/usbvision-i2c.c b/drivers/media/usb/usbvision/usbvision-i2c.c
index 89fec029e924..ba262a32bd3a 100644
--- a/drivers/media/usb/usbvision/usbvision-i2c.c
+++ b/drivers/media/usb/usbvision/usbvision-i2c.c
@@ -189,8 +189,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
if (usbvision->registered_i2c)
return 0;
- memcpy(&usbvision->i2c_adap, &i2c_adap_template,
- sizeof(struct i2c_adapter));
+ usbvision->i2c_adap = i2c_adap_template;
sprintf(usbvision->i2c_adap.name, "%s-%d-%s", i2c_adap_template.name,
usbvision->dev->bus->busnum, usbvision->dev->devpath);
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index ad7f7448072e..cd1fe78a5532 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -761,7 +761,7 @@ static int vidioc_querybuf(struct file *file,
if (vb->index >= usbvision->num_frames)
return -EINVAL;
/* Updating the corresponding frame state */
- vb->flags = 0;
+ vb->flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
frame = &usbvision->frame[vb->index];
if (frame->grabstate >= frame_state_ready)
vb->flags |= V4L2_BUF_FLAG_QUEUED;
@@ -843,7 +843,8 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *vb)
vb->memory = V4L2_MEMORY_MMAP;
vb->flags = V4L2_BUF_FLAG_MAPPED |
V4L2_BUF_FLAG_QUEUED |
- V4L2_BUF_FLAG_DONE;
+ V4L2_BUF_FLAG_DONE |
+ V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
vb->index = f->index;
vb->sequence = f->sequence;
vb->timestamp = f->timestamp;
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index d5baab17a5ef..61e28dec991d 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1838,7 +1838,7 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
{
int ret = 0;
- memcpy(&ctrl->info, info, sizeof(*info));
+ ctrl->info = *info;
INIT_LIST_HEAD(&ctrl->info.mappings);
/* Allocate an array to save control values (cur, def, max, etc.) */
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 778addc5caff..6c233a54ce40 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -115,11 +115,27 @@ static int uvc_buffer_finish(struct vb2_buffer *vb)
return 0;
}
+static void uvc_wait_prepare(struct vb2_queue *vq)
+{
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
+
+ mutex_unlock(&queue->mutex);
+}
+
+static void uvc_wait_finish(struct vb2_queue *vq)
+{
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
+
+ mutex_lock(&queue->mutex);
+}
+
static struct vb2_ops uvc_queue_qops = {
.queue_setup = uvc_queue_setup,
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
.buf_finish = uvc_buffer_finish,
+ .wait_prepare = uvc_wait_prepare,
+ .wait_finish = uvc_wait_finish,
};
int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 68d59b527492..b2dc32623a71 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -315,7 +315,7 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream,
goto done;
}
- memcpy(&stream->ctrl, &probe, sizeof probe);
+ stream->ctrl = probe;
stream->cur_format = format;
stream->cur_frame = frame;
@@ -387,7 +387,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
return -EBUSY;
}
- memcpy(&probe, &stream->ctrl, sizeof probe);
+ probe = stream->ctrl;
probe.dwFrameInterval =
uvc_try_frame_interval(stream->cur_frame, interval);
@@ -398,7 +398,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
return ret;
}
- memcpy(&stream->ctrl, &probe, sizeof probe);
+ stream->ctrl = probe;
mutex_unlock(&stream->mutex);
/* Return the actual frame period. */
@@ -501,8 +501,8 @@ static int uvc_v4l2_open(struct file *file)
if (atomic_inc_return(&stream->dev->users) == 1) {
ret = uvc_status_start(stream->dev);
if (ret < 0) {
- usb_autopm_put_interface(stream->dev->intf);
atomic_dec(&stream->dev->users);
+ usb_autopm_put_interface(stream->dev->intf);
kfree(handle);
return ret;
}
diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c
index 39edd4442932..74d56df3347f 100644
--- a/drivers/media/usb/zr364xx/zr364xx.c
+++ b/drivers/media/usb/zr364xx/zr364xx.c
@@ -501,7 +501,6 @@ static void zr364xx_fillbuff(struct zr364xx_camera *cam,
int jpgsize)
{
int pos = 0;
- struct timeval ts;
const char *tmpbuf;
char *vbuf = videobuf_to_vmalloc(&buf->vb);
unsigned long last_frame;
@@ -530,8 +529,7 @@ static void zr364xx_fillbuff(struct zr364xx_camera *cam,
/* tell v4l buffer was filled */
buf->vb.field_count = cam->frame_count * 2;
- do_gettimeofday(&ts);
- buf->vb.ts = ts;
+ v4l2_get_timestamp(&buf->vb.ts);
buf->vb.state = VIDEOBUF_DONE;
}
@@ -559,7 +557,7 @@ static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
goto unlock;
}
list_del(&buf->vb.queue);
- do_gettimeofday(&buf->vb.ts);
+ v4l2_get_timestamp(&buf->vb.ts);
DBG("[%p/%d] wakeup\n", buf, buf->vb.i);
zr364xx_fillbuff(cam, buf, jpgsize);
wake_up(&buf->vb.done);
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index 65875c3aba1b..976d029e9925 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -82,3 +82,14 @@ config VIDEOBUF2_DMA_SG
#depends on HAS_DMA
select VIDEOBUF2_CORE
select VIDEOBUF2_MEMOPS
+
+config VIDEO_V4L2_INT_DEVICE
+ tristate "V4L2 int device (DEPRECATED)"
+ depends on VIDEO_V4L2
+ ---help---
+ An early framework for a hardware-independent interface for
+ image sensors and bridges etc. Currently used by omap24xxcam and
+ tcm825x drivers that should be converted to V4L2 subdev.
+
+ Do not use for new developments.
+
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index c2d61d4f03d1..a9d355230e8e 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -10,7 +10,8 @@ ifeq ($(CONFIG_COMPAT),y)
videodev-objs += v4l2-compat-ioctl32.o
endif
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
+obj-$(CONFIG_VIDEO_DEV) += videodev.o
+obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o
obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index b5a819af2b8c..b5a8aac2e126 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -1013,6 +1013,11 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
t->standby = false;
analog_ops->set_params(&t->fe, &params);
+ /*
+ * The tuner driver might decide to change the audmode if it only
+ * supports stereo, so update t->audmode.
+ */
+ t->audmode = params.audmode;
}
/*
@@ -1235,8 +1240,18 @@ static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
if (set_mode(t, vt->type))
return 0;
- if (t->mode == V4L2_TUNER_RADIO)
+ if (t->mode == V4L2_TUNER_RADIO) {
t->audmode = vt->audmode;
+ /*
+ * For radio audmode can only be mono or stereo. Map any
+ * other values to stereo. The actual tuner driver that is
+ * called in set_radio_freq can decide to limit the audmode to
+ * mono if only mono is supported.
+ */
+ if (t->audmode != V4L2_TUNER_MODE_MONO &&
+ t->audmode != V4L2_TUNER_MODE_STEREO)
+ t->audmode = V4L2_TUNER_MODE_STEREO;
+ }
set_freq(t, 0);
return 0;
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 380ddd89fa4c..aa044f491666 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -238,7 +238,7 @@ int v4l2_chip_match_host(const struct v4l2_dbg_match *match)
}
EXPORT_SYMBOL(v4l2_chip_match_host);
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_I2C)
int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match *match)
{
int len;
@@ -384,7 +384,7 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr);
const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
{
static const unsigned short radio_addrs[] = {
-#if defined(CONFIG_MEDIA_TUNER_TEA5761) || defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE)
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761)
0x10,
#endif
0x60,
@@ -978,3 +978,13 @@ const struct v4l2_frmsize_discrete *v4l2_find_nearest_format(
return best;
}
EXPORT_SYMBOL_GPL(v4l2_find_nearest_format);
+
+void v4l2_get_timestamp(struct timeval *tv)
+{
+ struct timespec ts;
+
+ ktime_get_ts(&ts);
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+}
+EXPORT_SYMBOL_GPL(v4l2_get_timestamp);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index f6ee201d9347..6b28b5800500 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -577,8 +577,6 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_GAIN: return "Gain";
case V4L2_CID_HFLIP: return "Horizontal Flip";
case V4L2_CID_VFLIP: return "Vertical Flip";
- case V4L2_CID_HCENTER: return "Horizontal Center";
- case V4L2_CID_VCENTER: return "Vertical Center";
case V4L2_CID_POWER_LINE_FREQUENCY: return "Power Line Frequency";
case V4L2_CID_HUE_AUTO: return "Hue, Automatic";
case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature";
@@ -1160,8 +1158,7 @@ static int new_to_user(struct v4l2_ext_control *c,
}
/* Copy the new value to the current value. */
-static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
- bool update_inactive)
+static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
{
bool changed = false;
@@ -1185,8 +1182,8 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
ctrl->cur.val = ctrl->val;
break;
}
- if (update_inactive) {
- /* Note: update_inactive can only be true for auto clusters. */
+ if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
+ /* Note: CH_FLAGS is only set for auto clusters. */
ctrl->flags &=
~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE);
if (!is_cur_manual(ctrl->cluster[0])) {
@@ -1196,14 +1193,15 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
}
fh = NULL;
}
- if (changed || update_inactive) {
+ if (changed || ch_flags) {
/* If a control was changed that was not one of the controls
modified by the application, then send the event to all. */
if (!ctrl->is_new)
fh = NULL;
send_event(fh, ctrl,
- (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) |
- (update_inactive ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
+ (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | ch_flags);
+ if (ctrl->call_notify && changed && ctrl->handler->notify)
+ ctrl->handler->notify(ctrl, ctrl->handler->notify_priv);
}
}
@@ -1257,6 +1255,41 @@ static int cluster_changed(struct v4l2_ctrl *master)
return diff;
}
+/* Control range checking */
+static int check_range(enum v4l2_ctrl_type type,
+ s32 min, s32 max, u32 step, s32 def)
+{
+ switch (type) {
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ if (step != 1 || max > 1 || min < 0)
+ return -ERANGE;
+ /* fall through */
+ case V4L2_CTRL_TYPE_INTEGER:
+ if (step <= 0 || min > max || def < min || def > max)
+ return -ERANGE;
+ return 0;
+ case V4L2_CTRL_TYPE_BITMASK:
+ if (step || min || !max || (def & ~max))
+ return -ERANGE;
+ return 0;
+ case V4L2_CTRL_TYPE_MENU:
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ if (min > max || def < min || def > max)
+ return -ERANGE;
+ /* Note: step == menu_skip_mask for menu controls.
+ So here we check if the default value is masked out. */
+ if (step && ((1 << def) & step))
+ return -EINVAL;
+ return 0;
+ case V4L2_CTRL_TYPE_STRING:
+ if (min > max || min < 0 || step < 1 || def)
+ return -ERANGE;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
/* Validate a new control */
static int validate_new(const struct v4l2_ctrl *ctrl,
struct v4l2_ext_control *c)
@@ -1529,30 +1562,21 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
{
struct v4l2_ctrl *ctrl;
unsigned sz_extra = 0;
+ int err;
if (hdl->error)
return NULL;
/* Sanity checks */
if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
- (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
- (type == V4L2_CTRL_TYPE_BITMASK && max == 0) ||
(type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
- (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL) ||
- (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
- handler_set_err(hdl, -ERANGE);
- return NULL;
- }
- if (type != V4L2_CTRL_TYPE_BITMASK && max < min) {
+ (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
handler_set_err(hdl, -ERANGE);
return NULL;
}
- if ((type == V4L2_CTRL_TYPE_INTEGER ||
- type == V4L2_CTRL_TYPE_MENU ||
- type == V4L2_CTRL_TYPE_INTEGER_MENU ||
- type == V4L2_CTRL_TYPE_BOOLEAN) &&
- (def < min || def > max)) {
- handler_set_err(hdl, -ERANGE);
+ err = check_range(type, min, max, step, def);
+ if (err) {
+ handler_set_err(hdl, err);
return NULL;
}
if (type == V4L2_CTRL_TYPE_BITMASK && ((def & ~max) || min || step)) {
@@ -1980,6 +2004,13 @@ void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
}
EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
+int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd)
+{
+ v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_subdev_log_status);
+
/* Call s_ctrl for all controls owned by the handler */
int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
{
@@ -2426,8 +2457,8 @@ EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64);
/* Core function that calls try/s_ctrl and ensures that the new value is
copied to the current value on a set.
Must be called with ctrl->handler->lock held. */
-static int try_or_set_cluster(struct v4l2_fh *fh,
- struct v4l2_ctrl *master, bool set)
+static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
+ bool set, u32 ch_flags)
{
bool update_flag;
int ret;
@@ -2465,7 +2496,8 @@ static int try_or_set_cluster(struct v4l2_fh *fh,
/* If OK, then make the new values permanent. */
update_flag = is_cur_manual(master) != is_new_manual(master);
for (i = 0; i < master->ncontrols; i++)
- new_to_cur(fh, master->cluster[i], update_flag && i > 0);
+ new_to_cur(fh, master->cluster[i], ch_flags |
+ ((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
return 0;
}
@@ -2592,7 +2624,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
} while (!ret && idx);
if (!ret)
- ret = try_or_set_cluster(fh, master, set);
+ ret = try_or_set_cluster(fh, master, set, 0);
/* Copy the new values back to userspace. */
if (!ret) {
@@ -2638,10 +2670,9 @@ EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
/* Helper function for VIDIOC_S_CTRL compatibility */
static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
- struct v4l2_ext_control *c)
+ struct v4l2_ext_control *c, u32 ch_flags)
{
struct v4l2_ctrl *master = ctrl->cluster[0];
- int ret;
int i;
/* String controls are not supported. The user_to_new() and
@@ -2651,12 +2682,6 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
if (ctrl->type == V4L2_CTRL_TYPE_STRING)
return -EINVAL;
- ret = validate_new(ctrl, c);
- if (ret)
- return ret;
-
- v4l2_ctrl_lock(ctrl);
-
/* Reset the 'is_new' flags of the cluster */
for (i = 0; i < master->ncontrols; i++)
if (master->cluster[i])
@@ -2670,10 +2695,22 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
update_from_auto_cluster(master);
user_to_new(c, ctrl);
- ret = try_or_set_cluster(fh, master, true);
- cur_to_user(c, ctrl);
+ return try_or_set_cluster(fh, master, true, ch_flags);
+}
- v4l2_ctrl_unlock(ctrl);
+/* Helper function for VIDIOC_S_CTRL compatibility */
+static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
+ struct v4l2_ext_control *c)
+{
+ int ret = validate_new(ctrl, c);
+
+ if (!ret) {
+ v4l2_ctrl_lock(ctrl);
+ ret = set_ctrl(fh, ctrl, c, 0);
+ if (!ret)
+ cur_to_user(c, ctrl);
+ v4l2_ctrl_unlock(ctrl);
+ }
return ret;
}
@@ -2691,7 +2728,7 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
return -EACCES;
c.value = control->value;
- ret = set_ctrl(fh, ctrl, &c);
+ ret = set_ctrl_lock(fh, ctrl, &c);
control->value = c.value;
return ret;
}
@@ -2710,7 +2747,7 @@ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
/* It's a driver bug if this happens. */
WARN_ON(!type_is_int(ctrl));
c.value = val;
- return set_ctrl(NULL, ctrl, &c);
+ return set_ctrl_lock(NULL, ctrl, &c);
}
EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
@@ -2721,10 +2758,61 @@ int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
/* It's a driver bug if this happens. */
WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
c.value64 = val;
- return set_ctrl(NULL, ctrl, &c);
+ return set_ctrl_lock(NULL, ctrl, &c);
}
EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_int64);
+void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
+{
+ if (ctrl == NULL)
+ return;
+ if (notify == NULL) {
+ ctrl->call_notify = 0;
+ return;
+ }
+ if (WARN_ON(ctrl->handler->notify && ctrl->handler->notify != notify))
+ return;
+ ctrl->handler->notify = notify;
+ ctrl->handler->notify_priv = priv;
+ ctrl->call_notify = 1;
+}
+EXPORT_SYMBOL(v4l2_ctrl_notify);
+
+int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
+ s32 min, s32 max, u32 step, s32 def)
+{
+ int ret = check_range(ctrl->type, min, max, step, def);
+ struct v4l2_ext_control c;
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ case V4L2_CTRL_TYPE_MENU:
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ case V4L2_CTRL_TYPE_BITMASK:
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+ v4l2_ctrl_lock(ctrl);
+ ctrl->minimum = min;
+ ctrl->maximum = max;
+ ctrl->step = step;
+ ctrl->default_value = def;
+ c.value = ctrl->cur.val;
+ if (validate_new(ctrl, &c))
+ c.value = def;
+ if (c.value != ctrl->cur.val)
+ ret = set_ctrl(NULL, ctrl, &c, V4L2_EVENT_CTRL_CH_RANGE);
+ else
+ send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
+ v4l2_ctrl_unlock(ctrl);
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_modify_range);
+
static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
{
struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
@@ -2804,6 +2892,15 @@ int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
}
EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
+int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ if (!sd->ctrl_handler)
+ return -EINVAL;
+ return v4l2_ctrl_subscribe_event(fh, sub);
+}
+EXPORT_SYMBOL(v4l2_ctrl_subdev_subscribe_event);
+
unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)
{
struct v4l2_fh *fh = file->private_data;
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 98dcad9c8a3b..51b3a7713dcd 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -568,11 +568,6 @@ static void determine_valid_ioctls(struct video_device *vdev)
if (ops->vidioc_s_priority ||
test_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags))
set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls);
- SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
- SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
- SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf);
- SET_VALID_IOCTL(ops, VIDIOC_EXPBUF, vidioc_expbuf);
- SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf);
SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon);
SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
/* Note: the control handler can also be passed through the filehandle,
@@ -605,8 +600,6 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
SET_VALID_IOCTL(ops, VIDIOC_UNSUBSCRIBE_EVENT, vidioc_unsubscribe_event);
- SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs);
- SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator)
set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls);
@@ -672,6 +665,13 @@ static void determine_valid_ioctls(struct video_device *vdev)
}
if (!is_radio) {
/* ioctls valid for video or vbi */
+ SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
+ SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
+ SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_EXPBUF, vidioc_expbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs);
+ SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
if (ops->vidioc_s_std)
set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
if (ops->vidioc_g_std || vdev->current_norm)
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 513969fa695d..8ed5da2170bf 100644
--- a/drivers/media/v4l2-core/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
@@ -112,7 +112,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
/* Unregister subdevs */
list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {
v4l2_device_unregister_subdev(sd);
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_I2C)
if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -159,31 +159,21 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
sd->v4l2_dev = v4l2_dev;
if (sd->internal_ops && sd->internal_ops->registered) {
err = sd->internal_ops->registered(sd);
- if (err) {
- module_put(sd->owner);
- return err;
- }
+ if (err)
+ goto error_module;
}
/* This just returns 0 if either of the two args is NULL */
err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler, NULL);
- if (err) {
- if (sd->internal_ops && sd->internal_ops->unregistered)
- sd->internal_ops->unregistered(sd);
- module_put(sd->owner);
- return err;
- }
+ if (err)
+ goto error_unregister;
#if defined(CONFIG_MEDIA_CONTROLLER)
/* Register the entity. */
if (v4l2_dev->mdev) {
err = media_device_register_entity(v4l2_dev->mdev, entity);
- if (err < 0) {
- if (sd->internal_ops && sd->internal_ops->unregistered)
- sd->internal_ops->unregistered(sd);
- module_put(sd->owner);
- return err;
- }
+ if (err < 0)
+ goto error_unregister;
}
#endif
@@ -192,6 +182,14 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
spin_unlock(&v4l2_dev->lock);
return 0;
+
+error_unregister:
+ if (sd->internal_ops && sd->internal_ops->unregistered)
+ sd->internal_ops->unregistered(sd);
+error_module:
+ module_put(sd->owner);
+ sd->v4l2_dev = NULL;
+ return err;
}
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c
index c72009218152..86dcb5483c42 100644
--- a/drivers/media/v4l2-core/v4l2-event.c
+++ b/drivers/media/v4l2-core/v4l2-event.c
@@ -311,3 +311,10 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_event_unsubscribe);
+
+int v4l2_event_subdev_unsubscribe(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_unsubscribe(fh, sub);
+}
+EXPORT_SYMBOL_GPL(v4l2_event_subdev_unsubscribe);
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index 438ea45d1074..da99cf727162 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -62,7 +62,7 @@ struct v4l2_m2m_dev {
struct list_head job_queue;
spinlock_t job_spinlock;
- struct v4l2_m2m_ops *m2m_ops;
+ const struct v4l2_m2m_ops *m2m_ops;
};
static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
@@ -519,7 +519,7 @@ EXPORT_SYMBOL(v4l2_m2m_mmap);
*
* Usually called from driver's probe() function.
*/
-struct v4l2_m2m_dev *v4l2_m2m_init(struct v4l2_m2m_ops *m2m_ops)
+struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
{
struct v4l2_m2m_dev *m2m_dev;
diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c
index 5449e8aa984a..fb5ee5dd8fe9 100644
--- a/drivers/media/v4l2-core/videobuf-core.c
+++ b/drivers/media/v4l2-core/videobuf-core.c
@@ -340,7 +340,7 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
break;
}
- b->flags = 0;
+ b->flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
if (vb->map)
b->flags |= V4L2_BUF_FLAG_MAPPED;
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index e02c4797b1c6..db1235dcb328 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -40,9 +40,10 @@ module_param(debug, int, 0644);
#define call_qop(q, op, args...) \
(((q)->ops->op) ? ((q)->ops->op(args)) : 0)
-#define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
+#define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \
- V4L2_BUF_FLAG_PREPARED)
+ V4L2_BUF_FLAG_PREPARED | \
+ V4L2_BUF_FLAG_TIMESTAMP_MASK)
/**
* __vb2_buf_mem_alloc() - allocate video memory for the given buffer
@@ -401,7 +402,8 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
/*
* Clear any buffer state related flags.
*/
- b->flags &= ~V4L2_BUFFER_STATE_FLAGS;
+ b->flags &= ~V4L2_BUFFER_MASK_FLAGS;
+ b->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
switch (vb->state) {
case VB2_BUF_STATE_QUEUED:
@@ -941,7 +943,7 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
vb->v4l2_buf.field = b->field;
vb->v4l2_buf.timestamp = b->timestamp;
- vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;
+ vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS;
}
/**
@@ -1963,6 +1965,11 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
poll_wait(file, &fh->wait, wait);
}
+ if (!V4L2_TYPE_IS_OUTPUT(q->type) && !(req_events & (POLLIN | POLLRDNORM)))
+ return res;
+ if (V4L2_TYPE_IS_OUTPUT(q->type) && !(req_events & (POLLOUT | POLLWRNORM)))
+ return res;
+
/*
* Start file I/O emulator only if streaming API has not been used yet.
*/
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index 06d31c99e6ac..df0873694858 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -10,6 +10,7 @@
* 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/kernel.h>
#include <linux/reboot.h>
#include <linux/platform_data/emif_plat.h>
@@ -1468,12 +1469,9 @@ static int __init_or_module emif_probe(struct platform_device *pdev)
goto error;
}
- emif->base = devm_request_and_ioremap(emif->dev, res);
- if (!emif->base) {
- dev_err(emif->dev, "%s: devm_request_and_ioremap() failed\n",
- __func__);
+ emif->base = devm_ioremap_resource(emif->dev, res);
+ if (IS_ERR(emif->base))
goto error;
- }
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
diff --git a/drivers/memory/tegra20-mc.c b/drivers/memory/tegra20-mc.c
index 186f27d9e5f1..2ca5f2814f4a 100644
--- a/drivers/memory/tegra20-mc.c
+++ b/drivers/memory/tegra20-mc.c
@@ -17,6 +17,7 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ratelimit.h>
@@ -216,9 +217,9 @@ static int tegra20_mc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res)
return -ENODEV;
- mc->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
- if (!mc->regs[i])
- return -EBUSY;
+ mc->regs[i] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mc->regs[i]))
+ return PTR_ERR(mc->regs[i]);
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
diff --git a/drivers/memory/tegra30-mc.c b/drivers/memory/tegra30-mc.c
index 0b7ab9332a18..0b975986777d 100644
--- a/drivers/memory/tegra30-mc.c
+++ b/drivers/memory/tegra30-mc.c
@@ -17,6 +17,7 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ratelimit.h>
@@ -336,9 +337,9 @@ static int tegra30_mc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res)
return -ENODEV;
- mc->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
- if (!mc->regs[i])
- return -EBUSY;
+ mc->regs[i] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mc->regs[i]))
+ return PTR_ERR(mc->regs[i]);
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
diff --git a/drivers/memstick/Kconfig b/drivers/memstick/Kconfig
index f0ca41c20323..1314605d791f 100644
--- a/drivers/memstick/Kconfig
+++ b/drivers/memstick/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig MEMSTICK
- tristate "Sony MemoryStick card support (EXPERIMENTAL)"
+ tristate "Sony MemoryStick card support"
help
Sony MemoryStick is a proprietary storage/extension card protocol.
diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig
index 4f7a17fd1aa7..1b37cf8cd204 100644
--- a/drivers/memstick/host/Kconfig
+++ b/drivers/memstick/host/Kconfig
@@ -5,8 +5,8 @@
comment "MemoryStick Host Controller Drivers"
config MEMSTICK_TIFM_MS
- tristate "TI Flash Media MemoryStick Interface support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PCI
+ tristate "TI Flash Media MemoryStick Interface support "
+ depends on PCI
select TIFM_CORE
help
Say Y here if you want to be able to access MemoryStick cards with
@@ -21,8 +21,8 @@ config MEMSTICK_TIFM_MS
module will be called tifm_ms.
config MEMSTICK_JMICRON_38X
- tristate "JMicron JMB38X MemoryStick interface support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PCI
+ tristate "JMicron JMB38X MemoryStick interface support"
+ depends on PCI
help
Say Y here if you want to be able to access MemoryStick cards with
@@ -32,8 +32,8 @@ config MEMSTICK_JMICRON_38X
module will be called jmb38x_ms.
config MEMSTICK_R592
- tristate "Ricoh R5C592 MemoryStick interface support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PCI
+ tristate "Ricoh R5C592 MemoryStick interface support"
+ depends on PCI
help
Say Y here if you want to be able to access MemoryStick cards with
diff --git a/drivers/memstick/host/rtsx_pci_ms.c b/drivers/memstick/host/rtsx_pci_ms.c
index f5ddb82dadb7..64a779c58a74 100644
--- a/drivers/memstick/host/rtsx_pci_ms.c
+++ b/drivers/memstick/host/rtsx_pci_ms.c
@@ -426,6 +426,9 @@ static void rtsx_pci_ms_request(struct memstick_host *msh)
dev_dbg(ms_dev(host), "--> %s\n", __func__);
+ if (rtsx_pci_card_exclusive_check(host->pcr, RTSX_MS_CARD))
+ return;
+
schedule_work(&host->handle_req);
}
@@ -441,6 +444,10 @@ static int rtsx_pci_ms_set_param(struct memstick_host *msh,
dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n",
__func__, param, value);
+ err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_MS_CARD);
+ if (err)
+ return err;
+
switch (param) {
case MEMSTICK_POWER:
if (value == MEMSTICK_POWER_ON)
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
index 391e23e6a647..582bda543520 100644
--- a/drivers/mfd/88pm800.c
+++ b/drivers/mfd/88pm800.c
@@ -531,7 +531,7 @@ static int pm800_probe(struct i2c_client *client,
ret = device_800_init(chip, pdata);
if (ret) {
dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
- goto err_800_init;
+ goto err_subchip_alloc;
}
ret = pm800_pages_init(chip);
@@ -546,10 +546,8 @@ static int pm800_probe(struct i2c_client *client,
err_page_init:
mfd_remove_devices(chip->dev);
device_irq_exit_800(chip);
-err_800_init:
- devm_kfree(&client->dev, subchip);
err_subchip_alloc:
- pm80x_deinit(client);
+ pm80x_deinit();
out_init:
return ret;
}
@@ -562,9 +560,7 @@ static int pm800_remove(struct i2c_client *client)
device_irq_exit_800(chip);
pm800_pages_exit(chip);
- devm_kfree(&client->dev, chip->subchip);
-
- pm80x_deinit(client);
+ pm80x_deinit();
return 0;
}
diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c
index e671230be2b1..65d7ac099b20 100644
--- a/drivers/mfd/88pm805.c
+++ b/drivers/mfd/88pm805.c
@@ -257,7 +257,7 @@ static int pm805_probe(struct i2c_client *client,
pdata->plat_config(chip, pdata);
err_805_init:
- pm80x_deinit(client);
+ pm80x_deinit();
out_init:
return ret;
}
@@ -269,7 +269,7 @@ static int pm805_remove(struct i2c_client *client)
mfd_remove_devices(chip->dev);
device_irq_exit_805(chip);
- pm80x_deinit(client);
+ pm80x_deinit();
return 0;
}
diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c
index 1adb355d86d1..f736a46eb8c0 100644
--- a/drivers/mfd/88pm80x.c
+++ b/drivers/mfd/88pm80x.c
@@ -48,14 +48,12 @@ int pm80x_init(struct i2c_client *client,
ret = PTR_ERR(map);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
- goto err_regmap_init;
+ return ret;
}
chip->id = id->driver_data;
- if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805) {
- ret = -EINVAL;
- goto err_chip_id;
- }
+ if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805)
+ return -EINVAL;
chip->client = client;
chip->regmap = map;
@@ -82,19 +80,11 @@ int pm80x_init(struct i2c_client *client,
}
return 0;
-
-err_chip_id:
- regmap_exit(map);
-err_regmap_init:
- devm_kfree(&client->dev, chip);
- return ret;
}
EXPORT_SYMBOL_GPL(pm80x_init);
-int pm80x_deinit(struct i2c_client *client)
+int pm80x_deinit(void)
{
- struct pm80x_chip *chip = i2c_get_clientdata(client);
-
/*
* workaround: clear the dependency between pm800 and pm805.
* would remove it after HW chip fixes the issue.
@@ -103,10 +93,6 @@ int pm80x_deinit(struct i2c_client *client)
g_pm80x_chip->companion = NULL;
else
g_pm80x_chip = NULL;
-
- regmap_exit(chip->regmap);
- devm_kfree(&client->dev, chip);
-
return 0;
}
EXPORT_SYMBOL_GPL(pm80x_deinit);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ff553babf455..671f5b171c73 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -65,7 +65,7 @@ config MFD_SM501_GPIO
config MFD_RTSX_PCI
tristate "Support for Realtek PCI-E card reader"
- depends on PCI
+ depends on PCI && GENERIC_HARDIRQS
select MFD_CORE
help
This supports for Realtek PCI-Express card reader including rts5209,
@@ -95,7 +95,7 @@ config MFD_DM355EVM_MSP
config MFD_TI_SSP
tristate "TI Sequencer Serial Port support"
- depends on ARCH_DAVINCI_TNETV107X
+ depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS
select MFD_CORE
---help---
Say Y here if you want support for the Sequencer Serial Port
@@ -109,6 +109,7 @@ config MFD_TI_AM335X_TSCADC
select MFD_CORE
select REGMAP
select REGMAP_MMIO
+ depends on GENERIC_HARDIRQS
help
If you say yes here you get support for Texas Instruments series
of Touch Screen /ADC chips.
@@ -126,6 +127,7 @@ config HTC_EGPIO
config HTC_PASIC3
tristate "HTC PASIC3 LED/DS1WM chip support"
select MFD_CORE
+ depends on GENERIC_HARDIRQS
help
This core driver provides register access for the LED/DS1WM
chips labeled "AIC2" and "AIC3", found on HTC Blueangel and
@@ -157,6 +159,7 @@ config MFD_LM3533
depends on I2C
select MFD_CORE
select REGMAP_I2C
+ depends on GENERIC_HARDIRQS
help
Say yes here to enable support for National Semiconductor / TI
LM3533 Lighting Power chips.
@@ -171,6 +174,7 @@ config TPS6105X
select REGULATOR
select MFD_CORE
select REGULATOR_FIXED_VOLTAGE
+ depends on GENERIC_HARDIRQS
help
This option enables a driver for the TP61050/TPS61052
high-power "white LED driver". This boost converter is
@@ -193,7 +197,7 @@ config TPS65010
config TPS6507X
tristate "TPS6507x Power Management / Touch Screen chips"
select MFD_CORE
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
help
If you say yes here you get support for the TPS6507x series of
Power Management / Touch Screen chips. These include voltage
@@ -204,7 +208,7 @@ config TPS6507X
config MFD_TPS65217
tristate "TPS65217 Power Management / White LED chips"
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
help
@@ -234,7 +238,7 @@ config MFD_TPS6586X
config MFD_TPS65910
bool "TPS65910 Power Management chip"
- depends on I2C=y && GPIOLIB
+ depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
@@ -251,7 +255,7 @@ config MFD_TPS65912_I2C
bool "TPS65912 Power Management chip with I2C"
select MFD_CORE
select MFD_TPS65912
- depends on I2C=y && GPIOLIB
+ depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
help
If you say yes here you get support for the TPS65912 series of
PM chips with I2C interface.
@@ -260,7 +264,7 @@ config MFD_TPS65912_SPI
bool "TPS65912 Power Management chip with SPI"
select MFD_CORE
select MFD_TPS65912
- depends on SPI_MASTER && GPIOLIB
+ depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS
help
If you say yes here you get support for the TPS65912 series of
PM chips with SPI interface.
@@ -330,13 +334,13 @@ config TWL4030_POWER
config MFD_TWL4030_AUDIO
bool
- depends on TWL4030_CORE
+ depends on TWL4030_CORE && GENERIC_HARDIRQS
select MFD_CORE
default n
config TWL6040_CORE
bool "Support for TWL6040 audio codec"
- depends on I2C=y
+ depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
@@ -405,7 +409,7 @@ config MFD_TMIO
config MFD_T7L66XB
bool "Support Toshiba T7L66XB"
- depends on ARM && HAVE_CLK
+ depends on ARM && HAVE_CLK && GENERIC_HARDIRQS
select MFD_CORE
select MFD_TMIO
help
@@ -413,7 +417,7 @@ config MFD_T7L66XB
config MFD_SMSC
bool "Support for the SMSC ECE1099 series chips"
- depends on I2C=y
+ depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
help
@@ -460,7 +464,7 @@ config MFD_DA9052_SPI
select REGMAP_SPI
select REGMAP_IRQ
select PMIC_DA9052
- depends on SPI_MASTER=y
+ depends on SPI_MASTER=y && GENERIC_HARDIRQS
help
Support for the Dialog Semiconductor DA9052 PMIC
when controlled using SPI. This driver provides common support
@@ -472,7 +476,7 @@ config MFD_DA9052_I2C
select REGMAP_I2C
select REGMAP_IRQ
select PMIC_DA9052
- depends on I2C=y
+ depends on I2C=y && GENERIC_HARDIRQS
help
Support for the Dialog Semiconductor DA9052 PMIC
when controlled using I2C. This driver provides common support
@@ -485,7 +489,7 @@ config MFD_DA9055
select REGMAP_IRQ
select PMIC_DA9055
select MFD_CORE
- depends on I2C=y
+ depends on I2C=y && GENERIC_HARDIRQS
help
Say yes here for support of Dialog Semiconductor DA9055. This is
a Power Management IC. This driver provides common support for
@@ -508,7 +512,7 @@ config PMIC_ADP5520
config MFD_LP8788
bool "Texas Instruments LP8788 Power Management Unit Driver"
- depends on I2C=y
+ depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
select IRQ_DOMAIN
@@ -611,7 +615,7 @@ config MFD_ARIZONA_I2C
select MFD_ARIZONA
select MFD_CORE
select REGMAP_I2C
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
help
Support for the Wolfson Microelectronics Arizona platform audio SoC
core functionality controlled via I2C.
@@ -621,7 +625,7 @@ config MFD_ARIZONA_SPI
select MFD_ARIZONA
select MFD_CORE
select REGMAP_SPI
- depends on SPI_MASTER
+ depends on SPI_MASTER && GENERIC_HARDIRQS
help
Support for the Wolfson Microelectronics Arizona platform audio SoC
core functionality controlled via I2C.
@@ -641,7 +645,7 @@ config MFD_WM5110
config MFD_WM8400
bool "Support Wolfson Microelectronics WM8400"
select MFD_CORE
- depends on I2C=y
+ depends on I2C=y && GENERIC_HARDIRQS
select REGMAP_I2C
help
Support for the Wolfson Microelecronics WM8400 PMIC and audio
@@ -785,7 +789,7 @@ config MFD_MC13783
config MFD_MC13XXX
tristate
- depends on SPI_MASTER || I2C
+ depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS
select MFD_CORE
select MFD_MC13783
help
@@ -796,7 +800,7 @@ config MFD_MC13XXX
config MFD_MC13XXX_SPI
tristate "Freescale MC13783 and MC13892 SPI interface"
- depends on SPI_MASTER
+ depends on SPI_MASTER && GENERIC_HARDIRQS
select REGMAP_SPI
select MFD_MC13XXX
help
@@ -804,7 +808,7 @@ config MFD_MC13XXX_SPI
config MFD_MC13XXX_I2C
tristate "Freescale MC13892 I2C interface"
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
select REGMAP_I2C
select MFD_MC13XXX
help
@@ -822,7 +826,7 @@ config ABX500_CORE
config AB3100_CORE
bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
- depends on I2C=y && ABX500_CORE
+ depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS
select MFD_CORE
default y if ARCH_U300
help
@@ -909,7 +913,7 @@ config MFD_TIMBERDALE
config LPC_SCH
tristate "Intel SCH LPC"
- depends on PCI
+ depends on PCI && GENERIC_HARDIRQS
select MFD_CORE
help
LPC bridge function of the Intel SCH provides support for
@@ -917,7 +921,7 @@ config LPC_SCH
config LPC_ICH
tristate "Intel ICH LPC"
- depends on PCI
+ depends on PCI && GENERIC_HARDIRQS
select MFD_CORE
help
The LPC bridge function of the Intel ICH provides support for
@@ -928,7 +932,7 @@ config LPC_ICH
config MFD_RDC321X
tristate "Support for RDC-R321x southbridge"
select MFD_CORE
- depends on PCI
+ depends on PCI && GENERIC_HARDIRQS
help
Say yes here if you want to have support for the RDC R-321x SoC
southbridge which provides access to GPIOs and Watchdog using the
@@ -937,7 +941,7 @@ config MFD_RDC321X
config MFD_JANZ_CMODIO
tristate "Support for Janz CMOD-IO PCI MODULbus Carrier Board"
select MFD_CORE
- depends on PCI
+ depends on PCI && GENERIC_HARDIRQS
help
This is the core driver for the Janz CMOD-IO PCI MODULbus
carrier board. This device is a PCI to MODULbus bridge which may
@@ -955,7 +959,7 @@ config MFD_JZ4740_ADC
config MFD_VX855
tristate "Support for VIA VX855/VX875 integrated south bridge"
- depends on PCI
+ depends on PCI && GENERIC_HARDIRQS
select MFD_CORE
help
Say yes here to enable support for various functions of the
@@ -964,7 +968,7 @@ config MFD_VX855
config MFD_WL1273_CORE
tristate "Support for TI WL1273 FM radio."
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
select MFD_CORE
default n
help
@@ -1028,7 +1032,7 @@ config MFD_TPS65090
config MFD_AAT2870_CORE
bool "Support for the AnalogicTech AAT2870"
select MFD_CORE
- depends on I2C=y && GPIOLIB
+ depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
help
If you say yes here you get support for the AAT2870.
This driver provides common support for accessing the device,
@@ -1060,7 +1064,7 @@ config MFD_RC5T583
config MFD_STA2X11
bool "STA2X11 multi function device support"
- depends on STA2X11
+ depends on STA2X11 && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_MMIO
@@ -1077,7 +1081,7 @@ config MFD_PALMAS
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
- depends on I2C=y
+ depends on I2C=y && GENERIC_HARDIRQS
help
If you say yes here you get support for the Palmas
series of PMIC chips from Texas Instruments.
@@ -1085,7 +1089,7 @@ config MFD_PALMAS
config MFD_VIPERBOARD
tristate "Support for Nano River Technologies Viperboard"
select MFD_CORE
- depends on USB
+ depends on USB && GENERIC_HARDIRQS
default n
help
Say yes here if you want support for Nano River Technologies
@@ -1099,7 +1103,7 @@ config MFD_VIPERBOARD
config MFD_RETU
tristate "Support for Retu multi-function device"
select MFD_CORE
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
select REGMAP_IRQ
help
Retu is a multi-function device found on Nokia Internet Tablets
@@ -1110,7 +1114,7 @@ config MFD_AS3711
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
- depends on I2C=y
+ depends on I2C=y && GENERIC_HARDIRQS
help
Support for the AS3711 PMIC from AMS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 8b977f8045ae..b90409c23664 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o
obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
-rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o
+rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 4778bb124efe..7c84ced2e01b 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -320,6 +320,7 @@ static struct abx500_ops ab8500_ops = {
.mask_and_set_register = ab8500_mask_and_set_register,
.event_registers_startup_state_get = NULL,
.startup_irq_enabled = NULL,
+ .dump_all_banks = ab8500_dump_all_banks,
};
static void ab8500_irq_lock(struct irq_data *data)
@@ -368,16 +369,48 @@ static void ab8500_irq_mask(struct irq_data *data)
int mask = 1 << (offset % 8);
ab8500->mask[index] |= mask;
+
+ /* The AB8500 GPIOs have two interrupts each (rising & falling). */
+ if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
+ ab8500->mask[index + 2] |= mask;
+ if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
+ ab8500->mask[index + 1] |= mask;
+ if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
+ /* Here the falling IRQ is one bit lower */
+ ab8500->mask[index] |= (mask << 1);
}
static void ab8500_irq_unmask(struct irq_data *data)
{
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
+ unsigned int type = irqd_get_trigger_type(data);
int offset = data->hwirq;
int index = offset / 8;
int mask = 1 << (offset % 8);
- ab8500->mask[index] &= ~mask;
+ if (type & IRQ_TYPE_EDGE_RISING)
+ ab8500->mask[index] &= ~mask;
+
+ /* The AB8500 GPIOs have two interrupts each (rising & falling). */
+ if (type & IRQ_TYPE_EDGE_FALLING) {
+ if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R)
+ ab8500->mask[index + 2] &= ~mask;
+ else if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R)
+ ab8500->mask[index + 1] &= ~mask;
+ else if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R)
+ /* Here the falling IRQ is one bit lower */
+ ab8500->mask[index] &= ~(mask << 1);
+ else
+ ab8500->mask[index] &= ~mask;
+ } else {
+ /* Satisfies the case where type is not set. */
+ ab8500->mask[index] &= ~mask;
+ }
+}
+
+static int ab8500_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ return 0;
}
static struct irq_chip ab8500_irq_chip = {
@@ -387,6 +420,7 @@ static struct irq_chip ab8500_irq_chip = {
.irq_mask = ab8500_irq_mask,
.irq_disable = ab8500_irq_mask,
.irq_unmask = ab8500_irq_unmask,
+ .irq_set_type = ab8500_irq_set_type,
};
static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
@@ -411,6 +445,19 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
line = (i << 3) + int_bit;
latch_val &= ~(1 << int_bit);
+ /*
+ * This handles the falling edge hwirqs from the GPIO
+ * lines. Route them back to the line registered for the
+ * rising IRQ, as this is merely a flag for the same IRQ
+ * in linux terms.
+ */
+ if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F)
+ line -= 16;
+ if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F)
+ line -= 8;
+ if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F)
+ line += 1;
+
handle_nested_irq(ab8500->irq_base + line);
} while (latch_val);
@@ -521,6 +568,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
int virq = ab8500_irq_get_virq(ab8500, line);
handle_nested_irq(virq);
+ ab8500_debug_register_interrupt(line);
value &= ~(1 << bit);
} while (value);
@@ -750,6 +798,12 @@ static struct resource ab8500_charger_resources[] = {
.end = AB8500_INT_CH_WD_EXP,
.flags = IORESOURCE_IRQ,
},
+ {
+ .name = "VBUS_CH_DROP_END",
+ .start = AB8500_INT_VBUS_CH_DROP_END,
+ .end = AB8500_INT_VBUS_CH_DROP_END,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct resource ab8500_btemp_resources[] = {
@@ -923,7 +977,7 @@ static struct resource ab8505_iddet_resources[] = {
static struct resource ab8500_temp_resources[] = {
{
- .name = "AB8500_TEMP_WARM",
+ .name = "ABX500_TEMP_WARM",
.start = AB8500_INT_TEMP_WARM,
.end = AB8500_INT_TEMP_WARM,
.flags = IORESOURCE_IRQ,
@@ -999,8 +1053,8 @@ static struct mfd_cell abx500_common_devs[] = {
.of_compatible = "stericsson,ab8500-denc",
},
{
- .name = "ab8500-temp",
- .of_compatible = "stericsson,ab8500-temp",
+ .name = "abx500-temp",
+ .of_compatible = "stericsson,abx500-temp",
.num_resources = ARRAY_SIZE(ab8500_temp_resources),
.resources = ab8500_temp_resources,
},
@@ -1012,46 +1066,38 @@ static struct mfd_cell ab8500_bm_devs[] = {
.of_compatible = "stericsson,ab8500-charger",
.num_resources = ARRAY_SIZE(ab8500_charger_resources),
.resources = ab8500_charger_resources,
-#ifndef CONFIG_OF
.platform_data = &ab8500_bm_data,
.pdata_size = sizeof(ab8500_bm_data),
-#endif
},
{
.name = "ab8500-btemp",
.of_compatible = "stericsson,ab8500-btemp",
.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
.resources = ab8500_btemp_resources,
-#ifndef CONFIG_OF
.platform_data = &ab8500_bm_data,
.pdata_size = sizeof(ab8500_bm_data),
-#endif
},
{
.name = "ab8500-fg",
.of_compatible = "stericsson,ab8500-fg",
.num_resources = ARRAY_SIZE(ab8500_fg_resources),
.resources = ab8500_fg_resources,
-#ifndef CONFIG_OF
.platform_data = &ab8500_bm_data,
.pdata_size = sizeof(ab8500_bm_data),
-#endif
},
{
.name = "ab8500-chargalg",
.of_compatible = "stericsson,ab8500-chargalg",
.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
.resources = ab8500_chargalg_resources,
-#ifndef CONFIG_OF
.platform_data = &ab8500_bm_data,
.pdata_size = sizeof(ab8500_bm_data),
-#endif
},
};
static struct mfd_cell ab8500_devs[] = {
{
- .name = "ab8500-gpio",
+ .name = "pinctrl-ab8500",
.of_compatible = "stericsson,ab8500-gpio",
},
{
@@ -1068,7 +1114,8 @@ static struct mfd_cell ab8500_devs[] = {
static struct mfd_cell ab9540_devs[] = {
{
- .name = "ab8500-gpio",
+ .name = "pinctrl-ab9540",
+ .of_compatible = "stericsson,ab9540-gpio",
},
{
.name = "ab9540-usb",
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 5a8e707bc038..45fe3c50eb03 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -4,6 +4,72 @@
* Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
* License Terms: GNU General Public License v2
*/
+/*
+ * AB8500 register access
+ * ======================
+ *
+ * read:
+ * # echo BANK > <debugfs>/ab8500/register-bank
+ * # echo ADDR > <debugfs>/ab8500/register-address
+ * # cat <debugfs>/ab8500/register-value
+ *
+ * write:
+ * # echo BANK > <debugfs>/ab8500/register-bank
+ * # echo ADDR > <debugfs>/ab8500/register-address
+ * # echo VALUE > <debugfs>/ab8500/register-value
+ *
+ * read all registers from a bank:
+ * # echo BANK > <debugfs>/ab8500/register-bank
+ * # cat <debugfs>/ab8500/all-bank-register
+ *
+ * BANK target AB8500 register bank
+ * ADDR target AB8500 register address
+ * VALUE decimal or 0x-prefixed hexadecimal
+ *
+ *
+ * User Space notification on AB8500 IRQ
+ * =====================================
+ *
+ * Allows user space entity to be notified when target AB8500 IRQ occurs.
+ * When subscribed, a sysfs entry is created in ab8500.i2c platform device.
+ * One can pool this file to get target IRQ occurence information.
+ *
+ * subscribe to an AB8500 IRQ:
+ * # echo IRQ > <debugfs>/ab8500/irq-subscribe
+ *
+ * unsubscribe from an AB8500 IRQ:
+ * # echo IRQ > <debugfs>/ab8500/irq-unsubscribe
+ *
+ *
+ * AB8500 register formated read/write access
+ * ==========================================
+ *
+ * Read: read data, data>>SHIFT, data&=MASK, output data
+ * [0xABCDEF98] shift=12 mask=0xFFF => 0x00000CDE
+ * Write: read data, data &= ~(MASK<<SHIFT), data |= (VALUE<<SHIFT), write data
+ * [0xABCDEF98] shift=12 mask=0xFFF value=0x123 => [0xAB123F98]
+ *
+ * Usage:
+ * # echo "CMD [OPTIONS] BANK ADRESS [VALUE]" > $debugfs/ab8500/hwreg
+ *
+ * CMD read read access
+ * write write access
+ *
+ * BANK target reg bank
+ * ADDRESS target reg address
+ * VALUE (write) value to be updated
+ *
+ * OPTIONS
+ * -d|-dec (read) output in decimal
+ * -h|-hexa (read) output in 0x-hexa (default)
+ * -l|-w|-b 32bit (default), 16bit or 8bit reg access
+ * -m|-mask MASK 0x-hexa mask (default 0xFFFFFFFF)
+ * -s|-shift SHIFT bit shift value (read:left, write:right)
+ * -o|-offset OFFSET address offset to add to ADDRESS value
+ *
+ * Warning: bit shift operation is applied to bit-mask.
+ * Warning: bit shift direction depends on read or right command.
+ */
#include <linux/seq_file.h>
#include <linux/uaccess.h>
@@ -11,13 +77,30 @@
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/string.h>
+#include <linux/ctype.h>
+#endif
static u32 debug_bank;
static u32 debug_address;
+static int irq_first;
+static int irq_last;
+static u32 *irq_count;
+static int num_irqs;
+
+static struct device_attribute **dev_attr;
+static char **event_name;
+
/**
* struct ab8500_reg_range
* @first: the first address of the range
@@ -42,15 +125,35 @@ struct ab8500_prcmu_ranges {
const struct ab8500_reg_range *range;
};
+/* hwreg- "mask" and "shift" entries ressources */
+struct hwreg_cfg {
+ u32 bank; /* target bank */
+ u32 addr; /* target address */
+ uint fmt; /* format */
+ uint mask; /* read/write mask, applied before any bit shift */
+ int shift; /* bit shift (read:right shift, write:left shift */
+};
+/* fmt bit #0: 0=hexa, 1=dec */
+#define REG_FMT_DEC(c) ((c)->fmt & 0x1)
+#define REG_FMT_HEX(c) (!REG_FMT_DEC(c))
+
+static struct hwreg_cfg hwreg_cfg = {
+ .addr = 0, /* default: invalid phys addr */
+ .fmt = 0, /* default: 32bit access, hex output */
+ .mask = 0xFFFFFFFF, /* default: no mask */
+ .shift = 0, /* default: no bit shift */
+};
+
#define AB8500_NAME_STRING "ab8500"
-#define AB8500_NUM_BANKS 22
+#define AB8500_ADC_NAME_STRING "gpadc"
+#define AB8500_NUM_BANKS 24
#define AB8500_REV_REG 0x80
static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
[0x0] = {
.num_ranges = 0,
- .range = 0,
+ .range = NULL,
},
[AB8500_SYS_CTRL1_BLOCK] = {
.num_ranges = 3,
@@ -215,7 +318,7 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
},
},
[AB8500_CHARGER] = {
- .num_ranges = 8,
+ .num_ranges = 9,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
@@ -249,6 +352,10 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
.first = 0xC0,
.last = 0xC2,
},
+ {
+ .first = 0xf5,
+ .last = 0xf6,
+ },
},
},
[AB8500_GAS_GAUGE] = {
@@ -268,6 +375,24 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
},
},
},
+ [AB8500_DEVELOPMENT] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ },
+ },
+ [AB8500_DEBUG] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x05,
+ .last = 0x07,
+ },
+ },
+ },
[AB8500_AUDIO] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
@@ -354,15 +479,30 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
},
};
-static int ab8500_registers_print(struct seq_file *s, void *p)
+static irqreturn_t ab8500_debug_handler(int irq, void *data)
{
- struct device *dev = s->private;
- unsigned int i;
- u32 bank = debug_bank;
+ char buf[16];
+ struct kobject *kobj = (struct kobject *)data;
+ unsigned int irq_abb = irq - irq_first;
- seq_printf(s, AB8500_NAME_STRING " register values:\n");
+ if (irq_abb < num_irqs)
+ irq_count[irq_abb]++;
+ /*
+ * This makes it possible to use poll for events (POLLPRI | POLLERR)
+ * from userspace on sysfs file named <irq-nr>
+ */
+ sprintf(buf, "%d", irq);
+ sysfs_notify(kobj, NULL, buf);
+
+ return IRQ_HANDLED;
+}
+
+/* Prints to seq_file or log_buf */
+static int ab8500_registers_print(struct device *dev, u32 bank,
+ struct seq_file *s)
+{
+ unsigned int i;
- seq_printf(s, " bank %u:\n", bank);
for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
u32 reg;
@@ -379,22 +519,42 @@ static int ab8500_registers_print(struct seq_file *s, void *p)
return err;
}
- err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank,
- reg, value);
- if (err < 0) {
- dev_err(dev, "seq_printf overflow\n");
- /* Error is not returned here since
- * the output is wanted in any case */
- return 0;
+ if (s) {
+ err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n",
+ bank, reg, value);
+ if (err < 0) {
+ dev_err(dev,
+ "seq_printf overflow bank=%d reg=%d\n",
+ bank, reg);
+ /* Error is not returned here since
+ * the output is wanted in any case */
+ return 0;
+ }
+ } else {
+ printk(KERN_INFO" [%u/0x%02X]: 0x%02X\n", bank,
+ reg, value);
}
}
}
return 0;
}
+static int ab8500_print_bank_registers(struct seq_file *s, void *p)
+{
+ struct device *dev = s->private;
+ u32 bank = debug_bank;
+
+ seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+ seq_printf(s, " bank %u:\n", bank);
+
+ ab8500_registers_print(dev, bank, s);
+ return 0;
+}
+
static int ab8500_registers_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_registers_print, inode->i_private);
+ return single_open(file, ab8500_print_bank_registers, inode->i_private);
}
static const struct file_operations ab8500_registers_fops = {
@@ -405,6 +565,64 @@ static const struct file_operations ab8500_registers_fops = {
.owner = THIS_MODULE,
};
+static int ab8500_print_all_banks(struct seq_file *s, void *p)
+{
+ struct device *dev = s->private;
+ unsigned int i;
+ int err;
+
+ seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+ for (i = 1; i < AB8500_NUM_BANKS; i++) {
+ err = seq_printf(s, " bank %u:\n", i);
+ if (err < 0)
+ dev_err(dev, "seq_printf overflow, bank=%d\n", i);
+
+ ab8500_registers_print(dev, i, s);
+ }
+ return 0;
+}
+
+/* Dump registers to kernel log */
+void ab8500_dump_all_banks(struct device *dev)
+{
+ unsigned int i;
+
+ printk(KERN_INFO"ab8500 register values:\n");
+
+ for (i = 1; i < AB8500_NUM_BANKS; i++) {
+ printk(KERN_INFO" bank %u:\n", i);
+ ab8500_registers_print(dev, i, NULL);
+ }
+}
+
+static int ab8500_all_banks_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *s;
+ int err;
+
+ err = single_open(file, ab8500_print_all_banks, inode->i_private);
+ if (!err) {
+ /* Default buf size in seq_read is not enough */
+ s = (struct seq_file *)file->private_data;
+ s->size = (PAGE_SIZE * 2);
+ s->buf = kmalloc(s->size, GFP_KERNEL);
+ if (!s->buf) {
+ single_release(inode, file);
+ err = -ENOMEM;
+ }
+ }
+ return err;
+}
+
+static const struct file_operations ab8500_all_banks_fops = {
+ .open = ab8500_all_banks_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
static int ab8500_bank_print(struct seq_file *s, void *p)
{
return seq_printf(s, "%d\n", debug_bank);
@@ -519,6 +737,761 @@ static ssize_t ab8500_val_write(struct file *file,
return count;
}
+/*
+ * Interrupt status
+ */
+static u32 num_interrupts[AB8500_MAX_NR_IRQS];
+static int num_interrupt_lines;
+
+void ab8500_debug_register_interrupt(int line)
+{
+ if (line < num_interrupt_lines)
+ num_interrupts[line]++;
+}
+
+static int ab8500_interrupts_print(struct seq_file *s, void *p)
+{
+ int line;
+
+ seq_printf(s, "irq: number of\n");
+
+ for (line = 0; line < num_interrupt_lines; line++)
+ seq_printf(s, "%3i: %6i\n", line, num_interrupts[line]);
+
+ return 0;
+}
+
+static int ab8500_interrupts_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_interrupts_print, inode->i_private);
+}
+
+/*
+ * - HWREG DB8500 formated routines
+ */
+static int ab8500_hwreg_print(struct seq_file *s, void *d)
+{
+ struct device *dev = s->private;
+ int ret;
+ u8 regvalue;
+
+ ret = abx500_get_register_interruptible(dev,
+ (u8)hwreg_cfg.bank, (u8)hwreg_cfg.addr, &regvalue);
+ if (ret < 0) {
+ dev_err(dev, "abx500_get_reg fail %d, %d\n",
+ ret, __LINE__);
+ return -EINVAL;
+ }
+
+ if (hwreg_cfg.shift >= 0)
+ regvalue >>= hwreg_cfg.shift;
+ else
+ regvalue <<= -hwreg_cfg.shift;
+ regvalue &= hwreg_cfg.mask;
+
+ if (REG_FMT_DEC(&hwreg_cfg))
+ seq_printf(s, "%d\n", regvalue);
+ else
+ seq_printf(s, "0x%02X\n", regvalue);
+ return 0;
+}
+
+static int ab8500_hwreg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_hwreg_print, inode->i_private);
+}
+
+static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p)
+{
+ int bat_ctrl_raw;
+ int bat_ctrl_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL);
+ bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ BAT_CTRL, bat_ctrl_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ bat_ctrl_convert, bat_ctrl_raw);
+}
+
+static int ab8500_gpadc_bat_ctrl_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_bat_ctrl_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_bat_ctrl_fops = {
+ .open = ab8500_gpadc_bat_ctrl_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_btemp_ball_print(struct seq_file *s, void *p)
+{
+ int btemp_ball_raw;
+ int btemp_ball_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL);
+ btemp_ball_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
+ btemp_ball_raw);
+
+ return seq_printf(s,
+ "%d,0x%X\n", btemp_ball_convert, btemp_ball_raw);
+}
+
+static int ab8500_gpadc_btemp_ball_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_btemp_ball_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_btemp_ball_fops = {
+ .open = ab8500_gpadc_btemp_ball_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_main_charger_v_print(struct seq_file *s, void *p)
+{
+ int main_charger_v_raw;
+ int main_charger_v_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V);
+ main_charger_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ MAIN_CHARGER_V, main_charger_v_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ main_charger_v_convert, main_charger_v_raw);
+}
+
+static int ab8500_gpadc_main_charger_v_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_main_charger_v_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_main_charger_v_fops = {
+ .open = ab8500_gpadc_main_charger_v_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_acc_detect1_print(struct seq_file *s, void *p)
+{
+ int acc_detect1_raw;
+ int acc_detect1_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1);
+ acc_detect1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ACC_DETECT1,
+ acc_detect1_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ acc_detect1_convert, acc_detect1_raw);
+}
+
+static int ab8500_gpadc_acc_detect1_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_acc_detect1_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_acc_detect1_fops = {
+ .open = ab8500_gpadc_acc_detect1_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_acc_detect2_print(struct seq_file *s, void *p)
+{
+ int acc_detect2_raw;
+ int acc_detect2_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2);
+ acc_detect2_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ ACC_DETECT2, acc_detect2_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ acc_detect2_convert, acc_detect2_raw);
+}
+
+static int ab8500_gpadc_acc_detect2_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_acc_detect2_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_acc_detect2_fops = {
+ .open = ab8500_gpadc_acc_detect2_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_aux1_print(struct seq_file *s, void *p)
+{
+ int aux1_raw;
+ int aux1_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1);
+ aux1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX1,
+ aux1_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ aux1_convert, aux1_raw);
+}
+
+static int ab8500_gpadc_aux1_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_aux1_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_aux1_fops = {
+ .open = ab8500_gpadc_aux1_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_aux2_print(struct seq_file *s, void *p)
+{
+ int aux2_raw;
+ int aux2_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2);
+ aux2_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX2,
+ aux2_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ aux2_convert, aux2_raw);
+}
+
+static int ab8500_gpadc_aux2_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_aux2_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_aux2_fops = {
+ .open = ab8500_gpadc_aux2_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_main_bat_v_print(struct seq_file *s, void *p)
+{
+ int main_bat_v_raw;
+ int main_bat_v_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V);
+ main_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
+ main_bat_v_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ main_bat_v_convert, main_bat_v_raw);
+}
+
+static int ab8500_gpadc_main_bat_v_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_main_bat_v_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_main_bat_v_fops = {
+ .open = ab8500_gpadc_main_bat_v_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_vbus_v_print(struct seq_file *s, void *p)
+{
+ int vbus_v_raw;
+ int vbus_v_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V);
+ vbus_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBUS_V,
+ vbus_v_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ vbus_v_convert, vbus_v_raw);
+}
+
+static int ab8500_gpadc_vbus_v_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_vbus_v_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_vbus_v_fops = {
+ .open = ab8500_gpadc_vbus_v_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_main_charger_c_print(struct seq_file *s, void *p)
+{
+ int main_charger_c_raw;
+ int main_charger_c_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C);
+ main_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ MAIN_CHARGER_C, main_charger_c_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ main_charger_c_convert, main_charger_c_raw);
+}
+
+static int ab8500_gpadc_main_charger_c_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_main_charger_c_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_main_charger_c_fops = {
+ .open = ab8500_gpadc_main_charger_c_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_usb_charger_c_print(struct seq_file *s, void *p)
+{
+ int usb_charger_c_raw;
+ int usb_charger_c_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C);
+ usb_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ USB_CHARGER_C, usb_charger_c_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ usb_charger_c_convert, usb_charger_c_raw);
+}
+
+static int ab8500_gpadc_usb_charger_c_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_usb_charger_c_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_usb_charger_c_fops = {
+ .open = ab8500_gpadc_usb_charger_c_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_bk_bat_v_print(struct seq_file *s, void *p)
+{
+ int bk_bat_v_raw;
+ int bk_bat_v_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V);
+ bk_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ BK_BAT_V, bk_bat_v_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ bk_bat_v_convert, bk_bat_v_raw);
+}
+
+static int ab8500_gpadc_bk_bat_v_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_bk_bat_v_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_bk_bat_v_fops = {
+ .open = ab8500_gpadc_bk_bat_v_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_die_temp_print(struct seq_file *s, void *p)
+{
+ int die_temp_raw;
+ int die_temp_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP);
+ die_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, DIE_TEMP,
+ die_temp_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ die_temp_convert, die_temp_raw);
+}
+
+static int ab8500_gpadc_die_temp_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_die_temp_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_die_temp_fops = {
+ .open = ab8500_gpadc_die_temp_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * return length of an ASCII numerical value, 0 is string is not a
+ * numerical value.
+ * string shall start at value 1st char.
+ * string can be tailed with \0 or space or newline chars only.
+ * value can be decimal or hexadecimal (prefixed 0x or 0X).
+ */
+static int strval_len(char *b)
+{
+ char *s = b;
+ if ((*s == '0') && ((*(s+1) == 'x') || (*(s+1) == 'X'))) {
+ s += 2;
+ for (; *s && (*s != ' ') && (*s != '\n'); s++) {
+ if (!isxdigit(*s))
+ return 0;
+ }
+ } else {
+ if (*s == '-')
+ s++;
+ for (; *s && (*s != ' ') && (*s != '\n'); s++) {
+ if (!isdigit(*s))
+ return 0;
+ }
+ }
+ return (int) (s-b);
+}
+
+/*
+ * parse hwreg input data.
+ * update global hwreg_cfg only if input data syntax is ok.
+ */
+static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg,
+ struct device *dev)
+{
+ uint write, val = 0;
+ u8 regvalue;
+ int ret;
+ struct hwreg_cfg loc = {
+ .bank = 0, /* default: invalid phys addr */
+ .addr = 0, /* default: invalid phys addr */
+ .fmt = 0, /* default: 32bit access, hex output */
+ .mask = 0xFFFFFFFF, /* default: no mask */
+ .shift = 0, /* default: no bit shift */
+ };
+
+ /* read or write ? */
+ if (!strncmp(b, "read ", 5)) {
+ write = 0;
+ b += 5;
+ } else if (!strncmp(b, "write ", 6)) {
+ write = 1;
+ b += 6;
+ } else
+ return -EINVAL;
+
+ /* OPTIONS -l|-w|-b -s -m -o */
+ while ((*b == ' ') || (*b == '-')) {
+ if (*(b-1) != ' ') {
+ b++;
+ continue;
+ }
+ if ((!strncmp(b, "-d ", 3)) ||
+ (!strncmp(b, "-dec ", 5))) {
+ b += (*(b+2) == ' ') ? 3 : 5;
+ loc.fmt |= (1<<0);
+ } else if ((!strncmp(b, "-h ", 3)) ||
+ (!strncmp(b, "-hex ", 5))) {
+ b += (*(b+2) == ' ') ? 3 : 5;
+ loc.fmt &= ~(1<<0);
+ } else if ((!strncmp(b, "-m ", 3)) ||
+ (!strncmp(b, "-mask ", 6))) {
+ b += (*(b+2) == ' ') ? 3 : 6;
+ if (strval_len(b) == 0)
+ return -EINVAL;
+ loc.mask = simple_strtoul(b, &b, 0);
+ } else if ((!strncmp(b, "-s ", 3)) ||
+ (!strncmp(b, "-shift ", 7))) {
+ b += (*(b+2) == ' ') ? 3 : 7;
+ if (strval_len(b) == 0)
+ return -EINVAL;
+ loc.shift = simple_strtol(b, &b, 0);
+ } else {
+ return -EINVAL;
+ }
+ }
+ /* get arg BANK and ADDRESS */
+ if (strval_len(b) == 0)
+ return -EINVAL;
+ loc.bank = simple_strtoul(b, &b, 0);
+ while (*b == ' ')
+ b++;
+ if (strval_len(b) == 0)
+ return -EINVAL;
+ loc.addr = simple_strtoul(b, &b, 0);
+
+ if (write) {
+ while (*b == ' ')
+ b++;
+ if (strval_len(b) == 0)
+ return -EINVAL;
+ val = simple_strtoul(b, &b, 0);
+ }
+
+ /* args are ok, update target cfg (mainly for read) */
+ *cfg = loc;
+
+#ifdef ABB_HWREG_DEBUG
+ pr_warn("HWREG request: %s, %s, addr=0x%08X, mask=0x%X, shift=%d"
+ "value=0x%X\n", (write) ? "write" : "read",
+ REG_FMT_DEC(cfg) ? "decimal" : "hexa",
+ cfg->addr, cfg->mask, cfg->shift, val);
+#endif
+
+ if (!write)
+ return 0;
+
+ ret = abx500_get_register_interruptible(dev,
+ (u8)cfg->bank, (u8)cfg->addr, &regvalue);
+ if (ret < 0) {
+ dev_err(dev, "abx500_get_reg fail %d, %d\n",
+ ret, __LINE__);
+ return -EINVAL;
+ }
+
+ if (cfg->shift >= 0) {
+ regvalue &= ~(cfg->mask << (cfg->shift));
+ val = (val & cfg->mask) << (cfg->shift);
+ } else {
+ regvalue &= ~(cfg->mask >> (-cfg->shift));
+ val = (val & cfg->mask) >> (-cfg->shift);
+ }
+ val = val | regvalue;
+
+ ret = abx500_set_register_interruptible(dev,
+ (u8)cfg->bank, (u8)cfg->addr, (u8)val);
+ if (ret < 0) {
+ pr_err("abx500_set_reg failed %d, %d", ret, __LINE__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static ssize_t ab8500_hwreg_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[128];
+ int buf_size, ret;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ /* get args and process */
+ ret = hwreg_common_write(buf, &hwreg_cfg, dev);
+ return (ret) ? ret : buf_size;
+}
+
+/*
+ * - irq subscribe/unsubscribe stuff
+ */
+static int ab8500_subscribe_unsubscribe_print(struct seq_file *s, void *p)
+{
+ seq_printf(s, "%d\n", irq_first);
+
+ return 0;
+}
+
+static int ab8500_subscribe_unsubscribe_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_subscribe_unsubscribe_print,
+ inode->i_private);
+}
+
+/*
+ * Userspace should use poll() on this file. When an event occur
+ * the blocking poll will be released.
+ */
+static ssize_t show_irq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long name;
+ unsigned int irq_index;
+ int err;
+
+ err = strict_strtoul(attr->attr.name, 0, &name);
+ if (err)
+ return err;
+
+ irq_index = name - irq_first;
+ if (irq_index >= num_irqs)
+ return -EINVAL;
+ else
+ return sprintf(buf, "%u\n", irq_count[irq_index]);
+}
+
+static ssize_t ab8500_subscribe_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ int err;
+ unsigned int irq_index;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+ if (user_val < irq_first) {
+ dev_err(dev, "debugfs error input < %d\n", irq_first);
+ return -EINVAL;
+ }
+ if (user_val > irq_last) {
+ dev_err(dev, "debugfs error input > %d\n", irq_last);
+ return -EINVAL;
+ }
+
+ irq_index = user_val - irq_first;
+ if (irq_index >= num_irqs)
+ return -EINVAL;
+
+ /*
+ * This will create a sysfs file named <irq-nr> which userspace can
+ * use to select or poll and get the AB8500 events
+ */
+ dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute),
+ GFP_KERNEL);
+ event_name[irq_index] = kmalloc(buf_size, GFP_KERNEL);
+ sprintf(event_name[irq_index], "%lu", user_val);
+ dev_attr[irq_index]->show = show_irq;
+ dev_attr[irq_index]->store = NULL;
+ dev_attr[irq_index]->attr.name = event_name[irq_index];
+ dev_attr[irq_index]->attr.mode = S_IRUGO;
+ err = sysfs_create_file(&dev->kobj, &dev_attr[irq_index]->attr);
+ if (err < 0) {
+ printk(KERN_ERR "sysfs_create_file failed %d\n", err);
+ return err;
+ }
+
+ err = request_threaded_irq(user_val, NULL, ab8500_debug_handler,
+ IRQF_SHARED | IRQF_NO_SUSPEND,
+ "ab8500-debug", &dev->kobj);
+ if (err < 0) {
+ printk(KERN_ERR "request_threaded_irq failed %d, %lu\n",
+ err, user_val);
+ sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
+ return err;
+ }
+
+ return buf_size;
+}
+
+static ssize_t ab8500_unsubscribe_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ int err;
+ unsigned int irq_index;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+ if (user_val < irq_first) {
+ dev_err(dev, "debugfs error input < %d\n", irq_first);
+ return -EINVAL;
+ }
+ if (user_val > irq_last) {
+ dev_err(dev, "debugfs error input > %d\n", irq_last);
+ return -EINVAL;
+ }
+
+ irq_index = user_val - irq_first;
+ if (irq_index >= num_irqs)
+ return -EINVAL;
+
+ /* Set irq count to 0 when unsubscribe */
+ irq_count[irq_index] = 0;
+
+ if (dev_attr[irq_index])
+ sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
+
+
+ free_irq(user_val, &dev->kobj);
+ kfree(event_name[irq_index]);
+ kfree(dev_attr[irq_index]);
+
+ return buf_size;
+}
+
+/*
+ * - several deubgfs nodes fops
+ */
+
static const struct file_operations ab8500_bank_fops = {
.open = ab8500_bank_open,
.write = ab8500_bank_write,
@@ -546,64 +1519,231 @@ static const struct file_operations ab8500_val_fops = {
.owner = THIS_MODULE,
};
+static const struct file_operations ab8500_interrupts_fops = {
+ .open = ab8500_interrupts_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_subscribe_fops = {
+ .open = ab8500_subscribe_unsubscribe_open,
+ .write = ab8500_subscribe_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_unsubscribe_fops = {
+ .open = ab8500_subscribe_unsubscribe_open,
+ .write = ab8500_unsubscribe_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_hwreg_fops = {
+ .open = ab8500_hwreg_open,
+ .write = ab8500_hwreg_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
static struct dentry *ab8500_dir;
-static struct dentry *ab8500_reg_file;
-static struct dentry *ab8500_bank_file;
-static struct dentry *ab8500_address_file;
-static struct dentry *ab8500_val_file;
+static struct dentry *ab8500_gpadc_dir;
static int ab8500_debug_probe(struct platform_device *plf)
{
+ struct dentry *file;
+ int ret = -ENOMEM;
+ struct ab8500 *ab8500;
debug_bank = AB8500_MISC;
debug_address = AB8500_REV_REG & 0x00FF;
+ ab8500 = dev_get_drvdata(plf->dev.parent);
+ num_irqs = ab8500->mask_size;
+
+ irq_count = kzalloc(sizeof(*irq_count)*num_irqs, GFP_KERNEL);
+ if (!irq_count)
+ return -ENOMEM;
+
+ dev_attr = kzalloc(sizeof(*dev_attr)*num_irqs,GFP_KERNEL);
+ if (!dev_attr)
+ goto out_freeirq_count;
+
+ event_name = kzalloc(sizeof(*event_name)*num_irqs, GFP_KERNEL);
+ if (!event_name)
+ goto out_freedev_attr;
+
+ irq_first = platform_get_irq_byname(plf, "IRQ_FIRST");
+ if (irq_first < 0) {
+ dev_err(&plf->dev, "First irq not found, err %d\n",
+ irq_first);
+ ret = irq_first;
+ goto out_freeevent_name;
+ }
+
+ irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
+ if (irq_last < 0) {
+ dev_err(&plf->dev, "Last irq not found, err %d\n",
+ irq_last);
+ ret = irq_last;
+ goto out_freeevent_name;
+ }
+
ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
if (!ab8500_dir)
- goto exit_no_debugfs;
+ goto err;
+
+ ab8500_gpadc_dir = debugfs_create_dir(AB8500_ADC_NAME_STRING,
+ ab8500_dir);
+ if (!ab8500_gpadc_dir)
+ goto err;
+
+ file = debugfs_create_file("all-bank-registers", S_IRUGO,
+ ab8500_dir, &plf->dev, &ab8500_registers_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("all-banks", S_IRUGO,
+ ab8500_dir, &plf->dev, &ab8500_all_banks_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_bank_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("register-address", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_address_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("register-value", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_val_fops);
+ if (!file)
+ goto err;
- ab8500_reg_file = debugfs_create_file("all-bank-registers",
- S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
- if (!ab8500_reg_file)
- goto exit_destroy_dir;
+ file = debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_subscribe_fops);
+ if (!file)
+ goto err;
- ab8500_bank_file = debugfs_create_file("register-bank",
- (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_bank_fops);
- if (!ab8500_bank_file)
- goto exit_destroy_reg;
+ if (is_ab8500(ab8500))
+ num_interrupt_lines = AB8500_NR_IRQS;
+ else if (is_ab8505(ab8500))
+ num_interrupt_lines = AB8505_NR_IRQS;
+ else if (is_ab9540(ab8500))
+ num_interrupt_lines = AB9540_NR_IRQS;
- ab8500_address_file = debugfs_create_file("register-address",
- (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
- &ab8500_address_fops);
- if (!ab8500_address_file)
- goto exit_destroy_bank;
+ file = debugfs_create_file("interrupts", (S_IRUGO),
+ ab8500_dir, &plf->dev, &ab8500_interrupts_fops);
+ if (!file)
+ goto err;
- ab8500_val_file = debugfs_create_file("register-value",
- (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_val_fops);
- if (!ab8500_val_file)
- goto exit_destroy_address;
+ file = debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_hwreg_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bat_ctrl_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_btemp_ball_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_v_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect1_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect2_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux1_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux2_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_bat_v_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_vbus_v_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_c_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_charger_c_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bk_bat_v_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_die_temp_fops);
+ if (!file)
+ goto err;
return 0;
-exit_destroy_address:
- debugfs_remove(ab8500_address_file);
-exit_destroy_bank:
- debugfs_remove(ab8500_bank_file);
-exit_destroy_reg:
- debugfs_remove(ab8500_reg_file);
-exit_destroy_dir:
- debugfs_remove(ab8500_dir);
-exit_no_debugfs:
+err:
+ if (ab8500_dir)
+ debugfs_remove_recursive(ab8500_dir);
dev_err(&plf->dev, "failed to create debugfs entries.\n");
- return -ENOMEM;
+out_freeevent_name:
+ kfree(event_name);
+out_freedev_attr:
+ kfree(dev_attr);
+out_freeirq_count:
+ kfree(irq_count);
+
+ return ret;
}
static int ab8500_debug_remove(struct platform_device *plf)
{
- debugfs_remove(ab8500_val_file);
- debugfs_remove(ab8500_address_file);
- debugfs_remove(ab8500_bank_file);
- debugfs_remove(ab8500_reg_file);
- debugfs_remove(ab8500_dir);
+ debugfs_remove_recursive(ab8500_dir);
+ kfree(event_name);
+ kfree(dev_attr);
+ kfree(irq_count);
return 0;
}
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 3fb1f40d6389..b1f3561b023f 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
@@ -82,6 +83,11 @@
/* This is used to not lose precision when dividing to get gain and offset */
#define CALIB_SCALE 1000
+/* Time in ms before disabling regulator */
+#define GPADC_AUDOSUSPEND_DELAY 1
+
+#define CONVERSION_TIME 500 /* ms */
+
enum cal_channels {
ADC_INPUT_VMAIN = 0,
ADC_INPUT_BTEMP,
@@ -102,10 +108,10 @@ 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
+ * @parent: pointer to the struct ab8500
* @ab8500_gpadc_complete: pointer to the struct completion, to indicate
* the completion of gpadc conversion
* @ab8500_gpadc_lock: structure of type mutex
@@ -114,9 +120,9 @@ 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 ab8500 *parent;
struct completion ab8500_gpadc_complete;
struct mutex ab8500_gpadc_lock;
struct regulator *regu;
@@ -282,8 +288,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
return -ENODEV;
mutex_lock(&gpadc->ab8500_gpadc_lock);
+
/* Enable VTVout LDO this is required for GPADC */
- regulator_enable(gpadc->regu);
+ pm_runtime_get_sync(gpadc->dev);
/* Check if ADC is not busy, lock and proceed */
do {
@@ -332,7 +339,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
EN_BUF | EN_ICHAR);
break;
case BTEMP_BALL:
- if (gpadc->chip_id >= AB8500_CUT3P0) {
+ if (!is_ab8500_2p0_or_earlier(gpadc->parent)) {
/* Turn on btemp pull-up on ABB 3.0 */
ret = abx500_mask_and_set_register_interruptible(
gpadc->dev,
@@ -344,7 +351,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
* Delay might be needed for ABB8500 cut 3.0, if not, remove
* when hardware will be available
*/
- msleep(1);
+ usleep_range(1000, 1000);
break;
}
/* Intentional fallthrough */
@@ -367,7 +374,8 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
goto out;
}
/* wait for completion of conversion */
- if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) {
+ if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
+ msecs_to_jiffies(CONVERSION_TIME))) {
dev_err(gpadc->dev,
"timeout: didn't receive GPADC conversion interrupt\n");
ret = -EINVAL;
@@ -397,8 +405,10 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n");
goto out;
}
- /* Disable VTVout LDO this is required for GPADC */
- regulator_disable(gpadc->regu);
+
+ pm_runtime_mark_last_busy(gpadc->dev);
+ pm_runtime_put_autosuspend(gpadc->dev);
+
mutex_unlock(&gpadc->ab8500_gpadc_lock);
return (high_data << 8) | low_data;
@@ -412,7 +422,9 @@ out:
*/
(void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
AB8500_GPADC_CTRL1_REG, DIS_GPADC);
- regulator_disable(gpadc->regu);
+
+ pm_runtime_put(gpadc->dev);
+
mutex_unlock(&gpadc->ab8500_gpadc_lock);
dev_err(gpadc->dev,
"gpadc_conversion: Failed to AD convert channel %d\n", channel);
@@ -571,6 +583,28 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
gpadc->cal_data[ADC_INPUT_VBAT].offset);
}
+static int ab8500_gpadc_runtime_suspend(struct device *dev)
+{
+ struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
+
+ regulator_disable(gpadc->regu);
+ return 0;
+}
+
+static int ab8500_gpadc_runtime_resume(struct device *dev)
+{
+ struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
+
+ regulator_enable(gpadc->regu);
+ return 0;
+}
+
+static int ab8500_gpadc_runtime_idle(struct device *dev)
+{
+ pm_runtime_suspend(dev);
+ return 0;
+}
+
static int ab8500_gpadc_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -591,6 +625,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
}
gpadc->dev = &pdev->dev;
+ gpadc->parent = dev_get_drvdata(pdev->dev.parent);
mutex_init(&gpadc->ab8500_gpadc_lock);
/* Initialize completion used to notify completion of conversion */
@@ -607,14 +642,6 @@ static int 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)) {
@@ -622,6 +649,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
dev_err(gpadc->dev, "failed to get vtvout LDO\n");
goto fail_irq;
}
+
+ platform_set_drvdata(pdev, gpadc);
+
+ regulator_enable(gpadc->regu);
+
+ pm_runtime_set_autosuspend_delay(gpadc->dev, GPADC_AUDOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(gpadc->dev);
+ pm_runtime_set_active(gpadc->dev);
+ pm_runtime_enable(gpadc->dev);
+
ab8500_gpadc_read_calibration_data(gpadc);
list_add_tail(&gpadc->node, &ab8500_gpadc_list);
dev_dbg(gpadc->dev, "probe success\n");
@@ -642,19 +679,34 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
list_del(&gpadc->node);
/* remove interrupt - completion of Sw ADC conversion */
free_irq(gpadc->irq, gpadc);
- /* disable VTVout LDO that is being used by GPADC */
- regulator_put(gpadc->regu);
+
+ pm_runtime_get_sync(gpadc->dev);
+ pm_runtime_disable(gpadc->dev);
+
+ regulator_disable(gpadc->regu);
+
+ pm_runtime_set_suspended(gpadc->dev);
+
+ pm_runtime_put_noidle(gpadc->dev);
+
kfree(gpadc);
gpadc = NULL;
return 0;
}
+static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
+ SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
+ ab8500_gpadc_runtime_resume,
+ ab8500_gpadc_runtime_idle)
+};
+
static struct platform_driver ab8500_gpadc_driver = {
.probe = ab8500_gpadc_probe,
.remove = ab8500_gpadc_remove,
.driver = {
.name = "ab8500-gpadc",
.owner = THIS_MODULE,
+ .pm = &ab8500_gpadc_pm_ops,
},
};
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 8a33b2c7eead..108fd86552f0 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -7,12 +7,73 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/reboot.h>
+#include <linux/signal.h>
+#include <linux/power_supply.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
static struct device *sysctrl_dev;
+void ab8500_power_off(void)
+{
+ sigset_t old;
+ sigset_t all;
+ static char *pss[] = {"ab8500_ac", "ab8500_usb"};
+ int i;
+ bool charger_present = false;
+ union power_supply_propval val;
+ struct power_supply *psy;
+ int ret;
+
+ /*
+ * If we have a charger connected and we're powering off,
+ * reboot into charge-only mode.
+ */
+
+ for (i = 0; i < ARRAY_SIZE(pss); i++) {
+ psy = power_supply_get_by_name(pss[i]);
+ if (!psy)
+ continue;
+
+ ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
+
+ if (!ret && val.intval) {
+ charger_present = true;
+ break;
+ }
+ }
+
+ if (!charger_present)
+ goto shutdown;
+
+ /* Check if battery is known */
+ psy = power_supply_get_by_name("ab8500_btemp");
+ if (psy) {
+ ret = psy->get_property(psy, POWER_SUPPLY_PROP_TECHNOLOGY,
+ &val);
+ if (!ret && val.intval != POWER_SUPPLY_TECHNOLOGY_UNKNOWN) {
+ printk(KERN_INFO
+ "Charger \"%s\" is connected with known battery."
+ " Rebooting.\n",
+ pss[i]);
+ machine_restart("charging");
+ }
+ }
+
+shutdown:
+ sigfillset(&all);
+
+ if (!sigprocmask(SIG_BLOCK, &all, &old)) {
+ (void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
+ AB8500_STW4500CTRL1_SWOFF |
+ AB8500_STW4500CTRL1_SWRESET4500N);
+ (void)sigprocmask(SIG_SETMASK, &old, NULL);
+ }
+}
+
static inline bool valid_bank(u8 bank)
{
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
@@ -33,6 +94,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
return abx500_get_register_interruptible(sysctrl_dev, bank,
(u8)(reg & 0xFF), value);
}
+EXPORT_SYMBOL(ab8500_sysctrl_read);
int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
{
@@ -48,10 +110,40 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
(u8)(reg & 0xFF), mask, value);
}
+EXPORT_SYMBOL(ab8500_sysctrl_write);
static int ab8500_sysctrl_probe(struct platform_device *pdev)
{
+ struct ab8500_platform_data *plat;
+ struct ab8500_sysctrl_platform_data *pdata;
+
sysctrl_dev = &pdev->dev;
+ plat = dev_get_platdata(pdev->dev.parent);
+ if (plat->pm_power_off)
+ pm_power_off = ab8500_power_off;
+
+ pdata = plat->sysctrl;
+
+ if (pdata) {
+ int ret, i, j;
+
+ for (i = AB8500_SYSCLKREQ1RFCLKBUF;
+ i <= AB8500_SYSCLKREQ8RFCLKBUF; i++) {
+ j = i - AB8500_SYSCLKREQ1RFCLKBUF;
+ ret = ab8500_sysctrl_write(i, 0xff,
+ pdata->initial_req_buf_config[j]);
+ dev_dbg(&pdev->dev,
+ "Setting SysClkReq%dRfClkBuf 0x%X\n",
+ j + 1,
+ pdata->initial_req_buf_config[j]);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "unable to set sysClkReq%dRfClkBuf: "
+ "%d\n", j + 1, ret);
+ }
+ }
+ }
+
return 0;
}
diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c
index 7ce65f49480f..9818afba2515 100644
--- a/drivers/mfd/abx500-core.c
+++ b/drivers/mfd/abx500-core.c
@@ -153,6 +153,22 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
}
EXPORT_SYMBOL(abx500_startup_irq_enabled);
+void abx500_dump_all_banks(void)
+{
+ struct abx500_ops *ops;
+ struct device dummy_child = {0};
+ struct abx500_device_entry *dev_entry;
+
+ list_for_each_entry(dev_entry, &abx500_list, list) {
+ dummy_child.parent = dev_entry->dev;
+ ops = &dev_entry->ops;
+
+ if ((ops != NULL) && (ops->dump_all_banks != NULL))
+ ops->dump_all_banks(&dummy_child);
+ }
+}
+EXPORT_SYMBOL(abx500_dump_all_banks);
+
MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
MODULE_DESCRIPTION("ABX500 core driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 222c03a5ddc0..b562c7bf8a46 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -115,7 +115,7 @@ static irqreturn_t arizona_underclocked(int irq, void *data)
if (val & ARIZONA_ADC_UNDERCLOCKED_STS)
dev_err(arizona->dev, "ADC underclocked\n");
if (val & ARIZONA_MIXER_UNDERCLOCKED_STS)
- dev_err(arizona->dev, "Mixer underclocked\n");
+ dev_err(arizona->dev, "Mixer dropped sample\n");
return IRQ_HANDLED;
}
@@ -263,10 +263,36 @@ static int arizona_runtime_suspend(struct device *dev)
}
#endif
+#ifdef CONFIG_PM_SLEEP
+static int arizona_resume_noirq(struct device *dev)
+{
+ struct arizona *arizona = dev_get_drvdata(dev);
+
+ dev_dbg(arizona->dev, "Early resume, disabling IRQ\n");
+ disable_irq(arizona->irq);
+
+ return 0;
+}
+
+static int arizona_resume(struct device *dev)
+{
+ struct arizona *arizona = dev_get_drvdata(dev);
+
+ dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n");
+ enable_irq(arizona->irq);
+
+ return 0;
+}
+#endif
+
const struct dev_pm_ops arizona_pm_ops = {
SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
arizona_runtime_resume,
NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume)
+#ifdef CONFIG_PM_SLEEP
+ .resume_noirq = arizona_resume_noirq,
+#endif
};
EXPORT_SYMBOL_GPL(arizona_pm_ops);
@@ -275,19 +301,19 @@ static struct mfd_cell early_devs[] = {
};
static struct mfd_cell wm5102_devs[] = {
+ { .name = "arizona-micsupp" },
{ .name = "arizona-extcon" },
{ .name = "arizona-gpio" },
{ .name = "arizona-haptics" },
- { .name = "arizona-micsupp" },
{ .name = "arizona-pwm" },
{ .name = "wm5102-codec" },
};
static struct mfd_cell wm5110_devs[] = {
+ { .name = "arizona-micsupp" },
{ .name = "arizona-extcon" },
{ .name = "arizona-gpio" },
{ .name = "arizona-haptics" },
- { .name = "arizona-micsupp" },
{ .name = "arizona-pwm" },
{ .name = "wm5110-codec" },
};
@@ -484,6 +510,29 @@ int arizona_dev_init(struct arizona *arizona)
goto err_reset;
}
+ for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) {
+ if (!arizona->pdata.micbias[i].mV)
+ continue;
+
+ val = (arizona->pdata.micbias[i].mV - 1500) / 100;
+ val <<= ARIZONA_MICB1_LVL_SHIFT;
+
+ if (arizona->pdata.micbias[i].ext_cap)
+ val |= ARIZONA_MICB1_EXT_CAP;
+
+ if (arizona->pdata.micbias[i].discharge)
+ val |= ARIZONA_MICB1_DISCH;
+
+ if (arizona->pdata.micbias[i].fast_start)
+ val |= ARIZONA_MICB1_RATE;
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_MIC_BIAS_CTRL_1 + i,
+ ARIZONA_MICB1_LVL_MASK |
+ ARIZONA_MICB1_DISCH |
+ ARIZONA_MICB1_RATE, val);
+ }
+
for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
/* Default for both is 0 so noop with defaults */
val = arizona->pdata.dmic_ref[i]
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
index 885e56780358..6a9fec40d018 100644
--- a/drivers/mfd/da9052-i2c.c
+++ b/drivers/mfd/da9052-i2c.c
@@ -60,7 +60,7 @@ static inline bool i2c_safe_reg(unsigned char reg)
* This fix is to follow any read or write with a dummy read to a safe
* register.
*/
-int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
+static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
{
int val;
@@ -85,7 +85,6 @@ int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
return 0;
}
-EXPORT_SYMBOL(da9052_i2c_fix);
static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
{
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 268f45d42394..21f261bf9e95 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -26,22 +26,19 @@
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
+#include <linux/irqchip/arm-gic.h>
#include <linux/mfd/core.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/db8500-prcmu.h>
#include <linux/regulator/machine.h>
#include <linux/cpufreq.h>
-#include <asm/hardware/gic.h>
+#include <linux/platform_data/ux500_wdt.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/db8500-regs.h>
-#include <mach/id.h>
#include "dbx500-prcmu-regs.h"
-/* Offset for the firmware version within the TCPM */
-#define PRCMU_FW_VERSION_OFFSET 0xA4
-
/* Index of different voltages to be used when accessing AVSData */
#define PRCM_AVS_BASE 0x2FC
#define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0)
@@ -216,10 +213,8 @@
#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_WRITE(slave) (((slave) << 1) | BIT(6))
+#define PRCMU_I2C_READ(slave) (((slave) << 1) | BIT(0) | BIT(6))
#define PRCMU_I2C_STOP_EN BIT(3)
/* Mailbox 5 ACKs */
@@ -1049,12 +1044,13 @@ int db8500_prcmu_get_ddr_opp(void)
*
* This function sets the operating point of the DDR.
*/
+static bool enable_set_ddr_opp;
int db8500_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())
+ if (enable_set_ddr_opp)
writeb(opp, PRCM_DDR_SUBSYS_APE_MINBW);
return 0;
@@ -2212,21 +2208,25 @@ int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
sleep_auto_off ? A9WDOG_AUTO_OFF_EN :
A9WDOG_AUTO_OFF_DIS);
}
+EXPORT_SYMBOL(db8500_prcmu_config_a9wdog);
int db8500_prcmu_enable_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
}
+EXPORT_SYMBOL(db8500_prcmu_enable_a9wdog);
int db8500_prcmu_disable_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
}
+EXPORT_SYMBOL(db8500_prcmu_disable_a9wdog);
int db8500_prcmu_kick_a9wdog(u8 id)
{
return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
}
+EXPORT_SYMBOL(db8500_prcmu_kick_a9wdog);
/*
* timeout is 28 bit, in ms.
@@ -2244,6 +2244,7 @@ int db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
(u8)((timeout >> 12) & 0xff),
(u8)((timeout >> 20) & 0xff));
}
+EXPORT_SYMBOL(db8500_prcmu_load_a9wdog);
/**
* prcmu_abb_read() - Read register value(s) from the ABB.
@@ -2706,21 +2707,43 @@ static struct irq_chip prcmu_irq_chip = {
.irq_unmask = prcmu_irq_unmask,
};
-static char *fw_project_name(u8 project)
+static __init char *fw_project_name(u32 project)
{
switch (project) {
case PRCMU_FW_PROJECT_U8500:
return "U8500";
- case PRCMU_FW_PROJECT_U8500_C2:
- return "U8500 C2";
+ case PRCMU_FW_PROJECT_U8400:
+ return "U8400";
case PRCMU_FW_PROJECT_U9500:
return "U9500";
- case PRCMU_FW_PROJECT_U9500_C2:
- return "U9500 C2";
+ case PRCMU_FW_PROJECT_U8500_MBB:
+ return "U8500 MBB";
+ case PRCMU_FW_PROJECT_U8500_C1:
+ return "U8500 C1";
+ case PRCMU_FW_PROJECT_U8500_C2:
+ return "U8500 C2";
+ case PRCMU_FW_PROJECT_U8500_C3:
+ return "U8500 C3";
+ case PRCMU_FW_PROJECT_U8500_C4:
+ return "U8500 C4";
+ case PRCMU_FW_PROJECT_U9500_MBL:
+ return "U9500 MBL";
+ case PRCMU_FW_PROJECT_U8500_MBL:
+ return "U8500 MBL";
+ case PRCMU_FW_PROJECT_U8500_MBL2:
+ return "U8500 MBL2";
case PRCMU_FW_PROJECT_U8520:
- return "U8520";
+ return "U8520 MBL";
case PRCMU_FW_PROJECT_U8420:
return "U8420";
+ case PRCMU_FW_PROJECT_U9540:
+ return "U9540";
+ case PRCMU_FW_PROJECT_A9420:
+ return "A9420";
+ case PRCMU_FW_PROJECT_L8540:
+ return "L8540";
+ case PRCMU_FW_PROJECT_L8580:
+ return "L8580";
default:
return "Unknown";
}
@@ -2766,36 +2789,44 @@ static int db8500_irq_init(struct device_node *np)
return 0;
}
-void __init db8500_prcmu_early_init(void)
+static void dbx500_fw_version_init(struct platform_device *pdev,
+ u32 version_offset)
{
- if (cpu_is_u8500v2() || cpu_is_u9540()) {
- void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K);
-
- if (tcpm_base != NULL) {
- u32 version;
- version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
- fw_info.version.project = version & 0xFF;
- fw_info.version.api_version = (version >> 8) & 0xFF;
- fw_info.version.func_version = (version >> 16) & 0xFF;
- fw_info.version.errata = (version >> 24) & 0xFF;
- fw_info.valid = true;
- pr_info("PRCMU firmware: %s, version %d.%d.%d\n",
- fw_project_name(fw_info.version.project),
- (version >> 8) & 0xFF, (version >> 16) & 0xFF,
- (version >> 24) & 0xFF);
- iounmap(tcpm_base);
- }
+ struct resource *res;
+ void __iomem *tcpm_base;
- if (cpu_is_u9540())
- tcdm_base = ioremap_nocache(U8500_PRCMU_TCDM_BASE,
- SZ_4K + SZ_8K) + SZ_8K;
- else
- tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
- } else {
- pr_err("prcmu: Unsupported chip version\n");
- BUG();
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "prcmu-tcpm");
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Error: no prcmu tcpm memory region provided\n");
+ return;
+ }
+ tcpm_base = ioremap(res->start, resource_size(res));
+ if (tcpm_base != NULL) {
+ u32 version;
+
+ version = readl(tcpm_base + version_offset);
+ fw_info.version.project = (version & 0xFF);
+ fw_info.version.api_version = (version >> 8) & 0xFF;
+ fw_info.version.func_version = (version >> 16) & 0xFF;
+ fw_info.version.errata = (version >> 24) & 0xFF;
+ strncpy(fw_info.version.project_name,
+ fw_project_name(fw_info.version.project),
+ PRCMU_FW_PROJECT_NAME_LEN);
+ fw_info.valid = true;
+ pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n",
+ fw_info.version.project_name,
+ fw_info.version.project,
+ fw_info.version.api_version,
+ fw_info.version.func_version,
+ fw_info.version.errata);
+ iounmap(tcpm_base);
}
+}
+void __init db8500_prcmu_early_init(void)
+{
spin_lock_init(&mb0_transfer.lock);
spin_lock_init(&mb0_transfer.dbb_irqs_lock);
mutex_init(&mb0_transfer.ac_wake_lock);
@@ -3069,6 +3100,11 @@ static struct resource ab8500_resources[] = {
}
};
+static struct ux500_wdt_data db8500_wdt_pdata = {
+ .timeout = 600, /* 10 minutes */
+ .has_28_bits_resolution = true,
+};
+
static struct mfd_cell db8500_prcmu_devs[] = {
{
.name = "db8500-prcmu-regulators",
@@ -3077,12 +3113,18 @@ static struct mfd_cell db8500_prcmu_devs[] = {
.pdata_size = sizeof(db8500_regulators),
},
{
- .name = "cpufreq-u8500",
- .of_compatible = "stericsson,cpufreq-u8500",
+ .name = "cpufreq-ux500",
+ .of_compatible = "stericsson,cpufreq-ux500",
.platform_data = &db8500_cpufreq_table,
.pdata_size = sizeof(db8500_cpufreq_table),
},
{
+ .name = "ux500_wdt",
+ .platform_data = &db8500_wdt_pdata,
+ .pdata_size = sizeof(db8500_wdt_pdata),
+ .id = -1,
+ },
+ {
.name = "ab8500-core",
.of_compatible = "stericsson,ab8500",
.num_resources = ARRAY_SIZE(ab8500_resources),
@@ -3105,23 +3147,30 @@ static void db8500_prcmu_update_cpufreq(void)
*/
static int db8500_prcmu_probe(struct platform_device *pdev)
{
- struct ab8500_platform_data *ab8500_platdata = pdev->dev.platform_data;
struct device_node *np = pdev->dev.of_node;
+ struct prcmu_pdata *pdata = dev_get_platdata(&pdev->dev);
int irq = 0, err = 0, i;
-
- if (ux500_is_svp())
- return -ENODEV;
+ struct resource *res;
init_prcm_registers();
+ dbx500_fw_version_init(pdev, pdata->version_offset);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
+ if (!res) {
+ dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
+ return -ENOENT;
+ }
+ tcdm_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+
/* Clean up the mailbox interrupts after pre-kernel code. */
writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
- if (np)
- irq = platform_get_irq(pdev, 0);
-
- if (!np || irq <= 0)
- irq = IRQ_DB8500_PRCMU1;
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev, "no prcmu irq provided\n");
+ return -ENOENT;
+ }
err = request_threaded_irq(irq, prcmu_irq_handler,
prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
@@ -3135,13 +3184,12 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) {
if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) {
- db8500_prcmu_devs[i].platform_data = ab8500_platdata;
+ db8500_prcmu_devs[i].platform_data = pdata->ab_platdata;
db8500_prcmu_devs[i].pdata_size = sizeof(struct ab8500_platform_data);
}
}
- if (cpu_is_u8500v20_or_later())
- prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
+ prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
db8500_prcmu_update_cpufreq();
diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c
index ab8d0b2739b2..1804331bd52c 100644
--- a/drivers/mfd/intel_msic.c
+++ b/drivers/mfd/intel_msic.c
@@ -9,6 +9,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -424,11 +425,9 @@ static int intel_msic_probe(struct platform_device *pdev)
return -ENODEV;
}
- msic->irq_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!msic->irq_base) {
- dev_err(&pdev->dev, "failed to map SRAM memory\n");
- return -ENOMEM;
- }
+ msic->irq_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(msic->irq_base))
+ return PTR_ERR(msic->irq_base);
platform_set_drvdata(pdev, msic);
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
index d9d930302e98..9f12f91d6296 100644
--- a/drivers/mfd/lpc_ich.c
+++ b/drivers/mfd/lpc_ich.c
@@ -50,6 +50,7 @@
* document number TBD : Panther Point
* document number TBD : Lynx Point
* document number TBD : Lynx Point-LP
+ * document number TBD : Wellsburg
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -75,8 +76,10 @@
#define ACPIBASE_GCS_OFF 0x3410
#define ACPIBASE_GCS_END 0x3414
-#define GPIOBASE 0x48
-#define GPIOCTRL 0x4C
+#define GPIOBASE_ICH0 0x58
+#define GPIOCTRL_ICH0 0x5C
+#define GPIOBASE_ICH6 0x48
+#define GPIOCTRL_ICH6 0x4C
#define RCBABASE 0xf0
@@ -84,8 +87,17 @@
#define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i)
#define wdt_res(b, i) (&wdt_ich_res[(b) + (i)])
-static int lpc_ich_acpi_save = -1;
-static int lpc_ich_gpio_save = -1;
+struct lpc_ich_cfg {
+ int base;
+ int ctrl;
+ int save;
+};
+
+struct lpc_ich_priv {
+ int chipset;
+ struct lpc_ich_cfg acpi;
+ struct lpc_ich_cfg gpio;
+};
static struct resource wdt_ich_res[] = {
/* ACPI - TCO */
@@ -194,6 +206,7 @@ enum lpc_chipsets {
LPC_PPT, /* Panther Point */
LPC_LPT, /* Lynx Point */
LPC_LPT_LP, /* Lynx Point-LP */
+ LPC_WBG, /* Wellsburg */
};
struct lpc_ich_info lpc_chipset_info[] = {
@@ -474,6 +487,10 @@ struct lpc_ich_info lpc_chipset_info[] = {
.name = "Lynx Point_LP",
.iTCO_version = 2,
},
+ [LPC_WBG] = {
+ .name = "Wellsburg",
+ .iTCO_version = 2,
+ },
};
/*
@@ -655,45 +672,82 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = {
{ PCI_VDEVICE(INTEL, 0x9c45), LPC_LPT_LP},
{ PCI_VDEVICE(INTEL, 0x9c46), LPC_LPT_LP},
{ PCI_VDEVICE(INTEL, 0x9c47), LPC_LPT_LP},
+ { PCI_VDEVICE(INTEL, 0x8d40), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d41), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d42), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d43), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d44), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d45), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d46), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d47), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d48), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d49), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d4a), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d4b), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d4c), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d4d), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d4e), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d4f), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d50), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d51), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d52), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d53), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d54), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d55), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d56), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d57), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d58), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d59), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d5a), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d5b), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d5c), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d5d), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d5e), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x8d5f), LPC_WBG},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, lpc_ich_ids);
static void lpc_ich_restore_config_space(struct pci_dev *dev)
{
- if (lpc_ich_acpi_save >= 0) {
- pci_write_config_byte(dev, ACPICTRL, lpc_ich_acpi_save);
- lpc_ich_acpi_save = -1;
+ struct lpc_ich_priv *priv = pci_get_drvdata(dev);
+
+ if (priv->acpi.save >= 0) {
+ pci_write_config_byte(dev, priv->acpi.ctrl, priv->acpi.save);
+ priv->acpi.save = -1;
}
- if (lpc_ich_gpio_save >= 0) {
- pci_write_config_byte(dev, GPIOCTRL, lpc_ich_gpio_save);
- lpc_ich_gpio_save = -1;
+ if (priv->gpio.save >= 0) {
+ pci_write_config_byte(dev, priv->gpio.ctrl, priv->gpio.save);
+ priv->gpio.save = -1;
}
}
static void lpc_ich_enable_acpi_space(struct pci_dev *dev)
{
+ struct lpc_ich_priv *priv = pci_get_drvdata(dev);
u8 reg_save;
- pci_read_config_byte(dev, ACPICTRL, &reg_save);
- pci_write_config_byte(dev, ACPICTRL, reg_save | 0x10);
- lpc_ich_acpi_save = reg_save;
+ pci_read_config_byte(dev, priv->acpi.ctrl, &reg_save);
+ pci_write_config_byte(dev, priv->acpi.ctrl, reg_save | 0x10);
+ priv->acpi.save = reg_save;
}
static void lpc_ich_enable_gpio_space(struct pci_dev *dev)
{
+ struct lpc_ich_priv *priv = pci_get_drvdata(dev);
u8 reg_save;
- pci_read_config_byte(dev, GPIOCTRL, &reg_save);
- pci_write_config_byte(dev, GPIOCTRL, reg_save | 0x10);
- lpc_ich_gpio_save = reg_save;
+ pci_read_config_byte(dev, priv->gpio.ctrl, &reg_save);
+ pci_write_config_byte(dev, priv->gpio.ctrl, reg_save | 0x10);
+ priv->gpio.save = reg_save;
}
-static void lpc_ich_finalize_cell(struct mfd_cell *cell,
- const struct pci_device_id *id)
+static void lpc_ich_finalize_cell(struct pci_dev *dev, struct mfd_cell *cell)
{
- cell->platform_data = &lpc_chipset_info[id->driver_data];
+ struct lpc_ich_priv *priv = pci_get_drvdata(dev);
+
+ cell->platform_data = &lpc_chipset_info[priv->chipset];
cell->pdata_size = sizeof(struct lpc_ich_info);
}
@@ -721,9 +775,9 @@ static int lpc_ich_check_conflict_gpio(struct resource *res)
return use_gpio ? use_gpio : ret;
}
-static int lpc_ich_init_gpio(struct pci_dev *dev,
- const struct pci_device_id *id)
+static int lpc_ich_init_gpio(struct pci_dev *dev)
{
+ struct lpc_ich_priv *priv = pci_get_drvdata(dev);
u32 base_addr_cfg;
u32 base_addr;
int ret;
@@ -731,7 +785,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
struct resource *res;
/* Setup power management base register */
- pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
+ pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
base_addr = base_addr_cfg & 0x0000ff80;
if (!base_addr) {
dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
@@ -757,7 +811,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev,
gpe0_done:
/* Setup GPIO base register */
- pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
+ pci_read_config_dword(dev, priv->gpio.base, &base_addr_cfg);
base_addr = base_addr_cfg & 0x0000ff80;
if (!base_addr) {
dev_notice(&dev->dev, "I/O space for GPIO uninitialized\n");
@@ -768,7 +822,7 @@ gpe0_done:
/* Older devices provide fewer GPIO and have a smaller resource size. */
res = &gpio_ich_res[ICH_RES_GPIO];
res->start = base_addr;
- switch (lpc_chipset_info[id->driver_data].gpio_version) {
+ switch (lpc_chipset_info[priv->chipset].gpio_version) {
case ICH_V5_GPIO:
case ICH_V10CORP_GPIO:
res->end = res->start + 128 - 1;
@@ -784,10 +838,10 @@ gpe0_done:
acpi_conflict = true;
goto gpio_done;
}
- lpc_chipset_info[id->driver_data].use_gpio = ret;
+ lpc_chipset_info[priv->chipset].use_gpio = ret;
lpc_ich_enable_gpio_space(dev);
- lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id);
+ lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_GPIO]);
ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO],
1, NULL, 0, NULL);
@@ -798,16 +852,16 @@ gpio_done:
return ret;
}
-static int lpc_ich_init_wdt(struct pci_dev *dev,
- const struct pci_device_id *id)
+static int lpc_ich_init_wdt(struct pci_dev *dev)
{
+ struct lpc_ich_priv *priv = pci_get_drvdata(dev);
u32 base_addr_cfg;
u32 base_addr;
int ret;
struct resource *res;
/* Setup power management base register */
- pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
+ pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
base_addr = base_addr_cfg & 0x0000ff80;
if (!base_addr) {
dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
@@ -830,7 +884,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev,
* we have to read RCBA from PCI Config space 0xf0 and use
* it as base. GCS = RCBA + ICH6_GCS(0x3410).
*/
- if (lpc_chipset_info[id->driver_data].iTCO_version == 1) {
+ if (lpc_chipset_info[priv->chipset].iTCO_version == 1) {
/* Don't register iomem for TCO ver 1 */
lpc_ich_cells[LPC_WDT].num_resources--;
} else {
@@ -847,7 +901,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev,
res->end = base_addr + ACPIBASE_GCS_END;
}
- lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id);
+ lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]);
ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT],
1, NULL, 0, NULL);
@@ -858,14 +912,36 @@ wdt_done:
static int lpc_ich_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
+ struct lpc_ich_priv *priv;
int ret;
bool cell_added = false;
- ret = lpc_ich_init_wdt(dev, id);
+ priv = devm_kzalloc(&dev->dev,
+ sizeof(struct lpc_ich_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->chipset = id->driver_data;
+ priv->acpi.save = -1;
+ priv->acpi.base = ACPIBASE;
+ priv->acpi.ctrl = ACPICTRL;
+
+ priv->gpio.save = -1;
+ if (priv->chipset <= LPC_ICH5) {
+ priv->gpio.base = GPIOBASE_ICH0;
+ priv->gpio.ctrl = GPIOCTRL_ICH0;
+ } else {
+ priv->gpio.base = GPIOBASE_ICH6;
+ priv->gpio.ctrl = GPIOCTRL_ICH6;
+ }
+
+ pci_set_drvdata(dev, priv);
+
+ ret = lpc_ich_init_wdt(dev);
if (!ret)
cell_added = true;
- ret = lpc_ich_init_gpio(dev, id);
+ ret = lpc_ich_init_gpio(dev);
if (!ret)
cell_added = true;
@@ -876,6 +952,7 @@ static int lpc_ich_probe(struct pci_dev *dev,
if (!cell_added) {
dev_warn(&dev->dev, "No MFD cells added\n");
lpc_ich_restore_config_space(dev);
+ pci_set_drvdata(dev, NULL);
return -ENODEV;
}
@@ -886,6 +963,7 @@ static void lpc_ich_remove(struct pci_dev *dev)
{
mfd_remove_devices(&dev->dev);
lpc_ich_restore_config_space(dev);
+ pci_set_drvdata(dev, NULL);
}
static struct pci_driver lpc_ich_driver = {
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
index 5624fcbba69b..8cc6aac27cb2 100644
--- a/drivers/mfd/lpc_sch.c
+++ b/drivers/mfd/lpc_sch.c
@@ -45,34 +45,32 @@ static struct resource smbus_sch_resource = {
.flags = IORESOURCE_IO,
};
-
static struct resource gpio_sch_resource = {
.flags = IORESOURCE_IO,
};
-static struct mfd_cell lpc_sch_cells[] = {
- {
- .name = "isch_smbus",
- .num_resources = 1,
- .resources = &smbus_sch_resource,
- },
- {
- .name = "sch_gpio",
- .num_resources = 1,
- .resources = &gpio_sch_resource,
- },
-};
-
static struct resource wdt_sch_resource = {
.flags = IORESOURCE_IO,
};
-static struct mfd_cell tunnelcreek_cells[] = {
- {
- .name = "ie6xx_wdt",
- .num_resources = 1,
- .resources = &wdt_sch_resource,
- },
+static struct mfd_cell lpc_sch_cells[3];
+
+static struct mfd_cell isch_smbus_cell = {
+ .name = "isch_smbus",
+ .num_resources = 1,
+ .resources = &smbus_sch_resource,
+};
+
+static struct mfd_cell sch_gpio_cell = {
+ .name = "sch_gpio",
+ .num_resources = 1,
+ .resources = &gpio_sch_resource,
+};
+
+static struct mfd_cell wdt_sch_cell = {
+ .name = "ie6xx_wdt",
+ .num_resources = 1,
+ .resources = &wdt_sch_resource,
};
static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
@@ -88,79 +86,76 @@ static int lpc_sch_probe(struct pci_dev *dev,
{
unsigned int base_addr_cfg;
unsigned short base_addr;
- int i;
+ int i, cells = 0;
int ret;
pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
- if (!(base_addr_cfg & (1 << 31))) {
- dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
- return -ENODEV;
- }
- base_addr = (unsigned short)base_addr_cfg;
- if (base_addr == 0) {
- dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
- return -ENODEV;
- }
-
- smbus_sch_resource.start = base_addr;
- smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
+ base_addr = 0;
+ if (!(base_addr_cfg & (1 << 31)))
+ dev_warn(&dev->dev, "Decode of the SMBus I/O range disabled\n");
+ else
+ base_addr = (unsigned short)base_addr_cfg;
- pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
- if (!(base_addr_cfg & (1 << 31))) {
- dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n");
- return -ENODEV;
- }
- base_addr = (unsigned short)base_addr_cfg;
if (base_addr == 0) {
- dev_err(&dev->dev, "I/O space for GPIO uninitialized\n");
- return -ENODEV;
+ dev_warn(&dev->dev, "I/O space for SMBus uninitialized\n");
+ } else {
+ lpc_sch_cells[cells++] = isch_smbus_cell;
+ smbus_sch_resource.start = base_addr;
+ smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
}
- gpio_sch_resource.start = base_addr;
-
- if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
- gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
+ pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
+ base_addr = 0;
+ if (!(base_addr_cfg & (1 << 31)))
+ dev_warn(&dev->dev, "Decode of the GPIO I/O range disabled\n");
else
- gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
-
- for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
- lpc_sch_cells[i].id = id->device;
+ base_addr = (unsigned short)base_addr_cfg;
- ret = mfd_add_devices(&dev->dev, 0,
- lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL,
- 0, NULL);
- if (ret)
- goto out_dev;
+ if (base_addr == 0) {
+ dev_warn(&dev->dev, "I/O space for GPIO uninitialized\n");
+ } else {
+ lpc_sch_cells[cells++] = sch_gpio_cell;
+ gpio_sch_resource.start = base_addr;
+ if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
+ gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
+ else
+ gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
+ }
if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC
- || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
+ || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
- if (!(base_addr_cfg & (1 << 31))) {
- dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n");
- ret = -ENODEV;
- goto out_dev;
+ base_addr = 0;
+ if (!(base_addr_cfg & (1 << 31)))
+ dev_warn(&dev->dev, "Decode of the WDT I/O range disabled\n");
+ else
+ base_addr = (unsigned short)base_addr_cfg;
+ if (base_addr == 0)
+ dev_warn(&dev->dev, "I/O space for WDT uninitialized\n");
+ else {
+ lpc_sch_cells[cells++] = wdt_sch_cell;
+ wdt_sch_resource.start = base_addr;
+ wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
}
- base_addr = (unsigned short)base_addr_cfg;
- if (base_addr == 0) {
- dev_err(&dev->dev, "I/O space for WDT uninitialized\n");
- ret = -ENODEV;
- goto out_dev;
- }
-
- wdt_sch_resource.start = base_addr;
- wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
+ }
- for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++)
- tunnelcreek_cells[i].id = id->device;
+ if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) {
+ dev_err(&dev->dev, "Cell count exceeds array size");
+ return -ENODEV;
+ }
- ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells,
- ARRAY_SIZE(tunnelcreek_cells), NULL,
- 0, NULL);
+ if (cells == 0) {
+ dev_err(&dev->dev, "All decode registers disabled.\n");
+ return -ENODEV;
}
- return ret;
-out_dev:
- mfd_remove_devices(&dev->dev);
+ for (i = 0; i < cells; i++)
+ lpc_sch_cells[i].id = id->device;
+
+ ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
+ if (ret)
+ mfd_remove_devices(&dev->dev);
+
return ret;
}
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index e32466e865b9..f0cc40296d8c 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -14,10 +14,13 @@
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/platform_device.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max8925.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
static struct resource bk_resources[] = {
{ 0x84, 0x84, "mode control", IORESOURCE_REG, },
@@ -639,17 +642,33 @@ static struct irq_chip max8925_irq_chip = {
.irq_disable = max8925_irq_disable,
};
+static int max8925_irq_domain_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_data(virq, d->host_data);
+ irq_set_chip_and_handler(virq, &max8925_irq_chip, handle_edge_irq);
+ irq_set_nested_thread(virq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(virq, IRQF_VALID);
+#else
+ irq_set_noprobe(virq);
+#endif
+ return 0;
+}
+
+static struct irq_domain_ops max8925_irq_domain_ops = {
+ .map = max8925_irq_domain_map,
+ .xlate = irq_domain_xlate_onetwocell,
+};
+
+
static int max8925_irq_init(struct max8925_chip *chip, int irq,
struct max8925_platform_data *pdata)
{
unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
- int i, ret;
- int __irq;
+ int ret;
+ struct device_node *node = chip->dev->of_node;
- if (!pdata || !pdata->irq_base) {
- dev_warn(chip->dev, "No interrupt support on IRQ base\n");
- return -EINVAL;
- }
/* clear all interrupts */
max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ1);
max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ2);
@@ -667,35 +686,30 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq,
max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, 0xff);
mutex_init(&chip->irq_lock);
- chip->core_irq = irq;
- chip->irq_base = pdata->irq_base;
-
- /* register with genirq */
- for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) {
- __irq = i + chip->irq_base;
- irq_set_chip_data(__irq, chip);
- irq_set_chip_and_handler(__irq, &max8925_irq_chip,
- handle_edge_irq);
- irq_set_nested_thread(__irq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(__irq, IRQF_VALID);
-#else
- irq_set_noprobe(__irq);
-#endif
- }
- if (!irq) {
- dev_warn(chip->dev, "No interrupt support on core IRQ\n");
- goto tsc_irq;
+ chip->irq_base = irq_alloc_descs(-1, 0, MAX8925_NR_IRQS, 0);
+ if (chip->irq_base < 0) {
+ dev_err(chip->dev, "Failed to allocate interrupts, ret:%d\n",
+ chip->irq_base);
+ return -EBUSY;
}
+ irq_domain_add_legacy(node, MAX8925_NR_IRQS, chip->irq_base, 0,
+ &max8925_irq_domain_ops, chip);
+
+ /* request irq handler for pmic main irq*/
+ chip->core_irq = irq;
+ if (!chip->core_irq)
+ return -EBUSY;
ret = request_threaded_irq(irq, NULL, max8925_irq, flags | IRQF_ONESHOT,
"max8925", chip);
if (ret) {
dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret);
chip->core_irq = 0;
+ return -EBUSY;
}
-tsc_irq:
+ /* request irq handler for pmic tsc irq*/
+
/* mask TSC interrupt */
max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, 0x0f);
@@ -704,7 +718,6 @@ tsc_irq:
return 0;
}
chip->tsc_irq = pdata->tsc_irq;
-
ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq,
flags | IRQF_ONESHOT, "max8925-tsc", chip);
if (ret) {
@@ -846,7 +859,7 @@ int max8925_device_init(struct max8925_chip *chip,
ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
ARRAY_SIZE(rtc_devs),
- &rtc_resources[0], chip->irq_base, NULL);
+ NULL, chip->irq_base, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add rtc subdev\n");
goto out;
@@ -854,7 +867,7 @@ int max8925_device_init(struct max8925_chip *chip,
ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
ARRAY_SIZE(onkey_devs),
- &onkey_resources[0], 0, NULL);
+ NULL, chip->irq_base, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add onkey subdev\n");
goto out_dev;
@@ -873,21 +886,19 @@ int max8925_device_init(struct max8925_chip *chip,
goto out_dev;
}
- if (pdata && pdata->power) {
- ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
- ARRAY_SIZE(power_devs),
- &power_supply_resources[0], 0, NULL);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to add power supply "
- "subdev\n");
- goto out_dev;
- }
+ ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
+ ARRAY_SIZE(power_devs),
+ NULL, 0, NULL);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Failed to add power supply subdev, err = %d\n", ret);
+ goto out_dev;
}
if (pdata && pdata->touch) {
ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
ARRAY_SIZE(touch_devs),
- &touch_resources[0], 0, NULL);
+ NULL, chip->tsc_irq, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add touch subdev\n");
goto out_dev;
diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
index 00b5b456063d..92bbebd31598 100644
--- a/drivers/mfd/max8925-i2c.c
+++ b/drivers/mfd/max8925-i2c.c
@@ -135,13 +135,37 @@ static const struct i2c_device_id max8925_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, max8925_id_table);
+static int max8925_dt_init(struct device_node *np, struct device *dev,
+ struct max8925_platform_data *pdata)
+{
+ int ret;
+
+ ret = of_property_read_u32(np, "maxim,tsc-irq", &pdata->tsc_irq);
+ if (ret) {
+ dev_err(dev, "Not found maxim,tsc-irq property\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int max8925_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max8925_platform_data *pdata = client->dev.platform_data;
static struct max8925_chip *chip;
-
- if (!pdata) {
+ struct device_node *node = client->dev.of_node;
+
+ if (node && !pdata) {
+ /* parse DT to get platform data */
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct max8925_platform_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (max8925_dt_init(node, &client->dev, pdata))
+ return -EINVAL;
+ } else if (!pdata) {
pr_info("%s: platform data is missing\n", __func__);
return -EINVAL;
}
@@ -203,11 +227,18 @@ static int max8925_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(max8925_pm_ops, max8925_suspend, max8925_resume);
+static const struct of_device_id max8925_dt_ids[] = {
+ { .compatible = "maxim,max8925", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, max8925_dt_ids);
+
static struct i2c_driver max8925_driver = {
.driver = {
.name = "max8925",
.owner = THIS_MODULE,
.pm = &max8925_pm_ops,
+ .of_match_table = of_match_ptr(max8925_dt_ids),
},
.probe = max8925_probe,
.remove = max8925_remove,
@@ -217,7 +248,6 @@ static struct i2c_driver max8925_driver = {
static int __init max8925_i2c_init(void)
{
int ret;
-
ret = i2c_add_driver(&max8925_driver);
if (ret != 0)
pr_err("Failed to register MAX8925 I2C driver: %d\n", ret);
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 05164d7f054b..6b5edf64de2b 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
-#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/platform_data/usb-omap.h>
@@ -91,21 +90,23 @@
struct usbhs_hcd_omap {
+ int nports;
+ struct clk **utmi_clk;
+ struct clk **hsic60m_clk;
+ struct clk **hsic480m_clk;
+
struct clk *xclk60mhsp1_ck;
struct clk *xclk60mhsp2_ck;
- struct clk *utmi_p1_fck;
- struct clk *usbhost_p1_fck;
- struct clk *utmi_p2_fck;
- struct clk *usbhost_p2_fck;
+ struct clk *utmi_p1_gfclk;
+ struct clk *utmi_p2_gfclk;
struct clk *init_60m_fclk;
struct clk *ehci_logic_fck;
void __iomem *uhh_base;
- struct usbhs_omap_platform_data platdata;
+ struct usbhs_omap_platform_data *pdata;
u32 usbhs_rev;
- spinlock_t lock;
};
/*-------------------------------------------------------------------------*/
@@ -184,19 +185,13 @@ err_end:
static int omap_usbhs_alloc_children(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct usbhs_hcd_omap *omap;
- struct ehci_hcd_omap_platform_data *ehci_data;
- struct ohci_hcd_omap_platform_data *ohci_data;
+ struct usbhs_omap_platform_data *pdata = dev->platform_data;
struct platform_device *ehci;
struct platform_device *ohci;
struct resource *res;
struct resource resources[2];
int ret;
- omap = platform_get_drvdata(pdev);
- ehci_data = omap->platdata.ehci_data;
- ohci_data = omap->platdata.ohci_data;
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci");
if (!res) {
dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n");
@@ -213,8 +208,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
}
resources[1] = *res;
- ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, ehci_data,
- sizeof(*ehci_data), dev);
+ ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, pdata,
+ sizeof(*pdata), dev);
if (!ehci) {
dev_err(dev, "omap_usbhs_alloc_child failed\n");
@@ -238,8 +233,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
}
resources[1] = *res;
- ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, ohci_data,
- sizeof(*ohci_data), dev);
+ ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, pdata,
+ sizeof(*pdata), dev);
if (!ohci) {
dev_err(dev, "omap_usbhs_alloc_child failed\n");
ret = -ENOMEM;
@@ -278,31 +273,52 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
static int usbhs_runtime_resume(struct device *dev)
{
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
- struct usbhs_omap_platform_data *pdata = &omap->platdata;
- unsigned long flags;
+ struct usbhs_omap_platform_data *pdata = omap->pdata;
+ int i, r;
dev_dbg(dev, "usbhs_runtime_resume\n");
- if (!pdata) {
- dev_dbg(dev, "missing platform_data\n");
- return -ENODEV;
- }
-
omap_tll_enable();
- spin_lock_irqsave(&omap->lock, flags);
- if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
+ if (!IS_ERR(omap->ehci_logic_fck))
clk_enable(omap->ehci_logic_fck);
- if (is_ehci_tll_mode(pdata->port_mode[0]))
- clk_enable(omap->usbhost_p1_fck);
- if (is_ehci_tll_mode(pdata->port_mode[1]))
- clk_enable(omap->usbhost_p2_fck);
-
- clk_enable(omap->utmi_p1_fck);
- clk_enable(omap->utmi_p2_fck);
+ for (i = 0; i < omap->nports; i++) {
+ switch (pdata->port_mode[i]) {
+ case OMAP_EHCI_PORT_MODE_HSIC:
+ if (!IS_ERR(omap->hsic60m_clk[i])) {
+ r = clk_enable(omap->hsic60m_clk[i]);
+ if (r) {
+ dev_err(dev,
+ "Can't enable port %d hsic60m clk:%d\n",
+ i, r);
+ }
+ }
- spin_unlock_irqrestore(&omap->lock, flags);
+ if (!IS_ERR(omap->hsic480m_clk[i])) {
+ r = clk_enable(omap->hsic480m_clk[i]);
+ if (r) {
+ dev_err(dev,
+ "Can't enable port %d hsic480m clk:%d\n",
+ i, r);
+ }
+ }
+ /* Fall through as HSIC mode needs utmi_clk */
+
+ case OMAP_EHCI_PORT_MODE_TLL:
+ if (!IS_ERR(omap->utmi_clk[i])) {
+ r = clk_enable(omap->utmi_clk[i]);
+ if (r) {
+ dev_err(dev,
+ "Can't enable port %d clk : %d\n",
+ i, r);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
return 0;
}
@@ -310,51 +326,122 @@ static int usbhs_runtime_resume(struct device *dev)
static int usbhs_runtime_suspend(struct device *dev)
{
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
- struct usbhs_omap_platform_data *pdata = &omap->platdata;
- unsigned long flags;
+ struct usbhs_omap_platform_data *pdata = omap->pdata;
+ int i;
dev_dbg(dev, "usbhs_runtime_suspend\n");
- if (!pdata) {
- dev_dbg(dev, "missing platform_data\n");
- return -ENODEV;
- }
-
- spin_lock_irqsave(&omap->lock, flags);
+ for (i = 0; i < omap->nports; i++) {
+ switch (pdata->port_mode[i]) {
+ case OMAP_EHCI_PORT_MODE_HSIC:
+ if (!IS_ERR(omap->hsic60m_clk[i]))
+ clk_disable(omap->hsic60m_clk[i]);
- if (is_ehci_tll_mode(pdata->port_mode[0]))
- clk_disable(omap->usbhost_p1_fck);
- if (is_ehci_tll_mode(pdata->port_mode[1]))
- clk_disable(omap->usbhost_p2_fck);
+ if (!IS_ERR(omap->hsic480m_clk[i]))
+ clk_disable(omap->hsic480m_clk[i]);
+ /* Fall through as utmi_clks were used in HSIC mode */
- clk_disable(omap->utmi_p2_fck);
- clk_disable(omap->utmi_p1_fck);
+ case OMAP_EHCI_PORT_MODE_TLL:
+ if (!IS_ERR(omap->utmi_clk[i]))
+ clk_disable(omap->utmi_clk[i]);
+ break;
+ default:
+ break;
+ }
+ }
- if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
+ if (!IS_ERR(omap->ehci_logic_fck))
clk_disable(omap->ehci_logic_fck);
- spin_unlock_irqrestore(&omap->lock, flags);
omap_tll_disable();
return 0;
}
+static unsigned omap_usbhs_rev1_hostconfig(struct usbhs_hcd_omap *omap,
+ unsigned reg)
+{
+ struct usbhs_omap_platform_data *pdata = omap->pdata;
+ int i;
+
+ for (i = 0; i < omap->nports; i++) {
+ switch (pdata->port_mode[i]) {
+ case OMAP_USBHS_PORT_MODE_UNUSED:
+ reg &= ~(OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS << i);
+ break;
+ case OMAP_EHCI_PORT_MODE_PHY:
+ if (pdata->single_ulpi_bypass)
+ break;
+
+ if (i == 0)
+ reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
+ else
+ reg &= ~(OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
+ << (i-1));
+ break;
+ default:
+ if (pdata->single_ulpi_bypass)
+ break;
+
+ if (i == 0)
+ reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
+ else
+ reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
+ << (i-1);
+ break;
+ }
+ }
+
+ if (pdata->single_ulpi_bypass) {
+ /* bypass ULPI only if none of the ports use PHY mode */
+ reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
+
+ for (i = 0; i < omap->nports; i++) {
+ if (is_ehci_phy_mode(pdata->port_mode[i])) {
+ reg &= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
+ break;
+ }
+ }
+ }
+
+ return reg;
+}
+
+static unsigned omap_usbhs_rev2_hostconfig(struct usbhs_hcd_omap *omap,
+ unsigned reg)
+{
+ struct usbhs_omap_platform_data *pdata = omap->pdata;
+ int i;
+
+ for (i = 0; i < omap->nports; i++) {
+ /* Clear port mode fields for PHY mode */
+ reg &= ~(OMAP4_P1_MODE_CLEAR << 2 * i);
+
+ if (is_ehci_tll_mode(pdata->port_mode[i]) ||
+ (is_ohci_port(pdata->port_mode[i])))
+ reg |= OMAP4_P1_MODE_TLL << 2 * i;
+ else if (is_ehci_hsic_mode(pdata->port_mode[i]))
+ reg |= OMAP4_P1_MODE_HSIC << 2 * i;
+ }
+
+ return reg;
+}
+
static void omap_usbhs_init(struct device *dev)
{
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
- struct usbhs_omap_platform_data *pdata = &omap->platdata;
- unsigned long flags;
+ struct usbhs_omap_platform_data *pdata = omap->pdata;
unsigned reg;
dev_dbg(dev, "starting TI HSUSB Controller\n");
- if (pdata->ehci_data->phy_reset) {
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
- gpio_request_one(pdata->ehci_data->reset_gpio_port[0],
+ if (pdata->phy_reset) {
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
+ gpio_request_one(pdata->reset_gpio_port[0],
GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
- gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
+ gpio_request_one(pdata->reset_gpio_port[1],
GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
/* Hold the PHY in RESET for enough time till DIR is high */
@@ -362,9 +449,6 @@ static void omap_usbhs_init(struct device *dev)
}
pm_runtime_get_sync(dev);
- spin_lock_irqsave(&omap->lock, flags);
- omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
- dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
/* setup ULPI bypass and burst configurations */
@@ -374,89 +458,51 @@ static void omap_usbhs_init(struct device *dev)
reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK;
reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
- if (is_omap_usbhs_rev1(omap)) {
- if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED)
- reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
- if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED)
- reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
- if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED)
- reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
-
- /* Bypass the TLL module for PHY mode operation */
- if (pdata->single_ulpi_bypass) {
- dev_dbg(dev, "OMAP3 ES version <= ES2.1\n");
- if (is_ehci_phy_mode(pdata->port_mode[0]) ||
- is_ehci_phy_mode(pdata->port_mode[1]) ||
- is_ehci_phy_mode(pdata->port_mode[2]))
- reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
- else
- reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
- } else {
- dev_dbg(dev, "OMAP3 ES version > ES2.1\n");
- if (is_ehci_phy_mode(pdata->port_mode[0]))
- reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
- else
- reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
- if (is_ehci_phy_mode(pdata->port_mode[1]))
- reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
- else
- reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
- if (is_ehci_phy_mode(pdata->port_mode[2]))
- reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
- else
- reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
- }
- } else if (is_omap_usbhs_rev2(omap)) {
- /* Clear port mode fields for PHY mode*/
- reg &= ~OMAP4_P1_MODE_CLEAR;
- reg &= ~OMAP4_P2_MODE_CLEAR;
+ switch (omap->usbhs_rev) {
+ case OMAP_USBHS_REV1:
+ omap_usbhs_rev1_hostconfig(omap, reg);
+ break;
- if (is_ehci_tll_mode(pdata->port_mode[0]) ||
- (is_ohci_port(pdata->port_mode[0])))
- reg |= OMAP4_P1_MODE_TLL;
- else if (is_ehci_hsic_mode(pdata->port_mode[0]))
- reg |= OMAP4_P1_MODE_HSIC;
+ case OMAP_USBHS_REV2:
+ omap_usbhs_rev2_hostconfig(omap, reg);
+ break;
- if (is_ehci_tll_mode(pdata->port_mode[1]) ||
- (is_ohci_port(pdata->port_mode[1])))
- reg |= OMAP4_P2_MODE_TLL;
- else if (is_ehci_hsic_mode(pdata->port_mode[1]))
- reg |= OMAP4_P2_MODE_HSIC;
+ default: /* newer revisions */
+ omap_usbhs_rev2_hostconfig(omap, reg);
+ break;
}
usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
- spin_unlock_irqrestore(&omap->lock, flags);
-
pm_runtime_put_sync(dev);
- if (pdata->ehci_data->phy_reset) {
+ if (pdata->phy_reset) {
/* Hold the PHY in RESET for enough time till
* PHY is settled and ready
*/
udelay(10);
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
gpio_set_value_cansleep
- (pdata->ehci_data->reset_gpio_port[0], 1);
+ (pdata->reset_gpio_port[0], 1);
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
gpio_set_value_cansleep
- (pdata->ehci_data->reset_gpio_port[1], 1);
+ (pdata->reset_gpio_port[1], 1);
}
}
static void omap_usbhs_deinit(struct device *dev)
{
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
- struct usbhs_omap_platform_data *pdata = &omap->platdata;
+ struct usbhs_omap_platform_data *pdata = omap->pdata;
- 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]);
+ if (pdata->phy_reset) {
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
+ gpio_free(pdata->reset_gpio_port[0]);
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
- gpio_free(pdata->ehci_data->reset_gpio_port[1]);
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
+ gpio_free(pdata->reset_gpio_port[1]);
}
}
@@ -474,137 +520,185 @@ static int usbhs_omap_probe(struct platform_device *pdev)
struct resource *res;
int ret = 0;
int i;
+ bool need_logic_fck;
if (!pdata) {
dev_err(dev, "Missing platform data\n");
- ret = -ENOMEM;
- goto end_probe;
+ return -ENODEV;
}
- omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+ omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
if (!omap) {
dev_err(dev, "Memory allocation failed\n");
- ret = -ENOMEM;
- goto end_probe;
+ return -ENOMEM;
}
- spin_lock_init(&omap->lock);
-
- for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
- omap->platdata.port_mode[i] = pdata->port_mode[i];
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
+ omap->uhh_base = devm_request_and_ioremap(dev, res);
+ if (!omap->uhh_base) {
+ dev_err(dev, "Resource request/ioremap failed\n");
+ return -EADDRNOTAVAIL;
+ }
- omap->platdata.ehci_data = pdata->ehci_data;
- omap->platdata.ohci_data = pdata->ohci_data;
+ omap->pdata = pdata;
pm_runtime_enable(dev);
+ platform_set_drvdata(pdev, omap);
+ pm_runtime_get_sync(dev);
+
+ omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
- for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
- if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
- is_ehci_hsic_mode(i)) {
- omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
- if (IS_ERR(omap->ehci_logic_fck)) {
- ret = PTR_ERR(omap->ehci_logic_fck);
- dev_warn(dev, "ehci_logic_fck failed:%d\n",
- ret);
- }
+ /* we need to call runtime suspend before we update omap->nports
+ * to prevent unbalanced clk_disable()
+ */
+ pm_runtime_put_sync(dev);
+
+ /*
+ * If platform data contains nports then use that
+ * else make out number of ports from USBHS revision
+ */
+ if (pdata->nports) {
+ omap->nports = pdata->nports;
+ } else {
+ switch (omap->usbhs_rev) {
+ case OMAP_USBHS_REV1:
+ omap->nports = 3;
+ break;
+ case OMAP_USBHS_REV2:
+ omap->nports = 2;
+ break;
+ default:
+ omap->nports = OMAP3_HS_USB_PORTS;
+ dev_dbg(dev,
+ "USB HOST Rev:0x%d not recognized, assuming %d ports\n",
+ omap->usbhs_rev, omap->nports);
break;
}
+ }
- 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_end;
+ i = sizeof(struct clk *) * omap->nports;
+ omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL);
+ omap->hsic480m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
+ omap->hsic60m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
+
+ if (!omap->utmi_clk || !omap->hsic480m_clk || !omap->hsic60m_clk) {
+ dev_err(dev, "Memory allocation failed\n");
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+
+ need_logic_fck = false;
+ for (i = 0; i < omap->nports; i++) {
+ if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
+ is_ehci_hsic_mode(i))
+ need_logic_fck |= true;
+ }
+
+ omap->ehci_logic_fck = ERR_PTR(-EINVAL);
+ if (need_logic_fck) {
+ omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
+ if (IS_ERR(omap->ehci_logic_fck)) {
+ ret = PTR_ERR(omap->ehci_logic_fck);
+ dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret);
+ }
+ }
+
+ omap->utmi_p1_gfclk = clk_get(dev, "utmi_p1_gfclk");
+ if (IS_ERR(omap->utmi_p1_gfclk)) {
+ ret = PTR_ERR(omap->utmi_p1_gfclk);
+ dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
+ goto err_p1_gfclk;
+ }
+
+ omap->utmi_p2_gfclk = clk_get(dev, "utmi_p2_gfclk");
+ if (IS_ERR(omap->utmi_p2_gfclk)) {
+ ret = PTR_ERR(omap->utmi_p2_gfclk);
+ dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
+ goto err_p2_gfclk;
}
omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
if (IS_ERR(omap->xclk60mhsp1_ck)) {
ret = PTR_ERR(omap->xclk60mhsp1_ck);
dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
- goto err_utmi_p1_fck;
- }
-
- omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
- if (IS_ERR(omap->utmi_p2_fck)) {
- ret = PTR_ERR(omap->utmi_p2_fck);
- dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
- goto err_xclk60mhsp1_ck;
+ goto err_xclk60mhsp1;
}
omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
if (IS_ERR(omap->xclk60mhsp2_ck)) {
ret = PTR_ERR(omap->xclk60mhsp2_ck);
dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
- goto err_utmi_p2_fck;
- }
-
- omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
- if (IS_ERR(omap->usbhost_p1_fck)) {
- ret = PTR_ERR(omap->usbhost_p1_fck);
- dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
- goto err_xclk60mhsp2_ck;
- }
-
- omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
- if (IS_ERR(omap->usbhost_p2_fck)) {
- ret = PTR_ERR(omap->usbhost_p2_fck);
- dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
- goto err_usbhost_p1_fck;
+ goto err_xclk60mhsp2;
}
omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
if (IS_ERR(omap->init_60m_fclk)) {
ret = PTR_ERR(omap->init_60m_fclk);
dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
- goto err_usbhost_p2_fck;
+ goto err_init60m;
+ }
+
+ for (i = 0; i < omap->nports; i++) {
+ char clkname[30];
+
+ /* clock names are indexed from 1*/
+ snprintf(clkname, sizeof(clkname),
+ "usb_host_hs_utmi_p%d_clk", i + 1);
+
+ /* If a clock is not found we won't bail out as not all
+ * platforms have all clocks and we can function without
+ * them
+ */
+ omap->utmi_clk[i] = clk_get(dev, clkname);
+ if (IS_ERR(omap->utmi_clk[i]))
+ dev_dbg(dev, "Failed to get clock : %s : %ld\n",
+ clkname, PTR_ERR(omap->utmi_clk[i]));
+
+ snprintf(clkname, sizeof(clkname),
+ "usb_host_hs_hsic480m_p%d_clk", i + 1);
+ omap->hsic480m_clk[i] = clk_get(dev, clkname);
+ if (IS_ERR(omap->hsic480m_clk[i]))
+ dev_dbg(dev, "Failed to get clock : %s : %ld\n",
+ clkname, PTR_ERR(omap->hsic480m_clk[i]));
+
+ snprintf(clkname, sizeof(clkname),
+ "usb_host_hs_hsic60m_p%d_clk", i + 1);
+ omap->hsic60m_clk[i] = clk_get(dev, clkname);
+ if (IS_ERR(omap->hsic60m_clk[i]))
+ dev_dbg(dev, "Failed to get clock : %s : %ld\n",
+ clkname, PTR_ERR(omap->hsic60m_clk[i]));
}
if (is_ehci_phy_mode(pdata->port_mode[0])) {
- /* for OMAP3 , the clk set paretn fails */
- ret = clk_set_parent(omap->utmi_p1_fck,
+ /* for OMAP3, clk_set_parent fails */
+ ret = clk_set_parent(omap->utmi_p1_gfclk,
omap->xclk60mhsp1_ck);
if (ret != 0)
- dev_err(dev, "xclk60mhsp1_ck set parent"
- "failed error:%d\n", ret);
+ dev_dbg(dev, "xclk60mhsp1_ck set parent failed: %d\n",
+ ret);
} else if (is_ehci_tll_mode(pdata->port_mode[0])) {
- ret = clk_set_parent(omap->utmi_p1_fck,
+ ret = clk_set_parent(omap->utmi_p1_gfclk,
omap->init_60m_fclk);
if (ret != 0)
- dev_err(dev, "init_60m_fclk set parent"
- "failed error:%d\n", ret);
+ dev_dbg(dev, "P0 init_60m_fclk set parent failed: %d\n",
+ ret);
}
if (is_ehci_phy_mode(pdata->port_mode[1])) {
- ret = clk_set_parent(omap->utmi_p2_fck,
+ ret = clk_set_parent(omap->utmi_p2_gfclk,
omap->xclk60mhsp2_ck);
if (ret != 0)
- dev_err(dev, "xclk60mhsp2_ck set parent"
- "failed error:%d\n", ret);
+ dev_dbg(dev, "xclk60mhsp2_ck set parent failed: %d\n",
+ ret);
} else if (is_ehci_tll_mode(pdata->port_mode[1])) {
- ret = clk_set_parent(omap->utmi_p2_fck,
+ ret = clk_set_parent(omap->utmi_p2_gfclk,
omap->init_60m_fclk);
if (ret != 0)
- dev_err(dev, "init_60m_fclk set parent"
- "failed error:%d\n", ret);
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
- if (!res) {
- dev_err(dev, "UHH EHCI get resource failed\n");
- ret = -ENODEV;
- goto err_init_60m_fclk;
- }
-
- omap->uhh_base = ioremap(res->start, resource_size(res));
- if (!omap->uhh_base) {
- dev_err(dev, "UHH ioremap failed\n");
- ret = -ENOMEM;
- goto err_init_60m_fclk;
+ dev_dbg(dev, "P1 init_60m_fclk set parent failed: %d\n",
+ ret);
}
- platform_set_drvdata(pdev, omap);
-
omap_usbhs_init(dev);
ret = omap_usbhs_alloc_children(pdev);
if (ret) {
@@ -612,39 +706,41 @@ static int usbhs_omap_probe(struct platform_device *pdev)
goto err_alloc;
}
- goto end_probe;
+ return 0;
err_alloc:
omap_usbhs_deinit(&pdev->dev);
- iounmap(omap->uhh_base);
-
-err_init_60m_fclk:
- clk_put(omap->init_60m_fclk);
-err_usbhost_p2_fck:
- clk_put(omap->usbhost_p2_fck);
+ for (i = 0; i < omap->nports; i++) {
+ if (!IS_ERR(omap->utmi_clk[i]))
+ clk_put(omap->utmi_clk[i]);
+ if (!IS_ERR(omap->hsic60m_clk[i]))
+ clk_put(omap->hsic60m_clk[i]);
+ if (!IS_ERR(omap->hsic480m_clk[i]))
+ clk_put(omap->hsic480m_clk[i]);
+ }
-err_usbhost_p1_fck:
- clk_put(omap->usbhost_p1_fck);
+ clk_put(omap->init_60m_fclk);
-err_xclk60mhsp2_ck:
+err_init60m:
clk_put(omap->xclk60mhsp2_ck);
-err_utmi_p2_fck:
- clk_put(omap->utmi_p2_fck);
-
-err_xclk60mhsp1_ck:
+err_xclk60mhsp2:
clk_put(omap->xclk60mhsp1_ck);
-err_utmi_p1_fck:
- clk_put(omap->utmi_p1_fck);
+err_xclk60mhsp1:
+ clk_put(omap->utmi_p2_gfclk);
-err_end:
- clk_put(omap->ehci_logic_fck);
+err_p2_gfclk:
+ clk_put(omap->utmi_p1_gfclk);
+
+err_p1_gfclk:
+ if (!IS_ERR(omap->ehci_logic_fck))
+ clk_put(omap->ehci_logic_fck);
+
+err_mem:
pm_runtime_disable(dev);
- kfree(omap);
-end_probe:
return ret;
}
@@ -657,19 +753,29 @@ end_probe:
static int usbhs_omap_remove(struct platform_device *pdev)
{
struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
+ int i;
omap_usbhs_deinit(&pdev->dev);
- iounmap(omap->uhh_base);
+
+ for (i = 0; i < omap->nports; i++) {
+ if (!IS_ERR(omap->utmi_clk[i]))
+ clk_put(omap->utmi_clk[i]);
+ if (!IS_ERR(omap->hsic60m_clk[i]))
+ clk_put(omap->hsic60m_clk[i]);
+ if (!IS_ERR(omap->hsic480m_clk[i]))
+ clk_put(omap->hsic480m_clk[i]);
+ }
+
clk_put(omap->init_60m_fclk);
- clk_put(omap->usbhost_p2_fck);
- clk_put(omap->usbhost_p1_fck);
+ clk_put(omap->utmi_p1_gfclk);
+ clk_put(omap->utmi_p2_gfclk);
clk_put(omap->xclk60mhsp2_ck);
- clk_put(omap->utmi_p2_fck);
clk_put(omap->xclk60mhsp1_ck);
- clk_put(omap->utmi_p1_fck);
- clk_put(omap->ehci_logic_fck);
+
+ if (!IS_ERR(omap->ehci_logic_fck))
+ clk_put(omap->ehci_logic_fck);
+
pm_runtime_disable(&pdev->dev);
- kfree(omap);
return 0;
}
@@ -685,7 +791,7 @@ static struct platform_driver usbhs_omap_driver = {
.owner = THIS_MODULE,
.pm = &usbhsomap_dev_pm_ops,
},
- .remove = __exit_p(usbhs_omap_remove),
+ .remove = usbhs_omap_remove,
};
MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c
index eb869153206d..0aef1a768880 100644
--- a/drivers/mfd/omap-usb-tll.c
+++ b/drivers/mfd/omap-usb-tll.c
@@ -54,10 +54,13 @@
#define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num)
#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24
+#define OMAP_TLL_CHANNEL_CONF_DRVVBUS (1 << 16)
+#define OMAP_TLL_CHANNEL_CONF_CHRGVBUS (1 << 15)
#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11)
#define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10)
#define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9)
#define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8)
+#define OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI (2 << 1)
#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1)
#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0)
@@ -92,21 +95,25 @@
#define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */
#define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */
#define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */
+#define OMAP_USBTLL_REV4 0x00000006 /* OMAP5 */
#define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL)
+/* only PHY and UNUSED modes don't need TLL */
+#define omap_usb_mode_needs_tll(x) ((x) != OMAP_USBHS_PORT_MODE_UNUSED &&\
+ (x) != OMAP_EHCI_PORT_MODE_PHY)
+
struct usbtll_omap {
- struct clk *usbtll_p1_fck;
- struct clk *usbtll_p2_fck;
- struct usbtll_omap_platform_data platdata;
- /* secure the register updates */
- spinlock_t lock;
+ int nch; /* num. of channels */
+ struct usbhs_omap_platform_data *pdata;
+ struct clk **ch_clk;
};
/*-------------------------------------------------------------------------*/
-const char usbtll_driver_name[] = USBTLL_DRIVER_NAME;
-struct platform_device *tll_pdev;
+static const char usbtll_driver_name[] = USBTLL_DRIVER_NAME;
+static struct device *tll_dev;
+static DEFINE_SPINLOCK(tll_lock); /* serialize access to tll_dev */
/*-------------------------------------------------------------------------*/
@@ -203,84 +210,84 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode)
static int usbtll_omap_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct usbtll_omap_platform_data *pdata = dev->platform_data;
+ struct usbhs_omap_platform_data *pdata = dev->platform_data;
void __iomem *base;
struct resource *res;
struct usbtll_omap *tll;
unsigned reg;
- unsigned long flags;
int ret = 0;
- int i, ver, count;
+ int i, ver;
+ bool needs_tll;
dev_dbg(dev, "starting TI HSUSB TLL Controller\n");
- tll = kzalloc(sizeof(struct usbtll_omap), GFP_KERNEL);
+ tll = devm_kzalloc(dev, sizeof(struct usbtll_omap), GFP_KERNEL);
if (!tll) {
dev_err(dev, "Memory allocation failed\n");
- ret = -ENOMEM;
- goto end;
+ return -ENOMEM;
}
- spin_lock_init(&tll->lock);
-
- for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
- tll->platdata.port_mode[i] = pdata->port_mode[i];
-
- tll->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
- if (IS_ERR(tll->usbtll_p1_fck)) {
- ret = PTR_ERR(tll->usbtll_p1_fck);
- dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
- goto err_tll;
+ if (!pdata) {
+ dev_err(dev, "Platform data missing\n");
+ return -ENODEV;
}
- tll->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
- if (IS_ERR(tll->usbtll_p2_fck)) {
- ret = PTR_ERR(tll->usbtll_p2_fck);
- dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
- goto err_usbtll_p1_fck;
- }
+ tll->pdata = pdata;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "usb tll get resource failed\n");
- ret = -ENODEV;
- goto err_usbtll_p2_fck;
- }
-
- base = ioremap(res->start, resource_size(res));
+ base = devm_request_and_ioremap(dev, res);
if (!base) {
- dev_err(dev, "TLL ioremap failed\n");
- ret = -ENOMEM;
- goto err_usbtll_p2_fck;
+ ret = -EADDRNOTAVAIL;
+ dev_err(dev, "Resource request/ioremap failed:%d\n", ret);
+ return ret;
}
platform_set_drvdata(pdev, tll);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
- spin_lock_irqsave(&tll->lock, flags);
-
ver = usbtll_read(base, OMAP_USBTLL_REVISION);
switch (ver) {
case OMAP_USBTLL_REV1:
- case OMAP_USBTLL_REV2:
- count = OMAP_TLL_CHANNEL_COUNT;
+ case OMAP_USBTLL_REV4:
+ tll->nch = OMAP_TLL_CHANNEL_COUNT;
break;
+ case OMAP_USBTLL_REV2:
case OMAP_USBTLL_REV3:
- count = OMAP_REV2_TLL_CHANNEL_COUNT;
+ tll->nch = OMAP_REV2_TLL_CHANNEL_COUNT;
break;
default:
- dev_err(dev, "TLL version failed\n");
- ret = -ENODEV;
- goto err_ioremap;
+ tll->nch = OMAP_TLL_CHANNEL_COUNT;
+ dev_dbg(dev,
+ "USB TLL Rev : 0x%x not recognized, assuming %d channels\n",
+ ver, tll->nch);
+ break;
}
- if (is_ehci_tll_mode(pdata->port_mode[0]) ||
- is_ehci_tll_mode(pdata->port_mode[1]) ||
- is_ehci_tll_mode(pdata->port_mode[2]) ||
- is_ohci_port(pdata->port_mode[0]) ||
- is_ohci_port(pdata->port_mode[1]) ||
- is_ohci_port(pdata->port_mode[2])) {
+ tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]),
+ GFP_KERNEL);
+ if (!tll->ch_clk) {
+ ret = -ENOMEM;
+ dev_err(dev, "Couldn't allocate memory for channel clocks\n");
+ goto err_clk_alloc;
+ }
+
+ for (i = 0; i < tll->nch; i++) {
+ char clkname[] = "usb_tll_hs_usb_chx_clk";
+
+ snprintf(clkname, sizeof(clkname),
+ "usb_tll_hs_usb_ch%d_clk", i);
+ tll->ch_clk[i] = clk_get(dev, clkname);
+
+ if (IS_ERR(tll->ch_clk[i]))
+ dev_dbg(dev, "can't get clock : %s\n", clkname);
+ }
+
+ needs_tll = false;
+ for (i = 0; i < tll->nch; i++)
+ needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]);
+
+ if (needs_tll) {
/* Program Common TLL register */
reg = usbtll_read(base, OMAP_TLL_SHARED_CONF);
@@ -292,7 +299,7 @@ static int usbtll_omap_probe(struct platform_device *pdev)
usbtll_write(base, OMAP_TLL_SHARED_CONF, reg);
/* Enable channels now */
- for (i = 0; i < count; i++) {
+ for (i = 0; i < tll->nch; i++) {
reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i));
if (is_ohci_port(pdata->port_mode[i])) {
@@ -308,6 +315,15 @@ static int usbtll_omap_probe(struct platform_device *pdev)
reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
+ } else if (pdata->port_mode[i] ==
+ OMAP_EHCI_PORT_MODE_HSIC) {
+ /*
+ * HSIC Mode requires UTMI port configurations
+ */
+ reg |= OMAP_TLL_CHANNEL_CONF_DRVVBUS
+ | OMAP_TLL_CHANNEL_CONF_CHRGVBUS
+ | OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI
+ | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF;
} else {
continue;
}
@@ -320,25 +336,18 @@ static int usbtll_omap_probe(struct platform_device *pdev)
}
}
-err_ioremap:
- spin_unlock_irqrestore(&tll->lock, flags);
- iounmap(base);
pm_runtime_put_sync(dev);
- tll_pdev = pdev;
- if (!ret)
- goto end;
- pm_runtime_disable(dev);
+ /* only after this can omap_tll_enable/disable work */
+ spin_lock(&tll_lock);
+ tll_dev = dev;
+ spin_unlock(&tll_lock);
-err_usbtll_p2_fck:
- clk_put(tll->usbtll_p2_fck);
-
-err_usbtll_p1_fck:
- clk_put(tll->usbtll_p1_fck);
+ return 0;
-err_tll:
- kfree(tll);
+err_clk_alloc:
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
-end:
return ret;
}
@@ -351,36 +360,42 @@ end:
static int usbtll_omap_remove(struct platform_device *pdev)
{
struct usbtll_omap *tll = platform_get_drvdata(pdev);
+ int i;
+
+ spin_lock(&tll_lock);
+ tll_dev = NULL;
+ spin_unlock(&tll_lock);
+
+ for (i = 0; i < tll->nch; i++)
+ if (!IS_ERR(tll->ch_clk[i]))
+ clk_put(tll->ch_clk[i]);
- clk_put(tll->usbtll_p2_fck);
- clk_put(tll->usbtll_p1_fck);
pm_runtime_disable(&pdev->dev);
- kfree(tll);
return 0;
}
static int usbtll_runtime_resume(struct device *dev)
{
struct usbtll_omap *tll = dev_get_drvdata(dev);
- struct usbtll_omap_platform_data *pdata = &tll->platdata;
- unsigned long flags;
+ struct usbhs_omap_platform_data *pdata = tll->pdata;
+ int i;
dev_dbg(dev, "usbtll_runtime_resume\n");
- if (!pdata) {
- dev_dbg(dev, "missing platform_data\n");
- return -ENODEV;
- }
-
- spin_lock_irqsave(&tll->lock, flags);
+ for (i = 0; i < tll->nch; i++) {
+ if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
+ int r;
- if (is_ehci_tll_mode(pdata->port_mode[0]))
- clk_enable(tll->usbtll_p1_fck);
-
- if (is_ehci_tll_mode(pdata->port_mode[1]))
- clk_enable(tll->usbtll_p2_fck);
+ if (IS_ERR(tll->ch_clk[i]))
+ continue;
- spin_unlock_irqrestore(&tll->lock, flags);
+ r = clk_enable(tll->ch_clk[i]);
+ if (r) {
+ dev_err(dev,
+ "Error enabling ch %d clock: %d\n", i, r);
+ }
+ }
+ }
return 0;
}
@@ -388,26 +403,18 @@ static int usbtll_runtime_resume(struct device *dev)
static int usbtll_runtime_suspend(struct device *dev)
{
struct usbtll_omap *tll = dev_get_drvdata(dev);
- struct usbtll_omap_platform_data *pdata = &tll->platdata;
- unsigned long flags;
+ struct usbhs_omap_platform_data *pdata = tll->pdata;
+ int i;
dev_dbg(dev, "usbtll_runtime_suspend\n");
- if (!pdata) {
- dev_dbg(dev, "missing platform_data\n");
- return -ENODEV;
+ for (i = 0; i < tll->nch; i++) {
+ if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
+ if (!IS_ERR(tll->ch_clk[i]))
+ clk_disable(tll->ch_clk[i]);
+ }
}
- spin_lock_irqsave(&tll->lock, flags);
-
- if (is_ehci_tll_mode(pdata->port_mode[0]))
- clk_disable(tll->usbtll_p1_fck);
-
- if (is_ehci_tll_mode(pdata->port_mode[1]))
- clk_disable(tll->usbtll_p2_fck);
-
- spin_unlock_irqrestore(&tll->lock, flags);
-
return 0;
}
@@ -429,21 +436,39 @@ static struct platform_driver usbtll_omap_driver = {
int omap_tll_enable(void)
{
- if (!tll_pdev) {
- pr_err("missing omap usbhs tll platform_data\n");
- return -ENODEV;
+ int ret;
+
+ spin_lock(&tll_lock);
+
+ if (!tll_dev) {
+ pr_err("%s: OMAP USB TLL not initialized\n", __func__);
+ ret = -ENODEV;
+ } else {
+ ret = pm_runtime_get_sync(tll_dev);
}
- return pm_runtime_get_sync(&tll_pdev->dev);
+
+ spin_unlock(&tll_lock);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(omap_tll_enable);
int omap_tll_disable(void)
{
- if (!tll_pdev) {
- pr_err("missing omap usbhs tll platform_data\n");
- return -ENODEV;
+ int ret;
+
+ spin_lock(&tll_lock);
+
+ if (!tll_dev) {
+ pr_err("%s: OMAP USB TLL not initialized\n", __func__);
+ ret = -ENODEV;
+ } else {
+ ret = pm_runtime_put_sync(tll_dev);
}
- return pm_runtime_put_sync(&tll_pdev->dev);
+
+ spin_unlock(&tll_lock);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(omap_tll_disable);
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c
index 6ffd7a2affdc..bbdbc50a3cca 100644
--- a/drivers/mfd/palmas.c
+++ b/drivers/mfd/palmas.c
@@ -39,6 +39,14 @@ enum palmas_ids {
PALMAS_USB_ID,
};
+static struct resource palmas_rtc_resources[] = {
+ {
+ .start = PALMAS_RTC_ALARM_IRQ,
+ .end = PALMAS_RTC_ALARM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static const struct mfd_cell palmas_children[] = {
{
.name = "palmas-pmic",
@@ -59,6 +67,8 @@ static const struct mfd_cell palmas_children[] = {
{
.name = "palmas-rtc",
.id = PALMAS_RTC_ID,
+ .resources = &palmas_rtc_resources[0],
+ .num_resources = ARRAY_SIZE(palmas_rtc_resources),
},
{
.name = "palmas-pwrbutton",
@@ -456,8 +466,8 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
ret = mfd_add_devices(palmas->dev, -1,
children, ARRAY_SIZE(palmas_children),
- NULL, regmap_irq_chip_get_base(palmas->irq_data),
- NULL);
+ NULL, 0,
+ regmap_irq_get_domain(palmas->irq_data));
kfree(children);
if (ret < 0)
diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c
index 3d3b4addf81a..2a2d31687b72 100644
--- a/drivers/mfd/rtl8411.c
+++ b/drivers/mfd/rtl8411.c
@@ -115,14 +115,24 @@ static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card)
static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
{
u8 mask, val;
+ int err;
mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK;
- if (voltage == OUTPUT_3V3)
+ if (voltage == OUTPUT_3V3) {
+ err = rtsx_pci_write_register(pcr,
+ SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
+ if (err < 0)
+ return err;
val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3;
- else if (voltage == OUTPUT_1V8)
+ } else if (voltage == OUTPUT_1V8) {
+ err = rtsx_pci_write_register(pcr,
+ SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
+ if (err < 0)
+ return err;
val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8;
- else
+ } else {
return -EINVAL;
+ }
return rtsx_pci_write_register(pcr, LDO_CTL, mask, val);
}
diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c
index 98fe0f39463e..ec78d9fb0879 100644
--- a/drivers/mfd/rts5209.c
+++ b/drivers/mfd/rts5209.c
@@ -149,10 +149,18 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
int err;
if (voltage == OUTPUT_3V3) {
+ err = rtsx_pci_write_register(pcr,
+ SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
+ if (err < 0)
+ return err;
err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
if (err < 0)
return err;
} else if (voltage == OUTPUT_1V8) {
+ err = rtsx_pci_write_register(pcr,
+ SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
+ if (err < 0)
+ return err;
err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
if (err < 0)
return err;
diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c
new file mode 100644
index 000000000000..fc831dcb1480
--- /dev/null
+++ b/drivers/mfd/rts5227.c
@@ -0,0 +1,234 @@
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009 Realtek Semiconductor 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, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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/>.
+ *
+ * Author:
+ * Wei WANG <wei_wang@realsil.com.cn>
+ * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ *
+ * Roger Tseng <rogerable@realtek.com>
+ * No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mfd/rtsx_pci.h>
+
+#include "rtsx_pcr.h"
+
+static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
+{
+ u16 cap;
+
+ rtsx_pci_init_cmd(pcr);
+
+ /* Configure GPIO as output */
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
+ /* Switch LDO3318 source from DV33 to card_3v3 */
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
+ /* LED shine disabled, set initial shine cycle period */
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
+ /* Configure LTR */
+ pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &cap);
+ if (cap & PCI_EXP_LTR_EN)
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LTR_CTL, 0xFF, 0xA3);
+ /* Configure OBFF */
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG, 0x03, 0x03);
+ /* Configure force_clock_req
+ * Maybe We should define 0xFF03 as some name
+ */
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, 0xFF03, 0x08, 0x08);
+ /* Correct driving */
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+ SD30_CLK_DRIVE_SEL, 0xFF, 0x96);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+ SD30_CMD_DRIVE_SEL, 0xFF, 0x96);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+ SD30_DAT_DRIVE_SEL, 0xFF, 0x96);
+
+ return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5227_optimize_phy(struct rtsx_pcr *pcr)
+{
+ /* Optimize RX sensitivity */
+ return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
+}
+
+static int rts5227_turn_on_led(struct rtsx_pcr *pcr)
+{
+ return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02);
+}
+
+static int rts5227_turn_off_led(struct rtsx_pcr *pcr)
+{
+ return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
+}
+
+static int rts5227_enable_auto_blink(struct rtsx_pcr *pcr)
+{
+ return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08);
+}
+
+static int rts5227_disable_auto_blink(struct rtsx_pcr *pcr)
+{
+ return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00);
+}
+
+static int rts5227_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+ int err;
+
+ rtsx_pci_init_cmd(pcr);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+ SD_POWER_MASK, SD_PARTIAL_POWER_ON);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+ LDO3318_PWR_MASK, 0x02);
+ err = rtsx_pci_send_cmd(pcr, 100);
+ if (err < 0)
+ return err;
+
+ /* To avoid too large in-rush current */
+ udelay(150);
+
+ rtsx_pci_init_cmd(pcr);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+ SD_POWER_MASK, SD_POWER_ON);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+ LDO3318_PWR_MASK, 0x06);
+ err = rtsx_pci_send_cmd(pcr, 100);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rts5227_card_power_off(struct rtsx_pcr *pcr, int card)
+{
+ rtsx_pci_init_cmd(pcr);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
+ SD_POWER_MASK | PMOS_STRG_MASK,
+ SD_POWER_OFF | PMOS_STRG_400mA);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
+ LDO3318_PWR_MASK, 0X00);
+ return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+ int err;
+ u8 drive_sel;
+
+ if (voltage == OUTPUT_3V3) {
+ err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
+ if (err < 0)
+ return err;
+ drive_sel = 0x96;
+ } else if (voltage == OUTPUT_1V8) {
+ err = rtsx_pci_write_phy_register(pcr, 0x11, 0x3C02);
+ if (err < 0)
+ return err;
+ err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C80 | 0x24);
+ if (err < 0)
+ return err;
+ drive_sel = 0xB3;
+ } else {
+ return -EINVAL;
+ }
+
+ /* set pad drive */
+ rtsx_pci_init_cmd(pcr);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
+ 0xFF, drive_sel);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
+ 0xFF, drive_sel);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
+ 0xFF, drive_sel);
+ return rtsx_pci_send_cmd(pcr, 100);
+}
+
+static const struct pcr_ops rts5227_pcr_ops = {
+ .extra_init_hw = rts5227_extra_init_hw,
+ .optimize_phy = rts5227_optimize_phy,
+ .turn_on_led = rts5227_turn_on_led,
+ .turn_off_led = rts5227_turn_off_led,
+ .enable_auto_blink = rts5227_enable_auto_blink,
+ .disable_auto_blink = rts5227_disable_auto_blink,
+ .card_power_on = rts5227_card_power_on,
+ .card_power_off = rts5227_card_power_off,
+ .switch_output_voltage = rts5227_switch_output_voltage,
+ .cd_deglitch = NULL,
+ .conv_clk_and_div_n = NULL,
+};
+
+/* SD Pull Control Enable:
+ * SD_DAT[3:0] ==> pull up
+ * SD_CD ==> pull up
+ * SD_WP ==> pull up
+ * SD_CMD ==> pull up
+ * SD_CLK ==> pull down
+ */
+static const u32 rts5227_sd_pull_ctl_enable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
+ 0,
+};
+
+/* SD Pull Control Disable:
+ * SD_DAT[3:0] ==> pull down
+ * SD_CD ==> pull up
+ * SD_WP ==> pull down
+ * SD_CMD ==> pull down
+ * SD_CLK ==> pull down
+ */
+static const u32 rts5227_sd_pull_ctl_disable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
+ 0,
+};
+
+/* MS Pull Control Enable:
+ * MS CD ==> pull up
+ * others ==> pull down
+ */
+static const u32 rts5227_ms_pull_ctl_enable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+ RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+ 0,
+};
+
+/* MS Pull Control Disable:
+ * MS CD ==> pull up
+ * others ==> pull down
+ */
+static const u32 rts5227_ms_pull_ctl_disable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55),
+ RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15),
+ 0,
+};
+
+void rts5227_init_params(struct rtsx_pcr *pcr)
+{
+ pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+ pcr->num_slots = 2;
+ pcr->ops = &rts5227_pcr_ops;
+
+ pcr->sd_pull_ctl_enable_tbl = rts5227_sd_pull_ctl_enable_tbl;
+ pcr->sd_pull_ctl_disable_tbl = rts5227_sd_pull_ctl_disable_tbl;
+ pcr->ms_pull_ctl_enable_tbl = rts5227_ms_pull_ctl_enable_tbl;
+ pcr->ms_pull_ctl_disable_tbl = rts5227_ms_pull_ctl_disable_tbl;
+}
diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c
index 29d889cbb9c5..58af4dbe3586 100644
--- a/drivers/mfd/rts5229.c
+++ b/drivers/mfd/rts5229.c
@@ -119,10 +119,18 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
int err;
if (voltage == OUTPUT_3V3) {
+ err = rtsx_pci_write_register(pcr,
+ SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
+ if (err < 0)
+ return err;
err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
if (err < 0)
return err;
} else if (voltage == OUTPUT_1V8) {
+ err = rtsx_pci_write_register(pcr,
+ SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
+ if (err < 0)
+ return err;
err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
if (err < 0)
return err;
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
index 9fc57009e228..481a98a10ecd 100644
--- a/drivers/mfd/rtsx_pcr.c
+++ b/drivers/mfd/rtsx_pcr.c
@@ -55,6 +55,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = {
{ PCI_DEVICE(0x10EC, 0x5209), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+ { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ 0, }
};
@@ -325,7 +326,6 @@ static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr,
val = ((u64)addr << 32) | ((u64)len << 12) | option;
put_unaligned_le64(val, ptr);
- ptr++;
pcr->sgi++;
}
@@ -591,8 +591,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
{
int err, clk;
- u8 N, min_N, max_N, clk_divider;
- u8 mcu_cnt, div, max_div;
+ u8 n, clk_divider, mcu_cnt, div;
u8 depth[] = {
[RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M,
[RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M,
@@ -616,10 +615,6 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
card_clock /= 1000000;
dev_dbg(&(pcr->pci->dev), "Switch card clock to %dMHz\n", card_clock);
- min_N = 80;
- max_N = 208;
- max_div = CLK_DIV_8;
-
clk = card_clock;
if (!initial_mode && double_clk)
clk = card_clock * 2;
@@ -631,30 +626,30 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
return 0;
if (pcr->ops->conv_clk_and_div_n)
- N = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
+ n = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
else
- N = (u8)(clk - 2);
- if ((clk <= 2) || (N > max_N))
+ n = (u8)(clk - 2);
+ if ((clk <= 2) || (n > MAX_DIV_N_PCR))
return -EINVAL;
mcu_cnt = (u8)(125/clk + 3);
if (mcu_cnt > 15)
mcu_cnt = 15;
- /* Make sure that the SSC clock div_n is equal or greater than min_N */
+ /* Make sure that the SSC clock div_n is not less than MIN_DIV_N_PCR */
div = CLK_DIV_1;
- while ((N < min_N) && (div < max_div)) {
+ while ((n < MIN_DIV_N_PCR) && (div < CLK_DIV_8)) {
if (pcr->ops->conv_clk_and_div_n) {
- int dbl_clk = pcr->ops->conv_clk_and_div_n(N,
+ int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
DIV_N_TO_CLK) * 2;
- N = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
+ n = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
CLK_TO_DIV_N);
} else {
- N = (N + 2) * 2 - 2;
+ n = (n + 2) * 2 - 2;
}
div++;
}
- dev_dbg(&(pcr->pci->dev), "N = %d, div = %d\n", N, div);
+ dev_dbg(&(pcr->pci->dev), "n = %d, div = %d\n", n, div);
ssc_depth = depth[ssc_depth];
if (double_clk)
@@ -671,7 +666,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2,
SSC_DEPTH_MASK, ssc_depth);
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
if (vpclk) {
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
@@ -713,6 +708,25 @@ int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card)
}
EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off);
+int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card)
+{
+ unsigned int cd_mask[] = {
+ [RTSX_SD_CARD] = SD_EXIST,
+ [RTSX_MS_CARD] = MS_EXIST
+ };
+
+ if (!pcr->ms_pmos) {
+ /* When using single PMOS, accessing card is not permitted
+ * if the existing card is not the designated one.
+ */
+ if (pcr->card_exist & (~cd_mask[card]))
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_card_exclusive_check);
+
int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
{
if (pcr->ops->switch_output_voltage)
@@ -758,7 +772,7 @@ static void rtsx_pci_card_detect(struct work_struct *work)
struct delayed_work *dwork;
struct rtsx_pcr *pcr;
unsigned long flags;
- unsigned int card_detect = 0;
+ unsigned int card_detect = 0, card_inserted, card_removed;
u32 irq_status;
dwork = to_delayed_work(work);
@@ -766,25 +780,35 @@ static void rtsx_pci_card_detect(struct work_struct *work)
dev_dbg(&(pcr->pci->dev), "--> %s\n", __func__);
+ mutex_lock(&pcr->pcr_mutex);
spin_lock_irqsave(&pcr->lock, flags);
irq_status = rtsx_pci_readl(pcr, RTSX_BIPR);
dev_dbg(&(pcr->pci->dev), "irq_status: 0x%08x\n", irq_status);
- if (pcr->card_inserted || pcr->card_removed) {
+ irq_status &= CARD_EXIST;
+ card_inserted = pcr->card_inserted & irq_status;
+ card_removed = pcr->card_removed;
+ pcr->card_inserted = 0;
+ pcr->card_removed = 0;
+
+ spin_unlock_irqrestore(&pcr->lock, flags);
+
+ if (card_inserted || card_removed) {
dev_dbg(&(pcr->pci->dev),
"card_inserted: 0x%x, card_removed: 0x%x\n",
- pcr->card_inserted, pcr->card_removed);
+ card_inserted, card_removed);
if (pcr->ops->cd_deglitch)
- pcr->card_inserted = pcr->ops->cd_deglitch(pcr);
+ card_inserted = pcr->ops->cd_deglitch(pcr);
+
+ card_detect = card_inserted | card_removed;
- card_detect = pcr->card_inserted | pcr->card_removed;
- pcr->card_inserted = 0;
- pcr->card_removed = 0;
+ pcr->card_exist |= card_inserted;
+ pcr->card_exist &= ~card_removed;
}
- spin_unlock_irqrestore(&pcr->lock, flags);
+ mutex_unlock(&pcr->pcr_mutex);
if ((card_detect & SD_EXIST) && pcr->slots[RTSX_SD_CARD].card_event)
pcr->slots[RTSX_SD_CARD].card_event(
@@ -836,10 +860,6 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
}
}
- if (pcr->card_inserted || pcr->card_removed)
- schedule_delayed_work(&pcr->carddet_work,
- msecs_to_jiffies(200));
-
if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
pcr->trans_result = TRANS_RESULT_FAIL;
@@ -852,6 +872,10 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
}
}
+ if (pcr->card_inserted || pcr->card_removed)
+ schedule_delayed_work(&pcr->carddet_work,
+ msecs_to_jiffies(200));
+
spin_unlock(&pcr->lock);
return IRQ_HANDLED;
}
@@ -974,6 +998,14 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
return err;
}
+ /* No CD interrupt if probing driver with card inserted.
+ * So we need to initialize pcr->card_exist here.
+ */
+ if (pcr->ops->cd_deglitch)
+ pcr->card_exist = pcr->ops->cd_deglitch(pcr);
+ else
+ pcr->card_exist = rtsx_pci_readl(pcr, RTSX_BIPR) & CARD_EXIST;
+
return 0;
}
@@ -997,6 +1029,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
case 0x5289:
rtl8411_init_params(pcr);
break;
+
+ case 0x5227:
+ rts5227_init_params(pcr);
+ break;
}
dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n",
@@ -1030,6 +1066,10 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device,
(int)pcidev->revision);
+ ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
+ if (ret < 0)
+ return ret;
+
ret = pci_enable_device(pcidev);
if (ret)
return ret;
diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h
index 12462c1df1a9..2b3ab8a04823 100644
--- a/drivers/mfd/rtsx_pcr.h
+++ b/drivers/mfd/rtsx_pcr.h
@@ -25,8 +25,12 @@
#include <linux/mfd/rtsx_pci.h>
+#define MIN_DIV_N_PCR 80
+#define MAX_DIV_N_PCR 208
+
void rts5209_init_params(struct rtsx_pcr *pcr);
void rts5229_init_params(struct rtsx_pcr *pcr);
void rtl8411_init_params(struct rtsx_pcr *pcr);
+void rts5227_init_params(struct rtsx_pcr *pcr);
#endif
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index 49d361a618d0..77ee26ef5941 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
@@ -60,6 +61,15 @@ static struct mfd_cell s2mps11_devs[] = {
},
};
+#ifdef CONFIG_OF
+static struct of_device_id sec_dt_match[] = {
+ { .compatible = "samsung,s5m8767-pmic",
+ .data = (void *)S5M8767X,
+ },
+ {},
+};
+#endif
+
int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest)
{
return regmap_read(sec_pmic->regmap, reg, dest);
@@ -95,6 +105,57 @@ static struct regmap_config sec_regmap_config = {
.val_bits = 8,
};
+
+#ifdef CONFIG_OF
+/*
+ * Only the common platform data elements for s5m8767 are parsed here from the
+ * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and
+ * others have to parse their own platform data elements from device tree.
+ *
+ * The s5m8767 platform data structure is instantiated here and the drivers for
+ * the sub-modules need not instantiate another instance while parsing their
+ * platform data.
+ */
+static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
+ struct device *dev)
+{
+ struct sec_platform_data *pd;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ dev_err(dev, "could not allocate memory for pdata\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /*
+ * ToDo: the 'wakeup' member in the platform data is more of a linux
+ * specfic information. Hence, there is no binding for that yet and
+ * not parsed here.
+ */
+
+ return pd;
+}
+#else
+static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
+ struct device *dev)
+{
+ return 0;
+}
+#endif
+
+static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+#ifdef CONFIG_OF
+ if (i2c->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(sec_dt_match, i2c->dev.of_node);
+ return (int)match->data;
+ }
+#endif
+ return (int)id->driver_data;
+}
+
static int sec_pmic_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -111,13 +172,22 @@ static int sec_pmic_probe(struct i2c_client *i2c,
sec_pmic->dev = &i2c->dev;
sec_pmic->i2c = i2c;
sec_pmic->irq = i2c->irq;
- sec_pmic->type = id->driver_data;
-
+ sec_pmic->type = sec_i2c_get_driver_data(i2c, id);
+
+ if (sec_pmic->dev->of_node) {
+ pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ return ret;
+ }
+ pdata->device_type = sec_pmic->type;
+ }
if (pdata) {
sec_pmic->device_type = pdata->device_type;
sec_pmic->ono = pdata->ono;
sec_pmic->irq_base = pdata->irq_base;
sec_pmic->wakeup = pdata->wakeup;
+ sec_pmic->pdata = pdata;
}
sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config);
@@ -192,6 +262,7 @@ static struct i2c_driver sec_pmic_driver = {
.driver = {
.name = "sec_pmic",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(sec_dt_match),
},
.probe = sec_pmic_probe,
.remove = sec_pmic_remove,
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 3f10591ea94e..61aea6381cdf 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -20,6 +20,7 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
static struct platform_driver syscon_driver;
diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c
index 409afa23d5dc..5ad4b772b097 100644
--- a/drivers/mfd/tps6507x.c
+++ b/drivers/mfd/tps6507x.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/of_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps6507x.h>
@@ -116,11 +117,19 @@ static const struct i2c_device_id tps6507x_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id);
+#ifdef CONFIG_OF
+static struct of_device_id tps6507x_of_match[] = {
+ {.compatible = "ti,tps6507x", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tps6507x_of_match);
+#endif
static struct i2c_driver tps6507x_i2c_driver = {
.driver = {
.name = "tps6507x",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tps6507x_of_match),
},
.probe = tps6507x_i2c_probe,
.remove = tps6507x_i2c_remove,
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c
index 8d12a8e00d9c..98edb5be85c6 100644
--- a/drivers/mfd/tps65090.c
+++ b/drivers/mfd/tps65090.c
@@ -25,6 +25,8 @@
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps65090.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/err.h>
#define NUM_INT_REG 2
@@ -148,18 +150,31 @@ static const struct regmap_config tps65090_regmap_config = {
.volatile_reg = is_volatile_reg,
};
+#ifdef CONFIG_OF
+static const struct of_device_id tps65090_of_match[] = {
+ { .compatible = "ti,tps65090",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, tps65090_of_match);
+#endif
+
static int tps65090_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tps65090_platform_data *pdata = client->dev.platform_data;
+ int irq_base = 0;
struct tps65090 *tps65090;
int ret;
- if (!pdata) {
- dev_err(&client->dev, "tps65090 requires platform data\n");
+ if (!pdata && !client->dev.of_node) {
+ dev_err(&client->dev,
+ "tps65090 requires platform data or of_node\n");
return -EINVAL;
}
+ if (pdata)
+ irq_base = pdata->irq_base;
+
tps65090 = devm_kzalloc(&client->dev, sizeof(*tps65090), GFP_KERNEL);
if (!tps65090) {
dev_err(&client->dev, "mem alloc for tps65090 failed\n");
@@ -178,7 +193,7 @@ static int tps65090_i2c_probe(struct i2c_client *client,
if (client->irq) {
ret = regmap_add_irq_chip(tps65090->rmap, client->irq,
- IRQF_ONESHOT | IRQF_TRIGGER_LOW, pdata->irq_base,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
&tps65090_irq_chip, &tps65090->irq_data);
if (ret) {
dev_err(&client->dev,
@@ -189,7 +204,7 @@ static int tps65090_i2c_probe(struct i2c_client *client,
ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
ARRAY_SIZE(tps65090s), NULL,
- regmap_irq_chip_get_base(tps65090->irq_data), NULL);
+ 0, regmap_irq_get_domain(tps65090->irq_data));
if (ret) {
dev_err(&client->dev, "add mfd devices failed with err: %d\n",
ret);
@@ -215,28 +230,6 @@ static int tps65090_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int tps65090_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- if (client->irq)
- disable_irq(client->irq);
- return 0;
-}
-
-static int tps65090_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- if (client->irq)
- enable_irq(client->irq);
- return 0;
-}
-#endif
-
-static const struct dev_pm_ops tps65090_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(tps65090_suspend, tps65090_resume)
-};
-
static const struct i2c_device_id tps65090_id_table[] = {
{ "tps65090", 0 },
{ },
@@ -247,7 +240,7 @@ static struct i2c_driver tps65090_driver = {
.driver = {
.name = "tps65090",
.owner = THIS_MODULE,
- .pm = &tps65090_pm_ops,
+ .of_match_table = of_match_ptr(tps65090_of_match),
},
.probe = tps65090_i2c_probe,
.remove = tps65090_i2c_remove,
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 4f3baadd0038..89ab4d970643 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -66,16 +66,6 @@
/* Triton Core internal information (BEGIN) */
-#define TWL_NUM_SLAVES 4
-
-#define SUB_CHIP_ID0 0
-#define SUB_CHIP_ID1 1
-#define SUB_CHIP_ID2 2
-#define SUB_CHIP_ID3 3
-#define SUB_CHIP_ID_INVAL 0xff
-
-#define TWL_MODULE_LAST TWL4030_MODULE_LAST
-
/* Base Address defns for twl4030_map[] */
/* subchip/slave 0 - USB ID */
@@ -94,10 +84,7 @@
#define TWL4030_BASEADD_MADC 0x0000
#define TWL4030_BASEADD_MAIN_CHARGE 0x0074
#define TWL4030_BASEADD_PRECHARGE 0x00AA
-#define TWL4030_BASEADD_PWM0 0x00F8
-#define TWL4030_BASEADD_PWM1 0x00FB
-#define TWL4030_BASEADD_PWMA 0x00EF
-#define TWL4030_BASEADD_PWMB 0x00F1
+#define TWL4030_BASEADD_PWM 0x00F8
#define TWL4030_BASEADD_KEYPAD 0x00D2
#define TWL5031_BASEADD_ACCESSORY 0x0074 /* Replaces Main Charge */
@@ -117,7 +104,7 @@
/* subchip/slave 0 0x48 - POWER */
#define TWL6030_BASEADD_RTC 0x0000
-#define TWL6030_BASEADD_MEM 0x0017
+#define TWL6030_BASEADD_SECURED_REG 0x0017
#define TWL6030_BASEADD_PM_MASTER 0x001F
#define TWL6030_BASEADD_PM_SLAVE_MISC 0x0030 /* PM_RECEIVER */
#define TWL6030_BASEADD_PM_MISC 0x00E2
@@ -132,6 +119,7 @@
#define TWL6030_BASEADD_PIH 0x00D0
#define TWL6030_BASEADD_CHARGER 0x00E0
#define TWL6025_BASEADD_CHARGER 0x00DA
+#define TWL6030_BASEADD_LED 0x00F4
/* subchip/slave 2 0x4A - DFT */
#define TWL6030_BASEADD_DIEID 0x00C0
@@ -153,33 +141,28 @@
/*----------------------------------------------------------------------*/
-/* 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)
-{
- return twl_id;
-}
-EXPORT_SYMBOL(twl_rev);
-
/* Structure for each TWL4030/TWL6030 Slave */
struct twl_client {
struct i2c_client *client;
struct regmap *regmap;
};
-static struct twl_client twl_modules[TWL_NUM_SLAVES];
-
/* mapping the module id to slave id and base address */
struct twl_mapping {
unsigned char sid; /* Slave ID */
unsigned char base; /* base address */
};
-static struct twl_mapping *twl_map;
+
+struct twl_private {
+ bool ready; /* The core driver is ready to be used */
+ u32 twl_idcode; /* TWL IDCODE Register value */
+ unsigned int twl_id;
+
+ struct twl_mapping *twl_map;
+ struct twl_client *twl_modules;
+};
+
+static struct twl_private *twl_priv;
static struct twl_mapping twl4030_map[] = {
/*
@@ -188,34 +171,33 @@ static struct twl_mapping twl4030_map[] = {
* so they continue to match the order in this table.
*/
+ /* Common IPs */
{ 0, TWL4030_BASEADD_USB },
+ { 1, TWL4030_BASEADD_PIH },
+ { 2, TWL4030_BASEADD_MAIN_CHARGE },
+ { 3, TWL4030_BASEADD_PM_MASTER },
+ { 3, TWL4030_BASEADD_PM_RECEIVER },
+
+ { 3, TWL4030_BASEADD_RTC },
+ { 2, TWL4030_BASEADD_PWM },
+ { 2, TWL4030_BASEADD_LED },
+ { 3, TWL4030_BASEADD_SECURED_REG },
+
+ /* TWL4030 specific IPs */
{ 1, TWL4030_BASEADD_AUDIO_VOICE },
{ 1, TWL4030_BASEADD_GPIO },
{ 1, TWL4030_BASEADD_INTBR },
- { 1, TWL4030_BASEADD_PIH },
-
{ 1, TWL4030_BASEADD_TEST },
{ 2, TWL4030_BASEADD_KEYPAD },
+
{ 2, TWL4030_BASEADD_MADC },
{ 2, TWL4030_BASEADD_INTERRUPTS },
- { 2, TWL4030_BASEADD_LED },
-
- { 2, TWL4030_BASEADD_MAIN_CHARGE },
{ 2, TWL4030_BASEADD_PRECHARGE },
- { 2, TWL4030_BASEADD_PWM0 },
- { 2, TWL4030_BASEADD_PWM1 },
- { 2, TWL4030_BASEADD_PWMA },
-
- { 2, TWL4030_BASEADD_PWMB },
- { 2, TWL5031_BASEADD_ACCESSORY },
- { 2, TWL5031_BASEADD_INTERRUPTS },
{ 3, TWL4030_BASEADD_BACKUP },
{ 3, TWL4030_BASEADD_INT },
- { 3, TWL4030_BASEADD_PM_MASTER },
- { 3, TWL4030_BASEADD_PM_RECEIVER },
- { 3, TWL4030_BASEADD_RTC },
- { 3, TWL4030_BASEADD_SECURED_REG },
+ { 2, TWL5031_BASEADD_ACCESSORY },
+ { 2, TWL5031_BASEADD_INTERRUPTS },
};
static struct regmap_config twl4030_regmap_config[4] = {
@@ -251,35 +233,25 @@ static struct twl_mapping twl6030_map[] = {
* <linux/i2c/twl.h> defines for TWL4030_MODULE_*
* so they continue to match the order in this table.
*/
- { SUB_CHIP_ID1, TWL6030_BASEADD_USB },
- { SUB_CHIP_ID_INVAL, TWL6030_BASEADD_AUDIO },
- { SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
- { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
- { SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
-
- { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
- { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
- { SUB_CHIP_ID1, TWL6030_BASEADD_GPADC_CTRL },
- { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
- { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
-
- { SUB_CHIP_ID1, TWL6030_BASEADD_CHARGER },
- { SUB_CHIP_ID1, TWL6030_BASEADD_GASGAUGE },
- { SUB_CHIP_ID1, TWL6030_BASEADD_PWM },
- { SUB_CHIP_ID0, TWL6030_BASEADD_ZERO },
- { SUB_CHIP_ID1, TWL6030_BASEADD_ZERO },
-
- { SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
- { SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
- { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
- { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
- { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
-
- { SUB_CHIP_ID0, TWL6030_BASEADD_PM_MASTER },
- { SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_MISC },
- { SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
- { SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
- { SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER },
+
+ /* Common IPs */
+ { 1, TWL6030_BASEADD_USB },
+ { 1, TWL6030_BASEADD_PIH },
+ { 1, TWL6030_BASEADD_CHARGER },
+ { 0, TWL6030_BASEADD_PM_MASTER },
+ { 0, TWL6030_BASEADD_PM_SLAVE_MISC },
+
+ { 0, TWL6030_BASEADD_RTC },
+ { 1, TWL6030_BASEADD_PWM },
+ { 1, TWL6030_BASEADD_LED },
+ { 0, TWL6030_BASEADD_SECURED_REG },
+
+ /* TWL6030 specific IPs */
+ { 0, TWL6030_BASEADD_ZERO },
+ { 1, TWL6030_BASEADD_ZERO },
+ { 2, TWL6030_BASEADD_ZERO },
+ { 1, TWL6030_BASEADD_GPADC_CTRL },
+ { 1, TWL6030_BASEADD_GASGAUGE },
};
static struct regmap_config twl6030_regmap_config[3] = {
@@ -305,8 +277,30 @@ static struct regmap_config twl6030_regmap_config[3] = {
/*----------------------------------------------------------------------*/
+static inline int twl_get_num_slaves(void)
+{
+ if (twl_class_is_4030())
+ return 4; /* TWL4030 class have four slave address */
+ else
+ return 3; /* TWL6030 class have three slave address */
+}
+
+static inline int twl_get_last_module(void)
+{
+ if (twl_class_is_4030())
+ return TWL4030_MODULE_LAST;
+ else
+ return TWL6030_MODULE_LAST;
+}
+
/* Exported Functions */
+unsigned int twl_rev(void)
+{
+ return twl_priv ? twl_priv->twl_id : 0;
+}
+EXPORT_SYMBOL(twl_rev);
+
/**
* twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
* @mod_no: module number
@@ -314,9 +308,6 @@ static struct regmap_config twl6030_regmap_config[3] = {
* @reg: register address (just offset will do)
* @num_bytes: number of bytes to transfer
*
- * IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and
- * valid data starts at Offset 1.
- *
* Returns the result of operation - 0 is success
*/
int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
@@ -325,24 +316,21 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
int sid;
struct twl_client *twl;
- if (unlikely(mod_no >= TWL_MODULE_LAST)) {
- pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
- return -EPERM;
- }
- if (unlikely(!inuse)) {
+ if (unlikely(!twl_priv || !twl_priv->ready)) {
pr_err("%s: not initialized\n", DRIVER_NAME);
return -EPERM;
}
- sid = twl_map[mod_no].sid;
- if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
- pr_err("%s: module %d is not part of the pmic\n",
- DRIVER_NAME, mod_no);
- return -EINVAL;
+ if (unlikely(mod_no >= twl_get_last_module())) {
+ pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+ return -EPERM;
}
- twl = &twl_modules[sid];
- ret = regmap_bulk_write(twl->regmap, twl_map[mod_no].base + reg,
- value, num_bytes);
+ sid = twl_priv->twl_map[mod_no].sid;
+ twl = &twl_priv->twl_modules[sid];
+
+ ret = regmap_bulk_write(twl->regmap,
+ twl_priv->twl_map[mod_no].base + reg, value,
+ num_bytes);
if (ret)
pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n",
@@ -367,24 +355,21 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
int sid;
struct twl_client *twl;
- if (unlikely(mod_no >= TWL_MODULE_LAST)) {
- pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
- return -EPERM;
- }
- if (unlikely(!inuse)) {
+ if (unlikely(!twl_priv || !twl_priv->ready)) {
pr_err("%s: not initialized\n", DRIVER_NAME);
return -EPERM;
}
- sid = twl_map[mod_no].sid;
- if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
- pr_err("%s: module %d is not part of the pmic\n",
- DRIVER_NAME, mod_no);
- return -EINVAL;
+ if (unlikely(mod_no >= twl_get_last_module())) {
+ pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+ return -EPERM;
}
- twl = &twl_modules[sid];
- ret = regmap_bulk_read(twl->regmap, twl_map[mod_no].base + reg,
- value, num_bytes);
+ sid = twl_priv->twl_map[mod_no].sid;
+ twl = &twl_priv->twl_modules[sid];
+
+ ret = regmap_bulk_read(twl->regmap,
+ twl_priv->twl_map[mod_no].base + reg, value,
+ num_bytes);
if (ret)
pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n",
@@ -394,34 +379,6 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
}
EXPORT_SYMBOL(twl_i2c_read);
-/**
- * twl_i2c_write_u8 - Writes a 8 bit register in TWL4030/TWL5030/TWL60X0
- * @mod_no: module number
- * @value: the value to be written 8 bit
- * @reg: register address (just offset will do)
- *
- * Returns result of operation - 0 is success
- */
-int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
-{
- return twl_i2c_write(mod_no, &value, reg, 1);
-}
-EXPORT_SYMBOL(twl_i2c_write_u8);
-
-/**
- * twl_i2c_read_u8 - Reads a 8 bit register from TWL4030/TWL5030/TWL60X0
- * @mod_no: module number
- * @value: the value read 8 bit
- * @reg: register address (just offset will do)
- *
- * Returns result of operation - 0 is success
- */
-int twl_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
-{
- return twl_i2c_read(mod_no, value, reg, 1);
-}
-EXPORT_SYMBOL(twl_i2c_read_u8);
-
/*----------------------------------------------------------------------*/
/**
@@ -440,7 +397,7 @@ static int twl_read_idcode_register(void)
goto fail;
}
- err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode),
+ err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_priv->twl_idcode),
REG_IDCODE_7_0, 4);
if (err) {
pr_err("TWL4030: unable to read IDCODE -%d\n", err);
@@ -461,7 +418,7 @@ fail:
*/
int twl_get_type(void)
{
- return TWL_SIL_TYPE(twl_idcode);
+ return TWL_SIL_TYPE(twl_priv->twl_idcode);
}
EXPORT_SYMBOL_GPL(twl_get_type);
@@ -472,7 +429,7 @@ EXPORT_SYMBOL_GPL(twl_get_type);
*/
int twl_get_version(void)
{
- return TWL_SIL_REV(twl_idcode);
+ return TWL_SIL_REV(twl_priv->twl_idcode);
}
EXPORT_SYMBOL_GPL(twl_get_version);
@@ -509,13 +466,20 @@ int twl_get_hfclk_rate(void)
EXPORT_SYMBOL_GPL(twl_get_hfclk_rate);
static struct device *
-add_numbered_child(unsigned chip, const char *name, int num,
+add_numbered_child(unsigned mod_no, const char *name, int num,
void *pdata, unsigned pdata_len,
bool can_wakeup, int irq0, int irq1)
{
struct platform_device *pdev;
- struct twl_client *twl = &twl_modules[chip];
- int status;
+ struct twl_client *twl;
+ int status, sid;
+
+ if (unlikely(mod_no >= twl_get_last_module())) {
+ pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+ return ERR_PTR(-EPERM);
+ }
+ sid = twl_priv->twl_map[mod_no].sid;
+ twl = &twl_priv->twl_modules[sid];
pdev = platform_device_alloc(name, num);
if (!pdev) {
@@ -560,11 +524,11 @@ err:
return &pdev->dev;
}
-static inline struct device *add_child(unsigned chip, const char *name,
+static inline struct device *add_child(unsigned mod_no, const char *name,
void *pdata, unsigned pdata_len,
bool can_wakeup, int irq0, int irq1)
{
- return add_numbered_child(chip, name, -1, pdata, pdata_len,
+ return add_numbered_child(mod_no, name, -1, pdata, pdata_len,
can_wakeup, irq0, irq1);
}
@@ -573,7 +537,6 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
struct regulator_consumer_supply *consumers,
unsigned num_consumers, unsigned long features)
{
- unsigned sub_chip_id;
struct twl_regulator_driver_data drv_data;
/* regulator framework demands init_data ... */
@@ -600,8 +563,7 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
}
/* 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,
+ return add_numbered_child(TWL_MODULE_PM_MASTER, "twl_reg", num,
pdata, sizeof(*pdata), false, 0, 0);
}
@@ -623,10 +585,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
unsigned long features)
{
struct device *child;
- unsigned sub_chip_id;
if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) {
- child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
+ child = add_child(TWL4030_MODULE_GPIO, "twl4030_gpio",
pdata->gpio, sizeof(*pdata->gpio),
false, irq_base + GPIO_INTR_OFFSET, 0);
if (IS_ERR(child))
@@ -634,7 +595,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
}
if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) {
- child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
+ child = add_child(TWL4030_MODULE_KEYPAD, "twl4030_keypad",
pdata->keypad, sizeof(*pdata->keypad),
true, irq_base + KEYPAD_INTR_OFFSET, 0);
if (IS_ERR(child))
@@ -643,7 +604,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc &&
twl_class_is_4030()) {
- child = add_child(SUB_CHIP_ID2, "twl4030_madc",
+ child = add_child(TWL4030_MODULE_MADC, "twl4030_madc",
pdata->madc, sizeof(*pdata->madc),
true, irq_base + MADC_INTR_OFFSET, 0);
if (IS_ERR(child))
@@ -658,22 +619,21 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
* Eventually, Linux might become more aware of such
* HW security concerns, and "least privilege".
*/
- sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
- child = add_child(sub_chip_id, "twl_rtc", NULL, 0,
+ child = add_child(TWL_MODULE_RTC, "twl_rtc", NULL, 0,
true, irq_base + RTC_INTR_OFFSET, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
if (IS_ENABLED(CONFIG_PWM_TWL)) {
- child = add_child(SUB_CHIP_ID1, "twl-pwm", NULL, 0,
+ child = add_child(TWL_MODULE_PWM, "twl-pwm", NULL, 0,
false, 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
if (IS_ENABLED(CONFIG_PWM_TWL_LED)) {
- child = add_child(SUB_CHIP_ID1, "twl-pwmled", NULL, 0,
+ child = add_child(TWL_MODULE_LED, "twl-pwmled", NULL, 0,
false, 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
@@ -725,7 +685,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
}
- child = add_child(SUB_CHIP_ID0, "twl4030_usb",
+ child = add_child(TWL_MODULE_USB, "twl4030_usb",
pdata->usb, sizeof(*pdata->usb), true,
/* irq0 = USB_PRES, irq1 = USB */
irq_base + USB_PRES_INTR_OFFSET,
@@ -774,7 +734,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
pdata->usb->features = features;
- child = add_child(SUB_CHIP_ID0, "twl6030_usb",
+ child = add_child(TWL_MODULE_USB, "twl6030_usb",
pdata->usb, sizeof(*pdata->usb), true,
/* irq1 = VBUS_PRES, irq0 = USB ID */
irq_base + USBOTG_INTR_OFFSET,
@@ -799,22 +759,22 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
}
if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) {
- child = add_child(SUB_CHIP_ID3, "twl4030_wdt", NULL, 0,
- false, 0, 0);
+ child = add_child(TWL_MODULE_PM_RECEIVER, "twl4030_wdt", NULL,
+ 0, false, 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) {
- child = add_child(SUB_CHIP_ID3, "twl4030_pwrbutton", NULL, 0,
- true, irq_base + 8 + 0, 0);
+ child = add_child(TWL_MODULE_PM_MASTER, "twl4030_pwrbutton",
+ NULL, 0, true, irq_base + 8 + 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio &&
twl_class_is_4030()) {
- child = add_child(SUB_CHIP_ID1, "twl4030-audio",
+ child = add_child(TWL4030_MODULE_AUDIO_VOICE, "twl4030-audio",
pdata->audio, sizeof(*pdata->audio),
false, 0, 0);
if (IS_ERR(child))
@@ -1054,7 +1014,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci &&
!(features & (TPS_SUBSET | TWL5031))) {
- child = add_child(SUB_CHIP_ID3, "twl4030_bci",
+ child = add_child(TWL_MODULE_MAIN_CHARGE, "twl4030_bci",
pdata->bci, sizeof(*pdata->bci), false,
/* irq0 = CHG_PRES, irq1 = BCI */
irq_base + BCI_PRES_INTR_OFFSET,
@@ -1145,25 +1105,23 @@ static int twl_remove(struct i2c_client *client)
unsigned i, num_slaves;
int status;
- if (twl_class_is_4030()) {
+ if (twl_class_is_4030())
status = twl4030_exit_irq();
- num_slaves = TWL_NUM_SLAVES;
- } else {
+ else
status = twl6030_exit_irq();
- num_slaves = TWL_NUM_SLAVES - 1;
- }
if (status < 0)
return status;
+ num_slaves = twl_get_num_slaves();
for (i = 0; i < num_slaves; i++) {
- struct twl_client *twl = &twl_modules[i];
+ struct twl_client *twl = &twl_priv->twl_modules[i];
if (twl->client && twl->client != client)
i2c_unregister_device(twl->client);
- twl_modules[i].client = NULL;
+ twl->client = NULL;
}
- inuse = false;
+ twl_priv->ready = false;
return 0;
}
@@ -1179,6 +1137,17 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
int status;
unsigned i, num_slaves;
+ if (!node && !pdata) {
+ dev_err(&client->dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ if (twl_priv) {
+ dev_dbg(&client->dev, "only one instance of %s allowed\n",
+ DRIVER_NAME);
+ return -EBUSY;
+ }
+
pdev = platform_device_alloc(DRIVER_NAME, -1);
if (!pdev) {
dev_err(&client->dev, "can't alloc pdev\n");
@@ -1191,54 +1160,44 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
return status;
}
- if (node && !pdata) {
- /*
- * XXX: Temporary pdata until the information is correctly
- * retrieved by every TWL modules from DT.
- */
- pdata = devm_kzalloc(&client->dev,
- sizeof(struct twl4030_platform_data),
- GFP_KERNEL);
- if (!pdata) {
- status = -ENOMEM;
- goto free;
- }
- }
-
- if (!pdata) {
- dev_dbg(&client->dev, "no platform data?\n");
- status = -EINVAL;
- goto free;
- }
-
- platform_set_drvdata(pdev, pdata);
-
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
dev_dbg(&client->dev, "can't talk I2C?\n");
status = -EIO;
goto free;
}
- if (inuse) {
- dev_dbg(&client->dev, "driver is already in use\n");
- status = -EBUSY;
+ twl_priv = devm_kzalloc(&client->dev, sizeof(struct twl_private),
+ GFP_KERNEL);
+ if (!twl_priv) {
+ status = -ENOMEM;
goto free;
}
if ((id->driver_data) & TWL6030_CLASS) {
- twl_id = TWL6030_CLASS_ID;
- twl_map = &twl6030_map[0];
+ twl_priv->twl_id = TWL6030_CLASS_ID;
+ twl_priv->twl_map = &twl6030_map[0];
+ /* The charger base address is different in twl6025 */
+ if ((id->driver_data) & TWL6025_SUBCLASS)
+ twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base =
+ TWL6025_BASEADD_CHARGER;
twl_regmap_config = twl6030_regmap_config;
- num_slaves = TWL_NUM_SLAVES - 1;
} else {
- twl_id = TWL4030_CLASS_ID;
- twl_map = &twl4030_map[0];
+ twl_priv->twl_id = TWL4030_CLASS_ID;
+ twl_priv->twl_map = &twl4030_map[0];
twl_regmap_config = twl4030_regmap_config;
- num_slaves = TWL_NUM_SLAVES;
+ }
+
+ num_slaves = twl_get_num_slaves();
+ twl_priv->twl_modules = devm_kzalloc(&client->dev,
+ sizeof(struct twl_client) * num_slaves,
+ GFP_KERNEL);
+ if (!twl_priv->twl_modules) {
+ status = -ENOMEM;
+ goto free;
}
for (i = 0; i < num_slaves; i++) {
- struct twl_client *twl = &twl_modules[i];
+ struct twl_client *twl = &twl_priv->twl_modules[i];
if (i == 0) {
twl->client = client;
@@ -1264,19 +1223,19 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
}
- inuse = true;
+ twl_priv->ready = true;
/* setup clock framework */
- clocks_init(&pdev->dev, pdata->clock);
+ clocks_init(&pdev->dev, pdata ? pdata->clock : NULL);
/* read TWL IDCODE Register */
- if (twl_id == TWL4030_CLASS_ID) {
+ if (twl_class_is_4030()) {
status = twl_read_idcode_register();
WARN(status < 0, "Error: reading twl_idcode register value\n");
}
/* load power event scripts */
- if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power)
+ if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata && pdata->power)
twl4030_power_init(pdata->power);
/* Maybe init the T2 Interrupt subsystem */
@@ -1308,10 +1267,9 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
}
- status = -ENODEV;
if (node)
status = of_platform_populate(node, NULL, NULL, &client->dev);
- if (status)
+ else
status = add_children(pdata, irq_base, id->driver_data);
fail:
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
index 77048b18439e..bf75e967a1f3 100644
--- a/drivers/mfd/vexpress-sysreg.c
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -49,6 +49,8 @@
#define SYS_ID_HBI_SHIFT 16
#define SYS_PROCIDx_HBI_SHIFT 0
+#define SYS_LED_LED(n) (1 << (n))
+
#define SYS_MCI_CARDIN (1 << 0)
#define SYS_MCI_WPROT (1 << 1)
@@ -313,7 +315,7 @@ static void vexpress_sysreg_config_complete(unsigned long data)
}
-void __init vexpress_sysreg_setup(struct device_node *node)
+void vexpress_sysreg_setup(struct device_node *node)
{
if (WARN_ON(!vexpress_sysreg_base))
return;
@@ -336,34 +338,40 @@ void __init vexpress_sysreg_early_init(void __iomem *base)
void __init vexpress_sysreg_of_early_init(void)
{
- struct device_node *node = of_find_compatible_node(NULL, NULL,
- "arm,vexpress-sysreg");
+ struct device_node *node;
+
+ if (vexpress_sysreg_base)
+ return;
+ node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
if (node) {
vexpress_sysreg_base = of_iomap(node, 0);
vexpress_sysreg_setup(node);
- } else {
- pr_info("vexpress-sysreg: No Device Tree node found.");
}
}
+#define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \
+ [VEXPRESS_GPIO_##_name] = { \
+ .reg = _reg, \
+ .value = _reg##_##_value, \
+ }
+
static struct vexpress_sysreg_gpio {
unsigned long reg;
u32 value;
} vexpress_sysreg_gpios[] = {
- [VEXPRESS_GPIO_MMC_CARDIN] = {
- .reg = SYS_MCI,
- .value = SYS_MCI_CARDIN,
- },
- [VEXPRESS_GPIO_MMC_WPROT] = {
- .reg = SYS_MCI,
- .value = SYS_MCI_WPROT,
- },
- [VEXPRESS_GPIO_FLASH_WPn] = {
- .reg = SYS_FLASH,
- .value = SYS_FLASH_WPn,
- },
+ VEXPRESS_SYSREG_GPIO(MMC_CARDIN, SYS_MCI, CARDIN),
+ VEXPRESS_SYSREG_GPIO(MMC_WPROT, SYS_MCI, WPROT),
+ VEXPRESS_SYSREG_GPIO(FLASH_WPn, SYS_FLASH, WPn),
+ VEXPRESS_SYSREG_GPIO(LED0, SYS_LED, LED(0)),
+ VEXPRESS_SYSREG_GPIO(LED1, SYS_LED, LED(1)),
+ VEXPRESS_SYSREG_GPIO(LED2, SYS_LED, LED(2)),
+ VEXPRESS_SYSREG_GPIO(LED3, SYS_LED, LED(3)),
+ VEXPRESS_SYSREG_GPIO(LED4, SYS_LED, LED(4)),
+ VEXPRESS_SYSREG_GPIO(LED5, SYS_LED, LED(5)),
+ VEXPRESS_SYSREG_GPIO(LED6, SYS_LED, LED(6)),
+ VEXPRESS_SYSREG_GPIO(LED7, SYS_LED, LED(7)),
};
static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
@@ -372,12 +380,6 @@ static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
return 0;
}
-static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- return 0;
-}
-
static int vexpress_sysreg_gpio_get(struct gpio_chip *chip,
unsigned offset)
{
@@ -401,6 +403,14 @@ static void vexpress_sysreg_gpio_set(struct gpio_chip *chip,
writel(reg_value, vexpress_sysreg_base + gpio->reg);
}
+static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ vexpress_sysreg_gpio_set(chip, offset, value);
+
+ return 0;
+}
+
static struct gpio_chip vexpress_sysreg_gpio_chip = {
.label = "vexpress-sysreg",
.direction_input = vexpress_sysreg_gpio_direction_input,
@@ -412,6 +422,30 @@ static struct gpio_chip vexpress_sysreg_gpio_chip = {
};
+#define VEXPRESS_SYSREG_GREEN_LED(_name, _default_trigger, _gpio) \
+ { \
+ .name = "v2m:green:"_name, \
+ .default_trigger = _default_trigger, \
+ .gpio = VEXPRESS_GPIO_##_gpio, \
+ }
+
+struct gpio_led vexpress_sysreg_leds[] = {
+ VEXPRESS_SYSREG_GREEN_LED("user1", "heartbeat", LED0),
+ VEXPRESS_SYSREG_GREEN_LED("user2", "mmc0", LED1),
+ VEXPRESS_SYSREG_GREEN_LED("user3", "cpu0", LED2),
+ VEXPRESS_SYSREG_GREEN_LED("user4", "cpu1", LED3),
+ VEXPRESS_SYSREG_GREEN_LED("user5", "cpu2", LED4),
+ VEXPRESS_SYSREG_GREEN_LED("user6", "cpu3", LED5),
+ VEXPRESS_SYSREG_GREEN_LED("user7", "cpu4", LED6),
+ VEXPRESS_SYSREG_GREEN_LED("user8", "cpu5", LED7),
+};
+
+struct gpio_led_platform_data vexpress_sysreg_leds_pdata = {
+ .num_leds = ARRAY_SIZE(vexpress_sysreg_leds),
+ .leds = vexpress_sysreg_leds,
+};
+
+
static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -456,6 +490,10 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
return err;
}
+ platform_device_register_data(vexpress_sysreg_dev, "leds-gpio",
+ PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata,
+ sizeof(vexpress_sysreg_leds_pdata));
+
vexpress_sysreg_dev = &pdev->dev;
device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
@@ -478,6 +516,7 @@ static struct platform_driver vexpress_sysreg_driver = {
static int __init vexpress_sysreg_init(void)
{
+ vexpress_sysreg_of_early_init();
return platform_driver_register(&vexpress_sysreg_driver);
}
core_initcall(vexpress_sysreg_init);
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index 1133a64c2dc9..a433f580aa4c 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -59,12 +59,13 @@ static const struct reg_default wm5102_reva_patch[] = {
static const struct reg_default wm5102_revb_patch[] = {
{ 0x80, 0x0003 },
{ 0x081, 0xE022 },
- { 0x410, 0x6080 },
- { 0x418, 0x6080 },
- { 0x420, 0x6080 },
+ { 0x410, 0x4080 },
+ { 0x418, 0x4080 },
+ { 0x420, 0x4080 },
{ 0x428, 0xC000 },
- { 0x441, 0x8014 },
+ { 0x4B0, 0x0066 },
{ 0x458, 0x000b },
+ { 0x212, 0x0000 },
{ 0x80, 0x0000 },
};
@@ -84,6 +85,12 @@ int wm5102_patch(struct arizona *arizona)
}
static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = {
+ [ARIZONA_IRQ_MICD_CLAMP_FALL] = {
+ .mask = ARIZONA_MICD_CLAMP_FALL_EINT1
+ },
+ [ARIZONA_IRQ_MICD_CLAMP_RISE] = {
+ .mask = ARIZONA_MICD_CLAMP_RISE_EINT1
+ },
[ARIZONA_IRQ_GP5_FALL] = { .mask = ARIZONA_GP5_FALL_EINT1 },
[ARIZONA_IRQ_GP5_RISE] = { .mask = ARIZONA_GP5_RISE_EINT1 },
[ARIZONA_IRQ_JD_FALL] = { .mask = ARIZONA_JD1_FALL_EINT1 },
@@ -96,6 +103,7 @@ const struct regmap_irq_chip wm5102_aod = {
.mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1,
.ack_base = ARIZONA_AOD_IRQ1,
.wake_base = ARIZONA_WAKE_CONTROL,
+ .wake_invert = 1,
.num_regs = 1,
.irqs = wm5102_aod_irqs,
.num_irqs = ARRAY_SIZE(wm5102_aod_irqs),
@@ -224,11 +232,9 @@ const struct regmap_irq_chip wm5102_irq = {
static const struct reg_default wm5102_reg_default[] = {
{ 0x00000008, 0x0019 }, /* R8 - Ctrl IF SPI CFG 1 */
{ 0x00000009, 0x0001 }, /* R9 - Ctrl IF I2C1 CFG 1 */
- { 0x0000000D, 0x0000 }, /* R13 - Ctrl IF Status 1 */
{ 0x00000016, 0x0000 }, /* R22 - Write Sequencer Ctrl 0 */
{ 0x00000017, 0x0000 }, /* R23 - Write Sequencer Ctrl 1 */
{ 0x00000018, 0x0000 }, /* R24 - Write Sequencer Ctrl 2 */
- { 0x0000001A, 0x0000 }, /* R26 - Write Sequencer PROM */
{ 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */
{ 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */
{ 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */
@@ -243,12 +249,14 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */
{ 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */
{ 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */
- { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 1 */
- { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 2 */
- { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 3 */
- { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 4 */
- { 0x0000006C, 0x01FF }, /* R108 - Always On Triggers Sequence Select 5 */
- { 0x0000006D, 0x01FF }, /* R109 - Always On Triggers Sequence Select 6 */
+ { 0x00000066, 0x01FF }, /* R102 - Always On Triggers Sequence Select 1 */
+ { 0x00000067, 0x01FF }, /* R103 - Always On Triggers Sequence Select 2 */
+ { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */
+ { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */
+ { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */
+ { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */
+ { 0x0000006E, 0x01FF }, /* R110 - Trigger Sequence Select 32 */
+ { 0x0000006F, 0x01FF }, /* R111 - Trigger Sequence Select 33 */
{ 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */
{ 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */
{ 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */
@@ -258,13 +266,14 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000095, 0x0000 }, /* R149 - Haptics phase 2 duration */
{ 0x00000096, 0x0000 }, /* R150 - Haptics phase 3 intensity */
{ 0x00000097, 0x0000 }, /* R151 - Haptics phase 3 duration */
- { 0x00000100, 0x0001 }, /* R256 - Clock 32k 1 */
+ { 0x00000100, 0x0002 }, /* R256 - Clock 32k 1 */
{ 0x00000101, 0x0304 }, /* R257 - System Clock 1 */
{ 0x00000102, 0x0011 }, /* R258 - Sample rate 1 */
{ 0x00000103, 0x0011 }, /* R259 - Sample rate 2 */
{ 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */
{ 0x00000112, 0x0305 }, /* R274 - Async clock 1 */
{ 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */
+ { 0x00000114, 0x0011 }, /* R276 - Async sample rate 2 */
{ 0x00000149, 0x0000 }, /* R329 - Output system clock */
{ 0x0000014A, 0x0000 }, /* R330 - Output async clock */
{ 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */
@@ -273,13 +282,14 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */
{ 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */
{ 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */
- { 0x00000171, 0x0000 }, /* R369 - FLL1 Control 1 */
+ { 0x00000171, 0x0002 }, /* R369 - FLL1 Control 1 */
{ 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */
{ 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */
{ 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */
{ 0x00000175, 0x0004 }, /* R373 - FLL1 Control 5 */
{ 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */
{ 0x00000177, 0x0181 }, /* R375 - FLL1 Loop Filter Test 1 */
+ { 0x00000178, 0x0000 }, /* R376 - FLL1 NCO Test 0 */
{ 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */
{ 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */
{ 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */
@@ -295,6 +305,7 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000195, 0x0004 }, /* R405 - FLL2 Control 5 */
{ 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */
{ 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */
+ { 0x00000198, 0x0000 }, /* R408 - FLL2 NCO Test 0 */
{ 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */
{ 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */
{ 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */
@@ -310,8 +321,13 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */
{ 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */
{ 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */
+ { 0x00000225, 0x0400 }, /* R549 - HP Ctrl 1L */
+ { 0x00000226, 0x0400 }, /* R550 - HP Ctrl 1R */
{ 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */
{ 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */
+ { 0x0000029C, 0x0000 }, /* R668 - Headphone Detect 2 */
+ { 0x0000029F, 0x0000 }, /* R671 - Headphone Detect Test */
+ { 0x000002A2, 0x0000 }, /* R674 - Micd clamp control */
{ 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */
{ 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */
{ 0x000002A5, 0x0000 }, /* R677 - Mic Detect 3 */
@@ -342,53 +358,44 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */
{ 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */
{ 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */
- { 0x00000410, 0x0080 }, /* R1040 - Output Path Config 1L */
+ { 0x00000410, 0x4080 }, /* R1040 - Output Path Config 1L */
{ 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */
- { 0x00000412, 0x0080 }, /* R1042 - DAC Volume Limit 1L */
+ { 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */
{ 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */
{ 0x00000414, 0x0080 }, /* R1044 - Output Path Config 1R */
{ 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */
- { 0x00000416, 0x0080 }, /* R1046 - DAC Volume Limit 1R */
+ { 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */
{ 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */
- { 0x00000418, 0x0080 }, /* R1048 - Output Path Config 2L */
+ { 0x00000418, 0x4080 }, /* R1048 - Output Path Config 2L */
{ 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */
- { 0x0000041A, 0x0080 }, /* R1050 - DAC Volume Limit 2L */
+ { 0x0000041A, 0x0081 }, /* R1050 - DAC Volume Limit 2L */
{ 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */
{ 0x0000041C, 0x0080 }, /* R1052 - Output Path Config 2R */
{ 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */
- { 0x0000041E, 0x0080 }, /* R1054 - DAC Volume Limit 2R */
+ { 0x0000041E, 0x0081 }, /* R1054 - DAC Volume Limit 2R */
{ 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */
- { 0x00000420, 0x0080 }, /* R1056 - Output Path Config 3L */
+ { 0x00000420, 0x4080 }, /* R1056 - Output Path Config 3L */
{ 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */
- { 0x00000422, 0x0080 }, /* R1058 - DAC Volume Limit 3L */
+ { 0x00000422, 0x0081 }, /* R1058 - DAC Volume Limit 3L */
{ 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */
- { 0x00000424, 0x0080 }, /* R1060 - Output Path Config 3R */
- { 0x00000425, 0x0180 }, /* R1061 - DAC Digital Volume 3R */
- { 0x00000426, 0x0080 }, /* R1062 - DAC Volume Limit 3R */
- { 0x00000428, 0x0000 }, /* R1064 - Output Path Config 4L */
+ { 0x00000428, 0xC000 }, /* R1064 - Output Path Config 4L */
{ 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */
- { 0x0000042A, 0x0080 }, /* R1066 - Out Volume 4L */
+ { 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */
{ 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */
- { 0x0000042C, 0x0000 }, /* R1068 - Output Path Config 4R */
{ 0x0000042D, 0x0180 }, /* R1069 - DAC Digital Volume 4R */
- { 0x0000042E, 0x0080 }, /* R1070 - Out Volume 4R */
+ { 0x0000042E, 0x0081 }, /* R1070 - Out Volume 4R */
{ 0x0000042F, 0x0080 }, /* R1071 - Noise Gate Select 4R */
{ 0x00000430, 0x0000 }, /* R1072 - Output Path Config 5L */
{ 0x00000431, 0x0180 }, /* R1073 - DAC Digital Volume 5L */
- { 0x00000432, 0x0080 }, /* R1074 - DAC Volume Limit 5L */
+ { 0x00000432, 0x0081 }, /* R1074 - DAC Volume Limit 5L */
{ 0x00000433, 0x0100 }, /* R1075 - Noise Gate Select 5L */
- { 0x00000434, 0x0000 }, /* R1076 - Output Path Config 5R */
{ 0x00000435, 0x0180 }, /* R1077 - DAC Digital Volume 5R */
- { 0x00000436, 0x0080 }, /* R1078 - DAC Volume Limit 5R */
- { 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */
+ { 0x00000436, 0x0081 }, /* R1078 - DAC Volume Limit 5R */
+ { 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */
{ 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */
{ 0x00000458, 0x0001 }, /* R1112 - Noise Gate Control */
{ 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */
{ 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */
- { 0x000004DC, 0x0000 }, /* R1244 - DAC comp 1 */
- { 0x000004DD, 0x0000 }, /* R1245 - DAC comp 2 */
- { 0x000004DE, 0x0000 }, /* R1246 - DAC comp 3 */
- { 0x000004DF, 0x0000 }, /* R1247 - DAC comp 4 */
{ 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */
{ 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */
{ 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */
@@ -416,7 +423,6 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000518, 0x0007 }, /* R1304 - AIF1 Frame Ctrl 18 */
{ 0x00000519, 0x0000 }, /* R1305 - AIF1 Tx Enables */
{ 0x0000051A, 0x0000 }, /* R1306 - AIF1 Rx Enables */
- { 0x0000051B, 0x0000 }, /* R1307 - AIF1 Force Write */
{ 0x00000540, 0x000C }, /* R1344 - AIF2 BCLK Ctrl */
{ 0x00000541, 0x0008 }, /* R1345 - AIF2 Tx Pin Ctrl */
{ 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */
@@ -432,7 +438,6 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */
{ 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */
{ 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */
- { 0x0000055B, 0x0000 }, /* R1371 - AIF2 Force Write */
{ 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */
{ 0x00000581, 0x0008 }, /* R1409 - AIF3 Tx Pin Ctrl */
{ 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */
@@ -448,7 +453,6 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000592, 0x0001 }, /* R1426 - AIF3 Frame Ctrl 12 */
{ 0x00000599, 0x0000 }, /* R1433 - AIF3 Tx Enables */
{ 0x0000059A, 0x0000 }, /* R1434 - AIF3 Rx Enables */
- { 0x0000059B, 0x0000 }, /* R1435 - AIF3 Force Write */
{ 0x000005E3, 0x0004 }, /* R1507 - SLIMbus Framer Ref Gear */
{ 0x000005E5, 0x0000 }, /* R1509 - SLIMbus Rates 1 */
{ 0x000005E6, 0x0000 }, /* R1510 - SLIMbus Rates 2 */
@@ -772,22 +776,6 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x000008CD, 0x0080 }, /* R2253 - DRC1RMIX Input 3 Volume */
{ 0x000008CE, 0x0000 }, /* R2254 - DRC1RMIX Input 4 Source */
{ 0x000008CF, 0x0080 }, /* R2255 - DRC1RMIX Input 4 Volume */
- { 0x000008D0, 0x0000 }, /* R2256 - DRC2LMIX Input 1 Source */
- { 0x000008D1, 0x0080 }, /* R2257 - DRC2LMIX Input 1 Volume */
- { 0x000008D2, 0x0000 }, /* R2258 - DRC2LMIX Input 2 Source */
- { 0x000008D3, 0x0080 }, /* R2259 - DRC2LMIX Input 2 Volume */
- { 0x000008D4, 0x0000 }, /* R2260 - DRC2LMIX Input 3 Source */
- { 0x000008D5, 0x0080 }, /* R2261 - DRC2LMIX Input 3 Volume */
- { 0x000008D6, 0x0000 }, /* R2262 - DRC2LMIX Input 4 Source */
- { 0x000008D7, 0x0080 }, /* R2263 - DRC2LMIX Input 4 Volume */
- { 0x000008D8, 0x0000 }, /* R2264 - DRC2RMIX Input 1 Source */
- { 0x000008D9, 0x0080 }, /* R2265 - DRC2RMIX Input 1 Volume */
- { 0x000008DA, 0x0000 }, /* R2266 - DRC2RMIX Input 2 Source */
- { 0x000008DB, 0x0080 }, /* R2267 - DRC2RMIX Input 2 Volume */
- { 0x000008DC, 0x0000 }, /* R2268 - DRC2RMIX Input 3 Source */
- { 0x000008DD, 0x0080 }, /* R2269 - DRC2RMIX Input 3 Volume */
- { 0x000008DE, 0x0000 }, /* R2270 - DRC2RMIX Input 4 Source */
- { 0x000008DF, 0x0080 }, /* R2271 - DRC2RMIX Input 4 Volume */
{ 0x00000900, 0x0000 }, /* R2304 - HPLP1MIX Input 1 Source */
{ 0x00000901, 0x0080 }, /* R2305 - HPLP1MIX Input 1 Volume */
{ 0x00000902, 0x0000 }, /* R2306 - HPLP1MIX Input 2 Source */
@@ -879,7 +867,7 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000D1B, 0xFFFF }, /* R3355 - IRQ2 Status 4 Mask */
{ 0x00000D1C, 0xFFFF }, /* R3356 - IRQ2 Status 5 Mask */
{ 0x00000D1F, 0x0000 }, /* R3359 - IRQ2 Control */
- { 0x00000D41, 0x0000 }, /* R3393 - ADSP2 IRQ0 */
+ { 0x00000D50, 0x0000 }, /* R3408 - AOD wkup and trig */
{ 0x00000D53, 0xFFFF }, /* R3411 - AOD IRQ Mask IRQ1 */
{ 0x00000D54, 0xFFFF }, /* R3412 - AOD IRQ Mask IRQ2 */
{ 0x00000D56, 0x0000 }, /* R3414 - Jack detect debounce */
@@ -974,11 +962,6 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000E82, 0x0018 }, /* R3714 - DRC1 ctrl3 */
{ 0x00000E83, 0x0000 }, /* R3715 - DRC1 ctrl4 */
{ 0x00000E84, 0x0000 }, /* R3716 - DRC1 ctrl5 */
- { 0x00000E89, 0x0018 }, /* R3721 - DRC2 ctrl1 */
- { 0x00000E8A, 0x0933 }, /* R3722 - DRC2 ctrl2 */
- { 0x00000E8B, 0x0018 }, /* R3723 - DRC2 ctrl3 */
- { 0x00000E8C, 0x0000 }, /* R3724 - DRC2 ctrl4 */
- { 0x00000E8D, 0x0000 }, /* R3725 - DRC2 ctrl5 */
{ 0x00000EC0, 0x0000 }, /* R3776 - HPLPF1_1 */
{ 0x00000EC1, 0x0000 }, /* R3777 - HPLPF1_2 */
{ 0x00000EC4, 0x0000 }, /* R3780 - HPLPF2_1 */
@@ -989,16 +972,12 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */
{ 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */
{ 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */
- { 0x00000EE3, 0x4000 }, /* R3811 - ASRC_RATE2 */
{ 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */
{ 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */
{ 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */
{ 0x00000EF3, 0x0000 }, /* R3827 - ISRC 2 CTRL 1 */
{ 0x00000EF4, 0x0000 }, /* R3828 - ISRC 2 CTRL 2 */
{ 0x00000EF5, 0x0000 }, /* R3829 - ISRC 2 CTRL 3 */
- { 0x00000EF6, 0x0000 }, /* R3830 - ISRC 3 CTRL 1 */
- { 0x00000EF7, 0x0000 }, /* R3831 - ISRC 3 CTRL 2 */
- { 0x00000EF8, 0x0000 }, /* R3832 - ISRC 3 CTRL 3 */
{ 0x00001100, 0x0010 }, /* R4352 - DSP1 Control 1 */
{ 0x00001101, 0x0000 }, /* R4353 - DSP1 Clocking 1 */
};
@@ -1106,6 +1085,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_ACCESSORY_DETECT_MODE_1:
case ARIZONA_HEADPHONE_DETECT_1:
case ARIZONA_HEADPHONE_DETECT_2:
+ case ARIZONA_HP_DACVAL:
+ case ARIZONA_MICD_CLAMP_CONTROL:
case ARIZONA_MIC_DETECT_1:
case ARIZONA_MIC_DETECT_2:
case ARIZONA_MIC_DETECT_3:
@@ -1823,17 +1804,24 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_DSP1_STATUS_1:
case ARIZONA_DSP1_STATUS_2:
case ARIZONA_DSP1_STATUS_3:
+ case ARIZONA_DSP1_SCRATCH_0:
+ case ARIZONA_DSP1_SCRATCH_1:
+ case ARIZONA_DSP1_SCRATCH_2:
+ case ARIZONA_DSP1_SCRATCH_3:
return true;
default:
- return false;
+ if ((reg >= 0x100000 && reg < 0x106000) ||
+ (reg >= 0x180000 && reg < 0x180800) ||
+ (reg >= 0x190000 && reg < 0x194800) ||
+ (reg >= 0x1a8000 && reg < 0x1a9800))
+ return true;
+ else
+ return false;
}
}
static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
{
- if (reg > 0xffff)
- return true;
-
switch (reg) {
case ARIZONA_SOFTWARE_RESET:
case ARIZONA_DEVICE_REVISION:
@@ -1874,11 +1862,22 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_DSP1_STATUS_1:
case ARIZONA_DSP1_STATUS_2:
case ARIZONA_DSP1_STATUS_3:
+ case ARIZONA_DSP1_SCRATCH_0:
+ case ARIZONA_DSP1_SCRATCH_1:
+ case ARIZONA_DSP1_SCRATCH_2:
+ case ARIZONA_DSP1_SCRATCH_3:
case ARIZONA_HEADPHONE_DETECT_2:
+ case ARIZONA_HP_DACVAL:
case ARIZONA_MIC_DETECT_3:
return true;
default:
- return false;
+ if ((reg >= 0x100000 && reg < 0x106000) ||
+ (reg >= 0x180000 && reg < 0x180800) ||
+ (reg >= 0x190000 && reg < 0x194800) ||
+ (reg >= 0x1a8000 && reg < 0x1a9800))
+ return true;
+ else
+ return false;
}
}
diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c
index adda6b10b90d..c41599815299 100644
--- a/drivers/mfd/wm5110-tables.c
+++ b/drivers/mfd/wm5110-tables.c
@@ -255,6 +255,7 @@ const struct regmap_irq_chip wm5110_aod = {
.mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1,
.ack_base = ARIZONA_AOD_IRQ1,
.wake_base = ARIZONA_WAKE_CONTROL,
+ .wake_invert = 1,
.num_regs = 1,
.irqs = wm5110_aod_irqs,
.num_irqs = ARRAY_SIZE(wm5110_aod_irqs),
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 57c488d42d3e..803e93fae56a 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -467,7 +467,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
goto err;
}
- ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
+ ret = devm_regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
wm8994->supplies);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
@@ -478,7 +478,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
wm8994->supplies);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
- goto err_get;
+ goto err;
}
ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET);
@@ -658,8 +658,6 @@ err_irq:
err_enable:
regulator_bulk_disable(wm8994->num_supplies,
wm8994->supplies);
-err_get:
- regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
err:
mfd_remove_devices(wm8994->dev);
return ret;
@@ -672,7 +670,6 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
wm8994_irq_exit(wm8994);
regulator_bulk_disable(wm8994->num_supplies,
wm8994->supplies);
- regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
}
static const struct of_device_id wm8994_of_match[] = {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b151b7c1bd59..e83fdfe0c8ca 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -127,7 +127,7 @@ config PHANTOM
config INTEL_MID_PTI
tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard"
- depends on PCI
+ depends on PCI && TTY
default n
help
The PTI (Parallel Trace Interface) driver directs
@@ -192,7 +192,7 @@ config ICS932S401
config ATMEL_SSC
tristate "Device driver for Atmel SSC peripheral"
- depends on AVR32 || ARCH_AT91
+ depends on HAS_IOMEM
---help---
This option enables device driver support for Atmel Synchronized
Serial Communication peripheral (SSC).
@@ -499,6 +499,17 @@ config USB_SWITCH_FSA9480
stereo and mono audio, video, microphone and UART data to use
a common connector port.
+config LATTICE_ECP3_CONFIG
+ tristate "Lattice ECP3 FPGA bitstream configuration via SPI"
+ depends on SPI && SYSFS
+ select FW_LOADER
+ default n
+ help
+ This option enables support for bitstream configuration (programming
+ or loading) of the Lattice ECP3 FPGA family via SPI.
+
+ If unsure, say N.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
@@ -507,4 +518,5 @@ source "drivers/misc/lis3lv02d/Kconfig"
source "drivers/misc/carma/Kconfig"
source "drivers/misc/altera-stapl/Kconfig"
source "drivers/misc/mei/Kconfig"
+source "drivers/misc/vmw_vmci/Kconfig"
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2129377c0de6..35a1463c72d9 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -49,3 +49,6 @@ obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
obj-$(CONFIG_INTEL_MEI) += mei/
+obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o
+obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
+obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index 3c09cbb70b1d..c09c28f92055 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -159,11 +159,9 @@ static int ssc_probe(struct platform_device *pdev)
return -ENXIO;
}
- ssc->regs = devm_request_and_ioremap(&pdev->dev, regs);
- if (!ssc->regs) {
- dev_dbg(&pdev->dev, "ioremap failed\n");
- return -EINVAL;
- }
+ ssc->regs = devm_ioremap_resource(&pdev->dev, regs);
+ if (IS_ERR(ssc->regs))
+ return PTR_ERR(ssc->regs);
ssc->phybase = regs->start;
@@ -175,7 +173,7 @@ static int ssc_probe(struct platform_device *pdev)
/* disable all interrupts */
clk_enable(ssc->clk);
- ssc_writel(ssc->regs, IDR, ~0UL);
+ ssc_writel(ssc->regs, IDR, -1);
ssc_readl(ssc->regs, SR);
clk_disable(ssc->clk);
diff --git a/drivers/misc/cb710/Kconfig b/drivers/misc/cb710/Kconfig
index 22429b8b1068..5acb9c5b49c4 100644
--- a/drivers/misc/cb710/Kconfig
+++ b/drivers/misc/cb710/Kconfig
@@ -1,6 +1,6 @@
config CB710_CORE
tristate "ENE CB710/720 Flash memory card reader support"
- depends on PCI
+ depends on PCI && GENERIC_HARDIRQS
help
This option enables support for PCI ENE CB710/720 Flash memory card
reader found in some laptops (ie. some versions of HP Compaq nx9500).
diff --git a/drivers/misc/lattice-ecp3-config.c b/drivers/misc/lattice-ecp3-config.c
new file mode 100644
index 000000000000..155700bfd2b6
--- /dev/null
+++ b/drivers/misc/lattice-ecp3-config.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2012 Stefan Roese <sr@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#define FIRMWARE_NAME "lattice-ecp3.bit"
+
+/*
+ * The JTAG ID's of the supported FPGA's. The ID is 32bit wide
+ * reversed as noted in the manual.
+ */
+#define ID_ECP3_17 0xc2088080
+#define ID_ECP3_35 0xc2048080
+
+/* FPGA commands */
+#define FPGA_CMD_READ_ID 0x07 /* plus 24 bits */
+#define FPGA_CMD_READ_STATUS 0x09 /* plus 24 bits */
+#define FPGA_CMD_CLEAR 0x70
+#define FPGA_CMD_REFRESH 0x71
+#define FPGA_CMD_WRITE_EN 0x4a /* plus 2 bits */
+#define FPGA_CMD_WRITE_DIS 0x4f /* plus 8 bits */
+#define FPGA_CMD_WRITE_INC 0x41 /* plus 0 bits */
+
+/*
+ * The status register is 32bit revered, DONE is bit 17 from the TN1222.pdf
+ * (LatticeECP3 Slave SPI Port User's Guide)
+ */
+#define FPGA_STATUS_DONE 0x00004000
+#define FPGA_STATUS_CLEARED 0x00010000
+
+#define FPGA_CLEAR_TIMEOUT 5000 /* max. 5000ms for FPGA clear */
+#define FPGA_CLEAR_MSLEEP 10
+#define FPGA_CLEAR_LOOP_COUNT (FPGA_CLEAR_TIMEOUT / FPGA_CLEAR_MSLEEP)
+
+struct fpga_data {
+ struct completion fw_loaded;
+};
+
+struct ecp3_dev {
+ u32 jedec_id;
+ char *name;
+};
+
+static const struct ecp3_dev ecp3_dev[] = {
+ {
+ .jedec_id = ID_ECP3_17,
+ .name = "Lattice ECP3-17",
+ },
+ {
+ .jedec_id = ID_ECP3_35,
+ .name = "Lattice ECP3-35",
+ },
+};
+
+static void firmware_load(const struct firmware *fw, void *context)
+{
+ struct spi_device *spi = (struct spi_device *)context;
+ struct fpga_data *data = dev_get_drvdata(&spi->dev);
+ u8 *buffer;
+ int ret;
+ u8 txbuf[8];
+ u8 rxbuf[8];
+ int rx_len = 8;
+ int i;
+ u32 jedec_id;
+ u32 status;
+
+ if (fw->size == 0) {
+ dev_err(&spi->dev, "Error: Firmware size is 0!\n");
+ return;
+ }
+
+ /* Fill dummy data (24 stuffing bits for commands) */
+ txbuf[1] = 0x00;
+ txbuf[2] = 0x00;
+ txbuf[3] = 0x00;
+
+ /* Trying to speak with the FPGA via SPI... */
+ txbuf[0] = FPGA_CMD_READ_ID;
+ ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len);
+ dev_dbg(&spi->dev, "FPGA JTAG ID=%08x\n", *(u32 *)&rxbuf[4]);
+ jedec_id = *(u32 *)&rxbuf[4];
+
+ for (i = 0; i < ARRAY_SIZE(ecp3_dev); i++) {
+ if (jedec_id == ecp3_dev[i].jedec_id)
+ break;
+ }
+ if (i == ARRAY_SIZE(ecp3_dev)) {
+ dev_err(&spi->dev,
+ "Error: No supported FPGA detected (JEDEC_ID=%08x)!\n",
+ jedec_id);
+ return;
+ }
+
+ dev_info(&spi->dev, "FPGA %s detected\n", ecp3_dev[i].name);
+
+ txbuf[0] = FPGA_CMD_READ_STATUS;
+ ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len);
+ dev_dbg(&spi->dev, "FPGA Status=%08x\n", *(u32 *)&rxbuf[4]);
+
+ buffer = kzalloc(fw->size + 8, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&spi->dev, "Error: Can't allocate memory!\n");
+ return;
+ }
+
+ /*
+ * Insert WRITE_INC command into stream (one SPI frame)
+ */
+ buffer[0] = FPGA_CMD_WRITE_INC;
+ buffer[1] = 0xff;
+ buffer[2] = 0xff;
+ buffer[3] = 0xff;
+ memcpy(buffer + 4, fw->data, fw->size);
+
+ txbuf[0] = FPGA_CMD_REFRESH;
+ ret = spi_write(spi, txbuf, 4);
+
+ txbuf[0] = FPGA_CMD_WRITE_EN;
+ ret = spi_write(spi, txbuf, 4);
+
+ txbuf[0] = FPGA_CMD_CLEAR;
+ ret = spi_write(spi, txbuf, 4);
+
+ /*
+ * Wait for FPGA memory to become cleared
+ */
+ for (i = 0; i < FPGA_CLEAR_LOOP_COUNT; i++) {
+ txbuf[0] = FPGA_CMD_READ_STATUS;
+ ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len);
+ status = *(u32 *)&rxbuf[4];
+ if (status == FPGA_STATUS_CLEARED)
+ break;
+
+ msleep(FPGA_CLEAR_MSLEEP);
+ }
+
+ if (i == FPGA_CLEAR_LOOP_COUNT) {
+ dev_err(&spi->dev,
+ "Error: Timeout waiting for FPGA to clear (status=%08x)!\n",
+ status);
+ kfree(buffer);
+ return;
+ }
+
+ dev_info(&spi->dev, "Configuring the FPGA...\n");
+ ret = spi_write(spi, buffer, fw->size + 8);
+
+ txbuf[0] = FPGA_CMD_WRITE_DIS;
+ ret = spi_write(spi, txbuf, 4);
+
+ txbuf[0] = FPGA_CMD_READ_STATUS;
+ ret = spi_write_then_read(spi, txbuf, 8, rxbuf, rx_len);
+ dev_dbg(&spi->dev, "FPGA Status=%08x\n", *(u32 *)&rxbuf[4]);
+ status = *(u32 *)&rxbuf[4];
+
+ /* Check result */
+ if (status & FPGA_STATUS_DONE)
+ dev_info(&spi->dev, "FPGA succesfully configured!\n");
+ else
+ dev_info(&spi->dev, "FPGA not configured (DONE not set)\n");
+
+ /*
+ * Don't forget to release the firmware again
+ */
+ release_firmware(fw);
+
+ kfree(buffer);
+
+ complete(&data->fw_loaded);
+}
+
+static int lattice_ecp3_probe(struct spi_device *spi)
+{
+ struct fpga_data *data;
+ int err;
+
+ data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&spi->dev, "Memory allocation for fpga_data failed\n");
+ return -ENOMEM;
+ }
+ spi_set_drvdata(spi, data);
+
+ init_completion(&data->fw_loaded);
+ err = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+ FIRMWARE_NAME, &spi->dev,
+ GFP_KERNEL, spi, firmware_load);
+ if (err) {
+ dev_err(&spi->dev, "Firmware loading failed with %d!\n", err);
+ return err;
+ }
+
+ dev_info(&spi->dev, "FPGA bitstream configuration driver registered\n");
+
+ return 0;
+}
+
+static int lattice_ecp3_remove(struct spi_device *spi)
+{
+ struct fpga_data *data = spi_get_drvdata(spi);
+
+ wait_for_completion(&data->fw_loaded);
+
+ return 0;
+}
+
+static const struct spi_device_id lattice_ecp3_id[] = {
+ { "ecp3-17", 0 },
+ { "ecp3-35", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, lattice_ecp3_id);
+
+static struct spi_driver lattice_ecp3_driver = {
+ .driver = {
+ .name = "lattice-ecp3",
+ .owner = THIS_MODULE,
+ },
+ .probe = lattice_ecp3_probe,
+ .remove = lattice_ecp3_remove,
+ .id_table = lattice_ecp3_id,
+};
+
+module_spi_driver(lattice_ecp3_driver);
+
+MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
+MODULE_DESCRIPTION("Lattice ECP3 FPGA configuration via SPI");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index 5a79ccde2fdf..d21b4d006a55 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -1,11 +1,22 @@
config INTEL_MEI
- tristate "Intel Management Engine Interface (Intel MEI)"
+ tristate "Intel Management Engine Interface"
depends on X86 && PCI && WATCHDOG_CORE
help
The Intel Management Engine (Intel ME) provides Manageability,
Security and Media services for system containing Intel chipsets.
if selected /dev/mei misc device will be created.
+ For more information see
+ <http://software.intel.com/en-us/manageability/>
+
+config INTEL_MEI_ME
+ bool "ME Enabled Intel Chipsets"
+ depends on INTEL_MEI
+ depends on X86 && PCI && WATCHDOG_CORE
+ default y
+ help
+ MEI support for ME Enabled Intel chipsets.
+
Supported Chipsets are:
7 Series Chipset Family
6 Series Chipset Family
@@ -24,5 +35,3 @@ config INTEL_MEI
82Q33 Express
82X38/X48 Express
- For more information see
- <http://software.intel.com/en-us/manageability/>
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 0017842e166c..040af6c7b147 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -4,9 +4,11 @@
#
obj-$(CONFIG_INTEL_MEI) += mei.o
mei-objs := init.o
+mei-objs += hbm.o
mei-objs += interrupt.o
-mei-objs += interface.o
-mei-objs += iorw.o
+mei-objs += client.o
mei-objs += main.o
mei-objs += amthif.o
mei-objs += wd.o
+mei-$(CONFIG_INTEL_MEI_ME) += pci-me.o
+mei-$(CONFIG_INTEL_MEI_ME) += hw-me.o
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index e40ffd9502d1..c86d7e3839a4 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -31,15 +31,16 @@
#include <linux/jiffies.h>
#include <linux/uaccess.h>
+#include <linux/mei.h>
#include "mei_dev.h"
-#include "hw.h"
-#include <linux/mei.h>
-#include "interface.h"
+#include "hbm.h"
+#include "hw-me.h"
+#include "client.h"
-const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
- 0xa8, 0x46, 0xe0, 0xff, 0x65,
- 0x81, 0x4c);
+const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
+ 0xac, 0xa8, 0x46, 0xe0,
+ 0xff, 0x65, 0x81, 0x4c);
/**
* mei_amthif_reset_params - initializes mei device iamthif
@@ -64,22 +65,24 @@ void mei_amthif_reset_params(struct mei_device *dev)
* @dev: the device structure
*
*/
-void mei_amthif_host_init(struct mei_device *dev)
+int mei_amthif_host_init(struct mei_device *dev)
{
- int i;
+ struct mei_cl *cl = &dev->iamthif_cl;
unsigned char *msg_buf;
+ int ret, i;
+
+ dev->iamthif_state = MEI_IAMTHIF_IDLE;
- mei_cl_init(&dev->iamthif_cl, dev);
- dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
+ mei_cl_init(cl, dev);
- /* find ME amthi client */
- i = mei_me_cl_link(dev, &dev->iamthif_cl,
- &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
+ i = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
if (i < 0) {
- dev_info(&dev->pdev->dev, "failed to find iamthif client.\n");
- return;
+ dev_info(&dev->pdev->dev, "amthif: failed to find the client\n");
+ return -ENOENT;
}
+ cl->me_client_id = dev->me_clients[i].client_id;
+
/* Assign iamthif_mtu to the value received from ME */
dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
@@ -93,19 +96,29 @@ void mei_amthif_host_init(struct mei_device *dev)
msg_buf = kcalloc(dev->iamthif_mtu,
sizeof(unsigned char), GFP_KERNEL);
if (!msg_buf) {
- dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n");
- return;
+ dev_err(&dev->pdev->dev, "amthif: memory allocation for ME message buffer failed.\n");
+ return -ENOMEM;
}
dev->iamthif_msg_buf = msg_buf;
- if (mei_connect(dev, &dev->iamthif_cl)) {
- dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n");
- dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
- dev->iamthif_cl.host_client_id = 0;
+ ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
+
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "amthif: failed link client\n");
+ return -ENOENT;
+ }
+
+ cl->state = MEI_FILE_CONNECTING;
+
+ if (mei_hbm_cl_connect_req(dev, cl)) {
+ dev_dbg(&dev->pdev->dev, "amthif: Failed to connect to ME client\n");
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->host_client_id = 0;
} else {
- dev->iamthif_cl.timer_count = MEI_CONNECT_TIMEOUT;
+ cl->timer_count = MEI_CONNECT_TIMEOUT;
}
+ return 0;
}
/**
@@ -168,10 +181,10 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
if (i < 0) {
- dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
+ dev_dbg(&dev->pdev->dev, "amthif client not found.\n");
return -ENODEV;
}
- dev_dbg(&dev->pdev->dev, "checking amthi data\n");
+ dev_dbg(&dev->pdev->dev, "checking amthif data\n");
cb = mei_amthif_find_read_list_entry(dev, file);
/* Check for if we can block or not*/
@@ -179,7 +192,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
return -EAGAIN;
- dev_dbg(&dev->pdev->dev, "waiting for amthi data\n");
+ dev_dbg(&dev->pdev->dev, "waiting for amthif data\n");
while (cb == NULL) {
/* unlock the Mutex */
mutex_unlock(&dev->device_lock);
@@ -197,17 +210,17 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
}
- dev_dbg(&dev->pdev->dev, "Got amthi data\n");
+ dev_dbg(&dev->pdev->dev, "Got amthif data\n");
dev->iamthif_timer = 0;
if (cb) {
timeout = cb->read_time +
mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
- dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
+ dev_dbg(&dev->pdev->dev, "amthif timeout = %lud\n",
timeout);
if (time_after(jiffies, timeout)) {
- dev_dbg(&dev->pdev->dev, "amthi Time out\n");
+ dev_dbg(&dev->pdev->dev, "amthif Time out\n");
/* 15 sec for the message has expired */
list_del(&cb->list);
rets = -ETIMEDOUT;
@@ -227,9 +240,9 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
* remove message from deletion list
*/
- dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n",
+ dev_dbg(&dev->pdev->dev, "amthif cb->response_buffer size - %d\n",
cb->response_buffer.size);
- dev_dbg(&dev->pdev->dev, "amthi cb->buf_idx - %lu\n", cb->buf_idx);
+ dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
/* length is being turncated to PAGE_SIZE, however,
* the buf_idx may point beyond */
@@ -245,7 +258,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
}
}
free:
- dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n");
+ dev_dbg(&dev->pdev->dev, "free amthif cb memory.\n");
*offset = 0;
mei_io_cb_free(cb);
out:
@@ -269,7 +282,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
if (!dev || !cb)
return -ENODEV;
- dev_dbg(&dev->pdev->dev, "write data to amthi client.\n");
+ dev_dbg(&dev->pdev->dev, "write data to amthif client.\n");
dev->iamthif_state = MEI_IAMTHIF_WRITING;
dev->iamthif_current_cb = cb;
@@ -280,15 +293,15 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
cb->request_buffer.size);
- ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl);
+ ret = mei_cl_flow_ctrl_creds(&dev->iamthif_cl);
if (ret < 0)
return ret;
- if (ret && dev->mei_host_buffer_is_empty) {
+ if (ret && dev->hbuf_is_ready) {
ret = 0;
- dev->mei_host_buffer_is_empty = false;
- if (cb->request_buffer.size > mei_hbuf_max_data(dev)) {
- mei_hdr.length = mei_hbuf_max_data(dev);
+ dev->hbuf_is_ready = false;
+ if (cb->request_buffer.size > mei_hbuf_max_len(dev)) {
+ mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
} else {
mei_hdr.length = cb->request_buffer.size;
@@ -300,25 +313,24 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
mei_hdr.reserved = 0;
dev->iamthif_msg_buf_index += mei_hdr.length;
if (mei_write_message(dev, &mei_hdr,
- (unsigned char *)(dev->iamthif_msg_buf),
- mei_hdr.length))
+ (unsigned char *)dev->iamthif_msg_buf))
return -ENODEV;
if (mei_hdr.msg_complete) {
- if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl))
+ if (mei_cl_flow_ctrl_reduce(&dev->iamthif_cl))
return -ENODEV;
dev->iamthif_flow_control_pending = true;
dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
- dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n");
+ dev_dbg(&dev->pdev->dev, "add amthif cb to write waiting list\n");
dev->iamthif_current_cb = cb;
dev->iamthif_file_object = cb->file_object;
list_add_tail(&cb->list, &dev->write_waiting_list.list);
} else {
- dev_dbg(&dev->pdev->dev, "message does not complete, so add amthi cb to write list.\n");
+ dev_dbg(&dev->pdev->dev, "message does not complete, so add amthif cb to write list.\n");
list_add_tail(&cb->list, &dev->write_list.list);
}
} else {
- if (!(dev->mei_host_buffer_is_empty))
+ if (!dev->hbuf_is_ready)
dev_dbg(&dev->pdev->dev, "host buffer is not empty");
dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n");
@@ -383,7 +395,7 @@ void mei_amthif_run_next_cmd(struct mei_device *dev)
dev->iamthif_timer = 0;
dev->iamthif_file_object = NULL;
- dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n");
+ dev_dbg(&dev->pdev->dev, "complete amthif cmd_list cb.\n");
list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) {
list_del(&pos->list);
@@ -392,7 +404,7 @@ void mei_amthif_run_next_cmd(struct mei_device *dev)
status = mei_amthif_send_cmd(dev, pos);
if (status) {
dev_dbg(&dev->pdev->dev,
- "amthi write failed status = %d\n",
+ "amthif write failed status = %d\n",
status);
return;
}
@@ -412,7 +424,7 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
dev->iamthif_file_object == file) {
mask |= (POLLIN | POLLRDNORM);
- dev_dbg(&dev->pdev->dev, "run next amthi cb\n");
+ dev_dbg(&dev->pdev->dev, "run next amthif cb\n");
mei_amthif_run_next_cmd(dev);
}
return mask;
@@ -434,54 +446,51 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list)
{
- struct mei_msg_hdr *mei_hdr;
+ struct mei_msg_hdr mei_hdr;
struct mei_cl *cl = cb->cl;
size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index;
size_t msg_slots = mei_data2slots(len);
- mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
- mei_hdr->host_addr = cl->host_client_id;
- mei_hdr->me_addr = cl->me_client_id;
- mei_hdr->reserved = 0;
+ mei_hdr.host_addr = cl->host_client_id;
+ mei_hdr.me_addr = cl->me_client_id;
+ mei_hdr.reserved = 0;
if (*slots >= msg_slots) {
- mei_hdr->length = len;
- mei_hdr->msg_complete = 1;
+ mei_hdr.length = len;
+ mei_hdr.msg_complete = 1;
/* Split the message only if we can write the whole host buffer */
} else if (*slots == dev->hbuf_depth) {
msg_slots = *slots;
len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
- mei_hdr->length = len;
- mei_hdr->msg_complete = 0;
+ mei_hdr.length = len;
+ mei_hdr.msg_complete = 0;
} else {
/* wait for next time the host buffer is empty */
return 0;
}
- dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n",
- mei_hdr->length, mei_hdr->msg_complete);
+ dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
*slots -= msg_slots;
- if (mei_write_message(dev, mei_hdr,
- dev->iamthif_msg_buf + dev->iamthif_msg_buf_index,
- mei_hdr->length)) {
+ if (mei_write_message(dev, &mei_hdr,
+ dev->iamthif_msg_buf + dev->iamthif_msg_buf_index)) {
dev->iamthif_state = MEI_IAMTHIF_IDLE;
cl->status = -ENODEV;
list_del(&cb->list);
return -ENODEV;
}
- if (mei_flow_ctrl_reduce(dev, cl))
+ if (mei_cl_flow_ctrl_reduce(cl))
return -ENODEV;
- dev->iamthif_msg_buf_index += mei_hdr->length;
+ dev->iamthif_msg_buf_index += mei_hdr.length;
cl->status = 0;
- if (mei_hdr->msg_complete) {
+ if (mei_hdr.msg_complete) {
dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
dev->iamthif_flow_control_pending = true;
- /* save iamthif cb sent to amthi client */
+ /* save iamthif cb sent to amthif client */
cb->buf_idx = dev->iamthif_msg_buf_index;
dev->iamthif_current_cb = cb;
@@ -494,11 +503,11 @@ int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
/**
* mei_amthif_irq_read_message - read routine after ISR to
- * handle the read amthi message
+ * handle the read amthif message
*
* @complete_list: An instance of our list structure
* @dev: the device structure
- * @mei_hdr: header of amthi message
+ * @mei_hdr: header of amthif message
*
* returns 0 on success, <0 on failure.
*/
@@ -522,10 +531,10 @@ int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
return 0;
dev_dbg(&dev->pdev->dev,
- "amthi_message_buffer_index =%d\n",
+ "amthif_message_buffer_index =%d\n",
mei_hdr->length);
- dev_dbg(&dev->pdev->dev, "completed amthi read.\n ");
+ dev_dbg(&dev->pdev->dev, "completed amthif read.\n ");
if (!dev->iamthif_current_cb)
return -ENODEV;
@@ -540,8 +549,8 @@ int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
cb->read_time = jiffies;
if (dev->iamthif_ioctl && cb->cl == &dev->iamthif_cl) {
/* found the iamthif cb */
- dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n ");
- dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n ");
+ dev_dbg(&dev->pdev->dev, "complete the amthif read cb.\n ");
+ dev_dbg(&dev->pdev->dev, "add the amthif read cb to complete.\n ");
list_add_tail(&cb->list, &complete_list->list);
}
return 0;
@@ -563,7 +572,7 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
return -EMSGSIZE;
}
*slots -= mei_data2slots(sizeof(struct hbm_flow_control));
- if (mei_send_flow_control(dev, &dev->iamthif_cl)) {
+ if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) {
dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
return -EIO;
}
@@ -574,7 +583,7 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
dev->iamthif_msg_buf_index = 0;
dev->iamthif_msg_buf_size = 0;
dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
- dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
+ dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
return 0;
}
@@ -593,7 +602,7 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
dev->iamthif_msg_buf,
dev->iamthif_msg_buf_index);
list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
- dev_dbg(&dev->pdev->dev, "amthi read completed\n");
+ dev_dbg(&dev->pdev->dev, "amthif read completed\n");
dev->iamthif_timer = jiffies;
dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
dev->iamthif_timer);
@@ -601,7 +610,7 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
mei_amthif_run_next_cmd(dev);
}
- dev_dbg(&dev->pdev->dev, "completing amthi call back.\n");
+ dev_dbg(&dev->pdev->dev, "completing amthif call back.\n");
wake_up_interruptible(&dev->iamthif_cl.wait);
}
@@ -635,7 +644,8 @@ static bool mei_clear_list(struct mei_device *dev,
if (dev->iamthif_current_cb == cb_pos) {
dev->iamthif_current_cb = NULL;
/* send flow control to iamthif client */
- mei_send_flow_control(dev, &dev->iamthif_cl);
+ mei_hbm_cl_flow_control_req(dev,
+ &dev->iamthif_cl);
}
/* free all allocated buffers */
mei_io_cb_free(cb_pos);
@@ -706,11 +716,11 @@ int mei_amthif_release(struct mei_device *dev, struct file *file)
if (dev->iamthif_file_object == file &&
dev->iamthif_state != MEI_IAMTHIF_IDLE) {
- dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n",
+ dev_dbg(&dev->pdev->dev, "amthif canceled iamthif state %d\n",
dev->iamthif_state);
dev->iamthif_canceled = true;
if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
- dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n");
+ dev_dbg(&dev->pdev->dev, "run next amthif iamthif cb\n");
mei_amthif_run_next_cmd(dev);
}
}
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
new file mode 100644
index 000000000000..1569afe935de
--- /dev/null
+++ b/drivers/misc/mei/client.c
@@ -0,0 +1,729 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+#include "hbm.h"
+#include "client.h"
+
+/**
+ * mei_me_cl_by_uuid - locate index of me client
+ *
+ * @dev: mei device
+ * returns me client index or -ENOENT if not found
+ */
+int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
+{
+ int i, res = -ENOENT;
+
+ for (i = 0; i < dev->me_clients_num; ++i)
+ if (uuid_le_cmp(*uuid,
+ dev->me_clients[i].props.protocol_name) == 0) {
+ res = i;
+ break;
+ }
+
+ return res;
+}
+
+
+/**
+ * mei_me_cl_by_id return index to me_clients for client_id
+ *
+ * @dev: the device structure
+ * @client_id: me client id
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns index on success, -ENOENT on failure.
+ */
+
+int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
+{
+ int i;
+ for (i = 0; i < dev->me_clients_num; i++)
+ if (dev->me_clients[i].client_id == client_id)
+ break;
+ if (WARN_ON(dev->me_clients[i].client_id != client_id))
+ return -ENOENT;
+
+ if (i == dev->me_clients_num)
+ return -ENOENT;
+
+ return i;
+}
+
+
+/**
+ * mei_io_list_flush - removes list entry belonging to cl.
+ *
+ * @list: An instance of our list structure
+ * @cl: host client
+ */
+void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+{
+ struct mei_cl_cb *cb;
+ struct mei_cl_cb *next;
+
+ list_for_each_entry_safe(cb, next, &list->list, list) {
+ if (cb->cl && mei_cl_cmp_id(cl, cb->cl))
+ list_del(&cb->list);
+ }
+}
+
+/**
+ * mei_io_cb_free - free mei_cb_private related memory
+ *
+ * @cb: mei callback struct
+ */
+void mei_io_cb_free(struct mei_cl_cb *cb)
+{
+ if (cb == NULL)
+ return;
+
+ kfree(cb->request_buffer.data);
+ kfree(cb->response_buffer.data);
+ kfree(cb);
+}
+
+/**
+ * mei_io_cb_init - allocate and initialize io callback
+ *
+ * @cl - mei client
+ * @file: pointer to file structure
+ *
+ * returns mei_cl_cb pointer or NULL;
+ */
+struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
+{
+ struct mei_cl_cb *cb;
+
+ cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
+ if (!cb)
+ return NULL;
+
+ mei_io_list_init(cb);
+
+ cb->file_object = fp;
+ cb->cl = cl;
+ cb->buf_idx = 0;
+ return cb;
+}
+
+/**
+ * mei_io_cb_alloc_req_buf - allocate request buffer
+ *
+ * @cb - io callback structure
+ * @size: size of the buffer
+ *
+ * returns 0 on success
+ * -EINVAL if cb is NULL
+ * -ENOMEM if allocation failed
+ */
+int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
+{
+ if (!cb)
+ return -EINVAL;
+
+ if (length == 0)
+ return 0;
+
+ cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
+ if (!cb->request_buffer.data)
+ return -ENOMEM;
+ cb->request_buffer.size = length;
+ return 0;
+}
+/**
+ * mei_io_cb_alloc_req_buf - allocate respose buffer
+ *
+ * @cb - io callback structure
+ * @size: size of the buffer
+ *
+ * returns 0 on success
+ * -EINVAL if cb is NULL
+ * -ENOMEM if allocation failed
+ */
+int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
+{
+ if (!cb)
+ return -EINVAL;
+
+ if (length == 0)
+ return 0;
+
+ cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
+ if (!cb->response_buffer.data)
+ return -ENOMEM;
+ cb->response_buffer.size = length;
+ return 0;
+}
+
+
+
+/**
+ * mei_cl_flush_queues - flushes queue lists belonging to cl.
+ *
+ * @dev: the device structure
+ * @cl: host client
+ */
+int mei_cl_flush_queues(struct mei_cl *cl)
+{
+ if (WARN_ON(!cl || !cl->dev))
+ return -EINVAL;
+
+ dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
+ mei_io_list_flush(&cl->dev->read_list, cl);
+ mei_io_list_flush(&cl->dev->write_list, cl);
+ mei_io_list_flush(&cl->dev->write_waiting_list, cl);
+ mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
+ mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
+ mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
+ mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
+ return 0;
+}
+
+
+/**
+ * mei_cl_init - initializes intialize cl.
+ *
+ * @cl: host client to be initialized
+ * @dev: mei device
+ */
+void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
+{
+ memset(cl, 0, sizeof(struct mei_cl));
+ init_waitqueue_head(&cl->wait);
+ init_waitqueue_head(&cl->rx_wait);
+ init_waitqueue_head(&cl->tx_wait);
+ INIT_LIST_HEAD(&cl->link);
+ cl->reading_state = MEI_IDLE;
+ cl->writing_state = MEI_IDLE;
+ cl->dev = dev;
+}
+
+/**
+ * mei_cl_allocate - allocates cl structure and sets it up.
+ *
+ * @dev: mei device
+ * returns The allocated file or NULL on failure
+ */
+struct mei_cl *mei_cl_allocate(struct mei_device *dev)
+{
+ struct mei_cl *cl;
+
+ cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
+ if (!cl)
+ return NULL;
+
+ mei_cl_init(cl, dev);
+
+ return cl;
+}
+
+/**
+ * mei_cl_find_read_cb - find this cl's callback in the read list
+ *
+ * @dev: device structure
+ * returns cb on success, NULL on error
+ */
+struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
+{
+ struct mei_device *dev = cl->dev;
+ struct mei_cl_cb *cb = NULL;
+ struct mei_cl_cb *next = NULL;
+
+ list_for_each_entry_safe(cb, next, &dev->read_list.list, list)
+ if (mei_cl_cmp_id(cl, cb->cl))
+ return cb;
+ return NULL;
+}
+
+/** mei_cl_link: allocte host id in the host map
+ *
+ * @cl - host client
+ * @id - fixed host id or -1 for genereting one
+ * returns 0 on success
+ * -EINVAL on incorrect values
+ * -ENONET if client not found
+ */
+int mei_cl_link(struct mei_cl *cl, int id)
+{
+ struct mei_device *dev;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -EINVAL;
+
+ dev = cl->dev;
+
+ /* If Id is not asigned get one*/
+ if (id == MEI_HOST_CLIENT_ID_ANY)
+ id = find_first_zero_bit(dev->host_clients_map,
+ MEI_CLIENTS_MAX);
+
+ if (id >= MEI_CLIENTS_MAX) {
+ dev_err(&dev->pdev->dev, "id exceded %d", MEI_CLIENTS_MAX) ;
+ return -ENOENT;
+ }
+
+ dev->open_handle_count++;
+
+ cl->host_client_id = id;
+ list_add_tail(&cl->link, &dev->file_list);
+
+ set_bit(id, dev->host_clients_map);
+
+ cl->state = MEI_FILE_INITIALIZING;
+
+ dev_dbg(&dev->pdev->dev, "link cl host id = %d\n", cl->host_client_id);
+ return 0;
+}
+
+/**
+ * mei_cl_unlink - remove me_cl from the list
+ *
+ * @dev: the device structure
+ */
+int mei_cl_unlink(struct mei_cl *cl)
+{
+ struct mei_device *dev;
+ struct mei_cl *pos, *next;
+
+ /* don't shout on error exit path */
+ if (!cl)
+ return 0;
+
+ /* wd and amthif might not be initialized */
+ if (!cl->dev)
+ return 0;
+
+ dev = cl->dev;
+
+ list_for_each_entry_safe(pos, next, &dev->file_list, link) {
+ if (cl->host_client_id == pos->host_client_id) {
+ dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
+ pos->host_client_id, pos->me_client_id);
+ list_del_init(&pos->link);
+ break;
+ }
+ }
+ return 0;
+}
+
+
+void mei_host_client_init(struct work_struct *work)
+{
+ struct mei_device *dev = container_of(work,
+ struct mei_device, init_work);
+ struct mei_client_properties *client_props;
+ int i;
+
+ mutex_lock(&dev->device_lock);
+
+ bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
+ dev->open_handle_count = 0;
+
+ /*
+ * Reserving the first three client IDs
+ * 0: Reserved for MEI Bus Message communications
+ * 1: Reserved for Watchdog
+ * 2: Reserved for AMTHI
+ */
+ bitmap_set(dev->host_clients_map, 0, 3);
+
+ for (i = 0; i < dev->me_clients_num; i++) {
+ client_props = &dev->me_clients[i].props;
+
+ if (!uuid_le_cmp(client_props->protocol_name, mei_amthif_guid))
+ mei_amthif_host_init(dev);
+ else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
+ mei_wd_host_init(dev);
+ }
+
+ dev->dev_state = MEI_DEV_ENABLED;
+
+ mutex_unlock(&dev->device_lock);
+}
+
+
+/**
+ * mei_cl_disconnect - disconnect host clinet form the me one
+ *
+ * @cl: host client
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_cl_disconnect(struct mei_cl *cl)
+{
+ struct mei_device *dev;
+ struct mei_cl_cb *cb;
+ int rets, err;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ if (cl->state != MEI_FILE_DISCONNECTING)
+ return 0;
+
+ cb = mei_io_cb_init(cl, NULL);
+ if (!cb)
+ return -ENOMEM;
+
+ cb->fop_type = MEI_FOP_CLOSE;
+ if (dev->hbuf_is_ready) {
+ dev->hbuf_is_ready = false;
+ if (mei_hbm_cl_disconnect_req(dev, cl)) {
+ rets = -ENODEV;
+ dev_err(&dev->pdev->dev, "failed to disconnect.\n");
+ goto free;
+ }
+ mdelay(10); /* Wait for hardware disconnection ready */
+ list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
+ } else {
+ dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
+ list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+
+ }
+ mutex_unlock(&dev->device_lock);
+
+ err = wait_event_timeout(dev->wait_recvd_msg,
+ MEI_FILE_DISCONNECTED == cl->state,
+ mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
+
+ mutex_lock(&dev->device_lock);
+ if (MEI_FILE_DISCONNECTED == cl->state) {
+ rets = 0;
+ dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
+ } else {
+ rets = -ENODEV;
+ if (MEI_FILE_DISCONNECTED != cl->state)
+ dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
+
+ if (err)
+ dev_dbg(&dev->pdev->dev,
+ "wait failed disconnect err=%08x\n",
+ err);
+
+ dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
+ }
+
+ mei_io_list_flush(&dev->ctrl_rd_list, cl);
+ mei_io_list_flush(&dev->ctrl_wr_list, cl);
+free:
+ mei_io_cb_free(cb);
+ return rets;
+}
+
+
+/**
+ * mei_cl_is_other_connecting - checks if other
+ * client with the same me client id is connecting
+ *
+ * @cl: private data of the file object
+ *
+ * returns ture if other client is connected, 0 - otherwise.
+ */
+bool mei_cl_is_other_connecting(struct mei_cl *cl)
+{
+ struct mei_device *dev;
+ struct mei_cl *pos;
+ struct mei_cl *next;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return false;
+
+ dev = cl->dev;
+
+ list_for_each_entry_safe(pos, next, &dev->file_list, link) {
+ if ((pos->state == MEI_FILE_CONNECTING) &&
+ (pos != cl) && cl->me_client_id == pos->me_client_id)
+ return true;
+
+ }
+
+ return false;
+}
+
+/**
+ * mei_cl_connect - connect host clinet to the me one
+ *
+ * @cl: host client
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_cl_connect(struct mei_cl *cl, struct file *file)
+{
+ struct mei_device *dev;
+ struct mei_cl_cb *cb;
+ long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT);
+ int rets;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ cb = mei_io_cb_init(cl, file);
+ if (!cb) {
+ rets = -ENOMEM;
+ goto out;
+ }
+
+ cb->fop_type = MEI_FOP_IOCTL;
+
+ if (dev->hbuf_is_ready && !mei_cl_is_other_connecting(cl)) {
+ dev->hbuf_is_ready = false;
+
+ if (mei_hbm_cl_connect_req(dev, cl)) {
+ rets = -ENODEV;
+ goto out;
+ }
+ cl->timer_count = MEI_CONNECT_TIMEOUT;
+ list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
+ } else {
+ list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+ }
+
+ mutex_unlock(&dev->device_lock);
+ rets = wait_event_timeout(dev->wait_recvd_msg,
+ (cl->state == MEI_FILE_CONNECTED ||
+ cl->state == MEI_FILE_DISCONNECTED),
+ timeout * HZ);
+ mutex_lock(&dev->device_lock);
+
+ if (cl->state != MEI_FILE_CONNECTED) {
+ rets = -EFAULT;
+
+ mei_io_list_flush(&dev->ctrl_rd_list, cl);
+ mei_io_list_flush(&dev->ctrl_wr_list, cl);
+ goto out;
+ }
+
+ rets = cl->status;
+
+out:
+ mei_io_cb_free(cb);
+ return rets;
+}
+
+/**
+ * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ *
+ * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
+ * -ENOENT if mei_cl is not present
+ * -EINVAL if single_recv_buf == 0
+ */
+int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
+{
+ struct mei_device *dev;
+ int i;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -EINVAL;
+
+ dev = cl->dev;
+
+ if (!dev->me_clients_num)
+ return 0;
+
+ if (cl->mei_flow_ctrl_creds > 0)
+ return 1;
+
+ for (i = 0; i < dev->me_clients_num; i++) {
+ struct mei_me_client *me_cl = &dev->me_clients[i];
+ if (me_cl->client_id == cl->me_client_id) {
+ if (me_cl->mei_flow_ctrl_creds) {
+ if (WARN_ON(me_cl->props.single_recv_buf == 0))
+ return -EINVAL;
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+ return -ENOENT;
+}
+
+/**
+ * mei_cl_flow_ctrl_reduce - reduces flow_control.
+ *
+ * @dev: the device structure
+ * @cl: private data of the file object
+ * @returns
+ * 0 on success
+ * -ENOENT when me client is not found
+ * -EINVAL when ctrl credits are <= 0
+ */
+int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
+{
+ struct mei_device *dev;
+ int i;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -EINVAL;
+
+ dev = cl->dev;
+
+ if (!dev->me_clients_num)
+ return -ENOENT;
+
+ for (i = 0; i < dev->me_clients_num; i++) {
+ struct mei_me_client *me_cl = &dev->me_clients[i];
+ if (me_cl->client_id == cl->me_client_id) {
+ if (me_cl->props.single_recv_buf != 0) {
+ if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
+ return -EINVAL;
+ dev->me_clients[i].mei_flow_ctrl_creds--;
+ } else {
+ if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
+ return -EINVAL;
+ cl->mei_flow_ctrl_creds--;
+ }
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/**
+ * mei_cl_start_read - the start read client message function.
+ *
+ * @cl: host client
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_cl_read_start(struct mei_cl *cl)
+{
+ struct mei_device *dev;
+ struct mei_cl_cb *cb;
+ int rets;
+ int i;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ if (cl->state != MEI_FILE_CONNECTED)
+ return -ENODEV;
+
+ if (dev->dev_state != MEI_DEV_ENABLED)
+ return -ENODEV;
+
+ if (cl->read_cb) {
+ dev_dbg(&dev->pdev->dev, "read is pending.\n");
+ return -EBUSY;
+ }
+ i = mei_me_cl_by_id(dev, cl->me_client_id);
+ if (i < 0) {
+ dev_err(&dev->pdev->dev, "no such me client %d\n",
+ cl->me_client_id);
+ return -ENODEV;
+ }
+
+ cb = mei_io_cb_init(cl, NULL);
+ if (!cb)
+ return -ENOMEM;
+
+ rets = mei_io_cb_alloc_resp_buf(cb,
+ dev->me_clients[i].props.max_msg_length);
+ if (rets)
+ goto err;
+
+ cb->fop_type = MEI_FOP_READ;
+ cl->read_cb = cb;
+ if (dev->hbuf_is_ready) {
+ dev->hbuf_is_ready = false;
+ if (mei_hbm_cl_flow_control_req(dev, cl)) {
+ rets = -ENODEV;
+ goto err;
+ }
+ list_add_tail(&cb->list, &dev->read_list.list);
+ } else {
+ list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+ }
+ return rets;
+err:
+ mei_io_cb_free(cb);
+ return rets;
+}
+
+/**
+ * mei_cl_all_disconnect - disconnect forcefully all connected clients
+ *
+ * @dev - mei device
+ */
+
+void mei_cl_all_disconnect(struct mei_device *dev)
+{
+ struct mei_cl *cl, *next;
+
+ list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->mei_flow_ctrl_creds = 0;
+ cl->read_cb = NULL;
+ cl->timer_count = 0;
+ }
+}
+
+
+/**
+ * mei_cl_all_read_wakeup - wake up all readings so they can be interrupted
+ *
+ * @dev - mei device
+ */
+void mei_cl_all_read_wakeup(struct mei_device *dev)
+{
+ struct mei_cl *cl, *next;
+ list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ if (waitqueue_active(&cl->rx_wait)) {
+ dev_dbg(&dev->pdev->dev, "Waking up client!\n");
+ wake_up_interruptible(&cl->rx_wait);
+ }
+ }
+}
+
+/**
+ * mei_cl_all_write_clear - clear all pending writes
+
+ * @dev - mei device
+ */
+void mei_cl_all_write_clear(struct mei_device *dev)
+{
+ struct mei_cl_cb *cb, *next;
+
+ list_for_each_entry_safe(cb, next, &dev->write_list.list, list) {
+ list_del(&cb->list);
+ mei_io_cb_free(cb);
+ }
+}
+
+
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
new file mode 100644
index 000000000000..214b2397ec3e
--- /dev/null
+++ b/drivers/misc/mei/client.h
@@ -0,0 +1,102 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _MEI_CLIENT_H_
+#define _MEI_CLIENT_H_
+
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/poll.h>
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+
+int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid);
+int mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
+
+/*
+ * MEI IO Functions
+ */
+struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp);
+void mei_io_cb_free(struct mei_cl_cb *priv_cb);
+int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length);
+int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length);
+
+
+/**
+ * mei_io_list_init - Sets up a queue list.
+ *
+ * @list: An instance cl callback structure
+ */
+static inline void mei_io_list_init(struct mei_cl_cb *list)
+{
+ INIT_LIST_HEAD(&list->list);
+}
+void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
+
+/*
+ * MEI Host Client Functions
+ */
+
+struct mei_cl *mei_cl_allocate(struct mei_device *dev);
+void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
+
+
+int mei_cl_link(struct mei_cl *cl, int id);
+int mei_cl_unlink(struct mei_cl *cl);
+
+int mei_cl_flush_queues(struct mei_cl *cl);
+struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl);
+
+/**
+ * mei_cl_cmp_id - tells if file private data have same id
+ *
+ * @fe1: private data of 1. file object
+ * @fe2: private data of 2. file object
+ *
+ * returns true - if ids are the same and not NULL
+ */
+static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
+ const struct mei_cl *cl2)
+{
+ return cl1 && cl2 &&
+ (cl1->host_client_id == cl2->host_client_id) &&
+ (cl1->me_client_id == cl2->me_client_id);
+}
+
+
+int mei_cl_flow_ctrl_creds(struct mei_cl *cl);
+
+int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
+/*
+ * MEI input output function prototype
+ */
+bool mei_cl_is_other_connecting(struct mei_cl *cl);
+int mei_cl_disconnect(struct mei_cl *cl);
+
+int mei_cl_read_start(struct mei_cl *cl);
+
+int mei_cl_connect(struct mei_cl *cl, struct file *file);
+
+void mei_host_client_init(struct work_struct *work);
+
+
+void mei_cl_all_disconnect(struct mei_device *dev);
+void mei_cl_all_read_wakeup(struct mei_device *dev);
+void mei_cl_all_write_clear(struct mei_device *dev);
+
+
+#endif /* _MEI_CLIENT_H_ */
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
new file mode 100644
index 000000000000..fb9e63ba3bb1
--- /dev/null
+++ b/drivers/misc/mei/hbm.c
@@ -0,0 +1,669 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+#include "hbm.h"
+#include "hw-me.h"
+
+/**
+ * mei_hbm_me_cl_allocate - allocates storage for me clients
+ *
+ * @dev: the device structure
+ *
+ * returns none.
+ */
+static void mei_hbm_me_cl_allocate(struct mei_device *dev)
+{
+ struct mei_me_client *clients;
+ int b;
+
+ /* count how many ME clients we have */
+ for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
+ dev->me_clients_num++;
+
+ if (dev->me_clients_num <= 0)
+ return;
+
+ kfree(dev->me_clients);
+ dev->me_clients = NULL;
+
+ dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n",
+ dev->me_clients_num * sizeof(struct mei_me_client));
+ /* allocate storage for ME clients representation */
+ clients = kcalloc(dev->me_clients_num,
+ sizeof(struct mei_me_client), GFP_KERNEL);
+ if (!clients) {
+ dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
+ dev->dev_state = MEI_DEV_RESETING;
+ mei_reset(dev, 1);
+ return;
+ }
+ dev->me_clients = clients;
+ return;
+}
+
+/**
+ * mei_hbm_cl_hdr - construct client hbm header
+ * @cl: - client
+ * @hbm_cmd: host bus message command
+ * @buf: buffer for cl header
+ * @len: buffer length
+ */
+static inline
+void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
+{
+ struct mei_hbm_cl_cmd *cmd = buf;
+
+ memset(cmd, 0, len);
+
+ cmd->hbm_cmd = hbm_cmd;
+ cmd->host_addr = cl->host_client_id;
+ cmd->me_addr = cl->me_client_id;
+}
+
+/**
+ * same_disconn_addr - tells if they have the same address
+ *
+ * @file: private data of the file object.
+ * @disconn: disconnection request.
+ *
+ * returns true if addres are same
+ */
+static inline
+bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
+{
+ struct mei_hbm_cl_cmd *cmd = buf;
+ return cl->host_client_id == cmd->host_addr &&
+ cl->me_client_id == cmd->me_addr;
+}
+
+
+/**
+ * is_treat_specially_client - checks if the message belongs
+ * to the file private data.
+ *
+ * @cl: private data of the file object
+ * @rs: connect response bus message
+ *
+ */
+static bool is_treat_specially_client(struct mei_cl *cl,
+ struct hbm_client_connect_response *rs)
+{
+ if (mei_hbm_cl_addr_equal(cl, rs)) {
+ if (!rs->status) {
+ cl->state = MEI_FILE_CONNECTED;
+ cl->status = 0;
+
+ } else {
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->status = -ENODEV;
+ }
+ cl->timer_count = 0;
+
+ return true;
+ }
+ return false;
+}
+
+/**
+ * mei_hbm_start_req - sends start request message.
+ *
+ * @dev: the device structure
+ */
+void mei_hbm_start_req(struct mei_device *dev)
+{
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+ struct hbm_host_version_request *start_req;
+ const size_t len = sizeof(struct hbm_host_version_request);
+
+ mei_hbm_hdr(mei_hdr, len);
+
+ /* host start message */
+ start_req = (struct hbm_host_version_request *)dev->wr_msg.data;
+ memset(start_req, 0, len);
+ start_req->hbm_cmd = HOST_START_REQ_CMD;
+ start_req->host_version.major_version = HBM_MAJOR_VERSION;
+ start_req->host_version.minor_version = HBM_MINOR_VERSION;
+
+ dev->recvd_msg = false;
+ if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
+ dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
+ dev->dev_state = MEI_DEV_RESETING;
+ mei_reset(dev, 1);
+ }
+ dev->init_clients_state = MEI_START_MESSAGE;
+ dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
+ return ;
+}
+
+/**
+ * mei_hbm_enum_clients_req - sends enumeration client request message.
+ *
+ * @dev: the device structure
+ *
+ * returns none.
+ */
+static void mei_hbm_enum_clients_req(struct mei_device *dev)
+{
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+ struct hbm_host_enum_request *enum_req;
+ const size_t len = sizeof(struct hbm_host_enum_request);
+ /* enumerate clients */
+ mei_hbm_hdr(mei_hdr, len);
+
+ enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
+ memset(enum_req, 0, len);
+ enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
+
+ if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
+ dev->dev_state = MEI_DEV_RESETING;
+ dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
+ mei_reset(dev, 1);
+ }
+ dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
+ dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
+ return;
+}
+
+/**
+ * mei_hbm_prop_requsest - request property for a single client
+ *
+ * @dev: the device structure
+ *
+ * returns none.
+ */
+
+static int mei_hbm_prop_req(struct mei_device *dev)
+{
+
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+ struct hbm_props_request *prop_req;
+ const size_t len = sizeof(struct hbm_props_request);
+ unsigned long next_client_index;
+ u8 client_num;
+
+
+ client_num = dev->me_client_presentation_num;
+
+ next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
+ dev->me_client_index);
+
+ /* We got all client properties */
+ if (next_client_index == MEI_CLIENTS_MAX) {
+ schedule_work(&dev->init_work);
+
+ return 0;
+ }
+
+ dev->me_clients[client_num].client_id = next_client_index;
+ dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
+
+ mei_hbm_hdr(mei_hdr, len);
+ prop_req = (struct hbm_props_request *)dev->wr_msg.data;
+
+ memset(prop_req, 0, sizeof(struct hbm_props_request));
+
+
+ prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
+ prop_req->address = next_client_index;
+
+ if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
+ dev->dev_state = MEI_DEV_RESETING;
+ dev_err(&dev->pdev->dev, "Properties request command failed\n");
+ mei_reset(dev, 1);
+
+ return -EIO;
+ }
+
+ dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
+ dev->me_client_index = next_client_index;
+
+ return 0;
+}
+
+/**
+ * mei_hbm_stop_req_prepare - perpare stop request message
+ *
+ * @dev - mei device
+ * @mei_hdr - mei message header
+ * @data - hbm message body buffer
+ */
+static void mei_hbm_stop_req_prepare(struct mei_device *dev,
+ struct mei_msg_hdr *mei_hdr, unsigned char *data)
+{
+ struct hbm_host_stop_request *req =
+ (struct hbm_host_stop_request *)data;
+ const size_t len = sizeof(struct hbm_host_stop_request);
+
+ mei_hbm_hdr(mei_hdr, len);
+
+ memset(req, 0, len);
+ req->hbm_cmd = HOST_STOP_REQ_CMD;
+ req->reason = DRIVER_STOP_REQUEST;
+}
+
+/**
+ * mei_hbm_cl_flow_control_req - sends flow control requst.
+ *
+ * @dev: the device structure
+ * @cl: client info
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
+{
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+ const size_t len = sizeof(struct hbm_flow_control);
+
+ mei_hbm_hdr(mei_hdr, len);
+ mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, dev->wr_msg.data, len);
+
+ dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
+ cl->host_client_id, cl->me_client_id);
+
+ return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+}
+
+/**
+ * add_single_flow_creds - adds single buffer credentials.
+ *
+ * @file: private data ot the file object.
+ * @flow: flow control.
+ */
+static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
+ struct hbm_flow_control *flow)
+{
+ struct mei_me_client *client;
+ int i;
+
+ for (i = 0; i < dev->me_clients_num; i++) {
+ client = &dev->me_clients[i];
+ if (client && flow->me_addr == client->client_id) {
+ if (client->props.single_recv_buf) {
+ client->mei_flow_ctrl_creds++;
+ dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
+ flow->me_addr);
+ dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
+ client->mei_flow_ctrl_creds);
+ } else {
+ BUG(); /* error in flow control */
+ }
+ }
+ }
+}
+
+/**
+ * mei_hbm_cl_flow_control_res - flow control response from me
+ *
+ * @dev: the device structure
+ * @flow_control: flow control response bus message
+ */
+static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
+ struct hbm_flow_control *flow_control)
+{
+ struct mei_cl *cl = NULL;
+ struct mei_cl *next = NULL;
+
+ if (!flow_control->host_addr) {
+ /* single receive buffer */
+ mei_hbm_add_single_flow_creds(dev, flow_control);
+ return;
+ }
+
+ /* normal connection */
+ list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ if (mei_hbm_cl_addr_equal(cl, flow_control)) {
+ cl->mei_flow_ctrl_creds++;
+ dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
+ flow_control->host_addr, flow_control->me_addr);
+ dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
+ cl->mei_flow_ctrl_creds);
+ break;
+ }
+ }
+}
+
+
+/**
+ * mei_hbm_cl_disconnect_req - sends disconnect message to fw.
+ *
+ * @dev: the device structure
+ * @cl: a client to disconnect from
+ *
+ * This function returns -EIO on write failure
+ */
+int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
+{
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+ const size_t len = sizeof(struct hbm_client_connect_request);
+
+ mei_hbm_hdr(mei_hdr, len);
+ mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, dev->wr_msg.data, len);
+
+ return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+}
+
+/**
+ * mei_hbm_cl_disconnect_res - disconnect response from ME
+ *
+ * @dev: the device structure
+ * @rs: disconnect response bus message
+ */
+static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
+ struct hbm_client_connect_response *rs)
+{
+ struct mei_cl *cl;
+ struct mei_cl_cb *pos = NULL, *next = NULL;
+
+ dev_dbg(&dev->pdev->dev,
+ "disconnect_response:\n"
+ "ME Client = %d\n"
+ "Host Client = %d\n"
+ "Status = %d\n",
+ rs->me_addr,
+ rs->host_addr,
+ rs->status);
+
+ list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
+ cl = pos->cl;
+
+ if (!cl) {
+ list_del(&pos->list);
+ return;
+ }
+
+ dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
+ if (mei_hbm_cl_addr_equal(cl, rs)) {
+ list_del(&pos->list);
+ if (!rs->status)
+ cl->state = MEI_FILE_DISCONNECTED;
+
+ cl->status = 0;
+ cl->timer_count = 0;
+ break;
+ }
+ }
+}
+
+/**
+ * mei_hbm_cl_connect_req - send connection request to specific me client
+ *
+ * @dev: the device structure
+ * @cl: a client to connect to
+ *
+ * returns -EIO on write failure
+ */
+int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
+{
+ struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+ const size_t len = sizeof(struct hbm_client_connect_request);
+
+ mei_hbm_hdr(mei_hdr, len);
+ mei_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, dev->wr_msg.data, len);
+
+ return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+}
+
+/**
+ * mei_hbm_cl_connect_res - connect resposne from the ME
+ *
+ * @dev: the device structure
+ * @rs: connect response bus message
+ */
+static void mei_hbm_cl_connect_res(struct mei_device *dev,
+ struct hbm_client_connect_response *rs)
+{
+
+ struct mei_cl *cl;
+ struct mei_cl_cb *pos = NULL, *next = NULL;
+
+ dev_dbg(&dev->pdev->dev,
+ "connect_response:\n"
+ "ME Client = %d\n"
+ "Host Client = %d\n"
+ "Status = %d\n",
+ rs->me_addr,
+ rs->host_addr,
+ rs->status);
+
+ /* if WD or iamthif client treat specially */
+
+ if (is_treat_specially_client(&dev->wd_cl, rs)) {
+ dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
+ mei_watchdog_register(dev);
+
+ return;
+ }
+
+ if (is_treat_specially_client(&dev->iamthif_cl, rs)) {
+ dev->iamthif_state = MEI_IAMTHIF_IDLE;
+ return;
+ }
+ list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
+
+ cl = pos->cl;
+ if (!cl) {
+ list_del(&pos->list);
+ return;
+ }
+ if (pos->fop_type == MEI_FOP_IOCTL) {
+ if (is_treat_specially_client(cl, rs)) {
+ list_del(&pos->list);
+ cl->status = 0;
+ cl->timer_count = 0;
+ break;
+ }
+ }
+ }
+}
+
+
+/**
+ * mei_client_disconnect_request - disconnect request initiated by me
+ * host sends disoconnect response
+ *
+ * @dev: the device structure.
+ * @disconnect_req: disconnect request bus message from the me
+ */
+static void mei_hbm_fw_disconnect_req(struct mei_device *dev,
+ struct hbm_client_connect_request *disconnect_req)
+{
+ struct mei_cl *cl, *next;
+ const size_t len = sizeof(struct hbm_client_connect_response);
+
+ list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
+ dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
+ disconnect_req->host_addr,
+ disconnect_req->me_addr);
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->timer_count = 0;
+ if (cl == &dev->wd_cl)
+ dev->wd_pending = false;
+ else if (cl == &dev->iamthif_cl)
+ dev->iamthif_timer = 0;
+
+ /* prepare disconnect response */
+ mei_hbm_hdr(&dev->wr_ext_msg.hdr, len);
+ mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD,
+ dev->wr_ext_msg.data, len);
+ break;
+ }
+ }
+}
+
+
+/**
+ * mei_hbm_dispatch - bottom half read routine after ISR to
+ * handle the read bus message cmd processing.
+ *
+ * @dev: the device structure
+ * @mei_hdr: header of bus message
+ */
+void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
+{
+ struct mei_bus_message *mei_msg;
+ struct mei_me_client *me_client;
+ struct hbm_host_version_response *version_res;
+ struct hbm_client_connect_response *connect_res;
+ struct hbm_client_connect_response *disconnect_res;
+ struct hbm_client_connect_request *disconnect_req;
+ struct hbm_flow_control *flow_control;
+ struct hbm_props_response *props_res;
+ struct hbm_host_enum_response *enum_res;
+
+ /* read the message to our buffer */
+ BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
+ mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
+ mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
+
+ switch (mei_msg->hbm_cmd) {
+ case HOST_START_RES_CMD:
+ version_res = (struct hbm_host_version_response *)mei_msg;
+ if (!version_res->host_version_supported) {
+ dev->version = version_res->me_max_version;
+ dev_dbg(&dev->pdev->dev, "version mismatch.\n");
+
+ mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
+ dev->wr_msg.data);
+ mei_write_message(dev, &dev->wr_msg.hdr,
+ dev->wr_msg.data);
+ return;
+ }
+
+ dev->version.major_version = HBM_MAJOR_VERSION;
+ dev->version.minor_version = HBM_MINOR_VERSION;
+ if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
+ dev->init_clients_state == MEI_START_MESSAGE) {
+ dev->init_clients_timer = 0;
+ mei_hbm_enum_clients_req(dev);
+ } else {
+ dev->recvd_msg = false;
+ dev_dbg(&dev->pdev->dev, "reset due to received hbm: host start\n");
+ mei_reset(dev, 1);
+ return;
+ }
+
+ dev->recvd_msg = true;
+ dev_dbg(&dev->pdev->dev, "host start response message received.\n");
+ break;
+
+ case CLIENT_CONNECT_RES_CMD:
+ connect_res = (struct hbm_client_connect_response *) mei_msg;
+ mei_hbm_cl_connect_res(dev, connect_res);
+ dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
+ wake_up(&dev->wait_recvd_msg);
+ break;
+
+ case CLIENT_DISCONNECT_RES_CMD:
+ disconnect_res = (struct hbm_client_connect_response *) mei_msg;
+ mei_hbm_cl_disconnect_res(dev, disconnect_res);
+ dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
+ wake_up(&dev->wait_recvd_msg);
+ break;
+
+ case MEI_FLOW_CONTROL_CMD:
+ flow_control = (struct hbm_flow_control *) mei_msg;
+ mei_hbm_cl_flow_control_res(dev, flow_control);
+ dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
+ break;
+
+ case HOST_CLIENT_PROPERTIES_RES_CMD:
+ props_res = (struct hbm_props_response *)mei_msg;
+ me_client = &dev->me_clients[dev->me_client_presentation_num];
+
+ if (props_res->status || !dev->me_clients) {
+ dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
+ mei_reset(dev, 1);
+ return;
+ }
+
+ if (me_client->client_id != props_res->address) {
+ dev_err(&dev->pdev->dev,
+ "Host client properties reply mismatch\n");
+ mei_reset(dev, 1);
+
+ return;
+ }
+
+ if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
+ dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) {
+ dev_err(&dev->pdev->dev,
+ "Unexpected client properties reply\n");
+ mei_reset(dev, 1);
+
+ return;
+ }
+
+ me_client->props = props_res->client_properties;
+ dev->me_client_index++;
+ dev->me_client_presentation_num++;
+
+ /* request property for the next client */
+ mei_hbm_prop_req(dev);
+
+ break;
+
+ case HOST_ENUM_RES_CMD:
+ enum_res = (struct hbm_host_enum_response *) mei_msg;
+ memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
+ if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
+ dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
+ dev->init_clients_timer = 0;
+ dev->me_client_presentation_num = 0;
+ dev->me_client_index = 0;
+ mei_hbm_me_cl_allocate(dev);
+ dev->init_clients_state =
+ MEI_CLIENT_PROPERTIES_MESSAGE;
+
+ /* first property reqeust */
+ mei_hbm_prop_req(dev);
+ } else {
+ dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
+ mei_reset(dev, 1);
+ return;
+ }
+ break;
+
+ case HOST_STOP_RES_CMD:
+ dev->dev_state = MEI_DEV_DISABLED;
+ dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
+ mei_reset(dev, 1);
+ break;
+
+ case CLIENT_DISCONNECT_REQ_CMD:
+ /* search for client */
+ disconnect_req = (struct hbm_client_connect_request *)mei_msg;
+ mei_hbm_fw_disconnect_req(dev, disconnect_req);
+ break;
+
+ case ME_STOP_REQ_CMD:
+
+ mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
+ dev->wr_ext_msg.data);
+ break;
+ default:
+ BUG();
+ break;
+
+ }
+}
+
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h
new file mode 100644
index 000000000000..b552afbaf85c
--- /dev/null
+++ b/drivers/misc/mei/hbm.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _MEI_HBM_H_
+#define _MEI_HBM_H_
+
+void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
+
+static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
+{
+ hdr->host_addr = 0;
+ hdr->me_addr = 0;
+ hdr->length = length;
+ hdr->msg_complete = 1;
+ hdr->reserved = 0;
+}
+
+void mei_hbm_start_req(struct mei_device *dev);
+
+int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl);
+int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl);
+int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl);
+
+
+#endif /* _MEI_HBM_H_ */
+
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
new file mode 100644
index 000000000000..6a203b6e8346
--- /dev/null
+++ b/drivers/misc/mei/hw-me-regs.h
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * 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) 2003 - 2012 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 Corporation.
+ * linux-mei@linux.intel.com
+ * http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2003 - 2012 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 _MEI_HW_MEI_REGS_H_
+#define _MEI_HW_MEI_REGS_H_
+
+/*
+ * MEI device IDs
+ */
+#define MEI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */
+#define MEI_DEV_ID_82G35 0x2984 /* 82G35 Express */
+#define MEI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */
+#define MEI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */
+
+#define MEI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */
+#define MEI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */
+
+#define MEI_DEV_ID_ICH9_82Q35 0x29B4 /* 82Q35 Express */
+#define MEI_DEV_ID_ICH9_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */
+#define MEI_DEV_ID_ICH9_82Q33 0x29D4 /* 82Q33 Express */
+#define MEI_DEV_ID_ICH9_82X38 0x29E4 /* 82X38/X48 Express */
+#define MEI_DEV_ID_ICH9_3200 0x29F4 /* 3200/3210 Server */
+
+#define MEI_DEV_ID_ICH9_6 0x28B4 /* Bearlake */
+#define MEI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */
+#define MEI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */
+#define MEI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */
+#define MEI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */
+
+#define MEI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */
+#define MEI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */
+#define MEI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */
+#define MEI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */
+
+#define MEI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */
+#define MEI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */
+#define MEI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */
+#define MEI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */
+
+#define MEI_DEV_ID_IBXPK_1 0x3B64 /* Calpella */
+#define MEI_DEV_ID_IBXPK_2 0x3B65 /* Calpella */
+
+#define MEI_DEV_ID_CPT_1 0x1C3A /* Couger Point */
+#define MEI_DEV_ID_PBG_1 0x1D3A /* C600/X79 Patsburg */
+
+#define MEI_DEV_ID_PPT_1 0x1E3A /* Panther Point */
+#define MEI_DEV_ID_PPT_2 0x1CBA /* Panther Point */
+#define MEI_DEV_ID_PPT_3 0x1DBA /* Panther Point */
+
+#define MEI_DEV_ID_LPT 0x8C3A /* Lynx Point */
+#define MEI_DEV_ID_LPT_LP 0x9C3A /* Lynx Point LP */
+/*
+ * MEI HW Section
+ */
+
+/* MEI registers */
+/* H_CB_WW - Host Circular Buffer (CB) Write Window register */
+#define H_CB_WW 0
+/* H_CSR - Host Control Status register */
+#define H_CSR 4
+/* ME_CB_RW - ME Circular Buffer Read Window register (read only) */
+#define ME_CB_RW 8
+/* ME_CSR_HA - ME Control Status Host Access register (read only) */
+#define ME_CSR_HA 0xC
+
+
+/* register bits of H_CSR (Host Control Status register) */
+/* Host Circular Buffer Depth - maximum number of 32-bit entries in CB */
+#define H_CBD 0xFF000000
+/* Host Circular Buffer Write Pointer */
+#define H_CBWP 0x00FF0000
+/* Host Circular Buffer Read Pointer */
+#define H_CBRP 0x0000FF00
+/* Host Reset */
+#define H_RST 0x00000010
+/* Host Ready */
+#define H_RDY 0x00000008
+/* Host Interrupt Generate */
+#define H_IG 0x00000004
+/* Host Interrupt Status */
+#define H_IS 0x00000002
+/* Host Interrupt Enable */
+#define H_IE 0x00000001
+
+
+/* register bits of ME_CSR_HA (ME Control Status Host Access register) */
+/* ME CB (Circular Buffer) Depth HRA (Host Read Access) - host read only
+access to ME_CBD */
+#define ME_CBD_HRA 0xFF000000
+/* ME CB Write Pointer HRA - host read only access to ME_CBWP */
+#define ME_CBWP_HRA 0x00FF0000
+/* ME CB Read Pointer HRA - host read only access to ME_CBRP */
+#define ME_CBRP_HRA 0x0000FF00
+/* ME Reset HRA - host read only access to ME_RST */
+#define ME_RST_HRA 0x00000010
+/* ME Ready HRA - host read only access to ME_RDY */
+#define ME_RDY_HRA 0x00000008
+/* ME Interrupt Generate HRA - host read only access to ME_IG */
+#define ME_IG_HRA 0x00000004
+/* ME Interrupt Status HRA - host read only access to ME_IS */
+#define ME_IS_HRA 0x00000002
+/* ME Interrupt Enable HRA - host read only access to ME_IE */
+#define ME_IE_HRA 0x00000001
+
+#endif /* _MEI_HW_MEI_REGS_H_ */
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
new file mode 100644
index 000000000000..45ea7185c003
--- /dev/null
+++ b/drivers/misc/mei/hw-me.c
@@ -0,0 +1,576 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/pci.h>
+
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+
+#include "mei_dev.h"
+#include "hw-me.h"
+
+#include "hbm.h"
+
+
+/**
+ * mei_reg_read - Reads 32bit data from the mei device
+ *
+ * @dev: the device structure
+ * @offset: offset from which to read the data
+ *
+ * returns register value (u32)
+ */
+static inline u32 mei_reg_read(const struct mei_me_hw *hw,
+ unsigned long offset)
+{
+ return ioread32(hw->mem_addr + offset);
+}
+
+
+/**
+ * mei_reg_write - Writes 32bit data to the mei device
+ *
+ * @dev: the device structure
+ * @offset: offset from which to write the data
+ * @value: register value to write (u32)
+ */
+static inline void mei_reg_write(const struct mei_me_hw *hw,
+ unsigned long offset, u32 value)
+{
+ iowrite32(value, hw->mem_addr + offset);
+}
+
+/**
+ * mei_mecbrw_read - Reads 32bit data from ME circular buffer
+ * read window register
+ *
+ * @dev: the device structure
+ *
+ * returns ME_CB_RW register value (u32)
+ */
+static u32 mei_me_mecbrw_read(const struct mei_device *dev)
+{
+ return mei_reg_read(to_me_hw(dev), ME_CB_RW);
+}
+/**
+ * mei_mecsr_read - Reads 32bit data from the ME CSR
+ *
+ * @dev: the device structure
+ *
+ * returns ME_CSR_HA register value (u32)
+ */
+static inline u32 mei_mecsr_read(const struct mei_me_hw *hw)
+{
+ return mei_reg_read(hw, ME_CSR_HA);
+}
+
+/**
+ * mei_hcsr_read - Reads 32bit data from the host CSR
+ *
+ * @dev: the device structure
+ *
+ * returns H_CSR register value (u32)
+ */
+static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
+{
+ return mei_reg_read(hw, H_CSR);
+}
+
+/**
+ * mei_hcsr_set - writes H_CSR register to the mei device,
+ * and ignores the H_IS bit for it is write-one-to-zero.
+ *
+ * @dev: the device structure
+ */
+static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
+{
+ hcsr &= ~H_IS;
+ mei_reg_write(hw, H_CSR, hcsr);
+}
+
+
+/**
+ * me_hw_config - configure hw dependent settings
+ *
+ * @dev: mei device
+ */
+static void mei_me_hw_config(struct mei_device *dev)
+{
+ u32 hcsr = mei_hcsr_read(to_me_hw(dev));
+ /* Doesn't change in runtime */
+ dev->hbuf_depth = (hcsr & H_CBD) >> 24;
+}
+/**
+ * mei_clear_interrupts - clear and stop interrupts
+ *
+ * @dev: the device structure
+ */
+static void mei_me_intr_clear(struct mei_device *dev)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
+ if ((hcsr & H_IS) == H_IS)
+ mei_reg_write(hw, H_CSR, hcsr);
+}
+/**
+ * mei_me_intr_enable - enables mei device interrupts
+ *
+ * @dev: the device structure
+ */
+static void mei_me_intr_enable(struct mei_device *dev)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
+ hcsr |= H_IE;
+ mei_hcsr_set(hw, hcsr);
+}
+
+/**
+ * mei_disable_interrupts - disables mei device interrupts
+ *
+ * @dev: the device structure
+ */
+static void mei_me_intr_disable(struct mei_device *dev)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
+ hcsr &= ~H_IE;
+ mei_hcsr_set(hw, hcsr);
+}
+
+/**
+ * mei_me_hw_reset - resets fw via mei csr register.
+ *
+ * @dev: the device structure
+ * @interrupts_enabled: if interrupt should be enabled after reset.
+ */
+static void mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
+
+ dev_dbg(&dev->pdev->dev, "before reset HCSR = 0x%08x.\n", hcsr);
+
+ hcsr |= (H_RST | H_IG);
+
+ if (intr_enable)
+ hcsr |= H_IE;
+ else
+ hcsr &= ~H_IE;
+
+ mei_hcsr_set(hw, hcsr);
+
+ hcsr = mei_hcsr_read(hw) | H_IG;
+ hcsr &= ~H_RST;
+
+ mei_hcsr_set(hw, hcsr);
+
+ hcsr = mei_hcsr_read(hw);
+
+ dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", hcsr);
+}
+
+/**
+ * mei_me_host_set_ready - enable device
+ *
+ * @dev - mei device
+ * returns bool
+ */
+
+static void mei_me_host_set_ready(struct mei_device *dev)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ hw->host_hw_state |= H_IE | H_IG | H_RDY;
+ mei_hcsr_set(hw, hw->host_hw_state);
+}
+/**
+ * mei_me_host_is_ready - check whether the host has turned ready
+ *
+ * @dev - mei device
+ * returns bool
+ */
+static bool mei_me_host_is_ready(struct mei_device *dev)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ hw->host_hw_state = mei_hcsr_read(hw);
+ return (hw->host_hw_state & H_RDY) == H_RDY;
+}
+
+/**
+ * mei_me_hw_is_ready - check whether the me(hw) has turned ready
+ *
+ * @dev - mei device
+ * returns bool
+ */
+static bool mei_me_hw_is_ready(struct mei_device *dev)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ hw->me_hw_state = mei_mecsr_read(hw);
+ return (hw->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA;
+}
+
+/**
+ * mei_hbuf_filled_slots - gets number of device filled buffer slots
+ *
+ * @dev: the device structure
+ *
+ * returns number of filled slots
+ */
+static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ char read_ptr, write_ptr;
+
+ hw->host_hw_state = mei_hcsr_read(hw);
+
+ read_ptr = (char) ((hw->host_hw_state & H_CBRP) >> 8);
+ write_ptr = (char) ((hw->host_hw_state & H_CBWP) >> 16);
+
+ return (unsigned char) (write_ptr - read_ptr);
+}
+
+/**
+ * mei_hbuf_is_empty - checks if host buffer is empty.
+ *
+ * @dev: the device structure
+ *
+ * returns true if empty, false - otherwise.
+ */
+static bool mei_me_hbuf_is_empty(struct mei_device *dev)
+{
+ return mei_hbuf_filled_slots(dev) == 0;
+}
+
+/**
+ * mei_me_hbuf_empty_slots - counts write empty slots.
+ *
+ * @dev: the device structure
+ *
+ * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
+ */
+static int mei_me_hbuf_empty_slots(struct mei_device *dev)
+{
+ unsigned char filled_slots, empty_slots;
+
+ filled_slots = mei_hbuf_filled_slots(dev);
+ empty_slots = dev->hbuf_depth - filled_slots;
+
+ /* check for overflow */
+ if (filled_slots > dev->hbuf_depth)
+ return -EOVERFLOW;
+
+ return empty_slots;
+}
+
+static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
+{
+ return dev->hbuf_depth * sizeof(u32) - sizeof(struct mei_msg_hdr);
+}
+
+
+/**
+ * mei_write_message - writes a message to mei device.
+ *
+ * @dev: the device structure
+ * @header: mei HECI header of message
+ * @buf: message payload will be written
+ *
+ * This function returns -EIO if write has failed
+ */
+static int mei_me_write_message(struct mei_device *dev,
+ struct mei_msg_hdr *header,
+ unsigned char *buf)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ unsigned long rem, dw_cnt;
+ unsigned long length = header->length;
+ u32 *reg_buf = (u32 *)buf;
+ u32 hcsr;
+ int i;
+ int empty_slots;
+
+ dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
+
+ empty_slots = mei_hbuf_empty_slots(dev);
+ dev_dbg(&dev->pdev->dev, "empty slots = %hu.\n", empty_slots);
+
+ dw_cnt = mei_data2slots(length);
+ if (empty_slots < 0 || dw_cnt > empty_slots)
+ return -EIO;
+
+ mei_reg_write(hw, H_CB_WW, *((u32 *) header));
+
+ for (i = 0; i < length / 4; i++)
+ mei_reg_write(hw, H_CB_WW, reg_buf[i]);
+
+ rem = length & 0x3;
+ if (rem > 0) {
+ u32 reg = 0;
+ memcpy(&reg, &buf[length - rem], rem);
+ mei_reg_write(hw, H_CB_WW, reg);
+ }
+
+ hcsr = mei_hcsr_read(hw) | H_IG;
+ mei_hcsr_set(hw, hcsr);
+ if (!mei_me_hw_is_ready(dev))
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * mei_me_count_full_read_slots - counts read full slots.
+ *
+ * @dev: the device structure
+ *
+ * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
+ */
+static int mei_me_count_full_read_slots(struct mei_device *dev)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ char read_ptr, write_ptr;
+ unsigned char buffer_depth, filled_slots;
+
+ hw->me_hw_state = mei_mecsr_read(hw);
+ buffer_depth = (unsigned char)((hw->me_hw_state & ME_CBD_HRA) >> 24);
+ read_ptr = (char) ((hw->me_hw_state & ME_CBRP_HRA) >> 8);
+ write_ptr = (char) ((hw->me_hw_state & ME_CBWP_HRA) >> 16);
+ filled_slots = (unsigned char) (write_ptr - read_ptr);
+
+ /* check for overflow */
+ if (filled_slots > buffer_depth)
+ return -EOVERFLOW;
+
+ dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
+ return (int)filled_slots;
+}
+
+/**
+ * mei_me_read_slots - reads a message from mei device.
+ *
+ * @dev: the device structure
+ * @buffer: message buffer will be written
+ * @buffer_length: message size will be read
+ */
+static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
+ unsigned long buffer_length)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 *reg_buf = (u32 *)buffer;
+ u32 hcsr;
+
+ for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
+ *reg_buf++ = mei_me_mecbrw_read(dev);
+
+ if (buffer_length > 0) {
+ u32 reg = mei_me_mecbrw_read(dev);
+ memcpy(reg_buf, &reg, buffer_length);
+ }
+
+ hcsr = mei_hcsr_read(hw) | H_IG;
+ mei_hcsr_set(hw, hcsr);
+ return 0;
+}
+
+/**
+ * mei_me_irq_quick_handler - The ISR of the MEI device
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ */
+
+irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
+{
+ struct mei_device *dev = (struct mei_device *) dev_id;
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 csr_reg = mei_hcsr_read(hw);
+
+ if ((csr_reg & H_IS) != H_IS)
+ return IRQ_NONE;
+
+ /* clear H_IS bit in H_CSR */
+ mei_reg_write(hw, H_CSR, csr_reg);
+
+ return IRQ_WAKE_THREAD;
+}
+
+/**
+ * mei_me_irq_thread_handler - function called after ISR to handle the interrupt
+ * processing.
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ *
+ */
+irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
+{
+ struct mei_device *dev = (struct mei_device *) dev_id;
+ struct mei_cl_cb complete_list;
+ struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+ struct mei_cl *cl;
+ s32 slots;
+ int rets;
+ bool bus_message_received;
+
+
+ dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
+ /* initialize our complete list */
+ mutex_lock(&dev->device_lock);
+ mei_io_list_init(&complete_list);
+
+ /* Ack the interrupt here
+ * In case of MSI we don't go through the quick handler */
+ if (pci_dev_msi_enabled(dev->pdev))
+ mei_clear_interrupts(dev);
+
+ /* check if ME wants a reset */
+ if (!mei_hw_is_ready(dev) &&
+ dev->dev_state != MEI_DEV_RESETING &&
+ dev->dev_state != MEI_DEV_INITIALIZING) {
+ dev_dbg(&dev->pdev->dev, "FW not ready.\n");
+ mei_reset(dev, 1);
+ mutex_unlock(&dev->device_lock);
+ return IRQ_HANDLED;
+ }
+
+ /* check if we need to start the dev */
+ if (!mei_host_is_ready(dev)) {
+ if (mei_hw_is_ready(dev)) {
+ dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
+
+ mei_host_set_ready(dev);
+
+ dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
+ /* link is established * start sending messages. */
+
+ dev->dev_state = MEI_DEV_INIT_CLIENTS;
+
+ mei_hbm_start_req(dev);
+ mutex_unlock(&dev->device_lock);
+ return IRQ_HANDLED;
+ } else {
+ dev_dbg(&dev->pdev->dev, "FW not ready.\n");
+ mutex_unlock(&dev->device_lock);
+ return IRQ_HANDLED;
+ }
+ }
+ /* check slots available for reading */
+ slots = mei_count_full_read_slots(dev);
+ while (slots > 0) {
+ /* we have urgent data to send so break the read */
+ if (dev->wr_ext_msg.hdr.length)
+ break;
+ dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots);
+ dev_dbg(&dev->pdev->dev, "call mei_irq_read_handler.\n");
+ rets = mei_irq_read_handler(dev, &complete_list, &slots);
+ if (rets)
+ goto end;
+ }
+ rets = mei_irq_write_handler(dev, &complete_list);
+end:
+ dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
+ dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+
+ bus_message_received = false;
+ if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
+ dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
+ bus_message_received = true;
+ }
+ mutex_unlock(&dev->device_lock);
+ if (bus_message_received) {
+ dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
+ wake_up_interruptible(&dev->wait_recvd_msg);
+ bus_message_received = false;
+ }
+ if (list_empty(&complete_list.list))
+ return IRQ_HANDLED;
+
+
+ list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) {
+ cl = cb_pos->cl;
+ list_del(&cb_pos->list);
+ if (cl) {
+ if (cl != &dev->iamthif_cl) {
+ dev_dbg(&dev->pdev->dev, "completing call back.\n");
+ mei_irq_complete_handler(cl, cb_pos);
+ cb_pos = NULL;
+ } else if (cl == &dev->iamthif_cl) {
+ mei_amthif_complete(dev, cb_pos);
+ }
+ }
+ }
+ return IRQ_HANDLED;
+}
+static const struct mei_hw_ops mei_me_hw_ops = {
+
+ .host_set_ready = mei_me_host_set_ready,
+ .host_is_ready = mei_me_host_is_ready,
+
+ .hw_is_ready = mei_me_hw_is_ready,
+ .hw_reset = mei_me_hw_reset,
+ .hw_config = mei_me_hw_config,
+
+ .intr_clear = mei_me_intr_clear,
+ .intr_enable = mei_me_intr_enable,
+ .intr_disable = mei_me_intr_disable,
+
+ .hbuf_free_slots = mei_me_hbuf_empty_slots,
+ .hbuf_is_ready = mei_me_hbuf_is_empty,
+ .hbuf_max_len = mei_me_hbuf_max_len,
+
+ .write = mei_me_write_message,
+
+ .rdbuf_full_slots = mei_me_count_full_read_slots,
+ .read_hdr = mei_me_mecbrw_read,
+ .read = mei_me_read_slots
+};
+
+/**
+ * init_mei_device - allocates and initializes the mei device structure
+ *
+ * @pdev: The pci device structure
+ *
+ * returns The mei_device_device pointer on success, NULL on failure.
+ */
+struct mei_device *mei_me_dev_init(struct pci_dev *pdev)
+{
+ struct mei_device *dev;
+
+ dev = kzalloc(sizeof(struct mei_device) +
+ sizeof(struct mei_me_hw), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ mei_device_init(dev);
+
+ INIT_LIST_HEAD(&dev->wd_cl.link);
+ INIT_LIST_HEAD(&dev->iamthif_cl.link);
+ mei_io_list_init(&dev->amthif_cmd_list);
+ mei_io_list_init(&dev->amthif_rd_complete_list);
+
+ INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
+ INIT_WORK(&dev->init_work, mei_host_client_init);
+
+ dev->ops = &mei_me_hw_ops;
+
+ dev->pdev = pdev;
+ return dev;
+}
+
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
new file mode 100644
index 000000000000..8518d3eeb838
--- /dev/null
+++ b/drivers/misc/mei/hw-me.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+
+
+#ifndef _MEI_INTERFACE_H_
+#define _MEI_INTERFACE_H_
+
+#include <linux/mei.h>
+#include "mei_dev.h"
+#include "client.h"
+
+struct mei_me_hw {
+ void __iomem *mem_addr;
+ /*
+ * hw states of host and fw(ME)
+ */
+ u32 host_hw_state;
+ u32 me_hw_state;
+};
+
+#define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw)
+
+struct mei_device *mei_me_dev_init(struct pci_dev *pdev);
+
+/* get slots (dwords) from a message length + header (bytes) */
+static inline unsigned char mei_data2slots(size_t length)
+{
+ return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
+}
+
+irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id);
+irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id);
+
+#endif /* _MEI_INTERFACE_H_ */
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index be8ca6b333ca..cb2f556b4252 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -31,109 +31,6 @@
#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */
#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */
-/*
- * Internal Clients Number
- */
-#define MEI_WD_HOST_CLIENT_ID 1
-#define MEI_IAMTHIF_HOST_CLIENT_ID 2
-
-/*
- * MEI device IDs
- */
-#define MEI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */
-#define MEI_DEV_ID_82G35 0x2984 /* 82G35 Express */
-#define MEI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */
-#define MEI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */
-
-#define MEI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */
-#define MEI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */
-
-#define MEI_DEV_ID_ICH9_82Q35 0x29B4 /* 82Q35 Express */
-#define MEI_DEV_ID_ICH9_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */
-#define MEI_DEV_ID_ICH9_82Q33 0x29D4 /* 82Q33 Express */
-#define MEI_DEV_ID_ICH9_82X38 0x29E4 /* 82X38/X48 Express */
-#define MEI_DEV_ID_ICH9_3200 0x29F4 /* 3200/3210 Server */
-
-#define MEI_DEV_ID_ICH9_6 0x28B4 /* Bearlake */
-#define MEI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */
-#define MEI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */
-#define MEI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */
-#define MEI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */
-
-#define MEI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */
-#define MEI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */
-#define MEI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */
-#define MEI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */
-
-#define MEI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */
-#define MEI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */
-#define MEI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */
-#define MEI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */
-
-#define MEI_DEV_ID_IBXPK_1 0x3B64 /* Calpella */
-#define MEI_DEV_ID_IBXPK_2 0x3B65 /* Calpella */
-
-#define MEI_DEV_ID_CPT_1 0x1C3A /* Couger Point */
-#define MEI_DEV_ID_PBG_1 0x1D3A /* C600/X79 Patsburg */
-
-#define MEI_DEV_ID_PPT_1 0x1E3A /* Panther Point */
-#define MEI_DEV_ID_PPT_2 0x1CBA /* Panther Point */
-#define MEI_DEV_ID_PPT_3 0x1DBA /* Panther Point */
-
-#define MEI_DEV_ID_LPT 0x8C3A /* Lynx Point */
-#define MEI_DEV_ID_LPT_LP 0x9C3A /* Lynx Point LP */
-/*
- * MEI HW Section
- */
-
-/* MEI registers */
-/* H_CB_WW - Host Circular Buffer (CB) Write Window register */
-#define H_CB_WW 0
-/* H_CSR - Host Control Status register */
-#define H_CSR 4
-/* ME_CB_RW - ME Circular Buffer Read Window register (read only) */
-#define ME_CB_RW 8
-/* ME_CSR_HA - ME Control Status Host Access register (read only) */
-#define ME_CSR_HA 0xC
-
-
-/* register bits of H_CSR (Host Control Status register) */
-/* Host Circular Buffer Depth - maximum number of 32-bit entries in CB */
-#define H_CBD 0xFF000000
-/* Host Circular Buffer Write Pointer */
-#define H_CBWP 0x00FF0000
-/* Host Circular Buffer Read Pointer */
-#define H_CBRP 0x0000FF00
-/* Host Reset */
-#define H_RST 0x00000010
-/* Host Ready */
-#define H_RDY 0x00000008
-/* Host Interrupt Generate */
-#define H_IG 0x00000004
-/* Host Interrupt Status */
-#define H_IS 0x00000002
-/* Host Interrupt Enable */
-#define H_IE 0x00000001
-
-
-/* register bits of ME_CSR_HA (ME Control Status Host Access register) */
-/* ME CB (Circular Buffer) Depth HRA (Host Read Access) - host read only
-access to ME_CBD */
-#define ME_CBD_HRA 0xFF000000
-/* ME CB Write Pointer HRA - host read only access to ME_CBWP */
-#define ME_CBWP_HRA 0x00FF0000
-/* ME CB Read Pointer HRA - host read only access to ME_CBRP */
-#define ME_CBRP_HRA 0x0000FF00
-/* ME Reset HRA - host read only access to ME_RST */
-#define ME_RST_HRA 0x00000010
-/* ME Ready HRA - host read only access to ME_RDY */
-#define ME_RDY_HRA 0x00000008
-/* ME Interrupt Generate HRA - host read only access to ME_IG */
-#define ME_IG_HRA 0x00000004
-/* ME Interrupt Status HRA - host read only access to ME_IS */
-#define ME_IS_HRA 0x00000002
-/* ME Interrupt Enable HRA - host read only access to ME_IE */
-#define ME_IE_HRA 0x00000001
/*
* MEI Version
@@ -224,6 +121,22 @@ struct mei_bus_message {
u8 data[0];
} __packed;
+/**
+ * struct hbm_cl_cmd - client specific host bus command
+ * CONNECT, DISCONNECT, and FlOW CONTROL
+ *
+ * @hbm_cmd - bus message command header
+ * @me_addr - address of the client in ME
+ * @host_addr - address of the client in the driver
+ * @data
+ */
+struct mei_hbm_cl_cmd {
+ u8 hbm_cmd;
+ u8 me_addr;
+ u8 host_addr;
+ u8 data;
+};
+
struct hbm_version {
u8 minor_version;
u8 major_version;
@@ -333,11 +246,5 @@ struct hbm_flow_control {
u8 reserved[MEI_FC_MESSAGE_RESERVED_LENGTH];
} __packed;
-struct mei_me_client {
- struct mei_client_properties props;
- u8 client_id;
- u8 mei_flow_ctrl_creds;
-} __packed;
-
#endif
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index a54cd5567ca2..6ec530168afb 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -19,11 +19,11 @@
#include <linux/wait.h>
#include <linux/delay.h>
-#include "mei_dev.h"
-#include "hw.h"
-#include "interface.h"
#include <linux/mei.h>
+#include "mei_dev.h"
+#include "client.h"
+
const char *mei_dev_state_str(int state)
{
#define MEI_DEV_STATE(state) case MEI_DEV_##state: return #state
@@ -42,84 +42,20 @@ const char *mei_dev_state_str(int state)
#undef MEI_DEV_STATE
}
-
-
-/**
- * mei_io_list_flush - removes list entry belonging to cl.
- *
- * @list: An instance of our list structure
- * @cl: private data of the file object
- */
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
-{
- struct mei_cl_cb *pos;
- struct mei_cl_cb *next;
-
- list_for_each_entry_safe(pos, next, &list->list, list) {
- if (pos->cl) {
- if (mei_cl_cmp_id(cl, pos->cl))
- list_del(&pos->list);
- }
- }
-}
-/**
- * mei_cl_flush_queues - flushes queue lists belonging to cl.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- */
-int mei_cl_flush_queues(struct mei_cl *cl)
+void mei_device_init(struct mei_device *dev)
{
- if (!cl || !cl->dev)
- return -EINVAL;
-
- dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
- mei_io_list_flush(&cl->dev->read_list, cl);
- mei_io_list_flush(&cl->dev->write_list, cl);
- mei_io_list_flush(&cl->dev->write_waiting_list, cl);
- mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
- mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
- mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
- mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
- return 0;
-}
-
-
-
-/**
- * init_mei_device - allocates and initializes the mei device structure
- *
- * @pdev: The pci device structure
- *
- * returns The mei_device_device pointer on success, NULL on failure.
- */
-struct mei_device *mei_device_init(struct pci_dev *pdev)
-{
- struct mei_device *dev;
-
- dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL);
- if (!dev)
- return NULL;
-
/* setup our list array */
INIT_LIST_HEAD(&dev->file_list);
- INIT_LIST_HEAD(&dev->wd_cl.link);
- INIT_LIST_HEAD(&dev->iamthif_cl.link);
mutex_init(&dev->device_lock);
init_waitqueue_head(&dev->wait_recvd_msg);
init_waitqueue_head(&dev->wait_stop_wd);
dev->dev_state = MEI_DEV_INITIALIZING;
- dev->iamthif_state = MEI_IAMTHIF_IDLE;
mei_io_list_init(&dev->read_list);
mei_io_list_init(&dev->write_list);
mei_io_list_init(&dev->write_waiting_list);
mei_io_list_init(&dev->ctrl_wr_list);
mei_io_list_init(&dev->ctrl_rd_list);
- mei_io_list_init(&dev->amthif_cmd_list);
- mei_io_list_init(&dev->amthif_rd_complete_list);
- dev->pdev = pdev;
- return dev;
}
/**
@@ -131,101 +67,64 @@ struct mei_device *mei_device_init(struct pci_dev *pdev)
*/
int mei_hw_init(struct mei_device *dev)
{
- int err = 0;
- int ret;
+ int ret = 0;
mutex_lock(&dev->device_lock);
- dev->host_hw_state = mei_hcsr_read(dev);
- dev->me_hw_state = mei_mecsr_read(dev);
- dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, mestate = 0x%08x.\n",
- dev->host_hw_state, dev->me_hw_state);
-
/* acknowledge interrupt and stop interupts */
- if ((dev->host_hw_state & H_IS) == H_IS)
- mei_reg_write(dev, H_CSR, dev->host_hw_state);
+ mei_clear_interrupts(dev);
- /* Doesn't change in runtime */
- dev->hbuf_depth = (dev->host_hw_state & H_CBD) >> 24;
+ mei_hw_config(dev);
dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
mei_reset(dev, 1);
- dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
- dev->host_hw_state, dev->me_hw_state);
-
/* wait for ME to turn on ME_RDY */
if (!dev->recvd_msg) {
mutex_unlock(&dev->device_lock);
- err = wait_event_interruptible_timeout(dev->wait_recvd_msg,
+ ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
dev->recvd_msg,
mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
mutex_lock(&dev->device_lock);
}
- if (err <= 0 && !dev->recvd_msg) {
+ if (ret <= 0 && !dev->recvd_msg) {
dev->dev_state = MEI_DEV_DISABLED;
dev_dbg(&dev->pdev->dev,
"wait_event_interruptible_timeout failed"
"on wait for ME to turn on ME_RDY.\n");
- ret = -ENODEV;
- goto out;
+ goto err;
}
- if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
- ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
- dev->dev_state = MEI_DEV_DISABLED;
- dev_dbg(&dev->pdev->dev,
- "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
- dev->host_hw_state, dev->me_hw_state);
-
- if (!(dev->host_hw_state & H_RDY))
- dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n");
- if (!(dev->me_hw_state & ME_RDY_HRA))
- dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n");
+ if (!mei_host_is_ready(dev)) {
+ dev_err(&dev->pdev->dev, "host is not ready.\n");
+ goto err;
+ }
- dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
- ret = -ENODEV;
- goto out;
+ if (!mei_hw_is_ready(dev)) {
+ dev_err(&dev->pdev->dev, "ME is not ready.\n");
+ goto err;
}
if (dev->version.major_version != HBM_MAJOR_VERSION ||
dev->version.minor_version != HBM_MINOR_VERSION) {
dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
- ret = -ENODEV;
- goto out;
+ goto err;
}
dev->recvd_msg = false;
- dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
- dev->host_hw_state, dev->me_hw_state);
- dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n");
dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
- dev_dbg(&dev->pdev->dev, "MEI start success.\n");
- ret = 0;
-out:
mutex_unlock(&dev->device_lock);
- return ret;
-}
-
-/**
- * mei_hw_reset - resets fw via mei csr register.
- *
- * @dev: the device structure
- * @interrupts_enabled: if interrupt should be enabled after reset.
- */
-static void mei_hw_reset(struct mei_device *dev, int interrupts_enabled)
-{
- dev->host_hw_state |= (H_RST | H_IG);
-
- if (interrupts_enabled)
- mei_enable_interrupts(dev);
- else
- mei_disable_interrupts(dev);
+ return 0;
+err:
+ dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
+ dev->dev_state = MEI_DEV_DISABLED;
+ mutex_unlock(&dev->device_lock);
+ return -ENODEV;
}
/**
@@ -236,56 +135,34 @@ static void mei_hw_reset(struct mei_device *dev, int interrupts_enabled)
*/
void mei_reset(struct mei_device *dev, int interrupts_enabled)
{
- struct mei_cl *cl_pos = NULL;
- struct mei_cl *cl_next = NULL;
- struct mei_cl_cb *cb_pos = NULL;
- struct mei_cl_cb *cb_next = NULL;
bool unexpected;
- if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
- dev->need_reset = true;
+ if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET)
return;
- }
unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
dev->dev_state != MEI_DEV_DISABLED &&
dev->dev_state != MEI_DEV_POWER_DOWN &&
dev->dev_state != MEI_DEV_POWER_UP);
- dev->host_hw_state = mei_hcsr_read(dev);
-
- dev_dbg(&dev->pdev->dev, "before reset host_hw_state = 0x%08x.\n",
- dev->host_hw_state);
-
mei_hw_reset(dev, interrupts_enabled);
- dev->host_hw_state &= ~H_RST;
- dev->host_hw_state |= H_IG;
-
- mei_hcsr_set(dev);
-
- dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n",
- dev->host_hw_state);
-
- dev->need_reset = false;
if (dev->dev_state != MEI_DEV_INITIALIZING) {
if (dev->dev_state != MEI_DEV_DISABLED &&
dev->dev_state != MEI_DEV_POWER_DOWN)
dev->dev_state = MEI_DEV_RESETING;
- list_for_each_entry_safe(cl_pos,
- cl_next, &dev->file_list, link) {
- cl_pos->state = MEI_FILE_DISCONNECTED;
- cl_pos->mei_flow_ctrl_creds = 0;
- cl_pos->read_cb = NULL;
- cl_pos->timer_count = 0;
- }
+ mei_cl_all_disconnect(dev);
+
/* remove entry if already in list */
dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
- mei_me_cl_unlink(dev, &dev->wd_cl);
-
- mei_me_cl_unlink(dev, &dev->iamthif_cl);
+ mei_cl_unlink(&dev->wd_cl);
+ if (dev->open_handle_count > 0)
+ dev->open_handle_count--;
+ mei_cl_unlink(&dev->iamthif_cl);
+ if (dev->open_handle_count > 0)
+ dev->open_handle_count--;
mei_amthif_reset_params(dev);
memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg));
@@ -295,392 +172,17 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
dev->rd_msg_hdr = 0;
dev->wd_pending = false;
- /* update the state of the registers after reset */
- dev->host_hw_state = mei_hcsr_read(dev);
- dev->me_hw_state = mei_mecsr_read(dev);
-
- dev_dbg(&dev->pdev->dev, "after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
- dev->host_hw_state, dev->me_hw_state);
-
if (unexpected)
dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
- /* Wake up all readings so they can be interrupted */
- list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
- if (waitqueue_active(&cl_pos->rx_wait)) {
- dev_dbg(&dev->pdev->dev, "Waking up client!\n");
- wake_up_interruptible(&cl_pos->rx_wait);
- }
- }
- /* remove all waiting requests */
- list_for_each_entry_safe(cb_pos, cb_next, &dev->write_list.list, list) {
- list_del(&cb_pos->list);
- mei_io_cb_free(cb_pos);
- }
-}
-
-
-
-/**
- * host_start_message - mei host sends start message.
- *
- * @dev: the device structure
- *
- * returns none.
- */
-void mei_host_start_message(struct mei_device *dev)
-{
- struct mei_msg_hdr *mei_hdr;
- struct hbm_host_version_request *start_req;
- const size_t len = sizeof(struct hbm_host_version_request);
-
- mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
-
- /* host start message */
- start_req = (struct hbm_host_version_request *)&dev->wr_msg_buf[1];
- memset(start_req, 0, len);
- start_req->hbm_cmd = HOST_START_REQ_CMD;
- start_req->host_version.major_version = HBM_MAJOR_VERSION;
- start_req->host_version.minor_version = HBM_MINOR_VERSION;
-
- dev->recvd_msg = false;
- if (mei_write_message(dev, mei_hdr, (unsigned char *)start_req, len)) {
- dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
- dev->dev_state = MEI_DEV_RESETING;
- mei_reset(dev, 1);
- }
- dev->init_clients_state = MEI_START_MESSAGE;
- dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
- return ;
-}
-
-/**
- * host_enum_clients_message - host sends enumeration client request message.
- *
- * @dev: the device structure
- *
- * returns none.
- */
-void mei_host_enum_clients_message(struct mei_device *dev)
-{
- struct mei_msg_hdr *mei_hdr;
- struct hbm_host_enum_request *enum_req;
- const size_t len = sizeof(struct hbm_host_enum_request);
- /* enumerate clients */
- mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
-
- enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
- memset(enum_req, 0, sizeof(struct hbm_host_enum_request));
- enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
-
- if (mei_write_message(dev, mei_hdr, (unsigned char *)enum_req, len)) {
- dev->dev_state = MEI_DEV_RESETING;
- dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
- mei_reset(dev, 1);
- }
- dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
- dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
- return;
-}
-
-
-/**
- * allocate_me_clients_storage - allocates storage for me clients
- *
- * @dev: the device structure
- *
- * returns none.
- */
-void mei_allocate_me_clients_storage(struct mei_device *dev)
-{
- struct mei_me_client *clients;
- int b;
-
- /* count how many ME clients we have */
- for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
- dev->me_clients_num++;
-
- if (dev->me_clients_num <= 0)
- return ;
-
-
- if (dev->me_clients != NULL) {
- kfree(dev->me_clients);
- dev->me_clients = NULL;
- }
- dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n",
- dev->me_clients_num * sizeof(struct mei_me_client));
- /* allocate storage for ME clients representation */
- clients = kcalloc(dev->me_clients_num,
- sizeof(struct mei_me_client), GFP_KERNEL);
- if (!clients) {
- dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
- dev->dev_state = MEI_DEV_RESETING;
- mei_reset(dev, 1);
- return ;
- }
- dev->me_clients = clients;
- return ;
-}
-
-void mei_host_client_init(struct work_struct *work)
-{
- struct mei_device *dev = container_of(work,
- struct mei_device, init_work);
- struct mei_client_properties *client_props;
- int i;
-
- mutex_lock(&dev->device_lock);
-
- bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
- dev->open_handle_count = 0;
-
- /*
- * Reserving the first three client IDs
- * 0: Reserved for MEI Bus Message communications
- * 1: Reserved for Watchdog
- * 2: Reserved for AMTHI
- */
- bitmap_set(dev->host_clients_map, 0, 3);
-
- for (i = 0; i < dev->me_clients_num; i++) {
- client_props = &dev->me_clients[i].props;
-
- if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid))
- mei_amthif_host_init(dev);
- else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
- mei_wd_host_init(dev);
- }
-
- dev->dev_state = MEI_DEV_ENABLED;
-
- mutex_unlock(&dev->device_lock);
-}
-
-int mei_host_client_enumerate(struct mei_device *dev)
-{
-
- struct mei_msg_hdr *mei_hdr;
- struct hbm_props_request *prop_req;
- const size_t len = sizeof(struct hbm_props_request);
- unsigned long next_client_index;
- u8 client_num;
-
-
- client_num = dev->me_client_presentation_num;
-
- next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
- dev->me_client_index);
-
- /* We got all client properties */
- if (next_client_index == MEI_CLIENTS_MAX) {
- schedule_work(&dev->init_work);
-
- return 0;
- }
-
- dev->me_clients[client_num].client_id = next_client_index;
- dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
-
- mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
- prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1];
-
- memset(prop_req, 0, sizeof(struct hbm_props_request));
-
-
- prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
- prop_req->address = next_client_index;
-
- if (mei_write_message(dev, mei_hdr, (unsigned char *) prop_req,
- mei_hdr->length)) {
- dev->dev_state = MEI_DEV_RESETING;
- dev_err(&dev->pdev->dev, "Properties request command failed\n");
- mei_reset(dev, 1);
-
- return -EIO;
- }
-
- dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
- dev->me_client_index = next_client_index;
-
- return 0;
-}
-
-/**
- * mei_init_file_private - initializes private file structure.
- *
- * @priv: private file structure to be initialized
- * @file: the file structure
- */
-void mei_cl_init(struct mei_cl *priv, struct mei_device *dev)
-{
- memset(priv, 0, sizeof(struct mei_cl));
- init_waitqueue_head(&priv->wait);
- init_waitqueue_head(&priv->rx_wait);
- init_waitqueue_head(&priv->tx_wait);
- INIT_LIST_HEAD(&priv->link);
- priv->reading_state = MEI_IDLE;
- priv->writing_state = MEI_IDLE;
- priv->dev = dev;
-}
-
-int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid)
-{
- int i, res = -ENOENT;
-
- for (i = 0; i < dev->me_clients_num; ++i)
- if (uuid_le_cmp(*cuuid,
- dev->me_clients[i].props.protocol_name) == 0) {
- res = i;
- break;
- }
-
- return res;
-}
-
-
-/**
- * mei_me_cl_link - create link between host and me clinet and add
- * me_cl to the list
- *
- * @dev: the device structure
- * @cl: link between me and host client assocated with opened file descriptor
- * @cuuid: uuid of ME client
- * @client_id: id of the host client
- *
- * returns ME client index if ME client
- * -EINVAL on incorrect values
- * -ENONET if client not found
- */
-int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl,
- const uuid_le *cuuid, u8 host_cl_id)
-{
- int i;
-
- if (!dev || !cl || !cuuid)
- return -EINVAL;
-
- /* check for valid client id */
- i = mei_me_cl_by_uuid(dev, cuuid);
- if (i >= 0) {
- cl->me_client_id = dev->me_clients[i].client_id;
- cl->state = MEI_FILE_CONNECTING;
- cl->host_client_id = host_cl_id;
-
- list_add_tail(&cl->link, &dev->file_list);
- return (u8)i;
- }
-
- return -ENOENT;
-}
-/**
- * mei_me_cl_unlink - remove me_cl from the list
- *
- * @dev: the device structure
- * @host_client_id: host client id to be removed
- */
-void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl)
-{
- struct mei_cl *pos, *next;
- list_for_each_entry_safe(pos, next, &dev->file_list, link) {
- if (cl->host_client_id == pos->host_client_id) {
- dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
- pos->host_client_id, pos->me_client_id);
- list_del_init(&pos->link);
- break;
- }
- }
-}
+ /* wake up all readings so they can be interrupted */
+ mei_cl_all_read_wakeup(dev);
-/**
- * mei_alloc_file_private - allocates a private file structure and sets it up.
- * @file: the file structure
- *
- * returns The allocated file or NULL on failure
- */
-struct mei_cl *mei_cl_allocate(struct mei_device *dev)
-{
- struct mei_cl *cl;
-
- cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
- if (!cl)
- return NULL;
-
- mei_cl_init(cl, dev);
-
- return cl;
+ /* remove all waiting requests */
+ mei_cl_all_write_clear(dev);
}
-/**
- * mei_disconnect_host_client - sends disconnect message to fw from host client.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * Locking: called under "dev->device_lock" lock
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
-{
- struct mei_cl_cb *cb;
- int rets, err;
-
- if (!dev || !cl)
- return -ENODEV;
-
- if (cl->state != MEI_FILE_DISCONNECTING)
- return 0;
-
- cb = mei_io_cb_init(cl, NULL);
- if (!cb)
- return -ENOMEM;
-
- cb->fop_type = MEI_FOP_CLOSE;
- if (dev->mei_host_buffer_is_empty) {
- dev->mei_host_buffer_is_empty = false;
- if (mei_disconnect(dev, cl)) {
- rets = -ENODEV;
- dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n");
- goto free;
- }
- mdelay(10); /* Wait for hardware disconnection ready */
- list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
- } else {
- dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
- list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
-
- }
- mutex_unlock(&dev->device_lock);
-
- err = wait_event_timeout(dev->wait_recvd_msg,
- MEI_FILE_DISCONNECTED == cl->state,
- mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
-
- mutex_lock(&dev->device_lock);
- if (MEI_FILE_DISCONNECTED == cl->state) {
- rets = 0;
- dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
- } else {
- rets = -ENODEV;
- if (MEI_FILE_DISCONNECTED != cl->state)
- dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
-
- if (err)
- dev_dbg(&dev->pdev->dev,
- "wait failed disconnect err=%08x\n",
- err);
-
- dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
- }
-
- mei_io_list_flush(&dev->ctrl_rd_list, cl);
- mei_io_list_flush(&dev->ctrl_wr_list, cl);
-free:
- mei_io_cb_free(cb);
- return rets;
-}
diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c
deleted file mode 100644
index 8de854785960..000000000000
--- a/drivers/misc/mei/interface.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- */
-
-#include <linux/pci.h>
-#include "mei_dev.h"
-#include <linux/mei.h>
-#include "interface.h"
-
-
-
-/**
- * mei_set_csr_register - writes H_CSR register to the mei device,
- * and ignores the H_IS bit for it is write-one-to-zero.
- *
- * @dev: the device structure
- */
-void mei_hcsr_set(struct mei_device *dev)
-{
- if ((dev->host_hw_state & H_IS) == H_IS)
- dev->host_hw_state &= ~H_IS;
- mei_reg_write(dev, H_CSR, dev->host_hw_state);
- dev->host_hw_state = mei_hcsr_read(dev);
-}
-
-/**
- * mei_csr_enable_interrupts - enables mei device interrupts
- *
- * @dev: the device structure
- */
-void mei_enable_interrupts(struct mei_device *dev)
-{
- dev->host_hw_state |= H_IE;
- mei_hcsr_set(dev);
-}
-
-/**
- * mei_csr_disable_interrupts - disables mei device interrupts
- *
- * @dev: the device structure
- */
-void mei_disable_interrupts(struct mei_device *dev)
-{
- dev->host_hw_state &= ~H_IE;
- mei_hcsr_set(dev);
-}
-
-/**
- * mei_hbuf_filled_slots - gets number of device filled buffer slots
- *
- * @device: the device structure
- *
- * returns number of filled slots
- */
-static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
-{
- char read_ptr, write_ptr;
-
- dev->host_hw_state = mei_hcsr_read(dev);
-
- read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8);
- write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16);
-
- return (unsigned char) (write_ptr - read_ptr);
-}
-
-/**
- * mei_hbuf_is_empty - checks if host buffer is empty.
- *
- * @dev: the device structure
- *
- * returns true if empty, false - otherwise.
- */
-bool mei_hbuf_is_empty(struct mei_device *dev)
-{
- return mei_hbuf_filled_slots(dev) == 0;
-}
-
-/**
- * mei_hbuf_empty_slots - counts write empty slots.
- *
- * @dev: the device structure
- *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
- */
-int mei_hbuf_empty_slots(struct mei_device *dev)
-{
- unsigned char filled_slots, empty_slots;
-
- filled_slots = mei_hbuf_filled_slots(dev);
- empty_slots = dev->hbuf_depth - filled_slots;
-
- /* check for overflow */
- if (filled_slots > dev->hbuf_depth)
- return -EOVERFLOW;
-
- return empty_slots;
-}
-
-/**
- * mei_write_message - writes a message to mei device.
- *
- * @dev: the device structure
- * @header: header of message
- * @write_buffer: message buffer will be written
- * @write_length: message size will be written
- *
- * This function returns -EIO if write has failed
- */
-int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header,
- unsigned char *buf, unsigned long length)
-{
- unsigned long rem, dw_cnt;
- u32 *reg_buf = (u32 *)buf;
- int i;
- int empty_slots;
-
-
- dev_dbg(&dev->pdev->dev,
- "mei_write_message header=%08x.\n",
- *((u32 *) header));
-
- empty_slots = mei_hbuf_empty_slots(dev);
- dev_dbg(&dev->pdev->dev, "empty slots = %hu.\n", empty_slots);
-
- dw_cnt = mei_data2slots(length);
- if (empty_slots < 0 || dw_cnt > empty_slots)
- return -EIO;
-
- mei_reg_write(dev, H_CB_WW, *((u32 *) header));
-
- for (i = 0; i < length / 4; i++)
- mei_reg_write(dev, H_CB_WW, reg_buf[i]);
-
- rem = length & 0x3;
- if (rem > 0) {
- u32 reg = 0;
- memcpy(&reg, &buf[length - rem], rem);
- mei_reg_write(dev, H_CB_WW, reg);
- }
-
- dev->host_hw_state = mei_hcsr_read(dev);
- dev->host_hw_state |= H_IG;
- mei_hcsr_set(dev);
- dev->me_hw_state = mei_mecsr_read(dev);
- if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
- return -EIO;
-
- return 0;
-}
-
-/**
- * mei_count_full_read_slots - counts read full slots.
- *
- * @dev: the device structure
- *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
- */
-int mei_count_full_read_slots(struct mei_device *dev)
-{
- char read_ptr, write_ptr;
- unsigned char buffer_depth, filled_slots;
-
- dev->me_hw_state = mei_mecsr_read(dev);
- buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24);
- read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8);
- write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16);
- filled_slots = (unsigned char) (write_ptr - read_ptr);
-
- /* check for overflow */
- if (filled_slots > buffer_depth)
- return -EOVERFLOW;
-
- dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
- return (int)filled_slots;
-}
-
-/**
- * mei_read_slots - reads a message from mei device.
- *
- * @dev: the device structure
- * @buffer: message buffer will be written
- * @buffer_length: message size will be read
- */
-void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
- unsigned long buffer_length)
-{
- u32 *reg_buf = (u32 *)buffer;
-
- for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
- *reg_buf++ = mei_mecbrw_read(dev);
-
- if (buffer_length > 0) {
- u32 reg = mei_mecbrw_read(dev);
- memcpy(reg_buf, &reg, buffer_length);
- }
-
- dev->host_hw_state |= H_IG;
- mei_hcsr_set(dev);
-}
-
-/**
- * mei_flow_ctrl_creds - checks flow_control credentials.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
- * -ENOENT if mei_cl is not present
- * -EINVAL if single_recv_buf == 0
- */
-int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
-{
- int i;
-
- if (!dev->me_clients_num)
- return 0;
-
- if (cl->mei_flow_ctrl_creds > 0)
- return 1;
-
- for (i = 0; i < dev->me_clients_num; i++) {
- struct mei_me_client *me_cl = &dev->me_clients[i];
- if (me_cl->client_id == cl->me_client_id) {
- if (me_cl->mei_flow_ctrl_creds) {
- if (WARN_ON(me_cl->props.single_recv_buf == 0))
- return -EINVAL;
- return 1;
- } else {
- return 0;
- }
- }
- }
- return -ENOENT;
-}
-
-/**
- * mei_flow_ctrl_reduce - reduces flow_control.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- * @returns
- * 0 on success
- * -ENOENT when me client is not found
- * -EINVAL when ctrl credits are <= 0
- */
-int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
-{
- int i;
-
- if (!dev->me_clients_num)
- return -ENOENT;
-
- for (i = 0; i < dev->me_clients_num; i++) {
- struct mei_me_client *me_cl = &dev->me_clients[i];
- if (me_cl->client_id == cl->me_client_id) {
- if (me_cl->props.single_recv_buf != 0) {
- if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
- return -EINVAL;
- dev->me_clients[i].mei_flow_ctrl_creds--;
- } else {
- if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
- return -EINVAL;
- cl->mei_flow_ctrl_creds--;
- }
- return 0;
- }
- }
- return -ENOENT;
-}
-
-/**
- * mei_send_flow_control - sends flow control to fw.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * This function returns -EIO on write failure
- */
-int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
-{
- struct mei_msg_hdr *mei_hdr;
- struct hbm_flow_control *flow_ctrl;
- const size_t len = sizeof(struct hbm_flow_control);
-
- mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
-
- flow_ctrl = (struct hbm_flow_control *)&dev->wr_msg_buf[1];
- memset(flow_ctrl, 0, len);
- flow_ctrl->hbm_cmd = MEI_FLOW_CONTROL_CMD;
- flow_ctrl->host_addr = cl->host_client_id;
- flow_ctrl->me_addr = cl->me_client_id;
- /* FIXME: reserved !? */
- memset(flow_ctrl->reserved, 0, sizeof(flow_ctrl->reserved));
- dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
- cl->host_client_id, cl->me_client_id);
-
- return mei_write_message(dev, mei_hdr,
- (unsigned char *) flow_ctrl, len);
-}
-
-/**
- * mei_other_client_is_connecting - checks if other
- * client with the same client id is connected.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * returns 1 if other client is connected, 0 - otherwise.
- */
-int mei_other_client_is_connecting(struct mei_device *dev,
- struct mei_cl *cl)
-{
- struct mei_cl *cl_pos = NULL;
- struct mei_cl *cl_next = NULL;
-
- list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
- if ((cl_pos->state == MEI_FILE_CONNECTING) &&
- (cl_pos != cl) &&
- cl->me_client_id == cl_pos->me_client_id)
- return 1;
-
- }
- return 0;
-}
-
-/**
- * mei_disconnect - sends disconnect message to fw.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * This function returns -EIO on write failure
- */
-int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
-{
- struct mei_msg_hdr *mei_hdr;
- struct hbm_client_connect_request *req;
- const size_t len = sizeof(struct hbm_client_connect_request);
-
- mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
-
- req = (struct hbm_client_connect_request *)&dev->wr_msg_buf[1];
- memset(req, 0, len);
- req->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD;
- req->host_addr = cl->host_client_id;
- req->me_addr = cl->me_client_id;
- req->reserved = 0;
-
- return mei_write_message(dev, mei_hdr, (unsigned char *)req, len);
-}
-
-/**
- * mei_connect - sends connect message to fw.
- *
- * @dev: the device structure
- * @cl: private data of the file object
- *
- * This function returns -EIO on write failure
- */
-int mei_connect(struct mei_device *dev, struct mei_cl *cl)
-{
- struct mei_msg_hdr *mei_hdr;
- struct hbm_client_connect_request *req;
- const size_t len = sizeof(struct hbm_client_connect_request);
-
- mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len);
-
- req = (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
- req->hbm_cmd = CLIENT_CONNECT_REQ_CMD;
- req->host_addr = cl->host_client_id;
- req->me_addr = cl->me_client_id;
- req->reserved = 0;
-
- return mei_write_message(dev, mei_hdr, (unsigned char *) req, len);
-}
diff --git a/drivers/misc/mei/interface.h b/drivers/misc/mei/interface.h
deleted file mode 100644
index ec6c785a3961..000000000000
--- a/drivers/misc/mei/interface.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- */
-
-
-
-#ifndef _MEI_INTERFACE_H_
-#define _MEI_INTERFACE_H_
-
-#include <linux/mei.h>
-#include "mei_dev.h"
-
-
-
-void mei_read_slots(struct mei_device *dev,
- unsigned char *buffer,
- unsigned long buffer_length);
-
-int mei_write_message(struct mei_device *dev,
- struct mei_msg_hdr *header,
- unsigned char *write_buffer,
- unsigned long write_length);
-
-bool mei_hbuf_is_empty(struct mei_device *dev);
-
-int mei_hbuf_empty_slots(struct mei_device *dev);
-
-static inline size_t mei_hbuf_max_data(const struct mei_device *dev)
-{
- return dev->hbuf_depth * sizeof(u32) - sizeof(struct mei_msg_hdr);
-}
-
-/* get slots (dwords) from a message length + header (bytes) */
-static inline unsigned char mei_data2slots(size_t length)
-{
- return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
-}
-
-int mei_count_full_read_slots(struct mei_device *dev);
-
-
-int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
-
-
-
-int mei_wd_send(struct mei_device *dev);
-int mei_wd_stop(struct mei_device *dev);
-int mei_wd_host_init(struct mei_device *dev);
-/*
- * mei_watchdog_register - Registering watchdog interface
- * once we got connection to the WD Client
- * @dev - mei device
- */
-void mei_watchdog_register(struct mei_device *dev);
-/*
- * mei_watchdog_unregister - Unregistering watchdog interface
- * @dev - mei device
- */
-void mei_watchdog_unregister(struct mei_device *dev);
-
-int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl);
-
-int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl);
-
-int mei_disconnect(struct mei_device *dev, struct mei_cl *cl);
-int mei_other_client_is_connecting(struct mei_device *dev, struct mei_cl *cl);
-int mei_connect(struct mei_device *dev, struct mei_cl *cl);
-
-#endif /* _MEI_INTERFACE_H_ */
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 04fa2134615e..3535b2676c97 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -21,41 +21,21 @@
#include <linux/fs.h>
#include <linux/jiffies.h>
-#include "mei_dev.h"
#include <linux/mei.h>
-#include "hw.h"
-#include "interface.h"
-
-
-/**
- * mei_interrupt_quick_handler - The ISR of the MEI device
- *
- * @irq: The irq number
- * @dev_id: pointer to the device structure
- *
- * returns irqreturn_t
- */
-irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
-{
- struct mei_device *dev = (struct mei_device *) dev_id;
- u32 csr_reg = mei_hcsr_read(dev);
-
- if ((csr_reg & H_IS) != H_IS)
- return IRQ_NONE;
- /* clear H_IS bit in H_CSR */
- mei_reg_write(dev, H_CSR, csr_reg);
+#include "mei_dev.h"
+#include "hbm.h"
+#include "hw-me.h"
+#include "client.h"
- return IRQ_WAKE_THREAD;
-}
/**
- * _mei_cmpl - processes completed operation.
+ * mei_complete_handler - processes completed operation.
*
* @cl: private data of the file object.
* @cb_pos: callback block.
*/
-static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
+void mei_irq_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
{
if (cb_pos->fop_type == MEI_FOP_WRITE) {
mei_io_cb_free(cb_pos);
@@ -150,8 +130,8 @@ quit:
dev_dbg(&dev->pdev->dev, "message read\n");
if (!buffer) {
mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
- dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n",
- *(u32 *) dev->rd_msg_buf);
+ dev_dbg(&dev->pdev->dev, "discarding message " MEI_HDR_FMT "\n",
+ MEI_HDR_PRM(mei_hdr));
}
return 0;
@@ -179,7 +159,7 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
*slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
- if (mei_disconnect(dev, cl)) {
+ if (mei_hbm_cl_disconnect_req(dev, cl)) {
cl->status = 0;
cb_pos->buf_idx = 0;
list_move_tail(&cb_pos->list, &cmpl_list->list);
@@ -195,440 +175,6 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
return 0;
}
-/**
- * is_treat_specially_client - checks if the message belongs
- * to the file private data.
- *
- * @cl: private data of the file object
- * @rs: connect response bus message
- *
- */
-static bool is_treat_specially_client(struct mei_cl *cl,
- struct hbm_client_connect_response *rs)
-{
-
- if (cl->host_client_id == rs->host_addr &&
- cl->me_client_id == rs->me_addr) {
- if (!rs->status) {
- cl->state = MEI_FILE_CONNECTED;
- cl->status = 0;
-
- } else {
- cl->state = MEI_FILE_DISCONNECTED;
- cl->status = -ENODEV;
- }
- cl->timer_count = 0;
-
- return true;
- }
- return false;
-}
-
-/**
- * mei_client_connect_response - connects to response irq routine
- *
- * @dev: the device structure
- * @rs: connect response bus message
- */
-static void mei_client_connect_response(struct mei_device *dev,
- struct hbm_client_connect_response *rs)
-{
-
- struct mei_cl *cl;
- struct mei_cl_cb *pos = NULL, *next = NULL;
-
- dev_dbg(&dev->pdev->dev,
- "connect_response:\n"
- "ME Client = %d\n"
- "Host Client = %d\n"
- "Status = %d\n",
- rs->me_addr,
- rs->host_addr,
- rs->status);
-
- /* if WD or iamthif client treat specially */
-
- if (is_treat_specially_client(&(dev->wd_cl), rs)) {
- dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
- mei_watchdog_register(dev);
-
- return;
- }
-
- if (is_treat_specially_client(&(dev->iamthif_cl), rs)) {
- dev->iamthif_state = MEI_IAMTHIF_IDLE;
- return;
- }
- list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
-
- cl = pos->cl;
- if (!cl) {
- list_del(&pos->list);
- return;
- }
- if (pos->fop_type == MEI_FOP_IOCTL) {
- if (is_treat_specially_client(cl, rs)) {
- list_del(&pos->list);
- cl->status = 0;
- cl->timer_count = 0;
- break;
- }
- }
- }
-}
-
-/**
- * mei_client_disconnect_response - disconnects from response irq routine
- *
- * @dev: the device structure
- * @rs: disconnect response bus message
- */
-static void mei_client_disconnect_response(struct mei_device *dev,
- struct hbm_client_connect_response *rs)
-{
- struct mei_cl *cl;
- struct mei_cl_cb *pos = NULL, *next = NULL;
-
- dev_dbg(&dev->pdev->dev,
- "disconnect_response:\n"
- "ME Client = %d\n"
- "Host Client = %d\n"
- "Status = %d\n",
- rs->me_addr,
- rs->host_addr,
- rs->status);
-
- list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
- cl = pos->cl;
-
- if (!cl) {
- list_del(&pos->list);
- return;
- }
-
- dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
- if (cl->host_client_id == rs->host_addr &&
- cl->me_client_id == rs->me_addr) {
-
- list_del(&pos->list);
- if (!rs->status)
- cl->state = MEI_FILE_DISCONNECTED;
-
- cl->status = 0;
- cl->timer_count = 0;
- break;
- }
- }
-}
-
-/**
- * same_flow_addr - tells if they have the same address.
- *
- * @file: private data of the file object.
- * @flow: flow control.
- *
- * returns !=0, same; 0,not.
- */
-static int same_flow_addr(struct mei_cl *cl, struct hbm_flow_control *flow)
-{
- return (cl->host_client_id == flow->host_addr &&
- cl->me_client_id == flow->me_addr);
-}
-
-/**
- * add_single_flow_creds - adds single buffer credentials.
- *
- * @file: private data ot the file object.
- * @flow: flow control.
- */
-static void add_single_flow_creds(struct mei_device *dev,
- struct hbm_flow_control *flow)
-{
- struct mei_me_client *client;
- int i;
-
- for (i = 0; i < dev->me_clients_num; i++) {
- client = &dev->me_clients[i];
- if (client && flow->me_addr == client->client_id) {
- if (client->props.single_recv_buf) {
- client->mei_flow_ctrl_creds++;
- dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
- flow->me_addr);
- dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
- client->mei_flow_ctrl_creds);
- } else {
- BUG(); /* error in flow control */
- }
- }
- }
-}
-
-/**
- * mei_client_flow_control_response - flow control response irq routine
- *
- * @dev: the device structure
- * @flow_control: flow control response bus message
- */
-static void mei_client_flow_control_response(struct mei_device *dev,
- struct hbm_flow_control *flow_control)
-{
- struct mei_cl *cl_pos = NULL;
- struct mei_cl *cl_next = NULL;
-
- if (!flow_control->host_addr) {
- /* single receive buffer */
- add_single_flow_creds(dev, flow_control);
- } else {
- /* normal connection */
- list_for_each_entry_safe(cl_pos, cl_next,
- &dev->file_list, link) {
- dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in file_list\n");
-
- dev_dbg(&dev->pdev->dev, "cl of host client %d ME client %d.\n",
- cl_pos->host_client_id,
- cl_pos->me_client_id);
- dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
- flow_control->host_addr,
- flow_control->me_addr);
- if (same_flow_addr(cl_pos, flow_control)) {
- dev_dbg(&dev->pdev->dev, "recv ctrl msg for host %d ME %d.\n",
- flow_control->host_addr,
- flow_control->me_addr);
- cl_pos->mei_flow_ctrl_creds++;
- dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
- cl_pos->mei_flow_ctrl_creds);
- break;
- }
- }
- }
-}
-
-/**
- * same_disconn_addr - tells if they have the same address
- *
- * @file: private data of the file object.
- * @disconn: disconnection request.
- *
- * returns !=0, same; 0,not.
- */
-static int same_disconn_addr(struct mei_cl *cl,
- struct hbm_client_connect_request *req)
-{
- return (cl->host_client_id == req->host_addr &&
- cl->me_client_id == req->me_addr);
-}
-
-/**
- * mei_client_disconnect_request - disconnects from request irq routine
- *
- * @dev: the device structure.
- * @disconnect_req: disconnect request bus message.
- */
-static void mei_client_disconnect_request(struct mei_device *dev,
- struct hbm_client_connect_request *disconnect_req)
-{
- struct hbm_client_connect_response *disconnect_res;
- struct mei_cl *pos, *next;
- const size_t len = sizeof(struct hbm_client_connect_response);
-
- list_for_each_entry_safe(pos, next, &dev->file_list, link) {
- if (same_disconn_addr(pos, disconnect_req)) {
- dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
- disconnect_req->host_addr,
- disconnect_req->me_addr);
- pos->state = MEI_FILE_DISCONNECTED;
- pos->timer_count = 0;
- if (pos == &dev->wd_cl)
- dev->wd_pending = false;
- else if (pos == &dev->iamthif_cl)
- dev->iamthif_timer = 0;
-
- /* prepare disconnect response */
- (void)mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len);
- disconnect_res =
- (struct hbm_client_connect_response *)
- &dev->wr_ext_msg.data;
- disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD;
- disconnect_res->host_addr = pos->host_client_id;
- disconnect_res->me_addr = pos->me_client_id;
- disconnect_res->status = 0;
- break;
- }
- }
-}
-
-/**
- * mei_irq_thread_read_bus_message - bottom half read routine after ISR to
- * handle the read bus message cmd processing.
- *
- * @dev: the device structure
- * @mei_hdr: header of bus message
- */
-static void mei_irq_thread_read_bus_message(struct mei_device *dev,
- struct mei_msg_hdr *mei_hdr)
-{
- struct mei_bus_message *mei_msg;
- struct mei_me_client *me_client;
- struct hbm_host_version_response *version_res;
- struct hbm_client_connect_response *connect_res;
- struct hbm_client_connect_response *disconnect_res;
- struct hbm_client_connect_request *disconnect_req;
- struct hbm_flow_control *flow_control;
- struct hbm_props_response *props_res;
- struct hbm_host_enum_response *enum_res;
- struct hbm_host_stop_request *stop_req;
-
- /* read the message to our buffer */
- BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf));
- mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
- mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
-
- switch (mei_msg->hbm_cmd) {
- case HOST_START_RES_CMD:
- version_res = (struct hbm_host_version_response *) mei_msg;
- if (version_res->host_version_supported) {
- dev->version.major_version = HBM_MAJOR_VERSION;
- dev->version.minor_version = HBM_MINOR_VERSION;
- if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
- dev->init_clients_state == MEI_START_MESSAGE) {
- dev->init_clients_timer = 0;
- mei_host_enum_clients_message(dev);
- } else {
- dev->recvd_msg = false;
- dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
- mei_reset(dev, 1);
- return;
- }
- } else {
- u32 *buf = dev->wr_msg_buf;
- const size_t len = sizeof(struct hbm_host_stop_request);
-
- dev->version = version_res->me_max_version;
-
- /* send stop message */
- mei_hdr = mei_hbm_hdr(&buf[0], len);
- stop_req = (struct hbm_host_stop_request *)&buf[1];
- memset(stop_req, 0, len);
- stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
- stop_req->reason = DRIVER_STOP_REQUEST;
-
- mei_write_message(dev, mei_hdr,
- (unsigned char *)stop_req, len);
- dev_dbg(&dev->pdev->dev, "version mismatch.\n");
- return;
- }
-
- dev->recvd_msg = true;
- dev_dbg(&dev->pdev->dev, "host start response message received.\n");
- break;
-
- case CLIENT_CONNECT_RES_CMD:
- connect_res = (struct hbm_client_connect_response *) mei_msg;
- mei_client_connect_response(dev, connect_res);
- dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
- wake_up(&dev->wait_recvd_msg);
- break;
-
- case CLIENT_DISCONNECT_RES_CMD:
- disconnect_res = (struct hbm_client_connect_response *) mei_msg;
- mei_client_disconnect_response(dev, disconnect_res);
- dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
- wake_up(&dev->wait_recvd_msg);
- break;
-
- case MEI_FLOW_CONTROL_CMD:
- flow_control = (struct hbm_flow_control *) mei_msg;
- mei_client_flow_control_response(dev, flow_control);
- dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
- break;
-
- case HOST_CLIENT_PROPERTIES_RES_CMD:
- props_res = (struct hbm_props_response *)mei_msg;
- me_client = &dev->me_clients[dev->me_client_presentation_num];
-
- if (props_res->status || !dev->me_clients) {
- dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
- mei_reset(dev, 1);
- return;
- }
-
- if (me_client->client_id != props_res->address) {
- dev_err(&dev->pdev->dev,
- "Host client properties reply mismatch\n");
- mei_reset(dev, 1);
-
- return;
- }
-
- if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
- dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) {
- dev_err(&dev->pdev->dev,
- "Unexpected client properties reply\n");
- mei_reset(dev, 1);
-
- return;
- }
-
- me_client->props = props_res->client_properties;
- dev->me_client_index++;
- dev->me_client_presentation_num++;
-
- mei_host_client_enumerate(dev);
-
- break;
-
- case HOST_ENUM_RES_CMD:
- enum_res = (struct hbm_host_enum_response *) mei_msg;
- memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
- if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
- dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
- dev->init_clients_timer = 0;
- dev->me_client_presentation_num = 0;
- dev->me_client_index = 0;
- mei_allocate_me_clients_storage(dev);
- dev->init_clients_state =
- MEI_CLIENT_PROPERTIES_MESSAGE;
-
- mei_host_client_enumerate(dev);
- } else {
- dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
- mei_reset(dev, 1);
- return;
- }
- break;
-
- case HOST_STOP_RES_CMD:
- dev->dev_state = MEI_DEV_DISABLED;
- dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
- mei_reset(dev, 1);
- break;
-
- case CLIENT_DISCONNECT_REQ_CMD:
- /* search for client */
- disconnect_req = (struct hbm_client_connect_request *)mei_msg;
- mei_client_disconnect_request(dev, disconnect_req);
- break;
-
- case ME_STOP_REQ_CMD:
- {
- /* prepare stop request: sent in next interrupt event */
-
- const size_t len = sizeof(struct hbm_host_stop_request);
-
- mei_hdr = mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len);
- stop_req = (struct hbm_host_stop_request *)&dev->wr_ext_msg.data;
- memset(stop_req, 0, len);
- stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
- stop_req->reason = DRIVER_STOP_REQUEST;
- break;
- }
- default:
- BUG();
- break;
-
- }
-}
-
/**
* _mei_hb_read - processes read related operation.
@@ -655,7 +201,7 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots,
*slots -= mei_data2slots(sizeof(struct hbm_flow_control));
- if (mei_send_flow_control(dev, cl)) {
+ if (mei_hbm_cl_flow_control_req(dev, cl)) {
cl->status = -ENODEV;
cb_pos->buf_idx = 0;
list_move_tail(&cb_pos->list, &cmpl_list->list);
@@ -691,8 +237,8 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
}
cl->state = MEI_FILE_CONNECTING;
- *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
- if (mei_connect(dev, cl)) {
+ *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
+ if (mei_hbm_cl_connect_req(dev, cl)) {
cl->status = -ENODEV;
cb_pos->buf_idx = 0;
list_del(&cb_pos->list);
@@ -717,25 +263,24 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list)
{
- struct mei_msg_hdr *mei_hdr;
+ struct mei_msg_hdr mei_hdr;
struct mei_cl *cl = cb->cl;
size_t len = cb->request_buffer.size - cb->buf_idx;
size_t msg_slots = mei_data2slots(len);
- mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
- mei_hdr->host_addr = cl->host_client_id;
- mei_hdr->me_addr = cl->me_client_id;
- mei_hdr->reserved = 0;
+ mei_hdr.host_addr = cl->host_client_id;
+ mei_hdr.me_addr = cl->me_client_id;
+ mei_hdr.reserved = 0;
if (*slots >= msg_slots) {
- mei_hdr->length = len;
- mei_hdr->msg_complete = 1;
+ mei_hdr.length = len;
+ mei_hdr.msg_complete = 1;
/* Split the message only if we can write the whole host buffer */
} else if (*slots == dev->hbuf_depth) {
msg_slots = *slots;
len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
- mei_hdr->length = len;
- mei_hdr->msg_complete = 0;
+ mei_hdr.length = len;
+ mei_hdr.msg_complete = 0;
} else {
/* wait for next time the host buffer is empty */
return 0;
@@ -743,23 +288,22 @@ static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n",
cb->request_buffer.size, cb->buf_idx);
- dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n",
- mei_hdr->length, mei_hdr->msg_complete);
+ dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
*slots -= msg_slots;
- if (mei_write_message(dev, mei_hdr,
- cb->request_buffer.data + cb->buf_idx, len)) {
+ if (mei_write_message(dev, &mei_hdr,
+ cb->request_buffer.data + cb->buf_idx)) {
cl->status = -ENODEV;
list_move_tail(&cb->list, &cmpl_list->list);
return -ENODEV;
}
- if (mei_flow_ctrl_reduce(dev, cl))
+ if (mei_cl_flow_ctrl_reduce(cl))
return -ENODEV;
cl->status = 0;
- cb->buf_idx += mei_hdr->length;
- if (mei_hdr->msg_complete)
+ cb->buf_idx += mei_hdr.length;
+ if (mei_hdr.msg_complete)
list_move_tail(&cb->list, &dev->write_waiting_list.list);
return 0;
@@ -769,15 +313,14 @@ static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
* mei_irq_thread_read_handler - bottom half read routine after ISR to
* handle the read processing.
*
- * @cmpl_list: An instance of our list structure
* @dev: the device structure
+ * @cmpl_list: An instance of our list structure
* @slots: slots to read.
*
* returns 0 on success, <0 on failure.
*/
-static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list,
- struct mei_device *dev,
- s32 *slots)
+int mei_irq_read_handler(struct mei_device *dev,
+ struct mei_cl_cb *cmpl_list, s32 *slots)
{
struct mei_msg_hdr *mei_hdr;
struct mei_cl *cl_pos = NULL;
@@ -785,13 +328,13 @@ static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list,
int ret = 0;
if (!dev->rd_msg_hdr) {
- dev->rd_msg_hdr = mei_mecbrw_read(dev);
+ dev->rd_msg_hdr = mei_read_hdr(dev);
dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
(*slots)--;
dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
}
mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
- dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length);
+ dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
if (mei_hdr->reserved || !dev->rd_msg_hdr) {
dev_dbg(&dev->pdev->dev, "corrupted message header.\n");
@@ -830,19 +373,18 @@ static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list,
/* decide where to read the message too */
if (!mei_hdr->host_addr) {
dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
- mei_irq_thread_read_bus_message(dev, mei_hdr);
+ mei_hbm_dispatch(dev, mei_hdr);
dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
} else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
(MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
(dev->iamthif_state == MEI_IAMTHIF_READING)) {
dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
- dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
- mei_hdr->length);
+
+ dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr);
if (ret)
goto end;
-
} else {
dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
ret = mei_irq_thread_read_client_message(cmpl_list,
@@ -869,15 +411,15 @@ end:
/**
- * mei_irq_thread_write_handler - bottom half write routine after
- * ISR to handle the write processing.
+ * mei_irq_write_handler - dispatch write requests
+ * after irq received
*
* @dev: the device structure
* @cmpl_list: An instance of our list structure
*
* returns 0 on success, <0 on failure.
*/
-static int mei_irq_thread_write_handler(struct mei_device *dev,
+int mei_irq_write_handler(struct mei_device *dev,
struct mei_cl_cb *cmpl_list)
{
@@ -887,7 +429,7 @@ static int mei_irq_thread_write_handler(struct mei_device *dev,
s32 slots;
int ret;
- if (!mei_hbuf_is_empty(dev)) {
+ if (!mei_hbuf_is_ready(dev)) {
dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
return 0;
}
@@ -930,16 +472,16 @@ static int mei_irq_thread_write_handler(struct mei_device *dev,
if (dev->wr_ext_msg.hdr.length) {
mei_write_message(dev, &dev->wr_ext_msg.hdr,
- dev->wr_ext_msg.data, dev->wr_ext_msg.hdr.length);
+ dev->wr_ext_msg.data);
slots -= mei_data2slots(dev->wr_ext_msg.hdr.length);
dev->wr_ext_msg.hdr.length = 0;
}
if (dev->dev_state == MEI_DEV_ENABLED) {
if (dev->wd_pending &&
- mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
+ mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
if (mei_wd_send(dev))
dev_dbg(&dev->pdev->dev, "wd send failed.\n");
- else if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
+ else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl))
return -ENODEV;
dev->wd_pending = false;
@@ -978,7 +520,7 @@ static int mei_irq_thread_write_handler(struct mei_device *dev,
break;
case MEI_FOP_IOCTL:
/* connect message */
- if (mei_other_client_is_connecting(dev, cl))
+ if (mei_cl_is_other_connecting(cl))
continue;
ret = _mei_irq_thread_ioctl(dev, &slots, pos,
cl, cmpl_list);
@@ -998,7 +540,7 @@ static int mei_irq_thread_write_handler(struct mei_device *dev,
cl = pos->cl;
if (cl == NULL)
continue;
- if (mei_flow_ctrl_creds(dev, cl) <= 0) {
+ if (mei_cl_flow_ctrl_creds(cl) <= 0) {
dev_dbg(&dev->pdev->dev,
"No flow control credentials for client %d, not sending.\n",
cl->host_client_id);
@@ -1123,115 +665,3 @@ out:
mutex_unlock(&dev->device_lock);
}
-/**
- * mei_interrupt_thread_handler - function called after ISR to handle the interrupt
- * processing.
- *
- * @irq: The irq number
- * @dev_id: pointer to the device structure
- *
- * returns irqreturn_t
- *
- */
-irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
-{
- struct mei_device *dev = (struct mei_device *) dev_id;
- struct mei_cl_cb complete_list;
- struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
- struct mei_cl *cl;
- s32 slots;
- int rets;
- bool bus_message_received;
-
-
- dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
- /* initialize our complete list */
- mutex_lock(&dev->device_lock);
- mei_io_list_init(&complete_list);
- dev->host_hw_state = mei_hcsr_read(dev);
-
- /* Ack the interrupt here
- * In case of MSI we don't go through the quick handler */
- if (pci_dev_msi_enabled(dev->pdev))
- mei_reg_write(dev, H_CSR, dev->host_hw_state);
-
- dev->me_hw_state = mei_mecsr_read(dev);
-
- /* check if ME wants a reset */
- if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
- dev->dev_state != MEI_DEV_RESETING &&
- dev->dev_state != MEI_DEV_INITIALIZING) {
- dev_dbg(&dev->pdev->dev, "FW not ready.\n");
- mei_reset(dev, 1);
- mutex_unlock(&dev->device_lock);
- return IRQ_HANDLED;
- }
-
- /* check if we need to start the dev */
- if ((dev->host_hw_state & H_RDY) == 0) {
- if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
- dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
- dev->host_hw_state |= (H_IE | H_IG | H_RDY);
- mei_hcsr_set(dev);
- dev->dev_state = MEI_DEV_INIT_CLIENTS;
- dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
- /* link is established
- * start sending messages.
- */
- mei_host_start_message(dev);
- mutex_unlock(&dev->device_lock);
- return IRQ_HANDLED;
- } else {
- dev_dbg(&dev->pdev->dev, "FW not ready.\n");
- mutex_unlock(&dev->device_lock);
- return IRQ_HANDLED;
- }
- }
- /* check slots available for reading */
- slots = mei_count_full_read_slots(dev);
- while (slots > 0) {
- /* we have urgent data to send so break the read */
- if (dev->wr_ext_msg.hdr.length)
- break;
- dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots);
- dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n");
- rets = mei_irq_thread_read_handler(&complete_list, dev, &slots);
- if (rets)
- goto end;
- }
- rets = mei_irq_thread_write_handler(dev, &complete_list);
-end:
- dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
- dev->host_hw_state = mei_hcsr_read(dev);
- dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
-
- bus_message_received = false;
- if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
- dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
- bus_message_received = true;
- }
- mutex_unlock(&dev->device_lock);
- if (bus_message_received) {
- dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
- wake_up_interruptible(&dev->wait_recvd_msg);
- bus_message_received = false;
- }
- if (list_empty(&complete_list.list))
- return IRQ_HANDLED;
-
-
- list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) {
- cl = cb_pos->cl;
- list_del(&cb_pos->list);
- if (cl) {
- if (cl != &dev->iamthif_cl) {
- dev_dbg(&dev->pdev->dev, "completing call back.\n");
- _mei_cmpl(cl, cb_pos);
- cb_pos = NULL;
- } else if (cl == &dev->iamthif_cl) {
- mei_amthif_complete(dev, cb_pos);
- }
- }
- }
- return IRQ_HANDLED;
-}
diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c
deleted file mode 100644
index eb93a1b53b9b..000000000000
--- a/drivers/misc/mei/iorw.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- */
-
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/aio.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioctl.h>
-#include <linux/cdev.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/uuid.h>
-#include <linux/jiffies.h>
-#include <linux/uaccess.h>
-
-
-#include "mei_dev.h"
-#include "hw.h"
-#include <linux/mei.h>
-#include "interface.h"
-
-/**
- * mei_io_cb_free - free mei_cb_private related memory
- *
- * @cb: mei callback struct
- */
-void mei_io_cb_free(struct mei_cl_cb *cb)
-{
- if (cb == NULL)
- return;
-
- kfree(cb->request_buffer.data);
- kfree(cb->response_buffer.data);
- kfree(cb);
-}
-/**
- * mei_io_cb_init - allocate and initialize io callback
- *
- * @cl - mei client
- * @file: pointer to file structure
- *
- * returns mei_cl_cb pointer or NULL;
- */
-struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
-{
- struct mei_cl_cb *cb;
-
- cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
- if (!cb)
- return NULL;
-
- mei_io_list_init(cb);
-
- cb->file_object = fp;
- cb->cl = cl;
- cb->buf_idx = 0;
- return cb;
-}
-
-
-/**
- * mei_io_cb_alloc_req_buf - allocate request buffer
- *
- * @cb - io callback structure
- * @size: size of the buffer
- *
- * returns 0 on success
- * -EINVAL if cb is NULL
- * -ENOMEM if allocation failed
- */
-int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
-{
- if (!cb)
- return -EINVAL;
-
- if (length == 0)
- return 0;
-
- cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
- if (!cb->request_buffer.data)
- return -ENOMEM;
- cb->request_buffer.size = length;
- return 0;
-}
-/**
- * mei_io_cb_alloc_req_buf - allocate respose buffer
- *
- * @cb - io callback structure
- * @size: size of the buffer
- *
- * returns 0 on success
- * -EINVAL if cb is NULL
- * -ENOMEM if allocation failed
- */
-int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
-{
- if (!cb)
- return -EINVAL;
-
- if (length == 0)
- return 0;
-
- cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
- if (!cb->response_buffer.data)
- return -ENOMEM;
- cb->response_buffer.size = length;
- return 0;
-}
-
-
-/**
- * mei_me_cl_by_id return index to me_clients for client_id
- *
- * @dev: the device structure
- * @client_id: me client id
- *
- * Locking: called under "dev->device_lock" lock
- *
- * returns index on success, -ENOENT on failure.
- */
-
-int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
-{
- int i;
- for (i = 0; i < dev->me_clients_num; i++)
- if (dev->me_clients[i].client_id == client_id)
- break;
- if (WARN_ON(dev->me_clients[i].client_id != client_id))
- return -ENOENT;
-
- if (i == dev->me_clients_num)
- return -ENOENT;
-
- return i;
-}
-
-/**
- * mei_ioctl_connect_client - the connect to fw client IOCTL function
- *
- * @dev: the device structure
- * @data: IOCTL connect data, input and output parameters
- * @file: private data of the file object
- *
- * Locking: called under "dev->device_lock" lock
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_ioctl_connect_client(struct file *file,
- struct mei_connect_client_data *data)
-{
- struct mei_device *dev;
- struct mei_cl_cb *cb;
- struct mei_client *client;
- struct mei_cl *cl;
- long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT);
- int i;
- int err;
- int rets;
-
- cl = file->private_data;
- if (WARN_ON(!cl || !cl->dev))
- return -ENODEV;
-
- dev = cl->dev;
-
- dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n");
-
- /* buffered ioctl cb */
- cb = mei_io_cb_init(cl, file);
- if (!cb) {
- rets = -ENOMEM;
- goto end;
- }
-
- cb->fop_type = MEI_FOP_IOCTL;
-
- if (dev->dev_state != MEI_DEV_ENABLED) {
- rets = -ENODEV;
- goto end;
- }
- if (cl->state != MEI_FILE_INITIALIZING &&
- cl->state != MEI_FILE_DISCONNECTED) {
- rets = -EBUSY;
- goto end;
- }
-
- /* find ME client we're trying to connect to */
- i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
- if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
- cl->me_client_id = dev->me_clients[i].client_id;
- cl->state = MEI_FILE_CONNECTING;
- }
-
- dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
- cl->me_client_id);
- dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
- dev->me_clients[i].props.protocol_version);
- dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
- dev->me_clients[i].props.max_msg_length);
-
- /* if we're connecting to amthi client then we will use the
- * existing connection
- */
- if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) {
- dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
- if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
- rets = -ENODEV;
- goto end;
- }
- clear_bit(cl->host_client_id, dev->host_clients_map);
- mei_me_cl_unlink(dev, cl);
-
- kfree(cl);
- cl = NULL;
- file->private_data = &dev->iamthif_cl;
-
- client = &data->out_client_properties;
- client->max_msg_length =
- dev->me_clients[i].props.max_msg_length;
- client->protocol_version =
- dev->me_clients[i].props.protocol_version;
- rets = dev->iamthif_cl.status;
-
- goto end;
- }
-
- if (cl->state != MEI_FILE_CONNECTING) {
- rets = -ENODEV;
- goto end;
- }
-
-
- /* prepare the output buffer */
- client = &data->out_client_properties;
- client->max_msg_length = dev->me_clients[i].props.max_msg_length;
- client->protocol_version = dev->me_clients[i].props.protocol_version;
- dev_dbg(&dev->pdev->dev, "Can connect?\n");
- if (dev->mei_host_buffer_is_empty
- && !mei_other_client_is_connecting(dev, cl)) {
- dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
- dev->mei_host_buffer_is_empty = false;
- if (mei_connect(dev, cl)) {
- dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
- rets = -ENODEV;
- goto end;
- } else {
- dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n");
- cl->timer_count = MEI_CONNECT_TIMEOUT;
- list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
- }
-
-
- } else {
- dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n");
- dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n");
- list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
- }
- mutex_unlock(&dev->device_lock);
- err = wait_event_timeout(dev->wait_recvd_msg,
- (MEI_FILE_CONNECTED == cl->state ||
- MEI_FILE_DISCONNECTED == cl->state), timeout);
-
- mutex_lock(&dev->device_lock);
- if (MEI_FILE_CONNECTED == cl->state) {
- dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n");
- rets = cl->status;
- goto end;
- } else {
- dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n",
- cl->state);
- if (!err) {
- dev_dbg(&dev->pdev->dev,
- "wait_event_interruptible_timeout failed on client"
- " connect message fw response message.\n");
- }
- rets = -EFAULT;
-
- mei_io_list_flush(&dev->ctrl_rd_list, cl);
- mei_io_list_flush(&dev->ctrl_wr_list, cl);
- goto end;
- }
- rets = 0;
-end:
- dev_dbg(&dev->pdev->dev, "free connect cb memory.");
- mei_io_cb_free(cb);
- return rets;
-}
-
-/**
- * mei_start_read - the start read client message function.
- *
- * @dev: the device structure
- * @if_num: minor number
- * @cl: private data of the file object
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
-{
- struct mei_cl_cb *cb;
- int rets;
- int i;
-
- if (cl->state != MEI_FILE_CONNECTED)
- return -ENODEV;
-
- if (dev->dev_state != MEI_DEV_ENABLED)
- return -ENODEV;
-
- if (cl->read_pending || cl->read_cb) {
- dev_dbg(&dev->pdev->dev, "read is pending.\n");
- return -EBUSY;
- }
- i = mei_me_cl_by_id(dev, cl->me_client_id);
- if (i < 0) {
- dev_err(&dev->pdev->dev, "no such me client %d\n",
- cl->me_client_id);
- return -ENODEV;
- }
-
- cb = mei_io_cb_init(cl, NULL);
- if (!cb)
- return -ENOMEM;
-
- rets = mei_io_cb_alloc_resp_buf(cb,
- dev->me_clients[i].props.max_msg_length);
- if (rets)
- goto err;
-
- cb->fop_type = MEI_FOP_READ;
- cl->read_cb = cb;
- if (dev->mei_host_buffer_is_empty) {
- dev->mei_host_buffer_is_empty = false;
- if (mei_send_flow_control(dev, cl)) {
- rets = -ENODEV;
- goto err;
- }
- list_add_tail(&cb->list, &dev->read_list.list);
- } else {
- list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
- }
- return rets;
-err:
- mei_io_cb_free(cb);
- return rets;
-}
-
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 43fb52ff98ad..903f809b21f7 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -37,79 +37,11 @@
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
-#include "mei_dev.h"
#include <linux/mei.h>
-#include "interface.h"
-
-/* AMT device is a singleton on the platform */
-static struct pci_dev *mei_pdev;
-
-/* mei_pci_tbl - PCI Device ID Table */
-static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)},
-
- /* required last entry */
- {0, }
-};
-
-MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
-static DEFINE_MUTEX(mei_mutex);
-
-
-/**
- * find_read_list_entry - find read list entry
- *
- * @dev: device structure
- * @file: pointer to file structure
- *
- * returns cb on success, NULL on error
- */
-static struct mei_cl_cb *find_read_list_entry(
- struct mei_device *dev,
- struct mei_cl *cl)
-{
- struct mei_cl_cb *pos = NULL;
- struct mei_cl_cb *next = NULL;
-
- dev_dbg(&dev->pdev->dev, "remove read_list CB\n");
- list_for_each_entry_safe(pos, next, &dev->read_list.list, list)
- if (mei_cl_cmp_id(cl, pos->cl))
- return pos;
- return NULL;
-}
+#include "mei_dev.h"
+#include "hw-me.h"
+#include "client.h"
/**
* mei_open - the open function
@@ -121,16 +53,20 @@ static struct mei_cl_cb *find_read_list_entry(
*/
static int mei_open(struct inode *inode, struct file *file)
{
+ struct miscdevice *misc = file->private_data;
+ struct pci_dev *pdev;
struct mei_cl *cl;
struct mei_device *dev;
- unsigned long cl_id;
+
int err;
err = -ENODEV;
- if (!mei_pdev)
+ if (!misc->parent)
goto out;
- dev = pci_get_drvdata(mei_pdev);
+ pdev = container_of(misc->parent, struct pci_dev, dev);
+
+ dev = pci_get_drvdata(pdev);
if (!dev)
goto out;
@@ -153,24 +89,9 @@ static int mei_open(struct inode *inode, struct file *file)
goto out_unlock;
}
- cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
- if (cl_id >= MEI_CLIENTS_MAX) {
- dev_err(&dev->pdev->dev, "client_id exceded %d",
- MEI_CLIENTS_MAX) ;
+ err = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
+ if (err)
goto out_unlock;
- }
-
- cl->host_client_id = cl_id;
-
- dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id);
-
- dev->open_handle_count++;
-
- list_add_tail(&cl->link, &dev->file_list);
-
- set_bit(cl->host_client_id, dev->host_clients_map);
- cl->state = MEI_FILE_INITIALIZING;
- cl->sm_state = 0;
file->private_data = cl;
mutex_unlock(&dev->device_lock);
@@ -216,7 +137,7 @@ static int mei_release(struct inode *inode, struct file *file)
"ME client = %d\n",
cl->host_client_id,
cl->me_client_id);
- rets = mei_disconnect_host_client(dev, cl);
+ rets = mei_cl_disconnect(cl);
}
mei_cl_flush_queues(cl);
dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
@@ -227,12 +148,13 @@ static int mei_release(struct inode *inode, struct file *file)
clear_bit(cl->host_client_id, dev->host_clients_map);
dev->open_handle_count--;
}
- mei_me_cl_unlink(dev, cl);
+ mei_cl_unlink(cl);
+
/* free read cb */
cb = NULL;
if (cl->read_cb) {
- cb = find_read_list_entry(dev, cl);
+ cb = mei_cl_find_read_cb(cl);
/* Remove entry from read list */
if (cb)
list_del(&cb->list);
@@ -322,7 +244,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
goto out;
}
- err = mei_start_read(dev, cl);
+ err = mei_cl_read_start(cl);
if (err && err != -EBUSY) {
dev_dbg(&dev->pdev->dev,
"mei start read failure with status = %d\n", err);
@@ -393,14 +315,13 @@ copy_buffer:
goto out;
free:
- cb_pos = find_read_list_entry(dev, cl);
+ cb_pos = mei_cl_find_read_cb(cl);
/* Remove entry from read list */
if (cb_pos)
list_del(&cb_pos->list);
mei_io_cb_free(cb);
cl->reading_state = MEI_IDLE;
cl->read_cb = NULL;
- cl->read_pending = 0;
out:
dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets);
mutex_unlock(&dev->device_lock);
@@ -475,16 +396,15 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
/* free entry used in read */
if (cl->reading_state == MEI_READ_COMPLETE) {
*offset = 0;
- write_cb = find_read_list_entry(dev, cl);
+ write_cb = mei_cl_find_read_cb(cl);
if (write_cb) {
list_del(&write_cb->list);
mei_io_cb_free(write_cb);
write_cb = NULL;
cl->reading_state = MEI_IDLE;
cl->read_cb = NULL;
- cl->read_pending = 0;
}
- } else if (cl->reading_state == MEI_IDLE && !cl->read_pending)
+ } else if (cl->reading_state == MEI_IDLE)
*offset = 0;
@@ -519,7 +439,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
if (rets) {
dev_err(&dev->pdev->dev,
- "amthi write failed with status = %d\n", rets);
+ "amthif write failed with status = %d\n", rets);
goto err;
}
mutex_unlock(&dev->device_lock);
@@ -530,20 +450,20 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n",
cl->host_client_id, cl->me_client_id);
- rets = mei_flow_ctrl_creds(dev, cl);
+ rets = mei_cl_flow_ctrl_creds(cl);
if (rets < 0)
goto err;
- if (rets == 0 || dev->mei_host_buffer_is_empty == false) {
+ if (rets == 0 || !dev->hbuf_is_ready) {
write_cb->buf_idx = 0;
mei_hdr.msg_complete = 0;
cl->writing_state = MEI_WRITING;
goto out;
}
- dev->mei_host_buffer_is_empty = false;
- if (length > mei_hbuf_max_data(dev)) {
- mei_hdr.length = mei_hbuf_max_data(dev);
+ dev->hbuf_is_ready = false;
+ if (length > mei_hbuf_max_len(dev)) {
+ mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
} else {
mei_hdr.length = length;
@@ -552,10 +472,10 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
mei_hdr.host_addr = cl->host_client_id;
mei_hdr.me_addr = cl->me_client_id;
mei_hdr.reserved = 0;
- dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n",
- *((u32 *) &mei_hdr));
- if (mei_write_message(dev, &mei_hdr,
- write_cb->request_buffer.data, mei_hdr.length)) {
+
+ dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n",
+ MEI_HDR_PRM(&mei_hdr));
+ if (mei_write_message(dev, &mei_hdr, write_cb->request_buffer.data)) {
rets = -ENODEV;
goto err;
}
@@ -564,7 +484,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
out:
if (mei_hdr.msg_complete) {
- if (mei_flow_ctrl_reduce(dev, cl)) {
+ if (mei_cl_flow_ctrl_reduce(cl)) {
rets = -ENODEV;
goto err;
}
@@ -582,6 +502,103 @@ err:
return rets;
}
+/**
+ * mei_ioctl_connect_client - the connect to fw client IOCTL function
+ *
+ * @dev: the device structure
+ * @data: IOCTL connect data, input and output parameters
+ * @file: private data of the file object
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_ioctl_connect_client(struct file *file,
+ struct mei_connect_client_data *data)
+{
+ struct mei_device *dev;
+ struct mei_client *client;
+ struct mei_cl *cl;
+ int i;
+ int rets;
+
+ cl = file->private_data;
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ if (dev->dev_state != MEI_DEV_ENABLED) {
+ rets = -ENODEV;
+ goto end;
+ }
+
+ if (cl->state != MEI_FILE_INITIALIZING &&
+ cl->state != MEI_FILE_DISCONNECTED) {
+ rets = -EBUSY;
+ goto end;
+ }
+
+ /* find ME client we're trying to connect to */
+ i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
+ if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
+ cl->me_client_id = dev->me_clients[i].client_id;
+ cl->state = MEI_FILE_CONNECTING;
+ }
+
+ dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
+ cl->me_client_id);
+ dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
+ dev->me_clients[i].props.protocol_version);
+ dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
+ dev->me_clients[i].props.max_msg_length);
+
+ /* if we're connecting to amthif client then we will use the
+ * existing connection
+ */
+ if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
+ dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
+ if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
+ rets = -ENODEV;
+ goto end;
+ }
+ clear_bit(cl->host_client_id, dev->host_clients_map);
+ mei_cl_unlink(cl);
+
+ kfree(cl);
+ cl = NULL;
+ file->private_data = &dev->iamthif_cl;
+
+ client = &data->out_client_properties;
+ client->max_msg_length =
+ dev->me_clients[i].props.max_msg_length;
+ client->protocol_version =
+ dev->me_clients[i].props.protocol_version;
+ rets = dev->iamthif_cl.status;
+
+ goto end;
+ }
+
+ if (cl->state != MEI_FILE_CONNECTING) {
+ rets = -ENODEV;
+ goto end;
+ }
+
+
+ /* prepare the output buffer */
+ client = &data->out_client_properties;
+ client->max_msg_length = dev->me_clients[i].props.max_msg_length;
+ client->protocol_version = dev->me_clients[i].props.protocol_version;
+ dev_dbg(&dev->pdev->dev, "Can connect?\n");
+
+
+ rets = mei_cl_connect(cl, file);
+
+end:
+ dev_dbg(&dev->pdev->dev, "free connect cb memory.");
+ return rets;
+}
+
/**
* mei_ioctl - the IOCTL function
@@ -630,6 +647,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
rets = -EFAULT;
goto out;
}
+
rets = mei_ioctl_connect_client(file, connect_data);
/* if all is ok, copying the data back to user. */
@@ -726,7 +744,6 @@ static const struct file_operations mei_fops = {
.llseek = no_llseek
};
-
/*
* Misc Device Struct
*/
@@ -736,300 +753,17 @@ static struct miscdevice mei_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
};
-/**
- * mei_quirk_probe - probe for devices that doesn't valid ME interface
- * @pdev: PCI device structure
- * @ent: entry into pci_device_table
- *
- * returns true if ME Interface is valid, false otherwise
- */
-static bool mei_quirk_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+int mei_register(struct device *dev)
{
- u32 reg;
- if (ent->device == MEI_DEV_ID_PBG_1) {
- pci_read_config_dword(pdev, 0x48, &reg);
- /* make sure that bit 9 is up and bit 10 is down */
- if ((reg & 0x600) == 0x200) {
- dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
- return false;
- }
- }
- return true;
-}
-/**
- * mei_probe - Device Initialization Routine
- *
- * @pdev: PCI device structure
- * @ent: entry in kcs_pci_tbl
- *
- * returns 0 on success, <0 on failure.
- */
-static int mei_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct mei_device *dev;
- int err;
-
- mutex_lock(&mei_mutex);
-
- if (!mei_quirk_probe(pdev, ent)) {
- err = -ENODEV;
- goto end;
- }
-
- if (mei_pdev) {
- err = -EEXIST;
- goto end;
- }
- /* enable pci dev */
- err = pci_enable_device(pdev);
- if (err) {
- dev_err(&pdev->dev, "failed to enable pci device.\n");
- goto end;
- }
- /* set PCI host mastering */
- pci_set_master(pdev);
- /* pci request regions for mei driver */
- err = pci_request_regions(pdev, KBUILD_MODNAME);
- if (err) {
- dev_err(&pdev->dev, "failed to get pci regions.\n");
- goto disable_device;
- }
- /* allocates and initializes the mei dev structure */
- dev = mei_device_init(pdev);
- if (!dev) {
- err = -ENOMEM;
- goto release_regions;
- }
- /* mapping IO device memory */
- dev->mem_addr = pci_iomap(pdev, 0, 0);
- if (!dev->mem_addr) {
- dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
- err = -ENOMEM;
- goto free_device;
- }
- pci_enable_msi(pdev);
-
- /* request and enable interrupt */
- if (pci_dev_msi_enabled(pdev))
- err = request_threaded_irq(pdev->irq,
- NULL,
- mei_interrupt_thread_handler,
- IRQF_ONESHOT, KBUILD_MODNAME, dev);
- else
- err = request_threaded_irq(pdev->irq,
- mei_interrupt_quick_handler,
- mei_interrupt_thread_handler,
- IRQF_SHARED, KBUILD_MODNAME, dev);
-
- if (err) {
- dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
- pdev->irq);
- goto disable_msi;
- }
- INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
- INIT_WORK(&dev->init_work, mei_host_client_init);
-
- if (mei_hw_init(dev)) {
- dev_err(&pdev->dev, "init hw failure.\n");
- err = -ENODEV;
- goto release_irq;
- }
-
- err = misc_register(&mei_misc_device);
- if (err)
- goto release_irq;
-
- mei_pdev = pdev;
- pci_set_drvdata(pdev, dev);
-
-
- schedule_delayed_work(&dev->timer_work, HZ);
-
- mutex_unlock(&mei_mutex);
-
- pr_debug("initialization successful.\n");
-
- return 0;
-
-release_irq:
- /* disable interrupts */
- dev->host_hw_state = mei_hcsr_read(dev);
- mei_disable_interrupts(dev);
- flush_scheduled_work();
- free_irq(pdev->irq, dev);
-disable_msi:
- pci_disable_msi(pdev);
- pci_iounmap(pdev, dev->mem_addr);
-free_device:
- kfree(dev);
-release_regions:
- pci_release_regions(pdev);
-disable_device:
- pci_disable_device(pdev);
-end:
- mutex_unlock(&mei_mutex);
- dev_err(&pdev->dev, "initialization failed.\n");
- return err;
+ mei_misc_device.parent = dev;
+ return misc_register(&mei_misc_device);
}
-/**
- * mei_remove - Device Removal Routine
- *
- * @pdev: PCI device structure
- *
- * mei_remove is called by the PCI subsystem to alert the driver
- * that it should release a PCI device.
- */
-static void mei_remove(struct pci_dev *pdev)
+void mei_deregister(void)
{
- struct mei_device *dev;
-
- if (mei_pdev != pdev)
- return;
-
- dev = pci_get_drvdata(pdev);
- if (!dev)
- return;
-
- mutex_lock(&dev->device_lock);
-
- cancel_delayed_work(&dev->timer_work);
-
- mei_wd_stop(dev);
-
- mei_pdev = NULL;
-
- if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
- dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
- mei_disconnect_host_client(dev, &dev->iamthif_cl);
- }
- if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
- dev->wd_cl.state = MEI_FILE_DISCONNECTING;
- mei_disconnect_host_client(dev, &dev->wd_cl);
- }
-
- /* Unregistering watchdog device */
- mei_watchdog_unregister(dev);
-
- /* remove entry if already in list */
- dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
- mei_me_cl_unlink(dev, &dev->wd_cl);
- mei_me_cl_unlink(dev, &dev->iamthif_cl);
-
- dev->iamthif_current_cb = NULL;
- dev->me_clients_num = 0;
-
- mutex_unlock(&dev->device_lock);
-
- flush_scheduled_work();
-
- /* disable interrupts */
- mei_disable_interrupts(dev);
-
- free_irq(pdev->irq, dev);
- pci_disable_msi(pdev);
- pci_set_drvdata(pdev, NULL);
-
- if (dev->mem_addr)
- pci_iounmap(pdev, dev->mem_addr);
-
- kfree(dev);
-
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-
misc_deregister(&mei_misc_device);
-}
-#ifdef CONFIG_PM
-static int mei_pci_suspend(struct device *device)
-{
- struct pci_dev *pdev = to_pci_dev(device);
- struct mei_device *dev = pci_get_drvdata(pdev);
- int err;
-
- if (!dev)
- return -ENODEV;
- mutex_lock(&dev->device_lock);
-
- cancel_delayed_work(&dev->timer_work);
-
- /* Stop watchdog if exists */
- err = mei_wd_stop(dev);
- /* Set new mei state */
- if (dev->dev_state == MEI_DEV_ENABLED ||
- dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
- dev->dev_state = MEI_DEV_POWER_DOWN;
- mei_reset(dev, 0);
- }
- mutex_unlock(&dev->device_lock);
-
- free_irq(pdev->irq, dev);
- pci_disable_msi(pdev);
-
- return err;
+ mei_misc_device.parent = NULL;
}
-static int mei_pci_resume(struct device *device)
-{
- struct pci_dev *pdev = to_pci_dev(device);
- struct mei_device *dev;
- int err;
-
- dev = pci_get_drvdata(pdev);
- if (!dev)
- return -ENODEV;
-
- pci_enable_msi(pdev);
-
- /* request and enable interrupt */
- if (pci_dev_msi_enabled(pdev))
- err = request_threaded_irq(pdev->irq,
- NULL,
- mei_interrupt_thread_handler,
- IRQF_ONESHOT, KBUILD_MODNAME, dev);
- else
- err = request_threaded_irq(pdev->irq,
- mei_interrupt_quick_handler,
- mei_interrupt_thread_handler,
- IRQF_SHARED, KBUILD_MODNAME, dev);
-
- if (err) {
- dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
- pdev->irq);
- return err;
- }
-
- mutex_lock(&dev->device_lock);
- dev->dev_state = MEI_DEV_POWER_UP;
- mei_reset(dev, 1);
- mutex_unlock(&dev->device_lock);
-
- /* Start timer if stopped in suspend */
- schedule_delayed_work(&dev->timer_work, HZ);
-
- return err;
-}
-static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
-#define MEI_PM_OPS (&mei_pm_ops)
-#else
-#define MEI_PM_OPS NULL
-#endif /* CONFIG_PM */
-/*
- * PCI driver structure
- */
-static struct pci_driver mei_driver = {
- .name = KBUILD_MODNAME,
- .id_table = mei_pci_tbl,
- .probe = mei_probe,
- .remove = mei_remove,
- .shutdown = mei_remove,
- .driver.pm = MEI_PM_OPS,
-};
-
-module_pci_driver(mei_driver);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 25da04549d04..cb80166161f0 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -21,7 +21,9 @@
#include <linux/watchdog.h>
#include <linux/poll.h>
#include <linux/mei.h>
+
#include "hw.h"
+#include "hw-me-regs.h"
/*
* watch dog definition
@@ -44,7 +46,7 @@
/*
* AMTHI Client UUID
*/
-extern const uuid_le mei_amthi_guid;
+extern const uuid_le mei_amthif_guid;
/*
* Watchdog Client UUID
@@ -65,12 +67,18 @@ extern const u8 mei_wd_state_independence_msg[3][4];
* Number of File descriptors/handles
* that can be opened to the driver.
*
- * Limit to 253: 256 Total Clients
+ * Limit to 255: 256 Total Clients
* minus internal client for MEI Bus Messags
- * minus internal client for AMTHI
- * minus internal client for Watchdog
*/
-#define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 3)
+#define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 1)
+
+/*
+ * Internal Clients Number
+ */
+#define MEI_HOST_CLIENT_ID_ANY (-1)
+#define MEI_HBM_HOST_CLIENT_ID 0 /* not used, just for documentation */
+#define MEI_WD_HOST_CLIENT_ID 1
+#define MEI_IAMTHIF_HOST_CLIENT_ID 2
/* File state */
@@ -150,6 +158,19 @@ struct mei_message_data {
unsigned char *data;
};
+/**
+ * struct mei_me_client - representation of me (fw) client
+ *
+ * @props - client properties
+ * @client_id - me client id
+ * @mei_flow_ctrl_creds - flow control credits
+ */
+struct mei_me_client {
+ struct mei_client_properties props;
+ u8 client_id;
+ u8 mei_flow_ctrl_creds;
+};
+
struct mei_cl;
@@ -178,7 +199,6 @@ struct mei_cl {
wait_queue_head_t tx_wait;
wait_queue_head_t rx_wait;
wait_queue_head_t wait;
- int read_pending;
int status;
/* ID of client connected */
u8 host_client_id;
@@ -191,10 +211,67 @@ struct mei_cl {
struct mei_cl_cb *read_cb;
};
+/** struct mei_hw_ops
+ *
+ * @host_set_ready - notify FW that host side is ready
+ * @host_is_ready - query for host readiness
+
+ * @hw_is_ready - query if hw is ready
+ * @hw_reset - reset hw
+ * @hw_config - configure hw
+
+ * @intr_clear - clear pending interrupts
+ * @intr_enable - enable interrupts
+ * @intr_disable - disable interrupts
+
+ * @hbuf_free_slots - query for write buffer empty slots
+ * @hbuf_is_ready - query if write buffer is empty
+ * @hbuf_max_len - query for write buffer max len
+
+ * @write - write a message to FW
+
+ * @rdbuf_full_slots - query how many slots are filled
+
+ * @read_hdr - get first 4 bytes (header)
+ * @read - read a buffer from the FW
+ */
+struct mei_hw_ops {
+
+ void (*host_set_ready) (struct mei_device *dev);
+ bool (*host_is_ready) (struct mei_device *dev);
+
+ bool (*hw_is_ready) (struct mei_device *dev);
+ void (*hw_reset) (struct mei_device *dev, bool enable);
+ void (*hw_config) (struct mei_device *dev);
+
+ void (*intr_clear) (struct mei_device *dev);
+ void (*intr_enable) (struct mei_device *dev);
+ void (*intr_disable) (struct mei_device *dev);
+
+ int (*hbuf_free_slots) (struct mei_device *dev);
+ bool (*hbuf_is_ready) (struct mei_device *dev);
+ size_t (*hbuf_max_len) (const struct mei_device *dev);
+
+ int (*write)(struct mei_device *dev,
+ struct mei_msg_hdr *hdr,
+ unsigned char *buf);
+
+ int (*rdbuf_full_slots)(struct mei_device *dev);
+
+ u32 (*read_hdr)(const struct mei_device *dev);
+ int (*read) (struct mei_device *dev,
+ unsigned char *buf, unsigned long len);
+};
+
/**
* struct mei_device - MEI private device struct
- * @hbuf_depth - depth of host(write) buffer
- * @wr_ext_msg - buffer for hbm control responses (set in read cycle)
+
+ * @mem_addr - mem mapped base register address
+
+ * @hbuf_depth - depth of hardware host/write buffer is slots
+ * @hbuf_is_ready - query if the host host/write buffer is ready
+ * @wr_msg - the buffer for hbm control messages
+ * @wr_ext_msg - the buffer for hbm control responses (set in read cycle)
*/
struct mei_device {
struct pci_dev *pdev; /* pointer to pci device struct */
@@ -213,24 +290,14 @@ struct mei_device {
*/
struct list_head file_list;
long open_handle_count;
- /*
- * memory of device
- */
- unsigned int mem_base;
- unsigned int mem_length;
- void __iomem *mem_addr;
+
/*
* lock for the device
*/
struct mutex device_lock; /* device lock */
struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
bool recvd_msg;
- /*
- * hw states of host and fw(ME)
- */
- u32 host_hw_state;
- u32 me_hw_state;
- u8 hbuf_depth;
+
/*
* waiting queue for receive message from FW
*/
@@ -243,11 +310,20 @@ struct mei_device {
enum mei_dev_state dev_state;
enum mei_init_clients_states init_clients_state;
u16 init_clients_timer;
- bool need_reset;
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */
u32 rd_msg_hdr;
- u32 wr_msg_buf[128]; /* used for control messages */
+
+ /* write buffer */
+ u8 hbuf_depth;
+ bool hbuf_is_ready;
+
+ /* used for control messages */
+ struct {
+ struct mei_msg_hdr hdr;
+ unsigned char data[128];
+ } wr_msg;
+
struct {
struct mei_msg_hdr hdr;
unsigned char data[4]; /* All HBM messages are 4 bytes */
@@ -261,7 +337,6 @@ struct mei_device {
u8 me_clients_num;
u8 me_client_presentation_num;
u8 me_client_index;
- bool mei_host_buffer_is_empty;
struct mei_cl wd_cl;
enum mei_wd_states wd_state;
@@ -289,6 +364,9 @@ struct mei_device {
bool iamthif_canceled;
struct work_struct init_work;
+
+ const struct mei_hw_ops *ops;
+ char hw[0] __aligned(sizeof(void *));
};
static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
@@ -300,96 +378,28 @@ static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
/*
* mei init function prototypes
*/
-struct mei_device *mei_device_init(struct pci_dev *pdev);
+void mei_device_init(struct mei_device *dev);
void mei_reset(struct mei_device *dev, int interrupts);
int mei_hw_init(struct mei_device *dev);
-int mei_task_initialize_clients(void *data);
-int mei_initialize_clients(struct mei_device *dev);
-int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl);
-void mei_allocate_me_clients_storage(struct mei_device *dev);
-
-
-int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl,
- const uuid_le *cguid, u8 host_client_id);
-void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl);
-int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid);
-int mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
-
-/*
- * MEI IO Functions
- */
-struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp);
-void mei_io_cb_free(struct mei_cl_cb *priv_cb);
-int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length);
-int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length);
-
-
-/**
- * mei_io_list_init - Sets up a queue list.
- *
- * @list: An instance cl callback structure
- */
-static inline void mei_io_list_init(struct mei_cl_cb *list)
-{
- INIT_LIST_HEAD(&list->list);
-}
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
-
-/*
- * MEI ME Client Functions
- */
-
-struct mei_cl *mei_cl_allocate(struct mei_device *dev);
-void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
-int mei_cl_flush_queues(struct mei_cl *cl);
-/**
- * mei_cl_cmp_id - tells if file private data have same id
- *
- * @fe1: private data of 1. file object
- * @fe2: private data of 2. file object
- *
- * returns true - if ids are the same and not NULL
- */
-static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
- const struct mei_cl *cl2)
-{
- return cl1 && cl2 &&
- (cl1->host_client_id == cl2->host_client_id) &&
- (cl1->me_client_id == cl2->me_client_id);
-}
-
-
-
-/*
- * MEI Host Client Functions
- */
-void mei_host_start_message(struct mei_device *dev);
-void mei_host_enum_clients_message(struct mei_device *dev);
-int mei_host_client_enumerate(struct mei_device *dev);
-void mei_host_client_init(struct work_struct *work);
/*
* MEI interrupt functions prototype
*/
-irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id);
-irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id);
-void mei_timer(struct work_struct *work);
-/*
- * MEI input output function prototype
- */
-int mei_ioctl_connect_client(struct file *file,
- struct mei_connect_client_data *data);
+void mei_timer(struct work_struct *work);
+int mei_irq_read_handler(struct mei_device *dev,
+ struct mei_cl_cb *cmpl_list, s32 *slots);
-int mei_start_read(struct mei_device *dev, struct mei_cl *cl);
+int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list);
+void mei_irq_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb_pos);
/*
* AMTHIF - AMT Host Interface Functions
*/
void mei_amthif_reset_params(struct mei_device *dev);
-void mei_amthif_host_init(struct mei_device *dev);
+int mei_amthif_host_init(struct mei_device *dev);
int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb);
@@ -407,9 +417,6 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
void mei_amthif_run_next_cmd(struct mei_device *dev);
-int mei_amthif_read_message(struct mei_cl_cb *complete_list,
- struct mei_device *dev, struct mei_msg_hdr *mei_hdr);
-
int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list);
@@ -418,92 +425,107 @@ int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
struct mei_device *dev, struct mei_msg_hdr *mei_hdr);
int mei_amthif_irq_read(struct mei_device *dev, s32 *slots);
+
+int mei_wd_send(struct mei_device *dev);
+int mei_wd_stop(struct mei_device *dev);
+int mei_wd_host_init(struct mei_device *dev);
/*
- * Register Access Function
+ * mei_watchdog_register - Registering watchdog interface
+ * once we got connection to the WD Client
+ * @dev - mei device
+ */
+void mei_watchdog_register(struct mei_device *dev);
+/*
+ * mei_watchdog_unregister - Unregistering watchdog interface
+ * @dev - mei device
*/
+void mei_watchdog_unregister(struct mei_device *dev);
-/**
- * mei_reg_read - Reads 32bit data from the mei device
- *
- * @dev: the device structure
- * @offset: offset from which to read the data
- *
- * returns register value (u32)
+/*
+ * Register Access Function
*/
-static inline u32 mei_reg_read(const struct mei_device *dev,
- unsigned long offset)
+
+static inline void mei_hw_config(struct mei_device *dev)
+{
+ dev->ops->hw_config(dev);
+}
+static inline void mei_hw_reset(struct mei_device *dev, bool enable)
{
- return ioread32(dev->mem_addr + offset);
+ dev->ops->hw_reset(dev, enable);
}
-/**
- * mei_reg_write - Writes 32bit data to the mei device
- *
- * @dev: the device structure
- * @offset: offset from which to write the data
- * @value: register value to write (u32)
- */
-static inline void mei_reg_write(const struct mei_device *dev,
- unsigned long offset, u32 value)
+static inline void mei_clear_interrupts(struct mei_device *dev)
{
- iowrite32(value, dev->mem_addr + offset);
+ dev->ops->intr_clear(dev);
}
-/**
- * mei_hcsr_read - Reads 32bit data from the host CSR
- *
- * @dev: the device structure
- *
- * returns the byte read.
- */
-static inline u32 mei_hcsr_read(const struct mei_device *dev)
+static inline void mei_enable_interrupts(struct mei_device *dev)
{
- return mei_reg_read(dev, H_CSR);
+ dev->ops->intr_enable(dev);
}
-/**
- * mei_mecsr_read - Reads 32bit data from the ME CSR
- *
- * @dev: the device structure
- *
- * returns ME_CSR_HA register value (u32)
- */
-static inline u32 mei_mecsr_read(const struct mei_device *dev)
+static inline void mei_disable_interrupts(struct mei_device *dev)
{
- return mei_reg_read(dev, ME_CSR_HA);
+ dev->ops->intr_disable(dev);
}
-/**
- * get_me_cb_rw - Reads 32bit data from the mei ME_CB_RW register
- *
- * @dev: the device structure
- *
- * returns ME_CB_RW register value (u32)
- */
-static inline u32 mei_mecbrw_read(const struct mei_device *dev)
+static inline void mei_host_set_ready(struct mei_device *dev)
{
- return mei_reg_read(dev, ME_CB_RW);
+ dev->ops->host_set_ready(dev);
+}
+static inline bool mei_host_is_ready(struct mei_device *dev)
+{
+ return dev->ops->host_is_ready(dev);
+}
+static inline bool mei_hw_is_ready(struct mei_device *dev)
+{
+ return dev->ops->hw_is_ready(dev);
}
+static inline bool mei_hbuf_is_ready(struct mei_device *dev)
+{
+ return dev->ops->hbuf_is_ready(dev);
+}
-/*
- * mei interface function prototypes
- */
-void mei_hcsr_set(struct mei_device *dev);
-void mei_csr_clear_his(struct mei_device *dev);
+static inline int mei_hbuf_empty_slots(struct mei_device *dev)
+{
+ return dev->ops->hbuf_free_slots(dev);
+}
+
+static inline size_t mei_hbuf_max_len(const struct mei_device *dev)
+{
+ return dev->ops->hbuf_max_len(dev);
+}
-void mei_enable_interrupts(struct mei_device *dev);
-void mei_disable_interrupts(struct mei_device *dev);
+static inline int mei_write_message(struct mei_device *dev,
+ struct mei_msg_hdr *hdr,
+ unsigned char *buf)
+{
+ return dev->ops->write(dev, hdr, buf);
+}
-static inline struct mei_msg_hdr *mei_hbm_hdr(u32 *buf, size_t length)
+static inline u32 mei_read_hdr(const struct mei_device *dev)
{
- struct mei_msg_hdr *hdr = (struct mei_msg_hdr *)buf;
- hdr->host_addr = 0;
- hdr->me_addr = 0;
- hdr->length = length;
- hdr->msg_complete = 1;
- hdr->reserved = 0;
- return hdr;
+ return dev->ops->read_hdr(dev);
}
+static inline void mei_read_slots(struct mei_device *dev,
+ unsigned char *buf, unsigned long len)
+{
+ dev->ops->read(dev, buf, len);
+}
+
+static inline int mei_count_full_read_slots(struct mei_device *dev)
+{
+ return dev->ops->rdbuf_full_slots(dev);
+}
+
+int mei_register(struct device *dev);
+void mei_deregister(void);
+
+#define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d comp=%1d"
+#define MEI_HDR_PRM(hdr) \
+ (hdr)->host_addr, (hdr)->me_addr, \
+ (hdr)->length, (hdr)->msg_complete
+
#endif
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
new file mode 100644
index 000000000000..b40ec0601ab0
--- /dev/null
+++ b/drivers/misc/mei/pci-me.c
@@ -0,0 +1,396 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/aio.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/uuid.h>
+#include <linux/compat.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+#include "hw-me.h"
+#include "client.h"
+
+/* AMT device is a singleton on the platform */
+static struct pci_dev *mei_pdev;
+
+/* mei_pci_tbl - PCI Device ID Table */
+static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)},
+
+ /* required last entry */
+ {0, }
+};
+
+MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
+
+static DEFINE_MUTEX(mei_mutex);
+
+/**
+ * mei_quirk_probe - probe for devices that doesn't valid ME interface
+ * @pdev: PCI device structure
+ * @ent: entry into pci_device_table
+ *
+ * returns true if ME Interface is valid, false otherwise
+ */
+static bool mei_quirk_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ u32 reg;
+ if (ent->device == MEI_DEV_ID_PBG_1) {
+ pci_read_config_dword(pdev, 0x48, &reg);
+ /* make sure that bit 9 is up and bit 10 is down */
+ if ((reg & 0x600) == 0x200) {
+ dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
+ return false;
+ }
+ }
+ return true;
+}
+/**
+ * mei_probe - Device Initialization Routine
+ *
+ * @pdev: PCI device structure
+ * @ent: entry in kcs_pci_tbl
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct mei_device *dev;
+ struct mei_me_hw *hw;
+ int err;
+
+ mutex_lock(&mei_mutex);
+
+ if (!mei_quirk_probe(pdev, ent)) {
+ err = -ENODEV;
+ goto end;
+ }
+
+ if (mei_pdev) {
+ err = -EEXIST;
+ goto end;
+ }
+ /* enable pci dev */
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable pci device.\n");
+ goto end;
+ }
+ /* set PCI host mastering */
+ pci_set_master(pdev);
+ /* pci request regions for mei driver */
+ err = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (err) {
+ dev_err(&pdev->dev, "failed to get pci regions.\n");
+ goto disable_device;
+ }
+ /* allocates and initializes the mei dev structure */
+ dev = mei_me_dev_init(pdev);
+ if (!dev) {
+ err = -ENOMEM;
+ goto release_regions;
+ }
+ hw = to_me_hw(dev);
+ /* mapping IO device memory */
+ hw->mem_addr = pci_iomap(pdev, 0, 0);
+ if (!hw->mem_addr) {
+ dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
+ err = -ENOMEM;
+ goto free_device;
+ }
+ pci_enable_msi(pdev);
+
+ /* request and enable interrupt */
+ if (pci_dev_msi_enabled(pdev))
+ err = request_threaded_irq(pdev->irq,
+ NULL,
+ mei_me_irq_thread_handler,
+ IRQF_ONESHOT, KBUILD_MODNAME, dev);
+ else
+ err = request_threaded_irq(pdev->irq,
+ mei_me_irq_quick_handler,
+ mei_me_irq_thread_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+
+ if (err) {
+ dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
+ pdev->irq);
+ goto disable_msi;
+ }
+
+ if (mei_hw_init(dev)) {
+ dev_err(&pdev->dev, "init hw failure.\n");
+ err = -ENODEV;
+ goto release_irq;
+ }
+
+ err = mei_register(&pdev->dev);
+ if (err)
+ goto release_irq;
+
+ mei_pdev = pdev;
+ pci_set_drvdata(pdev, dev);
+
+
+ schedule_delayed_work(&dev->timer_work, HZ);
+
+ mutex_unlock(&mei_mutex);
+
+ pr_debug("initialization successful.\n");
+
+ return 0;
+
+release_irq:
+ mei_disable_interrupts(dev);
+ flush_scheduled_work();
+ free_irq(pdev->irq, dev);
+disable_msi:
+ pci_disable_msi(pdev);
+ pci_iounmap(pdev, hw->mem_addr);
+free_device:
+ kfree(dev);
+release_regions:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+end:
+ mutex_unlock(&mei_mutex);
+ dev_err(&pdev->dev, "initialization failed.\n");
+ return err;
+}
+
+/**
+ * mei_remove - Device Removal Routine
+ *
+ * @pdev: PCI device structure
+ *
+ * mei_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
+ */
+static void mei_remove(struct pci_dev *pdev)
+{
+ struct mei_device *dev;
+ struct mei_me_hw *hw;
+
+ if (mei_pdev != pdev)
+ return;
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev)
+ return;
+
+ hw = to_me_hw(dev);
+
+ mutex_lock(&dev->device_lock);
+
+ cancel_delayed_work(&dev->timer_work);
+
+ mei_wd_stop(dev);
+
+ mei_pdev = NULL;
+
+ if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
+ dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
+ mei_cl_disconnect(&dev->iamthif_cl);
+ }
+ if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
+ dev->wd_cl.state = MEI_FILE_DISCONNECTING;
+ mei_cl_disconnect(&dev->wd_cl);
+ }
+
+ /* Unregistering watchdog device */
+ mei_watchdog_unregister(dev);
+
+ /* remove entry if already in list */
+ dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
+
+ if (dev->open_handle_count > 0)
+ dev->open_handle_count--;
+ mei_cl_unlink(&dev->wd_cl);
+
+ if (dev->open_handle_count > 0)
+ dev->open_handle_count--;
+ mei_cl_unlink(&dev->iamthif_cl);
+
+ dev->iamthif_current_cb = NULL;
+ dev->me_clients_num = 0;
+
+ mutex_unlock(&dev->device_lock);
+
+ flush_scheduled_work();
+
+ /* disable interrupts */
+ mei_disable_interrupts(dev);
+
+ free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ if (hw->mem_addr)
+ pci_iounmap(pdev, hw->mem_addr);
+
+ kfree(dev);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+
+ mei_deregister();
+
+}
+#ifdef CONFIG_PM
+static int mei_pci_suspend(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct mei_device *dev = pci_get_drvdata(pdev);
+ int err;
+
+ if (!dev)
+ return -ENODEV;
+ mutex_lock(&dev->device_lock);
+
+ cancel_delayed_work(&dev->timer_work);
+
+ /* Stop watchdog if exists */
+ err = mei_wd_stop(dev);
+ /* Set new mei state */
+ if (dev->dev_state == MEI_DEV_ENABLED ||
+ dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
+ dev->dev_state = MEI_DEV_POWER_DOWN;
+ mei_reset(dev, 0);
+ }
+ mutex_unlock(&dev->device_lock);
+
+ free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
+
+ return err;
+}
+
+static int mei_pci_resume(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct mei_device *dev;
+ int err;
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev)
+ return -ENODEV;
+
+ pci_enable_msi(pdev);
+
+ /* request and enable interrupt */
+ if (pci_dev_msi_enabled(pdev))
+ err = request_threaded_irq(pdev->irq,
+ NULL,
+ mei_me_irq_thread_handler,
+ IRQF_ONESHOT, KBUILD_MODNAME, dev);
+ else
+ err = request_threaded_irq(pdev->irq,
+ mei_me_irq_quick_handler,
+ mei_me_irq_thread_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+
+ if (err) {
+ dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
+ pdev->irq);
+ return err;
+ }
+
+ mutex_lock(&dev->device_lock);
+ dev->dev_state = MEI_DEV_POWER_UP;
+ mei_reset(dev, 1);
+ mutex_unlock(&dev->device_lock);
+
+ /* Start timer if stopped in suspend */
+ schedule_delayed_work(&dev->timer_work, HZ);
+
+ return err;
+}
+static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
+#define MEI_PM_OPS (&mei_pm_ops)
+#else
+#define MEI_PM_OPS NULL
+#endif /* CONFIG_PM */
+/*
+ * PCI driver structure
+ */
+static struct pci_driver mei_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = mei_pci_tbl,
+ .probe = mei_probe,
+ .remove = mei_remove,
+ .shutdown = mei_remove,
+ .driver.pm = MEI_PM_OPS,
+};
+
+module_pci_driver(mei_driver);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index 9299a8c29a6f..2413247fc392 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -21,11 +21,13 @@
#include <linux/sched.h>
#include <linux/watchdog.h>
-#include "mei_dev.h"
-#include "hw.h"
-#include "interface.h"
#include <linux/mei.h>
+#include "mei_dev.h"
+#include "hbm.h"
+#include "hw-me.h"
+#include "client.h"
+
static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
@@ -62,30 +64,41 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
*/
int mei_wd_host_init(struct mei_device *dev)
{
- int id;
- mei_cl_init(&dev->wd_cl, dev);
+ struct mei_cl *cl = &dev->wd_cl;
+ int i;
+ int ret;
+
+ mei_cl_init(cl, dev);
- /* look for WD client and connect to it */
- dev->wd_cl.state = MEI_FILE_DISCONNECTED;
dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT;
dev->wd_state = MEI_WD_IDLE;
- /* Connect WD ME client to the host client */
- id = mei_me_cl_link(dev, &dev->wd_cl,
- &mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
- if (id < 0) {
+ /* check for valid client id */
+ i = mei_me_cl_by_uuid(dev, &mei_wd_guid);
+ if (i < 0) {
dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
return -ENOENT;
}
- if (mei_connect(dev, &dev->wd_cl)) {
+ cl->me_client_id = dev->me_clients[i].client_id;
+
+ ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);
+
+ if (ret < 0) {
+ dev_info(&dev->pdev->dev, "wd: failed link client\n");
+ return -ENOENT;
+ }
+
+ cl->state = MEI_FILE_CONNECTING;
+
+ if (mei_hbm_cl_connect_req(dev, cl)) {
dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
- dev->wd_cl.state = MEI_FILE_DISCONNECTED;
- dev->wd_cl.host_client_id = 0;
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->host_client_id = 0;
return -EIO;
}
- dev->wd_cl.timer_count = MEI_CONNECT_TIMEOUT;
+ cl->timer_count = MEI_CONNECT_TIMEOUT;
return 0;
}
@@ -101,22 +114,21 @@ int mei_wd_host_init(struct mei_device *dev)
*/
int mei_wd_send(struct mei_device *dev)
{
- struct mei_msg_hdr *mei_hdr;
+ struct mei_msg_hdr hdr;
- mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
- mei_hdr->host_addr = dev->wd_cl.host_client_id;
- mei_hdr->me_addr = dev->wd_cl.me_client_id;
- mei_hdr->msg_complete = 1;
- mei_hdr->reserved = 0;
+ hdr.host_addr = dev->wd_cl.host_client_id;
+ hdr.me_addr = dev->wd_cl.me_client_id;
+ hdr.msg_complete = 1;
+ hdr.reserved = 0;
if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE))
- mei_hdr->length = MEI_WD_START_MSG_SIZE;
+ hdr.length = MEI_WD_START_MSG_SIZE;
else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
- mei_hdr->length = MEI_WD_STOP_MSG_SIZE;
+ hdr.length = MEI_WD_STOP_MSG_SIZE;
else
return -EINVAL;
- return mei_write_message(dev, mei_hdr, dev->wd_data, mei_hdr->length);
+ return mei_write_message(dev, &hdr, dev->wd_data);
}
/**
@@ -141,16 +153,16 @@ int mei_wd_stop(struct mei_device *dev)
dev->wd_state = MEI_WD_STOPPING;
- ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
+ ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
if (ret < 0)
goto out;
- if (ret && dev->mei_host_buffer_is_empty) {
+ if (ret && dev->hbuf_is_ready) {
ret = 0;
- dev->mei_host_buffer_is_empty = false;
+ dev->hbuf_is_ready = false;
if (!mei_wd_send(dev)) {
- ret = mei_flow_ctrl_reduce(dev, &dev->wd_cl);
+ ret = mei_cl_flow_ctrl_reduce(&dev->wd_cl);
if (ret)
goto out;
} else {
@@ -270,10 +282,9 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
dev->wd_state = MEI_WD_RUNNING;
/* Check if we can send the ping to HW*/
- if (dev->mei_host_buffer_is_empty &&
- mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
+ if (dev->hbuf_is_ready && mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
- dev->mei_host_buffer_is_empty = false;
+ dev->hbuf_is_ready = false;
dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
if (mei_wd_send(dev)) {
@@ -282,9 +293,9 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
goto end;
}
- if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) {
+ if (mei_cl_flow_ctrl_reduce(&dev->wd_cl)) {
dev_err(&dev->pdev->dev,
- "wd: mei_flow_ctrl_reduce() failed.\n");
+ "wd: mei_cl_flow_ctrl_reduce() failed.\n");
ret = -EIO;
goto end;
}
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c
index 492c8cac69ac..44d273c5e19d 100644
--- a/drivers/misc/sgi-gru/grufile.c
+++ b/drivers/misc/sgi-gru/grufile.c
@@ -517,7 +517,7 @@ static int __init gru_init(void)
{
int ret;
- if (!is_uv_system())
+ if (!is_uv_system() || (is_uvx_hub() && !is_uv2_hub()))
return 0;
#if defined CONFIG_IA64
diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig
index abb5de1afce3..f34dcc514730 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 NET && GPIOLIB
+ depends on NET && GPIOLIB && TTY
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 b90a2241d79c..0a1428016350 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -240,7 +240,8 @@ void st_int_recv(void *disc_data,
char *ptr;
struct st_proto_s *proto;
unsigned short payload_len = 0;
- int len = 0, type = 0;
+ int len = 0;
+ unsigned char type = 0;
unsigned char *plen;
struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
unsigned long flags;
diff --git a/drivers/misc/vmw_vmci/Kconfig b/drivers/misc/vmw_vmci/Kconfig
new file mode 100644
index 000000000000..39c2ecadb273
--- /dev/null
+++ b/drivers/misc/vmw_vmci/Kconfig
@@ -0,0 +1,16 @@
+#
+# VMware VMCI device
+#
+
+config VMWARE_VMCI
+ tristate "VMware VMCI Driver"
+ depends on X86 && PCI
+ help
+ This is VMware's Virtual Machine Communication Interface. It enables
+ high-speed communication between host and guest in a virtual
+ environment via the VMCI virtual device.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vmw_vmci.
diff --git a/drivers/misc/vmw_vmci/Makefile b/drivers/misc/vmw_vmci/Makefile
new file mode 100644
index 000000000000..4da9893c3942
--- /dev/null
+++ b/drivers/misc/vmw_vmci/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci.o
+vmw_vmci-y += vmci_context.o vmci_datagram.o vmci_doorbell.o \
+ vmci_driver.o vmci_event.o vmci_guest.o vmci_handle_array.o \
+ vmci_host.o vmci_queue_pair.o vmci_resource.o vmci_route.o
diff --git a/drivers/misc/vmw_vmci/vmci_context.c b/drivers/misc/vmw_vmci/vmci_context.c
new file mode 100644
index 000000000000..f866a4baecb5
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_context.c
@@ -0,0 +1,1214 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+#include <linux/highmem.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "vmci_queue_pair.h"
+#include "vmci_datagram.h"
+#include "vmci_doorbell.h"
+#include "vmci_context.h"
+#include "vmci_driver.h"
+#include "vmci_event.h"
+
+/*
+ * List of current VMCI contexts. Contexts can be added by
+ * vmci_ctx_create() and removed via vmci_ctx_destroy().
+ * These, along with context lookup, are protected by the
+ * list structure's lock.
+ */
+static struct {
+ struct list_head head;
+ spinlock_t lock; /* Spinlock for context list operations */
+} ctx_list = {
+ .head = LIST_HEAD_INIT(ctx_list.head),
+ .lock = __SPIN_LOCK_UNLOCKED(ctx_list.lock),
+};
+
+/* Used by contexts that did not set up notify flag pointers */
+static bool ctx_dummy_notify;
+
+static void ctx_signal_notify(struct vmci_ctx *context)
+{
+ *context->notify = true;
+}
+
+static void ctx_clear_notify(struct vmci_ctx *context)
+{
+ *context->notify = false;
+}
+
+/*
+ * If nothing requires the attention of the guest, clears both
+ * notify flag and call.
+ */
+static void ctx_clear_notify_call(struct vmci_ctx *context)
+{
+ if (context->pending_datagrams == 0 &&
+ vmci_handle_arr_get_size(context->pending_doorbell_array) == 0)
+ ctx_clear_notify(context);
+}
+
+/*
+ * Sets the context's notify flag iff datagrams are pending for this
+ * context. Called from vmci_setup_notify().
+ */
+void vmci_ctx_check_signal_notify(struct vmci_ctx *context)
+{
+ spin_lock(&context->lock);
+ if (context->pending_datagrams)
+ ctx_signal_notify(context);
+ spin_unlock(&context->lock);
+}
+
+/*
+ * Allocates and initializes a VMCI context.
+ */
+struct vmci_ctx *vmci_ctx_create(u32 cid, u32 priv_flags,
+ uintptr_t event_hnd,
+ int user_version,
+ const struct cred *cred)
+{
+ struct vmci_ctx *context;
+ int error;
+
+ if (cid == VMCI_INVALID_ID) {
+ pr_devel("Invalid context ID for VMCI context\n");
+ error = -EINVAL;
+ goto err_out;
+ }
+
+ if (priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS) {
+ pr_devel("Invalid flag (flags=0x%x) for VMCI context\n",
+ priv_flags);
+ error = -EINVAL;
+ goto err_out;
+ }
+
+ if (user_version == 0) {
+ pr_devel("Invalid suer_version %d\n", user_version);
+ error = -EINVAL;
+ goto err_out;
+ }
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context) {
+ pr_warn("Failed to allocate memory for VMCI context\n");
+ error = -EINVAL;
+ goto err_out;
+ }
+
+ kref_init(&context->kref);
+ spin_lock_init(&context->lock);
+ INIT_LIST_HEAD(&context->list_item);
+ INIT_LIST_HEAD(&context->datagram_queue);
+ INIT_LIST_HEAD(&context->notifier_list);
+
+ /* Initialize host-specific VMCI context. */
+ init_waitqueue_head(&context->host_context.wait_queue);
+
+ context->queue_pair_array = vmci_handle_arr_create(0);
+ if (!context->queue_pair_array) {
+ error = -ENOMEM;
+ goto err_free_ctx;
+ }
+
+ context->doorbell_array = vmci_handle_arr_create(0);
+ if (!context->doorbell_array) {
+ error = -ENOMEM;
+ goto err_free_qp_array;
+ }
+
+ context->pending_doorbell_array = vmci_handle_arr_create(0);
+ if (!context->pending_doorbell_array) {
+ error = -ENOMEM;
+ goto err_free_db_array;
+ }
+
+ context->user_version = user_version;
+
+ context->priv_flags = priv_flags;
+
+ if (cred)
+ context->cred = get_cred(cred);
+
+ context->notify = &ctx_dummy_notify;
+ context->notify_page = NULL;
+
+ /*
+ * If we collide with an existing context we generate a new
+ * and use it instead. The VMX will determine if regeneration
+ * is okay. Since there isn't 4B - 16 VMs running on a given
+ * host, the below loop will terminate.
+ */
+ spin_lock(&ctx_list.lock);
+
+ while (vmci_ctx_exists(cid)) {
+ /* We reserve the lowest 16 ids for fixed contexts. */
+ cid = max(cid, VMCI_RESERVED_CID_LIMIT - 1) + 1;
+ if (cid == VMCI_INVALID_ID)
+ cid = VMCI_RESERVED_CID_LIMIT;
+ }
+ context->cid = cid;
+
+ list_add_tail_rcu(&context->list_item, &ctx_list.head);
+ spin_unlock(&ctx_list.lock);
+
+ return context;
+
+ err_free_db_array:
+ vmci_handle_arr_destroy(context->doorbell_array);
+ err_free_qp_array:
+ vmci_handle_arr_destroy(context->queue_pair_array);
+ err_free_ctx:
+ kfree(context);
+ err_out:
+ return ERR_PTR(error);
+}
+
+/*
+ * Destroy VMCI context.
+ */
+void vmci_ctx_destroy(struct vmci_ctx *context)
+{
+ spin_lock(&ctx_list.lock);
+ list_del_rcu(&context->list_item);
+ spin_unlock(&ctx_list.lock);
+ synchronize_rcu();
+
+ vmci_ctx_put(context);
+}
+
+/*
+ * Fire notification for all contexts interested in given cid.
+ */
+static int ctx_fire_notification(u32 context_id, u32 priv_flags)
+{
+ u32 i, array_size;
+ struct vmci_ctx *sub_ctx;
+ struct vmci_handle_arr *subscriber_array;
+ struct vmci_handle context_handle =
+ vmci_make_handle(context_id, VMCI_EVENT_HANDLER);
+
+ /*
+ * We create an array to hold the subscribers we find when
+ * scanning through all contexts.
+ */
+ subscriber_array = vmci_handle_arr_create(0);
+ if (subscriber_array == NULL)
+ return VMCI_ERROR_NO_MEM;
+
+ /*
+ * Scan all contexts to find who is interested in being
+ * notified about given contextID.
+ */
+ rcu_read_lock();
+ list_for_each_entry_rcu(sub_ctx, &ctx_list.head, list_item) {
+ struct vmci_handle_list *node;
+
+ /*
+ * We only deliver notifications of the removal of
+ * contexts, if the two contexts are allowed to
+ * interact.
+ */
+ if (vmci_deny_interaction(priv_flags, sub_ctx->priv_flags))
+ continue;
+
+ list_for_each_entry_rcu(node, &sub_ctx->notifier_list, node) {
+ if (!vmci_handle_is_equal(node->handle, context_handle))
+ continue;
+
+ vmci_handle_arr_append_entry(&subscriber_array,
+ vmci_make_handle(sub_ctx->cid,
+ VMCI_EVENT_HANDLER));
+ }
+ }
+ rcu_read_unlock();
+
+ /* Fire event to all subscribers. */
+ array_size = vmci_handle_arr_get_size(subscriber_array);
+ for (i = 0; i < array_size; i++) {
+ int result;
+ struct vmci_event_ctx ev;
+
+ ev.msg.hdr.dst = vmci_handle_arr_get_entry(subscriber_array, i);
+ ev.msg.hdr.src = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_CONTEXT_RESOURCE_ID);
+ ev.msg.hdr.payload_size = sizeof(ev) - sizeof(ev.msg.hdr);
+ ev.msg.event_data.event = VMCI_EVENT_CTX_REMOVED;
+ ev.payload.context_id = context_id;
+
+ result = vmci_datagram_dispatch(VMCI_HYPERVISOR_CONTEXT_ID,
+ &ev.msg.hdr, false);
+ if (result < VMCI_SUCCESS) {
+ pr_devel("Failed to enqueue event datagram (type=%d) for context (ID=0x%x)\n",
+ ev.msg.event_data.event,
+ ev.msg.hdr.dst.context);
+ /* We continue to enqueue on next subscriber. */
+ }
+ }
+ vmci_handle_arr_destroy(subscriber_array);
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Returns the current number of pending datagrams. The call may
+ * also serve as a synchronization point for the datagram queue,
+ * as no enqueue operations can occur concurrently.
+ */
+int vmci_ctx_pending_datagrams(u32 cid, u32 *pending)
+{
+ struct vmci_ctx *context;
+
+ context = vmci_ctx_get(cid);
+ if (context == NULL)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ spin_lock(&context->lock);
+ if (pending)
+ *pending = context->pending_datagrams;
+ spin_unlock(&context->lock);
+ vmci_ctx_put(context);
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Queues a VMCI datagram for the appropriate target VM context.
+ */
+int vmci_ctx_enqueue_datagram(u32 cid, struct vmci_datagram *dg)
+{
+ struct vmci_datagram_queue_entry *dq_entry;
+ struct vmci_ctx *context;
+ struct vmci_handle dg_src;
+ size_t vmci_dg_size;
+
+ vmci_dg_size = VMCI_DG_SIZE(dg);
+ if (vmci_dg_size > VMCI_MAX_DG_SIZE) {
+ pr_devel("Datagram too large (bytes=%Zu)\n", vmci_dg_size);
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ /* Get the target VM's VMCI context. */
+ context = vmci_ctx_get(cid);
+ if (!context) {
+ pr_devel("Invalid context (ID=0x%x)\n", cid);
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ /* Allocate guest call entry and add it to the target VM's queue. */
+ dq_entry = kmalloc(sizeof(*dq_entry), GFP_KERNEL);
+ if (dq_entry == NULL) {
+ pr_warn("Failed to allocate memory for datagram\n");
+ vmci_ctx_put(context);
+ return VMCI_ERROR_NO_MEM;
+ }
+ dq_entry->dg = dg;
+ dq_entry->dg_size = vmci_dg_size;
+ dg_src = dg->src;
+ INIT_LIST_HEAD(&dq_entry->list_item);
+
+ spin_lock(&context->lock);
+
+ /*
+ * We put a higher limit on datagrams from the hypervisor. If
+ * the pending datagram is not from hypervisor, then we check
+ * if enqueueing it would exceed the
+ * VMCI_MAX_DATAGRAM_QUEUE_SIZE limit on the destination. If
+ * the pending datagram is from hypervisor, we allow it to be
+ * queued at the destination side provided we don't reach the
+ * VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE limit.
+ */
+ if (context->datagram_queue_size + vmci_dg_size >=
+ VMCI_MAX_DATAGRAM_QUEUE_SIZE &&
+ (!vmci_handle_is_equal(dg_src,
+ vmci_make_handle
+ (VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_CONTEXT_RESOURCE_ID)) ||
+ context->datagram_queue_size + vmci_dg_size >=
+ VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE)) {
+ spin_unlock(&context->lock);
+ vmci_ctx_put(context);
+ kfree(dq_entry);
+ pr_devel("Context (ID=0x%x) receive queue is full\n", cid);
+ return VMCI_ERROR_NO_RESOURCES;
+ }
+
+ list_add(&dq_entry->list_item, &context->datagram_queue);
+ context->pending_datagrams++;
+ context->datagram_queue_size += vmci_dg_size;
+ ctx_signal_notify(context);
+ wake_up(&context->host_context.wait_queue);
+ spin_unlock(&context->lock);
+ vmci_ctx_put(context);
+
+ return vmci_dg_size;
+}
+
+/*
+ * Verifies whether a context with the specified context ID exists.
+ * FIXME: utility is dubious as no decisions can be reliably made
+ * using this data as context can appear and disappear at any time.
+ */
+bool vmci_ctx_exists(u32 cid)
+{
+ struct vmci_ctx *context;
+ bool exists = false;
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(context, &ctx_list.head, list_item) {
+ if (context->cid == cid) {
+ exists = true;
+ break;
+ }
+ }
+
+ rcu_read_unlock();
+ return exists;
+}
+
+/*
+ * Retrieves VMCI context corresponding to the given cid.
+ */
+struct vmci_ctx *vmci_ctx_get(u32 cid)
+{
+ struct vmci_ctx *c, *context = NULL;
+
+ if (cid == VMCI_INVALID_ID)
+ return NULL;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(c, &ctx_list.head, list_item) {
+ if (c->cid == cid) {
+ /*
+ * The context owner drops its own reference to the
+ * context only after removing it from the list and
+ * waiting for RCU grace period to expire. This
+ * means that we are not about to increase the
+ * reference count of something that is in the
+ * process of being destroyed.
+ */
+ context = c;
+ kref_get(&context->kref);
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return context;
+}
+
+/*
+ * Deallocates all parts of a context data structure. This
+ * function doesn't lock the context, because it assumes that
+ * the caller was holding the last reference to context.
+ */
+static void ctx_free_ctx(struct kref *kref)
+{
+ struct vmci_ctx *context = container_of(kref, struct vmci_ctx, kref);
+ struct vmci_datagram_queue_entry *dq_entry, *dq_entry_tmp;
+ struct vmci_handle temp_handle;
+ struct vmci_handle_list *notifier, *tmp;
+
+ /*
+ * Fire event to all contexts interested in knowing this
+ * context is dying.
+ */
+ ctx_fire_notification(context->cid, context->priv_flags);
+
+ /*
+ * Cleanup all queue pair resources attached to context. If
+ * the VM dies without cleaning up, this code will make sure
+ * that no resources are leaked.
+ */
+ temp_handle = vmci_handle_arr_get_entry(context->queue_pair_array, 0);
+ while (!vmci_handle_is_equal(temp_handle, VMCI_INVALID_HANDLE)) {
+ if (vmci_qp_broker_detach(temp_handle,
+ context) < VMCI_SUCCESS) {
+ /*
+ * When vmci_qp_broker_detach() succeeds it
+ * removes the handle from the array. If
+ * detach fails, we must remove the handle
+ * ourselves.
+ */
+ vmci_handle_arr_remove_entry(context->queue_pair_array,
+ temp_handle);
+ }
+ temp_handle =
+ vmci_handle_arr_get_entry(context->queue_pair_array, 0);
+ }
+
+ /*
+ * It is fine to destroy this without locking the callQueue, as
+ * this is the only thread having a reference to the context.
+ */
+ list_for_each_entry_safe(dq_entry, dq_entry_tmp,
+ &context->datagram_queue, list_item) {
+ WARN_ON(dq_entry->dg_size != VMCI_DG_SIZE(dq_entry->dg));
+ list_del(&dq_entry->list_item);
+ kfree(dq_entry->dg);
+ kfree(dq_entry);
+ }
+
+ list_for_each_entry_safe(notifier, tmp,
+ &context->notifier_list, node) {
+ list_del(&notifier->node);
+ kfree(notifier);
+ }
+
+ vmci_handle_arr_destroy(context->queue_pair_array);
+ vmci_handle_arr_destroy(context->doorbell_array);
+ vmci_handle_arr_destroy(context->pending_doorbell_array);
+ vmci_ctx_unset_notify(context);
+ if (context->cred)
+ put_cred(context->cred);
+ kfree(context);
+}
+
+/*
+ * Drops reference to VMCI context. If this is the last reference to
+ * the context it will be deallocated. A context is created with
+ * a reference count of one, and on destroy, it is removed from
+ * the context list before its reference count is decremented. Thus,
+ * if we reach zero, we are sure that nobody else are about to increment
+ * it (they need the entry in the context list for that), and so there
+ * is no need for locking.
+ */
+void vmci_ctx_put(struct vmci_ctx *context)
+{
+ kref_put(&context->kref, ctx_free_ctx);
+}
+
+/*
+ * Dequeues the next datagram and returns it to caller.
+ * The caller passes in a pointer to the max size datagram
+ * it can handle and the datagram is only unqueued if the
+ * size is less than max_size. If larger max_size is set to
+ * the size of the datagram to give the caller a chance to
+ * set up a larger buffer for the guestcall.
+ */
+int vmci_ctx_dequeue_datagram(struct vmci_ctx *context,
+ size_t *max_size,
+ struct vmci_datagram **dg)
+{
+ struct vmci_datagram_queue_entry *dq_entry;
+ struct list_head *list_item;
+ int rv;
+
+ /* Dequeue the next datagram entry. */
+ spin_lock(&context->lock);
+ if (context->pending_datagrams == 0) {
+ ctx_clear_notify_call(context);
+ spin_unlock(&context->lock);
+ pr_devel("No datagrams pending\n");
+ return VMCI_ERROR_NO_MORE_DATAGRAMS;
+ }
+
+ list_item = context->datagram_queue.next;
+
+ dq_entry =
+ list_entry(list_item, struct vmci_datagram_queue_entry, list_item);
+
+ /* Check size of caller's buffer. */
+ if (*max_size < dq_entry->dg_size) {
+ *max_size = dq_entry->dg_size;
+ spin_unlock(&context->lock);
+ pr_devel("Caller's buffer should be at least (size=%u bytes)\n",
+ (u32) *max_size);
+ return VMCI_ERROR_NO_MEM;
+ }
+
+ list_del(list_item);
+ context->pending_datagrams--;
+ context->datagram_queue_size -= dq_entry->dg_size;
+ if (context->pending_datagrams == 0) {
+ ctx_clear_notify_call(context);
+ rv = VMCI_SUCCESS;
+ } else {
+ /*
+ * Return the size of the next datagram.
+ */
+ struct vmci_datagram_queue_entry *next_entry;
+
+ list_item = context->datagram_queue.next;
+ next_entry =
+ list_entry(list_item, struct vmci_datagram_queue_entry,
+ list_item);
+
+ /*
+ * The following size_t -> int truncation is fine as
+ * the maximum size of a (routable) datagram is 68KB.
+ */
+ rv = (int)next_entry->dg_size;
+ }
+ spin_unlock(&context->lock);
+
+ /* Caller must free datagram. */
+ *dg = dq_entry->dg;
+ dq_entry->dg = NULL;
+ kfree(dq_entry);
+
+ return rv;
+}
+
+/*
+ * Reverts actions set up by vmci_setup_notify(). Unmaps and unlocks the
+ * page mapped/locked by vmci_setup_notify().
+ */
+void vmci_ctx_unset_notify(struct vmci_ctx *context)
+{
+ struct page *notify_page;
+
+ spin_lock(&context->lock);
+
+ notify_page = context->notify_page;
+ context->notify = &ctx_dummy_notify;
+ context->notify_page = NULL;
+
+ spin_unlock(&context->lock);
+
+ if (notify_page) {
+ kunmap(notify_page);
+ put_page(notify_page);
+ }
+}
+
+/*
+ * Add remote_cid to list of contexts current contexts wants
+ * notifications from/about.
+ */
+int vmci_ctx_add_notification(u32 context_id, u32 remote_cid)
+{
+ struct vmci_ctx *context;
+ struct vmci_handle_list *notifier, *n;
+ int result;
+ bool exists = false;
+
+ context = vmci_ctx_get(context_id);
+ if (!context)
+ return VMCI_ERROR_NOT_FOUND;
+
+ if (VMCI_CONTEXT_IS_VM(context_id) && VMCI_CONTEXT_IS_VM(remote_cid)) {
+ pr_devel("Context removed notifications for other VMs not supported (src=0x%x, remote=0x%x)\n",
+ context_id, remote_cid);
+ result = VMCI_ERROR_DST_UNREACHABLE;
+ goto out;
+ }
+
+ if (context->priv_flags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
+ result = VMCI_ERROR_NO_ACCESS;
+ goto out;
+ }
+
+ notifier = kmalloc(sizeof(struct vmci_handle_list), GFP_KERNEL);
+ if (!notifier) {
+ result = VMCI_ERROR_NO_MEM;
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&notifier->node);
+ notifier->handle = vmci_make_handle(remote_cid, VMCI_EVENT_HANDLER);
+
+ spin_lock(&context->lock);
+
+ list_for_each_entry(n, &context->notifier_list, node) {
+ if (vmci_handle_is_equal(n->handle, notifier->handle)) {
+ exists = true;
+ break;
+ }
+ }
+
+ if (exists) {
+ kfree(notifier);
+ result = VMCI_ERROR_ALREADY_EXISTS;
+ } else {
+ list_add_tail_rcu(&notifier->node, &context->notifier_list);
+ context->n_notifiers++;
+ result = VMCI_SUCCESS;
+ }
+
+ spin_unlock(&context->lock);
+
+ out:
+ vmci_ctx_put(context);
+ return result;
+}
+
+/*
+ * Remove remote_cid from current context's list of contexts it is
+ * interested in getting notifications from/about.
+ */
+int vmci_ctx_remove_notification(u32 context_id, u32 remote_cid)
+{
+ struct vmci_ctx *context;
+ struct vmci_handle_list *notifier, *tmp;
+ struct vmci_handle handle;
+ bool found = false;
+
+ context = vmci_ctx_get(context_id);
+ if (!context)
+ return VMCI_ERROR_NOT_FOUND;
+
+ handle = vmci_make_handle(remote_cid, VMCI_EVENT_HANDLER);
+
+ spin_lock(&context->lock);
+ list_for_each_entry_safe(notifier, tmp,
+ &context->notifier_list, node) {
+ if (vmci_handle_is_equal(notifier->handle, handle)) {
+ list_del_rcu(&notifier->node);
+ context->n_notifiers--;
+ found = true;
+ break;
+ }
+ }
+ spin_unlock(&context->lock);
+
+ if (found) {
+ synchronize_rcu();
+ kfree(notifier);
+ }
+
+ vmci_ctx_put(context);
+
+ return found ? VMCI_SUCCESS : VMCI_ERROR_NOT_FOUND;
+}
+
+static int vmci_ctx_get_chkpt_notifiers(struct vmci_ctx *context,
+ u32 *buf_size, void **pbuf)
+{
+ u32 *notifiers;
+ size_t data_size;
+ struct vmci_handle_list *entry;
+ int i = 0;
+
+ if (context->n_notifiers == 0) {
+ *buf_size = 0;
+ *pbuf = NULL;
+ return VMCI_SUCCESS;
+ }
+
+ data_size = context->n_notifiers * sizeof(*notifiers);
+ if (*buf_size < data_size) {
+ *buf_size = data_size;
+ return VMCI_ERROR_MORE_DATA;
+ }
+
+ notifiers = kmalloc(data_size, GFP_ATOMIC); /* FIXME: want GFP_KERNEL */
+ if (!notifiers)
+ return VMCI_ERROR_NO_MEM;
+
+ list_for_each_entry(entry, &context->notifier_list, node)
+ notifiers[i++] = entry->handle.context;
+
+ *buf_size = data_size;
+ *pbuf = notifiers;
+ return VMCI_SUCCESS;
+}
+
+static int vmci_ctx_get_chkpt_doorbells(struct vmci_ctx *context,
+ u32 *buf_size, void **pbuf)
+{
+ struct dbell_cpt_state *dbells;
+ size_t n_doorbells;
+ int i;
+
+ n_doorbells = vmci_handle_arr_get_size(context->doorbell_array);
+ if (n_doorbells > 0) {
+ size_t data_size = n_doorbells * sizeof(*dbells);
+ if (*buf_size < data_size) {
+ *buf_size = data_size;
+ return VMCI_ERROR_MORE_DATA;
+ }
+
+ dbells = kmalloc(data_size, GFP_ATOMIC);
+ if (!dbells)
+ return VMCI_ERROR_NO_MEM;
+
+ for (i = 0; i < n_doorbells; i++)
+ dbells[i].handle = vmci_handle_arr_get_entry(
+ context->doorbell_array, i);
+
+ *buf_size = data_size;
+ *pbuf = dbells;
+ } else {
+ *buf_size = 0;
+ *pbuf = NULL;
+ }
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Get current context's checkpoint state of given type.
+ */
+int vmci_ctx_get_chkpt_state(u32 context_id,
+ u32 cpt_type,
+ u32 *buf_size,
+ void **pbuf)
+{
+ struct vmci_ctx *context;
+ int result;
+
+ context = vmci_ctx_get(context_id);
+ if (!context)
+ return VMCI_ERROR_NOT_FOUND;
+
+ spin_lock(&context->lock);
+
+ switch (cpt_type) {
+ case VMCI_NOTIFICATION_CPT_STATE:
+ result = vmci_ctx_get_chkpt_notifiers(context, buf_size, pbuf);
+ break;
+
+ case VMCI_WELLKNOWN_CPT_STATE:
+ /*
+ * For compatibility with VMX'en with VM to VM communication, we
+ * always return zero wellknown handles.
+ */
+
+ *buf_size = 0;
+ *pbuf = NULL;
+ result = VMCI_SUCCESS;
+ break;
+
+ case VMCI_DOORBELL_CPT_STATE:
+ result = vmci_ctx_get_chkpt_doorbells(context, buf_size, pbuf);
+ break;
+
+ default:
+ pr_devel("Invalid cpt state (type=%d)\n", cpt_type);
+ result = VMCI_ERROR_INVALID_ARGS;
+ break;
+ }
+
+ spin_unlock(&context->lock);
+ vmci_ctx_put(context);
+
+ return result;
+}
+
+/*
+ * Set current context's checkpoint state of given type.
+ */
+int vmci_ctx_set_chkpt_state(u32 context_id,
+ u32 cpt_type,
+ u32 buf_size,
+ void *cpt_buf)
+{
+ u32 i;
+ u32 current_id;
+ int result = VMCI_SUCCESS;
+ u32 num_ids = buf_size / sizeof(u32);
+
+ if (cpt_type == VMCI_WELLKNOWN_CPT_STATE && num_ids > 0) {
+ /*
+ * We would end up here if VMX with VM to VM communication
+ * attempts to restore a checkpoint with wellknown handles.
+ */
+ pr_warn("Attempt to restore checkpoint with obsolete wellknown handles\n");
+ return VMCI_ERROR_OBSOLETE;
+ }
+
+ if (cpt_type != VMCI_NOTIFICATION_CPT_STATE) {
+ pr_devel("Invalid cpt state (type=%d)\n", cpt_type);
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ for (i = 0; i < num_ids && result == VMCI_SUCCESS; i++) {
+ current_id = ((u32 *)cpt_buf)[i];
+ result = vmci_ctx_add_notification(context_id, current_id);
+ if (result != VMCI_SUCCESS)
+ break;
+ }
+ if (result != VMCI_SUCCESS)
+ pr_devel("Failed to set cpt state (type=%d) (error=%d)\n",
+ cpt_type, result);
+
+ return result;
+}
+
+/*
+ * Retrieves the specified context's pending notifications in the
+ * form of a handle array. The handle arrays returned are the
+ * actual data - not a copy and should not be modified by the
+ * caller. They must be released using
+ * vmci_ctx_rcv_notifications_release.
+ */
+int vmci_ctx_rcv_notifications_get(u32 context_id,
+ struct vmci_handle_arr **db_handle_array,
+ struct vmci_handle_arr **qp_handle_array)
+{
+ struct vmci_ctx *context;
+ int result = VMCI_SUCCESS;
+
+ context = vmci_ctx_get(context_id);
+ if (context == NULL)
+ return VMCI_ERROR_NOT_FOUND;
+
+ spin_lock(&context->lock);
+
+ *db_handle_array = context->pending_doorbell_array;
+ context->pending_doorbell_array = vmci_handle_arr_create(0);
+ if (!context->pending_doorbell_array) {
+ context->pending_doorbell_array = *db_handle_array;
+ *db_handle_array = NULL;
+ result = VMCI_ERROR_NO_MEM;
+ }
+ *qp_handle_array = NULL;
+
+ spin_unlock(&context->lock);
+ vmci_ctx_put(context);
+
+ return result;
+}
+
+/*
+ * Releases handle arrays with pending notifications previously
+ * retrieved using vmci_ctx_rcv_notifications_get. If the
+ * notifications were not successfully handed over to the guest,
+ * success must be false.
+ */
+void vmci_ctx_rcv_notifications_release(u32 context_id,
+ struct vmci_handle_arr *db_handle_array,
+ struct vmci_handle_arr *qp_handle_array,
+ bool success)
+{
+ struct vmci_ctx *context = vmci_ctx_get(context_id);
+
+ spin_lock(&context->lock);
+ if (!success) {
+ struct vmci_handle handle;
+
+ /*
+ * New notifications may have been added while we were not
+ * holding the context lock, so we transfer any new pending
+ * doorbell notifications to the old array, and reinstate the
+ * old array.
+ */
+
+ handle = vmci_handle_arr_remove_tail(
+ context->pending_doorbell_array);
+ while (!vmci_handle_is_invalid(handle)) {
+ if (!vmci_handle_arr_has_entry(db_handle_array,
+ handle)) {
+ vmci_handle_arr_append_entry(
+ &db_handle_array, handle);
+ }
+ handle = vmci_handle_arr_remove_tail(
+ context->pending_doorbell_array);
+ }
+ vmci_handle_arr_destroy(context->pending_doorbell_array);
+ context->pending_doorbell_array = db_handle_array;
+ db_handle_array = NULL;
+ } else {
+ ctx_clear_notify_call(context);
+ }
+ spin_unlock(&context->lock);
+ vmci_ctx_put(context);
+
+ if (db_handle_array)
+ vmci_handle_arr_destroy(db_handle_array);
+
+ if (qp_handle_array)
+ vmci_handle_arr_destroy(qp_handle_array);
+}
+
+/*
+ * Registers that a new doorbell handle has been allocated by the
+ * context. Only doorbell handles registered can be notified.
+ */
+int vmci_ctx_dbell_create(u32 context_id, struct vmci_handle handle)
+{
+ struct vmci_ctx *context;
+ int result;
+
+ if (context_id == VMCI_INVALID_ID || vmci_handle_is_invalid(handle))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ context = vmci_ctx_get(context_id);
+ if (context == NULL)
+ return VMCI_ERROR_NOT_FOUND;
+
+ spin_lock(&context->lock);
+ if (!vmci_handle_arr_has_entry(context->doorbell_array, handle)) {
+ vmci_handle_arr_append_entry(&context->doorbell_array, handle);
+ result = VMCI_SUCCESS;
+ } else {
+ result = VMCI_ERROR_DUPLICATE_ENTRY;
+ }
+
+ spin_unlock(&context->lock);
+ vmci_ctx_put(context);
+
+ return result;
+}
+
+/*
+ * Unregisters a doorbell handle that was previously registered
+ * with vmci_ctx_dbell_create.
+ */
+int vmci_ctx_dbell_destroy(u32 context_id, struct vmci_handle handle)
+{
+ struct vmci_ctx *context;
+ struct vmci_handle removed_handle;
+
+ if (context_id == VMCI_INVALID_ID || vmci_handle_is_invalid(handle))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ context = vmci_ctx_get(context_id);
+ if (context == NULL)
+ return VMCI_ERROR_NOT_FOUND;
+
+ spin_lock(&context->lock);
+ removed_handle =
+ vmci_handle_arr_remove_entry(context->doorbell_array, handle);
+ vmci_handle_arr_remove_entry(context->pending_doorbell_array, handle);
+ spin_unlock(&context->lock);
+
+ vmci_ctx_put(context);
+
+ return vmci_handle_is_invalid(removed_handle) ?
+ VMCI_ERROR_NOT_FOUND : VMCI_SUCCESS;
+}
+
+/*
+ * Unregisters all doorbell handles that were previously
+ * registered with vmci_ctx_dbell_create.
+ */
+int vmci_ctx_dbell_destroy_all(u32 context_id)
+{
+ struct vmci_ctx *context;
+ struct vmci_handle handle;
+
+ if (context_id == VMCI_INVALID_ID)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ context = vmci_ctx_get(context_id);
+ if (context == NULL)
+ return VMCI_ERROR_NOT_FOUND;
+
+ spin_lock(&context->lock);
+ do {
+ struct vmci_handle_arr *arr = context->doorbell_array;
+ handle = vmci_handle_arr_remove_tail(arr);
+ } while (!vmci_handle_is_invalid(handle));
+ do {
+ struct vmci_handle_arr *arr = context->pending_doorbell_array;
+ handle = vmci_handle_arr_remove_tail(arr);
+ } while (!vmci_handle_is_invalid(handle));
+ spin_unlock(&context->lock);
+
+ vmci_ctx_put(context);
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Registers a notification of a doorbell handle initiated by the
+ * specified source context. The notification of doorbells are
+ * subject to the same isolation rules as datagram delivery. To
+ * allow host side senders of notifications a finer granularity
+ * of sender rights than those assigned to the sending context
+ * itself, the host context is required to specify a different
+ * set of privilege flags that will override the privileges of
+ * the source context.
+ */
+int vmci_ctx_notify_dbell(u32 src_cid,
+ struct vmci_handle handle,
+ u32 src_priv_flags)
+{
+ struct vmci_ctx *dst_context;
+ int result;
+
+ if (vmci_handle_is_invalid(handle))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ /* Get the target VM's VMCI context. */
+ dst_context = vmci_ctx_get(handle.context);
+ if (!dst_context) {
+ pr_devel("Invalid context (ID=0x%x)\n", handle.context);
+ return VMCI_ERROR_NOT_FOUND;
+ }
+
+ if (src_cid != handle.context) {
+ u32 dst_priv_flags;
+
+ if (VMCI_CONTEXT_IS_VM(src_cid) &&
+ VMCI_CONTEXT_IS_VM(handle.context)) {
+ pr_devel("Doorbell notification from VM to VM not supported (src=0x%x, dst=0x%x)\n",
+ src_cid, handle.context);
+ result = VMCI_ERROR_DST_UNREACHABLE;
+ goto out;
+ }
+
+ result = vmci_dbell_get_priv_flags(handle, &dst_priv_flags);
+ if (result < VMCI_SUCCESS) {
+ pr_warn("Failed to get privilege flags for destination (handle=0x%x:0x%x)\n",
+ handle.context, handle.resource);
+ goto out;
+ }
+
+ if (src_cid != VMCI_HOST_CONTEXT_ID ||
+ src_priv_flags == VMCI_NO_PRIVILEGE_FLAGS) {
+ src_priv_flags = vmci_context_get_priv_flags(src_cid);
+ }
+
+ if (vmci_deny_interaction(src_priv_flags, dst_priv_flags)) {
+ result = VMCI_ERROR_NO_ACCESS;
+ goto out;
+ }
+ }
+
+ if (handle.context == VMCI_HOST_CONTEXT_ID) {
+ result = vmci_dbell_host_context_notify(src_cid, handle);
+ } else {
+ spin_lock(&dst_context->lock);
+
+ if (!vmci_handle_arr_has_entry(dst_context->doorbell_array,
+ handle)) {
+ result = VMCI_ERROR_NOT_FOUND;
+ } else {
+ if (!vmci_handle_arr_has_entry(
+ dst_context->pending_doorbell_array,
+ handle)) {
+ vmci_handle_arr_append_entry(
+ &dst_context->pending_doorbell_array,
+ handle);
+
+ ctx_signal_notify(dst_context);
+ wake_up(&dst_context->host_context.wait_queue);
+
+ }
+ result = VMCI_SUCCESS;
+ }
+ spin_unlock(&dst_context->lock);
+ }
+
+ out:
+ vmci_ctx_put(dst_context);
+
+ return result;
+}
+
+bool vmci_ctx_supports_host_qp(struct vmci_ctx *context)
+{
+ return context && context->user_version >= VMCI_VERSION_HOSTQP;
+}
+
+/*
+ * Registers that a new queue pair handle has been allocated by
+ * the context.
+ */
+int vmci_ctx_qp_create(struct vmci_ctx *context, struct vmci_handle handle)
+{
+ int result;
+
+ if (context == NULL || vmci_handle_is_invalid(handle))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle)) {
+ vmci_handle_arr_append_entry(&context->queue_pair_array,
+ handle);
+ result = VMCI_SUCCESS;
+ } else {
+ result = VMCI_ERROR_DUPLICATE_ENTRY;
+ }
+
+ return result;
+}
+
+/*
+ * Unregisters a queue pair handle that was previously registered
+ * with vmci_ctx_qp_create.
+ */
+int vmci_ctx_qp_destroy(struct vmci_ctx *context, struct vmci_handle handle)
+{
+ struct vmci_handle hndl;
+
+ if (context == NULL || vmci_handle_is_invalid(handle))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ hndl = vmci_handle_arr_remove_entry(context->queue_pair_array, handle);
+
+ return vmci_handle_is_invalid(hndl) ?
+ VMCI_ERROR_NOT_FOUND : VMCI_SUCCESS;
+}
+
+/*
+ * Determines whether a given queue pair handle is registered
+ * with the given context.
+ */
+bool vmci_ctx_qp_exists(struct vmci_ctx *context, struct vmci_handle handle)
+{
+ if (context == NULL || vmci_handle_is_invalid(handle))
+ return false;
+
+ return vmci_handle_arr_has_entry(context->queue_pair_array, handle);
+}
+
+/*
+ * vmci_context_get_priv_flags() - Retrieve privilege flags.
+ * @context_id: The context ID of the VMCI context.
+ *
+ * Retrieves privilege flags of the given VMCI context ID.
+ */
+u32 vmci_context_get_priv_flags(u32 context_id)
+{
+ if (vmci_host_code_active()) {
+ u32 flags;
+ struct vmci_ctx *context;
+
+ context = vmci_ctx_get(context_id);
+ if (!context)
+ return VMCI_LEAST_PRIVILEGE_FLAGS;
+
+ flags = context->priv_flags;
+ vmci_ctx_put(context);
+ return flags;
+ }
+ return VMCI_NO_PRIVILEGE_FLAGS;
+}
+EXPORT_SYMBOL_GPL(vmci_context_get_priv_flags);
+
+/*
+ * vmci_is_context_owner() - Determimnes if user is the context owner
+ * @context_id: The context ID of the VMCI context.
+ * @uid: The host user id (real kernel value).
+ *
+ * Determines whether a given UID is the owner of given VMCI context.
+ */
+bool vmci_is_context_owner(u32 context_id, kuid_t uid)
+{
+ bool is_owner = false;
+
+ if (vmci_host_code_active()) {
+ struct vmci_ctx *context = vmci_ctx_get(context_id);
+ if (context) {
+ if (context->cred)
+ is_owner = uid_eq(context->cred->uid, uid);
+ vmci_ctx_put(context);
+ }
+ }
+
+ return is_owner;
+}
+EXPORT_SYMBOL_GPL(vmci_is_context_owner);
diff --git a/drivers/misc/vmw_vmci/vmci_context.h b/drivers/misc/vmw_vmci/vmci_context.h
new file mode 100644
index 000000000000..24a88e68a1e6
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_context.h
@@ -0,0 +1,182 @@
+/*
+ * VMware VMCI driver (vmciContext.h)
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _VMCI_CONTEXT_H_
+#define _VMCI_CONTEXT_H_
+
+#include <linux/vmw_vmci_defs.h>
+#include <linux/atomic.h>
+#include <linux/kref.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include "vmci_handle_array.h"
+#include "vmci_datagram.h"
+
+/* Used to determine what checkpoint state to get and set. */
+enum {
+ VMCI_NOTIFICATION_CPT_STATE = 1,
+ VMCI_WELLKNOWN_CPT_STATE = 2,
+ VMCI_DG_OUT_STATE = 3,
+ VMCI_DG_IN_STATE = 4,
+ VMCI_DG_IN_SIZE_STATE = 5,
+ VMCI_DOORBELL_CPT_STATE = 6,
+};
+
+/* Host specific struct used for signalling */
+struct vmci_host {
+ wait_queue_head_t wait_queue;
+};
+
+struct vmci_handle_list {
+ struct list_head node;
+ struct vmci_handle handle;
+};
+
+struct vmci_ctx {
+ struct list_head list_item; /* For global VMCI list. */
+ u32 cid;
+ struct kref kref;
+ struct list_head datagram_queue; /* Head of per VM queue. */
+ u32 pending_datagrams;
+ size_t datagram_queue_size; /* Size of datagram queue in bytes. */
+
+ /*
+ * Version of the code that created
+ * this context; e.g., VMX.
+ */
+ int user_version;
+ spinlock_t lock; /* Locks callQueue and handle_arrays. */
+
+ /*
+ * queue_pairs attached to. The array of
+ * handles for queue pairs is accessed
+ * from the code for QP API, and there
+ * it is protected by the QP lock. It
+ * is also accessed from the context
+ * clean up path, which does not
+ * require a lock. VMCILock is not
+ * used to protect the QP array field.
+ */
+ struct vmci_handle_arr *queue_pair_array;
+
+ /* Doorbells created by context. */
+ struct vmci_handle_arr *doorbell_array;
+
+ /* Doorbells pending for context. */
+ struct vmci_handle_arr *pending_doorbell_array;
+
+ /* Contexts current context is subscribing to. */
+ struct list_head notifier_list;
+ unsigned int n_notifiers;
+
+ struct vmci_host host_context;
+ u32 priv_flags;
+
+ const struct cred *cred;
+ bool *notify; /* Notify flag pointer - hosted only. */
+ struct page *notify_page; /* Page backing the notify UVA. */
+};
+
+/* VMCINotifyAddRemoveInfo: Used to add/remove remote context notifications. */
+struct vmci_ctx_info {
+ u32 remote_cid;
+ int result;
+};
+
+/* VMCICptBufInfo: Used to set/get current context's checkpoint state. */
+struct vmci_ctx_chkpt_buf_info {
+ u64 cpt_buf;
+ u32 cpt_type;
+ u32 buf_size;
+ s32 result;
+ u32 _pad;
+};
+
+/*
+ * VMCINotificationReceiveInfo: Used to recieve pending notifications
+ * for doorbells and queue pairs.
+ */
+struct vmci_ctx_notify_recv_info {
+ u64 db_handle_buf_uva;
+ u64 db_handle_buf_size;
+ u64 qp_handle_buf_uva;
+ u64 qp_handle_buf_size;
+ s32 result;
+ u32 _pad;
+};
+
+/*
+ * Utilility function that checks whether two entities are allowed
+ * to interact. If one of them is restricted, the other one must
+ * be trusted.
+ */
+static inline bool vmci_deny_interaction(u32 part_one, u32 part_two)
+{
+ return ((part_one & VMCI_PRIVILEGE_FLAG_RESTRICTED) &&
+ !(part_two & VMCI_PRIVILEGE_FLAG_TRUSTED)) ||
+ ((part_two & VMCI_PRIVILEGE_FLAG_RESTRICTED) &&
+ !(part_one & VMCI_PRIVILEGE_FLAG_TRUSTED));
+}
+
+struct vmci_ctx *vmci_ctx_create(u32 cid, u32 flags,
+ uintptr_t event_hnd, int version,
+ const struct cred *cred);
+void vmci_ctx_destroy(struct vmci_ctx *context);
+
+bool vmci_ctx_supports_host_qp(struct vmci_ctx *context);
+int vmci_ctx_enqueue_datagram(u32 cid, struct vmci_datagram *dg);
+int vmci_ctx_dequeue_datagram(struct vmci_ctx *context,
+ size_t *max_size, struct vmci_datagram **dg);
+int vmci_ctx_pending_datagrams(u32 cid, u32 *pending);
+struct vmci_ctx *vmci_ctx_get(u32 cid);
+void vmci_ctx_put(struct vmci_ctx *context);
+bool vmci_ctx_exists(u32 cid);
+
+int vmci_ctx_add_notification(u32 context_id, u32 remote_cid);
+int vmci_ctx_remove_notification(u32 context_id, u32 remote_cid);
+int vmci_ctx_get_chkpt_state(u32 context_id, u32 cpt_type,
+ u32 *num_cids, void **cpt_buf_ptr);
+int vmci_ctx_set_chkpt_state(u32 context_id, u32 cpt_type,
+ u32 num_cids, void *cpt_buf);
+
+int vmci_ctx_qp_create(struct vmci_ctx *context, struct vmci_handle handle);
+int vmci_ctx_qp_destroy(struct vmci_ctx *context, struct vmci_handle handle);
+bool vmci_ctx_qp_exists(struct vmci_ctx *context, struct vmci_handle handle);
+
+void vmci_ctx_check_signal_notify(struct vmci_ctx *context);
+void vmci_ctx_unset_notify(struct vmci_ctx *context);
+
+int vmci_ctx_dbell_create(u32 context_id, struct vmci_handle handle);
+int vmci_ctx_dbell_destroy(u32 context_id, struct vmci_handle handle);
+int vmci_ctx_dbell_destroy_all(u32 context_id);
+int vmci_ctx_notify_dbell(u32 cid, struct vmci_handle handle,
+ u32 src_priv_flags);
+
+int vmci_ctx_rcv_notifications_get(u32 context_id, struct vmci_handle_arr
+ **db_handle_array, struct vmci_handle_arr
+ **qp_handle_array);
+void vmci_ctx_rcv_notifications_release(u32 context_id, struct vmci_handle_arr
+ *db_handle_array, struct vmci_handle_arr
+ *qp_handle_array, bool success);
+
+static inline u32 vmci_ctx_get_id(struct vmci_ctx *context)
+{
+ if (!context)
+ return VMCI_INVALID_ID;
+ return context->cid;
+}
+
+#endif /* _VMCI_CONTEXT_H_ */
diff --git a/drivers/misc/vmw_vmci/vmci_datagram.c b/drivers/misc/vmw_vmci/vmci_datagram.c
new file mode 100644
index 000000000000..ed5c433cd493
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_datagram.c
@@ -0,0 +1,500 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/bug.h>
+
+#include "vmci_datagram.h"
+#include "vmci_resource.h"
+#include "vmci_context.h"
+#include "vmci_driver.h"
+#include "vmci_event.h"
+#include "vmci_route.h"
+
+/*
+ * struct datagram_entry describes the datagram entity. It is used for datagram
+ * entities created only on the host.
+ */
+struct datagram_entry {
+ struct vmci_resource resource;
+ u32 flags;
+ bool run_delayed;
+ vmci_datagram_recv_cb recv_cb;
+ void *client_data;
+ u32 priv_flags;
+};
+
+struct delayed_datagram_info {
+ struct datagram_entry *entry;
+ struct vmci_datagram msg;
+ struct work_struct work;
+ bool in_dg_host_queue;
+};
+
+/* Number of in-flight host->host datagrams */
+static atomic_t delayed_dg_host_queue_size = ATOMIC_INIT(0);
+
+/*
+ * Create a datagram entry given a handle pointer.
+ */
+static int dg_create_handle(u32 resource_id,
+ u32 flags,
+ u32 priv_flags,
+ vmci_datagram_recv_cb recv_cb,
+ void *client_data, struct vmci_handle *out_handle)
+{
+ int result;
+ u32 context_id;
+ struct vmci_handle handle;
+ struct datagram_entry *entry;
+
+ if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ if ((flags & VMCI_FLAG_ANYCID_DG_HND) != 0) {
+ context_id = VMCI_INVALID_ID;
+ } else {
+ context_id = vmci_get_context_id();
+ if (context_id == VMCI_INVALID_ID)
+ return VMCI_ERROR_NO_RESOURCES;
+ }
+
+ handle = vmci_make_handle(context_id, resource_id);
+
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ pr_warn("Failed allocating memory for datagram entry\n");
+ return VMCI_ERROR_NO_MEM;
+ }
+
+ entry->run_delayed = (flags & VMCI_FLAG_DG_DELAYED_CB) ? true : false;
+ entry->flags = flags;
+ entry->recv_cb = recv_cb;
+ entry->client_data = client_data;
+ entry->priv_flags = priv_flags;
+
+ /* Make datagram resource live. */
+ result = vmci_resource_add(&entry->resource,
+ VMCI_RESOURCE_TYPE_DATAGRAM,
+ handle);
+ if (result != VMCI_SUCCESS) {
+ pr_warn("Failed to add new resource (handle=0x%x:0x%x), error: %d\n",
+ handle.context, handle.resource, result);
+ kfree(entry);
+ return result;
+ }
+
+ *out_handle = vmci_resource_handle(&entry->resource);
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Internal utility function with the same purpose as
+ * vmci_datagram_get_priv_flags that also takes a context_id.
+ */
+static int vmci_datagram_get_priv_flags(u32 context_id,
+ struct vmci_handle handle,
+ u32 *priv_flags)
+{
+ if (context_id == VMCI_INVALID_ID)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ if (context_id == VMCI_HOST_CONTEXT_ID) {
+ struct datagram_entry *src_entry;
+ struct vmci_resource *resource;
+
+ resource = vmci_resource_by_handle(handle,
+ VMCI_RESOURCE_TYPE_DATAGRAM);
+ if (!resource)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ src_entry = container_of(resource, struct datagram_entry,
+ resource);
+ *priv_flags = src_entry->priv_flags;
+ vmci_resource_put(resource);
+ } else if (context_id == VMCI_HYPERVISOR_CONTEXT_ID)
+ *priv_flags = VMCI_MAX_PRIVILEGE_FLAGS;
+ else
+ *priv_flags = vmci_context_get_priv_flags(context_id);
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Calls the specified callback in a delayed context.
+ */
+static void dg_delayed_dispatch(struct work_struct *work)
+{
+ struct delayed_datagram_info *dg_info =
+ container_of(work, struct delayed_datagram_info, work);
+
+ dg_info->entry->recv_cb(dg_info->entry->client_data, &dg_info->msg);
+
+ vmci_resource_put(&dg_info->entry->resource);
+
+ if (dg_info->in_dg_host_queue)
+ atomic_dec(&delayed_dg_host_queue_size);
+
+ kfree(dg_info);
+}
+
+/*
+ * Dispatch datagram as a host, to the host, or other vm context. This
+ * function cannot dispatch to hypervisor context handlers. This should
+ * have been handled before we get here by vmci_datagram_dispatch.
+ * Returns number of bytes sent on success, error code otherwise.
+ */
+static int dg_dispatch_as_host(u32 context_id, struct vmci_datagram *dg)
+{
+ int retval;
+ size_t dg_size;
+ u32 src_priv_flags;
+
+ dg_size = VMCI_DG_SIZE(dg);
+
+ /* Host cannot send to the hypervisor. */
+ if (dg->dst.context == VMCI_HYPERVISOR_CONTEXT_ID)
+ return VMCI_ERROR_DST_UNREACHABLE;
+
+ /* Check that source handle matches sending context. */
+ if (dg->src.context != context_id) {
+ pr_devel("Sender context (ID=0x%x) is not owner of src datagram entry (handle=0x%x:0x%x)\n",
+ context_id, dg->src.context, dg->src.resource);
+ return VMCI_ERROR_NO_ACCESS;
+ }
+
+ /* Get hold of privileges of sending endpoint. */
+ retval = vmci_datagram_get_priv_flags(context_id, dg->src,
+ &src_priv_flags);
+ if (retval != VMCI_SUCCESS) {
+ pr_warn("Couldn't get privileges (handle=0x%x:0x%x)\n",
+ dg->src.context, dg->src.resource);
+ return retval;
+ }
+
+ /* Determine if we should route to host or guest destination. */
+ if (dg->dst.context == VMCI_HOST_CONTEXT_ID) {
+ /* Route to host datagram entry. */
+ struct datagram_entry *dst_entry;
+ struct vmci_resource *resource;
+
+ if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
+ dg->dst.resource == VMCI_EVENT_HANDLER) {
+ return vmci_event_dispatch(dg);
+ }
+
+ resource = vmci_resource_by_handle(dg->dst,
+ VMCI_RESOURCE_TYPE_DATAGRAM);
+ if (!resource) {
+ pr_devel("Sending to invalid destination (handle=0x%x:0x%x)\n",
+ dg->dst.context, dg->dst.resource);
+ return VMCI_ERROR_INVALID_RESOURCE;
+ }
+ dst_entry = container_of(resource, struct datagram_entry,
+ resource);
+ if (vmci_deny_interaction(src_priv_flags,
+ dst_entry->priv_flags)) {
+ vmci_resource_put(resource);
+ return VMCI_ERROR_NO_ACCESS;
+ }
+
+ /*
+ * If a VMCI datagram destined for the host is also sent by the
+ * host, we always run it delayed. This ensures that no locks
+ * are held when the datagram callback runs.
+ */
+ if (dst_entry->run_delayed ||
+ dg->src.context == VMCI_HOST_CONTEXT_ID) {
+ struct delayed_datagram_info *dg_info;
+
+ if (atomic_add_return(1, &delayed_dg_host_queue_size)
+ == VMCI_MAX_DELAYED_DG_HOST_QUEUE_SIZE) {
+ atomic_dec(&delayed_dg_host_queue_size);
+ vmci_resource_put(resource);
+ return VMCI_ERROR_NO_MEM;
+ }
+
+ dg_info = kmalloc(sizeof(*dg_info) +
+ (size_t) dg->payload_size, GFP_ATOMIC);
+ if (!dg_info) {
+ atomic_dec(&delayed_dg_host_queue_size);
+ vmci_resource_put(resource);
+ return VMCI_ERROR_NO_MEM;
+ }
+
+ dg_info->in_dg_host_queue = true;
+ dg_info->entry = dst_entry;
+ memcpy(&dg_info->msg, dg, dg_size);
+
+ INIT_WORK(&dg_info->work, dg_delayed_dispatch);
+ schedule_work(&dg_info->work);
+ retval = VMCI_SUCCESS;
+
+ } else {
+ retval = dst_entry->recv_cb(dst_entry->client_data, dg);
+ vmci_resource_put(resource);
+ if (retval < VMCI_SUCCESS)
+ return retval;
+ }
+ } else {
+ /* Route to destination VM context. */
+ struct vmci_datagram *new_dg;
+
+ if (context_id != dg->dst.context) {
+ if (vmci_deny_interaction(src_priv_flags,
+ vmci_context_get_priv_flags
+ (dg->dst.context))) {
+ return VMCI_ERROR_NO_ACCESS;
+ } else if (VMCI_CONTEXT_IS_VM(context_id)) {
+ /*
+ * If the sending context is a VM, it
+ * cannot reach another VM.
+ */
+
+ pr_devel("Datagram communication between VMs not supported (src=0x%x, dst=0x%x)\n",
+ context_id, dg->dst.context);
+ return VMCI_ERROR_DST_UNREACHABLE;
+ }
+ }
+
+ /* We make a copy to enqueue. */
+ new_dg = kmalloc(dg_size, GFP_KERNEL);
+ if (new_dg == NULL)
+ return VMCI_ERROR_NO_MEM;
+
+ memcpy(new_dg, dg, dg_size);
+ retval = vmci_ctx_enqueue_datagram(dg->dst.context, new_dg);
+ if (retval < VMCI_SUCCESS) {
+ kfree(new_dg);
+ return retval;
+ }
+ }
+
+ /*
+ * We currently truncate the size to signed 32 bits. This doesn't
+ * matter for this handler as it only support 4Kb messages.
+ */
+ return (int)dg_size;
+}
+
+/*
+ * Dispatch datagram as a guest, down through the VMX and potentially to
+ * the host.
+ * Returns number of bytes sent on success, error code otherwise.
+ */
+static int dg_dispatch_as_guest(struct vmci_datagram *dg)
+{
+ int retval;
+ struct vmci_resource *resource;
+
+ resource = vmci_resource_by_handle(dg->src,
+ VMCI_RESOURCE_TYPE_DATAGRAM);
+ if (!resource)
+ return VMCI_ERROR_NO_HANDLE;
+
+ retval = vmci_send_datagram(dg);
+ vmci_resource_put(resource);
+ return retval;
+}
+
+/*
+ * Dispatch datagram. This will determine the routing for the datagram
+ * and dispatch it accordingly.
+ * Returns number of bytes sent on success, error code otherwise.
+ */
+int vmci_datagram_dispatch(u32 context_id,
+ struct vmci_datagram *dg, bool from_guest)
+{
+ int retval;
+ enum vmci_route route;
+
+ BUILD_BUG_ON(sizeof(struct vmci_datagram) != 24);
+
+ if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
+ pr_devel("Payload (size=%llu bytes) too big to send\n",
+ (unsigned long long)dg->payload_size);
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ retval = vmci_route(&dg->src, &dg->dst, from_guest, &route);
+ if (retval < VMCI_SUCCESS) {
+ pr_devel("Failed to route datagram (src=0x%x, dst=0x%x, err=%d)\n",
+ dg->src.context, dg->dst.context, retval);
+ return retval;
+ }
+
+ if (VMCI_ROUTE_AS_HOST == route) {
+ if (VMCI_INVALID_ID == context_id)
+ context_id = VMCI_HOST_CONTEXT_ID;
+ return dg_dispatch_as_host(context_id, dg);
+ }
+
+ if (VMCI_ROUTE_AS_GUEST == route)
+ return dg_dispatch_as_guest(dg);
+
+ pr_warn("Unknown route (%d) for datagram\n", route);
+ return VMCI_ERROR_DST_UNREACHABLE;
+}
+
+/*
+ * Invoke the handler for the given datagram. This is intended to be
+ * called only when acting as a guest and receiving a datagram from the
+ * virtual device.
+ */
+int vmci_datagram_invoke_guest_handler(struct vmci_datagram *dg)
+{
+ struct vmci_resource *resource;
+ struct datagram_entry *dst_entry;
+
+ resource = vmci_resource_by_handle(dg->dst,
+ VMCI_RESOURCE_TYPE_DATAGRAM);
+ if (!resource) {
+ pr_devel("destination (handle=0x%x:0x%x) doesn't exist\n",
+ dg->dst.context, dg->dst.resource);
+ return VMCI_ERROR_NO_HANDLE;
+ }
+
+ dst_entry = container_of(resource, struct datagram_entry, resource);
+ if (dst_entry->run_delayed) {
+ struct delayed_datagram_info *dg_info;
+
+ dg_info = kmalloc(sizeof(*dg_info) + (size_t)dg->payload_size,
+ GFP_ATOMIC);
+ if (!dg_info) {
+ vmci_resource_put(resource);
+ return VMCI_ERROR_NO_MEM;
+ }
+
+ dg_info->in_dg_host_queue = false;
+ dg_info->entry = dst_entry;
+ memcpy(&dg_info->msg, dg, VMCI_DG_SIZE(dg));
+
+ INIT_WORK(&dg_info->work, dg_delayed_dispatch);
+ schedule_work(&dg_info->work);
+ } else {
+ dst_entry->recv_cb(dst_entry->client_data, dg);
+ vmci_resource_put(resource);
+ }
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * vmci_datagram_create_handle_priv() - Create host context datagram endpoint
+ * @resource_id: The resource ID.
+ * @flags: Datagram Flags.
+ * @priv_flags: Privilege Flags.
+ * @recv_cb: Callback when receiving datagrams.
+ * @client_data: Pointer for a datagram_entry struct
+ * @out_handle: vmci_handle that is populated as a result of this function.
+ *
+ * Creates a host context datagram endpoint and returns a handle to it.
+ */
+int vmci_datagram_create_handle_priv(u32 resource_id,
+ u32 flags,
+ u32 priv_flags,
+ vmci_datagram_recv_cb recv_cb,
+ void *client_data,
+ struct vmci_handle *out_handle)
+{
+ if (out_handle == NULL)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ if (recv_cb == NULL) {
+ pr_devel("Client callback needed when creating datagram\n");
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ if (priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ return dg_create_handle(resource_id, flags, priv_flags, recv_cb,
+ client_data, out_handle);
+}
+EXPORT_SYMBOL_GPL(vmci_datagram_create_handle_priv);
+
+/*
+ * vmci_datagram_create_handle() - Create host context datagram endpoint
+ * @resource_id: Resource ID.
+ * @flags: Datagram Flags.
+ * @recv_cb: Callback when receiving datagrams.
+ * @client_ata: Pointer for a datagram_entry struct
+ * @out_handle: vmci_handle that is populated as a result of this function.
+ *
+ * Creates a host context datagram endpoint and returns a handle to
+ * it. Same as vmci_datagram_create_handle_priv without the priviledge
+ * flags argument.
+ */
+int vmci_datagram_create_handle(u32 resource_id,
+ u32 flags,
+ vmci_datagram_recv_cb recv_cb,
+ void *client_data,
+ struct vmci_handle *out_handle)
+{
+ return vmci_datagram_create_handle_priv(
+ resource_id, flags,
+ VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS,
+ recv_cb, client_data,
+ out_handle);
+}
+EXPORT_SYMBOL_GPL(vmci_datagram_create_handle);
+
+/*
+ * vmci_datagram_destroy_handle() - Destroys datagram handle
+ * @handle: vmci_handle to be destroyed and reaped.
+ *
+ * Use this function to destroy any datagram handles created by
+ * vmci_datagram_create_handle{,Priv} functions.
+ */
+int vmci_datagram_destroy_handle(struct vmci_handle handle)
+{
+ struct datagram_entry *entry;
+ struct vmci_resource *resource;
+
+ resource = vmci_resource_by_handle(handle, VMCI_RESOURCE_TYPE_DATAGRAM);
+ if (!resource) {
+ pr_devel("Failed to destroy datagram (handle=0x%x:0x%x)\n",
+ handle.context, handle.resource);
+ return VMCI_ERROR_NOT_FOUND;
+ }
+
+ entry = container_of(resource, struct datagram_entry, resource);
+
+ vmci_resource_put(&entry->resource);
+ vmci_resource_remove(&entry->resource);
+ kfree(entry);
+
+ return VMCI_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(vmci_datagram_destroy_handle);
+
+/*
+ * vmci_datagram_send() - Send a datagram
+ * @msg: The datagram to send.
+ *
+ * Sends the provided datagram on its merry way.
+ */
+int vmci_datagram_send(struct vmci_datagram *msg)
+{
+ if (msg == NULL)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ return vmci_datagram_dispatch(VMCI_INVALID_ID, msg, false);
+}
+EXPORT_SYMBOL_GPL(vmci_datagram_send);
diff --git a/drivers/misc/vmw_vmci/vmci_datagram.h b/drivers/misc/vmw_vmci/vmci_datagram.h
new file mode 100644
index 000000000000..eb4aab7f64ec
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_datagram.h
@@ -0,0 +1,52 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _VMCI_DATAGRAM_H_
+#define _VMCI_DATAGRAM_H_
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+#include "vmci_context.h"
+
+#define VMCI_MAX_DELAYED_DG_HOST_QUEUE_SIZE 256
+
+/*
+ * The struct vmci_datagram_queue_entry is a queue header for the in-kernel VMCI
+ * datagram queues. It is allocated in non-paged memory, as the
+ * content is accessed while holding a spinlock. The pending datagram
+ * itself may be allocated from paged memory. We shadow the size of
+ * the datagram in the non-paged queue entry as this size is used
+ * while holding the same spinlock as above.
+ */
+struct vmci_datagram_queue_entry {
+ struct list_head list_item; /* For queuing. */
+ size_t dg_size; /* Size of datagram. */
+ struct vmci_datagram *dg; /* Pending datagram. */
+};
+
+/* VMCIDatagramSendRecvInfo */
+struct vmci_datagram_snd_rcv_info {
+ u64 addr;
+ u32 len;
+ s32 result;
+};
+
+/* Datagram API for non-public use. */
+int vmci_datagram_dispatch(u32 context_id, struct vmci_datagram *dg,
+ bool from_guest);
+int vmci_datagram_invoke_guest_handler(struct vmci_datagram *dg);
+
+#endif /* _VMCI_DATAGRAM_H_ */
diff --git a/drivers/misc/vmw_vmci/vmci_doorbell.c b/drivers/misc/vmw_vmci/vmci_doorbell.c
new file mode 100644
index 000000000000..c3e8397f62ed
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_doorbell.c
@@ -0,0 +1,604 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+#include <linux/completion.h>
+#include <linux/hash.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "vmci_datagram.h"
+#include "vmci_doorbell.h"
+#include "vmci_resource.h"
+#include "vmci_driver.h"
+#include "vmci_route.h"
+
+
+#define VMCI_DOORBELL_INDEX_BITS 6
+#define VMCI_DOORBELL_INDEX_TABLE_SIZE (1 << VMCI_DOORBELL_INDEX_BITS)
+#define VMCI_DOORBELL_HASH(_idx) hash_32(_idx, VMCI_DOORBELL_INDEX_BITS)
+
+/*
+ * DoorbellEntry describes the a doorbell notification handle allocated by the
+ * host.
+ */
+struct dbell_entry {
+ struct vmci_resource resource;
+ struct hlist_node node;
+ struct work_struct work;
+ vmci_callback notify_cb;
+ void *client_data;
+ u32 idx;
+ u32 priv_flags;
+ bool run_delayed;
+ atomic_t active; /* Only used by guest personality */
+};
+
+/* The VMCI index table keeps track of currently registered doorbells. */
+struct dbell_index_table {
+ spinlock_t lock; /* Index table lock */
+ struct hlist_head entries[VMCI_DOORBELL_INDEX_TABLE_SIZE];
+};
+
+static struct dbell_index_table vmci_doorbell_it = {
+ .lock = __SPIN_LOCK_UNLOCKED(vmci_doorbell_it.lock),
+};
+
+/*
+ * The max_notify_idx is one larger than the currently known bitmap index in
+ * use, and is used to determine how much of the bitmap needs to be scanned.
+ */
+static u32 max_notify_idx;
+
+/*
+ * The notify_idx_count is used for determining whether there are free entries
+ * within the bitmap (if notify_idx_count + 1 < max_notify_idx).
+ */
+static u32 notify_idx_count;
+
+/*
+ * The last_notify_idx_reserved is used to track the last index handed out - in
+ * the case where multiple handles share a notification index, we hand out
+ * indexes round robin based on last_notify_idx_reserved.
+ */
+static u32 last_notify_idx_reserved;
+
+/* This is a one entry cache used to by the index allocation. */
+static u32 last_notify_idx_released = PAGE_SIZE;
+
+
+/*
+ * Utility function that retrieves the privilege flags associated
+ * with a given doorbell handle. For guest endpoints, the
+ * privileges are determined by the context ID, but for host
+ * endpoints privileges are associated with the complete
+ * handle. Hypervisor endpoints are not yet supported.
+ */
+int vmci_dbell_get_priv_flags(struct vmci_handle handle, u32 *priv_flags)
+{
+ if (priv_flags == NULL || handle.context == VMCI_INVALID_ID)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ if (handle.context == VMCI_HOST_CONTEXT_ID) {
+ struct dbell_entry *entry;
+ struct vmci_resource *resource;
+
+ resource = vmci_resource_by_handle(handle,
+ VMCI_RESOURCE_TYPE_DOORBELL);
+ if (!resource)
+ return VMCI_ERROR_NOT_FOUND;
+
+ entry = container_of(resource, struct dbell_entry, resource);
+ *priv_flags = entry->priv_flags;
+ vmci_resource_put(resource);
+ } else if (handle.context == VMCI_HYPERVISOR_CONTEXT_ID) {
+ /*
+ * Hypervisor endpoints for notifications are not
+ * supported (yet).
+ */
+ return VMCI_ERROR_INVALID_ARGS;
+ } else {
+ *priv_flags = vmci_context_get_priv_flags(handle.context);
+ }
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Find doorbell entry by bitmap index.
+ */
+static struct dbell_entry *dbell_index_table_find(u32 idx)
+{
+ u32 bucket = VMCI_DOORBELL_HASH(idx);
+ struct dbell_entry *dbell;
+ struct hlist_node *node;
+
+ hlist_for_each_entry(dbell, node, &vmci_doorbell_it.entries[bucket],
+ node) {
+ if (idx == dbell->idx)
+ return dbell;
+ }
+
+ return NULL;
+}
+
+/*
+ * Add the given entry to the index table. This willi take a reference to the
+ * entry's resource so that the entry is not deleted before it is removed from
+ * the * table.
+ */
+static void dbell_index_table_add(struct dbell_entry *entry)
+{
+ u32 bucket;
+ u32 new_notify_idx;
+
+ vmci_resource_get(&entry->resource);
+
+ spin_lock_bh(&vmci_doorbell_it.lock);
+
+ /*
+ * Below we try to allocate an index in the notification
+ * bitmap with "not too much" sharing between resources. If we
+ * use less that the full bitmap, we either add to the end if
+ * there are no unused flags within the currently used area,
+ * or we search for unused ones. If we use the full bitmap, we
+ * allocate the index round robin.
+ */
+ if (max_notify_idx < PAGE_SIZE || notify_idx_count < PAGE_SIZE) {
+ if (last_notify_idx_released < max_notify_idx &&
+ !dbell_index_table_find(last_notify_idx_released)) {
+ new_notify_idx = last_notify_idx_released;
+ last_notify_idx_released = PAGE_SIZE;
+ } else {
+ bool reused = false;
+ new_notify_idx = last_notify_idx_reserved;
+ if (notify_idx_count + 1 < max_notify_idx) {
+ do {
+ if (!dbell_index_table_find
+ (new_notify_idx)) {
+ reused = true;
+ break;
+ }
+ new_notify_idx = (new_notify_idx + 1) %
+ max_notify_idx;
+ } while (new_notify_idx !=
+ last_notify_idx_released);
+ }
+ if (!reused) {
+ new_notify_idx = max_notify_idx;
+ max_notify_idx++;
+ }
+ }
+ } else {
+ new_notify_idx = (last_notify_idx_reserved + 1) % PAGE_SIZE;
+ }
+
+ last_notify_idx_reserved = new_notify_idx;
+ notify_idx_count++;
+
+ entry->idx = new_notify_idx;
+ bucket = VMCI_DOORBELL_HASH(entry->idx);
+ hlist_add_head(&entry->node, &vmci_doorbell_it.entries[bucket]);
+
+ spin_unlock_bh(&vmci_doorbell_it.lock);
+}
+
+/*
+ * Remove the given entry from the index table. This will release() the
+ * entry's resource.
+ */
+static void dbell_index_table_remove(struct dbell_entry *entry)
+{
+ spin_lock_bh(&vmci_doorbell_it.lock);
+
+ hlist_del_init(&entry->node);
+
+ notify_idx_count--;
+ if (entry->idx == max_notify_idx - 1) {
+ /*
+ * If we delete an entry with the maximum known
+ * notification index, we take the opportunity to
+ * prune the current max. As there might be other
+ * unused indices immediately below, we lower the
+ * maximum until we hit an index in use.
+ */
+ while (max_notify_idx > 0 &&
+ !dbell_index_table_find(max_notify_idx - 1))
+ max_notify_idx--;
+ }
+
+ last_notify_idx_released = entry->idx;
+
+ spin_unlock_bh(&vmci_doorbell_it.lock);
+
+ vmci_resource_put(&entry->resource);
+}
+
+/*
+ * Creates a link between the given doorbell handle and the given
+ * index in the bitmap in the device backend. A notification state
+ * is created in hypervisor.
+ */
+static int dbell_link(struct vmci_handle handle, u32 notify_idx)
+{
+ struct vmci_doorbell_link_msg link_msg;
+
+ link_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_DOORBELL_LINK);
+ link_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
+ link_msg.hdr.payload_size = sizeof(link_msg) - VMCI_DG_HEADERSIZE;
+ link_msg.handle = handle;
+ link_msg.notify_idx = notify_idx;
+
+ return vmci_send_datagram(&link_msg.hdr);
+}
+
+/*
+ * Unlinks the given doorbell handle from an index in the bitmap in
+ * the device backend. The notification state is destroyed in hypervisor.
+ */
+static int dbell_unlink(struct vmci_handle handle)
+{
+ struct vmci_doorbell_unlink_msg unlink_msg;
+
+ unlink_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_DOORBELL_UNLINK);
+ unlink_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
+ unlink_msg.hdr.payload_size = sizeof(unlink_msg) - VMCI_DG_HEADERSIZE;
+ unlink_msg.handle = handle;
+
+ return vmci_send_datagram(&unlink_msg.hdr);
+}
+
+/*
+ * Notify another guest or the host. We send a datagram down to the
+ * host via the hypervisor with the notification info.
+ */
+static int dbell_notify_as_guest(struct vmci_handle handle, u32 priv_flags)
+{
+ struct vmci_doorbell_notify_msg notify_msg;
+
+ notify_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_DOORBELL_NOTIFY);
+ notify_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
+ notify_msg.hdr.payload_size = sizeof(notify_msg) - VMCI_DG_HEADERSIZE;
+ notify_msg.handle = handle;
+
+ return vmci_send_datagram(&notify_msg.hdr);
+}
+
+/*
+ * Calls the specified callback in a delayed context.
+ */
+static void dbell_delayed_dispatch(struct work_struct *work)
+{
+ struct dbell_entry *entry = container_of(work,
+ struct dbell_entry, work);
+
+ entry->notify_cb(entry->client_data);
+ vmci_resource_put(&entry->resource);
+}
+
+/*
+ * Dispatches a doorbell notification to the host context.
+ */
+int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle)
+{
+ struct dbell_entry *entry;
+ struct vmci_resource *resource;
+
+ if (vmci_handle_is_invalid(handle)) {
+ pr_devel("Notifying an invalid doorbell (handle=0x%x:0x%x)\n",
+ handle.context, handle.resource);
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ resource = vmci_resource_by_handle(handle,
+ VMCI_RESOURCE_TYPE_DOORBELL);
+ if (!resource) {
+ pr_devel("Notifying an unknown doorbell (handle=0x%x:0x%x)\n",
+ handle.context, handle.resource);
+ return VMCI_ERROR_NOT_FOUND;
+ }
+
+ entry = container_of(resource, struct dbell_entry, resource);
+ if (entry->run_delayed) {
+ schedule_work(&entry->work);
+ } else {
+ entry->notify_cb(entry->client_data);
+ vmci_resource_put(resource);
+ }
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Register the notification bitmap with the host.
+ */
+bool vmci_dbell_register_notification_bitmap(u32 bitmap_ppn)
+{
+ int result;
+ struct vmci_notify_bm_set_msg bitmap_set_msg;
+
+ bitmap_set_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_SET_NOTIFY_BITMAP);
+ bitmap_set_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
+ bitmap_set_msg.hdr.payload_size = sizeof(bitmap_set_msg) -
+ VMCI_DG_HEADERSIZE;
+ bitmap_set_msg.bitmap_ppn = bitmap_ppn;
+
+ result = vmci_send_datagram(&bitmap_set_msg.hdr);
+ if (result != VMCI_SUCCESS) {
+ pr_devel("Failed to register (PPN=%u) as notification bitmap (error=%d)\n",
+ bitmap_ppn, result);
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Executes or schedules the handlers for a given notify index.
+ */
+static void dbell_fire_entries(u32 notify_idx)
+{
+ u32 bucket = VMCI_DOORBELL_HASH(notify_idx);
+ struct dbell_entry *dbell;
+ struct hlist_node *node;
+
+ spin_lock_bh(&vmci_doorbell_it.lock);
+
+ hlist_for_each_entry(dbell, node,
+ &vmci_doorbell_it.entries[bucket], node) {
+ if (dbell->idx == notify_idx &&
+ atomic_read(&dbell->active) == 1) {
+ if (dbell->run_delayed) {
+ vmci_resource_get(&dbell->resource);
+ schedule_work(&dbell->work);
+ } else {
+ dbell->notify_cb(dbell->client_data);
+ }
+ }
+ }
+
+ spin_unlock_bh(&vmci_doorbell_it.lock);
+}
+
+/*
+ * Scans the notification bitmap, collects pending notifications,
+ * resets the bitmap and invokes appropriate callbacks.
+ */
+void vmci_dbell_scan_notification_entries(u8 *bitmap)
+{
+ u32 idx;
+
+ for (idx = 0; idx < max_notify_idx; idx++) {
+ if (bitmap[idx] & 0x1) {
+ bitmap[idx] &= ~1;
+ dbell_fire_entries(idx);
+ }
+ }
+}
+
+/*
+ * vmci_doorbell_create() - Creates a doorbell
+ * @handle: A handle used to track the resource. Can be invalid.
+ * @flags: Flag that determines context of callback.
+ * @priv_flags: Privileges flags.
+ * @notify_cb: The callback to be ivoked when the doorbell fires.
+ * @client_data: A parameter to be passed to the callback.
+ *
+ * Creates a doorbell with the given callback. If the handle is
+ * VMCI_INVALID_HANDLE, a free handle will be assigned, if
+ * possible. The callback can be run immediately (potentially with
+ * locks held - the default) or delayed (in a kernel thread) by
+ * specifying the flag VMCI_FLAG_DELAYED_CB. If delayed execution
+ * is selected, a given callback may not be run if the kernel is
+ * unable to allocate memory for the delayed execution (highly
+ * unlikely).
+ */
+int vmci_doorbell_create(struct vmci_handle *handle,
+ u32 flags,
+ u32 priv_flags,
+ vmci_callback notify_cb, void *client_data)
+{
+ struct dbell_entry *entry;
+ struct vmci_handle new_handle;
+ int result;
+
+ if (!handle || !notify_cb || flags & ~VMCI_FLAG_DELAYED_CB ||
+ priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (entry == NULL) {
+ pr_warn("Failed allocating memory for datagram entry\n");
+ return VMCI_ERROR_NO_MEM;
+ }
+
+ if (vmci_handle_is_invalid(*handle)) {
+ u32 context_id = vmci_get_context_id();
+
+ /* Let resource code allocate a free ID for us */
+ new_handle = vmci_make_handle(context_id, VMCI_INVALID_ID);
+ } else {
+ bool valid_context = false;
+
+ /*
+ * Validate the handle. We must do both of the checks below
+ * because we can be acting as both a host and a guest at the
+ * same time. We always allow the host context ID, since the
+ * host functionality is in practice always there with the
+ * unified driver.
+ */
+ if (handle->context == VMCI_HOST_CONTEXT_ID ||
+ (vmci_guest_code_active() &&
+ vmci_get_context_id() == handle->context)) {
+ valid_context = true;
+ }
+
+ if (!valid_context || handle->resource == VMCI_INVALID_ID) {
+ pr_devel("Invalid argument (handle=0x%x:0x%x)\n",
+ handle->context, handle->resource);
+ result = VMCI_ERROR_INVALID_ARGS;
+ goto free_mem;
+ }
+
+ new_handle = *handle;
+ }
+
+ entry->idx = 0;
+ INIT_HLIST_NODE(&entry->node);
+ entry->priv_flags = priv_flags;
+ INIT_WORK(&entry->work, dbell_delayed_dispatch);
+ entry->run_delayed = flags & VMCI_FLAG_DELAYED_CB;
+ entry->notify_cb = notify_cb;
+ entry->client_data = client_data;
+ atomic_set(&entry->active, 0);
+
+ result = vmci_resource_add(&entry->resource,
+ VMCI_RESOURCE_TYPE_DOORBELL,
+ new_handle);
+ if (result != VMCI_SUCCESS) {
+ pr_warn("Failed to add new resource (handle=0x%x:0x%x), error: %d\n",
+ new_handle.context, new_handle.resource, result);
+ goto free_mem;
+ }
+
+ new_handle = vmci_resource_handle(&entry->resource);
+ if (vmci_guest_code_active()) {
+ dbell_index_table_add(entry);
+ result = dbell_link(new_handle, entry->idx);
+ if (VMCI_SUCCESS != result)
+ goto destroy_resource;
+
+ atomic_set(&entry->active, 1);
+ }
+
+ *handle = new_handle;
+
+ return result;
+
+ destroy_resource:
+ dbell_index_table_remove(entry);
+ vmci_resource_remove(&entry->resource);
+ free_mem:
+ kfree(entry);
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_doorbell_create);
+
+/*
+ * vmci_doorbell_destroy() - Destroy a doorbell.
+ * @handle: The handle tracking the resource.
+ *
+ * Destroys a doorbell previously created with vmcii_doorbell_create. This
+ * operation may block waiting for a callback to finish.
+ */
+int vmci_doorbell_destroy(struct vmci_handle handle)
+{
+ struct dbell_entry *entry;
+ struct vmci_resource *resource;
+
+ if (vmci_handle_is_invalid(handle))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ resource = vmci_resource_by_handle(handle,
+ VMCI_RESOURCE_TYPE_DOORBELL);
+ if (!resource) {
+ pr_devel("Failed to destroy doorbell (handle=0x%x:0x%x)\n",
+ handle.context, handle.resource);
+ return VMCI_ERROR_NOT_FOUND;
+ }
+
+ entry = container_of(resource, struct dbell_entry, resource);
+
+ if (vmci_guest_code_active()) {
+ int result;
+
+ dbell_index_table_remove(entry);
+
+ result = dbell_unlink(handle);
+ if (VMCI_SUCCESS != result) {
+
+ /*
+ * The only reason this should fail would be
+ * an inconsistency between guest and
+ * hypervisor state, where the guest believes
+ * it has an active registration whereas the
+ * hypervisor doesn't. One case where this may
+ * happen is if a doorbell is unregistered
+ * following a hibernation at a time where the
+ * doorbell state hasn't been restored on the
+ * hypervisor side yet. Since the handle has
+ * now been removed in the guest, we just
+ * print a warning and return success.
+ */
+ pr_devel("Unlink of doorbell (handle=0x%x:0x%x) unknown by hypervisor (error=%d)\n",
+ handle.context, handle.resource, result);
+ }
+ }
+
+ /*
+ * Now remove the resource from the table. It might still be in use
+ * after this, in a callback or still on the delayed work queue.
+ */
+ vmci_resource_put(&entry->resource);
+ vmci_resource_remove(&entry->resource);
+
+ kfree(entry);
+
+ return VMCI_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(vmci_doorbell_destroy);
+
+/*
+ * vmci_doorbell_notify() - Ring the doorbell (and hide in the bushes).
+ * @dst: The handlle identifying the doorbell resource
+ * @priv_flags: Priviledge flags.
+ *
+ * Generates a notification on the doorbell identified by the
+ * handle. For host side generation of notifications, the caller
+ * can specify what the privilege of the calling side is.
+ */
+int vmci_doorbell_notify(struct vmci_handle dst, u32 priv_flags)
+{
+ int retval;
+ enum vmci_route route;
+ struct vmci_handle src;
+
+ if (vmci_handle_is_invalid(dst) ||
+ (priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ src = VMCI_INVALID_HANDLE;
+ retval = vmci_route(&src, &dst, false, &route);
+ if (retval < VMCI_SUCCESS)
+ return retval;
+
+ if (VMCI_ROUTE_AS_HOST == route)
+ return vmci_ctx_notify_dbell(VMCI_HOST_CONTEXT_ID,
+ dst, priv_flags);
+
+ if (VMCI_ROUTE_AS_GUEST == route)
+ return dbell_notify_as_guest(dst, priv_flags);
+
+ pr_warn("Unknown route (%d) for doorbell\n", route);
+ return VMCI_ERROR_DST_UNREACHABLE;
+}
+EXPORT_SYMBOL_GPL(vmci_doorbell_notify);
diff --git a/drivers/misc/vmw_vmci/vmci_doorbell.h b/drivers/misc/vmw_vmci/vmci_doorbell.h
new file mode 100644
index 000000000000..e4c0b17486a5
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_doorbell.h
@@ -0,0 +1,51 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 VMCI_DOORBELL_H
+#define VMCI_DOORBELL_H
+
+#include <linux/vmw_vmci_defs.h>
+#include <linux/types.h>
+
+#include "vmci_driver.h"
+
+/*
+ * VMCINotifyResourceInfo: Used to create and destroy doorbells, and
+ * generate a notification for a doorbell or queue pair.
+ */
+struct vmci_dbell_notify_resource_info {
+ struct vmci_handle handle;
+ u16 resource;
+ u16 action;
+ s32 result;
+};
+
+/*
+ * Structure used for checkpointing the doorbell mappings. It is
+ * written to the checkpoint as is, so changing this structure will
+ * break checkpoint compatibility.
+ */
+struct dbell_cpt_state {
+ struct vmci_handle handle;
+ u64 bitmap_idx;
+};
+
+int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle);
+int vmci_dbell_get_priv_flags(struct vmci_handle handle, u32 *priv_flags);
+
+bool vmci_dbell_register_notification_bitmap(u32 bitmap_ppn);
+void vmci_dbell_scan_notification_entries(u8 *bitmap);
+
+#endif /* VMCI_DOORBELL_H */
diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c
new file mode 100644
index 000000000000..7b3fce2da6c3
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_driver.c
@@ -0,0 +1,117 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+#include <linux/atomic.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "vmci_driver.h"
+#include "vmci_event.h"
+
+static bool vmci_disable_host;
+module_param_named(disable_host, vmci_disable_host, bool, 0);
+MODULE_PARM_DESC(disable_host,
+ "Disable driver host personality (default=enabled)");
+
+static bool vmci_disable_guest;
+module_param_named(disable_guest, vmci_disable_guest, bool, 0);
+MODULE_PARM_DESC(disable_guest,
+ "Disable driver guest personality (default=enabled)");
+
+static bool vmci_guest_personality_initialized;
+static bool vmci_host_personality_initialized;
+
+/*
+ * vmci_get_context_id() - Gets the current context ID.
+ *
+ * Returns the current context ID. Note that since this is accessed only
+ * from code running in the host, this always returns the host context ID.
+ */
+u32 vmci_get_context_id(void)
+{
+ if (vmci_guest_code_active())
+ return vmci_get_vm_context_id();
+ else if (vmci_host_code_active())
+ return VMCI_HOST_CONTEXT_ID;
+
+ return VMCI_INVALID_ID;
+}
+EXPORT_SYMBOL_GPL(vmci_get_context_id);
+
+static int __init vmci_drv_init(void)
+{
+ int vmci_err;
+ int error;
+
+ vmci_err = vmci_event_init();
+ if (vmci_err < VMCI_SUCCESS) {
+ pr_err("Failed to initialize VMCIEvent (result=%d)\n",
+ vmci_err);
+ return -EINVAL;
+ }
+
+ if (!vmci_disable_guest) {
+ error = vmci_guest_init();
+ if (error) {
+ pr_warn("Failed to initialize guest personality (err=%d)\n",
+ error);
+ } else {
+ vmci_guest_personality_initialized = true;
+ pr_info("Guest personality initialized and is %s\n",
+ vmci_guest_code_active() ?
+ "active" : "inactive");
+ }
+ }
+
+ if (!vmci_disable_host) {
+ error = vmci_host_init();
+ if (error) {
+ pr_warn("Unable to initialize host personality (err=%d)\n",
+ error);
+ } else {
+ vmci_host_personality_initialized = true;
+ pr_info("Initialized host personality\n");
+ }
+ }
+
+ if (!vmci_guest_personality_initialized &&
+ !vmci_host_personality_initialized) {
+ vmci_event_exit();
+ return -ENODEV;
+ }
+
+ return 0;
+}
+module_init(vmci_drv_init);
+
+static void __exit vmci_drv_exit(void)
+{
+ if (vmci_guest_personality_initialized)
+ vmci_guest_exit();
+
+ if (vmci_host_personality_initialized)
+ vmci_host_exit();
+
+ vmci_event_exit();
+}
+module_exit(vmci_drv_exit);
+
+MODULE_AUTHOR("VMware, Inc.");
+MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface.");
+MODULE_VERSION("1.0.0.0-k");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/vmw_vmci/vmci_driver.h b/drivers/misc/vmw_vmci/vmci_driver.h
new file mode 100644
index 000000000000..f69156a1f30c
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_driver.h
@@ -0,0 +1,50 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _VMCI_DRIVER_H_
+#define _VMCI_DRIVER_H_
+
+#include <linux/vmw_vmci_defs.h>
+#include <linux/wait.h>
+
+#include "vmci_queue_pair.h"
+#include "vmci_context.h"
+
+enum vmci_obj_type {
+ VMCIOBJ_VMX_VM = 10,
+ VMCIOBJ_CONTEXT,
+ VMCIOBJ_SOCKET,
+ VMCIOBJ_NOT_SET,
+};
+
+/* For storing VMCI structures in file handles. */
+struct vmci_obj {
+ void *ptr;
+ enum vmci_obj_type type;
+};
+
+u32 vmci_get_context_id(void);
+int vmci_send_datagram(struct vmci_datagram *dg);
+
+int vmci_host_init(void);
+void vmci_host_exit(void);
+bool vmci_host_code_active(void);
+
+int vmci_guest_init(void);
+void vmci_guest_exit(void);
+bool vmci_guest_code_active(void);
+u32 vmci_get_vm_context_id(void);
+
+#endif /* _VMCI_DRIVER_H_ */
diff --git a/drivers/misc/vmw_vmci/vmci_event.c b/drivers/misc/vmw_vmci/vmci_event.c
new file mode 100644
index 000000000000..8449516d6ac6
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_event.c
@@ -0,0 +1,224 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "vmci_driver.h"
+#include "vmci_event.h"
+
+#define EVENT_MAGIC 0xEABE0000
+#define VMCI_EVENT_MAX_ATTEMPTS 10
+
+struct vmci_subscription {
+ u32 id;
+ u32 event;
+ vmci_event_cb callback;
+ void *callback_data;
+ struct list_head node; /* on one of subscriber lists */
+};
+
+static struct list_head subscriber_array[VMCI_EVENT_MAX];
+static DEFINE_MUTEX(subscriber_mutex);
+
+int __init vmci_event_init(void)
+{
+ int i;
+
+ for (i = 0; i < VMCI_EVENT_MAX; i++)
+ INIT_LIST_HEAD(&subscriber_array[i]);
+
+ return VMCI_SUCCESS;
+}
+
+void vmci_event_exit(void)
+{
+ int e;
+
+ /* We free all memory at exit. */
+ for (e = 0; e < VMCI_EVENT_MAX; e++) {
+ struct vmci_subscription *cur, *p2;
+ list_for_each_entry_safe(cur, p2, &subscriber_array[e], node) {
+
+ /*
+ * We should never get here because all events
+ * should have been unregistered before we try
+ * to unload the driver module.
+ */
+ pr_warn("Unexpected free events occurring\n");
+ list_del(&cur->node);
+ kfree(cur);
+ }
+ }
+}
+
+/*
+ * Find entry. Assumes subscriber_mutex is held.
+ */
+static struct vmci_subscription *event_find(u32 sub_id)
+{
+ int e;
+
+ for (e = 0; e < VMCI_EVENT_MAX; e++) {
+ struct vmci_subscription *cur;
+ list_for_each_entry(cur, &subscriber_array[e], node) {
+ if (cur->id == sub_id)
+ return cur;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Actually delivers the events to the subscribers.
+ * The callback function for each subscriber is invoked.
+ */
+static void event_deliver(struct vmci_event_msg *event_msg)
+{
+ struct vmci_subscription *cur;
+ struct list_head *subscriber_list;
+
+ rcu_read_lock();
+ subscriber_list = &subscriber_array[event_msg->event_data.event];
+ list_for_each_entry_rcu(cur, subscriber_list, node) {
+ cur->callback(cur->id, &event_msg->event_data,
+ cur->callback_data);
+ }
+ rcu_read_unlock();
+}
+
+/*
+ * Dispatcher for the VMCI_EVENT_RECEIVE datagrams. Calls all
+ * subscribers for given event.
+ */
+int vmci_event_dispatch(struct vmci_datagram *msg)
+{
+ struct vmci_event_msg *event_msg = (struct vmci_event_msg *)msg;
+
+ if (msg->payload_size < sizeof(u32) ||
+ msg->payload_size > sizeof(struct vmci_event_data_max))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ if (!VMCI_EVENT_VALID(event_msg->event_data.event))
+ return VMCI_ERROR_EVENT_UNKNOWN;
+
+ event_deliver(event_msg);
+ return VMCI_SUCCESS;
+}
+
+/*
+ * vmci_event_subscribe() - Subscribe to a given event.
+ * @event: The event to subscribe to.
+ * @callback: The callback to invoke upon the event.
+ * @callback_data: Data to pass to the callback.
+ * @subscription_id: ID used to track subscription. Used with
+ * vmci_event_unsubscribe()
+ *
+ * Subscribes to the provided event. The callback specified will be
+ * fired from RCU critical section and therefore must not sleep.
+ */
+int vmci_event_subscribe(u32 event,
+ vmci_event_cb callback,
+ void *callback_data,
+ u32 *new_subscription_id)
+{
+ struct vmci_subscription *sub;
+ int attempts;
+ int retval;
+ bool have_new_id = false;
+
+ if (!new_subscription_id) {
+ pr_devel("%s: Invalid subscription (NULL)\n", __func__);
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ if (!VMCI_EVENT_VALID(event) || !callback) {
+ pr_devel("%s: Failed to subscribe to event (type=%d) (callback=%p) (data=%p)\n",
+ __func__, event, callback, callback_data);
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ sub = kzalloc(sizeof(*sub), GFP_KERNEL);
+ if (!sub)
+ return VMCI_ERROR_NO_MEM;
+
+ sub->id = VMCI_EVENT_MAX;
+ sub->event = event;
+ sub->callback = callback;
+ sub->callback_data = callback_data;
+ INIT_LIST_HEAD(&sub->node);
+
+ mutex_lock(&subscriber_mutex);
+
+ /* Creation of a new event is always allowed. */
+ for (attempts = 0; attempts < VMCI_EVENT_MAX_ATTEMPTS; attempts++) {
+ static u32 subscription_id;
+ /*
+ * We try to get an id a couple of time before
+ * claiming we are out of resources.
+ */
+
+ /* Test for duplicate id. */
+ if (!event_find(++subscription_id)) {
+ sub->id = subscription_id;
+ have_new_id = true;
+ break;
+ }
+ }
+
+ if (have_new_id) {
+ list_add_rcu(&sub->node, &subscriber_array[event]);
+ retval = VMCI_SUCCESS;
+ } else {
+ retval = VMCI_ERROR_NO_RESOURCES;
+ }
+
+ mutex_unlock(&subscriber_mutex);
+
+ *new_subscription_id = sub->id;
+ return retval;
+}
+EXPORT_SYMBOL_GPL(vmci_event_subscribe);
+
+/*
+ * vmci_event_unsubscribe() - unsubscribe from an event.
+ * @sub_id: A subscription ID as provided by vmci_event_subscribe()
+ *
+ * Unsubscribe from given event. Removes it from list and frees it.
+ * Will return callback_data if requested by caller.
+ */
+int vmci_event_unsubscribe(u32 sub_id)
+{
+ struct vmci_subscription *s;
+
+ mutex_lock(&subscriber_mutex);
+ s = event_find(sub_id);
+ if (s)
+ list_del_rcu(&s->node);
+ mutex_unlock(&subscriber_mutex);
+
+ if (!s)
+ return VMCI_ERROR_NOT_FOUND;
+
+ synchronize_rcu();
+ kfree(s);
+
+ return VMCI_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(vmci_event_unsubscribe);
diff --git a/drivers/misc/vmw_vmci/vmci_event.h b/drivers/misc/vmw_vmci/vmci_event.h
new file mode 100644
index 000000000000..7df9b1c0a96c
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_event.h
@@ -0,0 +1,25 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 __VMCI_EVENT_H__
+#define __VMCI_EVENT_H__
+
+#include <linux/vmw_vmci_api.h>
+
+int vmci_event_init(void);
+void vmci_event_exit(void);
+int vmci_event_dispatch(struct vmci_datagram *msg);
+
+#endif /*__VMCI_EVENT_H__ */
diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c
new file mode 100644
index 000000000000..60c01999f489
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_guest.c
@@ -0,0 +1,759 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
+
+#include "vmci_datagram.h"
+#include "vmci_doorbell.h"
+#include "vmci_context.h"
+#include "vmci_driver.h"
+#include "vmci_event.h"
+
+#define PCI_VENDOR_ID_VMWARE 0x15AD
+#define PCI_DEVICE_ID_VMWARE_VMCI 0x0740
+
+#define VMCI_UTIL_NUM_RESOURCES 1
+
+static bool vmci_disable_msi;
+module_param_named(disable_msi, vmci_disable_msi, bool, 0);
+MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)");
+
+static bool vmci_disable_msix;
+module_param_named(disable_msix, vmci_disable_msix, bool, 0);
+MODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=0)");
+
+static u32 ctx_update_sub_id = VMCI_INVALID_ID;
+static u32 vm_context_id = VMCI_INVALID_ID;
+
+struct vmci_guest_device {
+ struct device *dev; /* PCI device we are attached to */
+ void __iomem *iobase;
+
+ unsigned int irq;
+ unsigned int intr_type;
+ bool exclusive_vectors;
+ struct msix_entry msix_entries[VMCI_MAX_INTRS];
+
+ struct tasklet_struct datagram_tasklet;
+ struct tasklet_struct bm_tasklet;
+
+ void *data_buffer;
+ void *notification_bitmap;
+};
+
+/* vmci_dev singleton device and supporting data*/
+static struct vmci_guest_device *vmci_dev_g;
+static DEFINE_SPINLOCK(vmci_dev_spinlock);
+
+static atomic_t vmci_num_guest_devices = ATOMIC_INIT(0);
+
+bool vmci_guest_code_active(void)
+{
+ return atomic_read(&vmci_num_guest_devices) != 0;
+}
+
+u32 vmci_get_vm_context_id(void)
+{
+ if (vm_context_id == VMCI_INVALID_ID) {
+ struct vmci_datagram get_cid_msg;
+ get_cid_msg.dst =
+ vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_GET_CONTEXT_ID);
+ get_cid_msg.src = VMCI_ANON_SRC_HANDLE;
+ get_cid_msg.payload_size = 0;
+ vm_context_id = vmci_send_datagram(&get_cid_msg);
+ }
+ return vm_context_id;
+}
+
+/*
+ * VM to hypervisor call mechanism. We use the standard VMware naming
+ * convention since shared code is calling this function as well.
+ */
+int vmci_send_datagram(struct vmci_datagram *dg)
+{
+ unsigned long flags;
+ int result;
+
+ /* Check args. */
+ if (dg == NULL)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ /*
+ * Need to acquire spinlock on the device because the datagram
+ * data may be spread over multiple pages and the monitor may
+ * interleave device user rpc calls from multiple
+ * VCPUs. Acquiring the spinlock precludes that
+ * possibility. Disabling interrupts to avoid incoming
+ * datagrams during a "rep out" and possibly landing up in
+ * this function.
+ */
+ spin_lock_irqsave(&vmci_dev_spinlock, flags);
+
+ if (vmci_dev_g) {
+ iowrite8_rep(vmci_dev_g->iobase + VMCI_DATA_OUT_ADDR,
+ dg, VMCI_DG_SIZE(dg));
+ result = ioread32(vmci_dev_g->iobase + VMCI_RESULT_LOW_ADDR);
+ } else {
+ result = VMCI_ERROR_UNAVAILABLE;
+ }
+
+ spin_unlock_irqrestore(&vmci_dev_spinlock, flags);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_send_datagram);
+
+/*
+ * Gets called with the new context id if updated or resumed.
+ * Context id.
+ */
+static void vmci_guest_cid_update(u32 sub_id,
+ const struct vmci_event_data *event_data,
+ void *client_data)
+{
+ const struct vmci_event_payld_ctx *ev_payload =
+ vmci_event_data_const_payload(event_data);
+
+ if (sub_id != ctx_update_sub_id) {
+ pr_devel("Invalid subscriber (ID=0x%x)\n", sub_id);
+ return;
+ }
+
+ if (!event_data || ev_payload->context_id == VMCI_INVALID_ID) {
+ pr_devel("Invalid event data\n");
+ return;
+ }
+
+ pr_devel("Updating context from (ID=0x%x) to (ID=0x%x) on event (type=%d)\n",
+ vm_context_id, ev_payload->context_id, event_data->event);
+
+ vm_context_id = ev_payload->context_id;
+}
+
+/*
+ * Verify that the host supports the hypercalls we need. If it does not,
+ * try to find fallback hypercalls and use those instead. Returns
+ * true if required hypercalls (or fallback hypercalls) are
+ * supported by the host, false otherwise.
+ */
+static bool vmci_check_host_caps(struct pci_dev *pdev)
+{
+ bool result;
+ struct vmci_resource_query_msg *msg;
+ u32 msg_size = sizeof(struct vmci_resource_query_hdr) +
+ VMCI_UTIL_NUM_RESOURCES * sizeof(u32);
+ struct vmci_datagram *check_msg;
+
+ check_msg = kmalloc(msg_size, GFP_KERNEL);
+ if (!check_msg) {
+ dev_err(&pdev->dev, "%s: Insufficient memory\n", __func__);
+ return false;
+ }
+
+ check_msg->dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_RESOURCES_QUERY);
+ check_msg->src = VMCI_ANON_SRC_HANDLE;
+ check_msg->payload_size = msg_size - VMCI_DG_HEADERSIZE;
+ msg = (struct vmci_resource_query_msg *)VMCI_DG_PAYLOAD(check_msg);
+
+ msg->num_resources = VMCI_UTIL_NUM_RESOURCES;
+ msg->resources[0] = VMCI_GET_CONTEXT_ID;
+
+ /* Checks that hyper calls are supported */
+ result = vmci_send_datagram(check_msg) == 0x01;
+ kfree(check_msg);
+
+ dev_dbg(&pdev->dev, "%s: Host capability check: %s\n",
+ __func__, result ? "PASSED" : "FAILED");
+
+ /* We need the vector. There are no fallbacks. */
+ return result;
+}
+
+/*
+ * Reads datagrams from the data in port and dispatches them. We
+ * always start reading datagrams into only the first page of the
+ * datagram buffer. If the datagrams don't fit into one page, we
+ * use the maximum datagram buffer size for the remainder of the
+ * invocation. This is a simple heuristic for not penalizing
+ * small datagrams.
+ *
+ * This function assumes that it has exclusive access to the data
+ * in port for the duration of the call.
+ */
+static void vmci_dispatch_dgs(unsigned long data)
+{
+ struct vmci_guest_device *vmci_dev = (struct vmci_guest_device *)data;
+ u8 *dg_in_buffer = vmci_dev->data_buffer;
+ struct vmci_datagram *dg;
+ size_t dg_in_buffer_size = VMCI_MAX_DG_SIZE;
+ size_t current_dg_in_buffer_size = PAGE_SIZE;
+ size_t remaining_bytes;
+
+ BUILD_BUG_ON(VMCI_MAX_DG_SIZE < PAGE_SIZE);
+
+ ioread8_rep(vmci_dev->iobase + VMCI_DATA_IN_ADDR,
+ vmci_dev->data_buffer, current_dg_in_buffer_size);
+ dg = (struct vmci_datagram *)dg_in_buffer;
+ remaining_bytes = current_dg_in_buffer_size;
+
+ while (dg->dst.resource != VMCI_INVALID_ID ||
+ remaining_bytes > PAGE_SIZE) {
+ unsigned dg_in_size;
+
+ /*
+ * When the input buffer spans multiple pages, a datagram can
+ * start on any page boundary in the buffer.
+ */
+ if (dg->dst.resource == VMCI_INVALID_ID) {
+ dg = (struct vmci_datagram *)roundup(
+ (uintptr_t)dg + 1, PAGE_SIZE);
+ remaining_bytes =
+ (size_t)(dg_in_buffer +
+ current_dg_in_buffer_size -
+ (u8 *)dg);
+ continue;
+ }
+
+ dg_in_size = VMCI_DG_SIZE_ALIGNED(dg);
+
+ if (dg_in_size <= dg_in_buffer_size) {
+ int result;
+
+ /*
+ * If the remaining bytes in the datagram
+ * buffer doesn't contain the complete
+ * datagram, we first make sure we have enough
+ * room for it and then we read the reminder
+ * of the datagram and possibly any following
+ * datagrams.
+ */
+ if (dg_in_size > remaining_bytes) {
+ if (remaining_bytes !=
+ current_dg_in_buffer_size) {
+
+ /*
+ * We move the partial
+ * datagram to the front and
+ * read the reminder of the
+ * datagram and possibly
+ * following calls into the
+ * following bytes.
+ */
+ memmove(dg_in_buffer, dg_in_buffer +
+ current_dg_in_buffer_size -
+ remaining_bytes,
+ remaining_bytes);
+ dg = (struct vmci_datagram *)
+ dg_in_buffer;
+ }
+
+ if (current_dg_in_buffer_size !=
+ dg_in_buffer_size)
+ current_dg_in_buffer_size =
+ dg_in_buffer_size;
+
+ ioread8_rep(vmci_dev->iobase +
+ VMCI_DATA_IN_ADDR,
+ vmci_dev->data_buffer +
+ remaining_bytes,
+ current_dg_in_buffer_size -
+ remaining_bytes);
+ }
+
+ /*
+ * We special case event datagrams from the
+ * hypervisor.
+ */
+ if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
+ dg->dst.resource == VMCI_EVENT_HANDLER) {
+ result = vmci_event_dispatch(dg);
+ } else {
+ result = vmci_datagram_invoke_guest_handler(dg);
+ }
+ if (result < VMCI_SUCCESS)
+ dev_dbg(vmci_dev->dev,
+ "Datagram with resource (ID=0x%x) failed (err=%d)\n",
+ dg->dst.resource, result);
+
+ /* On to the next datagram. */
+ dg = (struct vmci_datagram *)((u8 *)dg +
+ dg_in_size);
+ } else {
+ size_t bytes_to_skip;
+
+ /*
+ * Datagram doesn't fit in datagram buffer of maximal
+ * size. We drop it.
+ */
+ dev_dbg(vmci_dev->dev,
+ "Failed to receive datagram (size=%u bytes)\n",
+ dg_in_size);
+
+ bytes_to_skip = dg_in_size - remaining_bytes;
+ if (current_dg_in_buffer_size != dg_in_buffer_size)
+ current_dg_in_buffer_size = dg_in_buffer_size;
+
+ for (;;) {
+ ioread8_rep(vmci_dev->iobase +
+ VMCI_DATA_IN_ADDR,
+ vmci_dev->data_buffer,
+ current_dg_in_buffer_size);
+ if (bytes_to_skip <= current_dg_in_buffer_size)
+ break;
+
+ bytes_to_skip -= current_dg_in_buffer_size;
+ }
+ dg = (struct vmci_datagram *)(dg_in_buffer +
+ bytes_to_skip);
+ }
+
+ remaining_bytes =
+ (size_t) (dg_in_buffer + current_dg_in_buffer_size -
+ (u8 *)dg);
+
+ if (remaining_bytes < VMCI_DG_HEADERSIZE) {
+ /* Get the next batch of datagrams. */
+
+ ioread8_rep(vmci_dev->iobase + VMCI_DATA_IN_ADDR,
+ vmci_dev->data_buffer,
+ current_dg_in_buffer_size);
+ dg = (struct vmci_datagram *)dg_in_buffer;
+ remaining_bytes = current_dg_in_buffer_size;
+ }
+ }
+}
+
+/*
+ * Scans the notification bitmap for raised flags, clears them
+ * and handles the notifications.
+ */
+static void vmci_process_bitmap(unsigned long data)
+{
+ struct vmci_guest_device *dev = (struct vmci_guest_device *)data;
+
+ if (!dev->notification_bitmap) {
+ dev_dbg(dev->dev, "No bitmap present in %s\n", __func__);
+ return;
+ }
+
+ vmci_dbell_scan_notification_entries(dev->notification_bitmap);
+}
+
+/*
+ * Enable MSI-X. Try exclusive vectors first, then shared vectors.
+ */
+static int vmci_enable_msix(struct pci_dev *pdev,
+ struct vmci_guest_device *vmci_dev)
+{
+ int i;
+ int result;
+
+ for (i = 0; i < VMCI_MAX_INTRS; ++i) {
+ vmci_dev->msix_entries[i].entry = i;
+ vmci_dev->msix_entries[i].vector = i;
+ }
+
+ result = pci_enable_msix(pdev, vmci_dev->msix_entries, VMCI_MAX_INTRS);
+ if (result == 0)
+ vmci_dev->exclusive_vectors = true;
+ else if (result > 0)
+ result = pci_enable_msix(pdev, vmci_dev->msix_entries, 1);
+
+ return result;
+}
+
+/*
+ * Interrupt handler for legacy or MSI interrupt, or for first MSI-X
+ * interrupt (vector VMCI_INTR_DATAGRAM).
+ */
+static irqreturn_t vmci_interrupt(int irq, void *_dev)
+{
+ struct vmci_guest_device *dev = _dev;
+
+ /*
+ * If we are using MSI-X with exclusive vectors then we simply schedule
+ * the datagram tasklet, since we know the interrupt was meant for us.
+ * Otherwise we must read the ICR to determine what to do.
+ */
+
+ if (dev->intr_type == VMCI_INTR_TYPE_MSIX && dev->exclusive_vectors) {
+ tasklet_schedule(&dev->datagram_tasklet);
+ } else {
+ unsigned int icr;
+
+ /* Acknowledge interrupt and determine what needs doing. */
+ icr = ioread32(dev->iobase + VMCI_ICR_ADDR);
+ if (icr == 0 || icr == ~0)
+ return IRQ_NONE;
+
+ if (icr & VMCI_ICR_DATAGRAM) {
+ tasklet_schedule(&dev->datagram_tasklet);
+ icr &= ~VMCI_ICR_DATAGRAM;
+ }
+
+ if (icr & VMCI_ICR_NOTIFICATION) {
+ tasklet_schedule(&dev->bm_tasklet);
+ icr &= ~VMCI_ICR_NOTIFICATION;
+ }
+
+ if (icr != 0)
+ dev_warn(dev->dev,
+ "Ignoring unknown interrupt cause (%d)\n",
+ icr);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Interrupt handler for MSI-X interrupt vector VMCI_INTR_NOTIFICATION,
+ * which is for the notification bitmap. Will only get called if we are
+ * using MSI-X with exclusive vectors.
+ */
+static irqreturn_t vmci_interrupt_bm(int irq, void *_dev)
+{
+ struct vmci_guest_device *dev = _dev;
+
+ /* For MSI-X we can just assume it was meant for us. */
+ tasklet_schedule(&dev->bm_tasklet);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Most of the initialization at module load time is done here.
+ */
+static int vmci_guest_probe_device(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct vmci_guest_device *vmci_dev;
+ void __iomem *iobase;
+ unsigned int capabilities;
+ unsigned long cmd;
+ int vmci_err;
+ int error;
+
+ dev_dbg(&pdev->dev, "Probing for vmci/PCI guest device\n");
+
+ error = pcim_enable_device(pdev);
+ if (error) {
+ dev_err(&pdev->dev,
+ "Failed to enable VMCI device: %d\n", error);
+ return error;
+ }
+
+ error = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
+ if (error) {
+ dev_err(&pdev->dev, "Failed to reserve/map IO regions\n");
+ return error;
+ }
+
+ iobase = pcim_iomap_table(pdev)[0];
+
+ dev_info(&pdev->dev, "Found VMCI PCI device at %#lx, irq %u\n",
+ (unsigned long)iobase, pdev->irq);
+
+ vmci_dev = devm_kzalloc(&pdev->dev, sizeof(*vmci_dev), GFP_KERNEL);
+ if (!vmci_dev) {
+ dev_err(&pdev->dev,
+ "Can't allocate memory for VMCI device\n");
+ return -ENOMEM;
+ }
+
+ vmci_dev->dev = &pdev->dev;
+ vmci_dev->intr_type = VMCI_INTR_TYPE_INTX;
+ vmci_dev->exclusive_vectors = false;
+ vmci_dev->iobase = iobase;
+
+ tasklet_init(&vmci_dev->datagram_tasklet,
+ vmci_dispatch_dgs, (unsigned long)vmci_dev);
+ tasklet_init(&vmci_dev->bm_tasklet,
+ vmci_process_bitmap, (unsigned long)vmci_dev);
+
+ vmci_dev->data_buffer = vmalloc(VMCI_MAX_DG_SIZE);
+ if (!vmci_dev->data_buffer) {
+ dev_err(&pdev->dev,
+ "Can't allocate memory for datagram buffer\n");
+ return -ENOMEM;
+ }
+
+ pci_set_master(pdev); /* To enable queue_pair functionality. */
+
+ /*
+ * Verify that the VMCI Device supports the capabilities that
+ * we need. If the device is missing capabilities that we would
+ * like to use, check for fallback capabilities and use those
+ * instead (so we can run a new VM on old hosts). Fail the load if
+ * a required capability is missing and there is no fallback.
+ *
+ * Right now, we need datagrams. There are no fallbacks.
+ */
+ capabilities = ioread32(vmci_dev->iobase + VMCI_CAPS_ADDR);
+ if (!(capabilities & VMCI_CAPS_DATAGRAM)) {
+ dev_err(&pdev->dev, "Device does not support datagrams\n");
+ error = -ENXIO;
+ goto err_free_data_buffer;
+ }
+
+ /*
+ * If the hardware supports notifications, we will use that as
+ * well.
+ */
+ if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
+ vmci_dev->notification_bitmap = vmalloc(PAGE_SIZE);
+ if (!vmci_dev->notification_bitmap) {
+ dev_warn(&pdev->dev,
+ "Unable to allocate notification bitmap\n");
+ } else {
+ memset(vmci_dev->notification_bitmap, 0, PAGE_SIZE);
+ capabilities |= VMCI_CAPS_NOTIFICATIONS;
+ }
+ }
+
+ dev_info(&pdev->dev, "Using capabilities 0x%x\n", capabilities);
+
+ /* Let the host know which capabilities we intend to use. */
+ iowrite32(capabilities, vmci_dev->iobase + VMCI_CAPS_ADDR);
+
+ /* Set up global device so that we can start sending datagrams */
+ spin_lock_irq(&vmci_dev_spinlock);
+ vmci_dev_g = vmci_dev;
+ spin_unlock_irq(&vmci_dev_spinlock);
+
+ /*
+ * Register notification bitmap with device if that capability is
+ * used.
+ */
+ if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
+ struct page *page =
+ vmalloc_to_page(vmci_dev->notification_bitmap);
+ unsigned long bitmap_ppn = page_to_pfn(page);
+ if (!vmci_dbell_register_notification_bitmap(bitmap_ppn)) {
+ dev_warn(&pdev->dev,
+ "VMCI device unable to register notification bitmap with PPN 0x%x\n",
+ (u32) bitmap_ppn);
+ goto err_remove_vmci_dev_g;
+ }
+ }
+
+ /* Check host capabilities. */
+ if (!vmci_check_host_caps(pdev))
+ goto err_remove_bitmap;
+
+ /* Enable device. */
+
+ /*
+ * We subscribe to the VMCI_EVENT_CTX_ID_UPDATE here so we can
+ * update the internal context id when needed.
+ */
+ vmci_err = vmci_event_subscribe(VMCI_EVENT_CTX_ID_UPDATE,
+ vmci_guest_cid_update, NULL,
+ &ctx_update_sub_id);
+ if (vmci_err < VMCI_SUCCESS)
+ dev_warn(&pdev->dev,
+ "Failed to subscribe to event (type=%d): %d\n",
+ VMCI_EVENT_CTX_ID_UPDATE, vmci_err);
+
+ /*
+ * Enable interrupts. Try MSI-X first, then MSI, and then fallback on
+ * legacy interrupts.
+ */
+ if (!vmci_disable_msix && !vmci_enable_msix(pdev, vmci_dev)) {
+ vmci_dev->intr_type = VMCI_INTR_TYPE_MSIX;
+ vmci_dev->irq = vmci_dev->msix_entries[0].vector;
+ } else if (!vmci_disable_msi && !pci_enable_msi(pdev)) {
+ vmci_dev->intr_type = VMCI_INTR_TYPE_MSI;
+ vmci_dev->irq = pdev->irq;
+ } else {
+ vmci_dev->intr_type = VMCI_INTR_TYPE_INTX;
+ vmci_dev->irq = pdev->irq;
+ }
+
+ /*
+ * Request IRQ for legacy or MSI interrupts, or for first
+ * MSI-X vector.
+ */
+ error = request_irq(vmci_dev->irq, vmci_interrupt, IRQF_SHARED,
+ KBUILD_MODNAME, vmci_dev);
+ if (error) {
+ dev_err(&pdev->dev, "Irq %u in use: %d\n",
+ vmci_dev->irq, error);
+ goto err_disable_msi;
+ }
+
+ /*
+ * For MSI-X with exclusive vectors we need to request an
+ * interrupt for each vector so that we get a separate
+ * interrupt handler routine. This allows us to distinguish
+ * between the vectors.
+ */
+ if (vmci_dev->exclusive_vectors) {
+ error = request_irq(vmci_dev->msix_entries[1].vector,
+ vmci_interrupt_bm, 0, KBUILD_MODNAME,
+ vmci_dev);
+ if (error) {
+ dev_err(&pdev->dev,
+ "Failed to allocate irq %u: %d\n",
+ vmci_dev->msix_entries[1].vector, error);
+ goto err_free_irq;
+ }
+ }
+
+ dev_dbg(&pdev->dev, "Registered device\n");
+
+ atomic_inc(&vmci_num_guest_devices);
+
+ /* Enable specific interrupt bits. */
+ cmd = VMCI_IMR_DATAGRAM;
+ if (capabilities & VMCI_CAPS_NOTIFICATIONS)
+ cmd |= VMCI_IMR_NOTIFICATION;
+ iowrite32(cmd, vmci_dev->iobase + VMCI_IMR_ADDR);
+
+ /* Enable interrupts. */
+ iowrite32(VMCI_CONTROL_INT_ENABLE,
+ vmci_dev->iobase + VMCI_CONTROL_ADDR);
+
+ pci_set_drvdata(pdev, vmci_dev);
+ return 0;
+
+err_free_irq:
+ free_irq(vmci_dev->irq, &vmci_dev);
+ tasklet_kill(&vmci_dev->datagram_tasklet);
+ tasklet_kill(&vmci_dev->bm_tasklet);
+
+err_disable_msi:
+ if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSIX)
+ pci_disable_msix(pdev);
+ else if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSI)
+ pci_disable_msi(pdev);
+
+ vmci_err = vmci_event_unsubscribe(ctx_update_sub_id);
+ if (vmci_err < VMCI_SUCCESS)
+ dev_warn(&pdev->dev,
+ "Failed to unsubscribe from event (type=%d) with subscriber (ID=0x%x): %d\n",
+ VMCI_EVENT_CTX_ID_UPDATE, ctx_update_sub_id, vmci_err);
+
+err_remove_bitmap:
+ if (vmci_dev->notification_bitmap) {
+ iowrite32(VMCI_CONTROL_RESET,
+ vmci_dev->iobase + VMCI_CONTROL_ADDR);
+ vfree(vmci_dev->notification_bitmap);
+ }
+
+err_remove_vmci_dev_g:
+ spin_lock_irq(&vmci_dev_spinlock);
+ vmci_dev_g = NULL;
+ spin_unlock_irq(&vmci_dev_spinlock);
+
+err_free_data_buffer:
+ vfree(vmci_dev->data_buffer);
+
+ /* The rest are managed resources and will be freed by PCI core */
+ return error;
+}
+
+static void vmci_guest_remove_device(struct pci_dev *pdev)
+{
+ struct vmci_guest_device *vmci_dev = pci_get_drvdata(pdev);
+ int vmci_err;
+
+ dev_dbg(&pdev->dev, "Removing device\n");
+
+ atomic_dec(&vmci_num_guest_devices);
+
+ vmci_qp_guest_endpoints_exit();
+
+ vmci_err = vmci_event_unsubscribe(ctx_update_sub_id);
+ if (vmci_err < VMCI_SUCCESS)
+ dev_warn(&pdev->dev,
+ "Failed to unsubscribe from event (type=%d) with subscriber (ID=0x%x): %d\n",
+ VMCI_EVENT_CTX_ID_UPDATE, ctx_update_sub_id, vmci_err);
+
+ spin_lock_irq(&vmci_dev_spinlock);
+ vmci_dev_g = NULL;
+ spin_unlock_irq(&vmci_dev_spinlock);
+
+ dev_dbg(&pdev->dev, "Resetting vmci device\n");
+ iowrite32(VMCI_CONTROL_RESET, vmci_dev->iobase + VMCI_CONTROL_ADDR);
+
+ /*
+ * Free IRQ and then disable MSI/MSI-X as appropriate. For
+ * MSI-X, we might have multiple vectors, each with their own
+ * IRQ, which we must free too.
+ */
+ free_irq(vmci_dev->irq, vmci_dev);
+ if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSIX) {
+ if (vmci_dev->exclusive_vectors)
+ free_irq(vmci_dev->msix_entries[1].vector, vmci_dev);
+ pci_disable_msix(pdev);
+ } else if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSI) {
+ pci_disable_msi(pdev);
+ }
+
+ tasklet_kill(&vmci_dev->datagram_tasklet);
+ tasklet_kill(&vmci_dev->bm_tasklet);
+
+ if (vmci_dev->notification_bitmap) {
+ /*
+ * The device reset above cleared the bitmap state of the
+ * device, so we can safely free it here.
+ */
+
+ vfree(vmci_dev->notification_bitmap);
+ }
+
+ vfree(vmci_dev->data_buffer);
+
+ /* The rest are managed resources and will be freed by PCI core */
+}
+
+static DEFINE_PCI_DEVICE_TABLE(vmci_ids) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_VMCI), },
+ { 0 },
+};
+MODULE_DEVICE_TABLE(pci, vmci_ids);
+
+static struct pci_driver vmci_guest_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = vmci_ids,
+ .probe = vmci_guest_probe_device,
+ .remove = vmci_guest_remove_device,
+};
+
+int __init vmci_guest_init(void)
+{
+ return pci_register_driver(&vmci_guest_driver);
+}
+
+void __exit vmci_guest_exit(void)
+{
+ pci_unregister_driver(&vmci_guest_driver);
+}
diff --git a/drivers/misc/vmw_vmci/vmci_handle_array.c b/drivers/misc/vmw_vmci/vmci_handle_array.c
new file mode 100644
index 000000000000..344973a0fb0a
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_handle_array.c
@@ -0,0 +1,142 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/slab.h>
+#include "vmci_handle_array.h"
+
+static size_t handle_arr_calc_size(size_t capacity)
+{
+ return sizeof(struct vmci_handle_arr) +
+ capacity * sizeof(struct vmci_handle);
+}
+
+struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity)
+{
+ struct vmci_handle_arr *array;
+
+ if (capacity == 0)
+ capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE;
+
+ array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC);
+ if (!array)
+ return NULL;
+
+ array->capacity = capacity;
+ array->size = 0;
+
+ return array;
+}
+
+void vmci_handle_arr_destroy(struct vmci_handle_arr *array)
+{
+ kfree(array);
+}
+
+void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
+ struct vmci_handle handle)
+{
+ struct vmci_handle_arr *array = *array_ptr;
+
+ if (unlikely(array->size >= array->capacity)) {
+ /* reallocate. */
+ struct vmci_handle_arr *new_array;
+ size_t new_capacity = array->capacity * VMCI_ARR_CAP_MULT;
+ size_t new_size = handle_arr_calc_size(new_capacity);
+
+ new_array = krealloc(array, new_size, GFP_ATOMIC);
+ if (!new_array)
+ return;
+
+ new_array->capacity = new_capacity;
+ *array_ptr = array = new_array;
+ }
+
+ array->entries[array->size] = handle;
+ array->size++;
+}
+
+/*
+ * Handle that was removed, VMCI_INVALID_HANDLE if entry not found.
+ */
+struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
+ struct vmci_handle entry_handle)
+{
+ struct vmci_handle handle = VMCI_INVALID_HANDLE;
+ size_t i;
+
+ for (i = 0; i < array->size; i++) {
+ if (vmci_handle_is_equal(array->entries[i], entry_handle)) {
+ handle = array->entries[i];
+ array->size--;
+ array->entries[i] = array->entries[array->size];
+ array->entries[array->size] = VMCI_INVALID_HANDLE;
+ break;
+ }
+ }
+
+ return handle;
+}
+
+/*
+ * Handle that was removed, VMCI_INVALID_HANDLE if array was empty.
+ */
+struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array)
+{
+ struct vmci_handle handle = VMCI_INVALID_HANDLE;
+
+ if (array->size) {
+ array->size--;
+ handle = array->entries[array->size];
+ array->entries[array->size] = VMCI_INVALID_HANDLE;
+ }
+
+ return handle;
+}
+
+/*
+ * Handle at given index, VMCI_INVALID_HANDLE if invalid index.
+ */
+struct vmci_handle
+vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index)
+{
+ if (unlikely(index >= array->size))
+ return VMCI_INVALID_HANDLE;
+
+ return array->entries[index];
+}
+
+bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
+ struct vmci_handle entry_handle)
+{
+ size_t i;
+
+ for (i = 0; i < array->size; i++)
+ if (vmci_handle_is_equal(array->entries[i], entry_handle))
+ return true;
+
+ return false;
+}
+
+/*
+ * NULL if the array is empty. Otherwise, a pointer to the array
+ * of VMCI handles in the handle array.
+ */
+struct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array)
+{
+ if (array->size)
+ return array->entries;
+
+ return NULL;
+}
diff --git a/drivers/misc/vmw_vmci/vmci_handle_array.h b/drivers/misc/vmw_vmci/vmci_handle_array.h
new file mode 100644
index 000000000000..b5f3a7f98cf1
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_handle_array.h
@@ -0,0 +1,52 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _VMCI_HANDLE_ARRAY_H_
+#define _VMCI_HANDLE_ARRAY_H_
+
+#include <linux/vmw_vmci_defs.h>
+#include <linux/types.h>
+
+#define VMCI_HANDLE_ARRAY_DEFAULT_SIZE 4
+#define VMCI_ARR_CAP_MULT 2 /* Array capacity multiplier */
+
+struct vmci_handle_arr {
+ size_t capacity;
+ size_t size;
+ struct vmci_handle entries[];
+};
+
+struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity);
+void vmci_handle_arr_destroy(struct vmci_handle_arr *array);
+void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
+ struct vmci_handle handle);
+struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
+ struct vmci_handle
+ entry_handle);
+struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array);
+struct vmci_handle
+vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index);
+bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
+ struct vmci_handle entry_handle);
+struct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array);
+
+static inline size_t vmci_handle_arr_get_size(
+ const struct vmci_handle_arr *array)
+{
+ return array->size;
+}
+
+
+#endif /* _VMCI_HANDLE_ARRAY_H_ */
diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c
new file mode 100644
index 000000000000..d4722b3dc8ec
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_host.c
@@ -0,0 +1,1043 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/atomic.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/smp.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+
+#include "vmci_handle_array.h"
+#include "vmci_queue_pair.h"
+#include "vmci_datagram.h"
+#include "vmci_doorbell.h"
+#include "vmci_resource.h"
+#include "vmci_context.h"
+#include "vmci_driver.h"
+#include "vmci_event.h"
+
+#define VMCI_UTIL_NUM_RESOURCES 1
+
+enum {
+ VMCI_NOTIFY_RESOURCE_QUEUE_PAIR = 0,
+ VMCI_NOTIFY_RESOURCE_DOOR_BELL = 1,
+};
+
+enum {
+ VMCI_NOTIFY_RESOURCE_ACTION_NOTIFY = 0,
+ VMCI_NOTIFY_RESOURCE_ACTION_CREATE = 1,
+ VMCI_NOTIFY_RESOURCE_ACTION_DESTROY = 2,
+};
+
+/*
+ * VMCI driver initialization. This block can also be used to
+ * pass initial group membership etc.
+ */
+struct vmci_init_blk {
+ u32 cid;
+ u32 flags;
+};
+
+/* VMCIqueue_pairAllocInfo_VMToVM */
+struct vmci_qp_alloc_info_vmvm {
+ struct vmci_handle handle;
+ u32 peer;
+ u32 flags;
+ u64 produce_size;
+ u64 consume_size;
+ u64 produce_page_file; /* User VA. */
+ u64 consume_page_file; /* User VA. */
+ u64 produce_page_file_size; /* Size of the file name array. */
+ u64 consume_page_file_size; /* Size of the file name array. */
+ s32 result;
+ u32 _pad;
+};
+
+/* VMCISetNotifyInfo: Used to pass notify flag's address to the host driver. */
+struct vmci_set_notify_info {
+ u64 notify_uva;
+ s32 result;
+ u32 _pad;
+};
+
+/*
+ * Per-instance host state
+ */
+struct vmci_host_dev {
+ struct vmci_ctx *context;
+ int user_version;
+ enum vmci_obj_type ct_type;
+ struct mutex lock; /* Mutex lock for vmci context access */
+};
+
+static struct vmci_ctx *host_context;
+static bool vmci_host_device_initialized;
+static atomic_t vmci_host_active_users = ATOMIC_INIT(0);
+
+/*
+ * Determines whether the VMCI host personality is
+ * available. Since the core functionality of the host driver is
+ * always present, all guests could possibly use the host
+ * personality. However, to minimize the deviation from the
+ * pre-unified driver state of affairs, we only consider the host
+ * device active if there is no active guest device or if there
+ * are VMX'en with active VMCI contexts using the host device.
+ */
+bool vmci_host_code_active(void)
+{
+ return vmci_host_device_initialized &&
+ (!vmci_guest_code_active() ||
+ atomic_read(&vmci_host_active_users) > 0);
+}
+
+/*
+ * Called on open of /dev/vmci.
+ */
+static int vmci_host_open(struct inode *inode, struct file *filp)
+{
+ struct vmci_host_dev *vmci_host_dev;
+
+ vmci_host_dev = kzalloc(sizeof(struct vmci_host_dev), GFP_KERNEL);
+ if (vmci_host_dev == NULL)
+ return -ENOMEM;
+
+ vmci_host_dev->ct_type = VMCIOBJ_NOT_SET;
+ mutex_init(&vmci_host_dev->lock);
+ filp->private_data = vmci_host_dev;
+
+ return 0;
+}
+
+/*
+ * Called on close of /dev/vmci, most often when the process
+ * exits.
+ */
+static int vmci_host_close(struct inode *inode, struct file *filp)
+{
+ struct vmci_host_dev *vmci_host_dev = filp->private_data;
+
+ if (vmci_host_dev->ct_type == VMCIOBJ_CONTEXT) {
+ vmci_ctx_destroy(vmci_host_dev->context);
+ vmci_host_dev->context = NULL;
+
+ /*
+ * The number of active contexts is used to track whether any
+ * VMX'en are using the host personality. It is incremented when
+ * a context is created through the IOCTL_VMCI_INIT_CONTEXT
+ * ioctl.
+ */
+ atomic_dec(&vmci_host_active_users);
+ }
+ vmci_host_dev->ct_type = VMCIOBJ_NOT_SET;
+
+ kfree(vmci_host_dev);
+ filp->private_data = NULL;
+ return 0;
+}
+
+/*
+ * This is used to wake up the VMX when a VMCI call arrives, or
+ * to wake up select() or poll() at the next clock tick.
+ */
+static unsigned int vmci_host_poll(struct file *filp, poll_table *wait)
+{
+ struct vmci_host_dev *vmci_host_dev = filp->private_data;
+ struct vmci_ctx *context = vmci_host_dev->context;
+ unsigned int mask = 0;
+
+ if (vmci_host_dev->ct_type == VMCIOBJ_CONTEXT) {
+ /* Check for VMCI calls to this VM context. */
+ if (wait)
+ poll_wait(filp, &context->host_context.wait_queue,
+ wait);
+
+ spin_lock(&context->lock);
+ if (context->pending_datagrams > 0 ||
+ vmci_handle_arr_get_size(
+ context->pending_doorbell_array) > 0) {
+ mask = POLLIN;
+ }
+ spin_unlock(&context->lock);
+ }
+ return mask;
+}
+
+/*
+ * Copies the handles of a handle array into a user buffer, and
+ * returns the new length in userBufferSize. If the copy to the
+ * user buffer fails, the functions still returns VMCI_SUCCESS,
+ * but retval != 0.
+ */
+static int drv_cp_harray_to_user(void __user *user_buf_uva,
+ u64 *user_buf_size,
+ struct vmci_handle_arr *handle_array,
+ int *retval)
+{
+ u32 array_size = 0;
+ struct vmci_handle *handles;
+
+ if (handle_array)
+ array_size = vmci_handle_arr_get_size(handle_array);
+
+ if (array_size * sizeof(*handles) > *user_buf_size)
+ return VMCI_ERROR_MORE_DATA;
+
+ *user_buf_size = array_size * sizeof(*handles);
+ if (*user_buf_size)
+ *retval = copy_to_user(user_buf_uva,
+ vmci_handle_arr_get_handles
+ (handle_array), *user_buf_size);
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Sets up a given context for notify to work. Calls drv_map_bool_ptr()
+ * which maps the notify boolean in user VA in kernel space.
+ */
+static int vmci_host_setup_notify(struct vmci_ctx *context,
+ unsigned long uva)
+{
+ struct page *page;
+ int retval;
+
+ if (context->notify_page) {
+ pr_devel("%s: Notify mechanism is already set up\n", __func__);
+ return VMCI_ERROR_DUPLICATE_ENTRY;
+ }
+
+ /*
+ * We are using 'bool' internally, but let's make sure we explicit
+ * about the size.
+ */
+ BUILD_BUG_ON(sizeof(bool) != sizeof(u8));
+ if (!access_ok(VERIFY_WRITE, (void __user *)uva, sizeof(u8)))
+ return VMCI_ERROR_GENERIC;
+
+ /*
+ * Lock physical page backing a given user VA.
+ */
+ down_read(&current->mm->mmap_sem);
+ retval = get_user_pages(current, current->mm,
+ PAGE_ALIGN(uva),
+ 1, 1, 0, &page, NULL);
+ up_read(&current->mm->mmap_sem);
+ if (retval != 1)
+ return VMCI_ERROR_GENERIC;
+
+ /*
+ * Map the locked page and set up notify pointer.
+ */
+ context->notify = kmap(page) + (uva & (PAGE_SIZE - 1));
+ vmci_ctx_check_signal_notify(context);
+
+ return VMCI_SUCCESS;
+}
+
+static int vmci_host_get_version(struct vmci_host_dev *vmci_host_dev,
+ unsigned int cmd, void __user *uptr)
+{
+ if (cmd == IOCTL_VMCI_VERSION2) {
+ int __user *vptr = uptr;
+ if (get_user(vmci_host_dev->user_version, vptr))
+ return -EFAULT;
+ }
+
+ /*
+ * The basic logic here is:
+ *
+ * If the user sends in a version of 0 tell it our version.
+ * If the user didn't send in a version, tell it our version.
+ * If the user sent in an old version, tell it -its- version.
+ * If the user sent in an newer version, tell it our version.
+ *
+ * The rationale behind telling the caller its version is that
+ * Workstation 6.5 required that VMX and VMCI kernel module were
+ * version sync'd. All new VMX users will be programmed to
+ * handle the VMCI kernel module version.
+ */
+
+ if (vmci_host_dev->user_version > 0 &&
+ vmci_host_dev->user_version < VMCI_VERSION_HOSTQP) {
+ return vmci_host_dev->user_version;
+ }
+
+ return VMCI_VERSION;
+}
+
+#define vmci_ioctl_err(fmt, ...) \
+ pr_devel("%s: " fmt, ioctl_name, ##__VA_ARGS__)
+
+static int vmci_host_do_init_context(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_init_blk init_block;
+ const struct cred *cred;
+ int retval;
+
+ if (copy_from_user(&init_block, uptr, sizeof(init_block))) {
+ vmci_ioctl_err("error reading init block\n");
+ return -EFAULT;
+ }
+
+ mutex_lock(&vmci_host_dev->lock);
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_NOT_SET) {
+ vmci_ioctl_err("received VMCI init on initialized handle\n");
+ retval = -EINVAL;
+ goto out;
+ }
+
+ if (init_block.flags & ~VMCI_PRIVILEGE_FLAG_RESTRICTED) {
+ vmci_ioctl_err("unsupported VMCI restriction flag\n");
+ retval = -EINVAL;
+ goto out;
+ }
+
+ cred = get_current_cred();
+ vmci_host_dev->context = vmci_ctx_create(init_block.cid,
+ init_block.flags, 0,
+ vmci_host_dev->user_version,
+ cred);
+ put_cred(cred);
+ if (IS_ERR(vmci_host_dev->context)) {
+ retval = PTR_ERR(vmci_host_dev->context);
+ vmci_ioctl_err("error initializing context\n");
+ goto out;
+ }
+
+ /*
+ * Copy cid to userlevel, we do this to allow the VMX
+ * to enforce its policy on cid generation.
+ */
+ init_block.cid = vmci_ctx_get_id(vmci_host_dev->context);
+ if (copy_to_user(uptr, &init_block, sizeof(init_block))) {
+ vmci_ctx_destroy(vmci_host_dev->context);
+ vmci_host_dev->context = NULL;
+ vmci_ioctl_err("error writing init block\n");
+ retval = -EFAULT;
+ goto out;
+ }
+
+ vmci_host_dev->ct_type = VMCIOBJ_CONTEXT;
+ atomic_inc(&vmci_host_active_users);
+
+ retval = 0;
+
+out:
+ mutex_unlock(&vmci_host_dev->lock);
+ return retval;
+}
+
+static int vmci_host_do_send_datagram(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_datagram_snd_rcv_info send_info;
+ struct vmci_datagram *dg = NULL;
+ u32 cid;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&send_info, uptr, sizeof(send_info)))
+ return -EFAULT;
+
+ if (send_info.len > VMCI_MAX_DG_SIZE) {
+ vmci_ioctl_err("datagram is too big (size=%d)\n",
+ send_info.len);
+ return -EINVAL;
+ }
+
+ if (send_info.len < sizeof(*dg)) {
+ vmci_ioctl_err("datagram is too small (size=%d)\n",
+ send_info.len);
+ return -EINVAL;
+ }
+
+ dg = kmalloc(send_info.len, GFP_KERNEL);
+ if (!dg) {
+ vmci_ioctl_err(
+ "cannot allocate memory to dispatch datagram\n");
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(dg, (void __user *)(uintptr_t)send_info.addr,
+ send_info.len)) {
+ vmci_ioctl_err("error getting datagram\n");
+ kfree(dg);
+ return -EFAULT;
+ }
+
+ pr_devel("Datagram dst (handle=0x%x:0x%x) src (handle=0x%x:0x%x), payload (size=%llu bytes)\n",
+ dg->dst.context, dg->dst.resource,
+ dg->src.context, dg->src.resource,
+ (unsigned long long)dg->payload_size);
+
+ /* Get source context id. */
+ cid = vmci_ctx_get_id(vmci_host_dev->context);
+ send_info.result = vmci_datagram_dispatch(cid, dg, true);
+ kfree(dg);
+
+ return copy_to_user(uptr, &send_info, sizeof(send_info)) ? -EFAULT : 0;
+}
+
+static int vmci_host_do_receive_datagram(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_datagram_snd_rcv_info recv_info;
+ struct vmci_datagram *dg = NULL;
+ int retval;
+ size_t size;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&recv_info, uptr, sizeof(recv_info)))
+ return -EFAULT;
+
+ size = recv_info.len;
+ recv_info.result = vmci_ctx_dequeue_datagram(vmci_host_dev->context,
+ &size, &dg);
+
+ if (recv_info.result >= VMCI_SUCCESS) {
+ void __user *ubuf = (void __user *)(uintptr_t)recv_info.addr;
+ retval = copy_to_user(ubuf, dg, VMCI_DG_SIZE(dg));
+ kfree(dg);
+ if (retval != 0)
+ return -EFAULT;
+ }
+
+ return copy_to_user(uptr, &recv_info, sizeof(recv_info)) ? -EFAULT : 0;
+}
+
+static int vmci_host_do_alloc_queuepair(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_handle handle;
+ int vmci_status;
+ int __user *retptr;
+ u32 cid;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ cid = vmci_ctx_get_id(vmci_host_dev->context);
+
+ if (vmci_host_dev->user_version < VMCI_VERSION_NOVMVM) {
+ struct vmci_qp_alloc_info_vmvm alloc_info;
+ struct vmci_qp_alloc_info_vmvm __user *info = uptr;
+
+ if (copy_from_user(&alloc_info, uptr, sizeof(alloc_info)))
+ return -EFAULT;
+
+ handle = alloc_info.handle;
+ retptr = &info->result;
+
+ vmci_status = vmci_qp_broker_alloc(alloc_info.handle,
+ alloc_info.peer,
+ alloc_info.flags,
+ VMCI_NO_PRIVILEGE_FLAGS,
+ alloc_info.produce_size,
+ alloc_info.consume_size,
+ NULL,
+ vmci_host_dev->context);
+
+ if (vmci_status == VMCI_SUCCESS)
+ vmci_status = VMCI_SUCCESS_QUEUEPAIR_CREATE;
+ } else {
+ struct vmci_qp_alloc_info alloc_info;
+ struct vmci_qp_alloc_info __user *info = uptr;
+ struct vmci_qp_page_store page_store;
+
+ if (copy_from_user(&alloc_info, uptr, sizeof(alloc_info)))
+ return -EFAULT;
+
+ handle = alloc_info.handle;
+ retptr = &info->result;
+
+ page_store.pages = alloc_info.ppn_va;
+ page_store.len = alloc_info.num_ppns;
+
+ vmci_status = vmci_qp_broker_alloc(alloc_info.handle,
+ alloc_info.peer,
+ alloc_info.flags,
+ VMCI_NO_PRIVILEGE_FLAGS,
+ alloc_info.produce_size,
+ alloc_info.consume_size,
+ &page_store,
+ vmci_host_dev->context);
+ }
+
+ if (put_user(vmci_status, retptr)) {
+ if (vmci_status >= VMCI_SUCCESS) {
+ vmci_status = vmci_qp_broker_detach(handle,
+ vmci_host_dev->context);
+ }
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int vmci_host_do_queuepair_setva(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_qp_set_va_info set_va_info;
+ struct vmci_qp_set_va_info __user *info = uptr;
+ s32 result;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (vmci_host_dev->user_version < VMCI_VERSION_NOVMVM) {
+ vmci_ioctl_err("is not allowed\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&set_va_info, uptr, sizeof(set_va_info)))
+ return -EFAULT;
+
+ if (set_va_info.va) {
+ /*
+ * VMX is passing down a new VA for the queue
+ * pair mapping.
+ */
+ result = vmci_qp_broker_map(set_va_info.handle,
+ vmci_host_dev->context,
+ set_va_info.va);
+ } else {
+ /*
+ * The queue pair is about to be unmapped by
+ * the VMX.
+ */
+ result = vmci_qp_broker_unmap(set_va_info.handle,
+ vmci_host_dev->context, 0);
+ }
+
+ return put_user(result, &info->result) ? -EFAULT : 0;
+}
+
+static int vmci_host_do_queuepair_setpf(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_qp_page_file_info page_file_info;
+ struct vmci_qp_page_file_info __user *info = uptr;
+ s32 result;
+
+ if (vmci_host_dev->user_version < VMCI_VERSION_HOSTQP ||
+ vmci_host_dev->user_version >= VMCI_VERSION_NOVMVM) {
+ vmci_ioctl_err("not supported on this VMX (version=%d)\n",
+ vmci_host_dev->user_version);
+ return -EINVAL;
+ }
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&page_file_info, uptr, sizeof(*info)))
+ return -EFAULT;
+
+ /*
+ * Communicate success pre-emptively to the caller. Note that the
+ * basic premise is that it is incumbent upon the caller not to look at
+ * the info.result field until after the ioctl() returns. And then,
+ * only if the ioctl() result indicates no error. We send up the
+ * SUCCESS status before calling SetPageStore() store because failing
+ * to copy up the result code means unwinding the SetPageStore().
+ *
+ * It turns out the logic to unwind a SetPageStore() opens a can of
+ * worms. For example, if a host had created the queue_pair and a
+ * guest attaches and SetPageStore() is successful but writing success
+ * fails, then ... the host has to be stopped from writing (anymore)
+ * data into the queue_pair. That means an additional test in the
+ * VMCI_Enqueue() code path. Ugh.
+ */
+
+ if (put_user(VMCI_SUCCESS, &info->result)) {
+ /*
+ * In this case, we can't write a result field of the
+ * caller's info block. So, we don't even try to
+ * SetPageStore().
+ */
+ return -EFAULT;
+ }
+
+ result = vmci_qp_broker_set_page_store(page_file_info.handle,
+ page_file_info.produce_va,
+ page_file_info.consume_va,
+ vmci_host_dev->context);
+ if (result < VMCI_SUCCESS) {
+ if (put_user(result, &info->result)) {
+ /*
+ * Note that in this case the SetPageStore()
+ * call failed but we were unable to
+ * communicate that to the caller (because the
+ * copy_to_user() call failed). So, if we
+ * simply return an error (in this case
+ * -EFAULT) then the caller will know that the
+ * SetPageStore failed even though we couldn't
+ * put the result code in the result field and
+ * indicate exactly why it failed.
+ *
+ * That says nothing about the issue where we
+ * were once able to write to the caller's info
+ * memory and now can't. Something more
+ * serious is probably going on than the fact
+ * that SetPageStore() didn't work.
+ */
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int vmci_host_do_qp_detach(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_qp_dtch_info detach_info;
+ struct vmci_qp_dtch_info __user *info = uptr;
+ s32 result;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&detach_info, uptr, sizeof(detach_info)))
+ return -EFAULT;
+
+ result = vmci_qp_broker_detach(detach_info.handle,
+ vmci_host_dev->context);
+ if (result == VMCI_SUCCESS &&
+ vmci_host_dev->user_version < VMCI_VERSION_NOVMVM) {
+ result = VMCI_SUCCESS_LAST_DETACH;
+ }
+
+ return put_user(result, &info->result) ? -EFAULT : 0;
+}
+
+static int vmci_host_do_ctx_add_notify(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_ctx_info ar_info;
+ struct vmci_ctx_info __user *info = uptr;
+ s32 result;
+ u32 cid;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&ar_info, uptr, sizeof(ar_info)))
+ return -EFAULT;
+
+ cid = vmci_ctx_get_id(vmci_host_dev->context);
+ result = vmci_ctx_add_notification(cid, ar_info.remote_cid);
+
+ return put_user(result, &info->result) ? -EFAULT : 0;
+}
+
+static int vmci_host_do_ctx_remove_notify(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_ctx_info ar_info;
+ struct vmci_ctx_info __user *info = uptr;
+ u32 cid;
+ int result;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&ar_info, uptr, sizeof(ar_info)))
+ return -EFAULT;
+
+ cid = vmci_ctx_get_id(vmci_host_dev->context);
+ result = vmci_ctx_remove_notification(cid,
+ ar_info.remote_cid);
+
+ return put_user(result, &info->result) ? -EFAULT : 0;
+}
+
+static int vmci_host_do_ctx_get_cpt_state(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_ctx_chkpt_buf_info get_info;
+ u32 cid;
+ void *cpt_buf;
+ int retval;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&get_info, uptr, sizeof(get_info)))
+ return -EFAULT;
+
+ cid = vmci_ctx_get_id(vmci_host_dev->context);
+ get_info.result = vmci_ctx_get_chkpt_state(cid, get_info.cpt_type,
+ &get_info.buf_size, &cpt_buf);
+ if (get_info.result == VMCI_SUCCESS && get_info.buf_size) {
+ void __user *ubuf = (void __user *)(uintptr_t)get_info.cpt_buf;
+ retval = copy_to_user(ubuf, cpt_buf, get_info.buf_size);
+ kfree(cpt_buf);
+
+ if (retval)
+ return -EFAULT;
+ }
+
+ return copy_to_user(uptr, &get_info, sizeof(get_info)) ? -EFAULT : 0;
+}
+
+static int vmci_host_do_ctx_set_cpt_state(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_ctx_chkpt_buf_info set_info;
+ u32 cid;
+ void *cpt_buf;
+ int retval;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&set_info, uptr, sizeof(set_info)))
+ return -EFAULT;
+
+ cpt_buf = kmalloc(set_info.buf_size, GFP_KERNEL);
+ if (!cpt_buf) {
+ vmci_ioctl_err(
+ "cannot allocate memory to set cpt state (type=%d)\n",
+ set_info.cpt_type);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(cpt_buf, (void __user *)(uintptr_t)set_info.cpt_buf,
+ set_info.buf_size)) {
+ retval = -EFAULT;
+ goto out;
+ }
+
+ cid = vmci_ctx_get_id(vmci_host_dev->context);
+ set_info.result = vmci_ctx_set_chkpt_state(cid, set_info.cpt_type,
+ set_info.buf_size, cpt_buf);
+
+ retval = copy_to_user(uptr, &set_info, sizeof(set_info)) ? -EFAULT : 0;
+
+out:
+ kfree(cpt_buf);
+ return retval;
+}
+
+static int vmci_host_do_get_context_id(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ u32 __user *u32ptr = uptr;
+
+ return put_user(VMCI_HOST_CONTEXT_ID, u32ptr) ? -EFAULT : 0;
+}
+
+static int vmci_host_do_set_notify(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_set_notify_info notify_info;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&notify_info, uptr, sizeof(notify_info)))
+ return -EFAULT;
+
+ if (notify_info.notify_uva) {
+ notify_info.result =
+ vmci_host_setup_notify(vmci_host_dev->context,
+ notify_info.notify_uva);
+ } else {
+ vmci_ctx_unset_notify(vmci_host_dev->context);
+ notify_info.result = VMCI_SUCCESS;
+ }
+
+ return copy_to_user(uptr, &notify_info, sizeof(notify_info)) ?
+ -EFAULT : 0;
+}
+
+static int vmci_host_do_notify_resource(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_dbell_notify_resource_info info;
+ u32 cid;
+
+ if (vmci_host_dev->user_version < VMCI_VERSION_NOTIFY) {
+ vmci_ioctl_err("invalid for current VMX versions\n");
+ return -EINVAL;
+ }
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&info, uptr, sizeof(info)))
+ return -EFAULT;
+
+ cid = vmci_ctx_get_id(vmci_host_dev->context);
+
+ switch (info.action) {
+ case VMCI_NOTIFY_RESOURCE_ACTION_NOTIFY:
+ if (info.resource == VMCI_NOTIFY_RESOURCE_DOOR_BELL) {
+ u32 flags = VMCI_NO_PRIVILEGE_FLAGS;
+ info.result = vmci_ctx_notify_dbell(cid, info.handle,
+ flags);
+ } else {
+ info.result = VMCI_ERROR_UNAVAILABLE;
+ }
+ break;
+
+ case VMCI_NOTIFY_RESOURCE_ACTION_CREATE:
+ info.result = vmci_ctx_dbell_create(cid, info.handle);
+ break;
+
+ case VMCI_NOTIFY_RESOURCE_ACTION_DESTROY:
+ info.result = vmci_ctx_dbell_destroy(cid, info.handle);
+ break;
+
+ default:
+ vmci_ioctl_err("got unknown action (action=%d)\n",
+ info.action);
+ info.result = VMCI_ERROR_INVALID_ARGS;
+ }
+
+ return copy_to_user(uptr, &info, sizeof(info)) ? -EFAULT : 0;
+}
+
+static int vmci_host_do_recv_notifications(struct vmci_host_dev *vmci_host_dev,
+ const char *ioctl_name,
+ void __user *uptr)
+{
+ struct vmci_ctx_notify_recv_info info;
+ struct vmci_handle_arr *db_handle_array;
+ struct vmci_handle_arr *qp_handle_array;
+ void __user *ubuf;
+ u32 cid;
+ int retval = 0;
+
+ if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) {
+ vmci_ioctl_err("only valid for contexts\n");
+ return -EINVAL;
+ }
+
+ if (vmci_host_dev->user_version < VMCI_VERSION_NOTIFY) {
+ vmci_ioctl_err("not supported for the current vmx version\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&info, uptr, sizeof(info)))
+ return -EFAULT;
+
+ if ((info.db_handle_buf_size && !info.db_handle_buf_uva) ||
+ (info.qp_handle_buf_size && !info.qp_handle_buf_uva)) {
+ return -EINVAL;
+ }
+
+ cid = vmci_ctx_get_id(vmci_host_dev->context);
+
+ info.result = vmci_ctx_rcv_notifications_get(cid,
+ &db_handle_array, &qp_handle_array);
+ if (info.result != VMCI_SUCCESS)
+ return copy_to_user(uptr, &info, sizeof(info)) ? -EFAULT : 0;
+
+ ubuf = (void __user *)(uintptr_t)info.db_handle_buf_uva;
+ info.result = drv_cp_harray_to_user(ubuf, &info.db_handle_buf_size,
+ db_handle_array, &retval);
+ if (info.result == VMCI_SUCCESS && !retval) {
+ ubuf = (void __user *)(uintptr_t)info.qp_handle_buf_uva;
+ info.result = drv_cp_harray_to_user(ubuf,
+ &info.qp_handle_buf_size,
+ qp_handle_array, &retval);
+ }
+
+ if (!retval && copy_to_user(uptr, &info, sizeof(info)))
+ retval = -EFAULT;
+
+ vmci_ctx_rcv_notifications_release(cid,
+ db_handle_array, qp_handle_array,
+ info.result == VMCI_SUCCESS && !retval);
+
+ return retval;
+}
+
+static long vmci_host_unlocked_ioctl(struct file *filp,
+ unsigned int iocmd, unsigned long ioarg)
+{
+#define VMCI_DO_IOCTL(ioctl_name, ioctl_fn) do { \
+ char *name = __stringify(IOCTL_VMCI_ ## ioctl_name); \
+ return vmci_host_do_ ## ioctl_fn( \
+ vmci_host_dev, name, uptr); \
+ } while (0)
+
+ struct vmci_host_dev *vmci_host_dev = filp->private_data;
+ void __user *uptr = (void __user *)ioarg;
+
+ switch (iocmd) {
+ case IOCTL_VMCI_INIT_CONTEXT:
+ VMCI_DO_IOCTL(INIT_CONTEXT, init_context);
+ case IOCTL_VMCI_DATAGRAM_SEND:
+ VMCI_DO_IOCTL(DATAGRAM_SEND, send_datagram);
+ case IOCTL_VMCI_DATAGRAM_RECEIVE:
+ VMCI_DO_IOCTL(DATAGRAM_RECEIVE, receive_datagram);
+ case IOCTL_VMCI_QUEUEPAIR_ALLOC:
+ VMCI_DO_IOCTL(QUEUEPAIR_ALLOC, alloc_queuepair);
+ case IOCTL_VMCI_QUEUEPAIR_SETVA:
+ VMCI_DO_IOCTL(QUEUEPAIR_SETVA, queuepair_setva);
+ case IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE:
+ VMCI_DO_IOCTL(QUEUEPAIR_SETPAGEFILE, queuepair_setpf);
+ case IOCTL_VMCI_QUEUEPAIR_DETACH:
+ VMCI_DO_IOCTL(QUEUEPAIR_DETACH, qp_detach);
+ case IOCTL_VMCI_CTX_ADD_NOTIFICATION:
+ VMCI_DO_IOCTL(CTX_ADD_NOTIFICATION, ctx_add_notify);
+ case IOCTL_VMCI_CTX_REMOVE_NOTIFICATION:
+ VMCI_DO_IOCTL(CTX_REMOVE_NOTIFICATION, ctx_remove_notify);
+ case IOCTL_VMCI_CTX_GET_CPT_STATE:
+ VMCI_DO_IOCTL(CTX_GET_CPT_STATE, ctx_get_cpt_state);
+ case IOCTL_VMCI_CTX_SET_CPT_STATE:
+ VMCI_DO_IOCTL(CTX_SET_CPT_STATE, ctx_set_cpt_state);
+ case IOCTL_VMCI_GET_CONTEXT_ID:
+ VMCI_DO_IOCTL(GET_CONTEXT_ID, get_context_id);
+ case IOCTL_VMCI_SET_NOTIFY:
+ VMCI_DO_IOCTL(SET_NOTIFY, set_notify);
+ case IOCTL_VMCI_NOTIFY_RESOURCE:
+ VMCI_DO_IOCTL(NOTIFY_RESOURCE, notify_resource);
+ case IOCTL_VMCI_NOTIFICATIONS_RECEIVE:
+ VMCI_DO_IOCTL(NOTIFICATIONS_RECEIVE, recv_notifications);
+
+ case IOCTL_VMCI_VERSION:
+ case IOCTL_VMCI_VERSION2:
+ return vmci_host_get_version(vmci_host_dev, iocmd, uptr);
+
+ default:
+ pr_devel("%s: Unknown ioctl (iocmd=%d)\n", __func__, iocmd);
+ return -EINVAL;
+ }
+
+#undef VMCI_DO_IOCTL
+}
+
+static const struct file_operations vmuser_fops = {
+ .owner = THIS_MODULE,
+ .open = vmci_host_open,
+ .release = vmci_host_close,
+ .poll = vmci_host_poll,
+ .unlocked_ioctl = vmci_host_unlocked_ioctl,
+ .compat_ioctl = vmci_host_unlocked_ioctl,
+};
+
+static struct miscdevice vmci_host_miscdev = {
+ .name = "vmci",
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &vmuser_fops,
+};
+
+int __init vmci_host_init(void)
+{
+ int error;
+
+ host_context = vmci_ctx_create(VMCI_HOST_CONTEXT_ID,
+ VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS,
+ -1, VMCI_VERSION, NULL);
+ if (IS_ERR(host_context)) {
+ error = PTR_ERR(host_context);
+ pr_warn("Failed to initialize VMCIContext (error%d)\n",
+ error);
+ return error;
+ }
+
+ error = misc_register(&vmci_host_miscdev);
+ if (error) {
+ pr_warn("Module registration error (name=%s, major=%d, minor=%d, err=%d)\n",
+ vmci_host_miscdev.name,
+ MISC_MAJOR, vmci_host_miscdev.minor,
+ error);
+ pr_warn("Unable to initialize host personality\n");
+ vmci_ctx_destroy(host_context);
+ return error;
+ }
+
+ pr_info("VMCI host device registered (name=%s, major=%d, minor=%d)\n",
+ vmci_host_miscdev.name, MISC_MAJOR, vmci_host_miscdev.minor);
+
+ vmci_host_device_initialized = true;
+ return 0;
+}
+
+void __exit vmci_host_exit(void)
+{
+ int error;
+
+ vmci_host_device_initialized = false;
+
+ error = misc_deregister(&vmci_host_miscdev);
+ if (error)
+ pr_warn("Error unregistering character device: %d\n", error);
+
+ vmci_ctx_destroy(host_context);
+ vmci_qp_broker_exit();
+
+ pr_debug("VMCI host driver module unloaded\n");
+}
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
new file mode 100644
index 000000000000..d94245dbd765
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -0,0 +1,3425 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+#include <linux/highmem.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/wait.h>
+#include <linux/vmalloc.h>
+
+#include "vmci_handle_array.h"
+#include "vmci_queue_pair.h"
+#include "vmci_datagram.h"
+#include "vmci_resource.h"
+#include "vmci_context.h"
+#include "vmci_driver.h"
+#include "vmci_event.h"
+#include "vmci_route.h"
+
+/*
+ * In the following, we will distinguish between two kinds of VMX processes -
+ * the ones with versions lower than VMCI_VERSION_NOVMVM that use specialized
+ * VMCI page files in the VMX and supporting VM to VM communication and the
+ * newer ones that use the guest memory directly. We will in the following
+ * refer to the older VMX versions as old-style VMX'en, and the newer ones as
+ * new-style VMX'en.
+ *
+ * The state transition datagram is as follows (the VMCIQPB_ prefix has been
+ * removed for readability) - see below for more details on the transtions:
+ *
+ * -------------- NEW -------------
+ * | |
+ * \_/ \_/
+ * CREATED_NO_MEM <-----------------> CREATED_MEM
+ * | | |
+ * | o-----------------------o |
+ * | | |
+ * \_/ \_/ \_/
+ * ATTACHED_NO_MEM <----------------> ATTACHED_MEM
+ * | | |
+ * | o----------------------o |
+ * | | |
+ * \_/ \_/ \_/
+ * SHUTDOWN_NO_MEM <----------------> SHUTDOWN_MEM
+ * | |
+ * | |
+ * -------------> gone <-------------
+ *
+ * In more detail. When a VMCI queue pair is first created, it will be in the
+ * VMCIQPB_NEW state. It will then move into one of the following states:
+ *
+ * - VMCIQPB_CREATED_NO_MEM: this state indicates that either:
+ *
+ * - the created was performed by a host endpoint, in which case there is
+ * no backing memory yet.
+ *
+ * - the create was initiated by an old-style VMX, that uses
+ * vmci_qp_broker_set_page_store to specify the UVAs of the queue pair at
+ * a later point in time. This state can be distinguished from the one
+ * above by the context ID of the creator. A host side is not allowed to
+ * attach until the page store has been set.
+ *
+ * - VMCIQPB_CREATED_MEM: this state is the result when the queue pair
+ * is created by a VMX using the queue pair device backend that
+ * sets the UVAs of the queue pair immediately and stores the
+ * information for later attachers. At this point, it is ready for
+ * the host side to attach to it.
+ *
+ * Once the queue pair is in one of the created states (with the exception of
+ * the case mentioned for older VMX'en above), it is possible to attach to the
+ * queue pair. Again we have two new states possible:
+ *
+ * - VMCIQPB_ATTACHED_MEM: this state can be reached through the following
+ * paths:
+ *
+ * - from VMCIQPB_CREATED_NO_MEM when a new-style VMX allocates a queue
+ * pair, and attaches to a queue pair previously created by the host side.
+ *
+ * - from VMCIQPB_CREATED_MEM when the host side attaches to a queue pair
+ * already created by a guest.
+ *
+ * - from VMCIQPB_ATTACHED_NO_MEM, when an old-style VMX calls
+ * vmci_qp_broker_set_page_store (see below).
+ *
+ * - VMCIQPB_ATTACHED_NO_MEM: If the queue pair already was in the
+ * VMCIQPB_CREATED_NO_MEM due to a host side create, an old-style VMX will
+ * bring the queue pair into this state. Once vmci_qp_broker_set_page_store
+ * is called to register the user memory, the VMCIQPB_ATTACH_MEM state
+ * will be entered.
+ *
+ * From the attached queue pair, the queue pair can enter the shutdown states
+ * when either side of the queue pair detaches. If the guest side detaches
+ * first, the queue pair will enter the VMCIQPB_SHUTDOWN_NO_MEM state, where
+ * the content of the queue pair will no longer be available. If the host
+ * side detaches first, the queue pair will either enter the
+ * VMCIQPB_SHUTDOWN_MEM, if the guest memory is currently mapped, or
+ * VMCIQPB_SHUTDOWN_NO_MEM, if the guest memory is not mapped
+ * (e.g., the host detaches while a guest is stunned).
+ *
+ * New-style VMX'en will also unmap guest memory, if the guest is
+ * quiesced, e.g., during a snapshot operation. In that case, the guest
+ * memory will no longer be available, and the queue pair will transition from
+ * *_MEM state to a *_NO_MEM state. The VMX may later map the memory once more,
+ * in which case the queue pair will transition from the *_NO_MEM state at that
+ * point back to the *_MEM state. Note that the *_NO_MEM state may have changed,
+ * since the peer may have either attached or detached in the meantime. The
+ * values are laid out such that ++ on a state will move from a *_NO_MEM to a
+ * *_MEM state, and vice versa.
+ */
+
+/*
+ * VMCIMemcpy{To,From}QueueFunc() prototypes. Functions of these
+ * types are passed around to enqueue and dequeue routines. Note that
+ * often the functions passed are simply wrappers around memcpy
+ * itself.
+ *
+ * Note: In order for the memcpy typedefs to be compatible with the VMKernel,
+ * there's an unused last parameter for the hosted side. In
+ * ESX, that parameter holds a buffer type.
+ */
+typedef int vmci_memcpy_to_queue_func(struct vmci_queue *queue,
+ u64 queue_offset, const void *src,
+ size_t src_offset, size_t size);
+typedef int vmci_memcpy_from_queue_func(void *dest, size_t dest_offset,
+ const struct vmci_queue *queue,
+ u64 queue_offset, size_t size);
+
+/* The Kernel specific component of the struct vmci_queue structure. */
+struct vmci_queue_kern_if {
+ struct page **page;
+ struct page **header_page;
+ void *va;
+ struct mutex __mutex; /* Protects the queue. */
+ struct mutex *mutex; /* Shared by producer and consumer queues. */
+ bool host;
+ size_t num_pages;
+ bool mapped;
+};
+
+/*
+ * This structure is opaque to the clients.
+ */
+struct vmci_qp {
+ struct vmci_handle handle;
+ struct vmci_queue *produce_q;
+ struct vmci_queue *consume_q;
+ u64 produce_q_size;
+ u64 consume_q_size;
+ u32 peer;
+ u32 flags;
+ u32 priv_flags;
+ bool guest_endpoint;
+ unsigned int blocked;
+ unsigned int generation;
+ wait_queue_head_t event;
+};
+
+enum qp_broker_state {
+ VMCIQPB_NEW,
+ VMCIQPB_CREATED_NO_MEM,
+ VMCIQPB_CREATED_MEM,
+ VMCIQPB_ATTACHED_NO_MEM,
+ VMCIQPB_ATTACHED_MEM,
+ VMCIQPB_SHUTDOWN_NO_MEM,
+ VMCIQPB_SHUTDOWN_MEM,
+ VMCIQPB_GONE
+};
+
+#define QPBROKERSTATE_HAS_MEM(_qpb) (_qpb->state == VMCIQPB_CREATED_MEM || \
+ _qpb->state == VMCIQPB_ATTACHED_MEM || \
+ _qpb->state == VMCIQPB_SHUTDOWN_MEM)
+
+/*
+ * In the queue pair broker, we always use the guest point of view for
+ * the produce and consume queue values and references, e.g., the
+ * produce queue size stored is the guests produce queue size. The
+ * host endpoint will need to swap these around. The only exception is
+ * the local queue pairs on the host, in which case the host endpoint
+ * that creates the queue pair will have the right orientation, and
+ * the attaching host endpoint will need to swap.
+ */
+struct qp_entry {
+ struct list_head list_item;
+ struct vmci_handle handle;
+ u32 peer;
+ u32 flags;
+ u64 produce_size;
+ u64 consume_size;
+ u32 ref_count;
+};
+
+struct qp_broker_entry {
+ struct vmci_resource resource;
+ struct qp_entry qp;
+ u32 create_id;
+ u32 attach_id;
+ enum qp_broker_state state;
+ bool require_trusted_attach;
+ bool created_by_trusted;
+ bool vmci_page_files; /* Created by VMX using VMCI page files */
+ struct vmci_queue *produce_q;
+ struct vmci_queue *consume_q;
+ struct vmci_queue_header saved_produce_q;
+ struct vmci_queue_header saved_consume_q;
+ vmci_event_release_cb wakeup_cb;
+ void *client_data;
+ void *local_mem; /* Kernel memory for local queue pair */
+};
+
+struct qp_guest_endpoint {
+ struct vmci_resource resource;
+ struct qp_entry qp;
+ u64 num_ppns;
+ void *produce_q;
+ void *consume_q;
+ struct ppn_set ppn_set;
+};
+
+struct qp_list {
+ struct list_head head;
+ struct mutex mutex; /* Protect queue list. */
+};
+
+static struct qp_list qp_broker_list = {
+ .head = LIST_HEAD_INIT(qp_broker_list.head),
+ .mutex = __MUTEX_INITIALIZER(qp_broker_list.mutex),
+};
+
+static struct qp_list qp_guest_endpoints = {
+ .head = LIST_HEAD_INIT(qp_guest_endpoints.head),
+ .mutex = __MUTEX_INITIALIZER(qp_guest_endpoints.mutex),
+};
+
+#define INVALID_VMCI_GUEST_MEM_ID 0
+#define QPE_NUM_PAGES(_QPE) ((u32) \
+ (DIV_ROUND_UP(_QPE.produce_size, PAGE_SIZE) + \
+ DIV_ROUND_UP(_QPE.consume_size, PAGE_SIZE) + 2))
+
+
+/*
+ * Frees kernel VA space for a given queue and its queue header, and
+ * frees physical data pages.
+ */
+static void qp_free_queue(void *q, u64 size)
+{
+ struct vmci_queue *queue = q;
+
+ if (queue) {
+ u64 i = DIV_ROUND_UP(size, PAGE_SIZE);
+
+ if (queue->kernel_if->mapped) {
+ vunmap(queue->kernel_if->va);
+ queue->kernel_if->va = NULL;
+ }
+
+ while (i)
+ __free_page(queue->kernel_if->page[--i]);
+
+ vfree(queue->q_header);
+ }
+}
+
+/*
+ * Allocates kernel VA space of specified size, plus space for the
+ * queue structure/kernel interface and the queue header. Allocates
+ * physical pages for the queue data pages.
+ *
+ * PAGE m: struct vmci_queue_header (struct vmci_queue->q_header)
+ * PAGE m+1: struct vmci_queue
+ * PAGE m+1+q: struct vmci_queue_kern_if (struct vmci_queue->kernel_if)
+ * PAGE n-size: Data pages (struct vmci_queue->kernel_if->page[])
+ */
+static void *qp_alloc_queue(u64 size, u32 flags)
+{
+ u64 i;
+ struct vmci_queue *queue;
+ struct vmci_queue_header *q_header;
+ const u64 num_data_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+ const uint queue_size =
+ PAGE_SIZE +
+ sizeof(*queue) + sizeof(*(queue->kernel_if)) +
+ num_data_pages * sizeof(*(queue->kernel_if->page));
+
+ q_header = vmalloc(queue_size);
+ if (!q_header)
+ return NULL;
+
+ queue = (void *)q_header + PAGE_SIZE;
+ queue->q_header = q_header;
+ queue->saved_header = NULL;
+ queue->kernel_if = (struct vmci_queue_kern_if *)(queue + 1);
+ queue->kernel_if->header_page = NULL; /* Unused in guest. */
+ queue->kernel_if->page = (struct page **)(queue->kernel_if + 1);
+ queue->kernel_if->host = false;
+ queue->kernel_if->va = NULL;
+ queue->kernel_if->mapped = false;
+
+ for (i = 0; i < num_data_pages; i++) {
+ queue->kernel_if->page[i] = alloc_pages(GFP_KERNEL, 0);
+ if (!queue->kernel_if->page[i])
+ goto fail;
+ }
+
+ if (vmci_qp_pinned(flags)) {
+ queue->kernel_if->va =
+ vmap(queue->kernel_if->page, num_data_pages, VM_MAP,
+ PAGE_KERNEL);
+ if (!queue->kernel_if->va)
+ goto fail;
+
+ queue->kernel_if->mapped = true;
+ }
+
+ return (void *)queue;
+
+ fail:
+ qp_free_queue(queue, i * PAGE_SIZE);
+ return NULL;
+}
+
+/*
+ * Copies from a given buffer or iovector to a VMCI Queue. Uses
+ * kmap()/kunmap() to dynamically map/unmap required portions of the queue
+ * by traversing the offset -> page translation structure for the queue.
+ * Assumes that offset + size does not wrap around in the queue.
+ */
+static int __qp_memcpy_to_queue(struct vmci_queue *queue,
+ u64 queue_offset,
+ const void *src,
+ size_t size,
+ bool is_iovec)
+{
+ struct vmci_queue_kern_if *kernel_if = queue->kernel_if;
+ size_t bytes_copied = 0;
+
+ while (bytes_copied < size) {
+ u64 page_index = (queue_offset + bytes_copied) / PAGE_SIZE;
+ size_t page_offset =
+ (queue_offset + bytes_copied) & (PAGE_SIZE - 1);
+ void *va;
+ size_t to_copy;
+
+ if (!kernel_if->mapped)
+ va = kmap(kernel_if->page[page_index]);
+ else
+ va = (void *)((u8 *)kernel_if->va +
+ (page_index * PAGE_SIZE));
+
+ if (size - bytes_copied > PAGE_SIZE - page_offset)
+ /* Enough payload to fill up from this page. */
+ to_copy = PAGE_SIZE - page_offset;
+ else
+ to_copy = size - bytes_copied;
+
+ if (is_iovec) {
+ struct iovec *iov = (struct iovec *)src;
+ int err;
+
+ /* The iovec will track bytes_copied internally. */
+ err = memcpy_fromiovec((u8 *)va + page_offset,
+ iov, to_copy);
+ if (err != 0) {
+ kunmap(kernel_if->page[page_index]);
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+ } else {
+ memcpy((u8 *)va + page_offset,
+ (u8 *)src + bytes_copied, to_copy);
+ }
+
+ bytes_copied += to_copy;
+ if (!kernel_if->mapped)
+ kunmap(kernel_if->page[page_index]);
+ }
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Copies to a given buffer or iovector from a VMCI Queue. Uses
+ * kmap()/kunmap() to dynamically map/unmap required portions of the queue
+ * by traversing the offset -> page translation structure for the queue.
+ * Assumes that offset + size does not wrap around in the queue.
+ */
+static int __qp_memcpy_from_queue(void *dest,
+ const struct vmci_queue *queue,
+ u64 queue_offset,
+ size_t size,
+ bool is_iovec)
+{
+ struct vmci_queue_kern_if *kernel_if = queue->kernel_if;
+ size_t bytes_copied = 0;
+
+ while (bytes_copied < size) {
+ u64 page_index = (queue_offset + bytes_copied) / PAGE_SIZE;
+ size_t page_offset =
+ (queue_offset + bytes_copied) & (PAGE_SIZE - 1);
+ void *va;
+ size_t to_copy;
+
+ if (!kernel_if->mapped)
+ va = kmap(kernel_if->page[page_index]);
+ else
+ va = (void *)((u8 *)kernel_if->va +
+ (page_index * PAGE_SIZE));
+
+ if (size - bytes_copied > PAGE_SIZE - page_offset)
+ /* Enough payload to fill up this page. */
+ to_copy = PAGE_SIZE - page_offset;
+ else
+ to_copy = size - bytes_copied;
+
+ if (is_iovec) {
+ struct iovec *iov = (struct iovec *)dest;
+ int err;
+
+ /* The iovec will track bytes_copied internally. */
+ err = memcpy_toiovec(iov, (u8 *)va + page_offset,
+ to_copy);
+ if (err != 0) {
+ kunmap(kernel_if->page[page_index]);
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+ } else {
+ memcpy((u8 *)dest + bytes_copied,
+ (u8 *)va + page_offset, to_copy);
+ }
+
+ bytes_copied += to_copy;
+ if (!kernel_if->mapped)
+ kunmap(kernel_if->page[page_index]);
+ }
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Allocates two list of PPNs --- one for the pages in the produce queue,
+ * and the other for the pages in the consume queue. Intializes the list
+ * of PPNs with the page frame numbers of the KVA for the two queues (and
+ * the queue headers).
+ */
+static int qp_alloc_ppn_set(void *prod_q,
+ u64 num_produce_pages,
+ void *cons_q,
+ u64 num_consume_pages, struct ppn_set *ppn_set)
+{
+ u32 *produce_ppns;
+ u32 *consume_ppns;
+ struct vmci_queue *produce_q = prod_q;
+ struct vmci_queue *consume_q = cons_q;
+ u64 i;
+
+ if (!produce_q || !num_produce_pages || !consume_q ||
+ !num_consume_pages || !ppn_set)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ if (ppn_set->initialized)
+ return VMCI_ERROR_ALREADY_EXISTS;
+
+ produce_ppns =
+ kmalloc(num_produce_pages * sizeof(*produce_ppns), GFP_KERNEL);
+ if (!produce_ppns)
+ return VMCI_ERROR_NO_MEM;
+
+ consume_ppns =
+ kmalloc(num_consume_pages * sizeof(*consume_ppns), GFP_KERNEL);
+ if (!consume_ppns) {
+ kfree(produce_ppns);
+ return VMCI_ERROR_NO_MEM;
+ }
+
+ produce_ppns[0] = page_to_pfn(vmalloc_to_page(produce_q->q_header));
+ for (i = 1; i < num_produce_pages; i++) {
+ unsigned long pfn;
+
+ produce_ppns[i] =
+ page_to_pfn(produce_q->kernel_if->page[i - 1]);
+ pfn = produce_ppns[i];
+
+ /* Fail allocation if PFN isn't supported by hypervisor. */
+ if (sizeof(pfn) > sizeof(*produce_ppns)
+ && pfn != produce_ppns[i])
+ goto ppn_error;
+ }
+
+ consume_ppns[0] = page_to_pfn(vmalloc_to_page(consume_q->q_header));
+ for (i = 1; i < num_consume_pages; i++) {
+ unsigned long pfn;
+
+ consume_ppns[i] =
+ page_to_pfn(consume_q->kernel_if->page[i - 1]);
+ pfn = consume_ppns[i];
+
+ /* Fail allocation if PFN isn't supported by hypervisor. */
+ if (sizeof(pfn) > sizeof(*consume_ppns)
+ && pfn != consume_ppns[i])
+ goto ppn_error;
+ }
+
+ ppn_set->num_produce_pages = num_produce_pages;
+ ppn_set->num_consume_pages = num_consume_pages;
+ ppn_set->produce_ppns = produce_ppns;
+ ppn_set->consume_ppns = consume_ppns;
+ ppn_set->initialized = true;
+ return VMCI_SUCCESS;
+
+ ppn_error:
+ kfree(produce_ppns);
+ kfree(consume_ppns);
+ return VMCI_ERROR_INVALID_ARGS;
+}
+
+/*
+ * Frees the two list of PPNs for a queue pair.
+ */
+static void qp_free_ppn_set(struct ppn_set *ppn_set)
+{
+ if (ppn_set->initialized) {
+ /* Do not call these functions on NULL inputs. */
+ kfree(ppn_set->produce_ppns);
+ kfree(ppn_set->consume_ppns);
+ }
+ memset(ppn_set, 0, sizeof(*ppn_set));
+}
+
+/*
+ * Populates the list of PPNs in the hypercall structure with the PPNS
+ * of the produce queue and the consume queue.
+ */
+static int qp_populate_ppn_set(u8 *call_buf, const struct ppn_set *ppn_set)
+{
+ memcpy(call_buf, ppn_set->produce_ppns,
+ ppn_set->num_produce_pages * sizeof(*ppn_set->produce_ppns));
+ memcpy(call_buf +
+ ppn_set->num_produce_pages * sizeof(*ppn_set->produce_ppns),
+ ppn_set->consume_ppns,
+ ppn_set->num_consume_pages * sizeof(*ppn_set->consume_ppns));
+
+ return VMCI_SUCCESS;
+}
+
+static int qp_memcpy_to_queue(struct vmci_queue *queue,
+ u64 queue_offset,
+ const void *src, size_t src_offset, size_t size)
+{
+ return __qp_memcpy_to_queue(queue, queue_offset,
+ (u8 *)src + src_offset, size, false);
+}
+
+static int qp_memcpy_from_queue(void *dest,
+ size_t dest_offset,
+ const struct vmci_queue *queue,
+ u64 queue_offset, size_t size)
+{
+ return __qp_memcpy_from_queue((u8 *)dest + dest_offset,
+ queue, queue_offset, size, false);
+}
+
+/*
+ * Copies from a given iovec from a VMCI Queue.
+ */
+static int qp_memcpy_to_queue_iov(struct vmci_queue *queue,
+ u64 queue_offset,
+ const void *src,
+ size_t src_offset, size_t size)
+{
+
+ /*
+ * We ignore src_offset because src is really a struct iovec * and will
+ * maintain offset internally.
+ */
+ return __qp_memcpy_to_queue(queue, queue_offset, src, size, true);
+}
+
+/*
+ * Copies to a given iovec from a VMCI Queue.
+ */
+static int qp_memcpy_from_queue_iov(void *dest,
+ size_t dest_offset,
+ const struct vmci_queue *queue,
+ u64 queue_offset, size_t size)
+{
+ /*
+ * We ignore dest_offset because dest is really a struct iovec * and
+ * will maintain offset internally.
+ */
+ return __qp_memcpy_from_queue(dest, queue, queue_offset, size, true);
+}
+
+/*
+ * Allocates kernel VA space of specified size plus space for the queue
+ * and kernel interface. This is different from the guest queue allocator,
+ * because we do not allocate our own queue header/data pages here but
+ * share those of the guest.
+ */
+static struct vmci_queue *qp_host_alloc_queue(u64 size)
+{
+ struct vmci_queue *queue;
+ const size_t num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
+ const size_t queue_size = sizeof(*queue) + sizeof(*(queue->kernel_if));
+ const size_t queue_page_size =
+ num_pages * sizeof(*queue->kernel_if->page);
+
+ queue = kzalloc(queue_size + queue_page_size, GFP_KERNEL);
+ if (queue) {
+ queue->q_header = NULL;
+ queue->saved_header = NULL;
+ queue->kernel_if =
+ (struct vmci_queue_kern_if *)((u8 *)queue +
+ sizeof(*queue));
+ queue->kernel_if->host = true;
+ queue->kernel_if->mutex = NULL;
+ queue->kernel_if->num_pages = num_pages;
+ queue->kernel_if->header_page =
+ (struct page **)((u8 *)queue + queue_size);
+ queue->kernel_if->page = &queue->kernel_if->header_page[1];
+ queue->kernel_if->va = NULL;
+ queue->kernel_if->mapped = false;
+ }
+
+ return queue;
+}
+
+/*
+ * Frees kernel memory for a given queue (header plus translation
+ * structure).
+ */
+static void qp_host_free_queue(struct vmci_queue *queue, u64 queue_size)
+{
+ kfree(queue);
+}
+
+/*
+ * Initialize the mutex for the pair of queues. This mutex is used to
+ * protect the q_header and the buffer from changing out from under any
+ * users of either queue. Of course, it's only any good if the mutexes
+ * are actually acquired. Queue structure must lie on non-paged memory
+ * or we cannot guarantee access to the mutex.
+ */
+static void qp_init_queue_mutex(struct vmci_queue *produce_q,
+ struct vmci_queue *consume_q)
+{
+ /*
+ * Only the host queue has shared state - the guest queues do not
+ * need to synchronize access using a queue mutex.
+ */
+
+ if (produce_q->kernel_if->host) {
+ produce_q->kernel_if->mutex = &produce_q->kernel_if->__mutex;
+ consume_q->kernel_if->mutex = &produce_q->kernel_if->__mutex;
+ mutex_init(produce_q->kernel_if->mutex);
+ }
+}
+
+/*
+ * Cleans up the mutex for the pair of queues.
+ */
+static void qp_cleanup_queue_mutex(struct vmci_queue *produce_q,
+ struct vmci_queue *consume_q)
+{
+ if (produce_q->kernel_if->host) {
+ produce_q->kernel_if->mutex = NULL;
+ consume_q->kernel_if->mutex = NULL;
+ }
+}
+
+/*
+ * Acquire the mutex for the queue. Note that the produce_q and
+ * the consume_q share a mutex. So, only one of the two need to
+ * be passed in to this routine. Either will work just fine.
+ */
+static void qp_acquire_queue_mutex(struct vmci_queue *queue)
+{
+ if (queue->kernel_if->host)
+ mutex_lock(queue->kernel_if->mutex);
+}
+
+/*
+ * Release the mutex for the queue. Note that the produce_q and
+ * the consume_q share a mutex. So, only one of the two need to
+ * be passed in to this routine. Either will work just fine.
+ */
+static void qp_release_queue_mutex(struct vmci_queue *queue)
+{
+ if (queue->kernel_if->host)
+ mutex_unlock(queue->kernel_if->mutex);
+}
+
+/*
+ * Helper function to release pages in the PageStoreAttachInfo
+ * previously obtained using get_user_pages.
+ */
+static void qp_release_pages(struct page **pages,
+ u64 num_pages, bool dirty)
+{
+ int i;
+
+ for (i = 0; i < num_pages; i++) {
+ if (dirty)
+ set_page_dirty(pages[i]);
+
+ page_cache_release(pages[i]);
+ pages[i] = NULL;
+ }
+}
+
+/*
+ * Lock the user pages referenced by the {produce,consume}Buffer
+ * struct into memory and populate the {produce,consume}Pages
+ * arrays in the attach structure with them.
+ */
+static int qp_host_get_user_memory(u64 produce_uva,
+ u64 consume_uva,
+ struct vmci_queue *produce_q,
+ struct vmci_queue *consume_q)
+{
+ int retval;
+ int err = VMCI_SUCCESS;
+
+ down_write(&current->mm->mmap_sem);
+ retval = get_user_pages(current,
+ current->mm,
+ (uintptr_t) produce_uva,
+ produce_q->kernel_if->num_pages,
+ 1, 0, produce_q->kernel_if->header_page, NULL);
+ if (retval < produce_q->kernel_if->num_pages) {
+ pr_warn("get_user_pages(produce) failed (retval=%d)", retval);
+ qp_release_pages(produce_q->kernel_if->header_page, retval,
+ false);
+ err = VMCI_ERROR_NO_MEM;
+ goto out;
+ }
+
+ retval = get_user_pages(current,
+ current->mm,
+ (uintptr_t) consume_uva,
+ consume_q->kernel_if->num_pages,
+ 1, 0, consume_q->kernel_if->header_page, NULL);
+ if (retval < consume_q->kernel_if->num_pages) {
+ pr_warn("get_user_pages(consume) failed (retval=%d)", retval);
+ qp_release_pages(consume_q->kernel_if->header_page, retval,
+ false);
+ qp_release_pages(produce_q->kernel_if->header_page,
+ produce_q->kernel_if->num_pages, false);
+ err = VMCI_ERROR_NO_MEM;
+ }
+
+ out:
+ up_write(&current->mm->mmap_sem);
+
+ return err;
+}
+
+/*
+ * Registers the specification of the user pages used for backing a queue
+ * pair. Enough information to map in pages is stored in the OS specific
+ * part of the struct vmci_queue structure.
+ */
+static int qp_host_register_user_memory(struct vmci_qp_page_store *page_store,
+ struct vmci_queue *produce_q,
+ struct vmci_queue *consume_q)
+{
+ u64 produce_uva;
+ u64 consume_uva;
+
+ /*
+ * The new style and the old style mapping only differs in
+ * that we either get a single or two UVAs, so we split the
+ * single UVA range at the appropriate spot.
+ */
+ produce_uva = page_store->pages;
+ consume_uva = page_store->pages +
+ produce_q->kernel_if->num_pages * PAGE_SIZE;
+ return qp_host_get_user_memory(produce_uva, consume_uva, produce_q,
+ consume_q);
+}
+
+/*
+ * Releases and removes the references to user pages stored in the attach
+ * struct. Pages are released from the page cache and may become
+ * swappable again.
+ */
+static void qp_host_unregister_user_memory(struct vmci_queue *produce_q,
+ struct vmci_queue *consume_q)
+{
+ qp_release_pages(produce_q->kernel_if->header_page,
+ produce_q->kernel_if->num_pages, true);
+ memset(produce_q->kernel_if->header_page, 0,
+ sizeof(*produce_q->kernel_if->header_page) *
+ produce_q->kernel_if->num_pages);
+ qp_release_pages(consume_q->kernel_if->header_page,
+ consume_q->kernel_if->num_pages, true);
+ memset(consume_q->kernel_if->header_page, 0,
+ sizeof(*consume_q->kernel_if->header_page) *
+ consume_q->kernel_if->num_pages);
+}
+
+/*
+ * Once qp_host_register_user_memory has been performed on a
+ * queue, the queue pair headers can be mapped into the
+ * kernel. Once mapped, they must be unmapped with
+ * qp_host_unmap_queues prior to calling
+ * qp_host_unregister_user_memory.
+ * Pages are pinned.
+ */
+static int qp_host_map_queues(struct vmci_queue *produce_q,
+ struct vmci_queue *consume_q)
+{
+ int result;
+
+ if (!produce_q->q_header || !consume_q->q_header) {
+ struct page *headers[2];
+
+ if (produce_q->q_header != consume_q->q_header)
+ return VMCI_ERROR_QUEUEPAIR_MISMATCH;
+
+ if (produce_q->kernel_if->header_page == NULL ||
+ *produce_q->kernel_if->header_page == NULL)
+ return VMCI_ERROR_UNAVAILABLE;
+
+ headers[0] = *produce_q->kernel_if->header_page;
+ headers[1] = *consume_q->kernel_if->header_page;
+
+ produce_q->q_header = vmap(headers, 2, VM_MAP, PAGE_KERNEL);
+ if (produce_q->q_header != NULL) {
+ consume_q->q_header =
+ (struct vmci_queue_header *)((u8 *)
+ produce_q->q_header +
+ PAGE_SIZE);
+ result = VMCI_SUCCESS;
+ } else {
+ pr_warn("vmap failed\n");
+ result = VMCI_ERROR_NO_MEM;
+ }
+ } else {
+ result = VMCI_SUCCESS;
+ }
+
+ return result;
+}
+
+/*
+ * Unmaps previously mapped queue pair headers from the kernel.
+ * Pages are unpinned.
+ */
+static int qp_host_unmap_queues(u32 gid,
+ struct vmci_queue *produce_q,
+ struct vmci_queue *consume_q)
+{
+ if (produce_q->q_header) {
+ if (produce_q->q_header < consume_q->q_header)
+ vunmap(produce_q->q_header);
+ else
+ vunmap(consume_q->q_header);
+
+ produce_q->q_header = NULL;
+ consume_q->q_header = NULL;
+ }
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Finds the entry in the list corresponding to a given handle. Assumes
+ * that the list is locked.
+ */
+static struct qp_entry *qp_list_find(struct qp_list *qp_list,
+ struct vmci_handle handle)
+{
+ struct qp_entry *entry;
+
+ if (vmci_handle_is_invalid(handle))
+ return NULL;
+
+ list_for_each_entry(entry, &qp_list->head, list_item) {
+ if (vmci_handle_is_equal(entry->handle, handle))
+ return entry;
+ }
+
+ return NULL;
+}
+
+/*
+ * Finds the entry in the list corresponding to a given handle.
+ */
+static struct qp_guest_endpoint *
+qp_guest_handle_to_entry(struct vmci_handle handle)
+{
+ struct qp_guest_endpoint *entry;
+ struct qp_entry *qp = qp_list_find(&qp_guest_endpoints, handle);
+
+ entry = qp ? container_of(
+ qp, struct qp_guest_endpoint, qp) : NULL;
+ return entry;
+}
+
+/*
+ * Finds the entry in the list corresponding to a given handle.
+ */
+static struct qp_broker_entry *
+qp_broker_handle_to_entry(struct vmci_handle handle)
+{
+ struct qp_broker_entry *entry;
+ struct qp_entry *qp = qp_list_find(&qp_broker_list, handle);
+
+ entry = qp ? container_of(
+ qp, struct qp_broker_entry, qp) : NULL;
+ return entry;
+}
+
+/*
+ * Dispatches a queue pair event message directly into the local event
+ * queue.
+ */
+static int qp_notify_peer_local(bool attach, struct vmci_handle handle)
+{
+ u32 context_id = vmci_get_context_id();
+ struct vmci_event_qp ev;
+
+ ev.msg.hdr.dst = vmci_make_handle(context_id, VMCI_EVENT_HANDLER);
+ ev.msg.hdr.src = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_CONTEXT_RESOURCE_ID);
+ ev.msg.hdr.payload_size = sizeof(ev) - sizeof(ev.msg.hdr);
+ ev.msg.event_data.event =
+ attach ? VMCI_EVENT_QP_PEER_ATTACH : VMCI_EVENT_QP_PEER_DETACH;
+ ev.payload.peer_id = context_id;
+ ev.payload.handle = handle;
+
+ return vmci_event_dispatch(&ev.msg.hdr);
+}
+
+/*
+ * Allocates and initializes a qp_guest_endpoint structure.
+ * Allocates a queue_pair rid (and handle) iff the given entry has
+ * an invalid handle. 0 through VMCI_RESERVED_RESOURCE_ID_MAX
+ * are reserved handles. Assumes that the QP list mutex is held
+ * by the caller.
+ */
+static struct qp_guest_endpoint *
+qp_guest_endpoint_create(struct vmci_handle handle,
+ u32 peer,
+ u32 flags,
+ u64 produce_size,
+ u64 consume_size,
+ void *produce_q,
+ void *consume_q)
+{
+ int result;
+ struct qp_guest_endpoint *entry;
+ /* One page each for the queue headers. */
+ const u64 num_ppns = DIV_ROUND_UP(produce_size, PAGE_SIZE) +
+ DIV_ROUND_UP(consume_size, PAGE_SIZE) + 2;
+
+ if (vmci_handle_is_invalid(handle)) {
+ u32 context_id = vmci_get_context_id();
+
+ handle = vmci_make_handle(context_id, VMCI_INVALID_ID);
+ }
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (entry) {
+ entry->qp.peer = peer;
+ entry->qp.flags = flags;
+ entry->qp.produce_size = produce_size;
+ entry->qp.consume_size = consume_size;
+ entry->qp.ref_count = 0;
+ entry->num_ppns = num_ppns;
+ entry->produce_q = produce_q;
+ entry->consume_q = consume_q;
+ INIT_LIST_HEAD(&entry->qp.list_item);
+
+ /* Add resource obj */
+ result = vmci_resource_add(&entry->resource,
+ VMCI_RESOURCE_TYPE_QPAIR_GUEST,
+ handle);
+ entry->qp.handle = vmci_resource_handle(&entry->resource);
+ if ((result != VMCI_SUCCESS) ||
+ qp_list_find(&qp_guest_endpoints, entry->qp.handle)) {
+ pr_warn("Failed to add new resource (handle=0x%x:0x%x), error: %d",
+ handle.context, handle.resource, result);
+ kfree(entry);
+ entry = NULL;
+ }
+ }
+ return entry;
+}
+
+/*
+ * Frees a qp_guest_endpoint structure.
+ */
+static void qp_guest_endpoint_destroy(struct qp_guest_endpoint *entry)
+{
+ qp_free_ppn_set(&entry->ppn_set);
+ qp_cleanup_queue_mutex(entry->produce_q, entry->consume_q);
+ qp_free_queue(entry->produce_q, entry->qp.produce_size);
+ qp_free_queue(entry->consume_q, entry->qp.consume_size);
+ /* Unlink from resource hash table and free callback */
+ vmci_resource_remove(&entry->resource);
+
+ kfree(entry);
+}
+
+/*
+ * Helper to make a queue_pairAlloc hypercall when the driver is
+ * supporting a guest device.
+ */
+static int qp_alloc_hypercall(const struct qp_guest_endpoint *entry)
+{
+ struct vmci_qp_alloc_msg *alloc_msg;
+ size_t msg_size;
+ int result;
+
+ if (!entry || entry->num_ppns <= 2)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ msg_size = sizeof(*alloc_msg) +
+ (size_t) entry->num_ppns * sizeof(u32);
+ alloc_msg = kmalloc(msg_size, GFP_KERNEL);
+ if (!alloc_msg)
+ return VMCI_ERROR_NO_MEM;
+
+ alloc_msg->hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_QUEUEPAIR_ALLOC);
+ alloc_msg->hdr.src = VMCI_ANON_SRC_HANDLE;
+ alloc_msg->hdr.payload_size = msg_size - VMCI_DG_HEADERSIZE;
+ alloc_msg->handle = entry->qp.handle;
+ alloc_msg->peer = entry->qp.peer;
+ alloc_msg->flags = entry->qp.flags;
+ alloc_msg->produce_size = entry->qp.produce_size;
+ alloc_msg->consume_size = entry->qp.consume_size;
+ alloc_msg->num_ppns = entry->num_ppns;
+
+ result = qp_populate_ppn_set((u8 *)alloc_msg + sizeof(*alloc_msg),
+ &entry->ppn_set);
+ if (result == VMCI_SUCCESS)
+ result = vmci_send_datagram(&alloc_msg->hdr);
+
+ kfree(alloc_msg);
+
+ return result;
+}
+
+/*
+ * Helper to make a queue_pairDetach hypercall when the driver is
+ * supporting a guest device.
+ */
+static int qp_detatch_hypercall(struct vmci_handle handle)
+{
+ struct vmci_qp_detach_msg detach_msg;
+
+ detach_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_QUEUEPAIR_DETACH);
+ detach_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
+ detach_msg.hdr.payload_size = sizeof(handle);
+ detach_msg.handle = handle;
+
+ return vmci_send_datagram(&detach_msg.hdr);
+}
+
+/*
+ * Adds the given entry to the list. Assumes that the list is locked.
+ */
+static void qp_list_add_entry(struct qp_list *qp_list, struct qp_entry *entry)
+{
+ if (entry)
+ list_add(&entry->list_item, &qp_list->head);
+}
+
+/*
+ * Removes the given entry from the list. Assumes that the list is locked.
+ */
+static void qp_list_remove_entry(struct qp_list *qp_list,
+ struct qp_entry *entry)
+{
+ if (entry)
+ list_del(&entry->list_item);
+}
+
+/*
+ * Helper for VMCI queue_pair detach interface. Frees the physical
+ * pages for the queue pair.
+ */
+static int qp_detatch_guest_work(struct vmci_handle handle)
+{
+ int result;
+ struct qp_guest_endpoint *entry;
+ u32 ref_count = ~0; /* To avoid compiler warning below */
+
+ mutex_lock(&qp_guest_endpoints.mutex);
+
+ entry = qp_guest_handle_to_entry(handle);
+ if (!entry) {
+ mutex_unlock(&qp_guest_endpoints.mutex);
+ return VMCI_ERROR_NOT_FOUND;
+ }
+
+ if (entry->qp.flags & VMCI_QPFLAG_LOCAL) {
+ result = VMCI_SUCCESS;
+
+ if (entry->qp.ref_count > 1) {
+ result = qp_notify_peer_local(false, handle);
+ /*
+ * We can fail to notify a local queuepair
+ * because we can't allocate. We still want
+ * to release the entry if that happens, so
+ * don't bail out yet.
+ */
+ }
+ } else {
+ result = qp_detatch_hypercall(handle);
+ if (result < VMCI_SUCCESS) {
+ /*
+ * We failed to notify a non-local queuepair.
+ * That other queuepair might still be
+ * accessing the shared memory, so don't
+ * release the entry yet. It will get cleaned
+ * up by VMCIqueue_pair_Exit() if necessary
+ * (assuming we are going away, otherwise why
+ * did this fail?).
+ */
+
+ mutex_unlock(&qp_guest_endpoints.mutex);
+ return result;
+ }
+ }
+
+ /*
+ * If we get here then we either failed to notify a local queuepair, or
+ * we succeeded in all cases. Release the entry if required.
+ */
+
+ entry->qp.ref_count--;
+ if (entry->qp.ref_count == 0)
+ qp_list_remove_entry(&qp_guest_endpoints, &entry->qp);
+
+ /* If we didn't remove the entry, this could change once we unlock. */
+ if (entry)
+ ref_count = entry->qp.ref_count;
+
+ mutex_unlock(&qp_guest_endpoints.mutex);
+
+ if (ref_count == 0)
+ qp_guest_endpoint_destroy(entry);
+
+ return result;
+}
+
+/*
+ * This functions handles the actual allocation of a VMCI queue
+ * pair guest endpoint. Allocates physical pages for the queue
+ * pair. It makes OS dependent calls through generic wrappers.
+ */
+static int qp_alloc_guest_work(struct vmci_handle *handle,
+ struct vmci_queue **produce_q,
+ u64 produce_size,
+ struct vmci_queue **consume_q,
+ u64 consume_size,
+ u32 peer,
+ u32 flags,
+ u32 priv_flags)
+{
+ const u64 num_produce_pages =
+ DIV_ROUND_UP(produce_size, PAGE_SIZE) + 1;
+ const u64 num_consume_pages =
+ DIV_ROUND_UP(consume_size, PAGE_SIZE) + 1;
+ void *my_produce_q = NULL;
+ void *my_consume_q = NULL;
+ int result;
+ struct qp_guest_endpoint *queue_pair_entry = NULL;
+
+ if (priv_flags != VMCI_NO_PRIVILEGE_FLAGS)
+ return VMCI_ERROR_NO_ACCESS;
+
+ mutex_lock(&qp_guest_endpoints.mutex);
+
+ queue_pair_entry = qp_guest_handle_to_entry(*handle);
+ if (queue_pair_entry) {
+ if (queue_pair_entry->qp.flags & VMCI_QPFLAG_LOCAL) {
+ /* Local attach case. */
+ if (queue_pair_entry->qp.ref_count > 1) {
+ pr_devel("Error attempting to attach more than once\n");
+ result = VMCI_ERROR_UNAVAILABLE;
+ goto error_keep_entry;
+ }
+
+ if (queue_pair_entry->qp.produce_size != consume_size ||
+ queue_pair_entry->qp.consume_size !=
+ produce_size ||
+ queue_pair_entry->qp.flags !=
+ (flags & ~VMCI_QPFLAG_ATTACH_ONLY)) {
+ pr_devel("Error mismatched queue pair in local attach\n");
+ result = VMCI_ERROR_QUEUEPAIR_MISMATCH;
+ goto error_keep_entry;
+ }
+
+ /*
+ * Do a local attach. We swap the consume and
+ * produce queues for the attacher and deliver
+ * an attach event.
+ */
+ result = qp_notify_peer_local(true, *handle);
+ if (result < VMCI_SUCCESS)
+ goto error_keep_entry;
+
+ my_produce_q = queue_pair_entry->consume_q;
+ my_consume_q = queue_pair_entry->produce_q;
+ goto out;
+ }
+
+ result = VMCI_ERROR_ALREADY_EXISTS;
+ goto error_keep_entry;
+ }
+
+ my_produce_q = qp_alloc_queue(produce_size, flags);
+ if (!my_produce_q) {
+ pr_warn("Error allocating pages for produce queue\n");
+ result = VMCI_ERROR_NO_MEM;
+ goto error;
+ }
+
+ my_consume_q = qp_alloc_queue(consume_size, flags);
+ if (!my_consume_q) {
+ pr_warn("Error allocating pages for consume queue\n");
+ result = VMCI_ERROR_NO_MEM;
+ goto error;
+ }
+
+ queue_pair_entry = qp_guest_endpoint_create(*handle, peer, flags,
+ produce_size, consume_size,
+ my_produce_q, my_consume_q);
+ if (!queue_pair_entry) {
+ pr_warn("Error allocating memory in %s\n", __func__);
+ result = VMCI_ERROR_NO_MEM;
+ goto error;
+ }
+
+ result = qp_alloc_ppn_set(my_produce_q, num_produce_pages, my_consume_q,
+ num_consume_pages,
+ &queue_pair_entry->ppn_set);
+ if (result < VMCI_SUCCESS) {
+ pr_warn("qp_alloc_ppn_set failed\n");
+ goto error;
+ }
+
+ /*
+ * It's only necessary to notify the host if this queue pair will be
+ * attached to from another context.
+ */
+ if (queue_pair_entry->qp.flags & VMCI_QPFLAG_LOCAL) {
+ /* Local create case. */
+ u32 context_id = vmci_get_context_id();
+
+ /*
+ * Enforce similar checks on local queue pairs as we
+ * do for regular ones. The handle's context must
+ * match the creator or attacher context id (here they
+ * are both the current context id) and the
+ * attach-only flag cannot exist during create. We
+ * also ensure specified peer is this context or an
+ * invalid one.
+ */
+ if (queue_pair_entry->qp.handle.context != context_id ||
+ (queue_pair_entry->qp.peer != VMCI_INVALID_ID &&
+ queue_pair_entry->qp.peer != context_id)) {
+ result = VMCI_ERROR_NO_ACCESS;
+ goto error;
+ }
+
+ if (queue_pair_entry->qp.flags & VMCI_QPFLAG_ATTACH_ONLY) {
+ result = VMCI_ERROR_NOT_FOUND;
+ goto error;
+ }
+ } else {
+ result = qp_alloc_hypercall(queue_pair_entry);
+ if (result < VMCI_SUCCESS) {
+ pr_warn("qp_alloc_hypercall result = %d\n", result);
+ goto error;
+ }
+ }
+
+ qp_init_queue_mutex((struct vmci_queue *)my_produce_q,
+ (struct vmci_queue *)my_consume_q);
+
+ qp_list_add_entry(&qp_guest_endpoints, &queue_pair_entry->qp);
+
+ out:
+ queue_pair_entry->qp.ref_count++;
+ *handle = queue_pair_entry->qp.handle;
+ *produce_q = (struct vmci_queue *)my_produce_q;
+ *consume_q = (struct vmci_queue *)my_consume_q;
+
+ /*
+ * We should initialize the queue pair header pages on a local
+ * queue pair create. For non-local queue pairs, the
+ * hypervisor initializes the header pages in the create step.
+ */
+ if ((queue_pair_entry->qp.flags & VMCI_QPFLAG_LOCAL) &&
+ queue_pair_entry->qp.ref_count == 1) {
+ vmci_q_header_init((*produce_q)->q_header, *handle);
+ vmci_q_header_init((*consume_q)->q_header, *handle);
+ }
+
+ mutex_unlock(&qp_guest_endpoints.mutex);
+
+ return VMCI_SUCCESS;
+
+ error:
+ mutex_unlock(&qp_guest_endpoints.mutex);
+ if (queue_pair_entry) {
+ /* The queues will be freed inside the destroy routine. */
+ qp_guest_endpoint_destroy(queue_pair_entry);
+ } else {
+ qp_free_queue(my_produce_q, produce_size);
+ qp_free_queue(my_consume_q, consume_size);
+ }
+ return result;
+
+ error_keep_entry:
+ /* This path should only be used when an existing entry was found. */
+ mutex_unlock(&qp_guest_endpoints.mutex);
+ return result;
+}
+
+/*
+ * The first endpoint issuing a queue pair allocation will create the state
+ * of the queue pair in the queue pair broker.
+ *
+ * If the creator is a guest, it will associate a VMX virtual address range
+ * with the queue pair as specified by the page_store. For compatibility with
+ * older VMX'en, that would use a separate step to set the VMX virtual
+ * address range, the virtual address range can be registered later using
+ * vmci_qp_broker_set_page_store. In that case, a page_store of NULL should be
+ * used.
+ *
+ * If the creator is the host, a page_store of NULL should be used as well,
+ * since the host is not able to supply a page store for the queue pair.
+ *
+ * For older VMX and host callers, the queue pair will be created in the
+ * VMCIQPB_CREATED_NO_MEM state, and for current VMX callers, it will be
+ * created in VMCOQPB_CREATED_MEM state.
+ */
+static int qp_broker_create(struct vmci_handle handle,
+ u32 peer,
+ u32 flags,
+ u32 priv_flags,
+ u64 produce_size,
+ u64 consume_size,
+ struct vmci_qp_page_store *page_store,
+ struct vmci_ctx *context,
+ vmci_event_release_cb wakeup_cb,
+ void *client_data, struct qp_broker_entry **ent)
+{
+ struct qp_broker_entry *entry = NULL;
+ const u32 context_id = vmci_ctx_get_id(context);
+ bool is_local = flags & VMCI_QPFLAG_LOCAL;
+ int result;
+ u64 guest_produce_size;
+ u64 guest_consume_size;
+
+ /* Do not create if the caller asked not to. */
+ if (flags & VMCI_QPFLAG_ATTACH_ONLY)
+ return VMCI_ERROR_NOT_FOUND;
+
+ /*
+ * Creator's context ID should match handle's context ID or the creator
+ * must allow the context in handle's context ID as the "peer".
+ */
+ if (handle.context != context_id && handle.context != peer)
+ return VMCI_ERROR_NO_ACCESS;
+
+ if (VMCI_CONTEXT_IS_VM(context_id) && VMCI_CONTEXT_IS_VM(peer))
+ return VMCI_ERROR_DST_UNREACHABLE;
+
+ /*
+ * Creator's context ID for local queue pairs should match the
+ * peer, if a peer is specified.
+ */
+ if (is_local && peer != VMCI_INVALID_ID && context_id != peer)
+ return VMCI_ERROR_NO_ACCESS;
+
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry)
+ return VMCI_ERROR_NO_MEM;
+
+ if (vmci_ctx_get_id(context) == VMCI_HOST_CONTEXT_ID && !is_local) {
+ /*
+ * The queue pair broker entry stores values from the guest
+ * point of view, so a creating host side endpoint should swap
+ * produce and consume values -- unless it is a local queue
+ * pair, in which case no swapping is necessary, since the local
+ * attacher will swap queues.
+ */
+
+ guest_produce_size = consume_size;
+ guest_consume_size = produce_size;
+ } else {
+ guest_produce_size = produce_size;
+ guest_consume_size = consume_size;
+ }
+
+ entry->qp.handle = handle;
+ entry->qp.peer = peer;
+ entry->qp.flags = flags;
+ entry->qp.produce_size = guest_produce_size;
+ entry->qp.consume_size = guest_consume_size;
+ entry->qp.ref_count = 1;
+ entry->create_id = context_id;
+ entry->attach_id = VMCI_INVALID_ID;
+ entry->state = VMCIQPB_NEW;
+ entry->require_trusted_attach =
+ !!(context->priv_flags & VMCI_PRIVILEGE_FLAG_RESTRICTED);
+ entry->created_by_trusted =
+ !!(priv_flags & VMCI_PRIVILEGE_FLAG_TRUSTED);
+ entry->vmci_page_files = false;
+ entry->wakeup_cb = wakeup_cb;
+ entry->client_data = client_data;
+ entry->produce_q = qp_host_alloc_queue(guest_produce_size);
+ if (entry->produce_q == NULL) {
+ result = VMCI_ERROR_NO_MEM;
+ goto error;
+ }
+ entry->consume_q = qp_host_alloc_queue(guest_consume_size);
+ if (entry->consume_q == NULL) {
+ result = VMCI_ERROR_NO_MEM;
+ goto error;
+ }
+
+ qp_init_queue_mutex(entry->produce_q, entry->consume_q);
+
+ INIT_LIST_HEAD(&entry->qp.list_item);
+
+ if (is_local) {
+ u8 *tmp;
+
+ entry->local_mem = kcalloc(QPE_NUM_PAGES(entry->qp),
+ PAGE_SIZE, GFP_KERNEL);
+ if (entry->local_mem == NULL) {
+ result = VMCI_ERROR_NO_MEM;
+ goto error;
+ }
+ entry->state = VMCIQPB_CREATED_MEM;
+ entry->produce_q->q_header = entry->local_mem;
+ tmp = (u8 *)entry->local_mem + PAGE_SIZE *
+ (DIV_ROUND_UP(entry->qp.produce_size, PAGE_SIZE) + 1);
+ entry->consume_q->q_header = (struct vmci_queue_header *)tmp;
+ } else if (page_store) {
+ /*
+ * The VMX already initialized the queue pair headers, so no
+ * need for the kernel side to do that.
+ */
+ result = qp_host_register_user_memory(page_store,
+ entry->produce_q,
+ entry->consume_q);
+ if (result < VMCI_SUCCESS)
+ goto error;
+
+ entry->state = VMCIQPB_CREATED_MEM;
+ } else {
+ /*
+ * A create without a page_store may be either a host
+ * side create (in which case we are waiting for the
+ * guest side to supply the memory) or an old style
+ * queue pair create (in which case we will expect a
+ * set page store call as the next step).
+ */
+ entry->state = VMCIQPB_CREATED_NO_MEM;
+ }
+
+ qp_list_add_entry(&qp_broker_list, &entry->qp);
+ if (ent != NULL)
+ *ent = entry;
+
+ /* Add to resource obj */
+ result = vmci_resource_add(&entry->resource,
+ VMCI_RESOURCE_TYPE_QPAIR_HOST,
+ handle);
+ if (result != VMCI_SUCCESS) {
+ pr_warn("Failed to add new resource (handle=0x%x:0x%x), error: %d",
+ handle.context, handle.resource, result);
+ goto error;
+ }
+
+ entry->qp.handle = vmci_resource_handle(&entry->resource);
+ if (is_local) {
+ vmci_q_header_init(entry->produce_q->q_header,
+ entry->qp.handle);
+ vmci_q_header_init(entry->consume_q->q_header,
+ entry->qp.handle);
+ }
+
+ vmci_ctx_qp_create(context, entry->qp.handle);
+
+ return VMCI_SUCCESS;
+
+ error:
+ if (entry != NULL) {
+ qp_host_free_queue(entry->produce_q, guest_produce_size);
+ qp_host_free_queue(entry->consume_q, guest_consume_size);
+ kfree(entry);
+ }
+
+ return result;
+}
+
+/*
+ * Enqueues an event datagram to notify the peer VM attached to
+ * the given queue pair handle about attach/detach event by the
+ * given VM. Returns Payload size of datagram enqueued on
+ * success, error code otherwise.
+ */
+static int qp_notify_peer(bool attach,
+ struct vmci_handle handle,
+ u32 my_id,
+ u32 peer_id)
+{
+ int rv;
+ struct vmci_event_qp ev;
+
+ if (vmci_handle_is_invalid(handle) || my_id == VMCI_INVALID_ID ||
+ peer_id == VMCI_INVALID_ID)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ /*
+ * In vmci_ctx_enqueue_datagram() we enforce the upper limit on
+ * number of pending events from the hypervisor to a given VM
+ * otherwise a rogue VM could do an arbitrary number of attach
+ * and detach operations causing memory pressure in the host
+ * kernel.
+ */
+
+ ev.msg.hdr.dst = vmci_make_handle(peer_id, VMCI_EVENT_HANDLER);
+ ev.msg.hdr.src = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
+ VMCI_CONTEXT_RESOURCE_ID);
+ ev.msg.hdr.payload_size = sizeof(ev) - sizeof(ev.msg.hdr);
+ ev.msg.event_data.event = attach ?
+ VMCI_EVENT_QP_PEER_ATTACH : VMCI_EVENT_QP_PEER_DETACH;
+ ev.payload.handle = handle;
+ ev.payload.peer_id = my_id;
+
+ rv = vmci_datagram_dispatch(VMCI_HYPERVISOR_CONTEXT_ID,
+ &ev.msg.hdr, false);
+ if (rv < VMCI_SUCCESS)
+ pr_warn("Failed to enqueue queue_pair %s event datagram for context (ID=0x%x)\n",
+ attach ? "ATTACH" : "DETACH", peer_id);
+
+ return rv;
+}
+
+/*
+ * The second endpoint issuing a queue pair allocation will attach to
+ * the queue pair registered with the queue pair broker.
+ *
+ * If the attacher is a guest, it will associate a VMX virtual address
+ * range with the queue pair as specified by the page_store. At this
+ * point, the already attach host endpoint may start using the queue
+ * pair, and an attach event is sent to it. For compatibility with
+ * older VMX'en, that used a separate step to set the VMX virtual
+ * address range, the virtual address range can be registered later
+ * using vmci_qp_broker_set_page_store. In that case, a page_store of
+ * NULL should be used, and the attach event will be generated once
+ * the actual page store has been set.
+ *
+ * If the attacher is the host, a page_store of NULL should be used as
+ * well, since the page store information is already set by the guest.
+ *
+ * For new VMX and host callers, the queue pair will be moved to the
+ * VMCIQPB_ATTACHED_MEM state, and for older VMX callers, it will be
+ * moved to the VMCOQPB_ATTACHED_NO_MEM state.
+ */
+static int qp_broker_attach(struct qp_broker_entry *entry,
+ u32 peer,
+ u32 flags,
+ u32 priv_flags,
+ u64 produce_size,
+ u64 consume_size,
+ struct vmci_qp_page_store *page_store,
+ struct vmci_ctx *context,
+ vmci_event_release_cb wakeup_cb,
+ void *client_data,
+ struct qp_broker_entry **ent)
+{
+ const u32 context_id = vmci_ctx_get_id(context);
+ bool is_local = flags & VMCI_QPFLAG_LOCAL;
+ int result;
+
+ if (entry->state != VMCIQPB_CREATED_NO_MEM &&
+ entry->state != VMCIQPB_CREATED_MEM)
+ return VMCI_ERROR_UNAVAILABLE;
+
+ if (is_local) {
+ if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL) ||
+ context_id != entry->create_id) {
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+ } else if (context_id == entry->create_id ||
+ context_id == entry->attach_id) {
+ return VMCI_ERROR_ALREADY_EXISTS;
+ }
+
+ if (VMCI_CONTEXT_IS_VM(context_id) &&
+ VMCI_CONTEXT_IS_VM(entry->create_id))
+ return VMCI_ERROR_DST_UNREACHABLE;
+
+ /*
+ * If we are attaching from a restricted context then the queuepair
+ * must have been created by a trusted endpoint.
+ */
+ if ((context->priv_flags & VMCI_PRIVILEGE_FLAG_RESTRICTED) &&
+ !entry->created_by_trusted)
+ return VMCI_ERROR_NO_ACCESS;
+
+ /*
+ * If we are attaching to a queuepair that was created by a restricted
+ * context then we must be trusted.
+ */
+ if (entry->require_trusted_attach &&
+ (!(priv_flags & VMCI_PRIVILEGE_FLAG_TRUSTED)))
+ return VMCI_ERROR_NO_ACCESS;
+
+ /*
+ * If the creator specifies VMCI_INVALID_ID in "peer" field, access
+ * control check is not performed.
+ */
+ if (entry->qp.peer != VMCI_INVALID_ID && entry->qp.peer != context_id)
+ return VMCI_ERROR_NO_ACCESS;
+
+ if (entry->create_id == VMCI_HOST_CONTEXT_ID) {
+ /*
+ * Do not attach if the caller doesn't support Host Queue Pairs
+ * and a host created this queue pair.
+ */
+
+ if (!vmci_ctx_supports_host_qp(context))
+ return VMCI_ERROR_INVALID_RESOURCE;
+
+ } else if (context_id == VMCI_HOST_CONTEXT_ID) {
+ struct vmci_ctx *create_context;
+ bool supports_host_qp;
+
+ /*
+ * Do not attach a host to a user created queue pair if that
+ * user doesn't support host queue pair end points.
+ */
+
+ create_context = vmci_ctx_get(entry->create_id);
+ supports_host_qp = vmci_ctx_supports_host_qp(create_context);
+ vmci_ctx_put(create_context);
+
+ if (!supports_host_qp)
+ return VMCI_ERROR_INVALID_RESOURCE;
+ }
+
+ if ((entry->qp.flags & ~VMCI_QP_ASYMM) != (flags & ~VMCI_QP_ASYMM_PEER))
+ return VMCI_ERROR_QUEUEPAIR_MISMATCH;
+
+ if (context_id != VMCI_HOST_CONTEXT_ID) {
+ /*
+ * The queue pair broker entry stores values from the guest
+ * point of view, so an attaching guest should match the values
+ * stored in the entry.
+ */
+
+ if (entry->qp.produce_size != produce_size ||
+ entry->qp.consume_size != consume_size) {
+ return VMCI_ERROR_QUEUEPAIR_MISMATCH;
+ }
+ } else if (entry->qp.produce_size != consume_size ||
+ entry->qp.consume_size != produce_size) {
+ return VMCI_ERROR_QUEUEPAIR_MISMATCH;
+ }
+
+ if (context_id != VMCI_HOST_CONTEXT_ID) {
+ /*
+ * If a guest attached to a queue pair, it will supply
+ * the backing memory. If this is a pre NOVMVM vmx,
+ * the backing memory will be supplied by calling
+ * vmci_qp_broker_set_page_store() following the
+ * return of the vmci_qp_broker_alloc() call. If it is
+ * a vmx of version NOVMVM or later, the page store
+ * must be supplied as part of the
+ * vmci_qp_broker_alloc call. Under all circumstances
+ * must the initially created queue pair not have any
+ * memory associated with it already.
+ */
+
+ if (entry->state != VMCIQPB_CREATED_NO_MEM)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ if (page_store != NULL) {
+ /*
+ * Patch up host state to point to guest
+ * supplied memory. The VMX already
+ * initialized the queue pair headers, so no
+ * need for the kernel side to do that.
+ */
+
+ result = qp_host_register_user_memory(page_store,
+ entry->produce_q,
+ entry->consume_q);
+ if (result < VMCI_SUCCESS)
+ return result;
+
+ /*
+ * Preemptively load in the headers if non-blocking to
+ * prevent blocking later.
+ */
+ if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
+ result = qp_host_map_queues(entry->produce_q,
+ entry->consume_q);
+ if (result < VMCI_SUCCESS) {
+ qp_host_unregister_user_memory(
+ entry->produce_q,
+ entry->consume_q);
+ return result;
+ }
+ }
+
+ entry->state = VMCIQPB_ATTACHED_MEM;
+ } else {
+ entry->state = VMCIQPB_ATTACHED_NO_MEM;
+ }
+ } else if (entry->state == VMCIQPB_CREATED_NO_MEM) {
+ /*
+ * The host side is attempting to attach to a queue
+ * pair that doesn't have any memory associated with
+ * it. This must be a pre NOVMVM vmx that hasn't set
+ * the page store information yet, or a quiesced VM.
+ */
+
+ return VMCI_ERROR_UNAVAILABLE;
+ } else {
+ /*
+ * For non-blocking queue pairs, we cannot rely on
+ * enqueue/dequeue to map in the pages on the
+ * host-side, since it may block, so we make an
+ * attempt here.
+ */
+
+ if (flags & VMCI_QPFLAG_NONBLOCK) {
+ result =
+ qp_host_map_queues(entry->produce_q,
+ entry->consume_q);
+ if (result < VMCI_SUCCESS)
+ return result;
+
+ entry->qp.flags |= flags &
+ (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED);
+ }
+
+ /* The host side has successfully attached to a queue pair. */
+ entry->state = VMCIQPB_ATTACHED_MEM;
+ }
+
+ if (entry->state == VMCIQPB_ATTACHED_MEM) {
+ result =
+ qp_notify_peer(true, entry->qp.handle, context_id,
+ entry->create_id);
+ if (result < VMCI_SUCCESS)
+ pr_warn("Failed to notify peer (ID=0x%x) of attach to queue pair (handle=0x%x:0x%x)\n",
+ entry->create_id, entry->qp.handle.context,
+ entry->qp.handle.resource);
+ }
+
+ entry->attach_id = context_id;
+ entry->qp.ref_count++;
+ if (wakeup_cb) {
+ entry->wakeup_cb = wakeup_cb;
+ entry->client_data = client_data;
+ }
+
+ /*
+ * When attaching to local queue pairs, the context already has
+ * an entry tracking the queue pair, so don't add another one.
+ */
+ if (!is_local)
+ vmci_ctx_qp_create(context, entry->qp.handle);
+
+ if (ent != NULL)
+ *ent = entry;
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * queue_pair_Alloc for use when setting up queue pair endpoints
+ * on the host.
+ */
+static int qp_broker_alloc(struct vmci_handle handle,
+ u32 peer,
+ u32 flags,
+ u32 priv_flags,
+ u64 produce_size,
+ u64 consume_size,
+ struct vmci_qp_page_store *page_store,
+ struct vmci_ctx *context,
+ vmci_event_release_cb wakeup_cb,
+ void *client_data,
+ struct qp_broker_entry **ent,
+ bool *swap)
+{
+ const u32 context_id = vmci_ctx_get_id(context);
+ bool create;
+ struct qp_broker_entry *entry = NULL;
+ bool is_local = flags & VMCI_QPFLAG_LOCAL;
+ int result;
+
+ if (vmci_handle_is_invalid(handle) ||
+ (flags & ~VMCI_QP_ALL_FLAGS) || is_local ||
+ !(produce_size || consume_size) ||
+ !context || context_id == VMCI_INVALID_ID ||
+ handle.context == VMCI_INVALID_ID) {
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ if (page_store && !VMCI_QP_PAGESTORE_IS_WELLFORMED(page_store))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ /*
+ * In the initial argument check, we ensure that non-vmkernel hosts
+ * are not allowed to create local queue pairs.
+ */
+
+ mutex_lock(&qp_broker_list.mutex);
+
+ if (!is_local && vmci_ctx_qp_exists(context, handle)) {
+ pr_devel("Context (ID=0x%x) already attached to queue pair (handle=0x%x:0x%x)\n",
+ context_id, handle.context, handle.resource);
+ mutex_unlock(&qp_broker_list.mutex);
+ return VMCI_ERROR_ALREADY_EXISTS;
+ }
+
+ if (handle.resource != VMCI_INVALID_ID)
+ entry = qp_broker_handle_to_entry(handle);
+
+ if (!entry) {
+ create = true;
+ result =
+ qp_broker_create(handle, peer, flags, priv_flags,
+ produce_size, consume_size, page_store,
+ context, wakeup_cb, client_data, ent);
+ } else {
+ create = false;
+ result =
+ qp_broker_attach(entry, peer, flags, priv_flags,
+ produce_size, consume_size, page_store,
+ context, wakeup_cb, client_data, ent);
+ }
+
+ mutex_unlock(&qp_broker_list.mutex);
+
+ if (swap)
+ *swap = (context_id == VMCI_HOST_CONTEXT_ID) &&
+ !(create && is_local);
+
+ return result;
+}
+
+/*
+ * This function implements the kernel API for allocating a queue
+ * pair.
+ */
+static int qp_alloc_host_work(struct vmci_handle *handle,
+ struct vmci_queue **produce_q,
+ u64 produce_size,
+ struct vmci_queue **consume_q,
+ u64 consume_size,
+ u32 peer,
+ u32 flags,
+ u32 priv_flags,
+ vmci_event_release_cb wakeup_cb,
+ void *client_data)
+{
+ struct vmci_handle new_handle;
+ struct vmci_ctx *context;
+ struct qp_broker_entry *entry;
+ int result;
+ bool swap;
+
+ if (vmci_handle_is_invalid(*handle)) {
+ new_handle = vmci_make_handle(
+ VMCI_HOST_CONTEXT_ID, VMCI_INVALID_ID);
+ } else
+ new_handle = *handle;
+
+ context = vmci_ctx_get(VMCI_HOST_CONTEXT_ID);
+ entry = NULL;
+ result =
+ qp_broker_alloc(new_handle, peer, flags, priv_flags,
+ produce_size, consume_size, NULL, context,
+ wakeup_cb, client_data, &entry, &swap);
+ if (result == VMCI_SUCCESS) {
+ if (swap) {
+ /*
+ * If this is a local queue pair, the attacher
+ * will swap around produce and consume
+ * queues.
+ */
+
+ *produce_q = entry->consume_q;
+ *consume_q = entry->produce_q;
+ } else {
+ *produce_q = entry->produce_q;
+ *consume_q = entry->consume_q;
+ }
+
+ *handle = vmci_resource_handle(&entry->resource);
+ } else {
+ *handle = VMCI_INVALID_HANDLE;
+ pr_devel("queue pair broker failed to alloc (result=%d)\n",
+ result);
+ }
+ vmci_ctx_put(context);
+ return result;
+}
+
+/*
+ * Allocates a VMCI queue_pair. Only checks validity of input
+ * arguments. The real work is done in the host or guest
+ * specific function.
+ */
+int vmci_qp_alloc(struct vmci_handle *handle,
+ struct vmci_queue **produce_q,
+ u64 produce_size,
+ struct vmci_queue **consume_q,
+ u64 consume_size,
+ u32 peer,
+ u32 flags,
+ u32 priv_flags,
+ bool guest_endpoint,
+ vmci_event_release_cb wakeup_cb,
+ void *client_data)
+{
+ if (!handle || !produce_q || !consume_q ||
+ (!produce_size && !consume_size) || (flags & ~VMCI_QP_ALL_FLAGS))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ if (guest_endpoint) {
+ return qp_alloc_guest_work(handle, produce_q,
+ produce_size, consume_q,
+ consume_size, peer,
+ flags, priv_flags);
+ } else {
+ return qp_alloc_host_work(handle, produce_q,
+ produce_size, consume_q,
+ consume_size, peer, flags,
+ priv_flags, wakeup_cb, client_data);
+ }
+}
+
+/*
+ * This function implements the host kernel API for detaching from
+ * a queue pair.
+ */
+static int qp_detatch_host_work(struct vmci_handle handle)
+{
+ int result;
+ struct vmci_ctx *context;
+
+ context = vmci_ctx_get(VMCI_HOST_CONTEXT_ID);
+
+ result = vmci_qp_broker_detach(handle, context);
+
+ vmci_ctx_put(context);
+ return result;
+}
+
+/*
+ * Detaches from a VMCI queue_pair. Only checks validity of input argument.
+ * Real work is done in the host or guest specific function.
+ */
+static int qp_detatch(struct vmci_handle handle, bool guest_endpoint)
+{
+ if (vmci_handle_is_invalid(handle))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ if (guest_endpoint)
+ return qp_detatch_guest_work(handle);
+ else
+ return qp_detatch_host_work(handle);
+}
+
+/*
+ * Returns the entry from the head of the list. Assumes that the list is
+ * locked.
+ */
+static struct qp_entry *qp_list_get_head(struct qp_list *qp_list)
+{
+ if (!list_empty(&qp_list->head)) {
+ struct qp_entry *entry =
+ list_first_entry(&qp_list->head, struct qp_entry,
+ list_item);
+ return entry;
+ }
+
+ return NULL;
+}
+
+void vmci_qp_broker_exit(void)
+{
+ struct qp_entry *entry;
+ struct qp_broker_entry *be;
+
+ mutex_lock(&qp_broker_list.mutex);
+
+ while ((entry = qp_list_get_head(&qp_broker_list))) {
+ be = (struct qp_broker_entry *)entry;
+
+ qp_list_remove_entry(&qp_broker_list, entry);
+ kfree(be);
+ }
+
+ mutex_unlock(&qp_broker_list.mutex);
+}
+
+/*
+ * Requests that a queue pair be allocated with the VMCI queue
+ * pair broker. Allocates a queue pair entry if one does not
+ * exist. Attaches to one if it exists, and retrieves the page
+ * files backing that queue_pair. Assumes that the queue pair
+ * broker lock is held.
+ */
+int vmci_qp_broker_alloc(struct vmci_handle handle,
+ u32 peer,
+ u32 flags,
+ u32 priv_flags,
+ u64 produce_size,
+ u64 consume_size,
+ struct vmci_qp_page_store *page_store,
+ struct vmci_ctx *context)
+{
+ return qp_broker_alloc(handle, peer, flags, priv_flags,
+ produce_size, consume_size,
+ page_store, context, NULL, NULL, NULL, NULL);
+}
+
+/*
+ * VMX'en with versions lower than VMCI_VERSION_NOVMVM use a separate
+ * step to add the UVAs of the VMX mapping of the queue pair. This function
+ * provides backwards compatibility with such VMX'en, and takes care of
+ * registering the page store for a queue pair previously allocated by the
+ * VMX during create or attach. This function will move the queue pair state
+ * to either from VMCIQBP_CREATED_NO_MEM to VMCIQBP_CREATED_MEM or
+ * VMCIQBP_ATTACHED_NO_MEM to VMCIQBP_ATTACHED_MEM. If moving to the
+ * attached state with memory, the queue pair is ready to be used by the
+ * host peer, and an attached event will be generated.
+ *
+ * Assumes that the queue pair broker lock is held.
+ *
+ * This function is only used by the hosted platform, since there is no
+ * issue with backwards compatibility for vmkernel.
+ */
+int vmci_qp_broker_set_page_store(struct vmci_handle handle,
+ u64 produce_uva,
+ u64 consume_uva,
+ struct vmci_ctx *context)
+{
+ struct qp_broker_entry *entry;
+ int result;
+ const u32 context_id = vmci_ctx_get_id(context);
+
+ if (vmci_handle_is_invalid(handle) || !context ||
+ context_id == VMCI_INVALID_ID)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ /*
+ * We only support guest to host queue pairs, so the VMX must
+ * supply UVAs for the mapped page files.
+ */
+
+ if (produce_uva == 0 || consume_uva == 0)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ mutex_lock(&qp_broker_list.mutex);
+
+ if (!vmci_ctx_qp_exists(context, handle)) {
+ pr_warn("Context (ID=0x%x) not attached to queue pair (handle=0x%x:0x%x)\n",
+ context_id, handle.context, handle.resource);
+ result = VMCI_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ entry = qp_broker_handle_to_entry(handle);
+ if (!entry) {
+ result = VMCI_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ /*
+ * If I'm the owner then I can set the page store.
+ *
+ * Or, if a host created the queue_pair and I'm the attached peer
+ * then I can set the page store.
+ */
+ if (entry->create_id != context_id &&
+ (entry->create_id != VMCI_HOST_CONTEXT_ID ||
+ entry->attach_id != context_id)) {
+ result = VMCI_ERROR_QUEUEPAIR_NOTOWNER;
+ goto out;
+ }
+
+ if (entry->state != VMCIQPB_CREATED_NO_MEM &&
+ entry->state != VMCIQPB_ATTACHED_NO_MEM) {
+ result = VMCI_ERROR_UNAVAILABLE;
+ goto out;
+ }
+
+ result = qp_host_get_user_memory(produce_uva, consume_uva,
+ entry->produce_q, entry->consume_q);
+ if (result < VMCI_SUCCESS)
+ goto out;
+
+ result = qp_host_map_queues(entry->produce_q, entry->consume_q);
+ if (result < VMCI_SUCCESS) {
+ qp_host_unregister_user_memory(entry->produce_q,
+ entry->consume_q);
+ goto out;
+ }
+
+ if (entry->state == VMCIQPB_CREATED_NO_MEM)
+ entry->state = VMCIQPB_CREATED_MEM;
+ else
+ entry->state = VMCIQPB_ATTACHED_MEM;
+
+ entry->vmci_page_files = true;
+
+ if (entry->state == VMCIQPB_ATTACHED_MEM) {
+ result =
+ qp_notify_peer(true, handle, context_id, entry->create_id);
+ if (result < VMCI_SUCCESS) {
+ pr_warn("Failed to notify peer (ID=0x%x) of attach to queue pair (handle=0x%x:0x%x)\n",
+ entry->create_id, entry->qp.handle.context,
+ entry->qp.handle.resource);
+ }
+ }
+
+ result = VMCI_SUCCESS;
+ out:
+ mutex_unlock(&qp_broker_list.mutex);
+ return result;
+}
+
+/*
+ * Resets saved queue headers for the given QP broker
+ * entry. Should be used when guest memory becomes available
+ * again, or the guest detaches.
+ */
+static void qp_reset_saved_headers(struct qp_broker_entry *entry)
+{
+ entry->produce_q->saved_header = NULL;
+ entry->consume_q->saved_header = NULL;
+}
+
+/*
+ * The main entry point for detaching from a queue pair registered with the
+ * queue pair broker. If more than one endpoint is attached to the queue
+ * pair, the first endpoint will mainly decrement a reference count and
+ * generate a notification to its peer. The last endpoint will clean up
+ * the queue pair state registered with the broker.
+ *
+ * When a guest endpoint detaches, it will unmap and unregister the guest
+ * memory backing the queue pair. If the host is still attached, it will
+ * no longer be able to access the queue pair content.
+ *
+ * If the queue pair is already in a state where there is no memory
+ * registered for the queue pair (any *_NO_MEM state), it will transition to
+ * the VMCIQPB_SHUTDOWN_NO_MEM state. This will also happen, if a guest
+ * endpoint is the first of two endpoints to detach. If the host endpoint is
+ * the first out of two to detach, the queue pair will move to the
+ * VMCIQPB_SHUTDOWN_MEM state.
+ */
+int vmci_qp_broker_detach(struct vmci_handle handle, struct vmci_ctx *context)
+{
+ struct qp_broker_entry *entry;
+ const u32 context_id = vmci_ctx_get_id(context);
+ u32 peer_id;
+ bool is_local = false;
+ int result;
+
+ if (vmci_handle_is_invalid(handle) || !context ||
+ context_id == VMCI_INVALID_ID) {
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ mutex_lock(&qp_broker_list.mutex);
+
+ if (!vmci_ctx_qp_exists(context, handle)) {
+ pr_devel("Context (ID=0x%x) not attached to queue pair (handle=0x%x:0x%x)\n",
+ context_id, handle.context, handle.resource);
+ result = VMCI_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ entry = qp_broker_handle_to_entry(handle);
+ if (!entry) {
+ pr_devel("Context (ID=0x%x) reports being attached to queue pair(handle=0x%x:0x%x) that isn't present in broker\n",
+ context_id, handle.context, handle.resource);
+ result = VMCI_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ if (context_id != entry->create_id && context_id != entry->attach_id) {
+ result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
+ goto out;
+ }
+
+ if (context_id == entry->create_id) {
+ peer_id = entry->attach_id;
+ entry->create_id = VMCI_INVALID_ID;
+ } else {
+ peer_id = entry->create_id;
+ entry->attach_id = VMCI_INVALID_ID;
+ }
+ entry->qp.ref_count--;
+
+ is_local = entry->qp.flags & VMCI_QPFLAG_LOCAL;
+
+ if (context_id != VMCI_HOST_CONTEXT_ID) {
+ bool headers_mapped;
+
+ /*
+ * Pre NOVMVM vmx'en may detach from a queue pair
+ * before setting the page store, and in that case
+ * there is no user memory to detach from. Also, more
+ * recent VMX'en may detach from a queue pair in the
+ * quiesced state.
+ */
+
+ qp_acquire_queue_mutex(entry->produce_q);
+ headers_mapped = entry->produce_q->q_header ||
+ entry->consume_q->q_header;
+ if (QPBROKERSTATE_HAS_MEM(entry)) {
+ result =
+ qp_host_unmap_queues(INVALID_VMCI_GUEST_MEM_ID,
+ entry->produce_q,
+ entry->consume_q);
+ if (result < VMCI_SUCCESS)
+ pr_warn("Failed to unmap queue headers for queue pair (handle=0x%x:0x%x,result=%d)\n",
+ handle.context, handle.resource,
+ result);
+
+ if (entry->vmci_page_files)
+ qp_host_unregister_user_memory(entry->produce_q,
+ entry->
+ consume_q);
+ else
+ qp_host_unregister_user_memory(entry->produce_q,
+ entry->
+ consume_q);
+
+ }
+
+ if (!headers_mapped)
+ qp_reset_saved_headers(entry);
+
+ qp_release_queue_mutex(entry->produce_q);
+
+ if (!headers_mapped && entry->wakeup_cb)
+ entry->wakeup_cb(entry->client_data);
+
+ } else {
+ if (entry->wakeup_cb) {
+ entry->wakeup_cb = NULL;
+ entry->client_data = NULL;
+ }
+ }
+
+ if (entry->qp.ref_count == 0) {
+ qp_list_remove_entry(&qp_broker_list, &entry->qp);
+
+ if (is_local)
+ kfree(entry->local_mem);
+
+ qp_cleanup_queue_mutex(entry->produce_q, entry->consume_q);
+ qp_host_free_queue(entry->produce_q, entry->qp.produce_size);
+ qp_host_free_queue(entry->consume_q, entry->qp.consume_size);
+ /* Unlink from resource hash table and free callback */
+ vmci_resource_remove(&entry->resource);
+
+ kfree(entry);
+
+ vmci_ctx_qp_destroy(context, handle);
+ } else {
+ qp_notify_peer(false, handle, context_id, peer_id);
+ if (context_id == VMCI_HOST_CONTEXT_ID &&
+ QPBROKERSTATE_HAS_MEM(entry)) {
+ entry->state = VMCIQPB_SHUTDOWN_MEM;
+ } else {
+ entry->state = VMCIQPB_SHUTDOWN_NO_MEM;
+ }
+
+ if (!is_local)
+ vmci_ctx_qp_destroy(context, handle);
+
+ }
+ result = VMCI_SUCCESS;
+ out:
+ mutex_unlock(&qp_broker_list.mutex);
+ return result;
+}
+
+/*
+ * Establishes the necessary mappings for a queue pair given a
+ * reference to the queue pair guest memory. This is usually
+ * called when a guest is unquiesced and the VMX is allowed to
+ * map guest memory once again.
+ */
+int vmci_qp_broker_map(struct vmci_handle handle,
+ struct vmci_ctx *context,
+ u64 guest_mem)
+{
+ struct qp_broker_entry *entry;
+ const u32 context_id = vmci_ctx_get_id(context);
+ bool is_local = false;
+ int result;
+
+ if (vmci_handle_is_invalid(handle) || !context ||
+ context_id == VMCI_INVALID_ID)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ mutex_lock(&qp_broker_list.mutex);
+
+ if (!vmci_ctx_qp_exists(context, handle)) {
+ pr_devel("Context (ID=0x%x) not attached to queue pair (handle=0x%x:0x%x)\n",
+ context_id, handle.context, handle.resource);
+ result = VMCI_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ entry = qp_broker_handle_to_entry(handle);
+ if (!entry) {
+ pr_devel("Context (ID=0x%x) reports being attached to queue pair (handle=0x%x:0x%x) that isn't present in broker\n",
+ context_id, handle.context, handle.resource);
+ result = VMCI_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ if (context_id != entry->create_id && context_id != entry->attach_id) {
+ result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
+ goto out;
+ }
+
+ is_local = entry->qp.flags & VMCI_QPFLAG_LOCAL;
+ result = VMCI_SUCCESS;
+
+ if (context_id != VMCI_HOST_CONTEXT_ID) {
+ struct vmci_qp_page_store page_store;
+
+ page_store.pages = guest_mem;
+ page_store.len = QPE_NUM_PAGES(entry->qp);
+
+ qp_acquire_queue_mutex(entry->produce_q);
+ qp_reset_saved_headers(entry);
+ result =
+ qp_host_register_user_memory(&page_store,
+ entry->produce_q,
+ entry->consume_q);
+ qp_release_queue_mutex(entry->produce_q);
+ if (result == VMCI_SUCCESS) {
+ /* Move state from *_NO_MEM to *_MEM */
+
+ entry->state++;
+
+ if (entry->wakeup_cb)
+ entry->wakeup_cb(entry->client_data);
+ }
+ }
+
+ out:
+ mutex_unlock(&qp_broker_list.mutex);
+ return result;
+}
+
+/*
+ * Saves a snapshot of the queue headers for the given QP broker
+ * entry. Should be used when guest memory is unmapped.
+ * Results:
+ * VMCI_SUCCESS on success, appropriate error code if guest memory
+ * can't be accessed..
+ */
+static int qp_save_headers(struct qp_broker_entry *entry)
+{
+ int result;
+
+ if (entry->produce_q->saved_header != NULL &&
+ entry->consume_q->saved_header != NULL) {
+ /*
+ * If the headers have already been saved, we don't need to do
+ * it again, and we don't want to map in the headers
+ * unnecessarily.
+ */
+
+ return VMCI_SUCCESS;
+ }
+
+ if (NULL == entry->produce_q->q_header ||
+ NULL == entry->consume_q->q_header) {
+ result = qp_host_map_queues(entry->produce_q, entry->consume_q);
+ if (result < VMCI_SUCCESS)
+ return result;
+ }
+
+ memcpy(&entry->saved_produce_q, entry->produce_q->q_header,
+ sizeof(entry->saved_produce_q));
+ entry->produce_q->saved_header = &entry->saved_produce_q;
+ memcpy(&entry->saved_consume_q, entry->consume_q->q_header,
+ sizeof(entry->saved_consume_q));
+ entry->consume_q->saved_header = &entry->saved_consume_q;
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Removes all references to the guest memory of a given queue pair, and
+ * will move the queue pair from state *_MEM to *_NO_MEM. It is usually
+ * called when a VM is being quiesced where access to guest memory should
+ * avoided.
+ */
+int vmci_qp_broker_unmap(struct vmci_handle handle,
+ struct vmci_ctx *context,
+ u32 gid)
+{
+ struct qp_broker_entry *entry;
+ const u32 context_id = vmci_ctx_get_id(context);
+ bool is_local = false;
+ int result;
+
+ if (vmci_handle_is_invalid(handle) || !context ||
+ context_id == VMCI_INVALID_ID)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ mutex_lock(&qp_broker_list.mutex);
+
+ if (!vmci_ctx_qp_exists(context, handle)) {
+ pr_devel("Context (ID=0x%x) not attached to queue pair (handle=0x%x:0x%x)\n",
+ context_id, handle.context, handle.resource);
+ result = VMCI_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ entry = qp_broker_handle_to_entry(handle);
+ if (!entry) {
+ pr_devel("Context (ID=0x%x) reports being attached to queue pair (handle=0x%x:0x%x) that isn't present in broker\n",
+ context_id, handle.context, handle.resource);
+ result = VMCI_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ if (context_id != entry->create_id && context_id != entry->attach_id) {
+ result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
+ goto out;
+ }
+
+ is_local = entry->qp.flags & VMCI_QPFLAG_LOCAL;
+
+ if (context_id != VMCI_HOST_CONTEXT_ID) {
+ qp_acquire_queue_mutex(entry->produce_q);
+ result = qp_save_headers(entry);
+ if (result < VMCI_SUCCESS)
+ pr_warn("Failed to save queue headers for queue pair (handle=0x%x:0x%x,result=%d)\n",
+ handle.context, handle.resource, result);
+
+ qp_host_unmap_queues(gid, entry->produce_q, entry->consume_q);
+
+ /*
+ * On hosted, when we unmap queue pairs, the VMX will also
+ * unmap the guest memory, so we invalidate the previously
+ * registered memory. If the queue pair is mapped again at a
+ * later point in time, we will need to reregister the user
+ * memory with a possibly new user VA.
+ */
+ qp_host_unregister_user_memory(entry->produce_q,
+ entry->consume_q);
+
+ /*
+ * Move state from *_MEM to *_NO_MEM.
+ */
+ entry->state--;
+
+ qp_release_queue_mutex(entry->produce_q);
+ }
+
+ result = VMCI_SUCCESS;
+
+ out:
+ mutex_unlock(&qp_broker_list.mutex);
+ return result;
+}
+
+/*
+ * Destroys all guest queue pair endpoints. If active guest queue
+ * pairs still exist, hypercalls to attempt detach from these
+ * queue pairs will be made. Any failure to detach is silently
+ * ignored.
+ */
+void vmci_qp_guest_endpoints_exit(void)
+{
+ struct qp_entry *entry;
+ struct qp_guest_endpoint *ep;
+
+ mutex_lock(&qp_guest_endpoints.mutex);
+
+ while ((entry = qp_list_get_head(&qp_guest_endpoints))) {
+ ep = (struct qp_guest_endpoint *)entry;
+
+ /* Don't make a hypercall for local queue_pairs. */
+ if (!(entry->flags & VMCI_QPFLAG_LOCAL))
+ qp_detatch_hypercall(entry->handle);
+
+ /* We cannot fail the exit, so let's reset ref_count. */
+ entry->ref_count = 0;
+ qp_list_remove_entry(&qp_guest_endpoints, entry);
+
+ qp_guest_endpoint_destroy(ep);
+ }
+
+ mutex_unlock(&qp_guest_endpoints.mutex);
+}
+
+/*
+ * Helper routine that will lock the queue pair before subsequent
+ * operations.
+ * Note: Non-blocking on the host side is currently only implemented in ESX.
+ * Since non-blocking isn't yet implemented on the host personality we
+ * have no reason to acquire a spin lock. So to avoid the use of an
+ * unnecessary lock only acquire the mutex if we can block.
+ * Note: It is assumed that QPFLAG_PINNED implies QPFLAG_NONBLOCK. Therefore
+ * we can use the same locking function for access to both the queue
+ * and the queue headers as it is the same logic. Assert this behvior.
+ */
+static void qp_lock(const struct vmci_qp *qpair)
+{
+ if (vmci_can_block(qpair->flags))
+ qp_acquire_queue_mutex(qpair->produce_q);
+}
+
+/*
+ * Helper routine that unlocks the queue pair after calling
+ * qp_lock. Respects non-blocking and pinning flags.
+ */
+static void qp_unlock(const struct vmci_qp *qpair)
+{
+ if (vmci_can_block(qpair->flags))
+ qp_release_queue_mutex(qpair->produce_q);
+}
+
+/*
+ * The queue headers may not be mapped at all times. If a queue is
+ * currently not mapped, it will be attempted to do so.
+ */
+static int qp_map_queue_headers(struct vmci_queue *produce_q,
+ struct vmci_queue *consume_q,
+ bool can_block)
+{
+ int result;
+
+ if (NULL == produce_q->q_header || NULL == consume_q->q_header) {
+ if (can_block)
+ result = qp_host_map_queues(produce_q, consume_q);
+ else
+ result = VMCI_ERROR_QUEUEPAIR_NOT_READY;
+
+ if (result < VMCI_SUCCESS)
+ return (produce_q->saved_header &&
+ consume_q->saved_header) ?
+ VMCI_ERROR_QUEUEPAIR_NOT_READY :
+ VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
+ }
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Helper routine that will retrieve the produce and consume
+ * headers of a given queue pair. If the guest memory of the
+ * queue pair is currently not available, the saved queue headers
+ * will be returned, if these are available.
+ */
+static int qp_get_queue_headers(const struct vmci_qp *qpair,
+ struct vmci_queue_header **produce_q_header,
+ struct vmci_queue_header **consume_q_header)
+{
+ int result;
+
+ result = qp_map_queue_headers(qpair->produce_q, qpair->consume_q,
+ vmci_can_block(qpair->flags));
+ if (result == VMCI_SUCCESS) {
+ *produce_q_header = qpair->produce_q->q_header;
+ *consume_q_header = qpair->consume_q->q_header;
+ } else if (qpair->produce_q->saved_header &&
+ qpair->consume_q->saved_header) {
+ *produce_q_header = qpair->produce_q->saved_header;
+ *consume_q_header = qpair->consume_q->saved_header;
+ result = VMCI_SUCCESS;
+ }
+
+ return result;
+}
+
+/*
+ * Callback from VMCI queue pair broker indicating that a queue
+ * pair that was previously not ready, now either is ready or
+ * gone forever.
+ */
+static int qp_wakeup_cb(void *client_data)
+{
+ struct vmci_qp *qpair = (struct vmci_qp *)client_data;
+
+ qp_lock(qpair);
+ while (qpair->blocked > 0) {
+ qpair->blocked--;
+ qpair->generation++;
+ wake_up(&qpair->event);
+ }
+ qp_unlock(qpair);
+
+ return VMCI_SUCCESS;
+}
+
+/*
+ * Makes the calling thread wait for the queue pair to become
+ * ready for host side access. Returns true when thread is
+ * woken up after queue pair state change, false otherwise.
+ */
+static bool qp_wait_for_ready_queue(struct vmci_qp *qpair)
+{
+ unsigned int generation;
+
+ if (qpair->flags & VMCI_QPFLAG_NONBLOCK)
+ return false;
+
+ qpair->blocked++;
+ generation = qpair->generation;
+ qp_unlock(qpair);
+ wait_event(qpair->event, generation != qpair->generation);
+ qp_lock(qpair);
+
+ return true;
+}
+
+/*
+ * Enqueues a given buffer to the produce queue using the provided
+ * function. As many bytes as possible (space available in the queue)
+ * are enqueued. Assumes the queue->mutex has been acquired. Returns
+ * VMCI_ERROR_QUEUEPAIR_NOSPACE if no space was available to enqueue
+ * data, VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the
+ * queue (as defined by the queue size), VMCI_ERROR_INVALID_ARGS, if
+ * an error occured when accessing the buffer,
+ * VMCI_ERROR_QUEUEPAIR_NOTATTACHED, if the queue pair pages aren't
+ * available. Otherwise, the number of bytes written to the queue is
+ * returned. Updates the tail pointer of the produce queue.
+ */
+static ssize_t qp_enqueue_locked(struct vmci_queue *produce_q,
+ struct vmci_queue *consume_q,
+ const u64 produce_q_size,
+ const void *buf,
+ size_t buf_size,
+ vmci_memcpy_to_queue_func memcpy_to_queue,
+ bool can_block)
+{
+ s64 free_space;
+ u64 tail;
+ size_t written;
+ ssize_t result;
+
+ result = qp_map_queue_headers(produce_q, consume_q, can_block);
+ if (unlikely(result != VMCI_SUCCESS))
+ return result;
+
+ free_space = vmci_q_header_free_space(produce_q->q_header,
+ consume_q->q_header,
+ produce_q_size);
+ if (free_space == 0)
+ return VMCI_ERROR_QUEUEPAIR_NOSPACE;
+
+ if (free_space < VMCI_SUCCESS)
+ return (ssize_t) free_space;
+
+ written = (size_t) (free_space > buf_size ? buf_size : free_space);
+ tail = vmci_q_header_producer_tail(produce_q->q_header);
+ if (likely(tail + written < produce_q_size)) {
+ result = memcpy_to_queue(produce_q, tail, buf, 0, written);
+ } else {
+ /* Tail pointer wraps around. */
+
+ const size_t tmp = (size_t) (produce_q_size - tail);
+
+ result = memcpy_to_queue(produce_q, tail, buf, 0, tmp);
+ if (result >= VMCI_SUCCESS)
+ result = memcpy_to_queue(produce_q, 0, buf, tmp,
+ written - tmp);
+ }
+
+ if (result < VMCI_SUCCESS)
+ return result;
+
+ vmci_q_header_add_producer_tail(produce_q->q_header, written,
+ produce_q_size);
+ return written;
+}
+
+/*
+ * Dequeues data (if available) from the given consume queue. Writes data
+ * to the user provided buffer using the provided function.
+ * Assumes the queue->mutex has been acquired.
+ * Results:
+ * VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
+ * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
+ * (as defined by the queue size).
+ * VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer.
+ * Otherwise the number of bytes dequeued is returned.
+ * Side effects:
+ * Updates the head pointer of the consume queue.
+ */
+static ssize_t qp_dequeue_locked(struct vmci_queue *produce_q,
+ struct vmci_queue *consume_q,
+ const u64 consume_q_size,
+ void *buf,
+ size_t buf_size,
+ vmci_memcpy_from_queue_func memcpy_from_queue,
+ bool update_consumer,
+ bool can_block)
+{
+ s64 buf_ready;
+ u64 head;
+ size_t read;
+ ssize_t result;
+
+ result = qp_map_queue_headers(produce_q, consume_q, can_block);
+ if (unlikely(result != VMCI_SUCCESS))
+ return result;
+
+ buf_ready = vmci_q_header_buf_ready(consume_q->q_header,
+ produce_q->q_header,
+ consume_q_size);
+ if (buf_ready == 0)
+ return VMCI_ERROR_QUEUEPAIR_NODATA;
+
+ if (buf_ready < VMCI_SUCCESS)
+ return (ssize_t) buf_ready;
+
+ read = (size_t) (buf_ready > buf_size ? buf_size : buf_ready);
+ head = vmci_q_header_consumer_head(produce_q->q_header);
+ if (likely(head + read < consume_q_size)) {
+ result = memcpy_from_queue(buf, 0, consume_q, head, read);
+ } else {
+ /* Head pointer wraps around. */
+
+ const size_t tmp = (size_t) (consume_q_size - head);
+
+ result = memcpy_from_queue(buf, 0, consume_q, head, tmp);
+ if (result >= VMCI_SUCCESS)
+ result = memcpy_from_queue(buf, tmp, consume_q, 0,
+ read - tmp);
+
+ }
+
+ if (result < VMCI_SUCCESS)
+ return result;
+
+ if (update_consumer)
+ vmci_q_header_add_consumer_head(produce_q->q_header,
+ read, consume_q_size);
+
+ return read;
+}
+
+/*
+ * vmci_qpair_alloc() - Allocates a queue pair.
+ * @qpair: Pointer for the new vmci_qp struct.
+ * @handle: Handle to track the resource.
+ * @produce_qsize: Desired size of the producer queue.
+ * @consume_qsize: Desired size of the consumer queue.
+ * @peer: ContextID of the peer.
+ * @flags: VMCI flags.
+ * @priv_flags: VMCI priviledge flags.
+ *
+ * This is the client interface for allocating the memory for a
+ * vmci_qp structure and then attaching to the underlying
+ * queue. If an error occurs allocating the memory for the
+ * vmci_qp structure no attempt is made to attach. If an
+ * error occurs attaching, then the structure is freed.
+ */
+int vmci_qpair_alloc(struct vmci_qp **qpair,
+ struct vmci_handle *handle,
+ u64 produce_qsize,
+ u64 consume_qsize,
+ u32 peer,
+ u32 flags,
+ u32 priv_flags)
+{
+ struct vmci_qp *my_qpair;
+ int retval;
+ struct vmci_handle src = VMCI_INVALID_HANDLE;
+ struct vmci_handle dst = vmci_make_handle(peer, VMCI_INVALID_ID);
+ enum vmci_route route;
+ vmci_event_release_cb wakeup_cb;
+ void *client_data;
+
+ /*
+ * Restrict the size of a queuepair. The device already
+ * enforces a limit on the total amount of memory that can be
+ * allocated to queuepairs for a guest. However, we try to
+ * allocate this memory before we make the queuepair
+ * allocation hypercall. On Linux, we allocate each page
+ * separately, which means rather than fail, the guest will
+ * thrash while it tries to allocate, and will become
+ * increasingly unresponsive to the point where it appears to
+ * be hung. So we place a limit on the size of an individual
+ * queuepair here, and leave the device to enforce the
+ * restriction on total queuepair memory. (Note that this
+ * doesn't prevent all cases; a user with only this much
+ * physical memory could still get into trouble.) The error
+ * used by the device is NO_RESOURCES, so use that here too.
+ */
+
+ if (produce_qsize + consume_qsize < max(produce_qsize, consume_qsize) ||
+ produce_qsize + consume_qsize > VMCI_MAX_GUEST_QP_MEMORY)
+ return VMCI_ERROR_NO_RESOURCES;
+
+ retval = vmci_route(&src, &dst, false, &route);
+ if (retval < VMCI_SUCCESS)
+ route = vmci_guest_code_active() ?
+ VMCI_ROUTE_AS_GUEST : VMCI_ROUTE_AS_HOST;
+
+ /* If NONBLOCK or PINNED is set, we better be the guest personality. */
+ if ((!vmci_can_block(flags) || vmci_qp_pinned(flags)) &&
+ VMCI_ROUTE_AS_GUEST != route) {
+ pr_devel("Not guest personality w/ NONBLOCK OR PINNED set");
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ /*
+ * Limit the size of pinned QPs and check sanity.
+ *
+ * Pinned pages implies non-blocking mode. Mutexes aren't acquired
+ * when the NONBLOCK flag is set in qpair code; and also should not be
+ * acquired when the PINNED flagged is set. Since pinning pages
+ * implies we want speed, it makes no sense not to have NONBLOCK
+ * set if PINNED is set. Hence enforce this implication.
+ */
+ if (vmci_qp_pinned(flags)) {
+ if (vmci_can_block(flags)) {
+ pr_err("Attempted to enable pinning w/o non-blocking");
+ return VMCI_ERROR_INVALID_ARGS;
+ }
+
+ if (produce_qsize + consume_qsize > VMCI_MAX_PINNED_QP_MEMORY)
+ return VMCI_ERROR_NO_RESOURCES;
+ }
+
+ my_qpair = kzalloc(sizeof(*my_qpair), GFP_KERNEL);
+ if (!my_qpair)
+ return VMCI_ERROR_NO_MEM;
+
+ my_qpair->produce_q_size = produce_qsize;
+ my_qpair->consume_q_size = consume_qsize;
+ my_qpair->peer = peer;
+ my_qpair->flags = flags;
+ my_qpair->priv_flags = priv_flags;
+
+ wakeup_cb = NULL;
+ client_data = NULL;
+
+ if (VMCI_ROUTE_AS_HOST == route) {
+ my_qpair->guest_endpoint = false;
+ if (!(flags & VMCI_QPFLAG_LOCAL)) {
+ my_qpair->blocked = 0;
+ my_qpair->generation = 0;
+ init_waitqueue_head(&my_qpair->event);
+ wakeup_cb = qp_wakeup_cb;
+ client_data = (void *)my_qpair;
+ }
+ } else {
+ my_qpair->guest_endpoint = true;
+ }
+
+ retval = vmci_qp_alloc(handle,
+ &my_qpair->produce_q,
+ my_qpair->produce_q_size,
+ &my_qpair->consume_q,
+ my_qpair->consume_q_size,
+ my_qpair->peer,
+ my_qpair->flags,
+ my_qpair->priv_flags,
+ my_qpair->guest_endpoint,
+ wakeup_cb, client_data);
+
+ if (retval < VMCI_SUCCESS) {
+ kfree(my_qpair);
+ return retval;
+ }
+
+ *qpair = my_qpair;
+ my_qpair->handle = *handle;
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_alloc);
+
+/*
+ * vmci_qpair_detach() - Detatches the client from a queue pair.
+ * @qpair: Reference of a pointer to the qpair struct.
+ *
+ * This is the client interface for detaching from a VMCIQPair.
+ * Note that this routine will free the memory allocated for the
+ * vmci_qp structure too.
+ */
+int vmci_qpair_detach(struct vmci_qp **qpair)
+{
+ int result;
+ struct vmci_qp *old_qpair;
+
+ if (!qpair || !(*qpair))
+ return VMCI_ERROR_INVALID_ARGS;
+
+ old_qpair = *qpair;
+ result = qp_detatch(old_qpair->handle, old_qpair->guest_endpoint);
+
+ /*
+ * The guest can fail to detach for a number of reasons, and
+ * if it does so, it will cleanup the entry (if there is one).
+ * The host can fail too, but it won't cleanup the entry
+ * immediately, it will do that later when the context is
+ * freed. Either way, we need to release the qpair struct
+ * here; there isn't much the caller can do, and we don't want
+ * to leak.
+ */
+
+ memset(old_qpair, 0, sizeof(*old_qpair));
+ old_qpair->handle = VMCI_INVALID_HANDLE;
+ old_qpair->peer = VMCI_INVALID_ID;
+ kfree(old_qpair);
+ *qpair = NULL;
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_detach);
+
+/*
+ * vmci_qpair_get_produce_indexes() - Retrieves the indexes of the producer.
+ * @qpair: Pointer to the queue pair struct.
+ * @producer_tail: Reference used for storing producer tail index.
+ * @consumer_head: Reference used for storing the consumer head index.
+ *
+ * This is the client interface for getting the current indexes of the
+ * QPair from the point of the view of the caller as the producer.
+ */
+int vmci_qpair_get_produce_indexes(const struct vmci_qp *qpair,
+ u64 *producer_tail,
+ u64 *consumer_head)
+{
+ struct vmci_queue_header *produce_q_header;
+ struct vmci_queue_header *consume_q_header;
+ int result;
+
+ if (!qpair)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+ result =
+ qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
+ if (result == VMCI_SUCCESS)
+ vmci_q_header_get_pointers(produce_q_header, consume_q_header,
+ producer_tail, consumer_head);
+ qp_unlock(qpair);
+
+ if (result == VMCI_SUCCESS &&
+ ((producer_tail && *producer_tail >= qpair->produce_q_size) ||
+ (consumer_head && *consumer_head >= qpair->produce_q_size)))
+ return VMCI_ERROR_INVALID_SIZE;
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_get_produce_indexes);
+
+/*
+ * vmci_qpair_get_consume_indexes() - Retrieves the indexes of the comsumer.
+ * @qpair: Pointer to the queue pair struct.
+ * @consumer_tail: Reference used for storing consumer tail index.
+ * @producer_head: Reference used for storing the producer head index.
+ *
+ * This is the client interface for getting the current indexes of the
+ * QPair from the point of the view of the caller as the consumer.
+ */
+int vmci_qpair_get_consume_indexes(const struct vmci_qp *qpair,
+ u64 *consumer_tail,
+ u64 *producer_head)
+{
+ struct vmci_queue_header *produce_q_header;
+ struct vmci_queue_header *consume_q_header;
+ int result;
+
+ if (!qpair)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+ result =
+ qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
+ if (result == VMCI_SUCCESS)
+ vmci_q_header_get_pointers(consume_q_header, produce_q_header,
+ consumer_tail, producer_head);
+ qp_unlock(qpair);
+
+ if (result == VMCI_SUCCESS &&
+ ((consumer_tail && *consumer_tail >= qpair->consume_q_size) ||
+ (producer_head && *producer_head >= qpair->consume_q_size)))
+ return VMCI_ERROR_INVALID_SIZE;
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_get_consume_indexes);
+
+/*
+ * vmci_qpair_produce_free_space() - Retrieves free space in producer queue.
+ * @qpair: Pointer to the queue pair struct.
+ *
+ * This is the client interface for getting the amount of free
+ * space in the QPair from the point of the view of the caller as
+ * the producer which is the common case. Returns < 0 if err, else
+ * available bytes into which data can be enqueued if > 0.
+ */
+s64 vmci_qpair_produce_free_space(const struct vmci_qp *qpair)
+{
+ struct vmci_queue_header *produce_q_header;
+ struct vmci_queue_header *consume_q_header;
+ s64 result;
+
+ if (!qpair)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+ result =
+ qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
+ if (result == VMCI_SUCCESS)
+ result = vmci_q_header_free_space(produce_q_header,
+ consume_q_header,
+ qpair->produce_q_size);
+ else
+ result = 0;
+
+ qp_unlock(qpair);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_produce_free_space);
+
+/*
+ * vmci_qpair_consume_free_space() - Retrieves free space in consumer queue.
+ * @qpair: Pointer to the queue pair struct.
+ *
+ * This is the client interface for getting the amount of free
+ * space in the QPair from the point of the view of the caller as
+ * the consumer which is not the common case. Returns < 0 if err, else
+ * available bytes into which data can be enqueued if > 0.
+ */
+s64 vmci_qpair_consume_free_space(const struct vmci_qp *qpair)
+{
+ struct vmci_queue_header *produce_q_header;
+ struct vmci_queue_header *consume_q_header;
+ s64 result;
+
+ if (!qpair)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+ result =
+ qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
+ if (result == VMCI_SUCCESS)
+ result = vmci_q_header_free_space(consume_q_header,
+ produce_q_header,
+ qpair->consume_q_size);
+ else
+ result = 0;
+
+ qp_unlock(qpair);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_consume_free_space);
+
+/*
+ * vmci_qpair_produce_buf_ready() - Gets bytes ready to read from
+ * producer queue.
+ * @qpair: Pointer to the queue pair struct.
+ *
+ * This is the client interface for getting the amount of
+ * enqueued data in the QPair from the point of the view of the
+ * caller as the producer which is not the common case. Returns < 0 if err,
+ * else available bytes that may be read.
+ */
+s64 vmci_qpair_produce_buf_ready(const struct vmci_qp *qpair)
+{
+ struct vmci_queue_header *produce_q_header;
+ struct vmci_queue_header *consume_q_header;
+ s64 result;
+
+ if (!qpair)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+ result =
+ qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
+ if (result == VMCI_SUCCESS)
+ result = vmci_q_header_buf_ready(produce_q_header,
+ consume_q_header,
+ qpair->produce_q_size);
+ else
+ result = 0;
+
+ qp_unlock(qpair);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_produce_buf_ready);
+
+/*
+ * vmci_qpair_consume_buf_ready() - Gets bytes ready to read from
+ * consumer queue.
+ * @qpair: Pointer to the queue pair struct.
+ *
+ * This is the client interface for getting the amount of
+ * enqueued data in the QPair from the point of the view of the
+ * caller as the consumer which is the normal case. Returns < 0 if err,
+ * else available bytes that may be read.
+ */
+s64 vmci_qpair_consume_buf_ready(const struct vmci_qp *qpair)
+{
+ struct vmci_queue_header *produce_q_header;
+ struct vmci_queue_header *consume_q_header;
+ s64 result;
+
+ if (!qpair)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+ result =
+ qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
+ if (result == VMCI_SUCCESS)
+ result = vmci_q_header_buf_ready(consume_q_header,
+ produce_q_header,
+ qpair->consume_q_size);
+ else
+ result = 0;
+
+ qp_unlock(qpair);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_consume_buf_ready);
+
+/*
+ * vmci_qpair_enqueue() - Throw data on the queue.
+ * @qpair: Pointer to the queue pair struct.
+ * @buf: Pointer to buffer containing data
+ * @buf_size: Length of buffer.
+ * @buf_type: Buffer type (Unused).
+ *
+ * This is the client interface for enqueueing data into the queue.
+ * Returns number of bytes enqueued or < 0 on error.
+ */
+ssize_t vmci_qpair_enqueue(struct vmci_qp *qpair,
+ const void *buf,
+ size_t buf_size,
+ int buf_type)
+{
+ ssize_t result;
+
+ if (!qpair || !buf)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+
+ do {
+ result = qp_enqueue_locked(qpair->produce_q,
+ qpair->consume_q,
+ qpair->produce_q_size,
+ buf, buf_size,
+ qp_memcpy_to_queue,
+ vmci_can_block(qpair->flags));
+
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
+ !qp_wait_for_ready_queue(qpair))
+ result = VMCI_ERROR_WOULD_BLOCK;
+
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
+
+ qp_unlock(qpair);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_enqueue);
+
+/*
+ * vmci_qpair_dequeue() - Get data from the queue.
+ * @qpair: Pointer to the queue pair struct.
+ * @buf: Pointer to buffer for the data
+ * @buf_size: Length of buffer.
+ * @buf_type: Buffer type (Unused).
+ *
+ * This is the client interface for dequeueing data from the queue.
+ * Returns number of bytes dequeued or < 0 on error.
+ */
+ssize_t vmci_qpair_dequeue(struct vmci_qp *qpair,
+ void *buf,
+ size_t buf_size,
+ int buf_type)
+{
+ ssize_t result;
+
+ if (!qpair || !buf)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+
+ do {
+ result = qp_dequeue_locked(qpair->produce_q,
+ qpair->consume_q,
+ qpair->consume_q_size,
+ buf, buf_size,
+ qp_memcpy_from_queue, true,
+ vmci_can_block(qpair->flags));
+
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
+ !qp_wait_for_ready_queue(qpair))
+ result = VMCI_ERROR_WOULD_BLOCK;
+
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
+
+ qp_unlock(qpair);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_dequeue);
+
+/*
+ * vmci_qpair_peek() - Peek at the data in the queue.
+ * @qpair: Pointer to the queue pair struct.
+ * @buf: Pointer to buffer for the data
+ * @buf_size: Length of buffer.
+ * @buf_type: Buffer type (Unused on Linux).
+ *
+ * This is the client interface for peeking into a queue. (I.e.,
+ * copy data from the queue without updating the head pointer.)
+ * Returns number of bytes dequeued or < 0 on error.
+ */
+ssize_t vmci_qpair_peek(struct vmci_qp *qpair,
+ void *buf,
+ size_t buf_size,
+ int buf_type)
+{
+ ssize_t result;
+
+ if (!qpair || !buf)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+
+ do {
+ result = qp_dequeue_locked(qpair->produce_q,
+ qpair->consume_q,
+ qpair->consume_q_size,
+ buf, buf_size,
+ qp_memcpy_from_queue, false,
+ vmci_can_block(qpair->flags));
+
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
+ !qp_wait_for_ready_queue(qpair))
+ result = VMCI_ERROR_WOULD_BLOCK;
+
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
+
+ qp_unlock(qpair);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_peek);
+
+/*
+ * vmci_qpair_enquev() - Throw data on the queue using iov.
+ * @qpair: Pointer to the queue pair struct.
+ * @iov: Pointer to buffer containing data
+ * @iov_size: Length of buffer.
+ * @buf_type: Buffer type (Unused).
+ *
+ * This is the client interface for enqueueing data into the queue.
+ * This function uses IO vectors to handle the work. Returns number
+ * of bytes enqueued or < 0 on error.
+ */
+ssize_t vmci_qpair_enquev(struct vmci_qp *qpair,
+ void *iov,
+ size_t iov_size,
+ int buf_type)
+{
+ ssize_t result;
+
+ if (!qpair || !iov)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+
+ do {
+ result = qp_enqueue_locked(qpair->produce_q,
+ qpair->consume_q,
+ qpair->produce_q_size,
+ iov, iov_size,
+ qp_memcpy_to_queue_iov,
+ vmci_can_block(qpair->flags));
+
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
+ !qp_wait_for_ready_queue(qpair))
+ result = VMCI_ERROR_WOULD_BLOCK;
+
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
+
+ qp_unlock(qpair);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_enquev);
+
+/*
+ * vmci_qpair_dequev() - Get data from the queue using iov.
+ * @qpair: Pointer to the queue pair struct.
+ * @iov: Pointer to buffer for the data
+ * @iov_size: Length of buffer.
+ * @buf_type: Buffer type (Unused).
+ *
+ * This is the client interface for dequeueing data from the queue.
+ * This function uses IO vectors to handle the work. Returns number
+ * of bytes dequeued or < 0 on error.
+ */
+ssize_t vmci_qpair_dequev(struct vmci_qp *qpair,
+ void *iov,
+ size_t iov_size,
+ int buf_type)
+{
+ ssize_t result;
+
+ if (!qpair || !iov)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+
+ do {
+ result = qp_dequeue_locked(qpair->produce_q,
+ qpair->consume_q,
+ qpair->consume_q_size,
+ iov, iov_size,
+ qp_memcpy_from_queue_iov,
+ true, vmci_can_block(qpair->flags));
+
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
+ !qp_wait_for_ready_queue(qpair))
+ result = VMCI_ERROR_WOULD_BLOCK;
+
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
+
+ qp_unlock(qpair);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_dequev);
+
+/*
+ * vmci_qpair_peekv() - Peek at the data in the queue using iov.
+ * @qpair: Pointer to the queue pair struct.
+ * @iov: Pointer to buffer for the data
+ * @iov_size: Length of buffer.
+ * @buf_type: Buffer type (Unused on Linux).
+ *
+ * This is the client interface for peeking into a queue. (I.e.,
+ * copy data from the queue without updating the head pointer.)
+ * This function uses IO vectors to handle the work. Returns number
+ * of bytes peeked or < 0 on error.
+ */
+ssize_t vmci_qpair_peekv(struct vmci_qp *qpair,
+ void *iov,
+ size_t iov_size,
+ int buf_type)
+{
+ ssize_t result;
+
+ if (!qpair || !iov)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ qp_lock(qpair);
+
+ do {
+ result = qp_dequeue_locked(qpair->produce_q,
+ qpair->consume_q,
+ qpair->consume_q_size,
+ iov, iov_size,
+ qp_memcpy_from_queue_iov,
+ false, vmci_can_block(qpair->flags));
+
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
+ !qp_wait_for_ready_queue(qpair))
+ result = VMCI_ERROR_WOULD_BLOCK;
+
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
+
+ qp_unlock(qpair);
+ return result;
+}
+EXPORT_SYMBOL_GPL(vmci_qpair_peekv);
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.h b/drivers/misc/vmw_vmci/vmci_queue_pair.h
new file mode 100644
index 000000000000..58c6959f6b6d
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.h
@@ -0,0 +1,191 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _VMCI_QUEUE_PAIR_H_
+#define _VMCI_QUEUE_PAIR_H_
+
+#include <linux/vmw_vmci_defs.h>
+#include <linux/types.h>
+
+#include "vmci_context.h"
+
+/* Callback needed for correctly waiting on events. */
+typedef int (*vmci_event_release_cb) (void *client_data);
+
+/* Guest device port I/O. */
+struct ppn_set {
+ u64 num_produce_pages;
+ u64 num_consume_pages;
+ u32 *produce_ppns;
+ u32 *consume_ppns;
+ bool initialized;
+};
+
+/* VMCIqueue_pairAllocInfo */
+struct vmci_qp_alloc_info {
+ struct vmci_handle handle;
+ u32 peer;
+ u32 flags;
+ u64 produce_size;
+ u64 consume_size;
+ u64 ppn_va; /* Start VA of queue pair PPNs. */
+ u64 num_ppns;
+ s32 result;
+ u32 version;
+};
+
+/* VMCIqueue_pairSetVAInfo */
+struct vmci_qp_set_va_info {
+ struct vmci_handle handle;
+ u64 va; /* Start VA of queue pair PPNs. */
+ u64 num_ppns;
+ u32 version;
+ s32 result;
+};
+
+/*
+ * For backwards compatibility, here is a version of the
+ * VMCIqueue_pairPageFileInfo before host support end-points was added.
+ * Note that the current version of that structure requires VMX to
+ * pass down the VA of the mapped file. Before host support was added
+ * there was nothing of the sort. So, when the driver sees the ioctl
+ * with a parameter that is the sizeof
+ * VMCIqueue_pairPageFileInfo_NoHostQP then it can infer that the version
+ * of VMX running can't attach to host end points because it doesn't
+ * provide the VA of the mapped files.
+ *
+ * The Linux driver doesn't get an indication of the size of the
+ * structure passed down from user space. So, to fix a long standing
+ * but unfiled bug, the _pad field has been renamed to version.
+ * Existing versions of VMX always initialize the PageFileInfo
+ * structure so that _pad, er, version is set to 0.
+ *
+ * A version value of 1 indicates that the size of the structure has
+ * been increased to include two UVA's: produce_uva and consume_uva.
+ * These UVA's are of the mmap()'d queue contents backing files.
+ *
+ * In addition, if when VMX is sending down the
+ * VMCIqueue_pairPageFileInfo structure it gets an error then it will
+ * try again with the _NoHostQP version of the file to see if an older
+ * VMCI kernel module is running.
+ */
+
+/* VMCIqueue_pairPageFileInfo */
+struct vmci_qp_page_file_info {
+ struct vmci_handle handle;
+ u64 produce_page_file; /* User VA. */
+ u64 consume_page_file; /* User VA. */
+ u64 produce_page_file_size; /* Size of the file name array. */
+ u64 consume_page_file_size; /* Size of the file name array. */
+ s32 result;
+ u32 version; /* Was _pad. */
+ u64 produce_va; /* User VA of the mapped file. */
+ u64 consume_va; /* User VA of the mapped file. */
+};
+
+/* vmci queuepair detach info */
+struct vmci_qp_dtch_info {
+ struct vmci_handle handle;
+ s32 result;
+ u32 _pad;
+};
+
+/*
+ * struct vmci_qp_page_store describes how the memory of a given queue pair
+ * is backed. When the queue pair is between the host and a guest, the
+ * page store consists of references to the guest pages. On vmkernel,
+ * this is a list of PPNs, and on hosted, it is a user VA where the
+ * queue pair is mapped into the VMX address space.
+ */
+struct vmci_qp_page_store {
+ /* Reference to pages backing the queue pair. */
+ u64 pages;
+ /* Length of pageList/virtual addres range (in pages). */
+ u32 len;
+};
+
+/*
+ * This data type contains the information about a queue.
+ * There are two queues (hence, queue pairs) per transaction model between a
+ * pair of end points, A & B. One queue is used by end point A to transmit
+ * commands and responses to B. The other queue is used by B to transmit
+ * commands and responses.
+ *
+ * struct vmci_queue_kern_if is a per-OS defined Queue structure. It contains
+ * either a direct pointer to the linear address of the buffer contents or a
+ * pointer to structures which help the OS locate those data pages. See
+ * vmciKernelIf.c for each platform for its definition.
+ */
+struct vmci_queue {
+ struct vmci_queue_header *q_header;
+ struct vmci_queue_header *saved_header;
+ struct vmci_queue_kern_if *kernel_if;
+};
+
+/*
+ * Utility function that checks whether the fields of the page
+ * store contain valid values.
+ * Result:
+ * true if the page store is wellformed. false otherwise.
+ */
+static inline bool
+VMCI_QP_PAGESTORE_IS_WELLFORMED(struct vmci_qp_page_store *page_store)
+{
+ return page_store->len >= 2;
+}
+
+/*
+ * Helper function to check if the non-blocking flag
+ * is set for a given queue pair.
+ */
+static inline bool vmci_can_block(u32 flags)
+{
+ return !(flags & VMCI_QPFLAG_NONBLOCK);
+}
+
+/*
+ * Helper function to check if the queue pair is pinned
+ * into memory.
+ */
+static inline bool vmci_qp_pinned(u32 flags)
+{
+ return flags & VMCI_QPFLAG_PINNED;
+}
+
+void vmci_qp_broker_exit(void);
+int vmci_qp_broker_alloc(struct vmci_handle handle, u32 peer,
+ u32 flags, u32 priv_flags,
+ u64 produce_size, u64 consume_size,
+ struct vmci_qp_page_store *page_store,
+ struct vmci_ctx *context);
+int vmci_qp_broker_set_page_store(struct vmci_handle handle,
+ u64 produce_uva, u64 consume_uva,
+ struct vmci_ctx *context);
+int vmci_qp_broker_detach(struct vmci_handle handle, struct vmci_ctx *context);
+
+void vmci_qp_guest_endpoints_exit(void);
+
+int vmci_qp_alloc(struct vmci_handle *handle,
+ struct vmci_queue **produce_q, u64 produce_size,
+ struct vmci_queue **consume_q, u64 consume_size,
+ u32 peer, u32 flags, u32 priv_flags,
+ bool guest_endpoint, vmci_event_release_cb wakeup_cb,
+ void *client_data);
+int vmci_qp_broker_map(struct vmci_handle handle,
+ struct vmci_ctx *context, u64 guest_mem);
+int vmci_qp_broker_unmap(struct vmci_handle handle,
+ struct vmci_ctx *context, u32 gid);
+
+#endif /* _VMCI_QUEUE_PAIR_H_ */
diff --git a/drivers/misc/vmw_vmci/vmci_resource.c b/drivers/misc/vmw_vmci/vmci_resource.c
new file mode 100644
index 000000000000..a196f84a4fd2
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_resource.c
@@ -0,0 +1,229 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/vmw_vmci_defs.h>
+#include <linux/hash.h>
+#include <linux/types.h>
+#include <linux/rculist.h>
+
+#include "vmci_resource.h"
+#include "vmci_driver.h"
+
+
+#define VMCI_RESOURCE_HASH_BITS 7
+#define VMCI_RESOURCE_HASH_BUCKETS (1 << VMCI_RESOURCE_HASH_BITS)
+
+struct vmci_hash_table {
+ spinlock_t lock;
+ struct hlist_head entries[VMCI_RESOURCE_HASH_BUCKETS];
+};
+
+static struct vmci_hash_table vmci_resource_table = {
+ .lock = __SPIN_LOCK_UNLOCKED(vmci_resource_table.lock),
+};
+
+static unsigned int vmci_resource_hash(struct vmci_handle handle)
+{
+ return hash_32(handle.resource, VMCI_RESOURCE_HASH_BITS);
+}
+
+/*
+ * Gets a resource (if one exists) matching given handle from the hash table.
+ */
+static struct vmci_resource *vmci_resource_lookup(struct vmci_handle handle,
+ enum vmci_resource_type type)
+{
+ struct vmci_resource *r, *resource = NULL;
+ struct hlist_node *node;
+ unsigned int idx = vmci_resource_hash(handle);
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(r, node,
+ &vmci_resource_table.entries[idx], node) {
+ u32 cid = r->handle.context;
+ u32 rid = r->handle.resource;
+
+ if (r->type == type &&
+ rid == handle.resource &&
+ (cid == handle.context || cid == VMCI_INVALID_ID)) {
+ resource = r;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return resource;
+}
+
+/*
+ * Find an unused resource ID and return it. The first
+ * VMCI_RESERVED_RESOURCE_ID_MAX are reserved so we start from
+ * its value + 1.
+ * Returns VMCI resource id on success, VMCI_INVALID_ID on failure.
+ */
+static u32 vmci_resource_find_id(u32 context_id,
+ enum vmci_resource_type resource_type)
+{
+ static u32 resource_id = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
+ u32 old_rid = resource_id;
+ u32 current_rid;
+
+ /*
+ * Generate a unique resource ID. Keep on trying until we wrap around
+ * in the RID space.
+ */
+ do {
+ struct vmci_handle handle;
+
+ current_rid = resource_id;
+ resource_id++;
+ if (unlikely(resource_id == VMCI_INVALID_ID)) {
+ /* Skip the reserved rids. */
+ resource_id = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
+ }
+
+ handle = vmci_make_handle(context_id, current_rid);
+ if (!vmci_resource_lookup(handle, resource_type))
+ return current_rid;
+ } while (resource_id != old_rid);
+
+ return VMCI_INVALID_ID;
+}
+
+
+int vmci_resource_add(struct vmci_resource *resource,
+ enum vmci_resource_type resource_type,
+ struct vmci_handle handle)
+
+{
+ unsigned int idx;
+ int result;
+
+ spin_lock(&vmci_resource_table.lock);
+
+ if (handle.resource == VMCI_INVALID_ID) {
+ handle.resource = vmci_resource_find_id(handle.context,
+ resource_type);
+ if (handle.resource == VMCI_INVALID_ID) {
+ result = VMCI_ERROR_NO_HANDLE;
+ goto out;
+ }
+ } else if (vmci_resource_lookup(handle, resource_type)) {
+ result = VMCI_ERROR_ALREADY_EXISTS;
+ goto out;
+ }
+
+ resource->handle = handle;
+ resource->type = resource_type;
+ INIT_HLIST_NODE(&resource->node);
+ kref_init(&resource->kref);
+ init_completion(&resource->done);
+
+ idx = vmci_resource_hash(resource->handle);
+ hlist_add_head_rcu(&resource->node, &vmci_resource_table.entries[idx]);
+
+ result = VMCI_SUCCESS;
+
+out:
+ spin_unlock(&vmci_resource_table.lock);
+ return result;
+}
+
+void vmci_resource_remove(struct vmci_resource *resource)
+{
+ struct vmci_handle handle = resource->handle;
+ unsigned int idx = vmci_resource_hash(handle);
+ struct vmci_resource *r;
+ struct hlist_node *node;
+
+ /* Remove resource from hash table. */
+ spin_lock(&vmci_resource_table.lock);
+
+ hlist_for_each_entry(r, node, &vmci_resource_table.entries[idx], node) {
+ if (vmci_handle_is_equal(r->handle, resource->handle)) {
+ hlist_del_init_rcu(&r->node);
+ break;
+ }
+ }
+
+ spin_unlock(&vmci_resource_table.lock);
+ synchronize_rcu();
+
+ vmci_resource_put(resource);
+ wait_for_completion(&resource->done);
+}
+
+struct vmci_resource *
+vmci_resource_by_handle(struct vmci_handle resource_handle,
+ enum vmci_resource_type resource_type)
+{
+ struct vmci_resource *r, *resource = NULL;
+
+ rcu_read_lock();
+
+ r = vmci_resource_lookup(resource_handle, resource_type);
+ if (r &&
+ (resource_type == r->type ||
+ resource_type == VMCI_RESOURCE_TYPE_ANY)) {
+ resource = vmci_resource_get(r);
+ }
+
+ rcu_read_unlock();
+
+ return resource;
+}
+
+/*
+ * Get a reference to given resource.
+ */
+struct vmci_resource *vmci_resource_get(struct vmci_resource *resource)
+{
+ kref_get(&resource->kref);
+
+ return resource;
+}
+
+static void vmci_release_resource(struct kref *kref)
+{
+ struct vmci_resource *resource =
+ container_of(kref, struct vmci_resource, kref);
+
+ /* Verify the resource has been unlinked from hash table */
+ WARN_ON(!hlist_unhashed(&resource->node));
+
+ /* Signal that container of this resource can now be destroyed */
+ complete(&resource->done);
+}
+
+/*
+ * Resource's release function will get called if last reference.
+ * If it is the last reference, then we are sure that nobody else
+ * can increment the count again (it's gone from the resource hash
+ * table), so there's no need for locking here.
+ */
+int vmci_resource_put(struct vmci_resource *resource)
+{
+ /*
+ * We propagate the information back to caller in case it wants to know
+ * whether entry was freed.
+ */
+ return kref_put(&resource->kref, vmci_release_resource) ?
+ VMCI_SUCCESS_ENTRY_DEAD : VMCI_SUCCESS;
+}
+
+struct vmci_handle vmci_resource_handle(struct vmci_resource *resource)
+{
+ return resource->handle;
+}
diff --git a/drivers/misc/vmw_vmci/vmci_resource.h b/drivers/misc/vmw_vmci/vmci_resource.h
new file mode 100644
index 000000000000..9190cd298bee
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_resource.h
@@ -0,0 +1,59 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _VMCI_RESOURCE_H_
+#define _VMCI_RESOURCE_H_
+
+#include <linux/vmw_vmci_defs.h>
+#include <linux/types.h>
+
+#include "vmci_context.h"
+
+
+enum vmci_resource_type {
+ VMCI_RESOURCE_TYPE_ANY,
+ VMCI_RESOURCE_TYPE_API,
+ VMCI_RESOURCE_TYPE_GROUP,
+ VMCI_RESOURCE_TYPE_DATAGRAM,
+ VMCI_RESOURCE_TYPE_DOORBELL,
+ VMCI_RESOURCE_TYPE_QPAIR_GUEST,
+ VMCI_RESOURCE_TYPE_QPAIR_HOST
+};
+
+struct vmci_resource {
+ struct vmci_handle handle;
+ enum vmci_resource_type type;
+ struct hlist_node node;
+ struct kref kref;
+ struct completion done;
+};
+
+
+int vmci_resource_add(struct vmci_resource *resource,
+ enum vmci_resource_type resource_type,
+ struct vmci_handle handle);
+
+void vmci_resource_remove(struct vmci_resource *resource);
+
+struct vmci_resource *
+vmci_resource_by_handle(struct vmci_handle resource_handle,
+ enum vmci_resource_type resource_type);
+
+struct vmci_resource *vmci_resource_get(struct vmci_resource *resource);
+int vmci_resource_put(struct vmci_resource *resource);
+
+struct vmci_handle vmci_resource_handle(struct vmci_resource *resource);
+
+#endif /* _VMCI_RESOURCE_H_ */
diff --git a/drivers/misc/vmw_vmci/vmci_route.c b/drivers/misc/vmw_vmci/vmci_route.c
new file mode 100644
index 000000000000..91090658b929
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_route.c
@@ -0,0 +1,226 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+
+#include "vmci_context.h"
+#include "vmci_driver.h"
+#include "vmci_route.h"
+
+/*
+ * Make a routing decision for the given source and destination handles.
+ * This will try to determine the route using the handles and the available
+ * devices. Will set the source context if it is invalid.
+ */
+int vmci_route(struct vmci_handle *src,
+ const struct vmci_handle *dst,
+ bool from_guest,
+ enum vmci_route *route)
+{
+ bool has_host_device = vmci_host_code_active();
+ bool has_guest_device = vmci_guest_code_active();
+
+ *route = VMCI_ROUTE_NONE;
+
+ /*
+ * "from_guest" is only ever set to true by
+ * IOCTL_VMCI_DATAGRAM_SEND (or by the vmkernel equivalent),
+ * which comes from the VMX, so we know it is coming from a
+ * guest.
+ *
+ * To avoid inconsistencies, test these once. We will test
+ * them again when we do the actual send to ensure that we do
+ * not touch a non-existent device.
+ */
+
+ /* Must have a valid destination context. */
+ if (VMCI_INVALID_ID == dst->context)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ /* Anywhere to hypervisor. */
+ if (VMCI_HYPERVISOR_CONTEXT_ID == dst->context) {
+
+ /*
+ * If this message already came from a guest then we
+ * cannot send it to the hypervisor. It must come
+ * from a local client.
+ */
+ if (from_guest)
+ return VMCI_ERROR_DST_UNREACHABLE;
+
+ /*
+ * We must be acting as a guest in order to send to
+ * the hypervisor.
+ */
+ if (!has_guest_device)
+ return VMCI_ERROR_DEVICE_NOT_FOUND;
+
+ /* And we cannot send if the source is the host context. */
+ if (VMCI_HOST_CONTEXT_ID == src->context)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ /*
+ * If the client passed the ANON source handle then
+ * respect it (both context and resource are invalid).
+ * However, if they passed only an invalid context,
+ * then they probably mean ANY, in which case we
+ * should set the real context here before passing it
+ * down.
+ */
+ if (VMCI_INVALID_ID == src->context &&
+ VMCI_INVALID_ID != src->resource)
+ src->context = vmci_get_context_id();
+
+ /* Send from local client down to the hypervisor. */
+ *route = VMCI_ROUTE_AS_GUEST;
+ return VMCI_SUCCESS;
+ }
+
+ /* Anywhere to local client on host. */
+ if (VMCI_HOST_CONTEXT_ID == dst->context) {
+ /*
+ * If it is not from a guest but we are acting as a
+ * guest, then we need to send it down to the host.
+ * Note that if we are also acting as a host then this
+ * will prevent us from sending from local client to
+ * local client, but we accept that restriction as a
+ * way to remove any ambiguity from the host context.
+ */
+ if (src->context == VMCI_HYPERVISOR_CONTEXT_ID) {
+ /*
+ * If the hypervisor is the source, this is
+ * host local communication. The hypervisor
+ * may send vmci event datagrams to the host
+ * itself, but it will never send datagrams to
+ * an "outer host" through the guest device.
+ */
+
+ if (has_host_device) {
+ *route = VMCI_ROUTE_AS_HOST;
+ return VMCI_SUCCESS;
+ } else {
+ return VMCI_ERROR_DEVICE_NOT_FOUND;
+ }
+ }
+
+ if (!from_guest && has_guest_device) {
+ /* If no source context then use the current. */
+ if (VMCI_INVALID_ID == src->context)
+ src->context = vmci_get_context_id();
+
+ /* Send it from local client down to the host. */
+ *route = VMCI_ROUTE_AS_GUEST;
+ return VMCI_SUCCESS;
+ }
+
+ /*
+ * Otherwise we already received it from a guest and
+ * it is destined for a local client on this host, or
+ * it is from another local client on this host. We
+ * must be acting as a host to service it.
+ */
+ if (!has_host_device)
+ return VMCI_ERROR_DEVICE_NOT_FOUND;
+
+ if (VMCI_INVALID_ID == src->context) {
+ /*
+ * If it came from a guest then it must have a
+ * valid context. Otherwise we can use the
+ * host context.
+ */
+ if (from_guest)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ src->context = VMCI_HOST_CONTEXT_ID;
+ }
+
+ /* Route to local client. */
+ *route = VMCI_ROUTE_AS_HOST;
+ return VMCI_SUCCESS;
+ }
+
+ /*
+ * If we are acting as a host then this might be destined for
+ * a guest.
+ */
+ if (has_host_device) {
+ /* It will have a context if it is meant for a guest. */
+ if (vmci_ctx_exists(dst->context)) {
+ if (VMCI_INVALID_ID == src->context) {
+ /*
+ * If it came from a guest then it
+ * must have a valid context.
+ * Otherwise we can use the host
+ * context.
+ */
+
+ if (from_guest)
+ return VMCI_ERROR_INVALID_ARGS;
+
+ src->context = VMCI_HOST_CONTEXT_ID;
+ } else if (VMCI_CONTEXT_IS_VM(src->context) &&
+ src->context != dst->context) {
+ /*
+ * VM to VM communication is not
+ * allowed. Since we catch all
+ * communication destined for the host
+ * above, this must be destined for a
+ * VM since there is a valid context.
+ */
+
+ return VMCI_ERROR_DST_UNREACHABLE;
+ }
+
+ /* Pass it up to the guest. */
+ *route = VMCI_ROUTE_AS_HOST;
+ return VMCI_SUCCESS;
+ } else if (!has_guest_device) {
+ /*
+ * The host is attempting to reach a CID
+ * without an active context, and we can't
+ * send it down, since we have no guest
+ * device.
+ */
+
+ return VMCI_ERROR_DST_UNREACHABLE;
+ }
+ }
+
+ /*
+ * We must be a guest trying to send to another guest, which means
+ * we need to send it down to the host. We do not filter out VM to
+ * VM communication here, since we want to be able to use the guest
+ * driver on older versions that do support VM to VM communication.
+ */
+ if (!has_guest_device) {
+ /*
+ * Ending up here means we have neither guest nor host
+ * device.
+ */
+ return VMCI_ERROR_DEVICE_NOT_FOUND;
+ }
+
+ /* If no source context then use the current context. */
+ if (VMCI_INVALID_ID == src->context)
+ src->context = vmci_get_context_id();
+
+ /*
+ * Send it from local client down to the host, which will
+ * route it to the other guest for us.
+ */
+ *route = VMCI_ROUTE_AS_GUEST;
+ return VMCI_SUCCESS;
+}
diff --git a/drivers/misc/vmw_vmci/vmci_route.h b/drivers/misc/vmw_vmci/vmci_route.h
new file mode 100644
index 000000000000..3b30e82419c3
--- /dev/null
+++ b/drivers/misc/vmw_vmci/vmci_route.h
@@ -0,0 +1,30 @@
+/*
+ * VMware VMCI Driver
+ *
+ * Copyright (C) 2012 VMware, 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 version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT 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 _VMCI_ROUTE_H_
+#define _VMCI_ROUTE_H_
+
+#include <linux/vmw_vmci_defs.h>
+
+enum vmci_route {
+ VMCI_ROUTE_NONE,
+ VMCI_ROUTE_AS_HOST,
+ VMCI_ROUTE_AS_GUEST,
+};
+
+int vmci_route(struct vmci_handle *src, const struct vmci_handle *dst,
+ bool from_guest, enum vmci_route *route);
+
+#endif /* _VMCI_ROUTE_H_ */
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 3b1f783bf924..5562308699bc 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -52,6 +52,7 @@ config MMC_BLOCK_BOUNCE
config SDIO_UART
tristate "SDIO UART/GPS class support"
+ depends on TTY
help
SDIO function driver for SDIO cards that implements the UART
class, as well as the GPS class which appears like a UART.
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index bd57a11acc79..c931dfe6a59c 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -381,7 +381,6 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port)
static void sdio_uart_receive_chars(struct sdio_uart_port *port,
unsigned int *status)
{
- struct tty_struct *tty = tty_port_tty_get(&port->port);
unsigned int ch, flag;
int max_count = 256;
@@ -418,23 +417,19 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
}
if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
- if (tty)
- tty_insert_flip_char(tty, ch, flag);
+ tty_insert_flip_char(&port->port, ch, flag);
/*
* Overrun is special. Since it's reported immediately,
* it doesn't affect the current character.
*/
if (*status & ~port->ignore_status_mask & UART_LSR_OE)
- if (tty)
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
*status = sdio_in(port, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
- if (tty) {
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
- }
+
+ tty_flip_buffer_push(&port->port);
}
static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index ef103871517f..269d072ef55e 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -18,8 +18,7 @@ config MMC_UNSAFE_RESUME
module parameter "removable=0" or "removable=1".
config MMC_CLKGATE
- bool "MMC host clock gating (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "MMC host clock gating"
help
This will attempt to aggressively gate the clock to the MMC card.
This is done to save power due to gating off the logic and bus
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 8d13c6594520..3be8b94d7914 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -69,7 +69,7 @@ config MMC_SDHCI_PCI
If unsure, say N.
config MMC_RICOH_MMC
- bool "Ricoh MMC Controller Disabler (EXPERIMENTAL)"
+ bool "Ricoh MMC Controller Disabler"
depends on MMC_SDHCI_PCI
help
This adds a pci quirk to disable Ricoh MMC Controller. This
@@ -186,9 +186,6 @@ config MMC_SDHCI_S3C
often referrered to as the HSMMC block in some of the Samsung S3C
range of SoC.
- Note, due to the problems with DMA, the DMA support is only
- available with CONFIG_EXPERIMENTAL is selected.
-
If you have a controller with this interface, say Y or M here.
If unsure, say N.
@@ -233,7 +230,7 @@ config MMC_SDHCI_SPEAR
config MMC_SDHCI_S3C_DMA
bool "DMA support on S3C SDHCI"
- depends on MMC_SDHCI_S3C && EXPERIMENTAL
+ depends on MMC_SDHCI_S3C
help
Enable DMA support on the Samsung S3C SDHCI glue. The DMA
has proved to be problematic if the controller encounters
@@ -330,8 +327,8 @@ config MMC_MXS
If unsure, say N.
config MMC_TIFM_SD
- tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PCI
+ tristate "TI Flash Media MMC/SD Interface support"
+ depends on PCI
select TIFM_CORE
help
Say Y here if you want to be able to access MMC/SD cards with
@@ -410,8 +407,7 @@ config MMC_S3C_PIO
the S3C MCI driver.
config MMC_S3C_DMA
- bool "Use DMA transfers only (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "Use DMA transfers only"
help
Use DMA to transfer data between memory and the hardare.
@@ -420,7 +416,7 @@ config MMC_S3C_DMA
option is useful.
config MMC_S3C_PIODMA
- bool "Support for both PIO and DMA (EXPERIMENTAL)"
+ bool "Support for both PIO and DMA"
help
Compile both the PIO and DMA transfer routines into the
driver and let the platform select at run-time which one
@@ -431,8 +427,8 @@ config MMC_S3C_PIODMA
endchoice
config MMC_SDRICOH_CS
- tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PCI && PCMCIA
+ tristate "MMC/SD driver for Ricoh Bay1Controllers"
+ depends on PCI && PCMCIA
help
Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA
card whenever you insert a MMC or SD card into the card slot.
@@ -461,7 +457,7 @@ config MMC_SDHI
config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support"
- depends on PCI
+ depends on PCI && GENERIC_HARDIRQS
select CB710_CORE
help
This option enables support for MMC/SD part of ENE CB710/720 Flash
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 5e1fb1d2c422..41c27b74b003 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -10,6 +10,7 @@
* (at your option) any later version.
*/
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/io.h>
@@ -46,9 +47,9 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
host->dev = &pdev->dev;
host->irq_flags = 0;
host->pdata = pdev->dev.platform_data;
- host->regs = devm_request_and_ioremap(&pdev->dev, regs);
- if (!host->regs)
- return -ENOMEM;
+ host->regs = devm_ioremap_resource(&pdev->dev, regs);
+ if (IS_ERR(host->regs))
+ return PTR_ERR(host->regs);
if (drv_data && drv_data->init) {
ret = drv_data->init(host);
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 150772395cc6..372e921389c8 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/log2.h>
+#include <linux/mmc/pm.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/amba/bus.h>
@@ -59,6 +60,7 @@ static unsigned int fmax = 515633;
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
* @pwrreg_powerup: power up value for MMCIPOWER register
* @signal_direction: input/out direction of bus signals can be indicated
+ * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
*/
struct variant_data {
unsigned int clkreg;
@@ -71,6 +73,7 @@ struct variant_data {
bool blksz_datactrl16;
u32 pwrreg_powerup;
bool signal_direction;
+ bool pwrreg_clkgate;
};
static struct variant_data variant_arm = {
@@ -87,6 +90,14 @@ static struct variant_data variant_arm_extended_fifo = {
.pwrreg_powerup = MCI_PWR_UP,
};
+static struct variant_data variant_arm_extended_fifo_hwfc = {
+ .fifosize = 128 * 4,
+ .fifohalfsize = 64 * 4,
+ .clkreg_enable = MCI_ARM_HWFCEN,
+ .datalength_bits = 16,
+ .pwrreg_powerup = MCI_PWR_UP,
+};
+
static struct variant_data variant_u300 = {
.fifosize = 16 * 4,
.fifohalfsize = 8 * 4,
@@ -95,6 +106,7 @@ static struct variant_data variant_u300 = {
.sdio = true,
.pwrreg_powerup = MCI_PWR_ON,
.signal_direction = true,
+ .pwrreg_clkgate = true,
};
static struct variant_data variant_nomadik = {
@@ -106,6 +118,7 @@ static struct variant_data variant_nomadik = {
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
.signal_direction = true,
+ .pwrreg_clkgate = true,
};
static struct variant_data variant_ux500 = {
@@ -118,6 +131,7 @@ static struct variant_data variant_ux500 = {
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
.signal_direction = true,
+ .pwrreg_clkgate = true,
};
static struct variant_data variant_ux500v2 = {
@@ -131,9 +145,28 @@ static struct variant_data variant_ux500v2 = {
.blksz_datactrl16 = true,
.pwrreg_powerup = MCI_PWR_ON,
.signal_direction = true,
+ .pwrreg_clkgate = true,
};
/*
+ * Validate mmc prerequisites
+ */
+static int mmci_validate_data(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ if (!data)
+ return 0;
+
+ if (!is_power_of_2(data->blksz)) {
+ dev_err(mmc_dev(host->mmc),
+ "unsupported block size (%d bytes)\n", data->blksz);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
* This must be called with host->lock held
*/
static void mmci_write_clkreg(struct mmci_host *host, u32 clk)
@@ -202,6 +235,9 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
clk |= MCI_ST_8BIT_BUS;
+ if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+ clk |= MCI_ST_UX500_NEG_EDGE;
+
mmci_write_clkreg(host, clk);
}
@@ -352,10 +388,33 @@ static inline void mmci_dma_release(struct mmci_host *host)
host->dma_rx_channel = host->dma_tx_channel = NULL;
}
+static void mmci_dma_data_error(struct mmci_host *host)
+{
+ dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
+ dmaengine_terminate_all(host->dma_current);
+ host->dma_current = NULL;
+ host->dma_desc_current = NULL;
+ host->data->host_cookie = 0;
+}
+
static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
{
- struct dma_chan *chan = host->dma_current;
+ struct dma_chan *chan;
enum dma_data_direction dir;
+
+ if (data->flags & MMC_DATA_READ) {
+ dir = DMA_FROM_DEVICE;
+ chan = host->dma_rx_channel;
+ } else {
+ dir = DMA_TO_DEVICE;
+ chan = host->dma_tx_channel;
+ }
+
+ dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
+}
+
+static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
+{
u32 status;
int i;
@@ -374,19 +433,13 @@ static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
* contiguous buffers. On TX, we'll get a FIFO underrun error.
*/
if (status & MCI_RXDATAAVLBLMASK) {
- dmaengine_terminate_all(chan);
+ mmci_dma_data_error(host);
if (!data->error)
data->error = -EIO;
}
- if (data->flags & MMC_DATA_WRITE) {
- dir = DMA_TO_DEVICE;
- } else {
- dir = DMA_FROM_DEVICE;
- }
-
if (!data->host_cookie)
- dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
+ mmci_dma_unmap(host, data);
/*
* Use of DMA with scatter-gather is impossible.
@@ -396,16 +449,15 @@ static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n");
mmci_dma_release(host);
}
-}
-static void mmci_dma_data_error(struct mmci_host *host)
-{
- dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
- dmaengine_terminate_all(host->dma_current);
+ host->dma_current = NULL;
+ host->dma_desc_current = NULL;
}
-static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
- struct mmci_host_next *next)
+/* prepares DMA channel and DMA descriptor, returns non-zero on failure */
+static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
+ struct dma_chan **dma_chan,
+ struct dma_async_tx_descriptor **dma_desc)
{
struct variant_data *variant = host->variant;
struct dma_slave_config conf = {
@@ -423,16 +475,6 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
enum dma_data_direction buffer_dirn;
int nr_sg;
- /* Check if next job is already prepared */
- if (data->host_cookie && !next &&
- host->dma_current && host->dma_desc_current)
- return 0;
-
- if (!next) {
- host->dma_current = NULL;
- host->dma_desc_current = NULL;
- }
-
if (data->flags & MMC_DATA_READ) {
conf.direction = DMA_DEV_TO_MEM;
buffer_dirn = DMA_FROM_DEVICE;
@@ -462,29 +504,41 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
if (!desc)
goto unmap_exit;
- if (next) {
- next->dma_chan = chan;
- next->dma_desc = desc;
- } else {
- host->dma_current = chan;
- host->dma_desc_current = desc;
- }
+ *dma_chan = chan;
+ *dma_desc = desc;
return 0;
unmap_exit:
- if (!next)
- dmaengine_terminate_all(chan);
dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn);
return -ENOMEM;
}
+static inline int mmci_dma_prep_data(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ /* Check if next job is already prepared. */
+ if (host->dma_current && host->dma_desc_current)
+ return 0;
+
+ /* No job were prepared thus do it now. */
+ return __mmci_dma_prep_data(host, data, &host->dma_current,
+ &host->dma_desc_current);
+}
+
+static inline int mmci_dma_prep_next(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ struct mmci_host_next *nd = &host->next_data;
+ return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc);
+}
+
static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
{
int ret;
struct mmc_data *data = host->data;
- ret = mmci_dma_prep_data(host, host->data, NULL);
+ ret = mmci_dma_prep_data(host, host->data);
if (ret)
return ret;
@@ -514,19 +568,11 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
{
struct mmci_host_next *next = &host->next_data;
- if (data->host_cookie && data->host_cookie != next->cookie) {
- pr_warning("[%s] invalid cookie: data->host_cookie %d"
- " host->next_data.cookie %d\n",
- __func__, data->host_cookie, host->next_data.cookie);
- data->host_cookie = 0;
- }
-
- if (!data->host_cookie)
- return;
+ WARN_ON(data->host_cookie && data->host_cookie != next->cookie);
+ WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan));
host->dma_desc_current = next->dma_desc;
host->dma_current = next->dma_chan;
-
next->dma_desc = NULL;
next->dma_chan = NULL;
}
@@ -541,19 +587,13 @@ static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq,
if (!data)
return;
- if (data->host_cookie) {
- data->host_cookie = 0;
+ BUG_ON(data->host_cookie);
+
+ if (mmci_validate_data(host, data))
return;
- }
- /* if config for dma */
- if (((data->flags & MMC_DATA_WRITE) && host->dma_tx_channel) ||
- ((data->flags & MMC_DATA_READ) && host->dma_rx_channel)) {
- if (mmci_dma_prep_data(host, data, nd))
- data->host_cookie = 0;
- else
- data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
- }
+ if (!mmci_dma_prep_next(host, data))
+ data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
}
static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
@@ -561,29 +601,23 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
{
struct mmci_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
- struct dma_chan *chan;
- enum dma_data_direction dir;
- if (!data)
+ if (!data || !data->host_cookie)
return;
- if (data->flags & MMC_DATA_READ) {
- dir = DMA_FROM_DEVICE;
- chan = host->dma_rx_channel;
- } else {
- dir = DMA_TO_DEVICE;
- chan = host->dma_tx_channel;
- }
+ mmci_dma_unmap(host, data);
+ if (err) {
+ struct mmci_host_next *next = &host->next_data;
+ struct dma_chan *chan;
+ if (data->flags & MMC_DATA_READ)
+ chan = host->dma_rx_channel;
+ else
+ chan = host->dma_tx_channel;
+ dmaengine_terminate_all(chan);
- /* if config for dma */
- if (chan) {
- if (err)
- dmaengine_terminate_all(chan);
- if (data->host_cookie)
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, dir);
- mrq->data->host_cookie = 0;
+ next->dma_desc = NULL;
+ next->dma_chan = NULL;
}
}
@@ -604,6 +638,11 @@ static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
{
}
+static inline void mmci_dma_finalize(struct mmci_host *host,
+ struct mmc_data *data)
+{
+}
+
static inline void mmci_dma_data_error(struct mmci_host *host)
{
}
@@ -680,6 +719,9 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
mmci_write_clkreg(host, clk);
}
+ if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+ datactrl |= MCI_ST_DPSM_DDRMODE;
+
/*
* Attempt to use DMA operation mode, if this
* should fail, fall back to PIO mode
@@ -751,8 +793,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
u32 remain, success;
/* Terminate the DMA transfer */
- if (dma_inprogress(host))
+ if (dma_inprogress(host)) {
mmci_dma_data_error(host);
+ mmci_dma_unmap(host, data);
+ }
/*
* Calculate how far we are into the transfer. Note that
@@ -791,7 +835,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
if (status & MCI_DATAEND || data->error) {
if (dma_inprogress(host))
- mmci_dma_unmap(host, data);
+ mmci_dma_finalize(host, data);
mmci_stop_data(host);
if (!data->error)
@@ -828,8 +872,10 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
if (!cmd->data || cmd->error) {
if (host->data) {
/* Terminate the DMA transfer */
- if (dma_inprogress(host))
+ if (dma_inprogress(host)) {
mmci_dma_data_error(host);
+ mmci_dma_unmap(host, host->data);
+ }
mmci_stop_data(host);
}
mmci_request_end(host, cmd->mrq);
@@ -1055,10 +1101,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
WARN_ON(host->mrq != NULL);
- if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
- dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n",
- mrq->data->blksz);
- mrq->cmd->error = -EINVAL;
+ mrq->cmd->error = mmci_validate_data(host, mrq->data);
+ if (mrq->cmd->error) {
mmc_request_done(mmc, mrq);
return;
}
@@ -1086,7 +1130,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct variant_data *variant = host->variant;
u32 pwr = 0;
unsigned long flags;
- int ret;
pm_runtime_get_sync(mmc_dev(mmc));
@@ -1096,23 +1139,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_OFF:
- if (host->vcc)
- ret = mmc_regulator_set_ocr(mmc, host->vcc, 0);
+ if (!IS_ERR(mmc->supply.vmmc))
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
break;
case MMC_POWER_UP:
- if (host->vcc) {
- ret = mmc_regulator_set_ocr(mmc, host->vcc, ios->vdd);
- if (ret) {
- dev_err(mmc_dev(mmc), "unable to set OCR\n");
- /*
- * The .set_ios() function in the mmc_host_ops
- * struct return void, and failing to set the
- * power should be rare so we print an error
- * and return here.
- */
- goto out;
- }
- }
+ if (!IS_ERR(mmc->supply.vmmc))
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
+
/*
* The ST Micro variant doesn't have the PL180s MCI_PWR_UP
* and instead uses MCI_PWR_ON so apply whatever value is
@@ -1154,6 +1187,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
}
+ /*
+ * If clock = 0 and the variant requires the MMCIPOWER to be used for
+ * gating the clock, the MCI_PWR_ON bit is cleared.
+ */
+ if (!ios->clock && variant->pwrreg_clkgate)
+ pwr &= ~MCI_PWR_ON;
+
spin_lock_irqsave(&host->lock, flags);
mmci_set_clkreg(host, ios->clock);
@@ -1161,7 +1201,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
spin_unlock_irqrestore(&host->lock, flags);
- out:
pm_runtime_mark_last_busy(mmc_dev(mmc));
pm_runtime_put_autosuspend(mmc_dev(mmc));
}
@@ -1384,32 +1423,19 @@ static int mmci_probe(struct amba_device *dev,
} else
dev_warn(&dev->dev, "could not get default pinstate\n");
-#ifdef CONFIG_REGULATOR
- /* If we're using the regulator framework, try to fetch a regulator */
- host->vcc = regulator_get(&dev->dev, "vmmc");
- if (IS_ERR(host->vcc))
- host->vcc = NULL;
- else {
- int mask = mmc_regulator_get_ocrmask(host->vcc);
-
- if (mask < 0)
- dev_err(&dev->dev, "error getting OCR mask (%d)\n",
- mask);
- else {
- host->mmc->ocr_avail = (u32) mask;
- if (plat->ocr_mask)
- dev_warn(&dev->dev,
- "Provided ocr_mask/setpower will not be used "
- "(using regulator instead)\n");
- }
- }
-#endif
- /* Fall back to platform data if no regulator is found */
- if (host->vcc == NULL)
+ /* Get regulators and the supported OCR mask */
+ mmc_regulator_get_supply(mmc);
+ if (!mmc->ocr_avail)
mmc->ocr_avail = plat->ocr_mask;
+ else if (plat->ocr_mask)
+ dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
+
mmc->caps = plat->capabilities;
mmc->caps2 = plat->capabilities2;
+ /* We support these PM capabilities. */
+ mmc->pm_caps = MMC_PM_KEEP_POWER;
+
/*
* We can do SGIO
*/
@@ -1585,10 +1611,6 @@ static int mmci_remove(struct amba_device *dev)
clk_disable_unprepare(host->clk);
clk_put(host->clk);
- if (host->vcc)
- mmc_regulator_set_ocr(mmc, host->vcc, 0);
- regulator_put(host->vcc);
-
mmc_free_host(mmc);
amba_release_regions(dev);
@@ -1636,8 +1658,37 @@ static int mmci_resume(struct device *dev)
}
#endif
+#ifdef CONFIG_PM_RUNTIME
+static int mmci_runtime_suspend(struct device *dev)
+{
+ struct amba_device *adev = to_amba_device(dev);
+ struct mmc_host *mmc = amba_get_drvdata(adev);
+
+ if (mmc) {
+ struct mmci_host *host = mmc_priv(mmc);
+ clk_disable_unprepare(host->clk);
+ }
+
+ return 0;
+}
+
+static int mmci_runtime_resume(struct device *dev)
+{
+ struct amba_device *adev = to_amba_device(dev);
+ struct mmc_host *mmc = amba_get_drvdata(adev);
+
+ if (mmc) {
+ struct mmci_host *host = mmc_priv(mmc);
+ clk_prepare_enable(host->clk);
+ }
+
+ return 0;
+}
+#endif
+
static const struct dev_pm_ops mmci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume)
+ SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL)
};
static struct amba_id mmci_ids[] = {
@@ -1652,6 +1703,11 @@ static struct amba_id mmci_ids[] = {
.data = &variant_arm_extended_fifo,
},
{
+ .id = 0x02041180,
+ .mask = 0xff0fffff,
+ .data = &variant_arm_extended_fifo_hwfc,
+ },
+ {
.id = 0x00041181,
.mask = 0x000fffff,
.data = &variant_arm,
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index d34d8c0add8e..1f33ad5333a0 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -28,6 +28,8 @@
#define MCI_ST_UX500_NEG_EDGE (1 << 13)
#define MCI_ST_UX500_HWFCEN (1 << 14)
#define MCI_ST_UX500_CLK_INV (1 << 15)
+/* Modified PL180 on Versatile Express platform */
+#define MCI_ARM_HWFCEN (1 << 12)
#define MMCIARGUMENT 0x008
#define MMCICOMMAND 0x00c
@@ -193,7 +195,6 @@ struct mmci_host {
/* pio stuff */
struct sg_mapping_iter sg_miter;
unsigned int size;
- struct regulator *vcc;
/* pinctrl handles */
struct pinctrl *pinctrl;
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 206fe499ded5..5b665551a6f3 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -614,9 +614,9 @@ static int mxs_mmc_probe(struct platform_device *pdev)
host = mmc_priv(mmc);
ssp = &host->ssp;
ssp->dev = &pdev->dev;
- ssp->base = devm_request_and_ioremap(&pdev->dev, iores);
- if (!ssp->base) {
- ret = -EADDRNOTAVAIL;
+ ssp->base = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(ssp->base)) {
+ ret = PTR_ERR(ssp->base);
goto out_mmc_free;
}
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index f74b5adca642..468c92303167 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -678,12 +678,19 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
struct mmc_command *cmd = mrq->cmd;
struct mmc_data *data = mrq->data;
unsigned int data_size = 0;
+ int err;
if (host->eject) {
cmd->error = -ENOMEDIUM;
goto finish;
}
+ err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD);
+ if (err) {
+ cmd->error = err;
+ goto finish;
+ }
+
mutex_lock(&pcr->pcr_mutex);
rtsx_pci_start_run(pcr);
@@ -901,6 +908,9 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (host->eject)
return;
+ if (rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD))
+ return;
+
mutex_lock(&pcr->pcr_mutex);
rtsx_pci_start_run(pcr);
@@ -1073,6 +1083,10 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
if (host->eject)
return -ENOMEDIUM;
+ err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD);
+ if (err)
+ return err;
+
mutex_lock(&pcr->pcr_mutex);
rtsx_pci_start_run(pcr);
@@ -1122,6 +1136,10 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (host->eject)
return -ENOMEDIUM;
+ err = rtsx_pci_card_exclusive_check(host->pcr, RTSX_SD_CARD);
+ if (err)
+ return err;
+
mutex_lock(&pcr->pcr_mutex);
rtsx_pci_start_run(pcr);
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 82a8de148a8f..a0c621421ee8 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -651,10 +651,9 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
#endif
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- host->ioaddr = devm_request_and_ioremap(&pdev->dev, res);
- if (!host->ioaddr) {
- dev_err(dev, "failed to map registers\n");
- ret = -ENXIO;
+ host->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(host->ioaddr)) {
+ ret = PTR_ERR(host->ioaddr);
goto err_req_regs;
}
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 73fcbbeb78d0..03f2eb5627ec 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -291,7 +291,7 @@ config SSFDC
config SM_FTL
tristate "SmartMedia/xD new translation layer"
- depends on EXPERIMENTAL && BLOCK
+ depends on BLOCK
select MTD_BLKDEVS
select MTD_NAND_ECC
help
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index e469b01d40d2..c219e3d098d9 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -225,7 +225,7 @@ config MTD_ABSENT
config MTD_XIP
bool "XIP aware MTD support"
- depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL && ARCH_MTD_XIP
+ depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && ARCH_MTD_XIP
default y if XIP_KERNEL
help
This allows MTD support to work with flash memory which is also
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 46dcb54c32ec..12311f506ca1 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -52,7 +52,7 @@ config MTD_MS02NV
config MTD_DATAFLASH
tristate "Support for AT45xxx DataFlash"
- depends on SPI_MASTER && EXPERIMENTAL
+ depends on SPI_MASTER
help
This enables access to AT45xxx DataFlash chips, using SPI.
Sometimes DataFlash chips are packaged inside MMC-format
@@ -81,7 +81,7 @@ config MTD_DATAFLASH_OTP
config MTD_M25P80
tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
- depends on SPI_MASTER && EXPERIMENTAL
+ depends on SPI_MASTER
help
This enables access to most modern SPI flash chips, used for
program and data storage. Series supported include Atmel AT26DF,
diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c
index 2aabd96bf0ff..8a82b8bc21e1 100644
--- a/drivers/mtd/devices/spear_smi.c
+++ b/drivers/mtd/devices/spear_smi.c
@@ -949,10 +949,9 @@ static int spear_smi_probe(struct platform_device *pdev)
smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dev->io_base = devm_request_and_ioremap(&pdev->dev, smi_base);
- if (!dev->io_base) {
- ret = -EIO;
- dev_err(&pdev->dev, "devm_request_and_ioremap fail\n");
+ dev->io_base = devm_ioremap_resource(&pdev->dev, smi_base);
+ if (IS_ERR(dev->io_base)) {
+ ret = PTR_ERR(dev->io_base);
goto err;
}
diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c
index a2dc2ae4b24e..c3525d2a2fa8 100644
--- a/drivers/mtd/maps/autcpu12-nvram.c
+++ b/drivers/mtd/maps/autcpu12-nvram.c
@@ -16,6 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/err.h>
#include <linux/sizes.h>
#include <linux/types.h>
@@ -55,12 +56,10 @@ static int autcpu12_nvram_probe(struct platform_device *pdev)
priv->map.bankwidth = 4;
priv->map.phys = res->start;
priv->map.size = resource_size(res);
- priv->map.virt = devm_request_and_ioremap(&pdev->dev, res);
+ priv->map.virt = devm_ioremap_resource(&pdev->dev, res);
strcpy((char *)priv->map.name, res->name);
- if (!priv->map.virt) {
- dev_err(&pdev->dev, "failed to remap mem resource\n");
- return -EBUSY;
- }
+ if (IS_ERR(priv->map.virt))
+ return PTR_ERR(priv->map.virt);
simple_map_init(&priv->map);
diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c
index 3c3c791eb96a..d1da6ede3845 100644
--- a/drivers/mtd/maps/lantiq-flash.c
+++ b/drivers/mtd/maps/lantiq-flash.c
@@ -7,6 +7,7 @@
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -136,10 +137,9 @@ ltq_mtd_probe(struct platform_device *pdev)
ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL);
ltq_mtd->map->phys = ltq_mtd->res->start;
ltq_mtd->map->size = resource_size(ltq_mtd->res);
- ltq_mtd->map->virt = devm_request_and_ioremap(&pdev->dev, ltq_mtd->res);
- if (!ltq_mtd->map->virt) {
- dev_err(&pdev->dev, "failed to remap mem resource\n");
- err = -EBUSY;
+ ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res);
+ if (IS_ERR(ltq_mtd->map->virt)) {
+ err = PTR_ERR(ltq_mtd->map->virt);
goto err_out;
}
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 5819eb575210..81bf5e52601e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -260,8 +260,7 @@ config MTD_NAND_S3C2410_CLKSTOP
approximately 5mA of power when there is nothing happening.
config MTD_NAND_DISKONCHIP
- tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)"
depends on HAS_IOMEM
select REED_SOLOMON
select REED_SOLOMON_DEC16
@@ -331,8 +330,8 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
parameter "inftl_bbt_write=1".
config MTD_NAND_DOCG4
- tristate "Support for DiskOnChip G4 (EXPERIMENTAL)"
- depends on EXPERIMENTAL && HAS_IOMEM
+ tristate "Support for DiskOnChip G4"
+ depends on HAS_IOMEM
select BCH
select BITREVERSE
help
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 67e62d3d495c..09af555408b7 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -937,42 +937,35 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (!res)
return -EINVAL;
- host->data_va = devm_request_and_ioremap(&pdev->dev, res);
- if (!host->data_va) {
- dev_err(&pdev->dev, "data ioremap failed\n");
- return -ENOMEM;
- }
+ host->data_va = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(host->data_va))
+ return PTR_ERR(host->data_va);
+
host->data_pa = (dma_addr_t)res->start;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
if (!res)
return -EINVAL;
- host->addr_va = devm_request_and_ioremap(&pdev->dev, res);
- if (!host->addr_va) {
- dev_err(&pdev->dev, "ale ioremap failed\n");
- return -ENOMEM;
- }
+ host->addr_va = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(host->addr_va))
+ return PTR_ERR(host->addr_va);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
if (!res)
return -EINVAL;
- host->cmd_va = devm_request_and_ioremap(&pdev->dev, res);
- if (!host->cmd_va) {
- dev_err(&pdev->dev, "ale ioremap failed\n");
- return -ENOMEM;
- }
+ host->cmd_va = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(host->cmd_va))
+ return PTR_ERR(host->cmd_va);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
if (!res)
return -EINVAL;
- host->regs_va = devm_request_and_ioremap(&pdev->dev, res);
- if (!host->regs_va) {
- dev_err(&pdev->dev, "regs ioremap failed\n");
- return -ENOMEM;
- }
+ host->regs_va = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(host->regs_va))
+ return PTR_ERR(host->regs_va);
host->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk)) {
@@ -1218,6 +1211,7 @@ static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
#ifdef CONFIG_OF
static const struct of_device_id fsmc_nand_id_table[] = {
{ .compatible = "st,spear600-fsmc-nand" },
+ { .compatible = "stericsson,fsmc-nand" },
{}
};
MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index f182befa7360..0ca22ae9135c 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -677,11 +677,10 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
return -ENXIO;
}
- host->io_base = devm_request_and_ioremap(&pdev->dev, rc);
- if (host->io_base == NULL) {
- dev_err(&pdev->dev, "ioremap failed\n");
- return -EIO;
- }
+ host->io_base = devm_ioremap_resource(&pdev->dev, rc);
+ if (IS_ERR(host->io_base))
+ return PTR_ERR(host->io_base);
+
host->io_base_phy = rc->start;
mtd = &host->mtd;
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
index 030b78c62895..be94ed5abefb 100644
--- a/drivers/mtd/nand/lpc32xx_slc.c
+++ b/drivers/mtd/nand/lpc32xx_slc.c
@@ -778,11 +778,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}
host->io_base_dma = rc->start;
- host->io_base = devm_request_and_ioremap(&pdev->dev, rc);
- if (host->io_base == NULL) {
- dev_err(&pdev->dev, "ioremap failed\n");
- return -ENOMEM;
- }
+ host->io_base = devm_ioremap_resource(&pdev->dev, rc);
+ if (IS_ERR(host->io_base))
+ return PTR_ERR(host->io_base);
if (pdev->dev.of_node)
host->ncfg = lpc32xx_parse_dt(&pdev->dev);
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 45204e41a028..60ac5b98b718 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -1437,9 +1437,9 @@ static int mxcnd_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- host->regs_ip = devm_request_and_ioremap(&pdev->dev, res);
- if (!host->regs_ip)
- return -ENOMEM;
+ host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(host->regs_ip))
+ return PTR_ERR(host->regs_ip);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
} else {
@@ -1449,9 +1449,9 @@ static int mxcnd_probe(struct platform_device *pdev)
if (!res)
return -ENODEV;
- host->base = devm_request_and_ioremap(&pdev->dev, res);
- if (!host->base)
- return -ENOMEM;
+ host->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(host->base))
+ return PTR_ERR(host->base);
host->main_area0 = host->base;
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 0002d5e94f0d..1d333497cfcb 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -1332,6 +1332,7 @@ static int omap_nand_probe(struct platform_device *pdev)
dma_cap_mask_t mask;
unsigned sig;
struct resource *res;
+ struct mtd_part_parser_data ppdata = {};
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
@@ -1557,7 +1558,8 @@ static int omap_nand_probe(struct platform_device *pdev)
goto out_release_mem_region;
}
- mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts,
+ ppdata.of_node = pdata->of_node;
+ mtd_device_parse_register(&info->mtd, NULL, &ppdata, pdata->parts,
pdata->nr_parts);
platform_set_drvdata(pdev, &info->mtd);
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index df954b4dcba2..d65afd23e171 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -952,10 +952,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
info->platform = plat;
info->cpu_type = cpu_type;
- info->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (info->regs == NULL) {
- dev_err(&pdev->dev, "cannot reserve register region\n");
- err = -EIO;
+ info->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(info->regs)) {
+ err = PTR_ERR(info->regs);
goto exit_error;
}
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
index e3d7266e256f..e1e8748aa47b 100644
--- a/drivers/mtd/nand/txx9ndfmc.c
+++ b/drivers/mtd/nand/txx9ndfmc.c
@@ -9,6 +9,7 @@
* (C) Copyright TOSHIBA CORPORATION 2004-2007
* All Rights Reserved.
*/
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -286,9 +287,9 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
drvdata = devm_kzalloc(&dev->dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- drvdata->base = devm_request_and_ioremap(&dev->dev, res);
- if (!drvdata->base)
- return -EBUSY;
+ drvdata->base = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(drvdata->base))
+ return PTR_ERR(drvdata->base);
hold = plat->hold ?: 20; /* tDH */
spw = plat->spw ?: 90; /* max(tREADID, tWP, tRP) */
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 065f3fe02a2f..eec2aedb4ab8 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -637,6 +637,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
struct onenand_chip *this;
int r;
struct resource *res;
+ struct mtd_part_parser_data ppdata = {};
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
@@ -767,7 +768,8 @@ static int omap2_onenand_probe(struct platform_device *pdev)
if ((r = onenand_scan(&c->mtd, 1)) < 0)
goto err_release_regulator;
- r = mtd_device_parse_register(&c->mtd, NULL, NULL,
+ ppdata.of_node = pdata->of_node;
+ r = mtd_device_parse_register(&c->mtd, NULL, &ppdata,
pdata ? pdata->parts : NULL,
pdata ? pdata->nr_parts : 0);
if (r)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 6a70184c3f23..56c2d75a63d4 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -123,8 +123,7 @@ config IFB
source "drivers/net/team/Kconfig"
config MACVLAN
- tristate "MAC-VLAN support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "MAC-VLAN support"
---help---
This allows one to create virtual interfaces that map packets to
or from specific MAC addresses to a particular interface.
@@ -138,7 +137,7 @@ config MACVLAN
will be called macvlan.
config MACVTAP
- tristate "MAC-VLAN based tap driver (EXPERIMENTAL)"
+ tristate "MAC-VLAN based tap driver"
depends on MACVLAN
help
This adds a specialized tap character device driver that is based
@@ -189,6 +188,10 @@ config NETPOLL_TRAP
config NET_POLL_CONTROLLER
def_bool NETPOLL
+config NTB_NETDEV
+ tristate "Virtual Ethernet over NTB"
+ depends on NTB
+
config RIONET
tristate "RapidIO Ethernet over messaging driver support"
depends on RAPIDIO
@@ -234,8 +237,8 @@ config VETH
versa.
config VIRTIO_NET
- tristate "Virtio network driver (EXPERIMENTAL)"
- depends on EXPERIMENTAL && VIRTIO
+ tristate "Virtio network driver"
+ depends on VIRTIO
---help---
This is the virtual network driver for virtio. It can be used with
lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 335db78fd987..ef3d090efedf 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -71,3 +71,4 @@ obj-$(CONFIG_USB_IPHETH) += usb/
obj-$(CONFIG_USB_CDC_PHONET) += usb/
obj-$(CONFIG_HYPERV_NET) += hyperv/
+obj-$(CONFIG_NTB_NETDEV) += ntb_netdev.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index e3f0faca98d0..3a8c7532ee0d 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -37,35 +37,14 @@
ethernet adaptor have the name "eth[0123...]".
*/
-extern struct net_device *ne2_probe(int unit);
extern struct net_device *hp100_probe(int unit);
extern struct net_device *ultra_probe(int unit);
-extern struct net_device *ultra32_probe(int unit);
extern struct net_device *wd_probe(int unit);
-extern struct net_device *el2_probe(int unit);
extern struct net_device *ne_probe(int unit);
-extern struct net_device *hp_probe(int unit);
-extern struct net_device *hp_plus_probe(int unit);
-extern struct net_device *express_probe(int unit);
-extern struct net_device *eepro_probe(int unit);
-extern struct net_device *at1700_probe(int unit);
extern struct net_device *fmv18x_probe(int unit);
-extern struct net_device *eth16i_probe(int unit);
extern struct net_device *i82596_probe(int unit);
-extern struct net_device *ewrk3_probe(int unit);
-extern struct net_device *el1_probe(int unit);
-extern struct net_device *el16_probe(int unit);
-extern struct net_device *elmc_probe(int unit);
-extern struct net_device *elplus_probe(int unit);
-extern struct net_device *ac3200_probe(int unit);
-extern struct net_device *es_probe(int unit);
-extern struct net_device *lne390_probe(int unit);
-extern struct net_device *e2100_probe(int unit);
-extern struct net_device *ni5010_probe(int unit);
-extern struct net_device *ni52_probe(int unit);
extern struct net_device *ni65_probe(int unit);
extern struct net_device *sonic_probe(int unit);
-extern struct net_device *seeq8005_probe(int unit);
extern struct net_device *smc_init(int unit);
extern struct net_device *atarilance_probe(int unit);
extern struct net_device *sun3lance_probe(int unit);
@@ -77,13 +56,9 @@ extern struct net_device *tc515_probe(int unit);
extern struct net_device *lance_probe(int unit);
extern struct net_device *mac8390_probe(int unit);
extern struct net_device *mac89x0_probe(int unit);
-extern struct net_device *mc32_probe(int unit);
extern struct net_device *cops_probe(int unit);
extern struct net_device *ltpc_probe(void);
-/* Detachable devices ("pocket adaptors") */
-extern struct net_device *de620_probe(int unit);
-
/* Fibre Channel adapters */
extern int iph5526_probe(struct net_device *dev);
@@ -111,29 +86,6 @@ static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe)
}
/*
- * This is a bit of an artificial separation as there are PCI drivers
- * that also probe for EISA cards (in the PCI group) and there are ISA
- * drivers that probe for EISA cards (in the ISA group). These are the
- * legacy EISA only driver probes, and also the legacy PCI probes
- */
-
-static struct devprobe2 eisa_probes[] __initdata = {
-#ifdef CONFIG_ULTRA32
- {ultra32_probe, 0},
-#endif
-#ifdef CONFIG_AC3200
- {ac3200_probe, 0},
-#endif
-#ifdef CONFIG_ES3210
- {es_probe, 0},
-#endif
-#ifdef CONFIG_LNE390
- {lne390_probe, 0},
-#endif
- {NULL, 0},
-};
-
-/*
* ISA probes that touch addresses < 0x400 (including those that also
* look for EISA/PCI cards in addition to ISA cards).
*/
@@ -150,18 +102,6 @@ static struct devprobe2 isa_probes[] __initdata = {
#ifdef CONFIG_WD80x3
{wd_probe, 0},
#endif
-#ifdef CONFIG_EL2 /* 3c503 */
- {el2_probe, 0},
-#endif
-#ifdef CONFIG_HPLAN
- {hp_probe, 0},
-#endif
-#ifdef CONFIG_HPLAN_PLUS
- {hp_plus_probe, 0},
-#endif
-#ifdef CONFIG_E2100 /* Cabletron E21xx series. */
- {e2100_probe, 0},
-#endif
#if defined(CONFIG_NE2000) || \
defined(CONFIG_NE_H8300) /* ISA (use ne2k-pci for PCI cards) */
{ne_probe, 0},
@@ -172,60 +112,20 @@ static struct devprobe2 isa_probes[] __initdata = {
#ifdef CONFIG_SMC9194
{smc_init, 0},
#endif
-#ifdef CONFIG_SEEQ8005
- {seeq8005_probe, 0},
-#endif
#ifdef CONFIG_CS89x0
#ifndef CONFIG_CS89x0_PLATFORM
{cs89x0_probe, 0},
#endif
#endif
-#ifdef CONFIG_AT1700
- {at1700_probe, 0},
-#endif
-#ifdef CONFIG_ETH16I
- {eth16i_probe, 0}, /* ICL EtherTeam 16i/32 */
-#endif
-#ifdef CONFIG_EEXPRESS /* Intel EtherExpress */
- {express_probe, 0},
-#endif
-#ifdef CONFIG_EEXPRESS_PRO /* Intel EtherExpress Pro/10 */
- {eepro_probe, 0},
-#endif
-#ifdef CONFIG_EWRK3 /* DEC EtherWORKS 3 */
- {ewrk3_probe, 0},
-#endif
-#if defined(CONFIG_APRICOT) || defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET) /* Intel I82596 */
+#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET) /* Intel I82596 */
{i82596_probe, 0},
#endif
-#ifdef CONFIG_EL1 /* 3c501 */
- {el1_probe, 0},
-#endif
-#ifdef CONFIG_EL16 /* 3c507 */
- {el16_probe, 0},
-#endif
-#ifdef CONFIG_ELPLUS /* 3c505 */
- {elplus_probe, 0},
-#endif
-#ifdef CONFIG_NI5010
- {ni5010_probe, 0},
-#endif
-#ifdef CONFIG_NI52
- {ni52_probe, 0},
-#endif
#ifdef CONFIG_NI65
{ni65_probe, 0},
#endif
{NULL, 0},
};
-static struct devprobe2 parport_probes[] __initdata = {
-#ifdef CONFIG_DE620 /* D-Link DE-620 adapter */
- {de620_probe, 0},
-#endif
- {NULL, 0},
-};
-
static struct devprobe2 m68k_probes[] __initdata = {
#ifdef CONFIG_ATARILANCE /* Lance-based Atari ethernet boards */
{atarilance_probe, 0},
@@ -264,9 +164,7 @@ static void __init ethif_probe2(int unit)
return;
(void)( probe_list2(unit, m68k_probes, base_addr == 0) &&
- probe_list2(unit, eisa_probes, base_addr == 0) &&
- probe_list2(unit, isa_probes, base_addr == 0) &&
- probe_list2(unit, parport_probes, base_addr == 0));
+ probe_list2(unit, isa_probes, base_addr == 0));
}
/* Statically configured drivers -- order matters here. */
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index a030e635f001..fc58d118d844 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -389,13 +389,13 @@ static u8 __get_duplex(struct port *port)
/**
* __initialize_port_locks - initialize a port's STATE machine spinlock
- * @port: the port we're looking at
+ * @port: the slave of the port we're looking at
*
*/
-static inline void __initialize_port_locks(struct port *port)
+static inline void __initialize_port_locks(struct slave *slave)
{
// make sure it isn't called twice
- spin_lock_init(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
+ spin_lock_init(&(SLAVE_AD_INFO(slave).state_machine_lock));
}
//conversions
@@ -1127,7 +1127,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
// INFO_RECEIVED_LOOPBACK_FRAMES
pr_err("%s: An illegal loopback occurred on adapter (%s).\n"
"Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
- port->slave->dev->master->name, port->slave->dev->name);
+ port->slave->bond->dev->name, port->slave->dev->name);
return;
}
__update_selected(lacpdu, port);
@@ -1306,7 +1306,7 @@ static void ad_port_selection_logic(struct port *port)
}
if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list
pr_warning("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
- port->slave->dev->master->name,
+ port->slave->bond->dev->name,
port->actor_port_number,
port->slave->dev->name,
port->aggregator->aggregator_identifier);
@@ -1386,7 +1386,7 @@ static void ad_port_selection_logic(struct port *port)
port->aggregator->aggregator_identifier);
} else {
pr_err("%s: Port %d (on %s) did not find a suitable aggregator\n",
- port->slave->dev->master->name,
+ port->slave->bond->dev->name,
port->actor_port_number, port->slave->dev->name);
}
}
@@ -1463,7 +1463,7 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best,
default:
pr_warning("%s: Impossible agg select mode %d\n",
- curr->slave->dev->master->name,
+ curr->slave->bond->dev->name,
__get_agg_selection_mode(curr->lag_ports));
break;
}
@@ -1571,7 +1571,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
// check if any partner replys
if (best->is_individual) {
pr_warning("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
- best->slave ? best->slave->dev->master->name : "NULL");
+ best->slave ? best->slave->bond->dev->name : "NULL");
}
best->is_active = 1;
@@ -1898,7 +1898,7 @@ int bond_3ad_bind_slave(struct slave *slave)
if (bond == NULL) {
pr_err("%s: The slave %s is not attached to its bond\n",
- slave->dev->master->name, slave->dev->name);
+ slave->bond->dev->name, slave->dev->name);
return -1;
}
@@ -1910,6 +1910,7 @@ int bond_3ad_bind_slave(struct slave *slave)
ad_initialize_port(port, bond->params.lacp_fast);
+ __initialize_port_locks(slave);
port->slave = slave;
port->actor_port_number = SLAVE_AD_INFO(slave).id;
// key is determined according to the link speed, duplex and user key(which is yet not supported)
@@ -1932,8 +1933,6 @@ int bond_3ad_bind_slave(struct slave *slave)
port->next_port_in_aggregator = NULL;
__disable_port(port);
- __initialize_port_locks(port);
-
// aggregator initialization
aggregator = &(SLAVE_AD_INFO(slave).aggregator);
@@ -1973,7 +1972,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
// if slave is null, the whole port is not initialized
if (!port->slave) {
pr_warning("Warning: %s: Trying to unbind an uninitialized port on %s\n",
- slave->dev->master->name, slave->dev->name);
+ slave->bond->dev->name, slave->dev->name);
return;
}
@@ -2009,7 +2008,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) {
pr_info("%s: Removing an active aggregator\n",
- aggregator->slave->dev->master->name);
+ aggregator->slave->bond->dev->name);
// select new active aggregator
select_new_active_agg = 1;
}
@@ -2040,7 +2039,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
ad_agg_selection_logic(__get_first_agg(port));
} else {
pr_warning("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n",
- slave->dev->master->name);
+ slave->bond->dev->name);
}
} else { // in case that the only port related to this aggregator is the one we want to remove
select_new_active_agg = aggregator->is_active;
@@ -2048,7 +2047,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
ad_clear_agg(aggregator);
if (select_new_active_agg) {
pr_info("%s: Removing an active aggregator\n",
- slave->dev->master->name);
+ slave->bond->dev->name);
// select new active aggregator
ad_agg_selection_logic(__get_first_agg(port));
}
@@ -2076,7 +2075,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
ad_clear_agg(temp_aggregator);
if (select_new_active_agg) {
pr_info("%s: Removing an active aggregator\n",
- slave->dev->master->name);
+ slave->bond->dev->name);
// select new active aggregator
ad_agg_selection_logic(__get_first_agg(port));
}
@@ -2184,7 +2183,7 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u1
if (!port->slave) {
pr_warning("%s: Warning: port of slave %s is uninitialized\n",
- slave->dev->name, slave->dev->master->name);
+ slave->dev->name, slave->bond->dev->name);
return ret;
}
@@ -2240,7 +2239,7 @@ void bond_3ad_adapter_speed_changed(struct slave *slave)
// if slave is null, the whole port is not initialized
if (!port->slave) {
pr_warning("Warning: %s: speed changed for uninitialized port on %s\n",
- slave->dev->master->name, slave->dev->name);
+ slave->bond->dev->name, slave->dev->name);
return;
}
@@ -2268,7 +2267,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
// if slave is null, the whole port is not initialized
if (!port->slave) {
pr_warning("%s: Warning: duplex changed for uninitialized port on %s\n",
- slave->dev->master->name, slave->dev->name);
+ slave->bond->dev->name, slave->dev->name);
return;
}
@@ -2297,7 +2296,7 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
// if slave is null, the whole port is not initialized
if (!port->slave) {
pr_warning("Warning: %s: link status changed for uninitialized port on %s\n",
- slave->dev->master->name, slave->dev->name);
+ slave->bond->dev->name, slave->dev->name);
return;
}
@@ -2494,11 +2493,13 @@ void bond_3ad_update_lacp_rate(struct bonding *bond)
struct port *port = NULL;
int lacp_fast;
- read_lock(&bond->lock);
+ write_lock_bh(&bond->lock);
lacp_fast = bond->params.lacp_fast;
bond_for_each_slave(bond, slave, i) {
port = &(SLAVE_AD_INFO(slave).port);
+ if (port->slave == NULL)
+ continue;
__get_state_machine_lock(port);
if (lacp_fast)
port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT;
@@ -2507,5 +2508,5 @@ void bond_3ad_update_lacp_rate(struct bonding *bond)
__release_state_machine_lock(port);
}
- read_unlock(&bond->lock);
+ write_unlock_bh(&bond->lock);
}
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 7c9d136e74be..f5e052723029 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -507,7 +507,7 @@ static void rlb_update_client(struct rlb_client_info *client_info)
client_info->mac_dst);
if (!skb) {
pr_err("%s: Error: failed to create an ARP packet\n",
- client_info->slave->dev->master->name);
+ client_info->slave->bond->dev->name);
continue;
}
@@ -517,7 +517,7 @@ static void rlb_update_client(struct rlb_client_info *client_info)
skb = vlan_put_tag(skb, client_info->vlan_id);
if (!skb) {
pr_err("%s: Error: failed to insert VLAN tag\n",
- client_info->slave->dev->master->name);
+ client_info->slave->bond->dev->name);
continue;
}
}
@@ -1043,7 +1043,7 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[])
if (dev_set_mac_address(dev, &s_addr)) {
pr_err("%s: Error: dev_set_mac_address of dev %s failed!\n"
"ALB mode requires that the base driver support setting the hw address also when the network device's interface is open\n",
- dev->master->name, dev->name);
+ slave->bond->dev->name, dev->name);
return -EOPNOTSUPP;
}
return 0;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b7d45f367d4a..11d01d67b3f5 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -746,11 +746,9 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
{
struct in_device *in_dev;
- rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (in_dev)
ip_mc_rejoin_groups(in_dev);
- rcu_read_unlock();
}
/*
@@ -760,9 +758,10 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
*/
static void bond_resend_igmp_join_requests(struct bonding *bond)
{
- struct net_device *bond_dev, *vlan_dev, *master_dev;
+ struct net_device *bond_dev, *vlan_dev, *upper_dev;
struct vlan_entry *vlan;
+ rcu_read_lock();
read_lock(&bond->lock);
bond_dev = bond->dev;
@@ -774,18 +773,14 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
* if bond is enslaved to a bridge,
* then rejoin all groups on its master
*/
- master_dev = bond_dev->master;
- if (master_dev)
- if ((master_dev->priv_flags & IFF_EBRIDGE)
- && (bond_dev->priv_flags & IFF_BRIDGE_PORT))
- __bond_resend_igmp_join_requests(master_dev);
+ upper_dev = netdev_master_upper_dev_get_rcu(bond_dev);
+ if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE)
+ __bond_resend_igmp_join_requests(upper_dev);
/* rejoin all groups on vlan devices */
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
- rcu_read_lock();
vlan_dev = __vlan_find_dev_deep(bond_dev,
vlan->vlan_id);
- rcu_read_unlock();
if (vlan_dev)
__bond_resend_igmp_join_requests(vlan_dev);
}
@@ -794,13 +789,16 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
read_unlock(&bond->lock);
+ rcu_read_unlock();
}
static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
mcast_work.work);
+ rcu_read_lock();
bond_resend_igmp_join_requests(bond);
+ rcu_read_unlock();
}
/*
@@ -1251,7 +1249,7 @@ static inline void slave_disable_netpoll(struct slave *slave)
return;
slave->np = NULL;
- __netpoll_free_rcu(np);
+ __netpoll_free_async(np);
}
static inline bool slave_dev_support_netpoll(struct net_device *slave_dev)
{
@@ -1322,14 +1320,15 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
/*---------------------------------- IOCTL ----------------------------------*/
-static int bond_sethwaddr(struct net_device *bond_dev,
- struct net_device *slave_dev)
+static void bond_set_dev_addr(struct net_device *bond_dev,
+ struct net_device *slave_dev)
{
pr_debug("bond_dev=%p\n", bond_dev);
pr_debug("slave_dev=%p\n", slave_dev);
pr_debug("slave_dev->addr_len=%d\n", slave_dev->addr_len);
memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len);
- return 0;
+ bond_dev->addr_assign_type = NET_ADDR_SET;
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, bond_dev);
}
static netdev_features_t bond_fix_features(struct net_device *dev,
@@ -1493,6 +1492,27 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
return ret;
}
+static int bond_master_upper_dev_link(struct net_device *bond_dev,
+ struct net_device *slave_dev)
+{
+ int err;
+
+ err = netdev_master_upper_dev_link(slave_dev, bond_dev);
+ if (err)
+ return err;
+ slave_dev->flags |= IFF_SLAVE;
+ rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE);
+ return 0;
+}
+
+static void bond_upper_dev_unlink(struct net_device *bond_dev,
+ struct net_device *slave_dev)
+{
+ netdev_upper_dev_unlink(slave_dev, bond_dev);
+ slave_dev->flags &= ~IFF_SLAVE;
+ rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE);
+}
+
/* enslave device <slave> to bond device <master> */
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
{
@@ -1609,10 +1629,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
/* If this is the first slave, then we need to set the master's hardware
* address to be the same as the slave's. */
- if (is_zero_ether_addr(bond->dev->dev_addr))
- memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
- slave_dev->addr_len);
-
+ if (bond->dev_addr_from_first)
+ bond_set_dev_addr(bond->dev, slave_dev);
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) {
@@ -1655,9 +1673,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
}
- res = netdev_set_bond_master(slave_dev, bond_dev);
+ res = bond_master_upper_dev_link(bond_dev, slave_dev);
if (res) {
- pr_debug("Error %d calling netdev_set_bond_master\n", res);
+ pr_debug("Error %d calling bond_master_upper_dev_link\n", res);
goto err_restore_mac;
}
@@ -1891,7 +1909,7 @@ err_close:
dev_close(slave_dev);
err_unset_master:
- netdev_set_bond_master(slave_dev, NULL);
+ bond_upper_dev_unlink(bond_dev, slave_dev);
err_restore_mac:
if (!bond->params.fail_over_mac) {
@@ -1919,7 +1937,8 @@ err_undo_flags:
/*
* Try to release the slave device <slave> from the bond device <master>
* It is legal to access curr_active_slave without a lock because all the function
- * is write-locked.
+ * is write-locked. If "all" is true it means that the function is being called
+ * while destroying a bond interface and all slaves are being released.
*
* The rules for slave state should be:
* for Active/Backup:
@@ -1927,7 +1946,9 @@ err_undo_flags:
* for Bonded connections:
* The first up interface should be left on and all others downed.
*/
-int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
+static int __bond_release_one(struct net_device *bond_dev,
+ struct net_device *slave_dev,
+ bool all)
{
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave, *oldcurrent;
@@ -1936,7 +1957,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
/* slave is not a slave or master is not master of this slave */
if (!(slave_dev->flags & IFF_SLAVE) ||
- (slave_dev->master != bond_dev)) {
+ !netdev_has_upper_dev(slave_dev, bond_dev)) {
pr_err("%s: Error: cannot release %s.\n",
bond_dev->name, slave_dev->name);
return -EINVAL;
@@ -1964,7 +1985,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
synchronize_net();
write_lock_bh(&bond->lock);
- if (!bond->params.fail_over_mac) {
+ if (!all && !bond->params.fail_over_mac) {
if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
bond->slave_cnt > 1)
pr_warning("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
@@ -2010,7 +2031,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
write_lock_bh(&bond->lock);
}
- if (oldcurrent == slave) {
+ if (all) {
+ bond->curr_active_slave = NULL;
+ } else if (oldcurrent == slave) {
/*
* Note that we hold RTNL over this sequence, so there
* is no concern that another slave add/remove event
@@ -2029,12 +2052,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
if (bond->slave_cnt == 0) {
bond_set_carrier(bond);
-
- /* if the last slave was removed, zero the mac address
- * of the master so it will be set by the application
- * to the mac address of the first slave
- */
- memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
+ eth_hw_addr_random(bond_dev);
+ bond->dev_addr_from_first = true;
if (bond_vlan_used(bond)) {
pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
@@ -2080,7 +2099,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
netif_addr_unlock_bh(bond_dev);
}
- netdev_set_bond_master(slave_dev, NULL);
+ bond_upper_dev_unlink(bond_dev, slave_dev);
slave_disable_netpoll(slave);
@@ -2103,6 +2122,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
return 0; /* deletion OK */
}
+/* A wrapper used because of ndo_del_link */
+int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
+{
+ return __bond_release_one(bond_dev, slave_dev, false);
+}
+
/*
* First release a slave and then destroy the bond if no more slaves are left.
* Must be under rtnl_lock when this function is called.
@@ -2124,121 +2149,6 @@ static int bond_release_and_destroy(struct net_device *bond_dev,
}
/*
- * This function releases all slaves.
- */
-static int bond_release_all(struct net_device *bond_dev)
-{
- struct bonding *bond = netdev_priv(bond_dev);
- struct slave *slave;
- struct net_device *slave_dev;
- struct sockaddr addr;
-
- write_lock_bh(&bond->lock);
-
- netif_carrier_off(bond_dev);
-
- if (bond->slave_cnt == 0)
- goto out;
-
- bond->current_arp_slave = NULL;
- bond->primary_slave = NULL;
- bond_change_active_slave(bond, NULL);
-
- while ((slave = bond->first_slave) != NULL) {
- /* Inform AD package of unbinding of slave
- * before slave is detached from the list.
- */
- if (bond->params.mode == BOND_MODE_8023AD)
- bond_3ad_unbind_slave(slave);
-
- slave_dev = slave->dev;
- bond_detach_slave(bond, slave);
-
- /* now that the slave is detached, unlock and perform
- * all the undo steps that should not be called from
- * within a lock.
- */
- write_unlock_bh(&bond->lock);
-
- /* unregister rx_handler early so bond_handle_frame wouldn't
- * be called for this slave anymore.
- */
- netdev_rx_handler_unregister(slave_dev);
- synchronize_net();
-
- if (bond_is_lb(bond)) {
- /* must be called only after the slave
- * has been detached from the list
- */
- bond_alb_deinit_slave(bond, slave);
- }
-
- bond_destroy_slave_symlinks(bond_dev, slave_dev);
- bond_del_vlans_from_slave(bond, slave_dev);
-
- /* If the mode USES_PRIMARY, then we should only remove its
- * promisc and mc settings if it was the curr_active_slave, but that was
- * already taken care of above when we detached the slave
- */
- if (!USES_PRIMARY(bond->params.mode)) {
- /* unset promiscuity level from slave */
- if (bond_dev->flags & IFF_PROMISC)
- dev_set_promiscuity(slave_dev, -1);
-
- /* unset allmulti level from slave */
- if (bond_dev->flags & IFF_ALLMULTI)
- dev_set_allmulti(slave_dev, -1);
-
- /* flush master's mc_list from slave */
- netif_addr_lock_bh(bond_dev);
- bond_mc_list_flush(bond_dev, slave_dev);
- netif_addr_unlock_bh(bond_dev);
- }
-
- netdev_set_bond_master(slave_dev, NULL);
-
- slave_disable_netpoll(slave);
-
- /* close slave before restoring its mac address */
- dev_close(slave_dev);
-
- if (!bond->params.fail_over_mac) {
- /* restore original ("permanent") mac address*/
- memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
- }
-
- kfree(slave);
-
- /* re-acquire the lock before getting the next slave */
- write_lock_bh(&bond->lock);
- }
-
- /* zero the mac address of the master so it will be
- * set by the application to the mac address of the
- * first slave
- */
- memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
-
- if (bond_vlan_used(bond)) {
- 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);
- }
-
- pr_info("%s: released all slaves\n", bond_dev->name);
-
-out:
- write_unlock_bh(&bond->lock);
-
- bond_compute_features(bond);
-
- return 0;
-}
-
-/*
* This function changes the active slave to slave <slave_dev>.
* It returns -EINVAL in the following cases.
* - <slave_dev> is not found in the list.
@@ -2259,8 +2169,9 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
if (!USES_PRIMARY(bond->params.mode))
return -EINVAL;
- /* Verify that master_dev is indeed the master of slave_dev */
- if (!(slave_dev->flags & IFF_SLAVE) || (slave_dev->master != bond_dev))
+ /* Verify that bond_dev is indeed the master of slave_dev */
+ if (!(slave_dev->flags & IFF_SLAVE) ||
+ !netdev_has_upper_dev(slave_dev, bond_dev))
return -EINVAL;
read_lock(&bond->lock);
@@ -3258,36 +3169,32 @@ static int bond_master_netdev_event(unsigned long event,
static int bond_slave_netdev_event(unsigned long event,
struct net_device *slave_dev)
{
- struct net_device *bond_dev = slave_dev->master;
- struct bonding *bond = netdev_priv(bond_dev);
- struct slave *slave = NULL;
+ struct slave *slave = bond_slave_get_rtnl(slave_dev);
+ struct bonding *bond = slave->bond;
+ struct net_device *bond_dev = slave->bond->dev;
+ u32 old_speed;
+ u8 old_duplex;
switch (event) {
case NETDEV_UNREGISTER:
- if (bond_dev) {
- if (bond->setup_by_slave)
- bond_release_and_destroy(bond_dev, slave_dev);
- else
- bond_release(bond_dev, slave_dev);
- }
+ if (bond->setup_by_slave)
+ bond_release_and_destroy(bond_dev, slave_dev);
+ else
+ bond_release(bond_dev, slave_dev);
break;
case NETDEV_UP:
case NETDEV_CHANGE:
- slave = bond_get_slave_by_dev(bond, slave_dev);
- if (slave) {
- u32 old_speed = slave->speed;
- u8 old_duplex = slave->duplex;
+ old_speed = slave->speed;
+ old_duplex = slave->duplex;
- bond_update_speed_duplex(slave);
+ bond_update_speed_duplex(slave);
- if (bond->params.mode == BOND_MODE_8023AD) {
- if (old_speed != slave->speed)
- bond_3ad_adapter_speed_changed(slave);
- if (old_duplex != slave->duplex)
- bond_3ad_adapter_duplex_changed(slave);
- }
+ if (bond->params.mode == BOND_MODE_8023AD) {
+ if (old_speed != slave->speed)
+ bond_3ad_adapter_speed_changed(slave);
+ if (old_duplex != slave->duplex)
+ bond_3ad_adapter_duplex_changed(slave);
}
-
break;
case NETDEV_DOWN:
/*
@@ -3604,6 +3511,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
struct ifslave k_sinfo;
struct ifslave __user *u_sinfo = NULL;
struct mii_ioctl_data *mii = NULL;
+ struct net *net;
int res = 0;
pr_debug("bond_ioctl: master=%s, cmd=%d\n", bond_dev->name, cmd);
@@ -3670,10 +3578,12 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
break;
}
- if (!capable(CAP_NET_ADMIN))
+ net = dev_net(bond_dev);
+
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;
- slave_dev = dev_get_by_name(dev_net(bond_dev), ifr->ifr_slave);
+ slave_dev = dev_get_by_name(net, ifr->ifr_slave);
pr_debug("slave_dev=%p:\n", slave_dev);
@@ -3692,7 +3602,8 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
break;
case BOND_SETHWADDR_OLD:
case SIOCBONDSETHWADDR:
- res = bond_sethwaddr(bond_dev, slave_dev);
+ bond_set_dev_addr(bond_dev, slave_dev);
+ res = 0;
break;
case BOND_CHANGE_ACTIVE_OLD:
case SIOCBONDCHANGEACTIVE:
@@ -4314,11 +4225,12 @@ void bond_set_mode_ops(struct bonding *bond, int mode)
}
static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
- struct ethtool_drvinfo *drvinfo)
+ struct ethtool_drvinfo *drvinfo)
{
- strncpy(drvinfo->driver, DRV_NAME, 32);
- strncpy(drvinfo->version, DRV_VERSION, 32);
- snprintf(drvinfo->fw_version, 32, "%d", BOND_ABI_VERSION);
+ strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d",
+ BOND_ABI_VERSION);
}
static const struct ethtool_ops bond_ethtool_ops = {
@@ -4352,6 +4264,10 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_fix_features = bond_fix_features,
};
+static const struct device_type bond_type = {
+ .name = "bond",
+};
+
static void bond_destructor(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
@@ -4382,6 +4298,8 @@ static void bond_setup(struct net_device *bond_dev)
bond_dev->destructor = bond_destructor;
+ SET_NETDEV_DEVTYPE(bond_dev, &bond_type);
+
/* Initialize the device options */
bond_dev->tx_queue_len = 0;
bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
@@ -4427,7 +4345,9 @@ static void bond_uninit(struct net_device *bond_dev)
bond_netpoll_cleanup(bond_dev);
/* Release the bonded slaves */
- bond_release_all(bond_dev);
+ while (bond->first_slave != NULL)
+ __bond_release_one(bond_dev, bond->first_slave->dev, true);
+ pr_info("%s: released all slaves\n", bond_dev->name);
list_del(&bond->bond_list);
@@ -4841,6 +4761,13 @@ static int bond_init(struct net_device *bond_dev)
bond_debug_register(bond);
+ /* Ensure valid dev_addr */
+ if (is_zero_ether_addr(bond_dev->dev_addr) &&
+ bond_dev->addr_assign_type == NET_ADDR_PERM) {
+ eth_hw_addr_random(bond_dev);
+ bond->dev_addr_from_first = true;
+ }
+
__hw_addr_init(&bond->mc_list);
return 0;
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 1877ed7ca086..1c9e09fbdff8 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -1053,6 +1053,7 @@ static ssize_t bonding_store_primary(struct device *d,
pr_info("%s: Setting primary slave to None.\n",
bond->dev->name);
bond->primary_slave = NULL;
+ memset(bond->params.primary, 0, sizeof(bond->params.primary));
bond_select_active_slave(bond);
goto out;
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 21b68e5c14fd..2baec24388b1 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -248,6 +248,7 @@ struct bonding {
/* debugging support via debugfs */
struct dentry *debug_dir;
#endif /* CONFIG_DEBUG_FS */
+ bool dev_addr_from_first;
};
static inline bool bond_vlan_used(struct bonding *bond)
@@ -258,6 +259,9 @@ static inline bool bond_vlan_used(struct bonding *bond)
#define bond_slave_get_rcu(dev) \
((struct slave *) rcu_dereference(dev->rx_handler_data))
+#define bond_slave_get_rtnl(dev) \
+ ((struct slave *) rtnl_dereference(dev->rx_handler_data))
+
/**
* Returns NULL if the net_device does not belong to any of the bond's slaves
*
@@ -280,11 +284,9 @@ static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
{
- if (!slave || !slave->dev->master) {
+ if (!slave || !slave->bond)
return NULL;
- }
-
- return netdev_priv(slave->dev->master);
+ return slave->bond;
}
static inline bool bond_is_lb(const struct bonding *bond)
@@ -360,10 +362,9 @@ static inline void bond_netpoll_send_skb(const struct slave *slave,
static inline void bond_set_slave_inactive_flags(struct slave *slave)
{
- struct bonding *bond = netdev_priv(slave->dev->master);
- if (!bond_is_lb(bond))
+ if (!bond_is_lb(slave->bond))
bond_set_backup_slave(slave);
- if (!bond->params.all_slaves_active)
+ if (!slave->bond->params.all_slaves_active)
slave->inactive = 1;
}
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index abf4d7a9dcce..60c2142373c9 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -6,7 +6,7 @@ comment "CAIF transport drivers"
config CAIF_TTY
tristate "CAIF TTY transport driver"
- depends on CAIF
+ depends on CAIF && TTY
default n
---help---
The CAIF TTY transport driver is a Line Discipline (ldisc)
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 5de74e762021..666891a9a248 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -91,7 +91,7 @@ static inline void update_tty_status(struct ser_device *ser)
ser->tty->hw_stopped << 4 |
ser->tty->flow_stopped << 3 |
ser->tty->packet << 2 |
- ser->tty->low_latency << 1 |
+ ser->tty->port->low_latency << 1 |
ser->tty->warned;
}
static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c
index bc497d718858..bce8bac311c9 100644
--- a/drivers/net/caif/caif_shmcore.c
+++ b/drivers/net/caif/caif_shmcore.c
@@ -633,9 +633,6 @@ int caif_shmcore_probe(struct shmdev_layer *pshm_dev)
kmalloc(sizeof(struct buf_list), GFP_KERNEL);
if (tx_buf == NULL) {
- pr_warn("ERROR, Could not"
- " allocate dynamic mem. for tx_buf,"
- " Bailing out ...\n");
free_netdev(pshm_dev->pshm_netdev);
return -ENOMEM;
}
@@ -662,9 +659,6 @@ int caif_shmcore_probe(struct shmdev_layer *pshm_dev)
kmalloc(sizeof(struct buf_list), GFP_KERNEL);
if (rx_buf == NULL) {
- pr_warn("ERROR, Could not"
- " allocate dynamic mem.for rx_buf,"
- " Bailing out ...\n");
free_netdev(pshm_dev->pshm_netdev);
return -ENOMEM;
}
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index b56bd9e80957..9862b2e07644 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -1,9 +1,7 @@
menu "CAN Device Drivers"
- depends on CAN
config CAN_VCAN
tristate "Virtual Local CAN Interface (vcan)"
- depends on CAN
---help---
Similar to the network loopback devices, vcan offers a
virtual local CAN interface.
@@ -13,7 +11,7 @@ config CAN_VCAN
config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)"
- depends on CAN
+ depends on TTY
---help---
CAN driver for several 'low cost' CAN interfaces that are attached
via serial lines or via USB-to-serial adapters using the LAWICEL
@@ -33,16 +31,16 @@ config CAN_SLCAN
config CAN_DEV
tristate "Platform CAN drivers with Netlink support"
- depends on CAN
default y
---help---
Enables the common framework for platform CAN drivers with Netlink
support. This is the standard library for CAN drivers.
If unsure, say Y.
+if CAN_DEV
+
config CAN_CALC_BITTIMING
bool "CAN bit-timing calculation"
- depends on CAN_DEV
default y
---help---
If enabled, CAN bit-timing parameters will be calculated for the
@@ -54,15 +52,26 @@ config CAN_CALC_BITTIMING
arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
If unsure, say Y.
+config CAN_LEDS
+ bool "Enable LED triggers for Netlink based drivers"
+ depends on LEDS_CLASS
+ select LEDS_TRIGGERS
+ ---help---
+ This option adds two LED triggers for packet receive and transmit
+ events on each supported CAN device.
+
+ Say Y here if you are working on a system with led-class supported
+ LEDs and you want to use them as canbus activity indicators.
+
config CAN_AT91
tristate "Atmel AT91 onchip CAN controller"
- depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5)
+ depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5
---help---
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
and AT91SAM9X5 processors.
config CAN_TI_HECC
- depends on CAN_DEV && ARCH_OMAP3
+ depends on ARCH_OMAP3
tristate "TI High End CAN Controller"
---help---
Driver for TI HECC (High End CAN Controller) module found on many
@@ -70,12 +79,12 @@ config CAN_TI_HECC
config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers"
- depends on CAN_DEV && SPI && HAS_DMA
+ depends on SPI && HAS_DMA
---help---
Driver for the Microchip MCP251x SPI CAN controllers.
config CAN_BFIN
- depends on CAN_DEV && (BF534 || BF536 || BF537 || BF538 || BF539 || BF54x)
+ depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
tristate "Analog Devices Blackfin on-chip CAN"
---help---
Driver for the Analog Devices Blackfin on-chip CAN controllers
@@ -85,7 +94,7 @@ config CAN_BFIN
config CAN_JANZ_ICAN3
tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
- depends on CAN_DEV && MFD_JANZ_CMODIO
+ depends on MFD_JANZ_CMODIO
---help---
Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
connects to a MODULbus carrier board.
@@ -98,13 +107,13 @@ config HAVE_CAN_FLEXCAN
config CAN_FLEXCAN
tristate "Support for Freescale FLEXCAN based chips"
- depends on CAN_DEV && HAVE_CAN_FLEXCAN
+ depends on HAVE_CAN_FLEXCAN
---help---
Say Y here if you want to support for Freescale FlexCAN.
config PCH_CAN
tristate "Intel EG20T PCH CAN controller"
- depends on CAN_DEV && PCI
+ depends on PCI
---help---
This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
is an IOH for x86 embedded processor (Intel Atom E6xx series).
@@ -112,7 +121,7 @@ config PCH_CAN
config CAN_GRCAN
tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
- depends on CAN_DEV && OF
+ depends on OF
---help---
Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
Note that the driver supports little endian, even though little
@@ -131,9 +140,10 @@ source "drivers/net/can/usb/Kconfig"
source "drivers/net/can/softing/Kconfig"
+endif
+
config CAN_DEBUG_DEVICES
bool "CAN devices debugging messages"
- depends on CAN
---help---
Say Y here if you want the CAN device drivers to produce a bunch of
debug messages to the system log. Select this if you are having
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 7de59862bbe9..c7440392adbb 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -8,6 +8,8 @@ obj-$(CONFIG_CAN_SLCAN) += slcan.o
obj-$(CONFIG_CAN_DEV) += can-dev.o
can-dev-y := dev.o
+can-dev-$(CONFIG_CAN_LEDS) += led.o
+
obj-y += usb/
obj-y += softing/
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index 81baefda037b..44f363792b59 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -37,6 +37,7 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
+#include <linux/can/led.h>
#define AT91_MB_MASK(i) ((1 << (i)) - 1)
@@ -641,6 +642,8 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
+
+ can_led_event(dev, CAN_LED_EVENT_RX);
}
/**
@@ -875,6 +878,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
/* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
dev->stats.tx_packets++;
+ can_led_event(dev, CAN_LED_EVENT_TX);
}
}
@@ -1128,6 +1132,8 @@ static int at91_open(struct net_device *dev)
goto out_close;
}
+ can_led_event(dev, CAN_LED_EVENT_OPEN);
+
/* start chip and queuing */
at91_chip_start(dev);
napi_enable(&priv->napi);
@@ -1159,6 +1165,8 @@ static int at91_close(struct net_device *dev)
close_candev(dev);
+ can_led_event(dev, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -1321,6 +1329,8 @@ static int at91_can_probe(struct platform_device *pdev)
goto exit_free;
}
+ devm_can_led_init(dev);
+
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->reg_base, dev->irq);
diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig
index 3b83bafcd947..61ffc12d8fd8 100644
--- a/drivers/net/can/c_can/Kconfig
+++ b/drivers/net/can/c_can/Kconfig
@@ -1,6 +1,6 @@
menuconfig CAN_C_CAN
tristate "Bosch C_CAN/D_CAN devices"
- depends on CAN_DEV && HAS_IOMEM
+ depends on HAS_IOMEM
if CAN_C_CAN
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index 58607f196c9e..a668cd491cb3 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -39,6 +39,7 @@
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
+#include <linux/can/led.h>
#include "c_can.h"
@@ -477,6 +478,8 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
stats->rx_packets++;
stats->rx_bytes += frame->can_dlc;
+ can_led_event(dev, CAN_LED_EVENT_RX);
+
return 0;
}
@@ -488,8 +491,12 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface,
priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface),
IFX_WRITE_LOW_16BIT(mask));
+
+ /* According to C_CAN documentation, the reserved bit
+ * in IFx_MASK2 register is fixed 1
+ */
priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface),
- IFX_WRITE_HIGH_16BIT(mask));
+ IFX_WRITE_HIGH_16BIT(mask) | BIT(13));
priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
IFX_WRITE_LOW_16BIT(id));
@@ -751,6 +758,7 @@ static void c_can_do_tx(struct net_device *dev)
C_CAN_IFACE(MSGCTRL_REG, 0))
& IF_MCONT_DLC_MASK;
stats->tx_packets++;
+ can_led_event(dev, CAN_LED_EVENT_TX);
c_can_inval_msg_object(dev, 0, msg_obj_no);
} else {
break;
@@ -1115,6 +1123,8 @@ static int c_can_open(struct net_device *dev)
napi_enable(&priv->napi);
+ can_led_event(dev, CAN_LED_EVENT_OPEN);
+
/* start the c_can controller */
c_can_start(dev);
@@ -1143,6 +1153,8 @@ static int c_can_close(struct net_device *dev)
c_can_reset_ram(priv, false);
c_can_pm_runtime_put_sync(priv);
+ can_led_event(dev, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -1268,6 +1280,8 @@ int register_c_can_dev(struct net_device *dev)
err = register_candev(dev);
if (err)
c_can_pm_runtime_disable(priv);
+ else
+ devm_can_led_init(dev);
return err;
}
diff --git a/drivers/net/can/cc770/Kconfig b/drivers/net/can/cc770/Kconfig
index 22c07a8c8b43..6a9a5ba79220 100644
--- a/drivers/net/can/cc770/Kconfig
+++ b/drivers/net/can/cc770/Kconfig
@@ -1,6 +1,6 @@
menuconfig CAN_CC770
tristate "Bosch CC770 and Intel AN82527 devices"
- depends on CAN_DEV && HAS_IOMEM
+ depends on HAS_IOMEM
if CAN_CC770
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index 8233e5ed2939..f9cba4123c66 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -24,7 +24,9 @@
#include <linux/if_arp.h>
#include <linux/can.h>
#include <linux/can/dev.h>
+#include <linux/can/skb.h>
#include <linux/can/netlink.h>
+#include <linux/can/led.h>
#include <net/rtnetlink.h>
#define MOD_DESC "CAN device driver interface"
@@ -501,13 +503,18 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
{
struct sk_buff *skb;
- skb = netdev_alloc_skb(dev, sizeof(struct can_frame));
+ skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
+ sizeof(struct can_frame));
if (unlikely(!skb))
return NULL;
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ can_skb_reserve(skb);
+ can_skb_prv(skb)->ifindex = dev->ifindex;
+
*cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
memset(*cf, 0, sizeof(struct can_frame));
@@ -794,10 +801,25 @@ void unregister_candev(struct net_device *dev)
}
EXPORT_SYMBOL_GPL(unregister_candev);
+/*
+ * Test if a network device is a candev based device
+ * and return the can_priv* if so.
+ */
+struct can_priv *safe_candev_priv(struct net_device *dev)
+{
+ if ((dev->type != ARPHRD_CAN) || (dev->rtnl_link_ops != &can_link_ops))
+ return NULL;
+
+ return netdev_priv(dev);
+}
+EXPORT_SYMBOL_GPL(safe_candev_priv);
+
static __init int can_dev_init(void)
{
int err;
+ can_led_notifier_init();
+
err = rtnl_link_register(&can_link_ops);
if (!err)
printk(KERN_INFO MOD_DESC "\n");
@@ -809,6 +831,8 @@ module_init(can_dev_init);
static __exit void can_dev_exit(void)
{
rtnl_link_unregister(&can_link_ops);
+
+ can_led_notifier_exit();
}
module_exit(can_dev_exit);
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 0289a6d86f66..769d29ed106d 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -23,6 +23,7 @@
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
+#include <linux/can/led.h>
#include <linux/can/platform/flexcan.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -564,6 +565,8 @@ static int flexcan_read_frame(struct net_device *dev)
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
+ can_led_event(dev, CAN_LED_EVENT_RX);
+
return 1;
}
@@ -652,6 +655,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
stats->tx_bytes += can_get_echo_skb(dev, 0);
stats->tx_packets++;
+ can_led_event(dev, CAN_LED_EVENT_TX);
flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
netif_wake_queue(dev);
}
@@ -865,6 +869,9 @@ static int flexcan_open(struct net_device *dev)
err = flexcan_chip_start(dev);
if (err)
goto out_close;
+
+ can_led_event(dev, CAN_LED_EVENT_OPEN);
+
napi_enable(&priv->napi);
netif_start_queue(dev);
@@ -893,6 +900,8 @@ static int flexcan_close(struct net_device *dev)
close_candev(dev);
+ can_led_event(dev, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -1092,6 +1101,8 @@ static int flexcan_probe(struct platform_device *pdev)
goto failed_register;
}
+ devm_can_led_init(dev);
+
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->base, dev->irq);
diff --git a/drivers/net/can/led.c b/drivers/net/can/led.c
new file mode 100644
index 000000000000..f27fca65dc4a
--- /dev/null
+++ b/drivers/net/can/led.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
+ * Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be>
+ *
+ * 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/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/can/dev.h>
+
+#include <linux/can/led.h>
+
+static unsigned long led_delay = 50;
+module_param(led_delay, ulong, 0644);
+MODULE_PARM_DESC(led_delay,
+ "blink delay time for activity leds (msecs, default: 50).");
+
+/* Trigger a LED event in response to a CAN device event */
+void can_led_event(struct net_device *netdev, enum can_led_event event)
+{
+ struct can_priv *priv = netdev_priv(netdev);
+
+ switch (event) {
+ case CAN_LED_EVENT_OPEN:
+ led_trigger_event(priv->tx_led_trig, LED_FULL);
+ led_trigger_event(priv->rx_led_trig, LED_FULL);
+ break;
+ case CAN_LED_EVENT_STOP:
+ led_trigger_event(priv->tx_led_trig, LED_OFF);
+ led_trigger_event(priv->rx_led_trig, LED_OFF);
+ break;
+ case CAN_LED_EVENT_TX:
+ if (led_delay)
+ led_trigger_blink_oneshot(priv->tx_led_trig,
+ &led_delay, &led_delay, 1);
+ break;
+ case CAN_LED_EVENT_RX:
+ if (led_delay)
+ led_trigger_blink_oneshot(priv->rx_led_trig,
+ &led_delay, &led_delay, 1);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(can_led_event);
+
+static void can_led_release(struct device *gendev, void *res)
+{
+ struct can_priv *priv = netdev_priv(to_net_dev(gendev));
+
+ led_trigger_unregister_simple(priv->tx_led_trig);
+ led_trigger_unregister_simple(priv->rx_led_trig);
+}
+
+/* Register CAN LED triggers for a CAN device
+ *
+ * This is normally called from a driver's probe function
+ */
+void devm_can_led_init(struct net_device *netdev)
+{
+ struct can_priv *priv = netdev_priv(netdev);
+ void *res;
+
+ res = devres_alloc(can_led_release, 0, GFP_KERNEL);
+ if (!res) {
+ netdev_err(netdev, "cannot register LED triggers\n");
+ return;
+ }
+
+ snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name),
+ "%s-tx", netdev->name);
+ snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name),
+ "%s-rx", netdev->name);
+
+ led_trigger_register_simple(priv->tx_led_trig_name,
+ &priv->tx_led_trig);
+ led_trigger_register_simple(priv->rx_led_trig_name,
+ &priv->rx_led_trig);
+
+ devres_add(&netdev->dev, res);
+}
+EXPORT_SYMBOL_GPL(devm_can_led_init);
+
+/* NETDEV rename notifier to rename the associated led triggers too */
+static int can_led_notifier(struct notifier_block *nb, unsigned long msg,
+ void *data)
+{
+ struct net_device *netdev = data;
+ struct can_priv *priv = safe_candev_priv(netdev);
+ char name[CAN_LED_NAME_SZ];
+
+ if (!priv)
+ return NOTIFY_DONE;
+
+ if (msg == NETDEV_CHANGENAME) {
+ snprintf(name, sizeof(name), "%s-tx", netdev->name);
+ led_trigger_rename_static(name, priv->tx_led_trig);
+
+ snprintf(name, sizeof(name), "%s-rx", netdev->name);
+ led_trigger_rename_static(name, priv->rx_led_trig);
+ }
+
+ return NOTIFY_DONE;
+}
+
+/* notifier block for netdevice event */
+static struct notifier_block can_netdev_notifier __read_mostly = {
+ .notifier_call = can_led_notifier,
+};
+
+int __init can_led_notifier_init(void)
+{
+ return register_netdevice_notifier(&can_netdev_notifier);
+}
+
+void __exit can_led_notifier_exit(void)
+{
+ unregister_netdevice_notifier(&can_netdev_notifier);
+}
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index 5eaf47b8e37b..f32b9fc6a983 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -60,6 +60,7 @@
#include <linux/can/core.h>
#include <linux/can/dev.h>
+#include <linux/can/led.h>
#include <linux/can/platform/mcp251x.h>
#include <linux/completion.h>
#include <linux/delay.h>
@@ -494,6 +495,9 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
priv->net->stats.rx_packets++;
priv->net->stats.rx_bytes += frame->can_dlc;
+
+ can_led_event(priv->net, CAN_LED_EVENT_RX);
+
netif_rx_ni(skb);
}
@@ -707,6 +711,8 @@ static int mcp251x_stop(struct net_device *net)
mutex_unlock(&priv->mcp_lock);
+ can_led_event(net, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -905,6 +911,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
if (intf & CANINTF_TX) {
net->stats.tx_packets++;
net->stats.tx_bytes += priv->tx_len - 1;
+ can_led_event(net, CAN_LED_EVENT_TX);
if (priv->tx_len) {
can_get_echo_skb(net, 0);
priv->tx_len = 0;
@@ -968,6 +975,9 @@ static int mcp251x_open(struct net_device *net)
mcp251x_open_clean(net);
goto open_unlock;
}
+
+ can_led_event(net, CAN_LED_EVENT_OPEN);
+
netif_wake_queue(net);
open_unlock:
@@ -1077,10 +1087,15 @@ static int mcp251x_can_probe(struct spi_device *spi)
pdata->transceiver_enable(0);
ret = register_candev(net);
- if (!ret) {
- dev_info(&spi->dev, "probed\n");
- return ret;
- }
+ if (ret)
+ goto error_probe;
+
+ devm_can_led_init(net);
+
+ dev_info(&spi->dev, "probed\n");
+
+ return ret;
+
error_probe:
if (!mcp251x_enable_dma)
kfree(priv->spi_rx_buf);
diff --git a/drivers/net/can/mscan/Kconfig b/drivers/net/can/mscan/Kconfig
index d38706958af6..f19be5269e7b 100644
--- a/drivers/net/can/mscan/Kconfig
+++ b/drivers/net/can/mscan/Kconfig
@@ -1,5 +1,5 @@
config CAN_MSCAN
- depends on CAN_DEV && (PPC || M68K)
+ depends on PPC || M68K
tristate "Support for Freescale MSCAN based chips"
---help---
The Motorola Scalable Controller Area Network (MSCAN) definition
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 92f73c708a3d..b39ca5b3ea7f 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -1,6 +1,6 @@
menuconfig CAN_SJA1000
tristate "Philips/NXP SJA1000 devices"
- depends on CAN_DEV && HAS_IOMEM
+ depends on HAS_IOMEM
if CAN_SJA1000
@@ -99,11 +99,11 @@ config CAN_TSCAN1
tristate "TS-CAN1 PC104 boards"
depends on ISA
help
- This driver is for Technologic Systems' TSCAN-1 PC104 boards.
- http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
- The driver supports multiple boards and automatically configures them:
- PLD IO base addresses are read from jumpers JP1 and JP2,
- IRQ numbers are read from jumpers JP4 and JP5,
- SJA1000 IO base addresses are chosen heuristically (first that works).
+ This driver is for Technologic Systems' TSCAN-1 PC104 boards.
+ http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
+ The driver supports multiple boards and automatically configures them:
+ PLD IO base addresses are read from jumpers JP1 and JP2,
+ IRQ numbers are read from jumpers JP4 and JP5,
+ SJA1000 IO base addresses are chosen heuristically (first that works).
endif
diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index 036a326836b2..36d298da2af6 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -238,7 +238,6 @@ static int ems_pci_add_card(struct pci_dev *pdev,
/* Allocating card structures to hold addresses, ... */
card = kzalloc(sizeof(struct ems_pci_card), GFP_KERNEL);
if (card == NULL) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
pci_disable_device(pdev);
return -ENOMEM;
}
diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
index d84888f03d92..d1e7f1006ddd 100644
--- a/drivers/net/can/sja1000/peak_pci.c
+++ b/drivers/net/can/sja1000/peak_pci.c
@@ -339,8 +339,7 @@ static void peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s)
*/
static void peak_pciec_start_led_work(struct peak_pciec_card *card)
{
- if (!delayed_work_pending(&card->led_work))
- schedule_delayed_work(&card->led_work, HZ);
+ schedule_delayed_work(&card->led_work, HZ);
}
/*
@@ -451,11 +450,8 @@ static int peak_pciec_probe(struct pci_dev *pdev, struct net_device *dev)
} else {
/* create the bit banging I2C adapter structure */
card = kzalloc(sizeof(struct peak_pciec_card), GFP_KERNEL);
- if (!card) {
- dev_err(&pdev->dev,
- "failed allocating memory for i2c chip\n");
+ if (!card)
return -ENOMEM;
- }
card->cfg_base = chan->cfg_base;
card->reg_base = priv->reg_base;
diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c
index f1175142b0a0..1a7020ba37f5 100644
--- a/drivers/net/can/sja1000/peak_pcmcia.c
+++ b/drivers/net/can/sja1000/peak_pcmcia.c
@@ -660,7 +660,6 @@ static int pcan_probe(struct pcmcia_device *pdev)
card = kzalloc(sizeof(struct pcan_pccard), GFP_KERNEL);
if (!card) {
- dev_err(&pdev->dev, "couldn't allocate card memory\n");
err = -ENOMEM;
goto probe_err_2;
}
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
index 11d1062a9449..a042cdc260dc 100644
--- a/drivers/net/can/sja1000/plx_pci.c
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -508,7 +508,6 @@ static int plx_pci_add_card(struct pci_dev *pdev,
/* Allocate card structures to hold addresses, ... */
card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
pci_disable_device(pdev);
return -ENOMEM;
}
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 83ee11eca0e2..daf4013a8fc7 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -60,6 +60,7 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
+#include <linux/can/led.h>
#include "sja1000.h"
@@ -368,6 +369,8 @@ static void sja1000_rx(struct net_device *dev)
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
+
+ can_led_event(dev, CAN_LED_EVENT_RX);
}
static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
@@ -521,6 +524,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
can_get_echo_skb(dev, 0);
}
netif_wake_queue(dev);
+ can_led_event(dev, CAN_LED_EVENT_TX);
}
if (isrc & IRQ_RI) {
/* receive interrupt */
@@ -575,6 +579,8 @@ static int sja1000_open(struct net_device *dev)
/* init and start chi */
sja1000_start(dev);
+ can_led_event(dev, CAN_LED_EVENT_OPEN);
+
netif_start_queue(dev);
return 0;
@@ -592,6 +598,8 @@ static int sja1000_close(struct net_device *dev)
close_candev(dev);
+ can_led_event(dev, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -639,6 +647,8 @@ static const struct net_device_ops sja1000_netdev_ops = {
int register_sja1000dev(struct net_device *dev)
{
+ int ret;
+
if (!sja1000_probe_chip(dev))
return -ENODEV;
@@ -648,7 +658,12 @@ int register_sja1000dev(struct net_device *dev)
set_reset_mode(dev);
chipset_init(dev);
- return register_candev(dev);
+ ret = register_candev(dev);
+
+ if (!ret)
+ devm_can_led_init(dev);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(register_sja1000dev);
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index adc3708d8829..06b7e097d36e 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -55,6 +55,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/can.h>
+#include <linux/can/skb.h>
static __initconst const char banner[] =
KERN_INFO "slcan: serial line CAN interface driver\n";
@@ -184,7 +185,8 @@ static void slc_bump(struct slcan *sl)
cf.data[i] |= tmp;
}
- skb = dev_alloc_skb(sizeof(struct can_frame));
+ skb = dev_alloc_skb(sizeof(struct can_frame) +
+ sizeof(struct can_skb_priv));
if (!skb)
return;
@@ -192,6 +194,10 @@ static void slc_bump(struct slcan *sl)
skb->protocol = htons(ETH_P_CAN);
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ can_skb_reserve(skb);
+ can_skb_prv(skb)->ifindex = sl->dev->ifindex;
+
memcpy(skb_put(skb, sizeof(struct can_frame)),
&cf, sizeof(struct can_frame));
netif_rx_ni(skb);
diff --git a/drivers/net/can/softing/Kconfig b/drivers/net/can/softing/Kconfig
index 5de46a9a77bb..96b6fe158b5b 100644
--- a/drivers/net/can/softing/Kconfig
+++ b/drivers/net/can/softing/Kconfig
@@ -1,6 +1,6 @@
config CAN_SOFTING
tristate "Softing Gmbh CAN generic support"
- depends on CAN_DEV && HAS_IOMEM
+ depends on HAS_IOMEM
---help---
Support for CAN cards from Softing Gmbh & some cards
from Vector Gmbh.
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 300581b24ff3..f21fc37ec578 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -50,6 +50,7 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
+#include <linux/can/led.h>
#include <linux/can/platform/ti_hecc.h>
#define DRV_NAME "ti_hecc"
@@ -593,6 +594,7 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno)
spin_unlock_irqrestore(&priv->mbx_lock, flags);
stats->rx_bytes += cf->can_dlc;
+ can_led_event(priv->ndev, CAN_LED_EVENT_RX);
netif_receive_skb(skb);
stats->rx_packets++;
@@ -796,6 +798,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
stats->tx_bytes += hecc_read_mbx(priv, mbxno,
HECC_CANMCF) & 0xF;
stats->tx_packets++;
+ can_led_event(ndev, CAN_LED_EVENT_TX);
can_get_echo_skb(ndev, mbxno);
--priv->tx_tail;
}
@@ -851,6 +854,8 @@ static int ti_hecc_open(struct net_device *ndev)
return err;
}
+ can_led_event(ndev, CAN_LED_EVENT_OPEN);
+
ti_hecc_start(ndev);
napi_enable(&priv->napi);
netif_start_queue(ndev);
@@ -869,6 +874,8 @@ static int ti_hecc_close(struct net_device *ndev)
close_candev(ndev);
ti_hecc_transceiver_switch(priv, 0);
+ can_led_event(ndev, CAN_LED_EVENT_STOP);
+
return 0;
}
@@ -961,6 +968,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "register_candev() failed\n");
goto probe_exit_clk;
}
+
+ devm_can_led_init(ndev);
+
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
priv->base, (u32) ndev->irq);
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a4e4bee35710..fc96a3d83ebe 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -1,5 +1,5 @@
menu "CAN USB interfaces"
- depends on USB && CAN_DEV
+ depends on USB
config CAN_EMS_USB
tristate "EMS CPC-USB/ARM7 CAN/USB interface"
@@ -48,4 +48,10 @@ config CAN_PEAK_USB
This driver supports the PCAN-USB and PCAN-USB Pro adapters
from PEAK-System Technik (http://www.peak-system.com).
+config CAN_8DEV_USB
+ tristate "8 devices USB2CAN interface"
+ ---help---
+ This driver supports the USB2CAN interface
+ from 8 devices (http://www.8devices.com).
+
endmenu
diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
index 80a2ee41fd61..becef460a91a 100644
--- a/drivers/net/can/usb/Makefile
+++ b/drivers/net/can/usb/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
+obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index c69f0b72b352..5f9a7ad9b964 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -1014,17 +1014,13 @@ static int ems_usb_probe(struct usb_interface *intf,
}
dev->intr_in_buffer = kzalloc(INTR_IN_BUFFER_SIZE, GFP_KERNEL);
- if (!dev->intr_in_buffer) {
- dev_err(&intf->dev, "Couldn't alloc Intr buffer\n");
+ if (!dev->intr_in_buffer)
goto cleanup_intr_urb;
- }
dev->tx_msg_buffer = kzalloc(CPC_HEADER_SIZE +
sizeof(struct ems_cpc_msg), GFP_KERNEL);
- if (!dev->tx_msg_buffer) {
- dev_err(&intf->dev, "Couldn't alloc Tx buffer\n");
+ if (!dev->tx_msg_buffer)
goto cleanup_intr_in_buffer;
- }
usb_set_intfdata(intf, dev);
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 5b58a4d87397..45cb9f3c1324 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -561,7 +561,6 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
if (!buf) {
- netdev_err(netdev, "No memory left for USB buffer\n");
usb_free_urb(urb);
return -ENOMEM;
}
@@ -1268,7 +1267,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
if (!buf) {
- netdev_err(netdev, "No memory left for USB buffer\n");
stats->tx_dropped++;
goto nobufmem;
}
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index d9290ea788e0..a0f647f92bf5 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -386,7 +386,6 @@ static int peak_usb_start(struct peak_usb_device *dev)
buf = kmalloc(dev->adapter->rx_buffer_size, GFP_KERNEL);
if (!buf) {
- netdev_err(netdev, "No memory left for USB buffer\n");
usb_free_urb(urb);
err = -ENOMEM;
break;
@@ -442,7 +441,6 @@ static int peak_usb_start(struct peak_usb_device *dev)
buf = kmalloc(dev->adapter->tx_buffer_size, GFP_KERNEL);
if (!buf) {
- netdev_err(netdev, "No memory left for USB buffer\n");
usb_free_urb(urb);
err = -ENOMEM;
break;
@@ -634,7 +632,6 @@ static int peak_usb_restart(struct peak_usb_device *dev)
/* also allocate enough space for the commands to send */
buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_ATOMIC);
if (!buf) {
- netdev_err(dev->netdev, "no memory left for async cmd\n");
usb_free_urb(urb);
return -ENOMEM;
}
@@ -729,8 +726,6 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter,
/* allocate a buffer large enough to send commands */
dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL);
if (!dev->cmd_buf) {
- dev_err(&intf->dev, "%s: couldn't alloc cmd buffer\n",
- PCAN_USB_DRIVER_NAME);
err = -ENOMEM;
goto lbl_set_intf_data;
}
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
new file mode 100644
index 000000000000..6e15ef08f301
--- /dev/null
+++ b/drivers/net/can/usb/usb_8dev.c
@@ -0,0 +1,1031 @@
+/*
+ * CAN driver for "8 devices" USB2CAN converter
+ *
+ * Copyright (C) 2012 Bernd Krumboeck (krumboeck@universalnet.at)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; 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.
+ *
+ * This driver is inspired by the 3.2.0 version of drivers/net/can/usb/ems_usb.c
+ * and drivers/net/can/usb/esd_usb2.c
+ *
+ * Many thanks to Gerhard Bertelsmann (info@gerhard-bertelsmann.de)
+ * for testing and fixing this driver. Also many thanks to "8 devices",
+ * who were very cooperative and answered my questions.
+ */
+
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/led.h>
+
+/* driver constants */
+#define MAX_RX_URBS 20
+#define MAX_TX_URBS 20
+#define RX_BUFFER_SIZE 64
+
+/* vendor and product id */
+#define USB_8DEV_VENDOR_ID 0x0483
+#define USB_8DEV_PRODUCT_ID 0x1234
+
+/* endpoints */
+enum usb_8dev_endpoint {
+ USB_8DEV_ENDP_DATA_RX = 1,
+ USB_8DEV_ENDP_DATA_TX,
+ USB_8DEV_ENDP_CMD_RX,
+ USB_8DEV_ENDP_CMD_TX
+};
+
+/* device CAN clock */
+#define USB_8DEV_ABP_CLOCK 32000000
+
+/* setup flags */
+#define USB_8DEV_SILENT 0x01
+#define USB_8DEV_LOOPBACK 0x02
+#define USB_8DEV_DISABLE_AUTO_RESTRANS 0x04
+#define USB_8DEV_STATUS_FRAME 0x08
+
+/* commands */
+enum usb_8dev_cmd {
+ USB_8DEV_RESET = 1,
+ USB_8DEV_OPEN,
+ USB_8DEV_CLOSE,
+ USB_8DEV_SET_SPEED,
+ USB_8DEV_SET_MASK_FILTER,
+ USB_8DEV_GET_STATUS,
+ USB_8DEV_GET_STATISTICS,
+ USB_8DEV_GET_SERIAL,
+ USB_8DEV_GET_SOFTW_VER,
+ USB_8DEV_GET_HARDW_VER,
+ USB_8DEV_RESET_TIMESTAMP,
+ USB_8DEV_GET_SOFTW_HARDW_VER
+};
+
+/* command options */
+#define USB_8DEV_BAUD_MANUAL 0x09
+#define USB_8DEV_CMD_START 0x11
+#define USB_8DEV_CMD_END 0x22
+
+#define USB_8DEV_CMD_SUCCESS 0
+#define USB_8DEV_CMD_ERROR 255
+
+#define USB_8DEV_CMD_TIMEOUT 1000
+
+/* frames */
+#define USB_8DEV_DATA_START 0x55
+#define USB_8DEV_DATA_END 0xAA
+
+#define USB_8DEV_TYPE_CAN_FRAME 0
+#define USB_8DEV_TYPE_ERROR_FRAME 3
+
+#define USB_8DEV_EXTID 0x01
+#define USB_8DEV_RTR 0x02
+#define USB_8DEV_ERR_FLAG 0x04
+
+/* status */
+#define USB_8DEV_STATUSMSG_OK 0x00 /* Normal condition. */
+#define USB_8DEV_STATUSMSG_OVERRUN 0x01 /* Overrun occured when sending */
+#define USB_8DEV_STATUSMSG_BUSLIGHT 0x02 /* Error counter has reached 96 */
+#define USB_8DEV_STATUSMSG_BUSHEAVY 0x03 /* Error count. has reached 128 */
+#define USB_8DEV_STATUSMSG_BUSOFF 0x04 /* Device is in BUSOFF */
+#define USB_8DEV_STATUSMSG_STUFF 0x20 /* Stuff Error */
+#define USB_8DEV_STATUSMSG_FORM 0x21 /* Form Error */
+#define USB_8DEV_STATUSMSG_ACK 0x23 /* Ack Error */
+#define USB_8DEV_STATUSMSG_BIT0 0x24 /* Bit1 Error */
+#define USB_8DEV_STATUSMSG_BIT1 0x25 /* Bit0 Error */
+#define USB_8DEV_STATUSMSG_CRC 0x27 /* CRC Error */
+
+#define USB_8DEV_RP_MASK 0x7F /* Mask for Receive Error Bit */
+
+
+/* table of devices that work with this driver */
+static const struct usb_device_id usb_8dev_table[] = {
+ { USB_DEVICE(USB_8DEV_VENDOR_ID, USB_8DEV_PRODUCT_ID) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_8dev_table);
+
+struct usb_8dev_tx_urb_context {
+ struct usb_8dev_priv *priv;
+
+ u32 echo_index;
+ u8 dlc;
+};
+
+/* Structure to hold all of our device specific stuff */
+struct usb_8dev_priv {
+ struct can_priv can; /* must be the first member */
+
+ struct sk_buff *echo_skb[MAX_TX_URBS];
+
+ struct usb_device *udev;
+ struct net_device *netdev;
+
+ atomic_t active_tx_urbs;
+ struct usb_anchor tx_submitted;
+ struct usb_8dev_tx_urb_context tx_contexts[MAX_TX_URBS];
+
+ struct usb_anchor rx_submitted;
+
+ struct can_berr_counter bec;
+
+ u8 *cmd_msg_buffer;
+
+ struct mutex usb_8dev_cmd_lock;
+
+};
+
+/* tx frame */
+struct __packed usb_8dev_tx_msg {
+ u8 begin;
+ u8 flags; /* RTR and EXT_ID flag */
+ __be32 id; /* upper 3 bits not used */
+ u8 dlc; /* data length code 0-8 bytes */
+ u8 data[8]; /* 64-bit data */
+ u8 end;
+};
+
+/* rx frame */
+struct __packed usb_8dev_rx_msg {
+ u8 begin;
+ u8 type; /* frame type */
+ u8 flags; /* RTR and EXT_ID flag */
+ __be32 id; /* upper 3 bits not used */
+ u8 dlc; /* data length code 0-8 bytes */
+ u8 data[8]; /* 64-bit data */
+ __be32 timestamp; /* 32-bit timestamp */
+ u8 end;
+};
+
+/* command frame */
+struct __packed usb_8dev_cmd_msg {
+ u8 begin;
+ u8 channel; /* unkown - always 0 */
+ u8 command; /* command to execute */
+ u8 opt1; /* optional parameter / return value */
+ u8 opt2; /* optional parameter 2 */
+ u8 data[10]; /* optional parameter and data */
+ u8 end;
+};
+
+static int usb_8dev_send_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size)
+{
+ int actual_length;
+
+ return usb_bulk_msg(priv->udev,
+ usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_TX),
+ msg, size, &actual_length, USB_8DEV_CMD_TIMEOUT);
+}
+
+static int usb_8dev_wait_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size,
+ int *actual_length)
+{
+ return usb_bulk_msg(priv->udev,
+ usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_RX),
+ msg, size, actual_length, USB_8DEV_CMD_TIMEOUT);
+}
+
+/* Send command to device and receive result.
+ * Command was successful when opt1 = 0.
+ */
+static int usb_8dev_send_cmd(struct usb_8dev_priv *priv,
+ struct usb_8dev_cmd_msg *out,
+ struct usb_8dev_cmd_msg *in)
+{
+ int err;
+ int num_bytes_read;
+ struct net_device *netdev;
+
+ netdev = priv->netdev;
+
+ out->begin = USB_8DEV_CMD_START;
+ out->end = USB_8DEV_CMD_END;
+
+ mutex_lock(&priv->usb_8dev_cmd_lock);
+
+ memcpy(priv->cmd_msg_buffer, out,
+ sizeof(struct usb_8dev_cmd_msg));
+
+ err = usb_8dev_send_cmd_msg(priv, priv->cmd_msg_buffer,
+ sizeof(struct usb_8dev_cmd_msg));
+ if (err < 0) {
+ netdev_err(netdev, "sending command message failed\n");
+ goto failed;
+ }
+
+ err = usb_8dev_wait_cmd_msg(priv, priv->cmd_msg_buffer,
+ sizeof(struct usb_8dev_cmd_msg),
+ &num_bytes_read);
+ if (err < 0) {
+ netdev_err(netdev, "no command message answer\n");
+ goto failed;
+ }
+
+ memcpy(in, priv->cmd_msg_buffer, sizeof(struct usb_8dev_cmd_msg));
+
+ if (in->begin != USB_8DEV_CMD_START || in->end != USB_8DEV_CMD_END ||
+ num_bytes_read != 16 || in->opt1 != 0)
+ err = -EPROTO;
+
+failed:
+ mutex_unlock(&priv->usb_8dev_cmd_lock);
+ return err;
+}
+
+/* Send open command to device */
+static int usb_8dev_cmd_open(struct usb_8dev_priv *priv)
+{
+ struct can_bittiming *bt = &priv->can.bittiming;
+ struct usb_8dev_cmd_msg outmsg;
+ struct usb_8dev_cmd_msg inmsg;
+ u32 ctrlmode = priv->can.ctrlmode;
+ u32 flags = USB_8DEV_STATUS_FRAME;
+ __be32 beflags;
+ __be16 bebrp;
+
+ memset(&outmsg, 0, sizeof(outmsg));
+ outmsg.command = USB_8DEV_OPEN;
+ outmsg.opt1 = USB_8DEV_BAUD_MANUAL;
+ outmsg.data[0] = bt->prop_seg + bt->phase_seg1;
+ outmsg.data[1] = bt->phase_seg2;
+ outmsg.data[2] = bt->sjw;
+
+ /* BRP */
+ bebrp = cpu_to_be16((u16)bt->brp);
+ memcpy(&outmsg.data[3], &bebrp, sizeof(bebrp));
+
+ /* flags */
+ if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
+ flags |= USB_8DEV_LOOPBACK;
+ if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ flags |= USB_8DEV_SILENT;
+ if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+ flags |= USB_8DEV_DISABLE_AUTO_RESTRANS;
+
+ beflags = cpu_to_be32(flags);
+ memcpy(&outmsg.data[5], &beflags, sizeof(beflags));
+
+ return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+}
+
+/* Send close command to device */
+static int usb_8dev_cmd_close(struct usb_8dev_priv *priv)
+{
+ struct usb_8dev_cmd_msg inmsg;
+ struct usb_8dev_cmd_msg outmsg = {
+ .channel = 0,
+ .command = USB_8DEV_CLOSE,
+ .opt1 = 0,
+ .opt2 = 0
+ };
+
+ return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+}
+
+/* Get firmware and hardware version */
+static int usb_8dev_cmd_version(struct usb_8dev_priv *priv, u32 *res)
+{
+ struct usb_8dev_cmd_msg inmsg;
+ struct usb_8dev_cmd_msg outmsg = {
+ .channel = 0,
+ .command = USB_8DEV_GET_SOFTW_HARDW_VER,
+ .opt1 = 0,
+ .opt2 = 0
+ };
+
+ int err = usb_8dev_send_cmd(priv, &outmsg, &inmsg);
+ if (err)
+ return err;
+
+ *res = be32_to_cpup((__be32 *)inmsg.data);
+
+ return err;
+}
+
+/* Set network device mode
+ *
+ * Maybe we should leave this function empty, because the device
+ * set mode variable with open command.
+ */
+static int usb_8dev_set_mode(struct net_device *netdev, enum can_mode mode)
+{
+ struct usb_8dev_priv *priv = netdev_priv(netdev);
+ int err = 0;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ err = usb_8dev_cmd_open(priv);
+ if (err)
+ netdev_warn(netdev, "couldn't start device");
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
+/* Read error/status frames */
+static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
+ struct usb_8dev_rx_msg *msg)
+{
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct net_device_stats *stats = &priv->netdev->stats;
+
+ /* Error message:
+ * byte 0: Status
+ * byte 1: bit 7: Receive Passive
+ * byte 1: bit 0-6: Receive Error Counter
+ * byte 2: Transmit Error Counter
+ * byte 3: Always 0 (maybe reserved for future use)
+ */
+
+ u8 state = msg->data[0];
+ u8 rxerr = msg->data[1] & USB_8DEV_RP_MASK;
+ u8 txerr = msg->data[2];
+ int rx_errors = 0;
+ int tx_errors = 0;
+
+ skb = alloc_can_err_skb(priv->netdev, &cf);
+ if (!skb)
+ return;
+
+ switch (state) {
+ case USB_8DEV_STATUSMSG_OK:
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_ACTIVE;
+ break;
+ case USB_8DEV_STATUSMSG_BUSOFF:
+ priv->can.state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ can_bus_off(priv->netdev);
+ break;
+ case USB_8DEV_STATUSMSG_OVERRUN:
+ case USB_8DEV_STATUSMSG_BUSLIGHT:
+ case USB_8DEV_STATUSMSG_BUSHEAVY:
+ cf->can_id |= CAN_ERR_CRTL;
+ break;
+ default:
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+ priv->can.can_stats.bus_error++;
+ break;
+ }
+
+ switch (state) {
+ case USB_8DEV_STATUSMSG_OK:
+ case USB_8DEV_STATUSMSG_BUSOFF:
+ break;
+ case USB_8DEV_STATUSMSG_ACK:
+ cf->can_id |= CAN_ERR_ACK;
+ tx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_CRC:
+ cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+ cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL;
+ rx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_BIT0:
+ cf->data[2] |= CAN_ERR_PROT_BIT0;
+ tx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_BIT1:
+ cf->data[2] |= CAN_ERR_PROT_BIT1;
+ tx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_FORM:
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ rx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_STUFF:
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ rx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_OVERRUN:
+ cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+ stats->rx_over_errors++;
+ rx_errors = 1;
+ break;
+ case USB_8DEV_STATUSMSG_BUSLIGHT:
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ cf->data[1] = (txerr > rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ priv->can.can_stats.error_warning++;
+ break;
+ case USB_8DEV_STATUSMSG_BUSHEAVY:
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ cf->data[1] = (txerr > rxerr) ?
+ CAN_ERR_CRTL_TX_PASSIVE :
+ CAN_ERR_CRTL_RX_PASSIVE;
+ priv->can.can_stats.error_passive++;
+ break;
+ default:
+ netdev_warn(priv->netdev,
+ "Unknown status/error message (%d)\n", state);
+ break;
+ }
+
+ if (tx_errors) {
+ cf->data[2] |= CAN_ERR_PROT_TX;
+ stats->tx_errors++;
+ }
+
+ if (rx_errors)
+ stats->rx_errors++;
+
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
+
+ priv->bec.txerr = txerr;
+ priv->bec.rxerr = rxerr;
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+}
+
+/* Read data and status frames */
+static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv,
+ struct usb_8dev_rx_msg *msg)
+{
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct net_device_stats *stats = &priv->netdev->stats;
+
+ if (msg->type == USB_8DEV_TYPE_ERROR_FRAME &&
+ msg->flags == USB_8DEV_ERR_FLAG) {
+ usb_8dev_rx_err_msg(priv, msg);
+ } else if (msg->type == USB_8DEV_TYPE_CAN_FRAME) {
+ skb = alloc_can_skb(priv->netdev, &cf);
+ if (!skb)
+ return;
+
+ cf->can_id = be32_to_cpu(msg->id);
+ cf->can_dlc = get_can_dlc(msg->dlc & 0xF);
+
+ if (msg->flags & USB_8DEV_EXTID)
+ cf->can_id |= CAN_EFF_FLAG;
+
+ if (msg->flags & USB_8DEV_RTR)
+ cf->can_id |= CAN_RTR_FLAG;
+ else
+ memcpy(cf->data, msg->data, cf->can_dlc);
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ can_led_event(priv->netdev, CAN_LED_EVENT_RX);
+ } else {
+ netdev_warn(priv->netdev, "frame type %d unknown",
+ msg->type);
+ }
+
+}
+
+/* Callback for reading data from device
+ *
+ * Check urb status, call read function and resubmit urb read operation.
+ */
+static void usb_8dev_read_bulk_callback(struct urb *urb)
+{
+ struct usb_8dev_priv *priv = urb->context;
+ struct net_device *netdev;
+ int retval;
+ int pos = 0;
+
+ netdev = priv->netdev;
+
+ if (!netif_device_present(netdev))
+ return;
+
+ switch (urb->status) {
+ case 0: /* success */
+ break;
+
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+
+ default:
+ netdev_info(netdev, "Rx URB aborted (%d)\n",
+ urb->status);
+ goto resubmit_urb;
+ }
+
+ while (pos < urb->actual_length) {
+ struct usb_8dev_rx_msg *msg;
+
+ if (pos + sizeof(struct usb_8dev_rx_msg) > urb->actual_length) {
+ netdev_err(priv->netdev, "format error\n");
+ break;
+ }
+
+ msg = (struct usb_8dev_rx_msg *)(urb->transfer_buffer + pos);
+ usb_8dev_rx_can_msg(priv, msg);
+
+ pos += sizeof(struct usb_8dev_rx_msg);
+ }
+
+resubmit_urb:
+ usb_fill_bulk_urb(urb, priv->udev,
+ usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX),
+ urb->transfer_buffer, RX_BUFFER_SIZE,
+ usb_8dev_read_bulk_callback, priv);
+
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+ if (retval == -ENODEV)
+ netif_device_detach(netdev);
+ else if (retval)
+ netdev_err(netdev,
+ "failed resubmitting read bulk urb: %d\n", retval);
+}
+
+/* Callback handler for write operations
+ *
+ * Free allocated buffers, check transmit status and
+ * calculate statistic.
+ */
+static void usb_8dev_write_bulk_callback(struct urb *urb)
+{
+ struct usb_8dev_tx_urb_context *context = urb->context;
+ struct usb_8dev_priv *priv;
+ struct net_device *netdev;
+
+ BUG_ON(!context);
+
+ priv = context->priv;
+ netdev = priv->netdev;
+
+ /* free up our allocated buffer */
+ usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+
+ atomic_dec(&priv->active_tx_urbs);
+
+ if (!netif_device_present(netdev))
+ return;
+
+ if (urb->status)
+ netdev_info(netdev, "Tx URB aborted (%d)\n",
+ urb->status);
+
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += context->dlc;
+
+ can_get_echo_skb(netdev, context->echo_index);
+
+ can_led_event(netdev, CAN_LED_EVENT_TX);
+
+ /* Release context */
+ context->echo_index = MAX_TX_URBS;
+
+ netif_wake_queue(netdev);
+}
+
+/* Send data to device */
+static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct usb_8dev_priv *priv = netdev_priv(netdev);
+ struct net_device_stats *stats = &netdev->stats;
+ struct can_frame *cf = (struct can_frame *) skb->data;
+ struct usb_8dev_tx_msg *msg;
+ struct urb *urb;
+ struct usb_8dev_tx_urb_context *context = NULL;
+ u8 *buf;
+ int i, err;
+ size_t size = sizeof(struct usb_8dev_tx_msg);
+
+ if (can_dropped_invalid_skb(netdev, skb))
+ return NETDEV_TX_OK;
+
+ /* create a URB, and a buffer for it, and copy the data to the URB */
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ netdev_err(netdev, "No memory left for URBs\n");
+ goto nomem;
+ }
+
+ buf = usb_alloc_coherent(priv->udev, size, GFP_ATOMIC,
+ &urb->transfer_dma);
+ if (!buf) {
+ netdev_err(netdev, "No memory left for USB buffer\n");
+ goto nomembuf;
+ }
+
+ memset(buf, 0, size);
+
+ msg = (struct usb_8dev_tx_msg *)buf;
+ msg->begin = USB_8DEV_DATA_START;
+ msg->flags = 0x00;
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ msg->flags |= USB_8DEV_RTR;
+
+ if (cf->can_id & CAN_EFF_FLAG)
+ msg->flags |= USB_8DEV_EXTID;
+
+ msg->id = cpu_to_be32(cf->can_id & CAN_ERR_MASK);
+ msg->dlc = cf->can_dlc;
+ memcpy(msg->data, cf->data, cf->can_dlc);
+ msg->end = USB_8DEV_DATA_END;
+
+ for (i = 0; i < MAX_TX_URBS; i++) {
+ if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+ context = &priv->tx_contexts[i];
+ break;
+ }
+ }
+
+ /* May never happen! When this happens we'd more URBs in flight as
+ * allowed (MAX_TX_URBS).
+ */
+ if (!context)
+ goto nofreecontext;
+
+ context->priv = priv;
+ context->echo_index = i;
+ context->dlc = cf->can_dlc;
+
+ usb_fill_bulk_urb(urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_TX),
+ buf, size, usb_8dev_write_bulk_callback, context);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usb_anchor_urb(urb, &priv->tx_submitted);
+
+ can_put_echo_skb(skb, netdev, context->echo_index);
+
+ atomic_inc(&priv->active_tx_urbs);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (unlikely(err))
+ goto failed;
+ else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
+ /* Slow down tx path */
+ netif_stop_queue(netdev);
+
+ /* Release our reference to this URB, the USB core will eventually free
+ * it entirely.
+ */
+ usb_free_urb(urb);
+
+ return NETDEV_TX_OK;
+
+nofreecontext:
+ usb_unanchor_urb(urb);
+ usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
+
+ netdev_warn(netdev, "couldn't find free context");
+
+ return NETDEV_TX_BUSY;
+
+failed:
+ can_free_echo_skb(netdev, context->echo_index);
+
+ usb_unanchor_urb(urb);
+ usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
+
+ atomic_dec(&priv->active_tx_urbs);
+
+ if (err == -ENODEV)
+ netif_device_detach(netdev);
+ else
+ netdev_warn(netdev, "failed tx_urb %d\n", err);
+
+nomembuf:
+ usb_free_urb(urb);
+
+nomem:
+ dev_kfree_skb(skb);
+ stats->tx_dropped++;
+
+ return NETDEV_TX_OK;
+}
+
+static int usb_8dev_get_berr_counter(const struct net_device *netdev,
+ struct can_berr_counter *bec)
+{
+ struct usb_8dev_priv *priv = netdev_priv(netdev);
+
+ bec->txerr = priv->bec.txerr;
+ bec->rxerr = priv->bec.rxerr;
+
+ return 0;
+}
+
+/* Start USB device */
+static int usb_8dev_start(struct usb_8dev_priv *priv)
+{
+ struct net_device *netdev = priv->netdev;
+ int err, i;
+
+ for (i = 0; i < MAX_RX_URBS; i++) {
+ struct urb *urb = NULL;
+ u8 *buf;
+
+ /* create a URB, and a buffer for it */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ netdev_err(netdev, "No memory left for URBs\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buf) {
+ netdev_err(netdev, "No memory left for USB buffer\n");
+ usb_free_urb(urb);
+ err = -ENOMEM;
+ break;
+ }
+
+ usb_fill_bulk_urb(urb, priv->udev,
+ usb_rcvbulkpipe(priv->udev,
+ USB_8DEV_ENDP_DATA_RX),
+ buf, RX_BUFFER_SIZE,
+ usb_8dev_read_bulk_callback, priv);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usb_anchor_urb(urb, &priv->rx_submitted);
+
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err) {
+ usb_unanchor_urb(urb);
+ usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf,
+ urb->transfer_dma);
+ break;
+ }
+
+ /* Drop reference, USB core will take care of freeing it */
+ usb_free_urb(urb);
+ }
+
+ /* Did we submit any URBs */
+ if (i == 0) {
+ netdev_warn(netdev, "couldn't setup read URBs\n");
+ return err;
+ }
+
+ /* Warn if we've couldn't transmit all the URBs */
+ if (i < MAX_RX_URBS)
+ netdev_warn(netdev, "rx performance may be slow\n");
+
+ err = usb_8dev_cmd_open(priv);
+ if (err)
+ goto failed;
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ return 0;
+
+failed:
+ if (err == -ENODEV)
+ netif_device_detach(priv->netdev);
+
+ netdev_warn(netdev, "couldn't submit control: %d\n", err);
+
+ return err;
+}
+
+/* Open USB device */
+static int usb_8dev_open(struct net_device *netdev)
+{
+ struct usb_8dev_priv *priv = netdev_priv(netdev);
+ int err;
+
+ /* common open */
+ err = open_candev(netdev);
+ if (err)
+ return err;
+
+ can_led_event(netdev, CAN_LED_EVENT_OPEN);
+
+ /* finally start device */
+ err = usb_8dev_start(priv);
+ if (err) {
+ if (err == -ENODEV)
+ netif_device_detach(priv->netdev);
+
+ netdev_warn(netdev, "couldn't start device: %d\n",
+ err);
+
+ close_candev(netdev);
+
+ return err;
+ }
+
+ netif_start_queue(netdev);
+
+ return 0;
+}
+
+static void unlink_all_urbs(struct usb_8dev_priv *priv)
+{
+ int i;
+
+ usb_kill_anchored_urbs(&priv->rx_submitted);
+
+ usb_kill_anchored_urbs(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_urbs, 0);
+
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+}
+
+/* Close USB device */
+static int usb_8dev_close(struct net_device *netdev)
+{
+ struct usb_8dev_priv *priv = netdev_priv(netdev);
+ int err = 0;
+
+ /* Send CLOSE command to CAN controller */
+ err = usb_8dev_cmd_close(priv);
+ if (err)
+ netdev_warn(netdev, "couldn't stop device");
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ netif_stop_queue(netdev);
+
+ /* Stop polling */
+ unlink_all_urbs(priv);
+
+ close_candev(netdev);
+
+ can_led_event(netdev, CAN_LED_EVENT_STOP);
+
+ return err;
+}
+
+static const struct net_device_ops usb_8dev_netdev_ops = {
+ .ndo_open = usb_8dev_open,
+ .ndo_stop = usb_8dev_close,
+ .ndo_start_xmit = usb_8dev_start_xmit,
+};
+
+static const struct can_bittiming_const usb_8dev_bittiming_const = {
+ .name = "usb_8dev",
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
+/* Probe USB device
+ *
+ * Check device and firmware.
+ * Set supported modes and bittiming constants.
+ * Allocate some memory.
+ */
+static int usb_8dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct net_device *netdev;
+ struct usb_8dev_priv *priv;
+ int i, err = -ENOMEM;
+ u32 version;
+ char buf[18];
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+
+ /* product id looks strange, better we also check iProduct string */
+ if (usb_string(usbdev, usbdev->descriptor.iProduct, buf,
+ sizeof(buf)) > 0 && strcmp(buf, "USB2CAN converter")) {
+ dev_info(&usbdev->dev, "ignoring: not an USB2CAN converter\n");
+ return -ENODEV;
+ }
+
+ netdev = alloc_candev(sizeof(struct usb_8dev_priv), MAX_TX_URBS);
+ if (!netdev) {
+ dev_err(&intf->dev, "Couldn't alloc candev\n");
+ return -ENOMEM;
+ }
+
+ priv = netdev_priv(netdev);
+
+ priv->udev = usbdev;
+ priv->netdev = netdev;
+
+ priv->can.state = CAN_STATE_STOPPED;
+ priv->can.clock.freq = USB_8DEV_ABP_CLOCK;
+ priv->can.bittiming_const = &usb_8dev_bittiming_const;
+ priv->can.do_set_mode = usb_8dev_set_mode;
+ priv->can.do_get_berr_counter = usb_8dev_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_ONE_SHOT;
+
+ netdev->netdev_ops = &usb_8dev_netdev_ops;
+
+ netdev->flags |= IFF_ECHO; /* we support local echo */
+
+ init_usb_anchor(&priv->rx_submitted);
+
+ init_usb_anchor(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_urbs, 0);
+
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+
+ priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg),
+ GFP_KERNEL);
+ if (!priv->cmd_msg_buffer)
+ goto cleanup_candev;
+
+ usb_set_intfdata(intf, priv);
+
+ SET_NETDEV_DEV(netdev, &intf->dev);
+
+ mutex_init(&priv->usb_8dev_cmd_lock);
+
+ err = register_candev(netdev);
+ if (err) {
+ netdev_err(netdev,
+ "couldn't register CAN device: %d\n", err);
+ goto cleanup_cmd_msg_buffer;
+ }
+
+ err = usb_8dev_cmd_version(priv, &version);
+ if (err) {
+ netdev_err(netdev, "can't get firmware version\n");
+ goto cleanup_cmd_msg_buffer;
+ } else {
+ netdev_info(netdev,
+ "firmware: %d.%d, hardware: %d.%d\n",
+ (version>>24) & 0xff, (version>>16) & 0xff,
+ (version>>8) & 0xff, version & 0xff);
+ }
+
+ devm_can_led_init(netdev);
+
+ return 0;
+
+cleanup_cmd_msg_buffer:
+ kfree(priv->cmd_msg_buffer);
+
+cleanup_candev:
+ free_candev(netdev);
+
+ return err;
+
+}
+
+/* Called by the usb core when driver is unloaded or device is removed */
+static void usb_8dev_disconnect(struct usb_interface *intf)
+{
+ struct usb_8dev_priv *priv = usb_get_intfdata(intf);
+
+ usb_set_intfdata(intf, NULL);
+
+ if (priv) {
+ netdev_info(priv->netdev, "device disconnected\n");
+
+ unregister_netdev(priv->netdev);
+ free_candev(priv->netdev);
+
+ unlink_all_urbs(priv);
+ }
+
+}
+
+static struct usb_driver usb_8dev_driver = {
+ .name = "usb_8dev",
+ .probe = usb_8dev_probe,
+ .disconnect = usb_8dev_disconnect,
+ .id_table = usb_8dev_table,
+};
+
+module_usb_driver(usb_8dev_driver);
+
+MODULE_AUTHOR("Bernd Krumboeck <krumboeck@universalnet.at>");
+MODULE_DESCRIPTION("CAN driver for 8 devices USB2CAN interfaces");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 021d69c5d9bc..29e272cc7a98 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -1448,10 +1448,10 @@ static int e100_set_settings(struct net_device *dev,
static void e100_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strncpy(info->driver, "ETRAX 100LX", sizeof(info->driver) - 1);
- strncpy(info->version, "$Revision: 1.31 $", sizeof(info->version) - 1);
- strncpy(info->fw_version, "N/A", sizeof(info->fw_version) - 1);
- strncpy(info->bus_info, "N/A", sizeof(info->bus_info) - 1);
+ strlcpy(info->driver, "ETRAX 100LX", sizeof(info->driver));
+ strlcpy(info->version, "$Revision: 1.31 $", sizeof(info->version));
+ strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+ strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
}
static int e100_nway_reset(struct net_device *dev)
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c
index 325391d19bad..7a54ec04b418 100644
--- a/drivers/net/dsa/mv88e6060.c
+++ b/drivers/net/dsa/mv88e6060.c
@@ -8,6 +8,8 @@
* (at your option) any later version.
*/
+#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -66,36 +68,30 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
{
int i;
int ret;
+ unsigned long timeout;
- /*
- * Set all ports to the disabled state.
- */
+ /* Set all ports to the disabled state. */
for (i = 0; i < 6; i++) {
ret = REG_READ(REG_PORT(i), 0x04);
REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
}
- /*
- * Wait for transmit queues to drain.
- */
- msleep(2);
+ /* Wait for transmit queues to drain. */
+ usleep_range(2000, 4000);
- /*
- * Reset the switch.
- */
+ /* Reset the switch. */
REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
- /*
- * Wait up to one second for reset to complete.
- */
- for (i = 0; i < 1000; i++) {
+ /* Wait up to one second for reset to complete. */
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
ret = REG_READ(REG_GLOBAL, 0x00);
if ((ret & 0x8000) == 0x0000)
break;
- msleep(1);
+ usleep_range(1000, 2000);
}
- if (i == 1000)
+ if (time_after(jiffies, timeout))
return -ETIMEDOUT;
return 0;
@@ -103,15 +99,13 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
static int mv88e6060_setup_global(struct dsa_switch *ds)
{
- /*
- * Disable discarding of frames with excessive collisions,
+ /* Disable discarding of frames with excessive collisions,
* set the maximum frame size to 1536 bytes, and mask all
* interrupt sources.
*/
REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
- /*
- * Enable automatic address learning, set the address
+ /* Enable automatic address learning, set the address
* database size to 1024 entries, and set the default aging
* time to 5 minutes.
*/
@@ -124,16 +118,14 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
{
int addr = REG_PORT(p);
- /*
- * Do not force flow control, disable Ingress and Egress
+ /* Do not force flow control, disable Ingress and Egress
* Header tagging, disable VLAN tunneling, and set the port
* state to Forwarding. Additionally, if this is the CPU
* port, enable Ingress and Egress Trailer tagging mode.
*/
REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003);
- /*
- * Port based VLAN map: give each port its own address
+ /* Port based VLAN map: give each port its own address
* database, allow the CPU port to talk to each of the 'real'
* ports, and allow each of the 'real' ports to only talk to
* the CPU port.
@@ -144,8 +136,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
ds->phys_port_mask :
(1 << ds->dst->cpu_port)));
- /*
- * Port Association Vector: when learning source addresses
+ /* Port Association Vector: when learning source addresses
* of packets, add the address to the address database using
* a port bitmap that has only the bit for this port set and
* the other bits clear.
@@ -245,7 +236,7 @@ static void mv88e6060_poll_link(struct dsa_switch *ds)
if (!link) {
if (netif_carrier_ok(dev)) {
- printk(KERN_INFO "%s: link down\n", dev->name);
+ netdev_info(dev, "link down\n");
netif_carrier_off(dev);
}
continue;
@@ -256,10 +247,11 @@ static void mv88e6060_poll_link(struct dsa_switch *ds)
fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
if (!netif_carrier_ok(dev)) {
- printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
- "flow control %sabled\n", dev->name,
- speed, duplex ? "full" : "half",
- fc ? "en" : "dis");
+ netdev_info(dev,
+ "link up, %d Mb/s, %s duplex, flow control %sabled\n",
+ speed,
+ duplex ? "full" : "half",
+ fc ? "en" : "dis");
netif_carrier_on(dev);
}
}
diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c
index c17c75b9f531..41ee5b6ae917 100644
--- a/drivers/net/dsa/mv88e6123_61_65.c
+++ b/drivers/net/dsa/mv88e6123_61_65.c
@@ -8,6 +8,8 @@
* (at your option) any later version.
*/
+#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -50,36 +52,30 @@ static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds)
{
int i;
int ret;
+ unsigned long timeout;
- /*
- * Set all ports to the disabled state.
- */
+ /* Set all ports to the disabled state. */
for (i = 0; i < 8; i++) {
ret = REG_READ(REG_PORT(i), 0x04);
REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
}
- /*
- * Wait for transmit queues to drain.
- */
- msleep(2);
+ /* Wait for transmit queues to drain. */
+ usleep_range(2000, 4000);
- /*
- * Reset the switch.
- */
+ /* Reset the switch. */
REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
- /*
- * Wait up to one second for reset to complete.
- */
- for (i = 0; i < 1000; i++) {
+ /* Wait up to one second for reset to complete. */
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
ret = REG_READ(REG_GLOBAL, 0x00);
if ((ret & 0xc800) == 0xc800)
break;
- msleep(1);
+ usleep_range(1000, 2000);
}
- if (i == 1000)
+ if (time_after(jiffies, timeout))
return -ETIMEDOUT;
return 0;
@@ -90,54 +86,45 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
int ret;
int i;
- /*
- * Disable the PHY polling unit (since there won't be any
+ /* Disable the PHY polling unit (since there won't be any
* external PHYs to poll), don't discard packets with
* excessive collisions, and mask all interrupt sources.
*/
REG_WRITE(REG_GLOBAL, 0x04, 0x0000);
- /*
- * Set the default address aging time to 5 minutes, and
+ /* Set the default address aging time to 5 minutes, and
* enable address learn messages to be sent to all message
* ports.
*/
REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
- /*
- * Configure the priority mapping registers.
- */
+ /* Configure the priority mapping registers. */
ret = mv88e6xxx_config_prio(ds);
if (ret < 0)
return ret;
- /*
- * Configure the upstream port, and configure the upstream
+ /* Configure the upstream port, and configure the upstream
* port as the port to which ingress and egress monitor frames
* are to be sent.
*/
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
- /*
- * Disable remote management for now, and set the switch's
+ /* Disable remote management for now, and set the switch's
* DSA device number.
*/
REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
- /*
- * Send all frames with destination addresses matching
+ /* Send all frames with destination addresses matching
* 01:80:c2:00:00:2x to the CPU port.
*/
REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
- /*
- * Send all frames with destination addresses matching
+ /* Send all frames with destination addresses matching
* 01:80:c2:00:00:0x to the CPU port.
*/
REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
- /*
- * Disable the loopback filter, disable flow control
+ /* Disable the loopback filter, disable flow control
* messages, disable flood broadcast override, disable
* removing of provider tags, disable ATU age violation
* interrupts, disable tag flow control, force flow
@@ -146,9 +133,7 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
*/
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
- /*
- * Program the DSA routing table.
- */
+ /* Program the DSA routing table. */
for (i = 0; i < 32; i++) {
int nexthop;
@@ -159,33 +144,24 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
}
- /*
- * Clear all trunk masks.
- */
+ /* Clear all trunk masks. */
for (i = 0; i < 8; i++)
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
- /*
- * Clear all trunk mappings.
- */
+ /* Clear all trunk mappings. */
for (i = 0; i < 16; i++)
REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
- /*
- * Disable ingress rate limiting by resetting all ingress
+ /* Disable ingress rate limiting by resetting all ingress
* rate limit registers to their initial state.
*/
for (i = 0; i < 6; i++)
REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
- /*
- * Initialise cross-chip port VLAN table to reset defaults.
- */
+ /* Initialise cross-chip port VLAN table to reset defaults. */
REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
- /*
- * Clear the priority override table.
- */
+ /* Clear the priority override table. */
for (i = 0; i < 16; i++)
REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
@@ -199,8 +175,7 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
int addr = REG_PORT(p);
u16 val;
- /*
- * MAC Forcing register: don't force link, speed, duplex
+ /* MAC Forcing register: don't force link, speed, duplex
* or flow control state to any particular values on physical
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
* full duplex.
@@ -210,15 +185,13 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
else
REG_WRITE(addr, 0x01, 0x0003);
- /*
- * Do not limit the period of time that this port can be
+ /* Do not limit the period of time that this port can be
* paused for by the remote end or the period of time that
* this port can pause the remote end.
*/
REG_WRITE(addr, 0x02, 0x0000);
- /*
- * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
+ /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
* disable Header mode, enable IGMP/MLD snooping, disable VLAN
* tunneling, determine priority by looking at 802.1p and IP
* priority fields (IP prio has precedence), and set STP state
@@ -245,14 +218,12 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
val |= 0x000c;
REG_WRITE(addr, 0x04, val);
- /*
- * Port Control 1: disable trunking. Also, if this is the
+ /* Port Control 1: disable trunking. Also, if this is the
* CPU port, enable learn messages to be sent to this port.
*/
REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
- /*
- * Port based VLAN map: give each port its own address
+ /* Port based VLAN map: give each port its own address
* database, allow the CPU port to talk to each of the 'real'
* ports, and allow each of the 'real' ports to only talk to
* the upstream port.
@@ -264,14 +235,12 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
val |= 1 << dsa_upstream_port(ds);
REG_WRITE(addr, 0x06, val);
- /*
- * Default VLAN ID and priority: don't set a default VLAN
+ /* Default VLAN ID and priority: don't set a default VLAN
* ID, and set the default packet priority to zero.
*/
REG_WRITE(addr, 0x07, 0x0000);
- /*
- * Port Control 2: don't force a good FCS, set the maximum
+ /* Port Control 2: don't force a good FCS, set the maximum
* frame size to 10240 bytes, don't let the switch add or
* strip 802.1q tags, don't discard tagged or untagged frames
* on this port, do a destination address lookup on all
@@ -281,48 +250,36 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
*/
REG_WRITE(addr, 0x08, 0x2080);
- /*
- * Egress rate control: disable egress rate control.
- */
+ /* Egress rate control: disable egress rate control. */
REG_WRITE(addr, 0x09, 0x0001);
- /*
- * Egress rate control 2: disable egress rate control.
- */
+ /* Egress rate control 2: disable egress rate control. */
REG_WRITE(addr, 0x0a, 0x0000);
- /*
- * Port Association Vector: when learning source addresses
+ /* Port Association Vector: when learning source addresses
* of packets, add the address to the address database using
* a port bitmap that has only the bit for this port set and
* the other bits clear.
*/
REG_WRITE(addr, 0x0b, 1 << p);
- /*
- * Port ATU control: disable limiting the number of address
+ /* Port ATU control: disable limiting the number of address
* database entries that this port is allowed to use.
*/
REG_WRITE(addr, 0x0c, 0x0000);
- /*
- * Priorit Override: disable DA, SA and VTU priority override.
- */
+ /* Priority Override: disable DA, SA and VTU priority override. */
REG_WRITE(addr, 0x0d, 0x0000);
- /*
- * Port Ethertype: use the Ethertype DSA Ethertype value.
- */
+ /* Port Ethertype: use the Ethertype DSA Ethertype value. */
REG_WRITE(addr, 0x0f, ETH_P_EDSA);
- /*
- * Tag Remap: use an identity 802.1p prio -> switch prio
+ /* Tag Remap: use an identity 802.1p prio -> switch prio
* mapping.
*/
REG_WRITE(addr, 0x18, 0x3210);
- /*
- * Tag Remap 2: use an identity 802.1p prio -> switch prio
+ /* Tag Remap 2: use an identity 802.1p prio -> switch prio
* mapping.
*/
REG_WRITE(addr, 0x19, 0x7654);
diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c
index 55888b06d8b4..dadfafba64e9 100644
--- a/drivers/net/dsa/mv88e6131.c
+++ b/drivers/net/dsa/mv88e6131.c
@@ -8,6 +8,8 @@
* (at your option) any later version.
*/
+#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -15,9 +17,7 @@
#include <net/dsa.h>
#include "mv88e6xxx.h"
-/*
- * Switch product IDs
- */
+/* Switch product IDs */
#define ID_6085 0x04a0
#define ID_6095 0x0950
#define ID_6131 0x1060
@@ -44,36 +44,30 @@ static int mv88e6131_switch_reset(struct dsa_switch *ds)
{
int i;
int ret;
+ unsigned long timeout;
- /*
- * Set all ports to the disabled state.
- */
+ /* Set all ports to the disabled state. */
for (i = 0; i < 11; i++) {
ret = REG_READ(REG_PORT(i), 0x04);
REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
}
- /*
- * Wait for transmit queues to drain.
- */
- msleep(2);
+ /* Wait for transmit queues to drain. */
+ usleep_range(2000, 4000);
- /*
- * Reset the switch.
- */
+ /* Reset the switch. */
REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
- /*
- * Wait up to one second for reset to complete.
- */
- for (i = 0; i < 1000; i++) {
+ /* Wait up to one second for reset to complete. */
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
ret = REG_READ(REG_GLOBAL, 0x00);
if ((ret & 0xc800) == 0xc800)
break;
- msleep(1);
+ usleep_range(1000, 2000);
}
- if (i == 1000)
+ if (time_after(jiffies, timeout))
return -ETIMEDOUT;
return 0;
@@ -84,42 +78,34 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
int ret;
int i;
- /*
- * Enable the PHY polling unit, don't discard packets with
+ /* Enable the PHY polling unit, don't discard packets with
* excessive collisions, use a weighted fair queueing scheme
* to arbitrate between packet queues, set the maximum frame
* size to 1632, and mask all interrupt sources.
*/
REG_WRITE(REG_GLOBAL, 0x04, 0x4400);
- /*
- * Set the default address aging time to 5 minutes, and
+ /* Set the default address aging time to 5 minutes, and
* enable address learn messages to be sent to all message
* ports.
*/
REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
- /*
- * Configure the priority mapping registers.
- */
+ /* Configure the priority mapping registers. */
ret = mv88e6xxx_config_prio(ds);
if (ret < 0)
return ret;
- /*
- * Set the VLAN ethertype to 0x8100.
- */
+ /* Set the VLAN ethertype to 0x8100. */
REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
- /*
- * Disable ARP mirroring, and configure the upstream port as
+ /* Disable ARP mirroring, and configure the upstream port as
* the port to which ingress and egress monitor frames are to
* be sent.
*/
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
- /*
- * Disable cascade port functionality unless this device
+ /* Disable cascade port functionality unless this device
* is used in a cascade configuration, and set the switch's
* DSA device number.
*/
@@ -128,23 +114,19 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
else
REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
- /*
- * Send all frames with destination addresses matching
+ /* Send all frames with destination addresses matching
* 01:80:c2:00:00:0x to the CPU port.
*/
REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
- /*
- * Ignore removed tag data on doubly tagged packets, disable
+ /* Ignore removed tag data on doubly tagged packets, disable
* flow control messages, force flow control priority to the
* highest, and send all special multicast frames to the CPU
* port at the highest priority.
*/
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
- /*
- * Program the DSA routing table.
- */
+ /* Program the DSA routing table. */
for (i = 0; i < 32; i++) {
int nexthop;
@@ -155,20 +137,15 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
}
- /*
- * Clear all trunk masks.
- */
+ /* Clear all trunk masks. */
for (i = 0; i < 8; i++)
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff);
- /*
- * Clear all trunk mappings.
- */
+ /* Clear all trunk mappings. */
for (i = 0; i < 16; i++)
REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
- /*
- * Force the priority of IGMP/MLD snoop frames and ARP frames
+ /* Force the priority of IGMP/MLD snoop frames and ARP frames
* to the highest setting.
*/
REG_WRITE(REG_GLOBAL2, 0x0f, 0x00ff);
@@ -182,8 +159,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
int addr = REG_PORT(p);
u16 val;
- /*
- * MAC Forcing register: don't force link, speed, duplex
+ /* MAC Forcing register: don't force link, speed, duplex
* or flow control state to any particular values on physical
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
* (100 Mb/s on 6085) full duplex.
@@ -196,8 +172,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
else
REG_WRITE(addr, 0x01, 0x0003);
- /*
- * Port Control: disable Core Tag, disable Drop-on-Lock,
+ /* Port Control: disable Core Tag, disable Drop-on-Lock,
* transmit frames unmodified, disable Header mode,
* enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
* tunneling, determine priority by looking at 802.1p and
@@ -214,8 +189,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
val = 0x0433;
if (p == dsa_upstream_port(ds)) {
val |= 0x0104;
- /*
- * On 6085, unknown multicast forward is controlled
+ /* On 6085, unknown multicast forward is controlled
* here rather than in Port Control 2 register.
*/
if (ps->id == ID_6085)
@@ -225,14 +199,12 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
val |= 0x0100;
REG_WRITE(addr, 0x04, val);
- /*
- * Port Control 1: disable trunking. Also, if this is the
+ /* Port Control 1: disable trunking. Also, if this is the
* CPU port, enable learn messages to be sent to this port.
*/
REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
- /*
- * Port based VLAN map: give each port its own address
+ /* Port based VLAN map: give each port its own address
* database, allow the CPU port to talk to each of the 'real'
* ports, and allow each of the 'real' ports to only talk to
* the upstream port.
@@ -244,14 +216,12 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
val |= 1 << dsa_upstream_port(ds);
REG_WRITE(addr, 0x06, val);
- /*
- * Default VLAN ID and priority: don't set a default VLAN
+ /* Default VLAN ID and priority: don't set a default VLAN
* ID, and set the default packet priority to zero.
*/
REG_WRITE(addr, 0x07, 0x0000);
- /*
- * Port Control 2: don't force a good FCS, don't use
+ /* Port Control 2: don't force a good FCS, don't use
* VLAN-based, source address-based or destination
* address-based priority overrides, don't let the switch
* add or strip 802.1q tags, don't discard tagged or
@@ -264,8 +234,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
* forwarding of unknown multicast addresses.
*/
if (ps->id == ID_6085)
- /*
- * on 6085, bits 3:0 are reserved, bit 6 control ARP
+ /* on 6085, bits 3:0 are reserved, bit 6 control ARP
* mirroring, and multicast forward is handled in
* Port Control register.
*/
@@ -277,32 +246,25 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
REG_WRITE(addr, 0x08, val);
}
- /*
- * Rate Control: disable ingress rate limiting.
- */
+ /* Rate Control: disable ingress rate limiting. */
REG_WRITE(addr, 0x09, 0x0000);
- /*
- * Rate Control 2: disable egress rate limiting.
- */
+ /* Rate Control 2: disable egress rate limiting. */
REG_WRITE(addr, 0x0a, 0x0000);
- /*
- * Port Association Vector: when learning source addresses
+ /* Port Association Vector: when learning source addresses
* of packets, add the address to the address database using
* a port bitmap that has only the bit for this port set and
* the other bits clear.
*/
REG_WRITE(addr, 0x0b, 1 << p);
- /*
- * Tag Remap: use an identity 802.1p prio -> switch prio
+ /* Tag Remap: use an identity 802.1p prio -> switch prio
* mapping.
*/
REG_WRITE(addr, 0x18, 0x3210);
- /*
- * Tag Remap 2: use an identity 802.1p prio -> switch prio
+ /* Tag Remap 2: use an identity 802.1p prio -> switch prio
* mapping.
*/
REG_WRITE(addr, 0x19, 0x7654);
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index a2c62c2f30ee..17314ed9456d 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -8,6 +8,8 @@
* (at your option) any later version.
*/
+#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -15,8 +17,7 @@
#include <net/dsa.h>
#include "mv88e6xxx.h"
-/*
- * If the switch's ADDR[4:0] strap pins are strapped to zero, it will
+/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
* use all 32 SMI bus addresses on its SMI bus, and all switch registers
* will be directly accessible on some {device address,register address}
* pair. If the ADDR[4:0] pins are not strapped to zero, the switch
@@ -48,30 +49,22 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
if (sw_addr == 0)
return mdiobus_read(bus, addr, reg);
- /*
- * Wait for the bus to become free.
- */
+ /* Wait for the bus to become free. */
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
if (ret < 0)
return ret;
- /*
- * Transmit the read command.
- */
+ /* Transmit the read command. */
ret = mdiobus_write(bus, sw_addr, 0, 0x9800 | (addr << 5) | reg);
if (ret < 0)
return ret;
- /*
- * Wait for the read command to complete.
- */
+ /* Wait for the read command to complete. */
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
if (ret < 0)
return ret;
- /*
- * Read the data.
- */
+ /* Read the data. */
ret = mdiobus_read(bus, sw_addr, 1);
if (ret < 0)
return ret;
@@ -100,30 +93,22 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
if (sw_addr == 0)
return mdiobus_write(bus, addr, reg, val);
- /*
- * Wait for the bus to become free.
- */
+ /* Wait for the bus to become free. */
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
if (ret < 0)
return ret;
- /*
- * Transmit the data to write.
- */
+ /* Transmit the data to write. */
ret = mdiobus_write(bus, sw_addr, 1, val);
if (ret < 0)
return ret;
- /*
- * Transmit the write command.
- */
+ /* Transmit the write command. */
ret = mdiobus_write(bus, sw_addr, 0, 0x9400 | (addr << 5) | reg);
if (ret < 0)
return ret;
- /*
- * Wait for the write command to complete.
- */
+ /* Wait for the write command to complete. */
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
if (ret < 0)
return ret;
@@ -146,9 +131,7 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
int mv88e6xxx_config_prio(struct dsa_switch *ds)
{
- /*
- * Configure the IP ToS mapping registers.
- */
+ /* Configure the IP ToS mapping registers. */
REG_WRITE(REG_GLOBAL, 0x10, 0x0000);
REG_WRITE(REG_GLOBAL, 0x11, 0x0000);
REG_WRITE(REG_GLOBAL, 0x12, 0x5555);
@@ -158,9 +141,7 @@ int mv88e6xxx_config_prio(struct dsa_switch *ds)
REG_WRITE(REG_GLOBAL, 0x16, 0xffff);
REG_WRITE(REG_GLOBAL, 0x17, 0xffff);
- /*
- * Configure the IEEE 802.1p priority mapping register.
- */
+ /* Configure the IEEE 802.1p priority mapping register. */
REG_WRITE(REG_GLOBAL, 0x18, 0xfa41);
return 0;
@@ -183,14 +164,10 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
for (i = 0; i < 6; i++) {
int j;
- /*
- * Write the MAC address byte.
- */
+ /* Write the MAC address byte. */
REG_WRITE(REG_GLOBAL2, 0x0d, 0x8000 | (i << 8) | addr[i]);
- /*
- * Wait for the write to complete.
- */
+ /* Wait for the write to complete. */
for (j = 0; j < 16; j++) {
ret = REG_READ(REG_GLOBAL2, 0x0d);
if ((ret & 0x8000) == 0)
@@ -221,16 +198,17 @@ int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val)
static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
{
int ret;
- int i;
+ unsigned long timeout;
ret = REG_READ(REG_GLOBAL, 0x04);
REG_WRITE(REG_GLOBAL, 0x04, ret & ~0x4000);
- for (i = 0; i < 1000; i++) {
- ret = REG_READ(REG_GLOBAL, 0x00);
- msleep(1);
- if ((ret & 0xc000) != 0xc000)
- return 0;
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
+ ret = REG_READ(REG_GLOBAL, 0x00);
+ usleep_range(1000, 2000);
+ if ((ret & 0xc000) != 0xc000)
+ return 0;
}
return -ETIMEDOUT;
@@ -239,16 +217,17 @@ static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
{
int ret;
- int i;
+ unsigned long timeout;
ret = REG_READ(REG_GLOBAL, 0x04);
REG_WRITE(REG_GLOBAL, 0x04, ret | 0x4000);
- for (i = 0; i < 1000; i++) {
- ret = REG_READ(REG_GLOBAL, 0x00);
- msleep(1);
- if ((ret & 0xc000) == 0xc000)
- return 0;
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
+ ret = REG_READ(REG_GLOBAL, 0x00);
+ usleep_range(1000, 2000);
+ if ((ret & 0xc000) == 0xc000)
+ return 0;
}
return -ETIMEDOUT;
@@ -260,11 +239,11 @@ static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
if (mutex_trylock(&ps->ppu_mutex)) {
- struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
+ struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
- if (mv88e6xxx_ppu_enable(ds) == 0)
- ps->ppu_disabled = 0;
- mutex_unlock(&ps->ppu_mutex);
+ if (mv88e6xxx_ppu_enable(ds) == 0)
+ ps->ppu_disabled = 0;
+ mutex_unlock(&ps->ppu_mutex);
}
}
@@ -282,22 +261,21 @@ static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
mutex_lock(&ps->ppu_mutex);
- /*
- * If the PHY polling unit is enabled, disable it so that
+ /* If the PHY polling unit is enabled, disable it so that
* we can access the PHY registers. If it was already
* disabled, cancel the timer that is going to re-enable
* it.
*/
if (!ps->ppu_disabled) {
- ret = mv88e6xxx_ppu_disable(ds);
- if (ret < 0) {
- mutex_unlock(&ps->ppu_mutex);
- return ret;
- }
- ps->ppu_disabled = 1;
+ ret = mv88e6xxx_ppu_disable(ds);
+ if (ret < 0) {
+ mutex_unlock(&ps->ppu_mutex);
+ return ret;
+ }
+ ps->ppu_disabled = 1;
} else {
- del_timer(&ps->ppu_timer);
- ret = 0;
+ del_timer(&ps->ppu_timer);
+ ret = 0;
}
return ret;
@@ -307,9 +285,7 @@ static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
- /*
- * Schedule a timer to re-enable the PHY polling unit.
- */
+ /* Schedule a timer to re-enable the PHY polling unit. */
mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
mutex_unlock(&ps->ppu_mutex);
}
@@ -331,8 +307,8 @@ int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum)
ret = mv88e6xxx_ppu_access_get(ds);
if (ret >= 0) {
- ret = mv88e6xxx_reg_read(ds, addr, regnum);
- mv88e6xxx_ppu_access_put(ds);
+ ret = mv88e6xxx_reg_read(ds, addr, regnum);
+ mv88e6xxx_ppu_access_put(ds);
}
return ret;
@@ -345,8 +321,8 @@ int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
ret = mv88e6xxx_ppu_access_get(ds);
if (ret >= 0) {
- ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
- mv88e6xxx_ppu_access_put(ds);
+ ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
+ mv88e6xxx_ppu_access_put(ds);
}
return ret;
@@ -380,7 +356,7 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds)
if (!link) {
if (netif_carrier_ok(dev)) {
- printk(KERN_INFO "%s: link down\n", dev->name);
+ netdev_info(dev, "link down\n");
netif_carrier_off(dev);
}
continue;
@@ -404,10 +380,11 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds)
fc = (port_status & 0x8000) ? 1 : 0;
if (!netif_carrier_ok(dev)) {
- printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
- "flow control %sabled\n", dev->name,
- speed, duplex ? "full" : "half",
- fc ? "en" : "dis");
+ netdev_info(dev,
+ "link up, %d Mb/s, %s duplex, flow control %sabled\n",
+ speed,
+ duplex ? "full" : "half",
+ fc ? "en" : "dis");
netif_carrier_on(dev);
}
}
@@ -431,14 +408,10 @@ static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
{
int ret;
- /*
- * Snapshot the hardware statistics counters for this port.
- */
+ /* Snapshot the hardware statistics counters for this port. */
REG_WRITE(REG_GLOBAL, 0x1d, 0xdc00 | port);
- /*
- * Wait for the snapshotting to complete.
- */
+ /* Wait for the snapshotting to complete. */
ret = mv88e6xxx_stats_wait(ds);
if (ret < 0)
return ret;
@@ -502,9 +475,7 @@ void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
return;
}
- /*
- * Read each of the counters.
- */
+ /* Read each of the counters. */
for (i = 0; i < nr_stats; i++) {
struct mv88e6xxx_hw_stat *s = stats + i;
u32 low;
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index fc2cd7b90e8d..911ede58dd12 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -16,16 +16,14 @@
#define REG_GLOBAL2 0x1c
struct mv88e6xxx_priv_state {
- /*
- * When using multi-chip addressing, this mutex protects
+ /* When using multi-chip addressing, this mutex protects
* access to the indirect access registers. (In single-chip
* mode, this mutex is effectively useless.)
*/
struct mutex smi_mutex;
#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
- /*
- * Handles automatic disabling and re-enabling of the PHY
+ /* Handles automatic disabling and re-enabling of the PHY
* polling unit.
*/
struct mutex ppu_mutex;
@@ -34,8 +32,7 @@ struct mv88e6xxx_priv_state {
struct timer_list ppu_timer;
#endif
- /*
- * This mutex serialises access to the statistics unit.
+ /* This mutex serialises access to the statistics unit.
* Hold this mutex over snapshot + dump sequences.
*/
struct mutex stats_mutex;
@@ -52,7 +49,7 @@ struct mv88e6xxx_hw_stat {
int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg);
int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg);
int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
- int reg, u16 val);
+ int reg, u16 val);
int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val);
int mv88e6xxx_config_prio(struct dsa_switch *ds);
int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr);
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index c260af5411d0..42aa54af6842 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -100,6 +100,15 @@ static void dummy_dev_uninit(struct net_device *dev)
free_percpu(dev->dstats);
}
+static int dummy_change_carrier(struct net_device *dev, bool new_carrier)
+{
+ if (new_carrier)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
+ return 0;
+}
+
static const struct net_device_ops dummy_netdev_ops = {
.ndo_init = dummy_dev_init,
.ndo_uninit = dummy_dev_uninit,
@@ -108,6 +117,7 @@ static const struct net_device_ops dummy_netdev_ops = {
.ndo_set_rx_mode = set_multicast_list,
.ndo_set_mac_address = eth_mac_addr,
.ndo_get_stats64 = dummy_get_stats64,
+ .ndo_change_carrier = dummy_change_carrier,
};
static void dummy_setup(struct net_device *dev)
diff --git a/drivers/net/ethernet/3com/3c501.c b/drivers/net/ethernet/3com/3c501.c
deleted file mode 100644
index 2038eaabaea4..000000000000
--- a/drivers/net/ethernet/3com/3c501.c
+++ /dev/null
@@ -1,896 +0,0 @@
-/* 3c501.c: A 3Com 3c501 Ethernet driver for Linux. */
-/*
- Written 1992,1993,1994 Donald Becker
-
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used and
- distributed according to the terms of the GNU General Public License,
- incorporated herein by reference.
-
- This is a device driver for the 3Com Etherlink 3c501.
- Do not purchase this card, even as a joke. It's performance is horrible,
- and it breaks in many ways.
-
- The original author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- Fixed (again!) the missing interrupt locking on TX/RX shifting.
- Alan Cox <alan@lxorguk.ukuu.org.uk>
-
- Removed calls to init_etherdev since they are no longer needed, and
- cleaned up modularization just a bit. The driver still allows only
- the default address for cards when loaded as a module, but that's
- really less braindead than anyone using a 3c501 board. :)
- 19950208 (invid@msen.com)
-
- Added traps for interrupts hitting the window as we clear and TX load
- the board. Now getting 150K/second FTP with a 3c501 card. Still playing
- with a TX-TX optimisation to see if we can touch 180-200K/second as seems
- theoretically maximum.
- 19950402 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
- Cleaned up for 2.3.x because we broke SMP now.
- 20000208 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
- Check up pass for 2.5. Nothing significant changed
- 20021009 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
- Fixed zero fill corner case
- 20030104 Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-
- For the avoidance of doubt the "preferred form" of this code is one which
- is in an open non patent encumbered format. Where cryptographic key signing
- forms part of the process of creating an executable the information
- including keys needed to generate an equivalently functional executable
- are deemed to be part of the source code.
-
-*/
-
-
-/**
- * DOC: 3c501 Card Notes
- *
- * Some notes on this thing if you have to hack it. [Alan]
- *
- * Some documentation is available from 3Com. Due to the boards age
- * standard responses when you ask for this will range from 'be serious'
- * to 'give it to a museum'. The documentation is incomplete and mostly
- * of historical interest anyway.
- *
- * The basic system is a single buffer which can be used to receive or
- * transmit a packet. A third command mode exists when you are setting
- * things up.
- *
- * If it's transmitting it's not receiving and vice versa. In fact the
- * time to get the board back into useful state after an operation is
- * quite large.
- *
- * The driver works by keeping the board in receive mode waiting for a
- * packet to arrive. When one arrives it is copied out of the buffer
- * and delivered to the kernel. The card is reloaded and off we go.
- *
- * When transmitting lp->txing is set and the card is reset (from
- * receive mode) [possibly losing a packet just received] to command
- * mode. A packet is loaded and transmit mode triggered. The interrupt
- * handler runs different code for transmit interrupts and can handle
- * returning to receive mode or retransmissions (yes you have to help
- * out with those too).
- *
- * DOC: Problems
- *
- * There are a wide variety of undocumented error returns from the card
- * and you basically have to kick the board and pray if they turn up. Most
- * only occur under extreme load or if you do something the board doesn't
- * like (eg touching a register at the wrong time).
- *
- * The driver is less efficient than it could be. It switches through
- * receive mode even if more transmits are queued. If this worries you buy
- * a real Ethernet card.
- *
- * The combination of slow receive restart and no real multicast
- * filter makes the board unusable with a kernel compiled for IP
- * multicasting in a real multicast environment. That's down to the board,
- * but even with no multicast programs running a multicast IP kernel is
- * in group 224.0.0.1 and you will therefore be listening to all multicasts.
- * One nv conference running over that Ethernet and you can give up.
- *
- */
-
-#define DRV_NAME "3c501"
-#define DRV_VERSION "2002/10/09"
-
-
-static const char version[] =
- DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@lxorguk.ukuu.org.uk).\n";
-
-/*
- * Braindamage remaining:
- * The 3c501 board.
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include "3c501.h"
-
-/*
- * The boilerplate probe code.
- */
-
-static int io = 0x280;
-static int irq = 5;
-static int mem_start;
-
-/**
- * el1_probe - probe for a 3c501
- * @dev: The device structure passed in to probe.
- *
- * This can be called from two places. The network layer will probe using
- * a device structure passed in with the probe information completed. For a
- * modular driver we use #init_module to fill in our own structure and probe
- * for it.
- *
- * Returns 0 on success. ENXIO if asked not to probe and ENODEV if asked to
- * probe and failing to find anything.
- */
-
-struct net_device * __init el1_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- static const unsigned ports[] = { 0x280, 0x300, 0};
- const unsigned *port;
- int err = 0;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
- mem_start = dev->mem_start & 7;
- }
-
- if (io > 0x1ff) { /* Check a single specified location. */
- err = el1_probe1(dev, io);
- } else if (io != 0) {
- err = -ENXIO; /* Don't probe at all. */
- } else {
- for (port = ports; *port && el1_probe1(dev, *port); port++)
- ;
- if (!*port)
- err = -ENODEV;
- }
- if (err)
- goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
-out1:
- release_region(dev->base_addr, EL1_IO_EXTENT);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static const struct net_device_ops el_netdev_ops = {
- .ndo_open = el_open,
- .ndo_stop = el1_close,
- .ndo_start_xmit = el_start_xmit,
- .ndo_tx_timeout = el_timeout,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/**
- * el1_probe1:
- * @dev: The device structure to use
- * @ioaddr: An I/O address to probe at.
- *
- * The actual probe. This is iterated over by #el1_probe in order to
- * check all the applicable device locations.
- *
- * Returns 0 for a success, in which case the device is activated,
- * EAGAIN if the IRQ is in use by another driver, and ENODEV if the
- * board cannot be found.
- */
-
-static int __init el1_probe1(struct net_device *dev, int ioaddr)
-{
- struct net_local *lp;
- const char *mname; /* Vendor name */
- unsigned char station_addr[6];
- int autoirq = 0;
- int i;
-
- /*
- * Reserve I/O resource for exclusive use by this driver
- */
-
- if (!request_region(ioaddr, EL1_IO_EXTENT, DRV_NAME))
- return -ENODEV;
-
- /*
- * Read the station address PROM data from the special port.
- */
-
- for (i = 0; i < 6; i++) {
- outw(i, ioaddr + EL1_DATAPTR);
- station_addr[i] = inb(ioaddr + EL1_SAPROM);
- }
- /*
- * Check the first three octets of the S.A. for 3Com's prefix, or
- * for the Sager NP943 prefix.
- */
-
- if (station_addr[0] == 0x02 && station_addr[1] == 0x60 &&
- station_addr[2] == 0x8c)
- mname = "3c501";
- else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 &&
- station_addr[2] == 0xC8)
- mname = "NP943";
- else {
- release_region(ioaddr, EL1_IO_EXTENT);
- return -ENODEV;
- }
-
- /*
- * We auto-IRQ by shutting off the interrupt line and letting it
- * float high.
- */
-
- dev->irq = irq;
-
- if (dev->irq < 2) {
- unsigned long irq_mask;
-
- irq_mask = probe_irq_on();
- inb(RX_STATUS); /* Clear pending interrupts. */
- inb(TX_STATUS);
- outb(AX_LOOP + 1, AX_CMD);
-
- outb(0x00, AX_CMD);
-
- mdelay(20);
- autoirq = probe_irq_off(irq_mask);
-
- if (autoirq == 0) {
- pr_warning("%s probe at %#x failed to detect IRQ line.\n",
- mname, ioaddr);
- release_region(ioaddr, EL1_IO_EXTENT);
- return -EAGAIN;
- }
- }
-
- outb(AX_RESET+AX_LOOP, AX_CMD); /* Loopback mode. */
- dev->base_addr = ioaddr;
- memcpy(dev->dev_addr, station_addr, ETH_ALEN);
-
- if (mem_start & 0xf)
- el_debug = mem_start & 0x7;
- if (autoirq)
- dev->irq = autoirq;
-
- pr_info("%s: %s EtherLink at %#lx, using %sIRQ %d.\n",
- dev->name, mname, dev->base_addr,
- autoirq ? "auto":"assigned ", dev->irq);
-
-#ifdef CONFIG_IP_MULTICAST
- pr_warning("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n");
-#endif
-
- if (el_debug)
- pr_debug("%s", version);
-
- lp = netdev_priv(dev);
- memset(lp, 0, sizeof(struct net_local));
- spin_lock_init(&lp->lock);
-
- /*
- * The EL1-specific entries in the device structure.
- */
-
- dev->netdev_ops = &el_netdev_ops;
- dev->watchdog_timeo = HZ;
- dev->ethtool_ops = &netdev_ethtool_ops;
- return 0;
-}
-
-/**
- * el1_open:
- * @dev: device that is being opened
- *
- * When an ifconfig is issued which changes the device flags to include
- * IFF_UP this function is called. It is only called when the change
- * occurs, not when the interface remains up. #el1_close will be called
- * when it goes down.
- *
- * Returns 0 for a successful open, or -EAGAIN if someone has run off
- * with our interrupt line.
- */
-
-static int el_open(struct net_device *dev)
-{
- int retval;
- int ioaddr = dev->base_addr;
- struct net_local *lp = netdev_priv(dev);
- unsigned long flags;
-
- if (el_debug > 2)
- pr_debug("%s: Doing el_open()...\n", dev->name);
-
- retval = request_irq(dev->irq, el_interrupt, 0, dev->name, dev);
- if (retval)
- return retval;
-
- spin_lock_irqsave(&lp->lock, flags);
- el_reset(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
-
- lp->txing = 0; /* Board in RX mode */
- outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */
- netif_start_queue(dev);
- return 0;
-}
-
-/**
- * el_timeout:
- * @dev: The 3c501 card that has timed out
- *
- * Attempt to restart the board. This is basically a mixture of extreme
- * violence and prayer
- *
- */
-
-static void el_timeout(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- if (el_debug)
- pr_debug("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
- dev->name, inb(TX_STATUS),
- inb(AX_STATUS), inb(RX_STATUS));
- dev->stats.tx_errors++;
- outb(TX_NORM, TX_CMD);
- outb(RX_NORM, RX_CMD);
- outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */
- outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */
- lp->txing = 0; /* Ripped back in to RX */
- netif_wake_queue(dev);
-}
-
-
-/**
- * el_start_xmit:
- * @skb: The packet that is queued to be sent
- * @dev: The 3c501 card we want to throw it down
- *
- * Attempt to send a packet to a 3c501 card. There are some interesting
- * catches here because the 3c501 is an extremely old and therefore
- * stupid piece of technology.
- *
- * If we are handling an interrupt on the other CPU we cannot load a packet
- * as we may still be attempting to retrieve the last RX packet buffer.
- *
- * When a transmit times out we dump the card into control mode and just
- * start again. It happens enough that it isn't worth logging.
- *
- * We avoid holding the spin locks when doing the packet load to the board.
- * The device is very slow, and its DMA mode is even slower. If we held the
- * lock while loading 1500 bytes onto the controller we would drop a lot of
- * serial port characters. This requires we do extra locking, but we have
- * no real choice.
- */
-
-static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned long flags;
-
- /*
- * Avoid incoming interrupts between us flipping txing and flipping
- * mode as the driver assumes txing is a faithful indicator of card
- * state
- */
-
- spin_lock_irqsave(&lp->lock, flags);
-
- /*
- * Avoid timer-based retransmission conflicts.
- */
-
- netif_stop_queue(dev);
-
- do {
- int len = skb->len;
- int pad = 0;
- int gp_start;
- unsigned char *buf = skb->data;
-
- if (len < ETH_ZLEN)
- pad = ETH_ZLEN - len;
-
- gp_start = 0x800 - (len + pad);
-
- lp->tx_pkt_start = gp_start;
- lp->collisions = 0;
-
- dev->stats.tx_bytes += skb->len;
-
- /*
- * Command mode with status cleared should [in theory]
- * mean no more interrupts can be pending on the card.
- */
-
- outb_p(AX_SYS, AX_CMD);
- inb_p(RX_STATUS);
- inb_p(TX_STATUS);
-
- lp->loading = 1;
- lp->txing = 1;
-
- /*
- * Turn interrupts back on while we spend a pleasant
- * afternoon loading bytes into the board
- */
-
- spin_unlock_irqrestore(&lp->lock, flags);
-
- /* Set rx packet area to 0. */
- outw(0x00, RX_BUF_CLR);
- /* aim - packet will be loaded into buffer start */
- outw(gp_start, GP_LOW);
- /* load buffer (usual thing each byte increments the pointer) */
- outsb(DATAPORT, buf, len);
- if (pad) {
- while (pad--) /* Zero fill buffer tail */
- outb(0, DATAPORT);
- }
- /* the board reuses the same register */
- outw(gp_start, GP_LOW);
-
- if (lp->loading != 2) {
- /* fire ... Trigger xmit. */
- outb(AX_XMIT, AX_CMD);
- lp->loading = 0;
- if (el_debug > 2)
- pr_debug(" queued xmit.\n");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- /* A receive upset our load, despite our best efforts */
- if (el_debug > 2)
- pr_debug("%s: burped during tx load.\n", dev->name);
- spin_lock_irqsave(&lp->lock, flags);
- } while (1);
-}
-
-/**
- * el_interrupt:
- * @irq: Interrupt number
- * @dev_id: The 3c501 that burped
- *
- * Handle the ether interface interrupts. The 3c501 needs a lot more
- * hand holding than most cards. In particular we get a transmit interrupt
- * with a collision error because the board firmware isn't capable of rewinding
- * its own transmit buffer pointers. It can however count to 16 for us.
- *
- * On the receive side the card is also very dumb. It has no buffering to
- * speak of. We simply pull the packet out of its PIO buffer (which is slow)
- * and queue it for the kernel. Then we reset the card for the next packet.
- *
- * We sometimes get surprise interrupts late both because the SMP IRQ delivery
- * is message passing and because the card sometimes seems to deliver late. I
- * think if it is part way through a receive and the mode is changed it carries
- * on receiving and sends us an interrupt. We have to band aid all these cases
- * to get a sensible 150kBytes/second performance. Even then you want a small
- * TCP window.
- */
-
-static irqreturn_t el_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct net_local *lp;
- int ioaddr;
- int axsr; /* Aux. status reg. */
-
- ioaddr = dev->base_addr;
- lp = netdev_priv(dev);
-
- spin_lock(&lp->lock);
-
- /*
- * What happened ?
- */
-
- axsr = inb(AX_STATUS);
-
- /*
- * Log it
- */
-
- if (el_debug > 3)
- pr_debug("%s: el_interrupt() aux=%#02x\n", dev->name, axsr);
-
- if (lp->loading == 1 && !lp->txing)
- pr_warning("%s: Inconsistent state loading while not in tx\n",
- dev->name);
-
- if (lp->txing) {
- /*
- * Board in transmit mode. May be loading. If we are
- * loading we shouldn't have got this.
- */
- int txsr = inb(TX_STATUS);
-
- if (lp->loading == 1) {
- if (el_debug > 2)
- pr_debug("%s: Interrupt while loading [txsr=%02x gp=%04x rp=%04x]\n",
- dev->name, txsr, inw(GP_LOW), inw(RX_LOW));
-
- /* Force a reload */
- lp->loading = 2;
- spin_unlock(&lp->lock);
- goto out;
- }
- if (el_debug > 6)
- pr_debug("%s: txsr=%02x gp=%04x rp=%04x\n", dev->name,
- txsr, inw(GP_LOW), inw(RX_LOW));
-
- if ((axsr & 0x80) && (txsr & TX_READY) == 0) {
- /*
- * FIXME: is there a logic to whether to keep
- * on trying or reset immediately ?
- */
- if (el_debug > 1)
- pr_debug("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n",
- dev->name, txsr, axsr,
- inw(ioaddr + EL1_DATAPTR),
- inw(ioaddr + EL1_RXPTR));
- lp->txing = 0;
- netif_wake_queue(dev);
- } else if (txsr & TX_16COLLISIONS) {
- /*
- * Timed out
- */
- if (el_debug)
- pr_debug("%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name);
- outb(AX_SYS, AX_CMD);
- lp->txing = 0;
- dev->stats.tx_aborted_errors++;
- netif_wake_queue(dev);
- } else if (txsr & TX_COLLISION) {
- /*
- * Retrigger xmit.
- */
-
- if (el_debug > 6)
- pr_debug("%s: retransmitting after a collision.\n", dev->name);
- /*
- * Poor little chip can't reset its own start
- * pointer
- */
-
- outb(AX_SYS, AX_CMD);
- outw(lp->tx_pkt_start, GP_LOW);
- outb(AX_XMIT, AX_CMD);
- dev->stats.collisions++;
- spin_unlock(&lp->lock);
- goto out;
- } else {
- /*
- * It worked.. we will now fall through and receive
- */
- dev->stats.tx_packets++;
- if (el_debug > 6)
- pr_debug("%s: Tx succeeded %s\n", dev->name,
- (txsr & TX_RDY) ? "." : "but tx is busy!");
- /*
- * This is safe the interrupt is atomic WRT itself.
- */
- lp->txing = 0;
- /* In case more to transmit */
- netif_wake_queue(dev);
- }
- } else {
- /*
- * In receive mode.
- */
-
- int rxsr = inb(RX_STATUS);
- if (el_debug > 5)
- pr_debug("%s: rxsr=%02x txsr=%02x rp=%04x\n",
- dev->name, rxsr, inb(TX_STATUS), inw(RX_LOW));
- /*
- * Just reading rx_status fixes most errors.
- */
- if (rxsr & RX_MISSED)
- dev->stats.rx_missed_errors++;
- else if (rxsr & RX_RUNT) {
- /* Handled to avoid board lock-up. */
- dev->stats.rx_length_errors++;
- if (el_debug > 5)
- pr_debug("%s: runt.\n", dev->name);
- } else if (rxsr & RX_GOOD) {
- /*
- * Receive worked.
- */
- el_receive(dev);
- } else {
- /*
- * Nothing? Something is broken!
- */
- if (el_debug > 2)
- pr_debug("%s: No packet seen, rxsr=%02x **resetting 3c501***\n",
- dev->name, rxsr);
- el_reset(dev);
- }
- }
-
- /*
- * Move into receive mode
- */
-
- outb(AX_RX, AX_CMD);
- outw(0x00, RX_BUF_CLR);
- inb(RX_STATUS); /* Be certain that interrupts are cleared. */
- inb(TX_STATUS);
- spin_unlock(&lp->lock);
-out:
- return IRQ_HANDLED;
-}
-
-
-/**
- * el_receive:
- * @dev: Device to pull the packets from
- *
- * We have a good packet. Well, not really "good", just mostly not broken.
- * We must check everything to see if it is good. In particular we occasionally
- * get wild packet sizes from the card. If the packet seems sane we PIO it
- * off the card and queue it for the protocol layers.
- */
-
-static void el_receive(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- int pkt_len;
- struct sk_buff *skb;
-
- pkt_len = inw(RX_LOW);
-
- if (el_debug > 4)
- pr_debug(" el_receive %d.\n", pkt_len);
-
- if (pkt_len < 60 || pkt_len > 1536) {
- if (el_debug)
- pr_debug("%s: bogus packet, length=%d\n",
- dev->name, pkt_len);
- dev->stats.rx_over_errors++;
- return;
- }
-
- /*
- * Command mode so we can empty the buffer
- */
-
- outb(AX_SYS, AX_CMD);
- skb = netdev_alloc_skb(dev, pkt_len + 2);
-
- /*
- * Start of frame
- */
-
- outw(0x00, GP_LOW);
- if (skb == NULL) {
- pr_info("%s: Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- return;
- } else {
- skb_reserve(skb, 2); /* Force 16 byte alignment */
- /*
- * The read increments through the bytes. The interrupt
- * handler will fix the pointer when it returns to
- * receive mode.
- */
- insb(DATAPORT, skb_put(skb, pkt_len), pkt_len);
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
-}
-
-/**
- * el_reset: Reset a 3c501 card
- * @dev: The 3c501 card about to get zapped
- *
- * Even resetting a 3c501 isn't simple. When you activate reset it loses all
- * its configuration. You must hold the lock when doing this. The function
- * cannot take the lock itself as it is callable from the irq handler.
- */
-
-static void el_reset(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- if (el_debug > 2)
- pr_info("3c501 reset...\n");
- outb(AX_RESET, AX_CMD); /* Reset the chip */
- /* Aux control, irq and loopback enabled */
- outb(AX_LOOP, AX_CMD);
- {
- int i;
- for (i = 0; i < 6; i++) /* Set the station address. */
- outb(dev->dev_addr[i], ioaddr + i);
- }
-
- outw(0, RX_BUF_CLR); /* Set rx packet area to 0. */
- outb(TX_NORM, TX_CMD); /* tx irq on done, collision */
- outb(RX_NORM, RX_CMD); /* Set Rx commands. */
- inb(RX_STATUS); /* Clear status. */
- inb(TX_STATUS);
- lp->txing = 0;
-}
-
-/**
- * el1_close:
- * @dev: 3c501 card to shut down
- *
- * Close a 3c501 card. The IFF_UP flag has been cleared by the user via
- * the SIOCSIFFLAGS ioctl. We stop any further transmissions being queued,
- * and then disable the interrupts. Finally we reset the chip. The effects
- * of the rest will be cleaned up by #el1_open. Always returns 0 indicating
- * a success.
- */
-
-static int el1_close(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- if (el_debug > 2)
- pr_info("%s: Shutting down Ethernet card at %#x.\n",
- dev->name, ioaddr);
-
- netif_stop_queue(dev);
-
- /*
- * Free and disable the IRQ.
- */
-
- free_irq(dev->irq, dev);
- outb(AX_RESET, AX_CMD); /* Reset the chip */
-
- return 0;
-}
-
-/**
- * set_multicast_list:
- * @dev: The device to adjust
- *
- * Set or clear the multicast filter for this adaptor to use the best-effort
- * filtering supported. The 3c501 supports only three modes of filtering.
- * It always receives broadcasts and packets for itself. You can choose to
- * optionally receive all packets, or all multicast packets on top of this.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- if (dev->flags & IFF_PROMISC) {
- outb(RX_PROM, RX_CMD);
- inb(RX_STATUS);
- } else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
- /* Multicast or all multicast is the same */
- outb(RX_MULT, RX_CMD);
- inb(RX_STATUS); /* Clear status. */
- } else {
- outb(RX_NORM, RX_CMD);
- inb(RX_STATUS);
- }
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
- return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
- debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
- .get_msglevel = netdev_get_msglevel,
- .set_msglevel = netdev_set_msglevel,
-};
-
-#ifdef MODULE
-
-static struct net_device *dev_3c501;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "EtherLink I/O base address");
-MODULE_PARM_DESC(irq, "EtherLink IRQ number");
-
-/**
- * init_module:
- *
- * When the driver is loaded as a module this function is called. We fake up
- * a device structure with the base I/O and interrupt set as if it were being
- * called from Space.c. This minimises the extra code that would otherwise
- * be required.
- *
- * Returns 0 for success or -EIO if a card is not found. Returning an error
- * here also causes the module to be unloaded
- */
-
-int __init init_module(void)
-{
- dev_3c501 = el1_probe(-1);
- if (IS_ERR(dev_3c501))
- return PTR_ERR(dev_3c501);
- return 0;
-}
-
-/**
- * cleanup_module:
- *
- * The module is being unloaded. We unhook our network device from the system
- * and then free up the resources we took when the card was found.
- */
-
-void __exit cleanup_module(void)
-{
- struct net_device *dev = dev_3c501;
- unregister_netdev(dev);
- release_region(dev->base_addr, EL1_IO_EXTENT);
- free_netdev(dev);
-}
-
-#endif /* MODULE */
-
-MODULE_AUTHOR("Donald Becker, Alan Cox");
-MODULE_DESCRIPTION("Support for the ancient 3Com 3c501 ethernet card");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/net/ethernet/3com/3c501.h b/drivers/net/ethernet/3com/3c501.h
deleted file mode 100644
index 183fd55f03cb..000000000000
--- a/drivers/net/ethernet/3com/3c501.h
+++ /dev/null
@@ -1,91 +0,0 @@
-
-/*
- * Index to functions.
- */
-
-static int el1_probe1(struct net_device *dev, int ioaddr);
-static int el_open(struct net_device *dev);
-static void el_timeout(struct net_device *dev);
-static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el_interrupt(int irq, void *dev_id);
-static void el_receive(struct net_device *dev);
-static void el_reset(struct net_device *dev);
-static int el1_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-#define EL1_IO_EXTENT 16
-
-#ifndef EL_DEBUG
-#define EL_DEBUG 0 /* use 0 for production, 1 for devel., >2 for debug */
-#endif /* Anything above 5 is wordy death! */
-#define debug el_debug
-static int el_debug = EL_DEBUG;
-
-/*
- * Board-specific info in netdev_priv(dev).
- */
-
-struct net_local
-{
- int tx_pkt_start; /* The length of the current Tx packet. */
- int collisions; /* Tx collisions this packet */
- int loading; /* Spot buffer load collisions */
- int txing; /* True if card is in TX mode */
- spinlock_t lock; /* Serializing lock */
-};
-
-
-#define RX_STATUS (ioaddr + 0x06)
-#define RX_CMD RX_STATUS
-#define TX_STATUS (ioaddr + 0x07)
-#define TX_CMD TX_STATUS
-#define GP_LOW (ioaddr + 0x08)
-#define GP_HIGH (ioaddr + 0x09)
-#define RX_BUF_CLR (ioaddr + 0x0A)
-#define RX_LOW (ioaddr + 0x0A)
-#define RX_HIGH (ioaddr + 0x0B)
-#define SAPROM (ioaddr + 0x0C)
-#define AX_STATUS (ioaddr + 0x0E)
-#define AX_CMD AX_STATUS
-#define DATAPORT (ioaddr + 0x0F)
-#define TX_RDY 0x08 /* In TX_STATUS */
-
-#define EL1_DATAPTR 0x08
-#define EL1_RXPTR 0x0A
-#define EL1_SAPROM 0x0C
-#define EL1_DATAPORT 0x0f
-
-/*
- * Writes to the ax command register.
- */
-
-#define AX_OFF 0x00 /* Irq off, buffer access on */
-#define AX_SYS 0x40 /* Load the buffer */
-#define AX_XMIT 0x44 /* Transmit a packet */
-#define AX_RX 0x48 /* Receive a packet */
-#define AX_LOOP 0x0C /* Loopback mode */
-#define AX_RESET 0x80
-
-/*
- * Normal receive mode written to RX_STATUS. We must intr on short packets
- * to avoid bogus rx lockups.
- */
-
-#define RX_NORM 0xA8 /* 0x68 == all addrs, 0xA8 only to me. */
-#define RX_PROM 0x68 /* Senior Prom, uhmm promiscuous mode. */
-#define RX_MULT 0xE8 /* Accept multicast packets. */
-#define TX_NORM 0x0A /* Interrupt on everything that might hang the chip */
-
-/*
- * TX_STATUS register.
- */
-
-#define TX_COLLISION 0x02
-#define TX_16COLLISIONS 0x04
-#define TX_READY 0x08
-
-#define RX_RUNT 0x08
-#define RX_MISSED 0x01 /* Missed a packet due to 3c501 braindamage. */
-#define RX_GOOD 0x30 /* Good packet 0x20, or simple overflow 0x10. */
-
diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c
index 633c709b9d99..f36ff99fd394 100644
--- a/drivers/net/ethernet/3com/3c509.c
+++ b/drivers/net/ethernet/3com/3c509.c
@@ -1161,8 +1161,8 @@ el3_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
static void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
}
static int el3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c
index 59e1e001bc3f..94c656f5a05d 100644
--- a/drivers/net/ethernet/3com/3c515.c
+++ b/drivers/net/ethernet/3com/3c515.c
@@ -1542,9 +1542,10 @@ static void set_rx_mode(struct net_device *dev)
static void netdev_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ snprintf(info->bus_info, sizeof(info->bus_info), "ISA 0x%lx",
+ dev->base_addr);
}
static u32 netdev_get_msglevel(struct net_device *dev)
diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
index ed0feb3cc6fa..1928e2001587 100644
--- a/drivers/net/ethernet/3com/3c59x.c
+++ b/drivers/net/ethernet/3com/3c59x.c
@@ -1293,7 +1293,6 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum);
for (i = 0; i < 3; i++)
((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
if (print_info)
pr_cont(" %pM", dev->dev_addr);
/* Unfortunately an all zero eeprom passes the checksum and this
diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig
index eb56174469a7..1c71c763f680 100644
--- a/drivers/net/ethernet/3com/Kconfig
+++ b/drivers/net/ethernet/3com/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_3COM
bool "3Com devices"
default y
- depends on ISA || EISA || MCA || PCI || PCMCIA
+ depends on ISA || EISA || PCI || PCMCIA
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -18,23 +18,9 @@ config NET_VENDOR_3COM
if NET_VENDOR_3COM
-config EL1
- tristate "3c501 \"EtherLink\" support"
- depends on ISA
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Also, consider buying a
- new card, since the 3c501 is slow, broken, and obsolete: you will
- have problems. Some people suggest to ping ("man ping") a nearby
- machine every minute ("man cron") when using this card.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c501.
-
config EL3
- tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
- depends on (ISA || EISA || MCA)
+ tristate "3c509/3c579 \"EtherLink III\" support"
+ depends on (ISA || EISA)
---help---
If you have a network (Ethernet) card belonging to the 3Com
EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com/Makefile
index 1e5382a30ead..74046afab993 100644
--- a/drivers/net/ethernet/3com/Makefile
+++ b/drivers/net/ethernet/3com/Makefile
@@ -2,7 +2,6 @@
# Makefile for the 3Com Ethernet device drivers
#
-obj-$(CONFIG_EL1) += 3c501.o
obj-$(CONFIG_EL3) += 3c509.o
obj-$(CONFIG_3C515) += 3c515.o
obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
diff --git a/drivers/net/ethernet/8390/3c503.c b/drivers/net/ethernet/8390/3c503.c
deleted file mode 100644
index 49d76bd0dc86..000000000000
--- a/drivers/net/ethernet/8390/3c503.c
+++ /dev/null
@@ -1,777 +0,0 @@
-/* 3c503.c: A shared-memory NS8390 ethernet driver for linux. */
-/*
- Written 1992-94 by Donald Becker.
-
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used and
- distributed according to the terms of the GNU General Public License,
- incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
-
- This driver should work with the 3c503 and 3c503/16. It should be used
- in shared memory mode for best performance, although it may also work
- in programmed-I/O mode.
-
- Sources:
- EtherLink II Technical Reference Manual,
- EtherLink II/16 Technical Reference Manual Supplement,
- 3Com Corporation, 5400 Bayfront Plaza, Santa Clara CA 95052-8145
-
- The Crynwr 3c503 packet driver.
-
- Changelog:
-
- Paul Gortmaker : add support for the 2nd 8kB of RAM on 16 bit cards.
- Paul Gortmaker : multiple card support for module users.
- rjohnson@analogic.com : Fix up PIO interface for efficient operation.
- Jeff Garzik : ethtool support
-
-*/
-
-#define DRV_NAME "3c503"
-#define DRV_VERSION "1.10a"
-#define DRV_RELDATE "11/17/2001"
-
-
-static const char version[] =
- DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ethtool.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-
-#include "8390.h"
-#include "3c503.h"
-#define WRD_COUNT 4
-
-static int el2_pio_probe(struct net_device *dev);
-static int el2_probe1(struct net_device *dev, int ioaddr);
-
-/* A zero-terminated list of I/O addresses to be probed in PIO mode. */
-static unsigned int netcard_portlist[] __initdata =
- { 0x300,0x310,0x330,0x350,0x250,0x280,0x2a0,0x2e0,0};
-
-#define EL2_IO_EXTENT 16
-
-static int el2_open(struct net_device *dev);
-static int el2_close(struct net_device *dev);
-static void el2_reset_8390(struct net_device *dev);
-static void el2_init_card(struct net_device *dev);
-static void el2_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page);
-static void el2_block_input(struct net_device *dev, int count, struct sk_buff *skb,
- int ring_offset);
-static void el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-
-/* This routine probes for a memory-mapped 3c503 board by looking for
- the "location register" at the end of the jumpered boot PROM space.
- This works even if a PROM isn't there.
-
- If the ethercard isn't found there is an optional probe for
- ethercard jumpered to programmed-I/O mode.
- */
-static int __init do_el2_probe(struct net_device *dev)
-{
- int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0};
- int base_addr = dev->base_addr;
- int irq = dev->irq;
-
- if (base_addr > 0x1ff) /* Check a single specified location. */
- return el2_probe1(dev, base_addr);
- else if (base_addr != 0) /* Don't probe at all. */
- return -ENXIO;
-
- for (addr = addrs; *addr; addr++) {
- void __iomem *p = ioremap(*addr, 1);
- unsigned base_bits;
- int i;
-
- if (!p)
- continue;
- base_bits = readb(p);
- iounmap(p);
- i = ffs(base_bits) - 1;
- if (i == -1 || base_bits != (1 << i))
- continue;
- if (el2_probe1(dev, netcard_portlist[i]) == 0)
- return 0;
- dev->irq = irq;
- }
-#if ! defined(no_probe_nonshared_memory)
- return el2_pio_probe(dev);
-#else
- return -ENODEV;
-#endif
-}
-
-/* Try all of the locations that aren't obviously empty. This touches
- a lot of locations, and is much riskier than the code above. */
-static int __init
-el2_pio_probe(struct net_device *dev)
-{
- int i;
- int base_addr = dev->base_addr;
- int irq = dev->irq;
-
- if (base_addr > 0x1ff) /* Check a single specified location. */
- return el2_probe1(dev, base_addr);
- else if (base_addr != 0) /* Don't probe at all. */
- return -ENXIO;
-
- for (i = 0; netcard_portlist[i]; i++) {
- if (el2_probe1(dev, netcard_portlist[i]) == 0)
- return 0;
- dev->irq = irq;
- }
-
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init el2_probe(int unit)
-{
- struct net_device *dev = alloc_eip_netdev();
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_el2_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops el2_netdev_ops = {
- .ndo_open = el2_open,
- .ndo_stop = el2_close,
-
- .ndo_start_xmit = eip_start_xmit,
- .ndo_tx_timeout = eip_tx_timeout,
- .ndo_get_stats = eip_get_stats,
- .ndo_set_rx_mode = eip_set_multicast_list,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_change_mtu = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = eip_poll,
-#endif
-};
-
-/* Probe for the Etherlink II card at I/O port base IOADDR,
- returning non-zero on success. If found, set the station
- address and memory parameters in DEVICE. */
-static int __init
-el2_probe1(struct net_device *dev, int ioaddr)
-{
- int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
- static unsigned version_printed;
- unsigned long vendor_id;
-
- if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME))
- return -EBUSY;
-
- if (!request_region(ioaddr + 0x400, 8, DRV_NAME)) {
- retval = -EBUSY;
- goto out;
- }
-
- /* Reset and/or avoid any lurking NE2000 */
- if (inb(ioaddr + 0x408) == 0xff) {
- mdelay(1);
- retval = -ENODEV;
- goto out1;
- }
-
- /* We verify that it's a 3C503 board by checking the first three octets
- of its ethernet address. */
- iobase_reg = inb(ioaddr+0x403);
- membase_reg = inb(ioaddr+0x404);
- /* ASIC location registers should be 0 or have only a single bit set. */
- if ((iobase_reg & (iobase_reg - 1)) ||
- (membase_reg & (membase_reg - 1))) {
- retval = -ENODEV;
- goto out1;
- }
- saved_406 = inb_p(ioaddr + 0x406);
- outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */
- outb_p(ECNTRL_THIN, ioaddr + 0x406);
- /* Map the station addr PROM into the lower I/O ports. We now check
- for both the old and new 3Com prefix */
- outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406);
- vendor_id = inb(ioaddr)*0x10000 + inb(ioaddr + 1)*0x100 + inb(ioaddr + 2);
- if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID)) {
- /* Restore the register we frobbed. */
- outb(saved_406, ioaddr + 0x406);
- retval = -ENODEV;
- goto out1;
- }
-
- if (ei_debug && version_printed++ == 0)
- pr_debug("%s", version);
-
- dev->base_addr = ioaddr;
-
- pr_info("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr);
-
- /* Retrieve and print the ethernet address. */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = inb(ioaddr + i);
- pr_cont("%pM", dev->dev_addr);
-
- /* Map the 8390 back into the window. */
- outb(ECNTRL_THIN, ioaddr + 0x406);
-
- /* Check for EL2/16 as described in tech. man. */
- outb_p(E8390_PAGE0, ioaddr + E8390_CMD);
- outb_p(0, ioaddr + EN0_DCFG);
- outb_p(E8390_PAGE2, ioaddr + E8390_CMD);
- wordlength = inb_p(ioaddr + EN0_DCFG) & ENDCFG_WTS;
- outb_p(E8390_PAGE0, ioaddr + E8390_CMD);
-
- /* Probe for, turn on and clear the board's shared memory. */
- if (ei_debug > 2)
- pr_cont(" memory jumpers %2.2x ", membase_reg);
- outb(EGACFR_NORM, ioaddr + 0x405); /* Enable RAM */
-
- /* This should be probed for (or set via an ioctl()) at run-time.
- Right now we use a sleazy hack to pass in the interface number
- at boot-time via the low bits of the mem_end field. That value is
- unused, and the low bits would be discarded even if it was used. */
-#if defined(EI8390_THICK) || defined(EL2_AUI)
- ei_status.interface_num = 1;
-#else
- ei_status.interface_num = dev->mem_end & 0xf;
-#endif
- pr_cont(", using %sternal xcvr.\n", ei_status.interface_num == 0 ? "in" : "ex");
-
- if ((membase_reg & 0xf0) == 0) {
- dev->mem_start = 0;
- ei_status.name = "3c503-PIO";
- ei_status.mem = NULL;
- } else {
- dev->mem_start = ((membase_reg & 0xc0) ? 0xD8000 : 0xC8000) +
- ((membase_reg & 0xA0) ? 0x4000 : 0);
-#define EL2_MEMSIZE (EL2_MB1_STOP_PG - EL2_MB1_START_PG)*256
- ei_status.mem = ioremap(dev->mem_start, EL2_MEMSIZE);
-
-#ifdef EL2MEMTEST
- /* This has never found an error, but someone might care.
- Note that it only tests the 2nd 8kB on 16kB 3c503/16
- cards between card addr. 0x2000 and 0x3fff. */
- { /* Check the card's memory. */
- void __iomem *mem_base = ei_status.mem;
- unsigned int test_val = 0xbbadf00d;
- writel(0xba5eba5e, mem_base);
- for (i = sizeof(test_val); i < EL2_MEMSIZE; i+=sizeof(test_val)) {
- writel(test_val, mem_base + i);
- if (readl(mem_base) != 0xba5eba5e ||
- readl(mem_base + i) != test_val) {
- pr_warning("3c503: memory failure or memory address conflict.\n");
- dev->mem_start = 0;
- ei_status.name = "3c503-PIO";
- iounmap(mem_base);
- ei_status.mem = NULL;
- break;
- }
- test_val += 0x55555555;
- writel(0, mem_base + i);
- }
- }
-#endif /* EL2MEMTEST */
-
- if (dev->mem_start)
- dev->mem_end = dev->mem_start + EL2_MEMSIZE;
-
- if (wordlength) { /* No Tx pages to skip over to get to Rx */
- ei_status.priv = 0;
- ei_status.name = "3c503/16";
- } else {
- ei_status.priv = TX_PAGES * 256;
- ei_status.name = "3c503";
- }
- }
-
- /*
- Divide up the memory on the card. This is the same regardless of
- whether shared-mem or PIO is used. For 16 bit cards (16kB RAM),
- we use the entire 8k of bank1 for an Rx ring. We only use 3k
- of the bank0 for 2 full size Tx packet slots. For 8 bit cards,
- (8kB RAM) we use 3kB of bank1 for two Tx slots, and the remaining
- 5kB for an Rx ring. */
-
- if (wordlength) {
- ei_status.tx_start_page = EL2_MB0_START_PG;
- ei_status.rx_start_page = EL2_MB1_START_PG;
- } else {
- ei_status.tx_start_page = EL2_MB1_START_PG;
- ei_status.rx_start_page = EL2_MB1_START_PG + TX_PAGES;
- }
-
- /* Finish setting the board's parameters. */
- ei_status.stop_page = EL2_MB1_STOP_PG;
- ei_status.word16 = wordlength;
- ei_status.reset_8390 = el2_reset_8390;
- ei_status.get_8390_hdr = el2_get_8390_hdr;
- ei_status.block_input = el2_block_input;
- ei_status.block_output = el2_block_output;
-
- if (dev->irq == 2)
- dev->irq = 9;
- else if (dev->irq > 5 && dev->irq != 9) {
- pr_warning("3c503: configured interrupt %d invalid, will use autoIRQ.\n",
- dev->irq);
- dev->irq = 0;
- }
-
- ei_status.saved_irq = dev->irq;
-
- dev->netdev_ops = &el2_netdev_ops;
- dev->ethtool_ops = &netdev_ethtool_ops;
-
- retval = register_netdev(dev);
- if (retval)
- goto out1;
-
- if (dev->mem_start)
- pr_info("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n",
- dev->name, ei_status.name, (wordlength+1)<<3,
- dev->mem_start, dev->mem_end-1);
-
- else
- {
- ei_status.tx_start_page = EL2_MB1_START_PG;
- ei_status.rx_start_page = EL2_MB1_START_PG + TX_PAGES;
- pr_info("%s: %s, %dkB RAM, using programmed I/O (REJUMPER for SHARED MEMORY).\n",
- dev->name, ei_status.name, (wordlength+1)<<3);
- }
- release_region(ioaddr + 0x400, 8);
- return 0;
-out1:
- release_region(ioaddr + 0x400, 8);
-out:
- release_region(ioaddr, EL2_IO_EXTENT);
- return retval;
-}
-
-static irqreturn_t el2_probe_interrupt(int irq, void *seen)
-{
- *(bool *)seen = true;
- return IRQ_HANDLED;
-}
-
-static int
-el2_open(struct net_device *dev)
-{
- int retval;
-
- if (dev->irq < 2) {
- static const int irqlist[] = {5, 9, 3, 4, 0};
- const int *irqp = irqlist;
-
- outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM and interrupts. */
- do {
- bool seen;
-
- retval = request_irq(*irqp, el2_probe_interrupt, 0,
- dev->name, &seen);
- if (retval == -EBUSY)
- continue;
- if (retval < 0)
- goto err_disable;
-
- /* Twinkle the interrupt, and check if it's seen. */
- seen = false;
- smp_wmb();
- outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
- outb_p(0x00, E33G_IDCFR);
- msleep(1);
- free_irq(*irqp, &seen);
- if (!seen)
- continue;
-
- retval = request_irq(dev->irq = *irqp, eip_interrupt, 0,
- dev->name, dev);
- if (retval == -EBUSY)
- continue;
- if (retval < 0)
- goto err_disable;
- break;
- } while (*++irqp);
-
- if (*irqp == 0) {
- err_disable:
- outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */
- return -EAGAIN;
- }
- } else {
- if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
- return retval;
- }
- }
-
- el2_init_card(dev);
- eip_open(dev);
- return 0;
-}
-
-static int
-el2_close(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
- dev->irq = ei_status.saved_irq;
- outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */
-
- eip_close(dev);
- return 0;
-}
-
-/* This is called whenever we have a unrecoverable failure:
- transmit timeout
- Bad ring buffer packet header
- */
-static void
-el2_reset_8390(struct net_device *dev)
-{
- if (ei_debug > 1) {
- pr_debug("%s: Resetting the 3c503 board...", dev->name);
- pr_cont(" %#lx=%#02x %#lx=%#02x %#lx=%#02x...", E33G_IDCFR, inb(E33G_IDCFR),
- E33G_CNTRL, inb(E33G_CNTRL), E33G_GACFR, inb(E33G_GACFR));
- }
- outb_p(ECNTRL_RESET|ECNTRL_THIN, E33G_CNTRL);
- ei_status.txing = 0;
- outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
- el2_init_card(dev);
- if (ei_debug > 1)
- pr_cont("done\n");
-}
-
-/* Initialize the 3c503 GA registers after a reset. */
-static void
-el2_init_card(struct net_device *dev)
-{
- /* Unmap the station PROM and select the DIX or BNC connector. */
- outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-
- /* Set ASIC copy of rx's first and last+1 buffer pages */
- /* These must be the same as in the 8390. */
- outb(ei_status.rx_start_page, E33G_STARTPG);
- outb(ei_status.stop_page, E33G_STOPPG);
-
- /* Point the vector pointer registers somewhere ?harmless?. */
- outb(0xff, E33G_VP2); /* Point at the ROM restart location 0xffff0 */
- outb(0xff, E33G_VP1);
- outb(0x00, E33G_VP0);
- /* Turn off all interrupts until we're opened. */
- outb_p(0x00, dev->base_addr + EN0_IMR);
- /* Enable IRQs iff started. */
- outb(EGACFR_NORM, E33G_GACFR);
-
- /* Set the interrupt line. */
- outb_p((0x04 << (dev->irq == 9 ? 2 : dev->irq)), E33G_IDCFR);
- outb_p((WRD_COUNT << 1), E33G_DRQCNT); /* Set burst size to 8 */
- outb_p(0x20, E33G_DMAAH); /* Put a valid addr in the GA DMA */
- outb_p(0x00, E33G_DMAAL);
- return; /* We always succeed */
-}
-
-/*
- * Either use the shared memory (if enabled on the board) or put the packet
- * out through the ASIC FIFO.
- */
-static void
-el2_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- unsigned short int *wrd;
- int boguscount; /* timeout counter */
- unsigned short word; /* temporary for better machine code */
- void __iomem *base = ei_status.mem;
-
- if (ei_status.word16) /* Tx packets go into bank 0 on EL2/16 card */
- outb(EGACFR_RSEL|EGACFR_TCM, E33G_GACFR);
- else
- outb(EGACFR_NORM, E33G_GACFR);
-
- if (base) { /* Shared memory transfer */
- memcpy_toio(base + ((start_page - ei_status.tx_start_page) << 8),
- buf, count);
- outb(EGACFR_NORM, E33G_GACFR); /* Back to bank1 in case on bank0 */
- return;
- }
-
-/*
- * No shared memory, put the packet out the other way.
- * Set up then start the internal memory transfer to Tx Start Page
- */
-
- word = (unsigned short)start_page;
- outb(word&0xFF, E33G_DMAAH);
- outb(word>>8, E33G_DMAAL);
-
- outb_p((ei_status.interface_num ? ECNTRL_AUI : ECNTRL_THIN ) | ECNTRL_OUTPUT
- | ECNTRL_START, E33G_CNTRL);
-
-/*
- * Here I am going to write data to the FIFO as quickly as possible.
- * Note that E33G_FIFOH is defined incorrectly. It is really
- * E33G_FIFOL, the lowest port address for both the byte and
- * word write. Variable 'count' is NOT checked. Caller must supply a
- * valid count. Note that I may write a harmless extra byte to the
- * 8390 if the byte-count was not even.
- */
- wrd = (unsigned short int *) buf;
- count = (count + 1) >> 1;
- for(;;)
- {
- boguscount = 0x1000;
- while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
- {
- if(!boguscount--)
- {
- pr_notice("%s: FIFO blocked in el2_block_output.\n", dev->name);
- el2_reset_8390(dev);
- goto blocked;
- }
- }
- if(count > WRD_COUNT)
- {
- outsw(E33G_FIFOH, wrd, WRD_COUNT);
- wrd += WRD_COUNT;
- count -= WRD_COUNT;
- }
- else
- {
- outsw(E33G_FIFOH, wrd, count);
- break;
- }
- }
- blocked:;
- outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-}
-
-/* Read the 4 byte, page aligned 8390 specific header. */
-static void
-el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
- int boguscount;
- void __iomem *base = ei_status.mem;
- unsigned short word;
-
- if (base) { /* Use the shared memory. */
- void __iomem *hdr_start = base + ((ring_page - EL2_MB1_START_PG)<<8);
- memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
- hdr->count = le16_to_cpu(hdr->count);
- return;
- }
-
-/*
- * No shared memory, use programmed I/O.
- */
-
- word = (unsigned short)ring_page;
- outb(word&0xFF, E33G_DMAAH);
- outb(word>>8, E33G_DMAAL);
-
- outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT
- | ECNTRL_START, E33G_CNTRL);
- boguscount = 0x1000;
- while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
- {
- if(!boguscount--)
- {
- pr_notice("%s: FIFO blocked in el2_get_8390_hdr.\n", dev->name);
- memset(hdr, 0x00, sizeof(struct e8390_pkt_hdr));
- el2_reset_8390(dev);
- goto blocked;
- }
- }
- insw(E33G_FIFOH, hdr, (sizeof(struct e8390_pkt_hdr))>> 1);
- blocked:;
- outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-}
-
-
-static void
-el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
- int boguscount = 0;
- void __iomem *base = ei_status.mem;
- unsigned short int *buf;
- unsigned short word;
-
- /* Maybe enable shared memory just be to be safe... nahh.*/
- if (base) { /* Use the shared memory. */
- ring_offset -= (EL2_MB1_START_PG<<8);
- if (ring_offset + count > EL2_MEMSIZE) {
- /* We must wrap the input move. */
- int semi_count = EL2_MEMSIZE - ring_offset;
- memcpy_fromio(skb->data, base + ring_offset, semi_count);
- count -= semi_count;
- memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count);
- } else {
- memcpy_fromio(skb->data, base + ring_offset, count);
- }
- return;
- }
-
-/*
- * No shared memory, use programmed I/O.
- */
- word = (unsigned short) ring_offset;
- outb(word>>8, E33G_DMAAH);
- outb(word&0xFF, E33G_DMAAL);
-
- outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT
- | ECNTRL_START, E33G_CNTRL);
-
-/*
- * Here I also try to get data as fast as possible. I am betting that I
- * can read one extra byte without clobbering anything in the kernel because
- * this would only occur on an odd byte-count and allocation of skb->data
- * is word-aligned. Variable 'count' is NOT checked. Caller must check
- * for a valid count.
- * [This is currently quite safe.... but if one day the 3c503 explodes
- * you know where to come looking ;)]
- */
-
- buf = (unsigned short int *) skb->data;
- count = (count + 1) >> 1;
- for(;;)
- {
- boguscount = 0x1000;
- while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0)
- {
- if(!boguscount--)
- {
- pr_notice("%s: FIFO blocked in el2_block_input.\n", dev->name);
- el2_reset_8390(dev);
- goto blocked;
- }
- }
- if(count > WRD_COUNT)
- {
- insw(E33G_FIFOH, buf, WRD_COUNT);
- buf += WRD_COUNT;
- count -= WRD_COUNT;
- }
- else
- {
- insw(E33G_FIFOH, buf, count);
- break;
- }
- }
- blocked:;
- outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
-};
-
-#ifdef MODULE
-#define MAX_EL2_CARDS 4 /* Max number of EL2 cards per module */
-
-static struct net_device *dev_el2[MAX_EL2_CARDS];
-static int io[MAX_EL2_CARDS];
-static int irq[MAX_EL2_CARDS];
-static int xcvr[MAX_EL2_CARDS]; /* choose int. or ext. xcvr */
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(xcvr, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_PARM_DESC(xcvr, "transceiver(s) (0=internal, 1=external)");
-MODULE_DESCRIPTION("3Com ISA EtherLink II, II/16 (3c503, 3c503/16) driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-int __init
-init_module(void)
-{
- struct net_device *dev;
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) {
- if (io[this_dev] == 0) {
- if (this_dev != 0) break; /* only autoprobe 1st one */
- pr_notice("3c503.c: Presently autoprobing (not recommended) for a single card.\n");
- }
- dev = alloc_eip_netdev();
- if (!dev)
- break;
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */
- if (do_el2_probe(dev) == 0) {
- dev_el2[found++] = dev;
- continue;
- }
- free_netdev(dev);
- pr_warning("3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]);
- break;
- }
- if (found)
- return 0;
- return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
- /* NB: el2_close() handles free_irq */
- release_region(dev->base_addr, EL2_IO_EXTENT);
- if (ei_status.mem)
- iounmap(ei_status.mem);
-}
-
-void __exit
-cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) {
- struct net_device *dev = dev_el2[this_dev];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/3c503.h b/drivers/net/ethernet/8390/3c503.h
deleted file mode 100644
index e2367b82a2ec..000000000000
--- a/drivers/net/ethernet/8390/3c503.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* Definitions for the 3Com 3c503 Etherlink 2. */
-/* This file is distributed under the GPL.
- Many of these names and comments are directly from the Crynwr packet
- drivers, which are released under the GPL. */
-
-#define EL2H (dev->base_addr + 0x400)
-#define EL2L (dev->base_addr)
-
-/* Vendor unique hardware addr. prefix. 3Com has 2 because they ran
- out of available addresses on the first one... */
-
-#define OLD_3COM_ID 0x02608c
-#define NEW_3COM_ID 0x0020af
-
-/* Shared memory management parameters. NB: The 8 bit cards have only
- one bank (MB1) which serves both Tx and Rx packet space. The 16bit
- cards have 2 banks, MB0 for Tx packets, and MB1 for Rx packets.
- You choose which bank appears in the sh. mem window with EGACFR_MBSn */
-
-#define EL2_MB0_START_PG (0x00) /* EL2/16 Tx packets go in bank 0 */
-#define EL2_MB1_START_PG (0x20) /* First page of bank 1 */
-#define EL2_MB1_STOP_PG (0x40) /* Last page +1 of bank 1 */
-
-/* 3Com 3c503 ASIC registers */
-#define E33G_STARTPG (EL2H+0) /* Start page, matching EN0_STARTPG */
-#define E33G_STOPPG (EL2H+1) /* Stop page, must match EN0_STOPPG */
-#define E33G_DRQCNT (EL2H+2) /* DMA burst count */
-#define E33G_IOBASE (EL2H+3) /* Read of I/O base jumpers. */
- /* (non-useful, but it also appears at the end of EPROM space) */
-#define E33G_ROMBASE (EL2H+4) /* Read of memory base jumpers. */
-#define E33G_GACFR (EL2H+5) /* Config/setup bits for the ASIC GA */
-#define E33G_CNTRL (EL2H+6) /* Board's main control register */
-#define E33G_STATUS (EL2H+7) /* Status on completions. */
-#define E33G_IDCFR (EL2H+8) /* Interrupt/DMA config register */
- /* (Which IRQ to assert, DMA chan to use) */
-#define E33G_DMAAH (EL2H+9) /* High byte of DMA address reg */
-#define E33G_DMAAL (EL2H+10) /* Low byte of DMA address reg */
-/* "Vector pointer" - if this address matches a read, the EPROM (rather than
- shared RAM) is mapped into memory space. */
-#define E33G_VP2 (EL2H+11)
-#define E33G_VP1 (EL2H+12)
-#define E33G_VP0 (EL2H+13)
-#define E33G_FIFOH (EL2H+14) /* FIFO for programmed I/O moves */
-#define E33G_FIFOL (EL2H+15) /* ... low byte of above. */
-
-/* Bits in E33G_CNTRL register: */
-
-#define ECNTRL_RESET (0x01) /* Software reset of the ASIC and 8390 */
-#define ECNTRL_THIN (0x02) /* Onboard xcvr enable, AUI disable */
-#define ECNTRL_AUI (0x00) /* Onboard xcvr disable, AUI enable */
-#define ECNTRL_SAPROM (0x04) /* Map the station address prom */
-#define ECNTRL_DBLBFR (0x20) /* FIFO configuration bit */
-#define ECNTRL_OUTPUT (0x40) /* PC-to-3C503 direction if 1 */
-#define ECNTRL_INPUT (0x00) /* 3C503-to-PC direction if 0 */
-#define ECNTRL_START (0x80) /* Start the DMA logic */
-
-/* Bits in E33G_STATUS register: */
-
-#define ESTAT_DPRDY (0x80) /* Data port (of FIFO) ready */
-#define ESTAT_UFLW (0x40) /* Tried to read FIFO when it was empty */
-#define ESTAT_OFLW (0x20) /* Tried to write FIFO when it was full */
-#define ESTAT_DTC (0x10) /* Terminal Count from PC bus DMA logic */
-#define ESTAT_DIP (0x08) /* DMA In Progress */
-
-/* Bits in E33G_GACFR register: */
-
-#define EGACFR_NIM (0x80) /* NIC interrupt mask */
-#define EGACFR_TCM (0x40) /* DMA term. count interrupt mask */
-#define EGACFR_RSEL (0x08) /* Map a bank of card mem into system mem */
-#define EGACFR_MBS2 (0x04) /* Memory bank select, bit 2. */
-#define EGACFR_MBS1 (0x02) /* Memory bank select, bit 1. */
-#define EGACFR_MBS0 (0x01) /* Memory bank select, bit 0. */
-
-#define EGACFR_NORM (0x49) /* TCM | RSEL | MBS0 */
-#define EGACFR_IRQOFF (0xc9) /* TCM | RSEL | MBS0 | NIM */
-
-/*
- MBS2 MBS1 MBS0 Sh. mem windows card mem at:
- ---- ---- ---- -----------------------------
- 0 0 0 0x0000 -- bank 0
- 0 0 1 0x2000 -- bank 1 (only choice for 8bit card)
- 0 1 0 0x4000 -- bank 2, not used
- 0 1 1 0x6000 -- bank 3, not used
-
-There was going to be a 32k card that used bank 2 and 3, but it
-never got produced.
-
-*/
-
-
-/* End of 3C503 parameter definitions */
diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index e1219e037c04..a5f91e1e8fe3 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -5,10 +5,7 @@
config NET_VENDOR_8390
bool "National Semi-conductor 8390 devices"
default y
- depends on NET_VENDOR_NATSEMI && (AMIGA_PCMCIA || PCI || SUPERH || \
- ISA || MCA || EISA || MAC || M32R || MACH_TX49XX || \
- MCA_LEGACY || H8300 || ARM || MIPS || ZORRO || PCMCIA || \
- EXPERIMENTAL)
+ depends on NET_VENDOR_NATSEMI
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -21,30 +18,6 @@ config NET_VENDOR_8390
if NET_VENDOR_8390
-config EL2
- tristate "3c503 \"EtherLink II\" support"
- depends on ISA
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c503.
-
-config AC3200
- tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)"
- depends on PCI && (ISA || EISA) && EXPERIMENTAL
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called ac3200.
-
config PCMCIA_AXNET
tristate "Asix AX88190 PCMCIA support"
depends on PCMCIA
@@ -74,54 +47,6 @@ config AX88796_93CX6
---help---
Select this if your platform comes with an external 93CX6 eeprom.
-config E2100
- tristate "Cabletron E21xx support"
- depends on ISA
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called e2100.
-
-config ES3210
- tristate "Racal-Interlan EISA ES3210 support (EXPERIMENTAL)"
- depends on PCI && EISA && EXPERIMENTAL
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called es3210.
-
-config HPLAN_PLUS
- tristate "HP PCLAN+ (27247B and 27252A) support"
- depends on ISA
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called hp-plus.
-
-config HPLAN
- tristate "HP PCLAN (27245 and other 27xxx series) support"
- depends on ISA
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called hp.
-
config HYDRA
tristate "Hydra support"
depends on ZORRO
@@ -140,18 +65,6 @@ config ARM_ETHERH
If you have an Acorn system with one of these network cards, you
should say Y to this option if you wish to use it with Linux.
-config LNE390
- tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
- depends on PCI && EISA && EXPERIMENTAL
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called lne390.
-
config MAC8390
bool "Macintosh NS 8390 based ethernet cards"
depends on MAC
@@ -187,11 +100,7 @@ config NE2000
without a specific driver are compatible with NE2000.
If you have a PCI NE2000 card however, say N here and Y to "PCI
- NE2000 and clone support" under "EISA, VLB, PCI and on board
- controllers" below. If you have a NE2000 card and are running on
- an MCA system (a bus system used on some IBM PS/2 computers and
- laptops), say N here and Y to "NE/2 (ne2000 MCA version) support",
- below.
+ NE2000 and clone support" below.
To compile this driver as a module, choose M here. The module
will be called ne.
@@ -226,19 +135,6 @@ config APNE
To compile this driver as a module, choose M here: the module
will be called apne.
-config NE3210
- tristate "Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)"
- depends on PCI && EISA && EXPERIMENTAL
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Note that this driver
- will NOT WORK for NE3200 cards as they are completely different.
-
- To compile this driver as a module, choose M here. The module
- will be called ne3210.
-
config PCMCIA_PCNET
tristate "NE2000 compatible PCMCIA support"
depends on PCMCIA
@@ -288,18 +184,6 @@ config ULTRA
To compile this driver as a module, choose M here. The module
will be called smc-ultra.
-config ULTRA32
- tristate "SMC Ultra32 EISA support"
- depends on EISA
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called smc-ultra32.
-
config WD80x3
tristate "WD80*3 support"
depends on ISA
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index f43038babf86..588954a79b2a 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -3,27 +3,17 @@
#
obj-$(CONFIG_MAC8390) += mac8390.o
-obj-$(CONFIG_AC3200) += ac3200.o 8390.o
obj-$(CONFIG_APNE) += apne.o 8390.o
obj-$(CONFIG_ARM_ETHERH) += etherh.o
obj-$(CONFIG_AX88796) += ax88796.o
-obj-$(CONFIG_E2100) += e2100.o 8390.o
-obj-$(CONFIG_EL2) += 3c503.o 8390p.o
-obj-$(CONFIG_ES3210) += es3210.o 8390.o
-obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o
-obj-$(CONFIG_HPLAN) += hp.o 8390p.o
obj-$(CONFIG_HYDRA) += hydra.o 8390.o
-obj-$(CONFIG_LNE390) += lne390.o 8390.o
obj-$(CONFIG_MCF8390) += mcf8390.o 8390.o
obj-$(CONFIG_NE2000) += ne.o 8390p.o
-obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o
obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
-obj-$(CONFIG_NE3210) += ne3210.o 8390.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o
obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o
obj-$(CONFIG_STNIC) += stnic.o 8390.o
obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
-obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
obj-$(CONFIG_WD80x3) += wd.o 8390.o
obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
diff --git a/drivers/net/ethernet/8390/ac3200.c b/drivers/net/ethernet/8390/ac3200.c
deleted file mode 100644
index ccf07942ff6e..000000000000
--- a/drivers/net/ethernet/8390/ac3200.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/* ac3200.c: A driver for the Ansel Communications EISA ethernet adaptor. */
-/*
- Written 1993, 1994 by Donald Becker.
- Copyright 1993 United States Government as represented by the Director,
- National Security Agency. This software may only be used and distributed
- according to the terms of the GNU General Public License as modified by SRC,
- incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- This is driver for the Ansel Communications Model 3200 EISA Ethernet LAN
- Adapter. The programming information is from the users manual, as related
- by glee@ardnassak.math.clemson.edu.
-
- Changelog:
-
- Paul Gortmaker 05/98 : add support for shared mem above 1MB.
-
- */
-
-static const char version[] =
- "ac3200.c:v1.01 7/1/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "8390.h"
-
-#define DRV_NAME "ac3200"
-
-/* Offsets from the base address. */
-#define AC_NIC_BASE 0x00
-#define AC_SA_PROM 0x16 /* The station address PROM. */
-#define AC_ADDR0 0x00 /* Prefix station address values. */
-#define AC_ADDR1 0x40
-#define AC_ADDR2 0x90
-#define AC_ID_PORT 0xC80
-#define AC_EISA_ID 0x0110d305
-#define AC_RESET_PORT 0xC84
-#define AC_RESET 0x00
-#define AC_ENABLE 0x01
-#define AC_CONFIG 0xC90 /* The configuration port. */
-
-#define AC_IO_EXTENT 0x20
- /* Actually accessed is:
- * AC_NIC_BASE (0-15)
- * AC_SA_PROM (0-5)
- * AC_ID_PORT (0-3)
- * AC_RESET_PORT
- * AC_CONFIG
- */
-
-/* Decoding of the configuration register. */
-static unsigned char config2irqmap[8] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
-static int addrmap[8] =
-{0xFF0000, 0xFE0000, 0xFD0000, 0xFFF0000, 0xFFE0000, 0xFFC0000, 0xD0000, 0 };
-static const char *port_name[4] = { "10baseT", "invalid", "AUI", "10base2"};
-
-#define config2irq(configval) config2irqmap[((configval) >> 3) & 7]
-#define config2mem(configval) addrmap[(configval) & 7]
-#define config2name(configval) port_name[((configval) >> 6) & 3]
-
-/* First and last 8390 pages. */
-#define AC_START_PG 0x00 /* First page of 8390 TX buffer */
-#define AC_STOP_PG 0x80 /* Last page +1 of the 8390 RX ring */
-
-static int ac_probe1(int ioaddr, struct net_device *dev);
-
-static int ac_open(struct net_device *dev);
-static void ac_reset_8390(struct net_device *dev);
-static void ac_block_input(struct net_device *dev, int count,
- struct sk_buff *skb, int ring_offset);
-static void ac_block_output(struct net_device *dev, const int count,
- const unsigned char *buf, const int start_page);
-static void ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page);
-
-static int ac_close_card(struct net_device *dev);
-
-
-/* Probe for the AC3200.
-
- The AC3200 can be identified by either the EISA configuration registers,
- or the unique value in the station address PROM.
- */
-
-static int __init do_ac3200_probe(struct net_device *dev)
-{
- unsigned short ioaddr = dev->base_addr;
- int irq = dev->irq;
- int mem_start = dev->mem_start;
-
- if (ioaddr > 0x1ff) /* Check a single specified location. */
- return ac_probe1(ioaddr, dev);
- else if (ioaddr > 0) /* Don't probe at all. */
- return -ENXIO;
-
- if ( ! EISA_bus)
- return -ENXIO;
-
- for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
- if (ac_probe1(ioaddr, dev) == 0)
- return 0;
- dev->irq = irq;
- dev->mem_start = mem_start;
- }
-
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init ac3200_probe(int unit)
-{
- struct net_device *dev = alloc_ei_netdev();
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_ac3200_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops ac_netdev_ops = {
- .ndo_open = ac_open,
- .ndo_stop = ac_close_card,
-
- .ndo_start_xmit = ei_start_xmit,
- .ndo_tx_timeout = ei_tx_timeout,
- .ndo_get_stats = ei_get_stats,
- .ndo_set_rx_mode = ei_set_multicast_list,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_change_mtu = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = ei_poll,
-#endif
-};
-
-static int __init ac_probe1(int ioaddr, struct net_device *dev)
-{
- int i, retval;
-
- if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME))
- return -EBUSY;
-
- if (inb_p(ioaddr + AC_ID_PORT) == 0xff) {
- retval = -ENODEV;
- goto out;
- }
-
- if (inl(ioaddr + AC_ID_PORT) != AC_EISA_ID) {
- retval = -ENODEV;
- goto out;
- }
-
-#ifndef final_version
- printk(KERN_DEBUG "AC3200 ethercard configuration register is %#02x,"
- " EISA ID %02x %02x %02x %02x.\n", inb(ioaddr + AC_CONFIG),
- inb(ioaddr + AC_ID_PORT + 0), inb(ioaddr + AC_ID_PORT + 1),
- inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3));
-#endif
-
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
-
- printk(KERN_DEBUG "AC3200 in EISA slot %d, node %pM",
- ioaddr/0x1000, dev->dev_addr);
-#if 0
- /* Check the vendor ID/prefix. Redundant after checking the EISA ID */
- if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
- || inb(ioaddr + AC_SA_PROM + 1) != AC_ADDR1
- || inb(ioaddr + AC_SA_PROM + 2) != AC_ADDR2 ) {
- printk(", not found (invalid prefix).\n");
- retval = -ENODEV;
- goto out;
- }
-#endif
-
- /* Assign and allocate the interrupt now. */
- if (dev->irq == 0) {
- dev->irq = config2irq(inb(ioaddr + AC_CONFIG));
- printk(", using");
- } else {
- dev->irq = irq_canonicalize(dev->irq);
- printk(", assigning");
- }
-
- retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
- if (retval) {
- printk (" nothing! Unable to get IRQ %d.\n", dev->irq);
- goto out;
- }
-
- printk(" IRQ %d, %s port\n", dev->irq, port_name[dev->if_port]);
-
- dev->base_addr = ioaddr;
-
-#ifdef notyet
- if (dev->mem_start) { /* Override the value from the board. */
- for (i = 0; i < 7; i++)
- if (addrmap[i] == dev->mem_start)
- break;
- if (i >= 7)
- i = 0;
- outb((inb(ioaddr + AC_CONFIG) & ~7) | i, ioaddr + AC_CONFIG);
- }
-#endif
-
- dev->if_port = inb(ioaddr + AC_CONFIG) >> 6;
- dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG));
-
- printk("%s: AC3200 at %#3x with %dkB memory at physical address %#lx.\n",
- dev->name, ioaddr, AC_STOP_PG/4, dev->mem_start);
-
- /*
- * BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
- * the card mem within the region covered by `normal' RAM !!!
- *
- * ioremap() will fail in that case.
- */
- ei_status.mem = ioremap(dev->mem_start, AC_STOP_PG*0x100);
- if (!ei_status.mem) {
- printk(KERN_ERR "ac3200.c: Unable to remap card memory above 1MB !!\n");
- printk(KERN_ERR "ac3200.c: Try using EISA SCU to set memory below 1MB.\n");
- printk(KERN_ERR "ac3200.c: Driver NOT installed.\n");
- retval = -EINVAL;
- goto out1;
- }
- printk("ac3200.c: remapped %dkB card memory to virtual address %p\n",
- AC_STOP_PG/4, ei_status.mem);
-
- dev->mem_start = (unsigned long)ei_status.mem;
- dev->mem_end = dev->mem_start + (AC_STOP_PG - AC_START_PG)*256;
-
- ei_status.name = "AC3200";
- ei_status.tx_start_page = AC_START_PG;
- ei_status.rx_start_page = AC_START_PG + TX_PAGES;
- ei_status.stop_page = AC_STOP_PG;
- ei_status.word16 = 1;
-
- if (ei_debug > 0)
- printk(version);
-
- ei_status.reset_8390 = &ac_reset_8390;
- ei_status.block_input = &ac_block_input;
- ei_status.block_output = &ac_block_output;
- ei_status.get_8390_hdr = &ac_get_8390_hdr;
-
- dev->netdev_ops = &ac_netdev_ops;
- NS8390_init(dev, 0);
-
- retval = register_netdev(dev);
- if (retval)
- goto out2;
- return 0;
-out2:
- if (ei_status.reg0)
- iounmap(ei_status.mem);
-out1:
- free_irq(dev->irq, dev);
-out:
- release_region(ioaddr, AC_IO_EXTENT);
- return retval;
-}
-
-static int ac_open(struct net_device *dev)
-{
-#ifdef notyet
- /* Someday we may enable the IRQ and shared memory here. */
- int ioaddr = dev->base_addr;
-#endif
-
- ei_open(dev);
- return 0;
-}
-
-static void ac_reset_8390(struct net_device *dev)
-{
- ushort ioaddr = dev->base_addr;
-
- outb(AC_RESET, ioaddr + AC_RESET_PORT);
- if (ei_debug > 1) printk("resetting AC3200, t=%ld...", jiffies);
-
- ei_status.txing = 0;
- outb(AC_ENABLE, ioaddr + AC_RESET_PORT);
- if (ei_debug > 1) printk("reset done\n");
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
- we don't need to be concerned with ring wrap as the header will be at
- the start of a page, so we optimize accordingly. */
-
-static void
-ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
- void __iomem *hdr_start = ei_status.mem + ((ring_page - AC_START_PG)<<8);
- memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-}
-
-/* Block input and output are easy on shared memory ethercards, the only
- complication is when the ring buffer wraps. */
-
-static void ac_block_input(struct net_device *dev, int count, struct sk_buff *skb,
- int ring_offset)
-{
- void __iomem *start = ei_status.mem + ring_offset - AC_START_PG*256;
-
- if (ring_offset + count > AC_STOP_PG*256) {
- /* We must wrap the input move. */
- int semi_count = AC_STOP_PG*256 - ring_offset;
- memcpy_fromio(skb->data, start, semi_count);
- count -= semi_count;
- memcpy_fromio(skb->data + semi_count,
- ei_status.mem + TX_PAGES*256, count);
- } else {
- memcpy_fromio(skb->data, start, count);
- }
-}
-
-static void ac_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- void __iomem *shmem = ei_status.mem + ((start_page - AC_START_PG)<<8);
-
- memcpy_toio(shmem, buf, count);
-}
-
-static int ac_close_card(struct net_device *dev)
-{
- if (ei_debug > 1)
- printk("%s: Shutting down ethercard.\n", dev->name);
-
-#ifdef notyet
- /* We should someday disable shared memory and interrupts. */
- outb(0x00, ioaddr + 6); /* Disable interrupts. */
- free_irq(dev->irq, dev);
-#endif
-
- ei_close(dev);
- return 0;
-}
-
-#ifdef MODULE
-#define MAX_AC32_CARDS 4 /* Max number of AC32 cards per module */
-static struct net_device *dev_ac32[MAX_AC32_CARDS];
-static int io[MAX_AC32_CARDS];
-static int irq[MAX_AC32_CARDS];
-static int mem[MAX_AC32_CARDS];
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, "Memory base address(es)");
-MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-static int __init ac3200_module_init(void)
-{
- struct net_device *dev;
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
- if (io[this_dev] == 0 && this_dev != 0)
- break;
- dev = alloc_ei_netdev();
- if (!dev)
- break;
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- dev->mem_start = mem[this_dev]; /* Currently ignored by driver */
- if (do_ac3200_probe(dev) == 0) {
- dev_ac32[found++] = dev;
- continue;
- }
- free_netdev(dev);
- printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]);
- break;
- }
- if (found)
- return 0;
- return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
- /* Someday free_irq may be in ac_close_card() */
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, AC_IO_EXTENT);
- iounmap(ei_status.mem);
-}
-
-static void __exit ac3200_module_exit(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
- struct net_device *dev = dev_ac32[this_dev];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-module_init(ac3200_module_init);
-module_exit(ac3200_module_exit);
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
index 70dba5d01ad3..cab306a9888e 100644
--- a/drivers/net/ethernet/8390/ax88796.c
+++ b/drivers/net/ethernet/8390/ax88796.c
@@ -358,7 +358,7 @@ static int ax_mii_probe(struct net_device *dev)
return -ENODEV;
}
- ret = phy_connect_direct(dev, phy_dev, ax_handle_link_change, 0,
+ ret = phy_connect_direct(dev, phy_dev, ax_handle_link_change,
PHY_INTERFACE_MODE_MII);
if (ret) {
netdev_err(dev, "Could not attach to PHY\n");
@@ -469,9 +469,9 @@ static void ax_get_drvinfo(struct net_device *dev,
{
struct platform_device *pdev = to_platform_device(dev->dev.parent);
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, pdev->name);
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pdev->name, sizeof(info->bus_info));
}
static int ax_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/8390/e2100.c b/drivers/net/ethernet/8390/e2100.c
deleted file mode 100644
index ed55ce85ebbf..000000000000
--- a/drivers/net/ethernet/8390/e2100.c
+++ /dev/null
@@ -1,489 +0,0 @@
-/* e2100.c: A Cabletron E2100 series ethernet driver for linux. */
-/*
- Written 1993-1994 by Donald Becker.
-
- Copyright 1994 by Donald Becker.
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used and
- distributed according to the terms of the GNU General Public License,
- incorporated herein by reference.
-
- This is a driver for the Cabletron E2100 series ethercards.
-
- The Author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- The E2100 series ethercard is a fairly generic shared memory 8390
- implementation. The only unusual aspect is the way the shared memory
- registers are set: first you do an inb() in what is normally the
- station address region, and the low three bits of next outb() *address*
- is used as the write value for that register. Either someone wasn't
- too used to dem bit en bites, or they were trying to obfuscate the
- programming interface.
-
- There is an additional complication when setting the window on the packet
- buffer. You must first do a read into the packet buffer region with the
- low 8 address bits the address setting the page for the start of the packet
- buffer window, and then do the above operation. See mem_on() for details.
-
- One bug on the chip is that even a hard reset won't disable the memory
- window, usually resulting in a hung machine if mem_off() isn't called.
- If this happens, you must power down the machine for about 30 seconds.
-*/
-
-static const char version[] =
- "e2100.c:v1.01 7/21/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "e2100"
-
-static int e21_probe_list[] = {0x300, 0x280, 0x380, 0x220, 0};
-
-/* Offsets from the base_addr.
- Read from the ASIC register, and the low three bits of the next outb()
- address is used to set the corresponding register. */
-#define E21_NIC_OFFSET 0 /* Offset to the 8390 NIC. */
-#define E21_ASIC 0x10
-#define E21_MEM_ENABLE 0x10
-#define E21_MEM_ON 0x05 /* Enable memory in 16 bit mode. */
-#define E21_MEM_ON_8 0x07 /* Enable memory in 8 bit mode. */
-#define E21_MEM_BASE 0x11
-#define E21_IRQ_LOW 0x12 /* The low three bits of the IRQ number. */
-#define E21_IRQ_HIGH 0x14 /* The high IRQ bit and media select ... */
-#define E21_MEDIA 0x14 /* (alias). */
-#define E21_ALT_IFPORT 0x02 /* Set to use the other (BNC,AUI) port. */
-#define E21_BIG_MEM 0x04 /* Use a bigger (64K) buffer (we don't) */
-#define E21_SAPROM 0x10 /* Offset to station address data. */
-#define E21_IO_EXTENT 0x20
-
-static inline void mem_on(short port, volatile char __iomem *mem_base,
- unsigned char start_page )
-{
- /* This is a little weird: set the shared memory window by doing a
- read. The low address bits specify the starting page. */
- readb(mem_base+start_page);
- inb(port + E21_MEM_ENABLE);
- outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
-}
-
-static inline void mem_off(short port)
-{
- inb(port + E21_MEM_ENABLE);
- outb(0x00, port + E21_MEM_ENABLE);
-}
-
-/* In other drivers I put the TX pages first, but the E2100 window circuitry
- is designed to have a 4K Tx region last. The windowing circuitry wraps the
- window at 0x2fff->0x0000 so that the packets at e.g. 0x2f00 in the RX ring
- appear contiguously in the window. */
-#define E21_RX_START_PG 0x00 /* First page of RX buffer */
-#define E21_RX_STOP_PG 0x30 /* Last page +1 of RX ring */
-#define E21_BIG_RX_STOP_PG 0xF0 /* Last page +1 of RX ring */
-#define E21_TX_START_PG E21_RX_STOP_PG /* First page of TX buffer */
-
-static int e21_probe1(struct net_device *dev, int ioaddr);
-
-static int e21_open(struct net_device *dev);
-static void e21_reset_8390(struct net_device *dev);
-static void e21_block_input(struct net_device *dev, int count,
- struct sk_buff *skb, int ring_offset);
-static void e21_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page);
-static void e21_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page);
-static int e21_open(struct net_device *dev);
-static int e21_close(struct net_device *dev);
-
-
-/* Probe for the E2100 series ethercards. These cards have an 8390 at the
- base address and the station address at both offset 0x10 and 0x18. I read
- the station address from offset 0x18 to avoid the dataport of NE2000
- ethercards, and look for Ctron's unique ID (first three octets of the
- station address).
- */
-
-static int __init do_e2100_probe(struct net_device *dev)
-{
- int *port;
- int base_addr = dev->base_addr;
- int irq = dev->irq;
-
- if (base_addr > 0x1ff) /* Check a single specified location. */
- return e21_probe1(dev, base_addr);
- else if (base_addr != 0) /* Don't probe at all. */
- return -ENXIO;
-
- for (port = e21_probe_list; *port; port++) {
- dev->irq = irq;
- if (e21_probe1(dev, *port) == 0)
- return 0;
- }
-
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init e2100_probe(int unit)
-{
- struct net_device *dev = alloc_ei_netdev();
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_e2100_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops e21_netdev_ops = {
- .ndo_open = e21_open,
- .ndo_stop = e21_close,
-
- .ndo_start_xmit = ei_start_xmit,
- .ndo_tx_timeout = ei_tx_timeout,
- .ndo_get_stats = ei_get_stats,
- .ndo_set_rx_mode = ei_set_multicast_list,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_change_mtu = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = ei_poll,
-#endif
-};
-
-static int __init e21_probe1(struct net_device *dev, int ioaddr)
-{
- int i, status, retval;
- unsigned char *station_addr = dev->dev_addr;
- static unsigned version_printed;
-
- if (!request_region(ioaddr, E21_IO_EXTENT, DRV_NAME))
- return -EBUSY;
-
- /* First check the station address for the Ctron prefix. */
- if (inb(ioaddr + E21_SAPROM + 0) != 0x00 ||
- inb(ioaddr + E21_SAPROM + 1) != 0x00 ||
- inb(ioaddr + E21_SAPROM + 2) != 0x1d) {
- retval = -ENODEV;
- goto out;
- }
-
- /* Verify by making certain that there is a 8390 at there. */
- outb(E8390_NODMA + E8390_STOP, ioaddr);
- udelay(1); /* we want to delay one I/O cycle - which is 2MHz */
- status = inb(ioaddr);
- if (status != 0x21 && status != 0x23) {
- retval = -ENODEV;
- goto out;
- }
-
- /* Read the station address PROM. */
- for (i = 0; i < 6; i++)
- station_addr[i] = inb(ioaddr + E21_SAPROM + i);
-
- inb(ioaddr + E21_MEDIA); /* Point to media selection. */
- outb(0, ioaddr + E21_ASIC); /* and disable the secondary interface. */
-
- if (ei_debug && version_printed++ == 0)
- printk(version);
-
- for (i = 0; i < 6; i++)
- printk(" %02X", station_addr[i]);
-
- if (dev->irq < 2) {
- static const int irqlist[] = {15, 11, 10, 12, 5, 9, 3, 4};
- for (i = 0; i < ARRAY_SIZE(irqlist); i++)
- if (request_irq (irqlist[i], NULL, 0, "bogus", NULL) != -EBUSY) {
- dev->irq = irqlist[i];
- break;
- }
- if (i >= ARRAY_SIZE(irqlist)) {
- printk(" unable to get IRQ %d.\n", dev->irq);
- retval = -EAGAIN;
- goto out;
- }
- } else if (dev->irq == 2) /* Fixup luser bogosity: IRQ2 is really IRQ9 */
- dev->irq = 9;
-
- /* The 8390 is at the base address. */
- dev->base_addr = ioaddr;
-
- ei_status.name = "E2100";
- ei_status.word16 = 1;
- ei_status.tx_start_page = E21_TX_START_PG;
- ei_status.rx_start_page = E21_RX_START_PG;
- ei_status.stop_page = E21_RX_STOP_PG;
- ei_status.saved_irq = dev->irq;
-
- /* Check the media port used. The port can be passed in on the
- low mem_end bits. */
- if (dev->mem_end & 15)
- dev->if_port = dev->mem_end & 7;
- else {
- dev->if_port = 0;
- inb(ioaddr + E21_MEDIA); /* Turn automatic media detection on. */
- for(i = 0; i < 6; i++)
- if (station_addr[i] != inb(ioaddr + E21_SAPROM + 8 + i)) {
- dev->if_port = 1;
- break;
- }
- }
-
- /* Never map in the E21 shared memory unless you are actively using it.
- Also, the shared memory has effective only one setting -- spread all
- over the 128K region! */
- if (dev->mem_start == 0)
- dev->mem_start = 0xd0000;
-
- ei_status.mem = ioremap(dev->mem_start, 2*1024);
- if (!ei_status.mem) {
- printk("unable to remap memory\n");
- retval = -EAGAIN;
- goto out;
- }
-
-#ifdef notdef
- /* These values are unused. The E2100 has a 2K window into the packet
- buffer. The window can be set to start on any page boundary. */
- ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
- dev->mem_end = ei_status.rmem_end = dev->mem_start + 2*1024;
-#endif
-
- printk(", IRQ %d, %s media, memory @ %#lx.\n", dev->irq,
- dev->if_port ? "secondary" : "primary", dev->mem_start);
-
- ei_status.reset_8390 = &e21_reset_8390;
- ei_status.block_input = &e21_block_input;
- ei_status.block_output = &e21_block_output;
- ei_status.get_8390_hdr = &e21_get_8390_hdr;
-
- dev->netdev_ops = &e21_netdev_ops;
- NS8390_init(dev, 0);
-
- retval = register_netdev(dev);
- if (retval)
- goto out;
- return 0;
-out:
- release_region(ioaddr, E21_IO_EXTENT);
- return retval;
-}
-
-static int
-e21_open(struct net_device *dev)
-{
- short ioaddr = dev->base_addr;
- int retval;
-
- if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)))
- return retval;
-
- /* Set the interrupt line and memory base on the hardware. */
- inb(ioaddr + E21_IRQ_LOW);
- outb(0, ioaddr + E21_ASIC + (dev->irq & 7));
- inb(ioaddr + E21_IRQ_HIGH); /* High IRQ bit, and if_port. */
- outb(0, ioaddr + E21_ASIC + (dev->irq > 7 ? 1:0)
- + (dev->if_port ? E21_ALT_IFPORT : 0));
- inb(ioaddr + E21_MEM_BASE);
- outb(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7));
-
- ei_open(dev);
- return 0;
-}
-
-static void
-e21_reset_8390(struct net_device *dev)
-{
- short ioaddr = dev->base_addr;
-
- outb(0x01, ioaddr);
- if (ei_debug > 1) printk("resetting the E2180x3 t=%ld...", jiffies);
- ei_status.txing = 0;
-
- /* Set up the ASIC registers, just in case something changed them. */
-
- if (ei_debug > 1) printk("reset done\n");
-}
-
-/* Grab the 8390 specific header. We put the 2k window so the header page
- appears at the start of the shared memory. */
-
-static void
-e21_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-
- short ioaddr = dev->base_addr;
- char __iomem *shared_mem = ei_status.mem;
-
- mem_on(ioaddr, shared_mem, ring_page);
-
-#ifdef notdef
- /* Officially this is what we are doing, but the readl() is faster */
- memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr));
-#else
- ((unsigned int*)hdr)[0] = readl(shared_mem);
-#endif
-
- /* Turn off memory access: we would need to reprogram the window anyway. */
- mem_off(ioaddr);
-
-}
-
-/* Block input and output are easy on shared memory ethercards.
- The E21xx makes block_input() especially easy by wrapping the top
- ring buffer to the bottom automatically. */
-static void
-e21_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
- short ioaddr = dev->base_addr;
- char __iomem *shared_mem = ei_status.mem;
-
- mem_on(ioaddr, shared_mem, (ring_offset>>8));
-
- memcpy_fromio(skb->data, ei_status.mem + (ring_offset & 0xff), count);
-
- mem_off(ioaddr);
-}
-
-static void
-e21_block_output(struct net_device *dev, int count, const unsigned char *buf,
- int start_page)
-{
- short ioaddr = dev->base_addr;
- volatile char __iomem *shared_mem = ei_status.mem;
-
- /* Set the shared memory window start by doing a read, with the low address
- bits specifying the starting page. */
- readb(shared_mem + start_page);
- mem_on(ioaddr, shared_mem, start_page);
-
- memcpy_toio(shared_mem, buf, count);
- mem_off(ioaddr);
-}
-
-static int
-e21_close(struct net_device *dev)
-{
- short ioaddr = dev->base_addr;
-
- if (ei_debug > 1)
- printk("%s: Shutting down ethercard.\n", dev->name);
-
- free_irq(dev->irq, dev);
- dev->irq = ei_status.saved_irq;
-
- /* Shut off the interrupt line and secondary interface. */
- inb(ioaddr + E21_IRQ_LOW);
- outb(0, ioaddr + E21_ASIC);
- inb(ioaddr + E21_IRQ_HIGH); /* High IRQ bit, and if_port. */
- outb(0, ioaddr + E21_ASIC);
-
- ei_close(dev);
-
- /* Double-check that the memory has been turned off, because really
- really bad things happen if it isn't. */
- mem_off(ioaddr);
-
- return 0;
-}
-
-
-#ifdef MODULE
-#define MAX_E21_CARDS 4 /* Max number of E21 cards per module */
-static struct net_device *dev_e21[MAX_E21_CARDS];
-static int io[MAX_E21_CARDS];
-static int irq[MAX_E21_CARDS];
-static int mem[MAX_E21_CARDS];
-static int xcvr[MAX_E21_CARDS]; /* choose int. or ext. xcvr */
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-module_param_array(xcvr, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, " memory base address(es)");
-MODULE_PARM_DESC(xcvr, "transceiver(s) (0=internal, 1=external)");
-MODULE_DESCRIPTION("Cabletron E2100 ISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-
-int __init init_module(void)
-{
- struct net_device *dev;
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
- if (io[this_dev] == 0) {
- if (this_dev != 0) break; /* only autoprobe 1st one */
- printk(KERN_NOTICE "e2100.c: Presently autoprobing (not recommended) for a single card.\n");
- }
- dev = alloc_ei_netdev();
- if (!dev)
- break;
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- dev->mem_start = mem[this_dev];
- dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */
- if (do_e2100_probe(dev) == 0) {
- dev_e21[found++] = dev;
- continue;
- }
- free_netdev(dev);
- printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]);
- break;
- }
- if (found)
- return 0;
- return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
- /* NB: e21_close() handles free_irq */
- iounmap(ei_status.mem);
- release_region(dev->base_addr, E21_IO_EXTENT);
-}
-
-void __exit
-cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
- struct net_device *dev = dev_e21[this_dev];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/es3210.c b/drivers/net/ethernet/8390/es3210.c
deleted file mode 100644
index ba1b5c95531f..000000000000
--- a/drivers/net/ethernet/8390/es3210.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- es3210.c
-
- Linux driver for Racal-Interlan ES3210 EISA Network Adapter
-
- Copyright (C) 1996, Paul Gortmaker.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- Information and Code Sources:
-
- 1) The existing myriad of Linux 8390 drivers written by Donald Becker.
-
- 2) Once again Russ Nelson's asm packet driver provided additional info.
-
- 3) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
- Too bad it doesn't work -- see below.
-
- The ES3210 is an EISA shared memory NS8390 implementation. Note
- that all memory copies to/from the board must be 32bit transfers.
- Which rules out using eth_io_copy_and_sum() in this driver.
-
- Apparently there are two slightly different revisions of the
- card, since there are two distinct EISA cfg files (!rii0101.cfg
- and !rii0102.cfg) One has media select in the cfg file and the
- other doesn't. Hopefully this will work with either.
-
- That is about all I can tell you about it, having never actually
- even seen one of these cards. :) Try http://www.interlan.com
- if you want more info.
-
- Thanks go to Mark Salazar for testing v0.02 of this driver.
-
- Bugs, to-fix, etc:
-
- 1) The EISA cfg ports that are *supposed* to have the IRQ and shared
- mem values just read 0xff all the time. Hrrmpf. Apparently the
- same happens with the packet driver as the code for reading
- these registers is disabled there. In the meantime, boot with:
- ether=<IRQ>,0,0x<shared_mem_addr>,eth0 to override the IRQ and
- shared memory detection. (The i/o port detection is okay.)
-
- 2) Module support currently untested. Probably works though.
-
-*/
-
-static const char version[] =
- "es3210.c: Driver revision v0.03, 14/09/96\n";
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-static int es_probe1(struct net_device *dev, int ioaddr);
-
-static void es_reset_8390(struct net_device *dev);
-
-static void es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
-static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
-static void es_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page);
-
-#define ES_START_PG 0x00 /* First page of TX buffer */
-#define ES_STOP_PG 0x40 /* Last page +1 of RX ring */
-
-#define ES_IO_EXTENT 0x37 /* The cfg file says 0xc90 -> 0xcc7 */
-#define ES_ID_PORT 0xc80 /* Same for all EISA cards */
-#define ES_SA_PROM 0xc90 /* Start of e'net addr. */
-#define ES_RESET_PORT 0xc84 /* From the packet driver source */
-#define ES_NIC_OFFSET 0xca0 /* Hello, the 8390 is *here* */
-
-#define ES_ADDR0 0x02 /* 3 byte vendor prefix */
-#define ES_ADDR1 0x07
-#define ES_ADDR2 0x01
-
-/*
- * Two card revisions. EISA ID's are always rev. minor, rev. major,, and
- * then the three vendor letters stored in 5 bits each, with an "a" = 1.
- * For eg: "rii" = 10010 01001 01001 = 0x4929, which is how the EISA
- * config utility determines automagically what config file(s) to use.
- */
-#define ES_EISA_ID1 0x01012949 /* !rii0101.cfg */
-#define ES_EISA_ID2 0x02012949 /* !rii0102.cfg */
-
-#define ES_CFG1 0xcc0 /* IOPORT(1) --> IOPORT(6) in cfg file */
-#define ES_CFG2 0xcc1
-#define ES_CFG3 0xcc2
-#define ES_CFG4 0xcc3
-#define ES_CFG5 0xcc4
-#define ES_CFG6 0xc84 /* NB: 0xc84 is also "reset" port. */
-
-/*
- * You can OR any of the following bits together and assign it
- * to ES_DEBUG to get verbose driver info during operation.
- * Some of these don't do anything yet.
- */
-
-#define ES_D_PROBE 0x01
-#define ES_D_RX_PKT 0x02
-#define ES_D_TX_PKT 0x04
-#define ED_D_IRQ 0x08
-
-#define ES_DEBUG 0
-
-static unsigned char lo_irq_map[] __initdata = {3, 4, 5, 6, 7, 9, 10};
-static unsigned char hi_irq_map[] __initdata = {11, 12, 0, 14, 0, 0, 0, 15};
-
-/*
- * Probe for the card. The best way is to read the EISA ID if it
- * is known. Then we check the prefix of the station address
- * PROM for a match against the Racal-Interlan assigned value.
- */
-
-static int __init do_es_probe(struct net_device *dev)
-{
- unsigned short ioaddr = dev->base_addr;
- int irq = dev->irq;
- int mem_start = dev->mem_start;
-
- if (ioaddr > 0x1ff) /* Check a single specified location. */
- return es_probe1(dev, ioaddr);
- else if (ioaddr > 0) /* Don't probe at all. */
- return -ENXIO;
-
- if (!EISA_bus) {
-#if ES_DEBUG & ES_D_PROBE
- printk("es3210.c: Not EISA bus. Not probing high ports.\n");
-#endif
- return -ENXIO;
- }
-
- /* EISA spec allows for up to 16 slots, but 8 is typical. */
- for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
- if (es_probe1(dev, ioaddr) == 0)
- return 0;
- dev->irq = irq;
- dev->mem_start = mem_start;
- }
-
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init es_probe(int unit)
-{
- struct net_device *dev = alloc_ei_netdev();
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_es_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static int __init es_probe1(struct net_device *dev, int ioaddr)
-{
- int i, retval;
- unsigned long eisa_id;
-
- if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210"))
- return -ENODEV;
-
-#if ES_DEBUG & ES_D_PROBE
- printk("es3210.c: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + ES_ID_PORT));
- printk("es3210.c: config regs: %#x %#x %#x %#x %#x %#x\n",
- inb(ioaddr + ES_CFG1), inb(ioaddr + ES_CFG2), inb(ioaddr + ES_CFG3),
- inb(ioaddr + ES_CFG4), inb(ioaddr + ES_CFG5), inb(ioaddr + ES_CFG6));
-#endif
-
-/* Check the EISA ID of the card. */
- eisa_id = inl(ioaddr + ES_ID_PORT);
- if ((eisa_id != ES_EISA_ID1) && (eisa_id != ES_EISA_ID2)) {
- retval = -ENODEV;
- goto out;
- }
-
- for (i = 0; i < ETH_ALEN ; i++)
- dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i);
-
-/* Check the Racal vendor ID as well. */
- if (dev->dev_addr[0] != ES_ADDR0 ||
- dev->dev_addr[1] != ES_ADDR1 ||
- dev->dev_addr[2] != ES_ADDR2) {
- printk("es3210.c: card not found %pM (invalid_prefix).\n",
- dev->dev_addr);
- retval = -ENODEV;
- goto out;
- }
-
- printk("es3210.c: ES3210 rev. %ld at %#x, node %pM",
- eisa_id>>24, ioaddr, dev->dev_addr);
-
- /* Snarf the interrupt now. */
- if (dev->irq == 0) {
- unsigned char hi_irq = inb(ioaddr + ES_CFG2) & 0x07;
- unsigned char lo_irq = inb(ioaddr + ES_CFG1) & 0xfe;
-
- if (hi_irq != 0) {
- dev->irq = hi_irq_map[hi_irq - 1];
- } else {
- int i = 0;
- while (lo_irq > (1<<i)) i++;
- dev->irq = lo_irq_map[i];
- }
- printk(" using IRQ %d", dev->irq);
-#if ES_DEBUG & ES_D_PROBE
- printk("es3210.c: hi_irq %#x, lo_irq %#x, dev->irq = %d\n",
- hi_irq, lo_irq, dev->irq);
-#endif
- } else {
- if (dev->irq == 2)
- dev->irq = 9; /* Doh! */
- printk(" assigning IRQ %d", dev->irq);
- }
-
- if (request_irq(dev->irq, ei_interrupt, 0, "es3210", dev)) {
- printk (" unable to get IRQ %d.\n", dev->irq);
- retval = -EAGAIN;
- goto out;
- }
-
- if (dev->mem_start == 0) {
- unsigned char mem_enabled = inb(ioaddr + ES_CFG2) & 0xc0;
- unsigned char mem_bits = inb(ioaddr + ES_CFG3) & 0x07;
-
- if (mem_enabled != 0x80) {
- printk(" shared mem disabled - giving up\n");
- retval = -ENXIO;
- goto out1;
- }
- dev->mem_start = 0xC0000 + mem_bits*0x4000;
- printk(" using ");
- } else {
- printk(" assigning ");
- }
-
- ei_status.mem = ioremap(dev->mem_start, (ES_STOP_PG - ES_START_PG)*256);
- if (!ei_status.mem) {
- printk("ioremap failed - giving up\n");
- retval = -ENXIO;
- goto out1;
- }
-
- dev->mem_end = dev->mem_start + (ES_STOP_PG - ES_START_PG)*256;
-
- printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1);
-
-#if ES_DEBUG & ES_D_PROBE
- if (inb(ioaddr + ES_CFG5))
- printk("es3210: Warning - DMA channel enabled, but not used here.\n");
-#endif
- /* Note, point at the 8390, and not the card... */
- dev->base_addr = ioaddr + ES_NIC_OFFSET;
-
- ei_status.name = "ES3210";
- ei_status.tx_start_page = ES_START_PG;
- ei_status.rx_start_page = ES_START_PG + TX_PAGES;
- ei_status.stop_page = ES_STOP_PG;
- ei_status.word16 = 1;
-
- if (ei_debug > 0)
- printk(version);
-
- ei_status.reset_8390 = &es_reset_8390;
- ei_status.block_input = &es_block_input;
- ei_status.block_output = &es_block_output;
- ei_status.get_8390_hdr = &es_get_8390_hdr;
-
- dev->netdev_ops = &ei_netdev_ops;
- NS8390_init(dev, 0);
-
- retval = register_netdev(dev);
- if (retval)
- goto out1;
- return 0;
-out1:
- free_irq(dev->irq, dev);
-out:
- release_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT);
- return retval;
-}
-
-/*
- * Reset as per the packet driver method. Judging by the EISA cfg
- * file, this just toggles the "Board Enable" bits (bit 2 and 0).
- */
-
-static void es_reset_8390(struct net_device *dev)
-{
- unsigned short ioaddr = dev->base_addr;
- unsigned long end;
-
- outb(0x04, ioaddr + ES_RESET_PORT);
- if (ei_debug > 1) printk("%s: resetting the ES3210...", dev->name);
-
- end = jiffies + 2*HZ/100;
- while ((signed)(end - jiffies) > 0) continue;
-
- ei_status.txing = 0;
- outb(0x01, ioaddr + ES_RESET_PORT);
- if (ei_debug > 1) printk("reset done\n");
-}
-
-/*
- * Note: In the following three functions is the implicit assumption
- * that the associated memcpy will only use "rep; movsl" as long as
- * we keep the counts as some multiple of doublewords. This is a
- * requirement of the hardware, and also prevents us from using
- * eth_io_copy_and_sum() since we can't guarantee it will limit
- * itself to doubleword access.
- */
-
-/*
- * Grab the 8390 specific header. Similar to the block_input routine, but
- * we don't need to be concerned with ring wrap as the header will be at
- * the start of a page, so we optimize accordingly. (A single doubleword.)
- */
-
-static void
-es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
- void __iomem *hdr_start = ei_status.mem + ((ring_page - ES_START_PG)<<8);
- memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
- hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
-}
-
-/*
- * Block input and output are easy on shared memory ethercards, the only
- * complication is when the ring buffer wraps. The count will already
- * be rounded up to a doubleword value via es_get_8390_hdr() above.
- */
-
-static void es_block_input(struct net_device *dev, int count, struct sk_buff *skb,
- int ring_offset)
-{
- void __iomem *xfer_start = ei_status.mem + ring_offset - ES_START_PG*256;
-
- if (ring_offset + count > ES_STOP_PG*256) {
- /* Packet wraps over end of ring buffer. */
- int semi_count = ES_STOP_PG*256 - ring_offset;
- memcpy_fromio(skb->data, xfer_start, semi_count);
- count -= semi_count;
- memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
- } else {
- /* Packet is in one chunk. */
- memcpy_fromio(skb->data, xfer_start, count);
- }
-}
-
-static void es_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- void __iomem *shmem = ei_status.mem + ((start_page - ES_START_PG)<<8);
-
- count = (count + 3) & ~3; /* Round up to doubleword */
- memcpy_toio(shmem, buf, count);
-}
-
-#ifdef MODULE
-#define MAX_ES_CARDS 4 /* Max number of ES3210 cards per module */
-#define NAMELEN 8 /* # of chars for storing dev->name */
-static struct net_device *dev_es3210[MAX_ES_CARDS];
-static int io[MAX_ES_CARDS];
-static int irq[MAX_ES_CARDS];
-static int mem[MAX_ES_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, "memory base address(es)");
-MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
- struct net_device *dev;
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
- if (io[this_dev] == 0 && this_dev != 0)
- break;
- dev = alloc_ei_netdev();
- if (!dev)
- break;
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- dev->mem_start = mem[this_dev];
- if (do_es_probe(dev) == 0) {
- dev_es3210[found++] = dev;
- continue;
- }
- free_netdev(dev);
- printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]);
- break;
- }
- if (found)
- return 0;
- return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, ES_IO_EXTENT);
- iounmap(ei_status.mem);
-}
-
-void __exit
-cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
- struct net_device *dev = dev_es3210[this_dev];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
-
diff --git a/drivers/net/ethernet/8390/hp-plus.c b/drivers/net/ethernet/8390/hp-plus.c
deleted file mode 100644
index 52f70f999c00..000000000000
--- a/drivers/net/ethernet/8390/hp-plus.c
+++ /dev/null
@@ -1,505 +0,0 @@
-/* hp-plus.c: A HP PCLAN/plus ethernet driver for linux. */
-/*
- Written 1994 by Donald Becker.
-
- This driver is for the Hewlett Packard PC LAN (27***) plus ethercards.
- These cards are sold under several model numbers, usually 2724*.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- As is often the case, a great deal of credit is owed to Russ Nelson.
- The Crynwr packet driver was my primary source of HP-specific
- programming information.
-*/
-
-static const char version[] =
-"hp-plus.c:v1.10 9/24/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-
-#include <linux/string.h> /* Important -- this inlines word moves. */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "hp-plus"
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int hpplus_portlist[] __initdata =
-{0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
-
-/*
- The HP EtherTwist chip implementation is a fairly routine DP8390
- implementation. It allows both shared memory and programmed-I/O buffer
- access, using a custom interface for both. The programmed-I/O mode is
- entirely implemented in the HP EtherTwist chip, bypassing the problem
- ridden built-in 8390 facilities used on NE2000 designs. The shared
- memory mode is likewise special, with an offset register used to make
- packets appear at the shared memory base. Both modes use a base and bounds
- page register to hide the Rx ring buffer wrap -- a packet that spans the
- end of physical buffer memory appears continuous to the driver. (c.f. the
- 3c503 and Cabletron E2100)
-
- A special note: the internal buffer of the board is only 8 bits wide.
- This lays several nasty traps for the unaware:
- - the 8390 must be programmed for byte-wide operations
- - all I/O and memory operations must work on whole words (the access
- latches are serially preloaded and have no byte-swapping ability).
-
- This board is laid out in I/O space much like the earlier HP boards:
- the first 16 locations are for the board registers, and the second 16 are
- for the 8390. The board is easy to identify, with both a dedicated 16 bit
- ID register and a constant 0x530* value in the upper bits of the paging
- register.
-*/
-
-#define HP_ID 0x00 /* ID register, always 0x4850. */
-#define HP_PAGING 0x02 /* Registers visible @ 8-f, see PageName. */
-#define HPP_OPTION 0x04 /* Bitmapped options, see HP_Option. */
-#define HPP_OUT_ADDR 0x08 /* I/O output location in Perf_Page. */
-#define HPP_IN_ADDR 0x0A /* I/O input location in Perf_Page. */
-#define HP_DATAPORT 0x0c /* I/O data transfer in Perf_Page. */
-#define NIC_OFFSET 0x10 /* Offset to the 8390 registers. */
-#define HP_IO_EXTENT 32
-
-#define HP_START_PG 0x00 /* First page of TX buffer */
-#define HP_STOP_PG 0x80 /* Last page +1 of RX ring */
-
-/* The register set selected in HP_PAGING. */
-enum PageName {
- Perf_Page = 0, /* Normal operation. */
- MAC_Page = 1, /* The ethernet address (+checksum). */
- HW_Page = 2, /* EEPROM-loaded hardware parameters. */
- LAN_Page = 4, /* Transceiver selection, testing, etc. */
- ID_Page = 6 };
-
-/* The bit definitions for the HPP_OPTION register. */
-enum HP_Option {
- NICReset = 1, ChipReset = 2, /* Active low, really UNreset. */
- EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20,
- MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, };
-
-static int hpp_probe1(struct net_device *dev, int ioaddr);
-
-static void hpp_reset_8390(struct net_device *dev);
-static int hpp_open(struct net_device *dev);
-static int hpp_close(struct net_device *dev);
-static void hpp_mem_block_input(struct net_device *dev, int count,
- struct sk_buff *skb, int ring_offset);
-static void hpp_mem_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page);
-static void hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page);
-static void hpp_io_block_input(struct net_device *dev, int count,
- struct sk_buff *skb, int ring_offset);
-static void hpp_io_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page);
-static void hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page);
-
-
-/* Probe a list of addresses for an HP LAN+ adaptor.
- This routine is almost boilerplate. */
-
-static int __init do_hpp_probe(struct net_device *dev)
-{
- int i;
- int base_addr = dev->base_addr;
- int irq = dev->irq;
-
- if (base_addr > 0x1ff) /* Check a single specified location. */
- return hpp_probe1(dev, base_addr);
- else if (base_addr != 0) /* Don't probe at all. */
- return -ENXIO;
-
- for (i = 0; hpplus_portlist[i]; i++) {
- if (hpp_probe1(dev, hpplus_portlist[i]) == 0)
- return 0;
- dev->irq = irq;
- }
-
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init hp_plus_probe(int unit)
-{
- struct net_device *dev = alloc_eip_netdev();
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_hpp_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops hpp_netdev_ops = {
- .ndo_open = hpp_open,
- .ndo_stop = hpp_close,
- .ndo_start_xmit = eip_start_xmit,
- .ndo_tx_timeout = eip_tx_timeout,
- .ndo_get_stats = eip_get_stats,
- .ndo_set_rx_mode = eip_set_multicast_list,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_change_mtu = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = eip_poll,
-#endif
-};
-
-
-/* Do the interesting part of the probe at a single address. */
-static int __init hpp_probe1(struct net_device *dev, int ioaddr)
-{
- int i, retval;
- unsigned char checksum = 0;
- const char name[] = "HP-PC-LAN+";
- int mem_start;
- static unsigned version_printed;
-
- if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
- return -EBUSY;
-
- /* Check for the HP+ signature, 50 48 0x 53. */
- if (inw(ioaddr + HP_ID) != 0x4850 ||
- (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) {
- retval = -ENODEV;
- goto out;
- }
-
- if (ei_debug && version_printed++ == 0)
- printk(version);
-
- printk("%s: %s at %#3x, ", dev->name, name, ioaddr);
-
- /* Retrieve and checksum the station address. */
- outw(MAC_Page, ioaddr + HP_PAGING);
-
- for(i = 0; i < ETH_ALEN; i++) {
- unsigned char inval = inb(ioaddr + 8 + i);
- dev->dev_addr[i] = inval;
- checksum += inval;
- }
- checksum += inb(ioaddr + 14);
-
- printk("%pM", dev->dev_addr);
-
- if (checksum != 0xff) {
- printk(" bad checksum %2.2x.\n", checksum);
- retval = -ENODEV;
- goto out;
- } else {
- /* Point at the Software Configuration Flags. */
- outw(ID_Page, ioaddr + HP_PAGING);
- printk(" ID %4.4x", inw(ioaddr + 12));
- }
-
- /* Read the IRQ line. */
- outw(HW_Page, ioaddr + HP_PAGING);
- {
- int irq = inb(ioaddr + 13) & 0x0f;
- int option = inw(ioaddr + HPP_OPTION);
-
- dev->irq = irq;
- if (option & MemEnable) {
- mem_start = inw(ioaddr + 9) << 8;
- printk(", IRQ %d, memory address %#x.\n", irq, mem_start);
- } else {
- mem_start = 0;
- printk(", IRQ %d, programmed-I/O mode.\n", irq);
- }
- }
-
- /* Set the wrap registers for string I/O reads. */
- outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
-
- /* Set the base address to point to the NIC, not the "real" base! */
- dev->base_addr = ioaddr + NIC_OFFSET;
-
- dev->netdev_ops = &hpp_netdev_ops;
-
- ei_status.name = name;
- ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */
- ei_status.tx_start_page = HP_START_PG;
- ei_status.rx_start_page = HP_START_PG + TX_PAGES/2;
- ei_status.stop_page = HP_STOP_PG;
-
- ei_status.reset_8390 = &hpp_reset_8390;
- ei_status.block_input = &hpp_io_block_input;
- ei_status.block_output = &hpp_io_block_output;
- ei_status.get_8390_hdr = &hpp_io_get_8390_hdr;
-
- /* Check if the memory_enable flag is set in the option register. */
- if (mem_start) {
- ei_status.block_input = &hpp_mem_block_input;
- ei_status.block_output = &hpp_mem_block_output;
- ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
- dev->mem_start = mem_start;
- ei_status.mem = ioremap(mem_start,
- (HP_STOP_PG - HP_START_PG)*256);
- if (!ei_status.mem) {
- retval = -ENOMEM;
- goto out;
- }
- ei_status.rmem_start = dev->mem_start + TX_PAGES/2*256;
- dev->mem_end = ei_status.rmem_end
- = dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
- }
-
- outw(Perf_Page, ioaddr + HP_PAGING);
- NS8390p_init(dev, 0);
- /* Leave the 8390 and HP chip reset. */
- outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
-
- retval = register_netdev(dev);
- if (retval)
- goto out1;
- return 0;
-out1:
- iounmap(ei_status.mem);
-out:
- release_region(ioaddr, HP_IO_EXTENT);
- return retval;
-}
-
-static int
-hpp_open(struct net_device *dev)
-{
- int ioaddr = dev->base_addr - NIC_OFFSET;
- int option_reg;
- int retval;
-
- if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
- return retval;
- }
-
- /* Reset the 8390 and HP chip. */
- option_reg = inw(ioaddr + HPP_OPTION);
- outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
- udelay(5);
- /* Unreset the board and enable interrupts. */
- outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
-
- /* Set the wrap registers for programmed-I/O operation. */
- outw(HW_Page, ioaddr + HP_PAGING);
- outw((HP_START_PG + TX_PAGES/2) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
-
- /* Select the operational page. */
- outw(Perf_Page, ioaddr + HP_PAGING);
-
- return eip_open(dev);
-}
-
-static int
-hpp_close(struct net_device *dev)
-{
- int ioaddr = dev->base_addr - NIC_OFFSET;
- int option_reg = inw(ioaddr + HPP_OPTION);
-
- free_irq(dev->irq, dev);
- eip_close(dev);
- outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
- ioaddr + HPP_OPTION);
-
- return 0;
-}
-
-static void
-hpp_reset_8390(struct net_device *dev)
-{
- int ioaddr = dev->base_addr - NIC_OFFSET;
- int option_reg = inw(ioaddr + HPP_OPTION);
-
- if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
-
- outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
- /* Pause a few cycles for the hardware reset to take place. */
- udelay(5);
- ei_status.txing = 0;
- outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
-
- udelay(5);
-
-
- if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
- printk("%s: hp_reset_8390() did not complete.\n", dev->name);
-
- if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
-}
-
-/* The programmed-I/O version of reading the 4 byte 8390 specific header.
- Note that transfer with the EtherTwist+ must be on word boundaries. */
-
-static void
-hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
- int ioaddr = dev->base_addr - NIC_OFFSET;
-
- outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
- insw(ioaddr + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
-}
-
-/* Block input and output, similar to the Crynwr packet driver. */
-
-static void
-hpp_io_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
- int ioaddr = dev->base_addr - NIC_OFFSET;
- char *buf = skb->data;
-
- outw(ring_offset, ioaddr + HPP_IN_ADDR);
- insw(ioaddr + HP_DATAPORT, buf, count>>1);
- if (count & 0x01)
- buf[count-1] = inw(ioaddr + HP_DATAPORT);
-}
-
-/* The corresponding shared memory versions of the above 2 functions. */
-
-static void
-hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
- int ioaddr = dev->base_addr - NIC_OFFSET;
- int option_reg = inw(ioaddr + HPP_OPTION);
-
- outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
- outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
- memcpy_fromio(hdr, ei_status.mem, sizeof(struct e8390_pkt_hdr));
- outw(option_reg, ioaddr + HPP_OPTION);
- hdr->count = (le16_to_cpu(hdr->count) + 3) & ~3; /* Round up allocation. */
-}
-
-static void
-hpp_mem_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
- int ioaddr = dev->base_addr - NIC_OFFSET;
- int option_reg = inw(ioaddr + HPP_OPTION);
-
- outw(ring_offset, ioaddr + HPP_IN_ADDR);
-
- outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
-
- /* Caution: this relies on get_8390_hdr() rounding up count!
- Also note that we *can't* use eth_io_copy_and_sum() because
- it will not always copy "count" bytes (e.g. padded IP). */
-
- memcpy_fromio(skb->data, ei_status.mem, count);
- outw(option_reg, ioaddr + HPP_OPTION);
-}
-
-/* A special note: we *must* always transfer >=16 bit words.
- It's always safe to round up, so we do. */
-static void
-hpp_io_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- int ioaddr = dev->base_addr - NIC_OFFSET;
- outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
- outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2);
-}
-
-static void
-hpp_mem_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- int ioaddr = dev->base_addr - NIC_OFFSET;
- int option_reg = inw(ioaddr + HPP_OPTION);
-
- outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
- outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
- memcpy_toio(ei_status.mem, buf, (count + 3) & ~3);
- outw(option_reg, ioaddr + HPP_OPTION);
-}
-
-
-#ifdef MODULE
-#define MAX_HPP_CARDS 4 /* Max number of HPP cards per module */
-static struct net_device *dev_hpp[MAX_HPP_CARDS];
-static int io[MAX_HPP_CARDS];
-static int irq[MAX_HPP_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O port address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s); ignored if properly detected");
-MODULE_DESCRIPTION("HP PC-LAN+ ISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-int __init
-init_module(void)
-{
- struct net_device *dev;
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
- if (io[this_dev] == 0) {
- if (this_dev != 0) break; /* only autoprobe 1st one */
- printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n");
- }
- dev = alloc_eip_netdev();
- if (!dev)
- break;
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- if (do_hpp_probe(dev) == 0) {
- dev_hpp[found++] = dev;
- continue;
- }
- free_netdev(dev);
- printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
- break;
- }
- if (found)
- return 0;
- return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
- /* NB: hpp_close() handles free_irq */
- iounmap(ei_status.mem);
- release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
-void __exit
-cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
- struct net_device *dev = dev_hpp[this_dev];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/hp.c b/drivers/net/ethernet/8390/hp.c
deleted file mode 100644
index 37fa89aa4578..000000000000
--- a/drivers/net/ethernet/8390/hp.c
+++ /dev/null
@@ -1,438 +0,0 @@
-/* hp.c: A HP LAN ethernet driver for linux. */
-/*
- Written 1993-94 by Donald Becker.
-
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- This is a driver for the HP PC-LAN adaptors.
-
- Sources:
- The Crynwr packet driver.
-*/
-
-static const char version[] =
- "hp.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "hp"
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int hppclan_portlist[] __initdata =
-{ 0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
-
-#define HP_IO_EXTENT 32
-
-#define HP_DATAPORT 0x0c /* "Remote DMA" data port. */
-#define HP_ID 0x07
-#define HP_CONFIGURE 0x08 /* Configuration register. */
-#define HP_RUN 0x01 /* 1 == Run, 0 == reset. */
-#define HP_IRQ 0x0E /* Mask for software-configured IRQ line. */
-#define HP_DATAON 0x10 /* Turn on dataport */
-#define NIC_OFFSET 0x10 /* Offset the 8390 registers. */
-
-#define HP_START_PG 0x00 /* First page of TX buffer */
-#define HP_8BSTOP_PG 0x80 /* Last page +1 of RX ring */
-#define HP_16BSTOP_PG 0xFF /* Same, for 16 bit cards. */
-
-static int hp_probe1(struct net_device *dev, int ioaddr);
-
-static void hp_reset_8390(struct net_device *dev);
-static void hp_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page);
-static void hp_block_input(struct net_device *dev, int count,
- struct sk_buff *skb , int ring_offset);
-static void hp_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page);
-
-static void hp_init_card(struct net_device *dev);
-
-/* The map from IRQ number to HP_CONFIGURE register setting. */
-/* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */
-static char irqmap[16] __initdata= { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
-
-
-/* Probe for an HP LAN adaptor.
- Also initialize the card and fill in STATION_ADDR with the station
- address. */
-
-static int __init do_hp_probe(struct net_device *dev)
-{
- int i;
- int base_addr = dev->base_addr;
- int irq = dev->irq;
-
- if (base_addr > 0x1ff) /* Check a single specified location. */
- return hp_probe1(dev, base_addr);
- else if (base_addr != 0) /* Don't probe at all. */
- return -ENXIO;
-
- for (i = 0; hppclan_portlist[i]; i++) {
- if (hp_probe1(dev, hppclan_portlist[i]) == 0)
- return 0;
- dev->irq = irq;
- }
-
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init hp_probe(int unit)
-{
- struct net_device *dev = alloc_eip_netdev();
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_hp_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static int __init hp_probe1(struct net_device *dev, int ioaddr)
-{
- int i, retval, board_id, wordmode;
- const char *name;
- static unsigned version_printed;
-
- if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
- return -EBUSY;
-
- /* Check for the HP physical address, 08 00 09 xx xx xx. */
- /* This really isn't good enough: we may pick up HP LANCE boards
- also! Avoid the lance 0x5757 signature. */
- if (inb(ioaddr) != 0x08
- || inb(ioaddr+1) != 0x00
- || inb(ioaddr+2) != 0x09
- || inb(ioaddr+14) == 0x57) {
- retval = -ENODEV;
- goto out;
- }
-
- /* Set up the parameters based on the board ID.
- If you have additional mappings, please mail them to me -djb. */
- if ((board_id = inb(ioaddr + HP_ID)) & 0x80) {
- name = "HP27247";
- wordmode = 1;
- } else {
- name = "HP27250";
- wordmode = 0;
- }
-
- if (ei_debug && version_printed++ == 0)
- printk(version);
-
- printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
-
- for(i = 0; i < ETH_ALEN; i++)
- dev->dev_addr[i] = inb(ioaddr + i);
-
- printk(" %pM", dev->dev_addr);
-
- /* Snarf the interrupt now. Someday this could be moved to open(). */
- if (dev->irq < 2) {
- static const int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
- static const int irq_8list[] = { 7, 5, 3, 4, 9, 0};
- const int *irqp = wordmode ? irq_16list : irq_8list;
- do {
- int irq = *irqp;
- if (request_irq (irq, NULL, 0, "bogus", NULL) != -EBUSY) {
- unsigned long cookie = probe_irq_on();
- /* Twinkle the interrupt, and check if it's seen. */
- outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE);
- outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
- if (irq == probe_irq_off(cookie) /* It's a good IRQ line! */
- && request_irq (irq, eip_interrupt, 0, DRV_NAME, dev) == 0) {
- printk(" selecting IRQ %d.\n", irq);
- dev->irq = *irqp;
- break;
- }
- }
- } while (*++irqp);
- if (*irqp == 0) {
- printk(" no free IRQ lines.\n");
- retval = -EBUSY;
- goto out;
- }
- } else {
- if (dev->irq == 2)
- dev->irq = 9;
- if ((retval = request_irq(dev->irq, eip_interrupt, 0, DRV_NAME, dev))) {
- printk (" unable to get IRQ %d.\n", dev->irq);
- goto out;
- }
- }
-
- /* Set the base address to point to the NIC, not the "real" base! */
- dev->base_addr = ioaddr + NIC_OFFSET;
- dev->netdev_ops = &eip_netdev_ops;
-
- ei_status.name = name;
- ei_status.word16 = wordmode;
- ei_status.tx_start_page = HP_START_PG;
- ei_status.rx_start_page = HP_START_PG + TX_PAGES;
- ei_status.stop_page = wordmode ? HP_16BSTOP_PG : HP_8BSTOP_PG;
-
- ei_status.reset_8390 = hp_reset_8390;
- ei_status.get_8390_hdr = hp_get_8390_hdr;
- ei_status.block_input = hp_block_input;
- ei_status.block_output = hp_block_output;
- hp_init_card(dev);
-
- retval = register_netdev(dev);
- if (retval)
- goto out1;
- return 0;
-out1:
- free_irq(dev->irq, dev);
-out:
- release_region(ioaddr, HP_IO_EXTENT);
- return retval;
-}
-
-static void
-hp_reset_8390(struct net_device *dev)
-{
- int hp_base = dev->base_addr - NIC_OFFSET;
- int saved_config = inb_p(hp_base + HP_CONFIGURE);
-
- if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
- outb_p(0x00, hp_base + HP_CONFIGURE);
- ei_status.txing = 0;
- /* Pause just a few cycles for the hardware reset to take place. */
- udelay(5);
-
- outb_p(saved_config, hp_base + HP_CONFIGURE);
- udelay(5);
-
- if ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
- printk("%s: hp_reset_8390() did not complete.\n", dev->name);
-
- if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
-}
-
-static void
-hp_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
- int nic_base = dev->base_addr;
- int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
-
- outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
- outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
- outb_p(0, nic_base + EN0_RCNTHI);
- outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */
- outb_p(ring_page, nic_base + EN0_RSARHI);
- outb_p(E8390_RREAD+E8390_START, nic_base);
-
- if (ei_status.word16)
- insw(nic_base - NIC_OFFSET + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
- else
- insb(nic_base - NIC_OFFSET + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
-
- outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-}
-
-/* Block input and output, similar to the Crynwr packet driver. If you are
- porting to a new ethercard look at the packet driver source for hints.
- The HP LAN doesn't use shared memory -- we put the packet
- out through the "remote DMA" dataport. */
-
-static void
-hp_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
- int nic_base = dev->base_addr;
- int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
- int xfer_count = count;
- char *buf = skb->data;
-
- outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
- outb_p(count & 0xff, nic_base + EN0_RCNTLO);
- outb_p(count >> 8, nic_base + EN0_RCNTHI);
- outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
- outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
- outb_p(E8390_RREAD+E8390_START, nic_base);
- if (ei_status.word16) {
- insw(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
- if (count & 0x01)
- buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
- } else {
- insb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
- }
- /* This is for the ALPHA version only, remove for later releases. */
- if (ei_debug > 0) { /* DMA termination address check... */
- int high = inb_p(nic_base + EN0_RSARHI);
- int low = inb_p(nic_base + EN0_RSARLO);
- int addr = (high << 8) + low;
- /* Check only the lower 8 bits so we can ignore ring wrap. */
- if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
- printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
- dev->name, ring_offset + xfer_count, addr);
- }
- outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-}
-
-static void
-hp_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- int nic_base = dev->base_addr;
- int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
-
- outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
- /* Round the count up for word writes. Do we need to do this?
- What effect will an odd byte count have on the 8390?
- I should check someday. */
- if (ei_status.word16 && (count & 0x01))
- count++;
- /* We should already be in page 0, but to be safe... */
- outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
-
-#ifdef NE8390_RW_BUGFIX
- /* Handle the read-before-write bug the same way as the
- Crynwr packet driver -- the NatSemi method doesn't work. */
- outb_p(0x42, nic_base + EN0_RCNTLO);
- outb_p(0, nic_base + EN0_RCNTHI);
- outb_p(0xff, nic_base + EN0_RSARLO);
- outb_p(0x00, nic_base + EN0_RSARHI);
-#define NE_CMD 0x00
- outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
- /* Make certain that the dummy read has occurred. */
- inb_p(0x61);
- inb_p(0x61);
-#endif
-
- outb_p(count & 0xff, nic_base + EN0_RCNTLO);
- outb_p(count >> 8, nic_base + EN0_RCNTHI);
- outb_p(0x00, nic_base + EN0_RSARLO);
- outb_p(start_page, nic_base + EN0_RSARHI);
-
- outb_p(E8390_RWRITE+E8390_START, nic_base);
- if (ei_status.word16) {
- /* Use the 'rep' sequence for 16 bit boards. */
- outsw(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
- } else {
- outsb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
- }
-
- /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
-
- /* This is for the ALPHA version only, remove for later releases. */
- if (ei_debug > 0) { /* DMA termination address check... */
- int high = inb_p(nic_base + EN0_RSARHI);
- int low = inb_p(nic_base + EN0_RSARLO);
- int addr = (high << 8) + low;
- if ((start_page << 8) + count != addr)
- printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
- dev->name, (start_page << 8) + count, addr);
- }
- outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-}
-
-/* This function resets the ethercard if something screws up. */
-static void __init
-hp_init_card(struct net_device *dev)
-{
- int irq = dev->irq;
- NS8390p_init(dev, 0);
- outb_p(irqmap[irq&0x0f] | HP_RUN,
- dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
-}
-
-#ifdef MODULE
-#define MAX_HP_CARDS 4 /* Max number of HP cards per module */
-static struct net_device *dev_hp[MAX_HP_CARDS];
-static int io[MAX_HP_CARDS];
-static int irq[MAX_HP_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_DESCRIPTION("HP PC-LAN ISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-int __init
-init_module(void)
-{
- struct net_device *dev;
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
- if (io[this_dev] == 0) {
- if (this_dev != 0) break; /* only autoprobe 1st one */
- printk(KERN_NOTICE "hp.c: Presently autoprobing (not recommended) for a single card.\n");
- }
- dev = alloc_eip_netdev();
- if (!dev)
- break;
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- if (do_hp_probe(dev) == 0) {
- dev_hp[found++] = dev;
- continue;
- }
- free_netdev(dev);
- printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]);
- break;
- }
- if (found)
- return 0;
- return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
- release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
-}
-
-void __exit
-cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
- struct net_device *dev = dev_hp[this_dev];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/8390/lne390.c b/drivers/net/ethernet/8390/lne390.c
deleted file mode 100644
index 479409bf2e3c..000000000000
--- a/drivers/net/ethernet/8390/lne390.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- lne390.c
-
- Linux driver for Mylex LNE390 EISA Network Adapter
-
- Copyright (C) 1996-1998, Paul Gortmaker.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- Information and Code Sources:
-
- 1) Based upon framework of es3210 driver.
- 2) The existing myriad of other Linux 8390 drivers by Donald Becker.
- 3) Russ Nelson's asm packet driver provided additional info.
- 4) Info for getting IRQ and sh-mem gleaned from the EISA cfg files.
-
- The LNE390 is an EISA shared memory NS8390 implementation. Note
- that all memory copies to/from the board must be 32bit transfers.
- There are two versions of the card: the lne390a and the lne390b.
- Going by the EISA cfg files, the "a" has jumpers to select between
- BNC/AUI, but the "b" also has RJ-45 and selection is via the SCU.
- The shared memory address selection is also slightly different.
- Note that shared memory address > 1MB are supported with this driver.
-
- You can try <http://www.mylex.com> if you want more info, as I've
- never even seen one of these cards. :)
-
- Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/09/01
- - get rid of check_region
- - no need to check if dev == NULL in lne390_probe1
-*/
-
-static const char *version =
- "lne390.c: Driver revision v0.99.1, 01/09/2000\n";
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "lne390"
-
-static int lne390_probe1(struct net_device *dev, int ioaddr);
-
-static void lne390_reset_8390(struct net_device *dev);
-
-static void lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
-static void lne390_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
-static void lne390_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page);
-
-#define LNE390_START_PG 0x00 /* First page of TX buffer */
-#define LNE390_STOP_PG 0x80 /* Last page +1 of RX ring */
-
-#define LNE390_ID_PORT 0xc80 /* Same for all EISA cards */
-#define LNE390_IO_EXTENT 0x20
-#define LNE390_SA_PROM 0x16 /* Start of e'net addr. */
-#define LNE390_RESET_PORT 0xc84 /* From the pkt driver source */
-#define LNE390_NIC_OFFSET 0x00 /* Hello, the 8390 is *here* */
-
-#define LNE390_ADDR0 0x00 /* 3 byte vendor prefix */
-#define LNE390_ADDR1 0x80
-#define LNE390_ADDR2 0xe5
-
-#define LNE390_ID0 0x10009835 /* 0x3598 = 01101 01100 11000 = mlx */
-#define LNE390_ID1 0x11009835 /* above is the 390A, this is 390B */
-
-#define LNE390_CFG1 0xc84 /* NB: 0xc84 is also "reset" port. */
-#define LNE390_CFG2 0xc90
-
-/*
- * You can OR any of the following bits together and assign it
- * to LNE390_DEBUG to get verbose driver info during operation.
- * Currently only the probe one is implemented.
- */
-
-#define LNE390_D_PROBE 0x01
-#define LNE390_D_RX_PKT 0x02
-#define LNE390_D_TX_PKT 0x04
-#define LNE390_D_IRQ 0x08
-
-#define LNE390_DEBUG 0
-
-static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
-static unsigned int shmem_mapA[] __initdata = {0xff, 0xfe, 0xfd, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
-static unsigned int shmem_mapB[] __initdata = {0xff, 0xfe, 0x0e, 0xfff, 0xffe, 0xffc, 0x0d, 0x0};
-
-/*
- * Probe for the card. The best way is to read the EISA ID if it
- * is known. Then we can check the prefix of the station address
- * PROM for a match against the value assigned to Mylex.
- */
-
-static int __init do_lne390_probe(struct net_device *dev)
-{
- unsigned short ioaddr = dev->base_addr;
- int irq = dev->irq;
- int mem_start = dev->mem_start;
- int ret;
-
- if (ioaddr > 0x1ff) { /* Check a single specified location. */
- if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
- return -EBUSY;
- ret = lne390_probe1(dev, ioaddr);
- if (ret)
- release_region(ioaddr, LNE390_IO_EXTENT);
- return ret;
- }
- else if (ioaddr > 0) /* Don't probe at all. */
- return -ENXIO;
-
- if (!EISA_bus) {
-#if LNE390_DEBUG & LNE390_D_PROBE
- printk("lne390-debug: Not an EISA bus. Not probing high ports.\n");
-#endif
- return -ENXIO;
- }
-
- /* EISA spec allows for up to 16 slots, but 8 is typical. */
- for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
- if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
- continue;
- if (lne390_probe1(dev, ioaddr) == 0)
- return 0;
- release_region(ioaddr, LNE390_IO_EXTENT);
- dev->irq = irq;
- dev->mem_start = mem_start;
- }
-
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init lne390_probe(int unit)
-{
- struct net_device *dev = alloc_ei_netdev();
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_lne390_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static int __init lne390_probe1(struct net_device *dev, int ioaddr)
-{
- int i, revision, ret;
- unsigned long eisa_id;
-
- if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
-
-#if LNE390_DEBUG & LNE390_D_PROBE
- printk("lne390-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + LNE390_ID_PORT));
- printk("lne390-debug: config regs: %#x %#x\n",
- inb(ioaddr + LNE390_CFG1), inb(ioaddr + LNE390_CFG2));
-#endif
-
-
-/* Check the EISA ID of the card. */
- eisa_id = inl(ioaddr + LNE390_ID_PORT);
- if ((eisa_id != LNE390_ID0) && (eisa_id != LNE390_ID1)) {
- return -ENODEV;
- }
-
- revision = (eisa_id >> 24) & 0x01; /* 0 = rev A, 1 rev B */
-
-#if 0
-/* Check the Mylex vendor ID as well. Not really required. */
- if (inb(ioaddr + LNE390_SA_PROM + 0) != LNE390_ADDR0
- || inb(ioaddr + LNE390_SA_PROM + 1) != LNE390_ADDR1
- || inb(ioaddr + LNE390_SA_PROM + 2) != LNE390_ADDR2 ) {
- printk("lne390.c: card not found");
- for (i = 0; i < ETH_ALEN; i++)
- printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i));
- printk(" (invalid prefix).\n");
- return -ENODEV;
- }
-#endif
-
- for (i = 0; i < ETH_ALEN; i++)
- dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
- printk("lne390.c: LNE390%X in EISA slot %d, address %pM.\n",
- 0xa+revision, ioaddr/0x1000, dev->dev_addr);
-
- printk("lne390.c: ");
-
- /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
- if (dev->irq == 0) {
- unsigned char irq_reg = inb(ioaddr + LNE390_CFG2) >> 3;
- dev->irq = irq_map[irq_reg & 0x07];
- printk("using");
- } else {
- /* This is useless unless we reprogram the card here too */
- if (dev->irq == 2) dev->irq = 9; /* Doh! */
- printk("assigning");
- }
- printk(" IRQ %d,", dev->irq);
-
- if ((ret = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev))) {
- printk (" unable to get IRQ %d.\n", dev->irq);
- return ret;
- }
-
- if (dev->mem_start == 0) {
- unsigned char mem_reg = inb(ioaddr + LNE390_CFG2) & 0x07;
-
- if (revision) /* LNE390B */
- dev->mem_start = shmem_mapB[mem_reg] * 0x10000;
- else /* LNE390A */
- dev->mem_start = shmem_mapA[mem_reg] * 0x10000;
- printk(" using ");
- } else {
- /* Should check for value in shmem_map and reprogram the card to use it */
- dev->mem_start &= 0xfff0000;
- printk(" assigning ");
- }
-
- printk("%dkB memory at physical address %#lx\n",
- LNE390_STOP_PG/4, dev->mem_start);
-
- /*
- BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
- the card mem within the region covered by `normal' RAM !!!
-
- ioremap() will fail in that case.
- */
- ei_status.mem = ioremap(dev->mem_start, LNE390_STOP_PG*0x100);
- if (!ei_status.mem) {
- printk(KERN_ERR "lne390.c: Unable to remap card memory above 1MB !!\n");
- printk(KERN_ERR "lne390.c: Try using EISA SCU to set memory below 1MB.\n");
- printk(KERN_ERR "lne390.c: Driver NOT installed.\n");
- ret = -EAGAIN;
- goto cleanup;
- }
- printk("lne390.c: remapped %dkB card memory to virtual address %p\n",
- LNE390_STOP_PG/4, ei_status.mem);
-
- dev->mem_start = (unsigned long)ei_status.mem;
- dev->mem_end = dev->mem_start + (LNE390_STOP_PG - LNE390_START_PG)*256;
-
- /* The 8390 offset is zero for the LNE390 */
- dev->base_addr = ioaddr;
-
- ei_status.name = "LNE390";
- ei_status.tx_start_page = LNE390_START_PG;
- ei_status.rx_start_page = LNE390_START_PG + TX_PAGES;
- ei_status.stop_page = LNE390_STOP_PG;
- ei_status.word16 = 1;
-
- if (ei_debug > 0)
- printk(version);
-
- ei_status.reset_8390 = &lne390_reset_8390;
- ei_status.block_input = &lne390_block_input;
- ei_status.block_output = &lne390_block_output;
- ei_status.get_8390_hdr = &lne390_get_8390_hdr;
-
- dev->netdev_ops = &ei_netdev_ops;
- NS8390_init(dev, 0);
-
- ret = register_netdev(dev);
- if (ret)
- goto unmap;
- return 0;
-unmap:
- if (ei_status.reg0)
- iounmap(ei_status.mem);
-cleanup:
- free_irq(dev->irq, dev);
- return ret;
-}
-
-/*
- * Reset as per the packet driver method. Judging by the EISA cfg
- * file, this just toggles the "Board Enable" bits (bit 2 and 0).
- */
-
-static void lne390_reset_8390(struct net_device *dev)
-{
- unsigned short ioaddr = dev->base_addr;
-
- outb(0x04, ioaddr + LNE390_RESET_PORT);
- if (ei_debug > 1) printk("%s: resetting the LNE390...", dev->name);
-
- mdelay(2);
-
- ei_status.txing = 0;
- outb(0x01, ioaddr + LNE390_RESET_PORT);
- if (ei_debug > 1) printk("reset done\n");
-}
-
-/*
- * Note: In the following three functions is the implicit assumption
- * that the associated memcpy will only use "rep; movsl" as long as
- * we keep the counts as some multiple of doublewords. This is a
- * requirement of the hardware, and also prevents us from using
- * eth_io_copy_and_sum() since we can't guarantee it will limit
- * itself to doubleword access.
- */
-
-/*
- * Grab the 8390 specific header. Similar to the block_input routine, but
- * we don't need to be concerned with ring wrap as the header will be at
- * the start of a page, so we optimize accordingly. (A single doubleword.)
- */
-
-static void
-lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
- void __iomem *hdr_start = ei_status.mem + ((ring_page - LNE390_START_PG)<<8);
- memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
- hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
-}
-
-/*
- * Block input and output are easy on shared memory ethercards, the only
- * complication is when the ring buffer wraps. The count will already
- * be rounded up to a doubleword value via lne390_get_8390_hdr() above.
- */
-
-static void lne390_block_input(struct net_device *dev, int count, struct sk_buff *skb,
- int ring_offset)
-{
- void __iomem *xfer_start = ei_status.mem + ring_offset - (LNE390_START_PG<<8);
-
- if (ring_offset + count > (LNE390_STOP_PG<<8)) {
- /* Packet wraps over end of ring buffer. */
- int semi_count = (LNE390_STOP_PG<<8) - ring_offset;
- memcpy_fromio(skb->data, xfer_start, semi_count);
- count -= semi_count;
- memcpy_fromio(skb->data + semi_count,
- ei_status.mem + (TX_PAGES<<8), count);
- } else {
- /* Packet is in one chunk. */
- memcpy_fromio(skb->data, xfer_start, count);
- }
-}
-
-static void lne390_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- void __iomem *shmem = ei_status.mem + ((start_page - LNE390_START_PG)<<8);
-
- count = (count + 3) & ~3; /* Round up to doubleword */
- memcpy_toio(shmem, buf, count);
-}
-
-
-#ifdef MODULE
-#define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */
-static struct net_device *dev_lne[MAX_LNE_CARDS];
-static int io[MAX_LNE_CARDS];
-static int irq[MAX_LNE_CARDS];
-static int mem[MAX_LNE_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s)");
-MODULE_PARM_DESC(mem, "memory base address(es)");
-MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
- struct net_device *dev;
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
- if (io[this_dev] == 0 && this_dev != 0)
- break;
- dev = alloc_ei_netdev();
- if (!dev)
- break;
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- dev->mem_start = mem[this_dev];
- if (do_lne390_probe(dev) == 0) {
- dev_lne[found++] = dev;
- continue;
- }
- free_netdev(dev);
- printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]);
- break;
- }
- if (found)
- return 0;
- return -ENXIO;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, LNE390_IO_EXTENT);
- iounmap(ei_status.mem);
-}
-
-void __exit cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
- struct net_device *dev = dev_lne[this_dev];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
-
diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c
index c0c127913dec..587a885de259 100644
--- a/drivers/net/ethernet/8390/ne2k-pci.c
+++ b/drivers/net/ethernet/8390/ne2k-pci.c
@@ -374,7 +374,6 @@ static int ne2k_pci_init_one(struct pci_dev *pdev,
NS8390_init(dev, 0);
memcpy(dev->dev_addr, SA_prom, dev->addr_len);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
i = register_netdev(dev);
if (i)
diff --git a/drivers/net/ethernet/8390/ne3210.c b/drivers/net/ethernet/8390/ne3210.c
deleted file mode 100644
index ebcdb52ec739..000000000000
--- a/drivers/net/ethernet/8390/ne3210.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- ne3210.c
-
- Linux driver for Novell NE3210 EISA Network Adapter
-
- Copyright (C) 1998, Paul Gortmaker.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- Information and Code Sources:
-
- 1) Based upon my other EISA 8390 drivers (lne390, es3210, smc-ultra32)
- 2) The existing myriad of other Linux 8390 drivers by Donald Becker.
- 3) Info for getting IRQ and sh-mem gleaned from the EISA cfg file
-
- The NE3210 is an EISA shared memory NS8390 implementation. Shared
- memory address > 1MB should work with this driver.
-
- Note that the .cfg file (3/11/93, v1.0) has AUI and BNC switched
- around (or perhaps there are some defective/backwards cards ???)
-
- This driver WILL NOT WORK FOR THE NE3200 - it is completely different
- and does not use an 8390 at all.
-
- Updated to EISA probing API 5/2003 by Marc Zyngier.
-*/
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "ne3210"
-
-static void ne3210_reset_8390(struct net_device *dev);
-
-static void ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
-static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset);
-static void ne3210_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page);
-
-#define NE3210_START_PG 0x00 /* First page of TX buffer */
-#define NE3210_STOP_PG 0x80 /* Last page +1 of RX ring */
-
-#define NE3210_IO_EXTENT 0x20
-#define NE3210_SA_PROM 0x16 /* Start of e'net addr. */
-#define NE3210_RESET_PORT 0xc84
-#define NE3210_NIC_OFFSET 0x00 /* Hello, the 8390 is *here* */
-
-#define NE3210_ADDR0 0x00 /* 3 byte vendor prefix */
-#define NE3210_ADDR1 0x00
-#define NE3210_ADDR2 0x1b
-
-#define NE3210_CFG1 0xc84 /* NB: 0xc84 is also "reset" port. */
-#define NE3210_CFG2 0xc90
-#define NE3210_CFG_EXTENT (NE3210_CFG2 - NE3210_CFG1 + 1)
-
-/*
- * You can OR any of the following bits together and assign it
- * to NE3210_DEBUG to get verbose driver info during operation.
- * Currently only the probe one is implemented.
- */
-
-#define NE3210_D_PROBE 0x01
-#define NE3210_D_RX_PKT 0x02
-#define NE3210_D_TX_PKT 0x04
-#define NE3210_D_IRQ 0x08
-
-#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 * const ifmap[] __initconst = {"UTP", "?", "BNC", "AUI"};
-static int ifmap_val[] __initdata = {
- IF_PORT_10BASET,
- IF_PORT_UNKNOWN,
- IF_PORT_10BASE2,
- IF_PORT_AUI,
-};
-
-static int __init ne3210_eisa_probe (struct device *device)
-{
- unsigned long ioaddr, phys_mem;
- int i, retval, port_index;
- struct eisa_device *edev = to_eisa_device (device);
- struct net_device *dev;
-
- /* Allocate dev->priv and fill in 8390 specific dev fields. */
- if (!(dev = alloc_ei_netdev ())) {
- printk ("ne3210.c: unable to allocate memory for dev!\n");
- return -ENOMEM;
- }
-
- SET_NETDEV_DEV(dev, device);
- dev_set_drvdata(device, dev);
- ioaddr = edev->base_addr;
-
- if (!request_region(ioaddr, NE3210_IO_EXTENT, DRV_NAME)) {
- retval = -EBUSY;
- goto out;
- }
-
- if (!request_region(ioaddr + NE3210_CFG1,
- NE3210_CFG_EXTENT, DRV_NAME)) {
- retval = -EBUSY;
- goto out1;
- }
-
-#if NE3210_DEBUG & NE3210_D_PROBE
- printk("ne3210-debug: probe at %#x, ID %s\n", ioaddr, edev->id.sig);
- printk("ne3210-debug: config regs: %#x %#x\n",
- inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
-#endif
-
- port_index = inb(ioaddr + NE3210_CFG2) >> 6;
- for (i = 0; i < ETH_ALEN; i++)
- dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
- printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %pM.\n",
- edev->slot, ifmap[port_index], dev->dev_addr);
-
- /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
- dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
- printk("ne3210.c: using IRQ %d, ", dev->irq);
-
- retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
- if (retval) {
- printk (" unable to get IRQ %d.\n", dev->irq);
- goto out2;
- }
-
- phys_mem = shmem_map[inb(ioaddr + NE3210_CFG2) & 0x07] * 0x1000;
-
- /*
- BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
- the card mem within the region covered by `normal' RAM !!!
- */
- if (phys_mem > 1024*1024) { /* phys addr > 1MB */
- if (phys_mem < virt_to_phys(high_memory)) {
- printk(KERN_CRIT "ne3210.c: Card RAM overlaps with normal memory!!!\n");
- printk(KERN_CRIT "ne3210.c: Use EISA SCU to set card memory below 1MB,\n");
- printk(KERN_CRIT "ne3210.c: or to an address above 0x%llx.\n",
- (u64)virt_to_phys(high_memory));
- printk(KERN_CRIT "ne3210.c: Driver NOT installed.\n");
- retval = -EINVAL;
- goto out3;
- }
- }
-
- if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, DRV_NAME)) {
- printk ("ne3210.c: Unable to request shared memory at physical address %#lx\n",
- phys_mem);
- goto out3;
- }
-
- printk("%dkB memory at physical address %#lx\n",
- NE3210_STOP_PG/4, phys_mem);
-
- ei_status.mem = ioremap(phys_mem, NE3210_STOP_PG*0x100);
- if (!ei_status.mem) {
- printk(KERN_ERR "ne3210.c: Unable to remap card memory !!\n");
- printk(KERN_ERR "ne3210.c: Driver NOT installed.\n");
- retval = -EAGAIN;
- goto out4;
- }
- printk("ne3210.c: remapped %dkB card memory to virtual address %p\n",
- NE3210_STOP_PG/4, ei_status.mem);
- dev->mem_start = (unsigned long)ei_status.mem;
- dev->mem_end = dev->mem_start + (NE3210_STOP_PG - NE3210_START_PG)*256;
-
- /* The 8390 offset is zero for the NE3210 */
- dev->base_addr = ioaddr;
-
- ei_status.name = "NE3210";
- ei_status.tx_start_page = NE3210_START_PG;
- ei_status.rx_start_page = NE3210_START_PG + TX_PAGES;
- ei_status.stop_page = NE3210_STOP_PG;
- ei_status.word16 = 1;
- ei_status.priv = phys_mem;
-
- if (ei_debug > 0)
- printk("ne3210 loaded.\n");
-
- ei_status.reset_8390 = &ne3210_reset_8390;
- ei_status.block_input = &ne3210_block_input;
- ei_status.block_output = &ne3210_block_output;
- ei_status.get_8390_hdr = &ne3210_get_8390_hdr;
-
- dev->netdev_ops = &ei_netdev_ops;
-
- dev->if_port = ifmap_val[port_index];
-
- if ((retval = register_netdev (dev)))
- goto out5;
-
- NS8390_init(dev, 0);
- return 0;
-
- out5:
- iounmap(ei_status.mem);
- out4:
- release_mem_region (phys_mem, NE3210_STOP_PG*0x100);
- out3:
- free_irq (dev->irq, dev);
- out2:
- release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
- out1:
- release_region (ioaddr, NE3210_IO_EXTENT);
- out:
- free_netdev (dev);
-
- return retval;
-}
-
-static int ne3210_eisa_remove(struct device *device)
-{
- struct net_device *dev = dev_get_drvdata(device);
- unsigned long ioaddr = to_eisa_device (device)->base_addr;
-
- unregister_netdev (dev);
- iounmap(ei_status.mem);
- release_mem_region (ei_status.priv, NE3210_STOP_PG*0x100);
- free_irq (dev->irq, dev);
- release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
- release_region (ioaddr, NE3210_IO_EXTENT);
- free_netdev (dev);
-
- return 0;
-}
-
-/*
- * Reset by toggling the "Board Enable" bits (bit 2 and 0).
- */
-
-static void ne3210_reset_8390(struct net_device *dev)
-{
- unsigned short ioaddr = dev->base_addr;
-
- outb(0x04, ioaddr + NE3210_RESET_PORT);
- if (ei_debug > 1) printk("%s: resetting the NE3210...", dev->name);
-
- mdelay(2);
-
- ei_status.txing = 0;
- outb(0x01, ioaddr + NE3210_RESET_PORT);
- if (ei_debug > 1) printk("reset done\n");
-}
-
-/*
- * Note: In the following three functions is the implicit assumption
- * that the associated memcpy will only use "rep; movsl" as long as
- * we keep the counts as some multiple of doublewords. This is a
- * requirement of the hardware, and also prevents us from using
- * eth_io_copy_and_sum() since we can't guarantee it will limit
- * itself to doubleword access.
- */
-
-/*
- * Grab the 8390 specific header. Similar to the block_input routine, but
- * we don't need to be concerned with ring wrap as the header will be at
- * the start of a page, so we optimize accordingly. (A single doubleword.)
- */
-
-static void
-ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
- void __iomem *hdr_start = ei_status.mem + ((ring_page - NE3210_START_PG)<<8);
- memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
- hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
-}
-
-/*
- * Block input and output are easy on shared memory ethercards, the only
- * complication is when the ring buffer wraps. The count will already
- * be rounded up to a doubleword value via ne3210_get_8390_hdr() above.
- */
-
-static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff *skb,
- int ring_offset)
-{
- void __iomem *start = ei_status.mem + ring_offset - NE3210_START_PG*256;
-
- if (ring_offset + count > NE3210_STOP_PG*256) {
- /* Packet wraps over end of ring buffer. */
- int semi_count = NE3210_STOP_PG*256 - ring_offset;
- memcpy_fromio(skb->data, start, semi_count);
- count -= semi_count;
- memcpy_fromio(skb->data + semi_count,
- ei_status.mem + TX_PAGES*256, count);
- } else {
- /* Packet is in one chunk. */
- memcpy_fromio(skb->data, start, count);
- }
-}
-
-static void ne3210_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- void __iomem *shmem = ei_status.mem + ((start_page - NE3210_START_PG)<<8);
-
- count = (count + 3) & ~3; /* Round up to doubleword */
- memcpy_toio(shmem, buf, count);
-}
-
-static struct eisa_device_id ne3210_ids[] = {
- { "EGL0101" },
- { "NVL1801" },
- { "" },
-};
-MODULE_DEVICE_TABLE(eisa, ne3210_ids);
-
-static struct eisa_driver ne3210_eisa_driver = {
- .id_table = ne3210_ids,
- .driver = {
- .name = "ne3210",
- .probe = ne3210_eisa_probe,
- .remove = ne3210_eisa_remove,
- },
-};
-
-MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(eisa, ne3210_ids);
-
-static int ne3210_init(void)
-{
- return eisa_driver_register (&ne3210_eisa_driver);
-}
-
-static void ne3210_cleanup(void)
-{
- eisa_driver_unregister (&ne3210_eisa_driver);
-}
-
-module_init (ne3210_init);
-module_exit (ne3210_cleanup);
diff --git a/drivers/net/ethernet/8390/smc-ultra32.c b/drivers/net/ethernet/8390/smc-ultra32.c
deleted file mode 100644
index 923e42aedcfd..000000000000
--- a/drivers/net/ethernet/8390/smc-ultra32.c
+++ /dev/null
@@ -1,463 +0,0 @@
-/* smc-ultra32.c: An SMC Ultra32 EISA ethernet driver for linux.
-
-Sources:
-
- This driver is based on (cloned from) the ISA SMC Ultra driver
- written by Donald Becker. Modifications to support the EISA
- version of the card by Paul Gortmaker and Leonard N. Zubkoff.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
-Theory of Operation:
-
- The SMC Ultra32C card uses the SMC 83c790 chip which is also
- found on the ISA SMC Ultra cards. It has a shared memory mode of
- operation that makes it similar to the ISA version of the card.
- The main difference is that the EISA card has 32KB of RAM, but
- only an 8KB window into that memory. The EISA card also can be
- set for a bus-mastering mode of operation via the ECU, but that
- is not (and probably will never be) supported by this driver.
- The ECU should be run to enable shared memory and to disable the
- bus-mastering feature for use with linux.
-
- By programming the 8390 to use only 8KB RAM, the modifications
- to the ISA driver can be limited to the probe and initialization
- code. This allows easy integration of EISA support into the ISA
- driver. However, the driver development kit from SMC provided the
- register information for sliding the 8KB window, and hence the 8390
- is programmed to use the full 32KB RAM.
-
- Unfortunately this required code changes outside the probe/init
- routines, and thus we decided to separate the EISA driver from
- the ISA one. In this way, ISA users don't end up with a larger
- driver due to the EISA code, and EISA users don't end up with a
- larger driver due to the ISA EtherEZ PIO code. The driver is
- similar to the 3c503/16 driver, in that the window must be set
- back to the 1st 8KB of space for access to the two 8390 Tx slots.
-
- In testing, using only 8KB RAM (3 Tx / 5 Rx) didn't appear to
- be a limiting factor, since the EISA bus could get packets off
- the card fast enough, but having the use of lots of RAM as Rx
- space is extra insurance if interrupt latencies become excessive.
-
-*/
-
-static const char *version = "smc-ultra32.c: 06/97 v1.00\n";
-
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "smc-ultra32"
-
-static int ultra32_probe1(struct net_device *dev, int ioaddr);
-static int ultra32_open(struct net_device *dev);
-static void ultra32_reset_8390(struct net_device *dev);
-static void ultra32_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page);
-static void ultra32_block_input(struct net_device *dev, int count,
- struct sk_buff *skb, int ring_offset);
-static void ultra32_block_output(struct net_device *dev, int count,
- const unsigned char *buf,
- const int start_page);
-static int ultra32_close(struct net_device *dev);
-
-#define ULTRA32_CMDREG 0 /* Offset to ASIC command register. */
-#define ULTRA32_RESET 0x80 /* Board reset, in ULTRA32_CMDREG. */
-#define ULTRA32_MEMENB 0x40 /* Enable the shared memory. */
-#define ULTRA32_NIC_OFFSET 16 /* NIC register offset from the base_addr. */
-#define ULTRA32_IO_EXTENT 32
-#define EN0_ERWCNT 0x08 /* Early receive warning count. */
-
-/*
- * Defines that apply only to the Ultra32 EISA card. Note that
- * "smc" = 10011 01101 00011 = 0x4da3, and hence !smc8010.cfg translates
- * into an EISA ID of 0x1080A34D
- */
-#define ULTRA32_BASE 0xca0
-#define ULTRA32_ID 0x1080a34d
-#define ULTRA32_IDPORT (-0x20) /* 0xc80 */
-/* Config regs 1->7 from the EISA !SMC8010.CFG file. */
-#define ULTRA32_CFG1 0x04 /* 0xca4 */
-#define ULTRA32_CFG2 0x05 /* 0xca5 */
-#define ULTRA32_CFG3 (-0x18) /* 0xc88 */
-#define ULTRA32_CFG4 (-0x17) /* 0xc89 */
-#define ULTRA32_CFG5 (-0x16) /* 0xc8a */
-#define ULTRA32_CFG6 (-0x15) /* 0xc8b */
-#define ULTRA32_CFG7 0x0d /* 0xcad */
-
-static void cleanup_card(struct net_device *dev)
-{
- int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET;
- /* NB: ultra32_close_card() does free_irq */
- release_region(ioaddr, ULTRA32_IO_EXTENT);
- iounmap(ei_status.mem);
-}
-
-/* Probe for the Ultra32. This looks like a 8013 with the station
- address PROM at I/O ports <base>+8 to <base>+13, with a checksum
- following.
-*/
-
-struct net_device * __init ultra32_probe(int unit)
-{
- struct net_device *dev;
- int base;
- int irq;
- int err = -ENODEV;
-
- if (!EISA_bus)
- return ERR_PTR(-ENODEV);
-
- dev = alloc_ei_netdev();
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
-
- irq = dev->irq;
-
- /* EISA spec allows for up to 16 slots, but 8 is typical. */
- for (base = 0x1000 + ULTRA32_BASE; base < 0x9000; base += 0x1000) {
- if (ultra32_probe1(dev, base) == 0)
- break;
- dev->irq = irq;
- }
- if (base >= 0x9000)
- goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
-out1:
- cleanup_card(dev);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-
-static const struct net_device_ops ultra32_netdev_ops = {
- .ndo_open = ultra32_open,
- .ndo_stop = ultra32_close,
- .ndo_start_xmit = ei_start_xmit,
- .ndo_tx_timeout = ei_tx_timeout,
- .ndo_get_stats = ei_get_stats,
- .ndo_set_rx_mode = ei_set_multicast_list,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_change_mtu = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = ei_poll,
-#endif
-};
-
-static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
-{
- int i, edge, media, retval;
- int checksum = 0;
- const char *model_name;
- static unsigned version_printed;
- /* Values from various config regs. */
- unsigned char idreg;
- unsigned char reg4;
- const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
-
- if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME))
- return -EBUSY;
-
- if (inb(ioaddr + ULTRA32_IDPORT) == 0xff ||
- inl(ioaddr + ULTRA32_IDPORT) != ULTRA32_ID) {
- retval = -ENODEV;
- goto out;
- }
-
- media = inb(ioaddr + ULTRA32_CFG7) & 0x03;
- edge = inb(ioaddr + ULTRA32_CFG5) & 0x08;
- printk("SMC Ultra32 in EISA Slot %d, Media: %s, %s IRQs.\n",
- ioaddr >> 12, ifmap[media],
- (edge ? "Edge Triggered" : "Level Sensitive"));
-
- idreg = inb(ioaddr + 7);
- reg4 = inb(ioaddr + 4) & 0x7f;
-
- /* Check the ID nibble. */
- if ((idreg & 0xf0) != 0x20) { /* SMC Ultra */
- retval = -ENODEV;
- goto out;
- }
-
- /* Select the station address register set. */
- outb(reg4, ioaddr + 4);
-
- for (i = 0; i < 8; i++)
- checksum += inb(ioaddr + 8 + i);
- if ((checksum & 0xff) != 0xff) {
- retval = -ENODEV;
- goto out;
- }
-
- if (ei_debug && version_printed++ == 0)
- printk(version);
-
- model_name = "SMC Ultra32";
-
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = inb(ioaddr + 8 + i);
-
- printk("%s: %s at 0x%X, %pM",
- dev->name, model_name, ioaddr, dev->dev_addr);
-
- /* Switch from the station address to the alternate register set and
- read the useful registers there. */
- outb(0x80 | reg4, ioaddr + 4);
-
- /* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */
- outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
-
- /* Reset RAM addr. */
- outb(0x00, ioaddr + 0x0b);
-
- /* Switch back to the station address register set so that the
- MS-DOS driver can find the card after a warm boot. */
- outb(reg4, ioaddr + 4);
-
- if ((inb(ioaddr + ULTRA32_CFG5) & 0x40) == 0) {
- printk("\nsmc-ultra32: Card RAM is disabled! "
- "Run EISA config utility.\n");
- retval = -ENODEV;
- goto out;
- }
- if ((inb(ioaddr + ULTRA32_CFG2) & 0x04) == 0)
- printk("\nsmc-ultra32: Ignoring Bus-Master enable bit. "
- "Run EISA config utility.\n");
-
- if (dev->irq < 2) {
- unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15};
- int irq = irqmap[inb(ioaddr + ULTRA32_CFG5) & 0x07];
- if (irq == 0) {
- printk(", failed to detect IRQ line.\n");
- retval = -EAGAIN;
- goto out;
- }
- dev->irq = irq;
- }
-
- /* The 8390 isn't at the base address, so fake the offset */
- dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET;
-
- /* Save RAM address in the unused reg0 to avoid excess inb's. */
- ei_status.reg0 = inb(ioaddr + ULTRA32_CFG3) & 0xfc;
-
- dev->mem_start = 0xc0000 + ((ei_status.reg0 & 0x7c) << 11);
-
- ei_status.name = model_name;
- ei_status.word16 = 1;
- ei_status.tx_start_page = 0;
- ei_status.rx_start_page = TX_PAGES;
- /* All Ultra32 cards have 32KB memory with an 8KB window. */
- ei_status.stop_page = 128;
-
- ei_status.mem = ioremap(dev->mem_start, 0x2000);
- if (!ei_status.mem) {
- printk(", failed to ioremap.\n");
- retval = -ENOMEM;
- goto out;
- }
- dev->mem_end = dev->mem_start + 0x1fff;
-
- printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n",
- dev->irq, dev->mem_start, dev->mem_end);
- ei_status.block_input = &ultra32_block_input;
- ei_status.block_output = &ultra32_block_output;
- ei_status.get_8390_hdr = &ultra32_get_8390_hdr;
- ei_status.reset_8390 = &ultra32_reset_8390;
-
- dev->netdev_ops = &ultra32_netdev_ops;
- NS8390_init(dev, 0);
-
- return 0;
-out:
- release_region(ioaddr, ULTRA32_IO_EXTENT);
- return retval;
-}
-
-static int ultra32_open(struct net_device *dev)
-{
- int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */
- int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : IRQF_SHARED;
- int retval;
-
- retval = request_irq(dev->irq, ei_interrupt, irq_flags, dev->name, dev);
- if (retval)
- return retval;
-
- outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
- outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
- outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */
- outb(0x01, ioaddr + 6); /* Enable Interrupts. */
- /* Set the early receive warning level in window 0 high enough not
- to receive ERW interrupts. */
- outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
- outb(0xff, dev->base_addr + EN0_ERWCNT);
- ei_open(dev);
- return 0;
-}
-
-static int ultra32_close(struct net_device *dev)
-{
- int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* CMDREG */
-
- netif_stop_queue(dev);
-
- if (ei_debug > 1)
- printk("%s: Shutting down ethercard.\n", dev->name);
-
- outb(0x00, ioaddr + ULTRA32_CFG6); /* Disable Interrupts. */
- outb(0x00, ioaddr + 6); /* Disable interrupts. */
- free_irq(dev->irq, dev);
-
- NS8390_init(dev, 0);
-
- return 0;
-}
-
-static void ultra32_reset_8390(struct net_device *dev)
-{
- int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC base addr */
-
- outb(ULTRA32_RESET, ioaddr);
- if (ei_debug > 1) printk("resetting Ultra32, t=%ld...", jiffies);
- ei_status.txing = 0;
-
- outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */
- outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */
- outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */
- outb(0x01, ioaddr + 6); /* Enable Interrupts. */
- if (ei_debug > 1) printk("reset done\n");
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
- we don't need to be concerned with ring wrap as the header will be at
- the start of a page, so we optimize accordingly. */
-
-static void ultra32_get_8390_hdr(struct net_device *dev,
- struct e8390_pkt_hdr *hdr,
- int ring_page)
-{
- void __iomem *hdr_start = ei_status.mem + ((ring_page & 0x1f) << 8);
- unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
-
- /* Select correct 8KB Window. */
- outb(ei_status.reg0 | ((ring_page & 0x60) >> 5), RamReg);
-
-#ifdef __BIG_ENDIAN
- /* Officially this is what we are doing, but the readl() is faster */
- /* unfortunately it isn't endian aware of the struct */
- memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
- hdr->count = le16_to_cpu(hdr->count);
-#else
- ((unsigned int*)hdr)[0] = readl(hdr_start);
-#endif
-}
-
-/* Block input and output are easy on shared memory ethercards, the only
- complication is when the ring buffer wraps, or in this case, when a
- packet spans an 8KB boundary. Note that the current 8KB segment is
- already set by the get_8390_hdr routine. */
-
-static void ultra32_block_input(struct net_device *dev,
- int count,
- struct sk_buff *skb,
- int ring_offset)
-{
- void __iomem *xfer_start = ei_status.mem + (ring_offset & 0x1fff);
- unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
-
- if ((ring_offset & ~0x1fff) != ((ring_offset + count - 1) & ~0x1fff)) {
- int semi_count = 8192 - (ring_offset & 0x1FFF);
- memcpy_fromio(skb->data, xfer_start, semi_count);
- count -= semi_count;
- if (ring_offset < 96*256) {
- /* Select next 8KB Window. */
- ring_offset += semi_count;
- outb(ei_status.reg0 | ((ring_offset & 0x6000) >> 13), RamReg);
- memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
- } else {
- /* Select first 8KB Window. */
- outb(ei_status.reg0, RamReg);
- memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
- }
- } else {
- memcpy_fromio(skb->data, xfer_start, count);
- }
-}
-
-static void ultra32_block_output(struct net_device *dev,
- int count,
- const unsigned char *buf,
- int start_page)
-{
- void __iomem *xfer_start = ei_status.mem + (start_page<<8);
- unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3;
-
- /* Select first 8KB Window. */
- outb(ei_status.reg0, RamReg);
-
- memcpy_toio(xfer_start, buf, count);
-}
-
-#ifdef MODULE
-#define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */
-static struct net_device *dev_ultra[MAX_ULTRA32_CARDS];
-
-MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver");
-MODULE_LICENSE("GPL");
-
-int __init init_module(void)
-{
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
- struct net_device *dev = ultra32_probe(-1);
- if (IS_ERR(dev))
- break;
- dev_ultra[found++] = dev;
- }
- if (found)
- return 0;
- printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n");
- return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
- struct net_device *dev = dev_ultra[this_dev];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
-
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index e4ff38949112..ed956e08d38b 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -135,7 +135,6 @@ config ETHOC
source "drivers/net/ethernet/packetengines/Kconfig"
source "drivers/net/ethernet/pasemi/Kconfig"
source "drivers/net/ethernet/qlogic/Kconfig"
-source "drivers/net/ethernet/racal/Kconfig"
source "drivers/net/ethernet/realtek/Kconfig"
source "drivers/net/ethernet/renesas/Kconfig"
source "drivers/net/ethernet/rdc/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index d4473072654a..8268d85f9448 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -53,7 +53,6 @@ obj-$(CONFIG_ETHOC) += ethoc.o
obj-$(CONFIG_NET_PACKET_ENGINE) += packetengines/
obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
-obj-$(CONFIG_NET_VENDOR_RACAL) += racal/
obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
obj-$(CONFIG_SH_ETH) += renesas/
obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
index c1fdb8be8bee..a175d0be1ae1 100644
--- a/drivers/net/ethernet/adi/bfin_mac.c
+++ b/drivers/net/ethernet/adi/bfin_mac.c
@@ -425,8 +425,8 @@ static int mii_probe(struct net_device *dev, int phy_mode)
return -EINVAL;
}
- phydev = phy_connect(dev, dev_name(&phydev->dev), &bfin_mac_adjust_link,
- 0, phy_mode);
+ phydev = phy_connect(dev, dev_name(&phydev->dev),
+ &bfin_mac_adjust_link, phy_mode);
if (IS_ERR(phydev)) {
netdev_err(dev, "could not attach PHY\n");
@@ -498,10 +498,10 @@ bfin_mac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, KBUILD_MODNAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->fw_version, "N/A");
- strcpy(info->bus_info, dev_name(&dev->dev));
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+ strlcpy(info->bus_info, dev_name(&dev->dev), sizeof(info->bus_info));
}
static void bfin_mac_ethtool_getwol(struct net_device *dev,
@@ -647,7 +647,6 @@ static int bfin_mac_set_mac_address(struct net_device *dev, void *p)
if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
setup_mac_addr(dev->dev_addr);
return 0;
}
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index aa53115bb38b..0be2195e5034 100644
--- a/drivers/net/ethernet/aeroflex/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -1127,10 +1127,11 @@ static void greth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *in
{
struct greth_private *greth = netdev_priv(dev);
- strncpy(info->driver, dev_driver_string(greth->dev), 32);
- strncpy(info->version, "revision: 1.0", 32);
- strncpy(info->bus_info, greth->dev->bus->name, 32);
- strncpy(info->fw_version, "N/A", 32);
+ strlcpy(info->driver, dev_driver_string(greth->dev),
+ sizeof(info->driver));
+ strlcpy(info->version, "revision: 1.0", sizeof(info->version));
+ strlcpy(info->bus_info, greth->dev->bus->name, sizeof(info->bus_info));
+ strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
info->eedump_len = 0;
info->regdump_len = sizeof(struct greth_regs);
}
@@ -1287,9 +1288,7 @@ static int greth_mdio_probe(struct net_device *dev)
}
ret = phy_connect_direct(dev, phy, &greth_link_change,
- 0, greth->gbit_mac ?
- PHY_INTERFACE_MODE_GMII :
- PHY_INTERFACE_MODE_MII);
+ greth->gbit_mac ? PHY_INTERFACE_MODE_GMII : PHY_INTERFACE_MODE_MII);
if (ret) {
if (netif_msg_ifup(greth))
dev_err(&dev->dev, "could not attach to PHY\n");
diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
index 8350f4b37a8a..13d74aa4033d 100644
--- a/drivers/net/ethernet/amd/Kconfig
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -7,7 +7,7 @@ config NET_VENDOR_AMD
default y
depends on DIO || MACH_DECSTATION || MVME147 || ATARI || SUN3 || \
SUN3X || SBUS || PCI || ZORRO || (ISA && ISA_DMA_API) || \
- (ARM && ARCH_EBSA110) || ISA || EISA || MCA || PCMCIA
+ (ARM && ARCH_EBSA110) || ISA || EISA || PCMCIA
---help---
If you have a network (Ethernet) chipset belonging to this class,
say Y.
@@ -105,19 +105,6 @@ config DECLANCE
DEC (now Compaq) based on the AMD LANCE chipset, including the
DEPCA series. (This chipset is better known via the NE2100 cards.)
-config DEPCA
- tristate "DEPCA, DE10x, DE200, DE201, DE202, DE422 support"
- depends on (ISA || EISA || MCA)
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto> as well as
- <file:drivers/net/ethernet/amd/depca.c>.
-
- To compile this driver as a module, choose M here. The module
- will be called depca.
-
config HPLANCE
bool "HP on-board LANCE support"
depends on DIO
diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/Makefile
index 175caa5328c9..cdd4301a973d 100644
--- a/drivers/net/ethernet/amd/Makefile
+++ b/drivers/net/ethernet/amd/Makefile
@@ -8,7 +8,6 @@ obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
obj-$(CONFIG_ARIADNE) += ariadne.o
obj-$(CONFIG_ATARILANCE) += atarilance.o
obj-$(CONFIG_DECLANCE) += declance.o
-obj-$(CONFIG_DEPCA) += depca.o
obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
obj-$(CONFIG_LANCE) += lance.o
obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 2ea221ed4777..de774d419144 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -437,8 +437,8 @@ static int au1000_mii_probe(struct net_device *dev)
/* now we are supposed to have a proper phydev, to attach to... */
BUG_ON(phydev->attached_dev);
- phydev = phy_connect(dev, dev_name(&phydev->dev), &au1000_adjust_link,
- 0, PHY_INTERFACE_MODE_MII);
+ phydev = phy_connect(dev, dev_name(&phydev->dev),
+ &au1000_adjust_link, PHY_INTERFACE_MODE_MII);
if (IS_ERR(phydev)) {
netdev_err(dev, "Could not attach to PHY\n");
@@ -587,10 +587,10 @@ au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct au1000_private *aup = netdev_priv(dev);
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- info->fw_version[0] = '\0';
- sprintf(info->bus_info, "%s %d", DRV_NAME, aup->mac_id);
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ snprintf(info->bus_info, sizeof(info->bus_info), "%s %d", DRV_NAME,
+ aup->mac_id);
info->regdump_len = 0;
}
diff --git a/drivers/net/ethernet/amd/depca.c b/drivers/net/ethernet/amd/depca.c
deleted file mode 100644
index 34a485363d5b..000000000000
--- a/drivers/net/ethernet/amd/depca.c
+++ /dev/null
@@ -1,1910 +0,0 @@
-/* depca.c: A DIGITAL DEPCA & EtherWORKS ethernet driver for linux.
-
- Written 1994, 1995 by David C. Davies.
-
-
- Copyright 1994 David C. Davies
- and
- United States Government
- (as represented by the Director, National Security Agency).
-
- Copyright 1995 Digital Equipment Corporation.
-
-
- This software may be used and distributed according to the terms of
- the GNU General Public License, incorporated herein by reference.
-
- This driver is written for the Digital Equipment Corporation series
- of DEPCA and EtherWORKS ethernet cards:
-
- DEPCA (the original)
- DE100
- DE101
- DE200 Turbo
- DE201 Turbo
- DE202 Turbo (TP BNC)
- DE210
- DE422 (EISA)
-
- The driver has been tested on DE100, DE200 and DE202 cards in a
- relatively busy network. The DE422 has been tested a little.
-
- This driver will NOT work for the DE203, DE204 and DE205 series of
- cards, since they have a new custom ASIC in place of the AMD LANCE
- chip. See the 'ewrk3.c' driver in the Linux source tree for running
- those cards.
-
- I have benchmarked the driver with a DE100 at 595kB/s to (542kB/s from)
- a DECstation 5000/200.
-
- The author may be reached at davies@maniac.ultranet.com
-
- =========================================================================
-
- The driver was originally based on the 'lance.c' driver from Donald
- Becker which is included with the standard driver distribution for
- linux. V0.4 is a complete re-write with only the kernel interface
- remaining from the original code.
-
- 1) Lance.c code in /linux/drivers/net/
- 2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
- AMD, 1992 [(800) 222-9323].
- 3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
- AMD, Pub. #17881, May 1993.
- 4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA",
- AMD, Pub. #16907, May 1992
- 5) "DEC EtherWORKS LC Ethernet Controller Owners Manual",
- Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003
- 6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual",
- Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003
- 7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR
- Digital Equipment Corporation, 1989
- 8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
- Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
-
-
- Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
- driver.
-
- The original DEPCA card requires that the ethernet ROM address counter
- be enabled to count and has an 8 bit NICSR. The ROM counter enabling is
- only done when a 0x08 is read as the first address octet (to minimise
- the chances of writing over some other hardware's I/O register). The
- NICSR accesses have been changed to byte accesses for all the cards
- supported by this driver, since there is only one useful bit in the MSB
- (remote boot timeout) and it is not used. Also, there is a maximum of
- only 48kB network RAM for this card. My thanks to Torbjorn Lindh for
- help debugging all this (and holding my feet to the fire until I got it
- right).
-
- The DE200 series boards have on-board 64kB RAM for use as a shared
- memory network buffer. Only the DE100 cards make use of a 2kB buffer
- mode which has not been implemented in this driver (only the 32kB and
- 64kB modes are supported [16kB/48kB for the original DEPCA]).
-
- At the most only 2 DEPCA cards can be supported on the ISA bus because
- there is only provision for two I/O base addresses on each card (0x300
- and 0x200). The I/O address is detected by searching for a byte sequence
- in the Ethernet station address PROM at the expected I/O address for the
- Ethernet PROM. The shared memory base address is 'autoprobed' by
- looking for the self test PROM and detecting the card name. When a
- second DEPCA is detected, information is placed in the base_addr
- variable of the next device structure (which is created if necessary),
- thus enabling ethif_probe initialization for the device. More than 2
- EISA cards can be supported, but care will be needed assigning the
- shared memory to ensure that each slot has the correct IRQ, I/O address
- and shared memory address assigned.
-
- ************************************************************************
-
- NOTE: If you are using two ISA DEPCAs, it is important that you assign
- the base memory addresses correctly. The driver autoprobes I/O 0x300
- then 0x200. The base memory address for the first device must be less
- than that of the second so that the auto probe will correctly assign the
- I/O and memory addresses on the same card. I can't think of a way to do
- this unambiguously at the moment, since there is nothing on the cards to
- tie I/O and memory information together.
-
- I am unable to test 2 cards together for now, so this code is
- unchecked. All reports, good or bad, are welcome.
-
- ************************************************************************
-
- The board IRQ setting must be at an unused IRQ which is auto-probed
- using Donald Becker's autoprobe routines. DEPCA and DE100 board IRQs are
- {2,3,4,5,7}, whereas the DE200 is at {5,9,10,11,15}. Note that IRQ2 is
- really IRQ9 in machines with 16 IRQ lines.
-
- No 16MB memory limitation should exist with this driver as DMA is not
- used and the common memory area is in low memory on the network card (my
- current system has 20MB and I've not had problems yet).
-
- The ability to load this driver as a loadable module has been added. To
- utilise this ability, you have to do <8 things:
-
- 0) have a copy of the loadable modules code installed on your system.
- 1) copy depca.c from the /linux/drivers/net directory to your favourite
- temporary directory.
- 2) if you wish, edit the source code near line 1530 to reflect the I/O
- address and IRQ you're using (see also 5).
- 3) compile depca.c, but include -DMODULE in the command line to ensure
- that the correct bits are compiled (see end of source code).
- 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
- kernel with the depca configuration turned off and reboot.
- 5) insmod depca.o [irq=7] [io=0x200] [mem=0xd0000] [adapter_name=DE100]
- [Alan Cox: Changed the code to allow command line irq/io assignments]
- [Dave Davies: Changed the code to allow command line mem/name
- assignments]
- 6) run the net startup bits for your eth?? interface manually
- (usually /etc/rc.inet[12] at boot time).
- 7) enjoy!
-
- Note that autoprobing is not allowed in loadable modules - the system is
- already up and running and you're messing with interrupts.
-
- To unload a module, turn off the associated interface
- 'ifconfig eth?? down' then 'rmmod depca'.
-
- To assign a base memory address for the shared memory when running as a
- loadable module, see 5 above. To include the adapter name (if you have
- no PROM but know the card name) also see 5 above. Note that this last
- option will not work with kernel built-in depca's.
-
- The shared memory assignment for a loadable module makes sense to avoid
- the 'memory autoprobe' picking the wrong shared memory (for the case of
- 2 depca's in a PC).
-
- ************************************************************************
- Support for MCA EtherWORKS cards added 11-3-98. (MCA since deleted)
- Verified to work with up to 2 DE212 cards in a system (although not
- fully stress-tested).
-
- Revision History
- ----------------
-
- Version Date Description
-
- 0.1 25-jan-94 Initial writing.
- 0.2 27-jan-94 Added LANCE TX hardware buffer chaining.
- 0.3 1-feb-94 Added multiple DEPCA support.
- 0.31 4-feb-94 Added DE202 recognition.
- 0.32 19-feb-94 Tidy up. Improve multi-DEPCA support.
- 0.33 25-feb-94 Fix DEPCA ethernet ROM counter enable.
- Add jabber packet fix from murf@perftech.com
- and becker@super.org
- 0.34 7-mar-94 Fix DEPCA max network memory RAM & NICSR access.
- 0.35 8-mar-94 Added DE201 recognition. Tidied up.
- 0.351 30-apr-94 Added EISA support. Added DE422 recognition.
- 0.36 16-may-94 DE422 fix released.
- 0.37 22-jul-94 Added MODULE support
- 0.38 15-aug-94 Added DBR ROM switch in depca_close().
- Multi DEPCA bug fix.
- 0.38axp 15-sep-94 Special version for Alpha AXP Linux V1.0.
- 0.381 12-dec-94 Added DE101 recognition, fix multicast bug.
- 0.382 9-feb-95 Fix recognition bug reported by <bkm@star.rl.ac.uk>.
- 0.383 22-feb-95 Fix for conflict with VESA SCSI reported by
- <stromain@alf.dec.com>
- 0.384 17-mar-95 Fix a ring full bug reported by <bkm@star.rl.ac.uk>
- 0.385 3-apr-95 Fix a recognition bug reported by
- <ryan.niemi@lastfrontier.com>
- 0.386 21-apr-95 Fix the last fix...sorry, must be galloping senility
- 0.40 25-May-95 Rewrite for portability & updated.
- ALPHA support from <jestabro@amt.tay1.dec.com>
- 0.41 26-Jun-95 Added verify_area() calls in depca_ioctl() from
- suggestion by <heiko@colossus.escape.de>
- 0.42 27-Dec-95 Add 'mem' shared memory assignment for loadable
- modules.
- Add 'adapter_name' for loadable modules when no PROM.
- Both above from a suggestion by
- <pchen@woodruffs121.residence.gatech.edu>.
- Add new multicasting code.
- 0.421 22-Apr-96 Fix alloc_device() bug <jari@markkus2.fimr.fi>
- 0.422 29-Apr-96 Fix depca_hw_init() bug <jari@markkus2.fimr.fi>
- 0.423 7-Jun-96 Fix module load bug <kmg@barco.be>
- 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c
- 0.44 1-Sep-97 Fix *_probe() to test check_region() first - bug
- reported by <mmogilvi@elbert.uccs.edu>
- 0.45 3-Nov-98 Added support for MCA EtherWORKS (DE210/DE212) cards
- by <tymm@computer.org>
- 0.451 5-Nov-98 Fixed mca stuff cuz I'm a dummy. <tymm@computer.org>
- 0.5 14-Nov-98 Re-spin for 2.1.x kernels.
- 0.51 27-Jun-99 Correct received packet length for CRC from
- report by <worm@dkik.dk>
- 0.52 16-Oct-00 Fixes for 2.3 io memory accesses
- Fix show-stopper (ints left masked) in depca_interrupt
- by <peterd@pnd-pc.demon.co.uk>
- 0.53 12-Jan-01 Release resources on failure, bss tidbits
- by acme@conectiva.com.br
- 0.54 08-Nov-01 use library crc32 functions
- by Matt_Domsch@dell.com
- 0.55 01-Mar-03 Use EISA/sysfs framework <maz@wild-wind.fr.eu.org>
-
- =========================================================================
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/time.h>
-#include <linux/types.h>
-#include <linux/unistd.h>
-#include <linux/ctype.h>
-#include <linux/moduleparam.h>
-#include <linux/platform_device.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#ifdef CONFIG_EISA
-#include <linux/eisa.h>
-#endif
-
-#include "depca.h"
-
-static char version[] __initdata = "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
-
-#ifdef DEPCA_DEBUG
-static int depca_debug = DEPCA_DEBUG;
-#else
-static int depca_debug = 1;
-#endif
-
-#define DEPCA_NDA 0xffe0 /* No Device Address */
-
-#define TX_TIMEOUT (1*HZ)
-
-/*
-** Ethernet PROM defines
-*/
-#define PROBE_LENGTH 32
-#define ETH_PROM_SIG 0xAA5500FFUL
-
-/*
-** Set the number of Tx and Rx buffers. Ensure that the memory requested
-** here is <= to the amount of shared memory set up by the board switches.
-** The number of descriptors MUST BE A POWER OF 2.
-**
-** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
-*/
-#define NUM_RX_DESC 8 /* Number of RX descriptors */
-#define NUM_TX_DESC 8 /* Number of TX descriptors */
-#define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */
-#define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */
-
-/*
-** EISA bus defines
-*/
-#define DEPCA_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
-
-/*
-** ISA Bus defines
-*/
-#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
-#define DEPCA_TOTAL_SIZE 0x10
-
-static struct {
- u_long iobase;
- struct platform_device *device;
-} depca_io_ports[] = {
- { 0x300, NULL },
- { 0x200, NULL },
- { 0 , NULL },
-};
-
-/*
-** Name <-> Adapter mapping
-*/
-#define DEPCA_SIGNATURE {"DEPCA",\
- "DE100","DE101",\
- "DE200","DE201","DE202",\
- "DE210","DE212",\
- "DE422",\
- ""}
-
-static char* __initdata depca_signature[] = DEPCA_SIGNATURE;
-
-enum depca_type {
- DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
-};
-
-static char depca_string[] = "depca";
-
-static int depca_device_remove (struct device *device);
-
-#ifdef CONFIG_EISA
-static struct eisa_device_id depca_eisa_ids[] = {
- { "DEC4220", de422 },
- { "" }
-};
-MODULE_DEVICE_TABLE(eisa, depca_eisa_ids);
-
-static int depca_eisa_probe (struct device *device);
-
-static struct eisa_driver depca_eisa_driver = {
- .id_table = depca_eisa_ids,
- .driver = {
- .name = depca_string,
- .probe = depca_eisa_probe,
- .remove = depca_device_remove
- }
-};
-#endif
-
-static int depca_isa_probe (struct platform_device *);
-
-static int depca_isa_remove(struct platform_device *pdev)
-{
- return depca_device_remove(&pdev->dev);
-}
-
-static struct platform_driver depca_isa_driver = {
- .probe = depca_isa_probe,
- .remove = depca_isa_remove,
- .driver = {
- .name = depca_string,
- },
-};
-
-/*
-** Miscellaneous info...
-*/
-#define DEPCA_STRLEN 16
-
-/*
-** Memory Alignment. Each descriptor is 4 longwords long. To force a
-** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
-** DESC_ALIGN. DEPCA_ALIGN aligns the start address of the private memory area
-** and hence the RX descriptor ring's first entry.
-*/
-#define DEPCA_ALIGN4 ((u_long)4 - 1) /* 1 longword align */
-#define DEPCA_ALIGN8 ((u_long)8 - 1) /* 2 longword (quadword) align */
-#define DEPCA_ALIGN DEPCA_ALIGN8 /* Keep the LANCE happy... */
-
-/*
-** The DEPCA Rx and Tx ring descriptors.
-*/
-struct depca_rx_desc {
- volatile s32 base;
- s16 buf_length; /* This length is negative 2's complement! */
- s16 msg_length; /* This length is "normal". */
-};
-
-struct depca_tx_desc {
- volatile s32 base;
- s16 length; /* This length is negative 2's complement! */
- s16 misc; /* Errors and TDR info */
-};
-
-#define LA_MASK 0x0000ffff /* LANCE address mask for mapping network RAM
- to LANCE memory address space */
-
-/*
-** The Lance initialization block, described in databook, in common memory.
-*/
-struct depca_init {
- u16 mode; /* Mode register */
- u8 phys_addr[ETH_ALEN]; /* Physical ethernet address */
- u8 mcast_table[8]; /* Multicast Hash Table. */
- u32 rx_ring; /* Rx ring base pointer & ring length */
- u32 tx_ring; /* Tx ring base pointer & ring length */
-};
-
-#define DEPCA_PKT_STAT_SZ 16
-#define DEPCA_PKT_BIN_SZ 128 /* Should be >=100 unless you
- increase DEPCA_PKT_STAT_SZ */
-struct depca_private {
- char adapter_name[DEPCA_STRLEN]; /* /proc/ioports string */
- enum depca_type adapter; /* Adapter type */
- enum {
- DEPCA_BUS_ISA = 1,
- DEPCA_BUS_EISA,
- } depca_bus; /* type of bus */
- struct depca_init init_block; /* Shadow Initialization block */
-/* CPU address space fields */
- struct depca_rx_desc __iomem *rx_ring; /* Pointer to start of RX descriptor ring */
- struct depca_tx_desc __iomem *tx_ring; /* Pointer to start of TX descriptor ring */
- void __iomem *rx_buff[NUM_RX_DESC]; /* CPU virt address of sh'd memory buffs */
- void __iomem *tx_buff[NUM_TX_DESC]; /* CPU virt address of sh'd memory buffs */
- void __iomem *sh_mem; /* CPU mapped virt address of device RAM */
- u_long mem_start; /* Bus address of device RAM (before remap) */
- u_long mem_len; /* device memory size */
-/* Device address space fields */
- u_long device_ram_start; /* Start of RAM in device addr space */
-/* Offsets used in both address spaces */
- u_long rx_ring_offset; /* Offset from start of RAM to rx_ring */
- u_long tx_ring_offset; /* Offset from start of RAM to tx_ring */
- u_long buffs_offset; /* LANCE Rx and Tx buffers start address. */
-/* Kernel-only (not device) fields */
- int rx_new, tx_new; /* The next free ring entry */
- int rx_old, tx_old; /* The ring entries to be free()ed. */
- spinlock_t lock;
- struct { /* Private stats counters */
- u32 bins[DEPCA_PKT_STAT_SZ];
- u32 unicast;
- u32 multicast;
- u32 broadcast;
- u32 excessive_collisions;
- u32 tx_underruns;
- u32 excessive_underruns;
- } pktStats;
- int txRingMask; /* TX ring mask */
- int rxRingMask; /* RX ring mask */
- s32 rx_rlen; /* log2(rxRingMask+1) for the descriptors */
- s32 tx_rlen; /* log2(txRingMask+1) for the descriptors */
-};
-
-/*
-** The transmit ring full condition is described by the tx_old and tx_new
-** pointers by:
-** tx_old = tx_new Empty ring
-** tx_old = tx_new+1 Full ring
-** tx_old+txRingMask = tx_new Full ring (wrapped condition)
-*/
-#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
- lp->tx_old+lp->txRingMask-lp->tx_new:\
- lp->tx_old -lp->tx_new-1)
-
-/*
-** Public Functions
-*/
-static int depca_open(struct net_device *dev);
-static netdev_tx_t depca_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t depca_interrupt(int irq, void *dev_id);
-static int depca_close(struct net_device *dev);
-static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void depca_tx_timeout(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-
-/*
-** Private functions
-*/
-static void depca_init_ring(struct net_device *dev);
-static int depca_rx(struct net_device *dev);
-static int depca_tx(struct net_device *dev);
-
-static void LoadCSRs(struct net_device *dev);
-static int InitRestartDepca(struct net_device *dev);
-static int DepcaSignature(char *name, u_long paddr);
-static int DevicePresent(u_long ioaddr);
-static int get_hw_addr(struct net_device *dev);
-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 int irq;
-static int io;
-static char *adapter_name;
-static int mem; /* For loadable module assignment
- use insmod mem=0x????? .... */
-module_param (irq, int, 0);
-module_param (io, int, 0);
-module_param (adapter_name, charp, 0);
-module_param (mem, int, 0);
-MODULE_PARM_DESC(irq, "DEPCA IRQ number");
-MODULE_PARM_DESC(io, "DEPCA I/O base address");
-MODULE_PARM_DESC(adapter_name, "DEPCA adapter name");
-MODULE_PARM_DESC(mem, "DEPCA shared memory address");
-MODULE_LICENSE("GPL");
-
-/*
-** Miscellaneous defines...
-*/
-#define STOP_DEPCA \
- outw(CSR0, DEPCA_ADDR);\
- outw(STOP, DEPCA_DATA)
-
-static const struct net_device_ops depca_netdev_ops = {
- .ndo_open = depca_open,
- .ndo_start_xmit = depca_start_xmit,
- .ndo_stop = depca_close,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_do_ioctl = depca_ioctl,
- .ndo_tx_timeout = depca_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int __init depca_hw_init (struct net_device *dev, struct device *device)
-{
- struct depca_private *lp;
- int i, j, offset, netRAM, mem_len, status = 0;
- s16 nicsr;
- u_long ioaddr;
- u_long mem_start;
-
- /*
- * We are now supposed to enter this function with the
- * following fields filled with proper values :
- *
- * dev->base_addr
- * lp->mem_start
- * lp->depca_bus
- * lp->adapter
- *
- * dev->irq can be set if known from device configuration (on
- * MCA or EISA) or module option. Otherwise, it will be auto
- * detected.
- */
-
- ioaddr = dev->base_addr;
-
- STOP_DEPCA;
-
- nicsr = inb(DEPCA_NICSR);
- nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
- outb(nicsr, DEPCA_NICSR);
-
- if (inw(DEPCA_DATA) != STOP) {
- return -ENXIO;
- }
-
- lp = netdev_priv(dev);
- mem_start = lp->mem_start;
-
- if (!mem_start || lp->adapter < DEPCA || lp->adapter >=unknown)
- return -ENXIO;
-
- printk("%s: %s at 0x%04lx",
- dev_name(device), depca_signature[lp->adapter], ioaddr);
-
- switch (lp->depca_bus) {
-#ifdef CONFIG_EISA
- case DEPCA_BUS_EISA:
- printk(" (EISA slot %d)", to_eisa_device(device)->slot);
- break;
-#endif
-
- case DEPCA_BUS_ISA:
- break;
-
- default:
- printk("Unknown DEPCA bus %d\n", lp->depca_bus);
- return -ENXIO;
- }
-
- printk(", h/w address ");
- status = get_hw_addr(dev);
- printk("%pM", dev->dev_addr);
- if (status != 0) {
- printk(" which has an Ethernet PROM CRC error.\n");
- return -ENXIO;
- }
-
- /* Set up the maximum amount of network RAM(kB) */
- netRAM = ((lp->adapter != DEPCA) ? 64 : 48);
- if ((nicsr & _128KB) && (lp->adapter == de422))
- netRAM = 128;
-
- /* Shared Memory Base Address */
- if (nicsr & BUF) {
- nicsr &= ~BS; /* DEPCA RAM in top 32k */
- netRAM -= 32;
- mem_start += 0x8000;
- }
-
- if ((mem_len = (NUM_RX_DESC * (sizeof(struct depca_rx_desc) + RX_BUFF_SZ) + NUM_TX_DESC * (sizeof(struct depca_tx_desc) + TX_BUFF_SZ) + sizeof(struct depca_init)))
- > (netRAM << 10)) {
- printk(",\n requests %dkB RAM: only %dkB is available!\n", (mem_len >> 10), netRAM);
- return -ENXIO;
- }
-
- printk(",\n has %dkB RAM at 0x%.5lx", netRAM, mem_start);
-
- /* Enable the shadow RAM. */
- if (lp->adapter != DEPCA) {
- nicsr |= SHE;
- outb(nicsr, DEPCA_NICSR);
- }
-
- spin_lock_init(&lp->lock);
- sprintf(lp->adapter_name, "%s (%s)",
- depca_signature[lp->adapter], dev_name(device));
- status = -EBUSY;
-
- /* Initialisation Block */
- if (!request_mem_region (mem_start, mem_len, lp->adapter_name)) {
- printk(KERN_ERR "depca: cannot request ISA memory, aborting\n");
- goto out_priv;
- }
-
- status = -EIO;
- lp->sh_mem = ioremap(mem_start, mem_len);
- if (lp->sh_mem == NULL) {
- printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n");
- goto out1;
- }
-
- lp->mem_start = mem_start;
- lp->mem_len = mem_len;
- lp->device_ram_start = mem_start & LA_MASK;
-
- offset = 0;
- offset += sizeof(struct depca_init);
-
- /* Tx & Rx descriptors (aligned to a quadword boundary) */
- offset = (offset + DEPCA_ALIGN) & ~DEPCA_ALIGN;
- lp->rx_ring = lp->sh_mem + offset;
- lp->rx_ring_offset = offset;
-
- offset += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
- lp->tx_ring = lp->sh_mem + offset;
- lp->tx_ring_offset = offset;
-
- offset += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
-
- lp->buffs_offset = offset;
-
- /* Finish initialising the ring information. */
- lp->rxRingMask = NUM_RX_DESC - 1;
- lp->txRingMask = NUM_TX_DESC - 1;
-
- /* Calculate Tx/Rx RLEN size for the descriptors. */
- for (i = 0, j = lp->rxRingMask; j > 0; i++) {
- j >>= 1;
- }
- lp->rx_rlen = (s32) (i << 29);
- for (i = 0, j = lp->txRingMask; j > 0; i++) {
- j >>= 1;
- }
- lp->tx_rlen = (s32) (i << 29);
-
- /* Load the initialisation block */
- depca_init_ring(dev);
-
- /* Initialise the control and status registers */
- LoadCSRs(dev);
-
- /* Enable DEPCA board interrupts for autoprobing */
- nicsr = ((nicsr & ~IM) | IEN);
- outb(nicsr, DEPCA_NICSR);
-
- /* To auto-IRQ we enable the initialization-done and DMA err,
- interrupts. For now we will always get a DMA error. */
- if (dev->irq < 2) {
- unsigned char irqnum;
- unsigned long irq_mask, delay;
-
- irq_mask = probe_irq_on();
-
- /* Assign the correct irq list */
- switch (lp->adapter) {
- case DEPCA:
- case de100:
- case de101:
- depca_irq = de1xx_irq;
- break;
- case de200:
- case de201:
- case de202:
- case de210:
- case de212:
- depca_irq = de2xx_irq;
- break;
- case de422:
- depca_irq = de422_irq;
- break;
-
- default:
- break; /* Not reached */
- }
-
- /* Trigger an initialization just for the interrupt. */
- outw(INEA | INIT, DEPCA_DATA);
-
- delay = jiffies + HZ/50;
- while (time_before(jiffies, delay))
- yield();
-
- irqnum = probe_irq_off(irq_mask);
-
- status = -ENXIO;
- if (!irqnum) {
- printk(" and failed to detect IRQ line.\n");
- goto out2;
- } else {
- for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++)
- if (irqnum == depca_irq[i]) {
- dev->irq = irqnum;
- printk(" and uses IRQ%d.\n", dev->irq);
- }
-
- if (!dev->irq) {
- printk(" but incorrect IRQ line detected.\n");
- goto out2;
- }
- }
- } else {
- printk(" and assigned IRQ%d.\n", dev->irq);
- }
-
- if (depca_debug > 1) {
- printk(version);
- }
-
- /* The DEPCA-specific entries in the device structure. */
- dev->netdev_ops = &depca_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- dev->mem_start = 0;
-
- dev_set_drvdata(device, dev);
- SET_NETDEV_DEV (dev, device);
-
- status = register_netdev(dev);
- if (status == 0)
- return 0;
-out2:
- iounmap(lp->sh_mem);
-out1:
- release_mem_region (mem_start, mem_len);
-out_priv:
- return status;
-}
-
-
-static int depca_open(struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- u_long ioaddr = dev->base_addr;
- s16 nicsr;
- int status = 0;
-
- STOP_DEPCA;
- nicsr = inb(DEPCA_NICSR);
-
- /* Make sure the shadow RAM is enabled */
- if (lp->adapter != DEPCA) {
- nicsr |= SHE;
- outb(nicsr, DEPCA_NICSR);
- }
-
- /* Re-initialize the DEPCA... */
- depca_init_ring(dev);
- LoadCSRs(dev);
-
- depca_dbg_open(dev);
-
- if (request_irq(dev->irq, depca_interrupt, 0, lp->adapter_name, dev)) {
- printk("depca_open(): Requested IRQ%d is busy\n", dev->irq);
- status = -EAGAIN;
- } else {
-
- /* Enable DEPCA board interrupts and turn off LED */
- nicsr = ((nicsr & ~IM & ~LED) | IEN);
- outb(nicsr, DEPCA_NICSR);
- outw(CSR0, DEPCA_ADDR);
-
- netif_start_queue(dev);
-
- status = InitRestartDepca(dev);
-
- if (depca_debug > 1) {
- printk("CSR0: 0x%4.4x\n", inw(DEPCA_DATA));
- printk("nicsr: 0x%02x\n", inb(DEPCA_NICSR));
- }
- }
- return status;
-}
-
-/* Initialize the lance Rx and Tx descriptor rings. */
-static void depca_init_ring(struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- u_int i;
- u_long offset;
-
- /* Lock out other processes whilst setting up the hardware */
- netif_stop_queue(dev);
-
- lp->rx_new = lp->tx_new = 0;
- lp->rx_old = lp->tx_old = 0;
-
- /* Initialize the base address and length of each buffer in the ring */
- for (i = 0; i <= lp->rxRingMask; i++) {
- offset = lp->buffs_offset + i * RX_BUFF_SZ;
- writel((lp->device_ram_start + offset) | R_OWN, &lp->rx_ring[i].base);
- writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length);
- lp->rx_buff[i] = lp->sh_mem + offset;
- }
-
- for (i = 0; i <= lp->txRingMask; i++) {
- offset = lp->buffs_offset + (i + lp->rxRingMask + 1) * TX_BUFF_SZ;
- writel((lp->device_ram_start + offset) & 0x00ffffff, &lp->tx_ring[i].base);
- lp->tx_buff[i] = lp->sh_mem + offset;
- }
-
- /* Set up the initialization block */
- lp->init_block.rx_ring = (lp->device_ram_start + lp->rx_ring_offset) | lp->rx_rlen;
- lp->init_block.tx_ring = (lp->device_ram_start + lp->tx_ring_offset) | lp->tx_rlen;
-
- SetMulticastFilter(dev);
-
- for (i = 0; i < ETH_ALEN; i++) {
- lp->init_block.phys_addr[i] = dev->dev_addr[i];
- }
-
- lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */
-}
-
-
-static void depca_tx_timeout(struct net_device *dev)
-{
- u_long ioaddr = dev->base_addr;
-
- printk("%s: transmit timed out, status %04x, resetting.\n", dev->name, inw(DEPCA_DATA));
-
- STOP_DEPCA;
- depca_init_ring(dev);
- LoadCSRs(dev);
- dev->trans_start = jiffies; /* prevent tx timeout */
- netif_wake_queue(dev);
- InitRestartDepca(dev);
-}
-
-
-/*
-** Writes a socket buffer to TX descriptor ring and starts transmission
-*/
-static netdev_tx_t depca_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- u_long ioaddr = dev->base_addr;
- int status = 0;
-
- /* Transmitter timeout, serious problems. */
- if (skb->len < 1)
- goto out;
-
- if (skb_padto(skb, ETH_ZLEN))
- goto out;
-
- netif_stop_queue(dev);
-
- if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
- status = load_packet(dev, skb);
-
- if (!status) {
- /* Trigger an immediate send demand. */
- outw(CSR0, DEPCA_ADDR);
- outw(INEA | TDMD, DEPCA_DATA);
-
- dev_kfree_skb(skb);
- }
- if (TX_BUFFS_AVAIL)
- netif_start_queue(dev);
- } else
- status = NETDEV_TX_LOCKED;
-
- out:
- return status;
-}
-
-/*
-** The DEPCA interrupt handler.
-*/
-static irqreturn_t depca_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct depca_private *lp;
- s16 csr0, nicsr;
- u_long ioaddr;
-
- if (dev == NULL) {
- printk("depca_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
- lp = netdev_priv(dev);
- ioaddr = dev->base_addr;
-
- spin_lock(&lp->lock);
-
- /* mask the DEPCA board interrupts and turn on the LED */
- nicsr = inb(DEPCA_NICSR);
- nicsr |= (IM | LED);
- outb(nicsr, DEPCA_NICSR);
-
- outw(CSR0, DEPCA_ADDR);
- csr0 = inw(DEPCA_DATA);
-
- /* Acknowledge all of the current interrupt sources ASAP. */
- outw(csr0 & INTE, DEPCA_DATA);
-
- if (csr0 & RINT) /* Rx interrupt (packet arrived) */
- depca_rx(dev);
-
- if (csr0 & TINT) /* Tx interrupt (packet sent) */
- depca_tx(dev);
-
- /* Any resources available? */
- if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) {
- netif_wake_queue(dev);
- }
-
- /* Unmask the DEPCA board interrupts and turn off the LED */
- nicsr = (nicsr & ~IM & ~LED);
- outb(nicsr, DEPCA_NICSR);
-
- spin_unlock(&lp->lock);
- return IRQ_HANDLED;
-}
-
-/* Called with lp->lock held */
-static int depca_rx(struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- int i, entry;
- s32 status;
-
- for (entry = lp->rx_new; !(readl(&lp->rx_ring[entry].base) & R_OWN); entry = lp->rx_new) {
- status = readl(&lp->rx_ring[entry].base) >> 16;
- if (status & R_STP) { /* Remember start of frame */
- lp->rx_old = entry;
- }
- if (status & R_ENP) { /* Valid frame status */
- if (status & R_ERR) { /* There was an error. */
- dev->stats.rx_errors++; /* Update the error stats. */
- if (status & R_FRAM)
- dev->stats.rx_frame_errors++;
- if (status & R_OFLO)
- dev->stats.rx_over_errors++;
- if (status & R_CRC)
- dev->stats.rx_crc_errors++;
- if (status & R_BUFF)
- dev->stats.rx_fifo_errors++;
- } else {
- short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(dev, pkt_len + 2);
- if (skb != NULL) {
- unsigned char *buf;
- skb_reserve(skb, 2); /* 16 byte align the IP header */
- buf = skb_put(skb, pkt_len);
- if (entry < lp->rx_old) { /* Wrapped buffer */
- len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
- memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len);
- memcpy_fromio(buf + len, lp->rx_buff[0], pkt_len - len);
- } else { /* Linear buffer */
- memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
- }
-
- /*
- ** Notify the upper protocol layers that there is another
- ** packet to handle
- */
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
-
- /*
- ** Update stats
- */
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) {
- if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) {
- lp->pktStats.bins[i]++;
- i = DEPCA_PKT_STAT_SZ;
- }
- }
- if (is_multicast_ether_addr(buf)) {
- if (is_broadcast_ether_addr(buf)) {
- lp->pktStats.broadcast++;
- } else {
- lp->pktStats.multicast++;
- }
- } else if (ether_addr_equal(buf,
- dev->dev_addr)) {
- lp->pktStats.unicast++;
- }
-
- lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */
- if (lp->pktStats.bins[0] == 0) { /* Reset counters */
- memset((char *) &lp->pktStats, 0, sizeof(lp->pktStats));
- }
- } else {
- printk("%s: Memory squeeze, deferring packet.\n", dev->name);
- dev->stats.rx_dropped++; /* Really, deferred. */
- break;
- }
- }
- /* Change buffer ownership for this last frame, back to the adapter */
- for (; lp->rx_old != entry; lp->rx_old = (lp->rx_old + 1) & lp->rxRingMask) {
- writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, &lp->rx_ring[lp->rx_old].base);
- }
- writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
- }
-
- /*
- ** Update entry information
- */
- lp->rx_new = (lp->rx_new + 1) & lp->rxRingMask;
- }
-
- return 0;
-}
-
-/*
-** Buffer sent - check for buffer errors.
-** Called with lp->lock held
-*/
-static int depca_tx(struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- int entry;
- s32 status;
- u_long ioaddr = dev->base_addr;
-
- for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
- status = readl(&lp->tx_ring[entry].base) >> 16;
-
- if (status < 0) { /* Packet not yet sent! */
- break;
- } else if (status & T_ERR) { /* An error occurred. */
- status = readl(&lp->tx_ring[entry].misc);
- dev->stats.tx_errors++;
- if (status & TMD3_RTRY)
- dev->stats.tx_aborted_errors++;
- if (status & TMD3_LCAR)
- dev->stats.tx_carrier_errors++;
- if (status & TMD3_LCOL)
- dev->stats.tx_window_errors++;
- if (status & TMD3_UFLO)
- dev->stats.tx_fifo_errors++;
- if (status & (TMD3_BUFF | TMD3_UFLO)) {
- /* Trigger an immediate send demand. */
- outw(CSR0, DEPCA_ADDR);
- outw(INEA | TDMD, DEPCA_DATA);
- }
- } else if (status & (T_MORE | T_ONE)) {
- dev->stats.collisions++;
- } else {
- dev->stats.tx_packets++;
- }
-
- /* Update all the pointers */
- lp->tx_old = (lp->tx_old + 1) & lp->txRingMask;
- }
-
- return 0;
-}
-
-static int depca_close(struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- s16 nicsr;
- u_long ioaddr = dev->base_addr;
-
- netif_stop_queue(dev);
-
- outw(CSR0, DEPCA_ADDR);
-
- if (depca_debug > 1) {
- printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(DEPCA_DATA));
- }
-
- /*
- ** We stop the DEPCA here -- it occasionally polls
- ** memory if we don't.
- */
- outw(STOP, DEPCA_DATA);
-
- /*
- ** Give back the ROM in case the user wants to go to DOS
- */
- if (lp->adapter != DEPCA) {
- nicsr = inb(DEPCA_NICSR);
- nicsr &= ~SHE;
- outb(nicsr, DEPCA_NICSR);
- }
-
- /*
- ** Free the associated irq
- */
- free_irq(dev->irq, dev);
- return 0;
-}
-
-static void LoadCSRs(struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- u_long ioaddr = dev->base_addr;
-
- outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */
- outw((u16) lp->device_ram_start, DEPCA_DATA);
- outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */
- outw((u16) (lp->device_ram_start >> 16), DEPCA_DATA);
- outw(CSR3, DEPCA_ADDR); /* ALE control */
- outw(ACON, DEPCA_DATA);
-
- outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */
-}
-
-static int InitRestartDepca(struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- u_long ioaddr = dev->base_addr;
- int i, status = 0;
-
- /* Copy the shadow init_block to shared memory */
- memcpy_toio(lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
-
- outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
- outw(INIT, DEPCA_DATA); /* initialize DEPCA */
-
- /* wait for lance to complete initialisation */
- for (i = 0; (i < 100) && !(inw(DEPCA_DATA) & IDON); i++);
-
- if (i != 100) {
- /* clear IDON by writing a "1", enable interrupts and start lance */
- outw(IDON | INEA | STRT, DEPCA_DATA);
- if (depca_debug > 2) {
- printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA));
- }
- } else {
- printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, lp->mem_start, inw(DEPCA_DATA));
- status = -1;
- }
-
- return status;
-}
-
-/*
-** Set or clear the multicast filter for this adaptor.
-*/
-static void set_multicast_list(struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- u_long ioaddr = dev->base_addr;
-
- netif_stop_queue(dev);
- while (lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
-
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous mode */
- lp->init_block.mode |= PROM;
- } else {
- SetMulticastFilter(dev);
- lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */
- }
-
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- netif_start_queue(dev); /* Unlock the TX ring */
-}
-
-/*
-** Calculate the hash code and update the logical address filter
-** from a list of ethernet multicast addresses.
-** Big endian crc one liner is mine, all mine, ha ha ha ha!
-** LANCE calculates its hash codes big endian.
-*/
-static void SetMulticastFilter(struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- struct netdev_hw_addr *ha;
- int i, j, bit, byte;
- u16 hashcode;
- u32 crc;
-
- if (dev->flags & IFF_ALLMULTI) { /* Set all multicast bits */
- for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
- lp->init_block.mcast_table[i] = (char) 0xff;
- }
- } else {
- for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) { /* Clear the multicast table */
- lp->init_block.mcast_table[i] = 0;
- }
- /* Add multicast addresses */
- netdev_for_each_mc_addr(ha, dev) {
- crc = ether_crc(ETH_ALEN, ha->addr);
- hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */
- for (j = 0; j < 5; j++) { /* ... in reverse order. */
- hashcode = (hashcode << 1) | ((crc >>= 1) & 1);
- }
-
- byte = hashcode >> 3; /* bit[3-5] -> byte in filter */
- bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */
- lp->init_block.mcast_table[byte] |= bit;
- }
- }
-}
-
-static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
-{
- int status = 0;
-
- if (!request_region (ioaddr, DEPCA_TOTAL_SIZE, depca_string)) {
- status = -EBUSY;
- goto out;
- }
-
- if (DevicePresent(ioaddr)) {
- status = -ENODEV;
- goto out_release;
- }
-
- if (!(*devp = alloc_etherdev (sizeof (struct depca_private)))) {
- status = -ENOMEM;
- goto out_release;
- }
-
- return 0;
-
- out_release:
- release_region (ioaddr, DEPCA_TOTAL_SIZE);
- out:
- return status;
-}
-
-/*
-** ISA bus I/O device probe
-*/
-
-static void __init depca_platform_probe (void)
-{
- int i;
- struct platform_device *pldev;
-
- for (i = 0; depca_io_ports[i].iobase; i++) {
- depca_io_ports[i].device = NULL;
-
- /* if an address has been specified on the command
- * line, use it (if valid) */
- if (io && io != depca_io_ports[i].iobase)
- continue;
-
- pldev = platform_device_alloc(depca_string, i);
- if (!pldev)
- continue;
-
- pldev->dev.platform_data = (void *) depca_io_ports[i].iobase;
- depca_io_ports[i].device = pldev;
-
- if (platform_device_add(pldev)) {
- depca_io_ports[i].device = NULL;
- pldev->dev.platform_data = NULL;
- platform_device_put(pldev);
- continue;
- }
-
- if (!pldev->dev.driver) {
- /* The driver was not bound to this device, there was
- * no hardware at this address. Unregister it, as the
- * release function will take care of freeing the
- * allocated structure */
-
- depca_io_ports[i].device = NULL;
- pldev->dev.platform_data = NULL;
- platform_device_unregister (pldev);
- }
- }
-}
-
-static enum depca_type __init depca_shmem_probe (ulong *mem_start)
-{
- u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
- enum depca_type adapter = unknown;
- int i;
-
- for (i = 0; mem_base[i]; i++) {
- *mem_start = mem ? mem : mem_base[i];
- adapter = DepcaSignature (adapter_name, *mem_start);
- if (adapter != unknown)
- break;
- }
-
- return adapter;
-}
-
-static int depca_isa_probe(struct platform_device *device)
-{
- struct net_device *dev;
- struct depca_private *lp;
- u_long ioaddr, mem_start = 0;
- enum depca_type adapter = unknown;
- int status = 0;
-
- ioaddr = (u_long) device->dev.platform_data;
-
- if ((status = depca_common_init (ioaddr, &dev)))
- goto out;
-
- adapter = depca_shmem_probe (&mem_start);
-
- if (adapter == unknown) {
- status = -ENODEV;
- goto out_free;
- }
-
- dev->base_addr = ioaddr;
- dev->irq = irq; /* Use whatever value the user gave
- * us, and 0 if he didn't. */
- lp = netdev_priv(dev);
- lp->depca_bus = DEPCA_BUS_ISA;
- lp->adapter = adapter;
- lp->mem_start = mem_start;
-
- if ((status = depca_hw_init(dev, &device->dev)))
- goto out_free;
-
- return 0;
-
- out_free:
- free_netdev (dev);
- release_region (ioaddr, DEPCA_TOTAL_SIZE);
- out:
- return status;
-}
-
-/*
-** EISA callbacks from sysfs.
-*/
-
-#ifdef CONFIG_EISA
-static int __init depca_eisa_probe (struct device *device)
-{
- enum depca_type adapter = unknown;
- struct eisa_device *edev;
- struct net_device *dev;
- struct depca_private *lp;
- u_long ioaddr, mem_start;
- int status = 0;
-
- edev = to_eisa_device (device);
- ioaddr = edev->base_addr + DEPCA_EISA_IO_PORTS;
-
- if ((status = depca_common_init (ioaddr, &dev)))
- goto out;
-
- /* It would have been nice to get card configuration from the
- * card. Unfortunately, this register is write-only (shares
- * it's address with the ethernet prom)... As we don't parse
- * the EISA configuration structures (yet... :-), just rely on
- * the ISA probing to sort it out... */
-
- adapter = depca_shmem_probe (&mem_start);
- if (adapter == unknown) {
- status = -ENODEV;
- goto out_free;
- }
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
- lp = netdev_priv(dev);
- lp->depca_bus = DEPCA_BUS_EISA;
- lp->adapter = edev->id.driver_data;
- lp->mem_start = mem_start;
-
- if ((status = depca_hw_init(dev, device)))
- goto out_free;
-
- return 0;
-
- out_free:
- free_netdev (dev);
- release_region (ioaddr, DEPCA_TOTAL_SIZE);
- out:
- return status;
-}
-#endif
-
-static int depca_device_remove(struct device *device)
-{
- struct net_device *dev;
- struct depca_private *lp;
- int bus;
-
- dev = dev_get_drvdata(device);
- lp = netdev_priv(dev);
-
- unregister_netdev (dev);
- iounmap (lp->sh_mem);
- release_mem_region (lp->mem_start, lp->mem_len);
- release_region (dev->base_addr, DEPCA_TOTAL_SIZE);
- bus = lp->depca_bus;
- free_netdev (dev);
-
- return 0;
-}
-
-/*
-** Look for a particular board name in the on-board Remote Diagnostics
-** 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)
-{
- u_int i, j, k;
- void __iomem *ptr;
- char tmpstr[16];
- u_long prom_addr = base_addr + 0xc000;
- u_long mem_addr = base_addr + 0x8000; /* 32KB */
-
- /* Can't reserve the prom region, it is already marked as
- * used, at least on x86. Instead, reserve a memory region a
- * board would certainly use. If it works, go ahead. If not,
- * run like hell... */
-
- if (!request_mem_region (mem_addr, 16, depca_string))
- return unknown;
-
- /* Copy the first 16 bytes of ROM */
-
- ptr = ioremap(prom_addr, 16);
- if (ptr == NULL) {
- printk(KERN_ERR "depca: I/O remap failed at %lx\n", prom_addr);
- return unknown;
- }
- for (i = 0; i < 16; i++) {
- tmpstr[i] = readb(ptr + i);
- }
- iounmap(ptr);
-
- release_mem_region (mem_addr, 16);
-
- /* Check if PROM contains a valid string */
- for (i = 0; *depca_signature[i] != '\0'; i++) {
- for (j = 0, k = 0; j < 16 && k < strlen(depca_signature[i]); j++) {
- if (depca_signature[i][k] == tmpstr[j]) { /* track signature */
- k++;
- } else { /* lost signature; begin search again */
- k = 0;
- }
- }
- if (k == strlen(depca_signature[i]))
- break;
- }
-
- /* Check if name string is valid, provided there's no PROM */
- if (name && *name && (i == unknown)) {
- for (i = 0; *depca_signature[i] != '\0'; i++) {
- if (strcmp(name, depca_signature[i]) == 0)
- break;
- }
- }
-
- return i;
-}
-
-/*
-** Look for a special sequence in the Ethernet station address PROM that
-** is common across all DEPCA products. Note that the original DEPCA needs
-** its ROM address counter to be initialized and enabled. Only enable
-** if the first address octet is a 0x08 - this minimises the chances of
-** messing around with some other hardware, but it assumes that this DEPCA
-** card initialized itself correctly.
-**
-** Search the Ethernet address ROM for the signature. Since the ROM address
-** counter can start at an arbitrary point, the search must include the entire
-** probe sequence length plus the (length_of_the_signature - 1).
-** Stop the search IMMEDIATELY after the signature is found so that the
-** PROM address counter is correctly positioned at the start of the
-** ethernet address for later read out.
-*/
-static int __init DevicePresent(u_long ioaddr)
-{
- union {
- struct {
- u32 a;
- u32 b;
- } llsig;
- char Sig[sizeof(u32) << 1];
- }
- dev;
- short sigLength = 0;
- s8 data;
- s16 nicsr;
- int i, j, status = 0;
-
- data = inb(DEPCA_PROM); /* clear counter on DEPCA */
- data = inb(DEPCA_PROM); /* read data */
-
- if (data == 0x08) { /* Enable counter on DEPCA */
- nicsr = inb(DEPCA_NICSR);
- nicsr |= AAC;
- outb(nicsr, DEPCA_NICSR);
- }
-
- dev.llsig.a = ETH_PROM_SIG;
- dev.llsig.b = ETH_PROM_SIG;
- sigLength = sizeof(u32) << 1;
-
- for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) {
- data = inb(DEPCA_PROM);
- if (dev.Sig[j] == data) { /* track signature */
- j++;
- } else { /* lost signature; begin search again */
- if (data == dev.Sig[0]) { /* rare case.... */
- j = 1;
- } else {
- j = 0;
- }
- }
- }
-
- if (j != sigLength) {
- status = -ENODEV; /* search failed */
- }
-
- return status;
-}
-
-/*
-** The DE100 and DE101 PROM accesses were made non-standard for some bizarre
-** reason: access the upper half of the PROM with x=0; access the lower half
-** with x=1.
-*/
-static int __init get_hw_addr(struct net_device *dev)
-{
- u_long ioaddr = dev->base_addr;
- struct depca_private *lp = netdev_priv(dev);
- int i, k, tmp, status = 0;
- u_short j, x, chksum;
-
- x = (((lp->adapter == de100) || (lp->adapter == de101)) ? 1 : 0);
-
- for (i = 0, k = 0, j = 0; j < 3; j++) {
- k <<= 1;
- if (k > 0xffff)
- k -= 0xffff;
-
- k += (u_char) (tmp = inb(DEPCA_PROM + x));
- dev->dev_addr[i++] = (u_char) tmp;
- k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
- dev->dev_addr[i++] = (u_char) tmp;
-
- if (k > 0xffff)
- k -= 0xffff;
- }
- if (k == 0xffff)
- k = 0;
-
- chksum = (u_char) inb(DEPCA_PROM + x);
- chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
- if (k != chksum)
- status = -1;
-
- return status;
-}
-
-/*
-** Load a packet into the shared memory
-*/
-static int load_packet(struct net_device *dev, struct sk_buff *skb)
-{
- struct depca_private *lp = netdev_priv(dev);
- int i, entry, end, len, status = NETDEV_TX_OK;
-
- entry = lp->tx_new; /* Ring around buffer number. */
- end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
- if (!(readl(&lp->tx_ring[end].base) & T_OWN)) { /* Enough room? */
- /*
- ** Caution: the write order is important here... don't set up the
- ** ownership rights until all the other information is in place.
- */
- if (end < entry) { /* wrapped buffer */
- len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
- memcpy_toio(lp->tx_buff[entry], skb->data, len);
- memcpy_toio(lp->tx_buff[0], skb->data + len, skb->len - len);
- } else { /* linear buffer */
- memcpy_toio(lp->tx_buff[entry], skb->data, skb->len);
- }
-
- /* set up the buffer descriptors */
- len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
- for (i = entry; i != end; i = (i+1) & lp->txRingMask) {
- /* clean out flags */
- writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
- writew(0x0000, &lp->tx_ring[i].misc); /* clears other error flags */
- writew(-TX_BUFF_SZ, &lp->tx_ring[i].length); /* packet length in buffer */
- len -= TX_BUFF_SZ;
- }
- /* clean out flags */
- writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
- writew(0x0000, &lp->tx_ring[end].misc); /* clears other error flags */
- writew(-len, &lp->tx_ring[end].length); /* packet length in last buff */
-
- /* start of packet */
- writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
- /* end of packet */
- writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
-
- for (i = end; i != entry; --i) {
- /* ownership of packet */
- writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
- if (i == 0)
- i = lp->txRingMask + 1;
- }
- writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
-
- lp->tx_new = (++end) & lp->txRingMask; /* update current pointers */
- } else {
- status = NETDEV_TX_LOCKED;
- }
-
- return status;
-}
-
-static void depca_dbg_open(struct net_device *dev)
-{
- struct depca_private *lp = netdev_priv(dev);
- u_long ioaddr = dev->base_addr;
- struct depca_init *p = &lp->init_block;
- int i;
-
- if (depca_debug > 1) {
- /* Do not copy the shadow init block into shared memory */
- /* Debugging should not affect normal operation! */
- /* The shadow init block will get copied across during InitRestartDepca */
- printk("%s: depca open with irq %d\n", dev->name, dev->irq);
- printk("Descriptor head addresses (CPU):\n");
- printk(" 0x%lx 0x%lx\n", (u_long) lp->rx_ring, (u_long) lp->tx_ring);
- printk("Descriptor addresses (CPU):\nRX: ");
- for (i = 0; i < lp->rxRingMask; i++) {
- if (i < 3) {
- printk("%p ", &lp->rx_ring[i].base);
- }
- }
- printk("...%p\n", &lp->rx_ring[i].base);
- printk("TX: ");
- for (i = 0; i < lp->txRingMask; i++) {
- if (i < 3) {
- printk("%p ", &lp->tx_ring[i].base);
- }
- }
- printk("...%p\n", &lp->tx_ring[i].base);
- printk("\nDescriptor buffers (Device):\nRX: ");
- for (i = 0; i < lp->rxRingMask; i++) {
- if (i < 3) {
- printk("0x%8.8x ", readl(&lp->rx_ring[i].base));
- }
- }
- printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
- printk("TX: ");
- for (i = 0; i < lp->txRingMask; i++) {
- if (i < 3) {
- printk("0x%8.8x ", readl(&lp->tx_ring[i].base));
- }
- }
- printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
- printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start);
- printk(" mode: 0x%4.4x\n", p->mode);
- printk(" physical address: %pM\n", p->phys_addr);
- printk(" multicast hash table: ");
- for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) {
- printk("%2.2x:", p->mcast_table[i]);
- }
- printk("%2.2x\n", p->mcast_table[i]);
- printk(" rx_ring at: 0x%8.8x\n", p->rx_ring);
- printk(" tx_ring at: 0x%8.8x\n", p->tx_ring);
- printk("buffers (Phys): 0x%8.8lx\n", lp->mem_start + lp->buffs_offset);
- printk("Ring size:\nRX: %d Log2(rxRingMask): 0x%8.8x\n", (int) lp->rxRingMask + 1, lp->rx_rlen);
- printk("TX: %d Log2(txRingMask): 0x%8.8x\n", (int) lp->txRingMask + 1, lp->tx_rlen);
- outw(CSR2, DEPCA_ADDR);
- printk("CSR2&1: 0x%4.4x", inw(DEPCA_DATA));
- outw(CSR1, DEPCA_ADDR);
- printk("%4.4x\n", inw(DEPCA_DATA));
- outw(CSR3, DEPCA_ADDR);
- printk("CSR3: 0x%4.4x\n", inw(DEPCA_DATA));
- }
-}
-
-/*
-** Perform IOCTL call functions here. Some are privileged operations and the
-** effective uid is checked in those cases.
-** All multicast IOCTLs will not work here and are for testing purposes only.
-*/
-static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct depca_private *lp = netdev_priv(dev);
- struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_ifru;
- int i, status = 0;
- u_long ioaddr = dev->base_addr;
- union {
- u8 addr[(HASH_TABLE_LEN * ETH_ALEN)];
- u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
- u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
- } tmp;
- unsigned long flags;
- void *buf;
-
- switch (ioc->cmd) {
- case DEPCA_GET_HWADDR: /* Get the hardware address */
- for (i = 0; i < ETH_ALEN; i++) {
- tmp.addr[i] = dev->dev_addr[i];
- }
- ioc->len = ETH_ALEN;
- if (copy_to_user(ioc->data, tmp.addr, ioc->len))
- return -EFAULT;
- break;
-
- case DEPCA_SET_HWADDR: /* Set the hardware address */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN))
- return -EFAULT;
- for (i = 0; i < ETH_ALEN; i++) {
- dev->dev_addr[i] = tmp.addr[i];
- }
- netif_stop_queue(dev);
- while (lp->tx_old != lp->tx_new)
- cpu_relax(); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- netif_start_queue(dev); /* Unlock the TX ring */
- break;
-
- case DEPCA_SET_PROM: /* Set Promiscuous Mode */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- netif_stop_queue(dev);
- while (lp->tx_old != lp->tx_new)
- cpu_relax(); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- lp->init_block.mode |= PROM; /* Set promiscuous mode */
-
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- netif_start_queue(dev); /* Unlock the TX ring */
- break;
-
- case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- netif_stop_queue(dev);
- while (lp->tx_old != lp->tx_new)
- cpu_relax(); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */
-
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- netif_start_queue(dev); /* Unlock the TX ring */
- break;
-
- case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
- printk("%s: Boo!\n", dev->name);
- break;
-
- case DEPCA_GET_MCA: /* Get the multicast address table */
- ioc->len = (HASH_TABLE_LEN >> 3);
- if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len))
- return -EFAULT;
- break;
-
- case DEPCA_SET_MCA: /* Set a multicast address */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (ioc->len >= HASH_TABLE_LEN)
- return -EINVAL;
- if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
- return -EFAULT;
- set_multicast_list(dev);
- break;
-
- case DEPCA_CLR_MCA: /* Clear all multicast addresses */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- set_multicast_list(dev);
- break;
-
- case DEPCA_MCA_EN: /* Enable pass all multicast addressing */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- set_multicast_list(dev);
- break;
-
- case DEPCA_GET_STATS: /* Get the driver statistics */
- ioc->len = sizeof(lp->pktStats);
- buf = kmalloc(ioc->len, GFP_KERNEL);
- if(!buf)
- return -ENOMEM;
- spin_lock_irqsave(&lp->lock, flags);
- memcpy(buf, &lp->pktStats, ioc->len);
- spin_unlock_irqrestore(&lp->lock, flags);
- if (copy_to_user(ioc->data, buf, ioc->len))
- status = -EFAULT;
- kfree(buf);
- break;
-
- case DEPCA_CLR_STATS: /* Zero out the driver statistics */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- spin_lock_irqsave(&lp->lock, flags);
- memset(&lp->pktStats, 0, sizeof(lp->pktStats));
- spin_unlock_irqrestore(&lp->lock, flags);
- break;
-
- case DEPCA_GET_REG: /* Get the DEPCA Registers */
- i = 0;
- tmp.sval[i++] = inw(DEPCA_NICSR);
- outw(CSR0, DEPCA_ADDR); /* status register */
- tmp.sval[i++] = inw(DEPCA_DATA);
- memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
- ioc->len = i + sizeof(struct depca_init);
- if (copy_to_user(ioc->data, tmp.addr, ioc->len))
- return -EFAULT;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
-
- return status;
-}
-
-static int __init depca_module_init (void)
-{
- int err = 0;
-
-#ifdef CONFIG_EISA
- err = eisa_driver_register(&depca_eisa_driver);
- if (err)
- goto err_eisa;
-#endif
- err = platform_driver_register(&depca_isa_driver);
- if (err)
- goto err_eisa;
-
- depca_platform_probe();
- return 0;
-
-err_eisa:
-#ifdef CONFIG_EISA
- eisa_driver_unregister(&depca_eisa_driver);
-#endif
- return err;
-}
-
-static void __exit depca_module_exit (void)
-{
- int i;
-#ifdef CONFIG_EISA
- eisa_driver_unregister (&depca_eisa_driver);
-#endif
- platform_driver_unregister (&depca_isa_driver);
-
- for (i = 0; depca_io_ports[i].iobase; i++) {
- if (depca_io_ports[i].device) {
- depca_io_ports[i].device->dev.platform_data = NULL;
- platform_device_unregister (depca_io_ports[i].device);
- depca_io_ports[i].device = NULL;
- }
- }
-}
-
-module_init (depca_module_init);
-module_exit (depca_module_exit);
diff --git a/drivers/net/ethernet/amd/depca.h b/drivers/net/ethernet/amd/depca.h
deleted file mode 100644
index cdcfe4252c16..000000000000
--- a/drivers/net/ethernet/amd/depca.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- Written 1994 by David C. Davies.
-
- Copyright 1994 David C. Davies. This software may be used and distributed
- according to the terms of the GNU General Public License, incorporated herein by
- reference.
-*/
-
-/*
-** I/O addresses. Note that the 2k buffer option is not supported in
-** this driver.
-*/
-#define DEPCA_NICSR ioaddr+0x00 /* Network interface CSR */
-#define DEPCA_RBI ioaddr+0x02 /* RAM buffer index (2k buffer mode) */
-#define DEPCA_DATA ioaddr+0x04 /* LANCE registers' data port */
-#define DEPCA_ADDR ioaddr+0x06 /* LANCE registers' address port */
-#define DEPCA_HBASE ioaddr+0x08 /* EISA high memory base address reg. */
-#define DEPCA_PROM ioaddr+0x0c /* Ethernet address ROM data port */
-#define DEPCA_CNFG ioaddr+0x0c /* EISA Configuration port */
-#define DEPCA_RBSA ioaddr+0x0e /* RAM buffer starting address (2k buff.) */
-
-/*
-** These are LANCE registers addressable through DEPCA_ADDR
-*/
-#define CSR0 0
-#define CSR1 1
-#define CSR2 2
-#define CSR3 3
-
-/*
-** NETWORK INTERFACE CSR (NI_CSR) bit definitions
-*/
-
-#define TO 0x0100 /* Time Out for remote boot */
-#define SHE 0x0080 /* SHadow memory Enable */
-#define BS 0x0040 /* Bank Select */
-#define BUF 0x0020 /* BUFfer size (1->32k, 0->64k) */
-#define RBE 0x0010 /* Remote Boot Enable (1->net boot) */
-#define AAC 0x0008 /* Address ROM Address Counter (1->enable) */
-#define _128KB 0x0008 /* 128kB Network RAM (1->enable) */
-#define IM 0x0004 /* Interrupt Mask (1->mask) */
-#define IEN 0x0002 /* Interrupt tristate ENable (1->enable) */
-#define LED 0x0001 /* LED control */
-
-/*
-** Control and Status Register 0 (CSR0) bit definitions
-*/
-
-#define ERR 0x8000 /* Error summary */
-#define BABL 0x4000 /* Babble transmitter timeout error */
-#define CERR 0x2000 /* Collision Error */
-#define MISS 0x1000 /* Missed packet */
-#define MERR 0x0800 /* Memory Error */
-#define RINT 0x0400 /* Receiver Interrupt */
-#define TINT 0x0200 /* Transmit Interrupt */
-#define IDON 0x0100 /* Initialization Done */
-#define INTR 0x0080 /* Interrupt Flag */
-#define INEA 0x0040 /* Interrupt Enable */
-#define RXON 0x0020 /* Receiver on */
-#define TXON 0x0010 /* Transmitter on */
-#define TDMD 0x0008 /* Transmit Demand */
-#define STOP 0x0004 /* Stop */
-#define STRT 0x0002 /* Start */
-#define INIT 0x0001 /* Initialize */
-#define INTM 0xff00 /* Interrupt Mask */
-#define INTE 0xfff0 /* Interrupt Enable */
-
-/*
-** CONTROL AND STATUS REGISTER 3 (CSR3)
-*/
-
-#define BSWP 0x0004 /* Byte SWaP */
-#define ACON 0x0002 /* ALE control */
-#define BCON 0x0001 /* Byte CONtrol */
-
-/*
-** Initialization Block Mode Register
-*/
-
-#define PROM 0x8000 /* Promiscuous Mode */
-#define EMBA 0x0080 /* Enable Modified Back-off Algorithm */
-#define INTL 0x0040 /* Internal Loopback */
-#define DRTY 0x0020 /* Disable Retry */
-#define COLL 0x0010 /* Force Collision */
-#define DTCR 0x0008 /* Disable Transmit CRC */
-#define LOOP 0x0004 /* Loopback */
-#define DTX 0x0002 /* Disable the Transmitter */
-#define DRX 0x0001 /* Disable the Receiver */
-
-/*
-** Receive Message Descriptor 1 (RMD1) bit definitions.
-*/
-
-#define R_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */
-#define R_ERR 0x4000 /* Error Summary */
-#define R_FRAM 0x2000 /* Framing Error */
-#define R_OFLO 0x1000 /* Overflow Error */
-#define R_CRC 0x0800 /* CRC Error */
-#define R_BUFF 0x0400 /* Buffer Error */
-#define R_STP 0x0200 /* Start of Packet */
-#define R_ENP 0x0100 /* End of Packet */
-
-/*
-** Transmit Message Descriptor 1 (TMD1) bit definitions.
-*/
-
-#define T_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */
-#define T_ERR 0x4000 /* Error Summary */
-#define T_ADD_FCS 0x2000 /* More the 1 retry needed to Xmit */
-#define T_MORE 0x1000 /* >1 retry to transmit packet */
-#define T_ONE 0x0800 /* 1 try needed to transmit the packet */
-#define T_DEF 0x0400 /* Deferred */
-#define T_STP 0x02000000 /* Start of Packet */
-#define T_ENP 0x01000000 /* End of Packet */
-#define T_FLAGS 0xff000000 /* TX Flags Field */
-
-/*
-** Transmit Message Descriptor 3 (TMD3) bit definitions.
-*/
-
-#define TMD3_BUFF 0x8000 /* BUFFer error */
-#define TMD3_UFLO 0x4000 /* UnderFLOw error */
-#define TMD3_RES 0x2000 /* REServed */
-#define TMD3_LCOL 0x1000 /* Late COLlision */
-#define TMD3_LCAR 0x0800 /* Loss of CARrier */
-#define TMD3_RTRY 0x0400 /* ReTRY error */
-
-/*
-** EISA configuration Register (CNFG) bit definitions
-*/
-
-#define TIMEOUT 0x0100 /* 0:2.5 mins, 1: 30 secs */
-#define REMOTE 0x0080 /* Remote Boot Enable -> 1 */
-#define IRQ11 0x0040 /* Enable -> 1 */
-#define IRQ10 0x0020 /* Enable -> 1 */
-#define IRQ9 0x0010 /* Enable -> 1 */
-#define IRQ5 0x0008 /* Enable -> 1 */
-#define BUFF 0x0004 /* 0: 64kB or 128kB, 1: 32kB */
-#define PADR16 0x0002 /* RAM on 64kB boundary */
-#define PADR17 0x0001 /* RAM on 128kB boundary */
-
-/*
-** Miscellaneous
-*/
-#define HASH_TABLE_LEN 64 /* Bits */
-#define HASH_BITS 0x003f /* 6 LS bits */
-
-#define MASK_INTERRUPTS 1
-#define UNMASK_INTERRUPTS 0
-
-#define EISA_EN 0x0001 /* Enable EISA bus buffers */
-#define EISA_ID iobase+0x0080 /* ID long word for EISA card */
-#define EISA_CTRL iobase+0x0084 /* Control word for EISA card */
-
-/*
-** Include the IOCTL stuff
-*/
-#include <linux/sockios.h>
-
-struct depca_ioctl {
- unsigned short cmd; /* Command to run */
- unsigned short len; /* Length of the data buffer */
- unsigned char __user *data; /* Pointer to the data buffer */
-};
-
-/*
-** Recognised commands for the driver
-*/
-#define DEPCA_GET_HWADDR 0x01 /* Get the hardware address */
-#define DEPCA_SET_HWADDR 0x02 /* Get the hardware address */
-#define DEPCA_SET_PROM 0x03 /* Set Promiscuous Mode */
-#define DEPCA_CLR_PROM 0x04 /* Clear Promiscuous Mode */
-#define DEPCA_SAY_BOO 0x05 /* Say "Boo!" to the kernel log file */
-#define DEPCA_GET_MCA 0x06 /* Get a multicast address */
-#define DEPCA_SET_MCA 0x07 /* Set a multicast address */
-#define DEPCA_CLR_MCA 0x08 /* Clear a multicast address */
-#define DEPCA_MCA_EN 0x09 /* Enable a multicast address group */
-#define DEPCA_GET_STATS 0x0a /* Get the driver statistics */
-#define DEPCA_CLR_STATS 0x0b /* Zero out the driver statistics */
-#define DEPCA_GET_REG 0x0c /* Get the Register contents */
-#define DEPCA_SET_REG 0x0d /* Set the Register contents */
-#define DEPCA_DUMP 0x0f /* Dump the DEPCA Status */
-
diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c
index a227ccdcb9b5..797f847edf13 100644
--- a/drivers/net/ethernet/amd/pcnet32.c
+++ b/drivers/net/ethernet/amd/pcnet32.c
@@ -494,19 +494,15 @@ static void pcnet32_realloc_tx_ring(struct net_device *dev,
}
memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size));
- new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
- GFP_ATOMIC);
- if (!new_dma_addr_list) {
- netif_err(lp, drv, dev, "Memory allocation failed\n");
+ new_dma_addr_list = kcalloc(1 << size, sizeof(dma_addr_t),
+ GFP_ATOMIC);
+ if (!new_dma_addr_list)
goto free_new_tx_ring;
- }
- new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
- GFP_ATOMIC);
- if (!new_skb_list) {
- netif_err(lp, drv, dev, "Memory allocation failed\n");
+ new_skb_list = kcalloc(1 << size, sizeof(struct sk_buff *),
+ GFP_ATOMIC);
+ if (!new_skb_list)
goto free_new_lists;
- }
kfree(lp->tx_skbuff);
kfree(lp->tx_dma_addr);
@@ -564,19 +560,14 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
}
memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
- new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
- GFP_ATOMIC);
- if (!new_dma_addr_list) {
- netif_err(lp, drv, dev, "Memory allocation failed\n");
+ new_dma_addr_list = kcalloc(1 << size, sizeof(dma_addr_t), GFP_ATOMIC);
+ if (!new_dma_addr_list)
goto free_new_rx_ring;
- }
- new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
- GFP_ATOMIC);
- if (!new_skb_list) {
- netif_err(lp, drv, dev, "Memory allocation failed\n");
+ new_skb_list = kcalloc(1 << size, sizeof(struct sk_buff *),
+ GFP_ATOMIC);
+ if (!new_skb_list)
goto free_new_lists;
- }
/* first copy the current receive buffers */
overlap = min(size, lp->rx_ring_size);
@@ -1688,10 +1679,9 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
memcpy(dev->dev_addr, promaddr, 6);
}
}
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
/* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
- if (!is_valid_ether_addr(dev->perm_addr))
+ if (!is_valid_ether_addr(dev->dev_addr))
memset(dev->dev_addr, 0, ETH_ALEN);
if (pcnet32_debug & NETIF_MSG_PROBE) {
@@ -1934,31 +1924,23 @@ static int pcnet32_alloc_ring(struct net_device *dev, const char *name)
lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
- if (!lp->tx_dma_addr) {
- netif_err(lp, drv, dev, "Memory allocation failed\n");
+ if (!lp->tx_dma_addr)
return -ENOMEM;
- }
lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
- if (!lp->rx_dma_addr) {
- netif_err(lp, drv, dev, "Memory allocation failed\n");
+ if (!lp->rx_dma_addr)
return -ENOMEM;
- }
lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
- if (!lp->tx_skbuff) {
- netif_err(lp, drv, dev, "Memory allocation failed\n");
+ if (!lp->tx_skbuff)
return -ENOMEM;
- }
lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
- if (!lp->rx_skbuff) {
- netif_err(lp, drv, dev, "Memory allocation failed\n");
+ if (!lp->rx_skbuff)
return -ENOMEM;
- }
return 0;
}
diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c
index c2d696c88e46..6a40290d3727 100644
--- a/drivers/net/ethernet/amd/sunlance.c
+++ b/drivers/net/ethernet/amd/sunlance.c
@@ -1284,8 +1284,8 @@ static void lance_free_hwresources(struct lance_private *lp)
/* Ethtool support... */
static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strcpy(info->driver, "sunlance");
- strcpy(info->version, "2.02");
+ strlcpy(info->driver, "sunlance", sizeof(info->driver));
+ strlcpy(info->version, "2.02", sizeof(info->version));
}
static const struct ethtool_ops sparc_lance_ethtool_ops = {
diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig
index 1ed886d421f8..36d6abd1cfff 100644
--- a/drivers/net/ethernet/atheros/Kconfig
+++ b/drivers/net/ethernet/atheros/Kconfig
@@ -44,8 +44,8 @@ config ATL1
will be called atl1.
config ATL1E
- tristate "Atheros L1E Gigabit Ethernet support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "Atheros L1E Gigabit Ethernet support"
+ depends on PCI
select CRC32
select NET_CORE
select MII
@@ -56,8 +56,8 @@ config ATL1E
will be called atl1e.
config ATL1C
- tristate "Atheros L1C Gigabit Ethernet support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "Atheros L1C Gigabit Ethernet support"
+ depends on PCI
select CRC32
select NET_CORE
select MII
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 56d3f697e0c7..1f07fc633ab9 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -21,7 +21,7 @@
#include "atl1c.h"
-#define ATL1C_DRV_VERSION "1.0.1.0-NAPI"
+#define ATL1C_DRV_VERSION "1.0.1.1-NAPI"
char atl1c_driver_name[] = "atl1c";
char atl1c_driver_version[] = ATL1C_DRV_VERSION;
@@ -472,7 +472,6 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
- netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr);
@@ -983,11 +982,9 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter)
size = sizeof(struct atl1c_buffer) * (tpd_ring->count * 2 +
rfd_ring->count);
tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
- if (unlikely(!tpd_ring->buffer_info)) {
- dev_err(&pdev->dev, "kzalloc failed, size = %d\n",
- size);
+ if (unlikely(!tpd_ring->buffer_info))
goto err_nomem;
- }
+
for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
tpd_ring[i].buffer_info =
(tpd_ring->buffer_info + count);
@@ -1652,6 +1649,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
u16 num_alloc = 0;
u16 rfd_next_to_use, next_next;
struct atl1c_rx_free_desc *rfd_desc;
+ dma_addr_t mapping;
next_next = rfd_next_to_use = rfd_ring->next_to_use;
if (++next_next == rfd_ring->count)
@@ -1678,9 +1676,18 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
buffer_info->skb = skb;
buffer_info->length = adapter->rx_buffer_len;
- buffer_info->dma = pci_map_single(pdev, vir_addr,
+ mapping = pci_map_single(pdev, vir_addr,
buffer_info->length,
PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(pdev, mapping))) {
+ dev_kfree_skb(skb);
+ buffer_info->skb = NULL;
+ buffer_info->length = 0;
+ ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE);
+ netif_warn(adapter, rx_err, adapter->netdev, "RX pci_map_single failed");
+ break;
+ }
+ buffer_info->dma = mapping;
ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
ATL1C_PCIMAP_FROMDEVICE);
rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
@@ -2015,7 +2022,29 @@ check_sum:
return 0;
}
-static void atl1c_tx_map(struct atl1c_adapter *adapter,
+static void atl1c_tx_rollback(struct atl1c_adapter *adpt,
+ struct atl1c_tpd_desc *first_tpd,
+ enum atl1c_trans_queue type)
+{
+ struct atl1c_tpd_ring *tpd_ring = &adpt->tpd_ring[type];
+ struct atl1c_buffer *buffer_info;
+ struct atl1c_tpd_desc *tpd;
+ u16 first_index, index;
+
+ first_index = first_tpd - (struct atl1c_tpd_desc *)tpd_ring->desc;
+ index = first_index;
+ while (index != tpd_ring->next_to_use) {
+ tpd = ATL1C_TPD_DESC(tpd_ring, index);
+ buffer_info = &tpd_ring->buffer_info[index];
+ atl1c_clean_buffer(adpt->pdev, buffer_info, 0);
+ memset(tpd, 0, sizeof(struct atl1c_tpd_desc));
+ if (++index == tpd_ring->count)
+ index = 0;
+ }
+ tpd_ring->next_to_use = first_index;
+}
+
+static int atl1c_tx_map(struct atl1c_adapter *adapter,
struct sk_buff *skb, struct atl1c_tpd_desc *tpd,
enum atl1c_trans_queue type)
{
@@ -2040,6 +2069,9 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
buffer_info->length = map_len;
buffer_info->dma = pci_map_single(adapter->pdev,
skb->data, hdr_len, PCI_DMA_TODEVICE);
+ if (unlikely(pci_dma_mapping_error(adapter->pdev,
+ buffer_info->dma)))
+ goto err_dma;
ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
ATL1C_PCIMAP_TODEVICE);
@@ -2062,6 +2094,10 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
buffer_info->dma =
pci_map_single(adapter->pdev, skb->data + mapped_len,
buffer_info->length, PCI_DMA_TODEVICE);
+ if (unlikely(pci_dma_mapping_error(adapter->pdev,
+ buffer_info->dma)))
+ goto err_dma;
+
ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
ATL1C_PCIMAP_TODEVICE);
@@ -2083,6 +2119,9 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
frag, 0,
buffer_info->length,
DMA_TO_DEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma))
+ goto err_dma;
+
ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_PAGE,
ATL1C_PCIMAP_TODEVICE);
@@ -2095,6 +2134,13 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
/* The last buffer info contain the skb address,
so it will be free after unmap */
buffer_info->skb = skb;
+
+ return 0;
+
+err_dma:
+ buffer_info->dma = 0;
+ buffer_info->length = 0;
+ return -1;
}
static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb,
@@ -2157,10 +2203,18 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
if (skb_network_offset(skb) != ETH_HLEN)
tpd->word1 |= 1 << TPD_ETH_TYPE_SHIFT; /* Ethernet frame */
- atl1c_tx_map(adapter, skb, tpd, type);
- atl1c_tx_queue(adapter, skb, tpd, type);
+ if (atl1c_tx_map(adapter, skb, tpd, type) < 0) {
+ netif_info(adapter, tx_done, adapter->netdev,
+ "tx-skb droppted due to dma error\n");
+ /* roll back tpd/buffer */
+ atl1c_tx_rollback(adapter, tpd, type);
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ dev_kfree_skb(skb);
+ } else {
+ atl1c_tx_queue(adapter, skb, tpd, type);
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ }
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
return NETDEV_TX_OK;
}
@@ -2540,10 +2594,9 @@ static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
if (atl1c_read_mac_addr(&adapter->hw)) {
/* got a random MAC address, set NET_ADDR_RANDOM to netdev */
- netdev->addr_assign_type |= NET_ADDR_RANDOM;
+ netdev->addr_assign_type = NET_ADDR_RANDOM;
}
memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
- memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
if (netif_msg_probe(adapter))
dev_dbg(&pdev->dev, "mac address : %pM\n",
adapter->hw.mac_addr);
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index e4466a36d106..92f4734f860d 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -819,8 +819,6 @@ static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter)
size = sizeof(struct atl1e_tx_buffer) * (tx_ring->count);
tx_ring->tx_buffer = kzalloc(size, GFP_KERNEL);
if (tx_ring->tx_buffer == NULL) {
- netdev_err(adapter->netdev, "kzalloc failed, size = D%d\n",
- size);
err = -ENOMEM;
goto failed;
}
@@ -2342,7 +2340,6 @@ static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
- memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
netdev_dbg(netdev, "mac address : %pM\n", adapter->hw.mac_addr);
INIT_WORK(&adapter->reset_task, atl1e_reset_task);
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index 71b3d7daa21d..5b0d9931c720 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -3053,7 +3053,7 @@ static int atl1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* copy the MAC address out of the EEPROM */
if (atl1_read_mac_addr(&adapter->hw)) {
/* mark random mac */
- netdev->addr_assign_type |= NET_ADDR_RANDOM;
+ netdev->addr_assign_type = NET_ADDR_RANDOM;
}
memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c
index aab83a2d4e07..1278b47022e0 100644
--- a/drivers/net/ethernet/atheros/atlx/atl2.c
+++ b/drivers/net/ethernet/atheros/atlx/atl2.c
@@ -1433,14 +1433,7 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* copy the MAC address out of the EEPROM */
atl2_read_mac_addr(&adapter->hw);
memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
-/* FIXME: do we still need this? */
-#ifdef ETHTOOL_GPERMADDR
- memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
-
- if (!is_valid_ether_addr(netdev->perm_addr)) {
-#else
if (!is_valid_ether_addr(netdev->dev_addr)) {
-#endif
err = -EIO;
goto err_eeprom;
}
diff --git a/drivers/net/ethernet/atheros/atlx/atlx.c b/drivers/net/ethernet/atheros/atlx/atlx.c
index 77ffbc4a5071..f82eb1699464 100644
--- a/drivers/net/ethernet/atheros/atlx/atlx.c
+++ b/drivers/net/ethernet/atheros/atlx/atlx.c
@@ -84,7 +84,6 @@ static int atlx_set_mac(struct net_device *netdev, void *p)
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
- netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
atlx_set_mac_addr(&adapter->hw);
return 0;
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index f55267363f35..3e69b3f88099 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -121,4 +121,22 @@ config BNX2X
To compile this driver as a module, choose M here: the module
will be called bnx2x. This is recommended.
+config BNX2X_SRIOV
+ bool "Broadcom 578xx and 57712 SR-IOV support"
+ depends on BNX2X && PCI_IOV
+ default y
+ ---help---
+ This configuration parameter enables Single Root Input Output
+ Virtualization support in the 578xx and 57712 products. This
+ allows for virtual function acceleration in virtual environments.
+
+config BGMAC
+ tristate "BCMA bus GBit core support"
+ depends on BCMA_HOST_SOC && HAS_DMA
+ ---help---
+ This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
+ They can be found on BCM47xx SoCs and provide gigabit ethernet.
+ In case of using this driver on BCM4706 it's also requires to enable
+ BCMA_DRIVER_GMAC_CMN to make it work.
+
endif # NET_VENDOR_BROADCOM
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
index b7896051d54e..68efa1a3fb88 100644
--- a/drivers/net/ethernet/broadcom/Makefile
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_CNIC) += cnic.o
obj-$(CONFIG_BNX2X) += bnx2x/
obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
obj-$(CONFIG_TIGON3) += tg3.o
+obj-$(CONFIG_BGMAC) += bgmac.o
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 219f6226fcb1..a7efec293037 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -809,11 +809,10 @@ static int b44_rx(struct b44 *bp, int budget)
struct sk_buff *copy_skb;
b44_recycle_rx(bp, cons, bp->rx_prod);
- copy_skb = netdev_alloc_skb(bp->dev, len + 2);
+ copy_skb = netdev_alloc_skb_ip_align(bp->dev, len);
if (copy_skb == NULL)
goto drop_it_no_recycle;
- skb_reserve(copy_skb, 2);
skb_put(copy_skb, len);
/* DMA sync done above, copy just the actual packet */
skb_copy_from_linear_data_offset(skb, RX_PKT_OFFSET,
@@ -1518,10 +1517,8 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
u8 pwol_mask[B44_PMASK_SIZE];
pwol_pattern = kzalloc(B44_PATTERN_SIZE, GFP_KERNEL);
- if (!pwol_pattern) {
- pr_err("Memory not available for WOL\n");
+ if (!pwol_pattern)
return;
- }
/* Ipv4 magic packet pattern - pattern 0.*/
memset(pwol_mask, 0, B44_PMASK_SIZE);
@@ -2111,8 +2108,6 @@ static int b44_get_invariants(struct b44 *bp)
return -EINVAL;
}
- memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
-
bp->imask = IMASK_DEF;
/* XXX - really required?
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index 39387d67b722..7d81e059e811 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -799,7 +799,7 @@ static int bcm_enet_open(struct net_device *dev)
snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
priv->mii_bus->id, priv->phy_id);
- phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link, 0,
+ phydev = phy_connect(dev, phy_id, bcm_enet_adjust_phy_link,
PHY_INTERFACE_MODE_MII);
if (IS_ERR(phydev)) {
@@ -886,10 +886,9 @@ static int bcm_enet_open(struct net_device *dev)
priv->tx_desc_alloc_size = size;
priv->tx_desc_cpu = p;
- priv->tx_skb = kzalloc(sizeof(struct sk_buff *) * priv->tx_ring_size,
+ priv->tx_skb = kcalloc(priv->tx_ring_size, sizeof(struct sk_buff *),
GFP_KERNEL);
if (!priv->tx_skb) {
- dev_err(kdev, "cannot allocate rx skb queue\n");
ret = -ENOMEM;
goto out_free_tx_ring;
}
@@ -900,10 +899,9 @@ static int bcm_enet_open(struct net_device *dev)
spin_lock_init(&priv->tx_lock);
/* init & fill rx ring with skbs */
- priv->rx_skb = kzalloc(sizeof(struct sk_buff *) * priv->rx_ring_size,
+ priv->rx_skb = kcalloc(priv->rx_ring_size, sizeof(struct sk_buff *),
GFP_KERNEL);
if (!priv->rx_skb) {
- dev_err(kdev, "cannot allocate rx skb queue\n");
ret = -ENOMEM;
goto out_free_tx_skb;
}
@@ -1227,10 +1225,11 @@ static const u32 unused_mib_regs[] = {
static void bcm_enet_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
- strncpy(drvinfo->driver, bcm_enet_driver_name, 32);
- strncpy(drvinfo->version, bcm_enet_driver_version, 32);
- strncpy(drvinfo->fw_version, "N/A", 32);
- strncpy(drvinfo->bus_info, "bcm63xx", 32);
+ strlcpy(drvinfo->driver, bcm_enet_driver_name, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, bcm_enet_driver_version,
+ sizeof(drvinfo->version));
+ strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strlcpy(drvinfo->bus_info, "bcm63xx", sizeof(drvinfo->bus_info));
drvinfo->n_stats = BCM_ENET_STATS_LEN;
}
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
new file mode 100644
index 000000000000..3fd32880e526
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -0,0 +1,1461 @@
+/*
+ * Driver for (BCM4706)? GBit MAC core on BCMA bus.
+ *
+ * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bgmac.h"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <asm/mach-bcm47xx/nvram.h>
+
+static const struct bcma_device_id bgmac_bcma_tbl[] = {
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
+ BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
+
+static bool bgmac_wait_value(struct bcma_device *core, u16 reg, u32 mask,
+ u32 value, int timeout)
+{
+ u32 val;
+ int i;
+
+ for (i = 0; i < timeout / 10; i++) {
+ val = bcma_read32(core, reg);
+ if ((val & mask) == value)
+ return true;
+ udelay(10);
+ }
+ pr_err("Timeout waiting for reg 0x%X\n", reg);
+ return false;
+}
+
+/**************************************************
+ * DMA
+ **************************************************/
+
+static void bgmac_dma_tx_reset(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
+{
+ u32 val;
+ int i;
+
+ if (!ring->mmio_base)
+ return;
+
+ /* Suspend DMA TX ring first.
+ * bgmac_wait_value doesn't support waiting for any of few values, so
+ * implement whole loop here.
+ */
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL,
+ BGMAC_DMA_TX_SUSPEND);
+ for (i = 0; i < 10000 / 10; i++) {
+ val = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
+ val &= BGMAC_DMA_TX_STAT;
+ if (val == BGMAC_DMA_TX_STAT_DISABLED ||
+ val == BGMAC_DMA_TX_STAT_IDLEWAIT ||
+ val == BGMAC_DMA_TX_STAT_STOPPED) {
+ i = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (i)
+ bgmac_err(bgmac, "Timeout suspending DMA TX ring 0x%X (BGMAC_DMA_TX_STAT: 0x%08X)\n",
+ ring->mmio_base, val);
+
+ /* Remove SUSPEND bit */
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, 0);
+ if (!bgmac_wait_value(bgmac->core,
+ ring->mmio_base + BGMAC_DMA_TX_STATUS,
+ BGMAC_DMA_TX_STAT, BGMAC_DMA_TX_STAT_DISABLED,
+ 10000)) {
+ bgmac_warn(bgmac, "DMA TX ring 0x%X wasn't disabled on time, waiting additional 300us\n",
+ ring->mmio_base);
+ udelay(300);
+ val = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
+ if ((val & BGMAC_DMA_TX_STAT) != BGMAC_DMA_TX_STAT_DISABLED)
+ bgmac_err(bgmac, "Reset of DMA TX ring 0x%X failed\n",
+ ring->mmio_base);
+ }
+}
+
+static void bgmac_dma_tx_enable(struct bgmac *bgmac,
+ struct bgmac_dma_ring *ring)
+{
+ u32 ctl;
+
+ ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL);
+ ctl |= BGMAC_DMA_TX_ENABLE;
+ ctl |= BGMAC_DMA_TX_PARITY_DISABLE;
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, ctl);
+}
+
+static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac,
+ struct bgmac_dma_ring *ring,
+ struct sk_buff *skb)
+{
+ struct device *dma_dev = bgmac->core->dma_dev;
+ struct net_device *net_dev = bgmac->net_dev;
+ struct bgmac_dma_desc *dma_desc;
+ struct bgmac_slot_info *slot;
+ u32 ctl0, ctl1;
+ int free_slots;
+
+ if (skb->len > BGMAC_DESC_CTL1_LEN) {
+ bgmac_err(bgmac, "Too long skb (%d)\n", skb->len);
+ goto err_stop_drop;
+ }
+
+ if (ring->start <= ring->end)
+ free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS;
+ else
+ free_slots = ring->start - ring->end;
+ if (free_slots == 1) {
+ bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
+ netif_stop_queue(net_dev);
+ return NETDEV_TX_BUSY;
+ }
+
+ slot = &ring->slots[ring->end];
+ slot->skb = skb;
+ slot->dma_addr = dma_map_single(dma_dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dma_dev, slot->dma_addr)) {
+ bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
+ ring->mmio_base);
+ goto err_stop_drop;
+ }
+
+ ctl0 = BGMAC_DESC_CTL0_IOC | BGMAC_DESC_CTL0_SOF | BGMAC_DESC_CTL0_EOF;
+ if (ring->end == ring->num_slots - 1)
+ ctl0 |= BGMAC_DESC_CTL0_EOT;
+ ctl1 = skb->len & BGMAC_DESC_CTL1_LEN;
+
+ dma_desc = ring->cpu_base;
+ dma_desc += ring->end;
+ dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr));
+ dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr));
+ dma_desc->ctl0 = cpu_to_le32(ctl0);
+ dma_desc->ctl1 = cpu_to_le32(ctl1);
+
+ wmb();
+
+ /* Increase ring->end to point empty slot. We tell hardware the first
+ * slot it should *not* read.
+ */
+ if (++ring->end >= BGMAC_TX_RING_SLOTS)
+ ring->end = 0;
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
+ ring->end * sizeof(struct bgmac_dma_desc));
+
+ /* Always keep one slot free to allow detecting bugged calls. */
+ if (--free_slots == 1)
+ netif_stop_queue(net_dev);
+
+ return NETDEV_TX_OK;
+
+err_stop_drop:
+ netif_stop_queue(net_dev);
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+/* Free transmitted packets */
+static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
+{
+ struct device *dma_dev = bgmac->core->dma_dev;
+ int empty_slot;
+ bool freed = false;
+
+ /* The last slot that hardware didn't consume yet */
+ empty_slot = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
+ empty_slot &= BGMAC_DMA_TX_STATDPTR;
+ empty_slot /= sizeof(struct bgmac_dma_desc);
+
+ while (ring->start != empty_slot) {
+ struct bgmac_slot_info *slot = &ring->slots[ring->start];
+
+ if (slot->skb) {
+ /* Unmap no longer used buffer */
+ dma_unmap_single(dma_dev, slot->dma_addr,
+ slot->skb->len, DMA_TO_DEVICE);
+ slot->dma_addr = 0;
+
+ /* Free memory! :) */
+ dev_kfree_skb(slot->skb);
+ slot->skb = NULL;
+ } else {
+ bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
+ ring->start, ring->end);
+ }
+
+ if (++ring->start >= BGMAC_TX_RING_SLOTS)
+ ring->start = 0;
+ freed = true;
+ }
+
+ if (freed && netif_queue_stopped(bgmac->net_dev))
+ netif_wake_queue(bgmac->net_dev);
+}
+
+static void bgmac_dma_rx_reset(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
+{
+ if (!ring->mmio_base)
+ return;
+
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL, 0);
+ if (!bgmac_wait_value(bgmac->core,
+ ring->mmio_base + BGMAC_DMA_RX_STATUS,
+ BGMAC_DMA_RX_STAT, BGMAC_DMA_RX_STAT_DISABLED,
+ 10000))
+ bgmac_err(bgmac, "Reset of ring 0x%X RX failed\n",
+ ring->mmio_base);
+}
+
+static void bgmac_dma_rx_enable(struct bgmac *bgmac,
+ struct bgmac_dma_ring *ring)
+{
+ u32 ctl;
+
+ ctl = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL);
+ ctl &= BGMAC_DMA_RX_ADDREXT_MASK;
+ ctl |= BGMAC_DMA_RX_ENABLE;
+ ctl |= BGMAC_DMA_RX_PARITY_DISABLE;
+ ctl |= BGMAC_DMA_RX_OVERFLOW_CONT;
+ ctl |= BGMAC_RX_FRAME_OFFSET << BGMAC_DMA_RX_FRAME_OFFSET_SHIFT;
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_CTL, ctl);
+}
+
+static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
+ struct bgmac_slot_info *slot)
+{
+ struct device *dma_dev = bgmac->core->dma_dev;
+ struct bgmac_rx_header *rx;
+
+ /* Alloc skb */
+ slot->skb = netdev_alloc_skb(bgmac->net_dev, BGMAC_RX_BUF_SIZE);
+ if (!slot->skb) {
+ bgmac_err(bgmac, "Allocation of skb failed!\n");
+ return -ENOMEM;
+ }
+
+ /* Poison - if everything goes fine, hardware will overwrite it */
+ rx = (struct bgmac_rx_header *)slot->skb->data;
+ rx->len = cpu_to_le16(0xdead);
+ rx->flags = cpu_to_le16(0xbeef);
+
+ /* Map skb for the DMA */
+ slot->dma_addr = dma_map_single(dma_dev, slot->skb->data,
+ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dma_dev, slot->dma_addr)) {
+ bgmac_err(bgmac, "DMA mapping error\n");
+ return -ENOMEM;
+ }
+ if (slot->dma_addr & 0xC0000000)
+ bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+
+ return 0;
+}
+
+static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
+ int weight)
+{
+ u32 end_slot;
+ int handled = 0;
+
+ end_slot = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_STATUS);
+ end_slot &= BGMAC_DMA_RX_STATDPTR;
+ end_slot /= sizeof(struct bgmac_dma_desc);
+
+ ring->end = end_slot;
+
+ while (ring->start != ring->end) {
+ struct device *dma_dev = bgmac->core->dma_dev;
+ struct bgmac_slot_info *slot = &ring->slots[ring->start];
+ struct sk_buff *skb = slot->skb;
+ struct sk_buff *new_skb;
+ struct bgmac_rx_header *rx;
+ u16 len, flags;
+
+ /* Unmap buffer to make it accessible to the CPU */
+ dma_sync_single_for_cpu(dma_dev, slot->dma_addr,
+ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+
+ /* Get info from the header */
+ rx = (struct bgmac_rx_header *)skb->data;
+ len = le16_to_cpu(rx->len);
+ flags = le16_to_cpu(rx->flags);
+
+ /* Check for poison and drop or pass the packet */
+ if (len == 0xdead && flags == 0xbeef) {
+ bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
+ ring->start);
+ } else {
+ new_skb = netdev_alloc_skb_ip_align(bgmac->net_dev, len);
+ if (new_skb) {
+ skb_put(new_skb, len);
+ skb_copy_from_linear_data_offset(skb, BGMAC_RX_FRAME_OFFSET,
+ new_skb->data,
+ len);
+ new_skb->protocol =
+ eth_type_trans(new_skb, bgmac->net_dev);
+ netif_receive_skb(new_skb);
+ handled++;
+ } else {
+ bgmac->net_dev->stats.rx_dropped++;
+ bgmac_err(bgmac, "Allocation of skb for copying packet failed!\n");
+ }
+
+ /* Poison the old skb */
+ rx->len = cpu_to_le16(0xdead);
+ rx->flags = cpu_to_le16(0xbeef);
+ }
+
+ /* Make it back accessible to the hardware */
+ dma_sync_single_for_device(dma_dev, slot->dma_addr,
+ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+
+ if (++ring->start >= BGMAC_RX_RING_SLOTS)
+ ring->start = 0;
+
+ if (handled >= weight) /* Should never be greater */
+ break;
+ }
+
+ return handled;
+}
+
+/* Does ring support unaligned addressing? */
+static bool bgmac_dma_unaligned(struct bgmac *bgmac,
+ struct bgmac_dma_ring *ring,
+ enum bgmac_dma_ring_type ring_type)
+{
+ switch (ring_type) {
+ case BGMAC_DMA_RING_TX:
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO,
+ 0xff0);
+ if (bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO))
+ return true;
+ break;
+ case BGMAC_DMA_RING_RX:
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO,
+ 0xff0);
+ if (bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO))
+ return true;
+ break;
+ }
+ return false;
+}
+
+static void bgmac_dma_ring_free(struct bgmac *bgmac,
+ struct bgmac_dma_ring *ring)
+{
+ struct device *dma_dev = bgmac->core->dma_dev;
+ struct bgmac_slot_info *slot;
+ int size;
+ int i;
+
+ for (i = 0; i < ring->num_slots; i++) {
+ slot = &ring->slots[i];
+ if (slot->skb) {
+ if (slot->dma_addr)
+ dma_unmap_single(dma_dev, slot->dma_addr,
+ slot->skb->len, DMA_TO_DEVICE);
+ dev_kfree_skb(slot->skb);
+ }
+ }
+
+ if (ring->cpu_base) {
+ /* Free ring of descriptors */
+ size = ring->num_slots * sizeof(struct bgmac_dma_desc);
+ dma_free_coherent(dma_dev, size, ring->cpu_base,
+ ring->dma_base);
+ }
+}
+
+static void bgmac_dma_free(struct bgmac *bgmac)
+{
+ int i;
+
+ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
+ bgmac_dma_ring_free(bgmac, &bgmac->tx_ring[i]);
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
+ bgmac_dma_ring_free(bgmac, &bgmac->rx_ring[i]);
+}
+
+static int bgmac_dma_alloc(struct bgmac *bgmac)
+{
+ struct device *dma_dev = bgmac->core->dma_dev;
+ struct bgmac_dma_ring *ring;
+ static const u16 ring_base[] = { BGMAC_DMA_BASE0, BGMAC_DMA_BASE1,
+ BGMAC_DMA_BASE2, BGMAC_DMA_BASE3, };
+ int size; /* ring size: different for Tx and Rx */
+ int err;
+ int i;
+
+ BUILD_BUG_ON(BGMAC_MAX_TX_RINGS > ARRAY_SIZE(ring_base));
+ BUILD_BUG_ON(BGMAC_MAX_RX_RINGS > ARRAY_SIZE(ring_base));
+
+ if (!(bcma_aread32(bgmac->core, BCMA_IOST) & BCMA_IOST_DMA64)) {
+ bgmac_err(bgmac, "Core does not report 64-bit DMA\n");
+ return -ENOTSUPP;
+ }
+
+ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
+ ring = &bgmac->tx_ring[i];
+ ring->num_slots = BGMAC_TX_RING_SLOTS;
+ ring->mmio_base = ring_base[i];
+ if (bgmac_dma_unaligned(bgmac, ring, BGMAC_DMA_RING_TX))
+ bgmac_warn(bgmac, "TX on ring 0x%X supports unaligned addressing but this feature is not implemented\n",
+ ring->mmio_base);
+
+ /* Alloc ring of descriptors */
+ size = ring->num_slots * sizeof(struct bgmac_dma_desc);
+ ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
+ &ring->dma_base,
+ GFP_KERNEL);
+ if (!ring->cpu_base) {
+ bgmac_err(bgmac, "Allocation of TX ring 0x%X failed\n",
+ ring->mmio_base);
+ goto err_dma_free;
+ }
+ if (ring->dma_base & 0xC0000000)
+ bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+
+ /* No need to alloc TX slots yet */
+ }
+
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+ ring = &bgmac->rx_ring[i];
+ ring->num_slots = BGMAC_RX_RING_SLOTS;
+ ring->mmio_base = ring_base[i];
+ if (bgmac_dma_unaligned(bgmac, ring, BGMAC_DMA_RING_RX))
+ bgmac_warn(bgmac, "RX on ring 0x%X supports unaligned addressing but this feature is not implemented\n",
+ ring->mmio_base);
+
+ /* Alloc ring of descriptors */
+ size = ring->num_slots * sizeof(struct bgmac_dma_desc);
+ ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
+ &ring->dma_base,
+ GFP_KERNEL);
+ if (!ring->cpu_base) {
+ bgmac_err(bgmac, "Allocation of RX ring 0x%X failed\n",
+ ring->mmio_base);
+ err = -ENOMEM;
+ goto err_dma_free;
+ }
+ if (ring->dma_base & 0xC0000000)
+ bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
+
+ /* Alloc RX slots */
+ for (i = 0; i < ring->num_slots; i++) {
+ err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[i]);
+ if (err) {
+ bgmac_err(bgmac, "Can't allocate skb for slot in RX ring\n");
+ goto err_dma_free;
+ }
+ }
+ }
+
+ return 0;
+
+err_dma_free:
+ bgmac_dma_free(bgmac);
+ return -ENOMEM;
+}
+
+static void bgmac_dma_init(struct bgmac *bgmac)
+{
+ struct bgmac_dma_ring *ring;
+ struct bgmac_dma_desc *dma_desc;
+ u32 ctl0, ctl1;
+ int i;
+
+ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
+ ring = &bgmac->tx_ring[i];
+
+ /* We don't implement unaligned addressing, so enable first */
+ bgmac_dma_tx_enable(bgmac, ring);
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO,
+ lower_32_bits(ring->dma_base));
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGHI,
+ upper_32_bits(ring->dma_base));
+
+ ring->start = 0;
+ ring->end = 0; /* Points the slot that should *not* be read */
+ }
+
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+ ring = &bgmac->rx_ring[i];
+
+ /* We don't implement unaligned addressing, so enable first */
+ bgmac_dma_rx_enable(bgmac, ring);
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO,
+ lower_32_bits(ring->dma_base));
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGHI,
+ upper_32_bits(ring->dma_base));
+
+ for (i = 0, dma_desc = ring->cpu_base; i < ring->num_slots;
+ i++, dma_desc++) {
+ ctl0 = ctl1 = 0;
+
+ if (i == ring->num_slots - 1)
+ ctl0 |= BGMAC_DESC_CTL0_EOT;
+ ctl1 |= BGMAC_RX_BUF_SIZE & BGMAC_DESC_CTL1_LEN;
+ /* Is there any BGMAC device that requires extension? */
+ /* ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT) &
+ * B43_DMA64_DCTL1_ADDREXT_MASK;
+ */
+
+ dma_desc->addr_low = cpu_to_le32(lower_32_bits(ring->slots[i].dma_addr));
+ dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[i].dma_addr));
+ dma_desc->ctl0 = cpu_to_le32(ctl0);
+ dma_desc->ctl1 = cpu_to_le32(ctl1);
+ }
+
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
+ ring->num_slots * sizeof(struct bgmac_dma_desc));
+
+ ring->start = 0;
+ ring->end = 0;
+ }
+}
+
+/**************************************************
+ * PHY ops
+ **************************************************/
+
+static u16 bgmac_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg)
+{
+ struct bcma_device *core;
+ u16 phy_access_addr;
+ u16 phy_ctl_addr;
+ u32 tmp;
+
+ BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK);
+ BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK);
+ BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT);
+ BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK);
+ BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT);
+ BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE);
+ BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START);
+ BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK);
+ BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK);
+ BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
+ BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
+
+ if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
+ core = bgmac->core->bus->drv_gmac_cmn.core;
+ phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
+ phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
+ } else {
+ core = bgmac->core;
+ phy_access_addr = BGMAC_PHY_ACCESS;
+ phy_ctl_addr = BGMAC_PHY_CNTL;
+ }
+
+ tmp = bcma_read32(core, phy_ctl_addr);
+ tmp &= ~BGMAC_PC_EPA_MASK;
+ tmp |= phyaddr;
+ bcma_write32(core, phy_ctl_addr, tmp);
+
+ tmp = BGMAC_PA_START;
+ tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
+ tmp |= reg << BGMAC_PA_REG_SHIFT;
+ bcma_write32(core, phy_access_addr, tmp);
+
+ if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
+ bgmac_err(bgmac, "Reading PHY %d register 0x%X failed\n",
+ phyaddr, reg);
+ return 0xffff;
+ }
+
+ return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK;
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
+static int bgmac_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value)
+{
+ struct bcma_device *core;
+ u16 phy_access_addr;
+ u16 phy_ctl_addr;
+ u32 tmp;
+
+ if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
+ core = bgmac->core->bus->drv_gmac_cmn.core;
+ phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
+ phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
+ } else {
+ core = bgmac->core;
+ phy_access_addr = BGMAC_PHY_ACCESS;
+ phy_ctl_addr = BGMAC_PHY_CNTL;
+ }
+
+ tmp = bcma_read32(core, phy_ctl_addr);
+ tmp &= ~BGMAC_PC_EPA_MASK;
+ tmp |= phyaddr;
+ bcma_write32(core, phy_ctl_addr, tmp);
+
+ bgmac_write(bgmac, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
+ if (bgmac_read(bgmac, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
+ bgmac_warn(bgmac, "Error setting MDIO int\n");
+
+ tmp = BGMAC_PA_START;
+ tmp |= BGMAC_PA_WRITE;
+ tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
+ tmp |= reg << BGMAC_PA_REG_SHIFT;
+ tmp |= value;
+ bcma_write32(core, phy_access_addr, tmp);
+
+ if (!bgmac_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 1000)) {
+ bgmac_err(bgmac, "Writing to PHY %d register 0x%X failed\n",
+ phyaddr, reg);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyforce */
+static void bgmac_phy_force(struct bgmac *bgmac)
+{
+ u16 ctl;
+ u16 mask = ~(BGMAC_PHY_CTL_SPEED | BGMAC_PHY_CTL_SPEED_MSB |
+ BGMAC_PHY_CTL_ANENAB | BGMAC_PHY_CTL_DUPLEX);
+
+ if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
+ return;
+
+ if (bgmac->autoneg)
+ return;
+
+ ctl = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL);
+ ctl &= mask;
+ if (bgmac->full_duplex)
+ ctl |= BGMAC_PHY_CTL_DUPLEX;
+ if (bgmac->speed == BGMAC_SPEED_100)
+ ctl |= BGMAC_PHY_CTL_SPEED_100;
+ else if (bgmac->speed == BGMAC_SPEED_1000)
+ ctl |= BGMAC_PHY_CTL_SPEED_1000;
+ bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL, ctl);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyadvertise */
+static void bgmac_phy_advertise(struct bgmac *bgmac)
+{
+ u16 adv;
+
+ if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
+ return;
+
+ if (!bgmac->autoneg)
+ return;
+
+ /* Adv selected 10/100 speeds */
+ adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV);
+ adv &= ~(BGMAC_PHY_ADV_10HALF | BGMAC_PHY_ADV_10FULL |
+ BGMAC_PHY_ADV_100HALF | BGMAC_PHY_ADV_100FULL);
+ if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10)
+ adv |= BGMAC_PHY_ADV_10HALF;
+ if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100)
+ adv |= BGMAC_PHY_ADV_100HALF;
+ if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10)
+ adv |= BGMAC_PHY_ADV_10FULL;
+ if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100)
+ adv |= BGMAC_PHY_ADV_100FULL;
+ bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV, adv);
+
+ /* Adv selected 1000 speeds */
+ adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2);
+ adv &= ~(BGMAC_PHY_ADV2_1000HALF | BGMAC_PHY_ADV2_1000FULL);
+ if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000)
+ adv |= BGMAC_PHY_ADV2_1000HALF;
+ if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000)
+ adv |= BGMAC_PHY_ADV2_1000FULL;
+ bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2, adv);
+
+ /* Restart */
+ bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL,
+ bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL) |
+ BGMAC_PHY_CTL_RESTART);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
+static void bgmac_phy_init(struct bgmac *bgmac)
+{
+ struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
+ struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
+ u8 i;
+
+ if (ci->id == BCMA_CHIP_ID_BCM5356) {
+ for (i = 0; i < 5; i++) {
+ bgmac_phy_write(bgmac, i, 0x1f, 0x008b);
+ bgmac_phy_write(bgmac, i, 0x15, 0x0100);
+ bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+ bgmac_phy_write(bgmac, i, 0x12, 0x2aaa);
+ bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+ }
+ }
+ if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
+ (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
+ (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
+ bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
+ bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
+ for (i = 0; i < 5; i++) {
+ bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+ bgmac_phy_write(bgmac, i, 0x16, 0x5284);
+ bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+ bgmac_phy_write(bgmac, i, 0x17, 0x0010);
+ bgmac_phy_write(bgmac, i, 0x1f, 0x000f);
+ bgmac_phy_write(bgmac, i, 0x16, 0x5296);
+ bgmac_phy_write(bgmac, i, 0x17, 0x1073);
+ bgmac_phy_write(bgmac, i, 0x17, 0x9073);
+ bgmac_phy_write(bgmac, i, 0x16, 0x52b6);
+ bgmac_phy_write(bgmac, i, 0x17, 0x9273);
+ bgmac_phy_write(bgmac, i, 0x1f, 0x000b);
+ }
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
+static void bgmac_phy_reset(struct bgmac *bgmac)
+{
+ if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
+ return;
+
+ bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL,
+ BGMAC_PHY_CTL_RESET);
+ udelay(100);
+ if (bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL) &
+ BGMAC_PHY_CTL_RESET)
+ bgmac_err(bgmac, "PHY reset failed\n");
+ bgmac_phy_init(bgmac);
+}
+
+/**************************************************
+ * Chip ops
+ **************************************************/
+
+/* TODO: can we just drop @force? Can we don't reset MAC at all if there is
+ * nothing to change? Try if after stabilizng driver.
+ */
+static void bgmac_cmdcfg_maskset(struct bgmac *bgmac, u32 mask, u32 set,
+ bool force)
+{
+ u32 cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
+ u32 new_val = (cmdcfg & mask) | set;
+
+ bgmac_set(bgmac, BGMAC_CMDCFG, BGMAC_CMDCFG_SR);
+ udelay(2);
+
+ if (new_val != cmdcfg || force)
+ bgmac_write(bgmac, BGMAC_CMDCFG, new_val);
+
+ bgmac_mask(bgmac, BGMAC_CMDCFG, ~BGMAC_CMDCFG_SR);
+ udelay(2);
+}
+
+static void bgmac_write_mac_address(struct bgmac *bgmac, u8 *addr)
+{
+ u32 tmp;
+
+ tmp = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
+ bgmac_write(bgmac, BGMAC_MACADDR_HIGH, tmp);
+ tmp = (addr[4] << 8) | addr[5];
+ bgmac_write(bgmac, BGMAC_MACADDR_LOW, tmp);
+}
+
+static void bgmac_set_rx_mode(struct net_device *net_dev)
+{
+ struct bgmac *bgmac = netdev_priv(net_dev);
+
+ if (net_dev->flags & IFF_PROMISC)
+ bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_PROM, true);
+ else
+ bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_PROM, 0, true);
+}
+
+#if 0 /* We don't use that regs yet */
+static void bgmac_chip_stats_update(struct bgmac *bgmac)
+{
+ int i;
+
+ if (bgmac->core->id.id != BCMA_CORE_4706_MAC_GBIT) {
+ for (i = 0; i < BGMAC_NUM_MIB_TX_REGS; i++)
+ bgmac->mib_tx_regs[i] =
+ bgmac_read(bgmac,
+ BGMAC_TX_GOOD_OCTETS + (i * 4));
+ for (i = 0; i < BGMAC_NUM_MIB_RX_REGS; i++)
+ bgmac->mib_rx_regs[i] =
+ bgmac_read(bgmac,
+ BGMAC_RX_GOOD_OCTETS + (i * 4));
+ }
+
+ /* TODO: what else? how to handle BCM4706? Specs are needed */
+}
+#endif
+
+static void bgmac_clear_mib(struct bgmac *bgmac)
+{
+ int i;
+
+ if (bgmac->core->id.id == BCMA_CORE_4706_MAC_GBIT)
+ return;
+
+ bgmac_set(bgmac, BGMAC_DEV_CTL, BGMAC_DC_MROR);
+ for (i = 0; i < BGMAC_NUM_MIB_TX_REGS; i++)
+ bgmac_read(bgmac, BGMAC_TX_GOOD_OCTETS + (i * 4));
+ for (i = 0; i < BGMAC_NUM_MIB_RX_REGS; i++)
+ bgmac_read(bgmac, BGMAC_RX_GOOD_OCTETS + (i * 4));
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_speed */
+static void bgmac_speed(struct bgmac *bgmac, int speed)
+{
+ u32 mask = ~(BGMAC_CMDCFG_ES_MASK | BGMAC_CMDCFG_HD);
+ u32 set = 0;
+
+ if (speed & BGMAC_SPEED_10)
+ set |= BGMAC_CMDCFG_ES_10;
+ if (speed & BGMAC_SPEED_100)
+ set |= BGMAC_CMDCFG_ES_100;
+ if (speed & BGMAC_SPEED_1000)
+ set |= BGMAC_CMDCFG_ES_1000;
+ if (!bgmac->full_duplex)
+ set |= BGMAC_CMDCFG_HD;
+ bgmac_cmdcfg_maskset(bgmac, mask, set, true);
+}
+
+static void bgmac_miiconfig(struct bgmac *bgmac)
+{
+ u8 imode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
+ BGMAC_DS_MM_SHIFT;
+ if (imode == 0 || imode == 1) {
+ if (bgmac->autoneg)
+ bgmac_speed(bgmac, BGMAC_SPEED_100);
+ else
+ bgmac_speed(bgmac, bgmac->speed);
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipreset */
+static void bgmac_chip_reset(struct bgmac *bgmac)
+{
+ struct bcma_device *core = bgmac->core;
+ struct bcma_bus *bus = core->bus;
+ struct bcma_chipinfo *ci = &bus->chipinfo;
+ u32 flags = 0;
+ u32 iost;
+ int i;
+
+ if (bcma_core_is_enabled(core)) {
+ if (!bgmac->stats_grabbed) {
+ /* bgmac_chip_stats_update(bgmac); */
+ bgmac->stats_grabbed = true;
+ }
+
+ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
+ bgmac_dma_tx_reset(bgmac, &bgmac->tx_ring[i]);
+
+ bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_ML, false);
+ udelay(1);
+
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
+ bgmac_dma_rx_reset(bgmac, &bgmac->rx_ring[i]);
+
+ /* TODO: Clear software multicast filter list */
+ }
+
+ iost = bcma_aread32(core, BCMA_IOST);
+ if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == 10) ||
+ (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) ||
+ (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == 9))
+ iost &= ~BGMAC_BCMA_IOST_ATTACHED;
+
+ if (iost & BGMAC_BCMA_IOST_ATTACHED) {
+ flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
+ if (!bgmac->has_robosw)
+ flags |= BGMAC_BCMA_IOCTL_SW_RESET;
+ }
+
+ bcma_core_enable(core, flags);
+
+ if (core->id.rev > 2) {
+ bgmac_set(bgmac, BCMA_CLKCTLST, 1 << 8);
+ bgmac_wait_value(bgmac->core, BCMA_CLKCTLST, 1 << 24, 1 << 24,
+ 1000);
+ }
+
+ if (ci->id == BCMA_CHIP_ID_BCM5357 || ci->id == BCMA_CHIP_ID_BCM4749 ||
+ ci->id == BCMA_CHIP_ID_BCM53572) {
+ struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
+ u8 et_swtype = 0;
+ u8 sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHY |
+ BGMAC_CHIPCTL_1_IF_TYPE_RMII;
+ char buf[2];
+
+ if (nvram_getenv("et_swtype", buf, 1) > 0) {
+ if (kstrtou8(buf, 0, &et_swtype))
+ bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
+ buf);
+ et_swtype &= 0x0f;
+ et_swtype <<= 4;
+ sw_type = et_swtype;
+ } else if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == 9) {
+ sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII;
+ } else if ((ci->id != BCMA_CHIP_ID_BCM53572 && ci->pkg == 10) ||
+ (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == 9)) {
+ sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RGMII |
+ BGMAC_CHIPCTL_1_SW_TYPE_RGMII;
+ }
+ bcma_chipco_chipctl_maskset(cc, 1,
+ ~(BGMAC_CHIPCTL_1_IF_TYPE_MASK |
+ BGMAC_CHIPCTL_1_SW_TYPE_MASK),
+ sw_type);
+ }
+
+ if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw)
+ bcma_awrite32(core, BCMA_IOCTL,
+ bcma_aread32(core, BCMA_IOCTL) &
+ ~BGMAC_BCMA_IOCTL_SW_RESET);
+
+ /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_reset
+ * Specs don't say about using BGMAC_CMDCFG_SR, but in this routine
+ * BGMAC_CMDCFG is read _after_ putting chip in a reset. So it has to
+ * be keps until taking MAC out of the reset.
+ */
+ bgmac_cmdcfg_maskset(bgmac,
+ ~(BGMAC_CMDCFG_TE |
+ BGMAC_CMDCFG_RE |
+ BGMAC_CMDCFG_RPI |
+ BGMAC_CMDCFG_TAI |
+ BGMAC_CMDCFG_HD |
+ BGMAC_CMDCFG_ML |
+ BGMAC_CMDCFG_CFE |
+ BGMAC_CMDCFG_RL |
+ BGMAC_CMDCFG_RED |
+ BGMAC_CMDCFG_PE |
+ BGMAC_CMDCFG_TPI |
+ BGMAC_CMDCFG_PAD_EN |
+ BGMAC_CMDCFG_PF),
+ BGMAC_CMDCFG_PROM |
+ BGMAC_CMDCFG_NLC |
+ BGMAC_CMDCFG_CFE |
+ BGMAC_CMDCFG_SR,
+ false);
+
+ bgmac_clear_mib(bgmac);
+ if (core->id.id == BCMA_CORE_4706_MAC_GBIT)
+ bcma_maskset32(bgmac->cmn, BCMA_GMAC_CMN_PHY_CTL, ~0,
+ BCMA_GMAC_CMN_PC_MTE);
+ else
+ bgmac_set(bgmac, BGMAC_PHY_CNTL, BGMAC_PC_MTE);
+ bgmac_miiconfig(bgmac);
+ bgmac_phy_init(bgmac);
+
+ bgmac->int_status = 0;
+}
+
+static void bgmac_chip_intrs_on(struct bgmac *bgmac)
+{
+ bgmac_write(bgmac, BGMAC_INT_MASK, bgmac->int_mask);
+}
+
+static void bgmac_chip_intrs_off(struct bgmac *bgmac)
+{
+ bgmac_write(bgmac, BGMAC_INT_MASK, 0);
+ bgmac_read(bgmac, BGMAC_INT_MASK);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_enable */
+static void bgmac_enable(struct bgmac *bgmac)
+{
+ struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
+ u32 cmdcfg;
+ u32 mode;
+ u32 rxq_ctl;
+ u32 fl_ctl;
+ u16 bp_clk;
+ u8 mdp;
+
+ cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG);
+ bgmac_cmdcfg_maskset(bgmac, ~(BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE),
+ BGMAC_CMDCFG_SR, true);
+ udelay(2);
+ cmdcfg |= BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE;
+ bgmac_write(bgmac, BGMAC_CMDCFG, cmdcfg);
+
+ mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
+ BGMAC_DS_MM_SHIFT;
+ if (ci->id != BCMA_CHIP_ID_BCM47162 || mode != 0)
+ bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+ if (ci->id == BCMA_CHIP_ID_BCM47162 && mode == 2)
+ bcma_chipco_chipctl_maskset(&bgmac->core->bus->drv_cc, 1, ~0,
+ BGMAC_CHIPCTL_1_RXC_DLL_BYPASS);
+
+ switch (ci->id) {
+ case BCMA_CHIP_ID_BCM5357:
+ case BCMA_CHIP_ID_BCM4749:
+ case BCMA_CHIP_ID_BCM53572:
+ case BCMA_CHIP_ID_BCM4716:
+ case BCMA_CHIP_ID_BCM47162:
+ fl_ctl = 0x03cb04cb;
+ if (ci->id == BCMA_CHIP_ID_BCM5357 ||
+ ci->id == BCMA_CHIP_ID_BCM4749 ||
+ ci->id == BCMA_CHIP_ID_BCM53572)
+ fl_ctl = 0x2300e1;
+ bgmac_write(bgmac, BGMAC_FLOW_CTL_THRESH, fl_ctl);
+ bgmac_write(bgmac, BGMAC_PAUSE_CTL, 0x27fff);
+ break;
+ }
+
+ rxq_ctl = bgmac_read(bgmac, BGMAC_RXQ_CTL);
+ rxq_ctl &= ~BGMAC_RXQ_CTL_MDP_MASK;
+ bp_clk = bcma_pmu_get_bus_clock(&bgmac->core->bus->drv_cc) / 1000000;
+ mdp = (bp_clk * 128 / 1000) - 3;
+ rxq_ctl |= (mdp << BGMAC_RXQ_CTL_MDP_SHIFT);
+ bgmac_write(bgmac, BGMAC_RXQ_CTL, rxq_ctl);
+}
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */
+static void bgmac_chip_init(struct bgmac *bgmac, bool full_init)
+{
+ struct bgmac_dma_ring *ring;
+ int i;
+
+ /* 1 interrupt per received frame */
+ bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT);
+
+ /* Enable 802.3x tx flow control (honor received PAUSE frames) */
+ bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_RPI, 0, true);
+
+ bgmac_set_rx_mode(bgmac->net_dev);
+
+ bgmac_write_mac_address(bgmac, bgmac->net_dev->dev_addr);
+
+ if (bgmac->loopback)
+ bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_ML, false);
+ else
+ bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_ML, 0, false);
+
+ bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN);
+
+ if (!bgmac->autoneg) {
+ bgmac_speed(bgmac, bgmac->speed);
+ bgmac_phy_force(bgmac);
+ } else if (bgmac->speed) { /* if there is anything to adv */
+ bgmac_phy_advertise(bgmac);
+ }
+
+ if (full_init) {
+ bgmac_dma_init(bgmac);
+ if (1) /* FIXME: is there any case we don't want IRQs? */
+ bgmac_chip_intrs_on(bgmac);
+ } else {
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
+ ring = &bgmac->rx_ring[i];
+ bgmac_dma_rx_enable(bgmac, ring);
+ }
+ }
+
+ bgmac_enable(bgmac);
+}
+
+static irqreturn_t bgmac_interrupt(int irq, void *dev_id)
+{
+ struct bgmac *bgmac = netdev_priv(dev_id);
+
+ u32 int_status = bgmac_read(bgmac, BGMAC_INT_STATUS);
+ int_status &= bgmac->int_mask;
+
+ if (!int_status)
+ return IRQ_NONE;
+
+ /* Ack */
+ bgmac_write(bgmac, BGMAC_INT_STATUS, int_status);
+
+ /* Disable new interrupts until handling existing ones */
+ bgmac_chip_intrs_off(bgmac);
+
+ bgmac->int_status = int_status;
+
+ napi_schedule(&bgmac->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int bgmac_poll(struct napi_struct *napi, int weight)
+{
+ struct bgmac *bgmac = container_of(napi, struct bgmac, napi);
+ struct bgmac_dma_ring *ring;
+ int handled = 0;
+
+ if (bgmac->int_status & BGMAC_IS_TX0) {
+ ring = &bgmac->tx_ring[0];
+ bgmac_dma_tx_free(bgmac, ring);
+ bgmac->int_status &= ~BGMAC_IS_TX0;
+ }
+
+ if (bgmac->int_status & BGMAC_IS_RX) {
+ ring = &bgmac->rx_ring[0];
+ handled += bgmac_dma_rx_read(bgmac, ring, weight);
+ bgmac->int_status &= ~BGMAC_IS_RX;
+ }
+
+ if (bgmac->int_status) {
+ bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", bgmac->int_status);
+ bgmac->int_status = 0;
+ }
+
+ if (handled < weight)
+ napi_complete(napi);
+
+ bgmac_chip_intrs_on(bgmac);
+
+ return handled;
+}
+
+/**************************************************
+ * net_device_ops
+ **************************************************/
+
+static int bgmac_open(struct net_device *net_dev)
+{
+ struct bgmac *bgmac = netdev_priv(net_dev);
+ int err = 0;
+
+ bgmac_chip_reset(bgmac);
+ /* Specs say about reclaiming rings here, but we do that in DMA init */
+ bgmac_chip_init(bgmac, true);
+
+ err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED,
+ KBUILD_MODNAME, net_dev);
+ if (err < 0) {
+ bgmac_err(bgmac, "IRQ request error: %d!\n", err);
+ goto err_out;
+ }
+ napi_enable(&bgmac->napi);
+
+ netif_carrier_on(net_dev);
+
+err_out:
+ return err;
+}
+
+static int bgmac_stop(struct net_device *net_dev)
+{
+ struct bgmac *bgmac = netdev_priv(net_dev);
+
+ netif_carrier_off(net_dev);
+
+ napi_disable(&bgmac->napi);
+ bgmac_chip_intrs_off(bgmac);
+ free_irq(bgmac->core->irq, net_dev);
+
+ bgmac_chip_reset(bgmac);
+
+ return 0;
+}
+
+static netdev_tx_t bgmac_start_xmit(struct sk_buff *skb,
+ struct net_device *net_dev)
+{
+ struct bgmac *bgmac = netdev_priv(net_dev);
+ struct bgmac_dma_ring *ring;
+
+ /* No QOS support yet */
+ ring = &bgmac->tx_ring[0];
+ return bgmac_dma_tx_add(bgmac, ring, skb);
+}
+
+static int bgmac_set_mac_address(struct net_device *net_dev, void *addr)
+{
+ struct bgmac *bgmac = netdev_priv(net_dev);
+ int ret;
+
+ ret = eth_prepare_mac_addr_change(net_dev, addr);
+ if (ret < 0)
+ return ret;
+ bgmac_write_mac_address(bgmac, (u8 *)addr);
+ eth_commit_mac_addr_change(net_dev, addr);
+ return 0;
+}
+
+static int bgmac_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
+{
+ struct bgmac *bgmac = netdev_priv(net_dev);
+ struct mii_ioctl_data *data = if_mii(ifr);
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = bgmac->phyaddr;
+ /* fallthru */
+ case SIOCGMIIREG:
+ if (!netif_running(net_dev))
+ return -EAGAIN;
+ data->val_out = bgmac_phy_read(bgmac, data->phy_id,
+ data->reg_num & 0x1f);
+ return 0;
+ case SIOCSMIIREG:
+ if (!netif_running(net_dev))
+ return -EAGAIN;
+ bgmac_phy_write(bgmac, data->phy_id, data->reg_num & 0x1f,
+ data->val_in);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct net_device_ops bgmac_netdev_ops = {
+ .ndo_open = bgmac_open,
+ .ndo_stop = bgmac_stop,
+ .ndo_start_xmit = bgmac_start_xmit,
+ .ndo_set_rx_mode = bgmac_set_rx_mode,
+ .ndo_set_mac_address = bgmac_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = bgmac_ioctl,
+};
+
+/**************************************************
+ * ethtool_ops
+ **************************************************/
+
+static int bgmac_get_settings(struct net_device *net_dev,
+ struct ethtool_cmd *cmd)
+{
+ struct bgmac *bgmac = netdev_priv(net_dev);
+
+ cmd->supported = SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg;
+
+ if (bgmac->autoneg) {
+ WARN_ON(cmd->advertising);
+ if (bgmac->full_duplex) {
+ if (bgmac->speed & BGMAC_SPEED_10)
+ cmd->advertising |= ADVERTISED_10baseT_Full;
+ if (bgmac->speed & BGMAC_SPEED_100)
+ cmd->advertising |= ADVERTISED_100baseT_Full;
+ if (bgmac->speed & BGMAC_SPEED_1000)
+ cmd->advertising |= ADVERTISED_1000baseT_Full;
+ } else {
+ if (bgmac->speed & BGMAC_SPEED_10)
+ cmd->advertising |= ADVERTISED_10baseT_Half;
+ if (bgmac->speed & BGMAC_SPEED_100)
+ cmd->advertising |= ADVERTISED_100baseT_Half;
+ if (bgmac->speed & BGMAC_SPEED_1000)
+ cmd->advertising |= ADVERTISED_1000baseT_Half;
+ }
+ } else {
+ switch (bgmac->speed) {
+ case BGMAC_SPEED_10:
+ ethtool_cmd_speed_set(cmd, SPEED_10);
+ break;
+ case BGMAC_SPEED_100:
+ ethtool_cmd_speed_set(cmd, SPEED_100);
+ break;
+ case BGMAC_SPEED_1000:
+ ethtool_cmd_speed_set(cmd, SPEED_1000);
+ break;
+ }
+ }
+
+ cmd->duplex = bgmac->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+
+ cmd->autoneg = bgmac->autoneg;
+
+ return 0;
+}
+
+#if 0
+static int bgmac_set_settings(struct net_device *net_dev,
+ struct ethtool_cmd *cmd)
+{
+ struct bgmac *bgmac = netdev_priv(net_dev);
+
+ return -1;
+}
+#endif
+
+static void bgmac_get_drvinfo(struct net_device *net_dev,
+ struct ethtool_drvinfo *info)
+{
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ strlcpy(info->bus_info, "BCMA", sizeof(info->bus_info));
+}
+
+static const struct ethtool_ops bgmac_ethtool_ops = {
+ .get_settings = bgmac_get_settings,
+ .get_drvinfo = bgmac_get_drvinfo,
+};
+
+/**************************************************
+ * BCMA bus ops
+ **************************************************/
+
+/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
+static int bgmac_probe(struct bcma_device *core)
+{
+ struct net_device *net_dev;
+ struct bgmac *bgmac;
+ struct ssb_sprom *sprom = &core->bus->sprom;
+ u8 *mac = core->core_unit ? sprom->et1mac : sprom->et0mac;
+ int err;
+
+ /* We don't support 2nd, 3rd, ... units, SPROM has to be adjusted */
+ if (core->core_unit > 1) {
+ pr_err("Unsupported core_unit %d\n", core->core_unit);
+ return -ENOTSUPP;
+ }
+
+ if (!is_valid_ether_addr(mac)) {
+ dev_err(&core->dev, "Invalid MAC addr: %pM\n", mac);
+ eth_random_addr(mac);
+ dev_warn(&core->dev, "Using random MAC: %pM\n", mac);
+ }
+
+ /* Allocation and references */
+ net_dev = alloc_etherdev(sizeof(*bgmac));
+ if (!net_dev)
+ return -ENOMEM;
+ net_dev->netdev_ops = &bgmac_netdev_ops;
+ net_dev->irq = core->irq;
+ SET_ETHTOOL_OPS(net_dev, &bgmac_ethtool_ops);
+ bgmac = netdev_priv(net_dev);
+ bgmac->net_dev = net_dev;
+ bgmac->core = core;
+ bcma_set_drvdata(core, bgmac);
+
+ /* Defaults */
+ bgmac->autoneg = true;
+ bgmac->full_duplex = true;
+ bgmac->speed = BGMAC_SPEED_10 | BGMAC_SPEED_100 | BGMAC_SPEED_1000;
+ memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN);
+
+ /* On BCM4706 we need common core to access PHY */
+ if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
+ !core->bus->drv_gmac_cmn.core) {
+ bgmac_err(bgmac, "GMAC CMN core not found (required for BCM4706)\n");
+ err = -ENODEV;
+ goto err_netdev_free;
+ }
+ bgmac->cmn = core->bus->drv_gmac_cmn.core;
+
+ bgmac->phyaddr = core->core_unit ? sprom->et1phyaddr :
+ sprom->et0phyaddr;
+ bgmac->phyaddr &= BGMAC_PHY_MASK;
+ if (bgmac->phyaddr == BGMAC_PHY_MASK) {
+ bgmac_err(bgmac, "No PHY found\n");
+ err = -ENODEV;
+ goto err_netdev_free;
+ }
+ bgmac_info(bgmac, "Found PHY addr: %d%s\n", bgmac->phyaddr,
+ bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : "");
+
+ if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
+ bgmac_err(bgmac, "PCI setup not implemented\n");
+ err = -ENOTSUPP;
+ goto err_netdev_free;
+ }
+
+ bgmac_chip_reset(bgmac);
+
+ err = bgmac_dma_alloc(bgmac);
+ if (err) {
+ bgmac_err(bgmac, "Unable to alloc memory for DMA\n");
+ goto err_netdev_free;
+ }
+
+ bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK;
+ if (nvram_getenv("et0_no_txint", NULL, 0) == 0)
+ bgmac->int_mask &= ~BGMAC_IS_TX_MASK;
+
+ /* TODO: reset the external phy. Specs are needed */
+ bgmac_phy_reset(bgmac);
+
+ bgmac->has_robosw = !!(core->bus->sprom.boardflags_lo &
+ BGMAC_BFL_ENETROBO);
+ if (bgmac->has_robosw)
+ bgmac_warn(bgmac, "Support for Roboswitch not implemented\n");
+
+ if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
+ bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
+
+ err = register_netdev(bgmac->net_dev);
+ if (err) {
+ bgmac_err(bgmac, "Cannot register net device\n");
+ err = -ENOTSUPP;
+ goto err_dma_free;
+ }
+
+ netif_carrier_off(net_dev);
+
+ netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
+
+ return 0;
+
+err_dma_free:
+ bgmac_dma_free(bgmac);
+
+err_netdev_free:
+ bcma_set_drvdata(core, NULL);
+ free_netdev(net_dev);
+
+ return err;
+}
+
+static void bgmac_remove(struct bcma_device *core)
+{
+ struct bgmac *bgmac = bcma_get_drvdata(core);
+
+ netif_napi_del(&bgmac->napi);
+ unregister_netdev(bgmac->net_dev);
+ bgmac_dma_free(bgmac);
+ bcma_set_drvdata(core, NULL);
+ free_netdev(bgmac->net_dev);
+}
+
+static struct bcma_driver bgmac_bcma_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = bgmac_bcma_tbl,
+ .probe = bgmac_probe,
+ .remove = bgmac_remove,
+};
+
+static int __init bgmac_init(void)
+{
+ int err;
+
+ err = bcma_driver_register(&bgmac_bcma_driver);
+ if (err)
+ return err;
+ pr_info("Broadcom 47xx GBit MAC driver loaded\n");
+
+ return 0;
+}
+
+static void __exit bgmac_exit(void)
+{
+ bcma_driver_unregister(&bgmac_bcma_driver);
+}
+
+module_init(bgmac_init)
+module_exit(bgmac_exit)
+
+MODULE_AUTHOR("Rafał Miłecki");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h
new file mode 100644
index 000000000000..4ede614c81f8
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bgmac.h
@@ -0,0 +1,453 @@
+#ifndef _BGMAC_H
+#define _BGMAC_H
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define bgmac_err(bgmac, fmt, ...) \
+ dev_err(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
+#define bgmac_warn(bgmac, fmt, ...) \
+ dev_warn(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
+#define bgmac_info(bgmac, fmt, ...) \
+ dev_info(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
+#define bgmac_dbg(bgmac, fmt, ...) \
+ dev_dbg(&(bgmac)->core->dev, fmt, ##__VA_ARGS__)
+
+#include <linux/bcma/bcma.h>
+#include <linux/netdevice.h>
+
+#define BGMAC_DEV_CTL 0x000
+#define BGMAC_DC_TSM 0x00000002
+#define BGMAC_DC_CFCO 0x00000004
+#define BGMAC_DC_RLSS 0x00000008
+#define BGMAC_DC_MROR 0x00000010
+#define BGMAC_DC_FCM_MASK 0x00000060
+#define BGMAC_DC_FCM_SHIFT 5
+#define BGMAC_DC_NAE 0x00000080
+#define BGMAC_DC_TF 0x00000100
+#define BGMAC_DC_RDS_MASK 0x00030000
+#define BGMAC_DC_RDS_SHIFT 16
+#define BGMAC_DC_TDS_MASK 0x000c0000
+#define BGMAC_DC_TDS_SHIFT 18
+#define BGMAC_DEV_STATUS 0x004 /* Configuration of the interface */
+#define BGMAC_DS_RBF 0x00000001
+#define BGMAC_DS_RDF 0x00000002
+#define BGMAC_DS_RIF 0x00000004
+#define BGMAC_DS_TBF 0x00000008
+#define BGMAC_DS_TDF 0x00000010
+#define BGMAC_DS_TIF 0x00000020
+#define BGMAC_DS_PO 0x00000040
+#define BGMAC_DS_MM_MASK 0x00000300 /* Mode of the interface */
+#define BGMAC_DS_MM_SHIFT 8
+#define BGMAC_BIST_STATUS 0x00c
+#define BGMAC_INT_STATUS 0x020 /* Interrupt status */
+#define BGMAC_IS_MRO 0x00000001
+#define BGMAC_IS_MTO 0x00000002
+#define BGMAC_IS_TFD 0x00000004
+#define BGMAC_IS_LS 0x00000008
+#define BGMAC_IS_MDIO 0x00000010
+#define BGMAC_IS_MR 0x00000020
+#define BGMAC_IS_MT 0x00000040
+#define BGMAC_IS_TO 0x00000080
+#define BGMAC_IS_DESC_ERR 0x00000400 /* Descriptor error */
+#define BGMAC_IS_DATA_ERR 0x00000800 /* Data error */
+#define BGMAC_IS_DESC_PROT_ERR 0x00001000 /* Descriptor protocol error */
+#define BGMAC_IS_RX_DESC_UNDERF 0x00002000 /* Receive descriptor underflow */
+#define BGMAC_IS_RX_F_OVERF 0x00004000 /* Receive FIFO overflow */
+#define BGMAC_IS_TX_F_UNDERF 0x00008000 /* Transmit FIFO underflow */
+#define BGMAC_IS_RX 0x00010000 /* Interrupt for RX queue 0 */
+#define BGMAC_IS_TX0 0x01000000 /* Interrupt for TX queue 0 */
+#define BGMAC_IS_TX1 0x02000000 /* Interrupt for TX queue 1 */
+#define BGMAC_IS_TX2 0x04000000 /* Interrupt for TX queue 2 */
+#define BGMAC_IS_TX3 0x08000000 /* Interrupt for TX queue 3 */
+#define BGMAC_IS_TX_MASK 0x0f000000
+#define BGMAC_IS_INTMASK 0x0f01fcff
+#define BGMAC_IS_ERRMASK 0x0000fc00
+#define BGMAC_INT_MASK 0x024 /* Interrupt mask */
+#define BGMAC_GP_TIMER 0x028
+#define BGMAC_INT_RECV_LAZY 0x100
+#define BGMAC_IRL_TO_MASK 0x00ffffff
+#define BGMAC_IRL_FC_MASK 0xff000000
+#define BGMAC_IRL_FC_SHIFT 24 /* Shift the number of interrupts triggered per received frame */
+#define BGMAC_FLOW_CTL_THRESH 0x104 /* Flow control thresholds */
+#define BGMAC_WRRTHRESH 0x108
+#define BGMAC_GMAC_IDLE_CNT_THRESH 0x10c
+#define BGMAC_PHY_ACCESS 0x180 /* PHY access address */
+#define BGMAC_PA_DATA_MASK 0x0000ffff
+#define BGMAC_PA_ADDR_MASK 0x001f0000
+#define BGMAC_PA_ADDR_SHIFT 16
+#define BGMAC_PA_REG_MASK 0x1f000000
+#define BGMAC_PA_REG_SHIFT 24
+#define BGMAC_PA_WRITE 0x20000000
+#define BGMAC_PA_START 0x40000000
+#define BGMAC_PHY_CNTL 0x188 /* PHY control address */
+#define BGMAC_PC_EPA_MASK 0x0000001f
+#define BGMAC_PC_MCT_MASK 0x007f0000
+#define BGMAC_PC_MCT_SHIFT 16
+#define BGMAC_PC_MTE 0x00800000
+#define BGMAC_TXQ_CTL 0x18c
+#define BGMAC_TXQ_CTL_DBT_MASK 0x00000fff
+#define BGMAC_TXQ_CTL_DBT_SHIFT 0
+#define BGMAC_RXQ_CTL 0x190
+#define BGMAC_RXQ_CTL_DBT_MASK 0x00000fff
+#define BGMAC_RXQ_CTL_DBT_SHIFT 0
+#define BGMAC_RXQ_CTL_PTE 0x00001000
+#define BGMAC_RXQ_CTL_MDP_MASK 0x3f000000
+#define BGMAC_RXQ_CTL_MDP_SHIFT 24
+#define BGMAC_GPIO_SELECT 0x194
+#define BGMAC_GPIO_OUTPUT_EN 0x198
+/* For 0x1e0 see BCMA_CLKCTLST */
+#define BGMAC_HW_WAR 0x1e4
+#define BGMAC_PWR_CTL 0x1e8
+#define BGMAC_DMA_BASE0 0x200 /* Tx and Rx controller */
+#define BGMAC_DMA_BASE1 0x240 /* Tx controller only */
+#define BGMAC_DMA_BASE2 0x280 /* Tx controller only */
+#define BGMAC_DMA_BASE3 0x2C0 /* Tx controller only */
+#define BGMAC_TX_GOOD_OCTETS 0x300
+#define BGMAC_TX_GOOD_OCTETS_HIGH 0x304
+#define BGMAC_TX_GOOD_PKTS 0x308
+#define BGMAC_TX_OCTETS 0x30c
+#define BGMAC_TX_OCTETS_HIGH 0x310
+#define BGMAC_TX_PKTS 0x314
+#define BGMAC_TX_BROADCAST_PKTS 0x318
+#define BGMAC_TX_MULTICAST_PKTS 0x31c
+#define BGMAC_TX_LEN_64 0x320
+#define BGMAC_TX_LEN_65_TO_127 0x324
+#define BGMAC_TX_LEN_128_TO_255 0x328
+#define BGMAC_TX_LEN_256_TO_511 0x32c
+#define BGMAC_TX_LEN_512_TO_1023 0x330
+#define BGMAC_TX_LEN_1024_TO_1522 0x334
+#define BGMAC_TX_LEN_1523_TO_2047 0x338
+#define BGMAC_TX_LEN_2048_TO_4095 0x33c
+#define BGMAC_TX_LEN_4095_TO_8191 0x340
+#define BGMAC_TX_LEN_8192_TO_MAX 0x344
+#define BGMAC_TX_JABBER_PKTS 0x348 /* Error */
+#define BGMAC_TX_OVERSIZE_PKTS 0x34c /* Error */
+#define BGMAC_TX_FRAGMENT_PKTS 0x350
+#define BGMAC_TX_UNDERRUNS 0x354 /* Error */
+#define BGMAC_TX_TOTAL_COLS 0x358
+#define BGMAC_TX_SINGLE_COLS 0x35c
+#define BGMAC_TX_MULTIPLE_COLS 0x360
+#define BGMAC_TX_EXCESSIVE_COLS 0x364 /* Error */
+#define BGMAC_TX_LATE_COLS 0x368 /* Error */
+#define BGMAC_TX_DEFERED 0x36c
+#define BGMAC_TX_CARRIER_LOST 0x370
+#define BGMAC_TX_PAUSE_PKTS 0x374
+#define BGMAC_TX_UNI_PKTS 0x378
+#define BGMAC_TX_Q0_PKTS 0x37c
+#define BGMAC_TX_Q0_OCTETS 0x380
+#define BGMAC_TX_Q0_OCTETS_HIGH 0x384
+#define BGMAC_TX_Q1_PKTS 0x388
+#define BGMAC_TX_Q1_OCTETS 0x38c
+#define BGMAC_TX_Q1_OCTETS_HIGH 0x390
+#define BGMAC_TX_Q2_PKTS 0x394
+#define BGMAC_TX_Q2_OCTETS 0x398
+#define BGMAC_TX_Q2_OCTETS_HIGH 0x39c
+#define BGMAC_TX_Q3_PKTS 0x3a0
+#define BGMAC_TX_Q3_OCTETS 0x3a4
+#define BGMAC_TX_Q3_OCTETS_HIGH 0x3a8
+#define BGMAC_RX_GOOD_OCTETS 0x3b0
+#define BGMAC_RX_GOOD_OCTETS_HIGH 0x3b4
+#define BGMAC_RX_GOOD_PKTS 0x3b8
+#define BGMAC_RX_OCTETS 0x3bc
+#define BGMAC_RX_OCTETS_HIGH 0x3c0
+#define BGMAC_RX_PKTS 0x3c4
+#define BGMAC_RX_BROADCAST_PKTS 0x3c8
+#define BGMAC_RX_MULTICAST_PKTS 0x3cc
+#define BGMAC_RX_LEN_64 0x3d0
+#define BGMAC_RX_LEN_65_TO_127 0x3d4
+#define BGMAC_RX_LEN_128_TO_255 0x3d8
+#define BGMAC_RX_LEN_256_TO_511 0x3dc
+#define BGMAC_RX_LEN_512_TO_1023 0x3e0
+#define BGMAC_RX_LEN_1024_TO_1522 0x3e4
+#define BGMAC_RX_LEN_1523_TO_2047 0x3e8
+#define BGMAC_RX_LEN_2048_TO_4095 0x3ec
+#define BGMAC_RX_LEN_4095_TO_8191 0x3f0
+#define BGMAC_RX_LEN_8192_TO_MAX 0x3f4
+#define BGMAC_RX_JABBER_PKTS 0x3f8 /* Error */
+#define BGMAC_RX_OVERSIZE_PKTS 0x3fc /* Error */
+#define BGMAC_RX_FRAGMENT_PKTS 0x400
+#define BGMAC_RX_MISSED_PKTS 0x404 /* Error */
+#define BGMAC_RX_CRC_ALIGN_ERRS 0x408 /* Error */
+#define BGMAC_RX_UNDERSIZE 0x40c /* Error */
+#define BGMAC_RX_CRC_ERRS 0x410 /* Error */
+#define BGMAC_RX_ALIGN_ERRS 0x414 /* Error */
+#define BGMAC_RX_SYMBOL_ERRS 0x418 /* Error */
+#define BGMAC_RX_PAUSE_PKTS 0x41c
+#define BGMAC_RX_NONPAUSE_PKTS 0x420
+#define BGMAC_RX_SACHANGES 0x424
+#define BGMAC_RX_UNI_PKTS 0x428
+#define BGMAC_UNIMAC_VERSION 0x800
+#define BGMAC_HDBKP_CTL 0x804
+#define BGMAC_CMDCFG 0x808 /* Configuration */
+#define BGMAC_CMDCFG_TE 0x00000001 /* Set to activate TX */
+#define BGMAC_CMDCFG_RE 0x00000002 /* Set to activate RX */
+#define BGMAC_CMDCFG_ES_MASK 0x0000000c /* Ethernet speed see gmac_speed */
+#define BGMAC_CMDCFG_ES_10 0x00000000
+#define BGMAC_CMDCFG_ES_100 0x00000004
+#define BGMAC_CMDCFG_ES_1000 0x00000008
+#define BGMAC_CMDCFG_PROM 0x00000010 /* Set to activate promiscuous mode */
+#define BGMAC_CMDCFG_PAD_EN 0x00000020
+#define BGMAC_CMDCFG_CF 0x00000040
+#define BGMAC_CMDCFG_PF 0x00000080
+#define BGMAC_CMDCFG_RPI 0x00000100 /* Unset to enable 802.3x tx flow control */
+#define BGMAC_CMDCFG_TAI 0x00000200
+#define BGMAC_CMDCFG_HD 0x00000400 /* Set if in half duplex mode */
+#define BGMAC_CMDCFG_HD_SHIFT 10
+#define BGMAC_CMDCFG_SR 0x00000800 /* Set to reset mode */
+#define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */
+#define BGMAC_CMDCFG_AE 0x00400000
+#define BGMAC_CMDCFG_CFE 0x00800000
+#define BGMAC_CMDCFG_NLC 0x01000000
+#define BGMAC_CMDCFG_RL 0x02000000
+#define BGMAC_CMDCFG_RED 0x04000000
+#define BGMAC_CMDCFG_PE 0x08000000
+#define BGMAC_CMDCFG_TPI 0x10000000
+#define BGMAC_CMDCFG_AT 0x20000000
+#define BGMAC_MACADDR_HIGH 0x80c /* High 4 octets of own mac address */
+#define BGMAC_MACADDR_LOW 0x810 /* Low 2 octets of own mac address */
+#define BGMAC_RXMAX_LENGTH 0x814 /* Max receive frame length with vlan tag */
+#define BGMAC_PAUSEQUANTA 0x818
+#define BGMAC_MAC_MODE 0x844
+#define BGMAC_OUTERTAG 0x848
+#define BGMAC_INNERTAG 0x84c
+#define BGMAC_TXIPG 0x85c
+#define BGMAC_PAUSE_CTL 0xb30
+#define BGMAC_TX_FLUSH 0xb34
+#define BGMAC_RX_STATUS 0xb38
+#define BGMAC_TX_STATUS 0xb3c
+
+#define BGMAC_PHY_CTL 0x00
+#define BGMAC_PHY_CTL_SPEED_MSB 0x0040
+#define BGMAC_PHY_CTL_DUPLEX 0x0100 /* duplex mode */
+#define BGMAC_PHY_CTL_RESTART 0x0200 /* restart autonegotiation */
+#define BGMAC_PHY_CTL_ANENAB 0x1000 /* enable autonegotiation */
+#define BGMAC_PHY_CTL_SPEED 0x2000
+#define BGMAC_PHY_CTL_LOOP 0x4000 /* loopback */
+#define BGMAC_PHY_CTL_RESET 0x8000 /* reset */
+/* Helpers */
+#define BGMAC_PHY_CTL_SPEED_10 0
+#define BGMAC_PHY_CTL_SPEED_100 BGMAC_PHY_CTL_SPEED
+#define BGMAC_PHY_CTL_SPEED_1000 BGMAC_PHY_CTL_SPEED_MSB
+#define BGMAC_PHY_ADV 0x04
+#define BGMAC_PHY_ADV_10HALF 0x0020 /* advertise 10MBits/s half duplex */
+#define BGMAC_PHY_ADV_10FULL 0x0040 /* advertise 10MBits/s full duplex */
+#define BGMAC_PHY_ADV_100HALF 0x0080 /* advertise 100MBits/s half duplex */
+#define BGMAC_PHY_ADV_100FULL 0x0100 /* advertise 100MBits/s full duplex */
+#define BGMAC_PHY_ADV2 0x09
+#define BGMAC_PHY_ADV2_1000HALF 0x0100 /* advertise 1000MBits/s half duplex */
+#define BGMAC_PHY_ADV2_1000FULL 0x0200 /* advertise 1000MBits/s full duplex */
+
+/* BCMA GMAC core specific IO Control (BCMA_IOCTL) flags */
+#define BGMAC_BCMA_IOCTL_SW_CLKEN 0x00000004 /* PHY Clock Enable */
+#define BGMAC_BCMA_IOCTL_SW_RESET 0x00000008 /* PHY Reset */
+
+/* BCMA GMAC core specific IO status (BCMA_IOST) flags */
+#define BGMAC_BCMA_IOST_ATTACHED 0x00000800
+
+#define BGMAC_NUM_MIB_TX_REGS \
+ (((BGMAC_TX_Q3_OCTETS_HIGH - BGMAC_TX_GOOD_OCTETS) / 4) + 1)
+#define BGMAC_NUM_MIB_RX_REGS \
+ (((BGMAC_RX_UNI_PKTS - BGMAC_RX_GOOD_OCTETS) / 4) + 1)
+
+#define BGMAC_DMA_TX_CTL 0x00
+#define BGMAC_DMA_TX_ENABLE 0x00000001
+#define BGMAC_DMA_TX_SUSPEND 0x00000002
+#define BGMAC_DMA_TX_LOOPBACK 0x00000004
+#define BGMAC_DMA_TX_FLUSH 0x00000010
+#define BGMAC_DMA_TX_PARITY_DISABLE 0x00000800
+#define BGMAC_DMA_TX_ADDREXT_MASK 0x00030000
+#define BGMAC_DMA_TX_ADDREXT_SHIFT 16
+#define BGMAC_DMA_TX_INDEX 0x04
+#define BGMAC_DMA_TX_RINGLO 0x08
+#define BGMAC_DMA_TX_RINGHI 0x0C
+#define BGMAC_DMA_TX_STATUS 0x10
+#define BGMAC_DMA_TX_STATDPTR 0x00001FFF
+#define BGMAC_DMA_TX_STAT 0xF0000000
+#define BGMAC_DMA_TX_STAT_DISABLED 0x00000000
+#define BGMAC_DMA_TX_STAT_ACTIVE 0x10000000
+#define BGMAC_DMA_TX_STAT_IDLEWAIT 0x20000000
+#define BGMAC_DMA_TX_STAT_STOPPED 0x30000000
+#define BGMAC_DMA_TX_STAT_SUSP 0x40000000
+#define BGMAC_DMA_TX_ERROR 0x14
+#define BGMAC_DMA_TX_ERRDPTR 0x0001FFFF
+#define BGMAC_DMA_TX_ERR 0xF0000000
+#define BGMAC_DMA_TX_ERR_NOERR 0x00000000
+#define BGMAC_DMA_TX_ERR_PROT 0x10000000
+#define BGMAC_DMA_TX_ERR_UNDERRUN 0x20000000
+#define BGMAC_DMA_TX_ERR_TRANSFER 0x30000000
+#define BGMAC_DMA_TX_ERR_DESCREAD 0x40000000
+#define BGMAC_DMA_TX_ERR_CORE 0x50000000
+#define BGMAC_DMA_RX_CTL 0x20
+#define BGMAC_DMA_RX_ENABLE 0x00000001
+#define BGMAC_DMA_RX_FRAME_OFFSET_MASK 0x000000FE
+#define BGMAC_DMA_RX_FRAME_OFFSET_SHIFT 1
+#define BGMAC_DMA_RX_DIRECT_FIFO 0x00000100
+#define BGMAC_DMA_RX_OVERFLOW_CONT 0x00000400
+#define BGMAC_DMA_RX_PARITY_DISABLE 0x00000800
+#define BGMAC_DMA_RX_ADDREXT_MASK 0x00030000
+#define BGMAC_DMA_RX_ADDREXT_SHIFT 16
+#define BGMAC_DMA_RX_INDEX 0x24
+#define BGMAC_DMA_RX_RINGLO 0x28
+#define BGMAC_DMA_RX_RINGHI 0x2C
+#define BGMAC_DMA_RX_STATUS 0x30
+#define BGMAC_DMA_RX_STATDPTR 0x00001FFF
+#define BGMAC_DMA_RX_STAT 0xF0000000
+#define BGMAC_DMA_RX_STAT_DISABLED 0x00000000
+#define BGMAC_DMA_RX_STAT_ACTIVE 0x10000000
+#define BGMAC_DMA_RX_STAT_IDLEWAIT 0x20000000
+#define BGMAC_DMA_RX_STAT_STOPPED 0x30000000
+#define BGMAC_DMA_RX_STAT_SUSP 0x40000000
+#define BGMAC_DMA_RX_ERROR 0x34
+#define BGMAC_DMA_RX_ERRDPTR 0x0001FFFF
+#define BGMAC_DMA_RX_ERR 0xF0000000
+#define BGMAC_DMA_RX_ERR_NOERR 0x00000000
+#define BGMAC_DMA_RX_ERR_PROT 0x10000000
+#define BGMAC_DMA_RX_ERR_UNDERRUN 0x20000000
+#define BGMAC_DMA_RX_ERR_TRANSFER 0x30000000
+#define BGMAC_DMA_RX_ERR_DESCREAD 0x40000000
+#define BGMAC_DMA_RX_ERR_CORE 0x50000000
+
+#define BGMAC_DESC_CTL0_EOT 0x10000000 /* End of ring */
+#define BGMAC_DESC_CTL0_IOC 0x20000000 /* IRQ on complete */
+#define BGMAC_DESC_CTL0_SOF 0x40000000 /* Start of frame */
+#define BGMAC_DESC_CTL0_EOF 0x80000000 /* End of frame */
+#define BGMAC_DESC_CTL1_LEN 0x00001FFF
+
+#define BGMAC_PHY_NOREGS 0x1E
+#define BGMAC_PHY_MASK 0x1F
+
+#define BGMAC_MAX_TX_RINGS 4
+#define BGMAC_MAX_RX_RINGS 1
+
+#define BGMAC_TX_RING_SLOTS 128
+#define BGMAC_RX_RING_SLOTS 512 - 1 /* Why -1? Well, Broadcom does that... */
+
+#define BGMAC_RX_HEADER_LEN 28 /* Last 24 bytes are unused. Well... */
+#define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */
+#define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */
+#define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
+
+#define BGMAC_BFL_ENETROBO 0x0010 /* has ephy roboswitch spi */
+#define BGMAC_BFL_ENETADM 0x0080 /* has ADMtek switch */
+#define BGMAC_BFL_ENETVLAN 0x0100 /* can do vlan */
+
+#define BGMAC_CHIPCTL_1_IF_TYPE_MASK 0x00000030
+#define BGMAC_CHIPCTL_1_IF_TYPE_RMII 0x00000000
+#define BGMAC_CHIPCTL_1_IF_TYPE_MI 0x00000010
+#define BGMAC_CHIPCTL_1_IF_TYPE_RGMII 0x00000020
+#define BGMAC_CHIPCTL_1_SW_TYPE_MASK 0x000000C0
+#define BGMAC_CHIPCTL_1_SW_TYPE_EPHY 0x00000000
+#define BGMAC_CHIPCTL_1_SW_TYPE_EPHYMII 0x00000040
+#define BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII 0x00000080
+#define BGMAC_CHIPCTL_1_SW_TYPE_RGMII 0x000000C0
+#define BGMAC_CHIPCTL_1_RXC_DLL_BYPASS 0x00010000
+
+#define BGMAC_SPEED_10 0x0001
+#define BGMAC_SPEED_100 0x0002
+#define BGMAC_SPEED_1000 0x0004
+
+#define BGMAC_WEIGHT 64
+
+#define ETHER_MAX_LEN 1518
+
+struct bgmac_slot_info {
+ struct sk_buff *skb;
+ dma_addr_t dma_addr;
+};
+
+struct bgmac_dma_desc {
+ __le32 ctl0;
+ __le32 ctl1;
+ __le32 addr_low;
+ __le32 addr_high;
+} __packed;
+
+enum bgmac_dma_ring_type {
+ BGMAC_DMA_RING_TX,
+ BGMAC_DMA_RING_RX,
+};
+
+/**
+ * bgmac_dma_ring - contains info about DMA ring (either TX or RX one)
+ * @start: index of the first slot containing data
+ * @end: index of a slot that can *not* be read (yet)
+ *
+ * Be really aware of the specific @end meaning. It's an index of a slot *after*
+ * the one containing data that can be read. If @start equals @end the ring is
+ * empty.
+ */
+struct bgmac_dma_ring {
+ u16 num_slots;
+ u16 start;
+ u16 end;
+
+ u16 mmio_base;
+ struct bgmac_dma_desc *cpu_base;
+ dma_addr_t dma_base;
+
+ struct bgmac_slot_info slots[BGMAC_RX_RING_SLOTS];
+};
+
+struct bgmac_rx_header {
+ __le16 len;
+ __le16 flags;
+ __le16 pad[12];
+};
+
+struct bgmac {
+ struct bcma_device *core;
+ struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
+ struct net_device *net_dev;
+ struct napi_struct napi;
+
+ /* DMA */
+ struct bgmac_dma_ring tx_ring[BGMAC_MAX_TX_RINGS];
+ struct bgmac_dma_ring rx_ring[BGMAC_MAX_RX_RINGS];
+
+ /* Stats */
+ bool stats_grabbed;
+ u32 mib_tx_regs[BGMAC_NUM_MIB_TX_REGS];
+ u32 mib_rx_regs[BGMAC_NUM_MIB_RX_REGS];
+
+ /* Int */
+ u32 int_mask;
+ u32 int_status;
+
+ /* Speed-related */
+ int speed;
+ bool autoneg;
+ bool full_duplex;
+
+ u8 phyaddr;
+ bool has_robosw;
+
+ bool loopback;
+};
+
+static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
+{
+ return bcma_read32(bgmac->core, offset);
+}
+
+static inline void bgmac_write(struct bgmac *bgmac, u16 offset, u32 value)
+{
+ bcma_write32(bgmac->core, offset, value);
+}
+
+static inline void bgmac_maskset(struct bgmac *bgmac, u16 offset, u32 mask,
+ u32 set)
+{
+ bgmac_write(bgmac, offset, (bgmac_read(bgmac, offset) & mask) | set);
+}
+
+static inline void bgmac_mask(struct bgmac *bgmac, u16 offset, u32 mask)
+{
+ bgmac_maskset(bgmac, offset, mask, 0);
+}
+
+static inline void bgmac_set(struct bgmac *bgmac, u16 offset, u32 set)
+{
+ bgmac_maskset(bgmac, offset, ~0, set);
+}
+
+#endif /* _BGMAC_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index a1adfaf87f49..2f0ba8f2fd6c 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -8543,7 +8543,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, dev);
memcpy(dev->dev_addr, bp->mac_addr, 6);
- memcpy(dev->perm_addr, bp->mac_addr, 6);
dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
NETIF_F_TSO | NETIF_F_TSO_ECN |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/Makefile b/drivers/net/ethernet/broadcom/bnx2x/Makefile
index 48fbdd48f88f..116762daae09 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/Makefile
+++ b/drivers/net/ethernet/broadcom/bnx2x/Makefile
@@ -4,4 +4,5 @@
obj-$(CONFIG_BNX2X) += bnx2x.o
-bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o
+bnx2x-y := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o
+bnx2x-$(CONFIG_BNX2X_SRIOV) += bnx2x_vfpf.o bnx2x_sriov.o
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index e8d4db10c8f3..e4605a965084 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1,6 +1,6 @@
/* bnx2x.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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
@@ -13,9 +13,12 @@
#ifndef BNX2X_H
#define BNX2X_H
+
+#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/dma-mapping.h>
#include <linux/types.h>
+#include <linux/pci_regs.h>
/* compilation time flags */
@@ -23,8 +26,8 @@
* (you will need to reboot afterwards) */
/* #define BNX2X_STOP_ON_ERROR */
-#define DRV_MODULE_VERSION "1.78.00-0"
-#define DRV_MODULE_RELDATE "2012/09/27"
+#define DRV_MODULE_VERSION "1.78.02-0"
+#define DRV_MODULE_RELDATE "2013/01/14"
#define BNX2X_BC_VER 0x040200
#if defined(CONFIG_DCB)
@@ -48,6 +51,13 @@
#include "bnx2x_sp.h"
#include "bnx2x_dcb.h"
#include "bnx2x_stats.h"
+#include "bnx2x_vfpf.h"
+
+enum bnx2x_int_mode {
+ BNX2X_INT_MODE_MSIX,
+ BNX2X_INT_MODE_INTX,
+ BNX2X_INT_MODE_MSI
+};
/* error/debug prints */
@@ -112,29 +122,29 @@ do { \
dev_info(&bp->pdev->dev, fmt, ##__VA_ARGS__); \
} while (0)
+/* Error handling */
+void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int);
#ifdef BNX2X_STOP_ON_ERROR
-void bnx2x_int_disable(struct bnx2x *bp);
#define bnx2x_panic() \
do { \
bp->panic = 1; \
BNX2X_ERR("driver assert\n"); \
- bnx2x_int_disable(bp); \
- bnx2x_panic_dump(bp); \
+ bnx2x_panic_dump(bp, true); \
} while (0)
#else
#define bnx2x_panic() \
do { \
bp->panic = 1; \
BNX2X_ERR("driver assert\n"); \
- bnx2x_panic_dump(bp); \
+ bnx2x_panic_dump(bp, false); \
} while (0)
#endif
#define bnx2x_mc_addr(ha) ((ha)->addr)
#define bnx2x_uc_addr(ha) ((ha)->addr)
-#define U64_LO(x) (u32)(((u64)(x)) & 0xffffffff)
-#define U64_HI(x) (u32)(((u64)(x)) >> 32)
+#define U64_LO(x) ((u32)(((u64)(x)) & 0xffffffff))
+#define U64_HI(x) ((u32)(((u64)(x)) >> 32))
#define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo))
@@ -334,6 +344,9 @@ union db_prod {
#define SGE_PAGE_SIZE PAGE_SIZE
#define SGE_PAGE_SHIFT PAGE_SHIFT
#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))(addr))
+#define SGE_PAGES (SGE_PAGE_SIZE * PAGES_PER_SGE)
+#define TPA_AGG_SIZE min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) * \
+ SGE_PAGES), 0xffff)
/* SGE ring related macros */
#define NUM_RX_SGE_PAGES 2
@@ -789,48 +802,63 @@ struct bnx2x_common {
#define CHIP_NUM_57711E 0x1650
#define CHIP_NUM_57712 0x1662
#define CHIP_NUM_57712_MF 0x1663
+#define CHIP_NUM_57712_VF 0x166f
#define CHIP_NUM_57713 0x1651
#define CHIP_NUM_57713E 0x1652
#define CHIP_NUM_57800 0x168a
#define CHIP_NUM_57800_MF 0x16a5
+#define CHIP_NUM_57800_VF 0x16a9
#define CHIP_NUM_57810 0x168e
#define CHIP_NUM_57810_MF 0x16ae
+#define CHIP_NUM_57810_VF 0x16af
#define CHIP_NUM_57811 0x163d
#define CHIP_NUM_57811_MF 0x163e
-#define CHIP_NUM_57840_OBSOLETE 0x168d
+#define CHIP_NUM_57811_VF 0x163f
+#define CHIP_NUM_57840_OBSOLETE 0x168d
#define CHIP_NUM_57840_MF_OBSOLETE 0x16ab
#define CHIP_NUM_57840_4_10 0x16a1
#define CHIP_NUM_57840_2_20 0x16a2
#define CHIP_NUM_57840_MF 0x16a4
+#define CHIP_NUM_57840_VF 0x16ad
#define CHIP_IS_E1(bp) (CHIP_NUM(bp) == CHIP_NUM_57710)
#define CHIP_IS_57711(bp) (CHIP_NUM(bp) == CHIP_NUM_57711)
#define CHIP_IS_57711E(bp) (CHIP_NUM(bp) == CHIP_NUM_57711E)
#define CHIP_IS_57712(bp) (CHIP_NUM(bp) == CHIP_NUM_57712)
+#define CHIP_IS_57712_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57712_VF)
#define CHIP_IS_57712_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57712_MF)
#define CHIP_IS_57800(bp) (CHIP_NUM(bp) == CHIP_NUM_57800)
#define CHIP_IS_57800_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57800_MF)
+#define CHIP_IS_57800_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57800_VF)
#define CHIP_IS_57810(bp) (CHIP_NUM(bp) == CHIP_NUM_57810)
#define CHIP_IS_57810_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57810_MF)
+#define CHIP_IS_57810_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57810_VF)
#define CHIP_IS_57811(bp) (CHIP_NUM(bp) == CHIP_NUM_57811)
#define CHIP_IS_57811_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57811_MF)
+#define CHIP_IS_57811_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57811_VF)
#define CHIP_IS_57840(bp) \
((CHIP_NUM(bp) == CHIP_NUM_57840_4_10) || \
(CHIP_NUM(bp) == CHIP_NUM_57840_2_20) || \
(CHIP_NUM(bp) == CHIP_NUM_57840_OBSOLETE))
#define CHIP_IS_57840_MF(bp) ((CHIP_NUM(bp) == CHIP_NUM_57840_MF) || \
(CHIP_NUM(bp) == CHIP_NUM_57840_MF_OBSOLETE))
+#define CHIP_IS_57840_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57840_VF)
#define CHIP_IS_E1H(bp) (CHIP_IS_57711(bp) || \
CHIP_IS_57711E(bp))
#define CHIP_IS_E2(bp) (CHIP_IS_57712(bp) || \
- CHIP_IS_57712_MF(bp))
+ CHIP_IS_57712_MF(bp) || \
+ CHIP_IS_57712_VF(bp))
#define CHIP_IS_E3(bp) (CHIP_IS_57800(bp) || \
CHIP_IS_57800_MF(bp) || \
+ CHIP_IS_57800_VF(bp) || \
CHIP_IS_57810(bp) || \
CHIP_IS_57810_MF(bp) || \
+ CHIP_IS_57810_VF(bp) || \
CHIP_IS_57811(bp) || \
CHIP_IS_57811_MF(bp) || \
+ CHIP_IS_57811_VF(bp) || \
CHIP_IS_57840(bp) || \
- CHIP_IS_57840_MF(bp))
+ CHIP_IS_57840_MF(bp) || \
+ CHIP_IS_57840_VF(bp))
#define CHIP_IS_E1x(bp) (CHIP_IS_E1((bp)) || CHIP_IS_E1H((bp)))
#define USES_WARPCORE(bp) (CHIP_IS_E3(bp))
#define IS_E1H_OFFSET (!CHIP_IS_E1(bp))
@@ -954,6 +982,11 @@ struct bnx2x_port {
extern struct workqueue_struct *bnx2x_wq;
#define BNX2X_MAX_NUM_OF_VFS 64
+#define BNX2X_VF_CID_WND 0
+#define BNX2X_CIDS_PER_VF (1 << BNX2X_VF_CID_WND)
+#define BNX2X_CLIENTS_PER_VF 1
+#define BNX2X_FIRST_VF_CID 256
+#define BNX2X_VF_CIDS (BNX2X_MAX_NUM_OF_VFS * BNX2X_CIDS_PER_VF)
#define BNX2X_VF_ID_INVALID 0xFF
/*
@@ -1104,6 +1137,7 @@ struct hw_context {
/* forward */
struct bnx2x_ilt;
+struct bnx2x_vfdb;
enum bnx2x_recovery_state {
BNX2X_RECOVERY_DONE,
@@ -1165,19 +1199,22 @@ struct bnx2x_fw_stats_req {
};
struct bnx2x_fw_stats_data {
- struct stats_counter storm_counters;
- struct per_port_stats port;
- struct per_pf_stats pf;
+ struct stats_counter storm_counters;
+ struct per_port_stats port;
+ struct per_pf_stats pf;
struct fcoe_statistics_params fcoe;
- struct per_queue_stats queue_stats[1];
+ struct per_queue_stats queue_stats[1];
};
/* Public slow path states */
enum {
BNX2X_SP_RTNL_SETUP_TC,
BNX2X_SP_RTNL_TX_TIMEOUT,
- BNX2X_SP_RTNL_AFEX_F_UPDATE,
BNX2X_SP_RTNL_FAN_FAILURE,
+ BNX2X_SP_RTNL_AFEX_F_UPDATE,
+ BNX2X_SP_RTNL_ENABLE_SRIOV,
+ BNX2X_SP_RTNL_VFPF_MCAST,
+ BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
};
@@ -1231,6 +1268,21 @@ struct bnx2x {
(vn) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1))
#define BP_FW_MB_IDX(bp) BP_FW_MB_IDX_VN(bp, BP_VN(bp))
+#ifdef CONFIG_BNX2X_SRIOV
+ /* vf pf channel mailbox contains request and response buffers */
+ struct bnx2x_vf_mbx_msg *vf2pf_mbox;
+ dma_addr_t vf2pf_mbox_mapping;
+
+ /* we set aside a copy of the acquire response */
+ struct pfvf_acquire_resp_tlv acquire_resp;
+
+ /* bulletin board for messages from pf to vf */
+ union pf_vf_bulletin *pf2vf_bulletin;
+ dma_addr_t pf2vf_bulletin_mapping;
+
+ struct pf_vf_bulletin_content old_bulletin;
+#endif /* CONFIG_BNX2X_SRIOV */
+
struct net_device *dev;
struct pci_dev *pdev;
@@ -1295,8 +1347,6 @@ struct bnx2x {
__le16 *eq_cons_sb;
atomic_t eq_spq_left; /* COMMON_XXX ramrods credit */
-
-
/* Counter for marking that there is a STAT_QUERY ramrod pending */
u16 stats_pending;
/* Counter for completed statistics ramrods */
@@ -1318,8 +1368,6 @@ struct bnx2x {
#define DISABLE_MSI_FLAG (1 << 7)
#define TPA_ENABLE_FLAG (1 << 8)
#define NO_MCP_FLAG (1 << 9)
-
-#define BP_NOMCP(bp) (bp->flags & NO_MCP_FLAG)
#define GRO_ENABLE_FLAG (1 << 10)
#define MF_FUNC_DIS (1 << 11)
#define OWN_CNIC_IRQ (1 << 12)
@@ -1330,6 +1378,17 @@ struct bnx2x {
#define BC_SUPPORTS_FCOE_FEATURES (1 << 19)
#define USING_SINGLE_MSIX_FLAG (1 << 20)
#define BC_SUPPORTS_DCBX_MSG_NON_PMF (1 << 21)
+#define IS_VF_FLAG (1 << 22)
+
+#define BP_NOMCP(bp) ((bp)->flags & NO_MCP_FLAG)
+
+#ifdef CONFIG_BNX2X_SRIOV
+#define IS_VF(bp) ((bp)->flags & IS_VF_FLAG)
+#define IS_PF(bp) (!((bp)->flags & IS_VF_FLAG))
+#else
+#define IS_VF(bp) false
+#define IS_PF(bp) true
+#endif
#define NO_ISCSI(bp) ((bp)->flags & NO_ISCSI_FLAG)
#define NO_ISCSI_OOO(bp) ((bp)->flags & NO_ISCSI_OOO_FLAG)
@@ -1349,6 +1408,7 @@ struct bnx2x {
int mrrs;
struct delayed_work sp_task;
+ atomic_t interrupt_occurred;
struct delayed_work sp_rtnl_task;
struct delayed_work period_task;
@@ -1432,6 +1492,7 @@ struct bnx2x {
u8 igu_sb_cnt;
u8 min_msix_vec_cnt;
+ u32 igu_base_addr;
dma_addr_t def_status_blk_mapping;
struct bnx2x_slowpath *slowpath;
@@ -1580,6 +1641,9 @@ struct bnx2x {
char fw_ver[32];
const struct firmware *firmware;
+ struct bnx2x_vfdb *vfdb;
+#define IS_SRIOV(bp) ((bp)->vfdb)
+
/* DCB support on/off */
u16 dcb_state;
#define BNX2X_DCB_STATE_OFF 0
@@ -1599,6 +1663,10 @@ struct bnx2x {
int dcb_version;
/* CAM credit pools */
+
+ /* used only in sriov */
+ struct bnx2x_credit_pool_obj vlans_pool;
+
struct bnx2x_credit_pool_obj macs_pool;
/* RX_MODE object */
@@ -1636,6 +1704,9 @@ struct bnx2x {
/* priority to cos mapping */
u8 prio_to_cos[8];
+
+ int fp_array_size;
+ u32 dump_preset_idx;
};
/* Tx queues may be less or equal to Rx queues */
@@ -1813,12 +1884,16 @@ int bnx2x_del_all_macs(struct bnx2x *bp,
/* Init Function API */
void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p);
+void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
+ u8 vf_valid, int fw_sb_id, int igu_sb_id);
+u32 bnx2x_get_pretend_reg(struct bnx2x *bp);
int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
int bnx2x_set_mult_gpio(struct bnx2x *bp, u8 pins, u32 mode);
int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
void bnx2x_read_mf_cfg(struct bnx2x *bp);
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val);
/* dmae */
void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32);
@@ -1830,6 +1905,18 @@ u32 bnx2x_dmae_opcode_clr_src_reset(u32 opcode);
u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
bool with_comp, u8 comp_type);
+void bnx2x_prep_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
+ u8 src_type, u8 dst_type);
+int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae);
+void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl);
+
+/* FLR related routines */
+u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp);
+void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count);
+int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt);
+u8 bnx2x_is_pcie_pending(struct pci_dev *dev);
+int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
+ char *msg, u32 poll_cnt);
void bnx2x_calc_fc_adv(struct bnx2x *bp);
int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
@@ -1854,6 +1941,9 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
return val;
}
+void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
+ bool is_pf);
+
#define BNX2X_ILT_ZALLOC(x, y, size) \
do { \
x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
@@ -1990,10 +2080,8 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define BNX2X_LOOPBACK_FAILED (BNX2X_MAC_LOOPBACK_FAILED | \
BNX2X_PHY_LOOPBACK_FAILED)
-
#define STROM_ASSERT_ARRAY_SIZE 50
-
/* must be used on a CID before placing it on a HW ring */
#define HW_CID(bp, x) ((BP_PORT(bp) << 23) | \
(BP_VN(bp) << BNX2X_SWCID_SHIFT) | \
@@ -2024,7 +2112,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
/* Memory of fairness algorithm . 2 cycles */
#define FAIR_MEM 2
-
#define ATTN_NIG_FOR_FUNC (1L << 8)
#define ATTN_SW_TIMER_4_FUNC (1L << 9)
#define GPIO_2_FUNC (1L << 10)
@@ -2067,6 +2154,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
(AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT | \
AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT | \
AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT | \
+ AEU_INPUTS_ATTN_BITS_BRB_HW_INTERRUPT | \
AEU_INPUTS_ATTN_BITS_PBCLIENT_HW_INTERRUPT)
#define HW_PRTY_ASSERT_SET_0 (AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR | \
AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR | \
@@ -2128,7 +2216,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define MULTI_MASK 0x7f
-
#define DEF_USB_FUNC_OFF offsetof(struct cstorm_def_status_block_u, func)
#define DEF_CSB_FUNC_OFF offsetof(struct cstorm_def_status_block_c, func)
#define DEF_XSB_FUNC_OFF offsetof(struct xstorm_def_status_block, func)
@@ -2156,18 +2243,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
(&bp->def_status_blk->sp_sb.\
index_values[HC_SP_INDEX_ETH_DEF_CONS])
-#define SET_FLAG(value, mask, flag) \
- do {\
- (value) &= ~(mask);\
- (value) |= ((flag) << (mask##_SHIFT));\
- } while (0)
-
-#define GET_FLAG(value, mask) \
- (((value) & (mask)) >> (mask##_SHIFT))
-
-#define GET_FIELD(value, fname) \
- (((value) & (fname##_MASK)) >> (fname##_SHIFT))
-
#define CAM_IS_INVALID(x) \
(GET_FLAG(x.flags, \
MAC_CONFIGURATION_ENTRY_ACTION_TYPE) == \
@@ -2178,7 +2253,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define MC_HASH_OFFSET(bp, i) (BAR_TSTRORM_INTMEM + \
TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(BP_FUNC(bp)) + i*4)
-
#ifndef PXP2_REG_PXP2_INT_STS
#define PXP2_REG_PXP2_INT_STS PXP2_REG_PXP2_INT_STS_0
#endif
@@ -2190,9 +2264,16 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define BNX2X_VPD_LEN 128
#define VENDOR_ID_LEN 4
+#define VF_ACQUIRE_THRESH 3
+#define VF_ACQUIRE_MAC_FILTERS 1
+#define VF_ACQUIRE_MC_FILTERS 10
+
+#define GOOD_ME_REG(me_reg) (((me_reg) & ME_REG_VF_VALID) && \
+ (!((me_reg) & ME_REG_VF_ERR)))
+int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code);
/* Congestion management fairness mode */
-#define CMNG_FNS_NONE 0
-#define CMNG_FNS_MINMAX 1
+#define CMNG_FNS_NONE 0
+#define CMNG_FNS_MINMAX 1
#define HC_SEG_ACCESS_DEF 0 /*Driver decision 0-3*/
#define HC_SEG_ACCESS_ATTN 4
@@ -2208,7 +2289,6 @@ static const u32 dmae_reg_go_c[] = {
void bnx2x_set_ethtool_ops(struct net_device *netdev);
void bnx2x_notify_link_changed(struct bnx2x *bp);
-
#define BNX2X_MF_SD_PROTOCOL(bp) \
((bp)->mf_config[BP_VN(bp)] & FUNC_MF_CFG_PROTOCOL_MASK)
@@ -2229,6 +2309,18 @@ void bnx2x_notify_link_changed(struct bnx2x *bp);
(BNX2X_IS_MF_SD_PROTOCOL_ISCSI(bp) || \
BNX2X_IS_MF_SD_PROTOCOL_FCOE(bp)))
+#define SET_FLAG(value, mask, flag) \
+ do {\
+ (value) &= ~(mask);\
+ (value) |= ((flag) << (mask##_SHIFT));\
+ } while (0)
+
+#define GET_FLAG(value, mask) \
+ (((value) & (mask)) >> (mask##_SHIFT))
+
+#define GET_FIELD(value, fname) \
+ (((value) & (fname##_MASK)) >> (fname##_SHIFT))
+
enum {
SWITCH_UPDATE,
AFEX_UPDATE,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index f771ddfba646..ecac04a3687c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -1,6 +1,6 @@
/* bnx2x_cmn.c: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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,6 +21,7 @@
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/ip.h>
+#include <net/tcp.h>
#include <net/ipv6.h>
#include <net/ip6_checksum.h>
#include <linux/prefetch.h>
@@ -28,8 +29,6 @@
#include "bnx2x_init.h"
#include "bnx2x_sp.h"
-
-
/**
* bnx2x_move_fp - move content of the fastpath structure.
*
@@ -87,6 +86,34 @@ static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
}
/**
+ * bnx2x_fill_fw_str - Fill buffer with FW version string.
+ *
+ * @bp: driver handle
+ * @buf: character buffer to fill with the fw name
+ * @buf_len: length of the above buffer
+ *
+ */
+void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len)
+{
+ if (IS_PF(bp)) {
+ u8 phy_fw_ver[PHY_FW_VER_LEN];
+
+ phy_fw_ver[0] = '\0';
+ bnx2x_get_ext_phy_fw_version(&bp->link_params,
+ phy_fw_ver, PHY_FW_VER_LEN);
+ strlcpy(buf, bp->fw_ver, buf_len);
+ snprintf(buf + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
+ "bc %d.%d.%d%s%s",
+ (bp->common.bc_ver & 0xff0000) >> 16,
+ (bp->common.bc_ver & 0xff00) >> 8,
+ (bp->common.bc_ver & 0xff),
+ ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
+ } else {
+ bnx2x_vf_fill_fw_str(bp, buf, buf_len);
+ }
+}
+
+/**
* bnx2x_shrink_eth_fp - guarantees fastpath structures stay intact
*
* @bp: driver handle
@@ -210,7 +237,7 @@ int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata)
txdata->txq_index, hw_cons, sw_cons, pkt_cons);
bd_cons = bnx2x_free_tx_pkt(bp, txdata, pkt_cons,
- &pkts_compl, &bytes_compl);
+ &pkts_compl, &bytes_compl);
sw_cons++;
}
@@ -316,14 +343,14 @@ static inline void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
fp->last_max_sge, fp->rx_sge_prod);
}
-/* Set Toeplitz hash value in the skb using the value from the
+/* Get Toeplitz hash value in the skb using the value from the
* CQE (calculated by HW).
*/
static u32 bnx2x_get_rxhash(const struct bnx2x *bp,
const struct eth_fast_path_rx_cqe *cqe,
bool *l4_rxhash)
{
- /* Set Toeplitz hash from CQE */
+ /* Get Toeplitz hash from CQE */
if ((bp->dev->features & NETIF_F_RXHASH) &&
(cqe->status_flags & ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG)) {
enum eth_rss_hash_type htype;
@@ -390,8 +417,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
tpa_info->rxhash = bnx2x_get_rxhash(bp, cqe, &tpa_info->l4_rxhash);
if (fp->mode == TPA_MODE_GRO) {
u16 gro_size = le16_to_cpu(cqe->pkt_len_or_gro_seg_len);
- tpa_info->full_page =
- SGE_PAGE_SIZE * PAGES_PER_SGE / gro_size * gro_size;
+ tpa_info->full_page = SGE_PAGES / gro_size * gro_size;
tpa_info->gro_size = gro_size;
}
@@ -412,31 +438,34 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
*/
#define TPA_TSTAMP_OPT_LEN 12
/**
- * bnx2x_set_lro_mss - calculate the approximate value of the MSS
+ * bnx2x_set_gro_params - compute GRO values
*
- * @bp: driver handle
+ * @skb: packet skb
* @parsing_flags: parsing flags from the START CQE
* @len_on_bd: total length of the first packet for the
* aggregation.
+ * @pkt_len: length of all segments
*
* Approximate value of the MSS for this aggregation calculated using
* the first packet of it.
+ * Compute number of aggregated segments, and gso_type.
*/
-static u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags,
- u16 len_on_bd)
+static void bnx2x_set_gro_params(struct sk_buff *skb, u16 parsing_flags,
+ u16 len_on_bd, unsigned int pkt_len)
{
- /*
- * TPA arrgregation won't have either IP options or TCP options
+ /* TPA aggregation won't have either IP options or TCP options
* other than timestamp or IPv6 extension headers.
*/
u16 hdrs_len = ETH_HLEN + sizeof(struct tcphdr);
if (GET_FLAG(parsing_flags, PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) ==
- PRS_FLAG_OVERETH_IPV6)
+ PRS_FLAG_OVERETH_IPV6) {
hdrs_len += sizeof(struct ipv6hdr);
- else /* IPv4 */
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+ } else {
hdrs_len += sizeof(struct iphdr);
-
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+ }
/* Check if there was a TCP timestamp, if there is it's will
* always be 12 bytes length: nop nop kind length echo val.
@@ -446,7 +475,13 @@ static u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags,
if (parsing_flags & PARSING_FLAGS_TIME_STAMP_EXIST_FLAG)
hdrs_len += TPA_TSTAMP_OPT_LEN;
- return len_on_bd - hdrs_len;
+ skb_shinfo(skb)->gso_size = len_on_bd - hdrs_len;
+
+ /* tcp_gro_complete() will copy NAPI_GRO_CB(skb)->count
+ * to skb_shinfo(skb)->gso_segs
+ */
+ NAPI_GRO_CB(skb)->count = DIV_ROUND_UP(pkt_len - hdrs_len,
+ skb_shinfo(skb)->gso_size);
}
static int bnx2x_alloc_rx_sge(struct bnx2x *bp,
@@ -463,7 +498,7 @@ static int bnx2x_alloc_rx_sge(struct bnx2x *bp,
}
mapping = dma_map_page(&bp->pdev->dev, page, 0,
- SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+ SGE_PAGES, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
__free_pages(page, PAGES_PER_SGE_SHIFT);
BNX2X_ERR("Can't map sge\n");
@@ -500,22 +535,12 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
}
/* This is needed in order to enable forwarding support */
- if (frag_size) {
- skb_shinfo(skb)->gso_size = bnx2x_set_lro_mss(bp,
- tpa_info->parsing_flags, len_on_bd);
-
- /* set for GRO */
- if (fp->mode == TPA_MODE_GRO)
- skb_shinfo(skb)->gso_type =
- (GET_FLAG(tpa_info->parsing_flags,
- PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) ==
- PRS_FLAG_OVERETH_IPV6) ?
- SKB_GSO_TCPV6 : SKB_GSO_TCPV4;
- }
-
+ if (frag_size)
+ bnx2x_set_gro_params(skb, tpa_info->parsing_flags, len_on_bd,
+ le16_to_cpu(cqe->pkt_len));
#ifdef BNX2X_STOP_ON_ERROR
- if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
+ if (pages > min_t(u32, 8, MAX_SKB_FRAGS) * SGE_PAGES) {
BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
pages, cqe_idx);
BNX2X_ERR("cqe->pkt_len = %d\n", cqe->pkt_len);
@@ -533,8 +558,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
if (fp->mode == TPA_MODE_GRO)
frag_len = min_t(u32, frag_size, (u32)full_page);
else /* LRO */
- frag_len = min_t(u32, frag_size,
- (u32)(SGE_PAGE_SIZE * PAGES_PER_SGE));
+ frag_len = min_t(u32, frag_size, (u32)SGE_PAGES);
rx_pg = &fp->rx_page_ring[sge_idx];
old_rx_pg = *rx_pg;
@@ -550,7 +574,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
/* Unmap the page as we r going to pass it to the stack */
dma_unmap_page(&bp->pdev->dev,
dma_unmap_addr(&old_rx_pg, mapping),
- SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+ SGE_PAGES, DMA_FROM_DEVICE);
/* Add one frag and update the appropriate fields in the skb */
if (fp->mode == TPA_MODE_LRO)
skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
@@ -568,7 +592,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
}
skb->data_len += frag_len;
- skb->truesize += SGE_PAGE_SIZE * PAGES_PER_SGE;
+ skb->truesize += SGE_PAGES;
skb->len += frag_len;
frag_size -= frag_len;
@@ -593,6 +617,54 @@ static void *bnx2x_frag_alloc(const struct bnx2x_fastpath *fp)
return kmalloc(fp->rx_buf_size + NET_SKB_PAD, GFP_ATOMIC);
}
+#ifdef CONFIG_INET
+static void bnx2x_gro_ip_csum(struct bnx2x *bp, struct sk_buff *skb)
+{
+ const struct iphdr *iph = ip_hdr(skb);
+ struct tcphdr *th;
+
+ skb_set_transport_header(skb, sizeof(struct iphdr));
+ th = tcp_hdr(skb);
+
+ th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb),
+ iph->saddr, iph->daddr, 0);
+}
+
+static void bnx2x_gro_ipv6_csum(struct bnx2x *bp, struct sk_buff *skb)
+{
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ struct tcphdr *th;
+
+ skb_set_transport_header(skb, sizeof(struct ipv6hdr));
+ th = tcp_hdr(skb);
+
+ th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
+ &iph->saddr, &iph->daddr, 0);
+}
+#endif
+
+static void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+ struct sk_buff *skb)
+{
+#ifdef CONFIG_INET
+ if (skb_shinfo(skb)->gso_size) {
+ skb_set_network_header(skb, 0);
+ switch (be16_to_cpu(skb->protocol)) {
+ case ETH_P_IP:
+ bnx2x_gro_ip_csum(bp, skb);
+ break;
+ case ETH_P_IPV6:
+ bnx2x_gro_ipv6_csum(bp, skb);
+ break;
+ default:
+ BNX2X_ERR("FW GRO supports only IPv4/IPv6, not 0x%04x\n",
+ be16_to_cpu(skb->protocol));
+ }
+ tcp_gro_complete(skb);
+ }
+#endif
+ napi_gro_receive(&fp->napi, skb);
+}
static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
struct bnx2x_agg_info *tpa_info,
@@ -647,7 +719,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
skb, cqe, cqe_idx)) {
if (tpa_info->parsing_flags & PARSING_FLAGS_VLAN)
__vlan_hwaccel_put_tag(skb, tpa_info->vlan_tag);
- napi_gro_receive(&fp->napi, skb);
+ bnx2x_gro_receive(bp, fp, skb);
} else {
DP(NETIF_MSG_RX_STATUS,
"Failed to allocate new pages - dropping packet!\n");
@@ -1089,7 +1161,7 @@ void __bnx2x_link_report(struct bnx2x *bp)
struct bnx2x_link_report_data cur_data;
/* reread mf_cfg */
- if (!CHIP_IS_E1(bp))
+ if (IS_PF(bp) && !CHIP_IS_E1(bp))
bnx2x_read_mf_cfg(bp);
/* Read the current link report info */
@@ -1431,10 +1503,14 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs)
if (nvecs == offset)
return;
- free_irq(bp->msix_table[offset].vector, bp->dev);
- DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
- bp->msix_table[offset].vector);
- offset++;
+
+ /* VFs don't have a default SB */
+ if (IS_PF(bp)) {
+ free_irq(bp->msix_table[offset].vector, bp->dev);
+ DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
+ bp->msix_table[offset].vector);
+ offset++;
+ }
if (CNIC_SUPPORT(bp)) {
if (nvecs == offset)
@@ -1455,21 +1531,30 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs)
void bnx2x_free_irq(struct bnx2x *bp)
{
if (bp->flags & USING_MSIX_FLAG &&
- !(bp->flags & USING_SINGLE_MSIX_FLAG))
- bnx2x_free_msix_irqs(bp, BNX2X_NUM_ETH_QUEUES(bp) +
- CNIC_SUPPORT(bp) + 1);
- else
+ !(bp->flags & USING_SINGLE_MSIX_FLAG)) {
+ int nvecs = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp);
+
+ /* vfs don't have a default status block */
+ if (IS_PF(bp))
+ nvecs++;
+
+ bnx2x_free_msix_irqs(bp, nvecs);
+ } else {
free_irq(bp->dev->irq, bp->dev);
+ }
}
int bnx2x_enable_msix(struct bnx2x *bp)
{
- int msix_vec = 0, i, rc, req_cnt;
+ int msix_vec = 0, i, rc;
- bp->msix_table[msix_vec].entry = msix_vec;
- BNX2X_DEV_INFO("msix_table[0].entry = %d (slowpath)\n",
- bp->msix_table[0].entry);
- msix_vec++;
+ /* VFs don't have a default status block */
+ if (IS_PF(bp)) {
+ bp->msix_table[msix_vec].entry = msix_vec;
+ BNX2X_DEV_INFO("msix_table[0].entry = %d (slowpath)\n",
+ bp->msix_table[0].entry);
+ msix_vec++;
+ }
/* Cnic requires an msix vector for itself */
if (CNIC_SUPPORT(bp)) {
@@ -1487,9 +1572,10 @@ int bnx2x_enable_msix(struct bnx2x *bp)
msix_vec++;
}
- req_cnt = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp) + 1;
+ DP(BNX2X_MSG_SP, "about to request enable msix with %d vectors\n",
+ msix_vec);
- rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], req_cnt);
+ rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], msix_vec);
/*
* reconfigure number of tx/rx queues according to available
@@ -1497,7 +1583,7 @@ int bnx2x_enable_msix(struct bnx2x *bp)
*/
if (rc >= BNX2X_MIN_MSIX_VEC_CNT(bp)) {
/* how less vectors we will have? */
- int diff = req_cnt - rc;
+ int diff = msix_vec - rc;
BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc);
@@ -1551,12 +1637,15 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
{
int i, rc, offset = 0;
- rc = request_irq(bp->msix_table[offset++].vector,
- bnx2x_msix_sp_int, 0,
- bp->dev->name, bp->dev);
- if (rc) {
- BNX2X_ERR("request sp irq failed\n");
- return -EBUSY;
+ /* no default status block for vf */
+ if (IS_PF(bp)) {
+ rc = request_irq(bp->msix_table[offset++].vector,
+ bnx2x_msix_sp_int, 0,
+ bp->dev->name, bp->dev);
+ if (rc) {
+ BNX2X_ERR("request sp irq failed\n");
+ return -EBUSY;
+ }
}
if (CNIC_SUPPORT(bp))
@@ -1580,12 +1669,20 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
}
i = BNX2X_NUM_ETH_QUEUES(bp);
- offset = 1 + CNIC_SUPPORT(bp);
- netdev_info(bp->dev, "using MSI-X IRQs: sp %d fp[%d] %d ... fp[%d] %d\n",
- bp->msix_table[0].vector,
- 0, bp->msix_table[offset].vector,
- i - 1, bp->msix_table[offset + i - 1].vector);
-
+ if (IS_PF(bp)) {
+ offset = 1 + CNIC_SUPPORT(bp);
+ netdev_info(bp->dev,
+ "using MSI-X IRQs: sp %d fp[%d] %d ... fp[%d] %d\n",
+ bp->msix_table[0].vector,
+ 0, bp->msix_table[offset].vector,
+ i - 1, bp->msix_table[offset + i - 1].vector);
+ } else {
+ offset = CNIC_SUPPORT(bp);
+ netdev_info(bp->dev,
+ "using MSI-X IRQs: fp[%d] %d ... fp[%d] %d\n",
+ 0, bp->msix_table[offset].vector,
+ i - 1, bp->msix_table[offset + i - 1].vector);
+ }
return 0;
}
@@ -1630,7 +1727,6 @@ static int bnx2x_setup_irqs(struct bnx2x *bp)
if (rc)
return rc;
} else {
- bnx2x_ack_int(bp);
rc = bnx2x_req_irq(bp);
if (rc) {
BNX2X_ERR("IRQ request failed rc %d, aborting\n", rc);
@@ -1728,7 +1824,6 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb)
return __skb_tx_hash(dev, skb, BNX2X_NUM_ETH_QUEUES(bp));
}
-
void bnx2x_set_num_queues(struct bnx2x *bp)
{
/* RSS queues */
@@ -1993,27 +2088,212 @@ static void bnx2x_squeeze_objects(struct bnx2x *bp)
} while (0)
#endif /*BNX2X_STOP_ON_ERROR*/
-bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err)
+static void bnx2x_free_fw_stats_mem(struct bnx2x *bp)
+{
+ BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
+ bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+ return;
+}
+
+static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
{
- /* build FW version dword */
- u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
- (BCM_5710_FW_MINOR_VERSION << 8) +
- (BCM_5710_FW_REVISION_VERSION << 16) +
- (BCM_5710_FW_ENGINEERING_VERSION << 24);
+ int num_groups, vf_headroom = 0;
+ int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;
+
+ /* number of queues for statistics is number of eth queues + FCoE */
+ u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;
+
+ /* Total number of FW statistics requests =
+ * 1 for port stats + 1 for PF stats + potential 2 for FCoE (fcoe proper
+ * and fcoe l2 queue) stats + num of queues (which includes another 1
+ * for fcoe l2 queue if applicable)
+ */
+ bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;
- /* read loaded FW from chip */
- u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
+ /* vf stats appear in the request list, but their data is allocated by
+ * the VFs themselves. We don't include them in the bp->fw_stats_num as
+ * it is used to determine where to place the vf stats queries in the
+ * request struct
+ */
+ if (IS_SRIOV(bp))
+ vf_headroom = bnx2x_vf_headroom(bp);
+
+ /* Request is built from stats_query_header and an array of
+ * stats_query_cmd_group each of which contains
+ * STATS_QUERY_CMD_COUNT rules. The real number or requests is
+ * configured in the stats_query_header.
+ */
+ num_groups =
+ (((bp->fw_stats_num + vf_headroom) / STATS_QUERY_CMD_COUNT) +
+ (((bp->fw_stats_num + vf_headroom) % STATS_QUERY_CMD_COUNT) ?
+ 1 : 0));
+
+ DP(BNX2X_MSG_SP, "stats fw_stats_num %d, vf headroom %d, num_groups %d\n",
+ bp->fw_stats_num, vf_headroom, num_groups);
+ bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
+ num_groups * sizeof(struct stats_query_cmd_group);
+
+ /* Data for statistics requests + stats_counter
+ * stats_counter holds per-STORM counters that are incremented
+ * when STORM has finished with the current request.
+ * memory for FCoE offloaded statistics are counted anyway,
+ * even if they will not be sent.
+ * VF stats are not accounted for here as the data of VF stats is stored
+ * in memory allocated by the VF, not here.
+ */
+ bp->fw_stats_data_sz = sizeof(struct per_port_stats) +
+ sizeof(struct per_pf_stats) +
+ sizeof(struct fcoe_statistics_params) +
+ sizeof(struct per_queue_stats) * num_queue_stats +
+ sizeof(struct stats_counter);
+
+ BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
+ bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+
+ /* Set shortcuts */
+ bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
+ bp->fw_stats_req_mapping = bp->fw_stats_mapping;
+ bp->fw_stats_data = (struct bnx2x_fw_stats_data *)
+ ((u8 *)bp->fw_stats + bp->fw_stats_req_sz);
+ bp->fw_stats_data_mapping = bp->fw_stats_mapping +
+ bp->fw_stats_req_sz;
+
+ DP(BNX2X_MSG_SP, "statistics request base address set to %x %x",
+ U64_HI(bp->fw_stats_req_mapping),
+ U64_LO(bp->fw_stats_req_mapping));
+ DP(BNX2X_MSG_SP, "statistics data base address set to %x %x",
+ U64_HI(bp->fw_stats_data_mapping),
+ U64_LO(bp->fw_stats_data_mapping));
+ return 0;
+
+alloc_mem_err:
+ bnx2x_free_fw_stats_mem(bp);
+ BNX2X_ERR("Can't allocate FW stats memory\n");
+ return -ENOMEM;
+}
- DP(NETIF_MSG_IFUP, "loaded fw %x, my fw %x\n", loaded_fw, my_fw);
+/* send load request to mcp and analyze response */
+static int bnx2x_nic_load_request(struct bnx2x *bp, u32 *load_code)
+{
+ /* init fw_seq */
+ bp->fw_seq =
+ (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
+ DRV_MSG_SEQ_NUMBER_MASK);
+ BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
+
+ /* Get current FW pulse sequence */
+ bp->fw_drv_pulse_wr_seq =
+ (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
+ DRV_PULSE_SEQ_MASK);
+ BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
+
+ /* load request */
+ (*load_code) = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
+ DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
+
+ /* if mcp fails to respond we must abort */
+ if (!(*load_code)) {
+ BNX2X_ERR("MCP response failure, aborting\n");
+ return -EBUSY;
+ }
+
+ /* If mcp refused (e.g. other port is in diagnostic mode) we
+ * must abort
+ */
+ if ((*load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED) {
+ BNX2X_ERR("MCP refused load request, aborting\n");
+ return -EBUSY;
+ }
+ return 0;
+}
- if (loaded_fw != my_fw) {
- if (is_err)
- BNX2X_ERR("bnx2x with FW %x was already loaded, which mismatches my %x FW. aborting\n",
+/* check whether another PF has already loaded FW to chip. In
+ * virtualized environments a pf from another VM may have already
+ * initialized the device including loading FW
+ */
+int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code)
+{
+ /* is another pf loaded on this engine? */
+ if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
+ load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
+ /* build my FW version dword */
+ u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
+ (BCM_5710_FW_MINOR_VERSION << 8) +
+ (BCM_5710_FW_REVISION_VERSION << 16) +
+ (BCM_5710_FW_ENGINEERING_VERSION << 24);
+
+ /* read loaded FW from chip */
+ u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
+
+ DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x\n",
+ loaded_fw, my_fw);
+
+ /* abort nic load if version mismatch */
+ if (my_fw != loaded_fw) {
+ BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. aborting\n",
loaded_fw, my_fw);
- return false;
+ return -EBUSY;
+ }
+ }
+ return 0;
+}
+
+/* returns the "mcp load_code" according to global load_count array */
+static int bnx2x_nic_load_no_mcp(struct bnx2x *bp, int port)
+{
+ int path = BP_PATH(bp);
+
+ DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d] %d, %d, %d\n",
+ path, load_count[path][0], load_count[path][1],
+ load_count[path][2]);
+ load_count[path][0]++;
+ load_count[path][1 + port]++;
+ DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d] %d, %d, %d\n",
+ path, load_count[path][0], load_count[path][1],
+ load_count[path][2]);
+ if (load_count[path][0] == 1)
+ return FW_MSG_CODE_DRV_LOAD_COMMON;
+ else if (load_count[path][1 + port] == 1)
+ return FW_MSG_CODE_DRV_LOAD_PORT;
+ else
+ return FW_MSG_CODE_DRV_LOAD_FUNCTION;
+}
+
+/* mark PMF if applicable */
+static void bnx2x_nic_load_pmf(struct bnx2x *bp, u32 load_code)
+{
+ if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+ (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
+ (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
+ bp->port.pmf = 1;
+ /* We need the barrier to ensure the ordering between the
+ * writing to bp->port.pmf here and reading it from the
+ * bnx2x_periodic_task().
+ */
+ smp_mb();
+ } else {
+ bp->port.pmf = 0;
+ }
+
+ DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
+}
+
+static void bnx2x_nic_load_afex_dcc(struct bnx2x *bp, int load_code)
+{
+ if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
+ (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
+ (bp->common.shmem2_base)) {
+ if (SHMEM2_HAS(bp, dcc_support))
+ SHMEM2_WR(bp, dcc_support,
+ (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
+ SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
+ if (SHMEM2_HAS(bp, afex_driver_support))
+ SHMEM2_WR(bp, afex_driver_support,
+ SHMEM_AFEX_SUPPORTED_VERSION_ONE);
}
- return true;
+ /* Set AFEX default VLAN tag to an invalid value */
+ bp->afex_def_vlan_tag = -1;
}
/**
@@ -2028,49 +2308,15 @@ bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err)
static void bnx2x_bz_fp(struct bnx2x *bp, int index)
{
struct bnx2x_fastpath *fp = &bp->fp[index];
- struct bnx2x_fp_stats *fp_stats = &bp->fp_stats[index];
int cos;
struct napi_struct orig_napi = fp->napi;
struct bnx2x_agg_info *orig_tpa_info = fp->tpa_info;
/* bzero bnx2x_fastpath contents */
- if (bp->stats_init) {
- memset(fp->tpa_info, 0, sizeof(*fp->tpa_info));
- memset(fp, 0, sizeof(*fp));
- } else {
- /* Keep Queue statistics */
- struct bnx2x_eth_q_stats *tmp_eth_q_stats;
- struct bnx2x_eth_q_stats_old *tmp_eth_q_stats_old;
-
- tmp_eth_q_stats = kzalloc(sizeof(struct bnx2x_eth_q_stats),
- GFP_KERNEL);
- if (tmp_eth_q_stats)
- memcpy(tmp_eth_q_stats, &fp_stats->eth_q_stats,
- sizeof(struct bnx2x_eth_q_stats));
-
- tmp_eth_q_stats_old =
- kzalloc(sizeof(struct bnx2x_eth_q_stats_old),
- GFP_KERNEL);
- if (tmp_eth_q_stats_old)
- memcpy(tmp_eth_q_stats_old, &fp_stats->eth_q_stats_old,
- sizeof(struct bnx2x_eth_q_stats_old));
-
- memset(fp->tpa_info, 0, sizeof(*fp->tpa_info));
- memset(fp, 0, sizeof(*fp));
-
- if (tmp_eth_q_stats) {
- memcpy(&fp_stats->eth_q_stats, tmp_eth_q_stats,
- sizeof(struct bnx2x_eth_q_stats));
- kfree(tmp_eth_q_stats);
- }
-
- if (tmp_eth_q_stats_old) {
- memcpy(&fp_stats->eth_q_stats_old, tmp_eth_q_stats_old,
- sizeof(struct bnx2x_eth_q_stats_old));
- kfree(tmp_eth_q_stats_old);
- }
-
- }
+ if (fp->tpa_info)
+ memset(fp->tpa_info, 0, ETH_MAX_AGGREGATION_QUEUES_E1H_E2 *
+ sizeof(struct bnx2x_agg_info));
+ memset(fp, 0, sizeof(*fp));
/* Restore the NAPI object as it has been already initialized */
fp->napi = orig_napi;
@@ -2116,10 +2362,12 @@ int bnx2x_load_cnic(struct bnx2x *bp)
mutex_init(&bp->cnic_mutex);
- rc = bnx2x_alloc_mem_cnic(bp);
- if (rc) {
- BNX2X_ERR("Unable to allocate bp memory for cnic\n");
- LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
+ if (IS_PF(bp)) {
+ rc = bnx2x_alloc_mem_cnic(bp);
+ if (rc) {
+ BNX2X_ERR("Unable to allocate bp memory for cnic\n");
+ LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
+ }
}
rc = bnx2x_alloc_fp_mem_cnic(bp);
@@ -2146,14 +2394,17 @@ int bnx2x_load_cnic(struct bnx2x *bp)
bnx2x_nic_init_cnic(bp);
- /* Enable Timer scan */
- REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
+ if (IS_PF(bp)) {
+ /* Enable Timer scan */
+ REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
- for_each_cnic_queue(bp, i) {
- rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
- if (rc) {
- BNX2X_ERR("Queue setup failed\n");
- LOAD_ERROR_EXIT(bp, load_error_cnic2);
+ /* setup cnic queues */
+ for_each_cnic_queue(bp, i) {
+ rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
+ if (rc) {
+ BNX2X_ERR("Queue setup failed\n");
+ LOAD_ERROR_EXIT(bp, load_error_cnic2);
+ }
}
}
@@ -2194,13 +2445,11 @@ load_error_cnic0:
#endif /* ! BNX2X_STOP_ON_ERROR */
}
-
/* must be called with rtnl_lock */
int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
{
int port = BP_PORT(bp);
- u32 load_code;
- int i, rc;
+ int i, rc = 0, load_code = 0;
DP(NETIF_MSG_IFUP, "Starting NIC load\n");
DP(NETIF_MSG_IFUP,
@@ -2215,15 +2464,13 @@ 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);
+ if (IS_PF(bp))
+ /* must be called before memory allocation and HW init */
+ bnx2x_ilt_set_info(bp);
/*
* Zero fastpath structures preserving invariants like napi, which are
@@ -2242,8 +2489,33 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
/* Set the receive queues buffer size */
bnx2x_set_rx_buf_size(bp);
- if (bnx2x_alloc_mem(bp))
- return -ENOMEM;
+ if (IS_PF(bp)) {
+ rc = bnx2x_alloc_mem(bp);
+ if (rc) {
+ BNX2X_ERR("Unable to allocate bp memory\n");
+ return rc;
+ }
+ }
+
+ /* Allocated memory for FW statistics */
+ if (bnx2x_alloc_fw_stats_mem(bp))
+ LOAD_ERROR_EXIT(bp, load_error0);
+
+ /* need to be done after alloc mem, since it's self adjusting to amount
+ * of memory available for RSS queues
+ */
+ rc = bnx2x_alloc_fp_mem(bp);
+ if (rc) {
+ BNX2X_ERR("Unable to allocate memory for fps\n");
+ LOAD_ERROR_EXIT(bp, load_error0);
+ }
+
+ /* request pf to initialize status blocks */
+ if (IS_VF(bp)) {
+ rc = bnx2x_vfpf_init(bp);
+ if (rc)
+ LOAD_ERROR_EXIT(bp, load_error0);
+ }
/* As long as bnx2x_alloc_mem() may possibly update
* bp->num_queues, bnx2x_set_real_num_queues() should always
@@ -2266,98 +2538,48 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
DP(NETIF_MSG_IFUP, "napi added\n");
bnx2x_napi_enable(bp);
- /* set pf load just before approaching the MCP */
- bnx2x_set_pf_load(bp);
-
- /* Send LOAD_REQUEST command to MCP
- * Returns the type of LOAD command:
- * if it is the first port to be initialized
- * common blocks should be initialized, otherwise - not
- */
- if (!BP_NOMCP(bp)) {
- /* init fw_seq */
- bp->fw_seq =
- (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
- DRV_MSG_SEQ_NUMBER_MASK);
- BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
-
- /* Get current FW pulse sequence */
- bp->fw_drv_pulse_wr_seq =
- (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
- DRV_PULSE_SEQ_MASK);
- BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
-
- load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
- DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
- if (!load_code) {
- BNX2X_ERR("MCP response failure, aborting\n");
- rc = -EBUSY;
- LOAD_ERROR_EXIT(bp, load_error1);
- }
- if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
- BNX2X_ERR("Driver load refused\n");
- rc = -EBUSY; /* other port in diagnostic mode */
- LOAD_ERROR_EXIT(bp, load_error1);
- }
- if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
- load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
- /* abort nic load if version mismatch */
- if (!bnx2x_test_firmware_version(bp, true)) {
- rc = -EBUSY;
+ if (IS_PF(bp)) {
+ /* set pf load just before approaching the MCP */
+ bnx2x_set_pf_load(bp);
+
+ /* if mcp exists send load request and analyze response */
+ if (!BP_NOMCP(bp)) {
+ /* attempt to load pf */
+ rc = bnx2x_nic_load_request(bp, &load_code);
+ if (rc)
+ LOAD_ERROR_EXIT(bp, load_error1);
+
+ /* what did mcp say? */
+ rc = bnx2x_nic_load_analyze_req(bp, load_code);
+ if (rc) {
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
LOAD_ERROR_EXIT(bp, load_error2);
}
+ } else {
+ load_code = bnx2x_nic_load_no_mcp(bp, port);
}
- } else {
- int path = BP_PATH(bp);
-
- DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d] %d, %d, %d\n",
- path, load_count[path][0], load_count[path][1],
- load_count[path][2]);
- load_count[path][0]++;
- load_count[path][1 + port]++;
- DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d] %d, %d, %d\n",
- path, load_count[path][0], load_count[path][1],
- load_count[path][2]);
- if (load_count[path][0] == 1)
- load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
- else if (load_count[path][1 + port] == 1)
- load_code = FW_MSG_CODE_DRV_LOAD_PORT;
- else
- load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
- }
-
- if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
- (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
- (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
- bp->port.pmf = 1;
- /*
- * We need the barrier to ensure the ordering between the
- * writing to bp->port.pmf here and reading it from the
- * bnx2x_periodic_task().
- */
- smp_mb();
- } else
- bp->port.pmf = 0;
-
- DP(NETIF_MSG_IFUP, "pmf %d\n", bp->port.pmf);
+ /* mark pmf if applicable */
+ bnx2x_nic_load_pmf(bp, load_code);
- /* Init Function state controlling object */
- bnx2x__init_func_obj(bp);
+ /* Init Function state controlling object */
+ bnx2x__init_func_obj(bp);
- /* Initialize HW */
- rc = bnx2x_init_hw(bp, load_code);
- if (rc) {
- BNX2X_ERR("HW init failed, aborting\n");
- bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
- LOAD_ERROR_EXIT(bp, load_error2);
+ /* Initialize HW */
+ rc = bnx2x_init_hw(bp, load_code);
+ if (rc) {
+ BNX2X_ERR("HW init failed, aborting\n");
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
+ LOAD_ERROR_EXIT(bp, load_error2);
+ }
}
/* Connect to IRQs */
rc = bnx2x_setup_irqs(bp);
if (rc) {
- BNX2X_ERR("IRQs setup failed\n");
- bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
+ BNX2X_ERR("setup irqs failed\n");
+ if (IS_PF(bp))
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
LOAD_ERROR_EXIT(bp, load_error2);
}
@@ -2365,78 +2587,89 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
bnx2x_nic_init(bp, load_code);
/* Init per-function objects */
- bnx2x_init_bp_objs(bp);
-
- if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
- (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
- (bp->common.shmem2_base)) {
- if (SHMEM2_HAS(bp, dcc_support))
- SHMEM2_WR(bp, dcc_support,
- (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
- SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
- if (SHMEM2_HAS(bp, afex_driver_support))
- SHMEM2_WR(bp, afex_driver_support,
- SHMEM_AFEX_SUPPORTED_VERSION_ONE);
- }
+ if (IS_PF(bp)) {
+ bnx2x_init_bp_objs(bp);
+ bnx2x_iov_nic_init(bp);
+
+ /* Set AFEX default VLAN tag to an invalid value */
+ bp->afex_def_vlan_tag = -1;
+ bnx2x_nic_load_afex_dcc(bp, load_code);
+ bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
+ rc = bnx2x_func_start(bp);
+ if (rc) {
+ BNX2X_ERR("Function start failed!\n");
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
- /* Set AFEX default VLAN tag to an invalid value */
- bp->afex_def_vlan_tag = -1;
+ LOAD_ERROR_EXIT(bp, load_error3);
+ }
- bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
- rc = bnx2x_func_start(bp);
- if (rc) {
- BNX2X_ERR("Function start failed!\n");
- bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
- LOAD_ERROR_EXIT(bp, load_error3);
- }
+ /* Send LOAD_DONE command to MCP */
+ if (!BP_NOMCP(bp)) {
+ load_code = bnx2x_fw_command(bp,
+ DRV_MSG_CODE_LOAD_DONE, 0);
+ if (!load_code) {
+ BNX2X_ERR("MCP response failure, aborting\n");
+ rc = -EBUSY;
+ LOAD_ERROR_EXIT(bp, load_error3);
+ }
+ }
- /* Send LOAD_DONE command to MCP */
- if (!BP_NOMCP(bp)) {
- load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
- if (!load_code) {
- BNX2X_ERR("MCP response failure, aborting\n");
- rc = -EBUSY;
+ /* setup the leading queue */
+ rc = bnx2x_setup_leading(bp);
+ if (rc) {
+ BNX2X_ERR("Setup leading failed!\n");
LOAD_ERROR_EXIT(bp, load_error3);
}
- }
- rc = bnx2x_setup_leading(bp);
- if (rc) {
- BNX2X_ERR("Setup leading failed!\n");
- LOAD_ERROR_EXIT(bp, load_error3);
- }
+ /* set up the rest of the queues */
+ for_each_nondefault_eth_queue(bp, i) {
+ rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
+ if (rc) {
+ BNX2X_ERR("Queue setup failed\n");
+ LOAD_ERROR_EXIT(bp, load_error3);
+ }
+ }
- for_each_nondefault_eth_queue(bp, i) {
- rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
+ /* setup rss */
+ rc = bnx2x_init_rss_pf(bp);
if (rc) {
- BNX2X_ERR("Queue setup failed\n");
+ BNX2X_ERR("PF RSS init failed\n");
LOAD_ERROR_EXIT(bp, load_error3);
}
- }
- rc = bnx2x_init_rss_pf(bp);
- if (rc) {
- BNX2X_ERR("PF RSS init failed\n");
- LOAD_ERROR_EXIT(bp, load_error3);
+ } else { /* vf */
+ for_each_eth_queue(bp, i) {
+ rc = bnx2x_vfpf_setup_q(bp, i);
+ if (rc) {
+ BNX2X_ERR("Queue setup failed\n");
+ LOAD_ERROR_EXIT(bp, load_error3);
+ }
+ }
}
/* Now when Clients are configured we are ready to work */
bp->state = BNX2X_STATE_OPEN;
/* Configure a ucast MAC */
- rc = bnx2x_set_eth_mac(bp, true);
+ if (IS_PF(bp))
+ rc = bnx2x_set_eth_mac(bp, true);
+ else /* vf */
+ rc = bnx2x_vfpf_set_mac(bp);
if (rc) {
BNX2X_ERR("Setting Ethernet MAC failed\n");
LOAD_ERROR_EXIT(bp, load_error3);
}
- if (bp->pending_max) {
+ if (IS_PF(bp) && bp->pending_max) {
bnx2x_update_max_mf_config(bp, bp->pending_max);
bp->pending_max = 0;
}
- if (bp->port.pmf)
- bnx2x_initial_phy_init(bp, load_mode);
+ if (bp->port.pmf) {
+ rc = bnx2x_initial_phy_init(bp, load_mode);
+ if (rc)
+ LOAD_ERROR_EXIT(bp, load_error3);
+ }
bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_BOOT_FROM_SAN;
/* Start fast path */
@@ -2478,8 +2711,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
if (CNIC_ENABLED(bp))
bnx2x_load_cnic(bp);
- /* mark driver is loaded in shmem2 */
- if (SHMEM2_HAS(bp, drv_capabilities_flag)) {
+ if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
+ /* mark driver is loaded in shmem2 */
u32 val;
val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
@@ -2488,7 +2721,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
/* Wait for all pending SP commands to complete */
- if (!bnx2x_wait_sp_comp(bp, ~0x0UL)) {
+ if (IS_PF(bp) && !bnx2x_wait_sp_comp(bp, ~0x0UL)) {
BNX2X_ERR("Timeout waiting for SP elements to complete\n");
bnx2x_nic_unload(bp, UNLOAD_CLOSE, false);
return -EBUSY;
@@ -2504,10 +2737,12 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
#ifndef BNX2X_STOP_ON_ERROR
load_error3:
- bnx2x_int_disable_sync(bp, 1);
+ if (IS_PF(bp)) {
+ bnx2x_int_disable_sync(bp, 1);
- /* Clean queueable objects */
- bnx2x_squeeze_objects(bp);
+ /* Clean queueable objects */
+ bnx2x_squeeze_objects(bp);
+ }
/* Free SKBs, SGEs, TPA pool and driver internals */
bnx2x_free_skbs(bp);
@@ -2517,7 +2752,7 @@ load_error3:
/* Release IRQs */
bnx2x_free_irq(bp);
load_error2:
- if (!BP_NOMCP(bp)) {
+ if (IS_PF(bp) && !BP_NOMCP(bp)) {
bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0);
bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
}
@@ -2525,15 +2760,35 @@ load_error2:
bp->port.pmf = 0;
load_error1:
bnx2x_napi_disable(bp);
+
/* clear pf_load status, as it was already set */
- bnx2x_clear_pf_load(bp);
+ if (IS_PF(bp))
+ bnx2x_clear_pf_load(bp);
load_error0:
+ bnx2x_free_fp_mem(bp);
+ bnx2x_free_fw_stats_mem(bp);
bnx2x_free_mem(bp);
return rc;
#endif /* ! BNX2X_STOP_ON_ERROR */
}
+static int bnx2x_drain_tx_queues(struct bnx2x *bp)
+{
+ u8 rc = 0, cos, i;
+
+ /* Wait until tx fastpath tasks complete */
+ for_each_tx_queue(bp, i) {
+ struct bnx2x_fastpath *fp = &bp->fp[i];
+
+ for_each_cos_in_tx_queue(fp, cos)
+ rc = bnx2x_clean_tx_queue(bp, fp->txdata_ptr[cos]);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
/* must be called with rtnl_lock */
int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
{
@@ -2543,15 +2798,16 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
DP(NETIF_MSG_IFUP, "Starting NIC unload\n");
/* mark driver is unloaded in shmem2 */
- if (SHMEM2_HAS(bp, drv_capabilities_flag)) {
+ if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
u32 val;
val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
val & ~DRV_FLAGS_CAPABILITIES_LOADED_L2);
}
- if ((bp->state == BNX2X_STATE_CLOSED) ||
- (bp->state == BNX2X_STATE_ERROR)) {
+ if (IS_PF(bp) && bp->recovery_state != BNX2X_RECOVERY_DONE &&
+ (bp->state == BNX2X_STATE_CLOSED ||
+ bp->state == BNX2X_STATE_ERROR)) {
/* We can get here if the driver has been unloaded
* during parity error recovery and is either waiting for a
* leader to complete or for other functions to unload and
@@ -2569,8 +2825,16 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
return -EINVAL;
}
- /*
- * It's important to set the bp->state to the value different from
+ /* Nothing to do during unload if previous bnx2x_nic_load()
+ * have not completed succesfully - all resourses are released.
+ *
+ * we can get here only after unsuccessful ndo_* callback, during which
+ * dev->IFF_UP flag is still on.
+ */
+ if (bp->state == BNX2X_STATE_CLOSED || bp->state == BNX2X_STATE_ERROR)
+ return 0;
+
+ /* It's important to set the bp->state to the value different from
* BNX2X_STATE_OPEN and only then stop the Tx. Otherwise bnx2x_tx_int()
* may restart the Tx from the NAPI context (see bnx2x_tx_int()).
*/
@@ -2588,16 +2852,24 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
del_timer_sync(&bp->timer);
- /* Set ALWAYS_ALIVE bit in shmem */
- bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
-
- bnx2x_drv_pulse(bp);
+ if (IS_PF(bp)) {
+ /* Set ALWAYS_ALIVE bit in shmem */
+ bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
+ bnx2x_drv_pulse(bp);
+ bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+ bnx2x_save_statistics(bp);
+ }
- bnx2x_stats_handle(bp, STATS_EVENT_STOP);
- bnx2x_save_statistics(bp);
+ /* wait till consumers catch up with producers in all queues */
+ bnx2x_drain_tx_queues(bp);
- /* Cleanup the chip if needed */
- if (unload_mode != UNLOAD_RECOVERY)
+ /* if VF indicate to PF this function is going down (PF will delete sp
+ * elements and clear initializations
+ */
+ if (IS_VF(bp))
+ bnx2x_vfpf_close_vf(bp);
+ else if (unload_mode != UNLOAD_RECOVERY)
+ /* if this is a normal/close unload need to clean up chip*/
bnx2x_chip_cleanup(bp, unload_mode, keep_link);
else {
/* Send the UNLOAD_REQUEST to the MCP */
@@ -2630,7 +2902,8 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
* At this stage no more interrupts will arrive so we may safly clean
* the queueable objects here in case they failed to get cleaned so far.
*/
- bnx2x_squeeze_objects(bp);
+ if (IS_PF(bp))
+ bnx2x_squeeze_objects(bp);
/* There should be no more pending SP commands at this stage */
bp->sp_state = 0;
@@ -2644,19 +2917,22 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
for_each_rx_queue(bp, i)
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
- if (CNIC_LOADED(bp)) {
+ bnx2x_free_fp_mem(bp);
+ if (CNIC_LOADED(bp))
bnx2x_free_fp_mem_cnic(bp);
- bnx2x_free_mem_cnic(bp);
- }
- bnx2x_free_mem(bp);
+ if (IS_PF(bp)) {
+ bnx2x_free_mem(bp);
+ if (CNIC_LOADED(bp))
+ bnx2x_free_mem_cnic(bp);
+ }
bp->state = BNX2X_STATE_CLOSED;
bp->cnic_loaded = false;
/* Check if there are pending parity attentions. If there are - set
* RECOVERY_IN_PROGRESS.
*/
- if (bnx2x_chk_parity_attn(bp, &global, false)) {
+ if (IS_PF(bp) && bnx2x_chk_parity_attn(bp, &global, false)) {
bnx2x_set_reset_in_progress(bp);
/* Set RESET_IS_GLOBAL if needed */
@@ -2668,7 +2944,9 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
/* The last driver must disable a "close the gate" if there is no
* parity attention or "process kill" pending.
*/
- if (!bnx2x_clear_pf_load(bp) && bnx2x_reset_is_done(bp, BP_PATH(bp)))
+ if (IS_PF(bp) &&
+ !bnx2x_clear_pf_load(bp) &&
+ bnx2x_reset_is_done(bp, BP_PATH(bp)))
bnx2x_disable_close_the_gate(bp);
DP(NETIF_MSG_IFUP, "Ending NIC unload\n");
@@ -2752,7 +3030,6 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
if (bnx2x_tx_queue_has_work(fp->txdata_ptr[cos]))
bnx2x_tx_int(bp, fp->txdata_ptr[cos]);
-
if (bnx2x_has_rx_work(fp)) {
work_done += bnx2x_rx_int(fp, budget - work_done);
@@ -2851,17 +3128,21 @@ static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
return bd_prod;
}
-static inline u16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
+#define bswab32(b32) ((__force __le32) swab32((__force __u32) (b32)))
+#define bswab16(b16) ((__force __le16) swab16((__force __u16) (b16)))
+static inline __le16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
{
+ __sum16 tsum = (__force __sum16) csum;
+
if (fix > 0)
- csum = (u16) ~csum_fold(csum_sub(csum,
- csum_partial(t_header - fix, fix, 0)));
+ tsum = ~csum_fold(csum_sub((__force __wsum) csum,
+ csum_partial(t_header - fix, fix, 0)));
else if (fix < 0)
- csum = (u16) ~csum_fold(csum_add(csum,
- csum_partial(t_header, -fix, 0)));
+ tsum = ~csum_fold(csum_add((__force __wsum) csum,
+ csum_partial(t_header, -fix, 0)));
- return swab16(csum);
+ return bswab16(csum);
}
static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
@@ -2995,23 +3276,24 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
u32 xmit_type)
{
pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
- pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
+ pbd->tcp_send_seq = bswab32(tcp_hdr(skb)->seq);
pbd->tcp_flags = pbd_tcp_flags(skb);
if (xmit_type & XMIT_GSO_V4) {
- pbd->ip_id = swab16(ip_hdr(skb)->id);
+ pbd->ip_id = bswab16(ip_hdr(skb)->id);
pbd->tcp_pseudo_csum =
- swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
- ip_hdr(skb)->daddr,
- 0, IPPROTO_TCP, 0));
+ bswab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+ ip_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0));
} else
pbd->tcp_pseudo_csum =
- swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
- &ipv6_hdr(skb)->daddr,
- 0, IPPROTO_TCP, 0));
+ bswab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0));
- pbd->global_data |= ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN;
+ pbd->global_data |=
+ cpu_to_le16(ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN);
}
/**
@@ -3025,12 +3307,12 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
* 57712 related
*/
static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
- u32 *parsing_data, u32 xmit_type)
+ u32 *parsing_data, u32 xmit_type)
{
*parsing_data |=
- ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) <<
- ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
- ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
+ ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) <<
+ ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
+ ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
if (xmit_type & XMIT_CSUM_TCP) {
*parsing_data |= ((tcp_hdrlen(skb) / 4) <<
@@ -3038,12 +3320,11 @@ static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
- } else
- /* We support checksum offload for TCP and UDP only.
- * No need to pass the UDP header length - it's a constant.
- */
- return skb_transport_header(skb) +
- sizeof(struct udphdr) - skb->data;
+ }
+ /* We support checksum offload for TCP and UDP only.
+ * No need to pass the UDP header length - it's a constant.
+ */
+ return skb_transport_header(skb) + sizeof(struct udphdr) - skb->data;
}
static inline void bnx2x_set_sbd_csum(struct bnx2x *bp, struct sk_buff *skb,
@@ -3078,8 +3359,9 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
/* for now NS flag is not used in Linux */
pbd->global_data =
- (hlen | ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
- ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT));
+ cpu_to_le16(hlen |
+ ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
+ ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT));
pbd->ip_hlen_w = (skb_transport_header(skb) -
skb_network_header(skb)) >> 1;
@@ -3096,7 +3378,7 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
hlen = hlen*2;
if (xmit_type & XMIT_CSUM_TCP) {
- pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check);
+ pbd->tcp_pseudo_csum = bswab16(tcp_hdr(skb)->check);
} else {
s8 fix = SKB_CS_OFF(skb); /* signed! */
@@ -3176,17 +3458,18 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
- bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++;
- netif_tx_stop_queue(txq);
+ bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++;
+ netif_tx_stop_queue(txq);
BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
return NETDEV_TX_BUSY;
}
DP(NETIF_MSG_TX_QUEUED,
- "queue[%d]: SKB: summed %x protocol %x protocol(%x,%x) gso type %x xmit_type %x\n",
+ "queue[%d]: SKB: summed %x protocol %x protocol(%x,%x) gso type %x xmit_type %x len %d\n",
txq_index, skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
- ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type);
+ ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type,
+ skb->len);
eth = (struct ethhdr *)skb->data;
@@ -3267,8 +3550,22 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
cpu_to_le16(vlan_tx_tag_get(skb));
tx_start_bd->bd_flags.as_bitfield |=
(X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT);
- } else
- tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+ } else {
+ /* when transmitting in a vf, start bd must hold the ethertype
+ * for fw to enforce it
+ */
+#ifndef BNX2X_STOP_ON_ERROR
+ if (IS_VF(bp)) {
+#endif
+ tx_start_bd->vlan_or_ethertype =
+ cpu_to_le16(ntohs(eth->h_proto));
+#ifndef BNX2X_STOP_ON_ERROR
+ } else {
+ /* used by FW for packet accounting */
+ tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+ }
+#endif
+ }
/* turn on parsing and get a BD */
bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
@@ -3284,9 +3581,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
hlen = bnx2x_set_pbd_csum_e2(bp, skb,
&pbd_e2_parsing_data,
xmit_type);
- if (IS_MF_SI(bp)) {
- /*
- * fill in the MAC addresses in the PBD - for local
+
+ if (IS_MF_SI(bp) || IS_VF(bp)) {
+ /* fill in the MAC addresses in the PBD - for local
* switching
*/
bnx2x_set_fw_mac_addr(&pbd_e2->src_mac_addr_hi,
@@ -3567,7 +3864,6 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p)
return rc;
}
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
if (netif_running(dev))
@@ -3763,6 +4059,8 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
} else /* if rx_ring_size specified - use it */
rx_ring_size = bp->rx_ring_size;
+ DP(BNX2X_MSG_SP, "calculated rx_ring_size %d\n", rx_ring_size);
+
/* Common */
sb = &bnx2x_fp(bp, index, status_blk);
@@ -3909,7 +4207,10 @@ int bnx2x_alloc_fp_mem(struct bnx2x *bp)
void bnx2x_free_mem_bp(struct bnx2x *bp)
{
- kfree(bp->fp->tpa_info);
+ int i;
+
+ for (i = 0; i < bp->fp_array_size; i++)
+ kfree(bp->fp[i].tpa_info);
kfree(bp->fp);
kfree(bp->sp_objs);
kfree(bp->fp_stats);
@@ -3929,18 +4230,22 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp)
/*
* The biggest MSI-X table we might need is as a maximum number of fast
- * path IGU SBs plus default SB (for PF).
+ * path IGU SBs plus default SB (for PF only).
*/
- msix_table_size = bp->igu_sb_cnt + 1;
+ msix_table_size = bp->igu_sb_cnt;
+ if (IS_PF(bp))
+ msix_table_size++;
+ BNX2X_DEV_INFO("msix_table_size %d\n", msix_table_size);
/* fp array: RSS plus CNIC related L2 queues */
fp_array_size = BNX2X_MAX_RSS_COUNT(bp) + CNIC_SUPPORT(bp);
- BNX2X_DEV_INFO("fp_array_size %d", fp_array_size);
+ bp->fp_array_size = fp_array_size;
+ BNX2X_DEV_INFO("fp_array_size %d\n", bp->fp_array_size);
- fp = kcalloc(fp_array_size, sizeof(*fp), GFP_KERNEL);
+ fp = kcalloc(bp->fp_array_size, sizeof(*fp), GFP_KERNEL);
if (!fp)
goto alloc_err;
- for (i = 0; i < fp_array_size; i++) {
+ for (i = 0; i < bp->fp_array_size; i++) {
fp[i].tpa_info =
kcalloc(ETH_MAX_AGGREGATION_QUEUES_E1H_E2,
sizeof(struct bnx2x_agg_info), GFP_KERNEL);
@@ -3951,13 +4256,13 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp)
bp->fp = fp;
/* allocate sp objs */
- bp->sp_objs = kcalloc(fp_array_size, sizeof(struct bnx2x_sp_objs),
+ bp->sp_objs = kcalloc(bp->fp_array_size, sizeof(struct bnx2x_sp_objs),
GFP_KERNEL);
if (!bp->sp_objs)
goto alloc_err;
/* allocate fp_stats */
- bp->fp_stats = kcalloc(fp_array_size, sizeof(struct bnx2x_fp_stats),
+ bp->fp_stats = kcalloc(bp->fp_array_size, sizeof(struct bnx2x_fp_stats),
GFP_KERNEL);
if (!bp->fp_stats)
goto alloc_err;
@@ -4036,7 +4341,7 @@ int bnx2x_get_link_cfg_idx(struct bnx2x *bp)
{
u32 sel_phy_idx = bnx2x_get_cur_phy_idx(bp);
/*
- * The selected actived PHY is always after swapping (in case PHY
+ * The selected activated PHY is always after swapping (in case PHY
* swapping is enabled). So when swapping is enabled, we need to reverse
* the configuration
*/
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 0991534f61da..aee7671ff4c1 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -1,6 +1,6 @@
/* bnx2x_cmn.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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
@@ -24,6 +24,7 @@
#include "bnx2x.h"
+#include "bnx2x_sriov.h"
/* This is used as a replacement for an MCP if it's not present */
extern int load_count[2][3]; /* per-path: 0-common, 1-port0, 2-port1 */
@@ -196,6 +197,7 @@ void bnx2x_igu_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 segment,
/* Disable transactions from chip to host */
void bnx2x_pf_disable(struct bnx2x *bp);
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val);
/**
* bnx2x__link_status_update - handles link status change.
@@ -401,7 +403,7 @@ void bnx2x_set_rx_mode(struct net_device *dev);
* If bp->state is OPEN, should be called with
* netif_addr_lock_bh().
*/
-void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
+int bnx2x_set_storm_rx_mode(struct bnx2x *bp);
/**
* bnx2x_set_q_rx_mode - configures rx_mode for a single queue.
@@ -413,11 +415,11 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
* @tx_accept_flags: tx accept configuration (tx switch)
* @ramrod_flags: ramrod configuration
*/
-void bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
- unsigned long rx_mode_flags,
- unsigned long rx_accept_flags,
- unsigned long tx_accept_flags,
- unsigned long ramrod_flags);
+int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
+ unsigned long rx_mode_flags,
+ unsigned long rx_accept_flags,
+ unsigned long tx_accept_flags,
+ unsigned long ramrod_flags);
/* Parity errors related */
void bnx2x_set_pf_load(struct bnx2x *bp);
@@ -477,8 +479,6 @@ int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
*/
void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value);
/* Error handling */
-void bnx2x_panic_dump(struct bnx2x *bp);
-
void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl);
/* validate currect fw is loaded */
@@ -496,9 +496,44 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev);
/* setup_tc callback */
int bnx2x_setup_tc(struct net_device *dev, u8 num_tc);
+int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac);
+
/* select_queue callback */
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb);
+static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp,
+ u16 bd_prod, u16 rx_comp_prod,
+ u16 rx_sge_prod)
+{
+ struct ustorm_eth_rx_producers rx_prods = {0};
+ u32 i;
+
+ /* Update producers */
+ rx_prods.bd_prod = bd_prod;
+ rx_prods.cqe_prod = rx_comp_prod;
+ rx_prods.sge_prod = rx_sge_prod;
+
+ /* Make sure that the BD and SGE data is updated before updating the
+ * producers since FW might read the BD/SGE right after the producer
+ * is updated.
+ * This is only applicable for weak-ordered memory model archs such
+ * as IA-64. The following barrier is also mandatory since FW will
+ * assumes BDs must have buffers.
+ */
+ wmb();
+
+ for (i = 0; i < sizeof(rx_prods)/4; i++)
+ REG_WR(bp, fp->ustorm_rx_prods_offset + i*4,
+ ((u32 *)&rx_prods)[i]);
+
+ mmiowb(); /* keep prod updates ordered */
+
+ DP(NETIF_MSG_RX_STATUS,
+ "queue[%d]: wrote bd_prod %u cqe_prod %u sge_prod %u\n",
+ fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
+}
+
/* reload helper */
int bnx2x_reload_if_running(struct net_device *dev);
@@ -507,9 +542,6 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p);
/* NAPI poll Rx part */
int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget);
-void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp,
- u16 bd_prod, u16 rx_comp_prod, u16 rx_sge_prod);
-
/* NAPI poll Tx part */
int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata);
@@ -612,38 +644,6 @@ static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
fp->fp_hc_idx = fp->sb_running_index[SM_RX_ID];
}
-static inline void bnx2x_update_rx_prod_gen(struct bnx2x *bp,
- struct bnx2x_fastpath *fp, u16 bd_prod,
- u16 rx_comp_prod, u16 rx_sge_prod, u32 start)
-{
- struct ustorm_eth_rx_producers rx_prods = {0};
- u32 i;
-
- /* Update producers */
- rx_prods.bd_prod = bd_prod;
- rx_prods.cqe_prod = rx_comp_prod;
- rx_prods.sge_prod = rx_sge_prod;
-
- /*
- * Make sure that the BD and SGE data is updated before updating the
- * producers since FW might read the BD/SGE right after the producer
- * is updated.
- * This is only applicable for weak-ordered memory model archs such
- * as IA-64. The following barrier is also mandatory since FW will
- * assumes BDs must have buffers.
- */
- wmb();
-
- for (i = 0; i < sizeof(rx_prods)/4; i++)
- REG_WR(bp, start + i*4, ((u32 *)&rx_prods)[i]);
-
- mmiowb(); /* keep prod updates ordered */
-
- DP(NETIF_MSG_RX_STATUS,
- "queue[%d]: wrote bd_prod %u cqe_prod %u sge_prod %u\n",
- fp->index, bd_prod, rx_comp_prod, rx_sge_prod);
-}
-
static inline void bnx2x_igu_ack_sb_gen(struct bnx2x *bp, u8 igu_sb_id,
u8 segment, u16 index, u8 op,
u8 update, u32 igu_addr)
@@ -819,7 +819,7 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
return;
dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
- SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
+ SGE_PAGES, DMA_FROM_DEVICE);
__free_pages(page, PAGES_PER_SGE_SHIFT);
sw_buf->page = NULL;
@@ -863,7 +863,7 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp)
netif_napi_del(&bnx2x_fp(bp, i, napi));
}
-void bnx2x_set_int_mode(struct bnx2x *bp);
+int bnx2x_set_int_mode(struct bnx2x *bp);
static inline void bnx2x_disable_msi(struct bnx2x *bp)
{
@@ -973,7 +973,6 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
return bnx2x_func_state_change(bp, &func_params);
}
-
/**
* bnx2x_set_fw_mac_addr - fill in a MAC address in FW format
*
@@ -982,8 +981,8 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
* @fw_lo: pointer to lower part
* @mac: pointer to MAC address
*/
-static inline void bnx2x_set_fw_mac_addr(u16 *fw_hi, u16 *fw_mid, u16 *fw_lo,
- u8 *mac)
+static inline void bnx2x_set_fw_mac_addr(__le16 *fw_hi, __le16 *fw_mid,
+ __le16 *fw_lo, u8 *mac)
{
((u8 *)fw_hi)[0] = mac[1];
((u8 *)fw_hi)[1] = mac[0];
@@ -1108,6 +1107,9 @@ static inline void bnx2x_init_bp_objs(struct bnx2x *bp)
bnx2x_init_mac_credit_pool(bp, &bp->macs_pool, BP_FUNC(bp),
bnx2x_get_path_func_num(bp));
+ bnx2x_init_vlan_credit_pool(bp, &bp->vlans_pool, BP_ABS_FUNC(bp)>>1,
+ bnx2x_get_path_func_num(bp));
+
/* RSS configuration object */
bnx2x_init_rss_config_obj(bp, &bp->rss_conf_obj, bp->fp->cl_id,
bp->fp->cid, BP_FUNC(bp), BP_FUNC(bp),
@@ -1125,15 +1127,7 @@ static inline u8 bnx2x_fp_qzone_id(struct bnx2x_fastpath *fp)
return fp->cl_id;
}
-static inline u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
-{
- struct bnx2x *bp = fp->bp;
-
- if (!CHIP_IS_E1x(bp))
- return USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
- else
- return USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
-}
+u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp);
static inline void bnx2x_init_txdata(struct bnx2x *bp,
struct bnx2x_fp_txdata *txdata, u32 cid,
@@ -1228,7 +1222,7 @@ static inline int bnx2x_clean_tx_queue(struct bnx2x *bp,
#endif
}
cnt--;
- usleep_range(1000, 1000);
+ usleep_range(1000, 2000);
}
return 0;
@@ -1263,7 +1257,7 @@ static inline bool bnx2x_wait_sp_comp(struct bnx2x *bp, unsigned long mask)
}
netif_addr_unlock_bh(bp->dev);
- usleep_range(1000, 1000);
+ usleep_range(1000, 2000);
}
smp_mb();
@@ -1393,4 +1387,13 @@ static inline bool bnx2x_is_valid_ether_addr(struct bnx2x *bp, u8 *addr)
return false;
}
+/**
+ * bnx2x_fill_fw_str - Fill buffer with FW version string
+ *
+ * @bp: driver handle
+ * @buf: character buffer to fill with the fw name
+ * @buf_len: length of the above buffer
+ *
+ */
+void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len);
#endif /* BNX2X_CMN_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index 10bc093d2ca4..568205436a15 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -1,6 +1,6 @@
/* bnx2x_dcb.c: Broadcom Everest network driver.
*
- * Copyright 2009-2012 Broadcom Corporation
+ * Copyright 2009-2013 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -416,6 +416,7 @@ static void bnx2x_pfc_set_pfc(struct bnx2x *bp)
int mfw_configured = SHMEM2_HAS(bp, drv_flags) &&
GET_FLAGS(SHMEM2_RD(bp, drv_flags),
1 << DRV_FLAGS_DCB_MFW_CONFIGURED);
+
if (bp->dcbx_port_params.pfc.enabled &&
(!(bp->dcbx_error & DCBX_REMOTE_MIB_ERROR) || mfw_configured))
/*
@@ -558,6 +559,7 @@ static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)
int mfw_configured = SHMEM2_HAS(bp, drv_flags) &&
GET_FLAGS(SHMEM2_RD(bp, drv_flags),
1 << DRV_FLAGS_DCB_MFW_CONFIGURED);
+
bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);
if (!bp->dcbx_port_params.ets.enabled ||
@@ -1904,11 +1906,13 @@ static u8 bnx2x_dcbnl_set_state(struct net_device *netdev, u8 state)
struct bnx2x *bp = netdev_priv(netdev);
DP(BNX2X_MSG_DCB, "state = %s\n", state ? "on" : "off");
+ /* Fail to set state to "enabled" if dcbx is disabled in nvram */
if (state && ((bp->dcbx_enabled == BNX2X_DCBX_ENABLED_OFF) ||
(bp->dcbx_enabled == BNX2X_DCBX_ENABLED_INVALID))) {
DP(BNX2X_MSG_DCB, "Can not set dcbx to enabled while it is disabled in nvm\n");
return 1;
}
+
bnx2x_dcbx_set_state(bp, (state ? true : false), bp->dcbx_enabled);
return 0;
}
@@ -2052,7 +2056,6 @@ static void bnx2x_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio,
if (!bnx2x_dcbnl_set_valid(bp) || prio >= MAX_PFC_PRIORITIES)
return;
-
if (setting) {
bp->dcbx_config_params.admin_pfc_bitmap |= (1 << prio);
bp->dcbx_config_params.admin_pfc_tx_enable = 1;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
index 06c7a0435948..d153f44cf8f9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
@@ -1,6 +1,6 @@
/* bnx2x_dcb.h: Broadcom Everest network driver.
*
- * Copyright 2009-2012 Broadcom Corporation
+ * Copyright 2009-2013 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
index b926f58e983b..bff5e33eaa14 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
@@ -1,6 +1,6 @@
/* bnx2x_dump.h: Broadcom Everest network driver.
*
- * Copyright (c) 2012 Broadcom Corporation
+ * Copyright (c) 2012-2013 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -22,120 +22,37 @@
#ifndef BNX2X_DUMP_H
#define BNX2X_DUMP_H
+/* WaitP Definitions */
+#define DRV_DUMP_XSTORM_WAITP_ADDRESS 0x2b8a80
+#define DRV_DUMP_TSTORM_WAITP_ADDRESS 0x1b8a80
+#define DRV_DUMP_USTORM_WAITP_ADDRESS 0x338a80
+#define DRV_DUMP_CSTORM_WAITP_ADDRESS 0x238a80
-/*definitions */
-#define XSTORM_WAITP_ADDR 0x2b8a80
-#define TSTORM_WAITP_ADDR 0x1b8a80
-#define USTORM_WAITP_ADDR 0x338a80
-#define CSTORM_WAITP_ADDR 0x238a80
-#define TSTORM_CAM_MODE 0x1B1440
+/* Possible Chips */
+#define DUMP_CHIP_E1 1
+#define DUMP_CHIP_E1H 2
+#define DUMP_CHIP_E2 4
+#define DUMP_CHIP_E3A0 8
+#define DUMP_CHIP_E3B0 16
+#define DUMP_PATH_0 512
+#define DUMP_PATH_1 1024
+#define NUM_PRESETS 13
+#define NUM_CHIPS 5
-#define MAX_TIMER_PENDING 200
-#define TIMER_SCAN_DONT_CARE 0xFF
-#define RI_E1 0x1
-#define RI_E1H 0x2
-#define RI_E2 0x4
-#define RI_E3 0x8
-#define RI_E3B0 0x10
-#define RI_ONLINE 0x100
-#define RI_OFFLINE 0x0
-#define RI_PATH0_DUMP 0x200
-#define RI_PATH1_DUMP 0x400
-
-#define RI_E1_ONLINE (RI_E1 | RI_ONLINE)
-#define RI_E1H_ONLINE (RI_E1H | RI_ONLINE)
-#define RI_E1E1H_ONLINE (RI_E1 | RI_E1H | RI_ONLINE)
-#define RI_E2_ONLINE (RI_E2 | RI_ONLINE)
-#define RI_E1E2_ONLINE (RI_E1 | RI_E2 | RI_ONLINE)
-#define RI_E1HE2_ONLINE (RI_E1H | RI_E2 | RI_ONLINE)
-#define RI_E1E1HE2_ONLINE (RI_E1 | RI_E1H | RI_E2 | RI_ONLINE)
-#define RI_E3_ONLINE (RI_E3 | RI_ONLINE)
-#define RI_E1E3_ONLINE (RI_E1 | RI_E3 | RI_ONLINE)
-#define RI_E1HE3_ONLINE (RI_E1H | RI_E3 | RI_ONLINE)
-#define RI_E1E1HE3_ONLINE (RI_E1 | RI_E1H | RI_E3 | RI_ONLINE)
-#define RI_E2E3_ONLINE (RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E1E2E3_ONLINE (RI_E1 | RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E1HE2E3_ONLINE (RI_E1H | RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E1E1HE2E3_ONLINE (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_ONLINE)
-#define RI_E3B0_ONLINE (RI_E3B0 | RI_ONLINE)
-#define RI_E1E3B0_ONLINE (RI_E1 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE3B0_ONLINE (RI_E1H | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE3B0_ONLINE (RI_E1 | RI_E1H | RI_E3B0 | RI_ONLINE)
-#define RI_E2E3B0_ONLINE (RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E2E3B0_ONLINE (RI_E1 | RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE2E3B0_ONLINE (RI_E1H | RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE2E3B0_ONLINE (RI_E1 | RI_E1H | RI_E2 | RI_E3B0 | RI_ONLINE)
-#define RI_E3E3B0_ONLINE (RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E3E3B0_ONLINE (RI_E1 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE3E3B0_ONLINE (RI_E1H | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE3E3B0_ONLINE (RI_E1 | RI_E1H | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E2E3E3B0_ONLINE (RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E2E3E3B0_ONLINE (RI_E1 | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1HE2E3E3B0_ONLINE (RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1E1HE2E3E3B0_ONLINE \
- (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE)
-#define RI_E1_OFFLINE (RI_E1 | RI_OFFLINE)
-#define RI_E1H_OFFLINE (RI_E1H | RI_OFFLINE)
-#define RI_E1E1H_OFFLINE (RI_E1 | RI_E1H | RI_OFFLINE)
-#define RI_E2_OFFLINE (RI_E2 | RI_OFFLINE)
-#define RI_E1E2_OFFLINE (RI_E1 | RI_E2 | RI_OFFLINE)
-#define RI_E1HE2_OFFLINE (RI_E1H | RI_E2 | RI_OFFLINE)
-#define RI_E1E1HE2_OFFLINE (RI_E1 | RI_E1H | RI_E2 | RI_OFFLINE)
-#define RI_E3_OFFLINE (RI_E3 | RI_OFFLINE)
-#define RI_E1E3_OFFLINE (RI_E1 | RI_E3 | RI_OFFLINE)
-#define RI_E1HE3_OFFLINE (RI_E1H | RI_E3 | RI_OFFLINE)
-#define RI_E1E1HE3_OFFLINE (RI_E1 | RI_E1H | RI_E3 | RI_OFFLINE)
-#define RI_E2E3_OFFLINE (RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E1E2E3_OFFLINE (RI_E1 | RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E1HE2E3_OFFLINE (RI_E1H | RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E1E1HE2E3_OFFLINE (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_OFFLINE)
-#define RI_E3B0_OFFLINE (RI_E3B0 | RI_OFFLINE)
-#define RI_E1E3B0_OFFLINE (RI_E1 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE3B0_OFFLINE (RI_E1H | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE3B0_OFFLINE (RI_E1 | RI_E1H | RI_E3B0 | RI_OFFLINE)
-#define RI_E2E3B0_OFFLINE (RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E2E3B0_OFFLINE (RI_E1 | RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE2E3B0_OFFLINE (RI_E1H | RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE2E3B0_OFFLINE (RI_E1 | RI_E1H | RI_E2 | RI_E3B0 | RI_OFFLINE)
-#define RI_E3E3B0_OFFLINE (RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E3E3B0_OFFLINE (RI_E1 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE3E3B0_OFFLINE (RI_E1H | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE3E3B0_OFFLINE (RI_E1 | RI_E1H | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E2E3E3B0_OFFLINE (RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E2E3E3B0_OFFLINE (RI_E1 | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1HE2E3E3B0_OFFLINE (RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_E1E1HE2E3E3B0_OFFLINE \
- (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE)
-#define RI_ALL_ONLINE RI_E1E1HE2E3E3B0_ONLINE
-#define RI_ALL_OFFLINE RI_E1E1HE2E3E3B0_OFFLINE
-
-#define DBG_DMP_TRACE_BUFFER_SIZE 0x800
-#define DBG_DMP_TRACE_BUFFER_OFFSET(shmem0_offset) \
- ((shmem0_offset) - DBG_DMP_TRACE_BUFFER_SIZE)
-
-struct dump_sign {
- u32 time_stamp;
- u32 diag_ver;
- u32 grc_dump_ver;
-};
-
-struct dump_hdr {
- u32 hdr_size; /* in dwords, excluding this field */
- struct dump_sign dump_sign;
- u32 xstorm_waitp;
- u32 tstorm_waitp;
- u32 ustorm_waitp;
- u32 cstorm_waitp;
- u16 info;
- u8 idle_chk;
- u8 reserved;
+struct dump_header {
+ u32 header_size; /* Size in DWORDs excluding this field */
+ u32 version;
+ u32 preset;
+ u32 dump_meta_data; /* OR of CHIP and PATH. */
};
+#define BNX2X_DUMP_VERSION 0x50acff01
struct reg_addr {
u32 addr;
u32 size;
- u16 info;
+ u32 chips;
+ u32 presets;
};
struct wreg_addr {
@@ -143,1005 +60,2168 @@ struct wreg_addr {
u32 size;
u32 read_regs_count;
const u32 *read_regs;
- u16 info;
+ u32 chips;
+ u32 presets;
+};
+
+#define PAGE_MODE_VALUES_E2 2
+#define PAGE_READ_REGS_E2 1
+#define PAGE_WRITE_REGS_E2 1
+static const u32 page_vals_e2[] = {0, 128};
+static const u32 page_write_regs_e2[] = {328476};
+static const struct reg_addr page_read_regs_e2[] = {
+ {0x58000, 4608, DUMP_CHIP_E2, 0x30}
+};
+
+#define PAGE_MODE_VALUES_E3 2
+#define PAGE_READ_REGS_E3 1
+#define PAGE_WRITE_REGS_E3 1
+static const u32 page_vals_e3[] = {0, 128};
+static const u32 page_write_regs_e3[] = {328476};
+static const struct reg_addr page_read_regs_e3[] = {
+ {0x58000, 4608, DUMP_CHIP_E3A0 | DUMP_CHIP_E3B0, 0x30}
};
static const struct reg_addr reg_addrs[] = {
- { 0x2000, 341, RI_ALL_ONLINE },
- { 0x2800, 103, RI_ALL_ONLINE },
- { 0x3000, 287, RI_ALL_ONLINE },
- { 0x3800, 331, RI_ALL_ONLINE },
- { 0x8800, 6, RI_ALL_ONLINE },
- { 0x8818, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x9000, 147, RI_E2E3E3B0_ONLINE },
- { 0x924c, 1, RI_E2_ONLINE },
- { 0x9250, 16, RI_E2E3E3B0_ONLINE },
- { 0x9400, 33, RI_E2E3E3B0_ONLINE },
- { 0x9484, 5, RI_E3E3B0_ONLINE },
- { 0xa000, 27, RI_ALL_ONLINE },
- { 0xa06c, 1, RI_E1E1H_ONLINE },
- { 0xa070, 71, RI_ALL_ONLINE },
- { 0xa18c, 4, RI_E1E1H_ONLINE },
- { 0xa19c, 62, RI_ALL_ONLINE },
- { 0xa294, 2, RI_E1E1H_ONLINE },
- { 0xa29c, 2, RI_ALL_ONLINE },
- { 0xa2a4, 2, RI_E1E1HE2_ONLINE },
- { 0xa2ac, 52, RI_ALL_ONLINE },
- { 0xa39c, 7, RI_E1HE2E3E3B0_ONLINE },
- { 0xa3b8, 2, RI_E3E3B0_ONLINE },
- { 0xa3c0, 3, RI_E1HE2E3E3B0_ONLINE },
- { 0xa3d0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0xa3d8, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0xa3e0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0xa3e8, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0xa3f0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0xa3f8, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0xa400, 40, RI_ALL_ONLINE },
- { 0xa4a0, 1, RI_E1E1HE2_ONLINE },
- { 0xa4a4, 2, RI_ALL_ONLINE },
- { 0xa4ac, 2, RI_E1E1H_ONLINE },
- { 0xa4b4, 1, RI_E1E1HE2_ONLINE },
- { 0xa4b8, 2, RI_E1E1H_ONLINE },
- { 0xa4c0, 3, RI_ALL_ONLINE },
- { 0xa4cc, 5, RI_E1E1H_ONLINE },
- { 0xa4e0, 3, RI_ALL_ONLINE },
- { 0xa4fc, 2, RI_ALL_ONLINE },
- { 0xa504, 1, RI_E1E1H_ONLINE },
- { 0xa508, 3, RI_ALL_ONLINE },
- { 0xa518, 1, RI_ALL_ONLINE },
- { 0xa520, 1, RI_ALL_ONLINE },
- { 0xa528, 1, RI_ALL_ONLINE },
- { 0xa530, 1, RI_ALL_ONLINE },
- { 0xa538, 1, RI_ALL_ONLINE },
- { 0xa540, 1, RI_ALL_ONLINE },
- { 0xa548, 1, RI_E1E1H_ONLINE },
- { 0xa550, 1, RI_E1E1H_ONLINE },
- { 0xa558, 1, RI_E1E1H_ONLINE },
- { 0xa560, 1, RI_E1E1H_ONLINE },
- { 0xa568, 1, RI_E1E1H_ONLINE },
- { 0xa570, 1, RI_ALL_ONLINE },
- { 0xa580, 1, RI_ALL_ONLINE },
- { 0xa590, 1, RI_ALL_ONLINE },
- { 0xa5a0, 1, RI_E1E1HE2_ONLINE },
- { 0xa5c0, 1, RI_ALL_ONLINE },
- { 0xa5e0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0xa5e8, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0xa5f0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0xa5f8, 1, RI_E1HE2_ONLINE },
- { 0xa5fc, 9, RI_E1HE2E3E3B0_ONLINE },
- { 0xa620, 6, RI_E2E3E3B0_ONLINE },
- { 0xa638, 20, RI_E2_ONLINE },
- { 0xa688, 42, RI_E2E3E3B0_ONLINE },
- { 0xa730, 1, RI_E2_ONLINE },
- { 0xa734, 2, RI_E2E3E3B0_ONLINE },
- { 0xa73c, 4, RI_E2_ONLINE },
- { 0xa74c, 5, RI_E2E3E3B0_ONLINE },
- { 0xa760, 5, RI_E2_ONLINE },
- { 0xa774, 7, RI_E2E3E3B0_ONLINE },
- { 0xa790, 15, RI_E2_ONLINE },
- { 0xa7cc, 4, RI_E2E3E3B0_ONLINE },
- { 0xa7e0, 6, RI_E3E3B0_ONLINE },
- { 0xa800, 18, RI_E2_ONLINE },
- { 0xa848, 33, RI_E2E3E3B0_ONLINE },
- { 0xa8cc, 2, RI_E3E3B0_ONLINE },
- { 0xa8d4, 4, RI_E2E3E3B0_ONLINE },
- { 0xa8e4, 1, RI_E3E3B0_ONLINE },
- { 0xa8e8, 1, RI_E2E3E3B0_ONLINE },
- { 0xa8f0, 1, RI_E2E3E3B0_ONLINE },
- { 0xa8f8, 30, RI_E3E3B0_ONLINE },
- { 0xa974, 73, RI_E3E3B0_ONLINE },
- { 0xac30, 1, RI_E3E3B0_ONLINE },
- { 0xac40, 1, RI_E3E3B0_ONLINE },
- { 0xac50, 1, RI_E3E3B0_ONLINE },
- { 0xac60, 1, RI_E3B0_ONLINE },
- { 0x10000, 9, RI_ALL_ONLINE },
- { 0x10024, 1, RI_E1E1HE2_ONLINE },
- { 0x10028, 5, RI_ALL_ONLINE },
- { 0x1003c, 6, RI_E1E1HE2_ONLINE },
- { 0x10054, 20, RI_ALL_ONLINE },
- { 0x100a4, 4, RI_E1E1HE2_ONLINE },
- { 0x100b4, 11, RI_ALL_ONLINE },
- { 0x100e0, 4, RI_E1E1HE2_ONLINE },
- { 0x100f0, 8, RI_ALL_ONLINE },
- { 0x10110, 6, RI_E1E1HE2_ONLINE },
- { 0x10128, 110, RI_ALL_ONLINE },
- { 0x102e0, 4, RI_E1E1HE2_ONLINE },
- { 0x102f0, 18, RI_ALL_ONLINE },
- { 0x10338, 20, RI_E1E1HE2_ONLINE },
- { 0x10388, 10, RI_ALL_ONLINE },
- { 0x10400, 6, RI_E1E1HE2_ONLINE },
- { 0x10418, 6, RI_ALL_ONLINE },
- { 0x10430, 10, RI_E1E1HE2_ONLINE },
- { 0x10458, 22, RI_ALL_ONLINE },
- { 0x104b0, 12, RI_E1E1HE2_ONLINE },
- { 0x104e0, 1, RI_ALL_ONLINE },
- { 0x104e8, 2, RI_ALL_ONLINE },
- { 0x104f4, 2, RI_ALL_ONLINE },
- { 0x10500, 146, RI_ALL_ONLINE },
- { 0x10750, 2, RI_E1E1HE2_ONLINE },
- { 0x10760, 2, RI_E1E1HE2_ONLINE },
- { 0x10770, 2, RI_E1E1HE2_ONLINE },
- { 0x10780, 2, RI_E1E1HE2_ONLINE },
- { 0x10790, 2, RI_ALL_ONLINE },
- { 0x107a0, 2, RI_E1E1HE2_ONLINE },
- { 0x107b0, 2, RI_E1E1HE2_ONLINE },
- { 0x107c0, 2, RI_E1E1HE2_ONLINE },
- { 0x107d0, 2, RI_E1E1HE2_ONLINE },
- { 0x107e0, 2, RI_ALL_ONLINE },
- { 0x10880, 2, RI_ALL_ONLINE },
- { 0x10900, 2, RI_ALL_ONLINE },
- { 0x16000, 1, RI_E1HE2_ONLINE },
- { 0x16004, 25, RI_E1HE2E3E3B0_ONLINE },
- { 0x16070, 8, RI_E1HE2E3E3B0_ONLINE },
- { 0x16090, 4, RI_E1HE2E3_ONLINE },
- { 0x160a0, 6, RI_E1HE2E3E3B0_ONLINE },
- { 0x160c0, 7, RI_E1HE2E3E3B0_ONLINE },
- { 0x160dc, 2, RI_E1HE2_ONLINE },
- { 0x160e4, 10, RI_E1HE2E3E3B0_ONLINE },
- { 0x1610c, 2, RI_E1HE2_ONLINE },
- { 0x16114, 6, RI_E1HE2E3E3B0_ONLINE },
- { 0x16140, 48, RI_E1HE2E3E3B0_ONLINE },
- { 0x16204, 5, RI_E1HE2E3E3B0_ONLINE },
- { 0x18000, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x18008, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x18010, 35, RI_E2E3E3B0_ONLINE },
- { 0x180a4, 2, RI_E2E3E3B0_ONLINE },
- { 0x180c0, 9, RI_E2E3E3B0_ONLINE },
- { 0x180e4, 1, RI_E2E3_ONLINE },
- { 0x180e8, 2, RI_E2E3E3B0_ONLINE },
- { 0x180f0, 1, RI_E2E3_ONLINE },
- { 0x180f4, 79, RI_E2E3E3B0_ONLINE },
- { 0x18230, 1, RI_E2E3_ONLINE },
- { 0x18234, 2, RI_E2E3E3B0_ONLINE },
- { 0x1823c, 1, RI_E2E3_ONLINE },
- { 0x18240, 13, RI_E2E3E3B0_ONLINE },
- { 0x18274, 1, RI_E2_ONLINE },
- { 0x18278, 81, RI_E2E3E3B0_ONLINE },
- { 0x18440, 63, RI_E2E3E3B0_ONLINE },
- { 0x18570, 42, RI_E3E3B0_ONLINE },
- { 0x18618, 25, RI_E3B0_ONLINE },
- { 0x18680, 44, RI_E3B0_ONLINE },
- { 0x18748, 12, RI_E3B0_ONLINE },
- { 0x18788, 1, RI_E3B0_ONLINE },
- { 0x1879c, 6, RI_E3B0_ONLINE },
- { 0x187c4, 51, RI_E3B0_ONLINE },
- { 0x18a00, 48, RI_E3B0_ONLINE },
- { 0x20000, 24, RI_ALL_ONLINE },
- { 0x20060, 8, RI_ALL_ONLINE },
- { 0x20080, 94, RI_ALL_ONLINE },
- { 0x201f8, 1, RI_E1E1H_ONLINE },
- { 0x201fc, 1, RI_ALL_ONLINE },
- { 0x20200, 1, RI_E1E1H_ONLINE },
- { 0x20204, 1, RI_ALL_ONLINE },
- { 0x20208, 1, RI_E1E1H_ONLINE },
- { 0x2020c, 39, RI_ALL_ONLINE },
- { 0x202c8, 1, RI_E2E3E3B0_ONLINE },
- { 0x202d8, 4, RI_E2E3E3B0_ONLINE },
- { 0x202f0, 1, RI_E3B0_ONLINE },
- { 0x20400, 2, RI_ALL_ONLINE },
- { 0x2040c, 8, RI_ALL_ONLINE },
- { 0x2042c, 18, RI_E1HE2E3E3B0_ONLINE },
- { 0x20480, 1, RI_ALL_ONLINE },
- { 0x20500, 1, RI_ALL_ONLINE },
- { 0x20600, 1, RI_ALL_ONLINE },
- { 0x28000, 1, RI_ALL_ONLINE },
- { 0x28004, 8191, RI_ALL_OFFLINE },
- { 0x30000, 1, RI_ALL_ONLINE },
- { 0x30004, 16383, RI_ALL_OFFLINE },
- { 0x40000, 98, RI_ALL_ONLINE },
- { 0x401a8, 8, RI_E1HE2E3E3B0_ONLINE },
- { 0x401c8, 1, RI_E1H_ONLINE },
- { 0x401cc, 2, RI_E1HE2E3E3B0_ONLINE },
- { 0x401d4, 2, RI_E2E3E3B0_ONLINE },
- { 0x40200, 4, RI_ALL_ONLINE },
- { 0x40220, 6, RI_E2E3E3B0_ONLINE },
- { 0x40238, 8, RI_E2E3_ONLINE },
- { 0x40258, 4, RI_E2E3E3B0_ONLINE },
- { 0x40268, 2, RI_E3E3B0_ONLINE },
- { 0x40270, 17, RI_E3B0_ONLINE },
- { 0x40400, 43, RI_ALL_ONLINE },
- { 0x404cc, 3, RI_E1HE2E3E3B0_ONLINE },
- { 0x404e0, 1, RI_E2E3E3B0_ONLINE },
- { 0x40500, 2, RI_ALL_ONLINE },
- { 0x40510, 2, RI_ALL_ONLINE },
- { 0x40520, 2, RI_ALL_ONLINE },
- { 0x40530, 2, RI_ALL_ONLINE },
- { 0x40540, 2, RI_ALL_ONLINE },
- { 0x40550, 10, RI_E2E3E3B0_ONLINE },
- { 0x40610, 2, RI_E2E3E3B0_ONLINE },
- { 0x42000, 164, RI_ALL_ONLINE },
- { 0x422c0, 4, RI_E2E3E3B0_ONLINE },
- { 0x422d4, 5, RI_E1HE2E3E3B0_ONLINE },
- { 0x422e8, 1, RI_E2E3E3B0_ONLINE },
- { 0x42400, 49, RI_ALL_ONLINE },
- { 0x424c8, 38, RI_ALL_ONLINE },
- { 0x42568, 2, RI_ALL_ONLINE },
- { 0x42640, 5, RI_E2E3E3B0_ONLINE },
- { 0x42800, 1, RI_ALL_ONLINE },
- { 0x50000, 1, RI_ALL_ONLINE },
- { 0x50004, 19, RI_ALL_ONLINE },
- { 0x50050, 8, RI_ALL_ONLINE },
- { 0x50070, 88, RI_ALL_ONLINE },
- { 0x501f0, 4, RI_E1HE2E3E3B0_ONLINE },
- { 0x50200, 2, RI_ALL_ONLINE },
- { 0x5020c, 7, RI_ALL_ONLINE },
- { 0x50228, 6, RI_E1HE2E3E3B0_ONLINE },
- { 0x50240, 1, RI_ALL_ONLINE },
- { 0x50280, 1, RI_ALL_ONLINE },
- { 0x50300, 1, RI_E2E3E3B0_ONLINE },
- { 0x5030c, 1, RI_E2E3E3B0_ONLINE },
- { 0x50318, 1, RI_E2E3E3B0_ONLINE },
- { 0x5031c, 1, RI_E2E3E3B0_ONLINE },
- { 0x50320, 2, RI_E2E3E3B0_ONLINE },
- { 0x50330, 1, RI_E3B0_ONLINE },
- { 0x52000, 1, RI_ALL_ONLINE },
- { 0x54000, 1, RI_ALL_ONLINE },
- { 0x54004, 3327, RI_ALL_OFFLINE },
- { 0x58000, 1, RI_ALL_ONLINE },
- { 0x58004, 8191, RI_E1E1H_OFFLINE },
- { 0x60000, 26, RI_ALL_ONLINE },
- { 0x60068, 8, RI_E1E1H_ONLINE },
- { 0x60088, 12, RI_ALL_ONLINE },
- { 0x600b8, 9, RI_E1E1H_ONLINE },
- { 0x600dc, 1, RI_ALL_ONLINE },
- { 0x600e0, 5, RI_E1E1H_ONLINE },
- { 0x600f4, 1, RI_E1E1HE2_ONLINE },
- { 0x600f8, 1, RI_E1E1H_ONLINE },
- { 0x600fc, 8, RI_ALL_ONLINE },
- { 0x6013c, 24, RI_E1H_ONLINE },
- { 0x6019c, 2, RI_E2E3E3B0_ONLINE },
- { 0x601ac, 18, RI_E2E3E3B0_ONLINE },
- { 0x60200, 1, RI_ALL_ONLINE },
- { 0x60204, 2, RI_ALL_OFFLINE },
- { 0x60210, 13, RI_E2E3E3B0_ONLINE },
- { 0x60244, 16, RI_E3B0_ONLINE },
- { 0x61000, 1, RI_ALL_ONLINE },
- { 0x61004, 511, RI_ALL_OFFLINE },
- { 0x61800, 512, RI_E3E3B0_OFFLINE },
- { 0x70000, 8, RI_ALL_ONLINE },
- { 0x70020, 8184, RI_ALL_OFFLINE },
- { 0x78000, 8192, RI_E3E3B0_OFFLINE },
- { 0x85000, 3, RI_ALL_OFFLINE },
- { 0x8501c, 7, RI_ALL_OFFLINE },
- { 0x85048, 1, RI_ALL_OFFLINE },
- { 0x85200, 32, RI_ALL_OFFLINE },
- { 0xb0000, 16384, RI_E1H_OFFLINE },
- { 0xc1000, 7, RI_ALL_ONLINE },
- { 0xc103c, 2, RI_E2E3E3B0_ONLINE },
- { 0xc1800, 2, RI_ALL_ONLINE },
- { 0xc2000, 164, RI_ALL_ONLINE },
- { 0xc22c0, 5, RI_E2E3E3B0_ONLINE },
- { 0xc22d8, 4, RI_E2E3E3B0_ONLINE },
- { 0xc2400, 49, RI_ALL_ONLINE },
- { 0xc24c8, 38, RI_ALL_ONLINE },
- { 0xc2568, 2, RI_ALL_ONLINE },
- { 0xc2600, 1, RI_ALL_ONLINE },
- { 0xc4000, 165, RI_ALL_ONLINE },
- { 0xc42d8, 2, RI_E2E3E3B0_ONLINE },
- { 0xc42e0, 7, RI_E1HE2E3E3B0_ONLINE },
- { 0xc42fc, 1, RI_E2E3E3B0_ONLINE },
- { 0xc4400, 51, RI_ALL_ONLINE },
- { 0xc44d0, 38, RI_ALL_ONLINE },
- { 0xc4570, 2, RI_ALL_ONLINE },
- { 0xc4578, 5, RI_E2E3E3B0_ONLINE },
- { 0xc4600, 1, RI_ALL_ONLINE },
- { 0xd0000, 19, RI_ALL_ONLINE },
- { 0xd004c, 8, RI_ALL_ONLINE },
- { 0xd006c, 91, RI_ALL_ONLINE },
- { 0xd01fc, 1, RI_E2E3E3B0_ONLINE },
- { 0xd0200, 2, RI_ALL_ONLINE },
- { 0xd020c, 7, RI_ALL_ONLINE },
- { 0xd0228, 18, RI_E1HE2E3E3B0_ONLINE },
- { 0xd0280, 1, RI_ALL_ONLINE },
- { 0xd0300, 1, RI_ALL_ONLINE },
- { 0xd0400, 1, RI_ALL_ONLINE },
- { 0xd0818, 1, RI_E3B0_ONLINE },
- { 0xd4000, 1, RI_ALL_ONLINE },
- { 0xd4004, 2559, RI_ALL_OFFLINE },
- { 0xd8000, 1, RI_ALL_ONLINE },
- { 0xd8004, 8191, RI_ALL_OFFLINE },
- { 0xe0000, 21, RI_ALL_ONLINE },
- { 0xe0054, 8, RI_ALL_ONLINE },
- { 0xe0074, 49, RI_ALL_ONLINE },
- { 0xe0138, 1, RI_E1E1H_ONLINE },
- { 0xe013c, 35, RI_ALL_ONLINE },
- { 0xe01f4, 1, RI_E2_ONLINE },
- { 0xe01f8, 1, RI_E2E3E3B0_ONLINE },
- { 0xe0200, 2, RI_ALL_ONLINE },
- { 0xe020c, 8, RI_ALL_ONLINE },
- { 0xe022c, 18, RI_E1HE2E3E3B0_ONLINE },
- { 0xe0280, 1, RI_ALL_ONLINE },
- { 0xe0300, 1, RI_ALL_ONLINE },
- { 0xe0400, 1, RI_E3B0_ONLINE },
- { 0xe1000, 1, RI_ALL_ONLINE },
- { 0xe2000, 1, RI_ALL_ONLINE },
- { 0xe2004, 2047, RI_ALL_OFFLINE },
- { 0xf0000, 1, RI_ALL_ONLINE },
- { 0xf0004, 16383, RI_ALL_OFFLINE },
- { 0x101000, 12, RI_ALL_ONLINE },
- { 0x101050, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x101054, 3, RI_E2E3E3B0_ONLINE },
- { 0x101100, 1, RI_ALL_ONLINE },
- { 0x101800, 8, RI_ALL_ONLINE },
- { 0x102000, 18, RI_ALL_ONLINE },
- { 0x102068, 6, RI_E2E3E3B0_ONLINE },
- { 0x102080, 17, RI_ALL_ONLINE },
- { 0x1020c8, 8, RI_E1H_ONLINE },
- { 0x1020e8, 9, RI_E2E3E3B0_ONLINE },
- { 0x102400, 1, RI_ALL_ONLINE },
- { 0x103000, 26, RI_ALL_ONLINE },
- { 0x103098, 5, RI_E1HE2E3E3B0_ONLINE },
- { 0x1030ac, 2, RI_E2E3E3B0_ONLINE },
- { 0x1030b4, 1, RI_E2_ONLINE },
- { 0x1030b8, 7, RI_E2E3E3B0_ONLINE },
- { 0x1030d8, 8, RI_E2E3E3B0_ONLINE },
- { 0x103400, 1, RI_E2E3E3B0_ONLINE },
- { 0x103404, 135, RI_E2E3E3B0_OFFLINE },
- { 0x103800, 8, RI_ALL_ONLINE },
- { 0x104000, 63, RI_ALL_ONLINE },
- { 0x10411c, 16, RI_E2E3E3B0_ONLINE },
- { 0x104200, 17, RI_ALL_ONLINE },
- { 0x104400, 64, RI_ALL_ONLINE },
- { 0x104500, 192, RI_ALL_OFFLINE },
- { 0x104800, 64, RI_ALL_ONLINE },
- { 0x104900, 192, RI_ALL_OFFLINE },
- { 0x105000, 256, RI_ALL_ONLINE },
- { 0x105400, 768, RI_ALL_OFFLINE },
- { 0x107000, 7, RI_E2E3E3B0_ONLINE },
- { 0x10701c, 1, RI_E3E3B0_ONLINE },
- { 0x108000, 33, RI_E1E1H_ONLINE },
- { 0x1080ac, 5, RI_E1H_ONLINE },
- { 0x108100, 5, RI_E1E1H_ONLINE },
- { 0x108120, 5, RI_E1E1H_ONLINE },
- { 0x108200, 74, RI_E1E1H_ONLINE },
- { 0x108400, 74, RI_E1E1H_ONLINE },
- { 0x108800, 152, RI_E1E1H_ONLINE },
- { 0x110000, 111, RI_E2E3E3B0_ONLINE },
- { 0x1101dc, 1, RI_E3E3B0_ONLINE },
- { 0x110200, 4, RI_E2E3E3B0_ONLINE },
- { 0x120000, 2, RI_ALL_ONLINE },
- { 0x120008, 4, RI_ALL_ONLINE },
- { 0x120018, 3, RI_ALL_ONLINE },
- { 0x120024, 4, RI_ALL_ONLINE },
- { 0x120034, 3, RI_ALL_ONLINE },
- { 0x120040, 4, RI_ALL_ONLINE },
- { 0x120050, 3, RI_ALL_ONLINE },
- { 0x12005c, 4, RI_ALL_ONLINE },
- { 0x12006c, 3, RI_ALL_ONLINE },
- { 0x120078, 4, RI_ALL_ONLINE },
- { 0x120088, 3, RI_ALL_ONLINE },
- { 0x120094, 4, RI_ALL_ONLINE },
- { 0x1200a4, 3, RI_ALL_ONLINE },
- { 0x1200b0, 4, RI_ALL_ONLINE },
- { 0x1200c0, 3, RI_ALL_ONLINE },
- { 0x1200cc, 4, RI_ALL_ONLINE },
- { 0x1200dc, 3, RI_ALL_ONLINE },
- { 0x1200e8, 4, RI_ALL_ONLINE },
- { 0x1200f8, 3, RI_ALL_ONLINE },
- { 0x120104, 4, RI_ALL_ONLINE },
- { 0x120114, 1, RI_ALL_ONLINE },
- { 0x120118, 22, RI_ALL_ONLINE },
- { 0x120170, 2, RI_E1E1H_ONLINE },
- { 0x120178, 243, RI_ALL_ONLINE },
- { 0x120544, 4, RI_E1E1H_ONLINE },
- { 0x120554, 6, RI_ALL_ONLINE },
- { 0x12059c, 6, RI_E1HE2E3E3B0_ONLINE },
- { 0x1205b4, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1205b8, 15, RI_E1HE2E3E3B0_ONLINE },
- { 0x1205f4, 1, RI_E1HE2_ONLINE },
- { 0x1205f8, 4, RI_E2E3E3B0_ONLINE },
- { 0x120618, 1, RI_E2E3E3B0_ONLINE },
- { 0x12061c, 20, RI_E1HE2E3E3B0_ONLINE },
- { 0x12066c, 11, RI_E1HE2E3E3B0_ONLINE },
- { 0x120698, 3, RI_E2E3E3B0_ONLINE },
- { 0x1206a4, 1, RI_E2_ONLINE },
- { 0x1206a8, 1, RI_E2E3E3B0_ONLINE },
- { 0x1206b0, 75, RI_E2E3E3B0_ONLINE },
- { 0x1207dc, 1, RI_E2_ONLINE },
- { 0x1207fc, 1, RI_E2E3E3B0_ONLINE },
- { 0x12080c, 65, RI_ALL_ONLINE },
- { 0x120910, 7, RI_E2E3E3B0_ONLINE },
- { 0x120930, 9, RI_E2E3E3B0_ONLINE },
- { 0x12095c, 37, RI_E3E3B0_ONLINE },
- { 0x120a00, 2, RI_E1E1HE2_ONLINE },
- { 0x120b00, 1, RI_E3E3B0_ONLINE },
- { 0x122000, 2, RI_ALL_ONLINE },
- { 0x122008, 2046, RI_E1_OFFLINE },
- { 0x128000, 2, RI_E1HE2E3E3B0_ONLINE },
- { 0x128008, 6142, RI_E1HE2E3E3B0_OFFLINE },
- { 0x130000, 35, RI_E2E3E3B0_ONLINE },
- { 0x130100, 29, RI_E2E3E3B0_ONLINE },
- { 0x130180, 1, RI_E2E3E3B0_ONLINE },
- { 0x130200, 1, RI_E2E3E3B0_ONLINE },
- { 0x130280, 1, RI_E2E3E3B0_ONLINE },
- { 0x130300, 5, RI_E2E3E3B0_ONLINE },
- { 0x130380, 1, RI_E2E3E3B0_ONLINE },
- { 0x130400, 1, RI_E2E3E3B0_ONLINE },
- { 0x130480, 5, RI_E2E3E3B0_ONLINE },
- { 0x130800, 72, RI_E2E3E3B0_ONLINE },
- { 0x131000, 136, RI_E2E3E3B0_ONLINE },
- { 0x132000, 148, RI_E2E3E3B0_ONLINE },
- { 0x134000, 544, RI_E2E3E3B0_ONLINE },
- { 0x140000, 1, RI_ALL_ONLINE },
- { 0x140004, 9, RI_E1E1HE2E3_ONLINE },
- { 0x140028, 8, RI_ALL_ONLINE },
- { 0x140048, 10, RI_E1E1HE2E3_ONLINE },
- { 0x140070, 1, RI_ALL_ONLINE },
- { 0x140074, 10, RI_E1E1HE2E3_ONLINE },
- { 0x14009c, 1, RI_ALL_ONLINE },
- { 0x1400a0, 5, RI_E1E1HE2E3_ONLINE },
- { 0x1400b4, 7, RI_ALL_ONLINE },
- { 0x1400d0, 10, RI_E1E1HE2E3_ONLINE },
- { 0x1400f8, 2, RI_ALL_ONLINE },
- { 0x140100, 5, RI_E1E1H_ONLINE },
- { 0x140114, 5, RI_E1E1HE2E3_ONLINE },
- { 0x140128, 7, RI_ALL_ONLINE },
- { 0x140144, 9, RI_E1E1HE2E3_ONLINE },
- { 0x140168, 8, RI_ALL_ONLINE },
- { 0x140188, 3, RI_E1E1HE2E3_ONLINE },
- { 0x140194, 13, RI_ALL_ONLINE },
- { 0x140200, 6, RI_E1E1HE2E3_ONLINE },
- { 0x140260, 4, RI_E2E3_ONLINE },
- { 0x140280, 4, RI_E2E3_ONLINE },
- { 0x1402e0, 2, RI_E2E3_ONLINE },
- { 0x1402e8, 2, RI_E2E3E3B0_ONLINE },
- { 0x1402f0, 9, RI_E2E3_ONLINE },
- { 0x140314, 44, RI_E3B0_ONLINE },
- { 0x144000, 4, RI_E1E1H_ONLINE },
- { 0x148000, 4, RI_E1E1H_ONLINE },
- { 0x14c000, 4, RI_E1E1H_ONLINE },
- { 0x150000, 4, RI_E1E1H_ONLINE },
- { 0x154000, 4, RI_E1E1H_ONLINE },
- { 0x158000, 4, RI_E1E1H_ONLINE },
- { 0x15c000, 2, RI_E1HE2E3E3B0_ONLINE },
- { 0x15c008, 5, RI_E1H_ONLINE },
- { 0x15c020, 8, RI_E2E3E3B0_ONLINE },
- { 0x15c040, 1, RI_E2E3_ONLINE },
- { 0x15c044, 2, RI_E2E3E3B0_ONLINE },
- { 0x15c04c, 8, RI_E2E3_ONLINE },
- { 0x15c06c, 8, RI_E2E3E3B0_ONLINE },
- { 0x15c090, 13, RI_E2E3E3B0_ONLINE },
- { 0x15c0c8, 24, RI_E2E3E3B0_ONLINE },
- { 0x15c128, 2, RI_E2E3_ONLINE },
- { 0x15c130, 8, RI_E2E3E3B0_ONLINE },
- { 0x15c150, 2, RI_E3E3B0_ONLINE },
- { 0x15c158, 2, RI_E3_ONLINE },
- { 0x15c160, 149, RI_E3B0_ONLINE },
- { 0x161000, 7, RI_ALL_ONLINE },
- { 0x16103c, 2, RI_E2E3E3B0_ONLINE },
- { 0x161800, 2, RI_ALL_ONLINE },
- { 0x162000, 54, RI_E3E3B0_ONLINE },
- { 0x162200, 60, RI_E3E3B0_ONLINE },
- { 0x162400, 54, RI_E3E3B0_ONLINE },
- { 0x162600, 60, RI_E3E3B0_ONLINE },
- { 0x162800, 54, RI_E3E3B0_ONLINE },
- { 0x162a00, 60, RI_E3E3B0_ONLINE },
- { 0x162c00, 54, RI_E3E3B0_ONLINE },
- { 0x162e00, 60, RI_E3E3B0_ONLINE },
- { 0x164000, 60, RI_ALL_ONLINE },
- { 0x164110, 2, RI_E1HE2E3E3B0_ONLINE },
- { 0x164118, 15, RI_E2E3E3B0_ONLINE },
- { 0x164200, 1, RI_ALL_ONLINE },
- { 0x164208, 1, RI_ALL_ONLINE },
- { 0x164210, 1, RI_ALL_ONLINE },
- { 0x164218, 1, RI_ALL_ONLINE },
- { 0x164220, 1, RI_ALL_ONLINE },
- { 0x164228, 1, RI_ALL_ONLINE },
- { 0x164230, 1, RI_ALL_ONLINE },
- { 0x164238, 1, RI_ALL_ONLINE },
- { 0x164240, 1, RI_ALL_ONLINE },
- { 0x164248, 1, RI_ALL_ONLINE },
- { 0x164250, 1, RI_ALL_ONLINE },
- { 0x164258, 1, RI_ALL_ONLINE },
- { 0x164260, 1, RI_ALL_ONLINE },
- { 0x164270, 2, RI_ALL_ONLINE },
- { 0x164280, 2, RI_ALL_ONLINE },
- { 0x164800, 2, RI_ALL_ONLINE },
- { 0x165000, 2, RI_ALL_ONLINE },
- { 0x166000, 164, RI_ALL_ONLINE },
- { 0x1662cc, 7, RI_E2E3E3B0_ONLINE },
- { 0x166400, 49, RI_ALL_ONLINE },
- { 0x1664c8, 38, RI_ALL_ONLINE },
- { 0x166568, 2, RI_ALL_ONLINE },
- { 0x166570, 5, RI_E2E3E3B0_ONLINE },
- { 0x166800, 1, RI_ALL_ONLINE },
- { 0x168000, 137, RI_ALL_ONLINE },
- { 0x168224, 2, RI_E1E1H_ONLINE },
- { 0x16822c, 29, RI_ALL_ONLINE },
- { 0x1682a0, 12, RI_E1E1H_ONLINE },
- { 0x1682d0, 12, RI_ALL_ONLINE },
- { 0x168300, 2, RI_E1E1H_ONLINE },
- { 0x168308, 68, RI_ALL_ONLINE },
- { 0x168418, 2, RI_E1E1H_ONLINE },
- { 0x168420, 6, RI_ALL_ONLINE },
- { 0x168800, 19, RI_ALL_ONLINE },
- { 0x168900, 1, RI_ALL_ONLINE },
- { 0x168a00, 128, RI_ALL_ONLINE },
- { 0x16a000, 1, RI_ALL_ONLINE },
- { 0x16a004, 1535, RI_ALL_OFFLINE },
- { 0x16c000, 1, RI_ALL_ONLINE },
- { 0x16c004, 1535, RI_ALL_OFFLINE },
- { 0x16e000, 16, RI_E1H_ONLINE },
- { 0x16e040, 8, RI_E2E3E3B0_ONLINE },
- { 0x16e100, 1, RI_E1H_ONLINE },
- { 0x16e200, 2, RI_E1H_ONLINE },
- { 0x16e400, 161, RI_E1H_ONLINE },
- { 0x16e684, 2, RI_E1HE2E3E3B0_ONLINE },
- { 0x16e68c, 12, RI_E1H_ONLINE },
- { 0x16e6bc, 4, RI_E1HE2E3E3B0_ONLINE },
- { 0x16e6cc, 4, RI_E1H_ONLINE },
- { 0x16e6e0, 2, RI_E2E3E3B0_ONLINE },
- { 0x16e6e8, 5, RI_E2E3_ONLINE },
- { 0x16e6fc, 5, RI_E2E3E3B0_ONLINE },
- { 0x16e768, 17, RI_E2E3E3B0_ONLINE },
- { 0x16e7ac, 12, RI_E3B0_ONLINE },
- { 0x170000, 24, RI_ALL_ONLINE },
- { 0x170060, 4, RI_E1E1H_ONLINE },
- { 0x170070, 65, RI_ALL_ONLINE },
- { 0x170194, 11, RI_E2E3E3B0_ONLINE },
- { 0x1701c4, 1, RI_E2E3E3B0_ONLINE },
- { 0x1701cc, 7, RI_E2E3E3B0_ONLINE },
- { 0x1701e8, 1, RI_E3E3B0_ONLINE },
- { 0x1701ec, 1, RI_E2E3E3B0_ONLINE },
- { 0x1701f4, 1, RI_E2E3E3B0_ONLINE },
- { 0x170200, 4, RI_ALL_ONLINE },
- { 0x170214, 1, RI_ALL_ONLINE },
- { 0x170218, 77, RI_E2E3E3B0_ONLINE },
- { 0x170400, 64, RI_E2E3E3B0_ONLINE },
- { 0x178000, 1, RI_ALL_ONLINE },
- { 0x180000, 61, RI_ALL_ONLINE },
- { 0x18013c, 2, RI_E1HE2E3E3B0_ONLINE },
- { 0x180200, 58, RI_ALL_ONLINE },
- { 0x180340, 4, RI_ALL_ONLINE },
- { 0x180380, 1, RI_E2E3E3B0_ONLINE },
- { 0x180388, 1, RI_E2E3E3B0_ONLINE },
- { 0x180390, 1, RI_E2E3E3B0_ONLINE },
- { 0x180398, 1, RI_E2E3E3B0_ONLINE },
- { 0x1803a0, 5, RI_E2E3E3B0_ONLINE },
- { 0x1803b4, 2, RI_E3E3B0_ONLINE },
- { 0x180404, 255, RI_E1E1H_OFFLINE },
- { 0x181000, 4, RI_ALL_ONLINE },
- { 0x181010, 1020, RI_ALL_OFFLINE },
- { 0x182000, 4, RI_E3E3B0_ONLINE },
- { 0x1a0000, 1, RI_ALL_ONLINE },
- { 0x1a0004, 5631, RI_ALL_OFFLINE },
- { 0x1a5800, 2560, RI_E1HE2E3E3B0_OFFLINE },
- { 0x1a8000, 1, RI_ALL_ONLINE },
- { 0x1a8004, 8191, RI_E1HE2E3E3B0_OFFLINE },
- { 0x1b0000, 1, RI_ALL_ONLINE },
- { 0x1b0004, 15, RI_E1H_OFFLINE },
- { 0x1b0040, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b0044, 239, RI_E1H_OFFLINE },
- { 0x1b0400, 1, RI_ALL_ONLINE },
- { 0x1b0404, 255, RI_E1H_OFFLINE },
- { 0x1b0800, 1, RI_ALL_ONLINE },
- { 0x1b0840, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b0c00, 1, RI_ALL_ONLINE },
- { 0x1b1000, 1, RI_ALL_ONLINE },
- { 0x1b1040, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b1400, 1, RI_ALL_ONLINE },
- { 0x1b1440, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b1480, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b14c0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b1800, 128, RI_ALL_OFFLINE },
- { 0x1b1c00, 128, RI_ALL_OFFLINE },
- { 0x1b2000, 1, RI_ALL_ONLINE },
- { 0x1b2400, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b2404, 5631, RI_E2E3E3B0_OFFLINE },
- { 0x1b8000, 1, RI_ALL_ONLINE },
- { 0x1b8040, 1, RI_ALL_ONLINE },
- { 0x1b8080, 1, RI_ALL_ONLINE },
- { 0x1b80c0, 1, RI_ALL_ONLINE },
- { 0x1b8100, 1, RI_ALL_ONLINE },
- { 0x1b8140, 1, RI_ALL_ONLINE },
- { 0x1b8180, 1, RI_ALL_ONLINE },
- { 0x1b81c0, 1, RI_ALL_ONLINE },
- { 0x1b8200, 1, RI_ALL_ONLINE },
- { 0x1b8240, 1, RI_ALL_ONLINE },
- { 0x1b8280, 1, RI_ALL_ONLINE },
- { 0x1b82c0, 1, RI_ALL_ONLINE },
- { 0x1b8300, 1, RI_ALL_ONLINE },
- { 0x1b8340, 1, RI_ALL_ONLINE },
- { 0x1b8380, 1, RI_ALL_ONLINE },
- { 0x1b83c0, 1, RI_ALL_ONLINE },
- { 0x1b8400, 1, RI_ALL_ONLINE },
- { 0x1b8440, 1, RI_ALL_ONLINE },
- { 0x1b8480, 1, RI_ALL_ONLINE },
- { 0x1b84c0, 1, RI_ALL_ONLINE },
- { 0x1b8500, 1, RI_ALL_ONLINE },
- { 0x1b8540, 1, RI_ALL_ONLINE },
- { 0x1b8580, 1, RI_ALL_ONLINE },
- { 0x1b85c0, 19, RI_E2E3E3B0_ONLINE },
- { 0x1b8800, 1, RI_ALL_ONLINE },
- { 0x1b8840, 1, RI_ALL_ONLINE },
- { 0x1b8880, 1, RI_ALL_ONLINE },
- { 0x1b88c0, 1, RI_ALL_ONLINE },
- { 0x1b8900, 1, RI_ALL_ONLINE },
- { 0x1b8940, 1, RI_ALL_ONLINE },
- { 0x1b8980, 1, RI_ALL_ONLINE },
- { 0x1b89c0, 1, RI_ALL_ONLINE },
- { 0x1b8a00, 1, RI_ALL_ONLINE },
- { 0x1b8a40, 1, RI_ALL_ONLINE },
- { 0x1b8a80, 1, RI_ALL_ONLINE },
- { 0x1b8ac0, 1, RI_ALL_ONLINE },
- { 0x1b8b00, 1, RI_ALL_ONLINE },
- { 0x1b8b40, 1, RI_ALL_ONLINE },
- { 0x1b8b80, 1, RI_ALL_ONLINE },
- { 0x1b8bc0, 1, RI_ALL_ONLINE },
- { 0x1b8c00, 1, RI_ALL_ONLINE },
- { 0x1b8c40, 1, RI_ALL_ONLINE },
- { 0x1b8c80, 1, RI_ALL_ONLINE },
- { 0x1b8cc0, 1, RI_ALL_ONLINE },
- { 0x1b8cc4, 1, RI_E2E3E3B0_ONLINE },
- { 0x1b8d00, 1, RI_ALL_ONLINE },
- { 0x1b8d40, 1, RI_ALL_ONLINE },
- { 0x1b8d80, 1, RI_ALL_ONLINE },
- { 0x1b8dc0, 1, RI_ALL_ONLINE },
- { 0x1b8e00, 1, RI_ALL_ONLINE },
- { 0x1b8e40, 1, RI_ALL_ONLINE },
- { 0x1b8e80, 1, RI_ALL_ONLINE },
- { 0x1b8e84, 1, RI_E2E3E3B0_ONLINE },
- { 0x1b8ec0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b8f00, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b8f40, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b8f80, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b8fc0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x1b8fc4, 2, RI_E2E3E3B0_ONLINE },
- { 0x1b8fd0, 6, RI_E2E3E3B0_ONLINE },
- { 0x1b8fe8, 2, RI_E3E3B0_ONLINE },
- { 0x1b9000, 1, RI_E2E3E3B0_ONLINE },
- { 0x1b9040, 3, RI_E2E3E3B0_ONLINE },
- { 0x1b905c, 1, RI_E3E3B0_ONLINE },
- { 0x1b9064, 1, RI_E3B0_ONLINE },
- { 0x1b9080, 10, RI_E3B0_ONLINE },
- { 0x1b9400, 14, RI_E2E3E3B0_OFFLINE },
- { 0x1b943c, 19, RI_E2E3E3B0_OFFLINE },
- { 0x1b9490, 10, RI_E2E3E3B0_OFFLINE },
- { 0x1c0000, 2, RI_ALL_ONLINE },
- { 0x200000, 65, RI_ALL_ONLINE },
- { 0x20014c, 2, RI_E1HE2E3E3B0_ONLINE },
- { 0x200200, 58, RI_ALL_ONLINE },
- { 0x200340, 4, RI_ALL_ONLINE },
- { 0x200380, 1, RI_E2E3E3B0_ONLINE },
- { 0x200388, 1, RI_E2E3E3B0_ONLINE },
- { 0x200390, 1, RI_E2E3E3B0_ONLINE },
- { 0x200398, 1, RI_E2E3E3B0_ONLINE },
- { 0x2003a0, 1, RI_E2E3E3B0_ONLINE },
- { 0x2003a8, 2, RI_E2E3E3B0_ONLINE },
- { 0x200404, 255, RI_E1E1H_OFFLINE },
- { 0x202000, 4, RI_ALL_ONLINE },
- { 0x202010, 2044, RI_ALL_OFFLINE },
- { 0x204000, 4, RI_E3E3B0_ONLINE },
- { 0x220000, 1, RI_ALL_ONLINE },
- { 0x220004, 5631, RI_ALL_OFFLINE },
- { 0x225800, 2560, RI_E1HE2E3E3B0_OFFLINE },
- { 0x228000, 1, RI_ALL_ONLINE },
- { 0x228004, 8191, RI_E1HE2E3E3B0_OFFLINE },
- { 0x230000, 1, RI_ALL_ONLINE },
- { 0x230004, 15, RI_E1H_OFFLINE },
- { 0x230040, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x230044, 239, RI_E1H_OFFLINE },
- { 0x230400, 1, RI_ALL_ONLINE },
- { 0x230404, 255, RI_E1H_OFFLINE },
- { 0x230800, 1, RI_ALL_ONLINE },
- { 0x230840, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x230c00, 1, RI_ALL_ONLINE },
- { 0x231000, 1, RI_ALL_ONLINE },
- { 0x231040, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x231400, 1, RI_ALL_ONLINE },
- { 0x231440, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x231480, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2314c0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x231800, 128, RI_ALL_OFFLINE },
- { 0x231c00, 128, RI_ALL_OFFLINE },
- { 0x232000, 1, RI_ALL_ONLINE },
- { 0x232400, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x232404, 5631, RI_E2E3E3B0_OFFLINE },
- { 0x238000, 1, RI_ALL_ONLINE },
- { 0x238040, 1, RI_ALL_ONLINE },
- { 0x238080, 1, RI_ALL_ONLINE },
- { 0x2380c0, 1, RI_ALL_ONLINE },
- { 0x238100, 1, RI_ALL_ONLINE },
- { 0x238140, 1, RI_ALL_ONLINE },
- { 0x238180, 1, RI_ALL_ONLINE },
- { 0x2381c0, 1, RI_ALL_ONLINE },
- { 0x238200, 1, RI_ALL_ONLINE },
- { 0x238240, 1, RI_ALL_ONLINE },
- { 0x238280, 1, RI_ALL_ONLINE },
- { 0x2382c0, 1, RI_ALL_ONLINE },
- { 0x238300, 1, RI_ALL_ONLINE },
- { 0x238340, 1, RI_ALL_ONLINE },
- { 0x238380, 1, RI_ALL_ONLINE },
- { 0x2383c0, 1, RI_ALL_ONLINE },
- { 0x238400, 1, RI_ALL_ONLINE },
- { 0x238440, 1, RI_ALL_ONLINE },
- { 0x238480, 1, RI_ALL_ONLINE },
- { 0x2384c0, 1, RI_ALL_ONLINE },
- { 0x238500, 1, RI_ALL_ONLINE },
- { 0x238540, 1, RI_ALL_ONLINE },
- { 0x238580, 1, RI_ALL_ONLINE },
- { 0x2385c0, 19, RI_E2E3E3B0_ONLINE },
- { 0x238800, 1, RI_ALL_ONLINE },
- { 0x238840, 1, RI_ALL_ONLINE },
- { 0x238880, 1, RI_ALL_ONLINE },
- { 0x2388c0, 1, RI_ALL_ONLINE },
- { 0x238900, 1, RI_ALL_ONLINE },
- { 0x238940, 1, RI_ALL_ONLINE },
- { 0x238980, 1, RI_ALL_ONLINE },
- { 0x2389c0, 1, RI_ALL_ONLINE },
- { 0x238a00, 1, RI_ALL_ONLINE },
- { 0x238a40, 1, RI_ALL_ONLINE },
- { 0x238a80, 1, RI_ALL_ONLINE },
- { 0x238ac0, 1, RI_ALL_ONLINE },
- { 0x238b00, 1, RI_ALL_ONLINE },
- { 0x238b40, 1, RI_ALL_ONLINE },
- { 0x238b80, 1, RI_ALL_ONLINE },
- { 0x238bc0, 1, RI_ALL_ONLINE },
- { 0x238c00, 1, RI_ALL_ONLINE },
- { 0x238c40, 1, RI_ALL_ONLINE },
- { 0x238c80, 1, RI_ALL_ONLINE },
- { 0x238cc0, 1, RI_ALL_ONLINE },
- { 0x238cc4, 1, RI_E2E3E3B0_ONLINE },
- { 0x238d00, 1, RI_ALL_ONLINE },
- { 0x238d40, 1, RI_ALL_ONLINE },
- { 0x238d80, 1, RI_ALL_ONLINE },
- { 0x238dc0, 1, RI_ALL_ONLINE },
- { 0x238e00, 1, RI_ALL_ONLINE },
- { 0x238e40, 1, RI_ALL_ONLINE },
- { 0x238e80, 1, RI_ALL_ONLINE },
- { 0x238e84, 1, RI_E2E3E3B0_ONLINE },
- { 0x238ec0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x238f00, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x238f40, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x238f80, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x238fc0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x238fc4, 2, RI_E2E3E3B0_ONLINE },
- { 0x238fd0, 6, RI_E2E3E3B0_ONLINE },
- { 0x238fe8, 2, RI_E3E3B0_ONLINE },
- { 0x239000, 1, RI_E2E3E3B0_ONLINE },
- { 0x239040, 3, RI_E2E3E3B0_ONLINE },
- { 0x23905c, 1, RI_E3E3B0_ONLINE },
- { 0x239064, 1, RI_E3B0_ONLINE },
- { 0x239080, 10, RI_E3B0_ONLINE },
- { 0x240000, 2, RI_ALL_ONLINE },
- { 0x280000, 65, RI_ALL_ONLINE },
- { 0x28014c, 2, RI_E1HE2E3E3B0_ONLINE },
- { 0x280200, 58, RI_ALL_ONLINE },
- { 0x280340, 4, RI_ALL_ONLINE },
- { 0x280380, 1, RI_E2E3E3B0_ONLINE },
- { 0x280388, 1, RI_E2E3E3B0_ONLINE },
- { 0x280390, 1, RI_E2E3E3B0_ONLINE },
- { 0x280398, 1, RI_E2E3E3B0_ONLINE },
- { 0x2803a0, 1, RI_E2E3E3B0_ONLINE },
- { 0x2803a8, 2, RI_E2E3E3B0_ONLINE },
- { 0x280404, 255, RI_E1E1H_OFFLINE },
- { 0x282000, 4, RI_ALL_ONLINE },
- { 0x282010, 2044, RI_ALL_OFFLINE },
- { 0x284000, 4, RI_E3E3B0_ONLINE },
- { 0x2a0000, 1, RI_ALL_ONLINE },
- { 0x2a0004, 5631, RI_ALL_OFFLINE },
- { 0x2a5800, 2560, RI_E1HE2E3E3B0_OFFLINE },
- { 0x2a8000, 1, RI_ALL_ONLINE },
- { 0x2a8004, 8191, RI_E1HE2E3E3B0_OFFLINE },
- { 0x2b0000, 1, RI_ALL_ONLINE },
- { 0x2b0004, 15, RI_E1H_OFFLINE },
- { 0x2b0040, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b0044, 239, RI_E1H_OFFLINE },
- { 0x2b0400, 1, RI_ALL_ONLINE },
- { 0x2b0404, 255, RI_E1H_OFFLINE },
- { 0x2b0800, 1, RI_ALL_ONLINE },
- { 0x2b0840, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b0c00, 1, RI_ALL_ONLINE },
- { 0x2b1000, 1, RI_ALL_ONLINE },
- { 0x2b1040, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b1400, 1, RI_ALL_ONLINE },
- { 0x2b1440, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b1480, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b14c0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b1800, 128, RI_ALL_OFFLINE },
- { 0x2b1c00, 128, RI_ALL_OFFLINE },
- { 0x2b2000, 1, RI_ALL_ONLINE },
- { 0x2b2400, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b2404, 5631, RI_E2E3E3B0_OFFLINE },
- { 0x2b8000, 1, RI_ALL_ONLINE },
- { 0x2b8040, 1, RI_ALL_ONLINE },
- { 0x2b8080, 1, RI_ALL_ONLINE },
- { 0x2b80c0, 1, RI_ALL_ONLINE },
- { 0x2b8100, 1, RI_ALL_ONLINE },
- { 0x2b8140, 1, RI_ALL_ONLINE },
- { 0x2b8180, 1, RI_ALL_ONLINE },
- { 0x2b81c0, 1, RI_ALL_ONLINE },
- { 0x2b8200, 1, RI_ALL_ONLINE },
- { 0x2b8240, 1, RI_ALL_ONLINE },
- { 0x2b8280, 1, RI_ALL_ONLINE },
- { 0x2b82c0, 1, RI_ALL_ONLINE },
- { 0x2b8300, 1, RI_ALL_ONLINE },
- { 0x2b8340, 1, RI_ALL_ONLINE },
- { 0x2b8380, 1, RI_ALL_ONLINE },
- { 0x2b83c0, 1, RI_ALL_ONLINE },
- { 0x2b8400, 1, RI_ALL_ONLINE },
- { 0x2b8440, 1, RI_ALL_ONLINE },
- { 0x2b8480, 1, RI_ALL_ONLINE },
- { 0x2b84c0, 1, RI_ALL_ONLINE },
- { 0x2b8500, 1, RI_ALL_ONLINE },
- { 0x2b8540, 1, RI_ALL_ONLINE },
- { 0x2b8580, 1, RI_ALL_ONLINE },
- { 0x2b85c0, 19, RI_E2E3E3B0_ONLINE },
- { 0x2b8800, 1, RI_ALL_ONLINE },
- { 0x2b8840, 1, RI_ALL_ONLINE },
- { 0x2b8880, 1, RI_ALL_ONLINE },
- { 0x2b88c0, 1, RI_ALL_ONLINE },
- { 0x2b8900, 1, RI_ALL_ONLINE },
- { 0x2b8940, 1, RI_ALL_ONLINE },
- { 0x2b8980, 1, RI_ALL_ONLINE },
- { 0x2b89c0, 1, RI_ALL_ONLINE },
- { 0x2b8a00, 1, RI_ALL_ONLINE },
- { 0x2b8a40, 1, RI_ALL_ONLINE },
- { 0x2b8a80, 1, RI_ALL_ONLINE },
- { 0x2b8ac0, 1, RI_ALL_ONLINE },
- { 0x2b8b00, 1, RI_ALL_ONLINE },
- { 0x2b8b40, 1, RI_ALL_ONLINE },
- { 0x2b8b80, 1, RI_ALL_ONLINE },
- { 0x2b8bc0, 1, RI_ALL_ONLINE },
- { 0x2b8c00, 1, RI_ALL_ONLINE },
- { 0x2b8c40, 1, RI_ALL_ONLINE },
- { 0x2b8c80, 1, RI_ALL_ONLINE },
- { 0x2b8cc0, 1, RI_ALL_ONLINE },
- { 0x2b8cc4, 1, RI_E2E3E3B0_ONLINE },
- { 0x2b8d00, 1, RI_ALL_ONLINE },
- { 0x2b8d40, 1, RI_ALL_ONLINE },
- { 0x2b8d80, 1, RI_ALL_ONLINE },
- { 0x2b8dc0, 1, RI_ALL_ONLINE },
- { 0x2b8e00, 1, RI_ALL_ONLINE },
- { 0x2b8e40, 1, RI_ALL_ONLINE },
- { 0x2b8e80, 1, RI_ALL_ONLINE },
- { 0x2b8e84, 1, RI_E2E3E3B0_ONLINE },
- { 0x2b8ec0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b8f00, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b8f40, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b8f80, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b8fc0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x2b8fc4, 2, RI_E2E3E3B0_ONLINE },
- { 0x2b8fd0, 6, RI_E2E3E3B0_ONLINE },
- { 0x2b8fe8, 2, RI_E3E3B0_ONLINE },
- { 0x2b9000, 1, RI_E2E3E3B0_ONLINE },
- { 0x2b9040, 3, RI_E2E3E3B0_ONLINE },
- { 0x2b905c, 1, RI_E3E3B0_ONLINE },
- { 0x2b9064, 1, RI_E3B0_ONLINE },
- { 0x2b9080, 10, RI_E3B0_ONLINE },
- { 0x2b9400, 14, RI_E2E3E3B0_ONLINE },
- { 0x2b943c, 19, RI_E2E3E3B0_ONLINE },
- { 0x2b9490, 10, RI_E2E3E3B0_ONLINE },
- { 0x2c0000, 2, RI_ALL_ONLINE },
- { 0x300000, 65, RI_ALL_ONLINE },
- { 0x30014c, 2, RI_E1HE2E3E3B0_ONLINE },
- { 0x300200, 58, RI_ALL_ONLINE },
- { 0x300340, 4, RI_ALL_ONLINE },
- { 0x300380, 1, RI_E2E3E3B0_ONLINE },
- { 0x300388, 1, RI_E2E3E3B0_ONLINE },
- { 0x300390, 1, RI_E2E3E3B0_ONLINE },
- { 0x300398, 1, RI_E2E3E3B0_ONLINE },
- { 0x3003a0, 1, RI_E2E3E3B0_ONLINE },
- { 0x3003a8, 2, RI_E2E3E3B0_ONLINE },
- { 0x300404, 255, RI_E1E1H_OFFLINE },
- { 0x302000, 4, RI_ALL_ONLINE },
- { 0x302010, 2044, RI_ALL_OFFLINE },
- { 0x304000, 4, RI_E3E3B0_ONLINE },
- { 0x320000, 1, RI_ALL_ONLINE },
- { 0x320004, 5631, RI_ALL_OFFLINE },
- { 0x325800, 2560, RI_E1HE2E3E3B0_OFFLINE },
- { 0x328000, 1, RI_ALL_ONLINE },
- { 0x328004, 8191, RI_E1HE2E3E3B0_OFFLINE },
- { 0x330000, 1, RI_ALL_ONLINE },
- { 0x330004, 15, RI_E1H_OFFLINE },
- { 0x330040, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x330044, 239, RI_E1H_OFFLINE },
- { 0x330400, 1, RI_ALL_ONLINE },
- { 0x330404, 255, RI_E1H_OFFLINE },
- { 0x330800, 1, RI_ALL_ONLINE },
- { 0x330840, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x330c00, 1, RI_ALL_ONLINE },
- { 0x331000, 1, RI_ALL_ONLINE },
- { 0x331040, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x331400, 1, RI_ALL_ONLINE },
- { 0x331440, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x331480, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x3314c0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x331800, 128, RI_ALL_OFFLINE },
- { 0x331c00, 128, RI_ALL_OFFLINE },
- { 0x332000, 1, RI_ALL_ONLINE },
- { 0x332400, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x332404, 5631, RI_E2E3E3B0_OFFLINE },
- { 0x338000, 1, RI_ALL_ONLINE },
- { 0x338040, 1, RI_ALL_ONLINE },
- { 0x338080, 1, RI_ALL_ONLINE },
- { 0x3380c0, 1, RI_ALL_ONLINE },
- { 0x338100, 1, RI_ALL_ONLINE },
- { 0x338140, 1, RI_ALL_ONLINE },
- { 0x338180, 1, RI_ALL_ONLINE },
- { 0x3381c0, 1, RI_ALL_ONLINE },
- { 0x338200, 1, RI_ALL_ONLINE },
- { 0x338240, 1, RI_ALL_ONLINE },
- { 0x338280, 1, RI_ALL_ONLINE },
- { 0x3382c0, 1, RI_ALL_ONLINE },
- { 0x338300, 1, RI_ALL_ONLINE },
- { 0x338340, 1, RI_ALL_ONLINE },
- { 0x338380, 1, RI_ALL_ONLINE },
- { 0x3383c0, 1, RI_ALL_ONLINE },
- { 0x338400, 1, RI_ALL_ONLINE },
- { 0x338440, 1, RI_ALL_ONLINE },
- { 0x338480, 1, RI_ALL_ONLINE },
- { 0x3384c0, 1, RI_ALL_ONLINE },
- { 0x338500, 1, RI_ALL_ONLINE },
- { 0x338540, 1, RI_ALL_ONLINE },
- { 0x338580, 1, RI_ALL_ONLINE },
- { 0x3385c0, 19, RI_E2E3E3B0_ONLINE },
- { 0x338800, 1, RI_ALL_ONLINE },
- { 0x338840, 1, RI_ALL_ONLINE },
- { 0x338880, 1, RI_ALL_ONLINE },
- { 0x3388c0, 1, RI_ALL_ONLINE },
- { 0x338900, 1, RI_ALL_ONLINE },
- { 0x338940, 1, RI_ALL_ONLINE },
- { 0x338980, 1, RI_ALL_ONLINE },
- { 0x3389c0, 1, RI_ALL_ONLINE },
- { 0x338a00, 1, RI_ALL_ONLINE },
- { 0x338a40, 1, RI_ALL_ONLINE },
- { 0x338a80, 1, RI_ALL_ONLINE },
- { 0x338ac0, 1, RI_ALL_ONLINE },
- { 0x338b00, 1, RI_ALL_ONLINE },
- { 0x338b40, 1, RI_ALL_ONLINE },
- { 0x338b80, 1, RI_ALL_ONLINE },
- { 0x338bc0, 1, RI_ALL_ONLINE },
- { 0x338c00, 1, RI_ALL_ONLINE },
- { 0x338c40, 1, RI_ALL_ONLINE },
- { 0x338c80, 1, RI_ALL_ONLINE },
- { 0x338cc0, 1, RI_ALL_ONLINE },
- { 0x338cc4, 1, RI_E2E3E3B0_ONLINE },
- { 0x338d00, 1, RI_ALL_ONLINE },
- { 0x338d40, 1, RI_ALL_ONLINE },
- { 0x338d80, 1, RI_ALL_ONLINE },
- { 0x338dc0, 1, RI_ALL_ONLINE },
- { 0x338e00, 1, RI_ALL_ONLINE },
- { 0x338e40, 1, RI_ALL_ONLINE },
- { 0x338e80, 1, RI_ALL_ONLINE },
- { 0x338e84, 1, RI_E2E3E3B0_ONLINE },
- { 0x338ec0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x338f00, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x338f40, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x338f80, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x338fc0, 1, RI_E1HE2E3E3B0_ONLINE },
- { 0x338fc4, 2, RI_E2E3E3B0_ONLINE },
- { 0x338fd0, 6, RI_E2E3E3B0_ONLINE },
- { 0x338fe8, 2, RI_E3E3B0_ONLINE },
- { 0x339000, 1, RI_E2E3E3B0_ONLINE },
- { 0x339040, 3, RI_E2E3E3B0_ONLINE },
- { 0x33905c, 1, RI_E3E3B0_ONLINE },
- { 0x339064, 1, RI_E3B0_ONLINE },
- { 0x339080, 10, RI_E3B0_ONLINE },
- { 0x340000, 2, RI_ALL_ONLINE },
+ { 0x2000, 1, 0x1f, 0xfff},
+ { 0x2004, 1, 0x1f, 0x1fff},
+ { 0x2008, 25, 0x1f, 0xfff},
+ { 0x206c, 1, 0x1f, 0x1fff},
+ { 0x2070, 313, 0x1f, 0xfff},
+ { 0x2800, 103, 0x1f, 0xfff},
+ { 0x3000, 287, 0x1f, 0xfff},
+ { 0x3800, 331, 0x1f, 0xfff},
+ { 0x8800, 6, 0x1f, 0x924},
+ { 0x8818, 1, 0x1e, 0x924},
+ { 0x9000, 4, 0x1c, 0x924},
+ { 0x9010, 7, 0x1c, 0xfff},
+ { 0x902c, 1, 0x1c, 0x924},
+ { 0x9030, 1, 0x1c, 0xfff},
+ { 0x9034, 13, 0x1c, 0x924},
+ { 0x9068, 16, 0x1c, 0xfff},
+ { 0x90a8, 98, 0x1c, 0x924},
+ { 0x9230, 2, 0x1c, 0xfff},
+ { 0x9238, 3, 0x1c, 0x924},
+ { 0x9244, 1, 0x1c, 0xfff},
+ { 0x9248, 1, 0x1c, 0x924},
+ { 0x924c, 1, 0x4, 0x924},
+ { 0x9250, 16, 0x1c, 0x924},
+ { 0x92a8, 2, 0x1c, 0x1fff},
+ { 0x92b4, 1, 0x1c, 0x1fff},
+ { 0x9400, 33, 0x1c, 0x924},
+ { 0x9484, 5, 0x18, 0x924},
+ { 0xa000, 27, 0x1f, 0x924},
+ { 0xa06c, 1, 0x3, 0x924},
+ { 0xa070, 2, 0x1f, 0x924},
+ { 0xa078, 1, 0x1f, 0x1fff},
+ { 0xa07c, 31, 0x1f, 0x924},
+ { 0xa0f8, 1, 0x1f, 0x1fff},
+ { 0xa0fc, 3, 0x1f, 0x924},
+ { 0xa108, 1, 0x1f, 0x1fff},
+ { 0xa10c, 3, 0x1f, 0x924},
+ { 0xa118, 1, 0x1f, 0x1fff},
+ { 0xa11c, 28, 0x1f, 0x924},
+ { 0xa18c, 4, 0x3, 0x924},
+ { 0xa19c, 3, 0x1f, 0x924},
+ { 0xa1a8, 1, 0x1f, 0x1fff},
+ { 0xa1ac, 3, 0x1f, 0x924},
+ { 0xa1b8, 1, 0x1f, 0x1fff},
+ { 0xa1bc, 54, 0x1f, 0x924},
+ { 0xa294, 2, 0x3, 0x924},
+ { 0xa29c, 2, 0x1f, 0x924},
+ { 0xa2a4, 2, 0x7, 0x924},
+ { 0xa2ac, 2, 0x1f, 0x924},
+ { 0xa2b4, 1, 0x1f, 0x1fff},
+ { 0xa2b8, 49, 0x1f, 0x924},
+ { 0xa38c, 2, 0x1f, 0x1fff},
+ { 0xa398, 1, 0x1f, 0x1fff},
+ { 0xa39c, 7, 0x1e, 0x924},
+ { 0xa3b8, 2, 0x18, 0x924},
+ { 0xa3c0, 1, 0x1e, 0x924},
+ { 0xa3c4, 1, 0x1e, 0xfff},
+ { 0xa3c8, 1, 0x1e, 0x924},
+ { 0xa3d0, 1, 0x1e, 0x924},
+ { 0xa3d8, 1, 0x1e, 0x924},
+ { 0xa3e0, 1, 0x1e, 0x924},
+ { 0xa3e8, 1, 0x1e, 0x924},
+ { 0xa3f0, 1, 0x1e, 0x924},
+ { 0xa3f8, 1, 0x1e, 0x924},
+ { 0xa400, 1, 0x1f, 0x924},
+ { 0xa404, 1, 0x1f, 0xfff},
+ { 0xa408, 2, 0x1f, 0x1fff},
+ { 0xa410, 7, 0x1f, 0x924},
+ { 0xa42c, 12, 0x1f, 0xfff},
+ { 0xa45c, 1, 0x1f, 0x924},
+ { 0xa460, 1, 0x1f, 0x1924},
+ { 0xa464, 15, 0x1f, 0x924},
+ { 0xa4a0, 1, 0x7, 0x924},
+ { 0xa4a4, 2, 0x1f, 0x924},
+ { 0xa4ac, 2, 0x3, 0x924},
+ { 0xa4b4, 1, 0x7, 0x924},
+ { 0xa4b8, 2, 0x3, 0x924},
+ { 0xa4c0, 3, 0x1f, 0x924},
+ { 0xa4cc, 5, 0x3, 0x924},
+ { 0xa4e0, 3, 0x1f, 0x924},
+ { 0xa4fc, 2, 0x1f, 0x924},
+ { 0xa504, 1, 0x3, 0x924},
+ { 0xa508, 3, 0x1f, 0x924},
+ { 0xa518, 1, 0x1f, 0x924},
+ { 0xa520, 1, 0x1f, 0x924},
+ { 0xa528, 1, 0x1f, 0x924},
+ { 0xa530, 1, 0x1f, 0x924},
+ { 0xa538, 1, 0x1f, 0x924},
+ { 0xa540, 1, 0x1f, 0x924},
+ { 0xa548, 1, 0x3, 0x924},
+ { 0xa550, 1, 0x3, 0x924},
+ { 0xa558, 1, 0x3, 0x924},
+ { 0xa560, 1, 0x3, 0x924},
+ { 0xa568, 1, 0x3, 0x924},
+ { 0xa570, 1, 0x1f, 0x924},
+ { 0xa580, 1, 0x1f, 0x1fff},
+ { 0xa590, 1, 0x1f, 0x1fff},
+ { 0xa5a0, 1, 0x7, 0x924},
+ { 0xa5c0, 1, 0x1f, 0x924},
+ { 0xa5e0, 1, 0x1e, 0x924},
+ { 0xa5e8, 1, 0x1e, 0x924},
+ { 0xa5f0, 1, 0x1e, 0x924},
+ { 0xa5f8, 1, 0x6, 0x924},
+ { 0xa5fc, 1, 0x1e, 0x924},
+ { 0xa600, 5, 0x1e, 0xfff},
+ { 0xa614, 1, 0x1e, 0x924},
+ { 0xa618, 1, 0x1e, 0xfff},
+ { 0xa61c, 1, 0x1e, 0x924},
+ { 0xa620, 6, 0x1c, 0x924},
+ { 0xa638, 20, 0x4, 0x924},
+ { 0xa688, 35, 0x1c, 0x924},
+ { 0xa714, 1, 0x1c, 0xfff},
+ { 0xa718, 2, 0x1c, 0x924},
+ { 0xa720, 1, 0x1c, 0xfff},
+ { 0xa724, 3, 0x1c, 0x924},
+ { 0xa730, 1, 0x4, 0x924},
+ { 0xa734, 2, 0x1c, 0x924},
+ { 0xa73c, 4, 0x4, 0x924},
+ { 0xa74c, 1, 0x1c, 0x924},
+ { 0xa750, 1, 0x1c, 0xfff},
+ { 0xa754, 3, 0x1c, 0x924},
+ { 0xa760, 5, 0x4, 0x924},
+ { 0xa774, 7, 0x1c, 0x924},
+ { 0xa790, 15, 0x4, 0x924},
+ { 0xa7cc, 4, 0x1c, 0x924},
+ { 0xa7e0, 6, 0x18, 0x924},
+ { 0xa800, 18, 0x4, 0x924},
+ { 0xa848, 33, 0x1c, 0x924},
+ { 0xa8cc, 2, 0x18, 0x924},
+ { 0xa8d4, 4, 0x1c, 0x924},
+ { 0xa8e4, 1, 0x18, 0x924},
+ { 0xa8e8, 1, 0x1c, 0x924},
+ { 0xa8f0, 1, 0x1c, 0x924},
+ { 0xa8f8, 30, 0x18, 0x924},
+ { 0xa974, 73, 0x18, 0x924},
+ { 0xac30, 1, 0x18, 0x924},
+ { 0xac40, 1, 0x18, 0x924},
+ { 0xac50, 1, 0x18, 0x924},
+ { 0xac60, 1, 0x10, 0x924},
+ { 0x10000, 9, 0x1f, 0x924},
+ { 0x10024, 1, 0x7, 0x924},
+ { 0x10028, 5, 0x1f, 0x924},
+ { 0x1003c, 6, 0x7, 0x924},
+ { 0x10054, 20, 0x1f, 0x924},
+ { 0x100a4, 4, 0x7, 0x924},
+ { 0x100b4, 11, 0x1f, 0x924},
+ { 0x100e0, 4, 0x7, 0x924},
+ { 0x100f0, 8, 0x1f, 0x924},
+ { 0x10110, 6, 0x7, 0x924},
+ { 0x10128, 110, 0x1f, 0x924},
+ { 0x102e0, 4, 0x7, 0x924},
+ { 0x102f0, 18, 0x1f, 0x924},
+ { 0x10338, 20, 0x7, 0x924},
+ { 0x10388, 10, 0x1f, 0x924},
+ { 0x103d0, 2, 0x3, 0x1fff},
+ { 0x103dc, 1, 0x3, 0x1fff},
+ { 0x10400, 6, 0x7, 0x924},
+ { 0x10418, 1, 0x1f, 0xfff},
+ { 0x1041c, 1, 0x1f, 0x924},
+ { 0x10420, 1, 0x1f, 0xfff},
+ { 0x10424, 1, 0x1f, 0x924},
+ { 0x10428, 1, 0x1f, 0xfff},
+ { 0x1042c, 1, 0x1f, 0x924},
+ { 0x10430, 10, 0x7, 0x924},
+ { 0x10458, 2, 0x1f, 0x924},
+ { 0x10460, 1, 0x1f, 0xfff},
+ { 0x10464, 4, 0x1f, 0x924},
+ { 0x10474, 1, 0x1f, 0xfff},
+ { 0x10478, 14, 0x1f, 0x924},
+ { 0x104b0, 12, 0x7, 0x924},
+ { 0x104e0, 1, 0x1f, 0xfff},
+ { 0x104e8, 1, 0x1f, 0x924},
+ { 0x104ec, 1, 0x1f, 0xfff},
+ { 0x104f4, 1, 0x1f, 0x924},
+ { 0x104f8, 1, 0x1f, 0xfff},
+ { 0x10500, 2, 0x1f, 0x924},
+ { 0x10508, 1, 0x1f, 0xfff},
+ { 0x1050c, 9, 0x1f, 0x924},
+ { 0x10530, 1, 0x1f, 0xfff},
+ { 0x10534, 1, 0x1f, 0x924},
+ { 0x10538, 1, 0x1f, 0xfff},
+ { 0x1053c, 3, 0x1f, 0x924},
+ { 0x10548, 1, 0x1f, 0xfff},
+ { 0x1054c, 3, 0x1f, 0x924},
+ { 0x10558, 1, 0x1f, 0xfff},
+ { 0x1055c, 123, 0x1f, 0x924},
+ { 0x10750, 2, 0x7, 0x924},
+ { 0x10760, 2, 0x7, 0x924},
+ { 0x10770, 2, 0x7, 0x924},
+ { 0x10780, 2, 0x7, 0x924},
+ { 0x10790, 2, 0x1f, 0x924},
+ { 0x107a0, 2, 0x7, 0x924},
+ { 0x107b0, 2, 0x7, 0x924},
+ { 0x107c0, 2, 0x7, 0x924},
+ { 0x107d0, 2, 0x7, 0x924},
+ { 0x107e0, 2, 0x1f, 0x924},
+ { 0x10880, 2, 0x1f, 0x924},
+ { 0x10900, 2, 0x1f, 0x924},
+ { 0x16000, 1, 0x6, 0x924},
+ { 0x16004, 25, 0x1e, 0x924},
+ { 0x16070, 8, 0x1e, 0x924},
+ { 0x16090, 4, 0xe, 0x924},
+ { 0x160a0, 6, 0x1e, 0x924},
+ { 0x160c0, 7, 0x1e, 0x924},
+ { 0x160dc, 2, 0x6, 0x924},
+ { 0x160e4, 6, 0x1e, 0x924},
+ { 0x160fc, 4, 0x1e, 0x1fff},
+ { 0x1610c, 2, 0x6, 0x924},
+ { 0x16114, 6, 0x1e, 0x924},
+ { 0x16140, 48, 0x1e, 0x1fff},
+ { 0x16204, 5, 0x1e, 0x924},
+ { 0x18000, 1, 0x1e, 0x924},
+ { 0x18008, 1, 0x1e, 0x924},
+ { 0x18010, 35, 0x1c, 0x924},
+ { 0x180a4, 2, 0x1c, 0x924},
+ { 0x180c0, 9, 0x1c, 0x924},
+ { 0x180e4, 1, 0xc, 0x924},
+ { 0x180e8, 2, 0x1c, 0x924},
+ { 0x180f0, 1, 0xc, 0x924},
+ { 0x180f4, 79, 0x1c, 0x924},
+ { 0x18230, 1, 0xc, 0x924},
+ { 0x18234, 2, 0x1c, 0x924},
+ { 0x1823c, 1, 0xc, 0x924},
+ { 0x18240, 13, 0x1c, 0x924},
+ { 0x18274, 1, 0x4, 0x924},
+ { 0x18278, 12, 0x1c, 0x924},
+ { 0x182a8, 1, 0x1c, 0xfff},
+ { 0x182ac, 3, 0x1c, 0x924},
+ { 0x182b8, 1, 0x1c, 0xfff},
+ { 0x182bc, 19, 0x1c, 0x924},
+ { 0x18308, 1, 0x1c, 0xfff},
+ { 0x1830c, 3, 0x1c, 0x924},
+ { 0x18318, 1, 0x1c, 0xfff},
+ { 0x1831c, 7, 0x1c, 0x924},
+ { 0x18338, 1, 0x1c, 0xfff},
+ { 0x1833c, 3, 0x1c, 0x924},
+ { 0x18348, 1, 0x1c, 0xfff},
+ { 0x1834c, 28, 0x1c, 0x924},
+ { 0x183bc, 2, 0x1c, 0x1fff},
+ { 0x183c8, 3, 0x1c, 0x1fff},
+ { 0x183d8, 1, 0x1c, 0x1fff},
+ { 0x18440, 48, 0x1c, 0x1fff},
+ { 0x18500, 15, 0x1c, 0x924},
+ { 0x18570, 1, 0x18, 0xfff},
+ { 0x18574, 1, 0x18, 0x924},
+ { 0x18578, 1, 0x18, 0xfff},
+ { 0x1857c, 4, 0x18, 0x924},
+ { 0x1858c, 1, 0x18, 0xfff},
+ { 0x18590, 1, 0x18, 0x924},
+ { 0x18594, 1, 0x18, 0xfff},
+ { 0x18598, 32, 0x18, 0x924},
+ { 0x18618, 5, 0x10, 0x924},
+ { 0x1862c, 4, 0x10, 0xfff},
+ { 0x1863c, 16, 0x10, 0x924},
+ { 0x18680, 44, 0x10, 0x924},
+ { 0x18748, 12, 0x10, 0x924},
+ { 0x18788, 1, 0x10, 0x924},
+ { 0x1879c, 6, 0x10, 0x924},
+ { 0x187c4, 51, 0x10, 0x924},
+ { 0x18a00, 48, 0x10, 0x924},
+ { 0x20000, 24, 0x1f, 0x924},
+ { 0x20060, 8, 0x1f, 0x9e4},
+ { 0x20080, 94, 0x1f, 0x924},
+ { 0x201f8, 1, 0x3, 0x924},
+ { 0x201fc, 1, 0x1f, 0x924},
+ { 0x20200, 1, 0x3, 0x924},
+ { 0x20204, 1, 0x1f, 0x924},
+ { 0x20208, 1, 0x3, 0x924},
+ { 0x2020c, 4, 0x1f, 0x924},
+ { 0x2021c, 11, 0x1f, 0xfff},
+ { 0x20248, 24, 0x1f, 0x924},
+ { 0x202b8, 2, 0x1f, 0x1fff},
+ { 0x202c4, 1, 0x1f, 0x1fff},
+ { 0x202c8, 1, 0x1c, 0x924},
+ { 0x202d8, 4, 0x1c, 0x924},
+ { 0x202f0, 1, 0x10, 0x924},
+ { 0x20400, 1, 0x1f, 0x924},
+ { 0x20404, 1, 0x1f, 0xfff},
+ { 0x2040c, 2, 0x1f, 0xfff},
+ { 0x20414, 2, 0x1f, 0x924},
+ { 0x2041c, 2, 0x1f, 0xfff},
+ { 0x20424, 2, 0x1f, 0x924},
+ { 0x2042c, 18, 0x1e, 0x924},
+ { 0x20480, 1, 0x1f, 0x924},
+ { 0x20500, 1, 0x1f, 0x924},
+ { 0x20600, 1, 0x1f, 0x924},
+ { 0x28000, 1, 0x1f, 0x9e4},
+ { 0x28004, 255, 0x1f, 0x180},
+ { 0x28400, 1, 0x1f, 0x1c0},
+ { 0x28404, 255, 0x1f, 0x180},
+ { 0x28800, 1, 0x1f, 0x1c0},
+ { 0x28804, 255, 0x1f, 0x180},
+ { 0x28c00, 1, 0x1f, 0x1c0},
+ { 0x28c04, 255, 0x1f, 0x180},
+ { 0x29000, 1, 0x1f, 0x1c0},
+ { 0x29004, 255, 0x1f, 0x180},
+ { 0x29400, 1, 0x1f, 0x1c0},
+ { 0x29404, 255, 0x1f, 0x180},
+ { 0x29800, 1, 0x1f, 0x1c0},
+ { 0x29804, 255, 0x1f, 0x180},
+ { 0x29c00, 1, 0x1f, 0x1c0},
+ { 0x29c04, 255, 0x1f, 0x180},
+ { 0x2a000, 1, 0x1f, 0x1c0},
+ { 0x2a004, 255, 0x1f, 0x180},
+ { 0x2a400, 1, 0x1f, 0x1c0},
+ { 0x2a404, 255, 0x1f, 0x180},
+ { 0x2a800, 1, 0x1f, 0x1c0},
+ { 0x2a804, 255, 0x1f, 0x180},
+ { 0x2ac00, 1, 0x1f, 0x1c0},
+ { 0x2ac04, 255, 0x1f, 0x180},
+ { 0x2b000, 1, 0x1f, 0x1c0},
+ { 0x2b004, 255, 0x1f, 0x180},
+ { 0x2b400, 1, 0x1f, 0x1c0},
+ { 0x2b404, 255, 0x1f, 0x180},
+ { 0x2b800, 1, 0x1f, 0x1c0},
+ { 0x2b804, 255, 0x1f, 0x180},
+ { 0x2bc00, 1, 0x1f, 0x1c0},
+ { 0x2bc04, 255, 0x1f, 0x180},
+ { 0x2c000, 1, 0x1f, 0x1c0},
+ { 0x2c004, 255, 0x1f, 0x180},
+ { 0x2c400, 1, 0x1f, 0x1c0},
+ { 0x2c404, 255, 0x1f, 0x180},
+ { 0x2c800, 1, 0x1f, 0x1c0},
+ { 0x2c804, 255, 0x1f, 0x180},
+ { 0x2cc00, 1, 0x1f, 0x1c0},
+ { 0x2cc04, 255, 0x1f, 0x180},
+ { 0x2d000, 1, 0x1f, 0x1c0},
+ { 0x2d004, 255, 0x1f, 0x180},
+ { 0x2d400, 1, 0x1f, 0x1c0},
+ { 0x2d404, 255, 0x1f, 0x180},
+ { 0x2d800, 1, 0x1f, 0x1c0},
+ { 0x2d804, 255, 0x1f, 0x180},
+ { 0x2dc00, 1, 0x1f, 0x1c0},
+ { 0x2dc04, 255, 0x1f, 0x180},
+ { 0x2e000, 1, 0x1f, 0x1c0},
+ { 0x2e004, 255, 0x1f, 0x180},
+ { 0x2e400, 1, 0x1f, 0x1c0},
+ { 0x2e404, 255, 0x1f, 0x180},
+ { 0x2e800, 1, 0x1f, 0x1c0},
+ { 0x2e804, 255, 0x1f, 0x180},
+ { 0x2ec00, 1, 0x1f, 0x1c0},
+ { 0x2ec04, 255, 0x1f, 0x180},
+ { 0x2f000, 1, 0x1f, 0x1c0},
+ { 0x2f004, 255, 0x1f, 0x180},
+ { 0x2f400, 1, 0x1f, 0x1c0},
+ { 0x2f404, 255, 0x1f, 0x180},
+ { 0x2f800, 1, 0x1f, 0x1c0},
+ { 0x2f804, 255, 0x1f, 0x180},
+ { 0x2fc00, 1, 0x1f, 0x1c0},
+ { 0x2fc04, 255, 0x1f, 0x180},
+ { 0x30000, 1, 0x1f, 0x9e4},
+ { 0x30004, 255, 0x1f, 0x180},
+ { 0x30400, 1, 0x1f, 0x1c0},
+ { 0x30404, 255, 0x1f, 0x180},
+ { 0x30800, 1, 0x1f, 0x1c0},
+ { 0x30804, 255, 0x1f, 0x180},
+ { 0x30c00, 1, 0x1f, 0x1c0},
+ { 0x30c04, 255, 0x1f, 0x180},
+ { 0x31000, 1, 0x1f, 0x1c0},
+ { 0x31004, 255, 0x1f, 0x180},
+ { 0x31400, 1, 0x1f, 0x1c0},
+ { 0x31404, 255, 0x1f, 0x180},
+ { 0x31800, 1, 0x1f, 0x1c0},
+ { 0x31804, 255, 0x1f, 0x180},
+ { 0x31c00, 1, 0x1f, 0x1c0},
+ { 0x31c04, 255, 0x1f, 0x180},
+ { 0x32000, 1, 0x1f, 0x1c0},
+ { 0x32004, 255, 0x1f, 0x180},
+ { 0x32400, 1, 0x1f, 0x1c0},
+ { 0x32404, 255, 0x1f, 0x180},
+ { 0x32800, 1, 0x1f, 0x1c0},
+ { 0x32804, 255, 0x1f, 0x180},
+ { 0x32c00, 1, 0x1f, 0x1c0},
+ { 0x32c04, 255, 0x1f, 0x180},
+ { 0x33000, 1, 0x1f, 0x1c0},
+ { 0x33004, 255, 0x1f, 0x180},
+ { 0x33400, 1, 0x1f, 0x1c0},
+ { 0x33404, 255, 0x1f, 0x180},
+ { 0x33800, 1, 0x1f, 0x1c0},
+ { 0x33804, 255, 0x1f, 0x180},
+ { 0x33c00, 1, 0x1f, 0x1c0},
+ { 0x33c04, 255, 0x1f, 0x180},
+ { 0x34000, 1, 0x1f, 0x1c0},
+ { 0x34004, 255, 0x1f, 0x180},
+ { 0x34400, 1, 0x1f, 0x1c0},
+ { 0x34404, 255, 0x1f, 0x180},
+ { 0x34800, 1, 0x1f, 0x1c0},
+ { 0x34804, 255, 0x1f, 0x180},
+ { 0x34c00, 1, 0x1f, 0x1c0},
+ { 0x34c04, 255, 0x1f, 0x180},
+ { 0x35000, 1, 0x1f, 0x1c0},
+ { 0x35004, 255, 0x1f, 0x180},
+ { 0x35400, 1, 0x1f, 0x1c0},
+ { 0x35404, 255, 0x1f, 0x180},
+ { 0x35800, 1, 0x1f, 0x1c0},
+ { 0x35804, 255, 0x1f, 0x180},
+ { 0x35c00, 1, 0x1f, 0x1c0},
+ { 0x35c04, 255, 0x1f, 0x180},
+ { 0x36000, 1, 0x1f, 0x1c0},
+ { 0x36004, 255, 0x1f, 0x180},
+ { 0x36400, 1, 0x1f, 0x1c0},
+ { 0x36404, 255, 0x1f, 0x180},
+ { 0x36800, 1, 0x1f, 0x1c0},
+ { 0x36804, 255, 0x1f, 0x180},
+ { 0x36c00, 1, 0x1f, 0x1c0},
+ { 0x36c04, 255, 0x1f, 0x180},
+ { 0x37000, 1, 0x1f, 0x1c0},
+ { 0x37004, 255, 0x1f, 0x180},
+ { 0x37400, 1, 0x1f, 0x1c0},
+ { 0x37404, 255, 0x1f, 0x180},
+ { 0x37800, 1, 0x1f, 0x1c0},
+ { 0x37804, 255, 0x1f, 0x180},
+ { 0x37c00, 1, 0x1f, 0x1c0},
+ { 0x37c04, 255, 0x1f, 0x180},
+ { 0x38000, 1, 0x1f, 0x1c0},
+ { 0x38004, 255, 0x1f, 0x180},
+ { 0x38400, 1, 0x1f, 0x1c0},
+ { 0x38404, 255, 0x1f, 0x180},
+ { 0x38800, 1, 0x1f, 0x1c0},
+ { 0x38804, 255, 0x1f, 0x180},
+ { 0x38c00, 1, 0x1f, 0x1c0},
+ { 0x38c04, 255, 0x1f, 0x180},
+ { 0x39000, 1, 0x1f, 0x1c0},
+ { 0x39004, 255, 0x1f, 0x180},
+ { 0x39400, 1, 0x1f, 0x1c0},
+ { 0x39404, 255, 0x1f, 0x180},
+ { 0x39800, 1, 0x1f, 0x1c0},
+ { 0x39804, 255, 0x1f, 0x180},
+ { 0x39c00, 1, 0x1f, 0x1c0},
+ { 0x39c04, 255, 0x1f, 0x180},
+ { 0x3a000, 1, 0x1f, 0x1c0},
+ { 0x3a004, 255, 0x1f, 0x180},
+ { 0x3a400, 1, 0x1f, 0x1c0},
+ { 0x3a404, 255, 0x1f, 0x180},
+ { 0x3a800, 1, 0x1f, 0x1c0},
+ { 0x3a804, 255, 0x1f, 0x180},
+ { 0x3ac00, 1, 0x1f, 0x1c0},
+ { 0x3ac04, 255, 0x1f, 0x180},
+ { 0x3b000, 1, 0x1f, 0x1c0},
+ { 0x3b004, 255, 0x1f, 0x180},
+ { 0x3b400, 1, 0x1f, 0x1c0},
+ { 0x3b404, 255, 0x1f, 0x180},
+ { 0x3b800, 1, 0x1f, 0x1c0},
+ { 0x3b804, 255, 0x1f, 0x180},
+ { 0x3bc00, 1, 0x1f, 0x1c0},
+ { 0x3bc04, 255, 0x1f, 0x180},
+ { 0x3c000, 1, 0x1f, 0x1c0},
+ { 0x3c004, 255, 0x1f, 0x180},
+ { 0x3c400, 1, 0x1f, 0x1c0},
+ { 0x3c404, 255, 0x1f, 0x180},
+ { 0x3c800, 1, 0x1f, 0x1c0},
+ { 0x3c804, 255, 0x1f, 0x180},
+ { 0x3cc00, 1, 0x1f, 0x1c0},
+ { 0x3cc04, 255, 0x1f, 0x180},
+ { 0x3d000, 1, 0x1f, 0x1c0},
+ { 0x3d004, 255, 0x1f, 0x180},
+ { 0x3d400, 1, 0x1f, 0x1c0},
+ { 0x3d404, 255, 0x1f, 0x180},
+ { 0x3d800, 1, 0x1f, 0x1c0},
+ { 0x3d804, 255, 0x1f, 0x180},
+ { 0x3dc00, 1, 0x1f, 0x1c0},
+ { 0x3dc04, 255, 0x1f, 0x180},
+ { 0x3e000, 1, 0x1f, 0x1c0},
+ { 0x3e004, 255, 0x1f, 0x180},
+ { 0x3e400, 1, 0x1f, 0x1c0},
+ { 0x3e404, 255, 0x1f, 0x180},
+ { 0x3e800, 1, 0x1f, 0x1c0},
+ { 0x3e804, 255, 0x1f, 0x180},
+ { 0x3ec00, 1, 0x1f, 0x1c0},
+ { 0x3ec04, 255, 0x1f, 0x180},
+ { 0x3f000, 1, 0x1f, 0x1c0},
+ { 0x3f004, 255, 0x1f, 0x180},
+ { 0x3f400, 1, 0x1f, 0x1c0},
+ { 0x3f404, 255, 0x1f, 0x180},
+ { 0x3f800, 1, 0x1f, 0x1c0},
+ { 0x3f804, 255, 0x1f, 0x180},
+ { 0x3fc00, 1, 0x1f, 0x1c0},
+ { 0x3fc04, 255, 0x1f, 0x180},
+ { 0x40000, 85, 0x1f, 0x924},
+ { 0x40154, 13, 0x1f, 0xfff},
+ { 0x40198, 2, 0x1f, 0x1fff},
+ { 0x401a4, 1, 0x1f, 0x1fff},
+ { 0x401a8, 8, 0x1e, 0x924},
+ { 0x401c8, 1, 0x2, 0x924},
+ { 0x401cc, 2, 0x1e, 0x924},
+ { 0x401d4, 2, 0x1c, 0x924},
+ { 0x40200, 4, 0x1f, 0x924},
+ { 0x40220, 6, 0x1c, 0x924},
+ { 0x40238, 8, 0xc, 0x924},
+ { 0x40258, 4, 0x1c, 0x924},
+ { 0x40268, 2, 0x18, 0x924},
+ { 0x40270, 17, 0x10, 0x924},
+ { 0x40400, 43, 0x1f, 0x924},
+ { 0x404bc, 2, 0x1f, 0x1fff},
+ { 0x404c8, 1, 0x1f, 0x1fff},
+ { 0x404cc, 3, 0x1e, 0x924},
+ { 0x404e0, 1, 0x1c, 0x924},
+ { 0x40500, 2, 0x1f, 0x924},
+ { 0x40510, 2, 0x1f, 0x924},
+ { 0x40520, 2, 0x1f, 0x924},
+ { 0x40530, 2, 0x1f, 0x924},
+ { 0x40540, 2, 0x1f, 0x924},
+ { 0x40550, 10, 0x1c, 0x924},
+ { 0x40610, 2, 0x1c, 0x924},
+ { 0x42000, 164, 0x1f, 0x924},
+ { 0x422b0, 2, 0x1f, 0x1fff},
+ { 0x422bc, 1, 0x1f, 0x1fff},
+ { 0x422c0, 4, 0x1c, 0x924},
+ { 0x422d4, 5, 0x1e, 0x924},
+ { 0x422e8, 1, 0x1c, 0x924},
+ { 0x42400, 49, 0x1f, 0x924},
+ { 0x424c8, 32, 0x1f, 0x924},
+ { 0x42548, 1, 0x1f, 0xfff},
+ { 0x4254c, 1, 0x1f, 0x924},
+ { 0x42550, 1, 0x1f, 0xfff},
+ { 0x42554, 1, 0x1f, 0x924},
+ { 0x42558, 1, 0x1f, 0xfff},
+ { 0x4255c, 1, 0x1f, 0x924},
+ { 0x42568, 2, 0x1f, 0x924},
+ { 0x42640, 5, 0x1c, 0x924},
+ { 0x42800, 1, 0x1f, 0x924},
+ { 0x50000, 1, 0x1f, 0x1fff},
+ { 0x50004, 19, 0x1f, 0x924},
+ { 0x50050, 8, 0x1f, 0x93c},
+ { 0x50070, 60, 0x1f, 0x924},
+ { 0x50160, 8, 0x1f, 0xfff},
+ { 0x50180, 20, 0x1f, 0x924},
+ { 0x501e0, 2, 0x1f, 0x1fff},
+ { 0x501ec, 1, 0x1f, 0x1fff},
+ { 0x501f0, 4, 0x1e, 0x924},
+ { 0x50200, 1, 0x1f, 0x924},
+ { 0x50204, 1, 0x1f, 0xfff},
+ { 0x5020c, 2, 0x1f, 0xfff},
+ { 0x50214, 2, 0x1f, 0x924},
+ { 0x5021c, 1, 0x1f, 0xfff},
+ { 0x50220, 2, 0x1f, 0x924},
+ { 0x50228, 6, 0x1e, 0x924},
+ { 0x50240, 1, 0x1f, 0x924},
+ { 0x50280, 1, 0x1f, 0x924},
+ { 0x50300, 1, 0x1c, 0x924},
+ { 0x5030c, 1, 0x1c, 0x924},
+ { 0x50318, 1, 0x1c, 0x934},
+ { 0x5031c, 1, 0x1c, 0x924},
+ { 0x50320, 2, 0x1c, 0x934},
+ { 0x50330, 1, 0x10, 0x924},
+ { 0x52000, 1, 0x1f, 0x924},
+ { 0x54000, 1, 0x1f, 0x93c},
+ { 0x54004, 255, 0x1f, 0x30},
+ { 0x54400, 1, 0x1f, 0x38},
+ { 0x54404, 255, 0x1f, 0x30},
+ { 0x54800, 1, 0x1f, 0x38},
+ { 0x54804, 255, 0x1f, 0x30},
+ { 0x54c00, 1, 0x1f, 0x38},
+ { 0x54c04, 255, 0x1f, 0x30},
+ { 0x55000, 1, 0x1f, 0x38},
+ { 0x55004, 255, 0x1f, 0x30},
+ { 0x55400, 1, 0x1f, 0x38},
+ { 0x55404, 255, 0x1f, 0x30},
+ { 0x55800, 1, 0x1f, 0x38},
+ { 0x55804, 255, 0x1f, 0x30},
+ { 0x55c00, 1, 0x1f, 0x38},
+ { 0x55c04, 255, 0x1f, 0x30},
+ { 0x56000, 1, 0x1f, 0x38},
+ { 0x56004, 255, 0x1f, 0x30},
+ { 0x56400, 1, 0x1f, 0x38},
+ { 0x56404, 255, 0x1f, 0x30},
+ { 0x56800, 1, 0x1f, 0x38},
+ { 0x56804, 255, 0x1f, 0x30},
+ { 0x56c00, 1, 0x1f, 0x38},
+ { 0x56c04, 255, 0x1f, 0x30},
+ { 0x57000, 1, 0x1f, 0x38},
+ { 0x57004, 255, 0x1f, 0x30},
+ { 0x58000, 1, 0x1f, 0x934},
+ { 0x58004, 8191, 0x3, 0x30},
+ { 0x60000, 26, 0x1f, 0x924},
+ { 0x60068, 8, 0x3, 0x924},
+ { 0x60088, 2, 0x1f, 0x924},
+ { 0x60090, 1, 0x1f, 0xfff},
+ { 0x60094, 9, 0x1f, 0x924},
+ { 0x600b8, 9, 0x3, 0x924},
+ { 0x600dc, 1, 0x1f, 0x924},
+ { 0x600e0, 5, 0x3, 0x924},
+ { 0x600f4, 1, 0x7, 0x924},
+ { 0x600f8, 1, 0x3, 0x924},
+ { 0x600fc, 8, 0x1f, 0x924},
+ { 0x6012c, 2, 0x1f, 0x1fff},
+ { 0x60138, 1, 0x1f, 0x1fff},
+ { 0x6013c, 24, 0x2, 0x924},
+ { 0x6019c, 2, 0x1c, 0x924},
+ { 0x601ac, 18, 0x1c, 0x924},
+ { 0x60200, 1, 0x1f, 0xb6d},
+ { 0x60204, 2, 0x1f, 0x249},
+ { 0x60210, 13, 0x1c, 0x924},
+ { 0x60244, 16, 0x10, 0x924},
+ { 0x61000, 1, 0x1f, 0xb6d},
+ { 0x61004, 511, 0x1f, 0x249},
+ { 0x61800, 512, 0x18, 0x249},
+ { 0x70000, 8, 0x1f, 0xb6d},
+ { 0x70020, 8184, 0x1f, 0x249},
+ { 0x78000, 8192, 0x18, 0x249},
+ { 0x85000, 3, 0x1f, 0x1000},
+ { 0x8501c, 7, 0x1f, 0x1000},
+ { 0x85048, 1, 0x1f, 0x1000},
+ { 0x85200, 32, 0x1f, 0x1000},
+ { 0xa0000, 16384, 0x3, 0x1000},
+ { 0xb0000, 16384, 0x2, 0x1000},
+ { 0xc1000, 7, 0x1f, 0x924},
+ { 0xc102c, 2, 0x1f, 0x1fff},
+ { 0xc1038, 1, 0x1f, 0x1fff},
+ { 0xc103c, 2, 0x1c, 0x924},
+ { 0xc1800, 2, 0x1f, 0x924},
+ { 0xc2000, 164, 0x1f, 0x924},
+ { 0xc22b0, 2, 0x1f, 0x1fff},
+ { 0xc22bc, 1, 0x1f, 0x1fff},
+ { 0xc22c0, 5, 0x1c, 0x924},
+ { 0xc22d8, 4, 0x1c, 0x924},
+ { 0xc2400, 49, 0x1f, 0x924},
+ { 0xc24c8, 32, 0x1f, 0x924},
+ { 0xc2548, 1, 0x1f, 0xfff},
+ { 0xc254c, 1, 0x1f, 0x924},
+ { 0xc2550, 1, 0x1f, 0xfff},
+ { 0xc2554, 1, 0x1f, 0x924},
+ { 0xc2558, 1, 0x1f, 0xfff},
+ { 0xc255c, 1, 0x1f, 0x924},
+ { 0xc2568, 2, 0x1f, 0x924},
+ { 0xc2600, 1, 0x1f, 0x924},
+ { 0xc4000, 165, 0x1f, 0x924},
+ { 0xc42b4, 2, 0x1f, 0x1fff},
+ { 0xc42c0, 1, 0x1f, 0x1fff},
+ { 0xc42d8, 2, 0x1c, 0x924},
+ { 0xc42e0, 7, 0x1e, 0x924},
+ { 0xc42fc, 1, 0x1c, 0x924},
+ { 0xc4400, 51, 0x1f, 0x924},
+ { 0xc44d0, 32, 0x1f, 0x924},
+ { 0xc4550, 1, 0x1f, 0xfff},
+ { 0xc4554, 1, 0x1f, 0x924},
+ { 0xc4558, 1, 0x1f, 0xfff},
+ { 0xc455c, 1, 0x1f, 0x924},
+ { 0xc4560, 1, 0x1f, 0xfff},
+ { 0xc4564, 1, 0x1f, 0x924},
+ { 0xc4570, 2, 0x1f, 0x924},
+ { 0xc4578, 5, 0x1c, 0x924},
+ { 0xc4600, 1, 0x1f, 0x924},
+ { 0xd0000, 19, 0x1f, 0x924},
+ { 0xd004c, 8, 0x1f, 0x1927},
+ { 0xd006c, 64, 0x1f, 0x924},
+ { 0xd016c, 8, 0x1f, 0xfff},
+ { 0xd018c, 19, 0x1f, 0x924},
+ { 0xd01e8, 2, 0x1f, 0x1fff},
+ { 0xd01f4, 1, 0x1f, 0x1fff},
+ { 0xd01fc, 1, 0x1c, 0x924},
+ { 0xd0200, 1, 0x1f, 0x924},
+ { 0xd0204, 1, 0x1f, 0xfff},
+ { 0xd020c, 3, 0x1f, 0xfff},
+ { 0xd0218, 4, 0x1f, 0x924},
+ { 0xd0228, 18, 0x1e, 0x924},
+ { 0xd0280, 1, 0x1f, 0x924},
+ { 0xd0300, 1, 0x1f, 0x924},
+ { 0xd0400, 1, 0x1f, 0x924},
+ { 0xd0818, 1, 0x10, 0x924},
+ { 0xd4000, 1, 0x1f, 0x1927},
+ { 0xd4004, 255, 0x1f, 0x6},
+ { 0xd4400, 1, 0x1f, 0x1007},
+ { 0xd4404, 255, 0x1f, 0x6},
+ { 0xd4800, 1, 0x1f, 0x1007},
+ { 0xd4804, 255, 0x1f, 0x6},
+ { 0xd4c00, 1, 0x1f, 0x1007},
+ { 0xd4c04, 255, 0x1f, 0x6},
+ { 0xd5000, 1, 0x1f, 0x1007},
+ { 0xd5004, 255, 0x1f, 0x6},
+ { 0xd5400, 1, 0x1f, 0x1007},
+ { 0xd5404, 255, 0x1f, 0x6},
+ { 0xd5800, 1, 0x1f, 0x1007},
+ { 0xd5804, 255, 0x1f, 0x6},
+ { 0xd5c00, 1, 0x1f, 0x1007},
+ { 0xd5c04, 255, 0x1f, 0x6},
+ { 0xd6000, 1, 0x1f, 0x1007},
+ { 0xd6004, 255, 0x1f, 0x6},
+ { 0xd6400, 1, 0x1f, 0x1007},
+ { 0xd6404, 255, 0x1f, 0x6},
+ { 0xd8000, 1, 0x1f, 0x1927},
+ { 0xd8004, 255, 0x1f, 0x6},
+ { 0xd8400, 1, 0x1f, 0x1007},
+ { 0xd8404, 255, 0x1f, 0x6},
+ { 0xd8800, 1, 0x1f, 0x1007},
+ { 0xd8804, 255, 0x1f, 0x6},
+ { 0xd8c00, 1, 0x1f, 0x1007},
+ { 0xd8c04, 255, 0x1f, 0x6},
+ { 0xd9000, 1, 0x1f, 0x1007},
+ { 0xd9004, 255, 0x1f, 0x6},
+ { 0xd9400, 1, 0x1f, 0x1007},
+ { 0xd9404, 255, 0x1f, 0x6},
+ { 0xd9800, 1, 0x1f, 0x1007},
+ { 0xd9804, 255, 0x1f, 0x6},
+ { 0xd9c00, 1, 0x1f, 0x1007},
+ { 0xd9c04, 255, 0x1f, 0x6},
+ { 0xda000, 1, 0x1f, 0x1007},
+ { 0xda004, 255, 0x1f, 0x6},
+ { 0xda400, 1, 0x1f, 0x1007},
+ { 0xda404, 255, 0x1f, 0x6},
+ { 0xda800, 1, 0x1f, 0x1007},
+ { 0xda804, 255, 0x1f, 0x6},
+ { 0xdac00, 1, 0x1f, 0x1007},
+ { 0xdac04, 255, 0x1f, 0x6},
+ { 0xdb000, 1, 0x1f, 0x1007},
+ { 0xdb004, 255, 0x1f, 0x6},
+ { 0xdb400, 1, 0x1f, 0x1007},
+ { 0xdb404, 255, 0x1f, 0x6},
+ { 0xdb800, 1, 0x1f, 0x1007},
+ { 0xdb804, 255, 0x1f, 0x6},
+ { 0xdbc00, 1, 0x1f, 0x1007},
+ { 0xdbc04, 255, 0x1f, 0x6},
+ { 0xdc000, 1, 0x1f, 0x1007},
+ { 0xdc004, 255, 0x1f, 0x6},
+ { 0xdc400, 1, 0x1f, 0x1007},
+ { 0xdc404, 255, 0x1f, 0x6},
+ { 0xdc800, 1, 0x1f, 0x1007},
+ { 0xdc804, 255, 0x1f, 0x6},
+ { 0xdcc00, 1, 0x1f, 0x1007},
+ { 0xdcc04, 255, 0x1f, 0x6},
+ { 0xdd000, 1, 0x1f, 0x1007},
+ { 0xdd004, 255, 0x1f, 0x6},
+ { 0xdd400, 1, 0x1f, 0x1007},
+ { 0xdd404, 255, 0x1f, 0x6},
+ { 0xdd800, 1, 0x1f, 0x1007},
+ { 0xdd804, 255, 0x1f, 0x6},
+ { 0xddc00, 1, 0x1f, 0x1007},
+ { 0xddc04, 255, 0x1f, 0x6},
+ { 0xde000, 1, 0x1f, 0x1007},
+ { 0xde004, 255, 0x1f, 0x6},
+ { 0xde400, 1, 0x1f, 0x1007},
+ { 0xde404, 255, 0x1f, 0x6},
+ { 0xde800, 1, 0x1f, 0x1007},
+ { 0xde804, 255, 0x1f, 0x6},
+ { 0xdec00, 1, 0x1f, 0x1007},
+ { 0xdec04, 255, 0x1f, 0x6},
+ { 0xdf000, 1, 0x1f, 0x1007},
+ { 0xdf004, 255, 0x1f, 0x6},
+ { 0xdf400, 1, 0x1f, 0x1007},
+ { 0xdf404, 255, 0x1f, 0x6},
+ { 0xdf800, 1, 0x1f, 0x1007},
+ { 0xdf804, 255, 0x1f, 0x6},
+ { 0xdfc00, 1, 0x1f, 0x1007},
+ { 0xdfc04, 255, 0x1f, 0x6},
+ { 0xe0000, 21, 0x1f, 0x924},
+ { 0xe0054, 8, 0x1f, 0xf24},
+ { 0xe0074, 49, 0x1f, 0x924},
+ { 0xe0138, 1, 0x3, 0x924},
+ { 0xe013c, 6, 0x1f, 0x924},
+ { 0xe0154, 8, 0x1f, 0xfff},
+ { 0xe0174, 21, 0x1f, 0x924},
+ { 0xe01d8, 2, 0x1f, 0x1fff},
+ { 0xe01e4, 1, 0x1f, 0x1fff},
+ { 0xe01f4, 1, 0x4, 0x924},
+ { 0xe01f8, 1, 0x1c, 0x924},
+ { 0xe0200, 1, 0x1f, 0x924},
+ { 0xe0204, 1, 0x1f, 0xfff},
+ { 0xe020c, 2, 0x1f, 0xfff},
+ { 0xe0214, 2, 0x1f, 0x924},
+ { 0xe021c, 2, 0x1f, 0xfff},
+ { 0xe0224, 2, 0x1f, 0x924},
+ { 0xe022c, 18, 0x1e, 0x924},
+ { 0xe0280, 1, 0x1f, 0x924},
+ { 0xe0300, 1, 0x1f, 0x924},
+ { 0xe0400, 1, 0x10, 0x924},
+ { 0xe1000, 1, 0x1f, 0x924},
+ { 0xe2000, 1, 0x1f, 0xf24},
+ { 0xe2004, 255, 0x1f, 0xc00},
+ { 0xe2400, 1, 0x1f, 0xe00},
+ { 0xe2404, 255, 0x1f, 0xc00},
+ { 0xe2800, 1, 0x1f, 0xe00},
+ { 0xe2804, 255, 0x1f, 0xc00},
+ { 0xe2c00, 1, 0x1f, 0xe00},
+ { 0xe2c04, 255, 0x1f, 0xc00},
+ { 0xe3000, 1, 0x1f, 0xe00},
+ { 0xe3004, 255, 0x1f, 0xc00},
+ { 0xe3400, 1, 0x1f, 0xe00},
+ { 0xe3404, 255, 0x1f, 0xc00},
+ { 0xe3800, 1, 0x1f, 0xe00},
+ { 0xe3804, 255, 0x1f, 0xc00},
+ { 0xe3c00, 1, 0x1f, 0xe00},
+ { 0xe3c04, 255, 0x1f, 0xc00},
+ { 0xf0000, 1, 0x1f, 0xf24},
+ { 0xf0004, 255, 0x1f, 0xc00},
+ { 0xf0400, 1, 0x1f, 0xe00},
+ { 0xf0404, 255, 0x1f, 0xc00},
+ { 0xf0800, 1, 0x1f, 0xe00},
+ { 0xf0804, 255, 0x1f, 0xc00},
+ { 0xf0c00, 1, 0x1f, 0xe00},
+ { 0xf0c04, 255, 0x1f, 0xc00},
+ { 0xf1000, 1, 0x1f, 0xe00},
+ { 0xf1004, 255, 0x1f, 0xc00},
+ { 0xf1400, 1, 0x1f, 0xe00},
+ { 0xf1404, 255, 0x1f, 0xc00},
+ { 0xf1800, 1, 0x1f, 0xe00},
+ { 0xf1804, 255, 0x1f, 0xc00},
+ { 0xf1c00, 1, 0x1f, 0xe00},
+ { 0xf1c04, 255, 0x1f, 0xc00},
+ { 0xf2000, 1, 0x1f, 0xe00},
+ { 0xf2004, 255, 0x1f, 0xc00},
+ { 0xf2400, 1, 0x1f, 0xe00},
+ { 0xf2404, 255, 0x1f, 0xc00},
+ { 0xf2800, 1, 0x1f, 0xe00},
+ { 0xf2804, 255, 0x1f, 0xc00},
+ { 0xf2c00, 1, 0x1f, 0xe00},
+ { 0xf2c04, 255, 0x1f, 0xc00},
+ { 0xf3000, 1, 0x1f, 0xe00},
+ { 0xf3004, 255, 0x1f, 0xc00},
+ { 0xf3400, 1, 0x1f, 0xe00},
+ { 0xf3404, 255, 0x1f, 0xc00},
+ { 0xf3800, 1, 0x1f, 0xe00},
+ { 0xf3804, 255, 0x1f, 0xc00},
+ { 0xf3c00, 1, 0x1f, 0xe00},
+ { 0xf3c04, 255, 0x1f, 0xc00},
+ { 0xf4000, 1, 0x1f, 0xe00},
+ { 0xf4004, 255, 0x1f, 0xc00},
+ { 0xf4400, 1, 0x1f, 0xe00},
+ { 0xf4404, 255, 0x1f, 0xc00},
+ { 0xf4800, 1, 0x1f, 0xe00},
+ { 0xf4804, 255, 0x1f, 0xc00},
+ { 0xf4c00, 1, 0x1f, 0xe00},
+ { 0xf4c04, 255, 0x1f, 0xc00},
+ { 0xf5000, 1, 0x1f, 0xe00},
+ { 0xf5004, 255, 0x1f, 0xc00},
+ { 0xf5400, 1, 0x1f, 0xe00},
+ { 0xf5404, 255, 0x1f, 0xc00},
+ { 0xf5800, 1, 0x1f, 0xe00},
+ { 0xf5804, 255, 0x1f, 0xc00},
+ { 0xf5c00, 1, 0x1f, 0xe00},
+ { 0xf5c04, 255, 0x1f, 0xc00},
+ { 0xf6000, 1, 0x1f, 0xe00},
+ { 0xf6004, 255, 0x1f, 0xc00},
+ { 0xf6400, 1, 0x1f, 0xe00},
+ { 0xf6404, 255, 0x1f, 0xc00},
+ { 0xf6800, 1, 0x1f, 0xe00},
+ { 0xf6804, 255, 0x1f, 0xc00},
+ { 0xf6c00, 1, 0x1f, 0xe00},
+ { 0xf6c04, 255, 0x1f, 0xc00},
+ { 0xf7000, 1, 0x1f, 0xe00},
+ { 0xf7004, 255, 0x1f, 0xc00},
+ { 0xf7400, 1, 0x1f, 0xe00},
+ { 0xf7404, 255, 0x1f, 0xc00},
+ { 0xf7800, 1, 0x1f, 0xe00},
+ { 0xf7804, 255, 0x1f, 0xc00},
+ { 0xf7c00, 1, 0x1f, 0xe00},
+ { 0xf7c04, 255, 0x1f, 0xc00},
+ { 0xf8000, 1, 0x1f, 0xe00},
+ { 0xf8004, 255, 0x1f, 0xc00},
+ { 0xf8400, 1, 0x1f, 0xe00},
+ { 0xf8404, 255, 0x1f, 0xc00},
+ { 0xf8800, 1, 0x1f, 0xe00},
+ { 0xf8804, 255, 0x1f, 0xc00},
+ { 0xf8c00, 1, 0x1f, 0xe00},
+ { 0xf8c04, 255, 0x1f, 0xc00},
+ { 0xf9000, 1, 0x1f, 0xe00},
+ { 0xf9004, 255, 0x1f, 0xc00},
+ { 0xf9400, 1, 0x1f, 0xe00},
+ { 0xf9404, 255, 0x1f, 0xc00},
+ { 0xf9800, 1, 0x1f, 0xe00},
+ { 0xf9804, 255, 0x1f, 0xc00},
+ { 0xf9c00, 1, 0x1f, 0xe00},
+ { 0xf9c04, 255, 0x1f, 0xc00},
+ { 0xfa000, 1, 0x1f, 0xe00},
+ { 0xfa004, 255, 0x1f, 0xc00},
+ { 0xfa400, 1, 0x1f, 0xe00},
+ { 0xfa404, 255, 0x1f, 0xc00},
+ { 0xfa800, 1, 0x1f, 0xe00},
+ { 0xfa804, 255, 0x1f, 0xc00},
+ { 0xfac00, 1, 0x1f, 0xe00},
+ { 0xfac04, 255, 0x1f, 0xc00},
+ { 0xfb000, 1, 0x1f, 0xe00},
+ { 0xfb004, 255, 0x1f, 0xc00},
+ { 0xfb400, 1, 0x1f, 0xe00},
+ { 0xfb404, 255, 0x1f, 0xc00},
+ { 0xfb800, 1, 0x1f, 0xe00},
+ { 0xfb804, 255, 0x1f, 0xc00},
+ { 0xfbc00, 1, 0x1f, 0xe00},
+ { 0xfbc04, 255, 0x1f, 0xc00},
+ { 0xfc000, 1, 0x1f, 0xe00},
+ { 0xfc004, 255, 0x1f, 0xc00},
+ { 0xfc400, 1, 0x1f, 0xe00},
+ { 0xfc404, 255, 0x1f, 0xc00},
+ { 0xfc800, 1, 0x1f, 0xe00},
+ { 0xfc804, 255, 0x1f, 0xc00},
+ { 0xfcc00, 1, 0x1f, 0xe00},
+ { 0xfcc04, 255, 0x1f, 0xc00},
+ { 0xfd000, 1, 0x1f, 0xe00},
+ { 0xfd004, 255, 0x1f, 0xc00},
+ { 0xfd400, 1, 0x1f, 0xe00},
+ { 0xfd404, 255, 0x1f, 0xc00},
+ { 0xfd800, 1, 0x1f, 0xe00},
+ { 0xfd804, 255, 0x1f, 0xc00},
+ { 0xfdc00, 1, 0x1f, 0xe00},
+ { 0xfdc04, 255, 0x1f, 0xc00},
+ { 0xfe000, 1, 0x1f, 0xe00},
+ { 0xfe004, 255, 0x1f, 0xc00},
+ { 0xfe400, 1, 0x1f, 0xe00},
+ { 0xfe404, 255, 0x1f, 0xc00},
+ { 0xfe800, 1, 0x1f, 0xe00},
+ { 0xfe804, 255, 0x1f, 0xc00},
+ { 0xfec00, 1, 0x1f, 0xe00},
+ { 0xfec04, 255, 0x1f, 0xc00},
+ { 0xff000, 1, 0x1f, 0xe00},
+ { 0xff004, 255, 0x1f, 0xc00},
+ { 0xff400, 1, 0x1f, 0xe00},
+ { 0xff404, 255, 0x1f, 0xc00},
+ { 0xff800, 1, 0x1f, 0xe00},
+ { 0xff804, 255, 0x1f, 0xc00},
+ { 0xffc00, 1, 0x1f, 0xe00},
+ { 0xffc04, 255, 0x1f, 0xc00},
+ { 0x101000, 5, 0x1f, 0x924},
+ { 0x101014, 1, 0x1f, 0xfff},
+ { 0x101018, 6, 0x1f, 0x924},
+ { 0x101040, 2, 0x1f, 0x1fff},
+ { 0x10104c, 1, 0x1f, 0x1fff},
+ { 0x101050, 1, 0x1e, 0x924},
+ { 0x101054, 3, 0x1c, 0x924},
+ { 0x101100, 1, 0x1f, 0x924},
+ { 0x101800, 8, 0x1f, 0x924},
+ { 0x102000, 18, 0x1f, 0x924},
+ { 0x102058, 2, 0x1f, 0x1fff},
+ { 0x102064, 1, 0x1f, 0x1fff},
+ { 0x102068, 6, 0x1c, 0x924},
+ { 0x102080, 16, 0x1f, 0xfff},
+ { 0x1020c0, 1, 0x1f, 0x924},
+ { 0x1020c8, 8, 0x2, 0x924},
+ { 0x1020e8, 9, 0x1c, 0x924},
+ { 0x102400, 1, 0x1f, 0x924},
+ { 0x103000, 1, 0x1f, 0x924},
+ { 0x103004, 2, 0x1f, 0xfff},
+ { 0x10300c, 23, 0x1f, 0x924},
+ { 0x103088, 2, 0x1f, 0x1fff},
+ { 0x103094, 1, 0x1f, 0x1fff},
+ { 0x103098, 1, 0x1e, 0x924},
+ { 0x10309c, 2, 0x1e, 0xfff},
+ { 0x1030a4, 2, 0x1e, 0x924},
+ { 0x1030ac, 2, 0x1c, 0x924},
+ { 0x1030b4, 1, 0x4, 0x924},
+ { 0x1030b8, 2, 0x1c, 0xfff},
+ { 0x1030c0, 3, 0x1c, 0x924},
+ { 0x1030cc, 1, 0x1c, 0xfff},
+ { 0x1030d0, 1, 0x1c, 0x924},
+ { 0x1030d8, 2, 0x1c, 0x924},
+ { 0x1030e0, 1, 0x1c, 0xfff},
+ { 0x1030e4, 5, 0x1c, 0x924},
+ { 0x103400, 136, 0x1c, 0x1fff},
+ { 0x103800, 8, 0x1f, 0x924},
+ { 0x104000, 1, 0x1f, 0x924},
+ { 0x104004, 1, 0x1f, 0xfff},
+ { 0x104008, 4, 0x1f, 0x924},
+ { 0x104018, 1, 0x1f, 0xfff},
+ { 0x10401c, 1, 0x1f, 0x924},
+ { 0x104020, 1, 0x1f, 0xfff},
+ { 0x104024, 6, 0x1f, 0x924},
+ { 0x10403c, 1, 0x1f, 0xfff},
+ { 0x104040, 47, 0x1f, 0x924},
+ { 0x10410c, 2, 0x1f, 0x1fff},
+ { 0x104118, 1, 0x1f, 0x1fff},
+ { 0x10411c, 16, 0x1c, 0x924},
+ { 0x104200, 17, 0x1f, 0x924},
+ { 0x104400, 1, 0x1f, 0x1fff},
+ { 0x104404, 63, 0x1f, 0xfff},
+ { 0x104500, 192, 0x1f, 0xdb6},
+ { 0x104800, 1, 0x1f, 0x1fff},
+ { 0x104804, 63, 0x1f, 0xfff},
+ { 0x104900, 192, 0x1f, 0xdb6},
+ { 0x105000, 4, 0x1f, 0x1fff},
+ { 0x105010, 252, 0x1f, 0xfff},
+ { 0x105400, 768, 0x1f, 0xdb6},
+ { 0x107000, 7, 0x1c, 0x924},
+ { 0x10701c, 1, 0x18, 0x924},
+ { 0x108000, 33, 0x3, 0x924},
+ { 0x1080ac, 5, 0x2, 0x924},
+ { 0x108100, 5, 0x3, 0x924},
+ { 0x108120, 5, 0x3, 0x924},
+ { 0x108200, 74, 0x3, 0x924},
+ { 0x108400, 74, 0x3, 0x924},
+ { 0x108800, 152, 0x3, 0x924},
+ { 0x110000, 111, 0x1c, 0x924},
+ { 0x1101cc, 2, 0x1c, 0x1fff},
+ { 0x1101d8, 1, 0x1c, 0x1fff},
+ { 0x1101dc, 1, 0x18, 0x924},
+ { 0x110200, 4, 0x1c, 0x924},
+ { 0x120000, 92, 0x1f, 0x924},
+ { 0x120170, 2, 0x3, 0x924},
+ { 0x120178, 14, 0x1f, 0x924},
+ { 0x1201b0, 2, 0x1f, 0xfff},
+ { 0x1201b8, 93, 0x1f, 0x924},
+ { 0x12032c, 1, 0x1f, 0xfff},
+ { 0x120330, 15, 0x1f, 0x924},
+ { 0x12036c, 3, 0x1f, 0xfff},
+ { 0x120378, 36, 0x1f, 0x924},
+ { 0x120408, 2, 0x1f, 0xfff},
+ { 0x120410, 1, 0x1f, 0x924},
+ { 0x120414, 15, 0x1f, 0xfff},
+ { 0x120450, 10, 0x1f, 0x924},
+ { 0x120478, 2, 0x1f, 0xfff},
+ { 0x120480, 43, 0x1f, 0x924},
+ { 0x12052c, 1, 0x1f, 0xfff},
+ { 0x120530, 5, 0x1f, 0x924},
+ { 0x120544, 4, 0x3, 0x924},
+ { 0x120554, 4, 0x1f, 0x924},
+ { 0x120564, 2, 0x1f, 0xfff},
+ { 0x12057c, 2, 0x1f, 0x1fff},
+ { 0x120588, 3, 0x1f, 0x1fff},
+ { 0x120598, 1, 0x1f, 0x1fff},
+ { 0x12059c, 22, 0x1e, 0x924},
+ { 0x1205f4, 1, 0x6, 0x924},
+ { 0x1205f8, 4, 0x1c, 0x924},
+ { 0x120618, 1, 0x1c, 0x924},
+ { 0x12061c, 31, 0x1e, 0x924},
+ { 0x120698, 3, 0x1c, 0x924},
+ { 0x1206a4, 1, 0x4, 0x924},
+ { 0x1206a8, 1, 0x1c, 0x924},
+ { 0x1206b0, 38, 0x1c, 0x924},
+ { 0x120748, 1, 0x1c, 0xfff},
+ { 0x12074c, 11, 0x1c, 0x924},
+ { 0x120778, 2, 0x1c, 0xfff},
+ { 0x120780, 23, 0x1c, 0x924},
+ { 0x1207dc, 1, 0x4, 0x924},
+ { 0x1207fc, 1, 0x1c, 0x924},
+ { 0x12080c, 2, 0x1f, 0xfff},
+ { 0x120814, 1, 0x1f, 0x924},
+ { 0x120818, 1, 0x1f, 0xfff},
+ { 0x12081c, 1, 0x1f, 0x924},
+ { 0x120820, 1, 0x1f, 0xfff},
+ { 0x120824, 1, 0x1f, 0x924},
+ { 0x120828, 1, 0x1f, 0xfff},
+ { 0x12082c, 1, 0x1f, 0x924},
+ { 0x120830, 1, 0x1f, 0xfff},
+ { 0x120834, 1, 0x1f, 0x924},
+ { 0x120838, 1, 0x1f, 0xfff},
+ { 0x12083c, 1, 0x1f, 0x924},
+ { 0x120840, 1, 0x1f, 0xfff},
+ { 0x120844, 1, 0x1f, 0x924},
+ { 0x120848, 1, 0x1f, 0xfff},
+ { 0x12084c, 1, 0x1f, 0x924},
+ { 0x120850, 1, 0x1f, 0xfff},
+ { 0x120854, 1, 0x1f, 0x924},
+ { 0x120858, 1, 0x1f, 0xfff},
+ { 0x12085c, 1, 0x1f, 0x924},
+ { 0x120860, 1, 0x1f, 0xfff},
+ { 0x120864, 1, 0x1f, 0x924},
+ { 0x120868, 1, 0x1f, 0xfff},
+ { 0x12086c, 1, 0x1f, 0x924},
+ { 0x120870, 1, 0x1f, 0xfff},
+ { 0x120874, 1, 0x1f, 0x924},
+ { 0x120878, 1, 0x1f, 0xfff},
+ { 0x12087c, 1, 0x1f, 0x924},
+ { 0x120880, 1, 0x1f, 0xfff},
+ { 0x120884, 1, 0x1f, 0x924},
+ { 0x120888, 1, 0x1f, 0xfff},
+ { 0x12088c, 1, 0x1f, 0x924},
+ { 0x120890, 1, 0x1f, 0xfff},
+ { 0x120894, 1, 0x1f, 0x924},
+ { 0x120898, 1, 0x1f, 0xfff},
+ { 0x12089c, 1, 0x1f, 0x924},
+ { 0x1208a0, 1, 0x1f, 0xfff},
+ { 0x1208a4, 1, 0x1f, 0x924},
+ { 0x1208a8, 1, 0x1f, 0xfff},
+ { 0x1208ac, 1, 0x1f, 0x924},
+ { 0x1208b0, 1, 0x1f, 0xfff},
+ { 0x1208b4, 1, 0x1f, 0x924},
+ { 0x1208b8, 1, 0x1f, 0xfff},
+ { 0x1208bc, 1, 0x1f, 0x924},
+ { 0x1208c0, 1, 0x1f, 0xfff},
+ { 0x1208c4, 1, 0x1f, 0x924},
+ { 0x1208c8, 1, 0x1f, 0xfff},
+ { 0x1208cc, 1, 0x1f, 0x924},
+ { 0x1208d0, 1, 0x1f, 0xfff},
+ { 0x1208d4, 1, 0x1f, 0x924},
+ { 0x1208d8, 1, 0x1f, 0xfff},
+ { 0x1208dc, 1, 0x1f, 0x924},
+ { 0x1208e0, 1, 0x1f, 0xfff},
+ { 0x1208e4, 1, 0x1f, 0x924},
+ { 0x1208e8, 1, 0x1f, 0xfff},
+ { 0x1208ec, 1, 0x1f, 0x924},
+ { 0x1208f0, 1, 0x1f, 0xfff},
+ { 0x1208f4, 1, 0x1f, 0x924},
+ { 0x1208f8, 1, 0x1f, 0xfff},
+ { 0x1208fc, 1, 0x1f, 0x924},
+ { 0x120900, 1, 0x1f, 0xfff},
+ { 0x120904, 1, 0x1f, 0x924},
+ { 0x120908, 1, 0x1f, 0xfff},
+ { 0x12090c, 1, 0x1f, 0x924},
+ { 0x120910, 7, 0x1c, 0x924},
+ { 0x120930, 9, 0x1c, 0x924},
+ { 0x12095c, 37, 0x18, 0x924},
+ { 0x120a00, 2, 0x7, 0x924},
+ { 0x120b00, 1, 0x18, 0x924},
+ { 0x122000, 2, 0x1f, 0x924},
+ { 0x122008, 2046, 0x1, 0x924},
+ { 0x128000, 6144, 0x1e, 0x924},
+ { 0x130000, 1, 0x1c, 0x1fff},
+ { 0x130004, 11, 0x1c, 0x924},
+ { 0x130030, 1, 0x1c, 0xfff},
+ { 0x130034, 6, 0x1c, 0x924},
+ { 0x13004c, 3, 0x1c, 0xfff},
+ { 0x130058, 3, 0x1c, 0x924},
+ { 0x130064, 2, 0x1c, 0xfff},
+ { 0x13006c, 8, 0x1c, 0x924},
+ { 0x13009c, 2, 0x1c, 0x1fff},
+ { 0x1300a8, 1, 0x1c, 0x1fff},
+ { 0x130100, 12, 0x1c, 0x924},
+ { 0x130130, 1, 0x1c, 0xfff},
+ { 0x130134, 14, 0x1c, 0x924},
+ { 0x13016c, 1, 0x1c, 0xfff},
+ { 0x130170, 1, 0x1c, 0x924},
+ { 0x130180, 1, 0x1c, 0x924},
+ { 0x130200, 1, 0x1c, 0x924},
+ { 0x130280, 1, 0x1c, 0x924},
+ { 0x130300, 1, 0x1c, 0xfff},
+ { 0x130304, 4, 0x1c, 0x924},
+ { 0x130380, 1, 0x1c, 0x924},
+ { 0x130400, 1, 0x1c, 0x924},
+ { 0x130480, 1, 0x1c, 0xfff},
+ { 0x130484, 4, 0x1c, 0x924},
+ { 0x130800, 72, 0x1c, 0x924},
+ { 0x131000, 136, 0x1c, 0x924},
+ { 0x132000, 148, 0x1c, 0x924},
+ { 0x134000, 544, 0x1c, 0x924},
+ { 0x140000, 1, 0x1f, 0x924},
+ { 0x140004, 9, 0xf, 0x924},
+ { 0x140028, 8, 0x1f, 0x924},
+ { 0x140048, 5, 0xf, 0x924},
+ { 0x14005c, 2, 0xf, 0xfff},
+ { 0x140064, 3, 0xf, 0x924},
+ { 0x140070, 1, 0x1f, 0x924},
+ { 0x140074, 10, 0xf, 0x924},
+ { 0x14009c, 1, 0x1f, 0x924},
+ { 0x1400a0, 5, 0xf, 0x924},
+ { 0x1400b4, 7, 0x1f, 0x924},
+ { 0x1400d0, 2, 0xf, 0xfff},
+ { 0x1400d8, 2, 0xf, 0x924},
+ { 0x1400e0, 1, 0xf, 0xfff},
+ { 0x1400e4, 5, 0xf, 0x924},
+ { 0x1400f8, 2, 0x1f, 0x924},
+ { 0x140100, 5, 0x3, 0x924},
+ { 0x140114, 5, 0xf, 0x924},
+ { 0x140128, 7, 0x1f, 0x924},
+ { 0x140144, 9, 0xf, 0x924},
+ { 0x140168, 8, 0x1f, 0x924},
+ { 0x140188, 3, 0xf, 0x924},
+ { 0x140194, 13, 0x1f, 0x924},
+ { 0x1401d8, 2, 0x1f, 0x1fff},
+ { 0x1401e4, 1, 0x1f, 0x1fff},
+ { 0x140200, 6, 0xf, 0xfff},
+ { 0x1402e0, 2, 0xc, 0x924},
+ { 0x1402e8, 2, 0x1c, 0x924},
+ { 0x1402f0, 9, 0xc, 0x924},
+ { 0x140314, 9, 0x10, 0x924},
+ { 0x140338, 7, 0x10, 0xfff},
+ { 0x140354, 7, 0x10, 0x924},
+ { 0x140370, 7, 0x10, 0xfff},
+ { 0x14038c, 14, 0x10, 0x924},
+ { 0x1404b0, 14, 0x10, 0x924},
+ { 0x15c000, 2, 0x1e, 0x924},
+ { 0x15c008, 5, 0x2, 0x924},
+ { 0x15c020, 8, 0x1c, 0x924},
+ { 0x15c040, 1, 0xc, 0x924},
+ { 0x15c044, 2, 0x1c, 0x924},
+ { 0x15c04c, 8, 0xc, 0x924},
+ { 0x15c06c, 8, 0x1c, 0x924},
+ { 0x15c090, 13, 0x1c, 0x924},
+ { 0x15c0c8, 24, 0x1c, 0x924},
+ { 0x15c128, 2, 0xc, 0x924},
+ { 0x15c130, 1, 0x1c, 0x924},
+ { 0x15c138, 6, 0x1c, 0x924},
+ { 0x15c150, 2, 0x18, 0x924},
+ { 0x15c158, 2, 0x8, 0x924},
+ { 0x15c160, 23, 0x10, 0x924},
+ { 0x15c1bc, 6, 0x10, 0xfff},
+ { 0x15c1d4, 23, 0x10, 0x924},
+ { 0x15c230, 7, 0x10, 0xfff},
+ { 0x15c24c, 90, 0x10, 0x924},
+ { 0x160004, 6, 0x18, 0x924},
+ { 0x16003c, 1, 0x10, 0x924},
+ { 0x160040, 6, 0x18, 0x924},
+ { 0x16005c, 6, 0x18, 0x924},
+ { 0x160074, 1, 0x10, 0x924},
+ { 0x160078, 2, 0x18, 0x924},
+ { 0x160300, 8, 0x18, 0x924},
+ { 0x160330, 6, 0x18, 0x924},
+ { 0x160404, 6, 0x18, 0x924},
+ { 0x16043c, 1, 0x10, 0x924},
+ { 0x160440, 6, 0x18, 0x924},
+ { 0x16045c, 6, 0x18, 0x924},
+ { 0x160474, 1, 0x10, 0x924},
+ { 0x160478, 2, 0x18, 0x924},
+ { 0x160700, 8, 0x18, 0x924},
+ { 0x160730, 6, 0x18, 0x924},
+ { 0x161000, 7, 0x1f, 0x924},
+ { 0x16102c, 2, 0x1f, 0x1fff},
+ { 0x161038, 1, 0x1f, 0x1fff},
+ { 0x16103c, 2, 0x1c, 0x924},
+ { 0x161800, 2, 0x1f, 0x924},
+ { 0x162000, 54, 0x18, 0x924},
+ { 0x162200, 60, 0x18, 0x924},
+ { 0x162400, 54, 0x18, 0x924},
+ { 0x162600, 60, 0x18, 0x924},
+ { 0x162800, 54, 0x18, 0x924},
+ { 0x162a00, 60, 0x18, 0x924},
+ { 0x162c00, 54, 0x18, 0x924},
+ { 0x162e00, 60, 0x18, 0x924},
+ { 0x163000, 1, 0x18, 0x924},
+ { 0x163008, 1, 0x18, 0x924},
+ { 0x163010, 1, 0x18, 0x924},
+ { 0x163018, 1, 0x18, 0x924},
+ { 0x163020, 5, 0x18, 0x924},
+ { 0x163038, 3, 0x18, 0x924},
+ { 0x163048, 3, 0x18, 0x924},
+ { 0x163058, 1, 0x18, 0x924},
+ { 0x163060, 1, 0x18, 0x924},
+ { 0x163068, 1, 0x18, 0x924},
+ { 0x163070, 3, 0x18, 0x924},
+ { 0x163080, 1, 0x18, 0x924},
+ { 0x163088, 3, 0x18, 0x924},
+ { 0x163098, 1, 0x18, 0x924},
+ { 0x1630a0, 1, 0x18, 0x924},
+ { 0x1630a8, 1, 0x18, 0x924},
+ { 0x1630b0, 2, 0x10, 0x924},
+ { 0x1630c0, 1, 0x18, 0x924},
+ { 0x1630c8, 1, 0x18, 0x924},
+ { 0x1630d0, 1, 0x18, 0x924},
+ { 0x1630d8, 1, 0x18, 0x924},
+ { 0x1630e0, 2, 0x18, 0x924},
+ { 0x163110, 1, 0x18, 0x924},
+ { 0x163120, 2, 0x18, 0x924},
+ { 0x163420, 4, 0x18, 0x924},
+ { 0x163438, 2, 0x18, 0x924},
+ { 0x163488, 2, 0x18, 0x924},
+ { 0x163520, 2, 0x18, 0x924},
+ { 0x163800, 1, 0x18, 0x924},
+ { 0x163808, 1, 0x18, 0x924},
+ { 0x163810, 1, 0x18, 0x924},
+ { 0x163818, 1, 0x18, 0x924},
+ { 0x163820, 5, 0x18, 0x924},
+ { 0x163838, 3, 0x18, 0x924},
+ { 0x163848, 3, 0x18, 0x924},
+ { 0x163858, 1, 0x18, 0x924},
+ { 0x163860, 1, 0x18, 0x924},
+ { 0x163868, 1, 0x18, 0x924},
+ { 0x163870, 3, 0x18, 0x924},
+ { 0x163880, 1, 0x18, 0x924},
+ { 0x163888, 3, 0x18, 0x924},
+ { 0x163898, 1, 0x18, 0x924},
+ { 0x1638a0, 1, 0x18, 0x924},
+ { 0x1638a8, 1, 0x18, 0x924},
+ { 0x1638b0, 2, 0x10, 0x924},
+ { 0x1638c0, 1, 0x18, 0x924},
+ { 0x1638c8, 1, 0x18, 0x924},
+ { 0x1638d0, 1, 0x18, 0x924},
+ { 0x1638d8, 1, 0x18, 0x924},
+ { 0x1638e0, 2, 0x18, 0x924},
+ { 0x163910, 1, 0x18, 0x924},
+ { 0x163920, 2, 0x18, 0x924},
+ { 0x163c20, 4, 0x18, 0x924},
+ { 0x163c38, 2, 0x18, 0x924},
+ { 0x163c88, 2, 0x18, 0x924},
+ { 0x163d20, 2, 0x18, 0x924},
+ { 0x164000, 5, 0x1f, 0x924},
+ { 0x164014, 2, 0x1f, 0xfff},
+ { 0x16401c, 53, 0x1f, 0x924},
+ { 0x164100, 2, 0x1f, 0x1fff},
+ { 0x16410c, 1, 0x1f, 0x1fff},
+ { 0x164110, 2, 0x1e, 0x924},
+ { 0x164118, 15, 0x1c, 0x924},
+ { 0x164200, 1, 0x1f, 0x924},
+ { 0x164208, 1, 0x1f, 0x924},
+ { 0x164210, 1, 0x1f, 0x924},
+ { 0x164218, 1, 0x1f, 0x924},
+ { 0x164220, 1, 0x1f, 0x924},
+ { 0x164228, 1, 0x1f, 0x924},
+ { 0x164230, 1, 0x1f, 0x924},
+ { 0x164238, 1, 0x1f, 0x924},
+ { 0x164240, 1, 0x1f, 0x924},
+ { 0x164248, 1, 0x1f, 0x924},
+ { 0x164250, 1, 0x1f, 0x924},
+ { 0x164258, 1, 0x1f, 0x924},
+ { 0x164260, 1, 0x1f, 0x924},
+ { 0x164270, 2, 0x1f, 0x924},
+ { 0x164280, 2, 0x1f, 0x924},
+ { 0x164800, 2, 0x1f, 0x924},
+ { 0x165000, 2, 0x1f, 0x924},
+ { 0x166000, 164, 0x1f, 0x924},
+ { 0x1662b0, 2, 0x1f, 0x1fff},
+ { 0x1662bc, 1, 0x1f, 0x1fff},
+ { 0x1662cc, 7, 0x1c, 0x924},
+ { 0x166400, 49, 0x1f, 0x924},
+ { 0x1664c8, 32, 0x1f, 0x924},
+ { 0x166548, 1, 0x1f, 0xfff},
+ { 0x16654c, 1, 0x1f, 0x924},
+ { 0x166550, 1, 0x1f, 0xfff},
+ { 0x166554, 1, 0x1f, 0x924},
+ { 0x166558, 1, 0x1f, 0xfff},
+ { 0x16655c, 1, 0x1f, 0x924},
+ { 0x166568, 2, 0x1f, 0x924},
+ { 0x166570, 5, 0x1c, 0x924},
+ { 0x166800, 1, 0x1f, 0x924},
+ { 0x168000, 1, 0x1f, 0xfff},
+ { 0x168004, 1, 0x1f, 0x924},
+ { 0x168008, 1, 0x1f, 0xfff},
+ { 0x16800c, 1, 0x1f, 0x924},
+ { 0x168010, 1, 0x1f, 0xfff},
+ { 0x168014, 1, 0x1f, 0x924},
+ { 0x168018, 1, 0x1f, 0xfff},
+ { 0x16801c, 3, 0x1f, 0x924},
+ { 0x168028, 2, 0x1f, 0xfff},
+ { 0x168030, 10, 0x1f, 0x924},
+ { 0x168058, 9, 0x1f, 0xfff},
+ { 0x16807c, 106, 0x1f, 0x924},
+ { 0x168224, 2, 0x3, 0x924},
+ { 0x16822c, 3, 0x1f, 0x924},
+ { 0x168238, 1, 0x1f, 0xfff},
+ { 0x16823c, 25, 0x1f, 0x924},
+ { 0x1682a0, 12, 0x3, 0x924},
+ { 0x1682d0, 7, 0x1f, 0xfff},
+ { 0x1682ec, 5, 0x1f, 0x924},
+ { 0x168300, 2, 0x3, 0xfff},
+ { 0x168308, 65, 0x1f, 0xfff},
+ { 0x16840c, 1, 0x1f, 0x924},
+ { 0x168410, 2, 0x1f, 0xfff},
+ { 0x168418, 2, 0x3, 0x924},
+ { 0x168420, 6, 0x1f, 0x924},
+ { 0x168448, 2, 0x1f, 0x1fff},
+ { 0x168454, 1, 0x1f, 0x1fff},
+ { 0x168800, 19, 0x1f, 0x924},
+ { 0x168900, 1, 0x1f, 0x924},
+ { 0x168a00, 128, 0x1f, 0xfff},
+ { 0x16a000, 1536, 0x1f, 0x924},
+ { 0x16c000, 1536, 0x1f, 0x924},
+ { 0x16e000, 16, 0x2, 0x924},
+ { 0x16e040, 8, 0x1c, 0x924},
+ { 0x16e100, 1, 0x2, 0x924},
+ { 0x16e200, 2, 0x2, 0xfff},
+ { 0x16e400, 1, 0x2, 0x924},
+ { 0x16e404, 2, 0x2, 0xfff},
+ { 0x16e40c, 94, 0x2, 0x924},
+ { 0x16e584, 64, 0x2, 0xfff},
+ { 0x16e684, 2, 0x1e, 0xfff},
+ { 0x16e68c, 4, 0x2, 0xfff},
+ { 0x16e69c, 8, 0x2, 0x924},
+ { 0x16e6bc, 4, 0x1e, 0x924},
+ { 0x16e6cc, 4, 0x2, 0x924},
+ { 0x16e6e0, 2, 0x1c, 0x924},
+ { 0x16e6e8, 5, 0xc, 0x924},
+ { 0x16e6fc, 4, 0x1c, 0xfff},
+ { 0x16e70c, 1, 0x1c, 0x924},
+ { 0x16e768, 17, 0x1c, 0x924},
+ { 0x16e7ac, 12, 0x10, 0xfff},
+ { 0x170000, 24, 0x1f, 0x924},
+ { 0x170060, 4, 0x3, 0x924},
+ { 0x170070, 13, 0x1f, 0x924},
+ { 0x1700a4, 1, 0x1f, 0xfff},
+ { 0x1700a8, 1, 0x1f, 0x924},
+ { 0x1700ac, 2, 0x1f, 0xfff},
+ { 0x1700b4, 3, 0x1f, 0x924},
+ { 0x1700c0, 1, 0x1f, 0xfff},
+ { 0x1700c4, 44, 0x1f, 0x924},
+ { 0x170184, 2, 0x1f, 0x1fff},
+ { 0x170190, 1, 0x1f, 0x1fff},
+ { 0x170194, 11, 0x1c, 0x924},
+ { 0x1701c4, 1, 0x1c, 0x924},
+ { 0x1701cc, 7, 0x1c, 0x924},
+ { 0x1701e8, 1, 0x18, 0x924},
+ { 0x1701ec, 1, 0x1c, 0x924},
+ { 0x1701f4, 1, 0x1c, 0x924},
+ { 0x170200, 4, 0x1f, 0x924},
+ { 0x170214, 1, 0x1f, 0x924},
+ { 0x170218, 77, 0x1c, 0x924},
+ { 0x170400, 64, 0x1c, 0x924},
+ { 0x178000, 1, 0x1f, 0x924},
+ { 0x180000, 61, 0x1f, 0x924},
+ { 0x180114, 2, 0x1f, 0x1fff},
+ { 0x180120, 3, 0x1f, 0x1fff},
+ { 0x180130, 1, 0x1f, 0x1fff},
+ { 0x18013c, 2, 0x1e, 0x924},
+ { 0x180200, 27, 0x1f, 0x924},
+ { 0x18026c, 1, 0x1f, 0xfff},
+ { 0x180270, 12, 0x1f, 0x924},
+ { 0x1802a0, 1, 0x1f, 0xfff},
+ { 0x1802a4, 17, 0x1f, 0x924},
+ { 0x180340, 4, 0x1f, 0x924},
+ { 0x180380, 1, 0x1c, 0x924},
+ { 0x180388, 1, 0x1c, 0x924},
+ { 0x180390, 1, 0x1c, 0x924},
+ { 0x180398, 1, 0x1c, 0x924},
+ { 0x1803a0, 5, 0x1c, 0x924},
+ { 0x1803b4, 2, 0x18, 0x924},
+ { 0x180400, 256, 0x3, 0xfff},
+ { 0x181000, 4, 0x1f, 0x93c},
+ { 0x181010, 1020, 0x1f, 0x38},
+ { 0x182000, 4, 0x18, 0x924},
+ { 0x1a0000, 1, 0x1f, 0x92c},
+ { 0x1a0004, 5631, 0x1f, 0x8},
+ { 0x1a5800, 2560, 0x1e, 0x8},
+ { 0x1a8000, 1, 0x1f, 0x92c},
+ { 0x1a8004, 8191, 0x1e, 0x8},
+ { 0x1b0000, 1, 0x1f, 0x92c},
+ { 0x1b0004, 15, 0x2, 0x8},
+ { 0x1b0040, 1, 0x1e, 0x92c},
+ { 0x1b0044, 239, 0x2, 0x8},
+ { 0x1b0400, 1, 0x1f, 0x92c},
+ { 0x1b0404, 255, 0x2, 0x8},
+ { 0x1b0800, 1, 0x1f, 0x924},
+ { 0x1b0840, 1, 0x1e, 0x924},
+ { 0x1b0c00, 1, 0x1f, 0x1fff},
+ { 0x1b1000, 1, 0x1f, 0x1fff},
+ { 0x1b1040, 1, 0x1e, 0x1fff},
+ { 0x1b1400, 1, 0x1f, 0x924},
+ { 0x1b1440, 1, 0x1e, 0x924},
+ { 0x1b1480, 1, 0x1e, 0x924},
+ { 0x1b14c0, 1, 0x1e, 0x924},
+ { 0x1b1800, 128, 0x1f, 0x10},
+ { 0x1b1c00, 128, 0x1f, 0x10},
+ { 0x1b2000, 1, 0x1f, 0xdb6},
+ { 0x1b2400, 1, 0x1e, 0x92c},
+ { 0x1b2404, 5631, 0x1c, 0x8},
+ { 0x1b8000, 1, 0x1f, 0xfff},
+ { 0x1b8040, 1, 0x1f, 0xfff},
+ { 0x1b8080, 1, 0x1f, 0xfff},
+ { 0x1b80c0, 1, 0x1f, 0xfff},
+ { 0x1b8100, 1, 0x1f, 0x924},
+ { 0x1b8140, 1, 0x1f, 0x924},
+ { 0x1b8180, 1, 0x1f, 0x924},
+ { 0x1b81c0, 1, 0x1f, 0x924},
+ { 0x1b8200, 1, 0x1f, 0x924},
+ { 0x1b8240, 1, 0x1f, 0x924},
+ { 0x1b8280, 1, 0x1f, 0x924},
+ { 0x1b82c0, 1, 0x1f, 0x924},
+ { 0x1b8300, 1, 0x1f, 0x924},
+ { 0x1b8340, 1, 0x1f, 0x924},
+ { 0x1b8380, 1, 0x1f, 0x924},
+ { 0x1b83c0, 1, 0x1f, 0x924},
+ { 0x1b8400, 1, 0x1f, 0x924},
+ { 0x1b8440, 1, 0x1f, 0x924},
+ { 0x1b8480, 1, 0x1f, 0x924},
+ { 0x1b84c0, 1, 0x1f, 0x924},
+ { 0x1b8500, 1, 0x1f, 0x924},
+ { 0x1b8540, 1, 0x1f, 0x924},
+ { 0x1b8580, 1, 0x1f, 0x924},
+ { 0x1b85c0, 19, 0x1c, 0x924},
+ { 0x1b8800, 1, 0x1f, 0x924},
+ { 0x1b8840, 1, 0x1f, 0x924},
+ { 0x1b8880, 1, 0x1f, 0x924},
+ { 0x1b88c0, 1, 0x1f, 0x924},
+ { 0x1b8900, 1, 0x1f, 0x924},
+ { 0x1b8940, 1, 0x1f, 0x924},
+ { 0x1b8980, 1, 0x1f, 0x924},
+ { 0x1b89c0, 1, 0x1f, 0x924},
+ { 0x1b8a00, 1, 0x1f, 0x934},
+ { 0x1b8a40, 1, 0x1f, 0x924},
+ { 0x1b8a80, 1, 0x1f, 0x492},
+ { 0x1b8ac0, 1, 0x1f, 0x924},
+ { 0x1b8b00, 1, 0x1f, 0x924},
+ { 0x1b8b40, 1, 0x1f, 0x924},
+ { 0x1b8b80, 1, 0x1f, 0x924},
+ { 0x1b8bc0, 1, 0x1f, 0x924},
+ { 0x1b8c00, 1, 0x1f, 0x924},
+ { 0x1b8c40, 1, 0x1f, 0x924},
+ { 0x1b8c80, 1, 0x1f, 0x924},
+ { 0x1b8cc0, 1, 0x1f, 0x924},
+ { 0x1b8cc4, 1, 0x1c, 0x924},
+ { 0x1b8d00, 1, 0x1f, 0x924},
+ { 0x1b8d40, 1, 0x1f, 0x924},
+ { 0x1b8d80, 1, 0x1f, 0x924},
+ { 0x1b8dc0, 1, 0x1f, 0x924},
+ { 0x1b8e00, 1, 0x1f, 0x924},
+ { 0x1b8e40, 1, 0x1f, 0x924},
+ { 0x1b8e80, 1, 0x1f, 0x924},
+ { 0x1b8e84, 1, 0x1c, 0x924},
+ { 0x1b8ec0, 1, 0x1e, 0x924},
+ { 0x1b8f00, 1, 0x1e, 0x924},
+ { 0x1b8f40, 1, 0x1e, 0x924},
+ { 0x1b8f80, 1, 0x1e, 0x924},
+ { 0x1b8fc0, 1, 0x1e, 0x924},
+ { 0x1b8fd4, 5, 0x1c, 0x924},
+ { 0x1b8fe8, 2, 0x18, 0x924},
+ { 0x1b9000, 1, 0x1c, 0x924},
+ { 0x1b9040, 3, 0x1c, 0x924},
+ { 0x1b905c, 1, 0x18, 0x924},
+ { 0x1b9064, 1, 0x10, 0x924},
+ { 0x1b9080, 10, 0x10, 0x924},
+ { 0x1c0000, 2, 0x1f, 0x924},
+ { 0x200000, 65, 0x1f, 0x924},
+ { 0x200124, 2, 0x1f, 0x1fff},
+ { 0x200130, 3, 0x1f, 0x1fff},
+ { 0x200140, 1, 0x1f, 0x1fff},
+ { 0x20014c, 2, 0x1e, 0x924},
+ { 0x200200, 27, 0x1f, 0x924},
+ { 0x20026c, 1, 0x1f, 0xfff},
+ { 0x200270, 12, 0x1f, 0x924},
+ { 0x2002a0, 1, 0x1f, 0xfff},
+ { 0x2002a4, 17, 0x1f, 0x924},
+ { 0x200340, 4, 0x1f, 0x924},
+ { 0x200380, 1, 0x1c, 0x924},
+ { 0x200388, 1, 0x1c, 0x924},
+ { 0x200390, 1, 0x1c, 0x924},
+ { 0x200398, 1, 0x1c, 0x924},
+ { 0x2003a0, 1, 0x1c, 0x924},
+ { 0x2003a8, 2, 0x1c, 0x924},
+ { 0x200400, 256, 0x3, 0xfff},
+ { 0x202000, 4, 0x1f, 0x1927},
+ { 0x202010, 2044, 0x1f, 0x1007},
+ { 0x204000, 4, 0x18, 0x924},
+ { 0x220000, 1, 0x1f, 0x925},
+ { 0x220004, 5631, 0x1f, 0x1},
+ { 0x225800, 2560, 0x1e, 0x1},
+ { 0x228000, 1, 0x1f, 0x925},
+ { 0x228004, 8191, 0x1e, 0x1},
+ { 0x230000, 1, 0x1f, 0x925},
+ { 0x230004, 15, 0x2, 0x1},
+ { 0x230040, 1, 0x1e, 0x925},
+ { 0x230044, 239, 0x2, 0x1},
+ { 0x230400, 1, 0x1f, 0x925},
+ { 0x230404, 255, 0x2, 0x1},
+ { 0x230800, 1, 0x1f, 0x924},
+ { 0x230840, 1, 0x1e, 0x924},
+ { 0x230c00, 1, 0x1f, 0x924},
+ { 0x231000, 1, 0x1f, 0x924},
+ { 0x231040, 1, 0x1e, 0x924},
+ { 0x231400, 1, 0x1f, 0x924},
+ { 0x231440, 1, 0x1e, 0x924},
+ { 0x231480, 1, 0x1e, 0x924},
+ { 0x2314c0, 1, 0x1e, 0x924},
+ { 0x231800, 128, 0x1f, 0x2},
+ { 0x231c00, 128, 0x1f, 0x2},
+ { 0x232000, 1, 0x1f, 0xdb6},
+ { 0x232400, 1, 0x1e, 0x925},
+ { 0x232404, 5631, 0x1c, 0x1},
+ { 0x238000, 1, 0x1f, 0xfff},
+ { 0x238040, 1, 0x1f, 0xfff},
+ { 0x238080, 1, 0x1f, 0xfff},
+ { 0x2380c0, 1, 0x1f, 0xfff},
+ { 0x238100, 1, 0x1f, 0x924},
+ { 0x238140, 1, 0x1f, 0x924},
+ { 0x238180, 1, 0x1f, 0x924},
+ { 0x2381c0, 1, 0x1f, 0x924},
+ { 0x238200, 1, 0x1f, 0x924},
+ { 0x238240, 1, 0x1f, 0x924},
+ { 0x238280, 1, 0x1f, 0x924},
+ { 0x2382c0, 1, 0x1f, 0x924},
+ { 0x238300, 1, 0x1f, 0x924},
+ { 0x238340, 1, 0x1f, 0x924},
+ { 0x238380, 1, 0x1f, 0x924},
+ { 0x2383c0, 1, 0x1f, 0x924},
+ { 0x238400, 1, 0x1f, 0x924},
+ { 0x238440, 1, 0x1f, 0x924},
+ { 0x238480, 1, 0x1f, 0x924},
+ { 0x2384c0, 1, 0x1f, 0x924},
+ { 0x238500, 1, 0x1f, 0x924},
+ { 0x238540, 1, 0x1f, 0x924},
+ { 0x238580, 1, 0x1f, 0x924},
+ { 0x2385c0, 19, 0x1c, 0x924},
+ { 0x238800, 1, 0x1f, 0x924},
+ { 0x238840, 1, 0x1f, 0x924},
+ { 0x238880, 1, 0x1f, 0x924},
+ { 0x2388c0, 1, 0x1f, 0x924},
+ { 0x238900, 1, 0x1f, 0x924},
+ { 0x238940, 1, 0x1f, 0x924},
+ { 0x238980, 1, 0x1f, 0x924},
+ { 0x2389c0, 1, 0x1f, 0x924},
+ { 0x238a00, 1, 0x1f, 0x926},
+ { 0x238a40, 1, 0x1f, 0x924},
+ { 0x238a80, 1, 0x1f, 0x492},
+ { 0x238ac0, 1, 0x1f, 0x924},
+ { 0x238b00, 1, 0x1f, 0x924},
+ { 0x238b40, 1, 0x1f, 0x924},
+ { 0x238b80, 1, 0x1f, 0x924},
+ { 0x238bc0, 1, 0x1f, 0x924},
+ { 0x238c00, 1, 0x1f, 0x924},
+ { 0x238c40, 1, 0x1f, 0x924},
+ { 0x238c80, 1, 0x1f, 0x924},
+ { 0x238cc0, 1, 0x1f, 0x924},
+ { 0x238cc4, 1, 0x1c, 0x924},
+ { 0x238d00, 1, 0x1f, 0x924},
+ { 0x238d40, 1, 0x1f, 0x924},
+ { 0x238d80, 1, 0x1f, 0x924},
+ { 0x238dc0, 1, 0x1f, 0x924},
+ { 0x238e00, 1, 0x1f, 0x924},
+ { 0x238e40, 1, 0x1f, 0x924},
+ { 0x238e80, 1, 0x1f, 0x924},
+ { 0x238e84, 1, 0x1c, 0x924},
+ { 0x238ec0, 1, 0x1e, 0x924},
+ { 0x238f00, 1, 0x1e, 0x924},
+ { 0x238f40, 1, 0x1e, 0x924},
+ { 0x238f80, 1, 0x1e, 0x924},
+ { 0x238fc0, 1, 0x1e, 0x924},
+ { 0x238fd4, 5, 0x1c, 0x924},
+ { 0x238fe8, 2, 0x18, 0x924},
+ { 0x239000, 1, 0x1c, 0x924},
+ { 0x239040, 3, 0x1c, 0x924},
+ { 0x23905c, 1, 0x18, 0x924},
+ { 0x239064, 1, 0x10, 0x924},
+ { 0x239080, 10, 0x10, 0x924},
+ { 0x240000, 2, 0x1f, 0x924},
+ { 0x280000, 65, 0x1f, 0x924},
+ { 0x280124, 2, 0x1f, 0x1fff},
+ { 0x280130, 3, 0x1f, 0x1fff},
+ { 0x280140, 1, 0x1f, 0x1fff},
+ { 0x28014c, 2, 0x1e, 0x924},
+ { 0x280200, 27, 0x1f, 0x924},
+ { 0x28026c, 1, 0x1f, 0xfff},
+ { 0x280270, 12, 0x1f, 0x924},
+ { 0x2802a0, 1, 0x1f, 0xfff},
+ { 0x2802a4, 17, 0x1f, 0x924},
+ { 0x280340, 4, 0x1f, 0x924},
+ { 0x280380, 1, 0x1c, 0x924},
+ { 0x280388, 1, 0x1c, 0x924},
+ { 0x280390, 1, 0x1c, 0x924},
+ { 0x280398, 1, 0x1c, 0x924},
+ { 0x2803a0, 1, 0x1c, 0x924},
+ { 0x2803a8, 2, 0x1c, 0x924},
+ { 0x280400, 256, 0x3, 0xfff},
+ { 0x282000, 4, 0x1f, 0x9e4},
+ { 0x282010, 2044, 0x1f, 0x1c0},
+ { 0x284000, 4, 0x18, 0x924},
+ { 0x2a0000, 1, 0x1f, 0x964},
+ { 0x2a0004, 5631, 0x1f, 0x40},
+ { 0x2a5800, 2560, 0x1e, 0x40},
+ { 0x2a8000, 1, 0x1f, 0x964},
+ { 0x2a8004, 8191, 0x1e, 0x40},
+ { 0x2b0000, 1, 0x1f, 0x964},
+ { 0x2b0004, 15, 0x2, 0x40},
+ { 0x2b0040, 1, 0x1e, 0x964},
+ { 0x2b0044, 239, 0x2, 0x40},
+ { 0x2b0400, 1, 0x1f, 0x964},
+ { 0x2b0404, 255, 0x2, 0x40},
+ { 0x2b0800, 1, 0x1f, 0x924},
+ { 0x2b0840, 1, 0x1e, 0x924},
+ { 0x2b0c00, 1, 0x1f, 0x924},
+ { 0x2b1000, 1, 0x1f, 0x924},
+ { 0x2b1040, 1, 0x1e, 0x924},
+ { 0x2b1400, 1, 0x1f, 0x924},
+ { 0x2b1440, 1, 0x1e, 0x924},
+ { 0x2b1480, 1, 0x1e, 0x924},
+ { 0x2b14c0, 1, 0x1e, 0x924},
+ { 0x2b1800, 128, 0x1f, 0x80},
+ { 0x2b1c00, 128, 0x1f, 0x80},
+ { 0x2b2000, 1, 0x1f, 0xdb6},
+ { 0x2b2400, 1, 0x1e, 0x964},
+ { 0x2b2404, 5631, 0x1c, 0x40},
+ { 0x2b8000, 1, 0x1f, 0xfff},
+ { 0x2b8040, 1, 0x1f, 0xfff},
+ { 0x2b8080, 1, 0x1f, 0xfff},
+ { 0x2b80c0, 1, 0x1f, 0x924},
+ { 0x2b8100, 1, 0x1f, 0x924},
+ { 0x2b8140, 1, 0x1f, 0x924},
+ { 0x2b8180, 1, 0x1f, 0x924},
+ { 0x2b81c0, 1, 0x1f, 0x924},
+ { 0x2b8200, 1, 0x1f, 0x924},
+ { 0x2b8240, 1, 0x1f, 0x924},
+ { 0x2b8280, 1, 0x1f, 0x924},
+ { 0x2b82c0, 1, 0x1f, 0x924},
+ { 0x2b8300, 1, 0x1f, 0x924},
+ { 0x2b8340, 1, 0x1f, 0x924},
+ { 0x2b8380, 1, 0x1f, 0x924},
+ { 0x2b83c0, 1, 0x1f, 0x924},
+ { 0x2b8400, 1, 0x1f, 0x924},
+ { 0x2b8440, 1, 0x1f, 0x924},
+ { 0x2b8480, 1, 0x1f, 0x924},
+ { 0x2b84c0, 1, 0x1f, 0x924},
+ { 0x2b8500, 1, 0x1f, 0x924},
+ { 0x2b8540, 1, 0x1f, 0x924},
+ { 0x2b8580, 1, 0x1f, 0x924},
+ { 0x2b85c0, 19, 0x1c, 0x924},
+ { 0x2b8800, 1, 0x1f, 0x924},
+ { 0x2b8840, 1, 0x1f, 0x924},
+ { 0x2b8880, 1, 0x1f, 0x924},
+ { 0x2b88c0, 1, 0x1f, 0x924},
+ { 0x2b8900, 1, 0x1f, 0x924},
+ { 0x2b8940, 1, 0x1f, 0x924},
+ { 0x2b8980, 1, 0x1f, 0x924},
+ { 0x2b89c0, 1, 0x1f, 0x924},
+ { 0x2b8a00, 1, 0x1f, 0x9a4},
+ { 0x2b8a40, 1, 0x1f, 0x924},
+ { 0x2b8a80, 1, 0x1f, 0x492},
+ { 0x2b8ac0, 1, 0x1f, 0x924},
+ { 0x2b8b00, 1, 0x1f, 0x924},
+ { 0x2b8b40, 1, 0x1f, 0x924},
+ { 0x2b8b80, 1, 0x1f, 0x924},
+ { 0x2b8bc0, 1, 0x1f, 0x924},
+ { 0x2b8c00, 1, 0x1f, 0x924},
+ { 0x2b8c40, 1, 0x1f, 0x924},
+ { 0x2b8c80, 1, 0x1f, 0x924},
+ { 0x2b8cc0, 1, 0x1f, 0x924},
+ { 0x2b8cc4, 1, 0x1c, 0x924},
+ { 0x2b8d00, 1, 0x1f, 0x924},
+ { 0x2b8d40, 1, 0x1f, 0x924},
+ { 0x2b8d80, 1, 0x1f, 0x924},
+ { 0x2b8dc0, 1, 0x1f, 0x924},
+ { 0x2b8e00, 1, 0x1f, 0x924},
+ { 0x2b8e40, 1, 0x1f, 0x924},
+ { 0x2b8e80, 1, 0x1f, 0x924},
+ { 0x2b8e84, 1, 0x1c, 0x924},
+ { 0x2b8ec0, 1, 0x1e, 0x924},
+ { 0x2b8f00, 1, 0x1e, 0x924},
+ { 0x2b8f40, 1, 0x1e, 0x924},
+ { 0x2b8f80, 1, 0x1e, 0x924},
+ { 0x2b8fc0, 1, 0x1e, 0x924},
+ { 0x2b8fd4, 5, 0x1c, 0x924},
+ { 0x2b8fe8, 2, 0x18, 0x924},
+ { 0x2b9000, 1, 0x1c, 0x924},
+ { 0x2b9040, 3, 0x1c, 0x924},
+ { 0x2b905c, 1, 0x18, 0x924},
+ { 0x2b9064, 1, 0x10, 0x924},
+ { 0x2b9080, 10, 0x10, 0x924},
+ { 0x2c0000, 2, 0x1f, 0x1fff},
+ { 0x300000, 65, 0x1f, 0x924},
+ { 0x300124, 2, 0x1f, 0x1fff},
+ { 0x300130, 3, 0x1f, 0x1fff},
+ { 0x300140, 1, 0x1f, 0x1fff},
+ { 0x30014c, 2, 0x1e, 0x924},
+ { 0x300200, 27, 0x1f, 0x924},
+ { 0x30026c, 1, 0x1f, 0xfff},
+ { 0x300270, 12, 0x1f, 0x924},
+ { 0x3002a0, 1, 0x1f, 0xfff},
+ { 0x3002a4, 17, 0x1f, 0x924},
+ { 0x300340, 4, 0x1f, 0x924},
+ { 0x300380, 1, 0x1c, 0x924},
+ { 0x300388, 1, 0x1c, 0x924},
+ { 0x300390, 1, 0x1c, 0x924},
+ { 0x300398, 1, 0x1c, 0x924},
+ { 0x3003a0, 1, 0x1c, 0x924},
+ { 0x3003a8, 2, 0x1c, 0x924},
+ { 0x300400, 256, 0x3, 0xfff},
+ { 0x302000, 4, 0x1f, 0xf24},
+ { 0x302010, 2044, 0x1f, 0xe00},
+ { 0x304000, 4, 0x18, 0x924},
+ { 0x320000, 1, 0x1f, 0xb24},
+ { 0x320004, 5631, 0x1f, 0x200},
+ { 0x325800, 2560, 0x1e, 0x200},
+ { 0x328000, 1, 0x1f, 0xb24},
+ { 0x328004, 8191, 0x1e, 0x200},
+ { 0x330000, 1, 0x1f, 0xb24},
+ { 0x330004, 15, 0x2, 0x200},
+ { 0x330040, 1, 0x1e, 0xb24},
+ { 0x330044, 239, 0x2, 0x200},
+ { 0x330400, 1, 0x1f, 0xb24},
+ { 0x330404, 255, 0x2, 0x200},
+ { 0x330800, 1, 0x1f, 0x924},
+ { 0x330840, 1, 0x1e, 0x924},
+ { 0x330c00, 1, 0x1f, 0x924},
+ { 0x331000, 1, 0x1f, 0x924},
+ { 0x331040, 1, 0x1e, 0x924},
+ { 0x331400, 1, 0x1f, 0x924},
+ { 0x331440, 1, 0x1e, 0x924},
+ { 0x331480, 1, 0x1e, 0x924},
+ { 0x3314c0, 1, 0x1e, 0x924},
+ { 0x331800, 128, 0x1f, 0x400},
+ { 0x331c00, 128, 0x1f, 0x400},
+ { 0x332000, 1, 0x1f, 0xdb6},
+ { 0x332400, 1, 0x1e, 0xb24},
+ { 0x332404, 5631, 0x1c, 0x200},
+ { 0x338000, 1, 0x1f, 0xfff},
+ { 0x338040, 1, 0x1f, 0xfff},
+ { 0x338080, 1, 0x1f, 0xfff},
+ { 0x3380c0, 1, 0x1f, 0xfff},
+ { 0x338100, 1, 0x1f, 0x924},
+ { 0x338140, 1, 0x1f, 0x924},
+ { 0x338180, 1, 0x1f, 0x924},
+ { 0x3381c0, 1, 0x1f, 0x924},
+ { 0x338200, 1, 0x1f, 0x924},
+ { 0x338240, 1, 0x1f, 0x924},
+ { 0x338280, 1, 0x1f, 0x924},
+ { 0x3382c0, 1, 0x1f, 0x924},
+ { 0x338300, 1, 0x1f, 0x924},
+ { 0x338340, 1, 0x1f, 0x924},
+ { 0x338380, 1, 0x1f, 0x924},
+ { 0x3383c0, 1, 0x1f, 0x924},
+ { 0x338400, 1, 0x1f, 0x924},
+ { 0x338440, 1, 0x1f, 0x924},
+ { 0x338480, 1, 0x1f, 0x924},
+ { 0x3384c0, 1, 0x1f, 0x924},
+ { 0x338500, 1, 0x1f, 0x924},
+ { 0x338540, 1, 0x1f, 0x924},
+ { 0x338580, 1, 0x1f, 0x924},
+ { 0x3385c0, 19, 0x1c, 0x924},
+ { 0x338800, 1, 0x1f, 0x924},
+ { 0x338840, 1, 0x1f, 0x924},
+ { 0x338880, 1, 0x1f, 0x924},
+ { 0x3388c0, 1, 0x1f, 0x924},
+ { 0x338900, 1, 0x1f, 0x924},
+ { 0x338940, 1, 0x1f, 0x924},
+ { 0x338980, 1, 0x1f, 0x924},
+ { 0x3389c0, 1, 0x1f, 0x924},
+ { 0x338a00, 1, 0x1f, 0xd24},
+ { 0x338a40, 1, 0x1f, 0x924},
+ { 0x338a80, 1, 0x1f, 0x492},
+ { 0x338ac0, 1, 0x1f, 0x924},
+ { 0x338b00, 1, 0x1f, 0x924},
+ { 0x338b40, 1, 0x1f, 0x924},
+ { 0x338b80, 1, 0x1f, 0x924},
+ { 0x338bc0, 1, 0x1f, 0x924},
+ { 0x338c00, 1, 0x1f, 0x924},
+ { 0x338c40, 1, 0x1f, 0x924},
+ { 0x338c80, 1, 0x1f, 0x924},
+ { 0x338cc0, 1, 0x1f, 0x924},
+ { 0x338cc4, 1, 0x1c, 0x924},
+ { 0x338d00, 1, 0x1f, 0x924},
+ { 0x338d40, 1, 0x1f, 0x924},
+ { 0x338d80, 1, 0x1f, 0x924},
+ { 0x338dc0, 1, 0x1f, 0x924},
+ { 0x338e00, 1, 0x1f, 0x924},
+ { 0x338e40, 1, 0x1f, 0x924},
+ { 0x338e80, 1, 0x1f, 0x924},
+ { 0x338e84, 1, 0x1c, 0x924},
+ { 0x338ec0, 1, 0x1e, 0x924},
+ { 0x338f00, 1, 0x1e, 0x924},
+ { 0x338f40, 1, 0x1e, 0x924},
+ { 0x338f80, 1, 0x1e, 0x924},
+ { 0x338fc0, 1, 0x1e, 0x924},
+ { 0x338fd4, 5, 0x1c, 0x924},
+ { 0x338fe8, 2, 0x18, 0x924},
+ { 0x339000, 1, 0x1c, 0x924},
+ { 0x339040, 3, 0x1c, 0x924},
+ { 0x33905c, 1, 0x18, 0x924},
+ { 0x339064, 1, 0x10, 0x924},
+ { 0x339080, 10, 0x10, 0x924},
+ { 0x340000, 2, 0x1f, 0x924},
+ { 0x3a0000, 40960, 0x1c, 0x1000}
};
-#define REGS_COUNT ARRAY_SIZE(reg_addrs)
-static const struct dump_sign dump_sign_all = { 0x4e23fde1, 0x70017, 0x3a };
+#define REGS_COUNT ARRAY_SIZE(reg_addrs)
-static const u32 page_vals_e2[] = { 0, 128 };
-#define PAGE_MODE_VALUES_E2 ARRAY_SIZE(page_vals_e2)
+static const struct reg_addr idle_reg_addrs[] = {
+ { 0x2104, 1, 0x1f, 0xfff},
+ { 0x2110, 2, 0x1f, 0xfff},
+ { 0x211c, 8, 0x1f, 0xfff},
+ { 0x2814, 1, 0x1f, 0xfff},
+ { 0x281c, 2, 0x1f, 0xfff},
+ { 0x2854, 1, 0x1f, 0xfff},
+ { 0x285c, 1, 0x1f, 0xfff},
+ { 0x3040, 1, 0x1f, 0xfff},
+ { 0x9010, 7, 0x1c, 0xfff},
+ { 0x9030, 1, 0x1c, 0xfff},
+ { 0x9068, 16, 0x1c, 0xfff},
+ { 0x9230, 2, 0x1c, 0xfff},
+ { 0x9244, 1, 0x1c, 0xfff},
+ { 0x9298, 1, 0x1c, 0xfff},
+ { 0x92a8, 1, 0x1c, 0x1fff},
+ { 0xa38c, 1, 0x1f, 0x1fff},
+ { 0xa3c4, 1, 0x1e, 0xfff},
+ { 0xa404, 1, 0x1f, 0xfff},
+ { 0xa408, 2, 0x1f, 0x1fff},
+ { 0xa42c, 12, 0x1f, 0xfff},
+ { 0xa580, 1, 0x1f, 0x1fff},
+ { 0xa590, 1, 0x1f, 0x1fff},
+ { 0xa600, 5, 0x1e, 0xfff},
+ { 0xa618, 1, 0x1e, 0xfff},
+ { 0xa714, 1, 0x1c, 0xfff},
+ { 0xa720, 1, 0x1c, 0xfff},
+ { 0xa750, 1, 0x1c, 0xfff},
+ { 0xc09c, 1, 0x3, 0xfff},
+ { 0x103b0, 1, 0x1f, 0xfff},
+ { 0x103c0, 1, 0x1f, 0xfff},
+ { 0x103d0, 1, 0x3, 0x1fff},
+ { 0x10418, 1, 0x1f, 0xfff},
+ { 0x10420, 1, 0x1f, 0xfff},
+ { 0x10428, 1, 0x1f, 0xfff},
+ { 0x10460, 1, 0x1f, 0xfff},
+ { 0x10474, 1, 0x1f, 0xfff},
+ { 0x104e0, 1, 0x1f, 0xfff},
+ { 0x104ec, 1, 0x1f, 0xfff},
+ { 0x104f8, 1, 0x1f, 0xfff},
+ { 0x10508, 1, 0x1f, 0xfff},
+ { 0x10530, 1, 0x1f, 0xfff},
+ { 0x10538, 1, 0x1f, 0xfff},
+ { 0x10548, 1, 0x1f, 0xfff},
+ { 0x10558, 1, 0x1f, 0xfff},
+ { 0x182a8, 1, 0x1c, 0xfff},
+ { 0x182b8, 1, 0x1c, 0xfff},
+ { 0x18308, 1, 0x1c, 0xfff},
+ { 0x18318, 1, 0x1c, 0xfff},
+ { 0x18338, 1, 0x1c, 0xfff},
+ { 0x18348, 1, 0x1c, 0xfff},
+ { 0x183bc, 1, 0x1c, 0x1fff},
+ { 0x183cc, 1, 0x1c, 0x1fff},
+ { 0x18570, 1, 0x18, 0xfff},
+ { 0x18578, 1, 0x18, 0xfff},
+ { 0x1858c, 1, 0x18, 0xfff},
+ { 0x18594, 1, 0x18, 0xfff},
+ { 0x1862c, 4, 0x10, 0xfff},
+ { 0x2021c, 11, 0x1f, 0xfff},
+ { 0x202a8, 1, 0x1f, 0xfff},
+ { 0x202b8, 1, 0x1f, 0x1fff},
+ { 0x20404, 1, 0x1f, 0xfff},
+ { 0x2040c, 2, 0x1f, 0xfff},
+ { 0x2041c, 2, 0x1f, 0xfff},
+ { 0x40154, 14, 0x1f, 0xfff},
+ { 0x40198, 1, 0x1f, 0x1fff},
+ { 0x404ac, 1, 0x1f, 0xfff},
+ { 0x404bc, 1, 0x1f, 0x1fff},
+ { 0x42290, 1, 0x1f, 0xfff},
+ { 0x422a0, 1, 0x1f, 0xfff},
+ { 0x422b0, 1, 0x1f, 0x1fff},
+ { 0x42548, 1, 0x1f, 0xfff},
+ { 0x42550, 1, 0x1f, 0xfff},
+ { 0x42558, 1, 0x1f, 0xfff},
+ { 0x50160, 8, 0x1f, 0xfff},
+ { 0x501d0, 1, 0x1f, 0xfff},
+ { 0x501e0, 1, 0x1f, 0x1fff},
+ { 0x50204, 1, 0x1f, 0xfff},
+ { 0x5020c, 2, 0x1f, 0xfff},
+ { 0x5021c, 1, 0x1f, 0xfff},
+ { 0x60090, 1, 0x1f, 0xfff},
+ { 0x6011c, 1, 0x1f, 0xfff},
+ { 0x6012c, 1, 0x1f, 0x1fff},
+ { 0xc101c, 1, 0x1f, 0xfff},
+ { 0xc102c, 1, 0x1f, 0x1fff},
+ { 0xc2290, 1, 0x1f, 0xfff},
+ { 0xc22a0, 1, 0x1f, 0xfff},
+ { 0xc22b0, 1, 0x1f, 0x1fff},
+ { 0xc2548, 1, 0x1f, 0xfff},
+ { 0xc2550, 1, 0x1f, 0xfff},
+ { 0xc2558, 1, 0x1f, 0xfff},
+ { 0xc4294, 1, 0x1f, 0xfff},
+ { 0xc42a4, 1, 0x1f, 0xfff},
+ { 0xc42b4, 1, 0x1f, 0x1fff},
+ { 0xc4550, 1, 0x1f, 0xfff},
+ { 0xc4558, 1, 0x1f, 0xfff},
+ { 0xc4560, 1, 0x1f, 0xfff},
+ { 0xd016c, 8, 0x1f, 0xfff},
+ { 0xd01d8, 1, 0x1f, 0xfff},
+ { 0xd01e8, 1, 0x1f, 0x1fff},
+ { 0xd0204, 1, 0x1f, 0xfff},
+ { 0xd020c, 3, 0x1f, 0xfff},
+ { 0xe0154, 8, 0x1f, 0xfff},
+ { 0xe01c8, 1, 0x1f, 0xfff},
+ { 0xe01d8, 1, 0x1f, 0x1fff},
+ { 0xe0204, 1, 0x1f, 0xfff},
+ { 0xe020c, 2, 0x1f, 0xfff},
+ { 0xe021c, 2, 0x1f, 0xfff},
+ { 0x101014, 1, 0x1f, 0xfff},
+ { 0x101030, 1, 0x1f, 0xfff},
+ { 0x101040, 1, 0x1f, 0x1fff},
+ { 0x102058, 1, 0x1f, 0x1fff},
+ { 0x102080, 16, 0x1f, 0xfff},
+ { 0x103004, 2, 0x1f, 0xfff},
+ { 0x103068, 1, 0x1f, 0xfff},
+ { 0x103078, 1, 0x1f, 0xfff},
+ { 0x103088, 1, 0x1f, 0x1fff},
+ { 0x10309c, 2, 0x1e, 0xfff},
+ { 0x1030b8, 2, 0x1c, 0xfff},
+ { 0x1030cc, 1, 0x1c, 0xfff},
+ { 0x1030e0, 1, 0x1c, 0xfff},
+ { 0x104004, 1, 0x1f, 0xfff},
+ { 0x104018, 1, 0x1f, 0xfff},
+ { 0x104020, 1, 0x1f, 0xfff},
+ { 0x10403c, 1, 0x1f, 0xfff},
+ { 0x1040fc, 1, 0x1f, 0xfff},
+ { 0x10410c, 1, 0x1f, 0x1fff},
+ { 0x104400, 1, 0x1f, 0x1fff},
+ { 0x104404, 63, 0x1f, 0xfff},
+ { 0x104800, 1, 0x1f, 0x1fff},
+ { 0x104804, 63, 0x1f, 0xfff},
+ { 0x105000, 4, 0x1f, 0x1fff},
+ { 0x105010, 252, 0x1f, 0xfff},
+ { 0x108094, 1, 0x3, 0xfff},
+ { 0x1201b0, 2, 0x1f, 0xfff},
+ { 0x12032c, 1, 0x1f, 0xfff},
+ { 0x12036c, 3, 0x1f, 0xfff},
+ { 0x120408, 2, 0x1f, 0xfff},
+ { 0x120414, 15, 0x1f, 0xfff},
+ { 0x120478, 2, 0x1f, 0xfff},
+ { 0x12052c, 1, 0x1f, 0xfff},
+ { 0x120564, 3, 0x1f, 0xfff},
+ { 0x12057c, 1, 0x1f, 0x1fff},
+ { 0x12058c, 1, 0x1f, 0x1fff},
+ { 0x120608, 1, 0x1e, 0xfff},
+ { 0x120748, 1, 0x1c, 0xfff},
+ { 0x120778, 2, 0x1c, 0xfff},
+ { 0x120808, 3, 0x1f, 0xfff},
+ { 0x120818, 1, 0x1f, 0xfff},
+ { 0x120820, 1, 0x1f, 0xfff},
+ { 0x120828, 1, 0x1f, 0xfff},
+ { 0x120830, 1, 0x1f, 0xfff},
+ { 0x120838, 1, 0x1f, 0xfff},
+ { 0x120840, 1, 0x1f, 0xfff},
+ { 0x120848, 1, 0x1f, 0xfff},
+ { 0x120850, 1, 0x1f, 0xfff},
+ { 0x120858, 1, 0x1f, 0xfff},
+ { 0x120860, 1, 0x1f, 0xfff},
+ { 0x120868, 1, 0x1f, 0xfff},
+ { 0x120870, 1, 0x1f, 0xfff},
+ { 0x120878, 1, 0x1f, 0xfff},
+ { 0x120880, 1, 0x1f, 0xfff},
+ { 0x120888, 1, 0x1f, 0xfff},
+ { 0x120890, 1, 0x1f, 0xfff},
+ { 0x120898, 1, 0x1f, 0xfff},
+ { 0x1208a0, 1, 0x1f, 0xfff},
+ { 0x1208a8, 1, 0x1f, 0xfff},
+ { 0x1208b0, 1, 0x1f, 0xfff},
+ { 0x1208b8, 1, 0x1f, 0xfff},
+ { 0x1208c0, 1, 0x1f, 0xfff},
+ { 0x1208c8, 1, 0x1f, 0xfff},
+ { 0x1208d0, 1, 0x1f, 0xfff},
+ { 0x1208d8, 1, 0x1f, 0xfff},
+ { 0x1208e0, 1, 0x1f, 0xfff},
+ { 0x1208e8, 1, 0x1f, 0xfff},
+ { 0x1208f0, 1, 0x1f, 0xfff},
+ { 0x1208f8, 1, 0x1f, 0xfff},
+ { 0x120900, 1, 0x1f, 0xfff},
+ { 0x120908, 1, 0x1f, 0xfff},
+ { 0x130030, 1, 0x1c, 0xfff},
+ { 0x13004c, 3, 0x1c, 0xfff},
+ { 0x130064, 2, 0x1c, 0xfff},
+ { 0x13009c, 1, 0x1c, 0x1fff},
+ { 0x130130, 1, 0x1c, 0xfff},
+ { 0x13016c, 1, 0x1c, 0xfff},
+ { 0x130300, 1, 0x1c, 0xfff},
+ { 0x130480, 1, 0x1c, 0xfff},
+ { 0x14005c, 2, 0xf, 0xfff},
+ { 0x1400d0, 2, 0xf, 0xfff},
+ { 0x1400e0, 1, 0xf, 0xfff},
+ { 0x1401c8, 1, 0xf, 0xfff},
+ { 0x140200, 6, 0xf, 0xfff},
+ { 0x140338, 7, 0x10, 0xfff},
+ { 0x140370, 7, 0x10, 0xfff},
+ { 0x15c1bc, 6, 0x10, 0xfff},
+ { 0x15c230, 7, 0x10, 0xfff},
+ { 0x16101c, 1, 0x1f, 0xfff},
+ { 0x16102c, 1, 0x1f, 0x1fff},
+ { 0x164014, 2, 0x1f, 0xfff},
+ { 0x1640f0, 1, 0x1f, 0xfff},
+ { 0x166290, 1, 0x1f, 0xfff},
+ { 0x1662a0, 1, 0x1f, 0xfff},
+ { 0x1662b0, 1, 0x1f, 0x1fff},
+ { 0x166548, 1, 0x1f, 0xfff},
+ { 0x166550, 1, 0x1f, 0xfff},
+ { 0x166558, 1, 0x1f, 0xfff},
+ { 0x168000, 1, 0x1f, 0xfff},
+ { 0x168008, 1, 0x1f, 0xfff},
+ { 0x168010, 1, 0x1f, 0xfff},
+ { 0x168018, 1, 0x1f, 0xfff},
+ { 0x168028, 2, 0x1f, 0xfff},
+ { 0x168058, 9, 0x1f, 0xfff},
+ { 0x168238, 1, 0x1f, 0xfff},
+ { 0x1682d0, 7, 0x1f, 0xfff},
+ { 0x168300, 2, 0x3, 0xfff},
+ { 0x168308, 65, 0x1f, 0xfff},
+ { 0x168410, 2, 0x1f, 0xfff},
+ { 0x168438, 1, 0x1f, 0xfff},
+ { 0x168448, 1, 0x1f, 0x1fff},
+ { 0x168a00, 128, 0x1f, 0xfff},
+ { 0x16e200, 128, 0x2, 0xfff},
+ { 0x16e404, 2, 0x2, 0xfff},
+ { 0x16e584, 64, 0x2, 0xfff},
+ { 0x16e684, 2, 0x1e, 0xfff},
+ { 0x16e68c, 4, 0x2, 0xfff},
+ { 0x16e6fc, 4, 0x1c, 0xfff},
+ { 0x16e7ac, 12, 0x10, 0xfff},
+ { 0x1700a4, 1, 0x1f, 0xfff},
+ { 0x1700ac, 2, 0x1f, 0xfff},
+ { 0x1700c0, 1, 0x1f, 0xfff},
+ { 0x170174, 1, 0x1f, 0xfff},
+ { 0x170184, 1, 0x1f, 0x1fff},
+ { 0x1800f4, 1, 0x1f, 0xfff},
+ { 0x180104, 1, 0x1f, 0xfff},
+ { 0x180114, 1, 0x1f, 0x1fff},
+ { 0x180124, 1, 0x1f, 0x1fff},
+ { 0x18026c, 1, 0x1f, 0xfff},
+ { 0x1802a0, 1, 0x1f, 0xfff},
+ { 0x1b8000, 1, 0x1f, 0xfff},
+ { 0x1b8040, 1, 0x1f, 0xfff},
+ { 0x1b8080, 1, 0x1f, 0xfff},
+ { 0x1b80c0, 1, 0x1f, 0xfff},
+ { 0x200104, 1, 0x1f, 0xfff},
+ { 0x200114, 1, 0x1f, 0xfff},
+ { 0x200124, 1, 0x1f, 0x1fff},
+ { 0x200134, 1, 0x1f, 0x1fff},
+ { 0x20026c, 1, 0x1f, 0xfff},
+ { 0x2002a0, 1, 0x1f, 0xfff},
+ { 0x238000, 1, 0x1f, 0xfff},
+ { 0x238040, 1, 0x1f, 0xfff},
+ { 0x238080, 1, 0x1f, 0xfff},
+ { 0x2380c0, 1, 0x1f, 0xfff},
+ { 0x280104, 1, 0x1f, 0xfff},
+ { 0x280114, 1, 0x1f, 0xfff},
+ { 0x280124, 1, 0x1f, 0x1fff},
+ { 0x280134, 1, 0x1f, 0x1fff},
+ { 0x28026c, 1, 0x1f, 0xfff},
+ { 0x2802a0, 1, 0x1f, 0xfff},
+ { 0x2b8000, 1, 0x1f, 0xfff},
+ { 0x2b8040, 1, 0x1f, 0xfff},
+ { 0x2b8080, 1, 0x1f, 0xfff},
+ { 0x300104, 1, 0x1f, 0xfff},
+ { 0x300114, 1, 0x1f, 0xfff},
+ { 0x300124, 1, 0x1f, 0x1fff},
+ { 0x300134, 1, 0x1f, 0x1fff},
+ { 0x30026c, 1, 0x1f, 0xfff},
+ { 0x3002a0, 1, 0x1f, 0xfff},
+ { 0x338000, 1, 0x1f, 0xfff},
+ { 0x338040, 1, 0x1f, 0xfff},
+ { 0x338080, 1, 0x1f, 0xfff},
+ { 0x3380c0, 1, 0x1f, 0xfff}
+};
-static const u32 page_write_regs_e2[] = { 328476 };
-#define PAGE_WRITE_REGS_E2 ARRAY_SIZE(page_write_regs_e2)
+#define IDLE_REGS_COUNT ARRAY_SIZE(idle_reg_addrs)
-static const struct reg_addr page_read_regs_e2[] = {
- { 0x58000, 4608, RI_E2_ONLINE } };
-#define PAGE_READ_REGS_E2 ARRAY_SIZE(page_read_regs_e2)
+static const u32 read_reg_e1[] = {
+ 0x1b1000};
-static const u32 page_vals_e3[] = { 0, 128 };
-#define PAGE_MODE_VALUES_E3 ARRAY_SIZE(page_vals_e3)
+static const struct wreg_addr wreg_addr_e1 = {
+ 0x1b0c00, 192, 1, read_reg_e1, 0x1f, 0x1fff};
-static const u32 page_write_regs_e3[] = { 328476 };
-#define PAGE_WRITE_REGS_E3 ARRAY_SIZE(page_write_regs_e3)
+static const u32 read_reg_e1h[] = {
+ 0x1b1040, 0x1b1000};
-static const struct reg_addr page_read_regs_e3[] = {
- { 0x58000, 4608, RI_E3E3B0_ONLINE } };
-#define PAGE_READ_REGS_E3 ARRAY_SIZE(page_read_regs_e3)
+static const struct wreg_addr wreg_addr_e1h = {
+ 0x1b0c00, 256, 2, read_reg_e1h, 0x1f, 0x1fff};
+
+static const u32 read_reg_e2[] = {
+ 0x1b1040, 0x1b1000};
+
+static const struct wreg_addr wreg_addr_e2 = {
+ 0x1b0c00, 128, 2, read_reg_e2, 0x1f, 0x1fff};
-#endif /* BNX2X_DUMP_H */
+static const u32 read_reg_e3[] = {
+ 0x1b1040, 0x1b1000};
+
+static const struct wreg_addr wreg_addr_e3 = {
+ 0x1b0c00, 128, 2, read_reg_e3, 0x1f, 0x1fff};
+
+static const u32 read_reg_e3b0[] = {
+ 0x1b1040, 0x1b1000};
+
+static const struct wreg_addr wreg_addr_e3b0 = {
+ 0x1b0c00, 128, 2, read_reg_e3b0, 0x1f, 0x1fff};
+
+static const unsigned int dump_num_registers[NUM_CHIPS][NUM_PRESETS] = {
+ {20782, 18567, 27975, 19729, 18311, 27719, 20836, 32391, 41799, 20812,
+ 26247, 35655, 19074},
+ {32774, 19297, 33277, 31721, 19041, 33021, 32828, 33121, 47101, 32804,
+ 26977, 40957, 35895},
+ {36527, 17928, 33697, 35474, 18700, 34466, 36581, 31752, 47521, 36557,
+ 25608, 41377, 43903},
+ {45239, 17936, 34387, 44186, 18708, 35156, 45293, 31760, 48211, 45269,
+ 25616, 42067, 43903},
+ {45302, 17999, 34802, 44249, 18771, 35571, 45356, 31823, 48626, 45332,
+ 25679, 42482, 43903}
+};
+#endif
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index a427b49a886c..9a674b14b403 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -1,6 +1,6 @@
/* bnx2x_ethtool.c: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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
@@ -186,6 +186,7 @@ static const struct {
};
#define BNX2X_NUM_STATS ARRAY_SIZE(bnx2x_stats_arr)
+
static int bnx2x_get_port_type(struct bnx2x *bp)
{
int port_type;
@@ -233,7 +234,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if ((bp->state == BNX2X_STATE_OPEN) && bp->link_vars.link_up &&
!(bp->flags & MF_FUNC_DIS)) {
- cmd->duplex = bp->link_vars.duplex;
+ cmd->duplex = bp->link_vars.duplex;
if (IS_MF(bp) && !BP_NOMCP(bp))
ethtool_cmd_speed_set(cmd, bnx2x_get_mf_speed(bp));
@@ -399,7 +400,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
DP(BNX2X_MSG_ETHTOOL, "Unsupported port type\n");
return -EINVAL;
}
- /* Save new config in case command complete successully */
+ /* Save new config in case command complete successfully */
new_multi_phy_config = bp->link_params.multi_phy_config;
/* Get the new cfg_idx */
cfg_idx = bnx2x_get_link_cfg_idx(bp);
@@ -596,29 +597,58 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return 0;
}
-#define IS_E1_ONLINE(info) (((info) & RI_E1_ONLINE) == RI_E1_ONLINE)
-#define IS_E1H_ONLINE(info) (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE)
-#define IS_E2_ONLINE(info) (((info) & RI_E2_ONLINE) == RI_E2_ONLINE)
-#define IS_E3_ONLINE(info) (((info) & RI_E3_ONLINE) == RI_E3_ONLINE)
-#define IS_E3B0_ONLINE(info) (((info) & RI_E3B0_ONLINE) == RI_E3B0_ONLINE)
+#define DUMP_ALL_PRESETS 0x1FFF
+#define DUMP_MAX_PRESETS 13
-static bool bnx2x_is_reg_online(struct bnx2x *bp,
- const struct reg_addr *reg_info)
+static int __bnx2x_get_preset_regs_len(struct bnx2x *bp, u32 preset)
{
if (CHIP_IS_E1(bp))
- return IS_E1_ONLINE(reg_info->info);
+ return dump_num_registers[0][preset-1];
else if (CHIP_IS_E1H(bp))
- return IS_E1H_ONLINE(reg_info->info);
+ return dump_num_registers[1][preset-1];
else if (CHIP_IS_E2(bp))
- return IS_E2_ONLINE(reg_info->info);
+ return dump_num_registers[2][preset-1];
else if (CHIP_IS_E3A0(bp))
- return IS_E3_ONLINE(reg_info->info);
+ return dump_num_registers[3][preset-1];
else if (CHIP_IS_E3B0(bp))
- return IS_E3B0_ONLINE(reg_info->info);
+ return dump_num_registers[4][preset-1];
else
- return false;
+ return 0;
+}
+
+static int __bnx2x_get_regs_len(struct bnx2x *bp)
+{
+ u32 preset_idx;
+ int regdump_len = 0;
+
+ /* Calculate the total preset regs length */
+ for (preset_idx = 1; preset_idx <= DUMP_MAX_PRESETS; preset_idx++)
+ regdump_len += __bnx2x_get_preset_regs_len(bp, preset_idx);
+
+ return regdump_len;
+}
+
+static int bnx2x_get_regs_len(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int regdump_len = 0;
+
+ regdump_len = __bnx2x_get_regs_len(bp);
+ regdump_len *= 4;
+ regdump_len += sizeof(struct dump_header);
+
+ return regdump_len;
}
+#define IS_E1_REG(chips) ((chips & DUMP_CHIP_E1) == DUMP_CHIP_E1)
+#define IS_E1H_REG(chips) ((chips & DUMP_CHIP_E1H) == DUMP_CHIP_E1H)
+#define IS_E2_REG(chips) ((chips & DUMP_CHIP_E2) == DUMP_CHIP_E2)
+#define IS_E3A0_REG(chips) ((chips & DUMP_CHIP_E3A0) == DUMP_CHIP_E3A0)
+#define IS_E3B0_REG(chips) ((chips & DUMP_CHIP_E3B0) == DUMP_CHIP_E3B0)
+
+#define IS_REG_IN_PRESET(presets, idx) \
+ ((presets & (1 << (idx-1))) == (1 << (idx-1)))
+
/******* Paged registers info selectors ********/
static const u32 *__bnx2x_get_page_addr_ar(struct bnx2x *bp)
{
@@ -680,38 +710,39 @@ static u32 __bnx2x_get_page_read_num(struct bnx2x *bp)
return 0;
}
-static int __bnx2x_get_regs_len(struct bnx2x *bp)
+static bool bnx2x_is_reg_in_chip(struct bnx2x *bp,
+ const struct reg_addr *reg_info)
{
- int num_pages = __bnx2x_get_page_reg_num(bp);
- int page_write_num = __bnx2x_get_page_write_num(bp);
- const struct reg_addr *page_read_addr = __bnx2x_get_page_read_ar(bp);
- int page_read_num = __bnx2x_get_page_read_num(bp);
- int regdump_len = 0;
- int i, j, k;
-
- for (i = 0; i < REGS_COUNT; i++)
- if (bnx2x_is_reg_online(bp, &reg_addrs[i]))
- regdump_len += reg_addrs[i].size;
-
- for (i = 0; i < num_pages; i++)
- for (j = 0; j < page_write_num; j++)
- for (k = 0; k < page_read_num; k++)
- if (bnx2x_is_reg_online(bp, &page_read_addr[k]))
- regdump_len += page_read_addr[k].size;
-
- return regdump_len;
+ if (CHIP_IS_E1(bp))
+ return IS_E1_REG(reg_info->chips);
+ else if (CHIP_IS_E1H(bp))
+ return IS_E1H_REG(reg_info->chips);
+ else if (CHIP_IS_E2(bp))
+ return IS_E2_REG(reg_info->chips);
+ else if (CHIP_IS_E3A0(bp))
+ return IS_E3A0_REG(reg_info->chips);
+ else if (CHIP_IS_E3B0(bp))
+ return IS_E3B0_REG(reg_info->chips);
+ else
+ return false;
}
-static int bnx2x_get_regs_len(struct net_device *dev)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int regdump_len = 0;
- regdump_len = __bnx2x_get_regs_len(bp);
- regdump_len *= 4;
- regdump_len += sizeof(struct dump_hdr);
-
- return regdump_len;
+static bool bnx2x_is_wreg_in_chip(struct bnx2x *bp,
+ const struct wreg_addr *wreg_info)
+{
+ if (CHIP_IS_E1(bp))
+ return IS_E1_REG(wreg_info->chips);
+ else if (CHIP_IS_E1H(bp))
+ return IS_E1H_REG(wreg_info->chips);
+ else if (CHIP_IS_E2(bp))
+ return IS_E2_REG(wreg_info->chips);
+ else if (CHIP_IS_E3A0(bp))
+ return IS_E3A0_REG(wreg_info->chips);
+ else if (CHIP_IS_E3B0(bp))
+ return IS_E3B0_REG(wreg_info->chips);
+ else
+ return false;
}
/**
@@ -725,9 +756,10 @@ static int bnx2x_get_regs_len(struct net_device *dev)
* ("read address"). There may be more than one write address per "page" and
* more than one read address per write address.
*/
-static void bnx2x_read_pages_regs(struct bnx2x *bp, u32 *p)
+static void bnx2x_read_pages_regs(struct bnx2x *bp, u32 *p, u32 preset)
{
u32 i, j, k, n;
+
/* addresses of the paged registers */
const u32 *page_addr = __bnx2x_get_page_addr_ar(bp);
/* number of paged registers */
@@ -740,32 +772,100 @@ static void bnx2x_read_pages_regs(struct bnx2x *bp, u32 *p)
const struct reg_addr *read_addr = __bnx2x_get_page_read_ar(bp);
/* number of read addresses */
int read_num = __bnx2x_get_page_read_num(bp);
+ u32 addr, size;
for (i = 0; i < num_pages; i++) {
for (j = 0; j < write_num; j++) {
REG_WR(bp, write_addr[j], page_addr[i]);
- for (k = 0; k < read_num; k++)
- if (bnx2x_is_reg_online(bp, &read_addr[k]))
- for (n = 0; n <
- read_addr[k].size; n++)
- *p++ = REG_RD(bp,
- read_addr[k].addr + n*4);
+
+ for (k = 0; k < read_num; k++) {
+ if (IS_REG_IN_PRESET(read_addr[k].presets,
+ preset)) {
+ size = read_addr[k].size;
+ for (n = 0; n < size; n++) {
+ addr = read_addr[k].addr + n*4;
+ *p++ = REG_RD(bp, addr);
+ }
+ }
+ }
}
}
}
-static void __bnx2x_get_regs(struct bnx2x *bp, u32 *p)
+static int __bnx2x_get_preset_regs(struct bnx2x *bp, u32 *p, u32 preset)
{
- u32 i, j;
+ u32 i, j, addr;
+ const struct wreg_addr *wreg_addr_p = NULL;
+
+ if (CHIP_IS_E1(bp))
+ wreg_addr_p = &wreg_addr_e1;
+ else if (CHIP_IS_E1H(bp))
+ wreg_addr_p = &wreg_addr_e1h;
+ else if (CHIP_IS_E2(bp))
+ wreg_addr_p = &wreg_addr_e2;
+ else if (CHIP_IS_E3A0(bp))
+ wreg_addr_p = &wreg_addr_e3;
+ else if (CHIP_IS_E3B0(bp))
+ wreg_addr_p = &wreg_addr_e3b0;
+
+ /* Read the idle_chk registers */
+ for (i = 0; i < IDLE_REGS_COUNT; i++) {
+ if (bnx2x_is_reg_in_chip(bp, &idle_reg_addrs[i]) &&
+ IS_REG_IN_PRESET(idle_reg_addrs[i].presets, preset)) {
+ for (j = 0; j < idle_reg_addrs[i].size; j++)
+ *p++ = REG_RD(bp, idle_reg_addrs[i].addr + j*4);
+ }
+ }
/* Read the regular registers */
- for (i = 0; i < REGS_COUNT; i++)
- if (bnx2x_is_reg_online(bp, &reg_addrs[i]))
+ for (i = 0; i < REGS_COUNT; i++) {
+ if (bnx2x_is_reg_in_chip(bp, &reg_addrs[i]) &&
+ IS_REG_IN_PRESET(reg_addrs[i].presets, preset)) {
for (j = 0; j < reg_addrs[i].size; j++)
*p++ = REG_RD(bp, reg_addrs[i].addr + j*4);
+ }
+ }
+
+ /* Read the CAM registers */
+ if (bnx2x_is_wreg_in_chip(bp, wreg_addr_p) &&
+ IS_REG_IN_PRESET(wreg_addr_p->presets, preset)) {
+ for (i = 0; i < wreg_addr_p->size; i++) {
+ *p++ = REG_RD(bp, wreg_addr_p->addr + i*4);
- /* Read "paged" registes */
- bnx2x_read_pages_regs(bp, p);
+ /* In case of wreg_addr register, read additional
+ registers from read_regs array
+ */
+ for (j = 0; j < wreg_addr_p->read_regs_count; j++) {
+ addr = *(wreg_addr_p->read_regs);
+ *p++ = REG_RD(bp, addr + j*4);
+ }
+ }
+ }
+
+ /* Paged registers are supported in E2 & E3 only */
+ if (CHIP_IS_E2(bp) || CHIP_IS_E3(bp)) {
+ /* Read "paged" registes */
+ bnx2x_read_pages_regs(bp, p, preset);
+ }
+
+ return 0;
+}
+
+static void __bnx2x_get_regs(struct bnx2x *bp, u32 *p)
+{
+ u32 preset_idx;
+
+ /* Read all registers, by reading all preset registers */
+ for (preset_idx = 1; preset_idx <= DUMP_MAX_PRESETS; preset_idx++) {
+ /* Skip presets with IOR */
+ if ((preset_idx == 2) ||
+ (preset_idx == 5) ||
+ (preset_idx == 8) ||
+ (preset_idx == 11))
+ continue;
+ __bnx2x_get_preset_regs(bp, p, preset_idx);
+ p += __bnx2x_get_preset_regs_len(bp, preset_idx);
+ }
}
static void bnx2x_get_regs(struct net_device *dev,
@@ -773,9 +873,9 @@ static void bnx2x_get_regs(struct net_device *dev,
{
u32 *p = _p;
struct bnx2x *bp = netdev_priv(dev);
- struct dump_hdr dump_hdr = {0};
+ struct dump_header dump_hdr = {0};
- regs->version = 1;
+ regs->version = 2;
memset(p, 0, regs->len);
if (!netif_running(bp->dev))
@@ -785,53 +885,173 @@ static void bnx2x_get_regs(struct net_device *dev,
* cause false alarms by reading never written registers. We
* will re-enable parity attentions right after the dump.
*/
+
+ /* Disable parity on path 0 */
+ bnx2x_pretend_func(bp, 0);
bnx2x_disable_blocks_parity(bp);
- dump_hdr.hdr_size = (sizeof(struct dump_hdr) / 4) - 1;
- dump_hdr.dump_sign = dump_sign_all;
- dump_hdr.xstorm_waitp = REG_RD(bp, XSTORM_WAITP_ADDR);
- dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR);
- dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR);
- dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR);
+ /* Disable parity on path 1 */
+ bnx2x_pretend_func(bp, 1);
+ bnx2x_disable_blocks_parity(bp);
- if (CHIP_IS_E1(bp))
- dump_hdr.info = RI_E1_ONLINE;
- else if (CHIP_IS_E1H(bp))
- dump_hdr.info = RI_E1H_ONLINE;
- else if (!CHIP_IS_E1x(bp))
- dump_hdr.info = RI_E2_ONLINE |
- (BP_PATH(bp) ? RI_PATH1_DUMP : RI_PATH0_DUMP);
+ /* Return to current function */
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+ dump_hdr.header_size = (sizeof(struct dump_header) / 4) - 1;
+ dump_hdr.preset = DUMP_ALL_PRESETS;
+ dump_hdr.version = BNX2X_DUMP_VERSION;
+
+ /* dump_meta_data presents OR of CHIP and PATH. */
+ if (CHIP_IS_E1(bp)) {
+ dump_hdr.dump_meta_data = DUMP_CHIP_E1;
+ } else if (CHIP_IS_E1H(bp)) {
+ dump_hdr.dump_meta_data = DUMP_CHIP_E1H;
+ } else if (CHIP_IS_E2(bp)) {
+ dump_hdr.dump_meta_data = DUMP_CHIP_E2 |
+ (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+ } else if (CHIP_IS_E3A0(bp)) {
+ dump_hdr.dump_meta_data = DUMP_CHIP_E3A0 |
+ (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+ } else if (CHIP_IS_E3B0(bp)) {
+ dump_hdr.dump_meta_data = DUMP_CHIP_E3B0 |
+ (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+ }
- memcpy(p, &dump_hdr, sizeof(struct dump_hdr));
- p += dump_hdr.hdr_size + 1;
+ memcpy(p, &dump_hdr, sizeof(struct dump_header));
+ p += dump_hdr.header_size + 1;
/* Actually read the registers */
__bnx2x_get_regs(bp, p);
- /* Re-enable parity attentions */
+ /* Re-enable parity attentions on path 0 */
+ bnx2x_pretend_func(bp, 0);
bnx2x_clear_blocks_parity(bp);
bnx2x_enable_blocks_parity(bp);
+
+ /* Re-enable parity attentions on path 1 */
+ bnx2x_pretend_func(bp, 1);
+ bnx2x_clear_blocks_parity(bp);
+ bnx2x_enable_blocks_parity(bp);
+
+ /* Return to current function */
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+static int bnx2x_get_preset_regs_len(struct net_device *dev, u32 preset)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int regdump_len = 0;
+
+ regdump_len = __bnx2x_get_preset_regs_len(bp, preset);
+ regdump_len *= 4;
+ regdump_len += sizeof(struct dump_header);
+
+ return regdump_len;
+}
+
+static int bnx2x_set_dump(struct net_device *dev, struct ethtool_dump *val)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ /* Use the ethtool_dump "flag" field as the dump preset index */
+ bp->dump_preset_idx = val->flag;
+ return 0;
+}
+
+static int bnx2x_get_dump_flag(struct net_device *dev,
+ struct ethtool_dump *dump)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ /* Calculate the requested preset idx length */
+ dump->len = bnx2x_get_preset_regs_len(dev, bp->dump_preset_idx);
+ DP(BNX2X_MSG_ETHTOOL, "Get dump preset %d length=%d\n",
+ bp->dump_preset_idx, dump->len);
+
+ dump->flag = ETHTOOL_GET_DUMP_DATA;
+ return 0;
+}
+
+static int bnx2x_get_dump_data(struct net_device *dev,
+ struct ethtool_dump *dump,
+ void *buffer)
+{
+ u32 *p = buffer;
+ struct bnx2x *bp = netdev_priv(dev);
+ struct dump_header dump_hdr = {0};
+
+ memset(p, 0, dump->len);
+
+ /* Disable parity attentions as long as following dump may
+ * cause false alarms by reading never written registers. We
+ * will re-enable parity attentions right after the dump.
+ */
+
+ /* Disable parity on path 0 */
+ bnx2x_pretend_func(bp, 0);
+ bnx2x_disable_blocks_parity(bp);
+
+ /* Disable parity on path 1 */
+ bnx2x_pretend_func(bp, 1);
+ bnx2x_disable_blocks_parity(bp);
+
+ /* Return to current function */
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+ dump_hdr.header_size = (sizeof(struct dump_header) / 4) - 1;
+ dump_hdr.preset = bp->dump_preset_idx;
+ dump_hdr.version = BNX2X_DUMP_VERSION;
+
+ DP(BNX2X_MSG_ETHTOOL, "Get dump data of preset %d\n", dump_hdr.preset);
+
+ /* dump_meta_data presents OR of CHIP and PATH. */
+ if (CHIP_IS_E1(bp)) {
+ dump_hdr.dump_meta_data = DUMP_CHIP_E1;
+ } else if (CHIP_IS_E1H(bp)) {
+ dump_hdr.dump_meta_data = DUMP_CHIP_E1H;
+ } else if (CHIP_IS_E2(bp)) {
+ dump_hdr.dump_meta_data = DUMP_CHIP_E2 |
+ (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+ } else if (CHIP_IS_E3A0(bp)) {
+ dump_hdr.dump_meta_data = DUMP_CHIP_E3A0 |
+ (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+ } else if (CHIP_IS_E3B0(bp)) {
+ dump_hdr.dump_meta_data = DUMP_CHIP_E3B0 |
+ (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0);
+ }
+
+ memcpy(p, &dump_hdr, sizeof(struct dump_header));
+ p += dump_hdr.header_size + 1;
+
+ /* Actually read the registers */
+ __bnx2x_get_preset_regs(bp, p, dump_hdr.preset);
+
+ /* Re-enable parity attentions on path 0 */
+ bnx2x_pretend_func(bp, 0);
+ bnx2x_clear_blocks_parity(bp);
+ bnx2x_enable_blocks_parity(bp);
+
+ /* Re-enable parity attentions on path 1 */
+ bnx2x_pretend_func(bp, 1);
+ bnx2x_clear_blocks_parity(bp);
+ bnx2x_enable_blocks_parity(bp);
+
+ /* Return to current function */
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+ return 0;
}
static void bnx2x_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct bnx2x *bp = netdev_priv(dev);
- u8 phy_fw_ver[PHY_FW_VER_LEN];
strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
- phy_fw_ver[0] = '\0';
- bnx2x_get_ext_phy_fw_version(&bp->link_params,
- phy_fw_ver, PHY_FW_VER_LEN);
- strlcpy(info->fw_version, bp->fw_ver, sizeof(info->fw_version));
- snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
- "bc %d.%d.%d%s%s",
- (bp->common.bc_ver & 0xff0000) >> 16,
- (bp->common.bc_ver & 0xff00) >> 8,
- (bp->common.bc_ver & 0xff),
- ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
+ bnx2x_fill_fw_str(bp, info->fw_version, sizeof(info->fw_version));
+
strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
info->n_stats = BNX2X_NUM_STATS;
info->testinfo_len = BNX2X_NUM_TESTS(bp);
@@ -861,13 +1081,13 @@ static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct bnx2x *bp = netdev_priv(dev);
if (wol->wolopts & ~WAKE_MAGIC) {
- DP(BNX2X_MSG_ETHTOOL, "WOL not supproted\n");
+ DP(BNX2X_MSG_ETHTOOL, "WOL not supported\n");
return -EINVAL;
}
if (wol->wolopts & WAKE_MAGIC) {
if (bp->flags & NO_WOL_FLAG) {
- DP(BNX2X_MSG_ETHTOOL, "WOL not supproted\n");
+ DP(BNX2X_MSG_ETHTOOL, "WOL not supported\n");
return -EINVAL;
}
bp->wol = 1;
@@ -890,7 +1110,7 @@ static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
if (capable(CAP_NET_ADMIN)) {
/* dump MCP trace */
- if (level & BNX2X_MSG_MCP)
+ if (IS_PF(bp) && (level & BNX2X_MSG_MCP))
bnx2x_fw_dump_lvl(bp, KERN_INFO);
bp->msg_enable = level;
}
@@ -940,7 +1160,7 @@ static int bnx2x_get_eeprom_len(struct net_device *dev)
* Pf B takes the lock and proceeds to perform it's own access.
* pf A unlocks the per port lock, while pf B is still working (!).
* mcp takes the per port lock and corrupts pf B's access (and/or has it's own
- * acess corrupted by pf B).*
+ * access corrupted by pf B)
*/
static int bnx2x_acquire_nvram_lock(struct bnx2x *bp)
{
@@ -1070,7 +1290,8 @@ static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, __be32 *ret_val,
val = REG_RD(bp, MCP_REG_MCPR_NVM_READ);
/* we read nvram data in cpu order
* but ethtool sees it as an array of bytes
- * converting to big-endian will do the work */
+ * converting to big-endian will do the work
+ */
*ret_val = cpu_to_be32(val);
rc = 0;
break;
@@ -1297,7 +1518,8 @@ static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
val |= (*data_buf << BYTE_OFFSET(offset));
/* nvram data is returned as an array of bytes
- * convert it back to cpu order */
+ * convert it back to cpu order
+ */
val = be32_to_cpu(val);
rc = bnx2x_nvram_write_dword(bp, align_offset, val,
@@ -1509,6 +1731,10 @@ static int bnx2x_set_ringparam(struct net_device *dev,
{
struct bnx2x *bp = netdev_priv(dev);
+ DP(BNX2X_MSG_ETHTOOL,
+ "set ring params command parameters: rx_pending = %d, tx_pending = %d\n",
+ ering->rx_pending, ering->tx_pending);
+
if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
DP(BNX2X_MSG_ETHTOOL,
"Handling parity error recovery. Try again later\n");
@@ -1747,7 +1973,6 @@ static int bnx2x_set_eee(struct net_device *dev, struct ethtool_eee *edata)
return 0;
}
-
enum {
BNX2X_CHIP_E1_OFST = 0,
BNX2X_CHIP_E1H_OFST,
@@ -1875,7 +2100,8 @@ static int bnx2x_test_registers(struct bnx2x *bp)
hw = BNX2X_CHIP_MASK_E3;
/* Repeat the test twice:
- First by writing 0x00000000, second by writing 0xffffffff */
+ * First by writing 0x00000000, second by writing 0xffffffff
+ */
for (idx = 0; idx < 2; idx++) {
switch (idx) {
@@ -2388,8 +2614,8 @@ static void bnx2x_self_test(struct net_device *dev,
struct ethtool_test *etest, u64 *buf)
{
struct bnx2x *bp = netdev_priv(dev);
- u8 is_serdes;
- int rc;
+ u8 is_serdes, link_up;
+ int rc, cnt = 0;
if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
netdev_err(bp->dev,
@@ -2397,6 +2623,7 @@ static void bnx2x_self_test(struct net_device *dev,
etest->flags |= ETH_TEST_FL_FAILED;
return;
}
+
DP(BNX2X_MSG_ETHTOOL,
"Self-test command parameters: offline = %d, external_lb = %d\n",
(etest->flags & ETH_TEST_FL_OFFLINE),
@@ -2411,20 +2638,17 @@ static void bnx2x_self_test(struct net_device *dev,
}
is_serdes = (bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0;
-
+ link_up = bp->link_vars.link_up;
/* offline tests are not supported in MF mode */
if ((etest->flags & ETH_TEST_FL_OFFLINE) && !IS_MF(bp)) {
int port = BP_PORT(bp);
u32 val;
- u8 link_up;
/* save current value of input enable for TX port IF */
val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
/* disable input for TX port IF */
REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
- link_up = bp->link_vars.link_up;
-
bnx2x_nic_unload(bp, UNLOAD_NORMAL, false);
rc = bnx2x_nic_load(bp, LOAD_DIAG);
if (rc) {
@@ -2486,17 +2710,19 @@ static void bnx2x_self_test(struct net_device *dev,
etest->flags |= ETH_TEST_FL_FAILED;
}
- if (bnx2x_link_test(bp, is_serdes) != 0) {
+ if (link_up) {
+ cnt = 100;
+ while (bnx2x_link_test(bp, is_serdes) && --cnt)
+ msleep(20);
+ }
+
+ if (!cnt) {
if (!IS_MF(bp))
buf[6] = 1;
else
buf[2] = 1;
etest->flags |= ETH_TEST_FL_FAILED;
}
-
-#ifdef BNX2X_EXTRA_DEBUG
- bnx2x_panic_dump(bp);
-#endif
}
#define IS_PORT_STAT(i) \
@@ -2753,15 +2979,14 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
DP(BNX2X_MSG_ETHTOOL,
"Command parameters not supported\n");
return -EINVAL;
- } else {
- return 0;
}
+ return 0;
case UDP_V4_FLOW:
case UDP_V6_FLOW:
/* For UDP either 2-tupple hash or 4-tupple hash is supported */
if (info->data == (RXH_IP_SRC | RXH_IP_DST |
- RXH_L4_B_0_1 | RXH_L4_B_2_3))
+ RXH_L4_B_0_1 | RXH_L4_B_2_3))
udp_rss_requested = 1;
else if (info->data == (RXH_IP_SRC | RXH_IP_DST))
udp_rss_requested = 0;
@@ -2781,9 +3006,9 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
"rss re-configured, UDP 4-tupple %s\n",
udp_rss_requested ? "enabled" : "disabled");
return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
- } else {
- return 0;
}
+ return 0;
+
case IPV4_FLOW:
case IPV6_FLOW:
/* For IP only 2-tupple hash is supported */
@@ -2791,9 +3016,9 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
DP(BNX2X_MSG_ETHTOOL,
"Command parameters not supported\n");
return -EINVAL;
- } else {
- return 0;
}
+ return 0;
+
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
@@ -2809,9 +3034,9 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
DP(BNX2X_MSG_ETHTOOL,
"Command parameters not supported\n");
return -EINVAL;
- } else {
- return 0;
}
+ return 0;
+
default:
return -EINVAL;
}
@@ -2964,6 +3189,9 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
.get_drvinfo = bnx2x_get_drvinfo,
.get_regs_len = bnx2x_get_regs_len,
.get_regs = bnx2x_get_regs,
+ .get_dump_flag = bnx2x_get_dump_flag,
+ .get_dump_data = bnx2x_get_dump_data,
+ .set_dump = bnx2x_set_dump,
.get_wol = bnx2x_get_wol,
.set_wol = bnx2x_set_wol,
.get_msglevel = bnx2x_get_msglevel,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
index 60a83ad10370..e5f808377c91 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
@@ -1,6 +1,6 @@
/* bnx2x_fw_defs.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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
@@ -305,12 +305,10 @@
#define MAX_VLAN_CREDIT_E1H 0 /* Per Chip */
#define MAX_VLAN_CREDIT_E2 272 /* Per Path */
-
/* Maximal aggregation queues supported */
#define ETH_MAX_AGGREGATION_QUEUES_E1 32
#define ETH_MAX_AGGREGATION_QUEUES_E1H_E2 64
-
#define ETH_NUM_OF_MCAST_BINS 256
#define ETH_NUM_OF_MCAST_ENGINES_E2 72
@@ -353,7 +351,6 @@
/* max number of slow path commands per port */
#define MAX_RAMRODS_PER_PORT 8
-
/**** DEFINES FOR TIMERS/CLOCKS RESOLUTIONS ****/
#define TIMERS_TICK_SIZE_CHIP (1e-3)
@@ -380,7 +377,6 @@
that is not mapped to priority*/
#define LLFC_TRAFFIC_TYPE_TO_PRIORITY_UNMAPPED 0xFF
-
#define C_ERES_PER_PAGE \
(PAGE_SIZE / BITS_TO_BYTES(STRUCT_SIZE(event_ring_elem)))
#define C_ERE_PER_PAGE_MASK (C_ERES_PER_PAGE - 1)
@@ -391,8 +387,6 @@
#define INVALID_VNIC_ID 0xFF
-
#define UNDEF_IRO 0x80000000
-
#endif /* BNX2X_FW_DEFS_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h
index 4bed52ba300d..f572ae164fce 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h
@@ -1,6 +1,6 @@
/* bnx2x_fw_file_hdr.h: FW binary file header structure.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index 3369a50ac6b4..037860ecc343 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -1,6 +1,6 @@
/* bnx2x_hsi.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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
@@ -899,6 +899,10 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */
#define PORT_FEAT_CFG_DCBX_DISABLED 0x00000000
#define PORT_FEAT_CFG_DCBX_ENABLED 0x00000100
+ #define PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK 0x00000C00
+ #define PORT_FEAT_CFG_STORAGE_PERSONALITY_FCOE 0x00000400
+ #define PORT_FEAT_CFG_STORAGE_PERSONALITY_ISCSI 0x00000800
+
#define PORT_FEATURE_EN_SIZE_MASK 0x0f000000
#define PORT_FEATURE_EN_SIZE_SHIFT 24
#define PORT_FEATURE_WOL_ENABLED 0x01000000
@@ -3374,6 +3378,10 @@ struct regpair {
__le32 hi;
};
+struct regpair_native {
+ u32 lo;
+ u32 hi;
+};
/*
* Classify rule opcodes in E2/E3
@@ -4400,13 +4408,13 @@ struct tstorm_eth_function_common_config {
* MAC filtering configuration parameters per port in Tstorm
*/
struct tstorm_eth_mac_filter_config {
- __le32 ucast_drop_all;
- __le32 ucast_accept_all;
- __le32 mcast_drop_all;
- __le32 mcast_accept_all;
- __le32 bcast_accept_all;
- __le32 vlan_filter[2];
- __le32 unmatched_unicast;
+ u32 ucast_drop_all;
+ u32 ucast_accept_all;
+ u32 mcast_drop_all;
+ u32 mcast_accept_all;
+ u32 bcast_accept_all;
+ u32 vlan_filter[2];
+ u32 unmatched_unicast;
};
@@ -4898,7 +4906,7 @@ union event_data {
* per PF event ring data
*/
struct event_ring_data {
- struct regpair base_addr;
+ struct regpair_native base_addr;
#if defined(__BIG_ENDIAN)
u8 index_id;
u8 sb_id;
@@ -5131,7 +5139,7 @@ struct pci_entity {
* The fast-path status block meta-data, common to all chips
*/
struct hc_sb_data {
- struct regpair host_sb_addr;
+ struct regpair_native host_sb_addr;
struct hc_status_block_sm state_machine[HC_SB_MAX_SM];
struct pci_entity p_func;
#if defined(__BIG_ENDIAN)
@@ -5145,7 +5153,7 @@ struct hc_sb_data {
u8 state;
u8 rsrv0;
#endif
- struct regpair rsrv1[2];
+ struct regpair_native rsrv1[2];
};
@@ -5163,7 +5171,7 @@ enum hc_segment {
* The fast-path status block meta-data
*/
struct hc_sp_status_block_data {
- struct regpair host_sb_addr;
+ struct regpair_native host_sb_addr;
#if defined(__BIG_ENDIAN)
u8 rsrv1;
u8 state;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
index c8f10f0e8a0d..76df015f486a 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h
+++ b/drivers/net/ethernet/broadcom/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-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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/ethernet/broadcom/bnx2x/bnx2x_init_ops.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
index d755acfe7a40..8ab0dd900960 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h
+++ b/drivers/net/ethernet/broadcom/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-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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
@@ -218,7 +218,7 @@ static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, u32 len,
/* gunzip_outlen is in dwords */
len = GUNZIP_OUTLEN(bp);
for (i = 0; i < len; i++)
- ((u32 *)GUNZIP_BUF(bp))[i] =
+ ((u32 *)GUNZIP_BUF(bp))[i] = (__force u32)
cpu_to_le32(((u32 *)GUNZIP_BUF(bp))[i]);
bnx2x_write_big_buf_wb(bp, addr, len);
@@ -232,7 +232,7 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage)
u16 op_end =
INIT_OPS_OFFSETS(bp)[BLOCK_OPS_IDX(block, stage,
STAGE_END)];
- union init_op *op;
+ const union init_op *op;
u32 op_idx, op_type, addr, len;
const u32 *data, *data_base;
@@ -244,7 +244,7 @@ static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage)
for (op_idx = op_start; op_idx < op_end; op_idx++) {
- op = (union init_op *)&(INIT_OPS(bp)[op_idx]);
+ op = (const union init_op *)&(INIT_OPS(bp)[op_idx]);
/* Get generic data */
op_type = op->raw.op;
addr = op->raw.offset;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index 09096b43a6e9..c6da77fa9d07 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -1,4 +1,4 @@
-/* Copyright 2008-2012 Broadcom Corporation
+/* Copyright 2008-2013 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -3659,7 +3659,7 @@ static void bnx2x_warpcore_enable_AN_KR2(struct bnx2x_phy *phy,
bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_CL49_USERB0_CTRL, (3<<6));
- for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
reg_set[i].val);
@@ -3713,7 +3713,7 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
};
DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
/* Set to default registers that may be overriden by 10G force */
- for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
reg_set[i].val);
@@ -3854,7 +3854,7 @@ static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
{MDIO_PMA_DEVAD, MDIO_WC_REG_PMD_KR_CONTROL, 0x2}
};
- for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
reg_set[i].val);
@@ -4242,7 +4242,7 @@ static void bnx2x_warpcore_clear_regs(struct bnx2x_phy *phy,
bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_RX66_CONTROL, (3<<13));
- for (i = 0; i < sizeof(wc_regs)/sizeof(struct bnx2x_reg_set); i++)
+ for (i = 0; i < ARRAY_SIZE(wc_regs); i++)
bnx2x_cl45_write(bp, phy, wc_regs[i].devad, wc_regs[i].reg,
wc_regs[i].val);
@@ -4748,6 +4748,12 @@ void bnx2x_link_status_update(struct link_params *params,
vars->link_status = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region,
port_mb[port].link_status));
+
+ /* Force link UP in non LOOPBACK_EXT loopback mode(s) */
+ if (bp->link_params.loopback_mode != LOOPBACK_NONE &&
+ bp->link_params.loopback_mode != LOOPBACK_EXT)
+ vars->link_status |= LINK_STATUS_LINK_UP;
+
if (bnx2x_eee_has_cap(params))
vars->eee_status = REG_RD(bp, params->shmem2_base +
offsetof(struct shmem2_region,
@@ -9520,7 +9526,7 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
} else {
/* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */
/* (1) set reg 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
- for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set);
+ for (i = 0; i < ARRAY_SIZE(reg_set);
i++)
bnx2x_cl45_write(bp, phy, reg_set[i].devad,
reg_set[i].reg, reg_set[i].val);
@@ -9592,7 +9598,7 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LINK_SIGNAL, val);
- for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
reg_set[i].val);
@@ -13395,7 +13401,7 @@ static void bnx2x_disable_kr2(struct link_params *params,
};
DP(NETIF_MSG_LINK, "Disabling 20G-KR2\n");
- for (i = 0; i < sizeof(reg_set)/sizeof(struct bnx2x_reg_set); i++)
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
reg_set[i].val);
vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
index ee6e7ec85457..d25c7d79787a 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
@@ -1,4 +1,4 @@
-/* Copyright 2008-2012 Broadcom Corporation
+/* Copyright 2008-2013 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 5523da3afcdc..e81a747ea8ce 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -1,6 +1,6 @@
/* bnx2x_main.c: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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
@@ -59,6 +59,7 @@
#include "bnx2x_init.h"
#include "bnx2x_init_ops.h"
#include "bnx2x_cmn.h"
+#include "bnx2x_vfpf.h"
#include "bnx2x_dcb.h"
#include "bnx2x_sp.h"
@@ -144,39 +145,49 @@ enum bnx2x_board_type {
BCM57711E,
BCM57712,
BCM57712_MF,
+ BCM57712_VF,
BCM57800,
BCM57800_MF,
+ BCM57800_VF,
BCM57810,
BCM57810_MF,
- BCM57840_O,
+ BCM57810_VF,
BCM57840_4_10,
BCM57840_2_20,
- BCM57840_MFO,
BCM57840_MF,
+ BCM57840_VF,
BCM57811,
- BCM57811_MF
+ BCM57811_MF,
+ BCM57840_O,
+ BCM57840_MFO,
+ BCM57811_VF
};
/* indexed by board_type, above */
static struct {
char *name;
} board_info[] = {
- { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" },
- { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" },
- { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" },
- { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" },
- { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" },
- { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" },
- { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" },
- { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" },
- { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" },
- { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" },
- { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" },
- { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" },
- { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function"},
- { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function"},
- { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet"},
- { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function"},
+ [BCM57710] = { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" },
+ [BCM57711] = { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" },
+ [BCM57711E] = { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" },
+ [BCM57712] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" },
+ [BCM57712_MF] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" },
+ [BCM57712_VF] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Virtual Function" },
+ [BCM57800] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" },
+ [BCM57800_MF] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" },
+ [BCM57800_VF] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Virtual Function" },
+ [BCM57810] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" },
+ [BCM57810_MF] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" },
+ [BCM57810_VF] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Virtual Function" },
+ [BCM57840_4_10] = { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" },
+ [BCM57840_2_20] = { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" },
+ [BCM57840_MF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
+ [BCM57840_VF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" },
+ [BCM57811] = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet" },
+ [BCM57811_MF] = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function" },
+ [BCM57840_O] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" },
+ [BCM57840_MFO] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
+ [BCM57811_VF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" }
};
#ifndef PCI_DEVICE_ID_NX2_57710
@@ -194,12 +205,18 @@ static struct {
#ifndef PCI_DEVICE_ID_NX2_57712_MF
#define PCI_DEVICE_ID_NX2_57712_MF CHIP_NUM_57712_MF
#endif
+#ifndef PCI_DEVICE_ID_NX2_57712_VF
+#define PCI_DEVICE_ID_NX2_57712_VF CHIP_NUM_57712_VF
+#endif
#ifndef PCI_DEVICE_ID_NX2_57800
#define PCI_DEVICE_ID_NX2_57800 CHIP_NUM_57800
#endif
#ifndef PCI_DEVICE_ID_NX2_57800_MF
#define PCI_DEVICE_ID_NX2_57800_MF CHIP_NUM_57800_MF
#endif
+#ifndef PCI_DEVICE_ID_NX2_57800_VF
+#define PCI_DEVICE_ID_NX2_57800_VF CHIP_NUM_57800_VF
+#endif
#ifndef PCI_DEVICE_ID_NX2_57810
#define PCI_DEVICE_ID_NX2_57810 CHIP_NUM_57810
#endif
@@ -209,6 +226,9 @@ static struct {
#ifndef PCI_DEVICE_ID_NX2_57840_O
#define PCI_DEVICE_ID_NX2_57840_O CHIP_NUM_57840_OBSOLETE
#endif
+#ifndef PCI_DEVICE_ID_NX2_57810_VF
+#define PCI_DEVICE_ID_NX2_57810_VF CHIP_NUM_57810_VF
+#endif
#ifndef PCI_DEVICE_ID_NX2_57840_4_10
#define PCI_DEVICE_ID_NX2_57840_4_10 CHIP_NUM_57840_4_10
#endif
@@ -221,29 +241,41 @@ static struct {
#ifndef PCI_DEVICE_ID_NX2_57840_MF
#define PCI_DEVICE_ID_NX2_57840_MF CHIP_NUM_57840_MF
#endif
+#ifndef PCI_DEVICE_ID_NX2_57840_VF
+#define PCI_DEVICE_ID_NX2_57840_VF CHIP_NUM_57840_VF
+#endif
#ifndef PCI_DEVICE_ID_NX2_57811
#define PCI_DEVICE_ID_NX2_57811 CHIP_NUM_57811
#endif
#ifndef PCI_DEVICE_ID_NX2_57811_MF
#define PCI_DEVICE_ID_NX2_57811_MF CHIP_NUM_57811_MF
#endif
+#ifndef PCI_DEVICE_ID_NX2_57811_VF
+#define PCI_DEVICE_ID_NX2_57811_VF CHIP_NUM_57811_VF
+#endif
+
static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712), BCM57712 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_MF), BCM57712_MF },
+ { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_VF), BCM57712_VF },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800), BCM57800 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_MF), BCM57800_MF },
+ { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_VF), BCM57800_VF },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810), BCM57810 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_MF), BCM57810_MF },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_O), BCM57840_O },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_4_10), BCM57840_4_10 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_2_20), BCM57840_2_20 },
+ { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_VF), BCM57810_VF },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MFO), BCM57840_MFO },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF },
+ { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_VF), BCM57840_VF },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811), BCM57811 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_MF), BCM57811_MF },
+ { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_VF), BCM57811_VF },
{ 0 }
};
@@ -346,6 +378,65 @@ static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
#define DMAE_DP_DST_PCI "pci dst_addr [%x:%08x]"
#define DMAE_DP_DST_NONE "dst_addr [none]"
+void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl)
+{
+ u32 src_type = dmae->opcode & DMAE_COMMAND_SRC;
+
+ switch (dmae->opcode & DMAE_COMMAND_DST) {
+ case DMAE_CMD_DST_PCI:
+ if (src_type == DMAE_CMD_SRC_PCI)
+ DP(msglvl, "DMAE: opcode 0x%08x\n"
+ "src [%x:%08x], len [%d*4], dst [%x:%08x]\n"
+ "comp_addr [%x:%08x], comp_val 0x%08x\n",
+ dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+ dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
+ dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ else
+ DP(msglvl, "DMAE: opcode 0x%08x\n"
+ "src [%08x], len [%d*4], dst [%x:%08x]\n"
+ "comp_addr [%x:%08x], comp_val 0x%08x\n",
+ dmae->opcode, dmae->src_addr_lo >> 2,
+ dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
+ dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ break;
+ case DMAE_CMD_DST_GRC:
+ if (src_type == DMAE_CMD_SRC_PCI)
+ DP(msglvl, "DMAE: opcode 0x%08x\n"
+ "src [%x:%08x], len [%d*4], dst_addr [%08x]\n"
+ "comp_addr [%x:%08x], comp_val 0x%08x\n",
+ dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+ dmae->len, dmae->dst_addr_lo >> 2,
+ dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ else
+ DP(msglvl, "DMAE: opcode 0x%08x\n"
+ "src [%08x], len [%d*4], dst [%08x]\n"
+ "comp_addr [%x:%08x], comp_val 0x%08x\n",
+ dmae->opcode, dmae->src_addr_lo >> 2,
+ dmae->len, dmae->dst_addr_lo >> 2,
+ dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ break;
+ default:
+ if (src_type == DMAE_CMD_SRC_PCI)
+ DP(msglvl, "DMAE: opcode 0x%08x\n"
+ "src_addr [%x:%08x] len [%d * 4] dst_addr [none]\n"
+ "comp_addr [%x:%08x] comp_val 0x%08x\n",
+ dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+ dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ else
+ DP(msglvl, "DMAE: opcode 0x%08x\n"
+ "src_addr [%08x] len [%d * 4] dst_addr [none]\n"
+ "comp_addr [%x:%08x] comp_val 0x%08x\n",
+ dmae->opcode, dmae->src_addr_lo >> 2,
+ dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
+ dmae->comp_val);
+ break;
+ }
+}
/* copy command into DMAE command memory and set DMAE command go */
void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx)
@@ -396,7 +487,7 @@ u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
return opcode;
}
-static void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
+void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
struct dmae_command *dmae,
u8 src_type, u8 dst_type)
{
@@ -412,9 +503,8 @@ static void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
dmae->comp_val = DMAE_COMP_VAL;
}
-/* issue a dmae command over the init-channel and wailt for completion */
-static int bnx2x_issue_dmae_with_comp(struct bnx2x *bp,
- struct dmae_command *dmae)
+/* issue a dmae command over the init-channel and wait for completion */
+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) : 4000;
@@ -692,12 +782,16 @@ void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark);
printk("%s", lvl);
+
+ /* dump buffer after the mark */
for (offset = mark; offset <= trace_shmem_base; offset += 0x8*4) {
for (word = 0; word < 8; word++)
data[word] = htonl(REG_RD(bp, offset + 4*word));
data[8] = 0x0;
pr_cont("%s", (char *)data);
}
+
+ /* dump buffer before the mark */
for (offset = addr + 4; offset <= mark; offset += 0x8*4) {
for (word = 0; word < 8; word++)
data[word] = htonl(REG_RD(bp, offset + 4*word));
@@ -712,7 +806,71 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
bnx2x_fw_dump_lvl(bp, KERN_ERR);
}
-void bnx2x_panic_dump(struct bnx2x *bp)
+static void bnx2x_hc_int_disable(struct bnx2x *bp)
+{
+ int port = BP_PORT(bp);
+ u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+ u32 val = REG_RD(bp, addr);
+
+ /* in E1 we must use only PCI configuration space to disable
+ * MSI/MSIX capablility
+ * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
+ */
+ if (CHIP_IS_E1(bp)) {
+ /* Since IGU_PF_CONF_MSI_MSIX_EN still always on
+ * Use mask register to prevent from HC sending interrupts
+ * after we exit the function
+ */
+ REG_WR(bp, HC_REG_INT_MASK + port*4, 0);
+
+ val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+ HC_CONFIG_0_REG_INT_LINE_EN_0 |
+ HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+ } else
+ val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+ HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+ HC_CONFIG_0_REG_INT_LINE_EN_0 |
+ HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+
+ DP(NETIF_MSG_IFDOWN,
+ "write %x to HC %d (addr 0x%x)\n",
+ val, port, addr);
+
+ /* flush all outstanding writes */
+ mmiowb();
+
+ REG_WR(bp, addr, val);
+ if (REG_RD(bp, addr) != val)
+ BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+static void bnx2x_igu_int_disable(struct bnx2x *bp)
+{
+ u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
+
+ val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
+ IGU_PF_CONF_INT_LINE_EN |
+ IGU_PF_CONF_ATTN_BIT_EN);
+
+ DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val);
+
+ /* flush all outstanding writes */
+ mmiowb();
+
+ REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+ if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
+ BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+static void bnx2x_int_disable(struct bnx2x *bp)
+{
+ if (bp->common.int_block == INT_BLOCK_HC)
+ bnx2x_hc_int_disable(bp);
+ else
+ bnx2x_igu_int_disable(bp);
+}
+
+void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
{
int i;
u16 j;
@@ -722,6 +880,8 @@ void bnx2x_panic_dump(struct bnx2x *bp)
u16 start = 0, end = 0;
u8 cos;
#endif
+ if (disable_int)
+ bnx2x_int_disable(bp);
bp->stats_state = STATS_STATE_DISABLED;
bp->eth_stats.unrecoverable_error++;
@@ -867,6 +1027,17 @@ void bnx2x_panic_dump(struct bnx2x *bp)
}
#ifdef BNX2X_STOP_ON_ERROR
+
+ /* event queue */
+ for (i = 0; i < NUM_EQ_DESC; i++) {
+ u32 *data = (u32 *)&bp->eq_ring[i].message.data;
+
+ BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n",
+ i, bp->eq_ring[i].message.opcode,
+ bp->eq_ring[i].message.error);
+ BNX2X_ERR("data: %x %x %x\n", data[0], data[1], data[2]);
+ }
+
/* Rings */
/* Rx */
for_each_valid_rx_queue(bp, i) {
@@ -1038,8 +1209,8 @@ static u32 bnx2x_flr_clnup_reg_poll(struct bnx2x *bp, u32 reg,
return val;
}
-static int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
- char *msg, u32 poll_cnt)
+int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
+ char *msg, u32 poll_cnt)
{
u32 val = bnx2x_flr_clnup_reg_poll(bp, reg, 0, poll_cnt);
if (val != 0) {
@@ -1049,7 +1220,8 @@ static int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
return 0;
}
-static u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
+/* Common routines with VF FLR cleanup */
+u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
{
/* adjust polling timeout */
if (CHIP_REV_IS_EMUL(bp))
@@ -1061,7 +1233,7 @@ static u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
return FLR_POLL_CNT;
}
-static void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
+void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
{
struct pbf_pN_cmd_regs cmd_regs[] = {
{0, (CHIP_IS_E3B0(bp)) ?
@@ -1136,10 +1308,9 @@ static void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
(((index) << SDM_OP_GEN_AGG_VECT_IDX_SHIFT) & SDM_OP_GEN_AGG_VECT_IDX)
-static int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
- u32 poll_cnt)
+int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt)
{
- struct sdm_op_gen op_gen = {0};
+ u32 op_gen_command = 0;
u32 comp_addr = BAR_CSTRORM_INTMEM +
CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(clnup_func);
@@ -1150,19 +1321,20 @@ static int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
return 1;
}
- op_gen.command |= OP_GEN_PARAM(XSTORM_AGG_INT_FINAL_CLEANUP_INDEX);
- op_gen.command |= OP_GEN_TYPE(XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE);
- op_gen.command |= OP_GEN_AGG_VECT(clnup_func);
- op_gen.command |= 1 << SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT;
+ op_gen_command |= OP_GEN_PARAM(XSTORM_AGG_INT_FINAL_CLEANUP_INDEX);
+ op_gen_command |= OP_GEN_TYPE(XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE);
+ op_gen_command |= OP_GEN_AGG_VECT(clnup_func);
+ op_gen_command |= 1 << SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT;
DP(BNX2X_MSG_SP, "sending FW Final cleanup\n");
- REG_WR(bp, XSDM_REG_OPERATION_GEN, op_gen.command);
+ REG_WR(bp, XSDM_REG_OPERATION_GEN, op_gen_command);
if (bnx2x_flr_clnup_reg_poll(bp, comp_addr, 1, poll_cnt) != 1) {
BNX2X_ERR("FW final cleanup did not succeed\n");
DP(BNX2X_MSG_SP, "At timeout completion address contained %x\n",
(REG_RD(bp, comp_addr)));
- ret = 1;
+ bnx2x_panic();
+ return 1;
}
/* Zero completion for nxt FLR */
REG_WR(bp, comp_addr, 0);
@@ -1170,7 +1342,7 @@ static int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
return ret;
}
-static u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
+u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
{
u16 status;
@@ -1382,26 +1554,31 @@ static void bnx2x_igu_int_enable(struct bnx2x *bp)
if (msix) {
val &= ~(IGU_PF_CONF_INT_LINE_EN |
IGU_PF_CONF_SINGLE_ISR_EN);
- val |= (IGU_PF_CONF_FUNC_EN |
- IGU_PF_CONF_MSI_MSIX_EN |
+ val |= (IGU_PF_CONF_MSI_MSIX_EN |
IGU_PF_CONF_ATTN_BIT_EN);
if (single_msix)
val |= IGU_PF_CONF_SINGLE_ISR_EN;
} else if (msi) {
val &= ~IGU_PF_CONF_INT_LINE_EN;
- val |= (IGU_PF_CONF_FUNC_EN |
- IGU_PF_CONF_MSI_MSIX_EN |
+ val |= (IGU_PF_CONF_MSI_MSIX_EN |
IGU_PF_CONF_ATTN_BIT_EN |
IGU_PF_CONF_SINGLE_ISR_EN);
} else {
val &= ~IGU_PF_CONF_MSI_MSIX_EN;
- val |= (IGU_PF_CONF_FUNC_EN |
- IGU_PF_CONF_INT_LINE_EN |
+ val |= (IGU_PF_CONF_INT_LINE_EN |
IGU_PF_CONF_ATTN_BIT_EN |
IGU_PF_CONF_SINGLE_ISR_EN);
}
+ /* Clean previous status - need to configure igu prior to ack*/
+ if ((!msix) || single_msix) {
+ REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+ bnx2x_ack_int(bp);
+ }
+
+ val |= IGU_PF_CONF_FUNC_EN;
+
DP(NETIF_MSG_IFUP, "write 0x%x to IGU mode %s\n",
val, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
@@ -1436,71 +1613,6 @@ void bnx2x_int_enable(struct bnx2x *bp)
bnx2x_igu_int_enable(bp);
}
-static void bnx2x_hc_int_disable(struct bnx2x *bp)
-{
- int port = BP_PORT(bp);
- u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
- u32 val = REG_RD(bp, addr);
-
- /*
- * in E1 we must use only PCI configuration space to disable
- * MSI/MSIX capablility
- * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
- */
- if (CHIP_IS_E1(bp)) {
- /* Since IGU_PF_CONF_MSI_MSIX_EN still always on
- * Use mask register to prevent from HC sending interrupts
- * after we exit the function
- */
- REG_WR(bp, HC_REG_INT_MASK + port*4, 0);
-
- val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
- HC_CONFIG_0_REG_INT_LINE_EN_0 |
- HC_CONFIG_0_REG_ATTN_BIT_EN_0);
- } else
- val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
- HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
- HC_CONFIG_0_REG_INT_LINE_EN_0 |
- HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-
- DP(NETIF_MSG_IFDOWN,
- "write %x to HC %d (addr 0x%x)\n",
- val, port, addr);
-
- /* flush all outstanding writes */
- mmiowb();
-
- REG_WR(bp, addr, val);
- if (REG_RD(bp, addr) != val)
- BNX2X_ERR("BUG! proper val not read from IGU!\n");
-}
-
-static void bnx2x_igu_int_disable(struct bnx2x *bp)
-{
- u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
-
- val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
- IGU_PF_CONF_INT_LINE_EN |
- IGU_PF_CONF_ATTN_BIT_EN);
-
- DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val);
-
- /* flush all outstanding writes */
- mmiowb();
-
- REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
- if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
- BNX2X_ERR("BUG! proper val not read from IGU!\n");
-}
-
-static void bnx2x_int_disable(struct bnx2x *bp)
-{
- if (bp->common.int_block == INT_BLOCK_HC)
- bnx2x_hc_int_disable(bp);
- else
- bnx2x_igu_int_disable(bp);
-}
-
void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
{
int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
@@ -1586,11 +1698,11 @@ static int bnx2x_get_leader_lock_resource(struct bnx2x *bp)
}
/**
- * bnx2x_trylock_leader_lock- try to aquire a leader lock.
+ * bnx2x_trylock_leader_lock- try to acquire a leader lock.
*
* @bp: driver handle
*
- * Tries to aquire a leader lock for current engine.
+ * Tries to acquire a leader lock for current engine.
*/
static bool bnx2x_trylock_leader_lock(struct bnx2x *bp)
{
@@ -1599,6 +1711,24 @@ static bool bnx2x_trylock_leader_lock(struct bnx2x *bp)
static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid, u8 err);
+/* schedule the sp task and mark that interrupt occurred (runs from ISR) */
+static int bnx2x_schedule_sp_task(struct bnx2x *bp)
+{
+ /* Set the interrupt occurred bit for the sp-task to recognize it
+ * must ack the interrupt and transition according to the IGU
+ * state machine.
+ */
+ atomic_set(&bp->interrupt_occurred, 1);
+
+ /* The sp_task must execute only after this bit
+ * is set, otherwise we will get out of sync and miss all
+ * further interrupts. Hence, the barrier.
+ */
+ smp_wmb();
+
+ /* schedule sp_task to workqueue */
+ return queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+}
void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
{
@@ -1613,6 +1743,13 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
fp->index, cid, command, bp->state,
rr_cqe->ramrod_cqe.ramrod_type);
+ /* If cid is within VF range, replace the slowpath object with the
+ * one corresponding to this VF
+ */
+ if (cid >= BNX2X_FIRST_VF_CID &&
+ cid < BNX2X_FIRST_VF_CID + BNX2X_VF_CIDS)
+ bnx2x_iov_set_queue_sp_obj(bp, cid, &q_obj);
+
switch (command) {
case (RAMROD_CMD_ID_ETH_CLIENT_UPDATE):
DP(BNX2X_MSG_SP, "got UPDATE ramrod. CID %d\n", cid);
@@ -1664,6 +1801,8 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
#else
return;
#endif
+ /* SRIOV: reschedule any 'in_progress' operations */
+ bnx2x_iov_sp_event(bp, cid, true);
smp_mb__before_atomic_inc();
atomic_inc(&bp->cq_spq_left);
@@ -1680,7 +1819,7 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
* mark pending ACK to MCP bit.
* prevent case that both bits are cleared.
* At the end of load/unload driver checks that
- * sp_state is cleaerd, and this order prevents
+ * sp_state is cleared, and this order prevents
* races
*/
smp_mb__before_clear_bit();
@@ -1689,22 +1828,13 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
clear_bit(BNX2X_AFEX_FCOE_Q_UPDATE_PENDING, &bp->sp_state);
smp_mb__after_clear_bit();
- /* schedule workqueue to send ack to MCP */
- queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+ /* schedule the sp task as mcp ack is required */
+ bnx2x_schedule_sp_task(bp);
}
return;
}
-void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp,
- u16 bd_prod, u16 rx_comp_prod, u16 rx_sge_prod)
-{
- u32 start = BAR_USTRORM_INTMEM + fp->ustorm_rx_prods_offset;
-
- bnx2x_update_rx_prod_gen(bp, fp, bd_prod, rx_comp_prod, rx_sge_prod,
- start);
-}
-
irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
{
struct bnx2x *bp = netdev_priv(dev_instance);
@@ -1745,21 +1875,23 @@ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
if (status & (mask | 0x1)) {
struct cnic_ops *c_ops = NULL;
- if (likely(bp->state == BNX2X_STATE_OPEN)) {
- rcu_read_lock();
- c_ops = rcu_dereference(bp->cnic_ops);
- if (c_ops)
- c_ops->cnic_handler(bp->cnic_data,
- NULL);
- rcu_read_unlock();
- }
+ rcu_read_lock();
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops && (bp->cnic_eth_dev.drv_state &
+ CNIC_DRV_STATE_HANDLES_IRQ))
+ c_ops->cnic_handler(bp->cnic_data, NULL);
+ rcu_read_unlock();
status &= ~mask;
}
}
if (unlikely(status & 0x1)) {
- queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+
+ /* schedule sp task to perform default status block work, ack
+ * attentions and enable interrupts.
+ */
+ bnx2x_schedule_sp_task(bp);
status &= ~0x1;
if (!status)
@@ -2459,23 +2591,55 @@ void bnx2x__link_status_update(struct bnx2x *bp)
return;
/* read updated dcb configuration */
- bnx2x_dcbx_pmf_update(bp);
-
- bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
+ if (IS_PF(bp)) {
+ bnx2x_dcbx_pmf_update(bp);
+ bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
+ if (bp->link_vars.link_up)
+ bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
+ else
+ bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+ /* indicate link status */
+ bnx2x_link_report(bp);
- if (bp->link_vars.link_up)
+ } else { /* VF */
+ bp->port.supported[0] |= (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_2500baseX_Full |
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_TP |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Autoneg |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause);
+ bp->port.advertising[0] = bp->port.supported[0];
+
+ bp->link_params.bp = bp;
+ bp->link_params.port = BP_PORT(bp);
+ bp->link_params.req_duplex[0] = DUPLEX_FULL;
+ bp->link_params.req_flow_ctrl[0] = BNX2X_FLOW_CTRL_NONE;
+ bp->link_params.req_line_speed[0] = SPEED_10000;
+ bp->link_params.speed_cap_mask[0] = 0x7f0000;
+ bp->link_params.switch_cfg = SWITCH_CFG_10G;
+ bp->link_vars.mac_type = MAC_TYPE_BMAC;
+ bp->link_vars.line_speed = SPEED_10000;
+ bp->link_vars.link_status =
+ (LINK_STATUS_LINK_UP |
+ LINK_STATUS_SPEED_AND_DUPLEX_10GTFD);
+ bp->link_vars.link_up = 1;
+ bp->link_vars.duplex = DUPLEX_FULL;
+ bp->link_vars.flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+ __bnx2x_link_report(bp);
bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
- else
- bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
- /* indicate link status */
- bnx2x_link_report(bp);
+ }
}
static int bnx2x_afex_func_update(struct bnx2x *bp, u16 vifid,
u16 vlan_val, u8 allowed_prio)
{
- struct bnx2x_func_state_params func_params = {0};
+ struct bnx2x_func_state_params func_params = {NULL};
struct bnx2x_func_afex_update_params *f_update_params =
&func_params.params.afex_update;
@@ -2500,7 +2664,7 @@ static int bnx2x_afex_func_update(struct bnx2x *bp, u16 vifid,
static int bnx2x_afex_handle_vif_list_cmd(struct bnx2x *bp, u8 cmd_type,
u16 vif_index, u8 func_bit_map)
{
- struct bnx2x_func_state_params func_params = {0};
+ struct bnx2x_func_state_params func_params = {NULL};
struct bnx2x_func_afex_viflists_params *update_params =
&func_params.params.afex_viflists;
int rc;
@@ -2516,7 +2680,7 @@ static int bnx2x_afex_handle_vif_list_cmd(struct bnx2x *bp, u8 cmd_type,
/* set parameters according to cmd_type */
update_params->afex_vif_list_command = cmd_type;
- update_params->vif_list_index = cpu_to_le16(vif_index);
+ update_params->vif_list_index = vif_index;
update_params->func_bit_map =
(cmd_type == VIF_LIST_RULE_GET) ? 0 : func_bit_map;
update_params->func_to_clear = 0;
@@ -2800,6 +2964,10 @@ static unsigned long bnx2x_get_common_flags(struct bnx2x *bp,
__set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags);
+#ifdef BNX2X_STOP_ON_ERROR
+ __set_bit(BNX2X_Q_FLG_TX_SEC, &flags);
+#endif
+
return flags;
}
@@ -2875,15 +3043,12 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
pause->sge_th_hi + FW_PREFETCH_CNT >
MAX_RX_SGE_CNT * NUM_RX_SGE_PAGES);
- tpa_agg_size = min_t(u32,
- (min_t(u32, 8, MAX_SKB_FRAGS) *
- SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
+ tpa_agg_size = TPA_AGG_SIZE;
max_sge = SGE_PAGE_ALIGN(bp->dev->mtu) >>
SGE_PAGE_SHIFT;
max_sge = ((max_sge + PAGES_PER_SGE - 1) &
(~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT;
- sge_sz = (u16)min_t(u32, SGE_PAGE_SIZE * PAGES_PER_SGE,
- 0xffff);
+ sge_sz = (u16)min_t(u32, SGE_PAGES, 0xffff);
}
/* pause - not for e1 */
@@ -2928,7 +3093,7 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
/* Maximum number or simultaneous TPA aggregation for this Queue.
*
- * For PF Clients it should be the maximum avaliable number.
+ * For PF Clients it should be the maximum available number.
* VF driver(s) may want to define it to a smaller value.
*/
rxq_init->max_tpa_queues = MAX_AGG_QS(bp);
@@ -3022,7 +3187,7 @@ static void bnx2x_pf_init(struct bnx2x *bp)
if (bp->port.pmf)
storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
- /* init Event Queue */
+ /* init Event Queue - PCI bus guarantees correct endianity*/
eq_data.base_addr.hi = U64_HI(bp->eq_mapping);
eq_data.base_addr.lo = U64_LO(bp->eq_mapping);
eq_data.producer = bp->eq_prod;
@@ -3112,65 +3277,75 @@ static void bnx2x_drv_info_fcoe_stat(struct bnx2x *bp)
struct fcoe_statistics_params *fw_fcoe_stat =
&bp->fw_stats_data->fcoe;
- ADD_64(fcoe_stat->rx_bytes_hi, 0, fcoe_stat->rx_bytes_lo,
- fw_fcoe_stat->rx_stat0.fcoe_rx_byte_cnt);
+ ADD_64_LE(fcoe_stat->rx_bytes_hi, LE32_0,
+ fcoe_stat->rx_bytes_lo,
+ fw_fcoe_stat->rx_stat0.fcoe_rx_byte_cnt);
- ADD_64(fcoe_stat->rx_bytes_hi,
- fcoe_q_tstorm_stats->rcv_ucast_bytes.hi,
- fcoe_stat->rx_bytes_lo,
- fcoe_q_tstorm_stats->rcv_ucast_bytes.lo);
+ ADD_64_LE(fcoe_stat->rx_bytes_hi,
+ fcoe_q_tstorm_stats->rcv_ucast_bytes.hi,
+ fcoe_stat->rx_bytes_lo,
+ fcoe_q_tstorm_stats->rcv_ucast_bytes.lo);
- ADD_64(fcoe_stat->rx_bytes_hi,
- fcoe_q_tstorm_stats->rcv_bcast_bytes.hi,
- fcoe_stat->rx_bytes_lo,
- fcoe_q_tstorm_stats->rcv_bcast_bytes.lo);
+ ADD_64_LE(fcoe_stat->rx_bytes_hi,
+ fcoe_q_tstorm_stats->rcv_bcast_bytes.hi,
+ fcoe_stat->rx_bytes_lo,
+ fcoe_q_tstorm_stats->rcv_bcast_bytes.lo);
- ADD_64(fcoe_stat->rx_bytes_hi,
- fcoe_q_tstorm_stats->rcv_mcast_bytes.hi,
- fcoe_stat->rx_bytes_lo,
- fcoe_q_tstorm_stats->rcv_mcast_bytes.lo);
+ ADD_64_LE(fcoe_stat->rx_bytes_hi,
+ fcoe_q_tstorm_stats->rcv_mcast_bytes.hi,
+ fcoe_stat->rx_bytes_lo,
+ fcoe_q_tstorm_stats->rcv_mcast_bytes.lo);
- ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
- fw_fcoe_stat->rx_stat0.fcoe_rx_pkt_cnt);
+ ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+ fcoe_stat->rx_frames_lo,
+ fw_fcoe_stat->rx_stat0.fcoe_rx_pkt_cnt);
- ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
- fcoe_q_tstorm_stats->rcv_ucast_pkts);
+ ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+ fcoe_stat->rx_frames_lo,
+ fcoe_q_tstorm_stats->rcv_ucast_pkts);
- ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
- fcoe_q_tstorm_stats->rcv_bcast_pkts);
+ ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+ fcoe_stat->rx_frames_lo,
+ fcoe_q_tstorm_stats->rcv_bcast_pkts);
- ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
- fcoe_q_tstorm_stats->rcv_mcast_pkts);
+ ADD_64_LE(fcoe_stat->rx_frames_hi, LE32_0,
+ fcoe_stat->rx_frames_lo,
+ fcoe_q_tstorm_stats->rcv_mcast_pkts);
- ADD_64(fcoe_stat->tx_bytes_hi, 0, fcoe_stat->tx_bytes_lo,
- fw_fcoe_stat->tx_stat.fcoe_tx_byte_cnt);
+ ADD_64_LE(fcoe_stat->tx_bytes_hi, LE32_0,
+ fcoe_stat->tx_bytes_lo,
+ fw_fcoe_stat->tx_stat.fcoe_tx_byte_cnt);
- ADD_64(fcoe_stat->tx_bytes_hi,
- fcoe_q_xstorm_stats->ucast_bytes_sent.hi,
- fcoe_stat->tx_bytes_lo,
- fcoe_q_xstorm_stats->ucast_bytes_sent.lo);
+ ADD_64_LE(fcoe_stat->tx_bytes_hi,
+ fcoe_q_xstorm_stats->ucast_bytes_sent.hi,
+ fcoe_stat->tx_bytes_lo,
+ fcoe_q_xstorm_stats->ucast_bytes_sent.lo);
- ADD_64(fcoe_stat->tx_bytes_hi,
- fcoe_q_xstorm_stats->bcast_bytes_sent.hi,
- fcoe_stat->tx_bytes_lo,
- fcoe_q_xstorm_stats->bcast_bytes_sent.lo);
+ ADD_64_LE(fcoe_stat->tx_bytes_hi,
+ fcoe_q_xstorm_stats->bcast_bytes_sent.hi,
+ fcoe_stat->tx_bytes_lo,
+ fcoe_q_xstorm_stats->bcast_bytes_sent.lo);
- ADD_64(fcoe_stat->tx_bytes_hi,
- fcoe_q_xstorm_stats->mcast_bytes_sent.hi,
- fcoe_stat->tx_bytes_lo,
- fcoe_q_xstorm_stats->mcast_bytes_sent.lo);
+ ADD_64_LE(fcoe_stat->tx_bytes_hi,
+ fcoe_q_xstorm_stats->mcast_bytes_sent.hi,
+ fcoe_stat->tx_bytes_lo,
+ fcoe_q_xstorm_stats->mcast_bytes_sent.lo);
- ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
- fw_fcoe_stat->tx_stat.fcoe_tx_pkt_cnt);
+ ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+ fcoe_stat->tx_frames_lo,
+ fw_fcoe_stat->tx_stat.fcoe_tx_pkt_cnt);
- ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
- fcoe_q_xstorm_stats->ucast_pkts_sent);
+ ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+ fcoe_stat->tx_frames_lo,
+ fcoe_q_xstorm_stats->ucast_pkts_sent);
- ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
- fcoe_q_xstorm_stats->bcast_pkts_sent);
+ ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+ fcoe_stat->tx_frames_lo,
+ fcoe_q_xstorm_stats->bcast_pkts_sent);
- ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
- fcoe_q_xstorm_stats->mcast_pkts_sent);
+ ADD_64_LE(fcoe_stat->tx_frames_hi, LE32_0,
+ fcoe_stat->tx_frames_lo,
+ fcoe_q_xstorm_stats->mcast_pkts_sent);
}
/* ask L5 driver to add data to the struct */
@@ -3641,7 +3816,7 @@ static void bnx2x_fan_failure(struct bnx2x *bp)
"Please contact OEM Support for assistance\n");
/*
- * Scheudle device reset (unload)
+ * Schedule device reset (unload)
* This is due to some boards consuming sufficient power when driver is
* up to overheat if fan fails.
*/
@@ -3791,6 +3966,10 @@ static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
if (val & DRV_STATUS_DRV_INFO_REQ)
bnx2x_handle_drv_info_req(bp);
+
+ if (val & DRV_STATUS_VF_DISABLED)
+ bnx2x_vf_handle_flr_event(bp);
+
if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
bnx2x_pmf_update(bp);
@@ -4587,8 +4766,8 @@ static void bnx2x_attn_int(struct bnx2x *bp)
void bnx2x_igu_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 segment,
u16 index, u8 op, u8 update)
{
- u32 igu_addr = BAR_IGU_INTMEM + (IGU_CMD_INT_ACK_BASE + igu_sb_id)*8;
-
+ u32 igu_addr = bp->igu_base_addr;
+ igu_addr += (IGU_CMD_INT_ACK_BASE + igu_sb_id)*8;
bnx2x_igu_ack_sb_gen(bp, igu_sb_id, segment, index, op, update,
igu_addr);
}
@@ -4616,7 +4795,7 @@ static int bnx2x_cnic_handle_cfc_del(struct bnx2x *bp, u32 cid,
BNX2X_ERR("got delete ramrod for CNIC CID %d with error!\n",
cid);
- bnx2x_panic_dump(bp);
+ bnx2x_panic_dump(bp, false);
}
bnx2x_cnic_cfc_comp(bp, cid, err);
return 0;
@@ -4658,7 +4837,8 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,
/* Always push next commands out, don't wait here */
__set_bit(RAMROD_CONT, &ramrod_flags);
- switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) {
+ switch (le32_to_cpu((__force __le32)elem->message.data.eth_event.echo)
+ >> BNX2X_SWCID_SHIFT) {
case BNX2X_FILTER_MAC_PENDING:
DP(BNX2X_MSG_SP, "Got SETUP_MAC completions\n");
if (CNIC_LOADED(bp) && (cid == BNX2X_ISCSI_ETH_CID(bp)))
@@ -4735,7 +4915,7 @@ static void bnx2x_after_function_update(struct bnx2x *bp)
struct bnx2x_queue_update_params *q_update_params =
&queue_params.params.update;
- /* Send Q update command with afex vlan removal values for all Qs */
+ /* Send Q update command with afex vlan removal values for all Qs */
queue_params.cmd = BNX2X_Q_CMD_UPDATE;
/* set silent vlan removal values according to vlan mode */
@@ -4809,7 +4989,7 @@ static void bnx2x_eq_int(struct bnx2x *bp)
u8 echo;
u32 cid;
u8 opcode;
- int spqe_cnt = 0;
+ int rc, spqe_cnt = 0;
struct bnx2x_queue_sp_obj *q_obj;
struct bnx2x_func_sp_obj *f_obj = &bp->func_obj;
struct bnx2x_raw_obj *rss_raw = &bp->rss_conf_obj.raw;
@@ -4837,15 +5017,27 @@ static void bnx2x_eq_int(struct bnx2x *bp)
for (; sw_cons != hw_cons;
sw_prod = NEXT_EQ_IDX(sw_prod), sw_cons = NEXT_EQ_IDX(sw_cons)) {
-
elem = &bp->eq_ring[EQ_DESC(sw_cons)];
- cid = SW_CID(elem->message.data.cfc_del_event.cid);
- opcode = elem->message.opcode;
+ rc = bnx2x_iov_eq_sp_event(bp, elem);
+ if (!rc) {
+ DP(BNX2X_MSG_IOV, "bnx2x_iov_eq_sp_event returned %d\n",
+ rc);
+ goto next_spqe;
+ }
+ /* elem CID originates from FW; actually LE */
+ cid = SW_CID((__force __le32)
+ elem->message.data.cfc_del_event.cid);
+ opcode = elem->message.opcode;
/* handle eq element */
switch (opcode) {
+ case EVENT_RING_OPCODE_VF_PF_CHANNEL:
+ DP(BNX2X_MSG_IOV, "vf pf channel element on eq\n");
+ bnx2x_vf_mbx(bp, &elem->message.data.vf_pf_event);
+ continue;
+
case EVENT_RING_OPCODE_STAT_QUERY:
DP(BNX2X_MSG_SP | BNX2X_MSG_STATS,
"got statistics comp event %d\n",
@@ -5011,50 +5203,65 @@ next_spqe:
static void bnx2x_sp_task(struct work_struct *work)
{
struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
- u16 status;
- status = bnx2x_update_dsb_idx(bp);
-/* if (status == 0) */
-/* BNX2X_ERR("spurious slowpath interrupt!\n"); */
+ DP(BNX2X_MSG_SP, "sp task invoked\n");
- DP(BNX2X_MSG_SP, "got a slowpath interrupt (status 0x%x)\n", status);
+ /* make sure the atomic interupt_occurred has been written */
+ smp_rmb();
+ if (atomic_read(&bp->interrupt_occurred)) {
- /* HW attentions */
- if (status & BNX2X_DEF_SB_ATT_IDX) {
- bnx2x_attn_int(bp);
- status &= ~BNX2X_DEF_SB_ATT_IDX;
- }
+ /* what work needs to be performed? */
+ u16 status = bnx2x_update_dsb_idx(bp);
- /* SP events: STAT_QUERY and others */
- if (status & BNX2X_DEF_SB_IDX) {
- struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
+ DP(BNX2X_MSG_SP, "status %x\n", status);
+ DP(BNX2X_MSG_SP, "setting interrupt_occurred to 0\n");
+ atomic_set(&bp->interrupt_occurred, 0);
+
+ /* HW attentions */
+ if (status & BNX2X_DEF_SB_ATT_IDX) {
+ bnx2x_attn_int(bp);
+ status &= ~BNX2X_DEF_SB_ATT_IDX;
+ }
+
+ /* SP events: STAT_QUERY and others */
+ if (status & BNX2X_DEF_SB_IDX) {
+ struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
if (FCOE_INIT(bp) &&
- (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
- /*
- * Prevent local bottom-halves from running as
- * we are going to change the local NAPI list.
- */
- local_bh_disable();
- napi_schedule(&bnx2x_fcoe(bp, napi));
- local_bh_enable();
+ (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+ /* Prevent local bottom-halves from running as
+ * we are going to change the local NAPI list.
+ */
+ local_bh_disable();
+ napi_schedule(&bnx2x_fcoe(bp, napi));
+ local_bh_enable();
+ }
+
+ /* Handle EQ completions */
+ bnx2x_eq_int(bp);
+ bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID,
+ le16_to_cpu(bp->def_idx), IGU_INT_NOP, 1);
+
+ status &= ~BNX2X_DEF_SB_IDX;
}
- /* Handle EQ completions */
- bnx2x_eq_int(bp);
+ /* if status is non zero then perhaps something went wrong */
+ if (unlikely(status))
+ DP(BNX2X_MSG_SP,
+ "got an unknown interrupt! (status 0x%x)\n", status);
- bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID,
- le16_to_cpu(bp->def_idx), IGU_INT_NOP, 1);
+ /* ack status block only if something was actually handled */
+ bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID,
+ le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
- status &= ~BNX2X_DEF_SB_IDX;
}
- if (unlikely(status))
- DP(BNX2X_MSG_SP, "got an unknown interrupt! (status 0x%x)\n",
- status);
-
- bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID,
- le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
+ /* must be called after the EQ processing (since eq leads to sriov
+ * ramrod completion flows).
+ * This flow may have been scheduled by the arrival of a ramrod
+ * completion, or by the sriov code rescheduling itself.
+ */
+ bnx2x_iov_sp_task(bp);
/* afex - poll to check if VIFSET_ACK should be sent to MFW */
if (test_and_clear_bit(BNX2X_AFEX_PENDING_VIFSET_MCP_ACK,
@@ -5087,7 +5294,10 @@ irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
rcu_read_unlock();
}
- queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+ /* schedule sp task to perform default status block work, ack
+ * attentions and enable interrupts.
+ */
+ bnx2x_schedule_sp_task(bp);
return IRQ_HANDLED;
}
@@ -5101,7 +5311,6 @@ void bnx2x_drv_pulse(struct bnx2x *bp)
bp->fw_drv_pulse_wr_seq);
}
-
static void bnx2x_timer(unsigned long data)
{
struct bnx2x *bp = (struct bnx2x *) data;
@@ -5109,7 +5318,8 @@ static void bnx2x_timer(unsigned long data)
if (!netif_running(bp->dev))
return;
- if (!BP_NOMCP(bp)) {
+ if (IS_PF(bp) &&
+ !BP_NOMCP(bp)) {
int mb_idx = BP_FW_MB_IDX(bp);
u32 drv_pulse;
u32 mcp_pulse;
@@ -5136,6 +5346,10 @@ static void bnx2x_timer(unsigned long data)
if (bp->state == BNX2X_STATE_OPEN)
bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);
+ /* sample pf vf bulletin board for new posts from pf */
+ if (IS_VF(bp))
+ bnx2x_sample_bulletin(bp);
+
mod_timer(&bp->timer, jiffies + bp->current_interval);
}
@@ -5278,7 +5492,7 @@ static void bnx2x_map_sb_state_machines(struct hc_index_data *index_data)
SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
}
-static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
+void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
u8 vf_valid, int fw_sb_id, int igu_sb_id)
{
int igu_seg_id;
@@ -5334,7 +5548,7 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
DP(NETIF_MSG_IFUP, "Init FW SB %d\n", fw_sb_id);
- /* write indecies to HW */
+ /* write indices to HW - PCI guarantees endianity of regpairs */
bnx2x_wr_fp_sb_data(bp, fw_sb_id, sb_data_p, data_size);
}
@@ -5422,6 +5636,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
bnx2x_zero_sp_sb(bp);
+ /* PCI guarantees endianity of regpairs */
sp_sb_data.state = SB_ENABLED;
sp_sb_data.host_sb_addr.lo = U64_LO(section);
sp_sb_data.host_sb_addr.hi = U64_HI(section);
@@ -5478,13 +5693,12 @@ static void bnx2x_init_eq_ring(struct bnx2x *bp)
min_t(int, MAX_SP_DESC_CNT - MAX_SPQ_PENDING, NUM_EQ_DESC) - 1);
}
-
/* called with netif_addr_lock_bh() */
-void bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
- unsigned long rx_mode_flags,
- unsigned long rx_accept_flags,
- unsigned long tx_accept_flags,
- unsigned long ramrod_flags)
+int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
+ unsigned long rx_mode_flags,
+ unsigned long rx_accept_flags,
+ unsigned long tx_accept_flags,
+ unsigned long ramrod_flags)
{
struct bnx2x_rx_mode_ramrod_params ramrod_param;
int rc;
@@ -5514,22 +5728,21 @@ void bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
rc = bnx2x_config_rx_mode(bp, &ramrod_param);
if (rc < 0) {
BNX2X_ERR("Set rx_mode %d failed\n", bp->rx_mode);
- return;
+ return rc;
}
+
+ return 0;
}
-/* called with netif_addr_lock_bh() */
-void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
+ unsigned long *rx_accept_flags,
+ unsigned long *tx_accept_flags)
{
- unsigned long rx_mode_flags = 0, ramrod_flags = 0;
- unsigned long rx_accept_flags = 0, tx_accept_flags = 0;
+ /* Clear the flags first */
+ *rx_accept_flags = 0;
+ *tx_accept_flags = 0;
- if (!NO_FCOE(bp))
-
- /* Configure rx_mode of FCoE Queue */
- __set_bit(BNX2X_RX_MODE_FCOE_ETH, &rx_mode_flags);
-
- switch (bp->rx_mode) {
+ switch (rx_mode) {
case BNX2X_RX_MODE_NONE:
/*
* 'drop all' supersedes any accept flags that may have been
@@ -5537,25 +5750,25 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
*/
break;
case BNX2X_RX_MODE_NORMAL:
- __set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags);
- __set_bit(BNX2X_ACCEPT_MULTICAST, &rx_accept_flags);
- __set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_MULTICAST, rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_BROADCAST, rx_accept_flags);
/* internal switching mode */
- __set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags);
- __set_bit(BNX2X_ACCEPT_MULTICAST, &tx_accept_flags);
- __set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_MULTICAST, tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);
break;
case BNX2X_RX_MODE_ALLMULTI:
- __set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags);
- __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &rx_accept_flags);
- __set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_BROADCAST, rx_accept_flags);
/* internal switching mode */
- __set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags);
- __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &tx_accept_flags);
- __set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);
break;
case BNX2X_RX_MODE_PROMISC:
@@ -5563,36 +5776,57 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
* should receive matched and unmatched (in resolution of port)
* unicast packets.
*/
- __set_bit(BNX2X_ACCEPT_UNMATCHED, &rx_accept_flags);
- __set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags);
- __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &rx_accept_flags);
- __set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_UNMATCHED, rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_BROADCAST, rx_accept_flags);
/* internal switching mode */
- __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &tx_accept_flags);
- __set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags);
if (IS_MF_SI(bp))
- __set_bit(BNX2X_ACCEPT_ALL_UNICAST, &tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_ALL_UNICAST, tx_accept_flags);
else
- __set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags);
break;
default:
- BNX2X_ERR("Unknown rx_mode: %d\n", bp->rx_mode);
- return;
+ BNX2X_ERR("Unknown rx_mode: %d\n", rx_mode);
+ return -EINVAL;
}
+ /* Set ACCEPT_ANY_VLAN as we do not enable filtering by VLAN */
if (bp->rx_mode != BNX2X_RX_MODE_NONE) {
- __set_bit(BNX2X_ACCEPT_ANY_VLAN, &rx_accept_flags);
- __set_bit(BNX2X_ACCEPT_ANY_VLAN, &tx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags);
+ __set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags);
}
+ return 0;
+}
+
+/* called with netif_addr_lock_bh() */
+int bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+{
+ unsigned long rx_mode_flags = 0, ramrod_flags = 0;
+ unsigned long rx_accept_flags = 0, tx_accept_flags = 0;
+ int rc;
+
+ if (!NO_FCOE(bp))
+ /* Configure rx_mode of FCoE Queue */
+ __set_bit(BNX2X_RX_MODE_FCOE_ETH, &rx_mode_flags);
+
+ rc = bnx2x_fill_accept_flags(bp, bp->rx_mode, &rx_accept_flags,
+ &tx_accept_flags);
+ if (rc)
+ return rc;
+
__set_bit(RAMROD_RX, &ramrod_flags);
__set_bit(RAMROD_TX, &ramrod_flags);
- bnx2x_set_q_rx_mode(bp, bp->fp->cl_id, rx_mode_flags, rx_accept_flags,
- tx_accept_flags, ramrod_flags);
+ return bnx2x_set_q_rx_mode(bp, bp->fp->cl_id, rx_mode_flags,
+ rx_accept_flags, tx_accept_flags,
+ ramrod_flags);
}
static void bnx2x_init_internal_common(struct bnx2x *bp)
@@ -5699,6 +5933,13 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
cids[cos] = fp->txdata_ptr[cos]->cid;
}
+ /* nothing more for vf to do here */
+ if (IS_VF(bp))
+ return;
+
+ bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
+ fp->fw_sb_id, fp->igu_sb_id);
+ bnx2x_update_fpsb_idx(fp);
bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id, cids,
fp->max_cos, BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
bnx2x_sp_mapping(bp, q_rdata), q_type);
@@ -5708,13 +5949,10 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
*/
bnx2x_init_vlan_mac_fp_objs(fp, BNX2X_OBJ_TYPE_RX_TX);
- DP(NETIF_MSG_IFUP, "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d fw_sb %d igu_sb %d\n",
- fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
- fp->igu_sb_id);
- bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
- fp->fw_sb_id, fp->igu_sb_id);
-
- bnx2x_update_fpsb_idx(fp);
+ DP(NETIF_MSG_IFUP,
+ "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d fw_sb %d igu_sb %d\n",
+ fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
+ fp->igu_sb_id);
}
static void bnx2x_init_tx_ring_one(struct bnx2x_fp_txdata *txdata)
@@ -5786,17 +6024,22 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
for_each_eth_queue(bp, i)
bnx2x_init_eth_fp(bp, i);
+
+ /* ensure status block indices were read */
+ rmb();
+ bnx2x_init_rx_rings(bp);
+ bnx2x_init_tx_rings(bp);
+
+ if (IS_VF(bp))
+ return;
+
/* Initialize MOD_ABS interrupts */
bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
bp->common.shmem_base, bp->common.shmem2_base,
BP_PORT(bp));
- /* ensure status block indices were read */
- rmb();
bnx2x_init_def_sb(bp);
bnx2x_update_dsb_idx(bp);
- bnx2x_init_rx_rings(bp);
- bnx2x_init_tx_rings(bp);
bnx2x_init_sp_ring(bp);
bnx2x_init_eq_ring(bp);
bnx2x_init_internal(bp, load_code);
@@ -6236,49 +6479,6 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
}
-static void bnx2x_pretend_func(struct bnx2x *bp, u8 pretend_func_num)
-{
- u32 offset = 0;
-
- if (CHIP_IS_E1(bp))
- return;
- if (CHIP_IS_E1H(bp) && (pretend_func_num >= E1H_FUNC_MAX))
- return;
-
- switch (BP_ABS_FUNC(bp)) {
- case 0:
- offset = PXP2_REG_PGL_PRETEND_FUNC_F0;
- break;
- case 1:
- offset = PXP2_REG_PGL_PRETEND_FUNC_F1;
- break;
- case 2:
- offset = PXP2_REG_PGL_PRETEND_FUNC_F2;
- break;
- case 3:
- offset = PXP2_REG_PGL_PRETEND_FUNC_F3;
- break;
- case 4:
- offset = PXP2_REG_PGL_PRETEND_FUNC_F4;
- break;
- case 5:
- offset = PXP2_REG_PGL_PRETEND_FUNC_F5;
- break;
- case 6:
- offset = PXP2_REG_PGL_PRETEND_FUNC_F6;
- break;
- case 7:
- offset = PXP2_REG_PGL_PRETEND_FUNC_F7;
- break;
- default:
- return;
- }
-
- REG_WR(bp, offset, pretend_func_num);
- REG_RD(bp, offset);
- DP(NETIF_MSG_HW, "Pretending to func %d\n", pretend_func_num);
-}
-
void bnx2x_pf_disable(struct bnx2x *bp)
{
u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
@@ -6322,7 +6522,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
DP(NETIF_MSG_HW, "starting common init func %d\n", BP_ABS_FUNC(bp));
/*
- * take the UNDI lock to protect undi_unload flow from accessing
+ * take the RESET lock to protect undi_unload flow from accessing
* registers while we're resetting the chip
*/
bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
@@ -6452,7 +6652,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
* queues with "old" ILT addresses.
* c. PF enable in the PGLC.
* d. Clear the was_error of the PF in the PGLC. (could have
- * occured while driver was down)
+ * occurred while driver was down)
* e. PF enable in the CFC (WEAK + STRONG)
* f. Timers scan enable
* 3. PF driver unload flow:
@@ -6493,7 +6693,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
/* Step 1: set zeroes to all ilt page entries with valid bit on
* Step 2: set the timers first/last ilt entry to point
* to the entire range to prevent ILT range error for 3rd/4th
- * vnic (this code assumes existance of the vnic)
+ * vnic (this code assumes existence of the vnic)
*
* both steps performed by call to bnx2x_ilt_client_init_op()
* with dummy TM client
@@ -6510,7 +6710,6 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
REG_WR(bp, PXP2_REG_RQ_DRAM_ALIGN_SEL, 1);
}
-
REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0);
REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0);
@@ -6535,6 +6734,8 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
bnx2x_init_block(bp, BLOCK_DMAE, PHASE_COMMON);
+ bnx2x_iov_init_dmae(bp);
+
/* clean the DMAE memory */
bp->dmae_ready = 1;
bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8, 1);
@@ -6991,7 +7192,6 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
}
}
-
/* If SPIO5 is set to generate interrupts, enable it for this port */
val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
if (val & MISC_SPIO_SPIO5) {
@@ -7020,15 +7220,14 @@ static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr)
REG_WR_DMAE(bp, reg, wb_write, 2);
}
-static void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func,
- u8 idu_sb_id, bool is_Pf)
+void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, bool is_pf)
{
u32 data, ctl, cnt = 100;
u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA;
u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL;
u32 igu_addr_ack = IGU_REG_CSTORM_TYPE_0_SB_CLEANUP + (idu_sb_id/32)*4;
u32 sb_bit = 1 << (idu_sb_id%32);
- u32 func_encode = func | (is_Pf ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT;
+ u32 func_encode = func | (is_pf ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT;
u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + idu_sb_id;
/* Not supported in BC mode */
@@ -7219,8 +7418,10 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
/* FLR cleanup - hmmm */
if (!CHIP_IS_E1x(bp)) {
rc = bnx2x_pf_flr_clnup(bp);
- if (rc)
+ if (rc) {
+ bnx2x_fw_dump(bp);
return rc;
+ }
}
/* set MSI reconfigure capability */
@@ -7237,12 +7438,21 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
ilt = BP_ILT(bp);
cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start;
+ if (IS_SRIOV(bp))
+ cdu_ilt_start += BNX2X_FIRST_VF_CID/ILT_PAGE_CIDS;
+ cdu_ilt_start = bnx2x_iov_init_ilt(bp, cdu_ilt_start);
+
+ /* since BNX2X_FIRST_VF_CID > 0 the PF L2 cids precedes
+ * those of the VFs, so start line should be reset
+ */
+ cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start;
for (i = 0; i < L2_ILT_LINES(bp); i++) {
ilt->lines[cdu_ilt_start + i].page = bp->context[i].vcxt;
ilt->lines[cdu_ilt_start + i].page_mapping =
bp->context[i].cxt_mapping;
ilt->lines[cdu_ilt_start + i].size = bp->context[i].size;
}
+
bnx2x_ilt_init_op(bp, INITOP_SET);
if (!CONFIGURE_NIC_MODE(bp)) {
@@ -7315,6 +7525,9 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
bnx2x_init_block(bp, BLOCK_TM, init_phase);
bnx2x_init_block(bp, BLOCK_DORQ, init_phase);
+
+ bnx2x_iov_init_dq(bp);
+
bnx2x_init_block(bp, BLOCK_BRB1, init_phase);
bnx2x_init_block(bp, BLOCK_PRS, init_phase);
bnx2x_init_block(bp, BLOCK_TSDM, init_phase);
@@ -7523,10 +7736,6 @@ void bnx2x_free_mem(struct bnx2x *bp)
{
int i;
- /* fastpath */
- bnx2x_free_fp_mem(bp);
- /* end of fastpath */
-
BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
sizeof(struct host_sp_status_block));
@@ -7547,69 +7756,11 @@ void bnx2x_free_mem(struct bnx2x *bp)
BNX2X_PCI_FREE(bp->eq_ring, bp->eq_mapping,
BCM_PAGE_SIZE * NUM_EQ_PAGES);
-}
-
-static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
-{
- int num_groups;
- int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;
-
- /* number of queues for statistics is number of eth queues + FCoE */
- u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;
-
- /* Total number of FW statistics requests =
- * 1 for port stats + 1 for PF stats + potential 1 for FCoE stats +
- * num of queues
- */
- bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;
-
-
- /* Request is built from stats_query_header and an array of
- * stats_query_cmd_group each of which contains
- * STATS_QUERY_CMD_COUNT rules. The real number or requests is
- * configured in the stats_query_header.
- */
- num_groups = ((bp->fw_stats_num) / STATS_QUERY_CMD_COUNT) +
- (((bp->fw_stats_num) % STATS_QUERY_CMD_COUNT) ? 1 : 0);
-
- bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
- num_groups * sizeof(struct stats_query_cmd_group);
-
- /* Data for statistics requests + stats_conter
- *
- * stats_counter holds per-STORM counters that are incremented
- * when STORM has finished with the current request.
- *
- * memory for FCoE offloaded statistics are counted anyway,
- * even if they will not be sent.
- */
- bp->fw_stats_data_sz = sizeof(struct per_port_stats) +
- sizeof(struct per_pf_stats) +
- sizeof(struct fcoe_statistics_params) +
- sizeof(struct per_queue_stats) * num_queue_stats +
- sizeof(struct stats_counter);
-
- BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
- bp->fw_stats_data_sz + bp->fw_stats_req_sz);
- /* Set shortcuts */
- bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
- bp->fw_stats_req_mapping = bp->fw_stats_mapping;
-
- bp->fw_stats_data = (struct bnx2x_fw_stats_data *)
- ((u8 *)bp->fw_stats + bp->fw_stats_req_sz);
-
- bp->fw_stats_data_mapping = bp->fw_stats_mapping +
- bp->fw_stats_req_sz;
- return 0;
-
-alloc_mem_err:
- BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
- bp->fw_stats_data_sz + bp->fw_stats_req_sz);
- BNX2X_ERR("Can't allocate memory\n");
- return -ENOMEM;
+ bnx2x_iov_free_mem(bp);
}
+
int bnx2x_alloc_mem_cnic(struct bnx2x *bp)
{
if (!CHIP_IS_E1x(bp))
@@ -7655,10 +7806,6 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
sizeof(struct bnx2x_slowpath));
- /* Allocated memory for FW statistics */
- if (bnx2x_alloc_fw_stats_mem(bp))
- goto alloc_mem_err;
-
/* Allocate memory for CDU context:
* This memory is allocated separately and not in the generic ILT
* functions because CDU differs in few aspects:
@@ -7687,6 +7834,9 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC))
goto alloc_mem_err;
+ if (bnx2x_iov_alloc_mem(bp))
+ goto alloc_mem_err;
+
/* Slow path ring */
BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);
@@ -7694,13 +7844,6 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping,
BCM_PAGE_SIZE * NUM_EQ_PAGES);
-
- /* 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:
@@ -7803,43 +7946,53 @@ int bnx2x_setup_leading(struct bnx2x *bp)
*
* In case of MSI-X it will also try to enable MSI-X.
*/
-void bnx2x_set_int_mode(struct bnx2x *bp)
+int bnx2x_set_int_mode(struct bnx2x *bp)
{
+ int rc = 0;
+
+ if (IS_VF(bp) && int_mode != BNX2X_INT_MODE_MSIX)
+ return -EINVAL;
+
switch (int_mode) {
- case INT_MODE_MSI:
+ case BNX2X_INT_MODE_MSIX:
+ /* attempt to enable msix */
+ rc = bnx2x_enable_msix(bp);
+
+ /* msix attained */
+ if (!rc)
+ return 0;
+
+ /* vfs use only msix */
+ if (rc && IS_VF(bp))
+ return rc;
+
+ /* failed to enable multiple MSI-X */
+ BNX2X_DEV_INFO("Failed to enable multiple MSI-X (%d), set number of queues to %d\n",
+ bp->num_queues,
+ 1 + bp->num_cnic_queues);
+
+ /* falling through... */
+ case BNX2X_INT_MODE_MSI:
bnx2x_enable_msi(bp);
+
/* falling through... */
- case INT_MODE_INTx:
+ case BNX2X_INT_MODE_INTX:
bp->num_ethernet_queues = 1;
bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
BNX2X_DEV_INFO("set number of queues to 1\n");
break;
default:
- /* if we can't use MSI-X we only need one fp,
- * so try to enable MSI-X with the requested number of fp's
- * and fallback to MSI or legacy INTx with one fp
- */
- if (bnx2x_enable_msix(bp) ||
- bp->flags & USING_SINGLE_MSIX_FLAG) {
- /* failed to enable multiple MSI-X */
- BNX2X_DEV_INFO("Failed to enable multiple MSI-X (%d), set number of queues to %d\n",
- bp->num_queues,
- 1 + bp->num_cnic_queues);
-
- bp->num_queues = 1 + bp->num_cnic_queues;
-
- /* Try to enable MSI */
- if (!(bp->flags & USING_SINGLE_MSIX_FLAG) &&
- !(bp->flags & DISABLE_MSI_FLAG))
- bnx2x_enable_msi(bp);
- }
- break;
+ BNX2X_DEV_INFO("unknown value in int_mode module parameter\n");
+ return -EINVAL;
}
+ return 0;
}
-/* must be called prioir to any HW initializations */
+/* must be called prior to any HW initializations */
static inline u16 bnx2x_cid_ilt_lines(struct bnx2x *bp)
{
+ if (IS_SRIOV(bp))
+ return (BNX2X_FIRST_VF_CID + BNX2X_VF_CIDS)/ILT_PAGE_CIDS;
return L2_ILT_LINES(bp);
}
@@ -8222,8 +8375,8 @@ static void bnx2x_reset_func(struct bnx2x *bp)
/* SP SB */
REG_WR8(bp, BAR_CSTRORM_INTMEM +
- CSTORM_SP_STATUS_BLOCK_DATA_STATE_OFFSET(func),
- SB_DISABLED);
+ CSTORM_SP_STATUS_BLOCK_DATA_STATE_OFFSET(func),
+ SB_DISABLED);
for (i = 0; i < XSTORM_SPQ_DATA_SIZE / 4; i++)
REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_DATA_OFFSET(func),
@@ -8524,7 +8677,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode, bool keep_link)
}
/* Give HW time to discard old tx messages */
- usleep_range(1000, 1000);
+ usleep_range(1000, 2000);
/* Clean all ETH MACs */
rc = bnx2x_del_all_macs(bp, &bp->sp_objs[0].mac_obj, BNX2X_ETH_MAC,
@@ -8562,6 +8715,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode, bool keep_link)
netif_addr_unlock_bh(bp->dev);
+ bnx2x_iov_chip_cleanup(bp);
/*
@@ -8689,7 +8843,7 @@ static void bnx2x_set_234_gates(struct bnx2x *bp, bool close)
(!close) ? (val | HC_CONFIG_0_REG_BLOCK_DISABLE_0) :
(val & ~(u32)HC_CONFIG_0_REG_BLOCK_DISABLE_0));
} else {
- /* Prevent incomming interrupts in IGU */
+ /* Prevent incoming interrupts in IGU */
val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION);
REG_WR(bp, IGU_REG_BLOCK_CONFIGURATION,
@@ -8947,7 +9101,7 @@ static int bnx2x_er_poll_igu_vq(struct bnx2x *bp)
if (pend_bits == 0)
break;
- usleep_range(1000, 1000);
+ usleep_range(1000, 2000);
} while (cnt-- > 0);
if (cnt <= 0) {
@@ -8964,8 +9118,7 @@ static int bnx2x_process_kill(struct bnx2x *bp, bool global)
int cnt = 1000;
u32 val = 0;
u32 sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, pgl_exp_rom2;
- u32 tags_63_32 = 0;
-
+ u32 tags_63_32 = 0;
/* Empty the Tetris buffer, wait for 1s */
do {
@@ -8983,7 +9136,7 @@ static int bnx2x_process_kill(struct bnx2x *bp, bool global)
(pgl_exp_rom2 == 0xffffffff) &&
(!CHIP_IS_E3(bp) || (tags_63_32 == 0xffffffff)))
break;
- usleep_range(1000, 1000);
+ usleep_range(1000, 2000);
} while (cnt-- > 0);
if (cnt <= 0) {
@@ -9016,7 +9169,7 @@ static int bnx2x_process_kill(struct bnx2x *bp, bool global)
/* Wait for 1ms to empty GLUE and PCI-E core queues,
* PSWHST, GRC and PSWRD Tetris buffer.
*/
- usleep_range(1000, 1000);
+ usleep_range(1000, 2000);
/* Prepare to chip reset: */
/* MCP */
@@ -9299,8 +9452,10 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
rtnl_lock();
- if (!netif_running(bp->dev))
- goto sp_rtnl_exit;
+ if (!netif_running(bp->dev)) {
+ rtnl_unlock();
+ return;
+ }
/* if stop on error is defined no recovery flows should be executed */
#ifdef BNX2X_STOP_ON_ERROR
@@ -9319,7 +9474,8 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
bnx2x_parity_recover(bp);
- goto sp_rtnl_exit;
+ rtnl_unlock();
+ return;
}
if (test_and_clear_bit(BNX2X_SP_RTNL_TX_TIMEOUT, &bp->sp_rtnl_state)) {
@@ -9333,7 +9489,8 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
bnx2x_nic_unload(bp, UNLOAD_NORMAL, true);
bnx2x_nic_load(bp, LOAD_NORMAL);
- goto sp_rtnl_exit;
+ rtnl_unlock();
+ return;
}
#ifdef BNX2X_STOP_ON_ERROR
sp_rtnl_not_reset:
@@ -9351,13 +9508,33 @@ sp_rtnl_not_reset:
DP(NETIF_MSG_HW, "fan failure detected. Unloading driver\n");
netif_device_detach(bp->dev);
bnx2x_close(bp->dev);
+ rtnl_unlock();
+ return;
}
-sp_rtnl_exit:
+ if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_MCAST, &bp->sp_rtnl_state)) {
+ DP(BNX2X_MSG_SP,
+ "sending set mcast vf pf channel message from rtnl sp-task\n");
+ bnx2x_vfpf_set_mcast(bp->dev);
+ }
+
+ if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+ &bp->sp_rtnl_state)) {
+ DP(BNX2X_MSG_SP,
+ "sending set storm rx mode vf pf channel message from rtnl sp-task\n");
+ bnx2x_vfpf_storm_rx_mode(bp);
+ }
+
+ /* work which needs rtnl lock not-taken (as it takes the lock itself and
+ * can be called from other contexts as well)
+ */
rtnl_unlock();
-}
-/* end of nic load/unload */
+ /* enable SR-IOV if applicable */
+ if (IS_SRIOV(bp) && test_and_clear_bit(BNX2X_SP_RTNL_ENABLE_SRIOV,
+ &bp->sp_rtnl_state))
+ bnx2x_enable_sriov(bp);
+}
static void bnx2x_period_task(struct work_struct *work)
{
@@ -9394,43 +9571,13 @@ period_task_exit:
* Init service functions
*/
-static u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
+u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
{
u32 base = PXP2_REG_PGL_PRETEND_FUNC_F0;
u32 stride = PXP2_REG_PGL_PRETEND_FUNC_F1 - base;
return base + (BP_ABS_FUNC(bp)) * stride;
}
-static void bnx2x_undi_int_disable_e1h(struct bnx2x *bp)
-{
- u32 reg = bnx2x_get_pretend_reg(bp);
-
- /* Flush all outstanding writes */
- mmiowb();
-
- /* Pretend to be function 0 */
- REG_WR(bp, reg, 0);
- REG_RD(bp, reg); /* Flush the GRC transaction (in the chip) */
-
- /* From now we are in the "like-E1" mode */
- bnx2x_int_disable(bp);
-
- /* Flush all outstanding writes */
- mmiowb();
-
- /* Restore the original function */
- REG_WR(bp, reg, BP_ABS_FUNC(bp));
- REG_RD(bp, reg);
-}
-
-static inline void bnx2x_undi_int_disable(struct bnx2x *bp)
-{
- if (CHIP_IS_E1(bp))
- bnx2x_int_disable(bp);
- else
- bnx2x_undi_int_disable_e1h(bp);
-}
-
static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
struct bnx2x_mac_vals *vals)
{
@@ -9658,11 +9805,13 @@ static int bnx2x_prev_unload_uncommon(struct bnx2x *bp)
if (bnx2x_prev_is_path_marked(bp))
return bnx2x_prev_mcp_done(bp);
+ BNX2X_DEV_INFO("Path is unmarked\n");
+
/* If function has FLR capabilities, and existing FW version matches
* the one required, then FLR will be sufficient to clean any residue
* left by previous driver
*/
- rc = bnx2x_test_firmware_version(bp, false);
+ rc = bnx2x_nic_load_analyze_req(bp, FW_MSG_CODE_DRV_LOAD_FUNCTION);
if (!rc) {
/* fw version is good */
@@ -9718,7 +9867,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
/* Check if the UNDI driver was previously loaded
* UNDI driver initializes CID offset for normal bell to 0x7
*/
- reset_reg = REG_RD(bp, MISC_REG_RESET_REG_1);
if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_DORQ) {
tmp_reg = REG_RD(bp, DORQ_REG_NORM_CID_OFST);
if (tmp_reg == 0x7) {
@@ -9726,6 +9874,8 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
prev_undi = true;
/* clear the UNDI indication */
REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0);
+ /* clear possible idle check errors */
+ REG_RD(bp, NIG_REG_NIG_INT_STS_CLR_0);
}
}
/* wait until BRB is empty */
@@ -9792,7 +9942,8 @@ static void bnx2x_prev_interrupted_dmae(struct bnx2x *bp)
if (!CHIP_IS_E1x(bp)) {
u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS);
if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) {
- BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing");
+ DP(BNX2X_MSG_SP,
+ "'was error' bit was found to be set in pglueb upon startup. Clearing\n");
REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR,
1 << BP_FUNC(bp));
}
@@ -9834,7 +9985,6 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
REG_WR(bp, MCP_REG_MCPR_ACCESS_LOCK, 0);
}
-
do {
/* Lock MCP using an unload request */
fw = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS, 0);
@@ -10401,10 +10551,10 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
static void bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi)
{
- mac_hi = cpu_to_be16(mac_hi);
- mac_lo = cpu_to_be32(mac_lo);
- memcpy(mac_buf, &mac_hi, sizeof(mac_hi));
- memcpy(mac_buf + sizeof(mac_hi), &mac_lo, sizeof(mac_lo));
+ __be16 mac_hi_be = cpu_to_be16(mac_hi);
+ __be32 mac_lo_be = cpu_to_be32(mac_lo);
+ memcpy(mac_buf, &mac_hi_be, sizeof(mac_hi_be));
+ memcpy(mac_buf + sizeof(mac_hi_be), &mac_lo_be, sizeof(mac_lo_be));
}
static void bnx2x_get_port_hwinfo(struct bnx2x *bp)
@@ -10440,6 +10590,13 @@ static void bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
(config & PORT_FEATURE_WOL_ENABLED));
+ if ((config & PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK) ==
+ PORT_FEAT_CFG_STORAGE_PERSONALITY_FCOE && !IS_MF(bp))
+ bp->flags |= NO_ISCSI_FLAG;
+ if ((config & PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK) ==
+ PORT_FEAT_CFG_STORAGE_PERSONALITY_ISCSI && !(IS_MF(bp)))
+ bp->flags |= NO_FCOE_FLAG;
+
BNX2X_DEV_INFO("lane_config 0x%08x speed_cap_mask0 0x%08x link_config0 0x%08x\n",
bp->link_params.lane_config,
bp->link_params.speed_cap_mask[0],
@@ -10547,21 +10704,21 @@ static void bnx2x_get_fcoe_info(struct bnx2x *bp)
/* Port info */
bp->cnic_eth_dev.fcoe_wwn_port_name_hi =
SHMEM_RD(bp,
- dev_info.port_hw_config[port].
+ dev_info.port_hw_config[port].
fcoe_wwn_port_name_upper);
bp->cnic_eth_dev.fcoe_wwn_port_name_lo =
SHMEM_RD(bp,
- dev_info.port_hw_config[port].
+ dev_info.port_hw_config[port].
fcoe_wwn_port_name_lower);
/* Node info */
bp->cnic_eth_dev.fcoe_wwn_node_name_hi =
SHMEM_RD(bp,
- dev_info.port_hw_config[port].
+ dev_info.port_hw_config[port].
fcoe_wwn_node_name_upper);
bp->cnic_eth_dev.fcoe_wwn_node_name_lo =
SHMEM_RD(bp,
- dev_info.port_hw_config[port].
+ dev_info.port_hw_config[port].
fcoe_wwn_node_name_lower);
} else if (!IS_MF_SD(bp)) {
/*
@@ -10659,7 +10816,7 @@ static void bnx2x_get_cnic_mac_hwinfo(struct bnx2x *bp)
/* Zero primary MAC configuration */
memset(bp->dev->dev_addr, 0, ETH_ALEN);
- if (IS_MF_FCOE_AFEX(bp))
+ if (IS_MF_FCOE_AFEX(bp) || IS_MF_FCOE_SD(bp))
/* use FIP MAC as primary MAC */
memcpy(bp->dev->dev_addr, fip_mac, ETH_ALEN);
@@ -10722,7 +10879,6 @@ static void bnx2x_get_mac_hwinfo(struct bnx2x *bp)
}
memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
- memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
if (!bnx2x_is_valid_ether_addr(bp, bp->dev->dev_addr))
dev_err(&bp->pdev->dev,
@@ -10787,7 +10943,7 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp)
while (tout && REG_RD(bp, IGU_REG_RESET_MEMORIES)) {
tout--;
- usleep_range(1000, 1000);
+ usleep_range(1000, 2000);
}
if (REG_RD(bp, IGU_REG_RESET_MEMORIES)) {
@@ -11125,9 +11281,13 @@ static int bnx2x_init_bp(struct bnx2x *bp)
INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
INIT_DELAYED_WORK(&bp->period_task, bnx2x_period_task);
- rc = bnx2x_get_hwinfo(bp);
- if (rc)
- return rc;
+ if (IS_PF(bp)) {
+ rc = bnx2x_get_hwinfo(bp);
+ if (rc)
+ return rc;
+ } else {
+ random_ether_addr(bp->dev->dev_addr);
+ }
bnx2x_set_modes_bitmap(bp);
@@ -11140,7 +11300,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
func = BP_FUNC(bp);
/* need to reset chip if undi was active */
- if (!BP_NOMCP(bp)) {
+ if (IS_PF(bp) && !BP_NOMCP(bp)) {
/* init fw_seq */
bp->fw_seq =
SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
@@ -11177,6 +11337,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
bp->mrrs = mrrs;
bp->tx_ring_size = IS_MF_FCOE_AFEX(bp) ? 0 : MAX_TX_AVAIL;
+ if (IS_VF(bp))
+ bp->rx_ring_size = MAX_RX_AVAIL;
/* make sure that the numbers are in the right granularity */
bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR;
@@ -11205,12 +11367,18 @@ static int bnx2x_init_bp(struct bnx2x *bp)
bp->cnic_base_cl_id = FP_SB_MAX_E2;
/* multiple tx priority */
- if (CHIP_IS_E1x(bp))
+ if (IS_VF(bp))
+ bp->max_cos = 1;
+ else if (CHIP_IS_E1x(bp))
bp->max_cos = BNX2X_MULTI_TX_COS_E1X;
- if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp))
+ else if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp))
bp->max_cos = BNX2X_MULTI_TX_COS_E2_E3A0;
- if (CHIP_IS_E3B0(bp))
+ else if (CHIP_IS_E3B0(bp))
bp->max_cos = BNX2X_MULTI_TX_COS_E3B0;
+ else
+ BNX2X_ERR("unknown chip %x revision %x\n",
+ CHIP_NUM(bp), CHIP_REV(bp));
+ BNX2X_DEV_INFO("set bp->max_cos to %d\n", bp->max_cos);
/* We need at least one default status block for slow-path events,
* second status block for the L2 queue, and a third status block for
@@ -11234,6 +11402,26 @@ static int bnx2x_init_bp(struct bnx2x *bp)
* net_device service functions
*/
+static int bnx2x_open_epilog(struct bnx2x *bp)
+{
+ /* Enable sriov via delayed work. This must be done via delayed work
+ * because it causes the probe of the vf devices to be run, which invoke
+ * register_netdevice which must have rtnl lock taken. As we are holding
+ * the lock right now, that could only work if the probe would not take
+ * the lock. However, as the probe of the vf may be called from other
+ * contexts as well (such as passthrough to vm failes) it can't assume
+ * the lock is being held for it. Using delayed work here allows the
+ * probe code to simply take the lock (i.e. wait for it to be released
+ * if it is being held).
+ */
+ smp_mb__before_clear_bit();
+ set_bit(BNX2X_SP_RTNL_ENABLE_SRIOV, &bp->sp_rtnl_state);
+ smp_mb__after_clear_bit();
+ schedule_delayed_work(&bp->sp_rtnl_task, 0);
+
+ return 0;
+}
+
/* called with rtnl_lock */
static int bnx2x_open(struct net_device *dev)
{
@@ -11241,6 +11429,7 @@ static int bnx2x_open(struct net_device *dev)
bool global = false;
int other_engine = BP_PATH(bp) ? 0 : 1;
bool other_load_status, load_status;
+ int rc;
bp->stats_init = true;
@@ -11248,53 +11437,57 @@ static int bnx2x_open(struct net_device *dev)
bnx2x_set_power_state(bp, PCI_D0);
- other_load_status = bnx2x_get_load_status(bp, other_engine);
- load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
-
- /*
- * If parity had happen during the unload, then attentions
+ /* If parity had happen during the unload, then attentions
* and/or RECOVERY_IN_PROGRES may still be set. In this case we
* want the first function loaded on the current engine to
* complete the recovery.
+ * Parity recovery is only relevant for PF driver.
*/
- if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
- bnx2x_chk_parity_attn(bp, &global, true))
- do {
- /*
- * If there are attentions and they are in a global
- * blocks, set the GLOBAL_RESET bit regardless whether
- * it will be this function that will complete the
- * recovery or not.
- */
- if (global)
- bnx2x_set_reset_global(bp);
+ if (IS_PF(bp)) {
+ other_load_status = bnx2x_get_load_status(bp, other_engine);
+ load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
+ if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
+ bnx2x_chk_parity_attn(bp, &global, true)) {
+ do {
+ /* If there are attentions and they are in a
+ * global blocks, set the GLOBAL_RESET bit
+ * regardless whether it will be this function
+ * that will complete the recovery or not.
+ */
+ if (global)
+ bnx2x_set_reset_global(bp);
- /*
- * Only the first function on the current engine should
- * try to recover in open. In case of attentions in
- * global blocks only the first in the chip should try
- * to recover.
- */
- if ((!load_status &&
- (!global || !other_load_status)) &&
- bnx2x_trylock_leader_lock(bp) &&
- !bnx2x_leader_reset(bp)) {
- netdev_info(bp->dev, "Recovered in open\n");
- break;
- }
+ /* Only the first function on the current
+ * engine should try to recover in open. In case
+ * of attentions in global blocks only the first
+ * in the chip should try to recover.
+ */
+ if ((!load_status &&
+ (!global || !other_load_status)) &&
+ bnx2x_trylock_leader_lock(bp) &&
+ !bnx2x_leader_reset(bp)) {
+ netdev_info(bp->dev,
+ "Recovered in open\n");
+ break;
+ }
- /* recovery has failed... */
- bnx2x_set_power_state(bp, PCI_D3hot);
- bp->recovery_state = BNX2X_RECOVERY_FAILED;
+ /* recovery has failed... */
+ bnx2x_set_power_state(bp, PCI_D3hot);
+ bp->recovery_state = BNX2X_RECOVERY_FAILED;
- BNX2X_ERR("Recovery flow hasn't been properly completed yet. Try again later.\n"
- "If you still see this message after a few retries then power cycle is required.\n");
+ BNX2X_ERR("Recovery flow hasn't been properly completed yet. Try again later.\n"
+ "If you still see this message after a few retries then power cycle is required.\n");
- return -EAGAIN;
- } while (0);
+ return -EAGAIN;
+ } while (0);
+ }
+ }
bp->recovery_state = BNX2X_RECOVERY_DONE;
- return bnx2x_nic_load(bp, LOAD_OPEN);
+ rc = bnx2x_nic_load(bp, LOAD_OPEN);
+ if (rc)
+ return rc;
+ return bnx2x_open_epilog(bp);
}
/* called with rtnl_lock */
@@ -11428,7 +11621,6 @@ static int bnx2x_set_mc_list(struct bnx2x *bp)
return rc;
}
-
/* If bp->state is OPEN, should be called with netif_addr_lock_bh() */
void bnx2x_set_rx_mode(struct net_device *dev)
{
@@ -11449,12 +11641,25 @@ void bnx2x_set_rx_mode(struct net_device *dev)
CHIP_IS_E1(bp)))
rx_mode = BNX2X_RX_MODE_ALLMULTI;
else {
- /* some multicasts */
- if (bnx2x_set_mc_list(bp) < 0)
- rx_mode = BNX2X_RX_MODE_ALLMULTI;
+ if (IS_PF(bp)) {
+ /* some multicasts */
+ if (bnx2x_set_mc_list(bp) < 0)
+ rx_mode = BNX2X_RX_MODE_ALLMULTI;
- if (bnx2x_set_uc_list(bp) < 0)
- rx_mode = BNX2X_RX_MODE_PROMISC;
+ if (bnx2x_set_uc_list(bp) < 0)
+ rx_mode = BNX2X_RX_MODE_PROMISC;
+ } else {
+ /* configuring mcast to a vf involves sleeping (when we
+ * wait for the pf's response). Since this function is
+ * called from non sleepable context we must schedule
+ * a work item for this purpose
+ */
+ smp_mb__before_clear_bit();
+ set_bit(BNX2X_SP_RTNL_VFPF_MCAST,
+ &bp->sp_rtnl_state);
+ smp_mb__after_clear_bit();
+ schedule_delayed_work(&bp->sp_rtnl_task, 0);
+ }
}
bp->rx_mode = rx_mode;
@@ -11468,7 +11673,20 @@ void bnx2x_set_rx_mode(struct net_device *dev)
return;
}
- bnx2x_set_storm_rx_mode(bp);
+ if (IS_PF(bp)) {
+ bnx2x_set_storm_rx_mode(bp);
+ } else {
+ /* configuring rx mode to storms in a vf involves sleeping (when
+ * we wait for the pf's response). Since this function is
+ * called from non sleepable context we must schedule
+ * a work item for this purpose
+ */
+ smp_mb__before_clear_bit();
+ set_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+ &bp->sp_rtnl_state);
+ smp_mb__after_clear_bit();
+ schedule_delayed_work(&bp->sp_rtnl_task, 0);
+ }
}
/* called with rtnl_lock */
@@ -11571,7 +11789,9 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_poll_controller = poll_bnx2x,
#endif
.ndo_setup_tc = bnx2x_setup_tc,
-
+#ifdef CONFIG_BNX2X_SRIOV
+ .ndo_set_vf_mac = bnx2x_set_vf_mac,
+#endif
#ifdef NETDEV_FCOE_WWNN
.ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn,
#endif
@@ -11595,10 +11815,9 @@ static int bnx2x_set_coherency_mask(struct bnx2x *bp)
return 0;
}
-static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
- unsigned long board_type)
+static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
+ struct net_device *dev, unsigned long board_type)
{
- struct bnx2x *bp;
int rc;
u32 pci_cfg_dword;
bool chip_is_e1x = (board_type == BCM57710 ||
@@ -11606,11 +11825,9 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
board_type == BCM57711E);
SET_NETDEV_DEV(dev, &pdev->dev);
- bp = netdev_priv(dev);
bp->dev = dev;
bp->pdev = pdev;
- bp->flags = 0;
rc = pci_enable_device(pdev);
if (rc) {
@@ -11626,9 +11843,8 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
goto err_out_disable;
}
- if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
- dev_err(&bp->pdev->dev, "Cannot find second PCI device"
- " base address, aborting\n");
+ if (IS_PF(bp) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+ dev_err(&bp->pdev->dev, "Cannot find second PCI device base address, aborting\n");
rc = -ENODEV;
goto err_out_disable;
}
@@ -11653,12 +11869,14 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
pci_save_state(pdev);
}
- bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (bp->pm_cap == 0) {
- dev_err(&bp->pdev->dev,
- "Cannot find power management capability, aborting\n");
- rc = -EIO;
- goto err_out_release;
+ if (IS_PF(bp)) {
+ bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (bp->pm_cap == 0) {
+ dev_err(&bp->pdev->dev,
+ "Cannot find power management capability, aborting\n");
+ rc = -EIO;
+ goto err_out_release;
+ }
}
if (!pci_is_pcie(pdev)) {
@@ -11690,13 +11908,14 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
* support Physical Device Assignment where kernel BDF maybe arbitrary
* (depending on hypervisor).
*/
- if (chip_is_e1x)
+ if (chip_is_e1x) {
bp->pf_num = PCI_FUNC(pdev->devfn);
- else {/* chip is E2/3*/
+ } else {
+ /* chip is E2/3*/
pci_read_config_dword(bp->pdev,
PCICFG_ME_REGISTER, &pci_cfg_dword);
bp->pf_num = (u8)((pci_cfg_dword & ME_REG_ABS_PF_NUM) >>
- ME_REG_ABS_PF_NUM_SHIFT);
+ ME_REG_ABS_PF_NUM_SHIFT);
}
BNX2X_DEV_INFO("me reg PF num: %d\n", bp->pf_num);
@@ -11709,25 +11928,28 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
* Clean the following indirect addresses for all functions since it
* is not used by the driver.
*/
- REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
+ if (IS_PF(bp)) {
+ REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
+
+ if (chip_is_e1x) {
+ REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
+ REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+ }
- if (chip_is_e1x) {
- REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
- REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+ /* Enable internal target-read (in case we are probed after PF
+ * FLR). Must be done prior to any BAR read access. Only for
+ * 57712 and up
+ */
+ if (!chip_is_e1x)
+ REG_WR(bp,
+ PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
}
- /*
- * Enable internal target-read (in case we are probed after PF FLR).
- * Must be done prior to any BAR read access. Only for 57712 and up
- */
- if (!chip_is_e1x)
- REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
-
dev->watchdog_timeo = TX_TIMEOUT;
dev->netdev_ops = &bnx2x_netdev_ops;
@@ -11778,8 +12000,9 @@ err_out:
static void bnx2x_get_pcie_width_speed(struct bnx2x *bp, int *width, int *speed)
{
- u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL);
+ u32 val = 0;
+ pci_read_config_dword(bp->pdev, PCICFG_LINK_CONTROL, &val);
*width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
/* return value of 1=2.5GHz 2=5GHz */
@@ -11792,7 +12015,7 @@ static int bnx2x_check_firmware(struct bnx2x *bp)
struct bnx2x_fw_file_hdr *fw_hdr;
struct bnx2x_fw_file_section *sections;
u32 offset, len, num_ops;
- u16 *ops_offsets;
+ __be16 *ops_offsets;
int i;
const u8 *fw_ver;
@@ -11817,7 +12040,7 @@ static int bnx2x_check_firmware(struct bnx2x *bp)
/* Likewise for the init_ops offsets */
offset = be32_to_cpu(fw_hdr->init_ops_offsets.offset);
- ops_offsets = (u16 *)(firmware->data + offset);
+ ops_offsets = (__force __be16 *)(firmware->data + offset);
num_ops = be32_to_cpu(fw_hdr->init_ops.len) / sizeof(struct raw_op);
for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) {
@@ -12044,8 +12267,12 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp)
{
int cid_count = BNX2X_L2_MAX_CID(bp);
+ if (IS_SRIOV(bp))
+ cid_count += BNX2X_VF_CIDS;
+
if (CNIC_SUPPORT(bp))
cid_count += CNIC_CID_MAX;
+
return roundup(cid_count, QM_CID_ROUND);
}
@@ -12056,10 +12283,10 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp)
*
*/
static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev,
- int cnic_cnt)
+ int cnic_cnt, bool is_vf)
{
- int pos;
- u16 control;
+ int pos, index;
+ u16 control = 0;
pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
@@ -12067,85 +12294,114 @@ static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev,
* If MSI-X is not supported - return number of SBs needed to support
* one fast path queue: one FP queue + SB for CNIC
*/
- if (!pos)
+ if (!pos) {
+ dev_info(&pdev->dev, "no msix capability found\n");
return 1 + cnic_cnt;
+ }
+ dev_info(&pdev->dev, "msix capability found\n");
/*
* The value in the PCI configuration space is the index of the last
* entry, namely one less than the actual size of the table, which is
* exactly what we want to return from this function: number of all SBs
* without the default SB.
+ * For VFs there is no default SB, then we return (index+1).
*/
pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &control);
- return control & PCI_MSIX_FLAGS_QSIZE;
-}
-struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *);
+ index = control & PCI_MSIX_FLAGS_QSIZE;
-static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- struct net_device *dev = NULL;
- struct bnx2x *bp;
- int pcie_width, pcie_speed;
- int rc, max_non_def_sbs;
- int rx_count, tx_count, rss_count, doorbell_size;
- int cnic_cnt;
- /*
- * An estimated maximum supported CoS number according to the chip
- * version.
- * We will try to roughly estimate the maximum number of CoSes this chip
- * may support in order to minimize the memory allocated for Tx
- * netdev_queue's. This number will be accurately calculated during the
- * initialization of bp->max_cos based on the chip versions AND chip
- * revision in the bnx2x_init_bp().
- */
- u8 max_cos_est = 0;
+ return is_vf ? index + 1 : index;
+}
- switch (ent->driver_data) {
+static int set_max_cos_est(int chip_id)
+{
+ switch (chip_id) {
case BCM57710:
case BCM57711:
case BCM57711E:
- max_cos_est = BNX2X_MULTI_TX_COS_E1X;
- break;
-
+ return BNX2X_MULTI_TX_COS_E1X;
case BCM57712:
case BCM57712_MF:
- max_cos_est = BNX2X_MULTI_TX_COS_E2_E3A0;
- break;
-
+ case BCM57712_VF:
+ return BNX2X_MULTI_TX_COS_E2_E3A0;
case BCM57800:
case BCM57800_MF:
+ case BCM57800_VF:
case BCM57810:
case BCM57810_MF:
- case BCM57840_O:
case BCM57840_4_10:
case BCM57840_2_20:
+ case BCM57840_O:
case BCM57840_MFO:
+ case BCM57810_VF:
case BCM57840_MF:
+ case BCM57840_VF:
case BCM57811:
case BCM57811_MF:
- max_cos_est = BNX2X_MULTI_TX_COS_E3B0;
- break;
-
+ case BCM57811_VF:
+ return BNX2X_MULTI_TX_COS_E3B0;
+ return 1;
default:
- pr_err("Unknown board_type (%ld), aborting\n",
- ent->driver_data);
+ pr_err("Unknown board_type (%d), aborting\n", chip_id);
return -ENODEV;
}
+}
+
+static int set_is_vf(int chip_id)
+{
+ switch (chip_id) {
+ case BCM57712_VF:
+ case BCM57800_VF:
+ case BCM57810_VF:
+ case BCM57840_VF:
+ case BCM57811_VF:
+ return true;
+ default:
+ return false;
+ }
+}
- cnic_cnt = 1;
- max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev, cnic_cnt);
+struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
- WARN_ON(!max_non_def_sbs);
+static int bnx2x_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *dev = NULL;
+ struct bnx2x *bp;
+ int pcie_width, pcie_speed;
+ int rc, max_non_def_sbs;
+ int rx_count, tx_count, rss_count, doorbell_size;
+ int max_cos_est;
+ bool is_vf;
+ int cnic_cnt;
+
+ /* An estimated maximum supported CoS number according to the chip
+ * version.
+ * We will try to roughly estimate the maximum number of CoSes this chip
+ * may support in order to minimize the memory allocated for Tx
+ * netdev_queue's. This number will be accurately calculated during the
+ * initialization of bp->max_cos based on the chip versions AND chip
+ * revision in the bnx2x_init_bp().
+ */
+ max_cos_est = set_max_cos_est(ent->driver_data);
+ if (max_cos_est < 0)
+ return max_cos_est;
+ is_vf = set_is_vf(ent->driver_data);
+ cnic_cnt = is_vf ? 0 : 1;
+
+ max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev, cnic_cnt, is_vf);
/* Maximum number of RSS queues: one IGU SB goes to CNIC */
- rss_count = max_non_def_sbs - cnic_cnt;
+ rss_count = is_vf ? 1 : max_non_def_sbs - cnic_cnt;
+
+ if (rss_count < 1)
+ return -EINVAL;
/* Maximum number of netdev Rx queues: RSS + FCoE L2 */
rx_count = rss_count + cnic_cnt;
- /*
- * Maximum number of netdev Tx queues:
+ /* Maximum number of netdev Tx queues:
* Maximum TSS queues * Maximum supported number of CoS + FCoE L2
*/
tx_count = rss_count * max_cos_est + cnic_cnt;
@@ -12157,42 +12413,55 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bp = netdev_priv(dev);
+ bp->flags = 0;
+ if (is_vf)
+ bp->flags |= IS_VF_FLAG;
+
bp->igu_sb_cnt = max_non_def_sbs;
+ bp->igu_base_addr = IS_VF(bp) ? PXP_VF_ADDR_IGU_START : BAR_IGU_INTMEM;
bp->msg_enable = debug;
bp->cnic_support = cnic_cnt;
bp->cnic_probe = bnx2x_cnic_probe;
pci_set_drvdata(pdev, dev);
- rc = bnx2x_init_dev(pdev, dev, ent->driver_data);
+ rc = bnx2x_init_dev(bp, pdev, dev, ent->driver_data);
if (rc < 0) {
free_netdev(dev);
return rc;
}
+ BNX2X_DEV_INFO("This is a %s function\n",
+ IS_PF(bp) ? "physical" : "virtual");
BNX2X_DEV_INFO("Cnic support is %s\n", CNIC_SUPPORT(bp) ? "on" : "off");
- BNX2X_DEV_INFO("max_non_def_sbs %d\n", max_non_def_sbs);
-
+ BNX2X_DEV_INFO("Max num of status blocks %d\n", max_non_def_sbs);
BNX2X_DEV_INFO("Allocated netdev with %d tx and %d rx queues\n",
- tx_count, rx_count);
+ tx_count, rx_count);
rc = bnx2x_init_bp(bp);
if (rc)
goto init_one_exit;
- /*
- * Map doorbels here as we need the real value of bp->max_cos which
- * is initialized in bnx2x_init_bp().
+ /* Map doorbells here as we need the real value of bp->max_cos which
+ * is initialized in bnx2x_init_bp() to determine the number of
+ * l2 connections.
*/
- doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
- if (doorbell_size > pci_resource_len(pdev, 2)) {
- dev_err(&bp->pdev->dev,
- "Cannot map doorbells, bar size too small, aborting\n");
- rc = -ENOMEM;
- goto init_one_exit;
+ if (IS_VF(bp)) {
+ bnx2x_vf_map_doorbells(bp);
+ rc = bnx2x_vf_pci_alloc(bp);
+ if (rc)
+ goto init_one_exit;
+ } else {
+ doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
+ if (doorbell_size > pci_resource_len(pdev, 2)) {
+ dev_err(&bp->pdev->dev,
+ "Cannot map doorbells, bar size too small, aborting\n");
+ rc = -ENOMEM;
+ goto init_one_exit;
+ }
+ bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
+ doorbell_size);
}
- bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
- doorbell_size);
if (!bp->doorbells) {
dev_err(&bp->pdev->dev,
"Cannot map doorbell space, aborting\n");
@@ -12200,8 +12469,25 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto init_one_exit;
}
+ if (IS_VF(bp)) {
+ rc = bnx2x_vfpf_acquire(bp, tx_count, rx_count);
+ if (rc)
+ goto init_one_exit;
+ }
+
+ /* Enable SRIOV if capability found in configuration space.
+ * Once the generic SR-IOV framework makes it in from the
+ * pci tree this will be revised, to allow dynamic control
+ * over the number of VFs. Right now, change the num of vfs
+ * param below to enable SR-IOV.
+ */
+ rc = bnx2x_iov_init_one(bp, int_mode, 0/*num vfs*/);
+ if (rc)
+ goto init_one_exit;
+
/* calc qm_cid_count */
bp->qm_cid_count = bnx2x_set_qm_cid_count(bp);
+ BNX2X_DEV_INFO("qm_cid_count %d\n", bp->qm_cid_count);
/* disable FCOE L2 queue for E1x*/
if (CHIP_IS_E1x(bp))
@@ -12223,13 +12509,20 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Configure interrupt mode: try to enable MSI-X/MSI if
* needed.
*/
- bnx2x_set_int_mode(bp);
+ rc = bnx2x_set_int_mode(bp);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot set interrupts\n");
+ goto init_one_exit;
+ }
+ BNX2X_DEV_INFO("set interrupts successfully\n");
+ /* register the net device */
rc = register_netdev(dev);
if (rc) {
dev_err(&pdev->dev, "Cannot register net device\n");
goto init_one_exit;
}
+ BNX2X_DEV_INFO("device name after netdev register %s\n", dev->name);
if (!NO_FCOE(bp)) {
@@ -12240,6 +12533,8 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
+ BNX2X_DEV_INFO("got pcie width %d and speed %d\n",
+ pcie_width, pcie_speed);
BNX2X_DEV_INFO(
"%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n",
@@ -12257,7 +12552,7 @@ init_one_exit:
if (bp->regview)
iounmap(bp->regview);
- if (bp->doorbells)
+ if (IS_PF(bp) && bp->doorbells)
iounmap(bp->doorbells);
free_netdev(dev);
@@ -12297,25 +12592,37 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
unregister_netdev(dev);
/* Power on: we can't let PCI layer write to us while we are in D3 */
- bnx2x_set_power_state(bp, PCI_D0);
+ if (IS_PF(bp))
+ bnx2x_set_power_state(bp, PCI_D0);
/* Disable MSI/MSI-X */
bnx2x_disable_msi(bp);
/* Power off */
- bnx2x_set_power_state(bp, PCI_D3hot);
+ if (IS_PF(bp))
+ bnx2x_set_power_state(bp, PCI_D3hot);
/* Make sure RESET task is not scheduled before continuing */
cancel_delayed_work_sync(&bp->sp_rtnl_task);
+ bnx2x_iov_remove_one(bp);
+
+ /* send message via vfpf channel to release the resources of this vf */
+ if (IS_VF(bp))
+ bnx2x_vfpf_release(bp);
+
if (bp->regview)
iounmap(bp->regview);
- if (bp->doorbells)
- iounmap(bp->doorbells);
-
- bnx2x_release_firmware(bp);
+ /* for vf doorbells are part of the regview and were unmapped along with
+ * it. FW is only loaded by PF.
+ */
+ if (IS_PF(bp)) {
+ if (bp->doorbells)
+ iounmap(bp->doorbells);
+ bnx2x_release_firmware(bp);
+ }
bnx2x_free_mem_bp(bp);
free_netdev(dev);
@@ -13103,4 +13410,36 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
return cp;
}
+u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
+{
+ struct bnx2x *bp = fp->bp;
+ u32 offset = BAR_USTRORM_INTMEM;
+ if (IS_VF(bp))
+ return bnx2x_vf_ustorm_prods_offset(bp, fp);
+ else if (!CHIP_IS_E1x(bp))
+ offset += USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
+ else
+ offset += USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
+
+ return offset;
+}
+
+/* called only on E1H or E2.
+ * When pretending to be PF, the pretend value is the function number 0...7
+ * When pretending to be VF, the pretend val is the PF-num:VF-valid:ABS-VFID
+ * combination
+ */
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val)
+{
+ u32 pretend_reg;
+
+ if (CHIP_IS_E1H(bp) && pretend_func_val >= E1H_FUNC_MAX)
+ return -1;
+
+ /* get my own pretend register */
+ pretend_reg = bnx2x_get_pretend_reg(bp);
+ REG_WR(bp, pretend_reg, pretend_func_val);
+ REG_RD(bp, pretend_reg);
+ return 0;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h
index ddd5106ad2f9..caf1aef651eb 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h
@@ -1,6 +1,6 @@
/* bnx2x_mfw_req.h: Broadcom Everest network driver.
*
- * Copyright (c) 2012 Broadcom Corporation
+ * Copyright (c) 2012-2013 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/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
index bc2f65b32649..791eb2d53011 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
@@ -1,6 +1,6 @@
/* bnx2x_reg.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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
@@ -825,6 +825,7 @@
/* [RW 28] The value sent to CM header in the case of CFC load error. */
#define DORQ_REG_ERR_CMHEAD 0x170058
#define DORQ_REG_IF_EN 0x170004
+#define DORQ_REG_MAX_RVFID_SIZE 0x1701ec
#define DORQ_REG_MODE_ACT 0x170008
/* [RW 5] The normal mode CID extraction offset. */
#define DORQ_REG_NORM_CID_OFST 0x17002c
@@ -847,6 +848,22 @@
writes the same initial credit to the rspa_crd_cnt and rspb_crd_cnt. The
read reads this written value. */
#define DORQ_REG_RSP_INIT_CRD 0x170048
+#define DORQ_REG_RSPB_CRD_CNT 0x1700b0
+#define DORQ_REG_VF_NORM_CID_BASE 0x1701a0
+#define DORQ_REG_VF_NORM_CID_OFST 0x1701f4
+#define DORQ_REG_VF_NORM_CID_WND_SIZE 0x1701a4
+#define DORQ_REG_VF_NORM_MAX_CID_COUNT 0x1701e4
+#define DORQ_REG_VF_NORM_VF_BASE 0x1701a8
+/* [RW 10] VF type validation mask value */
+#define DORQ_REG_VF_TYPE_MASK_0 0x170218
+/* [RW 17] VF type validation Min MCID value */
+#define DORQ_REG_VF_TYPE_MAX_MCID_0 0x1702d8
+/* [RW 17] VF type validation Max MCID value */
+#define DORQ_REG_VF_TYPE_MIN_MCID_0 0x170298
+/* [RW 10] VF type validation comp value */
+#define DORQ_REG_VF_TYPE_VALUE_0 0x170258
+#define DORQ_REG_VF_USAGE_CT_LIMIT 0x170340
+
/* [RW 4] Initial activity counter value on the load request; when the
shortcut is done. */
#define DORQ_REG_SHRT_ACT_CNT 0x170070
@@ -859,6 +876,7 @@
#define HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 (0x1<<2)
#define HC_CONFIG_0_REG_SINGLE_ISR_EN_0 (0x1<<1)
#define HC_CONFIG_1_REG_BLOCK_DISABLE_1 (0x1<<0)
+#define DORQ_REG_VF_USAGE_CNT 0x170320
#define HC_REG_AGG_INT_0 0x108050
#define HC_REG_AGG_INT_1 0x108054
#define HC_REG_ATTN_BIT 0x108120
@@ -2136,6 +2154,8 @@
/* [R 32] Interrupt register #0 read */
#define NIG_REG_NIG_INT_STS_0 0x103b0
#define NIG_REG_NIG_INT_STS_1 0x103c0
+/* [RC 32] Interrupt register #0 read clear */
+#define NIG_REG_NIG_INT_STS_CLR_0 0x103b4
/* [R 32] Legacy E1 and E1H location for parity error mask register. */
#define NIG_REG_NIG_PRTY_MASK 0x103dc
/* [RW 32] Parity mask register #0 read/write */
@@ -2571,6 +2591,7 @@
current task in process). */
#define PBF_REG_DISABLE_NEW_TASK_PROC_P4 0x14006c
#define PBF_REG_DISABLE_PF 0x1402e8
+#define PBF_REG_DISABLE_VF 0x1402ec
/* [RW 18] For port 0: For each client that is subject to WFQ (the
* corresponding bit is 1); indicates to which of the credit registers this
* client is mapped. For clients which are not credit blocked; their mapping
@@ -3708,6 +3729,10 @@
#define PXP_REG_HST_DISCARD_INTERNAL_WRITES_STATUS 0x10309c
/* [WB 160] Used for initialization of the inbound interrupts memory */
#define PXP_REG_HST_INBOUND_INT 0x103800
+/* [RW 7] Indirect access to the permission table. The fields are : {Valid;
+ * VFID[5:0]}
+ */
+#define PXP_REG_HST_ZONE_PERMISSION_TABLE 0x103400
/* [RW 32] Interrupt mask register #0 read/write */
#define PXP_REG_PXP_INT_MASK_0 0x103074
#define PXP_REG_PXP_INT_MASK_1 0x103084
@@ -5966,6 +5991,7 @@
#define HW_LOCK_RESOURCE_SPIO 2
#define AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT (0x1<<4)
#define AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR (0x1<<5)
+#define AEU_INPUTS_ATTN_BITS_BRB_HW_INTERRUPT (0x1<<19)
#define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR (0x1<<18)
#define AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT (0x1<<31)
#define AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR (0x1<<30)
@@ -6305,6 +6331,15 @@
#define PCI_PM_DATA_B 0x414
#define PCI_ID_VAL1 0x434
#define PCI_ID_VAL2 0x438
+#define GRC_CONFIG_REG_PF_INIT_VF 0x624
+#define GRC_CR_PF_INIT_VF_PF_FIRST_VF_NUM_MASK 0xf
+/* First VF_NUM for PF is encoded in this register.
+ * The number of VFs assigned to a PF is assumed to be a multiple of 8.
+ * Software should program these bits based on Total Number of VFs \
+ * programmed for each PF.
+ * Since registers from 0x000-0x7ff are split across functions, each PF will
+ * have the same location for the same 4 bits
+ */
#define PXPCS_TL_CONTROL_5 0x814
#define PXPCS_TL_CONTROL_5_UNKNOWNTYPE_ERR_ATTN (1 << 29) /*WC*/
@@ -6554,6 +6589,27 @@
(7L<<ME_REG_ABS_PF_NUM_SHIFT) /* Absolute PF Num */
+#define PXP_VF_ADDR_IGU_START 0
+#define PXP_VF_ADDR_IGU_SIZE 0x3000
+#define PXP_VF_ADDR_IGU_END\
+ ((PXP_VF_ADDR_IGU_START) + (PXP_VF_ADDR_IGU_SIZE) - 1)
+
+#define PXP_VF_ADDR_USDM_QUEUES_START 0x3000
+#define PXP_VF_ADDR_USDM_QUEUES_SIZE\
+ (PXP_VF_ADRR_NUM_QUEUES * PXP_ADDR_QUEUE_SIZE)
+#define PXP_VF_ADDR_USDM_QUEUES_END\
+ ((PXP_VF_ADDR_USDM_QUEUES_START) + (PXP_VF_ADDR_USDM_QUEUES_SIZE) - 1)
+
+#define PXP_VF_ADDR_CSDM_GLOBAL_START 0x7600
+#define PXP_VF_ADDR_CSDM_GLOBAL_SIZE (PXP_ADDR_REG_SIZE)
+#define PXP_VF_ADDR_CSDM_GLOBAL_END\
+ ((PXP_VF_ADDR_CSDM_GLOBAL_START) + (PXP_VF_ADDR_CSDM_GLOBAL_SIZE) - 1)
+
+#define PXP_VF_ADDR_DB_START 0x7c00
+#define PXP_VF_ADDR_DB_SIZE 0x200
+#define PXP_VF_ADDR_DB_END\
+ ((PXP_VF_ADDR_DB_START) + (PXP_VF_ADDR_DB_SIZE) - 1)
+
#define MDIO_REG_BANK_CL73_IEEEB0 0x0
#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL 0x0
#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN 0x0200
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 09b625e0fdaa..7306416bc90d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -1,6 +1,6 @@
/* bnx2x_sp.c: Broadcom Everest network driver.
*
- * Copyright (c) 2011-2012 Broadcom Corporation
+ * Copyright (c) 2011-2013 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -325,7 +325,7 @@ static inline int bnx2x_state_wait(struct bnx2x *bp, int state,
return 0;
}
- usleep_range(1000, 1000);
+ usleep_range(1000, 2000);
if (bp->panic)
return -EIO;
@@ -707,7 +707,8 @@ static inline void bnx2x_vlan_mac_set_cmd_hdr_e2(struct bnx2x *bp,
static inline void bnx2x_vlan_mac_set_rdata_hdr_e2(u32 cid, int type,
struct eth_classify_header *hdr, int rule_cnt)
{
- hdr->echo = (cid & BNX2X_SWCID_MASK) | (type << BNX2X_SWCID_SHIFT);
+ hdr->echo = cpu_to_le32((cid & BNX2X_SWCID_MASK) |
+ (type << BNX2X_SWCID_SHIFT));
hdr->rule_cnt = (u8)rule_cnt;
}
@@ -813,8 +814,9 @@ static inline void bnx2x_vlan_mac_set_rdata_hdr_e1x(struct bnx2x *bp,
hdr->length = 1;
hdr->offset = (u8)cam_offset;
- hdr->client_id = 0xff;
- hdr->echo = ((r->cid & BNX2X_SWCID_MASK) | (type << BNX2X_SWCID_SHIFT));
+ hdr->client_id = cpu_to_le16(0xff);
+ hdr->echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+ (type << BNX2X_SWCID_SHIFT));
}
static inline void bnx2x_vlan_mac_set_cfg_entry_e1x(struct bnx2x *bp,
@@ -903,7 +905,7 @@ static void bnx2x_set_one_vlan_e2(struct bnx2x *bp,
(struct eth_classify_rules_ramrod_data *)(raw->rdata);
int rule_cnt = rule_idx + 1;
union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
- int cmd = elem->cmd_data.vlan_mac.cmd;
+ enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
u16 vlan = elem->cmd_data.vlan_mac.u.vlan.vlan;
@@ -953,7 +955,7 @@ static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp,
(struct eth_classify_rules_ramrod_data *)(raw->rdata);
int rule_cnt = rule_idx + 1;
union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
- int cmd = elem->cmd_data.vlan_mac.cmd;
+ enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan;
u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac;
@@ -1407,7 +1409,7 @@ static int bnx2x_wait_vlan_mac(struct bnx2x *bp,
/* Wait until there are no pending commands */
if (!bnx2x_exe_queue_empty(exeq))
- usleep_range(1000, 1000);
+ usleep_range(1000, 2000);
else
return 0;
}
@@ -1442,7 +1444,7 @@ static int bnx2x_complete_vlan_mac(struct bnx2x *bp,
if (cqe->message.error)
return -EINVAL;
- /* Run the next bulk of pending commands if requeted */
+ /* Run the next bulk of pending commands if requested */
if (test_bit(RAMROD_CONT, ramrod_flags)) {
rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags);
if (rc < 0)
@@ -1532,7 +1534,7 @@ static inline int bnx2x_vlan_mac_get_registry_elem(
bool restore,
struct bnx2x_vlan_mac_registry_elem **re)
{
- int cmd = elem->cmd_data.vlan_mac.cmd;
+ enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
struct bnx2x_vlan_mac_registry_elem *reg_elem;
/* Allocate a new registry element if needed. */
@@ -1591,7 +1593,7 @@ static int bnx2x_execute_vlan_mac(struct bnx2x *bp,
bool restore = test_bit(RAMROD_RESTORE, ramrod_flags);
bool drv_only = test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags);
struct bnx2x_vlan_mac_registry_elem *reg_elem;
- int cmd;
+ enum bnx2x_vlan_mac_cmd cmd;
/*
* If DRIVER_ONLY execution is requested, cleanup a registry
@@ -2103,7 +2105,7 @@ static inline void __storm_memset_mac_filters(struct bnx2x *bp,
static int bnx2x_set_rx_mode_e1x(struct bnx2x *bp,
struct bnx2x_rx_mode_ramrod_params *p)
{
- /* update the bp MAC filter structure */
+ /* update the bp MAC filter structure */
u32 mask = (1 << p->cl_id);
struct tstorm_eth_mac_filter_config *mac_filters =
@@ -2166,7 +2168,7 @@ static int bnx2x_set_rx_mode_e1x(struct bnx2x *bp,
mac_filters->unmatched_unicast & ~mask;
DP(BNX2X_MSG_SP, "drop_ucast 0x%x\ndrop_mcast 0x%x\n accp_ucast 0x%x\n"
- "accp_mcast 0x%x\naccp_bcast 0x%x\n",
+ "accp_mcast 0x%x\naccp_bcast 0x%x\n",
mac_filters->ucast_drop_all, mac_filters->mcast_drop_all,
mac_filters->ucast_accept_all, mac_filters->mcast_accept_all,
mac_filters->bcast_accept_all);
@@ -2186,12 +2188,12 @@ static inline void bnx2x_rx_mode_set_rdata_hdr_e2(u32 cid,
struct eth_classify_header *hdr,
u8 rule_cnt)
{
- hdr->echo = cid;
+ hdr->echo = cpu_to_le32(cid);
hdr->rule_cnt = rule_cnt;
}
static inline void bnx2x_rx_mode_set_cmd_state_e2(struct bnx2x *bp,
- unsigned long accept_flags,
+ unsigned long *accept_flags,
struct eth_filter_rules_cmd *cmd,
bool clear_accept_all)
{
@@ -2201,33 +2203,33 @@ static inline void bnx2x_rx_mode_set_cmd_state_e2(struct bnx2x *bp,
state = ETH_FILTER_RULES_CMD_UCAST_DROP_ALL |
ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
- if (accept_flags) {
- if (test_bit(BNX2X_ACCEPT_UNICAST, &accept_flags))
- state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
+ if (test_bit(BNX2X_ACCEPT_UNICAST, accept_flags))
+ state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
- if (test_bit(BNX2X_ACCEPT_MULTICAST, &accept_flags))
- state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
+ if (test_bit(BNX2X_ACCEPT_MULTICAST, accept_flags))
+ state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
- if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept_flags)) {
- state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
- state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL;
- }
+ if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, accept_flags)) {
+ state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
+ state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL;
+ }
- if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept_flags)) {
- state |= ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
- state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
- }
- if (test_bit(BNX2X_ACCEPT_BROADCAST, &accept_flags))
- state |= ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL;
+ if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, accept_flags)) {
+ state |= ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
+ state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL;
+ }
- if (test_bit(BNX2X_ACCEPT_UNMATCHED, &accept_flags)) {
- state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
- state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED;
- }
- if (test_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags))
- state |= ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN;
+ if (test_bit(BNX2X_ACCEPT_BROADCAST, accept_flags))
+ state |= ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL;
+
+ if (test_bit(BNX2X_ACCEPT_UNMATCHED, accept_flags)) {
+ state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL;
+ state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED;
}
+ if (test_bit(BNX2X_ACCEPT_ANY_VLAN, accept_flags))
+ state |= ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN;
+
/* Clear ACCEPT_ALL_XXX flags for FCoE L2 Queue */
if (clear_accept_all) {
state &= ~ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL;
@@ -2260,8 +2262,9 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
data->rules[rule_idx].cmd_general_data =
ETH_FILTER_RULES_CMD_TX_CMD;
- bnx2x_rx_mode_set_cmd_state_e2(bp, p->tx_accept_flags,
- &(data->rules[rule_idx++]), false);
+ bnx2x_rx_mode_set_cmd_state_e2(bp, &p->tx_accept_flags,
+ &(data->rules[rule_idx++]),
+ false);
}
/* Rx */
@@ -2272,8 +2275,9 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
data->rules[rule_idx].cmd_general_data =
ETH_FILTER_RULES_CMD_RX_CMD;
- bnx2x_rx_mode_set_cmd_state_e2(bp, p->rx_accept_flags,
- &(data->rules[rule_idx++]), false);
+ bnx2x_rx_mode_set_cmd_state_e2(bp, &p->rx_accept_flags,
+ &(data->rules[rule_idx++]),
+ false);
}
@@ -2293,9 +2297,10 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
data->rules[rule_idx].cmd_general_data =
ETH_FILTER_RULES_CMD_TX_CMD;
- bnx2x_rx_mode_set_cmd_state_e2(bp, p->tx_accept_flags,
- &(data->rules[rule_idx++]),
+ bnx2x_rx_mode_set_cmd_state_e2(bp, &p->tx_accept_flags,
+ &(data->rules[rule_idx]),
true);
+ rule_idx++;
}
/* Rx */
@@ -2306,9 +2311,10 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
data->rules[rule_idx].cmd_general_data =
ETH_FILTER_RULES_CMD_RX_CMD;
- bnx2x_rx_mode_set_cmd_state_e2(bp, p->rx_accept_flags,
- &(data->rules[rule_idx++]),
+ bnx2x_rx_mode_set_cmd_state_e2(bp, &p->rx_accept_flags,
+ &(data->rules[rule_idx]),
true);
+ rule_idx++;
}
}
@@ -2429,7 +2435,7 @@ static int bnx2x_mcast_wait(struct bnx2x *bp,
static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp,
struct bnx2x_mcast_obj *o,
struct bnx2x_mcast_ramrod_params *p,
- int cmd)
+ enum bnx2x_mcast_cmd cmd)
{
int total_sz;
struct bnx2x_pending_mcast_cmd *new_cmd;
@@ -2561,7 +2567,7 @@ static inline u8 bnx2x_mcast_get_rx_tx_flag(struct bnx2x_mcast_obj *o)
static void bnx2x_mcast_set_one_rule_e2(struct bnx2x *bp,
struct bnx2x_mcast_obj *o, int idx,
union bnx2x_mcast_config_data *cfg_data,
- int cmd)
+ enum bnx2x_mcast_cmd cmd)
{
struct bnx2x_raw_obj *r = &o->raw;
struct eth_multicast_rules_ramrod_data *data =
@@ -2625,7 +2631,7 @@ static inline int bnx2x_mcast_handle_restore_cmd_e2(
int *rdata_idx)
{
int cur_bin, cnt = *rdata_idx;
- union bnx2x_mcast_config_data cfg_data = {0};
+ union bnx2x_mcast_config_data cfg_data = {NULL};
/* go through the registry and configure the bins from it */
for (cur_bin = bnx2x_mcast_get_next_bin(o, start_bin); cur_bin >= 0;
@@ -2657,7 +2663,7 @@ static inline void bnx2x_mcast_hdl_pending_add_e2(struct bnx2x *bp,
{
struct bnx2x_mcast_mac_elem *pmac_pos, *pmac_pos_n;
int cnt = *line_idx;
- union bnx2x_mcast_config_data cfg_data = {0};
+ union bnx2x_mcast_config_data cfg_data = {NULL};
list_for_each_entry_safe(pmac_pos, pmac_pos_n, &cmd_pos->data.macs_head,
link) {
@@ -2780,7 +2786,7 @@ static inline void bnx2x_mcast_hdl_add(struct bnx2x *bp,
int *line_idx)
{
struct bnx2x_mcast_list_elem *mlist_pos;
- union bnx2x_mcast_config_data cfg_data = {0};
+ union bnx2x_mcast_config_data cfg_data = {NULL};
int cnt = *line_idx;
list_for_each_entry(mlist_pos, &p->mcast_list, link) {
@@ -2790,7 +2796,7 @@ static inline void bnx2x_mcast_hdl_add(struct bnx2x *bp,
cnt++;
DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
- mlist_pos->mac);
+ mlist_pos->mac);
}
*line_idx = cnt;
@@ -2827,7 +2833,8 @@ static inline void bnx2x_mcast_hdl_del(struct bnx2x *bp,
* Returns number of lines filled in the ramrod data in total.
*/
static inline int bnx2x_mcast_handle_current_cmd(struct bnx2x *bp,
- struct bnx2x_mcast_ramrod_params *p, int cmd,
+ struct bnx2x_mcast_ramrod_params *p,
+ enum bnx2x_mcast_cmd cmd,
int start_cnt)
{
struct bnx2x_mcast_obj *o = p->mcast_obj;
@@ -2861,7 +2868,7 @@ static inline int bnx2x_mcast_handle_current_cmd(struct bnx2x *bp,
static int bnx2x_mcast_validate_e2(struct bnx2x *bp,
struct bnx2x_mcast_ramrod_params *p,
- int cmd)
+ enum bnx2x_mcast_cmd cmd)
{
struct bnx2x_mcast_obj *o = p->mcast_obj;
int reg_sz = o->get_registry_size(o);
@@ -2930,8 +2937,9 @@ static inline void bnx2x_mcast_set_rdata_hdr_e2(struct bnx2x *bp,
struct eth_multicast_rules_ramrod_data *data =
(struct eth_multicast_rules_ramrod_data *)(r->rdata);
- data->header.echo = ((r->cid & BNX2X_SWCID_MASK) |
- (BNX2X_FILTER_MCAST_PENDING << BNX2X_SWCID_SHIFT));
+ data->header.echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+ (BNX2X_FILTER_MCAST_PENDING <<
+ BNX2X_SWCID_SHIFT));
data->header.rule_cnt = len;
}
@@ -2965,7 +2973,7 @@ static inline int bnx2x_mcast_refresh_registry_e2(struct bnx2x *bp,
static int bnx2x_mcast_setup_e2(struct bnx2x *bp,
struct bnx2x_mcast_ramrod_params *p,
- int cmd)
+ enum bnx2x_mcast_cmd cmd)
{
struct bnx2x_raw_obj *raw = &p->mcast_obj->raw;
struct bnx2x_mcast_obj *o = p->mcast_obj;
@@ -3051,7 +3059,7 @@ static int bnx2x_mcast_setup_e2(struct bnx2x *bp,
static int bnx2x_mcast_validate_e1h(struct bnx2x *bp,
struct bnx2x_mcast_ramrod_params *p,
- int cmd)
+ enum bnx2x_mcast_cmd cmd)
{
/* Mark, that there is a work to do */
if ((cmd == BNX2X_MCAST_CMD_DEL) || (cmd == BNX2X_MCAST_CMD_RESTORE))
@@ -3085,7 +3093,7 @@ static inline void bnx2x_mcast_hdl_add_e1h(struct bnx2x *bp,
BNX2X_57711_SET_MC_FILTER(mc_filter, bit);
DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC, bin %d\n",
- mlist_pos->mac, bit);
+ mlist_pos->mac, bit);
/* bookkeeping... */
BIT_VEC64_SET_BIT(o->registry.aprox_match.vec,
@@ -3113,7 +3121,7 @@ static inline void bnx2x_mcast_hdl_restore_e1h(struct bnx2x *bp,
*/
static int bnx2x_mcast_setup_e1h(struct bnx2x *bp,
struct bnx2x_mcast_ramrod_params *p,
- int cmd)
+ enum bnx2x_mcast_cmd cmd)
{
int i;
struct bnx2x_mcast_obj *o = p->mcast_obj;
@@ -3167,7 +3175,7 @@ static int bnx2x_mcast_setup_e1h(struct bnx2x *bp,
static int bnx2x_mcast_validate_e1(struct bnx2x *bp,
struct bnx2x_mcast_ramrod_params *p,
- int cmd)
+ enum bnx2x_mcast_cmd cmd)
{
struct bnx2x_mcast_obj *o = p->mcast_obj;
int reg_sz = o->get_registry_size(o);
@@ -3240,7 +3248,7 @@ static void bnx2x_mcast_revert_e1(struct bnx2x *bp,
static void bnx2x_mcast_set_one_rule_e1(struct bnx2x *bp,
struct bnx2x_mcast_obj *o, int idx,
union bnx2x_mcast_config_data *cfg_data,
- int cmd)
+ enum bnx2x_mcast_cmd cmd)
{
struct bnx2x_raw_obj *r = &o->raw;
struct mac_configuration_cmd *data =
@@ -3284,9 +3292,10 @@ static inline void bnx2x_mcast_set_rdata_hdr_e1(struct bnx2x *bp,
BNX2X_MAX_MULTICAST*(1 + r->func_id));
data->hdr.offset = offset;
- data->hdr.client_id = 0xff;
- data->hdr.echo = ((r->cid & BNX2X_SWCID_MASK) |
- (BNX2X_FILTER_MCAST_PENDING << BNX2X_SWCID_SHIFT));
+ data->hdr.client_id = cpu_to_le16(0xff);
+ data->hdr.echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+ (BNX2X_FILTER_MCAST_PENDING <<
+ BNX2X_SWCID_SHIFT));
data->hdr.length = len;
}
@@ -3309,7 +3318,7 @@ static inline int bnx2x_mcast_handle_restore_cmd_e1(
{
struct bnx2x_mcast_mac_elem *elem;
int i = 0;
- union bnx2x_mcast_config_data cfg_data = {0};
+ union bnx2x_mcast_config_data cfg_data = {NULL};
/* go through the registry and configure the MACs from it. */
list_for_each_entry(elem, &o->registry.exact_match.macs, link) {
@@ -3319,7 +3328,7 @@ static inline int bnx2x_mcast_handle_restore_cmd_e1(
i++;
DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
- cfg_data.mac);
+ cfg_data.mac);
}
*rdata_idx = i;
@@ -3334,7 +3343,7 @@ static inline int bnx2x_mcast_handle_pending_cmds_e1(
struct bnx2x_pending_mcast_cmd *cmd_pos;
struct bnx2x_mcast_mac_elem *pmac_pos;
struct bnx2x_mcast_obj *o = p->mcast_obj;
- union bnx2x_mcast_config_data cfg_data = {0};
+ union bnx2x_mcast_config_data cfg_data = {NULL};
int cnt = 0;
@@ -3355,7 +3364,7 @@ static inline int bnx2x_mcast_handle_pending_cmds_e1(
cnt++;
DP(BNX2X_MSG_SP, "About to configure %pM mcast MAC\n",
- pmac_pos->mac);
+ pmac_pos->mac);
}
break;
@@ -3458,7 +3467,7 @@ static inline int bnx2x_mcast_refresh_registry_e1(struct bnx2x *bp,
static int bnx2x_mcast_setup_e1(struct bnx2x *bp,
struct bnx2x_mcast_ramrod_params *p,
- int cmd)
+ enum bnx2x_mcast_cmd cmd)
{
struct bnx2x_mcast_obj *o = p->mcast_obj;
struct bnx2x_raw_obj *raw = &o->raw;
@@ -3562,7 +3571,7 @@ static void bnx2x_mcast_set_registry_size_aprox(struct bnx2x_mcast_obj *o,
int bnx2x_config_mcast(struct bnx2x *bp,
struct bnx2x_mcast_ramrod_params *p,
- int cmd)
+ enum bnx2x_mcast_cmd cmd)
{
struct bnx2x_mcast_obj *o = p->mcast_obj;
struct bnx2x_raw_obj *r = &o->raw;
@@ -4085,8 +4094,8 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
DP(BNX2X_MSG_SP, "Configuring RSS\n");
/* Set an echo field */
- data->echo = (r->cid & BNX2X_SWCID_MASK) |
- (r->state << BNX2X_SWCID_SHIFT);
+ data->echo = cpu_to_le32((r->cid & BNX2X_SWCID_MASK) |
+ (r->state << BNX2X_SWCID_SHIFT));
/* RSS mode */
if (test_bit(BNX2X_RSS_MODE_DISABLED, &p->rss_flags))
@@ -4237,11 +4246,16 @@ int bnx2x_queue_state_change(struct bnx2x *bp,
unsigned long *pending = &o->pending;
/* Check that the requested transition is legal */
- if (o->check_transition(bp, o, params))
+ rc = o->check_transition(bp, o, params);
+ if (rc) {
+ BNX2X_ERR("check transition returned an error. rc %d\n", rc);
return -EINVAL;
+ }
/* Set "pending" bit */
+ DP(BNX2X_MSG_SP, "pending bit was=%lx\n", o->pending);
pending_bit = o->set_pending(o, params);
+ DP(BNX2X_MSG_SP, "pending bit now=%lx\n", o->pending);
/* Don't send a command if only driver cleanup was requested */
if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags))
@@ -5025,8 +5039,11 @@ static int bnx2x_queue_chk_transition(struct bnx2x *bp,
* Don't allow a next state transition if we are in the middle of
* the previous one.
*/
- if (o->pending)
+ if (o->pending) {
+ BNX2X_ERR("Blocking transition since pending was %lx\n",
+ o->pending);
return -EBUSY;
+ }
switch (state) {
case BNX2X_Q_STATE_RESET:
@@ -5199,6 +5216,27 @@ void bnx2x_init_queue_obj(struct bnx2x *bp,
obj->set_pending = bnx2x_queue_set_pending;
}
+/* return a queue object's logical state*/
+int bnx2x_get_q_logical_state(struct bnx2x *bp,
+ struct bnx2x_queue_sp_obj *obj)
+{
+ switch (obj->state) {
+ case BNX2X_Q_STATE_ACTIVE:
+ case BNX2X_Q_STATE_MULTI_COS:
+ return BNX2X_Q_LOGICAL_STATE_ACTIVE;
+ case BNX2X_Q_STATE_RESET:
+ case BNX2X_Q_STATE_INITIALIZED:
+ case BNX2X_Q_STATE_MCOS_TERMINATED:
+ case BNX2X_Q_STATE_INACTIVE:
+ case BNX2X_Q_STATE_STOPPED:
+ case BNX2X_Q_STATE_TERMINATED:
+ case BNX2X_Q_STATE_FLRED:
+ return BNX2X_Q_LOGICAL_STATE_STOPPED;
+ default:
+ return -EINVAL;
+ }
+}
+
/********************** Function state object *********************************/
enum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp,
struct bnx2x_func_sp_obj *o)
@@ -5631,9 +5669,9 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp,
memset(rdata, 0, sizeof(*rdata));
/* Fill the ramrod data with provided parameters */
- rdata->function_mode = (u8)start_params->mf_mode;
- rdata->sd_vlan_tag = cpu_to_le16(start_params->sd_vlan_tag);
- rdata->path_id = BP_PATH(bp);
+ rdata->function_mode = (u8)start_params->mf_mode;
+ rdata->sd_vlan_tag = cpu_to_le16(start_params->sd_vlan_tag);
+ rdata->path_id = BP_PATH(bp);
rdata->network_cos_mode = start_params->network_cos_mode;
/*
@@ -5716,21 +5754,20 @@ inline int bnx2x_func_send_afex_viflists(struct bnx2x *bp,
struct bnx2x_func_sp_obj *o = params->f_obj;
struct afex_vif_list_ramrod_data *rdata =
(struct afex_vif_list_ramrod_data *)o->afex_rdata;
- struct bnx2x_func_afex_viflists_params *afex_viflist_params =
+ struct bnx2x_func_afex_viflists_params *afex_vif_params =
&params->params.afex_viflists;
u64 *p_rdata = (u64 *)rdata;
memset(rdata, 0, sizeof(*rdata));
/* Fill the ramrod data with provided parameters */
- rdata->vif_list_index = afex_viflist_params->vif_list_index;
- rdata->func_bit_map = afex_viflist_params->func_bit_map;
- rdata->afex_vif_list_command =
- afex_viflist_params->afex_vif_list_command;
- rdata->func_to_clear = afex_viflist_params->func_to_clear;
+ rdata->vif_list_index = cpu_to_le16(afex_vif_params->vif_list_index);
+ rdata->func_bit_map = afex_vif_params->func_bit_map;
+ rdata->afex_vif_list_command = afex_vif_params->afex_vif_list_command;
+ rdata->func_to_clear = afex_vif_params->func_to_clear;
/* send in echo type of sub command */
- rdata->echo = afex_viflist_params->afex_vif_list_command;
+ rdata->echo = afex_vif_params->afex_vif_list_command;
/* No need for an explicit memory barrier here as long we would
* need to ensure the ordering of writing to the SPQ element
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
index adbd91b1bdfc..ff907609b9fc 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
@@ -1,6 +1,6 @@
/* bnx2x_sp.h: Broadcom Everest network driver.
*
- * Copyright (c) 2011-2012 Broadcom Corporation
+ * Copyright (c) 2011-2013 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -54,7 +54,7 @@ typedef enum {
BNX2X_OBJ_TYPE_RX_TX,
} bnx2x_obj_type;
-/* Filtering states */
+/* Public slow path states */
enum {
BNX2X_FILTER_MAC_PENDING,
BNX2X_FILTER_VLAN_PENDING,
@@ -524,7 +524,7 @@ struct bnx2x_mcast_ramrod_params {
int mcast_list_len;
};
-enum {
+enum bnx2x_mcast_cmd {
BNX2X_MCAST_CMD_ADD,
BNX2X_MCAST_CMD_CONT,
BNX2X_MCAST_CMD_DEL,
@@ -573,7 +573,8 @@ struct bnx2x_mcast_obj {
* @param cmd command to execute (BNX2X_MCAST_CMD_X, see above)
*/
int (*config_mcast)(struct bnx2x *bp,
- struct bnx2x_mcast_ramrod_params *p, int cmd);
+ struct bnx2x_mcast_ramrod_params *p,
+ enum bnx2x_mcast_cmd cmd);
/**
* Fills the ramrod data during the RESTORE flow.
@@ -590,11 +591,13 @@ struct bnx2x_mcast_obj {
int start_bin, int *rdata_idx);
int (*enqueue_cmd)(struct bnx2x *bp, struct bnx2x_mcast_obj *o,
- struct bnx2x_mcast_ramrod_params *p, int cmd);
+ struct bnx2x_mcast_ramrod_params *p,
+ enum bnx2x_mcast_cmd cmd);
void (*set_one_rule)(struct bnx2x *bp,
struct bnx2x_mcast_obj *o, int idx,
- union bnx2x_mcast_config_data *cfg_data, int cmd);
+ union bnx2x_mcast_config_data *cfg_data,
+ enum bnx2x_mcast_cmd cmd);
/** Checks if there are more mcast MACs to be set or a previous
* command is still pending.
@@ -617,7 +620,8 @@ struct bnx2x_mcast_obj {
* feasible.
*/
int (*validate)(struct bnx2x *bp,
- struct bnx2x_mcast_ramrod_params *p, int cmd);
+ struct bnx2x_mcast_ramrod_params *p,
+ enum bnx2x_mcast_cmd cmd);
/**
* Restore the values of internal counters in case of a failure.
@@ -776,6 +780,12 @@ enum bnx2x_q_state {
BNX2X_Q_STATE_MAX,
};
+/* Allowed Queue states */
+enum bnx2x_q_logical_state {
+ BNX2X_Q_LOGICAL_STATE_ACTIVE,
+ BNX2X_Q_LOGICAL_STATE_STOPPED,
+};
+
/* Allowed commands */
enum bnx2x_queue_cmd {
BNX2X_Q_CMD_INIT,
@@ -1261,6 +1271,9 @@ void bnx2x_init_queue_obj(struct bnx2x *bp,
int bnx2x_queue_state_change(struct bnx2x *bp,
struct bnx2x_queue_state_params *params);
+int bnx2x_get_q_logical_state(struct bnx2x *bp,
+ struct bnx2x_queue_sp_obj *obj);
+
/********************* VLAN-MAC ****************/
void bnx2x_init_mac_obj(struct bnx2x *bp,
struct bnx2x_vlan_mac_obj *mac_obj,
@@ -1338,7 +1351,8 @@ void bnx2x_init_mcast_obj(struct bnx2x *bp,
* completions.
*/
int bnx2x_config_mcast(struct bnx2x *bp,
- struct bnx2x_mcast_ramrod_params *p, int cmd);
+ struct bnx2x_mcast_ramrod_params *p,
+ enum bnx2x_mcast_cmd cmd);
/****************** CREDIT POOL ****************/
void bnx2x_init_mac_credit_pool(struct bnx2x *bp,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
new file mode 100644
index 000000000000..6adfa2093581
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -0,0 +1,3198 @@
+/* bnx2x_sriov.c: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Shmulik Ravid <shmulikr@broadcom.com>
+ * Ariel Elior <ariele@broadcom.com>
+ *
+ */
+#include "bnx2x.h"
+#include "bnx2x_init.h"
+#include "bnx2x_cmn.h"
+#include <linux/crc32.h>
+
+/* General service functions */
+static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
+ u16 pf_id)
+{
+ REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_VF_TO_PF_OFFSET(abs_fid),
+ pf_id);
+ REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_VF_TO_PF_OFFSET(abs_fid),
+ pf_id);
+ REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_VF_TO_PF_OFFSET(abs_fid),
+ pf_id);
+ REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_VF_TO_PF_OFFSET(abs_fid),
+ pf_id);
+}
+
+static void storm_memset_func_en(struct bnx2x *bp, u16 abs_fid,
+ u8 enable)
+{
+ REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNC_EN_OFFSET(abs_fid),
+ enable);
+ REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNC_EN_OFFSET(abs_fid),
+ enable);
+ REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNC_EN_OFFSET(abs_fid),
+ enable);
+ REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(abs_fid),
+ enable);
+}
+
+int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid)
+{
+ int idx;
+
+ for_each_vf(bp, idx)
+ if (bnx2x_vf(bp, idx, abs_vfid) == abs_vfid)
+ break;
+ return idx;
+}
+
+static
+struct bnx2x_virtf *bnx2x_vf_by_abs_fid(struct bnx2x *bp, u16 abs_vfid)
+{
+ u16 idx = (u16)bnx2x_vf_idx_by_abs_fid(bp, abs_vfid);
+ return (idx < BNX2X_NR_VIRTFN(bp)) ? BP_VF(bp, idx) : NULL;
+}
+
+static void bnx2x_vf_igu_ack_sb(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ u8 igu_sb_id, u8 segment, u16 index, u8 op,
+ u8 update)
+{
+ /* acking a VF sb through the PF - use the GRC */
+ u32 ctl;
+ u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA;
+ u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL;
+ u32 func_encode = vf->abs_vfid;
+ u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + igu_sb_id;
+ struct igu_regular cmd_data = {0};
+
+ cmd_data.sb_id_and_flags =
+ ((index << IGU_REGULAR_SB_INDEX_SHIFT) |
+ (segment << IGU_REGULAR_SEGMENT_ACCESS_SHIFT) |
+ (update << IGU_REGULAR_BUPDATE_SHIFT) |
+ (op << IGU_REGULAR_ENABLE_INT_SHIFT));
+
+ ctl = addr_encode << IGU_CTRL_REG_ADDRESS_SHIFT |
+ func_encode << IGU_CTRL_REG_FID_SHIFT |
+ IGU_CTRL_CMD_TYPE_WR << IGU_CTRL_REG_TYPE_SHIFT;
+
+ DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
+ cmd_data.sb_id_and_flags, igu_addr_data);
+ REG_WR(bp, igu_addr_data, cmd_data.sb_id_and_flags);
+ mmiowb();
+ barrier();
+
+ DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
+ ctl, igu_addr_ctl);
+ REG_WR(bp, igu_addr_ctl, ctl);
+ mmiowb();
+ barrier();
+}
+/* VFOP - VF slow-path operation support */
+
+#define BNX2X_VFOP_FILTER_ADD_CNT_MAX 0x10000
+
+/* VFOP operations states */
+enum bnx2x_vfop_qctor_state {
+ BNX2X_VFOP_QCTOR_INIT,
+ BNX2X_VFOP_QCTOR_SETUP,
+ BNX2X_VFOP_QCTOR_INT_EN
+};
+
+enum bnx2x_vfop_qdtor_state {
+ BNX2X_VFOP_QDTOR_HALT,
+ BNX2X_VFOP_QDTOR_TERMINATE,
+ BNX2X_VFOP_QDTOR_CFCDEL,
+ BNX2X_VFOP_QDTOR_DONE
+};
+
+enum bnx2x_vfop_vlan_mac_state {
+ BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
+ BNX2X_VFOP_VLAN_MAC_CLEAR,
+ BNX2X_VFOP_VLAN_MAC_CHK_DONE,
+ BNX2X_VFOP_MAC_CONFIG_LIST,
+ BNX2X_VFOP_VLAN_CONFIG_LIST,
+ BNX2X_VFOP_VLAN_CONFIG_LIST_0
+};
+
+enum bnx2x_vfop_qsetup_state {
+ BNX2X_VFOP_QSETUP_CTOR,
+ BNX2X_VFOP_QSETUP_VLAN0,
+ BNX2X_VFOP_QSETUP_DONE
+};
+
+enum bnx2x_vfop_mcast_state {
+ BNX2X_VFOP_MCAST_DEL,
+ BNX2X_VFOP_MCAST_ADD,
+ BNX2X_VFOP_MCAST_CHK_DONE
+};
+enum bnx2x_vfop_qflr_state {
+ BNX2X_VFOP_QFLR_CLR_VLAN,
+ BNX2X_VFOP_QFLR_CLR_MAC,
+ BNX2X_VFOP_QFLR_TERMINATE,
+ BNX2X_VFOP_QFLR_DONE
+};
+
+enum bnx2x_vfop_flr_state {
+ BNX2X_VFOP_FLR_QUEUES,
+ BNX2X_VFOP_FLR_HW
+};
+
+enum bnx2x_vfop_close_state {
+ BNX2X_VFOP_CLOSE_QUEUES,
+ BNX2X_VFOP_CLOSE_HW
+};
+
+enum bnx2x_vfop_rxmode_state {
+ BNX2X_VFOP_RXMODE_CONFIG,
+ BNX2X_VFOP_RXMODE_DONE
+};
+
+enum bnx2x_vfop_qteardown_state {
+ BNX2X_VFOP_QTEARDOWN_RXMODE,
+ BNX2X_VFOP_QTEARDOWN_CLR_VLAN,
+ BNX2X_VFOP_QTEARDOWN_CLR_MAC,
+ BNX2X_VFOP_QTEARDOWN_QDTOR,
+ BNX2X_VFOP_QTEARDOWN_DONE
+};
+
+#define bnx2x_vfop_reset_wq(vf) atomic_set(&vf->op_in_progress, 0)
+
+void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_queue_init_params *init_params,
+ struct bnx2x_queue_setup_params *setup_params,
+ u16 q_idx, u16 sb_idx)
+{
+ DP(BNX2X_MSG_IOV,
+ "VF[%d] Q_SETUP: txq[%d]-- vfsb=%d, sb-index=%d, hc-rate=%d, flags=0x%lx, traffic-type=%d",
+ vf->abs_vfid,
+ q_idx,
+ sb_idx,
+ init_params->tx.sb_cq_index,
+ init_params->tx.hc_rate,
+ setup_params->flags,
+ setup_params->txq_params.traffic_type);
+}
+
+void bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_queue_init_params *init_params,
+ struct bnx2x_queue_setup_params *setup_params,
+ u16 q_idx, u16 sb_idx)
+{
+ struct bnx2x_rxq_setup_params *rxq_params = &setup_params->rxq_params;
+
+ DP(BNX2X_MSG_IOV, "VF[%d] Q_SETUP: rxq[%d]-- vfsb=%d, sb-index=%d, hc-rate=%d, mtu=%d, buf-size=%d\n"
+ "sge-size=%d, max_sge_pkt=%d, tpa-agg-size=%d, flags=0x%lx, drop-flags=0x%x, cache-log=%d\n",
+ vf->abs_vfid,
+ q_idx,
+ sb_idx,
+ init_params->rx.sb_cq_index,
+ init_params->rx.hc_rate,
+ setup_params->gen_params.mtu,
+ rxq_params->buf_sz,
+ rxq_params->sge_buf_sz,
+ rxq_params->max_sges_pkt,
+ rxq_params->tpa_agg_sz,
+ setup_params->flags,
+ rxq_params->drop_flags,
+ rxq_params->cache_line_log);
+}
+
+void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vf_queue *q,
+ struct bnx2x_vfop_qctor_params *p,
+ unsigned long q_type)
+{
+ struct bnx2x_queue_init_params *init_p = &p->qstate.params.init;
+ struct bnx2x_queue_setup_params *setup_p = &p->prep_qsetup;
+
+ /* INIT */
+
+ /* Enable host coalescing in the transition to INIT state */
+ if (test_bit(BNX2X_Q_FLG_HC, &init_p->rx.flags))
+ __set_bit(BNX2X_Q_FLG_HC_EN, &init_p->rx.flags);
+
+ if (test_bit(BNX2X_Q_FLG_HC, &init_p->tx.flags))
+ __set_bit(BNX2X_Q_FLG_HC_EN, &init_p->tx.flags);
+
+ /* FW SB ID */
+ init_p->rx.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+ init_p->tx.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+
+ /* context */
+ init_p->cxts[0] = q->cxt;
+
+ /* SETUP */
+
+ /* Setup-op general parameters */
+ setup_p->gen_params.spcl_id = vf->sp_cl_id;
+ setup_p->gen_params.stat_id = vfq_stat_id(vf, q);
+
+ /* Setup-op pause params:
+ * Nothing to do, the pause thresholds are set by default to 0 which
+ * effectively turns off the feature for this queue. We don't want
+ * one queue (VF) to interfering with another queue (another VF)
+ */
+ if (vf->cfg_flags & VF_CFG_FW_FC)
+ BNX2X_ERR("No support for pause to VFs (abs_vfid: %d)\n",
+ vf->abs_vfid);
+ /* Setup-op flags:
+ * collect statistics, zero statistics, local-switching, security,
+ * OV for Flex10, RSS and MCAST for leading
+ */
+ if (test_bit(BNX2X_Q_FLG_STATS, &setup_p->flags))
+ __set_bit(BNX2X_Q_FLG_ZERO_STATS, &setup_p->flags);
+
+ /* for VFs, enable tx switching, bd coherency, and mac address
+ * anti-spoofing
+ */
+ __set_bit(BNX2X_Q_FLG_TX_SWITCH, &setup_p->flags);
+ __set_bit(BNX2X_Q_FLG_TX_SEC, &setup_p->flags);
+ __set_bit(BNX2X_Q_FLG_ANTI_SPOOF, &setup_p->flags);
+
+ if (vfq_is_leading(q)) {
+ __set_bit(BNX2X_Q_FLG_LEADING_RSS, &setup_p->flags);
+ __set_bit(BNX2X_Q_FLG_MCAST, &setup_p->flags);
+ }
+
+ /* Setup-op rx parameters */
+ if (test_bit(BNX2X_Q_TYPE_HAS_RX, &q_type)) {
+ struct bnx2x_rxq_setup_params *rxq_p = &setup_p->rxq_params;
+
+ rxq_p->cl_qzone_id = vfq_qzone_id(vf, q);
+ rxq_p->fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+ rxq_p->rss_engine_id = FW_VF_HANDLE(vf->abs_vfid);
+
+ if (test_bit(BNX2X_Q_FLG_TPA, &setup_p->flags))
+ rxq_p->max_tpa_queues = BNX2X_VF_MAX_TPA_AGG_QUEUES;
+ }
+
+ /* Setup-op tx parameters */
+ if (test_bit(BNX2X_Q_TYPE_HAS_TX, &q_type)) {
+ setup_p->txq_params.tss_leading_cl_id = vf->leading_rss;
+ setup_p->txq_params.fw_sb_id = vf_igu_sb(vf, q->sb_idx);
+ }
+}
+
+/* VFOP queue construction */
+static void bnx2x_vfop_qctor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ struct bnx2x_vfop_args_qctor *args = &vfop->args.qctor;
+ struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
+ enum bnx2x_vfop_qctor_state state = vfop->state;
+
+ bnx2x_vfop_reset_wq(vf);
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+ switch (state) {
+ case BNX2X_VFOP_QCTOR_INIT:
+
+ /* has this queue already been opened? */
+ if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
+ BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+ DP(BNX2X_MSG_IOV,
+ "Entered qctor but queue was already up. Aborting gracefully\n");
+ goto op_done;
+ }
+
+ /* next state */
+ vfop->state = BNX2X_VFOP_QCTOR_SETUP;
+
+ q_params->cmd = BNX2X_Q_CMD_INIT;
+ vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+ case BNX2X_VFOP_QCTOR_SETUP:
+ /* next state */
+ vfop->state = BNX2X_VFOP_QCTOR_INT_EN;
+
+ /* copy pre-prepared setup params to the queue-state params */
+ vfop->op_p->qctor.qstate.params.setup =
+ vfop->op_p->qctor.prep_qsetup;
+
+ q_params->cmd = BNX2X_Q_CMD_SETUP;
+ vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+ case BNX2X_VFOP_QCTOR_INT_EN:
+
+ /* enable interrupts */
+ bnx2x_vf_igu_ack_sb(bp, vf, vf_igu_sb(vf, args->sb_idx),
+ USTORM_ID, 0, IGU_INT_ENABLE, 0);
+ goto op_done;
+ default:
+ bnx2x_vfop_default(state);
+ }
+op_err:
+ BNX2X_ERR("QCTOR[%d:%d] error: cmd %d, rc %d\n",
+ vf->abs_vfid, args->qid, q_params->cmd, vfop->rc);
+op_done:
+ bnx2x_vfop_end(bp, vf, vfop);
+op_pending:
+ return;
+}
+
+static int bnx2x_vfop_qctor_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ vf->op_params.qctor.qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+
+ vfop->args.qctor.qid = qid;
+ vfop->args.qctor.sb_idx = bnx2x_vfq(vf, qid, sb_idx);
+
+ bnx2x_vfop_opset(BNX2X_VFOP_QCTOR_INIT,
+ bnx2x_vfop_qctor, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qctor,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+/* VFOP queue destruction */
+static void bnx2x_vfop_qdtor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ struct bnx2x_vfop_args_qdtor *qdtor = &vfop->args.qdtor;
+ struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
+ enum bnx2x_vfop_qdtor_state state = vfop->state;
+
+ bnx2x_vfop_reset_wq(vf);
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+ switch (state) {
+ case BNX2X_VFOP_QDTOR_HALT:
+
+ /* has this queue already been stopped? */
+ if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
+ BNX2X_Q_LOGICAL_STATE_STOPPED) {
+ DP(BNX2X_MSG_IOV,
+ "Entered qdtor but queue was already stopped. Aborting gracefully\n");
+ goto op_done;
+ }
+
+ /* next state */
+ vfop->state = BNX2X_VFOP_QDTOR_TERMINATE;
+
+ q_params->cmd = BNX2X_Q_CMD_HALT;
+ vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+ case BNX2X_VFOP_QDTOR_TERMINATE:
+ /* next state */
+ vfop->state = BNX2X_VFOP_QDTOR_CFCDEL;
+
+ q_params->cmd = BNX2X_Q_CMD_TERMINATE;
+ vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+ case BNX2X_VFOP_QDTOR_CFCDEL:
+ /* next state */
+ vfop->state = BNX2X_VFOP_QDTOR_DONE;
+
+ q_params->cmd = BNX2X_Q_CMD_CFC_DEL;
+ vfop->rc = bnx2x_queue_state_change(bp, q_params);
+
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+op_err:
+ BNX2X_ERR("QDTOR[%d:%d] error: cmd %d, rc %d\n",
+ vf->abs_vfid, qdtor->qid, q_params->cmd, vfop->rc);
+op_done:
+ case BNX2X_VFOP_QDTOR_DONE:
+ /* invalidate the context */
+ qdtor->cxt->ustorm_ag_context.cdu_usage = 0;
+ qdtor->cxt->xstorm_ag_context.cdu_reserved = 0;
+ bnx2x_vfop_end(bp, vf, vfop);
+ return;
+ default:
+ bnx2x_vfop_default(state);
+ }
+op_pending:
+ return;
+}
+
+static int bnx2x_vfop_qdtor_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ struct bnx2x_queue_state_params *qstate =
+ &vf->op_params.qctor.qstate;
+
+ memset(qstate, 0, sizeof(*qstate));
+ qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+
+ vfop->args.qdtor.qid = qid;
+ vfop->args.qdtor.cxt = bnx2x_vfq(vf, qid, cxt);
+
+ bnx2x_vfop_opset(BNX2X_VFOP_QDTOR_HALT,
+ bnx2x_vfop_qdtor, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdtor,
+ cmd->block);
+ }
+ DP(BNX2X_MSG_IOV, "VF[%d] failed to add a vfop.\n", vf->abs_vfid);
+ return -ENOMEM;
+}
+
+static void
+bnx2x_vf_set_igu_info(struct bnx2x *bp, u8 igu_sb_id, u8 abs_vfid)
+{
+ struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+ if (vf) {
+ if (!vf_sb_count(vf))
+ vf->igu_base_id = igu_sb_id;
+ ++vf_sb_count(vf);
+ }
+}
+
+/* VFOP MAC/VLAN helpers */
+static inline void bnx2x_vfop_credit(struct bnx2x *bp,
+ struct bnx2x_vfop *vfop,
+ struct bnx2x_vlan_mac_obj *obj)
+{
+ struct bnx2x_vfop_args_filters *args = &vfop->args.filters;
+
+ /* update credit only if there is no error
+ * and a valid credit counter
+ */
+ if (!vfop->rc && args->credit) {
+ int cnt = 0;
+ struct list_head *pos;
+
+ list_for_each(pos, &obj->head)
+ cnt++;
+
+ atomic_set(args->credit, cnt);
+ }
+}
+
+static int bnx2x_vfop_set_user_req(struct bnx2x *bp,
+ struct bnx2x_vfop_filter *pos,
+ struct bnx2x_vlan_mac_data *user_req)
+{
+ user_req->cmd = pos->add ? BNX2X_VLAN_MAC_ADD :
+ BNX2X_VLAN_MAC_DEL;
+
+ switch (pos->type) {
+ case BNX2X_VFOP_FILTER_MAC:
+ memcpy(user_req->u.mac.mac, pos->mac, ETH_ALEN);
+ break;
+ case BNX2X_VFOP_FILTER_VLAN:
+ user_req->u.vlan.vlan = pos->vid;
+ break;
+ default:
+ BNX2X_ERR("Invalid filter type, skipping\n");
+ return 1;
+ }
+ return 0;
+}
+
+static int
+bnx2x_vfop_config_vlan0(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_ramrod_params *vlan_mac,
+ bool add)
+{
+ int rc;
+
+ vlan_mac->user_req.cmd = add ? BNX2X_VLAN_MAC_ADD :
+ BNX2X_VLAN_MAC_DEL;
+ vlan_mac->user_req.u.vlan.vlan = 0;
+
+ rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+ if (rc == -EEXIST)
+ rc = 0;
+ return rc;
+}
+
+static int bnx2x_vfop_config_list(struct bnx2x *bp,
+ struct bnx2x_vfop_filters *filters,
+ struct bnx2x_vlan_mac_ramrod_params *vlan_mac)
+{
+ struct bnx2x_vfop_filter *pos, *tmp;
+ struct list_head rollback_list, *filters_list = &filters->head;
+ struct bnx2x_vlan_mac_data *user_req = &vlan_mac->user_req;
+ int rc = 0, cnt = 0;
+
+ INIT_LIST_HEAD(&rollback_list);
+
+ list_for_each_entry_safe(pos, tmp, filters_list, link) {
+ if (bnx2x_vfop_set_user_req(bp, pos, user_req))
+ continue;
+
+ rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+ if (rc >= 0) {
+ cnt += pos->add ? 1 : -1;
+ list_del(&pos->link);
+ list_add(&pos->link, &rollback_list);
+ rc = 0;
+ } else if (rc == -EEXIST) {
+ rc = 0;
+ } else {
+ BNX2X_ERR("Failed to add a new vlan_mac command\n");
+ break;
+ }
+ }
+
+ /* rollback if error or too many rules added */
+ if (rc || cnt > filters->add_cnt) {
+ BNX2X_ERR("error or too many rules added. Performing rollback\n");
+ list_for_each_entry_safe(pos, tmp, &rollback_list, link) {
+ pos->add = !pos->add; /* reverse op */
+ bnx2x_vfop_set_user_req(bp, pos, user_req);
+ bnx2x_config_vlan_mac(bp, vlan_mac);
+ list_del(&pos->link);
+ }
+ cnt = 0;
+ if (!rc)
+ rc = -EINVAL;
+ }
+ filters->add_cnt = cnt;
+ return rc;
+}
+
+/* VFOP set VLAN/MAC */
+static void bnx2x_vfop_vlan_mac(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ struct bnx2x_vlan_mac_ramrod_params *vlan_mac = &vfop->op_p->vlan_mac;
+ struct bnx2x_vlan_mac_obj *obj = vlan_mac->vlan_mac_obj;
+ struct bnx2x_vfop_filters *filters = vfop->args.filters.multi_filter;
+
+ enum bnx2x_vfop_vlan_mac_state state = vfop->state;
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+ bnx2x_vfop_reset_wq(vf);
+
+ switch (state) {
+ case BNX2X_VFOP_VLAN_MAC_CLEAR:
+ /* next state */
+ vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+ /* do delete */
+ vfop->rc = obj->delete_all(bp, obj,
+ &vlan_mac->user_req.vlan_mac_flags,
+ &vlan_mac->ramrod_flags);
+
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+ case BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE:
+ /* next state */
+ vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+ /* do config */
+ vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+ if (vfop->rc == -EEXIST)
+ vfop->rc = 0;
+
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+ case BNX2X_VFOP_VLAN_MAC_CHK_DONE:
+ vfop->rc = !!obj->raw.check_pending(&obj->raw);
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+ case BNX2X_VFOP_MAC_CONFIG_LIST:
+ /* next state */
+ vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+ /* do list config */
+ vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
+ if (vfop->rc)
+ goto op_err;
+
+ set_bit(RAMROD_CONT, &vlan_mac->ramrod_flags);
+ vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+ case BNX2X_VFOP_VLAN_CONFIG_LIST:
+ /* next state */
+ vfop->state = BNX2X_VFOP_VLAN_CONFIG_LIST_0;
+
+ /* remove vlan0 - could be no-op */
+ vfop->rc = bnx2x_vfop_config_vlan0(bp, vlan_mac, false);
+ if (vfop->rc)
+ goto op_err;
+
+ /* Do vlan list config. if this operation fails we try to
+ * restore vlan0 to keep the queue is working order
+ */
+ vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
+ if (!vfop->rc) {
+ set_bit(RAMROD_CONT, &vlan_mac->ramrod_flags);
+ vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
+ }
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT); /* fall-through */
+
+ case BNX2X_VFOP_VLAN_CONFIG_LIST_0:
+ /* next state */
+ vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
+
+ if (list_empty(&obj->head))
+ /* add vlan0 */
+ vfop->rc = bnx2x_vfop_config_vlan0(bp, vlan_mac, true);
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+ default:
+ bnx2x_vfop_default(state);
+ }
+op_err:
+ BNX2X_ERR("VLAN-MAC error: rc %d\n", vfop->rc);
+op_done:
+ kfree(filters);
+ bnx2x_vfop_credit(bp, vfop, obj);
+ bnx2x_vfop_end(bp, vf, vfop);
+op_pending:
+ return;
+}
+
+struct bnx2x_vfop_vlan_mac_flags {
+ bool drv_only;
+ bool dont_consume;
+ bool single_cmd;
+ bool add;
+};
+
+static void
+bnx2x_vfop_vlan_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
+ struct bnx2x_vfop_vlan_mac_flags *flags)
+{
+ struct bnx2x_vlan_mac_data *ureq = &ramrod->user_req;
+
+ memset(ramrod, 0, sizeof(*ramrod));
+
+ /* ramrod flags */
+ if (flags->drv_only)
+ set_bit(RAMROD_DRV_CLR_ONLY, &ramrod->ramrod_flags);
+ if (flags->single_cmd)
+ set_bit(RAMROD_EXEC, &ramrod->ramrod_flags);
+
+ /* mac_vlan flags */
+ if (flags->dont_consume)
+ set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, &ureq->vlan_mac_flags);
+
+ /* cmd */
+ ureq->cmd = flags->add ? BNX2X_VLAN_MAC_ADD : BNX2X_VLAN_MAC_DEL;
+}
+
+static inline void
+bnx2x_vfop_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
+ struct bnx2x_vfop_vlan_mac_flags *flags)
+{
+ bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, flags);
+ set_bit(BNX2X_ETH_MAC, &ramrod->user_req.vlan_mac_flags);
+}
+
+static int bnx2x_vfop_mac_delall_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid, bool drv_only)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ struct bnx2x_vfop_args_filters filters = {
+ .multi_filter = NULL, /* single */
+ .credit = NULL, /* consume credit */
+ };
+ struct bnx2x_vfop_vlan_mac_flags flags = {
+ .drv_only = drv_only,
+ .dont_consume = (filters.credit != NULL),
+ .single_cmd = true,
+ .add = false /* don't care */,
+ };
+ struct bnx2x_vlan_mac_ramrod_params *ramrod =
+ &vf->op_params.vlan_mac;
+
+ /* set ramrod params */
+ bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
+
+ /* set object */
+ ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+
+ /* set extra args */
+ vfop->args.filters = filters;
+
+ bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
+ bnx2x_vfop_vlan_mac, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ struct bnx2x_vfop_filters *macs,
+ int qid, bool drv_only)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ struct bnx2x_vfop_args_filters filters = {
+ .multi_filter = macs,
+ .credit = NULL, /* consume credit */
+ };
+ struct bnx2x_vfop_vlan_mac_flags flags = {
+ .drv_only = drv_only,
+ .dont_consume = (filters.credit != NULL),
+ .single_cmd = false,
+ .add = false, /* don't care since only the items in the
+ * filters list affect the sp operation,
+ * not the list itself
+ */
+ };
+ struct bnx2x_vlan_mac_ramrod_params *ramrod =
+ &vf->op_params.vlan_mac;
+
+ /* set ramrod params */
+ bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
+
+ /* set object */
+ ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+
+ /* set extra args */
+ filters.multi_filter->add_cnt = BNX2X_VFOP_FILTER_ADD_CNT_MAX;
+ vfop->args.filters = filters;
+
+ bnx2x_vfop_opset(BNX2X_VFOP_MAC_CONFIG_LIST,
+ bnx2x_vfop_vlan_mac, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid, u16 vid, bool add)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ struct bnx2x_vfop_args_filters filters = {
+ .multi_filter = NULL, /* single command */
+ .credit = &bnx2x_vfq(vf, qid, vlan_count),
+ };
+ struct bnx2x_vfop_vlan_mac_flags flags = {
+ .drv_only = false,
+ .dont_consume = (filters.credit != NULL),
+ .single_cmd = true,
+ .add = add,
+ };
+ struct bnx2x_vlan_mac_ramrod_params *ramrod =
+ &vf->op_params.vlan_mac;
+
+ /* set ramrod params */
+ bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
+ ramrod->user_req.u.vlan.vlan = vid;
+
+ /* set object */
+ ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+
+ /* set extra args */
+ vfop->args.filters = filters;
+
+ bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
+ bnx2x_vfop_vlan_mac, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+static int bnx2x_vfop_vlan_delall_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid, bool drv_only)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ struct bnx2x_vfop_args_filters filters = {
+ .multi_filter = NULL, /* single command */
+ .credit = &bnx2x_vfq(vf, qid, vlan_count),
+ };
+ struct bnx2x_vfop_vlan_mac_flags flags = {
+ .drv_only = drv_only,
+ .dont_consume = (filters.credit != NULL),
+ .single_cmd = true,
+ .add = false, /* don't care */
+ };
+ struct bnx2x_vlan_mac_ramrod_params *ramrod =
+ &vf->op_params.vlan_mac;
+
+ /* set ramrod params */
+ bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
+
+ /* set object */
+ ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+
+ /* set extra args */
+ vfop->args.filters = filters;
+
+ bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
+ bnx2x_vfop_vlan_mac, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ struct bnx2x_vfop_filters *vlans,
+ int qid, bool drv_only)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ struct bnx2x_vfop_args_filters filters = {
+ .multi_filter = vlans,
+ .credit = &bnx2x_vfq(vf, qid, vlan_count),
+ };
+ struct bnx2x_vfop_vlan_mac_flags flags = {
+ .drv_only = drv_only,
+ .dont_consume = (filters.credit != NULL),
+ .single_cmd = false,
+ .add = false, /* don't care */
+ };
+ struct bnx2x_vlan_mac_ramrod_params *ramrod =
+ &vf->op_params.vlan_mac;
+
+ /* set ramrod params */
+ bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
+
+ /* set object */
+ ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+
+ /* set extra args */
+ filters.multi_filter->add_cnt = vf_vlan_rules_cnt(vf) -
+ atomic_read(filters.credit);
+
+ vfop->args.filters = filters;
+
+ bnx2x_vfop_opset(BNX2X_VFOP_VLAN_CONFIG_LIST,
+ bnx2x_vfop_vlan_mac, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+/* VFOP queue setup (queue constructor + set vlan 0) */
+static void bnx2x_vfop_qsetup(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ int qid = vfop->args.qctor.qid;
+ enum bnx2x_vfop_qsetup_state state = vfop->state;
+ struct bnx2x_vfop_cmd cmd = {
+ .done = bnx2x_vfop_qsetup,
+ .block = false,
+ };
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+ switch (state) {
+ case BNX2X_VFOP_QSETUP_CTOR:
+ /* init the queue ctor command */
+ vfop->state = BNX2X_VFOP_QSETUP_VLAN0;
+ vfop->rc = bnx2x_vfop_qctor_cmd(bp, vf, &cmd, qid);
+ if (vfop->rc)
+ goto op_err;
+ return;
+
+ case BNX2X_VFOP_QSETUP_VLAN0:
+ /* skip if non-leading or FPGA/EMU*/
+ if (qid)
+ goto op_done;
+
+ /* init the queue set-vlan command (for vlan 0) */
+ vfop->state = BNX2X_VFOP_QSETUP_DONE;
+ vfop->rc = bnx2x_vfop_vlan_set_cmd(bp, vf, &cmd, qid, 0, true);
+ if (vfop->rc)
+ goto op_err;
+ return;
+op_err:
+ BNX2X_ERR("QSETUP[%d:%d] error: rc %d\n", vf->abs_vfid, qid, vfop->rc);
+op_done:
+ case BNX2X_VFOP_QSETUP_DONE:
+ bnx2x_vfop_end(bp, vf, vfop);
+ return;
+ default:
+ bnx2x_vfop_default(state);
+ }
+}
+
+int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ vfop->args.qctor.qid = qid;
+
+ bnx2x_vfop_opset(BNX2X_VFOP_QSETUP_CTOR,
+ bnx2x_vfop_qsetup, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qsetup,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+/* VFOP queue FLR handling (clear vlans, clear macs, queue destructor) */
+static void bnx2x_vfop_qflr(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ int qid = vfop->args.qx.qid;
+ enum bnx2x_vfop_qflr_state state = vfop->state;
+ struct bnx2x_queue_state_params *qstate;
+ struct bnx2x_vfop_cmd cmd;
+
+ bnx2x_vfop_reset_wq(vf);
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "VF[%d] STATE: %d\n", vf->abs_vfid, state);
+
+ cmd.done = bnx2x_vfop_qflr;
+ cmd.block = false;
+
+ switch (state) {
+ case BNX2X_VFOP_QFLR_CLR_VLAN:
+ /* vlan-clear-all: driver-only, don't consume credit */
+ vfop->state = BNX2X_VFOP_QFLR_CLR_MAC;
+ vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, qid, true);
+ if (vfop->rc)
+ goto op_err;
+ return;
+
+ case BNX2X_VFOP_QFLR_CLR_MAC:
+ /* mac-clear-all: driver only consume credit */
+ vfop->state = BNX2X_VFOP_QFLR_TERMINATE;
+ vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, true);
+ DP(BNX2X_MSG_IOV,
+ "VF[%d] vfop->rc after bnx2x_vfop_mac_delall_cmd was %d",
+ vf->abs_vfid, vfop->rc);
+ if (vfop->rc)
+ goto op_err;
+ return;
+
+ case BNX2X_VFOP_QFLR_TERMINATE:
+ qstate = &vfop->op_p->qctor.qstate;
+ memset(qstate , 0, sizeof(*qstate));
+ qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+ vfop->state = BNX2X_VFOP_QFLR_DONE;
+
+ DP(BNX2X_MSG_IOV, "VF[%d] qstate during flr was %d\n",
+ vf->abs_vfid, qstate->q_obj->state);
+
+ if (qstate->q_obj->state != BNX2X_Q_STATE_RESET) {
+ qstate->q_obj->state = BNX2X_Q_STATE_STOPPED;
+ qstate->cmd = BNX2X_Q_CMD_TERMINATE;
+ vfop->rc = bnx2x_queue_state_change(bp, qstate);
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_VERIFY_PEND);
+ } else {
+ goto op_done;
+ }
+
+op_err:
+ BNX2X_ERR("QFLR[%d:%d] error: rc %d\n",
+ vf->abs_vfid, qid, vfop->rc);
+op_done:
+ case BNX2X_VFOP_QFLR_DONE:
+ bnx2x_vfop_end(bp, vf, vfop);
+ return;
+ default:
+ bnx2x_vfop_default(state);
+ }
+op_pending:
+ return;
+}
+
+static int bnx2x_vfop_qflr_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ vfop->args.qx.qid = qid;
+ bnx2x_vfop_opset(BNX2X_VFOP_QFLR_CLR_VLAN,
+ bnx2x_vfop_qflr, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qflr,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+/* VFOP multi-casts */
+static void bnx2x_vfop_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ struct bnx2x_mcast_ramrod_params *mcast = &vfop->op_p->mcast;
+ struct bnx2x_raw_obj *raw = &mcast->mcast_obj->raw;
+ struct bnx2x_vfop_args_mcast *args = &vfop->args.mc_list;
+ enum bnx2x_vfop_mcast_state state = vfop->state;
+ int i;
+
+ bnx2x_vfop_reset_wq(vf);
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+ switch (state) {
+ case BNX2X_VFOP_MCAST_DEL:
+ /* clear existing mcasts */
+ vfop->state = BNX2X_VFOP_MCAST_ADD;
+ vfop->rc = bnx2x_config_mcast(bp, mcast, BNX2X_MCAST_CMD_DEL);
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+
+ case BNX2X_VFOP_MCAST_ADD:
+ if (raw->check_pending(raw))
+ goto op_pending;
+
+ if (args->mc_num) {
+ /* update mcast list on the ramrod params */
+ INIT_LIST_HEAD(&mcast->mcast_list);
+ for (i = 0; i < args->mc_num; i++)
+ list_add_tail(&(args->mc[i].link),
+ &mcast->mcast_list);
+ /* add new mcasts */
+ vfop->state = BNX2X_VFOP_MCAST_CHK_DONE;
+ vfop->rc = bnx2x_config_mcast(bp, mcast,
+ BNX2X_MCAST_CMD_ADD);
+ }
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+
+ case BNX2X_VFOP_MCAST_CHK_DONE:
+ vfop->rc = raw->check_pending(raw) ? 1 : 0;
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+ default:
+ bnx2x_vfop_default(state);
+ }
+op_err:
+ BNX2X_ERR("MCAST CONFIG error: rc %d\n", vfop->rc);
+op_done:
+ kfree(args->mc);
+ bnx2x_vfop_end(bp, vf, vfop);
+op_pending:
+ return;
+}
+
+int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ bnx2x_mac_addr_t *mcasts,
+ int mcast_num, bool drv_only)
+{
+ struct bnx2x_vfop *vfop = NULL;
+ size_t mc_sz = mcast_num * sizeof(struct bnx2x_mcast_list_elem);
+ struct bnx2x_mcast_list_elem *mc = mc_sz ? kzalloc(mc_sz, GFP_KERNEL) :
+ NULL;
+
+ if (!mc_sz || mc) {
+ vfop = bnx2x_vfop_add(bp, vf);
+ if (vfop) {
+ int i;
+ struct bnx2x_mcast_ramrod_params *ramrod =
+ &vf->op_params.mcast;
+
+ /* set ramrod params */
+ memset(ramrod, 0, sizeof(*ramrod));
+ ramrod->mcast_obj = &vf->mcast_obj;
+ if (drv_only)
+ set_bit(RAMROD_DRV_CLR_ONLY,
+ &ramrod->ramrod_flags);
+
+ /* copy mcasts pointers */
+ vfop->args.mc_list.mc_num = mcast_num;
+ vfop->args.mc_list.mc = mc;
+ for (i = 0; i < mcast_num; i++)
+ mc[i].mac = mcasts[i];
+
+ bnx2x_vfop_opset(BNX2X_VFOP_MCAST_DEL,
+ bnx2x_vfop_mcast, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mcast,
+ cmd->block);
+ } else {
+ kfree(mc);
+ }
+ }
+ return -ENOMEM;
+}
+
+/* VFOP rx-mode */
+static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ struct bnx2x_rx_mode_ramrod_params *ramrod = &vfop->op_p->rx_mode;
+ enum bnx2x_vfop_rxmode_state state = vfop->state;
+
+ bnx2x_vfop_reset_wq(vf);
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+ switch (state) {
+ case BNX2X_VFOP_RXMODE_CONFIG:
+ /* next state */
+ vfop->state = BNX2X_VFOP_RXMODE_DONE;
+
+ vfop->rc = bnx2x_config_rx_mode(bp, ramrod);
+ bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
+op_err:
+ BNX2X_ERR("RXMODE error: rc %d\n", vfop->rc);
+op_done:
+ case BNX2X_VFOP_RXMODE_DONE:
+ bnx2x_vfop_end(bp, vf, vfop);
+ return;
+ default:
+ bnx2x_vfop_default(state);
+ }
+op_pending:
+ return;
+}
+
+int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid, unsigned long accept_flags)
+{
+ struct bnx2x_vf_queue *vfq = vfq_get(vf, qid);
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ struct bnx2x_rx_mode_ramrod_params *ramrod =
+ &vf->op_params.rx_mode;
+
+ memset(ramrod, 0, sizeof(*ramrod));
+
+ /* Prepare ramrod parameters */
+ ramrod->cid = vfq->cid;
+ ramrod->cl_id = vfq_cl_id(vf, vfq);
+ ramrod->rx_mode_obj = &bp->rx_mode_obj;
+ ramrod->func_id = FW_VF_HANDLE(vf->abs_vfid);
+
+ ramrod->rx_accept_flags = accept_flags;
+ ramrod->tx_accept_flags = accept_flags;
+ ramrod->pstate = &vf->filter_state;
+ ramrod->state = BNX2X_FILTER_RX_MODE_PENDING;
+
+ set_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state);
+ set_bit(RAMROD_RX, &ramrod->ramrod_flags);
+ set_bit(RAMROD_TX, &ramrod->ramrod_flags);
+
+ ramrod->rdata =
+ bnx2x_vf_sp(bp, vf, rx_mode_rdata.e2);
+ ramrod->rdata_mapping =
+ bnx2x_vf_sp_map(bp, vf, rx_mode_rdata.e2);
+
+ bnx2x_vfop_opset(BNX2X_VFOP_RXMODE_CONFIG,
+ bnx2x_vfop_rxmode, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_rxmode,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+/* VFOP queue tear-down ('drop all' rx-mode, clear vlans, clear macs,
+ * queue destructor)
+ */
+static void bnx2x_vfop_qdown(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ int qid = vfop->args.qx.qid;
+ enum bnx2x_vfop_qteardown_state state = vfop->state;
+ struct bnx2x_vfop_cmd cmd;
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+ cmd.done = bnx2x_vfop_qdown;
+ cmd.block = false;
+
+ switch (state) {
+ case BNX2X_VFOP_QTEARDOWN_RXMODE:
+ /* Drop all */
+ vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_VLAN;
+ vfop->rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd, qid, 0);
+ if (vfop->rc)
+ goto op_err;
+ return;
+
+ case BNX2X_VFOP_QTEARDOWN_CLR_VLAN:
+ /* vlan-clear-all: don't consume credit */
+ vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_MAC;
+ vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, qid, false);
+ if (vfop->rc)
+ goto op_err;
+ return;
+
+ case BNX2X_VFOP_QTEARDOWN_CLR_MAC:
+ /* mac-clear-all: consume credit */
+ vfop->state = BNX2X_VFOP_QTEARDOWN_QDTOR;
+ vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, false);
+ if (vfop->rc)
+ goto op_err;
+ return;
+
+ case BNX2X_VFOP_QTEARDOWN_QDTOR:
+ /* run the queue destruction flow */
+ DP(BNX2X_MSG_IOV, "case: BNX2X_VFOP_QTEARDOWN_QDTOR\n");
+ vfop->state = BNX2X_VFOP_QTEARDOWN_DONE;
+ DP(BNX2X_MSG_IOV, "new state: BNX2X_VFOP_QTEARDOWN_DONE\n");
+ vfop->rc = bnx2x_vfop_qdtor_cmd(bp, vf, &cmd, qid);
+ DP(BNX2X_MSG_IOV, "returned from cmd\n");
+ if (vfop->rc)
+ goto op_err;
+ return;
+op_err:
+ BNX2X_ERR("QTEARDOWN[%d:%d] error: rc %d\n",
+ vf->abs_vfid, qid, vfop->rc);
+
+ case BNX2X_VFOP_QTEARDOWN_DONE:
+ bnx2x_vfop_end(bp, vf, vfop);
+ return;
+ default:
+ bnx2x_vfop_default(state);
+ }
+}
+
+int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+
+ if (vfop) {
+ vfop->args.qx.qid = qid;
+ bnx2x_vfop_opset(BNX2X_VFOP_QTEARDOWN_RXMODE,
+ bnx2x_vfop_qdown, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdown,
+ cmd->block);
+ }
+
+ return -ENOMEM;
+}
+
+/* VF enable primitives
+ * when pretend is required the caller is responsible
+ * for calling pretend prior to calling these routines
+ */
+
+/* internal vf enable - until vf is enabled internally all transactions
+ * are blocked. this routine should always be called last with pretend.
+ */
+static void bnx2x_vf_enable_internal(struct bnx2x *bp, u8 enable)
+{
+ REG_WR(bp, PGLUE_B_REG_INTERNAL_VFID_ENABLE, enable ? 1 : 0);
+}
+
+/* clears vf error in all semi blocks */
+static void bnx2x_vf_semi_clear_err(struct bnx2x *bp, u8 abs_vfid)
+{
+ REG_WR(bp, TSEM_REG_VFPF_ERR_NUM, abs_vfid);
+ REG_WR(bp, USEM_REG_VFPF_ERR_NUM, abs_vfid);
+ REG_WR(bp, CSEM_REG_VFPF_ERR_NUM, abs_vfid);
+ REG_WR(bp, XSEM_REG_VFPF_ERR_NUM, abs_vfid);
+}
+
+static void bnx2x_vf_pglue_clear_err(struct bnx2x *bp, u8 abs_vfid)
+{
+ u32 was_err_group = (2 * BP_PATH(bp) + abs_vfid) >> 5;
+ u32 was_err_reg = 0;
+
+ switch (was_err_group) {
+ case 0:
+ was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_31_0_CLR;
+ break;
+ case 1:
+ was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_63_32_CLR;
+ break;
+ case 2:
+ was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_95_64_CLR;
+ break;
+ case 3:
+ was_err_reg = PGLUE_B_REG_WAS_ERROR_VF_127_96_CLR;
+ break;
+ }
+ REG_WR(bp, was_err_reg, 1 << (abs_vfid & 0x1f));
+}
+
+static void bnx2x_vf_igu_reset(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ int i;
+ u32 val;
+
+ /* Set VF masks and configuration - pretend */
+ bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+
+ REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_LSB, 0);
+ REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_MSB, 0);
+ REG_WR(bp, IGU_REG_SB_MASK_LSB, 0);
+ REG_WR(bp, IGU_REG_SB_MASK_MSB, 0);
+ REG_WR(bp, IGU_REG_PBA_STATUS_LSB, 0);
+ REG_WR(bp, IGU_REG_PBA_STATUS_MSB, 0);
+
+ val = REG_RD(bp, IGU_REG_VF_CONFIGURATION);
+ val |= (IGU_VF_CONF_FUNC_EN | IGU_VF_CONF_MSI_MSIX_EN);
+ if (vf->cfg_flags & VF_CFG_INT_SIMD)
+ val |= IGU_VF_CONF_SINGLE_ISR_EN;
+ val &= ~IGU_VF_CONF_PARENT_MASK;
+ val |= BP_FUNC(bp) << IGU_VF_CONF_PARENT_SHIFT; /* parent PF */
+ REG_WR(bp, IGU_REG_VF_CONFIGURATION, val);
+
+ DP(BNX2X_MSG_IOV,
+ "value in IGU_REG_VF_CONFIGURATION of vf %d after write %x\n",
+ vf->abs_vfid, REG_RD(bp, IGU_REG_VF_CONFIGURATION));
+
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+ /* iterate over all queues, clear sb consumer */
+ for (i = 0; i < vf_sb_count(vf); i++) {
+ u8 igu_sb_id = vf_igu_sb(vf, i);
+
+ /* zero prod memory */
+ REG_WR(bp, IGU_REG_PROD_CONS_MEMORY + igu_sb_id * 4, 0);
+
+ /* clear sb state machine */
+ bnx2x_igu_clear_sb_gen(bp, vf->abs_vfid, igu_sb_id,
+ false /* VF */);
+
+ /* disable + update */
+ bnx2x_vf_igu_ack_sb(bp, vf, igu_sb_id, USTORM_ID, 0,
+ IGU_INT_DISABLE, 1);
+ }
+}
+
+void bnx2x_vf_enable_access(struct bnx2x *bp, u8 abs_vfid)
+{
+ /* set the VF-PF association in the FW */
+ storm_memset_vf_to_pf(bp, FW_VF_HANDLE(abs_vfid), BP_FUNC(bp));
+ storm_memset_func_en(bp, FW_VF_HANDLE(abs_vfid), 1);
+
+ /* clear vf errors*/
+ bnx2x_vf_semi_clear_err(bp, abs_vfid);
+ bnx2x_vf_pglue_clear_err(bp, abs_vfid);
+
+ /* internal vf-enable - pretend */
+ bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, abs_vfid));
+ DP(BNX2X_MSG_IOV, "enabling internal access for vf %x\n", abs_vfid);
+ bnx2x_vf_enable_internal(bp, true);
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+static void bnx2x_vf_enable_traffic(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ /* Reset vf in IGU interrupts are still disabled */
+ bnx2x_vf_igu_reset(bp, vf);
+
+ /* pretend to enable the vf with the PBF */
+ bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+ REG_WR(bp, PBF_REG_DISABLE_VF, 0);
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+static u8 bnx2x_vf_is_pcie_pending(struct bnx2x *bp, u8 abs_vfid)
+{
+ struct pci_dev *dev;
+ struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+
+ if (!vf)
+ goto unknown_dev;
+
+ dev = pci_get_bus_and_slot(vf->bus, vf->devfn);
+ if (dev)
+ return bnx2x_is_pcie_pending(dev);
+
+unknown_dev:
+ BNX2X_ERR("Unknown device\n");
+ return false;
+}
+
+int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid)
+{
+ /* Wait 100ms */
+ msleep(100);
+
+ /* Verify no pending pci transactions */
+ if (bnx2x_vf_is_pcie_pending(bp, abs_vfid))
+ BNX2X_ERR("PCIE Transactions still pending\n");
+
+ return 0;
+}
+
+/* must be called after the number of PF queues and the number of VFs are
+ * both known
+ */
+static void
+bnx2x_iov_static_resc(struct bnx2x *bp, struct vf_pf_resc_request *resc)
+{
+ u16 vlan_count = 0;
+
+ /* will be set only during VF-ACQUIRE */
+ resc->num_rxqs = 0;
+ resc->num_txqs = 0;
+
+ /* no credit calculcis for macs (just yet) */
+ resc->num_mac_filters = 1;
+
+ /* divvy up vlan rules */
+ vlan_count = bp->vlans_pool.check(&bp->vlans_pool);
+ vlan_count = 1 << ilog2(vlan_count);
+ resc->num_vlan_filters = vlan_count / BNX2X_NR_VIRTFN(bp);
+
+ /* no real limitation */
+ resc->num_mc_filters = 0;
+
+ /* num_sbs already set */
+}
+
+/* FLR routines: */
+static void bnx2x_vf_free_resc(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ /* reset the state variables */
+ bnx2x_iov_static_resc(bp, &vf->alloc_resc);
+ vf->state = VF_FREE;
+}
+
+static void bnx2x_vf_flr_clnup_hw(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ u32 poll_cnt = bnx2x_flr_clnup_poll_count(bp);
+
+ /* DQ usage counter */
+ bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+ bnx2x_flr_clnup_poll_hw_counter(bp, DORQ_REG_VF_USAGE_CNT,
+ "DQ VF usage counter timed out",
+ poll_cnt);
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+
+ /* FW cleanup command - poll for the results */
+ if (bnx2x_send_final_clnup(bp, (u8)FW_VF_HANDLE(vf->abs_vfid),
+ poll_cnt))
+ BNX2X_ERR("VF[%d] Final cleanup timed-out\n", vf->abs_vfid);
+
+ /* verify TX hw is flushed */
+ bnx2x_tx_hw_flushed(bp, poll_cnt);
+}
+
+static void bnx2x_vfop_flr(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ struct bnx2x_vfop_args_qx *qx = &vfop->args.qx;
+ enum bnx2x_vfop_flr_state state = vfop->state;
+ struct bnx2x_vfop_cmd cmd = {
+ .done = bnx2x_vfop_flr,
+ .block = false,
+ };
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+ switch (state) {
+ case BNX2X_VFOP_FLR_QUEUES:
+ /* the cleanup operations are valid if and only if the VF
+ * was first acquired.
+ */
+ if (++(qx->qid) < vf_rxq_count(vf)) {
+ vfop->rc = bnx2x_vfop_qflr_cmd(bp, vf, &cmd,
+ qx->qid);
+ if (vfop->rc)
+ goto op_err;
+ return;
+ }
+ /* remove multicasts */
+ vfop->state = BNX2X_VFOP_FLR_HW;
+ vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL,
+ 0, true);
+ if (vfop->rc)
+ goto op_err;
+ return;
+ case BNX2X_VFOP_FLR_HW:
+
+ /* dispatch final cleanup and wait for HW queues to flush */
+ bnx2x_vf_flr_clnup_hw(bp, vf);
+
+ /* release VF resources */
+ bnx2x_vf_free_resc(bp, vf);
+
+ /* re-open the mailbox */
+ bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
+
+ goto op_done;
+ default:
+ bnx2x_vfop_default(state);
+ }
+op_err:
+ BNX2X_ERR("VF[%d] FLR error: rc %d\n", vf->abs_vfid, vfop->rc);
+op_done:
+ vf->flr_clnup_stage = VF_FLR_ACK;
+ bnx2x_vfop_end(bp, vf, vfop);
+ bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
+}
+
+static int bnx2x_vfop_flr_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ vfop_handler_t done)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+ if (vfop) {
+ vfop->args.qx.qid = -1; /* loop */
+ bnx2x_vfop_opset(BNX2X_VFOP_FLR_QUEUES,
+ bnx2x_vfop_flr, done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_flr, false);
+ }
+ return -ENOMEM;
+}
+
+static void bnx2x_vf_flr_clnup(struct bnx2x *bp, struct bnx2x_virtf *prev_vf)
+{
+ int i = prev_vf ? prev_vf->index + 1 : 0;
+ struct bnx2x_virtf *vf;
+
+ /* find next VF to cleanup */
+next_vf_to_clean:
+ for (;
+ i < BNX2X_NR_VIRTFN(bp) &&
+ (bnx2x_vf(bp, i, state) != VF_RESET ||
+ bnx2x_vf(bp, i, flr_clnup_stage) != VF_FLR_CLN);
+ i++)
+ ;
+
+ DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. num of vfs: %d\n", i,
+ BNX2X_NR_VIRTFN(bp));
+
+ if (i < BNX2X_NR_VIRTFN(bp)) {
+ vf = BP_VF(bp, i);
+
+ /* lock the vf pf channel */
+ bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
+
+ /* invoke the VF FLR SM */
+ if (bnx2x_vfop_flr_cmd(bp, vf, bnx2x_vf_flr_clnup)) {
+ BNX2X_ERR("VF[%d]: FLR cleanup failed -ENOMEM\n",
+ vf->abs_vfid);
+
+ /* mark the VF to be ACKED and continue */
+ vf->flr_clnup_stage = VF_FLR_ACK;
+ goto next_vf_to_clean;
+ }
+ return;
+ }
+
+ /* we are done, update vf records */
+ for_each_vf(bp, i) {
+ vf = BP_VF(bp, i);
+
+ if (vf->flr_clnup_stage != VF_FLR_ACK)
+ continue;
+
+ vf->flr_clnup_stage = VF_FLR_EPILOG;
+ }
+
+ /* Acknowledge the handled VFs.
+ * we are acknowledge all the vfs which an flr was requested for, even
+ * if amongst them there are such that we never opened, since the mcp
+ * will interrupt us immediately again if we only ack some of the bits,
+ * resulting in an endless loop. This can happen for example in KVM
+ * where an 'all ones' flr request is sometimes given by hyper visor
+ */
+ DP(BNX2X_MSG_MCP, "DRV_STATUS_VF_DISABLED ACK for vfs 0x%x 0x%x\n",
+ bp->vfdb->flrd_vfs[0], bp->vfdb->flrd_vfs[1]);
+ for (i = 0; i < FLRD_VFS_DWORDS; i++)
+ SHMEM2_WR(bp, drv_ack_vf_disabled[BP_FW_MB_IDX(bp)][i],
+ bp->vfdb->flrd_vfs[i]);
+
+ bnx2x_fw_command(bp, DRV_MSG_CODE_VF_DISABLED_DONE, 0);
+
+ /* clear the acked bits - better yet if the MCP implemented
+ * write to clear semantics
+ */
+ for (i = 0; i < FLRD_VFS_DWORDS; i++)
+ SHMEM2_WR(bp, drv_ack_vf_disabled[BP_FW_MB_IDX(bp)][i], 0);
+}
+
+void bnx2x_vf_handle_flr_event(struct bnx2x *bp)
+{
+ int i;
+
+ /* Read FLR'd VFs */
+ for (i = 0; i < FLRD_VFS_DWORDS; i++)
+ bp->vfdb->flrd_vfs[i] = SHMEM2_RD(bp, mcp_vf_disabled[i]);
+
+ DP(BNX2X_MSG_MCP,
+ "DRV_STATUS_VF_DISABLED received for vfs 0x%x 0x%x\n",
+ bp->vfdb->flrd_vfs[0], bp->vfdb->flrd_vfs[1]);
+
+ for_each_vf(bp, i) {
+ struct bnx2x_virtf *vf = BP_VF(bp, i);
+ u32 reset = 0;
+
+ if (vf->abs_vfid < 32)
+ reset = bp->vfdb->flrd_vfs[0] & (1 << vf->abs_vfid);
+ else
+ reset = bp->vfdb->flrd_vfs[1] &
+ (1 << (vf->abs_vfid - 32));
+
+ if (reset) {
+ /* set as reset and ready for cleanup */
+ vf->state = VF_RESET;
+ vf->flr_clnup_stage = VF_FLR_CLN;
+
+ DP(BNX2X_MSG_IOV,
+ "Initiating Final cleanup for VF %d\n",
+ vf->abs_vfid);
+ }
+ }
+
+ /* do the FLR cleanup for all marked VFs*/
+ bnx2x_vf_flr_clnup(bp, NULL);
+}
+
+/* IOV global initialization routines */
+void bnx2x_iov_init_dq(struct bnx2x *bp)
+{
+ if (!IS_SRIOV(bp))
+ return;
+
+ /* Set the DQ such that the CID reflect the abs_vfid */
+ REG_WR(bp, DORQ_REG_VF_NORM_VF_BASE, 0);
+ REG_WR(bp, DORQ_REG_MAX_RVFID_SIZE, ilog2(BNX2X_MAX_NUM_OF_VFS));
+
+ /* Set VFs starting CID. If its > 0 the preceding CIDs are belong to
+ * the PF L2 queues
+ */
+ REG_WR(bp, DORQ_REG_VF_NORM_CID_BASE, BNX2X_FIRST_VF_CID);
+
+ /* The VF window size is the log2 of the max number of CIDs per VF */
+ REG_WR(bp, DORQ_REG_VF_NORM_CID_WND_SIZE, BNX2X_VF_CID_WND);
+
+ /* The VF doorbell size 0 - *B, 4 - 128B. We set it here to match
+ * the Pf doorbell size although the 2 are independent.
+ */
+ REG_WR(bp, DORQ_REG_VF_NORM_CID_OFST,
+ BNX2X_DB_SHIFT - BNX2X_DB_MIN_SHIFT);
+
+ /* No security checks for now -
+ * configure single rule (out of 16) mask = 0x1, value = 0x0,
+ * CID range 0 - 0x1ffff
+ */
+ REG_WR(bp, DORQ_REG_VF_TYPE_MASK_0, 1);
+ REG_WR(bp, DORQ_REG_VF_TYPE_VALUE_0, 0);
+ REG_WR(bp, DORQ_REG_VF_TYPE_MIN_MCID_0, 0);
+ REG_WR(bp, DORQ_REG_VF_TYPE_MAX_MCID_0, 0x1ffff);
+
+ /* set the number of VF alllowed doorbells to the full DQ range */
+ REG_WR(bp, DORQ_REG_VF_NORM_MAX_CID_COUNT, 0x20000);
+
+ /* set the VF doorbell threshold */
+ REG_WR(bp, DORQ_REG_VF_USAGE_CT_LIMIT, 4);
+}
+
+void bnx2x_iov_init_dmae(struct bnx2x *bp)
+{
+ DP(BNX2X_MSG_IOV, "SRIOV is %s\n", IS_SRIOV(bp) ? "ON" : "OFF");
+ if (!IS_SRIOV(bp))
+ return;
+
+ REG_WR(bp, DMAE_REG_BACKWARD_COMP_EN, 0);
+}
+
+static int bnx2x_vf_bus(struct bnx2x *bp, int vfid)
+{
+ struct pci_dev *dev = bp->pdev;
+ struct bnx2x_sriov *iov = &bp->vfdb->sriov;
+
+ return dev->bus->number + ((dev->devfn + iov->offset +
+ iov->stride * vfid) >> 8);
+}
+
+static int bnx2x_vf_devfn(struct bnx2x *bp, int vfid)
+{
+ struct pci_dev *dev = bp->pdev;
+ struct bnx2x_sriov *iov = &bp->vfdb->sriov;
+
+ return (dev->devfn + iov->offset + iov->stride * vfid) & 0xff;
+}
+
+static void bnx2x_vf_set_bars(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ int i, n;
+ struct pci_dev *dev = bp->pdev;
+ struct bnx2x_sriov *iov = &bp->vfdb->sriov;
+
+ for (i = 0, n = 0; i < PCI_SRIOV_NUM_BARS; i += 2, n++) {
+ u64 start = pci_resource_start(dev, PCI_IOV_RESOURCES + i);
+ u32 size = pci_resource_len(dev, PCI_IOV_RESOURCES + i);
+
+ size /= iov->total;
+ vf->bars[n].bar = start + size * vf->abs_vfid;
+ vf->bars[n].size = size;
+ }
+}
+
+static int bnx2x_ari_enabled(struct pci_dev *dev)
+{
+ return dev->bus->self && dev->bus->self->ari_enabled;
+}
+
+static void
+bnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
+{
+ int sb_id;
+ u32 val;
+ u8 fid;
+
+ /* IGU in normal mode - read CAM */
+ for (sb_id = 0; sb_id < IGU_REG_MAPPING_MEMORY_SIZE; sb_id++) {
+ val = REG_RD(bp, IGU_REG_MAPPING_MEMORY + sb_id * 4);
+ if (!(val & IGU_REG_MAPPING_MEMORY_VALID))
+ continue;
+ fid = GET_FIELD((val), IGU_REG_MAPPING_MEMORY_FID);
+ if (!(fid & IGU_FID_ENCODE_IS_PF))
+ bnx2x_vf_set_igu_info(bp, sb_id,
+ (fid & IGU_FID_VF_NUM_MASK));
+
+ DP(BNX2X_MSG_IOV, "%s[%d], igu_sb_id=%d, msix=%d\n",
+ ((fid & IGU_FID_ENCODE_IS_PF) ? "PF" : "VF"),
+ ((fid & IGU_FID_ENCODE_IS_PF) ? (fid & IGU_FID_PF_NUM_MASK) :
+ (fid & IGU_FID_VF_NUM_MASK)), sb_id,
+ GET_FIELD((val), IGU_REG_MAPPING_MEMORY_VECTOR));
+ }
+}
+
+static void __bnx2x_iov_free_vfdb(struct bnx2x *bp)
+{
+ if (bp->vfdb) {
+ kfree(bp->vfdb->vfqs);
+ kfree(bp->vfdb->vfs);
+ kfree(bp->vfdb);
+ }
+ bp->vfdb = NULL;
+}
+
+static int bnx2x_sriov_pci_cfg_info(struct bnx2x *bp, struct bnx2x_sriov *iov)
+{
+ int pos;
+ struct pci_dev *dev = bp->pdev;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+ if (!pos) {
+ BNX2X_ERR("failed to find SRIOV capability in device\n");
+ return -ENODEV;
+ }
+
+ iov->pos = pos;
+ DP(BNX2X_MSG_IOV, "sriov ext pos %d\n", pos);
+ pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &iov->ctrl);
+ pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &iov->total);
+ pci_read_config_word(dev, pos + PCI_SRIOV_INITIAL_VF, &iov->initial);
+ pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &iov->offset);
+ pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &iov->stride);
+ pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &iov->pgsz);
+ pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
+ pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
+
+ return 0;
+}
+
+static int bnx2x_sriov_info(struct bnx2x *bp, struct bnx2x_sriov *iov)
+{
+ u32 val;
+
+ /* read the SRIOV capability structure
+ * The fields can be read via configuration read or
+ * directly from the device (starting at offset PCICFG_OFFSET)
+ */
+ if (bnx2x_sriov_pci_cfg_info(bp, iov))
+ return -ENODEV;
+
+ /* get the number of SRIOV bars */
+ iov->nres = 0;
+
+ /* read the first_vfid */
+ val = REG_RD(bp, PCICFG_OFFSET + GRC_CONFIG_REG_PF_INIT_VF);
+ iov->first_vf_in_pf = ((val & GRC_CR_PF_INIT_VF_PF_FIRST_VF_NUM_MASK)
+ * 8) - (BNX2X_MAX_NUM_OF_VFS * BP_PATH(bp));
+
+ DP(BNX2X_MSG_IOV,
+ "IOV info[%d]: first vf %d, nres %d, cap 0x%x, ctrl 0x%x, total %d, initial %d, num vfs %d, offset %d, stride %d, page size 0x%x\n",
+ BP_FUNC(bp),
+ iov->first_vf_in_pf, iov->nres, iov->cap, iov->ctrl, iov->total,
+ iov->initial, iov->nr_virtfn, iov->offset, iov->stride, iov->pgsz);
+
+ return 0;
+}
+
+static u8 bnx2x_iov_get_max_queue_count(struct bnx2x *bp)
+{
+ int i;
+ u8 queue_count = 0;
+
+ if (IS_SRIOV(bp))
+ for_each_vf(bp, i)
+ queue_count += bnx2x_vf(bp, i, alloc_resc.num_sbs);
+
+ return queue_count;
+}
+
+/* must be called after PF bars are mapped */
+int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
+ int num_vfs_param)
+{
+ int err, i, qcount;
+ struct bnx2x_sriov *iov;
+ struct pci_dev *dev = bp->pdev;
+
+ bp->vfdb = NULL;
+
+ /* verify is pf */
+ if (IS_VF(bp))
+ return 0;
+
+ /* verify sriov capability is present in configuration space */
+ if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV))
+ return 0;
+
+ /* verify chip revision */
+ if (CHIP_IS_E1x(bp))
+ return 0;
+
+ /* check if SRIOV support is turned off */
+ if (!num_vfs_param)
+ return 0;
+
+ /* SRIOV assumes that num of PF CIDs < BNX2X_FIRST_VF_CID */
+ if (BNX2X_L2_MAX_CID(bp) >= BNX2X_FIRST_VF_CID) {
+ BNX2X_ERR("PF cids %d are overspilling into vf space (starts at %d). Abort SRIOV\n",
+ BNX2X_L2_MAX_CID(bp), BNX2X_FIRST_VF_CID);
+ return 0;
+ }
+
+ /* SRIOV can be enabled only with MSIX */
+ if (int_mode_param == BNX2X_INT_MODE_MSI ||
+ int_mode_param == BNX2X_INT_MODE_INTX)
+ BNX2X_ERR("Forced MSI/INTx mode is incompatible with SRIOV\n");
+
+ err = -EIO;
+ /* verify ari is enabled */
+ if (!bnx2x_ari_enabled(bp->pdev)) {
+ BNX2X_ERR("ARI not supported, SRIOV can not be enabled\n");
+ return err;
+ }
+
+ /* verify igu is in normal mode */
+ if (CHIP_INT_MODE_IS_BC(bp)) {
+ BNX2X_ERR("IGU not normal mode, SRIOV can not be enabled\n");
+ return err;
+ }
+
+ /* allocate the vfs database */
+ bp->vfdb = kzalloc(sizeof(*(bp->vfdb)), GFP_KERNEL);
+ if (!bp->vfdb) {
+ BNX2X_ERR("failed to allocate vf database\n");
+ err = -ENOMEM;
+ goto failed;
+ }
+
+ /* get the sriov info - Linux already collected all the pertinent
+ * information, however the sriov structure is for the private use
+ * of the pci module. Also we want this information regardless
+ * of the hyper-visor.
+ */
+ iov = &(bp->vfdb->sriov);
+ err = bnx2x_sriov_info(bp, iov);
+ if (err)
+ goto failed;
+
+ /* SR-IOV capability was enabled but there are no VFs*/
+ if (iov->total == 0)
+ goto failed;
+
+ /* calculate the actual number of VFs */
+ iov->nr_virtfn = min_t(u16, iov->total, (u16)num_vfs_param);
+
+ /* allocate the vf array */
+ bp->vfdb->vfs = kzalloc(sizeof(struct bnx2x_virtf) *
+ BNX2X_NR_VIRTFN(bp), GFP_KERNEL);
+ if (!bp->vfdb->vfs) {
+ BNX2X_ERR("failed to allocate vf array\n");
+ err = -ENOMEM;
+ goto failed;
+ }
+
+ /* Initial VF init - index and abs_vfid - nr_virtfn must be set */
+ for_each_vf(bp, i) {
+ bnx2x_vf(bp, i, index) = i;
+ bnx2x_vf(bp, i, abs_vfid) = iov->first_vf_in_pf + i;
+ bnx2x_vf(bp, i, state) = VF_FREE;
+ INIT_LIST_HEAD(&bnx2x_vf(bp, i, op_list_head));
+ mutex_init(&bnx2x_vf(bp, i, op_mutex));
+ bnx2x_vf(bp, i, op_current) = CHANNEL_TLV_NONE;
+ }
+
+ /* re-read the IGU CAM for VFs - index and abs_vfid must be set */
+ bnx2x_get_vf_igu_cam_info(bp);
+
+ /* get the total queue count and allocate the global queue arrays */
+ qcount = bnx2x_iov_get_max_queue_count(bp);
+
+ /* allocate the queue arrays for all VFs */
+ bp->vfdb->vfqs = kzalloc(qcount * sizeof(struct bnx2x_vf_queue),
+ GFP_KERNEL);
+ if (!bp->vfdb->vfqs) {
+ BNX2X_ERR("failed to allocate vf queue array\n");
+ err = -ENOMEM;
+ goto failed;
+ }
+
+ return 0;
+failed:
+ DP(BNX2X_MSG_IOV, "Failed err=%d\n", err);
+ __bnx2x_iov_free_vfdb(bp);
+ return err;
+}
+
+void bnx2x_iov_remove_one(struct bnx2x *bp)
+{
+ /* if SRIOV is not enabled there's nothing to do */
+ if (!IS_SRIOV(bp))
+ return;
+
+ DP(BNX2X_MSG_IOV, "about to call disable sriov\n");
+ pci_disable_sriov(bp->pdev);
+ DP(BNX2X_MSG_IOV, "sriov disabled\n");
+
+ /* free vf database */
+ __bnx2x_iov_free_vfdb(bp);
+}
+
+void bnx2x_iov_free_mem(struct bnx2x *bp)
+{
+ int i;
+
+ if (!IS_SRIOV(bp))
+ return;
+
+ /* free vfs hw contexts */
+ for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
+ struct hw_dma *cxt = &bp->vfdb->context[i];
+ BNX2X_PCI_FREE(cxt->addr, cxt->mapping, cxt->size);
+ }
+
+ BNX2X_PCI_FREE(BP_VFDB(bp)->sp_dma.addr,
+ BP_VFDB(bp)->sp_dma.mapping,
+ BP_VFDB(bp)->sp_dma.size);
+
+ BNX2X_PCI_FREE(BP_VF_MBX_DMA(bp)->addr,
+ BP_VF_MBX_DMA(bp)->mapping,
+ BP_VF_MBX_DMA(bp)->size);
+
+ BNX2X_PCI_FREE(BP_VF_BULLETIN_DMA(bp)->addr,
+ BP_VF_BULLETIN_DMA(bp)->mapping,
+ BP_VF_BULLETIN_DMA(bp)->size);
+}
+
+int bnx2x_iov_alloc_mem(struct bnx2x *bp)
+{
+ size_t tot_size;
+ int i, rc = 0;
+
+ if (!IS_SRIOV(bp))
+ return rc;
+
+ /* allocate vfs hw contexts */
+ tot_size = (BP_VFDB(bp)->sriov.first_vf_in_pf + BNX2X_NR_VIRTFN(bp)) *
+ BNX2X_CIDS_PER_VF * sizeof(union cdu_context);
+
+ for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
+ struct hw_dma *cxt = BP_VF_CXT_PAGE(bp, i);
+ cxt->size = min_t(size_t, tot_size, CDU_ILT_PAGE_SZ);
+
+ if (cxt->size) {
+ BNX2X_PCI_ALLOC(cxt->addr, &cxt->mapping, cxt->size);
+ } else {
+ cxt->addr = NULL;
+ cxt->mapping = 0;
+ }
+ tot_size -= cxt->size;
+ }
+
+ /* allocate vfs ramrods dma memory - client_init and set_mac */
+ tot_size = BNX2X_NR_VIRTFN(bp) * sizeof(struct bnx2x_vf_sp);
+ BNX2X_PCI_ALLOC(BP_VFDB(bp)->sp_dma.addr, &BP_VFDB(bp)->sp_dma.mapping,
+ tot_size);
+ BP_VFDB(bp)->sp_dma.size = tot_size;
+
+ /* allocate mailboxes */
+ tot_size = BNX2X_NR_VIRTFN(bp) * MBX_MSG_ALIGNED_SIZE;
+ BNX2X_PCI_ALLOC(BP_VF_MBX_DMA(bp)->addr, &BP_VF_MBX_DMA(bp)->mapping,
+ tot_size);
+ BP_VF_MBX_DMA(bp)->size = tot_size;
+
+ /* allocate local bulletin boards */
+ tot_size = BNX2X_NR_VIRTFN(bp) * BULLETIN_CONTENT_SIZE;
+ BNX2X_PCI_ALLOC(BP_VF_BULLETIN_DMA(bp)->addr,
+ &BP_VF_BULLETIN_DMA(bp)->mapping, tot_size);
+ BP_VF_BULLETIN_DMA(bp)->size = tot_size;
+
+ return 0;
+
+alloc_mem_err:
+ return -ENOMEM;
+}
+
+static void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_queue *q)
+{
+ u8 cl_id = vfq_cl_id(vf, q);
+ u8 func_id = FW_VF_HANDLE(vf->abs_vfid);
+ unsigned long q_type = 0;
+
+ set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
+ set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);
+
+ /* Queue State object */
+ bnx2x_init_queue_obj(bp, &q->sp_obj,
+ cl_id, &q->cid, 1, func_id,
+ bnx2x_vf_sp(bp, vf, q_data),
+ bnx2x_vf_sp_map(bp, vf, q_data),
+ q_type);
+
+ DP(BNX2X_MSG_IOV,
+ "initialized vf %d's queue object. func id set to %d\n",
+ vf->abs_vfid, q->sp_obj.func_id);
+
+ /* mac/vlan objects are per queue, but only those
+ * that belong to the leading queue are initialized
+ */
+ if (vfq_is_leading(q)) {
+ /* mac */
+ bnx2x_init_mac_obj(bp, &q->mac_obj,
+ cl_id, q->cid, func_id,
+ bnx2x_vf_sp(bp, vf, mac_rdata),
+ bnx2x_vf_sp_map(bp, vf, mac_rdata),
+ BNX2X_FILTER_MAC_PENDING,
+ &vf->filter_state,
+ BNX2X_OBJ_TYPE_RX_TX,
+ &bp->macs_pool);
+ /* vlan */
+ bnx2x_init_vlan_obj(bp, &q->vlan_obj,
+ cl_id, q->cid, func_id,
+ bnx2x_vf_sp(bp, vf, vlan_rdata),
+ bnx2x_vf_sp_map(bp, vf, vlan_rdata),
+ BNX2X_FILTER_VLAN_PENDING,
+ &vf->filter_state,
+ BNX2X_OBJ_TYPE_RX_TX,
+ &bp->vlans_pool);
+
+ /* mcast */
+ bnx2x_init_mcast_obj(bp, &vf->mcast_obj, cl_id,
+ q->cid, func_id, func_id,
+ bnx2x_vf_sp(bp, vf, mcast_rdata),
+ bnx2x_vf_sp_map(bp, vf, mcast_rdata),
+ BNX2X_FILTER_MCAST_PENDING,
+ &vf->filter_state,
+ BNX2X_OBJ_TYPE_RX_TX);
+
+ vf->leading_rss = cl_id;
+ }
+}
+
+/* called by bnx2x_nic_load */
+int bnx2x_iov_nic_init(struct bnx2x *bp)
+{
+ int vfid, qcount, i;
+
+ if (!IS_SRIOV(bp)) {
+ DP(BNX2X_MSG_IOV, "vfdb was not allocated\n");
+ return 0;
+ }
+
+ DP(BNX2X_MSG_IOV, "num of vfs: %d\n", (bp)->vfdb->sriov.nr_virtfn);
+
+ /* initialize vf database */
+ for_each_vf(bp, vfid) {
+ struct bnx2x_virtf *vf = BP_VF(bp, vfid);
+
+ int base_vf_cid = (BP_VFDB(bp)->sriov.first_vf_in_pf + vfid) *
+ BNX2X_CIDS_PER_VF;
+
+ union cdu_context *base_cxt = (union cdu_context *)
+ BP_VF_CXT_PAGE(bp, base_vf_cid/ILT_PAGE_CIDS)->addr +
+ (base_vf_cid & (ILT_PAGE_CIDS-1));
+
+ DP(BNX2X_MSG_IOV,
+ "VF[%d] Max IGU SBs: %d, base vf cid 0x%x, base cid 0x%x, base cxt %p\n",
+ vf->abs_vfid, vf_sb_count(vf), base_vf_cid,
+ BNX2X_FIRST_VF_CID + base_vf_cid, base_cxt);
+
+ /* init statically provisioned resources */
+ bnx2x_iov_static_resc(bp, &vf->alloc_resc);
+
+ /* queues are initialized during VF-ACQUIRE */
+
+ /* reserve the vf vlan credit */
+ bp->vlans_pool.get(&bp->vlans_pool, vf_vlan_rules_cnt(vf));
+
+ vf->filter_state = 0;
+ vf->sp_cl_id = bnx2x_fp(bp, 0, cl_id);
+
+ /* init mcast object - This object will be re-initialized
+ * during VF-ACQUIRE with the proper cl_id and cid.
+ * It needs to be initialized here so that it can be safely
+ * handled by a subsequent FLR flow.
+ */
+ bnx2x_init_mcast_obj(bp, &vf->mcast_obj, 0xFF,
+ 0xFF, 0xFF, 0xFF,
+ bnx2x_vf_sp(bp, vf, mcast_rdata),
+ bnx2x_vf_sp_map(bp, vf, mcast_rdata),
+ BNX2X_FILTER_MCAST_PENDING,
+ &vf->filter_state,
+ BNX2X_OBJ_TYPE_RX_TX);
+
+ /* set the mailbox message addresses */
+ BP_VF_MBX(bp, vfid)->msg = (struct bnx2x_vf_mbx_msg *)
+ (((u8 *)BP_VF_MBX_DMA(bp)->addr) + vfid *
+ MBX_MSG_ALIGNED_SIZE);
+
+ BP_VF_MBX(bp, vfid)->msg_mapping = BP_VF_MBX_DMA(bp)->mapping +
+ vfid * MBX_MSG_ALIGNED_SIZE;
+
+ /* Enable vf mailbox */
+ bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
+ }
+
+ /* Final VF init */
+ qcount = 0;
+ for_each_vf(bp, i) {
+ struct bnx2x_virtf *vf = BP_VF(bp, i);
+
+ /* fill in the BDF and bars */
+ vf->bus = bnx2x_vf_bus(bp, i);
+ vf->devfn = bnx2x_vf_devfn(bp, i);
+ bnx2x_vf_set_bars(bp, vf);
+
+ DP(BNX2X_MSG_IOV,
+ "VF info[%d]: bus 0x%x, devfn 0x%x, bar0 [0x%x, %d], bar1 [0x%x, %d], bar2 [0x%x, %d]\n",
+ vf->abs_vfid, vf->bus, vf->devfn,
+ (unsigned)vf->bars[0].bar, vf->bars[0].size,
+ (unsigned)vf->bars[1].bar, vf->bars[1].size,
+ (unsigned)vf->bars[2].bar, vf->bars[2].size);
+
+ /* set local queue arrays */
+ vf->vfqs = &bp->vfdb->vfqs[qcount];
+ qcount += bnx2x_vf(bp, i, alloc_resc.num_sbs);
+ }
+
+ return 0;
+}
+
+/* called by bnx2x_chip_cleanup */
+int bnx2x_iov_chip_cleanup(struct bnx2x *bp)
+{
+ int i;
+
+ if (!IS_SRIOV(bp))
+ return 0;
+
+ /* release all the VFs */
+ for_each_vf(bp, i)
+ bnx2x_vf_release(bp, BP_VF(bp, i), true); /* blocking */
+
+ return 0;
+}
+
+/* called by bnx2x_init_hw_func, returns the next ilt line */
+int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line)
+{
+ int i;
+ struct bnx2x_ilt *ilt = BP_ILT(bp);
+
+ if (!IS_SRIOV(bp))
+ return line;
+
+ /* set vfs ilt lines */
+ for (i = 0; i < BNX2X_VF_CIDS/ILT_PAGE_CIDS; i++) {
+ struct hw_dma *hw_cxt = BP_VF_CXT_PAGE(bp, i);
+
+ ilt->lines[line+i].page = hw_cxt->addr;
+ ilt->lines[line+i].page_mapping = hw_cxt->mapping;
+ ilt->lines[line+i].size = hw_cxt->size; /* doesn't matter */
+ }
+ return line + i;
+}
+
+static u8 bnx2x_iov_is_vf_cid(struct bnx2x *bp, u16 cid)
+{
+ return ((cid >= BNX2X_FIRST_VF_CID) &&
+ ((cid - BNX2X_FIRST_VF_CID) < BNX2X_VF_CIDS));
+}
+
+static
+void bnx2x_vf_handle_classification_eqe(struct bnx2x *bp,
+ struct bnx2x_vf_queue *vfq,
+ union event_ring_elem *elem)
+{
+ unsigned long ramrod_flags = 0;
+ int rc = 0;
+
+ /* Always push next commands out, don't wait here */
+ set_bit(RAMROD_CONT, &ramrod_flags);
+
+ switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) {
+ case BNX2X_FILTER_MAC_PENDING:
+ rc = vfq->mac_obj.complete(bp, &vfq->mac_obj, elem,
+ &ramrod_flags);
+ break;
+ case BNX2X_FILTER_VLAN_PENDING:
+ rc = vfq->vlan_obj.complete(bp, &vfq->vlan_obj, elem,
+ &ramrod_flags);
+ break;
+ default:
+ BNX2X_ERR("Unsupported classification command: %d\n",
+ elem->message.data.eth_event.echo);
+ return;
+ }
+ if (rc < 0)
+ BNX2X_ERR("Failed to schedule new commands: %d\n", rc);
+ else if (rc > 0)
+ DP(BNX2X_MSG_IOV, "Scheduled next pending commands...\n");
+}
+
+static
+void bnx2x_vf_handle_mcast_eqe(struct bnx2x *bp,
+ struct bnx2x_virtf *vf)
+{
+ struct bnx2x_mcast_ramrod_params rparam = {NULL};
+ int rc;
+
+ rparam.mcast_obj = &vf->mcast_obj;
+ vf->mcast_obj.raw.clear_pending(&vf->mcast_obj.raw);
+
+ /* If there are pending mcast commands - send them */
+ if (vf->mcast_obj.check_pending(&vf->mcast_obj)) {
+ rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT);
+ if (rc < 0)
+ BNX2X_ERR("Failed to send pending mcast commands: %d\n",
+ rc);
+ }
+}
+
+static
+void bnx2x_vf_handle_filters_eqe(struct bnx2x *bp,
+ struct bnx2x_virtf *vf)
+{
+ smp_mb__before_clear_bit();
+ clear_bit(BNX2X_FILTER_RX_MODE_PENDING, &vf->filter_state);
+ smp_mb__after_clear_bit();
+}
+
+int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
+{
+ struct bnx2x_virtf *vf;
+ int qidx = 0, abs_vfid;
+ u8 opcode;
+ u16 cid = 0xffff;
+
+ if (!IS_SRIOV(bp))
+ return 1;
+
+ /* first get the cid - the only events we handle here are cfc-delete
+ * and set-mac completion
+ */
+ opcode = elem->message.opcode;
+
+ switch (opcode) {
+ case EVENT_RING_OPCODE_CFC_DEL:
+ cid = SW_CID((__force __le32)
+ elem->message.data.cfc_del_event.cid);
+ DP(BNX2X_MSG_IOV, "checking cfc-del comp cid=%d\n", cid);
+ break;
+ case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
+ case EVENT_RING_OPCODE_MULTICAST_RULES:
+ case EVENT_RING_OPCODE_FILTERS_RULES:
+ cid = (elem->message.data.eth_event.echo &
+ BNX2X_SWCID_MASK);
+ DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid);
+ break;
+ case EVENT_RING_OPCODE_VF_FLR:
+ abs_vfid = elem->message.data.vf_flr_event.vf_id;
+ DP(BNX2X_MSG_IOV, "Got VF FLR notification abs_vfid=%d\n",
+ abs_vfid);
+ goto get_vf;
+ case EVENT_RING_OPCODE_MALICIOUS_VF:
+ abs_vfid = elem->message.data.malicious_vf_event.vf_id;
+ DP(BNX2X_MSG_IOV, "Got VF MALICIOUS notification abs_vfid=%d\n",
+ abs_vfid);
+ goto get_vf;
+ default:
+ return 1;
+ }
+
+ /* check if the cid is the VF range */
+ if (!bnx2x_iov_is_vf_cid(bp, cid)) {
+ DP(BNX2X_MSG_IOV, "cid is outside vf range: %d\n", cid);
+ return 1;
+ }
+
+ /* extract vf and rxq index from vf_cid - relies on the following:
+ * 1. vfid on cid reflects the true abs_vfid
+ * 2. the max number of VFs (per path) is 64
+ */
+ qidx = cid & ((1 << BNX2X_VF_CID_WND)-1);
+ abs_vfid = (cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
+get_vf:
+ vf = bnx2x_vf_by_abs_fid(bp, abs_vfid);
+
+ if (!vf) {
+ BNX2X_ERR("EQ completion for unknown VF, cid %d, abs_vfid %d\n",
+ cid, abs_vfid);
+ return 0;
+ }
+
+ switch (opcode) {
+ case EVENT_RING_OPCODE_CFC_DEL:
+ DP(BNX2X_MSG_IOV, "got VF [%d:%d] cfc delete ramrod\n",
+ vf->abs_vfid, qidx);
+ vfq_get(vf, qidx)->sp_obj.complete_cmd(bp,
+ &vfq_get(vf,
+ qidx)->sp_obj,
+ BNX2X_Q_CMD_CFC_DEL);
+ break;
+ case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
+ DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mac/vlan ramrod\n",
+ vf->abs_vfid, qidx);
+ bnx2x_vf_handle_classification_eqe(bp, vfq_get(vf, qidx), elem);
+ break;
+ case EVENT_RING_OPCODE_MULTICAST_RULES:
+ DP(BNX2X_MSG_IOV, "got VF [%d:%d] set mcast ramrod\n",
+ vf->abs_vfid, qidx);
+ bnx2x_vf_handle_mcast_eqe(bp, vf);
+ break;
+ case EVENT_RING_OPCODE_FILTERS_RULES:
+ DP(BNX2X_MSG_IOV, "got VF [%d:%d] set rx-mode ramrod\n",
+ vf->abs_vfid, qidx);
+ bnx2x_vf_handle_filters_eqe(bp, vf);
+ break;
+ case EVENT_RING_OPCODE_VF_FLR:
+ DP(BNX2X_MSG_IOV, "got VF [%d] FLR notification\n",
+ vf->abs_vfid);
+ /* Do nothing for now */
+ break;
+ case EVENT_RING_OPCODE_MALICIOUS_VF:
+ DP(BNX2X_MSG_IOV, "got VF [%d] MALICIOUS notification\n",
+ vf->abs_vfid);
+ /* Do nothing for now */
+ break;
+ }
+ /* SRIOV: reschedule any 'in_progress' operations */
+ bnx2x_iov_sp_event(bp, cid, false);
+
+ return 0;
+}
+
+static struct bnx2x_virtf *bnx2x_vf_by_cid(struct bnx2x *bp, int vf_cid)
+{
+ /* extract the vf from vf_cid - relies on the following:
+ * 1. vfid on cid reflects the true abs_vfid
+ * 2. the max number of VFs (per path) is 64
+ */
+ int abs_vfid = (vf_cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
+ return bnx2x_vf_by_abs_fid(bp, abs_vfid);
+}
+
+void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
+ struct bnx2x_queue_sp_obj **q_obj)
+{
+ struct bnx2x_virtf *vf;
+
+ if (!IS_SRIOV(bp))
+ return;
+
+ vf = bnx2x_vf_by_cid(bp, vf_cid);
+
+ if (vf) {
+ /* extract queue index from vf_cid - relies on the following:
+ * 1. vfid on cid reflects the true abs_vfid
+ * 2. the max number of VFs (per path) is 64
+ */
+ int q_index = vf_cid & ((1 << BNX2X_VF_CID_WND)-1);
+ *q_obj = &bnx2x_vfq(vf, q_index, sp_obj);
+ } else {
+ BNX2X_ERR("No vf matching cid %d\n", vf_cid);
+ }
+}
+
+void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work)
+{
+ struct bnx2x_virtf *vf;
+
+ /* check if the cid is the VF range */
+ if (!IS_SRIOV(bp) || !bnx2x_iov_is_vf_cid(bp, vf_cid))
+ return;
+
+ vf = bnx2x_vf_by_cid(bp, vf_cid);
+ if (vf) {
+ /* set in_progress flag */
+ atomic_set(&vf->op_in_progress, 1);
+ if (queue_work)
+ queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+ }
+}
+
+void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
+{
+ int i;
+ int first_queue_query_index, num_queues_req;
+ dma_addr_t cur_data_offset;
+ struct stats_query_entry *cur_query_entry;
+ u8 stats_count = 0;
+ bool is_fcoe = false;
+
+ if (!IS_SRIOV(bp))
+ return;
+
+ if (!NO_FCOE(bp))
+ is_fcoe = true;
+
+ /* fcoe adds one global request and one queue request */
+ num_queues_req = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe;
+ first_queue_query_index = BNX2X_FIRST_QUEUE_QUERY_IDX -
+ (is_fcoe ? 0 : 1);
+
+ DP(BNX2X_MSG_IOV,
+ "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n",
+ BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index,
+ first_queue_query_index + num_queues_req);
+
+ cur_data_offset = bp->fw_stats_data_mapping +
+ offsetof(struct bnx2x_fw_stats_data, queue_stats) +
+ num_queues_req * sizeof(struct per_queue_stats);
+
+ cur_query_entry = &bp->fw_stats_req->
+ query[first_queue_query_index + num_queues_req];
+
+ for_each_vf(bp, i) {
+ int j;
+ struct bnx2x_virtf *vf = BP_VF(bp, i);
+
+ if (vf->state != VF_ENABLED) {
+ DP(BNX2X_MSG_IOV,
+ "vf %d not enabled so no stats for it\n",
+ vf->abs_vfid);
+ continue;
+ }
+
+ DP(BNX2X_MSG_IOV, "add addresses for vf %d\n", vf->abs_vfid);
+ for_each_vfq(vf, j) {
+ struct bnx2x_vf_queue *rxq = vfq_get(vf, j);
+
+ /* collect stats fro active queues only */
+ if (bnx2x_get_q_logical_state(bp, &rxq->sp_obj) ==
+ BNX2X_Q_LOGICAL_STATE_STOPPED)
+ continue;
+
+ /* create stats query entry for this queue */
+ cur_query_entry->kind = STATS_TYPE_QUEUE;
+ cur_query_entry->index = vfq_cl_id(vf, rxq);
+ cur_query_entry->funcID =
+ cpu_to_le16(FW_VF_HANDLE(vf->abs_vfid));
+ cur_query_entry->address.hi =
+ cpu_to_le32(U64_HI(vf->fw_stat_map));
+ cur_query_entry->address.lo =
+ cpu_to_le32(U64_LO(vf->fw_stat_map));
+ DP(BNX2X_MSG_IOV,
+ "added address %x %x for vf %d queue %d client %d\n",
+ cur_query_entry->address.hi,
+ cur_query_entry->address.lo, cur_query_entry->funcID,
+ j, cur_query_entry->index);
+ cur_query_entry++;
+ cur_data_offset += sizeof(struct per_queue_stats);
+ stats_count++;
+ }
+ }
+ bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
+}
+
+void bnx2x_iov_sp_task(struct bnx2x *bp)
+{
+ int i;
+
+ if (!IS_SRIOV(bp))
+ return;
+ /* Iterate over all VFs and invoke state transition for VFs with
+ * 'in-progress' slow-path operations
+ */
+ DP(BNX2X_MSG_IOV, "searching for pending vf operations\n");
+ for_each_vf(bp, i) {
+ struct bnx2x_virtf *vf = BP_VF(bp, i);
+
+ if (!list_empty(&vf->op_list_head) &&
+ atomic_read(&vf->op_in_progress)) {
+ DP(BNX2X_MSG_IOV, "running pending op for vf %d\n", i);
+ bnx2x_vfop_cur(bp, vf)->transition(bp, vf);
+ }
+ }
+}
+
+static inline
+struct bnx2x_virtf *__vf_from_stat_id(struct bnx2x *bp, u8 stat_id)
+{
+ int i;
+ struct bnx2x_virtf *vf = NULL;
+
+ for_each_vf(bp, i) {
+ vf = BP_VF(bp, i);
+ if (stat_id >= vf->igu_base_id &&
+ stat_id < vf->igu_base_id + vf_sb_count(vf))
+ break;
+ }
+ return vf;
+}
+
+/* VF API helpers */
+static void bnx2x_vf_qtbl_set_q(struct bnx2x *bp, u8 abs_vfid, u8 qid,
+ u8 enable)
+{
+ u32 reg = PXP_REG_HST_ZONE_PERMISSION_TABLE + qid * 4;
+ u32 val = enable ? (abs_vfid | (1 << 6)) : 0;
+
+ REG_WR(bp, reg, val);
+}
+
+static void bnx2x_vf_clr_qtbl(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ int i;
+
+ for_each_vfq(vf, i)
+ bnx2x_vf_qtbl_set_q(bp, vf->abs_vfid,
+ vfq_qzone_id(vf, vfq_get(vf, i)), false);
+}
+
+static void bnx2x_vf_igu_disable(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ u32 val;
+
+ /* clear the VF configuration - pretend */
+ bnx2x_pretend_func(bp, HW_VF_HANDLE(bp, vf->abs_vfid));
+ val = REG_RD(bp, IGU_REG_VF_CONFIGURATION);
+ val &= ~(IGU_VF_CONF_MSI_MSIX_EN | IGU_VF_CONF_SINGLE_ISR_EN |
+ IGU_VF_CONF_FUNC_EN | IGU_VF_CONF_PARENT_MASK);
+ REG_WR(bp, IGU_REG_VF_CONFIGURATION, val);
+ bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
+}
+
+u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ return min_t(u8, min_t(u8, vf_sb_count(vf), BNX2X_CIDS_PER_VF),
+ BNX2X_VF_MAX_QUEUES);
+}
+
+static
+int bnx2x_vf_chk_avail_resc(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct vf_pf_resc_request *req_resc)
+{
+ u8 rxq_cnt = vf_rxq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
+ u8 txq_cnt = vf_txq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
+
+ return ((req_resc->num_rxqs <= rxq_cnt) &&
+ (req_resc->num_txqs <= txq_cnt) &&
+ (req_resc->num_sbs <= vf_sb_count(vf)) &&
+ (req_resc->num_mac_filters <= vf_mac_rules_cnt(vf)) &&
+ (req_resc->num_vlan_filters <= vf_vlan_rules_cnt(vf)));
+}
+
+/* CORE VF API */
+int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct vf_pf_resc_request *resc)
+{
+ int base_vf_cid = (BP_VFDB(bp)->sriov.first_vf_in_pf + vf->index) *
+ BNX2X_CIDS_PER_VF;
+
+ union cdu_context *base_cxt = (union cdu_context *)
+ BP_VF_CXT_PAGE(bp, base_vf_cid/ILT_PAGE_CIDS)->addr +
+ (base_vf_cid & (ILT_PAGE_CIDS-1));
+ int i;
+
+ /* if state is 'acquired' the VF was not released or FLR'd, in
+ * this case the returned resources match the acquired already
+ * acquired resources. Verify that the requested numbers do
+ * not exceed the already acquired numbers.
+ */
+ if (vf->state == VF_ACQUIRED) {
+ DP(BNX2X_MSG_IOV, "VF[%d] Trying to re-acquire resources (VF was not released or FLR'd)\n",
+ vf->abs_vfid);
+
+ if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
+ BNX2X_ERR("VF[%d] When re-acquiring resources, requested numbers must be <= then previously acquired numbers\n",
+ vf->abs_vfid);
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ /* Otherwise vf state must be 'free' or 'reset' */
+ if (vf->state != VF_FREE && vf->state != VF_RESET) {
+ BNX2X_ERR("VF[%d] Can not acquire a VF with state %d\n",
+ vf->abs_vfid, vf->state);
+ return -EINVAL;
+ }
+
+ /* static allocation:
+ * the global maximum number are fixed per VF. fail the request if
+ * requested number exceed these globals
+ */
+ if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
+ DP(BNX2X_MSG_IOV,
+ "cannot fulfill vf resource request. Placing maximal available values in response\n");
+ /* set the max resource in the vf */
+ return -ENOMEM;
+ }
+
+ /* Set resources counters - 0 request means max available */
+ vf_sb_count(vf) = resc->num_sbs;
+ vf_rxq_count(vf) = resc->num_rxqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
+ vf_txq_count(vf) = resc->num_txqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
+ if (resc->num_mac_filters)
+ vf_mac_rules_cnt(vf) = resc->num_mac_filters;
+ if (resc->num_vlan_filters)
+ vf_vlan_rules_cnt(vf) = resc->num_vlan_filters;
+
+ DP(BNX2X_MSG_IOV,
+ "Fulfilling vf request: sb count %d, tx_count %d, rx_count %d, mac_rules_count %d, vlan_rules_count %d\n",
+ vf_sb_count(vf), vf_rxq_count(vf),
+ vf_txq_count(vf), vf_mac_rules_cnt(vf),
+ vf_vlan_rules_cnt(vf));
+
+ /* Initialize the queues */
+ if (!vf->vfqs) {
+ DP(BNX2X_MSG_IOV, "vf->vfqs was not allocated\n");
+ return -EINVAL;
+ }
+
+ for_each_vfq(vf, i) {
+ struct bnx2x_vf_queue *q = vfq_get(vf, i);
+
+ if (!q) {
+ DP(BNX2X_MSG_IOV, "q number %d was not allocated\n", i);
+ return -EINVAL;
+ }
+
+ q->index = i;
+ q->cxt = &((base_cxt + i)->eth);
+ q->cid = BNX2X_FIRST_VF_CID + base_vf_cid + i;
+
+ DP(BNX2X_MSG_IOV, "VFQ[%d:%d]: index %d, cid 0x%x, cxt %p\n",
+ vf->abs_vfid, i, q->index, q->cid, q->cxt);
+
+ /* init SP objects */
+ bnx2x_vfq_init(bp, vf, q);
+ }
+ vf->state = VF_ACQUIRED;
+ return 0;
+}
+
+int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf, dma_addr_t *sb_map)
+{
+ struct bnx2x_func_init_params func_init = {0};
+ u16 flags = 0;
+ int i;
+
+ /* the sb resources are initialized at this point, do the
+ * FW/HW initializations
+ */
+ for_each_vf_sb(vf, i)
+ bnx2x_init_sb(bp, (dma_addr_t)sb_map[i], vf->abs_vfid, true,
+ vf_igu_sb(vf, i), vf_igu_sb(vf, i));
+
+ /* Sanity checks */
+ if (vf->state != VF_ACQUIRED) {
+ DP(BNX2X_MSG_IOV, "VF[%d] is not in VF_ACQUIRED, but %d\n",
+ vf->abs_vfid, vf->state);
+ return -EINVAL;
+ }
+ /* FLR cleanup epilogue */
+ if (bnx2x_vf_flr_clnup_epilog(bp, vf->abs_vfid))
+ return -EBUSY;
+
+ /* reset IGU VF statistics: MSIX */
+ REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT + vf->abs_vfid * 4 , 0);
+
+ /* vf init */
+ if (vf->cfg_flags & VF_CFG_STATS)
+ flags |= (FUNC_FLG_STATS | FUNC_FLG_SPQ);
+
+ if (vf->cfg_flags & VF_CFG_TPA)
+ flags |= FUNC_FLG_TPA;
+
+ if (is_vf_multi(vf))
+ flags |= FUNC_FLG_RSS;
+
+ /* function setup */
+ func_init.func_flgs = flags;
+ func_init.pf_id = BP_FUNC(bp);
+ func_init.func_id = FW_VF_HANDLE(vf->abs_vfid);
+ func_init.fw_stat_map = vf->fw_stat_map;
+ func_init.spq_map = vf->spq_map;
+ func_init.spq_prod = 0;
+ bnx2x_func_init(bp, &func_init);
+
+ /* Enable the vf */
+ bnx2x_vf_enable_access(bp, vf->abs_vfid);
+ bnx2x_vf_enable_traffic(bp, vf);
+
+ /* queue protection table */
+ for_each_vfq(vf, i)
+ bnx2x_vf_qtbl_set_q(bp, vf->abs_vfid,
+ vfq_qzone_id(vf, vfq_get(vf, i)), true);
+
+ vf->state = VF_ENABLED;
+
+ /* update vf bulletin board */
+ bnx2x_post_vf_bulletin(bp, vf->index);
+
+ return 0;
+}
+
+/* VFOP close (teardown the queues, delete mcasts and close HW) */
+static void bnx2x_vfop_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ struct bnx2x_vfop_args_qx *qx = &vfop->args.qx;
+ enum bnx2x_vfop_close_state state = vfop->state;
+ struct bnx2x_vfop_cmd cmd = {
+ .done = bnx2x_vfop_close,
+ .block = false,
+ };
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+
+ switch (state) {
+ case BNX2X_VFOP_CLOSE_QUEUES:
+
+ if (++(qx->qid) < vf_rxq_count(vf)) {
+ vfop->rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qx->qid);
+ if (vfop->rc)
+ goto op_err;
+ return;
+ }
+
+ /* remove multicasts */
+ vfop->state = BNX2X_VFOP_CLOSE_HW;
+ vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL, 0, false);
+ if (vfop->rc)
+ goto op_err;
+ return;
+
+ case BNX2X_VFOP_CLOSE_HW:
+
+ /* disable the interrupts */
+ DP(BNX2X_MSG_IOV, "disabling igu\n");
+ bnx2x_vf_igu_disable(bp, vf);
+
+ /* disable the VF */
+ DP(BNX2X_MSG_IOV, "clearing qtbl\n");
+ bnx2x_vf_clr_qtbl(bp, vf);
+
+ goto op_done;
+ default:
+ bnx2x_vfop_default(state);
+ }
+op_err:
+ BNX2X_ERR("VF[%d] CLOSE error: rc %d\n", vf->abs_vfid, vfop->rc);
+op_done:
+ vf->state = VF_ACQUIRED;
+ DP(BNX2X_MSG_IOV, "set state to acquired\n");
+ bnx2x_vfop_end(bp, vf, vfop);
+}
+
+int bnx2x_vfop_close_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+ if (vfop) {
+ vfop->args.qx.qid = -1; /* loop */
+ bnx2x_vfop_opset(BNX2X_VFOP_CLOSE_QUEUES,
+ bnx2x_vfop_close, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_close,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+/* VF release can be called either: 1. the VF was acquired but
+ * not enabled 2. the vf was enabled or in the process of being
+ * enabled
+ */
+static void bnx2x_vfop_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ struct bnx2x_vfop_cmd cmd = {
+ .done = bnx2x_vfop_release,
+ .block = false,
+ };
+
+ DP(BNX2X_MSG_IOV, "vfop->rc %d\n", vfop->rc);
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ DP(BNX2X_MSG_IOV, "VF[%d] STATE: %s\n", vf->abs_vfid,
+ vf->state == VF_FREE ? "Free" :
+ vf->state == VF_ACQUIRED ? "Acquired" :
+ vf->state == VF_ENABLED ? "Enabled" :
+ vf->state == VF_RESET ? "Reset" :
+ "Unknown");
+
+ switch (vf->state) {
+ case VF_ENABLED:
+ vfop->rc = bnx2x_vfop_close_cmd(bp, vf, &cmd);
+ if (vfop->rc)
+ goto op_err;
+ return;
+
+ case VF_ACQUIRED:
+ DP(BNX2X_MSG_IOV, "about to free resources\n");
+ bnx2x_vf_free_resc(bp, vf);
+ DP(BNX2X_MSG_IOV, "vfop->rc %d\n", vfop->rc);
+ goto op_done;
+
+ case VF_FREE:
+ case VF_RESET:
+ /* do nothing */
+ goto op_done;
+ default:
+ bnx2x_vfop_default(vf->state);
+ }
+op_err:
+ BNX2X_ERR("VF[%d] RELEASE error: rc %d\n", vf->abs_vfid, vfop->rc);
+op_done:
+ bnx2x_vfop_end(bp, vf, vfop);
+}
+
+int bnx2x_vfop_release_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+ if (vfop) {
+ bnx2x_vfop_opset(-1, /* use vf->state */
+ bnx2x_vfop_release, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_release,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+/* VF release ~ VF close + VF release-resources
+ * Release is the ultimate SW shutdown and is called whenever an
+ * irrecoverable error is encountered.
+ */
+void bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf, bool block)
+{
+ struct bnx2x_vfop_cmd cmd = {
+ .done = NULL,
+ .block = block,
+ };
+ int rc;
+ bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
+
+ rc = bnx2x_vfop_release_cmd(bp, vf, &cmd);
+ if (rc)
+ WARN(rc,
+ "VF[%d] Failed to allocate resources for release op- rc=%d\n",
+ vf->abs_vfid, rc);
+}
+
+static inline void bnx2x_vf_get_sbdf(struct bnx2x *bp,
+ struct bnx2x_virtf *vf, u32 *sbdf)
+{
+ *sbdf = vf->devfn | (vf->bus << 8);
+}
+
+static inline void bnx2x_vf_get_bars(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_bar_info *bar_info)
+{
+ int n;
+
+ bar_info->nr_bars = bp->vfdb->sriov.nres;
+ for (n = 0; n < bar_info->nr_bars; n++)
+ bar_info->bars[n] = vf->bars[n];
+}
+
+void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ enum channel_tlvs tlv)
+{
+ /* lock the channel */
+ mutex_lock(&vf->op_mutex);
+
+ /* record the locking op */
+ vf->op_current = tlv;
+
+ /* log the lock */
+ DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel locked by %d\n",
+ vf->abs_vfid, tlv);
+}
+
+void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ enum channel_tlvs expected_tlv)
+{
+ WARN(expected_tlv != vf->op_current,
+ "lock mismatch: expected %d found %d", expected_tlv,
+ vf->op_current);
+
+ /* lock the channel */
+ mutex_unlock(&vf->op_mutex);
+
+ /* log the unlock */
+ DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel unlocked by %d\n",
+ vf->abs_vfid, vf->op_current);
+
+ /* record the locking op */
+ vf->op_current = CHANNEL_TLV_NONE;
+}
+
+void bnx2x_enable_sriov(struct bnx2x *bp)
+{
+ int rc = 0;
+
+ /* disbale sriov in case it is still enabled */
+ pci_disable_sriov(bp->pdev);
+ DP(BNX2X_MSG_IOV, "sriov disabled\n");
+
+ /* enable sriov */
+ DP(BNX2X_MSG_IOV, "vf num (%d)\n", (bp->vfdb->sriov.nr_virtfn));
+ rc = pci_enable_sriov(bp->pdev, (bp->vfdb->sriov.nr_virtfn));
+ if (rc)
+ BNX2X_ERR("pci_enable_sriov failed with %d\n", rc);
+ else
+ DP(BNX2X_MSG_IOV, "sriov enabled\n");
+}
+
+/* New mac for VF. Consider these cases:
+ * 1. VF hasn't been acquired yet - save the mac in local bulletin board and
+ * supply at acquire.
+ * 2. VF has already been acquired but has not yet initialized - store in local
+ * bulletin board. mac will be posted on VF bulletin board after VF init. VF
+ * will configure this mac when it is ready.
+ * 3. VF has already initialized but has not yet setup a queue - post the new
+ * mac on VF's bulletin board right now. VF will configure this mac when it
+ * is ready.
+ * 4. VF has already set a queue - delete any macs already configured for this
+ * queue and manually config the new mac.
+ * In any event, once this function has been called refuse any attempts by the
+ * VF to configure any mac for itself except for this mac. In case of a race
+ * where the VF fails to see the new post on its bulletin board before sending a
+ * mac configuration request, the PF will simply fail the request and VF can try
+ * again after consulting its bulletin board
+ */
+int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int rc, q_logical_state, vfidx = queue;
+ struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
+ struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+
+ /* if SRIOV is disabled there is nothing to do (and somewhere, someone
+ * has erred).
+ */
+ if (!IS_SRIOV(bp)) {
+ BNX2X_ERR("bnx2x_set_vf_mac called though sriov is disabled\n");
+ return -EINVAL;
+ }
+
+ if (!is_valid_ether_addr(mac)) {
+ BNX2X_ERR("mac address invalid\n");
+ return -EINVAL;
+ }
+
+ /* update PF's copy of the VF's bulletin. will no longer accept mac
+ * configuration requests from vf unless match this mac
+ */
+ bulletin->valid_bitmap |= 1 << MAC_ADDR_VALID;
+ memcpy(bulletin->mac, mac, ETH_ALEN);
+
+ /* Post update on VF's bulletin board */
+ rc = bnx2x_post_vf_bulletin(bp, vfidx);
+ if (rc) {
+ BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx);
+ return rc;
+ }
+
+ /* is vf initialized and queue set up? */
+ q_logical_state =
+ bnx2x_get_q_logical_state(bp, &bnx2x_vfq(vf, 0, sp_obj));
+ if (vf->state == VF_ENABLED &&
+ q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+ /* configure the mac in device on this vf's queue */
+ unsigned long flags = 0;
+ struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
+
+ /* must lock vfpf channel to protect against vf flows */
+ bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
+
+ /* remove existing eth macs */
+ rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true);
+ if (rc) {
+ BNX2X_ERR("failed to delete eth macs\n");
+ return -EINVAL;
+ }
+
+ /* remove existing uc list macs */
+ rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_UC_LIST_MAC, true);
+ if (rc) {
+ BNX2X_ERR("failed to delete uc_list macs\n");
+ return -EINVAL;
+ }
+
+ /* configure the new mac to device */
+ __set_bit(RAMROD_COMP_WAIT, &flags);
+ bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
+ BNX2X_ETH_MAC, &flags);
+
+ bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
+ }
+
+ return rc;
+}
+
+/* crc is the first field in the bulletin board. compute the crc over the
+ * entire bulletin board excluding the crc field itself
+ */
+u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
+ struct pf_vf_bulletin_content *bulletin)
+{
+ return crc32(BULLETIN_CRC_SEED,
+ ((u8 *)bulletin) + sizeof(bulletin->crc),
+ bulletin->length - sizeof(bulletin->crc));
+}
+
+/* Check for new posts on the bulletin board */
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
+{
+ struct pf_vf_bulletin_content bulletin = bp->pf2vf_bulletin->content;
+ int attempts;
+
+ /* bulletin board hasn't changed since last sample */
+ if (bp->old_bulletin.version == bulletin.version)
+ return PFVF_BULLETIN_UNCHANGED;
+
+ /* validate crc of new bulletin board */
+ if (bp->old_bulletin.version != bp->pf2vf_bulletin->content.version) {
+ /* sampling structure in mid post may result with corrupted data
+ * validate crc to ensure coherency.
+ */
+ for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
+ bulletin = bp->pf2vf_bulletin->content;
+ if (bulletin.crc == bnx2x_crc_vf_bulletin(bp,
+ &bulletin))
+ break;
+ BNX2X_ERR("bad crc on bulletin board. contained %x computed %x\n",
+ bulletin.crc,
+ bnx2x_crc_vf_bulletin(bp, &bulletin));
+ }
+ if (attempts >= BULLETIN_ATTEMPTS) {
+ BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n",
+ attempts);
+ return PFVF_BULLETIN_CRC_ERR;
+ }
+ }
+
+ /* the mac address in bulletin board is valid and is new */
+ if (bulletin.valid_bitmap & 1 << MAC_ADDR_VALID &&
+ memcmp(bulletin.mac, bp->old_bulletin.mac, ETH_ALEN)) {
+ /* update new mac to net device */
+ memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
+ }
+
+ /* copy new bulletin board to bp */
+ bp->old_bulletin = bulletin;
+
+ return PFVF_BULLETIN_UPDATED;
+}
+
+void bnx2x_vf_map_doorbells(struct bnx2x *bp)
+{
+ /* vf doorbells are embedded within the regview */
+ bp->doorbells = bp->regview + PXP_VF_ADDR_DB_START;
+}
+
+int bnx2x_vf_pci_alloc(struct bnx2x *bp)
+{
+ /* allocate vf2pf mailbox for vf to pf channel */
+ BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping,
+ sizeof(struct bnx2x_vf_mbx_msg));
+
+ /* allocate pf 2 vf bulletin board */
+ BNX2X_PCI_ALLOC(bp->pf2vf_bulletin, &bp->pf2vf_bulletin_mapping,
+ sizeof(union pf_vf_bulletin));
+
+ return 0;
+
+alloc_mem_err:
+ BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+ sizeof(struct bnx2x_vf_mbx_msg));
+ BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+ sizeof(union pf_vf_bulletin));
+ return -ENOMEM;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
new file mode 100644
index 000000000000..b4050173add9
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -0,0 +1,809 @@
+/* bnx2x_sriov.h: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Shmulik Ravid <shmulikr@broadcom.com>
+ * Ariel Elior <ariele@broadcom.com>
+ */
+#ifndef BNX2X_SRIOV_H
+#define BNX2X_SRIOV_H
+
+#include "bnx2x_vfpf.h"
+#include "bnx2x.h"
+
+enum sample_bulletin_result {
+ PFVF_BULLETIN_UNCHANGED,
+ PFVF_BULLETIN_UPDATED,
+ PFVF_BULLETIN_CRC_ERR
+};
+
+#ifdef CONFIG_BNX2X_SRIOV
+
+/* The bnx2x device structure holds vfdb structure described below.
+ * The VF array is indexed by the relative vfid.
+ */
+#define BNX2X_VF_MAX_QUEUES 16
+#define BNX2X_VF_MAX_TPA_AGG_QUEUES 8
+
+struct bnx2x_sriov {
+ u32 first_vf_in_pf;
+
+ /* standard SRIOV capability fields, mostly for debugging */
+ int pos; /* capability position */
+ int nres; /* number of resources */
+ u32 cap; /* SR-IOV Capabilities */
+ u16 ctrl; /* SR-IOV Control */
+ u16 total; /* total VFs associated with the PF */
+ u16 initial; /* initial VFs associated with the PF */
+ u16 nr_virtfn; /* number of VFs available */
+ u16 offset; /* first VF Routing ID offset */
+ u16 stride; /* following VF stride */
+ u32 pgsz; /* page size for BAR alignment */
+ u8 link; /* Function Dependency Link */
+};
+
+/* bars */
+struct bnx2x_vf_bar {
+ u64 bar;
+ u32 size;
+};
+
+struct bnx2x_vf_bar_info {
+ struct bnx2x_vf_bar bars[PCI_SRIOV_NUM_BARS];
+ u8 nr_bars;
+};
+
+/* vf queue (used both for rx or tx) */
+struct bnx2x_vf_queue {
+ struct eth_context *cxt;
+
+ /* MACs object */
+ struct bnx2x_vlan_mac_obj mac_obj;
+
+ /* VLANs object */
+ struct bnx2x_vlan_mac_obj vlan_obj;
+ atomic_t vlan_count; /* 0 means vlan-0 is set ~ untagged */
+
+ /* Queue Slow-path State object */
+ struct bnx2x_queue_sp_obj sp_obj;
+
+ u32 cid;
+ u16 index;
+ u16 sb_idx;
+};
+
+/* struct bnx2x_vfop_qctor_params - prepare queue construction parameters:
+ * q-init, q-setup and SB index
+ */
+struct bnx2x_vfop_qctor_params {
+ struct bnx2x_queue_state_params qstate;
+ struct bnx2x_queue_setup_params prep_qsetup;
+};
+
+/* VFOP parameters (one copy per VF) */
+union bnx2x_vfop_params {
+ struct bnx2x_vlan_mac_ramrod_params vlan_mac;
+ struct bnx2x_rx_mode_ramrod_params rx_mode;
+ struct bnx2x_mcast_ramrod_params mcast;
+ struct bnx2x_config_rss_params rss;
+ struct bnx2x_vfop_qctor_params qctor;
+};
+
+/* forward */
+struct bnx2x_virtf;
+
+/* VFOP definitions */
+typedef void (*vfop_handler_t)(struct bnx2x *bp, struct bnx2x_virtf *vf);
+
+struct bnx2x_vfop_cmd {
+ vfop_handler_t done;
+ bool block;
+};
+
+/* VFOP queue filters command additional arguments */
+struct bnx2x_vfop_filter {
+ struct list_head link;
+ int type;
+#define BNX2X_VFOP_FILTER_MAC 1
+#define BNX2X_VFOP_FILTER_VLAN 2
+
+ bool add;
+ u8 *mac;
+ u16 vid;
+};
+
+struct bnx2x_vfop_filters {
+ int add_cnt;
+ struct list_head head;
+ struct bnx2x_vfop_filter filters[];
+};
+
+/* transient list allocated, built and saved until its
+ * passed to the SP-VERBs layer.
+ */
+struct bnx2x_vfop_args_mcast {
+ int mc_num;
+ struct bnx2x_mcast_list_elem *mc;
+};
+
+struct bnx2x_vfop_args_qctor {
+ int qid;
+ u16 sb_idx;
+};
+
+struct bnx2x_vfop_args_qdtor {
+ int qid;
+ struct eth_context *cxt;
+};
+
+struct bnx2x_vfop_args_defvlan {
+ int qid;
+ bool enable;
+ u16 vid;
+ u8 prio;
+};
+
+struct bnx2x_vfop_args_qx {
+ int qid;
+ bool en_add;
+};
+
+struct bnx2x_vfop_args_filters {
+ struct bnx2x_vfop_filters *multi_filter;
+ atomic_t *credit; /* non NULL means 'don't consume credit' */
+};
+
+union bnx2x_vfop_args {
+ struct bnx2x_vfop_args_mcast mc_list;
+ struct bnx2x_vfop_args_qctor qctor;
+ struct bnx2x_vfop_args_qdtor qdtor;
+ struct bnx2x_vfop_args_defvlan defvlan;
+ struct bnx2x_vfop_args_qx qx;
+ struct bnx2x_vfop_args_filters filters;
+};
+
+struct bnx2x_vfop {
+ struct list_head link;
+ int rc; /* return code */
+ int state; /* next state */
+ union bnx2x_vfop_args args; /* extra arguments */
+ union bnx2x_vfop_params *op_p; /* ramrod params */
+
+ /* state machine callbacks */
+ vfop_handler_t transition;
+ vfop_handler_t done;
+};
+
+/* vf context */
+struct bnx2x_virtf {
+ u16 cfg_flags;
+#define VF_CFG_STATS 0x0001
+#define VF_CFG_FW_FC 0x0002
+#define VF_CFG_TPA 0x0004
+#define VF_CFG_INT_SIMD 0x0008
+#define VF_CACHE_LINE 0x0010
+
+ u8 state;
+#define VF_FREE 0 /* VF ready to be acquired holds no resc */
+#define VF_ACQUIRED 1 /* VF aquired, but not initalized */
+#define VF_ENABLED 2 /* VF Enabled */
+#define VF_RESET 3 /* VF FLR'd, pending cleanup */
+
+ /* non 0 during flr cleanup */
+ u8 flr_clnup_stage;
+#define VF_FLR_CLN 1 /* reclaim resources and do 'final cleanup'
+ * sans the end-wait
+ */
+#define VF_FLR_ACK 2 /* ACK flr notification */
+#define VF_FLR_EPILOG 3 /* wait for VF remnants to dissipate in the HW
+ * ~ final cleanup' end wait
+ */
+
+ /* dma */
+ dma_addr_t fw_stat_map; /* valid iff VF_CFG_STATS */
+ dma_addr_t spq_map;
+ dma_addr_t bulletin_map;
+
+ /* Allocated resources counters. Before the VF is acquired, the
+ * counters hold the following values:
+ *
+ * - xxq_count = 0 as the queues memory is not allocated yet.
+ *
+ * - sb_count = The number of status blocks configured for this VF in
+ * the IGU CAM. Initially read during probe.
+ *
+ * - xx_rules_count = The number of rules statically and equally
+ * allocated for each VF, during PF load.
+ */
+ struct vf_pf_resc_request alloc_resc;
+#define vf_rxq_count(vf) ((vf)->alloc_resc.num_rxqs)
+#define vf_txq_count(vf) ((vf)->alloc_resc.num_txqs)
+#define vf_sb_count(vf) ((vf)->alloc_resc.num_sbs)
+#define vf_mac_rules_cnt(vf) ((vf)->alloc_resc.num_mac_filters)
+#define vf_vlan_rules_cnt(vf) ((vf)->alloc_resc.num_vlan_filters)
+#define vf_mc_rules_cnt(vf) ((vf)->alloc_resc.num_mc_filters)
+
+ u8 sb_count; /* actual number of SBs */
+ u8 igu_base_id; /* base igu status block id */
+
+ struct bnx2x_vf_queue *vfqs;
+#define bnx2x_vfq(vf, nr, var) ((vf)->vfqs[(nr)].var)
+
+ u8 index; /* index in the vf array */
+ u8 abs_vfid;
+ u8 sp_cl_id;
+ u32 error; /* 0 means all's-well */
+
+ /* BDF */
+ unsigned int bus;
+ unsigned int devfn;
+
+ /* bars */
+ struct bnx2x_vf_bar bars[PCI_SRIOV_NUM_BARS];
+
+ /* set-mac ramrod state 1-pending, 0-done */
+ unsigned long filter_state;
+
+ /* leading rss client id ~~ the client id of the first rxq, must be
+ * set for each txq.
+ */
+ int leading_rss;
+
+ /* MCAST object */
+ struct bnx2x_mcast_obj mcast_obj;
+
+ /* RSS configuration object */
+ struct bnx2x_rss_config_obj rss_conf_obj;
+
+ /* slow-path operations */
+ atomic_t op_in_progress;
+ int op_rc;
+ bool op_wait_blocking;
+ struct list_head op_list_head;
+ union bnx2x_vfop_params op_params;
+ struct mutex op_mutex; /* one vfop at a time mutex */
+ enum channel_tlvs op_current;
+};
+
+#define BNX2X_NR_VIRTFN(bp) ((bp)->vfdb->sriov.nr_virtfn)
+
+#define for_each_vf(bp, var) \
+ for ((var) = 0; (var) < BNX2X_NR_VIRTFN(bp); (var)++)
+
+#define for_each_vfq(vf, var) \
+ for ((var) = 0; (var) < vf_rxq_count(vf); (var)++)
+
+#define for_each_vf_sb(vf, var) \
+ for ((var) = 0; (var) < vf_sb_count(vf); (var)++)
+
+#define is_vf_multi(vf) (vf_rxq_count(vf) > 1)
+
+#define HW_VF_HANDLE(bp, abs_vfid) \
+ (u16)(BP_ABS_FUNC((bp)) | (1<<3) | ((u16)(abs_vfid) << 4))
+
+#define FW_PF_MAX_HANDLE 8
+
+#define FW_VF_HANDLE(abs_vfid) \
+ (abs_vfid + FW_PF_MAX_HANDLE)
+
+/* locking and unlocking the channel mutex */
+void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ enum channel_tlvs tlv);
+
+void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ enum channel_tlvs expected_tlv);
+
+/* VF mail box (aka vf-pf channel) */
+
+/* a container for the bi-directional vf<-->pf messages.
+ * The actual response will be placed according to the offset parameter
+ * provided in the request
+ */
+
+#define MBX_MSG_ALIGN 8
+#define MBX_MSG_ALIGNED_SIZE (roundup(sizeof(struct bnx2x_vf_mbx_msg), \
+ MBX_MSG_ALIGN))
+
+struct bnx2x_vf_mbx_msg {
+ union vfpf_tlvs req;
+ union pfvf_tlvs resp;
+};
+
+struct bnx2x_vf_mbx {
+ struct bnx2x_vf_mbx_msg *msg;
+ dma_addr_t msg_mapping;
+
+ /* VF GPA address */
+ u32 vf_addr_lo;
+ u32 vf_addr_hi;
+
+ struct vfpf_first_tlv first_tlv; /* saved VF request header */
+
+ u8 flags;
+#define VF_MSG_INPROCESS 0x1 /* failsafe - the FW should prevent
+ * more then one pending msg
+ */
+};
+
+struct bnx2x_vf_sp {
+ union {
+ struct eth_classify_rules_ramrod_data e2;
+ } mac_rdata;
+
+ union {
+ struct eth_classify_rules_ramrod_data e2;
+ } vlan_rdata;
+
+ union {
+ struct eth_filter_rules_ramrod_data e2;
+ } rx_mode_rdata;
+
+ union {
+ struct eth_multicast_rules_ramrod_data e2;
+ } mcast_rdata;
+
+ union {
+ struct client_init_ramrod_data init_data;
+ struct client_update_ramrod_data update_data;
+ } q_data;
+};
+
+struct hw_dma {
+ void *addr;
+ dma_addr_t mapping;
+ size_t size;
+};
+
+struct bnx2x_vfdb {
+#define BP_VFDB(bp) ((bp)->vfdb)
+ /* vf array */
+ struct bnx2x_virtf *vfs;
+#define BP_VF(bp, idx) (&((bp)->vfdb->vfs[(idx)]))
+#define bnx2x_vf(bp, idx, var) ((bp)->vfdb->vfs[(idx)].var)
+
+ /* queue array - for all vfs */
+ struct bnx2x_vf_queue *vfqs;
+
+ /* vf HW contexts */
+ struct hw_dma context[BNX2X_VF_CIDS/ILT_PAGE_CIDS];
+#define BP_VF_CXT_PAGE(bp, i) (&(bp)->vfdb->context[(i)])
+
+ /* SR-IOV information */
+ struct bnx2x_sriov sriov;
+ struct hw_dma mbx_dma;
+#define BP_VF_MBX_DMA(bp) (&((bp)->vfdb->mbx_dma))
+ struct bnx2x_vf_mbx mbxs[BNX2X_MAX_NUM_OF_VFS];
+#define BP_VF_MBX(bp, vfid) (&((bp)->vfdb->mbxs[(vfid)]))
+
+ struct hw_dma bulletin_dma;
+#define BP_VF_BULLETIN_DMA(bp) (&((bp)->vfdb->bulletin_dma))
+#define BP_VF_BULLETIN(bp, vf) \
+ (((struct pf_vf_bulletin_content *)(BP_VF_BULLETIN_DMA(bp)->addr)) \
+ + (vf))
+
+ struct hw_dma sp_dma;
+#define bnx2x_vf_sp(bp, vf, field) ((bp)->vfdb->sp_dma.addr + \
+ (vf)->index * sizeof(struct bnx2x_vf_sp) + \
+ offsetof(struct bnx2x_vf_sp, field))
+#define bnx2x_vf_sp_map(bp, vf, field) ((bp)->vfdb->sp_dma.mapping + \
+ (vf)->index * sizeof(struct bnx2x_vf_sp) + \
+ offsetof(struct bnx2x_vf_sp, field))
+
+#define FLRD_VFS_DWORDS (BNX2X_MAX_NUM_OF_VFS / 32)
+ u32 flrd_vfs[FLRD_VFS_DWORDS];
+};
+
+/* queue access */
+static inline struct bnx2x_vf_queue *vfq_get(struct bnx2x_virtf *vf, u8 index)
+{
+ return &(vf->vfqs[index]);
+}
+
+static inline bool vfq_is_leading(struct bnx2x_vf_queue *vfq)
+{
+ return (vfq->index == 0);
+}
+
+/* FW ids */
+static inline u8 vf_igu_sb(struct bnx2x_virtf *vf, u16 sb_idx)
+{
+ return vf->igu_base_id + sb_idx;
+}
+
+static inline u8 vf_hc_qzone(struct bnx2x_virtf *vf, u16 sb_idx)
+{
+ return vf_igu_sb(vf, sb_idx);
+}
+
+static u8 vfq_cl_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
+{
+ return vf->igu_base_id + q->index;
+}
+
+static inline u8 vfq_stat_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
+{
+ return vfq_cl_id(vf, q);
+}
+
+static inline u8 vfq_qzone_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
+{
+ return vfq_cl_id(vf, q);
+}
+
+/* global iov routines */
+int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line);
+int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, int num_vfs_param);
+void bnx2x_iov_remove_one(struct bnx2x *bp);
+void bnx2x_iov_free_mem(struct bnx2x *bp);
+int bnx2x_iov_alloc_mem(struct bnx2x *bp);
+int bnx2x_iov_nic_init(struct bnx2x *bp);
+int bnx2x_iov_chip_cleanup(struct bnx2x *bp);
+void bnx2x_iov_init_dq(struct bnx2x *bp);
+void bnx2x_iov_init_dmae(struct bnx2x *bp);
+void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
+ struct bnx2x_queue_sp_obj **q_obj);
+void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work);
+int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem);
+void bnx2x_iov_adjust_stats_req(struct bnx2x *bp);
+void bnx2x_iov_storm_stats_update(struct bnx2x *bp);
+void bnx2x_iov_sp_task(struct bnx2x *bp);
+/* global vf mailbox routines */
+void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event);
+void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid);
+
+/* CORE VF API */
+typedef u8 bnx2x_mac_addr_t[ETH_ALEN];
+
+/* acquire */
+int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct vf_pf_resc_request *resc);
+/* init */
+int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ dma_addr_t *sb_map);
+
+/* VFOP generic helpers */
+#define bnx2x_vfop_default(state) do { \
+ BNX2X_ERR("Bad state %d\n", (state)); \
+ vfop->rc = -EINVAL; \
+ goto op_err; \
+ } while (0)
+
+enum {
+ VFOP_DONE,
+ VFOP_CONT,
+ VFOP_VERIFY_PEND,
+};
+
+#define bnx2x_vfop_finalize(vf, rc, next) do { \
+ if ((rc) < 0) \
+ goto op_err; \
+ else if ((rc) > 0) \
+ goto op_pending; \
+ else if ((next) == VFOP_DONE) \
+ goto op_done; \
+ else if ((next) == VFOP_VERIFY_PEND) \
+ BNX2X_ERR("expected pending\n"); \
+ else { \
+ DP(BNX2X_MSG_IOV, "no ramrod. scheduling\n"); \
+ atomic_set(&vf->op_in_progress, 1); \
+ queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); \
+ return; \
+ } \
+ } while (0)
+
+#define bnx2x_vfop_opset(first_state, trans_hndlr, done_hndlr) \
+ do { \
+ vfop->state = first_state; \
+ vfop->op_p = &vf->op_params; \
+ vfop->transition = trans_hndlr; \
+ vfop->done = done_hndlr; \
+ } while (0)
+
+static inline struct bnx2x_vfop *bnx2x_vfop_cur(struct bnx2x *bp,
+ struct bnx2x_virtf *vf)
+{
+ WARN(!mutex_is_locked(&vf->op_mutex), "about to access vf op linked list but mutex was not locked!");
+ WARN_ON(list_empty(&vf->op_list_head));
+ return list_first_entry(&vf->op_list_head, struct bnx2x_vfop, link);
+}
+
+static inline struct bnx2x_vfop *bnx2x_vfop_add(struct bnx2x *bp,
+ struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vfop *vfop = kzalloc(sizeof(*vfop), GFP_KERNEL);
+
+ WARN(!mutex_is_locked(&vf->op_mutex), "about to access vf op linked list but mutex was not locked!");
+ if (vfop) {
+ INIT_LIST_HEAD(&vfop->link);
+ list_add(&vfop->link, &vf->op_list_head);
+ }
+ return vfop;
+}
+
+static inline void bnx2x_vfop_end(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vfop *vfop)
+{
+ /* rc < 0 - error, otherwise set to 0 */
+ DP(BNX2X_MSG_IOV, "rc was %d\n", vfop->rc);
+ if (vfop->rc >= 0)
+ vfop->rc = 0;
+ DP(BNX2X_MSG_IOV, "rc is now %d\n", vfop->rc);
+
+ /* unlink the current op context and propagate error code
+ * must be done before invoking the 'done()' handler
+ */
+ WARN(!mutex_is_locked(&vf->op_mutex),
+ "about to access vf op linked list but mutex was not locked!");
+ list_del(&vfop->link);
+
+ if (list_empty(&vf->op_list_head)) {
+ DP(BNX2X_MSG_IOV, "list was empty %d\n", vfop->rc);
+ vf->op_rc = vfop->rc;
+ DP(BNX2X_MSG_IOV, "copying rc vf->op_rc %d, vfop->rc %d\n",
+ vf->op_rc, vfop->rc);
+ } else {
+ struct bnx2x_vfop *cur_vfop;
+
+ DP(BNX2X_MSG_IOV, "list not empty %d\n", vfop->rc);
+ cur_vfop = bnx2x_vfop_cur(bp, vf);
+ cur_vfop->rc = vfop->rc;
+ DP(BNX2X_MSG_IOV, "copying rc vf->op_rc %d, vfop->rc %d\n",
+ vf->op_rc, vfop->rc);
+ }
+
+ /* invoke done handler */
+ if (vfop->done) {
+ DP(BNX2X_MSG_IOV, "calling done handler\n");
+ vfop->done(bp, vf);
+ } else {
+ /* there is no done handler for the operation to unlock
+ * the mutex. Must have gotten here from PF initiated VF RELEASE
+ */
+ bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
+ }
+
+ DP(BNX2X_MSG_IOV, "done handler complete. vf->op_rc %d, vfop->rc %d\n",
+ vf->op_rc, vfop->rc);
+
+ /* if this is the last nested op reset the wait_blocking flag
+ * to release any blocking wrappers, only after 'done()' is invoked
+ */
+ if (list_empty(&vf->op_list_head)) {
+ DP(BNX2X_MSG_IOV, "list was empty after done %d\n", vfop->rc);
+ vf->op_wait_blocking = false;
+ }
+
+ kfree(vfop);
+}
+
+static inline int bnx2x_vfop_wait_blocking(struct bnx2x *bp,
+ struct bnx2x_virtf *vf)
+{
+ /* can take a while if any port is running */
+ int cnt = 5000;
+
+ might_sleep();
+ while (cnt--) {
+ if (vf->op_wait_blocking == false) {
+#ifdef BNX2X_STOP_ON_ERROR
+ DP(BNX2X_MSG_IOV, "exit (cnt %d)\n", 5000 - cnt);
+#endif
+ return 0;
+ }
+ usleep_range(1000, 2000);
+
+ if (bp->panic)
+ return -EIO;
+ }
+
+ /* timeout! */
+#ifdef BNX2X_STOP_ON_ERROR
+ bnx2x_panic();
+#endif
+
+ return -EBUSY;
+}
+
+static inline int bnx2x_vfop_transition(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ vfop_handler_t transition,
+ bool block)
+{
+ if (block)
+ vf->op_wait_blocking = true;
+ transition(bp, vf);
+ if (block)
+ return bnx2x_vfop_wait_blocking(bp, vf);
+ return 0;
+}
+
+/* VFOP queue construction helpers */
+void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_queue_init_params *init_params,
+ struct bnx2x_queue_setup_params *setup_params,
+ u16 q_idx, u16 sb_idx);
+
+void bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_queue_init_params *init_params,
+ struct bnx2x_queue_setup_params *setup_params,
+ u16 q_idx, u16 sb_idx);
+
+void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vf_queue *q,
+ struct bnx2x_vfop_qctor_params *p,
+ unsigned long q_type);
+int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ struct bnx2x_vfop_filters *macs,
+ int qid, bool drv_only);
+
+int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid, u16 vid, bool add);
+
+int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ struct bnx2x_vfop_filters *vlans,
+ int qid, bool drv_only);
+
+int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid);
+
+int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid);
+
+int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ bnx2x_mac_addr_t *mcasts,
+ int mcast_num, bool drv_only);
+
+int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd,
+ int qid, unsigned long accept_flags);
+
+int bnx2x_vfop_close_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd);
+
+int bnx2x_vfop_release_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd);
+
+/* VF release ~ VF close + VF release-resources
+ *
+ * Release is the ultimate SW shutdown and is called whenever an
+ * irrecoverable error is encountered.
+ */
+void bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf, bool block);
+int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid);
+u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf);
+
+/* FLR routines */
+
+/* VF FLR helpers */
+int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid);
+void bnx2x_vf_enable_access(struct bnx2x *bp, u8 abs_vfid);
+
+/* Handles an FLR (or VF_DISABLE) notification form the MCP */
+void bnx2x_vf_handle_flr_event(struct bnx2x *bp);
+
+void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
+ u16 length);
+void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
+ u16 type, u16 length);
+void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list);
+
+bool bnx2x_tlv_supported(u16 tlvtype);
+
+u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
+ struct pf_vf_bulletin_content *bulletin);
+int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf);
+
+
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
+
+/* VF side vfpf channel functions */
+int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count);
+int bnx2x_vfpf_release(struct bnx2x *bp);
+int bnx2x_vfpf_release(struct bnx2x *bp);
+int bnx2x_vfpf_init(struct bnx2x *bp);
+void bnx2x_vfpf_close_vf(struct bnx2x *bp);
+int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx);
+int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx);
+int bnx2x_vfpf_set_mac(struct bnx2x *bp);
+int bnx2x_vfpf_set_mcast(struct net_device *dev);
+int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp);
+
+static inline void bnx2x_vf_fill_fw_str(struct bnx2x *bp, char *buf,
+ size_t buf_len)
+{
+ strlcpy(buf, bp->acquire_resp.pfdev_info.fw_ver, buf_len);
+}
+
+static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp)
+{
+ return PXP_VF_ADDR_USDM_QUEUES_START +
+ bp->acquire_resp.resc.hw_qid[fp->index] *
+ sizeof(struct ustorm_queue_zone_data);
+}
+
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
+void bnx2x_vf_map_doorbells(struct bnx2x *bp);
+int bnx2x_vf_pci_alloc(struct bnx2x *bp);
+void bnx2x_enable_sriov(struct bnx2x *bp);
+static inline int bnx2x_vf_headroom(struct bnx2x *bp)
+{
+ return bp->vfdb->sriov.nr_virtfn * BNX2X_CLIENTS_PER_VF;
+}
+
+#else /* CONFIG_BNX2X_SRIOV */
+
+static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
+ struct bnx2x_queue_sp_obj **q_obj) {}
+static inline void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid,
+ bool queue_work) {}
+static inline void bnx2x_vf_handle_flr_event(struct bnx2x *bp) {}
+static inline int bnx2x_iov_eq_sp_event(struct bnx2x *bp,
+ union event_ring_elem *elem) {return 1; }
+static inline void bnx2x_iov_sp_task(struct bnx2x *bp) {}
+static inline void bnx2x_vf_mbx(struct bnx2x *bp,
+ struct vf_pf_event_data *vfpf_event) {}
+static inline int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line) {return line; }
+static inline void bnx2x_iov_init_dq(struct bnx2x *bp) {}
+static inline int bnx2x_iov_alloc_mem(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_free_mem(struct bnx2x *bp) {}
+static inline int bnx2x_iov_chip_cleanup(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_init_dmae(struct bnx2x *bp) {}
+static inline int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
+ int num_vfs_param) {return 0; }
+static inline void bnx2x_iov_remove_one(struct bnx2x *bp) {}
+static inline void bnx2x_enable_sriov(struct bnx2x *bp) {}
+static inline int bnx2x_vfpf_acquire(struct bnx2x *bp,
+ u8 tx_count, u8 rx_count) {return 0; }
+static inline int bnx2x_vfpf_release(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vfpf_init(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_vfpf_close_vf(struct bnx2x *bp) {}
+static inline int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx) {return 0; }
+static inline int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) {return 0; }
+static inline int bnx2x_vfpf_set_mac(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vfpf_set_mcast(struct net_device *dev) {return 0; }
+static inline int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_iov_nic_init(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vf_headroom(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_adjust_stats_req(struct bnx2x *bp) {}
+static inline void bnx2x_vf_fill_fw_str(struct bnx2x *bp, char *buf,
+ size_t buf_len) {}
+static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp) {return 0; }
+static inline enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
+{
+ return PFVF_BULLETIN_UNCHANGED;
+}
+
+static inline int bnx2x_vf_map_doorbells(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vf_pci_alloc(struct bnx2x *bp) {return 0; }
+
+#endif /* CONFIG_BNX2X_SRIOV */
+#endif /* bnx2x_sriov.h */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 89ec0667140a..4397f8b76f2e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -1,6 +1,6 @@
/* bnx2x_stats.c: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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
@@ -19,7 +19,7 @@
#include "bnx2x_stats.h"
#include "bnx2x_cmn.h"
-
+#include "bnx2x_sriov.h"
/* Statistics */
@@ -79,6 +79,42 @@ static inline u16 bnx2x_get_port_stats_dma_len(struct bnx2x *bp)
* Init service functions
*/
+static void bnx2x_dp_stats(struct bnx2x *bp)
+{
+ int i;
+
+ DP(BNX2X_MSG_STATS, "dumping stats:\n"
+ "fw_stats_req\n"
+ " hdr\n"
+ " cmd_num %d\n"
+ " reserved0 %d\n"
+ " drv_stats_counter %d\n"
+ " reserved1 %d\n"
+ " stats_counters_addrs %x %x\n",
+ bp->fw_stats_req->hdr.cmd_num,
+ bp->fw_stats_req->hdr.reserved0,
+ bp->fw_stats_req->hdr.drv_stats_counter,
+ bp->fw_stats_req->hdr.reserved1,
+ bp->fw_stats_req->hdr.stats_counters_addrs.hi,
+ bp->fw_stats_req->hdr.stats_counters_addrs.lo);
+
+ for (i = 0; i < bp->fw_stats_req->hdr.cmd_num; i++) {
+ DP(BNX2X_MSG_STATS,
+ "query[%d]\n"
+ " kind %d\n"
+ " index %d\n"
+ " funcID %d\n"
+ " reserved %d\n"
+ " address %x %x\n",
+ i, bp->fw_stats_req->query[i].kind,
+ bp->fw_stats_req->query[i].index,
+ bp->fw_stats_req->query[i].funcID,
+ bp->fw_stats_req->query[i].reserved,
+ bp->fw_stats_req->query[i].address.hi,
+ bp->fw_stats_req->query[i].address.lo);
+ }
+}
+
/* Post the next statistics ramrod. Protect it with the spin in
* order to ensure the strict order between statistics ramrods
* (each ramrod has a sequence number passed in a
@@ -103,7 +139,9 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
bp->fw_stats_req->hdr.drv_stats_counter);
-
+ /* adjust the ramrod to include VF queues statistics */
+ bnx2x_iov_adjust_stats_req(bp);
+ bnx2x_dp_stats(bp);
/* send FW stats ramrod */
rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0,
@@ -174,7 +212,7 @@ static int bnx2x_stats_comp(struct bnx2x *bp)
break;
}
cnt--;
- usleep_range(1000, 1000);
+ usleep_range(1000, 2000);
}
return 1;
}
@@ -482,6 +520,12 @@ static void bnx2x_func_stats_init(struct bnx2x *bp)
static void bnx2x_stats_start(struct bnx2x *bp)
{
+ /* vfs travel through here as part of the statistics FSM, but no action
+ * is required
+ */
+ if (IS_VF(bp))
+ return;
+
if (bp->port.pmf)
bnx2x_port_stats_init(bp);
@@ -501,6 +545,11 @@ static void bnx2x_stats_pmf_start(struct bnx2x *bp)
static void bnx2x_stats_restart(struct bnx2x *bp)
{
+ /* vfs travel through here as part of the statistics FSM, but no action
+ * is required
+ */
+ if (IS_VF(bp))
+ return;
bnx2x_stats_comp(bp);
bnx2x_stats_start(bp);
}
@@ -832,19 +881,10 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
return 0;
}
-static int bnx2x_storm_stats_update(struct bnx2x *bp)
+static int bnx2x_storm_stats_validate_counters(struct bnx2x *bp)
{
- struct tstorm_per_port_stats *tport =
- &bp->fw_stats_data->port.tstorm_port_statistics;
- struct tstorm_per_pf_stats *tfunc =
- &bp->fw_stats_data->pf.tstorm_pf_statistics;
- struct host_func_stats *fstats = &bp->func_stats;
- struct bnx2x_eth_stats *estats = &bp->eth_stats;
- struct bnx2x_eth_stats_old *estats_old = &bp->eth_stats_old;
struct stats_counter *counters = &bp->fw_stats_data->storm_counters;
- int i;
u16 cur_stats_counter;
-
/* Make sure we use the value of the counter
* used for sending the last stats ramrod.
*/
@@ -880,6 +920,23 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
le16_to_cpu(counters->tstats_counter), bp->stats_counter);
return -EAGAIN;
}
+ return 0;
+}
+
+static int bnx2x_storm_stats_update(struct bnx2x *bp)
+{
+ struct tstorm_per_port_stats *tport =
+ &bp->fw_stats_data->port.tstorm_port_statistics;
+ struct tstorm_per_pf_stats *tfunc =
+ &bp->fw_stats_data->pf.tstorm_pf_statistics;
+ struct host_func_stats *fstats = &bp->func_stats;
+ struct bnx2x_eth_stats *estats = &bp->eth_stats;
+ struct bnx2x_eth_stats_old *estats_old = &bp->eth_stats_old;
+ int i;
+
+ /* vfs stat counter is managed by pf */
+ if (IS_PF(bp) && bnx2x_storm_stats_validate_counters(bp))
+ return -EAGAIN;
estats->error_bytes_received_hi = 0;
estats->error_bytes_received_lo = 0;
@@ -953,8 +1010,8 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
UPDATE_EXTEND_TSTAT(rcv_bcast_pkts,
total_broadcast_packets_received);
UPDATE_EXTEND_E_TSTAT(pkts_too_big_discard,
- etherstatsoverrsizepkts);
- UPDATE_EXTEND_E_TSTAT(no_buff_discard, no_buff_discard);
+ etherstatsoverrsizepkts, 32);
+ UPDATE_EXTEND_E_TSTAT(no_buff_discard, no_buff_discard, 16);
SUB_EXTEND_USTAT(ucast_no_buff_pkts,
total_unicast_packets_received);
@@ -1033,15 +1090,15 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
estats->total_bytes_received_lo,
estats->rx_stat_ifhcinbadoctets_lo);
- ADD_64(estats->total_bytes_received_hi,
- le32_to_cpu(tfunc->rcv_error_bytes.hi),
- estats->total_bytes_received_lo,
- le32_to_cpu(tfunc->rcv_error_bytes.lo));
+ ADD_64_LE(estats->total_bytes_received_hi,
+ tfunc->rcv_error_bytes.hi,
+ estats->total_bytes_received_lo,
+ tfunc->rcv_error_bytes.lo);
- ADD_64(estats->error_bytes_received_hi,
- le32_to_cpu(tfunc->rcv_error_bytes.hi),
- estats->error_bytes_received_lo,
- le32_to_cpu(tfunc->rcv_error_bytes.lo));
+ ADD_64_LE(estats->error_bytes_received_hi,
+ tfunc->rcv_error_bytes.hi,
+ estats->error_bytes_received_lo,
+ tfunc->rcv_error_bytes.lo);
UPDATE_ESTAT(etherstatsoverrsizepkts, rx_stat_dot3statsframestoolong);
@@ -1174,23 +1231,34 @@ static void bnx2x_stats_update(struct bnx2x *bp)
if (bnx2x_edebug_stats_stopped(bp))
return;
- if (*stats_comp != DMAE_COMP_VAL)
- return;
+ if (IS_PF(bp)) {
+ if (*stats_comp != DMAE_COMP_VAL)
+ return;
- if (bp->port.pmf)
- bnx2x_hw_stats_update(bp);
+ if (bp->port.pmf)
+ bnx2x_hw_stats_update(bp);
- if (bnx2x_storm_stats_update(bp)) {
- if (bp->stats_pending++ == 3) {
- BNX2X_ERR("storm stats were not updated for 3 times\n");
- bnx2x_panic();
+ if (bnx2x_storm_stats_update(bp)) {
+ if (bp->stats_pending++ == 3) {
+ BNX2X_ERR("storm stats were not updated for 3 times\n");
+ bnx2x_panic();
+ }
+ return;
}
- return;
+ } else {
+ /* vf doesn't collect HW statistics, and doesn't get completions
+ * perform only update
+ */
+ bnx2x_storm_stats_update(bp);
}
bnx2x_net_stats_update(bp);
bnx2x_drv_stats_update(bp);
+ /* vf is done */
+ if (IS_VF(bp))
+ return;
+
if (netif_msg_timer(bp)) {
struct bnx2x_eth_stats *estats = &bp->eth_stats;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
index b4d7b26c7fe7..364e37ecbc5c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
@@ -1,6 +1,6 @@
/* bnx2x_stats.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 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
@@ -421,16 +421,19 @@ struct bnx2x_fw_port_stats_old {
new->s); \
} while (0)
-#define UPDATE_EXTEND_TSTAT(s, t) \
+#define UPDATE_EXTEND_TSTAT_X(s, t, size) \
do { \
- diff = le32_to_cpu(tclient->s) - le32_to_cpu(old_tclient->s); \
+ diff = le##size##_to_cpu(tclient->s) - \
+ le##size##_to_cpu(old_tclient->s); \
old_tclient->s = tclient->s; \
ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
} while (0)
-#define UPDATE_EXTEND_E_TSTAT(s, t) \
+#define UPDATE_EXTEND_TSTAT(s, t) UPDATE_EXTEND_TSTAT_X(s, t, 32)
+
+#define UPDATE_EXTEND_E_TSTAT(s, t, size) \
do { \
- UPDATE_EXTEND_TSTAT(s, t); \
+ UPDATE_EXTEND_TSTAT_X(s, t, size); \
ADD_EXTEND_64(estats->t##_hi, estats->t##_lo, diff); \
} while (0)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
new file mode 100644
index 000000000000..36246129864c
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -0,0 +1,1651 @@
+/* bnx2x_vfpf.c: Broadcom Everest network driver.
+ *
+ * Copyright 2009-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Shmulik Ravid <shmulikr@broadcom.com>
+ * Ariel Elior <ariele@broadcom.com>
+ */
+
+#include "bnx2x.h"
+#include "bnx2x_cmn.h"
+#include <linux/crc32.h>
+
+/* place a given tlv on the tlv buffer at a given offset */
+void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
+ u16 length)
+{
+ struct channel_tlv *tl =
+ (struct channel_tlv *)(tlvs_list + offset);
+
+ tl->type = type;
+ tl->length = length;
+}
+
+/* Clear the mailbox and init the header of the first tlv */
+void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
+ u16 type, u16 length)
+{
+ DP(BNX2X_MSG_IOV, "preparing to send %d tlv over vf pf channel\n",
+ type);
+
+ /* Clear mailbox */
+ memset(bp->vf2pf_mbox, 0, sizeof(struct bnx2x_vf_mbx_msg));
+
+ /* init type and length */
+ bnx2x_add_tlv(bp, &first_tlv->tl, 0, type, length);
+
+ /* init first tlv header */
+ first_tlv->resp_msg_offset = sizeof(bp->vf2pf_mbox->req);
+}
+
+/* list the types and lengths of the tlvs on the buffer */
+void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list)
+{
+ int i = 1;
+ struct channel_tlv *tlv = (struct channel_tlv *)tlvs_list;
+
+ while (tlv->type != CHANNEL_TLV_LIST_END) {
+ /* output tlv */
+ DP(BNX2X_MSG_IOV, "TLV number %d: type %d, length %d\n", i,
+ tlv->type, tlv->length);
+
+ /* advance to next tlv */
+ tlvs_list += tlv->length;
+
+ /* cast general tlv list pointer to channel tlv header*/
+ tlv = (struct channel_tlv *)tlvs_list;
+
+ i++;
+
+ /* break condition for this loop */
+ if (i > MAX_TLVS_IN_LIST) {
+ WARN(true, "corrupt tlvs");
+ return;
+ }
+ }
+
+ /* output last tlv */
+ DP(BNX2X_MSG_IOV, "TLV number %d: type %d, length %d\n", i,
+ tlv->type, tlv->length);
+}
+
+/* test whether we support a tlv type */
+bool bnx2x_tlv_supported(u16 tlvtype)
+{
+ return CHANNEL_TLV_NONE < tlvtype && tlvtype < CHANNEL_TLV_MAX;
+}
+
+static inline int bnx2x_pfvf_status_codes(int rc)
+{
+ switch (rc) {
+ case 0:
+ return PFVF_STATUS_SUCCESS;
+ case -ENOMEM:
+ return PFVF_STATUS_NO_RESOURCE;
+ default:
+ return PFVF_STATUS_FAILURE;
+ }
+}
+
+int bnx2x_send_msg2pf(struct bnx2x *bp, u8 *done, dma_addr_t msg_mapping)
+{
+ struct cstorm_vf_zone_data __iomem *zone_data =
+ REG_ADDR(bp, PXP_VF_ADDR_CSDM_GLOBAL_START);
+ int tout = 600, interval = 100; /* wait for 60 seconds */
+
+ if (*done) {
+ BNX2X_ERR("done was non zero before message to pf was sent\n");
+ WARN_ON(true);
+ return -EINVAL;
+ }
+
+ /* Write message address */
+ writel(U64_LO(msg_mapping),
+ &zone_data->non_trigger.vf_pf_channel.msg_addr_lo);
+ writel(U64_HI(msg_mapping),
+ &zone_data->non_trigger.vf_pf_channel.msg_addr_hi);
+
+ /* make sure the address is written before FW accesses it */
+ wmb();
+
+ /* Trigger the PF FW */
+ writeb(1, &zone_data->trigger.vf_pf_channel.addr_valid);
+
+ /* Wait for PF to complete */
+ while ((tout >= 0) && (!*done)) {
+ msleep(interval);
+ tout -= 1;
+
+ /* progress indicator - HV can take its own sweet time in
+ * answering VFs...
+ */
+ DP_CONT(BNX2X_MSG_IOV, ".");
+ }
+
+ if (!*done) {
+ BNX2X_ERR("PF response has timed out\n");
+ return -EAGAIN;
+ }
+ DP(BNX2X_MSG_SP, "Got a response from PF\n");
+ return 0;
+}
+
+int bnx2x_get_vf_id(struct bnx2x *bp, u32 *vf_id)
+{
+ u32 me_reg;
+ int tout = 10, interval = 100; /* Wait for 1 sec */
+
+ do {
+ /* pxp traps vf read of doorbells and returns me reg value */
+ me_reg = readl(bp->doorbells);
+ if (GOOD_ME_REG(me_reg))
+ break;
+
+ msleep(interval);
+
+ BNX2X_ERR("Invalid ME register value: 0x%08x\n. Is pf driver up?",
+ me_reg);
+ } while (tout-- > 0);
+
+ if (!GOOD_ME_REG(me_reg)) {
+ BNX2X_ERR("Invalid ME register value: 0x%08x\n", me_reg);
+ return -EINVAL;
+ }
+
+ BNX2X_ERR("valid ME register value: 0x%08x\n", me_reg);
+
+ *vf_id = (me_reg & ME_REG_VF_NUM_MASK) >> ME_REG_VF_NUM_SHIFT;
+
+ return 0;
+}
+
+int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
+{
+ int rc = 0, attempts = 0;
+ struct vfpf_acquire_tlv *req = &bp->vf2pf_mbox->req.acquire;
+ struct pfvf_acquire_resp_tlv *resp = &bp->vf2pf_mbox->resp.acquire_resp;
+ u32 vf_id;
+ bool resources_acquired = false;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_ACQUIRE, sizeof(*req));
+
+ if (bnx2x_get_vf_id(bp, &vf_id))
+ return -EAGAIN;
+
+ req->vfdev_info.vf_id = vf_id;
+ req->vfdev_info.vf_os = 0;
+
+ req->resc_request.num_rxqs = rx_count;
+ req->resc_request.num_txqs = tx_count;
+ req->resc_request.num_sbs = bp->igu_sb_cnt;
+ req->resc_request.num_mac_filters = VF_ACQUIRE_MAC_FILTERS;
+ req->resc_request.num_mc_filters = VF_ACQUIRE_MC_FILTERS;
+
+ /* pf 2 vf bulletin board address */
+ req->bulletin_addr = bp->pf2vf_bulletin_mapping;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ while (!resources_acquired) {
+ DP(BNX2X_MSG_SP, "attempting to acquire resources\n");
+
+ /* send acquire request */
+ rc = bnx2x_send_msg2pf(bp,
+ &resp->hdr.status,
+ bp->vf2pf_mbox_mapping);
+
+ /* PF timeout */
+ if (rc)
+ return rc;
+
+ /* copy acquire response from buffer to bp */
+ memcpy(&bp->acquire_resp, resp, sizeof(bp->acquire_resp));
+
+ attempts++;
+
+ /* test whether the PF accepted our request. If not, humble the
+ * the request and try again.
+ */
+ if (bp->acquire_resp.hdr.status == PFVF_STATUS_SUCCESS) {
+ DP(BNX2X_MSG_SP, "resources acquired\n");
+ resources_acquired = true;
+ } else if (bp->acquire_resp.hdr.status ==
+ PFVF_STATUS_NO_RESOURCE &&
+ attempts < VF_ACQUIRE_THRESH) {
+ DP(BNX2X_MSG_SP,
+ "PF unwilling to fulfill resource request. Try PF recommended amount\n");
+
+ /* humble our request */
+ req->resc_request.num_txqs =
+ bp->acquire_resp.resc.num_txqs;
+ req->resc_request.num_rxqs =
+ bp->acquire_resp.resc.num_rxqs;
+ req->resc_request.num_sbs =
+ bp->acquire_resp.resc.num_sbs;
+ req->resc_request.num_mac_filters =
+ bp->acquire_resp.resc.num_mac_filters;
+ req->resc_request.num_vlan_filters =
+ bp->acquire_resp.resc.num_vlan_filters;
+ req->resc_request.num_mc_filters =
+ bp->acquire_resp.resc.num_mc_filters;
+
+ /* Clear response buffer */
+ memset(&bp->vf2pf_mbox->resp, 0,
+ sizeof(union pfvf_tlvs));
+ } else {
+ /* PF reports error */
+ BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n",
+ bp->acquire_resp.hdr.status);
+ return -EAGAIN;
+ }
+ }
+
+ /* get HW info */
+ bp->common.chip_id |= (bp->acquire_resp.pfdev_info.chip_num & 0xffff);
+ bp->link_params.chip_id = bp->common.chip_id;
+ bp->db_size = bp->acquire_resp.pfdev_info.db_size;
+ bp->common.int_block = INT_BLOCK_IGU;
+ bp->common.chip_port_mode = CHIP_2_PORT_MODE;
+ bp->igu_dsb_id = -1;
+ bp->mf_ov = 0;
+ bp->mf_mode = 0;
+ bp->common.flash_size = 0;
+ bp->flags |=
+ NO_WOL_FLAG | NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG | NO_FCOE_FLAG;
+ bp->igu_sb_cnt = 1;
+ bp->igu_base_sb = bp->acquire_resp.resc.hw_sbs[0].hw_sb_id;
+ strlcpy(bp->fw_ver, bp->acquire_resp.pfdev_info.fw_ver,
+ sizeof(bp->fw_ver));
+
+ if (is_valid_ether_addr(bp->acquire_resp.resc.current_mac_addr))
+ memcpy(bp->dev->dev_addr,
+ bp->acquire_resp.resc.current_mac_addr,
+ ETH_ALEN);
+
+ return 0;
+}
+
+int bnx2x_vfpf_release(struct bnx2x *bp)
+{
+ struct vfpf_release_tlv *req = &bp->vf2pf_mbox->req.release;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ u32 rc = 0, vf_id;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_RELEASE, sizeof(*req));
+
+ if (bnx2x_get_vf_id(bp, &vf_id))
+ return -EAGAIN;
+
+ req->vf_id = vf_id;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ /* send release request */
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+ if (rc)
+ /* PF timeout */
+ return rc;
+ if (resp->hdr.status == PFVF_STATUS_SUCCESS) {
+ /* PF released us */
+ DP(BNX2X_MSG_SP, "vf released\n");
+ } else {
+ /* PF reports error */
+ BNX2X_ERR("PF failed our release request - are we out of sync? response status: %d\n",
+ resp->hdr.status);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+/* Tell PF about SB addresses */
+int bnx2x_vfpf_init(struct bnx2x *bp)
+{
+ struct vfpf_init_tlv *req = &bp->vf2pf_mbox->req.init;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int rc, i;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_INIT, sizeof(*req));
+
+ /* status blocks */
+ for_each_eth_queue(bp, i)
+ req->sb_addr[i] = (dma_addr_t)bnx2x_fp(bp, i,
+ status_blk_mapping);
+
+ /* statistics - requests only supports single queue for now */
+ req->stats_addr = bp->fw_stats_data_mapping +
+ offsetof(struct bnx2x_fw_stats_data, queue_stats);
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+ if (rc)
+ return rc;
+
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("INIT VF failed: %d. Breaking...\n",
+ resp->hdr.status);
+ return -EAGAIN;
+ }
+
+ DP(BNX2X_MSG_SP, "INIT VF Succeeded\n");
+ return 0;
+}
+
+/* CLOSE VF - opposite to INIT_VF */
+void bnx2x_vfpf_close_vf(struct bnx2x *bp)
+{
+ struct vfpf_close_tlv *req = &bp->vf2pf_mbox->req.close;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int i, rc;
+ u32 vf_id;
+
+ /* If we haven't got a valid VF id, there is no sense to
+ * continue with sending messages
+ */
+ if (bnx2x_get_vf_id(bp, &vf_id))
+ goto free_irq;
+
+ /* Close the queues */
+ for_each_queue(bp, i)
+ bnx2x_vfpf_teardown_queue(bp, i);
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_CLOSE, sizeof(*req));
+
+ req->vf_id = vf_id;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+ if (rc)
+ BNX2X_ERR("Sending CLOSE failed. rc was: %d\n", rc);
+
+ else if (resp->hdr.status != PFVF_STATUS_SUCCESS)
+ BNX2X_ERR("Sending CLOSE failed: pf response was %d\n",
+ resp->hdr.status);
+
+free_irq:
+ /* Disable HW interrupts, NAPI */
+ bnx2x_netif_stop(bp, 0);
+ /* Delete all NAPI objects */
+ bnx2x_del_all_napi(bp);
+
+ /* Release IRQs */
+ bnx2x_free_irq(bp);
+}
+
+/* ask the pf to open a queue for the vf */
+int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx)
+{
+ struct vfpf_setup_q_tlv *req = &bp->vf2pf_mbox->req.setup_q;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ struct bnx2x_fastpath *fp = &bp->fp[fp_idx];
+ u16 tpa_agg_size = 0, flags = 0;
+ int rc;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SETUP_Q, sizeof(*req));
+
+ /* select tpa mode to request */
+ if (!fp->disable_tpa) {
+ flags |= VFPF_QUEUE_FLG_TPA;
+ flags |= VFPF_QUEUE_FLG_TPA_IPV6;
+ if (fp->mode == TPA_MODE_GRO)
+ flags |= VFPF_QUEUE_FLG_TPA_GRO;
+ tpa_agg_size = TPA_AGG_SIZE;
+ }
+
+ /* calculate queue flags */
+ flags |= VFPF_QUEUE_FLG_STATS;
+ flags |= VFPF_QUEUE_FLG_CACHE_ALIGN;
+ flags |= IS_MF_SD(bp) ? VFPF_QUEUE_FLG_OV : 0;
+ flags |= VFPF_QUEUE_FLG_VLAN;
+ DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
+
+ /* Common */
+ req->vf_qid = fp_idx;
+ req->param_valid = VFPF_RXQ_VALID | VFPF_TXQ_VALID;
+
+ /* Rx */
+ req->rxq.rcq_addr = fp->rx_comp_mapping;
+ req->rxq.rcq_np_addr = fp->rx_comp_mapping + BCM_PAGE_SIZE;
+ req->rxq.rxq_addr = fp->rx_desc_mapping;
+ req->rxq.sge_addr = fp->rx_sge_mapping;
+ req->rxq.vf_sb = fp_idx;
+ req->rxq.sb_index = HC_INDEX_ETH_RX_CQ_CONS;
+ req->rxq.hc_rate = bp->rx_ticks ? 1000000/bp->rx_ticks : 0;
+ req->rxq.mtu = bp->dev->mtu;
+ req->rxq.buf_sz = fp->rx_buf_size;
+ req->rxq.sge_buf_sz = BCM_PAGE_SIZE * PAGES_PER_SGE;
+ req->rxq.tpa_agg_sz = tpa_agg_size;
+ req->rxq.max_sge_pkt = SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT;
+ req->rxq.max_sge_pkt = ((req->rxq.max_sge_pkt + PAGES_PER_SGE - 1) &
+ (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT;
+ req->rxq.flags = flags;
+ req->rxq.drop_flags = 0;
+ req->rxq.cache_line_log = BNX2X_RX_ALIGN_SHIFT;
+ req->rxq.stat_id = -1; /* No stats at the moment */
+
+ /* Tx */
+ req->txq.txq_addr = fp->txdata_ptr[FIRST_TX_COS_INDEX]->tx_desc_mapping;
+ req->txq.vf_sb = fp_idx;
+ req->txq.sb_index = HC_INDEX_ETH_TX_CQ_CONS_COS0;
+ req->txq.hc_rate = bp->tx_ticks ? 1000000/bp->tx_ticks : 0;
+ req->txq.flags = flags;
+ req->txq.traffic_type = LLFC_TRAFFIC_TYPE_NW;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+ if (rc)
+ BNX2X_ERR("Sending SETUP_Q message for queue[%d] failed!\n",
+ fp_idx);
+
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("Status of SETUP_Q for queue[%d] is %d\n",
+ fp_idx, resp->hdr.status);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
+{
+ struct vfpf_q_op_tlv *req = &bp->vf2pf_mbox->req.q_op;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int rc;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_TEARDOWN_Q,
+ sizeof(*req));
+
+ req->vf_qid = qidx;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+ if (rc) {
+ BNX2X_ERR("Sending TEARDOWN for queue %d failed: %d\n", qidx,
+ rc);
+ return rc;
+ }
+
+ /* PF failed the transaction */
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("TEARDOWN for queue %d failed: %d\n", qidx,
+ resp->hdr.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* request pf to add a mac for the vf */
+int bnx2x_vfpf_set_mac(struct bnx2x *bp)
+{
+ struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int rc;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+ sizeof(*req));
+
+ req->flags = VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED;
+ req->vf_qid = 0;
+ req->n_mac_vlan_filters = 1;
+ req->filters[0].flags =
+ VFPF_Q_FILTER_DEST_MAC_VALID | VFPF_Q_FILTER_SET_MAC;
+
+ /* sample bulletin board for new mac */
+ bnx2x_sample_bulletin(bp);
+
+ /* copy mac from device to request */
+ memcpy(req->filters[0].mac, bp->dev->dev_addr, ETH_ALEN);
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ /* send message to pf */
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+ if (rc) {
+ BNX2X_ERR("failed to send message to pf. rc was %d\n", rc);
+ return rc;
+ }
+
+ /* failure may mean PF was configured with a new mac for us */
+ while (resp->hdr.status == PFVF_STATUS_FAILURE) {
+ DP(BNX2X_MSG_IOV,
+ "vfpf SET MAC failed. Check bulletin board for new posts\n");
+
+ /* check if bulletin board was updated */
+ if (bnx2x_sample_bulletin(bp) == PFVF_BULLETIN_UPDATED) {
+ /* copy mac from device to request */
+ memcpy(req->filters[0].mac, bp->dev->dev_addr,
+ ETH_ALEN);
+
+ /* send message to pf */
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status,
+ bp->vf2pf_mbox_mapping);
+ } else {
+ /* no new info in bulletin */
+ break;
+ }
+ }
+
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int bnx2x_vfpf_set_mcast(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int rc, i = 0;
+ struct netdev_hw_addr *ha;
+
+ if (bp->state != BNX2X_STATE_OPEN) {
+ DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state);
+ return -EINVAL;
+ }
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+ sizeof(*req));
+
+ /* Get Rx mode requested */
+ DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags);
+
+ netdev_for_each_mc_addr(ha, dev) {
+ DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
+ bnx2x_mc_addr(ha));
+ memcpy(req->multicast[i], bnx2x_mc_addr(ha), ETH_ALEN);
+ i++;
+ }
+
+ /* We support four PFVF_MAX_MULTICAST_PER_VF mcast
+ * addresses tops
+ */
+ if (i >= PFVF_MAX_MULTICAST_PER_VF) {
+ DP(NETIF_MSG_IFUP,
+ "VF supports not more than %d multicast MAC addresses\n",
+ PFVF_MAX_MULTICAST_PER_VF);
+ return -EINVAL;
+ }
+
+ req->n_multicast = i;
+ req->flags |= VFPF_SET_Q_FILTERS_MULTICAST_CHANGED;
+ req->vf_qid = 0;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+ if (rc) {
+ BNX2X_ERR("Sending a message failed: %d\n", rc);
+ return rc;
+ }
+
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("Set Rx mode/multicast failed: %d\n",
+ resp->hdr.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
+{
+ int mode = bp->rx_mode;
+ struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int rc;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+ sizeof(*req));
+
+ DP(NETIF_MSG_IFUP, "Rx mode is %d\n", mode);
+
+ switch (mode) {
+ case BNX2X_RX_MODE_NONE: /* no Rx */
+ req->rx_mask = VFPF_RX_MASK_ACCEPT_NONE;
+ break;
+ case BNX2X_RX_MODE_NORMAL:
+ req->rx_mask = VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+ break;
+ case BNX2X_RX_MODE_ALLMULTI:
+ req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+ break;
+ case BNX2X_RX_MODE_PROMISC:
+ req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_UNICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+ break;
+ default:
+ BNX2X_ERR("BAD rx mode (%d)\n", mode);
+ return -EINVAL;
+ }
+
+ req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED;
+ req->vf_qid = 0;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+ if (rc)
+ BNX2X_ERR("Sending a message failed: %d\n", rc);
+
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("Set Rx mode failed: %d\n", resp->hdr.status);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+/* General service functions */
+static void storm_memset_vf_mbx_ack(struct bnx2x *bp, u16 abs_fid)
+{
+ u32 addr = BAR_CSTRORM_INTMEM +
+ CSTORM_VF_PF_CHANNEL_STATE_OFFSET(abs_fid);
+
+ REG_WR8(bp, addr, VF_PF_CHANNEL_STATE_READY);
+}
+
+static void storm_memset_vf_mbx_valid(struct bnx2x *bp, u16 abs_fid)
+{
+ u32 addr = BAR_CSTRORM_INTMEM +
+ CSTORM_VF_PF_CHANNEL_VALID_OFFSET(abs_fid);
+
+ REG_WR8(bp, addr, 1);
+}
+
+static inline void bnx2x_set_vf_mbxs_valid(struct bnx2x *bp)
+{
+ int i;
+
+ for_each_vf(bp, i)
+ storm_memset_vf_mbx_valid(bp, bnx2x_vf(bp, i, abs_vfid));
+}
+
+/* enable vf_pf mailbox (aka vf-pf-chanell) */
+void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid)
+{
+ bnx2x_vf_flr_clnup_epilog(bp, abs_vfid);
+
+ /* enable the mailbox in the FW */
+ storm_memset_vf_mbx_ack(bp, abs_vfid);
+ storm_memset_vf_mbx_valid(bp, abs_vfid);
+
+ /* enable the VF access to the mailbox */
+ bnx2x_vf_enable_access(bp, abs_vfid);
+}
+
+/* this works only on !E1h */
+static int bnx2x_copy32_vf_dmae(struct bnx2x *bp, u8 from_vf,
+ dma_addr_t pf_addr, u8 vfid, u32 vf_addr_hi,
+ u32 vf_addr_lo, u32 len32)
+{
+ struct dmae_command dmae;
+
+ if (CHIP_IS_E1x(bp)) {
+ BNX2X_ERR("Chip revision does not support VFs\n");
+ return DMAE_NOT_RDY;
+ }
+
+ if (!bp->dmae_ready) {
+ BNX2X_ERR("DMAE is not ready, can not copy\n");
+ return DMAE_NOT_RDY;
+ }
+
+ /* set opcode and fixed command fields */
+ bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_PCI, DMAE_DST_PCI);
+
+ if (from_vf) {
+ dmae.opcode_iov = (vfid << DMAE_COMMAND_SRC_VFID_SHIFT) |
+ (DMAE_SRC_VF << DMAE_COMMAND_SRC_VFPF_SHIFT) |
+ (DMAE_DST_PF << DMAE_COMMAND_DST_VFPF_SHIFT);
+
+ dmae.opcode |= (DMAE_C_DST << DMAE_COMMAND_C_FUNC_SHIFT);
+
+ dmae.src_addr_lo = vf_addr_lo;
+ dmae.src_addr_hi = vf_addr_hi;
+ dmae.dst_addr_lo = U64_LO(pf_addr);
+ dmae.dst_addr_hi = U64_HI(pf_addr);
+ } else {
+ dmae.opcode_iov = (vfid << DMAE_COMMAND_DST_VFID_SHIFT) |
+ (DMAE_DST_VF << DMAE_COMMAND_DST_VFPF_SHIFT) |
+ (DMAE_SRC_PF << DMAE_COMMAND_SRC_VFPF_SHIFT);
+
+ dmae.opcode |= (DMAE_C_SRC << DMAE_COMMAND_C_FUNC_SHIFT);
+
+ dmae.src_addr_lo = U64_LO(pf_addr);
+ dmae.src_addr_hi = U64_HI(pf_addr);
+ dmae.dst_addr_lo = vf_addr_lo;
+ dmae.dst_addr_hi = vf_addr_hi;
+ }
+ dmae.len = len32;
+ bnx2x_dp_dmae(bp, &dmae, BNX2X_MSG_DMAE);
+
+ /* issue the command and wait for completion */
+ return bnx2x_issue_dmae_with_comp(bp, &dmae);
+}
+
+static void bnx2x_vf_mbx_resp(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ struct bnx2x_vf_mbx *mbx = BP_VF_MBX(bp, vf->index);
+ u64 vf_addr;
+ dma_addr_t pf_addr;
+ u16 length, type;
+ int rc;
+ struct pfvf_general_resp_tlv *resp = &mbx->msg->resp.general_resp;
+
+ /* prepare response */
+ type = mbx->first_tlv.tl.type;
+ length = type == CHANNEL_TLV_ACQUIRE ?
+ sizeof(struct pfvf_acquire_resp_tlv) :
+ sizeof(struct pfvf_general_resp_tlv);
+ bnx2x_add_tlv(bp, resp, 0, type, length);
+ resp->hdr.status = bnx2x_pfvf_status_codes(vf->op_rc);
+ bnx2x_add_tlv(bp, resp, length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+ bnx2x_dp_tlv_list(bp, resp);
+ DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
+ mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
+
+ /* send response */
+ vf_addr = HILO_U64(mbx->vf_addr_hi, mbx->vf_addr_lo) +
+ mbx->first_tlv.resp_msg_offset;
+ pf_addr = mbx->msg_mapping +
+ offsetof(struct bnx2x_vf_mbx_msg, resp);
+
+ /* copy the response body, if there is one, before the header, as the vf
+ * is sensitive to the header being written
+ */
+ if (resp->hdr.tl.length > sizeof(u64)) {
+ length = resp->hdr.tl.length - sizeof(u64);
+ vf_addr += sizeof(u64);
+ pf_addr += sizeof(u64);
+ rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr, vf->abs_vfid,
+ U64_HI(vf_addr),
+ U64_LO(vf_addr),
+ length/4);
+ if (rc) {
+ BNX2X_ERR("Failed to copy response body to VF %d\n",
+ vf->abs_vfid);
+ goto mbx_error;
+ }
+ vf_addr -= sizeof(u64);
+ pf_addr -= sizeof(u64);
+ }
+
+ /* ack the FW */
+ storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
+ mmiowb();
+
+ /* initiate dmae to send the response */
+ mbx->flags &= ~VF_MSG_INPROCESS;
+
+ /* copy the response header including status-done field,
+ * must be last dmae, must be after FW is acked
+ */
+ rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr, vf->abs_vfid,
+ U64_HI(vf_addr),
+ U64_LO(vf_addr),
+ sizeof(u64)/4);
+
+ /* unlock channel mutex */
+ bnx2x_unlock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
+
+ if (rc) {
+ BNX2X_ERR("Failed to copy response status to VF %d\n",
+ vf->abs_vfid);
+ goto mbx_error;
+ }
+ return;
+
+mbx_error:
+ bnx2x_vf_release(bp, vf, false); /* non blocking */
+}
+
+static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx, int vfop_status)
+{
+ int i;
+ struct pfvf_acquire_resp_tlv *resp = &mbx->msg->resp.acquire_resp;
+ struct pf_vf_resc *resc = &resp->resc;
+ u8 status = bnx2x_pfvf_status_codes(vfop_status);
+
+ memset(resp, 0, sizeof(*resp));
+
+ /* fill in pfdev info */
+ resp->pfdev_info.chip_num = bp->common.chip_id;
+ resp->pfdev_info.db_size = (1 << BNX2X_DB_SHIFT);
+ resp->pfdev_info.indices_per_sb = HC_SB_MAX_INDICES_E2;
+ resp->pfdev_info.pf_cap = (PFVF_CAP_RSS |
+ /* PFVF_CAP_DHC |*/ PFVF_CAP_TPA);
+ bnx2x_fill_fw_str(bp, resp->pfdev_info.fw_ver,
+ sizeof(resp->pfdev_info.fw_ver));
+
+ if (status == PFVF_STATUS_NO_RESOURCE ||
+ status == PFVF_STATUS_SUCCESS) {
+ /* set resources numbers, if status equals NO_RESOURCE these
+ * are max possible numbers
+ */
+ resc->num_rxqs = vf_rxq_count(vf) ? :
+ bnx2x_vf_max_queue_cnt(bp, vf);
+ resc->num_txqs = vf_txq_count(vf) ? :
+ bnx2x_vf_max_queue_cnt(bp, vf);
+ resc->num_sbs = vf_sb_count(vf);
+ resc->num_mac_filters = vf_mac_rules_cnt(vf);
+ resc->num_vlan_filters = vf_vlan_rules_cnt(vf);
+ resc->num_mc_filters = 0;
+
+ if (status == PFVF_STATUS_SUCCESS) {
+ /* fill in the allocated resources */
+ struct pf_vf_bulletin_content *bulletin =
+ BP_VF_BULLETIN(bp, vf->index);
+
+ for_each_vfq(vf, i)
+ resc->hw_qid[i] =
+ vfq_qzone_id(vf, vfq_get(vf, i));
+
+ for_each_vf_sb(vf, i) {
+ resc->hw_sbs[i].hw_sb_id = vf_igu_sb(vf, i);
+ resc->hw_sbs[i].sb_qid = vf_hc_qzone(vf, i);
+ }
+
+ /* if a mac has been set for this vf, supply it */
+ if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID) {
+ memcpy(resc->current_mac_addr, bulletin->mac,
+ ETH_ALEN);
+ }
+ }
+ }
+
+ DP(BNX2X_MSG_IOV, "VF[%d] ACQUIRE_RESPONSE: pfdev_info- chip_num=0x%x, db_size=%d, idx_per_sb=%d, pf_cap=0x%x\n"
+ "resources- n_rxq-%d, n_txq-%d, n_sbs-%d, n_macs-%d, n_vlans-%d, n_mcs-%d, fw_ver: '%s'\n",
+ vf->abs_vfid,
+ resp->pfdev_info.chip_num,
+ resp->pfdev_info.db_size,
+ resp->pfdev_info.indices_per_sb,
+ resp->pfdev_info.pf_cap,
+ resc->num_rxqs,
+ resc->num_txqs,
+ resc->num_sbs,
+ resc->num_mac_filters,
+ resc->num_vlan_filters,
+ resc->num_mc_filters,
+ resp->pfdev_info.fw_ver);
+
+ DP_CONT(BNX2X_MSG_IOV, "hw_qids- [ ");
+ for (i = 0; i < vf_rxq_count(vf); i++)
+ DP_CONT(BNX2X_MSG_IOV, "%d ", resc->hw_qid[i]);
+ DP_CONT(BNX2X_MSG_IOV, "], sb_info- [ ");
+ for (i = 0; i < vf_sb_count(vf); i++)
+ DP_CONT(BNX2X_MSG_IOV, "%d:%d ",
+ resc->hw_sbs[i].hw_sb_id,
+ resc->hw_sbs[i].sb_qid);
+ DP_CONT(BNX2X_MSG_IOV, "]\n");
+
+ /* send the response */
+ vf->op_rc = vfop_status;
+ bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ int rc;
+ struct vfpf_acquire_tlv *acquire = &mbx->msg->req.acquire;
+
+ /* log vfdef info */
+ DP(BNX2X_MSG_IOV,
+ "VF[%d] ACQUIRE: vfdev_info- vf_id %d, vf_os %d resources- n_rxq-%d, n_txq-%d, n_sbs-%d, n_macs-%d, n_vlans-%d, n_mcs-%d\n",
+ vf->abs_vfid, acquire->vfdev_info.vf_id, acquire->vfdev_info.vf_os,
+ acquire->resc_request.num_rxqs, acquire->resc_request.num_txqs,
+ acquire->resc_request.num_sbs, acquire->resc_request.num_mac_filters,
+ acquire->resc_request.num_vlan_filters,
+ acquire->resc_request.num_mc_filters);
+
+ /* acquire the resources */
+ rc = bnx2x_vf_acquire(bp, vf, &acquire->resc_request);
+
+ /* store address of vf's bulletin board */
+ vf->bulletin_map = acquire->bulletin_addr;
+
+ /* response */
+ bnx2x_vf_mbx_acquire_resp(bp, vf, mbx, rc);
+}
+
+static void bnx2x_vf_mbx_init_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ struct vfpf_init_tlv *init = &mbx->msg->req.init;
+
+ /* record ghost addresses from vf message */
+ vf->spq_map = init->spq_addr;
+ vf->fw_stat_map = init->stats_addr;
+ vf->op_rc = bnx2x_vf_init(bp, vf, (dma_addr_t *)init->sb_addr);
+
+ /* response */
+ bnx2x_vf_mbx_resp(bp, vf);
+}
+
+/* convert MBX queue-flags to standard SP queue-flags */
+static void bnx2x_vf_mbx_set_q_flags(u32 mbx_q_flags,
+ unsigned long *sp_q_flags)
+{
+ if (mbx_q_flags & VFPF_QUEUE_FLG_TPA)
+ __set_bit(BNX2X_Q_FLG_TPA, sp_q_flags);
+ if (mbx_q_flags & VFPF_QUEUE_FLG_TPA_IPV6)
+ __set_bit(BNX2X_Q_FLG_TPA_IPV6, sp_q_flags);
+ if (mbx_q_flags & VFPF_QUEUE_FLG_TPA_GRO)
+ __set_bit(BNX2X_Q_FLG_TPA_GRO, sp_q_flags);
+ if (mbx_q_flags & VFPF_QUEUE_FLG_STATS)
+ __set_bit(BNX2X_Q_FLG_STATS, sp_q_flags);
+ if (mbx_q_flags & VFPF_QUEUE_FLG_OV)
+ __set_bit(BNX2X_Q_FLG_OV, sp_q_flags);
+ if (mbx_q_flags & VFPF_QUEUE_FLG_VLAN)
+ __set_bit(BNX2X_Q_FLG_VLAN, sp_q_flags);
+ if (mbx_q_flags & VFPF_QUEUE_FLG_COS)
+ __set_bit(BNX2X_Q_FLG_COS, sp_q_flags);
+ if (mbx_q_flags & VFPF_QUEUE_FLG_HC)
+ __set_bit(BNX2X_Q_FLG_HC, sp_q_flags);
+ if (mbx_q_flags & VFPF_QUEUE_FLG_DHC)
+ __set_bit(BNX2X_Q_FLG_DHC, sp_q_flags);
+}
+
+static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ struct vfpf_setup_q_tlv *setup_q = &mbx->msg->req.setup_q;
+ struct bnx2x_vfop_cmd cmd = {
+ .done = bnx2x_vf_mbx_resp,
+ .block = false,
+ };
+
+ /* verify vf_qid */
+ if (setup_q->vf_qid >= vf_rxq_count(vf)) {
+ BNX2X_ERR("vf_qid %d invalid, max queue count is %d\n",
+ setup_q->vf_qid, vf_rxq_count(vf));
+ vf->op_rc = -EINVAL;
+ goto response;
+ }
+
+ /* tx queues must be setup alongside rx queues thus if the rx queue
+ * is not marked as valid there's nothing to do.
+ */
+ if (setup_q->param_valid & (VFPF_RXQ_VALID|VFPF_TXQ_VALID)) {
+ struct bnx2x_vf_queue *q = vfq_get(vf, setup_q->vf_qid);
+ unsigned long q_type = 0;
+
+ struct bnx2x_queue_init_params *init_p;
+ struct bnx2x_queue_setup_params *setup_p;
+
+ /* reinit the VF operation context */
+ memset(&vf->op_params.qctor, 0 , sizeof(vf->op_params.qctor));
+ setup_p = &vf->op_params.qctor.prep_qsetup;
+ init_p = &vf->op_params.qctor.qstate.params.init;
+
+ /* activate immediately */
+ __set_bit(BNX2X_Q_FLG_ACTIVE, &setup_p->flags);
+
+ if (setup_q->param_valid & VFPF_TXQ_VALID) {
+ struct bnx2x_txq_setup_params *txq_params =
+ &setup_p->txq_params;
+
+ __set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
+
+ /* save sb resource index */
+ q->sb_idx = setup_q->txq.vf_sb;
+
+ /* tx init */
+ init_p->tx.hc_rate = setup_q->txq.hc_rate;
+ init_p->tx.sb_cq_index = setup_q->txq.sb_index;
+
+ bnx2x_vf_mbx_set_q_flags(setup_q->txq.flags,
+ &init_p->tx.flags);
+
+ /* tx setup - flags */
+ bnx2x_vf_mbx_set_q_flags(setup_q->txq.flags,
+ &setup_p->flags);
+
+ /* tx setup - general, nothing */
+
+ /* tx setup - tx */
+ txq_params->dscr_map = setup_q->txq.txq_addr;
+ txq_params->sb_cq_index = setup_q->txq.sb_index;
+ txq_params->traffic_type = setup_q->txq.traffic_type;
+
+ bnx2x_vfop_qctor_dump_tx(bp, vf, init_p, setup_p,
+ q->index, q->sb_idx);
+ }
+
+ if (setup_q->param_valid & VFPF_RXQ_VALID) {
+ struct bnx2x_rxq_setup_params *rxq_params =
+ &setup_p->rxq_params;
+
+ __set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);
+
+ /* Note: there is no support for different SBs
+ * for TX and RX
+ */
+ q->sb_idx = setup_q->rxq.vf_sb;
+
+ /* rx init */
+ init_p->rx.hc_rate = setup_q->rxq.hc_rate;
+ init_p->rx.sb_cq_index = setup_q->rxq.sb_index;
+ bnx2x_vf_mbx_set_q_flags(setup_q->rxq.flags,
+ &init_p->rx.flags);
+
+ /* rx setup - flags */
+ bnx2x_vf_mbx_set_q_flags(setup_q->rxq.flags,
+ &setup_p->flags);
+
+ /* rx setup - general */
+ setup_p->gen_params.mtu = setup_q->rxq.mtu;
+
+ /* rx setup - rx */
+ rxq_params->drop_flags = setup_q->rxq.drop_flags;
+ rxq_params->dscr_map = setup_q->rxq.rxq_addr;
+ rxq_params->sge_map = setup_q->rxq.sge_addr;
+ rxq_params->rcq_map = setup_q->rxq.rcq_addr;
+ rxq_params->rcq_np_map = setup_q->rxq.rcq_np_addr;
+ rxq_params->buf_sz = setup_q->rxq.buf_sz;
+ rxq_params->tpa_agg_sz = setup_q->rxq.tpa_agg_sz;
+ rxq_params->max_sges_pkt = setup_q->rxq.max_sge_pkt;
+ rxq_params->sge_buf_sz = setup_q->rxq.sge_buf_sz;
+ rxq_params->cache_line_log =
+ setup_q->rxq.cache_line_log;
+ rxq_params->sb_cq_index = setup_q->rxq.sb_index;
+
+ bnx2x_vfop_qctor_dump_rx(bp, vf, init_p, setup_p,
+ q->index, q->sb_idx);
+ }
+ /* complete the preparations */
+ bnx2x_vfop_qctor_prep(bp, vf, q, &vf->op_params.qctor, q_type);
+
+ vf->op_rc = bnx2x_vfop_qsetup_cmd(bp, vf, &cmd, q->index);
+ if (vf->op_rc)
+ goto response;
+ return;
+ }
+response:
+ bnx2x_vf_mbx_resp(bp, vf);
+}
+
+enum bnx2x_vfop_filters_state {
+ BNX2X_VFOP_MBX_Q_FILTERS_MACS,
+ BNX2X_VFOP_MBX_Q_FILTERS_VLANS,
+ BNX2X_VFOP_MBX_Q_FILTERS_RXMODE,
+ BNX2X_VFOP_MBX_Q_FILTERS_MCAST,
+ BNX2X_VFOP_MBX_Q_FILTERS_DONE
+};
+
+static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct vfpf_set_q_filters_tlv *tlv,
+ struct bnx2x_vfop_filters **pfl,
+ u32 type_flag)
+{
+ int i, j;
+ struct bnx2x_vfop_filters *fl = NULL;
+ size_t fsz;
+
+ fsz = tlv->n_mac_vlan_filters * sizeof(struct bnx2x_vfop_filter) +
+ sizeof(struct bnx2x_vfop_filters);
+
+ fl = kzalloc(fsz, GFP_KERNEL);
+ if (!fl)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&fl->head);
+
+ for (i = 0, j = 0; i < tlv->n_mac_vlan_filters; i++) {
+ struct vfpf_q_mac_vlan_filter *msg_filter = &tlv->filters[i];
+
+ if ((msg_filter->flags & type_flag) != type_flag)
+ continue;
+ if (type_flag == VFPF_Q_FILTER_DEST_MAC_VALID) {
+ fl->filters[j].mac = msg_filter->mac;
+ fl->filters[j].type = BNX2X_VFOP_FILTER_MAC;
+ } else {
+ fl->filters[j].vid = msg_filter->vlan_tag;
+ fl->filters[j].type = BNX2X_VFOP_FILTER_VLAN;
+ }
+ fl->filters[j].add =
+ (msg_filter->flags & VFPF_Q_FILTER_SET_MAC) ?
+ true : false;
+ list_add_tail(&fl->filters[j++].link, &fl->head);
+ }
+ if (list_empty(&fl->head))
+ kfree(fl);
+ else
+ *pfl = fl;
+
+ return 0;
+}
+
+static void bnx2x_vf_mbx_dp_q_filter(struct bnx2x *bp, int msglvl, int idx,
+ struct vfpf_q_mac_vlan_filter *filter)
+{
+ DP(msglvl, "MAC-VLAN[%d] -- flags=0x%x\n", idx, filter->flags);
+ if (filter->flags & VFPF_Q_FILTER_VLAN_TAG_VALID)
+ DP_CONT(msglvl, ", vlan=%d", filter->vlan_tag);
+ if (filter->flags & VFPF_Q_FILTER_DEST_MAC_VALID)
+ DP_CONT(msglvl, ", MAC=%pM", filter->mac);
+ DP_CONT(msglvl, "\n");
+}
+
+static void bnx2x_vf_mbx_dp_q_filters(struct bnx2x *bp, int msglvl,
+ struct vfpf_set_q_filters_tlv *filters)
+{
+ int i;
+
+ if (filters->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED)
+ for (i = 0; i < filters->n_mac_vlan_filters; i++)
+ bnx2x_vf_mbx_dp_q_filter(bp, msglvl, i,
+ &filters->filters[i]);
+
+ if (filters->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED)
+ DP(msglvl, "RX-MASK=0x%x\n", filters->rx_mask);
+
+ if (filters->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED)
+ for (i = 0; i < filters->n_multicast; i++)
+ DP(msglvl, "MULTICAST=%pM\n", filters->multicast[i]);
+}
+
+#define VFPF_MAC_FILTER VFPF_Q_FILTER_DEST_MAC_VALID
+#define VFPF_VLAN_FILTER VFPF_Q_FILTER_VLAN_TAG_VALID
+
+static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
+{
+ int rc;
+
+ struct vfpf_set_q_filters_tlv *msg =
+ &BP_VF_MBX(bp, vf->index)->msg->req.set_q_filters;
+
+ struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
+ enum bnx2x_vfop_filters_state state = vfop->state;
+
+ struct bnx2x_vfop_cmd cmd = {
+ .done = bnx2x_vfop_mbx_qfilters,
+ .block = false,
+ };
+
+ DP(BNX2X_MSG_IOV, "STATE: %d\n", state);
+
+ if (vfop->rc < 0)
+ goto op_err;
+
+ switch (state) {
+ case BNX2X_VFOP_MBX_Q_FILTERS_MACS:
+ /* next state */
+ vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_VLANS;
+
+ /* check for any vlan/mac changes */
+ if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
+ /* build mac list */
+ struct bnx2x_vfop_filters *fl = NULL;
+
+ vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+ VFPF_MAC_FILTER);
+ if (vfop->rc)
+ goto op_err;
+
+ if (fl) {
+ /* set mac list */
+ rc = bnx2x_vfop_mac_list_cmd(bp, vf, &cmd, fl,
+ msg->vf_qid,
+ false);
+ if (rc) {
+ vfop->rc = rc;
+ goto op_err;
+ }
+ return;
+ }
+ }
+ /* fall through */
+
+ case BNX2X_VFOP_MBX_Q_FILTERS_VLANS:
+ /* next state */
+ vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_RXMODE;
+
+ /* check for any vlan/mac changes */
+ if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
+ /* build vlan list */
+ struct bnx2x_vfop_filters *fl = NULL;
+
+ vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+ VFPF_VLAN_FILTER);
+ if (vfop->rc)
+ goto op_err;
+
+ if (fl) {
+ /* set vlan list */
+ rc = bnx2x_vfop_vlan_list_cmd(bp, vf, &cmd, fl,
+ msg->vf_qid,
+ false);
+ if (rc) {
+ vfop->rc = rc;
+ goto op_err;
+ }
+ return;
+ }
+ }
+ /* fall through */
+
+ case BNX2X_VFOP_MBX_Q_FILTERS_RXMODE:
+ /* next state */
+ vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_MCAST;
+
+ if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) {
+ unsigned long accept = 0;
+
+ /* covert VF-PF if mask to bnx2x accept flags */
+ if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST)
+ __set_bit(BNX2X_ACCEPT_UNICAST, &accept);
+
+ if (msg->rx_mask &
+ VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST)
+ __set_bit(BNX2X_ACCEPT_MULTICAST, &accept);
+
+ if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_UNICAST)
+ __set_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept);
+
+ if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_MULTICAST)
+ __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept);
+
+ if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_BROADCAST)
+ __set_bit(BNX2X_ACCEPT_BROADCAST, &accept);
+
+ /* A packet arriving the vf's mac should be accepted
+ * with any vlan
+ */
+ __set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept);
+
+ /* set rx-mode */
+ rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd,
+ msg->vf_qid, accept);
+ if (rc) {
+ vfop->rc = rc;
+ goto op_err;
+ }
+ return;
+ }
+ /* fall through */
+
+ case BNX2X_VFOP_MBX_Q_FILTERS_MCAST:
+ /* next state */
+ vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_DONE;
+
+ if (msg->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED) {
+ /* set mcasts */
+ rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, msg->multicast,
+ msg->n_multicast, false);
+ if (rc) {
+ vfop->rc = rc;
+ goto op_err;
+ }
+ return;
+ }
+ /* fall through */
+op_done:
+ case BNX2X_VFOP_MBX_Q_FILTERS_DONE:
+ bnx2x_vfop_end(bp, vf, vfop);
+ return;
+op_err:
+ BNX2X_ERR("QFILTERS[%d:%d] error: rc %d\n",
+ vf->abs_vfid, msg->vf_qid, vfop->rc);
+ goto op_done;
+
+ default:
+ bnx2x_vfop_default(state);
+ }
+}
+
+static int bnx2x_vfop_mbx_qfilters_cmd(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vfop_cmd *cmd)
+{
+ struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+ if (vfop) {
+ bnx2x_vfop_opset(BNX2X_VFOP_MBX_Q_FILTERS_MACS,
+ bnx2x_vfop_mbx_qfilters, cmd->done);
+ return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mbx_qfilters,
+ cmd->block);
+ }
+ return -ENOMEM;
+}
+
+static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
+ struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters;
+ struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf->index);
+ struct bnx2x_vfop_cmd cmd = {
+ .done = bnx2x_vf_mbx_resp,
+ .block = false,
+ };
+
+ /* if a mac was already set for this VF via the set vf mac ndo, we only
+ * accept mac configurations of that mac. Why accept them at all?
+ * because PF may have been unable to configure the mac at the time
+ * since queue was not set up.
+ */
+ if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID) {
+ /* once a mac was set by ndo can only accept a single mac... */
+ if (filters->n_mac_vlan_filters > 1) {
+ BNX2X_ERR("VF[%d] requested the addition of multiple macs after set_vf_mac ndo was called\n",
+ vf->abs_vfid);
+ vf->op_rc = -EPERM;
+ goto response;
+ }
+
+ /* ...and only the mac set by the ndo */
+ if (filters->n_mac_vlan_filters == 1 &&
+ memcmp(filters->filters->mac, bulletin->mac, ETH_ALEN)) {
+ BNX2X_ERR("VF[%d] requested the addition of a mac address not matching the one configured by set_vf_mac ndo\n",
+ vf->abs_vfid);
+
+ vf->op_rc = -EPERM;
+ goto response;
+ }
+ }
+
+ /* verify vf_qid */
+ if (filters->vf_qid > vf_rxq_count(vf))
+ goto response;
+
+ DP(BNX2X_MSG_IOV, "VF[%d] Q_FILTERS: queue[%d]\n",
+ vf->abs_vfid,
+ filters->vf_qid);
+
+ /* print q_filter message */
+ bnx2x_vf_mbx_dp_q_filters(bp, BNX2X_MSG_IOV, filters);
+
+ vf->op_rc = bnx2x_vfop_mbx_qfilters_cmd(bp, vf, &cmd);
+ if (vf->op_rc)
+ goto response;
+ return;
+
+response:
+ bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_teardown_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ int qid = mbx->msg->req.q_op.vf_qid;
+ struct bnx2x_vfop_cmd cmd = {
+ .done = bnx2x_vf_mbx_resp,
+ .block = false,
+ };
+
+ DP(BNX2X_MSG_IOV, "VF[%d] Q_TEARDOWN: vf_qid=%d\n",
+ vf->abs_vfid, qid);
+
+ vf->op_rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qid);
+ if (vf->op_rc)
+ bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_close_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ struct bnx2x_vfop_cmd cmd = {
+ .done = bnx2x_vf_mbx_resp,
+ .block = false,
+ };
+
+ DP(BNX2X_MSG_IOV, "VF[%d] VF_CLOSE\n", vf->abs_vfid);
+
+ vf->op_rc = bnx2x_vfop_close_cmd(bp, vf, &cmd);
+ if (vf->op_rc)
+ bnx2x_vf_mbx_resp(bp, vf);
+}
+
+static void bnx2x_vf_mbx_release_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ struct bnx2x_vfop_cmd cmd = {
+ .done = bnx2x_vf_mbx_resp,
+ .block = false,
+ };
+
+ DP(BNX2X_MSG_IOV, "VF[%d] VF_RELEASE\n", vf->abs_vfid);
+
+ vf->op_rc = bnx2x_vfop_release_cmd(bp, vf, &cmd);
+ if (vf->op_rc)
+ bnx2x_vf_mbx_resp(bp, vf);
+}
+
+/* dispatch request */
+static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
+ struct bnx2x_vf_mbx *mbx)
+{
+ int i;
+
+ /* check if tlv type is known */
+ if (bnx2x_tlv_supported(mbx->first_tlv.tl.type)) {
+ /* Lock the per vf op mutex and note the locker's identity.
+ * The unlock will take place in mbx response.
+ */
+ bnx2x_lock_vf_pf_channel(bp, vf, mbx->first_tlv.tl.type);
+
+ /* switch on the opcode */
+ switch (mbx->first_tlv.tl.type) {
+ case CHANNEL_TLV_ACQUIRE:
+ bnx2x_vf_mbx_acquire(bp, vf, mbx);
+ break;
+ case CHANNEL_TLV_INIT:
+ bnx2x_vf_mbx_init_vf(bp, vf, mbx);
+ break;
+ case CHANNEL_TLV_SETUP_Q:
+ bnx2x_vf_mbx_setup_q(bp, vf, mbx);
+ break;
+ case CHANNEL_TLV_SET_Q_FILTERS:
+ bnx2x_vf_mbx_set_q_filters(bp, vf, mbx);
+ break;
+ case CHANNEL_TLV_TEARDOWN_Q:
+ bnx2x_vf_mbx_teardown_q(bp, vf, mbx);
+ break;
+ case CHANNEL_TLV_CLOSE:
+ bnx2x_vf_mbx_close_vf(bp, vf, mbx);
+ break;
+ case CHANNEL_TLV_RELEASE:
+ bnx2x_vf_mbx_release_vf(bp, vf, mbx);
+ break;
+ }
+
+ } else {
+ /* unknown TLV - this may belong to a VF driver from the future
+ * - a version written after this PF driver was written, which
+ * supports features unknown as of yet. Too bad since we don't
+ * support them. Or this may be because someone wrote a crappy
+ * VF driver and is sending garbage over the channel.
+ */
+ BNX2X_ERR("unknown TLV. type %d length %d. first 20 bytes of mailbox buffer:\n",
+ mbx->first_tlv.tl.type, mbx->first_tlv.tl.length);
+ for (i = 0; i < 20; i++)
+ DP_CONT(BNX2X_MSG_IOV, "%x ",
+ mbx->msg->req.tlv_buf_size.tlv_buffer[i]);
+
+ /* test whether we can respond to the VF (do we have an address
+ * for it?)
+ */
+ if (vf->state == VF_ACQUIRED) {
+ /* mbx_resp uses the op_rc of the VF */
+ vf->op_rc = PFVF_STATUS_NOT_SUPPORTED;
+
+ /* notify the VF that we do not support this request */
+ bnx2x_vf_mbx_resp(bp, vf);
+ } else {
+ /* can't send a response since this VF is unknown to us
+ * just unlock the channel and be done with.
+ */
+ bnx2x_unlock_vf_pf_channel(bp, vf,
+ mbx->first_tlv.tl.type);
+ }
+ }
+}
+
+/* handle new vf-pf message */
+void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event)
+{
+ struct bnx2x_virtf *vf;
+ struct bnx2x_vf_mbx *mbx;
+ u8 vf_idx;
+ int rc;
+
+ DP(BNX2X_MSG_IOV,
+ "vf pf event received: vfid %d, address_hi %x, address lo %x",
+ vfpf_event->vf_id, vfpf_event->msg_addr_hi, vfpf_event->msg_addr_lo);
+ /* Sanity checks consider removing later */
+
+ /* check if the vf_id is valid */
+ if (vfpf_event->vf_id - BP_VFDB(bp)->sriov.first_vf_in_pf >
+ BNX2X_NR_VIRTFN(bp)) {
+ BNX2X_ERR("Illegal vf_id %d max allowed: %d\n",
+ vfpf_event->vf_id, BNX2X_NR_VIRTFN(bp));
+ goto mbx_done;
+ }
+ vf_idx = bnx2x_vf_idx_by_abs_fid(bp, vfpf_event->vf_id);
+ mbx = BP_VF_MBX(bp, vf_idx);
+
+ /* verify an event is not currently being processed -
+ * debug failsafe only
+ */
+ if (mbx->flags & VF_MSG_INPROCESS) {
+ BNX2X_ERR("Previous message is still being processed, vf_id %d\n",
+ vfpf_event->vf_id);
+ goto mbx_done;
+ }
+ vf = BP_VF(bp, vf_idx);
+
+ /* save the VF message address */
+ mbx->vf_addr_hi = vfpf_event->msg_addr_hi;
+ mbx->vf_addr_lo = vfpf_event->msg_addr_lo;
+ DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
+ mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
+
+ /* dmae to get the VF request */
+ rc = bnx2x_copy32_vf_dmae(bp, true, mbx->msg_mapping, vf->abs_vfid,
+ mbx->vf_addr_hi, mbx->vf_addr_lo,
+ sizeof(union vfpf_tlvs)/4);
+ if (rc) {
+ BNX2X_ERR("Failed to copy request VF %d\n", vf->abs_vfid);
+ goto mbx_error;
+ }
+
+ /* process the VF message header */
+ mbx->first_tlv = mbx->msg->req.first_tlv;
+
+ /* dispatch the request (will prepare the response) */
+ bnx2x_vf_mbx_request(bp, vf, mbx);
+ goto mbx_done;
+
+mbx_error:
+ bnx2x_vf_release(bp, vf, false); /* non blocking */
+mbx_done:
+ return;
+}
+
+/* propagate local bulletin board to vf */
+int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf)
+{
+ struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf);
+ dma_addr_t pf_addr = BP_VF_BULLETIN_DMA(bp)->mapping +
+ vf * BULLETIN_CONTENT_SIZE;
+ dma_addr_t vf_addr = bnx2x_vf(bp, vf, bulletin_map);
+ int rc;
+
+ /* can only update vf after init took place */
+ if (bnx2x_vf(bp, vf, state) != VF_ENABLED &&
+ bnx2x_vf(bp, vf, state) != VF_ACQUIRED)
+ return 0;
+
+ /* increment bulletin board version and compute crc */
+ bulletin->version++;
+ bulletin->length = BULLETIN_CONTENT_SIZE;
+ bulletin->crc = bnx2x_crc_vf_bulletin(bp, bulletin);
+
+ /* propagate bulletin board via dmae to vm memory */
+ rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr,
+ bnx2x_vf(bp, vf, abs_vfid), U64_HI(vf_addr),
+ U64_LO(vf_addr), bulletin->length / 4);
+ return rc;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
new file mode 100644
index 000000000000..bfc80baec00d
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
@@ -0,0 +1,360 @@
+/* bnx2x_vfpf.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2011-2013 Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available
+ * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Ariel Elior <ariele@broadcom.com>
+ */
+#ifndef VF_PF_IF_H
+#define VF_PF_IF_H
+
+#ifdef CONFIG_BNX2X_SRIOV
+
+/* Common definitions for all HVs */
+struct vf_pf_resc_request {
+ u8 num_rxqs;
+ u8 num_txqs;
+ u8 num_sbs;
+ u8 num_mac_filters;
+ u8 num_vlan_filters;
+ u8 num_mc_filters; /* No limit so superfluous */
+};
+
+struct hw_sb_info {
+ u8 hw_sb_id; /* aka absolute igu id, used to ack the sb */
+ u8 sb_qid; /* used to update DHC for sb */
+};
+
+/* HW VF-PF channel definitions
+ * A.K.A VF-PF mailbox
+ */
+#define TLV_BUFFER_SIZE 1024
+#define PF_VF_BULLETIN_SIZE 512
+
+#define VFPF_QUEUE_FLG_TPA 0x0001
+#define VFPF_QUEUE_FLG_TPA_IPV6 0x0002
+#define VFPF_QUEUE_FLG_TPA_GRO 0x0004
+#define VFPF_QUEUE_FLG_CACHE_ALIGN 0x0008
+#define VFPF_QUEUE_FLG_STATS 0x0010
+#define VFPF_QUEUE_FLG_OV 0x0020
+#define VFPF_QUEUE_FLG_VLAN 0x0040
+#define VFPF_QUEUE_FLG_COS 0x0080
+#define VFPF_QUEUE_FLG_HC 0x0100
+#define VFPF_QUEUE_FLG_DHC 0x0200
+
+#define VFPF_QUEUE_DROP_IP_CS_ERR (1 << 0)
+#define VFPF_QUEUE_DROP_TCP_CS_ERR (1 << 1)
+#define VFPF_QUEUE_DROP_TTL0 (1 << 2)
+#define VFPF_QUEUE_DROP_UDP_CS_ERR (1 << 3)
+
+#define VFPF_RX_MASK_ACCEPT_NONE 0x00000000
+#define VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST 0x00000001
+#define VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST 0x00000002
+#define VFPF_RX_MASK_ACCEPT_ALL_UNICAST 0x00000004
+#define VFPF_RX_MASK_ACCEPT_ALL_MULTICAST 0x00000008
+#define VFPF_RX_MASK_ACCEPT_BROADCAST 0x00000010
+#define BULLETIN_CONTENT_SIZE (sizeof(struct pf_vf_bulletin_content))
+#define BULLETIN_ATTEMPTS 5 /* crc failures before throwing towel */
+#define BULLETIN_CRC_SEED 0
+
+enum {
+ PFVF_STATUS_WAITING = 0,
+ PFVF_STATUS_SUCCESS,
+ PFVF_STATUS_FAILURE,
+ PFVF_STATUS_NOT_SUPPORTED,
+ PFVF_STATUS_NO_RESOURCE
+};
+
+/* vf pf channel tlvs */
+/* general tlv header (used for both vf->pf request and pf->vf response) */
+struct channel_tlv {
+ u16 type;
+ u16 length;
+};
+
+/* header of first vf->pf tlv carries the offset used to calculate response
+ * buffer address
+ */
+struct vfpf_first_tlv {
+ struct channel_tlv tl;
+ u32 resp_msg_offset;
+};
+
+/* header of pf->vf tlvs, carries the status of handling the request */
+struct pfvf_tlv {
+ struct channel_tlv tl;
+ u8 status;
+ u8 padding[3];
+};
+
+/* response tlv used for most tlvs */
+struct pfvf_general_resp_tlv {
+ struct pfvf_tlv hdr;
+};
+
+/* used to terminate and pad a tlv list */
+struct channel_list_end_tlv {
+ struct channel_tlv tl;
+ u8 padding[4];
+};
+
+/* Acquire */
+struct vfpf_acquire_tlv {
+ struct vfpf_first_tlv first_tlv;
+
+ struct vf_pf_vfdev_info {
+ /* the following fields are for debug purposes */
+ u8 vf_id; /* ME register value */
+ u8 vf_os; /* e.g. Linux, W2K8 */
+ u8 padding[2];
+ } vfdev_info;
+
+ struct vf_pf_resc_request resc_request;
+
+ aligned_u64 bulletin_addr;
+};
+
+/* simple operation request on queue */
+struct vfpf_q_op_tlv {
+ struct vfpf_first_tlv first_tlv;
+ u8 vf_qid;
+ u8 padding[3];
+};
+
+/* acquire response tlv - carries the allocated resources */
+struct pfvf_acquire_resp_tlv {
+ struct pfvf_tlv hdr;
+ struct pf_vf_pfdev_info {
+ u32 chip_num;
+ u32 pf_cap;
+#define PFVF_CAP_RSS 0x00000001
+#define PFVF_CAP_DHC 0x00000002
+#define PFVF_CAP_TPA 0x00000004
+ char fw_ver[32];
+ u16 db_size;
+ u8 indices_per_sb;
+ u8 padding;
+ } pfdev_info;
+ struct pf_vf_resc {
+ /* in case of status NO_RESOURCE in message hdr, pf will fill
+ * this struct with suggested amount of resources for next
+ * acquire request
+ */
+#define PFVF_MAX_QUEUES_PER_VF 16
+#define PFVF_MAX_SBS_PER_VF 16
+ struct hw_sb_info hw_sbs[PFVF_MAX_SBS_PER_VF];
+ u8 hw_qid[PFVF_MAX_QUEUES_PER_VF];
+ u8 num_rxqs;
+ u8 num_txqs;
+ u8 num_sbs;
+ u8 num_mac_filters;
+ u8 num_vlan_filters;
+ u8 num_mc_filters;
+ u8 permanent_mac_addr[ETH_ALEN];
+ u8 current_mac_addr[ETH_ALEN];
+ u8 padding[2];
+ } resc;
+};
+
+/* Init VF */
+struct vfpf_init_tlv {
+ struct vfpf_first_tlv first_tlv;
+ aligned_u64 sb_addr[PFVF_MAX_SBS_PER_VF]; /* vf_sb based */
+ aligned_u64 spq_addr;
+ aligned_u64 stats_addr;
+};
+
+/* Setup Queue */
+struct vfpf_setup_q_tlv {
+ struct vfpf_first_tlv first_tlv;
+
+ struct vf_pf_rxq_params {
+ /* physical addresses */
+ aligned_u64 rcq_addr;
+ aligned_u64 rcq_np_addr;
+ aligned_u64 rxq_addr;
+ aligned_u64 sge_addr;
+
+ /* sb + hc info */
+ u8 vf_sb; /* index in hw_sbs[] */
+ u8 sb_index; /* Index in the SB */
+ u16 hc_rate; /* desired interrupts per sec. */
+ /* valid iff VFPF_QUEUE_FLG_HC */
+ /* rx buffer info */
+ u16 mtu;
+ u16 buf_sz;
+ u16 flags; /* VFPF_QUEUE_FLG_X flags */
+ u16 stat_id; /* valid iff VFPF_QUEUE_FLG_STATS */
+
+ /* valid iff VFPF_QUEUE_FLG_TPA */
+ u16 sge_buf_sz;
+ u16 tpa_agg_sz;
+ u8 max_sge_pkt;
+
+ u8 drop_flags; /* VFPF_QUEUE_DROP_X, for Linux VMs
+ * all the flags are turned off
+ */
+
+ u8 cache_line_log; /* VFPF_QUEUE_FLG_CACHE_ALIGN */
+ u8 padding;
+ } rxq;
+
+ struct vf_pf_txq_params {
+ /* physical addresses */
+ aligned_u64 txq_addr;
+
+ /* sb + hc info */
+ u8 vf_sb; /* index in hw_sbs[] */
+ u8 sb_index; /* Index in the SB */
+ u16 hc_rate; /* desired interrupts per sec. */
+ /* valid iff VFPF_QUEUE_FLG_HC */
+ u32 flags; /* VFPF_QUEUE_FLG_X flags */
+ u16 stat_id; /* valid iff VFPF_QUEUE_FLG_STATS */
+ u8 traffic_type; /* see in setup_context() */
+ u8 padding;
+ } txq;
+
+ u8 vf_qid; /* index in hw_qid[] */
+ u8 param_valid;
+#define VFPF_RXQ_VALID 0x01
+#define VFPF_TXQ_VALID 0x02
+ u8 padding[2];
+};
+
+/* Set Queue Filters */
+struct vfpf_q_mac_vlan_filter {
+ u32 flags;
+#define VFPF_Q_FILTER_DEST_MAC_VALID 0x01
+#define VFPF_Q_FILTER_VLAN_TAG_VALID 0x02
+#define VFPF_Q_FILTER_SET_MAC 0x100 /* set/clear */
+ u8 mac[ETH_ALEN];
+ u16 vlan_tag;
+};
+
+/* configure queue filters */
+struct vfpf_set_q_filters_tlv {
+ struct vfpf_first_tlv first_tlv;
+
+ u32 flags;
+#define VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED 0x01
+#define VFPF_SET_Q_FILTERS_MULTICAST_CHANGED 0x02
+#define VFPF_SET_Q_FILTERS_RX_MASK_CHANGED 0x04
+
+ u8 vf_qid; /* index in hw_qid[] */
+ u8 n_mac_vlan_filters;
+ u8 n_multicast;
+ u8 padding;
+
+#define PFVF_MAX_MAC_FILTERS 16
+#define PFVF_MAX_VLAN_FILTERS 16
+#define PFVF_MAX_FILTERS (PFVF_MAX_MAC_FILTERS +\
+ PFVF_MAX_VLAN_FILTERS)
+ struct vfpf_q_mac_vlan_filter filters[PFVF_MAX_FILTERS];
+
+#define PFVF_MAX_MULTICAST_PER_VF 32
+ u8 multicast[PFVF_MAX_MULTICAST_PER_VF][ETH_ALEN];
+
+ u32 rx_mask; /* see mask constants at the top of the file */
+};
+
+/* close VF (disable VF) */
+struct vfpf_close_tlv {
+ struct vfpf_first_tlv first_tlv;
+ u16 vf_id; /* for debug */
+ u8 padding[2];
+};
+
+/* release the VF's acquired resources */
+struct vfpf_release_tlv {
+ struct vfpf_first_tlv first_tlv;
+ u16 vf_id;
+ u8 padding[2];
+};
+
+struct tlv_buffer_size {
+ u8 tlv_buffer[TLV_BUFFER_SIZE];
+};
+
+union vfpf_tlvs {
+ struct vfpf_first_tlv first_tlv;
+ struct vfpf_acquire_tlv acquire;
+ struct vfpf_init_tlv init;
+ struct vfpf_close_tlv close;
+ struct vfpf_q_op_tlv q_op;
+ struct vfpf_setup_q_tlv setup_q;
+ struct vfpf_set_q_filters_tlv set_q_filters;
+ struct vfpf_release_tlv release;
+ struct channel_list_end_tlv list_end;
+ struct tlv_buffer_size tlv_buf_size;
+};
+
+union pfvf_tlvs {
+ struct pfvf_general_resp_tlv general_resp;
+ struct pfvf_acquire_resp_tlv acquire_resp;
+ struct channel_list_end_tlv list_end;
+ struct tlv_buffer_size tlv_buf_size;
+};
+
+/* This is a structure which is allocated in the VF, which the PF may update
+ * when it deems it necessary to do so. The bulletin board is sampled
+ * periodically by the VF. A copy per VF is maintained in the PF (to prevent
+ * loss of data upon multiple updates (or the need for read modify write)).
+ */
+struct pf_vf_bulletin_size {
+ u8 size[PF_VF_BULLETIN_SIZE];
+};
+
+struct pf_vf_bulletin_content {
+ u32 crc; /* crc of structure to ensure is not in
+ * mid-update
+ */
+ u16 version;
+ u16 length;
+
+ aligned_u64 valid_bitmap; /* bitmap indicating which fields
+ * hold valid values
+ */
+
+#define MAC_ADDR_VALID 0 /* alert the vf that a new mac address
+ * is available for it
+ */
+
+ u8 mac[ETH_ALEN];
+ u8 padding[2];
+};
+
+union pf_vf_bulletin {
+ struct pf_vf_bulletin_content content;
+ struct pf_vf_bulletin_size size;
+};
+
+#define MAX_TLVS_IN_LIST 50
+
+enum channel_tlvs {
+ CHANNEL_TLV_NONE,
+ CHANNEL_TLV_ACQUIRE,
+ CHANNEL_TLV_INIT,
+ CHANNEL_TLV_SETUP_Q,
+ CHANNEL_TLV_SET_Q_FILTERS,
+ CHANNEL_TLV_TEARDOWN_Q,
+ CHANNEL_TLV_CLOSE,
+ CHANNEL_TLV_RELEASE,
+ CHANNEL_TLV_PF_RELEASE_VF,
+ CHANNEL_TLV_LIST_END,
+ CHANNEL_TLV_FLR,
+ CHANNEL_TLV_PF_SET_MAC,
+ CHANNEL_TLV_MAX
+};
+
+#endif /* CONFIG_BNX2X_SRIOV */
+#endif /* VF_PF_IF_H */
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index df8c30d1a52c..149a3a038491 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -4816,6 +4816,8 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
return err;
}
+ ethdev->drv_state |= CNIC_DRV_STATE_HANDLES_IRQ;
+
return 0;
}
@@ -5136,6 +5138,7 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
if (ret)
return ret;
+ ethdev->drv_state |= CNIC_DRV_STATE_HANDLES_IRQ;
return 0;
}
@@ -5387,6 +5390,7 @@ static void cnic_stop_hw(struct cnic_dev *dev)
}
cnic_shutdown_rings(dev);
cp->stop_cm(dev);
+ cp->ethdev->drv_state &= ~CNIC_DRV_STATE_HANDLES_IRQ;
clear_bit(CNIC_F_CNIC_UP, &dev->flags);
RCU_INIT_POINTER(cp->ulp_ops[CNIC_ULP_L4], NULL);
synchronize_rcu();
@@ -5421,11 +5425,9 @@ static struct cnic_dev *cnic_alloc_dev(struct net_device *dev,
alloc_size = sizeof(struct cnic_dev) + sizeof(struct cnic_local);
- cdev = kzalloc(alloc_size , GFP_KERNEL);
- if (cdev == NULL) {
- netdev_err(dev, "allocate dev struct failure\n");
+ cdev = kzalloc(alloc_size, GFP_KERNEL);
+ if (cdev == NULL)
return NULL;
- }
cdev->netdev = dev;
cdev->cnic_priv = (char *)cdev + sizeof(struct cnic_dev);
diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index 2a35436f9095..0c9367a0f57d 100644
--- a/drivers/net/ethernet/broadcom/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
@@ -179,6 +179,7 @@ struct cnic_eth_dev {
#define CNIC_DRV_STATE_NO_ISCSI_OOO 0x00000004
#define CNIC_DRV_STATE_NO_ISCSI 0x00000008
#define CNIC_DRV_STATE_NO_FCOE 0x00000010
+#define CNIC_DRV_STATE_HANDLES_IRQ 0x00000020
u32 chip_id;
u32 max_kwqe_pending;
struct pci_dev *pdev;
diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c
index 3a1c8a3cf7c9..e9b35da375cb 100644
--- a/drivers/net/ethernet/broadcom/sb1250-mac.c
+++ b/drivers/net/ethernet/broadcom/sb1250-mac.c
@@ -2385,7 +2385,7 @@ static int sbmac_mii_probe(struct net_device *dev)
return -ENXIO;
}
- phy_dev = phy_connect(dev, dev_name(&phy_dev->dev), &sbmac_mii_poll, 0,
+ phy_dev = phy_connect(dev, dev_name(&phy_dev->dev), &sbmac_mii_poll,
PHY_INTERFACE_MODE_GMII);
if (IS_ERR(phy_dev)) {
printk(KERN_ERR "%s: could not attach to PHY\n", dev->name);
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index bdb086934cd9..fdb9b5655414 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -4,7 +4,7 @@
* Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
* Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
* Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2005-2012 Broadcom Corporation.
+ * Copyright (C) 2005-2013 Broadcom Corporation.
*
* Firmware is:
* Derived from proprietary unpublished source code,
@@ -44,6 +44,7 @@
#include <linux/prefetch.h>
#include <linux/dma-mapping.h>
#include <linux/firmware.h>
+#include <linux/ssb/ssb_driver_gige.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
@@ -93,10 +94,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
#define DRV_MODULE_NAME "tg3"
#define TG3_MAJ_NUM 3
-#define TG3_MIN_NUM 128
+#define TG3_MIN_NUM 130
#define DRV_MODULE_VERSION \
__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE "December 03, 2012"
+#define DRV_MODULE_RELDATE "February 14, 2013"
#define RESET_KIND_SHUTDOWN 0
#define RESET_KIND_INIT 1
@@ -263,6 +264,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
TG3_DRV_DATA_FLAG_5705_10_100},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5722)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F),
@@ -330,6 +332,10 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
{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_BROADCOM, TG3PCI_DEVICE_TIGON3_57762)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57766)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5762)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5725)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5727)},
{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)},
@@ -570,7 +576,9 @@ 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 (!tg3_flag(tp, MBOX_WRITE_REORDER) && !tg3_flag(tp, ICH_WORKAROUND))
+ if (tg3_flag(tp, FLUSH_POSTED_WRITES) ||
+ (!tg3_flag(tp, MBOX_WRITE_REORDER) &&
+ !tg3_flag(tp, ICH_WORKAROUND)))
tp->read32_mbox(tp, off);
}
@@ -580,7 +588,8 @@ static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
writel(val, mbox);
if (tg3_flag(tp, TXD_MBOX_HWBUG))
writel(val, mbox);
- if (tg3_flag(tp, MBOX_WRITE_REORDER))
+ if (tg3_flag(tp, MBOX_WRITE_REORDER) ||
+ tg3_flag(tp, FLUSH_POSTED_WRITES))
readl(mbox);
}
@@ -609,7 +618,7 @@ 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 (tg3_asic_rev(tp) == ASIC_REV_5906 &&
(off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC))
return;
@@ -634,7 +643,7 @@ 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 (tg3_asic_rev(tp) == ASIC_REV_5906 &&
(off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) {
*val = 0;
return;
@@ -662,7 +671,7 @@ static void tg3_ape_lock_init(struct tg3 *tp)
int i;
u32 regbase, bit;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ if (tg3_asic_rev(tp) == ASIC_REV_5761)
regbase = TG3_APE_LOCK_GRANT;
else
regbase = TG3_APE_PER_LOCK_GRANT;
@@ -698,7 +707,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
switch (locknum) {
case TG3_APE_LOCK_GPIO:
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ if (tg3_asic_rev(tp) == ASIC_REV_5761)
return 0;
case TG3_APE_LOCK_GRC:
case TG3_APE_LOCK_MEM:
@@ -717,7 +726,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
return -EINVAL;
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5761) {
req = TG3_APE_LOCK_REQ;
gnt = TG3_APE_LOCK_GRANT;
} else {
@@ -755,7 +764,7 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
switch (locknum) {
case TG3_APE_LOCK_GPIO:
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ if (tg3_asic_rev(tp) == ASIC_REV_5761)
return;
case TG3_APE_LOCK_GRC:
case TG3_APE_LOCK_MEM:
@@ -774,7 +783,7 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
return;
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ if (tg3_asic_rev(tp) == ASIC_REV_5761)
gnt = TG3_APE_LOCK_GRANT;
else
gnt = TG3_APE_PER_LOCK_GRANT;
@@ -1088,7 +1097,8 @@ static void tg3_switch_clocks(struct tg3 *tp)
#define PHY_BUSY_LOOPS 5000
-static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
+static int __tg3_readphy(struct tg3 *tp, unsigned int phy_addr, int reg,
+ u32 *val)
{
u32 frame_val;
unsigned int loops;
@@ -1104,7 +1114,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
*val = 0x0;
- frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) &
+ frame_val = ((phy_addr << MI_COM_PHY_ADDR_SHIFT) &
MI_COM_PHY_ADDR_MASK);
frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
MI_COM_REG_ADDR_MASK);
@@ -1141,7 +1151,13 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
return ret;
}
-static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
+static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
+{
+ return __tg3_readphy(tp, tp->phy_addr, reg, val);
+}
+
+static int __tg3_writephy(struct tg3 *tp, unsigned int phy_addr, int reg,
+ u32 val)
{
u32 frame_val;
unsigned int loops;
@@ -1159,7 +1175,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
tg3_ape_lock(tp, tp->phy_ape_lock);
- frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) &
+ frame_val = ((phy_addr << MI_COM_PHY_ADDR_SHIFT) &
MI_COM_PHY_ADDR_MASK);
frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
MI_COM_REG_ADDR_MASK);
@@ -1194,6 +1210,11 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
return ret;
}
+static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
+{
+ return __tg3_writephy(tp, tp->phy_addr, reg, val);
+}
+
static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val)
{
int err;
@@ -1458,7 +1479,7 @@ static void tg3_mdio_start(struct tg3 *tp)
udelay(80);
if (tg3_flag(tp, MDIOBUS_INITED) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+ tg3_asic_rev(tp) == ASIC_REV_5785)
tg3_mdio_config_5785(tp);
}
@@ -1473,7 +1494,7 @@ static int tg3_mdio_init(struct tg3 *tp)
tp->phy_addr = tp->pci_fn + 1;
- if (tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
+ if (tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0)
is_serdes = tr32(SG_DIG_STATUS) & SG_DIG_IS_SERDES;
else
is_serdes = tr32(TG3_CPMU_PHY_STRAP) &
@@ -1561,7 +1582,7 @@ static int tg3_mdio_init(struct tg3 *tp)
tg3_flag_set(tp, MDIOBUS_INITED);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+ if (tg3_asic_rev(tp) == ASIC_REV_5785)
tg3_mdio_config_5785(tp);
return 0;
@@ -1778,7 +1799,12 @@ static int tg3_poll_fw(struct tg3 *tp)
int i;
u32 val;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tg3_flag(tp, IS_SSB_CORE)) {
+ /* We don't use firmware. */
+ return 0;
+ }
+
+ if (tg3_asic_rev(tp) == ASIC_REV_5906) {
/* Wait up to 20ms for init done. */
for (i = 0; i < 200; i++) {
if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
@@ -1807,7 +1833,7 @@ static int tg3_poll_fw(struct tg3 *tp)
netdev_info(tp->dev, "No firmware running\n");
}
- if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0) {
/* The 57765 A0 needs a little more
* time to do some important work.
*/
@@ -1937,7 +1963,7 @@ static void tg3_adjust_link(struct net_device *dev)
if (phydev->speed == SPEED_100 || phydev->speed == SPEED_10)
mac_mode |= MAC_MODE_PORT_MODE_MII;
else if (phydev->speed == SPEED_1000 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785)
+ tg3_asic_rev(tp) != ASIC_REV_5785)
mac_mode |= MAC_MODE_PORT_MODE_GMII;
else
mac_mode |= MAC_MODE_PORT_MODE_MII;
@@ -1964,7 +1990,7 @@ static void tg3_adjust_link(struct net_device *dev)
udelay(40);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5785) {
if (phydev->speed == SPEED_10)
tw32(MAC_MI_STAT,
MAC_MI_STAT_10MBPS_MODE |
@@ -2013,8 +2039,8 @@ static int tg3_phy_init(struct tg3 *tp)
phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
/* Attach the MAC to the PHY. */
- phydev = phy_connect(tp->dev, dev_name(&phydev->dev), tg3_adjust_link,
- phydev->dev_flags, phydev->interface);
+ phydev = phy_connect(tp->dev, dev_name(&phydev->dev),
+ tg3_adjust_link, phydev->interface);
if (IS_ERR(phydev)) {
dev_err(&tp->pdev->dev, "Could not attach to PHY\n");
return PTR_ERR(phydev);
@@ -2156,7 +2182,7 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable)
MII_TG3_MISC_SHDW_SCR5_DLPTLM |
MII_TG3_MISC_SHDW_SCR5_SDTL |
MII_TG3_MISC_SHDW_SCR5_C125OE;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 || !enable)
+ if (tg3_asic_rev(tp) != ASIC_REV_5784 || !enable)
reg |= MII_TG3_MISC_SHDW_SCR5_DLLAPD;
tg3_writephy(tp, MII_TG3_MISC_SHDW, reg);
@@ -2311,8 +2337,8 @@ 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 ||
+ (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_asic_rev(tp) == ASIC_REV_5719 ||
tg3_flag(tp, 57765_CLASS)) &&
!tg3_phy_toggle_auxctl_smdsp(tp, true)) {
val = MII_TG3_DSP_TAP26_ALNOKO |
@@ -2516,7 +2542,7 @@ static int tg3_phy_reset(struct tg3 *tp)
u32 val, cpmuctrl;
int err;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5906) {
val = tr32(GRC_MISC_CFG);
tw32_f(GRC_MISC_CFG, val & ~GRC_MISC_CFG_EPHY_IDDQ);
udelay(40);
@@ -2531,9 +2557,9 @@ static int tg3_phy_reset(struct tg3 *tp)
tg3_link_report(tp);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5703 ||
+ tg3_asic_rev(tp) == ASIC_REV_5704 ||
+ tg3_asic_rev(tp) == ASIC_REV_5705) {
err = tg3_phy_reset_5703_4_5(tp);
if (err)
return err;
@@ -2541,8 +2567,8 @@ static int tg3_phy_reset(struct tg3 *tp)
}
cpmuctrl = 0;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
- GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5784 &&
+ tg3_chip_rev(tp) != CHIPREV_5784_AX) {
cpmuctrl = tr32(TG3_CPMU_CTRL);
if (cpmuctrl & CPMU_CTRL_GPHY_10MB_RXONLY)
tw32(TG3_CPMU_CTRL,
@@ -2560,8 +2586,8 @@ static int tg3_phy_reset(struct tg3 *tp)
tw32(TG3_CPMU_CTRL, cpmuctrl);
}
- if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
- GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) {
+ if (tg3_chip_rev(tp) == CHIPREV_5784_AX ||
+ tg3_chip_rev(tp) == CHIPREV_5761_AX) {
val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
if ((val & CPMU_LSPD_1000MB_MACCLK_MASK) ==
CPMU_LSPD_1000MB_MACCLK_12_5) {
@@ -2639,11 +2665,14 @@ out:
val | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5906) {
/* adjust output voltage */
tg3_writephy(tp, MII_TG3_FET_PTEST, 0x12);
}
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5762_A0)
+ tg3_phydsp_write(tp, 0xffb, 0x4000);
+
tg3_phy_toggle_automdix(tp, 1);
tg3_phy_set_wirespeed(tp);
return 0;
@@ -2669,8 +2698,8 @@ static inline u32 tg3_set_function_status(struct tg3 *tp, u32 newstat)
{
u32 status, shift;
- 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_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_asic_rev(tp) == ASIC_REV_5719)
status = tg3_ape_read32(tp, TG3_APE_GPIO_MSG);
else
status = tr32(TG3_CPMU_DRV_STATUS);
@@ -2679,8 +2708,8 @@ static inline u32 tg3_set_function_status(struct tg3 *tp, u32 newstat)
status &= ~(TG3_GPIO_MSG_MASK << shift);
status |= (newstat << shift);
- 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_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_asic_rev(tp) == ASIC_REV_5719)
tg3_ape_write32(tp, TG3_APE_GPIO_MSG, status);
else
tw32(TG3_CPMU_DRV_STATUS, status);
@@ -2693,9 +2722,9 @@ static inline int tg3_pwrsrc_switch_to_vmain(struct tg3 *tp)
if (!tg3_flag(tp, IS_NIC))
return 0;
- 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_5720) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720) {
if (tg3_ape_lock(tp, TG3_APE_LOCK_GPIO))
return -EIO;
@@ -2718,8 +2747,8 @@ static void tg3_pwrsrc_die_with_vmain(struct tg3 *tp)
u32 grc_local_ctrl;
if (!tg3_flag(tp, IS_NIC) ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
+ tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701)
return;
grc_local_ctrl = tp->grc_local_ctrl | GRC_LCLCTRL_GPIO_OE1;
@@ -2742,8 +2771,8 @@ static void tg3_pwrsrc_switch_to_vaux(struct tg3 *tp)
if (!tg3_flag(tp, IS_NIC))
return;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701) {
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
(GRC_LCLCTRL_GPIO_OE0 |
GRC_LCLCTRL_GPIO_OE1 |
@@ -2775,7 +2804,7 @@ static void tg3_pwrsrc_switch_to_vaux(struct tg3 *tp)
u32 grc_local_ctrl = 0;
/* Workaround to prevent overdrawing Amps. */
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5714) {
grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
grc_local_ctrl,
@@ -2847,9 +2876,9 @@ static void tg3_frob_aux_power(struct tg3 *tp, bool include_wol)
if (!tg3_flag(tp, IS_NIC) || tg3_flag(tp, 57765_CLASS))
return;
- 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_5720) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720) {
tg3_frob_aux_power_5717(tp, include_wol ?
tg3_flag(tp, WOL_ENABLE) != 0 : 0);
return;
@@ -2901,7 +2930,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
u32 val;
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5704) {
u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
u32 serdes_cfg = tr32(MAC_SERDES_CFG);
@@ -2913,7 +2942,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
return;
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5906) {
tg3_bmcr_reset(tp);
val = tr32(GRC_MISC_CFG);
tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
@@ -2952,16 +2981,16 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
/* The PHY should not be powered down on some chips because
* of bugs.
*/
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
+ if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5704 ||
+ (tg3_asic_rev(tp) == ASIC_REV_5780 &&
(tp->phy_flags & TG3_PHYFLG_MII_SERDES)) ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
+ (tg3_asic_rev(tp) == ASIC_REV_5717 &&
!tp->pci_fn))
return;
- if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
- GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) {
+ if (tg3_chip_rev(tp) == CHIPREV_5784_AX ||
+ tg3_chip_rev(tp) == CHIPREV_5761_AX) {
val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
val |= CPMU_LSPD_1000MB_MACCLK_12_5;
@@ -3344,7 +3373,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
!tg3_flag(tp, 57765_PLUS))
tw32(NVRAM_ADDR, phy_addr);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
+ if (tg3_asic_rev(tp) != ASIC_REV_5752 &&
!tg3_flag(tp, 5755_PLUS) &&
(tp->nvram_jedecnum == JEDEC_ST) &&
(nvram_cmd & NVRAM_CMD_FIRST)) {
@@ -3429,7 +3458,7 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5906) {
u32 val = tr32(GRC_VCPU_EXT_CTRL);
tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
@@ -3447,6 +3476,13 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
tw32_f(offset + CPU_MODE, CPU_MODE_HALT);
udelay(10);
} else {
+ /*
+ * There is only an Rx CPU for the 5750 derivative in the
+ * BCM4785.
+ */
+ if (tg3_flag(tp, IS_SSB_CORE))
+ return 0;
+
for (i = 0; i < 10000; i++) {
tw32(offset + CPU_STATE, 0xffffffff);
tw32(offset + CPU_MODE, CPU_MODE_HALT);
@@ -3600,7 +3636,7 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
info.fw_len = tp->fw->size - 12;
info.fw_data = &fw_data[3];
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5705) {
cpu_base = RX_CPU_BASE;
cpu_scratch_base = NIC_SRAM_MBUF_POOL_BASE5705;
} else {
@@ -3658,8 +3694,8 @@ static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5703 ||
+ tg3_asic_rev(tp) == ASIC_REV_5704) {
for (i = 0; i < 12; i++) {
tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
@@ -3778,7 +3814,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
tg3_setup_phy(tp, 0);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5906) {
u32 val;
val = tr32(GRC_VCPU_EXT_CTRL);
@@ -3820,8 +3856,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
mac_mode = MAC_MODE_PORT_MODE_MII;
mac_mode |= tp->mac_mode & MAC_MODE_LINK_POLARITY;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
- ASIC_REV_5700) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5700) {
u32 speed = tg3_flag(tp, WOL_SPEED_100MB) ?
SPEED_100 : SPEED_10;
if (tg3_5700_link_polarity(tp, speed))
@@ -3854,8 +3889,8 @@ static int tg3_power_down_prepare(struct tg3 *tp)
}
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)) {
+ (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701)) {
u32 base_val;
base_val = tp->pci_clock_ctrl;
@@ -3866,13 +3901,13 @@ static int tg3_power_down_prepare(struct tg3 *tp)
CLOCK_CTRL_PWRDOWN_PLL133, 40);
} else if (tg3_flag(tp, 5780_CLASS) ||
tg3_flag(tp, CPMU_PRESENT) ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ tg3_asic_rev(tp) == ASIC_REV_5906) {
/* do nothing */
} 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 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701) {
newbits1 = (CLOCK_CTRL_RXCLK_DISABLE |
CLOCK_CTRL_TXCLK_DISABLE |
CLOCK_CTRL_ALTCLK);
@@ -3894,8 +3929,8 @@ static int tg3_power_down_prepare(struct tg3 *tp)
if (!tg3_flag(tp, 5705_PLUS)) {
u32 newbits3;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701) {
newbits3 = (CLOCK_CTRL_RXCLK_DISABLE |
CLOCK_CTRL_TXCLK_DISABLE |
CLOCK_CTRL_44MHZ_CORE);
@@ -3914,8 +3949,9 @@ static int tg3_power_down_prepare(struct tg3 *tp)
tg3_frob_aux_power(tp, true);
/* Workaround for unstable PLL clock */
- if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) ||
- (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) {
+ if ((!tg3_flag(tp, IS_SSB_CORE)) &&
+ ((tg3_chip_rev(tp) == CHIPREV_5750_AX) ||
+ (tg3_chip_rev(tp) == CHIPREV_5750_BX))) {
u32 val = tr32(0x7d00);
val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1);
@@ -4006,8 +4042,8 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
new_adv = ethtool_adv_to_mii_ctrl1000_t(advertise);
- if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
- tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B0)
new_adv |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
err = tg3_writephy(tp, MII_CTRL1000, new_adv);
@@ -4036,7 +4072,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
if (err)
val = 0;
- switch (GET_ASIC_REV(tp->pci_chip_rev_id)) {
+ switch (tg3_asic_rev(tp)) {
case ASIC_REV_5717:
case ASIC_REV_57765:
case ASIC_REV_57766:
@@ -4049,6 +4085,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val);
/* Fall through */
case ASIC_REV_5720:
+ case ASIC_REV_5762:
if (!tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val))
tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2, val |
MII_TG3_DSP_CH34TP2_HIBW01);
@@ -4183,8 +4220,8 @@ static bool tg3_phy_copper_an_config_ok(struct tg3 *tp, u32 *lcladv)
return false;
if (tgtadv &&
- (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
- tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) {
+ (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B0)) {
tgtadv |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL |
CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER);
@@ -4268,9 +4305,9 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
/* Some third-party PHYs need to be reset on link going
* down.
*/
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
+ if ((tg3_asic_rev(tp) == ASIC_REV_5703 ||
+ tg3_asic_rev(tp) == ASIC_REV_5704 ||
+ tg3_asic_rev(tp) == ASIC_REV_5705) &&
tp->link_up) {
tg3_readphy(tp, MII_BMSR, &bmsr);
if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
@@ -4312,8 +4349,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
return err;
}
}
- } else if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
- tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
+ } else if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B0) {
/* 5701 {A0,B0} CRC bug workaround */
tg3_writephy(tp, 0x15, 0x0a75);
tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8c68);
@@ -4330,8 +4367,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
else if (!(tp->phy_flags & TG3_PHYFLG_IS_FET))
tg3_writephy(tp, MII_TG3_IMASK, ~0);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701) {
if (tp->led_ctrl == LED_CTRL_MODE_PHY_1)
tg3_writephy(tp, MII_TG3_EXT_CTRL,
MII_TG3_EXT_CTRL_LNK3_LED_MODE);
@@ -4435,6 +4472,15 @@ relink:
if (current_link_up == 0 || (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
tg3_phy_copper_begin(tp);
+ if (tg3_flag(tp, ROBOSWITCH)) {
+ current_link_up = 1;
+ /* FIXME: when BCM5325 switch is used use 100 MBit/s */
+ current_speed = SPEED_1000;
+ current_duplex = DUPLEX_FULL;
+ tp->link_config.active_speed = current_speed;
+ tp->link_config.active_duplex = current_duplex;
+ }
+
tg3_readphy(tp, MII_BMSR, &bmsr);
if ((!tg3_readphy(tp, MII_BMSR, &bmsr) && (bmsr & BMSR_LSTATUS)) ||
(tp->mac_mode & MAC_MODE_PORT_INT_LPBACK))
@@ -4453,11 +4499,31 @@ relink:
else
tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+ /* In order for the 5750 core in BCM4785 chip to work properly
+ * in RGMII mode, the Led Control Register must be set up.
+ */
+ if (tg3_flag(tp, RGMII_MODE)) {
+ u32 led_ctrl = tr32(MAC_LED_CTRL);
+ led_ctrl &= ~(LED_CTRL_1000MBPS_ON | LED_CTRL_100MBPS_ON);
+
+ if (tp->link_config.active_speed == SPEED_10)
+ led_ctrl |= LED_CTRL_LNKLED_OVERRIDE;
+ else if (tp->link_config.active_speed == SPEED_100)
+ led_ctrl |= (LED_CTRL_LNKLED_OVERRIDE |
+ LED_CTRL_100MBPS_ON);
+ else if (tp->link_config.active_speed == SPEED_1000)
+ led_ctrl |= (LED_CTRL_LNKLED_OVERRIDE |
+ LED_CTRL_1000MBPS_ON);
+
+ tw32(MAC_LED_CTRL, led_ctrl);
+ udelay(40);
+ }
+
tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
if (tp->link_config.active_duplex == DUPLEX_HALF)
tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5700) {
if (current_link_up == 1 &&
tg3_5700_link_polarity(tp, tp->link_config.active_speed))
tp->mac_mode |= MAC_MODE_LINK_POLARITY;
@@ -4469,7 +4535,7 @@ relink:
* ??? send/receive packets...
*/
if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5411 &&
- tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5700_ALTIMA) {
tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
@@ -4488,7 +4554,7 @@ relink:
}
udelay(40);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
+ if (tg3_asic_rev(tp) == ASIC_REV_5700 &&
current_link_up == 1 &&
tp->link_config.active_speed == SPEED_1000 &&
(tg3_flag(tp, PCIX_MODE) || tg3_flag(tp, PCI_HIGH_SPEED))) {
@@ -4943,8 +5009,8 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
port_a = 1;
current_link_up = 0;
- if (tp->pci_chip_rev_id != CHIPREV_ID_5704_A0 &&
- tp->pci_chip_rev_id != CHIPREV_ID_5704_A1) {
+ if (tg3_chip_rev_id(tp) != CHIPREV_ID_5704_A0 &&
+ tg3_chip_rev_id(tp) != CHIPREV_ID_5704_A1) {
workaround = 1;
if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
port_a = 0;
@@ -5273,7 +5339,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
err |= tg3_readphy(tp, MII_BMSR, &bmsr);
err |= tg3_readphy(tp, MII_BMSR, &bmsr);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5714) {
if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
bmsr |= BMSR_LSTATUS;
else
@@ -5342,8 +5408,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
bmcr = new_bmcr;
err |= tg3_readphy(tp, MII_BMSR, &bmsr);
err |= tg3_readphy(tp, MII_BMSR, &bmsr);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
- ASIC_REV_5714) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5714) {
if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
bmsr |= BMSR_LSTATUS;
else
@@ -5478,7 +5543,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
else
err = tg3_setup_copper_phy(tp, force_reset);
- if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) {
+ if (tg3_chip_rev(tp) == CHIPREV_5784_AX) {
u32 scale;
val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK;
@@ -5496,7 +5561,8 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) |
(6 << TX_LENGTHS_IPG_SHIFT);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
val |= tr32(MAC_TX_LENGTHS) &
(TX_LENGTHS_JMB_FRM_LEN_MSK |
TX_LENGTHS_CNT_DWN_VAL_MSK);
@@ -5785,10 +5851,8 @@ static void tg3_dump_state(struct tg3 *tp)
u32 *regs;
regs = kzalloc(TG3_REG_BLK_SIZE, GFP_ATOMIC);
- if (!regs) {
- netdev_err(tp->dev, "Failed allocating register dump buffer\n");
+ if (!regs)
return;
- }
if (tg3_flag(tp, PCI_EXPRESS)) {
/* Read up to but not including private PCI registers */
@@ -7122,7 +7186,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
dma_addr_t new_addr = 0;
int ret = 0;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
+ if (tg3_asic_rev(tp) != ASIC_REV_5701)
new_skb = skb_copy(skb, GFP_ATOMIC);
else {
int more_headroom = 4 - ((unsigned long)skb->data & 3);
@@ -7296,7 +7360,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
} 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) {
+ tg3_asic_rev(tp) == ASIC_REV_5705) {
if (tcp_opt_len || iph->ihl > 5) {
int tsflags;
@@ -7452,7 +7516,7 @@ static void tg3_mac_loopback(struct tg3 *tp, bool enable)
if (tg3_flag(tp, 5705_PLUS) ||
(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+ tg3_asic_rev(tp) == ASIC_REV_5700)
tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
}
@@ -7511,7 +7575,7 @@ static int tg3_phy_lpbk_set(struct tg3 *tp, u32 speed, bool extlpbk)
udelay(40);
if ((tp->phy_flags & TG3_PHYFLG_IS_FET) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+ tg3_asic_rev(tp) == ASIC_REV_5785) {
tg3_writephy(tp, MII_TG3_FET_PTEST, ptest |
MII_TG3_FET_PTEST_FRC_TX_LINK |
MII_TG3_FET_PTEST_FRC_TX_LOCK);
@@ -7535,7 +7599,7 @@ static int tg3_phy_lpbk_set(struct tg3 *tp, u32 speed, bool extlpbk)
else
mac_mode |= MAC_MODE_PORT_MODE_MII;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5700) {
u32 masked_phy_id = tp->phy_id & TG3_PHY_ID_MASK;
if (masked_phy_id == TG3_PHY_ID_BCM5401)
@@ -8213,7 +8277,7 @@ 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 &&
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5704_A0 &&
tg3_flag(tp, PCIX_MODE))
val |= PCISTATE_RETRY_SAME_DMA;
/* Allow reads and writes to the APE register and memory space. */
@@ -8285,7 +8349,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 ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5752 ||
tg3_flag(tp, 5755_PLUS))
tw32(GRC_FASTBOOT_PC, 0);
@@ -8320,7 +8384,7 @@ static int tg3_chip_reset(struct tg3 *tp)
for (i = 0; i < tp->irq_cnt; i++)
synchronize_irq(tp->napi[i].irq_vec);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
+ if (tg3_asic_rev(tp) == ASIC_REV_57780) {
val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN;
tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS);
}
@@ -8330,19 +8394,19 @@ static int tg3_chip_reset(struct tg3 *tp)
if (tg3_flag(tp, PCI_EXPRESS)) {
/* Force PCIe 1.0a mode */
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+ if (tg3_asic_rev(tp) != ASIC_REV_5785 &&
!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);
- if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
+ if (tg3_chip_rev_id(tp) != CHIPREV_ID_5750_A0) {
tw32(GRC_MISC_CFG, (1 << 29));
val |= (1 << 29);
}
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5906) {
tw32(VCPU_STATUS, tr32(VCPU_STATUS) | VCPU_STATUS_DRV_RESET);
tw32(GRC_VCPU_EXT_CTRL,
tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU);
@@ -8385,7 +8449,7 @@ static int tg3_chip_reset(struct tg3 *tp)
if (tg3_flag(tp, PCI_EXPRESS) && pci_is_pcie(tp->pdev)) {
u16 val16;
- if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) {
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5750_A0) {
int j;
u32 cfg_val;
@@ -8426,23 +8490,33 @@ static int tg3_chip_reset(struct tg3 *tp)
val = tr32(MEMARB_MODE);
tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
- if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5750_A3) {
tg3_stop_fw(tp);
tw32(0x5000, 0x400);
}
+ if (tg3_flag(tp, IS_SSB_CORE)) {
+ /*
+ * BCM4785: In order to avoid repercussions from using
+ * potentially defective internal ROM, stop the Rx RISC CPU,
+ * which is not required.
+ */
+ tg3_stop_fw(tp);
+ tg3_halt_cpu(tp, RX_CPU_BASE);
+ }
+
tw32(GRC_MODE, tp->grc_mode);
- if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A0) {
val = tr32(0xc4);
tw32(0xc4, val | (1 << 15));
}
if ((tp->nic_sram_data_cfg & NIC_SRAM_DATA_CFG_MINI_PCI) != 0 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+ tg3_asic_rev(tp) == ASIC_REV_5705) {
tp->pci_clock_ctrl |= CLOCK_CTRL_CLKRUN_OENABLE;
- if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0)
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A0)
tp->pci_clock_ctrl |= CLOCK_CTRL_FORCE_CLKRUN;
tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
}
@@ -8468,15 +8542,15 @@ static int tg3_chip_reset(struct tg3 *tp)
tg3_mdio_start(tp);
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 &&
+ tg3_chip_rev_id(tp) != CHIPREV_ID_5750_A0 &&
+ tg3_asic_rev(tp) != ASIC_REV_5785 &&
!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) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5720) {
val = tr32(TG3_CPMU_CLCK_ORIDE);
tw32(TG3_CPMU_CLCK_ORIDE, val & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN);
}
@@ -8687,7 +8761,8 @@ static void tg3_rings_reset(struct tg3 *tp)
limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16;
else if (tg3_flag(tp, 5717_PLUS))
limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 4;
- else if (tg3_flag(tp, 57765_CLASS))
+ else if (tg3_flag(tp, 57765_CLASS) ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2;
else
limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE;
@@ -8703,7 +8778,8 @@ static void tg3_rings_reset(struct tg3 *tp)
limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17;
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 ||
+ else if (tg3_asic_rev(tp) == ASIC_REV_5755 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762 ||
tg3_flag(tp, 57765_CLASS))
limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 4;
else
@@ -8809,12 +8885,12 @@ static void tg3_setup_rxbd_thresholds(struct tg3 *tp)
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 ||
+ tg3_asic_rev(tp) == ASIC_REV_5750 ||
+ tg3_asic_rev(tp) == ASIC_REV_5752 ||
tg3_flag(tp, 57765_PLUS))
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)
+ else if (tg3_asic_rev(tp) == ASIC_REV_5755 ||
+ tg3_asic_rev(tp) == ASIC_REV_5787)
bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5755;
else
bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5906;
@@ -8994,9 +9070,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
/* Enable MAC control of LPI */
if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
- tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL,
- TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
- TG3_CPMU_EEE_LNKIDL_UART_IDL);
+ val = TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
+ TG3_CPMU_EEE_LNKIDL_UART_IDL;
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0)
+ val |= TG3_CPMU_EEE_LNKIDL_APE_TX_MT;
+
+ tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL, val);
tw32_f(TG3_CPMU_EEE_CTRL,
TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
@@ -9006,7 +9085,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
TG3_CPMU_EEEMD_LPI_IN_RX |
TG3_CPMU_EEEMD_EEE_ENABLE;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+ if (tg3_asic_rev(tp) != ASIC_REV_5717)
val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;
if (tg3_flag(tp, ENABLE_APE))
@@ -9032,7 +9111,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tg3_write_sig_legacy(tp, RESET_KIND_INIT);
- if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) {
+ if (tg3_chip_rev(tp) == CHIPREV_5784_AX) {
val = tr32(TG3_CPMU_CTRL);
val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE);
tw32(TG3_CPMU_CTRL, val);
@@ -9053,7 +9132,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3_CPMU_HST_ACC, val);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
+ if (tg3_asic_rev(tp) == ASIC_REV_57780) {
val = tr32(PCIE_PWR_MGMT_THRESH) & ~PCIE_PWR_MGMT_L1_THRESH_MSK;
val |= PCIE_PWR_MGMT_EXT_ASPM_TMR_EN |
PCIE_PWR_MGMT_L1_THRESH_4MS;
@@ -9083,7 +9162,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
}
if (tg3_flag(tp, 57765_CLASS)) {
- if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0) {
u32 grc_mode = tr32(GRC_MODE);
/* Access the lower 1K of PL PCIE block registers. */
@@ -9098,8 +9177,15 @@ 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);
+ if (tg3_chip_rev(tp) != CHIPREV_57765_AX) {
+ u32 grc_mode;
+
+ /* Fix transmit hangs */
+ val = tr32(TG3_CPMU_PADRNG_CTL);
+ val |= TG3_CPMU_PADRNG_CTL_RDIV2;
+ tw32(TG3_CPMU_PADRNG_CTL, val);
+
+ grc_mode = tr32(GRC_MODE);
/* Access the lower 1K of DL PCIE block registers. */
val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK;
@@ -9131,7 +9217,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
}
- if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5704_A0 &&
tg3_flag(tp, PCIX_MODE)) {
val = tr32(TG3PCI_PCISTATE);
val |= PCISTATE_RETRY_SAME_DMA;
@@ -9149,7 +9235,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3PCI_PCISTATE, val);
}
- if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) {
+ if (tg3_chip_rev(tp) == CHIPREV_5704_BX) {
/* Enable some hw fixes. */
val = tr32(TG3PCI_MSI_DATA);
val |= (1 << 26) | (1 << 28) | (1 << 29);
@@ -9168,14 +9254,15 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
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)
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0)
val &= ~DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK;
if (!tg3_flag(tp, 57765_CLASS) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+ tg3_asic_rev(tp) != ASIC_REV_5717 &&
+ tg3_asic_rev(tp) != ASIC_REV_5762)
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) {
+ } else if (tg3_asic_rev(tp) != ASIC_REV_5784 &&
+ tg3_asic_rev(tp) != ASIC_REV_5761) {
/* This value is determined during the probe time DMA
* engine test, tg3_test_dma.
*/
@@ -9215,9 +9302,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
/* Initialize MBUF/DESC pool. */
if (tg3_flag(tp, 5750_PLUS)) {
/* Do nothing. */
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+ } else if (tg3_asic_rev(tp) != ASIC_REV_5705) {
tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+ if (tg3_asic_rev(tp) == ASIC_REV_5704)
tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64);
else
tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
@@ -9255,11 +9342,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tp->bufmgr_config.dma_high_water);
val = BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ if (tg3_asic_rev(tp) == 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)
+ if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5720_A0)
val |= BUFMGR_MODE_MBLOW_ATTN_ENAB;
tw32(BUFMGR_MODE, val);
for (i = 0; i < 2000; i++) {
@@ -9272,7 +9359,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
return -ENODEV;
}
- if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1)
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5906_A1)
tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2);
tg3_setup_rxbd_thresholds(tp);
@@ -9310,7 +9397,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
/* Program the jumbo buffer descriptor ring control
* blocks on those devices that have them.
*/
- if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 ||
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0 ||
(tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS))) {
if (tg3_flag(tp, JUMBO_RING_ENABLE)) {
@@ -9323,7 +9410,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
val | BDINFO_FLAGS_USE_EXT_RECV);
if (!tg3_flag(tp, USE_JUMBO_BDFLAG) ||
- tg3_flag(tp, 57765_CLASS))
+ tg3_flag(tp, 57765_CLASS) ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
NIC_SRAM_RX_JUMBO_BUFFER_DESC);
} else {
@@ -9365,7 +9453,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
(6 << TX_LENGTHS_IPG_SHIFT) |
(32 << TX_LENGTHS_SLOT_TIME_SHIFT);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
val |= tr32(MAC_TX_LENGTHS) &
(TX_LENGTHS_JMB_FRM_LEN_MSK |
TX_LENGTHS_CNT_DWN_VAL_MSK);
@@ -9385,20 +9474,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
RDMAC_MODE_LNGREAD_ENAB);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ if (tg3_asic_rev(tp) == ASIC_REV_5717)
rdmac_mode |= RDMAC_MODE_MULT_DMA_RD_DIS;
- if (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)
+ if (tg3_asic_rev(tp) == ASIC_REV_5784 ||
+ tg3_asic_rev(tp) == ASIC_REV_5785 ||
+ tg3_asic_rev(tp) == ASIC_REV_57780)
rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB |
RDMAC_MODE_MBUF_RBD_CRPT_ENAB |
RDMAC_MODE_MBUF_SBD_CRPT_ENAB;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
- tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5705 &&
+ tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) {
if (tg3_flag(tp, TSO_CAPABLE) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+ tg3_asic_rev(tp) == ASIC_REV_5705) {
rdmac_mode |= RDMAC_MODE_FIFO_SIZE_128;
} else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
!tg3_flag(tp, IS_5788)) {
@@ -9409,26 +9498,43 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (tg3_flag(tp, PCI_EXPRESS))
rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
+ if (tg3_asic_rev(tp) == ASIC_REV_57766) {
+ tp->dma_limit = 0;
+ if (tp->dev->mtu <= ETH_DATA_LEN) {
+ rdmac_mode |= RDMAC_MODE_JMB_2K_MMRR;
+ tp->dma_limit = TG3_TX_BD_DMA_MAX_2K;
+ }
+ }
+
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 (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)
+ tg3_asic_rev(tp) == ASIC_REV_5785 ||
+ tg3_asic_rev(tp) == ASIC_REV_57780)
rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
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 ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5761 ||
+ tg3_asic_rev(tp) == ASIC_REV_5784 ||
+ tg3_asic_rev(tp) == ASIC_REV_5785 ||
+ tg3_asic_rev(tp) == ASIC_REV_57780 ||
tg3_flag(tp, 57765_PLUS)) {
- val = tr32(TG3_RDMA_RSRVCTRL_REG);
- if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) {
+ u32 tgtreg;
+
+ if (tg3_asic_rev(tp) == ASIC_REV_5762)
+ tgtreg = TG3_RDMA_RSRVCTRL_REG2;
+ else
+ tgtreg = TG3_RDMA_RSRVCTRL_REG;
+
+ val = tr32(tgtreg);
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762) {
val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK |
TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK |
TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK);
@@ -9436,14 +9542,21 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
TG3_RDMA_RSRVCTRL_FIFO_LWM_1_5K |
TG3_RDMA_RSRVCTRL_FIFO_HWM_1_5K;
}
- tw32(TG3_RDMA_RSRVCTRL_REG,
- val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
+ tw32(tgtreg, val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
}
- 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 |
+ if (tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762) {
+ u32 tgtreg;
+
+ if (tg3_asic_rev(tp) == ASIC_REV_5762)
+ tgtreg = TG3_LSO_RD_DMA_CRPTEN_CTRL2;
+ else
+ tgtreg = TG3_LSO_RD_DMA_CRPTEN_CTRL;
+
+ val = tr32(tgtreg);
+ tw32(tgtreg, val |
TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K |
TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K);
}
@@ -9520,7 +9633,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tp->mac_mode |= MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
if (!tg3_flag(tp, 5705_PLUS) &&
!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
+ tg3_asic_rev(tp) != ASIC_REV_5700)
tp->mac_mode |= MAC_MODE_LINK_POLARITY;
tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
udelay(40);
@@ -9538,11 +9651,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 |
GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_GPIO_OUTPUT2;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+ if (tg3_asic_rev(tp) == ASIC_REV_5752)
gpio_mask |= GRC_LCLCTRL_GPIO_OE3 |
GRC_LCLCTRL_GPIO_OUTPUT3;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+ if (tg3_asic_rev(tp) == ASIC_REV_5755)
gpio_mask |= GRC_LCLCTRL_GPIO_UART_SEL;
tp->grc_local_ctrl &= ~gpio_mask;
@@ -9577,11 +9690,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
WDMAC_MODE_LNGREAD_ENAB);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
- tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5705 &&
+ tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) {
if (tg3_flag(tp, TSO_CAPABLE) &&
- (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 ||
- tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) {
+ (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A1 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A2)) {
/* nothing */
} else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
!tg3_flag(tp, IS_5788)) {
@@ -9593,7 +9706,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (tg3_flag(tp, 5755_PLUS))
val |= WDMAC_MODE_STATUS_TAG_FIX;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+ if (tg3_asic_rev(tp) == ASIC_REV_5785)
val |= WDMAC_MODE_BURST_ALL_DATA;
tw32_f(WDMAC_MODE, val);
@@ -9604,10 +9717,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
&pcix_cmd);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5703) {
pcix_cmd &= ~PCI_X_CMD_MAX_READ;
pcix_cmd |= PCI_X_CMD_READ_2K;
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+ } else if (tg3_asic_rev(tp) == ASIC_REV_5704) {
pcix_cmd &= ~(PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ);
pcix_cmd |= PCI_X_CMD_READ_2K;
}
@@ -9618,7 +9731,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32_f(RDMAC_MODE, rdmac_mode);
udelay(40);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5719) {
for (i = 0; i < TG3_NUM_RDMA_CHANNELS; i++) {
if (tr32(TG3_RDMA_LENGTH + (i << 2)) > TG3_MAX_MTU(tp))
break;
@@ -9635,7 +9748,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (!tg3_flag(tp, 5705_PLUS))
tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ if (tg3_asic_rev(tp) == ASIC_REV_5761)
tw32(SNDDATAC_MODE,
SNDDATAC_MODE_ENABLE | SNDDATAC_MODE_CDELAY);
else
@@ -9658,7 +9771,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(SNDBDI_MODE, val);
tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE);
- if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) {
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
err = tg3_load_5701_a0_firmware_fix(tp);
if (err)
return err;
@@ -9673,10 +9786,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tp->tx_mode = TX_MODE_ENABLE;
if (tg3_flag(tp, 5755_PLUS) ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ tg3_asic_rev(tp) == ASIC_REV_5906)
tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762) {
val = TX_MODE_JMB_FRM_LEN | TX_MODE_CNT_DN_MODE;
tp->tx_mode &= ~val;
tp->tx_mode |= tr32(MAC_TX_MODE) & val;
@@ -9727,8 +9841,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
udelay(10);
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
- !(tp->phy_flags & TG3_PHYFLG_SERDES_PREEMPHASIS)) {
+ if ((tg3_asic_rev(tp) == ASIC_REV_5704) &&
+ !(tp->phy_flags & TG3_PHYFLG_SERDES_PREEMPHASIS)) {
/* Set drive transmission level to 1.2V */
/* only if the signal pre-emphasis bit is not set */
val = tr32(MAC_SERDES_CFG);
@@ -9736,7 +9850,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
val |= 0x880;
tw32(MAC_SERDES_CFG, val);
}
- if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5703_A1)
tw32(MAC_SERDES_CFG, 0x616000);
}
@@ -9749,14 +9863,14 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
val = 2;
tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, val);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
+ if (tg3_asic_rev(tp) == ASIC_REV_5704 &&
(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
/* Use hardware link auto-negotiation */
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) {
+ tg3_asic_rev(tp) == ASIC_REV_5714) {
u32 tmp;
tmp = tr32(SERDES_RX_CTRL);
@@ -10010,9 +10124,9 @@ 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);
- 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) {
+ if (tg3_asic_rev(tp) != ASIC_REV_5717 &&
+ tg3_chip_rev_id(tp) != CHIPREV_ID_5719_A0 &&
+ tg3_chip_rev_id(tp) != CHIPREV_ID_5720_A0) {
TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT);
} else {
u32 val = tr32(HOSTCC_FLOW_ATTN);
@@ -10060,10 +10174,15 @@ static void tg3_timer(unsigned long __opaque)
spin_lock(&tp->lock);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
tg3_flag(tp, 57765_CLASS))
tg3_chk_missed_msi(tp);
+ if (tg3_flag(tp, FLUSH_POSTED_WRITES)) {
+ /* BCM4785: Flush posted writes from GbE to host memory. */
+ tr32(HOSTCC_MODE);
+ }
+
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
@@ -10181,7 +10300,7 @@ restart_timer:
static void tg3_timer_init(struct tg3 *tp)
{
if (tg3_flag(tp, TAGGED_STATUS) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+ tg3_asic_rev(tp) != ASIC_REV_5717 &&
!tg3_flag(tp, 57765_CLASS))
tp->timer_offset = HZ;
else
@@ -10762,7 +10881,7 @@ static int tg3_open(struct net_device *dev)
if (tp->fw_needed) {
err = tg3_request_firmware(tp);
- if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) {
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
if (err)
return err;
} else if (err) {
@@ -10832,8 +10951,8 @@ static u64 tg3_calc_crc_errors(struct tg3 *tp)
struct tg3_hw_stats *hw_stats = tp->hw_stats;
if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
+ (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701)) {
u32 val;
if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) {
@@ -12357,11 +12476,12 @@ static int tg3_test_memory(struct tg3 *tp)
if (tg3_flag(tp, 5717_PLUS))
mem_tbl = mem_tbl_5717;
- else if (tg3_flag(tp, 57765_CLASS))
+ else if (tg3_flag(tp, 57765_CLASS) ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
mem_tbl = mem_tbl_57765;
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)
+ else if (tg3_asic_rev(tp) == ASIC_REV_5906)
mem_tbl = mem_tbl_5906;
else if (tg3_flag(tp, 5705_PLUS))
mem_tbl = mem_tbl_5705;
@@ -12473,7 +12593,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback)
} 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) {
+ tg3_asic_rev(tp) == ASIC_REV_5705) {
mss |= (TG3_TSO_TCP_OPT_LEN << 9);
} else {
base_flags |= (TG3_TSO_TCP_OPT_LEN << 10);
@@ -12659,7 +12779,7 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
* errata. Also, the MAC loopback test is deprecated for
* all newer ASIC revisions.
*/
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780 &&
+ if (tg3_asic_rev(tp) != ASIC_REV_5780 &&
!tg3_flag(tp, CPMU_PRESENT)) {
tg3_mac_loopback(tp, true);
@@ -12937,7 +13057,8 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EAGAIN;
spin_lock_bh(&tp->lock);
- err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
+ err = __tg3_readphy(tp, data->phy_id & 0x1f,
+ data->reg_num & 0x1f, &mii_regval);
spin_unlock_bh(&tp->lock);
data->val_out = mii_regval;
@@ -12953,7 +13074,8 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EAGAIN;
spin_lock_bh(&tp->lock);
- err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in);
+ err = __tg3_writephy(tp, data->phy_id & 0x1f,
+ data->reg_num & 0x1f, data->val_in);
spin_unlock_bh(&tp->lock);
return err;
@@ -13144,7 +13266,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
/* Reset PHY, otherwise the read DMA engine will be in a mode that
* breaks all requests to 256 bytes.
*/
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
+ if (tg3_asic_rev(tp) == ASIC_REV_57766)
reset_phy = 1;
err = tg3_restart_hw(tp, reset_phy);
@@ -13257,7 +13379,7 @@ static void tg3_get_nvram_info(struct tg3 *tp)
tw32(NVRAM_CFG1, nvcfg1);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5750 ||
tg3_flag(tp, 5780_CLASS)) {
switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
@@ -13698,6 +13820,22 @@ static void tg3_get_5720_nvram_info(struct tg3 *tp)
nvcfg1 = tr32(NVRAM_CFG1);
nvmpinstrp = nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK;
+ if (tg3_asic_rev(tp) == ASIC_REV_5762) {
+ if (!(nvcfg1 & NVRAM_CFG1_5762VENDOR_MASK)) {
+ tg3_flag_set(tp, NO_NVRAM);
+ return;
+ }
+
+ switch (nvmpinstrp) {
+ case FLASH_5762_EEPROM_HD:
+ nvmpinstrp = FLASH_5720_EEPROM_HD;
+ break;
+ case FLASH_5762_EEPROM_LD:
+ nvmpinstrp = FLASH_5720_EEPROM_LD;
+ break;
+ }
+ }
+
switch (nvmpinstrp) {
case FLASH_5720_EEPROM_HD:
case FLASH_5720_EEPROM_LD:
@@ -13743,7 +13881,8 @@ static void tg3_get_5720_nvram_info(struct tg3 *tp)
tp->nvram_size = TG3_NVRAM_SIZE_1MB;
break;
default:
- tp->nvram_size = TG3_NVRAM_SIZE_128KB;
+ if (tg3_asic_rev(tp) != ASIC_REV_5762)
+ tp->nvram_size = TG3_NVRAM_SIZE_128KB;
break;
}
break;
@@ -13789,7 +13928,8 @@ static void tg3_get_5720_nvram_info(struct tg3 *tp)
tp->nvram_size = TG3_NVRAM_SIZE_1MB;
break;
default:
- tp->nvram_size = TG3_NVRAM_SIZE_128KB;
+ if (tg3_asic_rev(tp) != ASIC_REV_5762)
+ tp->nvram_size = TG3_NVRAM_SIZE_128KB;
break;
}
break;
@@ -13801,11 +13941,30 @@ static void tg3_get_5720_nvram_info(struct tg3 *tp)
tg3_nvram_get_pagesize(tp, nvcfg1);
if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528)
tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS);
+
+ if (tg3_asic_rev(tp) == ASIC_REV_5762) {
+ u32 val;
+
+ if (tg3_nvram_read(tp, 0, &val))
+ return;
+
+ if (val != TG3_EEPROM_MAGIC &&
+ (val & TG3_EEPROM_MAGIC_FW_MSK) != TG3_EEPROM_MAGIC_FW)
+ tg3_flag_set(tp, NO_NVRAM);
+ }
}
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
static void tg3_nvram_init(struct tg3 *tp)
{
+ if (tg3_flag(tp, IS_SSB_CORE)) {
+ /* No NVRAM and EEPROM on the SSB Broadcom GigE core. */
+ tg3_flag_clear(tp, NVRAM);
+ tg3_flag_clear(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, NO_NVRAM);
+ return;
+ }
+
tw32_f(GRC_EEPROM_ADDR,
(EEPROM_ADDR_FSM_RESET |
(EEPROM_DEFAULT_CLOCK_PERIOD <<
@@ -13818,8 +13977,8 @@ static void tg3_nvram_init(struct tg3 *tp)
tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM);
udelay(100);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
+ if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
+ tg3_asic_rev(tp) != ASIC_REV_5701) {
tg3_flag_set(tp, NVRAM);
if (tg3_nvram_lock(tp)) {
@@ -13832,25 +13991,26 @@ static void tg3_nvram_init(struct tg3 *tp)
tp->nvram_size = 0;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+ if (tg3_asic_rev(tp) == ASIC_REV_5752)
tg3_get_5752_nvram_info(tp);
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+ else if (tg3_asic_rev(tp) == ASIC_REV_5755)
tg3_get_5755_nvram_info(tp);
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+ else if (tg3_asic_rev(tp) == ASIC_REV_5787 ||
+ tg3_asic_rev(tp) == ASIC_REV_5784 ||
+ tg3_asic_rev(tp) == ASIC_REV_5785)
tg3_get_5787_nvram_info(tp);
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ else if (tg3_asic_rev(tp) == ASIC_REV_5761)
tg3_get_5761_nvram_info(tp);
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ else if (tg3_asic_rev(tp) == ASIC_REV_5906)
tg3_get_5906_nvram_info(tp);
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+ else if (tg3_asic_rev(tp) == ASIC_REV_57780 ||
tg3_flag(tp, 57765_CLASS))
tg3_get_57780_nvram_info(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_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_asic_rev(tp) == ASIC_REV_5719)
tg3_get_5717_nvram_info(tp);
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ else if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
tg3_get_5720_nvram_info(tp);
else
tg3_get_nvram_info(tp);
@@ -13963,7 +14123,7 @@ static void tg3_get_eeprom_hw_cfg(struct tg3 *tp)
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 (tg3_asic_rev(tp) == ASIC_REV_5906) {
if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM)) {
tg3_flag_clear(tp, EEPROM_WRITE_PROT);
tg3_flag_set(tp, IS_NIC);
@@ -13990,13 +14150,13 @@ static void 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 (tg3_asic_rev(tp) != ASIC_REV_5700 &&
+ tg3_asic_rev(tp) != ASIC_REV_5701 &&
+ tg3_asic_rev(tp) != ASIC_REV_5703 &&
(ver > 0) && (ver < 0x100))
tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+ if (tg3_asic_rev(tp) == ASIC_REV_5785)
tg3_read_mem(tp, NIC_SRAM_DATA_CFG_4, &cfg4);
if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
@@ -14044,18 +14204,16 @@ static void tg3_get_eeprom_hw_cfg(struct tg3 *tp)
/* Default to PHY_1_MODE if 0 (MAC_MODE) is
* read on some older 5700/5701 bootcode.
*/
- if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
- ASIC_REV_5700 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) ==
- ASIC_REV_5701)
+ if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701)
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
break;
case SHASTA_EXT_LED_SHARED:
tp->led_ctrl = LED_CTRL_MODE_SHARED;
- if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
- tp->pci_chip_rev_id != CHIPREV_ID_5750_A1)
+ if (tg3_chip_rev_id(tp) != CHIPREV_ID_5750_A0 &&
+ tg3_chip_rev_id(tp) != CHIPREV_ID_5750_A1)
tp->led_ctrl |= (LED_CTRL_MODE_PHY_1 |
LED_CTRL_MODE_PHY_2);
break;
@@ -14066,19 +14224,19 @@ static void tg3_get_eeprom_hw_cfg(struct tg3 *tp)
case SHASTA_EXT_LED_COMBO:
tp->led_ctrl = LED_CTRL_MODE_COMBO;
- if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0)
+ if (tg3_chip_rev_id(tp) != CHIPREV_ID_5750_A0)
tp->led_ctrl |= (LED_CTRL_MODE_PHY_1 |
LED_CTRL_MODE_PHY_2);
break;
}
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) &&
+ if ((tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701) &&
tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
tp->led_ctrl = LED_CTRL_MODE_PHY_2;
- if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX)
+ if (tg3_chip_rev(tp) == CHIPREV_5784_AX)
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) {
@@ -14122,13 +14280,13 @@ static void tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->phy_flags |= TG3_PHYFLG_SERDES_PREEMPHASIS;
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)) &&
+ (tg3_asic_rev(tp) == ASIC_REV_5784 &&
+ tg3_chip_rev(tp) != CHIPREV_5784_AX)) &&
(cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN))
tp->phy_flags |= TG3_PHYFLG_ENABLE_APD;
if (tg3_flag(tp, PCI_EXPRESS) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+ tg3_asic_rev(tp) != ASIC_REV_5785 &&
!tg3_flag(tp, 57765_PLUS)) {
u32 cfg3;
@@ -14152,6 +14310,39 @@ done:
device_set_wakeup_capable(&tp->pdev->dev, false);
}
+static int tg3_ape_otp_read(struct tg3 *tp, u32 offset, u32 *val)
+{
+ int i, err;
+ u32 val2, off = offset * 8;
+
+ err = tg3_nvram_lock(tp);
+ if (err)
+ return err;
+
+ tg3_ape_write32(tp, TG3_APE_OTP_ADDR, off | APE_OTP_ADDR_CPU_ENABLE);
+ tg3_ape_write32(tp, TG3_APE_OTP_CTRL, APE_OTP_CTRL_PROG_EN |
+ APE_OTP_CTRL_CMD_RD | APE_OTP_CTRL_START);
+ tg3_ape_read32(tp, TG3_APE_OTP_CTRL);
+ udelay(10);
+
+ for (i = 0; i < 100; i++) {
+ val2 = tg3_ape_read32(tp, TG3_APE_OTP_STATUS);
+ if (val2 & APE_OTP_STATUS_CMD_DONE) {
+ *val = tg3_ape_read32(tp, TG3_APE_OTP_RD_DATA);
+ break;
+ }
+ udelay(10);
+ }
+
+ tg3_ape_write32(tp, TG3_APE_OTP_CTRL, 0);
+
+ tg3_nvram_unlock(tp);
+ if (val2 & APE_OTP_STATUS_CMD_DONE)
+ return 0;
+
+ return -EBUSY;
+}
+
static int tg3_issue_otp_command(struct tg3 *tp, u32 cmd)
{
int i;
@@ -14298,10 +14489,19 @@ static int tg3_phy_probe(struct tg3 *tp)
* subsys device table.
*/
p = tg3_lookup_by_subsys(tp);
- if (!p)
+ if (p) {
+ tp->phy_id = p->phy_id;
+ } else if (!tg3_flag(tp, IS_SSB_CORE)) {
+ /* For now we saw the IDs 0xbc050cd0,
+ * 0xbc050f80 and 0xbc050c30 on devices
+ * connected to an BCM4785 and there are
+ * probably more. Just assume that the phy is
+ * supported when it is connected to a SSB core
+ * for now.
+ */
return -ENODEV;
+ }
- tp->phy_id = p->phy_id;
if (!tp->phy_id ||
tp->phy_id == TG3_PHY_ID_BCM8002)
tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
@@ -14309,12 +14509,13 @@ static int tg3_phy_probe(struct tg3 *tp)
}
if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720 ||
- (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 &&
- tp->pci_chip_rev_id != CHIPREV_ID_5717_A0) ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
- tp->pci_chip_rev_id != CHIPREV_ID_57765_A0)))
+ (tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762 ||
+ (tg3_asic_rev(tp) == ASIC_REV_5717 &&
+ tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0) ||
+ (tg3_asic_rev(tp) == ASIC_REV_57765 &&
+ tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0)))
tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
tg3_phy_init_link_config(tp);
@@ -14424,7 +14625,7 @@ out_not_found:
return;
out_no_vpd:
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5717) {
if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717_C)
strcpy(tp->board_part_number, "BCM5717");
@@ -14432,7 +14633,7 @@ out_no_vpd:
strcpy(tp->board_part_number, "BCM5718");
else
goto nomatch;
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
+ } else if (tg3_asic_rev(tp) == ASIC_REV_57780) {
if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57780)
strcpy(tp->board_part_number, "BCM57780");
else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57760)
@@ -14443,7 +14644,7 @@ out_no_vpd:
strcpy(tp->board_part_number, "BCM57788");
else
goto nomatch;
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+ } else if (tg3_asic_rev(tp) == ASIC_REV_57765) {
if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761)
strcpy(tp->board_part_number, "BCM57761");
else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765)
@@ -14458,7 +14659,7 @@ out_no_vpd:
strcpy(tp->board_part_number, "BCM57795");
else
goto nomatch;
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766) {
+ } else if (tg3_asic_rev(tp) == ASIC_REV_57766) {
if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57762)
strcpy(tp->board_part_number, "BCM57762");
else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57766)
@@ -14469,7 +14670,7 @@ out_no_vpd:
strcpy(tp->board_part_number, "BCM57786");
else
goto nomatch;
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ } else if (tg3_asic_rev(tp) == ASIC_REV_5906) {
strcpy(tp->board_part_number, "BCM95906");
} else {
nomatch:
@@ -14691,6 +14892,8 @@ static void tg3_read_dash_ver(struct tg3 *tp)
if (tg3_flag(tp, APE_HAS_NCSI))
fwtype = "NCSI";
+ else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5725)
+ fwtype = "SMASH";
else
fwtype = "DASH";
@@ -14704,6 +14907,31 @@ static void tg3_read_dash_ver(struct tg3 *tp)
(apedata & APE_FW_VERSION_BLDMSK));
}
+static void tg3_read_otp_ver(struct tg3 *tp)
+{
+ u32 val, val2;
+
+ if (tg3_asic_rev(tp) != ASIC_REV_5762)
+ return;
+
+ if (!tg3_ape_otp_read(tp, OTP_ADDRESS_MAGIC0, &val) &&
+ !tg3_ape_otp_read(tp, OTP_ADDRESS_MAGIC0 + 4, &val2) &&
+ TG3_OTP_MAGIC0_VALID(val)) {
+ u64 val64 = (u64) val << 32 | val2;
+ u32 ver = 0;
+ int i, vlen;
+
+ for (i = 0; i < 7; i++) {
+ if ((val64 & 0xff) == 0)
+ break;
+ ver = val64 & 0xff;
+ val64 >>= 8;
+ }
+ vlen = strlen(tp->fw_ver);
+ snprintf(&tp->fw_ver[vlen], TG3_VER_SIZE - vlen, " .%02d", ver);
+ }
+}
+
static void tg3_read_fw_ver(struct tg3 *tp)
{
u32 val;
@@ -14714,6 +14942,7 @@ static void tg3_read_fw_ver(struct tg3 *tp)
if (tg3_flag(tp, NO_NVRAM)) {
strcat(tp->fw_ver, "sb");
+ tg3_read_otp_ver(tp);
return;
}
@@ -14788,7 +15017,7 @@ static struct pci_dev *tg3_find_peer(struct tg3 *tp)
static void tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg)
{
tp->pci_chip_rev_id = misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
+ if (tg3_asic_rev(tp) == ASIC_REV_USE_PROD_ID_REG) {
u32 reg;
/* All devices that use the alternate
@@ -14800,7 +15029,10 @@ static void tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg)
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717_C ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720)
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5762 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5725 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5727)
reg = TG3PCI_GEN2_PRODID_ASICREV;
else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 ||
@@ -14822,46 +15054,47 @@ static void tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg)
/* Wrong chip ID in 5752 A0. This code can be removed later
* as A0 is not in production.
*/
- if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5752_A0_HW)
tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;
- if (tp->pci_chip_rev_id == CHIPREV_ID_5717_C0)
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5717_C0)
tp->pci_chip_rev_id = CHIPREV_ID_5720_A0;
- 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_5720)
+ if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720)
tg3_flag_set(tp, 5717_PLUS);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766)
+ if (tg3_asic_rev(tp) == ASIC_REV_57765 ||
+ tg3_asic_rev(tp) == ASIC_REV_57766)
tg3_flag_set(tp, 57765_CLASS);
- if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS))
+ if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS) ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
tg3_flag_set(tp, 57765_PLUS);
/* Intentionally exclude ASIC_REV_5906 */
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- 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 ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5755 ||
+ tg3_asic_rev(tp) == ASIC_REV_5787 ||
+ tg3_asic_rev(tp) == ASIC_REV_5784 ||
+ tg3_asic_rev(tp) == ASIC_REV_5761 ||
+ tg3_asic_rev(tp) == ASIC_REV_5785 ||
+ tg3_asic_rev(tp) == ASIC_REV_57780 ||
tg3_flag(tp, 57765_PLUS))
tg3_flag_set(tp, 5755_PLUS);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
+ if (tg3_asic_rev(tp) == ASIC_REV_5780 ||
+ tg3_asic_rev(tp) == ASIC_REV_5714)
tg3_flag_set(tp, 5780_CLASS);
- 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 ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5750 ||
+ tg3_asic_rev(tp) == ASIC_REV_5752 ||
+ tg3_asic_rev(tp) == ASIC_REV_5906 ||
tg3_flag(tp, 5755_PLUS) ||
tg3_flag(tp, 5780_CLASS))
tg3_flag_set(tp, 5750_PLUS);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5705 ||
tg3_flag(tp, 5750_PLUS))
tg3_flag_set(tp, 5705_PLUS);
}
@@ -14871,13 +15104,13 @@ static bool tg3_10_100_only_device(struct tg3 *tp,
{
u32 grc_misc_cfg = tr32(GRC_MISC_CFG) & GRC_MISC_CFG_BOARD_ID_MASK;
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
- (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
+ if ((tg3_asic_rev(tp) == ASIC_REV_5703 &&
+ (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
(tp->phy_flags & TG3_PHYFLG_IS_FET))
return true;
if (ent->driver_data & TG3_DRV_DATA_FLAG_10_100_ONLY) {
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5705) {
if (ent->driver_data & TG3_DRV_DATA_FLAG_5705_10_100)
return true;
} else {
@@ -14938,8 +15171,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
* enable this workaround if the 5703 is on the secondary
* bus of these ICH bridges.
*/
- if ((tp->pci_chip_rev_id == CHIPREV_ID_5703_A1) ||
- (tp->pci_chip_rev_id == CHIPREV_ID_5703_A2)) {
+ if ((tg3_chip_rev_id(tp) == CHIPREV_ID_5703_A1) ||
+ (tg3_chip_rev_id(tp) == CHIPREV_ID_5703_A2)) {
static struct tg3_dev_id {
u32 vendor;
u32 device;
@@ -14979,7 +15212,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
}
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5701) {
static struct tg3_dev_id {
u32 vendor;
u32 device;
@@ -15039,29 +15272,29 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
} while (bridge);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)
+ if (tg3_asic_rev(tp) == ASIC_REV_5704 ||
+ tg3_asic_rev(tp) == ASIC_REV_5714)
tp->pdev_peer = tg3_find_peer(tp);
/* Determine TSO capabilities */
- if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0)
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0)
; /* Do nothing. HW bug. */
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)
+ tg3_asic_rev(tp) == ASIC_REV_5906)
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)
+ if (tg3_asic_rev(tp) == ASIC_REV_5750 &&
+ tg3_chip_rev_id(tp) >= CHIPREV_ID_5750_C2)
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) {
+ } else if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
+ tg3_asic_rev(tp) != ASIC_REV_5701 &&
+ tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) {
tg3_flag_set(tp, TSO_BUG);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+ if (tg3_asic_rev(tp) == ASIC_REV_5705)
tp->fw_needed = FIRMWARE_TG3TSO5;
else
tp->fw_needed = FIRMWARE_TG3TSO;
@@ -15083,22 +15316,22 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
tp->fw_needed = NULL;
}
- if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0)
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0)
tp->fw_needed = FIRMWARE_TG3;
tp->irq_max = 1;
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 &&
+ if (tg3_chip_rev(tp) == CHIPREV_5750_AX ||
+ tg3_chip_rev(tp) == CHIPREV_5750_BX ||
+ (tg3_asic_rev(tp) == ASIC_REV_5714 &&
+ tg3_chip_rev_id(tp) <= CHIPREV_ID_5714_A2 &&
tp->pdev_peer == tp->pdev))
tg3_flag_clear(tp, SUPPORT_MSI);
if (tg3_flag(tp, 5755_PLUS) ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ tg3_asic_rev(tp) == ASIC_REV_5906) {
tg3_flag_set(tp, 1SHOT_MSI);
}
@@ -15114,25 +15347,26 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
tp->rxq_max = TG3_RSS_MAX_NUM_QS;
tg3_rss_init_dflt_indir_tbl(tp, TG3_RSS_MAX_NUM_QS);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ if (tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720)
tp->txq_max = tp->irq_max - 1;
}
if (tg3_flag(tp, 5755_PLUS) ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ tg3_asic_rev(tp) == ASIC_REV_5906)
tg3_flag_set(tp, SHORT_DMA_BUG);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ if (tg3_asic_rev(tp) == ASIC_REV_5719)
tp->dma_limit = TG3_TX_BD_DMA_MAX_4K;
- 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_5720)
+ if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
tg3_flag_set(tp, LRG_PROD_RING_CAP);
if (tg3_flag(tp, 57765_PLUS) &&
- tp->pci_chip_rev_id != CHIPREV_ID_5719_A0)
+ tg3_chip_rev_id(tp) != CHIPREV_ID_5719_A0)
tg3_flag_set(tp, USE_JUMBO_BDFLAG);
if (!tg3_flag(tp, 5705_PLUS) ||
@@ -15150,20 +15384,19 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
pcie_capability_read_word(tp->pdev, PCI_EXP_LNKCTL, &lnkctl);
if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) {
- if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
- ASIC_REV_5906) {
+ if (tg3_asic_rev(tp) == 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)
+ if (tg3_asic_rev(tp) == ASIC_REV_5784 ||
+ tg3_asic_rev(tp) == ASIC_REV_5761 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_57780_A0 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_57780_A1)
tg3_flag_set(tp, CLKREQ_BUG);
- } else if (tp->pci_chip_rev_id == CHIPREV_ID_5717_A0) {
+ } else if (tg3_chip_rev_id(tp) == CHIPREV_ID_5717_A0) {
tg3_flag_set(tp, L1PLLPD_EN);
}
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+ } else if (tg3_asic_rev(tp) == ASIC_REV_5785) {
/* BCM5785 devices are effectively PCIe devices, and should
* follow PCIe codepaths, but do not have a PCIe capabilities
* section.
@@ -15196,7 +15429,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
&tp->pci_cacheline_sz);
pci_read_config_byte(tp->pdev, PCI_LATENCY_TIMER,
&tp->pci_lat_timer);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
+ if (tg3_asic_rev(tp) == ASIC_REV_5703 &&
tp->pci_lat_timer < 64) {
tp->pci_lat_timer = 64;
pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER,
@@ -15206,7 +15439,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
/* Important! -- It is critical that the PCI-X hw workaround
* situation is decided before the first MMIO register access.
*/
- if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) {
+ if (tg3_chip_rev(tp) == CHIPREV_5700_BX) {
/* 5700 BX chips need to have their TX producer index
* mailboxes written twice to workaround a bug.
*/
@@ -15248,7 +15481,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
tg3_flag_set(tp, PCI_32BIT);
/* Chip-specific fixup from Broadcom driver */
- if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) &&
+ if ((tg3_chip_rev_id(tp) == CHIPREV_ID_5704_A0) &&
(!(pci_state_reg & PCISTATE_RETRY_SAME_DMA))) {
pci_state_reg |= PCISTATE_RETRY_SAME_DMA;
pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
@@ -15265,9 +15498,9 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
/* Various workaround register access methods */
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 ||
+ else if (tg3_asic_rev(tp) == ASIC_REV_5701 ||
(tg3_flag(tp, PCI_EXPRESS) &&
- tp->pci_chip_rev_id == CHIPREV_ID_5750_A0)) {
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5750_A0)) {
/*
* Back to back register writes can cause problems on these
* chips, the workaround is to read back all reg writes
@@ -15299,7 +15532,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
pci_cmd &= ~PCI_COMMAND_MEMORY;
pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5906) {
tp->read32_mbox = tg3_read32_mbox_5906;
tp->write32_mbox = tg3_write32_mbox_5906;
tp->write32_tx_mbox = tg3_write32_mbox_5906;
@@ -15308,8 +15541,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
if (tp->write32 == tg3_write_indirect_reg32 ||
(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)))
+ (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701)))
tg3_flag_set(tp, SRAM_USE_CONFIG);
/* The memory arbiter has to be enabled in order for SRAM accesses
@@ -15321,7 +15554,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
tp->pci_fn = PCI_FUNC(tp->pdev->devfn) & 3;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5704 ||
tg3_flag(tp, 5780_CLASS)) {
if (tg3_flag(tp, PCIX_MODE)) {
pci_read_config_dword(tp->pdev,
@@ -15329,21 +15562,23 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
&val);
tp->pci_fn = val & 0x7;
}
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
+ } else if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720) {
tg3_read_mem(tp, NIC_SRAM_CPMU_STATUS, &val);
- if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) ==
- NIC_SRAM_CPMUSTAT_SIG) {
- tp->pci_fn = val & TG3_CPMU_STATUS_FMSK_5717;
- tp->pci_fn = tp->pci_fn ? 1 : 0;
- }
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
- tg3_read_mem(tp, NIC_SRAM_CPMU_STATUS, &val);
- if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) ==
- NIC_SRAM_CPMUSTAT_SIG) {
+ if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) != NIC_SRAM_CPMUSTAT_SIG)
+ val = tr32(TG3_CPMU_STATUS);
+
+ if (tg3_asic_rev(tp) == ASIC_REV_5717)
+ tp->pci_fn = (val & TG3_CPMU_STATUS_FMSK_5717) ? 1 : 0;
+ else
tp->pci_fn = (val & TG3_CPMU_STATUS_FMSK_5719) >>
TG3_CPMU_STATUS_FSHFT_5719;
- }
+ }
+
+ if (tg3_flag(tp, FLUSH_POSTED_WRITES)) {
+ tp->write32_tx_mbox = tg3_write_flush_reg32;
+ tp->write32_rx_mbox = tg3_write_flush_reg32;
}
/* Get eeprom hw config before calling tg3_set_power_state().
@@ -15381,18 +15616,18 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
* 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 ||
+ if (tg3_asic_rev(tp) == 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
* are no pull-up resistors on unused GPIO pins.
*/
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+ else if (tg3_asic_rev(tp) == ASIC_REV_5752)
tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5755 ||
+ tg3_asic_rev(tp) == ASIC_REV_57780 ||
tg3_flag(tp, 57765_CLASS))
tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
@@ -15406,6 +15641,10 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
GRC_LCLCTRL_GPIO_OUTPUT0;
}
+ if (tg3_asic_rev(tp) == ASIC_REV_5762)
+ tp->grc_local_ctrl |=
+ tr32(GRC_LOCAL_CTRL) & GRC_LCLCTRL_GPIO_UART_SEL;
+
/* Switch out of Vaux if it is a NIC */
tg3_pwrsrc_switch_to_vmain(tp);
@@ -15416,42 +15655,42 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
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) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B0 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B2) {
tg3_flag_clear(tp, WOL_SPEED_100MB);
} else {
tg3_flag_set(tp, WOL_SPEED_100MB);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ if (tg3_asic_rev(tp) == 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 &&
- (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
- (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ (tg3_asic_rev(tp) == ASIC_REV_5705 &&
+ (tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) &&
+ (tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A1)) ||
(tp->phy_flags & TG3_PHYFLG_IS_FET) ||
(tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
tp->phy_flags |= TG3_PHYFLG_NO_ETH_WIRE_SPEED;
- if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5703_AX ||
- GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_AX)
+ if (tg3_chip_rev(tp) == CHIPREV_5703_AX ||
+ tg3_chip_rev(tp) == CHIPREV_5704_AX)
tp->phy_flags |= TG3_PHYFLG_ADC_BUG;
- if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5704_A0)
tp->phy_flags |= TG3_PHYFLG_5704_A0_BUG;
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 &&
+ tg3_asic_rev(tp) != ASIC_REV_5785 &&
+ tg3_asic_rev(tp) != ASIC_REV_57780 &&
!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 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5755 ||
+ tg3_asic_rev(tp) == ASIC_REV_5787 ||
+ tg3_asic_rev(tp) == ASIC_REV_5784 ||
+ tg3_asic_rev(tp) == ASIC_REV_5761) {
if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 &&
tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722)
tp->phy_flags |= TG3_PHYFLG_JITTER_BUG;
@@ -15461,8 +15700,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
tp->phy_flags |= TG3_PHYFLG_BER_BUG;
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
- GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5784 &&
+ tg3_chip_rev(tp) != CHIPREV_5784_AX) {
tp->phy_otp = tg3_read_otp_phycfg(tp);
if (tp->phy_otp == 0)
tp->phy_otp = TG3_OTP_DEFAULT;
@@ -15474,20 +15713,20 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
tp->mi_mode = MAC_MI_MODE_BASE;
tp->coalesce_mode = 0;
- if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
- GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
+ if (tg3_chip_rev(tp) != CHIPREV_5700_AX &&
+ tg3_chip_rev(tp) != 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) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5719_A0 ||
+ tg3_chip_rev_id(tp) == 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)
+ if (tg3_asic_rev(tp) == ASIC_REV_5785 ||
+ tg3_asic_rev(tp) == ASIC_REV_57780)
tg3_flag_set(tp, USE_PHYLIB);
err = tg3_mdio_init(tp);
@@ -15496,7 +15735,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
/* Initialize data/descriptor byte/word swapping. */
val = tr32(GRC_MODE);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ if (tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
val &= (GRC_MODE_BYTE_SWAP_B2HRX_DATA |
GRC_MODE_WORD_SWAP_B2HRX_DATA |
GRC_MODE_B2HRX_ENABLE |
@@ -15516,12 +15756,10 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
&pci_state_reg);
if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0 &&
!tg3_flag(tp, PCIX_TARGET_HWBUG)) {
- u32 chiprevid = GET_CHIP_REV_ID(tp->misc_host_ctrl);
-
- if (chiprevid == CHIPREV_ID_5701_A0 ||
- chiprevid == CHIPREV_ID_5701_B0 ||
- chiprevid == CHIPREV_ID_5701_B2 ||
- chiprevid == CHIPREV_ID_5701_B5) {
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B0 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B2 ||
+ tg3_chip_rev_id(tp) == CHIPREV_ID_5701_B5) {
void __iomem *sram_base;
/* Write some dummy words into the SRAM status block
@@ -15544,13 +15782,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
grc_misc_cfg = tr32(GRC_MISC_CFG);
grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
+ if (tg3_asic_rev(tp) == ASIC_REV_5705 &&
(grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 ||
grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
tg3_flag_set(tp, IS_5788);
if (!tg3_flag(tp, IS_5788) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
+ tg3_asic_rev(tp) != ASIC_REV_5700)
tg3_flag_set(tp, TAGGED_STATUS);
if (tg3_flag(tp, TAGGED_STATUS)) {
tp->coalesce_mode |= (HOSTCC_MODE_CLRTICK_RXBD |
@@ -15583,7 +15821,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
tp->phy_flags &= ~TG3_PHYFLG_USE_MI_INTERRUPT;
} else {
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+ if (tg3_asic_rev(tp) == ASIC_REV_5700)
tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT;
else
tp->phy_flags &= ~TG3_PHYFLG_USE_MI_INTERRUPT;
@@ -15593,7 +15831,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
* change bit implementation, so we must use the
* status register in those cases.
*/
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+ if (tg3_asic_rev(tp) == ASIC_REV_5700)
tg3_flag_set(tp, USE_LINKCHG_REG);
else
tg3_flag_clear(tp, USE_LINKCHG_REG);
@@ -15603,7 +15841,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
* upon subsystem IDs.
*/
if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
+ tg3_asic_rev(tp) == ASIC_REV_5701 &&
!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT;
tg3_flag_set(tp, USE_LINKCHG_REG);
@@ -15617,7 +15855,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
tp->rx_offset = NET_SKB_PAD + NET_IP_ALIGN;
tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
+ if (tg3_asic_rev(tp) == ASIC_REV_5701 &&
tg3_flag(tp, PCIX_MODE)) {
tp->rx_offset = NET_SKB_PAD;
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
@@ -15634,9 +15872,9 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
/* Increment the rx prod index on the rx std ring by at most
* 8 for these chips to workaround hw errata.
*/
- 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_5755)
+ if (tg3_asic_rev(tp) == ASIC_REV_5750 ||
+ tg3_asic_rev(tp) == ASIC_REV_5752 ||
+ tg3_asic_rev(tp) == ASIC_REV_5755)
tp->rx_std_max_post = 8;
if (tg3_flag(tp, ASPM_WORKAROUND))
@@ -15658,7 +15896,6 @@ static int tg3_get_macaddr_sparc(struct tg3 *tp)
addr = of_get_property(dp, "local-mac-address", &len);
if (addr && len == 6) {
memcpy(dev->dev_addr, addr, 6);
- memcpy(dev->perm_addr, dev->dev_addr, 6);
return 0;
}
return -ENODEV;
@@ -15669,7 +15906,6 @@ static int tg3_get_default_macaddr_sparc(struct tg3 *tp)
struct net_device *dev = tp->dev;
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
- memcpy(dev->perm_addr, idprom->id_ethaddr, 6);
return 0;
}
#endif
@@ -15679,14 +15915,21 @@ static int tg3_get_device_address(struct tg3 *tp)
struct net_device *dev = tp->dev;
u32 hi, lo, mac_offset;
int addr_ok = 0;
+ int err;
#ifdef CONFIG_SPARC
if (!tg3_get_macaddr_sparc(tp))
return 0;
#endif
+ if (tg3_flag(tp, IS_SSB_CORE)) {
+ err = ssb_gige_get_macaddr(tp->pdev, &dev->dev_addr[0]);
+ if (!err && is_valid_ether_addr(&dev->dev_addr[0]))
+ return 0;
+ }
+
mac_offset = 0x7c;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
+ if (tg3_asic_rev(tp) == ASIC_REV_5704 ||
tg3_flag(tp, 5780_CLASS)) {
if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
mac_offset = 0xcc;
@@ -15699,7 +15942,7 @@ static int tg3_get_device_address(struct tg3 *tp)
mac_offset = 0xcc;
if (tp->pci_fn > 1)
mac_offset += 0x18c;
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ } else if (tg3_asic_rev(tp) == ASIC_REV_5906)
mac_offset = 0x10;
/* First try to get it from MAC address mailbox. */
@@ -15746,7 +15989,6 @@ static int tg3_get_device_address(struct tg3 *tp)
#endif
return -EINVAL;
}
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
return 0;
}
@@ -15768,8 +16010,8 @@ static u32 tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
/* On 5703 and later chips, the boundary bits have no
* effect.
*/
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
+ if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
+ tg3_asic_rev(tp) != ASIC_REV_5701 &&
!tg3_flag(tp, PCI_EXPRESS))
goto out;
@@ -16007,14 +16249,14 @@ static int tg3_test_dma(struct tg3 *tp)
/* DMA read watermark not used on PCIE */
tp->dma_rwctrl |= 0x00180000;
} 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)
+ if (tg3_asic_rev(tp) == ASIC_REV_5705 ||
+ tg3_asic_rev(tp) == ASIC_REV_5750)
tp->dma_rwctrl |= 0x003f0000;
else
tp->dma_rwctrl |= 0x003f000f;
} else {
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5703 ||
+ tg3_asic_rev(tp) == ASIC_REV_5704) {
u32 ccval = (tr32(TG3PCI_CLOCK_CTRL) & 0x1f);
u32 read_water = 0x7;
@@ -16023,35 +16265,37 @@ static int tg3_test_dma(struct tg3 *tp)
* better performance.
*/
if (tg3_flag(tp, 40BIT_DMA_BUG) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+ tg3_asic_rev(tp) == ASIC_REV_5704)
tp->dma_rwctrl |= 0x8000;
else if (ccval == 0x6 || ccval == 0x7)
tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703)
+ if (tg3_asic_rev(tp) == ASIC_REV_5703)
read_water = 4;
/* Set bit 23 to enable PCIX hw bug fix */
tp->dma_rwctrl |=
(read_water << DMA_RWCTRL_READ_WATER_SHIFT) |
(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
(1 << 23);
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) {
+ } else if (tg3_asic_rev(tp) == ASIC_REV_5780) {
/* 5780 always in PCIX mode */
tp->dma_rwctrl |= 0x00144000;
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+ } else if (tg3_asic_rev(tp) == ASIC_REV_5714) {
/* 5714 always in PCIX mode */
tp->dma_rwctrl |= 0x00148000;
} else {
tp->dma_rwctrl |= 0x001b000f;
}
}
+ if (tg3_flag(tp, ONE_DMA_AT_ONCE))
+ tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+ if (tg3_asic_rev(tp) == ASIC_REV_5703 ||
+ tg3_asic_rev(tp) == ASIC_REV_5704)
tp->dma_rwctrl &= 0xfffffff0;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
+ tg3_asic_rev(tp) == ASIC_REV_5701) {
/* Remove this if it causes problems for some boards. */
tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT;
@@ -16075,8 +16319,8 @@ static int tg3_test_dma(struct tg3 *tp)
tg3_switch_clocks(tp);
#endif
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
+ if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
+ tg3_asic_rev(tp) != ASIC_REV_5701)
goto out;
/* It is best to perform DMA test with maximum write burst size
@@ -16195,7 +16439,7 @@ static void tg3_init_bufmgr_config(struct tg3 *tp)
DEFAULT_MB_MACRX_LOW_WATER_5705;
tp->bufmgr_config.mbuf_high_water =
DEFAULT_MB_HIGH_WATER_5705;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5906) {
tp->bufmgr_config.mbuf_mac_rx_low_water =
DEFAULT_MB_MACRX_LOW_WATER_5906;
tp->bufmgr_config.mbuf_high_water =
@@ -16253,6 +16497,7 @@ static char *tg3_phy_string(struct tg3 *tp)
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_BCM5762: return "5762C";
case TG3_PHY_ID_BCM8002: return "8002/serdes";
case 0: return "serdes";
default: return "unknown";
@@ -16389,6 +16634,18 @@ static int tg3_init_one(struct pci_dev *pdev,
else
tp->msg_enable = TG3_DEF_MSG_ENABLE;
+ if (pdev_is_ssb_gige_core(pdev)) {
+ tg3_flag_set(tp, IS_SSB_CORE);
+ if (ssb_gige_must_flush_posted_writes(pdev))
+ tg3_flag_set(tp, FLUSH_POSTED_WRITES);
+ if (ssb_gige_one_dma_at_once(pdev))
+ tg3_flag_set(tp, ONE_DMA_AT_ONCE);
+ if (ssb_gige_have_roboswitch(pdev))
+ tg3_flag_set(tp, ROBOSWITCH);
+ if (ssb_gige_is_rgmii(pdev))
+ tg3_flag_set(tp, RGMII_MODE);
+ }
+
/* The word/byte swap controls here control register access byte
* swapping. DMA data byte swapping is controlled in the GRC_MODE
* setting below.
@@ -16429,7 +16686,10 @@ static int tg3_init_one(struct pci_dev *pdev,
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717_C ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720) {
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5762 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5725 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5727) {
tg3_flag_set(tp, ENABLE_APE);
tp->aperegs = pci_ioremap_bar(pdev, BAR_2);
if (!tp->aperegs) {
@@ -16501,7 +16761,7 @@ static int tg3_init_one(struct pci_dev *pdev,
/* 5700 B0 chips do not support checksumming correctly due
* to hardware bugs.
*/
- if (tp->pci_chip_rev_id != CHIPREV_ID_5700_B0) {
+ if (tg3_chip_rev_id(tp) != CHIPREV_ID_5700_B0) {
features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
if (tg3_flag(tp, 5755_PLUS))
@@ -16521,11 +16781,11 @@ static int tg3_init_one(struct pci_dev *pdev,
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)
+ tg3_asic_rev(tp) == ASIC_REV_5761 ||
+ (tg3_asic_rev(tp) == ASIC_REV_5784 &&
+ tg3_chip_rev(tp) != CHIPREV_5784_AX) ||
+ tg3_asic_rev(tp) == ASIC_REV_5785 ||
+ tg3_asic_rev(tp) == ASIC_REV_57780)
features |= NETIF_F_TSO_ECN;
}
@@ -16537,14 +16797,14 @@ static int tg3_init_one(struct pci_dev *pdev,
* 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 &&
+ if (tg3_asic_rev(tp) != 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 &&
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A1 &&
!tg3_flag(tp, TSO_CAPABLE) &&
!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH)) {
tg3_flag_set(tp, MAX_RXPEND_64);
@@ -16623,8 +16883,9 @@ static int tg3_init_one(struct pci_dev *pdev,
pci_set_drvdata(pdev, dev);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ if (tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_5762)
tg3_flag_set(tp, PTP_CAPABLE);
if (tg3_flag(tp, 5717_PLUS)) {
@@ -16634,6 +16895,8 @@ static int tg3_init_one(struct pci_dev *pdev,
tg3_timer_init(tp);
+ tg3_carrier_off(tp);
+
err = register_netdev(dev);
if (err) {
dev_err(&pdev->dev, "Cannot register net device, aborting\n");
@@ -16642,7 +16905,7 @@ static int tg3_init_one(struct pci_dev *pdev,
netdev_info(dev, "Tigon3 [partno(%s) rev %04x] (%s) MAC address %pM\n",
tp->board_part_number,
- tp->pci_chip_rev_id,
+ tg3_chip_rev_id(tp),
tg3_bus_string(tp, str),
dev->dev_addr);
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index d330e81f5793..8d7d4c2ab5d6 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -4,7 +4,7 @@
* Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
* Copyright (C) 2001 Jeff Garzik (jgarzik@pobox.com)
* Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2007-2012 Broadcom Corporation.
+ * Copyright (C) 2007-2013 Broadcom Corporation.
*/
#ifndef _T3_H
@@ -65,6 +65,9 @@
#define TG3PCI_DEVICE_TIGON3_57766 0x1686
#define TG3PCI_DEVICE_TIGON3_57786 0x16b3
#define TG3PCI_DEVICE_TIGON3_57782 0x16b7
+#define TG3PCI_DEVICE_TIGON3_5762 0x1687
+#define TG3PCI_DEVICE_TIGON3_5725 0x1643
+#define TG3PCI_DEVICE_TIGON3_5727 0x16f3
/* 0x04 --> 0x2c unused */
#define TG3PCI_SUBVENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM
#define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6 0x1644
@@ -117,9 +120,7 @@
#define MISC_HOST_CTRL_TAGGED_STATUS 0x00000200
#define MISC_HOST_CTRL_CHIPREV 0xffff0000
#define MISC_HOST_CTRL_CHIPREV_SHIFT 16
-#define GET_CHIP_REV_ID(MISC_HOST_CTRL) \
- (((MISC_HOST_CTRL) & MISC_HOST_CTRL_CHIPREV) >> \
- MISC_HOST_CTRL_CHIPREV_SHIFT)
+
#define CHIPREV_ID_5700_A0 0x7000
#define CHIPREV_ID_5700_A1 0x7001
#define CHIPREV_ID_5700_B0 0x7100
@@ -159,7 +160,8 @@
#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 CHIPREV_ID_5762_A0 0x05762000
+
#define ASIC_REV_5700 0x07
#define ASIC_REV_5701 0x00
#define ASIC_REV_5703 0x01
@@ -182,7 +184,7 @@
#define ASIC_REV_5719 0x5719
#define ASIC_REV_5720 0x5720
#define ASIC_REV_57766 0x57766
-#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
+#define ASIC_REV_5762 0x5762
#define CHIPREV_5700_AX 0x70
#define CHIPREV_5700_BX 0x71
#define CHIPREV_5700_CX 0x72
@@ -195,7 +197,6 @@
#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
#define METAL_REV_B0 0x00
@@ -774,7 +775,7 @@
#define SG_DIG_AUTONEG_ERROR 0x00000001
#define TG3_TX_TSTAMP_LSB 0x000005c0
#define TG3_TX_TSTAMP_MSB 0x000005c4
-#define TG3_TSTAMP_MASK 0x7fffffffffffffff
+#define TG3_TSTAMP_MASK 0x7fffffffffffffffLL
/* 0x5c8 --> 0x600 unused */
#define MAC_TX_MAC_STATE_BASE 0x00000600 /* 16 bytes */
#define MAC_RX_MAC_STATE_BASE 0x00000610 /* 20 bytes */
@@ -1159,6 +1160,8 @@
#define CPMU_MUTEX_GNT_DRIVER 0x00001000
#define TG3_CPMU_PHY_STRAP 0x00003664
#define TG3_CPMU_PHY_STRAP_IS_SERDES 0x00000020
+#define TG3_CPMU_PADRNG_CTL 0x00003668
+#define TG3_CPMU_PADRNG_CTL_RDIV2 0x00040000
/* 0x3664 --> 0x36b0 unused */
#define TG3_CPMU_EEE_MODE 0x000036b0
@@ -1178,6 +1181,7 @@
#define TG3_CPMU_EEE_LNKIDL_CTRL 0x000036bc
#define TG3_CPMU_EEE_LNKIDL_PCIE_NL0 0x01000000
#define TG3_CPMU_EEE_LNKIDL_UART_IDL 0x00000004
+#define TG3_CPMU_EEE_LNKIDL_APE_TX_MT 0x00000002
/* 0x36c0 --> 0x36d0 unused */
#define TG3_CPMU_EEE_CTRL 0x000036d0
@@ -1400,7 +1404,10 @@
#define RDMAC_STATUS_FIFOURUN 0x00000080
#define RDMAC_STATUS_FIFOOREAD 0x00000100
#define RDMAC_STATUS_LNGREAD 0x00000200
-/* 0x4808 --> 0x4900 unused */
+/* 0x4808 --> 0x4890 unused */
+
+#define TG3_RDMA_RSRVCTRL_REG2 0x00004890
+#define TG3_LSO_RD_DMA_CRPTEN_CTRL2 0x000048a0
#define TG3_RDMA_RSRVCTRL_REG 0x00004900
#define TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX 0x00000004
@@ -1850,6 +1857,7 @@
#define FLASH_VENDOR_SST_SMALL 0x00000001
#define FLASH_VENDOR_SST_LARGE 0x02000001
#define NVRAM_CFG1_5752VENDOR_MASK 0x03c00003
+#define NVRAM_CFG1_5762VENDOR_MASK 0x03e00003
#define FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ 0x00000000
#define FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ 0x02000000
#define FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED 0x02000003
@@ -1910,6 +1918,8 @@
#define FLASH_5717VENDOR_ST_45USPT 0x03400001
#define FLASH_5720_EEPROM_HD 0x00000001
#define FLASH_5720_EEPROM_LD 0x00000003
+#define FLASH_5762_EEPROM_HD 0x02000001
+#define FLASH_5762_EEPROM_LD 0x02000003
#define FLASH_5720VENDOR_M_ATMEL_DB011D 0x01000000
#define FLASH_5720VENDOR_M_ATMEL_DB021D 0x01000002
#define FLASH_5720VENDOR_M_ATMEL_DB041D 0x01000001
@@ -2365,6 +2375,20 @@
#define APE_LOCK_REQ_DRIVER 0x00001000
#define TG3_APE_LOCK_GRANT 0x004c
#define APE_LOCK_GRANT_DRIVER 0x00001000
+#define TG3_APE_OTP_CTRL 0x00e8
+#define APE_OTP_CTRL_PROG_EN 0x200000
+#define APE_OTP_CTRL_CMD_RD 0x000000
+#define APE_OTP_CTRL_START 0x000001
+#define TG3_APE_OTP_STATUS 0x00ec
+#define APE_OTP_STATUS_CMD_DONE 0x000001
+#define TG3_APE_OTP_ADDR 0x00f0
+#define APE_OTP_ADDR_CPU_ENABLE 0x80000000
+#define TG3_APE_OTP_RD_DATA 0x00f8
+
+#define OTP_ADDRESS_MAGIC0 0x00000050
+#define TG3_OTP_MAGIC0_VALID(val) \
+ ((((val) & 0xf0000000) == 0xa0000000) ||\
+ (((val) & 0x0f000000) == 0x0a000000))
/* APE shared memory. Accessible through BAR1 */
#define TG3_APE_SHMEM_BASE 0x4000
@@ -3030,6 +3054,11 @@ enum TG3_FLAGS {
TG3_FLAG_57765_PLUS,
TG3_FLAG_57765_CLASS,
TG3_FLAG_5717_PLUS,
+ TG3_FLAG_IS_SSB_CORE,
+ TG3_FLAG_FLUSH_POSTED_WRITES,
+ TG3_FLAG_ROBOSWITCH,
+ TG3_FLAG_ONE_DMA_AT_ONCE,
+ TG3_FLAG_RGMII_MODE,
/* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */
TG3_FLAG_NUMBER_OF_FLAGS, /* Last entry in enum TG3_FLAGS */
@@ -3206,6 +3235,7 @@ struct tg3 {
#define TG3_PHY_ID_BCM57765 0x5c0d8a40
#define TG3_PHY_ID_BCM5719C 0x5c0d8a20
#define TG3_PHY_ID_BCM5720C 0x5c0d8b60
+#define TG3_PHY_ID_BCM5762 0x85803780
#define TG3_PHY_ID_BCM5906 0xdc00ac40
#define TG3_PHY_ID_BCM8002 0x60010140
#define TG3_PHY_ID_INVALID 0xffffffff
@@ -3230,6 +3260,7 @@ struct tg3 {
(X) == TG3_PHY_ID_BCM5906 || (X) == TG3_PHY_ID_BCM5761 || \
(X) == TG3_PHY_ID_BCM5718C || (X) == TG3_PHY_ID_BCM5718S || \
(X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM5719C || \
+ (X) == TG3_PHY_ID_BCM5720C || (X) == TG3_PHY_ID_BCM5762 || \
(X) == TG3_PHY_ID_BCM8002)
u32 phy_flags;
@@ -3320,10 +3351,22 @@ struct tg3 {
const struct firmware *fw;
u32 fw_len; /* includes BSS */
-#if IS_ENABLED(CONFIG_HWMON)
struct device *hwmon_dev;
-#endif
bool link_up;
};
+/* Accessor macros for chip and asic attributes
+ *
+ * nb: Using static inlines equivalent to the accessor macros generates
+ * larger object code with gcc 4.7.
+ * Using statement expression macros to check tp with
+ * typecheck(struct tg3 *, tp) also creates larger objects.
+ */
+#define tg3_chip_rev_id(tp) \
+ ((tp)->pci_chip_rev_id)
+#define tg3_asic_rev(tp) \
+ ((tp)->pci_chip_rev_id >> 12)
+#define tg3_chip_rev(tp) \
+ ((tp)->pci_chip_rev_id >> 8)
+
#endif /* !(_T3_H) */
diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
index ceb0de0cf62c..1194446f859a 100644
--- a/drivers/net/ethernet/cadence/Kconfig
+++ b/drivers/net/ethernet/cadence/Kconfig
@@ -22,6 +22,7 @@ if NET_CADENCE
config ARM_AT91_ETHER
tristate "AT91RM9200 Ethernet support"
+ depends on GENERIC_HARDIRQS
select NET_CORE
select MACB
---help---
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index a9b0830fb39d..79039439bfdc 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -287,7 +287,7 @@ static int macb_mii_probe(struct net_device *dev)
}
/* attach the mac to the phy */
- ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0,
+ ret = phy_connect_direct(dev, phydev, &macb_handle_link_change,
bp->phy_interface);
if (ret) {
netdev_err(dev, "Could not attach to PHY\n");
@@ -693,6 +693,11 @@ static int macb_poll(struct napi_struct *napi, int budget)
* get notified when new packets arrive.
*/
macb_writel(bp, IER, MACB_RX_INT_FLAGS);
+
+ /* Packets received while interrupts were disabled */
+ status = macb_readl(bp, RSR);
+ if (unlikely(status))
+ napi_reschedule(napi);
}
/* TODO: Handle errors */
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index f7f02900f650..a170065b5973 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -1463,7 +1463,6 @@ static int xgmac_set_mac_address(struct net_device *dev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
xgmac_set_mac_addr(ioaddr, dev->dev_addr, 0);
diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
index c8fdeaae56c0..20d2085f61c5 100644
--- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
+++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
@@ -131,7 +131,7 @@ static void t1_set_rxmode(struct net_device *dev)
static void link_report(struct port_info *p)
{
if (!netif_carrier_ok(p->dev))
- printk(KERN_INFO "%s: link down\n", p->dev->name);
+ netdev_info(p->dev, "link down\n");
else {
const char *s = "10Mbps";
@@ -141,9 +141,9 @@ static void link_report(struct port_info *p)
case SPEED_100: s = "100Mbps"; break;
}
- printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
- p->dev->name, s,
- p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+ netdev_info(p->dev, "link up, %s, %s-duplex\n",
+ s, p->link_config.duplex == DUPLEX_FULL
+ ? "full" : "half");
}
}
@@ -976,19 +976,13 @@ static const struct net_device_ops cxgb_netdev_ops = {
static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int version_printed;
-
int i, err, pci_using_dac = 0;
unsigned long mmio_start, mmio_len;
const struct board_info *bi;
struct adapter *adapter = NULL;
struct port_info *pi;
- if (!version_printed) {
- printk(KERN_INFO "%s - version %s\n", DRV_DESCRIPTION,
- DRV_VERSION);
- ++version_printed;
- }
+ pr_info_once("%s - version %s\n", DRV_DESCRIPTION, DRV_VERSION);
err = pci_enable_device(pdev);
if (err)
@@ -1124,8 +1118,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
for (i = 0; i < bi->port_number; ++i) {
err = register_netdev(adapter->port[i].dev);
if (err)
- pr_warning("%s: cannot register net device %s, skipping\n",
- pci_name(pdev), adapter->port[i].dev->name);
+ pr_warn("%s: cannot register net device %s, skipping\n",
+ pci_name(pdev), adapter->port[i].dev->name);
else {
/*
* Change the name we use for messages to the name of
@@ -1143,10 +1137,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_release_adapter_res;
}
- printk(KERN_INFO "%s: %s (rev %d), %s %dMHz/%d-bit\n", adapter->name,
- bi->desc, adapter->params.chip_revision,
- adapter->params.pci.is_pcix ? "PCIX" : "PCI",
- adapter->params.pci.speed, adapter->params.pci.width);
+ pr_info("%s: %s (rev %d), %s %dMHz/%d-bit\n",
+ adapter->name, bi->desc, adapter->params.chip_revision,
+ adapter->params.pci.is_pcix ? "PCIX" : "PCI",
+ adapter->params.pci.speed, adapter->params.pci.width);
/*
* Set the T1B ASIC and memory clocks.
diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c
index d84872e88171..482976925154 100644
--- a/drivers/net/ethernet/chelsio/cxgb/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb/sge.c
@@ -1822,8 +1822,8 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
if (unlikely(skb->len < ETH_HLEN ||
skb->len > dev->mtu + eth_hdr_len(skb->data))) {
- pr_debug("%s: packet size %d hdr %d mtu%d\n", dev->name,
- skb->len, eth_hdr_len(skb->data), dev->mtu);
+ netdev_dbg(dev, "packet size %d hdr %d mtu%d\n",
+ skb->len, eth_hdr_len(skb->data), dev->mtu);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -1831,7 +1831,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
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);
+ netdev_dbg(dev, "unable to do udp checksum\n");
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index f15ee326d5c1..2b5e62193cea 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -29,6 +29,9 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -153,7 +156,7 @@ struct workqueue_struct *cxgb3_wq;
static void link_report(struct net_device *dev)
{
if (!netif_carrier_ok(dev))
- printk(KERN_INFO "%s: link down\n", dev->name);
+ netdev_info(dev, "link down\n");
else {
const char *s = "10Mbps";
const struct port_info *p = netdev_priv(dev);
@@ -170,8 +173,9 @@ static void link_report(struct net_device *dev)
break;
}
- printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
- p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+ netdev_info(dev, "link up, %s, %s-duplex\n",
+ s, p->link_config.duplex == DUPLEX_FULL
+ ? "full" : "half");
}
}
@@ -318,10 +322,10 @@ void t3_os_phymod_changed(struct adapter *adap, int port_id)
const struct port_info *pi = netdev_priv(dev);
if (pi->phy.modtype == phy_modtype_none)
- printk(KERN_INFO "%s: PHY module unplugged\n", dev->name);
+ netdev_info(dev, "PHY module unplugged\n");
else
- printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name,
- mod_str[pi->phy.modtype]);
+ netdev_info(dev, "%s PHY module inserted\n",
+ mod_str[pi->phy.modtype]);
}
static void cxgb_set_rxmode(struct net_device *dev)
@@ -1422,8 +1426,7 @@ static int cxgb_open(struct net_device *dev)
if (is_offload(adapter) && !ofld_disable) {
err = offload_open(dev);
if (err)
- printk(KERN_WARNING
- "Could not initialize offload capabilities\n");
+ pr_warn("Could not initialize offload capabilities\n");
}
netif_set_real_num_tx_queues(dev, pi->nqsets);
@@ -3132,14 +3135,13 @@ static void print_port_info(struct adapter *adap, const struct adapter_info *ai)
if (!test_bit(i, &adap->registered_device_map))
continue;
- printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
- dev->name, ai->desc, pi->phy.desc,
- is_offload(adap) ? "R" : "", adap->params.rev, buf,
- (adap->flags & USING_MSIX) ? " MSI-X" :
- (adap->flags & USING_MSI) ? " MSI" : "");
+ netdev_info(dev, "%s %s %sNIC (rev %d) %s%s\n",
+ ai->desc, pi->phy.desc,
+ is_offload(adap) ? "R" : "", adap->params.rev, buf,
+ (adap->flags & USING_MSIX) ? " MSI-X" :
+ (adap->flags & USING_MSI) ? " MSI" : "");
if (adap->name == dev->name && adap->params.vpd.mclk)
- printk(KERN_INFO
- "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
+ pr_info("%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
adap->name, t3_mc7_size(&adap->cm) >> 20,
t3_mc7_size(&adap->pmtx) >> 20,
t3_mc7_size(&adap->pmrx) >> 20,
@@ -3177,24 +3179,18 @@ static void cxgb3_init_iscsi_mac(struct net_device *dev)
NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA)
static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int version_printed;
-
int i, err, pci_using_dac = 0;
resource_size_t mmio_start, mmio_len;
const struct adapter_info *ai;
struct adapter *adapter = NULL;
struct port_info *pi;
- if (!version_printed) {
- printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
- ++version_printed;
- }
+ pr_info_once("%s - version %s\n", DRV_DESC, DRV_VERSION);
if (!cxgb3_wq) {
cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
if (!cxgb3_wq) {
- printk(KERN_ERR DRV_NAME
- ": cannot initialize work queue\n");
+ pr_err("cannot initialize work queue\n");
return -ENOMEM;
}
}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
index 942dace361d2..4232767862b5 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
@@ -30,6 +30,8 @@
* SOFTWARE.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/list.h>
#include <linux/slab.h>
#include <net/neighbour.h>
@@ -62,9 +64,8 @@ static const unsigned int MAX_ATIDS = 64 * 1024;
static const unsigned int ATID_BASE = 0x10000;
static void cxgb_neigh_update(struct neighbour *neigh);
-static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
- struct dst_entry *new, struct neighbour *new_neigh,
- const void *daddr);
+static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
+ struct neighbour *neigh, const void *daddr);
static inline int offload_activated(struct t3cdev *tdev)
{
@@ -182,14 +183,17 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter,
struct net_device *dev = adapter->port[i];
if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
+ rcu_read_lock();
if (vlan && vlan != VLAN_VID_MASK) {
- rcu_read_lock();
dev = __vlan_find_dev_deep(dev, vlan);
- rcu_read_unlock();
} else if (netif_is_bond_slave(dev)) {
- while (dev->master)
- dev = dev->master;
+ struct net_device *upper_dev;
+
+ while ((upper_dev =
+ netdev_master_upper_dev_get_rcu(dev)))
+ dev = upper_dev;
}
+ rcu_read_unlock();
return dev;
}
}
@@ -232,8 +236,7 @@ static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
if ((val >> S_MAXRXDATA) != 0x3f60) {
val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE);
val |= V_MAXRXDATA(0x3f60);
- printk(KERN_INFO
- "%s, iscsi set MaxRxData to 16224 (0x%x).\n",
+ pr_info("%s, iscsi set MaxRxData to 16224 (0x%x)\n",
adapter->name, val);
t3_write_reg(adapter, A_TP_PARA_REG2, val);
}
@@ -253,8 +256,7 @@ static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
for (i = 0; i < 4; i++)
val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i);
if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) {
- printk(KERN_INFO
- "%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u.\n",
+ pr_info("%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u\n",
adapter->name, val, uiip->pgsz_factor[0],
uiip->pgsz_factor[1], uiip->pgsz_factor[2],
uiip->pgsz_factor[3]);
@@ -706,8 +708,7 @@ static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
struct cpl_smt_write_rpl *rpl = cplhdr(skb);
if (rpl->status != CPL_ERR_NONE)
- printk(KERN_ERR
- "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
+ pr_err("Unexpected SMT_WRITE_RPL status %u for entry %u\n",
rpl->status, GET_TID(rpl));
return CPL_RET_BUF_DONE;
@@ -718,8 +719,7 @@ static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
if (rpl->status != CPL_ERR_NONE)
- printk(KERN_ERR
- "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
+ pr_err("Unexpected L2T_WRITE_RPL status %u for entry %u\n",
rpl->status, GET_TID(rpl));
return CPL_RET_BUF_DONE;
@@ -730,8 +730,7 @@ static int do_rte_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
struct cpl_rte_write_rpl *rpl = cplhdr(skb);
if (rpl->status != CPL_ERR_NONE)
- printk(KERN_ERR
- "Unexpected RTE_WRITE_RPL status %u for entry %u\n",
+ pr_err("Unexpected RTE_WRITE_RPL status %u for entry %u\n",
rpl->status, GET_TID(rpl));
return CPL_RET_BUF_DONE;
@@ -751,7 +750,7 @@ static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
t3c_tid->
ctx);
} else {
- printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ pr_err("%s: received clientless CPL command 0x%x\n",
dev->name, CPL_ACT_OPEN_RPL);
return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
}
@@ -769,7 +768,7 @@ static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
return t3c_tid->client->handlers[p->opcode] (dev, skb,
t3c_tid->ctx);
} else {
- printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ pr_err("%s: received clientless CPL command 0x%x\n",
dev->name, p->opcode);
return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
}
@@ -787,7 +786,7 @@ static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
return t3c_tid->client->handlers[p->opcode]
(dev, skb, t3c_tid->ctx);
} else {
- printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ pr_err("%s: received clientless CPL command 0x%x\n",
dev->name, p->opcode);
return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
}
@@ -814,7 +813,7 @@ static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
(dev, skb, t3c_tid->ctx);
} else {
- printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ pr_err("%s: received clientless CPL command 0x%x\n",
dev->name, CPL_PASS_ACCEPT_REQ);
return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
}
@@ -908,7 +907,7 @@ static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
(dev, skb, t3c_tid->ctx);
} else {
- printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ pr_err("%s: received clientless CPL command 0x%x\n",
dev->name, CPL_ACT_ESTABLISH);
return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
}
@@ -954,7 +953,7 @@ static int do_term(struct t3cdev *dev, struct sk_buff *skb)
return t3c_tid->client->handlers[opcode] (dev, skb,
t3c_tid->ctx);
} else {
- printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ pr_err("%s: received clientless CPL command 0x%x\n",
dev->name, opcode);
return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
}
@@ -970,10 +969,9 @@ static int nb_callback(struct notifier_block *self, unsigned long event,
}
case (NETEVENT_REDIRECT):{
struct netevent_redirect *nr = ctx;
- cxgb_redirect(nr->old, nr->old_neigh,
- nr->new, nr->new_neigh,
+ cxgb_redirect(nr->old, nr->new, nr->neigh,
nr->daddr);
- cxgb_neigh_update(nr->new_neigh);
+ cxgb_neigh_update(nr->neigh);
break;
}
default:
@@ -991,8 +989,7 @@ static struct notifier_block nb = {
*/
static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb)
{
- printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name,
- *skb->data);
+ pr_err("%s: received bad CPL command 0x%x\n", dev->name, *skb->data);
return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
}
@@ -1010,8 +1007,8 @@ void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
if (opcode < NUM_CPL_CMDS)
cpl_handlers[opcode] = h ? h : do_bad_cpl;
else
- printk(KERN_ERR "T3C: handler registration for "
- "opcode %x failed\n", opcode);
+ pr_err("T3C: handler registration for opcode %x failed\n",
+ opcode);
}
EXPORT_SYMBOL(t3_register_cpl_handler);
@@ -1030,9 +1027,8 @@ static int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
if (ret & CPL_RET_UNKNOWN_TID) {
union opcode_tid *p = cplhdr(skb);
- printk(KERN_ERR "%s: CPL message (opcode %u) had "
- "unknown TID %u\n", dev->name, opcode,
- G_TID(ntohl(p->opcode_tid)));
+ pr_err("%s: CPL message (opcode %u) had unknown TID %u\n",
+ dev->name, opcode, G_TID(ntohl(p->opcode_tid)));
}
#endif
if (ret & CPL_RET_BUF_DONE)
@@ -1096,7 +1092,7 @@ static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
if (!skb) {
- printk(KERN_ERR "%s: cannot allocate skb!\n", __func__);
+ pr_err("%s: cannot allocate skb!\n", __func__);
return;
}
skb->priority = CPL_PRIORITY_CONTROL;
@@ -1111,11 +1107,11 @@ static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
tdev->send(tdev, skb);
}
-static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
- struct dst_entry *new, struct neighbour *new_neigh,
+static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
+ struct neighbour *neigh,
const void *daddr)
{
- struct net_device *olddev, *newdev;
+ struct net_device *dev;
struct tid_info *ti;
struct t3cdev *tdev;
u32 tid;
@@ -1123,29 +1119,17 @@ static void cxgb_redirect(struct dst_entry *old, struct neighbour *old_neigh,
struct l2t_entry *e;
struct t3c_tid_entry *te;
- olddev = old_neigh->dev;
- newdev = new_neigh->dev;
+ dev = neigh->dev;
- if (!is_offloading(olddev))
- return;
- if (!is_offloading(newdev)) {
- printk(KERN_WARNING "%s: Redirect to non-offload "
- "device ignored.\n", __func__);
+ if (!is_offloading(dev))
return;
- }
- tdev = dev2t3cdev(olddev);
+ tdev = dev2t3cdev(dev);
BUG_ON(!tdev);
- if (tdev != dev2t3cdev(newdev)) {
- printk(KERN_WARNING "%s: Redirect to different "
- "offload device ignored.\n", __func__);
- return;
- }
/* Add new L2T entry */
- e = t3_l2t_get(tdev, new, newdev, daddr);
+ e = t3_l2t_get(tdev, new, dev, daddr);
if (!e) {
- printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
- __func__);
+ pr_err("%s: couldn't allocate new l2t entry!\n", __func__);
return;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index dd901c5061b9..9d67eb794c4b 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -1278,7 +1278,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* update port statistics */
- if (skb->ip_summed == CHECKSUM_COMPLETE)
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
qs->port_stats[SGE_PSTAT_TX_CSUM]++;
if (skb_shinfo(skb)->gso_size)
qs->port_stats[SGE_PSTAT_TSO]++;
@@ -2130,8 +2130,10 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]);
- if (cpl->vlan_valid)
+ if (cpl->vlan_valid) {
+ qs->port_stats[SGE_PSTAT_VLANEX]++;
__vlan_hwaccel_put_tag(skb, ntohs(cpl->vlan));
+ }
napi_gro_frags(&qs->napi);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
index 3dee68612c9e..c74a898fcd4f 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
@@ -3725,8 +3725,6 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
memcpy(adapter->port[i]->dev_addr, hw_addr,
ETH_ALEN);
- memcpy(adapter->port[i]->perm_addr, hw_addr,
- ETH_ALEN);
init_link_config(&p->link_config, p->phy.caps);
p->phy.ops->power_down(&p->phy, 1);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index c306df7d4568..c6c05bfef0e0 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -4027,8 +4027,7 @@ static int adap_init0_no_config(struct adapter *adapter, int reset)
VFRES_NEQ, VFRES_NETHCTRL,
VFRES_NIQFLINT, VFRES_NIQ,
VFRES_TC, VFRES_NVI,
- FW_PFVF_CMD_CMASK_GET(
- FW_PFVF_CMD_CMASK_MASK),
+ FW_PFVF_CMD_CMASK_MASK,
pfvfres_pmask(
adapter, pf, vf),
VFRES_NEXACTF,
@@ -5142,7 +5141,7 @@ static int __init cxgb4_init_module(void)
/* Debugfs support is optional, just warn if this fails */
cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
if (!cxgb4_debugfs_root)
- pr_warning("could not create debugfs entry, continuing\n");
+ pr_warn("could not create debugfs entry, continuing\n");
ret = pci_register_driver(&cxgb4_driver);
if (ret < 0)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 22f3af5166bf..4ce62031f62f 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -3603,7 +3603,6 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
p->lport = j;
p->rss_size = rss_size;
memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN);
- memcpy(adap->port[i]->perm_addr, addr, ETH_ALEN);
adap->port[i]->dev_id = j;
ret = ntohl(c.u.info.lstatus_to_modtype);
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
index 611396c4b381..68eaa9c88c7d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
@@ -466,7 +466,6 @@ static inline void t4_os_set_hw_addr(struct adapter *adapter, int pidx,
u8 hw_addr[])
{
memcpy(adapter->port[pidx]->dev_addr, hw_addr, ETH_ALEN);
- memcpy(adapter->port[pidx]->perm_addr, hw_addr, ETH_ALEN);
}
/**
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index 0188df705719..56b46ab2d4c5 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -33,6 +33,8 @@
* SOFTWARE.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -196,11 +198,10 @@ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok)
break;
}
- printk(KERN_INFO "%s: link up, %s, full-duplex, %s PAUSE\n",
- dev->name, s, fc);
+ netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, fc);
} else {
netif_carrier_off(dev);
- printk(KERN_INFO "%s: link down\n", dev->name);
+ netdev_info(dev, "link down\n");
}
}
@@ -2465,8 +2466,6 @@ static const struct net_device_ops cxgb4vf_netdev_ops = {
static int cxgb4vf_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- static int version_printed;
-
int pci_using_dac;
int err, pidx;
unsigned int pmask;
@@ -2478,10 +2477,7 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
* Print our driver banner the first time we're called to initialize a
* device.
*/
- if (version_printed == 0) {
- printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
- version_printed = 1;
- }
+ pr_info_once("%s - version %s\n", DRV_DESC, DRV_VERSION);
/*
* Initialize generic PCI device state.
@@ -2920,18 +2916,15 @@ static int __init cxgb4vf_module_init(void)
* Vet our module parameters.
*/
if (msi != MSI_MSIX && msi != MSI_MSI) {
- printk(KERN_WARNING KBUILD_MODNAME
- ": bad module parameter msi=%d; must be %d"
- " (MSI-X or MSI) or %d (MSI)\n",
- msi, MSI_MSIX, MSI_MSI);
+ pr_warn("bad module parameter msi=%d; must be %d (MSI-X or MSI) or %d (MSI)\n",
+ msi, MSI_MSIX, MSI_MSI);
return -EINVAL;
}
/* Debugfs support is optional, just warn if this fails */
cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
if (IS_ERR_OR_NULL(cxgb4vf_debugfs_root))
- printk(KERN_WARNING KBUILD_MODNAME ": could not create"
- " debugfs entry, continuing\n");
+ pr_warn("could not create debugfs entry, continuing\n");
ret = pci_register_driver(&cxgb4vf_driver);
if (ret < 0 && !IS_ERR_OR_NULL(cxgb4vf_debugfs_root))
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index 92170d50d9d8..9488032d6d2d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -1477,8 +1477,10 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_record_rx_queue(skb, rxq->rspq.idx);
- if (pkt->vlan_ex)
+ if (pkt->vlan_ex) {
__vlan_hwaccel_put_tag(skb, be16_to_cpu(pkt->vlan));
+ rxq->stats.vlan_ex++;
+ }
ret = napi_gro_frags(&rxq->rspq.napi);
if (ret == GRO_HELD)
@@ -1501,7 +1503,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
const struct pkt_gl *gl)
{
struct sk_buff *skb;
- const struct cpl_rx_pkt *pkt = (void *)&rsp[1];
+ const struct cpl_rx_pkt *pkt = (void *)rsp;
bool csum_ok = pkt->csum_calc && !pkt->err_vec;
struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c
index 78c55213eaf7..354cbb78ed50 100644
--- a/drivers/net/ethernet/cirrus/ep93xx_eth.c
+++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c
@@ -710,8 +710,8 @@ static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strcpy(info->driver, DRV_MODULE_NAME);
- strcpy(info->version, DRV_MODULE_VERSION);
+ strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
}
static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index 64866ff1aea0..ec1a233622c6 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -865,7 +865,6 @@ static int enic_set_mac_addr(struct net_device *netdev, char *addr)
}
memcpy(netdev->dev_addr, addr, netdev->addr_len);
- netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
return 0;
}
@@ -1491,7 +1490,8 @@ static int enic_request_intr(struct enic *enic)
for (i = 0; i < enic->rq_count; i++) {
intr = enic_msix_rq_intr(enic, i);
- sprintf(enic->msix[intr].devname,
+ snprintf(enic->msix[intr].devname,
+ sizeof(enic->msix[intr].devname),
"%.11s-rx-%d", netdev->name, i);
enic->msix[intr].isr = enic_isr_msix_rq;
enic->msix[intr].devid = &enic->napi[i];
@@ -1499,20 +1499,23 @@ static int enic_request_intr(struct enic *enic)
for (i = 0; i < enic->wq_count; i++) {
intr = enic_msix_wq_intr(enic, i);
- sprintf(enic->msix[intr].devname,
+ snprintf(enic->msix[intr].devname,
+ sizeof(enic->msix[intr].devname),
"%.11s-tx-%d", netdev->name, i);
enic->msix[intr].isr = enic_isr_msix_wq;
enic->msix[intr].devid = enic;
}
intr = enic_msix_err_intr(enic);
- sprintf(enic->msix[intr].devname,
+ snprintf(enic->msix[intr].devname,
+ sizeof(enic->msix[intr].devname),
"%.11s-err", netdev->name);
enic->msix[intr].isr = enic_isr_msix_err;
enic->msix[intr].devid = enic;
intr = enic_msix_notify_intr(enic);
- sprintf(enic->msix[intr].devname,
+ snprintf(enic->msix[intr].devname,
+ sizeof(enic->msix[intr].devname),
"%.11s-notify", netdev->name);
enic->msix[intr].isr = enic_isr_msix_notify;
enic->msix[intr].devid = enic;
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index c73472c369cd..8cdf02503d13 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -434,9 +434,10 @@ static void dm9000_get_drvinfo(struct net_device *dev,
{
board_info_t *dm = to_dm9000_board(dev);
- strcpy(info->driver, CARDNAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, to_platform_device(dm->dev)->name);
+ strlcpy(info->driver, CARDNAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, to_platform_device(dm->dev)->name,
+ sizeof(info->bus_info));
}
static u32 dm9000_get_msglevel(struct net_device *dev)
diff --git a/drivers/net/ethernet/dec/Kconfig b/drivers/net/ethernet/dec/Kconfig
index 37940279ded8..68262aa57d01 100644
--- a/drivers/net/ethernet/dec/Kconfig
+++ b/drivers/net/ethernet/dec/Kconfig
@@ -17,21 +17,5 @@ config NET_VENDOR_DEC
your specific card in the following questions.
if NET_VENDOR_DEC
-
-config EWRK3
- tristate "EtherWORKS 3 (DE203, DE204, DE205) support"
- depends on ISA
- select CRC32
- ---help---
- This driver supports the DE203, DE204 and DE205 network (Ethernet)
- cards. If this is for you, say Y and read
- <file:Documentation/networking/ewrk3.txt> in the kernel source as
- well as the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called ewrk3.
-
source "drivers/net/ethernet/dec/tulip/Kconfig"
-
endif # NET_VENDOR_DEC
diff --git a/drivers/net/ethernet/dec/Makefile b/drivers/net/ethernet/dec/Makefile
index 1b01ed8d42c8..32993fccbbfd 100644
--- a/drivers/net/ethernet/dec/Makefile
+++ b/drivers/net/ethernet/dec/Makefile
@@ -2,5 +2,4 @@
# Makefile for the Digital Equipment Inc. network device drivers.
#
-obj-$(CONFIG_EWRK3) += ewrk3.o
obj-$(CONFIG_NET_TULIP) += tulip/
diff --git a/drivers/net/ethernet/dec/ewrk3.c b/drivers/net/ethernet/dec/ewrk3.c
deleted file mode 100644
index 9f992b95eddc..000000000000
--- a/drivers/net/ethernet/dec/ewrk3.c
+++ /dev/null
@@ -1,1961 +0,0 @@
-/* ewrk3.c: A DIGITAL EtherWORKS 3 ethernet driver for Linux.
-
- Written 1994 by David C. Davies.
-
- Copyright 1994 Digital Equipment Corporation.
-
- This software may be used and distributed according to the terms of
- the GNU General Public License, incorporated herein by reference.
-
- This driver is written for the Digital Equipment Corporation series
- of EtherWORKS ethernet cards:
-
- DE203 Turbo (BNC)
- DE204 Turbo (TP)
- DE205 Turbo (TP BNC)
-
- The driver has been tested on a relatively busy network using the DE205
- card and benchmarked with 'ttcp': it transferred 16M of data at 975kB/s
- (7.8Mb/s) to a DECstation 5000/200.
-
- The author may be reached at davies@maniac.ultranet.com.
-
- =========================================================================
- This driver has been written substantially from scratch, although its
- inheritance of style and stack interface from 'depca.c' and in turn from
- Donald Becker's 'lance.c' should be obvious.
-
- The DE203/4/5 boards all use a new proprietary chip in place of the
- LANCE chip used in prior cards (DEPCA, DE100, DE200/1/2, DE210, DE422).
- Use the depca.c driver in the standard distribution for the LANCE based
- cards from DIGITAL; this driver will not work with them.
-
- The DE203/4/5 cards have 2 main modes: shared memory and I/O only. I/O
- only makes all the card accesses through I/O transactions and no high
- (shared) memory is used. This mode provides a >48% performance penalty
- and is deprecated in this driver, although allowed to provide initial
- setup when hardstrapped.
-
- The shared memory mode comes in 3 flavours: 2kB, 32kB and 64kB. There is
- no point in using any mode other than the 2kB mode - their performances
- are virtually identical, although the driver has been tested in the 2kB
- and 32kB modes. I would suggest you uncomment the line:
-
- FORCE_2K_MODE;
-
- to allow the driver to configure the card as a 2kB card at your current
- base address, thus leaving more room to clutter your system box with
- other memory hungry boards.
-
- As many ISA and EISA cards can be supported under this driver as you
- wish, limited primarily by the available IRQ lines, rather than by the
- available I/O addresses (24 ISA, 16 EISA). I have checked different
- configurations of multiple depca cards and ewrk3 cards and have not
- found a problem yet (provided you have at least depca.c v0.38) ...
-
- The board IRQ setting must be at an unused IRQ which is auto-probed
- using Donald Becker's autoprobe routines. All these cards are at
- {5,10,11,15}.
-
- No 16MB memory limitation should exist with this driver as DMA is not
- used and the common memory area is in low memory on the network card (my
- current system has 20MB and I've not had problems yet).
-
- The ability to load this driver as a loadable module has been included
- and used extensively during the driver development (to save those long
- reboot sequences). To utilise this ability, you have to do 8 things:
-
- 0) have a copy of the loadable modules code installed on your system.
- 1) copy ewrk3.c from the /linux/drivers/net directory to your favourite
- temporary directory.
- 2) edit the source code near line 1898 to reflect the I/O address and
- IRQ you're using.
- 3) compile ewrk3.c, but include -DMODULE in the command line to ensure
- that the correct bits are compiled (see end of source code).
- 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
- kernel with the ewrk3 configuration turned off and reboot.
- 5) insmod ewrk3.o
- [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
- [Adam Kropelin: now accepts irq=x1,x2 io=y1,y2 for multiple cards]
- 6) run the net startup bits for your new eth?? interface manually
- (usually /etc/rc.inet[12] at boot time).
- 7) enjoy!
-
- Note that autoprobing is not allowed in loadable modules - the system is
- already up and running and you're messing with interrupts.
-
- To unload a module, turn off the associated interface
- 'ifconfig eth?? down' then 'rmmod ewrk3'.
-
- Promiscuous mode has been turned off in this driver, but all the
- multicast address bits have been turned on. This improved the send
- performance on a busy network by about 13%.
-
- Ioctl's have now been provided (primarily because I wanted to grab some
- packet size statistics). They are patterned after 'plipconfig.c' from a
- suggestion by Alan Cox. Using these ioctls, you can enable promiscuous
- mode, add/delete multicast addresses, change the hardware address, get
- packet size distribution statistics and muck around with the control and
- status register. I'll add others if and when the need arises.
-
- TO DO:
- ------
-
-
- Revision History
- ----------------
-
- Version Date Description
-
- 0.1 26-aug-94 Initial writing. ALPHA code release.
- 0.11 31-aug-94 Fixed: 2k mode memory base calc.,
- LeMAC version calc.,
- IRQ vector assignments during autoprobe.
- 0.12 31-aug-94 Tested working on LeMAC2 (DE20[345]-AC) card.
- Fixed up MCA hash table algorithm.
- 0.20 4-sep-94 Added IOCTL functionality.
- 0.21 14-sep-94 Added I/O mode.
- 0.21axp 15-sep-94 Special version for ALPHA AXP Linux V1.0.
- 0.22 16-sep-94 Added more IOCTLs & tidied up.
- 0.23 21-sep-94 Added transmit cut through.
- 0.24 31-oct-94 Added uid checks in some ioctls.
- 0.30 1-nov-94 BETA code release.
- 0.31 5-dec-94 Added check/allocate region code.
- 0.32 16-jan-95 Broadcast packet fix.
- 0.33 10-Feb-95 Fix recognition bug reported by <bkm@star.rl.ac.uk>.
- 0.40 27-Dec-95 Rationalise MODULE and autoprobe code.
- Rewrite for portability & updated.
- ALPHA support from <jestabro@amt.tay1.dec.com>
- Added verify_area() calls in ewrk3_ioctl() from
- suggestion by <heiko@colossus.escape.de>.
- Add new multicasting code.
- 0.41 20-Jan-96 Fix IRQ set up problem reported by
- <kenneth@bbs.sas.ntu.ac.sg>.
- 0.42 22-Apr-96 Fix alloc_device() bug <jari@markkus2.fimr.fi>
- 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c
- 0.44 08-Nov-01 use library crc32 functions <Matt_Domsch@dell.com>
- 0.45 19-Jul-02 fix unaligned access on alpha <martin@bruli.net>
- 0.46 10-Oct-02 Multiple NIC support when module <akropel1@rochester.rr.com>
- 0.47 18-Oct-02 ethtool support <akropel1@rochester.rr.com>
- 0.48 18-Oct-02 cli/sti removal for 2.5 <vda@port.imtp.ilyichevsk.odessa.ua>
- ioctl locking, signature search cleanup <akropel1@rochester.rr.com>
-
- =========================================================================
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/ethtool.h>
-#include <linux/time.h>
-#include <linux/types.h>
-#include <linux/unistd.h>
-#include <linux/ctype.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include "ewrk3.h"
-
-#define DRV_NAME "ewrk3"
-#define DRV_VERSION "0.48"
-
-static char version[] __initdata =
-DRV_NAME ":v" DRV_VERSION " 2002/10/18 davies@maniac.ultranet.com\n";
-
-#ifdef EWRK3_DEBUG
-static int ewrk3_debug = EWRK3_DEBUG;
-#else
-static int ewrk3_debug = 1;
-#endif
-
-#define EWRK3_NDA 0xffe0 /* No Device Address */
-
-#define PROBE_LENGTH 32
-#define ETH_PROM_SIG 0xAA5500FFUL
-
-#ifndef EWRK3_SIGNATURE
-#define EWRK3_SIGNATURE {"DE203","DE204","DE205",""}
-#define EWRK3_STRLEN 8
-#endif
-
-#ifndef EWRK3_RAM_BASE_ADDRESSES
-#define EWRK3_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0x00000}
-#endif
-
-/*
- ** Sets up the I/O area for the autoprobe.
- */
-#define EWRK3_IO_BASE 0x100 /* Start address for probe search */
-#define EWRK3_IOP_INC 0x20 /* I/O address increment */
-#define EWRK3_TOTAL_SIZE 0x20 /* required I/O address length */
-
-#ifndef MAX_NUM_EWRK3S
-#define MAX_NUM_EWRK3S 21
-#endif
-
-#ifndef EWRK3_EISA_IO_PORTS
-#define EWRK3_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
-#endif
-
-#ifndef MAX_EISA_SLOTS
-#define MAX_EISA_SLOTS 16
-#define EISA_SLOT_INC 0x1000
-#endif
-
-#define QUEUE_PKT_TIMEOUT (1*HZ) /* Jiffies */
-
-/*
- ** EtherWORKS 3 shared memory window sizes
- */
-#define IO_ONLY 0x00
-#define SHMEM_2K 0x800
-#define SHMEM_32K 0x8000
-#define SHMEM_64K 0x10000
-
-/*
- ** EtherWORKS 3 IRQ ENABLE/DISABLE
- */
-#define ENABLE_IRQs { \
- icr |= lp->irq_mask;\
- outb(icr, EWRK3_ICR); /* Enable the IRQs */\
-}
-
-#define DISABLE_IRQs { \
- icr = inb(EWRK3_ICR);\
- icr &= ~lp->irq_mask;\
- outb(icr, EWRK3_ICR); /* Disable the IRQs */\
-}
-
-/*
- ** EtherWORKS 3 START/STOP
- */
-#define START_EWRK3 { \
- csr = inb(EWRK3_CSR);\
- csr &= ~(CSR_TXD|CSR_RXD);\
- outb(csr, EWRK3_CSR); /* Enable the TX and/or RX */\
-}
-
-#define STOP_EWRK3 { \
- csr = (CSR_TXD|CSR_RXD);\
- outb(csr, EWRK3_CSR); /* Disable the TX and/or RX */\
-}
-
-/*
- ** The EtherWORKS 3 private structure
- */
-#define EWRK3_PKT_STAT_SZ 16
-#define EWRK3_PKT_BIN_SZ 128 /* Should be >=100 unless you
- increase EWRK3_PKT_STAT_SZ */
-
-struct ewrk3_stats {
- u32 bins[EWRK3_PKT_STAT_SZ];
- u32 unicast;
- u32 multicast;
- u32 broadcast;
- u32 excessive_collisions;
- u32 tx_underruns;
- u32 excessive_underruns;
-};
-
-struct ewrk3_private {
- char adapter_name[80]; /* Name exported to /proc/ioports */
- u_long shmem_base; /* Shared memory start address */
- void __iomem *shmem;
- u_long shmem_length; /* Shared memory window length */
- struct ewrk3_stats pktStats; /* Private stats counters */
- u_char irq_mask; /* Adapter IRQ mask bits */
- u_char mPage; /* Maximum 2kB Page number */
- u_char lemac; /* Chip rev. level */
- u_char hard_strapped; /* Don't allow a full open */
- u_char txc; /* Transmit cut through */
- void __iomem *mctbl; /* Pointer to the multicast table */
- u_char led_mask; /* Used to reserve LED access for ethtool */
- spinlock_t hw_lock;
-};
-
-/*
- ** Force the EtherWORKS 3 card to be in 2kB MODE
- */
-#define FORCE_2K_MODE { \
- shmem_length = SHMEM_2K;\
- outb(((mem_start - 0x80000) >> 11), EWRK3_MBR);\
-}
-
-/*
- ** Public Functions
- */
-static int ewrk3_open(struct net_device *dev);
-static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ewrk3_interrupt(int irq, void *dev_id);
-static int ewrk3_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static const struct ethtool_ops ethtool_ops_203;
-static const struct ethtool_ops ethtool_ops;
-
-/*
- ** Private functions
- */
-static int ewrk3_hw_init(struct net_device *dev, u_long iobase);
-static void ewrk3_init(struct net_device *dev);
-static int ewrk3_rx(struct net_device *dev);
-static int ewrk3_tx(struct net_device *dev);
-static void ewrk3_timeout(struct net_device *dev);
-
-static void EthwrkSignature(char *name, char *eeprom_image);
-static int DevicePresent(u_long iobase);
-static void SetMulticastFilter(struct net_device *dev);
-static int EISA_signature(char *name, s32 eisa_id);
-
-static int Read_EEPROM(u_long iobase, u_char eaddr);
-static int Write_EEPROM(short data, u_long iobase, u_char eaddr);
-static u_char get_hw_addr(struct net_device *dev, u_char * eeprom_image, char chipType);
-
-static int ewrk3_probe1(struct net_device *dev, u_long iobase, int irq);
-static int isa_probe(struct net_device *dev, u_long iobase);
-static int eisa_probe(struct net_device *dev, u_long iobase);
-
-static u_char irq[MAX_NUM_EWRK3S+1] = {5, 0, 10, 3, 11, 9, 15, 12};
-
-static char name[EWRK3_STRLEN + 1];
-static int num_ewrks3s;
-
-/*
- ** Miscellaneous defines...
- */
-#define INIT_EWRK3 {\
- outb(EEPROM_INIT, EWRK3_IOPR);\
- mdelay(1);\
-}
-
-#ifndef MODULE
-struct net_device * __init ewrk3_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct ewrk3_private));
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
-
- err = ewrk3_probe1(dev, dev->base_addr, dev->irq);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-
-}
-#endif
-
-static int __init ewrk3_probe1(struct net_device *dev, u_long iobase, int irq)
-{
- int err;
-
- dev->base_addr = iobase;
- dev->irq = irq;
-
- /* Address PROM pattern */
- err = isa_probe(dev, iobase);
- if (err != 0)
- err = eisa_probe(dev, iobase);
-
- if (err)
- return err;
-
- err = register_netdev(dev);
- if (err)
- release_region(dev->base_addr, EWRK3_TOTAL_SIZE);
-
- return err;
-}
-
-static const struct net_device_ops ewrk3_netdev_ops = {
- .ndo_open = ewrk3_open,
- .ndo_start_xmit = ewrk3_queue_pkt,
- .ndo_stop = ewrk3_close,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_do_ioctl = ewrk3_ioctl,
- .ndo_tx_timeout = ewrk3_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int __init
-ewrk3_hw_init(struct net_device *dev, u_long iobase)
-{
- struct ewrk3_private *lp;
- int i, status = 0;
- u_long mem_start, shmem_length;
- u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0;
- u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0;
-
- /*
- ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot.
- ** This also disables the EISA_ENABLE bit in the EISA Control Register.
- */
- if (iobase > 0x400)
- eisa_cr = inb(EISA_CR);
- INIT_EWRK3;
-
- nicsr = inb(EWRK3_CSR);
-
- icr = inb(EWRK3_ICR);
- icr &= 0x70;
- outb(icr, EWRK3_ICR); /* Disable all the IRQs */
-
- if (nicsr != (CSR_TXD | CSR_RXD))
- return -ENXIO;
-
- /* Check that the EEPROM is alive and well and not living on Pluto... */
- for (chksum = 0, i = 0; i < EEPROM_MAX; i += 2) {
- union {
- short val;
- char c[2];
- } tmp;
-
- tmp.val = (short) Read_EEPROM(iobase, (i >> 1));
- eeprom_image[i] = tmp.c[0];
- eeprom_image[i + 1] = tmp.c[1];
- chksum += eeprom_image[i] + eeprom_image[i + 1];
- }
-
- if (chksum != 0) { /* Bad EEPROM Data! */
- printk("%s: Device has a bad on-board EEPROM.\n", dev->name);
- return -ENXIO;
- }
-
- EthwrkSignature(name, eeprom_image);
- if (*name == '\0')
- return -ENXIO;
-
- dev->base_addr = iobase;
-
- if (iobase > 0x400) {
- outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */
- }
- lemac = eeprom_image[EEPROM_CHIPVER];
- cmr = inb(EWRK3_CMR);
-
- if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) ||
- ((lemac == LeMAC2) && !(cmr & CMR_HS))) {
- printk("%s: %s at %#4lx", dev->name, name, iobase);
- hard_strapped = 1;
- } else if ((iobase & 0x0fff) == EWRK3_EISA_IO_PORTS) {
- /* EISA slot address */
- printk("%s: %s at %#4lx (EISA slot %ld)",
- dev->name, name, iobase, ((iobase >> 12) & 0x0f));
- } else { /* ISA port address */
- printk("%s: %s at %#4lx", dev->name, name, iobase);
- }
-
- printk(", h/w address ");
- if (lemac != LeMAC2)
- DevicePresent(iobase); /* need after EWRK3_INIT */
- status = get_hw_addr(dev, eeprom_image, lemac);
- printk("%pM\n", dev->dev_addr);
-
- if (status) {
- printk(" which has an EEPROM CRC error.\n");
- return -ENXIO;
- }
-
- if (lemac == LeMAC2) { /* Special LeMAC2 CMR things */
- cmr &= ~(CMR_RA | CMR_WB | CMR_LINK | CMR_POLARITY | CMR_0WS);
- if (eeprom_image[EEPROM_MISC0] & READ_AHEAD)
- cmr |= CMR_RA;
- if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND)
- cmr |= CMR_WB;
- if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL)
- cmr |= CMR_POLARITY;
- if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK)
- cmr |= CMR_LINK;
- if (eeprom_image[EEPROM_MISC0] & _0WS_ENA)
- cmr |= CMR_0WS;
- }
- if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM)
- cmr |= CMR_DRAM;
- outb(cmr, EWRK3_CMR);
-
- cr = inb(EWRK3_CR); /* Set up the Control Register */
- cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD;
- if (cr & SETUP_APD)
- cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS;
- cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS;
- cr |= eeprom_image[EEPROM_MISC0] & ENA_16;
- outb(cr, EWRK3_CR);
-
- /*
- ** Determine the base address and window length for the EWRK3
- ** RAM from the memory base register.
- */
- mem_start = inb(EWRK3_MBR);
- shmem_length = 0;
- if (mem_start != 0) {
- if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) {
- mem_start *= SHMEM_64K;
- shmem_length = SHMEM_64K;
- } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) {
- mem_start *= SHMEM_32K;
- shmem_length = SHMEM_32K;
- } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) {
- mem_start = mem_start * SHMEM_2K + 0x80000;
- shmem_length = SHMEM_2K;
- } else {
- return -ENXIO;
- }
- }
- /*
- ** See the top of this source code for comments about
- ** uncommenting this line.
- */
-/* FORCE_2K_MODE; */
-
- if (hard_strapped) {
- printk(" is hard strapped.\n");
- } else if (mem_start) {
- printk(" has a %dk RAM window", (int) (shmem_length >> 10));
- printk(" at 0x%.5lx", mem_start);
- } else {
- printk(" is in I/O only mode");
- }
-
- lp = netdev_priv(dev);
- lp->shmem_base = mem_start;
- lp->shmem = ioremap(mem_start, shmem_length);
- if (!lp->shmem)
- return -ENOMEM;
- lp->shmem_length = shmem_length;
- lp->lemac = lemac;
- lp->hard_strapped = hard_strapped;
- lp->led_mask = CR_LED;
- spin_lock_init(&lp->hw_lock);
-
- lp->mPage = 64;
- if (cmr & CMR_DRAM)
- lp->mPage <<= 1; /* 2 DRAMS on module */
-
- sprintf(lp->adapter_name, "%s (%s)", name, dev->name);
-
- lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM;
-
- if (!hard_strapped) {
- /*
- ** Enable EWRK3 board interrupts for autoprobing
- */
- icr |= ICR_IE; /* Enable interrupts */
- outb(icr, EWRK3_ICR);
-
- /* The DMA channel may be passed in on this parameter. */
- dev->dma = 0;
-
- /* To auto-IRQ we enable the initialization-done and DMA err,
- interrupts. For now we will always get a DMA error. */
- if (dev->irq < 2) {
-#ifndef MODULE
- u_char irqnum;
- unsigned long irq_mask;
-
-
- irq_mask = probe_irq_on();
-
- /*
- ** Trigger a TNE interrupt.
- */
- icr |= ICR_TNEM;
- outb(1, EWRK3_TDQ); /* Write to the TX done queue */
- outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */
-
- irqnum = irq[((icr & IRQ_SEL) >> 4)];
-
- mdelay(20);
- dev->irq = probe_irq_off(irq_mask);
- if ((dev->irq) && (irqnum == dev->irq)) {
- printk(" and uses IRQ%d.\n", dev->irq);
- } else {
- if (!dev->irq) {
- printk(" and failed to detect IRQ line.\n");
- } else if ((irqnum == 1) && (lemac == LeMAC2)) {
- printk(" and an illegal IRQ line detected.\n");
- } else {
- printk(", but incorrect IRQ line detected.\n");
- }
- iounmap(lp->shmem);
- return -ENXIO;
- }
-
- DISABLE_IRQs; /* Mask all interrupts */
-
-#endif /* MODULE */
- } else {
- printk(" and requires IRQ%d.\n", dev->irq);
- }
- }
-
- if (ewrk3_debug > 1) {
- printk(version);
- }
- /* The EWRK3-specific entries in the device structure. */
- dev->netdev_ops = &ewrk3_netdev_ops;
- if (lp->adapter_name[4] == '3')
- SET_ETHTOOL_OPS(dev, &ethtool_ops_203);
- else
- SET_ETHTOOL_OPS(dev, &ethtool_ops);
- dev->watchdog_timeo = QUEUE_PKT_TIMEOUT;
-
- dev->mem_start = 0;
-
- return 0;
-}
-
-
-static int ewrk3_open(struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- u_long iobase = dev->base_addr;
- int status = 0;
- u_char icr, csr;
-
- /*
- ** Stop the TX and RX...
- */
- STOP_EWRK3;
-
- if (!lp->hard_strapped) {
- if (request_irq(dev->irq, (void *) ewrk3_interrupt, 0, "ewrk3", dev)) {
- printk("ewrk3_open(): Requested IRQ%d is busy\n", dev->irq);
- status = -EAGAIN;
- } else {
-
- /*
- ** Re-initialize the EWRK3...
- */
- ewrk3_init(dev);
-
- if (ewrk3_debug > 1) {
- printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq);
- printk(" physical address: %pM\n", dev->dev_addr);
- if (lp->shmem_length == 0) {
- printk(" no shared memory, I/O only mode\n");
- } else {
- printk(" start of shared memory: 0x%08lx\n", lp->shmem_base);
- printk(" window length: 0x%04lx\n", lp->shmem_length);
- }
- printk(" # of DRAMS: %d\n", ((inb(EWRK3_CMR) & 0x02) ? 2 : 1));
- printk(" csr: 0x%02x\n", inb(EWRK3_CSR));
- printk(" cr: 0x%02x\n", inb(EWRK3_CR));
- printk(" icr: 0x%02x\n", inb(EWRK3_ICR));
- printk(" cmr: 0x%02x\n", inb(EWRK3_CMR));
- printk(" fmqc: 0x%02x\n", inb(EWRK3_FMQC));
- }
- netif_start_queue(dev);
- /*
- ** Unmask EWRK3 board interrupts
- */
- icr = inb(EWRK3_ICR);
- ENABLE_IRQs;
-
- }
- } else {
- printk(KERN_ERR "%s: ewrk3 available for hard strapped set up only.\n", dev->name);
- printk(KERN_ERR " Run the 'ewrk3setup' utility or remove the hard straps.\n");
- return -EINVAL;
- }
-
- return status;
-}
-
-/*
- ** Initialize the EtherWORKS 3 operating conditions
- */
-static void ewrk3_init(struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- u_char csr, page;
- u_long iobase = dev->base_addr;
- int i;
-
- /*
- ** Enable any multicasts
- */
- set_multicast_list(dev);
-
- /*
- ** Set hardware MAC address. Address is initialized from the EEPROM
- ** during startup but may have since been changed by the user.
- */
- for (i=0; i<ETH_ALEN; i++)
- outb(dev->dev_addr[i], EWRK3_PAR0 + i);
-
- /*
- ** Clean out any remaining entries in all the queues here
- */
- while (inb(EWRK3_TQ));
- while (inb(EWRK3_TDQ));
- while (inb(EWRK3_RQ));
- while (inb(EWRK3_FMQ));
-
- /*
- ** Write a clean free memory queue
- */
- for (page = 1; page < lp->mPage; page++) { /* Write the free page numbers */
- outb(page, EWRK3_FMQ); /* to the Free Memory Queue */
- }
-
- START_EWRK3; /* Enable the TX and/or RX */
-}
-
-/*
- * Transmit timeout
- */
-
-static void ewrk3_timeout(struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- u_char icr, csr;
- u_long iobase = dev->base_addr;
-
- if (!lp->hard_strapped)
- {
- printk(KERN_WARNING"%s: transmit timed/locked out, status %04x, resetting.\n",
- dev->name, inb(EWRK3_CSR));
-
- /*
- ** Mask all board interrupts
- */
- DISABLE_IRQs;
-
- /*
- ** Stop the TX and RX...
- */
- STOP_EWRK3;
-
- ewrk3_init(dev);
-
- /*
- ** Unmask EWRK3 board interrupts
- */
- ENABLE_IRQs;
-
- dev->trans_start = jiffies; /* prevent tx timeout */
- netif_wake_queue(dev);
- }
-}
-
-/*
- ** Writes a socket buffer to the free page queue
- */
-static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- u_long iobase = dev->base_addr;
- void __iomem *buf = NULL;
- u_char icr;
- u_char page;
-
- spin_lock_irq (&lp->hw_lock);
- DISABLE_IRQs;
-
- /* if no resources available, exit, request packet be queued */
- if (inb (EWRK3_FMQC) == 0) {
- printk (KERN_WARNING "%s: ewrk3_queue_pkt(): No free resources...\n",
- dev->name);
- printk (KERN_WARNING "%s: ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n",
- dev->name, inb (EWRK3_CSR), inb (EWRK3_ICR),
- inb (EWRK3_FMQC));
- goto err_out;
- }
-
- /*
- ** Get a free page from the FMQ
- */
- if ((page = inb (EWRK3_FMQ)) >= lp->mPage) {
- printk ("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
- (u_char) page);
- goto err_out;
- }
-
-
- /*
- ** Set up shared memory window and pointer into the window
- */
- if (lp->shmem_length == IO_ONLY) {
- outb (page, EWRK3_IOPR);
- } else if (lp->shmem_length == SHMEM_2K) {
- buf = lp->shmem;
- outb (page, EWRK3_MPR);
- } else if (lp->shmem_length == SHMEM_32K) {
- buf = (((short) page << 11) & 0x7800) + lp->shmem;
- outb ((page >> 4), EWRK3_MPR);
- } else if (lp->shmem_length == SHMEM_64K) {
- buf = (((short) page << 11) & 0xf800) + lp->shmem;
- outb ((page >> 5), EWRK3_MPR);
- } else {
- printk (KERN_ERR "%s: Oops - your private data area is hosed!\n",
- dev->name);
- BUG ();
- }
-
- /*
- ** Set up the buffer control structures and copy the data from
- ** the socket buffer to the shared memory .
- */
- if (lp->shmem_length == IO_ONLY) {
- int i;
- u_char *p = skb->data;
- outb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA);
- outb ((char) (skb->len & 0xff), EWRK3_DATA);
- outb ((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
- outb ((char) 0x04, EWRK3_DATA);
- for (i = 0; i < skb->len; i++) {
- outb (*p++, EWRK3_DATA);
- }
- outb (page, EWRK3_TQ); /* Start sending pkt */
- } else {
- writeb ((char) (TCR_QMODE | TCR_PAD | TCR_IFC), buf); /* ctrl byte */
- buf += 1;
- writeb ((char) (skb->len & 0xff), buf); /* length (16 bit xfer) */
- buf += 1;
- if (lp->txc) {
- writeb(((skb->len >> 8) & 0xff) | XCT, buf);
- buf += 1;
- writeb (0x04, buf); /* index byte */
- buf += 1;
- writeb (0x00, (buf + skb->len)); /* Write the XCT flag */
- memcpy_toio (buf, skb->data, PRELOAD); /* Write PRELOAD bytes */
- outb (page, EWRK3_TQ); /* Start sending pkt */
- memcpy_toio (buf + PRELOAD,
- skb->data + PRELOAD,
- skb->len - PRELOAD);
- writeb (0xff, (buf + skb->len)); /* Write the XCT flag */
- } else {
- writeb ((skb->len >> 8) & 0xff, buf);
- buf += 1;
- writeb (0x04, buf); /* index byte */
- buf += 1;
- memcpy_toio (buf, skb->data, skb->len); /* Write data bytes */
- outb (page, EWRK3_TQ); /* Start sending pkt */
- }
- }
-
- ENABLE_IRQs;
- spin_unlock_irq (&lp->hw_lock);
-
- dev->stats.tx_bytes += skb->len;
- dev_kfree_skb (skb);
-
- /* Check for free resources: stop Tx queue if there are none */
- if (inb (EWRK3_FMQC) == 0)
- netif_stop_queue (dev);
-
- return NETDEV_TX_OK;
-
-err_out:
- ENABLE_IRQs;
- spin_unlock_irq (&lp->hw_lock);
- return NETDEV_TX_BUSY;
-}
-
-/*
- ** The EWRK3 interrupt handler.
- */
-static irqreturn_t ewrk3_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct ewrk3_private *lp;
- u_long iobase;
- u_char icr, cr, csr;
-
- lp = netdev_priv(dev);
- iobase = dev->base_addr;
-
- /* get the interrupt information */
- csr = inb(EWRK3_CSR);
-
- /*
- ** Mask the EWRK3 board interrupts and turn on the LED
- */
- spin_lock(&lp->hw_lock);
- DISABLE_IRQs;
-
- cr = inb(EWRK3_CR);
- cr |= lp->led_mask;
- outb(cr, EWRK3_CR);
-
- if (csr & CSR_RNE) /* Rx interrupt (packet[s] arrived) */
- ewrk3_rx(dev);
-
- if (csr & CSR_TNE) /* Tx interrupt (packet sent) */
- ewrk3_tx(dev);
-
- /*
- ** Now deal with the TX/RX disable flags. These are set when there
- ** are no more resources. If resources free up then enable these
- ** interrupts, otherwise mask them - failure to do this will result
- ** in the system hanging in an interrupt loop.
- */
- if (inb(EWRK3_FMQC)) { /* any resources available? */
- lp->irq_mask |= ICR_TXDM | ICR_RXDM; /* enable the interrupt source */
- csr &= ~(CSR_TXD | CSR_RXD); /* ensure restart of a stalled TX or RX */
- outb(csr, EWRK3_CSR);
- netif_wake_queue(dev);
- } else {
- lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM); /* disable the interrupt source */
- }
-
- /* Unmask the EWRK3 board interrupts and turn off the LED */
- cr &= ~(lp->led_mask);
- outb(cr, EWRK3_CR);
- ENABLE_IRQs;
- spin_unlock(&lp->hw_lock);
- return IRQ_HANDLED;
-}
-
-/* Called with lp->hw_lock held */
-static int ewrk3_rx(struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- u_long iobase = dev->base_addr;
- int i, status = 0;
- u_char page;
- void __iomem *buf = NULL;
-
- while (inb(EWRK3_RQC) && !status) { /* Whilst there's incoming data */
- if ((page = inb(EWRK3_RQ)) < lp->mPage) { /* Get next entry's buffer page */
- /*
- ** Set up shared memory window and pointer into the window
- */
- if (lp->shmem_length == IO_ONLY) {
- outb(page, EWRK3_IOPR);
- } else if (lp->shmem_length == SHMEM_2K) {
- buf = lp->shmem;
- outb(page, EWRK3_MPR);
- } else if (lp->shmem_length == SHMEM_32K) {
- buf = (((short) page << 11) & 0x7800) + lp->shmem;
- outb((page >> 4), EWRK3_MPR);
- } else if (lp->shmem_length == SHMEM_64K) {
- buf = (((short) page << 11) & 0xf800) + lp->shmem;
- outb((page >> 5), EWRK3_MPR);
- } else {
- status = -1;
- printk("%s: Oops - your private data area is hosed!\n", dev->name);
- }
-
- if (!status) {
- char rx_status;
- int pkt_len;
-
- if (lp->shmem_length == IO_ONLY) {
- rx_status = inb(EWRK3_DATA);
- pkt_len = inb(EWRK3_DATA);
- pkt_len |= ((u_short) inb(EWRK3_DATA) << 8);
- } else {
- rx_status = readb(buf);
- buf += 1;
- pkt_len = readw(buf);
- buf += 3;
- }
-
- if (!(rx_status & R_ROK)) { /* There was an error. */
- dev->stats.rx_errors++; /* Update the error stats. */
- if (rx_status & R_DBE)
- dev->stats.rx_frame_errors++;
- if (rx_status & R_CRC)
- dev->stats.rx_crc_errors++;
- if (rx_status & R_PLL)
- dev->stats.rx_fifo_errors++;
- } else {
- struct sk_buff *skb;
- skb = netdev_alloc_skb(dev,
- pkt_len + 2);
-
- if (skb != NULL) {
- unsigned char *p;
- skb_reserve(skb, 2); /* Align to 16 bytes */
- p = skb_put(skb, pkt_len);
-
- if (lp->shmem_length == IO_ONLY) {
- *p = inb(EWRK3_DATA); /* dummy read */
- for (i = 0; i < pkt_len; i++) {
- *p++ = inb(EWRK3_DATA);
- }
- } else {
- memcpy_fromio(p, buf, pkt_len);
- }
-
- for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) {
- if (pkt_len < i * EWRK3_PKT_BIN_SZ) {
- lp->pktStats.bins[i]++;
- i = EWRK3_PKT_STAT_SZ;
- }
- }
- p = skb->data; /* Look at the dest addr */
- if (is_multicast_ether_addr(p)) {
- if (is_broadcast_ether_addr(p)) {
- lp->pktStats.broadcast++;
- } else {
- lp->pktStats.multicast++;
- }
- } else if (ether_addr_equal(p,
- dev->dev_addr)) {
- lp->pktStats.unicast++;
- }
- lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */
- if (lp->pktStats.bins[0] == 0) { /* Reset counters */
- memset(&lp->pktStats, 0, sizeof(lp->pktStats));
- }
- /*
- ** Notify the upper protocol layers that there is another
- ** packet to handle
- */
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
-
- /*
- ** Update stats
- */
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- } else {
- printk("%s: Insufficient memory; nuking packet.\n", dev->name);
- dev->stats.rx_dropped++; /* Really, deferred. */
- break;
- }
- }
- }
- /*
- ** Return the received buffer to the free memory queue
- */
- outb(page, EWRK3_FMQ);
- } else {
- printk("ewrk3_rx(): Illegal page number, page %d\n", page);
- printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
- }
- }
- return status;
-}
-
-/*
-** Buffer sent - check for TX buffer errors.
-** Called with lp->hw_lock held
-*/
-static int ewrk3_tx(struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- u_long iobase = dev->base_addr;
- u_char tx_status;
-
- while ((tx_status = inb(EWRK3_TDQ)) > 0) { /* Whilst there's old buffers */
- if (tx_status & T_VSTS) { /* The status is valid */
- if (tx_status & T_TXE) {
- dev->stats.tx_errors++;
- if (tx_status & T_NCL)
- dev->stats.tx_carrier_errors++;
- if (tx_status & T_LCL)
- dev->stats.tx_window_errors++;
- if (tx_status & T_CTU) {
- if ((tx_status & T_COLL) ^ T_XUR) {
- lp->pktStats.tx_underruns++;
- } else {
- lp->pktStats.excessive_underruns++;
- }
- } else if (tx_status & T_COLL) {
- if ((tx_status & T_COLL) ^ T_XCOLL) {
- dev->stats.collisions++;
- } else {
- lp->pktStats.excessive_collisions++;
- }
- }
- } else {
- dev->stats.tx_packets++;
- }
- }
- }
-
- return 0;
-}
-
-static int ewrk3_close(struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- u_long iobase = dev->base_addr;
- u_char icr, csr;
-
- netif_stop_queue(dev);
-
- if (ewrk3_debug > 1) {
- printk("%s: Shutting down ethercard, status was %2.2x.\n",
- dev->name, inb(EWRK3_CSR));
- }
- /*
- ** We stop the EWRK3 here... mask interrupts and stop TX & RX
- */
- DISABLE_IRQs;
-
- STOP_EWRK3;
-
- /*
- ** Clean out the TX and RX queues here (note that one entry
- ** may get added to either the TXD or RX queues if the TX or RX
- ** just starts processing a packet before the STOP_EWRK3 command
- ** is received. This will be flushed in the ewrk3_open() call).
- */
- while (inb(EWRK3_TQ));
- while (inb(EWRK3_TDQ));
- while (inb(EWRK3_RQ));
-
- if (!lp->hard_strapped) {
- free_irq(dev->irq, dev);
- }
- return 0;
-}
-
-/*
- ** Set or clear the multicast filter for this adapter.
- */
-static void set_multicast_list(struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- u_long iobase = dev->base_addr;
- u_char csr;
-
- csr = inb(EWRK3_CSR);
-
- if (lp->shmem_length == IO_ONLY) {
- lp->mctbl = NULL;
- } else {
- lp->mctbl = lp->shmem + PAGE0_HTE;
- }
-
- csr &= ~(CSR_PME | CSR_MCE);
- if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
- csr |= CSR_PME;
- outb(csr, EWRK3_CSR);
- } else {
- SetMulticastFilter(dev);
- csr |= CSR_MCE;
- outb(csr, EWRK3_CSR);
- }
-}
-
-/*
- ** Calculate the hash code and update the logical address filter
- ** from a list of ethernet multicast addresses.
- ** Little endian crc one liner from Matt Thomas, DEC.
- **
- ** Note that when clearing the table, the broadcast bit must remain asserted
- ** to receive broadcast messages.
- */
-static void SetMulticastFilter(struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- struct netdev_hw_addr *ha;
- u_long iobase = dev->base_addr;
- int i;
- char bit, byte;
- short __iomem *p = lp->mctbl;
- u16 hashcode;
- u32 crc;
-
- spin_lock_irq(&lp->hw_lock);
-
- if (lp->shmem_length == IO_ONLY) {
- outb(0, EWRK3_IOPR);
- outw(PAGE0_HTE, EWRK3_PIR1);
- } else {
- outb(0, EWRK3_MPR);
- }
-
- if (dev->flags & IFF_ALLMULTI) {
- for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
- if (lp->shmem_length == IO_ONLY) {
- outb(0xff, EWRK3_DATA);
- } else { /* memset didn't work here */
- writew(0xffff, p);
- p++;
- i++;
- }
- }
- } else {
- /* Clear table except for broadcast bit */
- if (lp->shmem_length == IO_ONLY) {
- for (i = 0; i < (HASH_TABLE_LEN >> 4) - 1; i++) {
- outb(0x00, EWRK3_DATA);
- }
- outb(0x80, EWRK3_DATA);
- i++; /* insert the broadcast bit */
- for (; i < (HASH_TABLE_LEN >> 3); i++) {
- outb(0x00, EWRK3_DATA);
- }
- } else {
- memset_io(lp->mctbl, 0, HASH_TABLE_LEN >> 3);
- writeb(0x80, lp->mctbl + (HASH_TABLE_LEN >> 4) - 1);
- }
-
- /* Update table */
- netdev_for_each_mc_addr(ha, dev) {
- crc = ether_crc_le(ETH_ALEN, ha->addr);
- hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */
-
- byte = hashcode >> 3; /* bit[3-8] -> byte in filter */
- bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */
-
- if (lp->shmem_length == IO_ONLY) {
- u_char tmp;
-
- outw(PAGE0_HTE + byte, EWRK3_PIR1);
- tmp = inb(EWRK3_DATA);
- tmp |= bit;
- outw(PAGE0_HTE + byte, EWRK3_PIR1);
- outb(tmp, EWRK3_DATA);
- } else {
- writeb(readb(lp->mctbl + byte) | bit, lp->mctbl + byte);
- }
- }
- }
-
- spin_unlock_irq(&lp->hw_lock);
-}
-
-/*
- ** ISA bus I/O device probe
- */
-static int __init isa_probe(struct net_device *dev, u_long ioaddr)
-{
- int i = num_ewrks3s, maxSlots;
- int ret = -ENODEV;
-
- u_long iobase;
-
- if (ioaddr >= 0x400)
- goto out;
-
- if (ioaddr == 0) { /* Autoprobing */
- iobase = EWRK3_IO_BASE; /* Get the first slot address */
- maxSlots = 24;
- } else { /* Probe a specific location */
- iobase = ioaddr;
- maxSlots = i + 1;
- }
-
- for (; (i < maxSlots) && (dev != NULL);
- iobase += EWRK3_IOP_INC, i++)
- {
- if (request_region(iobase, EWRK3_TOTAL_SIZE, DRV_NAME)) {
- if (DevicePresent(iobase) == 0) {
- int irq = dev->irq;
- ret = ewrk3_hw_init(dev, iobase);
- if (!ret)
- break;
- dev->irq = irq;
- }
- release_region(iobase, EWRK3_TOTAL_SIZE);
- }
- }
- out:
-
- return ret;
-}
-
-/*
- ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
- ** the motherboard.
- */
-static int __init eisa_probe(struct net_device *dev, u_long ioaddr)
-{
- int i, maxSlots;
- u_long iobase;
- int ret = -ENODEV;
-
- if (ioaddr < 0x1000)
- goto out;
-
- iobase = ioaddr;
- i = (ioaddr >> 12);
- maxSlots = i + 1;
-
- for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) {
- if (EISA_signature(name, EISA_ID) == 0) {
- if (request_region(iobase, EWRK3_TOTAL_SIZE, DRV_NAME) &&
- DevicePresent(iobase) == 0) {
- int irq = dev->irq;
- ret = ewrk3_hw_init(dev, iobase);
- if (!ret)
- break;
- dev->irq = irq;
- }
- release_region(iobase, EWRK3_TOTAL_SIZE);
- }
- }
-
- out:
- return ret;
-}
-
-
-/*
- ** Read the EWRK3 EEPROM using this routine
- */
-static int Read_EEPROM(u_long iobase, u_char eaddr)
-{
- int i;
-
- outb((eaddr & 0x3f), EWRK3_PIR1); /* set up 6 bits of address info */
- outb(EEPROM_RD, EWRK3_IOPR); /* issue read command */
- for (i = 0; i < 5000; i++)
- inb(EWRK3_CSR); /* wait 1msec */
-
- return inw(EWRK3_EPROM1); /* 16 bits data return */
-}
-
-/*
- ** Write the EWRK3 EEPROM using this routine
- */
-static int Write_EEPROM(short data, u_long iobase, u_char eaddr)
-{
- int i;
-
- outb(EEPROM_WR_EN, EWRK3_IOPR); /* issue write enable command */
- for (i = 0; i < 5000; i++)
- inb(EWRK3_CSR); /* wait 1msec */
- outw(data, EWRK3_EPROM1); /* write data to register */
- outb((eaddr & 0x3f), EWRK3_PIR1); /* set up 6 bits of address info */
- outb(EEPROM_WR, EWRK3_IOPR); /* issue write command */
- for (i = 0; i < 75000; i++)
- inb(EWRK3_CSR); /* wait 15msec */
- outb(EEPROM_WR_DIS, EWRK3_IOPR); /* issue write disable command */
- for (i = 0; i < 5000; i++)
- inb(EWRK3_CSR); /* wait 1msec */
-
- return 0;
-}
-
-/*
- ** Look for a particular board name in the on-board EEPROM.
- */
-static void __init EthwrkSignature(char *name, char *eeprom_image)
-{
- int i;
- char *signatures[] = EWRK3_SIGNATURE;
-
- for (i=0; *signatures[i] != '\0'; i++)
- if( !strncmp(eeprom_image+EEPROM_PNAME7, signatures[i], strlen(signatures[i])) )
- break;
-
- if (*signatures[i] != '\0') {
- memcpy(name, eeprom_image+EEPROM_PNAME7, EWRK3_STRLEN);
- name[EWRK3_STRLEN] = '\0';
- } else
- name[0] = '\0';
-}
-
-/*
- ** Look for a special sequence in the Ethernet station address PROM that
- ** is common across all EWRK3 products.
- **
- ** Search the Ethernet address ROM for the signature. Since the ROM address
- ** counter can start at an arbitrary point, the search must include the entire
- ** probe sequence length plus the (length_of_the_signature - 1).
- ** Stop the search IMMEDIATELY after the signature is found so that the
- ** PROM address counter is correctly positioned at the start of the
- ** ethernet address for later read out.
- */
-
-static int __init DevicePresent(u_long iobase)
-{
- union {
- struct {
- u32 a;
- u32 b;
- } llsig;
- char Sig[sizeof(u32) << 1];
- }
- dev;
- short sigLength;
- char data;
- int i, j, status = 0;
-
- dev.llsig.a = ETH_PROM_SIG;
- dev.llsig.b = ETH_PROM_SIG;
- sigLength = sizeof(u32) << 1;
-
- for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) {
- data = inb(EWRK3_APROM);
- if (dev.Sig[j] == data) { /* track signature */
- j++;
- } else { /* lost signature; begin search again */
- if (data == dev.Sig[0]) {
- j = 1;
- } else {
- j = 0;
- }
- }
- }
-
- if (j != sigLength) {
- status = -ENODEV; /* search failed */
- }
- return status;
-}
-
-static u_char __init get_hw_addr(struct net_device *dev, u_char * eeprom_image, char chipType)
-{
- int i, j, k;
- u_short chksum;
- u_char crc, lfsr, sd, status = 0;
- u_long iobase = dev->base_addr;
- u16 tmp;
-
- if (chipType == LeMAC2) {
- for (crc = 0x6a, j = 0; j < ETH_ALEN; j++) {
- sd = dev->dev_addr[j] = eeprom_image[EEPROM_PADDR0 + j];
- outb(dev->dev_addr[j], EWRK3_PAR0 + j);
- for (k = 0; k < 8; k++, sd >>= 1) {
- lfsr = ((((crc & 0x02) >> 1) ^ (crc & 0x01)) ^ (sd & 0x01)) << 7;
- crc = (crc >> 1) + lfsr;
- }
- }
- if (crc != eeprom_image[EEPROM_PA_CRC])
- status = -1;
- } else {
- for (i = 0, k = 0; i < ETH_ALEN;) {
- k <<= 1;
- if (k > 0xffff)
- k -= 0xffff;
-
- k += (u_char) (tmp = inb(EWRK3_APROM));
- dev->dev_addr[i] = (u_char) tmp;
- outb(dev->dev_addr[i], EWRK3_PAR0 + i);
- i++;
- k += (u_short) ((tmp = inb(EWRK3_APROM)) << 8);
- dev->dev_addr[i] = (u_char) tmp;
- outb(dev->dev_addr[i], EWRK3_PAR0 + i);
- i++;
-
- if (k > 0xffff)
- k -= 0xffff;
- }
- if (k == 0xffff)
- k = 0;
- chksum = inb(EWRK3_APROM);
- chksum |= (inb(EWRK3_APROM) << 8);
- if (k != chksum)
- status = -1;
- }
-
- return status;
-}
-
-/*
- ** Look for a particular board name in the EISA configuration space
- */
-static int __init EISA_signature(char *name, s32 eisa_id)
-{
- u_long i;
- char *signatures[] = EWRK3_SIGNATURE;
- char ManCode[EWRK3_STRLEN];
- union {
- s32 ID;
- char Id[4];
- } Eisa;
- int status = 0;
-
- *name = '\0';
- for (i = 0; i < 4; i++) {
- Eisa.Id[i] = inb(eisa_id + i);
- }
-
- ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40);
- ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40);
- ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30);
- ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30);
- ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30);
- ManCode[5] = '\0';
-
- for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) {
- if (strstr(ManCode, signatures[i]) != NULL) {
- strcpy(name, ManCode);
- status = 1;
- }
- }
-
- return status; /* return the device name string */
-}
-
-static void ewrk3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- int fwrev = Read_EEPROM(dev->base_addr, EEPROM_REVLVL);
-
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->fw_version, "%d", fwrev);
- strcpy(info->bus_info, "N/A");
- info->eedump_len = EEPROM_MAX;
-}
-
-static int ewrk3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- unsigned long iobase = dev->base_addr;
- u8 cr = inb(EWRK3_CR);
-
- switch (lp->adapter_name[4]) {
- case '3': /* DE203 */
- ecmd->supported = SUPPORTED_BNC;
- ecmd->port = PORT_BNC;
- break;
-
- case '4': /* DE204 */
- ecmd->supported = SUPPORTED_TP;
- ecmd->port = PORT_TP;
- break;
-
- case '5': /* DE205 */
- ecmd->supported = SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_AUI;
- ecmd->autoneg = !(cr & CR_APD);
- /*
- ** Port is only valid if autoneg is disabled
- ** and even then we don't know if AUI is jumpered.
- */
- if (!ecmd->autoneg)
- ecmd->port = (cr & CR_PSEL) ? PORT_BNC : PORT_TP;
- break;
- }
-
- ecmd->supported |= SUPPORTED_10baseT_Half;
- ethtool_cmd_speed_set(ecmd, SPEED_10);
- ecmd->duplex = DUPLEX_HALF;
- return 0;
-}
-
-static int ewrk3_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- unsigned long iobase = dev->base_addr;
- unsigned long flags;
- u8 cr;
-
- /* DE205 is the only card with anything to set */
- if (lp->adapter_name[4] != '5')
- return -EOPNOTSUPP;
-
- /* Sanity-check parameters */
- if (ecmd->speed != SPEED_10)
- return -EINVAL;
- if (ecmd->port != PORT_TP && ecmd->port != PORT_BNC)
- return -EINVAL; /* AUI is not software-selectable */
- if (ecmd->transceiver != XCVR_INTERNAL)
- return -EINVAL;
- if (ecmd->duplex != DUPLEX_HALF)
- return -EINVAL;
- if (ecmd->phy_address != 0)
- return -EINVAL;
-
- spin_lock_irqsave(&lp->hw_lock, flags);
- cr = inb(EWRK3_CR);
-
- /* If Autoneg is set, change to Auto Port mode */
- /* Otherwise, disable Auto Port and set port explicitly */
- if (ecmd->autoneg) {
- cr &= ~CR_APD;
- } else {
- cr |= CR_APD;
- if (ecmd->port == PORT_TP)
- cr &= ~CR_PSEL; /* Force TP */
- else
- cr |= CR_PSEL; /* Force BNC */
- }
-
- /* Commit the changes */
- outb(cr, EWRK3_CR);
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- return 0;
-}
-
-static u32 ewrk3_get_link(struct net_device *dev)
-{
- unsigned long iobase = dev->base_addr;
- u8 cmr = inb(EWRK3_CMR);
- /* DE203 has BNC only and link status does not apply */
- /* On DE204 this is always valid since TP is the only port. */
- /* On DE205 this reflects TP status even if BNC or AUI is selected. */
- return !(cmr & CMR_LINK);
-}
-
-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;
- u8 cr;
-
- spin_lock_irq(&lp->hw_lock);
-
- 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 */
-
- case ETHTOOL_ID_ON:
- cr = inb(EWRK3_CR);
- outb(cr | CR_LED, EWRK3_CR);
- break;
-
- case ETHTOOL_ID_OFF:
- cr = inb(EWRK3_CR);
- outb(cr & ~CR_LED, EWRK3_CR);
- 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);
-
- 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,
- .set_phys_id = ewrk3_set_phys_id,
-};
-
-static const struct ethtool_ops ethtool_ops = {
- .get_drvinfo = ewrk3_get_drvinfo,
- .get_settings = ewrk3_get_settings,
- .set_settings = ewrk3_set_settings,
- .get_link = ewrk3_get_link,
- .set_phys_id = ewrk3_set_phys_id,
-};
-
-/*
- ** Perform IOCTL call functions here. Some are privileged operations and the
- ** effective uid is checked in those cases.
- */
-static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
- struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_ifru;
- u_long iobase = dev->base_addr;
- int i, j, status = 0;
- u_char csr;
- unsigned long flags;
- union ewrk3_addr {
- u_char addr[HASH_TABLE_LEN * ETH_ALEN];
- u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
- };
-
- union ewrk3_addr *tmp;
-
- /* All we handle are private IOCTLs */
- if (cmd != EWRK3IOCTL)
- return -EOPNOTSUPP;
-
- tmp = kmalloc(sizeof(union ewrk3_addr), GFP_KERNEL);
- if(tmp==NULL)
- return -ENOMEM;
-
- switch (ioc->cmd) {
- case EWRK3_GET_HWADDR: /* Get the hardware address */
- for (i = 0; i < ETH_ALEN; i++) {
- tmp->addr[i] = dev->dev_addr[i];
- }
- ioc->len = ETH_ALEN;
- if (copy_to_user(ioc->data, tmp->addr, ioc->len))
- status = -EFAULT;
- break;
-
- case EWRK3_SET_HWADDR: /* Set the hardware address */
- if (capable(CAP_NET_ADMIN)) {
- spin_lock_irqsave(&lp->hw_lock, flags);
- csr = inb(EWRK3_CSR);
- csr |= (CSR_TXD | CSR_RXD);
- outb(csr, EWRK3_CSR); /* Disable the TX and RX */
- spin_unlock_irqrestore(&lp->hw_lock, flags);
-
- if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN)) {
- status = -EFAULT;
- break;
- }
- spin_lock_irqsave(&lp->hw_lock, flags);
- for (i = 0; i < ETH_ALEN; i++) {
- dev->dev_addr[i] = tmp->addr[i];
- outb(tmp->addr[i], EWRK3_PAR0 + i);
- }
-
- csr = inb(EWRK3_CSR);
- csr &= ~(CSR_TXD | CSR_RXD); /* Enable the TX and RX */
- outb(csr, EWRK3_CSR);
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_SET_PROM: /* Set Promiscuous Mode */
- if (capable(CAP_NET_ADMIN)) {
- spin_lock_irqsave(&lp->hw_lock, flags);
- csr = inb(EWRK3_CSR);
- csr |= CSR_PME;
- csr &= ~CSR_MCE;
- outb(csr, EWRK3_CSR);
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_CLR_PROM: /* Clear Promiscuous Mode */
- if (capable(CAP_NET_ADMIN)) {
- spin_lock_irqsave(&lp->hw_lock, flags);
- csr = inb(EWRK3_CSR);
- csr &= ~CSR_PME;
- outb(csr, EWRK3_CSR);
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_GET_MCA: /* Get the multicast address table */
- spin_lock_irqsave(&lp->hw_lock, flags);
- if (lp->shmem_length == IO_ONLY) {
- outb(0, EWRK3_IOPR);
- outw(PAGE0_HTE, EWRK3_PIR1);
- for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
- tmp->addr[i] = inb(EWRK3_DATA);
- }
- } else {
- outb(0, EWRK3_MPR);
- memcpy_fromio(tmp->addr, lp->shmem + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
- }
- spin_unlock_irqrestore(&lp->hw_lock, flags);
-
- ioc->len = (HASH_TABLE_LEN >> 3);
- if (copy_to_user(ioc->data, tmp->addr, ioc->len))
- status = -EFAULT;
-
- break;
- case EWRK3_SET_MCA: /* Set a multicast address */
- if (capable(CAP_NET_ADMIN)) {
- if (ioc->len > HASH_TABLE_LEN) {
- status = -EINVAL;
- break;
- }
- if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN * ioc->len)) {
- status = -EFAULT;
- break;
- }
- set_multicast_list(dev);
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_CLR_MCA: /* Clear all multicast addresses */
- if (capable(CAP_NET_ADMIN)) {
- set_multicast_list(dev);
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_MCA_EN: /* Enable multicast addressing */
- if (capable(CAP_NET_ADMIN)) {
- spin_lock_irqsave(&lp->hw_lock, flags);
- csr = inb(EWRK3_CSR);
- csr |= CSR_MCE;
- csr &= ~CSR_PME;
- outb(csr, EWRK3_CSR);
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_GET_STATS: { /* Get the driver statistics */
- struct ewrk3_stats *tmp_stats =
- kmalloc(sizeof(lp->pktStats), GFP_KERNEL);
- if (!tmp_stats) {
- status = -ENOMEM;
- break;
- }
-
- spin_lock_irqsave(&lp->hw_lock, flags);
- memcpy(tmp_stats, &lp->pktStats, sizeof(lp->pktStats));
- spin_unlock_irqrestore(&lp->hw_lock, flags);
-
- ioc->len = sizeof(lp->pktStats);
- if (copy_to_user(ioc->data, tmp_stats, sizeof(lp->pktStats)))
- status = -EFAULT;
- kfree(tmp_stats);
- break;
- }
- case EWRK3_CLR_STATS: /* Zero out the driver statistics */
- if (capable(CAP_NET_ADMIN)) {
- spin_lock_irqsave(&lp->hw_lock, flags);
- memset(&lp->pktStats, 0, sizeof(lp->pktStats));
- spin_unlock_irqrestore(&lp->hw_lock,flags);
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_GET_CSR: /* Get the CSR Register contents */
- tmp->addr[0] = inb(EWRK3_CSR);
- ioc->len = 1;
- if (copy_to_user(ioc->data, tmp->addr, ioc->len))
- status = -EFAULT;
- break;
- case EWRK3_SET_CSR: /* Set the CSR Register contents */
- if (capable(CAP_NET_ADMIN)) {
- if (copy_from_user(tmp->addr, ioc->data, 1)) {
- status = -EFAULT;
- break;
- }
- outb(tmp->addr[0], EWRK3_CSR);
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_GET_EEPROM: /* Get the EEPROM contents */
- if (capable(CAP_NET_ADMIN)) {
- for (i = 0; i < (EEPROM_MAX >> 1); i++) {
- tmp->val[i] = (short) Read_EEPROM(iobase, i);
- }
- i = EEPROM_MAX;
- tmp->addr[i++] = inb(EWRK3_CMR); /* Config/Management Reg. */
- for (j = 0; j < ETH_ALEN; j++) {
- tmp->addr[i++] = inb(EWRK3_PAR0 + j);
- }
- ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
- if (copy_to_user(ioc->data, tmp->addr, ioc->len))
- status = -EFAULT;
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_SET_EEPROM: /* Set the EEPROM contents */
- if (capable(CAP_NET_ADMIN)) {
- if (copy_from_user(tmp->addr, ioc->data, EEPROM_MAX)) {
- status = -EFAULT;
- break;
- }
- for (i = 0; i < (EEPROM_MAX >> 1); i++) {
- Write_EEPROM(tmp->val[i], iobase, i);
- }
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_GET_CMR: /* Get the CMR Register contents */
- tmp->addr[0] = inb(EWRK3_CMR);
- ioc->len = 1;
- if (copy_to_user(ioc->data, tmp->addr, ioc->len))
- status = -EFAULT;
- break;
- case EWRK3_SET_TX_CUT_THRU: /* Set TX cut through mode */
- if (capable(CAP_NET_ADMIN)) {
- lp->txc = 1;
- } else {
- status = -EPERM;
- }
-
- break;
- case EWRK3_CLR_TX_CUT_THRU: /* Clear TX cut through mode */
- if (capable(CAP_NET_ADMIN)) {
- lp->txc = 0;
- } else {
- status = -EPERM;
- }
-
- break;
- default:
- status = -EOPNOTSUPP;
- }
- kfree(tmp);
- return status;
-}
-
-#ifdef MODULE
-static struct net_device *ewrk3_devs[MAX_NUM_EWRK3S];
-static int ndevs;
-static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, };
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, byte, NULL, 0);
-MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number(s)");
-
-static __exit void ewrk3_exit_module(void)
-{
- int i;
-
- for( i=0; i<ndevs; i++ ) {
- struct net_device *dev = ewrk3_devs[i];
- struct ewrk3_private *lp = netdev_priv(dev);
- ewrk3_devs[i] = NULL;
- unregister_netdev(dev);
- release_region(dev->base_addr, EWRK3_TOTAL_SIZE);
- iounmap(lp->shmem);
- free_netdev(dev);
- }
-}
-
-static __init int ewrk3_init_module(void)
-{
- int i=0;
-
- while( io[i] && irq[i] ) {
- struct net_device *dev
- = alloc_etherdev(sizeof(struct ewrk3_private));
-
- if (!dev)
- break;
-
- if (ewrk3_probe1(dev, io[i], irq[i]) != 0) {
- free_netdev(dev);
- break;
- }
-
- ewrk3_devs[ndevs++] = dev;
- i++;
- }
-
- return ndevs ? 0 : -EIO;
-}
-
-
-/* Hack for breakage in new module stuff */
-module_exit(ewrk3_exit_module);
-module_init(ewrk3_init_module);
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dec/ewrk3.h b/drivers/net/ethernet/dec/ewrk3.h
deleted file mode 100644
index 8e0ee906567b..000000000000
--- a/drivers/net/ethernet/dec/ewrk3.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- Written 1994 by David C. Davies.
-
- Copyright 1994 Digital Equipment Corporation.
-
- This software may be used and distributed according to the terms of the
- GNU General Public License, incorporated herein by reference.
-
- The author may be reached as davies@wanton.lkg.dec.com or Digital
- Equipment Corporation, 550 King Street, Littleton MA 01460.
-
- =========================================================================
-*/
-
-/*
-** I/O Address Register Map
-*/
-#define EWRK3_CSR iobase+0x00 /* Control and Status Register */
-#define EWRK3_CR iobase+0x01 /* Control Register */
-#define EWRK3_ICR iobase+0x02 /* Interrupt Control Register */
-#define EWRK3_TSR iobase+0x03 /* Transmit Status Register */
-#define EWRK3_RSVD1 iobase+0x04 /* RESERVED */
-#define EWRK3_RSVD2 iobase+0x05 /* RESERVED */
-#define EWRK3_FMQ iobase+0x06 /* Free Memory Queue */
-#define EWRK3_FMQC iobase+0x07 /* Free Memory Queue Counter */
-#define EWRK3_RQ iobase+0x08 /* Receive Queue */
-#define EWRK3_RQC iobase+0x09 /* Receive Queue Counter */
-#define EWRK3_TQ iobase+0x0a /* Transmit Queue */
-#define EWRK3_TQC iobase+0x0b /* Transmit Queue Counter */
-#define EWRK3_TDQ iobase+0x0c /* Transmit Done Queue */
-#define EWRK3_TDQC iobase+0x0d /* Transmit Done Queue Counter */
-#define EWRK3_PIR1 iobase+0x0e /* Page Index Register 1 */
-#define EWRK3_PIR2 iobase+0x0f /* Page Index Register 2 */
-#define EWRK3_DATA iobase+0x10 /* Data Register */
-#define EWRK3_IOPR iobase+0x11 /* I/O Page Register */
-#define EWRK3_IOBR iobase+0x12 /* I/O Base Register */
-#define EWRK3_MPR iobase+0x13 /* Memory Page Register */
-#define EWRK3_MBR iobase+0x14 /* Memory Base Register */
-#define EWRK3_APROM iobase+0x15 /* Address PROM */
-#define EWRK3_EPROM1 iobase+0x16 /* EEPROM Data Register 1 */
-#define EWRK3_EPROM2 iobase+0x17 /* EEPROM Data Register 2 */
-#define EWRK3_PAR0 iobase+0x18 /* Physical Address Register 0 */
-#define EWRK3_PAR1 iobase+0x19 /* Physical Address Register 1 */
-#define EWRK3_PAR2 iobase+0x1a /* Physical Address Register 2 */
-#define EWRK3_PAR3 iobase+0x1b /* Physical Address Register 3 */
-#define EWRK3_PAR4 iobase+0x1c /* Physical Address Register 4 */
-#define EWRK3_PAR5 iobase+0x1d /* Physical Address Register 5 */
-#define EWRK3_CMR iobase+0x1e /* Configuration/Management Register */
-
-/*
-** Control Page Map
-*/
-#define PAGE0_FMQ 0x000 /* Free Memory Queue */
-#define PAGE0_RQ 0x080 /* Receive Queue */
-#define PAGE0_TQ 0x100 /* Transmit Queue */
-#define PAGE0_TDQ 0x180 /* Transmit Done Queue */
-#define PAGE0_HTE 0x200 /* Hash Table Entries */
-#define PAGE0_RSVD 0x240 /* RESERVED */
-#define PAGE0_USRD 0x600 /* User Data */
-
-/*
-** Control and Status Register bit definitions (EWRK3_CSR)
-*/
-#define CSR_RA 0x80 /* Runt Accept */
-#define CSR_PME 0x40 /* Promiscuous Mode Enable */
-#define CSR_MCE 0x20 /* Multicast Enable */
-#define CSR_TNE 0x08 /* TX Done Queue Not Empty */
-#define CSR_RNE 0x04 /* RX Queue Not Empty */
-#define CSR_TXD 0x02 /* TX Disable */
-#define CSR_RXD 0x01 /* RX Disable */
-
-/*
-** Control Register bit definitions (EWRK3_CR)
-*/
-#define CR_APD 0x80 /* Auto Port Disable */
-#define CR_PSEL 0x40 /* Port Select (0->TP port) */
-#define CR_LBCK 0x20 /* LoopBaCK enable */
-#define CR_FDUP 0x10 /* Full DUPlex enable */
-#define CR_FBUS 0x08 /* Fast BUS enable (ISA clk > 8.33MHz) */
-#define CR_EN_16 0x04 /* ENable 16 bit memory accesses */
-#define CR_LED 0x02 /* LED (1-> turn on) */
-
-/*
-** Interrupt Control Register bit definitions (EWRK3_ICR)
-*/
-#define ICR_IE 0x80 /* Interrupt Enable */
-#define ICR_IS 0x60 /* Interrupt Selected */
-#define ICR_TNEM 0x08 /* TNE Mask (0->mask) */
-#define ICR_RNEM 0x04 /* RNE Mask (0->mask) */
-#define ICR_TXDM 0x02 /* TXD Mask (0->mask) */
-#define ICR_RXDM 0x01 /* RXD Mask (0->mask) */
-
-/*
-** Transmit Status Register bit definitions (EWRK3_TSR)
-*/
-#define TSR_NCL 0x80 /* No Carrier Loopback */
-#define TSR_ID 0x40 /* Initially Deferred */
-#define TSR_LCL 0x20 /* Late CoLlision */
-#define TSR_ECL 0x10 /* Excessive CoLlisions */
-#define TSR_RCNTR 0x0f /* Retries CouNTeR */
-
-/*
-** I/O Page Register bit definitions (EWRK3_IOPR)
-*/
-#define EEPROM_INIT 0xc0 /* EEPROM INIT command */
-#define EEPROM_WR_EN 0xc8 /* EEPROM WRITE ENABLE command */
-#define EEPROM_WR 0xd0 /* EEPROM WRITE command */
-#define EEPROM_WR_DIS 0xd8 /* EEPROM WRITE DISABLE command */
-#define EEPROM_RD 0xe0 /* EEPROM READ command */
-
-/*
-** I/O Base Register bit definitions (EWRK3_IOBR)
-*/
-#define EISA_REGS_EN 0x20 /* Enable EISA ID and Control Registers */
-#define EISA_IOB 0x1f /* Compare bits for I/O Base Address */
-
-/*
-** I/O Configuration/Management Register bit definitions (EWRK3_CMR)
-*/
-#define CMR_RA 0x80 /* Read Ahead */
-#define CMR_WB 0x40 /* Write Behind */
-#define CMR_LINK 0x20 /* 0->TP */
-#define CMR_POLARITY 0x10 /* Informational */
-#define CMR_NO_EEPROM 0x0c /* NO_EEPROM<1:0> pin status */
-#define CMR_HS 0x08 /* Hard Strapped pin status (LeMAC2) */
-#define CMR_PNP 0x04 /* Plug 'n Play */
-#define CMR_DRAM 0x02 /* 0-> 1DRAM, 1-> 2 DRAM on board */
-#define CMR_0WS 0x01 /* Zero Wait State */
-
-/*
-** MAC Receive Status Register bit definitions
-*/
-
-#define R_ROK 0x80 /* Receive OK summary */
-#define R_IAM 0x10 /* Individual Address Match */
-#define R_MCM 0x08 /* MultiCast Match */
-#define R_DBE 0x04 /* Dribble Bit Error */
-#define R_CRC 0x02 /* CRC error */
-#define R_PLL 0x01 /* Phase Lock Lost */
-
-/*
-** MAC Transmit Control Register bit definitions
-*/
-
-#define TCR_SQEE 0x40 /* SQE Enable - look for heartbeat */
-#define TCR_SED 0x20 /* Stop when Error Detected */
-#define TCR_QMODE 0x10 /* Q_MODE */
-#define TCR_LAB 0x08 /* Less Aggressive Backoff */
-#define TCR_PAD 0x04 /* PAD Runt Packets */
-#define TCR_IFC 0x02 /* Insert Frame Check */
-#define TCR_ISA 0x01 /* Insert Source Address */
-
-/*
-** MAC Transmit Status Register bit definitions
-*/
-
-#define T_VSTS 0x80 /* Valid STatuS */
-#define T_CTU 0x40 /* Cut Through Used */
-#define T_SQE 0x20 /* Signal Quality Error */
-#define T_NCL 0x10 /* No Carrier Loopback */
-#define T_LCL 0x08 /* Late Collision */
-#define T_ID 0x04 /* Initially Deferred */
-#define T_COLL 0x03 /* COLLision status */
-#define T_XCOLL 0x03 /* Excessive Collisions */
-#define T_MCOLL 0x02 /* Multiple Collisions */
-#define T_OCOLL 0x01 /* One Collision */
-#define T_NOCOLL 0x00 /* No Collisions */
-#define T_XUR 0x03 /* Excessive Underruns */
-#define T_TXE 0x7f /* TX Errors */
-
-/*
-** EISA Configuration Register bit definitions
-*/
-
-#define EISA_ID iobase + 0x0c80 /* EISA ID Registers */
-#define EISA_ID0 iobase + 0x0c80 /* EISA ID Register 0 */
-#define EISA_ID1 iobase + 0x0c81 /* EISA ID Register 1 */
-#define EISA_ID2 iobase + 0x0c82 /* EISA ID Register 2 */
-#define EISA_ID3 iobase + 0x0c83 /* EISA ID Register 3 */
-#define EISA_CR iobase + 0x0c84 /* EISA Control Register */
-
-/*
-** EEPROM BYTES
-*/
-#define EEPROM_MEMB 0x00
-#define EEPROM_IOB 0x01
-#define EEPROM_EISA_ID0 0x02
-#define EEPROM_EISA_ID1 0x03
-#define EEPROM_EISA_ID2 0x04
-#define EEPROM_EISA_ID3 0x05
-#define EEPROM_MISC0 0x06
-#define EEPROM_MISC1 0x07
-#define EEPROM_PNAME7 0x08
-#define EEPROM_PNAME6 0x09
-#define EEPROM_PNAME5 0x0a
-#define EEPROM_PNAME4 0x0b
-#define EEPROM_PNAME3 0x0c
-#define EEPROM_PNAME2 0x0d
-#define EEPROM_PNAME1 0x0e
-#define EEPROM_PNAME0 0x0f
-#define EEPROM_SWFLAGS 0x10
-#define EEPROM_HWCAT 0x11
-#define EEPROM_NETMAN2 0x12
-#define EEPROM_REVLVL 0x13
-#define EEPROM_NETMAN0 0x14
-#define EEPROM_NETMAN1 0x15
-#define EEPROM_CHIPVER 0x16
-#define EEPROM_SETUP 0x17
-#define EEPROM_PADDR0 0x18
-#define EEPROM_PADDR1 0x19
-#define EEPROM_PADDR2 0x1a
-#define EEPROM_PADDR3 0x1b
-#define EEPROM_PADDR4 0x1c
-#define EEPROM_PADDR5 0x1d
-#define EEPROM_PA_CRC 0x1e
-#define EEPROM_CHKSUM 0x1f
-
-/*
-** EEPROM bytes for checksumming
-*/
-#define EEPROM_MAX 32 /* bytes */
-
-/*
-** EEPROM MISCELLANEOUS FLAGS
-*/
-#define RBE_SHADOW 0x0100 /* Remote Boot Enable Shadow */
-#define READ_AHEAD 0x0080 /* Read Ahead feature */
-#define IRQ_SEL2 0x0070 /* IRQ line selection (LeMAC2) */
-#define IRQ_SEL 0x0060 /* IRQ line selection */
-#define FAST_BUS 0x0008 /* ISA Bus speeds > 8.33MHz */
-#define ENA_16 0x0004 /* Enables 16 bit memory transfers */
-#define WRITE_BEHIND 0x0002 /* Write Behind feature */
-#define _0WS_ENA 0x0001 /* Zero Wait State Enable */
-
-/*
-** EEPROM NETWORK MANAGEMENT FLAGS
-*/
-#define NETMAN_POL 0x04 /* Polarity defeat */
-#define NETMAN_LINK 0x02 /* Link defeat */
-#define NETMAN_CCE 0x01 /* Custom Counters Enable */
-
-/*
-** EEPROM SW FLAGS
-*/
-#define SW_SQE 0x10 /* Signal Quality Error */
-#define SW_LAB 0x08 /* Less Aggressive Backoff */
-#define SW_INIT 0x04 /* Initialized */
-#define SW_TIMEOUT 0x02 /* 0:2.5 mins, 1: 30 secs */
-#define SW_REMOTE 0x01 /* Remote Boot Enable -> 1 */
-
-/*
-** EEPROM SETUP FLAGS
-*/
-#define SETUP_APD 0x80 /* AutoPort Disable */
-#define SETUP_PS 0x40 /* Port Select */
-#define SETUP_MP 0x20 /* MultiPort */
-#define SETUP_1TP 0x10 /* 1 port, TP */
-#define SETUP_1COAX 0x00 /* 1 port, Coax */
-#define SETUP_DRAM 0x02 /* Number of DRAMS on board */
-
-/*
-** EEPROM MANAGEMENT FLAGS
-*/
-#define MGMT_CCE 0x01 /* Custom Counters Enable */
-
-/*
-** EEPROM VERSIONS
-*/
-#define LeMAC 0x11
-#define LeMAC2 0x12
-
-/*
-** Miscellaneous
-*/
-
-#define EEPROM_WAIT_TIME 1000 /* Number of microseconds */
-#define EISA_EN 0x0001 /* Enable EISA bus buffers */
-
-#define HASH_TABLE_LEN 512 /* Bits */
-
-#define XCT 0x80 /* Transmit Cut Through */
-#define PRELOAD 16 /* 4 long words */
-
-#define MASK_INTERRUPTS 1
-#define UNMASK_INTERRUPTS 0
-
-#define EEPROM_OFFSET(a) ((u_short)((u_long)(a)))
-
-/*
-** Include the IOCTL stuff
-*/
-#include <linux/sockios.h>
-
-#define EWRK3IOCTL SIOCDEVPRIVATE
-
-struct ewrk3_ioctl {
- unsigned short cmd; /* Command to run */
- unsigned short len; /* Length of the data buffer */
- unsigned char __user *data; /* Pointer to the data buffer */
-};
-
-/*
-** Recognised commands for the driver
-*/
-#define EWRK3_GET_HWADDR 0x01 /* Get the hardware address */
-#define EWRK3_SET_HWADDR 0x02 /* Get the hardware address */
-#define EWRK3_SET_PROM 0x03 /* Set Promiscuous Mode */
-#define EWRK3_CLR_PROM 0x04 /* Clear Promiscuous Mode */
-#define EWRK3_SAY_BOO 0x05 /* Say "Boo!" to the kernel log file */
-#define EWRK3_GET_MCA 0x06 /* Get a multicast address */
-#define EWRK3_SET_MCA 0x07 /* Set a multicast address */
-#define EWRK3_CLR_MCA 0x08 /* Clear a multicast address */
-#define EWRK3_MCA_EN 0x09 /* Enable a multicast address group */
-#define EWRK3_GET_STATS 0x0a /* Get the driver statistics */
-#define EWRK3_CLR_STATS 0x0b /* Zero out the driver statistics */
-#define EWRK3_GET_CSR 0x0c /* Get the CSR Register contents */
-#define EWRK3_SET_CSR 0x0d /* Set the CSR Register contents */
-#define EWRK3_GET_EEPROM 0x0e /* Get the EEPROM contents */
-#define EWRK3_SET_EEPROM 0x0f /* Set the EEPROM contents */
-#define EWRK3_GET_CMR 0x10 /* Get the CMR Register contents */
-#define EWRK3_CLR_TX_CUT_THRU 0x11 /* Clear the TX cut through mode */
-#define EWRK3_SET_TX_CUT_THRU 0x12 /* Set the TX cut through mode */
diff --git a/drivers/net/ethernet/dec/tulip/Kconfig b/drivers/net/ethernet/dec/tulip/Kconfig
index 1203be0436e2..0c37fb2cc867 100644
--- a/drivers/net/ethernet/dec/tulip/Kconfig
+++ b/drivers/net/ethernet/dec/tulip/Kconfig
@@ -57,8 +57,8 @@ config TULIP
be called tulip.
config TULIP_MWI
- bool "New bus configuration (EXPERIMENTAL)"
- depends on TULIP && EXPERIMENTAL
+ bool "New bus configuration"
+ depends on TULIP
---help---
This configures your Tulip card specifically for the card and
system cache line size type you are using.
diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig
index b5afe218c31b..ee26ce78e270 100644
--- a/drivers/net/ethernet/dlink/Kconfig
+++ b/drivers/net/ethernet/dlink/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_DLINK
bool "D-Link devices"
default y
- depends on PCI || PARPORT
+ depends on PCI
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -18,36 +18,6 @@ config NET_VENDOR_DLINK
if NET_VENDOR_DLINK
-config DE600
- tristate "D-Link DE600 pocket adapter support"
- depends on PARPORT
- ---help---
- This is a network (Ethernet) device which attaches to your parallel
- port. Read <file:Documentation/networking/DLINK.txt> as well as the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, if you want to use
- this. It is possible to have several devices share a single parallel
- port and it is safe to compile the corresponding drivers into the
- kernel.
-
- To compile this driver as a module, choose M here: the module
- will be called de600.
-
-config DE620
- tristate "D-Link DE620 pocket adapter support"
- depends on PARPORT
- ---help---
- This is a network (Ethernet) device which attaches to your parallel
- port. Read <file:Documentation/networking/DLINK.txt> as well as the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, if you want to use
- this. It is possible to have several devices share a single parallel
- port and it is safe to compile the corresponding drivers into the
- kernel.
-
- To compile this driver as a module, choose M here: the module
- will be called de620.
-
config DL2K
tristate "DL2000/TC902x-based Gigabit Ethernet support"
depends on PCI
diff --git a/drivers/net/ethernet/dlink/Makefile b/drivers/net/ethernet/dlink/Makefile
index c705eaa4f5b2..40085f67157b 100644
--- a/drivers/net/ethernet/dlink/Makefile
+++ b/drivers/net/ethernet/dlink/Makefile
@@ -2,7 +2,5 @@
# Makefile for the D-Link network device drivers.
#
-obj-$(CONFIG_DE600) += de600.o
-obj-$(CONFIG_DE620) += de620.o
obj-$(CONFIG_DL2K) += dl2k.o
obj-$(CONFIG_SUNDANCE) += sundance.o
diff --git a/drivers/net/ethernet/dlink/de600.c b/drivers/net/ethernet/dlink/de600.c
deleted file mode 100644
index 414f0eea1049..000000000000
--- a/drivers/net/ethernet/dlink/de600.c
+++ /dev/null
@@ -1,529 +0,0 @@
-static const char version[] = "de600.c: $Revision: 1.41-2.5 $, Bjorn Ekwall (bj0rn@blox.se)\n";
-/*
- * de600.c
- *
- * Linux driver for the D-Link DE-600 Ethernet pocket adapter.
- *
- * Portions (C) Copyright 1993, 1994 by Bjorn Ekwall
- * The Author may be reached as bj0rn@blox.se
- *
- * Based on adapter information gathered from DE600.ASM by D-Link Inc.,
- * as included on disk C in the v.2.11 of PC/TCP from FTP Software.
- * For DE600.asm:
- * Portions (C) Copyright 1990 D-Link, Inc.
- * Copyright, 1988-1992, Russell Nelson, Crynwr Software
- *
- * Adapted to the sample network driver core for linux,
- * written by: Donald Becker <becker@super.org>
- * (Now at <becker@scyld.com>)
- *
- **************************************************************/
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- **************************************************************/
-
-/* Add more time here if your adapter won't work OK: */
-#define DE600_SLOW_DOWN udelay(delay_time)
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-#include "de600.h"
-
-static bool check_lost = true;
-module_param(check_lost, bool, 0);
-MODULE_PARM_DESC(check_lost, "If set then check for unplugged de600");
-
-static unsigned int delay_time = 10;
-module_param(delay_time, int, 0);
-MODULE_PARM_DESC(delay_time, "DE-600 deley on I/O in microseconds");
-
-
-/*
- * D-Link driver variables:
- */
-
-static volatile int rx_page;
-
-#define TX_PAGES 2
-static volatile int tx_fifo[TX_PAGES];
-static volatile int tx_fifo_in;
-static volatile int tx_fifo_out;
-static volatile int free_tx_pages = TX_PAGES;
-static int was_down;
-static DEFINE_SPINLOCK(de600_lock);
-
-static inline u8 de600_read_status(struct net_device *dev)
-{
- u8 status;
-
- outb_p(STATUS, DATA_PORT);
- status = inb(STATUS_PORT);
- outb_p(NULL_COMMAND | HI_NIBBLE, DATA_PORT);
-
- return status;
-}
-
-static inline u8 de600_read_byte(unsigned char type, struct net_device *dev)
-{
- /* dev used by macros */
- u8 lo;
- outb_p((type), DATA_PORT);
- lo = ((unsigned char)inb(STATUS_PORT)) >> 4;
- outb_p((type) | HI_NIBBLE, DATA_PORT);
- return ((unsigned char)inb(STATUS_PORT) & (unsigned char)0xf0) | lo;
-}
-
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * after booting when 'ifconfig <dev->name> $IP_ADDR' is run (in rc.inet1).
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is a non-reboot way to recover if something goes wrong.
- */
-
-static int de600_open(struct net_device *dev)
-{
- unsigned long flags;
- int ret = request_irq(DE600_IRQ, de600_interrupt, 0, dev->name, dev);
- if (ret) {
- printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, DE600_IRQ);
- return ret;
- }
- spin_lock_irqsave(&de600_lock, flags);
- ret = adapter_init(dev);
- spin_unlock_irqrestore(&de600_lock, flags);
- return ret;
-}
-
-/*
- * The inverse routine to de600_open().
- */
-
-static int de600_close(struct net_device *dev)
-{
- select_nic();
- rx_page = 0;
- de600_put_command(RESET);
- de600_put_command(STOP_RESET);
- de600_put_command(0);
- select_prn();
- free_irq(DE600_IRQ, dev);
- return 0;
-}
-
-static inline void trigger_interrupt(struct net_device *dev)
-{
- de600_put_command(FLIP_IRQ);
- select_prn();
- DE600_SLOW_DOWN;
- select_nic();
- de600_put_command(0);
-}
-
-/*
- * Copy a buffer to the adapter transmit page memory.
- * Start sending.
- */
-
-static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- unsigned long flags;
- int transmit_from;
- int len;
- int tickssofar;
- u8 *buffer = skb->data;
- int i;
-
- if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */
- tickssofar = jiffies - dev_trans_start(dev);
- if (tickssofar < HZ/20)
- return NETDEV_TX_BUSY;
- /* else */
- printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem");
- /* Restart the adapter. */
- spin_lock_irqsave(&de600_lock, flags);
- if (adapter_init(dev)) {
- spin_unlock_irqrestore(&de600_lock, flags);
- return NETDEV_TX_BUSY;
- }
- spin_unlock_irqrestore(&de600_lock, flags);
- }
-
- /* Start real output */
- pr_debug("de600_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages);
-
- if ((len = skb->len) < RUNT)
- len = RUNT;
-
- spin_lock_irqsave(&de600_lock, flags);
- select_nic();
- tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
- tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */
-
- if(check_lost)
- {
- /* This costs about 40 instructions per packet... */
- de600_setup_address(NODE_ADDRESS, RW_ADDR);
- de600_read_byte(READ_DATA, dev);
- if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) {
- if (adapter_init(dev)) {
- spin_unlock_irqrestore(&de600_lock, flags);
- return NETDEV_TX_BUSY;
- }
- }
- }
-
- de600_setup_address(transmit_from, RW_ADDR);
- for (i = 0; i < skb->len ; ++i, ++buffer)
- de600_put_byte(*buffer);
- for (; i < len; ++i)
- de600_put_byte(0);
-
- if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
- dev->trans_start = jiffies;
- netif_start_queue(dev); /* allow more packets into adapter */
- /* Send page and generate a faked interrupt */
- de600_setup_address(transmit_from, TX_ADDR);
- de600_put_command(TX_ENABLE);
- }
- else {
- if (free_tx_pages)
- netif_start_queue(dev);
- else
- netif_stop_queue(dev);
- select_prn();
- }
- spin_unlock_irqrestore(&de600_lock, flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-
-static irqreturn_t de600_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- u8 irq_status;
- int retrig = 0;
- int boguscount = 0;
-
- spin_lock(&de600_lock);
-
- select_nic();
- irq_status = de600_read_status(dev);
-
- do {
- pr_debug("de600_interrupt (%02X)\n", irq_status);
-
- if (irq_status & RX_GOOD)
- de600_rx_intr(dev);
- else if (!(irq_status & RX_BUSY))
- de600_put_command(RX_ENABLE);
-
- /* Any transmission in progress? */
- if (free_tx_pages < TX_PAGES)
- retrig = de600_tx_intr(dev, irq_status);
- else
- retrig = 0;
-
- irq_status = de600_read_status(dev);
- } while ( (irq_status & RX_GOOD) || ((++boguscount < 100) && retrig) );
- /*
- * Yeah, it _looks_ like busy waiting, smells like busy waiting
- * and I know it's not PC, but please, it will only occur once
- * in a while and then only for a loop or so (< 1ms for sure!)
- */
-
- /* Enable adapter interrupts */
- select_prn();
- if (retrig)
- trigger_interrupt(dev);
- spin_unlock(&de600_lock);
- return IRQ_HANDLED;
-}
-
-static int de600_tx_intr(struct net_device *dev, int irq_status)
-{
- /*
- * Returns 1 if tx still not done
- */
-
- /* Check if current transmission is done yet */
- if (irq_status & TX_BUSY)
- return 1; /* tx not done, try again */
-
- /* else */
- /* If last transmission OK then bump fifo index */
- if (!(irq_status & TX_FAILED16)) {
- tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
- ++free_tx_pages;
- dev->stats.tx_packets++;
- netif_wake_queue(dev);
- }
-
- /* More to send, or resend last packet? */
- if ((free_tx_pages < TX_PAGES) || (irq_status & TX_FAILED16)) {
- dev->trans_start = jiffies;
- de600_setup_address(tx_fifo[tx_fifo_out], TX_ADDR);
- de600_put_command(TX_ENABLE);
- return 1;
- }
- /* else */
-
- return 0;
-}
-
-/*
- * We have a good packet, get it out of the adapter.
- */
-static void de600_rx_intr(struct net_device *dev)
-{
- struct sk_buff *skb;
- int i;
- int read_from;
- int size;
- unsigned char *buffer;
-
- /* Get size of received packet */
- size = de600_read_byte(RX_LEN, dev); /* low byte */
- size += (de600_read_byte(RX_LEN, dev) << 8); /* high byte */
- size -= 4; /* Ignore trailing 4 CRC-bytes */
-
- /* Tell adapter where to store next incoming packet, enable receiver */
- read_from = rx_page_adr();
- next_rx_page();
- de600_put_command(RX_ENABLE);
-
- if ((size < 32) || (size > 1535)) {
- printk(KERN_WARNING "%s: Bogus packet size %d.\n", dev->name, size);
- if (size > 10000)
- adapter_init(dev);
- return;
- }
-
- skb = netdev_alloc_skb(dev, size + 2);
- if (skb == NULL) {
- printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
- return;
- }
- /* else */
-
- skb_reserve(skb,2); /* Align */
-
- /* 'skb->data' points to the start of sk_buff data area. */
- buffer = skb_put(skb,size);
-
- /* copy the packet into the buffer */
- de600_setup_address(read_from, RW_ADDR);
- for (i = size; i > 0; --i, ++buffer)
- *buffer = de600_read_byte(READ_DATA, dev);
-
- skb->protocol=eth_type_trans(skb,dev);
-
- netif_rx(skb);
-
- /* update stats */
- dev->stats.rx_packets++; /* count all receives */
- dev->stats.rx_bytes += size; /* count all received bytes */
-
- /*
- * If any worth-while packets have been received, netif_rx()
- * will work on them when we get to the tasklets.
- */
-}
-
-static const struct net_device_ops de600_netdev_ops = {
- .ndo_open = de600_open,
- .ndo_stop = de600_close,
- .ndo_start_xmit = de600_start_xmit,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-
-static struct net_device * __init de600_probe(void)
-{
- int i;
- struct net_device *dev;
- int err;
-
- dev = alloc_etherdev(0);
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
-
- if (!request_region(DE600_IO, 3, "de600")) {
- printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO);
- err = -EBUSY;
- goto out;
- }
-
- printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name);
- /* Alpha testers must have the version number to report bugs. */
- pr_debug("%s", version);
-
- /* probe for adapter */
- err = -ENODEV;
- rx_page = 0;
- select_nic();
- (void)de600_read_status(dev);
- de600_put_command(RESET);
- de600_put_command(STOP_RESET);
- if (de600_read_status(dev) & 0xf0) {
- printk(": not at I/O %#3x.\n", DATA_PORT);
- goto out1;
- }
-
- /*
- * Maybe we found one,
- * have to check if it is a D-Link DE-600 adapter...
- */
-
- /* Get the adapter ethernet address from the ROM */
- de600_setup_address(NODE_ADDRESS, RW_ADDR);
- for (i = 0; i < ETH_ALEN; i++) {
- dev->dev_addr[i] = de600_read_byte(READ_DATA, dev);
- dev->broadcast[i] = 0xff;
- }
-
- /* Check magic code */
- if ((dev->dev_addr[1] == 0xde) && (dev->dev_addr[2] == 0x15)) {
- /* OK, install real address */
- dev->dev_addr[0] = 0x00;
- dev->dev_addr[1] = 0x80;
- dev->dev_addr[2] = 0xc8;
- dev->dev_addr[3] &= 0x0f;
- dev->dev_addr[3] |= 0x70;
- } else {
- printk(" not identified in the printer port\n");
- goto out1;
- }
-
- printk(", Ethernet Address: %pM\n", dev->dev_addr);
-
- dev->netdev_ops = &de600_netdev_ops;
-
- dev->flags&=~IFF_MULTICAST;
-
- select_prn();
-
- err = register_netdev(dev);
- if (err)
- goto out1;
-
- return dev;
-
-out1:
- release_region(DE600_IO, 3);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static int adapter_init(struct net_device *dev)
-{
- int i;
-
- select_nic();
- rx_page = 0; /* used by RESET */
- de600_put_command(RESET);
- de600_put_command(STOP_RESET);
-
- /* Check if it is still there... */
- /* Get the some bytes of the adapter ethernet address from the ROM */
- de600_setup_address(NODE_ADDRESS, RW_ADDR);
- de600_read_byte(READ_DATA, dev);
- if ((de600_read_byte(READ_DATA, dev) != 0xde) ||
- (de600_read_byte(READ_DATA, dev) != 0x15)) {
- /* was: if (de600_read_status(dev) & 0xf0) { */
- printk("Something has happened to the DE-600! Please check it and do a new ifconfig!\n");
- /* Goodbye, cruel world... */
- dev->flags &= ~IFF_UP;
- de600_close(dev);
- was_down = 1;
- netif_stop_queue(dev); /* Transmit busy... */
- return 1; /* failed */
- }
-
- if (was_down) {
- printk(KERN_INFO "%s: Thanks, I feel much better now!\n", dev->name);
- was_down = 0;
- }
-
- tx_fifo_in = 0;
- tx_fifo_out = 0;
- free_tx_pages = TX_PAGES;
-
-
- /* set the ether address. */
- de600_setup_address(NODE_ADDRESS, RW_ADDR);
- for (i = 0; i < ETH_ALEN; i++)
- de600_put_byte(dev->dev_addr[i]);
-
- /* where to start saving incoming packets */
- rx_page = RX_BP | RX_BASE_PAGE;
- de600_setup_address(MEM_4K, RW_ADDR);
- /* Enable receiver */
- de600_put_command(RX_ENABLE);
- select_prn();
-
- netif_start_queue(dev);
-
- return 0; /* OK */
-}
-
-static struct net_device *de600_dev;
-
-static int __init de600_init(void)
-{
- de600_dev = de600_probe();
- if (IS_ERR(de600_dev))
- return PTR_ERR(de600_dev);
- return 0;
-}
-
-static void __exit de600_exit(void)
-{
- unregister_netdev(de600_dev);
- release_region(DE600_IO, 3);
- free_netdev(de600_dev);
-}
-
-module_init(de600_init);
-module_exit(de600_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dlink/de600.h b/drivers/net/ethernet/dlink/de600.h
deleted file mode 100644
index e80ecbabcf4e..000000000000
--- a/drivers/net/ethernet/dlink/de600.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/**************************************************
- * *
- * Definition of D-Link Ethernet Pocket adapter *
- * *
- **************************************************/
-/*
- * D-Link Ethernet pocket adapter ports
- */
-/*
- * OK, so I'm cheating, but there are an awful lot of
- * reads and writes in order to get anything in and out
- * of the DE-600 with 4 bits at a time in the parallel port,
- * so every saved instruction really helps :-)
- */
-
-#ifndef DE600_IO
-#define DE600_IO 0x378
-#endif
-
-#define DATA_PORT (DE600_IO)
-#define STATUS_PORT (DE600_IO + 1)
-#define COMMAND_PORT (DE600_IO + 2)
-
-#ifndef DE600_IRQ
-#define DE600_IRQ 7
-#endif
-/*
- * It really should look like this, and autoprobing as well...
- *
-#define DATA_PORT (dev->base_addr + 0)
-#define STATUS_PORT (dev->base_addr + 1)
-#define COMMAND_PORT (dev->base_addr + 2)
-#define DE600_IRQ dev->irq
- */
-
-/*
- * D-Link COMMAND_PORT commands
- */
-#define SELECT_NIC 0x04 /* select Network Interface Card */
-#define SELECT_PRN 0x1c /* select Printer */
-#define NML_PRN 0xec /* normal Printer situation */
-#define IRQEN 0x10 /* enable IRQ line */
-
-/*
- * D-Link STATUS_PORT
- */
-#define RX_BUSY 0x80
-#define RX_GOOD 0x40
-#define TX_FAILED16 0x10
-#define TX_BUSY 0x08
-
-/*
- * D-Link DATA_PORT commands
- * command in low 4 bits
- * data in high 4 bits
- * select current data nibble with HI_NIBBLE bit
- */
-#define WRITE_DATA 0x00 /* write memory */
-#define READ_DATA 0x01 /* read memory */
-#define STATUS 0x02 /* read status register */
-#define COMMAND 0x03 /* write command register (see COMMAND below) */
-#define NULL_COMMAND 0x04 /* null command */
-#define RX_LEN 0x05 /* read received packet length */
-#define TX_ADDR 0x06 /* set adapter transmit memory address */
-#define RW_ADDR 0x07 /* set adapter read/write memory address */
-#define HI_NIBBLE 0x08 /* read/write the high nibble of data,
- or-ed with rest of command */
-
-/*
- * command register, accessed through DATA_PORT with low bits = COMMAND
- */
-#define RX_ALL 0x01 /* PROMISCUOUS */
-#define RX_BP 0x02 /* default: BROADCAST & PHYSICAL ADDRESS */
-#define RX_MBP 0x03 /* MULTICAST, BROADCAST & PHYSICAL ADDRESS */
-
-#define TX_ENABLE 0x04 /* bit 2 */
-#define RX_ENABLE 0x08 /* bit 3 */
-
-#define RESET 0x80 /* set bit 7 high */
-#define STOP_RESET 0x00 /* set bit 7 low */
-
-/*
- * data to command register
- * (high 4 bits in write to DATA_PORT)
- */
-#define RX_PAGE2_SELECT 0x10 /* bit 4, only 2 pages to select */
-#define RX_BASE_PAGE 0x20 /* bit 5, always set when specifying RX_ADDR */
-#define FLIP_IRQ 0x40 /* bit 6 */
-
-/*
- * D-Link adapter internal memory:
- *
- * 0-2K 1:st transmit page (send from pointer up to 2K)
- * 2-4K 2:nd transmit page (send from pointer up to 4K)
- *
- * 4-6K 1:st receive page (data from 4K upwards)
- * 6-8K 2:nd receive page (data from 6K upwards)
- *
- * 8K+ Adapter ROM (contains magic code and last 3 bytes of Ethernet address)
- */
-#define MEM_2K 0x0800 /* 2048 */
-#define MEM_4K 0x1000 /* 4096 */
-#define MEM_6K 0x1800 /* 6144 */
-#define NODE_ADDRESS 0x2000 /* 8192 */
-
-#define RUNT 60 /* Too small Ethernet packet */
-
-/**************************************************
- * *
- * End of definition *
- * *
- **************************************************/
-
-/*
- * Index to functions, as function prototypes.
- */
-/* Routines used internally. (See "convenience macros") */
-static u8 de600_read_status(struct net_device *dev);
-static u8 de600_read_byte(unsigned char type, struct net_device *dev);
-
-/* Put in the device structure. */
-static int de600_open(struct net_device *dev);
-static int de600_close(struct net_device *dev);
-static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
-
-/* Dispatch from interrupts. */
-static irqreturn_t de600_interrupt(int irq, void *dev_id);
-static int de600_tx_intr(struct net_device *dev, int irq_status);
-static void de600_rx_intr(struct net_device *dev);
-
-/* Initialization */
-static void trigger_interrupt(struct net_device *dev);
-static int adapter_init(struct net_device *dev);
-
-/*
- * Convenience macros/functions for D-Link adapter
- */
-
-#define select_prn() outb_p(SELECT_PRN, COMMAND_PORT); DE600_SLOW_DOWN
-#define select_nic() outb_p(SELECT_NIC, COMMAND_PORT); DE600_SLOW_DOWN
-
-/* Thanks for hints from Mark Burton <markb@ordern.demon.co.uk> */
-#define de600_put_byte(data) ( \
- outb_p(((data) << 4) | WRITE_DATA , DATA_PORT), \
- outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT))
-
-/*
- * The first two outb_p()'s below could perhaps be deleted if there
- * would be more delay in the last two. Not certain about it yet...
- */
-#define de600_put_command(cmd) ( \
- outb_p(( rx_page << 4) | COMMAND , DATA_PORT), \
- outb_p(( rx_page & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT), \
- outb_p(((rx_page | cmd) << 4) | COMMAND , DATA_PORT), \
- outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT))
-
-#define de600_setup_address(addr,type) ( \
- outb_p((((addr) << 4) & 0xf0) | type , DATA_PORT), \
- outb_p(( (addr) & 0xf0) | type | HI_NIBBLE, DATA_PORT), \
- outb_p((((addr) >> 4) & 0xf0) | type , DATA_PORT), \
- outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT))
-
-#define rx_page_adr() ((rx_page & RX_PAGE2_SELECT)?(MEM_6K):(MEM_4K))
-
-/* Flip bit, only 2 pages */
-#define next_rx_page() (rx_page ^= RX_PAGE2_SELECT)
-
-#define tx_page_adr(a) (((a) + 1) * MEM_2K)
diff --git a/drivers/net/ethernet/dlink/de620.c b/drivers/net/ethernet/dlink/de620.c
deleted file mode 100644
index 2e2bc60ee811..000000000000
--- a/drivers/net/ethernet/dlink/de620.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*
- * de620.c $Revision: 1.40 $ BETA
- *
- *
- * Linux driver for the D-Link DE-620 Ethernet pocket adapter.
- *
- * Portions (C) Copyright 1993, 1994 by Bjorn Ekwall <bj0rn@blox.se>
- *
- * Based on adapter information gathered from DOS packetdriver
- * sources from D-Link Inc: (Special thanks to Henry Ngai of D-Link.)
- * Portions (C) Copyright D-Link SYSTEM Inc. 1991, 1992
- * Copyright, 1988, Russell Nelson, Crynwr Software
- *
- * Adapted to the sample network driver core for linux,
- * written by: Donald Becker <becker@super.org>
- * (Now at <becker@scyld.com>)
- *
- * Valuable assistance from:
- * J. Joshua Kopper <kopper@rtsg.mot.com>
- * Olav Kvittem <Olav.Kvittem@uninett.no>
- * Germano Caronni <caronni@nessie.cs.id.ethz.ch>
- * Jeremy Fitzhardinge <jeremy@suite.sw.oz.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, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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.
- *
- *****************************************************************************/
-static const char version[] =
- "de620.c: $Revision: 1.40 $, Bjorn Ekwall <bj0rn@blox.se>\n";
-
-/***********************************************************************
- *
- * "Tuning" section.
- *
- * Compile-time options: (see below for descriptions)
- * -DDE620_IO=0x378 (lpt1)
- * -DDE620_IRQ=7 (lpt1)
- * -DSHUTDOWN_WHEN_LOST
- * -DCOUNT_LOOPS
- * -DLOWSPEED
- * -DREAD_DELAY
- * -DWRITE_DELAY
- */
-
-/*
- * This driver assumes that the printer port is a "normal",
- * dumb, uni-directional port!
- * If your port is "fancy" in any way, please try to set it to "normal"
- * with your BIOS setup. I have no access to machines with bi-directional
- * ports, so I can't test such a driver :-(
- * (Yes, I _know_ it is possible to use DE620 with bidirectional ports...)
- *
- * There are some clones of DE620 out there, with different names.
- * If the current driver does not recognize a clone, try to change
- * the following #define to:
- *
- * #define DE620_CLONE 1
- */
-#define DE620_CLONE 0
-
-/*
- * If the adapter has problems with high speeds, enable this #define
- * otherwise full printerport speed will be attempted.
- *
- * You can tune the READ_DELAY/WRITE_DELAY below if you enable LOWSPEED
- *
-#define LOWSPEED
- */
-
-#ifndef READ_DELAY
-#define READ_DELAY 100 /* adapter internal read delay in 100ns units */
-#endif
-
-#ifndef WRITE_DELAY
-#define WRITE_DELAY 100 /* adapter internal write delay in 100ns units */
-#endif
-
-/*
- * Enable this #define if you want the adapter to do a "ifconfig down" on
- * itself when we have detected that something is possibly wrong with it.
- * The default behaviour is to retry with "adapter_init()" until success.
- * This should be used for debugging purposes only.
- *
-#define SHUTDOWN_WHEN_LOST
- */
-
-#ifdef LOWSPEED
-/*
- * Enable this #define if you want to see debugging output that show how long
- * we have to wait before the DE-620 is ready for the next read/write/command.
- *
-#define COUNT_LOOPS
- */
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-/* Constant definitions for the DE-620 registers, commands and bits */
-#include "de620.h"
-
-typedef unsigned char byte;
-
-/*******************************************************
- * *
- * Definition of D-Link DE-620 Ethernet Pocket adapter *
- * See also "de620.h" *
- * *
- *******************************************************/
-#ifndef DE620_IO /* Compile-time configurable */
-#define DE620_IO 0x378
-#endif
-
-#ifndef DE620_IRQ /* Compile-time configurable */
-#define DE620_IRQ 7
-#endif
-
-#define DATA_PORT (dev->base_addr)
-#define STATUS_PORT (dev->base_addr + 1)
-#define COMMAND_PORT (dev->base_addr + 2)
-
-#define RUNT 60 /* Too small Ethernet packet */
-#define GIANT 1514 /* largest legal size packet, no fcs */
-
-/*
- * Force media with insmod:
- * insmod de620.o bnc=1
- * or
- * insmod de620.o utp=1
- *
- * Force io and/or irq with insmod:
- * insmod de620.o io=0x378 irq=7
- *
- * Make a clone skip the Ethernet-address range check:
- * insmod de620.o clone=1
- */
-static int bnc;
-static int utp;
-static int io = DE620_IO;
-static int irq = DE620_IRQ;
-static int clone = DE620_CLONE;
-
-static spinlock_t de620_lock;
-
-module_param(bnc, int, 0);
-module_param(utp, int, 0);
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(clone, int, 0);
-MODULE_PARM_DESC(bnc, "DE-620 set BNC medium (0-1)");
-MODULE_PARM_DESC(utp, "DE-620 set UTP medium (0-1)");
-MODULE_PARM_DESC(io, "DE-620 I/O base address,required");
-MODULE_PARM_DESC(irq, "DE-620 IRQ number,required");
-MODULE_PARM_DESC(clone, "Check also for non-D-Link DE-620 clones (0-1)");
-
-/***********************************************
- * *
- * Index to functions, as function prototypes. *
- * *
- ***********************************************/
-
-/*
- * Routines used internally. (See also "convenience macros.. below")
- */
-
-/* Put in the device structure. */
-static int de620_open(struct net_device *);
-static int de620_close(struct net_device *);
-static void de620_set_multicast_list(struct net_device *);
-static int de620_start_xmit(struct sk_buff *, struct net_device *);
-
-/* Dispatch from interrupts. */
-static irqreturn_t de620_interrupt(int, void *);
-static int de620_rx_intr(struct net_device *);
-
-/* Initialization */
-static int adapter_init(struct net_device *);
-static int read_eeprom(struct net_device *);
-
-
-/*
- * D-Link driver variables:
- */
-#define SCR_DEF NIBBLEMODE |INTON | SLEEP | AUTOTX
-#define TCR_DEF RXPB /* not used: | TXSUCINT | T16INT */
-#define DE620_RX_START_PAGE 12 /* 12 pages (=3k) reserved for tx */
-#define DEF_NIC_CMD IRQEN | ICEN | DS1
-
-static volatile byte NIC_Cmd;
-static volatile byte next_rx_page;
-static byte first_rx_page;
-static byte last_rx_page;
-static byte EIPRegister;
-
-static struct nic {
- byte NodeID[6];
- byte RAM_Size;
- byte Model;
- byte Media;
- byte SCR;
-} nic_data;
-
-/**********************************************************
- * *
- * Convenience macros/functions for D-Link DE-620 adapter *
- * *
- **********************************************************/
-#define de620_tx_buffs(dd) (inb(STATUS_PORT) & (TXBF0 | TXBF1))
-#define de620_flip_ds(dd) NIC_Cmd ^= DS0 | DS1; outb(NIC_Cmd, COMMAND_PORT);
-
-/* Check for ready-status, and return a nibble (high 4 bits) for data input */
-#ifdef COUNT_LOOPS
-static int tot_cnt;
-#endif
-static inline byte
-de620_ready(struct net_device *dev)
-{
- byte value;
- register short int cnt = 0;
-
- while ((((value = inb(STATUS_PORT)) & READY) == 0) && (cnt <= 1000))
- ++cnt;
-
-#ifdef COUNT_LOOPS
- tot_cnt += cnt;
-#endif
- return value & 0xf0; /* nibble */
-}
-
-static inline void
-de620_send_command(struct net_device *dev, byte cmd)
-{
- de620_ready(dev);
- if (cmd == W_DUMMY)
- outb(NIC_Cmd, COMMAND_PORT);
-
- outb(cmd, DATA_PORT);
-
- outb(NIC_Cmd ^ CS0, COMMAND_PORT);
- de620_ready(dev);
- outb(NIC_Cmd, COMMAND_PORT);
-}
-
-static inline void
-de620_put_byte(struct net_device *dev, byte value)
-{
- /* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
- de620_ready(dev);
- outb(value, DATA_PORT);
- de620_flip_ds(dev);
-}
-
-static inline byte
-de620_read_byte(struct net_device *dev)
-{
- byte value;
-
- /* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
- value = de620_ready(dev); /* High nibble */
- de620_flip_ds(dev);
- value |= de620_ready(dev) >> 4; /* Low nibble */
- return value;
-}
-
-static inline void
-de620_write_block(struct net_device *dev, byte *buffer, int count, int pad)
-{
-#ifndef LOWSPEED
- byte uflip = NIC_Cmd ^ (DS0 | DS1);
- byte dflip = NIC_Cmd;
-#else /* LOWSPEED */
-#ifdef COUNT_LOOPS
- int bytes = count;
-#endif /* COUNT_LOOPS */
-#endif /* LOWSPEED */
-
-#ifdef LOWSPEED
-#ifdef COUNT_LOOPS
- tot_cnt = 0;
-#endif /* COUNT_LOOPS */
- /* No further optimization useful, the limit is in the adapter. */
- for ( ; count > 0; --count, ++buffer) {
- de620_put_byte(dev,*buffer);
- }
- for ( count = pad ; count > 0; --count, ++buffer) {
- de620_put_byte(dev, 0);
- }
- de620_send_command(dev,W_DUMMY);
-#ifdef COUNT_LOOPS
- /* trial debug output: loops per byte in de620_ready() */
- printk("WRITE(%d)\n", tot_cnt/((bytes?bytes:1)));
-#endif /* COUNT_LOOPS */
-#else /* not LOWSPEED */
- for ( ; count > 0; count -=2) {
- outb(*buffer++, DATA_PORT);
- outb(uflip, COMMAND_PORT);
- outb(*buffer++, DATA_PORT);
- outb(dflip, COMMAND_PORT);
- }
- de620_send_command(dev,W_DUMMY);
-#endif /* LOWSPEED */
-}
-
-static inline void
-de620_read_block(struct net_device *dev, byte *data, int count)
-{
-#ifndef LOWSPEED
- byte value;
- byte uflip = NIC_Cmd ^ (DS0 | DS1);
- byte dflip = NIC_Cmd;
-#else /* LOWSPEED */
-#ifdef COUNT_LOOPS
- int bytes = count;
-
- tot_cnt = 0;
-#endif /* COUNT_LOOPS */
-#endif /* LOWSPEED */
-
-#ifdef LOWSPEED
- /* No further optimization useful, the limit is in the adapter. */
- while (count-- > 0) {
- *data++ = de620_read_byte(dev);
- de620_flip_ds(dev);
- }
-#ifdef COUNT_LOOPS
- /* trial debug output: loops per byte in de620_ready() */
- printk("READ(%d)\n", tot_cnt/(2*(bytes?bytes:1)));
-#endif /* COUNT_LOOPS */
-#else /* not LOWSPEED */
- while (count-- > 0) {
- value = inb(STATUS_PORT) & 0xf0; /* High nibble */
- outb(uflip, COMMAND_PORT);
- *data++ = value | inb(STATUS_PORT) >> 4; /* Low nibble */
- outb(dflip , COMMAND_PORT);
- }
-#endif /* LOWSPEED */
-}
-
-static inline void
-de620_set_delay(struct net_device *dev)
-{
- de620_ready(dev);
- outb(W_DFR, DATA_PORT);
- outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-
- de620_ready(dev);
-#ifdef LOWSPEED
- outb(WRITE_DELAY, DATA_PORT);
-#else
- outb(0, DATA_PORT);
-#endif
- de620_flip_ds(dev);
-
- de620_ready(dev);
-#ifdef LOWSPEED
- outb(READ_DELAY, DATA_PORT);
-#else
- outb(0, DATA_PORT);
-#endif
- de620_flip_ds(dev);
-}
-
-static inline void
-de620_set_register(struct net_device *dev, byte reg, byte value)
-{
- de620_ready(dev);
- outb(reg, DATA_PORT);
- outb(NIC_Cmd ^ CS0, COMMAND_PORT);
-
- de620_put_byte(dev, value);
-}
-
-static inline byte
-de620_get_register(struct net_device *dev, byte reg)
-{
- byte value;
-
- de620_send_command(dev,reg);
- value = de620_read_byte(dev);
- de620_send_command(dev,W_DUMMY);
-
- return value;
-}
-
-/*********************************************************************
- *
- * Open/initialize the board.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is a non-reboot way to recover if something goes wrong.
- *
- */
-static int de620_open(struct net_device *dev)
-{
- int ret = request_irq(dev->irq, de620_interrupt, 0, dev->name, dev);
- if (ret) {
- printk (KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq);
- return ret;
- }
-
- if (adapter_init(dev)) {
- ret = -EIO;
- goto out_free_irq;
- }
-
- netif_start_queue(dev);
- return 0;
-
-out_free_irq:
- free_irq(dev->irq, dev);
- return ret;
-}
-
-/************************************************
- *
- * The inverse routine to de620_open().
- *
- */
-
-static int de620_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
- /* disable recv */
- de620_set_register(dev, W_TCR, RXOFF);
- free_irq(dev->irq, dev);
- return 0;
-}
-
-/*********************************************
- *
- * Set or clear the multicast filter for this adaptor.
- * (no real multicast implemented for the DE-620, but she can be promiscuous...)
- *
- */
-
-static void de620_set_multicast_list(struct net_device *dev)
-{
- if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
- { /* Enable promiscuous mode */
- de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL);
- }
- else
- { /* Disable promiscuous mode, use normal mode */
- de620_set_register(dev, W_TCR, TCR_DEF);
- }
-}
-
-/*******************************************************
- *
- * Handle timeouts on transmit
- */
-
-static void de620_timeout(struct net_device *dev)
-{
- printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, "network cable problem");
- /* Restart the adapter. */
- if (!adapter_init(dev)) /* maybe close it */
- netif_wake_queue(dev);
-}
-
-/*******************************************************
- *
- * Copy a buffer to the adapter transmit page memory.
- * Start sending.
- */
-static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- unsigned long flags;
- int len;
- byte *buffer = skb->data;
- byte using_txbuf;
-
- using_txbuf = de620_tx_buffs(dev); /* Peek at the adapter */
-
- netif_stop_queue(dev);
-
-
- if ((len = skb->len) < RUNT)
- len = RUNT;
- if (len & 1) /* send an even number of bytes */
- ++len;
-
- /* Start real output */
-
- spin_lock_irqsave(&de620_lock, flags);
- pr_debug("de620_start_xmit: len=%d, bufs 0x%02x\n",
- (int)skb->len, using_txbuf);
-
- /* select a free tx buffer. if there is one... */
- switch (using_txbuf) {
- default: /* both are free: use TXBF0 */
- case TXBF1: /* use TXBF0 */
- de620_send_command(dev,W_CR | RW0);
- using_txbuf |= TXBF0;
- break;
-
- case TXBF0: /* use TXBF1 */
- de620_send_command(dev,W_CR | RW1);
- using_txbuf |= TXBF1;
- break;
-
- case (TXBF0 | TXBF1): /* NONE!!! */
- printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name);
- spin_unlock_irqrestore(&de620_lock, flags);
- return NETDEV_TX_BUSY;
- }
- de620_write_block(dev, buffer, skb->len, len-skb->len);
-
- if(!(using_txbuf == (TXBF0 | TXBF1)))
- netif_wake_queue(dev);
-
- dev->stats.tx_packets++;
- spin_unlock_irqrestore(&de620_lock, flags);
- dev_kfree_skb (skb);
- return NETDEV_TX_OK;
-}
-
-/*****************************************************
- *
- * Handle the network interface interrupts.
- *
- */
-static irqreturn_t
-de620_interrupt(int irq_in, void *dev_id)
-{
- struct net_device *dev = dev_id;
- byte irq_status;
- int bogus_count = 0;
- int again = 0;
-
- spin_lock(&de620_lock);
-
- /* Read the status register (_not_ the status port) */
- irq_status = de620_get_register(dev, R_STS);
-
- pr_debug("de620_interrupt (%2.2X)\n", irq_status);
-
- if (irq_status & RXGOOD) {
- do {
- again = de620_rx_intr(dev);
- pr_debug("again=%d\n", again);
- }
- while (again && (++bogus_count < 100));
- }
-
- if(de620_tx_buffs(dev) != (TXBF0 | TXBF1))
- netif_wake_queue(dev);
-
- spin_unlock(&de620_lock);
- return IRQ_HANDLED;
-}
-
-/**************************************
- *
- * Get a packet from the adapter
- *
- * Send it "upstairs"
- *
- */
-static int de620_rx_intr(struct net_device *dev)
-{
- struct header_buf {
- byte status;
- byte Rx_NextPage;
- unsigned short Rx_ByteCount;
- } header_buf;
- struct sk_buff *skb;
- int size;
- byte *buffer;
- byte pagelink;
- byte curr_page;
-
- pr_debug("de620_rx_intr: next_rx_page = %d\n", next_rx_page);
-
- /* Tell the adapter that we are going to read data, and from where */
- de620_send_command(dev, W_CR | RRN);
- de620_set_register(dev, W_RSA1, next_rx_page);
- de620_set_register(dev, W_RSA0, 0);
-
- /* Deep breath, and away we goooooo */
- de620_read_block(dev, (byte *)&header_buf, sizeof(struct header_buf));
- pr_debug("page status=0x%02x, nextpage=%d, packetsize=%d\n",
- header_buf.status, header_buf.Rx_NextPage,
- header_buf.Rx_ByteCount);
-
- /* Plausible page header? */
- pagelink = header_buf.Rx_NextPage;
- if ((pagelink < first_rx_page) || (last_rx_page < pagelink)) {
- /* Ouch... Forget it! Skip all and start afresh... */
- printk(KERN_WARNING "%s: Ring overrun? Restoring...\n", dev->name);
- /* You win some, you lose some. And sometimes plenty... */
- adapter_init(dev);
- netif_wake_queue(dev);
- dev->stats.rx_over_errors++;
- return 0;
- }
-
- /* OK, this look good, so far. Let's see if it's consistent... */
- /* Let's compute the start of the next packet, based on where we are */
- pagelink = next_rx_page +
- ((header_buf.Rx_ByteCount + (4 - 1 + 0x100)) >> 8);
-
- /* Are we going to wrap around the page counter? */
- if (pagelink > last_rx_page)
- pagelink -= (last_rx_page - first_rx_page + 1);
-
- /* Is the _computed_ next page number equal to what the adapter says? */
- if (pagelink != header_buf.Rx_NextPage) {
- /* Naah, we'll skip this packet. Probably bogus data as well */
- printk(KERN_WARNING "%s: Page link out of sync! Restoring...\n", dev->name);
- next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
- de620_send_command(dev, W_DUMMY);
- de620_set_register(dev, W_NPRF, next_rx_page);
- dev->stats.rx_over_errors++;
- return 0;
- }
- next_rx_page = pagelink;
-
- size = header_buf.Rx_ByteCount - 4;
- if ((size < RUNT) || (GIANT < size)) {
- printk(KERN_WARNING "%s: Illegal packet size: %d!\n", dev->name, size);
- }
- else { /* Good packet? */
- skb = netdev_alloc_skb(dev, size + 2);
- if (skb == NULL) { /* Yeah, but no place to put it... */
- printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
- dev->stats.rx_dropped++;
- }
- else { /* Yep! Go get it! */
- skb_reserve(skb,2); /* Align */
- /* skb->data points to the start of sk_buff data area */
- buffer = skb_put(skb,size);
- /* copy the packet into the buffer */
- de620_read_block(dev, buffer, size);
- pr_debug("Read %d bytes\n", size);
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb); /* deliver it "upstairs" */
- /* count all receives */
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += size;
- }
- }
-
- /* Let's peek ahead to see if we have read the last current packet */
- /* NOTE! We're _not_ checking the 'EMPTY'-flag! This seems better... */
- curr_page = de620_get_register(dev, R_CPR);
- de620_set_register(dev, W_NPRF, next_rx_page);
- pr_debug("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page);
-
- return next_rx_page != curr_page; /* That was slightly tricky... */
-}
-
-/*********************************************
- *
- * Reset the adapter to a known state
- *
- */
-static int adapter_init(struct net_device *dev)
-{
- int i;
- static int was_down;
-
- if ((nic_data.Model == 3) || (nic_data.Model == 0)) { /* CT */
- EIPRegister = NCTL0;
- if (nic_data.Media != 1)
- EIPRegister |= NIS0; /* not BNC */
- }
- else if (nic_data.Model == 2) { /* UTP */
- EIPRegister = NCTL0 | NIS0;
- }
-
- if (utp)
- EIPRegister = NCTL0 | NIS0;
- if (bnc)
- EIPRegister = NCTL0;
-
- de620_send_command(dev, W_CR | RNOP | CLEAR);
- de620_send_command(dev, W_CR | RNOP);
-
- de620_set_register(dev, W_SCR, SCR_DEF);
- /* disable recv to wait init */
- de620_set_register(dev, W_TCR, RXOFF);
-
- /* Set the node ID in the adapter */
- for (i = 0; i < 6; ++i) { /* W_PARn = 0xaa + n */
- de620_set_register(dev, W_PAR0 + i, dev->dev_addr[i]);
- }
-
- de620_set_register(dev, W_EIP, EIPRegister);
-
- next_rx_page = first_rx_page = DE620_RX_START_PAGE;
- if (nic_data.RAM_Size)
- last_rx_page = nic_data.RAM_Size - 1;
- else /* 64k RAM */
- last_rx_page = 255;
-
- de620_set_register(dev, W_SPR, first_rx_page); /* Start Page Register*/
- de620_set_register(dev, W_EPR, last_rx_page); /* End Page Register */
- de620_set_register(dev, W_CPR, first_rx_page);/*Current Page Register*/
- de620_send_command(dev, W_NPR | first_rx_page); /* Next Page Register*/
- de620_send_command(dev, W_DUMMY);
- de620_set_delay(dev);
-
- /* Final sanity check: Anybody out there? */
- /* Let's hope some bits from the statusregister make a good check */
-#define CHECK_MASK ( 0 | TXSUC | T16 | 0 | RXCRC | RXSHORT | 0 | 0 )
-#define CHECK_OK ( 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 )
- /* success: X 0 0 X 0 0 X X */
- /* ignore: EEDI RXGOOD COLS LNKS*/
-
- if (((i = de620_get_register(dev, R_STS)) & CHECK_MASK) != CHECK_OK) {
- printk(KERN_ERR "%s: Something has happened to the DE-620! Please check it"
-#ifdef SHUTDOWN_WHEN_LOST
- " and do a new ifconfig"
-#endif
- "! (%02x)\n", dev->name, i);
-#ifdef SHUTDOWN_WHEN_LOST
- /* Goodbye, cruel world... */
- dev->flags &= ~IFF_UP;
- de620_close(dev);
-#endif
- was_down = 1;
- return 1; /* failed */
- }
- if (was_down) {
- printk(KERN_WARNING "%s: Thanks, I feel much better now!\n", dev->name);
- was_down = 0;
- }
-
- /* All OK, go ahead... */
- de620_set_register(dev, W_TCR, TCR_DEF);
-
- return 0; /* all ok */
-}
-
-static const struct net_device_ops de620_netdev_ops = {
- .ndo_open = de620_open,
- .ndo_stop = de620_close,
- .ndo_start_xmit = de620_start_xmit,
- .ndo_tx_timeout = de620_timeout,
- .ndo_set_rx_mode = de620_set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/******************************************************************************
- *
- * Only start-up code below
- *
- */
-/****************************************
- *
- * Check if there is a DE-620 connected
- */
-struct net_device * __init de620_probe(int unit)
-{
- byte checkbyte = 0xa5;
- struct net_device *dev;
- int err = -ENOMEM;
- int i;
-
- dev = alloc_etherdev(0);
- if (!dev)
- goto out;
-
- spin_lock_init(&de620_lock);
-
- /*
- * This is where the base_addr and irq gets set.
- * Tunable at compile-time and insmod-time
- */
- dev->base_addr = io;
- dev->irq = irq;
-
- /* allow overriding parameters on command line */
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
-
- pr_debug("%s", version);
-
- printk(KERN_INFO "D-Link DE-620 pocket adapter");
-
- if (!request_region(dev->base_addr, 3, "de620")) {
- printk(" io 0x%3lX, which is busy.\n", dev->base_addr);
- err = -EBUSY;
- goto out1;
- }
-
- /* Initially, configure basic nibble mode, so we can read the EEPROM */
- NIC_Cmd = DEF_NIC_CMD;
- de620_set_register(dev, W_EIP, EIPRegister);
-
- /* Anybody out there? */
- de620_set_register(dev, W_CPR, checkbyte);
- checkbyte = de620_get_register(dev, R_CPR);
-
- if ((checkbyte != 0xa5) || (read_eeprom(dev) != 0)) {
- printk(" not identified in the printer port\n");
- err = -ENODEV;
- goto out2;
- }
-
- /* else, got it! */
- dev->dev_addr[0] = nic_data.NodeID[0];
- for (i = 1; i < ETH_ALEN; i++) {
- dev->dev_addr[i] = nic_data.NodeID[i];
- dev->broadcast[i] = 0xff;
- }
-
- printk(", Ethernet Address: %pM", dev->dev_addr);
-
- printk(" (%dk RAM,",
- (nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64);
-
- if (nic_data.Media == 1)
- printk(" BNC)\n");
- else
- printk(" UTP)\n");
-
- dev->netdev_ops = &de620_netdev_ops;
- dev->watchdog_timeo = HZ*2;
-
- /* base_addr and irq are already set, see above! */
-
- /* dump eeprom */
- pr_debug("\nEEPROM contents:\n"
- "RAM_Size = 0x%02X\n"
- "NodeID = %pM\n"
- "Model = %d\n"
- "Media = %d\n"
- "SCR = 0x%02x\n", nic_data.RAM_Size, nic_data.NodeID,
- nic_data.Model, nic_data.Media, nic_data.SCR);
-
- err = register_netdev(dev);
- if (err)
- goto out2;
- return dev;
-
-out2:
- release_region(dev->base_addr, 3);
-out1:
- free_netdev(dev);
-out:
- return ERR_PTR(err);
-}
-
-/**********************************
- *
- * Read info from on-board EEPROM
- *
- * Note: Bitwise serial I/O to/from the EEPROM vi the status _register_!
- */
-#define sendit(dev,data) de620_set_register(dev, W_EIP, data | EIPRegister);
-
-static unsigned short __init ReadAWord(struct net_device *dev, int from)
-{
- unsigned short data;
- int nbits;
-
- /* cs [__~~] SET SEND STATE */
- /* di [____] */
- /* sck [_~~_] */
- sendit(dev, 0); sendit(dev, 1); sendit(dev, 5); sendit(dev, 4);
-
- /* Send the 9-bit address from where we want to read the 16-bit word */
- for (nbits = 9; nbits > 0; --nbits, from <<= 1) {
- if (from & 0x0100) { /* bit set? */
- /* cs [~~~~] SEND 1 */
- /* di [~~~~] */
- /* sck [_~~_] */
- sendit(dev, 6); sendit(dev, 7); sendit(dev, 7); sendit(dev, 6);
- }
- else {
- /* cs [~~~~] SEND 0 */
- /* di [____] */
- /* sck [_~~_] */
- sendit(dev, 4); sendit(dev, 5); sendit(dev, 5); sendit(dev, 4);
- }
- }
-
- /* Shift in the 16-bit word. The bits appear serially in EEDI (=0x80) */
- for (data = 0, nbits = 16; nbits > 0; --nbits) {
- /* cs [~~~~] SEND 0 */
- /* di [____] */
- /* sck [_~~_] */
- sendit(dev, 4); sendit(dev, 5); sendit(dev, 5); sendit(dev, 4);
- data = (data << 1) | ((de620_get_register(dev, R_STS) & EEDI) >> 7);
- }
- /* cs [____] RESET SEND STATE */
- /* di [____] */
- /* sck [_~~_] */
- sendit(dev, 0); sendit(dev, 1); sendit(dev, 1); sendit(dev, 0);
-
- return data;
-}
-
-static int __init read_eeprom(struct net_device *dev)
-{
- unsigned short wrd;
-
- /* D-Link Ethernet addresses are in the series 00:80:c8:7X:XX:XX:XX */
- wrd = ReadAWord(dev, 0x1aa); /* bytes 0 + 1 of NodeID */
- if (!clone && (wrd != htons(0x0080))) /* Valid D-Link ether sequence? */
- return -1; /* Nope, not a DE-620 */
- nic_data.NodeID[0] = wrd & 0xff;
- nic_data.NodeID[1] = wrd >> 8;
-
- wrd = ReadAWord(dev, 0x1ab); /* bytes 2 + 3 of NodeID */
- if (!clone && ((wrd & 0xff) != 0xc8)) /* Valid D-Link ether sequence? */
- return -1; /* Nope, not a DE-620 */
- nic_data.NodeID[2] = wrd & 0xff;
- nic_data.NodeID[3] = wrd >> 8;
-
- wrd = ReadAWord(dev, 0x1ac); /* bytes 4 + 5 of NodeID */
- nic_data.NodeID[4] = wrd & 0xff;
- nic_data.NodeID[5] = wrd >> 8;
-
- wrd = ReadAWord(dev, 0x1ad); /* RAM size in pages (256 bytes). 0 = 64k */
- nic_data.RAM_Size = (wrd >> 8);
-
- wrd = ReadAWord(dev, 0x1ae); /* hardware model (CT = 3) */
- nic_data.Model = (wrd & 0xff);
-
- wrd = ReadAWord(dev, 0x1af); /* media (indicates BNC/UTP) */
- nic_data.Media = (wrd & 0xff);
-
- wrd = ReadAWord(dev, 0x1a8); /* System Configuration Register */
- nic_data.SCR = (wrd >> 8);
-
- return 0; /* no errors */
-}
-
-/******************************************************************************
- *
- * Loadable module skeleton
- *
- */
-#ifdef MODULE
-static struct net_device *de620_dev;
-
-int __init init_module(void)
-{
- de620_dev = de620_probe(-1);
- if (IS_ERR(de620_dev))
- return PTR_ERR(de620_dev);
- return 0;
-}
-
-void cleanup_module(void)
-{
- unregister_netdev(de620_dev);
- release_region(de620_dev->base_addr, 3);
- free_netdev(de620_dev);
-}
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/dlink/de620.h b/drivers/net/ethernet/dlink/de620.h
deleted file mode 100644
index e8d9a88f4cb5..000000000000
--- a/drivers/net/ethernet/dlink/de620.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*********************************************************
- * *
- * Definition of D-Link DE-620 Ethernet Pocket adapter *
- * *
- *********************************************************/
-
-/* DE-620's CMD port Command */
-#define CS0 0x08 /* 1->0 command strobe */
-#define ICEN 0x04 /* 0=enable DL3520 host interface */
-#define DS0 0x02 /* 1->0 data strobe 0 */
-#define DS1 0x01 /* 1->0 data strobe 1 */
-
-#define WDIR 0x20 /* general 0=read 1=write */
-#define RDIR 0x00 /* (not 100% confirm ) */
-#define PS2WDIR 0x00 /* ps/2 mode 1=read, 0=write */
-#define PS2RDIR 0x20
-
-#define IRQEN 0x10 /* 1 = enable printer IRQ line */
-#define SELECTIN 0x08 /* 1 = select printer */
-#define INITP 0x04 /* 0 = initial printer */
-#define AUTOFEED 0x02 /* 1 = printer auto form feed */
-#define STROBE 0x01 /* 0->1 data strobe */
-
-#define RESET 0x08
-#define NIS0 0x20 /* 0 = BNC, 1 = UTP */
-#define NCTL0 0x10
-
-/* DE-620 DIC Command */
-#define W_DUMMY 0x00 /* DIC reserved command */
-#define W_CR 0x20 /* DIC write command register */
-#define W_NPR 0x40 /* DIC write Next Page Register */
-#define W_TBR 0x60 /* DIC write Tx Byte Count 1 reg */
-#define W_RSA 0x80 /* DIC write Remote Start Addr 1 */
-
-/* DE-620's STAT port bits 7-4 */
-#define EMPTY 0x80 /* 1 = receive buffer empty */
-#define INTLEVEL 0x40 /* 1 = interrupt level is high */
-#define TXBF1 0x20 /* 1 = transmit buffer 1 is in use */
-#define TXBF0 0x10 /* 1 = transmit buffer 0 is in use */
-#define READY 0x08 /* 1 = h/w ready to accept cmd/data */
-
-/* IDC 1 Command */
-#define W_RSA1 0xa0 /* write remote start address 1 */
-#define W_RSA0 0xa1 /* write remote start address 0 */
-#define W_NPRF 0xa2 /* write next page register NPR15-NPR8 */
-#define W_DFR 0xa3 /* write delay factor register */
-#define W_CPR 0xa4 /* write current page register */
-#define W_SPR 0xa5 /* write start page register */
-#define W_EPR 0xa6 /* write end page register */
-#define W_SCR 0xa7 /* write system configuration register */
-#define W_TCR 0xa8 /* write Transceiver Configuration reg */
-#define W_EIP 0xa9 /* write EEPM Interface port */
-#define W_PAR0 0xaa /* write physical address register 0 */
-#define W_PAR1 0xab /* write physical address register 1 */
-#define W_PAR2 0xac /* write physical address register 2 */
-#define W_PAR3 0xad /* write physical address register 3 */
-#define W_PAR4 0xae /* write physical address register 4 */
-#define W_PAR5 0xaf /* write physical address register 5 */
-
-/* IDC 2 Command */
-#define R_STS 0xc0 /* read status register */
-#define R_CPR 0xc1 /* read current page register */
-#define R_BPR 0xc2 /* read boundary page register */
-#define R_TDR 0xc3 /* read time domain reflectometry reg */
-
-/* STATUS Register */
-#define EEDI 0x80 /* EEPM DO pin */
-#define TXSUC 0x40 /* tx success */
-#define T16 0x20 /* tx fail 16 times */
-#define TS1 0x40 /* 0=Tx success, 1=T16 */
-#define TS0 0x20 /* 0=Tx success, 1=T16 */
-#define RXGOOD 0x10 /* rx a good packet */
-#define RXCRC 0x08 /* rx a CRC error packet */
-#define RXSHORT 0x04 /* rx a short packet */
-#define COLS 0x02 /* coaxial collision status */
-#define LNKS 0x01 /* UTP link status */
-
-/* Command Register */
-#define CLEAR 0x10 /* reset part of hardware */
-#define NOPER 0x08 /* No Operation */
-#define RNOP 0x08
-#define RRA 0x06 /* After RR then auto-advance NPR & BPR(=NPR-1) */
-#define RRN 0x04 /* Normal Remote Read mode */
-#define RW1 0x02 /* Remote Write tx buffer 1 ( page 6 - 11 ) */
-#define RW0 0x00 /* Remote Write tx buffer 0 ( page 0 - 5 ) */
-#define TXEN 0x01 /* 0->1 tx enable */
-
-/* System Configuration Register */
-#define TESTON 0x80 /* test host data transfer reliability */
-#define SLEEP 0x40 /* sleep mode */
-#if 0
-#define FASTMODE 0x04 /* fast mode for intel 82360SL fast mode */
-#define BYTEMODE 0x02 /* byte mode */
-#else
-#define FASTMODE 0x20 /* fast mode for intel 82360SL fast mode */
-#define BYTEMODE 0x10 /* byte mode */
-#endif
-#define NIBBLEMODE 0x00 /* nibble mode */
-#define IRQINV 0x08 /* turn off IRQ line inverter */
-#define IRQNML 0x00 /* turn on IRQ line inverter */
-#define INTON 0x04
-#define AUTOFFSET 0x02 /* auto shift address to TPR+12 */
-#define AUTOTX 0x01 /* auto tx when leave RW mode */
-
-/* Transceiver Configuration Register */
-#define JABBER 0x80 /* generate jabber condition */
-#define TXSUCINT 0x40 /* enable tx success interrupt */
-#define T16INT 0x20 /* enable T16 interrupt */
-#define RXERRPKT 0x10 /* accept CRC error or short packet */
-#define EXTERNALB2 0x0C /* external loopback 2 */
-#define EXTERNALB1 0x08 /* external loopback 1 */
-#define INTERNALB 0x04 /* internal loopback */
-#define NMLOPERATE 0x00 /* normal operation */
-#define RXPBM 0x03 /* rx physical, broadcast, multicast */
-#define RXPB 0x02 /* rx physical, broadcast */
-#define RXALL 0x01 /* rx all packet */
-#define RXOFF 0x00 /* rx disable */
diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c
index 1d342d37915c..110d26f4c602 100644
--- a/drivers/net/ethernet/dlink/dl2k.c
+++ b/drivers/net/ethernet/dlink/dl2k.c
@@ -1156,9 +1156,10 @@ set_multicast (struct net_device *dev)
static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct netdev_private *np = netdev_priv(dev);
- strcpy(info->driver, "dl2k");
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, pci_name(np->pdev));
+
+ strlcpy(info->driver, "dl2k", sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(np->pdev), sizeof(info->bus_info));
}
static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c
index 28fc11b2f1ea..50d9c6315930 100644
--- a/drivers/net/ethernet/dlink/sundance.c
+++ b/drivers/net/ethernet/dlink/sundance.c
@@ -530,7 +530,6 @@ static int sundance_probe1(struct pci_dev *pdev,
for (i = 0; i < 3; i++)
((__le16 *)dev->dev_addr)[i] =
cpu_to_le16(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
np = netdev_priv(dev);
np->base = ioaddr;
diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c
index 2c177b329c8b..f3d60eb13c3a 100644
--- a/drivers/net/ethernet/dnet.c
+++ b/drivers/net/ethernet/dnet.c
@@ -281,11 +281,11 @@ static int dnet_mii_probe(struct net_device *dev)
/* attach the mac to the phy */
if (bp->capabilities & DNET_HAS_RMII) {
phydev = phy_connect(dev, dev_name(&phydev->dev),
- &dnet_handle_link_change, 0,
+ &dnet_handle_link_change,
PHY_INTERFACE_MODE_RMII);
} else {
phydev = phy_connect(dev, dev_name(&phydev->dev),
- &dnet_handle_link_change, 0,
+ &dnet_handle_link_change,
PHY_INTERFACE_MODE_MII);
}
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 4eba17b83ba8..28ceb8414185 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -34,15 +34,15 @@
#include "be_hw.h"
#include "be_roce.h"
-#define DRV_VER "4.4.161.0u"
+#define DRV_VER "4.6.62.0u"
#define DRV_NAME "be2net"
-#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
-#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC"
-#define OC_NAME "Emulex OneConnect 10Gbps NIC"
+#define BE_NAME "Emulex BladeEngine2"
+#define BE3_NAME "Emulex BladeEngine3"
+#define OC_NAME "Emulex OneConnect"
#define OC_NAME_BE OC_NAME "(be3)"
#define OC_NAME_LANCER OC_NAME "(Lancer)"
#define OC_NAME_SH OC_NAME "(Skyhawk)"
-#define DRV_DESC "ServerEngines BladeEngine 10Gbps NIC Driver"
+#define DRV_DESC "Emulex OneConnect 10Gbps NIC Driver"
#define BE_VENDOR_ID 0x19a2
#define EMULEX_VENDOR_ID 0x10df
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 8a250c38fb82..071aea79d218 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -93,13 +93,16 @@ static void be_mcc_notify(struct be_adapter *adapter)
* little endian) */
static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
{
+ u32 flags;
+
if (compl->flags != 0) {
- compl->flags = le32_to_cpu(compl->flags);
- BUG_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0);
- return true;
- } else {
- return false;
+ flags = le32_to_cpu(compl->flags);
+ if (flags & CQE_FLAGS_VALID_MASK) {
+ compl->flags = flags;
+ return true;
+ }
}
+ return false;
}
/* Need to reset the entire word that houses the valid bit */
@@ -3138,6 +3141,39 @@ err:
return status;
}
+int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
+ int vf_num)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_iface_list *req;
+ struct be_cmd_resp_get_iface_list *resp;
+ 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_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_IFACE_LIST, sizeof(*resp),
+ wrb, NULL);
+ req->hdr.domain = vf_num + 1;
+
+ status = be_mcc_notify_wait(adapter);
+ if (!status) {
+ resp = (struct be_cmd_resp_get_iface_list *)req;
+ vf_cfg->if_handle = le32_to_cpu(resp->if_desc.if_id);
+ }
+
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
/* Uses sync mcc */
int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain)
{
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index d6552e19ffee..96970860c915 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -203,6 +203,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_GET_FN_PRIVILEGES 170
#define OPCODE_COMMON_READ_OBJECT 171
#define OPCODE_COMMON_WRITE_OBJECT 172
+#define OPCODE_COMMON_GET_IFACE_LIST 194
#define OPCODE_COMMON_ENABLE_DISABLE_VF 196
#define OPCODE_ETH_RSS_CONFIG 1
@@ -1795,6 +1796,23 @@ static inline bool check_privilege(struct be_adapter *adapter, u32 flags)
return flags & adapter->cmd_privileges ? true : false;
}
+/************** Get IFACE LIST *******************/
+struct be_if_desc {
+ u32 if_id;
+ u32 cap_flags;
+ u32 en_flags;
+};
+
+struct be_cmd_req_get_iface_list {
+ struct be_cmd_req_hdr hdr;
+};
+
+struct be_cmd_resp_get_iface_list {
+ struct be_cmd_req_hdr hdr;
+ u32 if_cnt;
+ struct be_if_desc if_desc;
+};
+
extern int be_pci_fnum_get(struct be_adapter *adapter);
extern int be_fw_wait_ready(struct be_adapter *adapter);
extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -1917,4 +1935,6 @@ extern int be_cmd_get_profile_config(struct be_adapter *adapter, u32 *cap_flags,
extern int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps,
u8 domain);
+extern int be_cmd_get_if_id(struct be_adapter *adapter,
+ struct be_vf_cfg *vf_cfg, int vf_num);
extern int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain);
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 00454a10f88d..76b302f30c87 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -183,12 +183,12 @@ static void be_get_drvinfo(struct net_device *netdev,
strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
strlcpy(drvinfo->version, DRV_VER, sizeof(drvinfo->version));
- strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
- if (memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN) != 0) {
- strcat(drvinfo->fw_version, " [");
- strcat(drvinfo->fw_version, fw_on_flash);
- strcat(drvinfo->fw_version, "]");
- }
+ if (!memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN))
+ strlcpy(drvinfo->fw_version, adapter->fw_ver,
+ sizeof(drvinfo->fw_version));
+ else
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+ "%s [%s]", adapter->fw_ver, fw_on_flash);
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
sizeof(drvinfo->bus_info));
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 5c995700e534..3860888ac711 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -25,7 +25,7 @@
MODULE_VERSION(DRV_VER);
MODULE_DEVICE_TABLE(pci, be_dev_ids);
MODULE_DESCRIPTION(DRV_DESC " " DRV_VER);
-MODULE_AUTHOR("ServerEngines Corporation");
+MODULE_AUTHOR("Emulex Corporation");
MODULE_LICENSE("GPL");
static unsigned int num_vfs;
@@ -2597,7 +2597,7 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
* These addresses are programmed in the ASIC by the PF and the VF driver
* queries for the MAC address during its probe.
*/
-static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
+static int be_vf_eth_addr_config(struct be_adapter *adapter)
{
u32 vf;
int status = 0;
@@ -2626,13 +2626,34 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
return status;
}
+static int be_vfs_mac_query(struct be_adapter *adapter)
+{
+ int status, vf;
+ u8 mac[ETH_ALEN];
+ struct be_vf_cfg *vf_cfg;
+ bool active;
+
+ for_all_vfs(adapter, vf_cfg, vf) {
+ be_cmd_get_mac_from_list(adapter, mac, &active,
+ &vf_cfg->pmac_id, 0);
+
+ status = be_cmd_mac_addr_query(adapter, mac, false,
+ vf_cfg->if_handle, 0);
+ if (status)
+ return status;
+ memcpy(vf_cfg->mac_addr, mac, ETH_ALEN);
+ }
+ return 0;
+}
+
static void be_vf_clear(struct be_adapter *adapter)
{
struct be_vf_cfg *vf_cfg;
u32 vf;
if (be_find_vfs(adapter, ASSIGNED)) {
- dev_warn(&adapter->pdev->dev, "VFs are assigned to VMs\n");
+ dev_warn(&adapter->pdev->dev,
+ "VFs are assigned to VMs: not disabling VFs\n");
goto done;
}
@@ -2681,21 +2702,29 @@ static int be_clear(struct be_adapter *adapter)
return 0;
}
-static void be_get_vf_if_cap_flags(struct be_adapter *adapter,
- u32 *cap_flags, u8 domain)
+static int be_vfs_if_create(struct be_adapter *adapter)
{
- bool profile_present = false;
+ struct be_vf_cfg *vf_cfg;
+ u32 cap_flags, en_flags, vf;
int status;
- if (lancer_chip(adapter)) {
- status = be_cmd_get_profile_config(adapter, cap_flags, domain);
- if (!status)
- profile_present = true;
- }
+ cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
+ BE_IF_FLAGS_MULTICAST;
- if (!profile_present)
- *cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
- BE_IF_FLAGS_MULTICAST;
+ for_all_vfs(adapter, vf_cfg, vf) {
+ if (!BE3_chip(adapter))
+ be_cmd_get_profile_config(adapter, &cap_flags, vf + 1);
+
+ /* If a FW profile exists, then cap_flags are updated */
+ en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
+ BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_MULTICAST);
+ status = be_cmd_if_create(adapter, cap_flags, en_flags,
+ &vf_cfg->if_handle, vf + 1);
+ if (status)
+ goto err;
+ }
+err:
+ return status;
}
static int be_vf_setup_init(struct be_adapter *adapter)
@@ -2718,65 +2747,70 @@ static int be_vf_setup_init(struct be_adapter *adapter)
static int be_vf_setup(struct be_adapter *adapter)
{
struct be_vf_cfg *vf_cfg;
- struct device *dev = &adapter->pdev->dev;
- u32 cap_flags, en_flags, vf;
u16 def_vlan, lnk_speed;
- int status, enabled_vfs;
-
- enabled_vfs = be_find_vfs(adapter, ENABLED);
- if (enabled_vfs) {
- dev_warn(dev, "%d VFs are already enabled\n", enabled_vfs);
- dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs);
- return 0;
- }
-
- if (num_vfs > adapter->dev_num_vfs) {
- dev_warn(dev, "Device supports %d VFs and not %d\n",
- adapter->dev_num_vfs, num_vfs);
- num_vfs = adapter->dev_num_vfs;
- }
+ int status, old_vfs, vf;
+ struct device *dev = &adapter->pdev->dev;
- status = pci_enable_sriov(adapter->pdev, num_vfs);
- if (!status) {
- adapter->num_vfs = num_vfs;
+ old_vfs = be_find_vfs(adapter, ENABLED);
+ if (old_vfs) {
+ dev_info(dev, "%d VFs are already enabled\n", old_vfs);
+ if (old_vfs != num_vfs)
+ dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs);
+ adapter->num_vfs = old_vfs;
} else {
- /* Platform doesn't support SRIOV though device supports it */
- dev_warn(dev, "SRIOV enable failed\n");
- return 0;
+ if (num_vfs > adapter->dev_num_vfs)
+ dev_info(dev, "Device supports %d VFs and not %d\n",
+ adapter->dev_num_vfs, num_vfs);
+ adapter->num_vfs = min_t(u16, num_vfs, adapter->dev_num_vfs);
+
+ status = pci_enable_sriov(adapter->pdev, num_vfs);
+ if (status) {
+ dev_err(dev, "SRIOV enable failed\n");
+ adapter->num_vfs = 0;
+ return 0;
+ }
}
status = be_vf_setup_init(adapter);
if (status)
goto err;
- for_all_vfs(adapter, vf_cfg, vf) {
- be_get_vf_if_cap_flags(adapter, &cap_flags, vf + 1);
-
- en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
- BE_IF_FLAGS_BROADCAST |
- BE_IF_FLAGS_MULTICAST);
-
- status = be_cmd_if_create(adapter, cap_flags, en_flags,
- &vf_cfg->if_handle, vf + 1);
+ if (old_vfs) {
+ for_all_vfs(adapter, vf_cfg, vf) {
+ status = be_cmd_get_if_id(adapter, vf_cfg, vf);
+ if (status)
+ goto err;
+ }
+ } else {
+ status = be_vfs_if_create(adapter);
if (status)
goto err;
}
- if (!enabled_vfs) {
+ if (old_vfs) {
+ status = be_vfs_mac_query(adapter);
+ if (status)
+ goto err;
+ } else {
status = be_vf_eth_addr_config(adapter);
if (status)
goto err;
}
for_all_vfs(adapter, vf_cfg, vf) {
- lnk_speed = 1000;
- status = be_cmd_set_qos(adapter, lnk_speed, vf + 1);
- if (status)
- goto err;
- vf_cfg->tx_rate = lnk_speed * 10;
+ /* BE3 FW, by default, caps VF TX-rate to 100mbps.
+ * Allow full available bandwidth
+ */
+ if (BE3_chip(adapter) && !old_vfs)
+ be_cmd_set_qos(adapter, 1000, vf+1);
+
+ status = be_cmd_link_status_query(adapter, &lnk_speed,
+ NULL, vf + 1);
+ if (!status)
+ vf_cfg->tx_rate = lnk_speed;
status = be_cmd_get_hsw_config(adapter, &def_vlan,
- vf + 1, vf_cfg->if_handle);
+ vf + 1, vf_cfg->if_handle);
if (status)
goto err;
vf_cfg->def_vid = def_vlan;
@@ -2785,6 +2819,8 @@ static int be_vf_setup(struct be_adapter *adapter)
}
return 0;
err:
+ dev_err(dev, "VF setup failed\n");
+ be_vf_clear(adapter);
return status;
}
@@ -2838,12 +2874,12 @@ static int be_get_mac_addr(struct be_adapter *adapter, u8 *mac, u32 if_handle,
static void be_get_resources(struct be_adapter *adapter)
{
- int status;
+ u16 dev_num_vfs;
+ int pos, status;
bool profile_present = false;
- if (lancer_chip(adapter)) {
+ if (!BEx_chip(adapter)) {
status = be_cmd_get_func_config(adapter);
-
if (!status)
profile_present = true;
}
@@ -2899,13 +2935,21 @@ static void be_get_resources(struct be_adapter *adapter)
if (adapter->function_caps & BE_FUNCTION_CAPS_RSS)
adapter->if_cap_flags |= BE_IF_FLAGS_RSS;
}
+
+ pos = pci_find_ext_capability(adapter->pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (pos) {
+ pci_read_config_word(adapter->pdev, pos + PCI_SRIOV_TOTAL_VF,
+ &dev_num_vfs);
+ if (BE3_chip(adapter))
+ dev_num_vfs = min_t(u16, dev_num_vfs, MAX_VFS);
+ adapter->dev_num_vfs = dev_num_vfs;
+ }
}
/* Routine to query per function resource limits */
static int be_get_config(struct be_adapter *adapter)
{
- int pos, status;
- u16 dev_num_vfs;
+ int status;
status = be_cmd_query_fw_cfg(adapter, &adapter->port_num,
&adapter->function_mode,
@@ -2923,14 +2967,6 @@ static int be_get_config(struct be_adapter *adapter)
goto err;
}
- pos = pci_find_ext_capability(adapter->pdev, PCI_EXT_CAP_ID_SRIOV);
- if (pos) {
- pci_read_config_word(adapter->pdev, pos + PCI_SRIOV_TOTAL_VF,
- &dev_num_vfs);
- if (!lancer_chip(adapter))
- dev_num_vfs = min_t(u16, dev_num_vfs, MAX_VFS);
- adapter->dev_num_vfs = dev_num_vfs;
- }
err:
return status;
}
diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c
index 8db1c06008de..5722bc61fa58 100644
--- a/drivers/net/ethernet/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -206,7 +206,7 @@ struct ethoc {
unsigned int num_rx;
unsigned int cur_rx;
- void** vma;
+ void **vma;
struct net_device *netdev;
struct napi_struct napi;
@@ -292,7 +292,7 @@ static int ethoc_init_ring(struct ethoc *dev, unsigned long mem_start)
{
struct ethoc_bd bd;
int i;
- void* vma;
+ void *vma;
dev->cur_tx = 0;
dev->dty_tx = 0;
@@ -447,8 +447,8 @@ static int ethoc_rx(struct net_device *dev, int limit)
netif_receive_skb(skb);
} else {
if (net_ratelimit())
- dev_warn(&dev->dev, "low on memory - "
- "packet dropped\n");
+ dev_warn(&dev->dev,
+ "low on memory - packet dropped\n");
dev->stats.rx_dropped++;
break;
@@ -555,9 +555,8 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
pending = ethoc_read(priv, INT_SOURCE);
pending &= mask;
- if (unlikely(pending == 0)) {
+ if (unlikely(pending == 0))
return IRQ_NONE;
- }
ethoc_ack_irq(priv, pending);
@@ -620,7 +619,7 @@ static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)
ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ);
- for (i=0; i < 5; i++) {
+ for (i = 0; i < 5; i++) {
u32 status = ethoc_read(priv, MIISTATUS);
if (!(status & MIISTATUS_BUSY)) {
u32 data = ethoc_read(priv, MIIRX_DATA);
@@ -628,7 +627,7 @@ static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)
ethoc_write(priv, MIICOMMAND, 0);
return data;
}
- usleep_range(100,200);
+ usleep_range(100, 200);
}
return -EBUSY;
@@ -643,14 +642,14 @@ static int ethoc_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
ethoc_write(priv, MIITX_DATA, val);
ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE);
- for (i=0; i < 5; i++) {
+ for (i = 0; i < 5; i++) {
u32 stat = ethoc_read(priv, MIISTATUS);
if (!(stat & MIISTATUS_BUSY)) {
/* reset MII command register */
ethoc_write(priv, MIICOMMAND, 0);
return 0;
}
- usleep_range(100,200);
+ usleep_range(100, 200);
}
return -EBUSY;
@@ -671,19 +670,18 @@ static int ethoc_mdio_probe(struct net_device *dev)
struct phy_device *phy;
int err;
- if (priv->phy_id != -1) {
+ if (priv->phy_id != -1)
phy = priv->mdio->phy_map[priv->phy_id];
- } else {
+ else
phy = phy_find_first(priv->mdio);
- }
if (!phy) {
dev_err(&dev->dev, "no PHY found\n");
return -ENXIO;
}
- err = phy_connect_direct(dev, phy, ethoc_mdio_poll, 0,
- PHY_INTERFACE_MODE_GMII);
+ err = phy_connect_direct(dev, phy, ethoc_mdio_poll,
+ PHY_INTERFACE_MODE_GMII);
if (err) {
dev_err(&dev->dev, "could not attach to PHY\n");
return err;
@@ -771,21 +769,24 @@ static int ethoc_config(struct net_device *dev, struct ifmap *map)
return -ENOSYS;
}
-static int ethoc_set_mac_address(struct net_device *dev, void *addr)
+static void ethoc_do_set_mac_address(struct net_device *dev)
{
struct ethoc *priv = netdev_priv(dev);
- u8 *mac = (u8 *)addr;
-
- if (!is_valid_ether_addr(mac))
- return -EADDRNOTAVAIL;
+ unsigned char *mac = dev->dev_addr;
ethoc_write(priv, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) |
(mac[4] << 8) | (mac[5] << 0));
ethoc_write(priv, MAC_ADDR1, (mac[0] << 8) | (mac[1] << 0));
+}
- memcpy(dev->dev_addr, mac, ETH_ALEN);
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
+static int ethoc_set_mac_address(struct net_device *dev, void *p)
+{
+ const struct sockaddr *addr = p;
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+ ethoc_do_set_mac_address(dev);
return 0;
}
@@ -1022,7 +1023,7 @@ static int ethoc_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "ethoc: num_tx: %d num_rx: %d\n",
priv->num_tx, priv->num_rx);
- priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void*), GFP_KERNEL);
+ priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void *), GFP_KERNEL);
if (!priv->vma) {
ret = -ENOMEM;
goto error;
@@ -1038,7 +1039,7 @@ static int ethoc_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
{
- const uint8_t* mac;
+ const uint8_t *mac;
mac = of_get_property(pdev->dev.of_node,
"local-mac-address",
@@ -1050,25 +1051,23 @@ static int ethoc_probe(struct platform_device *pdev)
}
/* Check that the given MAC address is valid. If it isn't, read the
- * current MAC from the controller. */
+ * current MAC from the controller.
+ */
if (!is_valid_ether_addr(netdev->dev_addr))
ethoc_get_mac_address(netdev, netdev->dev_addr);
/* Check the MAC again for validity, if it still isn't choose and
- * program a random one. */
+ * program a random one.
+ */
if (!is_valid_ether_addr(netdev->dev_addr)) {
eth_random_addr(netdev->dev_addr);
random_mac = true;
}
- ret = ethoc_set_mac_address(netdev, netdev->dev_addr);
- if (ret) {
- dev_err(&netdev->dev, "failed to set MAC address\n");
- goto error;
- }
+ ethoc_do_set_mac_address(netdev);
if (random_mac)
- netdev->addr_assign_type |= NET_ADDR_RANDOM;
+ netdev->addr_assign_type = NET_ADDR_RANDOM;
/* register MII bus */
priv->mdio = mdiobus_alloc();
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 74d749e29aab..7c361d1db94c 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -858,8 +858,7 @@ static int ftgmac100_mii_probe(struct ftgmac100 *priv)
}
phydev = phy_connect(netdev, dev_name(&phydev->dev),
- &ftgmac100_adjust_link, 0,
- PHY_INTERFACE_MODE_GMII);
+ &ftgmac100_adjust_link, PHY_INTERFACE_MODE_GMII);
if (IS_ERR(phydev)) {
netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
@@ -955,9 +954,9 @@ static int ftgmac100_mdiobus_reset(struct mii_bus *bus)
static void ftgmac100_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, dev_name(&netdev->dev));
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
}
static int ftgmac100_get_settings(struct net_device *netdev,
diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c
index b901a01e3fa5..b5ea8fbd8a76 100644
--- a/drivers/net/ethernet/faraday/ftmac100.c
+++ b/drivers/net/ethernet/faraday/ftmac100.c
@@ -820,9 +820,9 @@ static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg,
static void ftmac100_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, dev_name(&netdev->dev));
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
}
static int ftmac100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index ec490d741fc0..6048dc8604ee 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -26,6 +26,7 @@ config FEC
ARCH_MXC || SOC_IMX28)
default ARCH_MXC || SOC_IMX28 if ARM
select PHYLIB
+ select PTP_1588_CLOCK
---help---
Say Y here if you want to use the built-in 10/100 Fast ethernet
controller on some Motorola ColdFire and Freescale i.MX processors.
@@ -92,12 +93,4 @@ config GIANFAR
This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
and MPC86xx family of chips, and the FEC on the 8540.
-config FEC_PTP
- bool "PTP Hardware Clock (PHC)"
- depends on FEC && ARCH_MXC && !SOC_IMX25 && !SOC_IMX27 && !SOC_IMX35 && !SOC_IMX5
- select PTP_1588_CLOCK
- --help---
- Say Y here if you want to use PTP Hardware Clock (PHC) in the
- driver. Only the basic clock operations have been implemented.
-
endif # NET_VENDOR_FREESCALE
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index d4d19b3d00ae..b7d58fe6f531 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -2,8 +2,7 @@
# Makefile for the Freescale network device drivers.
#
-obj-$(CONFIG_FEC) += fec.o
-obj-$(CONFIG_FEC_PTP) += fec_ptp.o
+obj-$(CONFIG_FEC) += fec.o fec_ptp.o
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 0704bcab178a..29d82cf1528e 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -67,6 +67,15 @@
#endif
#define DRIVER_NAME "fec"
+#define FEC_NAPI_WEIGHT 64
+
+/* Pause frame feild and FIFO threshold */
+#define FEC_ENET_FCE (1 << 5)
+#define FEC_ENET_RSEM_V 0x84
+#define FEC_ENET_RSFL_V 16
+#define FEC_ENET_RAEM_V 0x8
+#define FEC_ENET_RAFL_V 0x8
+#define FEC_ENET_OPD_V 0xFFF0
/* Controller is ENET-MAC */
#define FEC_QUIRK_ENET_MAC (1 << 0)
@@ -76,6 +85,8 @@
#define FEC_QUIRK_USE_GASKET (1 << 2)
/* Controller has GBIT support */
#define FEC_QUIRK_HAS_GBIT (1 << 3)
+/* Controller has extend desc buffer */
+#define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4)
static struct platform_device_id fec_devtype[] = {
{
@@ -93,7 +104,8 @@ static struct platform_device_id fec_devtype[] = {
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
}, {
.name = "imx6q-fec",
- .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT,
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+ FEC_QUIRK_HAS_BUFDESC_EX,
}, {
/* sentinel */
}
@@ -140,7 +152,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#endif
#endif /* CONFIG_M5272 */
-#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
+#if (((RX_RING_SIZE + TX_RING_SIZE) * 32) > PAGE_SIZE)
#error "FEC: descriptor ring size constants too large"
#endif
@@ -157,6 +169,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
+#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
/* The FEC stores dest/src/type, data, and checksum for receive packets.
*/
@@ -190,8 +203,29 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
/* Transmitter timeout */
#define TX_TIMEOUT (2 * HZ)
+#define FEC_PAUSE_FLAG_AUTONEG 0x1
+#define FEC_PAUSE_FLAG_ENABLE 0x2
+
static int mii_cnt;
+static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, int is_ex)
+{
+ struct bufdesc_ex *ex = (struct bufdesc_ex *)bdp;
+ if (is_ex)
+ return (struct bufdesc *)(ex + 1);
+ else
+ return bdp + 1;
+}
+
+static struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, int is_ex)
+{
+ struct bufdesc_ex *ex = (struct bufdesc_ex *)bdp;
+ if (is_ex)
+ return (struct bufdesc *)(ex - 1);
+ else
+ return bdp - 1;
+}
+
static void *swap_buffer(void *bufaddr, int len)
{
int i;
@@ -248,7 +282,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
unsigned int index;
- index = bdp - fep->tx_bd_base;
+ if (fep->bufdesc_ex)
+ index = (struct bufdesc_ex *)bdp -
+ (struct bufdesc_ex *)fep->tx_bd_base;
+ else
+ index = bdp - fep->tx_bd_base;
memcpy(fep->tx_bounce[index], skb->data, skb->len);
bufaddr = fep->tx_bounce[index];
}
@@ -280,17 +318,19 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
| BD_ENET_TX_LAST | BD_ENET_TX_TC);
bdp->cbd_sc = status;
-#ifdef CONFIG_FEC_PTP
- bdp->cbd_bdu = 0;
- if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+ if (fep->bufdesc_ex) {
+
+ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+ ebdp->cbd_bdu = 0;
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
fep->hwts_tx_en)) {
- bdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
+ ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
- } else {
+ } else {
- bdp->cbd_esc = BD_ENET_TX_INT;
+ ebdp->cbd_esc = BD_ENET_TX_INT;
+ }
}
-#endif
/* Trigger transmission start */
writel(0, fep->hwp + FEC_X_DES_ACTIVE);
@@ -298,7 +338,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (status & BD_ENET_TX_WRAP)
bdp = fep->tx_bd_base;
else
- bdp++;
+ bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
if (bdp == fep->dirty_tx) {
fep->tx_full = 1;
@@ -359,8 +399,12 @@ fec_restart(struct net_device *ndev, int duplex)
/* Set receive and transmit descriptor base. */
writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
- writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE,
- fep->hwp + FEC_X_DES_START);
+ if (fep->bufdesc_ex)
+ writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex)
+ * RX_RING_SIZE, fep->hwp + FEC_X_DES_START);
+ else
+ writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
+ * RX_RING_SIZE, fep->hwp + FEC_X_DES_START);
fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
fep->cur_rx = fep->rx_bd_base;
@@ -439,6 +483,25 @@ fec_restart(struct net_device *ndev, int duplex)
}
#endif
}
+
+ /* enable pause frame*/
+ if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) ||
+ ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) &&
+ fep->phy_dev && fep->phy_dev->pause)) {
+ rcntl |= FEC_ENET_FCE;
+
+ /* set FIFO thresh hold parameter to reduce overrun */
+ writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
+ writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
+ writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
+ writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL);
+
+ /* OPD */
+ writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD);
+ } else {
+ rcntl &= ~FEC_ENET_FCE;
+ }
+
writel(rcntl, fep->hwp + FEC_R_CNTRL);
if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
@@ -448,17 +511,16 @@ fec_restart(struct net_device *ndev, int duplex)
writel(1 << 8, fep->hwp + FEC_X_WMRK);
}
-#ifdef CONFIG_FEC_PTP
- ecntl |= (1 << 4);
-#endif
+ if (fep->bufdesc_ex)
+ ecntl |= (1 << 4);
/* And last, enable the transmit and receive processing */
writel(ecntl, fep->hwp + FEC_ECNTRL);
writel(0, fep->hwp + FEC_R_DES_ACTIVE);
-#ifdef CONFIG_FEC_PTP
- fec_ptp_start_cyclecounter(ndev);
-#endif
+ if (fep->bufdesc_ex)
+ fec_ptp_start_cyclecounter(ndev);
+
/* Enable interrupts we wish to service */
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
}
@@ -544,19 +606,20 @@ fec_enet_tx(struct net_device *ndev)
ndev->stats.tx_packets++;
}
-#ifdef CONFIG_FEC_PTP
- if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) &&
+ fep->bufdesc_ex) {
struct skb_shared_hwtstamps shhwtstamps;
unsigned long flags;
+ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
spin_lock_irqsave(&fep->tmreg_lock, flags);
shhwtstamps.hwtstamp = ns_to_ktime(
- timecounter_cyc2time(&fep->tc, bdp->ts));
+ timecounter_cyc2time(&fep->tc, ebdp->ts));
spin_unlock_irqrestore(&fep->tmreg_lock, flags);
skb_tstamp_tx(skb, &shhwtstamps);
}
-#endif
+
if (status & BD_ENET_TX_READY)
printk("HEY! Enet xmit interrupt and TX_READY.\n");
@@ -575,7 +638,7 @@ fec_enet_tx(struct net_device *ndev)
if (status & BD_ENET_TX_WRAP)
bdp = fep->tx_bd_base;
else
- bdp++;
+ bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
/* Since we have freed up a buffer, the ring is no longer full
*/
@@ -595,8 +658,8 @@ fec_enet_tx(struct net_device *ndev)
* not been given to the system, we just set the empty indicator,
* effectively tossing the packet.
*/
-static void
-fec_enet_rx(struct net_device *ndev)
+static int
+fec_enet_rx(struct net_device *ndev, int budget)
{
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
@@ -606,13 +669,12 @@ fec_enet_rx(struct net_device *ndev)
struct sk_buff *skb;
ushort pkt_len;
__u8 *data;
+ int pkt_received = 0;
#ifdef CONFIG_M532x
flush_cache_all();
#endif
- spin_lock(&fep->hw_lock);
-
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
*/
@@ -620,6 +682,10 @@ fec_enet_rx(struct net_device *ndev)
while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
+ if (pkt_received >= budget)
+ break;
+ pkt_received++;
+
/* Since we have allocated space to hold a complete frame,
* the last indicator should be set.
*/
@@ -683,23 +749,25 @@ fec_enet_rx(struct net_device *ndev)
skb_put(skb, pkt_len - 4); /* Make room */
skb_copy_to_linear_data(skb, data, pkt_len - 4);
skb->protocol = eth_type_trans(skb, ndev);
-#ifdef CONFIG_FEC_PTP
+
/* Get receive timestamp from the skb */
- if (fep->hwts_rx_en) {
+ if (fep->hwts_rx_en && fep->bufdesc_ex) {
struct skb_shared_hwtstamps *shhwtstamps =
skb_hwtstamps(skb);
unsigned long flags;
+ struct bufdesc_ex *ebdp =
+ (struct bufdesc_ex *)bdp;
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
spin_lock_irqsave(&fep->tmreg_lock, flags);
shhwtstamps->hwtstamp = ns_to_ktime(
- timecounter_cyc2time(&fep->tc, bdp->ts));
+ timecounter_cyc2time(&fep->tc, ebdp->ts));
spin_unlock_irqrestore(&fep->tmreg_lock, flags);
}
-#endif
+
if (!skb_defer_rx_timestamp(skb))
- netif_rx(skb);
+ napi_gro_receive(&fep->napi, skb);
}
bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
@@ -712,17 +780,19 @@ rx_processing_done:
status |= BD_ENET_RX_EMPTY;
bdp->cbd_sc = status;
-#ifdef CONFIG_FEC_PTP
- bdp->cbd_esc = BD_ENET_RX_INT;
- bdp->cbd_prot = 0;
- bdp->cbd_bdu = 0;
-#endif
+ if (fep->bufdesc_ex) {
+ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+
+ ebdp->cbd_esc = BD_ENET_RX_INT;
+ ebdp->cbd_prot = 0;
+ ebdp->cbd_bdu = 0;
+ }
/* Update BD pointer to next entry */
if (status & BD_ENET_RX_WRAP)
bdp = fep->rx_bd_base;
else
- bdp++;
+ bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
/* Doing this here will keep the FEC running while we process
* incoming frames. On a heavily loaded network, we should be
* able to keep up at the expense of system resources.
@@ -731,7 +801,7 @@ rx_processing_done:
}
fep->cur_rx = bdp;
- spin_unlock(&fep->hw_lock);
+ return pkt_received;
}
static irqreturn_t
@@ -748,7 +818,13 @@ fec_enet_interrupt(int irq, void *dev_id)
if (int_events & FEC_ENET_RXF) {
ret = IRQ_HANDLED;
- fec_enet_rx(ndev);
+
+ /* Disable the RX interrupt */
+ if (napi_schedule_prep(&fep->napi)) {
+ writel(FEC_RX_DISABLED_IMASK,
+ fep->hwp + FEC_IMASK);
+ __napi_schedule(&fep->napi);
+ }
}
/* Transmit OK, or non-fatal error. Update the buffer
@@ -769,10 +845,21 @@ fec_enet_interrupt(int irq, void *dev_id)
return ret;
}
+static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
+{
+ struct net_device *ndev = napi->dev;
+ int pkts = fec_enet_rx(ndev, budget);
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ if (pkts < budget) {
+ napi_complete(napi);
+ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+ }
+ return pkts;
+}
/* ------------------------------------------------------------------------- */
-static void __inline__ fec_get_mac(struct net_device *ndev)
+static void fec_get_mac(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
@@ -973,7 +1060,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
}
snprintf(phy_name, sizeof(phy_name), PHY_ID_FMT, mdio_bus_id, phy_id);
- phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0,
+ phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link,
fep->phy_interface);
if (IS_ERR(phy_dev)) {
printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name);
@@ -981,8 +1068,10 @@ static int fec_enet_mii_probe(struct net_device *ndev)
}
/* mask with MAC supported features */
- if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT)
+ if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
phy_dev->supported &= PHY_GBIT_FEATURES;
+ phy_dev->supported |= SUPPORTED_Pause;
+ }
else
phy_dev->supported &= PHY_BASIC_FEATURES;
@@ -1133,17 +1222,95 @@ static void fec_enet_get_drvinfo(struct net_device *ndev,
{
struct fec_enet_private *fep = netdev_priv(ndev);
- strcpy(info->driver, fep->pdev->dev.driver->name);
- strcpy(info->version, "Revision: 1.0");
- strcpy(info->bus_info, dev_name(&ndev->dev));
+ strlcpy(info->driver, fep->pdev->dev.driver->name,
+ sizeof(info->driver));
+ strlcpy(info->version, "Revision: 1.0", sizeof(info->version));
+ strlcpy(info->bus_info, dev_name(&ndev->dev), sizeof(info->bus_info));
+}
+
+static int fec_enet_get_ts_info(struct net_device *ndev,
+ struct ethtool_ts_info *info)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ if (fep->bufdesc_ex) {
+
+ info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ if (fep->ptp_clock)
+ info->phc_index = ptp_clock_index(fep->ptp_clock);
+ else
+ info->phc_index = -1;
+
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) |
+ (1 << HWTSTAMP_TX_ON);
+
+ info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_ALL);
+ return 0;
+ } else {
+ return ethtool_op_get_ts_info(ndev, info);
+ }
+}
+
+static void fec_enet_get_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ pause->autoneg = (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) != 0;
+ pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) != 0;
+ pause->rx_pause = pause->tx_pause;
+}
+
+static int fec_enet_set_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ if (pause->tx_pause != pause->rx_pause) {
+ netdev_info(ndev,
+ "hardware only support enable/disable both tx and rx");
+ return -EINVAL;
+ }
+
+ fep->pause_flag = 0;
+
+ /* tx pause must be same as rx pause */
+ fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0;
+ fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0;
+
+ if (pause->rx_pause || pause->autoneg) {
+ fep->phy_dev->supported |= ADVERTISED_Pause;
+ fep->phy_dev->advertising |= ADVERTISED_Pause;
+ } else {
+ fep->phy_dev->supported &= ~ADVERTISED_Pause;
+ fep->phy_dev->advertising &= ~ADVERTISED_Pause;
+ }
+
+ if (pause->autoneg) {
+ if (netif_running(ndev))
+ fec_stop(ndev);
+ phy_start_aneg(fep->phy_dev);
+ }
+ if (netif_running(ndev))
+ fec_restart(ndev, 0);
+
+ return 0;
}
static const struct ethtool_ops fec_enet_ethtool_ops = {
+ .get_pauseparam = fec_enet_get_pauseparam,
+ .set_pauseparam = fec_enet_set_pauseparam,
.get_settings = fec_enet_get_settings,
.set_settings = fec_enet_set_settings,
.get_drvinfo = fec_enet_get_drvinfo,
.get_link = ethtool_op_get_link,
- .get_ts_info = ethtool_op_get_ts_info,
+ .get_ts_info = fec_enet_get_ts_info,
};
static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -1157,10 +1324,9 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
if (!phydev)
return -ENODEV;
-#ifdef CONFIG_FEC_PTP
- if (cmd == SIOCSHWTSTAMP)
+ if (cmd == SIOCSHWTSTAMP && fep->bufdesc_ex)
return fec_ptp_ioctl(ndev, rq, cmd);
-#endif
+
return phy_mii_ioctl(phydev, rq, cmd);
}
@@ -1180,7 +1346,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)
FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
if (skb)
dev_kfree_skb(skb);
- bdp++;
+ bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
}
bdp = fep->tx_bd_base;
@@ -1207,14 +1373,17 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
bdp->cbd_sc = BD_ENET_RX_EMPTY;
-#ifdef CONFIG_FEC_PTP
- bdp->cbd_esc = BD_ENET_RX_INT;
-#endif
- bdp++;
+
+ if (fep->bufdesc_ex) {
+ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+ ebdp->cbd_esc = BD_ENET_RX_INT;
+ }
+
+ bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
}
/* Set the last buffer to wrap. */
- bdp--;
+ bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
bdp->cbd_sc |= BD_SC_WRAP;
bdp = fep->tx_bd_base;
@@ -1224,14 +1393,16 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
bdp->cbd_sc = 0;
bdp->cbd_bufaddr = 0;
-#ifdef CONFIG_FEC_PTP
- bdp->cbd_esc = BD_ENET_RX_INT;
-#endif
- bdp++;
+ if (fep->bufdesc_ex) {
+ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
+ ebdp->cbd_esc = BD_ENET_RX_INT;
+ }
+
+ bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
}
/* Set the last buffer to wrap. */
- bdp--;
+ bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
bdp->cbd_sc |= BD_SC_WRAP;
return 0;
@@ -1243,6 +1414,8 @@ fec_enet_open(struct net_device *ndev)
struct fec_enet_private *fep = netdev_priv(ndev);
int ret;
+ napi_enable(&fep->napi);
+
/* I should reset the ring buffers here, but I don't yet know
* a simple way to do that.
*/
@@ -1444,24 +1617,31 @@ static int fec_enet_init(struct net_device *ndev)
/* Set receive and transmit descriptor base. */
fep->rx_bd_base = cbd_base;
- fep->tx_bd_base = cbd_base + RX_RING_SIZE;
+ if (fep->bufdesc_ex)
+ fep->tx_bd_base = (struct bufdesc *)
+ (((struct bufdesc_ex *)cbd_base) + RX_RING_SIZE);
+ else
+ fep->tx_bd_base = cbd_base + RX_RING_SIZE;
/* The FEC Ethernet specific entries in the device structure */
ndev->watchdog_timeo = TX_TIMEOUT;
ndev->netdev_ops = &fec_netdev_ops;
ndev->ethtool_ops = &fec_enet_ethtool_ops;
+ writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
+ netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
+
/* Initialize the receive buffer descriptors. */
bdp = fep->rx_bd_base;
for (i = 0; i < RX_RING_SIZE; i++) {
/* Initialize the BD for every fragment in the page. */
bdp->cbd_sc = 0;
- bdp++;
+ bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
}
/* Set the last buffer to wrap */
- bdp--;
+ bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
bdp->cbd_sc |= BD_SC_WRAP;
/* ...and the same for transmit */
@@ -1471,11 +1651,11 @@ static int fec_enet_init(struct net_device *ndev)
/* Initialize the BD for every fragment in the page. */
bdp->cbd_sc = 0;
bdp->cbd_bufaddr = 0;
- bdp++;
+ bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
}
/* Set the last buffer to wrap */
- bdp--;
+ bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
bdp->cbd_sc |= BD_SC_WRAP;
fec_restart(ndev, 0);
@@ -1509,22 +1689,25 @@ static void fec_reset_phy(struct platform_device *pdev)
msec = 1;
phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
+ if (!gpio_is_valid(phy_reset))
+ return;
+
err = devm_gpio_request_one(&pdev->dev, phy_reset,
GPIOF_OUT_INIT_LOW, "phy-reset");
if (err) {
- pr_debug("FEC: failed to get gpio phy-reset: %d\n", err);
+ dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err);
return;
}
msleep(msec);
gpio_set_value(phy_reset, 1);
}
#else /* CONFIG_OF */
-static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
+static int fec_get_phy_mode_dt(struct platform_device *pdev)
{
return -ENODEV;
}
-static inline void fec_reset_phy(struct platform_device *pdev)
+static void fec_reset_phy(struct platform_device *pdev)
{
/*
* In case of platform probe, the reset has been done
@@ -1570,10 +1753,17 @@ fec_probe(struct platform_device *pdev)
/* setup board info structure */
fep = netdev_priv(ndev);
+ /* default enable pause frame auto negotiation */
+ if (pdev->id_entry &&
+ (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
+ fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
+
fep->hwp = ioremap(r->start, resource_size(r));
fep->pdev = pdev;
fep->dev_id = dev_id++;
+ fep->bufdesc_ex = 0;
+
if (!fep->hwp) {
ret = -ENOMEM;
goto failed_ioremap;
@@ -1628,19 +1818,19 @@ fec_probe(struct platform_device *pdev)
goto failed_clk;
}
-#ifdef CONFIG_FEC_PTP
fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
+ fep->bufdesc_ex =
+ pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
if (IS_ERR(fep->clk_ptp)) {
ret = PTR_ERR(fep->clk_ptp);
- goto failed_clk;
+ fep->bufdesc_ex = 0;
}
-#endif
clk_prepare_enable(fep->clk_ahb);
clk_prepare_enable(fep->clk_ipg);
-#ifdef CONFIG_FEC_PTP
- clk_prepare_enable(fep->clk_ptp);
-#endif
+ if (!IS_ERR(fep->clk_ptp))
+ clk_prepare_enable(fep->clk_ptp);
+
reg_phy = devm_regulator_get(&pdev->dev, "phy");
if (!IS_ERR(reg_phy)) {
ret = regulator_enable(reg_phy);
@@ -1653,6 +1843,9 @@ fec_probe(struct platform_device *pdev)
fec_reset_phy(pdev);
+ if (fep->bufdesc_ex)
+ fec_ptp_init(ndev, pdev);
+
ret = fec_enet_init(ndev);
if (ret)
goto failed_init;
@@ -1668,10 +1861,6 @@ fec_probe(struct platform_device *pdev)
if (ret)
goto failed_register;
-#ifdef CONFIG_FEC_PTP
- fec_ptp_init(ndev, pdev);
-#endif
-
return 0;
failed_register:
@@ -1681,9 +1870,8 @@ failed_init:
failed_regulator:
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
-#ifdef CONFIG_FEC_PTP
- clk_disable_unprepare(fep->clk_ptp);
-#endif
+ if (!IS_ERR(fep->clk_ptp))
+ clk_disable_unprepare(fep->clk_ptp);
failed_pin:
failed_clk:
for (i = 0; i < FEC_IRQ_NUM; i++) {
@@ -1716,12 +1904,10 @@ fec_drv_remove(struct platform_device *pdev)
if (irq > 0)
free_irq(irq, ndev);
}
-#ifdef CONFIG_FEC_PTP
del_timer_sync(&fep->time_keep);
clk_disable_unprepare(fep->clk_ptp);
if (fep->ptp_clock)
ptp_clock_unregister(fep->ptp_clock);
-#endif
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
iounmap(fep->hwp);
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index c5a3bc1475c7..01579b8e37c4 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -13,11 +13,9 @@
#define FEC_H
/****************************************************************************/
-#ifdef CONFIG_FEC_PTP
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
-#endif
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
@@ -50,6 +48,10 @@
#define FEC_R_DES_START 0x180 /* Receive descriptor ring */
#define FEC_X_DES_START 0x184 /* Transmit descriptor ring */
#define FEC_R_BUFF_SIZE 0x188 /* Maximum receive buff size */
+#define FEC_R_FIFO_RSFL 0x190 /* Receive FIFO section full threshold */
+#define FEC_R_FIFO_RSEM 0x194 /* Receive FIFO section empty threshold */
+#define FEC_R_FIFO_RAEM 0x198 /* Receive FIFO almost empty threshold */
+#define FEC_R_FIFO_RAFL 0x19c /* Receive FIFO almost full threshold */
#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */
@@ -94,14 +96,17 @@ struct bufdesc {
unsigned short cbd_datlen; /* Data length */
unsigned short cbd_sc; /* Control and status info */
unsigned long cbd_bufaddr; /* Buffer address */
-#ifdef CONFIG_FEC_PTP
+};
+
+struct bufdesc_ex {
+ struct bufdesc desc;
unsigned long cbd_esc;
unsigned long cbd_prot;
unsigned long cbd_bdu;
unsigned long ts;
unsigned short res0[4];
-#endif
};
+
#else
struct bufdesc {
unsigned short cbd_sc; /* Control and status info */
@@ -203,9 +208,7 @@ struct fec_enet_private {
struct clk *clk_ipg;
struct clk *clk_ahb;
-#ifdef CONFIG_FEC_PTP
struct clk *clk_ptp;
-#endif
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
unsigned char *tx_bounce[TX_RING_SIZE];
@@ -243,8 +246,11 @@ struct fec_enet_private {
int full_duplex;
struct completion mdio_done;
int irq[FEC_IRQ_NUM];
+ int bufdesc_ex;
+ int pause_flag;
+
+ struct napi_struct napi;
-#ifdef CONFIG_FEC_PTP
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps;
unsigned long last_overflow_check;
@@ -257,15 +263,12 @@ struct fec_enet_private {
int hwts_rx_en;
int hwts_tx_en;
struct timer_list time_keep;
-#endif
};
-#ifdef CONFIG_FEC_PTP
void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev);
void fec_ptp_start_cyclecounter(struct net_device *ndev);
int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd);
-#endif
/****************************************************************************/
#endif /* FEC_H */
diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c
index 817d081d2cd8..77943a6a1b8c 100644
--- a/drivers/net/ethernet/freescale/fec_mpc52xx.c
+++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c
@@ -29,6 +29,7 @@
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
+#include <linux/of_net.h>
#include <linux/of_platform.h>
#include <linux/netdevice.h>
@@ -40,8 +41,8 @@
#include <asm/delay.h>
#include <asm/mpc52xx.h>
-#include <sysdev/bestcomm/bestcomm.h>
-#include <sysdev/bestcomm/fec.h>
+#include <linux/fsl/bestcomm/bestcomm.h>
+#include <linux/fsl/bestcomm/fec.h>
#include "fec_mpc52xx.h"
@@ -76,10 +77,6 @@ static void mpc52xx_fec_stop(struct net_device *dev);
static void mpc52xx_fec_start(struct net_device *dev);
static void mpc52xx_fec_reset(struct net_device *dev);
-static u8 mpc52xx_fec_mac_addr[6];
-module_param_array_named(mac, mpc52xx_fec_mac_addr, byte, NULL, 0);
-MODULE_PARM_DESC(mac, "six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe");
-
#define MPC52xx_MESSAGES_DEFAULT ( NETIF_MSG_DRV | NETIF_MSG_PROBE | \
NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP)
static int debug = -1; /* the above default */
@@ -110,15 +107,6 @@ static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)
out_be32(&fec->paddr2, (*(u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
}
-static void mpc52xx_fec_get_paddr(struct net_device *dev, u8 *mac)
-{
- struct mpc52xx_fec_priv *priv = netdev_priv(dev);
- struct mpc52xx_fec __iomem *fec = priv->fec;
-
- *(u32 *)(&mac[0]) = in_be32(&fec->paddr1);
- *(u16 *)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
-}
-
static int mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *sock = addr;
@@ -853,6 +841,8 @@ static int mpc52xx_fec_probe(struct platform_device *op)
struct resource mem;
const u32 *prop;
int prop_size;
+ struct device_node *np = op->dev.of_node;
+ const char *mac_addr;
phys_addr_t rx_fifo;
phys_addr_t tx_fifo;
@@ -866,7 +856,7 @@ static int mpc52xx_fec_probe(struct platform_device *op)
priv->ndev = ndev;
/* Reserve FEC control zone */
- rv = of_address_to_resource(op->dev.of_node, 0, &mem);
+ rv = of_address_to_resource(np, 0, &mem);
if (rv) {
printk(KERN_ERR DRIVER_NAME ": "
"Error while parsing device node resource\n" );
@@ -919,7 +909,7 @@ static int mpc52xx_fec_probe(struct platform_device *op)
/* Get the IRQ we need one by one */
/* Control */
- ndev->irq = irq_of_parse_and_map(op->dev.of_node, 0);
+ ndev->irq = irq_of_parse_and_map(np, 0);
/* RX */
priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk);
@@ -927,11 +917,33 @@ static int mpc52xx_fec_probe(struct platform_device *op)
/* TX */
priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk);
- /* MAC address init */
- if (!is_zero_ether_addr(mpc52xx_fec_mac_addr))
- memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
- else
- mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
+ /*
+ * MAC address init:
+ *
+ * First try to read MAC address from DT
+ */
+ mac_addr = of_get_mac_address(np);
+ if (mac_addr) {
+ memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
+ } else {
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ /*
+ * If the MAC addresse is not provided via DT then read
+ * it back from the controller regs
+ */
+ *(u32 *)(&ndev->dev_addr[0]) = in_be32(&fec->paddr1);
+ *(u16 *)(&ndev->dev_addr[4]) = in_be32(&fec->paddr2) >> 16;
+ }
+
+ /*
+ * Check if the MAC address is valid, if not get a random one
+ */
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ eth_hw_addr_random(ndev);
+ dev_warn(&ndev->dev, "using random MAC address %pM\n",
+ ndev->dev_addr);
+ }
priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT);
@@ -942,20 +954,20 @@ static int mpc52xx_fec_probe(struct platform_device *op)
/* Start with safe defaults for link connection */
priv->speed = 100;
priv->duplex = DUPLEX_HALF;
- priv->mdio_speed = ((mpc5xxx_get_bus_frequency(op->dev.of_node) >> 20) / 5) << 1;
+ priv->mdio_speed = ((mpc5xxx_get_bus_frequency(np) >> 20) / 5) << 1;
/* The current speed preconfigures the speed of the MII link */
- prop = of_get_property(op->dev.of_node, "current-speed", &prop_size);
+ prop = of_get_property(np, "current-speed", &prop_size);
if (prop && (prop_size >= sizeof(u32) * 2)) {
priv->speed = prop[0];
priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF;
}
/* If there is a phy handle, then get the PHY node */
- priv->phy_node = of_parse_phandle(op->dev.of_node, "phy-handle", 0);
+ priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
/* the 7-wire property means don't use MII mode */
- if (of_find_property(op->dev.of_node, "fsl,7-wire-mode", NULL)) {
+ if (of_find_property(np, "fsl,7-wire-mode", NULL)) {
priv->seven_wire_mode = 1;
dev_info(&ndev->dev, "using 7-wire PHY mode\n");
}
@@ -970,6 +982,8 @@ static int mpc52xx_fec_probe(struct platform_device *op)
/* We're done ! */
dev_set_drvdata(&op->dev, ndev);
+ printk(KERN_INFO "%s: %s MAC %pM\n",
+ ndev->name, op->dev.of_node->full_name, ndev->dev_addr);
return 0;
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index c40526c78c20..1f17ca0f2201 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -104,7 +104,7 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)
unsigned long flags;
int inc;
- inc = 1000000000 / clk_get_rate(fep->clk_ptp);
+ inc = 1000000000 / fep->cycle_speed;
/* grab the ptp lock */
spin_lock_irqsave(&fep->tmreg_lock, flags);
@@ -363,6 +363,8 @@ void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev)
fep->ptp_caps.settime = fec_ptp_settime;
fep->ptp_caps.enable = fec_ptp_enable;
+ fep->cycle_speed = clk_get_rate(fep->clk_ptp);
+
spin_lock_init(&fep->tmreg_lock);
fec_ptp_start_cyclecounter(ndev);
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index e9879c5af7ba..46df28893c10 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -888,8 +888,8 @@ static struct net_device_stats *fs_enet_get_stats(struct net_device *dev)
static void fs_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, DRV_MODULE_NAME);
- strcpy(info->version, DRV_MODULE_VERSION);
+ strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
}
static int fs_get_regs_len(struct net_device *dev)
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index bffb2edd6858..4b5e8a692481 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -133,8 +133,8 @@ static void gfar_netpoll(struct net_device *dev);
#endif
int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);
static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue);
-static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
- int amount_pull, struct napi_struct *napi);
+static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
+ int amount_pull, struct napi_struct *napi);
void gfar_halt(struct net_device *dev);
static void gfar_halt_nodisable(struct net_device *dev);
void gfar_start(struct net_device *dev);
@@ -231,7 +231,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
dma_addr_t addr;
int i, j, k;
struct gfar_private *priv = netdev_priv(ndev);
- struct device *dev = &priv->ofdev->dev;
+ struct device *dev = priv->dev;
struct gfar_priv_tx_q *tx_queue = NULL;
struct gfar_priv_rx_q *rx_queue = NULL;
@@ -277,14 +277,12 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
/* Setup the skbuff rings */
for (i = 0; i < priv->num_tx_queues; i++) {
tx_queue = priv->tx_queue[i];
- tx_queue->tx_skbuff = kmalloc(sizeof(*tx_queue->tx_skbuff) *
- tx_queue->tx_ring_size,
- GFP_KERNEL);
- if (!tx_queue->tx_skbuff) {
- netif_err(priv, ifup, ndev,
- "Could not allocate tx_skbuff\n");
+ tx_queue->tx_skbuff =
+ kmalloc_array(tx_queue->tx_ring_size,
+ sizeof(*tx_queue->tx_skbuff),
+ GFP_KERNEL);
+ if (!tx_queue->tx_skbuff)
goto cleanup;
- }
for (k = 0; k < tx_queue->tx_ring_size; k++)
tx_queue->tx_skbuff[k] = NULL;
@@ -292,15 +290,12 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
for (i = 0; i < priv->num_rx_queues; i++) {
rx_queue = priv->rx_queue[i];
- rx_queue->rx_skbuff = kmalloc(sizeof(*rx_queue->rx_skbuff) *
- rx_queue->rx_ring_size,
- GFP_KERNEL);
-
- if (!rx_queue->rx_skbuff) {
- netif_err(priv, ifup, ndev,
- "Could not allocate rx_skbuff\n");
+ rx_queue->rx_skbuff =
+ kmalloc_array(rx_queue->rx_ring_size,
+ sizeof(*rx_queue->rx_skbuff),
+ GFP_KERNEL);
+ if (!rx_queue->rx_skbuff)
goto cleanup;
- }
for (j = 0; j < rx_queue->rx_ring_size; j++)
rx_queue->rx_skbuff[j] = NULL;
@@ -349,14 +344,23 @@ static void gfar_init_mac(struct net_device *ndev)
/* Configure the coalescing support */
gfar_configure_coalescing(priv, 0xFF, 0xFF);
+ /* set this when rx hw offload (TOE) functions are being used */
+ priv->uses_rxfcb = 0;
+
if (priv->rx_filer_enable) {
rctrl |= RCTRL_FILREN;
/* Program the RIR0 reg with the required distribution */
gfar_write(&regs->rir0, DEFAULT_RIR0);
}
- if (ndev->features & NETIF_F_RXCSUM)
+ /* Restore PROMISC mode */
+ if (ndev->flags & IFF_PROMISC)
+ rctrl |= RCTRL_PROM;
+
+ if (ndev->features & NETIF_F_RXCSUM) {
rctrl |= RCTRL_CHECKSUMMING;
+ priv->uses_rxfcb = 1;
+ }
if (priv->extended_hash) {
rctrl |= RCTRL_EXTHASH;
@@ -378,11 +382,15 @@ static void gfar_init_mac(struct net_device *ndev)
}
/* Enable HW time stamping if requested from user space */
- if (priv->hwts_rx_en)
+ if (priv->hwts_rx_en) {
rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE;
+ priv->uses_rxfcb = 1;
+ }
- if (ndev->features & NETIF_F_HW_VLAN_RX)
+ if (ndev->features & NETIF_F_HW_VLAN_RX) {
rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
+ priv->uses_rxfcb = 1;
+ }
/* Init rctrl based on our settings */
gfar_write(&regs->rctrl, rctrl);
@@ -501,20 +509,6 @@ void unlock_tx_qs(struct gfar_private *priv)
spin_unlock(&priv->tx_queue[i]->txlock);
}
-static bool gfar_is_vlan_on(struct gfar_private *priv)
-{
- return (priv->ndev->features & NETIF_F_HW_VLAN_RX) ||
- (priv->ndev->features & NETIF_F_HW_VLAN_TX);
-}
-
-/* Returns 1 if incoming frames use an FCB */
-static inline int gfar_uses_fcb(struct gfar_private *priv)
-{
- return gfar_is_vlan_on(priv) ||
- (priv->ndev->features & NETIF_F_RXCSUM) ||
- (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER);
-}
-
static void free_tx_pointers(struct gfar_private *priv)
{
int i;
@@ -540,6 +534,19 @@ static void unmap_group_regs(struct gfar_private *priv)
iounmap(priv->gfargrp[i].regs);
}
+static void free_gfar_dev(struct gfar_private *priv)
+{
+ int i, j;
+
+ for (i = 0; i < priv->num_grps; i++)
+ for (j = 0; j < GFAR_NUM_IRQS; j++) {
+ kfree(priv->gfargrp[i].irqinfo[j]);
+ priv->gfargrp[i].irqinfo[j] = NULL;
+ }
+
+ free_netdev(priv->ndev);
+}
+
static void disable_napi(struct gfar_private *priv)
{
int i;
@@ -559,40 +566,46 @@ static void enable_napi(struct gfar_private *priv)
static int gfar_parse_group(struct device_node *np,
struct gfar_private *priv, const char *model)
{
+ struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps];
u32 *queue_mask;
+ int i;
+
+ for (i = 0; i < GFAR_NUM_IRQS; i++) {
+ grp->irqinfo[i] = kzalloc(sizeof(struct gfar_irqinfo),
+ GFP_KERNEL);
+ if (!grp->irqinfo[i])
+ return -ENOMEM;
+ }
- priv->gfargrp[priv->num_grps].regs = of_iomap(np, 0);
- if (!priv->gfargrp[priv->num_grps].regs)
+ grp->regs = of_iomap(np, 0);
+ if (!grp->regs)
return -ENOMEM;
- priv->gfargrp[priv->num_grps].interruptTransmit =
- irq_of_parse_and_map(np, 0);
+ gfar_irq(grp, TX)->irq = irq_of_parse_and_map(np, 0);
/* If we aren't the FEC we have multiple interrupts */
if (model && strcasecmp(model, "FEC")) {
- priv->gfargrp[priv->num_grps].interruptReceive =
- irq_of_parse_and_map(np, 1);
- priv->gfargrp[priv->num_grps].interruptError =
- irq_of_parse_and_map(np,2);
- if (priv->gfargrp[priv->num_grps].interruptTransmit == NO_IRQ ||
- priv->gfargrp[priv->num_grps].interruptReceive == NO_IRQ ||
- priv->gfargrp[priv->num_grps].interruptError == NO_IRQ)
+ gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1);
+ gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2);
+ if (gfar_irq(grp, TX)->irq == NO_IRQ ||
+ gfar_irq(grp, RX)->irq == NO_IRQ ||
+ gfar_irq(grp, ER)->irq == NO_IRQ)
return -EINVAL;
}
- priv->gfargrp[priv->num_grps].grp_id = priv->num_grps;
- priv->gfargrp[priv->num_grps].priv = priv;
- spin_lock_init(&priv->gfargrp[priv->num_grps].grplock);
+ grp->grp_id = priv->num_grps;
+ grp->priv = priv;
+ spin_lock_init(&grp->grplock);
if (priv->mode == MQ_MG_MODE) {
queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL);
- priv->gfargrp[priv->num_grps].rx_bit_map = queue_mask ?
+ grp->rx_bit_map = queue_mask ?
*queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL);
- priv->gfargrp[priv->num_grps].tx_bit_map = queue_mask ?
+ grp->tx_bit_map = queue_mask ?
*queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
} else {
- priv->gfargrp[priv->num_grps].rx_bit_map = 0xFF;
- priv->gfargrp[priv->num_grps].tx_bit_map = 0xFF;
+ grp->rx_bit_map = 0xFF;
+ grp->tx_bit_map = 0xFF;
}
priv->num_grps++;
@@ -645,7 +658,6 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
return -ENOMEM;
priv = netdev_priv(dev);
- priv->node = ofdev->dev.of_node;
priv->ndev = dev;
priv->num_tx_queues = num_tx_qs;
@@ -777,7 +789,7 @@ tx_alloc_failed:
free_tx_pointers(priv);
err_grp_init:
unmap_group_regs(priv);
- free_netdev(dev);
+ free_gfar_dev(priv);
return err;
}
@@ -983,7 +995,7 @@ static int gfar_probe(struct platform_device *ofdev)
priv = netdev_priv(dev);
priv->ndev = dev;
priv->ofdev = ofdev;
- priv->node = ofdev->dev.of_node;
+ priv->dev = &ofdev->dev;
SET_NETDEV_DEV(dev, &ofdev->dev);
spin_lock_init(&priv->bflock);
@@ -1020,8 +1032,6 @@ static int gfar_probe(struct platform_device *ofdev)
/* Set the dev->base_addr to the gfar reg region */
dev->base_addr = (unsigned long) regs;
- SET_NETDEV_DEV(dev, &ofdev->dev);
-
/* Fill in the dev structure */
dev->watchdog_timeo = TX_TIMEOUT;
dev->mtu = 1500;
@@ -1182,15 +1192,16 @@ static int gfar_probe(struct platform_device *ofdev)
/* fill out IRQ number and name fields */
for (i = 0; i < priv->num_grps; i++) {
+ struct gfar_priv_grp *grp = &priv->gfargrp[i];
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
- sprintf(priv->gfargrp[i].int_name_tx, "%s%s%c%s",
+ sprintf(gfar_irq(grp, TX)->name, "%s%s%c%s",
dev->name, "_g", '0' + i, "_tx");
- sprintf(priv->gfargrp[i].int_name_rx, "%s%s%c%s",
+ sprintf(gfar_irq(grp, RX)->name, "%s%s%c%s",
dev->name, "_g", '0' + i, "_rx");
- sprintf(priv->gfargrp[i].int_name_er, "%s%s%c%s",
+ sprintf(gfar_irq(grp, ER)->name, "%s%s%c%s",
dev->name, "_g", '0' + i, "_er");
} else
- strcpy(priv->gfargrp[i].int_name_tx, dev->name);
+ strcpy(gfar_irq(grp, TX)->name, dev->name);
}
/* Initialize the filer table */
@@ -1223,7 +1234,7 @@ register_fail:
of_node_put(priv->phy_node);
if (priv->tbi_node)
of_node_put(priv->tbi_node);
- free_netdev(dev);
+ free_gfar_dev(priv);
return err;
}
@@ -1240,7 +1251,7 @@ static int gfar_remove(struct platform_device *ofdev)
unregister_netdev(priv->ndev);
unmap_group_regs(priv);
- free_netdev(priv->ndev);
+ free_gfar_dev(priv);
return 0;
}
@@ -1648,9 +1659,9 @@ void gfar_halt(struct net_device *dev)
static void free_grp_irqs(struct gfar_priv_grp *grp)
{
- free_irq(grp->interruptError, grp);
- free_irq(grp->interruptTransmit, grp);
- free_irq(grp->interruptReceive, grp);
+ free_irq(gfar_irq(grp, TX)->irq, grp);
+ free_irq(gfar_irq(grp, RX)->irq, grp);
+ free_irq(gfar_irq(grp, ER)->irq, grp);
}
void stop_gfar(struct net_device *dev)
@@ -1679,7 +1690,7 @@ void stop_gfar(struct net_device *dev)
free_grp_irqs(&priv->gfargrp[i]);
} else {
for (i = 0; i < priv->num_grps; i++)
- free_irq(priv->gfargrp[i].interruptTransmit,
+ free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq,
&priv->gfargrp[i]);
}
@@ -1698,13 +1709,13 @@ static void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue)
if (!tx_queue->tx_skbuff[i])
continue;
- dma_unmap_single(&priv->ofdev->dev, txbdp->bufPtr,
+ dma_unmap_single(priv->dev, txbdp->bufPtr,
txbdp->length, DMA_TO_DEVICE);
txbdp->lstatus = 0;
for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags;
j++) {
txbdp++;
- dma_unmap_page(&priv->ofdev->dev, txbdp->bufPtr,
+ dma_unmap_page(priv->dev, txbdp->bufPtr,
txbdp->length, DMA_TO_DEVICE);
}
txbdp++;
@@ -1725,8 +1736,8 @@ static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue)
for (i = 0; i < rx_queue->rx_ring_size; i++) {
if (rx_queue->rx_skbuff[i]) {
- dma_unmap_single(&priv->ofdev->dev,
- rxbdp->bufPtr, priv->rx_buffer_size,
+ dma_unmap_single(priv->dev, rxbdp->bufPtr,
+ priv->rx_buffer_size,
DMA_FROM_DEVICE);
dev_kfree_skb_any(rx_queue->rx_skbuff[i]);
rx_queue->rx_skbuff[i] = NULL;
@@ -1765,7 +1776,7 @@ static void free_skb_resources(struct gfar_private *priv)
free_skb_rx_queue(rx_queue);
}
- dma_free_coherent(&priv->ofdev->dev,
+ dma_free_coherent(priv->dev,
sizeof(struct txbd8) * priv->total_tx_ring_size +
sizeof(struct rxbd8) * priv->total_rx_ring_size,
priv->tx_queue[0]->tx_bd_base,
@@ -1854,32 +1865,34 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
/* Install our interrupt handlers for Error,
* Transmit, and Receive
*/
- if ((err = request_irq(grp->interruptError, gfar_error,
- 0, grp->int_name_er, grp)) < 0) {
+ err = request_irq(gfar_irq(grp, ER)->irq, gfar_error, 0,
+ gfar_irq(grp, ER)->name, grp);
+ if (err < 0) {
netif_err(priv, intr, dev, "Can't get IRQ %d\n",
- grp->interruptError);
+ gfar_irq(grp, ER)->irq);
goto err_irq_fail;
}
-
- if ((err = request_irq(grp->interruptTransmit, gfar_transmit,
- 0, grp->int_name_tx, grp)) < 0) {
+ err = request_irq(gfar_irq(grp, TX)->irq, gfar_transmit, 0,
+ gfar_irq(grp, TX)->name, grp);
+ if (err < 0) {
netif_err(priv, intr, dev, "Can't get IRQ %d\n",
- grp->interruptTransmit);
+ gfar_irq(grp, TX)->irq);
goto tx_irq_fail;
}
-
- if ((err = request_irq(grp->interruptReceive, gfar_receive,
- 0, grp->int_name_rx, grp)) < 0) {
+ err = request_irq(gfar_irq(grp, RX)->irq, gfar_receive, 0,
+ gfar_irq(grp, RX)->name, grp);
+ if (err < 0) {
netif_err(priv, intr, dev, "Can't get IRQ %d\n",
- grp->interruptReceive);
+ gfar_irq(grp, RX)->irq);
goto rx_irq_fail;
}
} else {
- if ((err = request_irq(grp->interruptTransmit, gfar_interrupt,
- 0, grp->int_name_tx, grp)) < 0) {
+ err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0,
+ gfar_irq(grp, TX)->name, grp);
+ if (err < 0) {
netif_err(priv, intr, dev, "Can't get IRQ %d\n",
- grp->interruptTransmit);
+ gfar_irq(grp, TX)->irq);
goto err_irq_fail;
}
}
@@ -1887,9 +1900,9 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
return 0;
rx_irq_fail:
- free_irq(grp->interruptTransmit, grp);
+ free_irq(gfar_irq(grp, TX)->irq, grp);
tx_irq_fail:
- free_irq(grp->interruptError, grp);
+ free_irq(gfar_irq(grp, ER)->irq, grp);
err_irq_fail:
return err;
@@ -2143,7 +2156,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (i == nr_frags - 1)
lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
- bufaddr = skb_frag_dma_map(&priv->ofdev->dev,
+ bufaddr = skb_frag_dma_map(priv->dev,
&skb_shinfo(skb)->frags[i],
0,
length,
@@ -2195,7 +2208,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
lstatus |= BD_LFLAG(TXBD_TOE);
}
- txbdp_start->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data,
+ txbdp_start->bufPtr = dma_map_single(priv->dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE);
/* If time stamping is requested one additional TxBD must be set up. The
@@ -2308,10 +2321,13 @@ void gfar_check_rx_parser_mode(struct gfar_private *priv)
tempval = gfar_read(&regs->rctrl);
/* If parse is no longer required, then disable parser */
- if (tempval & RCTRL_REQ_PARSER)
+ if (tempval & RCTRL_REQ_PARSER) {
tempval |= RCTRL_PRSDEP_INIT;
- else
+ priv->uses_rxfcb = 1;
+ } else {
tempval &= ~RCTRL_PRSDEP_INIT;
+ priv->uses_rxfcb = 0;
+ }
gfar_write(&regs->rctrl, tempval);
}
@@ -2344,6 +2360,7 @@ void gfar_vlan_mode(struct net_device *dev, netdev_features_t features)
tempval = gfar_read(&regs->rctrl);
tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT);
gfar_write(&regs->rctrl, tempval);
+ priv->uses_rxfcb = 1;
} else {
/* Disable VLAN tag extraction */
tempval = gfar_read(&regs->rctrl);
@@ -2367,15 +2384,12 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
int oldsize = priv->rx_buffer_size;
int frame_size = new_mtu + ETH_HLEN;
- if (gfar_is_vlan_on(priv))
- frame_size += VLAN_HLEN;
-
if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
netif_err(priv, drv, dev, "Invalid MTU setting\n");
return -EINVAL;
}
- if (gfar_uses_fcb(priv))
+ if (priv->uses_rxfcb)
frame_size += GMAC_FCB_LEN;
frame_size += priv->padding;
@@ -2508,7 +2522,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
} else
buflen = bdp->length;
- dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
+ dma_unmap_single(priv->dev, bdp->bufPtr,
buflen, DMA_TO_DEVICE);
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
@@ -2527,7 +2541,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
bdp = next_txbd(bdp, base, tx_ring_size);
for (i = 0; i < frags; i++) {
- dma_unmap_page(&priv->ofdev->dev, bdp->bufPtr,
+ dma_unmap_page(priv->dev, bdp->bufPtr,
bdp->length, DMA_TO_DEVICE);
bdp->lstatus &= BD_LFLAG(TXBD_WRAP);
bdp = next_txbd(bdp, base, tx_ring_size);
@@ -2593,7 +2607,7 @@ static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
struct gfar_private *priv = netdev_priv(dev);
dma_addr_t buf;
- buf = dma_map_single(&priv->ofdev->dev, skb->data,
+ buf = dma_map_single(priv->dev, skb->data,
priv->rx_buffer_size, DMA_FROM_DEVICE);
gfar_init_rxbdp(rx_queue, bdp, buf);
}
@@ -2627,7 +2641,7 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
if (status & RXBD_TRUNCATED) {
stats->rx_length_errors++;
- estats->rx_trunc++;
+ atomic64_inc(&estats->rx_trunc);
return;
}
@@ -2636,20 +2650,20 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
stats->rx_length_errors++;
if (status & RXBD_LARGE)
- estats->rx_large++;
+ atomic64_inc(&estats->rx_large);
else
- estats->rx_short++;
+ atomic64_inc(&estats->rx_short);
}
if (status & RXBD_NONOCTET) {
stats->rx_frame_errors++;
- estats->rx_nonoctet++;
+ atomic64_inc(&estats->rx_nonoctet);
}
if (status & RXBD_CRCERR) {
- estats->rx_crcerr++;
+ atomic64_inc(&estats->rx_crcerr);
stats->rx_crc_errors++;
}
if (status & RXBD_OVERRUN) {
- estats->rx_overrun++;
+ atomic64_inc(&estats->rx_overrun);
stats->rx_crc_errors++;
}
}
@@ -2674,8 +2688,8 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
/* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */
-static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
- int amount_pull, struct napi_struct *napi)
+static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
+ int amount_pull, struct napi_struct *napi)
{
struct gfar_private *priv = netdev_priv(dev);
struct rxfcb *fcb = NULL;
@@ -2722,10 +2736,8 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
/* Send the packet up the stack */
ret = napi_gro_receive(napi, skb);
- if (GRO_DROP == ret)
- priv->extra_stats.kernel_dropped++;
-
- return 0;
+ if (unlikely(GRO_DROP == ret))
+ atomic64_inc(&priv->extra_stats.kernel_dropped);
}
/* gfar_clean_rx_ring() -- Processes each frame in the rx ring
@@ -2746,7 +2758,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
bdp = rx_queue->cur_rx;
base = rx_queue->rx_bd_base;
- amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0);
+ amount_pull = priv->uses_rxfcb ? GMAC_FCB_LEN : 0;
while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
struct sk_buff *newskb;
@@ -2758,7 +2770,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
skb = rx_queue->rx_skbuff[rx_queue->skb_currx];
- dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
+ dma_unmap_single(priv->dev, bdp->bufPtr,
priv->rx_buffer_size, DMA_FROM_DEVICE);
if (unlikely(!(bdp->status & RXBD_ERR) &&
@@ -2791,7 +2803,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
} else {
netif_warn(priv, rx_err, dev, "Missing skb!\n");
rx_queue->stats.rx_dropped++;
- priv->extra_stats.rx_skbmissing++;
+ atomic64_inc(&priv->extra_stats.rx_skbmissing);
}
}
@@ -3224,7 +3236,7 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
netif_dbg(priv, tx_err, dev,
"TX FIFO underrun, packet dropped\n");
dev->stats.tx_dropped++;
- priv->extra_stats.tx_underrun++;
+ atomic64_inc(&priv->extra_stats.tx_underrun);
local_irq_save(flags);
lock_tx_qs(priv);
@@ -3239,7 +3251,7 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
}
if (events & IEVENT_BSY) {
dev->stats.rx_errors++;
- priv->extra_stats.rx_bsy++;
+ atomic64_inc(&priv->extra_stats.rx_bsy);
gfar_receive(irq, grp_id);
@@ -3248,19 +3260,19 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
}
if (events & IEVENT_BABR) {
dev->stats.rx_errors++;
- priv->extra_stats.rx_babr++;
+ atomic64_inc(&priv->extra_stats.rx_babr);
netif_dbg(priv, rx_err, dev, "babbling RX error\n");
}
if (events & IEVENT_EBERR) {
- priv->extra_stats.eberr++;
+ atomic64_inc(&priv->extra_stats.eberr);
netif_dbg(priv, rx_err, dev, "bus error\n");
}
if (events & IEVENT_RXC)
netif_dbg(priv, rx_status, dev, "control frame\n");
if (events & IEVENT_BABT) {
- priv->extra_stats.tx_babt++;
+ atomic64_inc(&priv->extra_stats.tx_babt);
netif_dbg(priv, tx_err, dev, "babbling TX error\n");
}
return IRQ_HANDLED;
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 22eabc13ca99..63a28d294e20 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -627,36 +627,29 @@ struct rmon_mib
};
struct gfar_extra_stats {
- u64 kernel_dropped;
- u64 rx_large;
- u64 rx_short;
- u64 rx_nonoctet;
- u64 rx_crcerr;
- u64 rx_overrun;
- u64 rx_bsy;
- u64 rx_babr;
- u64 rx_trunc;
- u64 eberr;
- u64 tx_babt;
- u64 tx_underrun;
- u64 rx_skbmissing;
- u64 tx_timeout;
+ atomic64_t kernel_dropped;
+ atomic64_t rx_large;
+ atomic64_t rx_short;
+ atomic64_t rx_nonoctet;
+ atomic64_t rx_crcerr;
+ atomic64_t rx_overrun;
+ atomic64_t rx_bsy;
+ atomic64_t rx_babr;
+ atomic64_t rx_trunc;
+ atomic64_t eberr;
+ atomic64_t tx_babt;
+ atomic64_t tx_underrun;
+ atomic64_t rx_skbmissing;
+ atomic64_t tx_timeout;
};
#define GFAR_RMON_LEN ((sizeof(struct rmon_mib) - 16)/sizeof(u32))
-#define GFAR_EXTRA_STATS_LEN (sizeof(struct gfar_extra_stats)/sizeof(u64))
+#define GFAR_EXTRA_STATS_LEN \
+ (sizeof(struct gfar_extra_stats)/sizeof(atomic64_t))
-/* Number of stats in the stats structure (ignore car and cam regs)*/
+/* Number of stats exported via ethtool */
#define GFAR_STATS_LEN (GFAR_RMON_LEN + GFAR_EXTRA_STATS_LEN)
-#define GFAR_INFOSTR_LEN 32
-
-struct gfar_stats {
- u64 extra[GFAR_EXTRA_STATS_LEN];
- u64 rmon[GFAR_RMON_LEN];
-};
-
-
struct gfar {
u32 tsec_id; /* 0x.000 - Controller ID register */
u32 tsec_id2; /* 0x.004 - Controller ID2 register */
@@ -937,26 +930,25 @@ struct tx_q_stats {
* @txtime: coalescing value if based on time
*/
struct gfar_priv_tx_q {
+ /* cacheline 1 */
spinlock_t txlock __attribute__ ((aligned (SMP_CACHE_BYTES)));
- struct sk_buff ** tx_skbuff;
- /* Buffer descriptor pointers */
- dma_addr_t tx_bd_dma_base;
struct txbd8 *tx_bd_base;
struct txbd8 *cur_tx;
- struct txbd8 *dirty_tx;
+ unsigned int num_txbdfree;
+ unsigned short skb_curtx;
+ unsigned short tx_ring_size;
struct tx_q_stats stats;
- struct net_device *dev;
struct gfar_priv_grp *grp;
- u16 skb_curtx;
- u16 skb_dirtytx;
- u16 qindex;
- unsigned int tx_ring_size;
- unsigned int num_txbdfree;
+ /* cacheline 2 */
+ struct net_device *dev;
+ struct sk_buff **tx_skbuff;
+ struct txbd8 *dirty_tx;
+ unsigned short skb_dirtytx;
+ unsigned short qindex;
/* Configuration info for the coalescing features */
- unsigned char txcoalescing;
+ unsigned int txcoalescing;
unsigned long txic;
- unsigned short txcount;
- unsigned short txtime;
+ dma_addr_t tx_bd_dma_base;
};
/*
@@ -999,18 +991,25 @@ struct gfar_priv_rx_q {
unsigned long rxic;
};
+enum gfar_irqinfo_id {
+ GFAR_TX = 0,
+ GFAR_RX = 1,
+ GFAR_ER = 2,
+ GFAR_NUM_IRQS = 3
+};
+
+struct gfar_irqinfo {
+ unsigned int irq;
+ char name[GFAR_INT_NAME_MAX];
+};
+
/**
* struct gfar_priv_grp - per group structure
* @napi: the napi poll function
* @priv: back pointer to the priv structure
* @regs: the ioremapped register space for this group
* @grp_id: group id for this group
- * @interruptTransmit: The TX interrupt number for this group
- * @interruptReceive: The RX interrupt number for this group
- * @interruptError: The ERROR interrupt number for this group
- * @int_name_tx: tx interrupt name for this group
- * @int_name_rx: rx interrupt name for this group
- * @int_name_er: er interrupt name for this group
+ * @irqinfo: TX/RX/ER irq data for this group
*/
struct gfar_priv_grp {
@@ -1019,23 +1018,20 @@ struct gfar_priv_grp {
struct gfar_private *priv;
struct gfar __iomem *regs;
unsigned int grp_id;
- unsigned long rx_bit_map;
- unsigned long tx_bit_map;
- unsigned long num_tx_queues;
unsigned long num_rx_queues;
+ unsigned long rx_bit_map;
+ /* cacheline 3 */
unsigned int rstat;
unsigned int tstat;
- unsigned int imask;
- unsigned int ievent;
- unsigned int interruptTransmit;
- unsigned int interruptReceive;
- unsigned int interruptError;
-
- char int_name_tx[GFAR_INT_NAME_MAX];
- char int_name_rx[GFAR_INT_NAME_MAX];
- char int_name_er[GFAR_INT_NAME_MAX];
+ unsigned long num_tx_queues;
+ unsigned long tx_bit_map;
+
+ struct gfar_irqinfo *irqinfo[GFAR_NUM_IRQS];
};
+#define gfar_irq(grp, ID) \
+ ((grp)->irqinfo[GFAR_##ID])
+
enum gfar_errata {
GFAR_ERRATA_74 = 0x01,
GFAR_ERRATA_76 = 0x02,
@@ -1053,28 +1049,65 @@ enum gfar_errata {
* the buffer descriptor determines the actual condition.
*/
struct gfar_private {
-
- /* Indicates how many tx, rx queues are enabled */
- unsigned int num_tx_queues;
unsigned int num_rx_queues;
- unsigned int num_grps;
- unsigned int mode;
- /* The total tx and rx ring size for the enabled queues */
- unsigned int total_tx_ring_size;
- unsigned int total_rx_ring_size;
-
- struct device_node *node;
+ struct device *dev;
struct net_device *ndev;
- struct platform_device *ofdev;
enum gfar_errata errata;
+ unsigned int rx_buffer_size;
+
+ u16 uses_rxfcb;
+ u16 padding;
+
+ /* HW time stamping enabled flag */
+ int hwts_rx_en;
+ int hwts_tx_en;
- struct gfar_priv_grp gfargrp[MAXGROUPS];
struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];
struct gfar_priv_rx_q *rx_queue[MAX_RX_QS];
+ struct gfar_priv_grp gfargrp[MAXGROUPS];
+
+ u32 device_flags;
+
+ unsigned int mode;
+ unsigned int num_tx_queues;
+ unsigned int num_grps;
+
+ /* Network Statistics */
+ struct gfar_extra_stats extra_stats;
+
+ /* PHY stuff */
+ phy_interface_t interface;
+ struct device_node *phy_node;
+ struct device_node *tbi_node;
+ struct phy_device *phydev;
+ struct mii_bus *mii_bus;
+ int oldspeed;
+ int oldduplex;
+ int oldlink;
+
+ /* Bitfield update lock */
+ spinlock_t bflock;
+
+ uint32_t msg_enable;
+
+ struct work_struct reset_task;
+
+ struct platform_device *ofdev;
+ unsigned char
+ extended_hash:1,
+ bd_stash_en:1,
+ rx_filer_enable:1,
+ /* Wake-on-LAN enabled */
+ wol_en:1,
+ /* Enable priorty based Tx scheduling in Hw */
+ prio_sched_en:1;
+
+ /* The total tx and rx ring size for the enabled queues */
+ unsigned int total_tx_ring_size;
+ unsigned int total_rx_ring_size;
/* RX per device parameters */
- unsigned int rx_buffer_size;
unsigned int rx_stash_size;
unsigned int rx_stash_index;
@@ -1093,39 +1126,6 @@ struct gfar_private {
unsigned int fifo_starve;
unsigned int fifo_starve_off;
- /* Bitfield update lock */
- spinlock_t bflock;
-
- phy_interface_t interface;
- struct device_node *phy_node;
- struct device_node *tbi_node;
- u32 device_flags;
- unsigned char
- extended_hash:1,
- bd_stash_en:1,
- rx_filer_enable:1,
- wol_en:1, /* Wake-on-LAN enabled */
- prio_sched_en:1; /* Enable priorty based Tx scheduling in Hw */
- unsigned short padding;
-
- /* PHY stuff */
- struct phy_device *phydev;
- struct mii_bus *mii_bus;
- int oldspeed;
- int oldduplex;
- int oldlink;
-
- uint32_t msg_enable;
-
- struct work_struct reset_task;
-
- /* Network Statistics */
- struct gfar_extra_stats extra_stats;
-
- /* HW time stamping enabled flag */
- int hwts_rx_en;
- int hwts_tx_en;
-
/*Filer table*/
unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
@@ -1138,16 +1138,16 @@ static inline int gfar_has_errata(struct gfar_private *priv,
return priv->errata & err;
}
-static inline u32 gfar_read(volatile unsigned __iomem *addr)
+static inline u32 gfar_read(unsigned __iomem *addr)
{
u32 val;
- val = in_be32(addr);
+ val = ioread32be(addr);
return val;
}
-static inline void gfar_write(volatile unsigned __iomem *addr, u32 val)
+static inline void gfar_write(unsigned __iomem *addr, u32 val)
{
- out_be32(addr, val);
+ iowrite32be(val, addr);
}
static inline void gfar_write_filer(struct gfar_private *priv,
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index ab6762caa957..75e89acf4912 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -149,20 +149,17 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
int i;
struct gfar_private *priv = netdev_priv(dev);
struct gfar __iomem *regs = priv->gfargrp[0].regs;
- u64 *extra = (u64 *) & priv->extra_stats;
+ atomic64_t *extra = (atomic64_t *)&priv->extra_stats;
+
+ for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+ buf[i] = atomic64_read(&extra[i]);
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
u32 __iomem *rmon = (u32 __iomem *) &regs->rmon;
- struct gfar_stats *stats = (struct gfar_stats *) buf;
-
- for (i = 0; i < GFAR_RMON_LEN; i++)
- stats->rmon[i] = (u64) gfar_read(&rmon[i]);
- for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
- stats->extra[i] = extra[i];
- } else
- for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
- buf[i] = extra[i];
+ for (; i < GFAR_STATS_LEN; i++, rmon++)
+ buf[i] = (u64) gfar_read(rmon);
+ }
}
static int gfar_sset_count(struct net_device *dev, int sset)
@@ -184,10 +181,11 @@ static int gfar_sset_count(struct net_device *dev, int sset)
static void gfar_gdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *drvinfo)
{
- strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
- strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN);
- strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN);
- strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN);
+ strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, gfar_driver_version,
+ sizeof(drvinfo->version));
+ strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info));
drvinfo->regdump_len = 0;
drvinfo->eedump_len = 0;
}
@@ -715,12 +713,11 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow,
int j = MAX_FILER_IDX, l = 0x0;
int ret = 1;
- local_rqfpr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
- GFP_KERNEL);
- local_rqfcr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
- GFP_KERNEL);
+ local_rqfpr = kmalloc_array(MAX_FILER_IDX + 1, sizeof(unsigned int),
+ GFP_KERNEL);
+ local_rqfcr = kmalloc_array(MAX_FILER_IDX + 1, sizeof(unsigned int),
+ GFP_KERNEL);
if (!local_rqfpr || !local_rqfcr) {
- pr_err("Out of memory\n");
ret = 0;
goto err;
}
diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
index 37b035306013..1ebf7128ec04 100644
--- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
+++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
@@ -350,10 +350,10 @@ static void
uec_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
- strncpy(drvinfo->driver, DRV_NAME, 32);
- strncpy(drvinfo->version, DRV_VERSION, 32);
- strncpy(drvinfo->fw_version, "N/A", 32);
- strncpy(drvinfo->bus_info, "QUICC ENGINE", 32);
+ strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+ strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strlcpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info));
drvinfo->eedump_len = 0;
drvinfo->regdump_len = uec_get_regs_len(netdev);
}
diff --git a/drivers/net/ethernet/fujitsu/Kconfig b/drivers/net/ethernet/fujitsu/Kconfig
index dffee9d44fd5..6231bc02b964 100644
--- a/drivers/net/ethernet/fujitsu/Kconfig
+++ b/drivers/net/ethernet/fujitsu/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_FUJITSU
bool "Fujitsu devices"
default y
- depends on ISA || PCMCIA || ((ISA || MCA_LEGACY) && EXPERIMENTAL)
+ depends on ISA || PCMCIA
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -17,18 +17,6 @@ config NET_VENDOR_FUJITSU
if NET_VENDOR_FUJITSU
-config AT1700
- tristate "AT1700/1720 support (EXPERIMENTAL)"
- depends on (ISA || MCA_LEGACY) && EXPERIMENTAL
- select CRC32
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called at1700.
-
config PCMCIA_FMVJ18X
tristate "Fujitsu FMV-J18x PCMCIA support"
depends on PCMCIA
@@ -40,15 +28,4 @@ config PCMCIA_FMVJ18X
To compile this driver as a module, choose M here: the module will be
called fmvj18x_cs. If unsure, say N.
-config ETH16I
- tristate "ICL EtherTeam 16i/32 support"
- depends on ISA
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called eth16i.
-
endif # NET_VENDOR_FUJITSU
diff --git a/drivers/net/ethernet/fujitsu/Makefile b/drivers/net/ethernet/fujitsu/Makefile
index 2730ae67d3aa..21561fdcc69f 100644
--- a/drivers/net/ethernet/fujitsu/Makefile
+++ b/drivers/net/ethernet/fujitsu/Makefile
@@ -2,6 +2,4 @@
# Makefile for the Fujitsu network device drivers.
#
-obj-$(CONFIG_AT1700) += at1700.o
-obj-$(CONFIG_ETH16I) += eth16i.o
obj-$(CONFIG_PCMCIA_FMVJ18X) += fmvj18x_cs.o
diff --git a/drivers/net/ethernet/fujitsu/at1700.c b/drivers/net/ethernet/fujitsu/at1700.c
deleted file mode 100644
index 4b80dc4531ad..000000000000
--- a/drivers/net/ethernet/fujitsu/at1700.c
+++ /dev/null
@@ -1,791 +0,0 @@
-/* at1700.c: A network device driver for the Allied Telesis AT1700.
-
- Written 1993-98 by Donald Becker.
-
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- This is a device driver for the Allied Telesis AT1700, and
- Fujitsu FMV-181/182/181A/182A/183/184/183A/184A, which are
- straight-forward Fujitsu MB86965 implementations.
-
- Modification for Fujitsu FMV-18X cards is done by Yutaka Tamiya
- (tamy@flab.fujitsu.co.jp).
-
- Sources:
- The Fujitsu MB86965 datasheet.
-
- After the initial version of this driver was written Gerry Sawkins of
- ATI provided their EEPROM configuration code header file.
- Thanks to NIIBE Yutaka <gniibe@mri.co.jp> for bug fixes.
-
- MCA bus (AT1720) support (now deleted) by Rene Schmit <rene@bss.lu>
-
- Bugs:
- The MB86965 has a design flaw that makes all probes unreliable. Not
- only is it difficult to detect, it also moves around in I/O space in
- response to inb()s from other device probes!
-*/
-
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/skbuff.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-static char version[] __initdata =
- "at1700.c:v1.16 9/11/06 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#define DRV_NAME "at1700"
-
-/* Tunable parameters. */
-
-/* When to switch from the 64-entry multicast filter to Rx-all-multicast. */
-#define MC_FILTERBREAK 64
-
-/* These unusual address orders are used to verify the CONFIG register. */
-
-static int fmv18x_probe_list[] __initdata = {
- 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0
-};
-
-/*
- * ISA
- */
-
-static unsigned at1700_probe_list[] __initdata = {
- 0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
-};
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-typedef unsigned char uchar;
-
-/* Information that need to be kept for each board. */
-struct net_local {
- spinlock_t lock;
- unsigned char mc_filter[8];
- uint jumpered:1; /* Set iff the board has jumper config. */
- uint tx_started:1; /* Packets are on the Tx queue. */
- uint tx_queue_ready:1; /* Tx queue is ready to be sent. */
- uint rx_started:1; /* Packets are Rxing. */
- uchar tx_queue; /* Number of packet on the Tx queue. */
- ushort tx_queue_len; /* Current length of the Tx queue. */
-};
-
-
-/* Offsets from the base address. */
-#define STATUS 0
-#define TX_STATUS 0
-#define RX_STATUS 1
-#define TX_INTR 2 /* Bit-mapped interrupt enable registers. */
-#define RX_INTR 3
-#define TX_MODE 4
-#define RX_MODE 5
-#define CONFIG_0 6 /* Misc. configuration settings. */
-#define CONFIG_1 7
-/* Run-time register bank 2 definitions. */
-#define DATAPORT 8 /* Word-wide DMA or programmed-I/O dataport. */
-#define TX_START 10
-#define COL16CNTL 11 /* Control Reg for 16 collisions */
-#define MODE13 13
-#define RX_CTRL 14
-/* Configuration registers only on the '865A/B chips. */
-#define EEPROM_Ctrl 16
-#define EEPROM_Data 17
-#define CARDSTATUS 16 /* FMV-18x Card Status */
-#define CARDSTATUS1 17 /* FMV-18x Card Status */
-#define IOCONFIG 18 /* Either read the jumper, or move the I/O. */
-#define IOCONFIG1 19
-#define SAPROM 20 /* The station address PROM, if no EEPROM. */
-#define MODE24 24
-#define RESET 31 /* Write to reset some parts of the chip. */
-#define AT1700_IO_EXTENT 32
-#define PORT_OFFSET(o) (o)
-
-
-#define TX_TIMEOUT (HZ/10)
-
-
-/* Index to functions, as function prototypes. */
-
-static int at1700_probe1(struct net_device *dev, int ioaddr);
-static int read_eeprom(long ioaddr, int location);
-static int net_open(struct net_device *dev);
-static netdev_tx_t net_send_packet(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id);
-static void net_rx(struct net_device *dev);
-static int net_close(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static void net_tx_timeout (struct net_device *dev);
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
- If dev->base_addr == 0, probe all likely locations.
- If dev->base_addr == 1, always return failure.
- If dev->base_addr == 2, allocate space for the device and return success
- (detachable devices only).
- */
-
-static int io = 0x260;
-
-static int irq;
-
-static void cleanup_card(struct net_device *dev)
-{
- free_irq(dev->irq, NULL);
- release_region(dev->base_addr, AT1700_IO_EXTENT);
-}
-
-struct net_device * __init at1700_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- unsigned *port;
- int err = 0;
-
- if (!dev)
- return ERR_PTR(-ENODEV);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
- } else {
- dev->base_addr = io;
- dev->irq = irq;
- }
-
- if (io > 0x1ff) { /* Check a single specified location. */
- err = at1700_probe1(dev, io);
- } else if (io != 0) { /* Don't probe at all. */
- err = -ENXIO;
- } else {
- for (port = at1700_probe_list; *port; port++) {
- if (at1700_probe1(dev, *port) == 0)
- break;
- dev->irq = irq;
- }
- if (!*port)
- err = -ENODEV;
- }
- if (err)
- goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
-out1:
- cleanup_card(dev);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static const struct net_device_ops at1700_netdev_ops = {
- .ndo_open = net_open,
- .ndo_stop = net_close,
- .ndo_start_xmit = net_send_packet,
- .ndo_set_rx_mode = set_rx_mode,
- .ndo_tx_timeout = net_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/* The Fujitsu datasheet suggests that the NIC be probed for by checking its
- "signature", the default bit pattern after a reset. This *doesn't* work --
- there is no way to reset the bus interface without a complete power-cycle!
-
- It turns out that ATI came to the same conclusion I did: the only thing
- that can be done is checking a few bits and then diving right into an
- EEPROM read. */
-
-static int __init at1700_probe1(struct net_device *dev, int ioaddr)
-{
- static const char fmv_irqmap[4] = {3, 7, 10, 15};
- static const char fmv_irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
- static const char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
- unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
- int ret = -ENODEV;
- struct net_local *lp = netdev_priv(dev);
-
- if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME))
- return -EBUSY;
-
- /* Resetting the chip doesn't reset the ISA interface, so don't bother.
- That means we have to be careful with the register values we probe
- for.
- */
-#ifdef notdef
- printk("at1700 probe at %#x, eeprom is %4.4x %4.4x %4.4x ctrl %4.4x.\n",
- ioaddr, read_eeprom(ioaddr, 4), read_eeprom(ioaddr, 5),
- read_eeprom(ioaddr, 6), inw(ioaddr + EEPROM_Ctrl));
-#endif
- /* We must check for the EEPROM-config boards first, else accessing
- IOCONFIG0 will move the board! */
- if (at1700_probe_list[inb(ioaddr + IOCONFIG1) & 0x07] == ioaddr &&
- read_eeprom(ioaddr, 4) == 0x0000 &&
- (read_eeprom(ioaddr, 5) & 0xff00) == 0xF400)
- is_at1700 = 1;
- else if (inb(ioaddr + SAPROM ) == 0x00 &&
- inb(ioaddr + SAPROM + 1) == 0x00 &&
- inb(ioaddr + SAPROM + 2) == 0x0e)
- is_fmv18x = 1;
- else {
- goto err_out;
- }
-
- /* Reset the internal state machines. */
- outb(0, ioaddr + RESET);
-
- if (is_at1700) {
- irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04)
- | (read_eeprom(ioaddr, 0)>>14)];
- } else {
- /* Check PnP mode for FMV-183/184/183A/184A. */
- /* This PnP routine is very poor. IO and IRQ should be known. */
- if (inb(ioaddr + CARDSTATUS1) & 0x20) {
- irq = dev->irq;
- for (i = 0; i < 8; i++) {
- if (irq == fmv_irqmap_pnp[i])
- break;
- }
- if (i == 8) {
- goto err_out;
- }
- } else {
- if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr)
- goto err_out;
- irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03];
- }
- }
-
- printk("%s: %s found at %#3x, IRQ %d, address ", dev->name,
- is_at1700 ? "AT1700" : "FMV-18X", ioaddr, irq);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
- if (is_at1700) {
- for(i = 0; i < 3; i++) {
- unsigned short eeprom_val = read_eeprom(ioaddr, 4+i);
- ((unsigned short *)dev->dev_addr)[i] = ntohs(eeprom_val);
- }
- } else {
- for(i = 0; i < 6; i++) {
- unsigned char val = inb(ioaddr + SAPROM + i);
- dev->dev_addr[i] = val;
- }
- }
- printk("%pM", dev->dev_addr);
-
- /* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
- rather than 150 ohm shielded twisted pair compensation.
- 0x0000 == auto-sense the interface
- 0x0800 == use TP interface
- 0x1800 == use coax interface
- */
- {
- const char *porttype[] = {"auto-sense", "10baseT", "auto-sense", "10base2"};
- if (is_at1700) {
- ushort setup_value = read_eeprom(ioaddr, 12);
- dev->if_port = setup_value >> 8;
- } else {
- ushort setup_value = inb(ioaddr + CARDSTATUS);
- switch (setup_value & 0x07) {
- case 0x01: /* 10base5 */
- case 0x02: /* 10base2 */
- dev->if_port = 0x18; break;
- case 0x04: /* 10baseT */
- dev->if_port = 0x08; break;
- default: /* auto-sense */
- dev->if_port = 0x00; break;
- }
- }
- printk(" %s interface.\n", porttype[(dev->if_port>>3) & 3]);
- }
-
- /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit
- bus access, two 4K Tx queues, and disabled Tx and Rx. */
- outb(0xda, ioaddr + CONFIG_0);
-
- /* Set the station address in bank zero. */
- outb(0x00, ioaddr + CONFIG_1);
- for (i = 0; i < 6; i++)
- outb(dev->dev_addr[i], ioaddr + PORT_OFFSET(8 + i));
-
- /* Switch to bank 1 and set the multicast table to accept none. */
- outb(0x04, ioaddr + CONFIG_1);
- for (i = 0; i < 8; i++)
- outb(0x00, ioaddr + PORT_OFFSET(8 + i));
-
-
- /* Switch to bank 2 */
- /* Lock our I/O address, and set manual processing mode for 16 collisions. */
- outb(0x08, ioaddr + CONFIG_1);
- outb(dev->if_port, ioaddr + MODE13);
- outb(0x00, ioaddr + COL16CNTL);
-
- if (net_debug)
- printk(version);
-
- dev->netdev_ops = &at1700_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- spin_lock_init(&lp->lock);
-
- lp->jumpered = is_fmv18x;
- /* Snarf the interrupt vector now. */
- ret = request_irq(irq, net_interrupt, 0, DRV_NAME, dev);
- if (ret) {
- printk(KERN_ERR "AT1700 at %#3x is unusable due to a "
- "conflict on IRQ %d.\n",
- ioaddr, irq);
- goto err_out;
- }
-
- return 0;
-
-err_out:
- release_region(ioaddr, AT1700_IO_EXTENT);
- return ret;
-}
-
-
-/* EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK 0x40 /* EEPROM shift clock, in reg. 16. */
-#define EE_CS 0x20 /* EEPROM chip select, in reg. 16. */
-#define EE_DATA_WRITE 0x80 /* EEPROM chip data in, in reg. 17. */
-#define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD (5 << 6)
-#define EE_READ_CMD (6 << 6)
-#define EE_ERASE_CMD (7 << 6)
-
-static int __init read_eeprom(long ioaddr, int location)
-{
- int i;
- unsigned short retval = 0;
- long ee_addr = ioaddr + EEPROM_Ctrl;
- long ee_daddr = ioaddr + EEPROM_Data;
- int read_cmd = location | EE_READ_CMD;
-
- /* Shift the read command bits out. */
- for (i = 9; i >= 0; i--) {
- short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
- outb(EE_CS, ee_addr);
- outb(dataval, ee_daddr);
- outb(EE_CS | EE_SHIFT_CLK, ee_addr); /* EEPROM clock tick. */
- }
- outb(EE_DATA_WRITE, ee_daddr);
- for (i = 16; i > 0; i--) {
- outb(EE_CS, ee_addr);
- outb(EE_CS | EE_SHIFT_CLK, ee_addr);
- retval = (retval << 1) | ((inb(ee_daddr) & EE_DATA_READ) ? 1 : 0);
- }
-
- /* Terminate the EEPROM access. */
- outb(EE_CS, ee_addr);
- outb(EE_SHIFT_CLK, ee_addr);
- outb(0, ee_addr);
- return retval;
-}
-
-
-
-static int net_open(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit
- bus access, and two 4K Tx queues. */
- outb(0x5a, ioaddr + CONFIG_0);
-
- /* Powerup, switch to register bank 2, and enable the Rx and Tx. */
- outb(0xe8, ioaddr + CONFIG_1);
-
- lp->tx_started = 0;
- lp->tx_queue_ready = 1;
- lp->rx_started = 0;
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
-
- /* Turn on hardware Tx and Rx interrupts. */
- outb(0x82, ioaddr + TX_INTR);
- outb(0x81, ioaddr + RX_INTR);
-
- /* Enable the IRQ on boards of fmv18x it is feasible. */
- if (lp->jumpered) {
- outb(0x80, ioaddr + IOCONFIG1);
- }
-
- netif_start_queue(dev);
- return 0;
-}
-
-static void net_tx_timeout (struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- printk ("%s: transmit timed out with status %04x, %s?\n", dev->name,
- inw (ioaddr + STATUS), inb (ioaddr + TX_STATUS) & 0x80
- ? "IRQ conflict" : "network cable problem");
- printk ("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
- dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE),
- inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START),
- inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL));
- dev->stats.tx_errors++;
- /* ToDo: We should try to restart the adaptor... */
- outw(0xffff, ioaddr + MODE24);
- outw (0xffff, ioaddr + TX_STATUS);
- outb (0x5a, ioaddr + CONFIG_0);
- outb (0xe8, ioaddr + CONFIG_1);
- outw (0x8182, ioaddr + TX_INTR);
- outb (0x00, ioaddr + TX_START);
- outb (0x03, ioaddr + COL16CNTL);
-
- dev->trans_start = jiffies; /* prevent tx timeout */
-
- lp->tx_started = 0;
- lp->tx_queue_ready = 1;
- lp->rx_started = 0;
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
-
- netif_wake_queue(dev);
-}
-
-
-static netdev_tx_t net_send_packet (struct sk_buff *skb,
- struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- short len = skb->len;
- unsigned char *buf = skb->data;
- static u8 pad[ETH_ZLEN];
-
- netif_stop_queue (dev);
-
- /* We may not start transmitting unless we finish transferring
- a packet into the Tx queue. During executing the following
- codes we possibly catch a Tx interrupt. Thus we flag off
- tx_queue_ready, so that we prevent the interrupt routine
- (net_interrupt) to start transmitting. */
- lp->tx_queue_ready = 0;
- {
- outw (length, ioaddr + DATAPORT);
- /* Packet data */
- outsw (ioaddr + DATAPORT, buf, len >> 1);
- /* Check for dribble byte */
- if (len & 1) {
- outw(skb->data[skb->len-1], ioaddr + DATAPORT);
- len++;
- }
- /* Check for packet padding */
- if (length != skb->len)
- outsw(ioaddr + DATAPORT, pad, (length - len + 1) >> 1);
-
- lp->tx_queue++;
- lp->tx_queue_len += length + 2;
- }
- lp->tx_queue_ready = 1;
-
- if (lp->tx_started == 0) {
- /* If the Tx is idle, always trigger a transmit. */
- outb (0x80 | lp->tx_queue, ioaddr + TX_START);
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- lp->tx_started = 1;
- netif_start_queue (dev);
- } else if (lp->tx_queue_len < 4096 - 1502)
- /* Yes, there is room for one more packet. */
- netif_start_queue (dev);
- dev_kfree_skb (skb);
-
- return NETDEV_TX_OK;
-}
-
-/* The typical workload of the driver:
- Handle the network interface interrupts. */
-static irqreturn_t net_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct net_local *lp;
- int ioaddr, status;
- int handled = 0;
-
- if (dev == NULL) {
- printk ("at1700_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
- ioaddr = dev->base_addr;
- lp = netdev_priv(dev);
-
- spin_lock (&lp->lock);
-
- status = inw(ioaddr + TX_STATUS);
- outw(status, ioaddr + TX_STATUS);
-
- if (net_debug > 4)
- printk("%s: Interrupt with status %04x.\n", dev->name, status);
- if (lp->rx_started == 0 &&
- (status & 0xff00 || (inb(ioaddr + RX_MODE) & 0x40) == 0)) {
- /* Got a packet(s).
- We cannot execute net_rx more than once at the same time for
- the same device. During executing net_rx, we possibly catch a
- Tx interrupt. Thus we flag on rx_started, so that we prevent
- the interrupt routine (net_interrupt) to dive into net_rx
- again. */
- handled = 1;
- lp->rx_started = 1;
- outb(0x00, ioaddr + RX_INTR); /* Disable RX intr. */
- net_rx(dev);
- outb(0x81, ioaddr + RX_INTR); /* Enable RX intr. */
- lp->rx_started = 0;
- }
- if (status & 0x00ff) {
- handled = 1;
- if (status & 0x02) {
- /* More than 16 collisions occurred */
- if (net_debug > 4)
- printk("%s: 16 Collision occur during Txing.\n", dev->name);
- /* Cancel sending a packet. */
- outb(0x03, ioaddr + COL16CNTL);
- dev->stats.collisions++;
- }
- if (status & 0x82) {
- dev->stats.tx_packets++;
- /* The Tx queue has any packets and is not being
- transferred a packet from the host, start
- transmitting. */
- if (lp->tx_queue && lp->tx_queue_ready) {
- outb(0x80 | lp->tx_queue, ioaddr + TX_START);
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- dev->trans_start = jiffies;
- netif_wake_queue (dev);
- } else {
- lp->tx_started = 0;
- netif_wake_queue (dev);
- }
- }
- }
-
- spin_unlock (&lp->lock);
- return IRQ_RETVAL(handled);
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_rx(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- int boguscount = 5;
-
- while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {
- ushort status = inw(ioaddr + DATAPORT);
- ushort pkt_len = inw(ioaddr + DATAPORT);
-
- if (net_debug > 4)
- printk("%s: Rxing packet mode %02x status %04x.\n",
- dev->name, inb(ioaddr + RX_MODE), status);
-#ifndef final_version
- if (status == 0) {
- outb(0x05, ioaddr + RX_CTRL);
- break;
- }
-#endif
-
- if ((status & 0xF0) != 0x20) { /* There was an error. */
- dev->stats.rx_errors++;
- if (status & 0x08) dev->stats.rx_length_errors++;
- if (status & 0x04) dev->stats.rx_frame_errors++;
- if (status & 0x02) dev->stats.rx_crc_errors++;
- if (status & 0x01) dev->stats.rx_over_errors++;
- } else {
- /* Malloc up new buffer. */
- struct sk_buff *skb;
-
- if (pkt_len > 1550) {
- printk("%s: The AT1700 claimed a very large packet, size %d.\n",
- dev->name, pkt_len);
- /* Prime the FIFO and then flush the packet. */
- inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
- outb(0x05, ioaddr + RX_CTRL);
- dev->stats.rx_errors++;
- break;
- }
- skb = netdev_alloc_skb(dev, pkt_len + 3);
- if (skb == NULL) {
- printk("%s: Memory squeeze, dropping packet (len %d).\n",
- dev->name, pkt_len);
- /* Prime the FIFO and then flush the packet. */
- inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
- outb(0x05, ioaddr + RX_CTRL);
- dev->stats.rx_dropped++;
- break;
- }
- skb_reserve(skb,2);
-
- insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);
- skb->protocol=eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
- if (--boguscount <= 0)
- break;
- }
-
- /* If any worth-while packets have been received, dev_rint()
- has done a mark_bh(NET_BH) for us and will work on them
- when we get to the bottom-half routine. */
- {
- int i;
- for (i = 0; i < 20; i++) {
- if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)
- break;
- inw(ioaddr + DATAPORT); /* dummy status read */
- outb(0x05, ioaddr + RX_CTRL);
- }
-
- if (net_debug > 5)
- printk("%s: Exint Rx packet with mode %02x after %d ticks.\n",
- dev->name, inb(ioaddr + RX_MODE), i);
- }
-}
-
-/* The inverse routine to net_open(). */
-static int net_close(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- netif_stop_queue(dev);
-
- /* Set configuration register 0 to disable Tx and Rx. */
- outb(0xda, ioaddr + CONFIG_0);
-
- /* No statistic counters on the chip to update. */
-
- /* Disable the IRQ on boards of fmv18x where it is feasible. */
- if (lp->jumpered)
- outb(0x00, ioaddr + IOCONFIG1);
-
- /* Power-down the chip. Green, green, green! */
- outb(0x00, ioaddr + CONFIG_1);
- return 0;
-}
-
-/*
- Set the multicast/promiscuous mode for this adaptor.
-*/
-
-static void
-set_rx_mode(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- struct net_local *lp = netdev_priv(dev);
- unsigned char mc_filter[8]; /* Multicast hash filter */
- unsigned long flags;
-
- if (dev->flags & IFF_PROMISC) {
- memset(mc_filter, 0xff, sizeof(mc_filter));
- outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */
- } else if (netdev_mc_count(dev) > MC_FILTERBREAK ||
- (dev->flags & IFF_ALLMULTI)) {
- /* Too many to filter perfectly -- accept all multicasts. */
- memset(mc_filter, 0xff, sizeof(mc_filter));
- outb(2, ioaddr + RX_MODE); /* Use normal mode. */
- } else if (netdev_mc_empty(dev)) {
- memset(mc_filter, 0x00, sizeof(mc_filter));
- outb(1, ioaddr + RX_MODE); /* Ignore almost all multicasts. */
- } else {
- struct netdev_hw_addr *ha;
-
- memset(mc_filter, 0, sizeof(mc_filter));
- netdev_for_each_mc_addr(ha, dev) {
- unsigned int bit =
- ether_crc_le(ETH_ALEN, ha->addr) >> 26;
- mc_filter[bit >> 3] |= (1 << bit);
- }
- outb(0x02, ioaddr + RX_MODE); /* Use normal mode. */
- }
-
- spin_lock_irqsave (&lp->lock, flags);
- if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
- int i;
- int saved_bank = inw(ioaddr + CONFIG_0);
- /* Switch to bank 1 and set the multicast table. */
- outw((saved_bank & ~0x0C00) | 0x0480, ioaddr + CONFIG_0);
- for (i = 0; i < 8; i++)
- outb(mc_filter[i], ioaddr + PORT_OFFSET(8 + i));
- memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
- outw(saved_bank, ioaddr + CONFIG_0);
- }
- spin_unlock_irqrestore (&lp->lock, flags);
-}
-
-#ifdef MODULE
-static struct net_device *dev_at1700;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(net_debug, int, 0);
-MODULE_PARM_DESC(io, "AT1700/FMV18X I/O base address");
-MODULE_PARM_DESC(irq, "AT1700/FMV18X IRQ number");
-MODULE_PARM_DESC(net_debug, "AT1700/FMV18X debug level (0-6)");
-
-static int __init at1700_module_init(void)
-{
- if (io == 0)
- printk("at1700: You should not use auto-probing with insmod!\n");
- dev_at1700 = at1700_probe(-1);
- if (IS_ERR(dev_at1700))
- return PTR_ERR(dev_at1700);
- return 0;
-}
-
-static void __exit at1700_module_exit(void)
-{
- unregister_netdev(dev_at1700);
- cleanup_card(dev_at1700);
- free_netdev(dev_at1700);
-}
-module_init(at1700_module_init);
-module_exit(at1700_module_exit);
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/fujitsu/eth16i.c b/drivers/net/ethernet/fujitsu/eth16i.c
deleted file mode 100644
index a992d1f7e0d2..000000000000
--- a/drivers/net/ethernet/fujitsu/eth16i.c
+++ /dev/null
@@ -1,1483 +0,0 @@
-/* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
-
- Written 1994-1999 by Mika Kuoppala
-
- Copyright (C) 1994-1999 by Mika Kuoppala
- Based on skeleton.c and heavily on at1700.c by Donald Becker
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- The author may be reached as miku@iki.fi
-
- This driver supports following cards :
- - ICL EtherTeam 16i
- - ICL EtherTeam 32 EISA
- (Uses true 32 bit transfers rather than 16i compatibility mode)
-
- Example Module usage:
- insmod eth16i.o io=0x2a0 mediatype=bnc
-
- mediatype can be one of the following: bnc,tp,dix,auto,eprom
-
- 'auto' will try to autoprobe mediatype.
- 'eprom' will use whatever type defined in eprom.
-
- I have benchmarked driver with PII/300Mhz as a ftp client
- and 486/33Mhz as a ftp server. Top speed was 1128.37 kilobytes/sec.
-
- Sources:
- - skeleton.c a sample network driver core for linux,
- written by Donald Becker <becker@scyld.com>
- - at1700.c a driver for Allied Telesis AT1700, written
- by Donald Becker.
- - e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i
- written by Markku Viima
- - The Fujitsu MB86965 databook.
-
- Author thanks following persons due to their valueble assistance:
- Markku Viima (ICL)
- Ari Valve (ICL)
- Donald Becker
- Kurt Huwig <kurt@huwig.de>
-
- Revision history:
-
- Version Date Description
-
- 0.01 15.12-94 Initial version (card detection)
- 0.02 23.01-95 Interrupt is now hooked correctly
- 0.03 01.02-95 Rewrote initialization part
- 0.04 07.02-95 Base skeleton done...
- Made a few changes to signature checking
- to make it a bit reliable.
- - fixed bug in tx_buf mapping
- - fixed bug in initialization (DLC_EN
- wasn't enabled when initialization
- was done.)
- 0.05 08.02-95 If there were more than one packet to send,
- transmit was jammed due to invalid
- register write...now fixed
- 0.06 19.02-95 Rewrote interrupt handling
- 0.07 13.04-95 Wrote EEPROM read routines
- Card configuration now set according to
- data read from EEPROM
- 0.08 23.06-95 Wrote part that tries to probe used interface
- port if AUTO is selected
-
- 0.09 01.09-95 Added module support
-
- 0.10 04.09-95 Fixed receive packet allocation to work
- with kernels > 1.3.x
-
- 0.20 20.09-95 Added support for EtherTeam32 EISA
-
- 0.21 17.10-95 Removed the unnecessary extern
- init_etherdev() declaration. Some
- other cleanups.
-
- 0.22 22.02-96 Receive buffer was not flushed
- correctly when faulty packet was
- received. Now fixed.
-
- 0.23 26.02-96 Made resetting the adapter
- more reliable.
-
- 0.24 27.02-96 Rewrote faulty packet handling in eth16i_rx
-
- 0.25 22.05-96 kfree() was missing from cleanup_module.
-
- 0.26 11.06-96 Sometimes card was not found by
- check_signature(). Now made more reliable.
-
- 0.27 23.06-96 Oops. 16 consecutive collisions halted
- adapter. Now will try to retransmit
- MAX_COL_16 times before finally giving up.
-
- 0.28 28.10-97 Added dev_id parameter (NULL) for free_irq
-
- 0.29 29.10-97 Multiple card support for module users
-
- 0.30 30.10-97 Fixed irq allocation bug.
- (request_irq moved from probe to open)
-
- 0.30a 21.08-98 Card detection made more relaxed. Driver
- had problems with some TCP/IP-PROM boots
- to find the card. Suggested by
- Kurt Huwig <kurt@huwig.de>
-
- 0.31 28.08-98 Media interface port can now be selected
- with module parameters or kernel
- boot parameters.
-
- 0.32 31.08-98 IRQ was never freed if open/close
- pair wasn't called. Now fixed.
-
- 0.33 10.09-98 When eth16i_open() was called after
- eth16i_close() chip never recovered.
- Now more shallow reset is made on
- close.
-
- 0.34 29.06-99 Fixed one bad #ifdef.
- Changed ioaddr -> io for consistency
-
- 0.35 01.07-99 transmit,-receive bytes were never
- updated in stats.
-
- Bugs:
- In some cases the media interface autoprobing code doesn't find
- the correct interface type. In this case you can
- manually choose the interface type in DOS with E16IC.EXE which is
- configuration software for EtherTeam16i and EtherTeam32 cards.
- This is also true for IRQ setting. You cannot use module
- parameter to configure IRQ of the card (yet).
-
- To do:
- - Real multicast support
- - Rewrite the media interface autoprobing code. Its _horrible_ !
- - Possibly merge all the MB86965 specific code to external
- module for use by eth16.c and Donald's at1700.c
- - IRQ configuration with module parameter. I will do
- this when i will get enough info about setting
- irq without configuration utility.
-*/
-
-static char *version =
- "eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku@iki.fi)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-#include <linux/io.h>
-
-#include <asm/dma.h>
-
-
-
-/* Few macros */
-#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
-#define BITCLR(ioaddr, bnum) ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr)))
-
-/* This is the I/O address space for Etherteam 16i adapter. */
-#define ETH16I_IO_EXTENT 32
-
-/* Ticks before deciding that transmit has timed out */
-#define TX_TIMEOUT (400*HZ/1000)
-
-/* Maximum loop count when receiving packets */
-#define MAX_RX_LOOP 20
-
-/* Some interrupt masks */
-#define ETH16I_INTR_ON 0xef8a /* Higher is receive mask */
-#define ETH16I_INTR_OFF 0x0000
-
-/* Buffers header status byte meanings */
-#define PKT_GOOD BIT(5)
-#define PKT_GOOD_RMT BIT(4)
-#define PKT_SHORT BIT(3)
-#define PKT_ALIGN_ERR BIT(2)
-#define PKT_CRC_ERR BIT(1)
-#define PKT_RX_BUF_OVERFLOW BIT(0)
-
-/* Transmit status register (DLCR0) */
-#define TX_STATUS_REG 0
-#define TX_DONE BIT(7)
-#define NET_BUSY BIT(6)
-#define TX_PKT_RCD BIT(5)
-#define CR_LOST BIT(4)
-#define TX_JABBER_ERR BIT(3)
-#define COLLISION BIT(2)
-#define COLLISIONS_16 BIT(1)
-
-/* Receive status register (DLCR1) */
-#define RX_STATUS_REG 1
-#define RX_PKT BIT(7) /* Packet received */
-#define BUS_RD_ERR BIT(6)
-#define SHORT_PKT_ERR BIT(3)
-#define ALIGN_ERR BIT(2)
-#define CRC_ERR BIT(1)
-#define RX_BUF_OVERFLOW BIT(0)
-
-/* Transmit Interrupt Enable Register (DLCR2) */
-#define TX_INTR_REG 2
-#define TX_INTR_DONE BIT(7)
-#define TX_INTR_COL BIT(2)
-#define TX_INTR_16_COL BIT(1)
-
-/* Receive Interrupt Enable Register (DLCR3) */
-#define RX_INTR_REG 3
-#define RX_INTR_RECEIVE BIT(7)
-#define RX_INTR_SHORT_PKT BIT(3)
-#define RX_INTR_CRC_ERR BIT(1)
-#define RX_INTR_BUF_OVERFLOW BIT(0)
-
-/* Transmit Mode Register (DLCR4) */
-#define TRANSMIT_MODE_REG 4
-#define LOOPBACK_CONTROL BIT(1)
-#define CONTROL_OUTPUT BIT(2)
-
-/* Receive Mode Register (DLCR5) */
-#define RECEIVE_MODE_REG 5
-#define RX_BUFFER_EMPTY BIT(6)
-#define ACCEPT_BAD_PACKETS BIT(5)
-#define RECEIVE_SHORT_ADDR BIT(4)
-#define ACCEPT_SHORT_PACKETS BIT(3)
-#define REMOTE_RESET BIT(2)
-
-#define ADDRESS_FILTER_MODE BIT(1) | BIT(0)
-#define REJECT_ALL 0
-#define ACCEPT_ALL 3
-#define MODE_1 1 /* NODE ID, BC, MC, 2-24th bit */
-#define MODE_2 2 /* NODE ID, BC, MC, Hash Table */
-
-/* Configuration Register 0 (DLCR6) */
-#define CONFIG_REG_0 6
-#define DLC_EN BIT(7)
-#define SRAM_CYCLE_TIME_100NS BIT(6)
-#define SYSTEM_BUS_WIDTH_8 BIT(5) /* 1 = 8bit, 0 = 16bit */
-#define BUFFER_WIDTH_8 BIT(4) /* 1 = 8bit, 0 = 16bit */
-#define TBS1 BIT(3)
-#define TBS0 BIT(2)
-#define SRAM_BS1 BIT(1) /* 00=8kb, 01=16kb */
-#define SRAM_BS0 BIT(0) /* 10=32kb, 11=64kb */
-
-#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */
-#define ETH16I_TX_BUF_SIZE 3 /* 2 = 8kb, 3 = 16kb */
-#endif
-#define TX_BUF_1x2048 0
-#define TX_BUF_2x2048 1
-#define TX_BUF_2x4098 2
-#define TX_BUF_2x8192 3
-
-/* Configuration Register 1 (DLCR7) */
-#define CONFIG_REG_1 7
-#define POWERUP BIT(5)
-
-/* Transmit start register */
-#define TRANSMIT_START_REG 10
-#define TRANSMIT_START_RB 2
-#define TX_START BIT(7) /* Rest of register bit indicate*/
- /* number of packets in tx buffer*/
-/* Node ID registers (DLCR8-13) */
-#define NODE_ID_0 8
-#define NODE_ID_RB 0
-
-/* Hash Table registers (HT8-15) */
-#define HASH_TABLE_0 8
-#define HASH_TABLE_RB 1
-
-/* Buffer memory ports */
-#define BUFFER_MEM_PORT_LB 8
-#define DATAPORT BUFFER_MEM_PORT_LB
-#define BUFFER_MEM_PORT_HB 9
-
-/* 16 Collision control register (BMPR11) */
-#define COL_16_REG 11
-#define HALT_ON_16 0x00
-#define RETRANS_AND_HALT_ON_16 0x02
-
-/* Maximum number of attempts to send after 16 concecutive collisions */
-#define MAX_COL_16 10
-
-/* DMA Burst and Transceiver Mode Register (BMPR13) */
-#define TRANSCEIVER_MODE_REG 13
-#define TRANSCEIVER_MODE_RB 2
-#define IO_BASE_UNLOCK BIT(7)
-#define LOWER_SQUELCH_TRESH BIT(6)
-#define LINK_TEST_DISABLE BIT(5)
-#define AUI_SELECT BIT(4)
-#define DIS_AUTO_PORT_SEL BIT(3)
-
-/* Filter Self Receive Register (BMPR14) */
-#define FILTER_SELF_RX_REG 14
-#define SKIP_RX_PACKET BIT(2)
-#define FILTER_SELF_RECEIVE BIT(0)
-
-/* EEPROM Control Register (BMPR 16) */
-#define EEPROM_CTRL_REG 16
-
-/* EEPROM Data Register (BMPR 17) */
-#define EEPROM_DATA_REG 17
-
-/* NMC93CSx6 EEPROM Control Bits */
-#define CS_0 0x00
-#define CS_1 0x20
-#define SK_0 0x00
-#define SK_1 0x40
-#define DI_0 0x00
-#define DI_1 0x80
-
-/* NMC93CSx6 EEPROM Instructions */
-#define EEPROM_READ 0x80
-
-/* NMC93CSx6 EEPROM Addresses */
-#define E_NODEID_0 0x02
-#define E_NODEID_1 0x03
-#define E_NODEID_2 0x04
-#define E_PORT_SELECT 0x14
- #define E_PORT_BNC 0x00
- #define E_PORT_DIX 0x01
- #define E_PORT_TP 0x02
- #define E_PORT_AUTO 0x03
- #define E_PORT_FROM_EPROM 0x04
-#define E_PRODUCT_CFG 0x30
-
-
-/* Macro to slow down io between EEPROM clock transitions */
-#define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0)
-
-/* Jumperless Configuration Register (BMPR19) */
-#define JUMPERLESS_CONFIG 19
-
-/* ID ROM registers, writing to them also resets some parts of chip */
-#define ID_ROM_0 24
-#define ID_ROM_7 31
-#define RESET ID_ROM_0
-
-/* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] __initdata = {
- 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
-};
-
-static unsigned int eth32i_portlist[] __initdata = {
- 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
- 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
-};
-
-/* This is the Interrupt lookup table for Eth16i card */
-static unsigned int eth16i_irqmap[] __initdata = { 9, 10, 5, 15, 0 };
-#define NUM_OF_ISA_IRQS 4
-
-/* This is the Interrupt lookup table for Eth32i card */
-static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };
-#define EISA_IRQ_REG 0xc89
-#define NUM_OF_EISA_IRQS 8
-
-static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 };
-
-/* Use 0 for production, 1 for verification, >2 for debug */
-#ifndef ETH16I_DEBUG
-#define ETH16I_DEBUG 0
-#endif
-static unsigned int eth16i_debug = ETH16I_DEBUG;
-
-/* Information for each board */
-
-struct eth16i_local {
- unsigned char tx_started;
- unsigned char tx_buf_busy;
- unsigned short tx_queue; /* Number of packets in transmit buffer */
- unsigned short tx_queue_len;
- unsigned int tx_buf_size;
- unsigned long open_time;
- unsigned long tx_buffered_packets;
- unsigned long tx_buffered_bytes;
- unsigned long col_16;
- spinlock_t lock;
-};
-
-/* Function prototypes */
-
-static int eth16i_probe1(struct net_device *dev, int ioaddr);
-static int eth16i_check_signature(int ioaddr);
-static int eth16i_probe_port(int ioaddr);
-static void eth16i_set_port(int ioaddr, int porttype);
-static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l);
-static int eth16i_receive_probe_packet(int ioaddr);
-static int eth16i_get_irq(int ioaddr);
-static int eth16i_read_eeprom(int ioaddr, int offset);
-static int eth16i_read_eeprom_word(int ioaddr);
-static void eth16i_eeprom_cmd(int ioaddr, unsigned char command);
-static int eth16i_open(struct net_device *dev);
-static int eth16i_close(struct net_device *dev);
-static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev);
-static void eth16i_rx(struct net_device *dev);
-static void eth16i_timeout(struct net_device *dev);
-static irqreturn_t eth16i_interrupt(int irq, void *dev_id);
-static void eth16i_reset(struct net_device *dev);
-static void eth16i_timeout(struct net_device *dev);
-static void eth16i_skip_packet(struct net_device *dev);
-static void eth16i_multicast(struct net_device *dev);
-static void eth16i_select_regbank(unsigned char regbank, int ioaddr);
-static void eth16i_initialize(struct net_device *dev, int boot);
-
-#if 0
-static int eth16i_set_irq(struct net_device *dev);
-#endif
-
-#ifdef MODULE
-static ushort eth16i_parse_mediatype(const char* s);
-#endif
-
-static char cardname[] __initdata = "ICL EtherTeam 16i/32";
-
-static int __init do_eth16i_probe(struct net_device *dev)
-{
- int i;
- int ioaddr;
- int base_addr = dev->base_addr;
-
- if(eth16i_debug > 4)
- printk(KERN_DEBUG "Probing started for %s\n", cardname);
-
- if(base_addr > 0x1ff) /* Check only single location */
- return eth16i_probe1(dev, base_addr);
- else if(base_addr != 0) /* Don't probe at all */
- return -ENXIO;
-
- /* Seek card from the ISA io address space */
- for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++)
- if(eth16i_probe1(dev, ioaddr) == 0)
- return 0;
-
- /* Seek card from the EISA io address space */
- for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++)
- if(eth16i_probe1(dev, ioaddr) == 0)
- return 0;
-
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init eth16i_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct eth16i_local));
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_eth16i_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops eth16i_netdev_ops = {
- .ndo_open = eth16i_open,
- .ndo_stop = eth16i_close,
- .ndo_start_xmit = eth16i_tx,
- .ndo_set_rx_mode = eth16i_multicast,
- .ndo_tx_timeout = eth16i_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
-{
- struct eth16i_local *lp = netdev_priv(dev);
- static unsigned version_printed;
- int retval;
-
- /* Let's grab the region */
- if (!request_region(ioaddr, ETH16I_IO_EXTENT, cardname))
- return -EBUSY;
-
- /*
- The MB86985 chip has on register which holds information in which
- io address the chip lies. First read this register and compare
- it to our current io address and if match then this could
- be our chip.
- */
-
- if(ioaddr < 0x1000) {
- if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)]
- != ioaddr) {
- retval = -ENODEV;
- goto out;
- }
- }
-
- /* Now we will go a bit deeper and try to find the chip's signature */
-
- if(eth16i_check_signature(ioaddr) != 0) {
- retval = -ENODEV;
- goto out;
- }
-
- /*
- Now it seems that we have found a ethernet chip in this particular
- ioaddr. The MB86985 chip has this feature, that when you read a
- certain register it will increase it's io base address to next
- configurable slot. Now when we have found the chip, first thing is
- to make sure that the chip's ioaddr will hold still here.
- */
-
- eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
- outb(0x00, ioaddr + TRANSCEIVER_MODE_REG);
-
- outb(0x00, ioaddr + RESET); /* Reset some parts of chip */
- BITSET(ioaddr + CONFIG_REG_0, BIT(7)); /* Disable the data link */
-
- if( (eth16i_debug & version_printed++) == 0)
- printk(KERN_INFO "%s", version);
-
- dev->base_addr = ioaddr;
- dev->irq = eth16i_get_irq(ioaddr);
-
- /* Try to obtain interrupt vector */
-
- if ((retval = request_irq(dev->irq, (void *)&eth16i_interrupt, 0, cardname, dev))) {
- printk(KERN_WARNING "%s at %#3x, but is unusable due to conflicting IRQ %d.\n",
- cardname, ioaddr, dev->irq);
- goto out;
- }
-
- printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
- dev->name, cardname, ioaddr, dev->irq);
-
-
- /* Now we will have to lock the chip's io address */
- eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
- outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
-
- eth16i_initialize(dev, 1); /* Initialize rest of the chip's registers */
-
- /* Now let's same some energy by shutting down the chip ;) */
- BITCLR(ioaddr + CONFIG_REG_1, POWERUP);
-
- /* Initialize the device structure */
- dev->netdev_ops = &eth16i_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
- spin_lock_init(&lp->lock);
-
- retval = register_netdev(dev);
- if (retval)
- goto out1;
- return 0;
-out1:
- free_irq(dev->irq, dev);
-out:
- release_region(ioaddr, ETH16I_IO_EXTENT);
- return retval;
-}
-
-
-static void eth16i_initialize(struct net_device *dev, int boot)
-{
- int ioaddr = dev->base_addr;
- int i, node_w = 0;
- unsigned char node_byte = 0;
-
- /* Setup station address */
- eth16i_select_regbank(NODE_ID_RB, ioaddr);
- for(i = 0 ; i < 3 ; i++) {
- unsigned short node_val = eth16i_read_eeprom(ioaddr, E_NODEID_0 + i);
- ((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
- }
-
- for(i = 0; i < 6; i++) {
- outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
- if(boot) {
- printk("%02x", inb(ioaddr + NODE_ID_0 + i));
- if(i != 5)
- printk(":");
- }
- }
-
- /* Now we will set multicast addresses to accept none */
- eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
- for(i = 0; i < 8; i++)
- outb(0x00, ioaddr + HASH_TABLE_0 + i);
-
- /*
- Now let's disable the transmitter and receiver, set the buffer ram
- cycle time, bus width and buffer data path width. Also we shall
- set transmit buffer size and total buffer size.
- */
-
- eth16i_select_regbank(2, ioaddr);
-
- node_byte = 0;
- node_w = eth16i_read_eeprom(ioaddr, E_PRODUCT_CFG);
-
- if( (node_w & 0xFF00) == 0x0800)
- node_byte |= BUFFER_WIDTH_8;
-
- node_byte |= SRAM_BS1;
-
- if( (node_w & 0x00FF) == 64)
- node_byte |= SRAM_BS0;
-
- node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2);
-
- outb(node_byte, ioaddr + CONFIG_REG_0);
-
- /* We shall halt the transmitting, if 16 collisions are detected */
- outb(HALT_ON_16, ioaddr + COL_16_REG);
-
-#ifdef MODULE
- /* if_port already set by init_module() */
-#else
- dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ?
- dev->mem_start : E_PORT_FROM_EPROM;
-#endif
-
- /* Set interface port type */
- if(boot) {
- static const char * const porttype[] = {
- "BNC", "DIX", "TP", "AUTO", "FROM_EPROM"
- };
-
- switch(dev->if_port)
- {
-
- case E_PORT_FROM_EPROM:
- dev->if_port = eth16i_read_eeprom(ioaddr, E_PORT_SELECT);
- break;
-
- case E_PORT_AUTO:
- dev->if_port = eth16i_probe_port(ioaddr);
- break;
-
- case E_PORT_BNC:
- case E_PORT_TP:
- case E_PORT_DIX:
- break;
- }
-
- printk(" %s interface.\n", porttype[dev->if_port]);
-
- eth16i_set_port(ioaddr, dev->if_port);
- }
-
- /* Set Receive Mode to normal operation */
- outb(MODE_2, ioaddr + RECEIVE_MODE_REG);
-}
-
-static int eth16i_probe_port(int ioaddr)
-{
- int i;
- int retcode;
- unsigned char dummy_packet[64];
-
- /* Powerup the chip */
- outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
-
- BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-
- eth16i_select_regbank(NODE_ID_RB, ioaddr);
-
- for(i = 0; i < 6; i++) {
- dummy_packet[i] = inb(ioaddr + NODE_ID_0 + i);
- dummy_packet[i+6] = inb(ioaddr + NODE_ID_0 + i);
- }
-
- dummy_packet[12] = 0x00;
- dummy_packet[13] = 0x04;
- memset(dummy_packet + 14, 0, sizeof(dummy_packet) - 14);
-
- eth16i_select_regbank(2, ioaddr);
-
- for(i = 0; i < 3; i++) {
- BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
- BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
- eth16i_set_port(ioaddr, i);
-
- if(eth16i_debug > 1)
- printk(KERN_DEBUG "Set port number %d\n", i);
-
- retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64);
- if(retcode == 0) {
- retcode = eth16i_receive_probe_packet(ioaddr);
- if(retcode != -1) {
- if(eth16i_debug > 1)
- printk(KERN_DEBUG "Eth16i interface port found at %d\n", i);
- return i;
- }
- }
- else {
- if(eth16i_debug > 1)
- printk(KERN_DEBUG "TRANSMIT_DONE timeout when probing interface port\n");
- }
- }
-
- if( eth16i_debug > 1)
- printk(KERN_DEBUG "Using default port\n");
-
- return E_PORT_BNC;
-}
-
-static void eth16i_set_port(int ioaddr, int porttype)
-{
- unsigned short temp = 0;
-
- eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
- outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG);
-
- temp |= DIS_AUTO_PORT_SEL;
-
- switch(porttype) {
-
- case E_PORT_BNC :
- temp |= AUI_SELECT;
- break;
-
- case E_PORT_TP :
- break;
-
- case E_PORT_DIX :
- temp |= AUI_SELECT;
- BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
- break;
- }
-
- outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
-
- if(eth16i_debug > 1) {
- printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
- printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n",
- inb(ioaddr+TRANSCEIVER_MODE_REG));
- }
-}
-
-static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l)
-{
- unsigned long starttime;
-
- outb(0xff, ioaddr + TX_STATUS_REG);
-
- outw(l, ioaddr + DATAPORT);
- outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
-
- starttime = jiffies;
- outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
-
- while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
- if( time_after(jiffies, starttime + TX_TIMEOUT)) {
- return -1;
- }
- }
-
- return 0;
-}
-
-static int eth16i_receive_probe_packet(int ioaddr)
-{
- unsigned long starttime;
-
- starttime = jiffies;
-
- while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) {
- if( time_after(jiffies, starttime + TX_TIMEOUT)) {
-
- if(eth16i_debug > 1)
- printk(KERN_DEBUG "Timeout occurred waiting transmit packet received\n");
- starttime = jiffies;
- while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) {
- if( time_after(jiffies, starttime + TX_TIMEOUT)) {
- if(eth16i_debug > 1)
- printk(KERN_DEBUG "Timeout occurred waiting receive packet\n");
- return -1;
- }
- }
-
- if(eth16i_debug > 1)
- printk(KERN_DEBUG "RECEIVE_PACKET\n");
- return 0; /* Found receive packet */
- }
- }
-
- if(eth16i_debug > 1) {
- printk(KERN_DEBUG "TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG));
- printk(KERN_DEBUG "RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG));
- }
-
- return 0; /* Return success */
-}
-
-#if 0
-static int eth16i_set_irq(struct net_device* dev)
-{
- const int ioaddr = dev->base_addr;
- const int irq = dev->irq;
- int i = 0;
-
- if(ioaddr < 0x1000) {
- while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq)
- i++;
-
- if(i < NUM_OF_ISA_IRQS) {
- u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
- cbyte = (cbyte & 0x3F) | (i << 6);
- outb(cbyte, ioaddr + JUMPERLESS_CONFIG);
- return 0;
- }
- }
- else {
- printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name);
- }
-
- return -1;
-
-}
-#endif
-
-static int __init eth16i_get_irq(int ioaddr)
-{
- unsigned char cbyte;
-
- if( ioaddr < 0x1000) {
- cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
- return eth16i_irqmap[((cbyte & 0xC0) >> 6)];
- } else { /* Oh..the card is EISA so method getting IRQ different */
- unsigned short index = 0;
- cbyte = inb(ioaddr + EISA_IRQ_REG);
- while( (cbyte & 0x01) == 0) {
- cbyte = cbyte >> 1;
- index++;
- }
- return eth32i_irqmap[index];
- }
-}
-
-static int __init eth16i_check_signature(int ioaddr)
-{
- int i;
- unsigned char creg[4] = { 0 };
-
- for(i = 0; i < 4 ; i++) {
-
- creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
-
- if(eth16i_debug > 1)
- printk("eth16i: read signature byte %x at %x\n",
- creg[i],
- ioaddr + TRANSMIT_MODE_REG + i);
- }
-
- creg[0] &= 0x0F; /* Mask collision cnr */
- creg[2] &= 0x7F; /* Mask DCLEN bit */
-
-#if 0
- /*
- This was removed because the card was sometimes left to state
- from which it couldn't be find anymore. If there is need
- to more strict check still this have to be fixed.
- */
- if( ! ((creg[0] == 0x06) && (creg[1] == 0x41)) ) {
- if(creg[1] != 0x42)
- return -1;
- }
-#endif
-
- if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) {
- creg[2] &= 0x40;
- creg[3] &= 0x03;
-
- if( !((creg[2] == 0x40) && (creg[3] == 0x00)) )
- return -1;
- }
-
- if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
- return -1;
-
- if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
- return -1;
-
- return 0;
-}
-
-static int eth16i_read_eeprom(int ioaddr, int offset)
-{
- int data = 0;
-
- eth16i_eeprom_cmd(ioaddr, EEPROM_READ | offset);
- outb(CS_1, ioaddr + EEPROM_CTRL_REG);
- data = eth16i_read_eeprom_word(ioaddr);
- outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
-
- return data;
-}
-
-static int eth16i_read_eeprom_word(int ioaddr)
-{
- int i;
- int data = 0;
-
- for(i = 16; i > 0; i--) {
- outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
- eeprom_slow_io();
- outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
- eeprom_slow_io();
- data = (data << 1) |
- ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
-
- eeprom_slow_io();
- }
-
- return data;
-}
-
-static void eth16i_eeprom_cmd(int ioaddr, unsigned char command)
-{
- int i;
-
- outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
- outb(DI_0, ioaddr + EEPROM_DATA_REG);
- outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
- outb(DI_1, ioaddr + EEPROM_DATA_REG);
- outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
-
- for(i = 7; i >= 0; i--) {
- short cmd = ( (command & (1 << i)) ? DI_1 : DI_0 );
- outb(cmd, ioaddr + EEPROM_DATA_REG);
- outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
- eeprom_slow_io();
- outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
- eeprom_slow_io();
- }
-}
-
-static int eth16i_open(struct net_device *dev)
-{
- struct eth16i_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- /* Powerup the chip */
- outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
-
- /* Initialize the chip */
- eth16i_initialize(dev, 0);
-
- /* Set the transmit buffer size */
- lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
-
- if(eth16i_debug > 0)
- printk(KERN_DEBUG "%s: transmit buffer size %d\n",
- dev->name, lp->tx_buf_size);
-
- /* Now enable Transmitter and Receiver sections */
- BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-
- /* Now switch to register bank 2, for run time operation */
- eth16i_select_regbank(2, ioaddr);
-
- lp->open_time = jiffies;
- lp->tx_started = 0;
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
-
- /* Turn on interrupts*/
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
- netif_start_queue(dev);
- return 0;
-}
-
-static int eth16i_close(struct net_device *dev)
-{
- struct eth16i_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- eth16i_reset(dev);
-
- /* Turn off interrupts*/
- outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
- netif_stop_queue(dev);
-
- lp->open_time = 0;
-
- /* Disable transmit and receive */
- BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
-
- /* Reset the chip */
- /* outb(0xff, ioaddr + RESET); */
- /* outw(0xffff, ioaddr + TX_STATUS_REG); */
-
- outb(0x00, ioaddr + CONFIG_REG_1);
-
- return 0;
-}
-
-static void eth16i_timeout(struct net_device *dev)
-{
- struct eth16i_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- /*
- If we get here, some higher level has decided that
- we are broken. There should really be a "kick me"
- function call instead.
- */
-
- outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
- dev->name,
- inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
- "IRQ conflict" : "network cable problem");
-
- dev->trans_start = jiffies; /* prevent tx timeout */
-
- /* Let's dump all registers */
- if(eth16i_debug > 0) {
- printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
- dev->name, inb(ioaddr + 0),
- inb(ioaddr + 1), inb(ioaddr + 2),
- inb(ioaddr + 3), inb(ioaddr + 4),
- inb(ioaddr + 5),
- inb(ioaddr + 6), inb(ioaddr + 7));
-
- printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
- dev->name, inb(ioaddr + TRANSMIT_START_REG),
- inb(ioaddr + COL_16_REG));
- printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);
- printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
- printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
- }
- dev->stats.tx_errors++;
- eth16i_reset(dev);
- dev->trans_start = jiffies; /* prevent tx timeout */
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
- netif_wake_queue(dev);
-}
-
-static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev)
-{
- struct eth16i_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- int status = 0;
- ushort length = skb->len;
- unsigned char *buf;
- unsigned long flags;
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
- buf = skb->data;
-
- netif_stop_queue(dev);
-
- /* Turn off TX interrupts */
- outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
- /* We would be better doing the disable_irq tricks the 3c509 does,
- that would make this suck a lot less */
-
- spin_lock_irqsave(&lp->lock, flags);
-
- if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
- if(eth16i_debug > 0)
- printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
- }
- else {
- outw(length, ioaddr + DATAPORT);
-
- if( ioaddr < 0x1000 )
- outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
- else {
- unsigned char frag = length % 4;
- outsl(ioaddr + DATAPORT, buf, length >> 2);
- if( frag != 0 ) {
- outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
- if( frag == 3 )
- outsw(ioaddr + DATAPORT,
- (buf + (length & 0xFFFC) + 2), 1);
- }
- }
- lp->tx_buffered_packets++;
- lp->tx_buffered_bytes = length;
- lp->tx_queue++;
- lp->tx_queue_len += length + 2;
- }
- lp->tx_buf_busy = 0;
-
- if(lp->tx_started == 0) {
- /* If the transmitter is idle..always trigger a transmit */
- outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- lp->tx_started = 1;
- netif_wake_queue(dev);
- }
- else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
- /* There is still more room for one more packet in tx buffer */
- netif_wake_queue(dev);
- }
-
- spin_unlock_irqrestore(&lp->lock, flags);
-
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
- /* Turn TX interrupts back on */
- /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
- status = 0;
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-static void eth16i_rx(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- int boguscount = MAX_RX_LOOP;
-
- /* Loop until all packets have been read */
- while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {
-
- /* Read status byte from receive buffer */
- ushort status = inw(ioaddr + DATAPORT);
-
- /* Get the size of the packet from receive buffer */
- ushort pkt_len = inw(ioaddr + DATAPORT);
-
- if(eth16i_debug > 4)
- printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n",
- dev->name,
- inb(ioaddr + RECEIVE_MODE_REG), status);
-
- if( !(status & PKT_GOOD) ) {
- dev->stats.rx_errors++;
-
- if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
- dev->stats.rx_length_errors++;
- eth16i_reset(dev);
- return;
- }
- else {
- eth16i_skip_packet(dev);
- dev->stats.rx_dropped++;
- }
- }
- else { /* Ok so now we should have a good packet */
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(dev, pkt_len + 3);
- if( skb == NULL ) {
- printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
- dev->name, pkt_len);
- eth16i_skip_packet(dev);
- dev->stats.rx_dropped++;
- break;
- }
-
- skb_reserve(skb,2);
-
- /*
- Now let's get the packet out of buffer.
- size is (pkt_len + 1) >> 1, cause we are now reading words
- and it have to be even aligned.
- */
-
- if(ioaddr < 0x1000)
- insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
- (pkt_len + 1) >> 1);
- else {
- unsigned char *buf = skb_put(skb, pkt_len);
- unsigned char frag = pkt_len % 4;
-
- insl(ioaddr + DATAPORT, buf, pkt_len >> 2);
-
- if(frag != 0) {
- unsigned short rest[2];
- rest[0] = inw( ioaddr + DATAPORT );
- if(frag == 3)
- rest[1] = inw( ioaddr + DATAPORT );
-
- memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag);
- }
- }
-
- skb->protocol=eth_type_trans(skb, dev);
-
- if( eth16i_debug > 5 ) {
- int i;
- printk(KERN_DEBUG "%s: Received packet of length %d.\n",
- dev->name, pkt_len);
- for(i = 0; i < 14; i++)
- printk(KERN_DEBUG " %02x", skb->data[i]);
- printk(KERN_DEBUG ".\n");
- }
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
-
- } /* else */
-
- if(--boguscount <= 0)
- break;
-
- } /* while */
-}
-
-static irqreturn_t eth16i_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct eth16i_local *lp;
- int ioaddr = 0, status;
- int handled = 0;
-
- ioaddr = dev->base_addr;
- lp = netdev_priv(dev);
-
- /* Turn off all interrupts from adapter */
- outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
- /* eth16i_tx won't be called */
- spin_lock(&lp->lock);
-
- status = inw(ioaddr + TX_STATUS_REG); /* Get the status */
- outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */
-
- if (status)
- handled = 1;
-
- if(eth16i_debug > 3)
- printk(KERN_DEBUG "%s: Interrupt with status %04x.\n", dev->name, status);
-
- if( status & 0x7f00 ) {
-
- dev->stats.rx_errors++;
-
- if(status & (BUS_RD_ERR << 8) )
- printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
- if(status & (SHORT_PKT_ERR << 8) ) dev->stats.rx_length_errors++;
- if(status & (ALIGN_ERR << 8) ) dev->stats.rx_frame_errors++;
- if(status & (CRC_ERR << 8) ) dev->stats.rx_crc_errors++;
- if(status & (RX_BUF_OVERFLOW << 8) ) dev->stats.rx_over_errors++;
- }
- if( status & 0x001a) {
-
- dev->stats.tx_errors++;
-
- if(status & CR_LOST) dev->stats.tx_carrier_errors++;
- if(status & TX_JABBER_ERR) dev->stats.tx_window_errors++;
-
-#if 0
- if(status & COLLISION) {
- dev->stats.collisions +=
- ((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
- }
-#endif
- if(status & COLLISIONS_16) {
- if(lp->col_16 < MAX_COL_16) {
- lp->col_16++;
- dev->stats.collisions++;
- /* Resume transmitting, skip failed packet */
- outb(0x02, ioaddr + COL_16_REG);
- }
- else {
- printk(KERN_WARNING "%s: bailing out due to many consecutive 16-in-a-row collisions. Network cable problem?\n", dev->name);
- }
- }
- }
-
- if( status & 0x00ff ) { /* Let's check the transmit status reg */
-
- if(status & TX_DONE) { /* The transmit has been done */
- dev->stats.tx_packets = lp->tx_buffered_packets;
- dev->stats.tx_bytes += lp->tx_buffered_bytes;
- lp->col_16 = 0;
-
- if(lp->tx_queue) { /* Is there still packets ? */
- /* There was packet(s) so start transmitting and write also
- how many packets there is to be sended */
- outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- lp->tx_started = 1;
- }
- else {
- lp->tx_started = 0;
- }
- netif_wake_queue(dev);
- }
- }
-
- if( ( status & 0x8000 ) ||
- ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
- eth16i_rx(dev); /* We have packet in receive buffer */
- }
-
- /* Turn interrupts back on */
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
- if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
- /* There is still more room for one more packet in tx buffer */
- netif_wake_queue(dev);
- }
-
- spin_unlock(&lp->lock);
-
- return IRQ_RETVAL(handled);
-}
-
-static void eth16i_skip_packet(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- inw(ioaddr + DATAPORT);
- inw(ioaddr + DATAPORT);
- inw(ioaddr + DATAPORT);
-
- outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
- while( inb( ioaddr + FILTER_SELF_RX_REG ) != 0);
-}
-
-static void eth16i_reset(struct net_device *dev)
-{
- struct eth16i_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- if(eth16i_debug > 1)
- printk(KERN_DEBUG "%s: Resetting device.\n", dev->name);
-
- BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
- outw(0xffff, ioaddr + TX_STATUS_REG);
- eth16i_select_regbank(2, ioaddr);
-
- lp->tx_started = 0;
- lp->tx_buf_busy = 0;
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
-}
-
-static void eth16i_multicast(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- if (!netdev_mc_empty(dev) || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
- {
- outb(3, ioaddr + RECEIVE_MODE_REG);
- } else {
- outb(2, ioaddr + RECEIVE_MODE_REG);
- }
-}
-
-static void eth16i_select_regbank(unsigned char banknbr, int ioaddr)
-{
- unsigned char data;
-
- data = inb(ioaddr + CONFIG_REG_1);
- outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
-}
-
-#ifdef MODULE
-
-static ushort eth16i_parse_mediatype(const char* s)
-{
- if(!s)
- return E_PORT_FROM_EPROM;
-
- if (!strncmp(s, "bnc", 3))
- return E_PORT_BNC;
- else if (!strncmp(s, "tp", 2))
- return E_PORT_TP;
- else if (!strncmp(s, "dix", 3))
- return E_PORT_DIX;
- else if (!strncmp(s, "auto", 4))
- return E_PORT_AUTO;
- else
- return E_PORT_FROM_EPROM;
-}
-
-#define MAX_ETH16I_CARDS 4 /* Max number of Eth16i cards per module */
-
-static struct net_device *dev_eth16i[MAX_ETH16I_CARDS];
-static int io[MAX_ETH16I_CARDS];
-#if 0
-static int irq[MAX_ETH16I_CARDS];
-#endif
-static char* mediatype[MAX_ETH16I_CARDS];
-static int debug = -1;
-
-MODULE_AUTHOR("Mika Kuoppala <miku@iki.fi>");
-MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver");
-MODULE_LICENSE("GPL");
-
-
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io, "eth16i I/O base address(es)");
-
-#if 0
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq, "eth16i interrupt request number");
-#endif
-
-module_param_array(mediatype, charp, NULL, 0);
-MODULE_PARM_DESC(mediatype, "eth16i media type of interface(s) (bnc,tp,dix,auto,eprom)");
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "eth16i debug level (0-6)");
-
-int __init init_module(void)
-{
- int this_dev, found = 0;
- struct net_device *dev;
-
- for (this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
- dev = alloc_etherdev(sizeof(struct eth16i_local));
- if (!dev)
- break;
-
- dev->base_addr = io[this_dev];
-
- if(debug != -1)
- eth16i_debug = debug;
-
- if(eth16i_debug > 1)
- printk(KERN_NOTICE "eth16i(%d): interface type %s\n", this_dev, mediatype[this_dev] ? mediatype[this_dev] : "none" );
-
- dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);
-
- if(io[this_dev] == 0) {
- if (this_dev != 0) { /* Only autoprobe 1st one */
- free_netdev(dev);
- break;
- }
-
- printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n");
- }
-
- if (do_eth16i_probe(dev) == 0) {
- dev_eth16i[found++] = dev;
- continue;
- }
- printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",
- io[this_dev]);
- free_netdev(dev);
- break;
- }
- if (found)
- return 0;
- return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
- int this_dev;
-
- for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
- struct net_device *dev = dev_eth16i[this_dev];
-
- if (netdev_priv(dev)) {
- unregister_netdev(dev);
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, ETH16I_IO_EXTENT);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/i825xx/3c505.c b/drivers/net/ethernet/i825xx/3c505.c
deleted file mode 100644
index 6a5c21b82c51..000000000000
--- a/drivers/net/ethernet/i825xx/3c505.c
+++ /dev/null
@@ -1,1671 +0,0 @@
-/*
- * Linux Ethernet device driver for the 3Com Etherlink Plus (3C505)
- * By Craig Southeren, Juha Laiho and Philip Blundell
- *
- * 3c505.c This module implements an interface to the 3Com
- * Etherlink Plus (3c505) Ethernet card. Linux device
- * driver interface reverse engineered from the Linux 3C509
- * device drivers. Some 3C505 information gleaned from
- * the Crynwr packet driver. Still this driver would not
- * be here without 3C505 technical reference provided by
- * 3Com.
- *
- * $Id: 3c505.c,v 1.10 1996/04/16 13:06:27 phil Exp $
- *
- * Authors: Linux 3c505 device driver by
- * Craig Southeren, <craigs@ineluki.apana.org.au>
- * Final debugging by
- * Andrew Tridgell, <tridge@nimbus.anu.edu.au>
- * Auto irq/address, tuning, cleanup and v1.1.4+ kernel mods by
- * Juha Laiho, <jlaiho@ichaos.nullnet.fi>
- * Linux 3C509 driver by
- * Donald Becker, <becker@super.org>
- * (Now at <becker@scyld.com>)
- * Crynwr packet driver by
- * Krishnan Gopalan and Gregg Stefancik,
- * Clemson University Engineering Computer Operations.
- * Portions of the code have been adapted from the 3c505
- * driver for NCSA Telnet by Bruce Orchard and later
- * modified by Warren Van Houten and krus@diku.dk.
- * 3C505 technical information provided by
- * Terry Murphy, of 3Com Network Adapter Division
- * Linux 1.3.0 changes by
- * Alan Cox <Alan.Cox@linux.org>
- * More debugging, DMA support, currently maintained by
- * Philip Blundell <philb@gnu.org>
- * Multicard/soft configurable dma channel/rev 2 hardware support
- * by Christopher Collins <ccollins@pcug.org.au>
- * Ethtool support (jgarzik), 11/17/2001
- */
-
-#define DRV_NAME "3c505"
-#define DRV_VERSION "1.10a"
-
-
-/* Theory of operation:
- *
- * The 3c505 is quite an intelligent board. All communication with it is done
- * by means of Primary Command Blocks (PCBs); these are transferred using PIO
- * through the command register. The card has 256k of on-board RAM, which is
- * used to buffer received packets. It might seem at first that more buffers
- * are better, but in fact this isn't true. From my tests, it seems that
- * more than about 10 buffers are unnecessary, and there is a noticeable
- * performance hit in having more active on the card. So the majority of the
- * card's memory isn't, in fact, used. Sadly, the card only has one transmit
- * buffer and, short of loading our own firmware into it (which is what some
- * drivers resort to) there's nothing we can do about this.
- *
- * We keep up to 4 "receive packet" commands active on the board at a time.
- * When a packet comes in, so long as there is a receive command active, the
- * board will send us a "packet received" PCB and then add the data for that
- * packet to the DMA queue. If a DMA transfer is not already in progress, we
- * set one up to start uploading the data. We have to maintain a list of
- * backlogged receive packets, because the card may decide to tell us about
- * a newly-arrived packet at any time, and we may not be able to start a DMA
- * transfer immediately (ie one may already be going on). We can't NAK the
- * PCB, because then it would throw the packet away.
- *
- * Trying to send a PCB to the card at the wrong moment seems to have bad
- * effects. If we send it a transmit PCB while a receive DMA is happening,
- * it will just NAK the PCB and so we will have wasted our time. Worse, it
- * sometimes seems to interrupt the transfer. The majority of the low-level
- * code is protected by one huge semaphore -- "busy" -- which is set whenever
- * it probably isn't safe to do anything to the card. The receive routine
- * must gain a lock on "busy" before it can start a DMA transfer, and the
- * transmit routine must gain a lock before it sends the first PCB to the card.
- * The send_pcb() routine also has an internal semaphore to protect it against
- * being re-entered (which would be disastrous) -- this is needed because
- * several things can happen asynchronously (re-priming the receiver and
- * asking the card for statistics, for example). send_pcb() will also refuse
- * to talk to the card at all if a DMA upload is happening. The higher-level
- * networking code will reschedule a later retry if some part of the driver
- * is blocked. In practice, this doesn't seem to happen very often.
- */
-
-/* This driver may now work with revision 2.x hardware, since all the read
- * operations on the HCR have been removed (we now keep our own softcopy).
- * But I don't have an old card to test it on.
- *
- * This has had the bad effect that the autoprobe routine is now a bit
- * less friendly to other devices. However, it was never very good.
- * before, so I doubt it will hurt anybody.
- */
-
-/* The driver is a mess. I took Craig's and Juha's code, and hacked it firstly
- * to make it more reliable, and secondly to add DMA mode. Many things could
- * probably be done better; the concurrency protection is particularly awful.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include "3c505.h"
-
-/*********************************************************
- *
- * define debug messages here as common strings to reduce space
- *
- *********************************************************/
-
-#define timeout_msg "*** timeout at %s:%s (line %d) ***\n"
-#define TIMEOUT_MSG(lineno) \
- pr_notice(timeout_msg, __FILE__, __func__, (lineno))
-
-#define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***\n"
-#define INVALID_PCB_MSG(len) \
- pr_notice(invalid_pcb_msg, (len), __FILE__, __func__, __LINE__)
-
-#define search_msg "%s: Looking for 3c505 adapter at address %#x..."
-
-#define stilllooking_msg "still looking..."
-
-#define found_msg "found.\n"
-
-#define notfound_msg "not found (reason = %d)\n"
-
-#define couldnot_msg "%s: 3c505 not found\n"
-
-/*********************************************************
- *
- * various other debug stuff
- *
- *********************************************************/
-
-#ifdef ELP_DEBUG
-static int elp_debug = ELP_DEBUG;
-#else
-static int elp_debug;
-#endif
-#define debug elp_debug
-
-/*
- * 0 = no messages (well, some)
- * 1 = messages when high level commands performed
- * 2 = messages when low level commands performed
- * 3 = messages when interrupts received
- */
-
-/*****************************************************************
- *
- * List of I/O-addresses we try to auto-sense
- * Last element MUST BE 0!
- *****************************************************************/
-
-static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
-
-/* Dma Memory related stuff */
-
-static unsigned long dma_mem_alloc(int size)
-{
- int order = get_order(size);
- return __get_dma_pages(GFP_KERNEL, order);
-}
-
-
-/*****************************************************************
- *
- * Functions for I/O (note the inline !)
- *
- *****************************************************************/
-
-static inline unsigned char inb_status(unsigned int base_addr)
-{
- return inb(base_addr + PORT_STATUS);
-}
-
-static inline int inb_command(unsigned int base_addr)
-{
- return inb(base_addr + PORT_COMMAND);
-}
-
-static inline void outb_control(unsigned char val, struct net_device *dev)
-{
- outb(val, dev->base_addr + PORT_CONTROL);
- ((elp_device *)(netdev_priv(dev)))->hcr_val = val;
-}
-
-#define HCR_VAL(x) (((elp_device *)(netdev_priv(x)))->hcr_val)
-
-static inline void outb_command(unsigned char val, unsigned int base_addr)
-{
- outb(val, base_addr + PORT_COMMAND);
-}
-
-static inline unsigned int backlog_next(unsigned int n)
-{
- return (n + 1) % BACKLOG_SIZE;
-}
-
-/*****************************************************************
- *
- * useful functions for accessing the adapter
- *
- *****************************************************************/
-
-/*
- * use this routine when accessing the ASF bits as they are
- * changed asynchronously by the adapter
- */
-
-/* get adapter PCB status */
-#define GET_ASF(addr) \
- (get_status(addr)&ASF_PCB_MASK)
-
-static inline int get_status(unsigned int base_addr)
-{
- unsigned long timeout = jiffies + 10*HZ/100;
- register int stat1;
- do {
- stat1 = inb_status(base_addr);
- } while (stat1 != inb_status(base_addr) && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout))
- TIMEOUT_MSG(__LINE__);
- return stat1;
-}
-
-static inline void set_hsf(struct net_device *dev, int hsf)
-{
- elp_device *adapter = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->lock, flags);
- outb_control((HCR_VAL(dev) & ~HSF_PCB_MASK) | hsf, dev);
- spin_unlock_irqrestore(&adapter->lock, flags);
-}
-
-static bool start_receive(struct net_device *, pcb_struct *);
-
-static inline void adapter_reset(struct net_device *dev)
-{
- unsigned long timeout;
- elp_device *adapter = netdev_priv(dev);
- unsigned char orig_hcr = adapter->hcr_val;
-
- outb_control(0, dev);
-
- if (inb_status(dev->base_addr) & ACRF) {
- do {
- inb_command(dev->base_addr);
- timeout = jiffies + 2*HZ/100;
- while (time_before_eq(jiffies, timeout) && !(inb_status(dev->base_addr) & ACRF));
- } while (inb_status(dev->base_addr) & ACRF);
- set_hsf(dev, HSF_PCB_NAK);
- }
- outb_control(adapter->hcr_val | ATTN | DIR, dev);
- mdelay(10);
- outb_control(adapter->hcr_val & ~ATTN, dev);
- mdelay(10);
- outb_control(adapter->hcr_val | FLSH, dev);
- mdelay(10);
- outb_control(adapter->hcr_val & ~FLSH, dev);
- mdelay(10);
-
- outb_control(orig_hcr, dev);
- if (!start_receive(dev, &adapter->tx_pcb))
- pr_err("%s: start receive command failed\n", dev->name);
-}
-
-/* Check to make sure that a DMA transfer hasn't timed out. This should
- * never happen in theory, but seems to occur occasionally if the card gets
- * prodded at the wrong time.
- */
-static inline void check_3c505_dma(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
- if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
- unsigned long flags, f;
- pr_err("%s: DMA %s timed out, %d bytes left\n", dev->name,
- adapter->current_dma.direction ? "download" : "upload",
- get_dma_residue(dev->dma));
- spin_lock_irqsave(&adapter->lock, flags);
- adapter->dmaing = 0;
- adapter->busy = 0;
-
- f=claim_dma_lock();
- disable_dma(dev->dma);
- release_dma_lock(f);
-
- if (adapter->rx_active)
- adapter->rx_active--;
- outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
- spin_unlock_irqrestore(&adapter->lock, flags);
- }
-}
-
-/* Primitive functions used by send_pcb() */
-static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
-{
- unsigned long timeout;
- outb_command(byte, base_addr);
- for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
- if (inb_status(base_addr) & HCRE)
- return false;
- }
- pr_warning("3c505: send_pcb_slow timed out\n");
- return true;
-}
-
-static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
-{
- unsigned int timeout;
- outb_command(byte, base_addr);
- for (timeout = 0; timeout < 40000; timeout++) {
- if (inb_status(base_addr) & HCRE)
- return false;
- }
- pr_warning("3c505: send_pcb_fast timed out\n");
- return true;
-}
-
-/* Check to see if the receiver needs restarting, and kick it if so */
-static inline void prime_rx(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
- while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) {
- if (!start_receive(dev, &adapter->itx_pcb))
- break;
- }
-}
-
-/*****************************************************************
- *
- * send_pcb
- * Send a PCB to the adapter.
- *
- * output byte to command reg --<--+
- * wait until HCRE is non zero |
- * loop until all bytes sent -->--+
- * set HSF1 and HSF2 to 1
- * output pcb length
- * wait until ASF give ACK or NAK
- * set HSF1 and HSF2 to 0
- *
- *****************************************************************/
-
-/* This can be quite slow -- the adapter is allowed to take up to 40ms
- * to respond to the initial interrupt.
- *
- * We run initially with interrupts turned on, but with a semaphore set
- * so that nobody tries to re-enter this code. Once the first byte has
- * gone through, we turn interrupts off and then send the others (the
- * timeout is reduced to 500us).
- */
-
-static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
-{
- int i;
- unsigned long timeout;
- elp_device *adapter = netdev_priv(dev);
- unsigned long flags;
-
- check_3c505_dma(dev);
-
- if (adapter->dmaing && adapter->current_dma.direction == 0)
- return false;
-
- /* Avoid contention */
- if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
- if (elp_debug >= 3) {
- pr_debug("%s: send_pcb entered while threaded\n", dev->name);
- }
- return false;
- }
- /*
- * load each byte into the command register and
- * wait for the HCRE bit to indicate the adapter
- * had read the byte
- */
- set_hsf(dev, 0);
-
- if (send_pcb_slow(dev->base_addr, pcb->command))
- goto abort;
-
- spin_lock_irqsave(&adapter->lock, flags);
-
- if (send_pcb_fast(dev->base_addr, pcb->length))
- goto sti_abort;
-
- for (i = 0; i < pcb->length; i++) {
- if (send_pcb_fast(dev->base_addr, pcb->data.raw[i]))
- goto sti_abort;
- }
-
- outb_control(adapter->hcr_val | 3, dev); /* signal end of PCB */
- outb_command(2 + pcb->length, dev->base_addr);
-
- /* now wait for the acknowledgement */
- spin_unlock_irqrestore(&adapter->lock, flags);
-
- for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
- switch (GET_ASF(dev->base_addr)) {
- case ASF_PCB_ACK:
- adapter->send_pcb_semaphore = 0;
- return true;
-
- case ASF_PCB_NAK:
-#ifdef ELP_DEBUG
- pr_debug("%s: send_pcb got NAK\n", dev->name);
-#endif
- goto abort;
- }
- }
-
- if (elp_debug >= 1)
- pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)\n",
- dev->name, inb_status(dev->base_addr));
- goto abort;
-
- sti_abort:
- spin_unlock_irqrestore(&adapter->lock, flags);
- abort:
- adapter->send_pcb_semaphore = 0;
- return false;
-}
-
-
-/*****************************************************************
- *
- * receive_pcb
- * Read a PCB from the adapter
- *
- * wait for ACRF to be non-zero ---<---+
- * input a byte |
- * if ASF1 and ASF2 were not both one |
- * before byte was read, loop --->---+
- * set HSF1 and HSF2 for ack
- *
- *****************************************************************/
-
-static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
-{
- int i, j;
- int total_length;
- int stat;
- unsigned long timeout;
- unsigned long flags;
-
- elp_device *adapter = netdev_priv(dev);
-
- set_hsf(dev, 0);
-
- /* get the command code */
- timeout = jiffies + 2*HZ/100;
- while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout)) {
- TIMEOUT_MSG(__LINE__);
- return false;
- }
- pcb->command = inb_command(dev->base_addr);
-
- /* read the data length */
- timeout = jiffies + 3*HZ/100;
- while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout)) {
- TIMEOUT_MSG(__LINE__);
- pr_info("%s: status %02x\n", dev->name, stat);
- return false;
- }
- pcb->length = inb_command(dev->base_addr);
-
- if (pcb->length > MAX_PCB_DATA) {
- INVALID_PCB_MSG(pcb->length);
- adapter_reset(dev);
- return false;
- }
- /* read the data */
- spin_lock_irqsave(&adapter->lock, flags);
- for (i = 0; i < MAX_PCB_DATA; i++) {
- for (j = 0; j < 20000; j++) {
- stat = get_status(dev->base_addr);
- if (stat & ACRF)
- break;
- }
- pcb->data.raw[i] = inb_command(dev->base_addr);
- if ((stat & ASF_PCB_MASK) == ASF_PCB_END || j >= 20000)
- break;
- }
- spin_unlock_irqrestore(&adapter->lock, flags);
- if (i >= MAX_PCB_DATA) {
- INVALID_PCB_MSG(i);
- return false;
- }
- if (j >= 20000) {
- TIMEOUT_MSG(__LINE__);
- return false;
- }
- /* the last "data" byte was really the length! */
- total_length = pcb->data.raw[i];
-
- /* safety check total length vs data length */
- if (total_length != (pcb->length + 2)) {
- if (elp_debug >= 2)
- pr_warning("%s: mangled PCB received\n", dev->name);
- set_hsf(dev, HSF_PCB_NAK);
- return false;
- }
-
- if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
- if (test_and_set_bit(0, (void *) &adapter->busy)) {
- if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
- set_hsf(dev, HSF_PCB_NAK);
- pr_warning("%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
- pcb->command = 0;
- return true;
- } else {
- pcb->command = 0xff;
- }
- }
- }
- set_hsf(dev, HSF_PCB_ACK);
- return true;
-}
-
-/******************************************************
- *
- * queue a receive command on the adapter so we will get an
- * interrupt when a packet is received.
- *
- ******************************************************/
-
-static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
-{
- bool status;
- elp_device *adapter = netdev_priv(dev);
-
- if (elp_debug >= 3)
- pr_debug("%s: restarting receiver\n", dev->name);
- tx_pcb->command = CMD_RECEIVE_PACKET;
- tx_pcb->length = sizeof(struct Rcv_pkt);
- tx_pcb->data.rcv_pkt.buf_seg
- = tx_pcb->data.rcv_pkt.buf_ofs = 0; /* Unused */
- tx_pcb->data.rcv_pkt.buf_len = 1600;
- tx_pcb->data.rcv_pkt.timeout = 0; /* set timeout to zero */
- status = send_pcb(dev, tx_pcb);
- if (status)
- adapter->rx_active++;
- return status;
-}
-
-/******************************************************
- *
- * extract a packet from the adapter
- * this routine is only called from within the interrupt
- * service routine, so no cli/sti calls are needed
- * note that the length is always assumed to be even
- *
- ******************************************************/
-
-static void receive_packet(struct net_device *dev, int len)
-{
- int rlen;
- elp_device *adapter = netdev_priv(dev);
- void *target;
- struct sk_buff *skb;
- unsigned long flags;
-
- rlen = (len + 1) & ~1;
- skb = netdev_alloc_skb(dev, rlen + 2);
-
- if (!skb) {
- pr_warning("%s: memory squeeze, dropping packet\n", dev->name);
- target = adapter->dma_buffer;
- adapter->current_dma.target = NULL;
- /* FIXME: stats */
- return;
- }
-
- skb_reserve(skb, 2);
- target = skb_put(skb, rlen);
- if ((unsigned long)(target + rlen) >= MAX_DMA_ADDRESS) {
- adapter->current_dma.target = target;
- target = adapter->dma_buffer;
- } else {
- adapter->current_dma.target = NULL;
- }
-
- /* if this happens, we die */
- if (test_and_set_bit(0, (void *) &adapter->dmaing))
- pr_err("%s: rx blocked, DMA in progress, dir %d\n",
- dev->name, adapter->current_dma.direction);
-
- adapter->current_dma.direction = 0;
- adapter->current_dma.length = rlen;
- adapter->current_dma.skb = skb;
- adapter->current_dma.start_time = jiffies;
-
- outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev);
-
- flags=claim_dma_lock();
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, 0x04); /* dma read */
- set_dma_addr(dev->dma, isa_virt_to_bus(target));
- set_dma_count(dev->dma, rlen);
- enable_dma(dev->dma);
- release_dma_lock(flags);
-
- if (elp_debug >= 3) {
- pr_debug("%s: rx DMA transfer started\n", dev->name);
- }
-
- if (adapter->rx_active)
- adapter->rx_active--;
-
- if (!adapter->busy)
- pr_warning("%s: receive_packet called, busy not set.\n", dev->name);
-}
-
-/******************************************************
- *
- * interrupt handler
- *
- ******************************************************/
-
-static irqreturn_t elp_interrupt(int irq, void *dev_id)
-{
- int len;
- int dlen;
- int icount = 0;
- struct net_device *dev = dev_id;
- elp_device *adapter = netdev_priv(dev);
- unsigned long timeout;
-
- spin_lock(&adapter->lock);
-
- do {
- /*
- * has a DMA transfer finished?
- */
- if (inb_status(dev->base_addr) & DONE) {
- if (!adapter->dmaing)
- pr_warning("%s: phantom DMA completed\n", dev->name);
-
- if (elp_debug >= 3)
- pr_debug("%s: %s DMA complete, status %02x\n", dev->name,
- adapter->current_dma.direction ? "tx" : "rx",
- inb_status(dev->base_addr));
-
- outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
- if (adapter->current_dma.direction) {
- dev_kfree_skb_irq(adapter->current_dma.skb);
- } else {
- struct sk_buff *skb = adapter->current_dma.skb;
- if (skb) {
- if (adapter->current_dma.target) {
- /* have already done the skb_put() */
- memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
- }
- skb->protocol = eth_type_trans(skb,dev);
- dev->stats.rx_bytes += skb->len;
- netif_rx(skb);
- }
- }
- adapter->dmaing = 0;
- if (adapter->rx_backlog.in != adapter->rx_backlog.out) {
- int t = adapter->rx_backlog.length[adapter->rx_backlog.out];
- adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);
- if (elp_debug >= 2)
- pr_debug("%s: receiving backlogged packet (%d)\n", dev->name, t);
- receive_packet(dev, t);
- } else {
- adapter->busy = 0;
- }
- } else {
- /* has one timed out? */
- check_3c505_dma(dev);
- }
-
- /*
- * receive a PCB from the adapter
- */
- timeout = jiffies + 3*HZ/100;
- while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
- if (receive_pcb(dev, &adapter->irx_pcb)) {
- switch (adapter->irx_pcb.command)
- {
- case 0:
- break;
- /*
- * received a packet - this must be handled fast
- */
- case 0xff:
- case CMD_RECEIVE_PACKET_COMPLETE:
- /* if the device isn't open, don't pass packets up the stack */
- if (!netif_running(dev))
- break;
- len = adapter->irx_pcb.data.rcv_resp.pkt_len;
- dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
- if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
- pr_err("%s: interrupt - packet not received correctly\n", dev->name);
- } else {
- if (elp_debug >= 3) {
- pr_debug("%s: interrupt - packet received of length %i (%i)\n",
- dev->name, len, dlen);
- }
- if (adapter->irx_pcb.command == 0xff) {
- if (elp_debug >= 2)
- pr_debug("%s: adding packet to backlog (len = %d)\n",
- dev->name, dlen);
- adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen;
- adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in);
- } else {
- receive_packet(dev, dlen);
- }
- if (elp_debug >= 3)
- pr_debug("%s: packet received\n", dev->name);
- }
- break;
-
- /*
- * 82586 configured correctly
- */
- case CMD_CONFIGURE_82586_RESPONSE:
- adapter->got[CMD_CONFIGURE_82586] = 1;
- if (elp_debug >= 3)
- pr_debug("%s: interrupt - configure response received\n", dev->name);
- break;
-
- /*
- * Adapter memory configuration
- */
- case CMD_CONFIGURE_ADAPTER_RESPONSE:
- adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
- if (elp_debug >= 3)
- pr_debug("%s: Adapter memory configuration %s.\n", dev->name,
- adapter->irx_pcb.data.failed ? "failed" : "succeeded");
- break;
-
- /*
- * Multicast list loading
- */
- case CMD_LOAD_MULTICAST_RESPONSE:
- adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
- if (elp_debug >= 3)
- pr_debug("%s: Multicast address list loading %s.\n", dev->name,
- adapter->irx_pcb.data.failed ? "failed" : "succeeded");
- break;
-
- /*
- * Station address setting
- */
- case CMD_SET_ADDRESS_RESPONSE:
- adapter->got[CMD_SET_STATION_ADDRESS] = 1;
- if (elp_debug >= 3)
- pr_debug("%s: Ethernet address setting %s.\n", dev->name,
- adapter->irx_pcb.data.failed ? "failed" : "succeeded");
- break;
-
-
- /*
- * received board statistics
- */
- case CMD_NETWORK_STATISTICS_RESPONSE:
- dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
- dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
- dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
- dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
- dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
- dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
- adapter->got[CMD_NETWORK_STATISTICS] = 1;
- if (elp_debug >= 3)
- pr_debug("%s: interrupt - statistics response received\n", dev->name);
- break;
-
- /*
- * sent a packet
- */
- case CMD_TRANSMIT_PACKET_COMPLETE:
- if (elp_debug >= 3)
- pr_debug("%s: interrupt - packet sent\n", dev->name);
- if (!netif_running(dev))
- break;
- switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
- case 0xffff:
- dev->stats.tx_aborted_errors++;
- pr_info("%s: transmit timed out, network cable problem?\n", dev->name);
- break;
- case 0xfffe:
- dev->stats.tx_fifo_errors++;
- pr_info("%s: transmit timed out, FIFO underrun\n", dev->name);
- break;
- }
- netif_wake_queue(dev);
- break;
-
- /*
- * some unknown PCB
- */
- default:
- pr_debug("%s: unknown PCB received - %2.2x\n",
- dev->name, adapter->irx_pcb.command);
- break;
- }
- } else {
- pr_warning("%s: failed to read PCB on interrupt\n", dev->name);
- adapter_reset(dev);
- }
- }
-
- } while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE)));
-
- prime_rx(dev);
-
- /*
- * indicate no longer in interrupt routine
- */
- spin_unlock(&adapter->lock);
- return IRQ_HANDLED;
-}
-
-
-/******************************************************
- *
- * open the board
- *
- ******************************************************/
-
-static int elp_open(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
- int retval;
-
- if (elp_debug >= 3)
- pr_debug("%s: request to open device\n", dev->name);
-
- /*
- * make sure we actually found the device
- */
- if (adapter == NULL) {
- pr_err("%s: Opening a non-existent physical device\n", dev->name);
- return -EAGAIN;
- }
- /*
- * disable interrupts on the board
- */
- outb_control(0, dev);
-
- /*
- * clear any pending interrupts
- */
- inb_command(dev->base_addr);
- adapter_reset(dev);
-
- /*
- * no receive PCBs active
- */
- adapter->rx_active = 0;
-
- adapter->busy = 0;
- adapter->send_pcb_semaphore = 0;
- adapter->rx_backlog.in = 0;
- adapter->rx_backlog.out = 0;
-
- spin_lock_init(&adapter->lock);
-
- /*
- * install our interrupt service routine
- */
- if ((retval = request_irq(dev->irq, elp_interrupt, 0, dev->name, dev))) {
- pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq);
- return retval;
- }
- if ((retval = request_dma(dev->dma, dev->name))) {
- free_irq(dev->irq, dev);
- pr_err("%s: could not allocate DMA%d channel\n", dev->name, dev->dma);
- return retval;
- }
- adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE);
- if (!adapter->dma_buffer) {
- pr_err("%s: could not allocate DMA buffer\n", dev->name);
- free_dma(dev->dma);
- free_irq(dev->irq, dev);
- return -ENOMEM;
- }
- adapter->dmaing = 0;
-
- /*
- * enable interrupts on the board
- */
- outb_control(CMDE, dev);
-
- /*
- * configure adapter memory: we need 10 multicast addresses, default==0
- */
- if (elp_debug >= 3)
- pr_debug("%s: sending 3c505 memory configuration command\n", dev->name);
- adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
- adapter->tx_pcb.data.memconf.cmd_q = 10;
- adapter->tx_pcb.data.memconf.rcv_q = 20;
- adapter->tx_pcb.data.memconf.mcast = 10;
- adapter->tx_pcb.data.memconf.frame = 20;
- adapter->tx_pcb.data.memconf.rcv_b = 20;
- adapter->tx_pcb.data.memconf.progs = 0;
- adapter->tx_pcb.length = sizeof(struct Memconf);
- adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;
- if (!send_pcb(dev, &adapter->tx_pcb))
- pr_err("%s: couldn't send memory configuration command\n", dev->name);
- else {
- unsigned long timeout = jiffies + TIMEOUT;
- while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout))
- TIMEOUT_MSG(__LINE__);
- }
-
-
- /*
- * configure adapter to receive broadcast messages and wait for response
- */
- if (elp_debug >= 3)
- pr_debug("%s: sending 82586 configure command\n", dev->name);
- adapter->tx_pcb.command = CMD_CONFIGURE_82586;
- adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
- adapter->tx_pcb.length = 2;
- adapter->got[CMD_CONFIGURE_82586] = 0;
- if (!send_pcb(dev, &adapter->tx_pcb))
- pr_err("%s: couldn't send 82586 configure command\n", dev->name);
- else {
- unsigned long timeout = jiffies + TIMEOUT;
- while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout))
- TIMEOUT_MSG(__LINE__);
- }
-
- /* enable burst-mode DMA */
- /* outb(0x1, dev->base_addr + PORT_AUXDMA); */
-
- /*
- * queue receive commands to provide buffering
- */
- prime_rx(dev);
- if (elp_debug >= 3)
- pr_debug("%s: %d receive PCBs active\n", dev->name, adapter->rx_active);
-
- /*
- * device is now officially open!
- */
-
- netif_start_queue(dev);
- return 0;
-}
-
-
-/******************************************************
- *
- * send a packet to the adapter
- *
- ******************************************************/
-
-static netdev_tx_t send_packet(struct net_device *dev, struct sk_buff *skb)
-{
- elp_device *adapter = netdev_priv(dev);
- unsigned long target;
- unsigned long flags;
-
- /*
- * make sure the length is even and no shorter than 60 bytes
- */
- unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
-
- if (test_and_set_bit(0, (void *) &adapter->busy)) {
- if (elp_debug >= 2)
- pr_debug("%s: transmit blocked\n", dev->name);
- return false;
- }
-
- dev->stats.tx_bytes += nlen;
-
- /*
- * send the adapter a transmit packet command. Ignore segment and offset
- * and make sure the length is even
- */
- adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;
- adapter->tx_pcb.length = sizeof(struct Xmit_pkt);
- adapter->tx_pcb.data.xmit_pkt.buf_ofs
- = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0; /* Unused */
- adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen;
-
- if (!send_pcb(dev, &adapter->tx_pcb)) {
- adapter->busy = 0;
- return false;
- }
- /* if this happens, we die */
- if (test_and_set_bit(0, (void *) &adapter->dmaing))
- pr_debug("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction);
-
- adapter->current_dma.direction = 1;
- adapter->current_dma.start_time = jiffies;
-
- if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
- skb_copy_from_linear_data(skb, adapter->dma_buffer, nlen);
- memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
- target = isa_virt_to_bus(adapter->dma_buffer);
- }
- else {
- target = isa_virt_to_bus(skb->data);
- }
- adapter->current_dma.skb = skb;
-
- flags=claim_dma_lock();
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, 0x48); /* dma memory -> io */
- set_dma_addr(dev->dma, target);
- set_dma_count(dev->dma, nlen);
- outb_control(adapter->hcr_val | DMAE | TCEN, dev);
- enable_dma(dev->dma);
- release_dma_lock(flags);
-
- if (elp_debug >= 3)
- pr_debug("%s: DMA transfer started\n", dev->name);
-
- return true;
-}
-
-/*
- * The upper layer thinks we timed out
- */
-
-static void elp_timeout(struct net_device *dev)
-{
- int stat;
-
- stat = inb_status(dev->base_addr);
- pr_warning("%s: transmit timed out, lost %s?\n", dev->name,
- (stat & ACRF) ? "interrupt" : "command");
- if (elp_debug >= 1)
- pr_debug("%s: status %#02x\n", dev->name, stat);
- dev->trans_start = jiffies; /* prevent tx timeout */
- dev->stats.tx_dropped++;
- netif_wake_queue(dev);
-}
-
-/******************************************************
- *
- * start the transmitter
- * return 0 if sent OK, else return 1
- *
- ******************************************************/
-
-static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- unsigned long flags;
- elp_device *adapter = netdev_priv(dev);
-
- spin_lock_irqsave(&adapter->lock, flags);
- check_3c505_dma(dev);
-
- if (elp_debug >= 3)
- pr_debug("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
-
- netif_stop_queue(dev);
-
- /*
- * send the packet at skb->data for skb->len
- */
- if (!send_packet(dev, skb)) {
- if (elp_debug >= 2) {
- pr_debug("%s: failed to transmit packet\n", dev->name);
- }
- spin_unlock_irqrestore(&adapter->lock, flags);
- return NETDEV_TX_BUSY;
- }
- if (elp_debug >= 3)
- pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len);
-
- prime_rx(dev);
- spin_unlock_irqrestore(&adapter->lock, flags);
- netif_start_queue(dev);
- return NETDEV_TX_OK;
-}
-
-/******************************************************
- *
- * return statistics on the board
- *
- ******************************************************/
-
-static struct net_device_stats *elp_get_stats(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
-
- if (elp_debug >= 3)
- pr_debug("%s: request for stats\n", dev->name);
-
- /* If the device is closed, just return the latest stats we have,
- - we cannot ask from the adapter without interrupts */
- if (!netif_running(dev))
- return &dev->stats;
-
- /* send a get statistics command to the board */
- adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
- adapter->tx_pcb.length = 0;
- adapter->got[CMD_NETWORK_STATISTICS] = 0;
- if (!send_pcb(dev, &adapter->tx_pcb))
- pr_err("%s: couldn't send get statistics command\n", dev->name);
- else {
- unsigned long timeout = jiffies + TIMEOUT;
- while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout)) {
- TIMEOUT_MSG(__LINE__);
- return &dev->stats;
- }
- }
-
- /* statistics are now up to date */
- return &dev->stats;
-}
-
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
- return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
- debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
- .get_msglevel = netdev_get_msglevel,
- .set_msglevel = netdev_set_msglevel,
-};
-
-/******************************************************
- *
- * close the board
- *
- ******************************************************/
-
-static int elp_close(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
-
- if (elp_debug >= 3)
- pr_debug("%s: request to close device\n", dev->name);
-
- netif_stop_queue(dev);
-
- /* Someone may request the device statistic information even when
- * the interface is closed. The following will update the statistics
- * structure in the driver, so we'll be able to give current statistics.
- */
- (void) elp_get_stats(dev);
-
- /*
- * disable interrupts on the board
- */
- outb_control(0, dev);
-
- /*
- * release the IRQ
- */
- free_irq(dev->irq, dev);
-
- free_dma(dev->dma);
- free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
-
- return 0;
-}
-
-
-/************************************************************
- *
- * Set multicast list
- * num_addrs==0: clear mc_list
- * num_addrs==-1: set promiscuous mode
- * num_addrs>0: set mc_list
- *
- ************************************************************/
-
-static void elp_set_mc_list(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
- struct netdev_hw_addr *ha;
- int i;
- unsigned long flags;
-
- if (elp_debug >= 3)
- pr_debug("%s: request to set multicast list\n", dev->name);
-
- spin_lock_irqsave(&adapter->lock, flags);
-
- if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
- /* send a "load multicast list" command to the board, max 10 addrs/cmd */
- /* if num_addrs==0 the list will be cleared */
- adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
- adapter->tx_pcb.length = 6 * netdev_mc_count(dev);
- i = 0;
- netdev_for_each_mc_addr(ha, dev)
- memcpy(adapter->tx_pcb.data.multicast[i++],
- ha->addr, 6);
- adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
- if (!send_pcb(dev, &adapter->tx_pcb))
- pr_err("%s: couldn't send set_multicast command\n", dev->name);
- else {
- unsigned long timeout = jiffies + TIMEOUT;
- while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout)) {
- TIMEOUT_MSG(__LINE__);
- }
- }
- if (!netdev_mc_empty(dev))
- adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;
- else /* num_addrs == 0 */
- adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
- } else
- adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC;
- /*
- * configure adapter to receive messages (as specified above)
- * and wait for response
- */
- if (elp_debug >= 3)
- pr_debug("%s: sending 82586 configure command\n", dev->name);
- adapter->tx_pcb.command = CMD_CONFIGURE_82586;
- adapter->tx_pcb.length = 2;
- adapter->got[CMD_CONFIGURE_82586] = 0;
- if (!send_pcb(dev, &adapter->tx_pcb))
- {
- spin_unlock_irqrestore(&adapter->lock, flags);
- pr_err("%s: couldn't send 82586 configure command\n", dev->name);
- }
- else {
- unsigned long timeout = jiffies + TIMEOUT;
- spin_unlock_irqrestore(&adapter->lock, flags);
- while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
- if (time_after_eq(jiffies, timeout))
- TIMEOUT_MSG(__LINE__);
- }
-}
-
-/************************************************************
- *
- * A couple of tests to see if there's 3C505 or not
- * Called only by elp_autodetect
- ************************************************************/
-
-static int __init elp_sense(struct net_device *dev)
-{
- int addr = dev->base_addr;
- const char *name = dev->name;
- byte orig_HSR;
-
- if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
- return -ENODEV;
-
- orig_HSR = inb_status(addr);
-
- if (elp_debug > 0)
- pr_debug(search_msg, name, addr);
-
- if (orig_HSR == 0xff) {
- if (elp_debug > 0)
- pr_cont(notfound_msg, 1);
- goto out;
- }
-
- /* Wait for a while; the adapter may still be booting up */
- if (elp_debug > 0)
- pr_cont(stilllooking_msg);
-
- if (orig_HSR & DIR) {
- /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
- outb(0, dev->base_addr + PORT_CONTROL);
- msleep(300);
- if (inb_status(addr) & DIR) {
- if (elp_debug > 0)
- pr_cont(notfound_msg, 2);
- goto out;
- }
- } else {
- /* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
- outb(DIR, dev->base_addr + PORT_CONTROL);
- msleep(300);
- if (!(inb_status(addr) & DIR)) {
- if (elp_debug > 0)
- pr_cont(notfound_msg, 3);
- goto out;
- }
- }
- /*
- * It certainly looks like a 3c505.
- */
- if (elp_debug > 0)
- pr_cont(found_msg);
-
- return 0;
-out:
- release_region(addr, ELP_IO_EXTENT);
- return -ENODEV;
-}
-
-/*************************************************************
- *
- * Search through addr_list[] and try to find a 3C505
- * Called only by eplus_probe
- *************************************************************/
-
-static int __init elp_autodetect(struct net_device *dev)
-{
- int idx = 0;
-
- /* if base address set, then only check that address
- otherwise, run through the table */
- if (dev->base_addr != 0) { /* dev->base_addr == 0 ==> plain autodetect */
- if (elp_sense(dev) == 0)
- return dev->base_addr;
- } else
- while ((dev->base_addr = addr_list[idx++])) {
- if (elp_sense(dev) == 0)
- return dev->base_addr;
- }
-
- /* could not find an adapter */
- if (elp_debug > 0)
- pr_debug(couldnot_msg, dev->name);
-
- return 0; /* Because of this, the layer above will return -ENODEV */
-}
-
-static const struct net_device_ops elp_netdev_ops = {
- .ndo_open = elp_open,
- .ndo_stop = elp_close,
- .ndo_get_stats = elp_get_stats,
- .ndo_start_xmit = elp_start_xmit,
- .ndo_tx_timeout = elp_timeout,
- .ndo_set_rx_mode = elp_set_mc_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/******************************************************
- *
- * probe for an Etherlink Plus board at the specified address
- *
- ******************************************************/
-
-/* There are three situations we need to be able to detect here:
-
- * a) the card is idle
- * b) the card is still booting up
- * c) the card is stuck in a strange state (some DOS drivers do this)
- *
- * In case (a), all is well. In case (b), we wait 10 seconds to see if the
- * card finishes booting, and carry on if so. In case (c), we do a hard reset,
- * loop round, and hope for the best.
- *
- * This is all very unpleasant, but hopefully avoids the problems with the old
- * probe code (which had a 15-second delay if the card was idle, and didn't
- * work at all if it was in a weird state).
- */
-
-static int __init elplus_setup(struct net_device *dev)
-{
- elp_device *adapter = netdev_priv(dev);
- int i, tries, tries1, okay;
- unsigned long timeout;
- unsigned long cookie = 0;
- int err = -ENODEV;
-
- /*
- * setup adapter structure
- */
-
- dev->base_addr = elp_autodetect(dev);
- if (!dev->base_addr)
- return -ENODEV;
-
- adapter->send_pcb_semaphore = 0;
-
- for (tries1 = 0; tries1 < 3; tries1++) {
- outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);
- /* First try to write just one byte, to see if the card is
- * responding at all normally.
- */
- timeout = jiffies + 5*HZ/100;
- okay = 0;
- while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
- if ((inb_status(dev->base_addr) & HCRE)) {
- outb_command(0, dev->base_addr); /* send a spurious byte */
- timeout = jiffies + 5*HZ/100;
- while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
- if (inb_status(dev->base_addr) & HCRE)
- okay = 1;
- }
- if (!okay) {
- /* Nope, it's ignoring the command register. This means that
- * either it's still booting up, or it's died.
- */
- pr_err("%s: command register wouldn't drain, ", dev->name);
- if ((inb_status(dev->base_addr) & 7) == 3) {
- /* If the adapter status is 3, it *could* still be booting.
- * Give it the benefit of the doubt for 10 seconds.
- */
- pr_cont("assuming 3c505 still starting\n");
- timeout = jiffies + 10*HZ;
- while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));
- if (inb_status(dev->base_addr) & 7) {
- pr_err("%s: 3c505 failed to start\n", dev->name);
- } else {
- okay = 1; /* It started */
- }
- } else {
- /* Otherwise, it must just be in a strange
- * state. We probably need to kick it.
- */
- pr_cont("3c505 is sulking\n");
- }
- }
- for (tries = 0; tries < 5 && okay; tries++) {
-
- /*
- * Try to set the Ethernet address, to make sure that the board
- * is working.
- */
- adapter->tx_pcb.command = CMD_STATION_ADDRESS;
- adapter->tx_pcb.length = 0;
- cookie = probe_irq_on();
- if (!send_pcb(dev, &adapter->tx_pcb)) {
- pr_err("%s: could not send first PCB\n", dev->name);
- probe_irq_off(cookie);
- continue;
- }
- if (!receive_pcb(dev, &adapter->rx_pcb)) {
- pr_err("%s: could not read first PCB\n", dev->name);
- probe_irq_off(cookie);
- continue;
- }
- if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
- (adapter->rx_pcb.length != 6)) {
- pr_err("%s: first PCB wrong (%d, %d)\n", dev->name,
- adapter->rx_pcb.command, adapter->rx_pcb.length);
- probe_irq_off(cookie);
- continue;
- }
- goto okay;
- }
- /* It's broken. Do a hard reset to re-initialise the board,
- * and try again.
- */
- pr_info("%s: resetting adapter\n", dev->name);
- outb_control(adapter->hcr_val | FLSH | ATTN, dev);
- outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
- }
- pr_err("%s: failed to initialise 3c505\n", dev->name);
- goto out;
-
- okay:
- if (dev->irq) { /* Is there a preset IRQ? */
- int rpt = probe_irq_off(cookie);
- if (dev->irq != rpt) {
- pr_warning("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
- }
- /* if dev->irq == probe_irq_off(cookie), all is well */
- } else /* No preset IRQ; just use what we can detect */
- dev->irq = probe_irq_off(cookie);
- switch (dev->irq) { /* Legal, sane? */
- case 0:
- pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n",
- dev->name);
- goto out;
- case 1:
- case 6:
- case 8:
- case 13:
- pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n",
- dev->name, dev->irq);
- goto out;
- }
- /*
- * Now we have the IRQ number so we can disable the interrupts from
- * the board until the board is opened.
- */
- outb_control(adapter->hcr_val & ~CMDE, dev);
-
- /*
- * copy Ethernet address into structure
- */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];
-
- /* find a DMA channel */
- if (!dev->dma) {
- if (dev->mem_start) {
- dev->dma = dev->mem_start & 7;
- }
- else {
- pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name);
- dev->dma = ELP_DMA;
- }
- }
-
- /*
- * print remainder of startup message
- */
- pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ",
- dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr);
- /*
- * read more information from the adapter
- */
-
- adapter->tx_pcb.command = CMD_ADAPTER_INFO;
- adapter->tx_pcb.length = 0;
- if (!send_pcb(dev, &adapter->tx_pcb) ||
- !receive_pcb(dev, &adapter->rx_pcb) ||
- (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
- (adapter->rx_pcb.length != 10)) {
- pr_cont("not responding to second PCB\n");
- }
- pr_cont("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers,
- adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);
-
- /*
- * reconfigure the adapter memory to better suit our purposes
- */
- adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
- adapter->tx_pcb.length = 12;
- adapter->tx_pcb.data.memconf.cmd_q = 8;
- adapter->tx_pcb.data.memconf.rcv_q = 8;
- adapter->tx_pcb.data.memconf.mcast = 10;
- adapter->tx_pcb.data.memconf.frame = 10;
- adapter->tx_pcb.data.memconf.rcv_b = 10;
- adapter->tx_pcb.data.memconf.progs = 0;
- if (!send_pcb(dev, &adapter->tx_pcb) ||
- !receive_pcb(dev, &adapter->rx_pcb) ||
- (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
- (adapter->rx_pcb.length != 2)) {
- pr_err("%s: could not configure adapter memory\n", dev->name);
- }
- if (adapter->rx_pcb.data.configure) {
- pr_err("%s: adapter configuration failed\n", dev->name);
- }
-
- dev->netdev_ops = &elp_netdev_ops;
- dev->watchdog_timeo = 10*HZ;
- dev->ethtool_ops = &netdev_ethtool_ops; /* local */
-
- dev->mem_start = dev->mem_end = 0;
-
- err = register_netdev(dev);
- if (err)
- goto out;
-
- return 0;
-out:
- release_region(dev->base_addr, ELP_IO_EXTENT);
- return err;
-}
-
-#ifndef MODULE
-struct net_device * __init elplus_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(elp_device));
- int err;
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = elplus_setup(dev);
- if (err) {
- free_netdev(dev);
- return ERR_PTR(err);
- }
- return dev;
-}
-
-#else
-static struct net_device *dev_3c505[ELP_MAX_CARDS];
-static int io[ELP_MAX_CARDS];
-static int irq[ELP_MAX_CARDS];
-static int dma[ELP_MAX_CARDS];
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(dma, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");
-MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");
-
-int __init init_module(void)
-{
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
- struct net_device *dev = alloc_etherdev(sizeof(elp_device));
- if (!dev)
- break;
-
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- if (dma[this_dev]) {
- dev->dma = dma[this_dev];
- } else {
- dev->dma = ELP_DMA;
- pr_warning("3c505.c: warning, using default DMA channel,\n");
- }
- if (io[this_dev] == 0) {
- if (this_dev) {
- free_netdev(dev);
- break;
- }
- pr_notice("3c505.c: module autoprobe not recommended, give io=xx.\n");
- }
- if (elplus_setup(dev) != 0) {
- pr_warning("3c505.c: Failed to register card at 0x%x.\n", io[this_dev]);
- free_netdev(dev);
- break;
- }
- dev_3c505[this_dev] = dev;
- found++;
- }
- if (!found)
- return -ENODEV;
- return 0;
-}
-
-void __exit cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
- struct net_device *dev = dev_3c505[this_dev];
- if (dev) {
- unregister_netdev(dev);
- release_region(dev->base_addr, ELP_IO_EXTENT);
- free_netdev(dev);
- }
- }
-}
-
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/3c505.h b/drivers/net/ethernet/i825xx/3c505.h
deleted file mode 100644
index 04df2a9002b6..000000000000
--- a/drivers/net/ethernet/i825xx/3c505.h
+++ /dev/null
@@ -1,292 +0,0 @@
-/*****************************************************************
- *
- * defines for 3Com Etherlink Plus adapter
- *
- *****************************************************************/
-
-#define ELP_DMA 6
-#define ELP_RX_PCBS 4
-#define ELP_MAX_CARDS 4
-
-/*
- * I/O register offsets
- */
-#define PORT_COMMAND 0x00 /* read/write, 8-bit */
-#define PORT_STATUS 0x02 /* read only, 8-bit */
-#define PORT_AUXDMA 0x02 /* write only, 8-bit */
-#define PORT_DATA 0x04 /* read/write, 16-bit */
-#define PORT_CONTROL 0x06 /* read/write, 8-bit */
-
-#define ELP_IO_EXTENT 0x10 /* size of used IO registers */
-
-/*
- * host control registers bits
- */
-#define ATTN 0x80 /* attention */
-#define FLSH 0x40 /* flush data register */
-#define DMAE 0x20 /* DMA enable */
-#define DIR 0x10 /* direction */
-#define TCEN 0x08 /* terminal count interrupt enable */
-#define CMDE 0x04 /* command register interrupt enable */
-#define HSF2 0x02 /* host status flag 2 */
-#define HSF1 0x01 /* host status flag 1 */
-
-/*
- * combinations of HSF flags used for PCB transmission
- */
-#define HSF_PCB_ACK HSF1
-#define HSF_PCB_NAK HSF2
-#define HSF_PCB_END (HSF2|HSF1)
-#define HSF_PCB_MASK (HSF2|HSF1)
-
-/*
- * host status register bits
- */
-#define HRDY 0x80 /* data register ready */
-#define HCRE 0x40 /* command register empty */
-#define ACRF 0x20 /* adapter command register full */
-/* #define DIR 0x10 direction - same as in control register */
-#define DONE 0x08 /* DMA done */
-#define ASF3 0x04 /* adapter status flag 3 */
-#define ASF2 0x02 /* adapter status flag 2 */
-#define ASF1 0x01 /* adapter status flag 1 */
-
-/*
- * combinations of ASF flags used for PCB reception
- */
-#define ASF_PCB_ACK ASF1
-#define ASF_PCB_NAK ASF2
-#define ASF_PCB_END (ASF2|ASF1)
-#define ASF_PCB_MASK (ASF2|ASF1)
-
-/*
- * host aux DMA register bits
- */
-#define DMA_BRST 0x01 /* DMA burst */
-
-/*
- * maximum amount of data allowed in a PCB
- */
-#define MAX_PCB_DATA 62
-
-/*****************************************************************
- *
- * timeout value
- * this is a rough value used for loops to stop them from
- * locking up the whole machine in the case of failure or
- * error conditions
- *
- *****************************************************************/
-
-#define TIMEOUT 300
-
-/*****************************************************************
- *
- * PCB commands
- *
- *****************************************************************/
-
-enum {
- /*
- * host PCB commands
- */
- CMD_CONFIGURE_ADAPTER_MEMORY = 0x01,
- CMD_CONFIGURE_82586 = 0x02,
- CMD_STATION_ADDRESS = 0x03,
- CMD_DMA_DOWNLOAD = 0x04,
- CMD_DMA_UPLOAD = 0x05,
- CMD_PIO_DOWNLOAD = 0x06,
- CMD_PIO_UPLOAD = 0x07,
- CMD_RECEIVE_PACKET = 0x08,
- CMD_TRANSMIT_PACKET = 0x09,
- CMD_NETWORK_STATISTICS = 0x0a,
- CMD_LOAD_MULTICAST_LIST = 0x0b,
- CMD_CLEAR_PROGRAM = 0x0c,
- CMD_DOWNLOAD_PROGRAM = 0x0d,
- CMD_EXECUTE_PROGRAM = 0x0e,
- CMD_SELF_TEST = 0x0f,
- CMD_SET_STATION_ADDRESS = 0x10,
- CMD_ADAPTER_INFO = 0x11,
- NUM_TRANSMIT_CMDS,
-
- /*
- * adapter PCB commands
- */
- CMD_CONFIGURE_ADAPTER_RESPONSE = 0x31,
- CMD_CONFIGURE_82586_RESPONSE = 0x32,
- CMD_ADDRESS_RESPONSE = 0x33,
- CMD_DOWNLOAD_DATA_REQUEST = 0x34,
- CMD_UPLOAD_DATA_REQUEST = 0x35,
- CMD_RECEIVE_PACKET_COMPLETE = 0x38,
- CMD_TRANSMIT_PACKET_COMPLETE = 0x39,
- CMD_NETWORK_STATISTICS_RESPONSE = 0x3a,
- CMD_LOAD_MULTICAST_RESPONSE = 0x3b,
- CMD_CLEAR_PROGRAM_RESPONSE = 0x3c,
- CMD_DOWNLOAD_PROGRAM_RESPONSE = 0x3d,
- CMD_EXECUTE_RESPONSE = 0x3e,
- CMD_SELF_TEST_RESPONSE = 0x3f,
- CMD_SET_ADDRESS_RESPONSE = 0x40,
- CMD_ADAPTER_INFO_RESPONSE = 0x41
-};
-
-/* Definitions for the PCB data structure */
-
-/* Data units */
-typedef unsigned char byte;
-typedef unsigned short int word;
-typedef unsigned long int dword;
-
-/* Data structures */
-struct Memconf {
- word cmd_q,
- rcv_q,
- mcast,
- frame,
- rcv_b,
- progs;
-};
-
-struct Rcv_pkt {
- word buf_ofs,
- buf_seg,
- buf_len,
- timeout;
-};
-
-struct Xmit_pkt {
- word buf_ofs,
- buf_seg,
- pkt_len;
-};
-
-struct Rcv_resp {
- word buf_ofs,
- buf_seg,
- buf_len,
- pkt_len,
- timeout,
- status;
- dword timetag;
-};
-
-struct Xmit_resp {
- word buf_ofs,
- buf_seg,
- c_stat,
- status;
-};
-
-
-struct Netstat {
- dword tot_recv,
- tot_xmit;
- word err_CRC,
- err_align,
- err_res,
- err_ovrrun;
-};
-
-
-struct Selftest {
- word error;
- union {
- word ROM_cksum;
- struct {
- word ofs, seg;
- } RAM;
- word i82586;
- } failure;
-};
-
-struct Info {
- byte minor_vers,
- major_vers;
- word ROM_cksum,
- RAM_sz,
- free_ofs,
- free_seg;
-};
-
-struct Memdump {
- word size,
- off,
- seg;
-};
-
-/*
-Primary Command Block. The most important data structure. All communication
-between the host and the adapter is done with these. (Except for the actual
-Ethernet data, which has different packaging.)
-*/
-typedef struct {
- byte command;
- byte length;
- union {
- struct Memconf memconf;
- word configure;
- struct Rcv_pkt rcv_pkt;
- struct Xmit_pkt xmit_pkt;
- byte multicast[10][6];
- byte eth_addr[6];
- byte failed;
- struct Rcv_resp rcv_resp;
- struct Xmit_resp xmit_resp;
- struct Netstat netstat;
- struct Selftest selftest;
- struct Info info;
- struct Memdump memdump;
- byte raw[62];
- } data;
-} pcb_struct;
-
-/* These defines for 'configure' */
-#define RECV_STATION 0x00
-#define RECV_BROAD 0x01
-#define RECV_MULTI 0x02
-#define RECV_PROMISC 0x04
-#define NO_LOOPBACK 0x00
-#define INT_LOOPBACK 0x08
-#define EXT_LOOPBACK 0x10
-
-/*****************************************************************
- *
- * structure to hold context information for adapter
- *
- *****************************************************************/
-
-#define DMA_BUFFER_SIZE 1600
-#define BACKLOG_SIZE 4
-
-typedef struct {
- volatile short got[NUM_TRANSMIT_CMDS]; /* flags for
- command completion */
- pcb_struct tx_pcb; /* PCB for foreground sending */
- pcb_struct rx_pcb; /* PCB for foreground receiving */
- pcb_struct itx_pcb; /* PCB for background sending */
- pcb_struct irx_pcb; /* PCB for background receiving */
-
- void *dma_buffer;
-
- struct {
- unsigned int length[BACKLOG_SIZE];
- unsigned int in;
- unsigned int out;
- } rx_backlog;
-
- struct {
- unsigned int direction;
- unsigned int length;
- struct sk_buff *skb;
- void *target;
- unsigned long start_time;
- } current_dma;
-
- /* flags */
- unsigned long send_pcb_semaphore;
- unsigned long dmaing;
- unsigned long busy;
-
- unsigned int rx_active; /* number of receive PCBs */
- volatile unsigned char hcr_val; /* what we think the HCR contains */
- spinlock_t lock; /* Interrupt v tx lock */
-} elp_device;
diff --git a/drivers/net/ethernet/i825xx/3c507.c b/drivers/net/ethernet/i825xx/3c507.c
deleted file mode 100644
index e8984b059905..000000000000
--- a/drivers/net/ethernet/i825xx/3c507.c
+++ /dev/null
@@ -1,938 +0,0 @@
-/* 3c507.c: An EtherLink16 device driver for Linux. */
-/*
- Written 1993,1994 by Donald Becker.
-
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
-
- Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
- and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
- Mark Salazar <leslie@access.digex.net> made the changes for cards with
- only 16K packet buffers.
-
- Things remaining to do:
- Verify that the tx and rx buffers don't have fencepost errors.
- Move the theory of operation and memory map documentation.
- The statistics need to be updated correctly.
-*/
-
-#define DRV_NAME "3c507"
-#define DRV_VERSION "1.10a"
-#define DRV_RELDATE "11/17/2001"
-
-static const char version[] =
- DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n";
-
-/*
- Sources:
- This driver wouldn't have been written with the availability of the
- Crynwr driver source code. It provided a known-working implementation
- that filled in the gaping holes of the Intel documentation. Three cheers
- for Russ Nelson.
-
- Intel Microcommunications Databook, Vol. 1, 1990. It provides just enough
- info that the casual reader might think that it documents the i82586 :-<.
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-/* use 0 for production, 1 for verification, 2..7 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-#define debug net_debug
-
-
-/*
- Details of the i82586.
-
- You'll really need the databook to understand the details of this part,
- but the outline is that the i82586 has two separate processing units.
- Both are started from a list of three configuration tables, of which only
- the last, the System Control Block (SCB), is used after reset-time. The SCB
- has the following fields:
- Status word
- Command word
- Tx/Command block addr.
- Rx block addr.
- The command word accepts the following controls for the Tx and Rx units:
- */
-
-#define CUC_START 0x0100
-#define CUC_RESUME 0x0200
-#define CUC_SUSPEND 0x0300
-#define RX_START 0x0010
-#define RX_RESUME 0x0020
-#define RX_SUSPEND 0x0030
-
-/* The Rx unit uses a list of frame descriptors and a list of data buffer
- descriptors. We use full-sized (1518 byte) data buffers, so there is
- a one-to-one pairing of frame descriptors to buffer descriptors.
-
- The Tx ("command") unit executes a list of commands that look like:
- Status word Written by the 82586 when the command is done.
- Command word Command in lower 3 bits, post-command action in upper 3
- Link word The address of the next command.
- Parameters (as needed).
-
- Some definitions related to the Command Word are:
- */
-#define CMD_EOL 0x8000 /* The last command of the list, stop. */
-#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
-#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
-
-enum commands {
- CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
- CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
-
-/* Information that need to be kept for each board. */
-struct net_local {
- int last_restart;
- ushort rx_head;
- ushort rx_tail;
- ushort tx_head;
- ushort tx_cmd_link;
- ushort tx_reap;
- ushort tx_pkts_in_ring;
- spinlock_t lock;
- void __iomem *base;
-};
-
-/*
- Details of the EtherLink16 Implementation
- The 3c507 is a generic shared-memory i82586 implementation.
- The host can map 16K, 32K, 48K, or 64K of the 64K memory into
- 0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
- */
-
-/* Offsets from the base I/O address. */
-#define SA_DATA 0 /* Station address data, or 3Com signature. */
-#define MISC_CTRL 6 /* Switch the SA_DATA banks, and bus config bits. */
-#define RESET_IRQ 10 /* Reset the latched IRQ line. */
-#define SIGNAL_CA 11 /* Frob the 82586 Channel Attention line. */
-#define ROM_CONFIG 13
-#define MEM_CONFIG 14
-#define IRQ_CONFIG 15
-#define EL16_IO_EXTENT 16
-
-/* The ID port is used at boot-time to locate the ethercard. */
-#define ID_PORT 0x100
-
-/* Offsets to registers in the mailbox (SCB). */
-#define iSCB_STATUS 0x8
-#define iSCB_CMD 0xA
-#define iSCB_CBL 0xC /* Command BLock offset. */
-#define iSCB_RFA 0xE /* Rx Frame Area offset. */
-
-/* Since the 3c507 maps the shared memory window so that the last byte is
- at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
- 48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
- We can account for this be setting the 'SBC Base' entry in the ISCP table
- below for all the 16 bit offset addresses, and also adding the 'SCB Base'
- value to all 24 bit physical addresses (in the SCP table and the TX and RX
- Buffer Descriptors).
- -Mark
- */
-#define SCB_BASE ((unsigned)64*1024 - (dev->mem_end - dev->mem_start))
-
-/*
- What follows in 'init_words[]' is the "program" that is downloaded to the
- 82586 memory. It's mostly tables and command blocks, and starts at the
- reset address 0xfffff6. This is designed to be similar to the EtherExpress,
- thus the unusual location of the SCB at 0x0008.
-
- Even with the additional "don't care" values, doing it this way takes less
- program space than initializing the individual tables, and I feel it's much
- cleaner.
-
- The databook is particularly useless for the first two structures, I had
- to use the Crynwr driver as an example.
-
- The memory setup is as follows:
- */
-
-#define CONFIG_CMD 0x0018
-#define SET_SA_CMD 0x0024
-#define SA_OFFSET 0x002A
-#define IDLELOOP 0x30
-#define TDR_CMD 0x38
-#define TDR_TIME 0x3C
-#define DUMP_CMD 0x40
-#define DIAG_CMD 0x48
-#define SET_MC_CMD 0x4E
-#define DUMP_DATA 0x56 /* A 170 byte buffer for dump and Set-MC into. */
-
-#define TX_BUF_START 0x0100
-#define NUM_TX_BUFS 5
-#define TX_BUF_SIZE (1518+14+20+16) /* packet+header+TBD */
-
-#define RX_BUF_START 0x2000
-#define RX_BUF_SIZE (1518+14+18) /* packet+header+RBD */
-#define RX_BUF_END (dev->mem_end - dev->mem_start)
-
-#define TX_TIMEOUT (HZ/20)
-
-/*
- That's it: only 86 bytes to set up the beast, including every extra
- command available. The 170 byte buffer at DUMP_DATA is shared between the
- Dump command (called only by the diagnostic program) and the SetMulticastList
- command.
-
- To complete the memory setup you only have to write the station address at
- SA_OFFSET and create the Tx & Rx buffer lists.
-
- The Tx command chain and buffer list is setup as follows:
- A Tx command table, with the data buffer pointing to...
- A Tx data buffer descriptor. The packet is in a single buffer, rather than
- chaining together several smaller buffers.
- A NoOp command, which initially points to itself,
- And the packet data.
-
- A transmit is done by filling in the Tx command table and data buffer,
- re-writing the NoOp command, and finally changing the offset of the last
- command to point to the current Tx command. When the Tx command is finished,
- it jumps to the NoOp, when it loops until the next Tx command changes the
- "link offset" in the NoOp. This way the 82586 never has to go through the
- slow restart sequence.
-
- The Rx buffer list is set up in the obvious ring structure. We have enough
- memory (and low enough interrupt latency) that we can avoid the complicated
- Rx buffer linked lists by alway associating a full-size Rx data buffer with
- each Rx data frame.
-
- I current use four transmit buffers starting at TX_BUF_START (0x0100), and
- use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
-
- */
-
-static unsigned short init_words[] = {
- /* System Configuration Pointer (SCP). */
- 0x0000, /* Set bus size to 16 bits. */
- 0,0, /* pad words. */
- 0x0000,0x0000, /* ISCP phys addr, set in init_82586_mem(). */
-
- /* Intermediate System Configuration Pointer (ISCP). */
- 0x0001, /* Status word that's cleared when init is done. */
- 0x0008,0,0, /* SCB offset, (skip, skip) */
-
- /* System Control Block (SCB). */
- 0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */
- CONFIG_CMD, /* Command list pointer, points to Configure. */
- RX_BUF_START, /* Rx block list. */
- 0,0,0,0, /* Error count: CRC, align, buffer, overrun. */
-
- /* 0x0018: Configure command. Change to put MAC data with packet. */
- 0, CmdConfigure, /* Status, command. */
- SET_SA_CMD, /* Next command is Set Station Addr. */
- 0x0804, /* "4" bytes of config data, 8 byte FIFO. */
- 0x2e40, /* Magic values, including MAC data location. */
- 0, /* Unused pad word. */
-
- /* 0x0024: Setup station address command. */
- 0, CmdSASetup,
- SET_MC_CMD, /* Next command. */
- 0xaa00,0xb000,0x0bad, /* Station address (to be filled in) */
-
- /* 0x0030: NOP, looping back to itself. Point to first Tx buffer to Tx. */
- 0, CmdNOp, IDLELOOP, 0 /* pad */,
-
- /* 0x0038: A unused Time-Domain Reflectometer command. */
- 0, CmdTDR, IDLELOOP, 0,
-
- /* 0x0040: An unused Dump State command. */
- 0, CmdDump, IDLELOOP, DUMP_DATA,
-
- /* 0x0048: An unused Diagnose command. */
- 0, CmdDiagnose, IDLELOOP,
-
- /* 0x004E: An empty set-multicast-list command. */
- 0, CmdMulticastList, IDLELOOP, 0,
-};
-
-/* Index to functions, as function prototypes. */
-
-static int el16_probe1(struct net_device *dev, int ioaddr);
-static int el16_open(struct net_device *dev);
-static netdev_tx_t el16_send_packet(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t el16_interrupt(int irq, void *dev_id);
-static void el16_rx(struct net_device *dev);
-static int el16_close(struct net_device *dev);
-static void el16_tx_timeout (struct net_device *dev);
-
-static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
-static void init_82586_mem(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-static void init_rx_bufs(struct net_device *);
-
-static int io = 0x300;
-static int irq;
-static int mem_start;
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
- If dev->base_addr == 0, probe all likely locations.
- If dev->base_addr == 1, always return failure.
- If dev->base_addr == 2, (detachable devices only) allocate space for the
- device and return success.
- */
-
-struct net_device * __init el16_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- static const unsigned ports[] = { 0x300, 0x320, 0x340, 0x280, 0};
- const unsigned *port;
- int err = -ENODEV;
-
- if (!dev)
- return ERR_PTR(-ENODEV);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
- mem_start = dev->mem_start & 15;
- }
-
- if (io > 0x1ff) /* Check a single specified location. */
- err = el16_probe1(dev, io);
- else if (io != 0)
- err = -ENXIO; /* Don't probe at all. */
- else {
- for (port = ports; *port; port++) {
- err = el16_probe1(dev, *port);
- if (!err)
- break;
- }
- }
-
- if (err)
- goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
-out1:
- free_irq(dev->irq, dev);
- iounmap(((struct net_local *)netdev_priv(dev))->base);
- release_region(dev->base_addr, EL16_IO_EXTENT);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static const struct net_device_ops netdev_ops = {
- .ndo_open = el16_open,
- .ndo_stop = el16_close,
- .ndo_start_xmit = el16_send_packet,
- .ndo_tx_timeout = el16_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int __init el16_probe1(struct net_device *dev, int ioaddr)
-{
- static unsigned char init_ID_done;
- int i, irq, irqval, retval;
- struct net_local *lp;
-
- if (init_ID_done == 0) {
- ushort lrs_state = 0xff;
- /* Send the ID sequence to the ID_PORT to enable the board(s). */
- outb(0x00, ID_PORT);
- for(i = 0; i < 255; i++) {
- outb(lrs_state, ID_PORT);
- lrs_state <<= 1;
- if (lrs_state & 0x100)
- lrs_state ^= 0xe7;
- }
- outb(0x00, ID_PORT);
- init_ID_done = 1;
- }
-
- if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
- return -ENODEV;
-
- if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
- (inb(ioaddr + 2) != 'C') || (inb(ioaddr + 3) != 'O')) {
- retval = -ENODEV;
- goto out;
- }
-
- pr_info("%s: 3c507 at %#x,", dev->name, ioaddr);
-
- /* We should make a few more checks here, like the first three octets of
- the S.A. for the manufacturer's code. */
-
- irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
-
- irqval = request_irq(irq, el16_interrupt, 0, DRV_NAME, dev);
- if (irqval) {
- pr_cont("\n");
- pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval);
- retval = -EAGAIN;
- goto out;
- }
-
- /* We've committed to using the board, and can start filling in *dev. */
- dev->base_addr = ioaddr;
-
- outb(0x01, ioaddr + MISC_CTRL);
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = inb(ioaddr + i);
- pr_cont(" %pM", dev->dev_addr);
-
- if (mem_start)
- net_debug = mem_start & 7;
-
-#ifdef MEM_BASE
- dev->mem_start = MEM_BASE;
- dev->mem_end = dev->mem_start + 0x10000;
-#else
- {
- int base;
- int size;
- char mem_config = inb(ioaddr + MEM_CONFIG);
- if (mem_config & 0x20) {
- size = 64*1024;
- base = 0xf00000 + (mem_config & 0x08 ? 0x080000
- : ((mem_config & 3) << 17));
- } else {
- size = ((mem_config & 3) + 1) << 14;
- base = 0x0c0000 + ( (mem_config & 0x18) << 12);
- }
- dev->mem_start = base;
- dev->mem_end = base + size;
- }
-#endif
-
- dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
- dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
-
- pr_cont(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq,
- dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1);
-
- if (net_debug)
- pr_debug("%s", version);
-
- lp = netdev_priv(dev);
- spin_lock_init(&lp->lock);
- lp->base = ioremap(dev->mem_start, RX_BUF_END);
- if (!lp->base) {
- pr_err("3c507: unable to remap memory\n");
- retval = -EAGAIN;
- goto out1;
- }
-
- dev->netdev_ops = &netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
- dev->ethtool_ops = &netdev_ethtool_ops;
- dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */
- return 0;
-out1:
- free_irq(dev->irq, dev);
-out:
- release_region(ioaddr, EL16_IO_EXTENT);
- return retval;
-}
-
-static int el16_open(struct net_device *dev)
-{
- /* Initialize the 82586 memory and start it. */
- init_82586_mem(dev);
-
- netif_start_queue(dev);
- return 0;
-}
-
-
-static void el16_tx_timeout (struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- void __iomem *shmem = lp->base;
-
- if (net_debug > 1)
- pr_debug("%s: transmit timed out, %s? ", dev->name,
- readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
- "network cable problem");
- /* Try to restart the adaptor. */
- if (lp->last_restart == dev->stats.tx_packets) {
- if (net_debug > 1)
- pr_cont("Resetting board.\n");
- /* Completely reset the adaptor. */
- init_82586_mem (dev);
- lp->tx_pkts_in_ring = 0;
- } else {
- /* Issue the channel attention signal and hope it "gets better". */
- if (net_debug > 1)
- pr_cont("Kicking board.\n");
- writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
- outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
- lp->last_restart = dev->stats.tx_packets;
- }
- dev->trans_start = jiffies; /* prevent tx timeout */
- netif_wake_queue (dev);
-}
-
-
-static netdev_tx_t el16_send_packet (struct sk_buff *skb,
- struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned long flags;
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
-
- netif_stop_queue (dev);
-
- spin_lock_irqsave (&lp->lock, flags);
-
- dev->stats.tx_bytes += length;
- /* Disable the 82586's input to the interrupt line. */
- outb (0x80, ioaddr + MISC_CTRL);
-
- hardware_send_packet (dev, buf, skb->len, length - skb->len);
-
- /* Enable the 82586 interrupt input. */
- outb (0x84, ioaddr + MISC_CTRL);
-
- spin_unlock_irqrestore (&lp->lock, flags);
-
- dev_kfree_skb (skb);
-
- /* You might need to clean up and record Tx statistics here. */
-
- return NETDEV_TX_OK;
-}
-
-/* The typical workload of the driver:
- Handle the network interface interrupts. */
-static irqreturn_t el16_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct net_local *lp;
- int ioaddr, status, boguscount = 0;
- ushort ack_cmd = 0;
- void __iomem *shmem;
-
- if (dev == NULL) {
- pr_err("net_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
- ioaddr = dev->base_addr;
- lp = netdev_priv(dev);
- shmem = lp->base;
-
- spin_lock(&lp->lock);
-
- status = readw(shmem+iSCB_STATUS);
-
- if (net_debug > 4) {
- pr_debug("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
- }
-
- /* Disable the 82586's input to the interrupt line. */
- outb(0x80, ioaddr + MISC_CTRL);
-
- /* Reap the Tx packet buffers. */
- while (lp->tx_pkts_in_ring) {
- unsigned short tx_status = readw(shmem+lp->tx_reap);
- if (!(tx_status & 0x8000)) {
- if (net_debug > 5)
- pr_debug("Tx command incomplete (%#x).\n", lp->tx_reap);
- break;
- }
- /* Tx unsuccessful or some interesting status bit set. */
- if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
- dev->stats.tx_errors++;
- if (tx_status & 0x0600) dev->stats.tx_carrier_errors++;
- if (tx_status & 0x0100) dev->stats.tx_fifo_errors++;
- if (!(tx_status & 0x0040)) dev->stats.tx_heartbeat_errors++;
- if (tx_status & 0x0020) dev->stats.tx_aborted_errors++;
- dev->stats.collisions += tx_status & 0xf;
- }
- dev->stats.tx_packets++;
- if (net_debug > 5)
- pr_debug("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
- lp->tx_reap += TX_BUF_SIZE;
- if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
- lp->tx_reap = TX_BUF_START;
-
- lp->tx_pkts_in_ring--;
- /* There is always more space in the Tx ring buffer now. */
- netif_wake_queue(dev);
-
- if (++boguscount > 10)
- break;
- }
-
- if (status & 0x4000) { /* Packet received. */
- if (net_debug > 5)
- pr_debug("Received packet, rx_head %04x.\n", lp->rx_head);
- el16_rx(dev);
- }
-
- /* Acknowledge the interrupt sources. */
- ack_cmd = status & 0xf000;
-
- if ((status & 0x0700) != 0x0200 && netif_running(dev)) {
- if (net_debug)
- pr_debug("%s: Command unit stopped, status %04x, restarting.\n",
- dev->name, status);
- /* If this ever occurs we should really re-write the idle loop, reset
- the Tx list, and do a complete restart of the command unit.
- For now we rely on the Tx timeout if the resume doesn't work. */
- ack_cmd |= CUC_RESUME;
- }
-
- if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
- /* The Rx unit is not ready, it must be hung. Restart the receiver by
- initializing the rx buffers, and issuing an Rx start command. */
- if (net_debug)
- pr_debug("%s: Rx unit stopped, status %04x, restarting.\n",
- dev->name, status);
- init_rx_bufs(dev);
- writew(RX_BUF_START,shmem+iSCB_RFA);
- ack_cmd |= RX_START;
- }
-
- writew(ack_cmd,shmem+iSCB_CMD);
- outb(0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
-
- /* Clear the latched interrupt. */
- outb(0, ioaddr + RESET_IRQ);
-
- /* Enable the 82586's interrupt input. */
- outb(0x84, ioaddr + MISC_CTRL);
- spin_unlock(&lp->lock);
- return IRQ_HANDLED;
-}
-
-static int el16_close(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- void __iomem *shmem = lp->base;
-
- netif_stop_queue(dev);
-
- /* Flush the Tx and disable Rx. */
- writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD);
- outb(0, ioaddr + SIGNAL_CA);
-
- /* Disable the 82586's input to the interrupt line. */
- outb(0x80, ioaddr + MISC_CTRL);
-
- /* We always physically use the IRQ line, so we don't do free_irq(). */
-
- /* Update the statistics here. */
-
- return 0;
-}
-
-/* Initialize the Rx-block list. */
-static void init_rx_bufs(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- void __iomem *write_ptr;
- unsigned short SCB_base = SCB_BASE;
-
- int cur_rxbuf = lp->rx_head = RX_BUF_START;
-
- /* Initialize each Rx frame + data buffer. */
- do { /* While there is room for one more. */
-
- write_ptr = lp->base + cur_rxbuf;
-
- writew(0x0000,write_ptr); /* Status */
- writew(0x0000,write_ptr+=2); /* Command */
- writew(cur_rxbuf + RX_BUF_SIZE,write_ptr+=2); /* Link */
- writew(cur_rxbuf + 22,write_ptr+=2); /* Buffer offset */
- writew(0x0000,write_ptr+=2); /* Pad for dest addr. */
- writew(0x0000,write_ptr+=2);
- writew(0x0000,write_ptr+=2);
- writew(0x0000,write_ptr+=2); /* Pad for source addr. */
- writew(0x0000,write_ptr+=2);
- writew(0x0000,write_ptr+=2);
- writew(0x0000,write_ptr+=2); /* Pad for protocol. */
-
- writew(0x0000,write_ptr+=2); /* Buffer: Actual count */
- writew(-1,write_ptr+=2); /* Buffer: Next (none). */
- writew(cur_rxbuf + 0x20 + SCB_base,write_ptr+=2);/* Buffer: Address low */
- writew(0x0000,write_ptr+=2);
- /* Finally, the number of bytes in the buffer. */
- writew(0x8000 + RX_BUF_SIZE-0x20,write_ptr+=2);
-
- lp->rx_tail = cur_rxbuf;
- cur_rxbuf += RX_BUF_SIZE;
- } while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
-
- /* Terminate the list by setting the EOL bit, and wrap the pointer to make
- the list a ring. */
- write_ptr = lp->base + lp->rx_tail + 2;
- writew(0xC000,write_ptr); /* Command, mark as last. */
- writew(lp->rx_head,write_ptr+2); /* Link */
-}
-
-static void init_82586_mem(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- void __iomem *shmem = lp->base;
-
- /* Enable loopback to protect the wire while starting up,
- and hold the 586 in reset during the memory initialization. */
- outb(0x20, ioaddr + MISC_CTRL);
-
- /* Fix the ISCP address and base. */
- init_words[3] = SCB_BASE;
- init_words[7] = SCB_BASE;
-
- /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
- memcpy_toio(lp->base + RX_BUF_END - 10, init_words, 10);
-
- /* Write the words at 0x0000. */
- memcpy_toio(lp->base, init_words + 5, sizeof(init_words) - 10);
-
- /* Fill in the station address. */
- memcpy_toio(lp->base+SA_OFFSET, dev->dev_addr, ETH_ALEN);
-
- /* The Tx-block list is written as needed. We just set up the values. */
- lp->tx_cmd_link = IDLELOOP + 4;
- lp->tx_head = lp->tx_reap = TX_BUF_START;
-
- init_rx_bufs(dev);
-
- /* Start the 586 by releasing the reset line, but leave loopback. */
- outb(0xA0, ioaddr + MISC_CTRL);
-
- /* This was time consuming to track down: you need to give two channel
- attention signals to reliably start up the i82586. */
- outb(0, ioaddr + SIGNAL_CA);
-
- {
- int boguscnt = 50;
- while (readw(shmem+iSCB_STATUS) == 0)
- if (--boguscnt == 0) {
- pr_warning("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
- dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD));
- break;
- }
- /* Issue channel-attn -- the 82586 won't start. */
- outb(0, ioaddr + SIGNAL_CA);
- }
-
- /* Disable loopback and enable interrupts. */
- outb(0x84, ioaddr + MISC_CTRL);
- if (net_debug > 4)
- pr_debug("%s: Initialized 82586, status %04x.\n", dev->name,
- readw(shmem+iSCB_STATUS));
-}
-
-static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
-{
- struct net_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- ushort tx_block = lp->tx_head;
- void __iomem *write_ptr = lp->base + tx_block;
- static char padding[ETH_ZLEN];
-
- /* Set the write pointer to the Tx block, and put out the header. */
- writew(0x0000,write_ptr); /* Tx status */
- writew(CMD_INTR|CmdTx,write_ptr+=2); /* Tx command */
- writew(tx_block+16,write_ptr+=2); /* Next command is a NoOp. */
- writew(tx_block+8,write_ptr+=2); /* Data Buffer offset. */
-
- /* Output the data buffer descriptor. */
- writew((pad + length) | 0x8000,write_ptr+=2); /* Byte count parameter. */
- writew(-1,write_ptr+=2); /* No next data buffer. */
- writew(tx_block+22+SCB_BASE,write_ptr+=2); /* Buffer follows the NoOp command. */
- writew(0x0000,write_ptr+=2); /* Buffer address high bits (always zero). */
-
- /* Output the Loop-back NoOp command. */
- writew(0x0000,write_ptr+=2); /* Tx status */
- writew(CmdNOp,write_ptr+=2); /* Tx command */
- writew(tx_block+16,write_ptr+=2); /* Next is myself. */
-
- /* Output the packet at the write pointer. */
- memcpy_toio(write_ptr+2, buf, length);
- if (pad)
- memcpy_toio(write_ptr+length+2, padding, pad);
-
- /* Set the old command link pointing to this send packet. */
- writew(tx_block,lp->base + lp->tx_cmd_link);
- lp->tx_cmd_link = tx_block + 20;
-
- /* Set the next free tx region. */
- lp->tx_head = tx_block + TX_BUF_SIZE;
- if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
- lp->tx_head = TX_BUF_START;
-
- if (net_debug > 4) {
- pr_debug("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
- dev->name, ioaddr, length, tx_block, lp->tx_head);
- }
-
- /* Grimly block further packets if there has been insufficient reaping. */
- if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
- netif_wake_queue(dev);
-}
-
-static void el16_rx(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- void __iomem *shmem = lp->base;
- ushort rx_head = lp->rx_head;
- ushort rx_tail = lp->rx_tail;
- ushort boguscount = 10;
- short frame_status;
-
- while ((frame_status = readw(shmem+rx_head)) < 0) { /* Command complete */
- void __iomem *read_frame = lp->base + rx_head;
- ushort rfd_cmd = readw(read_frame+2);
- ushort next_rx_frame = readw(read_frame+4);
- ushort data_buffer_addr = readw(read_frame+6);
- void __iomem *data_frame = lp->base + data_buffer_addr;
- ushort pkt_len = readw(data_frame);
-
- if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 ||
- (pkt_len & 0xC000) != 0xC000) {
- pr_err("%s: Rx frame at %#x corrupted, "
- "status %04x cmd %04x next %04x "
- "data-buf @%04x %04x.\n",
- dev->name, rx_head, frame_status, rfd_cmd,
- next_rx_frame, data_buffer_addr, pkt_len);
- } else if ((frame_status & 0x2000) == 0) {
- /* Frame Rxed, but with error. */
- dev->stats.rx_errors++;
- if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
- if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
- if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
- if (frame_status & 0x0100) dev->stats.rx_over_errors++;
- if (frame_status & 0x0080) dev->stats.rx_length_errors++;
- } else {
- /* Malloc up new buffer. */
- struct sk_buff *skb;
-
- pkt_len &= 0x3fff;
- skb = netdev_alloc_skb(dev, pkt_len + 2);
- if (skb == NULL) {
- pr_err("%s: Memory squeeze, dropping packet.\n",
- dev->name);
- dev->stats.rx_dropped++;
- break;
- }
-
- skb_reserve(skb,2);
-
- /* 'skb->data' points to the start of sk_buff data area. */
- memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);
-
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
-
- /* Clear the status word and set End-of-List on the rx frame. */
- writew(0,read_frame);
- writew(0xC000,read_frame+2);
- /* Clear the end-of-list on the prev. RFD. */
- writew(0x0000,lp->base + rx_tail + 2);
-
- rx_tail = rx_head;
- rx_head = next_rx_frame;
- if (--boguscount == 0)
- break;
- }
-
- lp->rx_head = rx_head;
- lp->rx_tail = rx_tail;
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
- return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
- debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
- .get_msglevel = netdev_get_msglevel,
- .set_msglevel = netdev_set_msglevel,
-};
-
-#ifdef MODULE
-static struct net_device *dev_3c507;
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "EtherLink16 I/O base address");
-MODULE_PARM_DESC(irq, "(ignored)");
-
-int __init init_module(void)
-{
- if (io == 0)
- pr_notice("3c507: You should not use auto-probing with insmod!\n");
- dev_3c507 = el16_probe(-1);
- return IS_ERR(dev_3c507) ? PTR_ERR(dev_3c507) : 0;
-}
-
-void __exit
-cleanup_module(void)
-{
- struct net_device *dev = dev_3c507;
- unregister_netdev(dev);
- free_irq(dev->irq, dev);
- iounmap(((struct net_local *)netdev_priv(dev))->base);
- release_region(dev->base_addr, EL16_IO_EXTENT);
- free_netdev(dev);
-}
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/82596.c b/drivers/net/ethernet/i825xx/82596.c
index 6aa927af382c..1c54e229e3cc 100644
--- a/drivers/net/ethernet/i825xx/82596.c
+++ b/drivers/net/ethernet/i825xx/82596.c
@@ -95,9 +95,6 @@ static char version[] __initdata =
#if defined(CONFIG_BVME6000_NET) || defined(CONFIG_BVME6000_NET_MODULE)
#define ENABLE_BVME6000_NET
#endif
-#if defined(CONFIG_APRICOT) || defined(CONFIG_APRICOT_MODULE)
-#define ENABLE_APRICOT
-#endif
#ifdef ENABLE_MVME16x_NET
#include <asm/mvme16xhw.h>
@@ -120,8 +117,15 @@ static char version[] __initdata =
#define WSWAPtbd(x) ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
#define WSWAPchar(x) ((char *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
#define ISCP_BUSY 0x00010000
-#define MACH_IS_APRICOT 0
#else
+#error 82596.c: unknown architecture
+#endif
+
+/*
+ * These were the intel versions, left here for reference. There
+ * are currently no x86 users of this legacy i82596 chip.
+ */
+#if 0
#define WSWAPrfd(x) ((struct i596_rfd *)((long)x))
#define WSWAPrbd(x) ((struct i596_rbd *)((long)x))
#define WSWAPiscp(x) ((struct i596_iscp *)((long)x))
@@ -130,7 +134,6 @@ static char version[] __initdata =
#define WSWAPtbd(x) ((struct i596_tbd *)((long)x))
#define WSWAPchar(x) ((char *)((long)x))
#define ISCP_BUSY 0x0001
-#define MACH_IS_APRICOT 1
#endif
/*
@@ -383,11 +386,6 @@ static inline void CA(struct net_device *dev)
i = *(volatile u32 *) (dev->base_addr);
}
#endif
-#ifdef ENABLE_APRICOT
- if (MACH_IS_APRICOT) {
- outw(0, (short) (dev->base_addr) + 4);
- }
-#endif
}
@@ -617,9 +615,6 @@ static void rebuild_rx_bufs(struct net_device *dev)
static int init_i596_mem(struct net_device *dev)
{
struct i596_private *lp = dev->ml_priv;
-#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT)
- short ioaddr = dev->base_addr;
-#endif
unsigned long flags;
MPU_PORT(dev, PORT_RESET, NULL);
@@ -653,18 +648,6 @@ static int init_i596_mem(struct net_device *dev)
MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp));
-#elif defined(ENABLE_APRICOT)
-
- {
- u32 scp = virt_to_bus(&lp->scp);
-
- /* change the scp address */
- outw(0, ioaddr);
- outw(0, ioaddr);
- outb(4, ioaddr + 0xf);
- outw(scp | 2, ioaddr);
- outw(scp >> 16, ioaddr);
- }
#endif
lp->last_cmd = jiffies;
@@ -677,10 +660,6 @@ static int init_i596_mem(struct net_device *dev)
if (MACH_IS_BVME6000)
lp->scp.sysbus = 0x0000004c;
#endif
-#ifdef ENABLE_APRICOT
- if (MACH_IS_APRICOT)
- lp->scp.sysbus = 0x00440000;
-#endif
lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp));
lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb));
@@ -698,10 +677,6 @@ static int init_i596_mem(struct net_device *dev)
DEB(DEB_INIT,printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
-#if defined(ENABLE_APRICOT)
- (void) inb(ioaddr + 0x10);
- outb(4, ioaddr + 0xf);
-#endif
CA(dev);
if (wait_istat(dev,lp,1000,"initialization timed out"))
@@ -1203,43 +1178,6 @@ struct net_device * __init i82596_probe(int unit)
goto found;
}
#endif
-#ifdef ENABLE_APRICOT
- {
- int checksum = 0;
- int ioaddr = 0x300;
-
- /* this is easy the ethernet interface can only be at 0x300 */
- /* first check nothing is already registered here */
-
- if (!request_region(ioaddr, I596_TOTAL_SIZE, DRV_NAME)) {
- printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr);
- err = -EBUSY;
- goto out;
- }
-
- dev->base_addr = ioaddr;
-
- for (i = 0; i < 8; i++) {
- eth_addr[i] = inb(ioaddr + 8 + i);
- checksum += eth_addr[i];
- }
-
- /* checksum is a multiple of 0x100, got this wrong first time
- some machines have 0x100, some 0x200. The DOS driver doesn't
- even bother with the checksum.
- Some other boards trip the checksum.. but then appear as
- ether address 0. Trap these - AC */
-
- if ((checksum % 0x100) ||
- (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {
- err = -ENODEV;
- goto out1;
- }
-
- dev->irq = 10;
- goto found;
- }
-#endif
err = -ENODEV;
goto out;
@@ -1296,9 +1234,6 @@ out2:
#endif
free_page ((u32)(dev->mem_start));
out1:
-#ifdef ENABLE_APRICOT
- release_region(dev->base_addr, I596_TOTAL_SIZE);
-#endif
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -1455,10 +1390,6 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
*ethirq = 3;
}
#endif
-#ifdef ENABLE_APRICOT
- (void) inb(ioaddr + 0x10);
- outb(4, ioaddr + 0xf);
-#endif
CA(dev);
DEB(DEB_INTS,printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
@@ -1589,11 +1520,6 @@ static void set_multicast_list(struct net_device *dev)
#ifdef MODULE
static struct net_device *dev_82596;
-#ifdef ENABLE_APRICOT
-module_param(irq, int, 0);
-MODULE_PARM_DESC(irq, "Apricot IRQ number");
-#endif
-
static int debug = -1;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "i82596 debug mask");
@@ -1620,10 +1546,6 @@ void __exit cleanup_module(void)
IOMAP_FULL_CACHING);
#endif
free_page ((u32)(dev_82596->mem_start));
-#ifdef ENABLE_APRICOT
- /* If we don't do this, we can't re-insmod it later. */
- release_region(dev_82596->base_addr, I596_TOTAL_SIZE);
-#endif
free_netdev(dev_82596);
}
diff --git a/drivers/net/ethernet/i825xx/Kconfig b/drivers/net/ethernet/i825xx/Kconfig
index 959faf7388e2..9521e68aa3b3 100644
--- a/drivers/net/ethernet/i825xx/Kconfig
+++ b/drivers/net/ethernet/i825xx/Kconfig
@@ -5,9 +5,7 @@
config NET_VENDOR_I825XX
bool "Intel (82586/82593/82596) devices"
default y
- depends on NET_VENDOR_INTEL && (ISA || ISA_DMA_API || ARM || \
- ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \
- GSC || BVME6000 || MVME16x || EXPERIMENTAL)
+ depends on NET_VENDOR_INTEL
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -20,29 +18,6 @@ config NET_VENDOR_I825XX
if NET_VENDOR_I825XX
-config ELPLUS
- tristate "3c505 \"EtherLink Plus\" support"
- depends on ISA && ISA_DMA_API
- ---help---
- Information about this network (Ethernet) card can be found in
- <file:Documentation/networking/3c505.txt>. If you have a card of
- this type, say Y and read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c505.
-
-config EL16
- tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
- depends on ISA && EXPERIMENTAL
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called 3c507.
-
config ARM_ETHER1
tristate "Acorn Ether1 support"
depends on ARM && ARCH_ACORN
@@ -50,17 +25,6 @@ config ARM_ETHER1
If you have an Acorn system with one of these (AKA25) network cards,
you should say Y to this option if you wish to use it with Linux.
-config APRICOT
- tristate "Apricot Xen-II on board Ethernet"
- depends on ISA
- ---help---
- If you have a network (Ethernet) controller of this type, say Y and
- read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called apricot.
-
config BVME6000_NET
tristate "BVME6000 Ethernet support"
depends on BVME6000
@@ -70,33 +34,6 @@ config BVME6000_NET
in your kernel.
To compile this driver as a module, choose M here.
-config EEXPRESS
- tristate "EtherExpress 16 support"
- depends on ISA
- ---help---
- If you have an EtherExpress16 network (Ethernet) card, say Y and
- read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Note that the Intel
- EtherExpress16 card used to be regarded as a very poor choice
- because the driver was very unreliable. We now have a new driver
- that should do better.
-
- To compile this driver as a module, choose M here. The module
- will be called eexpress.
-
-config EEXPRESS_PRO
- tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
- depends on ISA
- ---help---
- If you have a network (Ethernet) card of this type, say Y. This
- driver supports Intel i82595{FX,TX} based boards. Note however
- that the EtherExpress PRO/100 Ethernet card has its own separate
- driver. Please read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called eepro.
-
config LASI_82596
tristate "Lasi ethernet"
depends on GSC
@@ -104,14 +41,6 @@ config LASI_82596
Say Y here to support the builtin Intel 82596 ethernet controller
found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
-config LP486E
- tristate "LP486E on board Ethernet"
- depends on ISA
- ---help---
- Say Y here to support the 82596-based on-board Ethernet controller
- for the Panther motherboard, which is one of the two shipped in the
- Intel Professional Workstation.
-
config MVME16x_NET
tristate "MVME16x Ethernet support"
depends on MVME16x
@@ -121,17 +50,6 @@ config MVME16x_NET
driver for this chip in your kernel.
To compile this driver as a module, choose M here.
-config NI52
- tristate "NI5210 support"
- depends on ISA
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called ni52.
-
config SNI_82596
tristate "SNI RM ethernet"
depends on SNI_RM
@@ -148,14 +66,4 @@ config SUN3_82586
that this driver does not support 82586-based adapters on additional
VME boards.
-config ZNET
- tristate "Zenith Z-Note support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && ISA_DMA_API && X86
- ---help---
- The Zenith Z-Note notebook computer has a built-in network
- (Ethernet) card, and this is the Linux driver for it. Note that the
- IBM Thinkpad 300 is compatible with the Z-Note and is also supported
- by this driver. Read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
endif # NET_VENDOR_I825XX
diff --git a/drivers/net/ethernet/i825xx/Makefile b/drivers/net/ethernet/i825xx/Makefile
index 6adff85e8ecc..8c8dcd29c40d 100644
--- a/drivers/net/ethernet/i825xx/Makefile
+++ b/drivers/net/ethernet/i825xx/Makefile
@@ -3,15 +3,7 @@
#
obj-$(CONFIG_ARM_ETHER1) += ether1.o
-obj-$(CONFIG_EEXPRESS) += eexpress.o
-obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
-obj-$(CONFIG_ELPLUS) += 3c505.o
-obj-$(CONFIG_EL16) += 3c507.o
-obj-$(CONFIG_LP486E) += lp486e.o
-obj-$(CONFIG_NI52) += ni52.o
obj-$(CONFIG_SUN3_82586) += sun3_82586.o
-obj-$(CONFIG_ZNET) += znet.o
-obj-$(CONFIG_APRICOT) += 82596.o
obj-$(CONFIG_LASI_82596) += lasi_82596.o
obj-$(CONFIG_SNI_82596) += sni_82596.o
obj-$(CONFIG_MVME16x_NET) += 82596.o
diff --git a/drivers/net/ethernet/i825xx/eepro.c b/drivers/net/ethernet/i825xx/eepro.c
deleted file mode 100644
index 7f49fd54c521..000000000000
--- a/drivers/net/ethernet/i825xx/eepro.c
+++ /dev/null
@@ -1,1822 +0,0 @@
-/* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
-/*
- Written 1994, 1995,1996 by Bao C. Ha.
-
- Copyright (C) 1994, 1995,1996 by Bao C. Ha.
-
- This software may be used and distributed
- according to the terms of the GNU General Public License,
- incorporated herein by reference.
-
- The author may be reached at bao.ha@srs.gov
- or 418 Hastings Place, Martinez, GA 30907.
-
- Things remaining to do:
- Better record keeping of errors.
- Eliminate transmit interrupt to reduce overhead.
- Implement "concurrent processing". I won't be doing it!
-
- Bugs:
-
- If you have a problem of not detecting the 82595 during a
- reboot (warm reset), disable the FLASH memory should fix it.
- This is a compatibility hardware problem.
-
- Versions:
- 0.13b basic ethtool support (aris, 09/13/2004)
- 0.13a in memory shortage, drop packets also in board
- (Michael Westermann <mw@microdata-pos.de>, 07/30/2002)
- 0.13 irq sharing, rewrote probe function, fixed a nasty bug in
- hardware_send_packet and a major cleanup (aris, 11/08/2001)
- 0.12d fixing a problem with single card detected as eight eth devices
- fixing a problem with sudden drop in card performance
- (chris (asdn@go2.pl), 10/29/2001)
- 0.12c fixing some problems with old cards (aris, 01/08/2001)
- 0.12b misc fixes (aris, 06/26/2000)
- 0.12a port of version 0.12a of 2.2.x kernels to 2.3.x
- (aris (aris@conectiva.com.br), 05/19/2000)
- 0.11e some tweaks about multiple cards support (PdP, jul/aug 1999)
- 0.11d added __initdata, __init stuff; call spin_lock_init
- in eepro_probe1. Replaced "eepro" by dev->name. Augmented
- the code protected by spin_lock in interrupt routine
- (PdP, 12/12/1998)
- 0.11c minor cleanup (PdP, RMC, 09/12/1998)
- 0.11b Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module
- under 2.1.xx. Debug messages are flagged as KERN_DEBUG to
- avoid console flooding. Added locking at critical parts. Now
- the dawn thing is SMP safe.
- 0.11a Attempt to get 2.1.xx support up (RMC)
- 0.11 Brian Candler added support for multiple cards. Tested as
- a module, no idea if it works when compiled into kernel.
-
- 0.10e Rick Bressler notified me that ifconfig up;ifconfig down fails
- because the irq is lost somewhere. Fixed that by moving
- request_irq and free_irq to eepro_open and eepro_close respectively.
- 0.10d Ugh! Now Wakeup works. Was seriously broken in my first attempt.
- I'll need to find a way to specify an ioport other than
- the default one in the PnP case. PnP definitively sucks.
- And, yes, this is not the only reason.
- 0.10c PnP Wakeup Test for 595FX. uncomment #define PnPWakeup;
- to use.
- 0.10b Should work now with (some) Pro/10+. At least for
- me (and my two cards) it does. _No_ guarantee for
- function with non-Pro/10+ cards! (don't have any)
- (RMC, 9/11/96)
-
- 0.10 Added support for the Etherexpress Pro/10+. The
- IRQ map was changed significantly from the old
- pro/10. The new interrupt map was provided by
- Rainer M. Canavan (Canavan@Zeus.cs.bonn.edu).
- (BCH, 9/3/96)
-
- 0.09 Fixed a race condition in the transmit algorithm,
- which causes crashes under heavy load with fast
- pentium computers. The performance should also
- improve a bit. The size of RX buffer, and hence
- TX buffer, can also be changed via lilo or insmod.
- (BCH, 7/31/96)
-
- 0.08 Implement 32-bit I/O for the 82595TX and 82595FX
- based lan cards. Disable full-duplex mode if TPE
- is not used. (BCH, 4/8/96)
-
- 0.07a Fix a stat report which counts every packet as a
- heart-beat failure. (BCH, 6/3/95)
-
- 0.07 Modified to support all other 82595-based lan cards.
- The IRQ vector of the EtherExpress Pro will be set
- according to the value saved in the EEPROM. For other
- cards, I will do autoirq_request() to grab the next
- available interrupt vector. (BCH, 3/17/95)
-
- 0.06a,b Interim released. Minor changes in the comments and
- print out format. (BCH, 3/9/95 and 3/14/95)
-
- 0.06 First stable release that I am comfortable with. (BCH,
- 3/2/95)
-
- 0.05 Complete testing of multicast. (BCH, 2/23/95)
-
- 0.04 Adding multicast support. (BCH, 2/14/95)
-
- 0.03 First widely alpha release for public testing.
- (BCH, 2/14/95)
-
-*/
-
-static const char version[] =
- "eepro.c: v0.13b 09/13/2004 aris@cathedrallabs.org\n";
-
-#include <linux/module.h>
-
-/*
- Sources:
-
- This driver wouldn't have been written without the availability
- of the Crynwr's Lan595 driver source code. It helps me to
- familiarize with the 82595 chipset while waiting for the Intel
- documentation. I also learned how to detect the 82595 using
- the packet driver's technique.
-
- This driver is written by cutting and pasting the skeleton.c driver
- provided by Donald Becker. I also borrowed the EEPROM routine from
- Donald Becker's 82586 driver.
-
- Datasheet for the Intel 82595 (including the TX and FX version). It
- provides just enough info that the casual reader might think that it
- documents the i82595.
-
- The User Manual for the 82595. It provides a lot of the missing
- information.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/ethtool.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "eepro"
-#define DRV_VERSION "0.13c"
-
-#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
-/* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
-#define SLOW_DOWN inb(0x80)
-/* udelay(2) */
-#define compat_init_data __initdata
-enum iftype { AUI=0, BNC=1, TPE=2 };
-
-/* First, a few definitions that the brave might change. */
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int eepro_portlist[] compat_init_data =
- { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
-/* note: 0x300 is default, the 595FX supports ALL IO Ports
- from 0x000 to 0x3F0, some of which are reserved in PCs */
-
-/* To try the (not-really PnP Wakeup: */
-/*
-#define PnPWakeup
-*/
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 0
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-/* The number of low I/O ports used by the ethercard. */
-#define EEPRO_IO_EXTENT 16
-
-/* Different 82595 chips */
-#define LAN595 0
-#define LAN595TX 1
-#define LAN595FX 2
-#define LAN595FX_10ISA 3
-
-/* Information that need to be kept for each board. */
-struct eepro_local {
- unsigned rx_start;
- unsigned tx_start; /* start of the transmit chain */
- int tx_last; /* pointer to last packet in the transmit chain */
- unsigned tx_end; /* end of the transmit chain (plus 1) */
- int eepro; /* 1 for the EtherExpress Pro/10,
- 2 for the EtherExpress Pro/10+,
- 3 for the EtherExpress 10 (blue cards),
- 0 for other 82595-based lan cards. */
- int version; /* a flag to indicate if this is a TX or FX
- version of the 82595 chip. */
- int stepping;
-
- spinlock_t lock; /* Serializing lock */
-
- unsigned rcv_ram; /* pre-calculated space for rx */
- unsigned xmt_ram; /* pre-calculated space for tx */
- unsigned char xmt_bar;
- unsigned char xmt_lower_limit_reg;
- unsigned char xmt_upper_limit_reg;
- short xmt_lower_limit;
- short xmt_upper_limit;
- short rcv_lower_limit;
- short rcv_upper_limit;
- unsigned char eeprom_reg;
- unsigned short word[8];
-};
-
-/* The station (ethernet) address prefix, used for IDing the board. */
-#define SA_ADDR0 0x00 /* Etherexpress Pro/10 */
-#define SA_ADDR1 0xaa
-#define SA_ADDR2 0x00
-
-#define GetBit(x,y) ((x & (1<<y))>>y)
-
-/* EEPROM Word 0: */
-#define ee_PnP 0 /* Plug 'n Play enable bit */
-#define ee_Word1 1 /* Word 1? */
-#define ee_BusWidth 2 /* 8/16 bit */
-#define ee_FlashAddr 3 /* Flash Address */
-#define ee_FlashMask 0x7 /* Mask */
-#define ee_AutoIO 6 /* */
-#define ee_reserved0 7 /* =0! */
-#define ee_Flash 8 /* Flash there? */
-#define ee_AutoNeg 9 /* Auto Negotiation enabled? */
-#define ee_IO0 10 /* IO Address LSB */
-#define ee_IO0Mask 0x /*...*/
-#define ee_IO1 15 /* IO MSB */
-
-/* EEPROM Word 1: */
-#define ee_IntSel 0 /* Interrupt */
-#define ee_IntMask 0x7
-#define ee_LI 3 /* Link Integrity 0= enabled */
-#define ee_PC 4 /* Polarity Correction 0= enabled */
-#define ee_TPE_AUI 5 /* PortSelection 1=TPE */
-#define ee_Jabber 6 /* Jabber prevention 0= enabled */
-#define ee_AutoPort 7 /* Auto Port Selection 1= Disabled */
-#define ee_SMOUT 8 /* SMout Pin Control 0= Input */
-#define ee_PROM 9 /* Flash EPROM / PROM 0=Flash */
-#define ee_reserved1 10 /* .. 12 =0! */
-#define ee_AltReady 13 /* Alternate Ready, 0=normal */
-#define ee_reserved2 14 /* =0! */
-#define ee_Duplex 15
-
-/* Word2,3,4: */
-#define ee_IA5 0 /*bit start for individual Addr Byte 5 */
-#define ee_IA4 8 /*bit start for individual Addr Byte 5 */
-#define ee_IA3 0 /*bit start for individual Addr Byte 5 */
-#define ee_IA2 8 /*bit start for individual Addr Byte 5 */
-#define ee_IA1 0 /*bit start for individual Addr Byte 5 */
-#define ee_IA0 8 /*bit start for individual Addr Byte 5 */
-
-/* Word 5: */
-#define ee_BNC_TPE 0 /* 0=TPE */
-#define ee_BootType 1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */
-#define ee_BootTypeMask 0x3
-#define ee_NumConn 3 /* Number of Connections 0= One or Two */
-#define ee_FlashSock 4 /* Presence of Flash Socket 0= Present */
-#define ee_PortTPE 5
-#define ee_PortBNC 6
-#define ee_PortAUI 7
-#define ee_PowerMgt 10 /* 0= disabled */
-#define ee_CP 13 /* Concurrent Processing */
-#define ee_CPMask 0x7
-
-/* Word 6: */
-#define ee_Stepping 0 /* Stepping info */
-#define ee_StepMask 0x0F
-#define ee_BoardID 4 /* Manucaturer Board ID, reserved */
-#define ee_BoardMask 0x0FFF
-
-/* Word 7: */
-#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping = 0x1EB8 for Pro/10+ */
-#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */
-
-/*..*/
-#define ee_SIZE 0x40 /* total EEprom Size */
-#define ee_Checksum 0xBABA /* initial and final value for adding checksum */
-
-
-/* Card identification via EEprom: */
-#define ee_addr_vendor 0x10 /* Word offset for EISA Vendor ID */
-#define ee_addr_id 0x11 /* Word offset for Card ID */
-#define ee_addr_SN 0x12 /* Serial Number */
-#define ee_addr_CRC_8 0x14 /* CRC over last thee Bytes */
-
-
-#define ee_vendor_intel0 0x25 /* Vendor ID Intel */
-#define ee_vendor_intel1 0xD4
-#define ee_id_eepro10p0 0x10 /* ID for eepro/10+ */
-#define ee_id_eepro10p1 0x31
-
-#define TX_TIMEOUT ((4*HZ)/10)
-
-/* Index to functions, as function prototypes. */
-
-static int eepro_probe1(struct net_device *dev, int autoprobe);
-static int eepro_open(struct net_device *dev);
-static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t eepro_interrupt(int irq, void *dev_id);
-static void eepro_rx(struct net_device *dev);
-static void eepro_transmit_interrupt(struct net_device *dev);
-static int eepro_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void eepro_tx_timeout (struct net_device *dev);
-
-static int read_eeprom(int ioaddr, int location, struct net_device *dev);
-static int hardware_send_packet(struct net_device *dev, void *buf, short length);
-static int eepro_grab_irq(struct net_device *dev);
-
-/*
- Details of the i82595.
-
-You will need either the datasheet or the user manual to understand what
-is going on here. The 82595 is very different from the 82586, 82593.
-
-The receive algorithm in eepro_rx() is just an implementation of the
-RCV ring structure that the Intel 82595 imposes at the hardware level.
-The receive buffer is set at 24K, and the transmit buffer is 8K. I
-am assuming that the total buffer memory is 32K, which is true for the
-Intel EtherExpress Pro/10. If it is less than that on a generic card,
-the driver will be broken.
-
-The transmit algorithm in the hardware_send_packet() is similar to the
-one in the eepro_rx(). The transmit buffer is a ring linked list.
-I just queue the next available packet to the end of the list. In my
-system, the 82595 is so fast that the list seems to always contain a
-single packet. In other systems with faster computers and more congested
-network traffics, the ring linked list should improve performance by
-allowing up to 8K worth of packets to be queued.
-
-The sizes of the receive and transmit buffers can now be changed via lilo
-or insmod. Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0"
-where rx-buffer is in KB unit. Modules uses the parameter mem which is
-also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer."
-The receive buffer has to be more than 3K or less than 29K. Otherwise,
-it is reset to the default of 24K, and, hence, 8K for the trasnmit
-buffer (transmit-buffer = 32K - receive-buffer).
-
-*/
-#define RAM_SIZE 0x8000
-
-#define RCV_HEADER 8
-#define RCV_DEFAULT_RAM 0x6000
-
-#define XMT_HEADER 8
-#define XMT_DEFAULT_RAM (RAM_SIZE - RCV_DEFAULT_RAM)
-
-#define XMT_START_PRO RCV_DEFAULT_RAM
-#define XMT_START_10 0x0000
-#define RCV_START_PRO 0x0000
-#define RCV_START_10 XMT_DEFAULT_RAM
-
-#define RCV_DONE 0x0008
-#define RX_OK 0x2000
-#define RX_ERROR 0x0d81
-
-#define TX_DONE_BIT 0x0080
-#define TX_OK 0x2000
-#define CHAIN_BIT 0x8000
-#define XMT_STATUS 0x02
-#define XMT_CHAIN 0x04
-#define XMT_COUNT 0x06
-
-#define BANK0_SELECT 0x00
-#define BANK1_SELECT 0x40
-#define BANK2_SELECT 0x80
-
-/* Bank 0 registers */
-#define COMMAND_REG 0x00 /* Register 0 */
-#define MC_SETUP 0x03
-#define XMT_CMD 0x04
-#define DIAGNOSE_CMD 0x07
-#define RCV_ENABLE_CMD 0x08
-#define RCV_DISABLE_CMD 0x0a
-#define STOP_RCV_CMD 0x0b
-#define RESET_CMD 0x0e
-#define POWER_DOWN_CMD 0x18
-#define RESUME_XMT_CMD 0x1c
-#define SEL_RESET_CMD 0x1e
-#define STATUS_REG 0x01 /* Register 1 */
-#define RX_INT 0x02
-#define TX_INT 0x04
-#define EXEC_STATUS 0x30
-#define ID_REG 0x02 /* Register 2 */
-#define R_ROBIN_BITS 0xc0 /* round robin counter */
-#define ID_REG_MASK 0x2c
-#define ID_REG_SIG 0x24
-#define AUTO_ENABLE 0x10
-#define INT_MASK_REG 0x03 /* Register 3 */
-#define RX_STOP_MASK 0x01
-#define RX_MASK 0x02
-#define TX_MASK 0x04
-#define EXEC_MASK 0x08
-#define ALL_MASK 0x0f
-#define IO_32_BIT 0x10
-#define RCV_BAR 0x04 /* The following are word (16-bit) registers */
-#define RCV_STOP 0x06
-
-#define XMT_BAR_PRO 0x0a
-#define XMT_BAR_10 0x0b
-
-#define HOST_ADDRESS_REG 0x0c
-#define IO_PORT 0x0e
-#define IO_PORT_32_BIT 0x0c
-
-/* Bank 1 registers */
-#define REG1 0x01
-#define WORD_WIDTH 0x02
-#define INT_ENABLE 0x80
-#define INT_NO_REG 0x02
-#define RCV_LOWER_LIMIT_REG 0x08
-#define RCV_UPPER_LIMIT_REG 0x09
-
-#define XMT_LOWER_LIMIT_REG_PRO 0x0a
-#define XMT_UPPER_LIMIT_REG_PRO 0x0b
-#define XMT_LOWER_LIMIT_REG_10 0x0b
-#define XMT_UPPER_LIMIT_REG_10 0x0a
-
-/* Bank 2 registers */
-#define XMT_Chain_Int 0x20 /* Interrupt at the end of the transmit chain */
-#define XMT_Chain_ErrStop 0x40 /* Interrupt at the end of the chain even if there are errors */
-#define RCV_Discard_BadFrame 0x80 /* Throw bad frames away, and continue to receive others */
-#define REG2 0x02
-#define PRMSC_Mode 0x01
-#define Multi_IA 0x20
-#define REG3 0x03
-#define TPE_BIT 0x04
-#define BNC_BIT 0x20
-#define REG13 0x0d
-#define FDX 0x00
-#define A_N_ENABLE 0x02
-
-#define I_ADD_REG0 0x04
-#define I_ADD_REG1 0x05
-#define I_ADD_REG2 0x06
-#define I_ADD_REG3 0x07
-#define I_ADD_REG4 0x08
-#define I_ADD_REG5 0x09
-
-#define EEPROM_REG_PRO 0x0a
-#define EEPROM_REG_10 0x0b
-
-#define EESK 0x01
-#define EECS 0x02
-#define EEDI 0x04
-#define EEDO 0x08
-
-/* do a full reset */
-#define eepro_reset(ioaddr) outb(RESET_CMD, ioaddr)
-
-/* do a nice reset */
-#define eepro_sel_reset(ioaddr) { \
- outb(SEL_RESET_CMD, ioaddr); \
- SLOW_DOWN; \
- SLOW_DOWN; \
- }
-
-/* disable all interrupts */
-#define eepro_dis_int(ioaddr) outb(ALL_MASK, ioaddr + INT_MASK_REG)
-
-/* clear all interrupts */
-#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG)
-
-/* enable tx/rx */
-#define eepro_en_int(ioaddr) outb(ALL_MASK & ~(RX_MASK | TX_MASK), \
- ioaddr + INT_MASK_REG)
-
-/* enable exec event interrupt */
-#define eepro_en_intexec(ioaddr) outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG)
-
-/* enable rx */
-#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr)
-
-/* disable rx */
-#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr)
-
-/* switch bank */
-#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
-#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
-#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
-
-/* enable interrupt line */
-#define eepro_en_intline(ioaddr) outb(inb(ioaddr + REG1) | INT_ENABLE,\
- ioaddr + REG1)
-
-/* disable interrupt line */
-#define eepro_dis_intline(ioaddr) outb(inb(ioaddr + REG1) & 0x7f, \
- ioaddr + REG1);
-
-/* set diagnose flag */
-#define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr)
-
-/* ack for rx int */
-#define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG)
-
-/* ack for tx int */
-#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG)
-
-/* a complete sel reset */
-#define eepro_complete_selreset(ioaddr) { \
- dev->stats.tx_errors++;\
- eepro_sel_reset(ioaddr);\
- lp->tx_end = \
- lp->xmt_lower_limit;\
- lp->tx_start = lp->tx_end;\
- lp->tx_last = 0;\
- dev->trans_start = jiffies;\
- netif_wake_queue(dev);\
- eepro_en_rx(ioaddr);\
- }
-
-/* Check for a network adaptor of this type, and return '0' if one exists.
- If dev->base_addr == 0, probe all likely locations.
- If dev->base_addr == 1, always return failure.
- If dev->base_addr == 2, allocate space for the device and return success
- (detachable devices only).
- */
-static int __init do_eepro_probe(struct net_device *dev)
-{
- int i;
- int base_addr = dev->base_addr;
- int irq = dev->irq;
-
-#ifdef PnPWakeup
- /* XXXX for multiple cards should this only be run once? */
-
- /* Wakeup: */
- #define WakeupPort 0x279
- #define WakeupSeq {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\
- 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\
- 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\
- 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43}
-
- {
- unsigned short int WS[32]=WakeupSeq;
-
- if (request_region(WakeupPort, 2, "eepro wakeup")) {
- if (net_debug>5)
- printk(KERN_DEBUG "Waking UP\n");
-
- outb_p(0,WakeupPort);
- outb_p(0,WakeupPort);
- for (i=0; i<32; i++) {
- outb_p(WS[i],WakeupPort);
- if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]);
- }
-
- release_region(WakeupPort, 2);
- } else
- printk(KERN_WARNING "PnP wakeup region busy!\n");
- }
-#endif
-
- if (base_addr > 0x1ff) /* Check a single specified location. */
- return eepro_probe1(dev, 0);
-
- else if (base_addr != 0) /* Don't probe at all. */
- return -ENXIO;
-
- for (i = 0; eepro_portlist[i]; i++) {
- dev->base_addr = eepro_portlist[i];
- dev->irq = irq;
- if (eepro_probe1(dev, 1) == 0)
- return 0;
- }
-
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init eepro_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local));
- int err;
-
- if (!dev)
- return ERR_PTR(-ENODEV);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_eepro_probe(dev);
- if (err)
- goto out;
- return dev;
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-static void __init printEEPROMInfo(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned short Word;
- int i,j;
-
- j = ee_Checksum;
- for (i = 0; i < 8; i++)
- j += lp->word[i];
- for ( ; i < ee_SIZE; i++)
- j += read_eeprom(ioaddr, i, dev);
-
- printk(KERN_DEBUG "Checksum: %#x\n",j&0xffff);
-
- Word = lp->word[0];
- printk(KERN_DEBUG "Word0:\n");
- printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
- printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
- printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg));
- printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4);
-
- if (net_debug>4) {
- Word = lp->word[1];
- printk(KERN_DEBUG "Word1:\n");
- printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask);
- printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI));
- printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
- printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
- printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
- printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
- printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
- }
-
- Word = lp->word[5];
- printk(KERN_DEBUG "Word5:\n");
- printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE));
- printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn));
- printk(KERN_DEBUG " Has ");
- if (GetBit(Word,ee_PortTPE)) printk(KERN_DEBUG "TPE ");
- if (GetBit(Word,ee_PortBNC)) printk(KERN_DEBUG "BNC ");
- if (GetBit(Word,ee_PortAUI)) printk(KERN_DEBUG "AUI ");
- printk(KERN_DEBUG "port(s)\n");
-
- Word = lp->word[6];
- printk(KERN_DEBUG "Word6:\n");
- printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask);
- printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID);
-
- Word = lp->word[7];
- printk(KERN_DEBUG "Word7:\n");
- printk(KERN_DEBUG " INT to IRQ:\n");
-
- for (i=0, j=0; i<15; i++)
- if (GetBit(Word,i)) printk(KERN_DEBUG " INT%d -> IRQ %d;",j++,i);
-
- printk(KERN_DEBUG "\n");
-}
-
-/* function to recalculate the limits of buffer based on rcv_ram */
-static void eepro_recalc (struct net_device *dev)
-{
- struct eepro_local * lp;
-
- lp = netdev_priv(dev);
- lp->xmt_ram = RAM_SIZE - lp->rcv_ram;
-
- if (lp->eepro == LAN595FX_10ISA) {
- lp->xmt_lower_limit = XMT_START_10;
- lp->xmt_upper_limit = (lp->xmt_ram - 2);
- lp->rcv_lower_limit = lp->xmt_ram;
- lp->rcv_upper_limit = (RAM_SIZE - 2);
- }
- else {
- lp->rcv_lower_limit = RCV_START_PRO;
- lp->rcv_upper_limit = (lp->rcv_ram - 2);
- lp->xmt_lower_limit = lp->rcv_ram;
- lp->xmt_upper_limit = (RAM_SIZE - 2);
- }
-}
-
-/* prints boot-time info */
-static void __init eepro_print_info (struct net_device *dev)
-{
- struct eepro_local * lp = netdev_priv(dev);
- int i;
- const char * ifmap[] = {"AUI", "10Base2", "10BaseT"};
-
- i = inb(dev->base_addr + ID_REG);
- printk(KERN_DEBUG " id: %#x ",i);
- printk(" io: %#x ", (unsigned)dev->base_addr);
-
- switch (lp->eepro) {
- case LAN595FX_10ISA:
- printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
- dev->name, (unsigned)dev->base_addr);
- break;
- case LAN595FX:
- printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,",
- dev->name, (unsigned)dev->base_addr);
- break;
- case LAN595TX:
- printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
- dev->name, (unsigned)dev->base_addr);
- break;
- case LAN595:
- printk("%s: Intel 82595-based lan card at %#x,",
- dev->name, (unsigned)dev->base_addr);
- break;
- }
-
- printk(" %pM", dev->dev_addr);
-
- if (net_debug > 3)
- printk(KERN_DEBUG ", %dK RCV buffer",
- (int)(lp->rcv_ram)/1024);
-
- if (dev->irq > 2)
- printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]);
- else
- printk(", %s.\n", ifmap[dev->if_port]);
-
- if (net_debug > 3) {
- i = lp->word[5];
- if (i & 0x2000) /* bit 13 of EEPROM word 5 */
- printk(KERN_DEBUG "%s: Concurrent Processing is "
- "enabled but not used!\n", dev->name);
- }
-
- /* Check the station address for the manufacturer's code */
- if (net_debug>3)
- printEEPROMInfo(dev);
-}
-
-static const struct ethtool_ops eepro_ethtool_ops;
-
-static const struct net_device_ops eepro_netdev_ops = {
- .ndo_open = eepro_open,
- .ndo_stop = eepro_close,
- .ndo_start_xmit = eepro_send_packet,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_tx_timeout = eepro_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/* This is the real probe routine. Linux has a history of friendly device
- probes on the ISA bus. A good device probe avoids doing writes, and
- verifies that the correct device exists and functions. */
-
-static int __init eepro_probe1(struct net_device *dev, int autoprobe)
-{
- unsigned short station_addr[3], id, counter;
- int i;
- struct eepro_local *lp;
- int ioaddr = dev->base_addr;
- int err;
-
- /* Grab the region so we can find another board if autoIRQ fails. */
- if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) {
- if (!autoprobe)
- printk(KERN_WARNING "EEPRO: io-port 0x%04x in use\n",
- ioaddr);
- return -EBUSY;
- }
-
- /* Now, we are going to check for the signature of the
- ID_REG (register 2 of bank 0) */
-
- id = inb(ioaddr + ID_REG);
-
- if ((id & ID_REG_MASK) != ID_REG_SIG)
- goto exit;
-
- /* We seem to have the 82595 signature, let's
- play with its counter (last 2 bits of
- register 2 of bank 0) to be sure. */
-
- counter = id & R_ROBIN_BITS;
-
- if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40))
- goto exit;
-
- lp = netdev_priv(dev);
- memset(lp, 0, sizeof(struct eepro_local));
- lp->xmt_bar = XMT_BAR_PRO;
- lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO;
- lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
- lp->eeprom_reg = EEPROM_REG_PRO;
- spin_lock_init(&lp->lock);
-
- /* Now, get the ethernet hardware address from
- the EEPROM */
- station_addr[0] = read_eeprom(ioaddr, 2, dev);
-
- /* FIXME - find another way to know that we've found
- * an Etherexpress 10
- */
- if (station_addr[0] == 0x0000 || station_addr[0] == 0xffff) {
- lp->eepro = LAN595FX_10ISA;
- lp->eeprom_reg = EEPROM_REG_10;
- lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
- lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
- lp->xmt_bar = XMT_BAR_10;
- station_addr[0] = read_eeprom(ioaddr, 2, dev);
- }
-
- /* get all words at once. will be used here and for ethtool */
- for (i = 0; i < 8; i++) {
- lp->word[i] = read_eeprom(ioaddr, i, dev);
- }
- station_addr[1] = lp->word[3];
- station_addr[2] = lp->word[4];
-
- if (!lp->eepro) {
- if (lp->word[7] == ee_FX_INT2IRQ)
- lp->eepro = 2;
- else if (station_addr[2] == SA_ADDR1)
- lp->eepro = 1;
- }
-
- /* Fill in the 'dev' fields. */
- for (i=0; i < 6; i++)
- dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
-
- /* RX buffer must be more than 3K and less than 29K */
- if (dev->mem_end < 3072 || dev->mem_end > 29696)
- lp->rcv_ram = RCV_DEFAULT_RAM;
-
- /* calculate {xmt,rcv}_{lower,upper}_limit */
- eepro_recalc(dev);
-
- if (GetBit(lp->word[5], ee_BNC_TPE))
- dev->if_port = BNC;
- else
- dev->if_port = TPE;
-
- if (dev->irq < 2 && lp->eepro != 0) {
- /* Mask off INT number */
- int count = lp->word[1] & 7;
- unsigned irqMask = lp->word[7];
-
- while (count--)
- irqMask &= irqMask - 1;
-
- count = ffs(irqMask);
-
- if (count)
- dev->irq = count - 1;
-
- if (dev->irq < 2) {
- printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n");
- goto exit;
- } else if (dev->irq == 2) {
- dev->irq = 9;
- }
- }
-
- dev->netdev_ops = &eepro_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
- dev->ethtool_ops = &eepro_ethtool_ops;
-
- /* print boot time info */
- eepro_print_info(dev);
-
- /* reset 82595 */
- eepro_reset(ioaddr);
-
- err = register_netdev(dev);
- if (err)
- goto err;
- return 0;
-exit:
- err = -ENODEV;
-err:
- release_region(dev->base_addr, EEPRO_IO_EXTENT);
- return err;
-}
-
-/* Open/initialize the board. This is called (in the current kernel)
- sometime after booting when the 'ifconfig' program is run.
-
- This routine should set everything up anew at each open, even
- registers that "should" only need to be set once at boot, so that
- there is non-reboot way to recover if something goes wrong.
- */
-
-static const char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
-static const char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
-static int eepro_grab_irq(struct net_device *dev)
-{
- static const int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
- const int *irqp = irqlist;
- int temp_reg, ioaddr = dev->base_addr;
-
- eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
- /* Enable the interrupt line. */
- eepro_en_intline(ioaddr);
-
- /* be CAREFUL, BANK 0 now */
- eepro_sw2bank0(ioaddr);
-
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
-
- /* Let EXEC event to interrupt */
- eepro_en_intexec(ioaddr);
-
- do {
- eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
- temp_reg = inb(ioaddr + INT_NO_REG);
- outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG);
-
- eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
- if (request_irq (*irqp, NULL, IRQF_SHARED, "bogus", dev) != EBUSY) {
- unsigned long irq_mask;
- /* Twinkle the interrupt, and check if it's seen */
- irq_mask = probe_irq_on();
-
- eepro_diag(ioaddr); /* RESET the 82595 */
- mdelay(20);
-
- if (*irqp == probe_irq_off(irq_mask)) /* It's a good IRQ line */
- break;
-
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
- }
- } while (*++irqp);
-
- eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
-
- /* Disable the physical interrupt line. */
- eepro_dis_intline(ioaddr);
-
- eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
- /* Mask all the interrupts. */
- eepro_dis_int(ioaddr);
-
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
-
- return dev->irq;
-}
-
-static int eepro_open(struct net_device *dev)
-{
- unsigned short temp_reg, old8, old9;
- int irqMask;
- int i, ioaddr = dev->base_addr;
- struct eepro_local *lp = netdev_priv(dev);
-
- if (net_debug > 3)
- printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name);
-
- irqMask = lp->word[7];
-
- if (lp->eepro == LAN595FX_10ISA) {
- if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n");
- }
- else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */
- {
- lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */
- if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n");
- }
-
- else if ((dev->dev_addr[0] == SA_ADDR0 &&
- dev->dev_addr[1] == SA_ADDR1 &&
- dev->dev_addr[2] == SA_ADDR2))
- {
- lp->eepro = 1;
- if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n");
- } /* Yes, an Intel EtherExpress Pro/10 */
-
- else lp->eepro = 0; /* No, it is a generic 82585 lan card */
-
- /* Get the interrupt vector for the 82595 */
- if (dev->irq < 2 && eepro_grab_irq(dev) == 0) {
- printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
- return -EAGAIN;
- }
-
- if (request_irq(dev->irq , eepro_interrupt, 0, dev->name, dev)) {
- printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
- return -EAGAIN;
- }
-
- /* Initialize the 82595. */
-
- eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
- temp_reg = inb(ioaddr + lp->eeprom_reg);
-
- lp->stepping = temp_reg >> 5; /* Get the stepping number of the 595 */
-
- if (net_debug > 3)
- printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping);
-
- if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
- outb(temp_reg & 0xef, ioaddr + lp->eeprom_reg);
- for (i=0; i < 6; i++)
- outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
-
- temp_reg = inb(ioaddr + REG1); /* Setup Transmit Chaining */
- outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
- | RCV_Discard_BadFrame, ioaddr + REG1);
-
- temp_reg = inb(ioaddr + REG2); /* Match broadcast */
- outb(temp_reg | 0x14, ioaddr + REG2);
-
- temp_reg = inb(ioaddr + REG3);
- outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
-
- /* Set the receiving mode */
- eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
-
- /* Set the interrupt vector */
- temp_reg = inb(ioaddr + INT_NO_REG);
- if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
- outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);
- else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
-
- temp_reg = inb(ioaddr + INT_NO_REG);
- if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA)
- outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);
- else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
-
- if (net_debug > 3)
- printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg);
-
-
- /* Initialize the RCV and XMT upper and lower limits */
- outb(lp->rcv_lower_limit >> 8, ioaddr + RCV_LOWER_LIMIT_REG);
- outb(lp->rcv_upper_limit >> 8, ioaddr + RCV_UPPER_LIMIT_REG);
- outb(lp->xmt_lower_limit >> 8, ioaddr + lp->xmt_lower_limit_reg);
- outb(lp->xmt_upper_limit >> 8, ioaddr + lp->xmt_upper_limit_reg);
-
- /* Enable the interrupt line. */
- eepro_en_intline(ioaddr);
-
- /* Switch back to Bank 0 */
- eepro_sw2bank0(ioaddr);
-
- /* Let RX and TX events to interrupt */
- eepro_en_int(ioaddr);
-
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
-
- /* Initialize RCV */
- outw(lp->rcv_lower_limit, ioaddr + RCV_BAR);
- lp->rx_start = lp->rcv_lower_limit;
- outw(lp->rcv_upper_limit | 0xfe, ioaddr + RCV_STOP);
-
- /* Initialize XMT */
- outw(lp->xmt_lower_limit, ioaddr + lp->xmt_bar);
- lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
- lp->tx_last = 0;
-
- /* Check for the i82595TX and i82595FX */
- old8 = inb(ioaddr + 8);
- outb(~old8, ioaddr + 8);
-
- if ((temp_reg = inb(ioaddr + 8)) == old8) {
- if (net_debug > 3)
- printk(KERN_DEBUG "i82595 detected!\n");
- lp->version = LAN595;
- }
- else {
- lp->version = LAN595TX;
- outb(old8, ioaddr + 8);
- old9 = inb(ioaddr + 9);
-
- if (irqMask==ee_FX_INT2IRQ) {
- if (net_debug > 3) {
- printk(KERN_DEBUG "IrqMask: %#x\n",irqMask);
- printk(KERN_DEBUG "i82595FX detected!\n");
- }
- lp->version = LAN595FX;
- outb(old9, ioaddr + 9);
- if (dev->if_port != TPE) { /* Hopefully, this will fix the
- problem of using Pentiums and
- pro/10 w/ BNC. */
- eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
- temp_reg = inb(ioaddr + REG13);
- /* disable the full duplex mode since it is not
- applicable with the 10Base2 cable. */
- outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);
- eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
- }
- }
- else if (net_debug > 3) {
- printk(KERN_DEBUG "temp_reg: %#x ~old9: %#x\n",temp_reg,((~old9)&0xff));
- printk(KERN_DEBUG "i82595TX detected!\n");
- }
- }
-
- eepro_sel_reset(ioaddr);
-
- netif_start_queue(dev);
-
- if (net_debug > 3)
- printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name);
-
- /* enabling rx */
- eepro_en_rx(ioaddr);
-
- return 0;
-}
-
-static void eepro_tx_timeout (struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- /* if (net_debug > 1) */
- printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
- "network cable problem");
- /* This is not a duplicate. One message for the console,
- one for the log file */
- printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
- "network cable problem");
- eepro_complete_selreset(ioaddr);
-}
-
-
-static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- unsigned long flags;
- int ioaddr = dev->base_addr;
- short length = skb->len;
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name);
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
- netif_stop_queue (dev);
-
- eepro_dis_int(ioaddr);
- spin_lock_irqsave(&lp->lock, flags);
-
- {
- unsigned char *buf = skb->data;
-
- if (hardware_send_packet(dev, buf, length))
- /* we won't wake queue here because we're out of space */
- dev->stats.tx_dropped++;
- else {
- dev->stats.tx_bytes+=skb->len;
- netif_wake_queue(dev);
- }
-
- }
-
- dev_kfree_skb (skb);
-
- /* You might need to clean up and record Tx statistics here. */
- /* dev->stats.tx_aborted_errors++; */
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
-
- eepro_en_int(ioaddr);
- spin_unlock_irqrestore(&lp->lock, flags);
-
- return NETDEV_TX_OK;
-}
-
-
-/* The typical workload of the driver:
- Handle the network interface interrupts. */
-
-static irqreturn_t
-eepro_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct eepro_local *lp;
- int ioaddr, status, boguscount = 20;
- int handled = 0;
-
- lp = netdev_priv(dev);
-
- spin_lock(&lp->lock);
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name);
-
- ioaddr = dev->base_addr;
-
- while (((status = inb(ioaddr + STATUS_REG)) & (RX_INT|TX_INT)) && (boguscount--))
- {
- handled = 1;
- if (status & RX_INT) {
- if (net_debug > 4)
- printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name);
-
- eepro_dis_int(ioaddr);
-
- /* Get the received packets */
- eepro_ack_rx(ioaddr);
- eepro_rx(dev);
-
- eepro_en_int(ioaddr);
- }
- if (status & TX_INT) {
- if (net_debug > 4)
- printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
-
-
- eepro_dis_int(ioaddr);
-
- /* Process the status of transmitted packets */
- eepro_ack_tx(ioaddr);
- eepro_transmit_interrupt(dev);
-
- eepro_en_int(ioaddr);
- }
- }
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name);
-
- spin_unlock(&lp->lock);
- return IRQ_RETVAL(handled);
-}
-
-static int eepro_close(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- short temp_reg;
-
- netif_stop_queue(dev);
-
- eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
-
- /* Disable the physical interrupt line. */
- temp_reg = inb(ioaddr + REG1);
- outb(temp_reg & 0x7f, ioaddr + REG1);
-
- eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
-
- /* Flush the Tx and disable Rx. */
- outb(STOP_RCV_CMD, ioaddr);
- lp->tx_start = lp->tx_end = lp->xmt_lower_limit;
- lp->tx_last = 0;
-
- /* Mask all the interrupts. */
- eepro_dis_int(ioaddr);
-
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
-
- /* Reset the 82595 */
- eepro_reset(ioaddr);
-
- /* release the interrupt */
- free_irq(dev->irq, dev);
-
- /* Update the statistics here. What statistics? */
-
- return 0;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- */
-static void
-set_multicast_list(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- unsigned short mode;
- struct netdev_hw_addr *ha;
- int mc_count = netdev_mc_count(dev);
-
- if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63)
- {
- eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
- mode = inb(ioaddr + REG2);
- outb(mode | PRMSC_Mode, ioaddr + REG2);
- mode = inb(ioaddr + REG3);
- outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
- eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
- }
-
- else if (mc_count == 0)
- {
- eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
- mode = inb(ioaddr + REG2);
- outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
- mode = inb(ioaddr + REG3);
- outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
- eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
- }
-
- else
- {
- unsigned short status, *eaddrs;
- int i, boguscount = 0;
-
- /* Disable RX and TX interrupts. Necessary to avoid
- corruption of the HOST_ADDRESS_REG by interrupt
- service routines. */
- eepro_dis_int(ioaddr);
-
- eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
- mode = inb(ioaddr + REG2);
- outb(mode | Multi_IA, ioaddr + REG2);
- mode = inb(ioaddr + REG3);
- outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
- eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
- outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
- outw(MC_SETUP, ioaddr + IO_PORT);
- outw(0, ioaddr + IO_PORT);
- outw(0, ioaddr + IO_PORT);
- outw(6 * (mc_count + 1), ioaddr + IO_PORT);
-
- netdev_for_each_mc_addr(ha, dev) {
- eaddrs = (unsigned short *) ha->addr;
- outw(*eaddrs++, ioaddr + IO_PORT);
- outw(*eaddrs++, ioaddr + IO_PORT);
- outw(*eaddrs++, ioaddr + IO_PORT);
- }
-
- eaddrs = (unsigned short *) dev->dev_addr;
- outw(eaddrs[0], ioaddr + IO_PORT);
- outw(eaddrs[1], ioaddr + IO_PORT);
- outw(eaddrs[2], ioaddr + IO_PORT);
- outw(lp->tx_end, ioaddr + lp->xmt_bar);
- outb(MC_SETUP, ioaddr);
-
- /* Update the transmit queue */
- i = lp->tx_end + XMT_HEADER + 6 * (mc_count + 1);
-
- if (lp->tx_start != lp->tx_end)
- {
- /* update the next address and the chain bit in the
- last packet */
- outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
- outw(i, ioaddr + IO_PORT);
- outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
- status = inw(ioaddr + IO_PORT);
- outw(status | CHAIN_BIT, ioaddr + IO_PORT);
- lp->tx_end = i ;
- }
- else {
- lp->tx_start = lp->tx_end = i ;
- }
-
- /* Acknowledge that the MC setup is done */
- do { /* We should be doing this in the eepro_interrupt()! */
- SLOW_DOWN;
- SLOW_DOWN;
- if (inb(ioaddr + STATUS_REG) & 0x08)
- {
- i = inb(ioaddr);
- outb(0x08, ioaddr + STATUS_REG);
-
- if (i & 0x20) { /* command ABORTed */
- printk(KERN_NOTICE "%s: multicast setup failed.\n",
- dev->name);
- break;
- } else if ((i & 0x0f) == 0x03) { /* MC-Done */
- printk(KERN_DEBUG "%s: set Rx mode to %d address%s.\n",
- dev->name, mc_count,
- mc_count > 1 ? "es":"");
- break;
- }
- }
- } while (++boguscount < 100);
-
- /* Re-enable RX and TX interrupts */
- eepro_en_int(ioaddr);
- }
- if (lp->eepro == LAN595FX_10ISA) {
- eepro_complete_selreset(ioaddr);
- }
- else
- eepro_en_rx(ioaddr);
-}
-
-/* The horrible routine to read a word from the serial EEPROM. */
-/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
-
-/* The delay between EEPROM clock transitions. */
-#define eeprom_delay() { udelay(40); }
-#define EE_READ_CMD (6 << 6)
-
-static int
-read_eeprom(int ioaddr, int location, struct net_device *dev)
-{
- int i;
- unsigned short retval = 0;
- struct eepro_local *lp = netdev_priv(dev);
- short ee_addr = ioaddr + lp->eeprom_reg;
- int read_cmd = location | EE_READ_CMD;
- short ctrl_val = EECS ;
-
- /* XXXX - black magic */
- eepro_sw2bank1(ioaddr);
- outb(0x00, ioaddr + STATUS_REG);
- /* XXXX - black magic */
-
- eepro_sw2bank2(ioaddr);
- outb(ctrl_val, ee_addr);
-
- /* Shift the read command bits out. */
- for (i = 8; i >= 0; i--) {
- short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI
- : ctrl_val;
- outb(outval, ee_addr);
- outb(outval | EESK, ee_addr); /* EEPROM clock tick. */
- eeprom_delay();
- outb(outval, ee_addr); /* Finish EEPROM a clock tick. */
- eeprom_delay();
- }
- outb(ctrl_val, ee_addr);
-
- for (i = 16; i > 0; i--) {
- outb(ctrl_val | EESK, ee_addr); eeprom_delay();
- retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
- outb(ctrl_val, ee_addr); eeprom_delay();
- }
-
- /* Terminate the EEPROM access. */
- ctrl_val &= ~EECS;
- outb(ctrl_val | EESK, ee_addr);
- eeprom_delay();
- outb(ctrl_val, ee_addr);
- eeprom_delay();
- eepro_sw2bank0(ioaddr);
- return retval;
-}
-
-static int
-hardware_send_packet(struct net_device *dev, void *buf, short length)
-{
- struct eepro_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- unsigned status, tx_available, last, end;
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name);
-
- /* determine how much of the transmit buffer space is available */
- if (lp->tx_end > lp->tx_start)
- tx_available = lp->xmt_ram - (lp->tx_end - lp->tx_start);
- else if (lp->tx_end < lp->tx_start)
- tx_available = lp->tx_start - lp->tx_end;
- else tx_available = lp->xmt_ram;
-
- if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) {
- /* No space available ??? */
- return 1;
- }
-
- last = lp->tx_end;
- end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
-
- if (end >= lp->xmt_upper_limit + 2) { /* the transmit buffer is wrapped around */
- if ((lp->xmt_upper_limit + 2 - last) <= XMT_HEADER) {
- /* Arrrr!!!, must keep the xmt header together,
- several days were lost to chase this one down. */
- last = lp->xmt_lower_limit;
- end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
- }
- else end = lp->xmt_lower_limit + (end -
- lp->xmt_upper_limit + 2);
- }
-
- outw(last, ioaddr + HOST_ADDRESS_REG);
- outw(XMT_CMD, ioaddr + IO_PORT);
- outw(0, ioaddr + IO_PORT);
- outw(end, ioaddr + IO_PORT);
- outw(length, ioaddr + IO_PORT);
-
- if (lp->version == LAN595)
- outsw(ioaddr + IO_PORT, buf, (length + 3) >> 1);
- else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
- unsigned short temp = inb(ioaddr + INT_MASK_REG);
- outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
- outsl(ioaddr + IO_PORT_32_BIT, buf, (length + 3) >> 2);
- outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
- }
-
- /* A dummy read to flush the DRAM write pipeline */
- status = inw(ioaddr + IO_PORT);
-
- if (lp->tx_start == lp->tx_end) {
- outw(last, ioaddr + lp->xmt_bar);
- outb(XMT_CMD, ioaddr);
- lp->tx_start = last; /* I don't like to change tx_start here */
- }
- else {
- /* update the next address and the chain bit in the
- last packet */
-
- if (lp->tx_end != last) {
- outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
- outw(last, ioaddr + IO_PORT);
- }
-
- outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
- status = inw(ioaddr + IO_PORT);
- outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-
- /* Continue the transmit command */
- outb(RESUME_XMT_CMD, ioaddr);
- }
-
- lp->tx_last = last;
- lp->tx_end = end;
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
-
- return 0;
-}
-
-static void
-eepro_rx(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- short boguscount = 20;
- short rcv_car = lp->rx_start;
- unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name);
-
- /* Set the read pointer to the start of the RCV */
- outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
-
- rcv_event = inw(ioaddr + IO_PORT);
-
- while (rcv_event == RCV_DONE) {
-
- rcv_status = inw(ioaddr + IO_PORT);
- rcv_next_frame = inw(ioaddr + IO_PORT);
- rcv_size = inw(ioaddr + IO_PORT);
-
- if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
-
- /* Malloc up new buffer. */
- struct sk_buff *skb;
-
- dev->stats.rx_bytes+=rcv_size;
- rcv_size &= 0x3fff;
- skb = netdev_alloc_skb(dev, rcv_size + 5);
- if (skb == NULL) {
- printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
- lp->rx_start = rcv_next_frame;
- outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
-
- break;
- }
- skb_reserve(skb,2);
-
- if (lp->version == LAN595)
- insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);
- else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
- unsigned short temp = inb(ioaddr + INT_MASK_REG);
- outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
- insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size),
- (rcv_size + 3) >> 2);
- outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
- }
-
- skb->protocol = eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- }
-
- else { /* Not sure will ever reach here,
- I set the 595 to discard bad received frames */
- dev->stats.rx_errors++;
-
- if (rcv_status & 0x0100)
- dev->stats.rx_over_errors++;
-
- else if (rcv_status & 0x0400)
- dev->stats.rx_frame_errors++;
-
- else if (rcv_status & 0x0800)
- dev->stats.rx_crc_errors++;
-
- printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
- dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
- }
-
- if (rcv_status & 0x1000)
- dev->stats.rx_length_errors++;
-
- rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
- lp->rx_start = rcv_next_frame;
-
- if (--boguscount == 0)
- break;
-
- outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
- rcv_event = inw(ioaddr + IO_PORT);
-
- }
- if (rcv_car == 0)
- rcv_car = lp->rcv_upper_limit | 0xff;
-
- outw(rcv_car - 1, ioaddr + RCV_STOP);
-
- if (net_debug > 5)
- printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);
-}
-
-static void
-eepro_transmit_interrupt(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- short boguscount = 25;
- short xmt_status;
-
- while ((lp->tx_start != lp->tx_end) && boguscount--) {
-
- outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
- xmt_status = inw(ioaddr+IO_PORT);
-
- if (!(xmt_status & TX_DONE_BIT))
- break;
-
- xmt_status = inw(ioaddr+IO_PORT);
- lp->tx_start = inw(ioaddr+IO_PORT);
-
- netif_wake_queue (dev);
-
- if (xmt_status & TX_OK)
- dev->stats.tx_packets++;
- else {
- dev->stats.tx_errors++;
- if (xmt_status & 0x0400) {
- dev->stats.tx_carrier_errors++;
- printk(KERN_DEBUG "%s: carrier error\n",
- dev->name);
- printk(KERN_DEBUG "%s: XMT status = %#x\n",
- dev->name, xmt_status);
- }
- else {
- printk(KERN_DEBUG "%s: XMT status = %#x\n",
- dev->name, xmt_status);
- printk(KERN_DEBUG "%s: XMT status = %#x\n",
- dev->name, xmt_status);
- }
- }
- if (xmt_status & 0x000f) {
- dev->stats.collisions += (xmt_status & 0x000f);
- }
-
- if ((xmt_status & 0x0040) == 0x0) {
- dev->stats.tx_heartbeat_errors++;
- }
- }
-}
-
-static int eepro_ethtool_get_settings(struct net_device *dev,
- struct ethtool_cmd *cmd)
-{
- struct eepro_local *lp = netdev_priv(dev);
-
- cmd->supported = SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_Autoneg;
- cmd->advertising = ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_Autoneg;
-
- if (GetBit(lp->word[5], ee_PortTPE)) {
- cmd->supported |= SUPPORTED_TP;
- cmd->advertising |= ADVERTISED_TP;
- }
- if (GetBit(lp->word[5], ee_PortBNC)) {
- cmd->supported |= SUPPORTED_BNC;
- cmd->advertising |= ADVERTISED_BNC;
- }
- if (GetBit(lp->word[5], ee_PortAUI)) {
- cmd->supported |= SUPPORTED_AUI;
- cmd->advertising |= ADVERTISED_AUI;
- }
-
- ethtool_cmd_speed_set(cmd, SPEED_10);
-
- if (dev->if_port == TPE && lp->word[1] & ee_Duplex) {
- cmd->duplex = DUPLEX_FULL;
- }
- else {
- cmd->duplex = DUPLEX_HALF;
- }
-
- cmd->port = dev->if_port;
- cmd->phy_address = dev->base_addr;
- cmd->transceiver = XCVR_INTERNAL;
-
- if (lp->word[0] & ee_AutoNeg) {
- cmd->autoneg = 1;
- }
-
- return 0;
-}
-
-static void eepro_ethtool_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *drvinfo)
-{
- strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
- strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
- snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
- "ISA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops eepro_ethtool_ops = {
- .get_settings = eepro_ethtool_get_settings,
- .get_drvinfo = eepro_ethtool_get_drvinfo,
-};
-
-#ifdef MODULE
-
-#define MAX_EEPRO 8
-static struct net_device *dev_eepro[MAX_EEPRO];
-
-static int io[MAX_EEPRO] = {
- [0 ... MAX_EEPRO-1] = -1
-};
-static int irq[MAX_EEPRO];
-static int mem[MAX_EEPRO] = { /* Size of the rx buffer in KB */
- [0 ... MAX_EEPRO-1] = RCV_DEFAULT_RAM/1024
-};
-static int autodetect;
-
-static int n_eepro;
-/* For linux 2.1.xx */
-
-MODULE_AUTHOR("Pascal Dupuis and others");
-MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
-MODULE_LICENSE("GPL");
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(mem, int, NULL, 0);
-module_param(autodetect, int, 0);
-MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");
-MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");
-MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");
-
-int __init init_module(void)
-{
- struct net_device *dev;
- int i;
- if (io[0] == -1 && autodetect == 0) {
- printk(KERN_WARNING "eepro_init_module: Probe is very dangerous in ISA boards!\n");
- printk(KERN_WARNING "eepro_init_module: Please add \"autodetect=1\" to force probe\n");
- return -ENODEV;
- }
- else if (autodetect) {
- /* if autodetect is set then we must force detection */
- for (i = 0; i < MAX_EEPRO; i++) {
- io[i] = 0;
- }
-
- printk(KERN_INFO "eepro_init_module: Auto-detecting boards (May God protect us...)\n");
- }
-
- for (i = 0; i < MAX_EEPRO && io[i] != -1; i++) {
- dev = alloc_etherdev(sizeof(struct eepro_local));
- if (!dev)
- break;
-
- dev->mem_end = mem[i];
- dev->base_addr = io[i];
- dev->irq = irq[i];
-
- if (do_eepro_probe(dev) == 0) {
- dev_eepro[n_eepro++] = dev;
- continue;
- }
- free_netdev(dev);
- break;
- }
-
- if (n_eepro)
- printk(KERN_INFO "%s", version);
-
- return n_eepro ? 0 : -ENODEV;
-}
-
-void __exit
-cleanup_module(void)
-{
- int i;
-
- for (i=0; i<n_eepro; i++) {
- struct net_device *dev = dev_eepro[i];
- unregister_netdev(dev);
- release_region(dev->base_addr, EEPRO_IO_EXTENT);
- free_netdev(dev);
- }
-}
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/i825xx/eexpress.c b/drivers/net/ethernet/i825xx/eexpress.c
deleted file mode 100644
index 7a6a2f04c5b1..000000000000
--- a/drivers/net/ethernet/i825xx/eexpress.c
+++ /dev/null
@@ -1,1661 +0,0 @@
-/* Intel EtherExpress 16 device driver for Linux
- *
- * Written by John Sullivan, 1995
- * based on original code by Donald Becker, with changes by
- * Alan Cox and Pauline Middelink.
- *
- * Support for 8-bit mode by Zoltan Szilagyi <zoltans@cs.arizona.edu>
- *
- * Many modifications, and currently maintained, by
- * Philip Blundell <philb@gnu.org>
- * Added the Compaq LTE Alan Cox <alan@lxorguk.ukuu.org.uk>
- * Added MCA support Adam Fritzler (now deleted)
- *
- * Note - this driver is experimental still - it has problems on faster
- * machines. Someone needs to sit down and go through it line by line with
- * a databook...
- */
-
-/* The EtherExpress 16 is a fairly simple card, based on a shared-memory
- * design using the i82586 Ethernet coprocessor. It bears no relationship,
- * as far as I know, to the similarly-named "EtherExpress Pro" range.
- *
- * Historically, Linux support for these cards has been very bad. However,
- * things seem to be getting better slowly.
- */
-
-/* If your card is confused about what sort of interface it has (eg it
- * persistently reports "10baseT" when none is fitted), running 'SOFTSET /BART'
- * or 'SOFTSET /LISA' from DOS seems to help.
- */
-
-/* Here's the scoop on memory mapping.
- *
- * There are three ways to access EtherExpress card memory: either using the
- * shared-memory mapping, or using PIO through the dataport, or using PIO
- * through the "shadow memory" ports.
- *
- * The shadow memory system works by having the card map some of its memory
- * as follows:
- *
- * (the low five bits of the SMPTR are ignored)
- *
- * base+0x4000..400f memory at SMPTR+0..15
- * base+0x8000..800f memory at SMPTR+16..31
- * base+0xc000..c007 dubious stuff (memory at SMPTR+16..23 apparently)
- * base+0xc008..c00f memory at 0x0008..0x000f
- *
- * This last set (the one at c008) is particularly handy because the SCB
- * lives at 0x0008. So that set of ports gives us easy random access to data
- * in the SCB without having to mess around setting up pointers and the like.
- * We always use this method to access the SCB (via the scb_xx() functions).
- *
- * Dataport access works by aiming the appropriate (read or write) pointer
- * at the first address you're interested in, and then reading or writing from
- * the dataport. The pointers auto-increment after each transfer. We use
- * this for data transfer.
- *
- * We don't use the shared-memory system because it allegedly doesn't work on
- * all cards, and because it's a bit more prone to go wrong (it's one more
- * thing to configure...).
- */
-
-/* Known bugs:
- *
- * - The card seems to want to give us two interrupts every time something
- * happens, where just one would be better.
- */
-
-/*
- *
- * Note by Zoltan Szilagyi 10-12-96:
- *
- * I've succeeded in eliminating the "CU wedged" messages, and hence the
- * lockups, which were only occurring with cards running in 8-bit mode ("force
- * 8-bit operation" in Intel's SoftSet utility). This version of the driver
- * sets the 82586 and the ASIC to 8-bit mode at startup; it also stops the
- * CU before submitting a packet for transmission, and then restarts it as soon
- * as the process of handing the packet is complete. This is definitely an
- * unnecessary slowdown if the card is running in 16-bit mode; therefore one
- * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
- * accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for
- * ftp's, which is significantly better than I get in DOS, so the overhead of
- * stopping and restarting the CU with each transmit is not prohibitive in
- * practice.
- *
- * Update by David Woodhouse 11/5/99:
- *
- * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture.
- * I assume that this is because 16-bit accesses are actually handled as two
- * 8-bit accesses.
- */
-
-#ifdef __alpha__
-#define LOCKUP16 1
-#endif
-#ifndef LOCKUP16
-#define LOCKUP16 0
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#ifndef NET_DEBUG
-#define NET_DEBUG 4
-#endif
-
-#include "eexpress.h"
-
-#define EEXP_IO_EXTENT 16
-
-/*
- * Private data declarations
- */
-
-struct net_local
-{
- unsigned long last_tx; /* jiffies when last transmit started */
- unsigned long init_time; /* jiffies when eexp_hw_init586 called */
- unsigned short rx_first; /* first rx buf, same as RX_BUF_START */
- unsigned short rx_last; /* last rx buf */
- unsigned short rx_ptr; /* first rx buf to look at */
- unsigned short tx_head; /* next free tx buf */
- unsigned short tx_reap; /* first in-use tx buf */
- unsigned short tx_tail; /* previous tx buf to tx_head */
- unsigned short tx_link; /* last known-executing tx buf */
- unsigned short last_tx_restart; /* set to tx_link when we
- restart the CU */
- unsigned char started;
- unsigned short rx_buf_start;
- unsigned short rx_buf_end;
- unsigned short num_tx_bufs;
- unsigned short num_rx_bufs;
- unsigned char width; /* 0 for 16bit, 1 for 8bit */
- unsigned char was_promisc;
- unsigned char old_mc_count;
- spinlock_t lock;
-};
-
-/* This is the code and data that is downloaded to the EtherExpress card's
- * memory at boot time.
- */
-
-static unsigned short start_code[] = {
-/* 0x0000 */
- 0x0001, /* ISCP: busy - cleared after reset */
- 0x0008,0x0000,0x0000, /* offset,address (lo,hi) of SCB */
-
- 0x0000,0x0000, /* SCB: status, commands */
- 0x0000,0x0000, /* links to first command block,
- first receive descriptor */
- 0x0000,0x0000, /* CRC error, alignment error counts */
- 0x0000,0x0000, /* out of resources, overrun error counts */
-
- 0x0000,0x0000, /* pad */
- 0x0000,0x0000,
-
-/* 0x20 -- start of 82586 CU program */
-#define CONF_LINK 0x20
- 0x0000,Cmd_Config,
- 0x0032, /* link to next command */
- 0x080c, /* 12 bytes follow : fifo threshold=8 */
- 0x2e40, /* don't rx bad frames
- * SRDY/ARDY => ext. sync. : preamble len=8
- * take addresses from data buffers
- * 6 bytes/address
- */
- 0x6000, /* default backoff method & priority
- * interframe spacing = 0x60 */
- 0xf200, /* slot time=0x200
- * max collision retry = 0xf */
-#define CONF_PROMISC 0x2e
- 0x0000, /* no HDLC : normal CRC : enable broadcast
- * disable promiscuous/multicast modes */
- 0x003c, /* minimum frame length = 60 octets) */
-
- 0x0000,Cmd_SetAddr,
- 0x003e, /* link to next command */
-#define CONF_HWADDR 0x38
- 0x0000,0x0000,0x0000, /* hardware address placed here */
-
- 0x0000,Cmd_MCast,
- 0x0076, /* link to next command */
-#define CONF_NR_MULTICAST 0x44
- 0x0000, /* number of bytes in multicast address(es) */
-#define CONF_MULTICAST 0x46
- 0x0000, 0x0000, 0x0000, /* some addresses */
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000,
-
-#define CONF_DIAG_RESULT 0x76
- 0x0000, Cmd_Diag,
- 0x007c, /* link to next command */
-
- 0x0000,Cmd_TDR|Cmd_INT,
- 0x0084,
-#define CONF_TDR_RESULT 0x82
- 0x0000,
-
- 0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */
- 0x0084 /* dummy link */
-};
-
-/* maps irq number to EtherExpress magic value */
-static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
-
-/*
- * Prototypes for Linux interface
- */
-
-static int eexp_open(struct net_device *dev);
-static int eexp_close(struct net_device *dev);
-static void eexp_timeout(struct net_device *dev);
-static netdev_tx_t eexp_xmit(struct sk_buff *buf,
- struct net_device *dev);
-
-static irqreturn_t eexp_irq(int irq, void *dev_addr);
-static void eexp_set_multicast(struct net_device *dev);
-
-/*
- * Prototypes for hardware access functions
- */
-
-static void eexp_hw_rx_pio(struct net_device *dev);
-static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
- unsigned short len);
-static int eexp_hw_probe(struct net_device *dev,unsigned short ioaddr);
-static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,
- unsigned char location);
-
-static unsigned short eexp_hw_lasttxstat(struct net_device *dev);
-static void eexp_hw_txrestart(struct net_device *dev);
-
-static void eexp_hw_txinit (struct net_device *dev);
-static void eexp_hw_rxinit (struct net_device *dev);
-
-static void eexp_hw_init586 (struct net_device *dev);
-static void eexp_setup_filter (struct net_device *dev);
-
-static char *eexp_ifmap[]={"AUI", "BNC", "RJ45"};
-enum eexp_iftype {AUI=0, BNC=1, TPE=2};
-
-#define STARTED_RU 2
-#define STARTED_CU 1
-
-/*
- * Primitive hardware access functions.
- */
-
-static inline unsigned short scb_status(struct net_device *dev)
-{
- return inw(dev->base_addr + 0xc008);
-}
-
-static inline unsigned short scb_rdcmd(struct net_device *dev)
-{
- return inw(dev->base_addr + 0xc00a);
-}
-
-static inline void scb_command(struct net_device *dev, unsigned short cmd)
-{
- outw(cmd, dev->base_addr + 0xc00a);
-}
-
-static inline void scb_wrcbl(struct net_device *dev, unsigned short val)
-{
- outw(val, dev->base_addr + 0xc00c);
-}
-
-static inline void scb_wrrfa(struct net_device *dev, unsigned short val)
-{
- outw(val, dev->base_addr + 0xc00e);
-}
-
-static inline void set_loopback(struct net_device *dev)
-{
- outb(inb(dev->base_addr + Config) | 2, dev->base_addr + Config);
-}
-
-static inline void clear_loopback(struct net_device *dev)
-{
- outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config);
-}
-
-static inline unsigned short int SHADOW(short int addr)
-{
- addr &= 0x1f;
- if (addr > 0xf) addr += 0x3ff0;
- return addr + 0x4000;
-}
-
-/*
- * Linux interface
- */
-
-/*
- * checks for presence of EtherExpress card
- */
-
-static int __init do_express_probe(struct net_device *dev)
-{
- unsigned short *port;
- static unsigned short ports[] = { 0x240,0x300,0x310,0x270,0x320,0x340,0 };
- unsigned short ioaddr = dev->base_addr;
- int dev_irq = dev->irq;
- int err;
-
- dev->if_port = 0xff; /* not set */
-
- if (ioaddr&0xfe00) {
- if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress"))
- return -EBUSY;
- err = eexp_hw_probe(dev,ioaddr);
- release_region(ioaddr, EEXP_IO_EXTENT);
- return err;
- } else if (ioaddr)
- return -ENXIO;
-
- for (port=&ports[0] ; *port ; port++ )
- {
- unsigned short sum = 0;
- int i;
- if (!request_region(*port, EEXP_IO_EXTENT, "EtherExpress"))
- continue;
- for ( i=0 ; i<4 ; i++ )
- {
- unsigned short t;
- t = inb(*port + ID_PORT);
- sum |= (t>>4) << ((t & 0x03)<<2);
- }
- if (sum==0xbaba && !eexp_hw_probe(dev,*port)) {
- release_region(*port, EEXP_IO_EXTENT);
- return 0;
- }
- release_region(*port, EEXP_IO_EXTENT);
- dev->irq = dev_irq;
- }
- return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init express_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- int err;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
-
- err = do_express_probe(dev);
- if (!err)
- return dev;
- free_netdev(dev);
- return ERR_PTR(err);
-}
-#endif
-
-/*
- * open and initialize the adapter, ready for use
- */
-
-static int eexp_open(struct net_device *dev)
-{
- int ret;
- unsigned short ioaddr = dev->base_addr;
- struct net_local *lp = netdev_priv(dev);
-
-#if NET_DEBUG > 6
- printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);
-#endif
-
- if (!dev->irq || !irqrmap[dev->irq])
- return -ENXIO;
-
- ret = request_irq(dev->irq, eexp_irq, 0, dev->name, dev);
- if (ret)
- return ret;
-
- if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) {
- printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
- , ioaddr);
- goto err_out1;
- }
- if (!request_region(ioaddr+0x4000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
- printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
- , ioaddr+0x4000);
- goto err_out2;
- }
- if (!request_region(ioaddr+0x8000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
- printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
- , ioaddr+0x8000);
- goto err_out3;
- }
- if (!request_region(ioaddr+0xc000, EEXP_IO_EXTENT, "EtherExpress shadow")) {
- printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
- , ioaddr+0xc000);
- goto err_out4;
- }
-
- if (lp->width) {
- printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
- outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config);
- }
-
- eexp_hw_init586(dev);
- netif_start_queue(dev);
-#if NET_DEBUG > 6
- printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);
-#endif
- return 0;
-
- err_out4:
- release_region(ioaddr+0x8000, EEXP_IO_EXTENT);
- err_out3:
- release_region(ioaddr+0x4000, EEXP_IO_EXTENT);
- err_out2:
- release_region(ioaddr, EEXP_IO_EXTENT);
- err_out1:
- free_irq(dev->irq, dev);
- return -EBUSY;
-}
-
-/*
- * close and disable the interface, leaving the 586 in reset.
- */
-
-static int eexp_close(struct net_device *dev)
-{
- unsigned short ioaddr = dev->base_addr;
- struct net_local *lp = netdev_priv(dev);
-
- int irq = dev->irq;
-
- netif_stop_queue(dev);
-
- outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
- lp->started = 0;
- scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
- outb(0,ioaddr+SIGNAL_CA);
- free_irq(irq,dev);
- outb(i586_RST,ioaddr+EEPROM_Ctrl);
- release_region(ioaddr, EEXP_IO_EXTENT);
- release_region(ioaddr+0x4000, 16);
- release_region(ioaddr+0x8000, 16);
- release_region(ioaddr+0xc000, 16);
-
- return 0;
-}
-
-/*
- * This gets called when a higher level thinks we are broken. Check that
- * nothing has become jammed in the CU.
- */
-
-static void unstick_cu(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short ioaddr = dev->base_addr;
-
- if (lp->started)
- {
- if (time_after(jiffies, dev_trans_start(dev) + HZ/2))
- {
- if (lp->tx_link==lp->last_tx_restart)
- {
- unsigned short boguscount=200,rsst;
- printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",
- dev->name, scb_status(dev));
- eexp_hw_txinit(dev);
- lp->last_tx_restart = 0;
- scb_wrcbl(dev, lp->tx_link);
- scb_command(dev, SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
- while (!SCB_complete(rsst=scb_status(dev)))
- {
- if (!--boguscount)
- {
- boguscount=200;
- printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",
- dev->name,rsst);
- scb_wrcbl(dev, lp->tx_link);
- scb_command(dev, SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
- }
- }
- netif_wake_queue(dev);
- }
- else
- {
- unsigned short status = scb_status(dev);
- if (SCB_CUdead(status))
- {
- unsigned short txstatus = eexp_hw_lasttxstat(dev);
- printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
- dev->name, status, txstatus);
- eexp_hw_txrestart(dev);
- }
- else
- {
- unsigned short txstatus = eexp_hw_lasttxstat(dev);
- if (netif_queue_stopped(dev) && !txstatus)
- {
- printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",
- dev->name,status,txstatus);
- eexp_hw_init586(dev);
- netif_wake_queue(dev);
- }
- else
- {
- printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
- }
- }
- }
- }
- }
- else
- {
- if (time_after(jiffies, lp->init_time + 10))
- {
- unsigned short status = scb_status(dev);
- printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
- dev->name, status);
- eexp_hw_init586(dev);
- netif_wake_queue(dev);
- }
- }
-}
-
-static void eexp_timeout(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-#ifdef CONFIG_SMP
- unsigned long flags;
-#endif
- int status;
-
- disable_irq(dev->irq);
-
- /*
- * Best would be to use synchronize_irq(); spin_lock() here
- * lets make it work first..
- */
-
-#ifdef CONFIG_SMP
- spin_lock_irqsave(&lp->lock, flags);
-#endif
-
- status = scb_status(dev);
- unstick_cu(dev);
- printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
- (SCB_complete(status)?"lost interrupt":
- "board on fire"));
- dev->stats.tx_errors++;
- lp->last_tx = jiffies;
- if (!SCB_complete(status)) {
- scb_command(dev, SCB_CUabort);
- outb(0,dev->base_addr+SIGNAL_CA);
- }
- netif_wake_queue(dev);
-#ifdef CONFIG_SMP
- spin_unlock_irqrestore(&lp->lock, flags);
-#endif
-}
-
-/*
- * Called to transmit a packet, or to allow us to right ourselves
- * if the kernel thinks we've died.
- */
-static netdev_tx_t eexp_xmit(struct sk_buff *buf, struct net_device *dev)
-{
- short length = buf->len;
-#ifdef CONFIG_SMP
- struct net_local *lp = netdev_priv(dev);
- unsigned long flags;
-#endif
-
-#if NET_DEBUG > 6
- printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
-#endif
-
- if (buf->len < ETH_ZLEN) {
- if (skb_padto(buf, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
-
- disable_irq(dev->irq);
-
- /*
- * Best would be to use synchronize_irq(); spin_lock() here
- * lets make it work first..
- */
-
-#ifdef CONFIG_SMP
- spin_lock_irqsave(&lp->lock, flags);
-#endif
-
- {
- unsigned short *data = (unsigned short *)buf->data;
-
- dev->stats.tx_bytes += length;
-
- eexp_hw_tx_pio(dev,data,length);
- }
- dev_kfree_skb(buf);
-#ifdef CONFIG_SMP
- spin_unlock_irqrestore(&lp->lock, flags);
-#endif
- enable_irq(dev->irq);
- return NETDEV_TX_OK;
-}
-
-/*
- * Handle an EtherExpress interrupt
- * If we've finished initializing, start the RU and CU up.
- * If we've already started, reap tx buffers, handle any received packets,
- * check to make sure we've not become wedged.
- */
-
-static unsigned short eexp_start_irq(struct net_device *dev,
- unsigned short status)
-{
- unsigned short ack_cmd = SCB_ack(status);
- struct net_local *lp = netdev_priv(dev);
- unsigned short ioaddr = dev->base_addr;
- if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) {
- short diag_status, tdr_status;
- while (SCB_CUstat(status)==2)
- status = scb_status(dev);
-#if NET_DEBUG > 4
- printk("%s: CU went non-active (status %04x)\n",
- dev->name, status);
-#endif
-
- outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR);
- diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT));
- if (diag_status & 1<<11) {
- printk(KERN_WARNING "%s: 82586 failed self-test\n",
- dev->name);
- } else if (!(diag_status & 1<<13)) {
- printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name);
- }
-
- outw(CONF_TDR_RESULT & ~31, ioaddr + SM_PTR);
- tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT));
- if (tdr_status & (TDR_SHORT|TDR_OPEN)) {
- printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
- }
- else if (tdr_status & TDR_XCVRPROBLEM) {
- printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);
- }
- else if (tdr_status & TDR_LINKOK) {
-#if NET_DEBUG > 4
- printk(KERN_DEBUG "%s: TDR reports link OK\n", dev->name);
-#endif
- } else {
- printk("%s: TDR is ga-ga (status %04x)\n", dev->name,
- tdr_status);
- }
-
- lp->started |= STARTED_CU;
- scb_wrcbl(dev, lp->tx_link);
- /* if the RU isn't running, start it now */
- if (!(lp->started & STARTED_RU)) {
- ack_cmd |= SCB_RUstart;
- scb_wrrfa(dev, lp->rx_buf_start);
- lp->rx_ptr = lp->rx_buf_start;
- lp->started |= STARTED_RU;
- }
- ack_cmd |= SCB_CUstart | 0x2000;
- }
-
- if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
- lp->started|=STARTED_RU;
-
- return ack_cmd;
-}
-
-static void eexp_cmd_clear(struct net_device *dev)
-{
- unsigned long int oldtime = jiffies;
- while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
- if (scb_rdcmd(dev)) {
- printk("%s: command didn't clear\n", dev->name);
- }
-}
-
-static irqreturn_t eexp_irq(int dummy, void *dev_info)
-{
- struct net_device *dev = dev_info;
- struct net_local *lp;
- unsigned short ioaddr,status,ack_cmd;
- unsigned short old_read_ptr, old_write_ptr;
-
- lp = netdev_priv(dev);
- ioaddr = dev->base_addr;
-
- spin_lock(&lp->lock);
-
- old_read_ptr = inw(ioaddr+READ_PTR);
- old_write_ptr = inw(ioaddr+WRITE_PTR);
-
- outb(SIRQ_dis|irqrmap[dev->irq], ioaddr+SET_IRQ);
-
- status = scb_status(dev);
-
-#if NET_DEBUG > 4
- printk(KERN_DEBUG "%s: interrupt (status %x)\n", dev->name, status);
-#endif
-
- if (lp->started == (STARTED_CU | STARTED_RU)) {
-
- do {
- eexp_cmd_clear(dev);
-
- ack_cmd = SCB_ack(status);
- scb_command(dev, ack_cmd);
- outb(0,ioaddr+SIGNAL_CA);
-
- eexp_cmd_clear(dev);
-
- if (SCB_complete(status)) {
- if (!eexp_hw_lasttxstat(dev)) {
- printk("%s: tx interrupt but no status\n", dev->name);
- }
- }
-
- if (SCB_rxdframe(status))
- eexp_hw_rx_pio(dev);
-
- status = scb_status(dev);
- } while (status & 0xc000);
-
- if (SCB_RUdead(status))
- {
- printk(KERN_WARNING "%s: RU stopped: status %04x\n",
- dev->name,status);
-#if 0
- printk(KERN_WARNING "%s: cur_rfd=%04x, cur_rbd=%04x\n", dev->name, lp->cur_rfd, lp->cur_rbd);
- outw(lp->cur_rfd, ioaddr+READ_PTR);
- printk(KERN_WARNING "%s: [%04x]\n", dev->name, inw(ioaddr+DATAPORT));
- outw(lp->cur_rfd+6, ioaddr+READ_PTR);
- printk(KERN_WARNING "%s: rbd is %04x\n", dev->name, rbd= inw(ioaddr+DATAPORT));
- outw(rbd, ioaddr+READ_PTR);
- printk(KERN_WARNING "%s: [%04x %04x] ", dev->name, inw(ioaddr+DATAPORT), inw(ioaddr+DATAPORT));
- outw(rbd+8, ioaddr+READ_PTR);
- printk("[%04x]\n", inw(ioaddr+DATAPORT));
-#endif
- dev->stats.rx_errors++;
-#if 1
- eexp_hw_rxinit(dev);
-#else
- lp->cur_rfd = lp->first_rfd;
-#endif
- scb_wrrfa(dev, lp->rx_buf_start);
- scb_command(dev, SCB_RUstart);
- outb(0,ioaddr+SIGNAL_CA);
- }
- } else {
- if (status & 0x8000)
- ack_cmd = eexp_start_irq(dev, status);
- else
- ack_cmd = SCB_ack(status);
- scb_command(dev, ack_cmd);
- outb(0,ioaddr+SIGNAL_CA);
- }
-
- eexp_cmd_clear(dev);
-
- outb(SIRQ_en|irqrmap[dev->irq], ioaddr+SET_IRQ);
-
-#if NET_DEBUG > 6
- printk("%s: leaving eexp_irq()\n", dev->name);
-#endif
- outw(old_read_ptr, ioaddr+READ_PTR);
- outw(old_write_ptr, ioaddr+WRITE_PTR);
-
- spin_unlock(&lp->lock);
- return IRQ_HANDLED;
-}
-
-/*
- * Hardware access functions
- */
-
-/*
- * Set the cable type to use.
- */
-
-static void eexp_hw_set_interface(struct net_device *dev)
-{
- unsigned char oldval = inb(dev->base_addr + 0x300e);
- oldval &= ~0x82;
- switch (dev->if_port) {
- case TPE:
- oldval |= 0x2;
- case BNC:
- oldval |= 0x80;
- break;
- }
- outb(oldval, dev->base_addr+0x300e);
- mdelay(20);
-}
-
-/*
- * Check all the receive buffers, and hand any received packets
- * to the upper levels. Basic sanity check on each frame
- * descriptor, though we don't bother trying to fix broken ones.
- */
-
-static void eexp_hw_rx_pio(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short rx_block = lp->rx_ptr;
- unsigned short boguscount = lp->num_rx_bufs;
- unsigned short ioaddr = dev->base_addr;
- unsigned short status;
-
-#if NET_DEBUG > 6
- printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);
-#endif
-
- do {
- unsigned short rfd_cmd, rx_next, pbuf, pkt_len;
-
- outw(rx_block, ioaddr + READ_PTR);
- status = inw(ioaddr + DATAPORT);
-
- if (FD_Done(status))
- {
- rfd_cmd = inw(ioaddr + DATAPORT);
- rx_next = inw(ioaddr + DATAPORT);
- pbuf = inw(ioaddr + DATAPORT);
-
- outw(pbuf, ioaddr + READ_PTR);
- pkt_len = inw(ioaddr + DATAPORT);
-
- if (rfd_cmd!=0x0000)
- {
- printk(KERN_WARNING "%s: rfd_cmd not zero:0x%04x\n",
- dev->name, rfd_cmd);
- continue;
- }
- else if (pbuf!=rx_block+0x16)
- {
- printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
- dev->name, rx_block+0x16, pbuf);
- continue;
- }
- else if ((pkt_len & 0xc000)!=0xc000)
- {
- printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n",
- dev->name, pkt_len & 0xc000);
- continue;
- }
- else if (!FD_OK(status))
- {
- dev->stats.rx_errors++;
- if (FD_CRC(status))
- dev->stats.rx_crc_errors++;
- if (FD_Align(status))
- dev->stats.rx_frame_errors++;
- if (FD_Resrc(status))
- dev->stats.rx_fifo_errors++;
- if (FD_DMA(status))
- dev->stats.rx_over_errors++;
- if (FD_Short(status))
- dev->stats.rx_length_errors++;
- }
- else
- {
- struct sk_buff *skb;
- pkt_len &= 0x3fff;
- skb = netdev_alloc_skb(dev, pkt_len + 16);
- if (skb == NULL)
- {
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
- dev->stats.rx_dropped++;
- break;
- }
- skb_reserve(skb, 2);
- outw(pbuf+10, ioaddr+READ_PTR);
- insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);
- skb->protocol = eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
- outw(rx_block, ioaddr+WRITE_PTR);
- outw(0, ioaddr+DATAPORT);
- outw(0, ioaddr+DATAPORT);
- rx_block = rx_next;
- }
- } while (FD_Done(status) && boguscount--);
- lp->rx_ptr = rx_block;
-}
-
-/*
- * Hand a packet to the card for transmission
- * If we get here, we MUST have already checked
- * to make sure there is room in the transmit
- * buffer region.
- */
-
-static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
- unsigned short len)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short ioaddr = dev->base_addr;
-
- if (LOCKUP16 || lp->width) {
- /* Stop the CU so that there is no chance that it
- jumps off to a bogus address while we are writing the
- pointer to the next transmit packet in 8-bit mode --
- this eliminates the "CU wedged" errors in 8-bit mode.
- (Zoltan Szilagyi 10-12-96) */
- scb_command(dev, SCB_CUsuspend);
- outw(0xFFFF, ioaddr+SIGNAL_CA);
- }
-
- outw(lp->tx_head, ioaddr + WRITE_PTR);
-
- outw(0x0000, ioaddr + DATAPORT);
- outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
- outw(lp->tx_head+0x08, ioaddr + DATAPORT);
- outw(lp->tx_head+0x0e, ioaddr + DATAPORT);
-
- outw(0x0000, ioaddr + DATAPORT);
- outw(0x0000, ioaddr + DATAPORT);
- outw(lp->tx_head+0x08, ioaddr + DATAPORT);
-
- outw(0x8000|len, ioaddr + DATAPORT);
- outw(-1, ioaddr + DATAPORT);
- outw(lp->tx_head+0x16, ioaddr + DATAPORT);
- outw(0, ioaddr + DATAPORT);
-
- outsw(ioaddr + DATAPORT, buf, (len+1)>>1);
-
- outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR);
- outw(lp->tx_head, ioaddr + DATAPORT);
-
- dev->trans_start = jiffies;
- lp->tx_tail = lp->tx_head;
- if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
- lp->tx_head = TX_BUF_START;
- else
- lp->tx_head += TX_BUF_SIZE;
- if (lp->tx_head != lp->tx_reap)
- netif_wake_queue(dev);
-
- if (LOCKUP16 || lp->width) {
- /* Restart the CU so that the packet can actually
- be transmitted. (Zoltan Szilagyi 10-12-96) */
- scb_command(dev, SCB_CUresume);
- outw(0xFFFF, ioaddr+SIGNAL_CA);
- }
-
- dev->stats.tx_packets++;
- lp->last_tx = jiffies;
-}
-
-static const struct net_device_ops eexp_netdev_ops = {
- .ndo_open = eexp_open,
- .ndo_stop = eexp_close,
- .ndo_start_xmit = eexp_xmit,
- .ndo_set_rx_mode = eexp_set_multicast,
- .ndo_tx_timeout = eexp_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/*
- * Sanity check the suspected EtherExpress card
- * Read hardware address, reset card, size memory and initialize buffer
- * memory pointers. These are held in netdev_priv(), in case someone has more
- * than one card in a machine.
- */
-
-static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
-{
- unsigned short hw_addr[3];
- unsigned char buswidth;
- unsigned int memory_size;
- int i;
- unsigned short xsum = 0;
- struct net_local *lp = netdev_priv(dev);
-
- printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr);
-
- outb(ASIC_RST, ioaddr+EEPROM_Ctrl);
- outb(0, ioaddr+EEPROM_Ctrl);
- udelay(500);
- outb(i586_RST, ioaddr+EEPROM_Ctrl);
-
- hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);
- hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
- hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);
-
- /* Standard Address or Compaq LTE Address */
- if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||
- (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
- {
- printk(" rejected: invalid address %04x%04x%04x\n",
- hw_addr[2],hw_addr[1],hw_addr[0]);
- return -ENODEV;
- }
-
- /* Calculate the EEPROM checksum. Carry on anyway if it's bad,
- * though.
- */
- for (i = 0; i < 64; i++)
- xsum += eexp_hw_readeeprom(ioaddr, i);
- if (xsum != 0xbaba)
- printk(" (bad EEPROM xsum 0x%02x)", xsum);
-
- dev->base_addr = ioaddr;
- for ( i=0 ; i<6 ; i++ )
- dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i];
-
- {
- static const char irqmap[] = { 0, 9, 3, 4, 5, 10, 11, 0 };
- unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
-
- /* Use the IRQ from EEPROM if none was given */
- if (!dev->irq)
- dev->irq = irqmap[setupval>>13];
-
- if (dev->if_port == 0xff) {
- dev->if_port = !(setupval & 0x1000) ? AUI :
- eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC;
- }
-
- buswidth = !((setupval & 0x400) >> 10);
- }
-
- memset(lp, 0, sizeof(struct net_local));
- spin_lock_init(&lp->lock);
-
- printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
- eexp_ifmap[dev->if_port], buswidth?8:16);
-
- if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress"))
- return -EBUSY;
-
- eexp_hw_set_interface(dev);
-
- release_region(dev->base_addr + 0x300e, 1);
-
- /* Find out how much RAM we have on the card */
- outw(0, dev->base_addr + WRITE_PTR);
- for (i = 0; i < 32768; i++)
- outw(0, dev->base_addr + DATAPORT);
-
- for (memory_size = 0; memory_size < 64; memory_size++)
- {
- outw(memory_size<<10, dev->base_addr + READ_PTR);
- if (inw(dev->base_addr+DATAPORT))
- break;
- outw(memory_size<<10, dev->base_addr + WRITE_PTR);
- outw(memory_size | 0x5000, dev->base_addr+DATAPORT);
- outw(memory_size<<10, dev->base_addr + READ_PTR);
- if (inw(dev->base_addr+DATAPORT) != (memory_size | 0x5000))
- break;
- }
-
- /* Sort out the number of buffers. We may have 16, 32, 48 or 64k
- * of RAM to play with.
- */
- lp->num_tx_bufs = 4;
- lp->rx_buf_end = 0x3ff6;
- switch (memory_size)
- {
- case 64:
- lp->rx_buf_end += 0x4000;
- case 48:
- lp->num_tx_bufs += 4;
- lp->rx_buf_end += 0x4000;
- case 32:
- lp->rx_buf_end += 0x4000;
- case 16:
- printk(", %dk RAM)\n", memory_size);
- break;
- default:
- printk(") bad memory size (%dk).\n", memory_size);
- return -ENODEV;
- break;
- }
-
- lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE);
- lp->width = buswidth;
-
- dev->netdev_ops = &eexp_netdev_ops;
- dev->watchdog_timeo = 2*HZ;
-
- return register_netdev(dev);
-}
-
-/*
- * Read a word from the EtherExpress on-board serial EEPROM.
- * The EEPROM contains 64 words of 16 bits.
- */
-static unsigned short __init eexp_hw_readeeprom(unsigned short ioaddr,
- unsigned char location)
-{
- unsigned short cmd = 0x180|(location&0x7f);
- unsigned short rval = 0,wval = EC_CS|i586_RST;
- int i;
-
- outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);
- for (i=0x100 ; i ; i>>=1 )
- {
- if (cmd&i)
- wval |= EC_Wr;
- else
- wval &= ~EC_Wr;
-
- outb(wval,ioaddr+EEPROM_Ctrl);
- outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- outb(wval,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- }
- wval &= ~EC_Wr;
- outb(wval,ioaddr+EEPROM_Ctrl);
- for (i=0x8000 ; i ; i>>=1 )
- {
- outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd)
- rval |= i;
- outb(wval,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- }
- wval &= ~EC_CS;
- outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- outb(wval,ioaddr+EEPROM_Ctrl);
- eeprom_delay();
- return rval;
-}
-
-/*
- * Reap tx buffers and return last transmit status.
- * if ==0 then either:
- * a) we're not transmitting anything, so why are we here?
- * b) we've died.
- * otherwise, Stat_Busy(return) means we've still got some packets
- * to transmit, Stat_Done(return) means our buffers should be empty
- * again
- */
-
-static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short tx_block = lp->tx_reap;
- unsigned short status;
-
- if (!netif_queue_stopped(dev) && lp->tx_head==lp->tx_reap)
- return 0x0000;
-
- do
- {
- outw(tx_block & ~31, dev->base_addr + SM_PTR);
- status = inw(dev->base_addr + SHADOW(tx_block));
- if (!Stat_Done(status))
- {
- lp->tx_link = tx_block;
- return status;
- }
- else
- {
- lp->last_tx_restart = 0;
- dev->stats.collisions += Stat_NoColl(status);
- if (!Stat_OK(status))
- {
- char *whatsup = NULL;
- dev->stats.tx_errors++;
- if (Stat_Abort(status))
- dev->stats.tx_aborted_errors++;
- if (Stat_TNoCar(status)) {
- whatsup = "aborted, no carrier";
- dev->stats.tx_carrier_errors++;
- }
- if (Stat_TNoCTS(status)) {
- whatsup = "aborted, lost CTS";
- dev->stats.tx_carrier_errors++;
- }
- if (Stat_TNoDMA(status)) {
- whatsup = "FIFO underran";
- dev->stats.tx_fifo_errors++;
- }
- if (Stat_TXColl(status)) {
- whatsup = "aborted, too many collisions";
- dev->stats.tx_aborted_errors++;
- }
- if (whatsup)
- printk(KERN_INFO "%s: transmit %s\n",
- dev->name, whatsup);
- }
- else
- dev->stats.tx_packets++;
- }
- if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
- lp->tx_reap = tx_block = TX_BUF_START;
- else
- lp->tx_reap = tx_block += TX_BUF_SIZE;
- netif_wake_queue(dev);
- }
- while (lp->tx_reap != lp->tx_head);
-
- lp->tx_link = lp->tx_tail + 0x08;
-
- return status;
-}
-
-/*
- * This should never happen. It is called when some higher routine detects
- * that the CU has stopped, to try to restart it from the last packet we knew
- * we were working on, or the idle loop if we had finished for the time.
- */
-
-static void eexp_hw_txrestart(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short ioaddr = dev->base_addr;
-
- lp->last_tx_restart = lp->tx_link;
- scb_wrcbl(dev, lp->tx_link);
- scb_command(dev, SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
-
- {
- unsigned short boguscount=50,failcount=5;
- while (!scb_status(dev))
- {
- if (!--boguscount)
- {
- if (--failcount)
- {
- printk(KERN_WARNING "%s: CU start timed out, status %04x, cmd %04x\n", dev->name, scb_status(dev), scb_rdcmd(dev));
- scb_wrcbl(dev, lp->tx_link);
- scb_command(dev, SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
- boguscount = 100;
- }
- else
- {
- printk(KERN_WARNING "%s: Failed to restart CU, resetting board...\n",dev->name);
- eexp_hw_init586(dev);
- netif_wake_queue(dev);
- return;
- }
- }
- }
- }
-}
-
-/*
- * Writes down the list of transmit buffers into card memory. Each
- * entry consists of an 82586 transmit command, followed by a jump
- * pointing to itself. When we want to transmit a packet, we write
- * the data into the appropriate transmit buffer and then modify the
- * preceding jump to point at the new transmit command. This means that
- * the 586 command unit is continuously active.
- */
-
-static void eexp_hw_txinit(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short tx_block = TX_BUF_START;
- unsigned short curtbuf;
- unsigned short ioaddr = dev->base_addr;
-
- for ( curtbuf=0 ; curtbuf<lp->num_tx_bufs ; curtbuf++ )
- {
- outw(tx_block, ioaddr + WRITE_PTR);
-
- outw(0x0000, ioaddr + DATAPORT);
- outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);
- outw(tx_block+0x08, ioaddr + DATAPORT);
- outw(tx_block+0x0e, ioaddr + DATAPORT);
-
- outw(0x0000, ioaddr + DATAPORT);
- outw(0x0000, ioaddr + DATAPORT);
- outw(tx_block+0x08, ioaddr + DATAPORT);
-
- outw(0x8000, ioaddr + DATAPORT);
- outw(-1, ioaddr + DATAPORT);
- outw(tx_block+0x16, ioaddr + DATAPORT);
- outw(0x0000, ioaddr + DATAPORT);
-
- tx_block += TX_BUF_SIZE;
- }
- lp->tx_head = TX_BUF_START;
- lp->tx_reap = TX_BUF_START;
- lp->tx_tail = tx_block - TX_BUF_SIZE;
- lp->tx_link = lp->tx_tail + 0x08;
- lp->rx_buf_start = tx_block;
-
-}
-
-/*
- * Write the circular list of receive buffer descriptors to card memory.
- * The end of the list isn't marked, which means that the 82586 receive
- * unit will loop until buffers become available (this avoids it giving us
- * "out of resources" messages).
- */
-
-static void eexp_hw_rxinit(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short rx_block = lp->rx_buf_start;
- unsigned short ioaddr = dev->base_addr;
-
- lp->num_rx_bufs = 0;
- lp->rx_first = lp->rx_ptr = rx_block;
- do
- {
- lp->num_rx_bufs++;
-
- outw(rx_block, ioaddr + WRITE_PTR);
-
- outw(0, ioaddr + DATAPORT); outw(0, ioaddr+DATAPORT);
- outw(rx_block + RX_BUF_SIZE, ioaddr+DATAPORT);
- outw(0xffff, ioaddr+DATAPORT);
-
- outw(0x0000, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
- outw(0xdead, ioaddr+DATAPORT);
-
- outw(0x0000, ioaddr+DATAPORT);
- outw(rx_block + RX_BUF_SIZE + 0x16, ioaddr+DATAPORT);
- outw(rx_block + 0x20, ioaddr+DATAPORT);
- outw(0, ioaddr+DATAPORT);
- outw(RX_BUF_SIZE-0x20, ioaddr+DATAPORT);
-
- lp->rx_last = rx_block;
- rx_block += RX_BUF_SIZE;
- } while (rx_block <= lp->rx_buf_end-RX_BUF_SIZE);
-
-
- /* Make first Rx frame descriptor point to first Rx buffer
- descriptor */
- outw(lp->rx_first + 6, ioaddr+WRITE_PTR);
- outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
- /* Close Rx frame descriptor ring */
- outw(lp->rx_last + 4, ioaddr+WRITE_PTR);
- outw(lp->rx_first, ioaddr+DATAPORT);
-
- /* Close Rx buffer descriptor ring */
- outw(lp->rx_last + 0x16 + 2, ioaddr+WRITE_PTR);
- outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
-}
-
-/*
- * Un-reset the 586, and start the configuration sequence. We don't wait for
- * this to finish, but allow the interrupt handler to start the CU and RU for
- * us. We can't start the receive/transmission system up before we know that
- * the hardware is configured correctly.
- */
-
-static void eexp_hw_init586(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned short ioaddr = dev->base_addr;
- int i;
-
-#if NET_DEBUG > 6
- printk("%s: eexp_hw_init586()\n", dev->name);
-#endif
-
- lp->started = 0;
-
- set_loopback(dev);
-
- outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
- /* Download the startup code */
- outw(lp->rx_buf_end & ~31, ioaddr + SM_PTR);
- outw(lp->width?0x0001:0x0000, ioaddr + 0x8006);
- outw(0x0000, ioaddr + 0x8008);
- outw(0x0000, ioaddr + 0x800a);
- outw(0x0000, ioaddr + 0x800c);
- outw(0x0000, ioaddr + 0x800e);
-
- for (i = 0; i < ARRAY_SIZE(start_code) * 2; i+=32) {
- int j;
- outw(i, ioaddr + SM_PTR);
- for (j = 0; j < 16 && (i+j)/2 < ARRAY_SIZE(start_code); j+=2)
- outw(start_code[(i+j)/2],
- ioaddr+0x4000+j);
- for (j = 0; j < 16 && (i+j+16)/2 < ARRAY_SIZE(start_code); j+=2)
- outw(start_code[(i+j+16)/2],
- ioaddr+0x8000+j);
- }
-
- /* Do we want promiscuous mode or multicast? */
- outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
- i = inw(ioaddr+SHADOW(CONF_PROMISC));
- outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
- ioaddr+SHADOW(CONF_PROMISC));
- lp->was_promisc = dev->flags & IFF_PROMISC;
-#if 0
- eexp_setup_filter(dev);
-#endif
-
- /* Write our hardware address */
- outw(CONF_HWADDR & ~31, ioaddr+SM_PTR);
- outw(((unsigned short *)dev->dev_addr)[0], ioaddr+SHADOW(CONF_HWADDR));
- outw(((unsigned short *)dev->dev_addr)[1],
- ioaddr+SHADOW(CONF_HWADDR+2));
- outw(((unsigned short *)dev->dev_addr)[2],
- ioaddr+SHADOW(CONF_HWADDR+4));
-
- eexp_hw_txinit(dev);
- eexp_hw_rxinit(dev);
-
- outb(0,ioaddr+EEPROM_Ctrl);
- mdelay(5);
-
- scb_command(dev, 0xf000);
- outb(0,ioaddr+SIGNAL_CA);
-
- outw(0, ioaddr+SM_PTR);
-
- {
- unsigned short rboguscount=50,rfailcount=5;
- while (inw(ioaddr+0x4000))
- {
- if (!--rboguscount)
- {
- printk(KERN_WARNING "%s: i82586 reset timed out, kicking...\n",
- dev->name);
- scb_command(dev, 0);
- outb(0,ioaddr+SIGNAL_CA);
- rboguscount = 100;
- if (!--rfailcount)
- {
- printk(KERN_WARNING "%s: i82586 not responding, giving up.\n",
- dev->name);
- return;
- }
- }
- }
- }
-
- scb_wrcbl(dev, CONF_LINK);
- scb_command(dev, 0xf000|SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
-
- {
- unsigned short iboguscount=50,ifailcount=5;
- while (!scb_status(dev))
- {
- if (!--iboguscount)
- {
- if (--ifailcount)
- {
- printk(KERN_WARNING "%s: i82586 initialization timed out, status %04x, cmd %04x\n",
- dev->name, scb_status(dev), scb_rdcmd(dev));
- scb_wrcbl(dev, CONF_LINK);
- scb_command(dev, 0xf000|SCB_CUstart);
- outb(0,ioaddr+SIGNAL_CA);
- iboguscount = 100;
- }
- else
- {
- printk(KERN_WARNING "%s: Failed to initialize i82586, giving up.\n",dev->name);
- return;
- }
- }
- }
- }
-
- clear_loopback(dev);
- outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
-
- lp->init_time = jiffies;
-#if NET_DEBUG > 6
- printk("%s: leaving eexp_hw_init586()\n", dev->name);
-#endif
-}
-
-static void eexp_setup_filter(struct net_device *dev)
-{
- struct netdev_hw_addr *ha;
- unsigned short ioaddr = dev->base_addr;
- int count = netdev_mc_count(dev);
- int i;
- if (count > 8) {
- printk(KERN_INFO "%s: too many multicast addresses (%d)\n",
- dev->name, count);
- count = 8;
- }
-
- outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
- outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST));
- i = 0;
- netdev_for_each_mc_addr(ha, dev) {
- unsigned short *data = (unsigned short *) ha->addr;
-
- if (i == count)
- break;
- outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR);
- outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i)));
- outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);
- outw(data[1], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+2));
- outw((CONF_MULTICAST+(6*i)+4) & ~31, ioaddr+SM_PTR);
- outw(data[2], ioaddr+SHADOW(CONF_MULTICAST+(6*i)+4));
- i++;
- }
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-static void
-eexp_set_multicast(struct net_device *dev)
-{
- unsigned short ioaddr = dev->base_addr;
- struct net_local *lp = netdev_priv(dev);
- int kick = 0, i;
- if ((dev->flags & IFF_PROMISC) != lp->was_promisc) {
- outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
- i = inw(ioaddr+SHADOW(CONF_PROMISC));
- outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
- ioaddr+SHADOW(CONF_PROMISC));
- lp->was_promisc = dev->flags & IFF_PROMISC;
- kick = 1;
- }
- if (!(dev->flags & IFF_PROMISC)) {
- eexp_setup_filter(dev);
- if (lp->old_mc_count != netdev_mc_count(dev)) {
- kick = 1;
- lp->old_mc_count = netdev_mc_count(dev);
- }
- }
- if (kick) {
- unsigned long oj;
- scb_command(dev, SCB_CUsuspend);
- outb(0, ioaddr+SIGNAL_CA);
- outb(0, ioaddr+SIGNAL_CA);
-#if 0
- printk("%s: waiting for CU to go suspended\n", dev->name);
-#endif
- oj = jiffies;
- while ((SCB_CUstat(scb_status(dev)) == 2) &&
- (time_before(jiffies, oj + 2000)));
- if (SCB_CUstat(scb_status(dev)) == 2)
- printk("%s: warning, CU didn't stop\n", dev->name);
- lp->started &= ~(STARTED_CU);
- scb_wrcbl(dev, CONF_LINK);
- scb_command(dev, SCB_CUstart);
- outb(0, ioaddr+SIGNAL_CA);
- }
-}
-
-
-/*
- * MODULE stuff
- */
-
-#ifdef MODULE
-
-#define EEXP_MAX_CARDS 4 /* max number of cards to support */
-
-static struct net_device *dev_eexp[EEXP_MAX_CARDS];
-static int irq[EEXP_MAX_CARDS];
-static int io[EEXP_MAX_CARDS];
-
-module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(io, "EtherExpress 16 I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherExpress 16 IRQ number(s)");
-MODULE_LICENSE("GPL");
-
-
-/* Ideally the user would give us io=, irq= for every card. If any parameters
- * are specified, we verify and then use them. If no parameters are given, we
- * autoprobe for one card only.
- */
-int __init init_module(void)
-{
- struct net_device *dev;
- int this_dev, found = 0;
-
- for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
- dev = alloc_etherdev(sizeof(struct net_local));
- dev->irq = irq[this_dev];
- dev->base_addr = io[this_dev];
- if (io[this_dev] == 0) {
- if (this_dev)
- break;
- printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
- }
- if (do_express_probe(dev) == 0) {
- dev_eexp[this_dev] = dev;
- found++;
- continue;
- }
- printk(KERN_WARNING "eexpress.c: Failed to register card at 0x%x.\n", io[this_dev]);
- free_netdev(dev);
- break;
- }
- if (found)
- return 0;
- return -ENXIO;
-}
-
-void __exit cleanup_module(void)
-{
- int this_dev;
-
- for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
- struct net_device *dev = dev_eexp[this_dev];
- if (dev) {
- unregister_netdev(dev);
- free_netdev(dev);
- }
- }
-}
-#endif
-
-/*
- * Local Variables:
- * c-file-style: "linux"
- * tab-width: 8
- * End:
- */
diff --git a/drivers/net/ethernet/i825xx/eexpress.h b/drivers/net/ethernet/i825xx/eexpress.h
deleted file mode 100644
index dc9c6ea289e9..000000000000
--- a/drivers/net/ethernet/i825xx/eexpress.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * eexpress.h: Intel EtherExpress16 defines
- */
-
-/*
- * EtherExpress card register addresses
- * as offsets from the base IO region (dev->base_addr)
- */
-
-#define DATAPORT 0x0000
-#define WRITE_PTR 0x0002
-#define READ_PTR 0x0004
-#define SIGNAL_CA 0x0006
-#define SET_IRQ 0x0007
-#define SM_PTR 0x0008
-#define MEM_Dec 0x000a
-#define MEM_Ctrl 0x000b
-#define MEM_Page_Ctrl 0x000c
-#define Config 0x000d
-#define EEPROM_Ctrl 0x000e
-#define ID_PORT 0x000f
-#define MEM_ECtrl 0x000f
-
-/*
- * card register defines
- */
-
-/* SET_IRQ */
-#define SIRQ_en 0x08
-#define SIRQ_dis 0x00
-
-/* EEPROM_Ctrl */
-#define EC_Clk 0x01
-#define EC_CS 0x02
-#define EC_Wr 0x04
-#define EC_Rd 0x08
-#define ASIC_RST 0x40
-#define i586_RST 0x80
-
-#define eeprom_delay() { udelay(40); }
-
-/*
- * i82586 Memory Configuration
- */
-
-/* (System Configuration Pointer) System start up block, read after 586_RST */
-#define SCP_START 0xfff6
-
-/* Intermediate System Configuration Pointer */
-#define ISCP_START 0x0000
-
-/* System Command Block */
-#define SCB_START 0x0008
-
-/* Start of buffer region. Everything before this is used for control
- * structures and the CU configuration program. The memory layout is
- * determined in eexp_hw_probe(), once we know how much memory is
- * available on the card.
- */
-
-#define TX_BUF_START 0x0100
-
-#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
-#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
-
-/*
- * SCB defines
- */
-
-/* these functions take the SCB status word and test the relevant status bit */
-#define SCB_complete(s) (((s) & 0x8000) != 0)
-#define SCB_rxdframe(s) (((s) & 0x4000) != 0)
-#define SCB_CUdead(s) (((s) & 0x2000) != 0)
-#define SCB_RUdead(s) (((s) & 0x1000) != 0)
-#define SCB_ack(s) ((s) & 0xf000)
-
-/* Command unit status: 0=idle, 1=suspended, 2=active */
-#define SCB_CUstat(s) (((s)&0x0300)>>8)
-
-/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
-#define SCB_RUstat(s) (((s)&0x0070)>>4)
-
-/* SCB commands */
-#define SCB_CUnop 0x0000
-#define SCB_CUstart 0x0100
-#define SCB_CUresume 0x0200
-#define SCB_CUsuspend 0x0300
-#define SCB_CUabort 0x0400
-#define SCB_resetchip 0x0080
-
-#define SCB_RUnop 0x0000
-#define SCB_RUstart 0x0010
-#define SCB_RUresume 0x0020
-#define SCB_RUsuspend 0x0030
-#define SCB_RUabort 0x0040
-
-/*
- * Command block defines
- */
-
-#define Stat_Done(s) (((s) & 0x8000) != 0)
-#define Stat_Busy(s) (((s) & 0x4000) != 0)
-#define Stat_OK(s) (((s) & 0x2000) != 0)
-#define Stat_Abort(s) (((s) & 0x1000) != 0)
-#define Stat_STFail (((s) & 0x0800) != 0)
-#define Stat_TNoCar(s) (((s) & 0x0400) != 0)
-#define Stat_TNoCTS(s) (((s) & 0x0200) != 0)
-#define Stat_TNoDMA(s) (((s) & 0x0100) != 0)
-#define Stat_TDefer(s) (((s) & 0x0080) != 0)
-#define Stat_TColl(s) (((s) & 0x0040) != 0)
-#define Stat_TXColl(s) (((s) & 0x0020) != 0)
-#define Stat_NoColl(s) ((s) & 0x000f)
-
-/* Cmd_END will end AFTER the command if this is the first
- * command block after an SCB_CUstart, but BEFORE the command
- * for all subsequent commands. Best strategy is to place
- * Cmd_INT on the last command in the sequence, followed by a
- * dummy Cmd_Nop with Cmd_END after this.
- */
-
-#define Cmd_END 0x8000
-#define Cmd_SUS 0x4000
-#define Cmd_INT 0x2000
-
-#define Cmd_Nop 0x0000
-#define Cmd_SetAddr 0x0001
-#define Cmd_Config 0x0002
-#define Cmd_MCast 0x0003
-#define Cmd_Xmit 0x0004
-#define Cmd_TDR 0x0005
-#define Cmd_Dump 0x0006
-#define Cmd_Diag 0x0007
-
-
-/*
- * Frame Descriptor (Receive block) defines
- */
-
-#define FD_Done(s) (((s) & 0x8000) != 0)
-#define FD_Busy(s) (((s) & 0x4000) != 0)
-#define FD_OK(s) (((s) & 0x2000) != 0)
-
-#define FD_CRC(s) (((s) & 0x0800) != 0)
-#define FD_Align(s) (((s) & 0x0400) != 0)
-#define FD_Resrc(s) (((s) & 0x0200) != 0)
-#define FD_DMA(s) (((s) & 0x0100) != 0)
-#define FD_Short(s) (((s) & 0x0080) != 0)
-#define FD_NoEOF(s) (((s) & 0x0040) != 0)
-
-struct rfd_header {
- volatile unsigned long flags;
- volatile unsigned short link;
- volatile unsigned short rbd_offset;
- volatile unsigned short dstaddr1;
- volatile unsigned short dstaddr2;
- volatile unsigned short dstaddr3;
- volatile unsigned short srcaddr1;
- volatile unsigned short srcaddr2;
- volatile unsigned short srcaddr3;
- volatile unsigned short length;
-
- /* This is actually a Receive Buffer Descriptor. The way we
- * arrange memory means that an RBD always follows the RFD that
- * points to it, so they might as well be in the same structure.
- */
- volatile unsigned short actual_count;
- volatile unsigned short next_rbd;
- volatile unsigned short buf_addr1;
- volatile unsigned short buf_addr2;
- volatile unsigned short size;
-};
-
-/* Returned data from the Time Domain Reflectometer */
-
-#define TDR_LINKOK (1<<15)
-#define TDR_XCVRPROBLEM (1<<14)
-#define TDR_OPEN (1<<13)
-#define TDR_SHORT (1<<12)
-#define TDR_TIME 0x7ff
diff --git a/drivers/net/ethernet/i825xx/lp486e.c b/drivers/net/ethernet/i825xx/lp486e.c
deleted file mode 100644
index 3735bfa53600..000000000000
--- a/drivers/net/ethernet/i825xx/lp486e.c
+++ /dev/null
@@ -1,1337 +0,0 @@
-/* Intel Professional Workstation/panther ethernet driver */
-/* lp486e.c: A panther 82596 ethernet driver for linux. */
-/*
- History and copyrights:
-
- Driver skeleton
- Written 1993 by Donald Becker.
- Copyright 1993 United States Government as represented by the Director,
- National Security Agency. This software may only be used and
- distributed according to the terms of the GNU General Public License
- as modified by SRC, incorporated herein by reference.
-
- The author may be reached as becker@scyld.com, or C/O
- Scyld Computing Corporation
- 410 Severn Ave., Suite 210
- Annapolis MD 21403
-
- Apricot
- Written 1994 by Mark Evans.
- This driver is for the Apricot 82596 bus-master interface
-
- Modularised 12/94 Mark Evans
-
- Professional Workstation
- Derived from apricot.c by Ard van Breemen
- <ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>
-
- Credits:
- Thanks to Murphy Software BV for letting me write this in their time.
- Well, actually, I get paid doing this...
- (Also: see http://www.murphy.nl for murphy, and my homepage ~ard for
- more information on the Professional Workstation)
-
- Present version
- aeb@cwi.nl
-*/
-/*
- There are currently two motherboards that I know of in the
- professional workstation. The only one that I know is the
- intel panther motherboard. -- ard
-*/
-/*
-The pws is equipped with an intel 82596. This is a very intelligent controller
-which runs its own micro-code. Communication with the hostprocessor is done
-through linked lists of commands and buffers in the hostprocessors memory.
-A complete description of the 82596 is available from intel. Search for
-a file called "29021806.pdf". It is a complete description of the chip itself.
-To use it for the pws some additions are needed regarding generation of
-the PORT and CA signal, and the interrupt glue needed for a pc.
-I/O map:
-PORT SIZE ACTION MEANING
-0xCB0 2 WRITE Lower 16 bits for PORT command
-0xCB2 2 WRITE Upper 16 bits for PORT command, and issue of PORT command
-0xCB4 1 WRITE Generation of CA signal
-0xCB8 1 WRITE Clear interrupt glue
-All other communication is through memory!
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define DRV_NAME "lp486e"
-
-/* debug print flags */
-#define LOG_SRCDST 0x80000000
-#define LOG_STATINT 0x40000000
-#define LOG_STARTINT 0x20000000
-
-#define i596_debug debug
-
-static int i596_debug = 0;
-
-static const char * const medianame[] = {
- "10baseT", "AUI",
- "10baseT-FD", "AUI-FD",
-};
-
-#define LP486E_TOTAL_SIZE 16
-
-#define I596_NULL (0xffffffff)
-
-#define CMD_EOL 0x8000 /* The last command of the list, stop. */
-#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
-#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
-
-#define CMD_FLEX 0x0008 /* Enable flexible memory model */
-
-enum commands {
- CmdNOP = 0,
- CmdIASetup = 1,
- CmdConfigure = 2,
- CmdMulticastList = 3,
- CmdTx = 4,
- CmdTDR = 5,
- CmdDump = 6,
- CmdDiagnose = 7
-};
-
-#if 0
-static const char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
- "Tx", "TDR", "Dump", "Diagnose" };
-#endif
-
-/* Status word bits */
-#define STAT_CX 0x8000 /* The CU finished executing a command
- with the Interrupt bit set */
-#define STAT_FR 0x4000 /* The RU finished receiving a frame */
-#define STAT_CNA 0x2000 /* The CU left the active state */
-#define STAT_RNR 0x1000 /* The RU left the active state */
-#define STAT_ACK (STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)
-#define STAT_CUS 0x0700 /* Status of CU: 0: idle, 1: suspended,
- 2: active, 3-7: unused */
-#define STAT_RUS 0x00f0 /* Status of RU: 0: idle, 1: suspended,
- 2: no resources, 4: ready,
- 10: no resources due to no more RBDs,
- 12: no more RBDs, other: unused */
-#define STAT_T 0x0008 /* Bus throttle timers loaded */
-#define STAT_ZERO 0x0807 /* Always zero */
-
-#if 0
-static char *CUstates[8] = {
- "idle", "suspended", "active", 0, 0, 0, 0, 0
-};
-static char *RUstates[16] = {
- "idle", "suspended", "no resources", 0, "ready", 0, 0, 0,
- 0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0
-};
-
-static void
-i596_out_status(int status) {
- int bad = 0;
- char *s;
-
- printk("status %4.4x:", status);
- if (status == 0xffff)
- printk(" strange..\n");
- else {
- if (status & STAT_CX)
- printk(" CU done");
- if (status & STAT_CNA)
- printk(" CU stopped");
- if (status & STAT_FR)
- printk(" got a frame");
- if (status & STAT_RNR)
- printk(" RU stopped");
- if (status & STAT_T)
- printk(" throttled");
- if (status & STAT_ZERO)
- bad = 1;
- s = CUstates[(status & STAT_CUS) >> 8];
- if (!s)
- bad = 1;
- else
- printk(" CU(%s)", s);
- s = RUstates[(status & STAT_RUS) >> 4];
- if (!s)
- bad = 1;
- else
- printk(" RU(%s)", s);
- if (bad)
- printk(" bad status");
- printk("\n");
- }
-}
-#endif
-
-/* Command word bits */
-#define ACK_CX 0x8000
-#define ACK_FR 0x4000
-#define ACK_CNA 0x2000
-#define ACK_RNR 0x1000
-
-#define CUC_START 0x0100
-#define CUC_RESUME 0x0200
-#define CUC_SUSPEND 0x0300
-#define CUC_ABORT 0x0400
-
-#define RX_START 0x0010
-#define RX_RESUME 0x0020
-#define RX_SUSPEND 0x0030
-#define RX_ABORT 0x0040
-
-typedef u32 phys_addr;
-
-static inline phys_addr
-va_to_pa(void *x) {
- return x ? virt_to_bus(x) : I596_NULL;
-}
-
-static inline void *
-pa_to_va(phys_addr x) {
- return (x == I596_NULL) ? NULL : bus_to_virt(x);
-}
-
-/* status bits for cmd */
-#define CMD_STAT_C 0x8000 /* CU command complete */
-#define CMD_STAT_B 0x4000 /* CU command in progress */
-#define CMD_STAT_OK 0x2000 /* CU command completed without errors */
-#define CMD_STAT_A 0x1000 /* CU command abnormally terminated */
-
-struct i596_cmd { /* 8 bytes */
- unsigned short status;
- unsigned short command;
- phys_addr pa_next; /* va_to_pa(struct i596_cmd *next) */
-};
-
-#define EOF 0x8000
-#define SIZE_MASK 0x3fff
-
-struct i596_tbd {
- unsigned short size;
- unsigned short pad;
- phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */
- phys_addr pa_data; /* va_to_pa(char *data) */
- struct sk_buff *skb;
-};
-
-struct tx_cmd {
- struct i596_cmd cmd;
- phys_addr pa_tbd; /* va_to_pa(struct i596_tbd *tbd) */
- unsigned short size;
- unsigned short pad;
-};
-
-/* status bits for rfd */
-#define RFD_STAT_C 0x8000 /* Frame reception complete */
-#define RFD_STAT_B 0x4000 /* Frame reception in progress */
-#define RFD_STAT_OK 0x2000 /* Frame received without errors */
-#define RFD_STATUS 0x1fff
-#define RFD_LENGTH_ERR 0x1000
-#define RFD_CRC_ERR 0x0800
-#define RFD_ALIGN_ERR 0x0400
-#define RFD_NOBUFS_ERR 0x0200
-#define RFD_DMA_ERR 0x0100 /* DMA overrun failure to acquire system bus */
-#define RFD_SHORT_FRAME_ERR 0x0080
-#define RFD_NOEOP_ERR 0x0040
-#define RFD_TRUNC_ERR 0x0020
-#define RFD_MULTICAST 0x0002 /* 0: destination had our address
- 1: destination was broadcast/multicast */
-#define RFD_COLLISION 0x0001
-
-/* receive frame descriptor */
-struct i596_rfd {
- unsigned short stat;
- unsigned short cmd;
- phys_addr pa_next; /* va_to_pa(struct i596_rfd *next) */
- phys_addr pa_rbd; /* va_to_pa(struct i596_rbd *rbd) */
- unsigned short count;
- unsigned short size;
- char data[1532];
-};
-
-#define RBD_EL 0x8000
-#define RBD_P 0x4000
-#define RBD_SIZEMASK 0x3fff
-#define RBD_EOF 0x8000
-#define RBD_F 0x4000
-
-/* receive buffer descriptor */
-struct i596_rbd {
- unsigned short size;
- unsigned short pad;
- phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */
- phys_addr pa_data; /* va_to_pa(char *data) */
- phys_addr pa_prev; /* va_to_pa(struct i596_tbd *prev) */
-
- /* Driver private part */
- struct sk_buff *skb;
-};
-
-#define RX_RING_SIZE 64
-#define RX_SKBSIZE (ETH_FRAME_LEN+10)
-#define RX_RBD_SIZE 32
-
-/* System Control Block - 40 bytes */
-struct i596_scb {
- u16 status; /* 0 */
- u16 command; /* 2 */
- phys_addr pa_cmd; /* 4 - va_to_pa(struct i596_cmd *cmd) */
- phys_addr pa_rfd; /* 8 - va_to_pa(struct i596_rfd *rfd) */
- u32 crc_err; /* 12 */
- u32 align_err; /* 16 */
- u32 resource_err; /* 20 */
- u32 over_err; /* 24 */
- u32 rcvdt_err; /* 28 */
- u32 short_err; /* 32 */
- u16 t_on; /* 36 */
- u16 t_off; /* 38 */
-};
-
-/* Intermediate System Configuration Pointer - 8 bytes */
-struct i596_iscp {
- u32 busy; /* 0 */
- phys_addr pa_scb; /* 4 - va_to_pa(struct i596_scb *scb) */
-};
-
-/* System Configuration Pointer - 12 bytes */
-struct i596_scp {
- u32 sysbus; /* 0 */
- u32 pad; /* 4 */
- phys_addr pa_iscp; /* 8 - va_to_pa(struct i596_iscp *iscp) */
-};
-
-/* Selftest and dump results - needs 16-byte alignment */
-/*
- * The size of the dump area is 304 bytes. When the dump is executed
- * by the Port command an extra word will be appended to the dump area.
- * The extra word is a copy of the Dump status word (containing the
- * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump]
- */
-struct i596_dump {
- u16 dump[153]; /* (304 = 130h) + 2 bytes */
-};
-
-struct i596_private { /* aligned to a 16-byte boundary */
- struct i596_scp scp; /* 0 - needs 16-byte alignment */
- struct i596_iscp iscp; /* 12 */
- struct i596_scb scb; /* 20 */
- u32 dummy; /* 60 */
- struct i596_dump dump; /* 64 - needs 16-byte alignment */
-
- struct i596_cmd set_add;
- char eth_addr[8]; /* directly follows set_add */
-
- struct i596_cmd set_conf;
- char i596_config[16]; /* directly follows set_conf */
-
- struct i596_cmd tdr;
- unsigned long tdr_stat; /* directly follows tdr */
-
- int last_restart;
- struct i596_rbd *rbd_list;
- struct i596_rbd *rbd_tail;
- struct i596_rfd *rx_tail;
- struct i596_cmd *cmd_tail;
- struct i596_cmd *cmd_head;
- int cmd_backlog;
- unsigned long last_cmd;
- spinlock_t cmd_lock;
-};
-
-static char init_setup[14] = {
- 0x8E, /* length 14 bytes, prefetch on */
- 0xC8, /* default: fifo to 8, monitor off */
- 0x40, /* default: don't save bad frames (apricot.c had 0x80) */
- 0x2E, /* (default is 0x26)
- No source address insertion, 8 byte preamble */
- 0x00, /* default priority and backoff */
- 0x60, /* default interframe spacing */
- 0x00, /* default slot time LSB */
- 0xf2, /* default slot time and nr of retries */
- 0x00, /* default various bits
- (0: promiscuous mode, 1: broadcast disable,
- 2: encoding mode, 3: transmit on no CRS,
- 4: no CRC insertion, 5: CRC type,
- 6: bit stuffing, 7: padding) */
- 0x00, /* default carrier sense and collision detect */
- 0x40, /* default minimum frame length */
- 0xff, /* (default is 0xff, and that is what apricot.c has;
- elp486.c has 0xfb: Enable crc append in memory.) */
- 0x00, /* default: not full duplex */
- 0x7f /* (default is 0x3f) multi IA */
-};
-
-static int i596_open(struct net_device *dev);
-static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void print_eth(char *);
-static void set_multicast_list(struct net_device *dev);
-static void i596_tx_timeout(struct net_device *dev);
-
-static int
-i596_timeout(struct net_device *dev, char *msg, int ct) {
- struct i596_private *lp;
- int boguscnt = ct;
-
- lp = netdev_priv(dev);
- while (lp->scb.command) {
- if (--boguscnt == 0) {
- printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",
- dev->name, msg,
- lp->scb.status, lp->scb.command);
- return 1;
- }
- udelay(5);
- barrier();
- }
- return 0;
-}
-
-static inline int
-init_rx_bufs(struct net_device *dev, int num) {
- struct i596_private *lp;
- struct i596_rfd *rfd;
- int i;
- // struct i596_rbd *rbd;
-
- lp = netdev_priv(dev);
- lp->scb.pa_rfd = I596_NULL;
-
- for (i = 0; i < num; i++) {
- rfd = kmalloc(sizeof(struct i596_rfd), GFP_KERNEL);
- if (rfd == NULL)
- break;
-
- rfd->stat = 0;
- rfd->pa_rbd = I596_NULL;
- rfd->count = 0;
- rfd->size = 1532;
- if (i == 0) {
- rfd->cmd = CMD_EOL;
- lp->rx_tail = rfd;
- } else {
- rfd->cmd = 0;
- }
- rfd->pa_next = lp->scb.pa_rfd;
- lp->scb.pa_rfd = va_to_pa(rfd);
- lp->rx_tail->pa_next = lp->scb.pa_rfd;
- }
-
-#if 0
- for (i = 0; i<RX_RBD_SIZE; i++) {
- rbd = kmalloc(sizeof(struct i596_rbd), GFP_KERNEL);
- if (rbd) {
- rbd->pad = 0;
- rbd->count = 0;
- rbd->skb = dev_alloc_skb(RX_SKBSIZE);
- if (!rbd->skb) {
- printk("dev_alloc_skb failed");
- }
- rbd->next = rfd->rbd;
- if (i) {
- rfd->rbd->prev = rbd;
- rbd->size = RX_SKBSIZE;
- } else {
- rbd->size = (RX_SKBSIZE | RBD_EL);
- lp->rbd_tail = rbd;
- }
-
- rfd->rbd = rbd;
- }
- }
- lp->rbd_tail->next = rfd->rbd;
-#endif
- return i;
-}
-
-static inline void
-remove_rx_bufs(struct net_device *dev) {
- struct i596_private *lp;
- struct i596_rfd *rfd;
-
- lp = netdev_priv(dev);
- lp->rx_tail->pa_next = I596_NULL;
-
- do {
- rfd = pa_to_va(lp->scb.pa_rfd);
- lp->scb.pa_rfd = rfd->pa_next;
- kfree(rfd);
- } while (rfd != lp->rx_tail);
-
- lp->rx_tail = NULL;
-
-#if 0
- for (lp->rbd_list) {
- }
-#endif
-}
-
-#define PORT_RESET 0x00 /* reset 82596 */
-#define PORT_SELFTEST 0x01 /* selftest */
-#define PORT_ALTSCP 0x02 /* alternate SCB address */
-#define PORT_DUMP 0x03 /* dump */
-
-#define IOADDR 0xcb0 /* real constant */
-#define IRQ 10 /* default IRQ - can be changed by ECU */
-
-/* The 82596 requires two 16-bit write cycles for a port command */
-static inline void
-PORT(phys_addr a, unsigned int cmd) {
- if (a & 0xf)
- printk("lp486e.c: PORT: address not aligned\n");
- outw(((a & 0xffff) | cmd), IOADDR);
- outw(((a>>16) & 0xffff), IOADDR+2);
-}
-
-static inline void
-CA(void) {
- outb(0, IOADDR+4);
- udelay(8);
-}
-
-static inline void
-CLEAR_INT(void) {
- outb(0, IOADDR+8);
-}
-
-#if 0
-/* selftest or dump */
-static void
-i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
- struct i596_private *lp = netdev_priv(dev);
- u16 *outp;
- int i, m;
-
- memset((void *)&(lp->dump), 0, sizeof(struct i596_dump));
- outp = &(lp->dump.dump[0]);
-
- PORT(va_to_pa(outp), portcmd);
- mdelay(30); /* random, unmotivated */
-
- printk("lp486e i82596 %s result:\n", cmdname);
- for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
- ;
- for (i = 0; i < m; i++) {
- printk(" %04x", lp->dump.dump[i]);
- if (i%8 == 7)
- printk("\n");
- }
- printk("\n");
-}
-#endif
-
-static int
-i596_scp_setup(struct net_device *dev) {
- struct i596_private *lp = netdev_priv(dev);
- int boguscnt;
-
- /* Setup SCP, ISCP, SCB */
- /*
- * sysbus bits:
- * only a single byte is significant - here 0x44
- * 0x80: big endian mode (details depend on stepping)
- * 0x40: 1
- * 0x20: interrupt pin is active low
- * 0x10: lock function disabled
- * 0x08: external triggering of bus throttle timers
- * 0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode
- * 0x01: unused
- */
- lp->scp.sysbus = 0x00440000; /* linear mode */
- lp->scp.pad = 0; /* must be zero */
- lp->scp.pa_iscp = va_to_pa(&(lp->iscp));
-
- /*
- * The CPU sets the ISCP to 1 before it gives the first CA()
- */
- lp->iscp.busy = 0x0001;
- lp->iscp.pa_scb = va_to_pa(&(lp->scb));
-
- lp->scb.command = 0;
- lp->scb.status = 0;
- lp->scb.pa_cmd = I596_NULL;
- /* lp->scb.pa_rfd has been initialised already */
-
- lp->last_cmd = jiffies;
- lp->cmd_backlog = 0;
- lp->cmd_head = NULL;
-
- /*
- * Reset the 82596.
- * We need to wait 10 systemclock cycles, and
- * 5 serial clock cycles.
- */
- PORT(0, PORT_RESET); /* address part ignored */
- udelay(100);
-
- /*
- * Before the CA signal is asserted, the default SCP address
- * (0x00fffff4) can be changed to a 16-byte aligned value
- */
- PORT(va_to_pa(&lp->scp), PORT_ALTSCP); /* change the scp address */
-
- /*
- * The initialization procedure begins when a
- * Channel Attention signal is asserted after a reset.
- */
-
- CA();
-
- /*
- * The ISCP busy is cleared by the 82596 after the SCB address is read.
- */
- boguscnt = 100;
- while (lp->iscp.busy) {
- if (--boguscnt == 0) {
- /* No i82596 present? */
- printk("%s: i82596 initialization timed out\n",
- dev->name);
- return 1;
- }
- udelay(5);
- barrier();
- }
- /* I find here boguscnt==100, so no delay was required. */
-
- return 0;
-}
-
-static int
-init_i596(struct net_device *dev) {
- struct i596_private *lp;
-
- if (i596_scp_setup(dev))
- return 1;
-
- lp = netdev_priv(dev);
- lp->scb.command = 0;
-
- memcpy ((void *)lp->i596_config, init_setup, 14);
- lp->set_conf.command = CmdConfigure;
- i596_add_cmd(dev, (void *)&lp->set_conf);
-
- memcpy ((void *)lp->eth_addr, dev->dev_addr, 6);
- lp->set_add.command = CmdIASetup;
- i596_add_cmd(dev, &lp->set_add);
-
- lp->tdr.command = CmdTDR;
- i596_add_cmd(dev, &lp->tdr);
-
- if (lp->scb.command && i596_timeout(dev, "i82596 init", 200))
- return 1;
-
- lp->scb.command = RX_START;
- CA();
-
- barrier();
-
- if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
- return 1;
-
- return 0;
-}
-
-/* Receive a single frame */
-static inline int
-i596_rx_one(struct net_device *dev, struct i596_private *lp,
- struct i596_rfd *rfd, int *frames) {
-
- if (rfd->stat & RFD_STAT_OK) {
- /* a good frame */
- int pkt_len = (rfd->count & 0x3fff);
- struct sk_buff *skb = netdev_alloc_skb(dev, pkt_len);
-
- (*frames)++;
-
- if (rfd->cmd & CMD_EOL)
- printk("Received on EOL\n");
-
- if (skb == NULL) {
- printk ("%s: i596_rx Memory squeeze, "
- "dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- return 1;
- }
-
- memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
-
- skb->protocol = eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- } else {
-#if 0
- printk("Frame reception error status %04x\n",
- rfd->stat);
-#endif
- dev->stats.rx_errors++;
- if (rfd->stat & RFD_COLLISION)
- dev->stats.collisions++;
- if (rfd->stat & RFD_SHORT_FRAME_ERR)
- dev->stats.rx_length_errors++;
- if (rfd->stat & RFD_DMA_ERR)
- dev->stats.rx_over_errors++;
- if (rfd->stat & RFD_NOBUFS_ERR)
- dev->stats.rx_fifo_errors++;
- if (rfd->stat & RFD_ALIGN_ERR)
- dev->stats.rx_frame_errors++;
- if (rfd->stat & RFD_CRC_ERR)
- dev->stats.rx_crc_errors++;
- if (rfd->stat & RFD_LENGTH_ERR)
- dev->stats.rx_length_errors++;
- }
- rfd->stat = rfd->count = 0;
- return 0;
-}
-
-static int
-i596_rx(struct net_device *dev) {
- struct i596_private *lp = netdev_priv(dev);
- struct i596_rfd *rfd;
- int frames = 0;
-
- while (1) {
- rfd = pa_to_va(lp->scb.pa_rfd);
- if (!rfd) {
- printk(KERN_ERR "i596_rx: NULL rfd?\n");
- return 0;
- }
-#if 1
- if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B)))
- printk("SF:%p-%04x\n", rfd, rfd->stat);
-#endif
- if (!(rfd->stat & RFD_STAT_C))
- break; /* next one not ready */
- if (i596_rx_one(dev, lp, rfd, &frames))
- break; /* out of memory */
- rfd->cmd = CMD_EOL;
- lp->rx_tail->cmd = 0;
- lp->rx_tail = rfd;
- lp->scb.pa_rfd = rfd->pa_next;
- barrier();
- }
-
- return frames;
-}
-
-static void
-i596_cleanup_cmd(struct net_device *dev) {
- struct i596_private *lp;
- struct i596_cmd *cmd;
-
- lp = netdev_priv(dev);
- while (lp->cmd_head) {
- cmd = lp->cmd_head;
-
- lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
- lp->cmd_backlog--;
-
- switch ((cmd->command) & 0x7) {
- case CmdTx: {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd;
- struct i596_tbd * tx_cmd_tbd;
- tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
-
- dev_kfree_skb_any(tx_cmd_tbd->skb);
-
- dev->stats.tx_errors++;
- dev->stats.tx_aborted_errors++;
-
- cmd->pa_next = I596_NULL;
- kfree((unsigned char *)tx_cmd);
- netif_wake_queue(dev);
- break;
- }
- case CmdMulticastList: {
- // unsigned short count = *((unsigned short *) (ptr + 1));
-
- cmd->pa_next = I596_NULL;
- kfree((unsigned char *)cmd);
- break;
- }
- default: {
- cmd->pa_next = I596_NULL;
- break;
- }
- }
- barrier();
- }
-
- if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100))
- ;
-
- lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
-}
-
-static void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) {
-
- if (lp->scb.command && i596_timeout(dev, "i596_reset", 100))
- ;
-
- netif_stop_queue(dev);
-
- lp->scb.command = CUC_ABORT | RX_ABORT;
- CA();
- barrier();
-
- /* wait for shutdown */
- if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
- ;
-
- i596_cleanup_cmd(dev);
- i596_rx(dev);
-
- netif_start_queue(dev);
- /*dev_kfree_skb(skb, FREE_WRITE);*/
- init_i596(dev);
-}
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
- struct i596_private *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned long flags;
-
- cmd->status = 0;
- cmd->command |= (CMD_EOL | CMD_INTR);
- cmd->pa_next = I596_NULL;
-
- spin_lock_irqsave(&lp->cmd_lock, flags);
-
- if (lp->cmd_head) {
- lp->cmd_tail->pa_next = va_to_pa(cmd);
- } else {
- lp->cmd_head = cmd;
- if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100))
- ;
- lp->scb.pa_cmd = va_to_pa(cmd);
- lp->scb.command = CUC_START;
- CA();
- }
- lp->cmd_tail = cmd;
- lp->cmd_backlog++;
-
- lp->cmd_head = pa_to_va(lp->scb.pa_cmd);
- spin_unlock_irqrestore(&lp->cmd_lock, flags);
-
- if (lp->cmd_backlog > 16) {
- int tickssofar = jiffies - lp->last_cmd;
- if (tickssofar < HZ/4)
- return;
-
- printk(KERN_WARNING "%s: command unit timed out, status resetting.\n", dev->name);
- i596_reset(dev, lp, ioaddr);
- }
-}
-
-static int i596_open(struct net_device *dev)
-{
- int i;
-
- i = request_irq(dev->irq, i596_interrupt, IRQF_SHARED, dev->name, dev);
- if (i) {
- printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
- return i;
- }
-
- if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
- printk(KERN_ERR "%s: only able to allocate %d receive buffers\n", dev->name, i);
-
- if (i < 4) {
- free_irq(dev->irq, dev);
- return -EAGAIN;
- }
- netif_start_queue(dev);
- init_i596(dev);
- return 0; /* Always succeed */
-}
-
-static netdev_tx_t i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
- struct tx_cmd *tx_cmd;
- short length;
-
- length = skb->len;
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
-
- tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
- if (tx_cmd == NULL) {
- printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.tx_dropped++;
- dev_kfree_skb (skb);
- } else {
- struct i596_tbd *tx_cmd_tbd;
- tx_cmd_tbd = (struct i596_tbd *) (tx_cmd + 1);
- tx_cmd->pa_tbd = va_to_pa (tx_cmd_tbd);
- tx_cmd_tbd->pa_next = I596_NULL;
-
- tx_cmd->cmd.command = (CMD_FLEX | CmdTx);
-
- tx_cmd->pad = 0;
- tx_cmd->size = 0;
- tx_cmd_tbd->pad = 0;
- tx_cmd_tbd->size = (EOF | length);
-
- tx_cmd_tbd->pa_data = va_to_pa (skb->data);
- tx_cmd_tbd->skb = skb;
-
- if (i596_debug & LOG_SRCDST)
- print_eth (skb->data);
-
- i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
-
- dev->stats.tx_packets++;
- }
-
- return NETDEV_TX_OK;
-}
-
-static void
-i596_tx_timeout (struct net_device *dev) {
- struct i596_private *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- /* Transmitter timeout, serious problems. */
- printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name);
- dev->stats.tx_errors++;
-
- /* Try to restart the adaptor */
- if (lp->last_restart == dev->stats.tx_packets) {
- printk ("Resetting board.\n");
-
- /* Shutdown and restart */
- i596_reset (dev, lp, ioaddr);
- } else {
- /* Issue a channel attention signal */
- printk ("Kicking board.\n");
- lp->scb.command = (CUC_START | RX_START);
- CA();
- lp->last_restart = dev->stats.tx_packets;
- }
- netif_wake_queue(dev);
-}
-
-static void print_eth(char *add)
-{
- int i;
-
- printk ("Dest ");
- for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char) add[i]);
- printk ("\n");
-
- printk ("Source");
- for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char) add[i+6]);
- printk ("\n");
-
- printk ("type %2.2X%2.2X\n",
- (unsigned char) add[12], (unsigned char) add[13]);
-}
-
-static const struct net_device_ops i596_netdev_ops = {
- .ndo_open = i596_open,
- .ndo_stop = i596_close,
- .ndo_start_xmit = i596_start_xmit,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_tx_timeout = i596_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int __init lp486e_probe(struct net_device *dev) {
- struct i596_private *lp;
- unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 };
- unsigned char *bios;
- int i, j;
- int ret = -ENOMEM;
- static int probed;
-
- if (probed)
- return -ENODEV;
- probed++;
-
- if (!request_region(IOADDR, LP486E_TOTAL_SIZE, DRV_NAME)) {
- printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR);
- return -EBUSY;
- }
-
- lp = netdev_priv(dev);
- spin_lock_init(&lp->cmd_lock);
-
- /*
- * Do we really have this thing?
- */
- if (i596_scp_setup(dev)) {
- ret = -ENODEV;
- goto err_out_kfree;
- }
-
- dev->base_addr = IOADDR;
- dev->irq = IRQ;
-
-
- /*
- * How do we find the ethernet address? I don't know.
- * One possibility is to look at the EISA configuration area
- * [0xe8000-0xe9fff]. This contains the ethernet address
- * but not at a fixed address - things depend on setup options.
- *
- * If we find no address, or the wrong address, use
- * ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6
- * with the value found in the BIOS setup.
- */
- bios = bus_to_virt(0xe8000);
- for (j = 0; j < 0x2000; j++) {
- if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) {
- printk("%s: maybe address at BIOS 0x%x:",
- dev->name, 0xe8000+j);
- for (i = 0; i < 6; i++) {
- eth_addr[i] = bios[i+j];
- printk(" %2.2X", eth_addr[i]);
- }
- printk("\n");
- }
- }
-
- printk("%s: lp486e 82596 at %#3lx, IRQ %d,",
- dev->name, dev->base_addr, dev->irq);
- for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
- printk("\n");
-
- /* The LP486E-specific entries in the device structure. */
- dev->netdev_ops = &i596_netdev_ops;
- dev->watchdog_timeo = 5*HZ;
-
-#if 0
- /* selftest reports 0x320925ae - don't know what that means */
- i596_port_do(dev, PORT_SELFTEST, "selftest");
- i596_port_do(dev, PORT_DUMP, "dump");
-#endif
- return 0;
-
-err_out_kfree:
- release_region(IOADDR, LP486E_TOTAL_SIZE);
- return ret;
-}
-
-static inline void
-i596_handle_CU_completion(struct net_device *dev,
- struct i596_private *lp,
- unsigned short status,
- unsigned short *ack_cmdp) {
- struct i596_cmd *cmd;
- int frames_out = 0;
- int commands_done = 0;
- int cmd_val;
- unsigned long flags;
-
- spin_lock_irqsave(&lp->cmd_lock, flags);
- cmd = lp->cmd_head;
-
- while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) {
- cmd = lp->cmd_head;
-
- lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
- lp->cmd_backlog--;
-
- commands_done++;
- cmd_val = cmd->command & 0x7;
-#if 0
- printk("finished CU %s command (%d)\n",
- CUcmdnames[cmd_val], cmd_val);
-#endif
- switch (cmd_val) {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd;
- struct i596_tbd *tx_cmd_tbd;
-
- tx_cmd = (struct tx_cmd *) cmd;
- tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
-
- frames_out++;
- if (cmd->status & CMD_STAT_OK) {
- if (i596_debug)
- print_eth(pa_to_va(tx_cmd_tbd->pa_data));
- } else {
- dev->stats.tx_errors++;
- if (i596_debug)
- printk("transmission failure:%04x\n",
- cmd->status);
- if (cmd->status & 0x0020)
- dev->stats.collisions++;
- if (!(cmd->status & 0x0040))
- dev->stats.tx_heartbeat_errors++;
- if (cmd->status & 0x0400)
- dev->stats.tx_carrier_errors++;
- if (cmd->status & 0x0800)
- dev->stats.collisions++;
- if (cmd->status & 0x1000)
- dev->stats.tx_aborted_errors++;
- }
- dev_kfree_skb_irq(tx_cmd_tbd->skb);
-
- cmd->pa_next = I596_NULL;
- kfree((unsigned char *)tx_cmd);
- netif_wake_queue(dev);
- break;
- }
-
- case CmdMulticastList:
- cmd->pa_next = I596_NULL;
- kfree((unsigned char *)cmd);
- break;
-
- case CmdTDR:
- {
- unsigned long status = *((unsigned long *) (cmd + 1));
- if (status & 0x8000) {
- if (i596_debug)
- printk("%s: link ok.\n", dev->name);
- } else {
- if (status & 0x4000)
- printk("%s: Transceiver problem.\n",
- dev->name);
- if (status & 0x2000)
- printk("%s: Termination problem.\n",
- dev->name);
- if (status & 0x1000)
- printk("%s: Short circuit.\n",
- dev->name);
- printk("%s: Time %ld.\n",
- dev->name, status & 0x07ff);
- }
- }
- default:
- cmd->pa_next = I596_NULL;
- lp->last_cmd = jiffies;
-
- }
- barrier();
- }
-
- cmd = lp->cmd_head;
- while (cmd && (cmd != lp->cmd_tail)) {
- cmd->command &= 0x1fff;
- cmd = pa_to_va(cmd->pa_next);
- barrier();
- }
-
- if (lp->cmd_head)
- *ack_cmdp |= CUC_START;
- lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
- spin_unlock_irqrestore(&lp->cmd_lock, flags);
-}
-
-static irqreturn_t
-i596_interrupt(int irq, void *dev_instance)
-{
- struct net_device *dev = dev_instance;
- struct i596_private *lp = netdev_priv(dev);
- unsigned short status, ack_cmd = 0;
- int frames_in = 0;
-
- /*
- * The 82596 examines the command, performs the required action,
- * and then clears the SCB command word.
- */
- if (lp->scb.command && i596_timeout(dev, "interrupt", 40))
- ;
-
- /*
- * The status word indicates the status of the 82596.
- * It is modified only by the 82596.
- *
- * [So, we must not clear it. I find often status 0xffff,
- * which is not one of the values allowed by the docs.]
- */
- status = lp->scb.status;
-#if 0
- if (i596_debug) {
- printk("%s: i596 interrupt, ", dev->name);
- i596_out_status(status);
- }
-#endif
- /* Impossible, but it happens - perhaps when we get
- a receive interrupt but scb.pa_rfd is I596_NULL. */
- if (status == 0xffff) {
- printk("%s: i596_interrupt: got status 0xffff\n", dev->name);
- goto out;
- }
-
- ack_cmd = (status & STAT_ACK);
-
- if (status & (STAT_CX | STAT_CNA))
- i596_handle_CU_completion(dev, lp, status, &ack_cmd);
-
- if (status & (STAT_FR | STAT_RNR)) {
- /* Restart the receive unit when it got inactive somehow */
- if ((status & STAT_RNR) && netif_running(dev))
- ack_cmd |= RX_START;
-
- if (status & STAT_FR) {
- frames_in = i596_rx(dev);
- if (!frames_in)
- printk("receive frame reported, but no frames\n");
- }
- }
-
- /* acknowledge the interrupt */
- /*
- if ((lp->scb.pa_cmd != I596_NULL) && netif_running(dev))
- ack_cmd |= CUC_START;
- */
-
- if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100))
- ;
-
- lp->scb.command = ack_cmd;
-
- CLEAR_INT();
- CA();
-
- out:
- return IRQ_HANDLED;
-}
-
-static int i596_close(struct net_device *dev) {
- struct i596_private *lp = netdev_priv(dev);
-
- netif_stop_queue(dev);
-
- if (i596_debug)
- printk("%s: Shutting down ethercard, status was %4.4x.\n",
- dev->name, lp->scb.status);
-
- lp->scb.command = (CUC_ABORT | RX_ABORT);
- CA();
-
- i596_cleanup_cmd(dev);
-
- if (lp->scb.command && i596_timeout(dev, "i596_close", 200))
- ;
-
- free_irq(dev->irq, dev);
- remove_rx_bufs(dev);
-
- return 0;
-}
-
-/*
-* Set or clear the multicast filter for this adaptor.
-*/
-
-static void set_multicast_list(struct net_device *dev) {
- struct i596_private *lp = netdev_priv(dev);
- struct i596_cmd *cmd;
-
- if (i596_debug > 1)
- printk ("%s: set multicast list %d\n",
- dev->name, netdev_mc_count(dev));
-
- if (!netdev_mc_empty(dev)) {
- struct netdev_hw_addr *ha;
- char *cp;
- cmd = kmalloc(sizeof(struct i596_cmd) + 2 +
- netdev_mc_count(dev) * 6, GFP_ATOMIC);
- if (cmd == NULL) {
- printk (KERN_ERR "%s: set_multicast Memory squeeze.\n", dev->name);
- return;
- }
- cmd->command = CmdMulticastList;
- *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6;
- cp = ((char *)(cmd + 1))+2;
- netdev_for_each_mc_addr(ha, dev) {
- memcpy(cp, ha->addr, 6);
- cp += 6;
- }
- if (i596_debug & LOG_SRCDST)
- print_eth (((char *)(cmd + 1)) + 2);
- i596_add_cmd(dev, cmd);
- } else {
- if (lp->set_conf.pa_next != I596_NULL) {
- return;
- }
- if (netdev_mc_empty(dev) &&
- !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
- lp->i596_config[8] &= ~0x01;
- } else {
- lp->i596_config[8] |= 0x01;
- }
-
- i596_add_cmd(dev, &lp->set_conf);
- }
-}
-
-MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>");
-MODULE_DESCRIPTION("Intel Panther onboard i82596 driver");
-MODULE_LICENSE("GPL");
-
-static struct net_device *dev_lp486e;
-static int full_duplex;
-static int options;
-static int io = IOADDR;
-static int irq = IRQ;
-
-module_param(debug, int, 0);
-//module_param(max_interrupt_work, int, 0);
-//module_param(reverse_probe, int, 0);
-//module_param(rx_copybreak, int, 0);
-module_param(options, int, 0);
-module_param(full_duplex, int, 0);
-
-static int __init lp486e_init_module(void) {
- int err;
- struct net_device *dev = alloc_etherdev(sizeof(struct i596_private));
- if (!dev)
- return -ENOMEM;
-
- dev->irq = irq;
- dev->base_addr = io;
- err = lp486e_probe(dev);
- if (err) {
- free_netdev(dev);
- return err;
- }
- err = register_netdev(dev);
- if (err) {
- release_region(dev->base_addr, LP486E_TOTAL_SIZE);
- free_netdev(dev);
- return err;
- }
- dev_lp486e = dev;
- full_duplex = 0;
- options = 0;
- return 0;
-}
-
-static void __exit lp486e_cleanup_module(void) {
- unregister_netdev(dev_lp486e);
- release_region(dev_lp486e->base_addr, LP486E_TOTAL_SIZE);
- free_netdev(dev_lp486e);
-}
-
-module_init(lp486e_init_module);
-module_exit(lp486e_cleanup_module);
diff --git a/drivers/net/ethernet/i825xx/ni52.c b/drivers/net/ethernet/i825xx/ni52.c
deleted file mode 100644
index 272976e1bb0f..000000000000
--- a/drivers/net/ethernet/i825xx/ni52.c
+++ /dev/null
@@ -1,1346 +0,0 @@
-/*
- * net-3-driver for the NI5210 card (i82586 Ethernet chip)
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
- * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
- * [feel free to mail ....]
- *
- * when using as module: (no autoprobing!)
- * run with e.g:
- * insmod ni52.o io=0x360 irq=9 memstart=0xd0000 memend=0xd4000
- *
- * CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
- *
- * If you find a bug, please report me:
- * The kernel panic output and any kmsg from the ni52 driver
- * the ni5210-driver-version and the linux-kernel version
- * how many shared memory (memsize) on the netcard,
- * bootprom: yes/no, base_addr, mem_start
- * maybe the ni5210-card revision and the i82586 version
- *
- * autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340
- * mem_start: 0xd0000,0xd2000,0xc8000,0xca000,0xd4000,0xd6000,
- * 0xd8000,0xcc000,0xce000,0xda000,0xdc000
- *
- * sources:
- * skeleton.c from Donald Becker
- *
- * I have also done a look in the following sources: (mail me if you need them)
- * crynwr-packet-driver by Russ Nelson
- * Garret A. Wollman's (fourth) i82586-driver for BSD
- * (before getting an i82596 (yes 596 not 586) manual, the existing drivers
- * helped me a lot to understand this tricky chip.)
- *
- * Known Problems:
- * The internal sysbus seems to be slow. So we often lose packets because of
- * overruns while receiving from a fast remote host.
- * This can slow down TCP connections. Maybe the newer ni5210 cards are
- * better. My experience is, that if a machine sends with more than about
- * 500-600K/s the fifo/sysbus overflows.
- *
- * IMPORTANT NOTE:
- * On fast networks, it's a (very) good idea to have 16K shared memory. With
- * 8K, we can store only 4 receive frames, so it can (easily) happen that a
- * remote machine 'overruns' our system.
- *
- * Known i82586/card problems (I'm sure, there are many more!):
- * Running the NOP-mode, the i82586 sometimes seems to forget to report
- * every xmit-interrupt until we restart the CU.
- * Another MAJOR bug is, that the RU sometimes seems to ignore the EL-Bit
- * in the RBD-Struct which indicates an end of the RBD queue.
- * Instead, the RU fetches another (randomly selected and
- * usually used) RBD and begins to fill it. (Maybe, this happens only if
- * the last buffer from the previous RFD fits exact into the queue and
- * the next RFD can't fetch an initial RBD. Anyone knows more? )
- *
- * results from ftp performance tests with Linux 1.2.5
- * send and receive about 350-400 KByte/s (peak up to 460 kbytes/s)
- * sending in NOP-mode: peak performance up to 530K/s (but better don't
- * run this mode)
- */
-
-/*
- * 29.Sept.96: virt_to_bus changes for new memory scheme
- * 19.Feb.96: more Mcast changes, module support (MH)
- *
- * 18.Nov.95: Mcast changes (AC).
- *
- * 23.April.95: fixed(?) receiving problems by configuring a RFD more
- * than the number of RBD's. Can maybe cause other problems.
- * 18.April.95: Added MODULE support (MH)
- * 17.April.95: MC related changes in init586() and set_multicast_list().
- * removed use of 'jiffies' in init586() (MH)
- *
- * 19.Sep.94: Added Multicast support (not tested yet) (MH)
- *
- * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling.
- * Now, every RFD has exact one RBD. (MH)
- *
- * 14.Sep.94: added promiscuous mode, a few cleanups (MH)
- *
- * 19.Aug.94: changed request_irq() parameter (MH)
- *
- * 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH)
- *
- * 19.July.94: lotsa cleanups .. (MH)
- *
- * 17.July.94: some patches ... verified to run with 1.1.29 (MH)
- *
- * 4.July.94: patches for Linux 1.1.24 (MH)
- *
- * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH)
- *
- * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff,
- * too (MH)
- *
- * < 30.Sep.93: first versions
- */
-
-static int debuglevel; /* debug-printk 0: off 1: a few 2: more */
-static int automatic_resume; /* experimental .. better should be zero */
-static int rfdadd; /* rfdadd=1 may be better for 8K MEM cards */
-static int fifo = 0x8; /* don't change */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "ni52.h"
-
-#define DRV_NAME "ni52"
-
-#define DEBUG /* debug on */
-#define SYSBUSVAL 1 /* 8 Bit */
-
-#define ni_attn586() { outb(0, dev->base_addr + NI52_ATTENTION); }
-#define ni_reset586() { outb(0, dev->base_addr + NI52_RESET); }
-#define ni_disint() { outb(0, dev->base_addr + NI52_INTDIS); }
-#define ni_enaint() { outb(0, dev->base_addr + NI52_INTENA); }
-
-#define make32(ptr16) ((void __iomem *)(p->memtop + (short) (ptr16)))
-#define make24(ptr32) ((char __iomem *)(ptr32)) - p->base
-#define make16(ptr32) ((unsigned short) ((char __iomem *)(ptr32)\
- - p->memtop))
-
-/******************* how to calculate the buffers *****************************
-
- * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
- * --------------- in a different (more stable?) mode. Only in this mode it's
- * possible to configure the driver with 'NO_NOPCOMMANDS'
-
-sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
-sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
-sizeof(rfd) = 24; sizeof(rbd) = 12;
-sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
-sizeof(nop_cmd) = 8;
-
- * if you don't know the driver, better do not change these values: */
-
-#define RECV_BUFF_SIZE 1524 /* slightly oversized */
-#define XMIT_BUFF_SIZE 1524 /* slightly oversized */
-#define NUM_XMIT_BUFFS 1 /* config for both, 8K and 16K shmem */
-#define NUM_RECV_BUFFS_8 4 /* config for 8K shared mem */
-#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */
-#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */
-
-/**************************************************************************/
-
-
-#define NI52_TOTAL_SIZE 16
-#define NI52_ADDR0 0x02
-#define NI52_ADDR1 0x07
-#define NI52_ADDR2 0x01
-
-static int ni52_probe1(struct net_device *dev, int ioaddr);
-static irqreturn_t ni52_interrupt(int irq, void *dev_id);
-static int ni52_open(struct net_device *dev);
-static int ni52_close(struct net_device *dev);
-static netdev_tx_t ni52_send_packet(struct sk_buff *, struct net_device *);
-static struct net_device_stats *ni52_get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void ni52_timeout(struct net_device *dev);
-
-/* helper-functions */
-static int init586(struct net_device *dev);
-static int check586(struct net_device *dev, unsigned size);
-static void alloc586(struct net_device *dev);
-static void startrecv586(struct net_device *dev);
-static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr);
-static void ni52_rcv_int(struct net_device *dev);
-static void ni52_xmt_int(struct net_device *dev);
-static void ni52_rnr_int(struct net_device *dev);
-
-struct priv {
- char __iomem *base;
- char __iomem *mapped;
- char __iomem *memtop;
- spinlock_t spinlock;
- int reset;
- struct rfd_struct __iomem *rfd_last, *rfd_top, *rfd_first;
- struct scp_struct __iomem *scp;
- struct iscp_struct __iomem *iscp;
- struct scb_struct __iomem *scb;
- struct tbd_struct __iomem *xmit_buffs[NUM_XMIT_BUFFS];
-#if (NUM_XMIT_BUFFS == 1)
- struct transmit_cmd_struct __iomem *xmit_cmds[2];
- struct nop_cmd_struct __iomem *nop_cmds[2];
-#else
- struct transmit_cmd_struct __iomem *xmit_cmds[NUM_XMIT_BUFFS];
- struct nop_cmd_struct __iomem *nop_cmds[NUM_XMIT_BUFFS];
-#endif
- int nop_point, num_recv_buffs;
- char __iomem *xmit_cbuffs[NUM_XMIT_BUFFS];
- int xmit_count, xmit_last;
-};
-
-/* wait for command with timeout: */
-static void wait_for_scb_cmd(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
- int i;
- for (i = 0; i < 16384; i++) {
- if (readb(&p->scb->cmd_cuc) == 0)
- break;
- udelay(4);
- if (i == 16383) {
- printk(KERN_ERR "%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",
- dev->name, readb(&p->scb->cmd_cuc), readb(&p->scb->cus));
- if (!p->reset) {
- p->reset = 1;
- ni_reset586();
- }
- }
- }
-}
-
-static void wait_for_scb_cmd_ruc(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
- int i;
- for (i = 0; i < 16384; i++) {
- if (readb(&p->scb->cmd_ruc) == 0)
- break;
- udelay(4);
- if (i == 16383) {
- printk(KERN_ERR "%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",
- dev->name, readb(&p->scb->cmd_ruc),
- readb(&p->scb->rus));
- if (!p->reset) {
- p->reset = 1;
- ni_reset586();
- }
- }
- }
-}
-
-static void wait_for_stat_compl(void __iomem *p)
-{
- struct nop_cmd_struct __iomem *addr = p;
- int i;
- for (i = 0; i < 32767; i++) {
- if (readw(&((addr)->cmd_status)) & STAT_COMPL)
- break;
- udelay(32);
- }
-}
-
-/**********************************************
- * close device
- */
-static int ni52_close(struct net_device *dev)
-{
- free_irq(dev->irq, dev);
- ni_reset586(); /* the hard way to stop the receiver */
- netif_stop_queue(dev);
- return 0;
-}
-
-/**********************************************
- * open device
- */
-static int ni52_open(struct net_device *dev)
-{
- int ret;
-
- ni_disint();
- alloc586(dev);
- init586(dev);
- startrecv586(dev);
- ni_enaint();
-
- ret = request_irq(dev->irq, ni52_interrupt, 0, dev->name, dev);
- if (ret) {
- ni_reset586();
- return ret;
- }
- netif_start_queue(dev);
- return 0; /* most done by init */
-}
-
-static int check_iscp(struct net_device *dev, void __iomem *addr)
-{
- struct iscp_struct __iomem *iscp = addr;
- struct priv *p = netdev_priv(dev);
- memset_io(iscp, 0, sizeof(struct iscp_struct));
-
- writel(make24(iscp), &p->scp->iscp);
- writeb(1, &iscp->busy);
-
- ni_reset586();
- ni_attn586();
- mdelay(32); /* wait a while... */
- /* i82586 clears 'busy' after successful init */
- if (readb(&iscp->busy))
- return 0;
- return 1;
-}
-
-/**********************************************
- * Check to see if there's an 82586 out there.
- */
-static int check586(struct net_device *dev, unsigned size)
-{
- struct priv *p = netdev_priv(dev);
- int i;
-
- p->mapped = ioremap(dev->mem_start, size);
- if (!p->mapped)
- return 0;
-
- p->base = p->mapped + size - 0x01000000;
- p->memtop = p->mapped + size;
- p->scp = (struct scp_struct __iomem *)(p->base + SCP_DEFAULT_ADDRESS);
- p->scb = (struct scb_struct __iomem *) p->mapped;
- p->iscp = (struct iscp_struct __iomem *)p->scp - 1;
- memset_io(p->scp, 0, sizeof(struct scp_struct));
- for (i = 0; i < sizeof(struct scp_struct); i++)
- /* memory was writeable? */
- if (readb((char __iomem *)p->scp + i))
- goto Enodev;
- writeb(SYSBUSVAL, &p->scp->sysbus); /* 1 = 8Bit-Bus, 0 = 16 Bit */
- if (readb(&p->scp->sysbus) != SYSBUSVAL)
- goto Enodev;
-
- if (!check_iscp(dev, p->mapped))
- goto Enodev;
- if (!check_iscp(dev, p->iscp))
- goto Enodev;
- return 1;
-Enodev:
- iounmap(p->mapped);
- return 0;
-}
-
-/******************************************************************
- * set iscp at the right place, called by ni52_probe1 and open586.
- */
-static void alloc586(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- ni_reset586();
- mdelay(32);
-
- memset_io(p->iscp, 0, sizeof(struct iscp_struct));
- memset_io(p->scp , 0, sizeof(struct scp_struct));
-
- writel(make24(p->iscp), &p->scp->iscp);
- writeb(SYSBUSVAL, &p->scp->sysbus);
- writew(make16(p->scb), &p->iscp->scb_offset);
-
- writeb(1, &p->iscp->busy);
- ni_reset586();
- ni_attn586();
-
- mdelay(32);
-
- if (readb(&p->iscp->busy))
- printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name);
-
- p->reset = 0;
-
- memset_io(p->scb, 0, sizeof(struct scb_struct));
-}
-
-/* set: io,irq,memstart,memend or set it when calling insmod */
-static int irq = 9;
-static int io = 0x300;
-static long memstart; /* e.g 0xd0000 */
-static long memend; /* e.g 0xd4000 */
-
-/**********************************************
- * probe the ni5210-card
- */
-struct net_device * __init ni52_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct priv));
- static const int ports[] = {0x300, 0x280, 0x360, 0x320, 0x340, 0};
- const int *port;
- struct priv *p;
- int err = 0;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- p = netdev_priv(dev);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
- memstart = dev->mem_start;
- memend = dev->mem_end;
- }
-
- if (io > 0x1ff) { /* Check a single specified location. */
- err = ni52_probe1(dev, io);
- } else if (io > 0) { /* Don't probe at all. */
- err = -ENXIO;
- } else {
- for (port = ports; *port && ni52_probe1(dev, *port) ; port++)
- ;
- if (*port)
- goto got_it;
-#ifdef FULL_IO_PROBE
- for (io = 0x200; io < 0x400 && ni52_probe1(dev, io); io += 8)
- ;
- if (io < 0x400)
- goto got_it;
-#endif
- err = -ENODEV;
- }
- if (err)
- goto out;
-got_it:
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
-out1:
- iounmap(p->mapped);
- release_region(dev->base_addr, NI52_TOTAL_SIZE);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static const struct net_device_ops ni52_netdev_ops = {
- .ndo_open = ni52_open,
- .ndo_stop = ni52_close,
- .ndo_get_stats = ni52_get_stats,
- .ndo_tx_timeout = ni52_timeout,
- .ndo_start_xmit = ni52_send_packet,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int __init ni52_probe1(struct net_device *dev, int ioaddr)
-{
- int i, size, retval;
- struct priv *priv = netdev_priv(dev);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
- dev->mem_start = memstart;
- dev->mem_end = memend;
-
- spin_lock_init(&priv->spinlock);
-
- if (!request_region(ioaddr, NI52_TOTAL_SIZE, DRV_NAME))
- return -EBUSY;
-
- if (!(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
- !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2)) {
- retval = -ENODEV;
- goto out;
- }
-
- for (i = 0; i < ETH_ALEN; i++)
- dev->dev_addr[i] = inb(dev->base_addr+i);
-
- if (dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 ||
- dev->dev_addr[2] != NI52_ADDR2) {
- retval = -ENODEV;
- goto out;
- }
-
- printk(KERN_INFO "%s: NI5210 found at %#3lx, ",
- dev->name, dev->base_addr);
-
- /*
- * check (or search) IO-Memory, 8K and 16K
- */
-#ifdef MODULE
- size = dev->mem_end - dev->mem_start;
- if (size != 0x2000 && size != 0x4000) {
- printk("\n");
- printk(KERN_ERR "%s: Invalid memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n", dev->name, size);
- retval = -ENODEV;
- goto out;
- }
- if (!check586(dev, size)) {
- printk(KERN_ERR "?memcheck, Can't find memory at 0x%lx with size %d!\n", dev->mem_start, size);
- retval = -ENODEV;
- goto out;
- }
-#else
- if (dev->mem_start != 0) {
- /* no auto-mem-probe */
- size = 0x4000; /* check for 16K mem */
- if (!check586(dev, size)) {
- size = 0x2000; /* check for 8K mem */
- if (!check586(dev, size)) {
- printk(KERN_ERR "?memprobe, Can't find memory at 0x%lx!\n", dev->mem_start);
- retval = -ENODEV;
- goto out;
- }
- }
- } else {
- static const unsigned long memaddrs[] = {
- 0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000,
- 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0
- };
- for (i = 0;; i++) {
- if (!memaddrs[i]) {
- printk(KERN_ERR "?memprobe, Can't find io-memory!\n");
- retval = -ENODEV;
- goto out;
- }
- dev->mem_start = memaddrs[i];
- size = 0x2000; /* check for 8K mem */
- if (check586(dev, size))
- /* 8K-check */
- break;
- size = 0x4000; /* check for 16K mem */
- if (check586(dev, size))
- /* 16K-check */
- break;
- }
- }
- /* set mem_end showed by 'ifconfig' */
- dev->mem_end = dev->mem_start + size;
-#endif
-
- alloc586(dev);
-
- /* set number of receive-buffs according to memsize */
- if (size == 0x2000)
- priv->num_recv_buffs = NUM_RECV_BUFFS_8;
- else
- priv->num_recv_buffs = NUM_RECV_BUFFS_16;
-
- printk(KERN_DEBUG "Memaddr: 0x%lx, Memsize: %d, ",
- dev->mem_start, size);
-
- if (dev->irq < 2) {
- unsigned long irq_mask;
-
- irq_mask = probe_irq_on();
- ni_reset586();
- ni_attn586();
-
- mdelay(20);
- dev->irq = probe_irq_off(irq_mask);
- if (!dev->irq) {
- printk("?autoirq, Failed to detect IRQ line!\n");
- retval = -EAGAIN;
- iounmap(priv->mapped);
- goto out;
- }
- printk("IRQ %d (autodetected).\n", dev->irq);
- } else {
- if (dev->irq == 2)
- dev->irq = 9;
- printk("IRQ %d (assigned and not checked!).\n", dev->irq);
- }
-
- dev->netdev_ops = &ni52_netdev_ops;
- dev->watchdog_timeo = HZ/20;
-
- return 0;
-out:
- release_region(ioaddr, NI52_TOTAL_SIZE);
- return retval;
-}
-
-/**********************************************
- * init the chip (ni52-interrupt should be disabled?!)
- * needs a correct 'allocated' memory
- */
-
-static int init586(struct net_device *dev)
-{
- void __iomem *ptr;
- int i, result = 0;
- struct priv *p = netdev_priv(dev);
- struct configure_cmd_struct __iomem *cfg_cmd;
- struct iasetup_cmd_struct __iomem *ias_cmd;
- struct tdr_cmd_struct __iomem *tdr_cmd;
- struct mcsetup_cmd_struct __iomem *mc_cmd;
- struct netdev_hw_addr *ha;
- int num_addrs = netdev_mc_count(dev);
-
- ptr = p->scb + 1;
-
- cfg_cmd = ptr; /* configure-command */
- writew(0, &cfg_cmd->cmd_status);
- writew(CMD_CONFIGURE | CMD_LAST, &cfg_cmd->cmd_cmd);
- writew(0xFFFF, &cfg_cmd->cmd_link);
-
- /* number of cfg bytes */
- writeb(0x0a, &cfg_cmd->byte_cnt);
- /* fifo-limit (8=tx:32/rx:64) */
- writeb(fifo, &cfg_cmd->fifo);
- /* hold or discard bad recv frames (bit 7) */
- writeb(0x40, &cfg_cmd->sav_bf);
- /* addr_len |!src_insert |pre-len |loopback */
- writeb(0x2e, &cfg_cmd->adr_len);
- writeb(0x00, &cfg_cmd->priority);
- writeb(0x60, &cfg_cmd->ifs);
- writeb(0x00, &cfg_cmd->time_low);
- writeb(0xf2, &cfg_cmd->time_high);
- writeb(0x00, &cfg_cmd->promisc);
- if (dev->flags & IFF_ALLMULTI) {
- int len = ((char __iomem *)p->iscp - (char __iomem *)ptr - 8) / 6;
- if (num_addrs > len) {
- printk(KERN_ERR "%s: switching to promisc. mode\n",
- dev->name);
- writeb(0x01, &cfg_cmd->promisc);
- }
- }
- if (dev->flags & IFF_PROMISC)
- writeb(0x01, &cfg_cmd->promisc);
- writeb(0x00, &cfg_cmd->carr_coll);
- writew(make16(cfg_cmd), &p->scb->cbl_offset);
- writeb(0, &p->scb->cmd_ruc);
-
- writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
- ni_attn586();
-
- wait_for_stat_compl(cfg_cmd);
-
- if ((readw(&cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
- (STAT_COMPL|STAT_OK)) {
- printk(KERN_ERR "%s: configure command failed: %x\n",
- dev->name, readw(&cfg_cmd->cmd_status));
- return 1;
- }
-
- /*
- * individual address setup
- */
-
- ias_cmd = ptr;
-
- writew(0, &ias_cmd->cmd_status);
- writew(CMD_IASETUP | CMD_LAST, &ias_cmd->cmd_cmd);
- writew(0xffff, &ias_cmd->cmd_link);
-
- memcpy_toio(&ias_cmd->iaddr, (char *)dev->dev_addr, ETH_ALEN);
-
- writew(make16(ias_cmd), &p->scb->cbl_offset);
-
- writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
- ni_attn586();
-
- wait_for_stat_compl(ias_cmd);
-
- if ((readw(&ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) !=
- (STAT_OK|STAT_COMPL)) {
- printk(KERN_ERR "%s (ni52): individual address setup command failed: %04x\n", dev->name, readw(&ias_cmd->cmd_status));
- return 1;
- }
-
- /*
- * TDR, wire check .. e.g. no resistor e.t.c
- */
-
- tdr_cmd = ptr;
-
- writew(0, &tdr_cmd->cmd_status);
- writew(CMD_TDR | CMD_LAST, &tdr_cmd->cmd_cmd);
- writew(0xffff, &tdr_cmd->cmd_link);
- writew(0, &tdr_cmd->status);
-
- writew(make16(tdr_cmd), &p->scb->cbl_offset);
- writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */
- ni_attn586();
-
- wait_for_stat_compl(tdr_cmd);
-
- if (!(readw(&tdr_cmd->cmd_status) & STAT_COMPL))
- printk(KERN_ERR "%s: Problems while running the TDR.\n",
- dev->name);
- else {
- udelay(16);
- result = readw(&tdr_cmd->status);
- writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
- ni_attn586(); /* ack the interrupts */
-
- if (result & TDR_LNK_OK)
- ;
- else if (result & TDR_XCVR_PRB)
- printk(KERN_ERR "%s: TDR: Transceiver problem. Check the cable(s)!\n",
- dev->name);
- else if (result & TDR_ET_OPN)
- printk(KERN_ERR "%s: TDR: No correct termination %d clocks away.\n",
- dev->name, result & TDR_TIMEMASK);
- else if (result & TDR_ET_SRT) {
- /* time == 0 -> strange :-) */
- if (result & TDR_TIMEMASK)
- printk(KERN_ERR "%s: TDR: Detected a short circuit %d clocks away.\n",
- dev->name, result & TDR_TIMEMASK);
- } else
- printk(KERN_ERR "%s: TDR: Unknown status %04x\n",
- dev->name, result);
- }
-
- /*
- * Multicast setup
- */
- if (num_addrs && !(dev->flags & IFF_PROMISC)) {
- mc_cmd = ptr;
- writew(0, &mc_cmd->cmd_status);
- writew(CMD_MCSETUP | CMD_LAST, &mc_cmd->cmd_cmd);
- writew(0xffff, &mc_cmd->cmd_link);
- writew(num_addrs * 6, &mc_cmd->mc_cnt);
-
- i = 0;
- netdev_for_each_mc_addr(ha, dev)
- memcpy_toio(mc_cmd->mc_list[i++], ha->addr, 6);
-
- writew(make16(mc_cmd), &p->scb->cbl_offset);
- writeb(CUC_START, &p->scb->cmd_cuc);
- ni_attn586();
-
- wait_for_stat_compl(mc_cmd);
-
- if ((readw(&mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK))
- != (STAT_COMPL|STAT_OK))
- printk(KERN_ERR "%s: Can't apply multicast-address-list.\n", dev->name);
- }
-
- /*
- * alloc nop/xmit-cmds
- */
-#if (NUM_XMIT_BUFFS == 1)
- for (i = 0; i < 2; i++) {
- p->nop_cmds[i] = ptr;
- writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
- writew(0, &p->nop_cmds[i]->cmd_status);
- writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
- ptr = ptr + sizeof(struct nop_cmd_struct);
- }
-#else
- for (i = 0; i < NUM_XMIT_BUFFS; i++) {
- p->nop_cmds[i] = ptr;
- writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd);
- writew(0, &p->nop_cmds[i]->cmd_status);
- writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link);
- ptr = ptr + sizeof(struct nop_cmd_struct);
- }
-#endif
-
- ptr = alloc_rfa(dev, ptr); /* init receive-frame-area */
-
- /*
- * alloc xmit-buffs / init xmit_cmds
- */
- for (i = 0; i < NUM_XMIT_BUFFS; i++) {
- /* Transmit cmd/buff 0 */
- p->xmit_cmds[i] = ptr;
- ptr = ptr + sizeof(struct transmit_cmd_struct);
- p->xmit_cbuffs[i] = ptr; /* char-buffs */
- ptr = ptr + XMIT_BUFF_SIZE;
- p->xmit_buffs[i] = ptr; /* TBD */
- ptr = ptr + sizeof(struct tbd_struct);
- if ((void __iomem *)ptr > (void __iomem *)p->iscp) {
- printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n",
- dev->name);
- return 1;
- }
- memset_io(p->xmit_cmds[i], 0,
- sizeof(struct transmit_cmd_struct));
- memset_io(p->xmit_buffs[i], 0,
- sizeof(struct tbd_struct));
- writew(make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]),
- &p->xmit_cmds[i]->cmd_link);
- writew(STAT_COMPL, &p->xmit_cmds[i]->cmd_status);
- writew(CMD_XMIT|CMD_INT, &p->xmit_cmds[i]->cmd_cmd);
- writew(make16(p->xmit_buffs[i]), &p->xmit_cmds[i]->tbd_offset);
- writew(0xffff, &p->xmit_buffs[i]->next);
- writel(make24(p->xmit_cbuffs[i]), &p->xmit_buffs[i]->buffer);
- }
-
- p->xmit_count = 0;
- p->xmit_last = 0;
-#ifndef NO_NOPCOMMANDS
- p->nop_point = 0;
-#endif
-
- /*
- * 'start transmitter'
- */
-#ifndef NO_NOPCOMMANDS
- writew(make16(p->nop_cmds[0]), &p->scb->cbl_offset);
- writeb(CUC_START, &p->scb->cmd_cuc);
- ni_attn586();
- wait_for_scb_cmd(dev);
-#else
- writew(make16(p->xmit_cmds[0]), &p->xmit_cmds[0]->cmd_link);
- writew(CMD_XMIT | CMD_SUSPEND | CMD_INT, &p->xmit_cmds[0]->cmd_cmd);
-#endif
-
- /*
- * ack. interrupts
- */
- writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc);
- ni_attn586();
- udelay(16);
-
- ni_enaint();
-
- return 0;
-}
-
-/******************************************************
- * This is a helper routine for ni52_rnr_int() and init586().
- * It sets up the Receive Frame Area (RFA).
- */
-
-static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr)
-{
- struct rfd_struct __iomem *rfd = ptr;
- struct rbd_struct __iomem *rbd;
- int i;
- struct priv *p = netdev_priv(dev);
-
- memset_io(rfd, 0,
- sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd));
- p->rfd_first = rfd;
-
- for (i = 0; i < (p->num_recv_buffs + rfdadd); i++) {
- writew(make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd)),
- &rfd[i].next);
- writew(0xffff, &rfd[i].rbd_offset);
- }
- /* RU suspend */
- writeb(RFD_SUSP, &rfd[p->num_recv_buffs-1+rfdadd].last);
-
- ptr = rfd + (p->num_recv_buffs + rfdadd);
-
- rbd = ptr;
- ptr = rbd + p->num_recv_buffs;
-
- /* clr descriptors */
- memset_io(rbd, 0, sizeof(struct rbd_struct) * (p->num_recv_buffs));
-
- for (i = 0; i < p->num_recv_buffs; i++) {
- writew(make16(rbd + (i+1) % p->num_recv_buffs), &rbd[i].next);
- writew(RECV_BUFF_SIZE, &rbd[i].size);
- writel(make24(ptr), &rbd[i].buffer);
- ptr = ptr + RECV_BUFF_SIZE;
- }
- p->rfd_top = p->rfd_first;
- p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
-
- writew(make16(p->rfd_first), &p->scb->rfa_offset);
- writew(make16(rbd), &p->rfd_first->rbd_offset);
-
- return ptr;
-}
-
-
-/**************************************************
- * Interrupt Handler ...
- */
-
-static irqreturn_t ni52_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- unsigned int stat;
- int cnt = 0;
- struct priv *p;
-
- p = netdev_priv(dev);
-
- if (debuglevel > 1)
- printk("I");
-
- spin_lock(&p->spinlock);
-
- wait_for_scb_cmd(dev); /* wait for last command */
-
- while ((stat = readb(&p->scb->cus) & STAT_MASK)) {
- writeb(stat, &p->scb->cmd_cuc);
- ni_attn586();
-
- if (stat & STAT_FR) /* received a frame */
- ni52_rcv_int(dev);
-
- if (stat & STAT_RNR) { /* RU went 'not ready' */
- printk("(R)");
- if (readb(&p->scb->rus) & RU_SUSPEND) {
- /* special case: RU_SUSPEND */
- wait_for_scb_cmd(dev);
- writeb(RUC_RESUME, &p->scb->cmd_ruc);
- ni_attn586();
- wait_for_scb_cmd_ruc(dev);
- } else {
- printk(KERN_ERR "%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",
- dev->name, stat, readb(&p->scb->rus));
- ni52_rnr_int(dev);
- }
- }
-
- /* Command with I-bit set complete */
- if (stat & STAT_CX)
- ni52_xmt_int(dev);
-
-#ifndef NO_NOPCOMMANDS
- if (stat & STAT_CNA) { /* CU went 'not ready' */
- if (netif_running(dev))
- printk(KERN_ERR "%s: oops! CU has left active state. stat: %04x/%02x.\n",
- dev->name, stat, readb(&p->scb->cus));
- }
-#endif
-
- if (debuglevel > 1)
- printk("%d", cnt++);
-
- /* Wait for ack. (ni52_xmt_int can be faster than ack!!) */
- wait_for_scb_cmd(dev);
- if (readb(&p->scb->cmd_cuc)) { /* timed out? */
- printk(KERN_ERR "%s: Acknowledge timed out.\n",
- dev->name);
- ni_disint();
- break;
- }
- }
- spin_unlock(&p->spinlock);
-
- if (debuglevel > 1)
- printk("i");
- return IRQ_HANDLED;
-}
-
-/*******************************************************
- * receive-interrupt
- */
-
-static void ni52_rcv_int(struct net_device *dev)
-{
- int status, cnt = 0;
- unsigned short totlen;
- struct sk_buff *skb;
- struct rbd_struct __iomem *rbd;
- struct priv *p = netdev_priv(dev);
-
- if (debuglevel > 0)
- printk("R");
-
- for (; (status = readb(&p->rfd_top->stat_high)) & RFD_COMPL;) {
- rbd = make32(readw(&p->rfd_top->rbd_offset));
- if (status & RFD_OK) { /* frame received without error? */
- totlen = readw(&rbd->status);
- if (totlen & RBD_LAST) {
- /* the first and the last buffer? */
- totlen &= RBD_MASK; /* length of this frame */
- writew(0x00, &rbd->status);
- skb = netdev_alloc_skb(dev, totlen + 2);
- if (skb != NULL) {
- skb_reserve(skb, 2);
- skb_put(skb, totlen);
- memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen);
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += totlen;
- } else
- dev->stats.rx_dropped++;
- } else {
- int rstat;
- /* free all RBD's until RBD_LAST is set */
- totlen = 0;
- while (!((rstat = readw(&rbd->status)) & RBD_LAST)) {
- totlen += rstat & RBD_MASK;
- if (!rstat) {
- printk(KERN_ERR "%s: Whoops .. no end mark in RBD list\n", dev->name);
- break;
- }
- writew(0, &rbd->status);
- rbd = make32(readw(&rbd->next));
- }
- totlen += rstat & RBD_MASK;
- writew(0, &rbd->status);
- printk(KERN_ERR "%s: received oversized frame! length: %d\n",
- dev->name, totlen);
- dev->stats.rx_dropped++;
- }
- } else {/* frame !(ok), only with 'save-bad-frames' */
- printk(KERN_ERR "%s: oops! rfd-error-status: %04x\n",
- dev->name, status);
- dev->stats.rx_errors++;
- }
- writeb(0, &p->rfd_top->stat_high);
- writeb(RFD_SUSP, &p->rfd_top->last); /* maybe exchange by RFD_LAST */
- writew(0xffff, &p->rfd_top->rbd_offset);
- writeb(0, &p->rfd_last->last); /* delete RFD_SUSP */
- p->rfd_last = p->rfd_top;
- p->rfd_top = make32(readw(&p->rfd_top->next)); /* step to next RFD */
- writew(make16(p->rfd_top), &p->scb->rfa_offset);
-
- if (debuglevel > 0)
- printk("%d", cnt++);
- }
-
- if (automatic_resume) {
- wait_for_scb_cmd(dev);
- writeb(RUC_RESUME, &p->scb->cmd_ruc);
- ni_attn586();
- wait_for_scb_cmd_ruc(dev);
- }
-
-#ifdef WAIT_4_BUSY
- {
- int i;
- for (i = 0; i < 1024; i++) {
- if (p->rfd_top->status)
- break;
- udelay(16);
- if (i == 1023)
- printk(KERN_ERR "%s: RU hasn't fetched next RFD (not busy/complete)\n", dev->name);
- }
- }
-#endif
- if (debuglevel > 0)
- printk("r");
-}
-
-/**********************************************************
- * handle 'Receiver went not ready'.
- */
-
-static void ni52_rnr_int(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- dev->stats.rx_errors++;
-
- wait_for_scb_cmd(dev); /* wait for the last cmd, WAIT_4_FULLSTAT?? */
- writeb(RUC_ABORT, &p->scb->cmd_ruc); /* usually the RU is in the 'no resource'-state .. abort it now. */
- ni_attn586();
- wait_for_scb_cmd_ruc(dev); /* wait for accept cmd. */
-
- alloc_rfa(dev, p->rfd_first);
- /* maybe add a check here, before restarting the RU */
- startrecv586(dev); /* restart RU */
-
- printk(KERN_ERR "%s: Receive-Unit restarted. Status: %04x\n",
- dev->name, readb(&p->scb->rus));
-
-}
-
-/**********************************************************
- * handle xmit - interrupt
- */
-
-static void ni52_xmt_int(struct net_device *dev)
-{
- int status;
- struct priv *p = netdev_priv(dev);
-
- if (debuglevel > 0)
- printk("X");
-
- status = readw(&p->xmit_cmds[p->xmit_last]->cmd_status);
- if (!(status & STAT_COMPL))
- printk(KERN_ERR "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
-
- if (status & STAT_OK) {
- dev->stats.tx_packets++;
- dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
- } else {
- dev->stats.tx_errors++;
- if (status & TCMD_LATECOLL) {
- printk(KERN_ERR "%s: late collision detected.\n",
- dev->name);
- dev->stats.collisions++;
- } else if (status & TCMD_NOCARRIER) {
- dev->stats.tx_carrier_errors++;
- printk(KERN_ERR "%s: no carrier detected.\n",
- dev->name);
- } else if (status & TCMD_LOSTCTS)
- printk(KERN_ERR "%s: loss of CTS detected.\n",
- dev->name);
- else if (status & TCMD_UNDERRUN) {
- dev->stats.tx_fifo_errors++;
- printk(KERN_ERR "%s: DMA underrun detected.\n",
- dev->name);
- } else if (status & TCMD_MAXCOLL) {
- printk(KERN_ERR "%s: Max. collisions exceeded.\n",
- dev->name);
- dev->stats.collisions += 16;
- }
- }
-#if (NUM_XMIT_BUFFS > 1)
- if ((++p->xmit_last) == NUM_XMIT_BUFFS)
- p->xmit_last = 0;
-#endif
- netif_wake_queue(dev);
-}
-
-/***********************************************************
- * (re)start the receiver
- */
-
-static void startrecv586(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-
- wait_for_scb_cmd(dev);
- wait_for_scb_cmd_ruc(dev);
- writew(make16(p->rfd_first), &p->scb->rfa_offset);
- writeb(RUC_START, &p->scb->cmd_ruc);
- ni_attn586(); /* start cmd. */
- wait_for_scb_cmd_ruc(dev);
- /* wait for accept cmd. (no timeout!!) */
-}
-
-static void ni52_timeout(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
-#ifndef NO_NOPCOMMANDS
- if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */
- netif_wake_queue(dev);
-#ifdef DEBUG
- printk(KERN_ERR "%s: strange ... timeout with CU active?!?\n",
- dev->name);
- printk(KERN_ERR "%s: X0: %04x N0: %04x N1: %04x %d\n",
- dev->name, (int)p->xmit_cmds[0]->cmd_status,
- readw(&p->nop_cmds[0]->cmd_status),
- readw(&p->nop_cmds[1]->cmd_status),
- p->nop_point);
-#endif
- writeb(CUC_ABORT, &p->scb->cmd_cuc);
- ni_attn586();
- wait_for_scb_cmd(dev);
- writew(make16(p->nop_cmds[p->nop_point]), &p->scb->cbl_offset);
- writeb(CUC_START, &p->scb->cmd_cuc);
- ni_attn586();
- wait_for_scb_cmd(dev);
- dev->trans_start = jiffies; /* prevent tx timeout */
- return 0;
- }
-#endif
- {
-#ifdef DEBUG
- printk(KERN_ERR "%s: xmitter timed out, try to restart! stat: %02x\n",
- dev->name, readb(&p->scb->cus));
- printk(KERN_ERR "%s: command-stats: %04x %04x\n",
- dev->name,
- readw(&p->xmit_cmds[0]->cmd_status),
- readw(&p->xmit_cmds[1]->cmd_status));
- printk(KERN_ERR "%s: check, whether you set the right interrupt number!\n",
- dev->name);
-#endif
- ni52_close(dev);
- ni52_open(dev);
- }
- dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
-/******************************************************
- * send frame
- */
-
-static netdev_tx_t ni52_send_packet(struct sk_buff *skb,
- struct net_device *dev)
-{
- int len, i;
-#ifndef NO_NOPCOMMANDS
- int next_nop;
-#endif
- struct priv *p = netdev_priv(dev);
-
- if (skb->len > XMIT_BUFF_SIZE) {
- printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
- return NETDEV_TX_OK;
- }
-
- netif_stop_queue(dev);
-
- memcpy_toio(p->xmit_cbuffs[p->xmit_count], skb->data, skb->len);
- len = skb->len;
- if (len < ETH_ZLEN) {
- len = ETH_ZLEN;
- memset_io(p->xmit_cbuffs[p->xmit_count]+skb->len, 0,
- len - skb->len);
- }
-
-#if (NUM_XMIT_BUFFS == 1)
-# ifdef NO_NOPCOMMANDS
-
-#ifdef DEBUG
- if (readb(&p->scb->cus) & CU_ACTIVE) {
- printk(KERN_ERR "%s: Hmmm .. CU is still running and we wanna send a new packet.\n", dev->name);
- printk(KERN_ERR "%s: stat: %04x %04x\n",
- dev->name, readb(&p->scb->cus),
- readw(&p->xmit_cmds[0]->cmd_status));
- }
-#endif
- writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
- for (i = 0; i < 16; i++) {
- writew(0, &p->xmit_cmds[0]->cmd_status);
- wait_for_scb_cmd(dev);
- if ((readb(&p->scb->cus) & CU_STATUS) == CU_SUSPEND)
- writeb(CUC_RESUME, &p->scb->cmd_cuc);
- else {
- writew(make16(p->xmit_cmds[0]), &p->scb->cbl_offset);
- writeb(CUC_START, &p->scb->cmd_cuc);
- }
- ni_attn586();
- if (!i)
- dev_kfree_skb(skb);
- wait_for_scb_cmd(dev);
- /* test it, because CU sometimes doesn't start immediately */
- if (readb(&p->scb->cus) & CU_ACTIVE)
- break;
- if (readw(&p->xmit_cmds[0]->cmd_status))
- break;
- if (i == 15)
- printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name);
- }
-# else
- next_nop = (p->nop_point + 1) & 0x1;
- writew(TBD_LAST | len, &p->xmit_buffs[0]->size);
- writew(make16(p->nop_cmds[next_nop]), &p->xmit_cmds[0]->cmd_link);
- writew(make16(p->nop_cmds[next_nop]),
- &p->nop_cmds[next_nop]->cmd_link);
- writew(0, &p->xmit_cmds[0]->cmd_status);
- writew(0, &p->nop_cmds[next_nop]->cmd_status);
-
- writew(make16(p->xmit_cmds[0]), &p->nop_cmds[p->nop_point]->cmd_link);
- p->nop_point = next_nop;
- dev_kfree_skb(skb);
-# endif
-#else
- writew(TBD_LAST | len, &p->xmit_buffs[p->xmit_count]->size);
- next_nop = p->xmit_count + 1
- if (next_nop == NUM_XMIT_BUFFS)
- next_nop = 0;
- writew(0, &p->xmit_cmds[p->xmit_count]->cmd_status);
- /* linkpointer of xmit-command already points to next nop cmd */
- writew(make16(p->nop_cmds[next_nop]),
- &p->nop_cmds[next_nop]->cmd_link);
- writew(0, &p->nop_cmds[next_nop]->cmd_status);
- writew(make16(p->xmit_cmds[p->xmit_count]),
- &p->nop_cmds[p->xmit_count]->cmd_link);
- p->xmit_count = next_nop;
- {
- unsigned long flags;
- spin_lock_irqsave(&p->spinlock);
- if (p->xmit_count != p->xmit_last)
- netif_wake_queue(dev);
- spin_unlock_irqrestore(&p->spinlock);
- }
- dev_kfree_skb(skb);
-#endif
- return NETDEV_TX_OK;
-}
-
-/*******************************************
- * Someone wanna have the statistics
- */
-
-static struct net_device_stats *ni52_get_stats(struct net_device *dev)
-{
- struct priv *p = netdev_priv(dev);
- unsigned short crc, aln, rsc, ovrn;
-
- /* Get error-statistics from the ni82586 */
- crc = readw(&p->scb->crc_errs);
- writew(0, &p->scb->crc_errs);
- aln = readw(&p->scb->aln_errs);
- writew(0, &p->scb->aln_errs);
- rsc = readw(&p->scb->rsc_errs);
- writew(0, &p->scb->rsc_errs);
- ovrn = readw(&p->scb->ovrn_errs);
- writew(0, &p->scb->ovrn_errs);
-
- dev->stats.rx_crc_errors += crc;
- dev->stats.rx_fifo_errors += ovrn;
- dev->stats.rx_frame_errors += aln;
- dev->stats.rx_dropped += rsc;
-
- return &dev->stats;
-}
-
-/********************************************************
- * Set MC list ..
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
- netif_stop_queue(dev);
- ni_disint();
- alloc586(dev);
- init586(dev);
- startrecv586(dev);
- ni_enaint();
- netif_wake_queue(dev);
-}
-
-#ifdef MODULE
-static struct net_device *dev_ni52;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(memstart, long, 0);
-module_param(memend, long, 0);
-MODULE_PARM_DESC(io, "NI5210 I/O base address,required");
-MODULE_PARM_DESC(irq, "NI5210 IRQ number,required");
-MODULE_PARM_DESC(memstart, "NI5210 memory base address,required");
-MODULE_PARM_DESC(memend, "NI5210 memory end address,required");
-
-int __init init_module(void)
-{
- if (io <= 0x0 || !memend || !memstart || irq < 2) {
- printk(KERN_ERR "ni52: Autoprobing not allowed for modules.\n");
- printk(KERN_ERR "ni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
- return -ENODEV;
- }
- dev_ni52 = ni52_probe(-1);
- if (IS_ERR(dev_ni52))
- return PTR_ERR(dev_ni52);
- return 0;
-}
-
-void __exit cleanup_module(void)
-{
- struct priv *p = netdev_priv(dev_ni52);
- unregister_netdev(dev_ni52);
- iounmap(p->mapped);
- release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE);
- free_netdev(dev_ni52);
-}
-#endif /* MODULE */
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/i825xx/ni52.h b/drivers/net/ethernet/i825xx/ni52.h
deleted file mode 100644
index 0a03b2883327..000000000000
--- a/drivers/net/ethernet/i825xx/ni52.h
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Intel i82586 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
- *
- * I have done a look in the following sources:
- * crynwr-packet-driver by Russ Nelson
- * Garret A. Wollman's i82586-driver for BSD
- */
-
-
-#define NI52_RESET 0 /* writing to this address, resets the i82586 */
-#define NI52_ATTENTION 1 /* channel attention, kick the 586 */
-#define NI52_TENA 3 /* 2-5 possibly wrong, Xmit enable */
-#define NI52_TDIS 2 /* Xmit disable */
-#define NI52_INTENA 5 /* Interrupt enable */
-#define NI52_INTDIS 4 /* Interrupt disable */
-#define NI52_MAGIC1 6 /* dunno exact function */
-#define NI52_MAGIC2 7 /* dunno exact function */
-
-#define NI52_MAGICVAL1 0x00 /* magic-values for ni5210 card */
-#define NI52_MAGICVAL2 0x55
-
-/*
- * where to find the System Configuration Pointer (SCP)
- */
-#define SCP_DEFAULT_ADDRESS 0xfffff4
-
-
-/*
- * System Configuration Pointer Struct
- */
-
-struct scp_struct
-{
- u16 zero_dum0; /* has to be zero */
- u8 sysbus; /* 0=16Bit,1=8Bit */
- u8 zero_dum1; /* has to be zero for 586 */
- u16 zero_dum2;
- u16 zero_dum3;
- u32 iscp; /* pointer to the iscp-block */
-};
-
-
-/*
- * Intermediate System Configuration Pointer (ISCP)
- */
-struct iscp_struct
-{
- u8 busy; /* 586 clears after successful init */
- u8 zero_dummy; /* has to be zero */
- u16 scb_offset; /* pointeroffset to the scb_base */
- u32 scb_base; /* base-address of all 16-bit offsets */
-};
-
-/*
- * System Control Block (SCB)
- */
-struct scb_struct
-{
- u8 rus;
- u8 cus;
- u8 cmd_ruc; /* command word: RU part */
- u8 cmd_cuc; /* command word: CU part & ACK */
- u16 cbl_offset; /* pointeroffset, command block list */
- u16 rfa_offset; /* pointeroffset, receive frame area */
- u16 crc_errs; /* CRC-Error counter */
- u16 aln_errs; /* alignmenterror counter */
- u16 rsc_errs; /* Resourceerror counter */
- u16 ovrn_errs; /* OVerrunerror counter */
-};
-
-/*
- * possible command values for the command word
- */
-#define RUC_MASK 0x0070 /* mask for RU commands */
-#define RUC_NOP 0x0000 /* NOP-command */
-#define RUC_START 0x0010 /* start RU */
-#define RUC_RESUME 0x0020 /* resume RU after suspend */
-#define RUC_SUSPEND 0x0030 /* suspend RU */
-#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
-
-#define CUC_MASK 0x07 /* mask for CU command */
-#define CUC_NOP 0x00 /* NOP-command */
-#define CUC_START 0x01 /* start execution of 1. cmd on the CBL */
-#define CUC_RESUME 0x02 /* resume after suspend */
-#define CUC_SUSPEND 0x03 /* Suspend CU */
-#define CUC_ABORT 0x04 /* abort command operation immediately */
-
-#define ACK_MASK 0xf0 /* mask for ACK command */
-#define ACK_CX 0x80 /* acknowledges STAT_CX */
-#define ACK_FR 0x40 /* ack. STAT_FR */
-#define ACK_CNA 0x20 /* ack. STAT_CNA */
-#define ACK_RNR 0x10 /* ack. STAT_RNR */
-
-/*
- * possible status values for the status word
- */
-#define STAT_MASK 0xf0 /* mask for cause of interrupt */
-#define STAT_CX 0x80 /* CU finished cmd with its I bit set */
-#define STAT_FR 0x40 /* RU finished receiving a frame */
-#define STAT_CNA 0x20 /* CU left active state */
-#define STAT_RNR 0x10 /* RU left ready state */
-
-#define CU_STATUS 0x7 /* CU status, 0=idle */
-#define CU_SUSPEND 0x1 /* CU is suspended */
-#define CU_ACTIVE 0x2 /* CU is active */
-
-#define RU_STATUS 0x70 /* RU status, 0=idle */
-#define RU_SUSPEND 0x10 /* RU suspended */
-#define RU_NOSPACE 0x20 /* RU no resources */
-#define RU_READY 0x40 /* RU is ready */
-
-/*
- * Receive Frame Descriptor (RFD)
- */
-struct rfd_struct
-{
- u8 stat_low; /* status word */
- u8 stat_high; /* status word */
- u8 rfd_sf; /* 82596 mode only */
- u8 last; /* Bit15,Last Frame on List / Bit14,suspend */
- u16 next; /* linkoffset to next RFD */
- u16 rbd_offset; /* pointeroffset to RBD-buffer */
- u8 dest[6]; /* ethernet-address, destination */
- u8 source[6]; /* ethernet-address, source */
- u16 length; /* 802.3 frame-length */
- u16 zero_dummy; /* dummy */
-};
-
-#define RFD_LAST 0x80 /* last: last rfd in the list */
-#define RFD_SUSP 0x40 /* last: suspend RU after */
-#define RFD_COMPL 0x80
-#define RFD_OK 0x20
-#define RFD_BUSY 0x40
-#define RFD_ERR_LEN 0x10 /* Length error (if enabled length-checking */
-#define RFD_ERR_CRC 0x08 /* CRC error */
-#define RFD_ERR_ALGN 0x04 /* Alignment error */
-#define RFD_ERR_RNR 0x02 /* status: receiver out of resources */
-#define RFD_ERR_OVR 0x01 /* DMA Overrun! */
-
-#define RFD_ERR_FTS 0x0080 /* Frame to short */
-#define RFD_ERR_NEOP 0x0040 /* No EOP flag (for bitstuffing only) */
-#define RFD_ERR_TRUN 0x0020 /* (82596 only/SF mode) indicates truncated frame */
-#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA (only 82596) */
-#define RFD_COLLDET 0x0001 /* Detected collision during reception */
-
-/*
- * Receive Buffer Descriptor (RBD)
- */
-struct rbd_struct
-{
- u16 status; /* status word,number of used bytes in buff */
- u16 next; /* pointeroffset to next RBD */
- u32 buffer; /* receive buffer address pointer */
- u16 size; /* size of this buffer */
- u16 zero_dummy; /* dummy */
-};
-
-#define RBD_LAST 0x8000 /* last buffer */
-#define RBD_USED 0x4000 /* this buffer has data */
-#define RBD_MASK 0x3fff /* size-mask for length */
-
-/*
- * Statusvalues for Commands/RFD
- */
-#define STAT_COMPL 0x8000 /* status: frame/command is complete */
-#define STAT_BUSY 0x4000 /* status: frame/command is busy */
-#define STAT_OK 0x2000 /* status: frame/command is ok */
-
-/*
- * Action-Commands
- */
-#define CMD_NOP 0x0000 /* NOP */
-#define CMD_IASETUP 0x0001 /* initial address setup command */
-#define CMD_CONFIGURE 0x0002 /* configure command */
-#define CMD_MCSETUP 0x0003 /* MC setup command */
-#define CMD_XMIT 0x0004 /* transmit command */
-#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
-#define CMD_DUMP 0x0006 /* dump command */
-#define CMD_DIAGNOSE 0x0007 /* diagnose command */
-
-/*
- * Action command bits
- */
-#define CMD_LAST 0x8000 /* indicates last command in the CBL */
-#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
-#define CMD_INT 0x2000 /* generate interrupt after execution */
-
-/*
- * NOP - command
- */
-struct nop_cmd_struct
-{
- u16 cmd_status; /* status of this command */
- u16 cmd_cmd; /* the command itself (+bits) */
- u16 cmd_link; /* offsetpointer to next command */
-};
-
-/*
- * IA Setup command
- */
-struct iasetup_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u8 iaddr[6];
-};
-
-/*
- * Configure command
- */
-struct configure_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u8 byte_cnt; /* size of the config-cmd */
- u8 fifo; /* fifo/recv monitor */
- u8 sav_bf; /* save bad frames (bit7=1)*/
- u8 adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
- u8 priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
- u8 ifs; /* inter frame spacing */
- u8 time_low; /* slot time low */
- u8 time_high; /* slot time high(0-2) and max. retries(4-7) */
- u8 promisc; /* promisc-mode(0) , et al (1-7) */
- u8 carr_coll; /* carrier(0-3)/collision(4-7) stuff */
- u8 fram_len; /* minimal frame len */
- u8 dummy; /* dummy */
-};
-
-/*
- * Multicast Setup command
- */
-struct mcsetup_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u16 mc_cnt; /* number of bytes in the MC-List */
- u8 mc_list[0][6]; /* pointer to 6 bytes entries */
-};
-
-/*
- * DUMP command
- */
-struct dump_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u16 dump_offset; /* pointeroffset to DUMP space */
-};
-
-/*
- * transmit command
- */
-struct transmit_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u16 tbd_offset; /* pointeroffset to TBD */
- u8 dest[6]; /* destination address of the frame */
- u16 length; /* user defined: 802.3 length / Ether type */
-};
-
-#define TCMD_ERRMASK 0x0fa0
-#define TCMD_MAXCOLLMASK 0x000f
-#define TCMD_MAXCOLL 0x0020
-#define TCMD_HEARTBEAT 0x0040
-#define TCMD_DEFERRED 0x0080
-#define TCMD_UNDERRUN 0x0100
-#define TCMD_LOSTCTS 0x0200
-#define TCMD_NOCARRIER 0x0400
-#define TCMD_LATECOLL 0x0800
-
-struct tdr_cmd_struct
-{
- u16 cmd_status;
- u16 cmd_cmd;
- u16 cmd_link;
- u16 status;
-};
-
-#define TDR_LNK_OK 0x8000 /* No link problem identified */
-#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
-#define TDR_ET_OPN 0x2000 /* open, no correct termination */
-#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
-#define TDR_TIMEMASK 0x07ff /* mask for the time field */
-
-/*
- * Transmit Buffer Descriptor (TBD)
- */
-struct tbd_struct
-{
- u16 size; /* size + EOF-Flag(15) */
- u16 next; /* pointeroffset to next TBD */
- u32 buffer; /* pointer to buffer */
-};
-
-#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
-
-
-
-
diff --git a/drivers/net/ethernet/i825xx/znet.c b/drivers/net/ethernet/i825xx/znet.c
deleted file mode 100644
index c9479e081b8a..000000000000
--- a/drivers/net/ethernet/i825xx/znet.c
+++ /dev/null
@@ -1,928 +0,0 @@
-/* znet.c: An Zenith Z-Note ethernet driver for linux. */
-
-/*
- Written by Donald Becker.
-
- The author may be reached as becker@scyld.com.
- This driver is based on the Linux skeleton driver. The copyright of the
- skeleton driver is held by the United States Government, as represented
- by DIRNSA, and it is released under the GPL.
-
- Thanks to Mike Hollick for alpha testing and suggestions.
-
- References:
- The Crynwr packet driver.
-
- "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992
- Intel Microcommunications Databook, Vol. 1, 1990.
- As usual with Intel, the documentation is incomplete and inaccurate.
- I had to read the Crynwr packet driver to figure out how to actually
- use the i82593, and guess at what register bits matched the loosely
- related i82586.
-
- Theory of Operation
-
- The i82593 used in the Zenith Z-Note series operates using two(!) slave
- DMA channels, one interrupt, and one 8-bit I/O port.
-
- While there several ways to configure '593 DMA system, I chose the one
- that seemed commensurate with the highest system performance in the face
- of moderate interrupt latency: Both DMA channels are configured as
- recirculating ring buffers, with one channel (#0) dedicated to Rx and
- the other channel (#1) to Tx and configuration. (Note that this is
- different than the Crynwr driver, where the Tx DMA channel is initialized
- before each operation. That approach simplifies operation and Tx error
- recovery, but requires additional I/O in normal operation and precludes
- transmit buffer chaining.)
-
- Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE. This provides
- a reasonable ring size for Rx, while simplifying DMA buffer allocation --
- DMA buffers must not cross a 128K boundary. (In truth the size selection
- was influenced by my lack of '593 documentation. I thus was constrained
- to use the Crynwr '593 initialization table, which sets the Rx ring size
- to 8K.)
-
- Despite my usual low opinion about Intel-designed parts, I must admit
- that the bulk data handling of the i82593 is a good design for
- an integrated system, like a laptop, where using two slave DMA channels
- doesn't pose a problem. I still take issue with using only a single I/O
- port. In the same controlled environment there are essentially no
- limitations on I/O space, and using multiple locations would eliminate
- the need for multiple operations when looking at status registers,
- setting the Rx ring boundary, or switching to promiscuous mode.
-
- I also question Zenith's selection of the '593: one of the advertised
- advantages of earlier Intel parts was that if you figured out the magic
- initialization incantation you could use the same part on many different
- network types. Zenith's use of the "FriendlyNet" (sic) connector rather
- than an on-board transceiver leads me to believe that they were planning
- to take advantage of this. But, uhmmm, the '593 omits all but ethernet
- functionality from the serial subsystem.
- */
-
-/* 10/2002
-
- o Resurected for Linux 2.5+ by Marc Zyngier <maz@wild-wind.fr.eu.org> :
-
- - Removed strange DMA snooping in znet_sent_packet, which lead to
- TX buffer corruption on my laptop.
- - Use init_etherdev stuff.
- - Use kmalloc-ed DMA buffers.
- - Use as few global variables as possible.
- - Use proper resources management.
- - Use wireless/i82593.h as much as possible (structure, constants)
- - Compiles as module or build-in.
- - Now survives unplugging/replugging cable.
-
- Some code was taken from wavelan_cs.
-
- Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
- anything else. Testers (and detailed bug reports) are welcome :-).
-
- o TODO :
-
- - Properly handle multicast
- - Understand why some traffic patterns add a 1s latency...
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/i82593.h>
-
-static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n";
-
-#ifndef ZNET_DEBUG
-#define ZNET_DEBUG 1
-#endif
-static unsigned int znet_debug = ZNET_DEBUG;
-module_param (znet_debug, int, 0);
-MODULE_PARM_DESC (znet_debug, "ZNet debug level");
-MODULE_LICENSE("GPL");
-
-/* The DMA modes we need aren't in <dma.h>. */
-#define DMA_RX_MODE 0x14 /* Auto init, I/O to mem, ++, demand. */
-#define DMA_TX_MODE 0x18 /* Auto init, Mem to I/O, ++, demand. */
-#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
-#define RX_BUF_SIZE 8192
-#define TX_BUF_SIZE 8192
-#define DMA_BUF_SIZE (RX_BUF_SIZE + 16) /* 8k + 16 bytes for trailers */
-
-#define TX_TIMEOUT (HZ/10)
-
-struct znet_private {
- int rx_dma, tx_dma;
- spinlock_t lock;
- short sia_base, sia_size, io_size;
- struct i82593_conf_block i593_init;
- /* The starting, current, and end pointers for the packet buffers. */
- ushort *rx_start, *rx_cur, *rx_end;
- ushort *tx_start, *tx_cur, *tx_end;
- ushort tx_buf_len; /* Tx buffer length, in words. */
-};
-
-/* Only one can be built-in;-> */
-static struct net_device *znet_dev;
-
-#define NETIDBLK_MAGIC "NETIDBLK"
-#define NETIDBLK_MAGIC_SIZE 8
-
-struct netidblk {
- char magic[NETIDBLK_MAGIC_SIZE]; /* The magic number (string) "NETIDBLK" */
- unsigned char netid[8]; /* The physical station address */
- char nettype, globalopt;
- char vendor[8]; /* The machine vendor and product name. */
- char product[8];
- char irq1, irq2; /* Interrupts, only one is currently used. */
- char dma1, dma2;
- short dma_mem_misc[8]; /* DMA buffer locations (unused in Linux). */
- short iobase1, iosize1;
- short iobase2, iosize2; /* Second iobase unused. */
- char driver_options; /* Misc. bits */
- char pad;
-};
-
-static int znet_open(struct net_device *dev);
-static netdev_tx_t znet_send_packet(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t znet_interrupt(int irq, void *dev_id);
-static void znet_rx(struct net_device *dev);
-static int znet_close(struct net_device *dev);
-static void hardware_init(struct net_device *dev);
-static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
-static void znet_tx_timeout (struct net_device *dev);
-
-/* Request needed resources */
-static int znet_request_resources (struct net_device *dev)
-{
- struct znet_private *znet = netdev_priv(dev);
-
- if (request_irq (dev->irq, znet_interrupt, 0, "ZNet", dev))
- goto failed;
- if (request_dma (znet->rx_dma, "ZNet rx"))
- goto free_irq;
- if (request_dma (znet->tx_dma, "ZNet tx"))
- goto free_rx_dma;
- if (!request_region (znet->sia_base, znet->sia_size, "ZNet SIA"))
- goto free_tx_dma;
- if (!request_region (dev->base_addr, znet->io_size, "ZNet I/O"))
- goto free_sia;
-
- return 0; /* Happy ! */
-
- free_sia:
- release_region (znet->sia_base, znet->sia_size);
- free_tx_dma:
- free_dma (znet->tx_dma);
- free_rx_dma:
- free_dma (znet->rx_dma);
- free_irq:
- free_irq (dev->irq, dev);
- failed:
- return -1;
-}
-
-static void znet_release_resources (struct net_device *dev)
-{
- struct znet_private *znet = netdev_priv(dev);
-
- release_region (znet->sia_base, znet->sia_size);
- release_region (dev->base_addr, znet->io_size);
- free_dma (znet->tx_dma);
- free_dma (znet->rx_dma);
- free_irq (dev->irq, dev);
-}
-
-/* Keep the magical SIA stuff in a single function... */
-static void znet_transceiver_power (struct net_device *dev, int on)
-{
- struct znet_private *znet = netdev_priv(dev);
- unsigned char v;
-
- /* Turn on/off the 82501 SIA, using zenith-specific magic. */
- /* Select LAN control register */
- outb(0x10, znet->sia_base);
-
- if (on)
- v = inb(znet->sia_base + 1) | 0x84;
- else
- v = inb(znet->sia_base + 1) & ~0x84;
-
- outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */
-}
-
-/* Init the i82593, with current promisc/mcast configuration.
- Also used from hardware_init. */
-static void znet_set_multicast_list (struct net_device *dev)
-{
- struct znet_private *znet = netdev_priv(dev);
- short ioaddr = dev->base_addr;
- struct i82593_conf_block *cfblk = &znet->i593_init;
-
- memset(cfblk, 0x00, sizeof(struct i82593_conf_block));
-
- /* The configuration block. What an undocumented nightmare.
- The first set of values are those suggested (without explanation)
- for ethernet in the Intel 82586 databook. The rest appear to be
- completely undocumented, except for cryptic notes in the Crynwr
- packet driver. This driver uses the Crynwr values verbatim. */
-
- /* maz : Rewritten to take advantage of the wanvelan includes.
- At least we have names, not just blind values */
-
- /* Byte 0 */
- cfblk->fifo_limit = 10; /* = 16 B rx and 80 B tx fifo thresholds */
- cfblk->forgnesi = 0; /* 0=82C501, 1=AMD7992B compatibility */
- cfblk->fifo_32 = 1;
- cfblk->d6mod = 0; /* Run in i82593 advanced mode */
- cfblk->throttle_enb = 1;
-
- /* Byte 1 */
- cfblk->throttle = 8; /* Continuous w/interrupts, 128-clock DMA. */
- cfblk->cntrxint = 0; /* enable continuous mode receive interrupts */
- cfblk->contin = 1; /* enable continuous mode */
-
- /* Byte 2 */
- cfblk->addr_len = ETH_ALEN;
- cfblk->acloc = 1; /* Disable source addr insertion by i82593 */
- cfblk->preamb_len = 2; /* 8 bytes preamble */
- cfblk->loopback = 0; /* Loopback off */
-
- /* Byte 3 */
- cfblk->lin_prio = 0; /* Default priorities & backoff methods. */
- cfblk->tbofstop = 0;
- cfblk->exp_prio = 0;
- cfblk->bof_met = 0;
-
- /* Byte 4 */
- cfblk->ifrm_spc = 6; /* 96 bit times interframe spacing */
-
- /* Byte 5 */
- cfblk->slottim_low = 0; /* 512 bit times slot time (low) */
-
- /* Byte 6 */
- cfblk->slottim_hi = 2; /* 512 bit times slot time (high) */
- cfblk->max_retr = 15; /* 15 collisions retries */
-
- /* Byte 7 */
- cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */
- cfblk->bc_dis = 0; /* Enable broadcast reception */
- cfblk->crs_1 = 0; /* Don't transmit without carrier sense */
- cfblk->nocrc_ins = 0; /* i82593 generates CRC */
- cfblk->crc_1632 = 0; /* 32-bit Autodin-II CRC */
- cfblk->crs_cdt = 0; /* CD not to be interpreted as CS */
-
- /* Byte 8 */
- cfblk->cs_filter = 0; /* CS is recognized immediately */
- cfblk->crs_src = 0; /* External carrier sense */
- cfblk->cd_filter = 0; /* CD is recognized immediately */
-
- /* Byte 9 */
- cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
-
- /* Byte A */
- cfblk->lng_typ = 1; /* Type/length checks OFF */
- cfblk->lng_fld = 1; /* Disable 802.3 length field check */
- cfblk->rxcrc_xf = 1; /* Don't transfer CRC to memory */
- cfblk->artx = 1; /* Disable automatic retransmission */
- cfblk->sarec = 1; /* Disable source addr trig of CD */
- cfblk->tx_jabber = 0; /* Disable jabber jam sequence */
- cfblk->hash_1 = 1; /* Use bits 0-5 in mc address hash */
- cfblk->lbpkpol = 0; /* Loopback pin active high */
-
- /* Byte B */
- cfblk->fdx = 0; /* Disable full duplex operation */
-
- /* Byte C */
- cfblk->dummy_6 = 0x3f; /* all ones, Default multicast addresses & backoff. */
- cfblk->mult_ia = 0; /* No multiple individual addresses */
- cfblk->dis_bof = 0; /* Disable the backoff algorithm ?! */
-
- /* Byte D */
- cfblk->dummy_1 = 1; /* set to 1 */
- cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
- cfblk->mc_all = (!netdev_mc_empty(dev) ||
- (dev->flags & IFF_ALLMULTI)); /* multicast all mode */
- cfblk->rcv_mon = 0; /* Monitor mode disabled */
- cfblk->frag_acpt = 0; /* Do not accept fragments */
- cfblk->tstrttrs = 0; /* No start transmission threshold */
-
- /* Byte E */
- cfblk->fretx = 1; /* FIFO automatic retransmission */
- cfblk->runt_eop = 0; /* drop "runt" packets */
- cfblk->hw_sw_pin = 0; /* ?? */
- cfblk->big_endn = 0; /* Big Endian ? no... */
- cfblk->syncrqs = 1; /* Synchronous DRQ deassertion... */
- cfblk->sttlen = 1; /* 6 byte status registers */
- cfblk->rx_eop = 0; /* Signal EOP on packet reception */
- cfblk->tx_eop = 0; /* Signal EOP on packet transmission */
-
- /* Byte F */
- cfblk->rbuf_size = RX_BUF_SIZE >> 12; /* Set receive buffer size */
- cfblk->rcvstop = 1; /* Enable Receive Stop Register */
-
- if (znet_debug > 2) {
- int i;
- unsigned char *c;
-
- for (i = 0, c = (char *) cfblk; i < sizeof (*cfblk); i++)
- printk ("%02X ", c[i]);
- printk ("\n");
- }
-
- *znet->tx_cur++ = sizeof(struct i82593_conf_block);
- memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block));
- znet->tx_cur += sizeof(struct i82593_conf_block)/2;
- outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
-
- /* XXX FIXME maz : Add multicast addresses here, so having a
- * multicast address configured isn't equal to IFF_ALLMULTI */
-}
-
-static const struct net_device_ops znet_netdev_ops = {
- .ndo_open = znet_open,
- .ndo_stop = znet_close,
- .ndo_start_xmit = znet_send_packet,
- .ndo_set_rx_mode = znet_set_multicast_list,
- .ndo_tx_timeout = znet_tx_timeout,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/* The Z-Note probe is pretty easy. The NETIDBLK exists in the safe-to-probe
- BIOS area. We just scan for the signature, and pull the vital parameters
- out of the structure. */
-
-static int __init znet_probe (void)
-{
- int i;
- struct netidblk *netinfo;
- struct znet_private *znet;
- struct net_device *dev;
- char *p;
- char *plast = phys_to_virt(0x100000 - NETIDBLK_MAGIC_SIZE);
- int err = -ENOMEM;
-
- /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
- for(p = (char *)phys_to_virt(0xf0000); p <= plast; p++)
- if (*p == 'N' &&
- strncmp(p, NETIDBLK_MAGIC, NETIDBLK_MAGIC_SIZE) == 0)
- break;
-
- if (p > plast) {
- if (znet_debug > 1)
- printk(KERN_INFO "No Z-Note ethernet adaptor found.\n");
- return -ENODEV;
- }
-
- dev = alloc_etherdev(sizeof(struct znet_private));
- if (!dev)
- return -ENOMEM;
-
- znet = netdev_priv(dev);
-
- netinfo = (struct netidblk *)p;
- dev->base_addr = netinfo->iobase1;
- dev->irq = netinfo->irq1;
-
- /* The station address is in the "netidblk" at 0x0f0000. */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = netinfo->netid[i];
-
- printk(KERN_INFO "%s: ZNET at %#3lx, %pM"
- ", using IRQ %d DMA %d and %d.\n",
- dev->name, dev->base_addr, dev->dev_addr,
- dev->irq, netinfo->dma1, netinfo->dma2);
-
- if (znet_debug > 1) {
- printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
- dev->name, netinfo->vendor,
- netinfo->irq1, netinfo->irq2,
- netinfo->dma1, netinfo->dma2);
- printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n",
- dev->name, netinfo->iobase1, netinfo->iosize1,
- netinfo->iobase2, netinfo->iosize2, netinfo->nettype);
- }
-
- if (znet_debug > 0)
- printk(KERN_INFO "%s", version);
-
- znet->rx_dma = netinfo->dma1;
- znet->tx_dma = netinfo->dma2;
- spin_lock_init(&znet->lock);
- znet->sia_base = 0xe6; /* Magic address for the 82501 SIA */
- znet->sia_size = 2;
- /* maz: Despite the '593 being advertised above as using a
- * single 8bits I/O port, this driver does many 16bits
- * access. So set io_size accordingly */
- znet->io_size = 2;
-
- if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
- goto free_dev;
- if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA)))
- goto free_rx;
-
- if (!dma_page_eq (znet->rx_start, znet->rx_start + (RX_BUF_SIZE/2-1)) ||
- !dma_page_eq (znet->tx_start, znet->tx_start + (TX_BUF_SIZE/2-1))) {
- printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n");
- goto free_tx;
- }
-
- znet->rx_end = znet->rx_start + RX_BUF_SIZE/2;
- znet->tx_buf_len = TX_BUF_SIZE/2;
- znet->tx_end = znet->tx_start + znet->tx_buf_len;
-
- /* The ZNET-specific entries in the device structure. */
- dev->netdev_ops = &znet_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
- err = register_netdev(dev);
- if (err)
- goto free_tx;
- znet_dev = dev;
- return 0;
-
- free_tx:
- kfree(znet->tx_start);
- free_rx:
- kfree(znet->rx_start);
- free_dev:
- free_netdev(dev);
- return err;
-}
-
-
-static int znet_open(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- if (znet_debug > 2)
- printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name);
-
- /* These should never fail. You can't add devices to a sealed box! */
- if (znet_request_resources (dev)) {
- printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
- return -EBUSY;
- }
-
- znet_transceiver_power (dev, 1);
-
- /* According to the Crynwr driver we should wait 50 msec. for the
- LAN clock to stabilize. My experiments indicates that the '593 can
- be initialized immediately. The delay is probably needed for the
- DC-to-DC converter to come up to full voltage, and for the oscillator
- to be spot-on at 20Mhz before transmitting.
- Until this proves to be a problem we rely on the higher layers for the
- delay and save allocating a timer entry. */
-
- /* maz : Well, I'm getting every time the following message
- * without the delay on a 486@33. This machine is much too
- * fast... :-) So maybe the Crynwr driver wasn't wrong after
- * all, even if the message is completly harmless on my
- * setup. */
- mdelay (50);
-
- /* This follows the packet driver's lead, and checks for success. */
- if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
- printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
- dev->name);
-
- hardware_init(dev);
- netif_start_queue (dev);
-
- return 0;
-}
-
-
-static void znet_tx_timeout (struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- ushort event, tx_status, rx_offset, state;
-
- outb (CR0_STATUS_0, ioaddr);
- event = inb (ioaddr);
- outb (CR0_STATUS_1, ioaddr);
- tx_status = inw (ioaddr);
- outb (CR0_STATUS_2, ioaddr);
- rx_offset = inw (ioaddr);
- outb (CR0_STATUS_3, ioaddr);
- state = inb (ioaddr);
- printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
- " resetting.\n", dev->name, event, tx_status, rx_offset, state);
- if (tx_status == TX_LOST_CRS)
- printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
- dev->name);
- outb (OP0_RESET, ioaddr);
- hardware_init (dev);
- netif_wake_queue (dev);
-}
-
-static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- struct znet_private *znet = netdev_priv(dev);
- unsigned long flags;
- short length = skb->len;
-
- if (znet_debug > 4)
- printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
-
- netif_stop_queue (dev);
-
- /* Check that the part hasn't reset itself, probably from suspend. */
- outb(CR0_STATUS_0, ioaddr);
- if (inw(ioaddr) == 0x0010 &&
- inw(ioaddr) == 0x0000 &&
- inw(ioaddr) == 0x0010) {
- if (znet_debug > 1)
- printk (KERN_WARNING "%s : waking up\n", dev->name);
- hardware_init(dev);
- znet_transceiver_power (dev, 1);
- }
-
- if (1) {
- unsigned char *buf = (void *)skb->data;
- ushort *tx_link = znet->tx_cur - 1;
- ushort rnd_len = (length + 1)>>1;
-
- dev->stats.tx_bytes+=length;
-
- if (znet->tx_cur >= znet->tx_end)
- znet->tx_cur = znet->tx_start;
- *znet->tx_cur++ = length;
- if (znet->tx_cur + rnd_len + 1 > znet->tx_end) {
- int semi_cnt = (znet->tx_end - znet->tx_cur)<<1; /* Cvrt to byte cnt. */
- memcpy(znet->tx_cur, buf, semi_cnt);
- rnd_len -= semi_cnt>>1;
- memcpy(znet->tx_start, buf + semi_cnt, length - semi_cnt);
- znet->tx_cur = znet->tx_start + rnd_len;
- } else {
- memcpy(znet->tx_cur, buf, skb->len);
- znet->tx_cur += rnd_len;
- }
- *znet->tx_cur++ = 0;
-
- spin_lock_irqsave(&znet->lock, flags);
- {
- *tx_link = OP0_TRANSMIT | CR0_CHNL;
- /* Is this always safe to do? */
- outb(OP0_TRANSMIT | CR0_CHNL, ioaddr);
- }
- spin_unlock_irqrestore (&znet->lock, flags);
-
- netif_start_queue (dev);
-
- if (znet_debug > 4)
- printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
- }
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-/* The ZNET interrupt handler. */
-static irqreturn_t znet_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct znet_private *znet = netdev_priv(dev);
- int ioaddr;
- int boguscnt = 20;
- int handled = 0;
-
- spin_lock (&znet->lock);
-
- ioaddr = dev->base_addr;
-
- outb(CR0_STATUS_0, ioaddr);
- do {
- ushort status = inb(ioaddr);
- if (znet_debug > 5) {
- ushort result, rx_ptr, running;
- outb(CR0_STATUS_1, ioaddr);
- result = inw(ioaddr);
- outb(CR0_STATUS_2, ioaddr);
- rx_ptr = inw(ioaddr);
- outb(CR0_STATUS_3, ioaddr);
- running = inb(ioaddr);
- printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",
- dev->name, status, result, rx_ptr, running, boguscnt);
- }
- if ((status & SR0_INTERRUPT) == 0)
- break;
-
- handled = 1;
-
- if ((status & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
- (status & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
- (status & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) {
- int tx_status;
- outb(CR0_STATUS_1, ioaddr);
- tx_status = inw(ioaddr);
- /* It's undocumented, but tx_status seems to match the i82586. */
- if (tx_status & TX_OK) {
- dev->stats.tx_packets++;
- dev->stats.collisions += tx_status & TX_NCOL_MASK;
- } else {
- if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
- dev->stats.tx_carrier_errors++;
- if (tx_status & TX_UND_RUN)
- dev->stats.tx_fifo_errors++;
- if (!(tx_status & TX_HRT_BEAT))
- dev->stats.tx_heartbeat_errors++;
- if (tx_status & TX_MAX_COL)
- dev->stats.tx_aborted_errors++;
- /* ...and the catch-all. */
- if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
- dev->stats.tx_errors++;
-
- /* Transceiver may be stuck if cable
- * was removed while emitting a
- * packet. Flip it off, then on to
- * reset it. This is very empirical,
- * but it seems to work. */
-
- znet_transceiver_power (dev, 0);
- znet_transceiver_power (dev, 1);
- }
- netif_wake_queue (dev);
- }
-
- if ((status & SR0_RECEPTION) ||
- (status & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) {
- znet_rx(dev);
- }
- /* Clear the interrupts we've handled. */
- outb(CR0_INT_ACK, ioaddr);
- } while (boguscnt--);
-
- spin_unlock (&znet->lock);
-
- return IRQ_RETVAL(handled);
-}
-
-static void znet_rx(struct net_device *dev)
-{
- struct znet_private *znet = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- int boguscount = 1;
- short next_frame_end_offset = 0; /* Offset of next frame start. */
- short *cur_frame_end;
- short cur_frame_end_offset;
-
- outb(CR0_STATUS_2, ioaddr);
- cur_frame_end_offset = inw(ioaddr);
-
- if (cur_frame_end_offset == znet->rx_cur - znet->rx_start) {
- printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n",
- dev->name, cur_frame_end_offset);
- return;
- }
-
- /* Use same method as the Crynwr driver: construct a forward list in
- the same area of the backwards links we now have. This allows us to
- pass packets to the upper layers in the order they were received --
- important for fast-path sequential operations. */
- while (znet->rx_start + cur_frame_end_offset != znet->rx_cur &&
- ++boguscount < 5) {
- unsigned short hi_cnt, lo_cnt, hi_status, lo_status;
- int count, status;
-
- if (cur_frame_end_offset < 4) {
- /* Oh no, we have a special case: the frame trailer wraps around
- the end of the ring buffer. We've saved space at the end of
- the ring buffer for just this problem. */
- memcpy(znet->rx_end, znet->rx_start, 8);
- cur_frame_end_offset += (RX_BUF_SIZE/2);
- }
- cur_frame_end = znet->rx_start + cur_frame_end_offset - 4;
-
- lo_status = *cur_frame_end++;
- hi_status = *cur_frame_end++;
- status = ((hi_status & 0xff) << 8) + (lo_status & 0xff);
- lo_cnt = *cur_frame_end++;
- hi_cnt = *cur_frame_end++;
- count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff);
-
- if (znet_debug > 5)
- printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x"
- " count %#x status %04x.\n",
- cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt,
- count, status);
- cur_frame_end[-4] = status;
- cur_frame_end[-3] = next_frame_end_offset;
- cur_frame_end[-2] = count;
- next_frame_end_offset = cur_frame_end_offset;
- cur_frame_end_offset -= ((count + 1)>>1) + 3;
- if (cur_frame_end_offset < 0)
- cur_frame_end_offset += RX_BUF_SIZE/2;
- }
-
- /* Now step forward through the list. */
- do {
- ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset;
- int status = this_rfp_ptr[-4];
- int pkt_len = this_rfp_ptr[-2];
-
- if (znet_debug > 5)
- printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
- " next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
- this_rfp_ptr[-3]<<1);
- /* Once again we must assume that the i82586 docs apply. */
- if ( ! (status & RX_RCV_OK)) { /* There was an error. */
- dev->stats.rx_errors++;
- if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
- if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
-#if 0
- if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
- if (status & 0x0100) dev->stats.rx_fifo_errors++;
-#else
- /* maz : Wild guess... */
- if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
-#endif
- if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
- } else if (pkt_len > 1536) {
- dev->stats.rx_length_errors++;
- } else {
- /* Malloc up new buffer. */
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(dev, pkt_len);
- if (skb == NULL) {
- if (znet_debug)
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- break;
- }
-
- if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) {
- int semi_cnt = (znet->rx_end - znet->rx_cur)<<1;
- memcpy(skb_put(skb,semi_cnt), znet->rx_cur, semi_cnt);
- memcpy(skb_put(skb,pkt_len-semi_cnt), znet->rx_start,
- pkt_len - semi_cnt);
- } else {
- memcpy(skb_put(skb,pkt_len), znet->rx_cur, pkt_len);
- if (znet_debug > 6) {
- unsigned int *packet = (unsigned int *) skb->data;
- printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0],
- packet[1], packet[2], packet[3]);
- }
- }
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
- znet->rx_cur = this_rfp_ptr;
- if (znet->rx_cur >= znet->rx_end)
- znet->rx_cur -= RX_BUF_SIZE/2;
- update_stop_hit(ioaddr, (znet->rx_cur - znet->rx_start)<<1);
- next_frame_end_offset = this_rfp_ptr[-3];
- if (next_frame_end_offset == 0) /* Read all the frames? */
- break; /* Done for now */
- this_rfp_ptr = znet->rx_start + next_frame_end_offset;
- } while (--boguscount);
-
- /* If any worth-while packets have been received, dev_rint()
- has done a mark_bh(INET_BH) for us and will work on them
- when we get to the bottom-half routine. */
-}
-
-/* The inverse routine to znet_open(). */
-static int znet_close(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- netif_stop_queue (dev);
-
- outb(OP0_RESET, ioaddr); /* CMD0_RESET */
-
- if (znet_debug > 1)
- printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
- /* Turn off transceiver power. */
- znet_transceiver_power (dev, 0);
-
- znet_release_resources (dev);
-
- return 0;
-}
-
-static void show_dma(struct net_device *dev)
-{
- short ioaddr = dev->base_addr;
- unsigned char stat = inb (ioaddr);
- struct znet_private *znet = netdev_priv(dev);
- unsigned long flags;
- short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE;
- unsigned addr = inb(dma_port);
- short residue;
-
- addr |= inb(dma_port) << 8;
- residue = get_dma_residue(znet->tx_dma);
-
- if (znet_debug > 1) {
- flags=claim_dma_lock();
- printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n",
- stat, addr<<1, residue);
- release_dma_lock(flags);
- }
-}
-
-/* Initialize the hardware. We have to do this when the board is open()ed
- or when we come out of suspend mode. */
-static void hardware_init(struct net_device *dev)
-{
- unsigned long flags;
- short ioaddr = dev->base_addr;
- struct znet_private *znet = netdev_priv(dev);
-
- znet->rx_cur = znet->rx_start;
- znet->tx_cur = znet->tx_start;
-
- /* Reset the chip, and start it up. */
- outb(OP0_RESET, ioaddr);
-
- flags=claim_dma_lock();
- disable_dma(znet->rx_dma); /* reset by an interrupting task. */
- clear_dma_ff(znet->rx_dma);
- set_dma_mode(znet->rx_dma, DMA_RX_MODE);
- set_dma_addr(znet->rx_dma, isa_virt_to_bus(znet->rx_start));
- set_dma_count(znet->rx_dma, RX_BUF_SIZE);
- enable_dma(znet->rx_dma);
- /* Now set up the Tx channel. */
- disable_dma(znet->tx_dma);
- clear_dma_ff(znet->tx_dma);
- set_dma_mode(znet->tx_dma, DMA_TX_MODE);
- set_dma_addr(znet->tx_dma, isa_virt_to_bus(znet->tx_start));
- set_dma_count(znet->tx_dma, znet->tx_buf_len<<1);
- enable_dma(znet->tx_dma);
- release_dma_lock(flags);
-
- if (znet_debug > 1)
- printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n",
- dev->name, znet->rx_start,znet->tx_start);
- /* Do an empty configure command, just like the Crynwr driver. This
- resets to chip to its default values. */
- *znet->tx_cur++ = 0;
- *znet->tx_cur++ = 0;
- show_dma(dev);
- outb(OP0_CONFIGURE | CR0_CHNL, ioaddr);
-
- znet_set_multicast_list (dev);
-
- *znet->tx_cur++ = 6;
- memcpy(znet->tx_cur, dev->dev_addr, 6);
- znet->tx_cur += 3;
- show_dma(dev);
- outb(OP0_IA_SETUP | CR0_CHNL, ioaddr);
- show_dma(dev);
-
- update_stop_hit(ioaddr, 8192);
- if (znet_debug > 1) printk(KERN_DEBUG "enabling Rx.\n");
- outb(OP0_RCV_ENABLE, ioaddr);
- netif_start_queue (dev);
-}
-
-static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
-{
- outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, ioaddr);
- if (znet_debug > 5)
- printk(KERN_DEBUG "Updating stop hit with value %02x.\n",
- (rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE);
- outb((rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE, ioaddr);
- outb(OP1_SWIT_TO_PORT_0, ioaddr);
-}
-
-static __exit void znet_cleanup (void)
-{
- if (znet_dev) {
- struct znet_private *znet = netdev_priv(znet_dev);
-
- unregister_netdev (znet_dev);
- kfree (znet->rx_start);
- kfree (znet->tx_start);
- free_netdev (znet_dev);
- }
-}
-
-module_init (znet_probe);
-module_exit (znet_cleanup);
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 19b64de7124b..328f47c92e26 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -76,16 +76,16 @@ MODULE_PARM_DESC(msg_level, "msg_level");
MODULE_PARM_DESC(prop_carrier_state, "Propagate carrier state of physical "
"port to stack. 1:yes, 0:no. Default = 0 ");
MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
- "[2^x - 1], x = [6..14]. Default = "
+ "[2^x - 1], x = [7..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")");
MODULE_PARM_DESC(rq2_entries, "Number of entries for Receive Queue 2 "
- "[2^x - 1], x = [6..14]. Default = "
+ "[2^x - 1], x = [7..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_RQ2) ")");
MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
- "[2^x - 1], x = [6..14]. Default = "
+ "[2^x - 1], x = [7..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_RQ1) ")");
MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
- "[2^x - 1], x = [6..14]. Default = "
+ "[2^x - 1], x = [7..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
MODULE_PARM_DESC(use_mcs, " Multiple receive queues, 1: enable, 0: disable, "
"Default = 1");
@@ -1921,10 +1921,8 @@ static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
u64 hret;
ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_ATOMIC);
- if (!ehea_mcl_entry) {
- pr_err("no mem for mcl_entry\n");
+ if (!ehea_mcl_entry)
return;
- }
INIT_LIST_HEAD(&ehea_mcl_entry->list);
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
index 27f881758d16..9b03033bb557 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c
@@ -64,11 +64,10 @@ static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages,
}
queue->queue_length = nr_of_pages * pagesize;
- queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL);
- if (!queue->queue_pages) {
- pr_err("no mem for queue_pages\n");
+ queue->queue_pages = kmalloc_array(nr_of_pages, sizeof(void *),
+ GFP_KERNEL);
+ if (!queue->queue_pages)
return -ENOMEM;
- }
/*
* allocate pages for queue:
@@ -129,10 +128,8 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
void *vpage;
cq = kzalloc(sizeof(*cq), GFP_KERNEL);
- if (!cq) {
- pr_err("no mem for cq\n");
+ if (!cq)
goto out_nomem;
- }
cq->attr.max_nr_of_cqes = nr_of_cqe;
cq->attr.cq_token = cq_token;
@@ -257,10 +254,8 @@ struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
struct ehea_eq *eq;
eq = kzalloc(sizeof(*eq), GFP_KERNEL);
- if (!eq) {
- pr_err("no mem for eq\n");
+ if (!eq)
return NULL;
- }
eq->adapter = adapter;
eq->attr.type = type;
@@ -428,10 +423,8 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
qp = kzalloc(sizeof(*qp), GFP_KERNEL);
- if (!qp) {
- pr_err("no mem for qp\n");
+ if (!qp)
return NULL;
- }
qp->adapter = adapter;
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 256bdb8e1994..4989481c19f0 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -2190,11 +2190,10 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
{
struct emac_instance *dev = netdev_priv(ndev);
- strcpy(info->driver, "ibm_emac");
- strcpy(info->version, DRV_VERSION);
- info->fw_version[0] = '\0';
- sprintf(info->bus_info, "PPC 4xx EMAC-%d %s",
- dev->cell_index, dev->ofdev->dev.of_node->full_name);
+ strlcpy(info->driver, "ibm_emac", sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ snprintf(info->bus_info, sizeof(info->bus_info), "PPC 4xx EMAC-%d %s",
+ dev->cell_index, dev->ofdev->dev.of_node->full_name);
info->regdump_len = emac_ethtool_get_regs_len(ndev);
}
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index 50ea12bfb579..1f7ecf57181e 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -528,12 +528,9 @@ static int mal_probe(struct platform_device *ofdev)
irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde;
mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL);
- if (!mal) {
- printk(KERN_ERR
- "mal%d: out of memory allocating MAL structure!\n",
- index);
+ if (!mal)
return -ENOMEM;
- }
+
mal->index = index;
mal->ofdev = ofdev;
mal->version = of_device_is_compatible(ofdev->dev.of_node, "ibm,mcmal2") ? 2 : 1;
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index f2fdbb79837e..c859771a9902 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -637,7 +637,6 @@ static int ibmveth_open(struct net_device *netdev)
adapter->bounce_buffer =
kmalloc(netdev->mtu + IBMVETH_BUFF_OH, GFP_KERNEL);
if (!adapter->bounce_buffer) {
- netdev_err(netdev, "unable to allocate bounce buffer\n");
rc = -ENOMEM;
goto err_out_free_irq;
}
@@ -722,9 +721,8 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static void netdev_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strncpy(info->driver, ibmveth_driver_name, sizeof(info->driver) - 1);
- strncpy(info->version, ibmveth_driver_version,
- sizeof(info->version) - 1);
+ strlcpy(info->driver, ibmveth_driver_name, sizeof(info->driver));
+ strlcpy(info->version, ibmveth_driver_version, sizeof(info->version));
}
static netdev_features_t ibmveth_fix_features(struct net_device *dev,
diff --git a/drivers/net/ethernet/icplus/Kconfig b/drivers/net/ethernet/icplus/Kconfig
index 3aff81d7989f..5119ef18953b 100644
--- a/drivers/net/ethernet/icplus/Kconfig
+++ b/drivers/net/ethernet/icplus/Kconfig
@@ -4,7 +4,7 @@
config IP1000
tristate "IP1000 Gigabit Ethernet support"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
select NET_CORE
select MII
---help---
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index ddee4060948a..05f7264c51f7 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -5,11 +5,6 @@
config NET_VENDOR_INTEL
bool "Intel devices"
default y
- depends on PCI || PCI_MSI || ISA || ISA_DMA_API || ARM || \
- ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \
- GSC || BVME6000 || MVME16x || \
- (ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR) || \
- EXPERIMENTAL
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -74,6 +69,7 @@ config E1000E
tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
depends on PCI && (!SPARC32 || BROKEN)
select CRC32
+ select PTP_1588_CLOCK
---help---
This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
ethernet family of adapters. For PCI or PCI-X e1000 adapters,
@@ -94,6 +90,8 @@ config IGB
tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
depends on PCI
select PTP_1588_CLOCK
+ select I2C
+ select I2C_ALGOBIT
---help---
This driver supports Intel(R) 82575/82576 gigabit ethernet family of
adapters. For more information on how to identify your adapter, go
@@ -112,6 +110,17 @@ config IGB
To compile this driver as a module, choose M here. The module
will be called igb.
+config IGB_HWMON
+ bool "Intel(R) PCI-Express Gigabit adapters HWMON support"
+ default y
+ depends on IGB && HWMON && !(IGB=y && HWMON=m)
+ ---help---
+ Say Y if you want to expose thermal sensor data on Intel devices.
+
+ Some of our devices contain thermal sensors, both external and internal.
+ This data is available via the hwmon sysfs interface and exposes
+ the onboard sensors.
+
config IGB_DCA
bool "Direct Cache Access (DCA) Support"
default y
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
index a59f0779e1c3..ec800b093e7e 100644
--- a/drivers/net/ethernet/intel/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -2928,8 +2928,7 @@ static int e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
e100_phy_init(nic);
memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
- memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
- if (!is_valid_ether_addr(netdev->perm_addr)) {
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
if (!eeprom_bad_csum_allow) {
netif_err(nic, probe, nic->netdev, "Invalid MAC address from EEPROM, aborting\n");
err = -EAGAIN;
diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h
index 2b6cd02bfba0..26d9cd59ec75 100644
--- a/drivers/net/ethernet/intel/e1000/e1000.h
+++ b/drivers/net/ethernet/intel/e1000/e1000.h
@@ -81,68 +81,69 @@ struct e1000_adapter;
#include "e1000_hw.h"
-#define E1000_MAX_INTR 10
+#define E1000_MAX_INTR 10
/* TX/RX descriptor defines */
-#define E1000_DEFAULT_TXD 256
-#define E1000_MAX_TXD 256
-#define E1000_MIN_TXD 48
-#define E1000_MAX_82544_TXD 4096
+#define E1000_DEFAULT_TXD 256
+#define E1000_MAX_TXD 256
+#define E1000_MIN_TXD 48
+#define E1000_MAX_82544_TXD 4096
-#define E1000_DEFAULT_RXD 256
-#define E1000_MAX_RXD 256
-#define E1000_MIN_RXD 48
-#define E1000_MAX_82544_RXD 4096
+#define E1000_DEFAULT_RXD 256
+#define E1000_MAX_RXD 256
+#define E1000_MIN_RXD 48
+#define E1000_MAX_82544_RXD 4096
#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */
#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */
/* this is the size past which hardware will drop packets when setting LPE=0 */
-#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
/* Supported Rx Buffer Sizes */
-#define E1000_RXBUFFER_128 128 /* Used for packet split */
-#define E1000_RXBUFFER_256 256 /* Used for packet split */
-#define E1000_RXBUFFER_512 512
-#define E1000_RXBUFFER_1024 1024
-#define E1000_RXBUFFER_2048 2048
-#define E1000_RXBUFFER_4096 4096
-#define E1000_RXBUFFER_8192 8192
-#define E1000_RXBUFFER_16384 16384
+#define E1000_RXBUFFER_128 128 /* Used for packet split */
+#define E1000_RXBUFFER_256 256 /* Used for packet split */
+#define E1000_RXBUFFER_512 512
+#define E1000_RXBUFFER_1024 1024
+#define E1000_RXBUFFER_2048 2048
+#define E1000_RXBUFFER_4096 4096
+#define E1000_RXBUFFER_8192 8192
+#define E1000_RXBUFFER_16384 16384
/* SmartSpeed delimiters */
-#define E1000_SMARTSPEED_DOWNSHIFT 3
-#define E1000_SMARTSPEED_MAX 15
+#define E1000_SMARTSPEED_DOWNSHIFT 3
+#define E1000_SMARTSPEED_MAX 15
/* Packet Buffer allocations */
-#define E1000_PBA_BYTES_SHIFT 0xA
-#define E1000_TX_HEAD_ADDR_SHIFT 7
-#define E1000_PBA_TX_MASK 0xFFFF0000
+#define E1000_PBA_BYTES_SHIFT 0xA
+#define E1000_TX_HEAD_ADDR_SHIFT 7
+#define E1000_PBA_TX_MASK 0xFFFF0000
/* Flow Control Watermarks */
-#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */
-#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */
+#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */
+#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */
-#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */
+#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#define E1000_TX_QUEUE_WAKE 16
/* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
+#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
-#define AUTO_ALL_MODES 0
-#define E1000_EEPROM_82544_APM 0x0004
-#define E1000_EEPROM_APME 0x0400
+#define AUTO_ALL_MODES 0
+#define E1000_EEPROM_82544_APM 0x0004
+#define E1000_EEPROM_APME 0x0400
#ifndef E1000_MASTER_SLAVE
/* Switch to override PHY master/slave setting */
#define E1000_MASTER_SLAVE e1000_ms_hw_default
#endif
-#define E1000_MNG_VLAN_NONE (-1)
+#define E1000_MNG_VLAN_NONE (-1)
/* wrapper around a pointer to a socket buffer,
- * so a DMA handle can be stored along with the buffer */
+ * so a DMA handle can be stored along with the buffer
+ */
struct e1000_buffer {
struct sk_buff *skb;
dma_addr_t dma;
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
index 14e30515f6aa..43462d596a4e 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -115,12 +115,12 @@ static int e1000_get_settings(struct net_device *netdev,
if (hw->media_type == e1000_media_type_copper) {
ecmd->supported = (SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_1000baseT_Full|
- SUPPORTED_Autoneg |
- SUPPORTED_TP);
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full|
+ SUPPORTED_Autoneg |
+ SUPPORTED_TP);
ecmd->advertising = ADVERTISED_TP;
if (hw->autoneg == 1) {
@@ -161,8 +161,8 @@ static int e1000_get_settings(struct net_device *netdev,
ethtool_cmd_speed_set(ecmd, adapter->link_speed);
/* unfortunately FULL_DUPLEX != DUPLEX_FULL
- * and HALF_DUPLEX != DUPLEX_HALF */
-
+ * and HALF_DUPLEX != DUPLEX_HALF
+ */
if (adapter->link_duplex == FULL_DUPLEX)
ecmd->duplex = DUPLEX_FULL;
else
@@ -179,8 +179,7 @@ static int e1000_get_settings(struct net_device *netdev,
if ((hw->media_type == e1000_media_type_copper) &&
netif_carrier_ok(netdev))
ecmd->eth_tp_mdix = (!!adapter->phy_info.mdix_mode ?
- ETH_TP_MDI_X :
- ETH_TP_MDI);
+ ETH_TP_MDI_X : ETH_TP_MDI);
else
ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
@@ -197,8 +196,7 @@ static int e1000_set_settings(struct net_device *netdev,
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- /*
- * MDI setting is only allowed when autoneg enabled because
+ /* MDI setting is only allowed when autoneg enabled because
* some hardware doesn't allow MDI setting when speed or
* duplex is forced.
*/
@@ -224,8 +222,8 @@ static int e1000_set_settings(struct net_device *netdev,
ADVERTISED_Autoneg;
else
hw->autoneg_advertised = ecmd->advertising |
- ADVERTISED_TP |
- ADVERTISED_Autoneg;
+ ADVERTISED_TP |
+ ADVERTISED_Autoneg;
ecmd->advertising = hw->autoneg_advertised;
} else {
u32 speed = ethtool_cmd_speed(ecmd);
@@ -260,8 +258,7 @@ static u32 e1000_get_link(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- /*
- * If the link is not reported up to netdev, interrupts are disabled,
+ /* If the link is not reported up to netdev, interrupts are disabled,
* and so the physical link state may have changed since we last
* looked. Set get_link_status to make sure that the true link
* state is interrogated, rather than pulling a cached and possibly
@@ -484,7 +481,7 @@ static int e1000_get_eeprom(struct net_device *netdev,
le16_to_cpus(&eeprom_buff[i]);
memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1),
- eeprom->len);
+ eeprom->len);
kfree(eeprom_buff);
return ret_val;
@@ -517,15 +514,17 @@ static int e1000_set_eeprom(struct net_device *netdev,
ptr = (void *)eeprom_buff;
if (eeprom->offset & 1) {
- /* need read/modify/write of first changed EEPROM word */
- /* only the second byte of the word is being modified */
+ /* need read/modify/write of first changed EEPROM word
+ * only the second byte of the word is being modified
+ */
ret_val = e1000_read_eeprom(hw, first_word, 1,
&eeprom_buff[0]);
ptr++;
}
if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
- /* need read/modify/write of last changed EEPROM word */
- /* only the first byte of the word is being modified */
+ /* need read/modify/write of last changed EEPROM word
+ * only the first byte of the word is being modified
+ */
ret_val = e1000_read_eeprom(hw, last_word, 1,
&eeprom_buff[last_word - first_word]);
}
@@ -606,11 +605,13 @@ static int e1000_set_ringparam(struct net_device *netdev,
rx_old = adapter->rx_ring;
err = -ENOMEM;
- txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring), GFP_KERNEL);
+ txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring),
+ GFP_KERNEL);
if (!txdr)
goto err_alloc_tx;
- rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring), GFP_KERNEL);
+ rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring),
+ GFP_KERNEL);
if (!rxdr)
goto err_alloc_rx;
@@ -619,12 +620,12 @@ static int e1000_set_ringparam(struct net_device *netdev,
rxdr->count = max(ring->rx_pending,(u32)E1000_MIN_RXD);
rxdr->count = min(rxdr->count,(u32)(mac_type < e1000_82544 ?
- E1000_MAX_RXD : E1000_MAX_82544_RXD));
+ E1000_MAX_RXD : E1000_MAX_82544_RXD));
rxdr->count = ALIGN(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
txdr->count = max(ring->tx_pending,(u32)E1000_MIN_TXD);
txdr->count = min(txdr->count,(u32)(mac_type < e1000_82544 ?
- E1000_MAX_TXD : E1000_MAX_82544_TXD));
+ E1000_MAX_TXD : E1000_MAX_82544_TXD));
txdr->count = ALIGN(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
for (i = 0; i < adapter->num_tx_queues; i++)
@@ -642,7 +643,8 @@ static int e1000_set_ringparam(struct net_device *netdev,
goto err_setup_tx;
/* save the new, restore the old in order to free it,
- * then restore the new back again */
+ * then restore the new back again
+ */
adapter->rx_ring = rx_old;
adapter->tx_ring = tx_old;
@@ -784,7 +786,6 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000);
if (hw->mac_type >= e1000_82543) {
-
REG_SET_AND_CHECK(RCTL, before, 0xFFFFFFFF);
REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
@@ -795,14 +796,11 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF,
0xFFFFFFFF);
}
-
} else {
-
REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x01FFFFFF);
REG_PATTERN_TEST(RDBAL, 0xFFFFF000, 0xFFFFFFFF);
REG_PATTERN_TEST(TXCW, 0x0000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(TDBAL, 0xFFFFF000, 0xFFFFFFFF);
-
}
value = E1000_MC_TBL_SIZE;
@@ -858,13 +856,14 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
*data = 0;
- /* NOTE: we don't test MSI interrupts here, yet */
- /* Hook up test interrupt handler just for this test */
+ /* NOTE: we don't test MSI interrupts here, yet
+ * Hook up test interrupt handler just for this test
+ */
if (!request_irq(irq, e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
- netdev))
+ netdev))
shared_int = false;
else if (request_irq(irq, e1000_test_intr, IRQF_SHARED,
- netdev->name, netdev)) {
+ netdev->name, netdev)) {
*data = 1;
return -1;
}
@@ -1253,14 +1252,15 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
- E1000_CTRL_FD); /* Force Duplex to FULL */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
if (hw->media_type == e1000_media_type_copper &&
hw->phy_type == e1000_phy_m88)
ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
else {
/* Set the ILOS bit on the fiber Nic is half
- * duplex link is detected. */
+ * duplex link is detected.
+ */
stat_reg = er32(STATUS);
if ((stat_reg & E1000_STATUS_FD) == 0)
ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
@@ -1446,7 +1446,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
ret_val = e1000_check_lbtest_frame(
rxdr->buffer_info[l].skb,
- 1024);
+ 1024);
if (!ret_val)
good_cnt++;
if (unlikely(++l == rxdr->count)) l = 0;
@@ -1493,7 +1493,8 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
hw->serdes_has_link = false;
/* On some blade server designs, link establishment
- * could take as long as 2-3 minutes */
+ * could take as long as 2-3 minutes
+ */
do {
e1000_check_for_link(hw);
if (hw->serdes_has_link)
@@ -1545,7 +1546,8 @@ static void e1000_diag_test(struct net_device *netdev,
e_info(hw, "offline testing starting\n");
/* Link test performed before hardware reset so autoneg doesn't
- * interfere with test result */
+ * interfere with test result
+ */
if (e1000_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1639,7 +1641,8 @@ static int e1000_wol_exclusion(struct e1000_adapter *adapter,
default:
/* dual port cards only support WoL on port A from now on
* unless it was enabled in the eeprom for port B
- * so exclude FUNC_1 ports from having WoL enabled */
+ * so exclude FUNC_1 ports from having WoL enabled
+ */
if (er32(STATUS) & E1000_STATUS_FUNC_1 &&
!adapter->eeprom_wol) {
wol->supported = 0;
@@ -1663,7 +1666,8 @@ static void e1000_get_wol(struct net_device *netdev,
wol->wolopts = 0;
/* this function will set ->supported = 0 and return 1 if wol is not
- * supported by this hardware */
+ * supported by this hardware
+ */
if (e1000_wol_exclusion(adapter, wol) ||
!device_can_wakeup(&adapter->pdev->dev))
return;
@@ -1839,7 +1843,7 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
-/* BUG_ON(i != E1000_STATS_LEN); */
+/* BUG_ON(i != E1000_STATS_LEN); */
}
static void e1000_get_strings(struct net_device *netdev, u32 stringset,
@@ -1859,37 +1863,37 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset,
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
-/* BUG_ON(p - data != E1000_STATS_LEN * ETH_GSTRING_LEN); */
+ /* BUG_ON(p - data != E1000_STATS_LEN * ETH_GSTRING_LEN); */
break;
}
}
static const struct ethtool_ops e1000_ethtool_ops = {
- .get_settings = e1000_get_settings,
- .set_settings = e1000_set_settings,
- .get_drvinfo = e1000_get_drvinfo,
- .get_regs_len = e1000_get_regs_len,
- .get_regs = e1000_get_regs,
- .get_wol = e1000_get_wol,
- .set_wol = e1000_set_wol,
- .get_msglevel = e1000_get_msglevel,
- .set_msglevel = e1000_set_msglevel,
- .nway_reset = e1000_nway_reset,
- .get_link = e1000_get_link,
- .get_eeprom_len = e1000_get_eeprom_len,
- .get_eeprom = e1000_get_eeprom,
- .set_eeprom = e1000_set_eeprom,
- .get_ringparam = e1000_get_ringparam,
- .set_ringparam = e1000_set_ringparam,
- .get_pauseparam = e1000_get_pauseparam,
- .set_pauseparam = e1000_set_pauseparam,
- .self_test = e1000_diag_test,
- .get_strings = e1000_get_strings,
- .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,
- .set_coalesce = e1000_set_coalesce,
+ .get_settings = e1000_get_settings,
+ .set_settings = e1000_set_settings,
+ .get_drvinfo = e1000_get_drvinfo,
+ .get_regs_len = e1000_get_regs_len,
+ .get_regs = e1000_get_regs,
+ .get_wol = e1000_get_wol,
+ .set_wol = e1000_set_wol,
+ .get_msglevel = e1000_get_msglevel,
+ .set_msglevel = e1000_set_msglevel,
+ .nway_reset = e1000_nway_reset,
+ .get_link = e1000_get_link,
+ .get_eeprom_len = e1000_get_eeprom_len,
+ .get_eeprom = e1000_get_eeprom,
+ .set_eeprom = e1000_set_eeprom,
+ .get_ringparam = e1000_get_ringparam,
+ .set_ringparam = e1000_set_ringparam,
+ .get_pauseparam = e1000_get_pauseparam,
+ .set_pauseparam = e1000_set_pauseparam,
+ .self_test = e1000_diag_test,
+ .get_strings = e1000_get_strings,
+ .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,
+ .set_coalesce = e1000_set_coalesce,
.get_ts_info = ethtool_op_get_ts_info,
};
diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.c b/drivers/net/ethernet/intel/e1000/e1000_hw.c
index 8fedd2451538..2879b9631e15 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c
@@ -164,8 +164,9 @@ static void e1000_phy_init_script(struct e1000_hw *hw)
if (hw->phy_init_script) {
msleep(20);
- /* Save off the current value of register 0x2F5B to be restored at
- * the end of this routine. */
+ /* Save off the current value of register 0x2F5B to be restored
+ * at the end of this routine.
+ */
ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
/* Disabled the PHY transmitter */
@@ -466,7 +467,8 @@ s32 e1000_reset_hw(struct e1000_hw *hw)
case e1000_82541:
case e1000_82541_rev_2:
/* These controllers can't ack the 64-bit write when issuing the
- * reset, so use IO-mapping as a workaround to issue the reset */
+ * reset, so use IO-mapping as a workaround to issue the reset
+ */
E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
break;
case e1000_82545_rev_3:
@@ -480,9 +482,9 @@ s32 e1000_reset_hw(struct e1000_hw *hw)
break;
}
- /* After MAC reset, force reload of EEPROM to restore power-on settings to
- * device. Later controllers reload the EEPROM automatically, so just wait
- * for reload to complete.
+ /* After MAC reset, force reload of EEPROM to restore power-on settings
+ * to device. Later controllers reload the EEPROM automatically, so
+ * just wait for reload to complete.
*/
switch (hw->mac_type) {
case e1000_82542_rev2_0:
@@ -591,8 +593,8 @@ s32 e1000_init_hw(struct e1000_hw *hw)
msleep(5);
}
- /* Setup the receive address. This involves initializing all of the Receive
- * Address Registers (RARs 0 - 15).
+ /* Setup the receive address. This involves initializing all of the
+ * Receive Address Registers (RARs 0 - 15).
*/
e1000_init_rx_addrs(hw);
@@ -611,7 +613,8 @@ s32 e1000_init_hw(struct e1000_hw *hw)
for (i = 0; i < mta_size; i++) {
E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
/* use write flush to prevent Memory Write Block (MWB) from
- * occurring when accessing our register space */
+ * occurring when accessing our register space
+ */
E1000_WRITE_FLUSH();
}
@@ -630,7 +633,9 @@ s32 e1000_init_hw(struct e1000_hw *hw)
case e1000_82546_rev_3:
break;
default:
- /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
+ /* Workaround for PCI-X problem when BIOS sets MMRBC
+ * incorrectly.
+ */
if (hw->bus_type == e1000_bus_type_pcix
&& e1000_pcix_get_mmrbc(hw) > 2048)
e1000_pcix_set_mmrbc(hw, 2048);
@@ -660,7 +665,8 @@ s32 e1000_init_hw(struct e1000_hw *hw)
hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) {
ctrl_ext = er32(CTRL_EXT);
/* Relaxed ordering must be disabled to avoid a parity
- * error crash in a PCI slot. */
+ * error crash in a PCI slot.
+ */
ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
ew32(CTRL_EXT, ctrl_ext);
}
@@ -810,8 +816,9 @@ s32 e1000_setup_link(struct e1000_hw *hw)
ew32(FCRTL, 0);
ew32(FCRTH, 0);
} else {
- /* We need to set up the Receive Threshold high and low water marks
- * as well as (optionally) enabling the transmission of XON frames.
+ /* We need to set up the Receive Threshold high and low water
+ * marks as well as (optionally) enabling the transmission of
+ * XON frames.
*/
if (hw->fc_send_xon) {
ew32(FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
@@ -868,42 +875,46 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
e1000_config_collision_dist(hw);
/* Check for a software override of the flow control settings, and setup
- * the device accordingly. If auto-negotiation is enabled, then software
- * will have to set the "PAUSE" bits to the correct value in the Tranmsit
- * Config Word Register (TXCW) and re-start auto-negotiation. However, if
- * auto-negotiation is disabled, then software will have to manually
- * configure the two flow control enable bits in the CTRL register.
+ * the device accordingly. If auto-negotiation is enabled, then
+ * software will have to set the "PAUSE" bits to the correct value in
+ * the Tranmsit Config Word Register (TXCW) and re-start
+ * auto-negotiation. However, if auto-negotiation is disabled, then
+ * software will have to manually configure the two flow control enable
+ * bits in the CTRL register.
*
* The possible values of the "fc" parameter are:
- * 0: Flow control is completely disabled
- * 1: Rx flow control is enabled (we can receive pause frames, but
- * not send pause frames).
- * 2: Tx flow control is enabled (we can send pause frames but we do
- * not support receiving pause frames).
- * 3: Both Rx and TX flow control (symmetric) are enabled.
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames, but
+ * not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we do
+ * not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
*/
switch (hw->fc) {
case E1000_FC_NONE:
- /* Flow control is completely disabled by a software over-ride. */
+ /* Flow ctrl is completely disabled by a software over-ride */
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
break;
case E1000_FC_RX_PAUSE:
- /* RX Flow control is enabled and TX Flow control is disabled by a
- * software over-ride. Since there really isn't a way to advertise
- * that we are capable of RX Pause ONLY, we will advertise that we
- * support both symmetric and asymmetric RX PAUSE. Later, we will
- * disable the adapter's ability to send PAUSE frames.
+ /* Rx Flow control is enabled and Tx Flow control is disabled by
+ * a software over-ride. Since there really isn't a way to
+ * advertise that we are capable of Rx Pause ONLY, we will
+ * advertise that we support both symmetric and asymmetric Rx
+ * PAUSE. Later, we will disable the adapter's ability to send
+ * PAUSE frames.
*/
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
break;
case E1000_FC_TX_PAUSE:
- /* TX Flow control is enabled, and RX Flow control is disabled, by a
- * software over-ride.
+ /* Tx Flow control is enabled, and Rx Flow control is disabled,
+ * by a software over-ride.
*/
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
break;
case E1000_FC_FULL:
- /* Flow control (both RX and TX) is enabled by a software over-ride. */
+ /* Flow control (both Rx and Tx) is enabled by a software
+ * over-ride.
+ */
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
break;
default:
@@ -912,11 +923,11 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
break;
}
- /* Since auto-negotiation is enabled, take the link out of reset (the link
- * will be in reset, because we previously reset the chip). This will
- * restart auto-negotiation. If auto-negotiation is successful then the
- * link-up status bit will be set and the flow control enable bits (RFCE
- * and TFCE) will be set according to their negotiated value.
+ /* Since auto-negotiation is enabled, take the link out of reset (the
+ * link will be in reset, because we previously reset the chip). This
+ * will restart auto-negotiation. If auto-negotiation is successful
+ * then the link-up status bit will be set and the flow control enable
+ * bits (RFCE and TFCE) will be set according to their negotiated value.
*/
e_dbg("Auto-negotiation enabled\n");
@@ -927,11 +938,12 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
hw->txcw = txcw;
msleep(1);
- /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
- * indication in the Device Status Register. Time-out if a link isn't
- * seen in 500 milliseconds seconds (Auto-negotiation should complete in
- * less than 500 milliseconds even if the other end is doing it in SW).
- * For internal serdes, we just assume a signal is present, then poll.
+ /* If we have a signal (the cable is plugged in) then poll for a
+ * "Link-Up" indication in the Device Status Register. Time-out if a
+ * link isn't seen in 500 milliseconds seconds (Auto-negotiation should
+ * complete in less than 500 milliseconds even if the other end is doing
+ * it in SW). For internal serdes, we just assume a signal is present,
+ * then poll.
*/
if (hw->media_type == e1000_media_type_internal_serdes ||
(er32(CTRL) & E1000_CTRL_SWDPIN1) == signal) {
@@ -946,9 +958,9 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
e_dbg("Never got a valid link from auto-neg!!!\n");
hw->autoneg_failed = 1;
/* AutoNeg failed to achieve a link, so we'll call
- * e1000_check_for_link. This routine will force the link up if
- * we detect a signal. This will allow us to communicate with
- * non-autonegotiating link partners.
+ * e1000_check_for_link. This routine will force the
+ * link up if we detect a signal. This will allow us to
+ * communicate with non-autonegotiating link partners.
*/
ret_val = e1000_check_for_link(hw);
if (ret_val) {
@@ -1042,9 +1054,9 @@ static s32 e1000_copper_link_preconfig(struct e1000_hw *hw)
e_dbg("e1000_copper_link_preconfig");
ctrl = er32(CTRL);
- /* With 82543, we need to force speed and duplex on the MAC equal to what
- * the PHY speed and duplex configuration is. In addition, we need to
- * perform a hardware reset on the PHY to take it out of reset.
+ /* With 82543, we need to force speed and duplex on the MAC equal to
+ * what the PHY speed and duplex configuration is. In addition, we need
+ * to perform a hardware reset on the PHY to take it out of reset.
*/
if (hw->mac_type > e1000_82543) {
ctrl |= E1000_CTRL_SLU;
@@ -1175,7 +1187,8 @@ static s32 e1000_copper_link_igp_setup(struct e1000_hw *hw)
/* when autonegotiation advertisement is only 1000Mbps then we
* should disable SmartSpeed and enable Auto MasterSlave
- * resolution as hardware default. */
+ * resolution as hardware default.
+ */
if (hw->autoneg_advertised == ADVERTISE_1000_FULL) {
/* Disable SmartSpeed */
ret_val =
@@ -1485,13 +1498,15 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw)
if (hw->autoneg) {
/* Setup autoneg and flow control advertisement
- * and perform autonegotiation */
+ * and perform autonegotiation
+ */
ret_val = e1000_copper_link_autoneg(hw);
if (ret_val)
return ret_val;
} else {
/* PHY will be set to 10H, 10F, 100H,or 100F
- * depending on value from forced_speed_duplex. */
+ * depending on value from forced_speed_duplex.
+ */
e_dbg("Forcing speed and duplex\n");
ret_val = e1000_phy_force_speed_duplex(hw);
if (ret_val) {
@@ -1609,7 +1624,8 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
* setup the PHY advertisement registers accordingly. If
* auto-negotiation is enabled, then software will have to set the
* "PAUSE" bits to the correct value in the Auto-Negotiation
- * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+ * Advertisement Register (PHY_AUTONEG_ADV) and re-start
+ * auto-negotiation.
*
* The possible values of the "fc" parameter are:
* 0: Flow control is completely disabled
@@ -1636,7 +1652,7 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
* capable of RX Pause ONLY, we will advertise that we
* support both symmetric and asymmetric RX PAUSE. Later
* (in e1000_config_fc_after_link_up) we will disable the
- *hw's ability to send PAUSE frames.
+ * hw's ability to send PAUSE frames.
*/
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
break;
@@ -1720,15 +1736,15 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
/* Are we forcing Full or Half Duplex? */
if (hw->forced_speed_duplex == e1000_100_full ||
hw->forced_speed_duplex == e1000_10_full) {
- /* We want to force full duplex so we SET the full duplex bits in the
- * Device and MII Control Registers.
+ /* We want to force full duplex so we SET the full duplex bits
+ * in the Device and MII Control Registers.
*/
ctrl |= E1000_CTRL_FD;
mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
e_dbg("Full Duplex\n");
} else {
- /* We want to force half duplex so we CLEAR the full duplex bits in
- * the Device and MII Control Registers.
+ /* We want to force half duplex so we CLEAR the full duplex bits
+ * in the Device and MII Control Registers.
*/
ctrl &= ~E1000_CTRL_FD;
mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;
@@ -1762,8 +1778,8 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
- * forced whenever speed are duplex are forced.
+ /* Clear Auto-Crossover to force MDI manually. M88E1000 requires
+ * MDI forced whenever speed are duplex are forced.
*/
phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
ret_val =
@@ -1814,10 +1830,10 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
e_dbg("Waiting for forced speed/duplex link.\n");
mii_status_reg = 0;
- /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+ /* Wait for autoneg to complete or 4.5 seconds to expire */
for (i = PHY_FORCE_TIME; i > 0; i--) {
- /* Read the MII Status Register and wait for Auto-Neg Complete bit
- * to be set.
+ /* Read the MII Status Register and wait for Auto-Neg
+ * Complete bit to be set.
*/
ret_val =
e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
@@ -1834,20 +1850,24 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
msleep(100);
}
if ((i == 0) && (hw->phy_type == e1000_phy_m88)) {
- /* We didn't get link. Reset the DSP and wait again for link. */
+ /* We didn't get link. Reset the DSP and wait again
+ * for link.
+ */
ret_val = e1000_phy_reset_dsp(hw);
if (ret_val) {
e_dbg("Error Resetting PHY DSP\n");
return ret_val;
}
}
- /* This loop will early-out if the link condition has been met. */
+ /* This loop will early-out if the link condition has been
+ * met
+ */
for (i = PHY_FORCE_TIME; i > 0; i--) {
if (mii_status_reg & MII_SR_LINK_STATUS)
break;
msleep(100);
- /* Read the MII Status Register and wait for Auto-Neg Complete bit
- * to be set.
+ /* Read the MII Status Register and wait for Auto-Neg
+ * Complete bit to be set.
*/
ret_val =
e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
@@ -1862,9 +1882,10 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
}
if (hw->phy_type == e1000_phy_m88) {
- /* Because we reset the PHY above, we need to re-force TX_CLK in the
- * Extended PHY Specific Control Register to 25MHz clock. This value
- * defaults back to a 2.5MHz clock when the PHY is reset.
+ /* Because we reset the PHY above, we need to re-force TX_CLK in
+ * the Extended PHY Specific Control Register to 25MHz clock.
+ * This value defaults back to a 2.5MHz clock when the PHY is
+ * reset.
*/
ret_val =
e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
@@ -1879,8 +1900,9 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- /* In addition, because of the s/w reset above, we need to enable CRS on
- * TX. This must be set for both full and half duplex operation.
+ /* In addition, because of the s/w reset above, we need to
+ * enable CRS on Tx. This must be set for both full and half
+ * duplex operation.
*/
ret_val =
e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
@@ -1951,7 +1973,8 @@ static s32 e1000_config_mac_to_phy(struct e1000_hw *hw)
e_dbg("e1000_config_mac_to_phy");
/* 82544 or newer MAC, Auto Speed Detection takes care of
- * MAC speed/duplex configuration.*/
+ * MAC speed/duplex configuration.
+ */
if ((hw->mac_type >= e1000_82544) && (hw->mac_type != e1000_ce4100))
return E1000_SUCCESS;
@@ -1985,7 +2008,7 @@ static s32 e1000_config_mac_to_phy(struct e1000_hw *hw)
* registers depending on negotiated values.
*/
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
- &phy_data);
+ &phy_data);
if (ret_val)
return ret_val;
@@ -2002,7 +2025,7 @@ static s32 e1000_config_mac_to_phy(struct e1000_hw *hw)
if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
ctrl |= E1000_CTRL_SPD_1000;
else if ((phy_data & M88E1000_PSSR_SPEED) ==
- M88E1000_PSSR_100MBS)
+ M88E1000_PSSR_100MBS)
ctrl |= E1000_CTRL_SPD_100;
}
@@ -2135,9 +2158,9 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
if (mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
/* The AutoNeg process has completed, so we now need to
* read both the Auto Negotiation Advertisement Register
- * (Address 4) and the Auto_Negotiation Base Page Ability
- * Register (Address 5) to determine how flow control was
- * negotiated.
+ * (Address 4) and the Auto_Negotiation Base Page
+ * Ability Register (Address 5) to determine how flow
+ * control was negotiated.
*/
ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV,
&mii_nway_adv_reg);
@@ -2148,18 +2171,19 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- /* Two bits in the Auto Negotiation Advertisement Register
- * (Address 4) and two bits in the Auto Negotiation Base
- * Page Ability Register (Address 5) determine flow control
- * for both the PHY and the link partner. The following
- * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
- * 1999, describes these PAUSE resolution bits and how flow
- * control is determined based upon these settings.
+ /* Two bits in the Auto Negotiation Advertisement
+ * Register (Address 4) and two bits in the Auto
+ * Negotiation Base Page Ability Register (Address 5)
+ * determine flow control for both the PHY and the link
+ * partner. The following table, taken out of the IEEE
+ * 802.3ab/D6.0 dated March 25, 1999, describes these
+ * PAUSE resolution bits and how flow control is
+ * determined based upon these settings.
* NOTE: DC = Don't Care
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
- *-------|---------|-------|---------|--------------------
+ *-------|---------|-------|---------|------------------
* 0 | 0 | DC | DC | E1000_FC_NONE
* 0 | 1 | 0 | DC | E1000_FC_NONE
* 0 | 1 | 1 | 0 | E1000_FC_NONE
@@ -2178,17 +2202,18 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
+ *-------|---------|-------|---------|------------------
* 1 | DC | 1 | DC | E1000_FC_FULL
*
*/
if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
- /* Now we need to check if the user selected RX ONLY
- * 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.
+ /* Now we need to check if the user selected Rx
+ * ONLY 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.
*/
if (hw->original_fc == E1000_FC_FULL) {
hw->fc = E1000_FC_FULL;
@@ -2203,7 +2228,7 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
+ *-------|---------|-------|---------|------------------
* 0 | 1 | 1 | 1 | E1000_FC_TX_PAUSE
*
*/
@@ -2220,7 +2245,7 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
+ *-------|---------|-------|---------|------------------
* 1 | 1 | 0 | 1 | E1000_FC_RX_PAUSE
*
*/
@@ -2233,25 +2258,27 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
e_dbg
("Flow Control = RX PAUSE frames only.\n");
}
- /* Per the IEEE spec, at this point flow control should be
- * disabled. However, we want to consider that we could
- * be connected to a legacy switch that doesn't advertise
- * desired flow control, but can be forced on the link
- * partner. So if we advertised no flow control, that is
- * what we will resolve to. If we advertised some kind of
- * receive capability (Rx Pause Only or Full Flow Control)
- * and the link partner advertised none, we will configure
- * ourselves to enable Rx Flow Control only. We can do
- * this safely for two reasons: If the link partner really
- * didn't want flow control enabled, and we enable Rx, no
- * harm done since we won't be receiving any PAUSE frames
- * anyway. If the intent on the link partner was to have
- * flow control enabled, then by us enabling RX only, we
- * can at least receive pause frames and process them.
- * This is a good idea because in most cases, since we are
- * predominantly a server NIC, more times than not we will
- * be asked to delay transmission of packets than asking
- * our link partner to pause transmission of frames.
+ /* Per the IEEE spec, at this point flow control should
+ * be disabled. However, we want to consider that we
+ * could be connected to a legacy switch that doesn't
+ * advertise desired flow control, but can be forced on
+ * the link partner. So if we advertised no flow
+ * control, that is what we will resolve to. If we
+ * advertised some kind of receive capability (Rx Pause
+ * Only or Full Flow Control) and the link partner
+ * advertised none, we will configure ourselves to
+ * enable Rx Flow Control only. We can do this safely
+ * for two reasons: If the link partner really
+ * didn't want flow control enabled, and we enable Rx,
+ * no harm done since we won't be receiving any PAUSE
+ * frames anyway. If the intent on the link partner was
+ * to have flow control enabled, then by us enabling Rx
+ * only, we can at least receive pause frames and
+ * process them. This is a good idea because in most
+ * cases, since we are predominantly a server NIC, more
+ * times than not we will be asked to delay transmission
+ * of packets than asking our link partner to pause
+ * transmission of frames.
*/
else if ((hw->original_fc == E1000_FC_NONE ||
hw->original_fc == E1000_FC_TX_PAUSE) ||
@@ -2316,8 +2343,7 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
status = er32(STATUS);
rxcw = er32(RXCW);
- /*
- * If we don't have link (auto-negotiation failed or link partner
+ /* If we don't have link (auto-negotiation failed or link partner
* cannot auto-negotiate), and our link partner is not trying to
* auto-negotiate with us (we are receiving idles or data),
* we need to force link up. We also need to give auto-negotiation
@@ -2346,8 +2372,7 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
goto out;
}
} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
- /*
- * If we are forcing link and we are receiving /C/ ordered
+ /* If we are forcing link and we are receiving /C/ ordered
* sets, re-enable auto-negotiation in the TXCW register
* and disable forced link in the Device Control register
* in an attempt to auto-negotiate with our link partner.
@@ -2358,8 +2383,7 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
hw->serdes_has_link = true;
} else if (!(E1000_TXCW_ANE & er32(TXCW))) {
- /*
- * If we force link for non-auto-negotiation switch, check
+ /* If we force link for non-auto-negotiation switch, check
* link status based on MAC synchronization for internal
* serdes media type.
*/
@@ -2468,15 +2492,17 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
if (phy_data & MII_SR_LINK_STATUS) {
hw->get_link_status = false;
- /* Check if there was DownShift, must be checked immediately after
- * link-up */
+ /* Check if there was DownShift, must be checked
+ * immediately after link-up
+ */
e1000_check_downshift(hw);
/* If we are on 82544 or 82543 silicon and speed/duplex
- * are forced to 10H or 10F, then we will implement the polarity
- * reversal workaround. We disable interrupts first, and upon
- * returning, place the devices interrupt state to its previous
- * value except for the link status change interrupt which will
+ * are forced to 10H or 10F, then we will implement the
+ * polarity reversal workaround. We disable interrupts
+ * first, and upon returning, place the devices
+ * interrupt state to its previous value except for the
+ * link status change interrupt which will
* happen due to the execution of this workaround.
*/
@@ -2527,9 +2553,10 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
}
}
- /* Configure Flow Control now that Auto-Neg has completed. First, we
- * need to restore the desired flow control settings because we may
- * have had to re-autoneg with a different link partner.
+ /* Configure Flow Control now that Auto-Neg has completed.
+ * First, we need to restore the desired flow control settings
+ * because we may have had to re-autoneg with a different link
+ * partner.
*/
ret_val = e1000_config_fc_after_link_up(hw);
if (ret_val) {
@@ -2538,11 +2565,12 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
}
/* At this point we know that we are on copper and we have
- * auto-negotiated link. These are conditions for checking the link
- * partner capability register. We use the link speed to determine if
- * TBI compatibility needs to be turned on or off. If the link is not
- * at gigabit speed, then TBI compatibility is not needed. If we are
- * at gigabit speed, we turn on TBI compatibility.
+ * auto-negotiated link. These are conditions for checking the
+ * link partner capability register. We use the link speed to
+ * determine if TBI compatibility needs to be turned on or off.
+ * If the link is not at gigabit speed, then TBI compatibility
+ * is not needed. If we are at gigabit speed, we turn on TBI
+ * compatibility.
*/
if (hw->tbi_compatibility_en) {
u16 speed, duplex;
@@ -2554,20 +2582,23 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
return ret_val;
}
if (speed != SPEED_1000) {
- /* If link speed is not set to gigabit speed, we do not need
- * to enable TBI compatibility.
+ /* If link speed is not set to gigabit speed, we
+ * do not need to enable TBI compatibility.
*/
if (hw->tbi_compatibility_on) {
- /* If we previously were in the mode, turn it off. */
+ /* If we previously were in the mode,
+ * turn it off.
+ */
rctl = er32(RCTL);
rctl &= ~E1000_RCTL_SBP;
ew32(RCTL, rctl);
hw->tbi_compatibility_on = false;
}
} else {
- /* If TBI compatibility is was previously off, turn it on. For
- * compatibility with a TBI link partner, we will store bad
- * packets. Some frames have an additional byte on the end and
+ /* If TBI compatibility is was previously off,
+ * turn it on. For compatibility with a TBI link
+ * partner, we will store bad packets. Some
+ * frames have an additional byte on the end and
* will look like CRC errors to to the hardware.
*/
if (!hw->tbi_compatibility_on) {
@@ -2629,9 +2660,9 @@ s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, u16 *duplex)
*duplex = FULL_DUPLEX;
}
- /* IGP01 PHY may advertise full duplex operation after speed downgrade even
- * if it is operating at half duplex. Here we set the duplex settings to
- * match the duplex in the link partner's capabilities.
+ /* IGP01 PHY may advertise full duplex operation after speed downgrade
+ * even if it is operating at half duplex. Here we set the duplex
+ * settings to match the duplex in the link partner's capabilities.
*/
if (hw->phy_type == e1000_phy_igp && hw->speed_downgraded) {
ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
@@ -2697,8 +2728,8 @@ static s32 e1000_wait_autoneg(struct e1000_hw *hw)
*/
static void e1000_raise_mdi_clk(struct e1000_hw *hw, u32 *ctrl)
{
- /* Raise the clock input to the Management Data Clock (by setting the MDC
- * bit), and then delay 10 microseconds.
+ /* Raise the clock input to the Management Data Clock (by setting the
+ * MDC bit), and then delay 10 microseconds.
*/
ew32(CTRL, (*ctrl | E1000_CTRL_MDC));
E1000_WRITE_FLUSH();
@@ -2712,8 +2743,8 @@ static void e1000_raise_mdi_clk(struct e1000_hw *hw, u32 *ctrl)
*/
static void e1000_lower_mdi_clk(struct e1000_hw *hw, u32 *ctrl)
{
- /* Lower the clock input to the Management Data Clock (by clearing the MDC
- * bit), and then delay 10 microseconds.
+ /* Lower the clock input to the Management Data Clock (by clearing the
+ * MDC bit), and then delay 10 microseconds.
*/
ew32(CTRL, (*ctrl & ~E1000_CTRL_MDC));
E1000_WRITE_FLUSH();
@@ -2746,10 +2777,10 @@ static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, u32 data, u16 count)
ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
while (mask) {
- /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
- * then raising and lowering the Management Data Clock. A "0" is
- * shifted out to the PHY by setting the MDIO bit to "0" and then
- * raising and lowering the clock.
+ /* A "1" is shifted out to the PHY by setting the MDIO bit to
+ * "1" and then raising and lowering the Management Data Clock.
+ * A "0" is shifted out to the PHY by setting the MDIO bit to
+ * "0" and then raising and lowering the clock.
*/
if (data & mask)
ctrl |= E1000_CTRL_MDIO;
@@ -2781,24 +2812,26 @@ static u16 e1000_shift_in_mdi_bits(struct e1000_hw *hw)
u8 i;
/* In order to read a register from the PHY, we need to shift in a total
- * of 18 bits from the PHY. The first two bit (turnaround) times are used
- * to avoid contention on the MDIO pin when a read operation is performed.
- * These two bits are ignored by us and thrown away. Bits are "shifted in"
- * by raising the input to the Management Data Clock (setting the MDC bit),
- * and then reading the value of the MDIO bit.
+ * of 18 bits from the PHY. The first two bit (turnaround) times are
+ * used to avoid contention on the MDIO pin when a read operation is
+ * performed. These two bits are ignored by us and thrown away. Bits are
+ * "shifted in" by raising the input to the Management Data Clock
+ * (setting the MDC bit), and then reading the value of the MDIO bit.
*/
ctrl = er32(CTRL);
- /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+ /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as
+ * input.
+ */
ctrl &= ~E1000_CTRL_MDIO_DIR;
ctrl &= ~E1000_CTRL_MDIO;
ew32(CTRL, ctrl);
E1000_WRITE_FLUSH();
- /* Raise and Lower the clock before reading in the data. This accounts for
- * the turnaround bits. The first clock occurred when we clocked out the
- * last bit of the Register Address.
+ /* Raise and Lower the clock before reading in the data. This accounts
+ * for the turnaround bits. The first clock occurred when we clocked out
+ * the last bit of the Register Address.
*/
e1000_raise_mdi_clk(hw, &ctrl);
e1000_lower_mdi_clk(hw, &ctrl);
@@ -2870,8 +2903,8 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
if (hw->mac_type > e1000_82543) {
/* Set up Op-code, Phy Address, and register address in the MDI
- * Control register. The MAC will take care of interfacing with the
- * PHY to retrieve the desired data.
+ * Control register. The MAC will take care of interfacing with
+ * the PHY to retrieve the desired data.
*/
if (hw->mac_type == e1000_ce4100) {
mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
@@ -2929,31 +2962,32 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
*phy_data = (u16) mdic;
}
} else {
- /* We must first send a preamble through the MDIO pin to signal the
- * beginning of an MII instruction. This is done by sending 32
- * consecutive "1" bits.
+ /* We must first send a preamble through the MDIO pin to signal
+ * the beginning of an MII instruction. This is done by sending
+ * 32 consecutive "1" bits.
*/
e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
/* Now combine the next few fields that are required for a read
* operation. We use this method instead of calling the
- * e1000_shift_out_mdi_bits routine five different times. The format of
- * a MII read instruction consists of a shift out of 14 bits and is
- * defined as follows:
+ * e1000_shift_out_mdi_bits routine five different times. The
+ * format of a MII read instruction consists of a shift out of
+ * 14 bits and is defined as follows:
* <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
- * followed by a shift in of 18 bits. This first two bits shifted in
- * are TurnAround bits used to avoid contention on the MDIO pin when a
- * READ operation is performed. These two bits are thrown away
- * followed by a shift in of 16 bits which contains the desired data.
+ * followed by a shift in of 18 bits. This first two bits
+ * shifted in are TurnAround bits used to avoid contention on
+ * the MDIO pin when a READ operation is performed. These two
+ * bits are thrown away followed by a shift in of 16 bits which
+ * contains the desired data.
*/
mdic = ((reg_addr) | (phy_addr << 5) |
(PHY_OP_READ << 10) | (PHY_SOF << 12));
e1000_shift_out_mdi_bits(hw, mdic, 14);
- /* Now that we've shifted out the read command to the MII, we need to
- * "shift in" the 16-bit value (18 total bits) of the requested PHY
- * register address.
+ /* Now that we've shifted out the read command to the MII, we
+ * need to "shift in" the 16-bit value (18 total bits) of the
+ * requested PHY register address.
*/
*phy_data = e1000_shift_in_mdi_bits(hw);
}
@@ -3060,18 +3094,18 @@ static s32 e1000_write_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
}
}
} else {
- /* We'll need to use the SW defined pins to shift the write command
- * out to the PHY. We first send a preamble to the PHY to signal the
- * beginning of the MII instruction. This is done by sending 32
- * consecutive "1" bits.
+ /* We'll need to use the SW defined pins to shift the write
+ * command out to the PHY. We first send a preamble to the PHY
+ * to signal the beginning of the MII instruction. This is done
+ * by sending 32 consecutive "1" bits.
*/
e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
- /* Now combine the remaining required fields that will indicate a
- * write operation. We use this method instead of calling the
- * e1000_shift_out_mdi_bits routine for each field in the command. The
- * format of a MII write instruction is as follows:
- * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+ /* Now combine the remaining required fields that will indicate
+ * a write operation. We use this method instead of calling the
+ * e1000_shift_out_mdi_bits routine for each field in the
+ * command. The format of a MII write instruction is as follows:
+ * <Preamble><SOF><OpCode><PhyAddr><RegAddr><Turnaround><Data>.
*/
mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
(PHY_OP_WRITE << 12) | (PHY_SOF << 14));
@@ -3100,10 +3134,10 @@ s32 e1000_phy_hw_reset(struct e1000_hw *hw)
e_dbg("Resetting Phy...\n");
if (hw->mac_type > e1000_82543) {
- /* Read the device control register and assert the E1000_CTRL_PHY_RST
- * bit. Then, take it out of reset.
+ /* Read the device control register and assert the
+ * E1000_CTRL_PHY_RST bit. Then, take it out of reset.
* For e1000 hardware, we delay for 10ms between the assert
- * and deassert.
+ * and de-assert.
*/
ctrl = er32(CTRL);
ew32(CTRL, ctrl | E1000_CTRL_PHY_RST);
@@ -3115,8 +3149,9 @@ s32 e1000_phy_hw_reset(struct e1000_hw *hw)
E1000_WRITE_FLUSH();
} else {
- /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
- * bit to put the PHY into reset. Then, take it out of reset.
+ /* Read the Extended Device Control Register, assert the
+ * PHY_RESET_DIR bit to put the PHY into reset. Then, take it
+ * out of reset.
*/
ctrl_ext = er32(CTRL_EXT);
ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
@@ -3301,7 +3336,8 @@ static s32 e1000_phy_igp_get_info(struct e1000_hw *hw,
e_dbg("e1000_phy_igp_get_info");
/* The downshift status is checked only once, after link is established,
- * and it stored in the hw->speed_downgraded parameter. */
+ * and it stored in the hw->speed_downgraded parameter.
+ */
phy_info->downshift = (e1000_downshift) hw->speed_downgraded;
/* IGP01E1000 does not need to support it. */
@@ -3327,7 +3363,9 @@ static s32 e1000_phy_igp_get_info(struct e1000_hw *hw,
if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
- /* Local/Remote Receiver Information are only valid at 1000 Mbps */
+ /* Local/Remote Receiver Information are only valid @ 1000
+ * Mbps
+ */
ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
if (ret_val)
return ret_val;
@@ -3379,7 +3417,8 @@ static s32 e1000_phy_m88_get_info(struct e1000_hw *hw,
e_dbg("e1000_phy_m88_get_info");
/* The downshift status is checked only once, after link is established,
- * and it stored in the hw->speed_downgraded parameter. */
+ * and it stored in the hw->speed_downgraded parameter.
+ */
phy_info->downshift = (e1000_downshift) hw->speed_downgraded;
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
@@ -3574,8 +3613,8 @@ s32 e1000_init_eeprom_params(struct e1000_hw *hw)
}
if (eeprom->type == e1000_eeprom_spi) {
- /* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to
- * 32KB (incremented by powers of 2).
+ /* eeprom_size will be an enum [0..8] that maps to eeprom sizes
+ * 128B to 32KB (incremented by powers of 2).
*/
/* Set to default value for initial eeprom read. */
eeprom->word_size = 64;
@@ -3585,8 +3624,9 @@ s32 e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom_size =
(eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT;
/* 256B eeprom size was not supported in earlier hardware, so we
- * bump eeprom_size up one to ensure that "1" (which maps to 256B)
- * is never the result used in the shifting logic below. */
+ * bump eeprom_size up one to ensure that "1" (which maps to
+ * 256B) is never the result used in the shifting logic below.
+ */
if (eeprom_size)
eeprom_size++;
@@ -3618,8 +3658,8 @@ static void e1000_raise_ee_clk(struct e1000_hw *hw, u32 *eecd)
*/
static void e1000_lower_ee_clk(struct e1000_hw *hw, u32 *eecd)
{
- /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
- * wait 50 microseconds.
+ /* Lower the clock input to the EEPROM (by clearing the SK bit), and
+ * then wait 50 microseconds.
*/
*eecd = *eecd & ~E1000_EECD_SK;
ew32(EECD, *eecd);
@@ -3651,10 +3691,11 @@ static void e1000_shift_out_ee_bits(struct e1000_hw *hw, u16 data, u16 count)
eecd |= E1000_EECD_DO;
}
do {
- /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
- * and then raising and then lowering the clock (the SK bit controls
- * the clock input to the EEPROM). A "0" is shifted out to the EEPROM
- * by setting "DI" to "0" and then raising and then lowering the clock.
+ /* A "1" is shifted out to the EEPROM by setting bit "DI" to a
+ * "1", and then raising and then lowering the clock (the SK bit
+ * controls the clock input to the EEPROM). A "0" is shifted
+ * out to the EEPROM by setting "DI" to "0" and then raising and
+ * then lowering the clock.
*/
eecd &= ~E1000_EECD_DI;
@@ -3691,9 +3732,9 @@ static u16 e1000_shift_in_ee_bits(struct e1000_hw *hw, u16 count)
/* In order to read a register from the EEPROM, we need to shift 'count'
* bits in from the EEPROM. Bits are "shifted in" by raising the clock
- * input to the EEPROM (setting the SK bit), and then reading the value of
- * the "DO" bit. During this "shifting in" process the "DI" bit should
- * always be clear.
+ * input to the EEPROM (setting the SK bit), and then reading the value
+ * of the "DO" bit. During this "shifting in" process the "DI" bit
+ * should always be clear.
*/
eecd = er32(EECD);
@@ -3945,8 +3986,8 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
if (eeprom->word_size == 0)
e1000_init_eeprom_params(hw);
- /* A check for invalid values: offset too large, too many words, and not
- * enough words.
+ /* A check for invalid values: offset too large, too many words, and
+ * not enough words.
*/
if ((offset >= eeprom->word_size)
|| (words > eeprom->word_size - offset) || (words == 0)) {
@@ -3964,7 +4005,8 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
return -E1000_ERR_EEPROM;
/* Set up the SPI or Microwire EEPROM for bit-bang reading. We have
- * acquired the EEPROM at this point, so any returns should release it */
+ * acquired the EEPROM at this point, so any returns should release it
+ */
if (eeprom->type == e1000_eeprom_spi) {
u16 word_in;
u8 read_opcode = EEPROM_READ_OPCODE_SPI;
@@ -3976,7 +4018,9 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
e1000_standby_eeprom(hw);
- /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+ /* Some SPI eeproms use the 8th address bit embedded in the
+ * opcode
+ */
if ((eeprom->address_bits == 8) && (offset >= 128))
read_opcode |= EEPROM_A8_OPCODE_SPI;
@@ -3985,11 +4029,13 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
e1000_shift_out_ee_bits(hw, (u16) (offset * 2),
eeprom->address_bits);
- /* Read the data. The address of the eeprom internally increments with
- * each byte (spi) being read, saving on the overhead of eeprom setup
- * and tear-down. The address counter will roll over if reading beyond
- * the size of the eeprom, thus allowing the entire memory to be read
- * starting from any offset. */
+ /* Read the data. The address of the eeprom internally
+ * increments with each byte (spi) being read, saving on the
+ * overhead of eeprom setup and tear-down. The address counter
+ * will roll over if reading beyond the size of the eeprom, thus
+ * allowing the entire memory to be read starting from any
+ * offset.
+ */
for (i = 0; i < words; i++) {
word_in = e1000_shift_in_ee_bits(hw, 16);
data[i] = (word_in >> 8) | (word_in << 8);
@@ -4003,8 +4049,9 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
e1000_shift_out_ee_bits(hw, (u16) (offset + i),
eeprom->address_bits);
- /* Read the data. For microwire, each word requires the overhead
- * of eeprom setup and tear-down. */
+ /* Read the data. For microwire, each word requires the
+ * overhead of eeprom setup and tear-down.
+ */
data[i] = e1000_shift_in_ee_bits(hw, 16);
e1000_standby_eeprom(hw);
}
@@ -4119,8 +4166,8 @@ static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
if (eeprom->word_size == 0)
e1000_init_eeprom_params(hw);
- /* A check for invalid values: offset too large, too many words, and not
- * enough words.
+ /* A check for invalid values: offset too large, too many words, and
+ * not enough words.
*/
if ((offset >= eeprom->word_size)
|| (words > eeprom->word_size - offset) || (words == 0)) {
@@ -4174,7 +4221,9 @@ static s32 e1000_write_eeprom_spi(struct e1000_hw *hw, u16 offset, u16 words,
e1000_standby_eeprom(hw);
- /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+ /* Some SPI eeproms use the 8th address bit embedded in the
+ * opcode
+ */
if ((eeprom->address_bits == 8) && (offset >= 128))
write_opcode |= EEPROM_A8_OPCODE_SPI;
@@ -4186,16 +4235,19 @@ static s32 e1000_write_eeprom_spi(struct e1000_hw *hw, u16 offset, u16 words,
/* Send the data */
- /* Loop to allow for up to whole page write (32 bytes) of eeprom */
+ /* Loop to allow for up to whole page write (32 bytes) of
+ * eeprom
+ */
while (widx < words) {
u16 word_out = data[widx];
word_out = (word_out >> 8) | (word_out << 8);
e1000_shift_out_ee_bits(hw, word_out, 16);
widx++;
- /* Some larger eeprom sizes are capable of a 32-byte PAGE WRITE
- * operation, while the smaller eeproms are capable of an 8-byte
- * PAGE WRITE operation. Break the inner loop to pass new address
+ /* Some larger eeprom sizes are capable of a 32-byte
+ * PAGE WRITE operation, while the smaller eeproms are
+ * capable of an 8-byte PAGE WRITE operation. Break the
+ * inner loop to pass new address
*/
if ((((offset + widx) * 2) % eeprom->page_size) == 0) {
e1000_standby_eeprom(hw);
@@ -4249,14 +4301,15 @@ static s32 e1000_write_eeprom_microwire(struct e1000_hw *hw, u16 offset,
/* Send the data */
e1000_shift_out_ee_bits(hw, data[words_written], 16);
- /* Toggle the CS line. This in effect tells the EEPROM to execute
- * the previous command.
+ /* Toggle the CS line. This in effect tells the EEPROM to
+ * execute the previous command.
*/
e1000_standby_eeprom(hw);
- /* Read DO repeatedly until it is high (equal to '1'). The EEPROM will
- * signal that the command has been completed by raising the DO signal.
- * If DO does not go high in 10 milliseconds, then error out.
+ /* Read DO repeatedly until it is high (equal to '1'). The
+ * EEPROM will signal that the command has been completed by
+ * raising the DO signal. If DO does not go high in 10
+ * milliseconds, then error out.
*/
for (i = 0; i < 200; i++) {
eecd = er32(EECD);
@@ -4483,7 +4536,8 @@ static void e1000_clear_vfta(struct e1000_hw *hw)
for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
/* If the offset we want to clear is the same offset of the
* manageability VLAN ID, then clear all bits except that of the
- * manageability unit */
+ * manageability unit
+ */
vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value);
E1000_WRITE_FLUSH();
@@ -4911,12 +4965,12 @@ void e1000_tbi_adjust_stats(struct e1000_hw *hw, struct e1000_hw_stats *stats,
* counters overcount this packet as a CRC error and undercount
* the packet as a good packet
*/
- /* This packet should not be counted as a CRC error. */
+ /* This packet should not be counted as a CRC error. */
stats->crcerrs--;
- /* This packet does count as a Good Packet Received. */
+ /* This packet does count as a Good Packet Received. */
stats->gprc++;
- /* Adjust the Good Octets received counters */
+ /* Adjust the Good Octets received counters */
carry_bit = 0x80000000 & stats->gorcl;
stats->gorcl += frame_len;
/* If the high bit of Gorcl (the low 32 bits of the Good Octets
@@ -5196,8 +5250,9 @@ static s32 e1000_check_polarity(struct e1000_hw *hw,
if (ret_val)
return ret_val;
- /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
- * find the polarity status */
+ /* If speed is 1000 Mbps, must read the
+ * IGP01E1000_PHY_PCS_INIT_REG to find the polarity status
+ */
if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
@@ -5213,8 +5268,9 @@ static s32 e1000_check_polarity(struct e1000_hw *hw,
e1000_rev_polarity_reversed :
e1000_rev_polarity_normal;
} else {
- /* For 10 Mbps, read the polarity bit in the status register. (for
- * 100 Mbps this bit is always 0) */
+ /* For 10 Mbps, read the polarity bit in the status
+ * register. (for 100 Mbps this bit is always 0)
+ */
*polarity =
(phy_data & IGP01E1000_PSSR_POLARITY_REVERSED) ?
e1000_rev_polarity_reversed :
@@ -5374,8 +5430,9 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
}
} else {
if (hw->dsp_config_state == e1000_dsp_config_activated) {
- /* Save off the current value of register 0x2F5B to be restored at
- * the end of the routines. */
+ /* Save off the current value of register 0x2F5B to be
+ * restored at the end of the routines.
+ */
ret_val =
e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
@@ -5391,7 +5448,7 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
msleep(20);
ret_val = e1000_write_phy_reg(hw, 0x0000,
- IGP01E1000_IEEE_FORCE_GIGA);
+ IGP01E1000_IEEE_FORCE_GIGA);
if (ret_val)
return ret_val;
for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
@@ -5412,7 +5469,7 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
}
ret_val = e1000_write_phy_reg(hw, 0x0000,
- IGP01E1000_IEEE_RESTART_AUTONEG);
+ IGP01E1000_IEEE_RESTART_AUTONEG);
if (ret_val)
return ret_val;
@@ -5429,8 +5486,9 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
}
if (hw->ffe_config_state == e1000_ffe_config_active) {
- /* Save off the current value of register 0x2F5B to be restored at
- * the end of the routines. */
+ /* Save off the current value of register 0x2F5B to be
+ * restored at the end of the routines.
+ */
ret_val =
e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
@@ -5446,7 +5504,7 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
msleep(20);
ret_val = e1000_write_phy_reg(hw, 0x0000,
- IGP01E1000_IEEE_FORCE_GIGA);
+ IGP01E1000_IEEE_FORCE_GIGA);
if (ret_val)
return ret_val;
ret_val =
@@ -5456,7 +5514,7 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
return ret_val;
ret_val = e1000_write_phy_reg(hw, 0x0000,
- IGP01E1000_IEEE_RESTART_AUTONEG);
+ IGP01E1000_IEEE_RESTART_AUTONEG);
if (ret_val)
return ret_val;
@@ -5542,8 +5600,9 @@ static s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active)
return E1000_SUCCESS;
/* During driver activity LPLU should not be used or it will attain link
- * from the lowest speeds starting from 10Mbps. The capability is used for
- * Dx transitions and states */
+ * from the lowest speeds starting from 10Mbps. The capability is used
+ * for Dx transitions and states
+ */
if (hw->mac_type == e1000_82541_rev_2
|| hw->mac_type == e1000_82547_rev_2) {
ret_val =
@@ -5563,10 +5622,11 @@ static s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active)
return ret_val;
}
- /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
- * Dx states where the power conservation is most important. During
- * driver activity we should enable SmartSpeed, so performance is
- * maintained. */
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
if (hw->smart_speed == e1000_smart_speed_on) {
ret_val =
e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 294da56b824c..8502c625dbef 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -239,7 +239,6 @@ struct net_device *e1000_get_hw_dev(struct e1000_hw *hw)
* e1000_init_module is the first routine called when the driver is
* loaded. All it does is register with the PCI subsystem.
**/
-
static int __init e1000_init_module(void)
{
int ret;
@@ -266,7 +265,6 @@ module_init(e1000_init_module);
* e1000_exit_module is called just before the driver is removed
* from memory.
**/
-
static void __exit e1000_exit_module(void)
{
pci_unregister_driver(&e1000_driver);
@@ -301,7 +299,6 @@ static void e1000_free_irq(struct e1000_adapter *adapter)
* e1000_irq_disable - Mask off interrupt generation on the NIC
* @adapter: board private structure
**/
-
static void e1000_irq_disable(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
@@ -315,7 +312,6 @@ static void e1000_irq_disable(struct e1000_adapter *adapter)
* e1000_irq_enable - Enable default interrupt generation settings
* @adapter: board private structure
**/
-
static void e1000_irq_enable(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
@@ -398,11 +394,12 @@ static void e1000_configure(struct e1000_adapter *adapter)
e1000_configure_rx(adapter);
/* call E1000_DESC_UNUSED which always leaves
* at least 1 descriptor unused to make sure
- * next_to_use != next_to_clean */
+ * next_to_use != next_to_clean
+ */
for (i = 0; i < adapter->num_rx_queues; i++) {
struct e1000_rx_ring *ring = &adapter->rx_ring[i];
adapter->alloc_rx_buf(adapter, ring,
- E1000_DESC_UNUSED(ring));
+ E1000_DESC_UNUSED(ring));
}
}
@@ -433,9 +430,7 @@ int e1000_up(struct e1000_adapter *adapter)
* The phy may be powered down to save power and turn off link when the
* driver is unloaded and wake on lan is not enabled (among others)
* *** this routine MUST be followed by a call to e1000_reset ***
- *
**/
-
void e1000_power_up_phy(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
@@ -444,7 +439,8 @@ void e1000_power_up_phy(struct e1000_adapter *adapter)
/* Just clear the power down bit to wake the phy back up */
if (hw->media_type == e1000_media_type_copper) {
/* according to the manual, the phy will retain its
- * settings across a power-down/up cycle */
+ * settings across a power-down/up cycle
+ */
e1000_read_phy_reg(hw, PHY_CTRL, &mii_reg);
mii_reg &= ~MII_CR_POWER_DOWN;
e1000_write_phy_reg(hw, PHY_CTRL, mii_reg);
@@ -459,7 +455,8 @@ static void e1000_power_down_phy(struct e1000_adapter *adapter)
* The PHY cannot be powered down if any of the following is true *
* (a) WoL is enabled
* (b) AMT is active
- * (c) SoL/IDER session is active */
+ * (c) SoL/IDER session is active
+ */
if (!adapter->wol && hw->mac_type >= e1000_82540 &&
hw->media_type == e1000_media_type_copper) {
u16 mii_reg = 0;
@@ -529,8 +526,7 @@ void e1000_down(struct e1000_adapter *adapter)
e1000_irq_disable(adapter);
- /*
- * Setting DOWN must be after irq_disable to prevent
+ /* Setting DOWN must be after irq_disable to prevent
* a screaming interrupt. Setting DOWN also prevents
* tasks from rescheduling.
*/
@@ -627,14 +623,14 @@ void e1000_reset(struct e1000_adapter *adapter)
* rounded up to the next 1KB and expressed in KB. Likewise,
* the Rx FIFO should be large enough to accommodate at least
* one full receive packet and is similarly rounded up and
- * expressed in KB. */
+ * expressed in KB.
+ */
pba = er32(PBA);
/* upper 16 bits has Tx packet buffer allocation size in KB */
tx_space = pba >> 16;
/* lower 16 bits has Rx packet buffer allocation size in KB */
pba &= 0xffff;
- /*
- * the tx fifo also stores 16 bytes of information about the tx
+ /* the Tx fifo also stores 16 bytes of information about the Tx
* but don't include ethernet FCS because hardware appends it
*/
min_tx_space = (hw->max_frame_size +
@@ -649,7 +645,8 @@ void e1000_reset(struct e1000_adapter *adapter)
/* If current Tx allocation is less than the min Tx FIFO size,
* and the min Tx FIFO size is less than the current Rx FIFO
- * allocation, take space away from current Rx allocation */
+ * allocation, take space away from current Rx allocation
+ */
if (tx_space < min_tx_space &&
((min_tx_space - tx_space) < pba)) {
pba = pba - (min_tx_space - tx_space);
@@ -663,8 +660,9 @@ void e1000_reset(struct e1000_adapter *adapter)
break;
}
- /* if short on rx space, rx wins and must trump tx
- * adjustment or use Early Receive if available */
+ /* if short on Rx space, Rx wins and must trump Tx
+ * adjustment or use Early Receive if available
+ */
if (pba < min_rx_space)
pba = min_rx_space;
}
@@ -672,8 +670,7 @@ void e1000_reset(struct e1000_adapter *adapter)
ew32(PBA, pba);
- /*
- * flow control settings:
+ /* flow control settings:
* The high water mark must be low enough to fit one full frame
* (or the size used for early receive) above it in the Rx FIFO.
* Set it to the lower of:
@@ -707,7 +704,8 @@ void e1000_reset(struct e1000_adapter *adapter)
u32 ctrl = er32(CTRL);
/* clear phy power management bit if we are in gig only mode,
* which if enabled will attempt negotiation to 100Mb, which
- * can cause a loss of link at power off or driver unload */
+ * can cause a loss of link at power off or driver unload
+ */
ctrl &= ~E1000_CTRL_SWDPIN3;
ew32(CTRL, ctrl);
}
@@ -808,9 +806,8 @@ static int e1000_is_need_ioport(struct pci_dev *pdev)
static netdev_features_t e1000_fix_features(struct net_device *netdev,
netdev_features_t features)
{
- /*
- * Since there is no support for separate rx/tx vlan accel
- * enable/disable make sure tx flag is always in same state as rx.
+ /* Since there is no support for separate Rx/Tx vlan accel
+ * enable/disable make sure Tx flag is always in same state as Rx.
*/
if (features & NETIF_F_HW_VLAN_RX)
features |= NETIF_F_HW_VLAN_TX;
@@ -1012,16 +1009,14 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_sw_init;
- /*
- * there is a workaround being applied below that limits
+ /* there is a workaround being applied below that limits
* 64-bit DMA addresses to 64-bit hardware. There are some
* 32-bit adapters that Tx hang when given 64-bit DMA addresses
*/
pci_using_dac = 0;
if ((hw->bus_type == e1000_bus_type_pcix) &&
!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
- /*
- * according to DMA-API-HOWTO, coherent calls will always
+ /* according to DMA-API-HOWTO, coherent calls will always
* succeed if the set call did
*/
dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
@@ -1099,7 +1094,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* before reading the EEPROM, reset the controller to
- * put the device in a known good starting state */
+ * put the device in a known good starting state
+ */
e1000_reset_hw(hw);
@@ -1107,8 +1103,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (e1000_validate_eeprom_checksum(hw) < 0) {
e_err(probe, "The EEPROM Checksum Is Not Valid\n");
e1000_dump_eeprom(adapter);
- /*
- * set MAC address to all zeroes to invalidate and temporary
+ /* set MAC address to all zeroes to invalidate and temporary
* disable this device for the user. This blocks regular
* traffic while still permitting ethtool ioctls from reaching
* the hardware as well as allowing the user to run the
@@ -1123,9 +1118,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* don't block initalization here due to bad MAC address */
memcpy(netdev->dev_addr, hw->mac_addr, netdev->addr_len);
- memcpy(netdev->perm_addr, hw->mac_addr, netdev->addr_len);
- if (!is_valid_ether_addr(netdev->perm_addr))
+ if (!is_valid_ether_addr(netdev->dev_addr))
e_err(probe, "Invalid MAC Address\n");
@@ -1170,7 +1164,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* now that we have the eeprom settings, apply the special cases
* where the eeprom may be wrong or the board simply won't support
- * wake on lan on a particular port */
+ * wake on lan on a particular port
+ */
switch (pdev->device) {
case E1000_DEV_ID_82546GB_PCIE:
adapter->eeprom_wol = 0;
@@ -1178,7 +1173,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case E1000_DEV_ID_82546EB_FIBER:
case E1000_DEV_ID_82546GB_FIBER:
/* Wake events only supported on port A for dual fiber
- * regardless of eeprom setting */
+ * regardless of eeprom setting
+ */
if (er32(STATUS) & E1000_STATUS_FUNC_1)
adapter->eeprom_wol = 0;
break;
@@ -1271,7 +1267,6 @@ err_pci_reg:
* Hot-Plug event, or because the driver is going to be removed from
* memory.
**/
-
static void e1000_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
@@ -1307,7 +1302,6 @@ static void e1000_remove(struct pci_dev *pdev)
* e1000_sw_init initializes the Adapter private data structure.
* e1000_init_hw_struct MUST be called before this function
**/
-
static int e1000_sw_init(struct e1000_adapter *adapter)
{
adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
@@ -1338,7 +1332,6 @@ static int e1000_sw_init(struct e1000_adapter *adapter)
* We allocate one ring per queue at run-time since we don't know the
* number of queues at compile-time.
**/
-
static int e1000_alloc_queues(struct e1000_adapter *adapter)
{
adapter->tx_ring = kcalloc(adapter->num_tx_queues,
@@ -1368,7 +1361,6 @@ static int e1000_alloc_queues(struct e1000_adapter *adapter)
* handler is registered with the OS, the watchdog task is started,
* and the stack is notified that the interface is ready.
**/
-
static int e1000_open(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1402,7 +1394,8 @@ static int e1000_open(struct net_device *netdev)
/* before we allocate an interrupt, we must be ready to handle it.
* Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
* as soon as we call pci_request_irq, so we have to setup our
- * clean_rx handler before we do so. */
+ * clean_rx handler before we do so.
+ */
e1000_configure(adapter);
err = e1000_request_irq(adapter);
@@ -1445,7 +1438,6 @@ err_setup_tx:
* needs to be disabled. A global MAC reset is issued to stop the
* hardware, and all transmit and receive resources are freed.
**/
-
static int e1000_close(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1460,10 +1452,11 @@ static int e1000_close(struct net_device *netdev)
e1000_free_all_rx_resources(adapter);
/* 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) */
+ * the same ID is registered on the host OS (let 8021q kill it)
+ */
if ((hw->mng_cookie.status &
- E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
- !test_bit(adapter->mng_vlan_id, adapter->active_vlans)) {
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
+ !test_bit(adapter->mng_vlan_id, adapter->active_vlans)) {
e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
}
@@ -1484,7 +1477,8 @@ static bool e1000_check_64k_bound(struct e1000_adapter *adapter, void *start,
unsigned long end = begin + len;
/* First rev 82545 and 82546 need to not allow any memory
- * write location to cross 64k boundary due to errata 23 */
+ * write location to cross 64k boundary due to errata 23
+ */
if (hw->mac_type == e1000_82545 ||
hw->mac_type == e1000_ce4100 ||
hw->mac_type == e1000_82546) {
@@ -1501,7 +1495,6 @@ static bool e1000_check_64k_bound(struct e1000_adapter *adapter, void *start,
*
* Return 0 on success, negative on failure
**/
-
static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
struct e1000_tx_ring *txdr)
{
@@ -1510,11 +1503,8 @@ static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
size = sizeof(struct e1000_buffer) * txdr->count;
txdr->buffer_info = vzalloc(size);
- if (!txdr->buffer_info) {
- e_err(probe, "Unable to allocate memory for the Tx descriptor "
- "ring\n");
+ if (!txdr->buffer_info)
return -ENOMEM;
- }
/* round up to nearest 4K */
@@ -1578,7 +1568,6 @@ setup_tx_desc_die:
*
* Return 0 on success, negative on failure
**/
-
int e1000_setup_all_tx_resources(struct e1000_adapter *adapter)
{
int i, err = 0;
@@ -1603,7 +1592,6 @@ int e1000_setup_all_tx_resources(struct e1000_adapter *adapter)
*
* Configure the Tx unit of the MAC after a reset.
**/
-
static void e1000_configure_tx(struct e1000_adapter *adapter)
{
u64 tdba;
@@ -1624,8 +1612,10 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
ew32(TDBAL, (tdba & 0x00000000ffffffffULL));
ew32(TDT, 0);
ew32(TDH, 0);
- adapter->tx_ring[0].tdh = ((hw->mac_type >= e1000_82543) ? E1000_TDH : E1000_82542_TDH);
- adapter->tx_ring[0].tdt = ((hw->mac_type >= e1000_82543) ? E1000_TDT : E1000_82542_TDT);
+ adapter->tx_ring[0].tdh = ((hw->mac_type >= e1000_82543) ?
+ E1000_TDH : E1000_82542_TDH);
+ adapter->tx_ring[0].tdt = ((hw->mac_type >= e1000_82543) ?
+ E1000_TDT : E1000_82542_TDT);
break;
}
@@ -1680,7 +1670,8 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
adapter->txd_cmd |= E1000_TXD_CMD_RS;
/* Cache if we're 82544 running in PCI-X because we'll
- * need this to apply a workaround later in the send path. */
+ * need this to apply a workaround later in the send path.
+ */
if (hw->mac_type == e1000_82544 &&
hw->bus_type == e1000_bus_type_pcix)
adapter->pcix_82544 = true;
@@ -1696,7 +1687,6 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
*
* Returns 0 on success, negative on failure
**/
-
static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
struct e1000_rx_ring *rxdr)
{
@@ -1705,11 +1695,8 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
size = sizeof(struct e1000_buffer) * rxdr->count;
rxdr->buffer_info = vzalloc(size);
- if (!rxdr->buffer_info) {
- e_err(probe, "Unable to allocate memory for the Rx descriptor "
- "ring\n");
+ if (!rxdr->buffer_info)
return -ENOMEM;
- }
desc_len = sizeof(struct e1000_rx_desc);
@@ -1778,7 +1765,6 @@ setup_rx_desc_die:
*
* Return 0 on success, negative on failure
**/
-
int e1000_setup_all_rx_resources(struct e1000_adapter *adapter)
{
int i, err = 0;
@@ -1847,7 +1833,8 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
/* This is useful for sniffing bad packets. */
if (adapter->netdev->features & NETIF_F_RXALL) {
/* UPE and MPE will be handled by normal PROMISC logic
- * in e1000e_set_rx_mode */
+ * in e1000e_set_rx_mode
+ */
rctl |= (E1000_RCTL_SBP | /* Receive bad packets */
E1000_RCTL_BAM | /* RX All Bcast Pkts */
E1000_RCTL_PMCF); /* RX All MAC Ctrl Pkts */
@@ -1869,7 +1856,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
*
* Configure the Rx unit of the MAC after a reset.
**/
-
static void e1000_configure_rx(struct e1000_adapter *adapter)
{
u64 rdba;
@@ -1902,7 +1888,8 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
}
/* Setup the HW Rx Head and Tail Descriptor Pointers and
- * the Base and Length of the Rx Descriptor Ring */
+ * the Base and Length of the Rx Descriptor Ring
+ */
switch (adapter->num_rx_queues) {
case 1:
default:
@@ -1912,8 +1899,10 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
ew32(RDBAL, (rdba & 0x00000000ffffffffULL));
ew32(RDT, 0);
ew32(RDH, 0);
- adapter->rx_ring[0].rdh = ((hw->mac_type >= e1000_82543) ? E1000_RDH : E1000_82542_RDH);
- adapter->rx_ring[0].rdt = ((hw->mac_type >= e1000_82543) ? E1000_RDT : E1000_82542_RDT);
+ adapter->rx_ring[0].rdh = ((hw->mac_type >= e1000_82543) ?
+ E1000_RDH : E1000_82542_RDH);
+ adapter->rx_ring[0].rdt = ((hw->mac_type >= e1000_82543) ?
+ E1000_RDT : E1000_82542_RDT);
break;
}
@@ -1939,7 +1928,6 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
*
* Free all transmit software resources
**/
-
static void e1000_free_tx_resources(struct e1000_adapter *adapter,
struct e1000_tx_ring *tx_ring)
{
@@ -1962,7 +1950,6 @@ static void e1000_free_tx_resources(struct e1000_adapter *adapter,
*
* Free all transmit software resources
**/
-
void e1000_free_all_tx_resources(struct e1000_adapter *adapter)
{
int i;
@@ -1997,7 +1984,6 @@ static void e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter,
* @adapter: board private structure
* @tx_ring: ring to be cleaned
**/
-
static void e1000_clean_tx_ring(struct e1000_adapter *adapter,
struct e1000_tx_ring *tx_ring)
{
@@ -2033,7 +2019,6 @@ static void e1000_clean_tx_ring(struct e1000_adapter *adapter,
* e1000_clean_all_tx_rings - Free Tx Buffers for all queues
* @adapter: board private structure
**/
-
static void e1000_clean_all_tx_rings(struct e1000_adapter *adapter)
{
int i;
@@ -2049,7 +2034,6 @@ static void e1000_clean_all_tx_rings(struct e1000_adapter *adapter)
*
* Free all receive software resources
**/
-
static void e1000_free_rx_resources(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring)
{
@@ -2072,7 +2056,6 @@ static void e1000_free_rx_resources(struct e1000_adapter *adapter,
*
* Free all receive software resources
**/
-
void e1000_free_all_rx_resources(struct e1000_adapter *adapter)
{
int i;
@@ -2086,7 +2069,6 @@ void e1000_free_all_rx_resources(struct e1000_adapter *adapter)
* @adapter: board private structure
* @rx_ring: ring to free buffers from
**/
-
static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring)
{
@@ -2145,7 +2127,6 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
* e1000_clean_all_rx_rings - Free Rx Buffers for all queues
* @adapter: board private structure
**/
-
static void e1000_clean_all_rx_rings(struct e1000_adapter *adapter)
{
int i;
@@ -2205,7 +2186,6 @@ static void e1000_leave_82542_rst(struct e1000_adapter *adapter)
*
* Returns 0 on success, negative on failure
**/
-
static int e1000_set_mac(struct net_device *netdev, void *p)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -2240,7 +2220,6 @@ static int e1000_set_mac(struct net_device *netdev, void *p)
* responsible for configuring the hardware for proper unicast, multicast,
* promiscuous mode, and all-multi behavior.
**/
-
static void e1000_set_rx_mode(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -2253,10 +2232,8 @@ static void e1000_set_rx_mode(struct net_device *netdev)
int mta_reg_count = E1000_NUM_MTA_REGISTERS;
u32 *mcarray = kcalloc(mta_reg_count, sizeof(u32), GFP_ATOMIC);
- if (!mcarray) {
- e_err(probe, "memory allocation failed\n");
+ if (!mcarray)
return;
- }
/* Check for Promiscuous and All Multicast modes */
@@ -2326,10 +2303,10 @@ static void e1000_set_rx_mode(struct net_device *netdev)
}
/* write the hash table completely, write from bottom to avoid
- * both stupid write combining chipsets, and flushing each write */
+ * both stupid write combining chipsets, and flushing each write
+ */
for (i = mta_reg_count - 1; i >= 0 ; i--) {
- /*
- * If we are on an 82544 has an errata where writing odd
+ /* If we are on an 82544 has an errata where writing odd
* offsets overwrites the previous even offset, but writing
* backwards over the range solves the issue by always
* writing the odd offset first
@@ -2467,8 +2444,8 @@ static void e1000_watchdog(struct work_struct *work)
bool txb2b = true;
/* update snapshot of PHY registers on LSC */
e1000_get_speed_and_duplex(hw,
- &adapter->link_speed,
- &adapter->link_duplex);
+ &adapter->link_speed,
+ &adapter->link_duplex);
ctrl = er32(CTRL);
pr_info("%s NIC Link is Up %d Mbps %s, "
@@ -2542,7 +2519,8 @@ link_up:
/* 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). */
+ * (Do the reset outside of interrupt context).
+ */
adapter->tx_timeout_count++;
schedule_work(&adapter->reset_task);
/* exit immediately since reset is imminent */
@@ -2552,8 +2530,7 @@ link_up:
/* Simple mode for Interrupt Throttle Rate (ITR) */
if (hw->mac_type >= e1000_82540 && adapter->itr_setting == 4) {
- /*
- * Symmetric Tx/Rx gets a reduced ITR=2000;
+ /* Symmetric Tx/Rx gets a reduced ITR=2000;
* Total asymmetrical Tx or Rx gets ITR=8000;
* everyone else is between 2000-8000.
*/
@@ -2668,18 +2645,16 @@ static void e1000_set_itr(struct e1000_adapter *adapter)
goto set_itr_now;
}
- adapter->tx_itr = e1000_update_itr(adapter,
- adapter->tx_itr,
- adapter->total_tx_packets,
- adapter->total_tx_bytes);
+ adapter->tx_itr = e1000_update_itr(adapter, adapter->tx_itr,
+ adapter->total_tx_packets,
+ adapter->total_tx_bytes);
/* conservative mode (itr 3) eliminates the lowest_latency setting */
if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency)
adapter->tx_itr = low_latency;
- adapter->rx_itr = e1000_update_itr(adapter,
- adapter->rx_itr,
- adapter->total_rx_packets,
- adapter->total_rx_bytes);
+ adapter->rx_itr = e1000_update_itr(adapter, adapter->rx_itr,
+ adapter->total_rx_packets,
+ adapter->total_rx_bytes);
/* conservative mode (itr 3) eliminates the lowest_latency setting */
if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
adapter->rx_itr = low_latency;
@@ -2705,10 +2680,11 @@ set_itr_now:
if (new_itr != adapter->itr) {
/* this attempts to bias the interrupt rate towards Bulk
* by adding intermediate steps when interrupt rate is
- * increasing */
+ * increasing
+ */
new_itr = new_itr > adapter->itr ?
- min(adapter->itr + (new_itr >> 2), new_itr) :
- new_itr;
+ min(adapter->itr + (new_itr >> 2), new_itr) :
+ new_itr;
adapter->itr = new_itr;
ew32(ITR, 1000000000 / (new_itr * 256));
}
@@ -2870,7 +2846,8 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
/* Workaround for Controller erratum --
* descriptor for non-tso packet in a linear SKB that follows a
* tso gets written back prematurely before the data is fully
- * DMA'd to the controller */
+ * DMA'd to the controller
+ */
if (!skb->data_len && tx_ring->last_tx_tso &&
!skb_is_gso(skb)) {
tx_ring->last_tx_tso = false;
@@ -2878,7 +2855,8 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
}
/* Workaround for premature desc write-backs
- * in TSO mode. Append 4-byte sentinel desc */
+ * in TSO mode. Append 4-byte sentinel desc
+ */
if (unlikely(mss && !nr_frags && size == len && size > 8))
size -= 4;
/* work-around for errata 10 and it applies
@@ -2891,7 +2869,8 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
size = 2015;
/* Workaround for potential 82544 hang in PCI-X. Avoid
- * terminating buffers within evenly-aligned dwords. */
+ * terminating buffers within evenly-aligned dwords.
+ */
if (unlikely(adapter->pcix_82544 &&
!((unsigned long)(skb->data + offset + size - 1) & 4) &&
size > 4))
@@ -2903,7 +2882,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
buffer_info->mapped_as_page = false;
buffer_info->dma = dma_map_single(&pdev->dev,
skb->data + offset,
- size, DMA_TO_DEVICE);
+ size, DMA_TO_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma))
goto dma_error;
buffer_info->next_to_watch = i;
@@ -2934,12 +2913,15 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
/* Workaround for premature desc write-backs
- * in TSO mode. Append 4-byte sentinel desc */
- if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8))
+ * in TSO mode. Append 4-byte sentinel desc
+ */
+ if (unlikely(mss && f == (nr_frags-1) &&
+ size == len && size > 8))
size -= 4;
/* Workaround for potential 82544 hang in PCI-X.
* Avoid terminating buffers within evenly-aligned
- * dwords. */
+ * dwords.
+ */
bufend = (unsigned long)
page_to_phys(skb_frag_page(frag));
bufend += offset + size - 1;
@@ -3003,7 +2985,7 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
if (likely(tx_flags & E1000_TX_FLAGS_TSO)) {
txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
- E1000_TXD_CMD_TSE;
+ E1000_TXD_CMD_TSE;
txd_upper |= E1000_TXD_POPTS_TXSM << 8;
if (likely(tx_flags & E1000_TX_FLAGS_IPV4))
@@ -3044,13 +3026,15 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
* applicable for weak-ordered memory model archs,
- * such as IA-64). */
+ * such as IA-64).
+ */
wmb();
tx_ring->next_to_use = i;
writel(i, hw->hw_addr + tx_ring->tdt);
/* we need this if more than one processor can write to our tail
- * at a time, it syncronizes IO on IA64/Altix systems */
+ * at a time, it synchronizes IO on IA64/Altix systems
+ */
mmiowb();
}
@@ -3099,11 +3083,13 @@ static int __e1000_maybe_stop_tx(struct net_device *netdev, int size)
netif_stop_queue(netdev);
/* Herbert's original patch had:
* smp_mb__after_netif_stop_queue();
- * but since that doesn't exist yet, just open code it. */
+ * but since that doesn't exist yet, just open code it.
+ */
smp_mb();
/* We need to check again in a case another CPU has just
- * made room available. */
+ * made room available.
+ */
if (likely(E1000_DESC_UNUSED(tx_ring) < size))
return -EBUSY;
@@ -3114,7 +3100,7 @@ static int __e1000_maybe_stop_tx(struct net_device *netdev, int size)
}
static int e1000_maybe_stop_tx(struct net_device *netdev,
- struct e1000_tx_ring *tx_ring, int size)
+ struct e1000_tx_ring *tx_ring, int size)
{
if (likely(E1000_DESC_UNUSED(tx_ring) >= size))
return 0;
@@ -3138,10 +3124,11 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
int tso;
unsigned int f;
- /* This goes back to the question of how to logically map a tx queue
+ /* This goes back to the question of how to logically map a Tx queue
* to a flow. Right now, performance is impacted slightly negatively
- * if using multiple tx queues. If the stack breaks away from a
- * single qdisc implementation, we can look at this again. */
+ * if using multiple Tx queues. If the stack breaks away from a
+ * single qdisc implementation, we can look at this again.
+ */
tx_ring = adapter->tx_ring;
if (unlikely(skb->len <= 0)) {
@@ -3166,7 +3153,8 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
* initiating the DMA for each buffer. The calc is:
* 4 = ceil(buffer len/mss). To make sure we don't
* overrun the FIFO, adjust the max buffer len if mss
- * drops. */
+ * drops.
+ */
if (mss) {
u8 hdr_len;
max_per_txd = min(mss << 2, max_per_txd);
@@ -3182,8 +3170,10 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
* this hardware's requirements
* NOTE: this is a TSO only workaround
* if end byte alignment not correct move us
- * into the next dword */
- if ((unsigned long)(skb_tail_pointer(skb) - 1) & 4)
+ * into the next dword
+ */
+ if ((unsigned long)(skb_tail_pointer(skb) - 1)
+ & 4)
break;
/* fall through */
pull_size = min((unsigned int)4, skb->data_len);
@@ -3231,7 +3221,8 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
count += nr_frags;
/* need: count + 2 desc gap to keep tail from touching
- * head, otherwise try next time */
+ * head, otherwise try next time
+ */
if (unlikely(e1000_maybe_stop_tx(netdev, tx_ring, count + 2)))
return NETDEV_TX_BUSY;
@@ -3270,7 +3261,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
tx_flags |= E1000_TX_FLAGS_NO_FCS;
count = e1000_tx_map(adapter, tx_ring, skb, first, max_per_txd,
- nr_frags, mss);
+ nr_frags, mss);
if (count) {
netdev_sent_queue(netdev, skb->len);
@@ -3372,9 +3363,7 @@ static void e1000_dump(struct e1000_adapter *adapter)
/* Print Registers */
e1000_regdump(adapter);
- /*
- * transmit dump
- */
+ /* transmit dump */
pr_info("TX Desc ring0 dump\n");
/* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
@@ -3435,9 +3424,7 @@ static void e1000_dump(struct e1000_adapter *adapter)
}
rx_ring_summary:
- /*
- * receive dump
- */
+ /* receive dump */
pr_info("\nRX Desc ring dump\n");
/* Legacy Receive Descriptor Format
@@ -3502,7 +3489,6 @@ exit:
* e1000_tx_timeout - Respond to a Tx Hang
* @netdev: network interface device structure
**/
-
static void e1000_tx_timeout(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3530,7 +3516,6 @@ static void e1000_reset_task(struct work_struct *work)
* Returns the address of the device statistics structure.
* The statistics are actually updated from the watchdog.
**/
-
static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
{
/* only return the current stats */
@@ -3544,7 +3529,6 @@ static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
*
* Returns 0 on success, negative on failure
**/
-
static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3581,8 +3565,9 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
* means we reserve 2 more, this pushes us to allocate from the next
* larger slab size.
* i.e. RXBUFFER_2048 --> size-4096 slab
- * however with the new *_jumbo_rx* routines, jumbo receives will use
- * fragmented skbs */
+ * however with the new *_jumbo_rx* routines, jumbo receives will use
+ * fragmented skbs
+ */
if (max_frame <= E1000_RXBUFFER_2048)
adapter->rx_buffer_len = E1000_RXBUFFER_2048;
@@ -3617,7 +3602,6 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
* e1000_update_stats - Update the board statistics counters
* @adapter: board private structure
**/
-
void e1000_update_stats(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -3628,8 +3612,7 @@ void e1000_update_stats(struct e1000_adapter *adapter)
#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
- /*
- * Prevent stats update while adapter is being reset, or if the pci
+ /* Prevent stats update while adapter is being reset, or if the pci
* connection is down.
*/
if (adapter->link_speed == 0)
@@ -3719,7 +3702,8 @@ void e1000_update_stats(struct e1000_adapter *adapter)
/* Rx Errors */
/* RLEC on some newer hardware can be incorrect so build
- * our own version based on RUC and ROC */
+ * our own version based on RUC and ROC
+ */
netdev->stats.rx_errors = adapter->stats.rxerrc +
adapter->stats.crcerrs + adapter->stats.algnerrc +
adapter->stats.ruc + adapter->stats.roc +
@@ -3773,7 +3757,6 @@ void e1000_update_stats(struct e1000_adapter *adapter)
* @irq: interrupt number
* @data: pointer to a network interface device structure
**/
-
static irqreturn_t e1000_intr(int irq, void *data)
{
struct net_device *netdev = data;
@@ -3784,8 +3767,7 @@ static irqreturn_t e1000_intr(int irq, void *data)
if (unlikely((!icr)))
return IRQ_NONE; /* Not our interrupt */
- /*
- * we might have caused the interrupt, but the above
+ /* we might have caused the interrupt, but the above
* read cleared it, and just in case the driver is
* down there is nothing to do so return handled
*/
@@ -3811,7 +3793,8 @@ static irqreturn_t e1000_intr(int irq, void *data)
__napi_schedule(&adapter->napi);
} else {
/* this really should not happen! if it does it is basically a
- * bug, but not a hard error, so enable ints and continue */
+ * bug, but not a hard error, so enable ints and continue
+ */
if (!test_bit(__E1000_DOWN, &adapter->flags))
e1000_irq_enable(adapter);
}
@@ -3825,7 +3808,8 @@ static irqreturn_t e1000_intr(int irq, void *data)
**/
static int e1000_clean(struct napi_struct *napi, int budget)
{
- struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+ struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter,
+ napi);
int tx_clean_complete = 0, work_done = 0;
tx_clean_complete = e1000_clean_tx_irq(adapter, &adapter->tx_ring[0]);
@@ -3916,11 +3900,12 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
if (adapter->detect_tx_hung) {
/* Detect a transmit hang in hardware, this serializes the
- * check with the clearing of time_stamp and movement of i */
+ * check with the clearing of time_stamp and movement of i
+ */
adapter->detect_tx_hung = false;
if (tx_ring->buffer_info[eop].time_stamp &&
time_after(jiffies, tx_ring->buffer_info[eop].time_stamp +
- (adapter->tx_timeout_factor * HZ)) &&
+ (adapter->tx_timeout_factor * HZ)) &&
!(er32(STATUS) & E1000_STATUS_TXOFF)) {
/* detected Tx unit hang */
@@ -3963,7 +3948,6 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
* @csum: receive descriptor csum field
* @sk_buff: socket buffer with received data
**/
-
static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
u32 csum, struct sk_buff *skb)
{
@@ -3999,7 +3983,7 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
* e1000_consume_page - helper function
**/
static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
- u16 length)
+ u16 length)
{
bi->page = NULL;
skb->len += length;
@@ -4095,11 +4079,11 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
if (TBI_ACCEPT(hw, status, rx_desc->errors, length,
last_byte)) {
spin_lock_irqsave(&adapter->stats_lock,
- irq_flags);
+ irq_flags);
e1000_tbi_adjust_stats(hw, &adapter->stats,
length, mapped);
spin_unlock_irqrestore(&adapter->stats_lock,
- irq_flags);
+ irq_flags);
length--;
} else {
if (netdev->features & NETIF_F_RXALL)
@@ -4107,7 +4091,8 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
/* recycle both page and skb */
buffer_info->skb = skb;
/* an error means any chain goes out the window
- * too */
+ * too
+ */
if (rx_ring->rx_skb_top)
dev_kfree_skb(rx_ring->rx_skb_top);
rx_ring->rx_skb_top = NULL;
@@ -4123,7 +4108,7 @@ process_skb:
/* this is the beginning of a chain */
rxtop = skb;
skb_fill_page_desc(rxtop, 0, buffer_info->page,
- 0, length);
+ 0, length);
} else {
/* this is the middle of a chain */
skb_fill_page_desc(rxtop,
@@ -4141,38 +4126,42 @@ process_skb:
skb_shinfo(rxtop)->nr_frags,
buffer_info->page, 0, length);
/* re-use the current skb, we only consumed the
- * page */
+ * page
+ */
buffer_info->skb = skb;
skb = rxtop;
rxtop = NULL;
e1000_consume_page(buffer_info, skb, length);
} else {
/* no chain, got EOP, this buf is the packet
- * copybreak to save the put_page/alloc_page */
+ * copybreak to save the put_page/alloc_page
+ */
if (length <= copybreak &&
skb_tailroom(skb) >= length) {
u8 *vaddr;
vaddr = kmap_atomic(buffer_info->page);
- memcpy(skb_tail_pointer(skb), vaddr, length);
+ memcpy(skb_tail_pointer(skb), vaddr,
+ length);
kunmap_atomic(vaddr);
/* re-use the page, so don't erase
- * buffer_info->page */
+ * buffer_info->page
+ */
skb_put(skb, length);
} else {
skb_fill_page_desc(skb, 0,
- buffer_info->page, 0,
- length);
+ buffer_info->page, 0,
+ length);
e1000_consume_page(buffer_info, skb,
- length);
+ length);
}
}
}
/* Receive Checksum Offload XXX recompute due to CRC strip? */
e1000_rx_checksum(adapter,
- (u32)(status) |
- ((u32)(rx_desc->errors) << 24),
- le16_to_cpu(rx_desc->csum), skb);
+ (u32)(status) |
+ ((u32)(rx_desc->errors) << 24),
+ le16_to_cpu(rx_desc->csum), skb);
total_rx_bytes += (skb->len - 4); /* don't count FCS */
if (likely(!(netdev->features & NETIF_F_RXFCS)))
@@ -4214,8 +4203,7 @@ next_desc:
return cleaned;
}
-/*
- * this should improve performance for small packets with large amounts
+/* this should improve performance for small packets with large amounts
* of reassembly being done in the stack
*/
static void e1000_check_copybreak(struct net_device *netdev,
@@ -4319,9 +4307,9 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
last_byte)) {
spin_lock_irqsave(&adapter->stats_lock, flags);
e1000_tbi_adjust_stats(hw, &adapter->stats,
- length, skb->data);
+ length, skb->data);
spin_unlock_irqrestore(&adapter->stats_lock,
- flags);
+ flags);
length--;
} else {
if (netdev->features & NETIF_F_RXALL)
@@ -4386,10 +4374,9 @@ next_desc:
* @rx_ring: pointer to receive ring structure
* @cleaned_count: number of buffers to allocate this pass
**/
-
static void
e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
- struct e1000_rx_ring *rx_ring, int cleaned_count)
+ struct e1000_rx_ring *rx_ring, int cleaned_count)
{
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
@@ -4430,7 +4417,7 @@ check_page:
if (!buffer_info->dma) {
buffer_info->dma = dma_map_page(&pdev->dev,
- buffer_info->page, 0,
+ buffer_info->page, 0,
buffer_info->length,
DMA_FROM_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
@@ -4460,7 +4447,8 @@ check_page:
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
* applicable for weak-ordered memory model archs,
- * such as IA-64). */
+ * such as IA-64).
+ */
wmb();
writel(i, adapter->hw.hw_addr + rx_ring->rdt);
}
@@ -4470,7 +4458,6 @@ check_page:
* e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
* @adapter: address of board private structure
**/
-
static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int cleaned_count)
@@ -4541,8 +4528,7 @@ map_skb:
break; /* while !buffer_info->skb */
}
- /*
- * XXX if it was allocated cleanly it will never map to a
+ /* XXX if it was allocated cleanly it will never map to a
* boundary crossing
*/
@@ -4580,7 +4566,8 @@ map_skb:
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
* applicable for weak-ordered memory model archs,
- * such as IA-64). */
+ * such as IA-64).
+ */
wmb();
writel(i, hw->hw_addr + rx_ring->rdt);
}
@@ -4590,7 +4577,6 @@ map_skb:
* e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers.
* @adapter:
**/
-
static void e1000_smartspeed(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
@@ -4603,7 +4589,8 @@ static void e1000_smartspeed(struct e1000_adapter *adapter)
if (adapter->smartspeed == 0) {
/* If Master/Slave config fault is asserted twice,
- * we assume back-to-back */
+ * we assume back-to-back
+ */
e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status);
if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return;
e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status);
@@ -4616,7 +4603,7 @@ static void e1000_smartspeed(struct e1000_adapter *adapter)
adapter->smartspeed++;
if (!e1000_phy_setup_autoneg(hw) &&
!e1000_read_phy_reg(hw, PHY_CTRL,
- &phy_ctrl)) {
+ &phy_ctrl)) {
phy_ctrl |= (MII_CR_AUTO_NEG_EN |
MII_CR_RESTART_AUTO_NEG);
e1000_write_phy_reg(hw, PHY_CTRL,
@@ -4647,7 +4634,6 @@ static void e1000_smartspeed(struct e1000_adapter *adapter)
* @ifreq:
* @cmd:
**/
-
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
switch (cmd) {
@@ -4666,7 +4652,6 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
* @ifreq:
* @cmd:
**/
-
static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
int cmd)
{
@@ -4928,7 +4913,8 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx)
hw->autoneg = 0;
/* Make sure dplx is at most 1 bit and lsb of speed is not set
- * for the switch() below to work */
+ * for the switch() below to work
+ */
if ((spd & 1) || (dplx & ~1))
goto err_inval;
@@ -5131,8 +5117,7 @@ static void e1000_shutdown(struct pci_dev *pdev)
}
#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling 'interrupt' - used by things like netconsole to send skbs
+/* Polling 'interrupt' - used by things like netconsole to send skbs
* without having to re-enable interrupts. It's not called while
* the interrupt routine is executing.
*/
diff --git a/drivers/net/ethernet/intel/e1000/e1000_param.c b/drivers/net/ethernet/intel/e1000/e1000_param.c
index 750fc0194f37..c9cde352b1c8 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_param.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_param.c
@@ -267,7 +267,6 @@ static void e1000_check_copper_options(struct e1000_adapter *adapter);
* value exists, a default value is used. The final value is stored
* in a variable in the adapter structure.
**/
-
void e1000_check_options(struct e1000_adapter *adapter)
{
struct e1000_option opt;
@@ -319,7 +318,8 @@ void e1000_check_options(struct e1000_adapter *adapter)
.def = E1000_DEFAULT_RXD,
.arg = { .r = {
.min = E1000_MIN_RXD,
- .max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD
+ .max = mac_type < e1000_82544 ? E1000_MAX_RXD :
+ E1000_MAX_82544_RXD
}}
};
@@ -408,7 +408,7 @@ void e1000_check_options(struct e1000_adapter *adapter)
if (num_TxAbsIntDelay > bd) {
adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
- adapter);
+ adapter);
} else {
adapter->tx_abs_int_delay = opt.def;
}
@@ -426,7 +426,7 @@ void e1000_check_options(struct e1000_adapter *adapter)
if (num_RxIntDelay > bd) {
adapter->rx_int_delay = RxIntDelay[bd];
e1000_validate_option(&adapter->rx_int_delay, &opt,
- adapter);
+ adapter);
} else {
adapter->rx_int_delay = opt.def;
}
@@ -444,7 +444,7 @@ void e1000_check_options(struct e1000_adapter *adapter)
if (num_RxAbsIntDelay > bd) {
adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
- adapter);
+ adapter);
} else {
adapter->rx_abs_int_delay = opt.def;
}
@@ -479,16 +479,17 @@ void e1000_check_options(struct e1000_adapter *adapter)
break;
case 4:
e_dev_info("%s set to simplified "
- "(2000-8000) ints mode\n", opt.name);
+ "(2000-8000) ints mode\n", opt.name);
adapter->itr_setting = adapter->itr;
break;
default:
e1000_validate_option(&adapter->itr, &opt,
- adapter);
+ adapter);
/* save the setting, because the dynamic bits
* change itr.
* clear the lower two bits because they are
- * used as control */
+ * used as control
+ */
adapter->itr_setting = adapter->itr & ~3;
break;
}
@@ -533,7 +534,6 @@ void e1000_check_options(struct e1000_adapter *adapter)
*
* Handles speed and duplex options on fiber adapters
**/
-
static void e1000_check_fiber_options(struct e1000_adapter *adapter)
{
int bd = adapter->bd_number;
@@ -559,7 +559,6 @@ static void e1000_check_fiber_options(struct e1000_adapter *adapter)
*
* Handles speed and duplex options on copper adapters
**/
-
static void e1000_check_copper_options(struct e1000_adapter *adapter)
{
struct e1000_option opt;
@@ -681,22 +680,22 @@ static void e1000_check_copper_options(struct e1000_adapter *adapter)
e_dev_info("Using Autonegotiation at Half Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
- ADVERTISE_100_HALF;
+ ADVERTISE_100_HALF;
break;
case FULL_DUPLEX:
e_dev_info("Full Duplex specified without Speed\n");
e_dev_info("Using Autonegotiation at Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
- ADVERTISE_100_FULL |
- ADVERTISE_1000_FULL;
+ ADVERTISE_100_FULL |
+ ADVERTISE_1000_FULL;
break;
case SPEED_10:
e_dev_info("10 Mbps Speed specified without Duplex\n");
e_dev_info("Using Autonegotiation at 10 Mbps only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
- ADVERTISE_10_FULL;
+ ADVERTISE_10_FULL;
break;
case SPEED_10 + HALF_DUPLEX:
e_dev_info("Forcing to 10 Mbps Half Duplex\n");
@@ -715,7 +714,7 @@ static void e1000_check_copper_options(struct e1000_adapter *adapter)
e_dev_info("Using Autonegotiation at 100 Mbps only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
- ADVERTISE_100_FULL;
+ ADVERTISE_100_FULL;
break;
case SPEED_100 + HALF_DUPLEX:
e_dev_info("Forcing to 100 Mbps Half Duplex\n");
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index e73c2c355993..e0991388664c 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -32,69 +32,6 @@
#include "e1000.h"
-#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00
-#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02
-#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10
-#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE 0x1F
-
-#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008
-#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800
-#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010
-
-#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
-#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000
-#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000
-
-#define E1000_KMRNCTRLSTA_OPMODE_MASK 0x000C
-#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO 0x0004
-
-#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
-#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000
-
-#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8
-#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9
-
-/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
-#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disab. */
-#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060
-#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */
-#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */
-#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */
-
-/* PHY Specific Control Register 2 (Page 0, Register 26) */
-#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000
- /* 1=Reverse Auto-Negotiation */
-
-/* MAC Specific Control Register (Page 2, Register 21) */
-/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
-#define GG82563_MSCR_TX_CLK_MASK 0x0007
-#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004
-#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005
-#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007
-
-#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */
-
-/* DSP Distance Register (Page 5, Register 26) */
-#define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M
- 1 = 50-80M
- 2 = 80-110M
- 3 = 110-140M
- 4 = >140M
- */
-
-/* Kumeran Mode Control Register (Page 193, Register 16) */
-#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800
-
-/* Max number of times Kumeran read/write should be validated */
-#define GG82563_MAX_KMRN_RETRY 0x5
-
-/* Power Management Control Register (Page 193, Register 20) */
-#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001
- /* 1=Enable SERDES Electrical Idle */
-
-/* In-Band Control Register (Page 194, Register 18) */
-#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */
-
/* A table for the GG82563 cable length where the range is defined
* with a lower bound at "index" and the upper bound at
* "index + 5".
@@ -111,11 +48,10 @@ static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
-static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw);
-static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
- u16 *data);
-static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
- u16 data);
+static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+ u16 *data);
+static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
+ u16 data);
static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw);
/**
@@ -625,16 +561,16 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
e_dbg("GG82563 PSCR: %X\n", phy_data);
- ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+ ret_val = e1e_rphy(hw, MII_BMCR, &phy_data);
if (ret_val)
return ret_val;
e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
/* Reset the phy to commit changes. */
- phy_data |= MII_CR_RESET;
+ phy_data |= BMCR_RESET;
- ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+ ret_val = e1e_wphy(hw, MII_BMCR, phy_data);
if (ret_val)
return ret_val;
@@ -696,7 +632,7 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val = 0;
+ s32 ret_val;
u16 phy_data, index;
ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
@@ -774,6 +710,9 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
ctrl = er32(CTRL);
ret_val = e1000_acquire_phy_80003es2lan(hw);
+ if (ret_val)
+ return ret_val;
+
e_dbg("Issuing a global reset to MAC\n");
ew32(CTRL, ctrl | E1000_CTRL_RST);
e1000_release_phy_80003es2lan(hw);
@@ -833,6 +772,8 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
/* Setup link and flow control */
ret_val = mac->ops.setup_link(hw);
+ if (ret_val)
+ return ret_val;
/* Disable IBIST slave mode (far-end loopback) */
e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
@@ -1006,7 +947,7 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
return ret_val;
/* SW Reset the PHY so all changes take effect */
- ret_val = e1000e_commit_phy(hw);
+ ret_val = hw->phy.ops.commit(hw);
if (ret_val) {
e_dbg("Error Resetting the PHY\n");
return ret_val;
@@ -1272,7 +1213,7 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
u16 *data)
{
u32 kmrnctrlsta;
- s32 ret_val = 0;
+ s32 ret_val;
ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
if (ret_val)
@@ -1307,7 +1248,7 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
u16 data)
{
u32 kmrnctrlsta;
- s32 ret_val = 0;
+ s32 ret_val;
ret_val = e1000_acquire_mac_csr_80003es2lan(hw);
if (ret_val)
@@ -1331,7 +1272,7 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
**/
static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw)
{
- s32 ret_val = 0;
+ s32 ret_val;
/* If there's an alternate MAC address place it in RAR0
* so that it will override the Si installed default perm
@@ -1434,18 +1375,18 @@ static const struct e1000_phy_operations es2_phy_ops = {
.acquire = e1000_acquire_phy_80003es2lan,
.check_polarity = e1000_check_polarity_m88,
.check_reset_block = e1000e_check_reset_block_generic,
- .commit = e1000e_phy_sw_reset,
- .force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan,
- .get_cfg_done = e1000_get_cfg_done_80003es2lan,
- .get_cable_length = e1000_get_cable_length_80003es2lan,
- .get_info = e1000e_get_phy_info_m88,
- .read_reg = e1000_read_phy_reg_gg82563_80003es2lan,
+ .commit = e1000e_phy_sw_reset,
+ .force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan,
+ .get_cfg_done = e1000_get_cfg_done_80003es2lan,
+ .get_cable_length = e1000_get_cable_length_80003es2lan,
+ .get_info = e1000e_get_phy_info_m88,
+ .read_reg = e1000_read_phy_reg_gg82563_80003es2lan,
.release = e1000_release_phy_80003es2lan,
- .reset = e1000e_phy_hw_reset_generic,
- .set_d0_lplu_state = NULL,
- .set_d3_lplu_state = e1000e_set_d3_lplu_state,
- .write_reg = e1000_write_phy_reg_gg82563_80003es2lan,
- .cfg_on_link_up = e1000_cfg_on_link_up_80003es2lan,
+ .reset = e1000e_phy_hw_reset_generic,
+ .set_d0_lplu_state = NULL,
+ .set_d3_lplu_state = e1000e_set_d3_lplu_state,
+ .write_reg = e1000_write_phy_reg_gg82563_80003es2lan,
+ .cfg_on_link_up = e1000_cfg_on_link_up_80003es2lan,
};
static const struct e1000_nvm_operations es2_nvm_ops = {
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.h b/drivers/net/ethernet/intel/e1000e/80003es2lan.h
new file mode 100644
index 000000000000..90d363b2d280
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.h
@@ -0,0 +1,95 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2013 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_80003ES2LAN_H_
+#define _E1000E_80003ES2LAN_H_
+
+#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00
+#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02
+#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10
+#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE 0x1F
+
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800
+#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010
+
+#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
+#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000
+#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000
+
+#define E1000_KMRNCTRLSTA_OPMODE_MASK 0x000C
+#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO 0x0004
+
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gig Carry Extend Padding */
+#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000
+
+#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8
+#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9
+
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Dis */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 /* 1=Reverse Auto-Neg */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK 0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26)
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-100M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define GG82563_DSPD_CABLE_LENGTH 0x0007
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800
+
+/* Max number of times Kumeran read/write should be validated */
+#define GG82563_MAX_KMRN_RETRY 0x5
+
+/* Power Management Control Register (Page 193, Register 20) */
+/* 1=Enable SERDES Electrical Idle */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index c77d010d5c59..2faffbde179e 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -44,21 +44,6 @@
#include "e1000.h"
-#define ID_LED_RESERVED_F746 0xF746
-#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
- (ID_LED_OFF1_ON2 << 8) | \
- (ID_LED_DEF1_DEF2 << 4) | \
- (ID_LED_DEF1_DEF2))
-
-#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
-#define AN_RETRY_COUNT 5 /* Autoneg Retry Count value */
-#define E1000_BASE1000T_STATUS 10
-#define E1000_IDLE_ERROR_COUNT_MASK 0xFF
-#define E1000_RECEIVE_ERROR_COUNTER 21
-#define E1000_RECEIVE_ERROR_MAX 0xFFFF
-
-#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
-
static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
@@ -67,9 +52,7 @@ static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
u16 words, u16 *data);
static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
-static s32 e1000_setup_link_82571(struct e1000_hw *hw);
static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
-static void e1000_clear_vfta_82571(struct e1000_hw *hw);
static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
static s32 e1000_led_on_82574(struct e1000_hw *hw);
static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
@@ -449,13 +432,13 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
break;
case e1000_82574:
case e1000_82583:
- ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+ ret_val = e1e_rphy(hw, MII_PHYSID1, &phy_id);
if (ret_val)
return ret_val;
phy->id = (u32)(phy_id << 16);
udelay(20);
- ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+ ret_val = e1e_rphy(hw, MII_PHYSID2, &phy_id);
if (ret_val)
return ret_val;
@@ -556,16 +539,14 @@ static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw)
s32 i = 0;
extcnf_ctrl = er32(EXTCNF_CTRL);
- extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
do {
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
ew32(EXTCNF_CTRL, extcnf_ctrl);
extcnf_ctrl = er32(EXTCNF_CTRL);
if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
break;
- extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
usleep_range(2000, 4000);
i++;
} while (i < MDIO_OWNERSHIP_TIMEOUT);
@@ -937,6 +918,8 @@ static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
/* When LPLU is enabled, we should disable SmartSpeed */
ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+ if (ret_val)
+ return ret_val;
data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
if (ret_val)
@@ -1329,9 +1312,10 @@ static void e1000_clear_vfta_82571(struct e1000_hw *hw)
*/
vfta_offset = (hw->mng_cookie.vlan_id >>
E1000_VFTA_ENTRY_SHIFT) &
- E1000_VFTA_ENTRY_MASK;
- vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
- E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+ E1000_VFTA_ENTRY_MASK;
+ vfta_bit_in_reg =
+ 1 << (hw->mng_cookie.vlan_id &
+ E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
}
break;
default:
@@ -1399,7 +1383,7 @@ bool e1000_check_phy_82574(struct e1000_hw *hw)
{
u16 status_1kbt = 0;
u16 receive_errors = 0;
- s32 ret_val = 0;
+ s32 ret_val;
/* Read PHY Receive Error counter first, if its is max - all F's then
* read the Base1000T status register If both are max then PHY is hung.
@@ -1544,13 +1528,12 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
ctrl = er32(CTRL);
status = er32(STATUS);
- rxcw = er32(RXCW);
+ er32(RXCW);
/* SYNCH bit and IV bit are sticky */
udelay(10);
rxcw = er32(RXCW);
if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) {
-
/* Receiver is synchronized with no invalid bits. */
switch (mac->serdes_link_state) {
case e1000_serdes_link_autoneg_complete:
@@ -1799,6 +1782,8 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
if (ret_val)
return ret_val;
ret_val = e1000e_update_nvm_checksum(hw);
+ if (ret_val)
+ return ret_val;
}
}
@@ -1812,7 +1797,7 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw)
{
if (hw->mac.type == e1000_82571) {
- s32 ret_val = 0;
+ s32 ret_val;
/* If there's an alternate MAC address place it in RAR0
* so that it will override the Si installed default perm
@@ -1931,7 +1916,7 @@ static const struct e1000_phy_operations e82_phy_ops_igp = {
.set_d0_lplu_state = e1000_set_d0_lplu_state_82571,
.set_d3_lplu_state = e1000e_set_d3_lplu_state,
.write_reg = e1000e_write_phy_reg_igp,
- .cfg_on_link_up = NULL,
+ .cfg_on_link_up = NULL,
};
static const struct e1000_phy_operations e82_phy_ops_m88 = {
@@ -1940,7 +1925,7 @@ static const struct e1000_phy_operations e82_phy_ops_m88 = {
.check_reset_block = e1000e_check_reset_block_generic,
.commit = e1000e_phy_sw_reset,
.force_speed_duplex = e1000e_phy_force_speed_duplex_m88,
- .get_cfg_done = e1000e_get_cfg_done,
+ .get_cfg_done = e1000e_get_cfg_done_generic,
.get_cable_length = e1000e_get_cable_length_m88,
.get_info = e1000e_get_phy_info_m88,
.read_reg = e1000e_read_phy_reg_m88,
@@ -1949,7 +1934,7 @@ static const struct e1000_phy_operations e82_phy_ops_m88 = {
.set_d0_lplu_state = e1000_set_d0_lplu_state_82571,
.set_d3_lplu_state = e1000e_set_d3_lplu_state,
.write_reg = e1000e_write_phy_reg_m88,
- .cfg_on_link_up = NULL,
+ .cfg_on_link_up = NULL,
};
static const struct e1000_phy_operations e82_phy_ops_bm = {
@@ -1958,7 +1943,7 @@ static const struct e1000_phy_operations e82_phy_ops_bm = {
.check_reset_block = e1000e_check_reset_block_generic,
.commit = e1000e_phy_sw_reset,
.force_speed_duplex = e1000e_phy_force_speed_duplex_m88,
- .get_cfg_done = e1000e_get_cfg_done,
+ .get_cfg_done = e1000e_get_cfg_done_generic,
.get_cable_length = e1000e_get_cable_length_m88,
.get_info = e1000e_get_phy_info_m88,
.read_reg = e1000e_read_phy_reg_bm2,
@@ -1967,7 +1952,7 @@ static const struct e1000_phy_operations e82_phy_ops_bm = {
.set_d0_lplu_state = e1000_set_d0_lplu_state_82571,
.set_d3_lplu_state = e1000e_set_d3_lplu_state,
.write_reg = e1000e_write_phy_reg_bm2,
- .cfg_on_link_up = NULL,
+ .cfg_on_link_up = NULL,
};
static const struct e1000_nvm_operations e82571_nvm_ops = {
@@ -2044,6 +2029,7 @@ const struct e1000_info e1000_82574_info = {
| FLAG_HAS_MSIX
| FLAG_HAS_JUMBO_FRAMES
| FLAG_HAS_WOL
+ | FLAG_HAS_HW_TIMESTAMP
| FLAG_APME_IN_CTRL3
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
@@ -2065,6 +2051,7 @@ const struct e1000_info e1000_82583_info = {
.mac = e1000_82583,
.flags = FLAG_HAS_HW_VLAN_FILTER
| FLAG_HAS_WOL
+ | FLAG_HAS_HW_TIMESTAMP
| FLAG_APME_IN_CTRL3
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
diff --git a/drivers/net/ethernet/intel/e1000e/82571.h b/drivers/net/ethernet/intel/e1000e/82571.h
new file mode 100644
index 000000000000..85cb1a3b7cd4
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/82571.h
@@ -0,0 +1,58 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2013 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_82571_H_
+#define _E1000E_82571_H_
+
+#define ID_LED_RESERVED_F746 0xF746
+#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_OFF1_ON2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+#define AN_RETRY_COUNT 5 /* Autoneg Retry Count value */
+
+/* Intr Throttling - RW */
+#define E1000_EITR_82574(_n) (0x000E8 + (0x4 * (_n)))
+
+#define E1000_EIAC_82574 0x000DC /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAC_MASK_82574 0x01F00000
+
+/* Manageability Operation Mode mask */
+#define E1000_NVM_INIT_CTRL2_MNGM 0x6000
+
+#define E1000_BASE1000T_STATUS 10
+#define E1000_IDLE_ERROR_COUNT_MASK 0xFF
+#define E1000_RECEIVE_ERROR_COUNTER 21
+#define E1000_RECEIVE_ERROR_MAX 0xFFFF
+bool e1000_check_phy_82574(struct e1000_hw *hw);
+bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
+void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/Makefile b/drivers/net/ethernet/intel/e1000e/Makefile
index 591b71324505..c2dcfcc10857 100644
--- a/drivers/net/ethernet/intel/e1000e/Makefile
+++ b/drivers/net/ethernet/intel/e1000e/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
# Intel PRO/1000 Linux driver
-# Copyright(c) 1999 - 2012 Intel Corporation.
+# Copyright(c) 1999 - 2013 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
@@ -34,5 +34,5 @@ obj-$(CONFIG_E1000E) += e1000e.o
e1000e-objs := 82571.o ich8lan.o 80003es2lan.o \
mac.o manage.o nvm.o phy.o \
- param.o ethtool.o netdev.o
+ param.o ethtool.o netdev.o ptp.o
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index 02a12b69555f..fc3a4fe1ac71 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -29,25 +29,6 @@
#ifndef _E1000_DEFINES_H_
#define _E1000_DEFINES_H_
-#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
-#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
-#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
-
/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
#define REQ_TX_DESCRIPTOR_MULTIPLE 8
#define REQ_RX_DESCRIPTOR_MULTIPLE 8
@@ -86,7 +67,6 @@
#define E1000_CTRL_EXT_EIAME 0x01000000
#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
-#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
#define E1000_CTRL_EXT_LSECCK 0x00001000
#define E1000_CTRL_EXT_PHYPDEN 0x00100000
@@ -107,6 +87,7 @@
#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */
#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
+#define E1000_RXDEXT_STATERR_TST 0x00000100 /* Time Stamp taken */
#define E1000_RXDEXT_STATERR_CE 0x01000000
#define E1000_RXDEXT_STATERR_SE 0x02000000
#define E1000_RXDEXT_STATERR_SEQ 0x04000000
@@ -115,19 +96,19 @@
/* mask to determine if packets should be dropped due to frame errors */
#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
- E1000_RXD_ERR_CE | \
- E1000_RXD_ERR_SE | \
- E1000_RXD_ERR_SEQ | \
- E1000_RXD_ERR_CXE | \
- E1000_RXD_ERR_RXE)
+ E1000_RXD_ERR_CE | \
+ E1000_RXD_ERR_SE | \
+ E1000_RXD_ERR_SEQ | \
+ E1000_RXD_ERR_CXE | \
+ E1000_RXD_ERR_RXE)
/* Same mask, but for extended and packet split descriptors */
#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
- E1000_RXDEXT_STATERR_CE | \
- E1000_RXDEXT_STATERR_SE | \
- E1000_RXDEXT_STATERR_SEQ | \
- E1000_RXDEXT_STATERR_CXE | \
- E1000_RXDEXT_STATERR_RXE)
+ E1000_RXDEXT_STATERR_CE | \
+ E1000_RXDEXT_STATERR_SE | \
+ E1000_RXDEXT_STATERR_SEQ | \
+ E1000_RXDEXT_STATERR_CXE | \
+ E1000_RXDEXT_STATERR_RXE)
#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000
#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
@@ -232,6 +213,7 @@
#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
#define E1000_CTRL_LANPHYPC_OVERRIDE 0x00010000 /* SW control of LANPHYPC */
#define E1000_CTRL_LANPHYPC_VALUE 0x00020000 /* SW value of LANPHYPC */
+#define E1000_CTRL_MEHE 0x00080000 /* Memory Error Handling Enable */
#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
@@ -241,9 +223,9 @@
#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
-/* Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
+#define E1000_PCS_LCTL_FORCE_FCTRL 0x80
+
+#define E1000_PCS_LSTS_AN_COMPLETE 0x10000
/* Device Status */
#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
@@ -259,8 +241,6 @@
#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */
#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
-/* Constants used to interpret the masked PCI-X bus speed. */
-
#define HALF_DUPLEX 1
#define FULL_DUPLEX 2
@@ -273,14 +253,15 @@
#define ADVERTISE_1000_FULL 0x0020
/* 1000/H is not supported, nor spec-compliant. */
-#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
- ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
- ADVERTISE_1000_FULL)
-#define E1000_ALL_NOT_GIG ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
- ADVERTISE_100_HALF | ADVERTISE_100_FULL)
-#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL)
-#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL)
-#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF)
+#define E1000_ALL_SPEED_DUPLEX ( \
+ ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \
+ ADVERTISE_100_FULL | ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG ( \
+ ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \
+ ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL)
+#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF)
#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX
@@ -318,6 +299,7 @@
#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
+#define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
/* Transmit Control */
#define E1000_TCTL_EN 0x00000002 /* enable Tx */
@@ -327,8 +309,6 @@
#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */
-/* Transmit Arbitration Count */
-
/* SerDes Control */
#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
@@ -383,12 +363,23 @@
#define E1000_KABGTXD_BGSQLBIAS 0x00050000
+/* Low Power IDLE Control */
+#define E1000_LPIC_LPIET_SHIFT 24 /* Low Power Idle Entry Time */
+
/* PBA constants */
#define E1000_PBA_8K 0x0008 /* 8KB */
#define E1000_PBA_16K 0x0010 /* 16KB */
+#define E1000_PBA_RXA_MASK 0xFFFF
+
#define E1000_PBS_16K E1000_PBA_16K
+/* Uncorrectable/correctable ECC Error counts and enable bits */
+#define E1000_PBECCSTS_CORR_ERR_CNT_MASK 0x000000FF
+#define E1000_PBECCSTS_UNCORR_ERR_CNT_MASK 0x0000FF00
+#define E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT 8
+#define E1000_PBECCSTS_ECC_ENABLE 0x00010000
+
#define IFS_MAX 80
#define IFS_MIN 40
#define IFS_RATIO 4
@@ -408,6 +399,7 @@
#define E1000_ICR_RXSEQ 0x00000008 /* Rx sequence error */
#define E1000_ICR_RXDMT0 0x00000010 /* Rx desc min. threshold (0) */
#define E1000_ICR_RXT0 0x00000080 /* Rx timer intr (ring 0) */
+#define E1000_ICR_ECCER 0x00400000 /* Uncorrectable ECC Error */
#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */
#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */
#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */
@@ -431,11 +423,11 @@
* o LSC = Link Status Change
*/
#define IMS_ENABLE_MASK ( \
- E1000_IMS_RXT0 | \
- E1000_IMS_TXDW | \
- E1000_IMS_RXDMT0 | \
- E1000_IMS_RXSEQ | \
- E1000_IMS_LSC)
+ E1000_IMS_RXT0 | \
+ E1000_IMS_TXDW | \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ | \
+ E1000_IMS_LSC)
/* Interrupt Mask Set */
#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
@@ -443,6 +435,7 @@
#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* Rx sequence error */
#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* Rx desc min. threshold */
#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* Rx timer intr */
+#define E1000_IMS_ECCER E1000_ICR_ECCER /* Uncorrectable ECC Error */
#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */
#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */
#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */
@@ -533,6 +526,28 @@
#define E1000_RXCW_C 0x20000000 /* Receive config */
#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */
+#define E1000_TSYNCTXCTL_VALID 0x00000001 /* Tx timestamp valid */
+#define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
+
+#define E1000_TSYNCRXCTL_VALID 0x00000001 /* Rx timestamp valid */
+#define E1000_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
+#define E1000_TSYNCRXCTL_TYPE_L2_V2 0x00
+#define E1000_TSYNCRXCTL_TYPE_L4_V1 0x02
+#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
+#define E1000_TSYNCRXCTL_TYPE_ALL 0x08
+#define E1000_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
+#define E1000_TSYNCRXCTL_ENABLED 0x00000010 /* enable Rx timestamping */
+#define E1000_TSYNCRXCTL_SYSCFI 0x00000020 /* Sys clock frequency */
+
+#define E1000_RXMTRL_PTP_V1_SYNC_MESSAGE 0x00000000
+#define E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE 0x00010000
+
+#define E1000_RXMTRL_PTP_V2_SYNC_MESSAGE 0x00000000
+#define E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE 0x01000000
+
+#define E1000_TIMINCA_INCPERIOD_SHIFT 24
+#define E1000_TIMINCA_INCVALUE_MASK 0x00FFFFFF
+
/* PCI Express Control */
#define E1000_GCR_RXD_NO_SNOOP 0x00000001
#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002
@@ -548,66 +563,6 @@
E1000_GCR_TXDSCW_NO_SNOOP | \
E1000_GCR_TXDSCR_NO_SNOOP)
-/* PHY Control Register */
-#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
-#define MII_CR_POWER_DOWN 0x0800 /* Power down */
-#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
-#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
-#define MII_CR_SPEED_1000 0x0040
-#define MII_CR_SPEED_100 0x2000
-#define MII_CR_SPEED_10 0x0000
-
-/* PHY Status Register */
-#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
-
-/* Autoneg Advertisement Register */
-#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
-#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
-#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
-#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
-#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
-#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
-
-/* Link Partner Ability Register (Base Page) */
-#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP 100TX Full Dplx Capable */
-#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
-#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
-
-/* Autoneg Expansion Register */
-#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
-
-/* 1000BASE-T Control Register */
-#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
-#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
- /* 0=DTE device */
-#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
- /* 0=Configure PHY as Slave */
-#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
- /* 0=Automatic Master/Slave config */
-
-/* 1000BASE-T Status Register */
-#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
-#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
-
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CONTROL 0x00 /* Control Register */
-#define PHY_STATUS 0x01 /* Status Register */
-#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
-#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
-#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
-
-#define PHY_CONTROL_LB 0x4000 /* PHY Loopback bit */
-
/* NVM Control */
#define E1000_EECD_SK 0x00000001 /* NVM Clock */
#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */
@@ -639,6 +594,10 @@
/* NVM Word Offsets */
#define NVM_COMPAT 0x0003
#define NVM_ID_LED_SETTINGS 0x0004
+#define NVM_FUTURE_INIT_WORD1 0x0019
+#define NVM_COMPAT_VALID_CSUM 0x0001
+#define NVM_FUTURE_INIT_WORD1_VALID_CSUM 0x0040
+
#define NVM_INIT_CONTROL2_REG 0x000F
#define NVM_INIT_CONTROL3_PORT_B 0x0014
#define NVM_INIT_3GIO_3 0x001A
@@ -647,8 +606,6 @@
#define NVM_ALT_MAC_ADDR_PTR 0x0037
#define NVM_CHECKSUM_REG 0x003F
-#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
-
#define E1000_NVM_CFG_DONE_PORT_0 0x40000 /* MNG config cycle done */
#define E1000_NVM_CFG_DONE_PORT_1 0x80000 /* ...for second port */
@@ -757,9 +714,6 @@
#define M88E1000_PSCR_AUTO_X_1000T 0x0040
/* Auto crossover enabled all speeds */
#define M88E1000_PSCR_AUTO_X_MODE 0x0060
-/* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold)
- * 0=Normal 10BASE-T Rx Threshold
- */
#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
/* M88E1000 PHY Specific Status Register */
@@ -795,11 +749,6 @@
/* BME1000 PHY Specific Control Register */
#define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */
-
-#define PHY_PAGE_SHIFT 5
-#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
- ((reg) & MAX_PHY_REG_ADDRESS))
-
/* Bits...
* 15-5: page
* 4-0: register offset
@@ -846,8 +795,4 @@
/* SerDes Control */
#define E1000_GEN_POLL_TIMEOUT 640
-/* FW Semaphore */
-#define E1000_FWSM_WLOCK_MAC_MASK 0x0380
-#define E1000_FWSM_WLOCK_MAC_SHIFT 7
-
#endif /* _E1000_DEFINES_H_ */
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index 6782a2eea1bc..fcc758138b8a 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -41,7 +41,11 @@
#include <linux/pci-aspm.h>
#include <linux/crc32.h>
#include <linux/if_vlan.h>
-
+#include <linux/clocksource.h>
+#include <linux/net_tstamp.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/ptp_classify.h>
+#include <linux/mii.h>
#include "hw.h"
struct e1000_info;
@@ -75,9 +79,6 @@ struct e1000_info;
#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */
#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */
-/* Early Receive defines */
-#define E1000_ERT_2048 0x100
-
#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
@@ -94,70 +95,6 @@ struct e1000_info;
#define DEFAULT_JUMBO 9234
-/* BM/HV Specific Registers */
-#define BM_PORT_CTRL_PAGE 769
-
-#define PHY_UPPER_SHIFT 21
-#define BM_PHY_REG(page, reg) \
- (((reg) & MAX_PHY_REG_ADDRESS) |\
- (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
- (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
-
-/* PHY Wakeup Registers and defines */
-#define BM_PORT_GEN_CFG PHY_REG(BM_PORT_CTRL_PAGE, 17)
-#define BM_RCTL PHY_REG(BM_WUC_PAGE, 0)
-#define BM_WUC PHY_REG(BM_WUC_PAGE, 1)
-#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2)
-#define BM_WUS PHY_REG(BM_WUC_PAGE, 3)
-#define BM_RAR_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
-#define BM_RAR_M(_i) (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
-#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
-#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
-#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
-
-#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */
-#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */
-#define BM_RCTL_MO_SHIFT 3 /* Multicast Offset Shift */
-#define BM_RCTL_MO_MASK (3 << 3) /* Multicast Offset Mask */
-#define BM_RCTL_BAM 0x0020 /* Broadcast Accept Mode */
-#define BM_RCTL_PMCF 0x0040 /* Pass MAC Control Frames */
-#define BM_RCTL_RFCE 0x0080 /* Rx Flow Control Enable */
-
-#define HV_STATS_PAGE 778
-#define HV_SCC_UPPER PHY_REG(HV_STATS_PAGE, 16) /* Single Collision Count */
-#define HV_SCC_LOWER PHY_REG(HV_STATS_PAGE, 17)
-#define HV_ECOL_UPPER PHY_REG(HV_STATS_PAGE, 18) /* Excessive Coll. Count */
-#define HV_ECOL_LOWER PHY_REG(HV_STATS_PAGE, 19)
-#define HV_MCC_UPPER PHY_REG(HV_STATS_PAGE, 20) /* Multiple Coll. Count */
-#define HV_MCC_LOWER PHY_REG(HV_STATS_PAGE, 21)
-#define HV_LATECOL_UPPER PHY_REG(HV_STATS_PAGE, 23) /* Late Collision Count */
-#define HV_LATECOL_LOWER PHY_REG(HV_STATS_PAGE, 24)
-#define HV_COLC_UPPER PHY_REG(HV_STATS_PAGE, 25) /* Collision Count */
-#define HV_COLC_LOWER PHY_REG(HV_STATS_PAGE, 26)
-#define HV_DC_UPPER PHY_REG(HV_STATS_PAGE, 27) /* Defer Count */
-#define HV_DC_LOWER PHY_REG(HV_STATS_PAGE, 28)
-#define HV_TNCRS_UPPER PHY_REG(HV_STATS_PAGE, 29) /* Transmit with no CRS */
-#define HV_TNCRS_LOWER PHY_REG(HV_STATS_PAGE, 30)
-
-#define E1000_FCRTV_PCH 0x05F40 /* PCH Flow Control Refresh Timer Value */
-
-/* BM PHY Copper Specific Status */
-#define BM_CS_STATUS 17
-#define BM_CS_STATUS_LINK_UP 0x0400
-#define BM_CS_STATUS_RESOLVED 0x0800
-#define BM_CS_STATUS_SPEED_MASK 0xC000
-#define BM_CS_STATUS_SPEED_1000 0x8000
-
-/* 82577 Mobile Phy Status Register */
-#define HV_M_STATUS 26
-#define HV_M_STATUS_AUTONEG_COMPLETE 0x1000
-#define HV_M_STATUS_SPEED_MASK 0x0300
-#define HV_M_STATUS_SPEED_1000 0x0200
-#define HV_M_STATUS_LINK_UP 0x0040
-
-#define E1000_ICH_FWSM_PCIM2PCI 0x01000000 /* ME PCIm-to-PCI active */
-#define E1000_ICH_FWSM_PCIM2PCI_COUNT 2000
-
/* Time to wait before putting the device into D3 if there's no link (in ms). */
#define LINK_TIMEOUT 100
@@ -309,6 +246,8 @@ struct e1000_adapter {
struct napi_struct napi;
+ unsigned int uncorr_errors; /* uncorrectable ECC errors */
+ unsigned int corr_errors; /* correctable ECC errors */
unsigned int restart_queue;
u32 txd_cmd;
@@ -353,6 +292,7 @@ struct e1000_adapter {
u64 gorc_old;
u32 alloc_rx_buff_failed;
u32 rx_dma_failed;
+ u32 rx_hwtstamp_cleared;
unsigned int rx_ps_pages;
u16 rx_ps_bsize0;
@@ -366,7 +306,7 @@ struct e1000_adapter {
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
- spinlock_t stats64_lock;
+ spinlock_t stats64_lock; /* protects statistics counters */
struct e1000_hw_stats stats;
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
@@ -402,6 +342,16 @@ struct e1000_adapter {
u16 tx_ring_count;
u16 rx_ring_count;
+
+ struct hwtstamp_config hwtstamp_config;
+ struct delayed_work systim_overflow_work;
+ struct sk_buff *tx_hwtstamp_skb;
+ struct work_struct tx_hwtstamp_work;
+ spinlock_t systim_lock; /* protects SYSTIML/H regsters */
+ struct cyclecounter cc;
+ struct timecounter tc;
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info ptp_clock_info;
};
struct e1000_info {
@@ -416,6 +366,40 @@ struct e1000_info {
const struct e1000_nvm_operations *nvm_ops;
};
+s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca);
+
+/* The system time is maintained by a 64-bit counter comprised of the 32-bit
+ * SYSTIMH and SYSTIML registers. How the counter increments (and therefore
+ * its resolution) is based on the contents of the TIMINCA register - it
+ * increments every incperiod (bits 31:24) clock ticks by incvalue (bits 23:0).
+ * For the best accuracy, the incperiod should be as small as possible. The
+ * incvalue is scaled by a factor as large as possible (while still fitting
+ * in bits 23:0) so that relatively small clock corrections can be made.
+ *
+ * As a result, a shift of INCVALUE_SHIFT_n is used to fit a value of
+ * INCVALUE_n into the TIMINCA register allowing 32+8+(24-INCVALUE_SHIFT_n)
+ * bits to count nanoseconds leaving the rest for fractional nonseconds.
+ */
+#define INCVALUE_96MHz 125
+#define INCVALUE_SHIFT_96MHz 17
+#define INCPERIOD_SHIFT_96MHz 2
+#define INCPERIOD_96MHz (12 >> INCPERIOD_SHIFT_96MHz)
+
+#define INCVALUE_25MHz 40
+#define INCVALUE_SHIFT_25MHz 18
+#define INCPERIOD_25MHz 1
+
+/* Another drawback of scaling the incvalue by a large factor is the
+ * 64-bit SYSTIM register overflows more quickly. This is dealt with
+ * by simply reading the clock before it overflows.
+ *
+ * Clock ns bits Overflows after
+ * ~~~~~~ ~~~~~~~ ~~~~~~~~~~~~~~~
+ * 96MHz 47-bit 2^(47-INCPERIOD_SHIFT_96MHz) / 10^9 / 3600 = 9.77 hrs
+ * 25MHz 46-bit 2^46 / 10^9 / 3600 = 19.55 hours
+ */
+#define E1000_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 60 * 4)
+
/* hardware capability, feature, and workaround flags */
#define FLAG_HAS_AMT (1 << 0)
#define FLAG_HAS_FLASH (1 << 1)
@@ -431,7 +415,7 @@ struct e1000_info {
#define FLAG_HAS_SMART_POWER_DOWN (1 << 11)
#define FLAG_IS_QUAD_PORT_A (1 << 12)
#define FLAG_IS_QUAD_PORT (1 << 13)
-/* reserved bit14 */
+#define FLAG_HAS_HW_TIMESTAMP (1 << 14)
#define FLAG_APME_IN_WUC (1 << 15)
#define FLAG_APME_IN_CTRL3 (1 << 16)
#define FLAG_APME_CHECK_PORT_B (1 << 17)
@@ -447,7 +431,7 @@ struct e1000_info {
#define FLAG_MSI_ENABLED (1 << 27)
/* reserved (1 << 28) */
#define FLAG_TSO_FORCE (1 << 29)
-#define FLAG_RX_RESTART_NOW (1 << 30)
+#define FLAG_RESTART_NOW (1 << 30)
#define FLAG_MSI_TEST_FAILED (1 << 31)
#define FLAG2_CRC_STRIPPING (1 << 0)
@@ -463,6 +447,7 @@ struct e1000_info {
#define FLAG2_NO_DISABLE_RX (1 << 10)
#define FLAG2_PCIM2PCI_ARBITER_WA (1 << 11)
#define FLAG2_DFLT_CRC_STRIPPING (1 << 12)
+#define FLAG2_CHECK_RX_HWTSTAMP (1 << 13)
#define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
@@ -512,8 +497,6 @@ extern void e1000e_write_itr(struct e1000_adapter *adapter, u32 itr);
extern unsigned int copybreak;
-extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
-
extern const struct e1000_info e1000_82571_info;
extern const struct e1000_info e1000_82572_info;
extern const struct e1000_info e1000_82573_info;
@@ -527,138 +510,8 @@ extern const struct e1000_info e1000_pch2_info;
extern const struct e1000_info e1000_pch_lpt_info;
extern const struct e1000_info e1000_es2_info;
-extern s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
- u32 pba_num_size);
-
-extern s32 e1000e_commit_phy(struct e1000_hw *hw);
-
-extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
-
-extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
-extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
-
-extern void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw);
-extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
- bool state);
-extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
-extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
-extern void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw);
-extern void e1000_resume_workarounds_pchlan(struct e1000_hw *hw);
-extern s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
-extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
-extern void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
-
-extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
-extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
-extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
-extern s32 e1000e_setup_led_generic(struct e1000_hw *hw);
-extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
-extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
-extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
-extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
-extern void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
-extern void e1000_set_lan_id_single_port(struct e1000_hw *hw);
-extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex);
-extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex);
-extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
-extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw);
-extern s32 e1000e_id_led_init_generic(struct e1000_hw *hw);
-extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
-extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
-extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw);
-extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw);
-extern s32 e1000e_setup_link_generic(struct e1000_hw *hw);
-extern void e1000_clear_vfta_generic(struct e1000_hw *hw);
-extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
-extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
- u8 *mc_addr_list,
- u32 mc_addr_count);
-extern void e1000e_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
-extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
-extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
-extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw);
-extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
-extern void e1000e_config_collision_dist_generic(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_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);
-extern void e1000e_update_adaptive(struct e1000_hw *hw);
-
-extern s32 e1000e_setup_copper_link(struct e1000_hw *hw);
-extern s32 e1000e_get_phy_id(struct e1000_hw *hw);
-extern void e1000e_put_hw_semaphore(struct e1000_hw *hw);
-extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw);
-extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
-extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
-extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
-extern s32 e1000_set_page_igp(struct e1000_hw *hw, u16 page);
-extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset,
- u16 *data);
-extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
-extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
-extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset,
- u16 data);
-extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
-extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
-extern s32 e1000e_get_cfg_done(struct e1000_hw *hw);
-extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
-extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
-extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw);
-extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
-extern s32 e1000e_determine_phy_address(struct e1000_hw *hw);
-extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000_enable_phy_wakeup_reg_access_bm(struct e1000_hw *hw,
- u16 *phy_reg);
-extern s32 e1000_disable_phy_wakeup_reg_access_bm(struct e1000_hw *hw,
- u16 *phy_reg);
-extern s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
-extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
-extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset,
- u16 data);
-extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset,
- u16 *data);
-extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
- u32 usec_interval, bool *success);
-extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
-extern void e1000_power_up_phy_copper(struct e1000_hw *hw);
-extern void e1000_power_down_phy_copper(struct e1000_hw *hw);
-extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_check_downshift(struct e1000_hw *hw);
-extern s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset,
- u16 *data);
-extern s32 e1000_read_phy_reg_page_hv(struct e1000_hw *hw, u32 offset,
- u16 *data);
-extern s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset,
- u16 data);
-extern s32 e1000_write_phy_reg_page_hv(struct e1000_hw *hw, u32 offset,
- u16 data);
-extern s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw);
-extern s32 e1000_copper_link_setup_82577(struct e1000_hw *hw);
-extern s32 e1000_check_polarity_82577(struct e1000_hw *hw);
-extern s32 e1000_get_phy_info_82577(struct e1000_hw *hw);
-extern s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
-extern s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
-
-extern s32 e1000_check_polarity_m88(struct e1000_hw *hw);
-extern s32 e1000_get_phy_info_ife(struct e1000_hw *hw);
-extern s32 e1000_check_polarity_ife(struct e1000_hw *hw);
-extern s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
-extern s32 e1000_check_polarity_igp(struct e1000_hw *hw);
-extern bool e1000_check_phy_82574(struct e1000_hw *hw);
+extern void e1000e_ptp_init(struct e1000_adapter *adapter);
+extern void e1000e_ptp_remove(struct e1000_adapter *adapter);
static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
{
@@ -685,20 +538,7 @@ static inline s32 e1e_wphy_locked(struct e1000_hw *hw, u32 offset, u16 data)
return hw->phy.ops.write_reg_locked(hw, offset, data);
}
-static inline s32 e1000_get_cable_length(struct e1000_hw *hw)
-{
- return hw->phy.ops.get_cable_length(hw);
-}
-
-extern s32 e1000e_acquire_nvm(struct e1000_hw *hw);
-extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
-extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
-extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
-extern void e1000e_release_nvm(struct e1000_hw *hw);
extern void e1000e_reload_nvm_generic(struct e1000_hw *hw);
-extern s32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
static inline s32 e1000e_read_mac_addr(struct e1000_hw *hw)
{
@@ -733,10 +573,6 @@ static inline s32 e1000_get_phy_info(struct e1000_hw *hw)
return hw->phy.ops.get_info(hw);
}
-extern bool e1000e_check_mng_mode_generic(struct e1000_hw *hw);
-extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
-extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
-
static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
{
return readl(hw->hw_addr + reg);
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index f95bc6ee1c22..2c1813737f6d 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -35,6 +35,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
+#include <linux/mdio.h>
#include "e1000.h"
@@ -98,7 +99,6 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
E1000_STAT("rx_flow_control_xoff", stats.xoffrxc),
E1000_STAT("tx_flow_control_xon", stats.xontxc),
E1000_STAT("tx_flow_control_xoff", stats.xofftxc),
- E1000_STAT("rx_long_byte_count", stats.gorc),
E1000_STAT("rx_csum_offload_good", hw_csum_good),
E1000_STAT("rx_csum_offload_errors", hw_csum_err),
E1000_STAT("rx_header_split", rx_hdr_split),
@@ -108,6 +108,9 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
E1000_STAT("dropped_smbus", stats.mgpdc),
E1000_STAT("rx_dma_failed", rx_dma_failed),
E1000_STAT("tx_dma_failed", tx_dma_failed),
+ E1000_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
+ E1000_STAT("uncorr_ecc_errors", uncorr_errors),
+ E1000_STAT("corr_ecc_errors", corr_errors),
};
#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
@@ -127,7 +130,6 @@ static int e1000_get_settings(struct net_device *netdev,
u32 speed;
if (hw->phy.media_type == e1000_media_type_copper) {
-
ecmd->supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
@@ -325,12 +327,12 @@ static int e1000_set_settings(struct net_device *netdev,
}
/* reset the link */
-
if (netif_running(adapter->netdev)) {
e1000e_down(adapter);
e1000e_up(adapter);
- } else
+ } else {
e1000e_reset(adapter);
+ }
clear_bit(__E1000_RESETTING, &adapter->state);
return 0;
@@ -415,7 +417,7 @@ static void e1000_set_msglevel(struct net_device *netdev, u32 data)
adapter->msg_enable = data;
}
-static int e1000_get_regs_len(struct net_device *netdev)
+static int e1000_get_regs_len(struct net_device __always_unused *netdev)
{
#define E1000_REGS_LEN 32 /* overestimate */
return E1000_REGS_LEN * sizeof(u32);
@@ -469,10 +471,10 @@ static void e1000_get_regs(struct net_device *netdev,
regs_buff[22] = adapter->phy_stats.receive_errors;
regs_buff[23] = regs_buff[13]; /* mdix mode */
}
- regs_buff[21] = 0; /* was idle_errors */
- e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
- regs_buff[24] = (u32)phy_data; /* phy local receiver status */
- regs_buff[25] = regs_buff[24]; /* phy remote receiver status */
+ regs_buff[21] = 0; /* was idle_errors */
+ e1e_rphy(hw, MII_STAT1000, &phy_data);
+ regs_buff[24] = (u32)phy_data; /* phy local receiver status */
+ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */
}
static int e1000_get_eeprom_len(struct net_device *netdev)
@@ -759,8 +761,9 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data,
(test[pat] & write));
val = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset);
if (val != (test[pat] & write & mask)) {
- e_err("pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",
- reg + offset, val, (test[pat] & write & mask));
+ e_err("pattern test failed (reg 0x%05X): got 0x%08X expected 0x%08X\n",
+ reg + (offset << 2), val,
+ (test[pat] & write & mask));
*data = reg;
return 1;
}
@@ -775,7 +778,7 @@ static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data,
__ew32(&adapter->hw, reg, write & mask);
val = __er32(&adapter->hw, reg);
if ((write & mask) != (val & mask)) {
- e_err("set/check reg %04X test failed: got 0x%08X expected 0x%08X\n",
+ e_err("set/check test failed (reg 0x%05X): got 0x%08X expected 0x%08X\n",
reg, (val & mask), (write & mask));
*data = reg;
return 1;
@@ -883,12 +886,20 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
E1000_FWSM_WLOCK_MAC_SHIFT;
for (i = 0; i < mac->rar_entry_count; i++) {
- /* Cannot test write-protected SHRAL[n] registers */
- if ((wlock_mac == 1) || (wlock_mac && (i > wlock_mac)))
- continue;
+ if (mac->type == e1000_pch_lpt) {
+ /* Cannot test write-protected SHRAL[n] registers */
+ if ((wlock_mac == 1) || (wlock_mac && (i > wlock_mac)))
+ continue;
- REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
- mask, 0xFFFFFFFF);
+ /* SHRAH[9] different than the others */
+ if (i == 10)
+ mask |= (1 << 30);
+ else
+ mask &= ~(1 << 30);
+ }
+
+ REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), mask,
+ 0xFFFFFFFF);
}
for (i = 0; i < mac->mta_reg_count; i++)
@@ -922,7 +933,7 @@ static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data)
return *data;
}
-static irqreturn_t e1000_test_intr(int irq, void *data)
+static irqreturn_t e1000_test_intr(int __always_unused irq, void *data)
{
struct net_device *netdev = (struct net_device *) data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1272,7 +1283,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
if (hw->phy.type == e1000_phy_ife) {
/* force 100, set loopback */
- e1e_wphy(hw, PHY_CONTROL, 0x6100);
+ e1e_wphy(hw, MII_BMCR, 0x6100);
/* Now set up the MAC to the same speed/duplex as the PHY. */
ctrl_reg = er32(CTRL);
@@ -1295,9 +1306,9 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
/* Auto-MDI/MDIX Off */
e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
/* reset to update Auto-MDI/MDIX */
- e1e_wphy(hw, PHY_CONTROL, 0x9140);
+ e1e_wphy(hw, MII_BMCR, 0x9140);
/* autoneg off */
- e1e_wphy(hw, PHY_CONTROL, 0x8140);
+ e1e_wphy(hw, MII_BMCR, 0x8140);
break;
case e1000_phy_gg82563:
e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);
@@ -1309,7 +1320,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
phy_reg |= 0x006;
e1e_wphy(hw, PHY_REG(2, 21), phy_reg);
/* Assert SW reset for above settings to take effect */
- e1000e_commit_phy(hw);
+ hw->phy.ops.commit(hw);
mdelay(1);
/* Force Full Duplex */
e1e_rphy(hw, PHY_REG(769, 16), &phy_reg);
@@ -1343,7 +1354,6 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
e1e_rphy(hw, PHY_REG(776, 18), &phy_reg);
e1e_wphy(hw, PHY_REG(776, 18), phy_reg | 1);
/* Enable loopback on the PHY */
-#define I82577_PHY_LBK_CTRL 19
e1e_wphy(hw, I82577_PHY_LBK_CTRL, 0x8001);
break;
default:
@@ -1351,7 +1361,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
}
/* force 1000, set loopback */
- e1e_wphy(hw, PHY_CONTROL, 0x4140);
+ e1e_wphy(hw, MII_BMCR, 0x4140);
mdelay(250);
/* Now set up the MAC to the same speed/duplex as the PHY. */
@@ -1393,7 +1403,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 ctrl = er32(CTRL);
- int link = 0;
+ int link;
/* special requirements for 82571/82572 fiber adapters */
@@ -1526,11 +1536,12 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
hw->mac.autoneg = 1;
if (hw->phy.type == e1000_phy_gg82563)
e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x180);
- e1e_rphy(hw, PHY_CONTROL, &phy_reg);
- if (phy_reg & MII_CR_LOOPBACK) {
- phy_reg &= ~MII_CR_LOOPBACK;
- e1e_wphy(hw, PHY_CONTROL, phy_reg);
- e1000e_commit_phy(hw);
+ e1e_rphy(hw, MII_BMCR, &phy_reg);
+ if (phy_reg & BMCR_LOOPBACK) {
+ phy_reg &= ~BMCR_LOOPBACK;
+ e1e_wphy(hw, MII_BMCR, phy_reg);
+ if (hw->phy.ops.commit)
+ hw->phy.ops.commit(hw);
}
break;
}
@@ -1692,7 +1703,8 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
return *data;
}
-static int e1000e_get_sset_count(struct net_device *netdev, int sset)
+static int e1000e_get_sset_count(struct net_device __always_unused *netdev,
+ int sset)
{
switch (sset) {
case ETH_SS_TEST:
@@ -1955,7 +1967,7 @@ static int e1000_nway_reset(struct net_device *netdev)
}
static void e1000_get_ethtool_stats(struct net_device *netdev,
- struct ethtool_stats *stats,
+ struct ethtool_stats __always_unused *stats,
u64 *data)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1984,8 +1996,8 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
}
}
-static void e1000_get_strings(struct net_device *netdev, u32 stringset,
- u8 *data)
+static void e1000_get_strings(struct net_device __always_unused *netdev,
+ u32 stringset, u8 *data)
{
u8 *p = data;
int i;
@@ -2005,7 +2017,8 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset,
}
static int e1000_get_rxnfc(struct net_device *netdev,
- struct ethtool_rxnfc *info, u32 *rule_locs)
+ struct ethtool_rxnfc *info,
+ u32 __always_unused *rule_locs)
{
info->data = 0;
@@ -2051,6 +2064,171 @@ static int e1000_get_rxnfc(struct net_device *netdev,
}
}
+static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u16 cap_addr, adv_addr, lpa_addr, pcs_stat_addr, phy_data, lpi_ctrl;
+ u32 status, ret_val;
+
+ if (!(adapter->flags & FLAG_IS_ICH) ||
+ !(adapter->flags2 & FLAG2_HAS_EEE))
+ return -EOPNOTSUPP;
+
+ switch (hw->phy.type) {
+ case e1000_phy_82579:
+ cap_addr = I82579_EEE_CAPABILITY;
+ adv_addr = I82579_EEE_ADVERTISEMENT;
+ lpa_addr = I82579_EEE_LP_ABILITY;
+ pcs_stat_addr = I82579_EEE_PCS_STATUS;
+ break;
+ case e1000_phy_i217:
+ cap_addr = I217_EEE_CAPABILITY;
+ adv_addr = I217_EEE_ADVERTISEMENT;
+ lpa_addr = I217_EEE_LP_ABILITY;
+ pcs_stat_addr = I217_EEE_PCS_STATUS;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return -EBUSY;
+
+ /* EEE Capability */
+ ret_val = e1000_read_emi_reg_locked(hw, cap_addr, &phy_data);
+ if (ret_val)
+ goto release;
+ edata->supported = mmd_eee_cap_to_ethtool_sup_t(phy_data);
+
+ /* EEE Advertised */
+ ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &phy_data);
+ if (ret_val)
+ goto release;
+ edata->advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
+
+ /* EEE Link Partner Advertised */
+ ret_val = e1000_read_emi_reg_locked(hw, lpa_addr, &phy_data);
+ if (ret_val)
+ goto release;
+ edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
+
+ /* EEE PCS Status */
+ ret_val = e1000_read_emi_reg_locked(hw, pcs_stat_addr, &phy_data);
+ if (hw->phy.type == e1000_phy_82579)
+ phy_data <<= 8;
+
+release:
+ hw->phy.ops.release(hw);
+ if (ret_val)
+ return -ENODATA;
+
+ e1e_rphy(hw, I82579_LPI_CTRL, &lpi_ctrl);
+ status = er32(STATUS);
+
+ /* Result of the EEE auto negotiation - there is no register that
+ * has the status of the EEE negotiation so do a best-guess based
+ * on whether both Tx and Rx LPI indications have been received or
+ * base it on the link speed, the EEE advertised speeds on both ends
+ * and the speeds on which EEE is enabled locally.
+ */
+ if (((phy_data & E1000_EEE_TX_LPI_RCVD) &&
+ (phy_data & E1000_EEE_RX_LPI_RCVD)) ||
+ ((status & E1000_STATUS_SPEED_100) &&
+ (edata->advertised & ADVERTISED_100baseT_Full) &&
+ (edata->lp_advertised & ADVERTISED_100baseT_Full) &&
+ (lpi_ctrl & I82579_LPI_CTRL_100_ENABLE)) ||
+ ((status & E1000_STATUS_SPEED_1000) &&
+ (edata->advertised & ADVERTISED_1000baseT_Full) &&
+ (edata->lp_advertised & ADVERTISED_1000baseT_Full) &&
+ (lpi_ctrl & I82579_LPI_CTRL_1000_ENABLE)))
+ edata->eee_active = true;
+
+ edata->eee_enabled = !hw->dev_spec.ich8lan.eee_disable;
+ edata->tx_lpi_enabled = true;
+ edata->tx_lpi_timer = er32(LPIC) >> E1000_LPIC_LPIET_SHIFT;
+
+ return 0;
+}
+
+static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ struct ethtool_eee eee_curr;
+ s32 ret_val;
+
+ if (!(adapter->flags & FLAG_IS_ICH) ||
+ !(adapter->flags2 & FLAG2_HAS_EEE))
+ return -EOPNOTSUPP;
+
+ ret_val = e1000e_get_eee(netdev, &eee_curr);
+ if (ret_val)
+ return ret_val;
+
+ if (eee_curr.advertised != edata->advertised) {
+ e_err("Setting EEE advertisement is not supported\n");
+ return -EINVAL;
+ }
+
+ if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) {
+ e_err("Setting EEE tx-lpi is not supported\n");
+ return -EINVAL;
+ }
+
+ if (eee_curr.tx_lpi_timer != edata->tx_lpi_timer) {
+ e_err("Setting EEE Tx LPI timer is not supported\n");
+ return -EINVAL;
+ }
+
+ if (hw->dev_spec.ich8lan.eee_disable != !edata->eee_enabled) {
+ hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled;
+
+ /* reset the link */
+ if (netif_running(netdev))
+ e1000e_reinit_locked(adapter);
+ else
+ e1000e_reset(adapter);
+ }
+
+ return 0;
+}
+
+static int e1000e_get_ts_info(struct net_device *netdev,
+ struct ethtool_ts_info *info)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ ethtool_op_get_ts_info(netdev, info);
+
+ if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+ return 0;
+
+ info->so_timestamping |= (SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE);
+
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
+
+ info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_ALL));
+
+ if (adapter->ptp_clock)
+ info->phc_index = ptp_clock_index(adapter->ptp_clock);
+
+ return 0;
+}
+
static const struct ethtool_ops e1000_ethtool_ops = {
.get_settings = e1000_get_settings,
.set_settings = e1000_set_settings,
@@ -2078,7 +2256,9 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_coalesce = e1000_get_coalesce,
.set_coalesce = e1000_set_coalesce,
.get_rxnfc = e1000_get_rxnfc,
- .get_ts_info = ethtool_op_get_ts_info,
+ .get_ts_info = e1000e_get_ts_info,
+ .get_eee = e1000e_get_eee,
+ .set_eee = e1000e_set_eee,
};
void e1000e_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index cf217777586c..1e6b889aee87 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -29,331 +29,10 @@
#ifndef _E1000_HW_H_
#define _E1000_HW_H_
-#include <linux/types.h>
-
-struct e1000_hw;
-struct e1000_adapter;
-
+#include "regs.h"
#include "defines.h"
-enum e1e_registers {
- E1000_CTRL = 0x00000, /* Device Control - RW */
- E1000_STATUS = 0x00008, /* Device Status - RO */
- E1000_EECD = 0x00010, /* EEPROM/Flash Control - RW */
- E1000_EERD = 0x00014, /* EEPROM Read - RW */
- E1000_CTRL_EXT = 0x00018, /* Extended Device Control - RW */
- E1000_FLA = 0x0001C, /* Flash Access - RW */
- E1000_MDIC = 0x00020, /* MDI Control - RW */
- E1000_SCTL = 0x00024, /* SerDes Control - RW */
- E1000_FCAL = 0x00028, /* Flow Control Address Low - RW */
- E1000_FCAH = 0x0002C, /* Flow Control Address High -RW */
- E1000_FEXTNVM4 = 0x00024, /* Future Extended NVM 4 - RW */
- E1000_FEXTNVM = 0x00028, /* Future Extended NVM - RW */
- E1000_FCT = 0x00030, /* Flow Control Type - RW */
- E1000_VET = 0x00038, /* VLAN Ether Type - RW */
- E1000_FEXTNVM3 = 0x0003C, /* Future Extended NVM 3 - RW */
- E1000_ICR = 0x000C0, /* Interrupt Cause Read - R/clr */
- E1000_ITR = 0x000C4, /* Interrupt Throttling Rate - RW */
- E1000_ICS = 0x000C8, /* Interrupt Cause Set - WO */
- E1000_IMS = 0x000D0, /* Interrupt Mask Set - RW */
- E1000_IMC = 0x000D8, /* Interrupt Mask Clear - WO */
- E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */
- E1000_IAM = 0x000E0, /* Interrupt Acknowledge Auto Mask */
- E1000_IVAR = 0x000E4, /* Interrupt Vector Allocation - RW */
- E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */
-#define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2))
- E1000_RCTL = 0x00100, /* Rx Control - RW */
- E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value - RW */
- E1000_TXCW = 0x00178, /* Tx Configuration Word - RW */
- E1000_RXCW = 0x00180, /* Rx Configuration Word - RO */
- E1000_TCTL = 0x00400, /* Tx Control - RW */
- E1000_TCTL_EXT = 0x00404, /* Extended Tx Control - RW */
- E1000_TIPG = 0x00410, /* Tx Inter-packet gap -RW */
- E1000_AIT = 0x00458, /* Adaptive Interframe Spacing Throttle -RW */
- E1000_LEDCTL = 0x00E00, /* LED Control - RW */
- E1000_EXTCNF_CTRL = 0x00F00, /* Extended Configuration Control */
- E1000_EXTCNF_SIZE = 0x00F08, /* Extended Configuration Size */
- E1000_PHY_CTRL = 0x00F10, /* PHY Control Register in CSR */
-#define E1000_POEMB E1000_PHY_CTRL /* PHY OEM Bits */
- E1000_PBA = 0x01000, /* Packet Buffer Allocation - RW */
- E1000_PBS = 0x01008, /* Packet Buffer Size */
- E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */
- E1000_EEWR = 0x0102C, /* EEPROM Write Register - RW */
- E1000_FLOP = 0x0103C, /* FLASH Opcode Register */
- E1000_PBA_ECC = 0x01100, /* PBA ECC Register */
- E1000_ERT = 0x02008, /* Early Rx Threshold - RW */
- E1000_FCRTL = 0x02160, /* Flow Control Receive Threshold Low - RW */
- E1000_FCRTH = 0x02168, /* Flow Control Receive Threshold High - RW */
- E1000_PSRCTL = 0x02170, /* Packet Split Receive Control - RW */
-/* Convenience macros
- *
- * Note: "_n" is the queue number of the register to be written to.
- *
- * Example usage:
- * E1000_RDBAL(current_rx_queue)
- */
- E1000_RDBAL_BASE = 0x02800, /* Rx Descriptor Base Address Low - RW */
-#define E1000_RDBAL(_n) (E1000_RDBAL_BASE + (_n << 8))
- E1000_RDBAH_BASE = 0x02804, /* Rx Descriptor Base Address High - RW */
-#define E1000_RDBAH(_n) (E1000_RDBAH_BASE + (_n << 8))
- E1000_RDLEN_BASE = 0x02808, /* Rx Descriptor Length - RW */
-#define E1000_RDLEN(_n) (E1000_RDLEN_BASE + (_n << 8))
- E1000_RDH_BASE = 0x02810, /* Rx Descriptor Head - RW */
-#define E1000_RDH(_n) (E1000_RDH_BASE + (_n << 8))
- E1000_RDT_BASE = 0x02818, /* Rx Descriptor Tail - RW */
-#define E1000_RDT(_n) (E1000_RDT_BASE + (_n << 8))
- E1000_RDTR = 0x02820, /* Rx Delay Timer - RW */
- E1000_RXDCTL_BASE = 0x02828, /* Rx Descriptor Control - RW */
-#define E1000_RXDCTL(_n) (E1000_RXDCTL_BASE + (_n << 8))
- E1000_RADV = 0x0282C, /* Rx Interrupt Absolute Delay Timer - RW */
-
- E1000_KABGTXD = 0x03004, /* AFE Band Gap Transmit Ref Data */
- E1000_TDBAL_BASE = 0x03800, /* Tx Descriptor Base Address Low - RW */
-#define E1000_TDBAL(_n) (E1000_TDBAL_BASE + (_n << 8))
- E1000_TDBAH_BASE = 0x03804, /* Tx Descriptor Base Address High - RW */
-#define E1000_TDBAH(_n) (E1000_TDBAH_BASE + (_n << 8))
- E1000_TDLEN_BASE = 0x03808, /* Tx Descriptor Length - RW */
-#define E1000_TDLEN(_n) (E1000_TDLEN_BASE + (_n << 8))
- E1000_TDH_BASE = 0x03810, /* Tx Descriptor Head - RW */
-#define E1000_TDH(_n) (E1000_TDH_BASE + (_n << 8))
- E1000_TDT_BASE = 0x03818, /* Tx Descriptor Tail - RW */
-#define E1000_TDT(_n) (E1000_TDT_BASE + (_n << 8))
- E1000_TIDV = 0x03820, /* Tx Interrupt Delay Value - RW */
- E1000_TXDCTL_BASE = 0x03828, /* Tx Descriptor Control - RW */
-#define E1000_TXDCTL(_n) (E1000_TXDCTL_BASE + (_n << 8))
- E1000_TADV = 0x0382C, /* Tx Interrupt Absolute Delay Val - RW */
- E1000_TARC_BASE = 0x03840, /* Tx Arbitration Count (0) */
-#define E1000_TARC(_n) (E1000_TARC_BASE + (_n << 8))
- E1000_CRCERRS = 0x04000, /* CRC Error Count - R/clr */
- E1000_ALGNERRC = 0x04004, /* Alignment Error Count - R/clr */
- E1000_SYMERRS = 0x04008, /* Symbol Error Count - R/clr */
- E1000_RXERRC = 0x0400C, /* Receive Error Count - R/clr */
- E1000_MPC = 0x04010, /* Missed Packet Count - R/clr */
- E1000_SCC = 0x04014, /* Single Collision Count - R/clr */
- E1000_ECOL = 0x04018, /* Excessive Collision Count - R/clr */
- E1000_MCC = 0x0401C, /* Multiple Collision Count - R/clr */
- E1000_LATECOL = 0x04020, /* Late Collision Count - R/clr */
- E1000_COLC = 0x04028, /* Collision Count - R/clr */
- E1000_DC = 0x04030, /* Defer Count - R/clr */
- E1000_TNCRS = 0x04034, /* Tx-No CRS - R/clr */
- E1000_SEC = 0x04038, /* Sequence Error Count - R/clr */
- E1000_CEXTERR = 0x0403C, /* Carrier Extension Error Count - R/clr */
- E1000_RLEC = 0x04040, /* Receive Length Error Count - R/clr */
- E1000_XONRXC = 0x04048, /* XON Rx Count - R/clr */
- E1000_XONTXC = 0x0404C, /* XON Tx Count - R/clr */
- E1000_XOFFRXC = 0x04050, /* XOFF Rx Count - R/clr */
- E1000_XOFFTXC = 0x04054, /* XOFF Tx Count - R/clr */
- E1000_FCRUC = 0x04058, /* Flow Control Rx Unsupported Count- R/clr */
- E1000_PRC64 = 0x0405C, /* Packets Rx (64 bytes) - R/clr */
- E1000_PRC127 = 0x04060, /* Packets Rx (65-127 bytes) - R/clr */
- E1000_PRC255 = 0x04064, /* Packets Rx (128-255 bytes) - R/clr */
- E1000_PRC511 = 0x04068, /* Packets Rx (255-511 bytes) - R/clr */
- E1000_PRC1023 = 0x0406C, /* Packets Rx (512-1023 bytes) - R/clr */
- E1000_PRC1522 = 0x04070, /* Packets Rx (1024-1522 bytes) - R/clr */
- E1000_GPRC = 0x04074, /* Good Packets Rx Count - R/clr */
- E1000_BPRC = 0x04078, /* Broadcast Packets Rx Count - R/clr */
- E1000_MPRC = 0x0407C, /* Multicast Packets Rx Count - R/clr */
- E1000_GPTC = 0x04080, /* Good Packets Tx Count - R/clr */
- E1000_GORCL = 0x04088, /* Good Octets Rx Count Low - R/clr */
- E1000_GORCH = 0x0408C, /* Good Octets Rx Count High - R/clr */
- E1000_GOTCL = 0x04090, /* Good Octets Tx Count Low - R/clr */
- E1000_GOTCH = 0x04094, /* Good Octets Tx Count High - R/clr */
- E1000_RNBC = 0x040A0, /* Rx No Buffers Count - R/clr */
- E1000_RUC = 0x040A4, /* Rx Undersize Count - R/clr */
- E1000_RFC = 0x040A8, /* Rx Fragment Count - R/clr */
- E1000_ROC = 0x040AC, /* Rx Oversize Count - R/clr */
- E1000_RJC = 0x040B0, /* Rx Jabber Count - R/clr */
- E1000_MGTPRC = 0x040B4, /* Management Packets Rx Count - R/clr */
- E1000_MGTPDC = 0x040B8, /* Management Packets Dropped Count - R/clr */
- E1000_MGTPTC = 0x040BC, /* Management Packets Tx Count - R/clr */
- E1000_TORL = 0x040C0, /* Total Octets Rx Low - R/clr */
- E1000_TORH = 0x040C4, /* Total Octets Rx High - R/clr */
- E1000_TOTL = 0x040C8, /* Total Octets Tx Low - R/clr */
- E1000_TOTH = 0x040CC, /* Total Octets Tx High - R/clr */
- E1000_TPR = 0x040D0, /* Total Packets Rx - R/clr */
- E1000_TPT = 0x040D4, /* Total Packets Tx - R/clr */
- E1000_PTC64 = 0x040D8, /* Packets Tx (64 bytes) - R/clr */
- E1000_PTC127 = 0x040DC, /* Packets Tx (65-127 bytes) - R/clr */
- E1000_PTC255 = 0x040E0, /* Packets Tx (128-255 bytes) - R/clr */
- E1000_PTC511 = 0x040E4, /* Packets Tx (256-511 bytes) - R/clr */
- E1000_PTC1023 = 0x040E8, /* Packets Tx (512-1023 bytes) - R/clr */
- E1000_PTC1522 = 0x040EC, /* Packets Tx (1024-1522 Bytes) - R/clr */
- E1000_MPTC = 0x040F0, /* Multicast Packets Tx Count - R/clr */
- E1000_BPTC = 0x040F4, /* Broadcast Packets Tx Count - R/clr */
- E1000_TSCTC = 0x040F8, /* TCP Segmentation Context Tx - R/clr */
- E1000_TSCTFC = 0x040FC, /* TCP Segmentation Context Tx Fail - R/clr */
- E1000_IAC = 0x04100, /* Interrupt Assertion Count */
- E1000_ICRXPTC = 0x04104, /* Irq Cause Rx Packet Timer Expire Count */
- E1000_ICRXATC = 0x04108, /* Irq Cause Rx Abs Timer Expire Count */
- E1000_ICTXPTC = 0x0410C, /* Irq Cause Tx Packet Timer Expire Count */
- E1000_ICTXATC = 0x04110, /* Irq Cause Tx Abs Timer Expire Count */
- E1000_ICTXQEC = 0x04118, /* Irq Cause Tx Queue Empty Count */
- E1000_ICTXQMTC = 0x0411C, /* Irq Cause Tx Queue MinThreshold Count */
- E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */
- E1000_ICRXOC = 0x04124, /* Irq Cause Receiver Overrun Count */
- E1000_RXCSUM = 0x05000, /* Rx Checksum Control - RW */
- E1000_RFCTL = 0x05008, /* Receive Filter Control */
- E1000_MTA = 0x05200, /* Multicast Table Array - RW Array */
- E1000_RAL_BASE = 0x05400, /* Receive Address Low - RW */
-#define E1000_RAL(_n) (E1000_RAL_BASE + ((_n) * 8))
-#define E1000_RA (E1000_RAL(0))
- E1000_RAH_BASE = 0x05404, /* Receive Address High - RW */
-#define E1000_RAH(_n) (E1000_RAH_BASE + ((_n) * 8))
- E1000_SHRAL_PCH_LPT_BASE = 0x05408,
-#define E1000_SHRAL_PCH_LPT(_n) (E1000_SHRAL_PCH_LPT_BASE + ((_n) * 8))
- E1000_SHRAH_PCH_LTP_BASE = 0x0540C,
-#define E1000_SHRAH_PCH_LPT(_n) (E1000_SHRAH_PCH_LTP_BASE + ((_n) * 8))
- E1000_SHRAL_BASE = 0x05438, /* Shared Receive Address Low - RW */
-#define E1000_SHRAL(_n) (E1000_SHRAL_BASE + ((_n) * 8))
- E1000_SHRAH_BASE = 0x0543C, /* Shared Receive Address High - RW */
-#define E1000_SHRAH(_n) (E1000_SHRAH_BASE + ((_n) * 8))
- E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */
- E1000_WUC = 0x05800, /* Wakeup Control - RW */
- E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */
- E1000_WUS = 0x05810, /* Wakeup Status - RO */
- E1000_MRQC = 0x05818, /* Multiple Receive Control - RW */
- E1000_MANC = 0x05820, /* Management Control - RW */
- E1000_FFLT = 0x05F00, /* Flexible Filter Length Table - RW Array */
- E1000_HOST_IF = 0x08800, /* Host Interface */
-
- E1000_KMRNCTRLSTA = 0x00034, /* MAC-PHY interface - RW */
- E1000_MANC2H = 0x05860, /* Management Control To Host - RW */
- E1000_MDEF_BASE = 0x05890, /* Management Decision Filters */
-#define E1000_MDEF(_n) (E1000_MDEF_BASE + ((_n) * 4))
- E1000_SW_FW_SYNC = 0x05B5C, /* Software-Firmware Synchronization - RW */
- E1000_GCR = 0x05B00, /* PCI-Ex Control */
- E1000_GCR2 = 0x05B64, /* PCI-Ex Control #2 */
- E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */
- E1000_SWSM = 0x05B50, /* SW Semaphore */
- E1000_FWSM = 0x05B54, /* FW Semaphore */
- E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */
- E1000_RETA_BASE = 0x05C00, /* Redirection Table - RW */
-#define E1000_RETA(_n) (E1000_RETA_BASE + ((_n) * 4))
- E1000_RSSRK_BASE = 0x05C80, /* RSS Random Key - RW */
-#define E1000_RSSRK(_n) (E1000_RSSRK_BASE + ((_n) * 4))
- E1000_FFLT_DBG = 0x05F04, /* Debug Register */
- E1000_PCH_RAICC_BASE = 0x05F50, /* Receive Address Initial CRC */
-#define E1000_PCH_RAICC(_n) (E1000_PCH_RAICC_BASE + ((_n) * 4))
-#define E1000_CRC_OFFSET E1000_PCH_RAICC_BASE
- E1000_HICR = 0x08F00, /* Host Interface Control */
-};
-
-#define E1000_MAX_PHY_ADDR 4
-
-/* IGP01E1000 Specific Registers */
-#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
-#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */
-#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */
-#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */
-#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */
-#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */
-#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */
-#define IGP_PAGE_SHIFT 5
-#define PHY_REG_MASK 0x1F
-
-#define BM_WUC_PAGE 800
-#define BM_WUC_ADDRESS_OPCODE 0x11
-#define BM_WUC_DATA_OPCODE 0x12
-#define BM_WUC_ENABLE_PAGE 769
-#define BM_WUC_ENABLE_REG 17
-#define BM_WUC_ENABLE_BIT (1 << 2)
-#define BM_WUC_HOST_WU_BIT (1 << 4)
-#define BM_WUC_ME_WU_BIT (1 << 5)
-
-#define BM_WUC PHY_REG(BM_WUC_PAGE, 1)
-#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2)
-#define BM_WUS PHY_REG(BM_WUC_PAGE, 3)
-
-#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
-#define IGP01E1000_PHY_POLARITY_MASK 0x0078
-
-#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
-#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */
-
-#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
-
-#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */
-#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */
-#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */
-
-#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000
-
-#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
-#define IGP01E1000_PSSR_MDIX 0x0800
-#define IGP01E1000_PSSR_SPEED_MASK 0xC000
-#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000
-
-#define IGP02E1000_PHY_CHANNEL_NUM 4
-#define IGP02E1000_PHY_AGC_A 0x11B1
-#define IGP02E1000_PHY_AGC_B 0x12B1
-#define IGP02E1000_PHY_AGC_C 0x14B1
-#define IGP02E1000_PHY_AGC_D 0x18B1
-
-#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */
-#define IGP02E1000_AGC_LENGTH_MASK 0x7F
-#define IGP02E1000_AGC_RANGE 15
-
-/* manage.c */
-#define E1000_VFTA_ENTRY_SHIFT 5
-#define E1000_VFTA_ENTRY_MASK 0x7F
-#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
-
-#define E1000_HICR_EN 0x01 /* Enable bit - RO */
-/* Driver sets this bit when done to put command in RAM */
-#define E1000_HICR_C 0x02
-#define E1000_HICR_FW_RESET_ENABLE 0x40
-#define E1000_HICR_FW_RESET 0x80
-
-#define E1000_FWSM_MODE_MASK 0xE
-#define E1000_FWSM_MODE_SHIFT 1
-
-#define E1000_MNG_IAMT_MODE 0x3
-#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10
-#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0
-#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10
-#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64
-#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
-#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
-
-/* nvm.c */
-#define E1000_STM_OPCODE 0xDB00
-
-#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000
-#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16
-#define E1000_KMRNCTRLSTA_REN 0x00200000
-#define E1000_KMRNCTRLSTA_CTRL_OFFSET 0x1 /* Kumeran Control */
-#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */
-#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */
-#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */
-#define E1000_KMRNCTRLSTA_IBIST_DISABLE 0x0200 /* Kumeran IBIST Disable */
-#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */
-#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7
-#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002
-#define E1000_KMRNCTRLSTA_HD_CTRL 0x10 /* Kumeran HD Control */
-
-#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
-#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */
-#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
-#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */
-
-/* IFE PHY Extended Status Control */
-#define IFE_PESC_POLARITY_REVERSED 0x0100
-
-/* IFE PHY Special Control */
-#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010
-#define IFE_PSC_FORCE_POLARITY 0x0020
-
-/* IFE PHY Special Control and LED Control */
-#define IFE_PSCL_PROBE_MODE 0x0020
-#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
-#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
-
-/* IFE PHY MDIX Control */
-#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
-#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */
-#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
-
-#define E1000_CABLE_LENGTH_UNDEFINED 0xFF
+struct e1000_hw;
#define E1000_DEV_ID_82571EB_COPPER 0x105E
#define E1000_DEV_ID_82571EB_FIBER 0x105F
@@ -373,13 +52,11 @@ enum e1e_registers {
#define E1000_DEV_ID_82573L 0x109A
#define E1000_DEV_ID_82574L 0x10D3
#define E1000_DEV_ID_82574LA 0x10F6
-#define E1000_DEV_ID_82583V 0x150C
-
+#define E1000_DEV_ID_82583V 0x150C
#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
-
#define E1000_DEV_ID_ICH8_82567V_3 0x1501
#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
@@ -414,12 +91,12 @@ enum e1e_registers {
#define E1000_DEV_ID_PCH_LPTLP_I218_LM 0x155A
#define E1000_DEV_ID_PCH_LPTLP_I218_V 0x1559
-#define E1000_REVISION_4 4
+#define E1000_REVISION_4 4
-#define E1000_FUNC_1 1
+#define E1000_FUNC_1 1
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3
enum e1000_mac_type {
e1000_82571,
@@ -524,16 +201,6 @@ enum e1000_serdes_link_state {
e1000_serdes_link_forced_up
};
-/* Receive Descriptor */
-struct e1000_rx_desc {
- __le64 buffer_addr; /* Address of the descriptor's data buffer */
- __le16 length; /* Length of data DMAed into data buffer */
- __le16 csum; /* Packet checksum */
- u8 status; /* Descriptor status */
- u8 errors; /* Descriptor Errors */
- __le16 special;
-};
-
/* Receive Descriptor - Extended */
union e1000_rx_desc_extended {
struct {
@@ -656,7 +323,7 @@ struct e1000_data_desc {
struct {
u8 status; /* Descriptor status */
u8 popts; /* Packet Options */
- __le16 special; /* */
+ __le16 special;
} fields;
} upper;
};
@@ -752,7 +419,7 @@ struct e1000_host_command_header {
u8 checksum;
};
-#define E1000_HI_MAX_DATA_LENGTH 252
+#define E1000_HI_MAX_DATA_LENGTH 252
struct e1000_host_command_info {
struct e1000_host_command_header command_header;
u8 command_data[E1000_HI_MAX_DATA_LENGTH];
@@ -767,13 +434,18 @@ struct e1000_host_mng_command_header {
u16 command_length;
};
-#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
struct e1000_host_mng_command_info {
struct e1000_host_mng_command_header command_header;
u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
};
-/* Function pointers and static data for the MAC. */
+#include "mac.h"
+#include "phy.h"
+#include "nvm.h"
+#include "manage.h"
+
+/* Function pointers for the MAC. */
struct e1000_mac_operations {
s32 (*id_led_init)(struct e1000_hw *);
s32 (*blink_led)(struct e1000_hw *);
@@ -1002,4 +674,8 @@ struct e1000_hw {
} dev_spec;
};
+#include "82571.h"
+#include "80003es2lan.h"
+#include "ich8lan.h"
+
#endif
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 976336547607..dff7bff8b8e0 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -57,147 +57,6 @@
#include "e1000.h"
-#define ICH_FLASH_GFPREG 0x0000
-#define ICH_FLASH_HSFSTS 0x0004
-#define ICH_FLASH_HSFCTL 0x0006
-#define ICH_FLASH_FADDR 0x0008
-#define ICH_FLASH_FDATA0 0x0010
-#define ICH_FLASH_PR0 0x0074
-
-#define ICH_FLASH_READ_COMMAND_TIMEOUT 500
-#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500
-#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 3000000
-#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
-#define ICH_FLASH_CYCLE_REPEAT_COUNT 10
-
-#define ICH_CYCLE_READ 0
-#define ICH_CYCLE_WRITE 2
-#define ICH_CYCLE_ERASE 3
-
-#define FLASH_GFPREG_BASE_MASK 0x1FFF
-#define FLASH_SECTOR_ADDR_SHIFT 12
-
-#define ICH_FLASH_SEG_SIZE_256 256
-#define ICH_FLASH_SEG_SIZE_4K 4096
-#define ICH_FLASH_SEG_SIZE_8K 8192
-#define ICH_FLASH_SEG_SIZE_64K 65536
-
-
-#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */
-/* FW established a valid mode */
-#define E1000_ICH_FWSM_FW_VALID 0x00008000
-
-#define E1000_ICH_MNG_IAMT_MODE 0x2
-
-#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
- (ID_LED_DEF1_OFF2 << 8) | \
- (ID_LED_DEF1_ON2 << 4) | \
- (ID_LED_DEF1_DEF2))
-
-#define E1000_ICH_NVM_SIG_WORD 0x13
-#define E1000_ICH_NVM_SIG_MASK 0xC000
-#define E1000_ICH_NVM_VALID_SIG_MASK 0xC0
-#define E1000_ICH_NVM_SIG_VALUE 0x80
-
-#define E1000_ICH8_LAN_INIT_TIMEOUT 1500
-
-#define E1000_FEXTNVM_SW_CONFIG 1
-#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */
-
-#define E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK 0x0C000000
-#define E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC 0x08000000
-
-#define E1000_FEXTNVM4_BEACON_DURATION_MASK 0x7
-#define E1000_FEXTNVM4_BEACON_DURATION_8USEC 0x7
-#define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3
-
-#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL
-
-#define E1000_ICH_RAR_ENTRIES 7
-#define E1000_PCH2_RAR_ENTRIES 5 /* RAR[0], SHRA[0-3] */
-#define E1000_PCH_LPT_RAR_ENTRIES 12 /* RAR[0], SHRA[0-10] */
-
-#define PHY_PAGE_SHIFT 5
-#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
- ((reg) & MAX_PHY_REG_ADDRESS))
-#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */
-#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */
-
-#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002
-#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
-#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200
-
-#define HV_LED_CONFIG PHY_REG(768, 30) /* LED Configuration */
-
-#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in milliseconds */
-
-/* SMBus Control Phy Register */
-#define CV_SMB_CTRL PHY_REG(769, 23)
-#define CV_SMB_CTRL_FORCE_SMBUS 0x0001
-
-/* SMBus Address Phy Register */
-#define HV_SMB_ADDR PHY_REG(768, 26)
-#define HV_SMB_ADDR_MASK 0x007F
-#define HV_SMB_ADDR_PEC_EN 0x0200
-#define HV_SMB_ADDR_VALID 0x0080
-#define HV_SMB_ADDR_FREQ_MASK 0x1100
-#define HV_SMB_ADDR_FREQ_LOW_SHIFT 8
-#define HV_SMB_ADDR_FREQ_HIGH_SHIFT 12
-
-/* PHY Power Management Control */
-#define HV_PM_CTRL PHY_REG(770, 17)
-#define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100
-
-/* PHY Low Power Idle Control */
-#define I82579_LPI_CTRL PHY_REG(772, 20)
-#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
-#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT 0x80
-
-/* EMI Registers */
-#define I82579_EMI_ADDR 0x10
-#define I82579_EMI_DATA 0x11
-#define I82579_LPI_UPDATE_TIMER 0x4805 /* in 40ns units + 40 ns base value */
-#define I82579_MSE_THRESHOLD 0x084F /* Mean Square Error Threshold */
-#define I82579_MSE_LINK_DOWN 0x2411 /* MSE count before dropping link */
-#define I217_EEE_ADVERTISEMENT 0x8001 /* IEEE MMD Register 7.60 */
-#define I217_EEE_LP_ABILITY 0x8002 /* IEEE MMD Register 7.61 */
-#define I217_EEE_100_SUPPORTED (1 << 1) /* 100BaseTx EEE supported */
-
-/* Intel Rapid Start Technology Support */
-#define I217_PROXY_CTRL BM_PHY_REG(BM_WUC_PAGE, 70)
-#define I217_PROXY_CTRL_AUTO_DISABLE 0x0080
-#define I217_SxCTRL PHY_REG(BM_PORT_CTRL_PAGE, 28)
-#define I217_SxCTRL_ENABLE_LPI_RESET 0x1000
-#define I217_CGFREG PHY_REG(772, 29)
-#define I217_CGFREG_ENABLE_MTA_RESET 0x0002
-#define I217_MEMPWR PHY_REG(772, 26)
-#define I217_MEMPWR_DISABLE_SMB_RELEASE 0x0010
-
-/* Strapping Option Register - RO */
-#define E1000_STRAP 0x0000C
-#define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000
-#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17
-#define E1000_STRAP_SMT_FREQ_MASK 0x00003000
-#define E1000_STRAP_SMT_FREQ_SHIFT 12
-
-/* OEM Bits Phy Register */
-#define HV_OEM_BITS PHY_REG(768, 25)
-#define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */
-#define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */
-#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
-
-#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */
-#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */
-
-/* KMRN Mode Control */
-#define HV_KMRN_MODE_CTRL PHY_REG(769, 16)
-#define HV_KMRN_MDIO_SLOW 0x0400
-
-/* KMRN FIFO Control and Status */
-#define HV_KMRN_FIFO_CTRLSTA PHY_REG(770, 16)
-#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK 0x7000
-#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT 12
-
/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
/* Offset 04h HSFSTS */
union ich8_hws_flash_status {
@@ -252,7 +111,6 @@ union ich8_flash_protected_range {
u32 regval;
};
-static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
@@ -264,9 +122,7 @@ static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
u16 *data);
static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
u8 size, u16 *data);
-static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
-static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
static s32 e1000_led_on_ich8lan(struct e1000_hw *hw);
static s32 e1000_led_off_ich8lan(struct e1000_hw *hw);
@@ -278,7 +134,7 @@ static s32 e1000_led_off_pchlan(struct e1000_hw *hw);
static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
-static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
+static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
@@ -330,12 +186,12 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
u16 retry_count;
for (retry_count = 0; retry_count < 2; retry_count++) {
- ret_val = e1e_rphy_locked(hw, PHY_ID1, &phy_reg);
+ ret_val = e1e_rphy_locked(hw, MII_PHYSID1, &phy_reg);
if (ret_val || (phy_reg == 0xFFFF))
continue;
phy_id = (u32)(phy_reg << 16);
- ret_val = e1e_rphy_locked(hw, PHY_ID2, &phy_reg);
+ ret_val = e1e_rphy_locked(hw, MII_PHYSID2, &phy_reg);
if (ret_val || (phy_reg == 0xFFFF)) {
phy_id = 0;
continue;
@@ -378,10 +234,15 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
s32 ret_val;
u16 phy_reg;
+ /* Gate automatic PHY configuration by hardware on managed and
+ * non-managed 82579 and newer adapters.
+ */
+ e1000_gate_hw_phy_config_ich8lan(hw, true);
+
ret_val = hw->phy.ops.acquire(hw);
if (ret_val) {
e_dbg("Failed to initialize PHY flow\n");
- return ret_val;
+ goto out;
}
/* The MAC-PHY interconnect may be in SMBus mode. If the PHY is
@@ -402,13 +263,6 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
/* fall-through */
case e1000_pch2lan:
- /* Gate automatic PHY configuration by hardware on
- * non-managed 82579
- */
- if ((hw->mac.type == e1000_pch2lan) &&
- !(fwsm & E1000_ICH_FWSM_FW_VALID))
- e1000_gate_hw_phy_config_ich8lan(hw, true);
-
if (e1000_phy_is_accessible_pchlan(hw)) {
if (hw->mac.type == e1000_pch_lpt) {
/* Unforce SMBus mode in PHY */
@@ -443,6 +297,15 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
ew32(FEXTNVM3, mac_reg);
+ if (hw->mac.type == e1000_pch_lpt) {
+ /* Toggling LANPHYPC brings the PHY out of SMBus mode
+ * So ensure that the MAC is also out of SMBus mode
+ */
+ mac_reg = er32(CTRL_EXT);
+ mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+ ew32(CTRL_EXT, mac_reg);
+ }
+
/* Toggle LANPHYPC Value bit */
mac_reg = er32(CTRL);
mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
@@ -476,6 +339,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
*/
ret_val = e1000e_phy_hw_reset_generic(hw);
+out:
/* Ungate automatic PHY configuration on non-managed 82579 */
if ((hw->mac.type == e1000_pch2lan) &&
!(fwsm & E1000_ICH_FWSM_FW_VALID)) {
@@ -495,7 +359,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val = 0;
+ s32 ret_val;
phy->addr = 1;
phy->reset_delay_us = 100;
@@ -778,68 +642,143 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
if (mac->type == e1000_ich8lan)
e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
- /* Gate automatic PHY configuration by hardware on managed
- * 82579 and i217
- */
- if ((mac->type == e1000_pch2lan || mac->type == e1000_pch_lpt) &&
- (er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
- e1000_gate_hw_phy_config_ich8lan(hw, true);
-
return 0;
}
/**
+ * __e1000_access_emi_reg_locked - Read/write EMI register
+ * @hw: pointer to the HW structure
+ * @addr: EMI address to program
+ * @data: pointer to value to read/write from/to the EMI address
+ * @read: boolean flag to indicate read or write
+ *
+ * This helper function assumes the SW/FW/HW Semaphore is already acquired.
+ **/
+static s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address,
+ u16 *data, bool read)
+{
+ s32 ret_val;
+
+ ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, address);
+ if (ret_val)
+ return ret_val;
+
+ if (read)
+ ret_val = e1e_rphy_locked(hw, I82579_EMI_DATA, data);
+ else
+ ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, *data);
+
+ return ret_val;
+}
+
+/**
+ * e1000_read_emi_reg_locked - Read Extended Management Interface register
+ * @hw: pointer to the HW structure
+ * @addr: EMI address to program
+ * @data: value to be read from the EMI address
+ *
+ * Assumes the SW/FW/HW Semaphore is already acquired.
+ **/
+s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data)
+{
+ return __e1000_access_emi_reg_locked(hw, addr, data, true);
+}
+
+/**
+ * e1000_write_emi_reg_locked - Write Extended Management Interface register
+ * @hw: pointer to the HW structure
+ * @addr: EMI address to program
+ * @data: value to be written to the EMI address
+ *
+ * Assumes the SW/FW/HW Semaphore is already acquired.
+ **/
+static s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
+{
+ return __e1000_access_emi_reg_locked(hw, addr, &data, false);
+}
+
+/**
* e1000_set_eee_pchlan - Enable/disable EEE support
* @hw: pointer to the HW structure
*
- * Enable/disable EEE based on setting in dev_spec structure. The bits in
- * the LPI Control register will remain set only if/when link is up.
+ * Enable/disable EEE based on setting in dev_spec structure, the duplex of
+ * the link and the EEE capabilities of the link partner. The LPI Control
+ * register bits will remain set only if/when link is up.
**/
static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
{
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
- s32 ret_val = 0;
- u16 phy_reg;
+ s32 ret_val;
+ u16 lpi_ctrl;
if ((hw->phy.type != e1000_phy_82579) &&
(hw->phy.type != e1000_phy_i217))
return 0;
- ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
+ ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
return ret_val;
- if (dev_spec->eee_disable)
- phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
- else
- phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;
-
- ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
+ ret_val = e1e_rphy_locked(hw, I82579_LPI_CTRL, &lpi_ctrl);
if (ret_val)
- return ret_val;
+ goto release;
+
+ /* Clear bits that enable EEE in various speeds */
+ lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK;
+
+ /* Enable EEE if not disabled by user */
+ if (!dev_spec->eee_disable) {
+ u16 lpa, pcs_status, data;
- if ((hw->phy.type == e1000_phy_i217) && !dev_spec->eee_disable) {
/* Save off link partner's EEE ability */
- ret_val = hw->phy.ops.acquire(hw);
- if (ret_val)
- return ret_val;
- ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
- I217_EEE_LP_ABILITY);
+ switch (hw->phy.type) {
+ case e1000_phy_82579:
+ lpa = I82579_EEE_LP_ABILITY;
+ pcs_status = I82579_EEE_PCS_STATUS;
+ break;
+ case e1000_phy_i217:
+ lpa = I217_EEE_LP_ABILITY;
+ pcs_status = I217_EEE_PCS_STATUS;
+ break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto release;
+ }
+ ret_val = e1000_read_emi_reg_locked(hw, lpa,
+ &dev_spec->eee_lp_ability);
if (ret_val)
goto release;
- e1e_rphy_locked(hw, I82579_EMI_DATA, &dev_spec->eee_lp_ability);
- /* EEE is not supported in 100Half, so ignore partner's EEE
- * in 100 ability if full-duplex is not advertised.
+ /* Enable EEE only for speeds in which the link partner is
+ * EEE capable.
*/
- e1e_rphy_locked(hw, PHY_LP_ABILITY, &phy_reg);
- if (!(phy_reg & NWAY_LPAR_100TX_FD_CAPS))
- dev_spec->eee_lp_ability &= ~I217_EEE_100_SUPPORTED;
-release:
- hw->phy.ops.release(hw);
+ if (dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
+ lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
+
+ if (dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
+ e1e_rphy_locked(hw, MII_LPA, &data);
+ if (data & LPA_100FULL)
+ lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
+ else
+ /* EEE is not supported in 100Half, so ignore
+ * partner's EEE in 100 ability if full-duplex
+ * is not advertised.
+ */
+ dev_spec->eee_lp_ability &=
+ ~I82579_EEE_100_SUPPORTED;
+ }
+
+ /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
+ ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
+ if (ret_val)
+ goto release;
}
- return 0;
+ ret_val = e1e_wphy_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
+release:
+ hw->phy.ops.release(hw);
+
+ return ret_val;
}
/**
@@ -1017,7 +956,7 @@ static DEFINE_MUTEX(nvm_mutex);
*
* Acquires the mutex for performing NVM operations.
**/
-static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
+static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw __always_unused *hw)
{
mutex_lock(&nvm_mutex);
@@ -1030,7 +969,7 @@ static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
*
* Releases the mutex used while performing NVM operations.
**/
-static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
+static void e1000_release_nvm_ich8lan(struct e1000_hw __always_unused *hw)
{
mutex_unlock(&nvm_mutex);
}
@@ -1322,7 +1261,7 @@ static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
u32 strap = er32(STRAP);
u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >>
E1000_STRAP_SMT_FREQ_SHIFT;
- s32 ret_val = 0;
+ s32 ret_val;
strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
@@ -1558,7 +1497,7 @@ release:
**/
s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
{
- s32 ret_val = 0;
+ s32 ret_val;
u32 ctrl_reg = 0;
u32 ctrl_ext = 0;
u32 reg = 0;
@@ -1727,7 +1666,7 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
*/
if (hw->phy.revision < 2) {
e1000e_phy_sw_reset(hw);
- ret_val = e1e_wphy(hw, PHY_CONTROL, 0x3140);
+ ret_val = e1e_wphy(hw, MII_BMCR, 0x3140);
}
}
@@ -1757,6 +1696,11 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
if (ret_val)
goto release;
ret_val = e1e_wphy_locked(hw, BM_PORT_GEN_CFG, phy_data & 0x00FF);
+ if (ret_val)
+ goto release;
+
+ /* set MSE higher to enable link to stay up when noise is high */
+ ret_val = e1000_write_emi_reg_locked(hw, I82577_MSE_THRESHOLD, 0x0034);
release:
hw->phy.ops.release(hw);
@@ -1983,22 +1927,18 @@ static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
/* Set MDIO slow mode before any other MDIO access */
ret_val = e1000_set_mdio_slow_mode_hv(hw);
+ if (ret_val)
+ return ret_val;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
return ret_val;
- ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, I82579_MSE_THRESHOLD);
- if (ret_val)
- goto release;
/* set MSE higher to enable link to stay up when noise is high */
- ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x0034);
- if (ret_val)
- goto release;
- ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, I82579_MSE_LINK_DOWN);
+ ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_THRESHOLD, 0x0034);
if (ret_val)
goto release;
/* drop link after 5 times MSE threshold was reached */
- ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x0005);
+ ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_LINK_DOWN, 0x0005);
release:
hw->phy.ops.release(hw);
@@ -2172,10 +2112,9 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
return ret_val;
- ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
- I82579_LPI_UPDATE_TIMER);
- if (!ret_val)
- ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x1387);
+ ret_val = e1000_write_emi_reg_locked(hw,
+ I82579_LPI_UPDATE_TIMER,
+ 0x1387);
hw->phy.ops.release(hw);
}
@@ -2219,7 +2158,7 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
**/
static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
{
- s32 ret_val = 0;
+ s32 ret_val;
u16 oem_reg;
ret_val = e1e_rphy(hw, HV_OEM_BITS, &oem_reg);
@@ -2277,6 +2216,8 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
/* When LPLU is enabled, we should disable SmartSpeed */
ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+ if (ret_val)
+ return ret_val;
data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
if (ret_val)
@@ -2949,19 +2890,32 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
{
s32 ret_val;
u16 data;
+ u16 word;
+ u16 valid_csum_mask;
- /* Read 0x19 and check bit 6. If this bit is 0, the checksum
- * needs to be fixed. This bit is an indication that the NVM
- * was prepared by OEM software and did not calculate the
- * checksum...a likely scenario.
+ /* Read NVM and check Invalid Image CSUM bit. If this bit is 0,
+ * the checksum needs to be fixed. This bit is an indication that
+ * the NVM was prepared by OEM software and did not calculate
+ * the checksum...a likely scenario.
*/
- ret_val = e1000_read_nvm(hw, 0x19, 1, &data);
+ switch (hw->mac.type) {
+ case e1000_pch_lpt:
+ word = NVM_COMPAT;
+ valid_csum_mask = NVM_COMPAT_VALID_CSUM;
+ break;
+ default:
+ word = NVM_FUTURE_INIT_WORD1;
+ valid_csum_mask = NVM_FUTURE_INIT_WORD1_VALID_CSUM;
+ break;
+ }
+
+ ret_val = e1000_read_nvm(hw, word, 1, &data);
if (ret_val)
return ret_val;
- if (!(data & 0x40)) {
- data |= 0x40;
- ret_val = e1000_write_nvm(hw, 0x19, 1, &data);
+ if (!(data & valid_csum_mask)) {
+ data |= valid_csum_mask;
+ ret_val = e1000_write_nvm(hw, word, 1, &data);
if (ret_val)
return ret_val;
ret_val = e1000e_update_nvm_checksum(hw);
@@ -3624,6 +3578,17 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
if (hw->mac.type == e1000_ich8lan)
reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS);
ew32(RFCTL, reg);
+
+ /* Enable ECC on Lynxpoint */
+ if (hw->mac.type == e1000_pch_lpt) {
+ reg = er32(PBECCSTS);
+ reg |= E1000_PBECCSTS_ECC_ENABLE;
+ ew32(PBECCSTS, reg);
+
+ reg = er32(CTRL);
+ reg |= E1000_CTRL_MEHE;
+ ew32(CTRL, reg);
+ }
}
/**
@@ -3964,8 +3929,7 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
if (ret_val)
return;
reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
- ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
- reg_data);
+ e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, reg_data);
}
/**
@@ -4000,19 +3964,20 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
if (!dev_spec->eee_disable) {
u16 eee_advert;
- ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
- I217_EEE_ADVERTISEMENT);
+ ret_val =
+ e1000_read_emi_reg_locked(hw,
+ I217_EEE_ADVERTISEMENT,
+ &eee_advert);
if (ret_val)
goto release;
- e1e_rphy_locked(hw, I82579_EMI_DATA, &eee_advert);
/* Disable LPLU if both link partners support 100BaseT
* EEE and 100Full is advertised on both ends of the
* link.
*/
- if ((eee_advert & I217_EEE_100_SUPPORTED) &&
+ if ((eee_advert & I82579_EEE_100_SUPPORTED) &&
(dev_spec->eee_lp_ability &
- I217_EEE_100_SUPPORTED) &&
+ I82579_EEE_100_SUPPORTED) &&
(hw->phy.autoneg_advertised & ADVERTISE_100_FULL))
phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
E1000_PHY_CTRL_NOND0A_LPLU);
@@ -4026,7 +3991,6 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
* The SMBus release must also be disabled on LCD reset.
*/
if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
-
/* Enable proxy to reset only on power good. */
e1e_rphy_locked(hw, I217_PROXY_CTRL, &phy_reg);
phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE;
@@ -4287,7 +4251,7 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
u32 bank = 0;
u32 status;
- e1000e_get_cfg_done(hw);
+ e1000e_get_cfg_done_generic(hw);
/* Wait for indication from h/w that it has completed basic config */
if (hw->mac.type >= e1000_ich10lan) {
@@ -4416,7 +4380,7 @@ static const struct e1000_mac_operations ich8_mac_ops = {
.reset_hw = e1000_reset_hw_ich8lan,
.init_hw = e1000_init_hw_ich8lan,
.setup_link = e1000_setup_link_ich8lan,
- .setup_physical_interface= e1000_setup_copper_link_ich8lan,
+ .setup_physical_interface = e1000_setup_copper_link_ich8lan,
/* id_led_init dependent on mac type */
.config_collision_dist = e1000e_config_collision_dist_generic,
.rar_set = e1000e_rar_set_generic,
@@ -4438,7 +4402,7 @@ static const struct e1000_phy_operations ich8_phy_ops = {
static const struct e1000_nvm_operations ich8_nvm_ops = {
.acquire = e1000_acquire_nvm_ich8lan,
- .read = e1000_read_nvm_ich8lan,
+ .read = e1000_read_nvm_ich8lan,
.release = e1000_release_nvm_ich8lan,
.reload = e1000e_reload_nvm_generic,
.update = e1000_update_nvm_checksum_ich8lan,
@@ -4520,6 +4484,7 @@ const struct e1000_info e1000_pch2_info = {
.mac = e1000_pch2lan,
.flags = FLAG_IS_ICH
| FLAG_HAS_WOL
+ | FLAG_HAS_HW_TIMESTAMP
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT
| FLAG_HAS_FLASH
@@ -4528,7 +4493,7 @@ const struct e1000_info e1000_pch2_info = {
.flags2 = FLAG2_HAS_PHY_STATS
| FLAG2_HAS_EEE,
.pba = 26,
- .max_hw_frame_size = DEFAULT_JUMBO,
+ .max_hw_frame_size = 9018,
.get_variants = e1000_get_variants_ich8lan,
.mac_ops = &ich8_mac_ops,
.phy_ops = &ich8_phy_ops,
@@ -4539,6 +4504,7 @@ const struct e1000_info e1000_pch_lpt_info = {
.mac = e1000_pch_lpt,
.flags = FLAG_IS_ICH
| FLAG_HAS_WOL
+ | FLAG_HAS_HW_TIMESTAMP
| FLAG_HAS_CTRLEXT_ON_LOAD
| FLAG_HAS_AMT
| FLAG_HAS_FLASH
@@ -4547,7 +4513,7 @@ const struct e1000_info e1000_pch_lpt_info = {
.flags2 = FLAG2_HAS_PHY_STATS
| FLAG2_HAS_EEE,
.pba = 26,
- .max_hw_frame_size = DEFAULT_JUMBO,
+ .max_hw_frame_size = 9018,
.get_variants = e1000_get_variants_ich8lan,
.mac_ops = &ich8_mac_ops,
.phy_ops = &ich8_phy_ops,
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h
new file mode 100644
index 000000000000..b6d3174d7d2d
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h
@@ -0,0 +1,268 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2013 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_ICH8LAN_H_
+#define _E1000E_ICH8LAN_H_
+
+#define ICH_FLASH_GFPREG 0x0000
+#define ICH_FLASH_HSFSTS 0x0004
+#define ICH_FLASH_HSFCTL 0x0006
+#define ICH_FLASH_FADDR 0x0008
+#define ICH_FLASH_FDATA0 0x0010
+#define ICH_FLASH_PR0 0x0074
+
+/* Requires up to 10 seconds when MNG might be accessing part. */
+#define ICH_FLASH_READ_COMMAND_TIMEOUT 10000000
+#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 10000000
+#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 10000000
+#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+#define ICH_FLASH_CYCLE_REPEAT_COUNT 10
+
+#define ICH_CYCLE_READ 0
+#define ICH_CYCLE_WRITE 2
+#define ICH_CYCLE_ERASE 3
+
+#define FLASH_GFPREG_BASE_MASK 0x1FFF
+#define FLASH_SECTOR_ADDR_SHIFT 12
+
+#define ICH_FLASH_SEG_SIZE_256 256
+#define ICH_FLASH_SEG_SIZE_4K 4096
+#define ICH_FLASH_SEG_SIZE_8K 8192
+#define ICH_FLASH_SEG_SIZE_64K 65536
+
+#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */
+/* FW established a valid mode */
+#define E1000_ICH_FWSM_FW_VALID 0x00008000
+#define E1000_ICH_FWSM_PCIM2PCI 0x01000000 /* ME PCIm-to-PCI active */
+#define E1000_ICH_FWSM_PCIM2PCI_COUNT 2000
+
+#define E1000_ICH_MNG_IAMT_MODE 0x2
+
+#define E1000_FWSM_WLOCK_MAC_MASK 0x0380
+#define E1000_FWSM_WLOCK_MAC_SHIFT 7
+
+/* Shared Receive Address Registers */
+#define E1000_SHRAL_PCH_LPT(_i) (0x05408 + ((_i) * 8))
+#define E1000_SHRAH_PCH_LPT(_i) (0x0540C + ((_i) * 8))
+
+#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_OFF1_OFF2 << 8) | \
+ (ID_LED_OFF1_ON2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#define E1000_ICH_NVM_SIG_WORD 0x13
+#define E1000_ICH_NVM_SIG_MASK 0xC000
+#define E1000_ICH_NVM_VALID_SIG_MASK 0xC0
+#define E1000_ICH_NVM_SIG_VALUE 0x80
+
+#define E1000_ICH8_LAN_INIT_TIMEOUT 1500
+
+#define E1000_FEXTNVM_SW_CONFIG 1
+#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* different on ICH8M */
+
+#define E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK 0x0C000000
+#define E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC 0x08000000
+
+#define E1000_FEXTNVM4_BEACON_DURATION_MASK 0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_8USEC 0x7
+#define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3
+
+#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL
+
+#define E1000_ICH_RAR_ENTRIES 7
+#define E1000_PCH2_RAR_ENTRIES 5 /* RAR[0], SHRA[0-3] */
+#define E1000_PCH_LPT_RAR_ENTRIES 12 /* RAR[0], SHRA[0-10] */
+
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
+ ((reg) & MAX_PHY_REG_ADDRESS))
+#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */
+#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */
+
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002
+#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
+#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200
+
+/* PHY Wakeup Registers and defines */
+#define BM_PORT_GEN_CFG PHY_REG(BM_PORT_CTRL_PAGE, 17)
+#define BM_RCTL PHY_REG(BM_WUC_PAGE, 0)
+#define BM_WUC PHY_REG(BM_WUC_PAGE, 1)
+#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2)
+#define BM_WUS PHY_REG(BM_WUC_PAGE, 3)
+#define BM_RAR_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
+#define BM_RAR_M(_i) (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
+#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
+#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
+#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
+
+#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */
+#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */
+#define BM_RCTL_MO_SHIFT 3 /* Multicast Offset Shift */
+#define BM_RCTL_MO_MASK (3 << 3) /* Multicast Offset Mask */
+#define BM_RCTL_BAM 0x0020 /* Broadcast Accept Mode */
+#define BM_RCTL_PMCF 0x0040 /* Pass MAC Control Frames */
+#define BM_RCTL_RFCE 0x0080 /* Rx Flow Control Enable */
+
+#define HV_LED_CONFIG PHY_REG(768, 30) /* LED Configuration */
+#define HV_MUX_DATA_CTRL PHY_REG(776, 16)
+#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400
+#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004
+#define HV_STATS_PAGE 778
+/* Half-duplex collision counts */
+#define HV_SCC_UPPER PHY_REG(HV_STATS_PAGE, 16) /* Single Collision */
+#define HV_SCC_LOWER PHY_REG(HV_STATS_PAGE, 17)
+#define HV_ECOL_UPPER PHY_REG(HV_STATS_PAGE, 18) /* Excessive Coll. */
+#define HV_ECOL_LOWER PHY_REG(HV_STATS_PAGE, 19)
+#define HV_MCC_UPPER PHY_REG(HV_STATS_PAGE, 20) /* Multiple Collision */
+#define HV_MCC_LOWER PHY_REG(HV_STATS_PAGE, 21)
+#define HV_LATECOL_UPPER PHY_REG(HV_STATS_PAGE, 23) /* Late Collision */
+#define HV_LATECOL_LOWER PHY_REG(HV_STATS_PAGE, 24)
+#define HV_COLC_UPPER PHY_REG(HV_STATS_PAGE, 25) /* Collision */
+#define HV_COLC_LOWER PHY_REG(HV_STATS_PAGE, 26)
+#define HV_DC_UPPER PHY_REG(HV_STATS_PAGE, 27) /* Defer Count */
+#define HV_DC_LOWER PHY_REG(HV_STATS_PAGE, 28)
+#define HV_TNCRS_UPPER PHY_REG(HV_STATS_PAGE, 29) /* Tx with no CRS */
+#define HV_TNCRS_LOWER PHY_REG(HV_STATS_PAGE, 30)
+
+#define E1000_FCRTV_PCH 0x05F40 /* PCH Flow Control Refresh Timer Value */
+
+#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */
+#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */
+
+/* SMBus Control Phy Register */
+#define CV_SMB_CTRL PHY_REG(769, 23)
+#define CV_SMB_CTRL_FORCE_SMBUS 0x0001
+
+/* SMBus Address Phy Register */
+#define HV_SMB_ADDR PHY_REG(768, 26)
+#define HV_SMB_ADDR_MASK 0x007F
+#define HV_SMB_ADDR_PEC_EN 0x0200
+#define HV_SMB_ADDR_VALID 0x0080
+#define HV_SMB_ADDR_FREQ_MASK 0x1100
+#define HV_SMB_ADDR_FREQ_LOW_SHIFT 8
+#define HV_SMB_ADDR_FREQ_HIGH_SHIFT 12
+
+/* Strapping Option Register - RO */
+#define E1000_STRAP 0x0000C
+#define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000
+#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17
+#define E1000_STRAP_SMT_FREQ_MASK 0x00003000
+#define E1000_STRAP_SMT_FREQ_SHIFT 12
+
+/* OEM Bits Phy Register */
+#define HV_OEM_BITS PHY_REG(768, 25)
+#define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */
+#define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */
+#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
+
+/* KMRN Mode Control */
+#define HV_KMRN_MODE_CTRL PHY_REG(769, 16)
+#define HV_KMRN_MDIO_SLOW 0x0400
+
+/* KMRN FIFO Control and Status */
+#define HV_KMRN_FIFO_CTRLSTA PHY_REG(770, 16)
+#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK 0x7000
+#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT 12
+
+/* PHY Power Management Control */
+#define HV_PM_CTRL PHY_REG(770, 17)
+#define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100
+
+#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in ms */
+
+/* PHY Low Power Idle Control */
+#define I82579_LPI_CTRL PHY_REG(772, 20)
+#define I82579_LPI_CTRL_100_ENABLE 0x2000
+#define I82579_LPI_CTRL_1000_ENABLE 0x4000
+#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT 0x80
+
+/* Extended Management Interface (EMI) Registers */
+#define I82579_EMI_ADDR 0x10
+#define I82579_EMI_DATA 0x11
+#define I82579_LPI_UPDATE_TIMER 0x4805 /* in 40ns units + 40 ns base value */
+#define I82579_MSE_THRESHOLD 0x084F /* 82579 Mean Square Error Threshold */
+#define I82577_MSE_THRESHOLD 0x0887 /* 82577 Mean Square Error Threshold */
+#define I82579_MSE_LINK_DOWN 0x2411 /* MSE count before dropping link */
+#define I82579_EEE_PCS_STATUS 0x182D /* IEEE MMD Register 3.1 >> 8 */
+#define I82579_EEE_CAPABILITY 0x0410 /* IEEE MMD Register 3.20 */
+#define I82579_EEE_ADVERTISEMENT 0x040E /* IEEE MMD Register 7.60 */
+#define I82579_EEE_LP_ABILITY 0x040F /* IEEE MMD Register 7.61 */
+#define I82579_EEE_100_SUPPORTED (1 << 1) /* 100BaseTx EEE */
+#define I82579_EEE_1000_SUPPORTED (1 << 2) /* 1000BaseTx EEE */
+#define I217_EEE_PCS_STATUS 0x9401 /* IEEE MMD Register 3.1 */
+#define I217_EEE_CAPABILITY 0x8000 /* IEEE MMD Register 3.20 */
+#define I217_EEE_ADVERTISEMENT 0x8001 /* IEEE MMD Register 7.60 */
+#define I217_EEE_LP_ABILITY 0x8002 /* IEEE MMD Register 7.61 */
+
+#define E1000_EEE_RX_LPI_RCVD 0x0400 /* Tx LP idle received */
+#define E1000_EEE_TX_LPI_RCVD 0x0800 /* Rx LP idle received */
+
+/* Intel Rapid Start Technology Support */
+#define I217_PROXY_CTRL BM_PHY_REG(BM_WUC_PAGE, 70)
+#define I217_PROXY_CTRL_AUTO_DISABLE 0x0080
+#define I217_SxCTRL PHY_REG(BM_PORT_CTRL_PAGE, 28)
+#define I217_SxCTRL_ENABLE_LPI_RESET 0x1000
+#define I217_CGFREG PHY_REG(772, 29)
+#define I217_CGFREG_ENABLE_MTA_RESET 0x0002
+#define I217_MEMPWR PHY_REG(772, 26)
+#define I217_MEMPWR_DISABLE_SMB_RELEASE 0x0010
+
+/* Receive Address Initial CRC Calculation */
+#define E1000_PCH_RAICC(_n) (0x05F50 + ((_n) * 4))
+
+/* Latency Tolerance Reporting */
+#define E1000_LTRV 0x000F8
+#define E1000_LTRV_SCALE_MAX 5
+#define E1000_LTRV_SCALE_FACTOR 5
+#define E1000_LTRV_REQ_SHIFT 15
+#define E1000_LTRV_NOSNOOP_SHIFT 16
+#define E1000_LTRV_SEND (1 << 30)
+
+/* Proprietary Latency Tolerance Reporting PCI Capability */
+#define E1000_PCI_LTR_CAP_LPT 0xA8
+
+/* OBFF Control & Threshold Defines */
+#define E1000_SVCR_OFF_EN 0x00000001
+#define E1000_SVCR_OFF_MASKINT 0x00001000
+#define E1000_SVCR_OFF_TIMER_MASK 0xFFFF0000
+#define E1000_SVCR_OFF_TIMER_SHIFT 16
+#define E1000_SVT_OFF_HWM_MASK 0x0000001F
+
+void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw);
+void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+ bool state);
+void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw);
+void e1000_resume_workarounds_pchlan(struct e1000_hw *hw);
+s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
+s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
+s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data);
+#endif /* _E1000E_ICH8LAN_H_ */
diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c
index 54d9dafaf126..b78e02174601 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.c
+++ b/drivers/net/ethernet/intel/e1000e/mac.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -165,7 +165,7 @@ void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
{
u32 i;
- s32 ret_val = 0;
+ s32 ret_val;
u16 offset, nvm_alt_mac_addr_offset, nvm_data;
u8 alt_mac_addr[ETH_ALEN];
@@ -1021,6 +1021,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
s32 ret_val = 0;
+ u32 pcs_status_reg, pcs_adv_reg, pcs_lp_ability_reg, pcs_ctrl_reg;
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
u16 speed, duplex;
@@ -1052,14 +1053,14 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
* has completed. We read this twice because this reg has
* some "sticky" (latched) bits.
*/
- ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+ ret_val = e1e_rphy(hw, MII_BMSR, &mii_status_reg);
if (ret_val)
return ret_val;
- ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+ ret_val = e1e_rphy(hw, MII_BMSR, &mii_status_reg);
if (ret_val)
return ret_val;
- if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+ if (!(mii_status_reg & BMSR_ANEGCOMPLETE)) {
e_dbg("Copper PHY and Auto Neg has not completed.\n");
return ret_val;
}
@@ -1070,11 +1071,10 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
* Page Ability Register (Address 5) to determine how
* flow control was negotiated.
*/
- ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg);
+ ret_val = e1e_rphy(hw, MII_ADVERTISE, &mii_nway_adv_reg);
if (ret_val)
return ret_val;
- ret_val =
- e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg);
+ ret_val = e1e_rphy(hw, MII_LPA, &mii_nway_lp_ability_reg);
if (ret_val)
return ret_val;
@@ -1111,8 +1111,8 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
* 1 | DC | 1 | DC | E1000_fc_full
*
*/
- if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ if ((mii_nway_adv_reg & ADVERTISE_PAUSE_CAP) &&
+ (mii_nway_lp_ability_reg & LPA_PAUSE_CAP)) {
/* Now we need to check if the user selected Rx ONLY
* of pause frames. In this case, we had to advertise
* FULL flow control because we could not advertise Rx
@@ -1134,10 +1134,10 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
*-------|---------|-------|---------|--------------------
* 0 | 1 | 1 | 1 | e1000_fc_tx_pause
*/
- else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ else if (!(mii_nway_adv_reg & ADVERTISE_PAUSE_CAP) &&
+ (mii_nway_adv_reg & ADVERTISE_PAUSE_ASYM) &&
+ (mii_nway_lp_ability_reg & LPA_PAUSE_CAP) &&
+ (mii_nway_lp_ability_reg & LPA_PAUSE_ASYM)) {
hw->fc.current_mode = e1000_fc_tx_pause;
e_dbg("Flow Control = Tx PAUSE frames only.\n");
}
@@ -1148,10 +1148,10 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
*-------|---------|-------|---------|--------------------
* 1 | 1 | 0 | 1 | e1000_fc_rx_pause
*/
- else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
- !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ else if ((mii_nway_adv_reg & ADVERTISE_PAUSE_CAP) &&
+ (mii_nway_adv_reg & ADVERTISE_PAUSE_ASYM) &&
+ !(mii_nway_lp_ability_reg & LPA_PAUSE_CAP) &&
+ (mii_nway_lp_ability_reg & LPA_PAUSE_ASYM)) {
hw->fc.current_mode = e1000_fc_rx_pause;
e_dbg("Flow Control = Rx PAUSE frames only.\n");
} else {
@@ -1185,6 +1185,130 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
}
}
+ /* Check for the case where we have SerDes media and auto-neg is
+ * enabled. In this case, we need to check and see if Auto-Neg
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+ if ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
+ mac->autoneg) {
+ /* Read the PCS_LSTS and check to see if AutoNeg
+ * has completed.
+ */
+ pcs_status_reg = er32(PCS_LSTAT);
+
+ if (!(pcs_status_reg & E1000_PCS_LSTS_AN_COMPLETE)) {
+ e_dbg("PCS Auto Neg has not completed.\n");
+ return ret_val;
+ }
+
+ /* The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement
+ * Register (PCS_ANADV) and the Auto_Negotiation Base
+ * Page Ability Register (PCS_LPAB) to determine how
+ * flow control was negotiated.
+ */
+ pcs_adv_reg = er32(PCS_ANADV);
+ pcs_lp_ability_reg = er32(PCS_LPAB);
+
+ /* Two bits in the Auto Negotiation Advertisement Register
+ * (PCS_ANADV) and two bits in the Auto Negotiation Base
+ * Page Ability Register (PCS_LPAB) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | e1000_fc_none
+ * 0 | 1 | 0 | DC | e1000_fc_none
+ * 0 | 1 | 1 | 0 | e1000_fc_none
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ * 1 | 0 | 0 | DC | e1000_fc_none
+ * 1 | DC | 1 | DC | e1000_fc_full
+ * 1 | 1 | 0 | 0 | e1000_fc_none
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ * Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | e1000_fc_full
+ *
+ */
+ if ((pcs_adv_reg & E1000_TXCW_PAUSE) &&
+ (pcs_lp_ability_reg & E1000_TXCW_PAUSE)) {
+ /* Now we need to check if the user selected Rx ONLY
+ * 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.
+ */
+ if (hw->fc.requested_mode == e1000_fc_full) {
+ hw->fc.current_mode = e1000_fc_full;
+ e_dbg("Flow Control = FULL.\n");
+ } else {
+ hw->fc.current_mode = e1000_fc_rx_pause;
+ e_dbg("Flow Control = Rx PAUSE frames only.\n");
+ }
+ }
+ /* For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ */
+ else if (!(pcs_adv_reg & E1000_TXCW_PAUSE) &&
+ (pcs_adv_reg & E1000_TXCW_ASM_DIR) &&
+ (pcs_lp_ability_reg & E1000_TXCW_PAUSE) &&
+ (pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) {
+ hw->fc.current_mode = e1000_fc_tx_pause;
+ e_dbg("Flow Control = Tx PAUSE frames only.\n");
+ }
+ /* For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ */
+ else if ((pcs_adv_reg & E1000_TXCW_PAUSE) &&
+ (pcs_adv_reg & E1000_TXCW_ASM_DIR) &&
+ !(pcs_lp_ability_reg & E1000_TXCW_PAUSE) &&
+ (pcs_lp_ability_reg & E1000_TXCW_ASM_DIR)) {
+ hw->fc.current_mode = e1000_fc_rx_pause;
+ e_dbg("Flow Control = Rx PAUSE frames only.\n");
+ } else {
+ /* Per the IEEE spec, at this point flow control
+ * should be disabled.
+ */
+ hw->fc.current_mode = e1000_fc_none;
+ e_dbg("Flow Control = NONE.\n");
+ }
+
+ /* Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ pcs_ctrl_reg = er32(PCS_LCTL);
+ pcs_ctrl_reg |= E1000_PCS_LCTL_FORCE_FCTRL;
+ ew32(PCS_LCTL, pcs_ctrl_reg);
+
+ ret_val = e1000e_force_mac_fc(hw);
+ if (ret_val) {
+ e_dbg("Error forcing flow control settings\n");
+ return ret_val;
+ }
+ }
+
return 0;
}
@@ -1231,8 +1355,8 @@ s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
* Sets the speed and duplex to gigabit full duplex (the only possible option)
* for fiber/serdes links.
**/
-s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed,
- u16 *duplex)
+s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw __always_unused
+ *hw, u16 *speed, u16 *duplex)
{
*speed = SPEED_1000;
*duplex = FULL_DUPLEX;
diff --git a/drivers/net/ethernet/intel/e1000e/mac.h b/drivers/net/ethernet/intel/e1000e/mac.h
new file mode 100644
index 000000000000..a61fee404ebe
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/mac.h
@@ -0,0 +1,74 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2013 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_MAC_H_
+#define _E1000E_MAC_H_
+
+s32 e1000e_blink_led_generic(struct e1000_hw *hw);
+s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
+s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
+s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
+s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
+s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
+s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
+s32 e1000e_force_mac_fc(struct e1000_hw *hw);
+s32 e1000e_get_auto_rd_done(struct e1000_hw *hw);
+s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
+void e1000_set_lan_id_single_port(struct e1000_hw *hw);
+s32 e1000e_get_hw_semaphore(struct e1000_hw *hw);
+s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
+ u16 *duplex);
+s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw,
+ u16 *speed, u16 *duplex);
+s32 e1000e_id_led_init_generic(struct e1000_hw *hw);
+s32 e1000e_led_on_generic(struct e1000_hw *hw);
+s32 e1000e_led_off_generic(struct e1000_hw *hw);
+void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count);
+s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
+s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
+s32 e1000e_setup_led_generic(struct e1000_hw *hw);
+s32 e1000e_setup_link_generic(struct e1000_hw *hw);
+s32 e1000e_validate_mdi_setting_generic(struct e1000_hw *hw);
+s32 e1000e_validate_mdi_setting_crossover_generic(struct e1000_hw *hw);
+
+void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
+void e1000_clear_vfta_generic(struct e1000_hw *hw);
+void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
+void e1000e_put_hw_semaphore(struct e1000_hw *hw);
+s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
+void e1000e_reset_adaptive(struct e1000_hw *hw);
+void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
+void e1000e_update_adaptive(struct e1000_hw *hw);
+void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
+
+void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
+void e1000e_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
+void e1000e_config_collision_dist_generic(struct e1000_hw *hw);
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/manage.c b/drivers/net/ethernet/intel/e1000e/manage.c
index 6dc47beb3adc..e4b0f1ef92f6 100644
--- a/drivers/net/ethernet/intel/e1000e/manage.c
+++ b/drivers/net/ethernet/intel/e1000e/manage.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -28,19 +28,6 @@
#include "e1000.h"
-enum e1000_mng_mode {
- e1000_mng_mode_none = 0,
- e1000_mng_mode_asf,
- e1000_mng_mode_pt,
- e1000_mng_mode_ipmi,
- e1000_mng_mode_host_if_only
-};
-
-#define E1000_FACTPS_MNGCG 0x20000000
-
-/* Intel(R) Active Management Technology signature */
-#define E1000_IAMT_SIGNATURE 0x544D4149
-
/**
* e1000_calculate_checksum - Calculate checksum for buffer
* @buffer: pointer to EEPROM
diff --git a/drivers/net/ethernet/intel/e1000e/manage.h b/drivers/net/ethernet/intel/e1000e/manage.h
new file mode 100644
index 000000000000..326897c29ea8
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/manage.h
@@ -0,0 +1,72 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2013 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_MANAGE_H_
+#define _E1000E_MANAGE_H_
+
+bool e1000e_check_mng_mode_generic(struct e1000_hw *hw);
+bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
+s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
+bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
+
+enum e1000_mng_mode {
+ e1000_mng_mode_none = 0,
+ e1000_mng_mode_asf,
+ e1000_mng_mode_pt,
+ e1000_mng_mode_ipmi,
+ e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG 0x20000000
+
+#define E1000_FWSM_MODE_MASK 0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
+
+#define E1000_VFTA_ENTRY_SHIFT 5
+#define E1000_VFTA_ENTRY_MASK 0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
+
+#define E1000_HICR_EN 0x01 /* Enable bit - RO */
+/* Driver sets this bit when done to put command in RAM */
+#define E1000_HICR_C 0x02
+#define E1000_HICR_SV 0x04 /* Status Validity */
+#define E1000_HICR_FW_RESET_ENABLE 0x40
+#define E1000_HICR_FW_RESET 0x80
+
+/* Intel(R) Active Management Technology signature */
+#define E1000_IAMT_SIGNATURE 0x544D4149
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index fbf75fdca994..a177b8b65c44 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -42,7 +42,6 @@
#include <linux/slab.h>
#include <net/checksum.h>
#include <net/ip6_checksum.h>
-#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/cpu.h>
@@ -56,7 +55,7 @@
#define DRV_EXTRAVERSION "-k"
-#define DRV_VERSION "2.1.4" DRV_EXTRAVERSION
+#define DRV_VERSION "2.2.14" DRV_EXTRAVERSION
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
@@ -87,20 +86,7 @@ struct e1000_reg_info {
char *name;
};
-#define E1000_RDFH 0x02410 /* Rx Data FIFO Head - RW */
-#define E1000_RDFT 0x02418 /* Rx Data FIFO Tail - RW */
-#define E1000_RDFHS 0x02420 /* Rx Data FIFO Head Saved - RW */
-#define E1000_RDFTS 0x02428 /* Rx Data FIFO Tail Saved - RW */
-#define E1000_RDFPC 0x02430 /* Rx Data FIFO Packet Count - RW */
-
-#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */
-#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */
-#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */
-#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */
-#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */
-
static const struct e1000_reg_info e1000_reg_info_tbl[] = {
-
/* General Registers */
{E1000_CTRL, "CTRL"},
{E1000_STATUS, "STATUS"},
@@ -488,20 +474,87 @@ static int e1000_desc_unused(struct e1000_ring *ring)
}
/**
+ * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+ * @adapter: board private structure
+ * @hwtstamps: time stamp structure to update
+ * @systim: unsigned 64bit system time value.
+ *
+ * Convert the system time value stored in the RX/TXSTMP registers into a
+ * hwtstamp which can be used by the upper level time stamping functions.
+ *
+ * The 'systim_lock' spinlock is used to protect the consistency of the
+ * system time value. This is needed because reading the 64 bit time
+ * value involves reading two 32 bit registers. The first read latches the
+ * value.
+ **/
+static void e1000e_systim_to_hwtstamp(struct e1000_adapter *adapter,
+ struct skb_shared_hwtstamps *hwtstamps,
+ u64 systim)
+{
+ u64 ns;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->systim_lock, flags);
+ ns = timecounter_cyc2time(&adapter->tc, systim);
+ spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+ memset(hwtstamps, 0, sizeof(*hwtstamps));
+ hwtstamps->hwtstamp = ns_to_ktime(ns);
+}
+
+/**
+ * e1000e_rx_hwtstamp - utility function which checks for Rx time stamp
+ * @adapter: board private structure
+ * @status: descriptor extended error and status field
+ * @skb: particular skb to include time stamp
+ *
+ * If the time stamp is valid, convert it into the timecounter ns value
+ * and store that result into the shhwtstamps structure which is passed
+ * up the network stack.
+ **/
+static void e1000e_rx_hwtstamp(struct e1000_adapter *adapter, u32 status,
+ struct sk_buff *skb)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u64 rxstmp;
+
+ if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP) ||
+ !(status & E1000_RXDEXT_STATERR_TST) ||
+ !(er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID))
+ return;
+
+ /* The Rx time stamp registers contain the time stamp. No other
+ * received packet will be time stamped until the Rx time stamp
+ * registers are read. Because only one packet can be time stamped
+ * at a time, the register values must belong to this packet and
+ * therefore none of the other additional attributes need to be
+ * compared.
+ */
+ rxstmp = (u64)er32(RXSTMPL);
+ rxstmp |= (u64)er32(RXSTMPH) << 32;
+ e1000e_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), rxstmp);
+
+ adapter->flags2 &= ~FLAG2_CHECK_RX_HWTSTAMP;
+}
+
+/**
* e1000_receive_skb - helper function to handle Rx indications
* @adapter: board private structure
- * @status: descriptor status field as written by hardware
+ * @staterr: descriptor extended error and status field as written by hardware
* @vlan: descriptor vlan field as written by hardware (no le/be conversion)
* @skb: pointer to sk_buff to be indicated to stack
**/
static void e1000_receive_skb(struct e1000_adapter *adapter,
struct net_device *netdev, struct sk_buff *skb,
- u8 status, __le16 vlan)
+ u32 staterr, __le16 vlan)
{
u16 tag = le16_to_cpu(vlan);
+
+ e1000e_rx_hwtstamp(adapter, staterr, skb);
+
skb->protocol = eth_type_trans(skb, netdev);
- if (status & E1000_RXD_STAT_VP)
+ if (staterr & E1000_RXD_STAT_VP)
__vlan_hwaccel_put_tag(skb, tag);
napi_gro_receive(&adapter->napi, skb);
@@ -765,7 +818,7 @@ static void e1000_alloc_jumbo_rx_buffers(struct e1000_ring *rx_ring,
struct e1000_buffer *buffer_info;
struct sk_buff *skb;
unsigned int i;
- unsigned int bufsz = 256 - 16 /* for skb_reserve */;
+ unsigned int bufsz = 256 - 16; /* for skb_reserve */
i = rx_ring->next_to_use;
buffer_info = &rx_ring->buffer_info[i];
@@ -1050,9 +1103,9 @@ static void e1000_print_hw_hang(struct work_struct *work)
adapter->tx_hang_recheck = false;
netif_stop_queue(netdev);
- e1e_rphy(hw, PHY_STATUS, &phy_status);
- e1e_rphy(hw, PHY_1000T_STATUS, &phy_1000t_status);
- e1e_rphy(hw, PHY_EXT_STATUS, &phy_ext_status);
+ e1e_rphy(hw, MII_BMSR, &phy_status);
+ e1e_rphy(hw, MII_STAT1000, &phy_1000t_status);
+ e1e_rphy(hw, MII_ESTATUS, &phy_ext_status);
pci_read_config_word(adapter->pdev, PCI_STATUS, &pci_status);
@@ -1092,6 +1145,41 @@ static void e1000_print_hw_hang(struct work_struct *work)
}
/**
+ * e1000e_tx_hwtstamp_work - check for Tx time stamp
+ * @work: pointer to work struct
+ *
+ * This work function polls the TSYNCTXCTL valid bit to determine when a
+ * timestamp has been taken for the current stored skb. The timestamp must
+ * be for this skb because only one such packet is allowed in the queue.
+ */
+static void e1000e_tx_hwtstamp_work(struct work_struct *work)
+{
+ struct e1000_adapter *adapter = container_of(work, struct e1000_adapter,
+ tx_hwtstamp_work);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (!adapter->tx_hwtstamp_skb)
+ return;
+
+ if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) {
+ struct skb_shared_hwtstamps shhwtstamps;
+ u64 txstmp;
+
+ txstmp = er32(TXSTMPL);
+ txstmp |= (u64)er32(TXSTMPH) << 32;
+
+ e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp);
+
+ skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps);
+ dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+ adapter->tx_hwtstamp_skb = NULL;
+ } else {
+ /* reschedule to check later */
+ schedule_work(&adapter->tx_hwtstamp_work);
+ }
+}
+
+/**
* e1000_clean_tx_irq - Reclaim resources after transmit completes
* @tx_ring: Tx descriptor ring
*
@@ -1345,8 +1433,8 @@ copydone:
cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))
adapter->rx_hdr_split++;
- e1000_receive_skb(adapter, netdev, skb,
- staterr, rx_desc->wb.middle.vlan);
+ e1000_receive_skb(adapter, netdev, skb, staterr,
+ rx_desc->wb.middle.vlan);
next_desc:
rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF);
@@ -1645,7 +1733,7 @@ static void e1000e_downshift_workaround(struct work_struct *work)
* @irq: interrupt number
* @data: pointer to a network interface device structure
**/
-static irqreturn_t e1000_intr_msi(int irq, void *data)
+static irqreturn_t e1000_intr_msi(int __always_unused irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1671,13 +1759,30 @@ static irqreturn_t e1000_intr_msi(int irq, void *data)
/* disable receives */
u32 rctl = er32(RCTL);
ew32(RCTL, rctl & ~E1000_RCTL_EN);
- adapter->flags |= FLAG_RX_RESTART_NOW;
+ adapter->flags |= FLAG_RESTART_NOW;
}
/* guard against interrupt when we're going down */
if (!test_bit(__E1000_DOWN, &adapter->state))
mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
+ /* Reset on uncorrectable ECC error */
+ if ((icr & E1000_ICR_ECCER) && (hw->mac.type == e1000_pch_lpt)) {
+ u32 pbeccsts = er32(PBECCSTS);
+
+ adapter->corr_errors +=
+ pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
+ adapter->uncorr_errors +=
+ (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
+ E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+
+ /* Do the reset outside of interrupt context */
+ schedule_work(&adapter->reset_task);
+
+ /* return immediately since reset is imminent */
+ return IRQ_HANDLED;
+ }
+
if (napi_schedule_prep(&adapter->napi)) {
adapter->total_tx_bytes = 0;
adapter->total_tx_packets = 0;
@@ -1694,7 +1799,7 @@ static irqreturn_t e1000_intr_msi(int irq, void *data)
* @irq: interrupt number
* @data: pointer to a network interface device structure
**/
-static irqreturn_t e1000_intr(int irq, void *data)
+static irqreturn_t e1000_intr(int __always_unused irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1734,13 +1839,30 @@ static irqreturn_t e1000_intr(int irq, void *data)
/* disable receives */
rctl = er32(RCTL);
ew32(RCTL, rctl & ~E1000_RCTL_EN);
- adapter->flags |= FLAG_RX_RESTART_NOW;
+ adapter->flags |= FLAG_RESTART_NOW;
}
/* guard against interrupt when we're going down */
if (!test_bit(__E1000_DOWN, &adapter->state))
mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
+ /* Reset on uncorrectable ECC error */
+ if ((icr & E1000_ICR_ECCER) && (hw->mac.type == e1000_pch_lpt)) {
+ u32 pbeccsts = er32(PBECCSTS);
+
+ adapter->corr_errors +=
+ pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
+ adapter->uncorr_errors +=
+ (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
+ E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+
+ /* Do the reset outside of interrupt context */
+ schedule_work(&adapter->reset_task);
+
+ /* return immediately since reset is imminent */
+ return IRQ_HANDLED;
+ }
+
if (napi_schedule_prep(&adapter->napi)) {
adapter->total_tx_bytes = 0;
adapter->total_tx_packets = 0;
@@ -1752,7 +1874,7 @@ static irqreturn_t e1000_intr(int irq, void *data)
return IRQ_HANDLED;
}
-static irqreturn_t e1000_msix_other(int irq, void *data)
+static irqreturn_t e1000_msix_other(int __always_unused irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1784,8 +1906,7 @@ no_link_interrupt:
return IRQ_HANDLED;
}
-
-static irqreturn_t e1000_intr_msix_tx(int irq, void *data)
+static irqreturn_t e1000_intr_msix_tx(int __always_unused irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1803,7 +1924,7 @@ static irqreturn_t e1000_intr_msix_tx(int irq, void *data)
return IRQ_HANDLED;
}
-static irqreturn_t e1000_intr_msix_rx(int irq, void *data)
+static irqreturn_t e1000_intr_msix_rx(int __always_unused irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1890,7 +2011,6 @@ static void e1000_configure_msix(struct e1000_adapter *adapter)
ctrl_ext |= E1000_CTRL_EXT_PBA_CLR;
/* Auto-Mask Other interrupts upon ICR read */
-#define E1000_EIAC_MASK_82574 0x01F00000
ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER);
ctrl_ext |= E1000_CTRL_EXT_EIAME;
ew32(CTRL_EXT, ctrl_ext);
@@ -2104,6 +2224,8 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
if (adapter->msix_entries) {
ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
+ } else if (hw->mac.type == e1000_pch_lpt) {
+ ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER);
} else {
ew32(IMS, IMS_ENABLE_MASK);
}
@@ -2358,9 +2480,7 @@ void e1000e_free_rx_resources(struct e1000_ring *rx_ring)
* while increasing bulk throughput. This functionality is controlled
* by the InterruptThrottleRate module parameter.
**/
-static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
- u16 itr_setting, int packets,
- int bytes)
+static unsigned int e1000_update_itr(u16 itr_setting, int packets, int bytes)
{
unsigned int retval = itr_setting;
@@ -2405,7 +2525,6 @@ static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
static void e1000_set_itr(struct e1000_adapter *adapter)
{
- struct e1000_hw *hw = &adapter->hw;
u16 current_itr;
u32 new_itr = adapter->itr;
@@ -2421,18 +2540,16 @@ static void e1000_set_itr(struct e1000_adapter *adapter)
goto set_itr_now;
}
- adapter->tx_itr = e1000_update_itr(adapter,
- adapter->tx_itr,
- adapter->total_tx_packets,
- adapter->total_tx_bytes);
+ adapter->tx_itr = e1000_update_itr(adapter->tx_itr,
+ adapter->total_tx_packets,
+ adapter->total_tx_bytes);
/* conservative mode (itr 3) eliminates the lowest_latency setting */
if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency)
adapter->tx_itr = low_latency;
- adapter->rx_itr = e1000_update_itr(adapter,
- adapter->rx_itr,
- adapter->total_rx_packets,
- adapter->total_rx_bytes);
+ adapter->rx_itr = e1000_update_itr(adapter->rx_itr,
+ adapter->total_rx_packets,
+ adapter->total_rx_bytes);
/* conservative mode (itr 3) eliminates the lowest_latency setting */
if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
adapter->rx_itr = low_latency;
@@ -2468,10 +2585,7 @@ set_itr_now:
if (adapter->msix_entries)
adapter->rx_ring->set_itr = 1;
else
- if (new_itr)
- ew32(ITR, 1000000000 / (new_itr * 256));
- else
- ew32(ITR, 0);
+ e1000e_write_itr(adapter, new_itr);
}
}
@@ -3013,7 +3127,7 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
ew32(RCTL, rctl);
/* just started the receive unit, no need to restart */
- adapter->flags &= ~FLAG_RX_RESTART_NOW;
+ adapter->flags &= ~FLAG_RESTART_NOW;
}
/**
@@ -3108,18 +3222,23 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
rxcsum &= ~E1000_RXCSUM_TUOFL;
ew32(RXCSUM, rxcsum);
- if (adapter->hw.mac.type == e1000_pch2lan) {
- /* With jumbo frames, excessive C-state transition
- * latencies result in dropped transactions.
- */
- if (adapter->netdev->mtu > ETH_DATA_LEN) {
+ /* With jumbo frames, excessive C-state transition latencies result
+ * in dropped transactions.
+ */
+ if (adapter->netdev->mtu > ETH_DATA_LEN) {
+ u32 lat =
+ ((er32(PBA) & E1000_PBA_RXA_MASK) * 1024 -
+ adapter->max_frame_size) * 8 / 1000;
+
+ if (adapter->flags & FLAG_IS_ICH) {
u32 rxdctl = er32(RXDCTL(0));
ew32(RXDCTL(0), rxdctl | 0x3);
- pm_qos_update_request(&adapter->netdev->pm_qos_req, 55);
- } else {
- pm_qos_update_request(&adapter->netdev->pm_qos_req,
- PM_QOS_DEFAULT_VALUE);
}
+
+ pm_qos_update_request(&adapter->netdev->pm_qos_req, lat);
+ } else {
+ pm_qos_update_request(&adapter->netdev->pm_qos_req,
+ PM_QOS_DEFAULT_VALUE);
}
/* Enable Receives */
@@ -3308,6 +3427,241 @@ static void e1000e_setup_rss_hash(struct e1000_adapter *adapter)
}
/**
+ * e1000e_get_base_timinca - get default SYSTIM time increment attributes
+ * @adapter: board private structure
+ * @timinca: pointer to returned time increment attributes
+ *
+ * Get attributes for incrementing the System Time Register SYSTIML/H at
+ * the default base frequency, and set the cyclecounter shift value.
+ **/
+s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 incvalue, incperiod, shift;
+
+ /* Make sure clock is enabled on I217 before checking the frequency */
+ if ((hw->mac.type == e1000_pch_lpt) &&
+ !(er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_ENABLED) &&
+ !(er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_ENABLED)) {
+ u32 fextnvm7 = er32(FEXTNVM7);
+
+ if (!(fextnvm7 & (1 << 0))) {
+ ew32(FEXTNVM7, fextnvm7 | (1 << 0));
+ e1e_flush();
+ }
+ }
+
+ switch (hw->mac.type) {
+ case e1000_pch2lan:
+ case e1000_pch_lpt:
+ /* On I217, the clock frequency is 25MHz or 96MHz as
+ * indicated by the System Clock Frequency Indication
+ */
+ if ((hw->mac.type != e1000_pch_lpt) ||
+ (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
+ /* Stable 96MHz frequency */
+ incperiod = INCPERIOD_96MHz;
+ incvalue = INCVALUE_96MHz;
+ shift = INCVALUE_SHIFT_96MHz;
+ adapter->cc.shift = shift + INCPERIOD_SHIFT_96MHz;
+ break;
+ }
+ /* fall-through */
+ case e1000_82574:
+ case e1000_82583:
+ /* Stable 25MHz frequency */
+ incperiod = INCPERIOD_25MHz;
+ incvalue = INCVALUE_25MHz;
+ shift = INCVALUE_SHIFT_25MHz;
+ adapter->cc.shift = shift;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *timinca = ((incperiod << E1000_TIMINCA_INCPERIOD_SHIFT) |
+ ((incvalue << shift) & E1000_TIMINCA_INCVALUE_MASK));
+
+ return 0;
+}
+
+/**
+ * e1000e_config_hwtstamp - configure the hwtstamp registers and enable/disable
+ * @adapter: board private structure
+ *
+ * Outgoing time stamping can be enabled and disabled. Play nice and
+ * disable it when requested, although it shouldn't cause any overhead
+ * when no packet needs it. At most one packet in the queue may be
+ * marked for time stamping, otherwise it would be impossible to tell
+ * for sure to which packet the hardware time stamp belongs.
+ *
+ * Incoming time stamping has to be configured via the hardware filters.
+ * Not all combinations are supported, in particular event type has to be
+ * specified. Matching the kind of event packet is not supported, with the
+ * exception of "all V2 events regardless of level 2 or 4".
+ **/
+static int e1000e_config_hwtstamp(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct hwtstamp_config *config = &adapter->hwtstamp_config;
+ u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
+ u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
+ u32 rxmtrl = 0;
+ u16 rxudp = 0;
+ bool is_l4 = false;
+ bool is_l2 = false;
+ u32 regval;
+ s32 ret_val;
+
+ if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+ return -EINVAL;
+
+ /* flags reserved for future extensions - must be zero */
+ if (config->flags)
+ return -EINVAL;
+
+ switch (config->tx_type) {
+ case HWTSTAMP_TX_OFF:
+ tsync_tx_ctl = 0;
+ break;
+ case HWTSTAMP_TX_ON:
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config->rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ tsync_rx_ctl = 0;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
+ rxmtrl = E1000_RXMTRL_PTP_V1_SYNC_MESSAGE;
+ is_l4 = true;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
+ rxmtrl = E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE;
+ is_l4 = true;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ /* Also time stamps V2 L2 Path Delay Request/Response */
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_V2;
+ rxmtrl = E1000_RXMTRL_PTP_V2_SYNC_MESSAGE;
+ is_l2 = true;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ /* Also time stamps V2 L2 Path Delay Request/Response. */
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_V2;
+ rxmtrl = E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE;
+ is_l2 = true;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ /* Hardware cannot filter just V2 L4 Sync messages;
+ * fall-through to V2 (both L2 and L4) Sync.
+ */
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ /* Also time stamps V2 Path Delay Request/Response. */
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
+ rxmtrl = E1000_RXMTRL_PTP_V2_SYNC_MESSAGE;
+ is_l2 = true;
+ is_l4 = true;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ /* Hardware cannot filter just V2 L4 Delay Request messages;
+ * fall-through to V2 (both L2 and L4) Delay Request.
+ */
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ /* Also time stamps V2 Path Delay Request/Response. */
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
+ rxmtrl = E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE;
+ is_l2 = true;
+ is_l4 = true;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ /* Hardware cannot filter just V2 L4 or L2 Event messages;
+ * fall-through to all V2 (both L2 and L4) Events.
+ */
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
+ config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ is_l2 = true;
+ is_l4 = true;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ /* For V1, the hardware can only filter Sync messages or
+ * Delay Request messages but not both so fall-through to
+ * time stamp all packets.
+ */
+ case HWTSTAMP_FILTER_ALL:
+ is_l2 = true;
+ is_l4 = true;
+ tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
+ config->rx_filter = HWTSTAMP_FILTER_ALL;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ /* enable/disable Tx h/w time stamping */
+ regval = er32(TSYNCTXCTL);
+ regval &= ~E1000_TSYNCTXCTL_ENABLED;
+ regval |= tsync_tx_ctl;
+ ew32(TSYNCTXCTL, regval);
+ if ((er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_ENABLED) !=
+ (regval & E1000_TSYNCTXCTL_ENABLED)) {
+ e_err("Timesync Tx Control register not set as expected\n");
+ return -EAGAIN;
+ }
+
+ /* enable/disable Rx h/w time stamping */
+ regval = er32(TSYNCRXCTL);
+ regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK);
+ regval |= tsync_rx_ctl;
+ ew32(TSYNCRXCTL, regval);
+ if ((er32(TSYNCRXCTL) & (E1000_TSYNCRXCTL_ENABLED |
+ E1000_TSYNCRXCTL_TYPE_MASK)) !=
+ (regval & (E1000_TSYNCRXCTL_ENABLED |
+ E1000_TSYNCRXCTL_TYPE_MASK))) {
+ e_err("Timesync Rx Control register not set as expected\n");
+ return -EAGAIN;
+ }
+
+ /* L2: define ethertype filter for time stamped packets */
+ if (is_l2)
+ rxmtrl |= ETH_P_1588;
+
+ /* define which PTP packets get time stamped */
+ ew32(RXMTRL, rxmtrl);
+
+ /* Filter by destination port */
+ if (is_l4) {
+ rxudp = PTP_EV_PORT;
+ cpu_to_be16s(&rxudp);
+ }
+ ew32(RXUDP, rxudp);
+
+ e1e_flush();
+
+ /* Clear TSYNCRXCTL_VALID & TSYNCTXCTL_VALID bit */
+ er32(RXSTMPH);
+ er32(TXSTMPH);
+
+ /* Get and set the System Time Register SYSTIM base frequency */
+ ret_val = e1000e_get_base_timinca(adapter, &regval);
+ if (ret_val)
+ return ret_val;
+ ew32(TIMINCA, regval);
+
+ /* reset the ns time counter */
+ timecounter_init(&adapter->tc, &adapter->cc,
+ ktime_to_ns(ktime_get_real()));
+
+ return 0;
+}
+
+/**
* e1000_configure - configure the hardware for Rx and Tx
* @adapter: private board structure
**/
@@ -3473,14 +3827,17 @@ void e1000e_reset(struct e1000_adapter *adapter)
break;
case e1000_pch2lan:
case e1000_pch_lpt:
- fc->high_water = 0x05C20;
- fc->low_water = 0x05048;
- fc->pause_time = 0x0650;
fc->refresh_time = 0x0400;
- if (adapter->netdev->mtu > ETH_DATA_LEN) {
- pba = 14;
- ew32(PBA, pba);
+
+ if (adapter->netdev->mtu <= ETH_DATA_LEN) {
+ fc->high_water = 0x05C20;
+ fc->low_water = 0x05048;
+ fc->pause_time = 0x0650;
+ break;
}
+
+ fc->high_water = ((pba << 10) * 9 / 10) & E1000_FCRTH_RTH;
+ fc->low_water = ((pba << 10) * 8 / 10) & E1000_FCRTL_RTL;
break;
}
@@ -3533,6 +3890,9 @@ void e1000e_reset(struct e1000_adapter *adapter)
e1000e_reset_adaptive(hw);
+ /* initialize systim and reset the ns time counter */
+ e1000e_config_hwtstamp(adapter);
+
if (!netif_running(adapter->netdev) &&
!test_bit(__E1000_TESTING, &adapter->state)) {
e1000_power_down_phy(adapter);
@@ -3669,6 +4029,24 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter)
}
/**
+ * e1000e_cyclecounter_read - read raw cycle counter (used by time counter)
+ * @cc: cyclecounter structure
+ **/
+static cycle_t e1000e_cyclecounter_read(const struct cyclecounter *cc)
+{
+ struct e1000_adapter *adapter = container_of(cc, struct e1000_adapter,
+ cc);
+ struct e1000_hw *hw = &adapter->hw;
+ cycle_t systim;
+
+ /* latch SYSTIMH on read of SYSTIML */
+ systim = (cycle_t)er32(SYSTIML);
+ systim |= (cycle_t)er32(SYSTIMH) << 32;
+
+ return systim;
+}
+
+/**
* e1000_sw_init - Initialize general software structures (struct e1000_adapter)
* @adapter: board private structure to initialize
*
@@ -3694,6 +4072,17 @@ static int e1000_sw_init(struct e1000_adapter *adapter)
if (e1000_alloc_queues(adapter))
return -ENOMEM;
+ /* Setup hardware time stamping cyclecounter */
+ if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) {
+ adapter->cc.read = e1000e_cyclecounter_read;
+ adapter->cc.mask = CLOCKSOURCE_MASK(64);
+ adapter->cc.mult = 1;
+ /* cc.shift set in e1000e_get_base_tininca() */
+
+ spin_lock_init(&adapter->systim_lock);
+ INIT_WORK(&adapter->tx_hwtstamp_work, e1000e_tx_hwtstamp_work);
+ }
+
/* Explicitly disable IRQ since the NIC can be in any state. */
e1000_irq_disable(adapter);
@@ -3706,7 +4095,7 @@ static int e1000_sw_init(struct e1000_adapter *adapter)
* @irq: interrupt number
* @data: pointer to a network interface device structure
**/
-static irqreturn_t e1000_intr_msi_test(int irq, void *data)
+static irqreturn_t e1000_intr_msi_test(int __always_unused irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3877,10 +4266,8 @@ static int e1000_open(struct net_device *netdev)
e1000_update_mng_vlan(adapter);
/* DMA latency requirement to workaround jumbo issue */
- if (adapter->hw.mac.type == e1000_pch2lan)
- pm_qos_add_request(&adapter->netdev->pm_qos_req,
- PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ pm_qos_add_request(&adapter->netdev->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
/* before we allocate an interrupt, we must be ready to handle it.
* Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
@@ -3988,8 +4375,7 @@ static int e1000_close(struct net_device *netdev)
!test_bit(__E1000_TESTING, &adapter->state))
e1000e_release_hw_control(adapter);
- if (adapter->hw.mac.type == e1000_pch2lan)
- pm_qos_remove_request(&adapter->netdev->pm_qos_req);
+ pm_qos_remove_request(&adapter->netdev->pm_qos_req);
pm_runtime_put_sync(&pdev->dev);
@@ -4251,6 +4637,16 @@ static void e1000e_update_stats(struct e1000_adapter *adapter)
adapter->stats.mgptc += er32(MGTPTC);
adapter->stats.mgprc += er32(MGTPRC);
adapter->stats.mgpdc += er32(MGTPDC);
+
+ /* Correctable ECC Errors */
+ if (hw->mac.type == e1000_pch_lpt) {
+ u32 pbeccsts = er32(PBECCSTS);
+ adapter->corr_errors +=
+ pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
+ adapter->uncorr_errors +=
+ (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
+ E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+ }
}
/**
@@ -4266,14 +4662,14 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter)
(adapter->hw.phy.media_type == e1000_media_type_copper)) {
int ret_val;
- ret_val = e1e_rphy(hw, PHY_CONTROL, &phy->bmcr);
- ret_val |= e1e_rphy(hw, PHY_STATUS, &phy->bmsr);
- ret_val |= e1e_rphy(hw, PHY_AUTONEG_ADV, &phy->advertise);
- ret_val |= e1e_rphy(hw, PHY_LP_ABILITY, &phy->lpa);
- ret_val |= e1e_rphy(hw, PHY_AUTONEG_EXP, &phy->expansion);
- ret_val |= e1e_rphy(hw, PHY_1000T_CTRL, &phy->ctrl1000);
- ret_val |= e1e_rphy(hw, PHY_1000T_STATUS, &phy->stat1000);
- ret_val |= e1e_rphy(hw, PHY_EXT_STATUS, &phy->estatus);
+ ret_val = e1e_rphy(hw, MII_BMCR, &phy->bmcr);
+ ret_val |= e1e_rphy(hw, MII_BMSR, &phy->bmsr);
+ ret_val |= e1e_rphy(hw, MII_ADVERTISE, &phy->advertise);
+ ret_val |= e1e_rphy(hw, MII_LPA, &phy->lpa);
+ ret_val |= e1e_rphy(hw, MII_EXPANSION, &phy->expansion);
+ ret_val |= e1e_rphy(hw, MII_CTRL1000, &phy->ctrl1000);
+ ret_val |= e1e_rphy(hw, MII_STAT1000, &phy->stat1000);
+ ret_val |= e1e_rphy(hw, MII_ESTATUS, &phy->estatus);
if (ret_val)
e_warn("Error reading PHY register\n");
} else {
@@ -4300,9 +4696,8 @@ static void e1000_print_link_info(struct e1000_adapter *adapter)
u32 ctrl = er32(CTRL);
/* Link status message must follow this format for user tools */
- printk(KERN_INFO "e1000e: %s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n",
- adapter->netdev->name,
- adapter->link_speed,
+ pr_info("%s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n",
+ adapter->netdev->name, adapter->link_speed,
adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half",
(ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE) ? "Rx/Tx" :
(ctrl & E1000_CTRL_RFCE) ? "Rx" :
@@ -4355,11 +4750,11 @@ static void e1000e_enable_receives(struct e1000_adapter *adapter)
{
/* make sure the receive unit is started */
if ((adapter->flags & FLAG_RX_NEEDS_RESTART) &&
- (adapter->flags & FLAG_RX_RESTART_NOW)) {
+ (adapter->flags & FLAG_RESTART_NOW)) {
struct e1000_hw *hw = &adapter->hw;
u32 rctl = er32(RCTL);
ew32(RCTL, rctl | E1000_RCTL_EN);
- adapter->flags &= ~FLAG_RX_RESTART_NOW;
+ adapter->flags &= ~FLAG_RESTART_NOW;
}
}
@@ -4435,6 +4830,13 @@ static void e1000_watchdog_task(struct work_struct *work)
&adapter->link_speed,
&adapter->link_duplex);
e1000_print_link_info(adapter);
+
+ /* check if SmartSpeed worked */
+ e1000e_check_downshift(hw);
+ if (phy->speed_downgraded)
+ netdev_warn(netdev,
+ "Link Speed was downgraded by SmartSpeed\n");
+
/* On supported PHYs, check for duplex mismatch only
* if link has autonegotiated at 10/100 half
*/
@@ -4446,9 +4848,9 @@ static void e1000_watchdog_task(struct work_struct *work)
(adapter->link_duplex == HALF_DUPLEX)) {
u16 autoneg_exp;
- e1e_rphy(hw, PHY_AUTONEG_EXP, &autoneg_exp);
+ e1e_rphy(hw, MII_EXPANSION, &autoneg_exp);
- if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS))
+ if (!(autoneg_exp & EXPANSION_NWAY))
e_info("Autonegotiated half duplex but link partner cannot autoneg. Try forcing full duplex if link gets many collisions.\n");
}
@@ -4521,15 +4923,22 @@ static void e1000_watchdog_task(struct work_struct *work)
adapter->link_speed = 0;
adapter->link_duplex = 0;
/* Link status message must follow this format */
- printk(KERN_INFO "e1000e: %s NIC Link is Down\n",
- adapter->netdev->name);
+ pr_info("%s NIC Link is Down\n", adapter->netdev->name);
netif_carrier_off(netdev);
if (!test_bit(__E1000_DOWN, &adapter->state))
mod_timer(&adapter->phy_info_timer,
round_jiffies(jiffies + 2 * HZ));
- if (adapter->flags & FLAG_RX_NEEDS_RESTART)
- schedule_work(&adapter->reset_task);
+ /* The link is lost so the controller stops DMA.
+ * If there is queued Tx work that cannot be done
+ * or if on an 8000ES2LAN which requires a Rx packet
+ * buffer work-around on link down event, reset the
+ * controller to flush the Tx/Rx packet buffers.
+ * (Do the reset outside of interrupt context).
+ */
+ if ((adapter->flags & FLAG_RX_NEEDS_RESTART) ||
+ (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
+ adapter->flags |= FLAG_RESTART_NOW;
else
pm_schedule_suspend(netdev->dev.parent,
LINK_TIMEOUT);
@@ -4551,20 +4960,14 @@ link_up:
adapter->gotc_old = adapter->stats.gotc;
spin_unlock(&adapter->stats64_lock);
- e1000e_update_adaptive(&adapter->hw);
-
- if (!netif_carrier_ok(netdev) &&
- (e1000_desc_unused(tx_ring) + 1 < tx_ring->count)) {
- /* 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).
- */
+ if (adapter->flags & FLAG_RESTART_NOW) {
schedule_work(&adapter->reset_task);
/* return immediately since reset is imminent */
return;
}
+ e1000e_update_adaptive(&adapter->hw);
+
/* Simple mode for Interrupt Throttle Rate (ITR) */
if (adapter->itr_setting == 4) {
/* Symmetric Tx/Rx gets a reduced ITR=2000;
@@ -4601,6 +5004,17 @@ link_up:
if (adapter->flags2 & FLAG2_CHECK_PHY_HANG)
e1000e_check_82574_phy_workaround(adapter);
+ /* Clear valid timestamp stuck in RXSTMPL/H due to a Rx error */
+ if (adapter->hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE) {
+ if ((adapter->flags2 & FLAG2_CHECK_RX_HWTSTAMP) &&
+ (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID)) {
+ er32(RXSTMPH);
+ adapter->rx_hwtstamp_cleared++;
+ } else {
+ adapter->flags2 |= FLAG2_CHECK_RX_HWTSTAMP;
+ }
+ }
+
/* Reset the timer */
if (!test_bit(__E1000_DOWN, &adapter->state))
mod_timer(&adapter->watchdog_timer,
@@ -4612,6 +5026,7 @@ link_up:
#define E1000_TX_FLAGS_TSO 0x00000004
#define E1000_TX_FLAGS_IPV4 0x00000008
#define E1000_TX_FLAGS_NO_FCS 0x00000010
+#define E1000_TX_FLAGS_HWTSTAMP 0x00000020
#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000
#define E1000_TX_FLAGS_VLAN_SHIFT 16
@@ -4870,6 +5285,11 @@ static void e1000_tx_queue(struct e1000_ring *tx_ring, int tx_flags, int count)
if (unlikely(tx_flags & E1000_TX_FLAGS_NO_FCS))
txd_lower &= ~(E1000_TXD_CMD_IFCS);
+ if (unlikely(tx_flags & E1000_TX_FLAGS_HWTSTAMP)) {
+ txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+ txd_upper |= E1000_TXD_EXTCMD_TSTAMP;
+ }
+
i = tx_ring->next_to_use;
do {
@@ -4918,12 +5338,11 @@ static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter,
struct e1000_hw *hw = &adapter->hw;
u16 length, offset;
- if (vlan_tx_tag_present(skb)) {
- if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) &&
- (adapter->hw.mng_cookie.status &
- E1000_MNG_DHCP_COOKIE_STATUS_VLAN)))
- return 0;
- }
+ if (vlan_tx_tag_present(skb) &&
+ !((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) &&
+ (adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN)))
+ return 0;
if (skb->len <= MINIMUM_DHCP_PACKET_SIZE)
return 0;
@@ -5094,7 +5513,15 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
count = e1000_tx_map(tx_ring, skb, first, adapter->tx_fifo_limit,
nr_frags);
if (count) {
- skb_tx_timestamp(skb);
+ if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ !adapter->tx_hwtstamp_skb)) {
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ tx_flags |= E1000_TX_FLAGS_HWTSTAMP;
+ adapter->tx_hwtstamp_skb = skb_get(skb);
+ schedule_work(&adapter->tx_hwtstamp_work);
+ } else {
+ skb_tx_timestamp(skb);
+ }
netdev_sent_queue(netdev, skb->len);
e1000_tx_queue(tx_ring, tx_flags, count);
@@ -5134,10 +5561,9 @@ static void e1000_reset_task(struct work_struct *work)
if (test_bit(__E1000_DOWN, &adapter->state))
return;
- if (!((adapter->flags & FLAG_RX_NEEDS_RESTART) &&
- (adapter->flags & FLAG_RX_RESTART_NOW))) {
+ if (!(adapter->flags & FLAG_RESTART_NOW)) {
e1000e_dump(adapter);
- e_err("Reset adapter\n");
+ e_err("Reset adapter unexpectedly\n");
}
e1000e_reinit_locked(adapter);
}
@@ -5323,6 +5749,61 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
return 0;
}
+/**
+ * e1000e_hwtstamp_ioctl - control hardware time stamping
+ * @netdev: network interface device structure
+ * @ifreq: interface request
+ *
+ * Outgoing time stamping can be enabled and disabled. Play nice and
+ * disable it when requested, although it shouldn't cause any overhead
+ * when no packet needs it. At most one packet in the queue may be
+ * marked for time stamping, otherwise it would be impossible to tell
+ * for sure to which packet the hardware time stamp belongs.
+ *
+ * Incoming time stamping has to be configured via the hardware filters.
+ * Not all combinations are supported, in particular event type has to be
+ * specified. Matching the kind of event packet is not supported, with the
+ * exception of "all V2 events regardless of level 2 or 4".
+ **/
+static int e1000e_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct hwtstamp_config config;
+ int ret_val;
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ adapter->hwtstamp_config = config;
+
+ ret_val = e1000e_config_hwtstamp(adapter);
+ if (ret_val)
+ return ret_val;
+
+ config = adapter->hwtstamp_config;
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ /* With V2 type filters which specify a Sync or Delay Request,
+ * Path Delay Request/Response messages are also time stamped
+ * by hardware so notify the caller the requested packets plus
+ * some others are time stamped.
+ */
+ config.rx_filter = HWTSTAMP_FILTER_SOME;
+ break;
+ default:
+ break;
+ }
+
+ return copy_to_user(ifr->ifr_data, &config,
+ sizeof(config)) ? -EFAULT : 0;
+}
+
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
switch (cmd) {
@@ -5330,6 +5811,8 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
case SIOCGMIIREG:
case SIOCSMIIREG:
return e1000_mii_ioctl(netdev, ifr, cmd);
+ case SIOCSHWTSTAMP:
+ return e1000e_hwtstamp_ioctl(netdev, ifr);
default:
return -EOPNOTSUPP;
}
@@ -5340,7 +5823,7 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
struct e1000_hw *hw = &adapter->hw;
u32 i, mac_reg;
u16 phy_reg, wuc_enable;
- int retval = 0;
+ int retval;
/* copy MAC RARs to PHY RARs */
e1000_copy_rx_addrs_to_phy_ich8lan(hw);
@@ -5554,14 +6037,21 @@ static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
#else
static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
{
+ u16 aspm_ctl = 0;
+
+ if (state & PCIE_LINK_STATE_L0S)
+ aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L0S;
+ if (state & PCIE_LINK_STATE_L1)
+ aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L1;
+
/* Both device and parent should have the same ASPM setting.
* Disable ASPM in downstream component first and then upstream.
*/
- pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, state);
+ pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_ctl);
if (pdev->bus->self)
pcie_capability_clear_word(pdev->bus->self, PCI_EXP_LNKCTL,
- state);
+ aspm_ctl);
}
#endif
static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
@@ -5746,7 +6236,7 @@ static void e1000_shutdown(struct pci_dev *pdev)
#ifdef CONFIG_NET_POLL_CONTROLLER
-static irqreturn_t e1000_intr_msix(int irq, void *data)
+static irqreturn_t e1000_intr_msix(int __always_unused irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -5910,7 +6400,6 @@ static void e1000_io_resume(struct pci_dev *pdev)
*/
if (!(adapter->flags & FLAG_HAS_AMT))
e1000e_get_hw_control(adapter);
-
}
static void e1000_print_device_info(struct e1000_adapter *adapter)
@@ -6068,8 +6557,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
err = pci_request_selected_regions_exclusive(pdev,
- pci_select_bars(pdev, IORESOURCE_MEM),
- e1000e_driver_name);
+ pci_select_bars(pdev, IORESOURCE_MEM),
+ e1000e_driver_name);
if (err)
goto err_pci_reg;
@@ -6228,11 +6717,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
"NVM Read Error while reading MAC address\n");
memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
- memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
- if (!is_valid_ether_addr(netdev->perm_addr)) {
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
dev_err(&pdev->dev, "Invalid MAC Address: %pM\n",
- netdev->perm_addr);
+ netdev->dev_addr);
err = -EIO;
goto err_eeprom;
}
@@ -6318,6 +6806,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
+ /* init PTP hardware clock */
+ e1000e_ptp_init(adapter);
+
e1000_print_device_info(adapter);
if (pci_dev_run_wake(pdev))
@@ -6366,6 +6857,8 @@ static void e1000_remove(struct pci_dev *pdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
bool down = test_bit(__E1000_DOWN, &adapter->state);
+ e1000e_ptp_remove(adapter);
+
/* The timers may be rescheduled, so explicitly disable them
* from being rescheduled.
*/
@@ -6380,6 +6873,14 @@ static void e1000_remove(struct pci_dev *pdev)
cancel_work_sync(&adapter->update_phy_task);
cancel_work_sync(&adapter->print_hang_task);
+ if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) {
+ cancel_work_sync(&adapter->tx_hwtstamp_work);
+ if (adapter->tx_hwtstamp_skb) {
+ dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+ adapter->tx_hwtstamp_skb = NULL;
+ }
+ }
+
if (!(netdev->flags & IFF_UP))
e1000_power_down_phy(adapter);
@@ -6532,7 +7033,7 @@ static int __init e1000_init_module(void)
int ret;
pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
e1000e_driver_version);
- pr_info("Copyright(c) 1999 - 2012 Intel Corporation.\n");
+ pr_info("Copyright(c) 1999 - 2013 Intel Corporation.\n");
ret = pci_register_driver(&e1000_driver);
return ret;
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c
index b6468804cb2e..84fecc268162 100644
--- a/drivers/net/ethernet/intel/e1000e/nvm.c
+++ b/drivers/net/ethernet/intel/e1000e/nvm.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -359,7 +359,7 @@ s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
{
struct e1000_nvm_info *nvm = &hw->nvm;
- s32 ret_val;
+ s32 ret_val = -E1000_ERR_NVM;
u16 widx = 0;
/* A check for invalid values: offset too large, too many words,
@@ -371,16 +371,18 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
return -E1000_ERR_NVM;
}
- ret_val = nvm->ops.acquire(hw);
- if (ret_val)
- return ret_val;
-
while (widx < words) {
u8 write_opcode = NVM_WRITE_OPCODE_SPI;
- ret_val = e1000_ready_nvm_eeprom(hw);
+ ret_val = nvm->ops.acquire(hw);
if (ret_val)
- goto release;
+ return ret_val;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val) {
+ nvm->ops.release(hw);
+ return ret_val;
+ }
e1000_standby_nvm(hw);
@@ -413,12 +415,10 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
break;
}
}
+ usleep_range(10000, 20000);
+ nvm->ops.release(hw);
}
- usleep_range(10000, 20000);
-release:
- nvm->ops.release(hw);
-
return ret_val;
}
@@ -464,8 +464,8 @@ s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
if (nvm_data != NVM_PBA_PTR_GUARD) {
e_dbg("NVM PBA number is not stored as string\n");
- /* we will need 11 characters to store the PBA */
- if (pba_num_size < 11) {
+ /* make sure callers buffer is big enough to store the PBA */
+ if (pba_num_size < E1000_PBANUM_LENGTH) {
e_dbg("PBA string buffer too small\n");
return E1000_ERR_NO_SPACE;
}
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.h b/drivers/net/ethernet/intel/e1000e/nvm.h
new file mode 100644
index 000000000000..45fc69561627
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/nvm.h
@@ -0,0 +1,47 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2013 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_NVM_H_
+#define _E1000E_NVM_H_
+
+s32 e1000e_acquire_nvm(struct e1000_hw *hw);
+
+s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+s32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
+s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
+ u32 pba_num_size);
+s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
+s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
+s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
+void e1000e_release_nvm(struct e1000_hw *hw);
+
+#define E1000_STM_OPCODE 0xDB00
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c
index 89d536dd7ff5..98da75dff936 100644
--- a/drivers/net/ethernet/intel/e1000e/param.c
+++ b/drivers/net/ethernet/intel/e1000e/param.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -53,8 +53,7 @@ MODULE_PARM_DESC(copybreak,
*/
#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
#define E1000_PARAM(X, desc) \
- static int X[E1000_MAX_NIC+1] \
- = E1000_PARAM_INIT; \
+ static int X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
static unsigned int num_##X; \
module_param_array_named(X, X, int, &num_##X, 0); \
MODULE_PARM_DESC(X, desc);
@@ -447,8 +446,7 @@ void e1000e_check_options(struct e1000_adapter *adapter)
if (num_SmartPowerDownEnable > bd) {
unsigned int spd = SmartPowerDownEnable[bd];
e1000_validate_option(&spd, &opt, adapter);
- if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN)
- && spd)
+ if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && spd)
adapter->flags |= FLAG_SMART_POWER_DOWN;
}
}
diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index 28b38ff37e84..0930c136aa31 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -28,16 +28,12 @@
#include "e1000.h"
-static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw);
-static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw);
-static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active);
static s32 e1000_wait_autoneg(struct e1000_hw *hw);
-static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg);
static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
u16 *data, bool read, bool page_set);
static u32 e1000_get_phy_addr_for_hv_page(u32 page);
static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
- u16 *data, bool read);
+ u16 *data, bool read);
/* Cable length tables */
static const u16 e1000_m88_cable_length_table[] = {
@@ -57,48 +53,6 @@ static const u16 e1000_igp_2_cable_length_table[] = {
#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
ARRAY_SIZE(e1000_igp_2_cable_length_table)
-#define BM_PHY_REG_PAGE(offset) \
- ((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
-#define BM_PHY_REG_NUM(offset) \
- ((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\
- (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
- ~MAX_PHY_REG_ADDRESS)))
-
-#define HV_INTC_FC_PAGE_START 768
-#define I82578_ADDR_REG 29
-#define I82577_ADDR_REG 16
-#define I82577_CFG_REG 22
-#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15)
-#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */
-#define I82577_CTRL_REG 23
-
-/* 82577 specific PHY registers */
-#define I82577_PHY_CTRL_2 18
-#define I82577_PHY_STATUS_2 26
-#define I82577_PHY_DIAG_STATUS 31
-
-/* I82577 PHY Status 2 */
-#define I82577_PHY_STATUS2_REV_POLARITY 0x0400
-#define I82577_PHY_STATUS2_MDIX 0x0800
-#define I82577_PHY_STATUS2_SPEED_MASK 0x0300
-#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200
-
-/* I82577 PHY Control 2 */
-#define I82577_PHY_CTRL2_MANUAL_MDIX 0x0200
-#define I82577_PHY_CTRL2_AUTO_MDI_MDIX 0x0400
-#define I82577_PHY_CTRL2_MDIX_CFG_MASK 0x0600
-
-/* I82577 PHY Diagnostics Status */
-#define I82577_DSTATUS_CABLE_LENGTH 0x03FC
-#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2
-
-/* BM PHY Copper Specific Control 1 */
-#define BM_CS_CTRL1 16
-
-#define HV_MUX_DATA_CTRL PHY_REG(776, 16)
-#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400
-#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004
-
/**
* e1000e_check_reset_block_generic - Check if PHY reset is blocked
* @hw: pointer to the HW structure
@@ -135,13 +89,13 @@ s32 e1000e_get_phy_id(struct e1000_hw *hw)
return 0;
while (retry_count < 2) {
- ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+ ret_val = e1e_rphy(hw, MII_PHYSID1, &phy_id);
if (ret_val)
return ret_val;
phy->id = (u32)(phy_id << 16);
udelay(20);
- ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+ ret_val = e1e_rphy(hw, MII_PHYSID2, &phy_id);
if (ret_val)
return ret_val;
@@ -645,31 +599,31 @@ static s32 e1000_set_master_slave_mode(struct e1000_hw *hw)
u16 phy_data;
/* Resolve Master/Slave mode */
- ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &phy_data);
+ ret_val = e1e_rphy(hw, MII_CTRL1000, &phy_data);
if (ret_val)
return ret_val;
/* load defaults for future use */
- hw->phy.original_ms_type = (phy_data & CR_1000T_MS_ENABLE) ?
- ((phy_data & CR_1000T_MS_VALUE) ?
+ hw->phy.original_ms_type = (phy_data & CTL1000_ENABLE_MASTER) ?
+ ((phy_data & CTL1000_AS_MASTER) ?
e1000_ms_force_master : e1000_ms_force_slave) : e1000_ms_auto;
switch (hw->phy.ms_type) {
case e1000_ms_force_master:
- phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ phy_data |= (CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
break;
case e1000_ms_force_slave:
- phy_data |= CR_1000T_MS_ENABLE;
- phy_data &= ~(CR_1000T_MS_VALUE);
+ phy_data |= CTL1000_ENABLE_MASTER;
+ phy_data &= ~(CTL1000_AS_MASTER);
break;
case e1000_ms_auto:
- phy_data &= ~CR_1000T_MS_ENABLE;
+ phy_data &= ~CTL1000_ENABLE_MASTER;
/* fall-through */
default:
break;
}
- return e1e_wphy(hw, PHY_1000T_CTRL, phy_data);
+ return e1e_wphy(hw, MII_CTRL1000, phy_data);
}
/**
@@ -792,7 +746,7 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
if (ret_val)
return ret_val;
/* Commit the changes. */
- ret_val = e1000e_commit_phy(hw);
+ ret_val = phy->ops.commit(hw);
if (ret_val) {
e_dbg("Error committing the PHY changes\n");
return ret_val;
@@ -848,10 +802,12 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
}
/* Commit the changes. */
- ret_val = e1000e_commit_phy(hw);
- if (ret_val) {
- e_dbg("Error committing the PHY changes\n");
- return ret_val;
+ if (phy->ops.commit) {
+ ret_val = phy->ops.commit(hw);
+ if (ret_val) {
+ e_dbg("Error committing the PHY changes\n");
+ return ret_val;
+ }
}
if (phy->type == e1000_phy_82578) {
@@ -895,10 +851,12 @@ s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw)
msleep(100);
/* disable lplu d0 during driver init */
- ret_val = e1000_set_d0_lplu_state(hw, false);
- if (ret_val) {
- e_dbg("Error Disabling LPLU D0\n");
- return ret_val;
+ if (hw->phy.ops.set_d0_lplu_state) {
+ ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
+ if (ret_val) {
+ e_dbg("Error Disabling LPLU D0\n");
+ return ret_val;
+ }
}
/* Configure mdi-mdix settings */
ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data);
@@ -943,12 +901,12 @@ s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw)
return ret_val;
/* Set auto Master/Slave resolution process */
- ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
+ ret_val = e1e_rphy(hw, MII_CTRL1000, &data);
if (ret_val)
return ret_val;
- data &= ~CR_1000T_MS_ENABLE;
- ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
+ data &= ~CTL1000_ENABLE_MASTER;
+ ret_val = e1e_wphy(hw, MII_CTRL1000, data);
if (ret_val)
return ret_val;
}
@@ -978,13 +936,13 @@ static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
phy->autoneg_advertised &= phy->autoneg_mask;
/* Read the MII Auto-Neg Advertisement Register (Address 4). */
- ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+ ret_val = e1e_rphy(hw, MII_ADVERTISE, &mii_autoneg_adv_reg);
if (ret_val)
return ret_val;
if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
/* Read the MII 1000Base-T Control Register (Address 9). */
- ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+ ret_val = e1e_rphy(hw, MII_CTRL1000, &mii_1000t_ctrl_reg);
if (ret_val)
return ret_val;
}
@@ -1000,36 +958,35 @@ static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
* Advertisement Register (Address 4) and the 1000 mb speed bits in
* the 1000Base-T Control Register (Address 9).
*/
- mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
- NWAY_AR_100TX_HD_CAPS |
- NWAY_AR_10T_FD_CAPS |
- NWAY_AR_10T_HD_CAPS);
- mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+ mii_autoneg_adv_reg &= ~(ADVERTISE_100FULL |
+ ADVERTISE_100HALF |
+ ADVERTISE_10FULL | ADVERTISE_10HALF);
+ mii_1000t_ctrl_reg &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
e_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
/* Do we want to advertise 10 Mb Half Duplex? */
if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
e_dbg("Advertise 10mb Half duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ mii_autoneg_adv_reg |= ADVERTISE_10HALF;
}
/* Do we want to advertise 10 Mb Full Duplex? */
if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
e_dbg("Advertise 10mb Full duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ mii_autoneg_adv_reg |= ADVERTISE_10FULL;
}
/* Do we want to advertise 100 Mb Half Duplex? */
if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
e_dbg("Advertise 100mb Half duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ mii_autoneg_adv_reg |= ADVERTISE_100HALF;
}
/* Do we want to advertise 100 Mb Full Duplex? */
if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
e_dbg("Advertise 100mb Full duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ mii_autoneg_adv_reg |= ADVERTISE_100FULL;
}
/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
@@ -1039,14 +996,14 @@ static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
/* Do we want to advertise 1000 Mb Full Duplex? */
if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
e_dbg("Advertise 1000mb Full duplex\n");
- mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ mii_1000t_ctrl_reg |= ADVERTISE_1000FULL;
}
/* Check for a software override of the flow control settings, and
* setup the PHY advertisement registers accordingly. If
* auto-negotiation is enabled, then software will have to set the
* "PAUSE" bits to the correct value in the Auto-Negotiation
- * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+ * Advertisement Register (MII_ADVERTISE) and re-start auto-
* negotiation.
*
* The possible values of the "fc" parameter are:
@@ -1064,7 +1021,8 @@ static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
/* Flow control (Rx & Tx) is completely disabled by a
* software over-ride.
*/
- mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ mii_autoneg_adv_reg &=
+ ~(ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP);
break;
case e1000_fc_rx_pause:
/* Rx Flow control is enabled, and Tx Flow control is
@@ -1076,34 +1034,36 @@ static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
* (in e1000e_config_fc_after_link_up) we will disable the
* hw's ability to send PAUSE frames.
*/
- mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ mii_autoneg_adv_reg |=
+ (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP);
break;
case e1000_fc_tx_pause:
/* Tx Flow control is enabled, and Rx Flow control is
* disabled, by a software over-ride.
*/
- mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
- mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ mii_autoneg_adv_reg |= ADVERTISE_PAUSE_ASYM;
+ mii_autoneg_adv_reg &= ~ADVERTISE_PAUSE_CAP;
break;
case e1000_fc_full:
/* Flow control (both Rx and Tx) is enabled by a software
* over-ride.
*/
- mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ mii_autoneg_adv_reg |=
+ (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP);
break;
default:
e_dbg("Flow control param set incorrectly\n");
return -E1000_ERR_CONFIG;
}
- ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+ ret_val = e1e_wphy(hw, MII_ADVERTISE, mii_autoneg_adv_reg);
if (ret_val)
return ret_val;
e_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
if (phy->autoneg_mask & ADVERTISE_1000_FULL)
- ret_val = e1e_wphy(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+ ret_val = e1e_wphy(hw, MII_CTRL1000, mii_1000t_ctrl_reg);
return ret_val;
}
@@ -1145,12 +1105,12 @@ static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
/* Restart auto-negotiation by setting the Auto Neg Enable bit and
* the Auto Neg Restart bit in the PHY control register.
*/
- ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+ ret_val = e1e_rphy(hw, MII_BMCR, &phy_ctrl);
if (ret_val)
return ret_val;
- phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
- ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+ phy_ctrl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ ret_val = e1e_wphy(hw, MII_BMCR, phy_ctrl);
if (ret_val)
return ret_val;
@@ -1196,7 +1156,7 @@ s32 e1000e_setup_copper_link(struct e1000_hw *hw)
* depending on user settings.
*/
e_dbg("Forcing Speed and Duplex\n");
- ret_val = e1000_phy_force_speed_duplex(hw);
+ ret_val = hw->phy.ops.force_speed_duplex(hw);
if (ret_val) {
e_dbg("Error Forcing Speed and Duplex\n");
return ret_val;
@@ -1237,13 +1197,13 @@ s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw)
u16 phy_data;
bool link;
- ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+ ret_val = e1e_rphy(hw, MII_BMCR, &phy_data);
if (ret_val)
return ret_val;
e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
- ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+ ret_val = e1e_wphy(hw, MII_BMCR, phy_data);
if (ret_val)
return ret_val;
@@ -1315,20 +1275,22 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
e_dbg("M88E1000 PSCR: %X\n", phy_data);
- ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+ ret_val = e1e_rphy(hw, MII_BMCR, &phy_data);
if (ret_val)
return ret_val;
e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
- ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+ ret_val = e1e_wphy(hw, MII_BMCR, phy_data);
if (ret_val)
return ret_val;
/* Reset the phy to commit changes. */
- ret_val = e1000e_commit_phy(hw);
- if (ret_val)
- return ret_val;
+ if (hw->phy.ops.commit) {
+ ret_val = hw->phy.ops.commit(hw);
+ if (ret_val)
+ return ret_val;
+ }
if (phy->autoneg_wait_to_complete) {
e_dbg("Waiting for forced speed/duplex link on M88 phy.\n");
@@ -1406,13 +1368,13 @@ s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
u16 data;
bool link;
- ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
+ ret_val = e1e_rphy(hw, MII_BMCR, &data);
if (ret_val)
return ret_val;
e1000e_phy_force_speed_duplex_setup(hw, &data);
- ret_val = e1e_wphy(hw, PHY_CONTROL, data);
+ ret_val = e1e_wphy(hw, MII_BMCR, data);
if (ret_val)
return ret_val;
@@ -1456,13 +1418,13 @@ s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
/**
* e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
* @hw: pointer to the HW structure
- * @phy_ctrl: pointer to current value of PHY_CONTROL
+ * @phy_ctrl: pointer to current value of MII_BMCR
*
* Forces speed and duplex on the PHY by doing the following: disable flow
* control, force speed/duplex on the MAC, disable auto speed detection,
* disable auto-negotiation, configure duplex, configure speed, configure
* the collision distance, write configuration to CTRL register. The
- * caller must write to the PHY_CONTROL register for these settings to
+ * caller must write to the MII_BMCR register for these settings to
* take affect.
**/
void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
@@ -1482,29 +1444,28 @@ void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
ctrl &= ~E1000_CTRL_ASDE;
/* Disable autoneg on the phy */
- *phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+ *phy_ctrl &= ~BMCR_ANENABLE;
/* Forcing Full or Half Duplex? */
if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
ctrl &= ~E1000_CTRL_FD;
- *phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+ *phy_ctrl &= ~BMCR_FULLDPLX;
e_dbg("Half Duplex\n");
} else {
ctrl |= E1000_CTRL_FD;
- *phy_ctrl |= MII_CR_FULL_DUPLEX;
+ *phy_ctrl |= BMCR_FULLDPLX;
e_dbg("Full Duplex\n");
}
/* Forcing 10mb or 100mb? */
if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
ctrl |= E1000_CTRL_SPD_100;
- *phy_ctrl |= MII_CR_SPEED_100;
- *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+ *phy_ctrl |= BMCR_SPEED100;
+ *phy_ctrl &= ~BMCR_SPEED1000;
e_dbg("Forcing 100mb\n");
} else {
ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
- *phy_ctrl |= MII_CR_SPEED_10;
- *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+ *phy_ctrl &= ~(BMCR_SPEED1000 | BMCR_SPEED100);
e_dbg("Forcing 10mb\n");
}
@@ -1745,13 +1706,13 @@ static s32 e1000_wait_autoneg(struct e1000_hw *hw)
/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
- ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ ret_val = e1e_rphy(hw, MII_BMSR, &phy_status);
if (ret_val)
break;
- ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ ret_val = e1e_rphy(hw, MII_BMSR, &phy_status);
if (ret_val)
break;
- if (phy_status & MII_SR_AUTONEG_COMPLETE)
+ if (phy_status & BMSR_ANEGCOMPLETE)
break;
msleep(100);
}
@@ -1778,21 +1739,21 @@ s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
u16 i, phy_status;
for (i = 0; i < iterations; i++) {
- /* Some PHYs require the PHY_STATUS register to be read
+ /* Some PHYs require the MII_BMSR register to be read
* twice due to the link bit being sticky. No harm doing
* it across the board.
*/
- ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ ret_val = e1e_rphy(hw, MII_BMSR, &phy_status);
if (ret_val)
/* If the first read fails, another entity may have
* ownership of the resources, wait and try again to
* see if they have relinquished the resources yet.
*/
udelay(usec_interval);
- ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ ret_val = e1e_rphy(hw, MII_BMSR, &phy_status);
if (ret_val)
break;
- if (phy_status & MII_SR_LINK_STATUS)
+ if (phy_status & BMSR_LSTATUS)
break;
if (usec_interval >= 1000)
mdelay(usec_interval/1000);
@@ -1962,21 +1923,19 @@ s32 e1000e_get_phy_info_m88(struct e1000_hw *hw)
phy->is_mdix = !!(phy_data & M88E1000_PSSR_MDIX);
if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
- ret_val = e1000_get_cable_length(hw);
+ ret_val = hw->phy.ops.get_cable_length(hw);
if (ret_val)
return ret_val;
- ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
+ ret_val = e1e_rphy(hw, MII_STAT1000, &phy_data);
if (ret_val)
return ret_val;
- phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
- ? e1000_1000t_rx_status_ok
- : e1000_1000t_rx_status_not_ok;
+ phy->local_rx = (phy_data & LPA_1000LOCALRXOK)
+ ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
- phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
- ? e1000_1000t_rx_status_ok
- : e1000_1000t_rx_status_not_ok;
+ phy->remote_rx = (phy_data & LPA_1000REMRXOK)
+ ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
} else {
/* Set values to "undefined" */
phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
@@ -2026,21 +1985,19 @@ s32 e1000e_get_phy_info_igp(struct e1000_hw *hw)
if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
- ret_val = e1000_get_cable_length(hw);
+ ret_val = phy->ops.get_cable_length(hw);
if (ret_val)
return ret_val;
- ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
+ ret_val = e1e_rphy(hw, MII_STAT1000, &data);
if (ret_val)
return ret_val;
- phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
- ? e1000_1000t_rx_status_ok
- : e1000_1000t_rx_status_not_ok;
+ phy->local_rx = (data & LPA_1000LOCALRXOK)
+ ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
- phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
- ? e1000_1000t_rx_status_ok
- : e1000_1000t_rx_status_not_ok;
+ phy->remote_rx = (data & LPA_1000REMRXOK)
+ ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
} else {
phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
phy->local_rx = e1000_1000t_rx_status_undefined;
@@ -2114,12 +2071,12 @@ s32 e1000e_phy_sw_reset(struct e1000_hw *hw)
s32 ret_val;
u16 phy_ctrl;
- ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+ ret_val = e1e_rphy(hw, MII_BMCR, &phy_ctrl);
if (ret_val)
return ret_val;
- phy_ctrl |= MII_CR_RESET;
- ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+ phy_ctrl |= BMCR_RESET;
+ ret_val = e1e_wphy(hw, MII_BMCR, phy_ctrl);
if (ret_val)
return ret_val;
@@ -2166,17 +2123,17 @@ s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
phy->ops.release(hw);
- return e1000_get_phy_cfg_done(hw);
+ return phy->ops.get_cfg_done(hw);
}
/**
- * e1000e_get_cfg_done - Generic configuration done
+ * e1000e_get_cfg_done_generic - Generic configuration done
* @hw: pointer to the HW structure
*
* Generic function to wait 10 milli-seconds for configuration to complete
* and return success.
**/
-s32 e1000e_get_cfg_done(struct e1000_hw *hw)
+s32 e1000e_get_cfg_done_generic(struct e1000_hw __always_unused *hw)
{
mdelay(10);
@@ -2266,38 +2223,6 @@ s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw)
return 0;
}
-/* Internal function pointers */
-
-/**
- * e1000_get_phy_cfg_done - Generic PHY configuration done
- * @hw: pointer to the HW structure
- *
- * Return success if silicon family did not implement a family specific
- * get_cfg_done function.
- **/
-static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
-{
- if (hw->phy.ops.get_cfg_done)
- return hw->phy.ops.get_cfg_done(hw);
-
- return 0;
-}
-
-/**
- * e1000_phy_force_speed_duplex - Generic force PHY speed/duplex
- * @hw: pointer to the HW structure
- *
- * When the silicon family has not implemented a forced speed/duplex
- * function for the PHY, simply return 0.
- **/
-static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
-{
- if (hw->phy.ops.force_speed_duplex)
- return hw->phy.ops.force_speed_duplex(hw);
-
- return 0;
-}
-
/**
* e1000e_get_phy_type_from_id - Get PHY type from id
* @phy_id: phy_id read from the phy
@@ -2549,7 +2474,6 @@ s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
hw->phy.addr = 1;
if (offset > MAX_PHY_MULTI_PAGE_REG) {
-
/* Page is shifted left, PHY expects (page x 32) */
ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
page);
@@ -2672,7 +2596,7 @@ s32 e1000_enable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg)
**/
s32 e1000_disable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg)
{
- s32 ret_val = 0;
+ s32 ret_val;
/* Select Port Control Registers page */
ret_val = e1000_set_page_igp(hw, (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
@@ -2781,9 +2705,9 @@ void e1000_power_up_phy_copper(struct e1000_hw *hw)
u16 mii_reg = 0;
/* The PHY will retain its settings across a power down/up cycle */
- e1e_rphy(hw, PHY_CONTROL, &mii_reg);
- mii_reg &= ~MII_CR_POWER_DOWN;
- e1e_wphy(hw, PHY_CONTROL, mii_reg);
+ e1e_rphy(hw, MII_BMCR, &mii_reg);
+ mii_reg &= ~BMCR_PDOWN;
+ e1e_wphy(hw, MII_BMCR, mii_reg);
}
/**
@@ -2799,50 +2723,13 @@ void e1000_power_down_phy_copper(struct e1000_hw *hw)
u16 mii_reg = 0;
/* The PHY will retain its settings across a power down/up cycle */
- e1e_rphy(hw, PHY_CONTROL, &mii_reg);
- mii_reg |= MII_CR_POWER_DOWN;
- e1e_wphy(hw, PHY_CONTROL, mii_reg);
+ e1e_rphy(hw, MII_BMCR, &mii_reg);
+ mii_reg |= BMCR_PDOWN;
+ e1e_wphy(hw, MII_BMCR, mii_reg);
usleep_range(1000, 2000);
}
/**
- * e1000e_commit_phy - Soft PHY reset
- * @hw: pointer to the HW structure
- *
- * Performs a soft PHY reset on those that apply. This is a function pointer
- * entry point called by drivers.
- **/
-s32 e1000e_commit_phy(struct e1000_hw *hw)
-{
- if (hw->phy.ops.commit)
- return hw->phy.ops.commit(hw);
-
- return 0;
-}
-
-/**
- * e1000_set_d0_lplu_state - Sets low power link up state for D0
- * @hw: pointer to the HW structure
- * @active: boolean used to enable/disable lplu
- *
- * Success returns 0, Failure returns 1
- *
- * The low power link up (lplu) state is set to the power management level D0
- * and SmartSpeed is disabled when active is true, else clear lplu for D0
- * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
- * is used during Dx states where the power conservation is most important.
- * During driver activity, SmartSpeed should be enabled so performance is
- * maintained. This is a function pointer entry point called by drivers.
- **/
-static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
-{
- if (hw->phy.ops.set_d0_lplu_state)
- return hw->phy.ops.set_d0_lplu_state(hw, active);
-
- return 0;
-}
-
-/**
* __e1000_read_phy_reg_hv - Read HV PHY register
* @hw: pointer to the HW structure
* @offset: register offset to be read
@@ -3104,8 +2991,8 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
u16 *data, bool read)
{
s32 ret_val;
- u32 addr_reg = 0;
- u32 data_reg = 0;
+ u32 addr_reg;
+ u32 data_reg;
/* This takes care of the difference with desktop vs mobile phy */
addr_reg = (hw->phy.type == e1000_phy_82578) ?
@@ -3154,8 +3041,8 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
return 0;
/* Do not apply workaround if in PHY loopback bit 14 set */
- e1e_rphy(hw, PHY_CONTROL, &data);
- if (data & PHY_CONTROL_LB)
+ e1e_rphy(hw, MII_BMCR, &data);
+ if (data & BMCR_LOOPBACK)
return 0;
/* check if link is up and at 1Gbps */
@@ -3173,8 +3060,9 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
msleep(200);
/* flush the packets in the fifo buffer */
- ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL, HV_MUX_DATA_CTRL_GEN_TO_MAC |
- HV_MUX_DATA_CTRL_FORCE_SPEED);
+ ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL,
+ (HV_MUX_DATA_CTRL_GEN_TO_MAC |
+ HV_MUX_DATA_CTRL_FORCE_SPEED));
if (ret_val)
return ret_val;
@@ -3218,13 +3106,13 @@ s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
u16 phy_data;
bool link;
- ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+ ret_val = e1e_rphy(hw, MII_BMCR, &phy_data);
if (ret_val)
return ret_val;
e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
- ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+ ret_val = e1e_wphy(hw, MII_BMCR, phy_data);
if (ret_val)
return ret_val;
@@ -3292,17 +3180,15 @@ s32 e1000_get_phy_info_82577(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
+ ret_val = e1e_rphy(hw, MII_STAT1000, &data);
if (ret_val)
return ret_val;
- phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
- ? e1000_1000t_rx_status_ok
- : e1000_1000t_rx_status_not_ok;
+ phy->local_rx = (data & LPA_1000LOCALRXOK)
+ ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
- phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
- ? e1000_1000t_rx_status_ok
- : e1000_1000t_rx_status_not_ok;
+ phy->remote_rx = (data & LPA_1000REMRXOK)
+ ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
} else {
phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
phy->local_rx = e1000_1000t_rx_status_undefined;
@@ -3333,7 +3219,7 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw)
I82577_DSTATUS_CABLE_LENGTH_SHIFT;
if (length == E1000_CABLE_LENGTH_UNDEFINED)
- ret_val = -E1000_ERR_PHY;
+ return -E1000_ERR_PHY;
phy->cable_length = length;
diff --git a/drivers/net/ethernet/intel/e1000e/phy.h b/drivers/net/ethernet/intel/e1000e/phy.h
new file mode 100644
index 000000000000..f4f71b9991e3
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/phy.h
@@ -0,0 +1,242 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2013 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_PHY_H_
+#define _E1000E_PHY_H_
+
+s32 e1000e_check_downshift(struct e1000_hw *hw);
+s32 e1000_check_polarity_m88(struct e1000_hw *hw);
+s32 e1000_check_polarity_igp(struct e1000_hw *hw);
+s32 e1000_check_polarity_ife(struct e1000_hw *hw);
+s32 e1000e_check_reset_block_generic(struct e1000_hw *hw);
+s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw);
+s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw);
+s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
+s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
+s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
+s32 e1000e_get_cfg_done_generic(struct e1000_hw *hw);
+s32 e1000e_get_phy_id(struct e1000_hw *hw);
+s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
+s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
+s32 e1000_get_phy_info_ife(struct e1000_hw *hw);
+s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
+void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
+s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
+s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
+s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_set_page_igp(struct e1000_hw *hw, u16 page);
+s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+s32 e1000e_setup_copper_link(struct e1000_hw *hw);
+s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+ u32 usec_interval, bool *success);
+s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw);
+enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
+s32 e1000e_determine_phy_address(struct e1000_hw *hw);
+s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_enable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg);
+s32 e1000_disable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg);
+s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
+void e1000_power_up_phy_copper(struct e1000_hw *hw);
+void e1000_power_down_phy_copper(struct e1000_hw *hw);
+s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_read_phy_reg_page_hv(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_write_phy_reg_page_hv(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw);
+s32 e1000_copper_link_setup_82577(struct e1000_hw *hw);
+s32 e1000_check_polarity_82577(struct e1000_hw *hw);
+s32 e1000_get_phy_info_82577(struct e1000_hw *hw);
+s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
+s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
+
+#define E1000_MAX_PHY_ADDR 8
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */
+#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */
+#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */
+#define IGP_PAGE_SHIFT 5
+#define PHY_REG_MASK 0x1F
+
+/* BM/HV Specific Registers */
+#define BM_PORT_CTRL_PAGE 769
+#define BM_WUC_PAGE 800
+#define BM_WUC_ADDRESS_OPCODE 0x11
+#define BM_WUC_DATA_OPCODE 0x12
+#define BM_WUC_ENABLE_PAGE BM_PORT_CTRL_PAGE
+#define BM_WUC_ENABLE_REG 17
+#define BM_WUC_ENABLE_BIT (1 << 2)
+#define BM_WUC_HOST_WU_BIT (1 << 4)
+#define BM_WUC_ME_WU_BIT (1 << 5)
+
+#define PHY_UPPER_SHIFT 21
+#define BM_PHY_REG(page, reg) \
+ (((reg) & MAX_PHY_REG_ADDRESS) |\
+ (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
+ (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
+#define BM_PHY_REG_PAGE(offset) \
+ ((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
+#define BM_PHY_REG_NUM(offset) \
+ ((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\
+ (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
+ ~MAX_PHY_REG_ADDRESS)))
+
+#define HV_INTC_FC_PAGE_START 768
+#define I82578_ADDR_REG 29
+#define I82577_ADDR_REG 16
+#define I82577_CFG_REG 22
+#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15)
+#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift */
+#define I82577_CTRL_REG 23
+
+/* 82577 specific PHY registers */
+#define I82577_PHY_CTRL_2 18
+#define I82577_PHY_LBK_CTRL 19
+#define I82577_PHY_STATUS_2 26
+#define I82577_PHY_DIAG_STATUS 31
+
+/* I82577 PHY Status 2 */
+#define I82577_PHY_STATUS2_REV_POLARITY 0x0400
+#define I82577_PHY_STATUS2_MDIX 0x0800
+#define I82577_PHY_STATUS2_SPEED_MASK 0x0300
+#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200
+
+/* I82577 PHY Control 2 */
+#define I82577_PHY_CTRL2_MANUAL_MDIX 0x0200
+#define I82577_PHY_CTRL2_AUTO_MDI_MDIX 0x0400
+#define I82577_PHY_CTRL2_MDIX_CFG_MASK 0x0600
+
+/* I82577 PHY Diagnostics Status */
+#define I82577_DSTATUS_CABLE_LENGTH 0x03FC
+#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2
+
+/* BM PHY Copper Specific Control 1 */
+#define BM_CS_CTRL1 16
+
+/* BM PHY Copper Specific Status */
+#define BM_CS_STATUS 17
+#define BM_CS_STATUS_LINK_UP 0x0400
+#define BM_CS_STATUS_RESOLVED 0x0800
+#define BM_CS_STATUS_SPEED_MASK 0xC000
+#define BM_CS_STATUS_SPEED_1000 0x8000
+
+/* 82577 Mobile Phy Status Register */
+#define HV_M_STATUS 26
+#define HV_M_STATUS_AUTONEG_COMPLETE 0x1000
+#define HV_M_STATUS_SPEED_MASK 0x0300
+#define HV_M_STATUS_SPEED_1000 0x0200
+#define HV_M_STATUS_LINK_UP 0x0040
+
+#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK 0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
+
+#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */
+
+#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000
+
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX 0x0800
+#define IGP01E1000_PSSR_SPEED_MASK 0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM 4
+#define IGP02E1000_PHY_AGC_A 0x11B1
+#define IGP02E1000_PHY_AGC_B 0x12B1
+#define IGP02E1000_PHY_AGC_C 0x14B1
+#define IGP02E1000_PHY_AGC_D 0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course=15:13, Fine=12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK 0x7F
+#define IGP02E1000_AGC_RANGE 15
+
+#define E1000_CABLE_LENGTH_UNDEFINED 0xFF
+
+#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16
+#define E1000_KMRNCTRLSTA_REN 0x00200000
+#define E1000_KMRNCTRLSTA_CTRL_OFFSET 0x1 /* Kumeran Control */
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */
+#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */
+#define E1000_KMRNCTRLSTA_IBIST_DISABLE 0x0200 /* Kumeran IBIST Disable */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */
+#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7
+#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002 /* enable K1 */
+#define E1000_KMRNCTRLSTA_HD_CTRL 0x10 /* Kumeran HD Control */
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
+#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Ctrl */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Ctrl */
+#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED 0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010
+#define IFE_PSC_FORCE_POLARITY 0x0020
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE 0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto, 0=disable */
+
+#endif
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
new file mode 100644
index 000000000000..b477fa53ec94
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -0,0 +1,277 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2013 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* PTP 1588 Hardware Clock (PHC)
+ * Derived from PTP Hardware Clock driver for Intel 82576 and 82580 (igb)
+ * Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com>
+ */
+
+#include "e1000.h"
+
+/**
+ * e1000e_phc_adjfreq - adjust the frequency of the hardware clock
+ * @ptp: ptp clock structure
+ * @delta: Desired frequency change in parts per billion
+ *
+ * Adjust the frequency of the PHC cycle counter by the indicated delta from
+ * the base frequency.
+ **/
+static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
+{
+ struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+ ptp_clock_info);
+ struct e1000_hw *hw = &adapter->hw;
+ bool neg_adj = false;
+ u64 adjustment;
+ u32 timinca, incvalue;
+ s32 ret_val;
+
+ if ((delta > ptp->max_adj) || (delta <= -1000000000))
+ return -EINVAL;
+
+ if (delta < 0) {
+ neg_adj = true;
+ delta = -delta;
+ }
+
+ /* Get the System Time Register SYSTIM base frequency */
+ ret_val = e1000e_get_base_timinca(adapter, &timinca);
+ if (ret_val)
+ return ret_val;
+
+ incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK;
+
+ adjustment = incvalue;
+ adjustment *= delta;
+ adjustment = div_u64(adjustment, 1000000000);
+
+ incvalue = neg_adj ? (incvalue - adjustment) : (incvalue + adjustment);
+
+ timinca &= ~E1000_TIMINCA_INCVALUE_MASK;
+ timinca |= incvalue;
+
+ ew32(TIMINCA, timinca);
+
+ return 0;
+}
+
+/**
+ * e1000e_phc_adjtime - Shift the time of the hardware clock
+ * @ptp: ptp clock structure
+ * @delta: Desired change in nanoseconds
+ *
+ * Adjust the timer by resetting the timecounter structure.
+ **/
+static int e1000e_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+ ptp_clock_info);
+ unsigned long flags;
+ s64 now;
+
+ spin_lock_irqsave(&adapter->systim_lock, flags);
+ now = timecounter_read(&adapter->tc);
+ now += delta;
+ timecounter_init(&adapter->tc, &adapter->cc, now);
+ spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+ return 0;
+}
+
+/**
+ * e1000e_phc_gettime - Reads the current time from the hardware clock
+ * @ptp: ptp clock structure
+ * @ts: timespec structure to hold the current time value
+ *
+ * Read the timecounter and return the correct value in ns after converting
+ * it into a struct timespec.
+ **/
+static int e1000e_phc_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+ struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+ ptp_clock_info);
+ unsigned long flags;
+ u32 remainder;
+ u64 ns;
+
+ spin_lock_irqsave(&adapter->systim_lock, flags);
+ ns = timecounter_read(&adapter->tc);
+ spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+ ts->tv_sec = div_u64_rem(ns, NSEC_PER_SEC, &remainder);
+ ts->tv_nsec = remainder;
+
+ return 0;
+}
+
+/**
+ * e1000e_phc_settime - Set the current time on the hardware clock
+ * @ptp: ptp clock structure
+ * @ts: timespec containing the new time for the cycle counter
+ *
+ * Reset the timecounter to use a new base value instead of the kernel
+ * wall timer value.
+ **/
+static int e1000e_phc_settime(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
+{
+ struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
+ ptp_clock_info);
+ unsigned long flags;
+ u64 ns;
+
+ ns = ts->tv_sec * NSEC_PER_SEC;
+ ns += ts->tv_nsec;
+
+ /* reset the timecounter */
+ spin_lock_irqsave(&adapter->systim_lock, flags);
+ timecounter_init(&adapter->tc, &adapter->cc, ns);
+ spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
+ return 0;
+}
+
+/**
+ * e1000e_phc_enable - enable or disable an ancillary feature
+ * @ptp: ptp clock structure
+ * @request: Desired resource to enable or disable
+ * @on: Caller passes one to enable or zero to disable
+ *
+ * Enable (or disable) ancillary features of the PHC subsystem.
+ * Currently, no ancillary features are supported.
+ **/
+static int e1000e_phc_enable(struct ptp_clock_info __always_unused *ptp,
+ struct ptp_clock_request __always_unused *request,
+ int __always_unused on)
+{
+ return -EOPNOTSUPP;
+}
+
+static void e1000e_systim_overflow_work(struct work_struct *work)
+{
+ struct e1000_adapter *adapter = container_of(work, struct e1000_adapter,
+ systim_overflow_work.work);
+ struct e1000_hw *hw = &adapter->hw;
+ struct timespec ts;
+
+ adapter->ptp_clock_info.gettime(&adapter->ptp_clock_info, &ts);
+
+ e_dbg("SYSTIM overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec);
+
+ schedule_delayed_work(&adapter->systim_overflow_work,
+ E1000_SYSTIM_OVERFLOW_PERIOD);
+}
+
+static const struct ptp_clock_info e1000e_ptp_clock_info = {
+ .owner = THIS_MODULE,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .pps = 0,
+ .adjfreq = e1000e_phc_adjfreq,
+ .adjtime = e1000e_phc_adjtime,
+ .gettime = e1000e_phc_gettime,
+ .settime = e1000e_phc_settime,
+ .enable = e1000e_phc_enable,
+};
+
+/**
+ * e1000e_ptp_init - initialize PTP for devices which support it
+ * @adapter: board private structure
+ *
+ * This function performs the required steps for enabling PTP support.
+ * If PTP support has already been loaded it simply calls the cyclecounter
+ * init routine and exits.
+ **/
+void e1000e_ptp_init(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ adapter->ptp_clock = NULL;
+
+ if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+ return;
+
+ adapter->ptp_clock_info = e1000e_ptp_clock_info;
+
+ snprintf(adapter->ptp_clock_info.name,
+ sizeof(adapter->ptp_clock_info.name), "%pm",
+ adapter->netdev->perm_addr);
+
+ switch (hw->mac.type) {
+ case e1000_pch2lan:
+ case e1000_pch_lpt:
+ if ((hw->mac.type != e1000_pch_lpt) ||
+ (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
+ adapter->ptp_clock_info.max_adj = 24000000 - 1;
+ break;
+ }
+ /* fall-through */
+ case e1000_82574:
+ case e1000_82583:
+ adapter->ptp_clock_info.max_adj = 600000000 - 1;
+ break;
+ default:
+ break;
+ }
+
+ INIT_DELAYED_WORK(&adapter->systim_overflow_work,
+ e1000e_systim_overflow_work);
+
+ schedule_delayed_work(&adapter->systim_overflow_work,
+ E1000_SYSTIM_OVERFLOW_PERIOD);
+
+ adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info,
+ &adapter->pdev->dev);
+ if (IS_ERR(adapter->ptp_clock)) {
+ adapter->ptp_clock = NULL;
+ e_err("ptp_clock_register failed\n");
+ } else {
+ e_info("registered PHC clock\n");
+ }
+}
+
+/**
+ * e1000e_ptp_remove - disable PTP device and stop the overflow check
+ * @adapter: board private structure
+ *
+ * Stop the PTP support, and cancel the delayed work.
+ **/
+void e1000e_ptp_remove(struct e1000_adapter *adapter)
+{
+ if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
+ return;
+
+ cancel_delayed_work_sync(&adapter->systim_overflow_work);
+
+ if (adapter->ptp_clock) {
+ ptp_clock_unregister(adapter->ptp_clock);
+ adapter->ptp_clock = NULL;
+ e_info("removed PHC\n");
+ }
+}
diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h
new file mode 100644
index 000000000000..794fe1497666
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000e/regs.h
@@ -0,0 +1,252 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2013 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000E_REGS_H_
+#define _E1000E_REGS_H_
+
+#define E1000_CTRL 0x00000 /* Device Control - RW */
+#define E1000_STATUS 0x00008 /* Device Status - RO */
+#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
+#define E1000_EERD 0x00014 /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
+#define E1000_FLA 0x0001C /* Flash Access - RW */
+#define E1000_MDIC 0x00020 /* MDI Control - RW */
+#define E1000_SCTL 0x00024 /* SerDes Control - RW */
+#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
+#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
+#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */
+#define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */
+#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */
+#define E1000_FEXTNVM7 0x000E4 /* Future Extended NVM 7 - RW */
+#define E1000_FCT 0x00030 /* Flow Control Type - RW */
+#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
+#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
+#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
+#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
+#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */
+#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
+#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
+#define E1000_IVAR 0x000E4 /* Interrupt Vector Allocation Register - RW */
+#define E1000_SVCR 0x000F0
+#define E1000_SVT 0x000F4
+#define E1000_LPIC 0x000FC /* Low Power IDLE control */
+#define E1000_RCTL 0x00100 /* Rx Control - RW */
+#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW 0x00178 /* Tx Configuration Word - RW */
+#define E1000_RXCW 0x00180 /* Rx Configuration Word - RO */
+#define E1000_PBA_ECC 0x01100 /* PBA ECC Register */
+#define E1000_TCTL 0x00400 /* Tx Control - RW */
+#define E1000_TCTL_EXT 0x00404 /* Extended Tx Control - RW */
+#define E1000_TIPG 0x00410 /* Tx Inter-packet gap -RW */
+#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
+#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
+#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
+#define E1000_POEMB E1000_PHY_CTRL /* PHY OEM Bits */
+#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
+#define E1000_PBS 0x01008 /* Packet Buffer Size */
+#define E1000_PBECCSTS 0x0100C /* Packet Buffer ECC Status - RW */
+#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
+#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
+#define E1000_FLOP 0x0103C /* FLASH Opcode Register */
+#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */
+#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */
+#define E1000_RDFH 0x02410 /* Rx Data FIFO Head - RW */
+#define E1000_RDFT 0x02418 /* Rx Data FIFO Tail - RW */
+#define E1000_RDFHS 0x02420 /* Rx Data FIFO Head Saved - RW */
+#define E1000_RDFTS 0x02428 /* Rx Data FIFO Tail Saved - RW */
+#define E1000_RDFPC 0x02430 /* Rx Data FIFO Packet Count - RW */
+/* Split and Replication Rx Control - RW */
+#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */
+#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */
+/* Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
+ (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
+ (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
+ (0x0C008 + ((_n) * 0x40)))
+#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
+ (0x0C010 + ((_n) * 0x40)))
+#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
+ (0x0C018 + ((_n) * 0x40)))
+#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
+ (0x0C028 + ((_n) * 0x40)))
+#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
+ (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
+ (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
+ (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
+ (0x0E010 + ((_n) * 0x40)))
+#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
+ (0x0E018 + ((_n) * 0x40)))
+#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
+ (0x0E028 + ((_n) * 0x40)))
+#define E1000_TARC(_n) (0x03840 + ((_n) * 0x100))
+#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */
+#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
+ (0x054E0 + ((_i - 16) * 8)))
+#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
+ (0x054E4 + ((_i - 16) * 8)))
+#define E1000_SHRAL(_i) (0x05438 + ((_i) * 8))
+#define E1000_SHRAH(_i) (0x0543C + ((_i) * 8))
+#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */
+#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */
+#define E1000_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */
+#define E1000_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */
+#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
+#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */
+#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */
+#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */
+#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */
+#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */
+#define E1000_COLC 0x04028 /* Collision Count - R/clr */
+#define E1000_DC 0x04030 /* Defer Count - R/clr */
+#define E1000_TNCRS 0x04034 /* Tx-No CRS - R/clr */
+#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC 0x04048 /* XON Rx Count - R/clr */
+#define E1000_XONTXC 0x0404C /* XON Tx Count - R/clr */
+#define E1000_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */
+#define E1000_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */
+#define E1000_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */
+#define E1000_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */
+#define E1000_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */
+#define E1000_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */
+#define E1000_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */
+#define E1000_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */
+#define E1000_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */
+#define E1000_GPRC 0x04074 /* Good Packets Rx Count - R/clr */
+#define E1000_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */
+#define E1000_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */
+#define E1000_GPTC 0x04080 /* Good Packets Tx Count - R/clr */
+#define E1000_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */
+#define E1000_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */
+#define E1000_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */
+#define E1000_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */
+#define E1000_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */
+#define E1000_RUC 0x040A4 /* Rx Undersize Count - R/clr */
+#define E1000_RFC 0x040A8 /* Rx Fragment Count - R/clr */
+#define E1000_ROC 0x040AC /* Rx Oversize Count - R/clr */
+#define E1000_RJC 0x040B0 /* Rx Jabber Count - R/clr */
+#define E1000_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */
+#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */
+#define E1000_TORL 0x040C0 /* Total Octets Rx Low - R/clr */
+#define E1000_TORH 0x040C4 /* Total Octets Rx High - R/clr */
+#define E1000_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */
+#define E1000_TOTH 0x040CC /* Total Octets Tx High - R/clr */
+#define E1000_TPR 0x040D0 /* Total Packets Rx - R/clr */
+#define E1000_TPT 0x040D4 /* Total Packets Tx - R/clr */
+#define E1000_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */
+#define E1000_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */
+#define E1000_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */
+#define E1000_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */
+#define E1000_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */
+#define E1000_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */
+#define E1000_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */
+#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */
+#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */
+#define E1000_IAC 0x04100 /* Interrupt Assertion Count */
+#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Pkt Timer Expire Count */
+#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Abs Timer Expire Count */
+#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */
+#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Abs Timer Expire Count */
+#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */
+#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Desc Min Thresh Count */
+#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */
+#define E1000_CRC_OFFSET 0x05F50 /* CRC Offset register */
+
+#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */
+#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */
+#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */
+#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */
+#define E1000_RXCSUM 0x05000 /* Rx Checksum Control - RW */
+#define E1000_RFCTL 0x05008 /* Receive Filter Control */
+#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
+#define E1000_RA 0x05400 /* Receive Address - RW Array */
+#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */
+#define E1000_WUC 0x05800 /* Wakeup Control - RW */
+#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */
+#define E1000_WUS 0x05810 /* Wakeup Status - RO */
+#define E1000_MANC 0x05820 /* Management Control - RW */
+#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF 0x08800 /* Host Interface */
+
+#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */
+/* Management Decision Filters */
+#define E1000_MDEF(_n) (0x05890 + (4 * (_n)))
+#define E1000_SW_FW_SYNC 0x05B5C /* SW-FW Synchronization - RW */
+#define E1000_GCR 0x05B00 /* PCI-Ex Control */
+#define E1000_GCR2 0x05B64 /* PCI-Ex Control #2 */
+#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM 0x05B50 /* SW Semaphore */
+#define E1000_FWSM 0x05B54 /* FW Semaphore */
+/* Driver-only SW semaphore (not used by BOOT agents) */
+#define E1000_SWSM2 0x05B58
+#define E1000_FFLT_DBG 0x05F04 /* Debug Register */
+#define E1000_HICR 0x08F00 /* Host Interface Control */
+
+/* RSS registers */
+#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */
+#define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
+#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
+#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
+#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
+#define E1000_RXSTMPL 0x0B624 /* Rx timestamp Low - RO */
+#define E1000_RXSTMPH 0x0B628 /* Rx timestamp High - RO */
+#define E1000_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
+#define E1000_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
+#define E1000_SYSTIML 0x0B600 /* System time register Low - RO */
+#define E1000_SYSTIMH 0x0B604 /* System time register High - RO */
+#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */
+#define E1000_RXMTRL 0x0B634 /* Time sync Rx EtherType and Msg Type - RW */
+#define E1000_RXUDP 0x0B638 /* Time Sync Rx UDP Port - RW */
+
+#endif
diff --git a/drivers/net/ethernet/intel/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile
index 624476cfa727..f19700e285bb 100644
--- a/drivers/net/ethernet/intel/igb/Makefile
+++ b/drivers/net/ethernet/intel/igb/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
# Intel 82575 PCI-Express Ethernet Linux driver
-# Copyright(c) 1999 - 2012 Intel Corporation.
+# Copyright(c) 1999 - 2013 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
@@ -34,4 +34,4 @@ obj-$(CONFIG_IGB) += igb.o
igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \
- e1000_i210.o igb_ptp.o
+ e1000_i210.o igb_ptp.o igb_hwmon.o
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index fdaaf2709d0a..84e7e0909def 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -33,6 +33,7 @@
#include <linux/types.h>
#include <linux/if_ether.h>
+#include <linux/i2c.h>
#include "e1000_mac.h"
#include "e1000_82575.h"
@@ -110,184 +111,168 @@ static bool igb_sgmii_uses_mdio_82575(struct e1000_hw *hw)
return ext_mdio;
}
-static s32 igb_get_invariants_82575(struct e1000_hw *hw)
+/**
+ * igb_init_phy_params_82575 - Init PHY func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- struct e1000_nvm_info *nvm = &hw->nvm;
- struct e1000_mac_info *mac = &hw->mac;
- struct e1000_dev_spec_82575 * dev_spec = &hw->dev_spec._82575;
- u32 eecd;
- s32 ret_val;
- u16 size;
- u32 ctrl_ext = 0;
+ s32 ret_val = 0;
+ u32 ctrl_ext;
- switch (hw->device_id) {
- case E1000_DEV_ID_82575EB_COPPER:
- case E1000_DEV_ID_82575EB_FIBER_SERDES:
- case E1000_DEV_ID_82575GB_QUAD_COPPER:
- mac->type = e1000_82575;
- break;
- case E1000_DEV_ID_82576:
- case E1000_DEV_ID_82576_NS:
- case E1000_DEV_ID_82576_NS_SERDES:
- case E1000_DEV_ID_82576_FIBER:
- case E1000_DEV_ID_82576_SERDES:
- case E1000_DEV_ID_82576_QUAD_COPPER:
- case E1000_DEV_ID_82576_QUAD_COPPER_ET2:
- case E1000_DEV_ID_82576_SERDES_QUAD:
- mac->type = e1000_82576;
- break;
- case E1000_DEV_ID_82580_COPPER:
- case E1000_DEV_ID_82580_FIBER:
- case E1000_DEV_ID_82580_QUAD_FIBER:
- case E1000_DEV_ID_82580_SERDES:
- case E1000_DEV_ID_82580_SGMII:
- case E1000_DEV_ID_82580_COPPER_DUAL:
- case E1000_DEV_ID_DH89XXCC_SGMII:
- case E1000_DEV_ID_DH89XXCC_SERDES:
- case E1000_DEV_ID_DH89XXCC_BACKPLANE:
- case E1000_DEV_ID_DH89XXCC_SFP:
- mac->type = e1000_82580;
- break;
- case E1000_DEV_ID_I350_COPPER:
- case E1000_DEV_ID_I350_FIBER:
- case E1000_DEV_ID_I350_SERDES:
- case E1000_DEV_ID_I350_SGMII:
- mac->type = e1000_i350;
- break;
- case E1000_DEV_ID_I210_COPPER:
- case E1000_DEV_ID_I210_COPPER_OEM1:
- case E1000_DEV_ID_I210_COPPER_IT:
- case E1000_DEV_ID_I210_FIBER:
- case E1000_DEV_ID_I210_SERDES:
- case E1000_DEV_ID_I210_SGMII:
- mac->type = e1000_i210;
- break;
- case E1000_DEV_ID_I211_COPPER:
- mac->type = e1000_i211;
- break;
- default:
- return -E1000_ERR_MAC_INIT;
- break;
+ if (hw->phy.media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ goto out;
}
- /* Set media type */
- /*
- * The 82575 uses bits 22:23 for link mode. The mode can be changed
- * based on the EEPROM. We cannot rely upon device ID. There
- * is no distinguishable difference between fiber and internal
- * SerDes mode on the 82575. There can be an external PHY attached
- * on the SGMII interface. For this, we'll set sgmii_active to true.
- */
- phy->media_type = e1000_media_type_copper;
- dev_spec->sgmii_active = false;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
ctrl_ext = rd32(E1000_CTRL_EXT);
- switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
- case E1000_CTRL_EXT_LINK_MODE_SGMII:
- dev_spec->sgmii_active = true;
- break;
- case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
- case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
- hw->phy.media_type = e1000_media_type_internal_serdes;
- break;
- default:
- break;
+
+ if (igb_sgmii_active_82575(hw)) {
+ phy->ops.reset = igb_phy_hw_reset_sgmii_82575;
+ ctrl_ext |= E1000_CTRL_I2C_ENA;
+ } else {
+ phy->ops.reset = igb_phy_hw_reset;
+ ctrl_ext &= ~E1000_CTRL_I2C_ENA;
}
- /* Set mta register count */
- mac->mta_reg_count = 128;
- /* Set rar entry count */
- switch (mac->type) {
- case e1000_82576:
- mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
+ wr32(E1000_CTRL_EXT, ctrl_ext);
+ igb_reset_mdicnfg_82580(hw);
+
+ if (igb_sgmii_active_82575(hw) && !igb_sgmii_uses_mdio_82575(hw)) {
+ phy->ops.read_reg = igb_read_phy_reg_sgmii_82575;
+ phy->ops.write_reg = igb_write_phy_reg_sgmii_82575;
+ } else {
+ switch (hw->mac.type) {
+ case e1000_82580:
+ case e1000_i350:
+ phy->ops.read_reg = igb_read_phy_reg_82580;
+ phy->ops.write_reg = igb_write_phy_reg_82580;
+ break;
+ case e1000_i210:
+ case e1000_i211:
+ phy->ops.read_reg = igb_read_phy_reg_gs40g;
+ phy->ops.write_reg = igb_write_phy_reg_gs40g;
+ break;
+ default:
+ phy->ops.read_reg = igb_read_phy_reg_igp;
+ phy->ops.write_reg = igb_write_phy_reg_igp;
+ }
+ }
+
+ /* set lan id */
+ hw->bus.func = (rd32(E1000_STATUS) & E1000_STATUS_FUNC_MASK) >>
+ E1000_STATUS_FUNC_SHIFT;
+
+ /* Set phy->phy_addr and phy->id. */
+ ret_val = igb_get_phy_id_82575(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Verify phy id and set remaining function pointers */
+ switch (phy->id) {
+ case I347AT4_E_PHY_ID:
+ case M88E1112_E_PHY_ID:
+ case M88E1111_I_PHY_ID:
+ phy->type = e1000_phy_m88;
+ phy->ops.get_phy_info = igb_get_phy_info_m88;
+ if (phy->id == I347AT4_E_PHY_ID ||
+ phy->id == M88E1112_E_PHY_ID)
+ phy->ops.get_cable_length =
+ igb_get_cable_length_m88_gen2;
+ else
+ phy->ops.get_cable_length = igb_get_cable_length_m88;
+ phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
break;
- case e1000_82580:
- mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
+ case IGP03E1000_E_PHY_ID:
+ phy->type = e1000_phy_igp_3;
+ phy->ops.get_phy_info = igb_get_phy_info_igp;
+ phy->ops.get_cable_length = igb_get_cable_length_igp_2;
+ phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_igp;
+ phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82575;
+ phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state;
break;
- case e1000_i350:
- mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
+ case I82580_I_PHY_ID:
+ case I350_I_PHY_ID:
+ phy->type = e1000_phy_82580;
+ phy->ops.force_speed_duplex =
+ igb_phy_force_speed_duplex_82580;
+ phy->ops.get_cable_length = igb_get_cable_length_82580;
+ phy->ops.get_phy_info = igb_get_phy_info_82580;
+ phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580;
+ phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
break;
- default:
- mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
+ case I210_I_PHY_ID:
+ phy->type = e1000_phy_i210;
+ phy->ops.check_polarity = igb_check_polarity_m88;
+ phy->ops.get_phy_info = igb_get_phy_info_m88;
+ phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
+ phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580;
+ phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
+ phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
break;
+ default:
+ ret_val = -E1000_ERR_PHY;
+ goto out;
}
- /* reset */
- if (mac->type >= e1000_82580)
- mac->ops.reset_hw = igb_reset_hw_82580;
- else
- mac->ops.reset_hw = igb_reset_hw_82575;
- if (mac->type >= e1000_i210) {
- mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_i210;
- mac->ops.release_swfw_sync = igb_release_swfw_sync_i210;
- } else {
- mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_82575;
- mac->ops.release_swfw_sync = igb_release_swfw_sync_82575;
- }
+out:
+ return ret_val;
+}
- /* Set if part includes ASF firmware */
- mac->asf_firmware_present = true;
- /* Set if manageability features are enabled. */
- mac->arc_subsystem_valid =
- (rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK)
- ? true : false;
- /* enable EEE on i350 parts and later parts */
- if (mac->type >= e1000_i350)
- dev_spec->eee_disable = false;
- else
- dev_spec->eee_disable = true;
- /* physical interface link setup */
- mac->ops.setup_physical_interface =
- (hw->phy.media_type == e1000_media_type_copper)
- ? igb_setup_copper_link_82575
- : igb_setup_serdes_link_82575;
+/**
+ * igb_init_nvm_params_82575 - Init NVM func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+s32 igb_init_nvm_params_82575(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = rd32(E1000_EECD);
+ u16 size;
- /* NVM initialization */
- eecd = rd32(E1000_EECD);
size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
E1000_EECD_SIZE_EX_SHIFT);
-
- /*
- * Added to a constant, "size" becomes the left-shift value
+ /* Added to a constant, "size" becomes the left-shift value
* for setting word_size.
*/
size += NVM_WORD_SIZE_BASE_SHIFT;
- /*
- * Check for invalid size
+ /* Just in case size is out of range, cap it to the largest
+ * EEPROM size supported
*/
- if ((hw->mac.type == e1000_82576) && (size > 15)) {
- pr_notice("The NVM size is not valid, defaulting to 32K\n");
+ if (size > 15)
size = 15;
- }
nvm->word_size = 1 << size;
if (hw->mac.type < e1000_i210) {
- nvm->opcode_bits = 8;
- nvm->delay_usec = 1;
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+
switch (nvm->override) {
case e1000_nvm_override_spi_large:
- nvm->page_size = 32;
+ nvm->page_size = 32;
nvm->address_bits = 16;
break;
case e1000_nvm_override_spi_small:
- nvm->page_size = 8;
+ nvm->page_size = 8;
nvm->address_bits = 8;
break;
default:
- nvm->page_size = eecd
- & E1000_EECD_ADDR_BITS ? 32 : 8;
- nvm->address_bits = eecd
- & E1000_EECD_ADDR_BITS ? 16 : 8;
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ?
+ 16 : 8;
break;
}
if (nvm->word_size == (1 << 15))
nvm->page_size = 128;
nvm->type = e1000_nvm_eeprom_spi;
- } else
+ } else {
nvm->type = e1000_nvm_flash_hw;
+ }
/* NVM Function Pointers */
switch (hw->mac.type) {
@@ -344,118 +329,176 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
break;
}
- /* if part supports SR-IOV then initialize mailbox parameters */
+ return 0;
+}
+
+/**
+ * igb_init_mac_params_82575 - Init MAC func ptrs.
+ * @hw: pointer to the HW structure
+ **/
+static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+ /* Set rar entry count */
switch (mac->type) {
case e1000_82576:
+ mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
+ break;
+ case e1000_82580:
+ mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
+ break;
case e1000_i350:
- igb_init_mbx_params_pf(hw);
+ mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
break;
default:
+ mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
break;
}
+ /* reset */
+ if (mac->type >= e1000_82580)
+ mac->ops.reset_hw = igb_reset_hw_82580;
+ else
+ mac->ops.reset_hw = igb_reset_hw_82575;
- /* setup PHY parameters */
- if (phy->media_type != e1000_media_type_copper) {
- phy->type = e1000_phy_none;
- return 0;
- }
-
- phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
- phy->reset_delay_us = 100;
-
- ctrl_ext = rd32(E1000_CTRL_EXT);
+ if (mac->type >= e1000_i210) {
+ mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_i210;
+ mac->ops.release_swfw_sync = igb_release_swfw_sync_i210;
- /* PHY function pointers */
- if (igb_sgmii_active_82575(hw)) {
- phy->ops.reset = igb_phy_hw_reset_sgmii_82575;
- ctrl_ext |= E1000_CTRL_I2C_ENA;
} else {
- phy->ops.reset = igb_phy_hw_reset;
- ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+ mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_82575;
+ mac->ops.release_swfw_sync = igb_release_swfw_sync_82575;
}
- wr32(E1000_CTRL_EXT, ctrl_ext);
- igb_reset_mdicnfg_82580(hw);
-
- if (igb_sgmii_active_82575(hw) && !igb_sgmii_uses_mdio_82575(hw)) {
- phy->ops.read_reg = igb_read_phy_reg_sgmii_82575;
- phy->ops.write_reg = igb_write_phy_reg_sgmii_82575;
- } else if ((hw->mac.type == e1000_82580)
- || (hw->mac.type == e1000_i350)) {
- phy->ops.read_reg = igb_read_phy_reg_82580;
- phy->ops.write_reg = igb_write_phy_reg_82580;
- } else if (hw->phy.type >= e1000_phy_i210) {
- phy->ops.read_reg = igb_read_phy_reg_gs40g;
- phy->ops.write_reg = igb_write_phy_reg_gs40g;
- } else {
- phy->ops.read_reg = igb_read_phy_reg_igp;
- phy->ops.write_reg = igb_write_phy_reg_igp;
- }
+ /* Set if part includes ASF firmware */
+ mac->asf_firmware_present = true;
+ /* Set if manageability features are enabled. */
+ mac->arc_subsystem_valid =
+ (rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK)
+ ? true : false;
+ /* enable EEE on i350 parts and later parts */
+ if (mac->type >= e1000_i350)
+ dev_spec->eee_disable = false;
+ else
+ dev_spec->eee_disable = true;
+ /* physical interface link setup */
+ mac->ops.setup_physical_interface =
+ (hw->phy.media_type == e1000_media_type_copper)
+ ? igb_setup_copper_link_82575
+ : igb_setup_serdes_link_82575;
- /* set lan id */
- hw->bus.func = (rd32(E1000_STATUS) & E1000_STATUS_FUNC_MASK) >>
- E1000_STATUS_FUNC_SHIFT;
+ return 0;
+}
- /* Set phy->phy_addr and phy->id. */
- ret_val = igb_get_phy_id_82575(hw);
- if (ret_val)
- return ret_val;
+static s32 igb_get_invariants_82575(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_dev_spec_82575 * dev_spec = &hw->dev_spec._82575;
+ s32 ret_val;
+ u32 ctrl_ext = 0;
- /* Verify phy id and set remaining function pointers */
- switch (phy->id) {
- case I347AT4_E_PHY_ID:
- case M88E1112_E_PHY_ID:
- case M88E1111_I_PHY_ID:
- phy->type = e1000_phy_m88;
- phy->ops.get_phy_info = igb_get_phy_info_m88;
+ switch (hw->device_id) {
+ case E1000_DEV_ID_82575EB_COPPER:
+ case E1000_DEV_ID_82575EB_FIBER_SERDES:
+ case E1000_DEV_ID_82575GB_QUAD_COPPER:
+ mac->type = e1000_82575;
+ break;
+ case E1000_DEV_ID_82576:
+ case E1000_DEV_ID_82576_NS:
+ case E1000_DEV_ID_82576_NS_SERDES:
+ case E1000_DEV_ID_82576_FIBER:
+ case E1000_DEV_ID_82576_SERDES:
+ case E1000_DEV_ID_82576_QUAD_COPPER:
+ case E1000_DEV_ID_82576_QUAD_COPPER_ET2:
+ case E1000_DEV_ID_82576_SERDES_QUAD:
+ mac->type = e1000_82576;
+ break;
+ case E1000_DEV_ID_82580_COPPER:
+ case E1000_DEV_ID_82580_FIBER:
+ case E1000_DEV_ID_82580_QUAD_FIBER:
+ case E1000_DEV_ID_82580_SERDES:
+ case E1000_DEV_ID_82580_SGMII:
+ case E1000_DEV_ID_82580_COPPER_DUAL:
+ case E1000_DEV_ID_DH89XXCC_SGMII:
+ case E1000_DEV_ID_DH89XXCC_SERDES:
+ case E1000_DEV_ID_DH89XXCC_BACKPLANE:
+ case E1000_DEV_ID_DH89XXCC_SFP:
+ mac->type = e1000_82580;
+ break;
+ case E1000_DEV_ID_I350_COPPER:
+ case E1000_DEV_ID_I350_FIBER:
+ case E1000_DEV_ID_I350_SERDES:
+ case E1000_DEV_ID_I350_SGMII:
+ mac->type = e1000_i350;
+ break;
+ case E1000_DEV_ID_I210_COPPER:
+ case E1000_DEV_ID_I210_COPPER_OEM1:
+ case E1000_DEV_ID_I210_COPPER_IT:
+ case E1000_DEV_ID_I210_FIBER:
+ case E1000_DEV_ID_I210_SERDES:
+ case E1000_DEV_ID_I210_SGMII:
+ mac->type = e1000_i210;
+ break;
+ case E1000_DEV_ID_I211_COPPER:
+ mac->type = e1000_i211;
+ break;
+ default:
+ return -E1000_ERR_MAC_INIT;
+ break;
+ }
- if (phy->id == I347AT4_E_PHY_ID ||
- phy->id == M88E1112_E_PHY_ID)
- phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
- else
- phy->ops.get_cable_length = igb_get_cable_length_m88;
+ /* Set media type */
+ /*
+ * The 82575 uses bits 22:23 for link mode. The mode can be changed
+ * based on the EEPROM. We cannot rely upon device ID. There
+ * is no distinguishable difference between fiber and internal
+ * SerDes mode on the 82575. There can be an external PHY attached
+ * on the SGMII interface. For this, we'll set sgmii_active to true.
+ */
+ hw->phy.media_type = e1000_media_type_copper;
+ dev_spec->sgmii_active = false;
- if (phy->id == I210_I_PHY_ID) {
- phy->ops.get_cable_length =
- igb_get_cable_length_m88_gen2;
- phy->ops.set_d0_lplu_state =
- igb_set_d0_lplu_state_82580;
- phy->ops.set_d3_lplu_state =
- igb_set_d3_lplu_state_82580;
- }
- phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
+ ctrl_ext = rd32(E1000_CTRL_EXT);
+ switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
+ case E1000_CTRL_EXT_LINK_MODE_SGMII:
+ dev_spec->sgmii_active = true;
break;
- case IGP03E1000_E_PHY_ID:
- phy->type = e1000_phy_igp_3;
- phy->ops.get_phy_info = igb_get_phy_info_igp;
- phy->ops.get_cable_length = igb_get_cable_length_igp_2;
- phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_igp;
- phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82575;
- phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state;
+ case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
+ case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
+ hw->phy.media_type = e1000_media_type_internal_serdes;
break;
- case I82580_I_PHY_ID:
- case I350_I_PHY_ID:
- phy->type = e1000_phy_82580;
- phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_82580;
- phy->ops.get_cable_length = igb_get_cable_length_82580;
- phy->ops.get_phy_info = igb_get_phy_info_82580;
- phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580;
- phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
+ default:
break;
- case I210_I_PHY_ID:
- phy->type = e1000_phy_i210;
- phy->ops.get_phy_info = igb_get_phy_info_m88;
- phy->ops.check_polarity = igb_check_polarity_m88;
- phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
- phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580;
- phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
- phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
+ }
+
+ /* mac initialization and operations */
+ ret_val = igb_init_mac_params_82575(hw);
+ if (ret_val)
+ goto out;
+
+ /* NVM initialization */
+ ret_val = igb_init_nvm_params_82575(hw);
+ if (ret_val)
+ goto out;
+
+ /* if part supports SR-IOV then initialize mailbox parameters */
+ switch (mac->type) {
+ case e1000_82576:
+ case e1000_i350:
+ igb_init_mbx_params_pf(hw);
break;
default:
- return -E1000_ERR_PHY;
+ break;
}
- return 0;
+ /* setup PHY parameters */
+ ret_val = igb_init_phy_params_82575(hw);
+
+out:
+ return ret_val;
}
/**
@@ -2302,18 +2345,157 @@ out:
return ret_val;
}
+static const u8 e1000_emc_temp_data[4] = {
+ E1000_EMC_INTERNAL_DATA,
+ E1000_EMC_DIODE1_DATA,
+ E1000_EMC_DIODE2_DATA,
+ E1000_EMC_DIODE3_DATA
+};
+static const u8 e1000_emc_therm_limit[4] = {
+ E1000_EMC_INTERNAL_THERM_LIMIT,
+ E1000_EMC_DIODE1_THERM_LIMIT,
+ E1000_EMC_DIODE2_THERM_LIMIT,
+ E1000_EMC_DIODE3_THERM_LIMIT
+};
+
+/* igb_get_thermal_sensor_data_generic - Gathers thermal sensor data
+ * @hw: pointer to hardware structure
+ *
+ * Updates the temperatures in mac.thermal_sensor_data
+ */
+s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
+{
+ s32 status = E1000_SUCCESS;
+ u16 ets_offset;
+ u16 ets_cfg;
+ u16 ets_sensor;
+ u8 num_sensors;
+ u8 sensor_index;
+ u8 sensor_location;
+ u8 i;
+ struct e1000_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
+
+ if ((hw->mac.type != e1000_i350) || (hw->bus.func != 0))
+ return E1000_NOT_IMPLEMENTED;
+
+ data->sensor[0].temp = (rd32(E1000_THMJT) & 0xFF);
+
+ /* Return the internal sensor only if ETS is unsupported */
+ hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_offset);
+ if ((ets_offset == 0x0000) || (ets_offset == 0xFFFF))
+ return status;
+
+ hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg);
+ if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT)
+ != NVM_ETS_TYPE_EMC)
+ return E1000_NOT_IMPLEMENTED;
+
+ num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK);
+ if (num_sensors > E1000_MAX_SENSORS)
+ num_sensors = E1000_MAX_SENSORS;
+
+ for (i = 1; i < num_sensors; i++) {
+ hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor);
+ sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >>
+ NVM_ETS_DATA_INDEX_SHIFT);
+ sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >>
+ NVM_ETS_DATA_LOC_SHIFT);
+
+ if (sensor_location != 0)
+ hw->phy.ops.read_i2c_byte(hw,
+ e1000_emc_temp_data[sensor_index],
+ E1000_I2C_THERMAL_SENSOR_ADDR,
+ &data->sensor[i].temp);
+ }
+ return status;
+}
+
+/* igb_init_thermal_sensor_thresh_generic - Sets thermal sensor thresholds
+ * @hw: pointer to hardware structure
+ *
+ * Sets the thermal sensor thresholds according to the NVM map
+ * and save off the threshold and location values into mac.thermal_sensor_data
+ */
+s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
+{
+ s32 status = E1000_SUCCESS;
+ u16 ets_offset;
+ u16 ets_cfg;
+ u16 ets_sensor;
+ u8 low_thresh_delta;
+ u8 num_sensors;
+ u8 sensor_index;
+ u8 sensor_location;
+ u8 therm_limit;
+ u8 i;
+ struct e1000_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
+
+ if ((hw->mac.type != e1000_i350) || (hw->bus.func != 0))
+ return E1000_NOT_IMPLEMENTED;
+
+ memset(data, 0, sizeof(struct e1000_thermal_sensor_data));
+
+ data->sensor[0].location = 0x1;
+ data->sensor[0].caution_thresh =
+ (rd32(E1000_THHIGHTC) & 0xFF);
+ data->sensor[0].max_op_thresh =
+ (rd32(E1000_THLOWTC) & 0xFF);
+
+ /* Return the internal sensor only if ETS is unsupported */
+ hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_offset);
+ if ((ets_offset == 0x0000) || (ets_offset == 0xFFFF))
+ return status;
+
+ hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg);
+ if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT)
+ != NVM_ETS_TYPE_EMC)
+ return E1000_NOT_IMPLEMENTED;
+
+ low_thresh_delta = ((ets_cfg & NVM_ETS_LTHRES_DELTA_MASK) >>
+ NVM_ETS_LTHRES_DELTA_SHIFT);
+ num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK);
+
+ for (i = 1; i <= num_sensors; i++) {
+ hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor);
+ sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >>
+ NVM_ETS_DATA_INDEX_SHIFT);
+ sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >>
+ NVM_ETS_DATA_LOC_SHIFT);
+ therm_limit = ets_sensor & NVM_ETS_DATA_HTHRESH_MASK;
+
+ hw->phy.ops.write_i2c_byte(hw,
+ e1000_emc_therm_limit[sensor_index],
+ E1000_I2C_THERMAL_SENSOR_ADDR,
+ therm_limit);
+
+ if ((i < E1000_MAX_SENSORS) && (sensor_location != 0)) {
+ data->sensor[i].location = sensor_location;
+ data->sensor[i].caution_thresh = therm_limit;
+ data->sensor[i].max_op_thresh = therm_limit -
+ low_thresh_delta;
+ }
+ }
+ return status;
+}
+
static struct e1000_mac_operations e1000_mac_ops_82575 = {
.init_hw = igb_init_hw_82575,
.check_for_link = igb_check_for_link_82575,
.rar_set = igb_rar_set,
.read_mac_addr = igb_read_mac_addr_82575,
.get_speed_and_duplex = igb_get_speed_and_duplex_copper,
+#ifdef CONFIG_IGB_HWMON
+ .get_thermal_sensor_data = igb_get_thermal_sensor_data_generic,
+ .init_thermal_sensor_thresh = igb_init_thermal_sensor_thresh_generic,
+#endif
};
static struct e1000_phy_operations e1000_phy_ops_82575 = {
.acquire = igb_acquire_phy_82575,
.get_cfg_done = igb_get_cfg_done_82575,
.release = igb_release_phy_82575,
+ .write_i2c_byte = igb_write_i2c_byte,
+ .read_i2c_byte = igb_read_i2c_byte,
};
static struct e1000_nvm_operations e1000_nvm_ops_82575 = {
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
index 44b76b3b6816..73ab41f0e032 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.h
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -32,6 +32,10 @@ extern void igb_shutdown_serdes_link_82575(struct e1000_hw *hw);
extern void igb_power_up_serdes_link_82575(struct e1000_hw *hw);
extern void igb_power_down_phy_copper_82575(struct e1000_hw *hw);
extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
+extern s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 *data);
+extern s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data);
#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
(ID_LED_DEF1_DEF2 << 8) | \
@@ -260,5 +264,16 @@ void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool);
void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
u16 igb_rxpbs_adjust_82580(u32 data);
s32 igb_set_eee_i350(struct e1000_hw *);
-
+s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *);
+s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw);
+
+#define E1000_I2C_THERMAL_SENSOR_ADDR 0xF8
+#define E1000_EMC_INTERNAL_DATA 0x00
+#define E1000_EMC_INTERNAL_THERM_LIMIT 0x20
+#define E1000_EMC_DIODE1_DATA 0x01
+#define E1000_EMC_DIODE1_THERM_LIMIT 0x19
+#define E1000_EMC_DIODE2_DATA 0x23
+#define E1000_EMC_DIODE2_THERM_LIMIT 0x1A
+#define E1000_EMC_DIODE3_DATA 0x2A
+#define E1000_EMC_DIODE3_THERM_LIMIT 0x30
#endif
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index 45dce06eff26..7e13337d3b9d 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -470,6 +470,7 @@
#define E1000_ERR_NO_SPACE 17
#define E1000_ERR_NVM_PBA_SECTION 18
#define E1000_ERR_INVM_VALUE_NOT_FOUND 19
+#define E1000_ERR_I2C 20
/* Loop limit on how long we wait for auto-negotiation to complete */
#define COPPER_LINK_UP_LIMIT 10
@@ -674,6 +675,18 @@
#define NVM_COMB_VER_SHFT 8
#define NVM_VER_INVALID 0xFFFF
#define NVM_ETRACK_SHIFT 16
+#define NVM_ETS_CFG 0x003E
+#define NVM_ETS_LTHRES_DELTA_MASK 0x07C0
+#define NVM_ETS_LTHRES_DELTA_SHIFT 6
+#define NVM_ETS_TYPE_MASK 0x0038
+#define NVM_ETS_TYPE_SHIFT 3
+#define NVM_ETS_TYPE_EMC 0x000
+#define NVM_ETS_NUM_SENSORS_MASK 0x0007
+#define NVM_ETS_DATA_LOC_MASK 0x3C00
+#define NVM_ETS_DATA_LOC_SHIFT 10
+#define NVM_ETS_DATA_INDEX_MASK 0x0300
+#define NVM_ETS_DATA_INDEX_SHIFT 8
+#define NVM_ETS_DATA_HTHRESH_MASK 0x00FF
#define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */
#define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */
diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h
index c2a51dcda550..0d5cf9c63d0d 100644
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -325,6 +325,10 @@ struct e1000_mac_operations {
s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *);
s32 (*acquire_swfw_sync)(struct e1000_hw *, u16);
void (*release_swfw_sync)(struct e1000_hw *, u16);
+#ifdef CONFIG_IGB_HWMON
+ s32 (*get_thermal_sensor_data)(struct e1000_hw *);
+ s32 (*init_thermal_sensor_thresh)(struct e1000_hw *);
+#endif
};
@@ -342,6 +346,8 @@ struct e1000_phy_operations {
s32 (*set_d0_lplu_state)(struct e1000_hw *, bool);
s32 (*set_d3_lplu_state)(struct e1000_hw *, bool);
s32 (*write_reg)(struct e1000_hw *, u32, u16);
+ s32 (*read_i2c_byte)(struct e1000_hw *, u8, u8, u8 *);
+ s32 (*write_i2c_byte)(struct e1000_hw *, u8, u8, u8);
};
struct e1000_nvm_operations {
@@ -354,6 +360,19 @@ struct e1000_nvm_operations {
s32 (*valid_led_default)(struct e1000_hw *, u16 *);
};
+#define E1000_MAX_SENSORS 3
+
+struct e1000_thermal_diode_data {
+ u8 location;
+ u8 temp;
+ u8 caution_thresh;
+ u8 max_op_thresh;
+};
+
+struct e1000_thermal_sensor_data {
+ struct e1000_thermal_diode_data sensor[E1000_MAX_SENSORS];
+};
+
struct e1000_info {
s32 (*get_invariants)(struct e1000_hw *);
struct e1000_mac_operations *mac_ops;
@@ -399,6 +418,7 @@ struct e1000_mac_info {
bool report_tx_early;
bool serdes_has_link;
bool tx_pkt_filtering;
+ struct e1000_thermal_sensor_data thermal_sensor_data;
};
struct e1000_phy_info {
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c
index fbcdbebb0b5f..6a42344f24f1 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.c
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.h b/drivers/net/ethernet/intel/igb/e1000_i210.h
index 1c89358a99ab..e4e1a73b7c75 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.h
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c
index 101e6e4da97f..a5c7200b9a71 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.h b/drivers/net/ethernet/intel/igb/e1000_mac.h
index e2b2c4b9c951..e6d6ce433261 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.c b/drivers/net/ethernet/intel/igb/e1000_mbx.c
index 5988b8958baf..38e0df350904 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mbx.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.h b/drivers/net/ethernet/intel/igb/e1000_mbx.h
index dbcfa3d5caec..c13b56d9edb2 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mbx.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c
index fbb7604db364..5b62adbe134d 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.c
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.h b/drivers/net/ethernet/intel/igb/e1000_nvm.h
index 7012d458c6f7..6bfc0c43aace 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.h
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2012 Intel Corporation.
+ Copyright(c) 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c
index fe76004aca4e..2918c979b5bb 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h
index ed282f877d9a..784fd1c40989 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.h
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h
index e5db48594e8a..15343286082e 100644
--- a/drivers/net/ethernet/intel/igb/e1000_regs.h
+++ b/drivers/net/ethernet/intel/igb/e1000_regs.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -75,6 +75,14 @@
#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */
+#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
+#define E1000_I2CBB_EN 0x00000100 /* I2C - Bit Bang Enable */
+#define E1000_I2C_CLK_OUT 0x00000200 /* I2C- Clock */
+#define E1000_I2C_DATA_OUT 0x00000400 /* I2C- Data Out */
+#define E1000_I2C_DATA_OE_N 0x00000800 /* I2C- Data Output Enable */
+#define E1000_I2C_DATA_IN 0x00001000 /* I2C- Data In */
+#define E1000_I2C_CLK_OE_N 0x00002000 /* I2C- Clock Output Enable */
+#define E1000_I2C_CLK_IN 0x00004000 /* I2C- Clock In */
/* IEEE 1588 TIMESYNCH */
#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
@@ -124,6 +132,14 @@
/* Split and Replication RX Control - RW */
#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
+
+/* Thermal sensor configuration and status registers */
+#define E1000_THMJT 0x08100 /* Junction Temperature */
+#define E1000_THLOWTC 0x08104 /* Low Threshold Control */
+#define E1000_THMIDTC 0x08108 /* Mid Threshold Control */
+#define E1000_THHIGHTC 0x0810C /* High Threshold Control */
+#define E1000_THSTAT 0x08110 /* Thermal Sensor Status */
+
/*
* Convenience macros
*
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 17f1686ee411..d27edbc63923 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -39,6 +39,8 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/bitops.h>
#include <linux/if_vlan.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
struct igb_adapter;
@@ -137,8 +139,6 @@ struct vf_data_storage {
#define IGB_RX_HDR_LEN IGB_RXBUFFER_256
#define IGB_RX_BUFSZ IGB_RXBUFFER_2048
-/* How many Tx Descriptors do we need to call netif_wake_queue ? */
-#define IGB_TX_QUEUE_WAKE 16
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define IGB_RX_BUFFER_WRITE 16 /* Must be power of 2 */
@@ -167,6 +167,17 @@ enum igb_tx_flags {
#define IGB_TX_FLAGS_VLAN_MASK 0xffff0000
#define IGB_TX_FLAGS_VLAN_SHIFT 16
+/*
+ * The largest size we can write to the descriptor is 65535. In order to
+ * maintain a power of two alignment we have to limit ourselves to 32K.
+ */
+#define IGB_MAX_TXD_PWR 15
+#define IGB_MAX_DATA_PER_TXD (1 << IGB_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGB_MAX_DATA_PER_TXD)
+#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct igb_tx_buffer {
@@ -219,6 +230,7 @@ struct igb_ring {
struct igb_tx_buffer *tx_buffer_info;
struct igb_rx_buffer *rx_buffer_info;
};
+ unsigned long last_rx_timestamp;
void *desc; /* descriptor ring memory */
unsigned long flags; /* ring specific flags */
void __iomem *tail; /* pointer to ring tail register */
@@ -272,10 +284,18 @@ struct igb_q_vector {
enum e1000_ring_flags_t {
IGB_RING_FLAG_RX_SCTP_CSUM,
IGB_RING_FLAG_RX_LB_VLAN_BSWAP,
+ IGB_RING_FLAG_RX_BUILD_SKB_ENABLED,
IGB_RING_FLAG_TX_CTX_IDX,
IGB_RING_FLAG_TX_DETECT_HANG
};
+#define ring_uses_build_skb(ring) \
+ test_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
+#define set_ring_build_skb_enabled(ring) \
+ set_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
+#define clear_ring_build_skb_enabled(ring) \
+ clear_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
+
#define IGB_TXD_DCMD (E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS)
#define IGB_RX_DESC(R, i) \
@@ -301,6 +321,32 @@ static inline int igb_desc_unused(struct igb_ring *ring)
return ring->count + ring->next_to_clean - ring->next_to_use - 1;
}
+struct igb_i2c_client_list {
+ struct i2c_client *client;
+ struct igb_i2c_client_list *next;
+};
+
+#ifdef CONFIG_IGB_HWMON
+
+#define IGB_HWMON_TYPE_LOC 0
+#define IGB_HWMON_TYPE_TEMP 1
+#define IGB_HWMON_TYPE_CAUTION 2
+#define IGB_HWMON_TYPE_MAX 3
+
+struct hwmon_attr {
+ struct device_attribute dev_attr;
+ struct e1000_hw *hw;
+ struct e1000_thermal_diode_data *sensor;
+ char name[12];
+ };
+
+struct hwmon_buff {
+ struct device *device;
+ struct hwmon_attr *hwmon_list;
+ unsigned int n_hwmon;
+ };
+#endif
+
/* board specific private data structure */
struct igb_adapter {
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -386,11 +432,22 @@ struct igb_adapter {
struct delayed_work ptp_overflow_work;
struct work_struct ptp_tx_work;
struct sk_buff *ptp_tx_skb;
+ unsigned long ptp_tx_start;
+ unsigned long last_rx_ptp_check;
spinlock_t tmreg_lock;
struct cyclecounter cc;
struct timecounter tc;
+ u32 tx_hwtstamp_timeouts;
+ u32 rx_hwtstamp_cleared;
char fw_version[32];
+#ifdef CONFIG_IGB_HWMON
+ struct hwmon_buff igb_hwmon_buff;
+ bool ets;
+#endif
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_adapter i2c_adap;
+ struct igb_i2c_client_list *i2c_clients;
};
#define IGB_FLAG_HAS_MSI (1 << 0)
@@ -449,6 +506,7 @@ extern void igb_ptp_init(struct igb_adapter *adapter);
extern void igb_ptp_stop(struct igb_adapter *adapter);
extern void igb_ptp_reset(struct igb_adapter *adapter);
extern void igb_ptp_tx_work(struct work_struct *work);
+extern void igb_ptp_rx_hang(struct igb_adapter *adapter);
extern void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter);
extern void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
struct sk_buff *skb);
@@ -466,7 +524,10 @@ static inline void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector,
extern int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
struct ifreq *ifr, int cmd);
-
+#ifdef CONFIG_IGB_HWMON
+extern void igb_sysfs_exit(struct igb_adapter *adapter);
+extern int igb_sysfs_init(struct igb_adapter *adapter);
+#endif
static inline s32 igb_reset_phy(struct e1000_hw *hw)
{
if (hw->phy.ops.reset)
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index bfe9208c4b18..a3830a8ba4c1 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -92,6 +92,8 @@ static const struct igb_stats igb_gstrings_stats[] = {
IGB_STAT("os2bmc_tx_by_bmc", stats.b2ospc),
IGB_STAT("os2bmc_tx_by_host", stats.o2bspc),
IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc),
+ IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
+ IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
};
#define IGB_NETDEV_STAT(_net_stat) { \
@@ -1889,7 +1891,7 @@ static int igb_link_test(struct igb_adapter *adapter, u64 *data)
} else {
hw->mac.ops.check_for_link(&adapter->hw);
if (hw->mac.autoneg)
- msleep(4000);
+ msleep(5000);
if (!(rd32(E1000_STATUS) & E1000_STATUS_LU))
*data = 1;
@@ -2272,12 +2274,21 @@ static int igb_get_ts_info(struct net_device *dev,
struct igb_adapter *adapter = netdev_priv(dev);
switch (adapter->hw.mac.type) {
+ case e1000_82575:
+ info->so_timestamping =
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+ return 0;
case e1000_82576:
case e1000_82580:
case e1000_i350:
case e1000_i210:
case e1000_i211:
info->so_timestamping =
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c
new file mode 100644
index 000000000000..0a9b073d0b03
--- /dev/null
+++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c
@@ -0,0 +1,242 @@
+/*******************************************************************************
+
+ Intel(R) Gigabit Ethernet Linux driver
+ Copyright(c) 2007-2013 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "igb.h"
+#include "e1000_82575.h"
+#include "e1000_hw.h"
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/hwmon.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_IGB_HWMON
+/* hwmon callback functions */
+static ssize_t igb_hwmon_show_location(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+ dev_attr);
+ return sprintf(buf, "loc%u\n",
+ igb_attr->sensor->location);
+}
+
+static ssize_t igb_hwmon_show_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+ dev_attr);
+ unsigned int value;
+
+ /* reset the temp field */
+ igb_attr->hw->mac.ops.get_thermal_sensor_data(igb_attr->hw);
+
+ value = igb_attr->sensor->temp;
+
+ /* display millidegree */
+ value *= 1000;
+
+ return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t igb_hwmon_show_cautionthresh(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+ dev_attr);
+ unsigned int value = igb_attr->sensor->caution_thresh;
+
+ /* display millidegree */
+ value *= 1000;
+
+ return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t igb_hwmon_show_maxopthresh(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
+ dev_attr);
+ unsigned int value = igb_attr->sensor->max_op_thresh;
+
+ /* display millidegree */
+ value *= 1000;
+
+ return sprintf(buf, "%u\n", value);
+}
+
+/* igb_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
+ * @ adapter: pointer to the adapter structure
+ * @ offset: offset in the eeprom sensor data table
+ * @ type: type of sensor data to display
+ *
+ * For each file we want in hwmon's sysfs interface we need a device_attribute
+ * This is included in our hwmon_attr struct that contains the references to
+ * the data structures we need to get the data to display.
+ */
+static int igb_add_hwmon_attr(struct igb_adapter *adapter,
+ unsigned int offset, int type) {
+ int rc;
+ unsigned int n_attr;
+ struct hwmon_attr *igb_attr;
+
+ n_attr = adapter->igb_hwmon_buff.n_hwmon;
+ igb_attr = &adapter->igb_hwmon_buff.hwmon_list[n_attr];
+
+ switch (type) {
+ case IGB_HWMON_TYPE_LOC:
+ igb_attr->dev_attr.show = igb_hwmon_show_location;
+ snprintf(igb_attr->name, sizeof(igb_attr->name),
+ "temp%u_label", offset);
+ break;
+ case IGB_HWMON_TYPE_TEMP:
+ igb_attr->dev_attr.show = igb_hwmon_show_temp;
+ snprintf(igb_attr->name, sizeof(igb_attr->name),
+ "temp%u_input", offset);
+ break;
+ case IGB_HWMON_TYPE_CAUTION:
+ igb_attr->dev_attr.show = igb_hwmon_show_cautionthresh;
+ snprintf(igb_attr->name, sizeof(igb_attr->name),
+ "temp%u_max", offset);
+ break;
+ case IGB_HWMON_TYPE_MAX:
+ igb_attr->dev_attr.show = igb_hwmon_show_maxopthresh;
+ snprintf(igb_attr->name, sizeof(igb_attr->name),
+ "temp%u_crit", offset);
+ break;
+ default:
+ rc = -EPERM;
+ return rc;
+ }
+
+ /* These always the same regardless of type */
+ igb_attr->sensor =
+ &adapter->hw.mac.thermal_sensor_data.sensor[offset];
+ igb_attr->hw = &adapter->hw;
+ igb_attr->dev_attr.store = NULL;
+ igb_attr->dev_attr.attr.mode = S_IRUGO;
+ igb_attr->dev_attr.attr.name = igb_attr->name;
+ sysfs_attr_init(&igb_attr->dev_attr.attr);
+ rc = device_create_file(&adapter->pdev->dev,
+ &igb_attr->dev_attr);
+ if (rc == 0)
+ ++adapter->igb_hwmon_buff.n_hwmon;
+
+ return rc;
+}
+
+static void igb_sysfs_del_adapter(struct igb_adapter *adapter)
+{
+ int i;
+
+ if (adapter == NULL)
+ return;
+
+ for (i = 0; i < adapter->igb_hwmon_buff.n_hwmon; i++) {
+ device_remove_file(&adapter->pdev->dev,
+ &adapter->igb_hwmon_buff.hwmon_list[i].dev_attr);
+ }
+
+ kfree(adapter->igb_hwmon_buff.hwmon_list);
+
+ if (adapter->igb_hwmon_buff.device)
+ hwmon_device_unregister(adapter->igb_hwmon_buff.device);
+}
+
+/* called from igb_main.c */
+void igb_sysfs_exit(struct igb_adapter *adapter)
+{
+ igb_sysfs_del_adapter(adapter);
+}
+
+/* called from igb_main.c */
+int igb_sysfs_init(struct igb_adapter *adapter)
+{
+ struct hwmon_buff *igb_hwmon = &adapter->igb_hwmon_buff;
+ unsigned int i;
+ int n_attrs;
+ int rc = 0;
+
+ /* If this method isn't defined we don't support thermals */
+ if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL)
+ goto exit;
+
+ /* Don't create thermal hwmon interface if no sensors present */
+ rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw));
+ if (rc)
+ goto exit;
+
+ /* Allocation space for max attributes
+ * max num sensors * values (loc, temp, max, caution)
+ */
+ n_attrs = E1000_MAX_SENSORS * 4;
+ igb_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr),
+ GFP_KERNEL);
+ if (!igb_hwmon->hwmon_list) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ igb_hwmon->device = hwmon_device_register(&adapter->pdev->dev);
+ if (IS_ERR(igb_hwmon->device)) {
+ rc = PTR_ERR(igb_hwmon->device);
+ goto err;
+ }
+
+ for (i = 0; i < E1000_MAX_SENSORS; i++) {
+
+ /* Only create hwmon sysfs entries for sensors that have
+ * meaningful data.
+ */
+ if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0)
+ continue;
+
+ /* Bail if any hwmon attr struct fails to initialize */
+ rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION);
+ rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC);
+ rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP);
+ rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX);
+ if (rc)
+ goto err;
+ }
+
+ goto exit;
+
+err:
+ igb_sysfs_del_adapter(adapter);
+exit:
+ return rc;
+}
+#endif
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 31cfe2ec75df..ed79a1c53b59 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel(R) Gigabit Ethernet Linux driver
- Copyright(c) 2007-2012 Intel Corporation.
+ Copyright(c) 2007-2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -57,6 +57,7 @@
#ifdef CONFIG_IGB_DCA
#include <linux/dca.h>
#endif
+#include <linux/i2c.h>
#include "igb.h"
#define MAJ 4
@@ -68,7 +69,8 @@ char igb_driver_name[] = "igb";
char igb_driver_version[] = DRV_VERSION;
static const char igb_driver_string[] =
"Intel(R) Gigabit Ethernet Network Driver";
-static const char igb_copyright[] = "Copyright (c) 2007-2012 Intel Corporation.";
+static const char igb_copyright[] =
+ "Copyright (c) 2007-2013 Intel Corporation.";
static const struct e1000_info *igb_info_tbl[] = {
[board_82575] = &e1000_82575_info,
@@ -193,6 +195,7 @@ static const struct dev_pm_ops igb_pm_ops = {
};
#endif
static void igb_shutdown(struct pci_dev *);
+static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
#ifdef CONFIG_IGB_DCA
static int igb_notify_dca(struct notifier_block *, unsigned long, void *);
static struct notifier_block dca_notifier = {
@@ -234,6 +237,7 @@ static struct pci_driver igb_driver = {
.driver.pm = &igb_pm_ops,
#endif
.shutdown = igb_shutdown,
+ .sriov_configure = igb_pci_sriov_configure,
.err_handler = &igb_err_handler
};
@@ -565,6 +569,91 @@ exit:
return;
}
+/* igb_get_i2c_data - Reads the I2C SDA data bit
+ * @hw: pointer to hardware structure
+ * @i2cctl: Current value of I2CCTL register
+ *
+ * Returns the I2C data bit value
+ */
+static int igb_get_i2c_data(void *data)
+{
+ struct igb_adapter *adapter = (struct igb_adapter *)data;
+ struct e1000_hw *hw = &adapter->hw;
+ s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+ return ((i2cctl & E1000_I2C_DATA_IN) != 0);
+}
+
+/* igb_set_i2c_data - Sets the I2C data bit
+ * @data: pointer to hardware structure
+ * @state: I2C data value (0 or 1) to set
+ *
+ * Sets the I2C data bit
+ */
+static void igb_set_i2c_data(void *data, int state)
+{
+ struct igb_adapter *adapter = (struct igb_adapter *)data;
+ struct e1000_hw *hw = &adapter->hw;
+ s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+ if (state)
+ i2cctl |= E1000_I2C_DATA_OUT;
+ else
+ i2cctl &= ~E1000_I2C_DATA_OUT;
+
+ i2cctl &= ~E1000_I2C_DATA_OE_N;
+ i2cctl |= E1000_I2C_CLK_OE_N;
+ wr32(E1000_I2CPARAMS, i2cctl);
+ wrfl();
+
+}
+
+/* igb_set_i2c_clk - Sets the I2C SCL clock
+ * @data: pointer to hardware structure
+ * @state: state to set clock
+ *
+ * Sets the I2C clock line to state
+ */
+static void igb_set_i2c_clk(void *data, int state)
+{
+ struct igb_adapter *adapter = (struct igb_adapter *)data;
+ struct e1000_hw *hw = &adapter->hw;
+ s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+ if (state) {
+ i2cctl |= E1000_I2C_CLK_OUT;
+ i2cctl &= ~E1000_I2C_CLK_OE_N;
+ } else {
+ i2cctl &= ~E1000_I2C_CLK_OUT;
+ i2cctl &= ~E1000_I2C_CLK_OE_N;
+ }
+ wr32(E1000_I2CPARAMS, i2cctl);
+ wrfl();
+}
+
+/* igb_get_i2c_clk - Gets the I2C SCL clock state
+ * @data: pointer to hardware structure
+ *
+ * Gets the I2C clock state
+ */
+static int igb_get_i2c_clk(void *data)
+{
+ struct igb_adapter *adapter = (struct igb_adapter *)data;
+ struct e1000_hw *hw = &adapter->hw;
+ s32 i2cctl = rd32(E1000_I2CPARAMS);
+
+ return ((i2cctl & E1000_I2C_CLK_IN) != 0);
+}
+
+static const struct i2c_algo_bit_data igb_i2c_algo = {
+ .setsda = igb_set_i2c_data,
+ .setscl = igb_set_i2c_clk,
+ .getsda = igb_get_i2c_data,
+ .getscl = igb_get_i2c_clk,
+ .udelay = 5,
+ .timeout = 20,
+};
+
/**
* igb_get_hw_dev - return device
* used by hardware layer to print debugging information
@@ -1708,6 +1797,18 @@ void igb_reset(struct igb_adapter *adapter)
igb_force_mac_fc(hw);
igb_init_dmac(adapter, pba);
+#ifdef CONFIG_IGB_HWMON
+ /* Re-initialize the thermal sensor on i350 devices. */
+ if (!test_bit(__IGB_DOWN, &adapter->state)) {
+ if (mac->type == e1000_i350 && hw->bus.func == 0) {
+ /* If present, re-initialize the external thermal sensor
+ * interface.
+ */
+ if (adapter->ets)
+ mac->ops.init_thermal_sensor_thresh(hw);
+ }
+ }
+#endif
if (!netif_running(adapter->netdev))
igb_power_down_link(adapter);
@@ -1822,6 +1923,37 @@ void igb_set_fw_version(struct igb_adapter *adapter)
return;
}
+static const struct i2c_board_info i350_sensor_info = {
+ I2C_BOARD_INFO("i350bb", 0Xf8),
+};
+
+/* igb_init_i2c - Init I2C interface
+ * @adapter: pointer to adapter structure
+ *
+ */
+static s32 igb_init_i2c(struct igb_adapter *adapter)
+{
+ s32 status = E1000_SUCCESS;
+
+ /* I2C interface supported on i350 devices */
+ if (adapter->hw.mac.type != e1000_i350)
+ return E1000_SUCCESS;
+
+ /* Initialize the i2c bus which is controlled by the registers.
+ * This bus will use the i2c_algo_bit structue that implements
+ * the protocol through toggling of the 4 bits in the register.
+ */
+ adapter->i2c_adap.owner = THIS_MODULE;
+ adapter->i2c_algo = igb_i2c_algo;
+ adapter->i2c_algo.data = adapter;
+ adapter->i2c_adap.algo_data = &adapter->i2c_algo;
+ adapter->i2c_adap.dev.parent = &adapter->pdev->dev;
+ strlcpy(adapter->i2c_adap.name, "igb BB",
+ sizeof(adapter->i2c_adap.name));
+ status = i2c_bit_add_bus(&adapter->i2c_adap);
+ return status;
+}
+
/**
* igb_probe - Device Initialization Routine
* @pdev: PCI device information struct
@@ -2022,9 +2154,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&pdev->dev, "NVM Read Error\n");
memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
- memcpy(netdev->perm_addr, hw->mac.addr, netdev->addr_len);
- if (!is_valid_ether_addr(netdev->perm_addr)) {
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
dev_err(&pdev->dev, "Invalid MAC Address\n");
err = -EIO;
goto err_eeprom;
@@ -2115,6 +2246,13 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* reset the hardware with the new settings */
igb_reset(adapter);
+ /* Init the I2C interface */
+ err = igb_init_i2c(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "failed to init i2c interface\n");
+ goto err_eeprom;
+ }
+
/* let the f/w know that the h/w is now under the control of the
* driver. */
igb_get_hw_control(adapter);
@@ -2135,7 +2273,27 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
#endif
+#ifdef CONFIG_IGB_HWMON
+ /* Initialize the thermal sensor on i350 devices. */
+ if (hw->mac.type == e1000_i350 && hw->bus.func == 0) {
+ u16 ets_word;
+ /*
+ * Read the NVM to determine if this i350 device supports an
+ * external thermal sensor.
+ */
+ hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_word);
+ if (ets_word != 0x0000 && ets_word != 0xFFFF)
+ adapter->ets = true;
+ else
+ adapter->ets = false;
+ if (igb_sysfs_init(adapter))
+ dev_err(&pdev->dev,
+ "failed to allocate sysfs resources\n");
+ } else {
+ adapter->ets = false;
+ }
+#endif
/* do hw tstamp init after resetting */
igb_ptp_init(adapter);
@@ -2176,6 +2334,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_register:
igb_release_hw_control(adapter);
+ memset(&adapter->i2c_adap, 0, sizeof(adapter->i2c_adap));
err_eeprom:
if (!igb_check_reset_block(hw))
igb_reset_phy(hw);
@@ -2196,6 +2355,111 @@ err_dma:
return err;
}
+#ifdef CONFIG_PCI_IOV
+static int igb_disable_sriov(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ /* reclaim resources allocated to VFs */
+ if (adapter->vf_data) {
+ /* disable iov and allow time for transactions to clear */
+ if (igb_vfs_are_assigned(adapter)) {
+ dev_warn(&pdev->dev,
+ "Cannot deallocate SR-IOV virtual functions while they are assigned - VFs will not be deallocated\n");
+ return -EPERM;
+ } else {
+ pci_disable_sriov(pdev);
+ msleep(500);
+ }
+
+ kfree(adapter->vf_data);
+ adapter->vf_data = NULL;
+ adapter->vfs_allocated_count = 0;
+ wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
+ wrfl();
+ msleep(100);
+ dev_info(&pdev->dev, "IOV Disabled\n");
+
+ /* Re-enable DMA Coalescing flag since IOV is turned off */
+ adapter->flags |= IGB_FLAG_DMAC;
+ }
+
+ return 0;
+}
+
+static int igb_enable_sriov(struct pci_dev *pdev, int num_vfs)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ int old_vfs = pci_num_vf(pdev);
+ int err = 0;
+ int i;
+
+ if (!num_vfs)
+ goto out;
+ else if (old_vfs && old_vfs == num_vfs)
+ goto out;
+ else if (old_vfs && old_vfs != num_vfs)
+ err = igb_disable_sriov(pdev);
+
+ if (err)
+ goto out;
+
+ if (num_vfs > 7) {
+ err = -EPERM;
+ goto out;
+ }
+
+ adapter->vfs_allocated_count = num_vfs;
+
+ adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
+ sizeof(struct vf_data_storage), GFP_KERNEL);
+
+ /* if allocation failed then we do not support SR-IOV */
+ if (!adapter->vf_data) {
+ adapter->vfs_allocated_count = 0;
+ dev_err(&pdev->dev,
+ "Unable to allocate memory for VF Data Storage\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = pci_enable_sriov(pdev, adapter->vfs_allocated_count);
+ if (err)
+ goto err_out;
+
+ dev_info(&pdev->dev, "%d VFs allocated\n",
+ adapter->vfs_allocated_count);
+ for (i = 0; i < adapter->vfs_allocated_count; i++)
+ igb_vf_configure(adapter, i);
+
+ /* DMA Coalescing is not supported in IOV mode. */
+ adapter->flags &= ~IGB_FLAG_DMAC;
+ goto out;
+
+err_out:
+ kfree(adapter->vf_data);
+ adapter->vf_data = NULL;
+ adapter->vfs_allocated_count = 0;
+out:
+ return err;
+}
+
+#endif
+/*
+ * igb_remove_i2c - Cleanup I2C interface
+ * @adapter: pointer to adapter structure
+ *
+ */
+static void igb_remove_i2c(struct igb_adapter *adapter)
+{
+
+ /* free the adapter bus structure */
+ i2c_del_adapter(&adapter->i2c_adap);
+}
+
/**
* igb_remove - Device Removal Routine
* @pdev: PCI device information struct
@@ -2212,8 +2476,11 @@ static void igb_remove(struct pci_dev *pdev)
struct e1000_hw *hw = &adapter->hw;
pm_runtime_get_noresume(&pdev->dev);
+#ifdef CONFIG_IGB_HWMON
+ igb_sysfs_exit(adapter);
+#endif
+ igb_remove_i2c(adapter);
igb_ptp_stop(adapter);
-
/*
* The watchdog timer may be rescheduled, so explicitly
* disable watchdog from being rescheduled.
@@ -2243,23 +2510,7 @@ static void igb_remove(struct pci_dev *pdev)
igb_clear_interrupt_scheme(adapter);
#ifdef CONFIG_PCI_IOV
- /* reclaim resources allocated to VFs */
- if (adapter->vf_data) {
- /* disable iov and allow time for transactions to clear */
- if (igb_vfs_are_assigned(adapter)) {
- dev_info(&pdev->dev, "Unloading driver while VFs are assigned - VFs will not be deallocated\n");
- } else {
- pci_disable_sriov(pdev);
- msleep(500);
- }
-
- kfree(adapter->vf_data);
- adapter->vf_data = NULL;
- wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
- wrfl();
- msleep(100);
- dev_info(&pdev->dev, "IOV Disabled\n");
- }
+ igb_disable_sriov(pdev);
#endif
iounmap(hw->hw_addr);
@@ -2290,103 +2541,22 @@ static void igb_probe_vfs(struct igb_adapter *adapter)
#ifdef CONFIG_PCI_IOV
struct pci_dev *pdev = adapter->pdev;
struct e1000_hw *hw = &adapter->hw;
- int old_vfs = pci_num_vf(adapter->pdev);
- int i;
/* Virtualization features not supported on i210 family. */
if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
return;
- if (old_vfs) {
- dev_info(&pdev->dev, "%d pre-allocated VFs found - override "
- "max_vfs setting of %d\n", old_vfs, max_vfs);
- adapter->vfs_allocated_count = old_vfs;
- }
-
- if (!adapter->vfs_allocated_count)
- return;
-
- adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
- sizeof(struct vf_data_storage), GFP_KERNEL);
-
- /* if allocation failed then we do not support SR-IOV */
- if (!adapter->vf_data) {
- adapter->vfs_allocated_count = 0;
- dev_err(&pdev->dev, "Unable to allocate memory for VF "
- "Data Storage\n");
- goto out;
- }
-
- if (!old_vfs) {
- if (pci_enable_sriov(pdev, adapter->vfs_allocated_count))
- goto err_out;
- }
- dev_info(&pdev->dev, "%d VFs allocated\n",
- adapter->vfs_allocated_count);
- for (i = 0; i < adapter->vfs_allocated_count; i++)
- igb_vf_configure(adapter, i);
+ igb_enable_sriov(pdev, max_vfs);
+ pci_sriov_set_totalvfs(pdev, 7);
- /* DMA Coalescing is not supported in IOV mode. */
- adapter->flags &= ~IGB_FLAG_DMAC;
- goto out;
-err_out:
- kfree(adapter->vf_data);
- adapter->vf_data = NULL;
- adapter->vfs_allocated_count = 0;
-out:
- return;
#endif /* CONFIG_PCI_IOV */
}
-/**
- * igb_sw_init - Initialize general software structures (struct igb_adapter)
- * @adapter: board private structure to initialize
- *
- * igb_sw_init initializes the Adapter private data structure.
- * Fields are initialized based on PCI device information and
- * OS network device settings (MTU size).
- **/
-static int igb_sw_init(struct igb_adapter *adapter)
+static void igb_init_queue_configuration(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
- struct net_device *netdev = adapter->netdev;
- struct pci_dev *pdev = adapter->pdev;
u32 max_rss_queues;
- pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
-
- /* set default ring sizes */
- adapter->tx_ring_count = IGB_DEFAULT_TXD;
- adapter->rx_ring_count = IGB_DEFAULT_RXD;
-
- /* set default ITR values */
- adapter->rx_itr_setting = IGB_DEFAULT_ITR;
- adapter->tx_itr_setting = IGB_DEFAULT_ITR;
-
- /* set default work limits */
- adapter->tx_work_limit = IGB_DEFAULT_TX_WORK;
-
- adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN +
- VLAN_HLEN;
- adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
-
- spin_lock_init(&adapter->stats64_lock);
-#ifdef CONFIG_PCI_IOV
- switch (hw->mac.type) {
- case e1000_82576:
- case e1000_i350:
- if (max_vfs > 7) {
- dev_warn(&pdev->dev,
- "Maximum of 7 VFs per PF, using max\n");
- adapter->vfs_allocated_count = 7;
- } else
- adapter->vfs_allocated_count = max_vfs;
- break;
- default:
- break;
- }
-#endif /* CONFIG_PCI_IOV */
-
/* Determine the maximum number of RSS queues supported. */
switch (hw->mac.type) {
case e1000_i211:
@@ -2445,11 +2615,64 @@ static int igb_sw_init(struct igb_adapter *adapter)
adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
break;
}
+}
+
+/**
+ * igb_sw_init - Initialize general software structures (struct igb_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * igb_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int igb_sw_init(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+
+ /* set default ring sizes */
+ adapter->tx_ring_count = IGB_DEFAULT_TXD;
+ adapter->rx_ring_count = IGB_DEFAULT_RXD;
+
+ /* set default ITR values */
+ adapter->rx_itr_setting = IGB_DEFAULT_ITR;
+ adapter->tx_itr_setting = IGB_DEFAULT_ITR;
+
+ /* set default work limits */
+ adapter->tx_work_limit = IGB_DEFAULT_TX_WORK;
+
+ adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN +
+ VLAN_HLEN;
+ adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+ spin_lock_init(&adapter->stats64_lock);
+#ifdef CONFIG_PCI_IOV
+ switch (hw->mac.type) {
+ case e1000_82576:
+ case e1000_i350:
+ if (max_vfs > 7) {
+ dev_warn(&pdev->dev,
+ "Maximum of 7 VFs per PF, using max\n");
+ adapter->vfs_allocated_count = 7;
+ } else
+ adapter->vfs_allocated_count = max_vfs;
+ if (adapter->vfs_allocated_count)
+ dev_warn(&pdev->dev,
+ "Enabling SR-IOV VFs using the module parameter is deprecated - please use the pci sysfs interface.\n");
+ break;
+ default:
+ break;
+ }
+#endif /* CONFIG_PCI_IOV */
+
+ igb_init_queue_configuration(adapter);
/* Setup and initialize a copy of the hw vlan table array */
- adapter->shadow_vfta = kzalloc(sizeof(u32) *
- E1000_VLAN_FILTER_TBL_SIZE,
- GFP_ATOMIC);
+ adapter->shadow_vfta = kcalloc(E1000_VLAN_FILTER_TBL_SIZE, sizeof(u32),
+ GFP_ATOMIC);
/* This call may decrease the number of queues */
if (igb_init_interrupt_scheme(adapter, true)) {
@@ -3131,6 +3354,20 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
wr32(E1000_RXDCTL(reg_idx), rxdctl);
}
+static void igb_set_rx_buffer_len(struct igb_adapter *adapter,
+ struct igb_ring *rx_ring)
+{
+#define IGB_MAX_BUILD_SKB_SIZE \
+ (SKB_WITH_OVERHEAD(IGB_RX_BUFSZ) - \
+ (NET_SKB_PAD + NET_IP_ALIGN + IGB_TS_HDR_LEN))
+
+ /* set build_skb flag */
+ if (adapter->max_frame_size <= IGB_MAX_BUILD_SKB_SIZE)
+ set_ring_build_skb_enabled(rx_ring);
+ else
+ clear_ring_build_skb_enabled(rx_ring);
+}
+
/**
* igb_configure_rx - Configure receive Unit after Reset
* @adapter: board private structure
@@ -3150,8 +3387,11 @@ static void igb_configure_rx(struct igb_adapter *adapter)
/* Setup the HW Rx Head and Tail Descriptor Pointers and
* the Base and Length of the Rx Descriptor Ring */
- for (i = 0; i < adapter->num_rx_queues; i++)
- igb_configure_rx_ring(adapter, adapter->rx_ring[i]);
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ struct igb_ring *rx_ring = adapter->rx_ring[i];
+ igb_set_rx_buffer_len(adapter, rx_ring);
+ igb_configure_rx_ring(adapter, rx_ring);
+ }
}
/**
@@ -3768,6 +4008,7 @@ static void igb_watchdog_task(struct work_struct *work)
}
igb_spoof_check(adapter);
+ igb_ptp_rx_hang(adapter);
/* Reset the timer */
if (!test_bit(__IGB_DOWN, &adapter->state))
@@ -4193,13 +4434,6 @@ static void igb_tx_olinfo_status(struct igb_ring *tx_ring,
tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
}
-/*
- * The largest size we can write to the descriptor is 65535. In order to
- * maintain a power of two alignment we have to limit ourselves to 32K.
- */
-#define IGB_MAX_TXD_PWR 15
-#define IGB_MAX_DATA_PER_TXD (1<<IGB_MAX_TXD_PWR)
-
static void igb_tx_map(struct igb_ring *tx_ring,
struct igb_tx_buffer *first,
const u8 hdr_len)
@@ -4368,15 +4602,25 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
struct igb_tx_buffer *first;
int tso;
u32 tx_flags = 0;
+ u16 count = TXD_USE_COUNT(skb_headlen(skb));
__be16 protocol = vlan_get_protocol(skb);
u8 hdr_len = 0;
- /* need: 1 descriptor per page,
+ /* need: 1 descriptor per page * PAGE_SIZE/IGB_MAX_DATA_PER_TXD,
+ * + 1 desc for skb_headlen/IGB_MAX_DATA_PER_TXD,
* + 2 desc gap to keep tail from touching head,
- * + 1 desc for skb->data,
* + 1 desc for context descriptor,
- * otherwise try next time */
- if (igb_maybe_stop_tx(tx_ring, skb_shinfo(skb)->nr_frags + 4)) {
+ * otherwise try next time
+ */
+ if (NETDEV_FRAG_PAGE_MAX_SIZE > IGB_MAX_DATA_PER_TXD) {
+ unsigned short f;
+ for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
+ } else {
+ count += skb_shinfo(skb)->nr_frags;
+ }
+
+ if (igb_maybe_stop_tx(tx_ring, count + 3)) {
/* this is a hard error */
return NETDEV_TX_BUSY;
}
@@ -4387,12 +4631,15 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
first->bytecount = skb->len;
first->gso_segs = 1;
+ skb_tx_timestamp(skb);
+
if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
!(adapter->ptp_tx_skb))) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IGB_TX_FLAGS_TSTAMP;
adapter->ptp_tx_skb = skb_get(skb);
+ adapter->ptp_tx_start = jiffies;
if (adapter->hw.mac.type == e1000_82576)
schedule_work(&adapter->ptp_tx_work);
}
@@ -4415,7 +4662,7 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
igb_tx_map(tx_ring, first, hdr_len);
/* Make sure there is space in the ring for the next send. */
- igb_maybe_stop_tx(tx_ring, MAX_SKB_FRAGS + 4);
+ igb_maybe_stop_tx(tx_ring, DESC_NEEDED);
return NETDEV_TX_OK;
@@ -4969,7 +5216,7 @@ static int igb_vf_configure(struct igb_adapter *adapter, int vf)
{
unsigned char mac_addr[ETH_ALEN];
- eth_random_addr(mac_addr);
+ eth_zero_addr(mac_addr);
igb_set_vf_mac(adapter, vf, mac_addr);
return 0;
@@ -5322,9 +5569,9 @@ static void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf)
{
unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
- /* generate a new mac address as we were hotplug removed/added */
+ /* clear mac address as we were hotplug removed/added */
if (!(adapter->vf_data[vf].flags & IGB_VF_FLAG_PF_SET_MAC))
- eth_random_addr(vf_mac);
+ eth_zero_addr(vf_mac);
/* process remaining reset events */
igb_vf_reset(adapter, vf);
@@ -5703,7 +5950,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
break;
/* prevent any other reads prior to eop_desc */
- rmb();
+ read_barrier_depends();
/* if DD is not set pending work has not been completed */
if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
@@ -5819,9 +6066,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
}
}
+#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
if (unlikely(total_packets &&
netif_carrier_ok(tx_ring->netdev) &&
- igb_desc_unused(tx_ring) >= IGB_TX_QUEUE_WAKE)) {
+ igb_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD)) {
/* Make sure that anybody stopping the queue after this
* sees the new next_to_clean.
*/
@@ -5870,6 +6118,41 @@ static void igb_reuse_rx_page(struct igb_ring *rx_ring,
DMA_FROM_DEVICE);
}
+static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer,
+ struct page *page,
+ unsigned int truesize)
+{
+ /* avoid re-using remote pages */
+ if (unlikely(page_to_nid(page) != numa_node_id()))
+ return false;
+
+#if (PAGE_SIZE < 8192)
+ /* if we are only owner of page we can reuse it */
+ if (unlikely(page_count(page) != 1))
+ return false;
+
+ /* flip page offset to other buffer */
+ rx_buffer->page_offset ^= IGB_RX_BUFSZ;
+
+ /* since we are the only owner of the page and we need to
+ * increment it, just set the value to 2 in order to avoid
+ * an unnecessary locked operation
+ */
+ atomic_set(&page->_count, 2);
+#else
+ /* move offset up to the next cache line */
+ rx_buffer->page_offset += truesize;
+
+ if (rx_buffer->page_offset > (PAGE_SIZE - IGB_RX_BUFSZ))
+ return false;
+
+ /* bump ref count on page before it is given to the stack */
+ get_page(page);
+#endif
+
+ return true;
+}
+
/**
* igb_add_rx_frag - Add contents of Rx buffer to sk_buff
* @rx_ring: rx descriptor ring to transact packets on
@@ -5892,6 +6175,11 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring,
{
struct page *page = rx_buffer->page;
unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
+#if (PAGE_SIZE < 8192)
+ unsigned int truesize = IGB_RX_BUFSZ;
+#else
+ unsigned int truesize = ALIGN(size, L1_CACHE_BYTES);
+#endif
if ((size <= IGB_RX_HDR_LEN) && !skb_is_nonlinear(skb)) {
unsigned char *va = page_address(page) + rx_buffer->page_offset;
@@ -5914,38 +6202,88 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring,
}
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
- rx_buffer->page_offset, size, IGB_RX_BUFSZ);
+ rx_buffer->page_offset, size, truesize);
- /* avoid re-using remote pages */
- if (unlikely(page_to_nid(page) != numa_node_id()))
- return false;
+ return igb_can_reuse_rx_page(rx_buffer, page, truesize);
+}
+static struct sk_buff *igb_build_rx_buffer(struct igb_ring *rx_ring,
+ union e1000_adv_rx_desc *rx_desc)
+{
+ struct igb_rx_buffer *rx_buffer;
+ struct sk_buff *skb;
+ struct page *page;
+ void *page_addr;
+ unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
#if (PAGE_SIZE < 8192)
- /* if we are only owner of page we can reuse it */
- if (unlikely(page_count(page) != 1))
- return false;
+ unsigned int truesize = IGB_RX_BUFSZ;
+#else
+ unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
+ SKB_DATA_ALIGN(NET_SKB_PAD +
+ NET_IP_ALIGN +
+ size);
+#endif
- /* flip page offset to other buffer */
- rx_buffer->page_offset ^= IGB_RX_BUFSZ;
+ /* If we spanned a buffer we have a huge mess so test for it */
+ BUG_ON(unlikely(!igb_test_staterr(rx_desc, E1000_RXD_STAT_EOP)));
- /*
- * since we are the only owner of the page and we need to
- * increment it, just set the value to 2 in order to avoid
- * an unnecessary locked operation
- */
- atomic_set(&page->_count, 2);
-#else
- /* move offset up to the next cache line */
- rx_buffer->page_offset += SKB_DATA_ALIGN(size);
+ /* Guarantee this function can be used by verifying buffer sizes */
+ BUILD_BUG_ON(SKB_WITH_OVERHEAD(IGB_RX_BUFSZ) < (NET_SKB_PAD +
+ NET_IP_ALIGN +
+ IGB_TS_HDR_LEN +
+ ETH_FRAME_LEN +
+ ETH_FCS_LEN));
- if (rx_buffer->page_offset > (PAGE_SIZE - IGB_RX_BUFSZ))
- return false;
+ rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
+ page = rx_buffer->page;
+ prefetchw(page);
- /* bump ref count on page before it is given to the stack */
- get_page(page);
+ page_addr = page_address(page) + rx_buffer->page_offset;
+
+ /* prefetch first cache line of first page */
+ prefetch(page_addr + NET_SKB_PAD + NET_IP_ALIGN);
+#if L1_CACHE_BYTES < 128
+ prefetch(page_addr + L1_CACHE_BYTES + NET_SKB_PAD + NET_IP_ALIGN);
#endif
- return true;
+ /* build an skb to around the page buffer */
+ skb = build_skb(page_addr, truesize);
+ if (unlikely(!skb)) {
+ rx_ring->rx_stats.alloc_failed++;
+ return NULL;
+ }
+
+ /* we are reusing so sync this buffer for CPU use */
+ dma_sync_single_range_for_cpu(rx_ring->dev,
+ rx_buffer->dma,
+ rx_buffer->page_offset,
+ IGB_RX_BUFSZ,
+ DMA_FROM_DEVICE);
+
+ /* update pointers within the skb to store the data */
+ skb_reserve(skb, NET_IP_ALIGN + NET_SKB_PAD);
+ __skb_put(skb, size);
+
+ /* pull timestamp out of packet data */
+ if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
+ igb_ptp_rx_pktstamp(rx_ring->q_vector, skb->data, skb);
+ __skb_pull(skb, IGB_TS_HDR_LEN);
+ }
+
+ if (igb_can_reuse_rx_page(rx_buffer, page, truesize)) {
+ /* hand second half of page back to the ring */
+ igb_reuse_rx_page(rx_ring, rx_buffer);
+ } else {
+ /* we are not reusing the buffer so unmap it */
+ dma_unmap_page(rx_ring->dev, rx_buffer->dma,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ }
+
+ /* clear contents of buffer_info */
+ rx_buffer->dma = 0;
+ rx_buffer->page = NULL;
+
+ return skb;
}
static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring,
@@ -5957,13 +6295,6 @@ static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring,
rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
- /*
- * This memory barrier is needed to keep us from reading
- * any other fields out of the rx_desc until we know the
- * RXD_STAT_DD bit is set
- */
- rmb();
-
page = rx_buffer->page;
prefetchw(page);
@@ -6363,8 +6694,17 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
if (!igb_test_staterr(rx_desc, E1000_RXD_STAT_DD))
break;
+ /* This memory barrier is needed to keep us from reading
+ * any other fields out of the rx_desc until we know the
+ * RXD_STAT_DD bit is set
+ */
+ rmb();
+
/* retrieve a buffer from the ring */
- skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);
+ if (ring_uses_build_skb(rx_ring))
+ skb = igb_build_rx_buffer(rx_ring, rx_desc);
+ else
+ skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);
/* exit if we failed to retrieve a buffer */
if (!skb)
@@ -6451,6 +6791,14 @@ static bool igb_alloc_mapped_page(struct igb_ring *rx_ring,
return true;
}
+static inline unsigned int igb_rx_offset(struct igb_ring *rx_ring)
+{
+ if (ring_uses_build_skb(rx_ring))
+ return NET_SKB_PAD + NET_IP_ALIGN;
+ else
+ return 0;
+}
+
/**
* igb_alloc_rx_buffers - Replace used receive buffers; packet split
* @adapter: address of board private structure
@@ -6477,7 +6825,9 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
* Refresh the desc even if buffer_addrs didn't change
* because each write-back erases this info.
*/
- rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset);
+ rx_desc->read.pkt_addr = cpu_to_le64(bi->dma +
+ bi->page_offset +
+ igb_rx_offset(rx_ring));
rx_desc++;
bi++;
@@ -6903,6 +7253,72 @@ static void igb_shutdown(struct pci_dev *pdev)
}
}
+#ifdef CONFIG_PCI_IOV
+static int igb_sriov_reinit(struct pci_dev *dev)
+{
+ struct net_device *netdev = pci_get_drvdata(dev);
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct pci_dev *pdev = adapter->pdev;
+
+ rtnl_lock();
+
+ if (netif_running(netdev))
+ igb_close(netdev);
+
+ igb_clear_interrupt_scheme(adapter);
+
+ igb_init_queue_configuration(adapter);
+
+ if (igb_init_interrupt_scheme(adapter, true)) {
+ dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+ return -ENOMEM;
+ }
+
+ if (netif_running(netdev))
+ igb_open(netdev);
+
+ rtnl_unlock();
+
+ return 0;
+}
+
+static int igb_pci_disable_sriov(struct pci_dev *dev)
+{
+ int err = igb_disable_sriov(dev);
+
+ if (!err)
+ err = igb_sriov_reinit(dev);
+
+ return err;
+}
+
+static int igb_pci_enable_sriov(struct pci_dev *dev, int num_vfs)
+{
+ int err = igb_enable_sriov(dev, num_vfs);
+
+ if (err)
+ goto out;
+
+ err = igb_sriov_reinit(dev);
+ if (!err)
+ return num_vfs;
+
+out:
+ return err;
+}
+
+#endif
+static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
+{
+#ifdef CONFIG_PCI_IOV
+ if (num_vfs == 0)
+ return igb_pci_disable_sriov(dev);
+ else
+ return igb_pci_enable_sriov(dev, num_vfs);
+#endif
+ return 0;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
* Polling 'interrupt' - used by things like netconsole to send skbs
@@ -7308,4 +7724,133 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
}
}
+static DEFINE_SPINLOCK(i2c_clients_lock);
+
+/* igb_get_i2c_client - returns matching client
+ * in adapters's client list.
+ * @adapter: adapter struct
+ * @dev_addr: device address of i2c needed.
+ */
+static struct i2c_client *
+igb_get_i2c_client(struct igb_adapter *adapter, u8 dev_addr)
+{
+ ulong flags;
+ struct igb_i2c_client_list *client_list;
+ struct i2c_client *client = NULL;
+ struct i2c_board_info client_info = {
+ I2C_BOARD_INFO("igb", 0x00),
+ };
+
+ spin_lock_irqsave(&i2c_clients_lock, flags);
+ client_list = adapter->i2c_clients;
+
+ /* See if we already have an i2c_client */
+ while (client_list) {
+ if (client_list->client->addr == (dev_addr >> 1)) {
+ client = client_list->client;
+ goto exit;
+ } else {
+ client_list = client_list->next;
+ }
+ }
+
+ /* no client_list found, create a new one */
+ client_list = kzalloc(sizeof(*client_list), GFP_ATOMIC);
+ if (client_list == NULL)
+ goto exit;
+
+ /* dev_addr passed to us is left-shifted by 1 bit
+ * i2c_new_device call expects it to be flush to the right.
+ */
+ client_info.addr = dev_addr >> 1;
+ client_info.platform_data = adapter;
+ client_list->client = i2c_new_device(&adapter->i2c_adap, &client_info);
+ if (client_list->client == NULL) {
+ dev_info(&adapter->pdev->dev,
+ "Failed to create new i2c device..\n");
+ goto err_no_client;
+ }
+
+ /* insert new client at head of list */
+ client_list->next = adapter->i2c_clients;
+ adapter->i2c_clients = client_list;
+
+ client = client_list->client;
+ goto exit;
+
+err_no_client:
+ kfree(client_list);
+exit:
+ spin_unlock_irqrestore(&i2c_clients_lock, flags);
+ return client;
+}
+
+/* igb_read_i2c_byte - Reads 8 bit word over I2C
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset to read
+ * @dev_addr: device address
+ * @data: value read
+ *
+ * Performs byte read operation over I2C interface at
+ * a specified device address.
+ */
+s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 *data)
+{
+ struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw);
+ struct i2c_client *this_client = igb_get_i2c_client(adapter, dev_addr);
+ s32 status;
+ u16 swfw_mask = 0;
+
+ if (!this_client)
+ return E1000_ERR_I2C;
+
+ swfw_mask = E1000_SWFW_PHY0_SM;
+
+ if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)
+ != E1000_SUCCESS)
+ return E1000_ERR_SWFW_SYNC;
+
+ status = i2c_smbus_read_byte_data(this_client, byte_offset);
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+
+ if (status < 0)
+ return E1000_ERR_I2C;
+ else {
+ *data = status;
+ return E1000_SUCCESS;
+ }
+}
+
+/* igb_write_i2c_byte - Writes 8 bit word over I2C
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset to write
+ * @dev_addr: device address
+ * @data: value to write
+ *
+ * Performs byte write operation over I2C interface at
+ * a specified device address.
+ */
+s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data)
+{
+ struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw);
+ struct i2c_client *this_client = igb_get_i2c_client(adapter, dev_addr);
+ s32 status;
+ u16 swfw_mask = E1000_SWFW_PHY0_SM;
+
+ if (!this_client)
+ return E1000_ERR_I2C;
+
+ if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != E1000_SUCCESS)
+ return E1000_ERR_SWFW_SYNC;
+ status = i2c_smbus_write_byte_data(this_client, byte_offset, data);
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+
+ if (status)
+ return E1000_ERR_I2C;
+ else
+ return E1000_SUCCESS;
+
+}
/* igb_main.c */
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index ab3429729bde..0987822359f0 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/pci.h>
+#include <linux/ptp_classify.h>
#include "igb.h"
@@ -70,6 +71,7 @@
*/
#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 9)
+#define IGB_PTP_TX_TIMEOUT (HZ * 15)
#define INCPERIOD_82576 (1 << E1000_TIMINCA_16NS_SHIFT)
#define INCVALUE_82576_MASK ((1 << E1000_TIMINCA_16NS_SHIFT) - 1)
#define INCVALUE_82576 (16 << IGB_82576_TSYNC_SHIFT)
@@ -396,6 +398,15 @@ void igb_ptp_tx_work(struct work_struct *work)
if (!adapter->ptp_tx_skb)
return;
+ if (time_is_before_jiffies(adapter->ptp_tx_start +
+ IGB_PTP_TX_TIMEOUT)) {
+ dev_kfree_skb_any(adapter->ptp_tx_skb);
+ adapter->ptp_tx_skb = NULL;
+ adapter->tx_hwtstamp_timeouts++;
+ dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang");
+ return;
+ }
+
tsynctxctl = rd32(E1000_TSYNCTXCTL);
if (tsynctxctl & E1000_TSYNCTXCTL_VALID)
igb_ptp_tx_hwtstamp(adapter);
@@ -419,6 +430,51 @@ static void igb_ptp_overflow_check(struct work_struct *work)
}
/**
+ * igb_ptp_rx_hang - detect error case when Rx timestamp registers latched
+ * @adapter: private network adapter structure
+ *
+ * This watchdog task is scheduled to detect error case where hardware has
+ * dropped an Rx packet that was timestamped when the ring is full. The
+ * particular error is rare but leaves the device in a state unable to timestamp
+ * any future packets.
+ */
+void igb_ptp_rx_hang(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct igb_ring *rx_ring;
+ u32 tsyncrxctl = rd32(E1000_TSYNCRXCTL);
+ unsigned long rx_event;
+ int n;
+
+ if (hw->mac.type != e1000_82576)
+ return;
+
+ /* If we don't have a valid timestamp in the registers, just update the
+ * timeout counter and exit
+ */
+ if (!(tsyncrxctl & E1000_TSYNCRXCTL_VALID)) {
+ adapter->last_rx_ptp_check = jiffies;
+ return;
+ }
+
+ /* Determine the most recent watchdog or rx_timestamp event */
+ rx_event = adapter->last_rx_ptp_check;
+ for (n = 0; n < adapter->num_rx_queues; n++) {
+ rx_ring = adapter->rx_ring[n];
+ if (time_after(rx_ring->last_rx_timestamp, rx_event))
+ rx_event = rx_ring->last_rx_timestamp;
+ }
+
+ /* Only need to read the high RXSTMP register to clear the lock */
+ if (time_is_before_jiffies(rx_event + 5 * HZ)) {
+ rd32(E1000_RXSTMPH);
+ adapter->last_rx_ptp_check = jiffies;
+ adapter->rx_hwtstamp_cleared++;
+ dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang");
+ }
+}
+
+/**
* igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
* @adapter: Board private structure.
*
@@ -643,7 +699,6 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
else
wr32(E1000_ETQF(3), 0);
-#define PTP_PORT 319
/* L4 Queue Filter[3]: filter by destination port and protocol */
if (is_l4) {
u32 ftqf = (IPPROTO_UDP /* UDP */
@@ -652,12 +707,12 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
| E1000_FTQF_MASK); /* mask all inputs */
ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */
- wr32(E1000_IMIR(3), htons(PTP_PORT));
+ wr32(E1000_IMIR(3), htons(PTP_EV_PORT));
wr32(E1000_IMIREXT(3),
(E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP));
if (hw->mac.type == e1000_82576) {
/* enable source port check */
- wr32(E1000_SPQF(3), htons(PTP_PORT));
+ wr32(E1000_SPQF(3), htons(PTP_EV_PORT));
ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
}
wr32(E1000_FTQF(3), ftqf);
@@ -801,6 +856,10 @@ void igb_ptp_stop(struct igb_adapter *adapter)
}
cancel_work_sync(&adapter->ptp_tx_work);
+ if (adapter->ptp_tx_skb) {
+ dev_kfree_skb_any(adapter->ptp_tx_skb);
+ adapter->ptp_tx_skb = NULL;
+ }
if (adapter->ptp_clock) {
ptp_clock_unregister(adapter->ptp_clock);
diff --git a/drivers/net/ethernet/intel/igbvf/igbvf.h b/drivers/net/ethernet/intel/igbvf/igbvf.h
index fdca7b672776..a1463e3d14c0 100644
--- a/drivers/net/ethernet/intel/igbvf/igbvf.h
+++ b/drivers/net/ethernet/intel/igbvf/igbvf.h
@@ -127,8 +127,8 @@ struct igbvf_buffer {
/* Tx */
struct {
unsigned long time_stamp;
+ union e1000_adv_tx_desc *next_to_watch;
u16 length;
- u16 next_to_watch;
u16 mapped_as_page;
};
/* Rx */
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 277f5dfe3d90..d60cd4393415 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -797,20 +797,31 @@ static bool igbvf_clean_tx_irq(struct igbvf_ring *tx_ring)
struct sk_buff *skb;
union e1000_adv_tx_desc *tx_desc, *eop_desc;
unsigned int total_bytes = 0, total_packets = 0;
- unsigned int i, eop, count = 0;
+ unsigned int i, count = 0;
bool cleaned = false;
i = tx_ring->next_to_clean;
- eop = tx_ring->buffer_info[i].next_to_watch;
- eop_desc = IGBVF_TX_DESC_ADV(*tx_ring, eop);
+ buffer_info = &tx_ring->buffer_info[i];
+ eop_desc = buffer_info->next_to_watch;
+
+ do {
+ /* if next_to_watch is not set then there is no work pending */
+ if (!eop_desc)
+ break;
+
+ /* prevent any other reads prior to eop_desc */
+ read_barrier_depends();
+
+ /* if DD is not set pending work has not been completed */
+ if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
+ break;
+
+ /* clear next_to_watch to prevent false hangs */
+ buffer_info->next_to_watch = NULL;
- while ((eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)) &&
- (count < tx_ring->count)) {
- rmb(); /* read buffer_info after eop_desc status */
for (cleaned = false; !cleaned; count++) {
tx_desc = IGBVF_TX_DESC_ADV(*tx_ring, i);
- buffer_info = &tx_ring->buffer_info[i];
- cleaned = (i == eop);
+ cleaned = (tx_desc == eop_desc);
skb = buffer_info->skb;
if (skb) {
@@ -831,10 +842,12 @@ static bool igbvf_clean_tx_irq(struct igbvf_ring *tx_ring)
i++;
if (i == tx_ring->count)
i = 0;
+
+ buffer_info = &tx_ring->buffer_info[i];
}
- eop = tx_ring->buffer_info[i].next_to_watch;
- eop_desc = IGBVF_TX_DESC_ADV(*tx_ring, eop);
- }
+
+ eop_desc = buffer_info->next_to_watch;
+ } while (count < tx_ring->count);
tx_ring->next_to_clean = i;
@@ -1399,12 +1412,10 @@ static void igbvf_set_multi(struct net_device *netdev)
int i;
if (!netdev_mc_empty(netdev)) {
- mta_list = kmalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC);
- if (!mta_list) {
- dev_err(&adapter->pdev->dev,
- "failed to allocate multicast filter list\n");
+ mta_list = kmalloc_array(netdev_mc_count(netdev), ETH_ALEN,
+ GFP_ATOMIC);
+ if (!mta_list)
return;
- }
}
/* prepare a packed array of only addresses. */
@@ -1738,7 +1749,6 @@ static int igbvf_set_mac(struct net_device *netdev, void *p)
return -EADDRNOTAVAIL;
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
- netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
return 0;
}
@@ -1964,7 +1974,6 @@ static int igbvf_tso(struct igbvf_adapter *adapter,
context_desc->seqnum_seed = 0;
buffer_info->time_stamp = jiffies;
- buffer_info->next_to_watch = i;
buffer_info->dma = 0;
i++;
if (i == tx_ring->count)
@@ -2024,7 +2033,6 @@ static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter,
context_desc->mss_l4len_idx = 0;
buffer_info->time_stamp = jiffies;
- buffer_info->next_to_watch = i;
buffer_info->dma = 0;
i++;
if (i == tx_ring->count)
@@ -2064,8 +2072,7 @@ static int igbvf_maybe_stop_tx(struct net_device *netdev, int size)
static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
struct igbvf_ring *tx_ring,
- struct sk_buff *skb,
- unsigned int first)
+ struct sk_buff *skb)
{
struct igbvf_buffer *buffer_info;
struct pci_dev *pdev = adapter->pdev;
@@ -2080,7 +2087,6 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
buffer_info->length = len;
/* set time_stamp *before* dma to help avoid a possible race */
buffer_info->time_stamp = jiffies;
- buffer_info->next_to_watch = i;
buffer_info->mapped_as_page = false;
buffer_info->dma = dma_map_single(&pdev->dev, skb->data, len,
DMA_TO_DEVICE);
@@ -2103,7 +2109,6 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
BUG_ON(len >= IGBVF_MAX_DATA_PER_TXD);
buffer_info->length = len;
buffer_info->time_stamp = jiffies;
- buffer_info->next_to_watch = i;
buffer_info->mapped_as_page = true;
buffer_info->dma = skb_frag_dma_map(&pdev->dev, frag, 0, len,
DMA_TO_DEVICE);
@@ -2112,7 +2117,6 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
}
tx_ring->buffer_info[i].skb = skb;
- tx_ring->buffer_info[first].next_to_watch = i;
return ++count;
@@ -2123,7 +2127,6 @@ dma_error:
buffer_info->dma = 0;
buffer_info->time_stamp = 0;
buffer_info->length = 0;
- buffer_info->next_to_watch = 0;
buffer_info->mapped_as_page = false;
if (count)
count--;
@@ -2142,7 +2145,8 @@ dma_error:
static inline void igbvf_tx_queue_adv(struct igbvf_adapter *adapter,
struct igbvf_ring *tx_ring,
- int tx_flags, int count, u32 paylen,
+ int tx_flags, int count,
+ unsigned int first, u32 paylen,
u8 hdr_len)
{
union e1000_adv_tx_desc *tx_desc = NULL;
@@ -2192,6 +2196,7 @@ static inline void igbvf_tx_queue_adv(struct igbvf_adapter *adapter,
* such as IA-64). */
wmb();
+ tx_ring->buffer_info[first].next_to_watch = tx_desc;
tx_ring->next_to_use = i;
writel(i, adapter->hw.hw_addr + tx_ring->tail);
/* we need this if more than one processor can write to our tail
@@ -2258,11 +2263,11 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb,
* count reflects descriptors mapped, if 0 then mapping error
* has occurred and we need to rewind the descriptor queue
*/
- count = igbvf_tx_map_adv(adapter, tx_ring, skb, first);
+ count = igbvf_tx_map_adv(adapter, tx_ring, skb);
if (count) {
igbvf_tx_queue_adv(adapter, tx_ring, tx_flags, count,
- skb->len, hdr_len);
+ first, skb->len, hdr_len);
/* Make sure there is space in the ring for the next send. */
igbvf_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 4);
} else {
@@ -2736,30 +2741,24 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = hw->mac.ops.reset_hw(hw);
if (err) {
dev_info(&pdev->dev,
- "PF still in reset state, assigning new address."
- " Is the PF interface up?\n");
- eth_hw_addr_random(netdev);
- memcpy(adapter->hw.mac.addr, netdev->dev_addr,
- netdev->addr_len);
+ "PF still in reset state. Is the PF interface up?\n");
} else {
err = hw->mac.ops.read_mac_addr(hw);
- if (err) {
- dev_err(&pdev->dev, "Error reading MAC address\n");
- goto err_hw_init;
- }
+ if (err)
+ dev_info(&pdev->dev, "Error reading MAC address.\n");
+ else if (is_zero_ether_addr(adapter->hw.mac.addr))
+ dev_info(&pdev->dev, "MAC address not assigned by administrator.\n");
memcpy(netdev->dev_addr, adapter->hw.mac.addr,
- netdev->addr_len);
+ netdev->addr_len);
}
if (!is_valid_ether_addr(netdev->dev_addr)) {
- dev_err(&pdev->dev, "Invalid MAC Address: %pM\n",
- netdev->dev_addr);
- err = -EIO;
- goto err_hw_init;
+ dev_info(&pdev->dev, "Assigning random MAC address.\n");
+ eth_hw_addr_random(netdev);
+ memcpy(adapter->hw.mac.addr, netdev->dev_addr,
+ netdev->addr_len);
}
- memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
-
setup_timer(&adapter->watchdog_timer, &igbvf_watchdog,
(unsigned long) adapter);
diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
index ae96c10251be..ea4808373435 100644
--- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
@@ -500,9 +500,8 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr);
- memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
- if (!is_valid_ether_addr(netdev->perm_addr)) {
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
netif_err(adapter, probe, adapter->netdev, "Invalid MAC Address\n");
err = -EIO;
goto err_eeprom;
@@ -709,11 +708,8 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter)
size = sizeof(struct ixgb_buffer) * txdr->count;
txdr->buffer_info = vzalloc(size);
- if (!txdr->buffer_info) {
- netif_err(adapter, probe, adapter->netdev,
- "Unable to allocate transmit descriptor ring memory\n");
+ if (!txdr->buffer_info)
return -ENOMEM;
- }
/* round up to nearest 4K */
@@ -798,11 +794,8 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter)
size = sizeof(struct ixgb_buffer) * rxdr->count;
rxdr->buffer_info = vzalloc(size);
- if (!rxdr->buffer_info) {
- netif_err(adapter, probe, adapter->netdev,
- "Unable to allocate receive descriptor ring\n");
+ if (!rxdr->buffer_info)
return -ENOMEM;
- }
/* Round up to nearest 4K */
diff --git a/drivers/net/ethernet/intel/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile
index 687c83d1bdab..be2989e60009 100644
--- a/drivers/net/ethernet/intel/ixgbe/Makefile
+++ b/drivers/net/ethernet/intel/ixgbe/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
# Intel 10 Gigabit PCI Express Linux driver
-# Copyright(c) 1999 - 2012 Intel Corporation.
+# Copyright(c) 1999 - 2013 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 8e786764c60e..a8e10cff7a89 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -35,6 +35,7 @@
#include <linux/cpumask.h>
#include <linux/aer.h>
#include <linux/if_vlan.h>
+#include <linux/jiffies.h>
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
@@ -91,21 +92,26 @@
*/
#define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256
-#define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
-
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */
-#define IXGBE_TX_FLAGS_CSUM (u32)(1)
-#define IXGBE_TX_FLAGS_HW_VLAN (u32)(1 << 1)
-#define IXGBE_TX_FLAGS_SW_VLAN (u32)(1 << 2)
-#define IXGBE_TX_FLAGS_TSO (u32)(1 << 3)
-#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 4)
-#define IXGBE_TX_FLAGS_FCOE (u32)(1 << 5)
-#define IXGBE_TX_FLAGS_FSO (u32)(1 << 6)
-#define IXGBE_TX_FLAGS_TXSW (u32)(1 << 7)
-#define IXGBE_TX_FLAGS_TSTAMP (u32)(1 << 8)
-#define IXGBE_TX_FLAGS_NO_IFCS (u32)(1 << 9)
+enum ixgbe_tx_flags {
+ /* cmd_type flags */
+ IXGBE_TX_FLAGS_HW_VLAN = 0x01,
+ IXGBE_TX_FLAGS_TSO = 0x02,
+ IXGBE_TX_FLAGS_TSTAMP = 0x04,
+
+ /* olinfo flags */
+ IXGBE_TX_FLAGS_CC = 0x08,
+ IXGBE_TX_FLAGS_IPV4 = 0x10,
+ IXGBE_TX_FLAGS_CSUM = 0x20,
+
+ /* software defined flags */
+ IXGBE_TX_FLAGS_SW_VLAN = 0x40,
+ IXGBE_TX_FLAGS_FCOE = 0x80,
+};
+
+/* VLAN info */
#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000
#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
#define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT 29
@@ -150,7 +156,7 @@ struct vf_macvlans {
/* Tx Descriptors needed, worst case */
#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IXGBE_MAX_DATA_PER_TXD)
-#define DESC_NEEDED ((MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE)) + 4)
+#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
@@ -195,6 +201,7 @@ struct ixgbe_rx_queue_stats {
enum ixgbe_ring_state_t {
__IXGBE_TX_FDIR_INIT_DONE,
+ __IXGBE_TX_XPS_INIT_DONE,
__IXGBE_TX_DETECT_HANG,
__IXGBE_HANG_CHECK_ARMED,
__IXGBE_RX_RSC_ENABLED,
@@ -224,6 +231,7 @@ struct ixgbe_ring {
struct ixgbe_tx_buffer *tx_buffer_info;
struct ixgbe_rx_buffer *rx_buffer_info;
};
+ unsigned long last_rx_timestamp;
unsigned long state;
u8 __iomem *tail;
dma_addr_t dma; /* phys. address of descriptor ring */
@@ -271,15 +279,10 @@ enum ixgbe_ring_f_enum {
#define IXGBE_MAX_RSS_INDICES 16
#define IXGBE_MAX_VMDQ_INDICES 64
-#define IXGBE_MAX_FDIR_INDICES 64
-#ifdef IXGBE_FCOE
+#define IXGBE_MAX_FDIR_INDICES 63 /* based on q_vector limit */
#define IXGBE_MAX_FCOE_INDICES 8
-#define MAX_RX_QUEUES (IXGBE_MAX_FDIR_INDICES + IXGBE_MAX_FCOE_INDICES)
-#define MAX_TX_QUEUES (IXGBE_MAX_FDIR_INDICES + IXGBE_MAX_FCOE_INDICES)
-#else
-#define MAX_RX_QUEUES IXGBE_MAX_FDIR_INDICES
-#define MAX_TX_QUEUES IXGBE_MAX_FDIR_INDICES
-#endif /* IXGBE_FCOE */
+#define MAX_RX_QUEUES (IXGBE_MAX_FDIR_INDICES + 1)
+#define MAX_TX_QUEUES (IXGBE_MAX_FDIR_INDICES + 1)
struct ixgbe_ring_feature {
u16 limit; /* upper limit on feature indices */
u16 indices; /* current value of indices */
@@ -573,11 +576,14 @@ struct ixgbe_adapter {
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps;
+ struct work_struct ptp_tx_work;
+ struct sk_buff *ptp_tx_skb;
+ unsigned long ptp_tx_start;
unsigned long last_overflow_check;
+ unsigned long last_rx_ptp_check;
spinlock_t tmreg_lock;
struct cyclecounter cc;
struct timecounter tc;
- int rx_hwtstamp_filter;
u32 base_incval;
/* SR-IOV */
@@ -614,6 +620,7 @@ enum ixgbe_state_t {
__IXGBE_DOWN,
__IXGBE_SERVICE_SCHED,
__IXGBE_IN_SFP_INIT,
+ __IXGBE_READ_I2C,
};
struct ixgbe_cb {
@@ -694,8 +701,8 @@ extern bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw);
extern void ixgbe_set_rx_mode(struct net_device *netdev);
#ifdef CONFIG_IXGBE_DCB
extern void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter);
-extern int ixgbe_setup_tc(struct net_device *dev, u8 tc);
#endif
+extern int ixgbe_setup_tc(struct net_device *dev, u8 tc);
extern void ixgbe_tx_ctxtdesc(struct ixgbe_ring *, u32, u32, u32, u32);
extern void ixgbe_do_reset(struct net_device *netdev);
#ifdef CONFIG_IXGBE_HWMON
@@ -742,15 +749,32 @@ static inline struct netdev_queue *txring_txq(const struct ixgbe_ring *ring)
extern void ixgbe_ptp_init(struct ixgbe_adapter *adapter);
extern void ixgbe_ptp_stop(struct ixgbe_adapter *adapter);
extern void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter);
-extern void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
- struct sk_buff *skb);
-extern void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
- union ixgbe_adv_rx_desc *rx_desc,
- struct sk_buff *skb);
+extern void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter);
+extern void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
+ struct sk_buff *skb);
+static inline void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring,
+ union ixgbe_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ if (unlikely(!ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
+ return;
+
+ __ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, skb);
+
+ /*
+ * Update the last_rx_timestamp timer in order to enable watchdog check
+ * for error case of latched timestamp on a dropped packet.
+ */
+ rx_ring->last_rx_timestamp = jiffies;
+}
+
extern int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
struct ifreq *ifr, int cmd);
extern void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter);
extern void ixgbe_ptp_reset(struct ixgbe_adapter *adapter);
extern void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr);
+#ifdef CONFIG_PCI_IOV
+void ixgbe_sriov_reinit(struct ixgbe_adapter *adapter);
+#endif
#endif /* _IXGBE_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
index 42537336110c..d0113fc97b6f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -41,7 +41,6 @@
static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
- bool autoneg,
bool autoneg_wait_to_complete);
static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
u8 *eeprom_data);
@@ -633,15 +632,15 @@ out:
* ixgbe_setup_mac_link_82598 - Set MAC link speed
* @hw: pointer to hardware structure
* @speed: new link speed
- * @autoneg: true if auto-negotiation enabled
* @autoneg_wait_to_complete: true when waiting for completion is needed
*
* Set the link speed in the AUTOC register and restarts link.
**/
static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw,
- ixgbe_link_speed speed, bool autoneg,
- bool autoneg_wait_to_complete)
+ ixgbe_link_speed speed,
+ bool autoneg_wait_to_complete)
{
+ bool autoneg = false;
s32 status = 0;
ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN;
u32 curr_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
@@ -685,20 +684,18 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw,
* ixgbe_setup_copper_link_82598 - Set the PHY autoneg advertised field
* @hw: pointer to hardware structure
* @speed: new link speed
- * @autoneg: true if autonegotiation enabled
* @autoneg_wait_to_complete: true if waiting is needed to complete
*
* Sets the link speed in the AUTOC register in the MAC and restarts link.
**/
static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
- bool autoneg,
bool autoneg_wait_to_complete)
{
s32 status;
/* Setup the PHY according to input speed */
- status = hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+ status = hw->phy.ops.setup_link_speed(hw, speed,
autoneg_wait_to_complete);
/* Set up MAC */
ixgbe_start_mac_link_82598(hw, autoneg_wait_to_complete);
@@ -1006,15 +1003,16 @@ static s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val)
}
/**
- * ixgbe_read_i2c_eeprom_82598 - Reads 8 bit word over I2C interface.
+ * ixgbe_read_i2c_phy_82598 - Reads 8 bit word over I2C interface.
* @hw: pointer to hardware structure
- * @byte_offset: EEPROM byte offset to read
+ * @dev_addr: address to read from
+ * @byte_offset: byte offset to read from dev_addr
* @eeprom_data: value read
*
- * Performs 8 byte read operation to SFP module's EEPROM over I2C interface.
+ * Performs 8 byte read operation to SFP module's data over I2C interface.
**/
-static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
- u8 *eeprom_data)
+static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
+ u8 byte_offset, u8 *eeprom_data)
{
s32 status = 0;
u16 sfp_addr = 0;
@@ -1028,7 +1026,7 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
* 0xC30D. These registers are used to talk to the SFP+
* module's EEPROM through the SDA/SCL (I2C) interface.
*/
- sfp_addr = (IXGBE_I2C_EEPROM_DEV_ADDR << 8) + byte_offset;
+ sfp_addr = (dev_addr << 8) + byte_offset;
sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK);
hw->phy.ops.write_reg(hw,
IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR,
@@ -1060,7 +1058,6 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
*eeprom_data = (u8)(sfp_data >> 8);
} else {
status = IXGBE_ERR_PHY;
- goto out;
}
out:
@@ -1068,6 +1065,36 @@ out:
}
/**
+ * ixgbe_read_i2c_eeprom_82598 - Reads 8 bit word over I2C interface.
+ * @hw: pointer to hardware structure
+ * @byte_offset: EEPROM byte offset to read
+ * @eeprom_data: value read
+ *
+ * Performs 8 byte read operation to SFP module's EEPROM over I2C interface.
+ **/
+static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 *eeprom_data)
+{
+ return ixgbe_read_i2c_phy_82598(hw, IXGBE_I2C_EEPROM_DEV_ADDR,
+ byte_offset, eeprom_data);
+}
+
+/**
+ * ixgbe_read_i2c_sff8472_82598 - Reads 8 bit word over I2C interface.
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset at address 0xA2
+ * @eeprom_data: value read
+ *
+ * Performs 8 byte read operation to SFP module's SFF-8472 data over I2C
+ **/
+static s32 ixgbe_read_i2c_sff8472_82598(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 *sff8472_data)
+{
+ return ixgbe_read_i2c_phy_82598(hw, IXGBE_I2C_EEPROM_DEV_ADDR2,
+ byte_offset, sff8472_data);
+}
+
+/**
* ixgbe_get_supported_physical_layer_82598 - Returns physical layer type
* @hw: pointer to hardware structure
*
@@ -1300,6 +1327,7 @@ static struct ixgbe_phy_operations phy_ops_82598 = {
.write_reg = &ixgbe_write_phy_reg_generic,
.setup_link = &ixgbe_setup_phy_link_generic,
.setup_link_speed = &ixgbe_setup_phy_link_speed_generic,
+ .read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_82598,
.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_82598,
.check_overtemp = &ixgbe_tn_check_overtemp,
};
@@ -1311,4 +1339,3 @@ struct ixgbe_info ixgbe_82598_info = {
.eeprom_ops = &eeprom_ops_82598,
.phy_ops = &phy_ops_82598,
};
-
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index 1073aea5da40..203a00c24330 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -45,21 +45,17 @@ static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
static void ixgbe_flap_tx_laser_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);
static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
- bool autoneg,
bool autoneg_wait_to_complete);
static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
bool autoneg_wait_to_complete);
static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
- bool autoneg,
bool autoneg_wait_to_complete);
static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
- bool autoneg,
bool autoneg_wait_to_complete);
static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw);
@@ -234,13 +230,13 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw)
* ixgbe_get_link_capabilities_82599 - Determines link capabilities
* @hw: pointer to hardware structure
* @speed: pointer to link speed
- * @negotiation: true when autoneg or autotry is enabled
+ * @autoneg: true when autoneg or autotry is enabled
*
* Determines the link capabilities by reading the AUTOC register.
**/
static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
ixgbe_link_speed *speed,
- bool *negotiation)
+ bool *autoneg)
{
s32 status = 0;
u32 autoc = 0;
@@ -251,7 +247,7 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
*speed = IXGBE_LINK_SPEED_1GB_FULL;
- *negotiation = true;
+ *autoneg = true;
goto out;
}
@@ -268,22 +264,22 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
switch (autoc & IXGBE_AUTOC_LMS_MASK) {
case IXGBE_AUTOC_LMS_1G_LINK_NO_AN:
*speed = IXGBE_LINK_SPEED_1GB_FULL;
- *negotiation = false;
+ *autoneg = false;
break;
case IXGBE_AUTOC_LMS_10G_LINK_NO_AN:
*speed = IXGBE_LINK_SPEED_10GB_FULL;
- *negotiation = false;
+ *autoneg = false;
break;
case IXGBE_AUTOC_LMS_1G_AN:
*speed = IXGBE_LINK_SPEED_1GB_FULL;
- *negotiation = true;
+ *autoneg = true;
break;
case IXGBE_AUTOC_LMS_10G_SERIAL:
*speed = IXGBE_LINK_SPEED_10GB_FULL;
- *negotiation = false;
+ *autoneg = false;
break;
case IXGBE_AUTOC_LMS_KX4_KX_KR:
@@ -295,7 +291,7 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
*speed |= IXGBE_LINK_SPEED_10GB_FULL;
if (autoc & IXGBE_AUTOC_KX_SUPP)
*speed |= IXGBE_LINK_SPEED_1GB_FULL;
- *negotiation = true;
+ *autoneg = true;
break;
case IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII:
@@ -306,12 +302,12 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
*speed |= IXGBE_LINK_SPEED_10GB_FULL;
if (autoc & IXGBE_AUTOC_KX_SUPP)
*speed |= IXGBE_LINK_SPEED_1GB_FULL;
- *negotiation = true;
+ *autoneg = true;
break;
case IXGBE_AUTOC_LMS_SGMII_1G_100M:
*speed = IXGBE_LINK_SPEED_1GB_FULL | IXGBE_LINK_SPEED_100_FULL;
- *negotiation = false;
+ *autoneg = false;
break;
default:
@@ -323,7 +319,7 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
if (hw->phy.multispeed_fiber) {
*speed |= IXGBE_LINK_SPEED_10GB_FULL |
IXGBE_LINK_SPEED_1GB_FULL;
- *negotiation = true;
+ *autoneg = true;
}
out:
@@ -510,14 +506,12 @@ static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
* ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed
* @hw: pointer to hardware structure
* @speed: new link speed
- * @autoneg: true if autonegotiation enabled
* @autoneg_wait_to_complete: true when waiting for completion is needed
*
* Set the link speed in the AUTOC register and restarts link.
**/
static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
- bool autoneg,
bool autoneg_wait_to_complete)
{
s32 status = 0;
@@ -527,11 +521,11 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
u32 i = 0;
bool link_up = false;
- bool negotiation;
+ bool autoneg = false;
/* Mask off requested but non-supported speeds */
status = hw->mac.ops.get_link_capabilities(hw, &link_speed,
- &negotiation);
+ &autoneg);
if (status != 0)
return status;
@@ -564,7 +558,6 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
status = ixgbe_setup_mac_link_82599(hw,
IXGBE_LINK_SPEED_10GB_FULL,
- autoneg,
autoneg_wait_to_complete);
if (status != 0)
return status;
@@ -617,7 +610,6 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
status = ixgbe_setup_mac_link_82599(hw,
IXGBE_LINK_SPEED_1GB_FULL,
- autoneg,
autoneg_wait_to_complete);
if (status != 0)
return status;
@@ -646,7 +638,6 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
if (speedcnt > 1)
status = ixgbe_setup_mac_link_multispeed_fiber(hw,
highest_link_speed,
- autoneg,
autoneg_wait_to_complete);
out:
@@ -666,13 +657,12 @@ out:
* ixgbe_setup_mac_link_smartspeed - Set MAC link speed using SmartSpeed
* @hw: pointer to hardware structure
* @speed: new link speed
- * @autoneg: true if autonegotiation enabled
* @autoneg_wait_to_complete: true when waiting for completion is needed
*
* Implements the Intel SmartSpeed algorithm.
**/
static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
- ixgbe_link_speed speed, bool autoneg,
+ ixgbe_link_speed speed,
bool autoneg_wait_to_complete)
{
s32 status = 0;
@@ -703,7 +693,7 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
/* First, try to get link with full advertisement */
hw->phy.smart_speed_active = false;
for (j = 0; j < IXGBE_SMARTSPEED_MAX_RETRIES; j++) {
- status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+ status = ixgbe_setup_mac_link_82599(hw, speed,
autoneg_wait_to_complete);
if (status != 0)
goto out;
@@ -738,7 +728,7 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
/* Turn SmartSpeed on to disable KR support */
hw->phy.smart_speed_active = true;
- status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+ status = ixgbe_setup_mac_link_82599(hw, speed,
autoneg_wait_to_complete);
if (status != 0)
goto out;
@@ -764,7 +754,7 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
/* We didn't get link. Turn SmartSpeed back off. */
hw->phy.smart_speed_active = false;
- status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+ status = ixgbe_setup_mac_link_82599(hw, speed,
autoneg_wait_to_complete);
out:
@@ -778,14 +768,13 @@ out:
* ixgbe_setup_mac_link_82599 - Set MAC link speed
* @hw: pointer to hardware structure
* @speed: new link speed
- * @autoneg: true if autonegotiation enabled
* @autoneg_wait_to_complete: true when waiting for completion is needed
*
* Set the link speed in the AUTOC register and restarts link.
**/
static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
- ixgbe_link_speed speed, bool autoneg,
- bool autoneg_wait_to_complete)
+ ixgbe_link_speed speed,
+ bool autoneg_wait_to_complete)
{
s32 status = 0;
u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
@@ -799,6 +788,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
u32 i;
ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN;
bool got_lock = false;
+ bool autoneg = false;
/* Check to see if speed passed in is supported. */
status = hw->mac.ops.get_link_capabilities(hw, &link_capabilities,
@@ -911,20 +901,18 @@ out:
* ixgbe_setup_copper_link_82599 - Set the PHY autoneg advertised field
* @hw: pointer to hardware structure
* @speed: new link speed
- * @autoneg: true if autonegotiation enabled
* @autoneg_wait_to_complete: true if waiting is needed to complete
*
* Restarts link on PHY and MAC based on settings passed in.
**/
static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
- bool autoneg,
bool autoneg_wait_to_complete)
{
s32 status;
/* Setup the PHY according to input speed */
- status = hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+ status = hw->phy.ops.setup_link_speed(hw, speed,
autoneg_wait_to_complete);
/* Set up MAC */
ixgbe_start_mac_link_82599(hw, autoneg_wait_to_complete);
@@ -2253,6 +2241,7 @@ static struct ixgbe_phy_operations phy_ops_82599 = {
.setup_link_speed = &ixgbe_setup_phy_link_speed_generic,
.read_i2c_byte = &ixgbe_read_i2c_byte_generic,
.write_i2c_byte = &ixgbe_write_i2c_byte_generic,
+ .read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_generic,
.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic,
.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic,
.check_overtemp = &ixgbe_tn_check_overtemp,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index 5e68afdd502a..99e472ebaa75 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
index f7a0970a251c..bc3948ead6e0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
index 9bc17c0cb972..1f2c805684dd 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
index 1f4108ee154b..1634de8b627f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
index 87592b458c9c..ac780770863d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h
index ba835708fcac..3164f5453b8f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
index 4eac80d01857..05e23b80b5e3 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
index 4dec47faeb00..a4ef07631d1e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
index f1e002d5fa8f..f3d68f9696ba 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -30,6 +30,7 @@
#include <linux/dcbnl.h>
#include "ixgbe_dcb_82598.h"
#include "ixgbe_dcb_82599.h"
+#include "ixgbe_sriov.h"
/* Callbacks for DCB netlink in the kernel */
#define BIT_DCB_MODE 0x01
@@ -301,7 +302,6 @@ static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority,
*setting = adapter->dcb_cfg.tc_config[priority].dcb_pfc;
}
-#ifdef IXGBE_FCOE
static void ixgbe_dcbnl_devreset(struct net_device *dev)
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
@@ -320,7 +320,6 @@ static void ixgbe_dcbnl_devreset(struct net_device *dev)
clear_bit(__IXGBE_RESETTING, &adapter->state);
}
-#endif
static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
{
@@ -450,7 +449,6 @@ static u8 ixgbe_dcbnl_getcap(struct net_device *netdev, int capid, u8 *cap)
static int ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- u8 rval = 0;
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
switch (tcid) {
@@ -461,14 +459,14 @@ static int ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
*num = adapter->dcb_cfg.num_tcs.pfc_tcs;
break;
default:
- rval = -EINVAL;
+ return -EINVAL;
break;
}
} else {
- rval = -EINVAL;
+ return -EINVAL;
}
- return rval;
+ return 0;
}
static int ixgbe_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num)
@@ -541,6 +539,7 @@ static int ixgbe_dcbnl_ieee_setets(struct net_device *dev,
int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
int i, err = 0;
__u8 max_tc = 0;
+ __u8 map_chg = 0;
if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
@@ -550,15 +549,22 @@ static int ixgbe_dcbnl_ieee_setets(struct net_device *dev,
GFP_KERNEL);
if (!adapter->ixgbe_ieee_ets)
return -ENOMEM;
- }
- memcpy(adapter->ixgbe_ieee_ets, ets, sizeof(*adapter->ixgbe_ieee_ets));
+ /* initialize UP2TC mappings to invalid value */
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
+ adapter->ixgbe_ieee_ets->prio_tc[i] =
+ IEEE_8021QAZ_MAX_TCS;
+ }
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
if (ets->prio_tc[i] > max_tc)
max_tc = ets->prio_tc[i];
+ if (ets->prio_tc[i] != adapter->ixgbe_ieee_ets->prio_tc[i])
+ map_chg = 1;
}
+ memcpy(adapter->ixgbe_ieee_ets, ets, sizeof(*adapter->ixgbe_ieee_ets));
+
if (max_tc)
max_tc++;
@@ -567,6 +573,8 @@ static int ixgbe_dcbnl_ieee_setets(struct net_device *dev,
if (max_tc != netdev_get_num_tc(dev))
err = ixgbe_setup_tc(dev, max_tc);
+ else if (map_chg)
+ ixgbe_dcbnl_devreset(dev);
if (err)
goto err_out;
@@ -643,9 +651,11 @@ static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev,
return err;
err = dcb_ieee_setapp(dev, app);
+ if (err)
+ return err;
#ifdef IXGBE_FCOE
- if (!err && app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+ if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
app->protocol == ETH_P_FCOE) {
u8 app_mask = dcb_ieee_getapp_mask(dev, app);
@@ -656,6 +666,23 @@ static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev,
ixgbe_dcbnl_devreset(dev);
}
#endif
+
+ /* VF devices should use default UP when available */
+ if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+ app->protocol == 0) {
+ int vf;
+
+ adapter->default_up = app->priority;
+
+ for (vf = 0; vf < adapter->num_vfs; vf++) {
+ struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+
+ if (!vfinfo->pf_qos)
+ ixgbe_set_vmvir(adapter, vfinfo->pf_vlan,
+ app->priority, vf);
+ }
+ }
+
return 0;
}
@@ -683,6 +710,24 @@ static int ixgbe_dcbnl_ieee_delapp(struct net_device *dev,
ixgbe_dcbnl_devreset(dev);
}
#endif
+ /* IF default priority is being removed clear VF default UP */
+ if (app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
+ app->protocol == 0 && adapter->default_up == app->priority) {
+ int vf;
+ long unsigned int app_mask = dcb_ieee_getapp_mask(dev, app);
+ int qos = app_mask ? find_first_bit(&app_mask, 8) : 0;
+
+ adapter->default_up = qos;
+
+ for (vf = 0; vf < adapter->num_vfs; vf++) {
+ struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+
+ if (!vfinfo->pf_qos)
+ ixgbe_set_vmvir(adapter, vfinfo->pf_vlan,
+ qos, vf);
+ }
+ }
+
return err;
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
index 3504686d3af5..c5933f6dceee 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 326858424345..f4d2e9e3c6d5 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -39,6 +39,7 @@
#include <linux/uaccess.h>
#include "ixgbe.h"
+#include "ixgbe_phy.h"
#define IXGBE_ALL_RAR_ENTRIES 16
@@ -156,7 +157,7 @@ static int ixgbe_get_settings(struct net_device *netdev,
struct ixgbe_hw *hw = &adapter->hw;
ixgbe_link_speed supported_link;
u32 link_speed = 0;
- bool autoneg;
+ bool autoneg = false;
bool link_up;
hw->mac.ops.get_link_capabilities(hw, &supported_link, &autoneg);
@@ -333,10 +334,10 @@ static int ixgbe_set_settings(struct net_device *netdev,
return err;
/* this sets the link speed and restarts auto-neg */
hw->mac.autotry_restart = true;
- err = hw->mac.ops.setup_link(hw, advertised, true, true);
+ err = hw->mac.ops.setup_link(hw, advertised, true);
if (err) {
e_info(probe, "setup link failed with code %d\n", err);
- hw->mac.ops.setup_link(hw, old, true, true);
+ hw->mac.ops.setup_link(hw, old, true);
}
} else {
/* in this case we currently only support 10Gb/FULL */
@@ -1040,6 +1041,9 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
p = (char *) adapter +
ixgbe_gstrings_stats[i].stat_offset;
break;
+ default:
+ data[i] = 0;
+ continue;
}
data[i] = (ixgbe_gstrings_stats[i].sizeof_stat ==
@@ -1096,8 +1100,10 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
switch (stringset) {
case ETH_SS_TEST:
- memcpy(data, *ixgbe_gstrings_test,
- IXGBE_TEST_LEN * ETH_GSTRING_LEN);
+ for (i = 0; i < IXGBE_TEST_LEN; i++) {
+ memcpy(data, ixgbe_gstrings_test[i], ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
break;
case ETH_SS_STATS:
for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
@@ -1837,19 +1843,11 @@ static void ixgbe_diag_test(struct net_device *netdev,
struct ethtool_test *eth_test, u64 *data)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
bool if_running = netif_running(netdev);
set_bit(__IXGBE_TESTING, &adapter->state);
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
- /* Offline tests */
-
- e_info(hw, "offline testing starting\n");
-
- /* Link test performed before hardware reset so autoneg doesn't
- * interfere with test result */
- if (ixgbe_link_test(adapter, &data[4]))
- eth_test->flags |= ETH_TEST_FL_FAILED;
-
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
int i;
for (i = 0; i < adapter->num_vfs; i++) {
@@ -1870,12 +1868,24 @@ static void ixgbe_diag_test(struct net_device *netdev,
}
}
+ /* Offline tests */
+ e_info(hw, "offline testing starting\n");
+
if (if_running)
/* indicate we're in test mode */
dev_close(netdev);
- else
- ixgbe_reset(adapter);
+ /* bringing adapter down disables SFP+ optics */
+ if (hw->mac.ops.enable_tx_laser)
+ hw->mac.ops.enable_tx_laser(hw);
+
+ /* Link test performed before hardware reset so autoneg doesn't
+ * interfere with test result
+ */
+ if (ixgbe_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ ixgbe_reset(adapter);
e_info(hw, "register testing starting\n");
if (ixgbe_reg_test(adapter, &data[0]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1908,16 +1918,22 @@ static void ixgbe_diag_test(struct net_device *netdev,
skip_loopback:
ixgbe_reset(adapter);
+ /* clear testing bit and return adapter to previous state */
clear_bit(__IXGBE_TESTING, &adapter->state);
if (if_running)
dev_open(netdev);
} else {
e_info(hw, "online testing starting\n");
+
+ /* if adapter is down, SFP+ optics will be disabled */
+ if (!if_running && hw->mac.ops.enable_tx_laser)
+ hw->mac.ops.enable_tx_laser(hw);
+
/* Online tests */
if (ixgbe_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
- /* Online tests aren't run; pass by default */
+ /* Offline tests aren't run; pass by default */
data[0] = 0;
data[1] = 0;
data[2] = 0;
@@ -1925,6 +1941,10 @@ skip_loopback:
clear_bit(__IXGBE_TESTING, &adapter->state);
}
+
+ /* if adapter was down, ensure SFP+ optics are disabled again */
+ if (!if_running && hw->mac.ops.disable_tx_laser)
+ hw->mac.ops.disable_tx_laser(hw);
skip_ol_tests:
msleep_interruptible(4 * 1000);
}
@@ -2093,13 +2113,17 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_q_vector *q_vector;
int i;
- u16 tx_itr_param, rx_itr_param;
+ u16 tx_itr_param, rx_itr_param, tx_itr_prev;
bool need_reset = false;
- /* don't accept tx specific changes if we've got mixed RxTx vectors */
- if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count
- && ec->tx_coalesce_usecs)
- return -EINVAL;
+ if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count) {
+ /* reject Tx specific changes in case of mixed RxTx vectors */
+ if (ec->tx_coalesce_usecs)
+ return -EINVAL;
+ tx_itr_prev = adapter->rx_itr_setting;
+ } else {
+ tx_itr_prev = adapter->tx_itr_setting;
+ }
if ((ec->rx_coalesce_usecs > (IXGBE_MAX_EITR >> 2)) ||
(ec->tx_coalesce_usecs > (IXGBE_MAX_EITR >> 2)))
@@ -2125,8 +2149,25 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
else
tx_itr_param = adapter->tx_itr_setting;
+ /* mixed Rx/Tx */
+ if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count)
+ adapter->tx_itr_setting = adapter->rx_itr_setting;
+
+#if IS_ENABLED(CONFIG_BQL)
+ /* detect ITR changes that require update of TXDCTL.WTHRESH */
+ if ((adapter->tx_itr_setting > 1) &&
+ (adapter->tx_itr_setting < IXGBE_100K_ITR)) {
+ if ((tx_itr_prev == 1) ||
+ (tx_itr_prev > IXGBE_100K_ITR))
+ need_reset = true;
+ } else {
+ if ((tx_itr_prev > 1) &&
+ (tx_itr_prev < IXGBE_100K_ITR))
+ need_reset = true;
+ }
+#endif
/* check the old value and enable RSC if necessary */
- need_reset = ixgbe_update_rsc(adapter);
+ need_reset |= ixgbe_update_rsc(adapter);
for (i = 0; i < adapter->num_q_vectors; i++) {
q_vector = adapter->q_vector[i];
@@ -2695,6 +2736,14 @@ static int ixgbe_get_ts_info(struct net_device *dev,
(1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
break;
default:
@@ -2704,6 +2753,225 @@ static int ixgbe_get_ts_info(struct net_device *dev,
return 0;
}
+static unsigned int ixgbe_max_channels(struct ixgbe_adapter *adapter)
+{
+ unsigned int max_combined;
+ u8 tcs = netdev_get_num_tc(adapter->netdev);
+
+ if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
+ /* We only support one q_vector without MSI-X */
+ max_combined = 1;
+ } else if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+ /* SR-IOV currently only allows one queue on the PF */
+ max_combined = 1;
+ } else if (tcs > 1) {
+ /* For DCB report channels per traffic class */
+ if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+ /* 8 TC w/ 4 queues per TC */
+ max_combined = 4;
+ } else if (tcs > 4) {
+ /* 8 TC w/ 8 queues per TC */
+ max_combined = 8;
+ } else {
+ /* 4 TC w/ 16 queues per TC */
+ max_combined = 16;
+ }
+ } else if (adapter->atr_sample_rate) {
+ /* support up to 64 queues with ATR */
+ max_combined = IXGBE_MAX_FDIR_INDICES;
+ } else {
+ /* support up to 16 queues with RSS */
+ max_combined = IXGBE_MAX_RSS_INDICES;
+ }
+
+ return max_combined;
+}
+
+static void ixgbe_get_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
+
+ /* report maximum channels */
+ ch->max_combined = ixgbe_max_channels(adapter);
+
+ /* report info for other vector */
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+ ch->max_other = NON_Q_VECTORS;
+ ch->other_count = NON_Q_VECTORS;
+ }
+
+ /* record RSS queues */
+ ch->combined_count = adapter->ring_feature[RING_F_RSS].indices;
+
+ /* nothing else to report if RSS is disabled */
+ if (ch->combined_count == 1)
+ return;
+
+ /* we do not support ATR queueing if SR-IOV is enabled */
+ if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+ return;
+
+ /* same thing goes for being DCB enabled */
+ if (netdev_get_num_tc(dev) > 1)
+ return;
+
+ /* if ATR is disabled we can exit */
+ if (!adapter->atr_sample_rate)
+ return;
+
+ /* report flow director queues as maximum channels */
+ ch->combined_count = adapter->ring_feature[RING_F_FDIR].indices;
+}
+
+static int ixgbe_set_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
+ unsigned int count = ch->combined_count;
+
+ /* verify they are not requesting separate vectors */
+ if (!count || ch->rx_count || ch->tx_count)
+ return -EINVAL;
+
+ /* verify other_count has not changed */
+ if (ch->other_count != NON_Q_VECTORS)
+ return -EINVAL;
+
+ /* verify the number of channels does not exceed hardware limits */
+ if (count > ixgbe_max_channels(adapter))
+ return -EINVAL;
+
+ /* update feature limits from largest to smallest supported values */
+ adapter->ring_feature[RING_F_FDIR].limit = count;
+
+ /* cap RSS limit at 16 */
+ if (count > IXGBE_MAX_RSS_INDICES)
+ count = IXGBE_MAX_RSS_INDICES;
+ adapter->ring_feature[RING_F_RSS].limit = count;
+
+#ifdef IXGBE_FCOE
+ /* cap FCoE limit at 8 */
+ if (count > IXGBE_FCRETA_SIZE)
+ count = IXGBE_FCRETA_SIZE;
+ adapter->ring_feature[RING_F_FCOE].limit = count;
+
+#endif
+ /* use setup TC to update any traffic class queue mapping */
+ return ixgbe_setup_tc(dev, netdev_get_num_tc(dev));
+}
+
+static int ixgbe_get_module_info(struct net_device *dev,
+ struct ethtool_modinfo *modinfo)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 status;
+ u8 sff8472_rev, addr_mode;
+ int ret_val = 0;
+ bool page_swap = false;
+
+ /* avoid concurent i2c reads */
+ while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+ msleep(100);
+
+ /* used by the service task */
+ set_bit(__IXGBE_READ_I2C, &adapter->state);
+
+ /* Check whether we support SFF-8472 or not */
+ status = hw->phy.ops.read_i2c_eeprom(hw,
+ IXGBE_SFF_SFF_8472_COMP,
+ &sff8472_rev);
+ if (status != 0) {
+ ret_val = -EIO;
+ goto err_out;
+ }
+
+ /* addressing mode is not supported */
+ status = hw->phy.ops.read_i2c_eeprom(hw,
+ IXGBE_SFF_SFF_8472_SWAP,
+ &addr_mode);
+ if (status != 0) {
+ ret_val = -EIO;
+ goto err_out;
+ }
+
+ if (addr_mode & IXGBE_SFF_ADDRESSING_MODE) {
+ e_err(drv, "Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n");
+ page_swap = true;
+ }
+
+ if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap) {
+ /* We have a SFP, but it does not support SFF-8472 */
+ modinfo->type = ETH_MODULE_SFF_8079;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+ } else {
+ /* We have a SFP which supports a revision of SFF-8472. */
+ modinfo->type = ETH_MODULE_SFF_8472;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+ }
+
+err_out:
+ clear_bit(__IXGBE_READ_I2C, &adapter->state);
+ return ret_val;
+}
+
+static int ixgbe_get_module_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *ee,
+ u8 *data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+ u8 databyte = 0xFF;
+ int i = 0;
+ int ret_val = 0;
+
+ /* ixgbe_get_module_info is called before this function in all
+ * cases, so we do not need any checks we already do above,
+ * and can trust ee->len to be a known value.
+ */
+
+ while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+ msleep(100);
+ set_bit(__IXGBE_READ_I2C, &adapter->state);
+
+ /* Read the first block, SFF-8079 */
+ for (i = 0; i < ETH_MODULE_SFF_8079_LEN; i++) {
+ status = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte);
+ if (status != 0) {
+ /* Error occured while reading module */
+ ret_val = -EIO;
+ goto err_out;
+ }
+ data[i] = databyte;
+ }
+
+ /* If the second block is requested, check if SFF-8472 is supported. */
+ if (ee->len == ETH_MODULE_SFF_8472_LEN) {
+ if (data[IXGBE_SFF_SFF_8472_COMP] == IXGBE_SFF_SFF_8472_UNSUP)
+ return -EOPNOTSUPP;
+
+ /* Read the second block, SFF-8472 */
+ for (i = ETH_MODULE_SFF_8079_LEN;
+ i < ETH_MODULE_SFF_8472_LEN; i++) {
+ status = hw->phy.ops.read_i2c_sff8472(hw,
+ i - ETH_MODULE_SFF_8079_LEN, &databyte);
+ if (status != 0) {
+ /* Error occured while reading module */
+ ret_val = -EIO;
+ goto err_out;
+ }
+ data[i] = databyte;
+ }
+ }
+
+err_out:
+ clear_bit(__IXGBE_READ_I2C, &adapter->state);
+
+ return ret_val;
+}
+
static const struct ethtool_ops ixgbe_ethtool_ops = {
.get_settings = ixgbe_get_settings,
.set_settings = ixgbe_set_settings,
@@ -2732,7 +3000,11 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
.set_coalesce = ixgbe_set_coalesce,
.get_rxnfc = ixgbe_get_rxnfc,
.set_rxnfc = ixgbe_set_rxnfc,
+ .get_channels = ixgbe_get_channels,
+ .set_channels = ixgbe_set_channels,
.get_ts_info = ixgbe_get_ts_info,
+ .get_module_info = ixgbe_get_module_info,
+ .get_module_eeprom = ixgbe_get_module_eeprom,
};
void ixgbe_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
index 252850d9a3e0..f58db453a97e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -544,15 +544,14 @@ int ixgbe_fso(struct ixgbe_ring *tx_ring,
first->gso_segs = DIV_ROUND_UP(skb->len - *hdr_len,
skb_shinfo(skb)->gso_size);
first->bytecount += (first->gso_segs - 1) * *hdr_len;
- first->tx_flags |= IXGBE_TX_FLAGS_FSO;
+ first->tx_flags |= IXGBE_TX_FLAGS_TSO;
}
/* set flag indicating FCOE to ixgbe_tx_map call */
- first->tx_flags |= IXGBE_TX_FLAGS_FCOE;
+ first->tx_flags |= IXGBE_TX_FLAGS_FCOE | IXGBE_TX_FLAGS_CC;
- /* mss_l4len_id: use 1 for FSO as TSO, no need for L4LEN */
+ /* mss_l4len_id: use 0 for FSO as TSO, no need for L4LEN */
mss_l4len_idx = skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT;
- mss_l4len_idx |= 1 << IXGBE_ADVTXD_IDX_SHIFT;
/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
vlan_macip_lens = skb_transport_offset(skb) +
@@ -717,10 +716,8 @@ int ixgbe_setup_fcoe_ddp_resources(struct ixgbe_adapter *adapter)
/* Extra buffer to be shared by all DDPs for HW work around */
buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_ATOMIC);
- if (!buffer) {
- e_err(drv, "failed to allocate extra DDP buffer\n");
+ if (!buffer)
return -ENOMEM;
- }
dma = dma_map_single(dev, buffer, IXGBE_FCBUFF_MIN, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, dma)) {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
index bf724da99375..3a02759b5e95 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index 8c74f739011d..ef5f7a678ce1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -386,7 +386,6 @@ static bool ixgbe_set_dcb_sriov_queues(struct ixgbe_adapter *adapter)
fcoe = &adapter->ring_feature[RING_F_FCOE];
/* limit ourselves based on feature limits */
- fcoe_i = min_t(u16, fcoe_i, num_online_cpus());
fcoe_i = min_t(u16, fcoe_i, fcoe->limit);
if (fcoe_i) {
@@ -562,9 +561,6 @@ static bool ixgbe_set_sriov_queues(struct ixgbe_adapter *adapter)
fcoe_i = min_t(u16, fcoe_i, fcoe->limit);
if (vmdq_i > 1 && fcoe_i) {
- /* reserve no more than number of CPUs */
- fcoe_i = min_t(u16, fcoe_i, num_online_cpus());
-
/* alloc queues for FCoE separately */
fcoe->indices = fcoe_i;
fcoe->offset = vmdq_i * rss_i;
@@ -623,8 +619,7 @@ static bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
if (rss_i > 1 && adapter->atr_sample_rate) {
f = &adapter->ring_feature[RING_F_FDIR];
- f->indices = min_t(u16, num_online_cpus(), f->limit);
- rss_i = max_t(u16, rss_i, f->indices);
+ rss_i = f->indices = f->limit;
if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
@@ -776,19 +771,23 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,
{
struct ixgbe_q_vector *q_vector;
struct ixgbe_ring *ring;
- int node = -1;
+ int node = NUMA_NO_NODE;
int cpu = -1;
int ring_count, size;
+ u8 tcs = netdev_get_num_tc(adapter->netdev);
ring_count = txr_count + rxr_count;
size = sizeof(struct ixgbe_q_vector) +
(sizeof(struct ixgbe_ring) * ring_count);
/* customize cpu for Flow Director mapping */
- if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
- if (cpu_online(v_idx)) {
- cpu = v_idx;
- node = cpu_to_node(cpu);
+ if ((tcs <= 1) && !(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)) {
+ u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
+ if (rss_i > 1 && adapter->atr_sample_rate) {
+ if (cpu_online(v_idx)) {
+ cpu = v_idx;
+ node = cpu_to_node(cpu);
+ }
}
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 20a5af6d87d0..68478d6dfa2d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -66,7 +66,7 @@ static char ixgbe_default_device_descr[] =
#define DRV_VERSION "3.11.33-k"
const char ixgbe_driver_version[] = DRV_VERSION;
static const char ixgbe_copyright[] =
- "Copyright (c) 1999-2012 Intel Corporation.";
+ "Copyright (c) 1999-2013 Intel Corporation.";
static const struct ixgbe_info *ixgbe_info_tbl[] = {
[board_82598] = &ixgbe_82598_info,
@@ -803,6 +803,7 @@ 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;
+ e_warn(drv, "initiating reset due to tx timeout\n");
ixgbe_service_event_schedule(adapter);
}
}
@@ -837,7 +838,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
break;
/* prevent any other reads prior to eop_desc */
- rmb();
+ read_barrier_depends();
/* if DD is not set pending work has not been completed */
if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
@@ -850,9 +851,6 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
total_bytes += tx_buffer->bytecount;
total_packets += tx_buffer->gso_segs;
- if (unlikely(tx_buffer->tx_flags & IXGBE_TX_FLAGS_TSTAMP))
- ixgbe_ptp_tx_hwtstamp(q_vector, tx_buffer->skb);
-
/* free the skb */
dev_kfree_skb_any(tx_buffer->skb);
@@ -1401,6 +1399,7 @@ static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring,
/* set gso_size to avoid messing up TCP MSS */
skb_shinfo(skb)->gso_size = DIV_ROUND_UP((skb->len - hdr_len),
IXGBE_CB(skb)->append_cnt);
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
}
static void ixgbe_update_rsc_stats(struct ixgbe_ring *rx_ring,
@@ -1441,7 +1440,7 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
ixgbe_rx_checksum(rx_ring, rx_desc, skb);
- ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, rx_desc, skb);
+ ixgbe_ptp_rx_hwtstamp(rx_ring, rx_desc, skb);
if ((dev->features & NETIF_F_HW_VLAN_RX) &&
ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) {
@@ -2180,10 +2179,10 @@ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter)
return;
if (!(eicr & IXGBE_EICR_LSC) && hw->mac.ops.check_link) {
- u32 autoneg;
+ u32 speed;
bool link_up = false;
- hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
+ hw->mac.ops.check_link(hw, &speed, &link_up, false);
if (link_up)
return;
@@ -2787,13 +2786,19 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
/*
* set WTHRESH to encourage burst writeback, it should not be set
- * higher than 1 when ITR is 0 as it could cause false TX hangs
+ * higher than 1 when:
+ * - ITR is 0 as it could cause false TX hangs
+ * - ITR is set to > 100k int/sec and BQL is enabled
*
* In order to avoid issues WTHRESH + PTHRESH should always be equal
* to or less than the number of on chip descriptors, which is
* currently 40.
*/
+#if IS_ENABLED(CONFIG_BQL)
+ if (!ring->q_vector || (ring->q_vector->itr < IXGBE_100K_ITR))
+#else
if (!ring->q_vector || (ring->q_vector->itr < 8))
+#endif
txdctl |= (1 << 16); /* WTHRESH = 1 */
else
txdctl |= (8 << 16); /* WTHRESH = 8 */
@@ -2814,6 +2819,16 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
ring->atr_sample_rate = 0;
}
+ /* initialize XPS */
+ if (!test_and_set_bit(__IXGBE_TX_XPS_INIT_DONE, &ring->state)) {
+ struct ixgbe_q_vector *q_vector = ring->q_vector;
+
+ if (q_vector)
+ netif_set_xps_queue(adapter->netdev,
+ &q_vector->affinity_mask,
+ ring->queue_index);
+ }
+
clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
/* enable queue */
@@ -3996,25 +4011,25 @@ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
**/
static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
{
- u32 autoneg;
- bool negotiation, link_up = false;
+ u32 speed;
+ bool autoneg, link_up = false;
u32 ret = IXGBE_ERR_LINK_SETUP;
if (hw->mac.ops.check_link)
- ret = hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
+ ret = hw->mac.ops.check_link(hw, &speed, &link_up, false);
if (ret)
goto link_cfg_out;
- autoneg = hw->phy.autoneg_advertised;
- if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
- ret = hw->mac.ops.get_link_capabilities(hw, &autoneg,
- &negotiation);
+ speed = hw->phy.autoneg_advertised;
+ if ((!speed) && (hw->mac.ops.get_link_capabilities))
+ ret = hw->mac.ops.get_link_capabilities(hw, &speed,
+ &autoneg);
if (ret)
goto link_cfg_out;
if (hw->mac.ops.setup_link)
- ret = hw->mac.ops.setup_link(hw, autoneg, negotiation, link_up);
+ ret = hw->mac.ops.setup_link(hw, speed, link_up);
link_cfg_out:
return ret;
}
@@ -4466,7 +4481,7 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
- unsigned int rss;
+ unsigned int rss, fdir;
u32 fwsm;
#ifdef CONFIG_IXGBE_DCB
int j;
@@ -4481,38 +4496,57 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
hw->subsystem_vendor_id = pdev->subsystem_vendor;
hw->subsystem_device_id = pdev->subsystem_device;
- /* Set capability flags */
+ /* Set common capability flags and settings */
rss = min_t(int, IXGBE_MAX_RSS_INDICES, num_online_cpus());
adapter->ring_feature[RING_F_RSS].limit = rss;
+ adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
+ adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
+ adapter->max_q_vectors = MAX_Q_VECTORS_82599;
+ adapter->atr_sample_rate = 20;
+ fdir = min_t(int, IXGBE_MAX_FDIR_INDICES, num_online_cpus());
+ adapter->ring_feature[RING_F_FDIR].limit = fdir;
+ adapter->fdir_pballoc = IXGBE_FDIR_PBALLOC_64K;
+#ifdef CONFIG_IXGBE_DCA
+ adapter->flags |= IXGBE_FLAG_DCA_CAPABLE;
+#endif
+#ifdef IXGBE_FCOE
+ adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE;
+ adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
+#ifdef CONFIG_IXGBE_DCB
+ /* Default traffic class to use for FCoE */
+ adapter->fcoe.up = IXGBE_FCOE_DEFTC;
+#endif /* CONFIG_IXGBE_DCB */
+#endif /* IXGBE_FCOE */
+
+ /* Set MAC specific capability flags and exceptions */
switch (hw->mac.type) {
case ixgbe_mac_82598EB:
+ adapter->flags2 &= ~IXGBE_FLAG2_RSC_CAPABLE;
+ adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
+
if (hw->device_id == IXGBE_DEV_ID_82598AT)
adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
+
adapter->max_q_vectors = MAX_Q_VECTORS_82598;
+ adapter->ring_feature[RING_F_FDIR].limit = 0;
+ adapter->atr_sample_rate = 0;
+ adapter->fdir_pballoc = 0;
+#ifdef IXGBE_FCOE
+ adapter->flags &= ~IXGBE_FLAG_FCOE_CAPABLE;
+ adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
+#ifdef CONFIG_IXGBE_DCB
+ adapter->fcoe.up = 0;
+#endif /* IXGBE_DCB */
+#endif /* IXGBE_FCOE */
+ break;
+ case ixgbe_mac_82599EB:
+ if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM)
+ adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
break;
case ixgbe_mac_X540:
fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
if (fwsm & IXGBE_FWSM_TS_ENABLED)
adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
- case ixgbe_mac_82599EB:
- adapter->max_q_vectors = MAX_Q_VECTORS_82599;
- adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE;
- adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
- if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM)
- adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
- /* Flow Director hash filters enabled */
- adapter->atr_sample_rate = 20;
- adapter->ring_feature[RING_F_FDIR].limit =
- IXGBE_MAX_FDIR_INDICES;
- adapter->fdir_pballoc = IXGBE_FDIR_PBALLOC_64K;
-#ifdef IXGBE_FCOE
- adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE;
- adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
-#ifdef CONFIG_IXGBE_DCB
- /* Default traffic class to use for FCoE */
- adapter->fcoe.up = IXGBE_FCOE_DEFTC;
-#endif
-#endif /* IXGBE_FCOE */
break;
default:
break;
@@ -4871,7 +4905,7 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
*/
if ((adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) &&
(adapter->hw.mac.type == ixgbe_mac_82599EB) &&
- (max_frame > MAXIMUM_ETHERNET_VLAN_SIZE))
+ (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)))
e_warn(probe, "Setting MTU > 1500 will disable legacy VFs\n");
e_info(probe, "changing MTU from %d to %d\n", netdev->mtu, new_mtu);
@@ -5534,6 +5568,8 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
break;
}
+ adapter->last_rx_ptp_check = jiffies;
+
if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED)
ixgbe_ptp_start_cyclecounter(adapter);
@@ -5614,6 +5650,7 @@ static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter)
* to get done, so reset controller to flush Tx.
* (Do the reset outside of interrupt context).
*/
+ e_warn(drv, "initiating reset to clear Tx work after link loss\n");
adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
}
}
@@ -5678,6 +5715,10 @@ static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
!(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
return;
+ /* concurent i2c reads are not supported */
+ if (test_bit(__IXGBE_READ_I2C, &adapter->state))
+ return;
+
/* someone else is in init, wait until next service event */
if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
return;
@@ -5738,8 +5779,8 @@ sfp_out:
static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
- u32 autoneg;
- bool negotiation;
+ u32 speed;
+ bool autoneg = false;
if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_CONFIG))
return;
@@ -5750,11 +5791,11 @@ static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter)
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);
+ speed = hw->phy.autoneg_advertised;
+ if ((!speed) && (hw->mac.ops.get_link_capabilities))
+ hw->mac.ops.get_link_capabilities(hw, &speed, &autoneg);
if (hw->mac.ops.setup_link)
- hw->mac.ops.setup_link(hw, autoneg, negotiation, true);
+ hw->mac.ops.setup_link(hw, speed, true);
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
adapter->link_check_timeout = jiffies;
@@ -5878,7 +5919,6 @@ 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);
@@ -5886,7 +5926,11 @@ static void ixgbe_service_task(struct work_struct *work)
ixgbe_watchdog_subtask(adapter);
ixgbe_fdir_reinit_subtask(adapter);
ixgbe_check_hang_subtask(adapter);
- ixgbe_ptp_overflow_check(adapter);
+
+ if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED) {
+ ixgbe_ptp_overflow_check(adapter);
+ ixgbe_ptp_rx_hang(adapter);
+ }
ixgbe_service_event_complete(adapter);
}
@@ -5899,6 +5943,9 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
u32 vlan_macip_lens, type_tucmd;
u32 mss_l4len_idx, l4len;
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ return 0;
+
if (!skb_is_gso(skb))
return 0;
@@ -5941,10 +5988,9 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
first->gso_segs = skb_shinfo(skb)->gso_segs;
first->bytecount += (first->gso_segs - 1) * *hdr_len;
- /* mss_l4len_id: use 1 as index for TSO */
+ /* mss_l4len_id: use 0 as index for TSO */
mss_l4len_idx = l4len << IXGBE_ADVTXD_L4LEN_SHIFT;
mss_l4len_idx |= skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT;
- mss_l4len_idx |= 1 << IXGBE_ADVTXD_IDX_SHIFT;
/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
vlan_macip_lens = skb_network_header_len(skb);
@@ -5966,12 +6012,9 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
u32 type_tucmd = 0;
if (skb->ip_summed != CHECKSUM_PARTIAL) {
- if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN)) {
- if (unlikely(skb->no_fcs))
- first->tx_flags |= IXGBE_TX_FLAGS_NO_IFCS;
- if (!(first->tx_flags & IXGBE_TX_FLAGS_TXSW))
- return;
- }
+ if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN) &&
+ !(first->tx_flags & IXGBE_TX_FLAGS_CC))
+ return;
} else {
u8 l4_hdr = 0;
switch (first->protocol) {
@@ -6029,30 +6072,32 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
type_tucmd, mss_l4len_idx);
}
-static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
+#define IXGBE_SET_FLAG(_input, _flag, _result) \
+ ((_flag <= _result) ? \
+ ((u32)(_input & _flag) * (_result / _flag)) : \
+ ((u32)(_input & _flag) / (_flag / _result)))
+
+static u32 ixgbe_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)
{
/* set type for advanced descriptor with frame checksum insertion */
- __le32 cmd_type = cpu_to_le32(IXGBE_ADVTXD_DTYP_DATA |
- IXGBE_ADVTXD_DCMD_DEXT);
+ u32 cmd_type = IXGBE_ADVTXD_DTYP_DATA |
+ IXGBE_ADVTXD_DCMD_DEXT |
+ IXGBE_ADVTXD_DCMD_IFCS;
/* set HW vlan bit if vlan is present */
- if (tx_flags & IXGBE_TX_FLAGS_HW_VLAN)
- cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_VLE);
-
- if (tx_flags & IXGBE_TX_FLAGS_TSTAMP)
- cmd_type |= cpu_to_le32(IXGBE_ADVTXD_MAC_TSTAMP);
+ cmd_type |= IXGBE_SET_FLAG(tx_flags, IXGBE_TX_FLAGS_HW_VLAN,
+ IXGBE_ADVTXD_DCMD_VLE);
/* set segmentation enable bits for TSO/FSO */
-#ifdef IXGBE_FCOE
- if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_FSO))
-#else
- if (tx_flags & IXGBE_TX_FLAGS_TSO)
-#endif
- cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_TSE);
+ cmd_type |= IXGBE_SET_FLAG(tx_flags, IXGBE_TX_FLAGS_TSO,
+ IXGBE_ADVTXD_DCMD_TSE);
+
+ /* set timestamp bit if present */
+ cmd_type |= IXGBE_SET_FLAG(tx_flags, IXGBE_TX_FLAGS_TSTAMP,
+ IXGBE_ADVTXD_MAC_TSTAMP);
/* insert frame checksum */
- if (!(tx_flags & IXGBE_TX_FLAGS_NO_IFCS))
- cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_IFCS);
+ cmd_type ^= IXGBE_SET_FLAG(skb->no_fcs, 1, IXGBE_ADVTXD_DCMD_IFCS);
return cmd_type;
}
@@ -6060,36 +6105,27 @@ static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
static void ixgbe_tx_olinfo_status(union ixgbe_adv_tx_desc *tx_desc,
u32 tx_flags, unsigned int paylen)
{
- __le32 olinfo_status = cpu_to_le32(paylen << IXGBE_ADVTXD_PAYLEN_SHIFT);
+ u32 olinfo_status = paylen << IXGBE_ADVTXD_PAYLEN_SHIFT;
/* enable L4 checksum for TSO and TX checksum offload */
- if (tx_flags & IXGBE_TX_FLAGS_CSUM)
- olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_TXSM);
+ olinfo_status |= IXGBE_SET_FLAG(tx_flags,
+ IXGBE_TX_FLAGS_CSUM,
+ IXGBE_ADVTXD_POPTS_TXSM);
/* enble IPv4 checksum for TSO */
- if (tx_flags & IXGBE_TX_FLAGS_IPV4)
- olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_POPTS_IXSM);
-
- /* use index 1 context for TSO/FSO/FCOE */
-#ifdef IXGBE_FCOE
- if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_FCOE))
-#else
- if (tx_flags & IXGBE_TX_FLAGS_TSO)
-#endif
- olinfo_status |= cpu_to_le32(1 << IXGBE_ADVTXD_IDX_SHIFT);
+ olinfo_status |= IXGBE_SET_FLAG(tx_flags,
+ IXGBE_TX_FLAGS_IPV4,
+ IXGBE_ADVTXD_POPTS_IXSM);
/*
* Check Context must be set if Tx switch is enabled, which it
* always is for case where virtual functions are running
*/
-#ifdef IXGBE_FCOE
- if (tx_flags & (IXGBE_TX_FLAGS_TXSW | IXGBE_TX_FLAGS_FCOE))
-#else
- if (tx_flags & IXGBE_TX_FLAGS_TXSW)
-#endif
- olinfo_status |= cpu_to_le32(IXGBE_ADVTXD_CC);
+ olinfo_status |= IXGBE_SET_FLAG(tx_flags,
+ IXGBE_TX_FLAGS_CC,
+ IXGBE_ADVTXD_CC);
- tx_desc->read.olinfo_status = olinfo_status;
+ tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
}
#define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \
@@ -6099,22 +6135,22 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
struct ixgbe_tx_buffer *first,
const u8 hdr_len)
{
- dma_addr_t dma;
struct sk_buff *skb = first->skb;
struct ixgbe_tx_buffer *tx_buffer;
union ixgbe_adv_tx_desc *tx_desc;
- struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
- unsigned int data_len = skb->data_len;
- unsigned int size = skb_headlen(skb);
- unsigned int paylen = skb->len - hdr_len;
+ struct skb_frag_struct *frag;
+ dma_addr_t dma;
+ unsigned int data_len, size;
u32 tx_flags = first->tx_flags;
- __le32 cmd_type;
+ u32 cmd_type = ixgbe_tx_cmd_type(skb, tx_flags);
u16 i = tx_ring->next_to_use;
tx_desc = IXGBE_TX_DESC(tx_ring, i);
- ixgbe_tx_olinfo_status(tx_desc, tx_flags, paylen);
- cmd_type = ixgbe_tx_cmd_type(tx_flags);
+ ixgbe_tx_olinfo_status(tx_desc, tx_flags, skb->len - hdr_len);
+
+ size = skb_headlen(skb);
+ data_len = skb->data_len;
#ifdef IXGBE_FCOE
if (tx_flags & IXGBE_TX_FLAGS_FCOE) {
@@ -6128,19 +6164,22 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
#endif
dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE);
- if (dma_mapping_error(tx_ring->dev, dma))
- goto dma_error;
- /* record length, and DMA address */
- dma_unmap_len_set(first, len, size);
- dma_unmap_addr_set(first, dma, dma);
+ tx_buffer = first;
- tx_desc->read.buffer_addr = cpu_to_le64(dma);
+ for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
+ if (dma_mapping_error(tx_ring->dev, dma))
+ goto dma_error;
+
+ /* record length, and DMA address */
+ dma_unmap_len_set(tx_buffer, len, size);
+ dma_unmap_addr_set(tx_buffer, dma, dma);
+
+ tx_desc->read.buffer_addr = cpu_to_le64(dma);
- for (;;) {
while (unlikely(size > IXGBE_MAX_DATA_PER_TXD)) {
tx_desc->read.cmd_type_len =
- cmd_type | cpu_to_le32(IXGBE_MAX_DATA_PER_TXD);
+ cpu_to_le32(cmd_type ^ IXGBE_MAX_DATA_PER_TXD);
i++;
tx_desc++;
@@ -6148,18 +6187,18 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
tx_desc = IXGBE_TX_DESC(tx_ring, 0);
i = 0;
}
+ tx_desc->read.olinfo_status = 0;
dma += IXGBE_MAX_DATA_PER_TXD;
size -= IXGBE_MAX_DATA_PER_TXD;
tx_desc->read.buffer_addr = cpu_to_le64(dma);
- tx_desc->read.olinfo_status = 0;
}
if (likely(!data_len))
break;
- tx_desc->read.cmd_type_len = cmd_type | cpu_to_le32(size);
+ tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type ^ size);
i++;
tx_desc++;
@@ -6167,6 +6206,7 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
tx_desc = IXGBE_TX_DESC(tx_ring, 0);
i = 0;
}
+ tx_desc->read.olinfo_status = 0;
#ifdef IXGBE_FCOE
size = min_t(unsigned int, data_len, skb_frag_size(frag));
@@ -6177,22 +6217,13 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
dma = skb_frag_dma_map(tx_ring->dev, frag, 0, size,
DMA_TO_DEVICE);
- if (dma_mapping_error(tx_ring->dev, dma))
- goto dma_error;
tx_buffer = &tx_ring->tx_buffer_info[i];
- dma_unmap_len_set(tx_buffer, len, size);
- dma_unmap_addr_set(tx_buffer, dma, dma);
-
- tx_desc->read.buffer_addr = cpu_to_le64(dma);
- tx_desc->read.olinfo_status = 0;
-
- frag++;
}
/* write last descriptor with RS and EOP bits */
- cmd_type |= cpu_to_le32(size) | cpu_to_le32(IXGBE_TXD_CMD);
- tx_desc->read.cmd_type_len = cmd_type;
+ cmd_type |= size | IXGBE_TXD_CMD;
+ tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
@@ -6353,38 +6384,40 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
return __ixgbe_maybe_stop_tx(tx_ring, size);
}
+#ifdef IXGBE_FCOE
static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
{
- struct ixgbe_adapter *adapter = netdev_priv(dev);
- int txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) :
- smp_processor_id();
-#ifdef IXGBE_FCOE
- __be16 protocol = vlan_get_protocol(skb);
+ struct ixgbe_adapter *adapter;
+ struct ixgbe_ring_feature *f;
+ int txq;
- if (((protocol == htons(ETH_P_FCOE)) ||
- (protocol == htons(ETH_P_FIP))) &&
- (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) {
- struct ixgbe_ring_feature *f;
+ /*
+ * only execute the code below if protocol is FCoE
+ * or FIP and we have FCoE enabled on the adapter
+ */
+ switch (vlan_get_protocol(skb)) {
+ case __constant_htons(ETH_P_FCOE):
+ case __constant_htons(ETH_P_FIP):
+ adapter = netdev_priv(dev);
- f = &adapter->ring_feature[RING_F_FCOE];
+ if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
+ break;
+ default:
+ return __netdev_pick_tx(dev, skb);
+ }
- while (txq >= f->indices)
- txq -= f->indices;
- txq += adapter->ring_feature[RING_F_FCOE].offset;
+ f = &adapter->ring_feature[RING_F_FCOE];
- return txq;
- }
-#endif
+ txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) :
+ smp_processor_id();
- if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
- while (unlikely(txq >= dev->real_num_tx_queues))
- txq -= dev->real_num_tx_queues;
- return txq;
- }
+ while (txq >= f->indices)
+ txq -= f->indices;
- return skb_tx_hash(dev, skb);
+ return txq + f->offset;
}
+#endif
netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
struct ixgbe_adapter *adapter,
struct ixgbe_ring *tx_ring)
@@ -6445,6 +6478,11 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
+
+ /* schedule check for Tx timestamp */
+ adapter->ptp_tx_skb = skb_get(skb);
+ adapter->ptp_tx_start = jiffies;
+ schedule_work(&adapter->ptp_tx_work);
}
#ifdef CONFIG_PCI_IOV
@@ -6453,7 +6491,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
* Tx switch had been disabled.
*/
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
- tx_flags |= IXGBE_TX_FLAGS_TXSW;
+ tx_flags |= IXGBE_TX_FLAGS_CC;
#endif
/* DCB maps skb priorities 0-7 onto 3 bit PCP of VLAN tag. */
@@ -6784,6 +6822,7 @@ static void ixgbe_set_prio_tc_map(struct ixgbe_adapter *adapter)
}
}
+#endif /* CONFIG_IXGBE_DCB */
/**
* ixgbe_setup_tc - configure net_device for multiple traffic classes
*
@@ -6809,6 +6848,7 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
ixgbe_close(dev);
ixgbe_clear_interrupt_scheme(adapter);
+#ifdef CONFIG_IXGBE_DCB
if (tc) {
netdev_set_num_tc(dev, tc);
ixgbe_set_prio_tc_map(adapter);
@@ -6831,15 +6871,28 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
adapter->dcb_cfg.pfc_mode_enable = false;
}
- ixgbe_init_interrupt_scheme(adapter);
ixgbe_validate_rtr(adapter, tc);
+
+#endif /* CONFIG_IXGBE_DCB */
+ ixgbe_init_interrupt_scheme(adapter);
+
if (netif_running(dev))
- ixgbe_open(dev);
+ return ixgbe_open(dev);
return 0;
}
-#endif /* CONFIG_IXGBE_DCB */
+#ifdef CONFIG_PCI_IOV
+void ixgbe_sriov_reinit(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ rtnl_lock();
+ ixgbe_setup_tc(netdev, netdev_get_num_tc(netdev));
+ rtnl_unlock();
+}
+
+#endif
void ixgbe_do_reset(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -6985,7 +7038,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
return err;
}
-static int ixgbe_ndo_fdb_del(struct ndmsg *ndm,
+static int ixgbe_ndo_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr)
{
@@ -7062,7 +7115,8 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
}
static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
- struct net_device *dev)
+ struct net_device *dev,
+ u32 filter_mask)
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
u16 mode;
@@ -7082,7 +7136,9 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_open = ixgbe_open,
.ndo_stop = ixgbe_close,
.ndo_start_xmit = ixgbe_xmit_frame,
+#ifdef IXGBE_FCOE
.ndo_select_queue = ixgbe_select_queue,
+#endif
.ndo_set_rx_mode = ixgbe_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ixgbe_set_mac,
@@ -7194,9 +7250,8 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
static int cards_found;
int i, err, pci_using_dac;
+ unsigned int indices = MAX_TX_QUEUES;
u8 part_str[IXGBE_PBANUM_LENGTH];
- unsigned int indices = num_possible_cpus();
- unsigned int dcb_max = 0;
#ifdef IXGBE_FCOE
u16 device_caps;
#endif
@@ -7245,25 +7300,15 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
pci_save_state(pdev);
+ if (ii->mac == ixgbe_mac_82598EB) {
#ifdef CONFIG_IXGBE_DCB
- if (ii->mac == ixgbe_mac_82598EB)
- dcb_max = min_t(unsigned int, indices * MAX_TRAFFIC_CLASS,
- IXGBE_MAX_RSS_INDICES);
- else
- dcb_max = min_t(unsigned int, indices * MAX_TRAFFIC_CLASS,
- IXGBE_MAX_FDIR_INDICES);
+ /* 8 TC w/ 4 queues per TC */
+ indices = 4 * MAX_TRAFFIC_CLASS;
+#else
+ indices = IXGBE_MAX_RSS_INDICES;
#endif
+ }
- if (ii->mac == ixgbe_mac_82598EB)
- indices = min_t(unsigned int, indices, IXGBE_MAX_RSS_INDICES);
- else
- indices = min_t(unsigned int, indices, IXGBE_MAX_FDIR_INDICES);
-
-#ifdef IXGBE_FCOE
- indices += min_t(unsigned int, num_possible_cpus(),
- IXGBE_MAX_FCOE_INDICES);
-#endif
- indices = max_t(unsigned int, dcb_max, indices);
netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), indices);
if (!netdev) {
err = -ENOMEM;
@@ -7366,7 +7411,15 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
#ifdef CONFIG_PCI_IOV
- ixgbe_enable_sriov(adapter, ii);
+ /* SR-IOV not supported on the 82598 */
+ if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+ goto skip_sriov;
+ /* Mailbox */
+ ixgbe_init_mbx_params_pf(hw);
+ memcpy(&hw->mbx.ops, ii->mbx_ops, sizeof(hw->mbx.ops));
+ ixgbe_enable_sriov(adapter);
+ pci_sriov_set_totalvfs(pdev, 63);
+skip_sriov:
#endif
netdev->features = NETIF_F_SG |
@@ -7410,13 +7463,17 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef IXGBE_FCOE
if (adapter->flags & IXGBE_FLAG_FCOE_CAPABLE) {
+ unsigned int fcoe_l;
+
if (hw->mac.ops.get_device_caps) {
hw->mac.ops.get_device_caps(hw, &device_caps);
if (device_caps & IXGBE_DEVICE_CAPS_FCOE_OFFLOADS)
adapter->flags &= ~IXGBE_FLAG_FCOE_CAPABLE;
}
- adapter->ring_feature[RING_F_FCOE].limit = IXGBE_FCRETA_SIZE;
+
+ fcoe_l = min_t(int, IXGBE_FCRETA_SIZE, num_online_cpus());
+ adapter->ring_feature[RING_F_FCOE].limit = fcoe_l;
netdev->features |= NETIF_F_FSO |
NETIF_F_FCOE_CRC;
@@ -7444,9 +7501,8 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len);
- memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len);
- if (!is_valid_ether_addr(netdev->perm_addr)) {
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
e_dev_err("invalid MAC address\n");
err = -EIO;
goto err_sw_init;
@@ -7623,8 +7679,14 @@ static void ixgbe_remove(struct pci_dev *pdev)
if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdev(netdev);
- ixgbe_disable_sriov(adapter);
-
+#ifdef CONFIG_PCI_IOV
+ /*
+ * Only disable SR-IOV on unload if the user specified the now
+ * deprecated max_vfs module parameter.
+ */
+ if (max_vfs)
+ ixgbe_disable_sriov(adapter);
+#endif
ixgbe_clear_interrupt_scheme(adapter);
ixgbe_release_hw_control(adapter);
@@ -7729,6 +7791,8 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
if (vfdev) {
e_dev_err("Issuing VFLR to VF %d\n", vf);
pci_write_config_dword(vfdev, 0xA8, 0x00008000);
+ /* Free device reference count */
+ pci_dev_put(vfdev);
}
pci_cleanup_aer_uncorrect_error_status(pdev);
@@ -7838,6 +7902,7 @@ static struct pci_driver ixgbe_driver = {
.resume = ixgbe_resume,
#endif
.shutdown = ixgbe_shutdown,
+ .sriov_configure = ixgbe_pci_sriov_configure,
.err_handler = &ixgbe_err_handler
};
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
index 1f3e32b576a5..d4a64e665398 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
index 42dd65e6ac97..e44ff47659b5 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index 71659edf81aa..060d2ad2ac96 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -494,11 +494,9 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
* ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities
* @hw: pointer to hardware structure
* @speed: new link speed
- * @autoneg: true if autonegotiation enabled
**/
s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
- bool autoneg,
bool autoneg_wait_to_complete)
{
@@ -854,11 +852,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_IDENTIFIER,
- &identifier);
+ &identifier);
- if (status == IXGBE_ERR_SWFW_SYNC ||
- status == IXGBE_ERR_I2C ||
- status == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (status != 0)
goto err_read_i2c_eeprom;
/* LAN ID is needed for sfp_type determination */
@@ -872,26 +868,20 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
IXGBE_SFF_1GBE_COMP_CODES,
&comp_codes_1g);
- if (status == IXGBE_ERR_SWFW_SYNC ||
- status == IXGBE_ERR_I2C ||
- status == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (status != 0)
goto err_read_i2c_eeprom;
status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_10GBE_COMP_CODES,
&comp_codes_10g);
- if (status == IXGBE_ERR_SWFW_SYNC ||
- status == IXGBE_ERR_I2C ||
- status == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (status != 0)
goto err_read_i2c_eeprom;
status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_CABLE_TECHNOLOGY,
&cable_tech);
- if (status == IXGBE_ERR_SWFW_SYNC ||
- status == IXGBE_ERR_I2C ||
- status == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (status != 0)
goto err_read_i2c_eeprom;
/* ID Module
@@ -986,30 +976,24 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
if (hw->phy.type != ixgbe_phy_nl) {
hw->phy.id = identifier;
status = hw->phy.ops.read_i2c_eeprom(hw,
- IXGBE_SFF_VENDOR_OUI_BYTE0,
- &oui_bytes[0]);
+ IXGBE_SFF_VENDOR_OUI_BYTE0,
+ &oui_bytes[0]);
- if (status == IXGBE_ERR_SWFW_SYNC ||
- status == IXGBE_ERR_I2C ||
- status == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (status != 0)
goto err_read_i2c_eeprom;
status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_VENDOR_OUI_BYTE1,
&oui_bytes[1]);
- if (status == IXGBE_ERR_SWFW_SYNC ||
- status == IXGBE_ERR_I2C ||
- status == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (status != 0)
goto err_read_i2c_eeprom;
status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_VENDOR_OUI_BYTE2,
&oui_bytes[2]);
- if (status == IXGBE_ERR_SWFW_SYNC ||
- status == IXGBE_ERR_I2C ||
- status == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (status != 0)
goto err_read_i2c_eeprom;
vendor_oui =
@@ -1206,6 +1190,22 @@ s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
}
/**
+ * ixgbe_read_i2c_sff8472_generic - Reads 8 bit word over I2C interface
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset at address 0xA2
+ * @eeprom_data: value read
+ *
+ * Performs byte read operation to SFP module's SFF-8472 data over I2C
+ **/
+s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 *sff8472_data)
+{
+ return hw->phy.ops.read_i2c_byte(hw, byte_offset,
+ IXGBE_I2C_EEPROM_DEV_ADDR2,
+ sff8472_data);
+}
+
+/**
* ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface
* @hw: pointer to hardware structure
* @byte_offset: EEPROM byte offset to write
@@ -1293,9 +1293,9 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
break;
fail:
+ ixgbe_i2c_bus_clear(hw);
hw->mac.ops.release_swfw_sync(hw, swfw_mask);
msleep(100);
- ixgbe_i2c_bus_clear(hw);
retry++;
if (retry < max_retry)
hw_dbg(hw, "I2C byte read error - Retrying.\n");
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
index cc18165b4c05..886a3431cf5b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -30,6 +30,7 @@
#include "ixgbe_type.h"
#define IXGBE_I2C_EEPROM_DEV_ADDR 0xA0
+#define IXGBE_I2C_EEPROM_DEV_ADDR2 0xA2
/* EEPROM byte offsets */
#define IXGBE_SFF_IDENTIFIER 0x0
@@ -41,6 +42,8 @@
#define IXGBE_SFF_10GBE_COMP_CODES 0x3
#define IXGBE_SFF_CABLE_TECHNOLOGY 0x8
#define IXGBE_SFF_CABLE_SPEC_COMP 0x3C
+#define IXGBE_SFF_SFF_8472_SWAP 0x5C
+#define IXGBE_SFF_SFF_8472_COMP 0x5E
/* Bitmasks */
#define IXGBE_SFF_DA_PASSIVE_CABLE 0x4
@@ -51,6 +54,7 @@
#define IXGBE_SFF_1GBASET_CAPABLE 0x8
#define IXGBE_SFF_10GBASESR_CAPABLE 0x10
#define IXGBE_SFF_10GBASELR_CAPABLE 0x20
+#define IXGBE_SFF_ADDRESSING_MODE 0x4
#define IXGBE_I2C_EEPROM_READ_MASK 0x100
#define IXGBE_I2C_EEPROM_STATUS_MASK 0x3
#define IXGBE_I2C_EEPROM_STATUS_NO_OPERATION 0x0
@@ -88,6 +92,9 @@
#define IXGBE_TN_LASI_STATUS_REG 0x9005
#define IXGBE_TN_LASI_STATUS_TEMP_ALARM 0x0008
+/* SFP+ SFF-8472 Compliance code */
+#define IXGBE_SFF_SFF_8472_UNSUP 0x00
+
s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw);
s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw);
s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw);
@@ -98,7 +105,6 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw);
s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
- bool autoneg,
bool autoneg_wait_to_complete);
s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
ixgbe_link_speed *speed,
@@ -126,6 +132,8 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 data);
s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 *eeprom_data);
+s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset,
+ u8 *sff8472_data);
s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 eeprom_data);
#endif /* _IXGBE_PHY_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index bb9256a1b0a9..331987d6815c 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -96,15 +96,12 @@
#define IXGBE_MAX_TIMEADJ_VALUE 0x7FFFFFFFFFFFFFFFULL
#define IXGBE_OVERFLOW_PERIOD (HZ * 30)
+#define IXGBE_PTP_TX_TIMEOUT (HZ * 15)
#ifndef NSECS_PER_SEC
#define NSECS_PER_SEC 1000000000ULL
#endif
-static struct sock_filter ptp_filter[] = {
- PTP_FILTER
-};
-
/**
* ixgbe_ptp_setup_sdp
* @hw: the hardware private structure
@@ -405,149 +402,145 @@ void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr)
}
}
-
/**
- * ixgbe_ptp_overflow_check - delayed work to detect SYSTIME overflow
- * @work: structure containing information about this work task
+ * ixgbe_ptp_overflow_check - watchdog task to detect SYSTIME overflow
+ * @adapter: private adapter struct
*
- * this work function is scheduled to continue reading the timecounter
+ * this watchdog task periodically reads the timecounter
* in order to prevent missing when the system time registers wrap
- * around. This needs to be run approximately twice a minute when no
- * PTP activity is occurring.
+ * around. This needs to be run approximately twice a minute.
*/
void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter)
{
- unsigned long elapsed_jiffies = adapter->last_overflow_check - jiffies;
+ bool timeout = time_is_before_jiffies(adapter->last_overflow_check +
+ IXGBE_OVERFLOW_PERIOD);
struct timespec ts;
- if ((adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED) &&
- (elapsed_jiffies >= IXGBE_OVERFLOW_PERIOD)) {
+ if (timeout) {
ixgbe_ptp_gettime(&adapter->ptp_caps, &ts);
adapter->last_overflow_check = jiffies;
}
}
/**
- * ixgbe_ptp_match - determine if this skb matches a ptp packet
- * @skb: pointer to the skb
- * @hwtstamp: pointer to the hwtstamp_config to check
- *
- * Determine whether the skb should have been timestamped, assuming the
- * hwtstamp was set via the hwtstamp ioctl. Returns non-zero when the packet
- * should have a timestamp waiting in the registers, and 0 otherwise.
+ * ixgbe_ptp_rx_hang - detect error case when Rx timestamp registers latched
+ * @adapter: private network adapter structure
*
- * V1 packets have to check the version type to determine whether they are
- * correct. However, we can't directly access the data because it might be
- * fragmented in the SKB, in paged memory. In order to work around this, we
- * use skb_copy_bits which will properly copy the data whether it is in the
- * paged memory fragments or not. We have to copy the IP header as well as the
- * message type.
+ * this watchdog task is scheduled to detect error case where hardware has
+ * dropped an Rx packet that was timestamped when the ring is full. The
+ * particular error is rare but leaves the device in a state unable to timestamp
+ * any future packets.
*/
-static int ixgbe_ptp_match(struct sk_buff *skb, int rx_filter)
+void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter)
{
- struct iphdr iph;
- u8 msgtype;
- unsigned int type, offset;
-
- if (rx_filter == HWTSTAMP_FILTER_NONE)
- return 0;
-
- type = sk_run_filter(skb, ptp_filter);
-
- if (likely(rx_filter == HWTSTAMP_FILTER_PTP_V2_EVENT))
- return type & PTP_CLASS_V2;
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct ixgbe_ring *rx_ring;
+ u32 tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
+ unsigned long rx_event;
+ int n;
- /* For the remaining cases actually check message type */
- switch (type) {
- case PTP_CLASS_V1_IPV4:
- skb_copy_bits(skb, OFF_IHL, &iph, sizeof(iph));
- offset = ETH_HLEN + (iph.ihl << 2) + UDP_HLEN + OFF_PTP_CONTROL;
- break;
- case PTP_CLASS_V1_IPV6:
- offset = OFF_PTP6 + OFF_PTP_CONTROL;
- break;
- default:
- /* other cases invalid or handled above */
- return 0;
+ /* if we don't have a valid timestamp in the registers, just update the
+ * timeout counter and exit
+ */
+ if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID)) {
+ adapter->last_rx_ptp_check = jiffies;
+ return;
}
- /* Make sure our buffer is long enough */
- if (skb->len < offset)
- return 0;
+ /* determine the most recent watchdog or rx_timestamp event */
+ rx_event = adapter->last_rx_ptp_check;
+ for (n = 0; n < adapter->num_rx_queues; n++) {
+ rx_ring = adapter->rx_ring[n];
+ if (time_after(rx_ring->last_rx_timestamp, rx_event))
+ rx_event = rx_ring->last_rx_timestamp;
+ }
- skb_copy_bits(skb, offset, &msgtype, sizeof(msgtype));
+ /* only need to read the high RXSTMP register to clear the lock */
+ if (time_is_before_jiffies(rx_event + 5*HZ)) {
+ IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
+ adapter->last_rx_ptp_check = jiffies;
- switch (rx_filter) {
- case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
- return (msgtype == IXGBE_RXMTRL_V1_SYNC_MSG);
- break;
- case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
- return (msgtype == IXGBE_RXMTRL_V1_DELAY_REQ_MSG);
- break;
- default:
- return 0;
+ e_warn(drv, "clearing RX Timestamp hang");
}
}
/**
* ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp
- * @q_vector: structure containing interrupt and ring information
- * @skb: particular skb to send timestamp with
+ * @adapter: the private adapter struct
*
* if the timestamp is valid, we convert it into the timecounter ns
* value, then store that result into the shhwtstamps structure which
* is passed up the network stack
*/
-void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector,
- struct sk_buff *skb)
+static void ixgbe_ptp_tx_hwtstamp(struct ixgbe_adapter *adapter)
{
- struct ixgbe_adapter *adapter;
- struct ixgbe_hw *hw;
+ struct ixgbe_hw *hw = &adapter->hw;
struct skb_shared_hwtstamps shhwtstamps;
u64 regval = 0, ns;
- u32 tsynctxctl;
unsigned long flags;
- /* we cannot process timestamps on a ring without a q_vector */
- if (!q_vector || !q_vector->adapter)
- return;
-
- adapter = q_vector->adapter;
- hw = &adapter->hw;
-
- tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPL);
regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPH) << 32;
- /*
- * if TX timestamp is not valid, exit after clearing the
- * timestamp registers
- */
- if (!(tsynctxctl & IXGBE_TSYNCTXCTL_VALID))
- return;
-
spin_lock_irqsave(&adapter->tmreg_lock, flags);
ns = timecounter_cyc2time(&adapter->tc, regval);
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
shhwtstamps.hwtstamp = ns_to_ktime(ns);
- skb_tstamp_tx(skb, &shhwtstamps);
+ skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
+
+ dev_kfree_skb_any(adapter->ptp_tx_skb);
+ adapter->ptp_tx_skb = NULL;
+}
+
+/**
+ * ixgbe_ptp_tx_hwtstamp_work
+ * @work: pointer to the work struct
+ *
+ * This work item polls TSYNCTXCTL valid bit to determine when a Tx hardware
+ * timestamp has been taken for the current skb. It is necesary, because the
+ * descriptor's "done" bit does not correlate with the timestamp event.
+ */
+static void ixgbe_ptp_tx_hwtstamp_work(struct work_struct *work)
+{
+ struct ixgbe_adapter *adapter = container_of(work, struct ixgbe_adapter,
+ ptp_tx_work);
+ struct ixgbe_hw *hw = &adapter->hw;
+ bool timeout = time_is_before_jiffies(adapter->ptp_tx_start +
+ IXGBE_PTP_TX_TIMEOUT);
+ u32 tsynctxctl;
+
+ /* we have to have a valid skb */
+ if (!adapter->ptp_tx_skb)
+ return;
+
+ if (timeout) {
+ dev_kfree_skb_any(adapter->ptp_tx_skb);
+ adapter->ptp_tx_skb = NULL;
+ e_warn(drv, "clearing Tx Timestamp hang");
+ return;
+ }
+
+ tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
+ if (tsynctxctl & IXGBE_TSYNCTXCTL_VALID)
+ ixgbe_ptp_tx_hwtstamp(adapter);
+ else
+ /* reschedule to keep checking if it's not available yet */
+ schedule_work(&adapter->ptp_tx_work);
}
/**
- * ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp
+ * __ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp
* @q_vector: structure containing interrupt and ring information
- * @rx_desc: the rx descriptor
* @skb: particular skb to send timestamp with
*
* if the timestamp is valid, we convert it into the timecounter ns
* value, then store that result into the shhwtstamps structure which
* is passed up the network stack
*/
-void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
- union ixgbe_adv_rx_desc *rx_desc,
- struct sk_buff *skb)
+void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
+ struct sk_buff *skb)
{
struct ixgbe_adapter *adapter;
struct ixgbe_hw *hw;
@@ -563,37 +556,17 @@ void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
adapter = q_vector->adapter;
hw = &adapter->hw;
- if (likely(!ixgbe_ptp_match(skb, adapter->rx_hwtstamp_filter)))
- return;
-
+ /*
+ * Read the tsyncrxctl register afterwards in order to prevent taking an
+ * I/O hit on every packet.
+ */
tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
-
- /* Check if we have a valid timestamp and make sure the skb should
- * have been timestamped */
if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID))
return;
- /*
- * Always read the registers, in order to clear a possible fault
- * because of stagnant RX timestamp values for a packet that never
- * reached the queue.
- */
regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPL);
regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPH) << 32;
- /*
- * If the timestamp bit is set in the packet's descriptor, we know the
- * timestamp belongs to this packet. No other packet can be
- * timestamped until the registers for timestamping have been read.
- * Therefor only one packet with this bit can be in the queue at a
- * time, and the rx timestamp values that were in the registers belong
- * to this packet.
- *
- * If nothing went wrong, then it should have a skb_shared_tx that we
- * can turn into a skb_shared_hwtstamps.
- */
- if (unlikely(!ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)))
- return;
spin_lock_irqsave(&adapter->tmreg_lock, flags);
ns = timecounter_cyc2time(&adapter->tc, regval);
@@ -698,9 +671,6 @@ int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
return 0;
}
- /* Store filter value for later use */
- adapter->rx_hwtstamp_filter = config.rx_filter;
-
/* define ethertype filter for timestamping L2 packets */
if (is_l2)
IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_1588),
@@ -902,11 +872,8 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
return;
}
- /* initialize the ptp filter */
- if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter)))
- e_dev_warn("ptp_filter_init failed\n");
-
spin_lock_init(&adapter->tmreg_lock);
+ INIT_WORK(&adapter->ptp_tx_work, ixgbe_ptp_tx_hwtstamp_work);
adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
&adapter->pdev->dev);
@@ -938,6 +905,12 @@ void ixgbe_ptp_stop(struct ixgbe_adapter *adapter)
ixgbe_ptp_setup_sdp(adapter);
+ cancel_work_sync(&adapter->ptp_tx_work);
+ if (adapter->ptp_tx_skb) {
+ dev_kfree_skb_any(adapter->ptp_tx_skb);
+ adapter->ptp_tx_skb = NULL;
+ }
+
if (adapter->ptp_clock) {
ptp_clock_unregister(adapter->ptp_clock);
adapter->ptp_clock = NULL;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index 85cddac673ef..d44b4d21268c 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -44,50 +44,11 @@
#include "ixgbe_sriov.h"
#ifdef CONFIG_PCI_IOV
-void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
- const struct ixgbe_info *ii)
+static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
int num_vf_macvlans, i;
struct vf_macvlans *mv_list;
- int pre_existing_vfs = 0;
-
- pre_existing_vfs = pci_num_vf(adapter->pdev);
- if (!pre_existing_vfs && !adapter->num_vfs)
- return;
-
- /* If there are pre-existing VFs then we have to force
- * use of that many because they were not deleted the last
- * time someone removed the PF driver. That would have
- * been because they were allocated to guest VMs and can't
- * be removed. Go ahead and just re-enable the old amount.
- * If the user wants to change the number of VFs they can
- * use ethtool while making sure no VFs are allocated to
- * guest VMs... i.e. the right way.
- */
- if (pre_existing_vfs) {
- adapter->num_vfs = pre_existing_vfs;
- dev_warn(&adapter->pdev->dev, "Virtual Functions already "
- "enabled for this device - Please reload all "
- "VF drivers to avoid spoofed packet errors\n");
- } else {
- int err;
- /*
- * The 82599 supports up to 64 VFs per physical function
- * but this implementation limits allocation to 63 so that
- * basic networking resources are still available to the
- * physical function. If the user requests greater thn
- * 63 VFs then it is an error - reset to default of zero.
- */
- adapter->num_vfs = min_t(unsigned int, adapter->num_vfs, 63);
-
- err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
- if (err) {
- e_err(probe, "Failed to enable PCI sriov: %d\n", err);
- adapter->num_vfs = 0;
- return;
- }
- }
adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED;
e_info(probe, "SR-IOV enabled with %d VFs\n", adapter->num_vfs);
@@ -128,12 +89,6 @@ void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
kcalloc(adapter->num_vfs,
sizeof(struct vf_data_storage), GFP_KERNEL);
if (adapter->vfinfo) {
- /* Now that we're sure SR-IOV is enabled
- * and memory allocated set up the mailbox parameters
- */
- ixgbe_init_mbx_params_pf(hw);
- memcpy(&hw->mbx.ops, ii->mbx_ops, sizeof(hw->mbx.ops));
-
/* limit trafffic classes based on VFs enabled */
if ((adapter->hw.mac.type == ixgbe_mac_82599EB) &&
(adapter->num_vfs < 16)) {
@@ -157,10 +112,62 @@ void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
/* enable spoof checking for all VFs */
for (i = 0; i < adapter->num_vfs; i++)
adapter->vfinfo[i].spoofchk_enabled = true;
+ return 0;
+ }
+
+ return -ENOMEM;
+}
+
+/* Note this function is called when the user wants to enable SR-IOV
+ * VFs using the now deprecated module parameter
+ */
+void ixgbe_enable_sriov(struct ixgbe_adapter *adapter)
+{
+ int pre_existing_vfs = 0;
+
+ pre_existing_vfs = pci_num_vf(adapter->pdev);
+ if (!pre_existing_vfs && !adapter->num_vfs)
return;
+
+ if (!pre_existing_vfs)
+ dev_warn(&adapter->pdev->dev,
+ "Enabling SR-IOV VFs using the module parameter is deprecated - please use the pci sysfs interface.\n");
+
+ /* If there are pre-existing VFs then we have to force
+ * use of that many - over ride any module parameter value.
+ * This may result from the user unloading the PF driver
+ * while VFs were assigned to guest VMs or because the VFs
+ * have been created via the new PCI SR-IOV sysfs interface.
+ */
+ if (pre_existing_vfs) {
+ adapter->num_vfs = pre_existing_vfs;
+ dev_warn(&adapter->pdev->dev,
+ "Virtual Functions already enabled for this device - Please reload all VF drivers to avoid spoofed packet errors\n");
+ } else {
+ int err;
+ /*
+ * The 82599 supports up to 64 VFs per physical function
+ * but this implementation limits allocation to 63 so that
+ * basic networking resources are still available to the
+ * physical function. If the user requests greater thn
+ * 63 VFs then it is an error - reset to default of zero.
+ */
+ adapter->num_vfs = min_t(unsigned int, adapter->num_vfs, 63);
+
+ err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
+ if (err) {
+ e_err(probe, "Failed to enable PCI sriov: %d\n", err);
+ adapter->num_vfs = 0;
+ return;
+ }
}
- /* Oh oh */
+ if (!__ixgbe_enable_sriov(adapter))
+ return;
+
+ /* If we have gotten to this point then there is no memory available
+ * to manage the VF devices - print message and bail.
+ */
e_err(probe, "Unable to allocate memory for VF Data Storage - "
"SRIOV disabled\n");
ixgbe_disable_sriov(adapter);
@@ -200,11 +207,12 @@ static bool ixgbe_vfs_are_assigned(struct ixgbe_adapter *adapter)
}
#endif /* #ifdef CONFIG_PCI_IOV */
-void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
+int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
u32 gpie;
u32 vmdctl;
+ int rss;
/* set num VFs to 0 to prevent access to vfinfo */
adapter->num_vfs = 0;
@@ -219,7 +227,7 @@ void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
/* if SR-IOV is already disabled then there is nothing to do */
if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
- return;
+ return 0;
#ifdef CONFIG_PCI_IOV
/*
@@ -229,7 +237,7 @@ void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
*/
if (ixgbe_vfs_are_assigned(adapter)) {
e_dev_warn("Unloading driver while VFs are assigned - VFs will not be deallocated\n");
- return;
+ return -EPERM;
}
/* disable iov and allow time for transactions to clear */
pci_disable_sriov(adapter->pdev);
@@ -252,10 +260,94 @@ void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
adapter->flags &= ~IXGBE_FLAG_VMDQ_ENABLED;
adapter->ring_feature[RING_F_VMDQ].offset = 0;
+ rss = min_t(int, IXGBE_MAX_RSS_INDICES, num_online_cpus());
+ adapter->ring_feature[RING_F_RSS].limit = rss;
+
/* take a breather then clean up driver data */
msleep(100);
adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
+ return 0;
+}
+
+static int ixgbe_pci_sriov_enable(struct pci_dev *dev, int num_vfs)
+{
+#ifdef CONFIG_PCI_IOV
+ struct ixgbe_adapter *adapter = pci_get_drvdata(dev);
+ int err = 0;
+ int i;
+ int pre_existing_vfs = pci_num_vf(dev);
+
+ if (pre_existing_vfs && pre_existing_vfs != num_vfs)
+ err = ixgbe_disable_sriov(adapter);
+ else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
+ goto out;
+
+ if (err)
+ goto err_out;
+
+ /* While the SR-IOV capability structure reports total VFs to be
+ * 64 we limit the actual number that can be allocated to 63 so
+ * that some transmit/receive resources can be reserved to the
+ * PF. The PCI bus driver already checks for other values out of
+ * range.
+ */
+ if (num_vfs > 63) {
+ err = -EPERM;
+ goto err_out;
+ }
+
+ adapter->num_vfs = num_vfs;
+
+ err = __ixgbe_enable_sriov(adapter);
+ if (err)
+ goto err_out;
+
+ for (i = 0; i < adapter->num_vfs; i++)
+ ixgbe_vf_configuration(dev, (i | 0x10000000));
+
+ err = pci_enable_sriov(dev, num_vfs);
+ if (err) {
+ e_dev_warn("Failed to enable PCI sriov: %d\n", err);
+ goto err_out;
+ }
+ ixgbe_sriov_reinit(adapter);
+
+out:
+ return num_vfs;
+
+err_out:
+ return err;
+#endif
+ return 0;
+}
+
+static int ixgbe_pci_sriov_disable(struct pci_dev *dev)
+{
+ struct ixgbe_adapter *adapter = pci_get_drvdata(dev);
+ int err;
+ u32 current_flags = adapter->flags;
+
+ err = ixgbe_disable_sriov(adapter);
+
+ /* Only reinit if no error and state changed */
+ if (!err && current_flags != adapter->flags) {
+ /* ixgbe_disable_sriov() doesn't clear VMDQ flag */
+ adapter->flags &= ~IXGBE_FLAG_VMDQ_ENABLED;
+#ifdef CONFIG_PCI_IOV
+ ixgbe_sriov_reinit(adapter);
+#endif
+ }
+
+ return err;
+}
+
+int ixgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
+{
+ if (num_vfs == 0)
+ return ixgbe_pci_sriov_disable(dev);
+ else
+ return ixgbe_pci_sriov_enable(dev, num_vfs);
}
static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
@@ -447,15 +539,6 @@ static void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe)
IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr);
}
-static void ixgbe_set_vmvir(struct ixgbe_adapter *adapter,
- u16 vid, u16 qos, u32 vf)
-{
- struct ixgbe_hw *hw = &adapter->hw;
- u32 vmvir = vid | (qos << VLAN_PRIO_SHIFT) | IXGBE_VMVIR_VLANA_DEFAULT;
-
- IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), vmvir);
-}
-
static void ixgbe_clear_vmvir(struct ixgbe_adapter *adapter, u32 vf)
{
struct ixgbe_hw *hw = &adapter->hw;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
index 1be1d30e4e78..4713f9fc7f46 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -41,12 +41,20 @@ int ixgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
int ixgbe_ndo_get_vf_config(struct net_device *netdev,
int vf, struct ifla_vf_info *ivi);
void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter);
-void ixgbe_disable_sriov(struct ixgbe_adapter *adapter);
+int ixgbe_disable_sriov(struct ixgbe_adapter *adapter);
#ifdef CONFIG_PCI_IOV
-void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
- const struct ixgbe_info *ii);
+void ixgbe_enable_sriov(struct ixgbe_adapter *adapter);
#endif
+int ixgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
+static inline void ixgbe_set_vmvir(struct ixgbe_adapter *adapter,
+ u16 vid, u16 qos, u32 vf)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 vmvir = vid | (qos << VLAN_PRIO_SHIFT) | IXGBE_VMVIR_VLANA_DEFAULT;
+
+ IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), vmvir);
+}
#endif /* _IXGBE_SRIOV_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
index 16ddf14e8ba4..d118def16f35 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 9cd8a13711d3..6652e96c352d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -2822,7 +2822,7 @@ struct ixgbe_mac_operations {
void (*disable_tx_laser)(struct ixgbe_hw *);
void (*enable_tx_laser)(struct ixgbe_hw *);
void (*flap_tx_laser)(struct ixgbe_hw *);
- s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool);
+ s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool);
s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool);
s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *,
bool *);
@@ -2869,12 +2869,12 @@ struct ixgbe_phy_operations {
s32 (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *);
s32 (*write_reg)(struct ixgbe_hw *, u32, u32, u16);
s32 (*setup_link)(struct ixgbe_hw *);
- s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool,
- bool);
+ s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool);
s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *);
s32 (*get_firmware_version)(struct ixgbe_hw *, u16 *);
s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *);
s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8);
+ s32 (*read_i2c_sff8472)(struct ixgbe_hw *, u8 , u8 *);
s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *);
s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8);
s32 (*check_overtemp)(struct ixgbe_hw *);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index c73b92993391..66c5e946284e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2012 Intel Corporation.
+ Copyright(c) 1999 - 2013 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
@@ -72,14 +72,13 @@ static s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw)
* ixgbe_setup_mac_link_X540 - Set the auto advertised capabilitires
* @hw: pointer to hardware structure
* @speed: new link speed
- * @autoneg: true if autonegotiation enabled
* @autoneg_wait_to_complete: true when waiting for completion is needed
**/
static s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw,
- ixgbe_link_speed speed, bool autoneg,
- bool autoneg_wait_to_complete)
+ ixgbe_link_speed speed,
+ bool autoneg_wait_to_complete)
{
- return hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+ return hw->phy.ops.setup_link_speed(hw, speed,
autoneg_wait_to_complete);
}
@@ -879,6 +878,7 @@ static struct ixgbe_phy_operations phy_ops_X540 = {
.setup_link_speed = &ixgbe_setup_phy_link_speed_generic,
.read_i2c_byte = &ixgbe_read_i2c_byte_generic,
.write_i2c_byte = &ixgbe_write_i2c_byte_generic,
+ .read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_generic,
.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic,
.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic,
.check_overtemp = &ixgbe_tn_check_overtemp,
diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
index 8f2070439b59..c9d0c12d6f04 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
@@ -99,6 +99,7 @@ static int ixgbevf_get_settings(struct net_device *netdev,
ecmd->transceiver = XCVR_DUMMY1;
ecmd->port = -1;
+ hw->mac.get_link_status = 1;
hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
if (link_up) {
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 257357ae66c3..c3db6cd69b68 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -750,12 +750,37 @@ static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector)
static irqreturn_t ixgbevf_msix_other(int irq, void *data)
{
struct ixgbevf_adapter *adapter = data;
+ struct pci_dev *pdev = adapter->pdev;
struct ixgbe_hw *hw = &adapter->hw;
+ u32 msg;
+ bool got_ack = false;
hw->mac.get_link_status = 1;
+ if (!hw->mbx.ops.check_for_ack(hw))
+ got_ack = true;
- if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
- mod_timer(&adapter->watchdog_timer, jiffies);
+ if (!hw->mbx.ops.check_for_msg(hw)) {
+ hw->mbx.ops.read(hw, &msg, 1);
+
+ if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG) {
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies + 1));
+ adapter->link_up = false;
+ }
+
+ if (msg & IXGBE_VT_MSGTYPE_NACK)
+ dev_info(&pdev->dev,
+ "Last Request of type %2.2x to PF Nacked\n",
+ msg & 0xFF);
+ hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFSTS;
+ }
+
+ /* checking for the ack clears the PFACK bit. Place
+ * it back in the v2p_mailbox cache so that anyone
+ * polling for an ack will not miss it
+ */
+ if (got_ack)
+ hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFACK;
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, adapter->eims_other);
@@ -2095,6 +2120,9 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
int i;
+ if (!adapter->link_up)
+ return;
+
UPDATE_VF_COUNTER_32bit(IXGBE_VFGPRC, adapter->stats.last_vfgprc,
adapter->stats.vfgprc);
UPDATE_VF_COUNTER_32bit(IXGBE_VFGPTC, adapter->stats.last_vfgptc,
@@ -2217,9 +2245,23 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
if (link_up) {
if (!netif_carrier_ok(netdev)) {
- hw_dbg(&adapter->hw, "NIC Link is Up, %u Gbps\n",
- (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
- 10 : 1);
+ char *link_speed_string;
+ switch (link_speed) {
+ case IXGBE_LINK_SPEED_10GB_FULL:
+ link_speed_string = "10 Gbps";
+ break;
+ case IXGBE_LINK_SPEED_1GB_FULL:
+ link_speed_string = "1 Gbps";
+ break;
+ case IXGBE_LINK_SPEED_100_FULL:
+ link_speed_string = "100 Mbps";
+ break;
+ default:
+ link_speed_string = "unknown speed";
+ break;
+ }
+ dev_info(&adapter->pdev->dev,
+ "NIC Link is Up, %s\n", link_speed_string);
netif_carrier_on(netdev);
netif_tx_wake_all_queues(netdev);
}
@@ -2227,7 +2269,7 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
adapter->link_up = false;
adapter->link_speed = 0;
if (netif_carrier_ok(netdev)) {
- hw_dbg(&adapter->hw, "NIC Link is Down\n");
+ dev_info(&adapter->pdev->dev, "NIC Link is Down\n");
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
}
@@ -3328,8 +3370,6 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_sw_init;
/* The HW MAC address was set and/or determined in sw_init */
- memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
-
if (!is_valid_ether_addr(netdev->dev_addr)) {
pr_err("invalid MAC address\n");
err = -EIO;
diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c
index bc58f1dc22f5..5409fe876a44 100644
--- a/drivers/net/ethernet/korina.c
+++ b/drivers/net/ethernet/korina.c
@@ -695,9 +695,9 @@ static void netdev_get_drvinfo(struct net_device *dev,
{
struct korina_private *lp = netdev_priv(dev);
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, lp->dev->name);
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, lp->dev->name, sizeof(info->bus_info));
}
static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c
index c124e67a1a1c..6a2127489af7 100644
--- a/drivers/net/ethernet/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -302,9 +302,9 @@ ltq_etop_hw_init(struct net_device *dev)
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);
+ strlcpy(info->driver, "Lantiq ETOP", sizeof(info->driver));
+ strlcpy(info->bus_info, "internal", sizeof(info->bus_info));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
}
static int
@@ -393,8 +393,8 @@ ltq_etop_mdio_probe(struct net_device *dev)
return -ENODEV;
}
- phydev = phy_connect(dev, dev_name(&phydev->dev), &ltq_etop_mdio_link,
- 0, priv->pldata->mii_mode);
+ phydev = phy_connect(dev, dev_name(&phydev->dev),
+ &ltq_etop_mdio_link, priv->pldata->mii_mode);
if (IS_ERR(phydev)) {
netdev_err(dev, "Could not attach to PHY\n");
@@ -655,7 +655,7 @@ ltq_etop_init(struct net_device *dev)
/* Set addr_assign_type here, ltq_etop_set_mac_address would reset it. */
if (random_mac)
- dev->addr_assign_type |= NET_ADDR_RANDOM;
+ dev->addr_assign_type = NET_ADDR_RANDOM;
ltq_etop_set_multicast_list(dev);
err = ltq_etop_mdio_init(dev);
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 84c13263c514..29140502b71a 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -1879,12 +1879,10 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index)
memset(rxq->rx_desc_area, 0, size);
rxq->rx_desc_area_size = size;
- rxq->rx_skb = kmalloc(rxq->rx_ring_size * sizeof(*rxq->rx_skb),
- GFP_KERNEL);
- if (rxq->rx_skb == NULL) {
- netdev_err(mp->dev, "can't allocate rx skb ring\n");
+ rxq->rx_skb = kmalloc_array(rxq->rx_ring_size, sizeof(*rxq->rx_skb),
+ GFP_KERNEL);
+ if (rxq->rx_skb == NULL)
goto out_free;
- }
rx_desc = rxq->rx_desc_area;
for (i = 0; i < rxq->rx_ring_size; i++) {
@@ -2789,7 +2787,7 @@ static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex)
phy_reset(mp);
- phy_attach(mp->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_GMII);
+ phy_attach(mp->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_GMII);
if (speed == 0) {
phy->autoneg = AUTONEG_ENABLE;
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index 74f1c157a480..77b7c80262f4 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -164,7 +164,6 @@ static int orion_mdio_probe(struct platform_device *pdev)
bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
if (!bus->irq) {
- dev_err(&pdev->dev, "Cannot allocate PHY IRQ array\n");
mdiobus_free(bus);
return -ENOMEM;
}
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index b6025c305e10..cd345b8969bc 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -12,7 +12,6 @@
*/
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/platform_device.h>
diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index 10d678d3dd01..037ed866c22f 100644
--- a/drivers/net/ethernet/marvell/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -627,7 +627,6 @@ static int pxa168_eth_set_mac_address(struct net_device *dev, void *addr)
if (!is_valid_ether_addr(sa->sa_data))
return -EADDRNOTAVAIL;
memcpy(oldMac, dev->dev_addr, ETH_ALEN);
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
netif_addr_lock_bh(dev);
update_hash_table_mac_address(pep, oldMac, dev->dev_addr);
@@ -1391,7 +1390,7 @@ static void phy_init(struct pxa168_eth_private *pep, int speed, int duplex)
struct phy_device *phy = pep->phy;
ethernet_phy_reset(pep);
- phy_attach(pep->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_MII);
+ phy_attach(pep->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_MII);
if (speed == 0) {
phy->autoneg = AUTONEG_ENABLE;
@@ -1444,10 +1443,10 @@ static int pxa168_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static void pxa168_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strncpy(info->driver, DRIVER_NAME, 32);
- strncpy(info->version, DRIVER_VERSION, 32);
- strncpy(info->fw_version, "N/A", 32);
- strncpy(info->bus_info, "N/A", 32);
+ strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+ strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
}
static const struct ethtool_ops pxa168_ethtool_ops = {
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index 5544a1fe2f94..171f4b3dda07 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -3855,7 +3855,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
/* read the mac address */
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
return dev;
}
@@ -3917,10 +3916,9 @@ static int skge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* space for skge@pci:0000:04:00.0 */
hw = kzalloc(sizeof(*hw) + strlen(DRV_NAME "@pci:")
+ strlen(pci_name(pdev)) + 1, GFP_KERNEL);
- if (!hw) {
- dev_err(&pdev->dev, "cannot allocate hardware struct\n");
+ if (!hw)
goto err_out_free_regions;
- }
+
sprintf(hw->irq_name, DRV_NAME "@pci:%s", pci_name(pdev));
hw->pdev = pdev;
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 3269eb38cc57..fc07ca35721b 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -4801,7 +4801,6 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
/* read the mac address */
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
return dev;
}
@@ -4970,10 +4969,8 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw = kzalloc(sizeof(*hw) + strlen(DRV_NAME "@pci:")
+ strlen(pci_name(pdev)) + 1, GFP_KERNEL);
- if (!hw) {
- dev_err(&pdev->dev, "cannot allocate hardware struct\n");
+ if (!hw)
goto err_out_free_regions;
- }
hw->pdev = pdev;
sprintf(hw->irq_name, DRV_NAME "@pci:%s", pci_name(pdev));
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 03447dad07e9..00f25b5f297f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -35,6 +35,8 @@
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/mlx4/driver.h>
+#include <linux/in.h>
+#include <net/ip.h>
#include "mlx4_en.h"
#include "en_port.h"
@@ -494,7 +496,7 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
mutex_lock(&mdev->state_lock);
if (priv->port_up) {
port_up = 1;
- mlx4_en_stop_port(dev);
+ mlx4_en_stop_port(dev, 1);
}
mlx4_en_free_resources(priv);
@@ -589,7 +591,7 @@ static int mlx4_en_set_rxfh_indir(struct net_device *dev,
mutex_lock(&mdev->state_lock);
if (priv->port_up) {
port_up = 1;
- mlx4_en_stop_port(dev);
+ mlx4_en_stop_port(dev, 1);
}
priv->prof->rss_rings = rss_rings;
@@ -664,27 +666,90 @@ static int mlx4_en_validate_flow(struct net_device *dev,
if ((cmd->fs.flow_type & FLOW_EXT)) {
if (cmd->fs.m_ext.vlan_etype ||
- !(cmd->fs.m_ext.vlan_tci == 0 ||
- cmd->fs.m_ext.vlan_tci == cpu_to_be16(0xfff)))
+ !((cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK)) ==
+ 0 ||
+ (cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK)) ==
+ cpu_to_be16(VLAN_VID_MASK)))
return -EINVAL;
+
+ if (cmd->fs.m_ext.vlan_tci) {
+ if (be16_to_cpu(cmd->fs.h_ext.vlan_tci) >= VLAN_N_VID)
+ return -EINVAL;
+
+ }
}
return 0;
}
+static int mlx4_en_ethtool_add_mac_rule(struct ethtool_rxnfc *cmd,
+ struct list_head *rule_list_h,
+ struct mlx4_spec_list *spec_l2,
+ unsigned char *mac)
+{
+ int err = 0;
+ __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
+
+ spec_l2->id = MLX4_NET_TRANS_RULE_ID_ETH;
+ memcpy(spec_l2->eth.dst_mac_msk, &mac_msk, ETH_ALEN);
+ memcpy(spec_l2->eth.dst_mac, mac, ETH_ALEN);
+
+ if ((cmd->fs.flow_type & FLOW_EXT) &&
+ (cmd->fs.m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK))) {
+ spec_l2->eth.vlan_id = cmd->fs.h_ext.vlan_tci;
+ spec_l2->eth.vlan_id_msk = cpu_to_be16(VLAN_VID_MASK);
+ }
+
+ list_add_tail(&spec_l2->list, rule_list_h);
+
+ return err;
+}
+
+static int mlx4_en_ethtool_add_mac_rule_by_ipv4(struct mlx4_en_priv *priv,
+ struct ethtool_rxnfc *cmd,
+ struct list_head *rule_list_h,
+ struct mlx4_spec_list *spec_l2,
+ __be32 ipv4_dst)
+{
+#ifdef CONFIG_INET
+ unsigned char mac[ETH_ALEN];
+
+ if (!ipv4_is_multicast(ipv4_dst)) {
+ if (cmd->fs.flow_type & FLOW_MAC_EXT)
+ memcpy(&mac, cmd->fs.h_ext.h_dest, ETH_ALEN);
+ else
+ memcpy(&mac, priv->dev->dev_addr, ETH_ALEN);
+ } else {
+ ip_eth_mc_map(ipv4_dst, mac);
+ }
+
+ return mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2, &mac[0]);
+#else
+ return -EINVAL;
+#endif
+}
+
static int add_ip_rule(struct mlx4_en_priv *priv,
- struct ethtool_rxnfc *cmd,
- struct list_head *list_h)
+ struct ethtool_rxnfc *cmd,
+ struct list_head *list_h)
{
- struct mlx4_spec_list *spec_l3;
+ int err;
+ struct mlx4_spec_list *spec_l2 = NULL;
+ struct mlx4_spec_list *spec_l3 = NULL;
struct ethtool_usrip4_spec *l3_mask = &cmd->fs.m_u.usr_ip4_spec;
- spec_l3 = kzalloc(sizeof *spec_l3, GFP_KERNEL);
- if (!spec_l3) {
- en_err(priv, "Fail to alloc ethtool rule.\n");
- return -ENOMEM;
+ spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL);
+ spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
+ if (!spec_l2 || !spec_l3) {
+ err = -ENOMEM;
+ goto free_spec;
}
+ err = mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h, spec_l2,
+ cmd->fs.h_u.
+ usr_ip4_spec.ip4dst);
+ if (err)
+ goto free_spec;
spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4;
spec_l3->ipv4.src_ip = cmd->fs.h_u.usr_ip4_spec.ip4src;
if (l3_mask->ip4src)
@@ -695,34 +760,52 @@ static int add_ip_rule(struct mlx4_en_priv *priv,
list_add_tail(&spec_l3->list, list_h);
return 0;
+
+free_spec:
+ kfree(spec_l2);
+ kfree(spec_l3);
+ return err;
}
static int add_tcp_udp_rule(struct mlx4_en_priv *priv,
struct ethtool_rxnfc *cmd,
struct list_head *list_h, int proto)
{
- struct mlx4_spec_list *spec_l3;
- struct mlx4_spec_list *spec_l4;
+ int err;
+ struct mlx4_spec_list *spec_l2 = NULL;
+ struct mlx4_spec_list *spec_l3 = NULL;
+ struct mlx4_spec_list *spec_l4 = NULL;
struct ethtool_tcpip4_spec *l4_mask = &cmd->fs.m_u.tcp_ip4_spec;
- spec_l3 = kzalloc(sizeof *spec_l3, GFP_KERNEL);
- spec_l4 = kzalloc(sizeof *spec_l4, GFP_KERNEL);
- if (!spec_l4 || !spec_l3) {
- en_err(priv, "Fail to alloc ethtool rule.\n");
- kfree(spec_l3);
- kfree(spec_l4);
- return -ENOMEM;
+ spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
+ spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL);
+ spec_l4 = kzalloc(sizeof(*spec_l4), GFP_KERNEL);
+ if (!spec_l2 || !spec_l3 || !spec_l4) {
+ err = -ENOMEM;
+ goto free_spec;
}
spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4;
if (proto == TCP_V4_FLOW) {
+ err = mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h,
+ spec_l2,
+ cmd->fs.h_u.
+ tcp_ip4_spec.ip4dst);
+ if (err)
+ goto free_spec;
spec_l4->id = MLX4_NET_TRANS_RULE_ID_TCP;
spec_l3->ipv4.src_ip = cmd->fs.h_u.tcp_ip4_spec.ip4src;
spec_l3->ipv4.dst_ip = cmd->fs.h_u.tcp_ip4_spec.ip4dst;
spec_l4->tcp_udp.src_port = cmd->fs.h_u.tcp_ip4_spec.psrc;
spec_l4->tcp_udp.dst_port = cmd->fs.h_u.tcp_ip4_spec.pdst;
} else {
+ err = mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h,
+ spec_l2,
+ cmd->fs.h_u.
+ udp_ip4_spec.ip4dst);
+ if (err)
+ goto free_spec;
spec_l4->id = MLX4_NET_TRANS_RULE_ID_UDP;
spec_l3->ipv4.src_ip = cmd->fs.h_u.udp_ip4_spec.ip4src;
spec_l3->ipv4.dst_ip = cmd->fs.h_u.udp_ip4_spec.ip4dst;
@@ -744,6 +827,12 @@ static int add_tcp_udp_rule(struct mlx4_en_priv *priv,
list_add_tail(&spec_l4->list, list_h);
return 0;
+
+free_spec:
+ kfree(spec_l2);
+ kfree(spec_l3);
+ kfree(spec_l4);
+ return err;
}
static int mlx4_en_ethtool_to_net_trans_rule(struct net_device *dev,
@@ -751,43 +840,23 @@ static int mlx4_en_ethtool_to_net_trans_rule(struct net_device *dev,
struct list_head *rule_list_h)
{
int err;
- __be64 be_mac;
struct ethhdr *eth_spec;
- struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_spec_list *spec_l2;
- __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
+ struct mlx4_en_priv *priv = netdev_priv(dev);
err = mlx4_en_validate_flow(dev, cmd);
if (err)
return err;
- spec_l2 = kzalloc(sizeof *spec_l2, GFP_KERNEL);
- if (!spec_l2)
- return -ENOMEM;
-
- if (cmd->fs.flow_type & FLOW_MAC_EXT) {
- memcpy(&be_mac, cmd->fs.h_ext.h_dest, ETH_ALEN);
- } else {
- u64 mac = priv->mac & MLX4_MAC_MASK;
- be_mac = cpu_to_be64(mac << 16);
- }
-
- spec_l2->id = MLX4_NET_TRANS_RULE_ID_ETH;
- memcpy(spec_l2->eth.dst_mac_msk, &mac_msk, ETH_ALEN);
- if ((cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) != ETHER_FLOW)
- memcpy(spec_l2->eth.dst_mac, &be_mac, ETH_ALEN);
-
- if ((cmd->fs.flow_type & FLOW_EXT) && cmd->fs.m_ext.vlan_tci) {
- spec_l2->eth.vlan_id = cmd->fs.h_ext.vlan_tci;
- spec_l2->eth.vlan_id_msk = cpu_to_be16(0xfff);
- }
-
- list_add_tail(&spec_l2->list, rule_list_h);
-
switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
case ETHER_FLOW:
+ spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
+ if (!spec_l2)
+ return -ENOMEM;
+
eth_spec = &cmd->fs.h_u.ether_spec;
- memcpy(&spec_l2->eth.dst_mac, eth_spec->h_dest, ETH_ALEN);
+ mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2,
+ &eth_spec->h_dest[0]);
spec_l2->eth.ether_type = eth_spec->h_proto;
if (eth_spec->h_proto)
spec_l2->eth.ether_type_enable = 1;
@@ -861,6 +930,7 @@ static int mlx4_en_flow_replace(struct net_device *dev,
loc_rule->id = 0;
memset(&loc_rule->flow_spec, 0,
sizeof(struct ethtool_rx_flow_spec));
+ list_del(&loc_rule->list);
}
err = mlx4_flow_attach(priv->mdev->dev, &rule, &reg_id);
if (err) {
@@ -871,6 +941,7 @@ static int mlx4_en_flow_replace(struct net_device *dev,
loc_rule->id = reg_id;
memcpy(&loc_rule->flow_spec, &cmd->fs,
sizeof(struct ethtool_rx_flow_spec));
+ list_add_tail(&loc_rule->list, &priv->ethtool_list);
out_free_list:
list_for_each_entry_safe(spec, tmp_spec, &rule.list, list) {
@@ -904,6 +975,7 @@ static int mlx4_en_flow_detach(struct net_device *dev,
}
rule->id = 0;
memset(&rule->flow_spec, 0, sizeof(struct ethtool_rx_flow_spec));
+ list_del(&rule->list);
out:
return err;
@@ -952,7 +1024,8 @@ static int mlx4_en_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
if ((cmd->cmd == ETHTOOL_GRXCLSRLCNT ||
cmd->cmd == ETHTOOL_GRXCLSRULE ||
cmd->cmd == ETHTOOL_GRXCLSRLALL) &&
- mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)
+ (mdev->dev->caps.steering_mode !=
+ MLX4_STEERING_MODE_DEVICE_MANAGED || !priv->port_up))
return -EINVAL;
switch (cmd->cmd) {
@@ -988,7 +1061,8 @@ static int mlx4_en_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
- if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)
+ if (mdev->dev->caps.steering_mode !=
+ MLX4_STEERING_MODE_DEVICE_MANAGED || !priv->port_up)
return -EINVAL;
switch (cmd->cmd) {
@@ -1037,7 +1111,7 @@ static int mlx4_en_set_channels(struct net_device *dev,
mutex_lock(&mdev->state_lock);
if (priv->port_up) {
port_up = 1;
- mlx4_en_stop_port(dev);
+ mlx4_en_stop_port(dev, 1);
}
mlx4_en_free_resources(priv);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index 3a2b8c65642d..b2cca58de910 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -64,7 +64,7 @@ static const char mlx4_en_version[] =
/* Enable RSS UDP traffic */
MLX4_EN_PARM_INT(udp_rss, 1,
- "Enable RSS for incomming UDP traffic or disabled (0)");
+ "Enable RSS for incoming UDP traffic or disabled (0)");
/* Priority pausing */
MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
@@ -95,6 +95,28 @@ int en_print(const char *level, const struct mlx4_en_priv *priv,
return i;
}
+void mlx4_en_update_loopback_state(struct net_device *dev,
+ netdev_features_t features)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+
+ priv->flags &= ~(MLX4_EN_FLAG_RX_FILTER_NEEDED|
+ MLX4_EN_FLAG_ENABLE_HW_LOOPBACK);
+
+ /* Drop the packet if SRIOV is not enabled
+ * and not performing the selftest or flb disabled
+ */
+ if (mlx4_is_mfunc(priv->mdev->dev) &&
+ !(features & NETIF_F_LOOPBACK) && !priv->validate_loopback)
+ priv->flags |= MLX4_EN_FLAG_RX_FILTER_NEEDED;
+
+ /* Set dmac in Tx WQE if we are in SRIOV mode or if loopback selftest
+ * is requested
+ */
+ if (mlx4_is_mfunc(priv->mdev->dev) || priv->validate_loopback)
+ priv->flags |= MLX4_EN_FLAG_ENABLE_HW_LOOPBACK;
+}
+
static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
{
struct mlx4_en_profile *params = &mdev->profile;
@@ -191,10 +213,8 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
printk_once(KERN_INFO "%s", mlx4_en_version);
- mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+ mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev) {
- dev_err(&dev->pdev->dev, "Device struct alloc failed, "
- "aborting.\n");
err = -ENOMEM;
goto err_free_res;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 75a3f467bb5b..5088dc5c3d1a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -132,17 +132,14 @@ static void mlx4_en_filter_work(struct work_struct *work)
.priority = MLX4_DOMAIN_RFS,
};
int rc;
- __be64 mac;
__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
list_add_tail(&spec_eth.list, &rule.list);
list_add_tail(&spec_ip.list, &rule.list);
list_add_tail(&spec_tcp.list, &rule.list);
- mac = cpu_to_be64((priv->mac & MLX4_MAC_MASK) << 16);
-
rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn;
- memcpy(spec_eth.eth.dst_mac, &mac, ETH_ALEN);
+ memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN);
memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
filter->activated = 0;
@@ -413,6 +410,235 @@ static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
return 0;
}
+static void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac)
+{
+ unsigned int i;
+ for (i = ETH_ALEN - 1; i; --i) {
+ dst_mac[i] = src_mac & 0xff;
+ src_mac >>= 8;
+ }
+ memset(&dst_mac[ETH_ALEN], 0, 2);
+}
+
+static int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv,
+ unsigned char *mac, int *qpn, u64 *reg_id)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_dev *dev = mdev->dev;
+ int err;
+
+ switch (dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_B0: {
+ struct mlx4_qp qp;
+ u8 gid[16] = {0};
+
+ qp.qpn = *qpn;
+ memcpy(&gid[10], mac, ETH_ALEN);
+ gid[5] = priv->port;
+
+ err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH);
+ break;
+ }
+ case MLX4_STEERING_MODE_DEVICE_MANAGED: {
+ struct mlx4_spec_list spec_eth = { {NULL} };
+ __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
+
+ struct mlx4_net_trans_rule rule = {
+ .queue_mode = MLX4_NET_TRANS_Q_FIFO,
+ .exclusive = 0,
+ .allow_loopback = 1,
+ .promisc_mode = MLX4_FS_PROMISC_NONE,
+ .priority = MLX4_DOMAIN_NIC,
+ };
+
+ rule.port = priv->port;
+ rule.qpn = *qpn;
+ INIT_LIST_HEAD(&rule.list);
+
+ spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH;
+ memcpy(spec_eth.eth.dst_mac, mac, ETH_ALEN);
+ memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
+ list_add_tail(&spec_eth.list, &rule.list);
+
+ err = mlx4_flow_attach(dev, &rule, reg_id);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+ if (err)
+ en_warn(priv, "Failed Attaching Unicast\n");
+
+ return err;
+}
+
+static void mlx4_en_uc_steer_release(struct mlx4_en_priv *priv,
+ unsigned char *mac, int qpn, u64 reg_id)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_dev *dev = mdev->dev;
+
+ switch (dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_B0: {
+ struct mlx4_qp qp;
+ u8 gid[16] = {0};
+
+ qp.qpn = qpn;
+ memcpy(&gid[10], mac, ETH_ALEN);
+ gid[5] = priv->port;
+
+ mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH);
+ break;
+ }
+ case MLX4_STEERING_MODE_DEVICE_MANAGED: {
+ mlx4_flow_detach(dev, reg_id);
+ break;
+ }
+ default:
+ en_err(priv, "Invalid steering mode.\n");
+ }
+}
+
+static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_dev *dev = mdev->dev;
+ struct mlx4_mac_entry *entry;
+ int index = 0;
+ int err = 0;
+ u64 reg_id;
+ int *qpn = &priv->base_qpn;
+ u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+
+ en_dbg(DRV, priv, "Registering MAC: %pM for adding\n",
+ priv->dev->dev_addr);
+ index = mlx4_register_mac(dev, priv->port, mac);
+ if (index < 0) {
+ err = index;
+ en_err(priv, "Failed adding MAC: %pM\n",
+ priv->dev->dev_addr);
+ return err;
+ }
+
+ if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
+ int base_qpn = mlx4_get_base_qpn(dev, priv->port);
+ *qpn = base_qpn + index;
+ return 0;
+ }
+
+ err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
+ en_dbg(DRV, priv, "Reserved qp %d\n", *qpn);
+ if (err) {
+ en_err(priv, "Failed to reserve qp for mac registration\n");
+ goto qp_err;
+ }
+
+ err = mlx4_en_uc_steer_add(priv, priv->dev->dev_addr, qpn, &reg_id);
+ if (err)
+ goto steer_err;
+
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ err = -ENOMEM;
+ goto alloc_err;
+ }
+ memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac));
+ entry->reg_id = reg_id;
+
+ hlist_add_head_rcu(&entry->hlist,
+ &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]);
+
+ return 0;
+
+alloc_err:
+ mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id);
+
+steer_err:
+ mlx4_qp_release_range(dev, *qpn, 1);
+
+qp_err:
+ mlx4_unregister_mac(dev, priv->port, mac);
+ return err;
+}
+
+static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_dev *dev = mdev->dev;
+ int qpn = priv->base_qpn;
+ u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+
+ en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
+ priv->dev->dev_addr);
+ mlx4_unregister_mac(dev, priv->port, mac);
+
+ if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
+ struct mlx4_mac_entry *entry;
+ struct hlist_node *n, *tmp;
+ struct hlist_head *bucket;
+ unsigned int mac_hash;
+
+ mac_hash = priv->dev->dev_addr[MLX4_EN_MAC_HASH_IDX];
+ bucket = &priv->mac_hash[mac_hash];
+ hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
+ if (ether_addr_equal_64bits(entry->mac,
+ priv->dev->dev_addr)) {
+ en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n",
+ priv->port, priv->dev->dev_addr, qpn);
+ mlx4_en_uc_steer_release(priv, entry->mac,
+ qpn, entry->reg_id);
+ mlx4_qp_release_range(dev, qpn, 1);
+
+ hlist_del_rcu(&entry->hlist);
+ kfree_rcu(entry, rcu);
+ break;
+ }
+ }
+ }
+}
+
+static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
+ unsigned char *new_mac, unsigned char *prev_mac)
+{
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct mlx4_dev *dev = mdev->dev;
+ int err = 0;
+ u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac);
+
+ if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
+ struct hlist_head *bucket;
+ unsigned int mac_hash;
+ struct mlx4_mac_entry *entry;
+ struct hlist_node *n, *tmp;
+ u64 prev_mac_u64 = mlx4_en_mac_to_u64(prev_mac);
+
+ bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]];
+ hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
+ if (ether_addr_equal_64bits(entry->mac, prev_mac)) {
+ mlx4_en_uc_steer_release(priv, entry->mac,
+ qpn, entry->reg_id);
+ mlx4_unregister_mac(dev, priv->port,
+ prev_mac_u64);
+ hlist_del_rcu(&entry->hlist);
+ synchronize_rcu();
+ memcpy(entry->mac, new_mac, ETH_ALEN);
+ entry->reg_id = 0;
+ mac_hash = new_mac[MLX4_EN_MAC_HASH_IDX];
+ hlist_add_head_rcu(&entry->hlist,
+ &priv->mac_hash[mac_hash]);
+ mlx4_register_mac(dev, priv->port, new_mac_u64);
+ err = mlx4_en_uc_steer_add(priv, new_mac,
+ &qpn,
+ &entry->reg_id);
+ return err;
+ }
+ }
+ return -EINVAL;
+ }
+
+ return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64);
+}
+
u64 mlx4_en_mac_to_u64(u8 *addr)
{
u64 mac = 0;
@@ -435,7 +661,6 @@ static int mlx4_en_set_mac(struct net_device *dev, void *addr)
return -EADDRNOTAVAIL;
memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN);
- priv->mac = mlx4_en_mac_to_u64(dev->dev_addr);
queue_work(mdev->workqueue, &priv->mac_task);
return 0;
}
@@ -450,13 +675,14 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
mutex_lock(&mdev->state_lock);
if (priv->port_up) {
/* Remove old MAC and insert the new one */
- err = mlx4_replace_mac(mdev->dev, priv->port,
- priv->base_qpn, priv->mac);
+ err = mlx4_en_replace_mac(priv, priv->base_qpn,
+ priv->dev->dev_addr, priv->prev_mac);
if (err)
en_err(priv, "Failed changing HW MAC address\n");
+ memcpy(priv->prev_mac, priv->dev->dev_addr,
+ sizeof(priv->prev_mac));
} else
- en_dbg(HW, priv, "Port is down while "
- "registering mac, exiting...\n");
+ en_dbg(HW, priv, "Port is down while registering mac, exiting...\n");
mutex_unlock(&mdev->state_lock);
}
@@ -482,7 +708,6 @@ static void mlx4_en_cache_mclist(struct net_device *dev)
netdev_for_each_mc_addr(ha, dev) {
tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC);
if (!tmp) {
- en_err(priv, "failed to allocate multicast list\n");
mlx4_en_clear_list(dev);
return;
}
@@ -526,181 +751,153 @@ static void update_mclist_flags(struct mlx4_en_priv *priv,
}
}
if (!found) {
- new_mc = kmalloc(sizeof(struct mlx4_en_mc_list),
+ new_mc = kmemdup(src_tmp,
+ sizeof(struct mlx4_en_mc_list),
GFP_KERNEL);
- if (!new_mc) {
- en_err(priv, "Failed to allocate current multicast list\n");
+ if (!new_mc)
return;
- }
- memcpy(new_mc, src_tmp,
- sizeof(struct mlx4_en_mc_list));
+
new_mc->action = MCLIST_ADD;
list_add_tail(&new_mc->list, dst);
}
}
}
-static void mlx4_en_set_multicast(struct net_device *dev)
+static void mlx4_en_set_rx_mode(struct net_device *dev)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
if (!priv->port_up)
return;
- queue_work(priv->mdev->workqueue, &priv->mcast_task);
+ queue_work(priv->mdev->workqueue, &priv->rx_mode_task);
}
-static void mlx4_en_do_set_multicast(struct work_struct *work)
+static void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv,
+ struct mlx4_en_dev *mdev)
{
- struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
- mcast_task);
- struct mlx4_en_dev *mdev = priv->mdev;
- struct net_device *dev = priv->dev;
- struct mlx4_en_mc_list *mclist, *tmp;
- u64 mcast_addr = 0;
- u8 mc_list[16] = {0};
int err = 0;
- mutex_lock(&mdev->state_lock);
- if (!mdev->device_up) {
- en_dbg(HW, priv, "Card is not up, "
- "ignoring multicast change.\n");
- goto out;
- }
- if (!priv->port_up) {
- en_dbg(HW, priv, "Port is down, "
- "ignoring multicast change.\n");
- goto out;
- }
-
- if (!netif_carrier_ok(dev)) {
- if (!mlx4_en_QUERY_PORT(mdev, priv->port)) {
- if (priv->port_state.link_state) {
- priv->last_link_state = MLX4_DEV_EVENT_PORT_UP;
- netif_carrier_on(dev);
- en_dbg(LINK, priv, "Link Up\n");
- }
- }
- }
-
- /*
- * Promsicuous mode: disable all filters
- */
-
- if (dev->flags & IFF_PROMISC) {
- if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) {
- if (netif_msg_rx_status(priv))
- en_warn(priv, "Entering promiscuous mode\n");
- priv->flags |= MLX4_EN_FLAG_PROMISC;
-
- /* Enable promiscouos mode */
- switch (mdev->dev->caps.steering_mode) {
- case MLX4_STEERING_MODE_DEVICE_MANAGED:
- err = mlx4_flow_steer_promisc_add(mdev->dev,
- priv->port,
- priv->base_qpn,
- MLX4_FS_PROMISC_UPLINK);
- if (err)
- en_err(priv, "Failed enabling promiscuous mode\n");
- priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
- break;
-
- case MLX4_STEERING_MODE_B0:
- err = mlx4_unicast_promisc_add(mdev->dev,
- priv->base_qpn,
- priv->port);
- if (err)
- en_err(priv, "Failed enabling unicast promiscuous mode\n");
-
- /* Add the default qp number as multicast
- * promisc
- */
- if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) {
- err = mlx4_multicast_promisc_add(mdev->dev,
- priv->base_qpn,
- priv->port);
- if (err)
- en_err(priv, "Failed enabling multicast promiscuous mode\n");
- priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
- }
- break;
-
- case MLX4_STEERING_MODE_A0:
- err = mlx4_SET_PORT_qpn_calc(mdev->dev,
- priv->port,
- priv->base_qpn,
- 1);
- if (err)
- en_err(priv, "Failed enabling promiscuous mode\n");
- break;
- }
-
- /* Disable port multicast filter (unconditionally) */
- err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
- 0, MLX4_MCAST_DISABLE);
- if (err)
- en_err(priv, "Failed disabling "
- "multicast filter\n");
-
- /* Disable port VLAN filter */
- err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
- if (err)
- en_err(priv, "Failed disabling VLAN filter\n");
- }
- goto out;
- }
-
- /*
- * Not in promiscuous mode
- */
-
- if (priv->flags & MLX4_EN_FLAG_PROMISC) {
+ if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) {
if (netif_msg_rx_status(priv))
- en_warn(priv, "Leaving promiscuous mode\n");
- priv->flags &= ~MLX4_EN_FLAG_PROMISC;
+ en_warn(priv, "Entering promiscuous mode\n");
+ priv->flags |= MLX4_EN_FLAG_PROMISC;
- /* Disable promiscouos mode */
+ /* Enable promiscouos mode */
switch (mdev->dev->caps.steering_mode) {
case MLX4_STEERING_MODE_DEVICE_MANAGED:
- err = mlx4_flow_steer_promisc_remove(mdev->dev,
- priv->port,
- MLX4_FS_PROMISC_UPLINK);
+ err = mlx4_flow_steer_promisc_add(mdev->dev,
+ priv->port,
+ priv->base_qpn,
+ MLX4_FS_PROMISC_UPLINK);
if (err)
- en_err(priv, "Failed disabling promiscuous mode\n");
- priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+ en_err(priv, "Failed enabling promiscuous mode\n");
+ priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
break;
case MLX4_STEERING_MODE_B0:
- err = mlx4_unicast_promisc_remove(mdev->dev,
- priv->base_qpn,
- priv->port);
+ err = mlx4_unicast_promisc_add(mdev->dev,
+ priv->base_qpn,
+ priv->port);
if (err)
- en_err(priv, "Failed disabling unicast promiscuous mode\n");
- /* Disable Multicast promisc */
- if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
- err = mlx4_multicast_promisc_remove(mdev->dev,
- priv->base_qpn,
- priv->port);
+ en_err(priv, "Failed enabling unicast promiscuous mode\n");
+
+ /* Add the default qp number as multicast
+ * promisc
+ */
+ if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) {
+ err = mlx4_multicast_promisc_add(mdev->dev,
+ priv->base_qpn,
+ priv->port);
if (err)
- en_err(priv, "Failed disabling multicast promiscuous mode\n");
- priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+ en_err(priv, "Failed enabling multicast promiscuous mode\n");
+ priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
}
break;
case MLX4_STEERING_MODE_A0:
err = mlx4_SET_PORT_qpn_calc(mdev->dev,
priv->port,
- priv->base_qpn, 0);
+ priv->base_qpn,
+ 1);
if (err)
- en_err(priv, "Failed disabling promiscuous mode\n");
+ en_err(priv, "Failed enabling promiscuous mode\n");
break;
}
- /* Enable port VLAN filter */
+ /* Disable port multicast filter (unconditionally) */
+ err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
+ 0, MLX4_MCAST_DISABLE);
+ if (err)
+ en_err(priv, "Failed disabling multicast filter\n");
+
+ /* Disable port VLAN filter */
err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
if (err)
- en_err(priv, "Failed enabling VLAN filter\n");
+ en_err(priv, "Failed disabling VLAN filter\n");
}
+}
+
+static void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv,
+ struct mlx4_en_dev *mdev)
+{
+ int err = 0;
+
+ if (netif_msg_rx_status(priv))
+ en_warn(priv, "Leaving promiscuous mode\n");
+ priv->flags &= ~MLX4_EN_FLAG_PROMISC;
+
+ /* Disable promiscouos mode */
+ switch (mdev->dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_DEVICE_MANAGED:
+ err = mlx4_flow_steer_promisc_remove(mdev->dev,
+ priv->port,
+ MLX4_FS_PROMISC_UPLINK);
+ if (err)
+ en_err(priv, "Failed disabling promiscuous mode\n");
+ priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+ break;
+
+ case MLX4_STEERING_MODE_B0:
+ err = mlx4_unicast_promisc_remove(mdev->dev,
+ priv->base_qpn,
+ priv->port);
+ if (err)
+ en_err(priv, "Failed disabling unicast promiscuous mode\n");
+ /* Disable Multicast promisc */
+ if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
+ err = mlx4_multicast_promisc_remove(mdev->dev,
+ priv->base_qpn,
+ priv->port);
+ if (err)
+ en_err(priv, "Failed disabling multicast promiscuous mode\n");
+ priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+ }
+ break;
+
+ case MLX4_STEERING_MODE_A0:
+ err = mlx4_SET_PORT_qpn_calc(mdev->dev,
+ priv->port,
+ priv->base_qpn, 0);
+ if (err)
+ en_err(priv, "Failed disabling promiscuous mode\n");
+ break;
+ }
+
+ /* Enable port VLAN filter */
+ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
+ if (err)
+ en_err(priv, "Failed enabling VLAN filter\n");
+}
+
+static void mlx4_en_do_multicast(struct mlx4_en_priv *priv,
+ struct net_device *dev,
+ struct mlx4_en_dev *mdev)
+{
+ struct mlx4_en_mc_list *mclist, *tmp;
+ u64 mcast_addr = 0;
+ u8 mc_list[16] = {0};
+ int err = 0;
/* Enable/disable the multicast filter according to IFF_ALLMULTI */
if (dev->flags & IFF_ALLMULTI) {
@@ -767,9 +964,9 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
/* Update multicast list - we cache all addresses so they won't
* change while HW is updated holding the command semaphor */
- netif_tx_lock_bh(dev);
+ netif_addr_lock_bh(dev);
mlx4_en_cache_mclist(dev);
- netif_tx_unlock_bh(dev);
+ netif_addr_unlock_bh(dev);
list_for_each_entry(mclist, &priv->mc_list, list) {
mcast_addr = mlx4_en_mac_to_u64(mclist->addr);
mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
@@ -814,6 +1011,170 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
}
}
}
+}
+
+static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv,
+ struct net_device *dev,
+ struct mlx4_en_dev *mdev)
+{
+ struct netdev_hw_addr *ha;
+ struct mlx4_mac_entry *entry;
+ struct hlist_node *n, *tmp;
+ bool found;
+ u64 mac;
+ int err = 0;
+ struct hlist_head *bucket;
+ unsigned int i;
+ int removed = 0;
+ u32 prev_flags;
+
+ /* Note that we do not need to protect our mac_hash traversal with rcu,
+ * since all modification code is protected by mdev->state_lock
+ */
+
+ /* find what to remove */
+ for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) {
+ bucket = &priv->mac_hash[i];
+ hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
+ found = false;
+ netdev_for_each_uc_addr(ha, dev) {
+ if (ether_addr_equal_64bits(entry->mac,
+ ha->addr)) {
+ found = true;
+ break;
+ }
+ }
+
+ /* MAC address of the port is not in uc list */
+ if (ether_addr_equal_64bits(entry->mac, dev->dev_addr))
+ found = true;
+
+ if (!found) {
+ mac = mlx4_en_mac_to_u64(entry->mac);
+ mlx4_en_uc_steer_release(priv, entry->mac,
+ priv->base_qpn,
+ entry->reg_id);
+ mlx4_unregister_mac(mdev->dev, priv->port, mac);
+
+ hlist_del_rcu(&entry->hlist);
+ kfree_rcu(entry, rcu);
+ en_dbg(DRV, priv, "Removed MAC %pM on port:%d\n",
+ entry->mac, priv->port);
+ ++removed;
+ }
+ }
+ }
+
+ /* if we didn't remove anything, there is no use in trying to add
+ * again once we are in a forced promisc mode state
+ */
+ if ((priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) && 0 == removed)
+ return;
+
+ prev_flags = priv->flags;
+ priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC;
+
+ /* find what to add */
+ netdev_for_each_uc_addr(ha, dev) {
+ found = false;
+ bucket = &priv->mac_hash[ha->addr[MLX4_EN_MAC_HASH_IDX]];
+ hlist_for_each_entry(entry, n, bucket, hlist) {
+ if (ether_addr_equal_64bits(entry->mac, ha->addr)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ en_err(priv, "Failed adding MAC %pM on port:%d (out of memory)\n",
+ ha->addr, priv->port);
+ priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
+ break;
+ }
+ mac = mlx4_en_mac_to_u64(ha->addr);
+ memcpy(entry->mac, ha->addr, ETH_ALEN);
+ err = mlx4_register_mac(mdev->dev, priv->port, mac);
+ if (err < 0) {
+ en_err(priv, "Failed registering MAC %pM on port %d: %d\n",
+ ha->addr, priv->port, err);
+ kfree(entry);
+ priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
+ break;
+ }
+ err = mlx4_en_uc_steer_add(priv, ha->addr,
+ &priv->base_qpn,
+ &entry->reg_id);
+ if (err) {
+ en_err(priv, "Failed adding MAC %pM on port %d: %d\n",
+ ha->addr, priv->port, err);
+ mlx4_unregister_mac(mdev->dev, priv->port, mac);
+ kfree(entry);
+ priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
+ break;
+ } else {
+ unsigned int mac_hash;
+ en_dbg(DRV, priv, "Added MAC %pM on port:%d\n",
+ ha->addr, priv->port);
+ mac_hash = ha->addr[MLX4_EN_MAC_HASH_IDX];
+ bucket = &priv->mac_hash[mac_hash];
+ hlist_add_head_rcu(&entry->hlist, bucket);
+ }
+ }
+ }
+
+ if (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) {
+ en_warn(priv, "Forcing promiscuous mode on port:%d\n",
+ priv->port);
+ } else if (prev_flags & MLX4_EN_FLAG_FORCE_PROMISC) {
+ en_warn(priv, "Stop forcing promiscuous mode on port:%d\n",
+ priv->port);
+ }
+}
+
+static void mlx4_en_do_set_rx_mode(struct work_struct *work)
+{
+ struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+ rx_mode_task);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct net_device *dev = priv->dev;
+
+ mutex_lock(&mdev->state_lock);
+ if (!mdev->device_up) {
+ en_dbg(HW, priv, "Card is not up, ignoring rx mode change.\n");
+ goto out;
+ }
+ if (!priv->port_up) {
+ en_dbg(HW, priv, "Port is down, ignoring rx mode change.\n");
+ goto out;
+ }
+
+ if (!netif_carrier_ok(dev)) {
+ if (!mlx4_en_QUERY_PORT(mdev, priv->port)) {
+ if (priv->port_state.link_state) {
+ priv->last_link_state = MLX4_DEV_EVENT_PORT_UP;
+ netif_carrier_on(dev);
+ en_dbg(LINK, priv, "Link Up\n");
+ }
+ }
+ }
+
+ if (dev->priv_flags & IFF_UNICAST_FLT)
+ mlx4_en_do_uc_filter(priv, dev, mdev);
+
+ /* Promsicuous mode: disable all filters */
+ if ((dev->flags & IFF_PROMISC) ||
+ (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) {
+ mlx4_en_set_promisc_mode(priv, mdev);
+ goto out;
+ }
+
+ /* Not in promiscuous mode */
+ if (priv->flags & MLX4_EN_FLAG_PROMISC)
+ mlx4_en_clear_promisc_mode(priv, mdev);
+
+ mlx4_en_do_multicast(priv, dev, mdev);
out:
mutex_unlock(&mdev->state_lock);
}
@@ -876,9 +1237,8 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
priv->rx_usecs = MLX4_EN_RX_COAL_TIME;
priv->tx_frames = MLX4_EN_TX_COAL_PKTS;
priv->tx_usecs = MLX4_EN_TX_COAL_TIME;
- en_dbg(INTR, priv, "Default coalesing params for mtu:%d - "
- "rx_frames:%d rx_usecs:%d\n",
- priv->dev->mtu, priv->rx_frames, priv->rx_usecs);
+ en_dbg(INTR, priv, "Default coalesing params for mtu:%d - rx_frames:%d rx_usecs:%d\n",
+ priv->dev->mtu, priv->rx_frames, priv->rx_usecs);
/* Setup cq moderation params */
for (i = 0; i < priv->rx_ring_num; i++) {
@@ -959,8 +1319,8 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
cq->moder_time = moder_time;
err = mlx4_en_set_cq_moder(priv, cq);
if (err)
- en_err(priv, "Failed modifying moderation "
- "for cq:%d\n", ring);
+ en_err(priv, "Failed modifying moderation for cq:%d\n",
+ ring);
}
priv->last_moder_packets[ring] = rx_packets;
priv->last_moder_bytes[ring] = rx_bytes;
@@ -977,12 +1337,12 @@ static void mlx4_en_do_get_stats(struct work_struct *work)
struct mlx4_en_dev *mdev = priv->mdev;
int err;
- err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0);
- if (err)
- en_dbg(HW, priv, "Could not update stats\n");
-
mutex_lock(&mdev->state_lock);
if (mdev->device_up) {
+ err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0);
+ if (err)
+ en_dbg(HW, priv, "Could not update stats\n");
+
if (priv->port_up)
mlx4_en_auto_moderation(priv);
@@ -1039,6 +1399,9 @@ int mlx4_en_start_port(struct net_device *dev)
INIT_LIST_HEAD(&priv->mc_list);
INIT_LIST_HEAD(&priv->curr_list);
+ INIT_LIST_HEAD(&priv->ethtool_list);
+ memset(&priv->ethtool_rules[0], 0,
+ sizeof(struct ethtool_flow_id) * MAX_NUM_OF_FS_RULES);
/* Calculate Rx buf size */
dev->mtu = min(dev->mtu, priv->max_mtu);
@@ -1074,8 +1437,7 @@ int mlx4_en_start_port(struct net_device *dev)
/* Set qp number */
en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port);
- err = mlx4_get_eth_qp(mdev->dev, priv->port,
- priv->mac, &priv->base_qpn);
+ err = mlx4_en_get_qp(priv);
if (err) {
en_err(priv, "Failed getting eth qp\n");
goto cq_err;
@@ -1138,8 +1500,8 @@ int mlx4_en_start_port(struct net_device *dev)
priv->prof->rx_pause,
priv->prof->rx_ppp);
if (err) {
- en_err(priv, "Failed setting port general configurations "
- "for port %d, with error %d\n", priv->port, err);
+ en_err(priv, "Failed setting port general configurations for port %d, with error %d\n",
+ priv->port, err);
goto tx_err;
}
/* Set default qp number */
@@ -1167,23 +1529,16 @@ int mlx4_en_start_port(struct net_device *dev)
/* Must redo promiscuous mode setup. */
priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC);
- if (mdev->dev->caps.steering_mode ==
- MLX4_STEERING_MODE_DEVICE_MANAGED) {
- mlx4_flow_steer_promisc_remove(mdev->dev,
- priv->port,
- MLX4_FS_PROMISC_UPLINK);
- mlx4_flow_steer_promisc_remove(mdev->dev,
- priv->port,
- MLX4_FS_PROMISC_ALL_MULTI);
- }
/* Schedule multicast task to populate multicast list */
- queue_work(mdev->workqueue, &priv->mcast_task);
+ queue_work(mdev->workqueue, &priv->rx_mode_task);
mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
priv->port_up = true;
netif_tx_start_all_queues(dev);
+ netif_device_attach(dev);
+
return 0;
tx_err:
@@ -1195,7 +1550,7 @@ tx_err:
rss_err:
mlx4_en_release_rss_steer(priv);
mac_err:
- mlx4_put_eth_qp(mdev->dev, priv->port, priv->mac, priv->base_qpn);
+ mlx4_en_put_qp(priv);
cq_err:
while (rx_index--)
mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]);
@@ -1206,11 +1561,12 @@ cq_err:
}
-void mlx4_en_stop_port(struct net_device *dev)
+void mlx4_en_stop_port(struct net_device *dev, int detach)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_mc_list *mclist, *tmp;
+ struct ethtool_flow_id *flow, *tmp_flow;
int i;
u8 mc_list[16] = {0};
@@ -1221,12 +1577,42 @@ void mlx4_en_stop_port(struct net_device *dev)
/* Synchronize with tx routine */
netif_tx_lock_bh(dev);
+ if (detach)
+ netif_device_detach(dev);
netif_tx_stop_all_queues(dev);
netif_tx_unlock_bh(dev);
+ netif_tx_disable(dev);
+
/* Set port as not active */
priv->port_up = false;
+ /* Promsicuous mode */
+ if (mdev->dev->caps.steering_mode ==
+ MLX4_STEERING_MODE_DEVICE_MANAGED) {
+ priv->flags &= ~(MLX4_EN_FLAG_PROMISC |
+ MLX4_EN_FLAG_MC_PROMISC);
+ mlx4_flow_steer_promisc_remove(mdev->dev,
+ priv->port,
+ MLX4_FS_PROMISC_UPLINK);
+ mlx4_flow_steer_promisc_remove(mdev->dev,
+ priv->port,
+ MLX4_FS_PROMISC_ALL_MULTI);
+ } else if (priv->flags & MLX4_EN_FLAG_PROMISC) {
+ priv->flags &= ~MLX4_EN_FLAG_PROMISC;
+
+ /* Disable promiscouos mode */
+ mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn,
+ priv->port);
+
+ /* Disable Multicast promisc */
+ if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
+ mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn,
+ priv->port);
+ priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC;
+ }
+ }
+
/* Detach All multicasts */
memset(&mc_list[10], 0xff, ETH_ALEN);
mc_list[5] = priv->port; /* needed for B0 steering support */
@@ -1263,8 +1649,20 @@ void mlx4_en_stop_port(struct net_device *dev)
mlx4_en_release_rss_steer(priv);
/* Unregister Mac address for the port */
- mlx4_put_eth_qp(mdev->dev, priv->port, priv->mac, priv->base_qpn);
- mdev->mac_removed[priv->port] = 1;
+ mlx4_en_put_qp(priv);
+ if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN))
+ mdev->mac_removed[priv->port] = 1;
+
+ /* Remove flow steering rules for the port*/
+ if (mdev->dev->caps.steering_mode ==
+ MLX4_STEERING_MODE_DEVICE_MANAGED) {
+ ASSERT_RTNL();
+ list_for_each_entry_safe(flow, tmp_flow,
+ &priv->ethtool_list, list) {
+ mlx4_flow_detach(mdev->dev, flow->id);
+ list_del(&flow->list);
+ }
+ }
/* Free RX Rings */
for (i = 0; i < priv->rx_ring_num; i++) {
@@ -1284,15 +1682,12 @@ static void mlx4_en_restart(struct work_struct *work)
watchdog_task);
struct mlx4_en_dev *mdev = priv->mdev;
struct net_device *dev = priv->dev;
- int i;
en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port);
mutex_lock(&mdev->state_lock);
if (priv->port_up) {
- mlx4_en_stop_port(dev);
- for (i = 0; i < priv->tx_ring_num; i++)
- netdev_tx_reset_queue(priv->tx_ring[i].tx_queue);
+ mlx4_en_stop_port(dev, 1);
if (mlx4_en_start_port(dev))
en_err(priv, "Failed restarting port %d\n", priv->port);
}
@@ -1362,7 +1757,7 @@ static int mlx4_en_close(struct net_device *dev)
mutex_lock(&mdev->state_lock);
- mlx4_en_stop_port(dev);
+ mlx4_en_stop_port(dev, 0);
netif_carrier_off(dev);
mutex_unlock(&mdev->state_lock);
@@ -1437,9 +1832,6 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->rx_ring_num);
if (!priv->dev->rx_cpu_rmap)
goto err;
-
- INIT_LIST_HEAD(&priv->filters);
- spin_lock_init(&priv->filters_lock);
#endif
return 0;
@@ -1503,7 +1895,7 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
* the port */
en_dbg(DRV, priv, "Change MTU called with card down!?\n");
} else {
- mlx4_en_stop_port(dev);
+ mlx4_en_stop_port(dev, 1);
err = mlx4_en_start_port(dev);
if (err) {
en_err(priv, "Failed restarting port:%d\n",
@@ -1527,17 +1919,92 @@ static int mlx4_en_set_features(struct net_device *netdev,
priv->ctrl_flags &=
cpu_to_be32(~MLX4_WQE_CTRL_FORCE_LOOPBACK);
+ mlx4_en_update_loopback_state(netdev, features);
+
return 0;
}
+static int mlx4_en_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+ struct net_device *dev,
+ const unsigned char *addr, u16 flags)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_dev *mdev = priv->mdev->dev;
+ int err;
+
+ if (!mlx4_is_mfunc(mdev))
+ return -EOPNOTSUPP;
+
+ /* Hardware does not support aging addresses, allow only
+ * permanent addresses if ndm_state is given
+ */
+ if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
+ en_info(priv, "Add FDB only supports static addresses\n");
+ return -EINVAL;
+ }
+
+ if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+ err = dev_uc_add_excl(dev, addr);
+ else if (is_multicast_ether_addr(addr))
+ err = dev_mc_add_excl(dev, addr);
+ else
+ err = -EINVAL;
+
+ /* Only return duplicate errors if NLM_F_EXCL is set */
+ if (err == -EEXIST && !(flags & NLM_F_EXCL))
+ err = 0;
+
+ return err;
+}
+
+static int mlx4_en_fdb_del(struct ndmsg *ndm,
+ struct nlattr *tb[],
+ struct net_device *dev,
+ const unsigned char *addr)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_dev *mdev = priv->mdev->dev;
+ int err;
+
+ if (!mlx4_is_mfunc(mdev))
+ return -EOPNOTSUPP;
+
+ if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
+ en_info(priv, "Del FDB only supports static addresses\n");
+ return -EINVAL;
+ }
+
+ if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+ err = dev_uc_del(dev, addr);
+ else if (is_multicast_ether_addr(addr))
+ err = dev_mc_del(dev, addr);
+ else
+ err = -EINVAL;
+
+ return err;
+}
+
+static int mlx4_en_fdb_dump(struct sk_buff *skb,
+ struct netlink_callback *cb,
+ struct net_device *dev, int idx)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_dev *mdev = priv->mdev->dev;
+
+ if (mlx4_is_mfunc(mdev))
+ idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
+
+ return idx;
+}
+
static const struct net_device_ops mlx4_netdev_ops = {
.ndo_open = mlx4_en_open,
.ndo_stop = mlx4_en_close,
.ndo_start_xmit = mlx4_en_xmit,
.ndo_select_queue = mlx4_en_select_queue,
.ndo_get_stats = mlx4_en_get_stats,
- .ndo_set_rx_mode = mlx4_en_set_multicast,
+ .ndo_set_rx_mode = mlx4_en_set_rx_mode,
.ndo_set_mac_address = mlx4_en_set_mac,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = mlx4_en_change_mtu,
@@ -1552,6 +2019,9 @@ static const struct net_device_ops mlx4_netdev_ops = {
#ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = mlx4_en_filter_rfs,
#endif
+ .ndo_fdb_add = mlx4_en_fdb_add,
+ .ndo_fdb_del = mlx4_en_fdb_del,
+ .ndo_fdb_dump = mlx4_en_fdb_dump,
};
int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
@@ -1608,7 +2078,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
priv->mac_index = -1;
priv->msg_enable = MLX4_EN_MSG_LEVEL;
spin_lock_init(&priv->stats_lock);
- INIT_WORK(&priv->mcast_task, mlx4_en_do_set_multicast);
+ INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode);
INIT_WORK(&priv->mac_task, mlx4_en_do_set_mac);
INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
@@ -1618,22 +2088,35 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
#endif
+ for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i)
+ INIT_HLIST_HEAD(&priv->mac_hash[i]);
+
/* Query for default mac and max mtu */
priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
- priv->mac = mdev->dev->caps.def_mac[priv->port];
- if (ILLEGAL_MAC(priv->mac)) {
- en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n",
- priv->port, priv->mac);
+
+ /* Set default MAC */
+ dev->addr_len = ETH_ALEN;
+ mlx4_en_u64_to_mac(dev->dev_addr, mdev->dev->caps.def_mac[priv->port]);
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ en_err(priv, "Port: %d, invalid mac burned: %pM, quiting\n",
+ priv->port, dev->dev_addr);
err = -EINVAL;
goto out;
}
+ memcpy(priv->prev_mac, dev->dev_addr, sizeof(priv->prev_mac));
+
priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
DS_SIZE * MLX4_EN_MAX_RX_FRAGS);
err = mlx4_en_alloc_resources(priv);
if (err)
goto out;
+#ifdef CONFIG_RFS_ACCEL
+ INIT_LIST_HEAD(&priv->filters);
+ spin_lock_init(&priv->filters_lock);
+#endif
+
/* Allocate page for receive rings */
err = mlx4_alloc_hwq_res(mdev->dev, &priv->res,
MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE);
@@ -1653,13 +2136,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
- /* Set defualt MAC */
- dev->addr_len = ETH_ALEN;
- for (i = 0; i < ETH_ALEN; i++) {
- dev->dev_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i));
- dev->perm_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i));
- }
-
/*
* Set driver features
*/
@@ -1679,6 +2155,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
MLX4_STEERING_MODE_DEVICE_MANAGED)
dev->hw_features |= NETIF_F_NTUPLE;
+ if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
+ dev->priv_flags |= IFF_UNICAST_FLT;
+
mdev->pndev[port] = dev;
netif_carrier_off(dev);
@@ -1692,6 +2171,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
+ mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+
/* Configure port */
mlx4_en_calc_rx_buf(dev);
err = mlx4_SET_PORT_general(mdev->dev, priv->port,
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index fed26d867f4e..ce38654bbdd0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -563,9 +563,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
unsigned int length;
int polled = 0;
int ip_summed;
- struct ethhdr *ethh;
- dma_addr_t dma;
- u64 s_mac;
int factor = priv->cqe_factor;
if (!priv->port_up)
@@ -603,21 +600,41 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
goto next;
}
- /* Get pointer to first fragment since we haven't skb yet and
- * cast it to ethhdr struct */
- dma = be64_to_cpu(rx_desc->data[0].addr);
- dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
- DMA_FROM_DEVICE);
- ethh = (struct ethhdr *)(page_address(frags[0].page) +
- frags[0].offset);
- s_mac = mlx4_en_mac_to_u64(ethh->h_source);
-
- /* If source MAC is equal to our own MAC and not performing
- * the selftest or flb disabled - drop the packet */
- if (s_mac == priv->mac &&
- !((dev->features & NETIF_F_LOOPBACK) ||
- priv->validate_loopback))
- goto next;
+ /* Check if we need to drop the packet if SRIOV is not enabled
+ * and not performing the selftest or flb disabled
+ */
+ if (priv->flags & MLX4_EN_FLAG_RX_FILTER_NEEDED) {
+ struct ethhdr *ethh;
+ dma_addr_t dma;
+ /* Get pointer to first fragment since we haven't
+ * skb yet and cast it to ethhdr struct
+ */
+ dma = be64_to_cpu(rx_desc->data[0].addr);
+ dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
+ DMA_FROM_DEVICE);
+ ethh = (struct ethhdr *)(page_address(frags[0].page) +
+ frags[0].offset);
+
+ if (is_multicast_ether_addr(ethh->h_dest)) {
+ struct mlx4_mac_entry *entry;
+ struct hlist_node *n;
+ struct hlist_head *bucket;
+ unsigned int mac_hash;
+
+ /* Drop the packet, since HW loopback-ed it */
+ mac_hash = ethh->h_source[MLX4_EN_MAC_HASH_IDX];
+ bucket = &priv->mac_hash[mac_hash];
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(entry, n, bucket, hlist) {
+ if (ether_addr_equal_64bits(entry->mac,
+ ethh->h_source)) {
+ rcu_read_unlock();
+ goto next;
+ }
+ }
+ rcu_read_unlock();
+ }
+ }
/*
* Packet is OK - process it.
@@ -835,11 +852,9 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn,
struct mlx4_qp_context *context;
int err = 0;
- context = kmalloc(sizeof *context , GFP_KERNEL);
- if (!context) {
- en_err(priv, "Failed to allocate qp context\n");
+ context = kmalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
return -ENOMEM;
- }
err = mlx4_qp_alloc(mdev->dev, qpn, qp);
if (err) {
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
index bf2e5d3f177c..3488c6d9e6b5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
@@ -87,6 +87,8 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
priv->loopback_ok = 0;
priv->validate_loopback = 1;
+ mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
+
/* xmit */
if (mlx4_en_test_loopback_xmit(priv)) {
en_err(priv, "Transmitting loopback packet failed\n");
@@ -107,6 +109,7 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
mlx4_en_test_loopback_exit:
priv->validate_loopback = 0;
+ mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
return !loopback_ok;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 6771b69f40d5..49308cc65ee7 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -294,6 +294,8 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
cnt++;
}
+ netdev_tx_reset_queue(ring->tx_queue);
+
if (cnt)
en_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt);
@@ -515,10 +517,6 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
wmb();
inl->byte_count = cpu_to_be32(1 << 31 | (skb->len - spc));
}
- tx_desc->ctrl.vlan_tag = cpu_to_be16(*vlan_tag);
- tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN *
- (!!vlan_tx_tag_present(skb));
- tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f;
}
u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb)
@@ -592,7 +590,21 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
netif_tx_stop_queue(ring->tx_queue);
priv->port_stats.queue_stopped++;
- return NETDEV_TX_BUSY;
+ /* If queue was emptied after the if, and before the
+ * stop_queue - need to wake the queue, or else it will remain
+ * stopped forever.
+ * Need a memory barrier to make sure ring->cons was not
+ * updated before queue was stopped.
+ */
+ wmb();
+
+ if (unlikely(((int)(ring->prod - ring->cons)) <=
+ ring->size - HEADROOM - MAX_DESC_TXBBS)) {
+ netif_tx_wake_queue(ring->tx_queue);
+ priv->port_stats.wake_queue++;
+ } else {
+ return NETDEV_TX_BUSY;
+ }
}
/* Track current inflight packets for performance analysis */
@@ -630,7 +642,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
ring->tx_csum++;
}
- if (mlx4_is_mfunc(mdev->dev) || priv->validate_loopback) {
+ if (priv->flags & MLX4_EN_FLAG_ENABLE_HW_LOOPBACK) {
/* Copy dst mac address to wqe. This allows loopback in eSwitch,
* so that VFs and PF can communicate with each other
*/
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 8b3d0512a46b..38b62c78d5da 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -127,7 +127,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
[0] = "RSS support",
[1] = "RSS Toeplitz Hash Function support",
[2] = "RSS XOR Hash Function support",
- [3] = "Device manage flow steering support"
+ [3] = "Device manage flow steering support",
+ [4] = "Automatic mac reassignment support"
};
int i;
@@ -478,6 +479,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET 0x94
#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98
#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0
+#define QUERY_DEV_CAP_FW_REASSIGN_MAC 0x9d
dev_cap->flags2 = 0;
mailbox = mlx4_alloc_cmd_mailbox(dev);
@@ -637,6 +639,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
MLX4_GET(dev_cap->reserved_lkey, outbox,
QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
+ MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC);
+ if (field & 1<<6)
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN;
MLX4_GET(dev_cap->max_icm_sz, outbox,
QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET);
if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS)
@@ -1287,14 +1292,14 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
/* Enable Ethernet flow steering
* with udp unicast and tcp unicast
*/
- MLX4_PUT(inbox, param->fs_hash_enable_bits,
+ MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
INIT_HCA_FS_ETH_BITS_OFFSET);
MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET);
/* Enable IPoIB flow steering
* with udp unicast and tcp unicast
*/
- MLX4_PUT(inbox, param->fs_hash_enable_bits,
+ MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
INIT_HCA_FS_IB_BITS_OFFSET);
MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
INIT_HCA_FS_IB_NUM_ADDRS_OFFSET);
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h
index dbf2f69cc59f..3af33ff669cc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.h
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.h
@@ -171,7 +171,6 @@ struct mlx4_init_hca_param {
u8 log_mpt_sz;
u8 log_uar_sz;
u8 uar_page_sz; /* log pg sz in 4k chunks */
- u8 fs_hash_enable_bits;
u8 steering_mode; /* for QUERY_HCA */
u64 dev_cap_enabled;
};
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index a6542d75374c..b9dde139dac5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -380,7 +380,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
}
}
- if ((dev_cap->flags &
+ if ((dev->caps.flags &
(MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) &&
mlx4_is_master(dev))
dev->caps.function_caps |= MLX4_FUNC_CAP_64B_EQE_CQE;
@@ -1415,22 +1415,6 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
if (mlx4_is_master(dev))
mlx4_parav_master_pf_caps(dev);
- priv->fs_hash_mode = MLX4_FS_L2_HASH;
-
- switch (priv->fs_hash_mode) {
- case MLX4_FS_L2_HASH:
- init_hca.fs_hash_enable_bits = 0;
- break;
-
- case MLX4_FS_L2_L3_L4_HASH:
- /* Enable flow steering with
- * udp unicast and tcp unicast
- */
- init_hca.fs_hash_enable_bits =
- MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN;
- break;
- }
-
profile = default_profile;
if (dev->caps.steering_mode ==
MLX4_STEERING_MODE_DEVICE_MANAGED)
@@ -1849,12 +1833,9 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
info->dev = dev;
info->port = port;
if (!mlx4_is_slave(dev)) {
- INIT_RADIX_TREE(&info->mac_tree, GFP_KERNEL);
mlx4_init_mac_table(dev, &info->mac_table);
mlx4_init_vlan_table(dev, &info->vlan_table);
- info->base_qpn =
- dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
- (port - 1) * (1 << log_num_mac);
+ info->base_qpn = mlx4_get_base_qpn(dev, port);
}
sprintf(info->dev_name, "mlx4_port%d", port);
@@ -2070,10 +2051,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
/* Allow large DMA segments, up to the firmware limit of 1 GB */
dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024);
- priv = kzalloc(sizeof *priv, GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
- dev_err(&pdev->dev, "Device struct alloc failed, "
- "aborting.\n");
err = -ENOMEM;
goto err_release_regions;
}
@@ -2162,7 +2141,8 @@ slave_start:
dev->num_slaves = MLX4_MAX_NUM_SLAVES;
else {
dev->num_slaves = 0;
- if (mlx4_multi_func_init(dev)) {
+ err = mlx4_multi_func_init(dev);
+ if (err) {
mlx4_err(dev, "Failed to init slave mfunc"
" interface, aborting.\n");
goto err_cmd;
@@ -2186,7 +2166,8 @@ slave_start:
/* In master functions, the communication channel must be initialized
* after obtaining its address from fw */
if (mlx4_is_master(dev)) {
- if (mlx4_multi_func_init(dev)) {
+ err = mlx4_multi_func_init(dev);
+ if (err) {
mlx4_err(dev, "Failed to init master mfunc"
"interface, aborting.\n");
goto err_close;
@@ -2203,6 +2184,7 @@ slave_start:
mlx4_enable_msi_x(dev);
if ((mlx4_is_mfunc(dev)) &&
!(dev->flags & MLX4_FLAG_MSI_X)) {
+ err = -ENOSYS;
mlx4_err(dev, "INTx is not supported in multi-function mode."
" aborting.\n");
goto err_free_eq;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index 1ee4db3c6400..52685524708d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -664,7 +664,7 @@ static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl,
dw |= ctrl->priority << 16;
hw->ctrl = cpu_to_be32(dw);
- hw->vf_vep_port = cpu_to_be32(ctrl->port);
+ hw->port = ctrl->port;
hw->qpn = cpu_to_be32(ctrl->qpn);
}
@@ -1157,7 +1157,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
.priority = MLX4_DOMAIN_NIC,
};
- rule.allow_loopback = ~block_mcast_loopback;
+ rule.allow_loopback = !block_mcast_loopback;
rule.port = port;
rule.qpn = qp->qpn;
INIT_LIST_HEAD(&rule.list);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 116c5c29d2d1..ed4a6959e828 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -60,11 +60,6 @@
#define MLX4_FS_MGM_LOG_ENTRY_SIZE 7
#define MLX4_FS_NUM_MCG (1 << 17)
-enum {
- MLX4_FS_L2_HASH = 0,
- MLX4_FS_L2_L3_L4_HASH,
-};
-
#define MLX4_NUM_UP 8
#define MLX4_NUM_TC 8
#define MLX4_RATELIMIT_UNITS 3 /* 100 Mbps */
@@ -658,11 +653,6 @@ struct mlx4_set_port_rqp_calc_context {
__be32 mcast;
};
-struct mlx4_mac_entry {
- u64 mac;
- u64 reg_id;
-};
-
struct mlx4_port_info {
struct mlx4_dev *dev;
int port;
@@ -672,7 +662,6 @@ struct mlx4_port_info {
char dev_mtu_name[16];
struct device_attribute port_mtu_attr;
struct mlx4_mac_table mac_table;
- struct radix_tree_root mac_tree;
struct mlx4_vlan_table vlan_table;
int base_qpn;
};
@@ -696,9 +685,12 @@ struct mlx4_steer {
struct mlx4_net_trans_rule_hw_ctrl {
__be32 ctrl;
- __be32 vf_vep_port;
+ u8 rsvd1;
+ u8 funcid;
+ u8 vep;
+ u8 port;
__be32 qpn;
- __be32 reserved;
+ __be32 rsvd2;
};
struct mlx4_net_trans_rule_hw_ib {
@@ -918,7 +910,6 @@ int __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align,
void __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt);
int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac);
void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac);
-int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac);
int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
int start_index, int npages, u64 *page_list);
int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 8d54412ada63..c313d7e943a9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -198,7 +198,6 @@ enum cq_type {
*/
#define ROUNDUP_LOG2(x) ilog2(roundup_pow_of_two(x))
#define XNOR(x, y) (!(x) == !(y))
-#define ILLEGAL_MAC(addr) (addr == 0xffffffffffffULL || addr == 0x0)
struct mlx4_en_tx_info {
@@ -427,10 +426,26 @@ struct mlx4_en_frag_info {
#endif
struct ethtool_flow_id {
+ struct list_head list;
struct ethtool_rx_flow_spec flow_spec;
u64 id;
};
+enum {
+ MLX4_EN_FLAG_PROMISC = (1 << 0),
+ MLX4_EN_FLAG_MC_PROMISC = (1 << 1),
+ /* whether we need to enable hardware loopback by putting dmac
+ * in Tx WQE
+ */
+ MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2),
+ /* whether we need to drop packets that hardware loopback-ed */
+ MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3),
+ MLX4_EN_FLAG_FORCE_PROMISC = (1 << 4)
+};
+
+#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE)
+#define MLX4_EN_MAC_HASH_IDX 5
+
struct mlx4_en_priv {
struct mlx4_en_dev *mdev;
struct mlx4_en_port_profile *prof;
@@ -441,6 +456,8 @@ struct mlx4_en_priv {
struct mlx4_en_port_state port_state;
spinlock_t stats_lock;
struct ethtool_flow_id ethtool_rules[MAX_NUM_OF_FS_RULES];
+ /* To allow rules removal while port is going down */
+ struct list_head ethtool_list;
unsigned long last_moder_packets[MAX_RX_RINGS];
unsigned long last_moder_tx_packets;
@@ -469,7 +486,7 @@ struct mlx4_en_priv {
int registered;
int allocated;
int stride;
- u64 mac;
+ unsigned char prev_mac[ETH_ALEN + 2];
int mac_index;
unsigned max_mtu;
int base_qpn;
@@ -478,8 +495,6 @@ struct mlx4_en_priv {
struct mlx4_en_rss_map rss_map;
__be32 ctrl_flags;
u32 flags;
-#define MLX4_EN_FLAG_PROMISC 0x1
-#define MLX4_EN_FLAG_MC_PROMISC 0x2
u8 num_tx_rings_p_up;
u32 tx_ring_num;
u32 rx_ring_num;
@@ -493,7 +508,7 @@ struct mlx4_en_priv {
struct mlx4_en_cq *tx_cq;
struct mlx4_en_cq rx_cq[MAX_RX_RINGS];
struct mlx4_qp drop_qp;
- struct work_struct mcast_task;
+ struct work_struct rx_mode_task;
struct work_struct mac_task;
struct work_struct watchdog_task;
struct work_struct linkstate_task;
@@ -510,6 +525,7 @@ struct mlx4_en_priv {
bool wol;
struct device *ddev;
int base_tx_qpn;
+ struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE];
#ifdef CONFIG_MLX4_EN_DCB
struct ieee_ets ets;
@@ -529,14 +545,24 @@ enum mlx4_en_wol {
MLX4_EN_WOL_ENABLED = (1ULL << 62),
};
+struct mlx4_mac_entry {
+ struct hlist_node hlist;
+ unsigned char mac[ETH_ALEN + 2];
+ u64 reg_id;
+ struct rcu_head rcu;
+};
+
#define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
+void mlx4_en_update_loopback_state(struct net_device *dev,
+ netdev_features_t features);
+
void mlx4_en_destroy_netdev(struct net_device *dev);
int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
struct mlx4_en_port_profile *prof);
int mlx4_en_start_port(struct net_device *dev);
-void mlx4_en_stop_port(struct net_device *dev);
+void mlx4_en_stop_port(struct net_device *dev, int detach);
void mlx4_en_free_resources(struct mlx4_en_priv *priv);
int mlx4_en_alloc_resources(struct mlx4_en_priv *priv);
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 4c51b05efa28..719ead15e491 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -74,87 +74,6 @@ void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
table->total = 0;
}
-static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port,
- u64 mac, int *qpn, u64 *reg_id)
-{
- __be64 be_mac;
- int err;
-
- mac &= MLX4_MAC_MASK;
- be_mac = cpu_to_be64(mac << 16);
-
- switch (dev->caps.steering_mode) {
- case MLX4_STEERING_MODE_B0: {
- struct mlx4_qp qp;
- u8 gid[16] = {0};
-
- qp.qpn = *qpn;
- memcpy(&gid[10], &be_mac, ETH_ALEN);
- gid[5] = port;
-
- err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH);
- break;
- }
- case MLX4_STEERING_MODE_DEVICE_MANAGED: {
- struct mlx4_spec_list spec_eth = { {NULL} };
- __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
-
- struct mlx4_net_trans_rule rule = {
- .queue_mode = MLX4_NET_TRANS_Q_FIFO,
- .exclusive = 0,
- .allow_loopback = 1,
- .promisc_mode = MLX4_FS_PROMISC_NONE,
- .priority = MLX4_DOMAIN_NIC,
- };
-
- rule.port = port;
- rule.qpn = *qpn;
- INIT_LIST_HEAD(&rule.list);
-
- spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH;
- memcpy(spec_eth.eth.dst_mac, &be_mac, ETH_ALEN);
- memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
- list_add_tail(&spec_eth.list, &rule.list);
-
- err = mlx4_flow_attach(dev, &rule, reg_id);
- break;
- }
- default:
- return -EINVAL;
- }
- if (err)
- mlx4_warn(dev, "Failed Attaching Unicast\n");
-
- return err;
-}
-
-static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port,
- u64 mac, int qpn, u64 reg_id)
-{
- switch (dev->caps.steering_mode) {
- case MLX4_STEERING_MODE_B0: {
- struct mlx4_qp qp;
- u8 gid[16] = {0};
- __be64 be_mac;
-
- qp.qpn = qpn;
- mac &= MLX4_MAC_MASK;
- be_mac = cpu_to_be64(mac << 16);
- memcpy(&gid[10], &be_mac, ETH_ALEN);
- gid[5] = port;
-
- mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH);
- break;
- }
- case MLX4_STEERING_MODE_DEVICE_MANAGED: {
- mlx4_flow_detach(dev, reg_id);
- break;
- }
- default:
- mlx4_err(dev, "Invalid steering mode.\n");
- }
-}
-
static int validate_index(struct mlx4_dev *dev,
struct mlx4_mac_table *table, int index)
{
@@ -181,92 +100,6 @@ static int find_index(struct mlx4_dev *dev,
return -EINVAL;
}
-int mlx4_get_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn)
-{
- struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
- struct mlx4_mac_entry *entry;
- int index = 0;
- int err = 0;
- u64 reg_id;
-
- mlx4_dbg(dev, "Registering MAC: 0x%llx for adding\n",
- (unsigned long long) mac);
- index = mlx4_register_mac(dev, port, mac);
- if (index < 0) {
- err = index;
- mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
- (unsigned long long) mac);
- return err;
- }
-
- if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
- *qpn = info->base_qpn + index;
- return 0;
- }
-
- err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
- mlx4_dbg(dev, "Reserved qp %d\n", *qpn);
- if (err) {
- mlx4_err(dev, "Failed to reserve qp for mac registration\n");
- goto qp_err;
- }
-
- err = mlx4_uc_steer_add(dev, port, mac, qpn, &reg_id);
- if (err)
- goto steer_err;
-
- entry = kmalloc(sizeof *entry, GFP_KERNEL);
- if (!entry) {
- err = -ENOMEM;
- goto alloc_err;
- }
- entry->mac = mac;
- entry->reg_id = reg_id;
- err = radix_tree_insert(&info->mac_tree, *qpn, entry);
- if (err)
- goto insert_err;
- return 0;
-
-insert_err:
- kfree(entry);
-
-alloc_err:
- mlx4_uc_steer_release(dev, port, mac, *qpn, reg_id);
-
-steer_err:
- mlx4_qp_release_range(dev, *qpn, 1);
-
-qp_err:
- mlx4_unregister_mac(dev, port, mac);
- return err;
-}
-EXPORT_SYMBOL_GPL(mlx4_get_eth_qp);
-
-void mlx4_put_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int qpn)
-{
- struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
- struct mlx4_mac_entry *entry;
-
- mlx4_dbg(dev, "Registering MAC: 0x%llx for deleting\n",
- (unsigned long long) mac);
- mlx4_unregister_mac(dev, port, mac);
-
- if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
- entry = radix_tree_lookup(&info->mac_tree, qpn);
- if (entry) {
- mlx4_dbg(dev, "Releasing qp: port %d, mac 0x%llx,"
- " qpn %d\n", port,
- (unsigned long long) mac, qpn);
- mlx4_uc_steer_release(dev, port, entry->mac,
- qpn, entry->reg_id);
- mlx4_qp_release_range(dev, qpn, 1);
- radix_tree_delete(&info->mac_tree, qpn);
- kfree(entry);
- }
- }
-}
-EXPORT_SYMBOL_GPL(mlx4_put_eth_qp);
-
static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
__be64 *entries)
{
@@ -359,6 +192,12 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
}
EXPORT_SYMBOL_GPL(mlx4_register_mac);
+int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port)
+{
+ return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
+ (port - 1) * (1 << dev->caps.log_num_macs);
+}
+EXPORT_SYMBOL_GPL(mlx4_get_base_qpn);
void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
{
@@ -397,29 +236,13 @@ void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
}
EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
-int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
+int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
{
struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
struct mlx4_mac_table *table = &info->mac_table;
- struct mlx4_mac_entry *entry;
int index = qpn - info->base_qpn;
int err = 0;
- if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
- entry = radix_tree_lookup(&info->mac_tree, qpn);
- if (!entry)
- return -EINVAL;
- mlx4_uc_steer_release(dev, port, entry->mac,
- qpn, entry->reg_id);
- mlx4_unregister_mac(dev, port, entry->mac);
- entry->mac = new_mac;
- entry->reg_id = 0;
- mlx4_register_mac(dev, port, new_mac);
- err = mlx4_uc_steer_add(dev, port, entry->mac,
- &qpn, &entry->reg_id);
- return err;
- }
-
/* CX1 doesn't support multi-functions */
mutex_lock(&table->mutex);
@@ -439,7 +262,7 @@ out:
mutex_unlock(&table->mutex);
return err;
}
-EXPORT_SYMBOL_GPL(mlx4_replace_mac);
+EXPORT_SYMBOL_GPL(__mlx4_replace_mac);
static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
__be32 *entries)
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 561ed2a22a17..5997adc943d0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -3018,7 +3018,7 @@ static int add_eth_header(struct mlx4_dev *dev, int slave,
__be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
- port = be32_to_cpu(ctrl->vf_vep_port) & 0xff;
+ port = ctrl->port;
eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1);
/* Clear a space in the inbox for eth header */
diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c
index b71eb39ab448..fbcb9e74d7fc 100644
--- a/drivers/net/ethernet/micrel/ks8842.c
+++ b/drivers/net/ethernet/micrel/ks8842.c
@@ -1080,7 +1080,6 @@ static int ks8842_set_mac(struct net_device *netdev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
memcpy(netdev->dev_addr, mac, netdev->addr_len);
ks8842_write_mac_addr(adapter, mac);
diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c
index 286816a4e783..33bcb63d56a2 100644
--- a/drivers/net/ethernet/micrel/ks8851.c
+++ b/drivers/net/ethernet/micrel/ks8851.c
@@ -69,7 +69,6 @@ union ks8851_tx_hdr {
* @mii: The MII state information for the mii calls.
* @rxctrl: RX settings for @rxctrl_work.
* @tx_work: Work queue for tx packets
- * @irq_work: Work queue for servicing interrupts
* @rxctrl_work: Work queue for updating RX mode and multicast lists
* @txq: Queue of packets for transmission.
* @spi_msg1: pre-setup SPI transfer with one message, @spi_xfer1.
@@ -121,7 +120,6 @@ struct ks8851_net {
struct ks8851_rxctrl rxctrl;
struct work_struct tx_work;
- struct work_struct irq_work;
struct work_struct rxctrl_work;
struct sk_buff_head txq;
@@ -444,23 +442,6 @@ static void ks8851_init_mac(struct ks8851_net *ks)
}
/**
- * ks8851_irq - device interrupt handler
- * @irq: Interrupt number passed from the IRQ handler.
- * @pw: The private word passed to register_irq(), our struct ks8851_net.
- *
- * Disable the interrupt from happening again until we've processed the
- * current status by scheduling ks8851_irq_work().
- */
-static irqreturn_t ks8851_irq(int irq, void *pw)
-{
- struct ks8851_net *ks = pw;
-
- disable_irq_nosync(irq);
- schedule_work(&ks->irq_work);
- return IRQ_HANDLED;
-}
-
-/**
* ks8851_rdfifo - read data from the receive fifo
* @ks: The device state.
* @buff: The buffer address
@@ -595,19 +576,20 @@ static void ks8851_rx_pkts(struct ks8851_net *ks)
}
/**
- * ks8851_irq_work - work queue handler for dealing with interrupt requests
- * @work: The work structure that was scheduled by schedule_work()
+ * ks8851_irq - IRQ handler for dealing with interrupt requests
+ * @irq: IRQ number
+ * @_ks: cookie
*
- * This is the handler invoked when the ks8851_irq() is called to find out
- * what happened, as we cannot allow ourselves to sleep whilst waiting for
- * anything other process has the chip's lock.
+ * This handler is invoked when the IRQ line asserts to find out what happened.
+ * As we cannot allow ourselves to sleep in HARDIRQ context, this handler runs
+ * in thread context.
*
* Read the interrupt status, work out what needs to be done and then clear
* any of the interrupts that are not needed.
*/
-static void ks8851_irq_work(struct work_struct *work)
+static irqreturn_t ks8851_irq(int irq, void *_ks)
{
- struct ks8851_net *ks = container_of(work, struct ks8851_net, irq_work);
+ struct ks8851_net *ks = _ks;
unsigned status;
unsigned handled = 0;
@@ -688,7 +670,7 @@ static void ks8851_irq_work(struct work_struct *work)
if (status & IRQ_TXI)
netif_wake_queue(ks->netdev);
- enable_irq(ks->netdev->irq);
+ return IRQ_HANDLED;
}
/**
@@ -896,7 +878,6 @@ static int ks8851_net_stop(struct net_device *dev)
mutex_unlock(&ks->lock);
/* stop any outstanding work */
- flush_work(&ks->irq_work);
flush_work(&ks->tx_work);
flush_work(&ks->rxctrl_work);
@@ -1052,7 +1033,6 @@ static int ks8851_set_mac_address(struct net_device *dev, void *addr)
if (!is_valid_ether_addr(sa->sa_data))
return -EADDRNOTAVAIL;
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
return ks8851_write_mac_addr(dev);
}
@@ -1438,7 +1418,6 @@ static int ks8851_probe(struct spi_device *spi)
spin_lock_init(&ks->statelock);
INIT_WORK(&ks->tx_work, ks8851_tx_work);
- INIT_WORK(&ks->irq_work, ks8851_irq_work);
INIT_WORK(&ks->rxctrl_work, ks8851_rxctrl_work);
/* initialise pre-made spi transfer messages */
@@ -1505,8 +1484,9 @@ static int ks8851_probe(struct spi_device *spi)
ks8851_read_selftest(ks);
ks8851_init_mac(ks);
- ret = request_irq(spi->irq, ks8851_irq, IRQF_TRIGGER_LOW,
- ndev->name, ks);
+ ret = request_threaded_irq(spi->irq, NULL, ks8851_irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ ndev->name, ks);
if (ret < 0) {
dev_err(&spi->dev, "failed to get irq\n");
goto err_irq;
diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c
index ef8f9f92e547..a343066f7b43 100644
--- a/drivers/net/ethernet/micrel/ks8851_mll.c
+++ b/drivers/net/ethernet/micrel/ks8851_mll.c
@@ -1237,7 +1237,6 @@ static int ks_set_mac_address(struct net_device *netdev, void *paddr)
struct sockaddr *addr = paddr;
u8 *da;
- netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
da = (u8 *)netdev->dev_addr;
diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index 8163fd0f453f..afaf0c07f37f 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_MICROCHIP
bool "Microchip devices"
default y
- depends on SPI && EXPERIMENTAL
+ depends on SPI
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -20,7 +20,7 @@ if NET_VENDOR_MICROCHIP
config ENC28J60
tristate "ENC28J60 support"
- depends on SPI && EXPERIMENTAL
+ depends on SPI
select CRC32
---help---
Support for the Microchip EN28J60 ethernet chip.
diff --git a/drivers/net/ethernet/microchip/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c
index a99456c3dd87..5d98a9f7bfc7 100644
--- a/drivers/net/ethernet/microchip/enc28j60.c
+++ b/drivers/net/ethernet/microchip/enc28j60.c
@@ -527,7 +527,6 @@ static int enc28j60_set_mac_address(struct net_device *dev, void *addr)
if (!is_valid_ether_addr(address->sa_data))
return -EADDRNOTAVAIL;
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
return enc28j60_set_hw_macaddr(dev);
}
diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
index f8408d6e961c..4f9937e026e5 100644
--- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -664,10 +664,9 @@ static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp)
/* copy header of running firmware from SRAM to host memory to
* validate firmware */
hdr = kmalloc(bytes, GFP_KERNEL);
- if (hdr == NULL) {
- dev_err(dev, "could not malloc firmware hdr\n");
+ if (hdr == NULL)
return -ENOMEM;
- }
+
memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes);
status = myri10ge_validate_firmware(mgp, hdr);
kfree(hdr);
diff --git a/drivers/net/ethernet/natsemi/Kconfig b/drivers/net/ethernet/natsemi/Kconfig
index f157334579fd..a100860d45e6 100644
--- a/drivers/net/ethernet/natsemi/Kconfig
+++ b/drivers/net/ethernet/natsemi/Kconfig
@@ -5,9 +5,6 @@
config NET_VENDOR_NATSEMI
bool "National Semi-conductor devices"
default y
- depends on AMIGA_PCMCIA || ARM || EISA || EXPERIMENTAL || H8300 || \
- ISA || M32R || MAC || MACH_JAZZ || MACH_TX49XX || MIPS || \
- PCI || PCMCIA || SUPERH || XTENSA_PLATFORM_XT2000 || ZORRO
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
diff --git a/drivers/net/ethernet/natsemi/ibmlana.c b/drivers/net/ethernet/natsemi/ibmlana.c
deleted file mode 100644
index 923e640d604c..000000000000
--- a/drivers/net/ethernet/natsemi/ibmlana.c
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
-net-3-driver for the IBM LAN Adapter/A
-
-This is an extension to the Linux operating system, and is covered by the
-same GNU General Public License that covers that work.
-
-Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
- alfred.arnold@lancom.de)
-
-This driver is based both on the SK_MCA driver, which is itself based on the
-SK_G16 and 3C523 driver.
-
-paper sources:
- 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
- Hans-Peter Messmer for the basic Microchannel stuff
-
- 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
- for help on Ethernet driver programming
-
- 'DP83934CVUL-20/25 MHz SONIC-T Ethernet Controller Datasheet' by National
- Semiconductor for info on the MAC chip
-
- 'LAN Technical Reference Ethernet Adapter Interface Version 1 Release 1.0
- Document Number SC30-3661-00' by IBM for info on the adapter itself
-
- Also see http://www.national.com/analog
-
-special acknowledgements to:
- - Bob Eager for helping me out with documentation from IBM
- - Jim Shorney for his endless patience with me while I was using
- him as a beta tester to trace down the address filter bug ;-)
-
- Missing things:
-
- -> set debug level via ioctl instead of compile-time switches
- -> I didn't follow the development of the 2.1.x kernels, so my
- assumptions about which things changed with which kernel version
- are probably nonsense
-
-History:
- Nov 6th, 1999
- startup from SK_MCA driver
- Dec 6th, 1999
- finally got docs about the card. A big thank you to Bob Eager!
- Dec 12th, 1999
- first packet received
- Dec 13th, 1999
- recv queue done, tcpdump works
- Dec 15th, 1999
- transmission part works
- Dec 28th, 1999
- added usage of the isa_functions for Linux 2.3 . Things should
- still work with 2.0.x....
- Jan 28th, 2000
- in Linux 2.2.13, the version.h file mysteriously didn't get
- included. Added a workaround for this. Furthermore, it now
- not only compiles as a modules ;-)
- Jan 30th, 2000
- newer kernels automatically probe more than one board, so the
- 'startslot' as a variable is also needed here
- Apr 12th, 2000
- the interrupt mask register is not set 'hard' instead of individually
- setting registers, since this seems to set bits that shouldn't be
- set
- May 21st, 2000
- reset interrupt status immediately after CAM load
- add a recovery delay after releasing the chip's reset line
- May 24th, 2000
- finally found the bug in the address filter setup - damned signed
- chars!
- June 1st, 2000
- corrected version codes, added support for the latest 2.3 changes
- Oct 28th, 2002
- cleaned up for the 2.5 tree <alan@lxorguk.ukuu.org.uk>
-
- *************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/mca.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/processor.h>
-#include <asm/io.h>
-
-#define _IBM_LANA_DRIVER_
-#include "ibmlana.h"
-
-#undef DEBUG
-
-#define DRV_NAME "ibmlana"
-
-/* ------------------------------------------------------------------------
- * global static data - not more since we can handle multiple boards and
- * have to pack all state info into the device struct!
- * ------------------------------------------------------------------------ */
-
-static char *MediaNames[Media_Count] = {
- "10BaseT", "10Base5", "Unknown", "10Base2"
-};
-
-/* ------------------------------------------------------------------------
- * private subfunctions
- * ------------------------------------------------------------------------ */
-
-#ifdef DEBUG
- /* dump all registers */
-
-static void dumpregs(struct net_device *dev)
-{
- int z;
-
- for (z = 0; z < 160; z += 2) {
- if (!(z & 15))
- printk("REGS: %04x:", z);
- printk(" %04x", inw(dev->base_addr + z));
- if ((z & 15) == 14)
- printk("\n");
- }
-}
-
-/* dump parts of shared memory - only needed during debugging */
-
-static void dumpmem(struct net_device *dev, u32 start, u32 len)
-{
- ibmlana_priv *priv = netdev_priv(dev);
- int z;
-
- printk("Address %04x:\n", start);
- for (z = 0; z < len; z++) {
- if ((z & 15) == 0)
- printk("%04x:", z);
- printk(" %02x", readb(priv->base + start + z));
- if ((z & 15) == 15)
- printk("\n");
- }
- if ((z & 15) != 0)
- printk("\n");
-}
-
-/* print exact time - ditto */
-
-static void PrTime(void)
-{
- struct timeval tv;
-
- do_gettimeofday(&tv);
- printk("%9d:%06d: ", (int) tv.tv_sec, (int) tv.tv_usec);
-}
-#endif /* DEBUG */
-
-/* deduce resources out of POS registers */
-
-static void getaddrs(struct mca_device *mdev, int *base, int *memlen,
- int *iobase, int *irq, ibmlana_medium *medium)
-{
- u_char pos0, pos1;
-
- pos0 = mca_device_read_stored_pos(mdev, 2);
- pos1 = mca_device_read_stored_pos(mdev, 3);
-
- *base = 0xc0000 + ((pos1 & 0xf0) << 9);
- *memlen = (pos1 & 0x01) ? 0x8000 : 0x4000;
- *iobase = (pos0 & 0xe0) << 7;
- switch (pos0 & 0x06) {
- case 0:
- *irq = 5;
- break;
- case 2:
- *irq = 15;
- break;
- case 4:
- *irq = 10;
- break;
- case 6:
- *irq = 11;
- break;
- }
- *medium = (pos0 & 0x18) >> 3;
-}
-
-/* wait on register value with mask and timeout */
-
-static int wait_timeout(struct net_device *dev, int regoffs, u16 mask,
- u16 value, int timeout)
-{
- unsigned long fin = jiffies + timeout;
-
- while (time_before(jiffies,fin))
- if ((inw(dev->base_addr + regoffs) & mask) == value)
- return 1;
-
- return 0;
-}
-
-
-/* reset the whole board */
-
-static void ResetBoard(struct net_device *dev)
-{
- unsigned char bcmval;
-
- /* read original board control value */
-
- bcmval = inb(dev->base_addr + BCMREG);
-
- /* set reset bit for a while */
-
- bcmval |= BCMREG_RESET;
- outb(bcmval, dev->base_addr + BCMREG);
- udelay(10);
- bcmval &= ~BCMREG_RESET;
- outb(bcmval, dev->base_addr + BCMREG);
-
- /* switch over to RAM again */
-
- bcmval |= BCMREG_RAMEN | BCMREG_RAMWIN;
- outb(bcmval, dev->base_addr + BCMREG);
-}
-
-/* calculate RAM layout & set up descriptors in RAM */
-
-static void InitDscrs(struct net_device *dev)
-{
- ibmlana_priv *priv = netdev_priv(dev);
- u32 addr, baddr, raddr;
- int z;
- tda_t tda;
- rda_t rda;
- rra_t rra;
-
- /* initialize RAM */
-
- memset_io(priv->base, 0xaa,
- dev->mem_start - dev->mem_start); /* XXX: typo? */
-
- /* setup n TX descriptors - independent of RAM size */
-
- priv->tdastart = addr = 0;
- priv->txbufstart = baddr = sizeof(tda_t) * TXBUFCNT;
- for (z = 0; z < TXBUFCNT; z++) {
- tda.status = 0;
- tda.config = 0;
- tda.length = 0;
- tda.fragcount = 1;
- tda.startlo = baddr;
- tda.starthi = 0;
- tda.fraglength = 0;
- if (z == TXBUFCNT - 1)
- tda.link = priv->tdastart;
- else
- tda.link = addr + sizeof(tda_t);
- tda.link |= 1;
- memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
- addr += sizeof(tda_t);
- baddr += PKTSIZE;
- }
-
- /* calculate how many receive buffers fit into remaining memory */
-
- priv->rxbufcnt = (dev->mem_end - dev->mem_start - baddr) / (sizeof(rra_t) + sizeof(rda_t) + PKTSIZE);
-
- /* calculate receive addresses */
-
- priv->rrastart = raddr = priv->txbufstart + (TXBUFCNT * PKTSIZE);
- priv->rdastart = addr = priv->rrastart + (priv->rxbufcnt * sizeof(rra_t));
- priv->rxbufstart = baddr = priv->rdastart + (priv->rxbufcnt * sizeof(rda_t));
-
- for (z = 0; z < priv->rxbufcnt; z++) {
- rra.startlo = baddr;
- rra.starthi = 0;
- rra.cntlo = PKTSIZE >> 1;
- rra.cnthi = 0;
- memcpy_toio(priv->base + raddr, &rra, sizeof(rra_t));
-
- rda.status = 0;
- rda.length = 0;
- rda.startlo = 0;
- rda.starthi = 0;
- rda.seqno = 0;
- if (z < priv->rxbufcnt - 1)
- rda.link = addr + sizeof(rda_t);
- else
- rda.link = 1;
- rda.inuse = 1;
- memcpy_toio(priv->base + addr, &rda, sizeof(rda_t));
-
- baddr += PKTSIZE;
- raddr += sizeof(rra_t);
- addr += sizeof(rda_t);
- }
-
- /* initialize current pointers */
-
- priv->nextrxdescr = 0;
- priv->lastrxdescr = priv->rxbufcnt - 1;
- priv->nexttxdescr = 0;
- priv->currtxdescr = 0;
- priv->txusedcnt = 0;
- memset(priv->txused, 0, sizeof(priv->txused));
-}
-
-/* set up Rx + Tx descriptors in SONIC */
-
-static int InitSONIC(struct net_device *dev)
-{
- ibmlana_priv *priv = netdev_priv(dev);
-
- /* set up start & end of resource area */
-
- outw(0, SONIC_URRA);
- outw(priv->rrastart, dev->base_addr + SONIC_RSA);
- outw(priv->rrastart + (priv->rxbufcnt * sizeof(rra_t)), dev->base_addr + SONIC_REA);
- outw(priv->rrastart, dev->base_addr + SONIC_RRP);
- outw(priv->rrastart, dev->base_addr + SONIC_RWP);
-
- /* set EOBC so that only one packet goes into one buffer */
-
- outw((PKTSIZE - 4) >> 1, dev->base_addr + SONIC_EOBC);
-
- /* let SONIC read the first RRA descriptor */
-
- outw(CMDREG_RRRA, dev->base_addr + SONIC_CMDREG);
- if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_RRRA, 0, 2)) {
- printk(KERN_ERR "%s: SONIC did not respond on RRRA command - giving up.", dev->name);
- return 0;
- }
-
- /* point SONIC to the first RDA */
-
- outw(0, dev->base_addr + SONIC_URDA);
- outw(priv->rdastart, dev->base_addr + SONIC_CRDA);
-
- /* set upper half of TDA address */
-
- outw(0, dev->base_addr + SONIC_UTDA);
-
- return 1;
-}
-
-/* stop SONIC so we can reinitialize it */
-
-static void StopSONIC(struct net_device *dev)
-{
- /* disable interrupts */
-
- outb(inb(dev->base_addr + BCMREG) & (~BCMREG_IEN), dev->base_addr + BCMREG);
- outb(0, dev->base_addr + SONIC_IMREG);
-
- /* reset the SONIC */
-
- outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
- udelay(10);
- outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
-}
-
-/* initialize card and SONIC for proper operation */
-
-static void putcam(camentry_t * cams, int *camcnt, char *addr)
-{
- camentry_t *pcam = cams + (*camcnt);
- u8 *uaddr = (u8 *) addr;
-
- pcam->index = *camcnt;
- pcam->addr0 = (((u16) uaddr[1]) << 8) | uaddr[0];
- pcam->addr1 = (((u16) uaddr[3]) << 8) | uaddr[2];
- pcam->addr2 = (((u16) uaddr[5]) << 8) | uaddr[4];
- (*camcnt)++;
-}
-
-static void InitBoard(struct net_device *dev)
-{
- ibmlana_priv *priv = netdev_priv(dev);
- int camcnt;
- camentry_t cams[16];
- u32 cammask;
- struct netdev_hw_addr *ha;
- u16 rcrval;
-
- /* reset the SONIC */
-
- outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
- udelay(10);
-
- /* clear all spurious interrupts */
-
- outw(inw(dev->base_addr + SONIC_ISREG), dev->base_addr + SONIC_ISREG);
-
- /* set up the SONIC's bus interface - constant for this adapter -
- must be done while the SONIC is in reset */
-
- outw(DCREG_USR1 | DCREG_USR0 | DCREG_WC1 | DCREG_DW32, dev->base_addr + SONIC_DCREG);
- outw(0, dev->base_addr + SONIC_DCREG2);
-
- /* remove reset form the SONIC */
-
- outw(0, dev->base_addr + SONIC_CMDREG);
- udelay(10);
-
- /* data sheet requires URRA to be programmed before setting up the CAM contents */
-
- outw(0, dev->base_addr + SONIC_URRA);
-
- /* program the CAM entry 0 to the device address */
-
- camcnt = 0;
- putcam(cams, &camcnt, dev->dev_addr);
-
- /* start putting the multicast addresses into the CAM list. Stop if
- it is full. */
-
- netdev_for_each_mc_addr(ha, dev) {
- putcam(cams, &camcnt, ha->addr);
- if (camcnt == 16)
- break;
- }
-
- /* calculate CAM mask */
-
- cammask = (1 << camcnt) - 1;
-
- /* feed CDA into SONIC, initialize RCR value (always get broadcasts) */
-
- memcpy_toio(priv->base, cams, sizeof(camentry_t) * camcnt);
- memcpy_toio(priv->base + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask));
-
-#ifdef DEBUG
- printk("CAM setup:\n");
- dumpmem(dev, 0, sizeof(camentry_t) * camcnt + sizeof(cammask));
-#endif
-
- outw(0, dev->base_addr + SONIC_CAMPTR);
- outw(camcnt, dev->base_addr + SONIC_CAMCNT);
- outw(CMDREG_LCAM, dev->base_addr + SONIC_CMDREG);
- if (!wait_timeout(dev, SONIC_CMDREG, CMDREG_LCAM, 0, 2)) {
- printk(KERN_ERR "%s:SONIC did not respond on LCAM command - giving up.", dev->name);
- return;
- } else {
- /* clear interrupt condition */
-
- outw(ISREG_LCD, dev->base_addr + SONIC_ISREG);
-
-#ifdef DEBUG
- printk("Loading CAM done, address pointers %04x:%04x\n",
- inw(dev->base_addr + SONIC_URRA),
- inw(dev->base_addr + SONIC_CAMPTR));
- {
- int z;
-
- printk("\n-->CAM: PTR %04x CNT %04x\n",
- inw(dev->base_addr + SONIC_CAMPTR),
- inw(dev->base_addr + SONIC_CAMCNT));
- outw(CMDREG_RST, dev->base_addr + SONIC_CMDREG);
- for (z = 0; z < camcnt; z++) {
- outw(z, dev->base_addr + SONIC_CAMEPTR);
- printk("Entry %d: %04x %04x %04x\n", z,
- inw(dev->base_addr + SONIC_CAMADDR0),
- inw(dev->base_addr + SONIC_CAMADDR1),
- inw(dev->base_addr + SONIC_CAMADDR2));
- }
- outw(0, dev->base_addr + SONIC_CMDREG);
- }
-#endif
- }
-
- rcrval = RCREG_BRD | RCREG_LB_NONE;
-
- /* if still multicast addresses left or ALLMULTI is set, set the multicast
- enable bit */
-
- if ((dev->flags & IFF_ALLMULTI) || netdev_mc_count(dev) > camcnt)
- rcrval |= RCREG_AMC;
-
- /* promiscuous mode ? */
-
- if (dev->flags & IFF_PROMISC)
- rcrval |= RCREG_PRO;
-
- /* program receive mode */
-
- outw(rcrval, dev->base_addr + SONIC_RCREG);
-#ifdef DEBUG
- printk("\nRCRVAL: %04x\n", rcrval);
-#endif
-
- /* set up descriptors in shared memory + feed them into SONIC registers */
-
- InitDscrs(dev);
- if (!InitSONIC(dev))
- return;
-
- /* reset all pending interrupts */
-
- outw(0xffff, dev->base_addr + SONIC_ISREG);
-
- /* enable transmitter + receiver interrupts */
-
- outw(CMDREG_RXEN, dev->base_addr + SONIC_CMDREG);
- outw(IMREG_PRXEN | IMREG_RBEEN | IMREG_PTXEN | IMREG_TXEREN, dev->base_addr + SONIC_IMREG);
-
- /* turn on card interrupts */
-
- outb(inb(dev->base_addr + BCMREG) | BCMREG_IEN, dev->base_addr + BCMREG);
-
-#ifdef DEBUG
- printk("Register dump after initialization:\n");
- dumpregs(dev);
-#endif
-}
-
-/* start transmission of a descriptor */
-
-static void StartTx(struct net_device *dev, int descr)
-{
- ibmlana_priv *priv = netdev_priv(dev);
- int addr;
-
- addr = priv->tdastart + (descr * sizeof(tda_t));
-
- /* put descriptor address into SONIC */
-
- outw(addr, dev->base_addr + SONIC_CTDA);
-
- /* trigger transmitter */
-
- priv->currtxdescr = descr;
- outw(CMDREG_TXP, dev->base_addr + SONIC_CMDREG);
-}
-
-/* ------------------------------------------------------------------------
- * interrupt handler(s)
- * ------------------------------------------------------------------------ */
-
-/* receive buffer area exhausted */
-
-static void irqrbe_handler(struct net_device *dev)
-{
- ibmlana_priv *priv = netdev_priv(dev);
-
- /* point the SONIC back to the RRA start */
-
- outw(priv->rrastart, dev->base_addr + SONIC_RRP);
- outw(priv->rrastart, dev->base_addr + SONIC_RWP);
-}
-
-/* receive interrupt */
-
-static void irqrx_handler(struct net_device *dev)
-{
- ibmlana_priv *priv = netdev_priv(dev);
- rda_t rda;
- u32 rdaaddr, lrdaaddr;
-
- /* loop until ... */
-
- while (1) {
- /* read descriptor that was next to be filled by SONIC */
-
- rdaaddr = priv->rdastart + (priv->nextrxdescr * sizeof(rda_t));
- lrdaaddr = priv->rdastart + (priv->lastrxdescr * sizeof(rda_t));
- memcpy_fromio(&rda, priv->base + rdaaddr, sizeof(rda_t));
-
- /* iron out upper word halves of fields we use - SONIC will duplicate
- bits 0..15 to 16..31 */
-
- rda.status &= 0xffff;
- rda.length &= 0xffff;
- rda.startlo &= 0xffff;
-
- /* stop if the SONIC still owns it, i.e. there is no data for us */
-
- if (rda.inuse)
- break;
-
- /* good packet? */
-
- else if (rda.status & RCREG_PRX) {
- struct sk_buff *skb;
-
- /* fetch buffer */
-
- skb = netdev_alloc_skb(dev, rda.length + 2);
- if (skb == NULL)
- dev->stats.rx_dropped++;
- else {
- /* copy out data */
-
- memcpy_fromio(skb_put(skb, rda.length),
- priv->base +
- rda.startlo, rda.length);
-
- /* set up skb fields */
-
- skb->protocol = eth_type_trans(skb, dev);
- skb_checksum_none_assert(skb);
-
- /* bookkeeping */
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += rda.length;
-
- /* pass to the upper layers */
- netif_rx(skb);
- }
- }
-
- /* otherwise check error status bits and increase statistics */
-
- else {
- dev->stats.rx_errors++;
- if (rda.status & RCREG_FAER)
- dev->stats.rx_frame_errors++;
- if (rda.status & RCREG_CRCR)
- dev->stats.rx_crc_errors++;
- }
-
- /* descriptor processed, will become new last descriptor in queue */
-
- rda.link = 1;
- rda.inuse = 1;
- memcpy_toio(priv->base + rdaaddr, &rda,
- sizeof(rda_t));
-
- /* set up link and EOL = 0 in currently last descriptor. Only write
- the link field since the SONIC may currently already access the
- other fields. */
-
- memcpy_toio(priv->base + lrdaaddr + 20, &rdaaddr, 4);
-
- /* advance indices */
-
- priv->lastrxdescr = priv->nextrxdescr;
- if ((++priv->nextrxdescr) >= priv->rxbufcnt)
- priv->nextrxdescr = 0;
- }
-}
-
-/* transmit interrupt */
-
-static void irqtx_handler(struct net_device *dev)
-{
- ibmlana_priv *priv = netdev_priv(dev);
- tda_t tda;
-
- /* fetch descriptor (we forgot the size ;-) */
- memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
-
- /* update statistics */
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += tda.length;
-
- /* update our pointers */
- priv->txused[priv->currtxdescr] = 0;
- priv->txusedcnt--;
-
- /* if there are more descriptors present in RAM, start them */
- if (priv->txusedcnt > 0)
- StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT);
-
- /* tell the upper layer we can go on transmitting */
- netif_wake_queue(dev);
-}
-
-static void irqtxerr_handler(struct net_device *dev)
-{
- ibmlana_priv *priv = netdev_priv(dev);
- tda_t tda;
-
- /* fetch descriptor to check status */
- memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
-
- /* update statistics */
- dev->stats.tx_errors++;
- if (tda.status & (TCREG_NCRS | TCREG_CRSL))
- dev->stats.tx_carrier_errors++;
- if (tda.status & TCREG_EXC)
- dev->stats.tx_aborted_errors++;
- if (tda.status & TCREG_OWC)
- dev->stats.tx_window_errors++;
- if (tda.status & TCREG_FU)
- dev->stats.tx_fifo_errors++;
-
- /* update our pointers */
- priv->txused[priv->currtxdescr] = 0;
- priv->txusedcnt--;
-
- /* if there are more descriptors present in RAM, start them */
- if (priv->txusedcnt > 0)
- StartTx(dev, (priv->currtxdescr + 1) % TXBUFCNT);
-
- /* tell the upper layer we can go on transmitting */
- netif_wake_queue(dev);
-}
-
-/* general interrupt entry */
-
-static irqreturn_t irq_handler(int dummy, void *device)
-{
- struct net_device *dev = device;
- u16 ival;
-
- /* in case we're not meant... */
- if (!(inb(dev->base_addr + BCMREG) & BCMREG_IPEND))
- return IRQ_NONE;
-
- /* loop through the interrupt bits until everything is clear */
- while (1) {
- ival = inw(dev->base_addr + SONIC_ISREG);
-
- if (ival & ISREG_RBE) {
- irqrbe_handler(dev);
- outw(ISREG_RBE, dev->base_addr + SONIC_ISREG);
- }
- if (ival & ISREG_PKTRX) {
- irqrx_handler(dev);
- outw(ISREG_PKTRX, dev->base_addr + SONIC_ISREG);
- }
- if (ival & ISREG_TXDN) {
- irqtx_handler(dev);
- outw(ISREG_TXDN, dev->base_addr + SONIC_ISREG);
- }
- if (ival & ISREG_TXER) {
- irqtxerr_handler(dev);
- outw(ISREG_TXER, dev->base_addr + SONIC_ISREG);
- }
- break;
- }
- return IRQ_HANDLED;
-}
-
-/* ------------------------------------------------------------------------
- * driver methods
- * ------------------------------------------------------------------------ */
-
-/* MCA info */
-
-#if 0 /* info available elsewhere, but this is kept for reference */
-static int ibmlana_getinfo(char *buf, int slot, void *d)
-{
- int len = 0, i;
- struct net_device *dev = (struct net_device *) d;
- ibmlana_priv *priv;
-
- /* can't say anything about an uninitialized device... */
-
- if (dev == NULL)
- return len;
- priv = netdev_priv(dev);
-
- /* print info */
-
- len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
- len += sprintf(buf + len, "I/O: %#lx\n", dev->base_addr);
- len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start, dev->mem_end - 1);
- len += sprintf(buf + len, "Transceiver: %s\n", MediaNames[priv->medium]);
- len += sprintf(buf + len, "Device: %s\n", dev->name);
- len += sprintf(buf + len, "MAC address:");
- for (i = 0; i < 6; i++)
- len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
- buf[len++] = '\n';
- buf[len] = 0;
-
- return len;
-}
-#endif
-
-/* open driver. Means also initialization and start of LANCE */
-
-static int ibmlana_open(struct net_device *dev)
-{
- int result;
- ibmlana_priv *priv = netdev_priv(dev);
-
- /* register resources - only necessary for IRQ */
-
- 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;
- }
- dev->irq = priv->realirq;
-
- /* set up the card and SONIC */
- InitBoard(dev);
-
- /* initialize operational flags */
- netif_start_queue(dev);
- return 0;
-}
-
-/* close driver. Shut down board and free allocated resources */
-
-static int ibmlana_close(struct net_device *dev)
-{
- /* turn off board */
-
- /* release resources */
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- dev->irq = 0;
- return 0;
-}
-
-/* transmit a block. */
-
-static netdev_tx_t ibmlana_tx(struct sk_buff *skb, struct net_device *dev)
-{
- ibmlana_priv *priv = netdev_priv(dev);
- int tmplen, addr;
- unsigned long flags;
- tda_t tda;
- int baddr;
-
- /* find out if there are free slots for a frame to transmit. If not,
- the upper layer is in deep desperation and we simply ignore the frame. */
-
- if (priv->txusedcnt >= TXBUFCNT) {
- dev->stats.tx_dropped++;
- goto tx_done;
- }
-
- /* copy the frame data into the next free transmit buffer - fillup missing */
- tmplen = skb->len;
- if (tmplen < 60)
- tmplen = 60;
- baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE);
- memcpy_toio(priv->base + baddr, skb->data, skb->len);
-
- /* copy filler into RAM - in case we're filling up...
- we're filling a bit more than necessary, but that doesn't harm
- since the buffer is far larger...
- Sorry Linus for the filler string but I couldn't resist ;-) */
-
- if (tmplen > skb->len) {
- char *fill = "NetBSD is a nice OS too! ";
- unsigned int destoffs = skb->len, l = strlen(fill);
-
- while (destoffs < tmplen) {
- memcpy_toio(priv->base + baddr + destoffs, fill, l);
- destoffs += l;
- }
- }
-
- /* set up the new frame descriptor */
- addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t));
- memcpy_fromio(&tda, priv->base + addr, sizeof(tda_t));
- tda.length = tda.fraglength = tmplen;
- memcpy_toio(priv->base + addr, &tda, sizeof(tda_t));
-
- /* if there were no active descriptors, trigger the SONIC */
- spin_lock_irqsave(&priv->lock, flags);
-
- priv->txusedcnt++;
- priv->txused[priv->nexttxdescr] = 1;
-
- /* are all transmission slots used up ? */
- if (priv->txusedcnt >= TXBUFCNT)
- netif_stop_queue(dev);
-
- if (priv->txusedcnt == 1)
- StartTx(dev, priv->nexttxdescr);
- priv->nexttxdescr = (priv->nexttxdescr + 1) % TXBUFCNT;
-
- spin_unlock_irqrestore(&priv->lock, flags);
-tx_done:
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-/* switch receiver mode. */
-
-static void ibmlana_set_multicast_list(struct net_device *dev)
-{
- /* first stop the SONIC... */
- StopSONIC(dev);
- /* ...then reinit it with the new flags */
- InitBoard(dev);
-}
-
-/* ------------------------------------------------------------------------
- * hardware check
- * ------------------------------------------------------------------------ */
-
-static int ibmlana_irq;
-static int ibmlana_io;
-static int startslot; /* counts through slots when probing multiple devices */
-
-static short ibmlana_adapter_ids[] __initdata = {
- IBM_LANA_ID,
- 0x0000
-};
-
-static char *ibmlana_adapter_names[] = {
- "IBM LAN Adapter/A",
- NULL
-};
-
-
-static const struct net_device_ops ibmlana_netdev_ops = {
- .ndo_open = ibmlana_open,
- .ndo_stop = ibmlana_close,
- .ndo_start_xmit = ibmlana_tx,
- .ndo_set_rx_mode = ibmlana_set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int ibmlana_init_one(struct device *kdev)
-{
- struct mca_device *mdev = to_mca_device(kdev);
- struct net_device *dev;
- int slot = mdev->slot, z, rc;
- int base = 0, irq = 0, iobase = 0, memlen = 0;
- ibmlana_priv *priv;
- ibmlana_medium medium;
-
- dev = alloc_etherdev(sizeof(ibmlana_priv));
- if (!dev)
- return -ENOMEM;
-
- dev->irq = ibmlana_irq;
- dev->base_addr = ibmlana_io;
-
- base = dev->mem_start;
- irq = dev->irq;
-
- /* deduce card addresses */
- getaddrs(mdev, &base, &memlen, &iobase, &irq, &medium);
-
- /* were we looking for something different ? */
- if (dev->irq && dev->irq != irq) {
- rc = -ENODEV;
- goto err_out;
- }
- if (dev->mem_start && dev->mem_start != base) {
- rc = -ENODEV;
- goto err_out;
- }
-
- /* announce success */
- printk(KERN_INFO "%s: IBM LAN Adapter/A found in slot %d\n", dev->name, slot + 1);
-
- /* try to obtain I/O range */
- if (!request_region(iobase, IBM_LANA_IORANGE, DRV_NAME)) {
- printk(KERN_ERR "%s: cannot allocate I/O range at %#x!\n", DRV_NAME, iobase);
- startslot = slot + 1;
- rc = -EBUSY;
- goto err_out;
- }
-
- priv = netdev_priv(dev);
- priv->slot = slot;
- priv->realirq = mca_device_transform_irq(mdev, irq);
- priv->medium = medium;
- spin_lock_init(&priv->lock);
-
- /* set base + irq for this device (irq not allocated so far) */
-
- dev->irq = 0;
- dev->mem_start = base;
- dev->mem_end = base + memlen;
- dev->base_addr = iobase;
-
- priv->base = ioremap(base, memlen);
- if (!priv->base) {
- printk(KERN_ERR "%s: cannot remap memory!\n", DRV_NAME);
- startslot = slot + 1;
- rc = -EBUSY;
- goto err_out_reg;
- }
-
- mca_device_set_name(mdev, ibmlana_adapter_names[mdev->index]);
- mca_device_set_claim(mdev, 1);
-
- /* set methods */
- dev->netdev_ops = &ibmlana_netdev_ops;
- dev->flags |= IFF_MULTICAST;
-
- /* copy out MAC address */
-
- for (z = 0; z < ETH_ALEN; z++)
- dev->dev_addr[z] = inb(dev->base_addr + MACADDRPROM + z);
-
- /* print config */
-
- printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, "
- "MAC address %pM.\n",
- dev->name, priv->realirq, dev->base_addr,
- dev->mem_start, dev->mem_end - 1,
- dev->dev_addr);
- printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]);
-
- /* reset board */
-
- ResetBoard(dev);
-
- /* next probe will start at next slot */
-
- startslot = slot + 1;
-
- rc = register_netdev(dev);
- if (rc)
- goto err_out_claimed;
-
- dev_set_drvdata(kdev, dev);
- return 0;
-
-err_out_claimed:
- mca_device_set_claim(mdev, 0);
- iounmap(priv->base);
-err_out_reg:
- release_region(iobase, IBM_LANA_IORANGE);
-err_out:
- free_netdev(dev);
- return rc;
-}
-
-static int ibmlana_remove_one(struct device *kdev)
-{
- struct mca_device *mdev = to_mca_device(kdev);
- struct net_device *dev = dev_get_drvdata(kdev);
- ibmlana_priv *priv = netdev_priv(dev);
-
- unregister_netdev(dev);
- /*DeinitBoard(dev); */
- release_region(dev->base_addr, IBM_LANA_IORANGE);
- mca_device_set_claim(mdev, 0);
- iounmap(priv->base);
- free_netdev(dev);
- return 0;
-}
-
-/* ------------------------------------------------------------------------
- * modularization support
- * ------------------------------------------------------------------------ */
-
-module_param_named(irq, ibmlana_irq, int, 0);
-module_param_named(io, ibmlana_io, int, 0);
-MODULE_PARM_DESC(irq, "IBM LAN/A IRQ number");
-MODULE_PARM_DESC(io, "IBM LAN/A I/O base address");
-MODULE_LICENSE("GPL");
-
-static struct mca_driver ibmlana_driver = {
- .id_table = ibmlana_adapter_ids,
- .driver = {
- .name = "ibmlana",
- .bus = &mca_bus_type,
- .probe = ibmlana_init_one,
- .remove = ibmlana_remove_one,
- },
-};
-
-static int __init ibmlana_init_module(void)
-{
- return mca_register_driver(&ibmlana_driver);
-}
-
-static void __exit ibmlana_cleanup_module(void)
-{
- mca_unregister_driver(&ibmlana_driver);
-}
-
-module_init(ibmlana_init_module);
-module_exit(ibmlana_cleanup_module);
diff --git a/drivers/net/ethernet/natsemi/ibmlana.h b/drivers/net/ethernet/natsemi/ibmlana.h
deleted file mode 100644
index accd5efc9c8a..000000000000
--- a/drivers/net/ethernet/natsemi/ibmlana.h
+++ /dev/null
@@ -1,278 +0,0 @@
-#ifndef _IBM_LANA_INCLUDE_
-#define _IBM_LANA_INCLUDE_
-
-#ifdef _IBM_LANA_DRIVER_
-
-/* maximum packet size */
-
-#define PKTSIZE 1524
-
-/* number of transmit buffers */
-
-#define TXBUFCNT 4
-
-/* Adapter ID's */
-#define IBM_LANA_ID 0xffe0
-
-/* media enumeration - defined in a way that it fits onto the LAN/A's
- POS registers... */
-
-typedef enum {
- Media_10BaseT, Media_10Base5,
- Media_Unknown, Media_10Base2, Media_Count
-} ibmlana_medium;
-
-/* private structure */
-
-typedef struct {
- unsigned int slot; /* MCA-Slot-# */
- int realirq; /* memorizes actual IRQ, even when
- currently not allocated */
- ibmlana_medium medium; /* physical cannector */
- u32 tdastart, txbufstart, /* addresses */
- rrastart, rxbufstart, rdastart, rxbufcnt, txusedcnt;
- int nextrxdescr, /* next rx descriptor to be used */
- lastrxdescr, /* last free rx descriptor */
- nexttxdescr, /* last tx descriptor to be used */
- currtxdescr, /* tx descriptor currently tx'ed */
- txused[TXBUFCNT]; /* busy flags */
- void __iomem *base;
- spinlock_t lock;
-} ibmlana_priv;
-
-/* this card uses quite a lot of I/O ports...luckily the MCA bus decodes
- a full 64K I/O range... */
-
-#define IBM_LANA_IORANGE 0xa0
-
-/* Command Register: */
-
-#define SONIC_CMDREG 0x00
-#define CMDREG_HTX 0x0001 /* halt transmission */
-#define CMDREG_TXP 0x0002 /* start transmission */
-#define CMDREG_RXDIS 0x0004 /* disable receiver */
-#define CMDREG_RXEN 0x0008 /* enable receiver */
-#define CMDREG_STP 0x0010 /* stop timer */
-#define CMDREG_ST 0x0020 /* start timer */
-#define CMDREG_RST 0x0080 /* software reset */
-#define CMDREG_RRRA 0x0100 /* force SONIC to read first RRA */
-#define CMDREG_LCAM 0x0200 /* force SONIC to read CAM descrs */
-
-/* Data Configuration Register */
-
-#define SONIC_DCREG 0x02
-#define DCREG_EXBUS 0x8000 /* Extended Bus Mode */
-#define DCREG_LBR 0x2000 /* Latched Bus Retry */
-#define DCREG_PO1 0x1000 /* Programmable Outputs */
-#define DCREG_PO0 0x0800
-#define DCREG_SBUS 0x0400 /* Synchronous Bus Mode */
-#define DCREG_USR1 0x0200 /* User Definable Pins */
-#define DCREG_USR0 0x0100
-#define DCREG_WC0 0x0000 /* 0..3 Wait States */
-#define DCREG_WC1 0x0040
-#define DCREG_WC2 0x0080
-#define DCREG_WC3 0x00c0
-#define DCREG_DW16 0x0000 /* 16 bit Bus Mode */
-#define DCREG_DW32 0x0020 /* 32 bit Bus Mode */
-#define DCREG_BMS 0x0010 /* Block Mode Select */
-#define DCREG_RFT4 0x0000 /* 4/8/16/24 bytes RX Threshold */
-#define DCREG_RFT8 0x0004
-#define DCREG_RFT16 0x0008
-#define DCREG_RFT24 0x000c
-#define DCREG_TFT8 0x0000 /* 8/16/24/28 bytes TX Threshold */
-#define DCREG_TFT16 0x0001
-#define DCREG_TFT24 0x0002
-#define DCREG_TFT28 0x0003
-
-/* Receive Control Register */
-
-#define SONIC_RCREG 0x04
-#define RCREG_ERR 0x8000 /* accept damaged and collided pkts */
-#define RCREG_RNT 0x4000 /* accept packets that are < 64 */
-#define RCREG_BRD 0x2000 /* accept broadcasts */
-#define RCREG_PRO 0x1000 /* promiscuous mode */
-#define RCREG_AMC 0x0800 /* accept all multicasts */
-#define RCREG_LB_NONE 0x0000 /* no loopback */
-#define RCREG_LB_MAC 0x0200 /* MAC loopback */
-#define RCREG_LB_ENDEC 0x0400 /* ENDEC loopback */
-#define RCREG_LB_XVR 0x0600 /* Transceiver loopback */
-#define RCREG_MC 0x0100 /* Multicast received */
-#define RCREG_BC 0x0080 /* Broadcast received */
-#define RCREG_LPKT 0x0040 /* last packet in RBA */
-#define RCREG_CRS 0x0020 /* carrier sense present */
-#define RCREG_COL 0x0010 /* recv'd packet with collision */
-#define RCREG_CRCR 0x0008 /* recv'd packet with CRC error */
-#define RCREG_FAER 0x0004 /* recv'd packet with inv. framing */
-#define RCREG_LBK 0x0002 /* recv'd loopback packet */
-#define RCREG_PRX 0x0001 /* recv'd packet is OK */
-
-/* Transmit Control Register */
-
-#define SONIC_TCREG 0x06
-#define TCREG_PINT 0x8000 /* generate interrupt after TDA read */
-#define TCREG_POWC 0x4000 /* timer start out of window detect */
-#define TCREG_CRCI 0x2000 /* inhibit CRC generation */
-#define TCREG_EXDIS 0x1000 /* disable excessive deferral timer */
-#define TCREG_EXD 0x0400 /* excessive deferral occurred */
-#define TCREG_DEF 0x0200 /* single deferral occurred */
-#define TCREG_NCRS 0x0100 /* no carrier detected */
-#define TCREG_CRSL 0x0080 /* carrier lost */
-#define TCREG_EXC 0x0040 /* excessive collisions occurred */
-#define TCREG_OWC 0x0020 /* out of window collision occurred */
-#define TCREG_PMB 0x0008 /* packet monitored bad */
-#define TCREG_FU 0x0004 /* FIFO underrun */
-#define TCREG_BCM 0x0002 /* byte count mismatch of fragments */
-#define TCREG_PTX 0x0001 /* packet transmitted OK */
-
-/* Interrupt Mask Register */
-
-#define SONIC_IMREG 0x08
-#define IMREG_BREN 0x4000 /* interrupt when bus retry occurred */
-#define IMREG_HBLEN 0x2000 /* interrupt when heartbeat lost */
-#define IMREG_LCDEN 0x1000 /* interrupt when CAM loaded */
-#define IMREG_PINTEN 0x0800 /* interrupt when PINT in TDA set */
-#define IMREG_PRXEN 0x0400 /* interrupt when packet received */
-#define IMREG_PTXEN 0x0200 /* interrupt when packet was sent */
-#define IMREG_TXEREN 0x0100 /* interrupt when send failed */
-#define IMREG_TCEN 0x0080 /* interrupt when timer completed */
-#define IMREG_RDEEN 0x0040 /* interrupt when RDA exhausted */
-#define IMREG_RBEEN 0x0020 /* interrupt when RBA exhausted */
-#define IMREG_RBAEEN 0x0010 /* interrupt when RBA too short */
-#define IMREG_CRCEN 0x0008 /* interrupt when CRC counter rolls */
-#define IMREG_FAEEN 0x0004 /* interrupt when FAE counter rolls */
-#define IMREG_MPEN 0x0002 /* interrupt when MP counter rolls */
-#define IMREG_RFOEN 0x0001 /* interrupt when Rx FIFO overflows */
-
-/* Interrupt Status Register */
-
-#define SONIC_ISREG 0x0a
-#define ISREG_BR 0x4000 /* bus retry occurred */
-#define ISREG_HBL 0x2000 /* heartbeat lost */
-#define ISREG_LCD 0x1000 /* CAM loaded */
-#define ISREG_PINT 0x0800 /* PINT in TDA set */
-#define ISREG_PKTRX 0x0400 /* packet received */
-#define ISREG_TXDN 0x0200 /* packet was sent */
-#define ISREG_TXER 0x0100 /* send failed */
-#define ISREG_TC 0x0080 /* timer completed */
-#define ISREG_RDE 0x0040 /* RDA exhausted */
-#define ISREG_RBE 0x0020 /* RBA exhausted */
-#define ISREG_RBAE 0x0010 /* RBA too short for received frame */
-#define ISREG_CRC 0x0008 /* CRC counter rolls over */
-#define ISREG_FAE 0x0004 /* FAE counter rolls over */
-#define ISREG_MP 0x0002 /* MP counter rolls over */
-#define ISREG_RFO 0x0001 /* Rx FIFO overflows */
-
-#define SONIC_UTDA 0x0c /* current transmit descr address */
-#define SONIC_CTDA 0x0e
-
-#define SONIC_URDA 0x1a /* current receive descr address */
-#define SONIC_CRDA 0x1c
-
-#define SONIC_CRBA0 0x1e /* current receive buffer address */
-#define SONIC_CRBA1 0x20
-
-#define SONIC_RBWC0 0x22 /* word count in receive buffer */
-#define SONIC_RBWC1 0x24
-
-#define SONIC_EOBC 0x26 /* minimum space to be free in RBA */
-
-#define SONIC_URRA 0x28 /* upper address of CDA & Recv Area */
-
-#define SONIC_RSA 0x2a /* start of receive resource area */
-
-#define SONIC_REA 0x2c /* end of receive resource area */
-
-#define SONIC_RRP 0x2e /* resource read pointer */
-
-#define SONIC_RWP 0x30 /* resource write pointer */
-
-#define SONIC_CAMEPTR 0x42 /* CAM entry pointer */
-
-#define SONIC_CAMADDR2 0x44 /* CAM address ports */
-#define SONIC_CAMADDR1 0x46
-#define SONIC_CAMADDR0 0x48
-
-#define SONIC_CAMPTR 0x4c /* lower address of CDA */
-
-#define SONIC_CAMCNT 0x4e /* # of CAM descriptors to load */
-
-/* Data Configuration Register 2 */
-
-#define SONIC_DCREG2 0x7e
-#define DCREG2_EXPO3 0x8000 /* extended programmable outputs */
-#define DCREG2_EXPO2 0x4000
-#define DCREG2_EXPO1 0x2000
-#define DCREG2_EXPO0 0x1000
-#define DCREG2_HD 0x0800 /* heartbeat disable */
-#define DCREG2_JD 0x0200 /* jabber timer disable */
-#define DCREG2_AUTO 0x0100 /* enable AUI/TP auto selection */
-#define DCREG2_XWRAP 0x0040 /* TP transceiver loopback */
-#define DCREG2_PH 0x0010 /* HOLD request timing */
-#define DCREG2_PCM 0x0004 /* packet compress when matched */
-#define DCREG2_PCNM 0x0002 /* packet compress when not matched */
-#define DCREG2_RJCM 0x0001 /* inverse packet match via CAM */
-
-/* Board Control Register: Enable RAM, Interrupts... */
-
-#define BCMREG 0x80
-#define BCMREG_RAMEN 0x80 /* switch over to RAM */
-#define BCMREG_IPEND 0x40 /* interrupt pending ? */
-#define BCMREG_RESET 0x08 /* reset board */
-#define BCMREG_16BIT 0x04 /* adapter in 16-bit slot */
-#define BCMREG_RAMWIN 0x02 /* enable RAM window */
-#define BCMREG_IEN 0x01 /* interrupt enable */
-
-/* MAC Address PROM */
-
-#define MACADDRPROM 0x92
-
-/* structure of a CAM entry */
-
-typedef struct {
- u32 index; /* pointer into CAM area */
- u32 addr0; /* address part (bits 0..15 used) */
- u32 addr1;
- u32 addr2;
-} camentry_t;
-
-/* structure of a receive resource */
-
-typedef struct {
- u32 startlo; /* start address (bits 0..15 used) */
- u32 starthi;
- u32 cntlo; /* size in 16-bit quantities */
- u32 cnthi;
-} rra_t;
-
-/* structure of a receive descriptor */
-
-typedef struct {
- u32 status; /* packet status */
- u32 length; /* length in bytes */
- u32 startlo; /* start address */
- u32 starthi;
- u32 seqno; /* frame sequence */
- u32 link; /* pointer to next descriptor */
- /* bit 0 = EOL */
- u32 inuse; /* !=0 --> free for SONIC to write */
-} rda_t;
-
-/* structure of a transmit descriptor */
-
-typedef struct {
- u32 status; /* transmit status */
- u32 config; /* value for TCR */
- u32 length; /* total length */
- u32 fragcount; /* number of fragments */
- u32 startlo; /* start address of fragment */
- u32 starthi;
- u32 fraglength; /* length of this fragment */
- /* more address/length triplets may */
- /* follow here */
- u32 link; /* pointer to next descriptor */
- /* bit 0 = EOL */
-} tda_t;
-
-#endif /* _IBM_LANA_DRIVER_ */
-
-#endif /* _IBM_LANA_INCLUDE_ */
diff --git a/drivers/net/ethernet/natsemi/natsemi.c b/drivers/net/ethernet/natsemi/natsemi.c
index f4ad60c97eae..7a5e295588b0 100644
--- a/drivers/net/ethernet/natsemi/natsemi.c
+++ b/drivers/net/ethernet/natsemi/natsemi.c
@@ -862,9 +862,6 @@ static int natsemi_probe1(struct pci_dev *pdev, const struct pci_device_id *ent)
prev_eedata = eedata;
}
- /* Store MAC Address in perm_addr */
- memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
-
np = netdev_priv(dev);
np->ioaddr = ioaddr;
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 7c94c089212f..bfd887382e19 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -8014,7 +8014,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Set the factory defined MAC address initially */
dev->addr_len = ETH_ALEN;
memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
- memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
/* initialize number of multicast & unicast MAC entries variables */
if (sp->device_type == XFRAME_I_DEVICE) {
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c
index 92dd72d3f9de..f8f073880f84 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c
@@ -82,9 +82,9 @@ static void vxge_ethtool_gdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct vxgedev *vdev = netdev_priv(dev);
- strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(VXGE_DRIVER_NAME));
- strlcpy(info->version, DRV_VERSION, sizeof(DRV_VERSION));
- strlcpy(info->fw_version, vdev->fw_version, VXGE_HW_FW_STRLEN);
+ strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, vdev->fw_version, sizeof(info->fw_version));
strlcpy(info->bus_info, pci_name(vdev->pdev), sizeof(info->bus_info));
info->regdump_len = sizeof(struct vxge_hw_vpath_reg)
* vdev->no_of_vpath;
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
index 7c87105ca049..794444e09492 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -4682,7 +4682,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Store the fw version for ethttool option */
strcpy(vdev->fw_version, ll_config->device_hw_info.fw_version.version);
memcpy(vdev->ndev->dev_addr, (u8 *)vdev->vpaths[0].macaddr, ETH_ALEN);
- memcpy(vdev->ndev->perm_addr, vdev->ndev->dev_addr, ETH_ALEN);
/* Copy the station mac address to the list */
for (i = 0; i < vdev->no_of_vpath; i++) {
diff --git a/drivers/net/ethernet/nuvoton/w90p910_ether.c b/drivers/net/ethernet/nuvoton/w90p910_ether.c
index cbd6a529d0c0..162da8975b05 100644
--- a/drivers/net/ethernet/nuvoton/w90p910_ether.c
+++ b/drivers/net/ethernet/nuvoton/w90p910_ether.c
@@ -878,8 +878,8 @@ static int w90p910_ether_ioctl(struct net_device *dev,
static void w90p910_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, DRV_MODULE_NAME);
- strcpy(info->version, DRV_MODULE_VERSION);
+ strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
}
static int w90p910_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index 87fa5919c455..0b8de12bcbca 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -3055,7 +3055,6 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
/* synchronized against open : rtnl_lock() held by caller */
memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
if (netif_running(dev)) {
netif_tx_lock_bh(dev);
@@ -5766,9 +5765,8 @@ static int nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
"%s: set workaround bit for reversed mac addr\n",
__func__);
}
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- if (!is_valid_ether_addr(dev->perm_addr)) {
+ if (!is_valid_ether_addr(dev->dev_addr)) {
/*
* Bad mac address. At least one bios sets the mac address
* to 01:23:45:67:89:ab
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index 3466ca1e8f6c..c4122c86f829 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -800,7 +800,7 @@ static int lpc_mii_probe(struct net_device *ndev)
else
netdev_info(ndev, "using RMII interface\n");
phydev = phy_connect(ndev, dev_name(&phydev->dev),
- &lpc_handle_link_change, 0,
+ &lpc_handle_link_change,
lpc_phy_interface_mode(&pldat->pdev->dev));
if (IS_ERR(phydev)) {
@@ -1239,9 +1239,10 @@ static int lpc_eth_open(struct net_device *ndev)
static void lpc_eth_ethtool_getdrvinfo(struct net_device *ndev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, MODNAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, dev_name(ndev->dev.parent));
+ strlcpy(info->driver, MODNAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, dev_name(ndev->dev.parent),
+ sizeof(info->bus_info));
}
static u32 lpc_eth_ethtool_getmsglevel(struct net_device *ndev)
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index b5499198e029..921729f9c85c 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -1350,10 +1350,10 @@ static void octeon_mgmt_poll_controller(struct net_device *netdev)
static void octeon_mgmt_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
- strncpy(info->driver, DRV_NAME, sizeof(info->driver));
- strncpy(info->version, DRV_VERSION, sizeof(info->version));
- strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
- strncpy(info->bus_info, "N/A", sizeof(info->bus_info));
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+ strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
info->n_stats = 0;
info->testinfo_len = 0;
info->regdump_len = 0;
@@ -1534,12 +1534,10 @@ static int octeon_mgmt_probe(struct platform_device *pdev)
mac = of_get_mac_address(pdev->dev.of_node);
- if (mac && is_valid_ether_addr(mac)) {
+ if (mac && is_valid_ether_addr(mac))
memcpy(netdev->dev_addr, mac, ETH_ALEN);
- netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
- } else {
+ else
eth_hw_addr_random(netdev);
- }
p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
diff --git a/drivers/net/ethernet/packetengines/Kconfig b/drivers/net/ethernet/packetengines/Kconfig
index 8f29feb35548..cbbeca3f8c5c 100644
--- a/drivers/net/ethernet/packetengines/Kconfig
+++ b/drivers/net/ethernet/packetengines/Kconfig
@@ -32,8 +32,8 @@ config HAMACHI
called hamachi.
config YELLOWFIN
- tristate "Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "Packet Engines Yellowfin Gigabit-NIC support"
+ depends on PCI
select CRC32
---help---
Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
diff --git a/drivers/net/ethernet/packetengines/hamachi.c b/drivers/net/ethernet/packetengines/hamachi.c
index bf829ee30077..cac33e5f9bc2 100644
--- a/drivers/net/ethernet/packetengines/hamachi.c
+++ b/drivers/net/ethernet/packetengines/hamachi.c
@@ -1808,9 +1808,10 @@ static int check_if_running(struct net_device *dev)
static void hamachi_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct hamachi_private *np = netdev_priv(dev);
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, pci_name(np->pci_dev));
+
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
}
static int hamachi_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
diff --git a/drivers/net/ethernet/packetengines/yellowfin.c b/drivers/net/ethernet/packetengines/yellowfin.c
index fbaed4fa72fa..d28593b1fc3e 100644
--- a/drivers/net/ethernet/packetengines/yellowfin.c
+++ b/drivers/net/ethernet/packetengines/yellowfin.c
@@ -1326,9 +1326,10 @@ static void set_rx_mode(struct net_device *dev)
static void yellowfin_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct yellowfin_private *np = netdev_priv(dev);
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, pci_name(np->pci_dev));
+
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
}
static const struct ethtool_ops ethtool_ops = {
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
index 7f556a84925d..1bcaf45aa864 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
@@ -201,11 +201,8 @@ netxen_setup_minidump(struct netxen_adapter *adapter)
adapter->mdump.md_template =
kmalloc(adapter->mdump.md_template_size, GFP_KERNEL);
- if (!adapter->mdump.md_template) {
- dev_err(&adapter->pdev->dev, "Unable to allocate memory "
- "for minidump template.\n");
+ if (!adapter->mdump.md_template)
return -ENOMEM;
- }
err = netxen_get_minidump_template(adapter);
if (err) {
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
index 946160fa5843..9fbb1cdbfa47 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c
@@ -670,11 +670,9 @@ static int nx_p3_nic_add_mac(struct netxen_adapter *adapter,
}
cur = kzalloc(sizeof(nx_mac_list_t), GFP_ATOMIC);
- if (cur == NULL) {
- printk(KERN_ERR "%s: failed to add mac address filter\n",
- adapter->netdev->name);
+ if (cur == NULL)
return -ENOMEM;
- }
+
memcpy(cur->mac_addr, addr, ETH_ALEN);
list_add_tail(&cur->list, &adapter->mac_list);
return nx_p3_sre_macaddr_change(adapter,
@@ -2568,16 +2566,10 @@ netxen_dump_fw(struct netxen_adapter *adapter)
adapter->mdump.md_capture_size;
if (!adapter->mdump.md_capture_buff) {
adapter->mdump.md_capture_buff =
- vmalloc(adapter->mdump.md_dump_size);
- if (!adapter->mdump.md_capture_buff) {
- dev_info(&adapter->pdev->dev,
- "Unable to allocate memory for minidump "
- "capture_buffer(%d bytes).\n",
- adapter->mdump.md_dump_size);
+ vzalloc(adapter->mdump.md_dump_size);
+ if (!adapter->mdump.md_capture_buff)
return;
- }
- memset(adapter->mdump.md_capture_buff, 0,
- adapter->mdump.md_dump_size);
+
if (netxen_collect_minidump(adapter)) {
adapter->mdump.has_valid_dump = 0;
adapter->mdump.md_dump_size = 0;
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
index 695667d471a1..4782dcfde736 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
@@ -197,41 +197,33 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
struct nx_host_sds_ring *sds_ring;
struct nx_host_tx_ring *tx_ring;
struct netxen_rx_buffer *rx_buf;
- int ring, i, size;
+ int ring, i;
struct netxen_cmd_buffer *cmd_buf_arr;
struct net_device *netdev = adapter->netdev;
- struct pci_dev *pdev = adapter->pdev;
- size = sizeof(struct nx_host_tx_ring);
- tx_ring = kzalloc(size, GFP_KERNEL);
- if (tx_ring == NULL) {
- dev_err(&pdev->dev, "%s: failed to allocate tx ring struct\n",
- netdev->name);
+ tx_ring = kzalloc(sizeof(struct nx_host_tx_ring), GFP_KERNEL);
+ if (tx_ring == NULL)
return -ENOMEM;
- }
+
adapter->tx_ring = tx_ring;
tx_ring->num_desc = adapter->num_txd;
tx_ring->txq = netdev_get_tx_queue(netdev, 0);
cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
- if (cmd_buf_arr == NULL) {
- dev_err(&pdev->dev, "%s: failed to allocate cmd buffer ring\n",
- netdev->name);
+ if (cmd_buf_arr == NULL)
goto err_out;
- }
+
tx_ring->cmd_buf_arr = cmd_buf_arr;
recv_ctx = &adapter->recv_ctx;
- size = adapter->max_rds_rings * sizeof (struct nx_host_rds_ring);
- rds_ring = kzalloc(size, GFP_KERNEL);
- if (rds_ring == NULL) {
- dev_err(&pdev->dev, "%s: failed to allocate rds ring struct\n",
- netdev->name);
+ rds_ring = kcalloc(adapter->max_rds_rings,
+ sizeof(struct nx_host_rds_ring), GFP_KERNEL);
+ if (rds_ring == NULL)
goto err_out;
- }
+
recv_ctx->rds_rings = rds_ring;
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 69e321a65077..501f49207da5 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -501,12 +501,11 @@ netxen_read_mac_addr(struct netxen_adapter *adapter)
for (i = 0; i < 6; i++)
netdev->dev_addr[i] = *(p + 5 - i);
- memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
/* set station address */
- if (!is_valid_ether_addr(netdev->perm_addr))
+ if (!is_valid_ether_addr(netdev->dev_addr))
dev_warn(&pdev->dev, "Bad MAC address %pM.\n", netdev->dev_addr);
return 0;
@@ -3177,11 +3176,8 @@ netxen_list_config_vlan_ip(struct netxen_adapter *adapter,
}
cur = kzalloc(sizeof(struct nx_vlan_ip_list), GFP_ATOMIC);
- if (cur == NULL) {
- printk(KERN_ERR "%s: failed to add vlan ip to list\n",
- adapter->netdev->name);
+ if (cur == NULL)
return;
- }
cur->ip_addr = ifa->ifa_address;
list_add_tail(&cur->list, &adapter->vlan_ip_list);
diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
index 67a679aaf29a..8fd38cb6d26a 100644
--- a/drivers/net/ethernet/qlogic/qla3xxx.c
+++ b/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -2591,13 +2591,11 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
else
qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2;
- qdev->lrg_buf =
- kmalloc(qdev->num_large_buffers * sizeof(struct ql_rcv_buf_cb),
- GFP_KERNEL);
- if (qdev->lrg_buf == NULL) {
- netdev_err(qdev->ndev, "qdev->lrg_buf alloc failed\n");
+ qdev->lrg_buf = kmalloc_array(qdev->num_large_buffers,
+ sizeof(struct ql_rcv_buf_cb),
+ GFP_KERNEL);
+ if (qdev->lrg_buf == NULL)
return -ENOMEM;
- }
qdev->lrg_buf_q_alloc_virt_addr =
pci_alloc_consistent(qdev->pdev,
@@ -3867,7 +3865,6 @@ static int ql3xxx_probe(struct pci_dev *pdev,
ndev->mtu = qdev->nvram_data.macCfg_port0.etherMtu_mac ;
ql_set_mac_addr(ndev, qdev->nvram_data.funcCfg_fn0.macAddress);
}
- memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
ndev->tx_queue_len = NUM_REQ_Q_ENTRIES;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/Makefile b/drivers/net/ethernet/qlogic/qlcnic/Makefile
index c4b8ced83829..7722a203e388 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/Makefile
+++ b/drivers/net/ethernet/qlogic/qlcnic/Makefile
@@ -6,4 +6,6 @@ obj-$(CONFIG_QLCNIC) := qlcnic.o
qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \
- qlcnic_sysfs.o qlcnic_minidump.o
+ qlcnic_sysfs.o qlcnic_minidump.o qlcnic_83xx_hw.o \
+ qlcnic_83xx_init.o qlcnic_83xx_vnic.o \
+ qlcnic_minidump.o
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index bc7ec64e9c7a..11c3db6daffd 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1,6 +1,6 @@
/*
* QLogic qlcnic NIC Driver
- * Copyright (c) 2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
*
* See LICENSE.qlcnic for copyright and licensing details.
*/
@@ -33,11 +33,13 @@
#include <linux/if_vlan.h>
#include "qlcnic_hdr.h"
+#include "qlcnic_hw.h"
+#include "qlcnic_83xx_hw.h"
#define _QLCNIC_LINUX_MAJOR 5
-#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 30
-#define QLCNIC_LINUX_VERSIONID "5.0.30"
+#define _QLCNIC_LINUX_MINOR 1
+#define _QLCNIC_LINUX_SUBVERSION 34
+#define QLCNIC_LINUX_VERSIONID "5.1.34"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -96,7 +98,6 @@
#define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
+ MGMT_CMD_DESC_RESV)
#define QLCNIC_MAX_TX_TIMEOUTS 2
-
/*
* Following are the states of the Phantom. Phantom will set them and
* Host will read to check if the fields are correct.
@@ -203,6 +204,7 @@ struct uni_data_desc{
/* Flash Defines and Structures */
#define QLCNIC_FLT_LOCATION 0x3F1000
+#define QLCNIC_FDT_LOCATION 0x3F0000
#define QLCNIC_B0_FW_IMAGE_REGION 0x74
#define QLCNIC_C0_FW_IMAGE_REGION 0x97
#define QLCNIC_BOOTLD_REGION 0X72
@@ -223,6 +225,36 @@ struct qlcnic_flt_entry {
u32 end_addr;
};
+/* Flash Descriptor Table */
+struct qlcnic_fdt {
+ u32 valid;
+ u16 ver;
+ u16 len;
+ u16 cksum;
+ u16 unused;
+ u8 model[16];
+ u16 mfg_id;
+ u16 id;
+ u8 flag;
+ u8 erase_cmd;
+ u8 alt_erase_cmd;
+ u8 write_enable_cmd;
+ u8 write_enable_bits;
+ u8 write_statusreg_cmd;
+ u8 unprotected_sec_cmd;
+ u8 read_manuf_cmd;
+ u32 block_size;
+ u32 alt_block_size;
+ u32 flash_size;
+ u32 write_enable_data;
+ u8 readid_addr_len;
+ u8 write_disable_bits;
+ u8 read_dev_id_len;
+ u8 chip_erase_cmd;
+ u16 read_timeo;
+ u8 protected_sec_cmd;
+ u8 resvd[65];
+};
/* Magic number to let user know flash is programmed */
#define QLCNIC_BDINFO_MAGIC 0x12345678
@@ -267,6 +299,12 @@ struct qlcnic_flt_entry {
extern char qlcnic_driver_name[];
+extern int qlcnic_use_msi;
+extern int qlcnic_use_msi_x;
+extern int qlcnic_auto_fw_reset;
+extern int qlcnic_load_fw_file;
+extern int qlcnic_config_npars;
+
/* Number of status descriptors to handle per interrupt */
#define MAX_STATUS_HANDLE (64)
@@ -314,6 +352,7 @@ struct qlcnic_rx_buffer {
#define QLCNIC_INTR_DEFAULT 0x04
#define QLCNIC_CONFIG_INTR_COALESCE 3
+#define QLCNIC_DEV_INFO_SIZE 1
struct qlcnic_nic_intr_coalesce {
u8 type;
@@ -337,6 +376,7 @@ struct qlcnic_dump_template_hdr {
u32 sys_info[3];
u32 saved_state[16];
u32 cap_sizes[8];
+ u32 ocm_wnd_reg[16];
u32 rsvd[0];
};
@@ -396,12 +436,24 @@ struct qlcnic_hardware_context {
u16 act_pci_func;
u32 capabilities;
+ u32 capabilities2;
u32 temp;
u32 int_vec_bit;
u32 fw_hal_version;
+ u32 port_config;
struct qlcnic_hardware_ops *hw_ops;
struct qlcnic_nic_intr_coalesce coal;
struct qlcnic_fw_dump fw_dump;
+ struct qlcnic_fdt fdt;
+ struct qlc_83xx_reset reset;
+ struct qlc_83xx_idc idc;
+ struct qlc_83xx_fw_info fw_info;
+ struct qlcnic_intrpt_config *intr_tbl;
+ u32 *reg_tbl;
+ u32 *ext_reg_tbl;
+ u32 mbox_aen[QLC_83XX_MBX_AEN_CNT];
+ u32 mbox_reg[4];
+ spinlock_t mbx_lock;
};
struct qlcnic_adapter_stats {
@@ -422,6 +474,8 @@ struct qlcnic_adapter_stats {
u64 null_rxbuf;
u64 rx_dma_map_error;
u64 tx_dma_map_error;
+ u64 spurious_intr;
+ u64 mac_filter_limit_overrun;
};
/*
@@ -460,12 +514,17 @@ struct qlcnic_host_sds_ring {
} ____cacheline_internodealigned_in_smp;
struct qlcnic_host_tx_ring {
+ int irq;
+ void __iomem *crb_intr_mask;
+ char name[IFNAMSIZ+4];
u16 ctx_id;
u32 producer;
u32 sw_consumer;
u32 num_desc;
void __iomem *crb_cmd_producer;
struct cmd_desc_type0 *desc_head;
+ struct qlcnic_adapter *adapter;
+ struct napi_struct napi;
struct qlcnic_cmd_buffer *cmd_buf_arr;
__le32 *hw_consumer;
@@ -492,8 +551,6 @@ struct qlcnic_recv_context {
/* HW context creation */
#define QLCNIC_OS_CRB_RETRY_COUNT 4000
-#define QLCNIC_CDRP_SIGNATURE_MAKE(pcifn, version) \
- (((pcifn) & 0xff) | (((version) & 0xff) << 8) | (0xcafe << 16))
#define QLCNIC_CDRP_CMD_BIT 0x80000000
@@ -513,43 +570,6 @@ struct qlcnic_recv_context {
* the crb QLCNIC_CDRP_CRB_OFFSET.
*/
#define QLCNIC_CDRP_FORM_CMD(cmd) (QLCNIC_CDRP_CMD_BIT | (cmd))
-#define QLCNIC_CDRP_IS_CMD(cmd) (((cmd) & QLCNIC_CDRP_CMD_BIT) != 0)
-
-#define QLCNIC_CDRP_CMD_SUBMIT_CAPABILITIES 0x00000001
-#define QLCNIC_CDRP_CMD_READ_MAX_RDS_PER_CTX 0x00000002
-#define QLCNIC_CDRP_CMD_READ_MAX_SDS_PER_CTX 0x00000003
-#define QLCNIC_CDRP_CMD_READ_MAX_RULES_PER_CTX 0x00000004
-#define QLCNIC_CDRP_CMD_READ_MAX_RX_CTX 0x00000005
-#define QLCNIC_CDRP_CMD_READ_MAX_TX_CTX 0x00000006
-#define QLCNIC_CDRP_CMD_CREATE_RX_CTX 0x00000007
-#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_INTRPT_TEST 0x00000011
-#define QLCNIC_CDRP_CMD_SET_MTU 0x00000012
-#define QLCNIC_CDRP_CMD_READ_PHY 0x00000013
-#define QLCNIC_CDRP_CMD_WRITE_PHY 0x00000014
-#define QLCNIC_CDRP_CMD_READ_HW_REG 0x00000015
-#define QLCNIC_CDRP_CMD_GET_FLOW_CTL 0x00000016
-#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_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_GET_ESWITCH_CAPABILITY 0x00000024
-#define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH 0x00000025
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS 0x00000026
-#define QLCNIC_CDRP_CMD_SET_PORTMIRRORING 0x00000027
-#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH 0x00000028
-#define QLCNIC_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_CDRP_CMD_GET_MAC_STATS 0x00000037
#define QLCNIC_RCODE_SUCCESS 0
#define QLCNIC_RCODE_INVALID_ARGS 6
@@ -726,6 +746,11 @@ struct qlcnic_mac_list_s {
uint8_t mac_addr[ETH_ALEN+2];
};
+/* MAC Learn */
+#define NO_MAC_LEARN 0
+#define DRV_MAC_LEARN 1
+#define FDB_MAC_LEARN 2
+
#define QLCNIC_HOST_REQUEST 0x13
#define QLCNIC_REQUEST 0x14
@@ -762,7 +787,7 @@ struct qlcnic_mac_list_s {
*/
#define QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK 0x8f
-#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141
+#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 0x8D
#define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */
#define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */
@@ -779,6 +804,8 @@ struct qlcnic_mac_list_s {
#define QLCNIC_FW_CAPABILITY_MORE_CAPS BIT_31
#define QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG BIT_2
+#define QLCNIC_FW_CAP2_HW_LRO_IPV6 BIT_3
+#define QLCNIC_FW_CAPABILITY_2_OCBB BIT_5
/* module types */
#define LINKEVENT_MODULE_NOT_PRESENT 1
@@ -855,7 +882,7 @@ struct qlcnic_ipaddr {
#define QLCNIC_MSI_ENABLED 0x02
#define QLCNIC_MSIX_ENABLED 0x04
-#define QLCNIC_LRO_ENABLED 0x08
+#define QLCNIC_LRO_ENABLED 0x01
#define QLCNIC_LRO_DISABLED 0x00
#define QLCNIC_BRIDGE_ENABLED 0X10
#define QLCNIC_DIAG_ENABLED 0x20
@@ -887,6 +914,7 @@ struct qlcnic_ipaddr {
#define __QLCNIC_AER 5
#define __QLCNIC_DIAG_RES_ALLOC 6
#define __QLCNIC_LED_ENABLE 7
+#define __QLCNIC_ELB_INPROGRESS 8
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2
@@ -895,12 +923,14 @@ struct qlcnic_ipaddr {
#define QLCNIC_FILTER_AGE 80
#define QLCNIC_READD_AGE 20
#define QLCNIC_LB_MAX_FILTERS 64
+#define QLCNIC_LB_BUCKET_SIZE 32
/* QLCNIC Driver Error Code */
#define QLCNIC_FW_NOT_RESPOND 51
#define QLCNIC_TEST_IN_PROGRESS 52
#define QLCNIC_UNDEFINED_ERROR 53
#define QLCNIC_LB_CABLE_NOT_CONN 54
+#define QLCNIC_ILB_MAX_RCV_LOOP 10
struct qlcnic_filter {
struct hlist_node fnode;
@@ -912,7 +942,8 @@ struct qlcnic_filter {
struct qlcnic_filter_hash {
struct hlist_head *fhead;
u8 fnum;
- u8 fmax;
+ u16 fmax;
+ u16 fbucket_size;
};
struct qlcnic_adapter {
@@ -934,6 +965,7 @@ struct qlcnic_adapter {
u8 max_rds_rings;
u8 max_sds_rings;
+ u8 rx_csum;
u8 portnum;
u8 fw_wait_cnt;
@@ -954,8 +986,10 @@ struct qlcnic_adapter {
u8 mac_addr[ETH_ALEN];
u64 dev_rst_time;
- u8 mac_learn;
+ bool drv_mac_learn;
+ bool fdb_mac_learn;
unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)];
+ u8 flash_mfg_id;
struct qlcnic_npar_info *npars;
struct qlcnic_eswitch *eswitch;
struct qlcnic_nic_template *nic_ops;
@@ -969,12 +1003,17 @@ struct qlcnic_adapter {
void __iomem *isr_int_vec;
struct msix_entry *msix_entries;
+ struct workqueue_struct *qlcnic_wq;
struct delayed_work fw_work;
+ struct delayed_work idc_aen_work;
struct qlcnic_filter_hash fhash;
+ struct qlcnic_filter_hash rx_fhash;
spinlock_t tx_clean_lock;
spinlock_t mac_learn_lock;
+ /* spinlock for catching rcv filters for eswitch traffic */
+ spinlock_t rx_mac_learn_lock;
u32 file_prd_off; /*File fw product offset*/
u32 fw_version;
const struct firmware *fw;
@@ -995,7 +1034,24 @@ struct qlcnic_info_le {
__le16 max_rx_ques;
__le16 min_tx_bw;
__le16 max_tx_bw;
- u8 reserved2[104];
+ __le32 op_type;
+ __le16 max_bw_reg_offset;
+ __le16 max_linkspeed_reg_offset;
+ __le32 capability1;
+ __le32 capability2;
+ __le32 capability3;
+ __le16 max_tx_mac_filters;
+ __le16 max_rx_mcast_mac_filters;
+ __le16 max_rx_ucast_mac_filters;
+ __le16 max_rx_ip_addr;
+ __le16 max_rx_lro_flow;
+ __le16 max_rx_status_rings;
+ __le16 max_rx_buf_rings;
+ __le16 max_tx_vlan_keys;
+ u8 total_pf;
+ u8 total_rss_engines;
+ __le16 max_vports;
+ u8 reserved2[64];
} __packed;
struct qlcnic_info {
@@ -1005,12 +1061,28 @@ struct qlcnic_info {
u16 switch_mode;
u32 capabilities;
u8 max_mac_filters;
- u8 reserved1;
u16 max_mtu;
u16 max_tx_ques;
u16 max_rx_ques;
u16 min_tx_bw;
u16 max_tx_bw;
+ u32 op_type;
+ u16 max_bw_reg_offset;
+ u16 max_linkspeed_reg_offset;
+ u32 capability1;
+ u32 capability2;
+ u32 capability3;
+ u16 max_tx_mac_filters;
+ u16 max_rx_mcast_mac_filters;
+ u16 max_rx_ucast_mac_filters;
+ u16 max_rx_ip_addr;
+ u16 max_rx_lro_flow;
+ u16 max_rx_status_rings;
+ u16 max_rx_buf_rings;
+ u16 max_tx_vlan_keys;
+ u8 total_pf;
+ u8 total_rss_engines;
+ u16 max_vports;
};
struct qlcnic_pci_info_le {
@@ -1024,7 +1096,9 @@ struct qlcnic_pci_info_le {
__le16 reserved1[2];
u8 mac[ETH_ALEN];
- u8 reserved2[106];
+ __le16 func_count;
+ u8 reserved2[104];
+
} __packed;
struct qlcnic_pci_info {
@@ -1035,6 +1109,7 @@ struct qlcnic_pci_info {
u16 tx_min_bw;
u16 tx_max_bw;
u8 mac[ETH_ALEN];
+ u16 func_count;
};
struct qlcnic_npar_info {
@@ -1266,10 +1341,8 @@ struct qlcnic_esw_statistics {
#define QLCNIC_RESET_QUIESCENT 0xadd00020
struct _cdrp_cmd {
- u32 cmd;
- u32 arg1;
- u32 arg2;
- u32 arg3;
+ u32 num;
+ u32 *arg;
};
struct qlcnic_cmd_args {
@@ -1279,9 +1352,6 @@ struct qlcnic_cmd_args {
int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config);
-
-int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off);
-int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data);
int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *, u64 off, u64 data);
int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *, u64 off, u64 *data);
void qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *, u64, u64 *);
@@ -1291,9 +1361,10 @@ void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64);
(((addr) < (high)) && ((addr) >= (low)))
#define QLCRD32(adapter, off) \
- (qlcnic_hw_read_wx_2M(adapter, off))
+ (adapter->ahw->hw_ops->read_reg)(adapter, off)
+
#define QLCWR32(adapter, off, val) \
- (qlcnic_hw_write_wx_2M(adapter, off, val))
+ adapter->ahw->hw_ops->write_reg(adapter, off, val)
int qlcnic_pcie_sem_lock(struct qlcnic_adapter *, int, u32);
void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
@@ -1306,10 +1377,6 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
qlcnic_pcie_sem_lock((a), 3, QLCNIC_PHY_LOCK_ID)
#define qlcnic_phy_unlock(a) \
qlcnic_pcie_sem_unlock((a), 3)
-#define qlcnic_api_lock(a) \
- qlcnic_pcie_sem_lock((a), 5, 0)
-#define qlcnic_api_unlock(a) \
- qlcnic_pcie_sem_unlock((a), 5)
#define qlcnic_sw_lock(a) \
qlcnic_pcie_sem_lock((a), 6, 0)
#define qlcnic_sw_unlock(a) \
@@ -1324,14 +1391,13 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
#define MAX_CTL_CHECK 1000
-int qlcnic_get_board_info(struct qlcnic_adapter *adapter);
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 */
+void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int);
int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter);
void qlcnic_request_firmware(struct qlcnic_adapter *adapter);
@@ -1361,54 +1427,42 @@ 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,
- struct qlcnic_host_rds_ring *rds_ring);
+ struct qlcnic_host_rds_ring *rds_ring, u8 ring_id);
int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max);
void qlcnic_set_multi(struct net_device *netdev);
+int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *);
+int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *);
void qlcnic_free_mac_list(struct qlcnic_adapter *adapter);
-int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
-int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter);
-int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable);
-int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd);
-int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable);
-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_fw_cmd_set_drv_version(struct qlcnic_adapter *);
int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
netdev_features_t qlcnic_fix_features(struct net_device *netdev,
netdev_features_t features);
int qlcnic_set_features(struct net_device *netdev, netdev_features_t 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);
void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *);
-void qlcnic_fetch_mac(u32, u32, u8, u8 *);
-void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
-void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter);
-int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode);
/* Functions from qlcnic_ethtool.c */
-int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]);
+int qlcnic_check_loopback_buff(unsigned char *, u8 []);
+int qlcnic_do_lb_test(struct qlcnic_adapter *, u8);
+int qlcnic_loopback_test(struct net_device *, u8);
/* Functions from qlcnic_main.c */
int qlcnic_reset_context(struct qlcnic_adapter *);
-void qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *);
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 *);
+int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, size_t);
+int qlcnic_validate_max_rss(u8, u8);
void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
-
-/* Management functions */
-int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
-int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
-int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
-int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
+int qlcnic_enable_msix(struct qlcnic_adapter *, u32);
/* eSwitch management functions */
int qlcnic_config_switch_port(struct qlcnic_adapter *,
struct qlcnic_esw_func_cfg *);
+
int qlcnic_get_eswitch_port_config(struct qlcnic_adapter *,
struct qlcnic_esw_func_cfg *);
int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8);
@@ -1418,14 +1472,12 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *, const u8, u8,
struct __qlcnic_esw_statistics *);
int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8);
int qlcnic_get_mac_stats(struct qlcnic_adapter *, struct qlcnic_mac_statistics *);
-extern int qlcnic_config_tso;
-int qlcnic_napi_add(struct qlcnic_adapter *, struct net_device *);
-void qlcnic_napi_del(struct qlcnic_adapter *adapter);
-void qlcnic_napi_enable(struct qlcnic_adapter *adapter);
-void qlcnic_napi_disable(struct qlcnic_adapter *adapter);
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd);
+
int qlcnic_alloc_sds_rings(struct qlcnic_recv_context *, int);
void qlcnic_free_sds_rings(struct qlcnic_recv_context *);
+void qlcnic_advert_link_change(struct qlcnic_adapter *, int);
void qlcnic_free_tx_rings(struct qlcnic_adapter *);
int qlcnic_alloc_tx_rings(struct qlcnic_adapter *, struct net_device *);
@@ -1433,6 +1485,9 @@ void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);
void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
+void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter);
+void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter);
+
int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
void qlcnic_set_vlan_config(struct qlcnic_adapter *,
@@ -1440,6 +1495,22 @@ void qlcnic_set_vlan_config(struct qlcnic_adapter *,
void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *,
struct qlcnic_esw_func_cfg *);
+void qlcnic_down(struct qlcnic_adapter *, struct net_device *);
+int qlcnic_up(struct qlcnic_adapter *, struct net_device *);
+void __qlcnic_down(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_detach(struct qlcnic_adapter *);
+void qlcnic_teardown_intr(struct qlcnic_adapter *);
+int qlcnic_attach(struct qlcnic_adapter *);
+int __qlcnic_up(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_restore_indev_addr(struct net_device *, unsigned long);
+
+int qlcnic_check_temp(struct qlcnic_adapter *);
+int qlcnic_init_pci_info(struct qlcnic_adapter *);
+int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
+int qlcnic_reset_npar_config(struct qlcnic_adapter *);
+int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
+void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int,
+ __le16);
/*
* QLOGIC Board information
*/
@@ -1462,6 +1533,277 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
tx_ring->producer;
}
+struct qlcnic_nic_template {
+ int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
+ int (*config_led) (struct qlcnic_adapter *, u32, u32);
+ int (*start_firmware) (struct qlcnic_adapter *);
+ int (*init_driver) (struct qlcnic_adapter *);
+ void (*request_reset) (struct qlcnic_adapter *, u32);
+ void (*cancel_idc_work) (struct qlcnic_adapter *);
+ int (*napi_add)(struct qlcnic_adapter *, struct net_device *);
+ void (*napi_del)(struct qlcnic_adapter *);
+ void (*config_ipaddr)(struct qlcnic_adapter *, __be32, int);
+ irqreturn_t (*clear_legacy_intr)(struct qlcnic_adapter *);
+};
+
+/* Adapter hardware abstraction */
+struct qlcnic_hardware_ops {
+ void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
+ void (*write_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
+ int (*read_reg) (struct qlcnic_adapter *, ulong);
+ int (*write_reg) (struct qlcnic_adapter *, ulong, u32);
+ void (*get_ocm_win) (struct qlcnic_hardware_context *);
+ int (*get_mac_address) (struct qlcnic_adapter *, u8 *);
+ int (*setup_intr) (struct qlcnic_adapter *, u8);
+ int (*alloc_mbx_args)(struct qlcnic_cmd_args *,
+ struct qlcnic_adapter *, u32);
+ int (*mbx_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+ void (*get_func_no) (struct qlcnic_adapter *);
+ int (*api_lock) (struct qlcnic_adapter *);
+ void (*api_unlock) (struct qlcnic_adapter *);
+ void (*add_sysfs) (struct qlcnic_adapter *);
+ void (*remove_sysfs) (struct qlcnic_adapter *);
+ void (*process_lb_rcv_ring_diag) (struct qlcnic_host_sds_ring *);
+ int (*create_rx_ctx) (struct qlcnic_adapter *);
+ int (*create_tx_ctx) (struct qlcnic_adapter *,
+ struct qlcnic_host_tx_ring *, int);
+ int (*setup_link_event) (struct qlcnic_adapter *, int);
+ int (*get_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *, u8);
+ int (*get_pci_info) (struct qlcnic_adapter *, struct qlcnic_pci_info *);
+ int (*set_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *);
+ int (*change_macvlan) (struct qlcnic_adapter *, u8*, __le16, u8);
+ void (*napi_enable) (struct qlcnic_adapter *);
+ void (*napi_disable) (struct qlcnic_adapter *);
+ void (*config_intr_coal) (struct qlcnic_adapter *);
+ int (*config_rss) (struct qlcnic_adapter *, int);
+ int (*config_hw_lro) (struct qlcnic_adapter *, int);
+ int (*config_loopback) (struct qlcnic_adapter *, u8);
+ int (*clear_loopback) (struct qlcnic_adapter *, u8);
+ int (*config_promisc_mode) (struct qlcnic_adapter *, u32);
+ void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, __le16);
+ int (*get_board_info) (struct qlcnic_adapter *);
+};
+
+extern struct qlcnic_nic_template qlcnic_vf_ops;
+
+static inline int qlcnic_start_firmware(struct qlcnic_adapter *adapter)
+{
+ return adapter->nic_ops->start_firmware(adapter);
+}
+
+static inline void qlcnic_read_crb(struct qlcnic_adapter *adapter, char *buf,
+ loff_t offset, size_t size)
+{
+ adapter->ahw->hw_ops->read_crb(adapter, buf, offset, size);
+}
+
+static inline void qlcnic_write_crb(struct qlcnic_adapter *adapter, char *buf,
+ loff_t offset, size_t size)
+{
+ adapter->ahw->hw_ops->write_crb(adapter, buf, offset, size);
+}
+
+static inline int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter,
+ ulong off)
+{
+ return adapter->ahw->hw_ops->read_reg(adapter, off);
+}
+
+static inline int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter,
+ ulong off, u32 data)
+{
+ return adapter->ahw->hw_ops->write_reg(adapter, off, data);
+}
+
+static inline int qlcnic_get_mac_address(struct qlcnic_adapter *adapter,
+ u8 *mac)
+{
+ return adapter->ahw->hw_ops->get_mac_address(adapter, mac);
+}
+
+static inline int qlcnic_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+{
+ return adapter->ahw->hw_ops->setup_intr(adapter, num_intr);
+}
+
+static inline int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+ struct qlcnic_adapter *adapter, u32 arg)
+{
+ return adapter->ahw->hw_ops->alloc_mbx_args(mbx, adapter, arg);
+}
+
+static inline int qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd)
+{
+ return adapter->ahw->hw_ops->mbx_cmd(adapter, cmd);
+}
+
+static inline void qlcnic_get_func_no(struct qlcnic_adapter *adapter)
+{
+ adapter->ahw->hw_ops->get_func_no(adapter);
+}
+
+static inline int qlcnic_api_lock(struct qlcnic_adapter *adapter)
+{
+ return adapter->ahw->hw_ops->api_lock(adapter);
+}
+
+static inline void qlcnic_api_unlock(struct qlcnic_adapter *adapter)
+{
+ adapter->ahw->hw_ops->api_unlock(adapter);
+}
+
+static inline void qlcnic_add_sysfs(struct qlcnic_adapter *adapter)
+{
+ adapter->ahw->hw_ops->add_sysfs(adapter);
+}
+
+static inline void qlcnic_remove_sysfs(struct qlcnic_adapter *adapter)
+{
+ adapter->ahw->hw_ops->remove_sysfs(adapter);
+}
+
+static inline void
+qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+ sds_ring->adapter->ahw->hw_ops->process_lb_rcv_ring_diag(sds_ring);
+}
+
+static inline int qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
+{
+ return adapter->ahw->hw_ops->create_rx_ctx(adapter);
+}
+
+static inline int qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *ptr,
+ int ring)
+{
+ return adapter->ahw->hw_ops->create_tx_ctx(adapter, ptr, ring);
+}
+
+static inline int qlcnic_linkevent_request(struct qlcnic_adapter *adapter,
+ int enable)
+{
+ return adapter->ahw->hw_ops->setup_link_event(adapter, enable);
+}
+
+static inline int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *info, u8 id)
+{
+ return adapter->ahw->hw_ops->get_nic_info(adapter, info, id);
+}
+
+static inline int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_pci_info *info)
+{
+ return adapter->ahw->hw_ops->get_pci_info(adapter, info);
+}
+
+static inline int qlcnic_set_nic_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *info)
+{
+ return adapter->ahw->hw_ops->set_nic_info(adapter, info);
+}
+
+static inline int qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter,
+ u8 *addr, __le16 id, u8 cmd)
+{
+ return adapter->ahw->hw_ops->change_macvlan(adapter, addr, id, cmd);
+}
+
+static inline int qlcnic_napi_add(struct qlcnic_adapter *adapter,
+ struct net_device *netdev)
+{
+ return adapter->nic_ops->napi_add(adapter, netdev);
+}
+
+static inline void qlcnic_napi_del(struct qlcnic_adapter *adapter)
+{
+ adapter->nic_ops->napi_del(adapter);
+}
+
+static inline void qlcnic_napi_enable(struct qlcnic_adapter *adapter)
+{
+ adapter->ahw->hw_ops->napi_enable(adapter);
+}
+
+static inline void qlcnic_napi_disable(struct qlcnic_adapter *adapter)
+{
+ adapter->ahw->hw_ops->napi_disable(adapter);
+}
+
+static inline void qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
+{
+ adapter->ahw->hw_ops->config_intr_coal(adapter);
+}
+
+static inline int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
+{
+ return adapter->ahw->hw_ops->config_rss(adapter, enable);
+}
+
+static inline int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter,
+ int enable)
+{
+ return adapter->ahw->hw_ops->config_hw_lro(adapter, enable);
+}
+
+static inline int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+ return adapter->ahw->hw_ops->config_loopback(adapter, mode);
+}
+
+static inline int qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+ return adapter->ahw->hw_ops->config_loopback(adapter, mode);
+}
+
+static inline int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter,
+ u32 mode)
+{
+ return adapter->ahw->hw_ops->config_promisc_mode(adapter, mode);
+}
+
+static inline void qlcnic_change_filter(struct qlcnic_adapter *adapter,
+ u64 *addr, __le16 id)
+{
+ adapter->ahw->hw_ops->change_l2_filter(adapter, addr, id);
+}
+
+static inline int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
+{
+ return adapter->ahw->hw_ops->get_board_info(adapter);
+}
+
+static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
+ u32 key)
+{
+ adapter->nic_ops->request_reset(adapter, key);
+}
+
+static inline void qlcnic_cancel_idc_work(struct qlcnic_adapter *adapter)
+{
+ adapter->nic_ops->cancel_idc_work(adapter);
+}
+
+static inline irqreturn_t
+qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
+{
+ return adapter->nic_ops->clear_legacy_intr(adapter);
+}
+
+static inline int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state,
+ u32 rate)
+{
+ return adapter->nic_ops->config_led(adapter, state, rate);
+}
+
+static inline void qlcnic_config_ipaddr(struct qlcnic_adapter *adapter,
+ __be32 ip, int cmd)
+{
+ adapter->nic_ops->config_ipaddr(adapter, ip, cmd);
+}
+
static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
{
writel(0, sds_ring->crb_intr_mask);
@@ -1480,12 +1822,6 @@ static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
extern const struct ethtool_ops qlcnic_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
-struct qlcnic_nic_template {
- int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
- int (*config_led) (struct qlcnic_adapter *, u32, u32);
- int (*start_firmware) (struct qlcnic_adapter *);
-};
-
#define QLCDB(adapter, lvl, _fmt, _args...) do { \
if (NETIF_MSG_##lvl & adapter->ahw->msg_enable) \
printk(KERN_INFO "%s: %s: " _fmt, \
@@ -1493,6 +1829,7 @@ struct qlcnic_nic_template {
__func__, ##_args); \
} while (0)
+#define PCI_DEVICE_ID_QLOGIC_QLE834X 0x8030
#define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020
static inline bool qlcnic_82xx_check(struct qlcnic_adapter *adapter)
{
@@ -1500,4 +1837,11 @@ static inline bool qlcnic_82xx_check(struct qlcnic_adapter *adapter)
return (device == PCI_DEVICE_ID_QLOGIC_QLE824X) ? true : false;
}
+static inline bool qlcnic_83xx_check(struct qlcnic_adapter *adapter)
+{
+ unsigned short device = adapter->pdev->device;
+ return (device == PCI_DEVICE_ID_QLOGIC_QLE834X) ? true : false;
+}
+
+
#endif /* __QLCNIC_H_ */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
new file mode 100644
index 000000000000..cd5ae8813cb3
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -0,0 +1,3011 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#include "qlcnic.h"
+#include <linux/if_vlan.h>
+#include <linux/ipv6.h>
+#include <linux/ethtool.h>
+#include <linux/interrupt.h>
+
+#define QLCNIC_MAX_TX_QUEUES 1
+#define RSS_HASHTYPE_IP_TCP 0x3
+
+/* status descriptor mailbox data
+ * @phy_addr: physical address of buffer
+ * @sds_ring_size: buffer size
+ * @intrpt_id: interrupt id
+ * @intrpt_val: source of interrupt
+ */
+struct qlcnic_sds_mbx {
+ u64 phy_addr;
+ u8 rsvd1[16];
+ u16 sds_ring_size;
+ u16 rsvd2[3];
+ u16 intrpt_id;
+ u8 intrpt_val;
+ u8 rsvd3[5];
+} __packed;
+
+/* receive descriptor buffer data
+ * phy_addr_reg: physical address of regular buffer
+ * phy_addr_jmb: physical address of jumbo buffer
+ * reg_ring_sz: size of regular buffer
+ * reg_ring_len: no. of entries in regular buffer
+ * jmb_ring_len: no. of entries in jumbo buffer
+ * jmb_ring_sz: size of jumbo buffer
+ */
+struct qlcnic_rds_mbx {
+ u64 phy_addr_reg;
+ u64 phy_addr_jmb;
+ u16 reg_ring_sz;
+ u16 reg_ring_len;
+ u16 jmb_ring_sz;
+ u16 jmb_ring_len;
+} __packed;
+
+/* host producers for regular and jumbo rings */
+struct __host_producer_mbx {
+ u32 reg_buf;
+ u32 jmb_buf;
+} __packed;
+
+/* Receive context mailbox data outbox registers
+ * @state: state of the context
+ * @vport_id: virtual port id
+ * @context_id: receive context id
+ * @num_pci_func: number of pci functions of the port
+ * @phy_port: physical port id
+ */
+struct qlcnic_rcv_mbx_out {
+ u8 rcv_num;
+ u8 sts_num;
+ u16 ctx_id;
+ u8 state;
+ u8 num_pci_func;
+ u8 phy_port;
+ u8 vport_id;
+ u32 host_csmr[QLCNIC_MAX_RING_SETS];
+ struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
+} __packed;
+
+struct qlcnic_add_rings_mbx_out {
+ u8 rcv_num;
+ u8 sts_num;
+ u16 ctx_id;
+ u32 host_csmr[QLCNIC_MAX_RING_SETS];
+ struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
+} __packed;
+
+/* Transmit context mailbox inbox registers
+ * @phys_addr: DMA address of the transmit buffer
+ * @cnsmr_index: host consumer index
+ * @size: legth of transmit buffer ring
+ * @intr_id: interrput id
+ * @src: src of interrupt
+ */
+struct qlcnic_tx_mbx {
+ u64 phys_addr;
+ u64 cnsmr_index;
+ u16 size;
+ u16 intr_id;
+ u8 src;
+ u8 rsvd[3];
+} __packed;
+
+/* Transmit context mailbox outbox registers
+ * @host_prod: host producer index
+ * @ctx_id: transmit context id
+ * @state: state of the transmit context
+ */
+struct qlcnic_tx_mbx_out {
+ u32 host_prod;
+ u16 ctx_id;
+ u8 state;
+ u8 rsvd;
+} __packed;
+
+static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
+ {QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1},
+ {QLCNIC_CMD_CONFIG_INTRPT, 18, 34},
+ {QLCNIC_CMD_CREATE_RX_CTX, 136, 27},
+ {QLCNIC_CMD_DESTROY_RX_CTX, 2, 1},
+ {QLCNIC_CMD_CREATE_TX_CTX, 54, 18},
+ {QLCNIC_CMD_DESTROY_TX_CTX, 2, 1},
+ {QLCNIC_CMD_CONFIGURE_MAC_LEARNING, 2, 1},
+ {QLCNIC_CMD_INTRPT_TEST, 22, 12},
+ {QLCNIC_CMD_SET_MTU, 3, 1},
+ {QLCNIC_CMD_READ_PHY, 4, 2},
+ {QLCNIC_CMD_WRITE_PHY, 5, 1},
+ {QLCNIC_CMD_READ_HW_REG, 4, 1},
+ {QLCNIC_CMD_GET_FLOW_CTL, 4, 2},
+ {QLCNIC_CMD_SET_FLOW_CTL, 4, 1},
+ {QLCNIC_CMD_READ_MAX_MTU, 4, 2},
+ {QLCNIC_CMD_READ_MAX_LRO, 4, 2},
+ {QLCNIC_CMD_MAC_ADDRESS, 4, 3},
+ {QLCNIC_CMD_GET_PCI_INFO, 1, 66},
+ {QLCNIC_CMD_GET_NIC_INFO, 2, 19},
+ {QLCNIC_CMD_SET_NIC_INFO, 32, 1},
+ {QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3},
+ {QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1},
+ {QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3},
+ {QLCNIC_CMD_SET_PORTMIRRORING, 4, 1},
+ {QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1},
+ {QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3},
+ {QLCNIC_CMD_GET_ESWITCH_STATS, 5, 1},
+ {QLCNIC_CMD_CONFIG_PORT, 4, 1},
+ {QLCNIC_CMD_TEMP_SIZE, 1, 4},
+ {QLCNIC_CMD_GET_TEMP_HDR, 5, 5},
+ {QLCNIC_CMD_GET_LINK_EVENT, 2, 1},
+ {QLCNIC_CMD_CONFIG_MAC_VLAN, 4, 3},
+ {QLCNIC_CMD_CONFIG_INTR_COAL, 6, 1},
+ {QLCNIC_CMD_CONFIGURE_RSS, 14, 1},
+ {QLCNIC_CMD_CONFIGURE_LED, 2, 1},
+ {QLCNIC_CMD_CONFIGURE_MAC_RX_MODE, 2, 1},
+ {QLCNIC_CMD_CONFIGURE_HW_LRO, 2, 1},
+ {QLCNIC_CMD_GET_STATISTICS, 2, 80},
+ {QLCNIC_CMD_SET_PORT_CONFIG, 2, 1},
+ {QLCNIC_CMD_GET_PORT_CONFIG, 2, 2},
+ {QLCNIC_CMD_GET_LINK_STATUS, 2, 4},
+ {QLCNIC_CMD_IDC_ACK, 5, 1},
+ {QLCNIC_CMD_INIT_NIC_FUNC, 2, 1},
+ {QLCNIC_CMD_STOP_NIC_FUNC, 2, 1},
+ {QLCNIC_CMD_SET_LED_CONFIG, 5, 1},
+ {QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
+ {QLCNIC_CMD_ADD_RCV_RINGS, 130, 26},
+};
+
+static const u32 qlcnic_83xx_ext_reg_tbl[] = {
+ 0x38CC, /* Global Reset */
+ 0x38F0, /* Wildcard */
+ 0x38FC, /* Informant */
+ 0x3038, /* Host MBX ctrl */
+ 0x303C, /* FW MBX ctrl */
+ 0x355C, /* BOOT LOADER ADDRESS REG */
+ 0x3560, /* BOOT LOADER SIZE REG */
+ 0x3564, /* FW IMAGE ADDR REG */
+ 0x1000, /* MBX intr enable */
+ 0x1200, /* Default Intr mask */
+ 0x1204, /* Default Interrupt ID */
+ 0x3780, /* QLC_83XX_IDC_MAJ_VERSION */
+ 0x3784, /* QLC_83XX_IDC_DEV_STATE */
+ 0x3788, /* QLC_83XX_IDC_DRV_PRESENCE */
+ 0x378C, /* QLC_83XX_IDC_DRV_ACK */
+ 0x3790, /* QLC_83XX_IDC_CTRL */
+ 0x3794, /* QLC_83XX_IDC_DRV_AUDIT */
+ 0x3798, /* QLC_83XX_IDC_MIN_VERSION */
+ 0x379C, /* QLC_83XX_RECOVER_DRV_LOCK */
+ 0x37A0, /* QLC_83XX_IDC_PF_0 */
+ 0x37A4, /* QLC_83XX_IDC_PF_1 */
+ 0x37A8, /* QLC_83XX_IDC_PF_2 */
+ 0x37AC, /* QLC_83XX_IDC_PF_3 */
+ 0x37B0, /* QLC_83XX_IDC_PF_4 */
+ 0x37B4, /* QLC_83XX_IDC_PF_5 */
+ 0x37B8, /* QLC_83XX_IDC_PF_6 */
+ 0x37BC, /* QLC_83XX_IDC_PF_7 */
+ 0x37C0, /* QLC_83XX_IDC_PF_8 */
+ 0x37C4, /* QLC_83XX_IDC_PF_9 */
+ 0x37C8, /* QLC_83XX_IDC_PF_10 */
+ 0x37CC, /* QLC_83XX_IDC_PF_11 */
+ 0x37D0, /* QLC_83XX_IDC_PF_12 */
+ 0x37D4, /* QLC_83XX_IDC_PF_13 */
+ 0x37D8, /* QLC_83XX_IDC_PF_14 */
+ 0x37DC, /* QLC_83XX_IDC_PF_15 */
+ 0x37E0, /* QLC_83XX_IDC_DEV_PARTITION_INFO_1 */
+ 0x37E4, /* QLC_83XX_IDC_DEV_PARTITION_INFO_2 */
+ 0x37F0, /* QLC_83XX_DRV_OP_MODE */
+ 0x37F4, /* QLC_83XX_VNIC_STATE */
+ 0x3868, /* QLC_83XX_DRV_LOCK */
+ 0x386C, /* QLC_83XX_DRV_UNLOCK */
+ 0x3504, /* QLC_83XX_DRV_LOCK_ID */
+ 0x34A4, /* QLC_83XX_ASIC_TEMP */
+};
+
+static const u32 qlcnic_83xx_reg_tbl[] = {
+ 0x34A8, /* PEG_HALT_STAT1 */
+ 0x34AC, /* PEG_HALT_STAT2 */
+ 0x34B0, /* FW_HEARTBEAT */
+ 0x3500, /* FLASH LOCK_ID */
+ 0x3528, /* FW_CAPABILITIES */
+ 0x3538, /* Driver active, DRV_REG0 */
+ 0x3540, /* Device state, DRV_REG1 */
+ 0x3544, /* Driver state, DRV_REG2 */
+ 0x3548, /* Driver scratch, DRV_REG3 */
+ 0x354C, /* Device partiton info, DRV_REG4 */
+ 0x3524, /* Driver IDC ver, DRV_REG5 */
+ 0x3550, /* FW_VER_MAJOR */
+ 0x3554, /* FW_VER_MINOR */
+ 0x3558, /* FW_VER_SUB */
+ 0x359C, /* NPAR STATE */
+ 0x35FC, /* FW_IMG_VALID */
+ 0x3650, /* CMD_PEG_STATE */
+ 0x373C, /* RCV_PEG_STATE */
+ 0x37B4, /* ASIC TEMP */
+ 0x356C, /* FW API */
+ 0x3570, /* DRV OP MODE */
+ 0x3850, /* FLASH LOCK */
+ 0x3854, /* FLASH UNLOCK */
+};
+
+static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
+ .read_crb = qlcnic_83xx_read_crb,
+ .write_crb = qlcnic_83xx_write_crb,
+ .read_reg = qlcnic_83xx_rd_reg_indirect,
+ .write_reg = qlcnic_83xx_wrt_reg_indirect,
+ .get_mac_address = qlcnic_83xx_get_mac_address,
+ .setup_intr = qlcnic_83xx_setup_intr,
+ .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args,
+ .mbx_cmd = qlcnic_83xx_mbx_op,
+ .get_func_no = qlcnic_83xx_get_func_no,
+ .api_lock = qlcnic_83xx_cam_lock,
+ .api_unlock = qlcnic_83xx_cam_unlock,
+ .add_sysfs = qlcnic_83xx_add_sysfs,
+ .remove_sysfs = qlcnic_83xx_remove_sysfs,
+ .process_lb_rcv_ring_diag = qlcnic_83xx_process_rcv_ring_diag,
+ .create_rx_ctx = qlcnic_83xx_create_rx_ctx,
+ .create_tx_ctx = qlcnic_83xx_create_tx_ctx,
+ .setup_link_event = qlcnic_83xx_setup_link_event,
+ .get_nic_info = qlcnic_83xx_get_nic_info,
+ .get_pci_info = qlcnic_83xx_get_pci_info,
+ .set_nic_info = qlcnic_83xx_set_nic_info,
+ .change_macvlan = qlcnic_83xx_sre_macaddr_change,
+ .napi_enable = qlcnic_83xx_napi_enable,
+ .napi_disable = qlcnic_83xx_napi_disable,
+ .config_intr_coal = qlcnic_83xx_config_intr_coal,
+ .config_rss = qlcnic_83xx_config_rss,
+ .config_hw_lro = qlcnic_83xx_config_hw_lro,
+ .config_promisc_mode = qlcnic_83xx_nic_set_promisc,
+ .change_l2_filter = qlcnic_83xx_change_l2_filter,
+ .get_board_info = qlcnic_83xx_get_port_info,
+};
+
+static struct qlcnic_nic_template qlcnic_83xx_ops = {
+ .config_bridged_mode = qlcnic_config_bridged_mode,
+ .config_led = qlcnic_config_led,
+ .request_reset = qlcnic_83xx_idc_request_reset,
+ .cancel_idc_work = qlcnic_83xx_idc_exit,
+ .napi_add = qlcnic_83xx_napi_add,
+ .napi_del = qlcnic_83xx_napi_del,
+ .config_ipaddr = qlcnic_83xx_config_ipaddr,
+ .clear_legacy_intr = qlcnic_83xx_clear_legacy_intr,
+};
+
+void qlcnic_83xx_register_map(struct qlcnic_hardware_context *ahw)
+{
+ ahw->hw_ops = &qlcnic_83xx_hw_ops;
+ ahw->reg_tbl = (u32 *)qlcnic_83xx_reg_tbl;
+ ahw->ext_reg_tbl = (u32 *)qlcnic_83xx_ext_reg_tbl;
+}
+
+int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *adapter)
+{
+ u32 fw_major, fw_minor, fw_build;
+ struct pci_dev *pdev = adapter->pdev;
+
+ fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+ fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+ fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
+ adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
+
+ dev_info(&pdev->dev, "Driver v%s, firmware version %d.%d.%d\n",
+ QLCNIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build);
+
+ return adapter->fw_version;
+}
+
+static int __qlcnic_set_win_base(struct qlcnic_adapter *adapter, u32 addr)
+{
+ void __iomem *base;
+ u32 val;
+
+ base = adapter->ahw->pci_base0 +
+ QLC_83XX_CRB_WIN_FUNC(adapter->ahw->pci_func);
+ writel(addr, base);
+ val = readl(base);
+ if (val != addr)
+ return -EIO;
+
+ return 0;
+}
+
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr)
+{
+ int ret;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ ret = __qlcnic_set_win_base(adapter, (u32) addr);
+ if (!ret) {
+ return QLCRDX(ahw, QLCNIC_WILDCARD);
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "%s failed, addr = 0x%x\n", __func__, (int)addr);
+ return -EIO;
+ }
+}
+
+int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,
+ u32 data)
+{
+ int err;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ err = __qlcnic_set_win_base(adapter, (u32) addr);
+ if (!err) {
+ QLCWRX(ahw, QLCNIC_WILDCARD, data);
+ return 0;
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "%s failed, addr = 0x%x data = 0x%x\n",
+ __func__, (int)addr, data);
+ return err;
+ }
+}
+
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+{
+ int err, i, num_msix;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (!num_intr)
+ num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS;
+ num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
+ num_intr));
+ /* account for AEN interrupt MSI-X based interrupts */
+ num_msix += 1;
+ num_msix += adapter->max_drv_tx_rings;
+ err = qlcnic_enable_msix(adapter, num_msix);
+ if (err == -ENOMEM)
+ return err;
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ num_msix = adapter->ahw->num_msix;
+ else
+ num_msix = 1;
+ /* setup interrupt mapping table for fw */
+ ahw->intr_tbl = vzalloc(num_msix *
+ sizeof(struct qlcnic_intrpt_config));
+ if (!ahw->intr_tbl)
+ return -ENOMEM;
+ if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ /* MSI-X enablement failed, use legacy interrupt */
+ adapter->tgt_status_reg = ahw->pci_base0 + QLC_83XX_INTX_PTR;
+ adapter->tgt_mask_reg = ahw->pci_base0 + QLC_83XX_INTX_MASK;
+ adapter->isr_int_vec = ahw->pci_base0 + QLC_83XX_INTX_TRGR;
+ adapter->msix_entries[0].vector = adapter->pdev->irq;
+ dev_info(&adapter->pdev->dev, "using legacy interrupt\n");
+ }
+
+ for (i = 0; i < num_msix; i++) {
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ ahw->intr_tbl[i].type = QLCNIC_INTRPT_MSIX;
+ else
+ ahw->intr_tbl[i].type = QLCNIC_INTRPT_INTX;
+ ahw->intr_tbl[i].id = i;
+ ahw->intr_tbl[i].src = 0;
+ }
+ return 0;
+}
+
+inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter)
+{
+ writel(0, adapter->tgt_mask_reg);
+}
+
+/* Enable MSI-x and INT-x interrupts */
+void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_sds_ring *sds_ring)
+{
+ writel(0, sds_ring->crb_intr_mask);
+}
+
+/* Disable MSI-x and INT-x interrupts */
+void qlcnic_83xx_disable_intr(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_sds_ring *sds_ring)
+{
+ writel(1, sds_ring->crb_intr_mask);
+}
+
+inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter
+ *adapter)
+{
+ u32 mask;
+
+ /* Mailbox in MSI-x mode and Legacy Interrupt share the same
+ * source register. We could be here before contexts are created
+ * and sds_ring->crb_intr_mask has not been initialized, calculate
+ * BAR offset for Interrupt Source Register
+ */
+ mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+ writel(0, adapter->ahw->pci_base0 + mask);
+}
+
+inline void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *adapter)
+{
+ u32 mask;
+
+ mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+ writel(1, adapter->ahw->pci_base0 + mask);
+}
+
+static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd)
+{
+ int i;
+ for (i = 0; i < cmd->rsp.num; i++)
+ cmd->rsp.arg[i] = readl(QLCNIC_MBX_FW(adapter->ahw, i));
+}
+
+irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
+{
+ u32 intr_val;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int retries = 0;
+
+ intr_val = readl(adapter->tgt_status_reg);
+
+ if (!QLC_83XX_VALID_INTX_BIT31(intr_val))
+ return IRQ_NONE;
+
+ if (QLC_83XX_INTX_FUNC(intr_val) != adapter->ahw->pci_func) {
+ adapter->stats.spurious_intr++;
+ return IRQ_NONE;
+ }
+ /* The barrier is required to ensure writes to the registers */
+ wmb();
+
+ /* clear the interrupt trigger control register */
+ writel(0, adapter->isr_int_vec);
+ intr_val = readl(adapter->isr_int_vec);
+ do {
+ intr_val = readl(adapter->tgt_status_reg);
+ if (QLC_83XX_INTX_FUNC(intr_val) != ahw->pci_func)
+ break;
+ retries++;
+ } while (QLC_83XX_VALID_INTX_BIT30(intr_val) &&
+ (retries < QLC_83XX_LEGACY_INTX_MAX_RETRY));
+
+ return IRQ_HANDLED;
+}
+
+static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
+{
+ u32 resp, event;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+
+ resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
+ if (!(resp & QLCNIC_SET_OWNER))
+ goto out;
+
+ event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
+ if (event & QLCNIC_MBX_ASYNC_EVENT)
+ qlcnic_83xx_process_aen(adapter);
+out:
+ qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+ spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+}
+
+irqreturn_t qlcnic_83xx_intr(int irq, void *data)
+{
+ struct qlcnic_adapter *adapter = data;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (qlcnic_83xx_clear_legacy_intr(adapter) == IRQ_NONE)
+ return IRQ_NONE;
+
+ qlcnic_83xx_poll_process_aen(adapter);
+
+ if (ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+ ahw->diag_cnt++;
+ qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+ return IRQ_HANDLED;
+ }
+
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+ qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+ } else {
+ sds_ring = &adapter->recv_ctx->sds_rings[0];
+ napi_schedule(&sds_ring->napi);
+ }
+
+ return IRQ_HANDLED;
+}
+
+irqreturn_t qlcnic_83xx_tmp_intr(int irq, void *data)
+{
+ struct qlcnic_host_sds_ring *sds_ring = data;
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ goto done;
+
+ if (adapter->nic_ops->clear_legacy_intr(adapter) == IRQ_NONE)
+ return IRQ_NONE;
+
+done:
+ adapter->ahw->diag_cnt++;
+ qlcnic_83xx_enable_intr(adapter, sds_ring);
+
+ return IRQ_HANDLED;
+}
+
+void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)
+{
+ u32 val = 0, num_msix = adapter->ahw->num_msix - 1;
+
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ num_msix = adapter->ahw->num_msix - 1;
+ else
+ num_msix = 0;
+
+ QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
+
+ qlcnic_83xx_disable_mbx_intr(adapter);
+
+ msleep(20);
+ synchronize_irq(adapter->msix_entries[num_msix].vector);
+ free_irq(adapter->msix_entries[num_msix].vector, adapter);
+}
+
+int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
+{
+ irq_handler_t handler;
+ u32 val;
+ char name[32];
+ int err = 0;
+ unsigned long flags = 0;
+
+ if (!(adapter->flags & QLCNIC_MSI_ENABLED) &&
+ !(adapter->flags & QLCNIC_MSIX_ENABLED))
+ flags |= IRQF_SHARED;
+
+ if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ handler = qlcnic_83xx_handle_aen;
+ val = adapter->msix_entries[adapter->ahw->num_msix - 1].vector;
+ snprintf(name, (IFNAMSIZ + 4),
+ "%s[%s]", "qlcnic", "aen");
+ err = request_irq(val, handler, flags, name, adapter);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "failed to register MBX interrupt\n");
+ return err;
+ }
+ } else {
+ handler = qlcnic_83xx_intr;
+ val = adapter->msix_entries[0].vector;
+ err = request_irq(val, handler, flags, "qlcnic", adapter);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "failed to register INTx interrupt\n");
+ return err;
+ }
+ qlcnic_83xx_clear_legacy_intr_mask(adapter);
+ }
+
+ /* Enable mailbox interrupt */
+ qlcnic_83xx_enable_mbx_intrpt(adapter);
+
+ return err;
+}
+
+void qlcnic_83xx_get_func_no(struct qlcnic_adapter *adapter)
+{
+ u32 val = QLCRDX(adapter->ahw, QLCNIC_INFORMANT);
+ adapter->ahw->pci_func = val & 0xf;
+}
+
+int qlcnic_83xx_cam_lock(struct qlcnic_adapter *adapter)
+{
+ void __iomem *addr;
+ u32 val, limit = 0;
+
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ addr = ahw->pci_base0 + QLC_83XX_SEM_LOCK_FUNC(ahw->pci_func);
+ do {
+ val = readl(addr);
+ if (val) {
+ /* write the function number to register */
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER,
+ ahw->pci_func);
+ return 0;
+ }
+ usleep_range(1000, 2000);
+ } while (++limit <= QLCNIC_PCIE_SEM_TIMEOUT);
+
+ return -EIO;
+}
+
+void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *adapter)
+{
+ void __iomem *addr;
+ u32 val;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ addr = ahw->pci_base0 + QLC_83XX_SEM_UNLOCK_FUNC(ahw->pci_func);
+ val = readl(addr);
+}
+
+void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
+ loff_t offset, size_t size)
+{
+ int ret;
+ u32 data;
+
+ if (qlcnic_api_lock(adapter)) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed to acquire lock. addr offset 0x%x\n",
+ __func__, (u32)offset);
+ return;
+ }
+
+ ret = qlcnic_83xx_rd_reg_indirect(adapter, (u32) offset);
+ qlcnic_api_unlock(adapter);
+
+ if (ret == -EIO) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed. addr offset 0x%x\n",
+ __func__, (u32)offset);
+ return;
+ }
+ data = ret;
+ memcpy(buf, &data, size);
+}
+
+void qlcnic_83xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
+ loff_t offset, size_t size)
+{
+ u32 data;
+
+ memcpy(&data, buf, size);
+ qlcnic_83xx_wrt_reg_indirect(adapter, (u32) offset, data);
+}
+
+int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
+{
+ int status;
+
+ status = qlcnic_83xx_get_port_config(adapter);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "Get Port Info failed\n");
+ } else {
+ if (QLC_83XX_SFP_10G_CAPABLE(adapter->ahw->port_config))
+ adapter->ahw->port_type = QLCNIC_XGBE;
+ else
+ adapter->ahw->port_type = QLCNIC_GBE;
+
+ if (QLC_83XX_AUTONEG(adapter->ahw->port_config))
+ adapter->ahw->link_autoneg = AUTONEG_ENABLE;
+ }
+ return status;
+}
+
+void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ val = BIT_2 | ((adapter->ahw->num_msix - 1) << 8);
+ else
+ val = BIT_2;
+
+ QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
+ qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+}
+
+void qlcnic_83xx_check_vf(struct qlcnic_adapter *adapter,
+ const struct pci_device_id *ent)
+{
+ u32 op_mode, priv_level;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ ahw->fw_hal_version = 2;
+ qlcnic_get_func_no(adapter);
+
+ /* Determine function privilege level */
+ op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+ if (op_mode == QLC_83XX_DEFAULT_OPMODE)
+ priv_level = QLCNIC_MGMT_FUNC;
+ else
+ priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
+ ahw->pci_func);
+
+ if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+ ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d Non Privileged function\n",
+ ahw->fw_hal_version);
+ adapter->nic_ops = &qlcnic_vf_ops;
+ } else {
+ adapter->nic_ops = &qlcnic_83xx_ops;
+ }
+}
+
+static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
+ u32 data[]);
+static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,
+ u32 data[]);
+
+static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd)
+{
+ int i;
+
+ dev_info(&adapter->pdev->dev,
+ "Host MBX regs(%d)\n", cmd->req.num);
+ for (i = 0; i < cmd->req.num; i++) {
+ if (i && !(i % 8))
+ pr_info("\n");
+ pr_info("%08x ", cmd->req.arg[i]);
+ }
+ pr_info("\n");
+ dev_info(&adapter->pdev->dev,
+ "FW MBX regs(%d)\n", cmd->rsp.num);
+ for (i = 0; i < cmd->rsp.num; i++) {
+ if (i && !(i % 8))
+ pr_info("\n");
+ pr_info("%08x ", cmd->rsp.arg[i]);
+ }
+ pr_info("\n");
+}
+
+/* Mailbox response for mac rcode */
+static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
+{
+ u32 fw_data;
+ u8 mac_cmd_rcode;
+
+ fw_data = readl(QLCNIC_MBX_FW(adapter->ahw, 2));
+ mac_cmd_rcode = (u8)fw_data;
+ if (mac_cmd_rcode == QLC_83XX_NO_NIC_RESOURCE ||
+ mac_cmd_rcode == QLC_83XX_MAC_PRESENT ||
+ mac_cmd_rcode == QLC_83XX_MAC_ABSENT)
+ return QLCNIC_RCODE_SUCCESS;
+ return 1;
+}
+
+static u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter)
+{
+ u32 data;
+ unsigned long wait_time = 0;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ /* wait for mailbox completion */
+ do {
+ data = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
+ if (++wait_time > QLCNIC_MBX_TIMEOUT) {
+ data = QLCNIC_RCODE_TIMEOUT;
+ break;
+ }
+ mdelay(1);
+ } while (!data);
+ return data;
+}
+
+int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd)
+{
+ int i;
+ u16 opcode;
+ u8 mbx_err_code;
+ unsigned long flags;
+ u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ opcode = LSW(cmd->req.arg[0]);
+ if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
+ dev_info(&adapter->pdev->dev,
+ "Mailbox cmd attempted, 0x%x\n", opcode);
+ dev_info(&adapter->pdev->dev, "Mailbox detached\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+ mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+
+ if (mbx_val) {
+ QLCDB(adapter, DRV,
+ "Mailbox cmd attempted, 0x%x\n", opcode);
+ QLCDB(adapter, DRV,
+ "Mailbox not available, 0x%x, collect FW dump\n",
+ mbx_val);
+ cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
+ spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+ return cmd->rsp.arg[0];
+ }
+
+ /* Fill in mailbox registers */
+ mbx_cmd = cmd->req.arg[0];
+ writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
+ for (i = 1; i < cmd->req.num; i++)
+ writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i));
+
+ /* Signal FW about the impending command */
+ QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
+poll:
+ rsp = qlcnic_83xx_mbx_poll(adapter);
+ if (rsp != QLCNIC_RCODE_TIMEOUT) {
+ /* Get the FW response data */
+ fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
+ if (fw_data & QLCNIC_MBX_ASYNC_EVENT) {
+ qlcnic_83xx_process_aen(adapter);
+ mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+ if (mbx_val)
+ goto poll;
+ }
+ mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
+ rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
+ opcode = QLCNIC_MBX_RSP(fw_data);
+ qlcnic_83xx_get_mbx_data(adapter, cmd);
+
+ switch (mbx_err_code) {
+ case QLCNIC_MBX_RSP_OK:
+ case QLCNIC_MBX_PORT_RSP_OK:
+ rsp = QLCNIC_RCODE_SUCCESS;
+ break;
+ default:
+ if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) {
+ rsp = qlcnic_83xx_mac_rcode(adapter);
+ if (!rsp)
+ goto out;
+ }
+ dev_err(&adapter->pdev->dev,
+ "MBX command 0x%x failed with err:0x%x\n",
+ opcode, mbx_err_code);
+ rsp = mbx_err_code;
+ qlcnic_dump_mbx(adapter, cmd);
+ break;
+ }
+ goto out;
+ }
+
+ dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n",
+ QLCNIC_MBX_RSP(mbx_cmd));
+ rsp = QLCNIC_RCODE_TIMEOUT;
+out:
+ /* clear fw mbx control register */
+ QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+ spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+ return rsp;
+}
+
+int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+ struct qlcnic_adapter *adapter, u32 type)
+{
+ int i, size;
+ u32 temp;
+ const struct qlcnic_mailbox_metadata *mbx_tbl;
+
+ mbx_tbl = qlcnic_83xx_mbx_tbl;
+ size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl);
+ for (i = 0; i < size; i++) {
+ if (type == mbx_tbl[i].cmd) {
+ mbx->req.num = mbx_tbl[i].in_args;
+ mbx->rsp.num = mbx_tbl[i].out_args;
+ mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),
+ GFP_ATOMIC);
+ if (!mbx->req.arg)
+ return -ENOMEM;
+ mbx->rsp.arg = kcalloc(mbx->rsp.num, sizeof(u32),
+ GFP_ATOMIC);
+ if (!mbx->rsp.arg) {
+ kfree(mbx->req.arg);
+ mbx->req.arg = NULL;
+ return -ENOMEM;
+ }
+ memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
+ memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
+ temp = adapter->ahw->fw_hal_version << 29;
+ mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp);
+ break;
+ }
+ }
+ return 0;
+}
+
+void qlcnic_83xx_idc_aen_work(struct work_struct *work)
+{
+ struct qlcnic_adapter *adapter;
+ struct qlcnic_cmd_args cmd;
+ int i, err = 0;
+
+ adapter = container_of(work, struct qlcnic_adapter, idc_aen_work.work);
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_IDC_ACK);
+
+ for (i = 1; i < QLC_83XX_MBX_AEN_CNT; i++)
+ cmd.req.arg[i] = adapter->ahw->mbox_aen[i];
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_info(&adapter->pdev->dev,
+ "%s: Mailbox IDC ACK failed.\n", __func__);
+ qlcnic_free_mbx_args(&cmd);
+}
+
+static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,
+ u32 data[])
+{
+ dev_dbg(&adapter->pdev->dev, "Completion AEN:0x%x.\n",
+ QLCNIC_MBX_RSP(data[0]));
+ clear_bit(QLC_83XX_IDC_COMP_AEN, &adapter->ahw->idc.status);
+ return;
+}
+
+void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
+{
+ u32 event[QLC_83XX_MBX_AEN_CNT];
+ int i;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++)
+ event[i] = readl(QLCNIC_MBX_FW(ahw, i));
+
+ switch (QLCNIC_MBX_RSP(event[0])) {
+
+ case QLCNIC_MBX_LINK_EVENT:
+ qlcnic_83xx_handle_link_aen(adapter, event);
+ break;
+ case QLCNIC_MBX_COMP_EVENT:
+ qlcnic_83xx_handle_idc_comp_aen(adapter, event);
+ break;
+ case QLCNIC_MBX_REQUEST_EVENT:
+ for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++)
+ adapter->ahw->mbox_aen[i] = QLCNIC_MBX_RSP(event[i]);
+ queue_delayed_work(adapter->qlcnic_wq,
+ &adapter->idc_aen_work, 0);
+ break;
+ case QLCNIC_MBX_TIME_EXTEND_EVENT:
+ break;
+ case QLCNIC_MBX_SFP_INSERT_EVENT:
+ dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n",
+ QLCNIC_MBX_RSP(event[0]));
+ break;
+ case QLCNIC_MBX_SFP_REMOVE_EVENT:
+ dev_info(&adapter->pdev->dev, "SFP Removed AEN:0x%x.\n",
+ QLCNIC_MBX_RSP(event[0]));
+ break;
+ default:
+ dev_dbg(&adapter->pdev->dev, "Unsupported AEN:0x%x.\n",
+ QLCNIC_MBX_RSP(event[0]));
+ break;
+ }
+
+ QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+}
+
+static int qlcnic_83xx_add_rings(struct qlcnic_adapter *adapter)
+{
+ int index, i, err, sds_mbx_size;
+ u32 *buf, intrpt_id, intr_mask;
+ u16 context_id;
+ u8 num_sds;
+ struct qlcnic_cmd_args cmd;
+ struct qlcnic_host_sds_ring *sds;
+ struct qlcnic_sds_mbx sds_mbx;
+ struct qlcnic_add_rings_mbx_out *mbx_out;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ sds_mbx_size = sizeof(struct qlcnic_sds_mbx);
+ context_id = recv_ctx->context_id;
+ num_sds = (adapter->max_sds_rings - QLCNIC_MAX_RING_SETS);
+ ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_ADD_RCV_RINGS);
+ cmd.req.arg[1] = 0 | (num_sds << 8) | (context_id << 16);
+
+ /* set up status rings, mbx 2-81 */
+ index = 2;
+ for (i = 8; i < adapter->max_sds_rings; i++) {
+ memset(&sds_mbx, 0, sds_mbx_size);
+ sds = &recv_ctx->sds_rings[i];
+ sds->consumer = 0;
+ memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));
+ sds_mbx.phy_addr = sds->phys_addr;
+ sds_mbx.sds_ring_size = sds->num_desc;
+
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ intrpt_id = ahw->intr_tbl[i].id;
+ else
+ intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+
+ if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+ sds_mbx.intrpt_id = intrpt_id;
+ else
+ sds_mbx.intrpt_id = 0xffff;
+ sds_mbx.intrpt_val = 0;
+ buf = &cmd.req.arg[index];
+ memcpy(buf, &sds_mbx, sds_mbx_size);
+ index += sds_mbx_size / sizeof(u32);
+ }
+
+ /* send the mailbox command */
+ err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to add rings %d\n", err);
+ goto out;
+ }
+
+ mbx_out = (struct qlcnic_add_rings_mbx_out *)&cmd.rsp.arg[1];
+ index = 0;
+ /* status descriptor ring */
+ for (i = 8; i < adapter->max_sds_rings; i++) {
+ sds = &recv_ctx->sds_rings[i];
+ sds->crb_sts_consumer = ahw->pci_base0 +
+ mbx_out->host_csmr[index];
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ intr_mask = ahw->intr_tbl[i].src;
+ else
+ intr_mask = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);
+
+ sds->crb_intr_mask = ahw->pci_base0 + intr_mask;
+ index++;
+ }
+out:
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)
+{
+ int i, err, index, sds_mbx_size, rds_mbx_size;
+ u8 num_sds, num_rds;
+ u32 *buf, intrpt_id, intr_mask, cap = 0;
+ struct qlcnic_host_sds_ring *sds;
+ struct qlcnic_host_rds_ring *rds;
+ struct qlcnic_sds_mbx sds_mbx;
+ struct qlcnic_rds_mbx rds_mbx;
+ struct qlcnic_cmd_args cmd;
+ struct qlcnic_rcv_mbx_out *mbx_out;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ num_rds = adapter->max_rds_rings;
+
+ if (adapter->max_sds_rings <= QLCNIC_MAX_RING_SETS)
+ num_sds = adapter->max_sds_rings;
+ else
+ num_sds = QLCNIC_MAX_RING_SETS;
+
+ sds_mbx_size = sizeof(struct qlcnic_sds_mbx);
+ rds_mbx_size = sizeof(struct qlcnic_rds_mbx);
+ cap = QLCNIC_CAP0_LEGACY_CONTEXT;
+
+ if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+ cap |= QLC_83XX_FW_CAP_LRO_MSS;
+
+ /* set mailbox hdr and capabilities */
+ qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_CREATE_RX_CTX);
+ cmd.req.arg[1] = cap;
+ cmd.req.arg[5] = 1 | (num_rds << 5) | (num_sds << 8) |
+ (QLC_83XX_HOST_RDS_MODE_UNIQUE << 16);
+ /* set up status rings, mbx 8-57/87 */
+ index = QLC_83XX_HOST_SDS_MBX_IDX;
+ for (i = 0; i < num_sds; i++) {
+ memset(&sds_mbx, 0, sds_mbx_size);
+ sds = &recv_ctx->sds_rings[i];
+ sds->consumer = 0;
+ memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));
+ sds_mbx.phy_addr = sds->phys_addr;
+ sds_mbx.sds_ring_size = sds->num_desc;
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ intrpt_id = ahw->intr_tbl[i].id;
+ else
+ intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+ if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+ sds_mbx.intrpt_id = intrpt_id;
+ else
+ sds_mbx.intrpt_id = 0xffff;
+ sds_mbx.intrpt_val = 0;
+ buf = &cmd.req.arg[index];
+ memcpy(buf, &sds_mbx, sds_mbx_size);
+ index += sds_mbx_size / sizeof(u32);
+ }
+ /* set up receive rings, mbx 88-111/135 */
+ index = QLCNIC_HOST_RDS_MBX_IDX;
+ rds = &recv_ctx->rds_rings[0];
+ rds->producer = 0;
+ memset(&rds_mbx, 0, rds_mbx_size);
+ rds_mbx.phy_addr_reg = rds->phys_addr;
+ rds_mbx.reg_ring_sz = rds->dma_size;
+ rds_mbx.reg_ring_len = rds->num_desc;
+ /* Jumbo ring */
+ rds = &recv_ctx->rds_rings[1];
+ rds->producer = 0;
+ rds_mbx.phy_addr_jmb = rds->phys_addr;
+ rds_mbx.jmb_ring_sz = rds->dma_size;
+ rds_mbx.jmb_ring_len = rds->num_desc;
+ buf = &cmd.req.arg[index];
+ memcpy(buf, &rds_mbx, rds_mbx_size);
+
+ /* send the mailbox command */
+ err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to create Rx ctx in firmware%d\n", err);
+ goto out;
+ }
+ mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd.rsp.arg[1];
+ recv_ctx->context_id = mbx_out->ctx_id;
+ recv_ctx->state = mbx_out->state;
+ recv_ctx->virt_port = mbx_out->vport_id;
+ dev_info(&adapter->pdev->dev, "Rx Context[%d] Created, state:0x%x\n",
+ recv_ctx->context_id, recv_ctx->state);
+ /* Receive descriptor ring */
+ /* Standard ring */
+ rds = &recv_ctx->rds_rings[0];
+ rds->crb_rcv_producer = ahw->pci_base0 +
+ mbx_out->host_prod[0].reg_buf;
+ /* Jumbo ring */
+ rds = &recv_ctx->rds_rings[1];
+ rds->crb_rcv_producer = ahw->pci_base0 +
+ mbx_out->host_prod[0].jmb_buf;
+ /* status descriptor ring */
+ for (i = 0; i < num_sds; i++) {
+ sds = &recv_ctx->sds_rings[i];
+ sds->crb_sts_consumer = ahw->pci_base0 +
+ mbx_out->host_csmr[i];
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ intr_mask = ahw->intr_tbl[i].src;
+ else
+ intr_mask = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);
+ sds->crb_intr_mask = ahw->pci_base0 + intr_mask;
+ }
+
+ if (adapter->max_sds_rings > QLCNIC_MAX_RING_SETS)
+ err = qlcnic_83xx_add_rings(adapter);
+out:
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx, int ring)
+{
+ int err;
+ u16 msix_id;
+ u32 *buf, intr_mask;
+ struct qlcnic_cmd_args cmd;
+ struct qlcnic_tx_mbx mbx;
+ struct qlcnic_tx_mbx_out *mbx_out;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ /* Reset host resources */
+ tx->producer = 0;
+ tx->sw_consumer = 0;
+ *(tx->hw_consumer) = 0;
+
+ memset(&mbx, 0, sizeof(struct qlcnic_tx_mbx));
+
+ /* setup mailbox inbox registerss */
+ mbx.phys_addr = tx->phys_addr;
+ mbx.cnsmr_index = tx->hw_cons_phys_addr;
+ mbx.size = tx->num_desc;
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ msix_id = ahw->intr_tbl[adapter->max_sds_rings + ring].id;
+ else
+ msix_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+ if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+ mbx.intr_id = msix_id;
+ else
+ mbx.intr_id = 0xffff;
+ mbx.src = 0;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+ cmd.req.arg[1] = QLCNIC_CAP0_LEGACY_CONTEXT;
+ cmd.req.arg[5] = QLCNIC_MAX_TX_QUEUES;
+ buf = &cmd.req.arg[6];
+ memcpy(buf, &mbx, sizeof(struct qlcnic_tx_mbx));
+ /* send the mailbox command*/
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to create Tx ctx in firmware 0x%x\n", err);
+ goto out;
+ }
+ mbx_out = (struct qlcnic_tx_mbx_out *)&cmd.rsp.arg[2];
+ tx->crb_cmd_producer = ahw->pci_base0 + mbx_out->host_prod;
+ tx->ctx_id = mbx_out->ctx_id;
+ if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ intr_mask = ahw->intr_tbl[adapter->max_sds_rings + ring].src;
+ tx->crb_intr_mask = ahw->pci_base0 + intr_mask;
+ }
+ dev_info(&adapter->pdev->dev, "Tx Context[0x%x] Created, state:0x%x\n",
+ tx->ctx_id, mbx_out->state);
+out:
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_rds_ring *rds_ring;
+ u8 ring;
+ int ret;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ __qlcnic_down(adapter, netdev);
+
+ qlcnic_detach(adapter);
+
+ adapter->max_sds_rings = 1;
+ adapter->ahw->diag_test = test;
+ adapter->ahw->linkup = 0;
+
+ ret = qlcnic_attach(adapter);
+ if (ret) {
+ netif_device_attach(netdev);
+ return ret;
+ }
+
+ ret = qlcnic_fw_create_ctx(adapter);
+ if (ret) {
+ qlcnic_detach(adapter);
+ netif_device_attach(netdev);
+ return ret;
+ }
+
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &adapter->recv_ctx->rds_rings[ring];
+ qlcnic_post_rx_buffers(adapter, rds_ring, ring);
+ }
+
+ if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &adapter->recv_ctx->sds_rings[ring];
+ qlcnic_83xx_enable_intr(adapter, sds_ring);
+ }
+ }
+
+ if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
+ /* disable and free mailbox interrupt */
+ qlcnic_83xx_free_mbx_intr(adapter);
+ adapter->ahw->loopback_state = 0;
+ adapter->ahw->hw_ops->setup_link_event(adapter, 1);
+ }
+
+ set_bit(__QLCNIC_DEV_UP, &adapter->state);
+ return 0;
+}
+
+static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
+ int max_sds_rings)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_host_sds_ring *sds_ring;
+ int ring, err;
+
+ clear_bit(__QLCNIC_DEV_UP, &adapter->state);
+ if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &adapter->recv_ctx->sds_rings[ring];
+ qlcnic_83xx_disable_intr(adapter, sds_ring);
+ }
+ }
+
+ qlcnic_fw_destroy_ctx(adapter);
+ qlcnic_detach(adapter);
+
+ if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
+ err = qlcnic_83xx_setup_mbx_intr(adapter);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed to setup mbx interrupt\n",
+ __func__);
+ goto out;
+ }
+ }
+ adapter->ahw->diag_test = 0;
+ adapter->max_sds_rings = max_sds_rings;
+
+ if (qlcnic_attach(adapter))
+ goto out;
+
+ if (netif_running(netdev))
+ __qlcnic_up(adapter, netdev);
+out:
+ netif_device_attach(netdev);
+}
+
+int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state,
+ u32 beacon)
+{
+ struct qlcnic_cmd_args cmd;
+ u32 mbx_in;
+ int i, status = 0;
+
+ if (state) {
+ /* Get LED configuration */
+ qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_GET_LED_CONFIG);
+ status = qlcnic_issue_cmd(adapter, &cmd);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "Get led config failed.\n");
+ goto mbx_err;
+ } else {
+ for (i = 0; i < 4; i++)
+ adapter->ahw->mbox_reg[i] = cmd.rsp.arg[i+1];
+ }
+ qlcnic_free_mbx_args(&cmd);
+ /* Set LED Configuration */
+ mbx_in = (LSW(QLC_83XX_LED_CONFIG) << 16) |
+ LSW(QLC_83XX_LED_CONFIG);
+ qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_SET_LED_CONFIG);
+ cmd.req.arg[1] = mbx_in;
+ cmd.req.arg[2] = mbx_in;
+ cmd.req.arg[3] = mbx_in;
+ if (beacon)
+ cmd.req.arg[4] = QLC_83XX_ENABLE_BEACON;
+ status = qlcnic_issue_cmd(adapter, &cmd);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "Set led config failed.\n");
+ }
+mbx_err:
+ qlcnic_free_mbx_args(&cmd);
+ return status;
+
+ } else {
+ /* Restoring default LED configuration */
+ qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_SET_LED_CONFIG);
+ cmd.req.arg[1] = adapter->ahw->mbox_reg[0];
+ cmd.req.arg[2] = adapter->ahw->mbox_reg[1];
+ cmd.req.arg[3] = adapter->ahw->mbox_reg[2];
+ if (beacon)
+ cmd.req.arg[4] = adapter->ahw->mbox_reg[3];
+ status = qlcnic_issue_cmd(adapter, &cmd);
+ if (status)
+ dev_err(&adapter->pdev->dev,
+ "Restoring led config failed.\n");
+ qlcnic_free_mbx_args(&cmd);
+ return status;
+ }
+}
+
+void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter,
+ int enable)
+{
+ struct qlcnic_cmd_args cmd;
+ int status;
+
+ if (enable) {
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INIT_NIC_FUNC);
+ cmd.req.arg[1] = BIT_0 | BIT_31;
+ } else {
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_STOP_NIC_FUNC);
+ cmd.req.arg[1] = BIT_0 | BIT_31;
+ }
+ status = qlcnic_issue_cmd(adapter, &cmd);
+ if (status)
+ dev_err(&adapter->pdev->dev,
+ "Failed to %s in NIC IDC function event.\n",
+ (enable ? "register" : "unregister"));
+
+ qlcnic_free_mbx_args(&cmd);
+}
+
+int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_cmd_args cmd;
+ int err;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORT_CONFIG);
+ cmd.req.arg[1] = adapter->ahw->port_config;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_info(&adapter->pdev->dev, "Set Port Config failed.\n");
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+int qlcnic_83xx_get_port_config(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_cmd_args cmd;
+ int err;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PORT_CONFIG);
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_info(&adapter->pdev->dev, "Get Port config failed\n");
+ else
+ adapter->ahw->port_config = cmd.rsp.arg[1];
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *adapter, int enable)
+{
+ int err;
+ u32 temp;
+ struct qlcnic_cmd_args cmd;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_EVENT);
+ temp = adapter->recv_ctx->context_id << 16;
+ cmd.req.arg[1] = (enable ? 1 : 0) | BIT_8 | temp;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_info(&adapter->pdev->dev,
+ "Setup linkevent mailbox failed\n");
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
+{
+ int err;
+ u32 temp;
+ struct qlcnic_cmd_args cmd;
+
+ if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+ return -EIO;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_MAC_RX_MODE);
+ temp = adapter->recv_ctx->context_id << 16;
+ cmd.req.arg[1] = (mode ? 1 : 0) | temp;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_info(&adapter->pdev->dev,
+ "Promiscous mode config failed\n");
+ qlcnic_free_mbx_args(&cmd);
+
+ return err;
+}
+
+int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int ret = 0, loop = 0, max_sds_rings = adapter->max_sds_rings;
+
+ QLCDB(adapter, DRV, "%s loopback test in progress\n",
+ mode == QLCNIC_ILB_MODE ? "internal" : "external");
+ if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+ dev_warn(&adapter->pdev->dev,
+ "Loopback test not supported for non privilege function\n");
+ return ret;
+ }
+
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EBUSY;
+
+ ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
+ if (ret)
+ goto fail_diag_alloc;
+
+ ret = qlcnic_83xx_set_lb_mode(adapter, mode);
+ if (ret)
+ goto free_diag_res;
+
+ /* Poll for link up event before running traffic */
+ do {
+ msleep(500);
+ qlcnic_83xx_process_aen(adapter);
+ if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+ dev_info(&adapter->pdev->dev,
+ "Firmware didn't sent link up event to loopback request\n");
+ ret = -QLCNIC_FW_NOT_RESPOND;
+ qlcnic_83xx_clear_lb_mode(adapter, mode);
+ goto free_diag_res;
+ }
+ } while ((adapter->ahw->linkup && ahw->has_link_events) != 1);
+
+ ret = qlcnic_do_lb_test(adapter, mode);
+
+ qlcnic_83xx_clear_lb_mode(adapter, mode);
+
+free_diag_res:
+ qlcnic_83xx_diag_free_res(netdev, max_sds_rings);
+
+fail_diag_alloc:
+ adapter->max_sds_rings = max_sds_rings;
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return ret;
+}
+
+int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int status = 0, loop = 0;
+ u32 config;
+
+ status = qlcnic_83xx_get_port_config(adapter);
+ if (status)
+ return status;
+
+ config = ahw->port_config;
+ set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+
+ if (mode == QLCNIC_ILB_MODE)
+ ahw->port_config |= QLC_83XX_CFG_LOOPBACK_HSS;
+ if (mode == QLCNIC_ELB_MODE)
+ ahw->port_config |= QLC_83XX_CFG_LOOPBACK_EXT;
+
+ status = qlcnic_83xx_set_port_config(adapter);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to Set Loopback Mode = 0x%x.\n",
+ ahw->port_config);
+ ahw->port_config = config;
+ clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+ return status;
+ }
+
+ /* Wait for Link and IDC Completion AEN */
+ do {
+ msleep(300);
+ qlcnic_83xx_process_aen(adapter);
+ if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+ dev_err(&adapter->pdev->dev,
+ "FW did not generate IDC completion AEN\n");
+ clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+ qlcnic_83xx_clear_lb_mode(adapter, mode);
+ return -EIO;
+ }
+ } while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));
+
+ qlcnic_sre_macaddr_change(adapter, adapter->mac_addr, 0,
+ QLCNIC_MAC_ADD);
+ return status;
+}
+
+int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int status = 0, loop = 0;
+ u32 config = ahw->port_config;
+
+ set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+ if (mode == QLCNIC_ILB_MODE)
+ ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_HSS;
+ if (mode == QLCNIC_ELB_MODE)
+ ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_EXT;
+
+ status = qlcnic_83xx_set_port_config(adapter);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to Clear Loopback Mode = 0x%x.\n",
+ ahw->port_config);
+ ahw->port_config = config;
+ clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+ return status;
+ }
+
+ /* Wait for Link and IDC Completion AEN */
+ do {
+ msleep(300);
+ qlcnic_83xx_process_aen(adapter);
+ if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+ dev_err(&adapter->pdev->dev,
+ "Firmware didn't sent IDC completion AEN\n");
+ clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+ return -EIO;
+ }
+ } while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));
+
+ qlcnic_sre_macaddr_change(adapter, adapter->mac_addr, 0,
+ QLCNIC_MAC_DEL);
+ return status;
+}
+
+void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip,
+ int mode)
+{
+ int err;
+ u32 temp, temp_ip;
+ struct qlcnic_cmd_args cmd;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_IP_ADDR);
+ if (mode == QLCNIC_IP_UP) {
+ temp = adapter->recv_ctx->context_id << 16;
+ cmd.req.arg[1] = 1 | temp;
+ } else {
+ temp = adapter->recv_ctx->context_id << 16;
+ cmd.req.arg[1] = 2 | temp;
+ }
+
+ /*
+ * Adapter needs IP address in network byte order.
+ * But hardware mailbox registers go through writel(), hence IP address
+ * gets swapped on big endian architecture.
+ * To negate swapping of writel() on big endian architecture
+ * use swab32(value).
+ */
+
+ temp_ip = swab32(ntohl(ip));
+ memcpy(&cmd.req.arg[2], &temp_ip, sizeof(u32));
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err != QLCNIC_RCODE_SUCCESS)
+ dev_err(&adapter->netdev->dev,
+ "could not notify %s IP 0x%x request\n",
+ (mode == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
+ qlcnic_free_mbx_args(&cmd);
+}
+
+int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *adapter, int mode)
+{
+ int err;
+ u32 temp, arg1;
+ struct qlcnic_cmd_args cmd;
+ int lro_bit_mask;
+
+ lro_bit_mask = (mode ? (BIT_0 | BIT_1 | BIT_2 | BIT_3) : 0);
+
+ if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+ return 0;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_HW_LRO);
+ temp = adapter->recv_ctx->context_id << 16;
+ arg1 = lro_bit_mask | temp;
+ cmd.req.arg[1] = arg1;
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_info(&adapter->pdev->dev, "LRO config failed\n");
+ qlcnic_free_mbx_args(&cmd);
+
+ return err;
+}
+
+int qlcnic_83xx_config_rss(struct qlcnic_adapter *adapter, int enable)
+{
+ int err;
+ u32 word;
+ struct qlcnic_cmd_args cmd;
+ const u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
+ 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
+ 0x255b0ec26d5a56daULL };
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_RSS);
+
+ /*
+ * RSS request:
+ * bits 3-0: Rsvd
+ * 5-4: hash_type_ipv4
+ * 7-6: hash_type_ipv6
+ * 8: enable
+ * 9: use indirection table
+ * 16-31: indirection table mask
+ */
+ word = ((u32)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
+ ((u32)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
+ ((u32)(enable & 0x1) << 8) |
+ ((0x7ULL) << 16);
+ cmd.req.arg[1] = (adapter->recv_ctx->context_id);
+ cmd.req.arg[2] = word;
+ memcpy(&cmd.req.arg[4], key, sizeof(key));
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+
+ if (err)
+ dev_info(&adapter->pdev->dev, "RSS config failed\n");
+ qlcnic_free_mbx_args(&cmd);
+
+ return err;
+
+}
+
+int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
+ __le16 vlan_id, u8 op)
+{
+ int err;
+ u32 *buf;
+ struct qlcnic_cmd_args cmd;
+ struct qlcnic_macvlan_mbx mv;
+
+ if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+ return -EIO;
+
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN);
+ if (err)
+ return err;
+ cmd.req.arg[1] = op | (1 << 8) |
+ (adapter->recv_ctx->context_id << 16);
+
+ mv.vlan = le16_to_cpu(vlan_id);
+ memcpy(&mv.mac, addr, ETH_ALEN);
+ buf = &cmd.req.arg[2];
+ memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx));
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_err(&adapter->pdev->dev,
+ "MAC-VLAN %s to CAM failed, err=%d.\n",
+ ((op == 1) ? "add " : "delete "), err);
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,
+ __le16 vlan_id)
+{
+ u8 mac[ETH_ALEN];
+ memcpy(&mac, addr, ETH_ALEN);
+ qlcnic_83xx_sre_macaddr_change(adapter, mac, vlan_id, QLCNIC_MAC_ADD);
+}
+
+void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac,
+ u8 type, struct qlcnic_cmd_args *cmd)
+{
+ switch (type) {
+ case QLCNIC_SET_STATION_MAC:
+ case QLCNIC_SET_FAC_DEF_MAC:
+ memcpy(&cmd->req.arg[2], mac, sizeof(u32));
+ memcpy(&cmd->req.arg[3], &mac[4], sizeof(u16));
+ break;
+ }
+ cmd->req.arg[1] = type;
+}
+
+int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+{
+ int err, i;
+ struct qlcnic_cmd_args cmd;
+ u32 mac_low, mac_high;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
+ qlcnic_83xx_configure_mac(adapter, mac, QLCNIC_GET_CURRENT_MAC, &cmd);
+ err = qlcnic_issue_cmd(adapter, &cmd);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ mac_low = cmd.rsp.arg[1];
+ mac_high = cmd.rsp.arg[2];
+
+ for (i = 0; i < 2; i++)
+ mac[i] = (u8) (mac_high >> ((1 - i) * 8));
+ for (i = 2; i < 6; i++)
+ mac[i] = (u8) (mac_low >> ((5 - i) * 8));
+ } else {
+ dev_err(&adapter->pdev->dev, "Failed to get mac address%d\n",
+ err);
+ err = -EIO;
+ }
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter)
+{
+ int err;
+ u32 temp;
+ struct qlcnic_cmd_args cmd;
+ struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;
+
+ if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+ return;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL);
+ cmd.req.arg[1] = 1 | (adapter->recv_ctx->context_id << 16);
+ cmd.req.arg[3] = coal->flag;
+ temp = coal->rx_time_us << 16;
+ cmd.req.arg[2] = coal->rx_packets | temp;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err != QLCNIC_RCODE_SUCCESS)
+ dev_info(&adapter->pdev->dev,
+ "Failed to send interrupt coalescence parameters\n");
+ qlcnic_free_mbx_args(&cmd);
+}
+
+static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
+ u32 data[])
+{
+ u8 link_status, duplex;
+ /* link speed */
+ link_status = LSB(data[3]) & 1;
+ adapter->ahw->link_speed = MSW(data[2]);
+ adapter->ahw->link_autoneg = MSB(MSW(data[3]));
+ adapter->ahw->module_type = MSB(LSW(data[3]));
+ duplex = LSB(MSW(data[3]));
+ if (duplex)
+ adapter->ahw->link_duplex = DUPLEX_FULL;
+ else
+ adapter->ahw->link_duplex = DUPLEX_HALF;
+ adapter->ahw->has_link_events = 1;
+ qlcnic_advert_link_change(adapter, link_status);
+}
+
+irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
+{
+ struct qlcnic_adapter *adapter = data;
+ unsigned long flags;
+ u32 mask, resp, event;
+
+ spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+ resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
+ if (!(resp & QLCNIC_SET_OWNER))
+ goto out;
+
+ event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
+ if (event & QLCNIC_MBX_ASYNC_EVENT)
+ qlcnic_83xx_process_aen(adapter);
+out:
+ mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+ writel(0, adapter->ahw->pci_base0 + mask);
+ spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+int qlcnic_enable_eswitch(struct qlcnic_adapter *adapter, u8 port, u8 enable)
+{
+ int err = -EIO;
+ struct qlcnic_cmd_args cmd;
+
+ if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
+ dev_err(&adapter->pdev->dev,
+ "%s: Error, invoked by non management func\n",
+ __func__);
+ return err;
+ }
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TOGGLE_ESWITCH);
+ cmd.req.arg[1] = (port & 0xf) | BIT_4;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev, "Failed to enable eswitch%d\n",
+ err);
+ err = -EIO;
+ }
+ qlcnic_free_mbx_args(&cmd);
+
+ return err;
+
+}
+
+int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *nic)
+{
+ int i, err = -EIO;
+ struct qlcnic_cmd_args cmd;
+
+ if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
+ dev_err(&adapter->pdev->dev,
+ "%s: Error, invoked by non management func\n",
+ __func__);
+ return err;
+ }
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+ cmd.req.arg[1] = (nic->pci_func << 16);
+ cmd.req.arg[2] = 0x1 << 16;
+ cmd.req.arg[3] = nic->phys_port | (nic->switch_mode << 16);
+ cmd.req.arg[4] = nic->capabilities;
+ cmd.req.arg[5] = (nic->max_mac_filters & 0xFF) | ((nic->max_mtu) << 16);
+ cmd.req.arg[6] = (nic->max_tx_ques) | ((nic->max_rx_ques) << 16);
+ cmd.req.arg[7] = (nic->min_tx_bw) | ((nic->max_tx_bw) << 16);
+ for (i = 8; i < 32; i++)
+ cmd.req.arg[i] = 0;
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev, "Failed to set nic info%d\n",
+ err);
+ err = -EIO;
+ }
+
+ qlcnic_free_mbx_args(&cmd);
+
+ return err;
+}
+
+int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *npar_info, u8 func_id)
+{
+ int err;
+ u32 temp;
+ u8 op = 0;
+ struct qlcnic_cmd_args cmd;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+ if (func_id != adapter->ahw->pci_func) {
+ temp = func_id << 16;
+ cmd.req.arg[1] = op | BIT_31 | temp;
+ } else {
+ cmd.req.arg[1] = adapter->ahw->pci_func << 16;
+ }
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err) {
+ dev_info(&adapter->pdev->dev,
+ "Failed to get nic info %d\n", err);
+ goto out;
+ }
+
+ npar_info->op_type = cmd.rsp.arg[1];
+ npar_info->pci_func = cmd.rsp.arg[2] & 0xFFFF;
+ npar_info->op_mode = (cmd.rsp.arg[2] & 0xFFFF0000) >> 16;
+ npar_info->phys_port = cmd.rsp.arg[3] & 0xFFFF;
+ npar_info->switch_mode = (cmd.rsp.arg[3] & 0xFFFF0000) >> 16;
+ npar_info->capabilities = cmd.rsp.arg[4];
+ npar_info->max_mac_filters = cmd.rsp.arg[5] & 0xFF;
+ npar_info->max_mtu = (cmd.rsp.arg[5] & 0xFFFF0000) >> 16;
+ npar_info->max_tx_ques = cmd.rsp.arg[6] & 0xFFFF;
+ npar_info->max_rx_ques = (cmd.rsp.arg[6] & 0xFFFF0000) >> 16;
+ npar_info->min_tx_bw = cmd.rsp.arg[7] & 0xFFFF;
+ npar_info->max_tx_bw = (cmd.rsp.arg[7] & 0xFFFF0000) >> 16;
+ if (cmd.rsp.arg[8] & 0x1)
+ npar_info->max_bw_reg_offset = (cmd.rsp.arg[8] & 0x7FFE) >> 1;
+ if (cmd.rsp.arg[8] & 0x10000) {
+ temp = (cmd.rsp.arg[8] & 0x7FFE0000) >> 17;
+ npar_info->max_linkspeed_reg_offset = temp;
+ }
+
+out:
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_pci_info *pci_info)
+{
+ int i, err = 0, j = 0;
+ u32 temp;
+ struct qlcnic_cmd_args cmd;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
+ err = qlcnic_issue_cmd(adapter, &cmd);
+
+ adapter->ahw->act_pci_func = 0;
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ pci_info->func_count = cmd.rsp.arg[1] & 0xFF;
+ dev_info(&adapter->pdev->dev,
+ "%s: total functions = %d\n",
+ __func__, pci_info->func_count);
+ for (i = 2, j = 0; j < QLCNIC_MAX_PCI_FUNC; j++, pci_info++) {
+ pci_info->id = cmd.rsp.arg[i] & 0xFFFF;
+ pci_info->active = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+ i++;
+ pci_info->type = cmd.rsp.arg[i] & 0xFFFF;
+ if (pci_info->type == QLCNIC_TYPE_NIC)
+ adapter->ahw->act_pci_func++;
+ temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+ pci_info->default_port = temp;
+ i++;
+ pci_info->tx_min_bw = cmd.rsp.arg[i] & 0xFFFF;
+ temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+ pci_info->tx_max_bw = temp;
+ i = i + 2;
+ memcpy(pci_info->mac, &cmd.rsp.arg[i], ETH_ALEN - 2);
+ i++;
+ memcpy(pci_info->mac + sizeof(u32), &cmd.rsp.arg[i], 2);
+ i = i + 3;
+
+ dev_info(&adapter->pdev->dev, "%s:\n"
+ "\tid = %d active = %d type = %d\n"
+ "\tport = %d min bw = %d max bw = %d\n"
+ "\tmac_addr = %pM\n", __func__,
+ pci_info->id, pci_info->active, pci_info->type,
+ pci_info->default_port, pci_info->tx_min_bw,
+ pci_info->tx_max_bw, pci_info->mac);
+ }
+ } else {
+ dev_err(&adapter->pdev->dev, "Failed to get PCI Info%d\n",
+ err);
+ err = -EIO;
+ }
+
+ qlcnic_free_mbx_args(&cmd);
+
+ return err;
+}
+
+int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *adapter, bool op_type)
+{
+ int i, index, err;
+ bool type;
+ u8 max_ints;
+ u32 val, temp;
+ struct qlcnic_cmd_args cmd;
+
+ max_ints = adapter->ahw->num_msix - 1;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTRPT);
+ cmd.req.arg[1] = max_ints;
+ for (i = 0, index = 2; i < max_ints; i++) {
+ type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL;
+ val = type | (adapter->ahw->intr_tbl[i].type << 4);
+ if (adapter->ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX)
+ val |= (adapter->ahw->intr_tbl[i].id << 16);
+ cmd.req.arg[index++] = val;
+ }
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to configure interrupts 0x%x\n", err);
+ goto out;
+ }
+
+ max_ints = cmd.rsp.arg[1];
+ for (i = 0, index = 2; i < max_ints; i++, index += 2) {
+ val = cmd.rsp.arg[index];
+ if (LSB(val)) {
+ dev_info(&adapter->pdev->dev,
+ "Can't configure interrupt %d\n",
+ adapter->ahw->intr_tbl[i].id);
+ continue;
+ }
+ if (op_type) {
+ adapter->ahw->intr_tbl[i].id = MSW(val);
+ adapter->ahw->intr_tbl[i].enabled = 1;
+ temp = cmd.rsp.arg[index + 1];
+ adapter->ahw->intr_tbl[i].src = temp;
+ } else {
+ adapter->ahw->intr_tbl[i].id = i;
+ adapter->ahw->intr_tbl[i].enabled = 0;
+ adapter->ahw->intr_tbl[i].src = 0;
+ }
+ }
+out:
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+int qlcnic_83xx_lock_flash(struct qlcnic_adapter *adapter)
+{
+ int id, timeout = 0;
+ u32 status = 0;
+
+ while (status == 0) {
+ status = QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_LOCK);
+ if (status)
+ break;
+
+ if (++timeout >= QLC_83XX_FLASH_LOCK_TIMEOUT) {
+ id = QLC_SHARED_REG_RD32(adapter,
+ QLCNIC_FLASH_LOCK_OWNER);
+ dev_err(&adapter->pdev->dev,
+ "%s: failed, lock held by %d\n", __func__, id);
+ return -EIO;
+ }
+ usleep_range(1000, 2000);
+ }
+
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER, adapter->portnum);
+ return 0;
+}
+
+void qlcnic_83xx_unlock_flash(struct qlcnic_adapter *adapter)
+{
+ QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_UNLOCK);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER, 0xFF);
+}
+
+int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
+ u32 flash_addr, u8 *p_data,
+ int count)
+{
+ int i, ret;
+ u32 word, range, flash_offset, addr = flash_addr;
+ ulong indirect_add, direct_window;
+
+ flash_offset = addr & (QLCNIC_FLASH_SECTOR_SIZE - 1);
+ if (addr & 0x3) {
+ dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);
+ return -EIO;
+ }
+
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_DIRECT_WINDOW,
+ (addr));
+
+ range = flash_offset + (count * sizeof(u32));
+ /* Check if data is spread across multiple sectors */
+ if (range > (QLCNIC_FLASH_SECTOR_SIZE - 1)) {
+
+ /* Multi sector read */
+ for (i = 0; i < count; i++) {
+ indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
+ ret = qlcnic_83xx_rd_reg_indirect(adapter,
+ indirect_add);
+ if (ret == -EIO)
+ return -EIO;
+
+ word = ret;
+ *(u32 *)p_data = word;
+ p_data = p_data + 4;
+ addr = addr + 4;
+ flash_offset = flash_offset + 4;
+
+ if (flash_offset > (QLCNIC_FLASH_SECTOR_SIZE - 1)) {
+ direct_window = QLC_83XX_FLASH_DIRECT_WINDOW;
+ /* This write is needed once for each sector */
+ qlcnic_83xx_wrt_reg_indirect(adapter,
+ direct_window,
+ (addr));
+ flash_offset = 0;
+ }
+ }
+ } else {
+ /* Single sector read */
+ for (i = 0; i < count; i++) {
+ indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
+ ret = qlcnic_83xx_rd_reg_indirect(adapter,
+ indirect_add);
+ if (ret == -EIO)
+ return -EIO;
+
+ word = ret;
+ *(u32 *)p_data = word;
+ p_data = p_data + 4;
+ addr = addr + 4;
+ }
+ }
+
+ return 0;
+}
+
+static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
+{
+ u32 status;
+ int retries = QLC_83XX_FLASH_READ_RETRY_COUNT;
+
+ do {
+ status = qlcnic_83xx_rd_reg_indirect(adapter,
+ QLC_83XX_FLASH_STATUS);
+ if ((status & QLC_83XX_FLASH_STATUS_READY) ==
+ QLC_83XX_FLASH_STATUS_READY)
+ break;
+
+ msleep(QLC_83XX_FLASH_STATUS_REG_POLL_DELAY);
+ } while (--retries);
+
+ if (!retries)
+ return -EIO;
+
+ return 0;
+}
+
+static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter)
+{
+ int ret;
+ u32 cmd;
+ cmd = adapter->ahw->fdt.write_statusreg_cmd;
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+ (QLC_83XX_FLASH_FDT_WRITE_DEF_SIG | cmd));
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+ adapter->ahw->fdt.write_enable_bits);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+ QLC_83XX_FLASH_SECOND_ERASE_MS_VAL);
+ ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+ if (ret)
+ return -EIO;
+
+ return 0;
+}
+
+static int qlcnic_83xx_disable_flash_write_op(struct qlcnic_adapter *adapter)
+{
+ int ret;
+
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+ (QLC_83XX_FLASH_FDT_WRITE_DEF_SIG |
+ adapter->ahw->fdt.write_statusreg_cmd));
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+ adapter->ahw->fdt.write_disable_bits);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+ QLC_83XX_FLASH_SECOND_ERASE_MS_VAL);
+ ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+ if (ret)
+ return -EIO;
+
+ return 0;
+}
+
+int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)
+{
+ int ret, mfg_id;
+
+ if (qlcnic_83xx_lock_flash(adapter))
+ return -EIO;
+
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+ QLC_83XX_FLASH_FDT_READ_MFG_ID_VAL);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+ QLC_83XX_FLASH_READ_CTRL);
+ ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+ if (ret) {
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+
+ mfg_id = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
+ if (mfg_id == -EIO)
+ return -EIO;
+
+ adapter->flash_mfg_id = (mfg_id & 0xFF);
+ qlcnic_83xx_unlock_flash(adapter);
+
+ return 0;
+}
+
+int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *adapter)
+{
+ int count, fdt_size, ret = 0;
+
+ fdt_size = sizeof(struct qlcnic_fdt);
+ count = fdt_size / sizeof(u32);
+
+ if (qlcnic_83xx_lock_flash(adapter))
+ return -EIO;
+
+ memset(&adapter->ahw->fdt, 0, fdt_size);
+ ret = qlcnic_83xx_lockless_flash_read32(adapter, QLCNIC_FDT_LOCATION,
+ (u8 *)&adapter->ahw->fdt,
+ count);
+
+ qlcnic_83xx_unlock_flash(adapter);
+ return ret;
+}
+
+int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
+ u32 sector_start_addr)
+{
+ u32 reversed_addr, addr1, addr2, cmd;
+ int ret = -EIO;
+
+ if (qlcnic_83xx_lock_flash(adapter) != 0)
+ return -EIO;
+
+ if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+ ret = qlcnic_83xx_enable_flash_write_op(adapter);
+ if (ret) {
+ qlcnic_83xx_unlock_flash(adapter);
+ dev_err(&adapter->pdev->dev,
+ "%s failed at %d\n",
+ __func__, __LINE__);
+ return ret;
+ }
+ }
+
+ ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+ if (ret) {
+ qlcnic_83xx_unlock_flash(adapter);
+ dev_err(&adapter->pdev->dev,
+ "%s: failed at %d\n", __func__, __LINE__);
+ return -EIO;
+ }
+
+ addr1 = (sector_start_addr & 0xFF) << 16;
+ addr2 = (sector_start_addr & 0xFF0000) >> 16;
+ reversed_addr = addr1 | addr2;
+
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+ reversed_addr);
+ cmd = QLC_83XX_FLASH_FDT_ERASE_DEF_SIG | adapter->ahw->fdt.erase_cmd;
+ if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id)
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, cmd);
+ else
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+ QLC_83XX_FLASH_OEM_ERASE_SIG);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+ QLC_83XX_FLASH_LAST_ERASE_MS_VAL);
+
+ ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+ if (ret) {
+ qlcnic_83xx_unlock_flash(adapter);
+ dev_err(&adapter->pdev->dev,
+ "%s: failed at %d\n", __func__, __LINE__);
+ return -EIO;
+ }
+
+ if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+ ret = qlcnic_83xx_disable_flash_write_op(adapter);
+ if (ret) {
+ qlcnic_83xx_unlock_flash(adapter);
+ dev_err(&adapter->pdev->dev,
+ "%s: failed at %d\n", __func__, __LINE__);
+ return ret;
+ }
+ }
+
+ qlcnic_83xx_unlock_flash(adapter);
+
+ return 0;
+}
+
+int qlcnic_83xx_flash_write32(struct qlcnic_adapter *adapter, u32 addr,
+ u32 *p_data)
+{
+ int ret = -EIO;
+ u32 addr1 = 0x00800000 | (addr >> 2);
+
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, addr1);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+ QLC_83XX_FLASH_LAST_ERASE_MS_VAL);
+ ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed at %d\n", __func__, __LINE__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
+ u32 *p_data, int count)
+{
+ u32 temp;
+ int ret = -EIO;
+
+ if ((count < QLC_83XX_FLASH_BULK_WRITE_MIN) ||
+ (count > QLC_83XX_FLASH_BULK_WRITE_MAX)) {
+ dev_err(&adapter->pdev->dev,
+ "%s: Invalid word count\n", __func__);
+ return -EIO;
+ }
+
+ temp = qlcnic_83xx_rd_reg_indirect(adapter,
+ QLC_83XX_FLASH_SPI_CONTROL);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL,
+ (temp | QLC_83XX_FLASH_SPI_CTRL));
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+ QLC_83XX_FLASH_ADDR_TEMP_VAL);
+
+ /* First DWORD write */
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data++);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+ QLC_83XX_FLASH_FIRST_MS_PATTERN);
+ ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed at %d\n", __func__, __LINE__);
+ return -EIO;
+ }
+
+ count--;
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+ QLC_83XX_FLASH_ADDR_SECOND_TEMP_VAL);
+ /* Second to N-1 DWORD writes */
+ while (count != 1) {
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+ *p_data++);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+ QLC_83XX_FLASH_SECOND_MS_PATTERN);
+ ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed at %d\n", __func__, __LINE__);
+ return -EIO;
+ }
+ count--;
+ }
+
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+ QLC_83XX_FLASH_ADDR_TEMP_VAL |
+ (addr >> 2));
+ /* Last DWORD write */
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data++);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+ QLC_83XX_FLASH_LAST_MS_PATTERN);
+ ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed at %d\n", __func__, __LINE__);
+ return -EIO;
+ }
+
+ ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_SPI_STATUS);
+ if ((ret & QLC_83XX_FLASH_SPI_CTRL) == QLC_83XX_FLASH_SPI_CTRL) {
+ dev_err(&adapter->pdev->dev, "%s: failed at %d\n",
+ __func__, __LINE__);
+ /* Operation failed, clear error bit */
+ temp = qlcnic_83xx_rd_reg_indirect(adapter,
+ QLC_83XX_FLASH_SPI_CONTROL);
+ qlcnic_83xx_wrt_reg_indirect(adapter,
+ QLC_83XX_FLASH_SPI_CONTROL,
+ (temp | QLC_83XX_FLASH_SPI_CTRL));
+ }
+
+ return 0;
+}
+
+static void qlcnic_83xx_recover_driver_lock(struct qlcnic_adapter *adapter)
+{
+ u32 val, id;
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);
+
+ /* Check if recovery need to be performed by the calling function */
+ if ((val & QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK) == 0) {
+ val = val & ~0x3F;
+ val = val | ((adapter->portnum << 2) |
+ QLC_83XX_NEED_DRV_LOCK_RECOVERY);
+ QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+ dev_info(&adapter->pdev->dev,
+ "%s: lock recovery initiated\n", __func__);
+ msleep(QLC_83XX_DRV_LOCK_RECOVERY_DELAY);
+ val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);
+ id = ((val >> 2) & 0xF);
+ if (id == adapter->portnum) {
+ val = val & ~QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK;
+ val = val | QLC_83XX_DRV_LOCK_RECOVERY_IN_PROGRESS;
+ QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+ /* Force release the lock */
+ QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);
+ /* Clear recovery bits */
+ val = val & ~0x3F;
+ QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+ dev_info(&adapter->pdev->dev,
+ "%s: lock recovery completed\n", __func__);
+ } else {
+ dev_info(&adapter->pdev->dev,
+ "%s: func %d to resume lock recovery process\n",
+ __func__, id);
+ }
+ } else {
+ dev_info(&adapter->pdev->dev,
+ "%s: lock recovery initiated by other functions\n",
+ __func__);
+ }
+}
+
+int qlcnic_83xx_lock_driver(struct qlcnic_adapter *adapter)
+{
+ u32 lock_alive_counter, val, id, i = 0, status = 0, temp = 0;
+ int max_attempt = 0;
+
+ while (status == 0) {
+ status = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK);
+ if (status)
+ break;
+
+ msleep(QLC_83XX_DRV_LOCK_WAIT_DELAY);
+ i++;
+
+ if (i == 1)
+ temp = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+
+ if (i == QLC_83XX_DRV_LOCK_WAIT_COUNTER) {
+ val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+ if (val == temp) {
+ id = val & 0xFF;
+ dev_info(&adapter->pdev->dev,
+ "%s: lock to be recovered from %d\n",
+ __func__, id);
+ qlcnic_83xx_recover_driver_lock(adapter);
+ i = 0;
+ max_attempt++;
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed to get lock\n", __func__);
+ return -EIO;
+ }
+ }
+
+ /* Force exit from while loop after few attempts */
+ if (max_attempt == QLC_83XX_MAX_DRV_LOCK_RECOVERY_ATTEMPT) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed to get lock\n", __func__);
+ return -EIO;
+ }
+ }
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+ lock_alive_counter = val >> 8;
+ lock_alive_counter++;
+ val = lock_alive_counter << 8 | adapter->portnum;
+ QLCWRX(adapter->ahw, QLC_83XX_DRV_LOCK_ID, val);
+
+ return 0;
+}
+
+void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *adapter)
+{
+ u32 val, lock_alive_counter, id;
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+ id = val & 0xFF;
+ lock_alive_counter = val >> 8;
+
+ if (id != adapter->portnum)
+ dev_err(&adapter->pdev->dev,
+ "%s:Warning func %d is unlocking lock owned by %d\n",
+ __func__, adapter->portnum, id);
+
+ val = (lock_alive_counter << 8) | 0xFF;
+ QLCWRX(adapter->ahw, QLC_83XX_DRV_LOCK_ID, val);
+ QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);
+}
+
+int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
+ u32 *data, u32 count)
+{
+ int i, j, ret = 0;
+ u32 temp;
+
+ /* Check alignment */
+ if (addr & 0xF)
+ return -EIO;
+
+ mutex_lock(&adapter->ahw->mem_lock);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_ADDR_HI, 0);
+
+ for (i = 0; i < count; i++, addr += 16) {
+ if (!((ADDR_IN_RANGE(addr, QLCNIC_ADDR_QDR_NET,
+ QLCNIC_ADDR_QDR_NET_MAX)) ||
+ (ADDR_IN_RANGE(addr, QLCNIC_ADDR_DDR_NET,
+ QLCNIC_ADDR_DDR_NET_MAX)))) {
+ mutex_unlock(&adapter->ahw->mem_lock);
+ return -EIO;
+ }
+
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_ADDR_LO, addr);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_LO,
+ *data++);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_HI,
+ *data++);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_ULO,
+ *data++);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_WRTDATA_UHI,
+ *data++);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_CTRL,
+ QLCNIC_TA_WRITE_ENABLE);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_CTRL,
+ QLCNIC_TA_WRITE_START);
+
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = qlcnic_83xx_rd_reg_indirect(adapter,
+ QLCNIC_MS_CTRL);
+ if ((temp & TA_CTL_BUSY) == 0)
+ break;
+ }
+
+ /* Status check failure */
+ if (j >= MAX_CTL_CHECK) {
+ printk_ratelimited(KERN_WARNING
+ "MS memory write failed\n");
+ mutex_unlock(&adapter->ahw->mem_lock);
+ return -EIO;
+ }
+ }
+
+ mutex_unlock(&adapter->ahw->mem_lock);
+
+ return ret;
+}
+
+int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
+ u8 *p_data, int count)
+{
+ int i, ret;
+ u32 word, addr = flash_addr;
+ ulong indirect_addr;
+
+ if (qlcnic_83xx_lock_flash(adapter) != 0)
+ return -EIO;
+
+ if (addr & 0x3) {
+ dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (qlcnic_83xx_wrt_reg_indirect(adapter,
+ QLC_83XX_FLASH_DIRECT_WINDOW,
+ (addr))) {
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+
+ indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr);
+ ret = qlcnic_83xx_rd_reg_indirect(adapter,
+ indirect_addr);
+ if (ret == -EIO)
+ return -EIO;
+ word = ret;
+ *(u32 *)p_data = word;
+ p_data = p_data + 4;
+ addr = addr + 4;
+ }
+
+ qlcnic_83xx_unlock_flash(adapter);
+
+ return 0;
+}
+
+int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
+{
+ int err;
+ u32 config = 0, state;
+ struct qlcnic_cmd_args cmd;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ state = readl(ahw->pci_base0 + QLC_83XX_LINK_STATE(ahw->pci_func));
+ if (!QLC_83xx_FUNC_VAL(state, ahw->pci_func)) {
+ dev_info(&adapter->pdev->dev, "link state down\n");
+ return config;
+ }
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LINK_STATUS);
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err) {
+ dev_info(&adapter->pdev->dev,
+ "Get Link Status Command failed: 0x%x\n", err);
+ goto out;
+ } else {
+ config = cmd.rsp.arg[1];
+ switch (QLC_83XX_CURRENT_LINK_SPEED(config)) {
+ case QLC_83XX_10M_LINK:
+ ahw->link_speed = SPEED_10;
+ break;
+ case QLC_83XX_100M_LINK:
+ ahw->link_speed = SPEED_100;
+ break;
+ case QLC_83XX_1G_LINK:
+ ahw->link_speed = SPEED_1000;
+ break;
+ case QLC_83XX_10G_LINK:
+ ahw->link_speed = SPEED_10000;
+ break;
+ default:
+ ahw->link_speed = 0;
+ break;
+ }
+ config = cmd.rsp.arg[3];
+ if (config & 1)
+ err = 1;
+ }
+out:
+ qlcnic_free_mbx_args(&cmd);
+ return config;
+}
+
+int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter)
+{
+ u32 config = 0;
+ int status = 0;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ /* Get port configuration info */
+ status = qlcnic_83xx_get_port_info(adapter);
+ /* Get Link Status related info */
+ config = qlcnic_83xx_test_link(adapter);
+ ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config);
+ /* hard code until there is a way to get it from flash */
+ ahw->board_type = QLCNIC_BRDTYPE_83XX_10G;
+ return status;
+}
+
+int qlcnic_83xx_set_settings(struct qlcnic_adapter *adapter,
+ struct ethtool_cmd *ecmd)
+{
+ int status = 0;
+ u32 config = adapter->ahw->port_config;
+
+ if (ecmd->autoneg)
+ adapter->ahw->port_config |= BIT_15;
+
+ switch (ethtool_cmd_speed(ecmd)) {
+ case SPEED_10:
+ adapter->ahw->port_config |= BIT_8;
+ break;
+ case SPEED_100:
+ adapter->ahw->port_config |= BIT_9;
+ break;
+ case SPEED_1000:
+ adapter->ahw->port_config |= BIT_10;
+ break;
+ case SPEED_10000:
+ adapter->ahw->port_config |= BIT_11;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ status = qlcnic_83xx_set_port_config(adapter);
+ if (status) {
+ dev_info(&adapter->pdev->dev,
+ "Faild to Set Link Speed and autoneg.\n");
+ adapter->ahw->port_config = config;
+ }
+ return status;
+}
+
+static inline u64 *qlcnic_83xx_copy_stats(struct qlcnic_cmd_args *cmd,
+ u64 *data, int index)
+{
+ u32 low, hi;
+ u64 val;
+
+ low = cmd->rsp.arg[index];
+ hi = cmd->rsp.arg[index + 1];
+ val = (((u64) low) | (((u64) hi) << 32));
+ *data++ = val;
+ return data;
+}
+
+static u64 *qlcnic_83xx_fill_stats(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd, u64 *data,
+ int type, int *ret)
+{
+ int err, k, total_regs;
+
+ *ret = 0;
+ err = qlcnic_issue_cmd(adapter, cmd);
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_info(&adapter->pdev->dev,
+ "Error in get statistics mailbox command\n");
+ *ret = -EIO;
+ return data;
+ }
+ total_regs = cmd->rsp.num;
+ switch (type) {
+ case QLC_83XX_STAT_MAC:
+ /* fill in MAC tx counters */
+ for (k = 2; k < 28; k += 2)
+ data = qlcnic_83xx_copy_stats(cmd, data, k);
+ /* skip 24 bytes of reserved area */
+ /* fill in MAC rx counters */
+ for (k += 6; k < 60; k += 2)
+ data = qlcnic_83xx_copy_stats(cmd, data, k);
+ /* skip 24 bytes of reserved area */
+ /* fill in MAC rx frame stats */
+ for (k += 6; k < 80; k += 2)
+ data = qlcnic_83xx_copy_stats(cmd, data, k);
+ break;
+ case QLC_83XX_STAT_RX:
+ for (k = 2; k < 8; k += 2)
+ data = qlcnic_83xx_copy_stats(cmd, data, k);
+ /* skip 8 bytes of reserved data */
+ for (k += 2; k < 24; k += 2)
+ data = qlcnic_83xx_copy_stats(cmd, data, k);
+ /* skip 8 bytes containing RE1FBQ error data */
+ for (k += 2; k < total_regs; k += 2)
+ data = qlcnic_83xx_copy_stats(cmd, data, k);
+ break;
+ case QLC_83XX_STAT_TX:
+ for (k = 2; k < 10; k += 2)
+ data = qlcnic_83xx_copy_stats(cmd, data, k);
+ /* skip 8 bytes of reserved data */
+ for (k += 2; k < total_regs; k += 2)
+ data = qlcnic_83xx_copy_stats(cmd, data, k);
+ break;
+ default:
+ dev_warn(&adapter->pdev->dev, "Unknown get statistics mode\n");
+ *ret = -EIO;
+ }
+ return data;
+}
+
+void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
+{
+ struct qlcnic_cmd_args cmd;
+ int ret = 0;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_STATISTICS);
+ /* Get Tx stats */
+ cmd.req.arg[1] = BIT_1 | (adapter->tx_ring->ctx_id << 16);
+ cmd.rsp.num = QLC_83XX_TX_STAT_REGS;
+ data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+ QLC_83XX_STAT_TX, &ret);
+ if (ret) {
+ dev_info(&adapter->pdev->dev, "Error getting MAC stats\n");
+ goto out;
+ }
+ /* Get MAC stats */
+ cmd.req.arg[1] = BIT_2 | (adapter->portnum << 16);
+ cmd.rsp.num = QLC_83XX_MAC_STAT_REGS;
+ memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);
+ data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+ QLC_83XX_STAT_MAC, &ret);
+ if (ret) {
+ dev_info(&adapter->pdev->dev,
+ "Error getting Rx stats\n");
+ goto out;
+ }
+ /* Get Rx stats */
+ cmd.req.arg[1] = adapter->recv_ctx->context_id << 16;
+ cmd.rsp.num = QLC_83XX_RX_STAT_REGS;
+ memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);
+ data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+ QLC_83XX_STAT_RX, &ret);
+ if (ret)
+ dev_info(&adapter->pdev->dev,
+ "Error getting Tx stats\n");
+out:
+ qlcnic_free_mbx_args(&cmd);
+}
+
+int qlcnic_83xx_reg_test(struct qlcnic_adapter *adapter)
+{
+ u32 major, minor, sub;
+
+ major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+ minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+ sub = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
+
+ if (adapter->fw_version != QLCNIC_VERSION_CODE(major, minor, sub)) {
+ dev_info(&adapter->pdev->dev, "%s: Reg test failed\n",
+ __func__);
+ return 1;
+ }
+ return 0;
+}
+
+int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *adapter)
+{
+ return (ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl) *
+ sizeof(adapter->ahw->ext_reg_tbl)) +
+ (ARRAY_SIZE(qlcnic_83xx_reg_tbl) +
+ sizeof(adapter->ahw->reg_tbl));
+}
+
+int qlcnic_83xx_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff)
+{
+ int i, j = 0;
+
+ for (i = QLCNIC_DEV_INFO_SIZE + 1;
+ j < ARRAY_SIZE(qlcnic_83xx_reg_tbl); i++, j++)
+ regs_buff[i] = QLC_SHARED_REG_RD32(adapter, j);
+
+ for (j = 0; j < ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl); j++)
+ regs_buff[i++] = QLCRDX(adapter->ahw, j);
+ return i;
+}
+
+int qlcnic_83xx_interrupt_test(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct qlcnic_cmd_args cmd;
+ u32 data;
+ u16 intrpt_id, id;
+ u8 val;
+ int ret, max_sds_rings = adapter->max_sds_rings;
+
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EIO;
+
+ ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
+ if (ret)
+ goto fail_diag_irq;
+
+ ahw->diag_cnt = 0;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
+
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ intrpt_id = ahw->intr_tbl[0].id;
+ else
+ intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+
+ cmd.req.arg[1] = 1;
+ cmd.req.arg[2] = intrpt_id;
+ cmd.req.arg[3] = BIT_0;
+
+ ret = qlcnic_issue_cmd(adapter, &cmd);
+ data = cmd.rsp.arg[2];
+ id = LSW(data);
+ val = LSB(MSW(data));
+ if (id != intrpt_id)
+ dev_info(&adapter->pdev->dev,
+ "Interrupt generated: 0x%x, requested:0x%x\n",
+ id, intrpt_id);
+ if (val)
+ dev_err(&adapter->pdev->dev,
+ "Interrupt test error: 0x%x\n", val);
+ if (ret)
+ goto done;
+
+ msleep(20);
+ ret = !ahw->diag_cnt;
+
+done:
+ qlcnic_free_mbx_args(&cmd);
+ qlcnic_83xx_diag_free_res(netdev, max_sds_rings);
+
+fail_diag_irq:
+ adapter->max_sds_rings = max_sds_rings;
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return ret;
+}
+
+void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *adapter,
+ struct ethtool_pauseparam *pause)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int status = 0;
+ u32 config;
+
+ status = qlcnic_83xx_get_port_config(adapter);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "%s: Get Pause Config failed\n", __func__);
+ return;
+ }
+ config = ahw->port_config;
+ if (config & QLC_83XX_CFG_STD_PAUSE) {
+ if (config & QLC_83XX_CFG_STD_TX_PAUSE)
+ pause->tx_pause = 1;
+ if (config & QLC_83XX_CFG_STD_RX_PAUSE)
+ pause->rx_pause = 1;
+ }
+
+ if (QLC_83XX_AUTONEG(config))
+ pause->autoneg = 1;
+}
+
+int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter,
+ struct ethtool_pauseparam *pause)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int status = 0;
+ u32 config;
+
+ status = qlcnic_83xx_get_port_config(adapter);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "%s: Get Pause Config failed.\n", __func__);
+ return status;
+ }
+ config = ahw->port_config;
+
+ if (ahw->port_type == QLCNIC_GBE) {
+ if (pause->autoneg)
+ ahw->port_config |= QLC_83XX_ENABLE_AUTONEG;
+ if (!pause->autoneg)
+ ahw->port_config &= ~QLC_83XX_ENABLE_AUTONEG;
+ } else if ((ahw->port_type == QLCNIC_XGBE) && (pause->autoneg)) {
+ return -EOPNOTSUPP;
+ }
+
+ if (!(config & QLC_83XX_CFG_STD_PAUSE))
+ ahw->port_config |= QLC_83XX_CFG_STD_PAUSE;
+
+ if (pause->rx_pause && pause->tx_pause) {
+ ahw->port_config |= QLC_83XX_CFG_STD_TX_RX_PAUSE;
+ } else if (pause->rx_pause && !pause->tx_pause) {
+ ahw->port_config &= ~QLC_83XX_CFG_STD_TX_PAUSE;
+ ahw->port_config |= QLC_83XX_CFG_STD_RX_PAUSE;
+ } else if (pause->tx_pause && !pause->rx_pause) {
+ ahw->port_config &= ~QLC_83XX_CFG_STD_RX_PAUSE;
+ ahw->port_config |= QLC_83XX_CFG_STD_TX_PAUSE;
+ } else if (!pause->rx_pause && !pause->tx_pause) {
+ ahw->port_config &= ~QLC_83XX_CFG_STD_TX_RX_PAUSE;
+ }
+ status = qlcnic_83xx_set_port_config(adapter);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "%s: Set Pause Config failed.\n", __func__);
+ ahw->port_config = config;
+ }
+ return status;
+}
+
+static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
+{
+ int ret;
+
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+ QLC_83XX_FLASH_OEM_READ_SIG);
+ qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+ QLC_83XX_FLASH_READ_CTRL);
+ ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+ if (ret)
+ return -EIO;
+
+ ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
+ return ret & 0xFF;
+}
+
+int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter)
+{
+ int status;
+
+ status = qlcnic_83xx_read_flash_status_reg(adapter);
+ if (status == -EIO) {
+ dev_info(&adapter->pdev->dev, "%s: EEPROM test failed.\n",
+ __func__);
+ return 1;
+ }
+ return 0;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
new file mode 100644
index 000000000000..61f81f6c84a9
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -0,0 +1,438 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#ifndef __QLCNIC_83XX_HW_H
+#define __QLCNIC_83XX_HW_H
+
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include "qlcnic_hw.h"
+
+/* Directly mapped registers */
+#define QLC_83XX_CRB_WIN_BASE 0x3800
+#define QLC_83XX_CRB_WIN_FUNC(f) (QLC_83XX_CRB_WIN_BASE+((f)*4))
+#define QLC_83XX_SEM_LOCK_BASE 0x3840
+#define QLC_83XX_SEM_UNLOCK_BASE 0x3844
+#define QLC_83XX_SEM_LOCK_FUNC(f) (QLC_83XX_SEM_LOCK_BASE+((f)*8))
+#define QLC_83XX_SEM_UNLOCK_FUNC(f) (QLC_83XX_SEM_UNLOCK_BASE+((f)*8))
+#define QLC_83XX_LINK_STATE(f) (0x3698+((f) > 7 ? 4 : 0))
+#define QLC_83XX_LINK_SPEED(f) (0x36E0+(((f) >> 2) * 4))
+#define QLC_83XX_LINK_SPEED_FACTOR 10
+#define QLC_83xx_FUNC_VAL(v, f) ((v) & (1 << (f * 4)))
+#define QLC_83XX_INTX_PTR 0x38C0
+#define QLC_83XX_INTX_TRGR 0x38C4
+#define QLC_83XX_INTX_MASK 0x38C8
+
+#define QLC_83XX_DRV_LOCK_WAIT_COUNTER 100
+#define QLC_83XX_DRV_LOCK_WAIT_DELAY 20
+#define QLC_83XX_NEED_DRV_LOCK_RECOVERY 1
+#define QLC_83XX_DRV_LOCK_RECOVERY_IN_PROGRESS 2
+#define QLC_83XX_MAX_DRV_LOCK_RECOVERY_ATTEMPT 3
+#define QLC_83XX_DRV_LOCK_RECOVERY_DELAY 200
+#define QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK 0x3
+
+#define QLC_83XX_NO_NIC_RESOURCE 0x5
+#define QLC_83XX_MAC_PRESENT 0xC
+#define QLC_83XX_MAC_ABSENT 0xD
+
+
+#define QLC_83XX_FLASH_SECTOR_SIZE (64 * 1024)
+
+/* PEG status definitions */
+#define QLC_83XX_CMDPEG_COMPLETE 0xff01
+#define QLC_83XX_VALID_INTX_BIT30(val) ((val) & BIT_30)
+#define QLC_83XX_VALID_INTX_BIT31(val) ((val) & BIT_31)
+#define QLC_83XX_INTX_FUNC(val) ((val) & 0xFF)
+#define QLC_83XX_LEGACY_INTX_MAX_RETRY 100
+#define QLC_83XX_LEGACY_INTX_DELAY 4
+#define QLC_83XX_REG_DESC 1
+#define QLC_83XX_LRO_DESC 2
+#define QLC_83XX_CTRL_DESC 3
+#define QLC_83XX_FW_CAPABILITY_TSO BIT_6
+#define QLC_83XX_FW_CAP_LRO_MSS BIT_17
+#define QLC_83XX_HOST_RDS_MODE_UNIQUE 0
+#define QLC_83XX_HOST_SDS_MBX_IDX 8
+
+#define QLCNIC_HOST_RDS_MBX_IDX 88
+#define QLCNIC_MAX_RING_SETS 8
+
+/* Pause control registers */
+#define QLC_83XX_SRE_SHIM_REG 0x0D200284
+#define QLC_83XX_PORT0_THRESHOLD 0x0B2003A4
+#define QLC_83XX_PORT1_THRESHOLD 0x0B2013A4
+#define QLC_83XX_PORT0_TC_MC_REG 0x0B200388
+#define QLC_83XX_PORT1_TC_MC_REG 0x0B201388
+#define QLC_83XX_PORT0_TC_STATS 0x0B20039C
+#define QLC_83XX_PORT1_TC_STATS 0x0B20139C
+#define QLC_83XX_PORT2_IFB_THRESHOLD 0x0B200704
+#define QLC_83XX_PORT3_IFB_THRESHOLD 0x0B201704
+
+/* Peg PC status registers */
+#define QLC_83XX_CRB_PEG_NET_0 0x3400003c
+#define QLC_83XX_CRB_PEG_NET_1 0x3410003c
+#define QLC_83XX_CRB_PEG_NET_2 0x3420003c
+#define QLC_83XX_CRB_PEG_NET_3 0x3430003c
+#define QLC_83XX_CRB_PEG_NET_4 0x34b0003c
+
+/* Firmware image definitions */
+#define QLC_83XX_BOOTLOADER_FLASH_ADDR 0x10000
+#define QLC_83XX_FW_FILE_NAME "83xx_fw.bin"
+#define QLC_83XX_BOOT_FROM_FLASH 0
+#define QLC_83XX_BOOT_FROM_FILE 0x12345678
+
+#define QLC_83XX_MAX_RESET_SEQ_ENTRIES 16
+
+struct qlcnic_intrpt_config {
+ u8 type;
+ u8 enabled;
+ u16 id;
+ u32 src;
+};
+
+struct qlcnic_macvlan_mbx {
+ u8 mac[ETH_ALEN];
+ u16 vlan;
+};
+
+struct qlc_83xx_fw_info {
+ const struct firmware *fw;
+ u16 major_fw_version;
+ u8 minor_fw_version;
+ u8 sub_fw_version;
+ u8 fw_build_num;
+ u8 load_from_file;
+};
+
+struct qlc_83xx_reset {
+ struct qlc_83xx_reset_hdr *hdr;
+ int seq_index;
+ int seq_error;
+ int array_index;
+ u32 array[QLC_83XX_MAX_RESET_SEQ_ENTRIES];
+ u8 *buff;
+ u8 *stop_offset;
+ u8 *start_offset;
+ u8 *init_offset;
+ u8 seq_end;
+ u8 template_end;
+};
+
+#define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY 0x1
+#define QLC_83XX_IDC_GRACEFULL_RESET 0x2
+#define QLC_83XX_IDC_TIMESTAMP 0
+#define QLC_83XX_IDC_DURATION 1
+#define QLC_83XX_IDC_INIT_TIMEOUT_SECS 30
+#define QLC_83XX_IDC_RESET_ACK_TIMEOUT_SECS 10
+#define QLC_83XX_IDC_RESET_TIMEOUT_SECS 10
+#define QLC_83XX_IDC_QUIESCE_ACK_TIMEOUT_SECS 20
+#define QLC_83XX_IDC_FW_POLL_DELAY (1 * HZ)
+#define QLC_83XX_IDC_FW_FAIL_THRESH 2
+#define QLC_83XX_IDC_MAX_FUNC_PER_PARTITION_INFO 8
+#define QLC_83XX_IDC_MAX_CNA_FUNCTIONS 16
+#define QLC_83XX_IDC_MAJOR_VERSION 1
+#define QLC_83XX_IDC_MINOR_VERSION 0
+#define QLC_83XX_IDC_FLASH_PARAM_ADDR 0x3e8020
+
+struct qlcnic_adapter;
+struct qlc_83xx_idc {
+ int (*state_entry) (struct qlcnic_adapter *);
+ u64 sec_counter;
+ u64 delay;
+ unsigned long status;
+ int err_code;
+ int collect_dump;
+ u8 curr_state;
+ u8 prev_state;
+ u8 vnic_state;
+ u8 vnic_wait_limit;
+ u8 quiesce_req;
+ char **name;
+};
+
+#define QLCNIC_MBX_RSP(reg) LSW(reg)
+#define QLCNIC_MBX_NUM_REGS(reg) (MSW(reg) & 0x1FF)
+#define QLCNIC_MBX_STATUS(reg) (((reg) >> 25) & 0x7F)
+#define QLCNIC_MBX_HOST(ahw, i) ((ahw)->pci_base0 + ((i) * 4))
+#define QLCNIC_MBX_FW(ahw, i) ((ahw)->pci_base0 + 0x800 + ((i) * 4))
+
+/* Mailbox process AEN count */
+#define QLC_83XX_IDC_COMP_AEN 3
+#define QLC_83XX_MBX_AEN_CNT 5
+#define QLC_83XX_MODULE_LOADED 1
+#define QLC_83XX_MBX_READY 2
+#define QLC_83XX_MBX_AEN_ACK 3
+#define QLC_83XX_SFP_PRESENT(data) ((data) & 3)
+#define QLC_83XX_SFP_ERR(data) (((data) >> 2) & 3)
+#define QLC_83XX_SFP_MODULE_TYPE(data) (((data) >> 4) & 0x1F)
+#define QLC_83XX_SFP_CU_LENGTH(data) (LSB((data) >> 16))
+#define QLC_83XX_SFP_TX_FAULT(data) ((data) & BIT_10)
+#define QLC_83XX_SFP_10G_CAPABLE(data) ((data) & BIT_11)
+#define QLC_83XX_LINK_STATS(data) ((data) & BIT_0)
+#define QLC_83XX_CURRENT_LINK_SPEED(data) (((data) >> 3) & 7)
+#define QLC_83XX_LINK_PAUSE(data) (((data) >> 6) & 3)
+#define QLC_83XX_LINK_LB(data) (((data) >> 8) & 7)
+#define QLC_83XX_LINK_FEC(data) ((data) & BIT_12)
+#define QLC_83XX_LINK_EEE(data) ((data) & BIT_13)
+#define QLC_83XX_DCBX(data) (((data) >> 28) & 7)
+#define QLC_83XX_AUTONEG(data) ((data) & BIT_15)
+#define QLC_83XX_CFG_STD_PAUSE (1 << 5)
+#define QLC_83XX_CFG_STD_TX_PAUSE (1 << 20)
+#define QLC_83XX_CFG_STD_RX_PAUSE (2 << 20)
+#define QLC_83XX_CFG_STD_TX_RX_PAUSE (3 << 20)
+#define QLC_83XX_ENABLE_AUTONEG (1 << 15)
+#define QLC_83XX_CFG_LOOPBACK_HSS (2 << 1)
+#define QLC_83XX_CFG_LOOPBACK_PHY (3 << 1)
+#define QLC_83XX_CFG_LOOPBACK_EXT (4 << 1)
+
+/* LED configuration settings */
+#define QLC_83XX_ENABLE_BEACON 0xe
+#define QLC_83XX_LED_RATE 0xff
+#define QLC_83XX_LED_ACT (1 << 10)
+#define QLC_83XX_LED_MOD (0 << 13)
+#define QLC_83XX_LED_CONFIG (QLC_83XX_LED_RATE | QLC_83XX_LED_ACT | \
+ QLC_83XX_LED_MOD)
+
+#define QLC_83XX_10M_LINK 1
+#define QLC_83XX_100M_LINK 2
+#define QLC_83XX_1G_LINK 3
+#define QLC_83XX_10G_LINK 4
+#define QLC_83XX_STAT_TX 3
+#define QLC_83XX_STAT_RX 2
+#define QLC_83XX_STAT_MAC 1
+#define QLC_83XX_TX_STAT_REGS 14
+#define QLC_83XX_RX_STAT_REGS 40
+#define QLC_83XX_MAC_STAT_REGS 80
+
+#define QLC_83XX_GET_FUNC_PRIVILEGE(VAL, FN) (0x3 & ((VAL) >> (FN * 2)))
+#define QLC_83XX_SET_FUNC_OPMODE(VAL, FN) ((VAL) << (FN * 2))
+#define QLC_83XX_DEFAULT_OPMODE 0x55555555
+#define QLC_83XX_PRIVLEGED_FUNC 0x1
+#define QLC_83XX_VIRTUAL_FUNC 0x2
+
+#define QLC_83XX_LB_MAX_FILTERS 2048
+#define QLC_83XX_LB_BUCKET_SIZE 256
+#define QLC_83XX_MINIMUM_VECTOR 3
+
+#define QLC_83XX_GET_FUNC_MODE_FROM_NPAR_INFO(val) (val & 0x80000000)
+#define QLC_83XX_GET_LRO_CAPABILITY(val) (val & 0x20)
+#define QLC_83XX_GET_LSO_CAPABILITY(val) (val & 0x40)
+#define QLC_83XX_GET_LSO_CAPABILITY(val) (val & 0x40)
+#define QLC_83XX_GET_HW_LRO_CAPABILITY(val) (val & 0x400)
+#define QLC_83XX_GET_VLAN_ALIGN_CAPABILITY(val) (val & 0x4000)
+#define QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(val) (val & 0x20000)
+#define QLC_83XX_VIRTUAL_NIC_MODE 0xFF
+#define QLC_83XX_DEFAULT_MODE 0x0
+#define QLCNIC_BRDTYPE_83XX_10G 0x0083
+
+#define QLC_83XX_FLASH_SPI_STATUS 0x2808E010
+#define QLC_83XX_FLASH_SPI_CONTROL 0x2808E014
+#define QLC_83XX_FLASH_STATUS 0x42100004
+#define QLC_83XX_FLASH_CONTROL 0x42110004
+#define QLC_83XX_FLASH_ADDR 0x42110008
+#define QLC_83XX_FLASH_WRDATA 0x4211000C
+#define QLC_83XX_FLASH_RDDATA 0x42110018
+#define QLC_83XX_FLASH_DIRECT_WINDOW 0x42110030
+#define QLC_83XX_FLASH_DIRECT_DATA(DATA) (0x42150000 | (0x0000FFFF&DATA))
+#define QLC_83XX_FLASH_SECTOR_ERASE_CMD 0xdeadbeef
+#define QLC_83XX_FLASH_WRITE_CMD 0xdacdacda
+#define QLC_83XX_FLASH_BULK_WRITE_CMD 0xcadcadca
+#define QLC_83XX_FLASH_READ_RETRY_COUNT 5000
+#define QLC_83XX_FLASH_STATUS_READY 0x6
+#define QLC_83XX_FLASH_BULK_WRITE_MIN 2
+#define QLC_83XX_FLASH_BULK_WRITE_MAX 64
+#define QLC_83XX_FLASH_STATUS_REG_POLL_DELAY 1
+#define QLC_83XX_ERASE_MODE 1
+#define QLC_83XX_WRITE_MODE 2
+#define QLC_83XX_BULK_WRITE_MODE 3
+#define QLC_83XX_FLASH_FDT_WRITE_DEF_SIG 0xFD0100
+#define QLC_83XX_FLASH_FDT_ERASE_DEF_SIG 0xFD0300
+#define QLC_83XX_FLASH_FDT_READ_MFG_ID_VAL 0xFD009F
+#define QLC_83XX_FLASH_OEM_ERASE_SIG 0xFD03D8
+#define QLC_83XX_FLASH_OEM_WRITE_SIG 0xFD0101
+#define QLC_83XX_FLASH_OEM_READ_SIG 0xFD0005
+#define QLC_83XX_FLASH_ADDR_TEMP_VAL 0x00800000
+#define QLC_83XX_FLASH_ADDR_SECOND_TEMP_VAL 0x00800001
+#define QLC_83XX_FLASH_WRDATA_DEF 0x0
+#define QLC_83XX_FLASH_READ_CTRL 0x3F
+#define QLC_83XX_FLASH_SPI_CTRL 0x4
+#define QLC_83XX_FLASH_FIRST_ERASE_MS_VAL 0x2
+#define QLC_83XX_FLASH_SECOND_ERASE_MS_VAL 0x5
+#define QLC_83XX_FLASH_LAST_ERASE_MS_VAL 0x3D
+#define QLC_83XX_FLASH_FIRST_MS_PATTERN 0x43
+#define QLC_83XX_FLASH_SECOND_MS_PATTERN 0x7F
+#define QLC_83XX_FLASH_LAST_MS_PATTERN 0x7D
+#define QLC_83xx_FLASH_MAX_WAIT_USEC 100
+#define QLC_83XX_FLASH_LOCK_TIMEOUT 10000
+
+/* Additional registers in 83xx */
+enum qlc_83xx_ext_regs {
+ QLCNIC_GLOBAL_RESET = 0,
+ QLCNIC_WILDCARD,
+ QLCNIC_INFORMANT,
+ QLCNIC_HOST_MBX_CTRL,
+ QLCNIC_FW_MBX_CTRL,
+ QLCNIC_BOOTLOADER_ADDR,
+ QLCNIC_BOOTLOADER_SIZE,
+ QLCNIC_FW_IMAGE_ADDR,
+ QLCNIC_MBX_INTR_ENBL,
+ QLCNIC_DEF_INT_MASK,
+ QLCNIC_DEF_INT_ID,
+ QLC_83XX_IDC_MAJ_VERSION,
+ QLC_83XX_IDC_DEV_STATE,
+ QLC_83XX_IDC_DRV_PRESENCE,
+ QLC_83XX_IDC_DRV_ACK,
+ QLC_83XX_IDC_CTRL,
+ QLC_83XX_IDC_DRV_AUDIT,
+ QLC_83XX_IDC_MIN_VERSION,
+ QLC_83XX_RECOVER_DRV_LOCK,
+ QLC_83XX_IDC_PF_0,
+ QLC_83XX_IDC_PF_1,
+ QLC_83XX_IDC_PF_2,
+ QLC_83XX_IDC_PF_3,
+ QLC_83XX_IDC_PF_4,
+ QLC_83XX_IDC_PF_5,
+ QLC_83XX_IDC_PF_6,
+ QLC_83XX_IDC_PF_7,
+ QLC_83XX_IDC_PF_8,
+ QLC_83XX_IDC_PF_9,
+ QLC_83XX_IDC_PF_10,
+ QLC_83XX_IDC_PF_11,
+ QLC_83XX_IDC_PF_12,
+ QLC_83XX_IDC_PF_13,
+ QLC_83XX_IDC_PF_14,
+ QLC_83XX_IDC_PF_15,
+ QLC_83XX_IDC_DEV_PARTITION_INFO_1,
+ QLC_83XX_IDC_DEV_PARTITION_INFO_2,
+ QLC_83XX_DRV_OP_MODE,
+ QLC_83XX_VNIC_STATE,
+ QLC_83XX_DRV_LOCK,
+ QLC_83XX_DRV_UNLOCK,
+ QLC_83XX_DRV_LOCK_ID,
+ QLC_83XX_ASIC_TEMP,
+};
+
+/* 83xx funcitons */
+int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *);
+int qlcnic_83xx_mbx_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8);
+void qlcnic_83xx_get_func_no(struct qlcnic_adapter *);
+int qlcnic_83xx_cam_lock(struct qlcnic_adapter *);
+void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *);
+int qlcnic_send_ctrl_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *, u32);
+void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *);
+void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *);
+void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong);
+int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32);
+void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *, int, u64 []);
+int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *, u8);
+int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8);
+int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_intr_coalesce(struct qlcnic_adapter *);
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, __le16);
+int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *);
+int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *, int);
+
+int qlcnic_83xx_napi_add(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_83xx_napi_del(struct qlcnic_adapter *);
+void qlcnic_83xx_napi_enable(struct qlcnic_adapter *);
+void qlcnic_83xx_napi_disable(struct qlcnic_adapter *);
+int qlcnic_83xx_config_led(struct qlcnic_adapter *, u32, u32);
+void qlcnic_ind_wr(struct qlcnic_adapter *, u32, u32);
+int qlcnic_ind_rd(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *);
+int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *,
+ struct qlcnic_host_tx_ring *, int);
+int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
+int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *, int);
+void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *);
+int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *, bool);
+int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8);
+int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *, u8 *);
+void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8,
+ struct qlcnic_cmd_args *);
+int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *,
+ struct qlcnic_adapter *, u32);
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *);
+void qlcnic_set_npar_data(struct qlcnic_adapter *, const struct qlcnic_info *,
+ struct qlcnic_info *);
+void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_handle_aen(int, void *);
+int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);
+void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_intr(int, void *);
+irqreturn_t qlcnic_83xx_tmp_intr(int, void *);
+void qlcnic_83xx_enable_intr(struct qlcnic_adapter *,
+ struct qlcnic_host_sds_ring *);
+void qlcnic_83xx_disable_intr(struct qlcnic_adapter *,
+ struct qlcnic_host_sds_ring *);
+void qlcnic_83xx_check_vf(struct qlcnic_adapter *,
+ const struct pci_device_id *);
+void qlcnic_83xx_process_aen(struct qlcnic_adapter *);
+int qlcnic_83xx_get_port_config(struct qlcnic_adapter *);
+int qlcnic_83xx_set_port_config(struct qlcnic_adapter *);
+int qlcnic_enable_eswitch(struct qlcnic_adapter *, u8, u8);
+int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *);
+int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *);
+int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *);
+void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *);
+void qlcnic_83xx_register_map(struct qlcnic_hardware_context *);
+void qlcnic_83xx_idc_aen_work(struct work_struct *);
+void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *, __be32, int);
+
+int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *, u32, u32 *, int);
+int qlcnic_83xx_flash_write32(struct qlcnic_adapter *, u32, u32 *);
+int qlcnic_83xx_lock_flash(struct qlcnic_adapter *);
+void qlcnic_83xx_unlock_flash(struct qlcnic_adapter *);
+int qlcnic_83xx_save_flash_status(struct qlcnic_adapter *);
+int qlcnic_83xx_restore_flash_status(struct qlcnic_adapter *, int);
+int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *);
+int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *);
+int qlcnic_83xx_flash_read32(struct qlcnic_adapter *, u32, u8 *, int);
+int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *,
+ u32, u8 *, int);
+int qlcnic_83xx_init(struct qlcnic_adapter *);
+int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *);
+int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev);
+void qlcnic_83xx_idc_poll_dev_state(struct work_struct *);
+int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *);
+void qlcnic_83xx_idc_exit(struct qlcnic_adapter *);
+void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_lock_driver(struct qlcnic_adapter *);
+void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *);
+int qlcnic_83xx_set_default_offload_settings(struct qlcnic_adapter *);
+int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *, u64, u32 *, u32);
+int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *);
+int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *, int);
+int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *);
+int qlcnic_83xx_get_vnic_vport_info(struct qlcnic_adapter *,
+ struct qlcnic_info *, u8);
+int qlcnic_83xx_get_vnic_pf_info(struct qlcnic_adapter *, struct qlcnic_info *);
+
+void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *);
+void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data);
+int qlcnic_83xx_get_settings(struct qlcnic_adapter *);
+int qlcnic_83xx_set_settings(struct qlcnic_adapter *, struct ethtool_cmd *);
+void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *,
+ struct ethtool_pauseparam *);
+int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *,
+ struct ethtool_pauseparam *);
+int qlcnic_83xx_test_link(struct qlcnic_adapter *);
+int qlcnic_83xx_reg_test(struct qlcnic_adapter *);
+int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *);
+int qlcnic_83xx_get_registers(struct qlcnic_adapter *, u32 *);
+int qlcnic_83xx_loopback_test(struct net_device *, u8);
+int qlcnic_83xx_interrupt_test(struct net_device *);
+int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
+#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
new file mode 100644
index 000000000000..c53832b02b3e
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -0,0 +1,2054 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+/* Reset template definitions */
+#define QLC_83XX_RESTART_TEMPLATE_SIZE 0x2000
+#define QLC_83XX_RESET_TEMPLATE_ADDR 0x4F0000
+#define QLC_83XX_RESET_SEQ_VERSION 0x0101
+
+#define QLC_83XX_OPCODE_NOP 0x0000
+#define QLC_83XX_OPCODE_WRITE_LIST 0x0001
+#define QLC_83XX_OPCODE_READ_WRITE_LIST 0x0002
+#define QLC_83XX_OPCODE_POLL_LIST 0x0004
+#define QLC_83XX_OPCODE_POLL_WRITE_LIST 0x0008
+#define QLC_83XX_OPCODE_READ_MODIFY_WRITE 0x0010
+#define QLC_83XX_OPCODE_SEQ_PAUSE 0x0020
+#define QLC_83XX_OPCODE_SEQ_END 0x0040
+#define QLC_83XX_OPCODE_TMPL_END 0x0080
+#define QLC_83XX_OPCODE_POLL_READ_LIST 0x0100
+
+static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter);
+static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
+static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev);
+static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter);
+
+/* Template header */
+struct qlc_83xx_reset_hdr {
+ u16 version;
+ u16 signature;
+ u16 size;
+ u16 entries;
+ u16 hdr_size;
+ u16 checksum;
+ u16 init_offset;
+ u16 start_offset;
+} __packed;
+
+/* Command entry header. */
+struct qlc_83xx_entry_hdr {
+ u16 cmd;
+ u16 size;
+ u16 count;
+ u16 delay;
+} __packed;
+
+/* Generic poll command */
+struct qlc_83xx_poll {
+ u32 mask;
+ u32 status;
+} __packed;
+
+/* Read modify write command */
+struct qlc_83xx_rmw {
+ u32 mask;
+ u32 xor_value;
+ u32 or_value;
+ u8 shl;
+ u8 shr;
+ u8 index_a;
+ u8 rsvd;
+} __packed;
+
+/* Generic command with 2 DWORD */
+struct qlc_83xx_entry {
+ u32 arg1;
+ u32 arg2;
+} __packed;
+
+/* Generic command with 4 DWORD */
+struct qlc_83xx_quad_entry {
+ u32 dr_addr;
+ u32 dr_value;
+ u32 ar_addr;
+ u32 ar_value;
+} __packed;
+static const char *const qlc_83xx_idc_states[] = {
+ "Unknown",
+ "Cold",
+ "Init",
+ "Ready",
+ "Need Reset",
+ "Need Quiesce",
+ "Failed",
+ "Quiesce"
+};
+
+/* Device States */
+enum qlcnic_83xx_states {
+ QLC_83XX_IDC_DEV_UNKNOWN,
+ QLC_83XX_IDC_DEV_COLD,
+ QLC_83XX_IDC_DEV_INIT,
+ QLC_83XX_IDC_DEV_READY,
+ QLC_83XX_IDC_DEV_NEED_RESET,
+ QLC_83XX_IDC_DEV_NEED_QUISCENT,
+ QLC_83XX_IDC_DEV_FAILED,
+ QLC_83XX_IDC_DEV_QUISCENT
+};
+
+static int
+qlcnic_83xx_idc_check_driver_presence_reg(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+ if ((val & 0xFFFF))
+ return 1;
+ else
+ return 0;
+}
+
+static void qlcnic_83xx_idc_log_state_history(struct qlcnic_adapter *adapter)
+{
+ u32 cur, prev;
+ cur = adapter->ahw->idc.curr_state;
+ prev = adapter->ahw->idc.prev_state;
+
+ dev_info(&adapter->pdev->dev,
+ "current state = %s, prev state = %s\n",
+ adapter->ahw->idc.name[cur],
+ adapter->ahw->idc.name[prev]);
+}
+
+static int qlcnic_83xx_idc_update_audit_reg(struct qlcnic_adapter *adapter,
+ u8 mode, int lock)
+{
+ u32 val;
+ int seconds;
+
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ val = adapter->portnum & 0xf;
+ val |= mode << 7;
+ if (mode)
+ seconds = jiffies / HZ - adapter->ahw->idc.sec_counter;
+ else
+ seconds = jiffies / HZ;
+
+ val |= seconds << 8;
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT, val);
+ adapter->ahw->idc.sec_counter = jiffies / HZ;
+
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static void qlcnic_83xx_idc_update_minor_version(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MIN_VERSION);
+ val = val & ~(0x3 << (adapter->portnum * 2));
+ val = val | (QLC_83XX_IDC_MINOR_VERSION << (adapter->portnum * 2));
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_MIN_VERSION, val);
+}
+
+static int qlcnic_83xx_idc_update_major_version(struct qlcnic_adapter *adapter,
+ int lock)
+{
+ u32 val;
+
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION);
+ val = val & ~0xFF;
+ val = val | QLC_83XX_IDC_MAJOR_VERSION;
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION, val);
+
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static int
+qlcnic_83xx_idc_update_drv_presence_reg(struct qlcnic_adapter *adapter,
+ int status, int lock)
+{
+ u32 val;
+
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+
+ if (status)
+ val = val | (1 << adapter->portnum);
+ else
+ val = val & ~(1 << adapter->portnum);
+
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+ qlcnic_83xx_idc_update_minor_version(adapter);
+
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_check_major_version(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+ u8 version;
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION);
+ version = val & 0xFF;
+
+ if (version != QLC_83XX_IDC_MAJOR_VERSION) {
+ dev_info(&adapter->pdev->dev,
+ "%s:mismatch. version 0x%x, expected version 0x%x\n",
+ __func__, version, QLC_83XX_IDC_MAJOR_VERSION);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_clear_registers(struct qlcnic_adapter *adapter,
+ int lock)
+{
+ u32 val;
+
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_ACK, 0);
+ /* Clear gracefull reset bit */
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+ val &= ~QLC_83XX_IDC_GRACEFULL_RESET;
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_update_drv_ack_reg(struct qlcnic_adapter *adapter,
+ int flag, int lock)
+{
+ u32 val;
+
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_ACK);
+ if (flag)
+ val = val | (1 << adapter->portnum);
+ else
+ val = val & ~(1 << adapter->portnum);
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_ACK, val);
+
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_check_timeout(struct qlcnic_adapter *adapter,
+ int time_limit)
+{
+ u64 seconds;
+
+ seconds = jiffies / HZ - adapter->ahw->idc.sec_counter;
+ if (seconds <= time_limit)
+ return 0;
+ else
+ return -EBUSY;
+}
+
+/**
+ * qlcnic_83xx_idc_check_reset_ack_reg
+ *
+ * @adapter: adapter structure
+ *
+ * Check ACK wait limit and clear the functions which failed to ACK
+ *
+ * Return 0 if all functions have acknowledged the reset request.
+ **/
+static int qlcnic_83xx_idc_check_reset_ack_reg(struct qlcnic_adapter *adapter)
+{
+ int timeout;
+ u32 ack, presence, val;
+
+ timeout = QLC_83XX_IDC_RESET_TIMEOUT_SECS;
+ ack = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_ACK);
+ presence = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+ dev_info(&adapter->pdev->dev,
+ "%s: ack = 0x%x, presence = 0x%x\n", __func__, ack, presence);
+ if (!((ack & presence) == presence)) {
+ if (qlcnic_83xx_idc_check_timeout(adapter, timeout)) {
+ /* Clear functions which failed to ACK */
+ dev_info(&adapter->pdev->dev,
+ "%s: ACK wait exceeds time limit\n", __func__);
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+ val = val & ~(ack ^ presence);
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+ dev_info(&adapter->pdev->dev,
+ "%s: updated drv presence reg = 0x%x\n",
+ __func__, val);
+ qlcnic_83xx_unlock_driver(adapter);
+ return 0;
+
+ } else {
+ return 1;
+ }
+ } else {
+ dev_info(&adapter->pdev->dev,
+ "%s: Reset ACK received from all functions\n",
+ __func__);
+ return 0;
+ }
+}
+
+/**
+ * qlcnic_83xx_idc_tx_soft_reset
+ *
+ * @adapter: adapter structure
+ *
+ * Handle context deletion and recreation request from transmit routine
+ *
+ * Returns -EBUSY or Success (0)
+ *
+ **/
+static int qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EBUSY;
+
+ netif_device_detach(netdev);
+ qlcnic_down(adapter, netdev);
+ qlcnic_up(adapter, netdev);
+ netif_device_attach(netdev);
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ dev_err(&adapter->pdev->dev, "%s:\n", __func__);
+
+ adapter->netdev->trans_start = jiffies;
+
+ return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_detach_driver
+ *
+ * @adapter: adapter structure
+ * Detach net interface, stop TX and cleanup resources before the HW reset.
+ * Returns: None
+ *
+ **/
+static void qlcnic_83xx_idc_detach_driver(struct qlcnic_adapter *adapter)
+{
+ int i;
+ struct net_device *netdev = adapter->netdev;
+
+ netif_device_detach(netdev);
+ /* Disable mailbox interrupt */
+ QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, 0);
+ qlcnic_down(adapter, netdev);
+ for (i = 0; i < adapter->ahw->num_msix; i++) {
+ adapter->ahw->intr_tbl[i].id = i;
+ adapter->ahw->intr_tbl[i].enabled = 0;
+ adapter->ahw->intr_tbl[i].src = 0;
+ }
+}
+
+/**
+ * qlcnic_83xx_idc_attach_driver
+ *
+ * @adapter: adapter structure
+ *
+ * Re-attach and re-enable net interface
+ * Returns: None
+ *
+ **/
+static void qlcnic_83xx_idc_attach_driver(struct qlcnic_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ if (netif_running(netdev)) {
+ if (qlcnic_up(adapter, netdev))
+ goto done;
+ qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+ }
+done:
+ netif_device_attach(netdev);
+ if (netif_running(netdev)) {
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+ }
+}
+
+static int qlcnic_83xx_idc_enter_failed_state(struct qlcnic_adapter *adapter,
+ int lock)
+{
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ qlcnic_83xx_idc_clear_registers(adapter, 0);
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_FAILED);
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ qlcnic_83xx_idc_log_state_history(adapter);
+ dev_info(&adapter->pdev->dev, "Device will enter failed state\n");
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_enter_init_state(struct qlcnic_adapter *adapter,
+ int lock)
+{
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_INIT);
+
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_enter_need_quiesce(struct qlcnic_adapter *adapter,
+ int lock)
+{
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+ QLC_83XX_IDC_DEV_NEED_QUISCENT);
+
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static int
+qlcnic_83xx_idc_enter_need_reset_state(struct qlcnic_adapter *adapter, int lock)
+{
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+ QLC_83XX_IDC_DEV_NEED_RESET);
+
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_enter_ready_state(struct qlcnic_adapter *adapter,
+ int lock)
+{
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_READY);
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_find_reset_owner_id
+ *
+ * @adapter: adapter structure
+ *
+ * NIC gets precedence over ISCSI and ISCSI has precedence over FCOE.
+ * Within the same class, function with lowest PCI ID assumes ownership
+ *
+ * Returns: reset owner id or failure indication (-EIO)
+ *
+ **/
+static int qlcnic_83xx_idc_find_reset_owner_id(struct qlcnic_adapter *adapter)
+{
+ u32 reg, reg1, reg2, i, j, owner, class;
+
+ reg1 = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_PARTITION_INFO_1);
+ reg2 = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_PARTITION_INFO_2);
+ owner = QLCNIC_TYPE_NIC;
+ i = 0;
+ j = 0;
+ reg = reg1;
+
+ do {
+ class = (((reg & (0xF << j * 4)) >> j * 4) & 0x3);
+ if (class == owner)
+ break;
+ if (i == (QLC_83XX_IDC_MAX_FUNC_PER_PARTITION_INFO - 1)) {
+ reg = reg2;
+ j = 0;
+ } else {
+ j++;
+ }
+
+ if (i == (QLC_83XX_IDC_MAX_CNA_FUNCTIONS - 1)) {
+ if (owner == QLCNIC_TYPE_NIC)
+ owner = QLCNIC_TYPE_ISCSI;
+ else if (owner == QLCNIC_TYPE_ISCSI)
+ owner = QLCNIC_TYPE_FCOE;
+ else if (owner == QLCNIC_TYPE_FCOE)
+ return -EIO;
+ reg = reg1;
+ j = 0;
+ i = 0;
+ }
+ } while (i++ < QLC_83XX_IDC_MAX_CNA_FUNCTIONS);
+
+ return i;
+}
+
+static int qlcnic_83xx_idc_restart_hw(struct qlcnic_adapter *adapter, int lock)
+{
+ int ret = 0;
+
+ ret = qlcnic_83xx_restart_hw(adapter);
+
+ if (ret) {
+ qlcnic_83xx_idc_enter_failed_state(adapter, lock);
+ } else {
+ qlcnic_83xx_idc_clear_registers(adapter, lock);
+ ret = qlcnic_83xx_idc_enter_ready_state(adapter, lock);
+ }
+
+ return ret;
+}
+
+static int qlcnic_83xx_idc_check_fan_failure(struct qlcnic_adapter *adapter)
+{
+ u32 status;
+
+ status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+
+ if (status & QLCNIC_RCODE_FATAL_ERROR) {
+ dev_err(&adapter->pdev->dev,
+ "peg halt status1=0x%x\n", status);
+ if (QLCNIC_FWERROR_CODE(status) == QLCNIC_FWERROR_FAN_FAILURE) {
+ dev_err(&adapter->pdev->dev,
+ "On board active cooling fan failed. "
+ "Device has been halted.\n");
+ dev_err(&adapter->pdev->dev,
+ "Replace the adapter.\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
+{
+ /* register for NIC IDC AEN Events */
+ qlcnic_83xx_register_nic_idc_func(adapter, 1);
+
+ qlcnic_83xx_enable_mbx_intrpt(adapter);
+ if ((adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ if (qlcnic_83xx_config_intrpt(adapter, 1)) {
+ netdev_err(adapter->netdev,
+ "Failed to enable mbx intr\n");
+ return -EIO;
+ }
+ }
+
+ if (qlcnic_83xx_configure_opmode(adapter)) {
+ qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+ return -EIO;
+ }
+
+ if (adapter->nic_ops->init_driver(adapter)) {
+ qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+ return -EIO;
+ }
+
+ qlcnic_83xx_idc_attach_driver(adapter);
+
+ return 0;
+}
+
+static void qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter *adapter)
+{
+ qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 1);
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+ qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+ set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+ adapter->ahw->idc.quiesce_req = 0;
+ adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
+ adapter->ahw->idc.err_code = 0;
+ adapter->ahw->idc.collect_dump = 0;
+}
+
+/**
+ * qlcnic_83xx_idc_ready_state_entry
+ *
+ * @adapter: adapter structure
+ *
+ * Perform ready state initialization, this routine will get invoked only
+ * once from READY state.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_READY) {
+ qlcnic_83xx_idc_update_idc_params(adapter);
+ /* Re-attach the device if required */
+ if ((ahw->idc.prev_state == QLC_83XX_IDC_DEV_NEED_RESET) ||
+ (ahw->idc.prev_state == QLC_83XX_IDC_DEV_INIT)) {
+ if (qlcnic_83xx_idc_reattach_driver(adapter))
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_vnic_pf_entry
+ *
+ * @adapter: adapter structure
+ *
+ * Ensure vNIC mode privileged function starts only after vNIC mode is
+ * enabled by management function.
+ * If vNIC mode is ready, start initialization.
+ *
+ * Returns: -EIO or 0
+ *
+ **/
+int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *adapter)
+{
+ u32 state;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ /* Privileged function waits till mgmt function enables VNIC mode */
+ state = QLCRDX(adapter->ahw, QLC_83XX_VNIC_STATE);
+ if (state != QLCNIC_DEV_NPAR_OPER) {
+ if (!ahw->idc.vnic_wait_limit--) {
+ qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+ return -EIO;
+ }
+ dev_info(&adapter->pdev->dev, "vNIC mode disabled\n");
+ return -EIO;
+
+ } else {
+ /* Perform one time initialization from ready state */
+ if (ahw->idc.vnic_state != QLCNIC_DEV_NPAR_OPER) {
+ qlcnic_83xx_idc_update_idc_params(adapter);
+
+ /* If the previous state is UNKNOWN, device will be
+ already attached properly by Init routine*/
+ if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_UNKNOWN) {
+ if (qlcnic_83xx_idc_reattach_driver(adapter))
+ return -EIO;
+ }
+ adapter->ahw->idc.vnic_state = QLCNIC_DEV_NPAR_OPER;
+ dev_info(&adapter->pdev->dev, "vNIC mode enabled\n");
+ }
+ }
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter)
+{
+ adapter->ahw->idc.err_code = -EIO;
+ dev_err(&adapter->pdev->dev,
+ "%s: Device in unknown state\n", __func__);
+ return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_cold_state
+ *
+ * @adapter: adapter structure
+ *
+ * If HW is up and running device will enter READY state.
+ * If firmware image from host needs to be loaded, device is
+ * forced to start with the file firmware image.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_cold_state_handler(struct qlcnic_adapter *adapter)
+{
+ qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 0);
+ qlcnic_83xx_idc_update_audit_reg(adapter, 1, 0);
+
+ if (qlcnic_load_fw_file) {
+ qlcnic_83xx_idc_restart_hw(adapter, 0);
+ } else {
+ if (qlcnic_83xx_check_hw_status(adapter)) {
+ qlcnic_83xx_idc_enter_failed_state(adapter, 0);
+ return -EIO;
+ } else {
+ qlcnic_83xx_idc_enter_ready_state(adapter, 0);
+ }
+ }
+ return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_init_state
+ *
+ * @adapter: adapter structure
+ *
+ * Reset owner will restart the device from this state.
+ * Device will enter failed state if it remains
+ * in this state for more than DEV_INIT time limit.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_init_state(struct qlcnic_adapter *adapter)
+{
+ int timeout, ret = 0;
+ u32 owner;
+
+ timeout = QLC_83XX_IDC_INIT_TIMEOUT_SECS;
+ if (adapter->ahw->idc.prev_state == QLC_83XX_IDC_DEV_NEED_RESET) {
+ owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
+ if (adapter->ahw->pci_func == owner)
+ ret = qlcnic_83xx_idc_restart_hw(adapter, 1);
+ } else {
+ ret = qlcnic_83xx_idc_check_timeout(adapter, timeout);
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * qlcnic_83xx_idc_ready_state
+ *
+ * @adapter: adapter structure
+ *
+ * Perform IDC protocol specicifed actions after monitoring device state and
+ * events.
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int ret = 0;
+
+ /* Perform NIC configuration based ready state entry actions */
+ if (ahw->idc.state_entry(adapter))
+ return -EIO;
+
+ if (qlcnic_check_temp(adapter)) {
+ if (ahw->temp == QLCNIC_TEMP_PANIC) {
+ qlcnic_83xx_idc_check_fan_failure(adapter);
+ dev_err(&adapter->pdev->dev,
+ "Error: device temperature %d above limits\n",
+ adapter->ahw->temp);
+ clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+ set_bit(__QLCNIC_RESETTING, &adapter->state);
+ qlcnic_83xx_idc_detach_driver(adapter);
+ qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+ return -EIO;
+ }
+ }
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+ ret = qlcnic_83xx_check_heartbeat(adapter);
+ if (ret) {
+ adapter->flags |= QLCNIC_FW_HANG;
+ if (!(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
+ clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+ set_bit(__QLCNIC_RESETTING, &adapter->state);
+ qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
+ }
+ return -EIO;
+ }
+
+ if ((val & QLC_83XX_IDC_GRACEFULL_RESET) || ahw->idc.collect_dump) {
+ /* Move to need reset state and prepare for reset */
+ qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
+ return ret;
+ }
+
+ /* Check for soft reset request */
+ if (ahw->reset_context &&
+ !(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
+ qlcnic_83xx_idc_tx_soft_reset(adapter);
+ return ret;
+ }
+
+ /* Move to need quiesce state if requested */
+ if (adapter->ahw->idc.quiesce_req) {
+ qlcnic_83xx_idc_enter_need_quiesce(adapter, 1);
+ qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * qlcnic_83xx_idc_need_reset_state
+ *
+ * @adapter: adapter structure
+ *
+ * Device will remain in this state until:
+ * Reset request ACK's are recieved from all the functions
+ * Wait time exceeds max time limit
+ *
+ * Returns: Error code or Success(0)
+ *
+ **/
+static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter)
+{
+ int ret = 0;
+
+ if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_NEED_RESET) {
+ qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
+ qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+ set_bit(__QLCNIC_RESETTING, &adapter->state);
+ clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+ if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE)
+ qlcnic_83xx_disable_vnic_mode(adapter, 1);
+ qlcnic_83xx_idc_detach_driver(adapter);
+ }
+
+ /* Check ACK from other functions */
+ ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
+ if (ret) {
+ dev_info(&adapter->pdev->dev,
+ "%s: Waiting for reset ACK\n", __func__);
+ return 0;
+ }
+
+ /* Transit to INIT state and restart the HW */
+ qlcnic_83xx_idc_enter_init_state(adapter, 1);
+
+ return ret;
+}
+
+static int qlcnic_83xx_idc_need_quiesce_state(struct qlcnic_adapter *adapter)
+{
+ dev_err(&adapter->pdev->dev, "%s: TBD\n", __func__);
+ return 0;
+}
+
+static int qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter)
+{
+ dev_err(&adapter->pdev->dev, "%s: please restart!!\n", __func__);
+ adapter->ahw->idc.err_code = -EIO;
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_quiesce_state(struct qlcnic_adapter *adapter)
+{
+ dev_info(&adapter->pdev->dev, "%s: TBD\n", __func__);
+ return 0;
+}
+
+static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter,
+ u32 state)
+{
+ u32 cur, prev, next;
+
+ cur = adapter->ahw->idc.curr_state;
+ prev = adapter->ahw->idc.prev_state;
+ next = state;
+
+ if ((next < QLC_83XX_IDC_DEV_COLD) ||
+ (next > QLC_83XX_IDC_DEV_QUISCENT)) {
+ dev_err(&adapter->pdev->dev,
+ "%s: curr %d, prev %d, next state %d is invalid\n",
+ __func__, cur, prev, state);
+ return 1;
+ }
+
+ if ((cur == QLC_83XX_IDC_DEV_UNKNOWN) &&
+ (prev == QLC_83XX_IDC_DEV_UNKNOWN)) {
+ if ((next != QLC_83XX_IDC_DEV_COLD) &&
+ (next != QLC_83XX_IDC_DEV_READY)) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed, cur %d prev %d next %d\n",
+ __func__, cur, prev, next);
+ return 1;
+ }
+ }
+
+ if (next == QLC_83XX_IDC_DEV_INIT) {
+ if ((prev != QLC_83XX_IDC_DEV_INIT) &&
+ (prev != QLC_83XX_IDC_DEV_COLD) &&
+ (prev != QLC_83XX_IDC_DEV_NEED_RESET)) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed, cur %d prev %d next %d\n",
+ __func__, cur, prev, next);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter)
+{
+ if (adapter->fhash.fnum)
+ qlcnic_prune_lb_filters(adapter);
+}
+
+/**
+ * qlcnic_83xx_idc_poll_dev_state
+ *
+ * @work: kernel work queue structure used to schedule the function
+ *
+ * Poll device state periodically and perform state specific
+ * actions defined by Inter Driver Communication (IDC) protocol.
+ *
+ * Returns: None
+ *
+ **/
+void qlcnic_83xx_idc_poll_dev_state(struct work_struct *work)
+{
+ struct qlcnic_adapter *adapter;
+ u32 state;
+
+ adapter = container_of(work, struct qlcnic_adapter, fw_work.work);
+ state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+
+ if (qlcnic_83xx_idc_check_state_validity(adapter, state)) {
+ qlcnic_83xx_idc_log_state_history(adapter);
+ adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_UNKNOWN;
+ } else {
+ adapter->ahw->idc.curr_state = state;
+ }
+
+ switch (adapter->ahw->idc.curr_state) {
+ case QLC_83XX_IDC_DEV_READY:
+ qlcnic_83xx_idc_ready_state(adapter);
+ break;
+ case QLC_83XX_IDC_DEV_NEED_RESET:
+ qlcnic_83xx_idc_need_reset_state(adapter);
+ break;
+ case QLC_83XX_IDC_DEV_NEED_QUISCENT:
+ qlcnic_83xx_idc_need_quiesce_state(adapter);
+ break;
+ case QLC_83XX_IDC_DEV_FAILED:
+ qlcnic_83xx_idc_failed_state(adapter);
+ return;
+ case QLC_83XX_IDC_DEV_INIT:
+ qlcnic_83xx_idc_init_state(adapter);
+ break;
+ case QLC_83XX_IDC_DEV_QUISCENT:
+ qlcnic_83xx_idc_quiesce_state(adapter);
+ break;
+ default:
+ qlcnic_83xx_idc_unknown_state(adapter);
+ return;
+ }
+ adapter->ahw->idc.prev_state = adapter->ahw->idc.curr_state;
+ qlcnic_83xx_periodic_tasks(adapter);
+
+ /* Re-schedule the function */
+ if (test_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status))
+ qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state,
+ adapter->ahw->idc.delay);
+}
+
+static void qlcnic_83xx_setup_idc_parameters(struct qlcnic_adapter *adapter)
+{
+ u32 idc_params, val;
+
+ if (qlcnic_83xx_lockless_flash_read32(adapter,
+ QLC_83XX_IDC_FLASH_PARAM_ADDR,
+ (u8 *)&idc_params, 1)) {
+ dev_info(&adapter->pdev->dev,
+ "%s:failed to get IDC params from flash\n", __func__);
+ adapter->dev_init_timeo = QLC_83XX_IDC_INIT_TIMEOUT_SECS;
+ adapter->reset_ack_timeo = QLC_83XX_IDC_RESET_TIMEOUT_SECS;
+ } else {
+ adapter->dev_init_timeo = idc_params & 0xFFFF;
+ adapter->reset_ack_timeo = ((idc_params >> 16) & 0xFFFF);
+ }
+
+ adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_UNKNOWN;
+ adapter->ahw->idc.prev_state = QLC_83XX_IDC_DEV_UNKNOWN;
+ adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
+ adapter->ahw->idc.err_code = 0;
+ adapter->ahw->idc.collect_dump = 0;
+ adapter->ahw->idc.name = (char **)qlc_83xx_idc_states;
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+ set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+
+ /* Check if reset recovery is disabled */
+ if (!qlcnic_auto_fw_reset) {
+ /* Propagate do not reset request to other functions */
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+ val = val | QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY;
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+ }
+}
+
+static int
+qlcnic_83xx_idc_first_to_load_function_handler(struct qlcnic_adapter *adapter)
+{
+ u32 state, val;
+
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EIO;
+
+ /* Clear driver lock register */
+ QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, 0);
+ if (qlcnic_83xx_idc_update_major_version(adapter, 0)) {
+ qlcnic_83xx_unlock_driver(adapter);
+ return -EIO;
+ }
+
+ state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+ if (qlcnic_83xx_idc_check_state_validity(adapter, state)) {
+ qlcnic_83xx_unlock_driver(adapter);
+ return -EIO;
+ }
+
+ if (state != QLC_83XX_IDC_DEV_COLD && qlcnic_load_fw_file) {
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+ QLC_83XX_IDC_DEV_COLD);
+ state = QLC_83XX_IDC_DEV_COLD;
+ }
+
+ adapter->ahw->idc.curr_state = state;
+ /* First to load function should cold boot the device */
+ if (state == QLC_83XX_IDC_DEV_COLD)
+ qlcnic_83xx_idc_cold_state_handler(adapter);
+
+ /* Check if reset recovery is enabled */
+ if (qlcnic_auto_fw_reset) {
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+ val = val & ~QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY;
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+ }
+
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static int qlcnic_83xx_idc_init(struct qlcnic_adapter *adapter)
+{
+ int ret = -EIO;
+
+ qlcnic_83xx_setup_idc_parameters(adapter);
+
+ if (qlcnic_83xx_get_reset_instruction_template(adapter))
+ return ret;
+
+ if (!qlcnic_83xx_idc_check_driver_presence_reg(adapter)) {
+ if (qlcnic_83xx_idc_first_to_load_function_handler(adapter))
+ return -EIO;
+ } else {
+ if (qlcnic_83xx_idc_check_major_version(adapter))
+ return -EIO;
+ }
+
+ qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+
+ return 0;
+}
+
+void qlcnic_83xx_idc_exit(struct qlcnic_adapter *adapter)
+{
+ int id;
+ u32 val;
+
+ while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ usleep_range(10000, 11000);
+
+ id = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+ id = id & 0xFF;
+
+ if (id == adapter->portnum) {
+ dev_err(&adapter->pdev->dev,
+ "%s: wait for lock recovery.. %d\n", __func__, id);
+ msleep(20);
+ id = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+ id = id & 0xFF;
+ }
+
+ /* Clear driver presence bit */
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+ val = val & ~(1 << adapter->portnum);
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+ clear_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+ cancel_delayed_work_sync(&adapter->fw_work);
+}
+
+void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *adapter, u32 key)
+{
+ u32 val;
+
+ if (qlcnic_83xx_lock_driver(adapter)) {
+ dev_err(&adapter->pdev->dev,
+ "%s:failed, please retry\n", __func__);
+ return;
+ }
+
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+ if ((val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) ||
+ !qlcnic_auto_fw_reset) {
+ dev_err(&adapter->pdev->dev,
+ "%s:failed, device in non reset mode\n", __func__);
+ qlcnic_83xx_unlock_driver(adapter);
+ return;
+ }
+
+ if (key == QLCNIC_FORCE_FW_RESET) {
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+ val = val | QLC_83XX_IDC_GRACEFULL_RESET;
+ QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+ } else if (key == QLCNIC_FORCE_FW_DUMP_KEY) {
+ adapter->ahw->idc.collect_dump = 1;
+ }
+
+ qlcnic_83xx_unlock_driver(adapter);
+ return;
+}
+
+static int qlcnic_83xx_copy_bootloader(struct qlcnic_adapter *adapter)
+{
+ u8 *p_cache;
+ u32 src, size;
+ u64 dest;
+ int ret = -EIO;
+
+ src = QLC_83XX_BOOTLOADER_FLASH_ADDR;
+ dest = QLCRDX(adapter->ahw, QLCNIC_BOOTLOADER_ADDR);
+ size = QLCRDX(adapter->ahw, QLCNIC_BOOTLOADER_SIZE);
+
+ /* alignment check */
+ if (size & 0xF)
+ size = (size + 16) & ~0xF;
+
+ p_cache = kzalloc(size, GFP_KERNEL);
+ if (p_cache == NULL)
+ return -ENOMEM;
+
+ ret = qlcnic_83xx_lockless_flash_read32(adapter, src, p_cache,
+ size / sizeof(u32));
+ if (ret) {
+ kfree(p_cache);
+ return ret;
+ }
+ /* 16 byte write to MS memory */
+ ret = qlcnic_83xx_ms_mem_write128(adapter, dest, (u32 *)p_cache,
+ size / 16);
+ if (ret) {
+ kfree(p_cache);
+ return ret;
+ }
+ kfree(p_cache);
+
+ return ret;
+}
+
+static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
+{
+ u32 dest, *p_cache;
+ u64 addr;
+ u8 data[16];
+ size_t size;
+ int i, ret = -EIO;
+
+ dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR);
+ size = (adapter->ahw->fw_info.fw->size & ~0xF);
+ p_cache = (u32 *)adapter->ahw->fw_info.fw->data;
+ addr = (u64)dest;
+
+ ret = qlcnic_83xx_ms_mem_write128(adapter, addr,
+ (u32 *)p_cache, size / 16);
+ if (ret) {
+ dev_err(&adapter->pdev->dev, "MS memory write failed\n");
+ release_firmware(adapter->ahw->fw_info.fw);
+ adapter->ahw->fw_info.fw = NULL;
+ return -EIO;
+ }
+
+ /* alignment check */
+ if (adapter->ahw->fw_info.fw->size & 0xF) {
+ addr = dest + size;
+ for (i = 0; i < (adapter->ahw->fw_info.fw->size & 0xF); i++)
+ data[i] = adapter->ahw->fw_info.fw->data[size + i];
+ for (; i < 16; i++)
+ data[i] = 0;
+ ret = qlcnic_83xx_ms_mem_write128(adapter, addr,
+ (u32 *)data, 1);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "MS memory write failed\n");
+ release_firmware(adapter->ahw->fw_info.fw);
+ adapter->ahw->fw_info.fw = NULL;
+ return -EIO;
+ }
+ }
+ release_firmware(adapter->ahw->fw_info.fw);
+ adapter->ahw->fw_info.fw = NULL;
+
+ return 0;
+}
+
+static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
+{
+ int i, j;
+ u32 val = 0, val1 = 0, reg = 0;
+
+ val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG);
+ dev_info(&adapter->pdev->dev, "SRE-Shim Ctrl:0x%x\n", val);
+
+ for (j = 0; j < 2; j++) {
+ if (j == 0) {
+ dev_info(&adapter->pdev->dev,
+ "Port 0 RxB Pause Threshold Regs[TC7..TC0]:");
+ reg = QLC_83XX_PORT0_THRESHOLD;
+ } else if (j == 1) {
+ dev_info(&adapter->pdev->dev,
+ "Port 1 RxB Pause Threshold Regs[TC7..TC0]:");
+ reg = QLC_83XX_PORT1_THRESHOLD;
+ }
+ for (i = 0; i < 8; i++) {
+ val = QLCRD32(adapter, reg + (i * 0x4));
+ dev_info(&adapter->pdev->dev, "0x%x ", val);
+ }
+ dev_info(&adapter->pdev->dev, "\n");
+ }
+
+ for (j = 0; j < 2; j++) {
+ if (j == 0) {
+ dev_info(&adapter->pdev->dev,
+ "Port 0 RxB TC Max Cell Registers[4..1]:");
+ reg = QLC_83XX_PORT0_TC_MC_REG;
+ } else if (j == 1) {
+ dev_info(&adapter->pdev->dev,
+ "Port 1 RxB TC Max Cell Registers[4..1]:");
+ reg = QLC_83XX_PORT1_TC_MC_REG;
+ }
+ for (i = 0; i < 4; i++) {
+ val = QLCRD32(adapter, reg + (i * 0x4));
+ dev_info(&adapter->pdev->dev, "0x%x ", val);
+ }
+ dev_info(&adapter->pdev->dev, "\n");
+ }
+
+ for (j = 0; j < 2; j++) {
+ if (j == 0) {
+ dev_info(&adapter->pdev->dev,
+ "Port 0 RxB Rx TC Stats[TC7..TC0]:");
+ reg = QLC_83XX_PORT0_TC_STATS;
+ } else if (j == 1) {
+ dev_info(&adapter->pdev->dev,
+ "Port 1 RxB Rx TC Stats[TC7..TC0]:");
+ reg = QLC_83XX_PORT1_TC_STATS;
+ }
+ for (i = 7; i >= 0; i--) {
+ val = QLCRD32(adapter, reg);
+ val &= ~(0x7 << 29); /* Reset bits 29 to 31 */
+ QLCWR32(adapter, reg, (val | (i << 29)));
+ val = QLCRD32(adapter, reg);
+ dev_info(&adapter->pdev->dev, "0x%x ", val);
+ }
+ dev_info(&adapter->pdev->dev, "\n");
+ }
+
+ val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD);
+ val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD);
+ dev_info(&adapter->pdev->dev,
+ "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
+ val, val1);
+}
+
+
+static void qlcnic_83xx_disable_pause_frames(struct qlcnic_adapter *adapter)
+{
+ u32 reg = 0, i, j;
+
+ if (qlcnic_83xx_lock_driver(adapter)) {
+ dev_err(&adapter->pdev->dev,
+ "%s:failed to acquire driver lock\n", __func__);
+ return;
+ }
+
+ qlcnic_83xx_dump_pause_control_regs(adapter);
+ QLCWR32(adapter, QLC_83XX_SRE_SHIM_REG, 0x0);
+
+ for (j = 0; j < 2; j++) {
+ if (j == 0)
+ reg = QLC_83XX_PORT0_THRESHOLD;
+ else if (j == 1)
+ reg = QLC_83XX_PORT1_THRESHOLD;
+
+ for (i = 0; i < 8; i++)
+ QLCWR32(adapter, reg + (i * 0x4), 0x0);
+ }
+
+ for (j = 0; j < 2; j++) {
+ if (j == 0)
+ reg = QLC_83XX_PORT0_TC_MC_REG;
+ else if (j == 1)
+ reg = QLC_83XX_PORT1_TC_MC_REG;
+
+ for (i = 0; i < 4; i++)
+ QLCWR32(adapter, reg + (i * 0x4), 0x03FF03FF);
+ }
+
+ QLCWR32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, 0);
+ QLCWR32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, 0);
+ dev_info(&adapter->pdev->dev,
+ "Disabled pause frames successfully on all ports\n");
+ qlcnic_83xx_unlock_driver(adapter);
+}
+
+static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
+{
+ u32 heartbeat, peg_status;
+ int retries, ret = -EIO;
+
+ retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
+ p_dev->heartbeat = QLC_SHARED_REG_RD32(p_dev,
+ QLCNIC_PEG_ALIVE_COUNTER);
+
+ do {
+ msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
+ heartbeat = QLC_SHARED_REG_RD32(p_dev,
+ QLCNIC_PEG_ALIVE_COUNTER);
+ if (heartbeat != p_dev->heartbeat) {
+ ret = QLCNIC_RCODE_SUCCESS;
+ break;
+ }
+ } while (--retries);
+
+ if (ret) {
+ dev_err(&p_dev->pdev->dev, "firmware hang detected\n");
+ qlcnic_83xx_disable_pause_frames(p_dev);
+ peg_status = QLC_SHARED_REG_RD32(p_dev,
+ QLCNIC_PEG_HALT_STATUS1);
+ dev_info(&p_dev->pdev->dev, "Dumping HW/FW registers\n"
+ "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
+ "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
+ "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
+ "PEG_NET_4_PC: 0x%x\n", peg_status,
+ QLC_SHARED_REG_RD32(p_dev, QLCNIC_PEG_HALT_STATUS2),
+ QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0),
+ QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1),
+ QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2),
+ QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3),
+ QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4));
+
+ if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
+ dev_err(&p_dev->pdev->dev,
+ "Device is being reset err code 0x00006700.\n");
+ }
+
+ return ret;
+}
+
+static int qlcnic_83xx_check_cmd_peg_status(struct qlcnic_adapter *p_dev)
+{
+ int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
+ u32 val;
+
+ do {
+ val = QLC_SHARED_REG_RD32(p_dev, QLCNIC_CMDPEG_STATE);
+ if (val == QLC_83XX_CMDPEG_COMPLETE)
+ return 0;
+ msleep(QLCNIC_CMDPEG_CHECK_DELAY);
+ } while (--retries);
+
+ dev_err(&p_dev->pdev->dev, "%s: failed, state = 0x%x\n", __func__, val);
+ return -EIO;
+}
+
+int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)
+{
+ int err;
+
+ err = qlcnic_83xx_check_cmd_peg_status(p_dev);
+ if (err)
+ return err;
+
+ err = qlcnic_83xx_check_heartbeat(p_dev);
+ if (err)
+ return err;
+
+ return err;
+}
+
+static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr,
+ int duration, u32 mask, u32 status)
+{
+ u32 value;
+ int timeout_error;
+ u8 retries;
+
+ value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+ retries = duration / 10;
+
+ do {
+ if ((value & mask) != status) {
+ timeout_error = 1;
+ msleep(duration / 10);
+ value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+ } else {
+ timeout_error = 0;
+ break;
+ }
+ } while (retries--);
+
+ if (timeout_error) {
+ p_dev->ahw->reset.seq_error++;
+ dev_err(&p_dev->pdev->dev,
+ "%s: Timeout Err, entry_num = %d\n",
+ __func__, p_dev->ahw->reset.seq_index);
+ dev_err(&p_dev->pdev->dev,
+ "0x%08x 0x%08x 0x%08x\n",
+ value, mask, status);
+ }
+
+ return timeout_error;
+}
+
+static int qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter *p_dev)
+{
+ u32 sum = 0;
+ u16 *buff = (u16 *)p_dev->ahw->reset.buff;
+ int count = p_dev->ahw->reset.hdr->size / sizeof(u16);
+
+ while (count-- > 0)
+ sum += *buff++;
+
+ while (sum >> 16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ if (~sum) {
+ return 0;
+ } else {
+ dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+ return -1;
+ }
+}
+
+int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
+{
+ u8 *p_buff;
+ u32 addr, count;
+ struct qlcnic_hardware_context *ahw = p_dev->ahw;
+
+ ahw->reset.seq_error = 0;
+ ahw->reset.buff = kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL);
+ if (p_dev->ahw->reset.buff == NULL)
+ return -ENOMEM;
+
+ p_buff = p_dev->ahw->reset.buff;
+ addr = QLC_83XX_RESET_TEMPLATE_ADDR;
+ count = sizeof(struct qlc_83xx_reset_hdr) / sizeof(u32);
+
+ /* Copy template header from flash */
+ if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
+ dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
+ return -EIO;
+ }
+ ahw->reset.hdr = (struct qlc_83xx_reset_hdr *)ahw->reset.buff;
+ addr = QLC_83XX_RESET_TEMPLATE_ADDR + ahw->reset.hdr->hdr_size;
+ p_buff = ahw->reset.buff + ahw->reset.hdr->hdr_size;
+ count = (ahw->reset.hdr->size - ahw->reset.hdr->hdr_size) / sizeof(u32);
+
+ /* Copy rest of the template */
+ if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
+ dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
+ return -EIO;
+ }
+
+ if (qlcnic_83xx_reset_template_checksum(p_dev))
+ return -EIO;
+ /* Get Stop, Start and Init command offsets */
+ ahw->reset.init_offset = ahw->reset.buff + ahw->reset.hdr->init_offset;
+ ahw->reset.start_offset = ahw->reset.buff +
+ ahw->reset.hdr->start_offset;
+ ahw->reset.stop_offset = ahw->reset.buff + ahw->reset.hdr->hdr_size;
+ return 0;
+}
+
+/* Read Write HW register command */
+static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev,
+ u32 raddr, u32 waddr)
+{
+ int value;
+
+ value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+ qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
+}
+
+/* Read Modify Write HW register command */
+static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev,
+ u32 raddr, u32 waddr,
+ struct qlc_83xx_rmw *p_rmw_hdr)
+{
+ int value;
+
+ if (p_rmw_hdr->index_a)
+ value = p_dev->ahw->reset.array[p_rmw_hdr->index_a];
+ else
+ value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+
+ value &= p_rmw_hdr->mask;
+ value <<= p_rmw_hdr->shl;
+ value >>= p_rmw_hdr->shr;
+ value |= p_rmw_hdr->or_value;
+ value ^= p_rmw_hdr->xor_value;
+ qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
+}
+
+/* Write HW register command */
+static void qlcnic_83xx_write_list(struct qlcnic_adapter *p_dev,
+ struct qlc_83xx_entry_hdr *p_hdr)
+{
+ int i;
+ struct qlc_83xx_entry *entry;
+
+ entry = (struct qlc_83xx_entry *)((char *)p_hdr +
+ sizeof(struct qlc_83xx_entry_hdr));
+
+ for (i = 0; i < p_hdr->count; i++, entry++) {
+ qlcnic_83xx_wrt_reg_indirect(p_dev, entry->arg1,
+ entry->arg2);
+ if (p_hdr->delay)
+ udelay((u32)(p_hdr->delay));
+ }
+}
+
+/* Read and Write instruction */
+static void qlcnic_83xx_read_write_list(struct qlcnic_adapter *p_dev,
+ struct qlc_83xx_entry_hdr *p_hdr)
+{
+ int i;
+ struct qlc_83xx_entry *entry;
+
+ entry = (struct qlc_83xx_entry *)((char *)p_hdr +
+ sizeof(struct qlc_83xx_entry_hdr));
+
+ for (i = 0; i < p_hdr->count; i++, entry++) {
+ qlcnic_83xx_read_write_crb_reg(p_dev, entry->arg1,
+ entry->arg2);
+ if (p_hdr->delay)
+ udelay((u32)(p_hdr->delay));
+ }
+}
+
+/* Poll HW register command */
+static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
+ struct qlc_83xx_entry_hdr *p_hdr)
+{
+ long delay;
+ struct qlc_83xx_entry *entry;
+ struct qlc_83xx_poll *poll;
+ int i;
+ unsigned long arg1, arg2;
+
+ poll = (struct qlc_83xx_poll *)((char *)p_hdr +
+ sizeof(struct qlc_83xx_entry_hdr));
+
+ entry = (struct qlc_83xx_entry *)((char *)poll +
+ sizeof(struct qlc_83xx_poll));
+ delay = (long)p_hdr->delay;
+
+ if (!delay) {
+ for (i = 0; i < p_hdr->count; i++, entry++)
+ qlcnic_83xx_poll_reg(p_dev, entry->arg1,
+ delay, poll->mask,
+ poll->status);
+ } else {
+ for (i = 0; i < p_hdr->count; i++, entry++) {
+ arg1 = entry->arg1;
+ arg2 = entry->arg2;
+ if (delay) {
+ if (qlcnic_83xx_poll_reg(p_dev,
+ arg1, delay,
+ poll->mask,
+ poll->status)){
+ qlcnic_83xx_rd_reg_indirect(p_dev,
+ arg1);
+ qlcnic_83xx_rd_reg_indirect(p_dev,
+ arg2);
+ }
+ }
+ }
+ }
+}
+
+/* Poll and write HW register command */
+static void qlcnic_83xx_poll_write_list(struct qlcnic_adapter *p_dev,
+ struct qlc_83xx_entry_hdr *p_hdr)
+{
+ int i;
+ long delay;
+ struct qlc_83xx_quad_entry *entry;
+ struct qlc_83xx_poll *poll;
+
+ poll = (struct qlc_83xx_poll *)((char *)p_hdr +
+ sizeof(struct qlc_83xx_entry_hdr));
+ entry = (struct qlc_83xx_quad_entry *)((char *)poll +
+ sizeof(struct qlc_83xx_poll));
+ delay = (long)p_hdr->delay;
+
+ for (i = 0; i < p_hdr->count; i++, entry++) {
+ qlcnic_83xx_wrt_reg_indirect(p_dev, entry->dr_addr,
+ entry->dr_value);
+ qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
+ entry->ar_value);
+ if (delay)
+ qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
+ poll->mask, poll->status);
+ }
+}
+
+/* Read Modify Write register command */
+static void qlcnic_83xx_read_modify_write(struct qlcnic_adapter *p_dev,
+ struct qlc_83xx_entry_hdr *p_hdr)
+{
+ int i;
+ struct qlc_83xx_entry *entry;
+ struct qlc_83xx_rmw *rmw_hdr;
+
+ rmw_hdr = (struct qlc_83xx_rmw *)((char *)p_hdr +
+ sizeof(struct qlc_83xx_entry_hdr));
+
+ entry = (struct qlc_83xx_entry *)((char *)rmw_hdr +
+ sizeof(struct qlc_83xx_rmw));
+
+ for (i = 0; i < p_hdr->count; i++, entry++) {
+ qlcnic_83xx_rmw_crb_reg(p_dev, entry->arg1,
+ entry->arg2, rmw_hdr);
+ if (p_hdr->delay)
+ udelay((u32)(p_hdr->delay));
+ }
+}
+
+static void qlcnic_83xx_pause(struct qlc_83xx_entry_hdr *p_hdr)
+{
+ if (p_hdr->delay)
+ mdelay((u32)((long)p_hdr->delay));
+}
+
+/* Read and poll register command */
+static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
+ struct qlc_83xx_entry_hdr *p_hdr)
+{
+ long delay;
+ int index, i, j;
+ struct qlc_83xx_quad_entry *entry;
+ struct qlc_83xx_poll *poll;
+ unsigned long addr;
+
+ poll = (struct qlc_83xx_poll *)((char *)p_hdr +
+ sizeof(struct qlc_83xx_entry_hdr));
+
+ entry = (struct qlc_83xx_quad_entry *)((char *)poll +
+ sizeof(struct qlc_83xx_poll));
+ delay = (long)p_hdr->delay;
+
+ for (i = 0; i < p_hdr->count; i++, entry++) {
+ qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
+ entry->ar_value);
+ if (delay) {
+ if (!qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
+ poll->mask, poll->status)){
+ index = p_dev->ahw->reset.array_index;
+ addr = entry->dr_addr;
+ j = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+ p_dev->ahw->reset.array[index++] = j;
+
+ if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES)
+ p_dev->ahw->reset.array_index = 1;
+ }
+ }
+ }
+}
+
+static inline void qlcnic_83xx_seq_end(struct qlcnic_adapter *p_dev)
+{
+ p_dev->ahw->reset.seq_end = 1;
+}
+
+static void qlcnic_83xx_template_end(struct qlcnic_adapter *p_dev)
+{
+ p_dev->ahw->reset.template_end = 1;
+ if (p_dev->ahw->reset.seq_error == 0)
+ dev_err(&p_dev->pdev->dev,
+ "HW restart process completed successfully.\n");
+ else
+ dev_err(&p_dev->pdev->dev,
+ "HW restart completed with timeout errors.\n");
+}
+
+/**
+* qlcnic_83xx_exec_template_cmd
+*
+* @p_dev: adapter structure
+* @p_buff: Poiter to instruction template
+*
+* Template provides instructions to stop, restart and initalize firmware.
+* These instructions are abstracted as a series of read, write and
+* poll operations on hardware registers. Register information and operation
+* specifics are not exposed to the driver. Driver reads the template from
+* flash and executes the instructions located at pre-defined offsets.
+*
+* Returns: None
+* */
+static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev,
+ char *p_buff)
+{
+ int index, entries;
+ struct qlc_83xx_entry_hdr *p_hdr;
+ char *entry = p_buff;
+
+ p_dev->ahw->reset.seq_end = 0;
+ p_dev->ahw->reset.template_end = 0;
+ entries = p_dev->ahw->reset.hdr->entries;
+ index = p_dev->ahw->reset.seq_index;
+
+ for (; (!p_dev->ahw->reset.seq_end) && (index < entries); index++) {
+ p_hdr = (struct qlc_83xx_entry_hdr *)entry;
+
+ switch (p_hdr->cmd) {
+ case QLC_83XX_OPCODE_NOP:
+ break;
+ case QLC_83XX_OPCODE_WRITE_LIST:
+ qlcnic_83xx_write_list(p_dev, p_hdr);
+ break;
+ case QLC_83XX_OPCODE_READ_WRITE_LIST:
+ qlcnic_83xx_read_write_list(p_dev, p_hdr);
+ break;
+ case QLC_83XX_OPCODE_POLL_LIST:
+ qlcnic_83xx_poll_list(p_dev, p_hdr);
+ break;
+ case QLC_83XX_OPCODE_POLL_WRITE_LIST:
+ qlcnic_83xx_poll_write_list(p_dev, p_hdr);
+ break;
+ case QLC_83XX_OPCODE_READ_MODIFY_WRITE:
+ qlcnic_83xx_read_modify_write(p_dev, p_hdr);
+ break;
+ case QLC_83XX_OPCODE_SEQ_PAUSE:
+ qlcnic_83xx_pause(p_hdr);
+ break;
+ case QLC_83XX_OPCODE_SEQ_END:
+ qlcnic_83xx_seq_end(p_dev);
+ break;
+ case QLC_83XX_OPCODE_TMPL_END:
+ qlcnic_83xx_template_end(p_dev);
+ break;
+ case QLC_83XX_OPCODE_POLL_READ_LIST:
+ qlcnic_83xx_poll_read_list(p_dev, p_hdr);
+ break;
+ default:
+ dev_err(&p_dev->pdev->dev,
+ "%s: Unknown opcode 0x%04x in template %d\n",
+ __func__, p_hdr->cmd, index);
+ break;
+ }
+ entry += p_hdr->size;
+ }
+ p_dev->ahw->reset.seq_index = index;
+}
+
+static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev)
+{
+ p_dev->ahw->reset.seq_index = 0;
+
+ qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.stop_offset);
+ if (p_dev->ahw->reset.seq_end != 1)
+ dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static void qlcnic_83xx_start_hw(struct qlcnic_adapter *p_dev)
+{
+ qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.start_offset);
+ if (p_dev->ahw->reset.template_end != 1)
+ dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static void qlcnic_83xx_init_hw(struct qlcnic_adapter *p_dev)
+{
+ qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.init_offset);
+ if (p_dev->ahw->reset.seq_end != 1)
+ dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static int qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter)
+{
+ int err = -EIO;
+
+ if (request_firmware(&adapter->ahw->fw_info.fw,
+ QLC_83XX_FW_FILE_NAME, &(adapter->pdev->dev))) {
+ dev_err(&adapter->pdev->dev,
+ "No file FW image, loading flash FW image.\n");
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+ QLC_83XX_BOOT_FROM_FLASH);
+ } else {
+ if (qlcnic_83xx_copy_fw_file(adapter))
+ return err;
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+ QLC_83XX_BOOT_FROM_FILE);
+ }
+
+ return 0;
+}
+
+static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
+{
+ u32 val;
+ int err = -EIO;
+
+ qlcnic_83xx_stop_hw(adapter);
+
+ /* Collect FW register dump if required */
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+ if (!(val & QLC_83XX_IDC_GRACEFULL_RESET))
+ qlcnic_dump_fw(adapter);
+ qlcnic_83xx_init_hw(adapter);
+
+ if (qlcnic_83xx_copy_bootloader(adapter))
+ return err;
+ /* Boot either flash image or firmware image from host file system */
+ if (qlcnic_load_fw_file) {
+ if (qlcnic_83xx_load_fw_image_from_host(adapter))
+ return err;
+ } else {
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+ QLC_83XX_BOOT_FROM_FLASH);
+ }
+
+ qlcnic_83xx_start_hw(adapter);
+ if (qlcnic_83xx_check_hw_status(adapter))
+ return -EIO;
+
+ return 0;
+}
+
+/**
+* qlcnic_83xx_config_default_opmode
+*
+* @adapter: adapter structure
+*
+* Configure default driver operating mode
+*
+* Returns: Error code or Success(0)
+* */
+int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *adapter)
+{
+ u32 op_mode;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ qlcnic_get_func_no(adapter);
+ op_mode = QLCRDX(ahw, QLC_83XX_DRV_OP_MODE);
+
+ if (op_mode == QLC_83XX_DEFAULT_OPMODE) {
+ adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver;
+ ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+ } else {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter)
+{
+ int err;
+ struct qlcnic_info nic_info;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ memset(&nic_info, 0, sizeof(struct qlcnic_info));
+ err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func);
+ if (err)
+ return -EIO;
+
+ ahw->physical_port = (u8) nic_info.phys_port;
+ ahw->switch_mode = nic_info.switch_mode;
+ ahw->max_tx_ques = nic_info.max_tx_ques;
+ ahw->max_rx_ques = nic_info.max_rx_ques;
+ ahw->capabilities = nic_info.capabilities;
+ ahw->max_mac_filters = nic_info.max_mac_filters;
+ ahw->max_mtu = nic_info.max_mtu;
+
+ if (ahw->capabilities & BIT_23)
+ ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE;
+ else
+ ahw->nic_mode = QLC_83XX_DEFAULT_MODE;
+
+ return ahw->nic_mode;
+}
+
+static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
+{
+ int ret;
+
+ ret = qlcnic_83xx_get_nic_configuration(adapter);
+ if (ret == -EIO)
+ return -EIO;
+
+ if (ret == QLC_83XX_VIRTUAL_NIC_MODE) {
+ if (qlcnic_83xx_config_vnic_opmode(adapter))
+ return -EIO;
+ } else if (ret == QLC_83XX_DEFAULT_MODE) {
+ if (qlcnic_83xx_config_default_opmode(adapter))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void qlcnic_83xx_config_buff_descriptors(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (ahw->port_type == QLCNIC_XGBE) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+ adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G;
+ adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
+ } else if (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;
+ adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
+ }
+ adapter->num_txd = MAX_CMD_DESCRIPTORS;
+ adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter)
+{
+ int err = -EIO;
+
+ qlcnic_83xx_get_minidump_template(adapter);
+ if (qlcnic_83xx_get_port_info(adapter))
+ return err;
+
+ qlcnic_83xx_config_buff_descriptors(adapter);
+ adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+ adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+ dev_info(&adapter->pdev->dev, "HAL Version: %d\n",
+ adapter->ahw->fw_hal_version);
+
+ return 0;
+}
+
+#define IS_QLC_83XX_USED(a, b, c) (((1 << a->portnum) & b) || ((c >> 6) & 0x1))
+static void qlcnic_83xx_clear_function_resources(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_cmd_args cmd;
+ u32 presence_mask, audit_mask;
+ int status;
+
+ presence_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+ audit_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT);
+
+ if (IS_QLC_83XX_USED(adapter, presence_mask, audit_mask)) {
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_STOP_NIC_FUNC);
+ cmd.req.arg[1] = BIT_31;
+ status = qlcnic_issue_cmd(adapter, &cmd);
+ if (status)
+ dev_err(&adapter->pdev->dev,
+ "Failed to clean up the function resources\n");
+ qlcnic_free_mbx_args(&cmd);
+ }
+}
+
+int qlcnic_83xx_init(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (qlcnic_83xx_check_hw_status(adapter))
+ return -EIO;
+
+ /* Initilaize 83xx mailbox spinlock */
+ spin_lock_init(&ahw->mbx_lock);
+
+ set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+ qlcnic_83xx_clear_function_resources(adapter);
+
+ /* register for NIC IDC AEN Events */
+ qlcnic_83xx_register_nic_idc_func(adapter, 1);
+
+ if (!qlcnic_83xx_read_flash_descriptor_table(adapter))
+ qlcnic_83xx_read_flash_mfg_id(adapter);
+
+ if (qlcnic_83xx_idc_init(adapter))
+ return -EIO;
+
+ /* Configure default, SR-IOV or Virtual NIC mode of operation */
+ if (qlcnic_83xx_configure_opmode(adapter))
+ return -EIO;
+
+ /* Perform operating mode specific initialization */
+ if (adapter->nic_ops->init_driver(adapter))
+ return -EIO;
+
+ INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
+
+ /* Periodically monitor device status */
+ qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
+
+ return adapter->ahw->idc.err_code;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
new file mode 100644
index 000000000000..b0c3de9ede03
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
@@ -0,0 +1,225 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+int qlcnic_83xx_enable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
+{
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+ QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_OPER);
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (lock) {
+ if (qlcnic_83xx_lock_driver(adapter))
+ return -EBUSY;
+ }
+
+ QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+ ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+
+ if (lock)
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+ u8 id;
+ int i, ret = -EBUSY;
+ u32 data = QLCNIC_MGMT_FUNC;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (qlcnic_83xx_lock_driver(adapter))
+ return ret;
+
+ if (qlcnic_config_npars) {
+ for (i = 0; i < ahw->act_pci_func; i++) {
+ id = adapter->npars[i].pci_func;
+ if (id == ahw->pci_func)
+ continue;
+ data |= qlcnic_config_npars &
+ QLC_83XX_SET_FUNC_OPMODE(0x3, id);
+ }
+ } else {
+ data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+ data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, ahw->pci_func)) |
+ QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC,
+ ahw->pci_func);
+ }
+ QLCWRX(adapter->ahw, QLC_83XX_DRV_OP_MODE, data);
+
+ qlcnic_83xx_unlock_driver(adapter);
+
+ return 0;
+}
+
+static void
+qlcnic_83xx_config_vnic_buff_descriptors(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (ahw->port_type == QLCNIC_XGBE) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
+ adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF;
+ adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
+ } else if (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;
+ adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
+ }
+ adapter->num_txd = MAX_CMD_DESCRIPTORS;
+ adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+
+/**
+ * qlcnic_83xx_init_mgmt_vnic
+ *
+ * @adapter: adapter structure
+ * Management virtual NIC sets the operational mode of other vNIC's and
+ * configures embedded switch (ESWITCH).
+ * Returns: Success(0) or error code.
+ *
+ **/
+static int qlcnic_83xx_init_mgmt_vnic(struct qlcnic_adapter *adapter)
+{
+ int err = -EIO;
+
+ qlcnic_83xx_get_minidump_template(adapter);
+ if (!(adapter->flags & QLCNIC_ADAPTER_INITIALIZED)) {
+ if (qlcnic_init_pci_info(adapter))
+ return err;
+
+ if (qlcnic_83xx_set_vnic_opmode(adapter))
+ return err;
+
+ if (qlcnic_set_default_offload_settings(adapter))
+ return err;
+ } else {
+ if (qlcnic_reset_npar_config(adapter))
+ return err;
+ }
+
+ if (qlcnic_83xx_get_port_info(adapter))
+ return err;
+
+ qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+ adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+ adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+ qlcnic_83xx_enable_vnic_mode(adapter, 1);
+
+ dev_info(&adapter->pdev->dev, "HAL Version: %d, Management function\n",
+ adapter->ahw->fw_hal_version);
+
+ return 0;
+}
+
+static int qlcnic_83xx_init_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+ int err = -EIO;
+
+ qlcnic_83xx_get_minidump_template(adapter);
+ if (qlcnic_83xx_get_port_info(adapter))
+ return err;
+
+ qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+ adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+ adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d, Privileged function\n",
+ adapter->ahw->fw_hal_version);
+ return 0;
+}
+
+static int qlcnic_83xx_init_non_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+ int err = -EIO;
+
+ qlcnic_83xx_get_fw_version(adapter);
+ if (qlcnic_set_eswitch_port_config(adapter))
+ return err;
+
+ if (qlcnic_83xx_get_port_info(adapter))
+ return err;
+
+ qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+ adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
+ adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+ dev_info(&adapter->pdev->dev, "HAL Version: %d, Virtual function\n",
+ adapter->ahw->fw_hal_version);
+
+ return 0;
+}
+
+/**
+ * qlcnic_83xx_vnic_opmode
+ *
+ * @adapter: adapter structure
+ * Identify virtual NIC operational modes.
+ *
+ * Returns: Success(0) or error code.
+ *
+ **/
+int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+ u32 op_mode, priv_level;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct qlcnic_nic_template *nic_ops = adapter->nic_ops;
+
+ qlcnic_get_func_no(adapter);
+ op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+
+ if (op_mode == QLC_83XX_DEFAULT_OPMODE)
+ priv_level = QLCNIC_MGMT_FUNC;
+ else
+ priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
+ ahw->pci_func);
+
+ if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+ ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
+ ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+ nic_ops->init_driver = qlcnic_83xx_init_non_privileged_vnic;
+ } else if (priv_level == QLCNIC_PRIV_FUNC) {
+ ahw->op_mode = QLCNIC_PRIV_FUNC;
+ ahw->idc.state_entry = qlcnic_83xx_idc_vnic_pf_entry;
+ nic_ops->init_driver = qlcnic_83xx_init_privileged_vnic;
+ } else if (priv_level == QLCNIC_MGMT_FUNC) {
+ ahw->op_mode = QLCNIC_MGMT_FUNC;
+ ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
+ nic_ops->init_driver = qlcnic_83xx_init_mgmt_vnic;
+ } else {
+ return -EIO;
+ }
+
+ if (ahw->capabilities & BIT_23)
+ adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+ else
+ adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+
+ adapter->ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+ adapter->ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index b14b8f0787ea..a69097c6b84d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -1,12 +1,92 @@
/*
* QLogic qlcnic NIC Driver
- * Copyright (c) 2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
*
* See LICENSE.qlcnic for copyright and licensing details.
*/
#include "qlcnic.h"
+static const struct qlcnic_mailbox_metadata qlcnic_mbx_tbl[] = {
+ {QLCNIC_CMD_CREATE_RX_CTX, 4, 1},
+ {QLCNIC_CMD_DESTROY_RX_CTX, 2, 1},
+ {QLCNIC_CMD_CREATE_TX_CTX, 4, 1},
+ {QLCNIC_CMD_DESTROY_TX_CTX, 2, 1},
+ {QLCNIC_CMD_INTRPT_TEST, 4, 1},
+ {QLCNIC_CMD_SET_MTU, 4, 1},
+ {QLCNIC_CMD_READ_PHY, 4, 2},
+ {QLCNIC_CMD_WRITE_PHY, 5, 1},
+ {QLCNIC_CMD_READ_HW_REG, 4, 1},
+ {QLCNIC_CMD_GET_FLOW_CTL, 4, 2},
+ {QLCNIC_CMD_SET_FLOW_CTL, 4, 1},
+ {QLCNIC_CMD_READ_MAX_MTU, 4, 2},
+ {QLCNIC_CMD_READ_MAX_LRO, 4, 2},
+ {QLCNIC_CMD_MAC_ADDRESS, 4, 3},
+ {QLCNIC_CMD_GET_PCI_INFO, 4, 1},
+ {QLCNIC_CMD_GET_NIC_INFO, 4, 1},
+ {QLCNIC_CMD_SET_NIC_INFO, 4, 1},
+ {QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3},
+ {QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1},
+ {QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3},
+ {QLCNIC_CMD_SET_PORTMIRRORING, 4, 1},
+ {QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1},
+ {QLCNIC_CMD_GET_MAC_STATS, 4, 1},
+ {QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3},
+ {QLCNIC_CMD_GET_ESWITCH_STATS, 5, 1},
+ {QLCNIC_CMD_CONFIG_PORT, 4, 1},
+ {QLCNIC_CMD_TEMP_SIZE, 4, 4},
+ {QLCNIC_CMD_GET_TEMP_HDR, 4, 1},
+ {QLCNIC_CMD_SET_DRV_VER, 4, 1},
+};
+
+static inline u32 qlcnic_get_cmd_signature(struct qlcnic_hardware_context *ahw)
+{
+ return (ahw->pci_func & 0xff) | ((ahw->fw_hal_version & 0xff) << 8) |
+ (0xcafe << 16);
+}
+
+/* Allocate mailbox registers */
+int qlcnic_82xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+ struct qlcnic_adapter *adapter, u32 type)
+{
+ int i, size;
+ const struct qlcnic_mailbox_metadata *mbx_tbl;
+
+ mbx_tbl = qlcnic_mbx_tbl;
+ size = ARRAY_SIZE(qlcnic_mbx_tbl);
+ for (i = 0; i < size; i++) {
+ if (type == mbx_tbl[i].cmd) {
+ mbx->req.num = mbx_tbl[i].in_args;
+ mbx->rsp.num = mbx_tbl[i].out_args;
+ mbx->req.arg = kcalloc(mbx->req.num,
+ sizeof(u32), GFP_ATOMIC);
+ if (!mbx->req.arg)
+ return -ENOMEM;
+ mbx->rsp.arg = kcalloc(mbx->rsp.num,
+ sizeof(u32), GFP_ATOMIC);
+ if (!mbx->rsp.arg) {
+ kfree(mbx->req.arg);
+ mbx->req.arg = NULL;
+ return -ENOMEM;
+ }
+ memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
+ memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
+ mbx->req.arg[0] = type;
+ break;
+ }
+ }
+ return 0;
+}
+
+/* Free up mailbox registers */
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd)
+{
+ kfree(cmd->req.arg);
+ cmd->req.arg = NULL;
+ kfree(cmd->rsp.arg);
+ cmd->rsp.arg = NULL;
+}
+
static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
{
int i;
@@ -38,194 +118,123 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
return rsp;
}
-void
-qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd)
+int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd)
{
+ int i;
u32 rsp;
u32 signature;
struct pci_dev *pdev = adapter->pdev;
struct qlcnic_hardware_context *ahw = adapter->ahw;
+ const char *fmt;
- signature = QLCNIC_CDRP_SIGNATURE_MAKE(ahw->pci_func,
- adapter->ahw->fw_hal_version);
+ signature = qlcnic_get_cmd_signature(ahw);
/* Acquire semaphore before accessing CRB */
if (qlcnic_api_lock(adapter)) {
- cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
- return;
+ cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
+ return cmd->rsp.arg[0];
}
QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature);
- QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, cmd->req.arg1);
- QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, cmd->req.arg2);
- QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, cmd->req.arg3);
+ for (i = 1; i < QLCNIC_CDRP_MAX_ARGS; i++)
+ QLCWR32(adapter, QLCNIC_CDRP_ARG(i), cmd->req.arg[i]);
QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET,
- QLCNIC_CDRP_FORM_CMD(cmd->req.cmd));
-
+ QLCNIC_CDRP_FORM_CMD(cmd->req.arg[0]));
rsp = qlcnic_poll_rsp(adapter);
if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) {
- dev_err(&pdev->dev, "CDRP response timeout.\n");
- cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
+ dev_err(&pdev->dev, "card response timeout.\n");
+ cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
} else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
- cmd->rsp.cmd = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
- switch (cmd->rsp.cmd) {
+ cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1));
+ switch (cmd->rsp.arg[0]) {
case QLCNIC_RCODE_INVALID_ARGS:
- dev_err(&pdev->dev, "CDRP invalid args: 0x%x.\n",
- cmd->rsp.cmd);
+ fmt = "CDRP invalid args: [%d]\n";
break;
case QLCNIC_RCODE_NOT_SUPPORTED:
case QLCNIC_RCODE_NOT_IMPL:
- dev_err(&pdev->dev,
- "CDRP command not supported: 0x%x.\n",
- cmd->rsp.cmd);
+ fmt = "CDRP command not supported: [%d]\n";
break;
case QLCNIC_RCODE_NOT_PERMITTED:
- dev_err(&pdev->dev,
- "CDRP requested action not permitted: 0x%x.\n",
- cmd->rsp.cmd);
+ fmt = "CDRP requested action not permitted: [%d]\n";
break;
case QLCNIC_RCODE_INVALID:
- dev_err(&pdev->dev,
- "CDRP invalid or unknown cmd received: 0x%x.\n",
- cmd->rsp.cmd);
+ fmt = "CDRP invalid or unknown cmd received: [%d]\n";
break;
case QLCNIC_RCODE_TIMEOUT:
- dev_err(&pdev->dev, "CDRP command timeout: 0x%x.\n",
- cmd->rsp.cmd);
+ fmt = "CDRP command timeout: [%d]\n";
break;
default:
- dev_err(&pdev->dev, "CDRP command failed: 0x%x.\n",
- cmd->rsp.cmd);
+ fmt = "CDRP command failed: [%d]\n";
+ break;
}
- } else if (rsp == QLCNIC_CDRP_RSP_OK) {
- cmd->rsp.cmd = QLCNIC_RCODE_SUCCESS;
- if (cmd->rsp.arg2)
- cmd->rsp.arg2 = QLCRD32(adapter,
- QLCNIC_ARG2_CRB_OFFSET);
- if (cmd->rsp.arg3)
- cmd->rsp.arg3 = QLCRD32(adapter,
- QLCNIC_ARG3_CRB_OFFSET);
- }
- if (cmd->rsp.arg1)
- cmd->rsp.arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+ dev_err(&pdev->dev, fmt, cmd->rsp.arg[0]);
+ } else if (rsp == QLCNIC_CDRP_RSP_OK)
+ cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS;
+
+ for (i = 1; i < cmd->rsp.num; i++)
+ cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i));
/* Release semaphore */
qlcnic_api_unlock(adapter);
-
-}
-
-static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u32 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;
+ return cmd->rsp.arg[0];
}
-int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
+int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter)
{
- int err, i;
- void *tmp_addr;
- u32 temp_size, version, csum, *template;
- __le32 *tmp_buf;
struct qlcnic_cmd_args cmd;
- struct qlcnic_hardware_context *ahw;
- struct qlcnic_dump_template_hdr *tmpl_hdr;
- dma_addr_t tmp_addr_t = 0;
-
- ahw = adapter->ahw;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_TEMP_SIZE;
- memset(&cmd.rsp, 1, sizeof(struct _cdrp_cmd));
- qlcnic_issue_cmd(adapter, &cmd);
- if (cmd.rsp.cmd != QLCNIC_RCODE_SUCCESS) {
- dev_info(&adapter->pdev->dev,
- "Can't get template size %d\n", cmd.rsp.cmd);
- err = -EIO;
- return err;
- }
- temp_size = cmd.rsp.arg2;
- version = cmd.rsp.arg3;
- dev_info(&adapter->pdev->dev,
- "minidump template version = 0x%x", version);
- if (!temp_size)
- return -EIO;
+ u32 arg1, arg2, arg3;
+ char drv_string[12];
+ int err = 0;
- 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;
- }
- memset(&cmd.rsp, 0, sizeof(struct _cdrp_cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_GET_TEMP_HDR;
- cmd.req.arg1 = LSD(tmp_addr_t);
- cmd.req.arg2 = MSD(tmp_addr_t);
- cmd.req.arg3 = temp_size;
- qlcnic_issue_cmd(adapter, &cmd);
-
- err = cmd.rsp.cmd;
- if (err != QLCNIC_RCODE_SUCCESS) {
- dev_err(&adapter->pdev->dev,
- "Failed to get mini dump template header %d\n", err);
- err = -EIO;
- goto error;
- }
- ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
- if (!ahw->fw_dump.tmpl_hdr) {
- err = -EIO;
- goto error;
- }
- tmp_buf = tmp_addr;
- template = (u32 *) ahw->fw_dump.tmpl_hdr;
- for (i = 0; i < temp_size/sizeof(u32); i++)
- *template++ = __le32_to_cpu(*tmp_buf++);
+ memset(drv_string, 0, sizeof(drv_string));
+ snprintf(drv_string, sizeof(drv_string), "%d"".""%d"".""%d",
+ _QLCNIC_LINUX_MAJOR, _QLCNIC_LINUX_MINOR,
+ _QLCNIC_LINUX_SUBVERSION);
- csum = qlcnic_temp_checksum((u32 *)ahw->fw_dump.tmpl_hdr, temp_size);
- if (csum) {
- dev_err(&adapter->pdev->dev,
- "Template header checksum validation failed\n");
- err = -EIO;
- goto error;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_DRV_VER);
+ memcpy(&arg1, drv_string, sizeof(u32));
+ memcpy(&arg2, drv_string + 4, sizeof(u32));
+ memcpy(&arg3, drv_string + 8, sizeof(u32));
+
+ cmd.req.arg[1] = arg1;
+ cmd.req.arg[2] = arg2;
+ cmd.req.arg[3] = arg3;
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err) {
+ dev_info(&adapter->pdev->dev,
+ "Failed to set driver version in firmware\n");
+ return -EIO;
}
- tmpl_hdr = ahw->fw_dump.tmpl_hdr;
- tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
- ahw->fw_dump.enable = 1;
-error:
- dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
- return err;
+ return 0;
}
int
qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
{
+ int err = 0;
struct qlcnic_cmd_args cmd;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_SET_MTU;
- cmd.req.arg1 = recv_ctx->context_id;
- cmd.req.arg2 = mtu;
- cmd.req.arg3 = 0;
- if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
- qlcnic_issue_cmd(adapter, &cmd);
- if (cmd.rsp.cmd) {
- dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
- return -EIO;
- }
- }
+ if (recv_ctx->state != QLCNIC_HOST_CTX_STATE_ACTIVE)
+ return err;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_MTU);
+ cmd.req.arg[1] = recv_ctx->context_id;
+ cmd.req.arg[2] = mtu;
- return 0;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err) {
+ dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
+ err = -EIO;
+ }
+ qlcnic_free_mbx_args(&cmd);
+ return err;
}
-static int
-qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
{
void *addr;
struct qlcnic_hostrq_rx_ctx *prq;
@@ -242,10 +251,10 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
u64 phys_addr;
u8 i, nrds_rings, nsds_rings;
+ u16 temp_u16;
size_t rq_size, rsp_size;
u32 cap, reg, val, reg2;
int err;
- u16 temp;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
@@ -279,11 +288,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
| QLCNIC_CAP0_VALIDOFF);
cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
- if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
- cap |= QLCNIC_CAP0_LRO_MSS;
-
- temp = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler);
- prq->valid_field_offset = cpu_to_le16(temp);
+ temp_u16 = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler);
+ prq->valid_field_offset = cpu_to_le16(temp_u16);
prq->txrx_sds_binding = nsds_rings - 1;
prq->capabilities[0] = cpu_to_le32(cap);
@@ -329,20 +335,17 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
}
phys_addr = hostrq_phys_addr;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.arg1 = (u32) (phys_addr >> 32);
- cmd.req.arg2 = (u32) (phys_addr & 0xffffffff);
- cmd.req.arg3 = rq_size;
- cmd.req.cmd = QLCNIC_CDRP_CMD_CREATE_RX_CTX;
- qlcnic_issue_cmd(adapter, &cmd);
- err = cmd.rsp.cmd;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_RX_CTX);
+ cmd.req.arg[1] = MSD(phys_addr);
+ cmd.req.arg[2] = LSD(phys_addr);
+ cmd.req.arg[3] = rq_size;
+ err = qlcnic_issue_cmd(adapter, &cmd);
if (err) {
dev_err(&adapter->pdev->dev,
"Failed to create rx ctx in firmware%d\n", err);
goto out_free_rsp;
}
-
prsp_rds = ((struct qlcnic_cardrsp_rds_ring *)
&prsp->data[le32_to_cpu(prsp->rds_ring_offset)]);
@@ -373,6 +376,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
out_free_rsp:
dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp,
cardrsp_phys_addr);
+ qlcnic_free_mbx_args(&cmd);
out_free_rq:
dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr);
return err;
@@ -381,24 +385,24 @@ out_free_rq:
static void
qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
{
+ int err;
struct qlcnic_cmd_args cmd;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.arg1 = recv_ctx->context_id;
- cmd.req.arg2 = QLCNIC_DESTROY_CTX_RESET;
- cmd.req.arg3 = 0;
- cmd.req.cmd = QLCNIC_CDRP_CMD_DESTROY_RX_CTX;
- qlcnic_issue_cmd(adapter, &cmd);
- if (cmd.rsp.cmd)
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX);
+ cmd.req.arg[1] = recv_ctx->context_id;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
dev_err(&adapter->pdev->dev,
"Failed to destroy rx ctx in firmware\n");
recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;
+ qlcnic_free_mbx_args(&cmd);
}
-static int
-qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring,
+ int ring)
{
struct qlcnic_hostrq_tx_ctx *prq;
struct qlcnic_hostrq_cds_ring *prq_cds;
@@ -410,7 +414,6 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
int err;
u64 phys_addr;
dma_addr_t rq_phys_addr, rsp_phys_addr;
- struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
/* reset host resources */
tx_ring->producer = 0;
@@ -445,9 +448,9 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
prq->host_int_crb_mode =
cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
+ prq->msi_index = 0;
prq->interrupt_ctl = 0;
- prq->msi_index = 0;
prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr);
prq_cds = &prq->cds_ring;
@@ -456,19 +459,17 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc);
phys_addr = rq_phys_addr;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.arg1 = (u32)(phys_addr >> 32);
- cmd.req.arg2 = ((u32)phys_addr & 0xffffffff);
- cmd.req.arg3 = rq_size;
- cmd.req.cmd = QLCNIC_CDRP_CMD_CREATE_TX_CTX;
- qlcnic_issue_cmd(adapter, &cmd);
- err = cmd.rsp.cmd;
+
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+ cmd.req.arg[1] = MSD(phys_addr);
+ cmd.req.arg[2] = LSD(phys_addr);
+ cmd.req.arg[3] = rq_size;
+ err = qlcnic_issue_cmd(adapter, &cmd);
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;
-
- adapter->tx_ring->ctx_id = le16_to_cpu(prsp->context_id);
+ tx_ring->ctx_id = le16_to_cpu(prsp->context_id);
} else {
dev_err(&adapter->pdev->dev,
"Failed to create tx ctx in firmware%d\n", err);
@@ -476,76 +477,81 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
}
dma_free_coherent(&adapter->pdev->dev, rsp_size, rsp_addr,
- rsp_phys_addr);
+ rsp_phys_addr);
out_free_rq:
dma_free_coherent(&adapter->pdev->dev, rq_size, rq_addr, rq_phys_addr);
+ qlcnic_free_mbx_args(&cmd);
return err;
}
static void
-qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
+qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring)
{
struct qlcnic_cmd_args cmd;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.arg1 = adapter->tx_ring->ctx_id;
- cmd.req.arg2 = QLCNIC_DESTROY_CTX_RESET;
- cmd.req.arg3 = 0;
- cmd.req.cmd = QLCNIC_CDRP_CMD_DESTROY_TX_CTX;
- qlcnic_issue_cmd(adapter, &cmd);
- if (cmd.rsp.cmd)
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX);
+ cmd.req.arg[1] = tx_ring->ctx_id;
+ if (qlcnic_issue_cmd(adapter, &cmd))
dev_err(&adapter->pdev->dev,
"Failed to destroy tx ctx in firmware\n");
+ qlcnic_free_mbx_args(&cmd);
}
int
qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config)
{
+ int err;
struct qlcnic_cmd_args cmd;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.arg1 = config;
- cmd.req.cmd = QLCNIC_CDRP_CMD_CONFIG_PORT;
- qlcnic_issue_cmd(adapter, &cmd);
-
- return cmd.rsp.cmd;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_PORT);
+ cmd.req.arg[1] = config;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ qlcnic_free_mbx_args(&cmd);
+ return err;
}
int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
{
void *addr;
- int err;
- int ring;
+ int err, ring;
struct qlcnic_recv_context *recv_ctx;
struct qlcnic_host_rds_ring *rds_ring;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_host_tx_ring *tx_ring;
+ __le32 *ptr;
struct pci_dev *pdev = adapter->pdev;
recv_ctx = adapter->recv_ctx;
- tx_ring = adapter->tx_ring;
- 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;
- }
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ ptr = (__le32 *)dma_alloc_coherent(&pdev->dev, sizeof(u32),
+ &tx_ring->hw_cons_phys_addr,
+ GFP_KERNEL);
- /* cmd desc ring */
- addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring),
- &tx_ring->phys_addr, GFP_KERNEL);
+ if (ptr == NULL) {
+ dev_err(&pdev->dev, "failed to allocate tx consumer\n");
+ return -ENOMEM;
+ }
+ tx_ring->hw_consumer = ptr;
+ /* cmd desc ring */
+ 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");
- err = -ENOMEM;
- goto err_out_free;
- }
+ if (addr == NULL) {
+ dev_err(&pdev->dev,
+ "failed to allocate tx desc ring\n");
+ err = -ENOMEM;
+ goto err_out_free;
+ }
- tx_ring->desc_head = addr;
+ tx_ring->desc_head = addr;
+ }
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
@@ -584,36 +590,70 @@ err_out_free:
return err;
}
-
-int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter)
+int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)
{
- int err;
+ int i, err, ring;
- if (adapter->flags & QLCNIC_NEED_FLR) {
- pci_reset_function(adapter->pdev);
- adapter->flags &= ~QLCNIC_NEED_FLR;
+ if (dev->flags & QLCNIC_NEED_FLR) {
+ pci_reset_function(dev->pdev);
+ dev->flags &= ~QLCNIC_NEED_FLR;
}
- err = qlcnic_fw_cmd_create_rx_ctx(adapter);
- if (err)
- return err;
+ if (qlcnic_83xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED)) {
+ if (dev->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+ err = qlcnic_83xx_config_intrpt(dev, 1);
+ if (err)
+ return err;
+ }
+ }
- err = qlcnic_fw_cmd_create_tx_ctx(adapter);
- if (err) {
- qlcnic_fw_cmd_destroy_rx_ctx(adapter);
- return err;
+ err = qlcnic_fw_cmd_create_rx_ctx(dev);
+ if (err)
+ goto err_out;
+
+ for (ring = 0; ring < dev->max_drv_tx_rings; ring++) {
+ err = qlcnic_fw_cmd_create_tx_ctx(dev,
+ &dev->tx_ring[ring],
+ ring);
+ if (err) {
+ qlcnic_fw_cmd_destroy_rx_ctx(dev);
+ if (ring == 0)
+ goto err_out;
+
+ for (i = 0; i < ring; i++)
+ qlcnic_fw_cmd_destroy_tx_ctx(dev,
+ &dev->tx_ring[i]);
+
+ goto err_out;
+ }
}
- set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+ set_bit(__QLCNIC_FW_ATTACHED, &dev->state);
return 0;
+
+err_out:
+ if (qlcnic_83xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED)) {
+ if (dev->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+ qlcnic_83xx_config_intrpt(dev, 0);
+ }
+ return err;
}
void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
{
+ int ring;
+
if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
qlcnic_fw_cmd_destroy_rx_ctx(adapter);
- qlcnic_fw_cmd_destroy_tx_ctx(adapter);
-
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++)
+ qlcnic_fw_cmd_destroy_tx_ctx(adapter,
+ &adapter->tx_ring[ring]);
+
+ if (qlcnic_83xx_check(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+ qlcnic_83xx_config_intrpt(adapter, 0);
+ }
/* Allow dma queues to drain after context reset */
mdelay(20);
}
@@ -629,20 +669,23 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
recv_ctx = adapter->recv_ctx;
- tx_ring = adapter->tx_ring;
- if (tx_ring->hw_consumer != NULL) {
- dma_free_coherent(&adapter->pdev->dev,
- sizeof(u32),
- tx_ring->hw_consumer,
- tx_ring->hw_cons_phys_addr);
- tx_ring->hw_consumer = NULL;
- }
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ if (tx_ring->hw_consumer != NULL) {
+ dma_free_coherent(&adapter->pdev->dev, sizeof(u32),
+ tx_ring->hw_consumer,
+ tx_ring->hw_cons_phys_addr);
- if (tx_ring->desc_head != NULL) {
- dma_free_coherent(&adapter->pdev->dev,
- TX_DESC_RINGSIZE(tx_ring),
- tx_ring->desc_head, tx_ring->phys_addr);
- tx_ring->desc_head = NULL;
+ tx_ring->hw_consumer = NULL;
+ }
+
+ if (tx_ring->desc_head != NULL) {
+ dma_free_coherent(&adapter->pdev->dev,
+ TX_DESC_RINGSIZE(tx_ring),
+ tx_ring->desc_head,
+ tx_ring->phys_addr);
+ tx_ring->desc_head = NULL;
+ }
}
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
@@ -671,40 +714,43 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
}
-/* Get MAC address of a NIC partition */
-int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
{
- int err;
+ int err, i;
struct qlcnic_cmd_args cmd;
+ u32 mac_low, mac_high;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.arg1 = adapter->ahw->pci_func | BIT_8;
- cmd.req.cmd = QLCNIC_CDRP_CMD_MAC_ADDRESS;
- cmd.rsp.arg1 = cmd.rsp.arg2 = 1;
- qlcnic_issue_cmd(adapter, &cmd);
- err = cmd.rsp.cmd;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
+ cmd.req.arg[1] = adapter->ahw->pci_func | BIT_8;
+ err = qlcnic_issue_cmd(adapter, &cmd);
- if (err == QLCNIC_RCODE_SUCCESS)
- qlcnic_fetch_mac(cmd.rsp.arg1, cmd.rsp.arg2, 0, mac);
- else {
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ mac_low = cmd.rsp.arg[1];
+ mac_high = cmd.rsp.arg[2];
+
+ for (i = 0; i < 2; i++)
+ mac[i] = (u8) (mac_high >> ((1 - i) * 8));
+ for (i = 2; i < 6; i++)
+ mac[i] = (u8) (mac_low >> ((5 - i) * 8));
+ } else {
dev_err(&adapter->pdev->dev,
"Failed to get mac address%d\n", err);
err = -EIO;
}
-
+ qlcnic_free_mbx_args(&cmd);
return err;
}
/* Get info of a NIC partition */
-int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
- struct qlcnic_info *npar_info, u8 func_id)
+int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *npar_info, u8 func_id)
{
int err;
dma_addr_t nic_dma_t;
- struct qlcnic_info_le *nic_info;
+ const struct qlcnic_info_le *nic_info;
void *nic_info_addr;
struct qlcnic_cmd_args cmd;
- size_t nic_size = sizeof(struct qlcnic_info_le);
+ size_t nic_size = sizeof(struct qlcnic_info_le);
nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
&nic_dma_t, GFP_KERNEL);
@@ -713,47 +759,39 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
memset(nic_info_addr, 0, nic_size);
nic_info = nic_info_addr;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_GET_NIC_INFO;
- cmd.req.arg1 = MSD(nic_dma_t);
- cmd.req.arg2 = LSD(nic_dma_t);
- cmd.req.arg3 = (func_id << 16 | nic_size);
- qlcnic_issue_cmd(adapter, &cmd);
- err = cmd.rsp.cmd;
- if (err == QLCNIC_RCODE_SUCCESS) {
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+ cmd.req.arg[1] = MSD(nic_dma_t);
+ cmd.req.arg[2] = LSD(nic_dma_t);
+ cmd.req.arg[3] = (func_id << 16 | nic_size);
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get nic info%d\n", err);
+ err = -EIO;
+ } else {
npar_info->pci_func = le16_to_cpu(nic_info->pci_func);
npar_info->op_mode = le16_to_cpu(nic_info->op_mode);
+ npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+ npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
- npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
- npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
-
- dev_info(&adapter->pdev->dev,
- "phy port: %d switch_mode: %d,\n"
- "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
- "\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
- npar_info->phys_port, npar_info->switch_mode,
- npar_info->max_tx_ques, npar_info->max_rx_ques,
- npar_info->min_tx_bw, npar_info->max_tx_bw,
- npar_info->max_mtu, npar_info->capabilities);
- } else {
- dev_err(&adapter->pdev->dev,
- "Failed to get nic info%d\n", err);
- err = -EIO;
}
dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
- nic_dma_t);
+ nic_dma_t);
+ qlcnic_free_mbx_args(&cmd);
+
return err;
}
/* Configure a NIC partition */
-int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
+int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *nic)
{
int err = -EIO;
dma_addr_t nic_dma_t;
@@ -784,13 +822,11 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_SET_NIC_INFO;
- cmd.req.arg1 = MSD(nic_dma_t);
- cmd.req.arg2 = LSD(nic_dma_t);
- cmd.req.arg3 = ((nic->pci_func << 16) | nic_size);
- qlcnic_issue_cmd(adapter, &cmd);
- err = cmd.rsp.cmd;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+ cmd.req.arg[1] = MSD(nic_dma_t);
+ cmd.req.arg[2] = LSD(nic_dma_t);
+ cmd.req.arg[3] = ((nic->pci_func << 16) | nic_size);
+ err = qlcnic_issue_cmd(adapter, &cmd);
if (err != QLCNIC_RCODE_SUCCESS) {
dev_err(&adapter->pdev->dev,
@@ -800,12 +836,14 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
nic_dma_t);
+ qlcnic_free_mbx_args(&cmd);
+
return err;
}
/* Get PCI Info of a partition */
-int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
- struct qlcnic_pci_info *pci_info)
+int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_pci_info *pci_info)
{
int err = 0, i;
struct qlcnic_cmd_args cmd;
@@ -822,13 +860,11 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
memset(pci_info_addr, 0, pci_size);
npar = pci_info_addr;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_GET_PCI_INFO;
- cmd.req.arg1 = MSD(pci_info_dma_t);
- cmd.req.arg2 = LSD(pci_info_dma_t);
- cmd.req.arg3 = pci_size;
- qlcnic_issue_cmd(adapter, &cmd);
- err = cmd.rsp.cmd;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
+ cmd.req.arg[1] = MSD(pci_info_dma_t);
+ cmd.req.arg[2] = LSD(pci_info_dma_t);
+ cmd.req.arg[3] = pci_size;
+ err = qlcnic_issue_cmd(adapter, &cmd);
adapter->ahw->act_pci_func = 0;
if (err == QLCNIC_RCODE_SUCCESS) {
@@ -854,6 +890,8 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr,
pci_info_dma_t);
+ qlcnic_free_mbx_args(&cmd);
+
return err;
}
@@ -872,21 +910,19 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
arg1 = id | (enable_mirroring ? BIT_4 : 0);
arg1 |= pci_func << 8;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_SET_PORTMIRRORING;
- cmd.req.arg1 = arg1;
- qlcnic_issue_cmd(adapter, &cmd);
- err = cmd.rsp.cmd;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORTMIRRORING);
+ cmd.req.arg[1] = arg1;
+ err = qlcnic_issue_cmd(adapter, &cmd);
- if (err != QLCNIC_RCODE_SUCCESS) {
+ if (err != QLCNIC_RCODE_SUCCESS)
dev_err(&adapter->pdev->dev,
"Failed to configure port mirroring%d on eswitch:%d\n",
pci_func, id);
- } else {
+ else
dev_info(&adapter->pdev->dev,
"Configured eSwitch %d for port mirroring:%d\n",
id, pci_func);
- }
+ qlcnic_free_mbx_args(&cmd);
return err;
}
@@ -923,13 +959,11 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12;
arg1 |= rx_tx << 15 | stats_size << 16;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_STATS;
- cmd.req.arg1 = arg1;
- cmd.req.arg2 = MSD(stats_dma_t);
- cmd.req.arg3 = LSD(stats_dma_t);
- qlcnic_issue_cmd(adapter, &cmd);
- err = cmd.rsp.cmd;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_ESWITCH_STATS);
+ cmd.req.arg[1] = arg1;
+ cmd.req.arg[2] = MSD(stats_dma_t);
+ cmd.req.arg[3] = LSD(stats_dma_t);
+ err = qlcnic_issue_cmd(adapter, &cmd);
if (!err) {
stats = stats_addr;
@@ -949,6 +983,8 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
stats_dma_t);
+ qlcnic_free_mbx_args(&cmd);
+
return err;
}
@@ -963,6 +999,9 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
void *stats_addr;
int err;
+ if (mac_stats == NULL)
+ return -ENOMEM;
+
stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size,
&stats_dma_t, GFP_KERNEL);
if (!stats_addr) {
@@ -971,15 +1010,11 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
return -ENOMEM;
}
memset(stats_addr, 0, stats_size);
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_GET_MAC_STATS;
- cmd.req.arg1 = stats_size << 16;
- cmd.req.arg2 = MSD(stats_dma_t);
- cmd.req.arg3 = LSD(stats_dma_t);
-
- qlcnic_issue_cmd(adapter, &cmd);
- err = cmd.rsp.cmd;
-
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_MAC_STATS);
+ cmd.req.arg[1] = stats_size << 16;
+ cmd.req.arg[2] = MSD(stats_dma_t);
+ cmd.req.arg[3] = LSD(stats_dma_t);
+ err = qlcnic_issue_cmd(adapter, &cmd);
if (!err) {
stats = stats_addr;
mac_stats->mac_tx_frames = le64_to_cpu(stats->mac_tx_frames);
@@ -1001,10 +1036,16 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
mac_stats->mac_rx_jabber = le64_to_cpu(stats->mac_rx_jabber);
mac_stats->mac_rx_dropped = le64_to_cpu(stats->mac_rx_dropped);
mac_stats->mac_rx_crc_error = le64_to_cpu(stats->mac_rx_crc_error);
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "%s: Get mac stats failed, err=%d.\n", __func__, err);
}
dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
stats_dma_t);
+
+ qlcnic_free_mbx_args(&cmd);
+
return err;
}
@@ -1065,7 +1106,7 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
const u8 port, const u8 rx_tx)
{
-
+ int err;
u32 arg1;
struct qlcnic_cmd_args cmd;
@@ -1088,15 +1129,16 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12;
arg1 |= BIT_14 | rx_tx << 15;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_STATS;
- cmd.req.arg1 = arg1;
- qlcnic_issue_cmd(adapter, &cmd);
- return cmd.rsp.cmd;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_ESWITCH_STATS);
+ cmd.req.arg[1] = arg1;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ qlcnic_free_mbx_args(&cmd);
+ return err;
err_ret:
- dev_err(&adapter->pdev->dev, "Invalid argument func_esw=%d port=%d"
- "rx_ctx=%d\n", func_esw, port, rx_tx);
+ dev_err(&adapter->pdev->dev,
+ "Invalid args func_esw %d port %d rx_ctx %d\n",
+ func_esw, port, rx_tx);
return -EIO;
}
@@ -1109,22 +1151,21 @@ __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
u8 pci_func;
pci_func = (*arg1 >> 8);
- cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG;
- cmd.req.arg1 = *arg1;
- cmd.rsp.arg1 = cmd.rsp.arg2 = 1;
- qlcnic_issue_cmd(adapter, &cmd);
- *arg1 = cmd.rsp.arg1;
- *arg2 = cmd.rsp.arg2;
- err = cmd.rsp.cmd;
+ qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG);
+ cmd.req.arg[1] = *arg1;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ *arg1 = cmd.rsp.arg[1];
+ *arg2 = cmd.rsp.arg[2];
+ qlcnic_free_mbx_args(&cmd);
- if (err == QLCNIC_RCODE_SUCCESS) {
+ if (err == QLCNIC_RCODE_SUCCESS)
dev_info(&adapter->pdev->dev,
- "eSwitch port config for pci func %d\n", pci_func);
- } else {
+ "eSwitch port config for pci func %d\n", pci_func);
+ else
dev_err(&adapter->pdev->dev,
"Failed to get eswitch port config for pci func %d\n",
pci_func);
- }
return err;
}
/* Configure eSwitch port
@@ -1189,20 +1230,18 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
return err;
}
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH;
- cmd.req.arg1 = arg1;
- cmd.req.arg2 = arg2;
- qlcnic_issue_cmd(adapter, &cmd);
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_ESWITCH);
+ cmd.req.arg[1] = arg1;
+ cmd.req.arg[2] = arg2;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ qlcnic_free_mbx_args(&cmd);
- err = cmd.rsp.cmd;
- if (err != QLCNIC_RCODE_SUCCESS) {
+ if (err != QLCNIC_RCODE_SUCCESS)
dev_err(&adapter->pdev->dev,
"Failed to configure eswitch pci func %d\n", pci_func);
- } else {
+ else
dev_info(&adapter->pdev->dev,
- "Configured eSwitch for pci func %d\n", pci_func);
- }
+ "Configured eSwitch for pci func %d\n", pci_func);
return err;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 74b98110c5b4..5641f8ec49ab 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -1,6 +1,6 @@
/*
* QLogic qlcnic NIC Driver
- * Copyright (c) 2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
*
* See LICENSE.qlcnic for copyright and licensing details.
*/
@@ -22,42 +22,37 @@ struct qlcnic_stats {
#define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m)
#define QLC_OFF(m) offsetof(struct qlcnic_adapter, m)
+static const u32 qlcnic_fw_dump_level[] = {
+ 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff
+};
static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
- {"xmit_called",
- QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)},
- {"xmit_finished",
- QLC_SIZEOF(stats.xmitfinished), QLC_OFF(stats.xmitfinished)},
- {"rx_dropped",
- QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
- {"tx_dropped",
- QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
- {"csummed",
- QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
- {"rx_pkts",
- QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
- {"lro_pkts",
- QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
- {"rx_bytes",
- QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
- {"tx_bytes",
- QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
- {"lrobytes",
- QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
- {"lso_frames",
- QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
- {"xmit_on",
- QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
- {"xmit_off",
- QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
+ {"xmit_called", QLC_SIZEOF(stats.xmitcalled),
+ QLC_OFF(stats.xmitcalled)},
+ {"xmit_finished", QLC_SIZEOF(stats.xmitfinished),
+ QLC_OFF(stats.xmitfinished)},
+ {"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
+ {"tx_dropped", QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
+ {"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
+ {"rx_pkts", QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
+ {"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
+ {"rx_bytes", QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
+ {"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
+ {"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
+ {"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
+ {"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
+ {"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
{"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
- QLC_OFF(stats.skb_alloc_failure)},
- {"null rxbuf",
- QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
+ QLC_OFF(stats.skb_alloc_failure)},
+ {"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
{"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
QLC_OFF(stats.rx_dma_map_error)},
{"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
QLC_OFF(stats.tx_dma_map_error)},
+ {"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
+ QLC_OFF(stats.mac_filter_limit_overrun)},
+ {"spurious intr", QLC_SIZEOF(stats.spurious_intr),
+ QLC_OFF(stats.spurious_intr)},
};
@@ -78,7 +73,15 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx numbytes",
};
-static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
+static const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = {
+ "ctx_tx_bytes",
+ "ctx_tx_pkts",
+ "ctx_tx_errors",
+ "ctx_tx_dropped_pkts",
+ "ctx_tx_num_buffers",
+};
+
+static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
"mac_tx_frames",
"mac_tx_bytes",
"mac_tx_mcast_pkts",
@@ -110,35 +113,70 @@ static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
"mac_rx_length_large",
"mac_rx_jabber",
"mac_rx_dropped",
- "mac_rx_crc_error",
+ "mac_crc_error",
"mac_align_error",
};
-#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
-#define QLCNIC_MAC_STATS_LEN ARRAY_SIZE(qlcnic_mac_stats_strings)
-#define QLCNIC_DEVICE_STATS_LEN ARRAY_SIZE(qlcnic_device_gstrings_stats)
-#define QLCNIC_TOTAL_STATS_LEN QLCNIC_STATS_LEN + QLCNIC_MAC_STATS_LEN
+#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
+static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
+ "ctx_rx_bytes",
+ "ctx_rx_pkts",
+ "ctx_lro_pkt_cnt",
+ "ctx_ip_csum_error",
+ "ctx_rx_pkts_wo_ctx",
+ "ctx_rx_pkts_dropped_wo_sts",
+ "ctx_rx_osized_pkts",
+ "ctx_rx_pkts_dropped_wo_rds",
+ "ctx_rx_unexpected_mcast_pkts",
+ "ctx_invalid_mac_address",
+ "ctx_rx_rds_ring_prim_attemoted",
+ "ctx_rx_rds_ring_prim_success",
+ "ctx_num_lro_flows_added",
+ "ctx_num_lro_flows_removed",
+ "ctx_num_lro_flows_active",
+ "ctx_pkts_dropped_unknown",
+};
static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_on_offline",
"Link_Test_on_offline",
"Interrupt_Test_offline",
"Internal_Loopback_offline",
- "External_Loopback_offline"
+ "EEPROM_Test_offline"
};
#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
+static inline int qlcnic_82xx_statistics(void)
+{
+ return QLCNIC_STATS_LEN + ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+}
+
+static inline int qlcnic_83xx_statistics(void)
+{
+ return ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) +
+ ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) +
+ ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
+}
+
+static int qlcnic_dev_statistics_len(struct qlcnic_adapter *adapter)
+{
+ if (qlcnic_82xx_check(adapter))
+ return qlcnic_82xx_statistics();
+ else if (qlcnic_83xx_check(adapter))
+ return qlcnic_83xx_statistics();
+ else
+ return -1;
+}
+
#define QLCNIC_RING_REGS_COUNT 20
#define QLCNIC_RING_REGS_LEN (QLCNIC_RING_REGS_COUNT * sizeof(u32))
#define QLCNIC_MAX_EEPROM_LEN 1024
static const u32 diag_registers[] = {
- CRB_CMDPEG_STATE,
- CRB_RCVPEG_STATE,
- CRB_XG_STATE_P3P,
- CRB_FW_CAPABILITIES_1,
- ISR_INT_STATE_REG,
+ QLCNIC_CMDPEG_STATE,
+ QLCNIC_RCVPEG_STATE,
+ QLCNIC_FW_CAPABILITIES,
QLCNIC_CRB_DRV_ACTIVE,
QLCNIC_CRB_DEV_STATE,
QLCNIC_CRB_DRV_STATE,
@@ -148,6 +186,13 @@ static const u32 diag_registers[] = {
QLCNIC_PEG_ALIVE_COUNTER,
QLCNIC_PEG_HALT_STATUS1,
QLCNIC_PEG_HALT_STATUS2,
+ -1
+};
+
+
+static const u32 ext_diag_registers[] = {
+ CRB_XG_STATE_P3P,
+ ISR_INT_STATE_REG,
QLCNIC_CRB_PEG_NET_0+0x3c,
QLCNIC_CRB_PEG_NET_1+0x3c,
QLCNIC_CRB_PEG_NET_2+0x3c,
@@ -156,12 +201,19 @@ static const u32 diag_registers[] = {
};
#define QLCNIC_MGMT_API_VERSION 2
-#define QLCNIC_DEV_INFO_SIZE 1
-#define QLCNIC_ETHTOOL_REGS_VER 2
+#define QLCNIC_ETHTOOL_REGS_VER 3
+
static int qlcnic_get_regs_len(struct net_device *dev)
{
- return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
- QLCNIC_DEV_INFO_SIZE + 1;
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ u32 len;
+
+ if (qlcnic_83xx_check(adapter))
+ len = qlcnic_83xx_get_regs_len(adapter);
+ else
+ len = sizeof(ext_diag_registers) + sizeof(diag_registers);
+
+ return QLCNIC_RING_REGS_LEN + len + QLCNIC_DEV_INFO_SIZE + 1;
}
static int qlcnic_get_eeprom_len(struct net_device *dev)
@@ -174,10 +226,9 @@ qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 fw_major, fw_minor, fw_build;
-
- fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
- fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
- fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+ fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+ fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+ fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
"%d.%d.%d", fw_major, fw_minor, fw_build);
@@ -192,7 +243,10 @@ static int
qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ u32 speed, reg;
int check_sfp_module = 0;
+ u16 pcifn = ahw->pci_func;
/* read which mode */
if (adapter->ahw->port_type == QLCNIC_GBE) {
@@ -213,9 +267,12 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->autoneg = adapter->ahw->link_autoneg;
} else if (adapter->ahw->port_type == QLCNIC_XGBE) {
- u32 val;
+ u32 val = 0;
+ if (qlcnic_83xx_check(adapter))
+ qlcnic_83xx_get_settings(adapter);
+ else
+ val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
- val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
if (val == QLCNIC_PORT_MODE_802_3_AP) {
ecmd->supported = SUPPORTED_1000baseT_Full;
ecmd->advertising = ADVERTISED_1000baseT_Full;
@@ -225,6 +282,12 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
}
if (netif_running(dev) && adapter->ahw->has_link_events) {
+ if (qlcnic_82xx_check(adapter)) {
+ reg = QLCRD32(adapter,
+ P3P_LINK_SPEED_REG(pcifn));
+ speed = P3P_LINK_SPEED_VAL(pcifn, reg);
+ ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
+ }
ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
ecmd->autoneg = adapter->ahw->link_autoneg;
ecmd->duplex = adapter->ahw->link_duplex;
@@ -294,6 +357,13 @@ skip:
ecmd->port = PORT_TP;
}
break;
+ case QLCNIC_BRDTYPE_83XX_10G:
+ ecmd->autoneg = AUTONEG_DISABLE;
+ ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
+ ecmd->advertising |= (ADVERTISED_FIBRE | ADVERTISED_TP);
+ ecmd->port = PORT_FIBRE;
+ check_sfp_module = netif_running(dev) && ahw->has_link_events;
+ break;
default:
dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
adapter->ahw->board_type);
@@ -321,16 +391,10 @@ skip:
return 0;
}
-static int
-qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+static int qlcnic_set_port_config(struct qlcnic_adapter *adapter,
+ struct ethtool_cmd *ecmd)
{
- u32 config = 0;
- u32 ret = 0;
- struct qlcnic_adapter *adapter = netdev_priv(dev);
-
- if (adapter->ahw->port_type != QLCNIC_GBE)
- return -EOPNOTSUPP;
-
+ u32 ret = 0, config = 0;
/* read which mode */
if (ecmd->duplex)
config |= 0x1;
@@ -358,6 +422,24 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
return -EOPNOTSUPP;
else if (ret)
return -EIO;
+ return ret;
+}
+
+static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ u32 ret = 0;
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+ if (adapter->ahw->port_type != QLCNIC_GBE)
+ return -EOPNOTSUPP;
+
+ if (qlcnic_83xx_check(adapter))
+ ret = qlcnic_83xx_set_settings(adapter, ecmd);
+ else
+ ret = qlcnic_set_port_config(adapter, ecmd);
+
+ if (!ret)
+ return ret;
adapter->ahw->link_speed = ethtool_cmd_speed(ecmd);
adapter->ahw->link_duplex = ecmd->duplex;
@@ -370,6 +452,19 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
return dev->netdev_ops->ndo_open(dev);
}
+static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter,
+ u32 *regs_buff)
+{
+ int i, j = 0;
+
+ for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
+ regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]);
+ j = 0;
+ while (ext_diag_registers[j] != -1)
+ regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++]);
+ return i;
+}
+
static void
qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
{
@@ -377,17 +472,20 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
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;
+ int ring, i = 0;
memset(p, 0, qlcnic_get_regs_len(dev));
+
regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
(adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
regs_buff[1] = QLCNIC_MGMT_API_VERSION;
- for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
- regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
+ if (qlcnic_82xx_check(adapter))
+ i = qlcnic_82xx_get_registers(adapter, regs_buff);
+ else
+ i = qlcnic_83xx_get_registers(adapter, regs_buff);
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
return;
@@ -415,6 +513,10 @@ static u32 qlcnic_test_link(struct net_device *dev)
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 val;
+ if (qlcnic_83xx_check(adapter)) {
+ val = qlcnic_83xx_test_link(adapter);
+ return (val & 1) ? 0 : 1;
+ }
val = QLCRD32(adapter, CRB_XG_STATE_P3P);
val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
return (val == XG_LINK_UP_P3P) ? 0 : 1;
@@ -426,8 +528,10 @@ qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
int offset;
- int ret;
+ int ret = -1;
+ if (qlcnic_83xx_check(adapter))
+ return 0;
if (eeprom->len == 0)
return -EINVAL;
@@ -435,8 +539,9 @@ qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
((adapter->pdev)->device << 16);
offset = eeprom->offset;
- ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
- eeprom->len);
+ if (qlcnic_82xx_check(adapter))
+ ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
+ eeprom->len);
if (ret < 0)
return ret;
@@ -529,11 +634,11 @@ static int qlcnic_set_channels(struct net_device *dev,
channel->tx_count != channel->max_tx)
return -EINVAL;
- err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
+ err = qlcnic_validate_max_rss(channel->max_rx, channel->rx_count);
if (err)
return err;
- err = qlcnic_set_max_rss(adapter, channel->rx_count);
+ err = qlcnic_set_max_rss(adapter, channel->rx_count, 0);
netdev_info(dev, "allocated 0x%x sds rings\n",
adapter->max_sds_rings);
return err;
@@ -547,6 +652,10 @@ qlcnic_get_pauseparam(struct net_device *netdev,
int port = adapter->ahw->physical_port;
__u32 val;
+ if (qlcnic_83xx_check(adapter)) {
+ qlcnic_83xx_get_pauseparam(adapter, pause);
+ return;
+ }
if (adapter->ahw->port_type == QLCNIC_GBE) {
if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
return;
@@ -592,6 +701,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
int port = adapter->ahw->physical_port;
__u32 val;
+ if (qlcnic_83xx_check(adapter))
+ return qlcnic_83xx_set_pauseparam(adapter, pause);
+
/* read mode */
if (adapter->ahw->port_type == QLCNIC_GBE) {
if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
@@ -606,6 +718,7 @@ qlcnic_set_pauseparam(struct net_device *netdev,
QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
val);
+ QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
/* set autoneg */
val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
switch (port) {
@@ -668,6 +781,9 @@ static int qlcnic_reg_test(struct net_device *dev)
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 data_read;
+ if (qlcnic_83xx_check(adapter))
+ return qlcnic_83xx_reg_test(adapter);
+
data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
if ((data_read & 0xffff) != adapter->pdev->vendor)
return 1;
@@ -675,16 +791,30 @@ static int qlcnic_reg_test(struct net_device *dev)
return 0;
}
+static int qlcnic_eeprom_test(struct net_device *dev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+ if (qlcnic_82xx_check(adapter))
+ return 0;
+
+ return qlcnic_83xx_flash_test(adapter);
+}
+
static int qlcnic_get_sset_count(struct net_device *dev, int sset)
{
+ int len;
+
struct qlcnic_adapter *adapter = netdev_priv(dev);
switch (sset) {
case ETH_SS_TEST:
return QLCNIC_TEST_LEN;
case ETH_SS_STATS:
- if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
- return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
- return QLCNIC_TOTAL_STATS_LEN;
+ len = qlcnic_dev_statistics_len(adapter) + QLCNIC_STATS_LEN;
+ if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+ qlcnic_83xx_check(adapter))
+ return len;
+ return qlcnic_82xx_statistics();
default:
return -EOPNOTSUPP;
}
@@ -693,35 +823,36 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)
static int qlcnic_irq_test(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
- int max_sds_rings = adapter->max_sds_rings;
- int ret;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
struct qlcnic_cmd_args cmd;
+ int ret, max_sds_rings = adapter->max_sds_rings;
+
+ if (qlcnic_83xx_check(adapter))
+ return qlcnic_83xx_interrupt_test(netdev);
if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
return -EIO;
ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
if (ret)
- goto clear_it;
+ goto clear_diag_irq;
- adapter->ahw->diag_cnt = 0;
- memset(&cmd, 0, sizeof(cmd));
- cmd.req.cmd = QLCNIC_CDRP_CMD_INTRPT_TEST;
- cmd.req.arg1 = adapter->ahw->pci_func;
- qlcnic_issue_cmd(adapter, &cmd);
- ret = cmd.rsp.cmd;
+ ahw->diag_cnt = 0;
+ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
+ cmd.req.arg[1] = ahw->pci_func;
+ ret = qlcnic_issue_cmd(adapter, &cmd);
if (ret)
goto done;
- msleep(10);
-
- ret = !adapter->ahw->diag_cnt;
+ usleep_range(1000, 12000);
+ ret = !ahw->diag_cnt;
done:
+ qlcnic_free_mbx_args(&cmd);
qlcnic_diag_free_res(netdev, max_sds_rings);
-clear_it:
+clear_diag_irq:
adapter->max_sds_rings = max_sds_rings;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
return ret;
@@ -750,7 +881,7 @@ int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
}
-static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
+int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
{
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
@@ -761,11 +892,10 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
skb_put(skb, QLCNIC_ILB_PKT_SIZE);
-
adapter->ahw->diag_cnt = 0;
qlcnic_xmit_frame(skb, adapter->netdev);
-
loop = 0;
+
do {
msleep(1);
qlcnic_process_rcv_ring_diag(sds_ring);
@@ -776,42 +906,46 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
dev_kfree_skb_any(skb);
if (!adapter->ahw->diag_cnt)
- QLCDB(adapter, DRV,
- "LB Test: packet #%d was not received\n", i + 1);
+ dev_warn(&adapter->pdev->dev,
+ "LB Test: packet #%d was not received\n",
+ i + 1);
else
cnt++;
}
if (cnt != i) {
- dev_warn(&adapter->pdev->dev, "LB Test failed\n");
- if (mode != QLCNIC_ILB_MODE) {
+ dev_err(&adapter->pdev->dev,
+ "LB Test: failed, TX[%d], RX[%d]\n", i, cnt);
+ if (mode != QLCNIC_ILB_MODE)
dev_warn(&adapter->pdev->dev,
- "WARNING: Please make sure external"
- "loopback connector is plugged in\n");
- }
+ "WARNING: Please check loopback cable\n");
return -1;
}
return 0;
}
-static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
+int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int max_sds_rings = adapter->max_sds_rings;
struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
int loop = 0;
int ret;
- if (!(adapter->ahw->capabilities &
- QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
- netdev_info(netdev, "Firmware is not loopback test capable\n");
+ if (qlcnic_83xx_check(adapter))
+ return qlcnic_83xx_loopback_test(netdev, mode);
+
+ if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
+ dev_info(&adapter->pdev->dev,
+ "Firmware do not support loopback test\n");
return -EOPNOTSUPP;
}
- QLCDB(adapter, DRV, "%s loopback test in progress\n",
- mode == QLCNIC_ILB_MODE ? "internal" : "external");
- if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
- netdev_warn(netdev, "Loopback test not supported for non "
- "privilege function\n");
+ dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n",
+ mode == QLCNIC_ILB_MODE ? "internal" : "external");
+ if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+ dev_warn(&adapter->pdev->dev,
+ "Loopback test not supported in nonprivileged mode\n");
return 0;
}
@@ -823,12 +957,11 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
goto clear_it;
sds_ring = &adapter->recv_ctx->sds_rings[0];
-
ret = qlcnic_set_lb_mode(adapter, mode);
if (ret)
goto free_res;
- adapter->ahw->diag_cnt = 0;
+ ahw->diag_cnt = 0;
do {
msleep(500);
qlcnic_process_rcv_ring_diag(sds_ring);
@@ -841,11 +974,11 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
ret = adapter->ahw->diag_cnt;
goto free_res;
}
- } while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
+ } while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state));
ret = qlcnic_do_lb_test(adapter, mode);
- qlcnic_clear_lb_mode(adapter);
+ qlcnic_clear_lb_mode(adapter, mode);
free_res:
qlcnic_diag_free_res(netdev, max_sds_rings);
@@ -878,20 +1011,18 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
if (data[3])
eth_test->flags |= ETH_TEST_FL_FAILED;
- if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
- data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
- if (data[4])
- eth_test->flags |= ETH_TEST_FL_FAILED;
- eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
- }
+
+ data[4] = qlcnic_eeprom_test(dev);
+ if (data[4])
+ eth_test->flags |= ETH_TEST_FL_FAILED;
}
}
static void
-qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
- int index, i, j;
+ int index, i, num_stats;
switch (stringset) {
case ETH_SS_TEST:
@@ -904,14 +1035,34 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
qlcnic_gstrings_stats[index].stat_string,
ETH_GSTRING_LEN);
}
- for (j = 0; j < QLCNIC_MAC_STATS_LEN; index++, j++) {
- memcpy(data + index * ETH_GSTRING_LEN,
- qlcnic_mac_stats_strings[j],
- ETH_GSTRING_LEN);
+ if (qlcnic_83xx_check(adapter)) {
+ num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
+ for (i = 0; i < num_stats; i++, index++)
+ memcpy(data + index * ETH_GSTRING_LEN,
+ qlcnic_83xx_tx_stats_strings[i],
+ ETH_GSTRING_LEN);
+ num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+ for (i = 0; i < num_stats; i++, index++)
+ memcpy(data + index * ETH_GSTRING_LEN,
+ qlcnic_83xx_mac_stats_strings[i],
+ ETH_GSTRING_LEN);
+ num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
+ for (i = 0; i < num_stats; i++, index++)
+ memcpy(data + index * ETH_GSTRING_LEN,
+ qlcnic_83xx_rx_stats_strings[i],
+ ETH_GSTRING_LEN);
+ return;
+ } else {
+ num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+ for (i = 0; i < num_stats; i++, index++)
+ memcpy(data + index * ETH_GSTRING_LEN,
+ qlcnic_83xx_mac_stats_strings[i],
+ ETH_GSTRING_LEN);
}
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
- for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
+ num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats);
+ for (i = 0; i < num_stats; index++, i++) {
memcpy(data + index * ETH_GSTRING_LEN,
qlcnic_device_gstrings_stats[i],
ETH_GSTRING_LEN);
@@ -920,89 +1071,84 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
static void
-qlcnic_fill_stats(int *index, u64 *data, void *stats, int type)
+qlcnic_fill_stats(u64 *data, void *stats, int type)
{
- int ind = *index;
-
if (type == QLCNIC_MAC_STATS) {
struct qlcnic_mac_statistics *mac_stats =
(struct qlcnic_mac_statistics *)stats;
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
- data[ind++] =
- QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
- data[ind++] =
- QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
- data[ind++] =
- QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
- data[ind++] =
- QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
- data[ind++] =
- QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
- data[ind++] =
- QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
- data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
+ *data++ = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
} else if (type == QLCNIC_ESW_STATS) {
struct __qlcnic_esw_statistics *esw_stats =
(struct __qlcnic_esw_statistics *)stats;
- data[ind++] = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
- data[ind++] = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
- data[ind++] = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
- data[ind++] = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
- data[ind++] = QLCNIC_FILL_STATS(esw_stats->errors);
- data[ind++] = QLCNIC_FILL_STATS(esw_stats->local_frames);
- data[ind++] = QLCNIC_FILL_STATS(esw_stats->numbytes);
+ *data++ = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
+ *data++ = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
+ *data++ = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
+ *data++ = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
+ *data++ = QLCNIC_FILL_STATS(esw_stats->errors);
+ *data++ = QLCNIC_FILL_STATS(esw_stats->local_frames);
+ *data++ = QLCNIC_FILL_STATS(esw_stats->numbytes);
}
-
- *index = ind;
}
-static void
-qlcnic_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats, u64 * data)
+static void qlcnic_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
struct qlcnic_esw_statistics port_stats;
struct qlcnic_mac_statistics mac_stats;
- int index, ret;
-
- for (index = 0; index < QLCNIC_STATS_LEN; index++) {
- char *p =
- (char *)adapter +
- qlcnic_gstrings_stats[index].stat_offset;
- data[index] =
- (qlcnic_gstrings_stats[index].sizeof_stat ==
- sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
+ int index, ret, length, size;
+ char *p;
+
+ memset(data, 0, stats->n_stats * sizeof(u64));
+ length = QLCNIC_STATS_LEN;
+ for (index = 0; index < length; index++) {
+ p = (char *)adapter + qlcnic_gstrings_stats[index].stat_offset;
+ size = qlcnic_gstrings_stats[index].sizeof_stat;
+ *data++ = (size == sizeof(u64)) ? (*(u64 *)p) : ((*(u32 *)p));
}
- /* Retrieve MAC statistics from firmware */
- memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
- qlcnic_get_mac_stats(adapter, &mac_stats);
- qlcnic_fill_stats(&index, data, &mac_stats, QLCNIC_MAC_STATS);
+ if (qlcnic_83xx_check(adapter)) {
+ if (adapter->ahw->linkup)
+ qlcnic_83xx_get_stats(adapter, data);
+ return;
+ } else {
+ /* Retrieve MAC statistics from firmware */
+ memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
+ qlcnic_get_mac_stats(adapter, &mac_stats);
+ qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
+ }
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
@@ -1013,14 +1159,13 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
if (ret)
return;
- qlcnic_fill_stats(&index, data, &port_stats.rx, QLCNIC_ESW_STATS);
-
+ qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
if (ret)
return;
- qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS);
+ qlcnic_fill_stats(data, &port_stats.tx, QLCNIC_ESW_STATS);
}
static int qlcnic_set_led(struct net_device *dev,
@@ -1030,6 +1175,8 @@ static int qlcnic_set_led(struct net_device *dev,
int max_sds_rings = adapter->max_sds_rings;
int err = -EIO, active = 1;
+ if (qlcnic_83xx_check(adapter))
+ return -EOPNOTSUPP;
if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
netdev_warn(dev, "LED test not supported for non "
"privilege function\n");
@@ -1096,6 +1243,8 @@ qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 wol_cfg;
+ if (qlcnic_83xx_check(adapter))
+ return;
wol->supported = 0;
wol->wolopts = 0;
@@ -1114,8 +1263,10 @@ qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct qlcnic_adapter *adapter = netdev_priv(dev);
u32 wol_cfg;
- if (wol->wolopts & ~WAKE_MAGIC)
+ if (qlcnic_83xx_check(adapter))
return -EOPNOTSUPP;
+ if (wol->wolopts & ~WAKE_MAGIC)
+ return -EINVAL;
wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
if (!(wol_cfg & (1 << adapter->portnum)))
@@ -1307,7 +1458,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
return 0;
}
netdev_info(netdev, "Forcing a FW dump\n");
- qlcnic_dev_request_reset(adapter);
+ qlcnic_dev_request_reset(adapter, val->flag);
break;
case QLCNIC_DISABLE_FW_DUMP:
if (fw_dump->enable && fw_dump->tmpl_hdr) {
@@ -1327,7 +1478,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
return 0;
case QLCNIC_FORCE_FW_RESET:
netdev_info(netdev, "Forcing a FW reset\n");
- qlcnic_dev_request_reset(adapter);
+ qlcnic_dev_request_reset(adapter, val->flag);
adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
return 0;
case QLCNIC_SET_QUIESCENT:
@@ -1341,8 +1492,8 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
netdev_err(netdev, "FW dump not supported\n");
return -ENOTSUPP;
}
- for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) {
- if (val->flag == FW_DUMP_LEVELS[i]) {
+ for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) {
+ if (val->flag == qlcnic_fw_dump_level[i]) {
fw_dump->tmpl_hdr->drv_cap_mask =
val->flag;
netdev_info(netdev, "Driver mask changed to: 0x%x\n",
@@ -1386,10 +1537,3 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
.get_dump_data = qlcnic_get_dump_data,
.set_dump = qlcnic_set_dump,
};
-
-const struct ethtool_ops qlcnic_ethtool_failed_ops = {
- .get_settings = qlcnic_get_settings,
- .get_drvinfo = qlcnic_get_drvinfo,
- .set_msglevel = qlcnic_set_msglevel,
- .get_msglevel = qlcnic_get_msglevel,
-};
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
index 49cc1ac4f057..44197ca1456c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
@@ -1,6 +1,6 @@
/*
* QLogic qlcnic NIC Driver
- * Copyright (c) 2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
*
* See LICENSE.qlcnic for copyright and licensing details.
*/
@@ -11,6 +11,8 @@
#include <linux/kernel.h>
#include <linux/types.h>
+#include "qlcnic_hw.h"
+
/*
* The basic unit of access when reading/writing control registers.
*/
@@ -387,9 +389,6 @@ enum {
#define QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014)
#define QLCNIC_ROMUSB_ROM_RDATA (ROMUSB_ROM + 0x0018)
-/* Lock IDs for ROM lock */
-#define ROM_LOCK_DRIVER 0x0d417340
-
/******************************************************************************
*
* Definitions specific to M25P flash
@@ -449,13 +448,10 @@ enum {
#define ISR_INT_TARGET_STATUS_F7 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F7))
#define ISR_INT_TARGET_MASK_F7 (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F7))
-#define QLCNIC_PCI_MN_2M (0)
-#define QLCNIC_PCI_MS_2M (0x80000)
#define QLCNIC_PCI_OCM0_2M (0x000c0000UL)
#define QLCNIC_PCI_CRBSPACE (0x06000000UL)
#define QLCNIC_PCI_CAMQM (0x04800000UL)
#define QLCNIC_PCI_CAMQM_END (0x04800800UL)
-#define QLCNIC_PCI_2MB_SIZE (0x00200000UL)
#define QLCNIC_PCI_CAMQM_2M_BASE (0x000ff800UL)
#define QLCNIC_CRB_CAM QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_CAM)
@@ -491,7 +487,7 @@ enum {
#define QLCNIC_NIU_GB_MAC_CONFIG_1(I) \
(QLCNIC_CRB_NIU + 0x30004 + (I)*0x10000)
-
+#define MAX_CTL_CHECK 1000
#define TEST_AGT_CTRL (0x00)
#define TA_CTL_START BIT_0
@@ -499,44 +495,6 @@ enum {
#define TA_CTL_WRITE BIT_2
#define TA_CTL_BUSY BIT_3
-/*
- * Register offsets for MN
- */
-#define MIU_TEST_AGT_BASE (0x90)
-
-#define MIU_TEST_AGT_ADDR_LO (0x04)
-#define MIU_TEST_AGT_ADDR_HI (0x08)
-#define MIU_TEST_AGT_WRDATA_LO (0x10)
-#define MIU_TEST_AGT_WRDATA_HI (0x14)
-#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x20)
-#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x24)
-#define MIU_TEST_AGT_WRDATA(i) (0x10+(0x10*((i)>>1))+(4*((i)&1)))
-#define MIU_TEST_AGT_RDDATA_LO (0x18)
-#define MIU_TEST_AGT_RDDATA_HI (0x1c)
-#define MIU_TEST_AGT_RDDATA_UPPER_LO (0x28)
-#define MIU_TEST_AGT_RDDATA_UPPER_HI (0x2c)
-#define MIU_TEST_AGT_RDDATA(i) (0x18+(0x10*((i)>>1))+(4*((i)&1)))
-
-#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8
-#define MIU_TEST_AGT_UPPER_ADDR(off) (0)
-
-/*
- * Register offsets for MS
- */
-#define SIU_TEST_AGT_BASE (0x60)
-
-#define SIU_TEST_AGT_ADDR_LO (0x04)
-#define SIU_TEST_AGT_ADDR_HI (0x18)
-#define SIU_TEST_AGT_WRDATA_LO (0x08)
-#define SIU_TEST_AGT_WRDATA_HI (0x0c)
-#define SIU_TEST_AGT_WRDATA(i) (0x08+(4*(i)))
-#define SIU_TEST_AGT_RDDATA_LO (0x10)
-#define SIU_TEST_AGT_RDDATA_HI (0x14)
-#define SIU_TEST_AGT_RDDATA(i) (0x10+(4*(i)))
-
-#define SIU_TEST_AGT_ADDR_MASK 0x3ffff8
-#define SIU_TEST_AGT_UPPER_ADDR(off) ((off)>>22)
-
/* XG Link status */
#define XG_LINK_UP 0x10
#define XG_LINK_DOWN 0x20
@@ -556,9 +514,6 @@ enum {
#define QLCNIC_CAM_RAM_BASE (QLCNIC_CRB_CAM + 0x02000)
#define QLCNIC_CAM_RAM(reg) (QLCNIC_CAM_RAM_BASE + (reg))
-#define QLCNIC_FW_VERSION_MAJOR (QLCNIC_CAM_RAM(0x150))
-#define QLCNIC_FW_VERSION_MINOR (QLCNIC_CAM_RAM(0x154))
-#define QLCNIC_FW_VERSION_SUB (QLCNIC_CAM_RAM(0x158))
#define QLCNIC_ROM_LOCK_ID (QLCNIC_CAM_RAM(0x100))
#define QLCNIC_PHY_LOCK_ID (QLCNIC_CAM_RAM(0x120))
#define QLCNIC_CRB_WIN_LOCK_ID (QLCNIC_CAM_RAM(0x124))
@@ -568,28 +523,17 @@ enum {
#define QLCNIC_REG(X) (NIC_CRB_BASE+(X))
#define QLCNIC_REG_2(X) (NIC_CRB_BASE_2+(X))
+#define QLCNIC_CDRP_MAX_ARGS 4
+#define QLCNIC_CDRP_ARG(i) (QLCNIC_REG(0x18 + ((i) * 4)))
+
#define QLCNIC_CDRP_CRB_OFFSET (QLCNIC_REG(0x18))
-#define QLCNIC_ARG1_CRB_OFFSET (QLCNIC_REG(0x1c))
-#define QLCNIC_ARG2_CRB_OFFSET (QLCNIC_REG(0x20))
-#define QLCNIC_ARG3_CRB_OFFSET (QLCNIC_REG(0x24))
#define QLCNIC_SIGN_CRB_OFFSET (QLCNIC_REG(0x28))
-#define CRB_CMDPEG_STATE (QLCNIC_REG(0x50))
-#define CRB_RCVPEG_STATE (QLCNIC_REG(0x13c))
-
#define CRB_XG_STATE_P3P (QLCNIC_REG(0x98))
#define CRB_PF_LINK_SPEED_1 (QLCNIC_REG(0xe8))
-#define CRB_PF_LINK_SPEED_2 (QLCNIC_REG(0xec))
-
-#define CRB_TEMP_STATE (QLCNIC_REG(0x1b4))
-
-#define CRB_V2P_0 (QLCNIC_REG(0x290))
-#define CRB_V2P(port) (CRB_V2P_0+((port)*4))
#define CRB_DRIVER_VERSION (QLCNIC_REG(0x2a0))
-#define CRB_FW_CAPABILITIES_1 (QLCNIC_CAM_RAM(0x128))
#define CRB_FW_CAPABILITIES_2 (QLCNIC_CAM_RAM(0x12c))
-#define CRB_MAC_BLOCK_START (QLCNIC_CAM_RAM(0x1c0))
/*
* CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address
@@ -616,11 +560,6 @@ enum {
/* Lock IDs for PHY lock */
#define PHY_LOCK_DRIVER 0x44524956
-/* Used for PS PCI Memory access */
-#define PCIX_PS_OP_ADDR_LO (0x10000)
-/* via CRB (PS side only) */
-#define PCIX_PS_OP_ADDR_HI (0x10004)
-
#define PCIX_INT_VECTOR (0x10100)
#define PCIX_INT_MASK (0x10104)
@@ -682,17 +621,6 @@ enum {
#define QLCNIC_PEG_TUNE_CAPABILITY (QLCNIC_CAM_RAM(0x02c))
#define QLCNIC_DMA_WATCHDOG_CTRL (QLCNIC_CAM_RAM(0x14))
-#define QLCNIC_PEG_ALIVE_COUNTER (QLCNIC_CAM_RAM(0xb0))
-#define QLCNIC_PEG_HALT_STATUS1 (QLCNIC_CAM_RAM(0xa8))
-#define QLCNIC_PEG_HALT_STATUS2 (QLCNIC_CAM_RAM(0xac))
-#define QLCNIC_CRB_DRV_ACTIVE (QLCNIC_CAM_RAM(0x138))
-#define QLCNIC_CRB_DEV_STATE (QLCNIC_CAM_RAM(0x140))
-
-#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144))
-#define QLCNIC_CRB_DRV_SCRATCH (QLCNIC_CAM_RAM(0x148))
-#define QLCNIC_CRB_DEV_PARTITION_INFO (QLCNIC_CAM_RAM(0x14c))
-#define QLCNIC_CRB_DRV_IDC_VER (QLCNIC_CAM_RAM(0x174))
-#define QLCNIC_CRB_DEV_NPAR_STATE (QLCNIC_CAM_RAM(0x19c))
#define QLCNIC_ROM_DEV_INIT_TIMEOUT (0x3e885c)
#define QLCNIC_ROM_DRV_RESET_TIMEOUT (0x3e8860)
@@ -711,7 +639,6 @@ enum {
#define QLCNIC_DEV_NPAR_OPER 1 /* NPAR Operational */
#define QLCNIC_DEV_NPAR_OPER_TIMEO 30 /* Operational time out */
-#define QLC_DEV_CHECK_ACTIVE(VAL, FN) ((VAL) & (1 << (FN * 4)))
#define QLC_DEV_SET_REF_CNT(VAL, FN) ((VAL) |= (1 << (FN * 4)))
#define QLC_DEV_CLR_REF_CNT(VAL, FN) ((VAL) &= ~(1 << (FN * 4)))
#define QLC_DEV_SET_RST_RDY(VAL, FN) ((VAL) |= (1 << (FN * 4)))
@@ -744,6 +671,9 @@ enum {
#define QLCNIC_HEARTBEAT_PERIOD_MSECS 200
#define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT 45
+#define QLCNIC_MAX_MC_COUNT 38
+#define QLCNIC_WATCHDOG_TIMEOUTVALUE 5
+
#define ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
#define ISR_LEGACY_INT_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200)
@@ -766,26 +696,13 @@ struct qlcnic_legacy_intr_set {
u32 pci_int_reg;
};
-#define QLCNIC_FW_API 0x1b216c
-#define QLCNIC_DRV_OP_MODE 0x1b2170
#define QLCNIC_MSIX_BASE 0x132110
#define QLCNIC_MAX_PCI_FUNC 8
#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 FW_DUMP_LEVELS[] = {
- 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
-
-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
@@ -796,7 +713,8 @@ static const u32 MIU_TEST_READ_DATA[] = {
enum {
QLCNIC_MGMT_FUNC = 0,
QLCNIC_PRIV_FUNC = 1,
- QLCNIC_NON_PRIV_FUNC = 2
+ QLCNIC_NON_PRIV_FUNC = 2,
+ QLCNIC_UNKNOWN_FUNC_MODE = 3
};
enum {
@@ -1013,6 +931,8 @@ enum {
#define QLCNIC_NIU_PROMISC_MODE 1
#define QLCNIC_NIU_ALLMULTI_MODE 2
+#define QLCNIC_PCIE_SEM_TIMEOUT 10000
+
struct crb_128M_2M_sub_block_map {
unsigned valid;
unsigned start_128M;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 7a6d5ebe4e0f..325e11e1ce0f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -1,6 +1,6 @@
/*
* QLogic qlcnic NIC Driver
- * Copyright (c) 2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
*
* See LICENSE.qlcnic for copyright and licensing details.
*/
@@ -344,21 +344,26 @@ qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem)
QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)));
}
-static int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
+int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
{
u32 data;
if (qlcnic_82xx_check(adapter))
qlcnic_read_window_reg(addr, adapter->ahw->pci_base0, &data);
- else
- return -EIO;
+ else {
+ data = qlcnic_83xx_rd_reg_indirect(adapter, addr);
+ if (data == -EIO)
+ return -EIO;
+ }
return data;
}
-static void qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data)
+void qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data)
{
if (qlcnic_82xx_check(adapter))
qlcnic_write_window_reg(addr, adapter->ahw->pci_base0, data);
+ else
+ qlcnic_83xx_wrt_reg_indirect(adapter, addr, data);
}
static int
@@ -417,9 +422,8 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
return 0;
}
-static int
-qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
- __le16 vlan_id, unsigned op)
+int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
+ __le16 vlan_id, u8 op)
{
struct qlcnic_nic_req req;
struct qlcnic_mac_req *mac_req;
@@ -442,7 +446,29 @@ qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
}
-static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
+int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
+{
+ struct list_head *head;
+ struct qlcnic_mac_list_s *cur;
+ int err = -EINVAL;
+
+ /* Delete MAC from the existing list */
+ list_for_each(head, &adapter->mac_list) {
+ cur = list_entry(head, struct qlcnic_mac_list_s, list);
+ if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) {
+ err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
+ 0, QLCNIC_MAC_DEL);
+ if (err)
+ return err;
+ list_del(&cur->list);
+ kfree(cur);
+ return err;
+ }
+ }
+ return err;
+}
+
+int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
{
struct list_head *head;
struct qlcnic_mac_list_s *cur;
@@ -455,11 +481,9 @@ static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
}
cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC);
- if (cur == NULL) {
- dev_err(&adapter->netdev->dev,
- "failed to add mac address filter\n");
+ if (cur == NULL)
return -ENOMEM;
- }
+
memcpy(cur->mac_addr, addr, ETH_ALEN);
if (qlcnic_sre_macaddr_change(adapter,
@@ -506,17 +530,17 @@ void qlcnic_set_multi(struct net_device *netdev)
}
send_fw_cmd:
- if (mode == VPORT_MISS_MODE_ACCEPT_ALL) {
+ if (mode == VPORT_MISS_MODE_ACCEPT_ALL && !adapter->fdb_mac_learn) {
qlcnic_alloc_lb_filters_mem(adapter);
- adapter->mac_learn = 1;
+ adapter->drv_mac_learn = true;
} else {
- adapter->mac_learn = 0;
+ adapter->drv_mac_learn = false;
}
qlcnic_nic_set_promisc(adapter, mode);
}
-int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
+int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
{
struct qlcnic_nic_req req;
u64 word;
@@ -555,18 +579,20 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
struct hlist_node *tmp_hnode, *n;
struct hlist_head *head;
int i;
+ unsigned long time;
+ u8 cmd;
- for (i = 0; i < adapter->fhash.fmax; i++) {
+ for (i = 0; i < adapter->fhash.fbucket_size; i++) {
head = &(adapter->fhash.fhead[i]);
-
- hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode)
- {
- if (jiffies >
- (QLCNIC_FILTER_AGE * HZ + tmp_fil->ftime)) {
+ hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+ cmd = tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
+ QLCNIC_MAC_DEL;
+ time = tmp_fil->ftime;
+ if (jiffies > (QLCNIC_FILTER_AGE * HZ + time)) {
qlcnic_sre_macaddr_change(adapter,
- tmp_fil->faddr, tmp_fil->vlan_id,
- tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
- QLCNIC_MAC_DEL);
+ tmp_fil->faddr,
+ tmp_fil->vlan_id,
+ cmd);
spin_lock_bh(&adapter->mac_learn_lock);
adapter->fhash.fnum--;
hlist_del(&tmp_fil->fnode);
@@ -575,6 +601,21 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
}
}
}
+ for (i = 0; i < adapter->rx_fhash.fbucket_size; i++) {
+ head = &(adapter->rx_fhash.fhead[i]);
+
+ hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode)
+ {
+ time = tmp_fil->ftime;
+ if (jiffies > (QLCNIC_FILTER_AGE * HZ + time)) {
+ spin_lock_bh(&adapter->rx_mac_learn_lock);
+ adapter->rx_fhash.fnum--;
+ hlist_del(&tmp_fil->fnode);
+ spin_unlock_bh(&adapter->rx_mac_learn_lock);
+ kfree(tmp_fil);
+ }
+ }
+ }
}
void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
@@ -583,14 +624,17 @@ void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
struct hlist_node *tmp_hnode, *n;
struct hlist_head *head;
int i;
+ u8 cmd;
- for (i = 0; i < adapter->fhash.fmax; i++) {
+ for (i = 0; i < adapter->fhash.fbucket_size; i++) {
head = &(adapter->fhash.fhead[i]);
-
hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
- qlcnic_sre_macaddr_change(adapter, tmp_fil->faddr,
- tmp_fil->vlan_id, tmp_fil->vlan_id ?
- QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL);
+ cmd = tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
+ QLCNIC_MAC_DEL;
+ qlcnic_sre_macaddr_change(adapter,
+ tmp_fil->faddr,
+ tmp_fil->vlan_id,
+ cmd);
spin_lock_bh(&adapter->mac_learn_lock);
adapter->fhash.fnum--;
hlist_del(&tmp_fil->fnode);
@@ -620,12 +664,13 @@ static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u8 flag)
return rv;
}
-int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
{
if (qlcnic_set_fw_loopback(adapter, mode))
return -EIO;
- if (qlcnic_nic_set_promisc(adapter, VPORT_MISS_MODE_ACCEPT_ALL)) {
+ if (qlcnic_nic_set_promisc(adapter,
+ VPORT_MISS_MODE_ACCEPT_ALL)) {
qlcnic_set_fw_loopback(adapter, 0);
return -EIO;
}
@@ -634,11 +679,11 @@ int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
return 0;
}
-void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
{
- int mode = VPORT_MISS_MODE_DROP;
struct net_device *netdev = adapter->netdev;
+ mode = VPORT_MISS_MODE_DROP;
qlcnic_set_fw_loopback(adapter, 0);
if (netdev->flags & IFF_PROMISC)
@@ -648,12 +693,13 @@ void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter)
qlcnic_nic_set_promisc(adapter, mode);
msleep(1000);
+ return 0;
}
/*
* Send the interrupt coalescing parameter set by ethtool to the card.
*/
-int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter)
{
struct qlcnic_nic_req req;
int rv;
@@ -675,10 +721,14 @@ int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
if (rv != 0)
dev_err(&adapter->netdev->dev,
"Could not send interrupt coalescing parameters\n");
- return rv;
}
-int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
+#define QLCNIC_ENABLE_IPV4_LRO 1
+#define QLCNIC_ENABLE_IPV6_LRO 2
+#define QLCNIC_NO_DEST_IPV4_CHECK (1 << 8)
+#define QLCNIC_NO_DEST_IPV6_CHECK (2 << 8)
+
+int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
{
struct qlcnic_nic_req req;
u64 word;
@@ -694,7 +744,15 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
word = QLCNIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16);
req.req_hdr = cpu_to_le64(word);
- req.words[0] = cpu_to_le64(enable);
+ word = 0;
+ if (enable) {
+ word = QLCNIC_ENABLE_IPV4_LRO | QLCNIC_NO_DEST_IPV4_CHECK;
+ if (adapter->ahw->capabilities2 & QLCNIC_FW_CAP2_HW_LRO_IPV6)
+ word |= QLCNIC_ENABLE_IPV6_LRO |
+ QLCNIC_NO_DEST_IPV6_CHECK;
+ }
+
+ req.words[0] = cpu_to_le64(word);
rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
if (rv != 0)
@@ -734,9 +792,12 @@ int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
}
-#define RSS_HASHTYPE_IP_TCP 0x3
+#define QLCNIC_RSS_HASHTYPE_IP_TCP 0x3
+#define QLCNIC_ENABLE_TYPE_C_RSS BIT_10
+#define QLCNIC_RSS_FEATURE_FLAG (1ULL << 63)
+#define QLCNIC_RSS_IND_TABLE_MASK 0x7ULL
-int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
+int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int enable)
{
struct qlcnic_nic_req req;
u64 word;
@@ -761,13 +822,19 @@ int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
* 7-6: hash_type_ipv6
* 8: enable
* 9: use indirection table
- * 47-10: reserved
- * 63-48: indirection table mask
+ * 10: type-c rss
+ * 11: udp rss
+ * 47-12: reserved
+ * 62-48: indirection table mask
+ * 63: feature flag
*/
- word = ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
- ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
+ word = ((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
+ ((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
((u64)(enable & 0x1) << 8) |
- ((0x7ULL) << 48);
+ ((u64)QLCNIC_RSS_IND_TABLE_MASK << 48) |
+ (u64)QLCNIC_ENABLE_TYPE_C_RSS |
+ (u64)QLCNIC_RSS_FEATURE_FLAG;
+
req.words[0] = cpu_to_le64(word);
for (i = 0; i < 5; i++)
req.words[i+1] = cpu_to_le64(key[i]);
@@ -779,7 +846,8 @@ int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
return rv;
}
-int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd)
+void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter,
+ __be32 ip, int cmd)
{
struct qlcnic_nic_req req;
struct qlcnic_ipaddr *ipa;
@@ -801,23 +869,19 @@ int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd)
dev_err(&adapter->netdev->dev,
"could not notify %s IP 0x%x reuqest\n",
(cmd == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
-
- return rv;
}
-int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable)
+int qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int enable)
{
struct qlcnic_nic_req req;
u64 word;
int rv;
-
memset(&req, 0, sizeof(struct qlcnic_nic_req));
req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16);
req.req_hdr = cpu_to_le64(word);
req.words[0] = cpu_to_le64(enable | (enable << 8));
-
rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
if (rv != 0)
dev_err(&adapter->netdev->dev,
@@ -882,7 +946,8 @@ netdev_features_t qlcnic_fix_features(struct net_device *netdev,
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
- if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) &&
+ qlcnic_82xx_check(adapter)) {
netdev_features_t changed = features ^ netdev->features;
features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM);
}
@@ -903,13 +968,15 @@ int qlcnic_set_features(struct net_device *netdev, netdev_features_t features)
if (!(changed & NETIF_F_LRO))
return 0;
- netdev->features = features ^ NETIF_F_LRO;
+ netdev->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;
+ if (!hw_lro && qlcnic_82xx_check(adapter)) {
+ if (qlcnic_send_lro_cleanup(adapter))
+ return -EIO;
+ }
return 0;
}
@@ -981,8 +1048,8 @@ qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
return 0;
}
-int
-qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
+int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off,
+ u32 data)
{
unsigned long flags;
int rv;
@@ -1013,7 +1080,7 @@ qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
return -EIO;
}
-int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
{
unsigned long flags;
int rv;
@@ -1042,7 +1109,6 @@ int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
return -1;
}
-
void __iomem *qlcnic_get_ioaddr(struct qlcnic_hardware_context *ahw,
u32 offset)
{
@@ -1268,7 +1334,7 @@ int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
return ret;
}
-int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
{
int offset, board_type, magic;
struct pci_dev *pdev = adapter->pdev;
@@ -1341,7 +1407,7 @@ qlcnic_wol_supported(struct qlcnic_adapter *adapter)
return 0;
}
-int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+int qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
{
struct qlcnic_nic_req req;
int rv;
@@ -1353,7 +1419,7 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16);
req.req_hdr = cpu_to_le64(word);
- req.words[0] = cpu_to_le64((u64)rate << 32);
+ req.words[0] = cpu_to_le64(((u64)rate << 32) | adapter->portnum);
req.words[1] = cpu_to_le64(state);
rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
@@ -1362,3 +1428,56 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
return rv;
}
+
+void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
+{
+ void __iomem *msix_base_addr;
+ u32 func;
+ u32 msix_base;
+
+ pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
+ msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE;
+ msix_base = readl(msix_base_addr);
+ func = (func - msix_base) / QLCNIC_MSIX_TBL_PGSIZE;
+ adapter->ahw->pci_func = func;
+}
+
+void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
+ loff_t offset, size_t size)
+{
+ u32 data;
+ u64 qmdata;
+
+ if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+ qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
+ memcpy(buf, &qmdata, size);
+ } else {
+ data = QLCRD32(adapter, offset);
+ memcpy(buf, &data, size);
+ }
+}
+
+void qlcnic_82xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
+ loff_t offset, size_t size)
+{
+ u32 data;
+ u64 qmdata;
+
+ if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+ memcpy(&qmdata, buf, size);
+ qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
+ } else {
+ memcpy(&data, buf, size);
+ QLCWR32(adapter, offset, data);
+ }
+}
+
+int qlcnic_82xx_api_lock(struct qlcnic_adapter *adapter)
+{
+ return qlcnic_pcie_sem_lock(adapter, 5, 0);
+}
+
+void qlcnic_82xx_api_unlock(struct qlcnic_adapter *adapter)
+{
+ qlcnic_pcie_sem_unlock(adapter, 5);
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
new file mode 100644
index 000000000000..5b8749eda11f
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -0,0 +1,194 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#ifndef __QLCNIC_HW_H
+#define __QLCNIC_HW_H
+
+/* Common registers in 83xx and 82xx */
+enum qlcnic_regs {
+ QLCNIC_PEG_HALT_STATUS1 = 0,
+ QLCNIC_PEG_HALT_STATUS2,
+ QLCNIC_PEG_ALIVE_COUNTER,
+ QLCNIC_FLASH_LOCK_OWNER,
+ QLCNIC_FW_CAPABILITIES,
+ QLCNIC_CRB_DRV_ACTIVE,
+ QLCNIC_CRB_DEV_STATE,
+ QLCNIC_CRB_DRV_STATE,
+ QLCNIC_CRB_DRV_SCRATCH,
+ QLCNIC_CRB_DEV_PARTITION_INFO,
+ QLCNIC_CRB_DRV_IDC_VER,
+ QLCNIC_FW_VERSION_MAJOR,
+ QLCNIC_FW_VERSION_MINOR,
+ QLCNIC_FW_VERSION_SUB,
+ QLCNIC_CRB_DEV_NPAR_STATE,
+ QLCNIC_FW_IMG_VALID,
+ QLCNIC_CMDPEG_STATE,
+ QLCNIC_RCVPEG_STATE,
+ QLCNIC_ASIC_TEMP,
+ QLCNIC_FW_API,
+ QLCNIC_DRV_OP_MODE,
+ QLCNIC_FLASH_LOCK,
+ QLCNIC_FLASH_UNLOCK,
+};
+
+/* Read from an address offset from BAR0, existing registers */
+#define QLC_SHARED_REG_RD32(a, addr) \
+ readl(((a)->ahw->pci_base0) + ((a)->ahw->reg_tbl[addr]))
+
+/* Write to an address offset from BAR0, existing registers */
+#define QLC_SHARED_REG_WR32(a, addr, value) \
+ writel(value, ((a)->ahw->pci_base0) + ((a)->ahw->reg_tbl[addr]))
+
+/* Read from a direct address offset from BAR0, additional registers */
+#define QLCRDX(ahw, addr) \
+ readl(((ahw)->pci_base0) + ((ahw)->ext_reg_tbl[addr]))
+
+/* Write to a direct address offset from BAR0, additional registers */
+#define QLCWRX(ahw, addr, value) \
+ writel(value, (((ahw)->pci_base0) + ((ahw)->ext_reg_tbl[addr])))
+
+#define QLCNIC_CMD_CONFIGURE_IP_ADDR 0x1
+#define QLCNIC_CMD_CONFIG_INTRPT 0x2
+#define QLCNIC_CMD_CREATE_RX_CTX 0x7
+#define QLCNIC_CMD_DESTROY_RX_CTX 0x8
+#define QLCNIC_CMD_CREATE_TX_CTX 0x9
+#define QLCNIC_CMD_DESTROY_TX_CTX 0xa
+#define QLCNIC_CMD_CONFIGURE_LRO 0xC
+#define QLCNIC_CMD_CONFIGURE_MAC_LEARNING 0xD
+#define QLCNIC_CMD_GET_STATISTICS 0xF
+#define QLCNIC_CMD_INTRPT_TEST 0x11
+#define QLCNIC_CMD_SET_MTU 0x12
+#define QLCNIC_CMD_READ_PHY 0x13
+#define QLCNIC_CMD_WRITE_PHY 0x14
+#define QLCNIC_CMD_READ_HW_REG 0x15
+#define QLCNIC_CMD_GET_FLOW_CTL 0x16
+#define QLCNIC_CMD_SET_FLOW_CTL 0x17
+#define QLCNIC_CMD_READ_MAX_MTU 0x18
+#define QLCNIC_CMD_READ_MAX_LRO 0x19
+#define QLCNIC_CMD_MAC_ADDRESS 0x1f
+#define QLCNIC_CMD_GET_PCI_INFO 0x20
+#define QLCNIC_CMD_GET_NIC_INFO 0x21
+#define QLCNIC_CMD_SET_NIC_INFO 0x22
+#define QLCNIC_CMD_GET_ESWITCH_CAPABILITY 0x24
+#define QLCNIC_CMD_TOGGLE_ESWITCH 0x25
+#define QLCNIC_CMD_GET_ESWITCH_STATUS 0x26
+#define QLCNIC_CMD_SET_PORTMIRRORING 0x27
+#define QLCNIC_CMD_CONFIGURE_ESWITCH 0x28
+#define QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG 0x29
+#define QLCNIC_CMD_GET_ESWITCH_STATS 0x2a
+#define QLCNIC_CMD_CONFIG_PORT 0x2e
+#define QLCNIC_CMD_TEMP_SIZE 0x2f
+#define QLCNIC_CMD_GET_TEMP_HDR 0x30
+#define QLCNIC_CMD_GET_MAC_STATS 0x37
+#define QLCNIC_CMD_SET_DRV_VER 0x38
+#define QLCNIC_CMD_CONFIGURE_RSS 0x41
+#define QLCNIC_CMD_CONFIG_INTR_COAL 0x43
+#define QLCNIC_CMD_CONFIGURE_LED 0x44
+#define QLCNIC_CMD_CONFIG_MAC_VLAN 0x45
+#define QLCNIC_CMD_GET_LINK_EVENT 0x48
+#define QLCNIC_CMD_CONFIGURE_MAC_RX_MODE 0x49
+#define QLCNIC_CMD_CONFIGURE_HW_LRO 0x4A
+#define QLCNIC_CMD_INIT_NIC_FUNC 0x60
+#define QLCNIC_CMD_STOP_NIC_FUNC 0x61
+#define QLCNIC_CMD_IDC_ACK 0x63
+#define QLCNIC_CMD_SET_PORT_CONFIG 0x66
+#define QLCNIC_CMD_GET_PORT_CONFIG 0x67
+#define QLCNIC_CMD_GET_LINK_STATUS 0x68
+#define QLCNIC_CMD_SET_LED_CONFIG 0x69
+#define QLCNIC_CMD_GET_LED_CONFIG 0x6A
+#define QLCNIC_CMD_ADD_RCV_RINGS 0x0B
+
+#define QLCNIC_INTRPT_INTX 1
+#define QLCNIC_INTRPT_MSIX 3
+#define QLCNIC_INTRPT_ADD 1
+#define QLCNIC_INTRPT_DEL 2
+
+#define QLCNIC_GET_CURRENT_MAC 1
+#define QLCNIC_SET_STATION_MAC 2
+#define QLCNIC_GET_DEFAULT_MAC 3
+#define QLCNIC_GET_FAC_DEF_MAC 4
+#define QLCNIC_SET_FAC_DEF_MAC 5
+
+#define QLCNIC_MBX_LINK_EVENT 0x8001
+#define QLCNIC_MBX_COMP_EVENT 0x8100
+#define QLCNIC_MBX_REQUEST_EVENT 0x8101
+#define QLCNIC_MBX_TIME_EXTEND_EVENT 0x8102
+#define QLCNIC_MBX_SFP_INSERT_EVENT 0x8130
+#define QLCNIC_MBX_SFP_REMOVE_EVENT 0x8131
+
+struct qlcnic_mailbox_metadata {
+ u32 cmd;
+ u32 in_args;
+ u32 out_args;
+};
+
+/* Mailbox ownership */
+#define QLCNIC_GET_OWNER(val) ((val) & (BIT_0 | BIT_1))
+
+#define QLCNIC_SET_OWNER 1
+#define QLCNIC_CLR_OWNER 0
+#define QLCNIC_MBX_TIMEOUT 10000
+
+#define QLCNIC_MBX_RSP_OK 1
+#define QLCNIC_MBX_PORT_RSP_OK 0x1a
+#define QLCNIC_MBX_ASYNC_EVENT BIT_15
+
+struct qlcnic_pci_info;
+struct qlcnic_info;
+struct qlcnic_cmd_args;
+struct ethtool_stats;
+struct pci_device_id;
+struct qlcnic_host_sds_ring;
+struct qlcnic_host_tx_ring;
+struct qlcnic_host_tx_ring;
+struct qlcnic_hardware_context;
+struct qlcnic_adapter;
+
+int qlcnic_82xx_start_firmware(struct qlcnic_adapter *);
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong);
+int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
+int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int);
+int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
+int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
+ struct net_device *netdev);
+void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter,
+ u64 *uaddr, __le16 vlan_id);
+void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter);
+int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int);
+void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter,
+ __be32, int);
+int qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int);
+void qlcnic_82xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
+int qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8);
+int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *, u8);
+void qlcnic_82xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_82xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *, u32);
+int qlcnic_82xx_setup_intr(struct qlcnic_adapter *, u8);
+irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *);
+int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *);
+int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *);
+int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *,
+ struct qlcnic_host_tx_ring *tx_ring, int);
+int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8);
+int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
+int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
+int qlcnic_82xx_alloc_mbx_args(struct qlcnic_cmd_args *,
+ struct qlcnic_adapter *, u32);
+int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
+int qlcnic_82xx_get_board_info(struct qlcnic_adapter *);
+int qlcnic_82xx_config_led(struct qlcnic_adapter *, u32, u32);
+void qlcnic_82xx_get_func_no(struct qlcnic_adapter *);
+int qlcnic_82xx_api_lock(struct qlcnic_adapter *);
+void qlcnic_82xx_api_unlock(struct qlcnic_adapter *);
+void qlcnic_82xx_napi_enable(struct qlcnic_adapter *);
+void qlcnic_82xx_napi_disable(struct qlcnic_adapter *);
+void qlcnic_82xx_napi_del(struct qlcnic_adapter *);
+#endif /* __QLCNIC_HW_H_ */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index de79cde233de..d28336fc65ab 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -1,15 +1,12 @@
/*
* QLogic qlcnic NIC Driver
- * Copyright (c) 2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
*
* See LICENSE.qlcnic for copyright and licensing details.
*/
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/if_vlan.h>
#include "qlcnic.h"
+#include "qlcnic_hw.h"
struct crb_addr_pair {
u32 addr;
@@ -166,13 +163,12 @@ void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter)
{
struct qlcnic_recv_context *recv_ctx;
struct qlcnic_host_rds_ring *rds_ring;
- struct qlcnic_host_tx_ring *tx_ring;
int ring;
recv_ctx = adapter->recv_ctx;
if (recv_ctx->rds_rings == NULL)
- goto skip_rds;
+ return;
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
@@ -180,16 +176,6 @@ void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter)
rds_ring->rx_buf_arr = NULL;
}
kfree(recv_ctx->rds_rings);
-
-skip_rds:
- if (adapter->tx_ring == NULL)
- return;
-
- tx_ring = adapter->tx_ring;
- vfree(tx_ring->cmd_buf_arr);
- tx_ring->cmd_buf_arr = NULL;
- kfree(adapter->tx_ring);
- adapter->tx_ring = NULL;
}
int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
@@ -197,39 +183,16 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
struct qlcnic_recv_context *recv_ctx;
struct qlcnic_host_rds_ring *rds_ring;
struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_host_tx_ring *tx_ring;
struct qlcnic_rx_buffer *rx_buf;
- int ring, i, size;
-
- struct qlcnic_cmd_buffer *cmd_buf_arr;
- struct net_device *netdev = adapter->netdev;
-
- size = sizeof(struct qlcnic_host_tx_ring);
- tx_ring = kzalloc(size, GFP_KERNEL);
- if (tx_ring == NULL) {
- dev_err(&netdev->dev, "failed to allocate tx ring struct\n");
- return -ENOMEM;
- }
- adapter->tx_ring = tx_ring;
-
- tx_ring->num_desc = adapter->num_txd;
- tx_ring->txq = netdev_get_tx_queue(netdev, 0);
-
- cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
- if (cmd_buf_arr == NULL) {
- dev_err(&netdev->dev, "failed to allocate cmd buffer ring\n");
- goto err_out;
- }
- tx_ring->cmd_buf_arr = cmd_buf_arr;
+ int ring, i;
recv_ctx = adapter->recv_ctx;
- size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring);
- rds_ring = kzalloc(size, GFP_KERNEL);
- if (rds_ring == NULL) {
- dev_err(&netdev->dev, "failed to allocate rds ring struct\n");
+ rds_ring = kcalloc(adapter->max_rds_rings,
+ sizeof(struct qlcnic_host_rds_ring), GFP_KERNEL);
+ if (rds_ring == NULL)
goto err_out;
- }
+
recv_ctx->rds_rings = rds_ring;
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
@@ -255,11 +218,9 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
break;
}
rds_ring->rx_buf_arr = vzalloc(RCV_BUFF_RINGSIZE(rds_ring));
- if (rds_ring->rx_buf_arr == NULL) {
- dev_err(&netdev->dev, "Failed to allocate "
- "rx buffer ring %d\n", ring);
+ if (rds_ring->rx_buf_arr == NULL)
goto err_out;
- }
+
INIT_LIST_HEAD(&rds_ring->free_list);
/*
* Now go through all of them, set reference handles
@@ -327,7 +288,6 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
long done = 0;
cond_resched();
-
while (done == 0) {
done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS);
done &= 2;
@@ -416,8 +376,8 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
u32 off;
struct pci_dev *pdev = adapter->pdev;
- QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
- QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, 0);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_RCVPEG_STATE, 0);
/* Halt all the indiviual PEGs and other blocks */
/* disable all I2Q */
@@ -482,10 +442,8 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
}
buf = kcalloc(n, sizeof(struct crb_addr_pair), GFP_KERNEL);
- if (buf == NULL) {
- dev_err(&pdev->dev, "Unable to calloc memory for rom read.\n");
+ if (buf == NULL)
return -ENOMEM;
- }
for (i = 0; i < n; i++) {
if (qlcnic_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 ||
@@ -564,8 +522,8 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0xc, 0);
msleep(1);
- QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
- QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
return 0;
}
@@ -576,7 +534,7 @@ static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
do {
- val = QLCRD32(adapter, CRB_CMDPEG_STATE);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CMDPEG_STATE);
switch (val) {
case PHAN_INITIALIZE_COMPLETE:
@@ -592,7 +550,8 @@ static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
} while (--retries);
- QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE,
+ PHAN_INITIALIZE_FAILED);
out_err:
dev_err(&adapter->pdev->dev, "Command Peg initialization not "
@@ -607,7 +566,7 @@ qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter)
int retries = QLCNIC_RCVPEG_CHECK_RETRY_COUNT;
do {
- val = QLCRD32(adapter, CRB_RCVPEG_STATE);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_RCVPEG_STATE);
if (val == PHAN_PEG_RCV_INITIALIZED)
return 0;
@@ -638,7 +597,7 @@ qlcnic_check_fw_status(struct qlcnic_adapter *adapter)
if (err)
return err;
- QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
return err;
}
@@ -649,7 +608,7 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
int timeo;
u32 val;
- val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
val = QLC_DEV_GET_DRV(val, adapter->portnum);
if ((val & 0x3) != QLCNIC_TYPE_NIC) {
dev_err(&adapter->pdev->dev,
@@ -689,11 +648,9 @@ static int qlcnic_get_flt_entry(struct qlcnic_adapter *adapter, u8 region,
}
entry_size = flt_hdr.len - sizeof(struct qlcnic_flt_header);
- flt_entry = (struct qlcnic_flt_entry *)vzalloc(entry_size);
- if (flt_entry == NULL) {
- dev_warn(&adapter->pdev->dev, "error allocating memory\n");
+ flt_entry = vzalloc(entry_size);
+ if (flt_entry == NULL)
return -EIO;
- }
ret = qlcnic_rom_fast_read_words(adapter, QLCNIC_FLT_LOCATION +
sizeof(struct qlcnic_flt_header),
@@ -1096,11 +1053,13 @@ qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter)
u32 heartbeat, ret = -EIO;
int retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
- adapter->heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+ adapter->heartbeat = QLC_SHARED_REG_RD32(adapter,
+ QLCNIC_PEG_ALIVE_COUNTER);
do {
msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
- heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+ heartbeat = QLC_SHARED_REG_RD32(adapter,
+ QLCNIC_PEG_ALIVE_COUNTER);
if (heartbeat != adapter->heartbeat) {
ret = QLCNIC_RCODE_SUCCESS;
break;
@@ -1270,7 +1229,7 @@ qlcnic_validate_firmware(struct qlcnic_adapter *adapter)
return -EINVAL;
}
- QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID, QLCNIC_BDINFO_MAGIC);
return 0;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 6f82812d0fab..6387e0cc3ea9 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -1,3 +1,10 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <net/ip.h>
@@ -5,9 +12,6 @@
#include "qlcnic.h"
-#define QLCNIC_MAC_HASH(MAC)\
- ((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
-
#define TX_ETHER_PKT 0x01
#define TX_TCP_PKT 0x02
#define TX_UDP_PKT 0x03
@@ -84,6 +88,8 @@
#define qlcnic_get_lro_sts_mss(sts_data1) \
((sts_data1 >> 32) & 0x0FFFF)
+#define qlcnic_83xx_get_lro_sts_mss(sts) ((sts) & 0xffff)
+
/* opcode field in status_desc */
#define QLCNIC_SYN_OFFLOAD 0x03
#define QLCNIC_RXPKT_DESC 0x04
@@ -91,18 +97,152 @@
#define QLCNIC_RESPONSE_DESC 0x05
#define QLCNIC_LRO_DESC 0x12
+#define QLCNIC_TX_POLL_BUDGET 128
+#define QLCNIC_TCP_HDR_SIZE 20
+#define QLCNIC_TCP_TS_OPTION_SIZE 12
+#define QLCNIC_FETCH_RING_ID(handle) ((handle) >> 63)
+#define QLCNIC_DESC_OWNER_FW cpu_to_le64(STATUS_OWNER_PHANTOM)
+
+#define QLCNIC_TCP_TS_HDR_SIZE (QLCNIC_TCP_HDR_SIZE + QLCNIC_TCP_TS_OPTION_SIZE)
+
/* for status field in status_desc */
#define STATUS_CKSUM_LOOP 0
#define STATUS_CKSUM_OK 2
-static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
- u64 uaddr, __le16 vlan_id,
- struct qlcnic_host_tx_ring *tx_ring)
+#define qlcnic_83xx_pktln(sts) ((sts >> 32) & 0x3FFF)
+#define qlcnic_83xx_hndl(sts) ((sts >> 48) & 0x7FFF)
+#define qlcnic_83xx_csum_status(sts) ((sts >> 39) & 7)
+#define qlcnic_83xx_opcode(sts) ((sts >> 42) & 0xF)
+#define qlcnic_83xx_vlan_tag(sts) (((sts) >> 48) & 0xFFFF)
+#define qlcnic_83xx_lro_pktln(sts) (((sts) >> 32) & 0x3FFF)
+#define qlcnic_83xx_l2_hdr_off(sts) (((sts) >> 16) & 0xFF)
+#define qlcnic_83xx_l4_hdr_off(sts) (((sts) >> 24) & 0xFF)
+#define qlcnic_83xx_pkt_cnt(sts) (((sts) >> 16) & 0x7)
+#define qlcnic_83xx_is_tstamp(sts) (((sts) >> 40) & 1)
+#define qlcnic_83xx_is_psh_bit(sts) (((sts) >> 41) & 1)
+#define qlcnic_83xx_is_ip_align(sts) (((sts) >> 46) & 1)
+#define qlcnic_83xx_has_vlan_tag(sts) (((sts) >> 47) & 1)
+
+struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *,
+ struct qlcnic_host_rds_ring *, u16, u16);
+
+inline void qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring)
+{
+ writel(0, tx_ring->crb_intr_mask);
+}
+
+inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring)
+{
+ writel(1, tx_ring->crb_intr_mask);
+}
+
+static inline u8 qlcnic_mac_hash(u64 mac)
+{
+ return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff));
+}
+
+static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter,
+ u16 handle, u8 ring_id)
+{
+ if (adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X)
+ return handle | (ring_id << 15);
+ else
+ return handle;
+}
+
+static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data)
+{
+ return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0;
+}
+
+void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
+ int loopback_pkt, __le16 vlan_id)
+{
+ struct ethhdr *phdr = (struct ethhdr *)(skb->data);
+ struct qlcnic_filter *fil, *tmp_fil;
+ struct hlist_node *tmp_hnode, *n;
+ struct hlist_head *head;
+ unsigned long time;
+ u64 src_addr = 0;
+ u8 hindex, found = 0, op;
+ int ret;
+
+ memcpy(&src_addr, phdr->h_source, ETH_ALEN);
+
+ if (loopback_pkt) {
+ if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax)
+ return;
+
+ hindex = qlcnic_mac_hash(src_addr) &
+ (adapter->fhash.fbucket_size - 1);
+ head = &(adapter->rx_fhash.fhead[hindex]);
+
+ hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+ if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
+ tmp_fil->vlan_id == vlan_id) {
+ time = tmp_fil->ftime;
+ if (jiffies > (QLCNIC_READD_AGE * HZ + time))
+ tmp_fil->ftime = jiffies;
+ return;
+ }
+ }
+
+ fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
+ if (!fil)
+ return;
+
+ fil->ftime = jiffies;
+ memcpy(fil->faddr, &src_addr, ETH_ALEN);
+ fil->vlan_id = vlan_id;
+ spin_lock(&adapter->rx_mac_learn_lock);
+ hlist_add_head(&(fil->fnode), head);
+ adapter->rx_fhash.fnum++;
+ spin_unlock(&adapter->rx_mac_learn_lock);
+ } else {
+ hindex = qlcnic_mac_hash(src_addr) &
+ (adapter->fhash.fbucket_size - 1);
+ head = &(adapter->rx_fhash.fhead[hindex]);
+ spin_lock(&adapter->rx_mac_learn_lock);
+ hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+ if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
+ tmp_fil->vlan_id == vlan_id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ spin_unlock(&adapter->rx_mac_learn_lock);
+ return;
+ }
+
+ op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
+ ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr,
+ vlan_id, op);
+ if (!ret) {
+ op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
+ ret = qlcnic_sre_macaddr_change(adapter,
+ (u8 *)&src_addr,
+ vlan_id, op);
+ if (!ret) {
+ hlist_del(&(tmp_fil->fnode));
+ adapter->rx_fhash.fnum--;
+ }
+ }
+ spin_unlock(&adapter->rx_mac_learn_lock);
+ }
+}
+
+void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
+ __le16 vlan_id)
{
struct cmd_desc_type0 *hwdesc;
struct qlcnic_nic_req *req;
struct qlcnic_mac_req *mac_req;
struct qlcnic_vlan_req *vlan_req;
+ struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
u32 producer;
u64 word;
@@ -128,14 +268,14 @@ static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
}
static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
- struct qlcnic_host_tx_ring *tx_ring,
struct cmd_desc_type0 *first_desc,
struct sk_buff *skb)
{
- struct ethhdr *phdr = (struct ethhdr *)(skb->data);
struct qlcnic_filter *fil, *tmp_fil;
struct hlist_node *tmp_hnode, *n;
struct hlist_head *head;
+ struct net_device *netdev = adapter->netdev;
+ struct ethhdr *phdr = (struct ethhdr *)(skb->data);
u64 src_addr = 0;
__le16 vlan_id = 0;
u8 hindex;
@@ -143,23 +283,23 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
return;
- if (adapter->fhash.fnum >= adapter->fhash.fmax)
+ if (adapter->fhash.fnum >= adapter->fhash.fmax) {
+ adapter->stats.mac_filter_limit_overrun++;
+ netdev_info(netdev, "Can not add more than %d mac addresses\n",
+ adapter->fhash.fmax);
return;
+ }
- /* Only NPAR capable devices support vlan based learning*/
- if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
- vlan_id = first_desc->vlan_TCI;
memcpy(&src_addr, phdr->h_source, ETH_ALEN);
- hindex = QLCNIC_MAC_HASH(src_addr) & (QLCNIC_LB_MAX_FILTERS - 1);
+ hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1);
head = &(adapter->fhash.fhead[hindex]);
hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
- tmp_fil->vlan_id == vlan_id) {
-
+ tmp_fil->vlan_id == vlan_id) {
if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
- qlcnic_change_filter(adapter, src_addr, vlan_id,
- tx_ring);
+ qlcnic_change_filter(adapter, &src_addr,
+ vlan_id);
tmp_fil->ftime = jiffies;
return;
}
@@ -169,17 +309,13 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
if (!fil)
return;
- qlcnic_change_filter(adapter, src_addr, vlan_id, tx_ring);
-
+ qlcnic_change_filter(adapter, &src_addr, vlan_id);
fil->ftime = jiffies;
fil->vlan_id = vlan_id;
memcpy(fil->faddr, &src_addr, ETH_ALEN);
-
spin_lock(&adapter->mac_learn_lock);
-
hlist_add_head(&(fil->fnode), head);
adapter->fhash.fnum++;
-
spin_unlock(&adapter->mac_learn_lock);
}
@@ -474,8 +610,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb)))
goto unwind_buff;
- if (adapter->mac_learn)
- qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
+ if (adapter->drv_mac_learn)
+ qlcnic_send_filter(adapter, first_desc, skb);
adapter->stats.txbytes += skb->len;
adapter->stats.xmitcalled++;
@@ -528,8 +664,8 @@ static int qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
}
skb_reserve(skb, NET_IP_ALIGN);
- dma = pci_map_single(pdev, skb->data, rds_ring->dma_size,
- PCI_DMA_FROMDEVICE);
+ dma = pci_map_single(pdev, skb->data,
+ rds_ring->dma_size, PCI_DMA_FROMDEVICE);
if (pci_dma_mapping_error(pdev, dma)) {
adapter->stats.rx_dma_map_error++;
@@ -544,12 +680,13 @@ static int qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
}
static void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring)
+ struct qlcnic_host_rds_ring *rds_ring,
+ u8 ring_id)
{
struct rcv_desc *pdesc;
struct qlcnic_rx_buffer *buffer;
int count = 0;
- uint32_t producer;
+ uint32_t producer, handle;
struct list_head *head;
if (!spin_trylock(&rds_ring->lock))
@@ -557,7 +694,6 @@ static void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
producer = rds_ring->producer;
head = &rds_ring->free_list;
-
while (!list_empty(head)) {
buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
@@ -565,28 +701,29 @@ static void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
break;
}
-
count++;
list_del(&buffer->list);
/* make a rcv descriptor */
pdesc = &rds_ring->desc_head[producer];
- pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+ handle = qlcnic_get_ref_handle(adapter,
+ buffer->ref_handle, ring_id);
+ pdesc->reference_handle = cpu_to_le16(handle);
pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
pdesc->addr_buffer = cpu_to_le64(buffer->dma);
producer = get_next_index(producer, rds_ring->num_desc);
}
-
if (count) {
rds_ring->producer = producer;
writel((producer - 1) & (rds_ring->num_desc - 1),
rds_ring->crb_rcv_producer);
}
-
spin_unlock(&rds_ring->lock);
}
-static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
+static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring,
+ int budget)
{
u32 sw_consumer, hw_consumer;
int i, done, count = 0;
@@ -594,7 +731,6 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
struct qlcnic_skb_frag *frag;
- struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
if (!spin_trylock(&adapter->tx_clean_lock))
return 1;
@@ -615,22 +751,19 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
PCI_DMA_TODEVICE);
frag->dma = 0ULL;
}
-
adapter->stats.xmitfinished++;
dev_kfree_skb_any(buffer->skb);
buffer->skb = NULL;
}
sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
- if (++count >= MAX_STATUS_HANDLE)
+ if (++count >= budget)
break;
}
if (count && netif_running(netdev)) {
tx_ring->sw_consumer = sw_consumer;
-
smp_mb();
-
if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
netif_wake_queue(netdev);
@@ -654,7 +787,6 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
*/
hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
done = (sw_consumer == hw_consumer);
-
spin_unlock(&adapter->tx_clean_lock);
return done;
@@ -662,16 +794,15 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
static int qlcnic_poll(struct napi_struct *napi, int budget)
{
+ int tx_complete, work_done;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_adapter *adapter;
- int tx_complete, work_done;
sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
adapter = sds_ring->adapter;
-
- tx_complete = qlcnic_process_cmd_ring(adapter);
+ tx_complete = qlcnic_process_cmd_ring(adapter, adapter->tx_ring,
+ budget);
work_done = qlcnic_process_rcv_ring(sds_ring, budget);
-
if ((work_done < budget) && tx_complete) {
napi_complete(&sds_ring->napi);
if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
@@ -804,26 +935,23 @@ static void qlcnic_handle_fw_message(int desc_cnt, int index,
}
}
-static struct sk_buff *
-qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring, u16 index,
- u16 cksum)
+struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *ring,
+ u16 index, u16 cksum)
{
struct qlcnic_rx_buffer *buffer;
struct sk_buff *skb;
- buffer = &rds_ring->rx_buf_arr[index];
-
+ buffer = &ring->rx_buf_arr[index];
if (unlikely(buffer->skb == NULL)) {
WARN_ON(1);
return NULL;
}
- pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
+ pci_unmap_single(adapter->pdev, buffer->dma, ring->dma_size,
PCI_DMA_FROMDEVICE);
skb = buffer->skb;
-
if (likely((adapter->netdev->features & NETIF_F_RXCSUM) &&
(cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
adapter->stats.csummed++;
@@ -832,6 +960,7 @@ qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
skb_checksum_none_assert(skb);
}
+
buffer->skb = NULL;
return skb;
@@ -871,8 +1000,8 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
struct qlcnic_rx_buffer *buffer;
struct sk_buff *skb;
struct qlcnic_host_rds_ring *rds_ring;
- int index, length, cksum, pkt_offset;
- u16 vid = 0xffff;
+ int index, length, cksum, pkt_offset, is_lb_pkt;
+ u16 vid = 0xffff, t_vid;
if (unlikely(ring >= adapter->max_rds_rings))
return NULL;
@@ -892,6 +1021,14 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
if (!skb)
return buffer;
+ if (adapter->drv_mac_learn &&
+ (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ t_vid = 0;
+ is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
+ qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+ cpu_to_le16(t_vid));
+ }
+
if (length > rds_ring->skb_size)
skb_put(skb, rds_ring->skb_size);
else
@@ -933,10 +1070,11 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
struct sk_buff *skb;
struct qlcnic_host_rds_ring *rds_ring;
struct iphdr *iph;
+ struct ipv6hdr *ipv6h;
struct tcphdr *th;
bool push, timestamp;
- int index, l2_hdr_offset, l4_hdr_offset;
- u16 lro_length, length, data_offset, vid = 0xffff;
+ int index, l2_hdr_offset, l4_hdr_offset, is_lb_pkt;
+ u16 lro_length, length, data_offset, t_vid, vid = 0xffff;
u32 seq_number;
if (unlikely(ring > adapter->max_rds_rings))
@@ -961,6 +1099,14 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
if (!skb)
return buffer;
+ if (adapter->drv_mac_learn &&
+ (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ t_vid = 0;
+ is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
+ qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+ cpu_to_le16(t_vid));
+ }
+
if (timestamp)
data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
else
@@ -976,18 +1122,32 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
}
skb->protocol = eth_type_trans(skb, netdev);
- iph = (struct iphdr *)skb->data;
- th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
- length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
- iph->tot_len = htons(length);
- iph->check = 0;
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+ if (ntohs(skb->protocol) == ETH_P_IPV6) {
+ ipv6h = (struct ipv6hdr *)skb->data;
+ th = (struct tcphdr *)(skb->data + sizeof(struct ipv6hdr));
+ length = (th->doff << 2) + lro_length;
+ ipv6h->payload_len = htons(length);
+ } else {
+ iph = (struct iphdr *)skb->data;
+ th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+ length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+ iph->tot_len = htons(length);
+ iph->check = 0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ }
+
th->psh = push;
th->seq = htonl(seq_number);
length = skb->len;
- if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+ if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) {
skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);
+ if (skb->protocol == htons(ETH_P_IPV6))
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+ else
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+ }
if (vid != 0xffff)
__vlan_hwaccel_put_tag(skb, vid);
@@ -1006,9 +1166,9 @@ int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
struct list_head *cur;
struct status_desc *desc;
struct qlcnic_rx_buffer *rxbuf;
+ int opcode, desc_cnt, count = 0;
u64 sts_data0, sts_data1;
- __le64 owner_phantom = cpu_to_le64(STATUS_OWNER_PHANTOM);
- int opcode, ring, desc_cnt, count = 0;
+ u8 ring;
u32 consumer = sds_ring->consumer;
while (count < max) {
@@ -1020,7 +1180,6 @@ int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
opcode = qlcnic_get_sts_opcode(sts_data0);
-
switch (opcode) {
case QLCNIC_RXPKT_DESC:
case QLCNIC_OLD_RXPKT_DESC:
@@ -1040,18 +1199,16 @@ int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
default:
goto skip;
}
-
WARN_ON(desc_cnt > 1);
if (likely(rxbuf))
list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
else
adapter->stats.null_rxbuf++;
-
skip:
for (; desc_cnt > 0; desc_cnt--) {
desc = &sds_ring->desc_head[consumer];
- desc->status_desc_data[0] = owner_phantom;
+ desc->status_desc_data[0] = QLCNIC_DESC_OWNER_FW;
consumer = get_next_index(consumer, sds_ring->num_desc);
}
count++;
@@ -1059,7 +1216,6 @@ skip:
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &adapter->recv_ctx->rds_rings[ring];
-
if (!list_empty(&sds_ring->free_list[ring])) {
list_for_each(cur, &sds_ring->free_list[ring]) {
rxbuf = list_entry(cur, struct qlcnic_rx_buffer,
@@ -1072,7 +1228,7 @@ skip:
spin_unlock(&rds_ring->lock);
}
- qlcnic_post_rx_buffers_nodb(adapter, rds_ring);
+ qlcnic_post_rx_buffers_nodb(adapter, rds_ring, ring);
}
if (count) {
@@ -1084,12 +1240,12 @@ skip:
}
void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring)
+ struct qlcnic_host_rds_ring *rds_ring, u8 ring_id)
{
struct rcv_desc *pdesc;
struct qlcnic_rx_buffer *buffer;
int count = 0;
- u32 producer;
+ u32 producer, handle;
struct list_head *head;
producer = rds_ring->producer;
@@ -1110,7 +1266,9 @@ void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
/* make a rcv descriptor */
pdesc = &rds_ring->desc_head[producer];
pdesc->addr_buffer = cpu_to_le64(buffer->dma);
- pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+ handle = qlcnic_get_ref_handle(adapter, buffer->ref_handle,
+ ring_id);
+ pdesc->reference_handle = cpu_to_le16(handle);
pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
producer = get_next_index(producer, rds_ring->num_desc);
}
@@ -1180,7 +1338,7 @@ static void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, int ring,
return;
}
-void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+void qlcnic_82xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
{
struct qlcnic_adapter *adapter = sds_ring->adapter;
struct status_desc *desc;
@@ -1217,26 +1375,8 @@ void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
writel(consumer, sds_ring->crb_sts_consumer);
}
-void qlcnic_fetch_mac(u32 off1, u32 off2, u8 alt_mac, u8 *mac)
-{
- u32 mac_low, mac_high;
- int i;
-
- mac_low = off1;
- mac_high = off2;
-
- if (alt_mac) {
- mac_low |= (mac_low >> 16) | (mac_high << 16);
- mac_high >>= 16;
- }
-
- for (i = 0; i < 2; i++)
- mac[i] = (u8)(mac_high >> ((1 - i) * 8));
- for (i = 2; i < 6; i++)
- mac[i] = (u8)(mac_low >> ((5 - i) * 8));
-}
-
-int qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
+int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
+ struct net_device *netdev)
{
int ring, max_sds_rings;
struct qlcnic_host_sds_ring *sds_ring;
@@ -1249,8 +1389,7 @@ int qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
-
- if (ring == max_sds_rings - 1)
+ if (ring == adapter->max_sds_rings - 1)
netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
QLCNIC_NETDEV_WEIGHT / max_sds_rings);
else
@@ -1258,10 +1397,15 @@ int qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
QLCNIC_NETDEV_WEIGHT*2);
}
+ if (qlcnic_alloc_tx_rings(adapter, netdev)) {
+ qlcnic_free_sds_rings(recv_ctx);
+ return -ENOMEM;
+ }
+
return 0;
}
-void qlcnic_napi_del(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_napi_del(struct qlcnic_adapter *adapter)
{
int ring;
struct qlcnic_host_sds_ring *sds_ring;
@@ -1273,9 +1417,10 @@ void qlcnic_napi_del(struct qlcnic_adapter *adapter)
}
qlcnic_free_sds_rings(adapter->recv_ctx);
+ qlcnic_free_tx_rings(adapter);
}
-void qlcnic_napi_enable(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_napi_enable(struct qlcnic_adapter *adapter)
{
int ring;
struct qlcnic_host_sds_ring *sds_ring;
@@ -1291,7 +1436,7 @@ void qlcnic_napi_enable(struct qlcnic_adapter *adapter)
}
}
-void qlcnic_napi_disable(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)
{
int ring;
struct qlcnic_host_sds_ring *sds_ring;
@@ -1307,3 +1452,481 @@ void qlcnic_napi_disable(struct qlcnic_adapter *adapter)
napi_disable(&sds_ring->napi);
}
}
+
+#define QLC_83XX_NORMAL_LB_PKT (1ULL << 36)
+#define QLC_83XX_LRO_LB_PKT (1ULL << 46)
+
+static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt)
+{
+ if (lro_pkt)
+ return (sts_data & QLC_83XX_LRO_LB_PKT) ? 1 : 0;
+ else
+ return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_sds_ring *sds_ring,
+ u8 ring, u64 sts_data[])
+{
+ struct net_device *netdev = adapter->netdev;
+ 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;
+ int index, length, cksum, is_lb_pkt;
+ u16 vid = 0xffff, t_vid;
+
+ if (unlikely(ring >= adapter->max_rds_rings))
+ return NULL;
+
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ index = qlcnic_83xx_hndl(sts_data[0]);
+ if (unlikely(index >= rds_ring->num_desc))
+ return NULL;
+
+ buffer = &rds_ring->rx_buf_arr[index];
+ length = qlcnic_83xx_pktln(sts_data[0]);
+ cksum = qlcnic_83xx_csum_status(sts_data[1]);
+ skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+ if (!skb)
+ return buffer;
+
+ if (adapter->drv_mac_learn &&
+ (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ t_vid = 0;
+ is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0);
+ qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+ cpu_to_le16(t_vid));
+ }
+
+ if (length > rds_ring->skb_size)
+ skb_put(skb, rds_ring->skb_size);
+ else
+ skb_put(skb, length);
+
+ if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+ adapter->stats.rxdropped++;
+ dev_kfree_skb(skb);
+ return buffer;
+ }
+
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ if (vid != 0xffff)
+ __vlan_hwaccel_put_tag(skb, vid);
+
+ napi_gro_receive(&sds_ring->napi, skb);
+
+ adapter->stats.rx_pkts++;
+ adapter->stats.rxbytes += length;
+
+ return buffer;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
+ u8 ring, u64 sts_data[])
+{
+ struct net_device *netdev = adapter->netdev;
+ 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;
+ struct iphdr *iph;
+ struct ipv6hdr *ipv6h;
+ struct tcphdr *th;
+ bool push;
+ int l2_hdr_offset, l4_hdr_offset;
+ int index, is_lb_pkt;
+ u16 lro_length, length, data_offset, gso_size;
+ u16 vid = 0xffff, t_vid;
+
+ if (unlikely(ring > adapter->max_rds_rings))
+ return NULL;
+
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ index = qlcnic_83xx_hndl(sts_data[0]);
+ if (unlikely(index > rds_ring->num_desc))
+ return NULL;
+
+ buffer = &rds_ring->rx_buf_arr[index];
+
+ lro_length = qlcnic_83xx_lro_pktln(sts_data[0]);
+ l2_hdr_offset = qlcnic_83xx_l2_hdr_off(sts_data[1]);
+ l4_hdr_offset = qlcnic_83xx_l4_hdr_off(sts_data[1]);
+ push = qlcnic_83xx_is_psh_bit(sts_data[1]);
+
+ skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+ if (!skb)
+ return buffer;
+
+ if (adapter->drv_mac_learn &&
+ (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ t_vid = 0;
+ is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1);
+ qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+ cpu_to_le16(t_vid));
+ }
+ if (qlcnic_83xx_is_tstamp(sts_data[1]))
+ data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE;
+ else
+ data_offset = l4_hdr_offset + QLCNIC_TCP_HDR_SIZE;
+
+ skb_put(skb, lro_length + data_offset);
+ skb_pull(skb, l2_hdr_offset);
+
+ if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+ adapter->stats.rxdropped++;
+ dev_kfree_skb(skb);
+ return buffer;
+ }
+
+ skb->protocol = eth_type_trans(skb, netdev);
+ if (ntohs(skb->protocol) == ETH_P_IPV6) {
+ ipv6h = (struct ipv6hdr *)skb->data;
+ th = (struct tcphdr *)(skb->data + sizeof(struct ipv6hdr));
+
+ length = (th->doff << 2) + lro_length;
+ ipv6h->payload_len = htons(length);
+ } else {
+ iph = (struct iphdr *)skb->data;
+ th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+ length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+ iph->tot_len = htons(length);
+ iph->check = 0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ }
+
+ th->psh = push;
+ length = skb->len;
+
+ if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) {
+ gso_size = qlcnic_83xx_get_lro_sts_mss(sts_data[0]);
+ skb_shinfo(skb)->gso_size = gso_size;
+ if (skb->protocol == htons(ETH_P_IPV6))
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+ else
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+ }
+
+ if (vid != 0xffff)
+ __vlan_hwaccel_put_tag(skb, vid);
+
+ netif_receive_skb(skb);
+
+ adapter->stats.lro_pkts++;
+ adapter->stats.lrobytes += length;
+ return buffer;
+}
+
+static int qlcnic_83xx_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring,
+ int max)
+{
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+ struct list_head *cur;
+ struct status_desc *desc;
+ struct qlcnic_rx_buffer *rxbuf = NULL;
+ u8 ring;
+ u64 sts_data[2];
+ int count = 0, opcode;
+ u32 consumer = sds_ring->consumer;
+
+ while (count < max) {
+ desc = &sds_ring->desc_head[consumer];
+ sts_data[1] = le64_to_cpu(desc->status_desc_data[1]);
+ opcode = qlcnic_83xx_opcode(sts_data[1]);
+ if (!opcode)
+ break;
+ sts_data[0] = le64_to_cpu(desc->status_desc_data[0]);
+ ring = QLCNIC_FETCH_RING_ID(sts_data[0]);
+
+ switch (opcode) {
+ case QLC_83XX_REG_DESC:
+ rxbuf = qlcnic_83xx_process_rcv(adapter, sds_ring,
+ ring, sts_data);
+ break;
+ case QLC_83XX_LRO_DESC:
+ rxbuf = qlcnic_83xx_process_lro(adapter, ring,
+ sts_data);
+ break;
+ default:
+ dev_info(&adapter->pdev->dev,
+ "Unkonwn opcode: 0x%x\n", opcode);
+ goto skip;
+ }
+
+ if (likely(rxbuf))
+ list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
+ else
+ adapter->stats.null_rxbuf++;
+skip:
+ desc = &sds_ring->desc_head[consumer];
+ /* Reset the descriptor */
+ desc->status_desc_data[1] = 0;
+ consumer = get_next_index(consumer, sds_ring->num_desc);
+ count++;
+ }
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ rds_ring = &adapter->recv_ctx->rds_rings[ring];
+ if (!list_empty(&sds_ring->free_list[ring])) {
+ list_for_each(cur, &sds_ring->free_list[ring]) {
+ rxbuf = list_entry(cur, struct qlcnic_rx_buffer,
+ list);
+ qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
+ }
+ spin_lock(&rds_ring->lock);
+ list_splice_tail_init(&sds_ring->free_list[ring],
+ &rds_ring->free_list);
+ spin_unlock(&rds_ring->lock);
+ }
+ qlcnic_post_rx_buffers_nodb(adapter, rds_ring, ring);
+ }
+ if (count) {
+ sds_ring->consumer = consumer;
+ writel(consumer, sds_ring->crb_sts_consumer);
+ }
+ return count;
+}
+
+static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)
+{
+ int tx_complete;
+ int work_done;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_adapter *adapter;
+ struct qlcnic_host_tx_ring *tx_ring;
+
+ sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
+ adapter = sds_ring->adapter;
+ /* tx ring count = 1 */
+ tx_ring = adapter->tx_ring;
+
+ tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
+ work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
+ if ((work_done < budget) && tx_complete) {
+ napi_complete(&sds_ring->napi);
+ qlcnic_83xx_enable_intr(adapter, sds_ring);
+ }
+
+ return work_done;
+}
+
+static int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget)
+{
+ int work_done;
+ struct qlcnic_host_tx_ring *tx_ring;
+ struct qlcnic_adapter *adapter;
+
+ budget = QLCNIC_TX_POLL_BUDGET;
+ tx_ring = container_of(napi, struct qlcnic_host_tx_ring, napi);
+ adapter = tx_ring->adapter;
+ work_done = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
+ if (work_done) {
+ napi_complete(&tx_ring->napi);
+ if (test_bit(__QLCNIC_DEV_UP , &adapter->state))
+ qlcnic_83xx_enable_tx_intr(adapter, tx_ring);
+ }
+
+ return work_done;
+}
+
+static int qlcnic_83xx_rx_poll(struct napi_struct *napi, int budget)
+{
+ int work_done;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_adapter *adapter;
+
+ sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
+ adapter = sds_ring->adapter;
+ work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
+ if (work_done < budget) {
+ napi_complete(&sds_ring->napi);
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+ qlcnic_83xx_enable_intr(adapter, sds_ring);
+ }
+
+ return work_done;
+}
+
+void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter)
+{
+ int ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ napi_enable(&sds_ring->napi);
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ qlcnic_83xx_enable_intr(adapter, sds_ring);
+ }
+
+ if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ napi_enable(&tx_ring->napi);
+ qlcnic_83xx_enable_tx_intr(adapter, tx_ring);
+ }
+ }
+}
+
+void qlcnic_83xx_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_host_tx_ring *tx_ring;
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ qlcnic_83xx_disable_intr(adapter, sds_ring);
+ napi_synchronize(&sds_ring->napi);
+ napi_disable(&sds_ring->napi);
+ }
+
+ if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ qlcnic_83xx_disable_tx_intr(adapter, tx_ring);
+ napi_synchronize(&tx_ring->napi);
+ napi_disable(&tx_ring->napi);
+ }
+ }
+}
+
+int qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter,
+ struct net_device *netdev)
+{
+ int ring, max_sds_rings;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+ if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
+ return -ENOMEM;
+
+ max_sds_rings = adapter->max_sds_rings;
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ if (adapter->flags & QLCNIC_MSIX_ENABLED)
+ netif_napi_add(netdev, &sds_ring->napi,
+ qlcnic_83xx_rx_poll,
+ QLCNIC_NETDEV_WEIGHT * 2);
+ else
+ netif_napi_add(netdev, &sds_ring->napi,
+ qlcnic_83xx_poll,
+ QLCNIC_NETDEV_WEIGHT / max_sds_rings);
+ }
+
+ if (qlcnic_alloc_tx_rings(adapter, netdev)) {
+ qlcnic_free_sds_rings(recv_ctx);
+ return -ENOMEM;
+ }
+
+ if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ netif_napi_add(netdev, &tx_ring->napi,
+ qlcnic_83xx_msix_tx_poll,
+ QLCNIC_NETDEV_WEIGHT);
+ }
+ }
+
+ return 0;
+}
+
+void qlcnic_83xx_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_host_tx_ring *tx_ring;
+
+ 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);
+
+ if ((adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ netif_napi_del(&tx_ring->napi);
+ }
+ }
+
+ qlcnic_free_tx_rings(adapter);
+}
+
+void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter,
+ int ring, u64 sts_data[])
+{
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+ struct sk_buff *skb;
+ struct qlcnic_host_rds_ring *rds_ring;
+ int index, length;
+
+ if (unlikely(ring >= adapter->max_rds_rings))
+ return;
+
+ rds_ring = &recv_ctx->rds_rings[ring];
+ index = qlcnic_83xx_hndl(sts_data[0]);
+ if (unlikely(index >= rds_ring->num_desc))
+ return;
+
+ length = qlcnic_83xx_pktln(sts_data[0]);
+
+ skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+ if (!skb)
+ return;
+
+ if (length > rds_ring->skb_size)
+ skb_put(skb, rds_ring->skb_size);
+ else
+ skb_put(skb, length);
+
+ if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
+ adapter->ahw->diag_cnt++;
+ else
+ dump_skb(skb, adapter);
+
+ dev_kfree_skb_any(skb);
+ return;
+}
+
+void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+ struct status_desc *desc;
+ u64 sts_data[2];
+ int ring, opcode;
+ u32 consumer = sds_ring->consumer;
+
+ desc = &sds_ring->desc_head[consumer];
+ sts_data[0] = le64_to_cpu(desc->status_desc_data[0]);
+ sts_data[1] = le64_to_cpu(desc->status_desc_data[1]);
+ opcode = qlcnic_83xx_opcode(sts_data[1]);
+ if (!opcode)
+ return;
+
+ ring = QLCNIC_FETCH_RING_ID(qlcnic_83xx_hndl(sts_data[0]));
+ qlcnic_83xx_process_rcv_diag(adapter, ring, sts_data);
+ desc = &sds_ring->desc_head[consumer];
+ desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+ consumer = get_next_index(consumer, sds_ring->num_desc);
+ sds_ring->consumer = consumer;
+ writel(consumer, sds_ring->crb_sts_consumer);
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index d833f5927891..28a6d4838364 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -1,24 +1,25 @@
/*
* QLogic qlcnic NIC Driver
- * Copyright (c) 2009-2010 QLogic Corporation
+ * Copyright (c) 2009-2013 QLogic Corporation
*
* See LICENSE.qlcnic for copyright and licensing details.
*/
-#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include "qlcnic.h"
+#include "qlcnic_hw.h"
#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>
+#include <linux/pci.h>
MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
MODULE_LICENSE("GPL");
@@ -29,28 +30,28 @@ char qlcnic_driver_name[] = "qlcnic";
static const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
"Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID;
-static struct workqueue_struct *qlcnic_wq;
static int qlcnic_mac_learn;
module_param(qlcnic_mac_learn, int, 0444);
-MODULE_PARM_DESC(qlcnic_mac_learn, "Mac Filter (0=disabled, 1=enabled)");
+MODULE_PARM_DESC(qlcnic_mac_learn,
+ "Mac Filter (0=learning is disabled, 1=Driver learning is enabled, 2=FDB learning is enabled)");
-static int qlcnic_use_msi = 1;
+int qlcnic_use_msi = 1;
MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
module_param_named(use_msi, qlcnic_use_msi, int, 0444);
-static int qlcnic_use_msi_x = 1;
+int qlcnic_use_msi_x = 1;
MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled");
module_param_named(use_msi_x, qlcnic_use_msi_x, int, 0444);
-static int qlcnic_auto_fw_reset = 1;
+int qlcnic_auto_fw_reset = 1;
MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled");
module_param_named(auto_fw_reset, qlcnic_auto_fw_reset, int, 0644);
-static int qlcnic_load_fw_file;
+int qlcnic_load_fw_file;
MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
module_param_named(load_fw_file, qlcnic_load_fw_file, int, 0444);
-static int qlcnic_config_npars;
+int qlcnic_config_npars;
module_param(qlcnic_config_npars, int, 0444);
MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
@@ -62,9 +63,6 @@ static void qlcnic_tx_timeout(struct net_device *netdev);
static void qlcnic_attach_work(struct work_struct *work);
static void qlcnic_fwinit_work(struct work_struct *work);
static void qlcnic_fw_poll_work(struct work_struct *work);
-static void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
- work_func_t func, int delay);
-static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void qlcnic_poll_controller(struct net_device *netdev);
#endif
@@ -77,9 +75,9 @@ static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
static irqreturn_t qlcnic_intr(int irq, void *data);
static irqreturn_t qlcnic_msi_intr(int irq, void *data);
static irqreturn_t qlcnic_msix_intr(int irq, void *data);
+static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data);
static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
-static void qlcnic_restore_indev_addr(struct net_device *dev, unsigned long);
static int qlcnic_start_firmware(struct qlcnic_adapter *);
static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
@@ -93,15 +91,24 @@ static int qlcnic_vlan_rx_del(struct net_device *, u16);
#define QLCNIC_IS_TSO_CAPABLE(adapter) \
((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
+static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ if (adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE824X)
+ return ahw->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX;
+ else
+ return 1;
+}
+
/* PCI Device ID Table */
#define ENTRY(device) \
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
.class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
-#define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020
-
static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
+ ENTRY(PCI_DEVICE_ID_QLOGIC_QLE834X),
{0,}
};
@@ -120,6 +127,32 @@ static const u32 msi_tgt_status[8] = {
ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
};
+static const u32 qlcnic_reg_tbl[] = {
+ 0x1B20A8, /* PEG_HALT_STAT1 */
+ 0x1B20AC, /* PEG_HALT_STAT2 */
+ 0x1B20B0, /* FW_HEARTBEAT */
+ 0x1B2100, /* LOCK ID */
+ 0x1B2128, /* FW_CAPABILITIES */
+ 0x1B2138, /* drv active */
+ 0x1B2140, /* dev state */
+ 0x1B2144, /* drv state */
+ 0x1B2148, /* drv scratch */
+ 0x1B214C, /* dev partition info */
+ 0x1B2174, /* drv idc ver */
+ 0x1B2150, /* fw version major */
+ 0x1B2154, /* fw version minor */
+ 0x1B2158, /* fw version sub */
+ 0x1B219C, /* npar state */
+ 0x1B21FC, /* FW_IMG_VALID */
+ 0x1B2250, /* CMD_PEG_STATE */
+ 0x1B233C, /* RCV_PEG_STATE */
+ 0x1B23B4, /* ASIC TEMP */
+ 0x1B216C, /* FW api */
+ 0x1B2170, /* drv op mode */
+ 0x13C010, /* flash lock */
+ 0x13C014, /* flash unlock */
+};
+
static const struct qlcnic_board_info qlcnic_boards[] = {
{0x1077, 0x8020, 0x1077, 0x203,
"8200 Series Single Port 10GbE Converged Network Adapter"
@@ -143,6 +176,7 @@ static const struct qlcnic_board_info qlcnic_boards[] = {
};
#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards)
+#define QLC_MAX_SDS_RINGS 8
static const
struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
@@ -164,35 +198,6 @@ void qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
recv_ctx->sds_rings = NULL;
}
-static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
-{
- memset(&adapter->stats, 0, sizeof(adapter->stats));
-}
-
-static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable)
-{
- u32 control;
- int pos;
-
- pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
- if (pos) {
- pci_read_config_dword(pdev, pos, &control);
- if (enable)
- control |= PCI_MSIX_FLAGS_ENABLE;
- else
- control = 0;
- pci_write_config_dword(pdev, pos, control);
- }
-}
-
-static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
-{
- int i;
-
- for (i = 0; i < count; i++)
- adapter->msix_entries[i].entry = i;
-}
-
static int
qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
{
@@ -204,12 +209,11 @@ qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
return -EIO;
memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
- memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
/* set station address */
- if (!is_valid_ether_addr(netdev->perm_addr))
+ if (!is_valid_ether_addr(netdev->dev_addr))
dev_warn(&pdev->dev, "Bad MAC address %pM.\n",
netdev->dev_addr);
@@ -225,7 +229,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
return -EOPNOTSUPP;
if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
+ return -EINVAL;
if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
netif_device_detach(netdev);
@@ -243,6 +247,85 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
return 0;
}
+static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
+ struct net_device *netdev, const unsigned char *addr)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int err = -EOPNOTSUPP;
+
+ if (!adapter->fdb_mac_learn) {
+ pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
+ __func__);
+ return err;
+ }
+
+ if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
+ if (is_unicast_ether_addr(addr))
+ err = qlcnic_nic_del_mac(adapter, addr);
+ else if (is_multicast_ether_addr(addr))
+ err = dev_mc_del(netdev, addr);
+ else
+ err = -EINVAL;
+ }
+ return err;
+}
+
+static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+ struct net_device *netdev,
+ const unsigned char *addr, u16 flags)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int err = 0;
+
+ if (!adapter->fdb_mac_learn) {
+ pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
+ __func__);
+ return -EOPNOTSUPP;
+ }
+
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ pr_info("%s: FDB e-switch is not enabled\n", __func__);
+ return -EOPNOTSUPP;
+ }
+
+ if (ether_addr_equal(addr, adapter->mac_addr))
+ return err;
+
+ if (is_unicast_ether_addr(addr))
+ err = qlcnic_nic_add_mac(adapter, addr);
+ else if (is_multicast_ether_addr(addr))
+ err = dev_mc_add_excl(netdev, addr);
+ else
+ err = -EINVAL;
+
+ return err;
+}
+
+static int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb,
+ struct net_device *netdev, int idx)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+ if (!adapter->fdb_mac_learn) {
+ pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
+ __func__);
+ return -EOPNOTSUPP;
+ }
+
+ if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
+ idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx);
+
+ return idx;
+}
+
+static void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter)
+{
+ while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ usleep_range(10000, 11000);
+
+ cancel_delayed_work_sync(&adapter->fw_work);
+}
+
static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_open = qlcnic_open,
.ndo_stop = qlcnic_close,
@@ -257,6 +340,9 @@ static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_tx_timeout = qlcnic_tx_timeout,
.ndo_vlan_rx_add_vid = qlcnic_vlan_rx_add,
.ndo_vlan_rx_kill_vid = qlcnic_vlan_rx_del,
+ .ndo_fdb_add = qlcnic_fdb_add,
+ .ndo_fdb_del = qlcnic_fdb_del,
+ .ndo_fdb_dump = qlcnic_fdb_dump,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = qlcnic_poll_controller,
#endif
@@ -267,50 +353,125 @@ static const struct net_device_ops qlcnic_netdev_failed_ops = {
};
static struct qlcnic_nic_template qlcnic_ops = {
- .config_bridged_mode = qlcnic_config_bridged_mode,
- .config_led = qlcnic_config_led,
- .start_firmware = qlcnic_start_firmware
+ .config_bridged_mode = qlcnic_config_bridged_mode,
+ .config_led = qlcnic_82xx_config_led,
+ .start_firmware = qlcnic_82xx_start_firmware,
+ .request_reset = qlcnic_82xx_dev_request_reset,
+ .cancel_idc_work = qlcnic_82xx_cancel_idc_work,
+ .napi_add = qlcnic_82xx_napi_add,
+ .napi_del = qlcnic_82xx_napi_del,
+ .config_ipaddr = qlcnic_82xx_config_ipaddr,
+ .clear_legacy_intr = qlcnic_82xx_clear_legacy_intr,
};
-static struct qlcnic_nic_template qlcnic_vf_ops = {
- .config_bridged_mode = qlcnicvf_config_bridged_mode,
- .config_led = qlcnicvf_config_led,
- .start_firmware = qlcnicvf_start_firmware
+struct qlcnic_nic_template qlcnic_vf_ops = {
+ .config_bridged_mode = qlcnicvf_config_bridged_mode,
+ .config_led = qlcnicvf_config_led,
+ .start_firmware = qlcnicvf_start_firmware
};
-static int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
+static struct qlcnic_hardware_ops qlcnic_hw_ops = {
+ .read_crb = qlcnic_82xx_read_crb,
+ .write_crb = qlcnic_82xx_write_crb,
+ .read_reg = qlcnic_82xx_hw_read_wx_2M,
+ .write_reg = qlcnic_82xx_hw_write_wx_2M,
+ .get_mac_address = qlcnic_82xx_get_mac_address,
+ .setup_intr = qlcnic_82xx_setup_intr,
+ .alloc_mbx_args = qlcnic_82xx_alloc_mbx_args,
+ .mbx_cmd = qlcnic_82xx_issue_cmd,
+ .get_func_no = qlcnic_82xx_get_func_no,
+ .api_lock = qlcnic_82xx_api_lock,
+ .api_unlock = qlcnic_82xx_api_unlock,
+ .add_sysfs = qlcnic_82xx_add_sysfs,
+ .remove_sysfs = qlcnic_82xx_remove_sysfs,
+ .process_lb_rcv_ring_diag = qlcnic_82xx_process_rcv_ring_diag,
+ .create_rx_ctx = qlcnic_82xx_fw_cmd_create_rx_ctx,
+ .create_tx_ctx = qlcnic_82xx_fw_cmd_create_tx_ctx,
+ .setup_link_event = qlcnic_82xx_linkevent_request,
+ .get_nic_info = qlcnic_82xx_get_nic_info,
+ .get_pci_info = qlcnic_82xx_get_pci_info,
+ .set_nic_info = qlcnic_82xx_set_nic_info,
+ .change_macvlan = qlcnic_82xx_sre_macaddr_change,
+ .napi_enable = qlcnic_82xx_napi_enable,
+ .napi_disable = qlcnic_82xx_napi_disable,
+ .config_intr_coal = qlcnic_82xx_config_intr_coalesce,
+ .config_rss = qlcnic_82xx_config_rss,
+ .config_hw_lro = qlcnic_82xx_config_hw_lro,
+ .config_loopback = qlcnic_82xx_set_lb_mode,
+ .clear_loopback = qlcnic_82xx_clear_lb_mode,
+ .config_promisc_mode = qlcnic_82xx_nic_set_promisc,
+ .change_l2_filter = qlcnic_82xx_change_filter,
+ .get_board_info = qlcnic_82xx_get_board_info,
+};
+
+int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
{
struct pci_dev *pdev = adapter->pdev;
- int err = -1;
+ int err = -1, i;
+ int max_tx_rings;
+
+ if (!adapter->msix_entries) {
+ adapter->msix_entries = kcalloc(num_msix,
+ sizeof(struct msix_entry),
+ GFP_KERNEL);
+ if (!adapter->msix_entries)
+ return -ENOMEM;
+ }
adapter->max_sds_rings = 1;
adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
- qlcnic_set_msix_bit(pdev, 0);
if (adapter->ahw->msix_supported) {
enable_msix:
- qlcnic_init_msix_entries(adapter, num_msix);
+ for (i = 0; i < num_msix; i++)
+ adapter->msix_entries[i].entry = i;
err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
if (err == 0) {
adapter->flags |= QLCNIC_MSIX_ENABLED;
- qlcnic_set_msix_bit(pdev, 1);
-
- adapter->max_sds_rings = num_msix;
-
+ if (qlcnic_83xx_check(adapter)) {
+ adapter->ahw->num_msix = num_msix;
+ /* subtract mail box and tx ring vectors */
+ max_tx_rings = adapter->max_drv_tx_rings;
+ adapter->max_sds_rings = num_msix -
+ max_tx_rings - 1;
+ } else {
+ adapter->max_sds_rings = num_msix;
+ }
dev_info(&pdev->dev, "using msi-x interrupts\n");
return err;
- }
- if (err > 0) {
- num_msix = rounddown_pow_of_two(err);
- if (num_msix)
+ } else if (err > 0) {
+ dev_info(&pdev->dev,
+ "Unable to allocate %d MSI-X interrupt vectors\n",
+ num_msix);
+ if (qlcnic_83xx_check(adapter)) {
+ if (err < QLC_83XX_MINIMUM_VECTOR)
+ return err;
+ err -= (adapter->max_drv_tx_rings + 1);
+ num_msix = rounddown_pow_of_two(err);
+ num_msix += (adapter->max_drv_tx_rings + 1);
+ } else {
+ num_msix = rounddown_pow_of_two(err);
+ }
+
+ if (num_msix) {
+ dev_info(&pdev->dev,
+ "Trying to allocate %d MSI-X interrupt vectors\n",
+ num_msix);
goto enable_msix;
+ }
+ } else {
+ dev_info(&pdev->dev,
+ "Unable to allocate %d MSI-X interrupt vectors\n",
+ num_msix);
}
}
+
return err;
}
-static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
+static int qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
{
+ int err = 0;
u32 offset, mask_reg;
const struct qlcnic_legacy_intr_set *legacy_intrp;
struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -323,8 +484,10 @@ static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
offset);
dev_info(&pdev->dev, "using msi interrupts\n");
adapter->msix_entries[0].vector = pdev->irq;
- return;
+ return err;
}
+ if (qlcnic_use_msi || qlcnic_use_msi_x)
+ return -EOPNOTSUPP;
legacy_intrp = &legacy_intr[adapter->ahw->pci_func];
adapter->ahw->int_vec_bit = legacy_intrp->int_vec_bit;
@@ -336,32 +499,47 @@ static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
adapter->crb_int_state_reg = qlcnic_get_ioaddr(ahw, ISR_INT_STATE_REG);
dev_info(&pdev->dev, "using legacy interrupts\n");
adapter->msix_entries[0].vector = pdev->irq;
+ return err;
}
-static void
-qlcnic_setup_intr(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
{
- int num_msix;
+ int num_msix, err = 0;
- if (adapter->ahw->msix_supported) {
+ if (!num_intr)
+ num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS;
+
+ if (adapter->ahw->msix_supported)
num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
- QLCNIC_DEF_NUM_STS_DESC_RINGS));
- } else
+ num_intr));
+ else
num_msix = 1;
- if (!qlcnic_enable_msix(adapter, num_msix))
- return;
+ err = qlcnic_enable_msix(adapter, num_msix);
+ if (err == -ENOMEM || !err)
+ return err;
- qlcnic_enable_msi_legacy(adapter);
+ err = qlcnic_enable_msi_legacy(adapter);
+ if (!err)
+ return err;
+
+ return -EIO;
}
-static void
-qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
+void qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
{
if (adapter->flags & QLCNIC_MSIX_ENABLED)
pci_disable_msix(adapter->pdev);
if (adapter->flags & QLCNIC_MSI_ENABLED)
pci_disable_msi(adapter->pdev);
+
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+
+ if (adapter->ahw->intr_tbl) {
+ vfree(adapter->ahw->intr_tbl);
+ adapter->ahw->intr_tbl = NULL;
+ }
}
static void
@@ -371,7 +549,36 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
iounmap(adapter->ahw->pci_base0);
}
-static int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
+static int qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_pci_info *pci_info;
+ int ret;
+
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ switch (adapter->ahw->port_type) {
+ case QLCNIC_GBE:
+ adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_GBE_PORTS;
+ break;
+ case QLCNIC_XGBE:
+ adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_XG_PORTS;
+ break;
+ }
+ return 0;
+ }
+
+ if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
+ return 0;
+
+ pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+ if (!pci_info)
+ return -ENOMEM;
+
+ ret = qlcnic_get_pci_info(adapter, pci_info);
+ kfree(pci_info);
+ return ret;
+}
+
+int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
{
struct qlcnic_pci_info *pci_info;
int i, ret = 0, j = 0;
@@ -423,8 +630,11 @@ static int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
j++;
}
- for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
+ for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) {
adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
+ if (qlcnic_83xx_check(adapter))
+ qlcnic_enable_eswitch(adapter, i, 1);
+ }
kfree(pci_info);
return 0;
@@ -462,40 +672,31 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
QLC_DEV_SET_DRV(0xf, id));
}
} else {
- data = QLCRD32(adapter, QLCNIC_DRV_OP_MODE);
+ data = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
data = (data & ~QLC_DEV_SET_DRV(0xf, ahw->pci_func)) |
(QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
ahw->pci_func));
}
- QLCWR32(adapter, QLCNIC_DRV_OP_MODE, data);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_DRV_OP_MODE, data);
qlcnic_api_unlock(adapter);
err_lock:
return ret;
}
-static void
-qlcnic_check_vf(struct qlcnic_adapter *adapter)
+static void qlcnic_check_vf(struct qlcnic_adapter *adapter,
+ const struct pci_device_id *ent)
{
- void __iomem *msix_base_addr;
- void __iomem *priv_op;
- u32 func;
- u32 msix_base;
u32 op_mode, priv_level;
/* Determine FW API version */
- adapter->ahw->fw_hal_version = readl(adapter->ahw->pci_base0 +
- QLCNIC_FW_API);
+ adapter->ahw->fw_hal_version = QLC_SHARED_REG_RD32(adapter,
+ QLCNIC_FW_API);
/* Find PCI function number */
- pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
- msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE;
- msix_base = readl(msix_base_addr);
- func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
- adapter->ahw->pci_func = func;
+ qlcnic_get_func_no(adapter);
/* Determine function privilege level */
- priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
- op_mode = readl(priv_op);
+ op_mode = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
if (op_mode == QLC_DEV_DRV_DEFAULT)
priv_level = QLCNIC_MGMT_FUNC;
else
@@ -512,12 +713,16 @@ qlcnic_check_vf(struct qlcnic_adapter *adapter)
}
#define QLCNIC_82XX_BAR0_LENGTH 0x00200000UL
+#define QLCNIC_83XX_BAR0_LENGTH 0x4000
static void qlcnic_get_bar_length(u32 dev_id, ulong *bar)
{
switch (dev_id) {
case PCI_DEVICE_ID_QLOGIC_QLE824X:
*bar = QLCNIC_82XX_BAR0_LENGTH;
break;
+ case PCI_DEVICE_ID_QLOGIC_QLE834X:
+ *bar = QLCNIC_83XX_BAR0_LENGTH;
+ break;
default:
*bar = 0;
}
@@ -547,6 +752,7 @@ static int qlcnic_setup_pci_map(struct pci_dev *pdev,
}
dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
+
ahw->pci_base0 = mem_ptr0;
ahw->pci_len0 = pci_len0;
offset = QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(ahw->pci_func));
@@ -581,19 +787,26 @@ static void qlcnic_get_board_name(struct qlcnic_adapter *adapter, char *name)
static void
qlcnic_check_options(struct qlcnic_adapter *adapter)
{
+ int err;
u32 fw_major, fw_minor, fw_build, prev_fw_version;
struct pci_dev *pdev = adapter->pdev;
- struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
prev_fw_version = adapter->fw_version;
- fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
- fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
- fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+ fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+ fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR);
+ fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB);
adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
- if (adapter->ahw->op_mode != QLCNIC_NON_PRIV_FUNC) {
+ err = qlcnic_get_board_info(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Error getting board config info.\n");
+ return;
+ }
+ if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC) {
if (fw_dump->tmpl_hdr == NULL ||
adapter->fw_version > prev_fw_version) {
if (fw_dump->tmpl_hdr)
@@ -604,8 +817,9 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
}
}
- dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
- fw_major, fw_minor, fw_build);
+ dev_info(&pdev->dev, "Driver v%s, firmware v%d.%d.%d\n",
+ QLCNIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build);
+
if (adapter->ahw->port_type == QLCNIC_XGBE) {
if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
@@ -648,9 +862,19 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
adapter->ahw->max_tx_ques = nic_info.max_tx_ques;
adapter->ahw->max_rx_ques = nic_info.max_rx_ques;
adapter->ahw->capabilities = nic_info.capabilities;
+
+ if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
+ u32 temp;
+ temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+ adapter->ahw->capabilities2 = temp;
+ }
adapter->ahw->max_mac_filters = nic_info.max_mac_filters;
adapter->ahw->max_mtu = nic_info.max_mtu;
+ /* Disable NPAR for 83XX */
+ if (qlcnic_83xx_check(adapter))
+ return err;
+
if (adapter->ahw->capabilities & BIT_6)
adapter->flags |= QLCNIC_ESWITCH_ENABLED;
else
@@ -709,7 +933,7 @@ void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
qlcnic_set_netdev_features(adapter, esw_cfg);
}
-static int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
+int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
{
struct qlcnic_esw_func_cfg esw_cfg;
@@ -730,14 +954,17 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
struct qlcnic_esw_func_cfg *esw_cfg)
{
struct net_device *netdev = adapter->netdev;
- netdev_features_t features, vlan_features;
+ unsigned long features, vlan_features;
+
+ if (qlcnic_83xx_check(adapter))
+ return;
features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
- NETIF_F_IPV6_CSUM | NETIF_F_GRO);
+ NETIF_F_IPV6_CSUM | NETIF_F_GRO);
vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER);
+ NETIF_F_IPV6_CSUM);
- if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
+ if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
features |= (NETIF_F_TSO | NETIF_F_TSO6);
vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
}
@@ -747,12 +974,19 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
if (esw_cfg->offload_flags & BIT_0) {
netdev->features |= features;
- if (!(esw_cfg->offload_flags & BIT_1))
+ adapter->rx_csum = 1;
+ if (!(esw_cfg->offload_flags & BIT_1)) {
netdev->features &= ~NETIF_F_TSO;
- if (!(esw_cfg->offload_flags & BIT_2))
+ features &= ~NETIF_F_TSO;
+ }
+ if (!(esw_cfg->offload_flags & BIT_2)) {
netdev->features &= ~NETIF_F_TSO6;
+ features &= ~NETIF_F_TSO6;
+ }
} else {
netdev->features &= ~features;
+ features &= ~features;
+ adapter->rx_csum = 0;
}
netdev->vlan_features = (features & vlan_features);
@@ -761,7 +995,6 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
static int
qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
{
- void __iomem *priv_op;
u32 op_mode, priv_level;
int err = 0;
@@ -772,8 +1005,7 @@ 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;
- op_mode = readl(priv_op);
+ op_mode = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func);
if (op_mode == QLC_DEV_DRV_DEFAULT)
@@ -805,7 +1037,7 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
return err;
}
-static int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
+int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
{
struct qlcnic_esw_func_cfg esw_cfg;
struct qlcnic_npar_info *npar;
@@ -838,6 +1070,7 @@ static int qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
return 0;
}
+
static int
qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
struct qlcnic_npar_info *npar, int pci_func)
@@ -861,7 +1094,7 @@ qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
return 0;
}
-static int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
+int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
{
int i, err;
struct qlcnic_npar_info *npar;
@@ -877,8 +1110,7 @@ static int qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
npar = &adapter->npars[i];
pci_func = npar->pci_func;
memset(&nic_info, 0, sizeof(struct qlcnic_info));
- err = qlcnic_get_nic_info(adapter,
- &nic_info, pci_func);
+ err = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
if (err)
return err;
nic_info.min_tx_bw = npar->min_bw;
@@ -909,14 +1141,16 @@ static int qlcnic_check_npar_opertional(struct qlcnic_adapter *adapter)
if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
return 0;
- npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+ npar_state = QLC_SHARED_REG_RD32(adapter,
+ QLCNIC_CRB_DEV_NPAR_STATE);
while (npar_state != QLCNIC_DEV_NPAR_OPER && --npar_opt_timeo) {
msleep(1000);
- npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+ npar_state = QLC_SHARED_REG_RD32(adapter,
+ QLCNIC_CRB_DEV_NPAR_STATE);
}
if (!npar_opt_timeo) {
dev_err(&adapter->pdev->dev,
- "Waiting for NPAR state to opertional timeout\n");
+ "Waiting for NPAR state to operational timeout\n");
return -EIO;
}
return 0;
@@ -944,8 +1178,7 @@ qlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter)
return err;
}
-static int
-qlcnic_start_firmware(struct qlcnic_adapter *adapter)
+int qlcnic_82xx_start_firmware(struct qlcnic_adapter *adapter)
{
int err;
@@ -985,9 +1218,8 @@ check_fw_status:
if (err)
goto err_out;
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
qlcnic_idc_debug_info(adapter, 1);
-
err = qlcnic_check_eswitch_mode(adapter);
if (err) {
dev_err(&adapter->pdev->dev,
@@ -1005,7 +1237,7 @@ check_fw_status:
return 0;
err_out:
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
dev_err(&adapter->pdev->dev, "Device state set to failed\n");
qlcnic_release_firmware(adapter);
@@ -1017,6 +1249,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
{
irq_handler_t handler;
struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
int err, ring;
unsigned long flags = 0;
@@ -1024,7 +1257,8 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
- handler = qlcnic_tmp_intr;
+ if (qlcnic_82xx_check(adapter))
+ handler = qlcnic_tmp_intr;
if (!QLCNIC_IS_MSI_FAMILY(adapter))
flags |= IRQF_SHARED;
@@ -1035,20 +1269,44 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
handler = qlcnic_msi_intr;
else {
flags |= IRQF_SHARED;
- handler = qlcnic_intr;
+ if (qlcnic_82xx_check(adapter))
+ handler = qlcnic_intr;
+ else
+ handler = qlcnic_83xx_intr;
}
}
adapter->irq = netdev->irq;
- for (ring = 0; ring < adapter->max_sds_rings; ring++) {
- sds_ring = &recv_ctx->sds_rings[ring];
- sprintf(sds_ring->name, "%s[%d]", netdev->name, ring);
- err = request_irq(sds_ring->irq, handler,
- flags, sds_ring->name, sds_ring);
- if (err)
- return err;
+ if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+ if (qlcnic_82xx_check(adapter) ||
+ (qlcnic_83xx_check(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED))) {
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ snprintf(sds_ring->name, sizeof(int) + IFNAMSIZ,
+ "%s[%d]", netdev->name, ring);
+ err = request_irq(sds_ring->irq, handler, flags,
+ sds_ring->name, sds_ring);
+ if (err)
+ return err;
+ }
+ }
+ if (qlcnic_83xx_check(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ handler = qlcnic_msix_tx_intr;
+ for (ring = 0; ring < adapter->max_drv_tx_rings;
+ ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ snprintf(tx_ring->name, sizeof(int) + IFNAMSIZ,
+ "%s[%d]", netdev->name,
+ adapter->max_sds_rings + ring);
+ err = request_irq(tx_ring->irq, handler, flags,
+ tx_ring->name, tx_ring);
+ if (err)
+ return err;
+ }
+ }
}
-
return 0;
}
@@ -1057,21 +1315,48 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)
{
int ring;
struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_host_tx_ring *tx_ring;
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];
- free_irq(sds_ring->irq, sds_ring);
+ if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+ if (qlcnic_82xx_check(adapter) ||
+ (qlcnic_83xx_check(adapter) &&
+ (adapter->flags & QLCNIC_MSIX_ENABLED))) {
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ free_irq(sds_ring->irq, sds_ring);
+ }
+ }
+ if (qlcnic_83xx_check(adapter)) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings;
+ ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ if (tx_ring->irq)
+ free_irq(tx_ring->irq, tx_ring);
+ }
+ }
}
}
-static int
-__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+static void qlcnic_get_lro_mss_capability(struct qlcnic_adapter *adapter)
{
- int ring;
- u32 capab2;
+ u32 capab = 0;
+
+ if (qlcnic_82xx_check(adapter)) {
+ if (adapter->ahw->capabilities2 &
+ QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
+ adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+ } else {
+ capab = adapter->ahw->capabilities;
+ if (QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(capab))
+ adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+ }
+}
+int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+ int ring;
struct qlcnic_host_rds_ring *rds_ring;
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
@@ -1081,19 +1366,14 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
return 0;
if (qlcnic_set_eswitch_port_config(adapter))
return -EIO;
-
- if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
- capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
- if (capab2 & QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
- adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
- }
+ qlcnic_get_lro_mss_capability(adapter);
if (qlcnic_fw_create_ctx(adapter))
return -EIO;
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &adapter->recv_ctx->rds_rings[ring];
- qlcnic_post_rx_buffers(adapter, rds_ring);
+ qlcnic_post_rx_buffers(adapter, rds_ring, ring);
}
qlcnic_set_multi(netdev);
@@ -1118,10 +1398,7 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
return 0;
}
-/* Usage: During resume and firmware recovery module.*/
-
-static int
-qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+int qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
{
int err = 0;
@@ -1133,8 +1410,7 @@ qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
return err;
}
-static void
-__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
{
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
return;
@@ -1166,8 +1442,7 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
/* Usage: During suspend and firmware recovery module */
-static void
-qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+void qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
{
rtnl_lock();
if (netif_running(netdev))
@@ -1176,7 +1451,7 @@ qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
}
-static int
+int
qlcnic_attach(struct qlcnic_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -1222,8 +1497,7 @@ err_out_napi_del:
return err;
}
-static void
-qlcnic_detach(struct qlcnic_adapter *adapter)
+void qlcnic_detach(struct qlcnic_adapter *adapter)
{
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
return;
@@ -1272,21 +1546,9 @@ out:
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;
}
@@ -1294,6 +1556,8 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
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;
+ /* clear stats */
+ memset(&adapter->stats, 0, sizeof(adapter->stats));
err_out:
return err;
}
@@ -1307,8 +1571,9 @@ static void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter)
vfree(adapter->ahw->fw_dump.tmpl_hdr);
adapter->ahw->fw_dump.tmpl_hdr = NULL;
}
- kfree(adapter->ahw);
- adapter->ahw = NULL;
+
+ kfree(adapter->ahw->reset.buff);
+ adapter->ahw->fw_dump.tmpl_hdr = NULL;
}
int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
@@ -1328,6 +1593,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
adapter->max_sds_rings = 1;
adapter->ahw->diag_test = test;
+ adapter->ahw->linkup = 0;
ret = qlcnic_attach(adapter);
if (ret) {
@@ -1344,7 +1610,7 @@ 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, rds_ring);
+ qlcnic_post_rx_buffers(adapter, rds_ring, ring);
}
if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
@@ -1382,6 +1648,7 @@ qlcnic_reset_hw_context(struct qlcnic_adapter *adapter)
netif_device_attach(netdev);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ dev_err(&adapter->pdev->dev, "%s:\n", __func__);
return 0;
}
@@ -1425,34 +1692,40 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
int err;
struct pci_dev *pdev = adapter->pdev;
+ adapter->rx_csum = 1;
adapter->ahw->mc_enabled = 0;
- adapter->ahw->max_mc_count = 38;
+ adapter->ahw->max_mc_count = QLCNIC_MAX_MC_COUNT;
netdev->netdev_ops = &qlcnic_netdev_ops;
- netdev->watchdog_timeo = 5*HZ;
+ netdev->watchdog_timeo = QLCNIC_WATCHDOG_TIMEOUTVALUE * HZ;
qlcnic_change_mtu(netdev, netdev->mtu);
SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
- netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
+ netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
+ 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);
+
+ if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
+ netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+ netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
+ }
- if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
- netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
- if (pci_using_dac == 1)
- 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 (qlcnic_vlan_tx_check(adapter))
+ netdev->features |= (NETIF_F_HW_VLAN_TX);
- if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX)
- netdev->hw_features |= NETIF_F_HW_VLAN_TX;
if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
- netdev->hw_features |= NETIF_F_LRO;
-
- netdev->features |= netdev->hw_features |
- NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+ netdev->features |= NETIF_F_LRO;
+ netdev->hw_features = netdev->features;
netdev->irq = adapter->msix_entries[0].vector;
err = register_netdev(netdev);
@@ -1480,17 +1753,61 @@ static int qlcnic_set_dma_mask(struct pci_dev *pdev, int *pci_using_dac)
return 0;
}
-static int
-qlcnic_alloc_msix_entries(struct qlcnic_adapter *adapter, u16 count)
+void qlcnic_free_tx_rings(struct qlcnic_adapter *adapter)
{
- adapter->msix_entries = kcalloc(count, sizeof(struct msix_entry),
- GFP_KERNEL);
+ int ring;
+ struct qlcnic_host_tx_ring *tx_ring;
- if (adapter->msix_entries)
- return 0;
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ if (tx_ring && tx_ring->cmd_buf_arr != NULL) {
+ vfree(tx_ring->cmd_buf_arr);
+ tx_ring->cmd_buf_arr = NULL;
+ }
+ }
+ if (adapter->tx_ring != NULL)
+ kfree(adapter->tx_ring);
+}
+
+int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,
+ struct net_device *netdev)
+{
+ int ring, vector, index;
+ struct qlcnic_host_tx_ring *tx_ring;
+ struct qlcnic_cmd_buffer *cmd_buf_arr;
+
+ tx_ring = kcalloc(adapter->max_drv_tx_rings,
+ sizeof(struct qlcnic_host_tx_ring), GFP_KERNEL);
+ if (tx_ring == NULL)
+ return -ENOMEM;
- dev_err(&adapter->pdev->dev, "failed allocating msix_entries\n");
- return -ENOMEM;
+ adapter->tx_ring = tx_ring;
+
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ tx_ring->num_desc = adapter->num_txd;
+ tx_ring->txq = netdev_get_tx_queue(netdev, ring);
+ cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
+ if (cmd_buf_arr == NULL) {
+ qlcnic_free_tx_rings(adapter);
+ return -ENOMEM;
+ }
+ memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
+ tx_ring->cmd_buf_arr = cmd_buf_arr;
+ }
+
+ if (qlcnic_83xx_check(adapter)) {
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ tx_ring->adapter = adapter;
+ if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ index = adapter->max_sds_rings + ring;
+ vector = adapter->msix_entries[index].vector;
+ tx_ring->irq = vector;
+ }
+ }
+ }
+ return 0;
}
static int
@@ -1498,9 +1815,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *netdev = NULL;
struct qlcnic_adapter *adapter = NULL;
+ struct qlcnic_hardware_context *ahw;
int err, pci_using_dac = -1;
- uint8_t revision_id;
- char board_name[QLCNIC_MAX_BOARD_NAME_LEN];
+ u32 capab2;
+ char board_name[QLCNIC_MAX_BOARD_NAME_LEN + 19]; /* MAC + ": " + name */
err = pci_enable_device(pdev);
if (err)
@@ -1522,10 +1840,27 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
pci_enable_pcie_error_reporting(pdev);
+ ahw = kzalloc(sizeof(struct qlcnic_hardware_context), GFP_KERNEL);
+ if (!ahw)
+ goto err_out_free_res;
+
+ if (ent->device == PCI_DEVICE_ID_QLOGIC_QLE824X) {
+ ahw->hw_ops = &qlcnic_hw_ops;
+ ahw->reg_tbl = (u32 *)qlcnic_reg_tbl;
+ } else if (ent->device == PCI_DEVICE_ID_QLOGIC_QLE834X) {
+ qlcnic_83xx_register_map(ahw);
+ } else {
+ goto err_out_free_hw_res;
+ }
+
+ err = qlcnic_setup_pci_map(pdev, ahw);
+ if (err)
+ goto err_out_free_hw_res;
+
netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
if (!netdev) {
err = -ENOMEM;
- goto err_out_free_res;
+ goto err_out_iounmap;
}
SET_NETDEV_DEV(netdev, &pdev->dev);
@@ -1533,15 +1868,25 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter = netdev_priv(netdev);
adapter->netdev = netdev;
adapter->pdev = pdev;
+ adapter->ahw = ahw;
+
+ adapter->qlcnic_wq = create_singlethread_workqueue("qlcnic");
+ if (adapter->qlcnic_wq == NULL) {
+ dev_err(&pdev->dev, "Failed to create workqueue\n");
+ goto err_out_free_netdev;
+ }
err = qlcnic_alloc_adapter_resources(adapter);
if (err)
goto err_out_free_netdev;
adapter->dev_rst_time = jiffies;
- revision_id = pdev->revision;
- adapter->ahw->revision_id = revision_id;
- adapter->mac_learn = qlcnic_mac_learn;
+ adapter->ahw->revision_id = pdev->revision;
+ if (qlcnic_mac_learn == FDB_MAC_LEARN)
+ adapter->fdb_mac_learn = true;
+ else if (qlcnic_mac_learn == DRV_MAC_LEARN)
+ adapter->drv_mac_learn = true;
+ adapter->max_drv_tx_rings = 1;
rwlock_init(&adapter->ahw->crb_lock);
mutex_init(&adapter->ahw->mem_lock);
@@ -1549,31 +1894,32 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
spin_lock_init(&adapter->tx_clean_lock);
INIT_LIST_HEAD(&adapter->mac_list);
- err = qlcnic_setup_pci_map(pdev, adapter->ahw);
- if (err)
- goto err_out_free_hw;
- qlcnic_check_vf(adapter);
-
- /* This will be reset for mezz cards */
- adapter->portnum = adapter->ahw->pci_func;
-
- err = qlcnic_get_board_info(adapter);
- if (err) {
- dev_err(&pdev->dev, "Error getting board config info.\n");
- goto err_out_iounmap;
- }
-
- err = qlcnic_setup_idc_param(adapter);
- if (err)
- goto err_out_iounmap;
+ if (qlcnic_82xx_check(adapter)) {
+ qlcnic_check_vf(adapter, ent);
+ adapter->portnum = adapter->ahw->pci_func;
+ err = qlcnic_start_firmware(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
+ goto err_out_free_hw;
+ }
- adapter->flags |= QLCNIC_NEED_FLR;
+ err = qlcnic_setup_idc_param(adapter);
+ if (err)
+ goto err_out_free_hw;
- err = adapter->nic_ops->start_firmware(adapter);
- if (err) {
- dev_err(&pdev->dev, "Loading fw failed. Please Reboot\n"
- "\t\tIf reboot doesn't help, try flashing the card\n");
- goto err_out_maintenance_mode;
+ adapter->flags |= QLCNIC_NEED_FLR;
+ } else if (qlcnic_83xx_check(adapter)) {
+ qlcnic_83xx_check_vf(adapter, ent);
+ adapter->portnum = adapter->ahw->pci_func;
+ err = qlcnic_83xx_init(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "%s: failed\n", __func__);
+ goto err_out_free_hw;
+ }
+ } else {
+ dev_err(&pdev->dev,
+ "%s: failed. Please Reboot\n", __func__);
+ goto err_out_free_hw;
}
if (qlcnic_read_mac_addr(adapter))
@@ -1581,22 +1927,34 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (adapter->portnum == 0) {
qlcnic_get_board_name(adapter, board_name);
+
pr_info("%s: %s Board Chip rev 0x%x\n",
module_name(THIS_MODULE),
board_name, adapter->ahw->revision_id);
}
+ err = qlcnic_setup_intr(adapter, 0);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to setup interrupt\n");
+ goto err_out_disable_msi;
+ }
- qlcnic_clear_stats(adapter);
-
- err = qlcnic_alloc_msix_entries(adapter, adapter->ahw->max_rx_ques);
- if (err)
- goto err_out_decr_ref;
-
- qlcnic_setup_intr(adapter);
+ if (qlcnic_83xx_check(adapter)) {
+ err = qlcnic_83xx_setup_mbx_intr(adapter);
+ if (err)
+ goto err_out_disable_msi;
+ }
err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
if (err)
- goto err_out_disable_msi;
+ goto err_out_disable_mbx_intr;
+
+ if (qlcnic_82xx_check(adapter)) {
+ if (ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
+ capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+ if (capab2 & QLCNIC_FW_CAPABILITY_2_OCBB)
+ qlcnic_fw_cmd_set_drv_version(adapter);
+ }
+ }
pci_set_drvdata(pdev, adapter);
@@ -1615,29 +1973,37 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
- if (adapter->mac_learn)
+ if (qlcnic_get_act_pci_func(adapter))
+ goto err_out_disable_mbx_intr;
+
+ if (adapter->drv_mac_learn)
qlcnic_alloc_lb_filters_mem(adapter);
- qlcnic_create_diag_entries(adapter);
+ qlcnic_add_sysfs(adapter);
return 0;
+err_out_disable_mbx_intr:
+ if (qlcnic_83xx_check(adapter))
+ qlcnic_83xx_free_mbx_intr(adapter);
+
err_out_disable_msi:
qlcnic_teardown_intr(adapter);
- kfree(adapter->msix_entries);
-
-err_out_decr_ref:
+ qlcnic_cancel_idc_work(adapter);
qlcnic_clr_all_drv_state(adapter, 0);
-err_out_iounmap:
- qlcnic_cleanup_pci_map(adapter);
-
err_out_free_hw:
qlcnic_free_adapter_resources(adapter);
err_out_free_netdev:
free_netdev(netdev);
+err_out_iounmap:
+ qlcnic_cleanup_pci_map(adapter);
+
+err_out_free_hw_res:
+ kfree(ahw);
+
err_out_free_res:
pci_release_regions(pdev);
@@ -1645,24 +2011,13 @@ err_out_disable_pdev:
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
return err;
-
-err_out_maintenance_mode:
- netdev->netdev_ops = &qlcnic_netdev_failed_ops;
- SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
- err = register_netdev(netdev);
- if (err) {
- dev_err(&pdev->dev, "failed to register net device\n");
- goto err_out_decr_ref;
- }
- pci_set_drvdata(pdev, adapter);
- qlcnic_create_diag_entries(adapter);
- return 0;
}
static void qlcnic_remove(struct pci_dev *pdev)
{
struct qlcnic_adapter *adapter;
struct net_device *netdev;
+ struct qlcnic_hardware_context *ahw;
adapter = pci_get_drvdata(pdev);
if (adapter == NULL)
@@ -1670,10 +2025,17 @@ static void qlcnic_remove(struct pci_dev *pdev)
netdev = adapter->netdev;
- qlcnic_cancel_fw_work(adapter);
+ qlcnic_cancel_idc_work(adapter);
+ ahw = adapter->ahw;
unregister_netdev(netdev);
+ if (qlcnic_83xx_check(adapter)) {
+ qlcnic_83xx_free_mbx_intr(adapter);
+ qlcnic_83xx_register_nic_idc_func(adapter, 0);
+ cancel_delayed_work_sync(&adapter->idc_aen_work);
+ }
+
qlcnic_detach(adapter);
if (adapter->npars != NULL)
@@ -1689,9 +2051,8 @@ static void 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);
+ qlcnic_remove_sysfs(adapter);
qlcnic_cleanup_pci_map(adapter);
@@ -1702,7 +2063,12 @@ static void qlcnic_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
+ if (adapter->qlcnic_wq) {
+ destroy_workqueue(adapter->qlcnic_wq);
+ adapter->qlcnic_wq = NULL;
+ }
qlcnic_free_adapter_resources(adapter);
+ kfree(ahw);
free_netdev(netdev);
}
static int __qlcnic_shutdown(struct pci_dev *pdev)
@@ -1713,7 +2079,7 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
netif_device_detach(netdev);
- qlcnic_cancel_fw_work(adapter);
+ qlcnic_cancel_idc_work(adapter);
if (netif_running(netdev))
qlcnic_down(adapter, netdev);
@@ -1726,7 +2092,6 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
retval = pci_save_state(pdev);
if (retval)
return retval;
-
if (qlcnic_82xx_check(adapter)) {
if (qlcnic_wol_supported(adapter)) {
pci_enable_wake(pdev, PCI_D3cold, 1);
@@ -1774,7 +2139,7 @@ qlcnic_resume(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
- err = adapter->nic_ops->start_firmware(adapter);
+ err = qlcnic_start_firmware(adapter);
if (err) {
dev_err(&pdev->dev, "failed to start firmware\n");
return err;
@@ -1797,14 +2162,8 @@ done:
static int qlcnic_open(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
- u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
int err;
- if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
- netdev_err(netdev, "Device in FAILED state\n");
- return -EIO;
- }
-
netif_carrier_off(netdev);
err = qlcnic_attach(adapter);
@@ -1832,6 +2191,7 @@ static int qlcnic_close(struct net_device *netdev)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
__qlcnic_down(adapter, netdev);
+
return 0;
}
@@ -1839,22 +2199,53 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
{
void *head;
int i;
+ struct net_device *netdev = adapter->netdev;
+ u32 filter_size = 0;
+ u16 act_pci_func = 0;
if (adapter->fhash.fmax && adapter->fhash.fhead)
return;
+ act_pci_func = adapter->ahw->act_pci_func;
spin_lock_init(&adapter->mac_learn_lock);
+ spin_lock_init(&adapter->rx_mac_learn_lock);
+
+ if (qlcnic_82xx_check(adapter)) {
+ filter_size = QLCNIC_LB_MAX_FILTERS;
+ adapter->fhash.fbucket_size = QLCNIC_LB_BUCKET_SIZE;
+ } else {
+ filter_size = QLC_83XX_LB_MAX_FILTERS;
+ adapter->fhash.fbucket_size = QLC_83XX_LB_BUCKET_SIZE;
+ }
+
+ head = kcalloc(adapter->fhash.fbucket_size,
+ sizeof(struct hlist_head), GFP_ATOMIC);
- head = kcalloc(QLCNIC_LB_MAX_FILTERS, sizeof(struct hlist_head),
- GFP_KERNEL);
if (!head)
return;
- adapter->fhash.fmax = QLCNIC_LB_MAX_FILTERS;
+ adapter->fhash.fmax = (filter_size / act_pci_func);
adapter->fhash.fhead = head;
- for (i = 0; i < adapter->fhash.fmax; i++)
+ netdev_info(netdev, "active nic func = %d, mac filter size=%d\n",
+ act_pci_func, adapter->fhash.fmax);
+
+ for (i = 0; i < adapter->fhash.fbucket_size; i++)
INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
+
+ adapter->rx_fhash.fbucket_size = adapter->fhash.fbucket_size;
+
+ head = kcalloc(adapter->rx_fhash.fbucket_size,
+ sizeof(struct hlist_head), GFP_ATOMIC);
+
+ if (!head)
+ return;
+
+ adapter->rx_fhash.fmax = (filter_size / act_pci_func);
+ adapter->rx_fhash.fhead = head;
+
+ for (i = 0; i < adapter->rx_fhash.fbucket_size; i++)
+ INIT_HLIST_HEAD(&adapter->rx_fhash.fhead[i]);
}
static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
@@ -1864,16 +2255,25 @@ static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
adapter->fhash.fhead = NULL;
adapter->fhash.fmax = 0;
+
+ if (adapter->rx_fhash.fmax && adapter->rx_fhash.fhead)
+ kfree(adapter->rx_fhash.fhead);
+
+ adapter->rx_fhash.fmax = 0;
+ adapter->rx_fhash.fhead = NULL;
}
-static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
+int qlcnic_check_temp(struct qlcnic_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
u32 temp_state, temp_val, temp = 0;
int rv = 0;
+ if (qlcnic_83xx_check(adapter))
+ temp = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP);
+
if (qlcnic_82xx_check(adapter))
- temp = QLCRD32(adapter, CRB_TEMP_STATE);
+ temp = QLC_SHARED_REG_RD32(adapter, QLCNIC_ASIC_TEMP);
temp_state = qlcnic_get_temp_state(temp);
temp_val = qlcnic_get_temp_val(temp);
@@ -1933,7 +2333,7 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
return stats;
}
-static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
+irqreturn_t qlcnic_82xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
{
u32 status;
@@ -2009,6 +2409,14 @@ static irqreturn_t qlcnic_msix_intr(int irq, void *data)
return IRQ_HANDLED;
}
+static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data)
+{
+ struct qlcnic_host_tx_ring *tx_ring = data;
+
+ napi_schedule(&tx_ring->napi);
+ return IRQ_HANDLED;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void qlcnic_poll_controller(struct net_device *netdev)
{
@@ -2035,7 +2443,7 @@ qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
val |= encoding << 7;
val |= (jiffies - adapter->dev_rst_time) << 8;
- QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
adapter->dev_rst_time = jiffies;
}
@@ -2050,14 +2458,14 @@ qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
if (qlcnic_api_lock(adapter))
return -EIO;
- val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
if (state == QLCNIC_DEV_NEED_RESET)
QLC_DEV_SET_RST_RDY(val, adapter->portnum);
else if (state == QLCNIC_DEV_NEED_QUISCENT)
QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
- QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
qlcnic_api_unlock(adapter);
@@ -2072,9 +2480,9 @@ qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
if (qlcnic_api_lock(adapter))
return -EBUSY;
- val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
- QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
qlcnic_api_unlock(adapter);
@@ -2089,20 +2497,22 @@ qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
if (qlcnic_api_lock(adapter))
goto err;
- val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
- QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
if (failed) {
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+ QLCNIC_DEV_FAILED);
dev_info(&adapter->pdev->dev,
"Device state set to Failed. Please Reboot\n");
} else if (!(val & 0x11111111))
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+ QLCNIC_DEV_COLD);
- val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
- QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
qlcnic_api_unlock(adapter);
err:
@@ -2117,12 +2527,13 @@ static int
qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
{
int act, state, active_mask;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
- state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
- act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+ state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
+ act = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
if (adapter->flags & QLCNIC_FW_RESET_OWNER) {
- active_mask = (~(1 << (adapter->ahw->pci_func * 4)));
+ active_mask = (~(1 << (ahw->pci_func * 4)));
act = act & active_mask;
}
@@ -2135,7 +2546,7 @@ qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
{
- u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
+ u32 val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
if (val != QLCNIC_DRV_IDC_VER) {
dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
@@ -2159,19 +2570,21 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
if (qlcnic_api_lock(adapter))
return -1;
- val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
if (!(val & (1 << (portnum * 4)))) {
QLC_DEV_SET_REF_CNT(val, portnum);
- QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
}
- prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
QLCDB(adapter, HW, "Device state = %u\n", prev_state);
switch (prev_state) {
case QLCNIC_DEV_COLD:
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
- QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+ QLCNIC_DEV_INITIALIZING);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_IDC_VER,
+ QLCNIC_DRV_IDC_VER);
qlcnic_idc_debug_info(adapter, 0);
qlcnic_api_unlock(adapter);
return 1;
@@ -2182,15 +2595,15 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
return ret;
case QLCNIC_DEV_NEED_RESET:
- val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
QLC_DEV_SET_RST_RDY(val, portnum);
- QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
break;
case QLCNIC_DEV_NEED_QUISCENT:
- val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
QLC_DEV_SET_QSCNT_RDY(val, portnum);
- QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
break;
case QLCNIC_DEV_FAILED:
@@ -2207,7 +2620,7 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
do {
msleep(1000);
- prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (prev_state == QLCNIC_DEV_QUISCENT)
continue;
@@ -2222,9 +2635,9 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
if (qlcnic_api_lock(adapter))
return -1;
- val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DRV_STATE);
QLC_DEV_CLR_RST_QSCNT(val, portnum);
- QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DRV_STATE, val);
ret = qlcnic_check_idc_ver(adapter);
qlcnic_api_unlock(adapter);
@@ -2243,7 +2656,7 @@ qlcnic_fwinit_work(struct work_struct *work)
if (qlcnic_api_lock(adapter))
goto err_ret;
- dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (dev_state == QLCNIC_DEV_QUISCENT ||
dev_state == QLCNIC_DEV_NEED_QUISCENT) {
qlcnic_api_unlock(adapter);
@@ -2272,17 +2685,19 @@ qlcnic_fwinit_work(struct work_struct *work)
if (!qlcnic_check_drv_state(adapter)) {
skip_ack_check:
- dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (dev_state == QLCNIC_DEV_NEED_RESET) {
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
- QLCNIC_DEV_INITIALIZING);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+ QLCNIC_DEV_INITIALIZING);
set_bit(__QLCNIC_START_FW, &adapter->state);
QLCDB(adapter, DRV, "Restarting fw\n");
qlcnic_idc_debug_info(adapter, 0);
- val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+ val = QLC_SHARED_REG_RD32(adapter,
+ QLCNIC_CRB_DRV_STATE);
QLC_DEV_SET_RST_RDY(val, adapter->portnum);
- QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+ QLC_SHARED_REG_WR32(adapter,
+ QLCNIC_CRB_DRV_STATE, val);
}
qlcnic_api_unlock(adapter);
@@ -2308,12 +2723,12 @@ skip_ack_check:
qlcnic_api_unlock(adapter);
wait_npar:
- dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ dev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
switch (dev_state) {
case QLCNIC_DEV_READY:
- if (!adapter->nic_ops->start_firmware(adapter)) {
+ if (!qlcnic_start_firmware(adapter)) {
qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
adapter->fw_wait_cnt = 0;
return;
@@ -2350,7 +2765,7 @@ qlcnic_detach_work(struct work_struct *work)
} else
qlcnic_down(adapter, netdev);
- status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+ status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
if (status & QLCNIC_RCODE_FATAL_ERROR) {
dev_err(&adapter->pdev->dev,
@@ -2401,19 +2816,18 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
{
u32 state;
- state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+ state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
if (state == QLCNIC_DEV_NPAR_NON_OPER)
return;
if (qlcnic_api_lock(adapter))
return;
- QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+ QLCNIC_DEV_NPAR_NON_OPER);
qlcnic_api_unlock(adapter);
}
-/*Transit to RESET state from READY state only */
-void
-qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key)
{
u32 state, xg_val = 0, gb_val = 0;
@@ -2428,25 +2842,22 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
dev_info(&adapter->pdev->dev, "Pause control frames disabled"
" on all ports\n");
adapter->need_fw_reset = 1;
+
if (qlcnic_api_lock(adapter))
return;
- state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
- if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
- netdev_err(adapter->netdev,
- "Device is in FAILED state, Please Reboot\n");
- qlcnic_api_unlock(adapter);
- return;
- }
+ state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state == QLCNIC_DEV_READY) {
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+ QLCNIC_DEV_NEED_RESET);
adapter->flags |= QLCNIC_FW_RESET_OWNER;
QLCDB(adapter, DRV, "NEED_RESET state set\n");
qlcnic_idc_debug_info(adapter, 0);
}
- QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+ QLCNIC_DEV_NPAR_NON_OPER);
qlcnic_api_unlock(adapter);
}
@@ -2457,34 +2868,22 @@ qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
if (qlcnic_api_lock(adapter))
return;
- QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+ QLCNIC_DEV_NPAR_OPER);
QLCDB(adapter, DRV, "NPAR operational state set\n");
qlcnic_api_unlock(adapter);
}
-static void
-qlcnic_schedule_work(struct qlcnic_adapter *adapter,
- work_func_t func, int delay)
+void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
+ work_func_t func, int delay)
{
if (test_bit(__QLCNIC_AER, &adapter->state))
return;
INIT_DELAYED_WORK(&adapter->fw_work, func);
- queue_delayed_work(qlcnic_wq, &adapter->fw_work,
- round_jiffies_relative(delay));
-}
-
-static void
-qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
-{
- while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
- msleep(10);
-
- if (!adapter->fw_work.work.func)
- return;
-
- cancel_delayed_work_sync(&adapter->fw_work);
+ queue_delayed_work(adapter->qlcnic_wq, &adapter->fw_work,
+ round_jiffies_relative(delay));
}
static void
@@ -2496,7 +2895,8 @@ qlcnic_attach_work(struct work_struct *work)
u32 npar_state;
if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
- npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+ npar_state = QLC_SHARED_REG_RD32(adapter,
+ QLCNIC_CRB_DEV_NPAR_STATE);
if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO)
qlcnic_clr_all_drv_state(adapter, 0);
else if (npar_state != QLCNIC_DEV_NPAR_OPER)
@@ -2536,16 +2936,16 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
goto detach;
if (adapter->need_fw_reset)
- qlcnic_dev_request_reset(adapter);
+ qlcnic_dev_request_reset(adapter, 0);
- state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+ state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state == QLCNIC_DEV_NEED_RESET) {
qlcnic_set_npar_non_operational(adapter);
adapter->need_fw_reset = 1;
} else if (state == QLCNIC_DEV_NEED_QUISCENT)
goto detach;
- heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+ heartbeat = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
if (heartbeat != adapter->heartbeat) {
adapter->heartbeat = heartbeat;
adapter->fw_fail_cnt = 0;
@@ -2565,25 +2965,25 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
adapter->flags |= QLCNIC_FW_HANG;
- qlcnic_dev_request_reset(adapter);
+ qlcnic_dev_request_reset(adapter, 0);
if (qlcnic_auto_fw_reset)
clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
dev_err(&adapter->pdev->dev, "firmware hang detected\n");
+ peg_status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
dev_err(&adapter->pdev->dev, "Dumping hw/fw registers\n"
"PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
"PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
"PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
"PEG_NET_4_PC: 0x%x\n",
- QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1),
- QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS2),
+ peg_status,
+ QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS2),
QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c),
QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c),
QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c),
QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c),
QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c));
- peg_status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
dev_err(&adapter->pdev->dev,
"Firmware aborted with error code 0x00006700. "
@@ -2667,17 +3067,39 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
if (adapter->ahw->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
adapter->need_fw_reset = 1;
set_bit(__QLCNIC_START_FW, &adapter->state);
- QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_CRB_DEV_STATE,
+ QLCNIC_DEV_INITIALIZING);
QLCDB(adapter, DRV, "Restarting fw\n");
}
qlcnic_api_unlock(adapter);
- err = adapter->nic_ops->start_firmware(adapter);
+ err = qlcnic_start_firmware(adapter);
if (err)
return err;
qlcnic_clr_drv_state(adapter);
- qlcnic_setup_intr(adapter);
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+ err = qlcnic_setup_intr(adapter, 0);
+
+ if (err) {
+ kfree(adapter->msix_entries);
+ netdev_err(netdev, "failed to setup interrupt\n");
+ return err;
+ }
+
+ if (qlcnic_83xx_check(adapter)) {
+ /* register for NIC IDC AEN Events */
+ qlcnic_83xx_register_nic_idc_func(adapter, 1);
+ err = qlcnic_83xx_setup_mbx_intr(adapter);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "failed to setup mbx interrupt\n");
+ qlcnic_clr_all_drv_state(adapter, 1);
+ clear_bit(__QLCNIC_AER, &adapter->state);
+ goto done;
+ }
+ }
if (netif_running(netdev)) {
err = qlcnic_attach(adapter);
@@ -2719,6 +3141,12 @@ static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
if (netif_running(netdev))
qlcnic_down(adapter, netdev);
+ if (qlcnic_83xx_check(adapter)) {
+ qlcnic_83xx_free_mbx_intr(adapter);
+ qlcnic_83xx_register_nic_idc_func(adapter, 0);
+ cancel_delayed_work_sync(&adapter->idc_aen_work);
+ }
+
qlcnic_detach(adapter);
qlcnic_teardown_intr(adapter);
@@ -2738,12 +3166,13 @@ static pci_ers_result_t qlcnic_io_slot_reset(struct pci_dev *pdev)
static void qlcnic_io_resume(struct pci_dev *pdev)
{
+ u32 state;
struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
pci_cleanup_aer_uncorrect_error_status(pdev);
-
- if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
- test_and_clear_bit(__QLCNIC_AER, &adapter->state))
+ state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
+ if (state == QLCNIC_DEV_READY && test_and_clear_bit(__QLCNIC_AER,
+ &adapter->state))
qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
FW_POLL_DELAY);
}
@@ -2776,39 +3205,59 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
return err;
}
-int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val)
+int qlcnic_validate_max_rss(u8 max_hw, u8 val)
{
- if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
- netdev_info(netdev, "no msix or msi support, hence no rss\n");
- return -EINVAL;
+ u32 max_allowed;
+
+ if (max_hw > QLC_MAX_SDS_RINGS) {
+ max_hw = QLC_MAX_SDS_RINGS;
+ pr_info("max rss reset to %d\n", QLC_MAX_SDS_RINGS);
}
- 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);
+ max_allowed = rounddown_pow_of_two(min_t(int, max_hw,
+ num_online_cpus()));
+ if ((val > max_allowed) || (val < 2) || !is_power_of_2(val)) {
+ pr_info("rss_ring valid range [2 - %x] in powers of 2\n",
+ max_allowed);
return -EINVAL;
}
return 0;
-
}
-int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
+int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len)
{
+ int err;
struct net_device *netdev = adapter->netdev;
- int err = 0;
- if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state))
return -EBUSY;
netif_device_detach(netdev);
if (netif_running(netdev))
__qlcnic_down(adapter, netdev);
+
qlcnic_detach(adapter);
+
+ if (qlcnic_83xx_check(adapter))
+ qlcnic_83xx_free_mbx_intr(adapter);
+
qlcnic_teardown_intr(adapter);
+ err = qlcnic_setup_intr(adapter, data);
+ if (err) {
+ kfree(adapter->msix_entries);
+ netdev_err(netdev, "failed to setup interrupt\n");
+ return err;
+ }
- if (qlcnic_enable_msix(adapter, data)) {
- netdev_info(netdev, "failed setting max_rss; rss disabled\n");
- qlcnic_enable_msi_legacy(adapter);
+ if (qlcnic_83xx_check(adapter)) {
+ /* register for NIC IDC AEN Events */
+ qlcnic_83xx_register_nic_idc_func(adapter, 1);
+ err = qlcnic_83xx_setup_mbx_intr(adapter);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "failed to setup mbx interrupt\n");
+ goto done;
+ }
}
if (netif_running(netdev)) {
@@ -2820,6 +3269,7 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
goto done;
qlcnic_restore_indev_addr(netdev, NETDEV_UP);
}
+ err = len;
done:
netif_device_attach(netdev);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -2858,8 +3308,7 @@ qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
in_dev_put(indev);
}
-static void
-qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
+void qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct net_device *dev;
@@ -2867,12 +3316,14 @@ qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
qlcnic_config_indev_addr(adapter, netdev, event);
+ rcu_read_lock();
for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) {
dev = __vlan_find_dev_deep(netdev, vid);
if (!dev)
continue;
qlcnic_config_indev_addr(adapter, dev, event);
}
+ rcu_read_unlock();
}
static int qlcnic_netdev_event(struct notifier_block *this,
@@ -2940,9 +3391,11 @@ recheck:
switch (event) {
case NETDEV_UP:
qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
+
break;
case NETDEV_DOWN:
qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
+
break;
default:
break;
@@ -2960,11 +3413,10 @@ static struct notifier_block qlcnic_inetaddr_cb = {
.notifier_call = qlcnic_inetaddr_event,
};
#else
-static void
-qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event)
+void qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event)
{ }
#endif
-static struct pci_error_handlers qlcnic_err_handler = {
+static const struct pci_error_handlers qlcnic_err_handler = {
.error_detected = qlcnic_io_error_detected,
.slot_reset = qlcnic_io_slot_reset,
.resume = qlcnic_io_resume,
@@ -2990,12 +3442,6 @@ static int __init qlcnic_init_module(void)
printk(KERN_INFO "%s\n", qlcnic_driver_string);
- qlcnic_wq = create_singlethread_workqueue("qlcnic");
- if (qlcnic_wq == NULL) {
- printk(KERN_ERR "qlcnic: cannot create workqueue\n");
- return -ENOMEM;
- }
-
#ifdef CONFIG_INET
register_netdevice_notifier(&qlcnic_netdev_cb);
register_inetaddr_notifier(&qlcnic_inetaddr_cb);
@@ -3007,7 +3453,6 @@ static int __init qlcnic_init_module(void)
unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
unregister_netdevice_notifier(&qlcnic_netdev_cb);
#endif
- destroy_workqueue(qlcnic_wq);
}
return ret;
@@ -3017,14 +3462,12 @@ module_init(qlcnic_init_module);
static void __exit qlcnic_exit_module(void)
{
-
pci_unregister_driver(&qlcnic_driver);
#ifdef CONFIG_INET
unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
unregister_netdevice_notifier(&qlcnic_netdev_cb);
#endif
- destroy_workqueue(qlcnic_wq);
}
module_exit(qlcnic_exit_module);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
index 0b8d8625834c..abbd22c814a6 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -1,8 +1,25 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
#include "qlcnic.h"
#include "qlcnic_hdr.h"
+#include "qlcnic_83xx_hw.h"
+#include "qlcnic_hw.h"
#include <net/ip.h>
+#define QLC_83XX_MINIDUMP_FLASH 0x520000
+#define QLC_83XX_OCM_INDEX 3
+#define QLC_83XX_PCI_INDEX 0
+
+static const u32 qlcnic_ms_read_data[] = {
+ 0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC
+};
+
#define QLCNIC_DUMP_WCRB BIT_0
#define QLCNIC_DUMP_RWCRB BIT_1
#define QLCNIC_DUMP_ANDCRB BIT_2
@@ -102,16 +119,55 @@ struct __queue {
u8 rsvd3[2];
} __packed;
+struct __pollrd {
+ u32 sel_addr;
+ u32 read_addr;
+ u32 sel_val;
+ u16 sel_val_stride;
+ u16 no_ops;
+ u32 poll_wait;
+ u32 poll_mask;
+ u32 data_size;
+ u8 rsvd[4];
+} __packed;
+
+struct __mux2 {
+ u32 sel_addr1;
+ u32 sel_addr2;
+ u32 sel_val1;
+ u32 sel_val2;
+ u32 no_ops;
+ u32 sel_val_mask;
+ u32 read_addr;
+ u8 sel_val_stride;
+ u8 data_size;
+ u8 rsvd[2];
+} __packed;
+
+struct __pollrdmwr {
+ u32 addr1;
+ u32 addr2;
+ u32 val1;
+ u32 val2;
+ u32 poll_wait;
+ u32 poll_mask;
+ u32 mod_mask;
+ u32 data_size;
+} __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;
+ struct __crb crb;
+ struct __cache cache;
+ struct __ocm ocm;
+ struct __mem mem;
+ struct __mux mux;
+ struct __queue que;
+ struct __ctrl ctrl;
+ struct __pollrdmwr pollrdmwr;
+ struct __mux2 mux2;
+ struct __pollrd pollrd;
} region;
} __packed;
@@ -131,6 +187,9 @@ enum qlcnic_minidump_opcode {
QLCNIC_DUMP_L2_ITAG = 22,
QLCNIC_DUMP_L2_DATA = 23,
QLCNIC_DUMP_L2_INST = 24,
+ QLCNIC_DUMP_POLL_RD = 35,
+ QLCNIC_READ_MUX2 = 36,
+ QLCNIC_READ_POLLRDMWR = 37,
QLCNIC_DUMP_READ_ROM = 71,
QLCNIC_DUMP_READ_MEM = 72,
QLCNIC_DUMP_READ_CTRL = 98,
@@ -144,46 +203,17 @@ struct qlcnic_dump_operations {
__le32 *);
};
-static void qlcnic_read_dump_reg(u32 addr, void __iomem *bar0, u32 *data)
-{
- u32 dest;
- void __iomem *window_reg;
-
- dest = addr & 0xFFFF0000;
- window_reg = bar0 + QLCNIC_FW_DUMP_REG1;
- writel(dest, window_reg);
- readl(window_reg);
- window_reg = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
- *data = readl(window_reg);
-}
-
-static void qlcnic_write_dump_reg(u32 addr, void __iomem *bar0, u32 data)
-{
- u32 dest;
- void __iomem *window_reg;
-
- dest = addr & 0xFFFF0000;
- window_reg = bar0 + QLCNIC_FW_DUMP_REG1;
- writel(dest, window_reg);
- readl(window_reg);
- window_reg = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
- writel(data, window_reg);
- readl(window_reg);
-}
-
-/* FW dump related functions */
static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
struct qlcnic_dump_entry *entry, __le32 *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_read_dump_reg(addr, base, &data);
+ data = qlcnic_ind_rd(adapter, addr);
*buffer++ = cpu_to_le32(addr);
*buffer++ = cpu_to_le32(data);
addr += crb->stride;
@@ -195,7 +225,6 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
struct qlcnic_dump_entry *entry, __le32 *buffer)
{
int i, k, timeout = 0;
- void __iomem *base = adapter->ahw->pci_base0;
u32 addr, data;
u8 no_ops;
struct __ctrl *ctr = &entry->region.ctrl;
@@ -211,28 +240,28 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
continue;
switch (1 << k) {
case QLCNIC_DUMP_WCRB:
- qlcnic_write_dump_reg(addr, base, ctr->val1);
+ qlcnic_ind_wr(adapter, addr, ctr->val1);
break;
case QLCNIC_DUMP_RWCRB:
- qlcnic_read_dump_reg(addr, base, &data);
- qlcnic_write_dump_reg(addr, base, data);
+ data = qlcnic_ind_rd(adapter, addr);
+ qlcnic_ind_wr(adapter, addr, data);
break;
case QLCNIC_DUMP_ANDCRB:
- qlcnic_read_dump_reg(addr, base, &data);
- qlcnic_write_dump_reg(addr, base,
- data & ctr->val2);
+ data = qlcnic_ind_rd(adapter, addr);
+ qlcnic_ind_wr(adapter, addr,
+ (data & ctr->val2));
break;
case QLCNIC_DUMP_ORCRB:
- qlcnic_read_dump_reg(addr, base, &data);
- qlcnic_write_dump_reg(addr, base,
- data | ctr->val3);
+ data = qlcnic_ind_rd(adapter, addr);
+ qlcnic_ind_wr(adapter, addr,
+ (data | ctr->val3));
break;
case QLCNIC_DUMP_POLLCRB:
while (timeout <= ctr->timeout) {
- qlcnic_read_dump_reg(addr, base, &data);
+ data = qlcnic_ind_rd(adapter, addr);
if ((data & ctr->val2) == ctr->val1)
break;
- msleep(1);
+ usleep_range(1000, 2000);
timeout++;
}
if (timeout > ctr->timeout) {
@@ -244,7 +273,7 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
case QLCNIC_DUMP_RD_SAVE:
if (ctr->index_a)
addr = t_hdr->saved_state[ctr->index_a];
- qlcnic_read_dump_reg(addr, base, &data);
+ data = qlcnic_ind_rd(adapter, addr);
t_hdr->saved_state[ctr->index_v] = data;
break;
case QLCNIC_DUMP_WRT_SAVED:
@@ -254,7 +283,7 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
data = ctr->val1;
if (ctr->index_a)
addr = t_hdr->saved_state[ctr->index_a];
- qlcnic_write_dump_reg(addr, base, data);
+ qlcnic_ind_wr(adapter, addr, data);
break;
case QLCNIC_DUMP_MOD_SAVE_ST:
data = t_hdr->saved_state[ctr->index_v];
@@ -283,12 +312,11 @@ static u32 qlcnic_dump_mux(struct qlcnic_adapter *adapter,
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_write_dump_reg(mux->addr, base, val);
- qlcnic_read_dump_reg(mux->read_addr, base, &data);
+ qlcnic_ind_wr(adapter, mux->addr, val);
+ data = qlcnic_ind_rd(adapter, mux->read_addr);
*buffer++ = cpu_to_le32(val);
*buffer++ = cpu_to_le32(data);
val += mux->val_stride;
@@ -301,17 +329,16 @@ static u32 qlcnic_dump_que(struct qlcnic_adapter *adapter,
{
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_write_dump_reg(que->sel_addr, base, que_id);
+ qlcnic_ind_wr(adapter, que->sel_addr, que_id);
addr = que->read_addr;
for (i = 0; i < cnt; i++) {
- qlcnic_read_dump_reg(addr, base, &data);
+ data = qlcnic_ind_rd(adapter, addr);
*buffer++ = cpu_to_le32(data);
addr += que->read_addr_stride;
}
@@ -343,27 +370,27 @@ static u32 qlcnic_read_rom(struct qlcnic_adapter *adapter,
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;
+ size = rom->size / 4;
lock_try:
- lck_val = readl(base + QLCNIC_FLASH_SEM2_LK);
+ lck_val = QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_LOCK);
if (!lck_val && count < MAX_CTL_CHECK) {
- msleep(10);
+ usleep_range(10000, 11000);
count++;
goto lock_try;
}
- writel(adapter->ahw->pci_func, (base + QLCNIC_FLASH_LOCK_ID));
+ QLC_SHARED_REG_WR32(adapter, QLCNIC_FLASH_LOCK_OWNER,
+ adapter->ahw->pci_func);
for (i = 0; i < size; i++) {
addr = fl_addr & 0xFFFF0000;
- qlcnic_write_dump_reg(FLASH_ROM_WINDOW, base, addr);
+ qlcnic_ind_wr(adapter, FLASH_ROM_WINDOW, addr);
addr = LSW(fl_addr) + FLASH_ROM_DATA;
- qlcnic_read_dump_reg(addr, base, &val);
+ val = qlcnic_ind_rd(adapter, addr);
fl_addr += 4;
*buffer++ = cpu_to_le32(val);
}
- readl(base + QLCNIC_FLASH_SEM2_ULK);
+ QLC_SHARED_REG_RD32(adapter, QLCNIC_FLASH_UNLOCK);
return rom->size;
}
@@ -372,18 +399,17 @@ static u32 qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter,
{
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_write_dump_reg(l1->addr, base, val);
- qlcnic_write_dump_reg(l1->ctrl_addr, base, LSW(l1->ctrl_val));
+ qlcnic_ind_wr(adapter, l1->addr, val);
+ qlcnic_ind_wr(adapter, l1->ctrl_addr, LSW(l1->ctrl_val));
addr = l1->read_addr;
cnt = l1->read_addr_num;
while (cnt) {
- qlcnic_read_dump_reg(addr, base, &data);
+ data = qlcnic_ind_rd(adapter, addr);
*buffer++ = cpu_to_le32(data);
addr += l1->read_addr_stride;
cnt--;
@@ -399,7 +425,6 @@ static u32 qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
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;
@@ -407,17 +432,17 @@ static u32 qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
poll_to = MSB(MSW(l2->ctrl_val));
for (i = 0; i < l2->no_ops; i++) {
- qlcnic_write_dump_reg(l2->addr, base, val);
+ qlcnic_ind_wr(adapter, l2->addr, val);
if (LSW(l2->ctrl_val))
- qlcnic_write_dump_reg(l2->ctrl_addr, base,
- LSW(l2->ctrl_val));
+ qlcnic_ind_wr(adapter, l2->ctrl_addr,
+ LSW(l2->ctrl_val));
if (!poll_mask)
goto skip_poll;
do {
- qlcnic_read_dump_reg(l2->ctrl_addr, base, &data);
+ data = qlcnic_ind_rd(adapter, l2->ctrl_addr);
if (!(data & poll_mask))
break;
- msleep(1);
+ usleep_range(1000, 2000);
time_out++;
} while (time_out <= poll_to);
@@ -431,7 +456,7 @@ skip_poll:
addr = l2->read_addr;
cnt = l2->read_addr_num;
while (cnt) {
- qlcnic_read_dump_reg(addr, base, &data);
+ data = qlcnic_ind_rd(adapter, addr);
*buffer++ = cpu_to_le32(data);
addr += l2->read_addr_stride;
cnt--;
@@ -447,7 +472,6 @@ static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
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;
@@ -462,13 +486,12 @@ static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
mutex_lock(&adapter->ahw->mem_lock);
while (reg_read != 0) {
- qlcnic_write_dump_reg(MIU_TEST_ADDR_LO, base, addr);
- qlcnic_write_dump_reg(MIU_TEST_ADDR_HI, base, 0);
- qlcnic_write_dump_reg(MIU_TEST_CTR, base,
- TA_CTL_ENABLE | TA_CTL_START);
+ qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_LO, addr);
+ qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_HI, 0);
+ qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLCNIC_TA_START_ENABLE);
for (i = 0; i < MAX_CTL_CHECK; i++) {
- qlcnic_read_dump_reg(MIU_TEST_CTR, base, &test);
+ test = qlcnic_ind_rd(adapter, QLCNIC_MS_CTRL);
if (!(test & TA_CTL_BUSY))
break;
}
@@ -481,8 +504,7 @@ static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
}
}
for (i = 0; i < 4; i++) {
- qlcnic_read_dump_reg(MIU_TEST_READ_DATA[i], base,
- &data);
+ data = qlcnic_ind_rd(adapter, qlcnic_ms_read_data[i]);
*buffer++ = cpu_to_le32(data);
}
addr += 16;
@@ -501,48 +523,388 @@ static u32 qlcnic_dump_nop(struct qlcnic_adapter *adapter,
return 0;
}
-static const 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)
+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,
- "Invalid 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");
+ dev_err(dev,
+ "Invalid entry, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
+ entry->hdr.type, entry->hdr.mask, size,
+ entry->hdr.cap_size);
ret = 0;
}
return ret;
}
+static u32 qlcnic_read_pollrdmwr(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry,
+ __le32 *buffer)
+{
+ struct __pollrdmwr *poll = &entry->region.pollrdmwr;
+ u32 data, wait_count, poll_wait, temp;
+
+ poll_wait = poll->poll_wait;
+
+ qlcnic_ind_wr(adapter, poll->addr1, poll->val1);
+ wait_count = 0;
+
+ while (wait_count < poll_wait) {
+ data = qlcnic_ind_rd(adapter, poll->addr1);
+ if ((data & poll->poll_mask) != 0)
+ break;
+ wait_count++;
+ }
+
+ if (wait_count == poll_wait) {
+ dev_err(&adapter->pdev->dev,
+ "Timeout exceeded in %s, aborting dump\n",
+ __func__);
+ return 0;
+ }
+
+ data = qlcnic_ind_rd(adapter, poll->addr2) & poll->mod_mask;
+ qlcnic_ind_wr(adapter, poll->addr2, data);
+ qlcnic_ind_wr(adapter, poll->addr1, poll->val2);
+ wait_count = 0;
+
+ while (wait_count < poll_wait) {
+ temp = qlcnic_ind_rd(adapter, poll->addr1);
+ if ((temp & poll->poll_mask) != 0)
+ break;
+ wait_count++;
+ }
+
+ *buffer++ = cpu_to_le32(poll->addr2);
+ *buffer++ = cpu_to_le32(data);
+
+ return 2 * sizeof(u32);
+
+}
+
+static u32 qlcnic_read_pollrd(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ struct __pollrd *pollrd = &entry->region.pollrd;
+ u32 data, wait_count, poll_wait, sel_val;
+ int i;
+
+ poll_wait = pollrd->poll_wait;
+ sel_val = pollrd->sel_val;
+
+ for (i = 0; i < pollrd->no_ops; i++) {
+ qlcnic_ind_wr(adapter, pollrd->sel_addr, sel_val);
+ wait_count = 0;
+ while (wait_count < poll_wait) {
+ data = qlcnic_ind_rd(adapter, pollrd->sel_addr);
+ if ((data & pollrd->poll_mask) != 0)
+ break;
+ wait_count++;
+ }
+
+ if (wait_count == poll_wait) {
+ dev_err(&adapter->pdev->dev,
+ "Timeout exceeded in %s, aborting dump\n",
+ __func__);
+ return 0;
+ }
+
+ data = qlcnic_ind_rd(adapter, pollrd->read_addr);
+ *buffer++ = cpu_to_le32(sel_val);
+ *buffer++ = cpu_to_le32(data);
+ sel_val += pollrd->sel_val_stride;
+ }
+ return pollrd->no_ops * (2 * sizeof(u32));
+}
+
+static u32 qlcnic_read_mux2(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ struct __mux2 *mux2 = &entry->region.mux2;
+ u32 data;
+ u32 t_sel_val, sel_val1, sel_val2;
+ int i;
+
+ sel_val1 = mux2->sel_val1;
+ sel_val2 = mux2->sel_val2;
+
+ for (i = 0; i < mux2->no_ops; i++) {
+ qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val1);
+ t_sel_val = sel_val1 & mux2->sel_val_mask;
+ qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
+ data = qlcnic_ind_rd(adapter, mux2->read_addr);
+ *buffer++ = cpu_to_le32(t_sel_val);
+ *buffer++ = cpu_to_le32(data);
+ qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val2);
+ t_sel_val = sel_val2 & mux2->sel_val_mask;
+ qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
+ data = qlcnic_ind_rd(adapter, mux2->read_addr);
+ *buffer++ = cpu_to_le32(t_sel_val);
+ *buffer++ = cpu_to_le32(data);
+ sel_val1 += mux2->sel_val_stride;
+ sel_val2 += mux2->sel_val_stride;
+ }
+
+ return mux2->no_ops * (4 * sizeof(u32));
+}
+
+static u32 qlcnic_83xx_dump_rom(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ u32 fl_addr, size;
+ struct __mem *rom = &entry->region.mem;
+
+ fl_addr = rom->addr;
+ size = rom->size / 4;
+
+ if (!qlcnic_83xx_lockless_flash_read32(adapter, fl_addr,
+ (u8 *)buffer, size))
+ return rom->size;
+
+ return 0;
+}
+
+static const struct qlcnic_dump_operations qlcnic_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},
+};
+
+static const struct qlcnic_dump_operations qlcnic_83xx_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_83xx_dump_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_POLL_RD, qlcnic_read_pollrd},
+ {QLCNIC_READ_MUX2, qlcnic_read_mux2},
+ {QLCNIC_READ_POLLRDMWR, qlcnic_read_pollrdmwr},
+ {QLCNIC_DUMP_READ_ROM, qlcnic_83xx_dump_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},
+};
+
+static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u32 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;
+}
+
+static int qlcnic_fw_flash_get_minidump_temp(struct qlcnic_adapter *adapter,
+ u8 *buffer, u32 size)
+{
+ int ret = 0;
+
+ if (qlcnic_82xx_check(adapter))
+ return -EIO;
+
+ if (qlcnic_83xx_lock_flash(adapter))
+ return -EIO;
+
+ ret = qlcnic_83xx_lockless_flash_read32(adapter,
+ QLC_83XX_MINIDUMP_FLASH,
+ buffer, size / sizeof(u32));
+
+ qlcnic_83xx_unlock_flash(adapter);
+
+ return ret;
+}
+
+static int
+qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_dump_template_hdr tmp_hdr;
+ u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32);
+ int ret = 0;
+
+ if (qlcnic_82xx_check(adapter))
+ return -EIO;
+
+ if (qlcnic_83xx_lock_flash(adapter))
+ return -EIO;
+
+ ret = qlcnic_83xx_lockless_flash_read32(adapter,
+ QLC_83XX_MINIDUMP_FLASH,
+ (u8 *)&tmp_hdr, size);
+
+ qlcnic_83xx_unlock_flash(adapter);
+
+ cmd->rsp.arg[2] = tmp_hdr.size;
+ cmd->rsp.arg[3] = tmp_hdr.version;
+
+ return ret;
+}
+
+static int qlcnic_fw_get_minidump_temp_size(struct qlcnic_adapter *adapter,
+ u32 *version, u32 *temp_size,
+ u8 *use_flash_temp)
+{
+ int err = 0;
+ struct qlcnic_cmd_args cmd;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TEMP_SIZE))
+ return -ENOMEM;
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ if (qlcnic_fw_flash_get_minidump_temp_size(adapter, &cmd)) {
+ qlcnic_free_mbx_args(&cmd);
+ return -EIO;
+ }
+ *use_flash_temp = 1;
+ }
+
+ *temp_size = cmd.rsp.arg[2];
+ *version = cmd.rsp.arg[3];
+ qlcnic_free_mbx_args(&cmd);
+
+ if (!(*temp_size))
+ return -EIO;
+
+ return 0;
+}
+
+static int __qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter,
+ u32 *buffer, u32 temp_size)
+{
+ int err = 0, i;
+ void *tmp_addr;
+ __le32 *tmp_buf;
+ struct qlcnic_cmd_args cmd;
+ dma_addr_t tmp_addr_t = 0;
+
+ 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;
+ }
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_TEMP_HDR)) {
+ err = -ENOMEM;
+ goto free_mem;
+ }
+
+ cmd.req.arg[1] = LSD(tmp_addr_t);
+ cmd.req.arg[2] = MSD(tmp_addr_t);
+ cmd.req.arg[3] = temp_size;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+
+ tmp_buf = tmp_addr;
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ for (i = 0; i < temp_size / sizeof(u32); i++)
+ *buffer++ = __le32_to_cpu(*tmp_buf++);
+ }
+
+ qlcnic_free_mbx_args(&cmd);
+
+free_mem:
+ dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
+
+ return err;
+}
+
+int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
+{
+ int err;
+ u32 temp_size = 0;
+ u32 version, csum, *tmp_buf;
+ struct qlcnic_hardware_context *ahw;
+ struct qlcnic_dump_template_hdr *tmpl_hdr;
+ u8 use_flash_temp = 0;
+
+ ahw = adapter->ahw;
+
+ err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size,
+ &use_flash_temp);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Can't get template size %d\n", err);
+ return -EIO;
+ }
+
+ ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
+ if (!ahw->fw_dump.tmpl_hdr)
+ return -ENOMEM;
+
+ tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr;
+ if (use_flash_temp)
+ goto flash_temp;
+
+ err = __qlcnic_fw_cmd_get_minidump_temp(adapter, tmp_buf, temp_size);
+
+ if (err) {
+flash_temp:
+ err = qlcnic_fw_flash_get_minidump_temp(adapter, (u8 *)tmp_buf,
+ temp_size);
+
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get minidump template header %d\n",
+ err);
+ vfree(ahw->fw_dump.tmpl_hdr);
+ ahw->fw_dump.tmpl_hdr = NULL;
+ return -EIO;
+ }
+ }
+
+ csum = qlcnic_temp_checksum((uint32_t *)tmp_buf, temp_size);
+
+ if (csum) {
+ dev_err(&adapter->pdev->dev,
+ "Template header checksum validation failed\n");
+ vfree(ahw->fw_dump.tmpl_hdr);
+ ahw->fw_dump.tmpl_hdr = NULL;
+ return -EIO;
+ }
+
+ tmpl_hdr = ahw->fw_dump.tmpl_hdr;
+ tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
+ ahw->fw_dump.enable = 1;
+
+ return 0;
+}
+
int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
{
__le32 *buffer;
+ u32 ocm_window;
char mesg[64];
char *msg[] = {mesg, NULL};
int i, k, ops_cnt, ops_index, dump_size = 0;
@@ -550,12 +912,23 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
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;
+ static const struct qlcnic_dump_operations *fw_dump_ops;
+ struct qlcnic_hardware_context *ahw;
+
+ ahw = adapter->ahw;
+
+ if (!fw_dump->enable) {
+ dev_info(&adapter->pdev->dev, "Dump not enabled\n");
+ return -EIO;
+ }
if (fw_dump->clr) {
dev_info(&adapter->pdev->dev,
"Previous dump not cleared, not capturing dump\n");
return -EIO;
}
+
+ netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n");
/* 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)
@@ -564,20 +937,27 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
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);
+ if (!fw_dump->data)
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;
+ if (qlcnic_82xx_check(adapter)) {
+ ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
+ fw_dump_ops = qlcnic_fw_dump_ops;
+ } else {
+ ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
+ fw_dump_ops = qlcnic_83xx_fw_dump_ops;
+ ocm_window = tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func];
+ tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
+ tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
+ }
+
for (i = 0; i < no_entries; i++) {
entry = (void *)tmpl_hdr + entry_offset;
if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
@@ -585,6 +965,7 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
entry_offset += entry->hdr.offset;
continue;
}
+
/* Find the handler for this entry */
ops_index = 0;
while (ops_index < ops_cnt) {
@@ -592,16 +973,17 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
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))
+ if (!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;
@@ -616,8 +998,8 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
fw_dump->clr = 1;
snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
adapter->netdev->name);
- dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n",
- fw_dump->size);
+ dev_info(&adapter->pdev->dev, "%s: Dump data, %d bytes captured\n",
+ adapter->netdev->name, 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;
@@ -626,3 +1008,21 @@ error:
vfree(fw_dump->data);
return -EINVAL;
}
+
+void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter)
+{
+ u32 prev_version, current_version;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
+ struct pci_dev *pdev = adapter->pdev;
+
+ prev_version = adapter->fw_version;
+ current_version = qlcnic_83xx_get_fw_version(adapter);
+
+ if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) {
+ if (fw_dump->tmpl_hdr)
+ vfree(fw_dump->tmpl_hdr);
+ if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
+ dev_info(&pdev->dev, "Supports FW dump capability\n");
+ }
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
index 341d37c867ff..987fb6f8adc3 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -1,8 +1,16 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include "qlcnic.h"
+#include "qlcnic_hw.h"
#include <linux/swab.h>
#include <linux/dma-mapping.h>
@@ -13,6 +21,10 @@
#include <linux/aer.h>
#include <linux/log2.h>
+#include <linux/sysfs.h>
+
+#define QLC_STATUS_UNSUPPORTED_CMD -2
+
int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
{
return -EOPNOTSUPP;
@@ -40,7 +52,7 @@ static ssize_t qlcnic_store_bridged_mode(struct device *dev,
if (strict_strtoul(buf, 2, &new))
goto err_out;
- if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
+ if (!qlcnic_config_bridged_mode(adapter, !!new))
ret = len;
err_out:
@@ -80,9 +92,7 @@ static ssize_t qlcnic_show_diag_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-
- return sprintf(buf, "%d\n",
- !!(adapter->flags & QLCNIC_DIAG_ENABLED));
+ return sprintf(buf, "%d\n", !!(adapter->flags & QLCNIC_DIAG_ENABLED));
}
static int qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon,
@@ -111,10 +121,11 @@ static ssize_t qlcnic_store_beacon(struct device *dev,
const char *buf, size_t len)
{
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- int max_sds_rings = adapter->max_sds_rings;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int err, max_sds_rings = adapter->max_sds_rings;
u16 beacon;
u8 b_state, b_rate;
- int err;
+ unsigned long h_beacon;
if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
dev_warn(dev,
@@ -122,6 +133,41 @@ static ssize_t qlcnic_store_beacon(struct device *dev,
return -EOPNOTSUPP;
}
+ if (qlcnic_83xx_check(adapter) &&
+ !test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+ if (kstrtoul(buf, 2, &h_beacon))
+ return -EINVAL;
+
+ if (ahw->beacon_state == h_beacon)
+ return len;
+
+ rtnl_lock();
+ if (!ahw->beacon_state) {
+ if (test_and_set_bit(__QLCNIC_LED_ENABLE,
+ &adapter->state)) {
+ rtnl_unlock();
+ return -EBUSY;
+ }
+ }
+ if (h_beacon) {
+ err = qlcnic_83xx_config_led(adapter, 1, h_beacon);
+ if (err)
+ goto beacon_err;
+ } else {
+ err = qlcnic_83xx_config_led(adapter, 0, !h_beacon);
+ if (err)
+ goto beacon_err;
+ }
+ /* set the current beacon state */
+ ahw->beacon_state = h_beacon;
+beacon_err:
+ if (!ahw->beacon_state)
+ clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+
+ rtnl_unlock();
+ return len;
+ }
+
if (len != sizeof(u16))
return QL_STATUS_INVALID_PARAM;
@@ -154,11 +200,10 @@ static ssize_t qlcnic_store_beacon(struct device *dev,
}
err = qlcnic_config_led(adapter, b_state, b_rate);
-
- if (!err) {
+ if (!err)
err = len;
- adapter->ahw->beacon_state = b_state;
- }
+ else
+ ahw->beacon_state = b_state;
if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
@@ -207,21 +252,13 @@ static ssize_t qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u32 data;
- u64 qmdata;
int ret;
ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
if (ret != 0)
return ret;
+ qlcnic_read_crb(adapter, buf, offset, size);
- if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
- qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
- memcpy(buf, &qmdata, size);
- } else {
- data = QLCRD32(adapter, offset);
- memcpy(buf, &data, size);
- }
return size;
}
@@ -231,21 +268,13 @@ static ssize_t qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u32 data;
- u64 qmdata;
int ret;
ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
if (ret != 0)
return ret;
- if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
- memcpy(&qmdata, buf, size);
- qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
- } else {
- memcpy(&data, buf, size);
- QLCWR32(adapter, offset, data);
- }
+ qlcnic_write_crb(adapter, buf, offset, size);
return size;
}
@@ -303,33 +332,44 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
return size;
}
+static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
+{
+ int i;
+ for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+ if (adapter->npars[i].pci_func == pci_func)
+ return i;
+ }
+
+ return -1;
+}
+
static int validate_pm_config(struct qlcnic_adapter *adapter,
struct qlcnic_pm_func_cfg *pm_cfg, int count)
{
- u8 src_pci_func, s_esw_id, d_esw_id, dest_pci_func;
- int i;
+ u8 src_pci_func, s_esw_id, d_esw_id;
+ u8 dest_pci_func;
+ int i, src_index, dest_index;
for (i = 0; i < count; i++) {
src_pci_func = pm_cfg[i].pci_func;
dest_pci_func = pm_cfg[i].dest_npar;
- if (src_pci_func >= QLCNIC_MAX_PCI_FUNC ||
- dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
- return QL_STATUS_INVALID_PARAM;
+ src_index = qlcnic_is_valid_nic_func(adapter, src_pci_func);
- if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
+ if (src_index < 0)
return QL_STATUS_INVALID_PARAM;
- if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
+ dest_index = qlcnic_is_valid_nic_func(adapter, dest_pci_func);
+ if (dest_index < 0)
return QL_STATUS_INVALID_PARAM;
- s_esw_id = adapter->npars[src_pci_func].phy_port;
- d_esw_id = adapter->npars[dest_pci_func].phy_port;
+ s_esw_id = adapter->npars[src_index].phy_port;
+ d_esw_id = adapter->npars[dest_index].phy_port;
if (s_esw_id != d_esw_id)
return QL_STATUS_INVALID_PARAM;
}
- return 0;
+ return 0;
}
static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
@@ -342,7 +382,7 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
struct qlcnic_pm_func_cfg *pm_cfg;
u32 id, action, pci_func;
- int count, rem, i, ret;
+ int count, rem, i, ret, index;
count = size / sizeof(struct qlcnic_pm_func_cfg);
rem = size % sizeof(struct qlcnic_pm_func_cfg);
@@ -350,26 +390,32 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
return QL_STATUS_INVALID_PARAM;
pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
-
ret = validate_pm_config(adapter, pm_cfg, count);
+
if (ret)
return ret;
for (i = 0; i < count; i++) {
pci_func = pm_cfg[i].pci_func;
action = !!pm_cfg[i].action;
- id = adapter->npars[pci_func].phy_port;
- ret = qlcnic_config_port_mirroring(adapter, id, action,
- pci_func);
+ index = qlcnic_is_valid_nic_func(adapter, pci_func);
+ if (index < 0)
+ return QL_STATUS_INVALID_PARAM;
+
+ id = adapter->npars[index].phy_port;
+ ret = qlcnic_config_port_mirroring(adapter, id,
+ action, pci_func);
if (ret)
return ret;
}
for (i = 0; i < count; i++) {
pci_func = pm_cfg[i].pci_func;
- id = adapter->npars[pci_func].phy_port;
- adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
- adapter->npars[pci_func].dest_npar = id;
+ index = qlcnic_is_valid_nic_func(adapter, pci_func);
+ id = adapter->npars[index].phy_port;
+ adapter->npars[index].enable_pm = !!pm_cfg[i].action;
+ adapter->npars[index].dest_npar = id;
}
+
return size;
}
@@ -383,16 +429,19 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
int i;
+ u8 pci_func;
if (size != sizeof(pm_cfg))
return QL_STATUS_INVALID_PARAM;
- for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
- if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
- continue;
- pm_cfg[i].action = adapter->npars[i].enable_pm;
- pm_cfg[i].dest_npar = 0;
- pm_cfg[i].pci_func = i;
+ memset(&pm_cfg, 0,
+ sizeof(struct qlcnic_pm_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+ for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+ pci_func = adapter->npars[i].pci_func;
+ pm_cfg[pci_func].action = adapter->npars[i].enable_pm;
+ pm_cfg[pci_func].dest_npar = 0;
+ pm_cfg[pci_func].pci_func = i;
}
memcpy(buf, &pm_cfg, size);
@@ -404,24 +453,33 @@ static int validate_esw_config(struct qlcnic_adapter *adapter,
{
u32 op_mode;
u8 pci_func;
- int i;
+ int i, ret;
- op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
+ if (qlcnic_82xx_check(adapter))
+ op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
+ else
+ op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
for (i = 0; i < count; i++) {
pci_func = esw_cfg[i].pci_func;
if (pci_func >= QLCNIC_MAX_PCI_FUNC)
return QL_STATUS_INVALID_PARAM;
- if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) {
- if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+ if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
+ if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
return QL_STATUS_INVALID_PARAM;
- }
switch (esw_cfg[i].op_mode) {
case QLCNIC_PORT_DEFAULTS:
- if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
- QLCNIC_NON_PRIV_FUNC) {
+ if (qlcnic_82xx_check(adapter)) {
+ ret = QLC_DEV_GET_DRV(op_mode, pci_func);
+ } else {
+ ret = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
+ pci_func);
+ esw_cfg[i].offload_flags = 0;
+ }
+
+ if (ret != QLCNIC_NON_PRIV_FUNC) {
if (esw_cfg[i].mac_anti_spoof != 0)
return QL_STATUS_INVALID_PARAM;
if (esw_cfg[i].mac_override != 1)
@@ -444,6 +502,7 @@ static int validate_esw_config(struct qlcnic_adapter *adapter,
return QL_STATUS_INVALID_PARAM;
}
}
+
return 0;
}
@@ -458,7 +517,8 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
struct qlcnic_esw_func_cfg *esw_cfg;
struct qlcnic_npar_info *npar;
int count, rem, i, ret;
- u8 pci_func, op_mode = 0;
+ int index;
+ u8 op_mode = 0, pci_func;
count = size / sizeof(struct qlcnic_esw_func_cfg);
rem = size % sizeof(struct qlcnic_esw_func_cfg);
@@ -471,10 +531,9 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
return ret;
for (i = 0; i < count; i++) {
- if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) {
+ if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
return QL_STATUS_INVALID_PARAM;
- }
if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
continue;
@@ -503,7 +562,8 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
for (i = 0; i < count; i++) {
pci_func = esw_cfg[i].pci_func;
- npar = &adapter->npars[pci_func];
+ index = qlcnic_is_valid_nic_func(adapter, pci_func);
+ npar = &adapter->npars[index];
switch (esw_cfg[i].op_mode) {
case QLCNIC_PORT_DEFAULTS:
npar->promisc_mode = esw_cfg[i].promisc_mode;
@@ -533,18 +593,21 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
- u8 i;
+ u8 i, pci_func;
if (size != sizeof(esw_cfg))
return QL_STATUS_INVALID_PARAM;
- for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
- if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
- continue;
- esw_cfg[i].pci_func = i;
- if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
+ memset(&esw_cfg, 0,
+ sizeof(struct qlcnic_esw_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+ for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+ pci_func = adapter->npars[i].pci_func;
+ esw_cfg[pci_func].pci_func = pci_func;
+ if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func]))
return QL_STATUS_INVALID_PARAM;
}
+
memcpy(buf, &esw_cfg, size);
return size;
@@ -558,10 +621,7 @@ static int validate_npar_config(struct qlcnic_adapter *adapter,
for (i = 0; i < count; i++) {
pci_func = np_cfg[i].pci_func;
- if (pci_func >= QLCNIC_MAX_PCI_FUNC)
- return QL_STATUS_INVALID_PARAM;
-
- if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+ if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
return QL_STATUS_INVALID_PARAM;
if (!IS_VALID_BW(np_cfg[i].min_bw) ||
@@ -581,7 +641,7 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
struct qlcnic_info nic_info;
struct qlcnic_npar_func_cfg *np_cfg;
- int i, count, rem, ret;
+ int i, count, rem, ret, index;
u8 pci_func;
count = size / sizeof(struct qlcnic_npar_func_cfg);
@@ -594,8 +654,10 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
if (ret)
return ret;
- for (i = 0; i < count ; i++) {
+ for (i = 0; i < count; i++) {
pci_func = np_cfg[i].pci_func;
+
+ memset(&nic_info, 0, sizeof(struct qlcnic_info));
ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
if (ret)
return ret;
@@ -605,12 +667,12 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
ret = qlcnic_set_nic_info(adapter, &nic_info);
if (ret)
return ret;
- adapter->npars[i].min_bw = nic_info.min_tx_bw;
- adapter->npars[i].max_bw = nic_info.max_tx_bw;
+ index = qlcnic_is_valid_nic_func(adapter, pci_func);
+ adapter->npars[index].min_bw = nic_info.min_tx_bw;
+ adapter->npars[index].max_bw = nic_info.max_tx_bw;
}
return size;
-
}
static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
@@ -628,8 +690,12 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
if (size != sizeof(np_cfg))
return QL_STATUS_INVALID_PARAM;
+ memset(&nic_info, 0, sizeof(struct qlcnic_info));
+ memset(&np_cfg, 0,
+ sizeof(struct qlcnic_npar_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
- if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+ if (qlcnic_is_valid_nic_func(adapter, i) < 0)
continue;
ret = qlcnic_get_nic_info(adapter, &nic_info, i);
if (ret)
@@ -644,6 +710,7 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
}
+
memcpy(buf, &np_cfg, size);
return size;
}
@@ -659,6 +726,9 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
struct qlcnic_esw_statistics port_stats;
int ret;
+ if (qlcnic_83xx_check(adapter))
+ return QLC_STATUS_UNSUPPORTED_CMD;
+
if (size != sizeof(struct qlcnic_esw_statistics))
return QL_STATUS_INVALID_PARAM;
@@ -691,6 +761,9 @@ static ssize_t qlcnic_sysfs_get_esw_stats(struct file *file,
struct qlcnic_esw_statistics esw_stats;
int ret;
+ if (qlcnic_83xx_check(adapter))
+ return QLC_STATUS_UNSUPPORTED_CMD;
+
if (size != sizeof(struct qlcnic_esw_statistics))
return QL_STATUS_INVALID_PARAM;
@@ -722,6 +795,9 @@ static ssize_t qlcnic_sysfs_clear_esw_stats(struct file *file,
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
int ret;
+ if (qlcnic_83xx_check(adapter))
+ return QLC_STATUS_UNSUPPORTED_CMD;
+
if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
return QL_STATUS_INVALID_PARAM;
@@ -744,10 +820,14 @@ static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file,
char *buf, loff_t offset,
size_t size)
{
+
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
int ret;
+ if (qlcnic_83xx_check(adapter))
+ return QLC_STATUS_UNSUPPORTED_CMD;
+
if (offset >= QLCNIC_MAX_PCI_FUNC)
return QL_STATUS_INVALID_PARAM;
@@ -789,7 +869,10 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
return ret;
}
- for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+ memset(&pci_cfg, 0,
+ sizeof(struct qlcnic_pci_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
pci_cfg[i].pci_func = pci_info[i].id;
pci_cfg[i].func_type = pci_info[i].type;
pci_cfg[i].port_num = pci_info[i].default_port;
@@ -797,6 +880,7 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
}
+
memcpy(buf, &pci_cfg, size);
kfree(pci_info);
return size;
@@ -897,7 +981,6 @@ void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
- u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
if (device_create_bin_file(dev, &bin_attr_port_stats))
dev_info(dev, "failed to create port stats sysfs entry");
@@ -911,9 +994,6 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
if (device_create_bin_file(dev, &bin_attr_mem))
dev_info(dev, "failed to create mem sysfs entry\n");
- if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
- return;
-
if (device_create_bin_file(dev, &bin_attr_pci_config))
dev_info(dev, "failed to create pci config sysfs entry");
if (device_create_file(dev, &dev_attr_beacon))
@@ -936,7 +1016,6 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
- u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
device_remove_bin_file(dev, &bin_attr_port_stats);
@@ -945,8 +1024,6 @@ void 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);
- if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
- return;
device_remove_bin_file(dev, &bin_attr_pci_config);
device_remove_file(dev, &dev_attr_beacon);
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
@@ -958,3 +1035,23 @@ void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
device_remove_bin_file(dev, &bin_attr_pm_config);
device_remove_bin_file(dev, &bin_attr_esw_stats);
}
+
+void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter)
+{
+ qlcnic_create_diag_entries(adapter);
+}
+
+void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter)
+{
+ qlcnic_remove_diag_entries(adapter);
+}
+
+void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter)
+{
+ qlcnic_create_diag_entries(adapter);
+}
+
+void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter)
+{
+ qlcnic_remove_diag_entries(adapter);
+}
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index 3e73742024b0..b13ab544a7eb 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -2920,14 +2920,11 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev,
/*
* Allocate small buffer queue control blocks.
*/
- rx_ring->sbq =
- kmalloc(rx_ring->sbq_len * sizeof(struct bq_desc),
- GFP_KERNEL);
- if (rx_ring->sbq == NULL) {
- netif_err(qdev, ifup, qdev->ndev,
- "Small buffer queue control block allocation failed.\n");
+ rx_ring->sbq = kmalloc_array(rx_ring->sbq_len,
+ sizeof(struct bq_desc),
+ GFP_KERNEL);
+ if (rx_ring->sbq == NULL)
goto err_mem;
- }
ql_init_sbq_ring(qdev, rx_ring);
}
@@ -2948,14 +2945,11 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev,
/*
* Allocate large buffer queue control blocks.
*/
- rx_ring->lbq =
- kmalloc(rx_ring->lbq_len * sizeof(struct bq_desc),
- GFP_KERNEL);
- if (rx_ring->lbq == NULL) {
- netif_err(qdev, ifup, qdev->ndev,
- "Large buffer queue control block allocation failed.\n");
+ rx_ring->lbq = kmalloc_array(rx_ring->lbq_len,
+ sizeof(struct bq_desc),
+ GFP_KERNEL);
+ if (rx_ring->lbq == NULL)
goto err_mem;
- }
ql_init_lbq_ring(qdev, rx_ring);
}
@@ -4572,7 +4566,6 @@ static int ql_init_device(struct pci_dev *pdev, struct net_device *ndev,
qdev->mpi_coredump =
vmalloc(sizeof(struct ql_mpi_coredump));
if (qdev->mpi_coredump == NULL) {
- dev_err(&pdev->dev, "Coredump alloc failed.\n");
err = -ENOMEM;
goto err_out2;
}
@@ -4586,7 +4579,6 @@ static int ql_init_device(struct pci_dev *pdev, struct net_device *ndev,
goto err_out2;
}
- memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
/* Keep local copy of current mac address. */
memcpy(qdev->current_mac_addr, ndev->dev_addr, ndev->addr_len);
diff --git a/drivers/net/ethernet/racal/Kconfig b/drivers/net/ethernet/racal/Kconfig
deleted file mode 100644
index 01969e0a9c68..000000000000
--- a/drivers/net/ethernet/racal/Kconfig
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Racal-Interlan device configuration
-#
-
-config NET_VENDOR_RACAL
- bool "Racal-Interlan (Micom) NI devices"
- default y
- depends on ISA
- ---help---
- If you have a network (Ethernet) card belonging to this class, such
- as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about NI cards. If you say Y, you will be asked for
- your specific card in the following questions.
-
-if NET_VENDOR_RACAL
-
-config NI5010
- tristate "NI5010 support (EXPERIMENTAL)"
- depends on ISA && EXPERIMENTAL && BROKEN_ON_SMP
- ---help---
- If you have a network (Ethernet) card of this type, say Y and read
- the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. Note that this is still
- experimental code.
-
- To compile this driver as a module, choose M here. The module
- will be called ni5010.
-
-endif # NET_VENDOR_RACAL
diff --git a/drivers/net/ethernet/racal/Makefile b/drivers/net/ethernet/racal/Makefile
deleted file mode 100644
index 1e210ca1d78b..000000000000
--- a/drivers/net/ethernet/racal/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the Racal-Interlan network device drivers.
-#
-
-obj-$(CONFIG_NI5010) += ni5010.o
diff --git a/drivers/net/ethernet/racal/ni5010.c b/drivers/net/ethernet/racal/ni5010.c
deleted file mode 100644
index 807982220050..000000000000
--- a/drivers/net/ethernet/racal/ni5010.c
+++ /dev/null
@@ -1,771 +0,0 @@
-/* ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard.
- *
- * Copyright 1996,1997,2006 Jan-Pascal van Best and Andreas Mohr.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * The authors may be reached as:
- * janpascal@vanbest.org andi@lisas.de
- *
- * Sources:
- * Donald Becker's "skeleton.c"
- * Crynwr ni5010 packet driver
- *
- * Changes:
- * v0.0: First test version
- * v0.1: First working version
- * v0.2:
- * v0.3->v0.90: Now demand setting io and irq when loading as module
- * 970430 v0.91: modified for Linux 2.1.14
- * v0.92: Implemented Andreas' (better) NI5010 probe
- * 970503 v0.93: Fixed auto-irq failure on warm reboot (JB)
- * 970623 v1.00: First kernel version (AM)
- * 970814 v1.01: Added detection of onboard receive buffer size (AM)
- * 060611 v1.02: slight cleanup: email addresses, driver modernization.
- * Bugs:
- * - not SMP-safe (no locking of I/O accesses)
- * - Note that you have to patch ifconfig for the new /proc/net/dev
- * format. It gives incorrect stats otherwise.
- *
- * To do:
- * Fix all bugs :-)
- * Move some stuff to chipset_init()
- * Handle xmt errors other than collisions
- * Complete merge with Andreas' driver
- * Implement ring buffers (Is this useful? You can't squeeze
- * too many packet in a 2k buffer!)
- * Implement DMA (Again, is this useful? Some docs say DMA is
- * slower than programmed I/O)
- *
- * Compile with:
- * gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ \
- * -DMODULE -c ni5010.c
- *
- * Insert with e.g.:
- * insmod ni5010.ko io=0x300 irq=5
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "ni5010.h"
-
-static const char boardname[] = "NI5010";
-static char version[] __initdata =
- "ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n";
-
-/* bufsize_rcv == 0 means autoprobing */
-static unsigned int bufsize_rcv;
-
-#define JUMPERED_INTERRUPTS /* IRQ line jumpered on board */
-#undef JUMPERED_DMA /* No DMA used */
-#undef FULL_IODETECT /* Only detect in portlist */
-
-#ifndef FULL_IODETECT
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int ports[] __initdata =
- { 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 };
-#endif
-
-/* Use 0 for production, 1 for verification, >2 for debug */
-#ifndef NI5010_DEBUG
-#define NI5010_DEBUG 0
-#endif
-
-/* Information that needs to be kept for each board. */
-struct ni5010_local {
- int o_pkt_size;
- spinlock_t lock;
-};
-
-/* Index to functions, as function prototypes. */
-
-static int ni5010_probe1(struct net_device *dev, int ioaddr);
-static int ni5010_open(struct net_device *dev);
-static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ni5010_interrupt(int irq, void *dev_id);
-static void ni5010_rx(struct net_device *dev);
-static void ni5010_timeout(struct net_device *dev);
-static int ni5010_close(struct net_device *dev);
-static void ni5010_set_multicast_list(struct net_device *dev);
-static void reset_receiver(struct net_device *dev);
-
-static int process_xmt_interrupt(struct net_device *dev);
-#define tx_done(dev) 1
-static void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad);
-static void chipset_init(struct net_device *dev, int startp);
-static void dump_packet(void *buf, int len);
-static void ni5010_show_registers(struct net_device *dev);
-
-static int io;
-static int irq;
-
-struct net_device * __init ni5010_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct ni5010_local));
- int *port;
- int err = 0;
-
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
- }
-
- PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name));
-
- if (io > 0x1ff) { /* Check a single specified location. */
- err = ni5010_probe1(dev, io);
- } else if (io != 0) { /* Don't probe at all. */
- err = -ENXIO;
- } else {
-#ifdef FULL_IODETECT
- for (io=0x200; io<0x400 && ni5010_probe1(dev, io) ; io+=0x20)
- ;
- if (io == 0x400)
- err = -ENODEV;
-
-#else
- for (port = ports; *port && ni5010_probe1(dev, *port); port++)
- ;
- if (!*port)
- err = -ENODEV;
-#endif /* FULL_IODETECT */
- }
- if (err)
- goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
-out1:
- release_region(dev->base_addr, NI5010_IO_EXTENT);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static inline int rd_port(int ioaddr)
-{
- inb(IE_RBUF);
- return inb(IE_SAPROM);
-}
-
-static void __init trigger_irq(int ioaddr)
-{
- outb(0x00, EDLC_RESET); /* Clear EDLC hold RESET state */
- outb(0x00, IE_RESET); /* Board reset */
- outb(0x00, EDLC_XMASK); /* Disable all Xmt interrupts */
- outb(0x00, EDLC_RMASK); /* Disable all Rcv interrupt */
- outb(0xff, EDLC_XCLR); /* Clear all pending Xmt interrupts */
- outb(0xff, EDLC_RCLR); /* Clear all pending Rcv interrupts */
- /*
- * Transmit packet mode: Ignore parity, Power xcvr,
- * Enable loopback
- */
- outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
- outb(RMD_BROADCAST, EDLC_RMODE); /* Receive normal&broadcast */
- outb(XM_ALL, EDLC_XMASK); /* Enable all Xmt interrupts */
- udelay(50); /* FIXME: Necessary? */
- outb(MM_EN_XMT|MM_MUX, IE_MMODE); /* Start transmission */
-}
-
-static const struct net_device_ops ni5010_netdev_ops = {
- .ndo_open = ni5010_open,
- .ndo_stop = ni5010_close,
- .ndo_start_xmit = ni5010_send_packet,
- .ndo_set_rx_mode = ni5010_set_multicast_list,
- .ndo_tx_timeout = ni5010_timeout,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_change_mtu = eth_change_mtu,
-};
-
-/*
- * This is the real probe routine. Linux has a history of friendly device
- * probes on the ISA bus. A good device probes avoids doing writes, and
- * verifies that the correct device exists and functions.
- */
-
-static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
-{
- static unsigned version_printed;
- struct ni5010_local *lp;
- int i;
- unsigned int data = 0;
- int boguscount = 40;
- int err = -ENODEV;
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
- if (!request_region(ioaddr, NI5010_IO_EXTENT, boardname))
- return -EBUSY;
-
- /*
- * This is no "official" probe method, I've rather tested which
- * probe works best with my seven NI5010 cards
- * (they have very different serial numbers)
- * Suggestions or failure reports are very, very welcome !
- * But I think it is a relatively good probe method
- * since it doesn't use any "outb"
- * It should be nearly 100% reliable !
- * well-known WARNING: this probe method (like many others)
- * will hang the system if a NE2000 card region is probed !
- *
- * - Andreas
- */
-
- PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n",
- dev->name, ioaddr));
-
- if (inb(ioaddr+0) == 0xff)
- goto out;
-
- while ( (rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) &
- rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr)) != 0xff)
- {
- if (boguscount-- == 0)
- goto out;
- }
-
- PRINTK2((KERN_DEBUG "%s: I/O #1 passed!\n", dev->name));
-
- for (i=0; i<32; i++)
- if ( (data = rd_port(ioaddr)) != 0xff) break;
- if (data==0xff)
- goto out;
-
- PRINTK2((KERN_DEBUG "%s: I/O #2 passed!\n", dev->name));
-
- if ((data != SA_ADDR0) || (rd_port(ioaddr) != SA_ADDR1) ||
- (rd_port(ioaddr) != SA_ADDR2))
- goto out;
-
- for (i=0; i<4; i++)
- rd_port(ioaddr);
-
- if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) ||
- (rd_port(ioaddr) != NI5010_MAGICVAL2) )
- goto out;
-
- PRINTK2((KERN_DEBUG "%s: I/O #3 passed!\n", dev->name));
-
- if (NI5010_DEBUG && version_printed++ == 0)
- printk(KERN_INFO "%s", version);
-
- printk("NI5010 ethercard probe at 0x%x: ", ioaddr);
-
- dev->base_addr = ioaddr;
-
- for (i=0; i<6; i++) {
- outw(i, IE_GP);
- dev->dev_addr[i] = inb(IE_SAPROM);
- }
- printk("%pM ", dev->dev_addr);
-
- PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
-
-#ifdef JUMPERED_INTERRUPTS
- if (dev->irq == 0xff)
- ;
- else if (dev->irq < 2) {
- unsigned long irq_mask;
-
- PRINTK2((KERN_DEBUG "%s: I/O #5 passed!\n", dev->name));
-
- irq_mask = probe_irq_on();
- trigger_irq(ioaddr);
- mdelay(20);
- dev->irq = probe_irq_off(irq_mask);
-
- PRINTK2((KERN_DEBUG "%s: I/O #6 passed!\n", dev->name));
-
- if (dev->irq == 0) {
- err = -EAGAIN;
- printk(KERN_WARNING "%s: no IRQ found!\n", dev->name);
- goto out;
- }
- PRINTK2((KERN_DEBUG "%s: I/O #7 passed!\n", dev->name));
- } else if (dev->irq == 2) {
- dev->irq = 9;
- }
-#endif /* JUMPERED_INTERRUPTS */
- PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
-
- /* DMA is not supported (yet?), so no use detecting it */
- lp = netdev_priv(dev);
-
- spin_lock_init(&lp->lock);
-
- PRINTK2((KERN_DEBUG "%s: I/O #10 passed!\n", dev->name));
-
-/* get the size of the onboard receive buffer
- * higher addresses than bufsize are wrapped into real buffer
- * i.e. data for offs. 0x801 is written to 0x1 with a 2K onboard buffer
- */
- if (!bufsize_rcv) {
- outb(1, IE_MMODE); /* Put Rcv buffer on system bus */
- outw(0, IE_GP); /* Point GP at start of packet */
- outb(0, IE_RBUF); /* set buffer byte 0 to 0 */
- for (i = 1; i < 0xff; i++) {
- outw(i << 8, IE_GP); /* Point GP at packet size to be tested */
- outb(i, IE_RBUF);
- outw(0x0, IE_GP); /* Point GP at start of packet */
- data = inb(IE_RBUF);
- if (data == i) break;
- }
- bufsize_rcv = i << 8;
- outw(0, IE_GP); /* Point GP at start of packet */
- outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */
- }
- printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
-
- dev->netdev_ops = &ni5010_netdev_ops;
- dev->watchdog_timeo = HZ/20;
-
- dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */
-
- /* Shut up the ni5010 */
- outb(0, EDLC_RMASK); /* Mask all receive interrupts */
- outb(0, EDLC_XMASK); /* Mask all xmit interrupts */
- outb(0xff, EDLC_RCLR); /* Kill all pending rcv interrupts */
- outb(0xff, EDLC_XCLR); /* Kill all pending xmt interrupts */
-
- printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq);
- if (dev->dma)
- printk(" & DMA %d", dev->dma);
- printk(".\n");
- return 0;
-out:
- release_region(dev->base_addr, NI5010_IO_EXTENT);
- return err;
-}
-
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is a non-reboot way to recover if something goes wrong.
- */
-
-static int ni5010_open(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- int i;
-
- PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name));
-
- if (request_irq(dev->irq, ni5010_interrupt, 0, boardname, dev)) {
- printk(KERN_WARNING "%s: Cannot get irq %#2x\n", dev->name, dev->irq);
- return -EAGAIN;
- }
- PRINTK3((KERN_DEBUG "%s: passed open() #1\n", dev->name));
- /*
- * Always allocate the DMA channel after the IRQ,
- * and clean up on failure.
- */
-#ifdef JUMPERED_DMA
- if (request_dma(dev->dma, cardname)) {
- printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
- free_irq(dev->irq, NULL);
- return -EAGAIN;
- }
-#endif /* JUMPERED_DMA */
-
- PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
- /* Reset the hardware here. Don't forget to set the station address. */
-
- outb(RS_RESET, EDLC_RESET); /* Hold up EDLC_RESET while configing board */
- outb(0, IE_RESET); /* Hardware reset of ni5010 board */
- outb(XMD_LBC, EDLC_XMODE); /* Only loopback xmits */
-
- PRINTK3((KERN_DEBUG "%s: passed open() #3\n", dev->name));
- /* Set the station address */
- for(i = 0;i < 6; i++) {
- outb(dev->dev_addr[i], EDLC_ADDR + i);
- }
-
- PRINTK3((KERN_DEBUG "%s: Initialising ni5010\n", dev->name));
- outb(0, EDLC_XMASK); /* No xmit interrupts for now */
- outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
- /* Normal packet xmit mode */
- outb(0xff, EDLC_XCLR); /* Clear all pending xmit interrupts */
- outb(RMD_BROADCAST, EDLC_RMODE);
- /* Receive broadcast and normal packets */
- reset_receiver(dev); /* Ready ni5010 for receiving packets */
-
- outb(0, EDLC_RESET); /* Un-reset the ni5010 */
-
- netif_start_queue(dev);
-
- if (NI5010_DEBUG) ni5010_show_registers(dev);
-
- PRINTK((KERN_DEBUG "%s: open successful\n", dev->name));
- return 0;
-}
-
-static void reset_receiver(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- PRINTK3((KERN_DEBUG "%s: resetting receiver\n", dev->name));
- outw(0, IE_GP); /* Receive packet at start of buffer */
- outb(0xff, EDLC_RCLR); /* Clear all pending rcv interrupts */
- outb(0, IE_MMODE); /* Put EDLC to rcv buffer */
- outb(MM_EN_RCV, IE_MMODE); /* Enable rcv */
- outb(0xff, EDLC_RMASK); /* Enable all rcv interrupts */
-}
-
-static void ni5010_timeout(struct net_device *dev)
-{
- printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
- tx_done(dev) ? "IRQ conflict" : "network cable problem");
- /* Try to restart the adaptor. */
- /* FIXME: Give it a real kick here */
- chipset_init(dev, 1);
- dev->trans_start = jiffies; /* prevent tx timeout */
- netif_wake_queue(dev);
-}
-
-static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
- int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-
- PRINTK2((KERN_DEBUG "%s: entering ni5010_send_packet\n", dev->name));
-
- /*
- * Block sending
- */
-
- netif_stop_queue(dev);
- hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
- dev_kfree_skb (skb);
- return NETDEV_TX_OK;
-}
-
-/*
- * The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-static irqreturn_t ni5010_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct ni5010_local *lp;
- int ioaddr, status;
- int xmit_was_error = 0;
-
- PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name));
-
- ioaddr = dev->base_addr;
- lp = netdev_priv(dev);
-
- spin_lock(&lp->lock);
- status = inb(IE_ISTAT);
- PRINTK3((KERN_DEBUG "%s: IE_ISTAT = %#02x\n", dev->name, status));
-
- if ((status & IS_R_INT) == 0) ni5010_rx(dev);
-
- if ((status & IS_X_INT) == 0) {
- xmit_was_error = process_xmt_interrupt(dev);
- }
-
- if ((status & IS_DMA_INT) == 0) {
- PRINTK((KERN_DEBUG "%s: DMA complete (?)\n", dev->name));
- outb(0, IE_DMA_RST); /* Reset DMA int */
- }
-
- if (!xmit_was_error)
- reset_receiver(dev);
- spin_unlock(&lp->lock);
- return IRQ_HANDLED;
-}
-
-
-static void dump_packet(void *buf, int len)
-{
- int i;
-
- printk(KERN_DEBUG "Packet length = %#4x\n", len);
- for (i = 0; i < len; i++){
- if (i % 16 == 0) printk(KERN_DEBUG "%#4.4x", i);
- if (i % 2 == 0) printk(" ");
- printk("%2.2x", ((unsigned char *)buf)[i]);
- if (i % 16 == 15) printk("\n");
- }
- printk("\n");
-}
-
-/* We have a good packet, get it out of the buffer. */
-static void ni5010_rx(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- unsigned char rcv_stat;
- struct sk_buff *skb;
- int i_pkt_size;
-
- PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name));
-
- rcv_stat = inb(EDLC_RSTAT);
- PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat));
-
- if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) {
- PRINTK((KERN_INFO "%s: receive error.\n", dev->name));
- dev->stats.rx_errors++;
- if (rcv_stat & RS_RUNT) dev->stats.rx_length_errors++;
- if (rcv_stat & RS_ALIGN) dev->stats.rx_frame_errors++;
- if (rcv_stat & RS_CRC_ERR) dev->stats.rx_crc_errors++;
- if (rcv_stat & RS_OFLW) dev->stats.rx_fifo_errors++;
- outb(0xff, EDLC_RCLR); /* Clear the interrupt */
- return;
- }
-
- outb(0xff, EDLC_RCLR); /* Clear the interrupt */
-
- i_pkt_size = inw(IE_RCNT);
- if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) {
- PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
- dev->name, i_pkt_size));
- dev->stats.rx_errors++;
- dev->stats.rx_length_errors++;
- return;
- }
-
- /* Malloc up new buffer. */
- skb = netdev_alloc_skb(dev, i_pkt_size + 3);
- if (skb == NULL) {
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- return;
- }
-
- skb_reserve(skb, 2);
-
- /* Read packet into buffer */
- outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */
- outw(0, IE_GP); /* Seek to beginning of packet */
- insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size);
-
- if (NI5010_DEBUG >= 4)
- dump_packet(skb->data, skb->len);
-
- skb->protocol = eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += i_pkt_size;
-
- PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
- dev->name, i_pkt_size));
-}
-
-static int process_xmt_interrupt(struct net_device *dev)
-{
- struct ni5010_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- int xmit_stat;
-
- PRINTK2((KERN_DEBUG "%s: entering process_xmt_interrupt\n", dev->name));
-
- xmit_stat = inb(EDLC_XSTAT);
- PRINTK3((KERN_DEBUG "%s: EDLC_XSTAT = %2.2x\n", dev->name, xmit_stat));
-
- outb(0, EDLC_XMASK); /* Disable xmit IRQ's */
- outb(0xff, EDLC_XCLR); /* Clear all pending xmit IRQ's */
-
- if (xmit_stat & XS_COLL){
- PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n",
- dev->name));
- outw(NI5010_BUFSIZE - lp->o_pkt_size, IE_GP);
- /* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */
- outb(MM_EN_XMT | MM_MUX, IE_MMODE);
- outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */
- dev->stats.collisions++;
- return 1;
- }
-
- /* FIXME: handle other xmt error conditions */
-
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += lp->o_pkt_size;
- netif_wake_queue(dev);
-
- PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
- dev->name, lp->o_pkt_size));
-
- return 0;
-}
-
-/* The inverse routine to ni5010_open(). */
-static int ni5010_close(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
-#ifdef JUMPERED_INTERRUPTS
- free_irq(dev->irq, NULL);
-#endif
- /* Put card in held-RESET state */
- outb(0, IE_MMODE);
- outb(RS_RESET, EDLC_RESET);
-
- netif_stop_queue(dev);
-
- PRINTK((KERN_DEBUG "%s: %s closed down\n", dev->name, boardname));
- return 0;
-
-}
-
-/* Set or clear the multicast filter for this adaptor.
- num_addrs == -1 Promiscuous mode, receive all packets
- num_addrs == 0 Normal mode, clear multicast list
- num_addrs > 0 Multicast mode, receive normal and MC packets, and do
- best-effort filtering.
-*/
-static void ni5010_set_multicast_list(struct net_device *dev)
-{
- short ioaddr = dev->base_addr;
-
- PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
-
- if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI ||
- !netdev_mc_empty(dev)) {
- outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */
- PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name));
- } else {
- PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name));
- outb(RMD_BROADCAST, EDLC_RMODE); /* Disable promiscuous mode, use normal mode */
- }
-}
-
-static void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad)
-{
- struct ni5010_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- unsigned long flags;
- unsigned int buf_offs;
-
- PRINTK2((KERN_DEBUG "%s: entering hardware_send_packet\n", dev->name));
-
- if (length > ETH_FRAME_LEN) {
- PRINTK((KERN_WARNING "%s: packet too large, not possible\n",
- dev->name));
- return;
- }
-
- if (NI5010_DEBUG) ni5010_show_registers(dev);
-
- if (inb(IE_ISTAT) & IS_EN_XMT) {
- PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n",
- dev->name));
- return;
- }
-
- if (NI5010_DEBUG > 3) dump_packet(buf, length);
-
- buf_offs = NI5010_BUFSIZE - length - pad;
-
- spin_lock_irqsave(&lp->lock, flags);
- lp->o_pkt_size = length + pad;
-
- outb(0, EDLC_RMASK); /* Mask all receive interrupts */
- outb(0, IE_MMODE); /* Put Xmit buffer on system bus */
- outb(0xff, EDLC_RCLR); /* Clear out pending rcv interrupts */
-
- outw(buf_offs, IE_GP); /* Point GP at start of packet */
- outsb(IE_XBUF, buf, length); /* Put data in buffer */
- while(pad--)
- outb(0, IE_XBUF);
-
- outw(buf_offs, IE_GP); /* Rewrite where packet starts */
-
- /* should work without that outb() (Crynwr used it) */
- /*outb(MM_MUX, IE_MMODE);*/ /* Xmt buffer to EDLC bus */
- outb(MM_EN_XMT | MM_MUX, IE_MMODE); /* Begin transmission */
- outb(XM_ALL, EDLC_XMASK); /* Cause interrupt after completion or fail */
-
- spin_unlock_irqrestore(&lp->lock, flags);
-
- netif_wake_queue(dev);
-
- if (NI5010_DEBUG) ni5010_show_registers(dev);
-}
-
-static void chipset_init(struct net_device *dev, int startp)
-{
- /* FIXME: Move some stuff here */
- PRINTK3((KERN_DEBUG "%s: doing NOTHING in chipset_init\n", dev->name));
-}
-
-static void ni5010_show_registers(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
-
- PRINTK3((KERN_DEBUG "%s: XSTAT %#2.2x\n", dev->name, inb(EDLC_XSTAT)));
- PRINTK3((KERN_DEBUG "%s: XMASK %#2.2x\n", dev->name, inb(EDLC_XMASK)));
- PRINTK3((KERN_DEBUG "%s: RSTAT %#2.2x\n", dev->name, inb(EDLC_RSTAT)));
- PRINTK3((KERN_DEBUG "%s: RMASK %#2.2x\n", dev->name, inb(EDLC_RMASK)));
- PRINTK3((KERN_DEBUG "%s: RMODE %#2.2x\n", dev->name, inb(EDLC_RMODE)));
- PRINTK3((KERN_DEBUG "%s: XMODE %#2.2x\n", dev->name, inb(EDLC_XMODE)));
- PRINTK3((KERN_DEBUG "%s: ISTAT %#2.2x\n", dev->name, inb(IE_ISTAT)));
-}
-
-#ifdef MODULE
-static struct net_device *dev_ni5010;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "ni5010 I/O base address");
-MODULE_PARM_DESC(irq, "ni5010 IRQ number");
-
-static int __init ni5010_init_module(void)
-{
- PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname));
- /*
- if(io <= 0 || irq == 0){
- printk(KERN_WARNING "%s: Autoprobing not allowed for modules.\n", boardname);
- printk(KERN_WARNING "%s: Set symbols 'io' and 'irq'\n", boardname);
- return -EINVAL;
- }
- */
- if (io <= 0){
- printk(KERN_WARNING "%s: Autoprobing for modules is hazardous, trying anyway..\n", boardname);
- }
-
- PRINTK2((KERN_DEBUG "%s: init_module irq=%#2x, io=%#3x\n", boardname, irq, io));
- dev_ni5010 = ni5010_probe(-1);
- if (IS_ERR(dev_ni5010))
- return PTR_ERR(dev_ni5010);
- return 0;
-}
-
-static void __exit ni5010_cleanup_module(void)
-{
- PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
- unregister_netdev(dev_ni5010);
- release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
- free_netdev(dev_ni5010);
-}
-module_init(ni5010_init_module);
-module_exit(ni5010_cleanup_module);
-#endif /* MODULE */
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/racal/ni5010.h b/drivers/net/ethernet/racal/ni5010.h
deleted file mode 100644
index e10e717fcd76..000000000000
--- a/drivers/net/ethernet/racal/ni5010.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Racal-Interlan ni5010 Ethernet definitions
- *
- * This is an extension to the Linux operating system, and is covered by the
- * same GNU General Public License that covers that work.
- *
- * copyrights (c) 1996 by Jan-Pascal van Best (jvbest@wi.leidenuniv.nl)
- *
- * I have done a look in the following sources:
- * crynwr-packet-driver by Russ Nelson
- */
-
-#define NI5010_BUFSIZE 2048 /* number of bytes in a buffer */
-
-#define NI5010_MAGICVAL0 0x00 /* magic-values for ni5010 card */
-#define NI5010_MAGICVAL1 0x55
-#define NI5010_MAGICVAL2 0xAA
-
-#define SA_ADDR0 0x02
-#define SA_ADDR1 0x07
-#define SA_ADDR2 0x01
-
-/* The number of low I/O ports used by the ni5010 ethercard. */
-#define NI5010_IO_EXTENT 32
-
-#define PRINTK(x) if (NI5010_DEBUG) printk x
-#define PRINTK2(x) if (NI5010_DEBUG>=2) printk x
-#define PRINTK3(x) if (NI5010_DEBUG>=3) printk x
-
-/* The various IE command registers */
-#define EDLC_XSTAT (ioaddr + 0x00) /* EDLC transmit csr */
-#define EDLC_XCLR (ioaddr + 0x00) /* EDLC transmit "Clear IRQ" */
-#define EDLC_XMASK (ioaddr + 0x01) /* EDLC transmit "IRQ Masks" */
-#define EDLC_RSTAT (ioaddr + 0x02) /* EDLC receive csr */
-#define EDLC_RCLR (ioaddr + 0x02) /* EDLC receive "Clear IRQ" */
-#define EDLC_RMASK (ioaddr + 0x03) /* EDLC receive "IRQ Masks" */
-#define EDLC_XMODE (ioaddr + 0x04) /* EDLC transmit Mode */
-#define EDLC_RMODE (ioaddr + 0x05) /* EDLC receive Mode */
-#define EDLC_RESET (ioaddr + 0x06) /* EDLC RESET register */
-#define EDLC_TDR1 (ioaddr + 0x07) /* "Time Domain Reflectometry" reg1 */
-#define EDLC_ADDR (ioaddr + 0x08) /* EDLC station address, 6 bytes */
- /* 0x0E doesn't exist for r/w */
-#define EDLC_TDR2 (ioaddr + 0x0f) /* "Time Domain Reflectometry" reg2 */
-#define IE_GP (ioaddr + 0x10) /* GP pointer (word register) */
- /* 0x11 is 2nd byte of GP Pointer */
-#define IE_RCNT (ioaddr + 0x10) /* Count of bytes in rcv'd packet */
- /* 0x11 is 2nd byte of "Byte Count" */
-#define IE_MMODE (ioaddr + 0x12) /* Memory Mode register */
-#define IE_DMA_RST (ioaddr + 0x13) /* IE DMA Reset. write only */
-#define IE_ISTAT (ioaddr + 0x13) /* IE Interrupt Status. read only */
-#define IE_RBUF (ioaddr + 0x14) /* IE Receive Buffer port */
-#define IE_XBUF (ioaddr + 0x15) /* IE Transmit Buffer port */
-#define IE_SAPROM (ioaddr + 0x16) /* window on station addr prom */
-#define IE_RESET (ioaddr + 0x17) /* any write causes Board Reset */
-
-/* bits in EDLC_XSTAT, interrupt clear on write, status when read */
-#define XS_TPOK 0x80 /* transmit packet successful */
-#define XS_CS 0x40 /* carrier sense */
-#define XS_RCVD 0x20 /* transmitted packet received */
-#define XS_SHORT 0x10 /* transmission media is shorted */
-#define XS_UFLW 0x08 /* underflow. iff failed board */
-#define XS_COLL 0x04 /* collision occurred */
-#define XS_16COLL 0x02 /* 16th collision occurred */
-#define XS_PERR 0x01 /* parity error */
-
-#define XS_CLR_UFLW 0x08 /* clear underflow */
-#define XS_CLR_COLL 0x04 /* clear collision */
-#define XS_CLR_16COLL 0x02 /* clear 16th collision */
-#define XS_CLR_PERR 0x01 /* clear parity error */
-
-/* bits in EDLC_XMASK, mask/enable transmit interrupts. register is r/w */
-#define XM_TPOK 0x80 /* =1 to enable Xmt Pkt OK interrupts */
-#define XM_RCVD 0x20 /* =1 to enable Xmt Pkt Rcvd ints */
-#define XM_UFLW 0x08 /* =1 to enable Xmt Underflow ints */
-#define XM_COLL 0x04 /* =1 to enable Xmt Collision ints */
-#define XM_COLL16 0x02 /* =1 to enable Xmt 16th Coll ints */
-#define XM_PERR 0x01 /* =1 to enable Xmt Parity Error ints */
- /* note: always clear this bit */
-#define XM_ALL (XM_TPOK | XM_RCVD | XM_UFLW | XM_COLL | XM_COLL16)
-
-/* bits in EDLC_RSTAT, interrupt clear on write, status when read */
-#define RS_PKT_OK 0x80 /* received good packet */
-#define RS_RST_PKT 0x10 /* RESET packet received */
-#define RS_RUNT 0x08 /* Runt Pkt rcvd. Len < 64 Bytes */
-#define RS_ALIGN 0x04 /* Alignment error. not 8 bit aligned */
-#define RS_CRC_ERR 0x02 /* Bad CRC on rcvd pkt */
-#define RS_OFLW 0x01 /* overflow for rcv FIFO */
-#define RS_VALID_BITS ( RS_PKT_OK | RS_RST_PKT | RS_RUNT | RS_ALIGN | RS_CRC_ERR | RS_OFLW )
- /* all valid RSTAT bits */
-
-#define RS_CLR_PKT_OK 0x80 /* clear rcvd packet interrupt */
-#define RS_CLR_RST_PKT 0x10 /* clear RESET packet received */
-#define RS_CLR_RUNT 0x08 /* clear Runt Pckt received */
-#define RS_CLR_ALIGN 0x04 /* clear Alignment error */
-#define RS_CLR_CRC_ERR 0x02 /* clear CRC error */
-#define RS_CLR_OFLW 0x01 /* clear rcv FIFO Overflow */
-
-/* bits in EDLC_RMASK, mask/enable receive interrupts. register is r/w */
-#define RM_PKT_OK 0x80 /* =1 to enable rcvd good packet ints */
-#define RM_RST_PKT 0x10 /* =1 to enable RESET packet ints */
-#define RM_RUNT 0x08 /* =1 to enable Runt Pkt rcvd ints */
-#define RM_ALIGN 0x04 /* =1 to enable Alignment error ints */
-#define RM_CRC_ERR 0x02 /* =1 to enable Bad CRC error ints */
-#define RM_OFLW 0x01 /* =1 to enable overflow error ints */
-
-/* bits in EDLC_RMODE, set Receive Packet mode. register is r/w */
-#define RMD_TEST 0x80 /* =1 for Chip testing. normally 0 */
-#define RMD_ADD_SIZ 0x10 /* =1 5-byte addr match. normally 0 */
-#define RMD_EN_RUNT 0x08 /* =1 enable runt rcv. normally 0 */
-#define RMD_EN_RST 0x04 /* =1 to rcv RESET pkt. normally 0 */
-
-#define RMD_PROMISC 0x03 /* receive *all* packets. unusual */
-#define RMD_MULTICAST 0x02 /* receive multicasts too. unusual */
-#define RMD_BROADCAST 0x01 /* receive broadcasts & normal. usual */
-#define RMD_NO_PACKETS 0x00 /* don't receive any packets. unusual */
-
-/* bits in EDLC_XMODE, set Transmit Packet mode. register is r/w */
-#define XMD_COLL_CNT 0xf0 /* coll's since success. read-only */
-#define XMD_IG_PAR 0x08 /* =1 to ignore parity. ALWAYS set */
-#define XMD_T_MODE 0x04 /* =1 to power xcvr. ALWAYS set this */
-#define XMD_LBC 0x02 /* =1 for loopbakc. normally set */
-#define XMD_DIS_C 0x01 /* =1 disables contention. normally 0 */
-
-/* bits in EDLC_RESET, write only */
-#define RS_RESET 0x80 /* =1 to hold EDLC in reset state */
-
-/* bits in IE_MMODE, write only */
-#define MM_EN_DMA 0x80 /* =1 begin DMA xfer, Cplt clrs it */
-#define MM_EN_RCV 0x40 /* =1 allows Pkt rcv. clr'd by rcv */
-#define MM_EN_XMT 0x20 /* =1 begin Xmt pkt. Cplt clrs it */
-#define MM_BUS_PAGE 0x18 /* =00 ALWAYS. Used when MUX=1 */
-#define MM_NET_PAGE 0x06 /* =00 ALWAYS. Used when MUX=0 */
-#define MM_MUX 0x01 /* =1 means Rcv Buff on system bus */
- /* =0 means Xmt Buff on system bus */
-
-/* bits in IE_ISTAT, read only */
-#define IS_TDIAG 0x80 /* =1 if Diagnostic problem */
-#define IS_EN_RCV 0x20 /* =1 until frame is rcv'd cplt */
-#define IS_EN_XMT 0x10 /* =1 until frame is xmt'd cplt */
-#define IS_EN_DMA 0x08 /* =1 until DMA is cplt or aborted */
-#define IS_DMA_INT 0x04 /* =0 iff DMA done interrupt. */
-#define IS_R_INT 0x02 /* =0 iff unmasked Rcv interrupt */
-#define IS_X_INT 0x01 /* =0 iff unmasked Xmt interrupt */
-
diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c
index 63c13125db6c..5b4103db70f5 100644
--- a/drivers/net/ethernet/rdc/r6040.c
+++ b/drivers/net/ethernet/rdc/r6040.c
@@ -755,9 +755,6 @@ static void r6040_mac_address(struct net_device *dev)
iowrite16(adrp[0], ioaddr + MID_0L);
iowrite16(adrp[1], ioaddr + MID_0M);
iowrite16(adrp[2], ioaddr + MID_0H);
-
- /* Store MAC Address in perm_addr */
- memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
}
static int r6040_open(struct net_device *dev)
@@ -957,9 +954,9 @@ static void netdev_get_drvinfo(struct net_device *dev,
{
struct r6040_private *rp = netdev_priv(dev);
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, pci_name(rp->pdev));
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info));
}
static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1045,7 +1042,7 @@ static int r6040_mii_probe(struct net_device *dev)
}
phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
- 0, PHY_INTERFACE_MODE_MII);
+ PHY_INTERFACE_MODE_MII);
if (IS_ERR(phydev)) {
dev_err(&lp->pdev->dev, "could not attach to PHY\n");
@@ -1195,9 +1192,8 @@ static int r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
lp->mii_bus->name = "r6040_eth_mii";
snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
dev_name(&pdev->dev), card_idx);
- lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ lp->mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
if (!lp->mii_bus->irq) {
- dev_err(&pdev->dev, "mii_bus irq allocation failed\n");
err = -ENOMEM;
goto err_out_mdio;
}
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 5ac93323a40c..b62a32484f6a 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -1949,7 +1949,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
for (i = 0; i < 3; i++)
((__le16 *) (dev->dev_addr))[i] =
cpu_to_le16(read_eeprom (regs, i + 7, addr_len));
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
dev->netdev_ops = &cp_netdev_ops;
netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c
index 5dc161630127..1276ac71353a 100644
--- a/drivers/net/ethernet/realtek/8139too.c
+++ b/drivers/net/ethernet/realtek/8139too.c
@@ -991,7 +991,6 @@ static int rtl8139_init_one(struct pci_dev *pdev,
for (i = 0; i < 3; i++)
((__le16 *) (dev->dev_addr))[i] =
cpu_to_le16(read_eeprom (ioaddr, i + 7, addr_len));
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
/* The Rtl8139-specific entries in the device structure. */
dev->netdev_ops = &rtl8139_netdev_ops;
diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig
index 5821966f9f28..783fa8b5cde7 100644
--- a/drivers/net/ethernet/realtek/Kconfig
+++ b/drivers/net/ethernet/realtek/Kconfig
@@ -34,8 +34,8 @@ config ATP
will be called atp.
config 8139CP
- tristate "RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support"
+ depends on PCI
select CRC32
select NET_CORE
select MII
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 11702324a071..8900398ba103 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -83,7 +83,7 @@ static const int multicast_filter_limit = 32;
#define R8169_REGS_SIZE 256
#define R8169_NAPI_WEIGHT 64
#define NUM_TX_DESC 64 /* Number of Tx descriptor registers */
-#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */
+#define NUM_RX_DESC 256U /* Number of Rx descriptor registers */
#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
@@ -450,7 +450,6 @@ enum rtl8168_registers {
#define PWM_EN (1 << 22)
#define RXDV_GATED_EN (1 << 19)
#define EARLY_TALLY_EN (1 << 16)
-#define FORCE_CLK (1 << 15) /* force clock request */
};
enum rtl_register_content {
@@ -514,7 +513,6 @@ enum rtl_register_content {
PMEnable = (1 << 0), /* Power Management Enable */
/* Config2 register p. 25 */
- ClkReqEn = (1 << 7), /* Clock Request Enable */
MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */
PCI_Clock_66MHz = 0x01,
PCI_Clock_33MHz = 0x00,
@@ -535,7 +533,6 @@ enum rtl_register_content {
Spi_en = (1 << 3),
LanWake = (1 << 1), /* LanWake enable/disable */
PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
- ASPM_en = (1 << 0), /* ASPM enable */
/* TBICSR p.28 */
TBIReset = 0x80000000,
@@ -684,7 +681,6 @@ enum features {
RTL_FEATURE_WOL = (1 << 0),
RTL_FEATURE_MSI = (1 << 1),
RTL_FEATURE_GMII = (1 << 2),
- RTL_FEATURE_FW_LOADED = (1 << 3),
};
struct rtl8169_counters {
@@ -727,7 +723,6 @@ struct rtl8169_private {
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;
u32 dirty_tx;
struct rtl8169_stats rx_stats;
struct rtl8169_stats tx_stats;
@@ -2389,10 +2384,8 @@ static void rtl_apply_firmware(struct rtl8169_private *tp)
struct rtl_fw *rtl_fw = tp->rtl_fw;
/* TODO: release firmware once rtl_phy_write_fw signals failures. */
- if (!IS_ERR_OR_NULL(rtl_fw)) {
+ if (!IS_ERR_OR_NULL(rtl_fw))
rtl_phy_write_fw(tp, rtl_fw);
- tp->features |= RTL_FEATURE_FW_LOADED;
- }
}
static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
@@ -2403,31 +2396,6 @@ static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
rtl_apply_firmware(tp);
}
-static void r810x_aldps_disable(struct rtl8169_private *tp)
-{
- rtl_writephy(tp, 0x1f, 0x0000);
- rtl_writephy(tp, 0x18, 0x0310);
- msleep(100);
-}
-
-static void r810x_aldps_enable(struct rtl8169_private *tp)
-{
- if (!(tp->features & RTL_FEATURE_FW_LOADED))
- return;
-
- rtl_writephy(tp, 0x1f, 0x0000);
- rtl_writephy(tp, 0x18, 0x8310);
-}
-
-static void r8168_aldps_enable_1(struct rtl8169_private *tp)
-{
- if (!(tp->features & RTL_FEATURE_FW_LOADED))
- return;
-
- rtl_writephy(tp, 0x1f, 0x0000);
- rtl_w1w0_phy(tp, 0x15, 0x1000, 0x0000);
-}
-
static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
@@ -3218,8 +3186,6 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
rtl_writephy(tp, 0x1f, 0x0000);
- r8168_aldps_enable_1(tp);
-
/* Broken BIOS workaround: feed GigaMAC registers with MAC address. */
rtl_rar_exgmac_set(tp, tp->dev->dev_addr);
}
@@ -3294,8 +3260,6 @@ static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x05, 0x8b85);
rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
rtl_writephy(tp, 0x1f, 0x0000);
-
- r8168_aldps_enable_1(tp);
}
static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
@@ -3303,8 +3267,6 @@ static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
rtl_apply_firmware(tp);
rtl8168f_hw_phy_config(tp);
-
- r8168_aldps_enable_1(tp);
}
static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
@@ -3402,8 +3364,6 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
rtl_writephy(tp, 0x1f, 0x0000);
-
- r8168_aldps_enable_1(tp);
}
static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
@@ -3489,19 +3449,21 @@ static void rtl8105e_hw_phy_config(struct rtl8169_private *tp)
};
/* Disable ALDPS before ram code */
- r810x_aldps_disable(tp);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x18, 0x0310);
+ msleep(100);
rtl_apply_firmware(tp);
rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
-
- r810x_aldps_enable(tp);
}
static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
{
/* Disable ALDPS before setting firmware */
- r810x_aldps_disable(tp);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x18, 0x0310);
+ msleep(20);
rtl_apply_firmware(tp);
@@ -3511,8 +3473,6 @@ static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x10, 0x401f);
rtl_writephy(tp, 0x19, 0x7030);
rtl_writephy(tp, 0x1f, 0x0000);
-
- r810x_aldps_enable(tp);
}
static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
@@ -3525,7 +3485,9 @@ static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
};
/* Disable ALDPS before ram code */
- r810x_aldps_disable(tp);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x18, 0x0310);
+ msleep(100);
rtl_apply_firmware(tp);
@@ -3533,8 +3495,6 @@ static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
-
- r810x_aldps_enable(tp);
}
static void rtl_hw_phy_config(struct net_device *dev)
@@ -4175,7 +4135,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
{
- tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
+ tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
}
static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
@@ -5051,6 +5011,8 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
RTL_W8(MaxTxPacketSize, EarlySize);
+ rtl_disable_clock_request(pdev);
+
RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
@@ -5059,8 +5021,7 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
- RTL_W8(Config5, (RTL_R8(Config5) & ~Spi_en) | ASPM_en);
- RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
+ RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
}
static void rtl_hw_start_8168f(struct rtl8169_private *tp)
@@ -5085,12 +5046,13 @@ static void rtl_hw_start_8168f(struct rtl8169_private *tp)
RTL_W8(MaxTxPacketSize, EarlySize);
+ rtl_disable_clock_request(pdev);
+
RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
- RTL_W32(MISC, RTL_R32(MISC) | PWM_EN | FORCE_CLK);
- RTL_W8(Config5, (RTL_R8(Config5) & ~Spi_en) | ASPM_en);
- RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
+ RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
+ RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
}
static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
@@ -5147,10 +5109,8 @@ static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
- RTL_W32(MISC, (RTL_R32(MISC) | FORCE_CLK) & ~RXDV_GATED_EN);
+ RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
RTL_W8(MaxTxPacketSize, EarlySize);
- RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
- RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
@@ -5366,9 +5326,6 @@ static void rtl_hw_start_8105e_1(struct rtl8169_private *tp)
RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
- RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
- RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
- RTL_W32(MISC, RTL_R32(MISC) | FORCE_CLK);
rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1));
}
@@ -5394,9 +5351,6 @@ static void rtl_hw_start_8402(struct rtl8169_private *tp)
RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
- RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
- RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
- RTL_W32(MISC, RTL_R32(MISC) | FORCE_CLK);
rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));
@@ -5418,10 +5372,7 @@ static void rtl_hw_start_8106(struct rtl8169_private *tp)
/* Force LAN exit from ASPM if Rx/Tx are not idle */
RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
- RTL_W32(MISC,
- (RTL_R32(MISC) | DISABLE_LAN_EN | FORCE_CLK) & ~EARLY_TALLY_EN);
- RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
- RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
+ RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
}
@@ -5918,7 +5869,7 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT));
/* The infamous DAC f*ckup only happens at boot time */
- if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
+ if ((tp->cp_cmd & PCIDAC) && !tp->cur_rx) {
void __iomem *ioaddr = tp->mmio_addr;
netif_info(tp, intr, dev, "disabling PCI DAC\n");
@@ -6033,10 +5984,8 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget
unsigned int count;
cur_rx = tp->cur_rx;
- rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
- rx_left = min(rx_left, budget);
- for (; rx_left > 0; rx_left--, cur_rx++) {
+ for (rx_left = min(budget, NUM_RX_DESC); rx_left > 0; rx_left--, cur_rx++) {
unsigned int entry = cur_rx % NUM_RX_DESC;
struct RxDesc *desc = tp->RxDescArray + entry;
u32 status;
@@ -6114,8 +6063,6 @@ release_descriptor:
count = cur_rx - tp->cur_rx;
tp->cur_rx = cur_rx;
- tp->dirty_rx += count;
-
return count;
}
@@ -6939,7 +6886,6 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Get MAC address */
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = RTL_R8(MAC0 + i);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 3d705862bd7d..33e96176e4d8 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -891,18 +891,16 @@ static int sh_eth_ring_init(struct net_device *ndev)
mdp->rx_buf_sz += NET_IP_ALIGN;
/* Allocate RX and TX skb rings */
- mdp->rx_skbuff = kmalloc(sizeof(*mdp->rx_skbuff) * mdp->num_rx_ring,
- GFP_KERNEL);
+ mdp->rx_skbuff = kmalloc_array(mdp->num_rx_ring,
+ sizeof(*mdp->rx_skbuff), GFP_KERNEL);
if (!mdp->rx_skbuff) {
- dev_err(&ndev->dev, "Cannot allocate Rx skb\n");
ret = -ENOMEM;
return ret;
}
- mdp->tx_skbuff = kmalloc(sizeof(*mdp->tx_skbuff) * mdp->num_tx_ring,
- GFP_KERNEL);
+ mdp->tx_skbuff = kmalloc_array(mdp->num_tx_ring,
+ sizeof(*mdp->tx_skbuff), GFP_KERNEL);
if (!mdp->tx_skbuff) {
- dev_err(&ndev->dev, "Cannot allocate Tx skb\n");
ret = -ENOMEM;
goto skb_ring_free;
}
@@ -1422,7 +1420,7 @@ static int sh_eth_phy_init(struct net_device *ndev)
/* Try connect to PHY */
phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
- 0, mdp->phy_interface);
+ mdp->phy_interface);
if (IS_ERR(phydev)) {
dev_err(&ndev->dev, "phy_connect failed\n");
return PTR_ERR(phydev);
diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c
index 72fc57dd084d..21683e2b1ff4 100644
--- a/drivers/net/ethernet/s6gmac.c
+++ b/drivers/net/ethernet/s6gmac.c
@@ -795,7 +795,7 @@ static inline int s6gmac_phy_start(struct net_device *dev)
struct phy_device *p = NULL;
while ((i < PHY_MAX_ADDR) && (!(p = pd->mii.bus->phy_map[i])))
i++;
- p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, 0,
+ p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link,
PHY_INTERFACE_MODE_RGMII);
if (IS_ERR(p)) {
printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
diff --git a/drivers/net/ethernet/seeq/Kconfig b/drivers/net/ethernet/seeq/Kconfig
index 29f18533fdc7..11f168e46ebe 100644
--- a/drivers/net/ethernet/seeq/Kconfig
+++ b/drivers/net/ethernet/seeq/Kconfig
@@ -6,7 +6,6 @@ config NET_VENDOR_SEEQ
bool "SEEQ devices"
default y
depends on HAS_IOMEM
- depends on (ARM && ARCH_ACORN) || SGI_HAS_SEEQ || EXPERIMENTAL
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -26,17 +25,6 @@ config ARM_ETHER3
If you have an Acorn system with one of these network cards, you
should say Y to this option if you wish to use it with Linux.
-config SEEQ8005
- tristate "SEEQ8005 support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- ---help---
- This is a driver for the SEEQ 8005 network (Ethernet) card. If this
- is for you, read the Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here. The module
- will be called seeq8005.
-
config SGISEEQ
tristate "SGI Seeq ethernet controller support"
depends on SGI_HAS_SEEQ
diff --git a/drivers/net/ethernet/seeq/Makefile b/drivers/net/ethernet/seeq/Makefile
index 3e258a580c05..0488e99b831f 100644
--- a/drivers/net/ethernet/seeq/Makefile
+++ b/drivers/net/ethernet/seeq/Makefile
@@ -3,5 +3,4 @@
#
obj-$(CONFIG_ARM_ETHER3) += ether3.o
-obj-$(CONFIG_SEEQ8005) += seeq8005.o
obj-$(CONFIG_SGISEEQ) += sgiseeq.o
diff --git a/drivers/net/ethernet/seeq/seeq8005.c b/drivers/net/ethernet/seeq/seeq8005.c
deleted file mode 100644
index d6e50de71186..000000000000
--- a/drivers/net/ethernet/seeq/seeq8005.c
+++ /dev/null
@@ -1,749 +0,0 @@
-/* seeq8005.c: A network driver for linux. */
-/*
- Based on skeleton.c,
- Written 1993-94 by Donald Becker.
- See the skeleton.c file for further copyright information.
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- The author may be reached as hamish@zot.apana.org.au
-
- This file is a network device driver for the SEEQ 8005 chipset and
- the Linux operating system.
-
-*/
-
-static const char version[] =
- "seeq8005.c:v1.00 8/07/95 Hamish Coleman (hamish@zot.apana.org.au)\n";
-
-/*
- Sources:
- SEEQ 8005 databook
-
- Version history:
- 1.00 Public release. cosmetic changes (no warnings now)
- 0.68 Turning per- packet,interrupt debug messages off - testing for release.
- 0.67 timing problems/bad buffer reads seem to be fixed now
- 0.63 *!@$ protocol=eth_type_trans -- now packets flow
- 0.56 Send working
- 0.48 Receive working
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "seeq8005.h"
-
-/* First, a few definitions that the brave might change. */
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int seeq8005_portlist[] __initdata =
- { 0x300, 0x320, 0x340, 0x360, 0};
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 1
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-/* Information that need to be kept for each board. */
-struct net_local {
- unsigned short receive_ptr; /* What address in packet memory do we expect a recv_pkt_header? */
- long open_time; /* Useless example local info. */
-};
-
-/* The station (ethernet) address prefix, used for IDing the board. */
-#define SA_ADDR0 0x00
-#define SA_ADDR1 0x80
-#define SA_ADDR2 0x4b
-
-/* Index to functions, as function prototypes. */
-
-static int seeq8005_probe1(struct net_device *dev, int ioaddr);
-static int seeq8005_open(struct net_device *dev);
-static void seeq8005_timeout(struct net_device *dev);
-static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
-static void seeq8005_rx(struct net_device *dev);
-static int seeq8005_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-
-/* Example routines you must write ;->. */
-#define tx_done(dev) (inw(SEEQ_STATUS) & SEEQSTAT_TX_ON)
-static void hardware_send_packet(struct net_device *dev, char *buf, int length);
-extern void seeq8005_init(struct net_device *dev, int startp);
-static inline void wait_for_buffer(struct net_device *dev);
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
- If dev->base_addr == 0, probe all likely locations.
- If dev->base_addr == 1, always return failure.
- */
-
-static int io = 0x320;
-static int irq = 10;
-
-struct net_device * __init seeq8005_probe(int unit)
-{
- struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
- unsigned *port;
- int err = 0;
-
- if (!dev)
- return ERR_PTR(-ENODEV);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- io = dev->base_addr;
- irq = dev->irq;
- }
-
- if (io > 0x1ff) { /* Check a single specified location. */
- err = seeq8005_probe1(dev, io);
- } else if (io != 0) { /* Don't probe at all. */
- err = -ENXIO;
- } else {
- for (port = seeq8005_portlist; *port; port++) {
- if (seeq8005_probe1(dev, *port) == 0)
- break;
- }
- if (!*port)
- err = -ENODEV;
- }
- if (err)
- goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
- return dev;
-out1:
- release_region(dev->base_addr, SEEQ8005_IO_EXTENT);
-out:
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-static const struct net_device_ops seeq8005_netdev_ops = {
- .ndo_open = seeq8005_open,
- .ndo_stop = seeq8005_close,
- .ndo_start_xmit = seeq8005_send_packet,
- .ndo_tx_timeout = seeq8005_timeout,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/* This is the real probe routine. Linux has a history of friendly device
- probes on the ISA bus. A good device probes avoids doing writes, and
- verifies that the correct device exists and functions. */
-
-static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
-{
- static unsigned version_printed;
- int i,j;
- unsigned char SA_prom[32];
- int old_cfg1;
- int old_cfg2;
- int old_stat;
- int old_dmaar;
- int old_rear;
- int retval;
-
- if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
- return -ENODEV;
-
- if (net_debug>1)
- printk("seeq8005: probing at 0x%x\n",ioaddr);
-
- old_stat = inw(SEEQ_STATUS); /* read status register */
- if (old_stat == 0xffff) {
- retval = -ENODEV;
- goto out; /* assume that 0xffff == no device */
- }
- if ( (old_stat & 0x1800) != 0x1800 ) { /* assume that unused bits are 1, as my manual says */
- if (net_debug>1) {
- printk("seeq8005: reserved stat bits != 0x1800\n");
- printk(" == 0x%04x\n",old_stat);
- }
- retval = -ENODEV;
- goto out;
- }
-
- old_rear = inw(SEEQ_REA);
- if (old_rear == 0xffff) {
- outw(0,SEEQ_REA);
- if (inw(SEEQ_REA) == 0xffff) { /* assume that 0xffff == no device */
- retval = -ENODEV;
- goto out;
- }
- } else if ((old_rear & 0xff00) != 0xff00) { /* assume that unused bits are 1 */
- if (net_debug>1) {
- printk("seeq8005: unused rear bits != 0xff00\n");
- printk(" == 0x%04x\n",old_rear);
- }
- retval = -ENODEV;
- goto out;
- }
-
- old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */
- old_cfg1 = inw(SEEQ_CFG1);
- old_dmaar = inw(SEEQ_DMAAR);
-
- if (net_debug>4) {
- printk("seeq8005: stat = 0x%04x\n",old_stat);
- printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
- printk("seeq8005: cfg2 = 0x%04x\n",old_cfg2);
- printk("seeq8005: raer = 0x%04x\n",old_rear);
- printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
- }
-
- outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); /* setup for reading PROM */
- outw( 0, SEEQ_DMAAR); /* set starting PROM address */
- outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1); /* set buffer to look at PROM */
-
-
- j=0;
- for(i=0; i <32; i++) {
- j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff;
- }
-
-#if 0
- /* untested because I only have the one card */
- if ( (j&0xff) != 0 ) { /* checksum appears to be 8bit = 0 */
- if (net_debug>1) { /* check this before deciding that we have a card */
- printk("seeq8005: prom sum error\n");
- }
- outw( old_stat, SEEQ_STATUS);
- outw( old_dmaar, SEEQ_DMAAR);
- outw( old_cfg1, SEEQ_CFG1);
- retval = -ENODEV;
- goto out;
- }
-#endif
-
- outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */
- udelay(5);
- outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-
- if (net_debug) {
- printk("seeq8005: prom sum = 0x%08x\n",j);
- for(j=0; j<32; j+=16) {
- printk("seeq8005: prom %02x: ",j);
- for(i=0;i<16;i++) {
- printk("%02x ",SA_prom[j|i]);
- }
- printk(" ");
- for(i=0;i<16;i++) {
- if ((SA_prom[j|i]>31)&&(SA_prom[j|i]<127)) {
- printk("%c", SA_prom[j|i]);
- } else {
- printk(" ");
- }
- }
- printk("\n");
- }
- }
-
-#if 0
- /*
- * testing the packet buffer memory doesn't work yet
- * but all other buffer accesses do
- * - fixing is not a priority
- */
- if (net_debug>1) { /* test packet buffer memory */
- printk("seeq8005: testing packet buffer ... ");
- outw( SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
- outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
- outw( 0 , SEEQ_DMAAR);
- for(i=0;i<32768;i++) {
- outw(0x5a5a, SEEQ_BUFFER);
- }
- j=jiffies+HZ;
- while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && time_before(jiffies, j) )
- mb();
- outw( 0 , SEEQ_DMAAR);
- while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, j+HZ))
- mb();
- if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
- outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD);
- outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
- j=0;
- for(i=0;i<32768;i++) {
- if (inw(SEEQ_BUFFER) != 0x5a5a)
- j++;
- }
- if (j) {
- printk("%i\n",j);
- } else {
- printk("ok.\n");
- }
- }
-#endif
-
- if (net_debug && version_printed++ == 0)
- printk(version);
-
- printk("%s: %s found at %#3x, ", dev->name, "seeq8005", ioaddr);
-
- /* Fill in the 'dev' fields. */
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
- /* Retrieve and print the ethernet address. */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = SA_prom[i+6];
- printk("%pM", dev->dev_addr);
-
- if (dev->irq == 0xff)
- ; /* Do nothing: a user-level program will set it. */
- else if (dev->irq < 2) { /* "Auto-IRQ" */
- unsigned long cookie = probe_irq_on();
-
- outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
-
- dev->irq = probe_irq_off(cookie);
-
- if (net_debug >= 2)
- printk(" autoirq is %d\n", dev->irq);
- } else if (dev->irq == 2)
- /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
- * or don't know which one to set.
- */
- dev->irq = 9;
-
-#if 0
- {
- int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev);
- if (irqval) {
- printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
- dev->irq, irqval);
- retval = -EAGAIN;
- goto out;
- }
- }
-#endif
- dev->netdev_ops = &seeq8005_netdev_ops;
- dev->watchdog_timeo = HZ/20;
- dev->flags &= ~IFF_MULTICAST;
-
- return 0;
-out:
- release_region(ioaddr, SEEQ8005_IO_EXTENT);
- return retval;
-}
-
-
-/* Open/initialize the board. This is called (in the current kernel)
- sometime after booting when the 'ifconfig' program is run.
-
- This routine should set everything up anew at each open, even
- registers that "should" only need to be set once at boot, so that
- there is non-reboot way to recover if something goes wrong.
- */
-static int seeq8005_open(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-
- {
- int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev);
- if (irqval) {
- printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
- dev->irq, irqval);
- return -EAGAIN;
- }
- }
-
- /* Reset the hardware here. Don't forget to set the station address. */
- seeq8005_init(dev, 1);
-
- lp->open_time = jiffies;
-
- netif_start_queue(dev);
- return 0;
-}
-
-static void seeq8005_timeout(struct net_device *dev)
-{
- int ioaddr = dev->base_addr;
- printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
- tx_done(dev) ? "IRQ conflict" : "network cable problem");
- /* Try to restart the adaptor. */
- seeq8005_init(dev, 1);
- dev->trans_start = jiffies; /* prevent tx timeout */
- netif_wake_queue(dev);
-}
-
-static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
- struct net_device *dev)
-{
- short length = skb->len;
- unsigned char *buf;
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
- buf = skb->data;
-
- /* Block a timer-based transmit from overlapping */
- netif_stop_queue(dev);
-
- hardware_send_packet(dev, buf, length);
- dev->stats.tx_bytes += length;
- dev_kfree_skb (skb);
- /* You might need to clean up and record Tx statistics here. */
-
- return NETDEV_TX_OK;
-}
-
-/*
- * wait_for_buffer
- *
- * This routine waits for the SEEQ chip to assert that the FIFO is ready
- * by checking for a window interrupt, and then clearing it. This has to
- * occur in the interrupt handler!
- */
-inline void wait_for_buffer(struct net_device * dev)
-{
- int ioaddr = dev->base_addr;
- unsigned long tmp;
- int status;
-
- tmp = jiffies + HZ;
- while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
- cpu_relax();
-
- if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
- outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-}
-
-/* The typical workload of the driver:
- Handle the network interface interrupts. */
-static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct net_local *lp;
- int ioaddr, status, boguscount = 0;
- int handled = 0;
-
- ioaddr = dev->base_addr;
- lp = netdev_priv(dev);
-
- status = inw(SEEQ_STATUS);
- do {
- if (net_debug >2) {
- printk("%s: int, status=0x%04x\n",dev->name,status);
- }
-
- if (status & SEEQSTAT_WINDOW_INT) {
- handled = 1;
- outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
- if (net_debug) {
- printk("%s: window int!\n",dev->name);
- }
- }
- if (status & SEEQSTAT_TX_INT) {
- handled = 1;
- outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
- dev->stats.tx_packets++;
- netif_wake_queue(dev); /* Inform upper layers. */
- }
- if (status & SEEQSTAT_RX_INT) {
- handled = 1;
- /* Got a packet(s). */
- seeq8005_rx(dev);
- }
- status = inw(SEEQ_STATUS);
- } while ( (++boguscount < 10) && (status & SEEQSTAT_ANY_INT)) ;
-
- if(net_debug>2) {
- printk("%s: eoi\n",dev->name);
- }
- return IRQ_RETVAL(handled);
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void seeq8005_rx(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int boguscount = 10;
- int pkt_hdr;
- int ioaddr = dev->base_addr;
-
- do {
- int next_packet;
- int pkt_len;
- int i;
- int status;
-
- status = inw(SEEQ_STATUS);
- outw( lp->receive_ptr, SEEQ_DMAAR);
- outw(SEEQCMD_FIFO_READ | SEEQCMD_RX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
- wait_for_buffer(dev);
- next_packet = ntohs(inw(SEEQ_BUFFER));
- pkt_hdr = inw(SEEQ_BUFFER);
-
- if (net_debug>2) {
- printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
- }
-
- if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) { /* Read all the frames? */
- return; /* Done for now */
- }
-
- if ((pkt_hdr & SEEQPKTS_DONE)==0)
- break;
-
- if (next_packet < lp->receive_ptr) {
- pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
- } else {
- pkt_len = next_packet - lp->receive_ptr - 4;
- }
-
- if (next_packet < ((DEFAULT_TEA+1)<<8)) { /* is the next_packet address sane? */
- printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
- seeq8005_init(dev,1);
- return;
- }
-
- lp->receive_ptr = next_packet;
-
- if (net_debug>2) {
- printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
- }
-
- if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */
- dev->stats.rx_errors++;
- if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++;
- if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++;
- if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++;
- if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++;
- /* skip over this packet */
- outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
- outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
- } else {
- /* Malloc up new buffer. */
- struct sk_buff *skb;
- unsigned char *buf;
-
- skb = netdev_alloc_skb(dev, pkt_len);
- if (skb == NULL) {
- printk("%s: Memory squeeze, dropping packet.\n", dev->name);
- dev->stats.rx_dropped++;
- break;
- }
- skb_reserve(skb, 2); /* align data on 16 byte */
- buf = skb_put(skb,pkt_len);
-
- insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
-
- if (net_debug>2) {
- char * p = buf;
- printk("%s: recv ",dev->name);
- for(i=0;i<14;i++) {
- printk("%02x ",*(p++)&0xff);
- }
- printk("\n");
- }
-
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
- }
- } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
-
- /* If any worth-while packets have been received, netif_rx()
- has done a mark_bh(NET_BH) for us and will work on them
- when we get to the bottom-half routine. */
-}
-
-/* The inverse routine to net_open(). */
-static int seeq8005_close(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
-
- lp->open_time = 0;
-
- netif_stop_queue(dev);
-
- /* Flush the Tx and disable Rx here. */
- outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-
- free_irq(dev->irq, dev);
-
- /* Update the statistics here. */
-
- return 0;
-
-}
-
-/* Set or clear the multicast filter for this adaptor.
- num_addrs == -1 Promiscuous mode, receive all packets
- num_addrs == 0 Normal mode, clear multicast list
- num_addrs > 0 Multicast mode, receive normal and MC packets, and do
- best-effort filtering.
- */
-static void set_multicast_list(struct net_device *dev)
-{
-/*
- * I _could_ do up to 6 addresses here, but won't (yet?)
- */
-
-#if 0
- int ioaddr = dev->base_addr;
-/*
- * hmm, not even sure if my matching works _anyway_ - seem to be receiving
- * _everything_ . . .
- */
-
- if (num_addrs) { /* Enable promiscuous mode */
- outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL, SEEQ_CFG1);
- dev->flags|=IFF_PROMISC;
- } else { /* Disable promiscuous mode, use normal mode */
- outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1);
- }
-#endif
-}
-
-void seeq8005_init(struct net_device *dev, int startp)
-{
- struct net_local *lp = netdev_priv(dev);
- int ioaddr = dev->base_addr;
- int i;
-
- outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */
- udelay(5);
-
- outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
- outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */
-/* wait_for_buffer(dev); */ /* I think that you only need a wait for memory buffer */
- outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
-
- for(i=0;i<6;i++) { /* set Station address */
- outb(dev->dev_addr[i], SEEQ_BUFFER);
- udelay(2);
- }
-
- outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */
- outb( DEFAULT_TEA, SEEQ_BUFFER); /* this gives us 16K of send buffer and 48K of recv buffer */
-
- lp->receive_ptr = (DEFAULT_TEA+1)<<8; /* so we can find our packet_header */
- outw( lp->receive_ptr, SEEQ_RPR); /* Receive Pointer Register is set to recv buffer memory */
-
- outw( 0x00ff, SEEQ_REA); /* Receive Area End */
-
- if (net_debug>4) {
- printk("%s: SA0 = ",dev->name);
-
- outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
- outw( 0, SEEQ_DMAAR);
- outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
-
- for(i=0;i<6;i++) {
- printk("%02x ",inb(SEEQ_BUFFER));
- }
- printk("\n");
- }
-
- outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
- outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
- outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
-
- if (net_debug>4) {
- int old_cfg1;
- old_cfg1 = inw(SEEQ_CFG1);
- printk("%s: stat = 0x%04x\n",dev->name,inw(SEEQ_STATUS));
- printk("%s: cfg1 = 0x%04x\n",dev->name,old_cfg1);
- printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
- printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
- printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
-
- }
-}
-
-
-static void hardware_send_packet(struct net_device * dev, char *buf, int length)
-{
- int ioaddr = dev->base_addr;
- int status = inw(SEEQ_STATUS);
- int transmit_ptr = 0;
- unsigned long tmp;
-
- if (net_debug>4) {
- printk("%s: send 0x%04x\n",dev->name,length);
- }
-
- /* Set FIFO to writemode and set packet-buffer address */
- outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
- outw( transmit_ptr, SEEQ_DMAAR);
-
- /* output SEEQ Packet header barfage */
- outw( htons(length + 4), SEEQ_BUFFER);
- outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
-
- /* blat the buffer */
- outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
- /* paranoia !! */
- outw( 0, SEEQ_BUFFER);
- outw( 0, SEEQ_BUFFER);
-
- /* set address of start of transmit chain */
- outw( transmit_ptr, SEEQ_TPR);
-
- /* drain FIFO */
- tmp = jiffies;
- while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ))
- mb();
-
- /* doit ! */
- outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-
-}
-
-
-#ifdef MODULE
-
-static struct net_device *dev_seeq;
-MODULE_LICENSE("GPL");
-module_param(io, int, 0);
-module_param(irq, int, 0);
-MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address");
-MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number");
-
-int __init init_module(void)
-{
- dev_seeq = seeq8005_probe(-1);
- return PTR_RET(dev_seeq);
-}
-
-void __exit cleanup_module(void)
-{
- unregister_netdev(dev_seeq);
- release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT);
- free_netdev(dev_seeq);
-}
-
-#endif /* MODULE */
diff --git a/drivers/net/ethernet/seeq/seeq8005.h b/drivers/net/ethernet/seeq/seeq8005.h
deleted file mode 100644
index 5dfb0098c6ca..000000000000
--- a/drivers/net/ethernet/seeq/seeq8005.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * defines, etc for the seeq8005
- */
-
-/*
- * This file is distributed under GPL.
- *
- * This style and layout of this file is also copied
- * from many of the other linux network device drivers.
- */
-
-/* The number of low I/O ports used by the ethercard. */
-#define SEEQ8005_IO_EXTENT 16
-
-#define SEEQ_B (ioaddr)
-
-#define SEEQ_CMD (SEEQ_B) /* Write only */
-#define SEEQ_STATUS (SEEQ_B) /* Read only */
-#define SEEQ_CFG1 (SEEQ_B + 2)
-#define SEEQ_CFG2 (SEEQ_B + 4)
-#define SEEQ_REA (SEEQ_B + 6) /* Receive End Area Register */
-#define SEEQ_RPR (SEEQ_B + 10) /* Receive Pointer Register */
-#define SEEQ_TPR (SEEQ_B + 12) /* Transmit Pointer Register */
-#define SEEQ_DMAAR (SEEQ_B + 14) /* DMA Address Register */
-#define SEEQ_BUFFER (SEEQ_B + 8) /* Buffer Window Register */
-
-#define DEFAULT_TEA (0x3f)
-
-#define SEEQCMD_DMA_INT_EN (0x0001) /* DMA Interrupt Enable */
-#define SEEQCMD_RX_INT_EN (0x0002) /* Receive Interrupt Enable */
-#define SEEQCMD_TX_INT_EN (0x0004) /* Transmit Interrupt Enable */
-#define SEEQCMD_WINDOW_INT_EN (0x0008) /* What the hell is this for?? */
-#define SEEQCMD_INT_MASK (0x000f)
-
-#define SEEQCMD_DMA_INT_ACK (0x0010) /* DMA ack */
-#define SEEQCMD_RX_INT_ACK (0x0020)
-#define SEEQCMD_TX_INT_ACK (0x0040)
-#define SEEQCMD_WINDOW_INT_ACK (0x0080)
-#define SEEQCMD_ACK_ALL (0x00f0)
-
-#define SEEQCMD_SET_DMA_ON (0x0100) /* Enables DMA Request logic */
-#define SEEQCMD_SET_RX_ON (0x0200) /* Enables Packet RX */
-#define SEEQCMD_SET_TX_ON (0x0400) /* Starts TX run */
-#define SEEQCMD_SET_DMA_OFF (0x0800)
-#define SEEQCMD_SET_RX_OFF (0x1000)
-#define SEEQCMD_SET_TX_OFF (0x2000)
-#define SEEQCMD_SET_ALL_OFF (0x3800) /* set all logic off */
-
-#define SEEQCMD_FIFO_READ (0x4000) /* Set FIFO to read mode (read from Buffer) */
-#define SEEQCMD_FIFO_WRITE (0x8000) /* Set FIFO to write mode */
-
-#define SEEQSTAT_DMA_INT_EN (0x0001) /* Status of interrupt enable */
-#define SEEQSTAT_RX_INT_EN (0x0002)
-#define SEEQSTAT_TX_INT_EN (0x0004)
-#define SEEQSTAT_WINDOW_INT_EN (0x0008)
-
-#define SEEQSTAT_DMA_INT (0x0010) /* Interrupt flagged */
-#define SEEQSTAT_RX_INT (0x0020)
-#define SEEQSTAT_TX_INT (0x0040)
-#define SEEQSTAT_WINDOW_INT (0x0080)
-#define SEEQSTAT_ANY_INT (0x00f0)
-
-#define SEEQSTAT_DMA_ON (0x0100) /* DMA logic on */
-#define SEEQSTAT_RX_ON (0x0200) /* Packet RX on */
-#define SEEQSTAT_TX_ON (0x0400) /* TX running */
-
-#define SEEQSTAT_FIFO_FULL (0x2000)
-#define SEEQSTAT_FIFO_EMPTY (0x4000)
-#define SEEQSTAT_FIFO_DIR (0x8000) /* 1=read, 0=write */
-
-#define SEEQCFG1_BUFFER_MASK (0x000f) /* define what maps into the BUFFER register */
-#define SEEQCFG1_BUFFER_MAC0 (0x0000) /* MAC station addresses 0-5 */
-#define SEEQCFG1_BUFFER_MAC1 (0x0001)
-#define SEEQCFG1_BUFFER_MAC2 (0x0002)
-#define SEEQCFG1_BUFFER_MAC3 (0x0003)
-#define SEEQCFG1_BUFFER_MAC4 (0x0004)
-#define SEEQCFG1_BUFFER_MAC5 (0x0005)
-#define SEEQCFG1_BUFFER_PROM (0x0006) /* The Address/CFG PROM */
-#define SEEQCFG1_BUFFER_TEA (0x0007) /* Transmit end area */
-#define SEEQCFG1_BUFFER_BUFFER (0x0008) /* Packet buffer memory */
-#define SEEQCFG1_BUFFER_INT_VEC (0x0009) /* Interrupt Vector */
-
-#define SEEQCFG1_DMA_INTVL_MASK (0x0030)
-#define SEEQCFG1_DMA_CONT (0x0000)
-#define SEEQCFG1_DMA_800ns (0x0010)
-#define SEEQCFG1_DMA_1600ns (0x0020)
-#define SEEQCFG1_DMA_3200ns (0x0030)
-
-#define SEEQCFG1_DMA_LEN_MASK (0x00c0)
-#define SEEQCFG1_DMA_LEN1 (0x0000)
-#define SEEQCFG1_DMA_LEN2 (0x0040)
-#define SEEQCFG1_DMA_LEN4 (0x0080)
-#define SEEQCFG1_DMA_LEN8 (0x00c0)
-
-#define SEEQCFG1_MAC_MASK (0x3f00) /* Dis/enable bits for MAC addresses */
-#define SEEQCFG1_MAC0_EN (0x0100)
-#define SEEQCFG1_MAC1_EN (0x0200)
-#define SEEQCFG1_MAC2_EN (0x0400)
-#define SEEQCFG1_MAC3_EN (0x0800)
-#define SEEQCFG1_MAC4_EN (0x1000)
-#define SEEQCFG1_MAC5_EN (0x2000)
-
-#define SEEQCFG1_MATCH_MASK (0xc000) /* Packet matching logic cfg bits */
-#define SEEQCFG1_MATCH_SPECIFIC (0x0000) /* only matching MAC addresses */
-#define SEEQCFG1_MATCH_BROAD (0x4000) /* matching and broadcast addresses */
-#define SEEQCFG1_MATCH_MULTI (0x8000) /* matching, broadcast and multicast */
-#define SEEQCFG1_MATCH_ALL (0xc000) /* Promiscuous mode */
-
-#define SEEQCFG1_DEFAULT (SEEQCFG1_BUFFER_BUFFER | SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD)
-
-#define SEEQCFG2_BYTE_SWAP (0x0001) /* 0=Intel byte-order */
-#define SEEQCFG2_AUTO_REA (0x0002) /* if set, Receive End Area will be updated when reading from Buffer */
-
-#define SEEQCFG2_CRC_ERR_EN (0x0008) /* enables receiving of packets with CRC errors */
-#define SEEQCFG2_DRIBBLE_EN (0x0010) /* enables receiving of non-aligned packets */
-#define SEEQCFG2_SHORT_EN (0x0020) /* enables receiving of short packets */
-
-#define SEEQCFG2_SLOTSEL (0x0040) /* 0= standard IEEE802.3, 1= smaller,faster, non-standard */
-#define SEEQCFG2_NO_PREAM (0x0080) /* 1= user supplies Xmit preamble bytes */
-#define SEEQCFG2_ADDR_LEN (0x0100) /* 1= 2byte addresses */
-#define SEEQCFG2_REC_CRC (0x0200) /* 0= received packets will have CRC stripped from them */
-#define SEEQCFG2_XMIT_NO_CRC (0x0400) /* don't xmit CRC with each packet (user supplies it) */
-#define SEEQCFG2_LOOPBACK (0x0800)
-#define SEEQCFG2_CTRLO (0x1000)
-#define SEEQCFG2_RESET (0x8000) /* software Hard-reset bit */
-
-struct seeq_pkt_hdr {
- unsigned short next; /* address of next packet header */
- unsigned char babble_int:1, /* enable int on >1514 byte packet */
- coll_int:1, /* enable int on collision */
- coll_16_int:1, /* enable int on >15 collision */
- xmit_int:1, /* enable int on success (or xmit with <15 collision) */
- unused:1,
- data_follows:1, /* if not set, process this as a header and pointer only */
- chain_cont:1, /* if set, more headers in chain only cmd bit valid in recv header */
- xmit_recv:1; /* if set, a xmit packet, else a receive packet.*/
- unsigned char status;
-};
-
-#define SEEQPKTH_BAB_INT_EN (0x01) /* xmit only */
-#define SEEQPKTH_COL_INT_EN (0x02) /* xmit only */
-#define SEEQPKTH_COL16_INT_EN (0x04) /* xmit only */
-#define SEEQPKTH_XMIT_INT_EN (0x08) /* xmit only */
-#define SEEQPKTH_DATA_FOLLOWS (0x20) /* supposedly in xmit only */
-#define SEEQPKTH_CHAIN (0x40) /* more headers follow */
-#define SEEQPKTH_XMIT (0x80)
-
-#define SEEQPKTS_BABBLE (0x0100) /* xmit only */
-#define SEEQPKTS_OVERSIZE (0x0100) /* recv only */
-#define SEEQPKTS_COLLISION (0x0200) /* xmit only */
-#define SEEQPKTS_CRC_ERR (0x0200) /* recv only */
-#define SEEQPKTS_COLL16 (0x0400) /* xmit only */
-#define SEEQPKTS_DRIB (0x0400) /* recv only */
-#define SEEQPKTS_SHORT (0x0800) /* recv only */
-#define SEEQPKTS_DONE (0x8000)
-#define SEEQPKTS_ANY_ERROR (0x0f00)
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index 0767043f44a4..3f93624fc273 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -1439,7 +1439,7 @@ static int efx_phc_settime(struct ptp_clock_info *ptp,
delta = timespec_sub(*e_ts, time_now);
- efx_phc_adjtime(ptp, timespec_to_ns(&delta));
+ rc = efx_phc_adjtime(ptp, timespec_to_ns(&delta));
if (rc != 0)
return rc;
diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
index dc171b4961e4..7ed08c32a9c5 100644
--- a/drivers/net/ethernet/sgi/ioc3-eth.c
+++ b/drivers/net/ethernet/sgi/ioc3-eth.c
@@ -1565,9 +1565,9 @@ static void ioc3_get_drvinfo (struct net_device *dev,
{
struct ioc3_private *ip = netdev_priv(dev);
- strcpy (info->driver, IOC3_NAME);
- strcpy (info->version, IOC3_VERSION);
- strcpy (info->bus_info, pci_name(ip->pdev));
+ strlcpy(info->driver, IOC3_NAME, sizeof(info->driver));
+ strlcpy(info->version, IOC3_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(ip->pdev), sizeof(info->bus_info));
}
static int ioc3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/silan/Kconfig b/drivers/net/ethernet/silan/Kconfig
index ae1ce170864d..3409b3f97a1b 100644
--- a/drivers/net/ethernet/silan/Kconfig
+++ b/drivers/net/ethernet/silan/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_SILAN
bool "Silan devices"
default y
- depends on PCI && EXPERIMENTAL
+ depends on PCI
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -19,8 +19,8 @@ config NET_VENDOR_SILAN
if NET_VENDOR_SILAN
config SC92031
- tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "Silan SC92031 PCI Fast Ethernet Adapter driver"
+ depends on PCI
select CRC32
---help---
This is a driver for the Fast Ethernet PCI network cards based on
diff --git a/drivers/net/ethernet/silan/sc92031.c b/drivers/net/ethernet/silan/sc92031.c
index b2315324cc6d..28f7268f1b88 100644
--- a/drivers/net/ethernet/silan/sc92031.c
+++ b/drivers/net/ethernet/silan/sc92031.c
@@ -1458,12 +1458,12 @@ static int sc92031_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mac0 = ioread32(port_base + MAC0);
mac1 = ioread32(port_base + MAC0 + 4);
- dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24;
- dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16;
- dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8;
- dev->dev_addr[3] = dev->perm_addr[3] = mac0;
- dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8;
- dev->dev_addr[5] = dev->perm_addr[5] = mac1;
+ dev->dev_addr[0] = mac0 >> 24;
+ dev->dev_addr[1] = mac0 >> 16;
+ dev->dev_addr[2] = mac0 >> 8;
+ dev->dev_addr[3] = mac0;
+ dev->dev_addr[4] = mac1 >> 8;
+ dev->dev_addr[5] = mac1;
err = register_netdev(dev);
if (err < 0)
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index 5bffd9749a58..efca14eaefa9 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -247,8 +247,7 @@ static const struct ethtool_ops sis900_ethtool_ops;
* @net_dev: the net device to get address for
*
* Older SiS900 and friends, use EEPROM to store MAC address.
- * MAC address is read from read_eeprom() into @net_dev->dev_addr and
- * @net_dev->perm_addr.
+ * MAC address is read from read_eeprom() into @net_dev->dev_addr.
*/
static int sis900_get_mac_addr(struct pci_dev *pci_dev,
@@ -271,9 +270,6 @@ static int sis900_get_mac_addr(struct pci_dev *pci_dev,
for (i = 0; i < 3; i++)
((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
- /* Store MAC Address in perm_addr */
- memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
return 1;
}
@@ -284,8 +280,7 @@ static int sis900_get_mac_addr(struct pci_dev *pci_dev,
*
* SiS630E model, use APC CMOS RAM to store MAC address.
* APC CMOS RAM is accessed through ISA bridge.
- * MAC address is read into @net_dev->dev_addr and
- * @net_dev->perm_addr.
+ * MAC address is read into @net_dev->dev_addr.
*/
static int sis630e_get_mac_addr(struct pci_dev *pci_dev,
@@ -311,9 +306,6 @@ static int sis630e_get_mac_addr(struct pci_dev *pci_dev,
((u8 *)(net_dev->dev_addr))[i] = inb(0x71);
}
- /* Store MAC Address in perm_addr */
- memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40);
pci_dev_put(isa_bridge);
@@ -328,7 +320,7 @@ static int sis630e_get_mac_addr(struct pci_dev *pci_dev,
*
* SiS635 model, set MAC Reload Bit to load Mac address from APC
* to rfdr. rfdr is accessed through rfcr. MAC address is read into
- * @net_dev->dev_addr and @net_dev->perm_addr.
+ * @net_dev->dev_addr.
*/
static int sis635_get_mac_addr(struct pci_dev *pci_dev,
@@ -353,9 +345,6 @@ static int sis635_get_mac_addr(struct pci_dev *pci_dev,
*( ((u16 *)net_dev->dev_addr) + i) = sr16(rfdr);
}
- /* Store MAC Address in perm_addr */
- memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
/* enable packet filtering */
sw32(rfcr, rfcrSave | RFEN);
@@ -375,7 +364,7 @@ static int sis635_get_mac_addr(struct pci_dev *pci_dev,
* EEDONE signal to refuse EEPROM access by LAN.
* The EEPROM map of SiS962 or SiS963 is different to SiS900.
* The signature field in SiS962 or SiS963 spec is meaningless.
- * MAC address is read into @net_dev->dev_addr and @net_dev->perm_addr.
+ * MAC address is read into @net_dev->dev_addr.
*/
static int sis96x_get_mac_addr(struct pci_dev *pci_dev,
@@ -395,9 +384,6 @@ static int sis96x_get_mac_addr(struct pci_dev *pci_dev,
for (i = 0; i < 3; i++)
mac[i] = read_eeprom(ioaddr, i + EEPROMMACAddr);
- /* Store MAC Address in perm_addr */
- memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN);
-
rc = 1;
break;
}
diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c
index 59a6f88da867..9dd842dbb859 100644
--- a/drivers/net/ethernet/smsc/smc911x.c
+++ b/drivers/net/ethernet/smsc/smc911x.c
@@ -1522,9 +1522,10 @@ smc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
static void
smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strncpy(info->driver, CARDNAME, sizeof(info->driver));
- strncpy(info->version, version, sizeof(info->version));
- strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
+ strlcpy(info->driver, CARDNAME, sizeof(info->driver));
+ strlcpy(info->version, version, sizeof(info->version));
+ strlcpy(info->bus_info, dev_name(dev->dev.parent),
+ sizeof(info->bus_info));
}
static int smc911x_ethtool_nwayreset(struct net_device *dev)
@@ -2035,7 +2036,7 @@ static int smc911x_drv_probe(struct platform_device *pdev)
struct net_device *ndev;
struct resource *res;
struct smc911x_local *lp;
- unsigned int *addr;
+ void __iomem *addr;
int ret;
DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index a670d23d9340..591650a8de38 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -1597,9 +1597,10 @@ smc_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
static void
smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strncpy(info->driver, CARDNAME, sizeof(info->driver));
- strncpy(info->version, version, sizeof(info->version));
- strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
+ strlcpy(info->driver, CARDNAME, sizeof(info->driver));
+ strlcpy(info->version, version, sizeof(info->version));
+ strlcpy(info->bus_info, dev_name(dev->dev.parent),
+ sizeof(info->bus_info));
}
static int smc_ethtool_nwayreset(struct net_device *dev)
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index e112877d15d3..da5cc9a3b34c 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -997,9 +997,8 @@ static int smsc911x_mii_probe(struct net_device *dev)
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);
+ ret = phy_connect_direct(dev, phydev, &smsc911x_phy_adjust_link,
+ pdata->config.phy_interface);
if (ret) {
netdev_err(dev, "Could not attach to PHY\n");
@@ -1831,7 +1830,6 @@ static int smsc911x_set_mac_address(struct net_device *dev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
spin_lock_irq(&pdata->mac_lock);
diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c
index 3c586585e1b3..d457fa2d7509 100644
--- a/drivers/net/ethernet/smsc/smsc9420.c
+++ b/drivers/net/ethernet/smsc/smsc9420.c
@@ -1179,7 +1179,7 @@ static int smsc9420_mii_probe(struct net_device *dev)
phydev->phy_id);
phydev = phy_connect(dev, dev_name(&phydev->dev),
- smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+ smsc9420_phy_adjust_link, PHY_INTERFACE_MODE_MII);
if (IS_ERR(phydev)) {
pr_err("%s: Could not attach to PHY\n", dev->name);
@@ -1250,12 +1250,11 @@ static int smsc9420_alloc_tx_ring(struct smsc9420_pdata *pd)
BUG_ON(!pd->tx_ring);
- pd->tx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) *
- TX_RING_SIZE), GFP_KERNEL);
- if (!pd->tx_buffers) {
- smsc_warn(IFUP, "Failed to allocated tx_buffers");
+ pd->tx_buffers = kmalloc_array(TX_RING_SIZE,
+ sizeof(struct smsc9420_ring_info),
+ GFP_KERNEL);
+ if (!pd->tx_buffers)
return -ENOMEM;
- }
/* Initialize the TX Ring */
for (i = 0; i < TX_RING_SIZE; i++) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 1164930a40a5..c0ea838c78d1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -26,8 +26,8 @@ config STMMAC_PLATFORM
If unsure, say N.
config STMMAC_PCI
- bool "STMMAC PCI bus support (EXPERIMENTAL)"
- depends on STMMAC_ETH && PCI && EXPERIMENTAL
+ bool "STMMAC PCI bus support"
+ depends on STMMAC_ETH && PCI
---help---
This is to select the Synopsys DWMAC available on PCI devices,
if you have a controller with this interface, say Y or M here.
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 1372ce210b58..d1ac39c1b05d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -210,8 +210,7 @@ static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
strlcpy(info->driver, MAC100_ETHTOOL_NAME,
sizeof(info->driver));
- strcpy(info->version, DRV_MODULE_VERSION);
- info->fw_version[0] = '\0';
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
}
static int stmmac_ethtool_getsettings(struct net_device *dev,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index f07c0612abf6..39c6c5524633 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -69,7 +69,7 @@
#undef STMMAC_XMIT_DEBUG
/*#define STMMAC_XMIT_DEBUG*/
-#ifdef STMMAC_TX_DEBUG
+#ifdef STMMAC_XMIT_DEBUG
#define TX_DBG(fmt, args...) printk(fmt, ## args)
#else
#define TX_DBG(fmt, args...) do { } while (0)
@@ -428,8 +428,7 @@ static int stmmac_init_phy(struct net_device *dev)
priv->plat->phy_addr);
pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt);
- phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, 0,
- interface);
+ phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface);
if (IS_ERR(phydev)) {
pr_err("%s: Could not attach to PHY\n", dev->name);
@@ -531,17 +530,18 @@ static void init_dma_desc_rings(struct net_device *dev)
DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
txsize, rxsize, bfsize);
- priv->rx_skbuff_dma = kmalloc(rxsize * sizeof(dma_addr_t), GFP_KERNEL);
- priv->rx_skbuff =
- kmalloc(sizeof(struct sk_buff *) * rxsize, GFP_KERNEL);
+ priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t),
+ GFP_KERNEL);
+ priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *),
+ GFP_KERNEL);
priv->dma_rx =
(struct dma_desc *)dma_alloc_coherent(priv->device,
rxsize *
sizeof(struct dma_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
- priv->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * txsize,
- GFP_KERNEL);
+ priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
+ GFP_KERNEL);
priv->dma_tx =
(struct dma_desc *)dma_alloc_coherent(priv->device,
txsize *
@@ -2254,7 +2254,7 @@ static int __init stmmac_cmdline_opt(char *str)
} else if (!strncmp(opt, "pause:", 6)) {
if (kstrtoint(opt + 6, 0, &pause))
goto err;
- } else if (!strncmp(opt, "eee_timer:", 6)) {
+ } else if (!strncmp(opt, "eee_timer:", 10)) {
if (kstrtoint(opt + 10, 0, &eee_timer))
goto err;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 0376a5e6b2bf..0b9829fe3eea 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -188,8 +188,6 @@ int stmmac_mdio_register(struct net_device *ndev)
goto bus_register_fail;
}
- priv->mii = new_bus;
-
found = 0;
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
struct phy_device *phydev = new_bus->phy_map[addr];
@@ -237,8 +235,14 @@ int stmmac_mdio_register(struct net_device *ndev)
}
}
- if (!found)
+ if (!found) {
pr_warning("%s: No PHY found\n", ndev->name);
+ mdiobus_unregister(new_bus);
+ mdiobus_free(new_bus);
+ return -ENODEV;
+ }
+
+ priv->mii = new_bus;
return 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 064eaac9616f..19b3a2567a46 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -102,6 +102,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr);
if (!priv) {
pr_err("%s: main driver probe failed", __func__);
+ ret = -ENODEV;
goto err_out;
}
priv->dev->irq = pdev->irq;
diff --git a/drivers/net/ethernet/sun/Kconfig b/drivers/net/ethernet/sun/Kconfig
index 57bfd8599679..3074aa374c6b 100644
--- a/drivers/net/ethernet/sun/Kconfig
+++ b/drivers/net/ethernet/sun/Kconfig
@@ -32,8 +32,8 @@ config HAPPYMEAL
will be called sunhme.
config SUNBMAC
- tristate "Sun BigMAC 10/100baseT support (EXPERIMENTAL)"
- depends on SBUS && EXPERIMENTAL
+ tristate "Sun BigMAC 10/100baseT support"
+ depends on SBUS
select CRC32
---help---
This driver supports the "be" interface available as an Sbus option.
@@ -61,7 +61,7 @@ config SUNGEM
select SUNGEM_PHY
---help---
Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also
- <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
+ <http://docs.oracle.com/cd/E19455-01/806-3985-10/806-3985-10.pdf>.
config CASSINI
tristate "Sun Cassini support"
@@ -69,7 +69,7 @@ config CASSINI
select CRC32
---help---
Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
- <http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf>
+ <http://docs.oracle.com/cd/E19113-01/giga.ether.pci/817-4341-10/817-4341-10.pdf>.
config SUNVNET
tristate "Sun Virtual Network support"
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index a0bdf0779466..e4c1c88e4c2a 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -4342,7 +4342,7 @@ static int niu_alloc_rx_ring_info(struct niu *np,
{
BUILD_BUG_ON(sizeof(struct rxdma_mailbox) != 64);
- rp->rxhash = kzalloc(MAX_RBR_RING_SIZE * sizeof(struct page *),
+ rp->rxhash = kcalloc(MAX_RBR_RING_SIZE, sizeof(struct page *),
GFP_KERNEL);
if (!rp->rxhash)
return -ENOMEM;
@@ -8366,14 +8366,12 @@ static void niu_pci_vpd_validate(struct niu *np)
return;
}
- memcpy(dev->perm_addr, vpd->local_mac, ETH_ALEN);
+ memcpy(dev->dev_addr, vpd->local_mac, ETH_ALEN);
- val8 = dev->perm_addr[5];
- dev->perm_addr[5] += np->port;
- if (dev->perm_addr[5] < val8)
- dev->perm_addr[4]++;
-
- memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+ val8 = dev->dev_addr[5];
+ dev->dev_addr[5] += np->port;
+ if (dev->dev_addr[5] < val8)
+ dev->dev_addr[4]++;
}
static int niu_pci_probe_sprom(struct niu *np)
@@ -8470,29 +8468,27 @@ static int niu_pci_probe_sprom(struct niu *np)
val = nr64(ESPC_MAC_ADDR0);
netif_printk(np, probe, KERN_DEBUG, np->dev,
"SPROM: MAC_ADDR0[%08llx]\n", (unsigned long long)val);
- dev->perm_addr[0] = (val >> 0) & 0xff;
- dev->perm_addr[1] = (val >> 8) & 0xff;
- dev->perm_addr[2] = (val >> 16) & 0xff;
- dev->perm_addr[3] = (val >> 24) & 0xff;
+ dev->dev_addr[0] = (val >> 0) & 0xff;
+ dev->dev_addr[1] = (val >> 8) & 0xff;
+ dev->dev_addr[2] = (val >> 16) & 0xff;
+ dev->dev_addr[3] = (val >> 24) & 0xff;
val = nr64(ESPC_MAC_ADDR1);
netif_printk(np, probe, KERN_DEBUG, np->dev,
"SPROM: MAC_ADDR1[%08llx]\n", (unsigned long long)val);
- dev->perm_addr[4] = (val >> 0) & 0xff;
- dev->perm_addr[5] = (val >> 8) & 0xff;
+ dev->dev_addr[4] = (val >> 0) & 0xff;
+ dev->dev_addr[5] = (val >> 8) & 0xff;
- if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+ if (!is_valid_ether_addr(&dev->dev_addr[0])) {
dev_err(np->device, "SPROM MAC address invalid [ %pM ]\n",
- dev->perm_addr);
+ dev->dev_addr);
return -EINVAL;
}
- val8 = dev->perm_addr[5];
- dev->perm_addr[5] += np->port;
- if (dev->perm_addr[5] < val8)
- dev->perm_addr[4]++;
-
- memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+ val8 = dev->dev_addr[5];
+ dev->dev_addr[5] += np->port;
+ if (dev->dev_addr[5] < val8)
+ dev->dev_addr[4]++;
val = nr64(ESPC_MOD_STR_LEN);
netif_printk(np, probe, KERN_DEBUG, np->dev,
@@ -9267,16 +9263,14 @@ static int niu_get_of_props(struct niu *np)
netdev_err(dev, "%s: OF MAC address prop len (%d) is wrong\n",
dp->full_name, prop_len);
}
- memcpy(dev->perm_addr, mac_addr, dev->addr_len);
- if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+ memcpy(dev->dev_addr, mac_addr, dev->addr_len);
+ if (!is_valid_ether_addr(&dev->dev_addr[0])) {
netdev_err(dev, "%s: OF MAC address is invalid\n",
dp->full_name);
- netdev_err(dev, "%s: [ %pM ]\n", dp->full_name, dev->perm_addr);
+ netdev_err(dev, "%s: [ %pM ]\n", dp->full_name, dev->dev_addr);
return -EINVAL;
}
- memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
-
model = of_get_property(dp, "model", &prop_len);
if (model)
diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c
index be82f6d13c51..5fafca065305 100644
--- a/drivers/net/ethernet/sun/sunbmac.c
+++ b/drivers/net/ethernet/sun/sunbmac.c
@@ -1042,8 +1042,8 @@ static void bigmac_set_multicast(struct net_device *dev)
/* Ethtool support... */
static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strcpy(info->driver, "sunbmac");
- strcpy(info->version, "2.0");
+ strlcpy(info->driver, "sunbmac", sizeof(info->driver));
+ strlcpy(info->version, "2.0", sizeof(info->version));
}
static u32 bigmac_get_link(struct net_device *dev)
diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c
index 1dcee6915843..49bf3e2eb652 100644
--- a/drivers/net/ethernet/sun/sunqe.c
+++ b/drivers/net/ethernet/sun/sunqe.c
@@ -685,13 +685,14 @@ static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
struct sunqe *qep = netdev_priv(dev);
struct platform_device *op;
- strcpy(info->driver, "sunqe");
- strcpy(info->version, "3.0");
+ strlcpy(info->driver, "sunqe", sizeof(info->driver));
+ strlcpy(info->version, "3.0", sizeof(info->version));
op = qep->op;
regs = of_get_property(op->dev.of_node, "reg", NULL);
if (regs)
- sprintf(info->bus_info, "SBUS:%d", regs->which_io);
+ snprintf(info->bus_info, sizeof(info->bus_info), "SBUS:%d",
+ regs->which_io);
}
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index e1b895530827..289b4eefb42f 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -882,8 +882,8 @@ static int vnet_set_mac_addr(struct net_device *dev, void *p)
static void vnet_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, DRV_MODULE_NAME);
- strcpy(info->version, DRV_MODULE_VERSION);
+ strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
}
static u32 vnet_get_msglevel(struct net_device *dev)
@@ -1032,8 +1032,6 @@ static struct vnet *vnet_new(const u64 *local_mac)
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
vp = netdev_priv(dev);
spin_lock_init(&vp->lock);
diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c
index 1e4d743ff03e..e15cc71b826d 100644
--- a/drivers/net/ethernet/tehuti/tehuti.c
+++ b/drivers/net/ethernet/tehuti/tehuti.c
@@ -2179,10 +2179,10 @@ bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
{
struct bdx_priv *priv = netdev_priv(netdev);
- strlcat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver));
- strlcat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version));
- strlcat(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
- strlcat(drvinfo->bus_info, pci_name(priv->pdev),
+ strlcpy(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version));
+ strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strlcpy(drvinfo->bus_info, pci_name(priv->pdev),
sizeof(drvinfo->bus_info));
drvinfo->n_stats = ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0);
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index 4426151d4ac9..de71b1ec4625 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -88,8 +88,8 @@ config TLAN
Please email feedback to <torben.mathiasen@compaq.com>.
config CPMAC
- tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && AR7
+ tristate "TI AR7 CPMAC Ethernet support"
+ depends on AR7
select PHYLIB
---help---
TI AR7 CPMAC Ethernet support
diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c
index d9625f62b026..31bbbca341a7 100644
--- a/drivers/net/ethernet/ti/cpmac.c
+++ b/drivers/net/ethernet/ti/cpmac.c
@@ -904,10 +904,9 @@ static int cpmac_set_ringparam(struct net_device *dev,
static void cpmac_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, "cpmac");
- strcpy(info->version, CPMAC_VERSION);
- info->fw_version[0] = '\0';
- sprintf(info->bus_info, "%s", "cpmac");
+ strlcpy(info->driver, "cpmac", sizeof(info->driver));
+ strlcpy(info->version, CPMAC_VERSION, sizeof(info->version));
+ snprintf(info->bus_info, sizeof(info->bus_info), "%s", "cpmac");
info->regdump_len = 0;
}
@@ -1173,8 +1172,8 @@ static int cpmac_probe(struct platform_device *pdev)
snprintf(priv->phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT,
mdio_bus_id, phy_id);
- priv->phy = phy_connect(dev, priv->phy_name, cpmac_adjust_link, 0,
- PHY_INTERFACE_MODE_MII);
+ priv->phy = phy_connect(dev, priv->phy_name, cpmac_adjust_link,
+ PHY_INTERFACE_MODE_MII);
if (IS_ERR(priv->phy)) {
if (netif_msg_drv(priv))
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 40aff684aa23..7e93df6585e7 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -32,6 +32,7 @@
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/of_device.h>
+#include <linux/if_vlan.h>
#include <linux/platform_data/cpsw.h>
@@ -118,6 +119,13 @@ do { \
#define TX_PRIORITY_MAPPING 0x33221100
#define CPDMA_TX_PRIORITY_MAP 0x76543210
+#define CPSW_VLAN_AWARE BIT(1)
+#define CPSW_ALE_VLAN_AWARE 1
+
+#define CPSW_FIFO_NORMAL_MODE (0 << 15)
+#define CPSW_FIFO_DUAL_MAC_MODE (1 << 15)
+#define CPSW_FIFO_RATE_LIMIT_MODE (2 << 15)
+
#define cpsw_enable_irq(priv) \
do { \
u32 i; \
@@ -250,7 +258,7 @@ struct cpsw_ss_regs {
struct cpsw_host_regs {
u32 max_blks;
u32 blk_cnt;
- u32 flow_thresh;
+ u32 tx_in_ctl;
u32 port_vlan;
u32 tx_pri_map;
u32 cpdma_tx_pri_map;
@@ -277,6 +285,9 @@ struct cpsw_slave {
u32 mac_control;
struct cpsw_slave_data *data;
struct phy_device *phy;
+ struct net_device *ndev;
+ u32 port_vlan;
+ u32 open_stat;
};
static inline u32 slave_read(struct cpsw_slave *slave, u32 offset)
@@ -315,17 +326,65 @@ struct cpsw_priv {
/* snapshot of IRQ numbers */
u32 irqs_table[4];
u32 num_irqs;
- struct cpts cpts;
+ struct cpts *cpts;
+ u32 emac_port;
};
#define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi)
-#define for_each_slave(priv, func, arg...) \
- do { \
- int idx; \
- for (idx = 0; idx < (priv)->data.slaves; idx++) \
- (func)((priv)->slaves + idx, ##arg); \
+#define for_each_slave(priv, func, arg...) \
+ do { \
+ int idx; \
+ if (priv->data.dual_emac) \
+ (func)((priv)->slaves + priv->emac_port, ##arg);\
+ else \
+ for (idx = 0; idx < (priv)->data.slaves; idx++) \
+ (func)((priv)->slaves + idx, ##arg); \
+ } while (0)
+#define cpsw_get_slave_ndev(priv, __slave_no__) \
+ (priv->slaves[__slave_no__].ndev)
+#define cpsw_get_slave_priv(priv, __slave_no__) \
+ ((priv->slaves[__slave_no__].ndev) ? \
+ netdev_priv(priv->slaves[__slave_no__].ndev) : NULL) \
+
+#define cpsw_dual_emac_src_port_detect(status, priv, ndev, skb) \
+ do { \
+ if (!priv->data.dual_emac) \
+ break; \
+ if (CPDMA_RX_SOURCE_PORT(status) == 1) { \
+ ndev = cpsw_get_slave_ndev(priv, 0); \
+ priv = netdev_priv(ndev); \
+ skb->dev = ndev; \
+ } else if (CPDMA_RX_SOURCE_PORT(status) == 2) { \
+ ndev = cpsw_get_slave_ndev(priv, 1); \
+ priv = netdev_priv(ndev); \
+ skb->dev = ndev; \
+ } \
+ } while (0)
+#define cpsw_add_mcast(priv, addr) \
+ do { \
+ if (priv->data.dual_emac) { \
+ struct cpsw_slave *slave = priv->slaves + \
+ priv->emac_port; \
+ int slave_port = cpsw_get_slave_port(priv, \
+ slave->slave_num); \
+ cpsw_ale_add_mcast(priv->ale, addr, \
+ 1 << slave_port | 1 << priv->host_port, \
+ ALE_VLAN, slave->port_vlan, 0); \
+ } else { \
+ cpsw_ale_add_mcast(priv->ale, addr, \
+ ALE_ALL_PORTS << priv->host_port, \
+ 0, 0, 0); \
+ } \
} while (0)
+static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
+{
+ if (priv->host_port == 0)
+ return slave_num + 1;
+ else
+ return slave_num;
+}
+
static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
{
struct cpsw_priv *priv = netdev_priv(ndev);
@@ -344,8 +403,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
/* program multicast address list into ALE register */
netdev_for_each_mc_addr(ha, ndev) {
- cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr,
- ALE_ALL_PORTS << priv->host_port, 0, 0);
+ cpsw_add_mcast(priv, (u8 *)ha->addr);
}
}
}
@@ -374,9 +432,12 @@ void cpsw_tx_handler(void *token, int len, int status)
struct net_device *ndev = skb->dev;
struct cpsw_priv *priv = netdev_priv(ndev);
+ /* Check whether the queue is stopped due to stalled tx dma, if the
+ * queue is stopped then start the queue as we have free desc for tx
+ */
if (unlikely(netif_queue_stopped(ndev)))
netif_start_queue(ndev);
- cpts_tx_timestamp(&priv->cpts, skb);
+ cpts_tx_timestamp(priv->cpts, skb);
priv->stats.tx_packets++;
priv->stats.tx_bytes += len;
dev_kfree_skb_any(skb);
@@ -389,6 +450,8 @@ void cpsw_rx_handler(void *token, int len, int status)
struct cpsw_priv *priv = netdev_priv(ndev);
int ret = 0;
+ cpsw_dual_emac_src_port_detect(status, priv, ndev, skb);
+
/* free and bail if we are shutting down */
if (unlikely(!netif_running(ndev)) ||
unlikely(!netif_carrier_ok(ndev))) {
@@ -397,7 +460,7 @@ void cpsw_rx_handler(void *token, int len, int status)
}
if (likely(status >= 0)) {
skb_put(skb, len);
- cpts_rx_timestamp(&priv->cpts, skb);
+ cpts_rx_timestamp(priv->cpts, skb);
skb->protocol = eth_type_trans(skb, ndev);
netif_receive_skb(skb);
priv->stats.rx_bytes += len;
@@ -417,7 +480,7 @@ void cpsw_rx_handler(void *token, int len, int status)
return;
ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
- skb_tailroom(skb), GFP_KERNEL);
+ skb_tailroom(skb), 0, GFP_KERNEL);
}
WARN_ON(ret < 0);
}
@@ -430,37 +493,38 @@ static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
cpsw_intr_disable(priv);
cpsw_disable_irq(priv);
napi_schedule(&priv->napi);
+ } else {
+ priv = cpsw_get_slave_priv(priv, 1);
+ if (likely(priv) && likely(netif_running(priv->ndev))) {
+ cpsw_intr_disable(priv);
+ cpsw_disable_irq(priv);
+ napi_schedule(&priv->napi);
+ }
}
return IRQ_HANDLED;
}
-static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
-{
- if (priv->host_port == 0)
- return slave_num + 1;
- else
- return slave_num;
-}
-
static int cpsw_poll(struct napi_struct *napi, int budget)
{
struct cpsw_priv *priv = napi_to_priv(napi);
int num_tx, num_rx;
num_tx = cpdma_chan_process(priv->txch, 128);
- num_rx = cpdma_chan_process(priv->rxch, budget);
-
- if (num_rx || num_tx)
- cpsw_dbg(priv, intr, "poll %d rx, %d tx pkts\n",
- num_rx, num_tx);
+ if (num_tx)
+ cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
+ num_rx = cpdma_chan_process(priv->rxch, budget);
if (num_rx < budget) {
napi_complete(napi);
cpsw_intr_enable(priv);
- cpdma_ctlr_eoi(priv->dma);
+ cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
cpsw_enable_irq(priv);
}
+ if (num_rx || num_tx)
+ cpsw_dbg(priv, intr, "poll %d rx, %d tx pkts\n",
+ num_rx, num_tx);
+
return num_rx;
}
@@ -559,6 +623,54 @@ static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val)
leader + strlen(name), val);
}
+static int cpsw_common_res_usage_state(struct cpsw_priv *priv)
+{
+ u32 i;
+ u32 usage_count = 0;
+
+ if (!priv->data.dual_emac)
+ return 0;
+
+ for (i = 0; i < priv->data.slaves; i++)
+ if (priv->slaves[i].open_stat)
+ usage_count++;
+
+ return usage_count;
+}
+
+static inline int cpsw_tx_packet_submit(struct net_device *ndev,
+ struct cpsw_priv *priv, struct sk_buff *skb)
+{
+ if (!priv->data.dual_emac)
+ return cpdma_chan_submit(priv->txch, skb, skb->data,
+ skb->len, 0, GFP_KERNEL);
+
+ if (ndev == cpsw_get_slave_ndev(priv, 0))
+ return cpdma_chan_submit(priv->txch, skb, skb->data,
+ skb->len, 1, GFP_KERNEL);
+ else
+ return cpdma_chan_submit(priv->txch, skb, skb->data,
+ skb->len, 2, GFP_KERNEL);
+}
+
+static inline void cpsw_add_dual_emac_def_ale_entries(
+ struct cpsw_priv *priv, struct cpsw_slave *slave,
+ u32 slave_port)
+{
+ u32 port_mask = 1 << slave_port | 1 << priv->host_port;
+
+ if (priv->version == CPSW_VERSION_1)
+ slave_write(slave, slave->port_vlan, CPSW1_PORT_VLAN);
+ else
+ slave_write(slave, slave->port_vlan, CPSW2_PORT_VLAN);
+ cpsw_ale_add_vlan(priv->ale, slave->port_vlan, port_mask,
+ port_mask, port_mask, 0);
+ cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+ port_mask, ALE_VLAN, slave->port_vlan, 0);
+ cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
+ priv->host_port, ALE_VLAN, slave->port_vlan);
+}
+
static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
{
char name[32];
@@ -588,11 +700,14 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
slave_port = cpsw_get_slave_port(priv, slave->slave_num);
- cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
- 1 << slave_port, 0, ALE_MCAST_FWD_2);
+ if (priv->data.dual_emac)
+ cpsw_add_dual_emac_def_ale_entries(priv, slave, slave_port);
+ else
+ cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+ 1 << slave_port, 0, 0, ALE_MCAST_FWD_2);
slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
- &cpsw_adjust_link, 0, slave->data->phy_if);
+ &cpsw_adjust_link, slave->data->phy_if);
if (IS_ERR(slave->phy)) {
dev_err(priv->dev, "phy %s not found on slave %d\n",
slave->data->phy_id, slave->slave_num);
@@ -604,14 +719,44 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
}
}
+static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
+{
+ const int vlan = priv->data.default_vlan;
+ const int port = priv->host_port;
+ u32 reg;
+ int i;
+
+ reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN :
+ CPSW2_PORT_VLAN;
+
+ writel(vlan, &priv->host_port_regs->port_vlan);
+
+ for (i = 0; i < 2; i++)
+ slave_write(priv->slaves + i, vlan, reg);
+
+ cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port,
+ ALE_ALL_PORTS << port, ALE_ALL_PORTS << port,
+ (ALE_PORT_1 | ALE_PORT_2) << port);
+}
+
static void cpsw_init_host_port(struct cpsw_priv *priv)
{
+ u32 control_reg;
+ u32 fifo_mode;
+
/* soft reset the controller and initialize ale */
soft_reset("cpsw", &priv->regs->soft_reset);
cpsw_ale_start(priv->ale);
/* switch to vlan unaware mode */
- cpsw_ale_control_set(priv->ale, 0, ALE_VLAN_AWARE, 0);
+ cpsw_ale_control_set(priv->ale, priv->host_port, ALE_VLAN_AWARE,
+ CPSW_ALE_VLAN_AWARE);
+ control_reg = readl(&priv->regs->control);
+ control_reg |= CPSW_VLAN_AWARE;
+ writel(control_reg, &priv->regs->control);
+ fifo_mode = (priv->data.dual_emac) ? CPSW_FIFO_DUAL_MAC_MODE :
+ CPSW_FIFO_NORMAL_MODE;
+ writel(fifo_mode, &priv->host_port_regs->tx_in_ctl);
/* setup host port priority mapping */
__raw_writel(CPDMA_TX_PRIORITY_MAP,
@@ -621,9 +766,12 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
cpsw_ale_control_set(priv->ale, priv->host_port,
ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
- cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0);
- cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
- 1 << priv->host_port, 0, ALE_MCAST_FWD_2);
+ if (!priv->data.dual_emac) {
+ cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port,
+ 0, 0);
+ cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+ 1 << priv->host_port, 0, 0, ALE_MCAST_FWD_2);
+ }
}
static int cpsw_ndo_open(struct net_device *ndev)
@@ -632,7 +780,8 @@ static int cpsw_ndo_open(struct net_device *ndev)
int i, ret;
u32 reg;
- cpsw_intr_disable(priv);
+ if (!cpsw_common_res_usage_state(priv))
+ cpsw_intr_disable(priv);
netif_carrier_off(ndev);
pm_runtime_get_sync(&priv->pdev->dev);
@@ -644,43 +793,55 @@ static int cpsw_ndo_open(struct net_device *ndev)
CPSW_RTL_VERSION(reg));
/* initialize host and slave ports */
- cpsw_init_host_port(priv);
+ if (!cpsw_common_res_usage_state(priv))
+ cpsw_init_host_port(priv);
for_each_slave(priv, cpsw_slave_open, priv);
- /* setup tx dma to fixed prio and zero offset */
- cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);
- cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);
+ /* Add default VLAN */
+ if (!priv->data.dual_emac)
+ cpsw_add_default_vlan(priv);
- /* disable priority elevation and enable statistics on all ports */
- __raw_writel(0, &priv->regs->ptype);
+ if (!cpsw_common_res_usage_state(priv)) {
+ /* setup tx dma to fixed prio and zero offset */
+ cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);
+ cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);
- /* enable statistics collection only on the host port */
- __raw_writel(0x7, &priv->regs->stat_port_en);
+ /* disable priority elevation */
+ __raw_writel(0, &priv->regs->ptype);
- if (WARN_ON(!priv->data.rx_descs))
- priv->data.rx_descs = 128;
+ /* enable statistics collection only on all ports */
+ __raw_writel(0x7, &priv->regs->stat_port_en);
- for (i = 0; i < priv->data.rx_descs; i++) {
- struct sk_buff *skb;
+ if (WARN_ON(!priv->data.rx_descs))
+ priv->data.rx_descs = 128;
- ret = -ENOMEM;
- skb = netdev_alloc_skb_ip_align(priv->ndev,
- priv->rx_packet_max);
- if (!skb)
- break;
- ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
- skb_tailroom(skb), GFP_KERNEL);
- if (WARN_ON(ret < 0))
- break;
+ for (i = 0; i < priv->data.rx_descs; i++) {
+ struct sk_buff *skb;
+
+ ret = -ENOMEM;
+ skb = netdev_alloc_skb_ip_align(priv->ndev,
+ priv->rx_packet_max);
+ if (!skb)
+ break;
+ ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
+ skb_tailroom(skb), 0, GFP_KERNEL);
+ if (WARN_ON(ret < 0))
+ break;
+ }
+ /* continue even if we didn't manage to submit all
+ * receive descs
+ */
+ cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);
}
- /* continue even if we didn't manage to submit all receive descs */
- cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);
cpdma_ctlr_start(priv->dma);
cpsw_intr_enable(priv);
napi_enable(&priv->napi);
- cpdma_ctlr_eoi(priv->dma);
+ cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+ cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
+ if (priv->data.dual_emac)
+ priv->slaves[priv->emac_port].open_stat = true;
return 0;
}
@@ -701,12 +862,17 @@ static int cpsw_ndo_stop(struct net_device *ndev)
netif_stop_queue(priv->ndev);
napi_disable(&priv->napi);
netif_carrier_off(priv->ndev);
- cpsw_intr_disable(priv);
- cpdma_ctlr_int_ctrl(priv->dma, false);
- cpdma_ctlr_stop(priv->dma);
- cpsw_ale_stop(priv->ale);
+
+ if (cpsw_common_res_usage_state(priv) <= 1) {
+ cpsw_intr_disable(priv);
+ cpdma_ctlr_int_ctrl(priv->dma, false);
+ cpdma_ctlr_stop(priv->dma);
+ cpsw_ale_stop(priv->ale);
+ }
for_each_slave(priv, cpsw_slave_stop, priv);
pm_runtime_put_sync(&priv->pdev->dev);
+ if (priv->data.dual_emac)
+ priv->slaves[priv->emac_port].open_stat = false;
return 0;
}
@@ -724,18 +890,24 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
- if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && priv->cpts.tx_enable)
+ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+ priv->cpts->tx_enable)
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
skb_tx_timestamp(skb);
- ret = cpdma_chan_submit(priv->txch, skb, skb->data,
- skb->len, GFP_KERNEL);
+ ret = cpsw_tx_packet_submit(ndev, priv, skb);
if (unlikely(ret != 0)) {
cpsw_err(priv, tx_err, "desc submit failed\n");
goto fail;
}
+ /* If there is no more tx desc left free then we need to
+ * tell the kernel to stop sending us tx frames.
+ */
+ if (unlikely(cpdma_check_free_tx_desc(priv->txch)))
+ netif_stop_queue(ndev);
+
return NETDEV_TX_OK;
fail:
priv->stats.tx_dropped++;
@@ -773,7 +945,7 @@ static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)
struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave];
u32 ts_en, seq_id;
- if (!priv->cpts.tx_enable && !priv->cpts.rx_enable) {
+ if (!priv->cpts->tx_enable && !priv->cpts->rx_enable) {
slave_write(slave, 0, CPSW1_TS_CTL);
return;
}
@@ -781,10 +953,10 @@ static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)
seq_id = (30 << CPSW_V1_SEQ_ID_OFS_SHIFT) | ETH_P_1588;
ts_en = EVENT_MSG_BITS << CPSW_V1_MSG_TYPE_OFS;
- if (priv->cpts.tx_enable)
+ if (priv->cpts->tx_enable)
ts_en |= CPSW_V1_TS_TX_EN;
- if (priv->cpts.rx_enable)
+ if (priv->cpts->rx_enable)
ts_en |= CPSW_V1_TS_RX_EN;
slave_write(slave, ts_en, CPSW1_TS_CTL);
@@ -793,16 +965,21 @@ static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)
static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
{
- struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave];
+ struct cpsw_slave *slave;
u32 ctrl, mtype;
+ if (priv->data.dual_emac)
+ slave = &priv->slaves[priv->emac_port];
+ else
+ slave = &priv->slaves[priv->data.cpts_active_slave];
+
ctrl = slave_read(slave, CPSW2_CONTROL);
ctrl &= ~CTRL_ALL_TS_MASK;
- if (priv->cpts.tx_enable)
+ if (priv->cpts->tx_enable)
ctrl |= CTRL_TX_TS_BITS;
- if (priv->cpts.rx_enable)
+ if (priv->cpts->rx_enable)
ctrl |= CTRL_RX_TS_BITS;
mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS;
@@ -815,7 +992,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
{
struct cpsw_priv *priv = netdev_priv(dev);
- struct cpts *cpts = &priv->cpts;
+ struct cpts *cpts = priv->cpts;
struct hwtstamp_config cfg;
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
@@ -901,7 +1078,9 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)
cpdma_chan_start(priv->txch);
cpdma_ctlr_int_ctrl(priv->dma, true);
cpsw_intr_enable(priv);
- cpdma_ctlr_eoi(priv->dma);
+ cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+ cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
+
}
static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev)
@@ -920,10 +1099,79 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
cpsw_interrupt(ndev->irq, priv);
cpdma_ctlr_int_ctrl(priv->dma, true);
cpsw_intr_enable(priv);
- cpdma_ctlr_eoi(priv->dma);
+ cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+ cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
+
}
#endif
+static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
+ unsigned short vid)
+{
+ int ret;
+
+ ret = cpsw_ale_add_vlan(priv->ale, vid,
+ ALE_ALL_PORTS << priv->host_port,
+ 0, ALE_ALL_PORTS << priv->host_port,
+ (ALE_PORT_1 | ALE_PORT_2) << priv->host_port);
+ if (ret != 0)
+ return ret;
+
+ ret = cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
+ priv->host_port, ALE_VLAN, vid);
+ if (ret != 0)
+ goto clean_vid;
+
+ ret = cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+ ALE_ALL_PORTS << priv->host_port,
+ ALE_VLAN, vid, 0);
+ if (ret != 0)
+ goto clean_vlan_ucast;
+ return 0;
+
+clean_vlan_ucast:
+ cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
+ priv->host_port, ALE_VLAN, vid);
+clean_vid:
+ cpsw_ale_del_vlan(priv->ale, vid, 0);
+ return ret;
+}
+
+static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
+ unsigned short vid)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+
+ if (vid == priv->data.default_vlan)
+ return 0;
+
+ dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
+ return cpsw_add_vlan_ale_entry(priv, vid);
+}
+
+static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
+ unsigned short vid)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ if (vid == priv->data.default_vlan)
+ return 0;
+
+ dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
+ ret = cpsw_ale_del_vlan(priv->ale, vid, 0);
+ if (ret != 0)
+ return ret;
+
+ ret = cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
+ priv->host_port, ALE_VLAN, vid);
+ if (ret != 0)
+ return ret;
+
+ return cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast,
+ 0, ALE_VLAN, vid);
+}
+
static const struct net_device_ops cpsw_netdev_ops = {
.ndo_open = cpsw_ndo_open,
.ndo_stop = cpsw_ndo_stop,
@@ -938,15 +1186,18 @@ static const struct net_device_ops cpsw_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = cpsw_ndo_poll_controller,
#endif
+ .ndo_vlan_rx_add_vid = cpsw_ndo_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = cpsw_ndo_vlan_rx_kill_vid,
};
static void cpsw_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *info)
{
struct cpsw_priv *priv = netdev_priv(ndev);
- strcpy(info->driver, "TI CPSW Driver v1.0");
- strcpy(info->version, "1.0");
- strcpy(info->bus_info, priv->pdev->name);
+
+ strlcpy(info->driver, "TI CPSW Driver v1.0", sizeof(info->driver));
+ strlcpy(info->version, "1.0", sizeof(info->version));
+ strlcpy(info->bus_info, priv->pdev->name, sizeof(info->bus_info));
}
static u32 cpsw_get_msglevel(struct net_device *ndev)
@@ -974,7 +1225,7 @@ static int cpsw_get_ts_info(struct net_device *ndev,
SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
- info->phc_index = priv->cpts.phc_index;
+ info->phc_index = priv->cpts->phc_index;
info->tx_types =
(1 << HWTSTAMP_TX_OFF) |
(1 << HWTSTAMP_TX_ON);
@@ -1011,6 +1262,7 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
slave->data = data;
slave->regs = regs + slave_reg_ofs;
slave->sliver = regs + sliver_reg_ofs;
+ slave->port_vlan = data->dual_emac_res_vlan;
}
static int cpsw_probe_dt(struct cpsw_platform_data *data,
@@ -1051,12 +1303,10 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
}
data->cpts_clock_shift = prop;
- data->slave_data = kzalloc(sizeof(struct cpsw_slave_data) *
- data->slaves, GFP_KERNEL);
- if (!data->slave_data) {
- pr_err("Could not allocate slave memory.\n");
+ data->slave_data = kcalloc(data->slaves, sizeof(struct cpsw_slave_data),
+ GFP_KERNEL);
+ if (!data->slave_data)
return -EINVAL;
- }
if (of_property_read_u32(node, "cpdma_channels", &prop)) {
pr_err("Missing cpdma_channels property in the DT.\n");
@@ -1093,6 +1343,9 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
}
data->mac_control = prop;
+ if (!of_property_read_u32(node, "dual_emac", &prop))
+ data->dual_emac = prop;
+
/*
* Populate all the child nodes here...
*/
@@ -1126,6 +1379,18 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
if (mac_addr)
memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
+ if (data->dual_emac) {
+ if (of_property_read_u32(node, "dual_emac_res_vlan",
+ &prop)) {
+ pr_err("Missing dual_emac_res_vlan in DT.\n");
+ slave_data->dual_emac_res_vlan = i+1;
+ pr_err("Using %d as Reserved VLAN for %d slave\n",
+ slave_data->dual_emac_res_vlan, i);
+ } else {
+ slave_data->dual_emac_res_vlan = prop;
+ }
+ }
+
i++;
}
@@ -1136,6 +1401,79 @@ error_ret:
return ret;
}
+static int cpsw_probe_dual_emac(struct platform_device *pdev,
+ struct cpsw_priv *priv)
+{
+ struct cpsw_platform_data *data = &priv->data;
+ struct net_device *ndev;
+ struct cpsw_priv *priv_sl2;
+ int ret = 0, i;
+
+ ndev = alloc_etherdev(sizeof(struct cpsw_priv));
+ if (!ndev) {
+ pr_err("cpsw: error allocating net_device\n");
+ return -ENOMEM;
+ }
+
+ priv_sl2 = netdev_priv(ndev);
+ spin_lock_init(&priv_sl2->lock);
+ priv_sl2->data = *data;
+ priv_sl2->pdev = pdev;
+ priv_sl2->ndev = ndev;
+ priv_sl2->dev = &ndev->dev;
+ priv_sl2->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
+ priv_sl2->rx_packet_max = max(rx_packet_max, 128);
+
+ if (is_valid_ether_addr(data->slave_data[1].mac_addr)) {
+ memcpy(priv_sl2->mac_addr, data->slave_data[1].mac_addr,
+ ETH_ALEN);
+ pr_info("cpsw: Detected MACID = %pM\n", priv_sl2->mac_addr);
+ } else {
+ random_ether_addr(priv_sl2->mac_addr);
+ pr_info("cpsw: Random MACID = %pM\n", priv_sl2->mac_addr);
+ }
+ memcpy(ndev->dev_addr, priv_sl2->mac_addr, ETH_ALEN);
+
+ priv_sl2->slaves = priv->slaves;
+ priv_sl2->clk = priv->clk;
+
+ priv_sl2->cpsw_res = priv->cpsw_res;
+ priv_sl2->regs = priv->regs;
+ priv_sl2->host_port = priv->host_port;
+ priv_sl2->host_port_regs = priv->host_port_regs;
+ priv_sl2->wr_regs = priv->wr_regs;
+ priv_sl2->dma = priv->dma;
+ priv_sl2->txch = priv->txch;
+ priv_sl2->rxch = priv->rxch;
+ priv_sl2->ale = priv->ale;
+ priv_sl2->emac_port = 1;
+ priv->slaves[1].ndev = ndev;
+ priv_sl2->cpts = priv->cpts;
+ priv_sl2->version = priv->version;
+
+ for (i = 0; i < priv->num_irqs; i++) {
+ priv_sl2->irqs_table[i] = priv->irqs_table[i];
+ priv_sl2->num_irqs = priv->num_irqs;
+ }
+
+ ndev->features |= NETIF_F_HW_VLAN_FILTER;
+
+ ndev->netdev_ops = &cpsw_netdev_ops;
+ SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops);
+ netif_napi_add(ndev, &priv_sl2->napi, cpsw_poll, CPSW_POLL_WEIGHT);
+
+ /* register the network device */
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ ret = register_netdev(ndev);
+ if (ret) {
+ pr_err("cpsw: error registering net device\n");
+ free_netdev(ndev);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
static int cpsw_probe(struct platform_device *pdev)
{
struct cpsw_platform_data *data = pdev->dev.platform_data;
@@ -1162,6 +1500,11 @@ static int cpsw_probe(struct platform_device *pdev)
priv->dev = &ndev->dev;
priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
priv->rx_packet_max = max(rx_packet_max, 128);
+ priv->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL);
+ if (!ndev) {
+ pr_err("error allocating cpts\n");
+ goto clean_ndev_ret;
+ }
/*
* This may be required here for child devices.
@@ -1194,6 +1537,9 @@ static int cpsw_probe(struct platform_device *pdev)
for (i = 0; i < data->slaves; i++)
priv->slaves[i].slave_num = i;
+ priv->slaves[0].ndev = ndev;
+ priv->emac_port = 0;
+
priv->clk = clk_get(&pdev->dev, "fck");
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "fck is not found\n");
@@ -1248,7 +1594,7 @@ static int cpsw_probe(struct platform_device *pdev)
switch (priv->version) {
case CPSW_VERSION_1:
priv->host_port_regs = ss_regs + CPSW1_HOST_PORT_OFFSET;
- priv->cpts.reg = ss_regs + CPSW1_CPTS_OFFSET;
+ priv->cpts->reg = ss_regs + CPSW1_CPTS_OFFSET;
dma_params.dmaregs = ss_regs + CPSW1_CPDMA_OFFSET;
dma_params.txhdp = ss_regs + CPSW1_STATERAM_OFFSET;
ale_params.ale_regs = ss_regs + CPSW1_ALE_OFFSET;
@@ -1259,7 +1605,7 @@ static int cpsw_probe(struct platform_device *pdev)
break;
case CPSW_VERSION_2:
priv->host_port_regs = ss_regs + CPSW2_HOST_PORT_OFFSET;
- priv->cpts.reg = ss_regs + CPSW2_CPTS_OFFSET;
+ priv->cpts->reg = ss_regs + CPSW2_CPTS_OFFSET;
dma_params.dmaregs = ss_regs + CPSW2_CPDMA_OFFSET;
dma_params.txhdp = ss_regs + CPSW2_STATERAM_OFFSET;
ale_params.ale_regs = ss_regs + CPSW2_ALE_OFFSET;
@@ -1346,7 +1692,7 @@ static int cpsw_probe(struct platform_device *pdev)
k++;
}
- ndev->flags |= IFF_ALLMULTI; /* see cpsw_ndo_change_rx_flags() */
+ ndev->features |= NETIF_F_HW_VLAN_FILTER;
ndev->netdev_ops = &cpsw_netdev_ops;
SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops);
@@ -1361,13 +1707,21 @@ static int cpsw_probe(struct platform_device *pdev)
goto clean_irq_ret;
}
- if (cpts_register(&pdev->dev, &priv->cpts,
+ if (cpts_register(&pdev->dev, priv->cpts,
data->cpts_clock_mult, data->cpts_clock_shift))
dev_err(priv->dev, "error registering cpts device\n");
cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n",
priv->cpsw_res->start, ndev->irq);
+ if (priv->data.dual_emac) {
+ ret = cpsw_probe_dual_emac(pdev, priv);
+ if (ret) {
+ cpsw_err(priv, probe, "error probe slave 2 emac interface\n");
+ goto clean_irq_ret;
+ }
+ }
+
return 0;
clean_irq_ret:
@@ -1406,7 +1760,7 @@ static int cpsw_remove(struct platform_device *pdev)
pr_info("removing device");
platform_set_drvdata(pdev, NULL);
- cpts_unregister(&priv->cpts);
+ cpts_unregister(priv->cpts);
free_irq(ndev->irq, priv);
cpsw_ale_destroy(priv->ale);
cpdma_chan_destroy(priv->txch);
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 0e9ccc2cf91f..7fa60d6092ed 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -148,7 +148,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry)
return idx;
}
-static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
+int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS];
int type, idx;
@@ -160,6 +160,8 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
type = cpsw_ale_get_entry_type(ale_entry);
if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
continue;
+ if (cpsw_ale_get_vlan_id(ale_entry) != vid)
+ continue;
cpsw_ale_get_addr(ale_entry, entry_addr);
if (memcmp(entry_addr, addr, 6) == 0)
return idx;
@@ -167,6 +169,22 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
return -ENOENT;
}
+int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS];
+ int type, idx;
+
+ for (idx = 0; idx < ale->params.ale_entries; idx++) {
+ cpsw_ale_read(ale, idx, ale_entry);
+ type = cpsw_ale_get_entry_type(ale_entry);
+ if (type != ALE_TYPE_VLAN)
+ continue;
+ if (cpsw_ale_get_vlan_id(ale_entry) == vid)
+ return idx;
+ }
+ return -ENOENT;
+}
+
static int cpsw_ale_match_free(struct cpsw_ale *ale)
{
u32 ale_entry[ALE_ENTRY_WORDS];
@@ -274,19 +292,32 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
return 0;
}
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
+static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry,
+ int flags, u16 vid)
+{
+ if (flags & ALE_VLAN) {
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
+ cpsw_ale_set_vlan_id(ale_entry, vid);
+ } else {
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+ }
+}
+
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+ int flags, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx;
- cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+ cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);
+
cpsw_ale_set_addr(ale_entry, addr);
cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
cpsw_ale_set_port_num(ale_entry, port);
- idx = cpsw_ale_match_addr(ale, addr);
+ idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
if (idx < 0)
idx = cpsw_ale_match_free(ale);
if (idx < 0)
@@ -298,12 +329,13 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
return 0;
}
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port)
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+ int flags, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx;
- idx = cpsw_ale_match_addr(ale, addr);
+ idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
if (idx < 0)
return -ENOENT;
@@ -313,18 +345,19 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port)
}
int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
- int super, int mcast_state)
+ int flags, u16 vid, int mcast_state)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx, mask;
- idx = cpsw_ale_match_addr(ale, addr);
+ idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
if (idx >= 0)
cpsw_ale_read(ale, idx, ale_entry);
- cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+ cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);
+
cpsw_ale_set_addr(ale_entry, addr);
- cpsw_ale_set_super(ale_entry, super);
+ cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
cpsw_ale_set_mcast_state(ale_entry, mcast_state);
mask = cpsw_ale_get_port_mask(ale_entry);
@@ -342,12 +375,13 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
return 0;
}
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+ int flags, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx;
- idx = cpsw_ale_match_addr(ale, addr);
+ idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
if (idx < 0)
return -EINVAL;
@@ -362,6 +396,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
return 0;
}
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
+ int reg_mcast, int unreg_mcast)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+ int idx;
+
+ idx = cpsw_ale_match_vlan(ale, vid);
+ if (idx >= 0)
+ cpsw_ale_read(ale, idx, ale_entry);
+
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN);
+ cpsw_ale_set_vlan_id(ale_entry, vid);
+
+ cpsw_ale_set_vlan_untag_force(ale_entry, untag);
+ cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast);
+ cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
+ cpsw_ale_set_vlan_member_list(ale_entry, port);
+
+ if (idx < 0)
+ idx = cpsw_ale_match_free(ale);
+ if (idx < 0)
+ idx = cpsw_ale_find_ageable(ale);
+ if (idx < 0)
+ return -ENOMEM;
+
+ cpsw_ale_write(ale, idx, ale_entry);
+ return 0;
+}
+
+int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+ int idx;
+
+ idx = cpsw_ale_match_vlan(ale, vid);
+ if (idx < 0)
+ return -ENOENT;
+
+ cpsw_ale_read(ale, idx, ale_entry);
+
+ if (port_mask)
+ cpsw_ale_set_vlan_member_list(ale_entry, port_mask);
+ else
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
+
+ cpsw_ale_write(ale, idx, ale_entry);
+ return 0;
+}
+
struct ale_control_info {
const char *name;
int offset, port_offset;
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h
index 2bd09cbce522..30daa1265f0c 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.h
+++ b/drivers/net/ethernet/ti/cpsw_ale.h
@@ -64,8 +64,14 @@ enum cpsw_ale_port_state {
};
/* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */
-#define ALE_SECURE 1
-#define ALE_BLOCKED 2
+#define ALE_SECURE BIT(0)
+#define ALE_BLOCKED BIT(1)
+#define ALE_SUPER BIT(2)
+#define ALE_VLAN BIT(3)
+
+#define ALE_PORT_HOST BIT(0)
+#define ALE_PORT_1 BIT(1)
+#define ALE_PORT_2 BIT(2)
#define ALE_MCAST_FWD 0
#define ALE_MCAST_BLOCK_LEARN_FWD 1
@@ -81,11 +87,17 @@ void cpsw_ale_stop(struct cpsw_ale *ale);
int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout);
int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask);
int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask);
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags);
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port);
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+ int flags, u16 vid);
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+ int flags, u16 vid);
int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
- int super, int mcast_state);
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask);
+ int flags, u16 vid, int mcast_state);
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+ int flags, u16 vid);
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
+ int reg_mcast, int unreg_mcast);
+int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port);
int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control);
int cpsw_ale_control_set(struct cpsw_ale *ale, int port,
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index 49956730cd8d..ee13dc78430c 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -60,6 +60,9 @@
#define CPDMA_DESC_EOQ BIT(28)
#define CPDMA_DESC_TD_COMPLETE BIT(27)
#define CPDMA_DESC_PASS_CRC BIT(26)
+#define CPDMA_DESC_TO_PORT_EN BIT(20)
+#define CPDMA_TO_PORT_SHIFT 16
+#define CPDMA_DESC_PORT_MASK (BIT(18) | BIT(17) | BIT(16))
#define CPDMA_TEARDOWN_VALUE 0xfffffffc
@@ -105,13 +108,13 @@ struct cpdma_ctlr {
};
struct cpdma_chan {
+ struct cpdma_desc __iomem *head, *tail;
+ void __iomem *hdp, *cp, *rxfree;
enum cpdma_state state;
struct cpdma_ctlr *ctlr;
int chan_num;
spinlock_t lock;
- struct cpdma_desc __iomem *head, *tail;
int count;
- void __iomem *hdp, *cp, *rxfree;
u32 mask;
cpdma_handler_fn handler;
enum dma_data_direction dir;
@@ -132,6 +135,14 @@ struct cpdma_chan {
#define chan_write(chan, fld, v) __raw_writel(v, (chan)->fld)
#define desc_write(desc, fld, v) __raw_writel((u32)(v), &(desc)->fld)
+#define cpdma_desc_to_port(chan, mode, directed) \
+ do { \
+ if (!is_rx_chan(chan) && ((directed == 1) || \
+ (directed == 2))) \
+ mode |= (CPDMA_DESC_TO_PORT_EN | \
+ (directed << CPDMA_TO_PORT_SHIFT)); \
+ } while (0)
+
/*
* Utility constructs for a cpdma descriptor pool. Some devices (e.g. davinci
* emac) have dedicated on-chip memory for these descriptors. Some other
@@ -217,17 +228,27 @@ desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma)
}
static struct cpdma_desc __iomem *
-cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc)
+cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc, bool is_rx)
{
unsigned long flags;
int index;
+ int desc_start;
+ int desc_end;
struct cpdma_desc __iomem *desc = NULL;
spin_lock_irqsave(&pool->lock, flags);
- index = bitmap_find_next_zero_area(pool->bitmap, pool->num_desc, 0,
- num_desc, 0);
- if (index < pool->num_desc) {
+ if (is_rx) {
+ desc_start = 0;
+ desc_end = pool->num_desc/2;
+ } else {
+ desc_start = pool->num_desc/2;
+ desc_end = pool->num_desc;
+ }
+
+ index = bitmap_find_next_zero_area(pool->bitmap,
+ desc_end, desc_start, num_desc, 0);
+ if (index < desc_end) {
bitmap_set(pool->bitmap, index, num_desc);
desc = pool->iomap + pool->desc_size * index;
pool->used_desc++;
@@ -439,10 +460,8 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
if (ctlr->state != CPDMA_STATE_IDLE)
cpdma_ctlr_stop(ctlr);
- for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
- if (ctlr->channels[i])
- cpdma_chan_destroy(ctlr->channels[i]);
- }
+ for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++)
+ cpdma_chan_destroy(ctlr->channels[i]);
cpdma_desc_pool_destroy(ctlr->pool);
spin_unlock_irqrestore(&ctlr->lock, flags);
@@ -473,11 +492,13 @@ int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable)
spin_unlock_irqrestore(&ctlr->lock, flags);
return 0;
}
+EXPORT_SYMBOL_GPL(cpdma_ctlr_int_ctrl);
-void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr)
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value)
{
- dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, 0);
+ dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, value);
}
+EXPORT_SYMBOL_GPL(cpdma_ctlr_eoi);
struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
cpdma_handler_fn handler)
@@ -652,7 +673,7 @@ static void __cpdma_chan_submit(struct cpdma_chan *chan,
}
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
- int len, gfp_t gfp_mask)
+ int len, int directed, gfp_t gfp_mask)
{
struct cpdma_ctlr *ctlr = chan->ctlr;
struct cpdma_desc __iomem *desc;
@@ -668,7 +689,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
goto unlock_ret;
}
- desc = cpdma_desc_alloc(ctlr->pool, 1);
+ desc = cpdma_desc_alloc(ctlr->pool, 1, is_rx_chan(chan));
if (!desc) {
chan->stats.desc_alloc_fail++;
ret = -ENOMEM;
@@ -682,6 +703,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
buffer = dma_map_single(ctlr->dev, data, len, chan->dir);
mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
+ cpdma_desc_to_port(chan, mode, directed);
desc_write(desc, hw_next, 0);
desc_write(desc, hw_buffer, buffer);
@@ -704,6 +726,29 @@ unlock_ret:
}
EXPORT_SYMBOL_GPL(cpdma_chan_submit);
+bool cpdma_check_free_tx_desc(struct cpdma_chan *chan)
+{
+ unsigned long flags;
+ int index;
+ bool ret;
+ struct cpdma_ctlr *ctlr = chan->ctlr;
+ struct cpdma_desc_pool *pool = ctlr->pool;
+
+ spin_lock_irqsave(&pool->lock, flags);
+
+ index = bitmap_find_next_zero_area(pool->bitmap,
+ pool->num_desc, pool->num_desc/2, 1, 0);
+
+ if (index < pool->num_desc)
+ ret = true;
+ else
+ ret = false;
+
+ spin_unlock_irqrestore(&pool->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpdma_check_free_tx_desc);
+
static void __cpdma_chan_free(struct cpdma_chan *chan,
struct cpdma_desc __iomem *desc,
int outlen, int status)
@@ -749,7 +794,8 @@ static int __cpdma_chan_process(struct cpdma_chan *chan)
status = -EBUSY;
goto unlock_ret;
}
- status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE);
+ status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE |
+ CPDMA_DESC_PORT_MASK);
chan->head = desc_from_phys(pool, desc_read(desc, hw_next));
chan_write(chan, cp, desc_dma);
@@ -984,3 +1030,4 @@ unlock_ret:
spin_unlock_irqrestore(&ctlr->lock, flags);
return ret;
}
+EXPORT_SYMBOL_GPL(cpdma_control_set);
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h
index afa19a0c0d81..d9bcc6032fdc 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.h
+++ b/drivers/net/ethernet/ti/davinci_cpdma.h
@@ -24,6 +24,13 @@
#define __chan_linear(chan_num) ((chan_num) & (CPDMA_MAX_CHANNELS - 1))
#define chan_linear(chan) __chan_linear((chan)->chan_num)
+#define CPDMA_RX_SOURCE_PORT(__status__) ((__status__ >> 16) & 0x7)
+
+#define CPDMA_EOI_RX_THRESH 0x0
+#define CPDMA_EOI_RX 0x1
+#define CPDMA_EOI_TX 0x2
+#define CPDMA_EOI_MISC 0x3
+
struct cpdma_params {
struct device *dev;
void __iomem *dmaregs;
@@ -82,12 +89,13 @@ int cpdma_chan_dump(struct cpdma_chan *chan);
int cpdma_chan_get_stats(struct cpdma_chan *chan,
struct cpdma_chan_stats *stats);
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
- int len, gfp_t gfp_mask);
+ int len, int directed, gfp_t gfp_mask);
int cpdma_chan_process(struct cpdma_chan *chan, int quota);
int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable);
-void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr);
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value);
int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable);
+bool cpdma_check_free_tx_desc(struct cpdma_chan *chan);
enum cpdma_control {
CPDMA_CMD_IDLE, /* write-only */
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index 2a3e2c56bc60..52c05366599a 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -120,7 +120,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
#define EMAC_DEF_TX_CH (0) /* Default 0th channel */
#define EMAC_DEF_RX_CH (0) /* Default 0th channel */
#define EMAC_DEF_RX_NUM_DESC (128)
-#define EMAC_DEF_TX_NUM_DESC (128)
#define EMAC_DEF_MAX_TX_CH (1) /* Max TX channels configured */
#define EMAC_DEF_MAX_RX_CH (1) /* Max RX channels configured */
#define EMAC_POLL_WEIGHT (64) /* Default NAPI poll weight */
@@ -342,7 +341,6 @@ struct emac_priv {
u32 mac_hash2;
u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];
u32 rx_addr_type;
- atomic_t cur_tx;
const char *phy_id;
#ifdef CONFIG_OF
struct device_node *phy_node;
@@ -480,8 +478,8 @@ static void emac_dump_regs(struct emac_priv *priv)
static void emac_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, emac_version_string);
- strcpy(info->version, EMAC_MODULE_VERSION);
+ strlcpy(info->driver, emac_version_string, sizeof(info->driver));
+ strlcpy(info->version, EMAC_MODULE_VERSION, sizeof(info->version));
}
/**
@@ -1039,7 +1037,7 @@ static void emac_rx_handler(void *token, int len, int status)
recycle:
ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
- skb_tailroom(skb), GFP_KERNEL);
+ skb_tailroom(skb), 0, GFP_KERNEL);
WARN_ON(ret == -ENOMEM);
if (unlikely(ret < 0))
@@ -1050,10 +1048,10 @@ static void emac_tx_handler(void *token, int len, int status)
{
struct sk_buff *skb = token;
struct net_device *ndev = skb->dev;
- struct emac_priv *priv = netdev_priv(ndev);
-
- atomic_dec(&priv->cur_tx);
+ /* Check whether the queue is stopped due to stalled tx dma, if the
+ * queue is stopped then start the queue as we have free desc for tx
+ */
if (unlikely(netif_queue_stopped(ndev)))
netif_start_queue(ndev);
ndev->stats.tx_packets++;
@@ -1094,14 +1092,17 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)
skb_tx_timestamp(skb);
ret_code = cpdma_chan_submit(priv->txchan, skb, skb->data, skb->len,
- GFP_KERNEL);
+ 0, GFP_KERNEL);
if (unlikely(ret_code != 0)) {
if (netif_msg_tx_err(priv) && net_ratelimit())
dev_err(emac_dev, "DaVinci EMAC: desc submit failed");
goto fail_tx;
}
- if (atomic_inc_return(&priv->cur_tx) >= EMAC_DEF_TX_NUM_DESC)
+ /* If there is no more tx desc left free then we need to
+ * tell the kernel to stop sending us tx frames.
+ */
+ if (unlikely(cpdma_check_free_tx_desc(priv->txchan)))
netif_stop_queue(ndev);
return NETDEV_TX_OK;
@@ -1264,7 +1265,6 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
/* Store mac addr in priv and rx channel and set it in EMAC hw */
memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len);
memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len);
- ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
/* MAC address is configured only after the interface is enabled. */
if (netif_running(ndev)) {
@@ -1558,7 +1558,7 @@ static int emac_dev_open(struct net_device *ndev)
break;
ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
- skb_tailroom(skb), GFP_KERNEL);
+ skb_tailroom(skb), 0, GFP_KERNEL);
if (WARN_ON(ret < 0))
break;
}
@@ -1600,7 +1600,7 @@ static int emac_dev_open(struct net_device *ndev)
if (priv->phy_id && *priv->phy_id) {
priv->phydev = phy_connect(ndev, priv->phy_id,
- &emac_adjust_link, 0,
+ &emac_adjust_link,
PHY_INTERFACE_MODE_MII);
if (IS_ERR(priv->phydev)) {
diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
index cca25509b039..d04a622b08d4 100644
--- a/drivers/net/ethernet/ti/davinci_mdio.c
+++ b/drivers/net/ethernet/ti/davinci_mdio.c
@@ -320,10 +320,8 @@ static int davinci_mdio_probe(struct platform_device *pdev)
int ret, addr;
data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- dev_err(dev, "failed to alloc device data\n");
+ if (!data)
return -ENOMEM;
- }
data->bus = mdiobus_alloc();
if (!data->bus) {
diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c
index 96070e9b50dc..36435499814b 100644
--- a/drivers/net/ethernet/tile/tilepro.c
+++ b/drivers/net/ethernet/tile/tilepro.c
@@ -2195,7 +2195,6 @@ static int tile_net_set_mac_address(struct net_device *dev, void *p)
/* ISSUE: Note that "dev_addr" is now a pointer. */
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
return 0;
}
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
index e321d0b6fc88..445c0595c997 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -1226,8 +1226,8 @@ int gelic_net_open(struct net_device *netdev)
void gelic_net_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
- strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
- strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
}
static int gelic_ether_get_settings(struct net_device *netdev,
diff --git a/drivers/net/ethernet/toshiba/spider_net_ethtool.c b/drivers/net/ethernet/toshiba/spider_net_ethtool.c
index 9c288cd7d171..ffe519382e11 100644
--- a/drivers/net/ethernet/toshiba/spider_net_ethtool.c
+++ b/drivers/net/ethernet/toshiba/spider_net_ethtool.c
@@ -72,11 +72,13 @@ spider_net_ethtool_get_drvinfo(struct net_device *netdev,
card = netdev_priv(netdev);
/* clear and fill out info */
- memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
- strncpy(drvinfo->driver, spider_net_driver_name, 32);
- strncpy(drvinfo->version, VERSION, 32);
- strcpy(drvinfo->fw_version, "no information");
- strncpy(drvinfo->bus_info, pci_name(card->pdev), 32);
+ strlcpy(drvinfo->driver, spider_net_driver_name,
+ sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, VERSION, sizeof(drvinfo->version));
+ strlcpy(drvinfo->fw_version, "no information",
+ sizeof(drvinfo->fw_version));
+ strlcpy(drvinfo->bus_info, pci_name(card->pdev),
+ sizeof(drvinfo->bus_info));
}
static void
diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c
index 9819349eaa1e..fe256094db35 100644
--- a/drivers/net/ethernet/toshiba/tc35815.c
+++ b/drivers/net/ethernet/toshiba/tc35815.c
@@ -633,9 +633,8 @@ static int tc_mii_probe(struct net_device *dev)
/* attach the mac to the phy */
phydev = phy_connect(dev, dev_name(&phydev->dev),
- &tc_handle_link_change, 0,
- lp->chiptype == TC35815_TX4939 ?
- PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII);
+ &tc_handle_link_change,
+ lp->chiptype == TC35815_TX4939 ? PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII);
if (IS_ERR(phydev)) {
printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
return PTR_ERR(phydev);
@@ -856,7 +855,6 @@ static int tc35815_init_one(struct pci_dev *pdev,
if (rc)
goto err_out;
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
printk(KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n",
dev->name,
chip_info[ent->driver_data].name,
@@ -1976,9 +1974,10 @@ tc35815_set_multicast_list(struct net_device *dev)
static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct tc35815_local *lp = netdev_priv(dev);
- strcpy(info->driver, MODNAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, pci_name(lp->pci_dev));
+
+ strlcpy(info->driver, MODNAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(lp->pci_dev), sizeof(info->bus_info));
}
static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index 7992b3e05d3d..185c721c52d7 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -417,6 +417,12 @@ enum chip_cmd_bits {
Cmd1NoTxPoll=0x08, Cmd1Reset=0x80,
};
+struct rhine_stats {
+ u64 packets;
+ u64 bytes;
+ struct u64_stats_sync syncp;
+};
+
struct rhine_private {
/* Bit mask for configured VLAN ids */
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -458,6 +464,8 @@ struct rhine_private {
unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
+ struct rhine_stats rx_stats;
+ struct rhine_stats tx_stats;
u8 wolopts;
u8 tx_thresh, rx_thresh;
@@ -495,7 +503,8 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance);
static void rhine_tx(struct net_device *dev);
static int rhine_rx(struct net_device *dev, int limit);
static void rhine_set_rx_mode(struct net_device *dev);
-static struct net_device_stats *rhine_get_stats(struct net_device *dev);
+static struct rtnl_link_stats64 *rhine_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops netdev_ethtool_ops;
static int rhine_close(struct net_device *dev);
@@ -842,7 +851,7 @@ static const struct net_device_ops rhine_netdev_ops = {
.ndo_open = rhine_open,
.ndo_stop = rhine_close,
.ndo_start_xmit = rhine_start_tx,
- .ndo_get_stats = rhine_get_stats,
+ .ndo_get_stats64 = rhine_get_stats64,
.ndo_set_rx_mode = rhine_set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
@@ -990,7 +999,6 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
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)
@@ -1791,8 +1799,11 @@ static void rhine_tx(struct net_device *dev)
dev->stats.collisions += txstatus & 0x0F;
netif_dbg(rp, tx_done, 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++;
+
+ u64_stats_update_begin(&rp->tx_stats.syncp);
+ rp->tx_stats.bytes += rp->tx_skbuff[entry]->len;
+ rp->tx_stats.packets++;
+ u64_stats_update_end(&rp->tx_stats.syncp);
}
/* Free the original skb. */
if (rp->tx_skbuff_dma[entry]) {
@@ -1801,7 +1812,7 @@ static void rhine_tx(struct net_device *dev)
rp->tx_skbuff[entry]->len,
PCI_DMA_TODEVICE);
}
- dev_kfree_skb_irq(rp->tx_skbuff[entry]);
+ dev_kfree_skb(rp->tx_skbuff[entry]);
rp->tx_skbuff[entry] = NULL;
entry = (++rp->dirty_tx) % TX_RING_SIZE;
}
@@ -1924,8 +1935,11 @@ static int rhine_rx(struct net_device *dev, int limit)
if (unlikely(desc_length & DescTag))
__vlan_hwaccel_put_tag(skb, vlan_tci);
netif_receive_skb(skb);
- dev->stats.rx_bytes += pkt_len;
- dev->stats.rx_packets++;
+
+ u64_stats_update_begin(&rp->rx_stats.syncp);
+ rp->rx_stats.bytes += pkt_len;
+ rp->rx_stats.packets++;
+ u64_stats_update_end(&rp->rx_stats.syncp);
}
entry = (++rp->cur_rx) % RX_RING_SIZE;
rp->rx_head_desc = &rp->rx_ring[entry];
@@ -2010,25 +2024,37 @@ static void rhine_slow_event_task(struct work_struct *work)
if (intr_status & IntrPCIErr)
netif_warn(rp, hw, dev, "PCI error\n");
- napi_disable(&rp->napi);
- rhine_irq_disable(rp);
- /* Slow and safe. Consider __napi_schedule as a replacement ? */
- napi_enable(&rp->napi);
- napi_schedule(&rp->napi);
+ iowrite16(RHINE_EVENT & 0xffff, rp->base + IntrEnable);
out_unlock:
mutex_unlock(&rp->task_lock);
}
-static struct net_device_stats *rhine_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *
+rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
struct rhine_private *rp = netdev_priv(dev);
+ unsigned int start;
spin_lock_bh(&rp->lock);
rhine_update_rx_crc_and_missed_errord(rp);
spin_unlock_bh(&rp->lock);
- return &dev->stats;
+ netdev_stats_to_stats64(stats, &dev->stats);
+
+ do {
+ start = u64_stats_fetch_begin_bh(&rp->rx_stats.syncp);
+ stats->rx_packets = rp->rx_stats.packets;
+ stats->rx_bytes = rp->rx_stats.bytes;
+ } while (u64_stats_fetch_retry_bh(&rp->rx_stats.syncp, start));
+
+ do {
+ start = u64_stats_fetch_begin_bh(&rp->tx_stats.syncp);
+ stats->tx_packets = rp->tx_stats.packets;
+ stats->tx_bytes = rp->tx_stats.bytes;
+ } while (u64_stats_fetch_retry_bh(&rp->tx_stats.syncp, start));
+
+ return stats;
}
static void rhine_set_rx_mode(struct net_device *dev)
diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c
index 352383890326..545043cc4c0b 100644
--- a/drivers/net/ethernet/wiznet/w5100.c
+++ b/drivers/net/ethernet/wiznet/w5100.c
@@ -570,7 +570,6 @@ static int w5100_set_macaddr(struct net_device *ndev, void *addr)
if (!is_valid_ether_addr(sock_addr->sa_data))
return -EADDRNOTAVAIL;
memcpy(ndev->dev_addr, sock_addr->sa_data, ETH_ALEN);
- ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
w5100_write_macaddr(priv);
return 0;
}
diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c
index 9d1d986f8d40..7cbd0e6fc6f3 100644
--- a/drivers/net/ethernet/wiznet/w5300.c
+++ b/drivers/net/ethernet/wiznet/w5300.c
@@ -490,7 +490,6 @@ static int w5300_set_macaddr(struct net_device *ndev, void *addr)
if (!is_valid_ether_addr(sock_addr->sa_data))
return -EADDRNOTAVAIL;
memcpy(ndev->dev_addr, sock_addr->sa_data, ETH_ALEN);
- ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
w5300_write_macaddr(priv);
return 0;
}
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index aad909d793d7..9fc2ada4c3c2 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -238,11 +238,9 @@ static int temac_dma_bd_init(struct net_device *ndev)
int i;
lp->rx_skb = kcalloc(RX_BD_NUM, sizeof(*lp->rx_skb), GFP_KERNEL);
- if (!lp->rx_skb) {
- dev_err(&ndev->dev,
- "can't allocate memory for DMA RX buffer\n");
+ if (!lp->rx_skb)
goto out;
- }
+
/* allocate the tx and rx ring buffer descriptors. */
/* returns a virtual address and a physical address. */
lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
@@ -319,18 +317,10 @@ out:
* net_device_ops
*/
-static int temac_set_mac_address(struct net_device *ndev, void *address)
+static void temac_do_set_mac_address(struct net_device *ndev)
{
struct temac_local *lp = netdev_priv(ndev);
- if (address)
- memcpy(ndev->dev_addr, address, ETH_ALEN);
-
- if (!is_valid_ether_addr(ndev->dev_addr))
- eth_hw_addr_random(ndev);
- else
- ndev->addr_assign_type &= ~NET_ADDR_RANDOM;
-
/* set up unicast MAC address filter set its mac address */
mutex_lock(&lp->indirect_mutex);
temac_indirect_out32(lp, XTE_UAW0_OFFSET,
@@ -344,15 +334,26 @@ static int temac_set_mac_address(struct net_device *ndev, void *address)
(ndev->dev_addr[4] & 0x000000ff) |
(ndev->dev_addr[5] << 8));
mutex_unlock(&lp->indirect_mutex);
+}
+static int temac_init_mac_address(struct net_device *ndev, void *address)
+{
+ memcpy(ndev->dev_addr, address, ETH_ALEN);
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ eth_hw_addr_random(ndev);
+ temac_do_set_mac_address(ndev);
return 0;
}
-static int netdev_set_mac_address(struct net_device *ndev, void *p)
+static int temac_set_mac_address(struct net_device *ndev, void *p)
{
struct sockaddr *addr = p;
- return temac_set_mac_address(ndev, addr->sa_data);
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+ memcpy(ndev->dev_addr, addr->sa_data, ETH_ALEN);
+ temac_do_set_mac_address(ndev);
+ return 0;
}
static void temac_set_multicast_list(struct net_device *ndev)
@@ -579,7 +580,7 @@ static void temac_device_reset(struct net_device *ndev)
temac_setoptions(ndev,
lp->options & ~(XTE_OPTION_TXEN | XTE_OPTION_RXEN));
- temac_set_mac_address(ndev, NULL);
+ temac_do_set_mac_address(ndev);
/* Set address filter table */
temac_set_multicast_list(ndev);
@@ -938,7 +939,7 @@ static const struct net_device_ops temac_netdev_ops = {
.ndo_open = temac_open,
.ndo_stop = temac_stop,
.ndo_start_xmit = temac_start_xmit,
- .ndo_set_mac_address = netdev_set_mac_address,
+ .ndo_set_mac_address = temac_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = temac_ioctl,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1106,7 +1107,7 @@ static int temac_of_probe(struct platform_device *op)
rc = -ENODEV;
goto err_iounmap_2;
}
- temac_set_mac_address(ndev, (void *)addr);
+ temac_init_mac_address(ndev, (void *)addr);
rc = temac_mdio_setup(lp, op->dev.of_node);
if (rc)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 6f47100e58d7..278c9db3b5b8 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -1124,9 +1124,8 @@ static int axienet_ethtools_set_settings(struct net_device *ndev,
static void axienet_ethtools_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *ed)
{
- memset(ed, 0, sizeof(struct ethtool_drvinfo));
- strcpy(ed->driver, DRIVER_NAME);
- strcpy(ed->version, DRIVER_VERSION);
+ strlcpy(ed->driver, DRIVER_NAME, sizeof(ed->driver));
+ strlcpy(ed->version, DRIVER_VERSION, sizeof(ed->version));
ed->regdump_len = sizeof(u32) * AXIENET_REGS_N;
}
diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c
index 94a1f94f74b8..98e09d0d3ce2 100644
--- a/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c
@@ -1412,7 +1412,8 @@ static void netdev_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
strlcpy(info->driver, "xirc2ps_cs", sizeof(info->driver));
- sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+ snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx",
+ dev->base_addr);
}
static const struct ethtool_ops netdev_ethtool_ops = {
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
index d3ebb73277be..6958a5e87703 100644
--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -977,11 +977,12 @@ static void ixp4xx_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct port *port = netdev_priv(dev);
- strcpy(info->driver, DRV_NAME);
+
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
snprintf(info->fw_version, sizeof(info->fw_version), "%u:%u:%u:%u",
port->firmware[0], port->firmware[1],
port->firmware[2], port->firmware[3]);
- strcpy(info->bus_info, "internal");
+ strlcpy(info->bus_info, "internal", sizeof(info->bus_info));
}
static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1450,7 +1451,7 @@ static int eth_init_one(struct platform_device *pdev)
snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
mdio_bus->id, plat->phy);
- port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
+ port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link,
PHY_INTERFACE_MODE_MII);
if (IS_ERR(port->phydev)) {
err = PTR_ERR(port->phydev);
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
index 95dbcfdf131d..bf5e59687680 100644
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -1,6 +1,6 @@
config MKISS
tristate "Serial port KISS driver"
- depends on AX25
+ depends on AX25 && TTY
select CRC16
---help---
KISS is a protocol used for the exchange of data between a computer
@@ -18,7 +18,7 @@ config MKISS
config 6PACK
tristate "Serial port 6PACK driver"
- depends on AX25
+ depends on AX25 && TTY
---help---
6pack is a transmission protocol for the data exchange between your
PC and your TNC (the Terminal Node Controller acts as a kind of
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index c2e5497397d5..02de6c891670 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -586,7 +586,8 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
static int __init bpq_init_driver(void)
{
#ifdef CONFIG_PROC_FS
- if (!proc_net_fops_create(&init_net, "bpqether", S_IRUGO, &bpq_info_fops)) {
+ if (!proc_create("bpqether", S_IRUGO, init_net.proc_net,
+ &bpq_info_fops)) {
printk(KERN_ERR
"bpq: cannot create /proc/net/bpqether entry.\n");
return -ENOENT;
@@ -610,7 +611,7 @@ static void __exit bpq_cleanup_driver(void)
unregister_netdevice_notifier(&bpq_dev_notifier);
- proc_net_remove(&init_net, "bpqether");
+ remove_proc_entry("bpqether", init_net.proc_net);
rtnl_lock();
while (!list_empty(&bpq_devices)) {
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index ce555d9ac02c..6636022a1027 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -463,13 +463,8 @@ static int __init setup_adapter(int card_base, int type, int n)
/* Initialize what is necessary for write_scc and write_scc_data */
info = kzalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
- if (!info) {
- printk(KERN_ERR "dmascc: "
- "could not allocate memory for %s at %#3x\n",
- hw[type].name, card_base);
+ if (!info)
goto out;
- }
-
info->dev[0] = alloc_netdev(0, "", dev_setup);
if (!info->dev[0]) {
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 1b4a47bd32b7..bc1d52170389 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -2118,7 +2118,7 @@ static int __init scc_init_driver (void)
}
rtnl_unlock();
- proc_net_fops_create(&init_net, "z8530drv", 0, &scc_net_seq_fops);
+ proc_create("z8530drv", 0, init_net.proc_net, &scc_net_seq_fops);
return 0;
}
@@ -2173,7 +2173,7 @@ static void __exit scc_cleanup_driver(void)
if (Vector_Latch)
release_region(Vector_Latch, 1);
- proc_net_remove(&init_net, "z8530drv");
+ remove_proc_entry("z8530drv", init_net.proc_net);
}
MODULE_AUTHOR("Joerg Reuter <jreuter@yaina.de>");
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index c6645f1017af..4cf8f1017aad 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -1167,7 +1167,7 @@ static int __init yam_init_driver(void)
yam_timer.expires = jiffies + HZ / 100;
add_timer(&yam_timer);
- proc_net_fops_create(&init_net, "yam", S_IRUGO, &yam_info_fops);
+ proc_create("yam", S_IRUGO, init_net.proc_net, &yam_info_fops);
return 0;
error:
while (--i >= 0) {
@@ -1199,7 +1199,7 @@ static void __exit yam_cleanup_driver(void)
kfree(p);
}
- proc_net_remove(&init_net, "yam");
+ remove_proc_entry("yam", init_net.proc_net);
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hippi/Kconfig b/drivers/net/hippi/Kconfig
index 95eb34fdbba7..f71515dc5beb 100644
--- a/drivers/net/hippi/Kconfig
+++ b/drivers/net/hippi/Kconfig
@@ -3,8 +3,8 @@
#
config HIPPI
- bool "HIPPI driver support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && INET && PCI
+ bool "HIPPI driver support"
+ depends on INET && PCI
---help---
HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI
@@ -18,7 +18,7 @@ config HIPPI
if HIPPI
config ROADRUNNER
- tristate "Essential RoadRunner HIPPI PCI adapter support (EXPERIMENTAL)"
+ tristate "Essential RoadRunner HIPPI PCI adapter support"
depends on PCI
---help---
Say Y here if this is your PCI HIPPI network card.
@@ -27,7 +27,7 @@ config ROADRUNNER
will be called rrunner. If unsure, say N.
config ROADRUNNER_LARGE_RINGS
- bool "Use large TX/RX rings (EXPERIMENTAL)"
+ bool "Use large TX/RX rings"
depends on ROADRUNNER
---help---
If you say Y here, the RoadRunner driver will preallocate up to 2 MB
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 8264f0ef7692..5f85205cd12b 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -304,9 +304,9 @@ int netvsc_recv_callback(struct hv_device *device_obj,
static void netvsc_get_drvinfo(struct net_device *net,
struct ethtool_drvinfo *info)
{
- strcpy(info->driver, KBUILD_MODNAME);
- strcpy(info->version, HV_DRV_VERSION);
- strcpy(info->fw_version, "N/A");
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ strlcpy(info->version, HV_DRV_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
}
static int netvsc_change_mtu(struct net_device *ndev, int mtu)
@@ -498,8 +498,7 @@ static int netvsc_remove(struct hv_device *dev)
static const struct hv_vmbus_device_id id_table[] = {
/* Network guid */
- { VMBUS_DEVICE(0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
- 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E) },
+ { HV_NIC_GUID, },
{ },
};
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index a4a62e170ec0..fc1687ea4a42 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -751,16 +751,6 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
return 0;
}
-static int at86rf230_suspend(struct spi_device *spi, pm_message_t message)
-{
- return 0;
-}
-
-static int at86rf230_resume(struct spi_device *spi)
-{
- return 0;
-}
-
static int at86rf230_fill_data(struct spi_device *spi)
{
struct at86rf230_local *lp = spi_get_drvdata(spi);
@@ -948,8 +938,6 @@ static struct spi_driver at86rf230_driver = {
},
.probe = at86rf230_probe,
.remove = at86rf230_remove,
- .suspend = at86rf230_suspend,
- .resume = at86rf230_resume,
};
module_spi_driver(at86rf230_driver);
diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c
index 1e9cb0bbf62c..8f1c25676d44 100644
--- a/drivers/net/ieee802154/fakehard.c
+++ b/drivers/net/ieee802154/fakehard.c
@@ -372,7 +372,6 @@ static int ieee802154fake_probe(struct platform_device *pdev)
memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
dev->addr_len);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
/*
* For now we'd like to emulate 2.4 GHz-only device,
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 344dceb1aaf9..82164381f778 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -90,7 +90,7 @@ static void ri_tasklet(unsigned long dev)
u64_stats_update_end(&dp->tsync);
rcu_read_lock();
- skb->dev = dev_get_by_index_rcu(&init_net, skb->skb_iif);
+ skb->dev = dev_get_by_index_rcu(dev_net(_dev), skb->skb_iif);
if (!skb->dev) {
rcu_read_unlock();
dev_kfree_skb(skb);
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 595205406d73..2a30193d0d50 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -5,7 +5,7 @@ comment "SIR device drivers"
config IRTTY_SIR
tristate "IrTTY (uses Linux serial driver)"
- depends on IRDA
+ depends on IRDA && TTY
help
Say Y here if you want to build support for the IrTTY line
discipline. To compile it as a module, choose M here: the module
@@ -140,7 +140,7 @@ config LITELINK_DONGLE
config MA600_DONGLE
tristate "Mobile Action MA600 dongle"
- depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Mobile Action MA600
dongle. To compile it as a module, choose M here. The MA600 dongle
@@ -153,7 +153,7 @@ config MA600_DONGLE
config GIRBIL_DONGLE
tristate "Greenwich GIrBIL dongle"
- depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Greenwich GIrBIL
dongle. If you want to compile it as a module, choose M here.
@@ -164,7 +164,7 @@ config GIRBIL_DONGLE
config MCP2120_DONGLE
tristate "Microchip MCP2120"
- depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Microchip MCP2120
dongle. If you want to compile it as a module, choose M here.
@@ -178,7 +178,7 @@ config MCP2120_DONGLE
config OLD_BELKIN_DONGLE
tristate "Old Belkin dongle"
- depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Adaptec Airport 1000
and 2000 dongles. If you want to compile it as a module, choose
@@ -187,7 +187,7 @@ config OLD_BELKIN_DONGLE
config ACT200L_DONGLE
tristate "ACTiSYS IR-200L dongle"
- depends on IRTTY_SIR && DONGLE && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the ACTiSYS IR-200L
dongle. If you want to compile it as a module, choose M here.
@@ -198,7 +198,7 @@ config ACT200L_DONGLE
config KINGSUN_DONGLE
tristate "KingSun/DonShine DS-620 IrDA-USB dongle"
- depends on IRDA && USB && EXPERIMENTAL
+ depends on IRDA && USB
help
Say Y or M here if you want to build support for the KingSun/DonShine
DS-620 IrDA-USB bridge device driver.
@@ -212,14 +212,14 @@ config KINGSUN_DONGLE
config EP7211_DONGLE
tristate "Cirrus Logic clps711x I/R support"
- depends on IRTTY_SIR && ARCH_CLPS711X && IRDA && EXPERIMENTAL
+ depends on IRTTY_SIR && ARCH_CLPS711X && IRDA
help
Say Y here if you want to build support for the Cirrus logic
EP7211 chipset's infrared module.
config KSDAZZLE_DONGLE
- tristate "KingSun Dazzle IrDA-USB dongle (EXPERIMENTAL)"
- depends on IRDA && USB && EXPERIMENTAL
+ tristate "KingSun Dazzle IrDA-USB dongle"
+ depends on IRDA && USB
help
Say Y or M here if you want to build support for the KingSun Dazzle
IrDA-USB bridge device driver.
@@ -232,8 +232,8 @@ config KSDAZZLE_DONGLE
ksdazzle-sir.
config KS959_DONGLE
- tristate "KingSun KS-959 IrDA-USB dongle (EXPERIMENTAL)"
- depends on IRDA && USB && EXPERIMENTAL
+ tristate "KingSun KS-959 IrDA-USB dongle"
+ depends on IRDA && USB
help
Say Y or M here if you want to build support for the KingSun KS-959
IrDA-USB bridge device driver.
@@ -264,8 +264,8 @@ config USB_IRDA
you will need both USB and IrDA support in your kernel...
config SIGMATEL_FIR
- tristate "SigmaTel STIr4200 bridge (EXPERIMENTAL)"
- depends on IRDA && USB && EXPERIMENTAL
+ tristate "SigmaTel STIr4200 bridge"
+ depends on IRDA && USB
select CRC32
---help---
Say Y here if you want to build support for the SigmaTel STIr4200
@@ -331,8 +331,8 @@ config SMC_IRCC_FIR
smsc-ircc2.o.
config ALI_FIR
- tristate "ALi M5123 FIR (EXPERIMENTAL)"
- depends on EXPERIMENTAL && IRDA && ISA_DMA_API
+ tristate "ALi M5123 FIR"
+ depends on IRDA && ISA_DMA_API
help
Say Y here if you want to build support for the ALi M5123 FIR
Controller. The ALi M5123 FIR Controller is embedded in ALi M1543C,
@@ -343,8 +343,8 @@ config ALI_FIR
ali-ircc.
config VLSI_FIR
- tristate "VLSI 82C147 SIR/MIR/FIR (EXPERIMENTAL)"
- depends on EXPERIMENTAL && IRDA && PCI
+ tristate "VLSI 82C147 SIR/MIR/FIR"
+ depends on IRDA && PCI
help
Say Y here if you want to build support for the VLSI 82C147
PCI-IrDA Controller. This controller is used by the HP OmniBook 800
@@ -387,7 +387,7 @@ config PXA_FICP
config MCS_FIR
tristate "MosChip MCS7780 IrDA-USB dongle"
- depends on IRDA && USB && EXPERIMENTAL
+ depends on IRDA && USB
select CRC32
help
Say Y or M here if you want to build support for the MosChip
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 84872043b5c6..9cea451a6081 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -993,7 +993,7 @@ static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud)
/* Enable Interuupt */
self->ier = IER_EOM; // benjamin 2000/11/20 07:24PM
- /* Be ready for incomming frames */
+ /* Be ready for incoming frames */
ali_ircc_dma_receive(self); // benajmin 2000/11/8 07:46PM not complete
}
/* Go to SIR Speed */
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 6e4d4b62c9a8..a41267197839 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -210,7 +210,7 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
* been received, which can now be decapsulated and delivered for
* further processing
*
- * calling context depends on underlying driver and tty->low_latency!
+ * calling context depends on underlying driver and tty->port->low_latency!
* for example (low_latency: 1 / 0):
* serial.c: uart-interrupt / softint
* usbserial: urb-complete-interrupt / softint
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index d3fb97d97cbc..defcd8a85744 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -29,6 +29,7 @@
#include <linux/if_vlan.h>
#include <linux/if_link.h>
#include <linux/if_macvlan.h>
+#include <linux/hash.h>
#include <net/rtnetlink.h>
#include <net/xfrm.h>
@@ -126,6 +127,21 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
return vlan->receive(skb);
}
+static u32 macvlan_hash_mix(const struct macvlan_dev *vlan)
+{
+ return (u32)(((unsigned long)vlan) >> L1_CACHE_SHIFT);
+}
+
+
+static unsigned int mc_hash(const struct macvlan_dev *vlan,
+ const unsigned char *addr)
+{
+ u32 val = __get_unaligned_cpu32(addr + 2);
+
+ val ^= macvlan_hash_mix(vlan);
+ return hash_32(val, MACVLAN_MC_FILTER_BITS);
+}
+
static void macvlan_broadcast(struct sk_buff *skb,
const struct macvlan_port *port,
struct net_device *src,
@@ -137,6 +153,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
struct sk_buff *nskb;
unsigned int i;
int err;
+ unsigned int hash;
if (skb->protocol == htons(ETH_P_PAUSE))
return;
@@ -146,6 +163,9 @@ static void macvlan_broadcast(struct sk_buff *skb,
if (vlan->dev == src || !(vlan->mode & mode))
continue;
+ hash = mc_hash(vlan, eth->h_dest);
+ if (!test_bit(hash, vlan->mc_filter))
+ continue;
nskb = skb_clone(skb, GFP_ATOMIC);
err = macvlan_broadcast_one(nskb, vlan, eth,
mode == MACVLAN_MODE_BRIDGE);
@@ -375,7 +395,6 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p)
if (!(dev->flags & IFF_UP)) {
/* Just copy in the new address */
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
} else {
/* Rehash and update the device filters */
@@ -406,6 +425,21 @@ static void macvlan_set_mac_lists(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
+ if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+ bitmap_fill(vlan->mc_filter, MACVLAN_MC_FILTER_SZ);
+ } else {
+ struct netdev_hw_addr *ha;
+ DECLARE_BITMAP(filter, MACVLAN_MC_FILTER_SZ);
+
+ bitmap_zero(filter, MACVLAN_MC_FILTER_SZ);
+ netdev_for_each_mc_addr(ha, dev) {
+ __set_bit(mc_hash(vlan, ha->addr), filter);
+ }
+
+ __set_bit(mc_hash(vlan, dev->broadcast), filter);
+
+ bitmap_copy(vlan->mc_filter, filter, MACVLAN_MC_FILTER_SZ);
+ }
dev_uc_sync(vlan->lowerdev, dev);
dev_mc_sync(vlan->lowerdev, dev);
}
@@ -565,7 +599,7 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
return err;
}
-static int macvlan_fdb_del(struct ndmsg *ndm,
+static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr)
{
@@ -586,8 +620,8 @@ static int macvlan_fdb_del(struct ndmsg *ndm,
static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *drvinfo)
{
- snprintf(drvinfo->driver, 32, "macvlan");
- snprintf(drvinfo->version, 32, "0.1");
+ strlcpy(drvinfo->driver, "macvlan", sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, "0.1", sizeof(drvinfo->version));
}
static int macvlan_ethtool_get_settings(struct net_device *dev,
@@ -765,16 +799,22 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN);
}
+ err = netdev_upper_dev_link(lowerdev, dev);
+ if (err)
+ goto destroy_port;
+
port->count += 1;
err = register_netdevice(dev);
if (err < 0)
- goto destroy_port;
+ goto upper_dev_unlink;
list_add_tail(&vlan->list, &port->vlans);
netif_stacked_transfer_operstate(lowerdev, dev);
return 0;
+upper_dev_unlink:
+ netdev_upper_dev_unlink(lowerdev, dev);
destroy_port:
port->count -= 1;
if (!port->count)
@@ -798,6 +838,7 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head)
list_del(&vlan->list);
unregister_netdevice_queue(dev, head);
+ netdev_upper_dev_unlink(vlan->lowerdev, dev);
}
EXPORT_SYMBOL_GPL(macvlan_dellink);
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 0f0f9ce3a776..97243011d319 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -742,6 +742,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
if (zerocopy) {
skb_shinfo(skb)->destructor_arg = m->msg_control;
skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+ skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
}
if (vlan)
macvlan_start_xmit(skb, vlan->dev);
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 6989ebe2bc79..37add21a3d7d 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -269,12 +269,18 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
+ if (nt->np.ipv6)
+ return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
+ else
+ return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
}
static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
+ if (nt->np.ipv6)
+ return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
+ else
+ return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
}
static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
@@ -410,7 +416,22 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
return -EINVAL;
}
- nt->np.local_ip = in_aton(buf);
+ if (strnchr(buf, count, ':')) {
+ const char *end;
+ if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
+ if (*end && *end != '\n') {
+ printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+ return -EINVAL;
+ }
+ nt->np.ipv6 = true;
+ } else
+ return -EINVAL;
+ } else {
+ if (!nt->np.ipv6) {
+ nt->np.local_ip.ip = in_aton(buf);
+ } else
+ return -EINVAL;
+ }
return strnlen(buf, count);
}
@@ -426,7 +447,22 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
return -EINVAL;
}
- nt->np.remote_ip = in_aton(buf);
+ if (strnchr(buf, count, ':')) {
+ const char *end;
+ if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
+ if (*end && *end != '\n') {
+ printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+ return -EINVAL;
+ }
+ nt->np.ipv6 = true;
+ } else
+ return -EINVAL;
+ } else {
+ if (!nt->np.ipv6) {
+ nt->np.remote_ip.ip = in_aton(buf);
+ } else
+ return -EINVAL;
+ }
return strnlen(buf, count);
}
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
new file mode 100644
index 000000000000..ed947dd76fbd
--- /dev/null
+++ b/drivers/net/ntb_netdev.c
@@ -0,0 +1,408 @@
+/*
+ * 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) 2012 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.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 Intel Corporation. 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 copy
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of 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.
+ *
+ * Intel PCIe NTB Network Linux driver
+ *
+ * Contact Information:
+ * Jon Mason <jon.mason@intel.com>
+ */
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ntb.h>
+
+#define NTB_NETDEV_VER "0.7"
+
+MODULE_DESCRIPTION(KBUILD_MODNAME);
+MODULE_VERSION(NTB_NETDEV_VER);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+
+struct ntb_netdev {
+ struct list_head list;
+ struct pci_dev *pdev;
+ struct net_device *ndev;
+ struct ntb_transport_qp *qp;
+};
+
+#define NTB_TX_TIMEOUT_MS 1000
+#define NTB_RXQ_SIZE 100
+
+static LIST_HEAD(dev_list);
+
+static void ntb_netdev_event_handler(void *data, int status)
+{
+ struct net_device *ndev = data;
+ struct ntb_netdev *dev = netdev_priv(ndev);
+
+ netdev_dbg(ndev, "Event %x, Link %x\n", status,
+ ntb_transport_link_query(dev->qp));
+
+ /* Currently, only link status event is supported */
+ if (status)
+ netif_carrier_on(ndev);
+ else
+ netif_carrier_off(ndev);
+}
+
+static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
+ void *data, int len)
+{
+ struct net_device *ndev = qp_data;
+ struct sk_buff *skb;
+ int rc;
+
+ skb = data;
+ if (!skb)
+ return;
+
+ netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len);
+
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, ndev);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (netif_rx(skb) == NET_RX_DROP) {
+ ndev->stats.rx_errors++;
+ ndev->stats.rx_dropped++;
+ } else {
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += len;
+ }
+
+ skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
+ if (!skb) {
+ ndev->stats.rx_errors++;
+ ndev->stats.rx_frame_errors++;
+ return;
+ }
+
+ rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
+ if (rc) {
+ dev_kfree_skb(skb);
+ ndev->stats.rx_errors++;
+ ndev->stats.rx_fifo_errors++;
+ }
+}
+
+static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
+ void *data, int len)
+{
+ struct net_device *ndev = qp_data;
+ struct sk_buff *skb;
+
+ skb = data;
+ if (!skb || !ndev)
+ return;
+
+ if (len > 0) {
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
+ } else {
+ ndev->stats.tx_errors++;
+ ndev->stats.tx_aborted_errors++;
+ }
+
+ dev_kfree_skb(skb);
+}
+
+static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ struct ntb_netdev *dev = netdev_priv(ndev);
+ int rc;
+
+ netdev_dbg(ndev, "%s: skb len %d\n", __func__, skb->len);
+
+ rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len);
+ if (rc)
+ goto err;
+
+ return NETDEV_TX_OK;
+
+err:
+ ndev->stats.tx_dropped++;
+ ndev->stats.tx_errors++;
+ return NETDEV_TX_BUSY;
+}
+
+static int ntb_netdev_open(struct net_device *ndev)
+{
+ struct ntb_netdev *dev = netdev_priv(ndev);
+ struct sk_buff *skb;
+ int rc, i, len;
+
+ /* Add some empty rx bufs */
+ for (i = 0; i < NTB_RXQ_SIZE; i++) {
+ skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
+ if (!skb) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
+ ndev->mtu + ETH_HLEN);
+ if (rc == -EINVAL)
+ goto err;
+ }
+
+ netif_carrier_off(ndev);
+ ntb_transport_link_up(dev->qp);
+
+ return 0;
+
+err:
+ while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
+ dev_kfree_skb(skb);
+ return rc;
+}
+
+static int ntb_netdev_close(struct net_device *ndev)
+{
+ struct ntb_netdev *dev = netdev_priv(ndev);
+ struct sk_buff *skb;
+ int len;
+
+ ntb_transport_link_down(dev->qp);
+
+ while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+static int ntb_netdev_change_mtu(struct net_device *ndev, int new_mtu)
+{
+ struct ntb_netdev *dev = netdev_priv(ndev);
+ struct sk_buff *skb;
+ int len, rc;
+
+ if (new_mtu > ntb_transport_max_size(dev->qp) - ETH_HLEN)
+ return -EINVAL;
+
+ if (!netif_running(ndev)) {
+ ndev->mtu = new_mtu;
+ return 0;
+ }
+
+ /* Bring down the link and dispose of posted rx entries */
+ ntb_transport_link_down(dev->qp);
+
+ if (ndev->mtu < new_mtu) {
+ int i;
+
+ for (i = 0; (skb = ntb_transport_rx_remove(dev->qp, &len)); i++)
+ dev_kfree_skb(skb);
+
+ for (; i; i--) {
+ skb = netdev_alloc_skb(ndev, new_mtu + ETH_HLEN);
+ if (!skb) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
+ new_mtu + ETH_HLEN);
+ if (rc) {
+ dev_kfree_skb(skb);
+ goto err;
+ }
+ }
+ }
+
+ ndev->mtu = new_mtu;
+
+ ntb_transport_link_up(dev->qp);
+
+ return 0;
+
+err:
+ ntb_transport_link_down(dev->qp);
+
+ while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
+ dev_kfree_skb(skb);
+
+ netdev_err(ndev, "Error changing MTU, device inoperable\n");
+ return rc;
+}
+
+static const struct net_device_ops ntb_netdev_ops = {
+ .ndo_open = ntb_netdev_open,
+ .ndo_stop = ntb_netdev_close,
+ .ndo_start_xmit = ntb_netdev_start_xmit,
+ .ndo_change_mtu = ntb_netdev_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+static void ntb_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct ntb_netdev *dev = netdev_priv(ndev);
+
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ strlcpy(info->version, NTB_NETDEV_VER, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(dev->pdev), sizeof(info->bus_info));
+}
+
+static int ntb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ cmd->supported = SUPPORTED_Backplane;
+ cmd->advertising = ADVERTISED_Backplane;
+ cmd->speed = SPEED_UNKNOWN;
+ ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
+ cmd->duplex = DUPLEX_FULL;
+ cmd->port = PORT_OTHER;
+ cmd->phy_address = 0;
+ cmd->transceiver = XCVR_DUMMY1;
+ cmd->autoneg = AUTONEG_ENABLE;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+
+ return 0;
+}
+
+static const struct ethtool_ops ntb_ethtool_ops = {
+ .get_drvinfo = ntb_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_settings = ntb_get_settings,
+};
+
+static const struct ntb_queue_handlers ntb_netdev_handlers = {
+ .tx_handler = ntb_netdev_tx_handler,
+ .rx_handler = ntb_netdev_rx_handler,
+ .event_handler = ntb_netdev_event_handler,
+};
+
+static int ntb_netdev_probe(struct pci_dev *pdev)
+{
+ struct net_device *ndev;
+ struct ntb_netdev *dev;
+ int rc;
+
+ ndev = alloc_etherdev(sizeof(struct ntb_netdev));
+ if (!ndev)
+ return -ENOMEM;
+
+ dev = netdev_priv(ndev);
+ dev->ndev = ndev;
+ dev->pdev = pdev;
+ BUG_ON(!dev->pdev);
+ ndev->features = NETIF_F_HIGHDMA;
+
+ ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+
+ ndev->hw_features = ndev->features;
+ ndev->watchdog_timeo = msecs_to_jiffies(NTB_TX_TIMEOUT_MS);
+
+ random_ether_addr(ndev->perm_addr);
+ memcpy(ndev->dev_addr, ndev->perm_addr, ndev->addr_len);
+
+ ndev->netdev_ops = &ntb_netdev_ops;
+ SET_ETHTOOL_OPS(ndev, &ntb_ethtool_ops);
+
+ dev->qp = ntb_transport_create_queue(ndev, pdev, &ntb_netdev_handlers);
+ if (!dev->qp) {
+ rc = -EIO;
+ goto err;
+ }
+
+ ndev->mtu = ntb_transport_max_size(dev->qp) - ETH_HLEN;
+
+ rc = register_netdev(ndev);
+ if (rc)
+ goto err1;
+
+ list_add(&dev->list, &dev_list);
+ dev_info(&pdev->dev, "%s created\n", ndev->name);
+ return 0;
+
+err1:
+ ntb_transport_free_queue(dev->qp);
+err:
+ free_netdev(ndev);
+ return rc;
+}
+
+static void ntb_netdev_remove(struct pci_dev *pdev)
+{
+ struct net_device *ndev;
+ struct ntb_netdev *dev;
+
+ list_for_each_entry(dev, &dev_list, list) {
+ if (dev->pdev == pdev)
+ break;
+ }
+ if (dev == NULL)
+ return;
+
+ ndev = dev->ndev;
+
+ unregister_netdev(ndev);
+ ntb_transport_free_queue(dev->qp);
+ free_netdev(ndev);
+}
+
+static struct ntb_client ntb_netdev_client = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .probe = ntb_netdev_probe,
+ .remove = ntb_netdev_remove,
+};
+
+static int __init ntb_netdev_init_module(void)
+{
+ int rc;
+
+ rc = ntb_register_client_dev(KBUILD_MODNAME);
+ if (rc)
+ return rc;
+ return ntb_register_client(&ntb_netdev_client);
+}
+module_init(ntb_netdev_init_module);
+
+static void __exit ntb_netdev_exit_module(void)
+{
+ ntb_unregister_client(&ntb_netdev_client);
+ ntb_unregister_client_dev(KBUILD_MODNAME);
+}
+module_exit(ntb_netdev_exit_module);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 961f0b293913..450345261bd3 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -4,7 +4,6 @@
menuconfig PHYLIB
tristate "PHY Device support and infrastructure"
- depends on !S390
depends on NETDEVICES
help
Ethernet controllers are usually attached to PHY
diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c
index 0c9accb1c14f..e91d7d736ae2 100644
--- a/drivers/net/phy/mdio-mux-gpio.c
+++ b/drivers/net/phy/mdio-mux-gpio.c
@@ -53,7 +53,7 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev)
{
enum of_gpio_flags f;
struct mdio_mux_gpio_state *s;
- unsigned int num_gpios;
+ int num_gpios;
unsigned int n;
int r;
@@ -61,7 +61,7 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev)
return -ENODEV;
num_gpios = of_gpio_count(pdev->dev.of_node);
- if (num_gpios == 0 || num_gpios > MDIO_MUX_GPIO_MAX_BITS)
+ if (num_gpios <= 0 || num_gpios > MDIO_MUX_GPIO_MAX_BITS)
return -ENODEV;
s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 044b5326459f..dc920974204e 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -95,7 +95,7 @@ static struct class mdio_bus_class = {
#if IS_ENABLED(CONFIG_OF_MDIO)
/* Helper function for of_mdio_find_bus */
-static int of_mdio_bus_match(struct device *dev, void *mdio_bus_np)
+static int of_mdio_bus_match(struct device *dev, const void *mdio_bus_np)
{
return dev->of_node == mdio_bus_np;
}
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index b983596abcbb..29934446436a 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -5,15 +5,20 @@
*
* Author: David J. Choi
*
- * Copyright (c) 2010 Micrel, Inc.
+ * Copyright (c) 2010-2013 Micrel, 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.
*
- * Support : ksz9021 1000/100/10 phy from Micrel
- * ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy
+ * Support : Micrel Phys:
+ * Giga phys: ksz9021, ksz9031
+ * 100/10 Phys : ksz8001, ksz8721, ksz8737, ksz8041
+ * ksz8021, ksz8031, ksz8051,
+ * ksz8081, ksz8091,
+ * ksz8061,
+ * Switch : ksz8873, ksz886x
*/
#include <linux/kernel.h>
@@ -176,7 +181,7 @@ static struct phy_driver ksphy_driver[] = {
}, {
.phy_id = PHY_ID_KSZ8021,
.phy_id_mask = 0x00ffffff,
- .name = "Micrel KSZ8021",
+ .name = "Micrel KSZ8021 or KSZ8031",
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
@@ -225,6 +230,30 @@ static struct phy_driver ksphy_driver[] = {
.config_intr = kszphy_config_intr,
.driver = { .owner = THIS_MODULE,},
}, {
+ .phy_id = PHY_ID_KSZ8081,
+ .name = "Micrel KSZ8081 or KSZ8091",
+ .phy_id_mask = 0x00fffff0,
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = kszphy_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = kszphy_ack_interrupt,
+ .config_intr = kszphy_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+}, {
+ .phy_id = PHY_ID_KSZ8061,
+ .name = "Micrel KSZ8061",
+ .phy_id_mask = 0x00fffff0,
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = kszphy_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = kszphy_ack_interrupt,
+ .config_intr = kszphy_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+}, {
.phy_id = PHY_ID_KSZ9021,
.phy_id_mask = 0x000ffffe,
.name = "Micrel KSZ9021 Gigabit PHY",
@@ -238,6 +267,19 @@ static struct phy_driver ksphy_driver[] = {
.config_intr = ksz9021_config_intr,
.driver = { .owner = THIS_MODULE, },
}, {
+ .phy_id = PHY_ID_KSZ9031,
+ .phy_id_mask = 0x00fffff0,
+ .name = "Micrel KSZ9031 Gigabit PHY",
+ .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = kszphy_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = kszphy_ack_interrupt,
+ .config_intr = ksz9021_config_intr,
+ .driver = { .owner = THIS_MODULE, },
+}, {
.phy_id = PHY_ID_KSZ8873MLL,
.phy_id_mask = 0x00fffff0,
.name = "Micrel KSZ8873MLL Switch",
@@ -247,6 +289,16 @@ static struct phy_driver ksphy_driver[] = {
.config_aneg = ksz8873mll_config_aneg,
.read_status = ksz8873mll_read_status,
.driver = { .owner = THIS_MODULE, },
+}, {
+ .phy_id = PHY_ID_KSZ886X,
+ .phy_id_mask = 0x00fffff0,
+ .name = "Micrel KSZ886X Switch",
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = kszphy_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .driver = { .owner = THIS_MODULE, },
} };
static int __init ksphy_init(void)
@@ -270,12 +322,16 @@ MODULE_LICENSE("GPL");
static struct mdio_device_id __maybe_unused micrel_tbl[] = {
{ PHY_ID_KSZ9021, 0x000ffffe },
+ { PHY_ID_KSZ9031, 0x00fffff0 },
{ PHY_ID_KSZ8001, 0x00ffffff },
{ PHY_ID_KS8737, 0x00fffff0 },
{ PHY_ID_KSZ8021, 0x00ffffff },
{ PHY_ID_KSZ8041, 0x00fffff0 },
{ PHY_ID_KSZ8051, 0x00fffff0 },
+ { PHY_ID_KSZ8061, 0x00fffff0 },
+ { PHY_ID_KSZ8081, 0x00fffff0 },
{ PHY_ID_KSZ8873MLL, 0x00fffff0 },
+ { PHY_ID_KSZ886X, 0x00fffff0 },
{ }
};
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8af46e88a181..9930f9999561 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -416,16 +416,15 @@ static void phy_prepare_link(struct phy_device *phydev,
* @dev: the network device to connect
* @phydev: the pointer to the phy device
* @handler: callback function for state change notifications
- * @flags: PHY device's dev_flags
* @interface: PHY device's interface
*/
int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
- void (*handler)(struct net_device *), u32 flags,
+ void (*handler)(struct net_device *),
phy_interface_t interface)
{
int rc;
- rc = phy_attach_direct(dev, phydev, flags, interface);
+ rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
if (rc)
return rc;
@@ -443,7 +442,6 @@ EXPORT_SYMBOL(phy_connect_direct);
* @dev: the network device to connect
* @bus_id: the id string of the PHY device to connect
* @handler: callback function for state change notifications
- * @flags: PHY device's dev_flags
* @interface: PHY device's interface
*
* Description: Convenience function for connecting ethernet
@@ -455,7 +453,7 @@ EXPORT_SYMBOL(phy_connect_direct);
* the desired functionality.
*/
struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
- void (*handler)(struct net_device *), u32 flags,
+ void (*handler)(struct net_device *),
phy_interface_t interface)
{
struct phy_device *phydev;
@@ -471,7 +469,7 @@ struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
}
phydev = to_phy_device(d);
- rc = phy_connect_direct(dev, phydev, handler, flags, interface);
+ rc = phy_connect_direct(dev, phydev, handler, interface);
if (rc)
return ERR_PTR(rc);
@@ -576,14 +574,13 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
* phy_attach - attach a network device to a particular PHY device
* @dev: network device to attach
* @bus_id: Bus ID of PHY device to attach
- * @flags: PHY device's dev_flags
* @interface: PHY device's interface
*
* Description: Same as phy_attach_direct() except that a PHY bus_id
* string is passed instead of a pointer to a struct phy_device.
*/
struct phy_device *phy_attach(struct net_device *dev,
- const char *bus_id, u32 flags, phy_interface_t interface)
+ const char *bus_id, phy_interface_t interface)
{
struct bus_type *bus = &mdio_bus_type;
struct phy_device *phydev;
@@ -599,7 +596,7 @@ struct phy_device *phy_attach(struct net_device *dev,
}
phydev = to_phy_device(d);
- rc = phy_attach_direct(dev, phydev, flags, interface);
+ rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
if (rc)
return ERR_PTR(rc);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 72f93470ea35..8e7af8354342 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -23,6 +23,8 @@
#define RTL821x_INER_INIT 0x6400
#define RTL821x_INSR 0x13
+#define RTL8211E_INER_LINK_STAT 0x10
+
MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
MODULE_LICENSE("GPL");
@@ -36,7 +38,7 @@ static int rtl821x_ack_interrupt(struct phy_device *phydev)
return (err < 0) ? err : 0;
}
-static int rtl821x_config_intr(struct phy_device *phydev)
+static int rtl8211b_config_intr(struct phy_device *phydev)
{
int err;
@@ -49,28 +51,63 @@ static int rtl821x_config_intr(struct phy_device *phydev)
return err;
}
+static int rtl8211e_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_write(phydev, RTL821x_INER,
+ RTL8211E_INER_LINK_STAT);
+ else
+ err = phy_write(phydev, RTL821x_INER, 0);
+
+ return err;
+}
+
/* RTL8211B */
-static struct phy_driver rtl821x_driver = {
+static struct phy_driver rtl8211b_driver = {
.phy_id = 0x001cc912,
- .name = "RTL821x Gigabit Ethernet",
+ .name = "RTL8211B Gigabit Ethernet",
.phy_id_mask = 0x001fffff,
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_aneg = &genphy_config_aneg,
.read_status = &genphy_read_status,
.ack_interrupt = &rtl821x_ack_interrupt,
- .config_intr = &rtl821x_config_intr,
+ .config_intr = &rtl8211b_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+/* RTL8211E */
+static struct phy_driver rtl8211e_driver = {
+ .phy_id = 0x001cc915,
+ .name = "RTL8211E Gigabit Ethernet",
+ .phy_id_mask = 0x001fffff,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &rtl821x_ack_interrupt,
+ .config_intr = &rtl8211e_config_intr,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
.driver = { .owner = THIS_MODULE,},
};
static int __init realtek_init(void)
{
- return phy_driver_register(&rtl821x_driver);
+ int ret;
+
+ ret = phy_driver_register(&rtl8211b_driver);
+ if (ret < 0)
+ return -ENODEV;
+ return phy_driver_register(&rtl8211e_driver);
}
static void __exit realtek_exit(void)
{
- phy_driver_unregister(&rtl821x_driver);
+ phy_driver_unregister(&rtl8211b_driver);
+ phy_driver_unregister(&rtl8211e_driver);
}
module_init(realtek_init);
@@ -78,6 +115,7 @@ module_exit(realtek_exit);
static struct mdio_device_id __maybe_unused realtek_tbl[] = {
{ 0x001cc912, 0x001fffff },
+ { 0x001cc915, 0x001fffff },
{ }
};
diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c
index 41eb8ffeb53d..5c87eef40bf9 100644
--- a/drivers/net/phy/spi_ks8995.c
+++ b/drivers/net/phy/spi_ks8995.c
@@ -275,10 +275,8 @@ static int ks8995_probe(struct spi_device *spi)
pdata = spi->dev.platform_data;
ks = kzalloc(sizeof(*ks), GFP_KERNEL);
- if (!ks) {
- dev_err(&spi->dev, "no memory for private data\n");
+ if (!ks)
return -ENOMEM;
- }
mutex_init(&ks->lock);
ks->pdata = pdata;
diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig
index 872df3ef07a6..1373c6d7278d 100644
--- a/drivers/net/ppp/Kconfig
+++ b/drivers/net/ppp/Kconfig
@@ -82,8 +82,8 @@ config PPP_FILTER
If unsure, say N.
config PPP_MPPE
- tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)"
- depends on PPP && EXPERIMENTAL
+ tristate "PPP MPPE compression (encryption)"
+ depends on PPP
select CRYPTO
select CRYPTO_SHA1
select CRYPTO_ARC4
@@ -96,8 +96,8 @@ config PPP_MPPE
configuring PPTP clients and servers to utilize this method.
config PPP_MULTILINK
- bool "PPP multilink support (EXPERIMENTAL)"
- depends on PPP && EXPERIMENTAL
+ bool "PPP multilink support"
+ depends on PPP
---help---
PPP multilink is a protocol (defined in RFC 1990) which allows you
to combine several (logical or physical) lines into one logical PPP
@@ -118,8 +118,8 @@ config PPPOATM
changes its encapsulation unilaterally.
config PPPOE
- tristate "PPP over Ethernet (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PPP
+ tristate "PPP over Ethernet"
+ depends on PPP
---help---
Support for PPP over Ethernet.
@@ -130,8 +130,8 @@ config PPPOE
the heading "Kernel mode PPPoE").
config PPTP
- tristate "PPP over IPv4 (PPTP) (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PPP && NET_IPGRE_DEMUX
+ tristate "PPP over IPv4 (PPTP)"
+ depends on PPP && NET_IPGRE_DEMUX
---help---
Support for PPP over IPv4.(Point-to-Point Tunneling Protocol)
@@ -141,12 +141,13 @@ config PPTP
utilize this module.
config PPPOL2TP
- tristate "PPP over L2TP (EXPERIMENTAL)"
- depends on EXPERIMENTAL && L2TP && PPP
+ tristate "PPP over L2TP"
+ depends on L2TP && PPP
---help---
Support for PPP-over-L2TP socket family. L2TP is a protocol
used by ISPs and enterprises to tunnel PPP traffic over UDP
tunnels. L2TP is replacing PPTP for VPN uses.
+if TTY
config PPP_ASYNC
tristate "PPP support for async serial ports"
@@ -172,4 +173,6 @@ config PPP_SYNC_TTY
To compile this driver as a module, choose M here.
+endif # TTY
+
endif # PPP
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 0b2706abe3e3..3db9131e9229 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -1058,7 +1058,15 @@ ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64)
return stats64;
}
+static struct lock_class_key ppp_tx_busylock;
+static int ppp_dev_init(struct net_device *dev)
+{
+ dev->qdisc_tx_busylock = &ppp_tx_busylock;
+ return 0;
+}
+
static const struct net_device_ops ppp_netdev_ops = {
+ .ndo_init = ppp_dev_init,
.ndo_start_xmit = ppp_start_xmit,
.ndo_do_ioctl = ppp_net_ioctl,
.ndo_get_stats64 = ppp_get_stats64,
@@ -1805,8 +1813,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
/* the filter instructions are constructed assuming
a four-byte PPP header on each packet */
if (ppp->pass_filter || ppp->active_filter) {
- if (skb_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ if (skb_unclone(skb, GFP_ATOMIC))
goto err;
*skb_push(skb, 2) = 0;
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 20f31d0d1536..bb07ba94c3aa 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -1134,7 +1134,7 @@ static __net_init int pppoe_init_net(struct net *net)
rwlock_init(&pn->hash_lock);
- pde = proc_net_fops_create(net, "pppoe", S_IRUGO, &pppoe_seq_fops);
+ pde = proc_create("pppoe", S_IRUGO, net->proc_net, &pppoe_seq_fops);
#ifdef CONFIG_PROC_FS
if (!pde)
return -ENOMEM;
@@ -1145,7 +1145,7 @@ static __net_init int pppoe_init_net(struct net *net)
static __net_exit void pppoe_exit_net(struct net *net)
{
- proc_net_remove(net, "pppoe");
+ remove_proc_entry("pppoe", net->proc_net);
}
static struct pernet_operations pppoe_net_ops = {
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index d8b9b1e8ee02..f433b594388e 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -410,10 +410,10 @@ static void rionet_get_drvinfo(struct net_device *ndev,
{
struct rionet_private *rnet = netdev_priv(ndev);
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->fw_version, "n/a");
- strcpy(info->bus_info, rnet->mport->name);
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, "n/a", sizeof(info->fw_version));
+ strlcpy(info->bus_info, rnet->mport->name, sizeof(info->bus_info));
}
static u32 rionet_get_msglevel(struct net_device *ndev)
diff --git a/drivers/net/slip/Kconfig b/drivers/net/slip/Kconfig
index 211b160e4e9c..48e68714eef3 100644
--- a/drivers/net/slip/Kconfig
+++ b/drivers/net/slip/Kconfig
@@ -4,6 +4,7 @@
config SLIP
tristate "SLIP (serial line) support"
+ depends on TTY
---help---
Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
connect to your Internet service provider or to connect to some
diff --git a/drivers/net/team/Kconfig b/drivers/net/team/Kconfig
index 6b08bd419fba..c3011af68e91 100644
--- a/drivers/net/team/Kconfig
+++ b/drivers/net/team/Kconfig
@@ -1,6 +1,5 @@
menuconfig NET_TEAM
- tristate "Ethernet team driver support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "Ethernet team driver support"
---help---
This allows one to create virtual interfaces that teams together
multiple ethernet devices.
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index ad86660fb8f9..05c5efe84591 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -28,6 +28,7 @@
#include <net/genetlink.h>
#include <net/netlink.h>
#include <net/sch_generic.h>
+#include <generated/utsrelease.h>
#include <linux/if_team.h>
#define DRV_NAME "team"
@@ -507,6 +508,7 @@ static bool team_is_mode_set(struct team *team)
static void team_set_no_mode(struct team *team)
{
+ team->user_carrier_enabled = false;
team->mode = &__team_no_mode;
}
@@ -1054,10 +1056,11 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
}
}
- err = netdev_set_master(port_dev, dev);
+ err = netdev_master_upper_dev_link(port_dev, dev);
if (err) {
- netdev_err(dev, "Device %s failed to set master\n", portname);
- goto err_set_master;
+ netdev_err(dev, "Device %s failed to set upper link\n",
+ portname);
+ goto err_set_upper_link;
}
err = netdev_rx_handler_register(port_dev, team_handle_frame,
@@ -1090,9 +1093,9 @@ err_option_port_add:
netdev_rx_handler_unregister(port_dev);
err_handler_register:
- netdev_set_master(port_dev, NULL);
+ netdev_upper_dev_unlink(port_dev, dev);
-err_set_master:
+err_set_upper_link:
team_port_disable_netpoll(port);
err_enable_netpoll:
@@ -1129,18 +1132,20 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
return -ENOENT;
}
- __team_option_inst_mark_removed_port(team, port);
- __team_options_change_check(team);
- __team_option_inst_del_port(team, port);
- __team_port_change_port_removed(port);
team_port_disable(team, port);
list_del_rcu(&port->list);
netdev_rx_handler_unregister(port_dev);
- netdev_set_master(port_dev, NULL);
+ netdev_upper_dev_unlink(port_dev, dev);
team_port_disable_netpoll(port);
vlan_vids_del_by_dev(port_dev, dev);
dev_close(port_dev);
team_port_leave(team, port);
+
+ __team_option_inst_mark_removed_port(team, port);
+ __team_options_change_check(team);
+ __team_option_inst_del_port(team, port);
+ __team_port_change_port_removed(port);
+
team_port_set_orig_dev_addr(port);
dev_set_mtu(port_dev, port->orig.mtu);
synchronize_rcu();
@@ -1399,13 +1404,11 @@ static void team_destructor(struct net_device *dev)
static int team_open(struct net_device *dev)
{
- netif_carrier_on(dev);
return 0;
}
static int team_close(struct net_device *dev)
{
- netif_carrier_off(dev);
return 0;
}
@@ -1501,7 +1504,6 @@ static int team_set_mac_address(struct net_device *dev, void *p)
if (dev->type == ARPHRD_ETHER && !is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
rcu_read_lock();
list_for_each_entry_rcu(port, &team->port_list, list)
if (team->ops.port_change_dev_addr)
@@ -1707,6 +1709,19 @@ static netdev_features_t team_fix_features(struct net_device *dev,
return features;
}
+static int team_change_carrier(struct net_device *dev, bool new_carrier)
+{
+ struct team *team = netdev_priv(dev);
+
+ team->user_carrier_enabled = true;
+
+ if (new_carrier)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
+ return 0;
+}
+
static const struct net_device_ops team_netdev_ops = {
.ndo_init = team_init,
.ndo_uninit = team_uninit,
@@ -1729,8 +1744,24 @@ static const struct net_device_ops team_netdev_ops = {
.ndo_add_slave = team_add_slave,
.ndo_del_slave = team_del_slave,
.ndo_fix_features = team_fix_features,
+ .ndo_change_carrier = team_change_carrier,
};
+/***********************
+ * ethtool interface
+ ***********************/
+
+static void team_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
+}
+
+static const struct ethtool_ops team_ethtool_ops = {
+ .get_drvinfo = team_ethtool_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
/***********************
* rt netlink interface
@@ -1746,7 +1777,6 @@ static void team_setup_by_port(struct net_device *dev,
dev->mtu = port_dev->mtu;
memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len);
memcpy(dev->dev_addr, port_dev->dev_addr, port_dev->addr_len);
- dev->addr_assign_type &= ~NET_ADDR_RANDOM;
}
static int team_dev_type_check_change(struct net_device *dev,
@@ -1780,6 +1810,7 @@ static void team_setup(struct net_device *dev)
ether_setup(dev);
dev->netdev_ops = &team_netdev_ops;
+ dev->ethtool_ops = &team_ethtool_ops;
dev->destructor = team_destructor;
dev->tx_queue_len = 0;
dev->flags |= IFF_MULTICAST;
@@ -1941,30 +1972,6 @@ static void team_nl_team_put(struct team *team)
dev_put(team->dev);
}
-static int team_nl_send_generic(struct genl_info *info, struct team *team,
- int (*fill_func)(struct sk_buff *skb,
- struct genl_info *info,
- int flags, struct team *team))
-{
- struct sk_buff *skb;
- int err;
-
- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- err = fill_func(skb, info, NLM_F_ACK, team);
- if (err < 0)
- goto err_fill;
-
- err = genlmsg_unicast(genl_info_net(info), skb, info->snd_portid);
- return err;
-
-err_fill:
- nlmsg_free(skb);
- return err;
-}
-
typedef int team_nl_send_func_t(struct sk_buff *skb,
struct team *team, u32 portid);
@@ -2309,16 +2316,57 @@ team_put:
return err;
}
-static int team_nl_fill_port_list_get(struct sk_buff *skb,
- u32 portid, u32 seq, int flags,
- struct team *team,
- bool fillall)
+static int team_nl_fill_one_port_get(struct sk_buff *skb,
+ struct team_port *port)
+{
+ struct nlattr *port_item;
+
+ port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
+ if (!port_item)
+ goto nest_cancel;
+ if (nla_put_u32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex))
+ goto nest_cancel;
+ if (port->changed) {
+ if (nla_put_flag(skb, TEAM_ATTR_PORT_CHANGED))
+ goto nest_cancel;
+ port->changed = false;
+ }
+ if ((port->removed &&
+ nla_put_flag(skb, TEAM_ATTR_PORT_REMOVED)) ||
+ (port->state.linkup &&
+ nla_put_flag(skb, TEAM_ATTR_PORT_LINKUP)) ||
+ nla_put_u32(skb, TEAM_ATTR_PORT_SPEED, port->state.speed) ||
+ nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->state.duplex))
+ goto nest_cancel;
+ nla_nest_end(skb, port_item);
+ return 0;
+
+nest_cancel:
+ nla_nest_cancel(skb, port_item);
+ return -EMSGSIZE;
+}
+
+static int team_nl_send_port_list_get(struct team *team, u32 portid, u32 seq,
+ int flags, team_nl_send_func_t *send_func,
+ struct team_port *one_port)
{
struct nlattr *port_list;
+ struct nlmsghdr *nlh;
void *hdr;
struct team_port *port;
+ int err;
+ struct sk_buff *skb = NULL;
+ bool incomplete;
+ int i;
+
+ port = list_first_entry(&team->port_list, struct team_port, list);
+
+start_again:
+ err = __send_and_alloc_skb(&skb, team, portid, send_func);
+ if (err)
+ return err;
- hdr = genlmsg_put(skb, portid, seq, &team_nl_family, flags,
+ hdr = genlmsg_put(skb, portid, seq, &team_nl_family, flags | NLM_F_MULTI,
TEAM_CMD_PORT_LIST_GET);
if (!hdr)
return -EMSGSIZE;
@@ -2329,47 +2377,54 @@ static int team_nl_fill_port_list_get(struct sk_buff *skb,
if (!port_list)
goto nla_put_failure;
- list_for_each_entry(port, &team->port_list, list) {
- struct nlattr *port_item;
+ i = 0;
+ incomplete = false;
- /* Include only changed ports if fill all mode is not on */
- if (!fillall && !port->changed)
- continue;
- port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
- if (!port_item)
- goto nla_put_failure;
- if (nla_put_u32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex))
- goto nla_put_failure;
- if (port->changed) {
- if (nla_put_flag(skb, TEAM_ATTR_PORT_CHANGED))
- goto nla_put_failure;
- port->changed = false;
+ /* If one port is selected, called wants to send port list containing
+ * only this port. Otherwise go through all listed ports and send all
+ */
+ if (one_port) {
+ err = team_nl_fill_one_port_get(skb, one_port);
+ if (err)
+ goto errout;
+ } else {
+ list_for_each_entry(port, &team->port_list, list) {
+ err = team_nl_fill_one_port_get(skb, port);
+ if (err) {
+ if (err == -EMSGSIZE) {
+ if (!i)
+ goto errout;
+ incomplete = true;
+ break;
+ }
+ goto errout;
+ }
+ i++;
}
- if ((port->removed &&
- nla_put_flag(skb, TEAM_ATTR_PORT_REMOVED)) ||
- (port->state.linkup &&
- nla_put_flag(skb, TEAM_ATTR_PORT_LINKUP)) ||
- nla_put_u32(skb, TEAM_ATTR_PORT_SPEED, port->state.speed) ||
- nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->state.duplex))
- goto nla_put_failure;
- nla_nest_end(skb, port_item);
}
nla_nest_end(skb, port_list);
- return genlmsg_end(skb, hdr);
+ genlmsg_end(skb, hdr);
+ if (incomplete)
+ goto start_again;
+
+send_done:
+ nlh = nlmsg_put(skb, portid, seq, NLMSG_DONE, 0, flags | NLM_F_MULTI);
+ if (!nlh) {
+ err = __send_and_alloc_skb(&skb, team, portid, send_func);
+ if (err)
+ goto errout;
+ goto send_done;
+ }
+
+ return send_func(skb, team, portid);
nla_put_failure:
+ err = -EMSGSIZE;
+errout:
genlmsg_cancel(skb, hdr);
- return -EMSGSIZE;
-}
-
-static int team_nl_fill_port_list_get_all(struct sk_buff *skb,
- struct genl_info *info, int flags,
- struct team *team)
-{
- return team_nl_fill_port_list_get(skb, info->snd_portid,
- info->snd_seq, NLM_F_ACK,
- team, true);
+ nlmsg_free(skb);
+ return err;
}
static int team_nl_cmd_port_list_get(struct sk_buff *skb,
@@ -2382,7 +2437,8 @@ static int team_nl_cmd_port_list_get(struct sk_buff *skb,
if (!team)
return -EINVAL;
- err = team_nl_send_generic(info, team, team_nl_fill_port_list_get_all);
+ err = team_nl_send_port_list_get(team, info->snd_portid, info->snd_seq,
+ NLM_F_ACK, team_nl_send_unicast, NULL);
team_nl_team_put(team);
@@ -2433,27 +2489,11 @@ static int team_nl_send_event_options_get(struct team *team,
sel_opt_inst_list);
}
-static int team_nl_send_event_port_list_get(struct team *team)
+static int team_nl_send_event_port_get(struct team *team,
+ struct team_port *port)
{
- struct sk_buff *skb;
- int err;
- struct net *net = dev_net(team->dev);
-
- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- err = team_nl_fill_port_list_get(skb, 0, 0, 0, team, false);
- if (err < 0)
- goto err_fill;
-
- err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
- GFP_KERNEL);
- return err;
-
-err_fill:
- nlmsg_free(skb);
- return err;
+ return team_nl_send_port_list_get(team, 0, 0, 0, team_nl_send_multicast,
+ port);
}
static int team_nl_init(void)
@@ -2526,28 +2566,53 @@ static void __team_port_change_send(struct team_port *port, bool linkup)
port->state.duplex = 0;
send_event:
- err = team_nl_send_event_port_list_get(port->team);
+ err = team_nl_send_event_port_get(port->team, port);
if (err && err != -ESRCH)
netdev_warn(port->team->dev, "Failed to send port change of device %s via netlink (err %d)\n",
port->dev->name, err);
}
+static void __team_carrier_check(struct team *team)
+{
+ struct team_port *port;
+ bool team_linkup;
+
+ if (team->user_carrier_enabled)
+ return;
+
+ team_linkup = false;
+ list_for_each_entry(port, &team->port_list, list) {
+ if (port->linkup) {
+ team_linkup = true;
+ break;
+ }
+ }
+
+ if (team_linkup)
+ netif_carrier_on(team->dev);
+ else
+ netif_carrier_off(team->dev);
+}
+
static void __team_port_change_check(struct team_port *port, bool linkup)
{
if (port->state.linkup != linkup)
__team_port_change_send(port, linkup);
+ __team_carrier_check(port->team);
}
static void __team_port_change_port_added(struct team_port *port, bool linkup)
{
__team_port_change_send(port, linkup);
+ __team_carrier_check(port->team);
}
static void __team_port_change_port_removed(struct team_port *port)
{
port->removed = true;
__team_port_change_send(port, false);
+ __team_carrier_check(port->team);
}
static void team_port_change_check(struct team_port *port, bool linkup)
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
index 6262b4defd93..40fd3381b693 100644
--- a/drivers/net/team/team_mode_activebackup.c
+++ b/drivers/net/team/team_mode_activebackup.c
@@ -19,6 +19,7 @@
struct ab_priv {
struct team_port __rcu *active_port;
+ struct team_option_inst_info *ap_opt_inst_info;
};
static struct ab_priv *ab_priv(struct team *team)
@@ -54,8 +55,17 @@ drop:
static void ab_port_leave(struct team *team, struct team_port *port)
{
- if (ab_priv(team)->active_port == port)
+ if (ab_priv(team)->active_port == port) {
RCU_INIT_POINTER(ab_priv(team)->active_port, NULL);
+ team_option_inst_set_change(ab_priv(team)->ap_opt_inst_info);
+ }
+}
+
+static int ab_active_port_init(struct team *team,
+ struct team_option_inst_info *info)
+{
+ ab_priv(team)->ap_opt_inst_info = info;
+ return 0;
}
static int ab_active_port_get(struct team *team, struct team_gsetter_ctx *ctx)
@@ -88,6 +98,7 @@ static const struct team_option ab_options[] = {
{
.name = "activeport",
.type = TEAM_OPTION_TYPE_U32,
+ .init = ab_active_port_init,
.getter = ab_active_port_get,
.setter = ab_active_port_set,
},
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index cc09b67c23bc..b6f45c5d84d5 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -298,11 +298,12 @@ static void tun_flow_cleanup(unsigned long data)
}
static void tun_flow_update(struct tun_struct *tun, u32 rxhash,
- u16 queue_index)
+ struct tun_file *tfile)
{
struct hlist_head *head;
struct tun_flow_entry *e;
unsigned long delay = tun->ageing_time;
+ u16 queue_index = tfile->queue_index;
if (!rxhash)
return;
@@ -311,7 +312,9 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash,
rcu_read_lock();
- if (tun->numqueues == 1)
+ /* We may get a very small possibility of OOO during switching, not
+ * worth to optimize.*/
+ if (tun->numqueues == 1 || tfile->detached)
goto unlock;
e = tun_flow_find(head, rxhash);
@@ -411,21 +414,21 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
tun = rtnl_dereference(tfile->tun);
- if (tun) {
+ if (tun && !tfile->detached) {
u16 index = tfile->queue_index;
BUG_ON(index >= tun->numqueues);
dev = tun->dev;
rcu_assign_pointer(tun->tfiles[index],
tun->tfiles[tun->numqueues - 1]);
- rcu_assign_pointer(tfile->tun, NULL);
ntfile = rtnl_dereference(tun->tfiles[index]);
ntfile->queue_index = index;
--tun->numqueues;
- if (clean)
+ if (clean) {
+ rcu_assign_pointer(tfile->tun, NULL);
sock_put(&tfile->sk);
- else
+ } else
tun_disable_queue(tun, tfile);
synchronize_net();
@@ -439,10 +442,13 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
}
if (clean) {
- if (tun && tun->numqueues == 0 && tun->numdisabled == 0 &&
- !(tun->flags & TUN_PERSIST))
- if (tun->dev->reg_state == NETREG_REGISTERED)
+ if (tun && tun->numqueues == 0 && tun->numdisabled == 0) {
+ netif_carrier_off(tun->dev);
+
+ if (!(tun->flags & TUN_PERSIST) &&
+ tun->dev->reg_state == NETREG_REGISTERED)
unregister_netdevice(tun->dev);
+ }
BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED,
&tfile->socket.flags));
@@ -470,6 +476,10 @@ static void tun_detach_all(struct net_device *dev)
rcu_assign_pointer(tfile->tun, NULL);
--tun->numqueues;
}
+ list_for_each_entry(tfile, &tun->disabled, next) {
+ wake_up_all(&tfile->wq.wait);
+ rcu_assign_pointer(tfile->tun, NULL);
+ }
BUG_ON(tun->numqueues != 0);
synchronize_net();
@@ -500,7 +510,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
goto out;
err = -EINVAL;
- if (rtnl_dereference(tfile->tun))
+ if (rtnl_dereference(tfile->tun) && !tfile->detached)
goto out;
err = -EBUSY;
@@ -1190,6 +1200,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
if (zerocopy) {
skb_shinfo(skb)->destructor_arg = msg_control;
skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+ skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
}
skb_reset_network_header(skb);
@@ -1199,7 +1210,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
tun->dev->stats.rx_packets++;
tun->dev->stats.rx_bytes += len;
- tun_flow_update(tun, rxhash, tfile->queue_index);
+ tun_flow_update(tun, rxhash, tfile);
return total_len;
}
@@ -1658,10 +1669,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
device_create_file(&tun->dev->dev, &dev_attr_owner) ||
device_create_file(&tun->dev->dev, &dev_attr_group))
pr_err("Failed to create tun sysfs files\n");
-
- netif_carrier_on(tun->dev);
}
+ netif_carrier_on(tun->dev);
+
tun_debug(KERN_INFO, tun, "tun_set_iff\n");
if (ifr->ifr_flags & IFF_NO_PI)
@@ -1813,7 +1824,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
ret = tun_attach(tun, file);
} else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
tun = rtnl_dereference(tfile->tun);
- if (!tun || !(tun->flags & TUN_TAP_MQ))
+ if (!tun || !(tun->flags & TUN_TAP_MQ) || tfile->detached)
ret = -EINVAL;
else
__tun_detach(tfile, false);
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index ef976215b649..da92ed3797aa 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -8,8 +8,7 @@ menu "USB Network Adapters"
depends on USB && NET
config USB_CATC
- tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "USB CATC NetMate-based Ethernet device support"
select CRC32
---help---
Say Y if you want to use one of the following 10Mbps USB Ethernet
@@ -83,8 +82,7 @@ config USB_PEGASUS
module will be called pegasus.
config USB_RTL8150
- tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "USB RTL8150 based ethernet device support"
select NET_CORE
select MII
help
@@ -188,7 +186,7 @@ config USB_NET_CDCETHER
config USB_NET_CDC_EEM
tristate "CDC EEM support"
- depends on USB_USBNET && EXPERIMENTAL
+ depends on USB_USBNET
help
This option supports devices conforming to the Communication Device
Class (CDC) Ethernet Emulation Model, a specification that's easy to
@@ -287,7 +285,7 @@ config USB_NET_PLUSB
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
+ depends on USB_USBNET
help
Choose this option if you're using a host-to-host cable
with one of these chips.
@@ -301,8 +299,8 @@ config USB_NET_MCS7830
adapters marketed under the DeLOCK brand.
config USB_NET_RNDIS_HOST
- tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
- depends on USB_USBNET && EXPERIMENTAL
+ tristate "Host for RNDIS and ActiveSync devices"
+ depends on USB_USBNET
select USB_NET_CDCETHER
help
This option enables hosting "Remote NDIS" USB networking links,
@@ -380,7 +378,7 @@ config USB_EPSON2888
config USB_KC2190
boolean "KT Technology KC2190 based cables (InstaNet)"
- depends on USB_NET_CDC_SUBSET && EXPERIMENTAL
+ depends on USB_NET_CDC_SUBSET
help
Choose this option if you're using a host-to-host cable
with one of these chips.
@@ -445,7 +443,7 @@ config USB_NET_QMI_WWAN
config USB_HSO
tristate "Option USB High Speed Mobile Devices"
- depends on USB && RFKILL
+ depends on USB && RFKILL && TTY
default n
help
Choose this option if you have an Option HSDPA/HSUPA card.
@@ -493,7 +491,7 @@ config USB_SIERRA_NET
config USB_VL600
tristate "LG VL600 modem dongle"
- depends on USB_NET_CDCETHER
+ depends on USB_NET_CDCETHER && TTY
select USB_ACM
help
Select this if you want to use an LG Electronics 4G/LTE usb modem
diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h
index e889631161b8..346c032aa795 100644
--- a/drivers/net/usb/asix.h
+++ b/drivers/net/usb/asix.h
@@ -167,6 +167,20 @@ struct asix_data {
u8 res;
};
+struct asix_rx_fixup_info {
+ struct sk_buff *ax_skb;
+ u32 header;
+ u16 size;
+ bool split_head;
+};
+
+struct asix_common_private {
+ struct asix_rx_fixup_info rx_fixup_info;
+};
+
+/* ASIX specific flags */
+#define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */
+
int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data);
@@ -176,7 +190,9 @@ int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
u16 index, u16 size, void *data);
-int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb);
+int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
+ struct asix_rx_fixup_info *rx);
+int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb);
struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
gfp_t flags);
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c
index 50d167330d38..f7f623a5390e 100644
--- a/drivers/net/usb/asix_common.c
+++ b/drivers/net/usb/asix_common.c
@@ -51,49 +51,89 @@ void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
value, index, data, size);
}
-int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
+ struct asix_rx_fixup_info *rx)
{
int offset = 0;
- while (offset + sizeof(u32) < skb->len) {
- struct sk_buff *ax_skb;
- u16 size;
- u32 header = get_unaligned_le32(skb->data + offset);
-
- offset += sizeof(u32);
-
- /* get the packet length */
- size = (u16) (header & 0x7ff);
- if (size != ((~header >> 16) & 0x07ff)) {
- netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
- return 0;
+ while (offset + sizeof(u16) <= skb->len) {
+ u16 remaining = 0;
+ unsigned char *data;
+
+ if (!rx->size) {
+ if ((skb->len - offset == sizeof(u16)) ||
+ rx->split_head) {
+ if(!rx->split_head) {
+ rx->header = get_unaligned_le16(
+ skb->data + offset);
+ rx->split_head = true;
+ offset += sizeof(u16);
+ break;
+ } else {
+ rx->header |= (get_unaligned_le16(
+ skb->data + offset)
+ << 16);
+ rx->split_head = false;
+ offset += sizeof(u16);
+ }
+ } else {
+ rx->header = get_unaligned_le32(skb->data +
+ offset);
+ offset += sizeof(u32);
+ }
+
+ /* get the packet length */
+ rx->size = (u16) (rx->header & 0x7ff);
+ if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
+ netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
+ rx->header, offset);
+ rx->size = 0;
+ return 0;
+ }
+ rx->ax_skb = netdev_alloc_skb_ip_align(dev->net,
+ rx->size);
+ if (!rx->ax_skb)
+ return 0;
}
- if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
- (size + offset > skb->len)) {
+ if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
- size);
+ rx->size);
+ kfree_skb(rx->ax_skb);
return 0;
}
- ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
- if (!ax_skb)
- return 0;
- skb_put(ax_skb, size);
- memcpy(ax_skb->data, skb->data + offset, size);
- usbnet_skb_return(dev, ax_skb);
+ if (rx->size > skb->len - offset) {
+ remaining = rx->size - (skb->len - offset);
+ rx->size = skb->len - offset;
+ }
+
+ data = skb_put(rx->ax_skb, rx->size);
+ memcpy(data, skb->data + offset, rx->size);
+ if (!remaining)
+ usbnet_skb_return(dev, rx->ax_skb);
- offset += (size + 1) & 0xfffe;
+ offset += (rx->size + 1) & 0xfffe;
+ rx->size = remaining;
}
if (skb->len != offset) {
- netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
- skb->len);
+ netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
+ skb->len, offset);
return 0;
}
+
return 1;
}
+int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb)
+{
+ struct asix_common_private *dp = dev->driver_priv;
+ struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
+
+ return asix_rx_fixup_internal(dev, skb, rx);
+}
+
struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
gfp_t flags)
{
@@ -510,8 +550,8 @@ void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
{
/* Inherit standard device info */
usbnet_get_drvinfo(net, info);
- strncpy (info->driver, DRIVER_NAME, sizeof info->driver);
- strncpy (info->version, DRIVER_VERSION, sizeof info->version);
+ strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
info->eedump_len = AX_EEPROM_LEN;
}
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 7a6e758f48e7..2205dbc8d32f 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -422,14 +422,25 @@ static const struct net_device_ops ax88772_netdev_ops = {
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{
- int ret, embd_phy;
+ int ret, embd_phy, i;
u8 buf[ETH_ALEN];
u32 phyid;
usbnet_get_endpoints(dev,intf);
/* Get the MAC address */
- ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
+ if (dev->driver_info->data & FLAG_EEPROM_MAC) {
+ for (i = 0; i < (ETH_ALEN >> 1); i++) {
+ ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x04 + i,
+ 0, 2, buf + i * 2);
+ if (ret < 0)
+ break;
+ }
+ } else {
+ ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
+ 0, 0, ETH_ALEN, buf);
+ }
+
if (ret < 0) {
netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret);
return ret;
@@ -484,9 +495,19 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
dev->rx_urb_size = 2048;
}
+ dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
+ if (!dev->driver_priv)
+ return -ENOMEM;
+
return 0;
}
+static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+ if (dev->driver_priv)
+ kfree(dev->driver_priv);
+}
+
static const struct ethtool_ops ax88178_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
.get_link = asix_get_link,
@@ -818,6 +839,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
dev->rx_urb_size = 2048;
}
+ dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
+ if (!dev->driver_priv)
+ return -ENOMEM;
+
return 0;
}
@@ -864,22 +889,38 @@ static const struct driver_info hawking_uf200_info = {
static const struct driver_info ax88772_info = {
.description = "ASIX AX88772 USB 2.0 Ethernet",
.bind = ax88772_bind,
+ .unbind = ax88772_unbind,
.status = asix_status,
.link_reset = ax88772_link_reset,
.reset = ax88772_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
- .rx_fixup = asix_rx_fixup,
+ .rx_fixup = asix_rx_fixup_common,
.tx_fixup = asix_tx_fixup,
};
+static const struct driver_info ax88772b_info = {
+ .description = "ASIX AX88772B USB 2.0 Ethernet",
+ .bind = ax88772_bind,
+ .unbind = ax88772_unbind,
+ .status = asix_status,
+ .link_reset = ax88772_link_reset,
+ .reset = ax88772_reset,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
+ FLAG_MULTI_PACKET,
+ .rx_fixup = asix_rx_fixup_common,
+ .tx_fixup = asix_tx_fixup,
+ .data = FLAG_EEPROM_MAC,
+};
+
static const struct driver_info ax88178_info = {
.description = "ASIX AX88178 USB 2.0 Ethernet",
.bind = ax88178_bind,
+ .unbind = ax88772_unbind,
.status = asix_status,
.link_reset = ax88178_link_reset,
.reset = ax88178_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
- .rx_fixup = asix_rx_fixup,
+ .rx_fixup = asix_rx_fixup_common,
.tx_fixup = asix_tx_fixup,
};
@@ -953,7 +994,7 @@ static const struct usb_device_id products [] = {
}, {
// ASIX AX88772B 10/100
USB_DEVICE (0x0b95, 0x772b),
- .driver_info = (unsigned long) &ax88772_info,
+ .driver_info = (unsigned long) &ax88772b_info,
}, {
// ASIX AX88772 10/100
USB_DEVICE (0x0b95, 0x7720),
diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c
index c8e0aa85fb8e..d012203b0f29 100644
--- a/drivers/net/usb/ax88172a.c
+++ b/drivers/net/usb/ax88172a.c
@@ -35,6 +35,7 @@ struct ax88172a_private {
u16 phy_addr;
u16 oldmode;
int use_embdphy;
+ struct asix_rx_fixup_info rx_fixup_info;
};
/* MDIO read and write wrappers for phylib */
@@ -116,7 +117,6 @@ static int ax88172a_init_mdio(struct usbnet *dev)
priv->mdio->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
if (!priv->mdio->irq) {
- netdev_err(dev->net, "Could not allocate mdio->irq\n");
ret = -ENOMEM;
goto mfree;
}
@@ -235,10 +235,9 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)
usbnet_get_endpoints(dev, intf);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- netdev_err(dev->net, "Could not allocate memory for private data\n");
+ if (!priv)
return -ENOMEM;
- }
+
dev->driver_priv = priv;
/* Get the MAC address */
@@ -377,7 +376,7 @@ static int ax88172a_reset(struct usbnet *dev)
priv->phydev = phy_connect(dev->net, priv->phy_name,
&ax88172a_adjust_link,
- 0, PHY_INTERFACE_MODE_MII);
+ PHY_INTERFACE_MODE_MII);
if (IS_ERR(priv->phydev)) {
netdev_err(dev->net, "Could not connect to PHY device %s\n",
priv->phy_name);
@@ -400,6 +399,14 @@ out:
}
+static int ax88172a_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ struct ax88172a_private *dp = dev->driver_priv;
+ struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
+
+ return asix_rx_fixup_internal(dev, skb, rx);
+}
+
const struct driver_info ax88172a_info = {
.description = "ASIX AX88172A USB 2.0 Ethernet",
.bind = ax88172a_bind,
@@ -409,6 +416,6 @@ const struct driver_info ax88172a_info = {
.status = ax88172a_status,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
FLAG_MULTI_PACKET,
- .rx_fixup = asix_rx_fixup,
+ .rx_fixup = ax88172a_rx_fixup,
.tx_fixup = asix_tx_fixup,
};
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 18d9579123ea..8d5cac2d8e33 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -685,9 +685,9 @@ static void catc_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct catc *catc = netdev_priv(dev);
- strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
- strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
- usb_make_path (catc->usbdev, info->bus_info, sizeof info->bus_info);
+ strlcpy(info->driver, driver_name, sizeof(info->driver));
+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ usb_make_path(catc->usbdev, info->bus_info, sizeof(info->bus_info));
}
static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 3f3d12d766e7..57136dc1b887 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -615,6 +615,13 @@ static const struct usb_device_id products [] = {
.driver_info = 0,
},
+/* AnyDATA ADU960S - handled by qmi_wwan */
+{
+ USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+ .driver_info = 0,
+},
+
/*
* WHITELIST!!!
*
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 9197b2c72ca3..4a8c25a22294 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -65,9 +65,9 @@ cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
{
struct usbnet *dev = netdev_priv(net);
- strncpy(info->driver, dev->driver_name, sizeof(info->driver));
- strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
- strncpy(info->fw_version, dev->driver_info->description,
+ strlcpy(info->driver, dev->driver_name, sizeof(info->driver));
+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, dev->driver_info->description,
sizeof(info->fw_version));
usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
}
@@ -576,9 +576,14 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
if ((intf->num_altsetting == 2) &&
!usb_set_interface(dev->udev,
intf->cur_altsetting->desc.bInterfaceNumber,
- CDC_NCM_COMM_ALTSETTING_MBIM) &&
- cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
- return -ENODEV;
+ CDC_NCM_COMM_ALTSETTING_MBIM)) {
+ if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
+ return -ENODEV;
+ else
+ usb_set_interface(dev->udev,
+ intf->cur_altsetting->desc.bInterfaceNumber,
+ CDC_NCM_COMM_ALTSETTING_NCM);
+ }
#endif
/* NCM data altsetting is always 1 */
@@ -1215,6 +1220,9 @@ static const struct usb_device_id cdc_devs[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46),
.driver_info = (unsigned long)&wwan_info,
},
+ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x76),
+ .driver_info = (unsigned long)&wwan_info,
+ },
/* Infineon(now Intel) HSPA Modem platform */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1519, 0x0443,
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index d7e99445518e..174e5ecea4cc 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -118,7 +118,7 @@ static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *valu
dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);
for (i = 0; i < DM_TIMEOUT; i++) {
- u8 tmp;
+ u8 tmp = 0;
udelay(1);
ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
@@ -161,7 +161,7 @@ static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 valu
dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1a : 0x12);
for (i = 0; i < DM_TIMEOUT; i++) {
- u8 tmp;
+ u8 tmp = 0;
udelay(1);
ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index cd8ccb240f4b..e2dd3249b6bd 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2035,25 +2035,23 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
tty = tty_port_tty_get(&serial->port);
/* Push data to tty */
- if (tty) {
- write_length_remaining = urb->actual_length -
- serial->curr_rx_urb_offset;
- D1("data to push to tty");
- while (write_length_remaining) {
- if (test_bit(TTY_THROTTLED, &tty->flags)) {
- tty_kref_put(tty);
- return -1;
- }
- curr_write_len = tty_insert_flip_string
- (tty, urb->transfer_buffer +
- serial->curr_rx_urb_offset,
- write_length_remaining);
- serial->curr_rx_urb_offset += curr_write_len;
- write_length_remaining -= curr_write_len;
- tty_flip_buffer_push(tty);
+ write_length_remaining = urb->actual_length -
+ serial->curr_rx_urb_offset;
+ D1("data to push to tty");
+ while (write_length_remaining) {
+ if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
+ tty_kref_put(tty);
+ return -1;
}
- tty_kref_put(tty);
+ curr_write_len = tty_insert_flip_string(&serial->port,
+ urb->transfer_buffer + serial->curr_rx_urb_offset,
+ write_length_remaining);
+ serial->curr_rx_urb_offset += curr_write_len;
+ write_length_remaining -= curr_write_len;
+ tty_flip_buffer_push(&serial->port);
}
+ tty_kref_put(tty);
+
if (write_length_remaining == 0) {
serial->curr_rx_urb_offset = 0;
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
@@ -2317,10 +2315,8 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
serial->rx_urb[i]->transfer_buffer_length = 0;
serial->rx_data[i] = kzalloc(serial->rx_data_length,
GFP_KERNEL);
- if (!serial->rx_data[i]) {
- dev_err(dev, "%s - Out of memory\n", __func__);
+ if (!serial->rx_data[i])
goto exit;
- }
}
/* TX, allocate urb and initialize */
@@ -2336,15 +2332,12 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
serial->tx_buffer_count = 0;
serial->tx_data_length = tx_size;
serial->tx_data = kzalloc(serial->tx_data_length, GFP_KERNEL);
- if (!serial->tx_data) {
- dev_err(dev, "%s - Out of memory\n", __func__);
+ if (!serial->tx_data)
goto exit;
- }
+
serial->tx_buffer = kzalloc(serial->tx_data_length, GFP_KERNEL);
- if (!serial->tx_buffer) {
- dev_err(dev, "%s - Out of memory\n", __func__);
+ if (!serial->tx_buffer)
goto exit;
- }
return 0;
exit:
@@ -2580,10 +2573,8 @@ static struct hso_device *hso_create_net_device(struct usb_interface *interface,
}
hso_net->mux_bulk_rx_buf_pool[i] = kzalloc(MUX_BULK_RX_BUF_SIZE,
GFP_KERNEL);
- if (!hso_net->mux_bulk_rx_buf_pool[i]) {
- dev_err(&interface->dev, "Could not allocate rx buf\n");
+ if (!hso_net->mux_bulk_rx_buf_pool[i])
goto exit;
- }
}
hso_net->mux_bulk_tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!hso_net->mux_bulk_tx_urb) {
@@ -2591,10 +2582,8 @@ static struct hso_device *hso_create_net_device(struct usb_interface *interface,
goto exit;
}
hso_net->mux_bulk_tx_buf = kzalloc(MUX_BULK_TX_BUF_SIZE, GFP_KERNEL);
- if (!hso_net->mux_bulk_tx_buf) {
- dev_err(&interface->dev, "Could not allocate tx buf\n");
+ if (!hso_net->mux_bulk_tx_buf)
goto exit;
- }
add_net_device(hso_dev);
@@ -2818,10 +2807,8 @@ struct hso_shared_int *hso_create_shared_int(struct usb_interface *interface)
mux->shared_intr_buf =
kzalloc(le16_to_cpu(mux->intr_endp->wMaxPacketSize),
GFP_KERNEL);
- if (!mux->shared_intr_buf) {
- dev_err(&interface->dev, "Could not allocate intr buf?\n");
+ if (!mux->shared_intr_buf)
goto exit;
- }
mutex_init(&mux->shared_int_lock);
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c
index 92c49e0a59ec..0192073e53a3 100644
--- a/drivers/net/usb/kalmia.c
+++ b/drivers/net/usb/kalmia.c
@@ -159,7 +159,6 @@ kalmia_bind(struct usbnet *dev, struct usb_interface *intf)
}
memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN);
- memcpy(dev->net->perm_addr, ethernet_addr, ETH_ALEN);
return status;
}
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index a0b5807b30d4..73051d10ead2 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -149,11 +149,9 @@ static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
DECLARE_WAITQUEUE(wait, current);
buffer = kmalloc(size, GFP_KERNEL);
- if (!buffer) {
- netif_warn(pegasus, drv, pegasus->net,
- "out of memory in %s\n", __func__);
+ if (!buffer)
return -ENOMEM;
- }
+
add_wait_queue(&pegasus->ctrl_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
while (pegasus->flags & ETH_REGS_CHANGED)
@@ -1074,8 +1072,9 @@ static void pegasus_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
pegasus_t *pegasus = netdev_priv(dev);
- strncpy(info->driver, driver_name, sizeof(info->driver) - 1);
- strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+
+ strlcpy(info->driver, driver_name, sizeof(info->driver));
+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
usb_make_path(pegasus->usb, info->bus_info, sizeof(info->bus_info));
}
@@ -1096,6 +1095,7 @@ pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
pegasus_t *pegasus = netdev_priv(dev);
u8 reg78 = 0x04;
+ int ret;
if (wol->wolopts & ~WOL_SUPPORTED)
return -EINVAL;
@@ -1110,7 +1110,12 @@ pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
else
pegasus->eth_regs[0] &= ~0x10;
pegasus->wolopts = wol->wolopts;
- return set_register(pegasus, WakeupControl, reg78);
+
+ ret = set_register(pegasus, WakeupControl, reg78);
+ if (!ret)
+ ret = device_set_wakeup_enable(&pegasus->usb->dev,
+ wol->wolopts);
+ return ret;
}
static inline void pegasus_reset_wol(struct net_device *dev)
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 575a5839ee34..efb5c7c33a28 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -351,6 +351,10 @@ static const struct usb_device_id products[] = {
USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 57),
.driver_info = (unsigned long)&qmi_wwan_info,
},
+ { /* HUAWEI_INTERFACE_NDIS_CONTROL_QUALCOMM */
+ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x69),
+ .driver_info = (unsigned long)&qmi_wwan_info,
+ },
/* 2. Combined interface devices matching on class+protocol */
{ /* Huawei E367 and possibly others in "Windows mode" */
@@ -361,6 +365,14 @@ static const struct usb_device_id products[] = {
USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17),
.driver_info = (unsigned long)&qmi_wwan_info,
},
+ { /* HUAWEI_NDIS_SINGLE_INTERFACE_VDF */
+ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x37),
+ .driver_info = (unsigned long)&qmi_wwan_info,
+ },
+ { /* HUAWEI_INTERFACE_NDIS_HW_QUALCOMM */
+ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x67),
+ .driver_info = (unsigned long)&qmi_wwan_info,
+ },
{ /* Pantech UML290, P4200 and more */
USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff),
.driver_info = (unsigned long)&qmi_wwan_info,
@@ -397,8 +409,16 @@ static const struct usb_device_id products[] = {
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long)&qmi_wwan_info,
},
+ { /* ADU960S */
+ USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a,
+ USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET,
+ USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&qmi_wwan_info,
+ },
/* 3. Combined interface devices matching on interface number */
+ {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */
{QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */
{QMI_FIXED_INTF(0x19d2, 0x0002, 1)},
{QMI_FIXED_INTF(0x19d2, 0x0012, 1)},
@@ -461,6 +481,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x1199, 0x901c, 8)}, /* Sierra Wireless EM7700 */
{QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
{QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */
+ {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 4a4335833c36..cc49aac70224 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -431,7 +431,6 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
goto halt_fail_and_release;
}
memcpy(net->dev_addr, bp, ETH_ALEN);
- memcpy(net->perm_addr, bp, ETH_ALEN);
/* set a nonzero filter to enable data transfers */
memset(u.set, 0, sizeof *u.set);
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 5f39a3b225ef..a491d3a95393 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -776,9 +776,9 @@ static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinf
{
rtl8150_t *dev = netdev_priv(netdev);
- strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
- strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
- usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info);
+ strlcpy(info->driver, driver_name, sizeof(info->driver));
+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
}
static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index 18dd4257ab17..79ab2435d9d3 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -459,11 +459,9 @@ static void sierra_net_kevent(struct work_struct *work)
/* Query the modem for the LSI message */
buf = kzalloc(SIERRA_NET_USBCTL_BUF_LEN, GFP_KERNEL);
- if (!buf) {
- netdev_err(dev->net,
- "failed to allocate buf for LS msg\n");
+ if (!buf)
return;
- }
+
ifnum = priv->ifnum;
len = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
USB_CDC_GET_ENCAPSULATED_RESPONSE,
@@ -598,8 +596,8 @@ static void sierra_net_get_drvinfo(struct net_device *net,
{
/* Inherit standard device info */
usbnet_get_drvinfo(net, info);
- strncpy(info->driver, driver_name, sizeof info->driver);
- strncpy(info->version, DRIVER_VERSION, sizeof info->version);
+ strlcpy(info->driver, driver_name, sizeof(info->driver));
+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
}
static u32 sierra_net_get_link(struct net_device *net)
@@ -686,10 +684,8 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
}
/* Initialize sierra private data */
priv = kzalloc(sizeof *priv, GFP_KERNEL);
- if (!priv) {
- dev_err(&dev->udev->dev, "No memory");
+ if (!priv)
return -ENOMEM;
- }
priv->usbnet = dev;
priv->ifnum = ifacenum;
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 251a3354a4b0..9abe51710f22 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -1393,13 +1393,11 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
}
dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc75xx_priv),
- GFP_KERNEL);
+ GFP_KERNEL);
pdata = (struct smsc75xx_priv *)(dev->data[0]);
- if (!pdata) {
- netdev_warn(dev->net, "Unable to allocate smsc75xx_priv\n");
+ if (!pdata)
return -ENOMEM;
- }
pdata->dev = dev;
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 9b736701f854..ff4fa37dfd1d 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -55,6 +55,13 @@
#define FEATURE_PHY_NLP_CROSSOVER (0x02)
#define FEATURE_AUTOSUSPEND (0x04)
+#define SUSPEND_SUSPEND0 (0x01)
+#define SUSPEND_SUSPEND1 (0x02)
+#define SUSPEND_SUSPEND2 (0x04)
+#define SUSPEND_SUSPEND3 (0x08)
+#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
+ SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
+
struct smsc95xx_priv {
u32 mac_cr;
u32 hash_hi;
@@ -62,6 +69,7 @@ struct smsc95xx_priv {
u32 wolopts;
spinlock_t mac_cr_lock;
u8 features;
+ u8 suspend_flags;
};
static bool turbo_mode = true;
@@ -513,10 +521,8 @@ static int smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
u32 flow, afc_cfg = 0;
int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading AFC_CFG\n");
+ if (ret < 0)
return ret;
- }
if (duplex == DUPLEX_FULL) {
u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
@@ -541,16 +547,10 @@ static int smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
}
ret = smsc95xx_write_reg(dev, FLOW, flow);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing FLOW\n");
- return ret;
- }
-
- ret = smsc95xx_write_reg(dev, AFC_CFG, afc_cfg);
if (ret < 0)
- netdev_warn(dev->net, "Error writing AFC_CFG\n");
+ return ret;
- return ret;
+ return smsc95xx_write_reg(dev, AFC_CFG, afc_cfg);
}
static int smsc95xx_link_reset(struct usbnet *dev)
@@ -564,16 +564,12 @@ static int smsc95xx_link_reset(struct usbnet *dev)
/* clear interrupt status */
ret = smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
+ if (ret < 0)
return ret;
- }
ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing INT_STS\n");
+ if (ret < 0)
return ret;
- }
mii_check_media(mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
@@ -595,10 +591,8 @@ static int smsc95xx_link_reset(struct usbnet *dev)
spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing MAC_CR\n");
+ if (ret < 0)
return ret;
- }
ret = smsc95xx_phy_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
if (ret < 0)
@@ -638,10 +632,8 @@ static int smsc95xx_set_features(struct net_device *netdev,
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);
+ if (ret < 0)
return ret;
- }
if (features & NETIF_F_HW_CSUM)
read_buf |= Tx_COE_EN_;
@@ -654,10 +646,8 @@ static int smsc95xx_set_features(struct net_device *netdev,
read_buf &= ~Rx_COE_EN_;
ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write COE_CR: %d\n", ret);
+ if (ret < 0)
return ret;
- }
netif_dbg(dev, hw, dev->net, "COE_CR = 0x%08x\n", read_buf);
return 0;
@@ -800,16 +790,10 @@ static int smsc95xx_set_mac_address(struct usbnet *dev)
int ret;
ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write ADDRL: %d\n", ret);
- return ret;
- }
-
- ret = smsc95xx_write_reg(dev, ADDRH, addr_hi);
if (ret < 0)
- netdev_warn(dev->net, "Failed to write ADDRH: %d\n", ret);
+ return ret;
- return ret;
+ return smsc95xx_write_reg(dev, ADDRH, addr_hi);
}
/* starts the TX path */
@@ -825,17 +809,11 @@ static int smsc95xx_start_tx_path(struct usbnet *dev)
spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write MAC_CR: %d\n", ret);
+ if (ret < 0)
return ret;
- }
/* Enable Tx at SCSRs */
- ret = smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_);
- if (ret < 0)
- netdev_warn(dev->net, "Failed to write TX_CFG: %d\n", ret);
-
- return ret;
+ return smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_);
}
/* Starts the Receive path */
@@ -843,17 +821,12 @@ static int smsc95xx_start_rx_path(struct usbnet *dev, int in_pm)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
unsigned long flags;
- int ret;
spin_lock_irqsave(&pdata->mac_cr_lock, flags);
pdata->mac_cr |= MAC_CR_RXEN_;
spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
- ret = __smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr, in_pm);
- if (ret < 0)
- netdev_warn(dev->net, "Failed to write MAC_CR: %d\n", ret);
-
- return ret;
+ return __smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr, in_pm);
}
static int smsc95xx_phy_initialize(struct usbnet *dev)
@@ -910,19 +883,15 @@ static int smsc95xx_reset(struct usbnet *dev)
netif_dbg(dev, ifup, dev->net, "entering smsc95xx_reset\n");
ret = smsc95xx_write_reg(dev, HW_CFG, HW_CFG_LRST_);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write HW_CFG_LRST_ bit in HW_CFG\n");
+ if (ret < 0)
return ret;
- }
timeout = 0;
do {
msleep(10);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0)
return ret;
- }
timeout++;
} while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
@@ -932,19 +901,15 @@ static int smsc95xx_reset(struct usbnet *dev)
}
ret = smsc95xx_write_reg(dev, PM_CTRL, PM_CTL_PHY_RST_);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write PM_CTRL: %d\n", ret);
+ if (ret < 0)
return ret;
- }
timeout = 0;
do {
msleep(10);
ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read PM_CTRL: %d\n", ret);
+ if (ret < 0)
return ret;
- }
timeout++;
} while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
@@ -961,10 +926,8 @@ static int smsc95xx_reset(struct usbnet *dev)
dev->net->dev_addr);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0)
return ret;
- }
netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x\n",
read_buf);
@@ -972,16 +935,12 @@ static int smsc95xx_reset(struct usbnet *dev)
read_buf |= HW_CFG_BIR_;
ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write HW_CFG_BIR_ bit in HW_CFG\n");
+ if (ret < 0)
return ret;
- }
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0)
return ret;
- }
netif_dbg(dev, ifup, dev->net,
"Read Value from HW_CFG after writing HW_CFG_BIR_: 0x%08x\n",
@@ -1002,42 +961,32 @@ static int smsc95xx_reset(struct usbnet *dev)
(ulong)dev->rx_urb_size);
ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret);
+ if (ret < 0)
return ret;
- }
ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret);
+ if (ret < 0)
return ret;
- }
netif_dbg(dev, ifup, dev->net,
"Read Value from BURST_CAP after writing: 0x%08x\n",
read_buf);
ret = smsc95xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write BULK_IN_DLY: %d\n", ret);
+ if (ret < 0)
return ret;
- }
ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret);
+ if (ret < 0)
return ret;
- }
netif_dbg(dev, ifup, dev->net,
"Read Value from BULK_IN_DLY after writing: 0x%08x\n",
read_buf);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0)
return ret;
- }
netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG: 0x%08x\n",
read_buf);
@@ -1051,69 +1000,51 @@ static int smsc95xx_reset(struct usbnet *dev)
read_buf |= NET_IP_ALIGN << 9;
ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
+ if (ret < 0)
return ret;
- }
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0)
return ret;
- }
netif_dbg(dev, ifup, dev->net,
"Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write INT_STS: %d\n", ret);
+ if (ret < 0)
return ret;
- }
ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
+ if (ret < 0)
return ret;
- }
netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", read_buf);
/* Configure GPIO pins as LED outputs */
write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
LED_GPIO_CFG_FDX_LED;
ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write LED_GPIO_CFG: %d\n", ret);
+ if (ret < 0)
return ret;
- }
/* Init Tx */
ret = smsc95xx_write_reg(dev, FLOW, 0);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret);
+ if (ret < 0)
return ret;
- }
ret = smsc95xx_write_reg(dev, AFC_CFG, AFC_CFG_DEFAULT);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write AFC_CFG: %d\n", ret);
+ if (ret < 0)
return ret;
- }
/* Don't need mac_cr_lock during initialisation */
ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret);
+ if (ret < 0)
return ret;
- }
/* Init Rx */
/* Set Vlan */
ret = smsc95xx_write_reg(dev, VLAN1, (u32)ETH_P_8021Q);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write VLAN1: %d\n", ret);
+ if (ret < 0)
return ret;
- }
/* Enable or disable checksum offload engines */
ret = smsc95xx_set_features(dev->net, dev->net->features);
@@ -1131,19 +1062,15 @@ static int smsc95xx_reset(struct usbnet *dev)
}
ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret);
+ if (ret < 0)
return ret;
- }
/* enable PHY interrupts */
read_buf |= INT_EP_CTL_PHY_INT_;
ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret);
+ if (ret < 0)
return ret;
- }
ret = smsc95xx_start_tx_path(dev);
if (ret < 0) {
@@ -1189,13 +1116,11 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
}
dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc95xx_priv),
- GFP_KERNEL);
+ GFP_KERNEL);
pdata = (struct smsc95xx_priv *)(dev->data[0]);
- if (!pdata) {
- netdev_warn(dev->net, "Unable to allocate struct smsc95xx_priv\n");
+ if (!pdata)
return -ENOMEM;
- }
spin_lock_init(&pdata->mac_cr_lock);
@@ -1213,10 +1138,8 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
/* detect device revision as different features may be available */
ret = smsc95xx_read_reg(dev, ID_REV, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
+ if (ret < 0)
return ret;
- }
val >>= 16;
if ((val == ID_REV_CHIP_ID_9500A_) || (val == ID_REV_CHIP_ID_9530_) ||
@@ -1261,17 +1184,13 @@ static int smsc95xx_enable_phy_wakeup_interrupts(struct usbnet *dev, u16 mask)
/* read to clear */
ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
+ if (ret < 0)
return ret;
- }
/* enable interrupt source */
ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading PHY_INT_MASK\n");
+ if (ret < 0)
return ret;
- }
ret |= mask;
@@ -1287,16 +1206,12 @@ static int smsc95xx_link_ok_nopm(struct usbnet *dev)
/* first, a dummy read, needed to latch some MII phys */
ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading MII_BMSR\n");
+ if (ret < 0)
return ret;
- }
ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading MII_BMSR\n");
+ if (ret < 0)
return ret;
- }
return !!(ret & BMSR_LSTATUS);
}
@@ -1308,19 +1223,15 @@ static int smsc95xx_enter_suspend0(struct usbnet *dev)
int ret;
ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading PM_CTRL\n");
+ if (ret < 0)
return ret;
- }
val &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
val |= PM_CTL_SUS_MODE_0;
ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing PM_CTRL\n");
+ if (ret < 0)
return ret;
- }
/* clear wol status */
val &= ~PM_CTL_WUPS_;
@@ -1331,15 +1242,13 @@ static int smsc95xx_enter_suspend0(struct usbnet *dev)
val |= PM_CTL_WUPS_ED_;
ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing PM_CTRL\n");
+ if (ret < 0)
return ret;
- }
/* read back PM_CTRL */
ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
- if (ret < 0)
- netdev_warn(dev->net, "Error reading PM_CTRL\n");
+
+ pdata->suspend_flags |= SUSPEND_SUSPEND0;
return ret;
}
@@ -1360,10 +1269,8 @@ static int smsc95xx_enter_suspend1(struct usbnet *dev)
/* enable energy detect power-down mode */
ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_MODE_CTRL_STS);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading PHY_MODE_CTRL_STS\n");
+ if (ret < 0)
return ret;
- }
ret |= MODE_CTRL_STS_EDPWRDOWN_;
@@ -1371,52 +1278,133 @@ static int smsc95xx_enter_suspend1(struct usbnet *dev)
/* enter SUSPEND1 mode */
ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading PM_CTRL\n");
+ if (ret < 0)
return ret;
- }
val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
val |= PM_CTL_SUS_MODE_1;
ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing PM_CTRL\n");
+ if (ret < 0)
return ret;
- }
/* clear wol status, enable energy detection */
val &= ~PM_CTL_WUPS_;
val |= (PM_CTL_WUPS_ED_ | PM_CTL_ED_EN_);
ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
- if (ret < 0)
- netdev_warn(dev->net, "Error writing PM_CTRL\n");
+
+ pdata->suspend_flags |= SUSPEND_SUSPEND1;
return ret;
}
static int smsc95xx_enter_suspend2(struct usbnet *dev)
{
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
u32 val;
int ret;
ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading PM_CTRL\n");
+ if (ret < 0)
return ret;
- }
val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
val |= PM_CTL_SUS_MODE_2;
ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
- if (ret < 0)
- netdev_warn(dev->net, "Error writing PM_CTRL\n");
+
+ pdata->suspend_flags |= SUSPEND_SUSPEND2;
return ret;
}
+static int smsc95xx_enter_suspend3(struct usbnet *dev)
+{
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ u32 val;
+ int ret;
+
+ ret = smsc95xx_read_reg_nopm(dev, RX_FIFO_INF, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val & 0xFFFF) {
+ netdev_info(dev->net, "rx fifo not empty in autosuspend\n");
+ return -EBUSY;
+ }
+
+ ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+ if (ret < 0)
+ return ret;
+
+ val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
+ val |= PM_CTL_SUS_MODE_3 | PM_CTL_RES_CLR_WKP_STS;
+
+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+ if (ret < 0)
+ return ret;
+
+ /* clear wol status */
+ val &= ~PM_CTL_WUPS_;
+ val |= PM_CTL_WUPS_WOL_;
+
+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+ if (ret < 0)
+ return ret;
+
+ pdata->suspend_flags |= SUSPEND_SUSPEND3;
+
+ return 0;
+}
+
+static int smsc95xx_autosuspend(struct usbnet *dev, u32 link_up)
+{
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ int ret;
+
+ if (!netif_running(dev->net)) {
+ /* interface is ifconfig down so fully power down hw */
+ netdev_dbg(dev->net, "autosuspend entering SUSPEND2\n");
+ return smsc95xx_enter_suspend2(dev);
+ }
+
+ if (!link_up) {
+ /* link is down so enter EDPD mode, but only if device can
+ * reliably resume from it. This check should be redundant
+ * as current FEATURE_AUTOSUSPEND parts also support
+ * FEATURE_PHY_NLP_CROSSOVER but it's included for clarity */
+ if (!(pdata->features & FEATURE_PHY_NLP_CROSSOVER)) {
+ netdev_warn(dev->net, "EDPD not supported\n");
+ return -EBUSY;
+ }
+
+ netdev_dbg(dev->net, "autosuspend entering SUSPEND1\n");
+
+ /* enable PHY wakeup events for if cable is attached */
+ ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
+ PHY_INT_MASK_ANEG_COMP_);
+ if (ret < 0) {
+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
+ return ret;
+ }
+
+ netdev_info(dev->net, "entering SUSPEND1 mode\n");
+ return smsc95xx_enter_suspend1(dev);
+ }
+
+ /* enable PHY wakeup events so we remote wakeup if cable is pulled */
+ ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
+ PHY_INT_MASK_LINK_DOWN_);
+ if (ret < 0) {
+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
+ return ret;
+ }
+
+ netdev_dbg(dev->net, "autosuspend entering SUSPEND3\n");
+ return smsc95xx_enter_suspend3(dev);
+}
+
static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usbnet *dev = usb_get_intfdata(intf);
@@ -1424,15 +1412,35 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
u32 val, link_up;
int ret;
+ /* TODO: don't indicate this feature to usb framework if
+ * our current hardware doesn't have the capability
+ */
+ if ((message.event == PM_EVENT_AUTO_SUSPEND) &&
+ (!(pdata->features & FEATURE_AUTOSUSPEND))) {
+ netdev_warn(dev->net, "autosuspend not supported\n");
+ return -EBUSY;
+ }
+
ret = usbnet_suspend(intf, message);
if (ret < 0) {
netdev_warn(dev->net, "usbnet_suspend error\n");
return ret;
}
+ if (pdata->suspend_flags) {
+ netdev_warn(dev->net, "error during last resume\n");
+ pdata->suspend_flags = 0;
+ }
+
/* determine if link is up using only _nopm functions */
link_up = smsc95xx_link_ok_nopm(dev);
+ if (message.event == PM_EVENT_AUTO_SUSPEND) {
+ ret = smsc95xx_autosuspend(dev, link_up);
+ goto done;
+ }
+
+ /* if we get this far we're not autosuspending */
/* if no wol options set, or if link is down and we're not waking on
* PHY activity, enter lowest power SUSPEND2 mode
*/
@@ -1442,32 +1450,24 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
/* disable energy detect (link up) & wake up events */
ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading WUCSR\n");
+ if (ret < 0)
goto done;
- }
val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_);
ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing WUCSR\n");
+ if (ret < 0)
goto done;
- }
ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading PM_CTRL\n");
+ if (ret < 0)
goto done;
- }
val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_);
ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing PM_CTRL\n");
+ if (ret < 0)
goto done;
- }
ret = smsc95xx_enter_suspend2(dev);
goto done;
@@ -1565,7 +1565,6 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
for (i = 0; i < (wuff_filter_count * 4); i++) {
ret = smsc95xx_write_reg_nopm(dev, WUFF, filter_mask[i]);
if (ret < 0) {
- netdev_warn(dev->net, "Error writing WUFF\n");
kfree(filter_mask);
goto done;
}
@@ -1574,67 +1573,51 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
for (i = 0; i < (wuff_filter_count / 4); i++) {
ret = smsc95xx_write_reg_nopm(dev, WUFF, command[i]);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing WUFF\n");
+ if (ret < 0)
goto done;
- }
}
for (i = 0; i < (wuff_filter_count / 4); i++) {
ret = smsc95xx_write_reg_nopm(dev, WUFF, offset[i]);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing WUFF\n");
+ if (ret < 0)
goto done;
- }
}
for (i = 0; i < (wuff_filter_count / 2); i++) {
ret = smsc95xx_write_reg_nopm(dev, WUFF, crc[i]);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing WUFF\n");
+ if (ret < 0)
goto done;
- }
}
/* clear any pending pattern match packet status */
ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading WUCSR\n");
+ if (ret < 0)
goto done;
- }
val |= WUCSR_WUFR_;
ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing WUCSR\n");
+ if (ret < 0)
goto done;
- }
}
if (pdata->wolopts & WAKE_MAGIC) {
/* clear any pending magic packet status */
ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading WUCSR\n");
+ if (ret < 0)
goto done;
- }
val |= WUCSR_MPR_;
ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing WUCSR\n");
+ if (ret < 0)
goto done;
- }
}
/* enable/disable wakeup sources */
ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading WUCSR\n");
+ if (ret < 0)
goto done;
- }
if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
netdev_info(dev->net, "enabling pattern match wakeup\n");
@@ -1653,17 +1636,13 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
}
ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing WUCSR\n");
+ if (ret < 0)
goto done;
- }
/* enable wol wakeup source */
ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading PM_CTRL\n");
+ if (ret < 0)
goto done;
- }
val |= PM_CTL_WOL_EN_;
@@ -1672,10 +1651,8 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
val |= PM_CTL_ED_EN_;
ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing PM_CTRL\n");
+ if (ret < 0)
goto done;
- }
/* enable receiver to enable frame reception */
smsc95xx_start_rx_path(dev, 1);
@@ -1694,42 +1671,40 @@ static int smsc95xx_resume(struct usb_interface *intf)
{
struct usbnet *dev = usb_get_intfdata(intf);
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ u8 suspend_flags = pdata->suspend_flags;
int ret;
u32 val;
BUG_ON(!dev);
- if (pdata->wolopts) {
+ netdev_dbg(dev->net, "resume suspend_flags=0x%02x\n", suspend_flags);
+
+ /* do this first to ensure it's cleared even in error case */
+ pdata->suspend_flags = 0;
+
+ if (suspend_flags & SUSPEND_ALLMODES) {
/* clear wake-up sources */
ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading WUCSR\n");
+ if (ret < 0)
return ret;
- }
val &= ~(WUCSR_WAKE_EN_ | WUCSR_MPEN_);
ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing WUCSR\n");
+ if (ret < 0)
return ret;
- }
/* clear wake-up status */
ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error reading PM_CTRL\n");
+ if (ret < 0)
return ret;
- }
val &= ~PM_CTL_WOL_EN_;
val |= PM_CTL_WUPS_;
ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
- if (ret < 0) {
- netdev_warn(dev->net, "Error writing PM_CTRL\n");
+ if (ret < 0)
return ret;
- }
}
ret = usbnet_resume(intf);
@@ -1891,6 +1866,26 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
return skb;
}
+static int smsc95xx_manage_power(struct usbnet *dev, int on)
+{
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+ dev->intf->needs_remote_wakeup = on;
+
+ if (pdata->features & FEATURE_AUTOSUSPEND)
+ return 0;
+
+ /* this chip revision doesn't support autosuspend */
+ netdev_info(dev->net, "hardware doesn't support USB autosuspend\n");
+
+ if (on)
+ usb_autopm_get_interface_no_resume(dev->intf);
+ else
+ usb_autopm_put_interface(dev->intf);
+
+ return 0;
+}
+
static const struct driver_info smsc95xx_info = {
.description = "smsc95xx USB 2.0 Ethernet",
.bind = smsc95xx_bind,
@@ -1900,6 +1895,7 @@ static const struct driver_info smsc95xx_info = {
.rx_fixup = smsc95xx_rx_fixup,
.tx_fixup = smsc95xx_tx_fixup,
.status = smsc95xx_status,
+ .manage_power = smsc95xx_manage_power,
.flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR,
};
@@ -2007,6 +2003,7 @@ static struct usb_driver smsc95xx_driver = {
.reset_resume = smsc95xx_resume,
.disconnect = usbnet_disconnect,
.disable_hub_initiated_lpm = 1,
+ .supports_autosuspend = 1,
};
module_usb_driver(smsc95xx_driver);
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index f34b2ebee815..51f3192f3931 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -380,6 +380,12 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
unsigned long lockflags;
size_t size = dev->rx_urb_size;
+ /* prevent rx skb allocation when error ratio is high */
+ if (test_bit(EVENT_RX_KILL, &dev->flags)) {
+ usb_free_urb(urb);
+ return -ENOLINK;
+ }
+
skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
if (!skb) {
netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
@@ -539,6 +545,17 @@ block:
break;
}
+ /* stop rx if packet error rate is high */
+ if (++dev->pkt_cnt > 30) {
+ dev->pkt_cnt = 0;
+ dev->pkt_err = 0;
+ } else {
+ if (state == rx_cleanup)
+ dev->pkt_err++;
+ if (dev->pkt_err > 20)
+ set_bit(EVENT_RX_KILL, &dev->flags);
+ }
+
state = defer_bh(dev, skb, &dev->rxq, state);
if (urb) {
@@ -791,6 +808,11 @@ int usbnet_open (struct net_device *net)
(dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" :
"simple");
+ /* reset rx error state */
+ dev->pkt_cnt = 0;
+ dev->pkt_err = 0;
+ clear_bit(EVENT_RX_KILL, &dev->flags);
+
// delay posting reads until we're fully open
tasklet_schedule (&dev->bh);
if (info->manage_power) {
@@ -1103,13 +1125,11 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
if (info->tx_fixup) {
skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
if (!skb) {
- if (netif_msg_tx_err(dev)) {
- netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
- goto drop;
- } else {
- /* cdc_ncm collected packet; waits for more */
+ /* packet collected; minidriver waiting for more */
+ if (info->flags & FLAG_MULTI_PACKET)
goto not_drop;
- }
+ netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
+ goto drop;
}
}
length = skb->len;
@@ -1254,6 +1274,9 @@ static void usbnet_bh (unsigned long param)
}
}
+ /* restart RX again after disabling due to high error rate */
+ clear_bit(EVENT_RX_KILL, &dev->flags);
+
// waiting for all pending urbs to complete?
if (dev->wait) {
if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
@@ -1790,11 +1813,8 @@ int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
}
req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
- if (!req) {
- netdev_err(dev->net, "Failed to allocate memory for %s\n",
- __func__);
+ if (!req)
goto fail_free_buf;
- }
req->bRequestType = reqtype;
req->bRequest = cmd;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 95814d9747ef..07a4af0aa3dc 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -25,18 +25,15 @@
#define MIN_MTU 68 /* Min L3 MTU */
#define MAX_MTU 65535 /* Max L3 MTU (arbitrary) */
-struct veth_net_stats {
- u64 rx_packets;
- u64 rx_bytes;
- u64 tx_packets;
- u64 tx_bytes;
- u64 rx_dropped;
+struct pcpu_vstats {
+ u64 packets;
+ u64 bytes;
struct u64_stats_sync syncp;
};
struct veth_priv {
- struct net_device *peer;
- struct veth_net_stats __percpu *stats;
+ struct net_device __rcu *peer;
+ atomic64_t dropped;
};
/*
@@ -92,10 +89,10 @@ static int veth_get_sset_count(struct net_device *dev, int sset)
static void veth_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
- struct veth_priv *priv;
+ struct veth_priv *priv = netdev_priv(dev);
+ struct net_device *peer = rtnl_dereference(priv->peer);
- priv = netdev_priv(dev);
- data[0] = priv->peer->ifindex;
+ data[0] = peer ? peer->ifindex : 0;
}
static const struct ethtool_ops veth_ethtool_ops = {
@@ -107,50 +104,37 @@ static const struct ethtool_ops veth_ethtool_ops = {
.get_ethtool_stats = veth_get_ethtool_stats,
};
-/*
- * xmit
- */
-
static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct net_device *rcv = NULL;
- struct veth_priv *priv, *rcv_priv;
- struct veth_net_stats *stats, *rcv_stats;
- int length;
-
- priv = netdev_priv(dev);
- rcv = priv->peer;
- rcv_priv = netdev_priv(rcv);
-
- stats = this_cpu_ptr(priv->stats);
- rcv_stats = this_cpu_ptr(rcv_priv->stats);
-
+ struct veth_priv *priv = netdev_priv(dev);
+ struct net_device *rcv;
+ int length = skb->len;
+
+ rcu_read_lock();
+ rcv = rcu_dereference(priv->peer);
+ if (unlikely(!rcv)) {
+ kfree_skb(skb);
+ goto drop;
+ }
/* don't change ip_summed == CHECKSUM_PARTIAL, as that
- will cause bad checksum on forwarded packets */
+ * will cause bad checksum on forwarded packets
+ */
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)
- goto rx_drop;
+ if (likely(dev_forward_skb(rcv, skb) == NET_RX_SUCCESS)) {
+ struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);
- u64_stats_update_begin(&stats->syncp);
- stats->tx_bytes += length;
- stats->tx_packets++;
- u64_stats_update_end(&stats->syncp);
-
- u64_stats_update_begin(&rcv_stats->syncp);
- rcv_stats->rx_bytes += length;
- rcv_stats->rx_packets++;
- u64_stats_update_end(&rcv_stats->syncp);
-
- return NETDEV_TX_OK;
-
-rx_drop:
- u64_stats_update_begin(&rcv_stats->syncp);
- rcv_stats->rx_dropped++;
- u64_stats_update_end(&rcv_stats->syncp);
+ u64_stats_update_begin(&stats->syncp);
+ stats->bytes += length;
+ stats->packets++;
+ u64_stats_update_end(&stats->syncp);
+ } else {
+drop:
+ atomic64_inc(&priv->dropped);
+ }
+ rcu_read_unlock();
return NETDEV_TX_OK;
}
@@ -158,47 +142,63 @@ rx_drop:
* general routines
*/
-static struct rtnl_link_stats64 *veth_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot)
+static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev)
{
struct veth_priv *priv = netdev_priv(dev);
int cpu;
+ result->packets = 0;
+ result->bytes = 0;
for_each_possible_cpu(cpu) {
- struct veth_net_stats *stats = per_cpu_ptr(priv->stats, cpu);
- u64 rx_packets, rx_bytes, rx_dropped;
- u64 tx_packets, tx_bytes;
+ struct pcpu_vstats *stats = per_cpu_ptr(dev->vstats, cpu);
+ u64 packets, bytes;
unsigned int start;
do {
start = u64_stats_fetch_begin_bh(&stats->syncp);
- rx_packets = stats->rx_packets;
- tx_packets = stats->tx_packets;
- rx_bytes = stats->rx_bytes;
- tx_bytes = stats->tx_bytes;
- rx_dropped = stats->rx_dropped;
+ packets = stats->packets;
+ bytes = stats->bytes;
} while (u64_stats_fetch_retry_bh(&stats->syncp, start));
- tot->rx_packets += rx_packets;
- tot->tx_packets += tx_packets;
- tot->rx_bytes += rx_bytes;
- tot->tx_bytes += tx_bytes;
- tot->rx_dropped += rx_dropped;
+ result->packets += packets;
+ result->bytes += bytes;
}
+ return atomic64_read(&priv->dropped);
+}
+
+static struct rtnl_link_stats64 *veth_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *tot)
+{
+ struct veth_priv *priv = netdev_priv(dev);
+ struct net_device *peer;
+ struct pcpu_vstats one;
+
+ tot->tx_dropped = veth_stats_one(&one, dev);
+ tot->tx_bytes = one.bytes;
+ tot->tx_packets = one.packets;
+
+ rcu_read_lock();
+ peer = rcu_dereference(priv->peer);
+ if (peer) {
+ tot->rx_dropped = veth_stats_one(&one, peer);
+ tot->rx_bytes = one.bytes;
+ tot->rx_packets = one.packets;
+ }
+ rcu_read_unlock();
return tot;
}
static int veth_open(struct net_device *dev)
{
- struct veth_priv *priv;
+ struct veth_priv *priv = netdev_priv(dev);
+ struct net_device *peer = rtnl_dereference(priv->peer);
- priv = netdev_priv(dev);
- if (priv->peer == NULL)
+ if (!peer)
return -ENOTCONN;
- if (priv->peer->flags & IFF_UP) {
+ if (peer->flags & IFF_UP) {
netif_carrier_on(dev);
- netif_carrier_on(priv->peer);
+ netif_carrier_on(peer);
}
return 0;
}
@@ -206,9 +206,11 @@ static int veth_open(struct net_device *dev)
static int veth_close(struct net_device *dev)
{
struct veth_priv *priv = netdev_priv(dev);
+ struct net_device *peer = rtnl_dereference(priv->peer);
netif_carrier_off(dev);
- netif_carrier_off(priv->peer);
+ if (peer)
+ netif_carrier_off(peer);
return 0;
}
@@ -228,24 +230,16 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu)
static int veth_dev_init(struct net_device *dev)
{
- struct veth_net_stats __percpu *stats;
- struct veth_priv *priv;
-
- stats = alloc_percpu(struct veth_net_stats);
- if (stats == NULL)
+ dev->vstats = alloc_percpu(struct pcpu_vstats);
+ if (!dev->vstats)
return -ENOMEM;
- priv = netdev_priv(dev);
- priv->stats = stats;
return 0;
}
static void veth_dev_free(struct net_device *dev)
{
- struct veth_priv *priv;
-
- priv = netdev_priv(dev);
- free_percpu(priv->stats);
+ free_percpu(dev->vstats);
free_netdev(dev);
}
@@ -259,6 +253,10 @@ static const struct net_device_ops veth_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
};
+#define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
+ NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_HIGHDMA | \
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX)
+
static void veth_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -269,9 +267,10 @@ static void veth_setup(struct net_device *dev)
dev->netdev_ops = &veth_netdev_ops;
dev->ethtool_ops = &veth_ethtool_ops;
dev->features |= NETIF_F_LLTX;
+ dev->features |= VETH_FEATURES;
dev->destructor = veth_dev_free;
- dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_RXCSUM;
+ dev->hw_features = VETH_FEATURES;
}
/*
@@ -396,10 +395,10 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
*/
priv = netdev_priv(dev);
- priv->peer = peer;
+ rcu_assign_pointer(priv->peer, peer);
priv = netdev_priv(peer);
- priv->peer = dev;
+ rcu_assign_pointer(priv->peer, dev);
return 0;
err_register_dev:
@@ -420,10 +419,20 @@ static void veth_dellink(struct net_device *dev, struct list_head *head)
struct net_device *peer;
priv = netdev_priv(dev);
- peer = priv->peer;
+ peer = rtnl_dereference(priv->peer);
+ /* Note : dellink() is called from default_device_exit_batch(),
+ * before a rcu_synchronize() point. The devices are guaranteed
+ * not being freed before one RCU grace period.
+ */
+ RCU_INIT_POINTER(priv->peer, NULL);
unregister_netdevice_queue(dev, head);
- unregister_netdevice_queue(peer, head);
+
+ if (peer) {
+ priv = netdev_priv(peer);
+ RCU_INIT_POINTER(priv->peer, NULL);
+ unregister_netdevice_queue(peer, head);
+ }
}
static const struct nla_policy veth_policy[VETH_INFO_MAX + 1] = {
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 35c00c5ea02a..192c91c8e799 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -227,6 +227,7 @@ static void set_skb_frag(struct sk_buff *skb, struct page *page,
skb->len += size;
skb->truesize += PAGE_SIZE;
skb_shinfo(skb)->nr_frags++;
+ skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
*len -= size;
}
@@ -760,19 +761,77 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
+/*
+ * Send command via the control virtqueue and check status. Commands
+ * supported by the hypervisor, as indicated by feature bits, should
+ * never fail unless improperly formated.
+ */
+static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
+ struct scatterlist *data, int out, int in)
+{
+ struct scatterlist *s, sg[VIRTNET_SEND_COMMAND_SG_MAX + 2];
+ struct virtio_net_ctrl_hdr ctrl;
+ virtio_net_ctrl_ack status = ~0;
+ unsigned int tmp;
+ int i;
+
+ /* Caller should know better */
+ BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ||
+ (out + in > VIRTNET_SEND_COMMAND_SG_MAX));
+
+ out++; /* Add header */
+ in++; /* Add return status */
+
+ ctrl.class = class;
+ ctrl.cmd = cmd;
+
+ sg_init_table(sg, out + in);
+
+ sg_set_buf(&sg[0], &ctrl, sizeof(ctrl));
+ for_each_sg(data, s, out + in - 2, i)
+ sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
+ sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
+
+ BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0);
+
+ virtqueue_kick(vi->cvq);
+
+ /* Spin for a response, the kick causes an ioport write, trapping
+ * into the hypervisor, so the request should be handled immediately.
+ */
+ while (!virtqueue_get_buf(vi->cvq, &tmp))
+ cpu_relax();
+
+ return status == VIRTIO_NET_OK;
+}
+
static int virtnet_set_mac_address(struct net_device *dev, void *p)
{
struct virtnet_info *vi = netdev_priv(dev);
struct virtio_device *vdev = vi->vdev;
int ret;
+ struct sockaddr *addr = p;
+ struct scatterlist sg;
- ret = eth_mac_addr(dev, p);
+ ret = eth_prepare_mac_addr_change(dev, p);
if (ret)
return ret;
- if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC))
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
+ sg_init_one(&sg, addr->sa_data, dev->addr_len);
+ if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC,
+ VIRTIO_NET_CTRL_MAC_ADDR_SET,
+ &sg, 1, 0)) {
+ dev_warn(&vdev->dev,
+ "Failed to set mac address by vq command.\n");
+ return -EINVAL;
+ }
+ } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
vdev->config->set(vdev, offsetof(struct virtio_net_config, mac),
- dev->dev_addr, dev->addr_len);
+ addr->sa_data, dev->addr_len);
+ }
+
+ eth_commit_mac_addr_change(dev, p);
return 0;
}
@@ -826,51 +885,6 @@ static void virtnet_netpoll(struct net_device *dev)
}
#endif
-/*
- * Send command via the control virtqueue and check status. Commands
- * supported by the hypervisor, as indicated by feature bits, should
- * never fail unless improperly formated.
- */
-static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
- struct scatterlist *data, int out, int in)
-{
- struct scatterlist *s, sg[VIRTNET_SEND_COMMAND_SG_MAX + 2];
- struct virtio_net_ctrl_hdr ctrl;
- virtio_net_ctrl_ack status = ~0;
- unsigned int tmp;
- int i;
-
- /* Caller should know better */
- BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ||
- (out + in > VIRTNET_SEND_COMMAND_SG_MAX));
-
- out++; /* Add header */
- in++; /* Add return status */
-
- ctrl.class = class;
- ctrl.cmd = cmd;
-
- sg_init_table(sg, out + in);
-
- sg_set_buf(&sg[0], &ctrl, sizeof(ctrl));
- for_each_sg(data, s, out + in - 2, i)
- sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
- sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
-
- BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0);
-
- virtqueue_kick(vi->cvq);
-
- /*
- * Spin for a response, the kick causes an ioport write, trapping
- * into the hypervisor, so the request should be handled immediately.
- */
- while (!virtqueue_get_buf(vi->cvq, &tmp))
- cpu_relax();
-
- return status == VIRTIO_NET_OK;
-}
-
static void virtnet_ack_link_announce(struct virtnet_info *vi)
{
rtnl_lock();
@@ -959,10 +973,8 @@ static void virtnet_set_rx_mode(struct net_device *dev)
buf = kzalloc(((uc_count + mc_count) * ETH_ALEN) +
(2 * sizeof(mac_data->entries)), GFP_ATOMIC);
mac_data = buf;
- if (!buf) {
- dev_warn(&dev->dev, "No memory for MAC address buffer\n");
+ if (!buf)
return;
- }
sg_init_table(sg, 2);
@@ -1706,6 +1718,7 @@ static unsigned int features[] = {
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
+ VIRTIO_NET_F_CTRL_MAC_ADDR,
};
static struct virtio_driver virtio_net_driver = {
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index dc8913c6238c..ffb97b2a15a0 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -43,11 +43,7 @@ static DEFINE_PCI_DEVICE_TABLE(vmxnet3_pciid_table) = {
MODULE_DEVICE_TABLE(pci, vmxnet3_pciid_table);
-static atomic_t devices_found;
-
-#define VMXNET3_MAX_DEVICES 10
static int enable_mq = 1;
-static int irq_share_mode;
static void
vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac);
@@ -152,10 +148,9 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
adapter->link_speed = ret >> 16;
if (ret & 1) { /* Link is up. */
- printk(KERN_INFO "%s: NIC Link is Up %d Mbps\n",
- adapter->netdev->name, adapter->link_speed);
- if (!netif_carrier_ok(adapter->netdev))
- netif_carrier_on(adapter->netdev);
+ netdev_info(adapter->netdev, "NIC Link is Up %d Mbps\n",
+ adapter->link_speed);
+ netif_carrier_on(adapter->netdev);
if (affectTxQueue) {
for (i = 0; i < adapter->num_tx_queues; i++)
@@ -163,10 +158,8 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
adapter);
}
} else {
- printk(KERN_INFO "%s: NIC Link is Down\n",
- adapter->netdev->name);
- if (netif_carrier_ok(adapter->netdev))
- netif_carrier_off(adapter->netdev);
+ netdev_info(adapter->netdev, "NIC Link is Down\n");
+ netif_carrier_off(adapter->netdev);
if (affectTxQueue) {
for (i = 0; i < adapter->num_tx_queues; i++)
@@ -510,8 +503,7 @@ vmxnet3_tq_create(struct vmxnet3_tx_queue *tq,
* sizeof(struct Vmxnet3_TxDesc),
&tq->tx_ring.basePA);
if (!tq->tx_ring.base) {
- printk(KERN_ERR "%s: failed to allocate tx ring\n",
- adapter->netdev->name);
+ netdev_err(adapter->netdev, "failed to allocate tx ring\n");
goto err;
}
@@ -520,8 +512,7 @@ vmxnet3_tq_create(struct vmxnet3_tx_queue *tq,
sizeof(struct Vmxnet3_TxDataDesc),
&tq->data_ring.basePA);
if (!tq->data_ring.base) {
- printk(KERN_ERR "%s: failed to allocate data ring\n",
- adapter->netdev->name);
+ netdev_err(adapter->netdev, "failed to allocate data ring\n");
goto err;
}
@@ -530,8 +521,7 @@ vmxnet3_tq_create(struct vmxnet3_tx_queue *tq,
sizeof(struct Vmxnet3_TxCompDesc),
&tq->comp_ring.basePA);
if (!tq->comp_ring.base) {
- printk(KERN_ERR "%s: failed to allocate tx comp ring\n",
- adapter->netdev->name);
+ netdev_err(adapter->netdev, "failed to allocate tx comp ring\n");
goto err;
}
@@ -580,15 +570,14 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
if (rbi->buf_type == VMXNET3_RX_BUF_SKB) {
if (rbi->skb == NULL) {
- rbi->skb = dev_alloc_skb(rbi->len +
- NET_IP_ALIGN);
+ rbi->skb = __netdev_alloc_skb_ip_align(adapter->netdev,
+ rbi->len,
+ GFP_KERNEL);
if (unlikely(rbi->skb == NULL)) {
rq->stats.rx_buf_alloc_failure++;
break;
}
- rbi->skb->dev = adapter->netdev;
- skb_reserve(rbi->skb, NET_IP_ALIGN);
rbi->dma_addr = pci_map_single(adapter->pdev,
rbi->skb->data, rbi->len,
PCI_DMA_FROMDEVICE);
@@ -629,12 +618,10 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
num_allocated++;
vmxnet3_cmd_ring_adv_next2fill(ring);
}
- rq->uncommitted[ring_idx] += num_allocated;
- dev_dbg(&adapter->netdev->dev,
- "alloc_rx_buf: %d allocated, next2fill %u, next2comp "
- "%u, uncommitted %u\n", num_allocated, ring->next2fill,
- ring->next2comp, rq->uncommitted[ring_idx]);
+ netdev_dbg(adapter->netdev,
+ "alloc_rx_buf: %d allocated, next2fill %u, next2comp %u\n",
+ num_allocated, ring->next2fill, ring->next2comp);
/* so that the device can distinguish a full ring and an empty ring */
BUG_ON(num_allocated != 0 && ring->next2fill == ring->next2comp);
@@ -691,7 +678,7 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
tbi = tq->buf_info + tq->tx_ring.next2fill;
tbi->map_type = VMXNET3_MAP_NONE;
- dev_dbg(&adapter->netdev->dev,
+ netdev_dbg(adapter->netdev,
"txd[%u]: 0x%Lx 0x%x 0x%x\n",
tq->tx_ring.next2fill,
le64_to_cpu(ctx->sop_txd->txd.addr),
@@ -731,7 +718,7 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
gdesc->dword[2] = cpu_to_le32(dw2);
gdesc->dword[3] = 0;
- dev_dbg(&adapter->netdev->dev,
+ netdev_dbg(adapter->netdev,
"txd[%u]: 0x%Lx 0x%x 0x%x\n",
tq->tx_ring.next2fill, le64_to_cpu(gdesc->txd.addr),
le32_to_cpu(gdesc->dword[2]), gdesc->dword[3]);
@@ -771,7 +758,7 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
gdesc->dword[2] = cpu_to_le32(dw2);
gdesc->dword[3] = 0;
- dev_dbg(&adapter->netdev->dev,
+ netdev_dbg(adapter->netdev,
"txd[%u]: 0x%llu %u %u\n",
tq->tx_ring.next2fill, le64_to_cpu(gdesc->txd.addr),
le32_to_cpu(gdesc->dword[2]), gdesc->dword[3]);
@@ -871,7 +858,7 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
tdd = tq->data_ring.base + tq->tx_ring.next2fill;
memcpy(tdd->data, skb->data, ctx->copy_size);
- dev_dbg(&adapter->netdev->dev,
+ netdev_dbg(adapter->netdev,
"copy %u bytes to dataRing[%u]\n",
ctx->copy_size, tq->tx_ring.next2fill);
return 1;
@@ -977,7 +964,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
tq->stats.tx_ring_full++;
- dev_dbg(&adapter->netdev->dev,
+ netdev_dbg(adapter->netdev,
"tx queue stopped on %s, next2comp %u"
" next2fill %u\n", adapter->netdev->name,
tq->tx_ring.next2comp, tq->tx_ring.next2fill);
@@ -1060,7 +1047,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
(struct Vmxnet3_TxDesc *)ctx.sop_txd);
gdesc = ctx.sop_txd;
#endif
- dev_dbg(&adapter->netdev->dev,
+ netdev_dbg(adapter->netdev,
"txd[%u]: SOP 0x%Lx 0x%x 0x%x\n",
(u32)(ctx.sop_txd -
tq->tx_ring.base), le64_to_cpu(gdesc->txd.addr),
@@ -1213,7 +1200,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
if (unlikely(rcd->len == 0)) {
/* Pretend the rx buffer is skipped. */
BUG_ON(!(rcd->sop && rcd->eop));
- dev_dbg(&adapter->netdev->dev,
+ netdev_dbg(adapter->netdev,
"rxRing[%u][%u] 0 length\n",
ring_idx, idx);
goto rcd_done;
@@ -1221,7 +1208,8 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
skip_page_frags = false;
ctx->skb = rbi->skb;
- new_skb = dev_alloc_skb(rbi->len + NET_IP_ALIGN);
+ new_skb = netdev_alloc_skb_ip_align(adapter->netdev,
+ rbi->len);
if (new_skb == NULL) {
/* Skb allocation failed, do not handover this
* skb to stack. Reuse it. Drop the existing pkt
@@ -1236,11 +1224,14 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
pci_unmap_single(adapter->pdev, rbi->dma_addr, rbi->len,
PCI_DMA_FROMDEVICE);
+#ifdef VMXNET3_RSS
+ if (rcd->rssType != VMXNET3_RCD_RSS_TYPE_NONE &&
+ (adapter->netdev->features & NETIF_F_RXHASH))
+ ctx->skb->rxhash = le32_to_cpu(rcd->rssHash);
+#endif
skb_put(ctx->skb, rcd->len);
/* Immediate refill */
- new_skb->dev = adapter->netdev;
- skb_reserve(new_skb, NET_IP_ALIGN);
rbi->skb = new_skb;
rbi->dma_addr = pci_map_single(adapter->pdev,
rbi->skb->data, rbi->len,
@@ -1333,7 +1324,6 @@ rcd_done:
VMXNET3_WRITE_BAR0_REG(adapter,
rxprod_reg[ring_idx] + rq->qid * 8,
ring->next2fill);
- rq->uncommitted[ring_idx] = 0;
}
vmxnet3_comp_ring_adv_next2proc(&rq->comp_ring);
@@ -1378,7 +1368,6 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq,
rq->rx_ring[ring_idx].gen = VMXNET3_INIT_GEN;
rq->rx_ring[ring_idx].next2fill =
rq->rx_ring[ring_idx].next2comp = 0;
- rq->uncommitted[ring_idx] = 0;
}
rq->comp_ring.gen = VMXNET3_INIT_GEN;
@@ -1459,7 +1448,6 @@ vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
/* reset internal state and allocate buffers for both rings */
for (i = 0; i < 2; i++) {
rq->rx_ring[i].next2fill = rq->rx_ring[i].next2comp = 0;
- rq->uncommitted[i] = 0;
memset(rq->rx_ring[i].base, 0, rq->rx_ring[i].size *
sizeof(struct Vmxnet3_RxDesc));
@@ -1518,8 +1506,8 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter)
rq->rx_ring[i].base = pci_alloc_consistent(adapter->pdev, sz,
&rq->rx_ring[i].basePA);
if (!rq->rx_ring[i].base) {
- printk(KERN_ERR "%s: failed to allocate rx ring %d\n",
- adapter->netdev->name, i);
+ netdev_err(adapter->netdev,
+ "failed to allocate rx ring %d\n", i);
goto err;
}
}
@@ -1528,8 +1516,7 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter)
rq->comp_ring.base = pci_alloc_consistent(adapter->pdev, sz,
&rq->comp_ring.basePA);
if (!rq->comp_ring.base) {
- printk(KERN_ERR "%s: failed to allocate rx comp ring\n",
- adapter->netdev->name);
+ netdev_err(adapter->netdev, "failed to allocate rx comp ring\n");
goto err;
}
@@ -1821,9 +1808,10 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
adapter->rx_queue[i].name,
&(adapter->rx_queue[i]));
if (err) {
- printk(KERN_ERR "Failed to request irq for MSIX"
- ", %s, error %d\n",
- adapter->rx_queue[i].name, err);
+ netdev_err(adapter->netdev,
+ "Failed to request irq for MSIX, "
+ "%s, error %d\n",
+ adapter->rx_queue[i].name, err);
return err;
}
@@ -1852,8 +1840,9 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
#endif
intr->num_intrs = vector + 1;
if (err) {
- printk(KERN_ERR "Failed to request irq %s (intr type:%d), error"
- ":%d\n", adapter->netdev->name, intr->type, err);
+ netdev_err(adapter->netdev,
+ "Failed to request irq (intr type:%d), error %d\n",
+ intr->type, err);
} else {
/* Number of rx queues will not change after this */
for (i = 0; i < adapter->num_rx_queues; i++) {
@@ -1874,9 +1863,9 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
adapter->rx_queue[0].comp_ring.intr_idx = 0;
}
- printk(KERN_INFO "%s: intr type %u, mode %u, %u vectors "
- "allocated\n", adapter->netdev->name, intr->type,
- intr->mask_mode, intr->num_intrs);
+ netdev_info(adapter->netdev,
+ "intr type %u, mode %u, %u vectors allocated\n",
+ intr->type, intr->mask_mode, intr->num_intrs);
}
return err;
@@ -2042,8 +2031,8 @@ vmxnet3_set_mc(struct net_device *netdev)
rxConf->mfTablePA = cpu_to_le64(virt_to_phys(
new_table));
} else {
- printk(KERN_INFO "%s: failed to copy mcast list"
- ", setting ALL_MULTI\n", netdev->name);
+ netdev_info(netdev, "failed to copy mcast list"
+ ", setting ALL_MULTI\n");
new_mode |= VMXNET3_RXM_ALL_MULTI;
}
}
@@ -2171,6 +2160,14 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
if (adapter->rss) {
struct UPT1_RSSConf *rssConf = adapter->rss_conf;
+ static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
+ 0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
+ 0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
+ 0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
+ 0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
+ 0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
+ };
+
devRead->misc.uptFeatures |= UPT1_F_RSS;
devRead->misc.numRxQueues = adapter->num_rx_queues;
rssConf->hashType = UPT1_RSS_HASH_TYPE_TCP_IPV4 |
@@ -2180,7 +2177,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
rssConf->hashFunc = UPT1_RSS_HASH_FUNC_TOEPLITZ;
rssConf->hashKeySize = UPT1_RSS_MAX_KEY_SIZE;
rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE;
- get_random_bytes(&rssConf->hashKey[0], rssConf->hashKeySize);
+ memcpy(rssConf->hashKey, rss_key, sizeof(rss_key));
+
for (i = 0; i < rssConf->indTableSize; i++)
rssConf->indTable[i] = ethtool_rxfh_indir_default(
i, adapter->num_rx_queues);
@@ -2218,7 +2216,7 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
u32 ret;
unsigned long flags;
- dev_dbg(&adapter->netdev->dev, "%s: skb_buf_size %d, rx_buf_per_pkt %d,"
+ netdev_dbg(adapter->netdev, "%s: skb_buf_size %d, rx_buf_per_pkt %d,"
" ring sizes %u %u %u\n", adapter->netdev->name,
adapter->skb_buf_size, adapter->rx_buf_per_pkt,
adapter->tx_queue[0].tx_ring.size,
@@ -2228,15 +2226,15 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
vmxnet3_tq_init_all(adapter);
err = vmxnet3_rq_init_all(adapter);
if (err) {
- printk(KERN_ERR "Failed to init rx queue for %s: error %d\n",
- adapter->netdev->name, err);
+ netdev_err(adapter->netdev,
+ "Failed to init rx queue error %d\n", err);
goto rq_err;
}
err = vmxnet3_request_irqs(adapter);
if (err) {
- printk(KERN_ERR "Failed to setup irq for %s: error %d\n",
- adapter->netdev->name, err);
+ netdev_err(adapter->netdev,
+ "Failed to setup irq for error %d\n", err);
goto irq_err;
}
@@ -2253,8 +2251,8 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
spin_unlock_irqrestore(&adapter->cmd_lock, flags);
if (ret != 0) {
- printk(KERN_ERR "Failed to activate dev %s: error %u\n",
- adapter->netdev->name, ret);
+ netdev_err(adapter->netdev,
+ "Failed to activate dev: error %u\n", ret);
err = -EINVAL;
goto activate_err;
}
@@ -2369,23 +2367,22 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64)
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR "Failed to enable adapter %s: error %d\n",
- pci_name(pdev), err);
+ dev_err(&pdev->dev, "Failed to enable adapter: error %d\n", err);
return err;
}
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
- printk(KERN_ERR "pci_set_consistent_dma_mask failed "
- "for adapter %s\n", pci_name(pdev));
+ dev_err(&pdev->dev,
+ "pci_set_consistent_dma_mask failed\n");
err = -EIO;
goto err_set_mask;
}
*dma64 = true;
} else {
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
- printk(KERN_ERR "pci_set_dma_mask failed for adapter "
- "%s\n", pci_name(pdev));
+ dev_err(&pdev->dev,
+ "pci_set_dma_mask failed\n");
err = -EIO;
goto err_set_mask;
}
@@ -2395,8 +2392,8 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64)
err = pci_request_selected_regions(pdev, (1 << 2) - 1,
vmxnet3_driver_name);
if (err) {
- printk(KERN_ERR "Failed to request region for adapter %s: "
- "error %d\n", pci_name(pdev), err);
+ dev_err(&pdev->dev,
+ "Failed to request region for adapter: error %d\n", err);
goto err_set_mask;
}
@@ -2406,8 +2403,7 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64)
mmio_len = pci_resource_len(pdev, 0);
adapter->hw_addr0 = ioremap(mmio_start, mmio_len);
if (!adapter->hw_addr0) {
- printk(KERN_ERR "Failed to map bar0 for adapter %s\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "Failed to map bar0\n");
err = -EIO;
goto err_ioremap;
}
@@ -2416,8 +2412,7 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64)
mmio_len = pci_resource_len(pdev, 1);
adapter->hw_addr1 = ioremap(mmio_start, mmio_len);
if (!adapter->hw_addr1) {
- printk(KERN_ERR "Failed to map bar1 for adapter %s\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "Failed to map bar1\n");
err = -EIO;
goto err_bar1;
}
@@ -2524,12 +2519,14 @@ vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size,
err = vmxnet3_rq_create(rq, adapter);
if (err) {
if (i == 0) {
- printk(KERN_ERR "Could not allocate any rx"
- "queues. Aborting.\n");
+ netdev_err(adapter->netdev,
+ "Could not allocate any rx queues. "
+ "Aborting.\n");
goto queue_err;
} else {
- printk(KERN_INFO "Number of rx queues changed "
- "to : %d.\n", i);
+ netdev_info(adapter->netdev,
+ "Number of rx queues changed "
+ "to : %d.\n", i);
adapter->num_rx_queues = i;
err = 0;
break;
@@ -2642,15 +2639,17 @@ vmxnet3_change_mtu(struct net_device *netdev, int new_mtu)
vmxnet3_adjust_rx_ring_size(adapter);
err = vmxnet3_rq_create_all(adapter);
if (err) {
- printk(KERN_ERR "%s: failed to re-create rx queues,"
- " error %d. Closing it.\n", netdev->name, err);
+ netdev_err(netdev,
+ "failed to re-create rx queues, "
+ " error %d. Closing it.\n", err);
goto out;
}
err = vmxnet3_activate_dev(adapter);
if (err) {
- printk(KERN_ERR "%s: failed to re-activate, error %d. "
- "Closing it\n", netdev->name, err);
+ netdev_err(netdev,
+ "failed to re-activate, error %d. "
+ "Closing it\n", err);
goto out;
}
}
@@ -2678,10 +2677,6 @@ vmxnet3_declare_features(struct vmxnet3_adapter *adapter, bool dma64)
netdev->vlan_features = netdev->hw_features &
~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_FILTER;
-
- netdev_info(adapter->netdev,
- "features: sg csum vlan jf tso tsoIPv6 lro%s\n",
- dma64 ? " highDMA" : "");
}
@@ -2724,7 +2719,7 @@ vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter,
adapter->intr.num_intrs = vectors;
return 0;
} else if (err < 0) {
- netdev_err(adapter->netdev,
+ dev_err(&adapter->netdev->dev,
"Failed to enable MSI-X, error: %d\n", err);
vectors = 0;
} else if (err < vector_threshold) {
@@ -2733,15 +2728,16 @@ vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter,
/* If fails to enable required number of MSI-x vectors
* try enabling minimum number of vectors required.
*/
- netdev_err(adapter->netdev,
- "Failed to enable %d MSI-X, trying %d instead\n",
+ dev_err(&adapter->netdev->dev,
+ "Failed to enable %d MSI-X, trying %d instead\n",
vectors, vector_threshold);
vectors = vector_threshold;
}
}
- netdev_info(adapter->netdev,
- "Number of MSI-X interrupts which can be allocated are lower than min threshold required.\n");
+ dev_info(&adapter->pdev->dev,
+ "Number of MSI-X interrupts which can be allocated "
+ "is lower than min threshold required.\n");
return err;
}
@@ -2796,7 +2792,8 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
|| adapter->num_rx_queues != 1) {
adapter->share_intr = VMXNET3_INTR_TXSHARE;
- printk(KERN_ERR "Number of rx queues : 1\n");
+ netdev_err(adapter->netdev,
+ "Number of rx queues : 1\n");
adapter->num_rx_queues = 1;
adapter->intr.num_intrs =
VMXNET3_LINUX_MIN_MSIX_VECT;
@@ -2807,9 +2804,9 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
return;
/* If we cannot allocate MSIx vectors use only one rx queue */
- netdev_info(adapter->netdev,
- "Failed to enable MSI-X, error %d . Limiting #rx queues to 1, try MSI.\n",
- err);
+ dev_info(&adapter->pdev->dev,
+ "Failed to enable MSI-X, error %d. "
+ "Limiting #rx queues to 1, try MSI.\n", err);
adapter->intr.type = VMXNET3_IT_MSI;
}
@@ -2826,7 +2823,8 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
#endif /* CONFIG_PCI_MSI */
adapter->num_rx_queues = 1;
- printk(KERN_INFO "Using INTx interrupt, #Rx queues: 1.\n");
+ dev_info(&adapter->netdev->dev,
+ "Using INTx interrupt, #Rx queues: 1.\n");
adapter->intr.type = VMXNET3_IT_INTX;
/* INT-X related setting */
@@ -2852,7 +2850,7 @@ vmxnet3_tx_timeout(struct net_device *netdev)
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
adapter->tx_timeout_count++;
- printk(KERN_ERR "%s: tx hang\n", adapter->netdev->name);
+ netdev_err(adapter->netdev, "tx hang\n");
schedule_work(&adapter->work);
netif_wake_queue(adapter->netdev);
}
@@ -2872,12 +2870,12 @@ vmxnet3_reset_work(struct work_struct *data)
/* if the device is closed, we must leave it alone */
rtnl_lock();
if (netif_running(adapter->netdev)) {
- printk(KERN_INFO "%s: resetting\n", adapter->netdev->name);
+ netdev_notice(adapter->netdev, "resetting\n");
vmxnet3_quiesce_dev(adapter);
vmxnet3_reset_dev(adapter);
vmxnet3_activate_dev(adapter);
} else {
- printk(KERN_INFO "%s: already closed\n", adapter->netdev->name);
+ netdev_info(adapter->netdev, "already closed\n");
}
rtnl_unlock();
@@ -2936,8 +2934,9 @@ vmxnet3_probe_device(struct pci_dev *pdev,
num_tx_queues = rounddown_pow_of_two(num_tx_queues);
netdev = alloc_etherdev_mq(sizeof(struct vmxnet3_adapter),
max(num_tx_queues, num_rx_queues));
- printk(KERN_INFO "# of Tx queues : %d, # of Rx queues : %d\n",
- num_tx_queues, num_rx_queues);
+ dev_info(&pdev->dev,
+ "# of Tx queues : %d, # of Rx queues : %d\n",
+ num_tx_queues, num_rx_queues);
if (!netdev)
return -ENOMEM;
@@ -2952,8 +2951,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
sizeof(struct Vmxnet3_DriverShared),
&adapter->shared_pa);
if (!adapter->shared) {
- printk(KERN_ERR "Failed to allocate memory for %s\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "Failed to allocate memory\n");
err = -ENOMEM;
goto err_alloc_shared;
}
@@ -2967,8 +2965,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
&adapter->queue_desc_pa);
if (!adapter->tqd_start) {
- printk(KERN_ERR "Failed to allocate memory for %s\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "Failed to allocate memory\n");
err = -ENOMEM;
goto err_alloc_queue_desc;
}
@@ -2998,8 +2995,8 @@ vmxnet3_probe_device(struct pci_dev *pdev,
if (ver & 1) {
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1);
} else {
- printk(KERN_ERR "Incompatible h/w version (0x%x) for adapter"
- " %s\n", ver, pci_name(pdev));
+ dev_err(&pdev->dev,
+ "Incompatible h/w version (0x%x) for adapter\n", ver);
err = -EBUSY;
goto err_ver;
}
@@ -3008,8 +3005,8 @@ vmxnet3_probe_device(struct pci_dev *pdev,
if (ver & 1) {
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_UVRS, 1);
} else {
- printk(KERN_ERR "Incompatible upt version (0x%x) for "
- "adapter %s\n", ver, pci_name(pdev));
+ dev_err(&pdev->dev,
+ "Incompatible upt version (0x%x) for adapter\n", ver);
err = -EBUSY;
goto err_ver;
}
@@ -3017,11 +3014,9 @@ vmxnet3_probe_device(struct pci_dev *pdev,
SET_NETDEV_DEV(netdev, &pdev->dev);
vmxnet3_declare_features(adapter, dma64);
- adapter->dev_number = atomic_read(&devices_found);
-
- adapter->share_intr = irq_share_mode;
- if (adapter->share_intr == VMXNET3_INTR_BUDDYSHARE &&
- adapter->num_tx_queues != adapter->num_rx_queues)
+ if (adapter->num_tx_queues == adapter->num_rx_queues)
+ adapter->share_intr = VMXNET3_INTR_BUDDYSHARE;
+ else
adapter->share_intr = VMXNET3_INTR_DONTSHARE;
vmxnet3_alloc_intr_resources(adapter);
@@ -3030,7 +3025,9 @@ vmxnet3_probe_device(struct pci_dev *pdev,
if (adapter->num_rx_queues > 1 &&
adapter->intr.type == VMXNET3_IT_MSIX) {
adapter->rss = true;
- printk(KERN_INFO "RSS is enabled.\n");
+ netdev->hw_features |= NETIF_F_RXHASH;
+ netdev->features |= NETIF_F_RXHASH;
+ dev_dbg(&pdev->dev, "RSS is enabled.\n");
} else {
adapter->rss = false;
}
@@ -3061,16 +3058,15 @@ vmxnet3_probe_device(struct pci_dev *pdev,
netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues);
netif_set_real_num_rx_queues(adapter->netdev, adapter->num_rx_queues);
+ netif_carrier_off(netdev);
err = register_netdev(netdev);
if (err) {
- printk(KERN_ERR "Failed to register adapter %s\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "Failed to register adapter\n");
goto err_register;
}
vmxnet3_check_link(adapter, false);
- atomic_inc(&devices_found);
return 0;
err_register:
@@ -3312,7 +3308,7 @@ static struct pci_driver vmxnet3_driver = {
static int __init
vmxnet3_init_module(void)
{
- printk(KERN_INFO "%s - version %s\n", VMXNET3_DRIVER_DESC,
+ pr_info("%s - version %s\n", VMXNET3_DRIVER_DESC,
VMXNET3_DRIVER_VERSION_REPORT);
return pci_register_driver(&vmxnet3_driver);
}
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 587a218b2345..9bc542be2937 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -207,7 +207,7 @@ vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
sizeof(drvinfo->version));
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
- ETHTOOL_BUSINFO_LEN);
+ sizeof(drvinfo->bus_info));
drvinfo->n_stats = vmxnet3_get_sset_count(netdev, ETH_SS_STATS);
drvinfo->testinfo_len = 0;
drvinfo->eedump_len = 0;
@@ -522,24 +522,23 @@ vmxnet3_set_ringparam(struct net_device *netdev,
if (err) {
/* failed, most likely because of OOM, try default
* size */
- printk(KERN_ERR "%s: failed to apply new sizes, try the"
- " default ones\n", netdev->name);
+ netdev_err(netdev, "failed to apply new sizes, "
+ "try the default ones\n");
err = vmxnet3_create_queues(adapter,
VMXNET3_DEF_TX_RING_SIZE,
VMXNET3_DEF_RX_RING_SIZE,
VMXNET3_DEF_RX_RING_SIZE);
if (err) {
- printk(KERN_ERR "%s: failed to create queues "
- "with default sizes. Closing it\n",
- netdev->name);
+ netdev_err(netdev, "failed to create queues "
+ "with default sizes. Closing it\n");
goto out;
}
}
err = vmxnet3_activate_dev(adapter);
if (err)
- printk(KERN_ERR "%s: failed to re-activate, error %d."
- " Closing it\n", netdev->name, err);
+ netdev_err(netdev, "failed to re-activate, error %d."
+ " Closing it\n", err);
}
out:
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index fc46a81ad538..3198384689d9 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -276,8 +276,6 @@ struct vmxnet3_rx_queue {
struct vmxnet3_rx_ctx rx_ctx;
u32 qid; /* rqID in RCD for buffer from 1st ring */
u32 qid2; /* rqID in RCD for buffer from 2nd ring */
- u32 uncommitted[2]; /* # of buffers allocated since last RXPROD
- * update */
struct vmxnet3_rx_buf_info *buf_info[2];
struct Vmxnet3_RxQueueCtrl *shared;
struct vmxnet3_rq_driver_stats stats;
@@ -354,7 +352,6 @@ struct vmxnet3_adapter {
unsigned long state; /* VMXNET3_STATE_BIT_xxx */
- int dev_number;
int share_intr;
};
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 656230e0d18c..9d70421cf3a0 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -29,6 +29,7 @@
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/hash.h>
+#include <linux/ethtool.h>
#include <net/arp.h>
#include <net/ndisc.h>
#include <net/ip.h>
@@ -392,7 +393,8 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
}
/* Delete entry (via netlink) */
-static int vxlan_fdb_delete(struct ndmsg *ndm, struct net_device *dev,
+static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
+ struct net_device *dev,
const unsigned char *addr)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
@@ -1271,6 +1273,18 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
return 0;
}
+static void vxlan_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ strlcpy(drvinfo->version, VXLAN_VERSION, sizeof(drvinfo->version));
+ strlcpy(drvinfo->driver, "vxlan", sizeof(drvinfo->driver));
+}
+
+static const struct ethtool_ops vxlan_ethtool_ops = {
+ .get_drvinfo = vxlan_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
+
static int vxlan_newlink(struct net *net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
@@ -1348,6 +1362,8 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
vxlan->port_max = ntohs(p->high);
}
+ SET_ETHTOOL_OPS(dev, &vxlan_ethtool_ops);
+
err = register_netdevice(dev);
if (!err)
hlist_add_head_rcu(&vxlan->hlist, vni_head(net, vxlan->vni));
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index d58431e99f73..94e234975c61 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -356,63 +356,9 @@ config SDLA
To compile this driver as a module, choose M here: the
module will be called sdla.
-# Wan router core.
-config WAN_ROUTER_DRIVERS
- tristate "WAN router drivers"
- depends on WAN_ROUTER
- ---help---
- Connect LAN to WAN via Linux box.
-
- Select driver your card and remember to say Y to "Wan Router."
- You will need the wan-tools package which is available from
- <ftp://ftp.sangoma.com/>.
-
- Note that the answer to this question won't directly affect the
- kernel except for how subordinate drivers may be built:
- saying N will just cause the configurator to skip all
- the questions about WAN router drivers.
-
- If unsure, say N.
-
-config CYCLADES_SYNC
- tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)"
- depends on WAN_ROUTER_DRIVERS && (PCI || ISA)
- ---help---
- Cyclom 2X from Cyclades Corporation <http://www.avocent.com/> is an
- intelligent multiprotocol WAN adapter with data transfer rates up to
- 512 Kbps. These cards support the X.25 and SNA related protocols.
-
- While no documentation is available at this time please grab the
- wanconfig tarball in
- <http://www.conectiva.com.br/~acme/cycsyn-devel/> (with minor changes
- to make it compile with the current wanrouter include files; efforts
- are being made to use the original package available at
- <ftp://ftp.sangoma.com/>).
-
- Feel free to contact me or the cycsyn-devel mailing list at
- <acme@conectiva.com.br> and <cycsyn-devel@bazar.conectiva.com.br> for
- additional details, I hope to have documentation available as soon as
- possible. (Cyclades Brazil is writing the Documentation).
-
- The next questions will ask you about the protocols you want the
- driver to support (for now only X.25 is supported).
-
- If you have one or more of these cards, say Y to this option.
-
- To compile this driver as a module, choose M here: the
- module will be called cyclomx.
-
-config CYCLOMX_X25
- bool "Cyclom 2X X.25 support (EXPERIMENTAL)"
- depends on CYCLADES_SYNC
- help
- Connect a Cyclom 2X card to an X.25 network.
-
- Enabling X.25 support will enlarge your kernel by about 11 kB.
-
# X.25 network drivers
config LAPBETHER
- tristate "LAPB over Ethernet driver (EXPERIMENTAL)"
+ tristate "LAPB over Ethernet driver"
depends on LAPB && X25
---help---
Driver for a pseudo device (typically called /dev/lapb0) which allows
@@ -428,8 +374,8 @@ config LAPBETHER
If unsure, say N.
config X25_ASY
- tristate "X.25 async driver (EXPERIMENTAL)"
- depends on LAPB && X25
+ tristate "X.25 async driver"
+ depends on LAPB && X25 && TTY
---help---
Send and receive X.25 frames over regular asynchronous serial
lines such as telephone lines equipped with ordinary modems.
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index df70248e2fda..c135ef47cbca 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -5,10 +5,6 @@
# Rewritten to use lists instead of if-statements.
#
-cyclomx-y := cycx_main.o
-cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o
-cyclomx-objs := $(cyclomx-y)
-
obj-$(CONFIG_HDLC) += hdlc.o
obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o
obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
@@ -28,7 +24,6 @@ obj-$(CONFIG_LANMEDIA) += lmc/
obj-$(CONFIG_DLCI) += dlci.o
obj-$(CONFIG_SDLA) += sdla.o
-obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o
obj-$(CONFIG_LAPBETHER) += lapbether.o
obj-$(CONFIG_SBNI) += sbni.o
obj-$(CONFIG_N2) += n2.o
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 6aed238e573e..0179cefae438 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -795,8 +795,8 @@ static ssize_t cosa_read(struct file *file,
if (mutex_lock_interruptible(&chan->rlock))
return -ERESTARTSYS;
- if ((chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL)) == NULL) {
- pr_info("%s: cosa_read() - OOM\n", cosa->name);
+ chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL);
+ if (chan->rxdata == NULL) {
mutex_unlock(&chan->rlock);
return -ENOMEM;
}
@@ -874,9 +874,8 @@ static ssize_t cosa_write(struct file *file,
count = COSA_MTU;
/* Allocate the buffer */
- if ((kbuf = kmalloc(count, GFP_KERNEL|GFP_DMA)) == NULL) {
- pr_notice("%s: cosa_write() OOM - dropping packet\n",
- cosa->name);
+ kbuf = kmalloc(count, GFP_KERNEL|GFP_DMA);
+ if (kbuf == NULL) {
up(&chan->wsem);
return -ENOMEM;
}
diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
deleted file mode 100644
index 2a3ecae67a90..000000000000
--- a/drivers/net/wan/cycx_drv.c
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
-* cycx_drv.c Cyclom 2X Support Module.
-*
-* This module is a library of common hardware specific
-* functions used by the Cyclades Cyclom 2X sync card.
-*
-* Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Copyright: (c) 1998-2003 Arnaldo Carvalho de Melo
-*
-* Based on sdladrv.c by Gene Kozin <genek@compuserve.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.
-* ============================================================================
-* 1999/11/11 acme set_current_state(TASK_INTERRUPTIBLE), code
-* cleanup
-* 1999/11/08 acme init_cyc2x deleted, doing nothing
-* 1999/11/06 acme back to read[bw], write[bw] and memcpy_to and
-* fromio to use dpmbase ioremaped
-* 1999/10/26 acme use isa_read[bw], isa_write[bw] & isa_memcpy_to
-* & fromio
-* 1999/10/23 acme cleanup to only supports cyclom2x: all the other
-* boards are no longer manufactured by cyclades,
-* if someone wants to support them... be my guest!
-* 1999/05/28 acme cycx_intack & cycx_intde gone for good
-* 1999/05/18 acme lots of unlogged work, submitting to Linus...
-* 1999/01/03 acme more judicious use of data types
-* 1999/01/03 acme judicious use of data types :>
-* cycx_inten trying to reset pending interrupts
-* from cyclom 2x - I think this isn't the way to
-* go, but for now...
-* 1999/01/02 acme cycx_intack ok, I think there's nothing to do
-* to ack an int in cycx_drv.c, only handle it in
-* cyx_isr (or in the other protocols: cyp_isr,
-* cyf_isr, when they get implemented.
-* Dec 31, 1998 acme cycx_data_boot & cycx_code_boot fixed, crossing
-* fingers to see x25_configure in cycx_x25.c
-* work... :)
-* Dec 26, 1998 acme load implementation fixed, seems to work! :)
-* cycx_2x_dpmbase_options with all the possible
-* DPM addresses (20).
-* cycx_intr implemented (test this!)
-* general code cleanup
-* Dec 8, 1998 Ivan Passos Cyclom-2X firmware load implementation.
-* Aug 8, 1998 acme Initial version.
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h> /* __init */
-#include <linux/module.h>
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/errno.h> /* return codes */
-#include <linux/cycx_drv.h> /* API definitions */
-#include <linux/cycx_cfm.h> /* CYCX firmware module definitions */
-#include <linux/delay.h> /* udelay, msleep_interruptible */
-#include <asm/io.h> /* read[wl], write[wl], ioremap, iounmap */
-
-#define MOD_VERSION 0
-#define MOD_RELEASE 6
-
-MODULE_AUTHOR("Arnaldo Carvalho de Melo");
-MODULE_DESCRIPTION("Cyclom 2x Sync Card Driver");
-MODULE_LICENSE("GPL");
-
-/* Hardware-specific functions */
-static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len);
-static void cycx_bootcfg(struct cycx_hw *hw);
-
-static int reset_cyc2x(void __iomem *addr);
-static int detect_cyc2x(void __iomem *addr);
-
-/* Miscellaneous functions */
-static int get_option_index(const long *optlist, long optval);
-static u16 checksum(u8 *buf, u32 len);
-
-#define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET)
-
-/* Global Data */
-
-/* private data */
-static const char fullname[] = "Cyclom 2X Support Module";
-static const char copyright[] =
- "(c) 1998-2003 Arnaldo Carvalho de Melo <acme@conectiva.com.br>";
-
-/* Hardware configuration options.
- * These are arrays of configuration options used by verification routines.
- * The first element of each array is its size (i.e. number of options).
- */
-static const long cyc2x_dpmbase_options[] = {
- 20,
- 0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, 0xB8000,
- 0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, 0xD0000, 0xD4000,
- 0xD8000, 0xDC000, 0xE0000, 0xE4000, 0xE8000, 0xEC000
-};
-
-static const long cycx_2x_irq_options[] = { 7, 3, 5, 9, 10, 11, 12, 15 };
-
-/* Kernel Loadable Module Entry Points */
-/* Module 'insert' entry point.
- * o print announcement
- * o initialize static data
- *
- * Return: 0 Ok
- * < 0 error.
- * Context: process */
-
-static int __init cycx_drv_init(void)
-{
- pr_info("%s v%u.%u %s\n",
- fullname, MOD_VERSION, MOD_RELEASE, copyright);
-
- return 0;
-}
-
-/* Module 'remove' entry point.
- * o release all remaining system resources */
-static void cycx_drv_cleanup(void)
-{
-}
-
-/* Kernel APIs */
-/* Set up adapter.
- * o detect adapter type
- * o verify hardware configuration options
- * o check for hardware conflicts
- * o set up adapter shared memory
- * o test adapter memory
- * o load firmware
- * Return: 0 ok.
- * < 0 error */
-EXPORT_SYMBOL(cycx_setup);
-int cycx_setup(struct cycx_hw *hw, void *cfm, u32 len, unsigned long dpmbase)
-{
- int err;
-
- /* Verify IRQ configuration options */
- if (!get_option_index(cycx_2x_irq_options, hw->irq)) {
- pr_err("IRQ %d is invalid!\n", hw->irq);
- return -EINVAL;
- }
-
- /* Setup adapter dual-port memory window and test memory */
- if (!dpmbase) {
- pr_err("you must specify the dpm address!\n");
- return -EINVAL;
- } else if (!get_option_index(cyc2x_dpmbase_options, dpmbase)) {
- pr_err("memory address 0x%lX is invalid!\n", dpmbase);
- return -EINVAL;
- }
-
- hw->dpmbase = ioremap(dpmbase, CYCX_WINDOWSIZE);
- hw->dpmsize = CYCX_WINDOWSIZE;
-
- if (!detect_cyc2x(hw->dpmbase)) {
- pr_err("adapter Cyclom 2X not found at address 0x%lX!\n",
- dpmbase);
- return -EINVAL;
- }
-
- pr_info("found Cyclom 2X card at address 0x%lX\n", dpmbase);
-
- /* Load firmware. If loader fails then shut down adapter */
- err = load_cyc2x(hw, cfm, len);
-
- if (err)
- cycx_down(hw); /* shutdown adapter */
-
- return err;
-}
-
-EXPORT_SYMBOL(cycx_down);
-int cycx_down(struct cycx_hw *hw)
-{
- iounmap(hw->dpmbase);
- return 0;
-}
-
-/* Enable interrupt generation. */
-static void cycx_inten(struct cycx_hw *hw)
-{
- writeb(0, hw->dpmbase);
-}
-
-/* Generate an interrupt to adapter's CPU. */
-EXPORT_SYMBOL(cycx_intr);
-void cycx_intr(struct cycx_hw *hw)
-{
- writew(0, hw->dpmbase + GEN_CYCX_INTR);
-}
-
-/* Execute Adapter Command.
- * o Set exec flag.
- * o Busy-wait until flag is reset. */
-EXPORT_SYMBOL(cycx_exec);
-int cycx_exec(void __iomem *addr)
-{
- u16 i = 0;
- /* wait till addr content is zeroed */
-
- while (readw(addr)) {
- udelay(1000);
-
- if (++i > 50)
- return -1;
- }
-
- return 0;
-}
-
-/* Read absolute adapter memory.
- * Transfer data from adapter's memory to data buffer. */
-EXPORT_SYMBOL(cycx_peek);
-int cycx_peek(struct cycx_hw *hw, u32 addr, void *buf, u32 len)
-{
- if (len == 1)
- *(u8*)buf = readb(hw->dpmbase + addr);
- else
- memcpy_fromio(buf, hw->dpmbase + addr, len);
-
- return 0;
-}
-
-/* Write Absolute Adapter Memory.
- * Transfer data from data buffer to adapter's memory. */
-EXPORT_SYMBOL(cycx_poke);
-int cycx_poke(struct cycx_hw *hw, u32 addr, void *buf, u32 len)
-{
- if (len == 1)
- writeb(*(u8*)buf, hw->dpmbase + addr);
- else
- memcpy_toio(hw->dpmbase + addr, buf, len);
-
- return 0;
-}
-
-/* Hardware-Specific Functions */
-
-/* Load Aux Routines */
-/* Reset board hardware.
- return 1 if memory exists at addr and 0 if not. */
-static int memory_exists(void __iomem *addr)
-{
- int tries = 0;
-
- for (; tries < 3 ; tries++) {
- writew(TEST_PATTERN, addr + 0x10);
-
- if (readw(addr + 0x10) == TEST_PATTERN)
- if (readw(addr + 0x10) == TEST_PATTERN)
- return 1;
-
- msleep_interruptible(1 * 1000);
- }
-
- return 0;
-}
-
-/* Load reset code. */
-static void reset_load(void __iomem *addr, u8 *buffer, u32 cnt)
-{
- void __iomem *pt_code = addr + RESET_OFFSET;
- u16 i; /*, j; */
-
- for (i = 0 ; i < cnt ; i++) {
-/* for (j = 0 ; j < 50 ; j++); Delay - FIXME busy waiting... */
- writeb(*buffer++, pt_code++);
- }
-}
-
-/* Load buffer using boot interface.
- * o copy data from buffer to Cyclom-X memory
- * o wait for reset code to copy it to right portion of memory */
-static int buffer_load(void __iomem *addr, u8 *buffer, u32 cnt)
-{
- memcpy_toio(addr + DATA_OFFSET, buffer, cnt);
- writew(GEN_BOOT_DAT, addr + CMD_OFFSET);
-
- return wait_cyc(addr);
-}
-
-/* Set up entry point and kick start Cyclom-X CPU. */
-static void cycx_start(void __iomem *addr)
-{
- /* put in 0x30 offset the jump instruction to the code entry point */
- writeb(0xea, addr + 0x30);
- writeb(0x00, addr + 0x31);
- writeb(0xc4, addr + 0x32);
- writeb(0x00, addr + 0x33);
- writeb(0x00, addr + 0x34);
-
- /* cmd to start executing code */
- writew(GEN_START, addr + CMD_OFFSET);
-}
-
-/* Load and boot reset code. */
-static void cycx_reset_boot(void __iomem *addr, u8 *code, u32 len)
-{
- void __iomem *pt_start = addr + START_OFFSET;
-
- writeb(0xea, pt_start++); /* jmp to f000:3f00 */
- writeb(0x00, pt_start++);
- writeb(0xfc, pt_start++);
- writeb(0x00, pt_start++);
- writeb(0xf0, pt_start);
- reset_load(addr, code, len);
-
- /* 80186 was in hold, go */
- writeb(0, addr + START_CPU);
- msleep_interruptible(1 * 1000);
-}
-
-/* Load data.bin file through boot (reset) interface. */
-static int cycx_data_boot(void __iomem *addr, u8 *code, u32 len)
-{
- void __iomem *pt_boot_cmd = addr + CMD_OFFSET;
- u32 i;
-
- /* boot buffer length */
- writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
- writew(GEN_DEFPAR, pt_boot_cmd);
-
- if (wait_cyc(addr) < 0)
- return -1;
-
- writew(0, pt_boot_cmd + sizeof(u16));
- writew(0x4000, pt_boot_cmd + 2 * sizeof(u16));
- writew(GEN_SET_SEG, pt_boot_cmd);
-
- if (wait_cyc(addr) < 0)
- return -1;
-
- for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
- if (buffer_load(addr, code + i,
- min_t(u32, CFM_LOAD_BUFSZ, (len - i))) < 0) {
- pr_err("Error !!\n");
- return -1;
- }
-
- return 0;
-}
-
-
-/* Load code.bin file through boot (reset) interface. */
-static int cycx_code_boot(void __iomem *addr, u8 *code, u32 len)
-{
- void __iomem *pt_boot_cmd = addr + CMD_OFFSET;
- u32 i;
-
- /* boot buffer length */
- writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
- writew(GEN_DEFPAR, pt_boot_cmd);
-
- if (wait_cyc(addr) < 0)
- return -1;
-
- writew(0x0000, pt_boot_cmd + sizeof(u16));
- writew(0xc400, pt_boot_cmd + 2 * sizeof(u16));
- writew(GEN_SET_SEG, pt_boot_cmd);
-
- if (wait_cyc(addr) < 0)
- return -1;
-
- for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
- if (buffer_load(addr, code + i,
- min_t(u32, CFM_LOAD_BUFSZ, (len - i)))) {
- pr_err("Error !!\n");
- return -1;
- }
-
- return 0;
-}
-
-/* Load adapter from the memory image of the CYCX firmware module.
- * o verify firmware integrity and compatibility
- * o start adapter up */
-static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len)
-{
- int i, j;
- struct cycx_fw_header *img_hdr;
- u8 *reset_image,
- *data_image,
- *code_image;
- void __iomem *pt_cycld = hw->dpmbase + 0x400;
- u16 cksum;
-
- /* Announce */
- pr_info("firmware signature=\"%s\"\n", cfm->signature);
-
- /* Verify firmware signature */
- if (strcmp(cfm->signature, CFM_SIGNATURE)) {
- pr_err("load_cyc2x: not Cyclom-2X firmware!\n");
- return -EINVAL;
- }
-
- pr_info("firmware version=%u\n", cfm->version);
-
- /* Verify firmware module format version */
- if (cfm->version != CFM_VERSION) {
- pr_err("%s: firmware format %u rejected! Expecting %u.\n",
- __func__, cfm->version, CFM_VERSION);
- return -EINVAL;
- }
-
- /* Verify firmware module length and checksum */
- cksum = checksum((u8*)&cfm->info, sizeof(struct cycx_fw_info) +
- cfm->info.codesize);
-/*
- FIXME cfm->info.codesize is off by 2
- if (((len - sizeof(struct cycx_firmware) - 1) != cfm->info.codesize) ||
-*/
- if (cksum != cfm->checksum) {
- pr_err("%s: firmware corrupted!\n", __func__);
- pr_err(" cdsize = 0x%x (expected 0x%lx)\n",
- len - (int)sizeof(struct cycx_firmware) - 1,
- cfm->info.codesize);
- pr_err(" chksum = 0x%x (expected 0x%x)\n",
- cksum, cfm->checksum);
- return -EINVAL;
- }
-
- /* If everything is ok, set reset, data and code pointers */
- img_hdr = (struct cycx_fw_header *)&cfm->image;
-#ifdef FIRMWARE_DEBUG
- pr_info("%s: image sizes\n", __func__);
- pr_info(" reset=%lu\n", img_hdr->reset_size);
- pr_info(" data=%lu\n", img_hdr->data_size);
- pr_info(" code=%lu\n", img_hdr->code_size);
-#endif
- reset_image = ((u8 *)img_hdr) + sizeof(struct cycx_fw_header);
- data_image = reset_image + img_hdr->reset_size;
- code_image = data_image + img_hdr->data_size;
-
- /*---- Start load ----*/
- /* Announce */
- pr_info("loading firmware %s (ID=%u)...\n",
- cfm->descr[0] ? cfm->descr : "unknown firmware",
- cfm->info.codeid);
-
- for (i = 0 ; i < 5 ; i++) {
- /* Reset Cyclom hardware */
- if (!reset_cyc2x(hw->dpmbase)) {
- pr_err("dpm problem or board not found\n");
- return -EINVAL;
- }
-
- /* Load reset.bin */
- cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size);
- /* reset is waiting for boot */
- writew(GEN_POWER_ON, pt_cycld);
- msleep_interruptible(1 * 1000);
-
- for (j = 0 ; j < 3 ; j++)
- if (!readw(pt_cycld))
- goto reset_loaded;
- else
- msleep_interruptible(1 * 1000);
- }
-
- pr_err("reset not started\n");
- return -EINVAL;
-
-reset_loaded:
- /* Load data.bin */
- if (cycx_data_boot(hw->dpmbase, data_image, img_hdr->data_size)) {
- pr_err("cannot load data file\n");
- return -EINVAL;
- }
-
- /* Load code.bin */
- if (cycx_code_boot(hw->dpmbase, code_image, img_hdr->code_size)) {
- pr_err("cannot load code file\n");
- return -EINVAL;
- }
-
- /* Prepare boot-time configuration data */
- cycx_bootcfg(hw);
-
- /* kick-off CPU */
- cycx_start(hw->dpmbase);
-
- /* Arthur Ganzert's tip: wait a while after the firmware loading...
- seg abr 26 17:17:12 EST 1999 - acme */
- msleep_interruptible(7 * 1000);
- pr_info("firmware loaded!\n");
-
- /* enable interrupts */
- cycx_inten(hw);
-
- return 0;
-}
-
-/* Prepare boot-time firmware configuration data.
- * o initialize configuration data area
- From async.doc - V_3.4.0 - 07/18/1994
- - As of now, only static buffers are available to the user.
- So, the bit VD_RXDIRC must be set in 'valid'. That means that user
- wants to use the static transmission and reception buffers. */
-static void cycx_bootcfg(struct cycx_hw *hw)
-{
- /* use fixed buffers */
- writeb(FIXED_BUFFERS, hw->dpmbase + CONF_OFFSET);
-}
-
-/* Detect Cyclom 2x adapter.
- * Following tests are used to detect Cyclom 2x adapter:
- * to be completed based on the tests done below
- * Return 1 if detected o.k. or 0 if failed.
- * Note: This test is destructive! Adapter will be left in shutdown
- * state after the test. */
-static int detect_cyc2x(void __iomem *addr)
-{
- reset_cyc2x(addr);
-
- return memory_exists(addr);
-}
-
-/* Miscellaneous */
-/* Get option's index into the options list.
- * Return option's index (1 .. N) or zero if option is invalid. */
-static int get_option_index(const long *optlist, long optval)
-{
- int i = 1;
-
- for (; i <= optlist[0]; ++i)
- if (optlist[i] == optval)
- return i;
-
- return 0;
-}
-
-/* Reset adapter's CPU. */
-static int reset_cyc2x(void __iomem *addr)
-{
- writeb(0, addr + RST_ENABLE);
- msleep_interruptible(2 * 1000);
- writeb(0, addr + RST_DISABLE);
- msleep_interruptible(2 * 1000);
-
- return memory_exists(addr);
-}
-
-/* Calculate 16-bit CRC using CCITT polynomial. */
-static u16 checksum(u8 *buf, u32 len)
-{
- u16 crc = 0;
- u16 mask, flag;
-
- for (; len; --len, ++buf)
- for (mask = 0x80; mask; mask >>= 1) {
- flag = (crc & 0x8000);
- crc <<= 1;
- crc |= ((*buf & mask) ? 1 : 0);
-
- if (flag)
- crc ^= 0x1021;
- }
-
- return crc;
-}
-
-module_init(cycx_drv_init);
-module_exit(cycx_drv_cleanup);
-
-/* End */
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
deleted file mode 100644
index 81fbbad406be..000000000000
--- a/drivers/net/wan/cycx_main.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
-* cycx_main.c Cyclades Cyclom 2X WAN Link Driver. Main module.
-*
-* Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Copyright: (c) 1998-2003 Arnaldo Carvalho de Melo
-*
-* Based on sdlamain.c by Gene Kozin <genek@compuserve.com> &
-* Jaspreet Singh <jaspreet@sangoma.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.
-* ============================================================================
-* Please look at the bitkeeper changelog (or any other scm tool that ends up
-* importing bitkeeper changelog or that replaces bitkeeper in the future as
-* main tool for linux development).
-*
-* 2001/05/09 acme Fix MODULE_DESC for debug, .bss nitpicks,
-* some cleanups
-* 2000/07/13 acme remove useless #ifdef MODULE and crap
-* #if KERNEL_VERSION > blah
-* 2000/07/06 acme __exit at cyclomx_cleanup
-* 2000/04/02 acme dprintk and cycx_debug
-* module_init/module_exit
-* 2000/01/21 acme rename cyclomx_open to cyclomx_mod_inc_use_count
-* and cyclomx_close to cyclomx_mod_dec_use_count
-* 2000/01/08 acme cleanup
-* 1999/11/06 acme cycx_down back to life (it needs to be
-* called to iounmap the dpmbase)
-* 1999/08/09 acme removed references to enable_tx_int
-* use spinlocks instead of cli/sti in
-* cyclomx_set_state
-* 1999/05/19 acme works directly linked into the kernel
-* init_waitqueue_head for 2.3.* kernel
-* 1999/05/18 acme major cleanup (polling not needed), etc
-* 1998/08/28 acme minor cleanup (ioctls for firmware deleted)
-* queue_task activated
-* 1998/08/08 acme Initial version.
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/errno.h> /* return codes */
-#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/slab.h> /* kmalloc(), kfree() */
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/module.h> /* support for loadable modules */
-#include <linux/ioport.h> /* request_region(), release_region() */
-#include <linux/wanrouter.h> /* WAN router definitions */
-#include <linux/cyclomx.h> /* cyclomx common user API definitions */
-#include <linux/init.h> /* __init (when not using as a module) */
-#include <linux/interrupt.h>
-
-unsigned int cycx_debug;
-
-MODULE_AUTHOR("Arnaldo Carvalho de Melo");
-MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver.");
-MODULE_LICENSE("GPL");
-module_param(cycx_debug, int, 0);
-MODULE_PARM_DESC(cycx_debug, "cyclomx debug level");
-
-/* Defines & Macros */
-
-#define CYCX_DRV_VERSION 0 /* version number */
-#define CYCX_DRV_RELEASE 11 /* release (minor version) number */
-#define CYCX_MAX_CARDS 1 /* max number of adapters */
-
-#define CONFIG_CYCX_CARDS 1
-
-/* Function Prototypes */
-
-/* WAN link driver entry points */
-static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf);
-static int cycx_wan_shutdown(struct wan_device *wandev);
-
-/* Miscellaneous functions */
-static irqreturn_t cycx_isr(int irq, void *dev_id);
-
-/* Global Data
- * Note: All data must be explicitly initialized!!!
- */
-
-/* private data */
-static const char cycx_drvname[] = "cyclomx";
-static const char cycx_fullname[] = "CYCLOM 2X(tm) Sync Card Driver";
-static const char cycx_copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
- "<acme@conectiva.com.br>";
-static int cycx_ncards = CONFIG_CYCX_CARDS;
-static struct cycx_device *cycx_card_array; /* adapter data space */
-
-/* Kernel Loadable Module Entry Points */
-
-/*
- * Module 'insert' entry point.
- * o print announcement
- * o allocate adapter data space
- * o initialize static data
- * o register all cards with WAN router
- * o calibrate Cyclom 2X shared memory access delay.
- *
- * Return: 0 Ok
- * < 0 error.
- * Context: process
- */
-static int __init cycx_init(void)
-{
- int cnt, err = -ENOMEM;
-
- pr_info("%s v%u.%u %s\n",
- cycx_fullname, CYCX_DRV_VERSION, CYCX_DRV_RELEASE,
- cycx_copyright);
-
- /* Verify number of cards and allocate adapter data space */
- cycx_ncards = min_t(int, cycx_ncards, CYCX_MAX_CARDS);
- cycx_ncards = max_t(int, cycx_ncards, 1);
- cycx_card_array = kcalloc(cycx_ncards, sizeof(struct cycx_device), GFP_KERNEL);
- if (!cycx_card_array)
- goto out;
-
-
- /* Register adapters with WAN router */
- for (cnt = 0; cnt < cycx_ncards; ++cnt) {
- struct cycx_device *card = &cycx_card_array[cnt];
- struct wan_device *wandev = &card->wandev;
-
- sprintf(card->devname, "%s%d", cycx_drvname, cnt + 1);
- wandev->magic = ROUTER_MAGIC;
- wandev->name = card->devname;
- wandev->private = card;
- wandev->setup = cycx_wan_setup;
- wandev->shutdown = cycx_wan_shutdown;
- err = register_wan_device(wandev);
-
- if (err) {
- pr_err("%s registration failed with error %d!\n",
- card->devname, err);
- break;
- }
- }
-
- err = -ENODEV;
- if (!cnt) {
- kfree(cycx_card_array);
- goto out;
- }
- err = 0;
- cycx_ncards = cnt; /* adjust actual number of cards */
-out: return err;
-}
-
-/*
- * Module 'remove' entry point.
- * o unregister all adapters from the WAN router
- * o release all remaining system resources
- */
-static void __exit cycx_exit(void)
-{
- int i = 0;
-
- for (; i < cycx_ncards; ++i) {
- struct cycx_device *card = &cycx_card_array[i];
- unregister_wan_device(card->devname);
- }
-
- kfree(cycx_card_array);
-}
-
-/* WAN Device Driver Entry Points */
-/*
- * Setup/configure WAN link driver.
- * o check adapter state
- * o make sure firmware is present in configuration
- * o allocate interrupt vector
- * o setup Cyclom 2X hardware
- * o call appropriate routine to perform protocol-specific initialization
- *
- * This function is called when router handles ROUTER_SETUP IOCTL. The
- * configuration structure is in kernel memory (including extended data, if
- * any).
- */
-static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf)
-{
- int rc = -EFAULT;
- struct cycx_device *card;
- int irq;
-
- /* Sanity checks */
-
- if (!wandev || !wandev->private || !conf)
- goto out;
-
- card = wandev->private;
- rc = -EBUSY;
- if (wandev->state != WAN_UNCONFIGURED)
- goto out;
-
- rc = -EINVAL;
- if (!conf->data_size || !conf->data) {
- pr_err("%s: firmware not found in configuration data!\n",
- wandev->name);
- goto out;
- }
-
- if (conf->irq <= 0) {
- pr_err("%s: can't configure without IRQ!\n", wandev->name);
- goto out;
- }
-
- /* Allocate IRQ */
- irq = conf->irq == 2 ? 9 : conf->irq; /* IRQ2 -> IRQ9 */
-
- if (request_irq(irq, cycx_isr, 0, wandev->name, card)) {
- pr_err("%s: can't reserve IRQ %d!\n", wandev->name, irq);
- goto out;
- }
-
- /* Configure hardware, load firmware, etc. */
- memset(&card->hw, 0, sizeof(card->hw));
- card->hw.irq = irq;
- card->hw.dpmsize = CYCX_WINDOWSIZE;
- card->hw.fwid = CFID_X25_2X;
- spin_lock_init(&card->lock);
- init_waitqueue_head(&card->wait_stats);
-
- rc = cycx_setup(&card->hw, conf->data, conf->data_size, conf->maddr);
- if (rc)
- goto out_irq;
-
- /* Initialize WAN device data space */
- wandev->irq = irq;
- wandev->dma = wandev->ioport = 0;
- wandev->maddr = (unsigned long)card->hw.dpmbase;
- wandev->msize = card->hw.dpmsize;
- wandev->hw_opt[2] = 0;
- wandev->hw_opt[3] = card->hw.fwid;
-
- /* Protocol-specific initialization */
- switch (card->hw.fwid) {
-#ifdef CONFIG_CYCLOMX_X25
- case CFID_X25_2X:
- rc = cycx_x25_wan_init(card, conf);
- break;
-#endif
- default:
- pr_err("%s: this firmware is not supported!\n", wandev->name);
- rc = -EINVAL;
- }
-
- if (rc) {
- cycx_down(&card->hw);
- goto out_irq;
- }
-
- rc = 0;
-out:
- return rc;
-out_irq:
- free_irq(irq, card);
- goto out;
-}
-
-/*
- * Shut down WAN link driver.
- * o shut down adapter hardware
- * o release system resources.
- *
- * This function is called by the router when device is being unregistered or
- * when it handles ROUTER_DOWN IOCTL.
- */
-static int cycx_wan_shutdown(struct wan_device *wandev)
-{
- int ret = -EFAULT;
- struct cycx_device *card;
-
- /* sanity checks */
- if (!wandev || !wandev->private)
- goto out;
-
- ret = 0;
- if (wandev->state == WAN_UNCONFIGURED)
- goto out;
-
- card = wandev->private;
- wandev->state = WAN_UNCONFIGURED;
- cycx_down(&card->hw);
- pr_info("%s: irq %d being freed!\n", wandev->name, wandev->irq);
- free_irq(wandev->irq, card);
-out: return ret;
-}
-
-/* Miscellaneous */
-/*
- * Cyclom 2X Interrupt Service Routine.
- * o acknowledge Cyclom 2X hardware interrupt.
- * o call protocol-specific interrupt service routine, if any.
- */
-static irqreturn_t cycx_isr(int irq, void *dev_id)
-{
- struct cycx_device *card = dev_id;
-
- if (card->wandev.state == WAN_UNCONFIGURED)
- goto out;
-
- if (card->in_isr) {
- pr_warn("%s: interrupt re-entrancy on IRQ %d!\n",
- card->devname, card->wandev.irq);
- goto out;
- }
-
- if (card->isr)
- card->isr(card);
- return IRQ_HANDLED;
-out:
- return IRQ_NONE;
-}
-
-/* Set WAN device state. */
-void cycx_set_state(struct cycx_device *card, int state)
-{
- unsigned long flags;
- char *string_state = NULL;
-
- spin_lock_irqsave(&card->lock, flags);
-
- if (card->wandev.state != state) {
- switch (state) {
- case WAN_CONNECTED:
- string_state = "connected!";
- break;
- case WAN_DISCONNECTED:
- string_state = "disconnected!";
- break;
- }
- pr_info("%s: link %s\n", card->devname, string_state);
- card->wandev.state = state;
- }
-
- card->state_tick = jiffies;
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-module_init(cycx_init);
-module_exit(cycx_exit);
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
deleted file mode 100644
index 06f3f6309e4b..000000000000
--- a/drivers/net/wan/cycx_x25.c
+++ /dev/null
@@ -1,1602 +0,0 @@
-/*
-* cycx_x25.c Cyclom 2X WAN Link Driver. X.25 module.
-*
-* Author: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Copyright: (c) 1998-2003 Arnaldo Carvalho de Melo
-*
-* Based on sdla_x25.c by Gene Kozin <genek@compuserve.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.
-* ============================================================================
-* 2001/01/12 acme use dev_kfree_skb_irq on interrupt context
-* 2000/04/02 acme dprintk, cycx_debug
-* fixed the bug introduced in get_dev_by_lcn and
-* get_dev_by_dte_addr by the anonymous hacker
-* that converted this driver to softnet
-* 2000/01/08 acme cleanup
-* 1999/10/27 acme use ARPHRD_HWX25 so that the X.25 stack know
-* that we have a X.25 stack implemented in
-* firmware onboard
-* 1999/10/18 acme support for X.25 sockets in if_send,
-* beware: socket(AF_X25...) IS WORK IN PROGRESS,
-* TCP/IP over X.25 via wanrouter not affected,
-* working.
-* 1999/10/09 acme chan_disc renamed to chan_disconnect,
-* began adding support for X.25 sockets:
-* conf->protocol in new_if
-* 1999/10/05 acme fixed return E... to return -E...
-* 1999/08/10 acme serialized access to the card thru a spinlock
-* in x25_exec
-* 1999/08/09 acme removed per channel spinlocks
-* removed references to enable_tx_int
-* 1999/05/28 acme fixed nibble_to_byte, ackvc now properly treated
-* if_send simplified
-* 1999/05/25 acme fixed t1, t2, t21 & t23 configuration
-* use spinlocks instead of cli/sti in some points
-* 1999/05/24 acme finished the x25_get_stat function
-* 1999/05/23 acme dev->type = ARPHRD_X25 (tcpdump only works,
-* AFAIT, with ARPHRD_ETHER). This seems to be
-* needed to use socket(AF_X25)...
-* Now the config file must specify a peer media
-* address for svc channels over a crossover cable.
-* Removed hold_timeout from x25_channel_t,
-* not used.
-* A little enhancement in the DEBUG processing
-* 1999/05/22 acme go to DISCONNECTED in disconnect_confirm_intr,
-* instead of chan_disc.
-* 1999/05/16 marcelo fixed timer initialization in SVCs
-* 1999/01/05 acme x25_configure now get (most of) all
-* parameters...
-* 1999/01/05 acme pktlen now (correctly) uses log2 (value
-* configured)
-* 1999/01/03 acme judicious use of data types (u8, u16, u32, etc)
-* 1999/01/03 acme cyx_isr: reset dpmbase to acknowledge
-* indication (interrupt from cyclom 2x)
-* 1999/01/02 acme cyx_isr: first hackings...
-* 1999/01/0203 acme when initializing an array don't give less
-* elements than declared...
-* example: char send_cmd[6] = "?\xFF\x10";
-* you'll gonna lose a couple hours, 'cause your
-* brain won't admit that there's an error in the
-* above declaration... the side effect is that
-* memset is put into the unresolved symbols
-* instead of using the inline memset functions...
-* 1999/01/02 acme began chan_connect, chan_send, x25_send
-* 1998/12/31 acme x25_configure
-* this code can be compiled as non module
-* 1998/12/27 acme code cleanup
-* IPX code wiped out! let's decrease code
-* complexity for now, remember: I'm learning! :)
-* bps_to_speed_code OK
-* 1998/12/26 acme Minimal debug code cleanup
-* 1998/08/08 acme Initial version.
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define CYCLOMX_X25_DEBUG 1
-
-#include <linux/ctype.h> /* isdigit() */
-#include <linux/errno.h> /* return codes */
-#include <linux/if_arp.h> /* ARPHRD_HWX25 */
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/module.h>
-#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/sched.h>
-#include <linux/slab.h> /* kmalloc(), kfree() */
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/wanrouter.h> /* WAN router definitions */
-
-#include <asm/byteorder.h> /* htons(), etc. */
-
-#include <linux/cyclomx.h> /* Cyclom 2X common user API definitions */
-#include <linux/cycx_x25.h> /* X.25 firmware API definitions */
-
-#include <net/x25device.h>
-
-/* Defines & Macros */
-#define CYCX_X25_MAX_CMD_RETRY 5
-#define CYCX_X25_CHAN_MTU 2048 /* unfragmented logical channel MTU */
-
-/* Data Structures */
-/* This is an extension of the 'struct net_device' we create for each network
- interface to keep the rest of X.25 channel-specific data. */
-struct cycx_x25_channel {
- /* This member must be first. */
- struct net_device *slave; /* WAN slave */
-
- char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
- char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */
- char *local_addr; /* local media address, ASCIIZ -
- svc thru crossover cable */
- s16 lcn; /* logical channel number/conn.req.key*/
- u8 link;
- struct timer_list timer; /* timer used for svc channel disc. */
- u16 protocol; /* ethertype, 0 - multiplexed */
- u8 svc; /* 0 - permanent, 1 - switched */
- u8 state; /* channel state */
- u8 drop_sequence; /* mark sequence for dropping */
- u32 idle_tmout; /* sec, before disconnecting */
- struct sk_buff *rx_skb; /* receive socket buffer */
- struct cycx_device *card; /* -> owner */
- struct net_device_stats ifstats;/* interface statistics */
-};
-
-/* Function Prototypes */
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int cycx_wan_update(struct wan_device *wandev),
- cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
- wanif_conf_t *conf),
- cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev);
-
-/* Network device interface */
-static int cycx_netdevice_init(struct net_device *dev);
-static int cycx_netdevice_open(struct net_device *dev);
-static int cycx_netdevice_stop(struct net_device *dev);
-static int cycx_netdevice_hard_header(struct sk_buff *skb,
- struct net_device *dev, u16 type,
- const void *daddr, const void *saddr,
- unsigned len);
-static int cycx_netdevice_rebuild_header(struct sk_buff *skb);
-static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-
-static struct net_device_stats *
- cycx_netdevice_get_stats(struct net_device *dev);
-
-/* Interrupt handlers */
-static void cycx_x25_irq_handler(struct cycx_device *card),
- cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd),
- cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd),
- cycx_x25_irq_log(struct cycx_device *card,
- struct cycx_x25_cmd *cmd),
- cycx_x25_irq_stat(struct cycx_device *card,
- struct cycx_x25_cmd *cmd),
- cycx_x25_irq_connect_confirm(struct cycx_device *card,
- struct cycx_x25_cmd *cmd),
- cycx_x25_irq_disconnect_confirm(struct cycx_device *card,
- struct cycx_x25_cmd *cmd),
- cycx_x25_irq_connect(struct cycx_device *card,
- struct cycx_x25_cmd *cmd),
- cycx_x25_irq_disconnect(struct cycx_device *card,
- struct cycx_x25_cmd *cmd),
- cycx_x25_irq_spurious(struct cycx_device *card,
- struct cycx_x25_cmd *cmd);
-
-/* X.25 firmware interface functions */
-static int cycx_x25_configure(struct cycx_device *card,
- struct cycx_x25_config *conf),
- cycx_x25_get_stats(struct cycx_device *card),
- cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm,
- int len, void *buf),
- cycx_x25_connect_response(struct cycx_device *card,
- struct cycx_x25_channel *chan),
- cycx_x25_disconnect_response(struct cycx_device *card, u8 link,
- u8 lcn);
-
-/* channel functions */
-static int cycx_x25_chan_connect(struct net_device *dev),
- cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb);
-
-static void cycx_x25_chan_disconnect(struct net_device *dev),
- cycx_x25_chan_send_event(struct net_device *dev, u8 event);
-
-/* Miscellaneous functions */
-static void cycx_x25_set_chan_state(struct net_device *dev, u8 state),
- cycx_x25_chan_timer(unsigned long d);
-
-static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble),
- reset_timer(struct net_device *dev);
-
-static u8 bps_to_speed_code(u32 bps);
-static u8 cycx_log2(u32 n);
-
-static unsigned dec_to_uint(u8 *str, int len);
-
-static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev,
- s16 lcn);
-static struct net_device *
- cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte);
-
-static void cycx_x25_chan_setup(struct net_device *dev);
-
-#ifdef CYCLOMX_X25_DEBUG
-static void hex_dump(char *msg, unsigned char *p, int len);
-static void cycx_x25_dump_config(struct cycx_x25_config *conf);
-static void cycx_x25_dump_stats(struct cycx_x25_stats *stats);
-static void cycx_x25_dump_devs(struct wan_device *wandev);
-#else
-#define hex_dump(msg, p, len)
-#define cycx_x25_dump_config(conf)
-#define cycx_x25_dump_stats(stats)
-#define cycx_x25_dump_devs(wandev)
-#endif
-/* Public Functions */
-
-/* X.25 Protocol Initialization routine.
- *
- * This routine is called by the main Cyclom 2X module during setup. At this
- * point adapter is completely initialized and X.25 firmware is running.
- * o configure adapter
- * o initialize protocol-specific fields of the adapter data space.
- *
- * Return: 0 o.k.
- * < 0 failure. */
-int cycx_x25_wan_init(struct cycx_device *card, wandev_conf_t *conf)
-{
- struct cycx_x25_config cfg;
-
- /* Verify configuration ID */
- if (conf->config_id != WANCONFIG_X25) {
- pr_info("%s: invalid configuration ID %u!\n",
- card->devname, conf->config_id);
- return -EINVAL;
- }
-
- /* Initialize protocol-specific fields */
- card->mbox = card->hw.dpmbase + X25_MBOX_OFFS;
- card->u.x.connection_keys = 0;
- spin_lock_init(&card->u.x.lock);
-
- /* Configure adapter. Here we set reasonable defaults, then parse
- * device configuration structure and set configuration options.
- * Most configuration options are verified and corrected (if
- * necessary) since we can't rely on the adapter to do so and don't
- * want it to fail either. */
- memset(&cfg, 0, sizeof(cfg));
- cfg.link = 0;
- cfg.clock = conf->clocking == WANOPT_EXTERNAL ? 8 : 55;
- cfg.speed = bps_to_speed_code(conf->bps);
- cfg.n3win = 7;
- cfg.n2win = 2;
- cfg.n2 = 5;
- cfg.nvc = 1;
- cfg.npvc = 1;
- cfg.flags = 0x02; /* default = V35 */
- cfg.t1 = 10; /* line carrier timeout */
- cfg.t2 = 29; /* tx timeout */
- cfg.t21 = 180; /* CALL timeout */
- cfg.t23 = 180; /* CLEAR timeout */
-
- /* adjust MTU */
- if (!conf->mtu || conf->mtu >= 512)
- card->wandev.mtu = 512;
- else if (conf->mtu >= 256)
- card->wandev.mtu = 256;
- else if (conf->mtu >= 128)
- card->wandev.mtu = 128;
- else
- card->wandev.mtu = 64;
-
- cfg.pktlen = cycx_log2(card->wandev.mtu);
-
- if (conf->station == WANOPT_DTE) {
- cfg.locaddr = 3; /* DTE */
- cfg.remaddr = 1; /* DCE */
- } else {
- cfg.locaddr = 1; /* DCE */
- cfg.remaddr = 3; /* DTE */
- }
-
- if (conf->interface == WANOPT_RS232)
- cfg.flags = 0; /* FIXME just reset the 2nd bit */
-
- if (conf->u.x25.hi_pvc) {
- card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, 4095);
- card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc);
- }
-
- if (conf->u.x25.hi_svc) {
- card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, 4095);
- card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc);
- }
-
- if (card->u.x.lo_pvc == 255)
- cfg.npvc = 0;
- else
- cfg.npvc = card->u.x.hi_pvc - card->u.x.lo_pvc + 1;
-
- cfg.nvc = card->u.x.hi_svc - card->u.x.lo_svc + 1 + cfg.npvc;
-
- if (conf->u.x25.hdlc_window)
- cfg.n2win = min_t(unsigned int, conf->u.x25.hdlc_window, 7);
-
- if (conf->u.x25.pkt_window)
- cfg.n3win = min_t(unsigned int, conf->u.x25.pkt_window, 7);
-
- if (conf->u.x25.t1)
- cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30);
-
- if (conf->u.x25.t2)
- cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 30);
-
- if (conf->u.x25.t11_t21)
- cfg.t21 = min_t(unsigned int, conf->u.x25.t11_t21, 30);
-
- if (conf->u.x25.t13_t23)
- cfg.t23 = min_t(unsigned int, conf->u.x25.t13_t23, 30);
-
- if (conf->u.x25.n2)
- cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30);
-
- /* initialize adapter */
- if (cycx_x25_configure(card, &cfg))
- return -EIO;
-
- /* Initialize protocol-specific fields of adapter data space */
- card->wandev.bps = conf->bps;
- card->wandev.interface = conf->interface;
- card->wandev.clocking = conf->clocking;
- card->wandev.station = conf->station;
- card->isr = cycx_x25_irq_handler;
- card->exec = NULL;
- card->wandev.update = cycx_wan_update;
- card->wandev.new_if = cycx_wan_new_if;
- card->wandev.del_if = cycx_wan_del_if;
- card->wandev.state = WAN_DISCONNECTED;
-
- return 0;
-}
-
-/* WAN Device Driver Entry Points */
-/* Update device status & statistics. */
-static int cycx_wan_update(struct wan_device *wandev)
-{
- /* sanity checks */
- if (!wandev || !wandev->private)
- return -EFAULT;
-
- if (wandev->state == WAN_UNCONFIGURED)
- return -ENODEV;
-
- cycx_x25_get_stats(wandev->private);
-
- return 0;
-}
-
-/* Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registration.
- *
- * Return: 0 o.k.
- * < 0 failure (channel will not be created) */
-static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
- wanif_conf_t *conf)
-{
- struct cycx_device *card = wandev->private;
- struct cycx_x25_channel *chan;
- int err = 0;
-
- if (!conf->name[0] || strlen(conf->name) > WAN_IFNAME_SZ) {
- pr_info("%s: invalid interface name!\n", card->devname);
- return -EINVAL;
- }
-
- dev = alloc_netdev(sizeof(struct cycx_x25_channel), conf->name,
- cycx_x25_chan_setup);
- if (!dev)
- return -ENOMEM;
-
- chan = netdev_priv(dev);
- strcpy(chan->name, conf->name);
- chan->card = card;
- chan->link = conf->port;
- chan->protocol = conf->protocol ? ETH_P_X25 : ETH_P_IP;
- chan->rx_skb = NULL;
- /* only used in svc connected thru crossover cable */
- chan->local_addr = NULL;
-
- if (conf->addr[0] == '@') { /* SVC */
- int len = strlen(conf->local_addr);
-
- if (len) {
- if (len > WAN_ADDRESS_SZ) {
- pr_err("%s: %s local addr too long!\n",
- wandev->name, chan->name);
- err = -EINVAL;
- goto error;
- } else {
- chan->local_addr = kmalloc(len + 1, GFP_KERNEL);
-
- if (!chan->local_addr) {
- err = -ENOMEM;
- goto error;
- }
- }
-
- strncpy(chan->local_addr, conf->local_addr,
- WAN_ADDRESS_SZ);
- }
-
- chan->svc = 1;
- strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
- init_timer(&chan->timer);
- chan->timer.function = cycx_x25_chan_timer;
- chan->timer.data = (unsigned long)dev;
-
- /* Set channel timeouts (default if not specified) */
- chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90;
- } else if (isdigit(conf->addr[0])) { /* PVC */
- s16 lcn = dec_to_uint(conf->addr, 0);
-
- if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc)
- chan->lcn = lcn;
- else {
- pr_err("%s: PVC %u is out of range on interface %s!\n",
- wandev->name, lcn, chan->name);
- err = -EINVAL;
- goto error;
- }
- } else {
- pr_err("%s: invalid media address on interface %s!\n",
- wandev->name, chan->name);
- err = -EINVAL;
- goto error;
- }
-
- return 0;
-
-error:
- free_netdev(dev);
- return err;
-}
-
-/* Delete logical channel. */
-static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev)
-{
- struct cycx_x25_channel *chan = netdev_priv(dev);
-
- if (chan->svc) {
- kfree(chan->local_addr);
- if (chan->state == WAN_CONNECTED)
- del_timer(&chan->timer);
- }
-
- return 0;
-}
-
-
-/* Network Device Interface */
-
-static const struct header_ops cycx_header_ops = {
- .create = cycx_netdevice_hard_header,
- .rebuild = cycx_netdevice_rebuild_header,
-};
-
-static const struct net_device_ops cycx_netdev_ops = {
- .ndo_init = cycx_netdevice_init,
- .ndo_open = cycx_netdevice_open,
- .ndo_stop = cycx_netdevice_stop,
- .ndo_start_xmit = cycx_netdevice_hard_start_xmit,
- .ndo_get_stats = cycx_netdevice_get_stats,
-};
-
-static void cycx_x25_chan_setup(struct net_device *dev)
-{
- /* Initialize device driver entry points */
- dev->netdev_ops = &cycx_netdev_ops;
- dev->header_ops = &cycx_header_ops;
-
- /* Initialize media-specific parameters */
- dev->mtu = CYCX_X25_CHAN_MTU;
- dev->type = ARPHRD_HWX25; /* ARP h/w type */
- dev->hard_header_len = 0; /* media header length */
- dev->addr_len = 0; /* hardware address length */
-}
-
-/* Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration. Returning anything but zero will fail interface
- * registration. */
-static int cycx_netdevice_init(struct net_device *dev)
-{
- struct cycx_x25_channel *chan = netdev_priv(dev);
- struct cycx_device *card = chan->card;
- struct wan_device *wandev = &card->wandev;
-
- if (!chan->svc)
- *(__be16*)dev->dev_addr = htons(chan->lcn);
-
- /* Initialize hardware parameters (just for reference) */
- dev->irq = wandev->irq;
- dev->dma = wandev->dma;
- dev->base_addr = wandev->ioport;
- dev->mem_start = (unsigned long)wandev->maddr;
- dev->mem_end = (unsigned long)(wandev->maddr +
- wandev->msize - 1);
- dev->flags |= IFF_NOARP;
-
- /* Set transmit buffer queue length */
- dev->tx_queue_len = 10;
-
- /* Initialize socket buffers */
- cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
-
- return 0;
-}
-
-/* Open network interface.
- * o prevent module from unloading by incrementing use count
- * o if link is disconnected then initiate connection
- *
- * Return 0 if O.k. or errno. */
-static int cycx_netdevice_open(struct net_device *dev)
-{
- if (netif_running(dev))
- return -EBUSY; /* only one open is allowed */
-
- netif_start_queue(dev);
- return 0;
-}
-
-/* Close network interface.
- * o reset flags.
- * o if there's no more open channels then disconnect physical link. */
-static int cycx_netdevice_stop(struct net_device *dev)
-{
- struct cycx_x25_channel *chan = netdev_priv(dev);
-
- netif_stop_queue(dev);
-
- if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING)
- cycx_x25_chan_disconnect(dev);
-
- return 0;
-}
-
-/* Build media header.
- * o encapsulate packet according to encapsulation type.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it. If encapsulation fails,
- * set skb->protocol to 0 and discard packet later.
- *
- * Return: media header length. */
-static int cycx_netdevice_hard_header(struct sk_buff *skb,
- struct net_device *dev, u16 type,
- const void *daddr, const void *saddr,
- unsigned len)
-{
- skb->protocol = htons(type);
-
- return dev->hard_header_len;
-}
-
-/* * Re-build media header.
- * Return: 1 physical address resolved.
- * 0 physical address not resolved */
-static int cycx_netdevice_rebuild_header(struct sk_buff *skb)
-{
- return 1;
-}
-
-/* Send a packet on a network interface.
- * o set busy flag (marks start of the transmission).
- * o check link state. If link is not up, then drop the packet.
- * o check channel status. If it's down then initiate a call.
- * o pass a packet to corresponding WAN device.
- * o free socket buffer
- *
- * Return: 0 complete (socket buffer must be freed)
- * non-0 packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- * bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- * protocol stack and can be used for flow control with protocol layer. */
-static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct cycx_x25_channel *chan = netdev_priv(dev);
- struct cycx_device *card = chan->card;
-
- if (!chan->svc)
- chan->protocol = ntohs(skb->protocol);
-
- if (card->wandev.state != WAN_CONNECTED)
- ++chan->ifstats.tx_dropped;
- else if (chan->svc && chan->protocol &&
- chan->protocol != ntohs(skb->protocol)) {
- pr_info("%s: unsupported Ethertype 0x%04X on interface %s!\n",
- card->devname, ntohs(skb->protocol), dev->name);
- ++chan->ifstats.tx_errors;
- } else if (chan->protocol == ETH_P_IP) {
- switch (chan->state) {
- case WAN_DISCONNECTED:
- if (cycx_x25_chan_connect(dev)) {
- netif_stop_queue(dev);
- return NETDEV_TX_BUSY;
- }
- /* fall thru */
- case WAN_CONNECTED:
- reset_timer(dev);
- dev->trans_start = jiffies;
- netif_stop_queue(dev);
-
- if (cycx_x25_chan_send(dev, skb))
- return NETDEV_TX_BUSY;
-
- break;
- default:
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- }
- } else { /* chan->protocol == ETH_P_X25 */
- switch (skb->data[0]) {
- case X25_IFACE_DATA:
- break;
- case X25_IFACE_CONNECT:
- cycx_x25_chan_connect(dev);
- goto free_packet;
- case X25_IFACE_DISCONNECT:
- cycx_x25_chan_disconnect(dev);
- goto free_packet;
- default:
- pr_info("%s: unknown %d x25-iface request on %s!\n",
- card->devname, skb->data[0], dev->name);
- ++chan->ifstats.tx_errors;
- goto free_packet;
- }
-
- skb_pull(skb, 1); /* Remove control byte */
- reset_timer(dev);
- dev->trans_start = jiffies;
- netif_stop_queue(dev);
-
- if (cycx_x25_chan_send(dev, skb)) {
- /* prepare for future retransmissions */
- skb_push(skb, 1);
- return NETDEV_TX_BUSY;
- }
- }
-
-free_packet:
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-/* Get Ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats */
-static struct net_device_stats *cycx_netdevice_get_stats(struct net_device *dev)
-{
- struct cycx_x25_channel *chan = netdev_priv(dev);
-
- return chan ? &chan->ifstats : NULL;
-}
-
-/* Interrupt Handlers */
-/* X.25 Interrupt Service Routine. */
-static void cycx_x25_irq_handler(struct cycx_device *card)
-{
- struct cycx_x25_cmd cmd;
- u16 z = 0;
-
- card->in_isr = 1;
- card->buff_int_mode_unbusy = 0;
- cycx_peek(&card->hw, X25_RXMBOX_OFFS, &cmd, sizeof(cmd));
-
- switch (cmd.command) {
- case X25_DATA_INDICATION:
- cycx_x25_irq_rx(card, &cmd);
- break;
- case X25_ACK_FROM_VC:
- cycx_x25_irq_tx(card, &cmd);
- break;
- case X25_LOG:
- cycx_x25_irq_log(card, &cmd);
- break;
- case X25_STATISTIC:
- cycx_x25_irq_stat(card, &cmd);
- break;
- case X25_CONNECT_CONFIRM:
- cycx_x25_irq_connect_confirm(card, &cmd);
- break;
- case X25_CONNECT_INDICATION:
- cycx_x25_irq_connect(card, &cmd);
- break;
- case X25_DISCONNECT_INDICATION:
- cycx_x25_irq_disconnect(card, &cmd);
- break;
- case X25_DISCONNECT_CONFIRM:
- cycx_x25_irq_disconnect_confirm(card, &cmd);
- break;
- case X25_LINE_ON:
- cycx_set_state(card, WAN_CONNECTED);
- break;
- case X25_LINE_OFF:
- cycx_set_state(card, WAN_DISCONNECTED);
- break;
- default:
- cycx_x25_irq_spurious(card, &cmd);
- break;
- }
-
- cycx_poke(&card->hw, 0, &z, sizeof(z));
- cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z));
- card->in_isr = 0;
-}
-
-/* Transmit interrupt handler.
- * o Release socket buffer
- * o Clear 'tbusy' flag */
-static void cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd)
-{
- struct net_device *dev;
- struct wan_device *wandev = &card->wandev;
- u8 lcn;
-
- cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-
- /* unbusy device and then dev_tint(); */
- dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
- if (dev) {
- card->buff_int_mode_unbusy = 1;
- netif_wake_queue(dev);
- } else
- pr_err("%s:ackvc for inexistent lcn %d\n", card->devname, lcn);
-}
-
-/* Receive interrupt handler.
- * This routine handles fragmented IP packets using M-bit according to the
- * RFC1356.
- * o map logical channel number to network interface.
- * o allocate socket buffer or append received packet to the existing one.
- * o if M-bit is reset (i.e. it's the last packet in a sequence) then
- * decapsulate packet and pass socket buffer to the protocol stack.
- *
- * Notes:
- * 1. When allocating a socket buffer, if M-bit is set then more data is
- * coming and we have to allocate buffer for the maximum IP packet size
- * expected on this channel.
- * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
- * socket buffers available) the whole packet sequence must be discarded. */
-static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd)
-{
- struct wan_device *wandev = &card->wandev;
- struct net_device *dev;
- struct cycx_x25_channel *chan;
- struct sk_buff *skb;
- u8 bitm, lcn;
- int pktlen = cmd->len - 5;
-
- cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
- cycx_peek(&card->hw, cmd->buf + 4, &bitm, sizeof(bitm));
- bitm &= 0x10;
-
- dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
- if (!dev) {
- /* Invalid channel, discard packet */
- pr_info("%s: receiving on orphaned LCN %d!\n",
- card->devname, lcn);
- return;
- }
-
- chan = netdev_priv(dev);
- reset_timer(dev);
-
- if (chan->drop_sequence) {
- if (!bitm)
- chan->drop_sequence = 0;
- else
- return;
- }
-
- if ((skb = chan->rx_skb) == NULL) {
- /* Allocate new socket buffer */
- int bufsize = bitm ? dev->mtu : pktlen;
-
- if ((skb = dev_alloc_skb((chan->protocol == ETH_P_X25 ? 1 : 0) +
- bufsize +
- dev->hard_header_len)) == NULL) {
- pr_info("%s: no socket buffers available!\n",
- card->devname);
- chan->drop_sequence = 1;
- ++chan->ifstats.rx_dropped;
- return;
- }
-
- if (chan->protocol == ETH_P_X25) /* X.25 socket layer control */
- /* 0 = data packet (dev_alloc_skb zeroed skb->data) */
- skb_put(skb, 1);
-
- skb->dev = dev;
- skb->protocol = htons(chan->protocol);
- chan->rx_skb = skb;
- }
-
- if (skb_tailroom(skb) < pktlen) {
- /* No room for the packet. Call off the whole thing! */
- dev_kfree_skb_irq(skb);
- chan->rx_skb = NULL;
-
- if (bitm)
- chan->drop_sequence = 1;
-
- pr_info("%s: unexpectedly long packet sequence on interface %s!\n",
- card->devname, dev->name);
- ++chan->ifstats.rx_length_errors;
- return;
- }
-
- /* Append packet to the socket buffer */
- cycx_peek(&card->hw, cmd->buf + 5, skb_put(skb, pktlen), pktlen);
-
- if (bitm)
- return; /* more data is coming */
-
- chan->rx_skb = NULL; /* dequeue packet */
-
- ++chan->ifstats.rx_packets;
- chan->ifstats.rx_bytes += pktlen;
-
- skb_reset_mac_header(skb);
- netif_rx(skb);
-}
-
-/* Connect interrupt handler. */
-static void cycx_x25_irq_connect(struct cycx_device *card,
- struct cycx_x25_cmd *cmd)
-{
- struct wan_device *wandev = &card->wandev;
- struct net_device *dev = NULL;
- struct cycx_x25_channel *chan;
- u8 d[32],
- loc[24],
- rem[24];
- u8 lcn, sizeloc, sizerem;
-
- cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
- cycx_peek(&card->hw, cmd->buf + 5, &sizeloc, sizeof(sizeloc));
- cycx_peek(&card->hw, cmd->buf + 6, d, cmd->len - 6);
-
- sizerem = sizeloc >> 4;
- sizeloc &= 0x0F;
-
- loc[0] = rem[0] = '\0';
-
- if (sizeloc)
- nibble_to_byte(d, loc, sizeloc, 0);
-
- if (sizerem)
- nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1);
-
- dprintk(1, KERN_INFO "%s:lcn=%d, local=%s, remote=%s\n",
- __func__, lcn, loc, rem);
-
- dev = cycx_x25_get_dev_by_dte_addr(wandev, rem);
- if (!dev) {
- /* Invalid channel, discard packet */
- pr_info("%s: connect not expected: remote %s!\n",
- card->devname, rem);
- return;
- }
-
- chan = netdev_priv(dev);
- chan->lcn = lcn;
- cycx_x25_connect_response(card, chan);
- cycx_x25_set_chan_state(dev, WAN_CONNECTED);
-}
-
-/* Connect confirm interrupt handler. */
-static void cycx_x25_irq_connect_confirm(struct cycx_device *card,
- struct cycx_x25_cmd *cmd)
-{
- struct wan_device *wandev = &card->wandev;
- struct net_device *dev;
- struct cycx_x25_channel *chan;
- u8 lcn, key;
-
- cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
- cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key));
- dprintk(1, KERN_INFO "%s: %s:lcn=%d, key=%d\n",
- card->devname, __func__, lcn, key);
-
- dev = cycx_x25_get_dev_by_lcn(wandev, -key);
- if (!dev) {
- /* Invalid channel, discard packet */
- clear_bit(--key, (void*)&card->u.x.connection_keys);
- pr_info("%s: connect confirm not expected: lcn %d, key=%d!\n",
- card->devname, lcn, key);
- return;
- }
-
- clear_bit(--key, (void*)&card->u.x.connection_keys);
- chan = netdev_priv(dev);
- chan->lcn = lcn;
- cycx_x25_set_chan_state(dev, WAN_CONNECTED);
-}
-
-/* Disconnect confirm interrupt handler. */
-static void cycx_x25_irq_disconnect_confirm(struct cycx_device *card,
- struct cycx_x25_cmd *cmd)
-{
- struct wan_device *wandev = &card->wandev;
- struct net_device *dev;
- u8 lcn;
-
- cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
- dprintk(1, KERN_INFO "%s: %s:lcn=%d\n",
- card->devname, __func__, lcn);
- dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
- if (!dev) {
- /* Invalid channel, discard packet */
- pr_info("%s:disconnect confirm not expected!:lcn %d\n",
- card->devname, lcn);
- return;
- }
-
- cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
-}
-
-/* disconnect interrupt handler. */
-static void cycx_x25_irq_disconnect(struct cycx_device *card,
- struct cycx_x25_cmd *cmd)
-{
- struct wan_device *wandev = &card->wandev;
- struct net_device *dev;
- u8 lcn;
-
- cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
- dprintk(1, KERN_INFO "%s:lcn=%d\n", __func__, lcn);
-
- dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
- if (dev) {
- struct cycx_x25_channel *chan = netdev_priv(dev);
-
- cycx_x25_disconnect_response(card, chan->link, lcn);
- cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
- } else
- cycx_x25_disconnect_response(card, 0, lcn);
-}
-
-/* LOG interrupt handler. */
-static void cycx_x25_irq_log(struct cycx_device *card, struct cycx_x25_cmd *cmd)
-{
-#if CYCLOMX_X25_DEBUG
- char bf[20];
- u16 size, toread, link, msg_code;
- u8 code, routine;
-
- cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code));
- cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link));
- cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size));
- /* at most 20 bytes are available... thanks to Daniela :) */
- toread = size < 20 ? size : 20;
- cycx_peek(&card->hw, cmd->buf + 10, &bf, toread);
- cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1);
- cycx_peek(&card->hw, cmd->buf + 10 + toread + 1, &routine, 1);
-
- pr_info("cycx_x25_irq_handler: X25_LOG (0x4500) indic.:\n");
- pr_info("cmd->buf=0x%X\n", cmd->buf);
- pr_info("Log message code=0x%X\n", msg_code);
- pr_info("Link=%d\n", link);
- pr_info("log code=0x%X\n", code);
- pr_info("log routine=0x%X\n", routine);
- pr_info("Message size=%d\n", size);
- hex_dump("Message", bf, toread);
-#endif
-}
-
-/* STATISTIC interrupt handler. */
-static void cycx_x25_irq_stat(struct cycx_device *card,
- struct cycx_x25_cmd *cmd)
-{
- cycx_peek(&card->hw, cmd->buf, &card->u.x.stats,
- sizeof(card->u.x.stats));
- hex_dump("cycx_x25_irq_stat", (unsigned char*)&card->u.x.stats,
- sizeof(card->u.x.stats));
- cycx_x25_dump_stats(&card->u.x.stats);
- wake_up_interruptible(&card->wait_stats);
-}
-
-/* Spurious interrupt handler.
- * o print a warning
- * If number of spurious interrupts exceeded some limit, then ??? */
-static void cycx_x25_irq_spurious(struct cycx_device *card,
- struct cycx_x25_cmd *cmd)
-{
- pr_info("%s: spurious interrupt (0x%X)!\n",
- card->devname, cmd->command);
-}
-#ifdef CYCLOMX_X25_DEBUG
-static void hex_dump(char *msg, unsigned char *p, int len)
-{
- print_hex_dump(KERN_INFO, msg, DUMP_PREFIX_OFFSET, 16, 1,
- p, len, true);
-}
-#endif
-
-/* Cyclom 2X Firmware-Specific Functions */
-/* Exec X.25 command. */
-static int x25_exec(struct cycx_device *card, int command, int link,
- void *d1, int len1, void *d2, int len2)
-{
- struct cycx_x25_cmd c;
- unsigned long flags;
- u32 addr = 0x1200 + 0x2E0 * link + 0x1E2;
- u8 retry = CYCX_X25_MAX_CMD_RETRY;
- int err = 0;
-
- c.command = command;
- c.link = link;
- c.len = len1 + len2;
-
- spin_lock_irqsave(&card->u.x.lock, flags);
-
- /* write command */
- cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf));
-
- /* write X.25 data */
- if (d1) {
- cycx_poke(&card->hw, addr, d1, len1);
-
- if (d2) {
- if (len2 > 254) {
- u32 addr1 = 0xA00 + 0x400 * link;
-
- cycx_poke(&card->hw, addr + len1, d2, 249);
- cycx_poke(&card->hw, addr1, ((u8*)d2) + 249,
- len2 - 249);
- } else
- cycx_poke(&card->hw, addr + len1, d2, len2);
- }
- }
-
- /* generate interruption, executing command */
- cycx_intr(&card->hw);
-
- /* wait till card->mbox == 0 */
- do {
- err = cycx_exec(card->mbox);
- } while (retry-- && err);
-
- spin_unlock_irqrestore(&card->u.x.lock, flags);
-
- return err;
-}
-
-/* Configure adapter. */
-static int cycx_x25_configure(struct cycx_device *card,
- struct cycx_x25_config *conf)
-{
- struct {
- u16 nlinks;
- struct cycx_x25_config conf[2];
- } x25_cmd_conf;
-
- memset(&x25_cmd_conf, 0, sizeof(x25_cmd_conf));
- x25_cmd_conf.nlinks = 2;
- x25_cmd_conf.conf[0] = *conf;
- /* FIXME: we need to find a way in the wanrouter framework
- to configure the second link, for now lets use it
- with the same config from the first link, fixing
- the interface type to RS232, the speed in 38400 and
- the clock to external */
- x25_cmd_conf.conf[1] = *conf;
- x25_cmd_conf.conf[1].link = 1;
- x25_cmd_conf.conf[1].speed = 5; /* 38400 */
- x25_cmd_conf.conf[1].clock = 8;
- x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */
-
- cycx_x25_dump_config(&x25_cmd_conf.conf[0]);
- cycx_x25_dump_config(&x25_cmd_conf.conf[1]);
-
- return x25_exec(card, X25_CONFIG, 0,
- &x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0);
-}
-
-/* Get protocol statistics. */
-static int cycx_x25_get_stats(struct cycx_device *card)
-{
- /* the firmware expects 20 in the size field!!!
- thanks to Daniela */
- int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0);
-
- if (err)
- return err;
-
- interruptible_sleep_on(&card->wait_stats);
-
- if (signal_pending(current))
- return -EINTR;
-
- card->wandev.stats.rx_packets = card->u.x.stats.n2_rx_frames;
- card->wandev.stats.rx_over_errors = card->u.x.stats.rx_over_errors;
- card->wandev.stats.rx_crc_errors = card->u.x.stats.rx_crc_errors;
- card->wandev.stats.rx_length_errors = 0; /* not available from fw */
- card->wandev.stats.rx_frame_errors = 0; /* not available from fw */
- card->wandev.stats.rx_missed_errors = card->u.x.stats.rx_aborts;
- card->wandev.stats.rx_dropped = 0; /* not available from fw */
- card->wandev.stats.rx_errors = 0; /* not available from fw */
- card->wandev.stats.tx_packets = card->u.x.stats.n2_tx_frames;
- card->wandev.stats.tx_aborted_errors = card->u.x.stats.tx_aborts;
- card->wandev.stats.tx_dropped = 0; /* not available from fw */
- card->wandev.stats.collisions = 0; /* not available from fw */
- card->wandev.stats.tx_errors = 0; /* not available from fw */
-
- cycx_x25_dump_devs(&card->wandev);
-
- return 0;
-}
-
-/* return the number of nibbles */
-static int byte_to_nibble(u8 *s, u8 *d, char *nibble)
-{
- int i = 0;
-
- if (*nibble && *s) {
- d[i] |= *s++ - '0';
- *nibble = 0;
- ++i;
- }
-
- while (*s) {
- d[i] = (*s - '0') << 4;
- if (*(s + 1))
- d[i] |= *(s + 1) - '0';
- else {
- *nibble = 1;
- break;
- }
- ++i;
- s += 2;
- }
-
- return i;
-}
-
-static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble)
-{
- if (nibble) {
- *d++ = '0' + (*s++ & 0x0F);
- --len;
- }
-
- while (len) {
- *d++ = '0' + (*s >> 4);
-
- if (--len) {
- *d++ = '0' + (*s & 0x0F);
- --len;
- } else break;
-
- ++s;
- }
-
- *d = '\0';
-}
-
-/* Place X.25 call. */
-static int x25_place_call(struct cycx_device *card,
- struct cycx_x25_channel *chan)
-{
- int err = 0,
- len;
- char d[64],
- nibble = 0,
- mylen = chan->local_addr ? strlen(chan->local_addr) : 0,
- remotelen = strlen(chan->addr);
- u8 key;
-
- if (card->u.x.connection_keys == ~0U) {
- pr_info("%s: too many simultaneous connection requests!\n",
- card->devname);
- return -EAGAIN;
- }
-
- key = ffz(card->u.x.connection_keys);
- set_bit(key, (void*)&card->u.x.connection_keys);
- ++key;
- dprintk(1, KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key);
- memset(d, 0, sizeof(d));
- d[1] = key; /* user key */
- d[2] = 0x10;
- d[4] = 0x0B;
-
- len = byte_to_nibble(chan->addr, d + 6, &nibble);
-
- if (chan->local_addr)
- len += byte_to_nibble(chan->local_addr, d + 6 + len, &nibble);
-
- if (nibble)
- ++len;
-
- d[5] = mylen << 4 | remotelen;
- d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanks to Daniela :) */
-
- if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link,
- &d, 7 + len + 1, NULL, 0)) != 0)
- clear_bit(--key, (void*)&card->u.x.connection_keys);
- else
- chan->lcn = -key;
-
- return err;
-}
-
-/* Place X.25 CONNECT RESPONSE. */
-static int cycx_x25_connect_response(struct cycx_device *card,
- struct cycx_x25_channel *chan)
-{
- u8 d[8];
-
- memset(d, 0, sizeof(d));
- d[0] = d[3] = chan->lcn;
- d[2] = 0x10;
- d[4] = 0x0F;
- d[7] = 0xCC; /* TCP/IP over X.25, thanks Daniela */
-
- return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0);
-}
-
-/* Place X.25 DISCONNECT RESPONSE. */
-static int cycx_x25_disconnect_response(struct cycx_device *card, u8 link,
- u8 lcn)
-{
- char d[5];
-
- memset(d, 0, sizeof(d));
- d[0] = d[3] = lcn;
- d[2] = 0x10;
- d[4] = 0x17;
-
- return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0);
-}
-
-/* Clear X.25 call. */
-static int x25_clear_call(struct cycx_device *card, u8 link, u8 lcn, u8 cause,
- u8 diagn)
-{
- u8 d[7];
-
- memset(d, 0, sizeof(d));
- d[0] = d[3] = lcn;
- d[2] = 0x10;
- d[4] = 0x13;
- d[5] = cause;
- d[6] = diagn;
-
- return x25_exec(card, X25_DISCONNECT_REQUEST, link, d, 7, NULL, 0);
-}
-
-/* Send X.25 data packet. */
-static int cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm,
- int len, void *buf)
-{
- u8 d[] = "?\xFF\x10??";
-
- d[0] = d[3] = lcn;
- d[4] = bitm;
-
- return x25_exec(card, X25_DATA_REQUEST, link, &d, 5, buf, len);
-}
-
-/* Miscellaneous */
-/* Find network device by its channel number. */
-static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev,
- s16 lcn)
-{
- struct net_device *dev = wandev->dev;
- struct cycx_x25_channel *chan;
-
- while (dev) {
- chan = netdev_priv(dev);
-
- if (chan->lcn == lcn)
- break;
- dev = chan->slave;
- }
- return dev;
-}
-
-/* Find network device by its remote dte address. */
-static struct net_device *
- cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte)
-{
- struct net_device *dev = wandev->dev;
- struct cycx_x25_channel *chan;
-
- while (dev) {
- chan = netdev_priv(dev);
-
- if (!strcmp(chan->addr, dte))
- break;
- dev = chan->slave;
- }
- return dev;
-}
-
-/* Initiate connection on the logical channel.
- * o for PVC we just get channel configuration
- * o for SVCs place an X.25 call
- *
- * Return: 0 connected
- * >0 connection in progress
- * <0 failure */
-static int cycx_x25_chan_connect(struct net_device *dev)
-{
- struct cycx_x25_channel *chan = netdev_priv(dev);
- struct cycx_device *card = chan->card;
-
- if (chan->svc) {
- if (!chan->addr[0])
- return -EINVAL; /* no destination address */
-
- dprintk(1, KERN_INFO "%s: placing X.25 call to %s...\n",
- card->devname, chan->addr);
-
- if (x25_place_call(card, chan))
- return -EIO;
-
- cycx_x25_set_chan_state(dev, WAN_CONNECTING);
- return 1;
- } else
- cycx_x25_set_chan_state(dev, WAN_CONNECTED);
-
- return 0;
-}
-
-/* Disconnect logical channel.
- * o if SVC then clear X.25 call */
-static void cycx_x25_chan_disconnect(struct net_device *dev)
-{
- struct cycx_x25_channel *chan = netdev_priv(dev);
-
- if (chan->svc) {
- x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0);
- cycx_x25_set_chan_state(dev, WAN_DISCONNECTING);
- } else
- cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
-}
-
-/* Called by kernel timer */
-static void cycx_x25_chan_timer(unsigned long d)
-{
- struct net_device *dev = (struct net_device *)d;
- struct cycx_x25_channel *chan = netdev_priv(dev);
-
- if (chan->state == WAN_CONNECTED)
- cycx_x25_chan_disconnect(dev);
- else
- pr_err("%s: %s for svc (%s) not connected!\n",
- chan->card->devname, __func__, dev->name);
-}
-
-/* Set logical channel state. */
-static void cycx_x25_set_chan_state(struct net_device *dev, u8 state)
-{
- struct cycx_x25_channel *chan = netdev_priv(dev);
- struct cycx_device *card = chan->card;
- unsigned long flags;
- char *string_state = NULL;
-
- spin_lock_irqsave(&card->lock, flags);
-
- if (chan->state != state) {
- if (chan->svc && chan->state == WAN_CONNECTED)
- del_timer(&chan->timer);
-
- switch (state) {
- case WAN_CONNECTED:
- string_state = "connected!";
- *(__be16*)dev->dev_addr = htons(chan->lcn);
- netif_wake_queue(dev);
- reset_timer(dev);
-
- if (chan->protocol == ETH_P_X25)
- cycx_x25_chan_send_event(dev,
- X25_IFACE_CONNECT);
-
- break;
- case WAN_CONNECTING:
- string_state = "connecting...";
- break;
- case WAN_DISCONNECTING:
- string_state = "disconnecting...";
- break;
- case WAN_DISCONNECTED:
- string_state = "disconnected!";
-
- if (chan->svc) {
- *(unsigned short*)dev->dev_addr = 0;
- chan->lcn = 0;
- }
-
- if (chan->protocol == ETH_P_X25)
- cycx_x25_chan_send_event(dev,
- X25_IFACE_DISCONNECT);
-
- netif_wake_queue(dev);
- break;
- }
-
- pr_info("%s: interface %s %s\n",
- card->devname, dev->name, string_state);
- chan->state = state;
- }
-
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* Send packet on a logical channel.
- * When this function is called, tx_skb field of the channel data space
- * points to the transmit socket buffer. When transmission is complete,
- * release socket buffer and reset 'tbusy' flag.
- *
- * Return: 0 - transmission complete
- * 1 - busy
- *
- * Notes:
- * 1. If packet length is greater than MTU for this channel, we'll fragment
- * the packet into 'complete sequence' using M-bit.
- * 2. When transmission is complete, an event notification should be issued
- * to the router. */
-static int cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb)
-{
- struct cycx_x25_channel *chan = netdev_priv(dev);
- struct cycx_device *card = chan->card;
- int bitm = 0; /* final packet */
- unsigned len = skb->len;
-
- if (skb->len > card->wandev.mtu) {
- len = card->wandev.mtu;
- bitm = 0x10; /* set M-bit (more data) */
- }
-
- if (cycx_x25_send(card, chan->link, chan->lcn, bitm, len, skb->data))
- return 1;
-
- if (bitm) {
- skb_pull(skb, len);
- return 1;
- }
-
- ++chan->ifstats.tx_packets;
- chan->ifstats.tx_bytes += len;
-
- return 0;
-}
-
-/* Send event (connection, disconnection, etc) to X.25 socket layer */
-
-static void cycx_x25_chan_send_event(struct net_device *dev, u8 event)
-{
- struct sk_buff *skb;
- unsigned char *ptr;
-
- if ((skb = dev_alloc_skb(1)) == NULL) {
- pr_err("%s: out of memory\n", __func__);
- return;
- }
-
- ptr = skb_put(skb, 1);
- *ptr = event;
-
- skb->protocol = x25_type_trans(skb, dev);
- netif_rx(skb);
-}
-
-/* Convert line speed in bps to a number used by cyclom 2x code. */
-static u8 bps_to_speed_code(u32 bps)
-{
- u8 number = 0; /* defaults to the lowest (1200) speed ;> */
-
- if (bps >= 512000) number = 8;
- else if (bps >= 256000) number = 7;
- else if (bps >= 64000) number = 6;
- else if (bps >= 38400) number = 5;
- else if (bps >= 19200) number = 4;
- else if (bps >= 9600) number = 3;
- else if (bps >= 4800) number = 2;
- else if (bps >= 2400) number = 1;
-
- return number;
-}
-
-/* log base 2 */
-static u8 cycx_log2(u32 n)
-{
- u8 log = 0;
-
- if (!n)
- return 0;
-
- while (n > 1) {
- n >>= 1;
- ++log;
- }
-
- return log;
-}
-
-/* Convert decimal string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are converted. */
-static unsigned dec_to_uint(u8 *str, int len)
-{
- unsigned val = 0;
-
- if (!len)
- len = strlen(str);
-
- for (; len && isdigit(*str); ++str, --len)
- val = (val * 10) + (*str - (unsigned) '0');
-
- return val;
-}
-
-static void reset_timer(struct net_device *dev)
-{
- struct cycx_x25_channel *chan = netdev_priv(dev);
-
- if (chan->svc)
- mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ);
-}
-#ifdef CYCLOMX_X25_DEBUG
-static void cycx_x25_dump_config(struct cycx_x25_config *conf)
-{
- pr_info("X.25 configuration\n");
- pr_info("-----------------\n");
- pr_info("link number=%d\n", conf->link);
- pr_info("line speed=%d\n", conf->speed);
- pr_info("clock=%sternal\n", conf->clock == 8 ? "Ex" : "In");
- pr_info("# level 2 retransm.=%d\n", conf->n2);
- pr_info("level 2 window=%d\n", conf->n2win);
- pr_info("level 3 window=%d\n", conf->n3win);
- pr_info("# logical channels=%d\n", conf->nvc);
- pr_info("level 3 pkt len=%d\n", conf->pktlen);
- pr_info("my address=%d\n", conf->locaddr);
- pr_info("remote address=%d\n", conf->remaddr);
- pr_info("t1=%d seconds\n", conf->t1);
- pr_info("t2=%d seconds\n", conf->t2);
- pr_info("t21=%d seconds\n", conf->t21);
- pr_info("# PVCs=%d\n", conf->npvc);
- pr_info("t23=%d seconds\n", conf->t23);
- pr_info("flags=0x%x\n", conf->flags);
-}
-
-static void cycx_x25_dump_stats(struct cycx_x25_stats *stats)
-{
- pr_info("X.25 statistics\n");
- pr_info("--------------\n");
- pr_info("rx_crc_errors=%d\n", stats->rx_crc_errors);
- pr_info("rx_over_errors=%d\n", stats->rx_over_errors);
- pr_info("n2_tx_frames=%d\n", stats->n2_tx_frames);
- pr_info("n2_rx_frames=%d\n", stats->n2_rx_frames);
- pr_info("tx_timeouts=%d\n", stats->tx_timeouts);
- pr_info("rx_timeouts=%d\n", stats->rx_timeouts);
- pr_info("n3_tx_packets=%d\n", stats->n3_tx_packets);
- pr_info("n3_rx_packets=%d\n", stats->n3_rx_packets);
- pr_info("tx_aborts=%d\n", stats->tx_aborts);
- pr_info("rx_aborts=%d\n", stats->rx_aborts);
-}
-
-static void cycx_x25_dump_devs(struct wan_device *wandev)
-{
- struct net_device *dev = wandev->dev;
-
- pr_info("X.25 dev states\n");
- pr_info("name: addr: txoff: protocol:\n");
- pr_info("---------------------------------------\n");
-
- while(dev) {
- struct cycx_x25_channel *chan = netdev_priv(dev);
-
- pr_info("%-5.5s %-15.15s %d ETH_P_%s\n",
- chan->name, chan->addr, netif_queue_stopped(dev),
- chan->protocol == ETH_P_IP ? "IP" : "X25");
- dev = chan->slave;
- }
-}
-
-#endif /* CYCLOMX_X25_DEBUG */
-/* End */
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 56941d6547eb..3f0c4f268751 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -2448,11 +2448,9 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* Allocate driver private data */
- card = kzalloc(sizeof (struct fst_card_info), GFP_KERNEL);
- if (card == NULL) {
- pr_err("FarSync card found but insufficient memory for driver storage\n");
+ card = kzalloc(sizeof(struct fst_card_info), GFP_KERNEL);
+ if (card == NULL)
return -ENOMEM;
- }
/* Try to enable the device */
if ((err = pci_enable_device(pdev)) != 0) {
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index 10cc7df95498..a0a932c63d0a 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -280,14 +280,13 @@ int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
if (!try_module_get(proto->module))
return -ENOSYS;
- if (size)
- if ((dev_to_hdlc(dev)->state = kmalloc(size,
- GFP_KERNEL)) == NULL) {
- netdev_warn(dev,
- "Memory squeeze on hdlc_proto_attach()\n");
+ if (size) {
+ dev_to_hdlc(dev)->state = kmalloc(size, GFP_KERNEL);
+ if (dev_to_hdlc(dev)->state == NULL) {
module_put(proto->module);
return -ENOBUFS;
}
+ }
dev_to_hdlc(dev)->proto = proto;
return 0;
}
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 44db8b75a531..5895f1978691 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -128,7 +128,6 @@ static int x25_asy_change_mtu(struct net_device *dev, int newmtu)
rbuff = kmalloc(len + 4, GFP_ATOMIC);
if (xbuff == NULL || rbuff == NULL) {
- netdev_warn(dev, "unable to grow X.25 buffers, MTU change cancelled\n");
kfree(xbuff);
kfree(rbuff);
return -ENOMEM;
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index def12b38cbf7..c9c711dcd0e6 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -1055,7 +1055,6 @@ int i2400m_read_mac_addr(struct i2400m *i2400m)
result = 0;
}
net_dev->addr_len = ETH_ALEN;
- memcpy(net_dev->perm_addr, ack_buf.ack_pl, ETH_ALEN);
memcpy(net_dev->dev_addr, ack_buf.ack_pl, ETH_ALEN);
error_read_mac:
d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, result);
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index 1d76ae855f07..48896138418f 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -156,7 +156,7 @@ void i2400m_wake_tx_work(struct work_struct *ws)
struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws);
struct net_device *net_dev = i2400m->wimax_dev.net_dev;
struct device *dev = i2400m_dev(i2400m);
- struct sk_buff *skb = i2400m->wake_tx_skb;
+ struct sk_buff *skb;
unsigned long flags;
spin_lock_irqsave(&i2400m->tx_lock, flags);
@@ -236,23 +236,26 @@ void i2400m_tx_prep_header(struct sk_buff *skb)
void i2400m_net_wake_stop(struct i2400m *i2400m)
{
struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *wake_tx_skb;
+ unsigned long flags;
d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
- /* See i2400m_hard_start_xmit(), references are taken there
- * and here we release them if the work was still
- * pending. Note we can't differentiate work not pending vs
- * never scheduled, so the NULL check does that. */
- if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
- && i2400m->wake_tx_skb != NULL) {
- unsigned long flags;
- struct sk_buff *wake_tx_skb;
- spin_lock_irqsave(&i2400m->tx_lock, flags);
- wake_tx_skb = i2400m->wake_tx_skb; /* compat help */
- i2400m->wake_tx_skb = NULL; /* compat help */
- spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+ /*
+ * See i2400m_hard_start_xmit(), references are taken there and
+ * here we release them if the packet was still pending.
+ */
+ cancel_work_sync(&i2400m->wake_tx_ws);
+
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ wake_tx_skb = i2400m->wake_tx_skb;
+ i2400m->wake_tx_skb = NULL;
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+
+ if (wake_tx_skb) {
i2400m_put(i2400m);
kfree_skb(wake_tx_skb);
}
+
d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
}
@@ -288,7 +291,7 @@ int i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev,
* and if pending, release those resources. */
result = 0;
spin_lock_irqsave(&i2400m->tx_lock, flags);
- if (!work_pending(&i2400m->wake_tx_ws)) {
+ if (!i2400m->wake_tx_skb) {
netif_stop_queue(net_dev);
i2400m_get(i2400m);
i2400m->wake_tx_skb = skb_get(skb); /* transfer ref count */
@@ -596,12 +599,12 @@ static void i2400m_get_drvinfo(struct net_device *net_dev,
{
struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
- strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1);
- strncpy(info->fw_version,
- i2400m->fw_name ? : "", sizeof(info->fw_version) - 1);
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ strlcpy(info->fw_version, i2400m->fw_name ? : "",
+ sizeof(info->fw_version));
if (net_dev->dev.parent)
- strncpy(info->bus_info, dev_name(net_dev->dev.parent),
- sizeof(info->bus_info) - 1);
+ strlcpy(info->bus_info, dev_name(net_dev->dev.parent),
+ sizeof(info->bus_info));
}
static const struct ethtool_ops i2400m_ethtool_ops = {
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 37becfcc98f2..0b602951ff6b 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -1346,29 +1346,22 @@ EXPORT_SYMBOL(i2400m_unknown_barker);
int i2400m_rx_setup(struct i2400m *i2400m)
{
int result = 0;
- struct device *dev = i2400m_dev(i2400m);
i2400m->rx_reorder = i2400m_rx_reorder_disabled? 0 : 1;
if (i2400m->rx_reorder) {
unsigned itr;
- size_t size;
struct i2400m_roq_log *rd;
result = -ENOMEM;
- size = sizeof(i2400m->rx_roq[0]) * (I2400M_RO_CIN + 1);
- i2400m->rx_roq = kzalloc(size, GFP_KERNEL);
- if (i2400m->rx_roq == NULL) {
- dev_err(dev, "RX: cannot allocate %zu bytes for "
- "reorder queues\n", size);
+ i2400m->rx_roq = kcalloc(I2400M_RO_CIN + 1,
+ sizeof(i2400m->rx_roq[0]), GFP_KERNEL);
+ if (i2400m->rx_roq == NULL)
goto error_roq_alloc;
- }
- size = sizeof(*i2400m->rx_roq[0].log) * (I2400M_RO_CIN + 1);
- rd = kzalloc(size, GFP_KERNEL);
+ rd = kcalloc(I2400M_RO_CIN + 1, sizeof(*i2400m->rx_roq[0].log),
+ GFP_KERNEL);
if (rd == NULL) {
- dev_err(dev, "RX: cannot allocate %zu bytes for "
- "reorder queues log areas\n", size);
result = -ENOMEM;
goto error_roq_log_alloc;
}
diff --git a/drivers/net/wimax/i2400m/usb-notif.c b/drivers/net/wimax/i2400m/usb-notif.c
index d44b545f4082..fc1355d98bc6 100644
--- a/drivers/net/wimax/i2400m/usb-notif.c
+++ b/drivers/net/wimax/i2400m/usb-notif.c
@@ -199,7 +199,6 @@ int i2400mu_notification_setup(struct i2400mu *i2400mu)
d_fnstart(4, dev, "(i2400m %p)\n", i2400mu);
buf = kmalloc(I2400MU_MAX_NOTIFICATION_LEN, GFP_KERNEL | GFP_DMA);
if (buf == NULL) {
- dev_err(dev, "notification: buffer allocation failed\n");
ret = -ENOMEM;
goto error_buf_alloc;
}
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 080f36303a4f..cd15a93d9084 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -346,9 +346,9 @@ static void i2400mu_get_drvinfo(struct net_device *net_dev,
struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
struct usb_device *udev = i2400mu->usb_dev;
- strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1);
- strncpy(info->fw_version,
- i2400m->fw_name ? : "", sizeof(info->fw_version) - 1);
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ strlcpy(info->fw_version, i2400m->fw_name ? : "",
+ sizeof(info->fw_version));
usb_make_path(udev, info->bus_info, sizeof(info->bus_info));
}
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 28aa05f60c26..f8f0156dff4e 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -138,7 +138,7 @@ config AIRO_CS
config PCMCIA_WL3501
tristate "Planet WL3501 PCMCIA cards"
- depends on EXPERIMENTAL && PCMCIA
+ depends on PCMCIA
select WIRELESS_EXT
select WEXT_SPY
help
@@ -148,7 +148,7 @@ config PCMCIA_WL3501
config PRISM54
tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)'
- depends on PCI && EXPERIMENTAL
+ depends on PCI
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV
@@ -187,7 +187,7 @@ config USB_ZD1201
config USB_NET_RNDIS_WLAN
tristate "Wireless RNDIS USB support"
- depends on USB && EXPERIMENTAL
+ depends on USB
depends on CFG80211
select USB_USBNET
select USB_NET_CDCETHER
@@ -217,7 +217,7 @@ source "drivers/net/wireless/rtl818x/Kconfig"
config ADM8211
tristate "ADMtek ADM8211 support"
- depends on MAC80211 && PCI && EXPERIMENTAL
+ depends on MAC80211 && PCI
select CRC32
select EEPROM_93CX6
---help---
@@ -257,7 +257,7 @@ config MAC80211_HWSIM
config MWL8K
tristate "Marvell 88W8xxx PCI/PCIe Wireless support"
- depends on MAC80211 && PCI && EXPERIMENTAL
+ depends on MAC80211 && PCI
---help---
This driver supports Marvell TOPDOG 802.11 wireless cards.
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index 630577dd3a7a..956024a636e6 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -69,10 +69,9 @@ static int airo_probe(struct pcmcia_device *p_dev)
/* Allocate space for private device-specific data */
local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
- if (!local) {
- printk(KERN_ERR "airo_cs: no memory for new device\n");
+ if (!local)
return -ENOMEM;
- }
+
p_dev->priv = local;
return airo_config(p_dev);
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 77fa4286e5e9..5ac5f7ae2721 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2164,10 +2164,8 @@ static int at76_alloc_urbs(struct at76_priv *priv,
buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE;
priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
- if (!priv->bulk_out_buffer) {
- dev_err(&interface->dev, "cannot allocate output buffer\n");
+ if (!priv->bulk_out_buffer)
return -ENOMEM;
- }
at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 30ca0a60a64c..1d264c0f5a9b 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -240,13 +240,14 @@ static const struct ath_ops ath5k_common_ops = {
* Driver Initialization *
\***********************/
-static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+static void ath5k_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath5k_hw *ah = hw->priv;
struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
- return ath_reg_notifier_apply(wiphy, request, regulatory);
+ ath_reg_notifier_apply(wiphy, request, regulatory);
}
/********************\
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index ab363f34b4df..a78afa98c650 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1613,6 +1613,10 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
ah->ah_cal_mask |= AR5K_CALIBRATION_NF;
ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel);
+ if (WARN_ON(ee_mode < 0)) {
+ ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF;
+ return;
+ }
/* completed NF calibration, test threshold */
nf = ath5k_hw_read_measured_noise_floor(ah);
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 4084b1076286..e2d8b2cf19eb 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -985,6 +985,8 @@ ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
return;
ee_mode = ath5k_eeprom_mode_from_channel(channel);
+ if (WARN_ON(ee_mode < 0))
+ return;
/* Adjust power delta for channel 14 */
if (channel->center_freq == 2484)
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig
index 26c4b7220859..630c83db056e 100644
--- a/drivers/net/wireless/ath/ath6kl/Kconfig
+++ b/drivers/net/wireless/ath/ath6kl/Kconfig
@@ -18,7 +18,6 @@ config ATH6KL_USB
depends on ATH6KL
depends on USB
depends on CFG80211
- depends on EXPERIMENTAL
---help---
This module adds support for wireless adapters based on
Atheros AR6004 chipset running over USB. This is still under
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 5516a8ccc3c6..752ffc4f4166 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -427,6 +427,30 @@ static bool ath6kl_is_tx_pending(struct ath6kl *ar)
return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0;
}
+static void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif,
+ bool enable)
+{
+ int err;
+
+ if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
+ return;
+
+ if (vif->nw_type != INFRA_NETWORK)
+ return;
+
+ if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
+ vif->ar->fw_capabilities))
+ return;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
+ enable ? "enable" : "disable");
+
+ err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
+ vif->fw_vif_idx, enable);
+ if (err)
+ ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
+ enable ? "enable" : "disable", err);
+}
static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme)
@@ -616,13 +640,13 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
vif->req_bssid, vif->ch_hint,
ar->connect_ctrl_flags, nw_subtype);
- /* disable background scan if period is 0 */
- if (sme->bg_scan_period == 0)
+ if (sme->bg_scan_period == 0) {
+ /* disable background scan if period is 0 */
sme->bg_scan_period = 0xffff;
-
- /* configure default value if not specified */
- if (sme->bg_scan_period == -1)
+ } else if (sme->bg_scan_period == -1) {
+ /* configure default value if not specified */
sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
+ }
ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0,
sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
@@ -767,7 +791,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
nw_type & ADHOC_CREATOR ? "creator" : "joiner");
cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(ar->wiphy, bss);
return;
}
@@ -778,7 +802,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
assoc_req_ie, assoc_req_len,
assoc_resp_ie, assoc_resp_len,
WLAN_STATUS_SUCCESS, GFP_KERNEL);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(ar->wiphy, bss);
} else if (vif->sme_state == SME_CONNECTED) {
/* inform roam event to cfg80211 */
cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
@@ -1454,10 +1478,10 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
return -EIO;
if (pmgmt) {
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
mode.pwr_mode = REC_POWER;
} else {
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__);
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__);
mode.pwr_mode = MAX_PERF_POWER;
}
@@ -1509,7 +1533,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
list_del(&vif->list);
spin_unlock_bh(&ar->list_lock);
- ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
+ ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
ath6kl_cfg80211_vif_cleanup(vif);
@@ -1559,17 +1583,13 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
set_iface_type:
switch (type) {
case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
vif->next_mode = INFRA_NETWORK;
break;
case NL80211_IFTYPE_ADHOC:
vif->next_mode = ADHOC_NETWORK;
break;
case NL80211_IFTYPE_AP:
- vif->next_mode = AP_NETWORK;
- break;
- case NL80211_IFTYPE_P2P_CLIENT:
- vif->next_mode = INFRA_NETWORK;
- break;
case NL80211_IFTYPE_P2P_GO:
vif->next_mode = AP_NETWORK;
break;
@@ -1778,14 +1798,14 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
if (vif->target_stats.rx_byte) {
sinfo->rx_bytes = vif->target_stats.rx_byte;
- sinfo->filled |= STATION_INFO_RX_BYTES;
+ sinfo->filled |= STATION_INFO_RX_BYTES64;
sinfo->rx_packets = vif->target_stats.rx_pkt;
sinfo->filled |= STATION_INFO_RX_PACKETS;
}
if (vif->target_stats.tx_byte) {
sinfo->tx_bytes = vif->target_stats.tx_byte;
- sinfo->filled |= STATION_INFO_TX_BYTES;
+ sinfo->filled |= STATION_INFO_TX_BYTES64;
sinfo->tx_packets = vif->target_stats.tx_pkt;
sinfo->filled |= STATION_INFO_TX_PACKETS;
}
@@ -2673,30 +2693,6 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
return 0;
}
-void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable)
-{
- int err;
-
- if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
- return;
-
- if (vif->nw_type != INFRA_NETWORK)
- return;
-
- if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
- vif->ar->fw_capabilities))
- return;
-
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
- enable ? "enable" : "disable");
-
- err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
- vif->fw_vif_idx, enable);
- if (err)
- ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
- enable ? "enable" : "disable", err);
-}
-
static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
u8 *rsn_capab)
{
@@ -2776,9 +2772,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
ar->ap_mode_bkey.valid = false;
- /* TODO:
- * info->interval
- */
+ ret = ath6kl_wmi_ap_set_beacon_intvl_cmd(ar->wmi, vif->fw_vif_idx,
+ info->beacon_interval);
+
+ if (ret)
+ ath6kl_warn("Failed to set beacon interval: %d\n", ret);
ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx,
info->dtim_period);
@@ -3492,8 +3490,8 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
ath6kl_cfg80211_stop(vif);
}
-static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
- struct regulatory_request *request)
+static void ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
+ struct regulatory_request *request)
{
struct ath6kl *ar = wiphy_priv(wiphy);
u32 rates[IEEE80211_NUM_BANDS];
@@ -3506,17 +3504,13 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
request->processed ? " processed" : "",
request->initiator, request->user_reg_hint_type);
- /*
- * As firmware is not able intersect regdoms, we can only listen to
- * cellular hints.
- */
if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
- return -EOPNOTSUPP;
+ return;
ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2);
if (ret) {
ath6kl_err("failed to set regdomain: %d\n", ret);
- return ret;
+ return;
}
/*
@@ -3536,10 +3530,8 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
if (ret) {
ath6kl_err("failed to start scan for a regdomain change: %d\n",
ret);
- return ret;
+ return;
}
-
- return 0;
}
static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
@@ -3563,6 +3555,37 @@ static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
return 0;
}
+void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready)
+{
+ static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ bool discon_issued;
+
+ netif_stop_queue(vif->ndev);
+
+ clear_bit(WLAN_ENABLED, &vif->flags);
+
+ if (wmi_ready) {
+ discon_issued = test_bit(CONNECTED, &vif->flags) ||
+ test_bit(CONNECT_PEND, &vif->flags);
+ ath6kl_disconnect(vif);
+ del_timer(&vif->disconnect_timer);
+
+ if (discon_issued)
+ ath6kl_disconnect_event(vif, DISCONNECT_CMD,
+ (vif->nw_type & AP_NETWORK) ?
+ bcast_mac : vif->bssid,
+ 0, NULL, 0);
+ }
+
+ if (vif->scan_req) {
+ cfg80211_scan_done(vif->scan_req, true);
+ vif->scan_req = NULL;
+ }
+
+ /* need to clean up enhanced bmiss detection fw state */
+ ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
+}
+
void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
{
struct ath6kl *ar = vif->ar;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index e5e70f3a8ca8..b59becd91aea 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -61,7 +61,5 @@ void ath6kl_cfg80211_cleanup(struct ath6kl *ar);
struct ath6kl *ath6kl_cfg80211_create(void);
void ath6kl_cfg80211_destroy(struct ath6kl *ar);
-/* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */
-void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable);
#endif /* ATH6KL_CFG80211_H */
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 189d8faf8c87..61b2f98b4e77 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -940,7 +940,7 @@ void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
bool wait_fot_compltn, bool cold_reset);
void ath6kl_init_control_info(struct ath6kl_vif *vif);
struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar);
-void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready);
+void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready);
int ath6kl_init_hw_start(struct ath6kl *ar);
int ath6kl_init_hw_stop(struct ath6kl *ar);
int ath6kl_init_fetch_firmwares(struct ath6kl *ar);
diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
index ba6bd497b787..281390178e3d 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
@@ -509,9 +509,7 @@ static void destroy_htc_txctrl_packet(struct htc_packet *packet)
{
struct sk_buff *skb;
skb = packet->skb;
- if (skb != NULL)
- dev_kfree_skb(skb);
-
+ dev_kfree_skb(skb);
kfree(packet);
}
@@ -969,6 +967,22 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
u16 payload_len;
int status = 0;
+ /*
+ * ar->htc_target can be NULL due to a race condition that can occur
+ * during driver initialization(we do 'ath6kl_hif_power_on' before
+ * initializing 'ar->htc_target' via 'ath6kl_htc_create').
+ * 'ath6kl_hif_power_on' assigns 'ath6kl_recv_complete' as
+ * usb_complete_t/callback function for 'usb_fill_bulk_urb'.
+ * Thus the possibility of ar->htc_target being NULL
+ * via ath6kl_recv_complete -> ath6kl_usb_io_comp_work.
+ */
+ if (WARN_ON_ONCE(!target)) {
+ ath6kl_err("Target not yet initialized\n");
+ status = -EINVAL;
+ goto free_skb;
+ }
+
+
netdata = skb->data;
netlen = skb->len;
@@ -1054,6 +1068,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
dev_kfree_skb(skb);
skb = NULL;
+
goto free_skb;
}
@@ -1089,8 +1104,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
skb = NULL;
free_skb:
- if (skb != NULL)
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
return status;
@@ -1184,7 +1198,7 @@ static void reset_endpoint_states(struct htc_target *target)
INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue);
INIT_LIST_HEAD(&ep->rx_bufq);
ep->target = target;
- ep->pipe.tx_credit_flow_enabled = (bool) 1; /* FIXME */
+ ep->pipe.tx_credit_flow_enabled = true;
}
}
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index f21fa322e5ca..5d434cf88f35 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1715,38 +1715,6 @@ void ath6kl_init_hw_restart(struct ath6kl *ar)
}
}
-/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */
-void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
-{
- static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- bool discon_issued;
-
- netif_stop_queue(vif->ndev);
-
- clear_bit(WLAN_ENABLED, &vif->flags);
-
- if (wmi_ready) {
- discon_issued = test_bit(CONNECTED, &vif->flags) ||
- test_bit(CONNECT_PEND, &vif->flags);
- ath6kl_disconnect(vif);
- del_timer(&vif->disconnect_timer);
-
- if (discon_issued)
- ath6kl_disconnect_event(vif, DISCONNECT_CMD,
- (vif->nw_type & AP_NETWORK) ?
- bcast_mac : vif->bssid,
- 0, NULL, 0);
- }
-
- if (vif->scan_req) {
- cfg80211_scan_done(vif->scan_req, true);
- vif->scan_req = NULL;
- }
-
- /* need to clean up enhanced bmiss detection fw state */
- ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
-}
-
void ath6kl_stop_txrx(struct ath6kl *ar)
{
struct ath6kl_vif *vif, *tmp_vif;
@@ -1766,7 +1734,7 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
list_for_each_entry_safe(vif, tmp_vif, &ar->vif_list, list) {
list_del(&vif->list);
spin_unlock_bh(&ar->list_lock);
- ath6kl_cleanup_vif(vif, test_bit(WMI_READY, &ar->flag));
+ ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
rtnl_lock();
ath6kl_cfg80211_vif_cleanup(vif);
rtnl_unlock();
@@ -1801,8 +1769,6 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
"attempting to reset target on instance destroy\n");
ath6kl_reset_device(ar, ar->target_type, true, true);
- clear_bit(WLAN_ENABLED, &ar->flag);
-
up(&ar->sem);
}
EXPORT_SYMBOL(ath6kl_stop_txrx);
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index 62bcc0d5bc23..5fcd342762de 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -159,10 +159,8 @@ static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe,
static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context)
{
- if (urb_context->skb != NULL) {
- dev_kfree_skb(urb_context->skb);
- urb_context->skb = NULL;
- }
+ dev_kfree_skb(urb_context->skb);
+ urb_context->skb = NULL;
ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context);
}
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 998f8b0f62fd..d76b5bd81a0d 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -751,6 +751,23 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
NO_SYNC_WMIFLAG);
}
+int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx,
+ u32 beacon_intvl)
+{
+ struct sk_buff *skb;
+ struct set_beacon_int_cmd *cmd;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct set_beacon_int_cmd *) skb->data;
+
+ cmd->beacon_intvl = cpu_to_le32(beacon_intvl);
+ return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+ WMI_SET_BEACON_INT_CMDID, NO_SYNC_WMIFLAG);
+}
+
int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)
{
struct sk_buff *skb;
@@ -1108,7 +1125,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
kfree(mgmt);
if (bss == NULL)
return -ENOMEM;
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(ar->wiphy, bss);
/*
* Firmware doesn't return any event when scheduled scan has
@@ -2480,16 +2497,11 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
free_cmd_skb:
/* free up any resources left over (possibly due to an error) */
- if (skb)
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
free_data_skb:
- for (index = 0; index < num_pri_streams; index++) {
- if (data_sync_bufs[index].skb != NULL) {
- dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].
- skb);
- }
- }
+ for (index = 0; index < num_pri_streams; index++)
+ dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].skb);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 98b1755e67f4..b5f226503baf 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1660,6 +1660,10 @@ struct roam_ctrl_cmd {
u8 roam_ctrl;
} __packed;
+struct set_beacon_int_cmd {
+ __le32 beacon_intvl;
+} __packed;
+
struct set_dtim_cmd {
__le32 dtim_period;
} __packed;
@@ -2649,6 +2653,8 @@ int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi);
int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
+int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx,
+ u32 beacon_interval);
int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode);
int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 7647ed6b73d7..17507dc8a1e7 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -58,6 +58,7 @@ config ATH9K_DEBUGFS
bool "Atheros ath9k debugging"
depends on ATH9K
select MAC80211_DEBUGFS
+ select RELAY
---help---
Say Y, if you need access to ath9k's statistics for
interrupts, rate control, etc.
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 3a69804f4c16..d1ff3c246a12 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -86,29 +86,25 @@ static int ath_ahb_probe(struct platform_device *pdev)
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "no platform data specified\n");
- ret = -EINVAL;
- goto err_out;
+ return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "no memory resource found\n");
- ret = -ENXIO;
- goto err_out;
+ return -ENXIO;
}
- mem = ioremap_nocache(res->start, resource_size(res));
+ mem = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
if (mem == NULL) {
dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
- goto err_out;
+ return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
dev_err(&pdev->dev, "no IRQ resource found\n");
- ret = -ENXIO;
- goto err_iounmap;
+ return -ENXIO;
}
irq = res->start;
@@ -116,8 +112,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
if (hw == NULL) {
dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
- ret = -ENOMEM;
- goto err_iounmap;
+ return -ENOMEM;
}
SET_IEEE80211_DEV(hw, &pdev->dev);
@@ -156,9 +151,6 @@ static int ath_ahb_probe(struct platform_device *pdev)
err_free_hw:
ieee80211_free_hw(hw);
platform_set_drvdata(pdev, NULL);
- err_iounmap:
- iounmap(mem);
- err_out:
return ret;
}
@@ -168,12 +160,10 @@ static int ath_ahb_remove(struct platform_device *pdev)
if (hw) {
struct ath_softc *sc = hw->priv;
- void __iomem *mem = sc->mem;
ath9k_deinit_device(sc);
free_irq(sc->irq, sc);
ieee80211_free_hw(sc->hw);
- iounmap(mem);
platform_set_drvdata(pdev, NULL);
}
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index e09ec40ce71a..7ecd40f07a74 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -152,7 +152,8 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
aniState->ofdmNoiseImmunityLevel,
immunityLevel, BEACON_RSSI(ah),
- aniState->rssiThrLow, aniState->rssiThrHigh);
+ ATH9K_ANI_RSSI_THR_LOW,
+ ATH9K_ANI_RSSI_THR_HIGH);
if (!scan)
aniState->ofdmNoiseImmunityLevel = immunityLevel;
@@ -173,7 +174,7 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
weak_sig = entry_ofdm->ofdm_weak_signal_on;
if (ah->opmode == NL80211_IFTYPE_STATION &&
- BEACON_RSSI(ah) <= aniState->rssiThrHigh)
+ BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
weak_sig = true;
if (aniState->ofdmWeakSigDetect != weak_sig)
@@ -216,11 +217,11 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
aniState->cckNoiseImmunityLevel, immunityLevel,
- BEACON_RSSI(ah), aniState->rssiThrLow,
- aniState->rssiThrHigh);
+ BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW,
+ ATH9K_ANI_RSSI_THR_HIGH);
if (ah->opmode == NL80211_IFTYPE_STATION &&
- BEACON_RSSI(ah) <= aniState->rssiThrLow &&
+ BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW &&
immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
@@ -418,9 +419,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
return;
aniState = &ah->curchan->ani;
- if (WARN_ON(!aniState))
- return;
-
if (!ath9k_hw_ani_read_counters(ah))
return;
@@ -489,23 +487,6 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
-void ath9k_hw_ani_setup(struct ath_hw *ah)
-{
- int i;
-
- static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
- static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
- static const int coarseLow[] = { -64, -64, -64, -64, -70 };
- static const int firpwr[] = { -78, -78, -78, -78, -80 };
-
- for (i = 0; i < 5; i++) {
- ah->totalSizeDesired[i] = totalSizeDesired[i];
- ah->coarse_high[i] = coarseHigh[i];
- ah->coarse_low[i] = coarseLow[i];
- ah->firpwr[i] = firpwr[i];
- }
-}
-
void ath9k_hw_ani_init(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
@@ -531,8 +512,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ani->ofdmsTurn = true;
- ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
- ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index 1485bf5e3518..dddb1361039a 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -104,7 +104,6 @@ struct ath9k_ani_default {
};
struct ar5416AniState {
- struct ath9k_channel *c;
u8 noiseImmunityLevel;
u8 ofdmNoiseImmunityLevel;
u8 cckNoiseImmunityLevel;
@@ -113,15 +112,9 @@ struct ar5416AniState {
u8 spurImmunityLevel;
u8 firstepLevel;
u8 ofdmWeakSigDetect;
- u8 cckWeakSigThreshold;
u32 listenTime;
- int32_t rssiThrLow;
- int32_t rssiThrHigh;
u32 ofdmPhyErrCount;
u32 cckPhyErrCount;
- int16_t pktRssi[2];
- int16_t ofdmErrRssi[2];
- int16_t cckErrRssi[2];
struct ath9k_ani_default iniDef;
};
@@ -147,7 +140,6 @@ struct ar5416Stats {
void ath9k_enable_mib_counters(struct ath_hw *ah);
void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
-void ath9k_hw_ani_setup(struct ath_hw *ah);
void ath9k_hw_ani_init(struct ath_hw *ah);
#endif /* ANI_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
index f81e7fc60a36..467ccfae2cee 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
@@ -466,7 +466,7 @@ static const u32 ar5416Bank0[][2] = {
};
static const u32 ar5416BB_RfGain[][3] = {
- /* Addr 5G_HT20 5G_HT40 */
+ /* Addr 5G 2G */
{0x00009a00, 0x00000000, 0x00000000},
{0x00009a04, 0x00000040, 0x00000040},
{0x00009a08, 0x00000080, 0x00000080},
@@ -546,12 +546,12 @@ static const u32 ar5416Bank2[][2] = {
};
static const u32 ar5416Bank3[][3] = {
- /* Addr 5G_HT20 5G_HT40 */
+ /* Addr 5G 2G */
{0x000098f0, 0x01400018, 0x01c00018},
};
static const u32 ar5416Bank6[][3] = {
- /* Addr 5G_HT20 5G_HT40 */
+ /* Addr 5G 2G */
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
@@ -588,7 +588,7 @@ static const u32 ar5416Bank6[][3] = {
};
static const u32 ar5416Bank6TPC[][3] = {
- /* Addr 5G_HT20 5G_HT40 */
+ /* Addr 5G 2G */
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 874186bfda41..fd69376ecc83 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -470,16 +470,15 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
{
#define ATH_ALLOC_BANK(bank, size) do { \
- bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \
- if (!bank) { \
- ath_err(common, "Cannot allocate RF banks\n"); \
- return -ENOMEM; \
- } \
+ bank = devm_kzalloc(ah->dev, sizeof(u32) * size, GFP_KERNEL); \
+ if (!bank) \
+ goto error; \
} while (0);
struct ath_common *common = ath9k_hw_common(ah);
- BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
+ if (AR_SREV_9280_20_OR_LATER(ah))
+ return 0;
ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
@@ -492,35 +491,12 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
return 0;
#undef ATH_ALLOC_BANK
+error:
+ ath_err(common, "Cannot allocate RF banks\n");
+ return -ENOMEM;
}
-/**
- * ar5008_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers
- * @ah: atheros hardware struture
- * For the external AR2133/AR5133 radios banks.
- */
-static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah)
-{
-#define ATH_FREE_BANK(bank) do { \
- kfree(bank); \
- bank = NULL; \
- } while (0);
-
- BUG_ON(AR_SREV_9280_20_OR_LATER(ah));
-
- ATH_FREE_BANK(ah->analogBank0Data);
- ATH_FREE_BANK(ah->analogBank1Data);
- ATH_FREE_BANK(ah->analogBank2Data);
- ATH_FREE_BANK(ah->analogBank3Data);
- ATH_FREE_BANK(ah->analogBank6Data);
- ATH_FREE_BANK(ah->analogBank6TPCData);
- ATH_FREE_BANK(ah->analogBank7Data);
- ATH_FREE_BANK(ah->bank6Temp);
-
-#undef ATH_FREE_BANK
-}
-
/* *
* ar5008_hw_set_rf_regs - programs rf registers based on EEPROM
* @ah: atheros hardware structure
@@ -1380,7 +1356,7 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah)
conf->radar_inband = 8;
}
-void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
+int ar5008_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
static const u32 ar5416_cca_regs[6] = {
@@ -1391,12 +1367,15 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
AR_PHY_CH1_EXT_CCA,
AR_PHY_CH2_EXT_CCA
};
+ int ret;
+
+ ret = ar5008_hw_rf_alloc_ext_banks(ah);
+ if (ret)
+ return ret;
priv_ops->rf_set_freq = ar5008_hw_set_channel;
priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
- priv_ops->rf_alloc_ext_banks = ar5008_hw_rf_alloc_ext_banks;
- priv_ops->rf_free_ext_banks = ar5008_hw_rf_free_ext_banks;
priv_ops->set_rf_regs = ar5008_hw_set_rf_regs;
priv_ops->set_channel_regs = ar5008_hw_set_channel_regs;
priv_ops->init_bb = ar5008_hw_init_bb;
@@ -1421,4 +1400,5 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
ar5008_hw_set_nf_limits(ah);
ar5008_hw_set_radar_conf(ah);
memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
+ return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
index ea4a230997ac..59524e1d4678 100644
--- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
@@ -460,7 +460,7 @@ static const u32 ar5416Common_9100[][2] = {
};
static const u32 ar5416Bank6_9100[][3] = {
- /* Addr 5G_HT20 5G_HT40 */
+ /* Addr 5G 2G */
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
@@ -497,7 +497,7 @@ static const u32 ar5416Bank6_9100[][3] = {
};
static const u32 ar5416Bank6TPC_9100[][3] = {
- /* Addr 5G_HT20 5G_HT40 */
+ /* Addr 5G 2G */
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
{0x0000989c, 0x00000000, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index 648da3e885e9..f053d978540e 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -23,13 +23,13 @@
/* General hardware code for the A5008/AR9001/AR9002 hadware families */
-static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
+static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
{
if (AR_SREV_9271(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271);
INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271);
INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg);
- return;
+ return 0;
}
if (ah->config.pcie_clock_req)
@@ -102,9 +102,9 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns;
u32 *data;
- data = kmalloc(size, GFP_KERNEL);
+ data = devm_kzalloc(ah->dev, size, GFP_KERNEL);
if (!data)
- return;
+ return -ENOMEM;
memcpy(data, addac->ia_array, size);
addac->ia_array = data;
@@ -120,6 +120,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
ar9287Common_japan_2484_cck_fir_coeff_9287_1_1);
}
+ return 0;
}
static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah)
@@ -409,22 +410,30 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
}
/* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
-void ar9002_hw_attach_ops(struct ath_hw *ah)
+int ar9002_hw_attach_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);
+ int ret;
+
+ ret = ar9002_hw_init_mode_regs(ah);
+ if (ret)
+ return ret;
- priv_ops->init_mode_regs = ar9002_hw_init_mode_regs;
priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
ops->config_pci_powersave = ar9002_hw_configpcipowersave;
- ar5008_hw_attach_phy_ops(ah);
+ ret = ar5008_hw_attach_phy_ops(ah);
+ if (ret)
+ return ret;
+
if (AR_SREV_9280_20_OR_LATER(ah))
ar9002_hw_attach_phy_ops(ah);
ar9002_hw_attach_calib_ops(ah);
ar9002_hw_attach_mac_ops(ah);
+ return 0;
}
void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index 846dd7974eb8..f4003512d8d5 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -555,14 +555,73 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
}
+static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
+ struct ath_spec_scan *param)
+{
+ u8 count;
+
+ if (!param->enabled) {
+ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ENABLE);
+ return;
+ }
+ REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+
+ if (param->short_repeat)
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+ else
+ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+
+ /* on AR92xx, the highest bit of count will make the the chip send
+ * spectral samples endlessly. Check if this really was intended,
+ * and fix otherwise.
+ */
+ count = param->count;
+ if (param->endless)
+ count = 0x80;
+ else if (count & 0x80)
+ count = 0x7f;
+
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_COUNT, count);
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
+
+ return;
+}
+
+static void ar9002_hw_spectral_scan_trigger(struct ath_hw *ah)
+{
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+ /* Activate spectral scan */
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ACTIVE);
+}
+
+static void ar9002_hw_spectral_scan_wait(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ /* Poll for spectral scan complete */
+ if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ACTIVE,
+ 0, AH_WAIT_TIMEOUT)) {
+ ath_err(common, "spectral scan wait failed\n");
+ return;
+ }
+}
+
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;
@@ -571,6 +630,9 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
+ ops->spectral_scan_config = ar9002_hw_spectral_scan_config;
+ ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger;
+ ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait;
ar9002_hw_set_nf_limits(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index 262e1e036fd7..db5ffada2217 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -744,6 +744,186 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
+static const u32 ar9300Modes_mixed_ob_db_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {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},
+ {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400},
+ {0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402},
+ {0x0000a51c, 0x27002223, 0x27002223, 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, 0x52022470, 0x52022470, 0x3b001861, 0x3b001861},
+ {0x0000a548, 0x55022490, 0x55022490, 0x3e001a81, 0x3e001a81},
+ {0x0000a54c, 0x59022492, 0x59022492, 0x42001a83, 0x42001a83},
+ {0x0000a550, 0x5d022692, 0x5d022692, 0x44001c84, 0x44001c84},
+ {0x0000a554, 0x61022892, 0x61022892, 0x48001ce3, 0x48001ce3},
+ {0x0000a558, 0x65024890, 0x65024890, 0x4c001ce5, 0x4c001ce5},
+ {0x0000a55c, 0x69024892, 0x69024892, 0x50001ce9, 0x50001ce9},
+ {0x0000a560, 0x6e024c92, 0x6e024c92, 0x54001ceb, 0x54001ceb},
+ {0x0000a564, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+ {0x0000a56c, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+ {0x0000a570, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+ {0x0000a574, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+ {0x0000a578, 0x74026e92, 0x74026e92, 0x56001eec, 0x56001eec},
+ {0x0000a57c, 0x74026e92, 0x74026e92, 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, 0x21802220, 0x21802220, 0x15800402, 0x15800402},
+ {0x0000a59c, 0x27802223, 0x27802223, 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, 0x52822470, 0x52822470, 0x3b801861, 0x3b801861},
+ {0x0000a5c8, 0x55822490, 0x55822490, 0x3e801a81, 0x3e801a81},
+ {0x0000a5cc, 0x59822492, 0x59822492, 0x42801a83, 0x42801a83},
+ {0x0000a5d0, 0x5d822692, 0x5d822692, 0x44801c84, 0x44801c84},
+ {0x0000a5d4, 0x61822892, 0x61822892, 0x48801ce3, 0x48801ce3},
+ {0x0000a5d8, 0x65824890, 0x65824890, 0x4c801ce5, 0x4c801ce5},
+ {0x0000a5dc, 0x69824892, 0x69824892, 0x50801ce9, 0x50801ce9},
+ {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x54801ceb, 0x54801ceb},
+ {0x0000a5e4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+ {0x0000a5e8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+ {0x0000a5ec, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+ {0x0000a5f0, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+ {0x0000a5f4, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+ {0x0000a5f8, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+ {0x0000a5fc, 0x74826e92, 0x74826e92, 0x56801eec, 0x56801eec},
+ {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, 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, 0x056db2e4, 0x056db2e4},
+ {0x00016048, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+ {0x00016448, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4},
+ {0x00016848, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Modes_type5_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {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, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
+ {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
+ {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
+ {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
+ {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
+ {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
+ {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
+ {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
+ {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
+ {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
+ {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
+ {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+ {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+ {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
+ {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
+ {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
+ {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
+ {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+ {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
+ {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
/* Addr allmodes */
{0x0000a000, 0x00010000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 56317b0fb6b6..4cc13940c895 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -32,7 +32,6 @@ struct coeff {
enum ar9003_cal_types {
IQ_MISMATCH_CAL = BIT(0),
- TEMP_COMP_CAL = BIT(1),
};
static void ar9003_hw_setup_calibration(struct ath_hw *ah,
@@ -49,7 +48,7 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
*/
REG_RMW_FIELD(ah, AR_PHY_TIMING4,
AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
- currCal->calData->calCountMax);
+ currCal->calData->calCountMax);
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
ath_dbg(common, CALIBRATE,
@@ -58,14 +57,8 @@ static void ar9003_hw_setup_calibration(struct ath_hw *ah,
/* Kick-off cal */
REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
break;
- case TEMP_COMP_CAL:
- REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
- AR_PHY_65NM_CH0_THERM_LOCAL, 1);
- REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
- AR_PHY_65NM_CH0_THERM_START, 1);
-
- ath_dbg(common, CALIBRATE,
- "starting Temperature Compensation Calibration\n");
+ default:
+ ath_err(common, "Invalid calibration type\n");
break;
}
}
@@ -323,6 +316,14 @@ static const struct ath9k_percal_data iq_cal_single_sample = {
static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
{
ah->iq_caldata.calData = &iq_cal_single_sample;
+
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ ah->enabled_cals |= TX_IQ_CAL;
+ if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah))
+ ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
+ }
+
+ ah->supp_cals = IQ_MISMATCH_CAL;
}
/*
@@ -959,22 +960,68 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
}
+static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ int i;
+
+ if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah))
+ return;
+
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->rxchainmask & (1 << i)))
+ continue;
+ ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));
+ }
+}
+
+static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
+{
+ u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
+ AR_PHY_CL_TAB_1,
+ AR_PHY_CL_TAB_2 };
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+ bool txclcal_done = false;
+ int i, j;
+
+ if (!caldata || !(ah->enabled_cals & TX_CL_CAL))
+ return;
+
+ txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
+ AR_PHY_AGC_CONTROL_CLC_SUCCESS);
+
+ if (caldata->done_txclcal_once) {
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->txchainmask & (1 << i)))
+ continue;
+ for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
+ REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
+ caldata->tx_clcal[i][j]);
+ }
+ } else if (is_reusable && txclcal_done) {
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->txchainmask & (1 << i)))
+ continue;
+ for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
+ caldata->tx_clcal[i][j] =
+ REG_READ(ah, CL_TAB_ENTRY(cl_idx[i]));
+ }
+ caldata->done_txclcal_once = true;
+ }
+}
+
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_cal_data *caldata = ah->caldata;
- bool txiqcal_done = false, txclcal_done = false;
+ bool txiqcal_done = false;
bool is_reusable = true, status = true;
- bool run_rtt_cal = false, run_agc_cal;
+ bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false;
bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
AR_PHY_AGC_CONTROL_FLTR_CAL |
AR_PHY_AGC_CONTROL_PKDET_CAL;
- int i, j;
- u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
- AR_PHY_CL_TAB_1,
- AR_PHY_CL_TAB_2 };
ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
@@ -1014,7 +1061,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
}
}
- if (!(ah->enabled_cals & TX_IQ_CAL))
+ if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) ||
+ !(ah->enabled_cals & TX_IQ_CAL))
goto skip_tx_iqcal;
/* Do Tx IQ Calibration */
@@ -1034,21 +1082,22 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
txiqcal_done = run_agc_cal = true;
- goto skip_tx_iqcal;
- } else if (caldata && !caldata->done_txiqcal_once)
+ } else if (caldata && !caldata->done_txiqcal_once) {
run_agc_cal = true;
+ sep_iq_cal = true;
+ }
+skip_tx_iqcal:
if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
ar9003_mci_init_cal_req(ah, &is_reusable);
- if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
+ if (sep_iq_cal) {
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);
}
-skip_tx_iqcal:
if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
/* Calibrate the AGC */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
@@ -1059,14 +1108,8 @@ skip_tx_iqcal:
status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT);
- if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
- for (i = 0; i < AR9300_MAX_CHAINS; i++) {
- if (!(ah->rxchainmask & (1 << i)))
- continue;
- ar9003_hw_manual_peak_cal(ah, i,
- IS_CHAN_2GHZ(chan));
- }
- }
+
+ ar9003_hw_do_manual_peak_cal(ah, chan);
}
if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
@@ -1091,31 +1134,7 @@ skip_tx_iqcal:
else if (caldata && caldata->done_txiqcal_once)
ar9003_hw_tx_iq_cal_reload(ah);
-#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j))
- if (caldata && (ah->enabled_cals & TX_CL_CAL)) {
- txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
- AR_PHY_AGC_CONTROL_CLC_SUCCESS);
- if (caldata->done_txclcal_once) {
- for (i = 0; i < AR9300_MAX_CHAINS; i++) {
- if (!(ah->txchainmask & (1 << i)))
- continue;
- for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
- REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
- caldata->tx_clcal[i][j]);
- }
- } else if (is_reusable && txclcal_done) {
- for (i = 0; i < AR9300_MAX_CHAINS; i++) {
- if (!(ah->txchainmask & (1 << i)))
- continue;
- for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
- caldata->tx_clcal[i][j] =
- REG_READ(ah,
- CL_TAB_ENTRY(cl_idx[i]));
- }
- caldata->done_txclcal_once = true;
- }
- }
-#undef CL_TAB_ENTRY
+ ar9003_hw_cl_cal_post_proc(ah, is_reusable);
if (run_rtt_cal && caldata) {
if (is_reusable) {
@@ -1133,20 +1152,10 @@ skip_tx_iqcal:
/* Initialize list pointers */
ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
- ah->supp_cals = IQ_MISMATCH_CAL;
-
- if (ah->supp_cals & IQ_MISMATCH_CAL) {
- INIT_CAL(&ah->iq_caldata);
- INSERT_CAL(ah, &ah->iq_caldata);
- ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
- }
- if (ah->supp_cals & TEMP_COMP_CAL) {
- INIT_CAL(&ah->tempCompCalData);
- INSERT_CAL(ah, &ah->tempCompCalData);
- ath_dbg(common, CALIBRATE,
- "enabling Temperature Compensation Calibration\n");
- }
+ INIT_CAL(&ah->iq_caldata);
+ INSERT_CAL(ah, &ah->iq_caldata);
+ ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
/* Initialize current pointer to first element in list */
ah->cal_list_curr = ah->cal_list;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 562186ca9b52..881e989ea470 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -4586,14 +4586,14 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
return 0;
}
-static int ar9003_hw_power_control_override(struct ath_hw *ah,
- int frequency,
- int *correction,
- int *voltage, int *temperature)
+static void ar9003_hw_power_control_override(struct ath_hw *ah,
+ int frequency,
+ int *correction,
+ int *voltage, int *temperature)
{
- int tempSlope = 0;
+ int temp_slope = 0, temp_slope1 = 0, temp_slope2 = 0;
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
- int f[8], t[8], i;
+ int f[8], t[8], t1[3], t2[3], i;
REG_RMW(ah, AR_PHY_TPC_11_B0,
(correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
@@ -4624,38 +4624,108 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah,
* enable temperature compensation
* Need to use register names
*/
- if (frequency < 4000)
- tempSlope = eep->modalHeader2G.tempSlope;
- else if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) {
- for (i = 0; i < 8; i++) {
- t[i] = eep->base_ext1.tempslopextension[i];
- f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0);
+ if (frequency < 4000) {
+ temp_slope = eep->modalHeader2G.tempSlope;
+ } else {
+ if (AR_SREV_9550(ah)) {
+ t[0] = eep->base_ext1.tempslopextension[2];
+ t1[0] = eep->base_ext1.tempslopextension[3];
+ t2[0] = eep->base_ext1.tempslopextension[4];
+ f[0] = 5180;
+
+ t[1] = eep->modalHeader5G.tempSlope;
+ t1[1] = eep->base_ext1.tempslopextension[0];
+ t2[1] = eep->base_ext1.tempslopextension[1];
+ f[1] = 5500;
+
+ t[2] = eep->base_ext1.tempslopextension[5];
+ t1[2] = eep->base_ext1.tempslopextension[6];
+ t2[2] = eep->base_ext1.tempslopextension[7];
+ f[2] = 5785;
+
+ temp_slope = ar9003_hw_power_interpolate(frequency,
+ f, t, 3);
+ temp_slope1 = ar9003_hw_power_interpolate(frequency,
+ f, t1, 3);
+ temp_slope2 = ar9003_hw_power_interpolate(frequency,
+ f, t2, 3);
+
+ goto tempslope;
}
- tempSlope = ar9003_hw_power_interpolate((s32) frequency,
- f, t, 8);
- } else if (eep->base_ext2.tempSlopeLow != 0) {
- t[0] = eep->base_ext2.tempSlopeLow;
- f[0] = 5180;
- t[1] = eep->modalHeader5G.tempSlope;
- f[1] = 5500;
- t[2] = eep->base_ext2.tempSlopeHigh;
- f[2] = 5785;
- tempSlope = ar9003_hw_power_interpolate((s32) frequency,
- f, t, 3);
- } else
- tempSlope = eep->modalHeader5G.tempSlope;
- REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope);
+ if ((eep->baseEepHeader.miscConfiguration & 0x20) != 0) {
+ for (i = 0; i < 8; i++) {
+ t[i] = eep->base_ext1.tempslopextension[i];
+ f[i] = FBIN2FREQ(eep->calFreqPier5G[i], 0);
+ }
+ temp_slope = ar9003_hw_power_interpolate((s32) frequency,
+ f, t, 8);
+ } else if (eep->base_ext2.tempSlopeLow != 0) {
+ t[0] = eep->base_ext2.tempSlopeLow;
+ f[0] = 5180;
+ t[1] = eep->modalHeader5G.tempSlope;
+ f[1] = 5500;
+ t[2] = eep->base_ext2.tempSlopeHigh;
+ f[2] = 5785;
+ temp_slope = ar9003_hw_power_interpolate((s32) frequency,
+ f, t, 3);
+ } else {
+ temp_slope = eep->modalHeader5G.tempSlope;
+ }
+ }
+
+tempslope:
+ if (AR_SREV_9550(ah)) {
+ /*
+ * AR955x has tempSlope register for each chain.
+ * Check whether temp_compensation feature is enabled or not.
+ */
+ if (eep->baseEepHeader.featureEnable & 0x1) {
+ if (frequency < 4000) {
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ eep->base_ext2.tempSlopeLow);
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ temp_slope);
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ eep->base_ext2.tempSlopeHigh);
+ } else {
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ temp_slope);
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ temp_slope1);
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+ AR_PHY_TPC_19_ALPHA_THERM,
+ temp_slope2);
+ }
+ } else {
+ /*
+ * If temp compensation is not enabled,
+ * set all registers to 0.
+ */
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+ AR_PHY_TPC_19_ALPHA_THERM, 0);
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
+ AR_PHY_TPC_19_ALPHA_THERM, 0);
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2,
+ AR_PHY_TPC_19_ALPHA_THERM, 0);
+ }
+ } else {
+ REG_RMW_FIELD(ah, AR_PHY_TPC_19,
+ AR_PHY_TPC_19_ALPHA_THERM, temp_slope);
+ }
if (AR_SREV_9462_20(ah))
REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1,
- AR_PHY_TPC_19_B1_ALPHA_THERM, tempSlope);
+ AR_PHY_TPC_19_B1_ALPHA_THERM, temp_slope);
REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE,
temperature[0]);
-
- return 0;
}
/* Apply the recorded correction values. */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index 59bf5f31e212..a3523c969a3a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -507,28 +507,59 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah)
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_mixed_ob_db_tx_gain_table);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_mixed_ob_db_tx_gain_table_2p2);
+}
+
+static void ar9003_tx_gain_table_mode5(struct ath_hw *ah)
+{
+ if (AR_SREV_9485_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485Modes_green_ob_db_tx_gain_1_1);
+ else if (AR_SREV_9340(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9340Modes_ub124_tx_gain_table_1p0);
+ else if (AR_SREV_9580(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9580_1p0_type5_tx_gain_table);
+ else if (AR_SREV_9300_22(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_type5_tx_gain_table_2p2);
}
+static void ar9003_tx_gain_table_mode6(struct ath_hw *ah)
+{
+ if (AR_SREV_9340(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0);
+ else if (AR_SREV_9485_11(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9485Modes_green_spur_ob_db_tx_gain_1_1);
+ else if (AR_SREV_9580(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9580_1p0_type6_tx_gain_table);
+}
+
+typedef void (*ath_txgain_tab)(struct ath_hw *ah);
+
static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
{
- switch (ar9003_hw_get_tx_gain_idx(ah)) {
- case 0:
- default:
- ar9003_tx_gain_table_mode0(ah);
- break;
- case 1:
- ar9003_tx_gain_table_mode1(ah);
- break;
- case 2:
- ar9003_tx_gain_table_mode2(ah);
- break;
- case 3:
- ar9003_tx_gain_table_mode3(ah);
- break;
- case 4:
- ar9003_tx_gain_table_mode4(ah);
- break;
- }
+ static const ath_txgain_tab modes[] = {
+ ar9003_tx_gain_table_mode0,
+ ar9003_tx_gain_table_mode1,
+ ar9003_tx_gain_table_mode2,
+ ar9003_tx_gain_table_mode3,
+ ar9003_tx_gain_table_mode4,
+ ar9003_tx_gain_table_mode5,
+ ar9003_tx_gain_table_mode6,
+ };
+ int idx = ar9003_hw_get_tx_gain_idx(ah);
+
+ if (idx >= ARRAY_SIZE(modes))
+ idx = 0;
+
+ modes[idx](ah);
}
static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
@@ -673,7 +704,7 @@ void ar9003_hw_attach_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->init_mode_regs = ar9003_hw_init_mode_regs;
+ ar9003_hw_init_mode_regs(ah);
priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
ops->config_pci_powersave = ar9003_hw_configpcipowersave;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 3afc24bde6d6..2bf6548dd143 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -68,7 +68,7 @@ static const int m2ThreshExt_off = 127;
static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
{
u16 bMode, fracMode = 0, aModeRefSel = 0;
- u32 freq, channelSel = 0, reg32 = 0;
+ u32 freq, chan_frac, div, channelSel = 0, reg32 = 0;
struct chan_centers centers;
int loadSynthChannel;
@@ -77,9 +77,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
if (freq < 4800) { /* 2 GHz, fractional mode */
if (AR_SREV_9330(ah)) {
- u32 chan_frac;
- u32 div;
-
if (ah->is_clk_25mhz)
div = 75;
else
@@ -89,34 +86,40 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
chan_frac = (((freq * 4) % div) * 0x20000) / div;
channelSel = (channelSel << 17) | chan_frac;
} else if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
- u32 chan_frac;
-
/*
- * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0
+ * 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) || AR_SREV_9550(ah)) {
+ } 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
+ } else {
channelSel = CHANSEL_2G(freq) >> 1;
- } else
+ }
+ } else if (AR_SREV_9550(ah)) {
+ if (ah->is_clk_25mhz)
+ div = 75;
+ else
+ div = 120;
+
+ channelSel = (freq * 4) / div;
+ chan_frac = (((freq * 4) % div) * 0x20000) / div;
+ channelSel = (channelSel << 17) | chan_frac;
+ } else {
channelSel = CHANSEL_2G(freq);
+ }
/* Set to 2G mode */
bMode = 1;
} else {
if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) &&
ah->is_clk_25mhz) {
- u32 chan_frac;
-
channelSel = freq / 75;
chan_frac = ((freq % 75) * 0x20000) / 75;
channelSel = (channelSel << 17) | chan_frac;
@@ -1437,6 +1440,67 @@ set_rfmode:
return 0;
}
+static void ar9003_hw_spectral_scan_config(struct ath_hw *ah,
+ struct ath_spec_scan *param)
+{
+ u8 count;
+
+ if (!param->enabled) {
+ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ENABLE);
+ return;
+ }
+
+ REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
+
+ /* on AR93xx and newer, count = 0 will make the the chip send
+ * spectral samples endlessly. Check if this really was intended,
+ * and fix otherwise.
+ */
+ count = param->count;
+ if (param->endless)
+ count = 0;
+ else if (param->count == 0)
+ count = 1;
+
+ if (param->short_repeat)
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+ else
+ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
+
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_COUNT, count);
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_FFT_PERIOD, param->fft_period);
+
+ return;
+}
+
+static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah)
+{
+ /* Activate spectral scan */
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ACTIVE);
+}
+
+static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ /* Poll for spectral scan complete */
+ if (!ath9k_hw_wait(ah, AR_PHY_SPECTRAL_SCAN,
+ AR_PHY_SPECTRAL_SCAN_ACTIVE,
+ 0, AH_WAIT_TIMEOUT)) {
+ ath_err(common, "spectral scan wait failed\n");
+ return;
+ }
+}
+
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -1470,6 +1534,9 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv;
+ ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
+ ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger;
+ ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait;
ar9003_hw_set_nf_limits(ah);
ar9003_hw_set_radar_conf(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 107956298488..e71774196c01 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -1028,7 +1028,7 @@
#define AR_PHY_TPC_5_B2 (AR_SM2_BASE + 0x208)
#define AR_PHY_TPC_6_B2 (AR_SM2_BASE + 0x20c)
#define AR_PHY_TPC_11_B2 (AR_SM2_BASE + 0x220)
-#define AR_PHY_PDADC_TAB_2 (AR_SM2_BASE + 0x240)
+#define AR_PHY_TPC_19_B2 (AR_SM2_BASE + 0x240)
#define AR_PHY_TX_IQCAL_STATUS_B2 (AR_SM2_BASE + 0x48c)
#define AR_PHY_TX_IQCAL_CORR_COEFF_B2(_i) (AR_SM2_BASE + 0x450 + ((_i) << 2))
diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h
index f69d292bdc02..25db9215985a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h
@@ -1172,6 +1172,106 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = {
{0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266},
};
+static const u32 ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a},
+ {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac},
+ {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000},
+ {0x0000a394, 0x00000444, 0x00000444, 0x00000404, 0x00000404},
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+ {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a504, 0x06000003, 0x06000003, 0x02000001, 0x02000001},
+ {0x0000a508, 0x0a000020, 0x0a000020, 0x05000003, 0x05000003},
+ {0x0000a50c, 0x10000023, 0x10000023, 0x0a000005, 0x0a000005},
+ {0x0000a510, 0x16000220, 0x16000220, 0x0e000201, 0x0e000201},
+ {0x0000a514, 0x1c000223, 0x1c000223, 0x11000203, 0x11000203},
+ {0x0000a518, 0x21002220, 0x21002220, 0x14000401, 0x14000401},
+ {0x0000a51c, 0x27002223, 0x27002223, 0x18000403, 0x18000403},
+ {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000602, 0x1b000602},
+ {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000802, 0x1f000802},
+ {0x0000a528, 0x34022225, 0x34022225, 0x21000620, 0x21000620},
+ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x25000820, 0x25000820},
+ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x29000822, 0x29000822},
+ {0x0000a534, 0x4202242a, 0x4202242a, 0x2d000824, 0x2d000824},
+ {0x0000a538, 0x4702244a, 0x4702244a, 0x30000828, 0x30000828},
+ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x3400082a, 0x3400082a},
+ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38000849, 0x38000849},
+ {0x0000a544, 0x5302266c, 0x5302266c, 0x3b000a2c, 0x3b000a2c},
+ {0x0000a548, 0x5702286c, 0x5702286c, 0x3e000e2b, 0x3e000e2b},
+ {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42000e2d, 0x42000e2d},
+ {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4500124a, 0x4500124a},
+ {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4900124c, 0x4900124c},
+ {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c00126c, 0x4c00126c},
+ {0x0000a55c, 0x7002708c, 0x7002708c, 0x4f00128c, 0x4f00128c},
+ {0x0000a560, 0x7302b08a, 0x7302b08a, 0x52001290, 0x52001290},
+ {0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+ {0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+ {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+ {0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+ {0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+ {0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+ {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001292, 0x56001292},
+ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06800003, 0x06800003, 0x02800001, 0x02800001},
+ {0x0000a588, 0x0a800020, 0x0a800020, 0x05800003, 0x05800003},
+ {0x0000a58c, 0x10800023, 0x10800023, 0x0a800005, 0x0a800005},
+ {0x0000a590, 0x16800220, 0x16800220, 0x0e800201, 0x0e800201},
+ {0x0000a594, 0x1c800223, 0x1c800223, 0x11800203, 0x11800203},
+ {0x0000a598, 0x21820220, 0x21820220, 0x14800401, 0x14800401},
+ {0x0000a59c, 0x27820223, 0x27820223, 0x18800403, 0x18800403},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800602, 0x1b800602},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800802, 0x1f800802},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x21800620, 0x21800620},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x25800820, 0x25800820},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x29800822, 0x29800822},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2d800824, 0x2d800824},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x30800828, 0x30800828},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x3480082a, 0x3480082a},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38800849, 0x38800849},
+ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b800a2c, 0x3b800a2c},
+ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e800e2b, 0x3e800e2b},
+ {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42800e2d, 0x42800e2d},
+ {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4580124a, 0x4580124a},
+ {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4980124c, 0x4980124c},
+ {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c80126c, 0x4c80126c},
+ {0x0000a5dc, 0x7086308c, 0x7086308c, 0x4f80128c, 0x4f80128c},
+ {0x0000a5e0, 0x738a308a, 0x738a308a, 0x52801290, 0x52801290},
+ {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+ {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+ {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+ {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+ {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+ {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+ {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801292, 0x56801292},
+ {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, 0x01404501, 0x01404501},
+ {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+ {0x0000a61c, 0x02008802, 0x02008802, 0x01404501, 0x01404501},
+ {0x0000a620, 0x0300cc03, 0x0300cc03, 0x03c0cf02, 0x03c0cf02},
+ {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03c0cf03, 0x03c0cf03},
+ {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04011004, 0x04011004},
+ {0x0000a62c, 0x03810c03, 0x03810c03, 0x05419405, 0x05419405},
+ {0x0000a630, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+ {0x0000a634, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+ {0x0000a638, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+ {0x0000a63c, 0x03810e04, 0x03810e04, 0x05419506, 0x05419506},
+ {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03eaac5a, 0x03eaac5a},
+ {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03f330ac, 0x03f330ac},
+ {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc3f00, 0x03fc3f00},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ffc000, 0x03ffc000},
+ {0x00016044, 0x022492db, 0x022492db, 0x022492db, 0x022492db},
+ {0x00016048, 0x24925666, 0x24925666, 0x24925266, 0x24925266},
+ {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015},
+ {0x00016288, 0xf0318000, 0xf0318000, 0xf0318000, 0xf0318000},
+ {0x00016444, 0x022492db, 0x022492db, 0x022492db, 0x022492db},
+ {0x00016448, 0x24925666, 0x24925666, 0x24925266, 0x24925266},
+};
+
static const u32 ar9340_1p0_mac_core[][2] = {
/* Addr allmodes */
{0x00000008, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
index a3710f3bb90c..712f415b8c08 100644
--- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
@@ -260,6 +260,79 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
};
+static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+ {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
+ {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
+ {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
+ {0x0000a508, 0x0c002e00, 0x0c002e00, 0x06000203, 0x06000203},
+ {0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401},
+ {0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403},
+ {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405},
+ {0x0000a518, 0x25020ec0, 0x25020ec0, 0x15000604, 0x15000604},
+ {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x18000605, 0x18000605},
+ {0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000a04, 0x1c000a04},
+ {0x0000a524, 0x35001fc4, 0x35001fc4, 0x21000a06, 0x21000a06},
+ {0x0000a528, 0x3c022f04, 0x3c022f04, 0x29000a24, 0x29000a24},
+ {0x0000a52c, 0x41023e85, 0x41023e85, 0x2f000e21, 0x2f000e21},
+ {0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000e20, 0x31000e20},
+ {0x0000a534, 0x4d023f01, 0x4d023f01, 0x33000e20, 0x33000e20},
+ {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+ {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+ {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+ {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+ {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+ {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+ {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+ {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+ {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
+ {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
+ {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+ {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+ {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+ {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+ {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+ {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+ {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a},
+ {0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a},
+ {0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a},
+ {0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+ {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
@@ -450,6 +523,79 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1
+static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+ {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
+ {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
+ {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
+ {0x0000a508, 0x0c002e00, 0x0c002e00, 0x07000203, 0x07000203},
+ {0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401},
+ {0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403},
+ {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405},
+ {0x0000a518, 0x25020ec0, 0x25020ec0, 0x14000406, 0x14000406},
+ {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1800040a, 0x1800040a},
+ {0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000460, 0x1c000460},
+ {0x0000a524, 0x35001fc4, 0x35001fc4, 0x22000463, 0x22000463},
+ {0x0000a528, 0x3c022f04, 0x3c022f04, 0x26000465, 0x26000465},
+ {0x0000a52c, 0x41023e85, 0x41023e85, 0x2e0006e0, 0x2e0006e0},
+ {0x0000a530, 0x48023ec6, 0x48023ec6, 0x310006e0, 0x310006e0},
+ {0x0000a534, 0x4d023f01, 0x4d023f01, 0x330006e0, 0x330006e0},
+ {0x0000a538, 0x53023f4b, 0x53023f4b, 0x3e0008e3, 0x3e0008e3},
+ {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x410008e5, 0x410008e5},
+ {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x430008e6, 0x430008e6},
+ {0x0000a544, 0x6502feca, 0x6502feca, 0x4a0008ec, 0x4a0008ec},
+ {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4e0008f1, 0x4e0008f1},
+ {0x0000a54c, 0x7203feca, 0x7203feca, 0x520008f3, 0x520008f3},
+ {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x54000eed, 0x54000eed},
+ {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x58000ef1, 0x58000ef1},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5c000ef3, 0x5c000ef3},
+ {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x60000ef5, 0x60000ef5},
+ {0x0000a560, 0x900fff0b, 0x900fff0b, 0x62000ef6, 0x62000ef6},
+ {0x0000a564, 0x960fffcb, 0x960fffcb, 0x62000ef6, 0x62000ef6},
+ {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+ {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+ {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+ {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+ {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+ {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+ {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+ {0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a},
+ {0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a},
+ {0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a},
+ {0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+ {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+ {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
static const u32 ar9485_1_1[][2] = {
/* Addr allmodes */
{0x0000a580, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
index df97f21c52dc..ccc5b6c99add 100644
--- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
@@ -23,16 +23,16 @@
static const u32 ar955x_1p0_radio_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330},
- {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x06345f2a, 0x06345f2a},
- {0x000160ac, 0xa4647c00, 0xa4647c00, 0xa4646800, 0xa4646800},
- {0x000160b0, 0x01885f52, 0x01885f52, 0x04accf3a, 0x04accf3a},
- {0x00016104, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
+ {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a, 0x0a566f3a},
+ {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24647c00, 0x24647c00},
+ {0x000160b0, 0x01885f52, 0x01885f52, 0x01885f52, 0x01885f52},
+ {0x00016104, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
{0x0001610c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016140, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
- {0x00016504, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
+ {0x00016504, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
{0x0001650c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016540, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
- {0x00016904, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001},
+ {0x00016904, 0xb7a00000, 0xb7a00000, 0xb7a00001, 0xb7a00001},
{0x0001690c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000},
{0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008},
};
@@ -69,15 +69,15 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = {
{0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0},
{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
{0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
- {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+ {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
{0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
- {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e},
{0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
- {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e},
{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
@@ -125,7 +125,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
{0x00016094, 0x00000000},
{0x000160a0, 0x0a108ffe},
{0x000160a4, 0x812fc370},
- {0x000160a8, 0x423c8000},
+ {0x000160a8, 0x423c8100},
{0x000160b4, 0x92480080},
{0x000160c0, 0x006db6d0},
{0x000160c4, 0x6db6db60},
@@ -134,7 +134,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
{0x00016100, 0x11999601},
{0x00016108, 0x00080010},
{0x00016144, 0x02084080},
- {0x00016148, 0x000080c0},
+ {0x00016148, 0x00008040},
{0x00016280, 0x01800804},
{0x00016284, 0x00038dc5},
{0x00016288, 0x00000000},
@@ -178,7 +178,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
{0x00016500, 0x11999601},
{0x00016508, 0x00080010},
{0x00016544, 0x02084080},
- {0x00016548, 0x000080c0},
+ {0x00016548, 0x00008040},
{0x00016780, 0x00000000},
{0x00016784, 0x00000000},
{0x00016788, 0x00400705},
@@ -218,7 +218,7 @@ static const u32 ar955x_1p0_radio_core[][2] = {
{0x00016900, 0x11999601},
{0x00016908, 0x00080010},
{0x00016944, 0x02084080},
- {0x00016948, 0x000080c0},
+ {0x00016948, 0x00008040},
{0x00016b80, 0x00000000},
{0x00016b84, 0x00000000},
{0x00016b88, 0x00400705},
@@ -245,9 +245,9 @@ static const u32 ar955x_1p0_radio_core[][2] = {
static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = {
/* Addr 5G_HT20_L 5G_HT40_L 5G_HT20_M 5G_HT40_M 5G_HT20_H 5G_HT40_H 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
- {0x0000a2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
- {0x0000a2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
+ {0x0000a2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
+ {0x0000a2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
+ {0x0000a2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
{0x0000a2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
{0x0000a410, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050da, 0x000050da},
{0x0000a500, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000000, 0x00000000},
@@ -256,63 +256,63 @@ static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = {
{0x0000a50c, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c000006, 0x0c000006},
{0x0000a510, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x0f00000a, 0x0f00000a},
{0x0000a514, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x1300000c, 0x1300000c},
- {0x0000a518, 0x19004008, 0x19004008, 0x19004008, 0x19004008, 0x18004008, 0x18004008, 0x1700000e, 0x1700000e},
- {0x0000a51c, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1c00400a, 0x1c00400a, 0x1b000064, 0x1b000064},
- {0x0000a520, 0x230020a2, 0x230020a2, 0x210020a2, 0x210020a2, 0x200020a2, 0x200020a2, 0x1f000242, 0x1f000242},
- {0x0000a524, 0x2500006e, 0x2500006e, 0x2500006e, 0x2500006e, 0x2400006e, 0x2400006e, 0x23000229, 0x23000229},
- {0x0000a528, 0x29022221, 0x29022221, 0x28022221, 0x28022221, 0x27022221, 0x27022221, 0x270002a2, 0x270002a2},
- {0x0000a52c, 0x2d00062a, 0x2d00062a, 0x2c00062a, 0x2c00062a, 0x2a00062a, 0x2a00062a, 0x2c001203, 0x2c001203},
- {0x0000a530, 0x340220a5, 0x340220a5, 0x320220a5, 0x320220a5, 0x2f0220a5, 0x2f0220a5, 0x30001803, 0x30001803},
- {0x0000a534, 0x380022c5, 0x380022c5, 0x350022c5, 0x350022c5, 0x320022c5, 0x320022c5, 0x33000881, 0x33000881},
- {0x0000a538, 0x3b002486, 0x3b002486, 0x39002486, 0x39002486, 0x36002486, 0x36002486, 0x38001809, 0x38001809},
- {0x0000a53c, 0x3f00248a, 0x3f00248a, 0x3d00248a, 0x3d00248a, 0x3a00248a, 0x3a00248a, 0x3a000814, 0x3a000814},
- {0x0000a540, 0x4202242c, 0x4202242c, 0x4102242c, 0x4102242c, 0x3f02242c, 0x3f02242c, 0x3f001a0c, 0x3f001a0c},
- {0x0000a544, 0x490044c6, 0x490044c6, 0x460044c6, 0x460044c6, 0x420044c6, 0x420044c6, 0x43001a0e, 0x43001a0e},
- {0x0000a548, 0x4d024485, 0x4d024485, 0x4a024485, 0x4a024485, 0x46024485, 0x46024485, 0x46001812, 0x46001812},
- {0x0000a54c, 0x51044483, 0x51044483, 0x4e044483, 0x4e044483, 0x4a044483, 0x4a044483, 0x49001884, 0x49001884},
- {0x0000a550, 0x5404a40c, 0x5404a40c, 0x5204a40c, 0x5204a40c, 0x4d04a40c, 0x4d04a40c, 0x4d001e84, 0x4d001e84},
- {0x0000a554, 0x57024632, 0x57024632, 0x55024632, 0x55024632, 0x52024632, 0x52024632, 0x50001e69, 0x50001e69},
- {0x0000a558, 0x5c00a634, 0x5c00a634, 0x5900a634, 0x5900a634, 0x5600a634, 0x5600a634, 0x550006f4, 0x550006f4},
- {0x0000a55c, 0x5f026832, 0x5f026832, 0x5d026832, 0x5d026832, 0x5a026832, 0x5a026832, 0x59000ad3, 0x59000ad3},
- {0x0000a560, 0x6602b012, 0x6602b012, 0x6202b012, 0x6202b012, 0x5d02b012, 0x5d02b012, 0x5e000ad5, 0x5e000ad5},
- {0x0000a564, 0x6e02d0e1, 0x6e02d0e1, 0x6802d0e1, 0x6802d0e1, 0x6002d0e1, 0x6002d0e1, 0x61001ced, 0x61001ced},
- {0x0000a568, 0x7202b4c4, 0x7202b4c4, 0x6c02b4c4, 0x6c02b4c4, 0x6502b4c4, 0x6502b4c4, 0x660018d4, 0x660018d4},
- {0x0000a56c, 0x75007894, 0x75007894, 0x70007894, 0x70007894, 0x6b007894, 0x6b007894, 0x660018d4, 0x660018d4},
- {0x0000a570, 0x7b025c74, 0x7b025c74, 0x75025c74, 0x75025c74, 0x70025c74, 0x70025c74, 0x660018d4, 0x660018d4},
- {0x0000a574, 0x8300bcb5, 0x8300bcb5, 0x7a00bcb5, 0x7a00bcb5, 0x7600bcb5, 0x7600bcb5, 0x660018d4, 0x660018d4},
- {0x0000a578, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4},
- {0x0000a57c, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4},
+ {0x0000a518, 0x1700002b, 0x1700002b, 0x1700002b, 0x1700002b, 0x1600002b, 0x1600002b, 0x1700000e, 0x1700000e},
+ {0x0000a51c, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1b00002d, 0x1a00002d, 0x1a00002d, 0x1b000064, 0x1b000064},
+ {0x0000a520, 0x20000031, 0x20000031, 0x1f000031, 0x1f000031, 0x1e000031, 0x1e000031, 0x1f000242, 0x1f000242},
+ {0x0000a524, 0x24000051, 0x24000051, 0x23000051, 0x23000051, 0x23000051, 0x23000051, 0x23000229, 0x23000229},
+ {0x0000a528, 0x27000071, 0x27000071, 0x27000071, 0x27000071, 0x26000071, 0x26000071, 0x270002a2, 0x270002a2},
+ {0x0000a52c, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2b000092, 0x2c001203, 0x2c001203},
+ {0x0000a530, 0x3000028c, 0x3000028c, 0x2f00028c, 0x2f00028c, 0x2e00028c, 0x2e00028c, 0x30001803, 0x30001803},
+ {0x0000a534, 0x34000290, 0x34000290, 0x33000290, 0x33000290, 0x32000290, 0x32000290, 0x33000881, 0x33000881},
+ {0x0000a538, 0x37000292, 0x37000292, 0x36000292, 0x36000292, 0x35000292, 0x35000292, 0x38001809, 0x38001809},
+ {0x0000a53c, 0x3b02028d, 0x3b02028d, 0x3a02028d, 0x3a02028d, 0x3902028d, 0x3902028d, 0x3a000814, 0x3a000814},
+ {0x0000a540, 0x3f020291, 0x3f020291, 0x3e020291, 0x3e020291, 0x3d020291, 0x3d020291, 0x3f001a0c, 0x3f001a0c},
+ {0x0000a544, 0x44020490, 0x44020490, 0x43020490, 0x43020490, 0x42020490, 0x42020490, 0x43001a0e, 0x43001a0e},
+ {0x0000a548, 0x48020492, 0x48020492, 0x47020492, 0x47020492, 0x46020492, 0x46020492, 0x46001812, 0x46001812},
+ {0x0000a54c, 0x4c020692, 0x4c020692, 0x4b020692, 0x4b020692, 0x4a020692, 0x4a020692, 0x49001884, 0x49001884},
+ {0x0000a550, 0x50020892, 0x50020892, 0x4f020892, 0x4f020892, 0x4e020892, 0x4e020892, 0x4d001e84, 0x4d001e84},
+ {0x0000a554, 0x53040891, 0x53040891, 0x53040891, 0x53040891, 0x52040891, 0x52040891, 0x50001e69, 0x50001e69},
+ {0x0000a558, 0x58040893, 0x58040893, 0x57040893, 0x57040893, 0x56040893, 0x56040893, 0x550006f4, 0x550006f4},
+ {0x0000a55c, 0x5c0408b4, 0x5c0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x5a0408b4, 0x59000ad3, 0x59000ad3},
+ {0x0000a560, 0x610408b6, 0x610408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e0408b6, 0x5e000ad5, 0x5e000ad5},
+ {0x0000a564, 0x670408f6, 0x670408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x620408f6, 0x61001ced, 0x61001ced},
+ {0x0000a568, 0x6a040cf6, 0x6a040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x66040cf6, 0x660018d4, 0x660018d4},
+ {0x0000a56c, 0x6d040d76, 0x6d040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x6a040d76, 0x660018d4, 0x660018d4},
+ {0x0000a570, 0x70060db6, 0x70060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x6e060db6, 0x660018d4, 0x660018d4},
+ {0x0000a574, 0x730a0df6, 0x730a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x720a0df6, 0x660018d4, 0x660018d4},
+ {0x0000a578, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4},
+ {0x0000a57c, 0x770a13f6, 0x770a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x760a13f6, 0x660018d4, 0x660018d4},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x03804000, 0x03804000},
- {0x0000a610, 0x04c08c01, 0x04c08c01, 0x04808b01, 0x04808b01, 0x04808a01, 0x04808a01, 0x0300ca02, 0x0300ca02},
- {0x0000a614, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00000e04, 0x00000e04},
- {0x0000a618, 0x04010c01, 0x04010c01, 0x03c10b01, 0x03c10b01, 0x03810a01, 0x03810a01, 0x03014000, 0x03014000},
- {0x0000a61c, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x00000000, 0x00000000},
- {0x0000a620, 0x04010303, 0x04010303, 0x03c10303, 0x03c10303, 0x03810303, 0x03810303, 0x00000000, 0x00000000},
- {0x0000a624, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03014000, 0x03014000},
- {0x0000a628, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x03804c05, 0x03804c05},
- {0x0000a62c, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x0701de06, 0x0701de06},
- {0x0000a630, 0x03418000, 0x03418000, 0x03018000, 0x03018000, 0x02c18000, 0x02c18000, 0x07819c07, 0x07819c07},
- {0x0000a634, 0x03815004, 0x03815004, 0x03414f04, 0x03414f04, 0x03414e04, 0x03414e04, 0x0701dc07, 0x0701dc07},
- {0x0000a638, 0x03005302, 0x03005302, 0x02c05202, 0x02c05202, 0x02805202, 0x02805202, 0x0701dc07, 0x0701dc07},
- {0x0000a63c, 0x04c09302, 0x04c09302, 0x04809202, 0x04809202, 0x04809202, 0x04809202, 0x0701dc07, 0x0701dc07},
- {0x0000b2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
- {0x0000b2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
- {0x0000b2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
+ {0x0000a60c, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x02c04b01, 0x03804000, 0x03804000},
+ {0x0000a610, 0x04008b01, 0x04008b01, 0x04008b01, 0x04008b01, 0x03c08b01, 0x03c08b01, 0x0300ca02, 0x0300ca02},
+ {0x0000a614, 0x05811403, 0x05811403, 0x05411303, 0x05411303, 0x05411303, 0x05411303, 0x00000e04, 0x00000e04},
+ {0x0000a618, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000},
+ {0x0000a61c, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000},
+ {0x0000a620, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x00000000, 0x00000000},
+ {0x0000a624, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03014000, 0x03014000},
+ {0x0000a628, 0x05811604, 0x05811604, 0x05411504, 0x05411504, 0x05411504, 0x05411504, 0x03804c05, 0x03804c05},
+ {0x0000a62c, 0x06815604, 0x06815604, 0x06415504, 0x06415504, 0x06015504, 0x06015504, 0x0701de06, 0x0701de06},
+ {0x0000a630, 0x07819a05, 0x07819a05, 0x07419905, 0x07419905, 0x07019805, 0x07019805, 0x07819c07, 0x07819c07},
+ {0x0000a634, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
+ {0x0000a638, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
+ {0x0000a63c, 0x07819e06, 0x07819e06, 0x07419d06, 0x07419d06, 0x07019c06, 0x07019c06, 0x0701dc07, 0x0701dc07},
+ {0x0000b2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
+ {0x0000b2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
+ {0x0000b2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
{0x0000b2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
- {0x0000c2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa},
- {0x0000c2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc},
- {0x0000c2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0},
+ {0x0000c2dc, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xffff6aaa, 0xfffd5aaa, 0xfffd5aaa},
+ {0x0000c2e0, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffdcccc, 0xfffe9ccc, 0xfffe9ccc},
+ {0x0000c2e4, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffe3b0f0, 0xffffe0f0, 0xffffe0f0},
{0x0000c2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00},
{0x00016044, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
- {0x00016048, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
+ {0x00016048, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
{0x00016280, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01808e84, 0x01808e84},
{0x00016444, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
- {0x00016448, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
+ {0x00016448, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
{0x00016844, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4},
- {0x00016848, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401},
+ {0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401},
};
static const u32 ar955x_1p0_mac_core[][2] = {
@@ -846,7 +846,7 @@ static const u32 ar955x_1p0_baseband_core[][2] = {
{0x0000a44c, 0x00000001},
{0x0000a450, 0x00010000},
{0x0000a458, 0x00000000},
- {0x0000a644, 0x3fad9d74},
+ {0x0000a644, 0xbfad9d74},
{0x0000a648, 0x0048060a},
{0x0000a64c, 0x00003c37},
{0x0000a670, 0x03020100},
@@ -1277,7 +1277,7 @@ static const u32 ar955x_1p0_modes_fast_clock[][3] = {
{0x0000801c, 0x148ec02b, 0x148ec057},
{0x00008318, 0x000044c0, 0x00008980},
{0x00009e00, 0x0372131c, 0x0372131c},
- {0x0000a230, 0x0000000b, 0x00000016},
+ {0x0000a230, 0x0000400b, 0x00004016},
{0x0000a254, 0x00000898, 0x00001130},
};
diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
index 6e1915aee712..28fd99203f64 100644
--- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
@@ -685,6 +685,82 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = {
#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2
+#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2
+
+static const u32 ar9580_1p0_type6_tx_gain_table[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {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, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
+ {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
+ {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
+ {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
+ {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
+ {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
+ {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
+ {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
+ {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
+ {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
+ {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
+ {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+ {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
+ {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
+ {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
+ {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
+ {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
+ {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+ {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
+ {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
+ {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
static const u32 ar9580_1p0_soc_preamble[][2] = {
/* Addr allmodes */
{0x000040a4, 0x00a0c1c9},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 42794c546a40..a56b2416e2f9 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -109,14 +109,11 @@ struct ath_descdma {
void *dd_desc;
dma_addr_t dd_desc_paddr;
u32 dd_desc_len;
- struct ath_buf *dd_bufptr;
};
int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
struct list_head *head, const char *name,
int nbuf, int ndesc, bool is_tx);
-void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
- struct list_head *head);
/***********/
/* RX / TX */
@@ -319,10 +316,11 @@ struct ath_rx {
unsigned int rxfilter;
struct list_head rxbuf;
struct ath_descdma rxdma;
- struct ath_buf *rx_bufptr;
struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
struct sk_buff *frag;
+
+ u32 ampdu_ref;
};
int ath_startrecv(struct ath_softc *sc);
@@ -336,14 +334,12 @@ void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq);
void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq);
void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq);
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
-bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
-void ath_draintxq(struct ath_softc *sc,
- struct ath_txq *txq, bool retry_tx);
+bool ath_drain_all_txq(struct ath_softc *sc);
+void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq);
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
int ath_tx_init(struct ath_softc *sc, int nbufs);
-void ath_tx_cleanup(struct ath_softc *sc);
int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *q);
void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
@@ -393,6 +389,7 @@ struct ath_beacon_config {
u16 bmiss_timeout;
u8 dtim_count;
bool enable_beacon;
+ bool ibss_creator;
};
struct ath_beacon {
@@ -672,6 +669,23 @@ struct ath9k_vif_iter_data {
int nadhocs; /* number of adhoc vifs */
};
+/* enum spectral_mode:
+ *
+ * @SPECTRAL_DISABLED: spectral mode is disabled
+ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
+ * something else.
+ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
+ * is performed manually.
+ * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels
+ * during a channel scan.
+ */
+enum spectral_mode {
+ SPECTRAL_DISABLED = 0,
+ SPECTRAL_BACKGROUND,
+ SPECTRAL_MANUAL,
+ SPECTRAL_CHANSCAN,
+};
+
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
@@ -740,6 +754,11 @@ struct ath_softc {
u8 ant_tx, ant_rx;
struct dfs_pattern_detector *dfs_detector;
u32 wow_enabled;
+ /* relay(fs) channel for spectral scan */
+ struct rchan *rfs_chan_spec_scan;
+ enum spectral_mode spectral_mode;
+ struct ath_spec_scan spec_config;
+ int scanning;
#ifdef CONFIG_PM_SLEEP
atomic_t wow_got_bmiss_intr;
@@ -748,6 +767,133 @@ struct ath_softc {
#endif
};
+#define SPECTRAL_SCAN_BITMASK 0x10
+/* Radar info packet format, used for DFS and spectral formats. */
+struct ath_radar_info {
+ u8 pulse_length_pri;
+ u8 pulse_length_ext;
+ u8 pulse_bw_info;
+} __packed;
+
+/* The HT20 spectral data has 4 bytes of additional information at it's end.
+ *
+ * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: all bins max_magnitude[9:2]
+ * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]}
+ * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
+ */
+struct ath_ht20_mag_info {
+ u8 all_bins[3];
+ u8 max_exp;
+} __packed;
+
+#define SPECTRAL_HT20_NUM_BINS 56
+
+/* WARNING: don't actually use this struct! MAC may vary the amount of
+ * data by -1/+2. This struct is for reference only.
+ */
+struct ath_ht20_fft_packet {
+ u8 data[SPECTRAL_HT20_NUM_BINS];
+ struct ath_ht20_mag_info mag_info;
+ struct ath_radar_info radar_info;
+} __packed;
+
+#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet))
+
+/* Dynamic 20/40 mode:
+ *
+ * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: lower bins max_magnitude[9:2]
+ * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]}
+ * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]}
+ * [7:0]: upper bins max_magnitude[9:2]
+ * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]}
+ * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned)
+ */
+struct ath_ht20_40_mag_info {
+ u8 lower_bins[3];
+ u8 upper_bins[3];
+ u8 max_exp;
+} __packed;
+
+#define SPECTRAL_HT20_40_NUM_BINS 128
+
+/* WARNING: don't actually use this struct! MAC may vary the amount of
+ * data. This struct is for reference only.
+ */
+struct ath_ht20_40_fft_packet {
+ u8 data[SPECTRAL_HT20_40_NUM_BINS];
+ struct ath_ht20_40_mag_info mag_info;
+ struct ath_radar_info radar_info;
+} __packed;
+
+
+#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet))
+
+/* grabs the max magnitude from the all/upper/lower bins */
+static inline u16 spectral_max_magnitude(u8 *bins)
+{
+ return (bins[0] & 0xc0) >> 6 |
+ (bins[1] & 0xff) << 2 |
+ (bins[2] & 0x03) << 10;
+}
+
+/* return the max magnitude from the all/upper/lower bins */
+static inline u8 spectral_max_index(u8 *bins)
+{
+ s8 m = (bins[2] & 0xfc) >> 2;
+
+ /* TODO: this still doesn't always report the right values ... */
+ if (m > 32)
+ m |= 0xe0;
+ else
+ m &= ~0xe0;
+
+ return m + 29;
+}
+
+/* return the bitmap weight from the all/upper/lower bins */
+static inline u8 spectral_bitmap_weight(u8 *bins)
+{
+ return bins[0] & 0x3f;
+}
+
+/* FFT sample format given to userspace via debugfs.
+ *
+ * Please keep the type/length at the front position and change
+ * other fields after adding another sample type
+ *
+ * TODO: this might need rework when switching to nl80211-based
+ * interface.
+ */
+enum ath_fft_sample_type {
+ ATH_FFT_SAMPLE_HT20 = 1,
+};
+
+struct fft_sample_tlv {
+ u8 type; /* see ath_fft_sample */
+ __be16 length;
+ /* type dependent data follows */
+} __packed;
+
+struct fft_sample_ht20 {
+ struct fft_sample_tlv tlv;
+
+ u8 max_exp;
+
+ __be16 freq;
+ s8 rssi;
+ s8 noise;
+
+ __be16 max_magnitude;
+ u8 max_index;
+ u8 bitmap_weight;
+
+ __be64 tsf;
+
+ u8 data[SPECTRAL_HT20_NUM_BINS];
+} __packed;
+
void ath9k_tasklet(unsigned long data);
int ath_cabq_update(struct ath_softc *);
@@ -770,6 +916,10 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath9k_reload_chainmask_settings(struct ath_softc *sc);
bool ath9k_uses_beacons(int type);
+void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
+int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
+ enum spectral_mode spectral_mode);
+
#ifdef CONFIG_ATH9K_PCI
int ath_pci_init(void);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 2ca355e94da6..5f05c26d1ec4 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -199,7 +199,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
if (sc->nvifs > 1) {
ath_dbg(common, BEACON,
"Flushing previous cabq traffic\n");
- ath_draintxq(sc, cabq, false);
+ ath_draintxq(sc, cabq);
}
}
@@ -407,12 +407,17 @@ void ath9k_beacon_tasklet(unsigned long data)
}
}
-static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval)
+/*
+ * Both nexttbtt and intval have to be in usecs.
+ */
+static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
+ u32 intval, bool reset_tsf)
{
struct ath_hw *ah = sc->sc_ah;
ath9k_hw_disable_interrupts(ah);
- ath9k_hw_reset_tsf(ah);
+ if (reset_tsf)
+ ath9k_hw_reset_tsf(ah);
ath9k_beaconq_config(sc);
ath9k_hw_beaconinit(ah, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
@@ -442,10 +447,12 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
else
ah->imask &= ~ATH9K_INT_SWBA;
- ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n",
+ ath_dbg(common, BEACON,
+ "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
+ (conf->enable_beacon) ? "Enable" : "Disable",
nexttbtt, intval, conf->beacon_interval);
- ath9k_beacon_init(sc, nexttbtt, intval);
+ ath9k_beacon_init(sc, nexttbtt, intval, true);
}
/*
@@ -586,17 +593,45 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
ath9k_reset_beacon_status(sc);
intval = TU_TO_USEC(conf->beacon_interval);
- nexttbtt = intval;
+
+ if (conf->ibss_creator) {
+ nexttbtt = intval;
+ } else {
+ u32 tbtt, offset, tsftu;
+ u64 tsf;
+
+ /*
+ * Pull nexttbtt forward to reflect the current
+ * sync'd TSF.
+ */
+ tsf = ath9k_hw_gettsf64(ah);
+ tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
+ offset = tsftu % conf->beacon_interval;
+ tbtt = tsftu - offset;
+ if (offset)
+ tbtt += conf->beacon_interval;
+
+ nexttbtt = TU_TO_USEC(tbtt);
+ }
if (conf->enable_beacon)
ah->imask |= ATH9K_INT_SWBA;
else
ah->imask &= ~ATH9K_INT_SWBA;
- ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n",
+ ath_dbg(common, BEACON,
+ "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
+ (conf->enable_beacon) ? "Enable" : "Disable",
nexttbtt, intval, conf->beacon_interval);
- ath9k_beacon_init(sc, nexttbtt, intval);
+ ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator);
+
+ /*
+ * Set the global 'beacon has been configured' flag for the
+ * joiner case in IBSS mode.
+ */
+ if (!conf->ibss_creator && conf->enable_beacon)
+ set_bit(SC_OP_BEACONS, &sc->sc_flags);
}
bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
@@ -639,6 +674,7 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
cur_conf->dtim_period = bss_conf->dtim_period;
cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1;
+ cur_conf->ibss_creator = bss_conf->ibss_creator;
cur_conf->bmiss_timeout =
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
@@ -666,34 +702,59 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
{
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+ unsigned long flags;
+ bool skip_beacon = false;
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
ath9k_cache_beacon_config(sc, bss_conf);
ath9k_set_beacon(sc);
set_bit(SC_OP_BEACONS, &sc->sc_flags);
- } else {
- /*
- * Take care of multiple interfaces when
- * enabling/disabling SWBA.
- */
- if (changed & BSS_CHANGED_BEACON_ENABLED) {
- if (!bss_conf->enable_beacon &&
- (sc->nbcnvifs <= 1)) {
- cur_conf->enable_beacon = false;
- } else if (bss_conf->enable_beacon) {
- cur_conf->enable_beacon = true;
- ath9k_cache_beacon_config(sc, bss_conf);
- }
+ return;
+
+ }
+
+ /*
+ * Take care of multiple interfaces when
+ * enabling/disabling SWBA.
+ */
+ if (changed & BSS_CHANGED_BEACON_ENABLED) {
+ if (!bss_conf->enable_beacon &&
+ (sc->nbcnvifs <= 1)) {
+ cur_conf->enable_beacon = false;
+ } else if (bss_conf->enable_beacon) {
+ cur_conf->enable_beacon = true;
+ ath9k_cache_beacon_config(sc, bss_conf);
}
+ }
- if (cur_conf->beacon_interval) {
+ /*
+ * Configure the HW beacon registers only when we have a valid
+ * beacon interval.
+ */
+ if (cur_conf->beacon_interval) {
+ /*
+ * If we are joining an existing IBSS network, start beaconing
+ * only after a TSF-sync has taken place. Ensure that this
+ * happens by setting the appropriate flags.
+ */
+ if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator &&
+ bss_conf->enable_beacon) {
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+ skip_beacon = true;
+ } else {
ath9k_set_beacon(sc);
-
- if (cur_conf->enable_beacon)
- set_bit(SC_OP_BEACONS, &sc->sc_flags);
- else
- clear_bit(SC_OP_BEACONS, &sc->sc_flags);
}
+
+ /*
+ * Do not set the SC_OP_BEACONS flag for IBSS joiner mode
+ * here, it is done in ath9k_beacon_config_adhoc().
+ */
+ if (cur_conf->enable_beacon && !skip_beacon)
+ set_bit(SC_OP_BEACONS, &sc->sc_flags);
+ else
+ clear_bit(SC_OP_BEACONS, &sc->sc_flags);
}
}
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index e585fc827c50..3714b971d18e 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/export.h>
+#include <linux/relay.h>
#include <asm/unaligned.h>
#include "ath9k.h"
@@ -894,6 +895,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
RXS_ERR("RX-Bytes-All", rx_bytes_all);
RXS_ERR("RX-Beacons", rx_beacons);
RXS_ERR("RX-Frags", rx_frags);
+ RXS_ERR("RX-Spectral", rx_spectral);
if (len > size)
len = size;
@@ -965,6 +967,290 @@ static const struct file_operations fops_recv = {
.llseek = default_llseek,
};
+static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ char *mode = "";
+ unsigned int len;
+
+ switch (sc->spectral_mode) {
+ case SPECTRAL_DISABLED:
+ mode = "disable";
+ break;
+ case SPECTRAL_BACKGROUND:
+ mode = "background";
+ break;
+ case SPECTRAL_CHANSCAN:
+ mode = "chanscan";
+ break;
+ case SPECTRAL_MANUAL:
+ mode = "manual";
+ break;
+ }
+ len = strlen(mode);
+ return simple_read_from_buffer(user_buf, count, ppos, mode, len);
+}
+
+static ssize_t write_file_spec_scan_ctl(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ 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 (strncmp("trigger", buf, 7) == 0) {
+ ath9k_spectral_scan_trigger(sc->hw);
+ } else if (strncmp("background", buf, 9) == 0) {
+ ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
+ ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
+ } else if (strncmp("chanscan", buf, 8) == 0) {
+ ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN);
+ ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
+ } else if (strncmp("manual", buf, 6) == 0) {
+ ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL);
+ ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
+ } else if (strncmp("disable", buf, 7) == 0) {
+ ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED);
+ ath_dbg(common, CONFIG, "spectral scan: disabled\n");
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static const struct file_operations fops_spec_scan_ctl = {
+ .read = read_file_spec_scan_ctl,
+ .write = write_file_spec_scan_ctl,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_short_repeat(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ char buf[32];
+ unsigned int len;
+
+ len = sprintf(buf, "%d\n", sc->spec_config.short_repeat);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_short_repeat(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ unsigned long val;
+ 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 (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val < 0 || val > 1)
+ return -EINVAL;
+
+ sc->spec_config.short_repeat = val;
+ return count;
+}
+
+static const struct file_operations fops_spectral_short_repeat = {
+ .read = read_file_spectral_short_repeat,
+ .write = write_file_spectral_short_repeat,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_count(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ char buf[32];
+ unsigned int len;
+
+ len = sprintf(buf, "%d\n", sc->spec_config.count);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_count(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ unsigned long val;
+ 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 (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val < 0 || val > 255)
+ return -EINVAL;
+
+ sc->spec_config.count = val;
+ return count;
+}
+
+static const struct file_operations fops_spectral_count = {
+ .read = read_file_spectral_count,
+ .write = write_file_spectral_count,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_period(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ char buf[32];
+ unsigned int len;
+
+ len = sprintf(buf, "%d\n", sc->spec_config.period);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_period(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ unsigned long val;
+ 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 (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val < 0 || val > 255)
+ return -EINVAL;
+
+ sc->spec_config.period = val;
+ return count;
+}
+
+static const struct file_operations fops_spectral_period = {
+ .read = read_file_spectral_period,
+ .write = write_file_spectral_period,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_fft_period(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ char buf[32];
+ unsigned int len;
+
+ len = sprintf(buf, "%d\n", sc->spec_config.fft_period);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_fft_period(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ unsigned long val;
+ 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 (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val < 0 || val > 15)
+ return -EINVAL;
+
+ sc->spec_config.fft_period = val;
+ return count;
+}
+
+static const struct file_operations fops_spectral_fft_period = {
+ .read = read_file_spectral_fft_period,
+ .write = write_file_spectral_fft_period,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static struct dentry *create_buf_file_handler(const char *filename,
+ struct dentry *parent,
+ umode_t mode,
+ struct rchan_buf *buf,
+ int *is_global)
+{
+ struct dentry *buf_file;
+
+ buf_file = debugfs_create_file(filename, mode, parent, buf,
+ &relay_file_operations);
+ *is_global = 1;
+ return buf_file;
+}
+
+static int remove_buf_file_handler(struct dentry *dentry)
+{
+ debugfs_remove(dentry);
+
+ return 0;
+}
+
+void ath_debug_send_fft_sample(struct ath_softc *sc,
+ struct fft_sample_tlv *fft_sample_tlv)
+{
+ int length;
+ if (!sc->rfs_chan_spec_scan)
+ return;
+
+ length = __be16_to_cpu(fft_sample_tlv->length) +
+ sizeof(*fft_sample_tlv);
+ relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length);
+}
+
+static struct rchan_callbacks rfs_spec_scan_cb = {
+ .create_buf_file = create_buf_file_handler,
+ .remove_buf_file = remove_buf_file_handler,
+};
+
+
static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -1779,6 +2065,24 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_base_eeprom);
debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_modal_eeprom);
+ sc->rfs_chan_spec_scan = relay_open("spectral_scan",
+ sc->debug.debugfs_phy,
+ 262144, 4, &rfs_spec_scan_cb,
+ NULL);
+ debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc,
+ &fops_spec_scan_ctl);
+ debugfs_create_file("spectral_short_repeat", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc,
+ &fops_spectral_short_repeat);
+ debugfs_create_file("spectral_count", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_spectral_count);
+ debugfs_create_file("spectral_period", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_spectral_period);
+ debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc,
+ &fops_spectral_fft_period);
+
#ifdef CONFIG_ATH9K_MAC_DEBUG
debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_samps);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 6df2ab62dcb7..410d6d8f1aa7 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -23,6 +23,7 @@
struct ath_txq;
struct ath_buf;
+struct fft_sample_tlv;
#ifdef CONFIG_ATH9K_DEBUGFS
#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
@@ -218,6 +219,7 @@ struct ath_tx_stats {
* @rx_too_many_frags_err: Frames dropped due to too-many-frags received.
* @rx_beacons: No. of beacons received.
* @rx_frags: No. of rx-fragements received.
+ * @rx_spectral: No of spectral packets received.
*/
struct ath_rx_stats {
u32 rx_pkts_all;
@@ -236,6 +238,7 @@ struct ath_rx_stats {
u32 rx_too_many_frags_err;
u32 rx_beacons;
u32 rx_frags;
+ u32 rx_spectral;
};
struct ath_stats {
@@ -321,6 +324,10 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct dentry *dir);
+
+void ath_debug_send_fft_sample(struct ath_softc *sc,
+ struct fft_sample_tlv *fft_sample);
+
#else
#define RX_STAT_INC(c) /* NOP */
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
index 24877b00cbf4..467b60014b7b 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
@@ -288,11 +288,11 @@ struct dfs_pattern_detector *
dfs_pattern_detector_init(enum nl80211_dfs_regions region)
{
struct dfs_pattern_detector *dpd;
+
dpd = kmalloc(sizeof(*dpd), GFP_KERNEL);
- if (dpd == NULL) {
- pr_err("allocation of dfs_pattern_detector failed\n");
+ if (dpd == NULL)
return NULL;
- }
+
*dpd = default_dpd;
INIT_LIST_HEAD(&dpd->channel_detectors);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 05d5ba66cac3..716058b67557 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -280,14 +280,14 @@ err:
return ret;
}
-static int ath9k_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
+static void ath9k_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath9k_htc_priv *priv = hw->priv;
- return ath_reg_notifier_apply(wiphy, request,
- ath9k_hw_regulatory(priv->ah));
+ ath_reg_notifier_apply(wiphy, request,
+ ath9k_hw_regulatory(priv->ah));
}
static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
@@ -783,7 +783,7 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
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",
+ snprintf(hw->wiphy->fw_version, sizeof(hw->wiphy->fw_version), "%d.%d",
priv->fw_version_major,
priv->fw_version_minor);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 9c07a8fa5134..a8016d70088a 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1628,7 +1628,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
if (!ret)
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index b6a5a08810b8..3ad1fd05c5e7 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -1196,20 +1196,17 @@ void ath9k_rx_cleanup(struct ath9k_htc_priv *priv)
int ath9k_rx_init(struct ath9k_htc_priv *priv)
{
- struct ath_hw *ah = priv->ah;
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_rxbuf *rxbuf;
int i = 0;
INIT_LIST_HEAD(&priv->rx.rxbuf);
spin_lock_init(&priv->rx.rxbuflock);
for (i = 0; i < ATH9K_HTC_RXBUF; i++) {
- rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL);
- if (rxbuf == NULL) {
- ath_err(common, "Unable to allocate RX buffers\n");
+ struct ath9k_htc_rxbuf *rxbuf =
+ kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL);
+ if (rxbuf == NULL)
goto err;
- }
+
list_add_tail(&rxbuf->list, &priv->rx.rxbuf);
}
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 0f2b97f6b739..14b701140b49 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -101,22 +101,6 @@ static inline void ath9k_hw_spur_mitigate_freq(struct ath_hw *ah,
ath9k_hw_private_ops(ah)->spur_mitigate_freq(ah, chan);
}
-static inline int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah)
-{
- if (!ath9k_hw_private_ops(ah)->rf_alloc_ext_banks)
- return 0;
-
- return ath9k_hw_private_ops(ah)->rf_alloc_ext_banks(ah);
-}
-
-static inline void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah)
-{
- if (!ath9k_hw_private_ops(ah)->rf_free_ext_banks)
- return;
-
- ath9k_hw_private_ops(ah)->rf_free_ext_banks(ah);
-}
-
static inline bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
struct ath9k_channel *chan,
u16 modesIndex)
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 7cb787065913..2a2ae403e0e5 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -54,11 +54,6 @@ static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
ath9k_hw_private_ops(ah)->init_cal_settings(ah);
}
-static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
-{
- ath9k_hw_private_ops(ah)->init_mode_regs(ah);
-}
-
static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@@ -208,7 +203,7 @@ void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
udelay(hw_delay + BASE_ACTIVATE_DELAY);
}
-void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
int column, unsigned int *writecnt)
{
int r;
@@ -554,28 +549,19 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
ah->eep_ops->get_eeprom_ver(ah),
ah->eep_ops->get_eeprom_rev(ah));
- ecode = ath9k_hw_rf_alloc_ext_banks(ah);
- if (ecode) {
- ath_err(ath9k_hw_common(ah),
- "Failed allocating banks for external radio\n");
- ath9k_hw_rf_free_ext_banks(ah);
- return ecode;
- }
-
- if (ah->config.enable_ani) {
- ath9k_hw_ani_setup(ah);
+ if (ah->config.enable_ani)
ath9k_hw_ani_init(ah);
- }
return 0;
}
-static void ath9k_hw_attach_ops(struct ath_hw *ah)
+static int ath9k_hw_attach_ops(struct ath_hw *ah)
{
- if (AR_SREV_9300_20_OR_LATER(ah))
- ar9003_hw_attach_ops(ah);
- else
- ar9002_hw_attach_ops(ah);
+ if (!AR_SREV_9300_20_OR_LATER(ah))
+ return ar9002_hw_attach_ops(ah);
+
+ ar9003_hw_attach_ops(ah);
+ return 0;
}
/* Called for all hardware families */
@@ -611,7 +597,9 @@ static int __ath9k_hw_init(struct ath_hw *ah)
ath9k_hw_init_defaults(ah);
ath9k_hw_init_config(ah);
- ath9k_hw_attach_ops(ah);
+ r = ath9k_hw_attach_ops(ah);
+ if (r)
+ return r;
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
ath_err(common, "Couldn't wakeup chip\n");
@@ -675,8 +663,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
if (!AR_SREV_9300_20_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
- ath9k_hw_init_mode_regs(ah);
-
if (!ah->is_pciexpress)
ath9k_hw_disablepcie(ah);
@@ -1153,12 +1139,9 @@ void ath9k_hw_deinit(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
if (common->state < ATH_HW_INITIALIZED)
- goto free_hw;
+ return;
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
-
-free_hw:
- ath9k_hw_rf_free_ext_banks(ah);
}
EXPORT_SYMBOL(ath9k_hw_deinit);
@@ -2576,12 +2559,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
rx_chainmask >>= 1;
}
- if (AR_SREV_9300_20_OR_LATER(ah)) {
- ah->enabled_cals |= TX_IQ_CAL;
- if (AR_SREV_9485_OR_LATER(ah))
- ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
- }
-
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
if (!(ah->ent_mode & AR_ENT_OTP_49GHZ_DISABLE))
pCap->hw_caps |= ATH9K_HW_CAP_MCI;
@@ -2590,7 +2567,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_RTT;
}
-
if (AR_SREV_9280_20_OR_LATER(ah)) {
pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE |
ATH9K_HW_WOW_PATTERN_MATCH_EXACT;
@@ -3005,13 +2981,8 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
struct ath_gen_timer *timer;
timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
-
- if (timer == NULL) {
- ath_err(ath9k_hw_common(ah),
- "Failed to allocate memory for hw timer[%d]\n",
- timer_index);
+ if (timer == NULL)
return NULL;
- }
/* allocate a hardware generic timer slot */
timer_table->timers[timer_index] = timer;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 9d26fc56ca56..784e81ccb903 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -397,6 +397,7 @@ enum ath9k_int {
#define MAX_RTT_TABLE_ENTRY 6
#define MAX_IQCAL_MEASUREMENT 8
#define MAX_CL_TAB_ENTRY 16
+#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j))
struct ath9k_hw_cal_data {
u16 channel;
@@ -599,13 +600,10 @@ struct ath_hw_radar_conf {
* @init_cal_settings: setup types of calibrations supported
* @init_cal: starts actual calibration
*
- * @init_mode_regs: Initializes mode registers
* @init_mode_gain_regs: Initialize TX/RX gain registers
*
* @rf_set_freq: change frequency
* @spur_mitigate_freq: spur mitigation
- * @rf_alloc_ext_banks:
- * @rf_free_ext_banks:
* @set_rf_regs:
* @compute_pll_control: compute the PLL control value to use for
* AR_RTC_PLL_CONTROL for a given channel
@@ -620,7 +618,6 @@ struct ath_hw_private_ops {
void (*init_cal_settings)(struct ath_hw *ah);
bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan);
- void (*init_mode_regs)(struct ath_hw *ah);
void (*init_mode_gain_regs)(struct ath_hw *ah);
void (*setup_calibration)(struct ath_hw *ah,
struct ath9k_cal_list *currCal);
@@ -630,8 +627,6 @@ struct ath_hw_private_ops {
struct ath9k_channel *chan);
void (*spur_mitigate_freq)(struct ath_hw *ah,
struct ath9k_channel *chan);
- int (*rf_alloc_ext_banks)(struct ath_hw *ah);
- void (*rf_free_ext_banks)(struct ath_hw *ah);
bool (*set_rf_regs)(struct ath_hw *ah,
struct ath9k_channel *chan,
u16 modesIndex);
@@ -661,6 +656,37 @@ struct ath_hw_private_ops {
};
/**
+ * struct ath_spec_scan - parameters for Atheros spectral scan
+ *
+ * @enabled: enable/disable spectral scan
+ * @short_repeat: controls whether the chip is in spectral scan mode
+ * for 4 usec (enabled) or 204 usec (disabled)
+ * @count: number of scan results requested. There are special meanings
+ * in some chip revisions:
+ * AR92xx: highest bit set (>=128) for endless mode
+ * (spectral scan won't stopped until explicitly disabled)
+ * AR9300 and newer: 0 for endless mode
+ * @endless: true if endless mode is intended. Otherwise, count value is
+ * corrected to the next possible value.
+ * @period: time duration between successive spectral scan entry points
+ * (period*256*Tclk). Tclk = ath_common->clockrate
+ * @fft_period: PHY passes FFT frames to MAC every (fft_period+1)*4uS
+ *
+ * Note: Tclk = 40MHz or 44MHz depending upon operating mode.
+ * Typically it's 44MHz in 2/5GHz on later chips, but there's
+ * a "fast clock" check for this in 5GHz.
+ *
+ */
+struct ath_spec_scan {
+ bool enabled;
+ bool short_repeat;
+ bool endless;
+ u8 count;
+ u8 period;
+ u8 fft_period;
+};
+
+/**
* struct ath_hw_ops - callbacks used by hardware code and driver code
*
* This structure contains callbacks designed to to be used internally by
@@ -668,6 +694,10 @@ struct ath_hw_private_ops {
*
* @config_pci_powersave:
* @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
+ *
+ * @spectral_scan_config: set parameters for spectral scan and enable/disable it
+ * @spectral_scan_trigger: trigger a spectral scan run
+ * @spectral_scan_wait: wait for a spectral scan run to finish
*/
struct ath_hw_ops {
void (*config_pci_powersave)(struct ath_hw *ah,
@@ -688,6 +718,10 @@ struct ath_hw_ops {
void (*antdiv_comb_conf_set)(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf);
void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable);
+ void (*spectral_scan_config)(struct ath_hw *ah,
+ struct ath_spec_scan *param);
+ void (*spectral_scan_trigger)(struct ath_hw *ah);
+ void (*spectral_scan_wait)(struct ath_hw *ah);
};
struct ath_nf_limits {
@@ -710,6 +744,7 @@ enum ath_cal_list {
struct ath_hw {
struct ath_ops reg_ops;
+ struct device *dev;
struct ieee80211_hw *hw;
struct ath_common common;
struct ath9k_hw_version hw_version;
@@ -771,7 +806,6 @@ struct ath_hw {
struct ath9k_cal_list iq_caldata;
struct ath9k_cal_list adcgain_caldata;
struct ath9k_cal_list adcdc_caldata;
- struct ath9k_cal_list tempCompCalData;
struct ath9k_cal_list *cal_list;
struct ath9k_cal_list *cal_list_last;
struct ath9k_cal_list *cal_list_curr;
@@ -830,10 +864,6 @@ struct ath_hw {
/* ANI */
u32 proc_phyerr;
u32 aniperiod;
- int totalSizeDesired[5];
- int coarse_high[5];
- int coarse_low[5];
- int firpwr[5];
enum ath9k_ani_cmd ani_function;
u32 ani_skip_count;
@@ -979,7 +1009,7 @@ void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
int hw_delay);
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,
+void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
int column, unsigned int *writecnt);
u32 ath9k_hw_reverse_bits(u32 val, u32 n);
u16 ath9k_hw_computetxtime(struct ath_hw *ah,
@@ -1069,14 +1099,14 @@ bool ar9003_is_paprd_enabled(struct ath_hw *ah);
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
/* Hardware family op attach helpers */
-void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
+int ar5008_hw_attach_phy_ops(struct ath_hw *ah);
void ar9002_hw_attach_phy_ops(struct ath_hw *ah);
void ar9003_hw_attach_phy_ops(struct ath_hw *ah);
void ar9002_hw_attach_calib_ops(struct ath_hw *ah);
void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
-void ar9002_hw_attach_ops(struct ath_hw *ah);
+int ar9002_hw_attach_ops(struct ath_hw *ah);
void ar9003_hw_attach_ops(struct ath_hw *ah);
void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index f69ef5d48c7b..af932c9444de 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/ath9k_platform.h>
#include <linux/module.h>
+#include <linux/relay.h>
#include "ath9k.h"
@@ -302,16 +303,15 @@ static void setup_ht_cap(struct ath_softc *sc,
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
}
-static int ath9k_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
+static void ath9k_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
- int ret;
- ret = ath_reg_notifier_apply(wiphy, request, reg);
+ ath_reg_notifier_apply(wiphy, request, reg);
/* Set tx power */
if (ah->curchan) {
@@ -321,8 +321,6 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
ath9k_ps_restore(sc);
}
-
- return ret;
}
/*
@@ -337,7 +335,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
u8 *ds;
struct ath_buf *bf;
- int i, bsize, error, desc_len;
+ int i, bsize, desc_len;
ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n",
name, nbuf, ndesc);
@@ -353,8 +351,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
if ((desc_len % 4) != 0) {
ath_err(common, "ath_desc not DWORD aligned\n");
BUG_ON((desc_len % 4) != 0);
- error = -ENOMEM;
- goto fail;
+ return -ENOMEM;
}
dd->dd_desc_len = desc_len * nbuf * ndesc;
@@ -378,12 +375,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
}
/* allocate descriptors */
- dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
- &dd->dd_desc_paddr, GFP_KERNEL);
- if (dd->dd_desc == NULL) {
- error = -ENOMEM;
- goto fail;
- }
+ dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len,
+ &dd->dd_desc_paddr, GFP_KERNEL);
+ if (!dd->dd_desc)
+ return -ENOMEM;
+
ds = (u8 *) dd->dd_desc;
ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
name, ds, (u32) dd->dd_desc_len,
@@ -391,12 +387,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
/* allocate buffers */
bsize = sizeof(struct ath_buf) * nbuf;
- bf = kzalloc(bsize, GFP_KERNEL);
- if (bf == NULL) {
- error = -ENOMEM;
- goto fail2;
- }
- dd->dd_bufptr = bf;
+ bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL);
+ if (!bf)
+ return -ENOMEM;
for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) {
bf->bf_desc = ds;
@@ -422,12 +415,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
list_add_tail(&bf->list, head);
}
return 0;
-fail2:
- dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
- dd->dd_desc_paddr);
-fail:
- memset(dd, 0, sizeof(*dd));
- return error;
}
static int ath9k_init_queues(struct ath_softc *sc)
@@ -457,11 +444,13 @@ static int ath9k_init_channels_rates(struct ath_softc *sc)
ATH9K_NUM_CHANNELS);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
- channels = kmemdup(ath9k_2ghz_chantable,
+ channels = devm_kzalloc(sc->dev,
sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
if (!channels)
return -ENOMEM;
+ memcpy(channels, ath9k_2ghz_chantable,
+ sizeof(ath9k_2ghz_chantable));
sc->sbands[IEEE80211_BAND_2GHZ].channels = channels;
sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
@@ -472,14 +461,13 @@ static int ath9k_init_channels_rates(struct ath_softc *sc)
}
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
- channels = kmemdup(ath9k_5ghz_chantable,
+ channels = devm_kzalloc(sc->dev,
sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
- if (!channels) {
- if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
- kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
+ if (!channels)
return -ENOMEM;
- }
+ memcpy(channels, ath9k_5ghz_chantable,
+ sizeof(ath9k_5ghz_chantable));
sc->sbands[IEEE80211_BAND_5GHZ].channels = channels;
sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
@@ -509,6 +497,13 @@ static void ath9k_init_misc(struct ath_softc *sc)
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
+
+ sc->spec_config.enabled = 0;
+ sc->spec_config.short_repeat = true;
+ sc->spec_config.count = 8;
+ sc->spec_config.endless = false;
+ sc->spec_config.period = 0xFF;
+ sc->spec_config.fft_period = 0xF;
}
static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob,
@@ -565,10 +560,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
int ret = 0, i;
int csz = 0;
- ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
+ ah = devm_kzalloc(sc->dev, sizeof(struct ath_hw), GFP_KERNEL);
if (!ah)
return -ENOMEM;
+ ah->dev = sc->dev;
ah->hw = sc->hw;
ah->hw_version.devid = devid;
ah->reg_ops.read = ath9k_ioread32;
@@ -636,7 +632,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
if (pdata && pdata->eeprom_name) {
ret = ath9k_eeprom_request(sc, pdata->eeprom_name);
if (ret)
- goto err_eeprom;
+ return ret;
}
/* Initializes the hardware for all supported chipsets */
@@ -676,10 +672,6 @@ err_queues:
ath9k_hw_deinit(ah);
err_hw:
ath9k_eeprom_release(sc);
-err_eeprom:
- kfree(ah);
- sc->sc_ah = NULL;
-
return ret;
}
@@ -844,8 +836,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
/* Bring up device */
error = ath9k_init_softc(devid, sc, bus_ops);
- if (error != 0)
- goto error_init;
+ if (error)
+ return error;
ah = sc->sc_ah;
common = ath9k_hw_common(ah);
@@ -855,19 +847,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
ath9k_reg_notifier);
if (error)
- goto error_regd;
+ goto deinit;
reg = &common->regulatory;
/* Setup TX DMA */
error = ath_tx_init(sc, ATH_TXBUF);
if (error != 0)
- goto error_tx;
+ goto deinit;
/* Setup RX DMA */
error = ath_rx_init(sc, ATH_RXBUF);
if (error != 0)
- goto error_rx;
+ goto deinit;
ath9k_init_txpower_limits(sc);
@@ -881,19 +873,19 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
/* Register with mac80211 */
error = ieee80211_register_hw(hw);
if (error)
- goto error_register;
+ goto rx_cleanup;
error = ath9k_init_debug(ah);
if (error) {
ath_err(common, "Unable to create debugfs files\n");
- goto error_world;
+ goto unregister;
}
/* Handle world regulatory */
if (!ath_is_world_regd(reg)) {
error = regulatory_hint(hw->wiphy, reg->alpha2);
if (error)
- goto error_world;
+ goto unregister;
}
ath_init_leds(sc);
@@ -901,17 +893,12 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
return 0;
-error_world:
+unregister:
ieee80211_unregister_hw(hw);
-error_register:
+rx_cleanup:
ath_rx_cleanup(sc);
-error_rx:
- ath_tx_cleanup(sc);
-error_tx:
- /* Nothing */
-error_regd:
+deinit:
ath9k_deinit_softc(sc);
-error_init:
return error;
}
@@ -923,12 +910,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
{
int i = 0;
- if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
- kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
-
- if (sc->sbands[IEEE80211_BAND_5GHZ].channels)
- kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels);
-
ath9k_deinit_btcoex(sc);
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
@@ -940,8 +921,11 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
sc->dfs_detector->exit(sc->dfs_detector);
ath9k_eeprom_release(sc);
- kfree(sc->sc_ah);
- sc->sc_ah = NULL;
+
+ if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
+ relay_close(sc->rfs_chan_spec_scan);
+ sc->rfs_chan_spec_scan = NULL;
+ }
}
void ath9k_deinit_device(struct ath_softc *sc)
@@ -957,22 +941,9 @@ void ath9k_deinit_device(struct ath_softc *sc)
ieee80211_unregister_hw(hw);
ath_rx_cleanup(sc);
- ath_tx_cleanup(sc);
ath9k_deinit_softc(sc);
}
-void ath_descdma_cleanup(struct ath_softc *sc,
- struct ath_descdma *dd,
- struct list_head *head)
-{
- dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
- dd->dd_desc_paddr);
-
- INIT_LIST_HEAD(head);
- kfree(dd->dd_bufptr);
- memset(dd, 0, sizeof(*dd));
-}
-
/************************/
/* Module Hooks */
/************************/
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index b42be910a83d..811007ec07a7 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -605,13 +605,13 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
* reported, then decryption and MIC errors are irrelevant,
* the frame is going to be dropped either way
*/
- if (ads.ds_rxstatus8 & AR_CRCErr)
- rs->rs_status |= ATH9K_RXERR_CRC;
- else if (ads.ds_rxstatus8 & AR_PHYErr) {
+ if (ads.ds_rxstatus8 & AR_PHYErr) {
rs->rs_status |= ATH9K_RXERR_PHY;
phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
rs->rs_phyerr = phyerr;
- } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+ } else if (ads.ds_rxstatus8 & AR_CRCErr)
+ rs->rs_status |= ATH9K_RXERR_CRC;
+ else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
rs->rs_status |= ATH9K_RXERR_DECRYPT;
else if (ads.ds_rxstatus8 & AR_MichaelErr)
rs->rs_status |= ATH9K_RXERR_MIC;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 4a745e68dd94..1ff817061ebc 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -226,7 +226,8 @@ enum ath9k_phyerr {
ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35,
ATH9K_PHYERR_HT_RATE_ILLEGAL = 36,
- ATH9K_PHYERR_MAX = 37,
+ ATH9K_PHYERR_SPECTRAL = 38,
+ ATH9K_PHYERR_MAX = 39,
};
struct ath_desc {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index dd91f8fdc01c..6e66f9c6782b 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -182,7 +182,7 @@ static void ath_restart_work(struct ath_softc *sc)
ath_start_ani(sc);
}
-static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx)
+static bool ath_prepare_reset(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
bool ret = true;
@@ -196,10 +196,10 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx)
ath9k_debug_samp_bb_mac(sc);
ath9k_hw_disable_interrupts(ah);
- if (!ath_stoprecv(sc))
+ if (!ath_drain_all_txq(sc))
ret = false;
- if (!ath_drain_all_txq(sc, retry_tx))
+ if (!ath_stoprecv(sc))
ret = false;
return ret;
@@ -247,8 +247,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
return true;
}
-static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
- bool retry_tx)
+static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
@@ -271,7 +270,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
hchan = ah->curchan;
}
- if (!ath_prepare_reset(sc, retry_tx))
+ if (!ath_prepare_reset(sc))
fastcc = false;
ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
@@ -312,7 +311,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (test_bit(SC_OP_INVALID, &sc->sc_flags))
return -EIO;
- r = ath_reset_internal(sc, hchan, false);
+ r = ath_reset_internal(sc, hchan);
return r;
}
@@ -321,28 +320,25 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
struct ieee80211_vif *vif)
{
struct ath_node *an;
- u8 density;
an = (struct ath_node *)sta->drv_priv;
an->sc = sc;
an->sta = sta;
an->vif = vif;
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
- ath_tx_node_init(sc, an);
+ ath_tx_node_init(sc, an);
+
+ if (sta->ht_cap.ht_supported) {
an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->ht_cap.ampdu_factor);
- density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
- an->mpdudensity = density;
+ an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
}
}
static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
{
struct ath_node *an = (struct ath_node *)sta->drv_priv;
-
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
- ath_tx_node_cleanup(sc, an);
+ ath_tx_node_cleanup(sc, an);
}
void ath9k_tasklet(unsigned long data)
@@ -542,23 +538,21 @@ chip_reset:
#undef SCHED_INTR
}
-static int ath_reset(struct ath_softc *sc, bool retry_tx)
+static int ath_reset(struct ath_softc *sc)
{
- int r;
+ int i, r;
ath9k_ps_wakeup(sc);
- r = ath_reset_internal(sc, NULL, retry_tx);
+ r = ath_reset_internal(sc, NULL);
- if (retry_tx) {
- int i;
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
- if (ATH_TXQ_SETUP(sc, i)) {
- spin_lock_bh(&sc->tx.txq[i].axq_lock);
- ath_txq_schedule(sc, &sc->tx.txq[i]);
- spin_unlock_bh(&sc->tx.txq[i].axq_lock);
- }
- }
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (!ATH_TXQ_SETUP(sc, i))
+ continue;
+
+ spin_lock_bh(&sc->tx.txq[i].axq_lock);
+ ath_txq_schedule(sc, &sc->tx.txq[i]);
+ spin_unlock_bh(&sc->tx.txq[i].axq_lock);
}
ath9k_ps_restore(sc);
@@ -579,7 +573,7 @@ void ath_reset_work(struct work_struct *work)
{
struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
- ath_reset(sc, true);
+ ath_reset(sc);
}
/**********************/
@@ -797,7 +791,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
}
- ath_prepare_reset(sc, false);
+ ath_prepare_reset(sc);
if (sc->rx.frag) {
dev_kfree_skb_any(sc->rx.frag);
@@ -1068,6 +1062,75 @@ static void ath9k_disable_ps(struct ath_softc *sc)
ath_dbg(common, PS, "PowerSave disabled\n");
}
+void ath9k_spectral_scan_trigger(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);
+ u32 rxfilter;
+
+ if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
+ ath_err(common, "spectrum analyzer not implemented on this hardware\n");
+ return;
+ }
+
+ ath9k_ps_wakeup(sc);
+ rxfilter = ath9k_hw_getrxfilter(ah);
+ ath9k_hw_setrxfilter(ah, rxfilter |
+ ATH9K_RX_FILTER_PHYRADAR |
+ ATH9K_RX_FILTER_PHYERR);
+
+ /* TODO: usually this should not be neccesary, but for some reason
+ * (or in some mode?) the trigger must be called after the
+ * configuration, otherwise the register will have its values reset
+ * (on my ar9220 to value 0x01002310)
+ */
+ ath9k_spectral_scan_config(hw, sc->spectral_mode);
+ ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
+ ath9k_ps_restore(sc);
+}
+
+int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
+ enum spectral_mode spectral_mode)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
+ ath_err(common, "spectrum analyzer not implemented on this hardware\n");
+ return -1;
+ }
+
+ switch (spectral_mode) {
+ case SPECTRAL_DISABLED:
+ sc->spec_config.enabled = 0;
+ break;
+ case SPECTRAL_BACKGROUND:
+ /* send endless samples.
+ * TODO: is this really useful for "background"?
+ */
+ sc->spec_config.endless = 1;
+ sc->spec_config.enabled = 1;
+ break;
+ case SPECTRAL_CHANSCAN:
+ case SPECTRAL_MANUAL:
+ sc->spec_config.endless = 0;
+ sc->spec_config.enabled = 1;
+ break;
+ default:
+ return -1;
+ }
+
+ ath9k_ps_wakeup(sc);
+ ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config);
+ ath9k_ps_restore(sc);
+
+ sc->spectral_mode = spectral_mode;
+
+ return 0;
+}
+
static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath_softc *sc = hw->priv;
@@ -1181,6 +1244,11 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
*/
if (old_pos >= 0)
ath_update_survey_nf(sc, old_pos);
+
+ /* perform spectral scan if requested. */
+ if (sc->scanning && sc->spectral_mode == SPECTRAL_CHANSCAN)
+ ath9k_spectral_scan_trigger(hw);
+
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -1603,7 +1671,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
ath9k_ps_restore(sc);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ath9k_ps_wakeup(sc);
ath_tx_aggr_stop(sc, sta, tid);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@ -1722,11 +1792,11 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
if (drop) {
ath9k_ps_wakeup(sc);
spin_lock_bh(&sc->sc_pcu_lock);
- drain_txq = ath_drain_all_txq(sc, false);
+ drain_txq = ath_drain_all_txq(sc);
spin_unlock_bh(&sc->sc_pcu_lock);
if (!drain_txq)
- ath_reset(sc, false);
+ ath_reset(sc);
ath9k_ps_restore(sc);
ieee80211_wake_queues(hw);
@@ -2234,6 +2304,19 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
}
#endif
+static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+
+ sc->scanning = 1;
+}
+
+static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+
+ sc->scanning = 0;
+}
struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
@@ -2280,4 +2363,6 @@ struct ieee80211_ops ath9k_ops = {
.sta_add_debugfs = ath9k_sta_add_debugfs,
.sta_remove_debugfs = ath9k_sta_remove_debugfs,
#endif
+ .sw_scan_start = ath9k_sw_scan_start,
+ .sw_scan_complete = ath9k_sw_scan_complete,
};
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
index 5c02702f21e7..815bee21c19a 100644
--- a/drivers/net/wireless/ath/ath9k/mci.c
+++ b/drivers/net/wireless/ath/ath9k/mci.c
@@ -438,7 +438,7 @@ int ath_mci_setup(struct ath_softc *sc)
struct ath_mci_buf *buf = &mci->sched_buf;
int ret;
- buf->bf_addr = dma_alloc_coherent(sc->dev,
+ buf->bf_addr = dmam_alloc_coherent(sc->dev,
ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
&buf->bf_paddr, GFP_KERNEL);
@@ -474,13 +474,6 @@ void ath_mci_cleanup(struct ath_softc *sc)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_hw *ah = sc->sc_ah;
- struct ath_mci_coex *mci = &sc->mci_coex;
- struct ath_mci_buf *buf = &mci->sched_buf;
-
- if (buf->bf_addr)
- dma_free_coherent(sc->dev,
- ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
- buf->bf_addr, buf->bf_paddr);
ar9003_mci_cleanup(ah);
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 7ae73fbd9136..0e0d39583837 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -147,7 +147,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = {
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- void __iomem *mem;
struct ath_softc *sc;
struct ieee80211_hw *hw;
u8 csz;
@@ -155,19 +154,19 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
int ret = 0;
char hw_name[64];
- if (pci_enable_device(pdev))
+ if (pcim_enable_device(pdev))
return -EIO;
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
pr_err("32-bit DMA not available\n");
- goto err_dma;
+ return ret;
}
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
pr_err("32-bit DMA consistent DMA enable failed\n");
- goto err_dma;
+ return ret;
}
/*
@@ -203,25 +202,16 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
- ret = pci_request_region(pdev, 0, "ath9k");
+ ret = pcim_iomap_regions(pdev, BIT(0), "ath9k");
if (ret) {
dev_err(&pdev->dev, "PCI memory region reserve error\n");
- ret = -ENODEV;
- goto err_region;
- }
-
- mem = pci_iomap(pdev, 0, 0);
- if (!mem) {
- pr_err("PCI memory map error\n") ;
- ret = -EIO;
- goto err_iomap;
+ return -ENODEV;
}
hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
if (!hw) {
dev_err(&pdev->dev, "No memory for ieee80211_hw\n");
- ret = -ENOMEM;
- goto err_alloc_hw;
+ return -ENOMEM;
}
SET_IEEE80211_DEV(hw, &pdev->dev);
@@ -230,7 +220,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc = hw->priv;
sc->hw = hw;
sc->dev = &pdev->dev;
- sc->mem = mem;
+ sc->mem = pcim_iomap_table(pdev)[0];
/* Will be cleared in ath9k_start() */
set_bit(SC_OP_INVALID, &sc->sc_flags);
@@ -251,7 +241,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
- hw_name, (unsigned long)mem, pdev->irq);
+ hw_name, (unsigned long)sc->mem, pdev->irq);
return 0;
@@ -259,14 +249,6 @@ err_init:
free_irq(sc->irq, sc);
err_irq:
ieee80211_free_hw(hw);
-err_alloc_hw:
- pci_iounmap(pdev, mem);
-err_iomap:
- pci_release_region(pdev, 0);
-err_region:
- /* Nothing */
-err_dma:
- pci_disable_device(pdev);
return ret;
}
@@ -274,17 +256,12 @@ static void ath_pci_remove(struct pci_dev *pdev)
{
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv;
- void __iomem *mem = sc->mem;
if (!is_ath9k_unloaded)
sc->sc_ah->ah_flags |= AH_UNPLUGGED;
ath9k_deinit_device(sc);
free_irq(sc->irq, sc);
ieee80211_free_hw(sc->hw);
-
- pci_iounmap(pdev, mem);
- pci_disable_device(pdev);
- pci_release_region(pdev, 0);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 714558d1ba78..96ac433ba7f6 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -1204,7 +1204,7 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta)
caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
else if (sta->ht_cap.mcs.rx_mask[1])
caps |= WLAN_RC_DS_FLAG;
- if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+ if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
caps |= WLAN_RC_40_FLAG;
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
caps |= WLAN_RC_SGI_FLAG;
@@ -1452,17 +1452,7 @@ static void ath_rate_free(void *priv)
static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
{
- struct ath_softc *sc = priv;
- struct ath_rate_priv *rate_priv;
-
- rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp);
- if (!rate_priv) {
- ath_err(ath9k_hw_common(sc->sc_ah),
- "Unable to allocate private rc structure\n");
- return NULL;
- }
-
- return rate_priv;
+ return kzalloc(sizeof(struct ath_rate_priv), gfp);
}
static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 90752f246970..ee156e543147 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -15,6 +15,7 @@
*/
#include <linux/dma-mapping.h>
+#include <linux/relay.h>
#include "ath9k.h"
#include "ar9003_mac.h"
@@ -180,11 +181,6 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc)
bf->bf_mpdu = NULL;
}
}
-
- INIT_LIST_HEAD(&sc->rx.rxbuf);
-
- kfree(sc->rx.rx_bufptr);
- sc->rx.rx_bufptr = NULL;
}
static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size)
@@ -211,12 +207,11 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
ah->caps.rx_hp_qdepth);
size = sizeof(struct ath_buf) * nbufs;
- bf = kzalloc(size, GFP_KERNEL);
+ bf = devm_kzalloc(sc->dev, size, GFP_KERNEL);
if (!bf)
return -ENOMEM;
INIT_LIST_HEAD(&sc->rx.rxbuf);
- sc->rx.rx_bufptr = bf;
for (i = 0; i < nbufs; i++, bf++) {
skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL);
@@ -357,9 +352,6 @@ void ath_rx_cleanup(struct ath_softc *sc)
bf->bf_mpdu = NULL;
}
}
-
- if (sc->rx.rxdma.dd_desc_len != 0)
- ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf);
}
}
@@ -541,7 +533,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
if (sc->ps_flags & PS_BEACON_SYNC) {
sc->ps_flags &= ~PS_BEACON_SYNC;
ath_dbg(common, PS,
- "Reconfigure Beacon timers based on timestamp from the AP\n");
+ "Reconfigure beacon timers based on synchronized timestamp\n");
ath9k_set_beacon(sc);
}
@@ -1024,6 +1016,134 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
rxs->flag &= ~RX_FLAG_DECRYPTED;
}
+#ifdef CONFIG_ATH9K_DEBUGFS
+static s8 fix_rssi_inv_only(u8 rssi_val)
+{
+ if (rssi_val == 128)
+ rssi_val = 0;
+ return (s8) rssi_val;
+}
+#endif
+
+/* returns 1 if this was a spectral frame, even if not handled. */
+static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
+ struct ath_rx_status *rs, u64 tsf)
+{
+#ifdef CONFIG_ATH9K_DEBUGFS
+ struct ath_hw *ah = sc->sc_ah;
+ u8 bins[SPECTRAL_HT20_NUM_BINS];
+ u8 *vdata = (u8 *)hdr;
+ struct fft_sample_ht20 fft_sample;
+ struct ath_radar_info *radar_info;
+ struct ath_ht20_mag_info *mag_info;
+ int len = rs->rs_datalen;
+ int dc_pos;
+ u16 length, max_magnitude;
+
+ /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
+ * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
+ * yet, but this is supposed to be possible as well.
+ */
+ if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
+ rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
+ rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
+ return 0;
+
+ /* check if spectral scan bit is set. This does not have to be checked
+ * if received through a SPECTRAL phy error, but shouldn't hurt.
+ */
+ radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
+ if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
+ return 0;
+
+ /* Variation in the data length is possible and will be fixed later.
+ * Note that we only support HT20 for now.
+ *
+ * TODO: add HT20_40 support as well.
+ */
+ if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) ||
+ (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1))
+ return 1;
+
+ fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20;
+ length = sizeof(fft_sample) - sizeof(fft_sample.tlv);
+ fft_sample.tlv.length = __cpu_to_be16(length);
+
+ fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
+ fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
+ fft_sample.noise = ah->noise;
+
+ switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) {
+ case 0:
+ /* length correct, nothing to do. */
+ memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS);
+ break;
+ case -1:
+ /* first byte missing, duplicate it. */
+ memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1);
+ bins[0] = vdata[0];
+ break;
+ case 2:
+ /* MAC added 2 extra bytes at bin 30 and 32, remove them. */
+ memcpy(bins, vdata, 30);
+ bins[30] = vdata[31];
+ memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31);
+ break;
+ case 1:
+ /* MAC added 2 extra bytes AND first byte is missing. */
+ bins[0] = vdata[0];
+ memcpy(&bins[0], vdata, 30);
+ bins[31] = vdata[31];
+ memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32);
+ break;
+ default:
+ return 1;
+ }
+
+ /* DC value (value in the middle) is the blind spot of the spectral
+ * sample and invalid, interpolate it.
+ */
+ dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
+ bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
+
+ /* mag data is at the end of the frame, in front of radar_info */
+ mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
+
+ /* copy raw bins without scaling them */
+ memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS);
+ fft_sample.max_exp = mag_info->max_exp & 0xf;
+
+ max_magnitude = spectral_max_magnitude(mag_info->all_bins);
+ fft_sample.max_magnitude = __cpu_to_be16(max_magnitude);
+ fft_sample.max_index = spectral_max_index(mag_info->all_bins);
+ fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins);
+ fft_sample.tsf = __cpu_to_be64(tsf);
+
+ ath_debug_send_fft_sample(sc, &fft_sample.tlv);
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+static void ath9k_apply_ampdu_details(struct ath_softc *sc,
+ struct ath_rx_status *rs, struct ieee80211_rx_status *rxs)
+{
+ if (rs->rs_isaggr) {
+ rxs->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN;
+
+ rxs->ampdu_reference = sc->rx.ampdu_ref;
+
+ if (!rs->rs_moreaggr) {
+ rxs->flag |= RX_FLAG_AMPDU_IS_LAST;
+ sc->rx.ampdu_ref++;
+ }
+
+ if (rs->rs_flags & ATH9K_RX_DELIM_CRC_PRE)
+ rxs->flag |= RX_FLAG_AMPDU_DELIM_CRC_ERROR;
+ }
+}
+
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
{
struct ath_buf *bf;
@@ -1108,6 +1228,13 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
rxs->mactime += 0x100000000ULL;
+ if (rs.rs_status & ATH9K_RXERR_PHY) {
+ if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) {
+ RX_STAT_INC(rx_spectral);
+ goto requeue_drop_frag;
+ }
+ }
+
retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
rxs, &decrypt_error);
if (retval)
@@ -1223,6 +1350,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3)
ath_ant_comb_scan(sc, &rs);
+ ath9k_apply_ampdu_details(sc, &rs, rxs);
+
ieee80211_rx(hw, skb);
requeue_drop_frag:
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index ad3c82c09177..5929850649f0 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -789,6 +789,7 @@
#define AR_SREV_REVISION_9271_11 1
#define AR_SREV_VERSION_9300 0x1c0
#define AR_SREV_REVISION_9300_20 2 /* 2.0 and 2.1 */
+#define AR_SREV_REVISION_9300_22 3
#define AR_SREV_VERSION_9330 0x200
#define AR_SREV_REVISION_9330_10 0
#define AR_SREV_REVISION_9330_11 1
@@ -869,6 +870,9 @@
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
#define AR_SREV_9300_20_OR_LATER(_ah) \
((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300)
+#define AR_SREV_9300_22(_ah) \
+ (AR_SREV_9300(ah) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_22))
#define AR_SREV_9330(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9330))
@@ -884,9 +888,6 @@
#define AR_SREV_9485(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
-#define AR_SREV_9485_10(_ah) \
- (AR_SREV_9485(_ah) && \
- ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_10))
#define AR_SREV_9485_11(_ah) \
(AR_SREV_9485(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11))
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 90e48a0fafe5..89a64411b82e 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -378,7 +378,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf, struct list_head *bf_q,
- struct ath_tx_status *ts, int txok, bool retry)
+ struct ath_tx_status *ts, int txok)
{
struct ath_node *an = NULL;
struct sk_buff *skb;
@@ -490,7 +490,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
} else if (!isaggr && txok) {
/* transmit completion */
acked_cnt++;
- } else if ((tid->state & AGGR_CLEANUP) || !retry) {
+ } else if (tid->state & AGGR_CLEANUP) {
/*
* cleanup in progress, just fail
* the un-acked sub-frames
@@ -604,6 +604,37 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR);
}
+static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
+ return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+}
+
+static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_tx_status *ts, struct ath_buf *bf,
+ struct list_head *bf_head)
+{
+ bool txok, flush;
+
+ txok = !(ts->ts_status & ATH9K_TXERR_MASK);
+ flush = !!(ts->ts_status & ATH9K_TX_FLUSH);
+ txq->axq_tx_inprogress = false;
+
+ txq->axq_depth--;
+ if (bf_is_ampdu_not_probing(bf))
+ txq->axq_ampdu_depth--;
+
+ if (!bf_isampdu(bf)) {
+ if (!flush)
+ ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
+ ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
+ } else
+ ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
+
+ if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !flush)
+ ath_txq_schedule(sc, txq);
+}
+
static bool ath_lookup_legacy(struct ath_buf *bf)
{
struct sk_buff *skb;
@@ -1202,7 +1233,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
* in HT IBSS when a beacon with HT-info is received after the station
* has already been added.
*/
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+ if (sta->ht_cap.ht_supported) {
an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->ht_cap.ampdu_factor);
density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
@@ -1331,23 +1362,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
/* Queue Management */
/********************/
-static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
- struct ath_txq *txq)
-{
- struct ath_atx_ac *ac, *ac_tmp;
- struct ath_atx_tid *tid, *tid_tmp;
-
- list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
- list_del(&ac->list);
- ac->sched = false;
- list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
- list_del(&tid->list);
- tid->sched = false;
- ath_tid_drain(sc, txq, tid);
- }
- }
-}
-
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
{
struct ath_hw *ah = sc->sc_ah;
@@ -1470,14 +1484,8 @@ int ath_cabq_update(struct ath_softc *sc)
return 0;
}
-static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
- return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
-}
-
static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
- struct list_head *list, bool retry_tx)
+ struct list_head *list)
{
struct ath_buf *bf, *lastbf;
struct list_head bf_head;
@@ -1499,16 +1507,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
lastbf = bf->bf_lastbf;
list_cut_position(&bf_head, list, &lastbf->list);
-
- txq->axq_depth--;
- if (bf_is_ampdu_not_probing(bf))
- txq->axq_ampdu_depth--;
-
- if (bf_isampdu(bf))
- ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
- retry_tx);
- else
- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
+ ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
}
}
@@ -1518,7 +1517,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
* This assumes output has been stopped and
* we do not need to block ath_tx_tasklet.
*/
-void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
+void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq)
{
ath_txq_lock(sc, txq);
@@ -1526,8 +1525,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
int idx = txq->txq_tailidx;
while (!list_empty(&txq->txq_fifo[idx])) {
- ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
- retry_tx);
+ ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx]);
INCR(idx, ATH_TXFIFO_DEPTH);
}
@@ -1536,16 +1534,12 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
txq->axq_link = NULL;
txq->axq_tx_inprogress = false;
- ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
-
- /* flush any pending frames if aggregation is enabled */
- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !retry_tx)
- ath_txq_drain_pending_buffers(sc, txq);
+ ath_drain_txq_list(sc, txq, &txq->axq_q);
ath_txq_unlock_complete(sc, txq);
}
-bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
+bool ath_drain_all_txq(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -1581,7 +1575,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
*/
txq = &sc->tx.txq[i];
txq->stopped = false;
- ath_draintxq(sc, txq, retry_tx);
+ ath_draintxq(sc, txq);
}
return !npend;
@@ -1910,8 +1904,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
struct ath_buf *bf;
u8 tidno;
- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && txctl->an &&
- ieee80211_is_data_qos(hdr->frame_control)) {
+ if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) {
tidno = ieee80211_get_qos_ctl(hdr)[0] &
IEEE80211_QOS_CTL_TID_MASK;
tid = ATH_AN_2_TID(txctl->an, tidno);
@@ -2175,28 +2168,6 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
}
-static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_tx_status *ts, struct ath_buf *bf,
- struct list_head *bf_head)
-{
- int txok;
-
- txq->axq_depth--;
- txok = !(ts->ts_status & ATH9K_TXERR_MASK);
- txq->axq_tx_inprogress = false;
- if (bf_is_ampdu_not_probing(bf))
- txq->axq_ampdu_depth--;
-
- if (!bf_isampdu(bf)) {
- ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
- ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
- } else
- ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
-
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
- ath_txq_schedule(sc, txq);
-}
-
static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
{
struct ath_hw *ah = sc->sc_ah;
@@ -2361,8 +2332,8 @@ static int ath_txstatus_setup(struct ath_softc *sc, int size)
u8 txs_len = sc->sc_ah->caps.txs_len;
dd->dd_desc_len = size * txs_len;
- dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
- &dd->dd_desc_paddr, GFP_KERNEL);
+ dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len,
+ &dd->dd_desc_paddr, GFP_KERNEL);
if (!dd->dd_desc)
return -ENOMEM;
@@ -2382,14 +2353,6 @@ static int ath_tx_edma_init(struct ath_softc *sc)
return err;
}
-static void ath_tx_edma_cleanup(struct ath_softc *sc)
-{
- struct ath_descdma *dd = &sc->txsdma;
-
- dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
- dd->dd_desc_paddr);
-}
-
int ath_tx_init(struct ath_softc *sc, int nbufs)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -2402,7 +2365,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
if (error != 0) {
ath_err(common,
"Failed to allocate tx descriptors: %d\n", error);
- goto err;
+ return error;
}
error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
@@ -2410,36 +2373,17 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
if (error != 0) {
ath_err(common,
"Failed to allocate beacon descriptors: %d\n", error);
- goto err;
+ return error;
}
INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
error = ath_tx_edma_init(sc);
- if (error)
- goto err;
- }
-
-err:
- if (error != 0)
- ath_tx_cleanup(sc);
return error;
}
-void ath_tx_cleanup(struct ath_softc *sc)
-{
- if (sc->beacon.bdma.dd_desc_len != 0)
- ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
-
- if (sc->tx.txdma.dd_desc_len != 0)
- ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
-
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
- ath_tx_edma_cleanup(sc);
-}
-
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
{
struct ath_atx_tid *tid;
diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig
index 13a204598766..1a796e5f69ec 100644
--- a/drivers/net/wireless/ath/carl9170/Kconfig
+++ b/drivers/net/wireless/ath/carl9170/Kconfig
@@ -1,6 +1,6 @@
config CARL9170
tristate "Linux Community AR9170 802.11n USB support"
- depends on USB && MAC80211 && EXPERIMENTAL
+ depends on USB && MAC80211
select ATH_COMMON
select FW_LOADER
select CRC32
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index 2df17f1e49ef..25599741cd8a 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -85,20 +85,14 @@ enum carl9170_device_state {
CARL9170_STARTED,
};
-#define CARL9170_NUM_TID 16
#define WME_BA_BMP_SIZE 64
#define CARL9170_TX_USER_RATE_TRIES 3
-#define WME_AC_BE 2
-#define WME_AC_BK 3
-#define WME_AC_VI 1
-#define WME_AC_VO 0
-
#define TID_TO_WME_AC(_tid) \
- ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
- (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
- (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
- WME_AC_VO)
+ ((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE : \
+ (((_tid) == 1) || ((_tid) == 2)) ? IEEE80211_AC_BK : \
+ (((_tid) == 4) || ((_tid) == 5)) ? IEEE80211_AC_VI : \
+ IEEE80211_AC_VO)
#define SEQ_DIFF(_start, _seq) \
(((_start) - (_seq)) & 0x0fff)
@@ -290,6 +284,7 @@ struct ar9170 {
unsigned int rx_size;
unsigned int tx_seq_table;
bool ba_filter;
+ bool disable_offload_fw;
} fw;
/* interface configuration combinations */
@@ -493,8 +488,8 @@ struct carl9170_sta_info {
bool sleeping;
atomic_t pending_frames;
unsigned int ampdu_max_len;
- struct carl9170_sta_tid __rcu *agg[CARL9170_NUM_TID];
- struct carl9170_ba_stats stats[CARL9170_NUM_TID];
+ struct carl9170_sta_tid __rcu *agg[IEEE80211_NUM_TIDS];
+ struct carl9170_ba_stats stats[IEEE80211_NUM_TIDS];
};
struct carl9170_tx_info {
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index 63fd9af3fd39..47d5c2e910ad 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -215,6 +215,24 @@ static int carl9170_fw_tx_sequence(struct ar9170 *ar)
return 0;
}
+static void carl9170_fw_set_if_combinations(struct ar9170 *ar,
+ u16 if_comb_types)
+{
+ if (ar->fw.vif_num < 2)
+ return;
+
+ 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);
+}
+
static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
{
const struct carl9170fw_otus_desc *otus_desc;
@@ -264,7 +282,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
if (!SUPP(CARL9170FW_COMMAND_CAM)) {
dev_info(&ar->udev->dev, "crypto offloading is disabled "
"by firmware.\n");
- ar->disable_offload = true;
+ ar->fw.disable_offload_fw = true;
}
if (SUPP(CARL9170FW_PSM) && SUPP(CARL9170FW_FIXED_5GHZ_PSM))
@@ -345,20 +363,15 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
}
}
- 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);
+ carl9170_fw_set_if_combinations(ar, if_comb_types);
ar->hw->wiphy->interface_modes |= if_comb_types;
- ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ ar->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+ /* As IBSS Encryption is software-based, IBSS RSN is supported. */
+ ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_SUPPORTS_TDLS;
#undef SUPPORTED
return carl9170_fw_tx_sequence(ar);
diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h
index 9443c802b25b..9111d4ffc1b3 100644
--- a/drivers/net/wireless/ath/carl9170/fwcmd.h
+++ b/drivers/net/wireless/ath/carl9170/fwcmd.h
@@ -156,6 +156,14 @@ struct carl9170_psm {
} __packed;
#define CARL9170_PSM_SIZE 4
+/*
+ * Note: If a bit in rx_filter is set, then it
+ * means that the particular frames which matches
+ * the condition are FILTERED/REMOVED/DISCARDED!
+ * (This is can be a bit confusing, especially
+ * because someone people think it's the exact
+ * opposite way, so watch out!)
+ */
struct carl9170_rx_filter_cmd {
__le32 rx_filter;
} __packed;
diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h
index fa834c1460f0..0db874abde50 100644
--- a/drivers/net/wireless/ath/carl9170/hw.h
+++ b/drivers/net/wireless/ath/carl9170/hw.h
@@ -384,7 +384,7 @@
#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_BCN_LENGTH_MAX 256
+#define AR9170_MAC_BCN_LENGTH_MAX (512 - 32)
#define AR9170_MAC_REG_BCN_STATUS (AR9170_MAC_REG_BASE + 0xd8c)
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 25a1e2f4f738..f293b3ff4756 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -358,8 +358,13 @@ static int carl9170_op_start(struct ieee80211_hw *hw)
ar->ps.last_action = jiffies;
ar->ps.last_slept = jiffies;
ar->erp_mode = CARL9170_ERP_AUTO;
- ar->rx_software_decryption = false;
- ar->disable_offload = false;
+
+ /* Set "disable hw crypto offload" whenever the module parameter
+ * nohwcrypt is true or if the firmware does not support it.
+ */
+ ar->disable_offload = modparam_nohwcrypt |
+ ar->fw.disable_offload_fw;
+ ar->rx_software_decryption = ar->disable_offload;
for (i = 0; i < ar->hw->queues; i++) {
ar->queue_stop_timeout[i] = jiffies;
@@ -565,12 +570,28 @@ static int carl9170_init_interface(struct ar9170 *ar,
memcpy(common->macaddr, vif->addr, ETH_ALEN);
- if (modparam_nohwcrypt ||
- ((vif->type != NL80211_IFTYPE_STATION) &&
- (vif->type != NL80211_IFTYPE_AP))) {
- ar->rx_software_decryption = true;
- ar->disable_offload = true;
- }
+ /* We have to fall back to software crypto, whenever
+ * the user choose to participates in an IBSS. HW
+ * offload for IBSS RSN is not supported by this driver.
+ *
+ * NOTE: If the previous main interface has already
+ * disabled hw crypto offload, we have to keep this
+ * previous disable_offload setting as it was.
+ * Altough ideally, we should notify mac80211 and tell
+ * it to forget about any HW crypto offload for now.
+ */
+ ar->disable_offload |= ((vif->type != NL80211_IFTYPE_STATION) &&
+ (vif->type != NL80211_IFTYPE_AP));
+
+ /* While the driver supports HW offload in a single
+ * P2P client configuration, it doesn't support HW
+ * offload in the favourit, concurrent P2P GO+CLIENT
+ * configuration. Hence, HW offload will always be
+ * disabled for P2P.
+ */
+ ar->disable_offload |= vif->p2p;
+
+ ar->rx_software_decryption = ar->disable_offload;
err = carl9170_set_operating_mode(ar);
return err;
@@ -580,7 +601,7 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv;
- struct ieee80211_vif *main_vif;
+ struct ieee80211_vif *main_vif, *old_main = NULL;
struct ar9170 *ar = hw->priv;
int vif_id = -1, err = 0;
@@ -602,6 +623,15 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
goto init;
}
+ /* Because the AR9170 HW's MAC doesn't provide full support for
+ * multiple, independent interfaces [of different operation modes].
+ * We have to select ONE main interface [main mode of HW], but we
+ * can have multiple slaves [AKA: entry in the ACK-table].
+ *
+ * The first (from HEAD/TOP) interface in the ar->vif_list is
+ * always the main intf. All following intfs in this list
+ * are considered to be slave intfs.
+ */
main_vif = carl9170_get_main_vif(ar);
if (main_vif) {
@@ -610,6 +640,18 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_STATION)
break;
+ /* P2P GO [master] use-case
+ * Because the P2P GO station is selected dynamically
+ * by all participating peers of a WIFI Direct network,
+ * the driver has be able to change the main interface
+ * operating mode on the fly.
+ */
+ if (main_vif->p2p && vif->p2p &&
+ vif->type == NL80211_IFTYPE_AP) {
+ old_main = main_vif;
+ break;
+ }
+
err = -EBUSY;
rcu_read_unlock();
@@ -648,14 +690,41 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
vif_priv->id = vif_id;
vif_priv->enable_beacon = false;
ar->vifs++;
- list_add_tail_rcu(&vif_priv->list, &ar->vif_list);
+ if (old_main) {
+ /* We end up in here, if the main interface is being replaced.
+ * Put the new main interface at the HEAD of the list and the
+ * previous inteface will automatically become second in line.
+ */
+ list_add_rcu(&vif_priv->list, &ar->vif_list);
+ } else {
+ /* Add new inteface. If the list is empty, it will become the
+ * main inteface, otherwise it will be slave.
+ */
+ list_add_tail_rcu(&vif_priv->list, &ar->vif_list);
+ }
rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif);
init:
- if (carl9170_get_main_vif(ar) == vif) {
+ main_vif = carl9170_get_main_vif(ar);
+
+ if (main_vif == vif) {
rcu_assign_pointer(ar->beacon_iter, vif_priv);
rcu_read_unlock();
+ if (old_main) {
+ struct carl9170_vif_info *old_main_priv =
+ (void *) old_main->drv_priv;
+ /* downgrade old main intf to slave intf.
+ * NOTE: We are no longer under rcu_read_lock.
+ * But we are still holding ar->mutex, so the
+ * vif data [id, addr] is safe.
+ */
+ err = carl9170_mod_virtual_mac(ar, old_main_priv->id,
+ old_main->addr);
+ if (err)
+ goto unlock;
+ }
+
err = carl9170_init_interface(ar, vif);
if (err)
goto unlock;
@@ -1112,9 +1181,7 @@ static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (ar->disable_offload || !vif)
return -EOPNOTSUPP;
- /*
- * We have to fall back to software encryption, whenever
- * the user choose to participates in an IBSS or is connected
+ /* Fall back to software encryption whenever the driver is connected
* to more than one network.
*
* This is very unfortunate, because some machines cannot handle
@@ -1263,7 +1330,7 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw,
return 0;
}
- for (i = 0; i < CARL9170_NUM_TID; i++)
+ for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++)
RCU_INIT_POINTER(sta_info->agg[i], NULL);
sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
@@ -1287,7 +1354,7 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw,
sta_info->ht_sta = false;
rcu_read_lock();
- for (i = 0; i < CARL9170_NUM_TID; i++) {
+ for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) {
struct carl9170_sta_tid *tid_info;
tid_info = rcu_dereference(sta_info->agg[i]);
@@ -1394,7 +1461,9 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
rcu_read_lock();
tid_info = rcu_dereference(sta_info->agg[tid]);
if (tid_info) {
@@ -1784,7 +1853,7 @@ void *carl9170_alloc(size_t priv_size)
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
- IEEE80211_HW_NEED_DTIM_PERIOD |
+ IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
IEEE80211_HW_SIGNAL_DBM;
if (!modparam_noht) {
@@ -1805,10 +1874,6 @@ void *carl9170_alloc(size_t priv_size)
for (i = 0; i < ARRAY_SIZE(ar->noise); i++)
ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
- hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
- /* As IBSS Encryption is software-based, IBSS RSN is supported. */
- hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
return ar;
err_nomem:
@@ -1916,13 +1981,13 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
return 0;
}
-static int carl9170_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
+static void carl9170_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);
+ ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
}
int carl9170_register(struct ar9170 *ar)
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index ef4ec0da6e49..9c0b150d5b8e 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -1520,35 +1520,92 @@ void carl9170_tx_scheduler(struct ar9170 *ar)
carl9170_tx(ar);
}
-int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
+/* caller has to take rcu_read_lock */
+static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar)
{
- struct sk_buff *skb = NULL;
struct carl9170_vif_info *cvif;
+ int i = 1;
+
+ /* The AR9170 hardware has no fancy beacon queue or some
+ * other scheduling mechanism. So, the driver has to make
+ * due by setting the two beacon timers (pretbtt and tbtt)
+ * once and then swapping the beacon address in the HW's
+ * register file each time the pretbtt fires.
+ */
+
+ cvif = rcu_dereference(ar->beacon_iter);
+ if (ar->vifs > 0 && cvif) {
+ do {
+ list_for_each_entry_continue_rcu(cvif, &ar->vif_list,
+ list) {
+ if (cvif->active && cvif->enable_beacon)
+ goto out;
+ }
+ } while (ar->beacon_enabled && i--);
+ }
+
+out:
+ rcu_assign_pointer(ar->beacon_iter, cvif);
+ return cvif;
+}
+
+static bool carl9170_tx_beacon_physet(struct ar9170 *ar, struct sk_buff *skb,
+ u32 *ht1, u32 *plcp)
+{
struct ieee80211_tx_info *txinfo;
struct ieee80211_tx_rate *rate;
- __le32 *data, *old = NULL;
- unsigned int plcp, power, chains;
- u32 word, ht1, off, addr, len;
- int i = 0, err = 0;
+ unsigned int power, chains;
+ bool ht_rate;
- rcu_read_lock();
- cvif = rcu_dereference(ar->beacon_iter);
-retry:
- if (ar->vifs == 0 || !cvif)
- goto out_unlock;
+ txinfo = IEEE80211_SKB_CB(skb);
+ rate = &txinfo->control.rates[0];
+ ht_rate = !!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS);
+ carl9170_tx_rate_tpc_chains(ar, txinfo, rate, plcp, &power, &chains);
- list_for_each_entry_continue_rcu(cvif, &ar->vif_list, list) {
- if (cvif->active && cvif->enable_beacon)
- goto found;
+ *ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
+ if (chains == AR9170_TX_PHY_TXCHAIN_2)
+ *ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
+ SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, *ht1, 7);
+ SET_VAL(AR9170_MAC_BCN_HT1_TPC, *ht1, power);
+ SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, *ht1, chains);
+
+ if (ht_rate) {
+ *ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
+ if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+ *plcp |= AR9170_MAC_BCN_HT2_SGI;
+
+ if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
+ *ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
+ *plcp |= AR9170_MAC_BCN_HT2_BW40;
+ } else if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
+ *ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
+ *plcp |= AR9170_MAC_BCN_HT2_BW40;
+ }
+
+ SET_VAL(AR9170_MAC_BCN_HT2_LEN, *plcp, skb->len + FCS_LEN);
+ } else {
+ if (*plcp <= AR9170_TX_PHY_RATE_CCK_11M)
+ *plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
+ else
+ *plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
}
- if (!ar->beacon_enabled || i++)
- goto out_unlock;
+ return ht_rate;
+}
- goto retry;
+int carl9170_update_beacon(struct ar9170 *ar, const bool submit)
+{
+ struct sk_buff *skb = NULL;
+ struct carl9170_vif_info *cvif;
+ __le32 *data, *old = NULL;
+ u32 word, ht1, plcp, off, addr, len;
+ int i = 0, err = 0;
+ bool ht_rate;
-found:
- rcu_assign_pointer(ar->beacon_iter, cvif);
+ rcu_read_lock();
+ cvif = carl9170_pick_beaconing_vif(ar);
+ if (!cvif)
+ goto out_unlock;
skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif),
NULL, NULL);
@@ -1558,7 +1615,6 @@ found:
goto err_free;
}
- txinfo = IEEE80211_SKB_CB(skb);
spin_lock_bh(&ar->beacon_lock);
data = (__le32 *)skb->data;
if (cvif->beacon)
@@ -1588,43 +1644,14 @@ found:
goto err_unlock;
}
- ht1 = AR9170_MAC_BCN_HT1_TX_ANT0;
- rate = &txinfo->control.rates[0];
- carl9170_tx_rate_tpc_chains(ar, txinfo, rate, &plcp, &power, &chains);
- if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
- if (plcp <= AR9170_TX_PHY_RATE_CCK_11M)
- plcp |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400;
- else
- plcp |= ((skb->len + FCS_LEN) << 16) + 0x0010;
- } else {
- ht1 |= AR9170_MAC_BCN_HT1_HT_EN;
- if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
- plcp |= AR9170_MAC_BCN_HT2_SGI;
-
- if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
- ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_SHARED;
- plcp |= AR9170_MAC_BCN_HT2_BW40;
- }
- if (rate->flags & IEEE80211_TX_RC_DUP_DATA) {
- ht1 |= AR9170_MAC_BCN_HT1_BWC_40M_DUP;
- plcp |= AR9170_MAC_BCN_HT2_BW40;
- }
-
- SET_VAL(AR9170_MAC_BCN_HT2_LEN, plcp, skb->len + FCS_LEN);
- }
-
- SET_VAL(AR9170_MAC_BCN_HT1_PWR_CTRL, ht1, 7);
- SET_VAL(AR9170_MAC_BCN_HT1_TPC, ht1, power);
- SET_VAL(AR9170_MAC_BCN_HT1_CHAIN_MASK, ht1, chains);
- if (chains == AR9170_TX_PHY_TXCHAIN_2)
- ht1 |= AR9170_MAC_BCN_HT1_TX_ANT1;
+ ht_rate = carl9170_tx_beacon_physet(ar, skb, &ht1, &plcp);
carl9170_async_regwrite_begin(ar);
carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT1, ht1);
- if (!(txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS))
- carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
- else
+ if (ht_rate)
carl9170_async_regwrite(AR9170_MAC_REG_BCN_HT2, plcp);
+ else
+ carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, plcp);
for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
/*
diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h
index 2ec3e9191e4d..2282847d4bb8 100644
--- a/drivers/net/wireless/ath/carl9170/version.h
+++ b/drivers/net/wireless/ath/carl9170/version.h
@@ -1,7 +1,7 @@
#ifndef __CARL9170_SHARED_VERSION_H
#define __CARL9170_SHARED_VERSION_H
#define CARL9170FW_VERSION_YEAR 12
-#define CARL9170FW_VERSION_MONTH 7
-#define CARL9170FW_VERSION_DAY 7
-#define CARL9170FW_VERSION_GIT "1.9.6"
+#define CARL9170FW_VERSION_MONTH 12
+#define CARL9170FW_VERSION_DAY 15
+#define CARL9170FW_VERSION_GIT "1.9.7"
#endif /* __CARL9170_SHARED_VERSION_H */
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index d81698015bf7..ccc4c718f124 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -195,8 +195,6 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
const struct ieee80211_reg_rule *reg_rule;
struct ieee80211_channel *ch;
unsigned int i;
- u32 bandwidth = 0;
- int r;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
@@ -214,11 +212,8 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
- r = freq_reg_info(wiphy,
- ch->center_freq,
- bandwidth,
- &reg_rule);
- if (r)
+ reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ if (IS_ERR(reg_rule))
continue;
/*
* If 11d had a rule for this channel ensure
@@ -254,8 +249,6 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
const struct ieee80211_reg_rule *reg_rule;
- u32 bandwidth = 0;
- int r;
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
if (!sband)
@@ -283,16 +276,16 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/
ch = &sband->channels[11]; /* CH 12 */
- r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
- if (!r) {
+ reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
}
ch = &sband->channels[12]; /* CH 13 */
- r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
- if (!r) {
+ reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
@@ -363,9 +356,9 @@ static u16 ath_regd_find_country_by_name(char *alpha2)
return -1;
}
-int ath_reg_notifier_apply(struct wiphy *wiphy,
- struct regulatory_request *request,
- struct ath_regulatory *reg)
+void ath_reg_notifier_apply(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ struct ath_regulatory *reg)
{
struct ath_common *common = container_of(reg, struct ath_common,
regulatory);
@@ -380,7 +373,7 @@ int ath_reg_notifier_apply(struct wiphy *wiphy,
* any pending requests in the queue.
*/
if (!request)
- return 0;
+ return;
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_CORE:
@@ -416,8 +409,6 @@ int ath_reg_notifier_apply(struct wiphy *wiphy,
break;
}
-
- return 0;
}
EXPORT_SYMBOL(ath_reg_notifier_apply);
@@ -507,8 +498,8 @@ ath_get_regpair(int regdmn)
static int
ath_regd_init_wiphy(struct ath_regulatory *reg,
struct wiphy *wiphy,
- int (*reg_notifier)(struct wiphy *wiphy,
- struct regulatory_request *request))
+ void (*reg_notifier)(struct wiphy *wiphy,
+ struct regulatory_request *request))
{
const struct ieee80211_regdomain *regd;
@@ -628,8 +619,8 @@ static int __ath_regd_init(struct ath_regulatory *reg)
int
ath_regd_init(struct ath_regulatory *reg,
struct wiphy *wiphy,
- int (*reg_notifier)(struct wiphy *wiphy,
- struct regulatory_request *request))
+ void (*reg_notifier)(struct wiphy *wiphy,
+ struct regulatory_request *request))
{
struct ath_common *common = container_of(reg, struct ath_common,
regulatory);
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h
index 03a8268ccf21..37f53bd8fcb1 100644
--- a/drivers/net/wireless/ath/regd.h
+++ b/drivers/net/wireless/ath/regd.h
@@ -252,12 +252,12 @@ enum CountryCode {
bool ath_is_world_regd(struct ath_regulatory *reg);
bool ath_is_49ghz_allowed(u16 redomain);
int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy,
- int (*reg_notifier)(struct wiphy *wiphy,
- struct regulatory_request *request));
+ void (*reg_notifier)(struct wiphy *wiphy,
+ struct regulatory_request *request));
u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
enum ieee80211_band band);
-int ath_reg_notifier_apply(struct wiphy *wiphy,
- struct regulatory_request *request,
- struct ath_regulatory *reg);
+void ath_reg_notifier_apply(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ struct ath_regulatory *reg);
#endif
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 116f4e807ae1..9ecc1968262c 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -204,7 +204,6 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
break;
default:
return -EOPNOTSUPP;
-
}
/* FW don't support scan after connection attempt */
@@ -228,8 +227,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
}
/* 0-based channel indexes */
cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
- wil_dbg(wil, "Scan for ch %d : %d MHz\n", ch,
- request->channels[i]->center_freq);
+ wil_dbg_misc(wil, "Scan for ch %d : %d MHz\n", ch,
+ request->channels[i]->center_freq);
}
return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
@@ -342,7 +341,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
}
out:
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
return rc;
}
@@ -425,8 +424,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
return -EINVAL;
}
- wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
- channel->center_freq, info->privacy ? "secure" : "open");
+ wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
+ channel->center_freq, info->privacy ? "secure" : "open");
print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
info->ssid, info->ssid_len);
diff --git a/drivers/net/wireless/ath/wil6210/dbg_hexdump.h b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h
index 6a315ba5aa7d..e5712f026c47 100644
--- a/drivers/net/wireless/ath/wil6210/dbg_hexdump.h
+++ b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h
@@ -1,25 +1,15 @@
#ifndef WIL_DBG_HEXDUMP_H_
#define WIL_DBG_HEXDUMP_H_
-#if defined(CONFIG_DYNAMIC_DEBUG)
-#define wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \
- groupsize, buf, len, ascii) \
-do { \
- DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, \
- __builtin_constant_p(prefix_str) ? prefix_str : "hexdump");\
- if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \
- print_hex_dump(KERN_DEBUG, prefix_str, \
- prefix_type, rowsize, groupsize, \
- buf, len, ascii); \
-} while (0)
+#include <linux/printk.h>
+#include <linux/dynamic_debug.h>
+#if defined(CONFIG_DYNAMIC_DEBUG)
#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
- wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \
+ dynamic_hex_dump(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii)
-#define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \
- wil_dynamic_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true)
#else /* defined(CONFIG_DYNAMIC_DEBUG) */
#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 38049da71049..dc97e7b2609c 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -38,7 +38,9 @@
#define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE
#define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \
BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
-#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT)
+#define WIL6210_IMC_MISC (ISR_MISC_FW_READY | \
+ ISR_MISC_MBOX_EVT | \
+ ISR_MISC_FW_ERROR)
#define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \
BIT_DMA_PSEUDO_CAUSE_TX | \
@@ -50,7 +52,6 @@
static inline void wil_icr_clear(u32 x, void __iomem *addr)
{
-
}
#else /* defined(CONFIG_WIL6210_ISR_COR) */
/* configure to Write-1-to-Clear mode */
@@ -94,7 +95,7 @@ static void wil6210_mask_irq_misc(struct wil6210_priv *wil)
static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
{
- wil_dbg_IRQ(wil, "%s()\n", __func__);
+ wil_dbg_irq(wil, "%s()\n", __func__);
iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
@@ -125,7 +126,7 @@ static void wil6210_unmask_irq_misc(struct wil6210_priv *wil)
static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
{
- wil_dbg_IRQ(wil, "%s()\n", __func__);
+ wil_dbg_irq(wil, "%s()\n", __func__);
set_bit(wil_status_irqen, &wil->status);
@@ -135,7 +136,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
void wil6210_disable_irq(struct wil6210_priv *wil)
{
- wil_dbg_IRQ(wil, "%s()\n", __func__);
+ wil_dbg_irq(wil, "%s()\n", __func__);
wil6210_mask_irq_tx(wil);
wil6210_mask_irq_rx(wil);
@@ -145,7 +146,7 @@ void wil6210_disable_irq(struct wil6210_priv *wil)
void wil6210_enable_irq(struct wil6210_priv *wil)
{
- wil_dbg_IRQ(wil, "%s()\n", __func__);
+ wil_dbg_irq(wil, "%s()\n", __func__);
iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICC));
@@ -167,7 +168,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICR));
- wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr);
+ wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
if (!isr) {
wil_err(wil, "spurious IRQ: RX\n");
@@ -177,7 +178,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
wil6210_mask_irq_rx(wil);
if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
- wil_dbg_IRQ(wil, "RX done\n");
+ wil_dbg_irq(wil, "RX done\n");
isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
wil_rx_handle(wil);
}
@@ -197,7 +198,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
HOSTADDR(RGF_DMA_EP_TX_ICR) +
offsetof(struct RGF_ICR, ICR));
- wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr);
+ wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
if (!isr) {
wil_err(wil, "spurious IRQ: TX\n");
@@ -208,13 +209,13 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
uint i;
- wil_dbg_IRQ(wil, "TX done\n");
+ wil_dbg_irq(wil, "TX done\n");
isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
for (i = 0; i < 24; i++) {
u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i);
if (isr & mask) {
isr &= ~mask;
- wil_dbg_IRQ(wil, "TX done(%i)\n", i);
+ wil_dbg_irq(wil, "TX done(%i)\n", i);
wil_tx_complete(wil, i);
}
}
@@ -228,6 +229,17 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
return IRQ_HANDLED;
}
+static void wil_notify_fw_error(struct wil6210_priv *wil)
+{
+ struct device *dev = &wil_to_ndev(wil)->dev;
+ char *envp[3] = {
+ [0] = "SOURCE=wil6210",
+ [1] = "EVENT=FW_ERROR",
+ [2] = NULL,
+ };
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+}
+
static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
@@ -235,7 +247,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICR));
- wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr);
+ wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr);
if (!isr) {
wil_err(wil, "spurious IRQ: MISC\n");
@@ -244,8 +256,15 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
wil6210_mask_irq_misc(wil);
+ if (isr & ISR_MISC_FW_ERROR) {
+ wil_dbg_irq(wil, "IRQ: Firmware error\n");
+ clear_bit(wil_status_fwready, &wil->status);
+ wil_notify_fw_error(wil);
+ isr &= ~ISR_MISC_FW_ERROR;
+ }
+
if (isr & ISR_MISC_FW_READY) {
- wil_dbg_IRQ(wil, "IRQ: FW ready\n");
+ wil_dbg_irq(wil, "IRQ: FW ready\n");
/**
* Actual FW ready indicated by the
* WMI_FW_READY_EVENTID
@@ -268,10 +287,10 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
struct wil6210_priv *wil = cookie;
u32 isr = wil->isr_misc;
- wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr);
+ wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
if (isr & ISR_MISC_MBOX_EVT) {
- wil_dbg_IRQ(wil, "MBOX event\n");
+ wil_dbg_irq(wil, "MBOX event\n");
wmi_recv_cmd(wil);
isr &= ~ISR_MISC_MBOX_EVT;
}
@@ -293,7 +312,7 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
- wil_dbg_IRQ(wil, "Thread IRQ\n");
+ wil_dbg_irq(wil, "Thread IRQ\n");
/* Discover real IRQ cause */
if (wil->isr_misc)
wil6210_irq_misc_thread(irq, cookie);
@@ -370,6 +389,8 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie)
if (wil6210_debug_irq_mask(wil, pseudo_cause))
return IRQ_NONE;
+ wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause);
+
wil6210_mask_irq_pseudo(wil);
/* Discover real IRQ cause
@@ -401,8 +422,6 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie)
if (rc != IRQ_WAKE_THREAD)
wil6210_unmask_irq_pseudo(wil);
- wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause);
-
return rc;
}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 95fcd361322b..761c389586d4 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -64,7 +64,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
- wil_dbg(wil, "%s()\n", __func__);
+ wil_dbg_misc(wil, "%s()\n", __func__);
wil_link_off(wil);
clear_bit(wil_status_fwconnected, &wil->status);
@@ -80,11 +80,13 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
GFP_KERNEL);
break;
default:
- ;
+ break;
}
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
wil_vring_fini_tx(wil, i);
+
+ clear_bit(wil_status_dontscan, &wil->status);
}
static void wil_disconnect_worker(struct work_struct *work)
@@ -99,7 +101,7 @@ static void wil_connect_timer_fn(ulong x)
{
struct wil6210_priv *wil = (void *)x;
- wil_dbg(wil, "Connect timeout\n");
+ wil_dbg_misc(wil, "Connect timeout\n");
/* reschedule to thread context - disconnect won't
* run from atomic context
@@ -107,9 +109,18 @@ static void wil_connect_timer_fn(ulong x)
schedule_work(&wil->disconnect_worker);
}
+static void wil_cache_mbox_regs(struct wil6210_priv *wil)
+{
+ /* make shadow copy of registers that should not change on run time */
+ wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
+ sizeof(struct wil6210_mbox_ctl));
+ wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
+ wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+}
+
int wil_priv_init(struct wil6210_priv *wil)
{
- wil_dbg(wil, "%s()\n", __func__);
+ wil_dbg_misc(wil, "%s()\n", __func__);
mutex_init(&wil->mutex);
mutex_init(&wil->wmi_mutex);
@@ -136,11 +147,7 @@ int wil_priv_init(struct wil6210_priv *wil)
return -EAGAIN;
}
- /* make shadow copy of registers that should not change on run time */
- wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
- sizeof(struct wil6210_mbox_ctl));
- wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
- wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+ wil_cache_mbox_regs(wil);
return 0;
}
@@ -162,7 +169,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
static void wil_target_reset(struct wil6210_priv *wil)
{
- wil_dbg(wil, "Resetting...\n");
+ wil_dbg_misc(wil, "Resetting...\n");
/* register write */
#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
@@ -202,7 +209,7 @@ static void wil_target_reset(struct wil6210_priv *wil)
msleep(2000);
- wil_dbg(wil, "Reset completed\n");
+ wil_dbg_misc(wil, "Reset completed\n");
#undef W
#undef S
@@ -225,8 +232,8 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
wil_err(wil, "Firmware not ready\n");
return -ETIME;
} else {
- wil_dbg(wil, "FW ready after %d ms\n",
- jiffies_to_msecs(to-left));
+ wil_dbg_misc(wil, "FW ready after %d ms\n",
+ jiffies_to_msecs(to-left));
}
return 0;
}
@@ -243,13 +250,13 @@ int wil_reset(struct wil6210_priv *wil)
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL);
+ wil6210_disable_irq(wil);
+ wil->status = 0;
+
wmi_event_flush(wil);
- flush_workqueue(wil->wmi_wq);
flush_workqueue(wil->wmi_wq_conn);
-
- wil6210_disable_irq(wil);
- wil->status = 0;
+ flush_workqueue(wil->wmi_wq);
/* TODO: put MAC in reset */
wil_target_reset(wil);
@@ -258,11 +265,7 @@ int wil_reset(struct wil6210_priv *wil)
wil->pending_connect_cid = -1;
INIT_COMPLETION(wil->wmi_ready);
- /* make shadow copy of registers that should not change on run time */
- wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
- sizeof(struct wil6210_mbox_ctl));
- wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
- wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+ wil_cache_mbox_regs(wil);
/* TODO: release MAC reset */
wil6210_enable_irq(wil);
@@ -278,7 +281,7 @@ void wil_link_on(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
- wil_dbg(wil, "%s()\n", __func__);
+ wil_dbg_misc(wil, "%s()\n", __func__);
netif_carrier_on(ndev);
netif_tx_wake_all_queues(ndev);
@@ -288,7 +291,7 @@ void wil_link_off(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
- wil_dbg(wil, "%s()\n", __func__);
+ wil_dbg_misc(wil, "%s()\n", __func__);
netif_tx_stop_all_queues(ndev);
netif_carrier_off(ndev);
@@ -311,27 +314,27 @@ static int __wil_up(struct wil6210_priv *wil)
wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC);
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
- wil_dbg(wil, "type: STATION\n");
+ wil_dbg_misc(wil, "type: STATION\n");
bi = 0;
ndev->type = ARPHRD_ETHER;
break;
case NL80211_IFTYPE_AP:
- wil_dbg(wil, "type: AP\n");
+ wil_dbg_misc(wil, "type: AP\n");
bi = 100;
ndev->type = ARPHRD_ETHER;
break;
case NL80211_IFTYPE_P2P_CLIENT:
- wil_dbg(wil, "type: P2P_CLIENT\n");
+ wil_dbg_misc(wil, "type: P2P_CLIENT\n");
bi = 0;
ndev->type = ARPHRD_ETHER;
break;
case NL80211_IFTYPE_P2P_GO:
- wil_dbg(wil, "type: P2P_GO\n");
+ wil_dbg_misc(wil, "type: P2P_GO\n");
bi = 100;
ndev->type = ARPHRD_ETHER;
break;
case NL80211_IFTYPE_MONITOR:
- wil_dbg(wil, "type: Monitor\n");
+ wil_dbg_misc(wil, "type: Monitor\n");
bi = 0;
ndev->type = ARPHRD_IEEE80211_RADIOTAP;
/* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
@@ -354,7 +357,7 @@ static int __wil_up(struct wil6210_priv *wil)
wmi_set_channel(wil, channel->hw_value);
break;
default:
- ;
+ break;
}
/* MAC address - pre-requisite for other commands */
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 3068b5cb53a7..8ce2e33dce20 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -35,37 +35,12 @@ static int wil_stop(struct net_device *ndev)
return wil_down(wil);
}
-/*
- * AC to queue mapping
- *
- * AC_VO -> queue 3
- * AC_VI -> queue 2
- * AC_BE -> queue 1
- * AC_BK -> queue 0
- */
-static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb)
-{
- static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
- struct wil6210_priv *wil = ndev_to_wil(ndev);
- u16 rc;
-
- skb->priority = cfg80211_classify8021d(skb);
-
- rc = wil_1d_to_queue[skb->priority];
-
- wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority,
- (int)rc);
-
- return rc;
-}
-
static const struct net_device_ops wil_netdev_ops = {
.ndo_open = wil_open,
.ndo_stop = wil_stop,
.ndo_start_xmit = wil_start_xmit,
- .ndo_select_queue = wil_select_queue,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
};
void *wil_if_alloc(struct device *dev, void __iomem *csr)
@@ -97,7 +72,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
- ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1);
+ ndev = alloc_netdev(0, "wlan%d", ether_setup);
if (!ndev) {
dev_err(dev, "alloc_netdev_mqs failed\n");
rc = -ENOMEM;
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 0fc83edd6bad..81c35c6e3832 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -53,7 +53,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
}
wil->n_msi = use_msi;
if (wil->n_msi) {
- wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi);
+ wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi);
rc = pci_enable_msi_block(pdev, wil->n_msi);
if (rc && (wil->n_msi == 3)) {
wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
@@ -65,7 +65,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
wil->n_msi = 0;
}
} else {
- wil_dbg(wil, "MSI interrupts disabled, use INTx\n");
+ wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
}
rc = wil6210_init_irq(wil, pdev->irq);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index f29c294413cf..d1315b442375 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -74,8 +74,6 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
vring->swtail = 0;
vring->ctx = kzalloc(vring->size * sizeof(vring->ctx[0]), GFP_KERNEL);
if (!vring->ctx) {
- wil_err(wil, "vring_alloc [%d] failed to alloc ctx mem\n",
- vring->size);
vring->va = NULL;
return -ENOMEM;
}
@@ -100,8 +98,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
d->dma.status = TX_DMA_STATUS_DU;
}
- wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size,
- vring->va, (unsigned long long)vring->pa, vring->ctx);
+ wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size,
+ vring->va, (unsigned long long)vring->pa, vring->ctx);
return 0;
}
@@ -353,8 +351,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
wil_rx_add_radiotap_header(wil, skb, d);
- wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length);
- wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4,
+ wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length);
+ wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);
wil_vring_advance_head(vring, 1);
@@ -369,7 +367,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
*/
ftype = wil_rxdesc_ftype(d) << 2;
if (ftype != IEEE80211_FTYPE_DATA) {
- wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype);
+ wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype);
/* TODO: process it */
kfree_skb(skb);
return NULL;
@@ -430,6 +428,8 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
int rc;
unsigned int len = skb->len;
+ skb_orphan(skb);
+
if (in_interrupt())
rc = netif_rx(skb);
else
@@ -459,13 +459,11 @@ void wil_rx_handle(struct wil6210_priv *wil)
wil_err(wil, "Rx IRQ while Rx not yet initialized\n");
return;
}
- wil_dbg_TXRX(wil, "%s()\n", __func__);
+ wil_dbg_txrx(wil, "%s()\n", __func__);
while (NULL != (skb = wil_vring_reap_rx(wil, v))) {
- wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
+ wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb_headlen(skb), false);
- skb_orphan(skb);
-
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
skb->dev = ndev;
skb_reset_mac_header(skb);
@@ -484,53 +482,18 @@ void wil_rx_handle(struct wil6210_priv *wil)
int wil_rx_init(struct wil6210_priv *wil)
{
- struct net_device *ndev = wil_to_ndev(wil);
- struct wireless_dev *wdev = wil->wdev;
struct vring *vring = &wil->vring_rx;
int rc;
- struct wmi_cfg_rx_chain_cmd cmd = {
- .action = WMI_RX_CHAIN_ADD,
- .rx_sw_ring = {
- .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
- },
- .mid = 0, /* TODO - what is it? */
- .decap_trans_type = WMI_DECAP_TYPE_802_3,
- };
- struct {
- struct wil6210_mbox_hdr_wmi wmi;
- struct wmi_cfg_rx_chain_done_event evt;
- } __packed evt;
vring->size = WIL6210_RX_RING_SIZE;
rc = wil_vring_alloc(wil, vring);
if (rc)
return rc;
- cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
- cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size);
- if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
- struct ieee80211_channel *ch = wdev->preset_chandef.chan;
-
- cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
- if (ch)
- cmd.sniffer_cfg.channel = ch->hw_value - 1;
- cmd.sniffer_cfg.phy_info_mode =
- cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
- cmd.sniffer_cfg.phy_support =
- cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
- ? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
- }
- /* typical time for secure PCP is 840ms */
- rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
- WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
+ rc = wmi_rx_chain_add(wil, vring);
if (rc)
goto err_free;
- vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
-
- wil_dbg(wil, "Rx init: status %d tail 0x%08x\n",
- le32_to_cpu(evt.evt.status), vring->hwtail);
-
rc = wil_rx_refill(wil, vring->size);
if (rc)
goto err_free;
@@ -546,25 +509,8 @@ void wil_rx_fini(struct wil6210_priv *wil)
{
struct vring *vring = &wil->vring_rx;
- if (vring->va) {
- int rc;
- struct wmi_cfg_rx_chain_cmd cmd = {
- .action = cpu_to_le32(WMI_RX_CHAIN_DEL),
- .rx_sw_ring = {
- .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
- },
- };
- struct {
- struct wil6210_mbox_hdr_wmi wmi;
- struct wmi_cfg_rx_chain_done_event cfg;
- } __packed wmi_rx_cfg_reply;
-
- rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
- WMI_CFG_RX_CHAIN_DONE_EVENTID,
- &wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply),
- 100);
+ if (vring->va)
wil_vring_free(wil, vring, 0);
- }
}
int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
@@ -617,6 +563,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) {
wil_err(wil, "Tx config failed, status 0x%02x\n",
reply.cmd.status);
+ rc = -EINVAL;
goto out_free;
}
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
@@ -689,7 +636,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
uint i = swhead;
dma_addr_t pa;
- wil_dbg_TXRX(wil, "%s()\n", __func__);
+ wil_dbg_txrx(wil, "%s()\n", __func__);
if (avail < vring->size/8)
netif_tx_stop_all_queues(wil_to_ndev(wil));
@@ -706,9 +653,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
pa = dma_map_single(dev, skb->data,
skb_headlen(skb), DMA_TO_DEVICE);
- wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb),
+ wil_dbg_txrx(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb),
skb->data, (unsigned long long)pa);
- wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1,
+ wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb_headlen(skb), false);
if (unlikely(dma_mapping_error(dev, pa)))
@@ -737,12 +684,12 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS);
- wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4,
+ wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);
/* advance swhead */
wil_vring_advance_head(vring, nr_frags + 1);
- wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
+ wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail));
/* hold reference to skb
* to prevent skb release before accounting
@@ -775,7 +722,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
struct vring *vring;
int rc;
- wil_dbg_TXRX(wil, "%s()\n", __func__);
+ wil_dbg_txrx(wil, "%s()\n", __func__);
if (!test_bit(wil_status_fwready, &wil->status)) {
wil_err(wil, "FW not ready\n");
goto drop;
@@ -802,15 +749,13 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
switch (rc) {
case 0:
- ndev->stats.tx_packets++;
- ndev->stats.tx_bytes += skb->len;
+ /* statistics will be updated on the tx_complete */
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
case -ENOMEM:
return NETDEV_TX_BUSY;
default:
- ; /* goto drop; */
- break;
+ break; /* goto drop; */
}
drop:
netif_tx_stop_all_queues(ndev);
@@ -827,6 +772,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
void wil_tx_complete(struct wil6210_priv *wil, int ringid)
{
+ struct net_device *ndev = wil_to_ndev(wil);
struct device *dev = wil_to_dev(wil);
struct vring *vring = &wil->vring_tx[ringid];
@@ -835,7 +781,7 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid)
return;
}
- wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid);
+ wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid);
while (!wil_vring_is_empty(vring)) {
volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx;
@@ -844,16 +790,23 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid)
if (!(d->dma.status & TX_DMA_STATUS_DU))
break;
- wil_dbg_TXRX(wil,
+ wil_dbg_txrx(wil,
"Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
vring->swtail, d->dma.length, d->dma.status,
d->dma.error);
- wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4,
+ wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);
pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
skb = vring->ctx[vring->swtail];
if (skb) {
+ if (d->dma.error == 0) {
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
+ } else {
+ ndev->stats.tx_errors++;
+ }
+
dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
vring->ctx[vring->swtail] = NULL;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 9bcfffa4006c..aea961ff8f08 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -36,8 +36,6 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL6210_MEM_SIZE (2*1024*1024UL)
-#define WIL6210_TX_QUEUES (4)
-
#define WIL6210_RX_RING_SIZE (128)
#define WIL6210_TX_RING_SIZE (128)
#define WIL6210_MAX_TX_RINGS (24)
@@ -101,8 +99,7 @@ struct RGF_ICR {
#define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */
#define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0)
#define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1)
- #define BIT_DMA_EP_MISC_ICR_FW_INT0 BIT(28)
- #define BIT_DMA_EP_MISC_ICR_FW_INT1 BIT(29)
+ #define BIT_DMA_EP_MISC_ICR_FW_INT(n) BIT(28+n) /* n = [0..3] */
/* Interrupt moderation control */
#define RGF_DMA_ITR_CNT_TRSH (0x881c5c)
@@ -121,8 +118,9 @@ struct RGF_ICR {
#define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2
/* ISR register bits */
-#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0
-#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1
+#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT(0)
+#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT(1)
+#define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3)
/* Hardware definitions end */
@@ -272,17 +270,18 @@ struct wil6210_priv {
#define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg)
#define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg)
-#define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg)
-#define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)
-#define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
+#define wil_dbg_irq(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg)
+#define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)
+#define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
+#define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg)
-#define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize, \
+#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\
prefix_type, rowsize, \
groupsize, buf, len, ascii)
-#define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize, \
+#define wil_hex_dump_wmi(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\
prefix_type, rowsize, \
@@ -328,6 +327,7 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
const void *mac_addr, int key_len, const void *key);
int wmi_echo(struct wil6210_priv *wil);
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
+int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 12915f6e7617..0bb3b76b4b58 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -18,8 +18,10 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
#include "wil6210.h"
+#include "txrx.h"
#include "wmi.h"
/**
@@ -186,7 +188,6 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
(int)(sizeof(cmd) + len), r->entry_size);
return -ERANGE;
-
}
might_sleep();
@@ -213,7 +214,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
}
/* next head */
next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
- wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
+ wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
/* wait till FW finish with previous command */
for (retry = 5; retry > 0; retry--) {
r->tail = ioread32(wil->csr + HOST_MBOX +
@@ -234,10 +235,10 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
}
cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
/* set command */
- wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
- wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
+ wil_dbg_wmi(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
+ wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
sizeof(cmd), true);
- wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
+ wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
len, true);
wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
@@ -273,7 +274,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
struct wmi_ready_event *evt = d;
u32 ver = le32_to_cpu(evt->sw_version);
- wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac);
+ wil_dbg_wmi(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac);
if (!is_valid_ether_addr(ndev->dev_addr)) {
memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
@@ -286,7 +287,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
int len)
{
- wil_dbg_WMI(wil, "WMI: FW ready\n");
+ wil_dbg_wmi(wil, "WMI: FW ready\n");
set_bit(wil_status_fwready, &wil->status);
/* reuse wmi_ready for the firmware ready indication */
@@ -309,11 +310,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
u32 d_len = le32_to_cpu(data->info.len);
u16 d_status = le16_to_cpu(data->info.status);
- wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n",
+ wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n",
data->info.channel, data->info.mcs, data->info.snr);
- wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len,
+ wil_dbg_wmi(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len,
le16_to_cpu(data->info.stype));
- wil_dbg_WMI(wil, "qid %d mid %d cid %d\n",
+ wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
data->info.qid, data->info.mid, data->info.cid);
if (!channel) {
@@ -329,15 +330,15 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
u.beacon.variable);
- wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap);
+ wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid,
tsf, cap, bi, ie_buf, ie_len,
signal, GFP_KERNEL);
if (bss) {
- wil_dbg_WMI(wil, "Added BSS %pM\n",
+ wil_dbg_wmi(wil, "Added BSS %pM\n",
rx_mgmt_frame->bssid);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
} else {
wil_err(wil, "cfg80211_inform_bss() failed\n");
}
@@ -351,7 +352,7 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
struct wmi_scan_complete_event *data = d;
bool aborted = (data->status != 0);
- wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
+ wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
cfg80211_scan_done(wil->scan_request, aborted);
wil->scan_request = NULL;
} else {
@@ -386,9 +387,9 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
return;
}
ch = evt->channel + 1;
- wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n",
+ wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
evt->bssid, ch, evt->cid);
- wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
+ wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
evt->assoc_info, len - sizeof(*evt), true);
/* figure out IE's */
@@ -450,14 +451,13 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
{
struct wmi_disconnect_event *evt = d;
- wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n",
+ wil_dbg_wmi(wil, "Disconnect %pM reason %d proto %d wmi\n",
evt->bssid,
evt->protocol_reason_status, evt->disconnect_reason);
wil->sinfo_gen++;
wil6210_disconnect(wil, evt->bssid);
- clear_bit(wil_status_dontscan, &wil->status);
}
static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
@@ -476,7 +476,7 @@ static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
- wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n"
+ wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
"BF status 0x%08x SNR 0x%08x\n"
"Tx Tpt %d goodput %d Rx goodput %d\n"
"Sectors(rx:tx) my %d:%d peer %d:%d\n",
@@ -501,7 +501,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
struct sk_buff *skb;
struct ethhdr *eth;
- wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len,
+ wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
evt->src_mac);
if (eapol_len > 196) { /* TODO: revisit size limit */
@@ -587,11 +587,9 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
event.wmi) + len, 4),
GFP_KERNEL);
- if (!evt) {
- wil_err(wil, "kmalloc for WMI event (%d) failed\n",
- len);
+ if (!evt)
return;
- }
+
evt->event.hdr = hdr;
cmd = (void *)&evt->event.wmi;
wil_memcpy_fromio_32(cmd, src, len);
@@ -599,15 +597,15 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
iowrite32(0, wil->csr + HOSTADDR(r->tail) +
offsetof(struct wil6210_mbox_ring_desc, sync));
/* indicate */
- wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n",
+ wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n",
le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
hdr.flags);
if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
(len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
- wil_dbg_WMI(wil, "WMI event 0x%04x\n",
+ wil_dbg_wmi(wil, "WMI event 0x%04x\n",
evt->event.wmi.id);
}
- wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1,
+ wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
&evt->event.hdr, sizeof(hdr) + len, true);
/* advance tail */
@@ -623,7 +621,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
{
int q = queue_work(wil->wmi_wq,
&wil->wmi_event_worker);
- wil_dbg_WMI(wil, "queue_work -> %d\n", q);
+ wil_dbg_wmi(wil, "queue_work -> %d\n", q);
}
}
}
@@ -650,7 +648,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
cmdid, reply_id, to_msec);
rc = -ETIME;
} else {
- wil_dbg_WMI(wil,
+ wil_dbg_wmi(wil,
"wmi_call(0x%04x->0x%04x) completed in %d msec\n",
cmdid, reply_id,
to_msec - jiffies_to_msecs(remain));
@@ -680,7 +678,7 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
memcpy(cmd.mac, addr, ETH_ALEN);
- wil_dbg_WMI(wil, "Set MAC %pM\n", addr);
+ wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
}
@@ -778,7 +776,7 @@ int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb)
skb_set_mac_header(skb, 0);
eth = eth_hdr(skb);
- wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest);
+ wil_dbg_wmi(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest);
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0)
goto found_dest;
@@ -838,10 +836,8 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
int rc;
u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
- if (!cmd) {
- wil_err(wil, "kmalloc(%d) failed\n", len);
+ if (!cmd)
return -ENOMEM;
- }
cmd->mgmt_frm_type = type;
/* BUG: FW API define ieLen as u8. Will fix FW */
@@ -853,11 +849,60 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
return rc;
}
+int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
+{
+ struct wireless_dev *wdev = wil->wdev;
+ struct net_device *ndev = wil_to_ndev(wil);
+ struct wmi_cfg_rx_chain_cmd cmd = {
+ .action = WMI_RX_CHAIN_ADD,
+ .rx_sw_ring = {
+ .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
+ .ring_mem_base = cpu_to_le64(vring->pa),
+ .ring_size = cpu_to_le16(vring->size),
+ },
+ .mid = 0, /* TODO - what is it? */
+ .decap_trans_type = WMI_DECAP_TYPE_802_3,
+ };
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_cfg_rx_chain_done_event evt;
+ } __packed evt;
+ int rc;
+
+ if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
+ struct ieee80211_channel *ch = wdev->preset_chandef.chan;
+
+ cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
+ if (ch)
+ cmd.sniffer_cfg.channel = ch->hw_value - 1;
+ cmd.sniffer_cfg.phy_info_mode =
+ cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
+ cmd.sniffer_cfg.phy_support =
+ cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
+ ? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
+ }
+ /* typical time for secure PCP is 840ms */
+ rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
+ WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
+ if (rc)
+ return rc;
+
+ vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
+
+ wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n",
+ le32_to_cpu(evt.evt.status), vring->hwtail);
+
+ if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS)
+ rc = -EINVAL;
+
+ return rc;
+}
+
void wmi_event_flush(struct wil6210_priv *wil)
{
struct pending_wmi_event *evt, *t;
- wil_dbg_WMI(wil, "%s()\n", __func__);
+ wil_dbg_wmi(wil, "%s()\n", __func__);
list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
list_del(&evt->list);
@@ -899,7 +944,7 @@ static void wmi_event_handle(struct wil6210_priv *wil,
wmi_evt_call_handler(wil, id, evt_data,
len - sizeof(*wmi));
}
- wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id);
+ wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
complete(&wil->wmi_ready);
return;
}
@@ -964,7 +1009,7 @@ void wmi_connect_worker(struct work_struct *work)
return;
}
- wil_dbg_WMI(wil, "Configure for connection CID %d\n",
+ wil_dbg_wmi(wil, "Configure for connection CID %d\n",
wil->pending_connect_cid);
rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE,
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index ded03d226a71..b42930f457c2 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -79,10 +79,9 @@ static int atmel_probe(struct pcmcia_device *p_dev)
/* Allocate space for private device-specific data */
local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
- if (!local) {
- printk(KERN_ERR "atmel_cs: no memory for new device\n");
+ if (!local)
return -ENOMEM;
- }
+
p_dev->priv = local;
return atmel_config(p_dev);
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 7a28d21ac389..287c6b670a36 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -78,8 +78,8 @@ config B43_PCMCIA
If unsure, say N.
config B43_SDIO
- bool "Broadcom 43xx SDIO device support (EXPERIMENTAL)"
- depends on B43 && SSB_SDIOHOST_POSSIBLE && EXPERIMENTAL
+ bool "Broadcom 43xx SDIO device support"
+ depends on B43 && SSB_SDIOHOST_POSSIBLE
select SSB_SDIOHOST
---help---
Broadcom 43xx device support for Soft-MAC SDIO devices.
@@ -109,8 +109,8 @@ config B43_PIO
default y
config B43_PHY_N
- bool "Support for 802.11n (N-PHY) devices (EXPERIMENTAL)"
- depends on B43 && EXPERIMENTAL
+ bool "Support for 802.11n (N-PHY) devices"
+ depends on B43
---help---
Support for the N-PHY.
@@ -130,8 +130,8 @@ config B43_PHY_LP
(802.11a support is optional, and currently disabled).
config B43_PHY_HT
- bool "Support for HT-PHY (high throughput) devices (EXPERIMENTAL)"
- depends on B43 && EXPERIMENTAL
+ bool "Support for HT-PHY (high throughput) devices"
+ depends on B43
---help---
Support for the HT-PHY.
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index 315b96ed1d90..9fdd1983079c 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -169,7 +169,7 @@ struct b43_dmadesc_generic {
/* DMA engine tuning knobs */
#define B43_TXRING_SLOTS 256
-#define B43_RXRING_SLOTS 64
+#define B43_RXRING_SLOTS 256
#define B43_DMA0_RX_FW598_BUFSIZE (B43_DMA0_RX_FW598_FO + IEEE80211_MAX_FRAME_LEN)
#define B43_DMA0_RX_FW351_BUFSIZE (B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN)
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index 97d4e27bf36f..aaca60c6f575 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -3226,8 +3226,6 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
{
struct nphy_gain_ctl_workaround_entry *e;
u8 phy_idx;
- u8 tr_iso = ghz5 ? dev->dev->bus_sprom->fem.ghz5.tr_iso :
- dev->dev->bus_sprom->fem.ghz2.tr_iso;
if (!ghz5 && dev->phy.rev >= 6 && dev->phy.radio_rev == 11)
return &nphy_gain_ctl_wa_phy6_radio11_ghz2;
@@ -3249,6 +3247,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
!b43_channel_type_is_40mhz(dev->phy.channel_type))
e->cliplo_gain = 0x2d;
} else if (!ghz5 && dev->phy.rev >= 5) {
+ static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a,
+ 0x106c, 0x1074, 0x107c, 0x207c};
+ u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso;
+
if (ext_lna) {
e->rfseq_init[0] &= ~0x4000;
e->rfseq_init[1] &= ~0x4000;
@@ -3256,26 +3258,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
e->rfseq_init[3] &= ~0x4000;
e->init_gain &= ~0x4000;
}
- switch (tr_iso) {
- case 0:
- e->cliplo_gain = 0x0062;
- case 1:
- e->cliplo_gain = 0x0064;
- case 2:
- e->cliplo_gain = 0x006a;
- case 3:
- e->cliplo_gain = 0x106a;
- case 4:
- e->cliplo_gain = 0x106c;
- case 5:
- e->cliplo_gain = 0x1074;
- case 6:
- e->cliplo_gain = 0x107c;
- case 7:
- e->cliplo_gain = 0x207c;
- default:
- e->cliplo_gain = 0x106a;
- }
+ if (tr_iso > 7)
+ tr_iso = 3;
+ e->cliplo_gain = gain_data[tr_iso];
+
} else if (ghz5 && dev->phy.rev == 4 && ext_lna) {
e->rfseq_init[0] &= ~0x4000;
e->rfseq_init[1] &= ~0x4000;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index 1a6661a9f008..756e19fc2795 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -26,6 +26,7 @@ brcmfmac-objs += \
wl_cfg80211.o \
fwil.o \
fweh.o \
+ p2p.o \
dhd_cdc.o \
dhd_common.o \
dhd_linux.o
@@ -37,4 +38,4 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
usb.o
brcmfmac-$(CONFIG_BRCMDBG) += \
- dhd_dbg.o \ No newline at end of file
+ dhd_dbg.o
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index be35a2f99b1c..11fd1c735589 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -15,8 +15,6 @@
*/
/* ****************** SDIO CARD Interface Functions **************************/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/export.h>
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index d33e5598611b..d92d373733d7 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -14,8 +14,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/mmc/sdio.h>
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index fd672bf53867..ef6f23be6d32 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -39,6 +39,7 @@
#define BRCMF_C_GET_BSSID 23
#define BRCMF_C_GET_SSID 25
#define BRCMF_C_SET_SSID 26
+#define BRCMF_C_TERMINATED 28
#define BRCMF_C_GET_CHANNEL 29
#define BRCMF_C_SET_CHANNEL 30
#define BRCMF_C_GET_SRL 31
@@ -71,6 +72,7 @@
#define BRCMF_C_SET_WSEC 134
#define BRCMF_C_GET_PHY_NOISE 135
#define BRCMF_C_GET_BSS_INFO 136
+#define BRCMF_C_SET_SCB_TIMEOUT 158
#define BRCMF_C_GET_PHYLIST 180
#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185
#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187
@@ -148,6 +150,7 @@
#define BRCMF_E_REASON_MINTXRATE 9
#define BRCMF_E_REASON_TXFAIL 10
+#define BRCMF_E_REASON_LINK_BSSCFG_DIS 4
#define BRCMF_E_REASON_FAST_ROAM_FAILED 5
#define BRCMF_E_REASON_DIRECTED_ROAM 6
#define BRCMF_E_REASON_TSPEC_REJECTED 7
@@ -374,6 +377,28 @@ struct brcmf_join_params {
struct brcmf_assoc_params_le params_le;
};
+/* scan params for extended join */
+struct brcmf_join_scan_params_le {
+ u8 scan_type; /* 0 use default, active or passive scan */
+ __le32 nprobes; /* -1 use default, nr of probes per channel */
+ __le32 active_time; /* -1 use default, dwell time per channel for
+ * active scanning
+ */
+ __le32 passive_time; /* -1 use default, dwell time per channel
+ * for passive scanning
+ */
+ __le32 home_time; /* -1 use default, dwell time for the home
+ * channel between channel scans
+ */
+};
+
+/* extended join params */
+struct brcmf_ext_join_params_le {
+ struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */
+ struct brcmf_join_scan_params_le scan_le;
+ struct brcmf_assoc_params_le assoc_le;
+};
+
struct brcmf_wsec_key {
u32 index; /* key index */
u32 len; /* key length */
@@ -450,6 +475,19 @@ struct brcmf_sta_info_le {
__le32 rx_decrypt_failures; /* # of packet decrypted failed */
};
+/*
+ * WLC_E_PROBRESP_MSG
+ * WLC_E_P2P_PROBREQ_MSG
+ * WLC_E_ACTION_FRAME_RX
+ */
+struct brcmf_rx_mgmt_data {
+ __be16 version;
+ __be16 chanspec;
+ __be32 rssi;
+ __be32 mactime;
+ __be32 rate;
+};
+
/* Bus independent dongle command */
struct brcmf_dcmd {
uint cmd; /* common dongle cmd definition */
@@ -480,50 +518,20 @@ struct brcmf_pub {
unsigned long drv_version; /* Version of dongle-resident driver */
u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */
- /* Additional stats for the bus level */
-
/* Multicast data packets sent to dongle */
unsigned long tx_multicast;
- /* Packets flushed due to unscheduled sendup thread */
- unsigned long rx_flushed;
- /* Number of times dpc scheduled by watchdog timer */
- unsigned long wd_dpc_sched;
-
- /* Number of flow control pkts recvd */
- unsigned long fc_packets;
-
- /* Last error return */
- int bcmerror;
-
- /* Last error from dongle */
- int dongle_error;
-
- /* Suspend disable flag flag */
- int suspend_disable_flag; /* "1" to disable all extra powersaving
- during suspend */
- int in_suspend; /* flag set to 1 when early suspend called */
- int dtim_skip; /* dtim skip , default 0 means wake each dtim */
struct brcmf_if *iflist[BRCMF_MAX_IFS];
struct mutex proto_block;
unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
- u8 macvalue[ETH_ALEN];
- atomic_t pend_8021x_cnt;
- wait_queue_head_t pend_8021x_wait;
-
struct brcmf_fweh_info fweh;
#ifdef DEBUG
struct dentry *dbgfs_dir;
#endif
};
-struct bcmevent_name {
- uint event;
- const char *name;
-};
-
struct brcmf_if_event {
u8 ifidx;
u8 action;
@@ -541,9 +549,11 @@ struct brcmf_cfg80211_vif;
* @vif: points to cfg80211 specific interface information.
* @ndev: associated network device.
* @stats: interface specific network statistics.
- * @idx: interface index in device firmware.
+ * @ifidx: interface index in device firmware.
* @bssidx: index of bss associated with this interface.
* @mac_addr: assigned mac address.
+ * @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
+ * @pend_8021x_wait: used for signalling change in count.
*/
struct brcmf_if {
struct brcmf_pub *drvr;
@@ -552,18 +562,13 @@ struct brcmf_if {
struct net_device_stats stats;
struct work_struct setmacaddr_work;
struct work_struct multicast_work;
- int idx;
+ int ifidx;
s32 bssidx;
u8 mac_addr[ETH_ALEN];
+ atomic_t pend_8021x_cnt;
+ wait_queue_head_t pend_8021x_wait;
};
-static inline s32 brcmf_ndev_bssidx(struct net_device *ndev)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- return ifp->bssidx;
-}
-
-extern const struct bcmevent_name bcmevent_names[];
extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
@@ -576,9 +581,14 @@ extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx,
extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len);
-extern int brcmf_net_attach(struct brcmf_if *ifp);
-extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx,
- s32 bssidx, char *name, u8 *mac_addr);
-extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx);
+/* Remove any protocol-specific data header. */
+extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
+ struct sk_buff *rxp);
+
+extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
+extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx,
+ s32 ifidx, char *name, u8 *mac_addr);
+extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
+extern u32 brcmf_get_chip_info(struct brcmf_if *ifp);
#endif /* _BRCMF_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index dd38b78a9726..ad25c3408b59 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -24,18 +24,6 @@ enum brcmf_bus_state {
BRCMF_BUS_DATA /* Ready for frame transfers */
};
-struct dngl_stats {
- unsigned long rx_packets; /* total packets received */
- unsigned long tx_packets; /* total packets transmitted */
- unsigned long rx_bytes; /* total bytes received */
- unsigned long tx_bytes; /* total bytes transmitted */
- unsigned long rx_errors; /* bad packets received */
- unsigned long tx_errors; /* packet transmit problems */
- unsigned long rx_dropped; /* packets dropped by dongle */
- unsigned long tx_dropped; /* packets dropped by dongle */
- unsigned long multicast; /* multicast packets received */
-};
-
struct brcmf_bus_dcmd {
char *name;
char *param;
@@ -72,11 +60,12 @@ struct brcmf_bus_ops {
* @drvr: public driver information.
* @state: operational state of the bus interface.
* @maxctl: maximum size for rxctl request message.
- * @drvr_up: indicates driver up/down status.
* @tx_realloc: number of tx packets realloced for headroom.
* @dstats: dongle-based statistical data.
* @align: alignment requirement for the bus.
* @dcmd_list: bus/device specific dongle initialization commands.
+ * @chip: device identifier of the dongle chip.
+ * @chiprev: revision of the dongle chip.
*/
struct brcmf_bus {
union {
@@ -87,10 +76,10 @@ struct brcmf_bus {
struct brcmf_pub *drvr;
enum brcmf_bus_state state;
uint maxctl;
- bool drvr_up;
unsigned long tx_realloc;
- struct dngl_stats dstats;
u8 align;
+ u32 chip;
+ u32 chiprev;
struct list_head dcmd_list;
struct brcmf_bus_ops *ops;
@@ -130,31 +119,18 @@ int brcmf_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint len)
* interface functions from common layer
*/
-/* Remove any protocol-specific data header. */
-extern int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
- struct sk_buff *rxp);
-
extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
struct sk_buff *pkt, int prec);
/* Receive frame for delivery to OS. Callee disposes of rxp. */
-extern void brcmf_rx_frame(struct device *dev, u8 ifidx,
- struct sk_buff_head *rxlist);
-static inline void brcmf_rx_packet(struct device *dev, int ifidx,
- struct sk_buff *pkt)
-{
- struct sk_buff_head q;
-
- skb_queue_head_init(&q);
- skb_queue_tail(&q, pkt);
- brcmf_rx_frame(dev, ifidx, &q);
-}
+extern void brcmf_rx_frames(struct device *dev, struct sk_buff_head *rxlist);
/* Indication from bus module regarding presence/insertion of dongle. */
extern int brcmf_attach(uint bus_hdrlen, struct device *dev);
/* Indication from bus module regarding removal/absence of dongle */
extern void brcmf_detach(struct device *dev);
-
+/* Indication from bus module that dongle should be reset */
+extern void brcmf_dev_reset(struct device *dev);
/* Indication from bus module to change flow-control state */
extern void brcmf_txflowblock(struct device *dev, bool state);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
index 83923553f1ac..a2354d951dd7 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
@@ -19,8 +19,6 @@
* For certain dcmd codes, the dongle interprets string data from the host.
******************************************************************************/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/types.h>
#include <linux/netdevice.h>
@@ -94,8 +92,6 @@ struct brcmf_proto_bdc_header {
struct brcmf_proto {
u16 reqid;
- u8 pending;
- u32 lastcmd;
u8 bus_header[BUS_HEADER_LEN];
struct brcmf_proto_cdc_dcmd msg;
unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
@@ -107,7 +103,7 @@ static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)
int len = le32_to_cpu(prot->msg.len) +
sizeof(struct brcmf_proto_cdc_dcmd);
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CDC, "Enter\n");
/* NOTE : cdc->msg.len holds the desired length of the buffer to be
* returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
@@ -125,7 +121,7 @@ static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
int ret;
struct brcmf_proto *prot = drvr->prot;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CDC, "Enter\n");
len += sizeof(struct brcmf_proto_cdc_dcmd);
do {
ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg,
@@ -147,20 +143,7 @@ brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
int ret = 0, retries = 0;
u32 id, flags;
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
-
- /* Respond "bcmerror" and "bcmerrorstr" with local cache */
- if (cmd == BRCMF_C_GET_VAR && buf) {
- if (!strcmp((char *)buf, "bcmerrorstr")) {
- strncpy((char *)buf, "bcm_error",
- BCME_STRLEN);
- goto done;
- } else if (!strcmp((char *)buf, "bcmerror")) {
- *(int *)buf = drvr->dongle_error;
- goto done;
- }
- }
+ brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
@@ -210,11 +193,8 @@ retry:
}
/* Check the ERROR flag */
- if (flags & CDC_DCMD_ERROR) {
+ if (flags & CDC_DCMD_ERROR)
ret = le32_to_cpu(msg->status);
- /* Cache error from dongle */
- drvr->dongle_error = ret;
- }
done:
return ret;
@@ -228,8 +208,7 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
int ret = 0;
u32 flags, id;
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
+ brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
@@ -262,11 +241,8 @@ int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
}
/* Check the ERROR flag */
- if (flags & CDC_DCMD_ERROR) {
+ if (flags & CDC_DCMD_ERROR)
ret = le32_to_cpu(msg->status);
- /* Cache error from dongle */
- drvr->dongle_error = ret;
- }
done:
return ret;
@@ -287,7 +263,7 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
{
struct brcmf_proto_bdc_header *h;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CDC, "Enter\n");
/* Push BDC header used to convey priority for buses that don't */
@@ -305,14 +281,12 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
BDC_SET_IF_IDX(h, ifidx);
}
-int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
+int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
struct sk_buff *pktbuf)
{
struct brcmf_proto_bdc_header *h;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CDC, "Enter\n");
/* Pop BDC header used to convey priority for buses that don't */
@@ -329,6 +303,14 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);
return -EBADE;
}
+ /* The ifidx is the idx to map to matching netdev/ifp. When receiving
+ * events this is easy because it contains the bssidx which maps
+ * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.
+ * bssidx 1 is used for p2p0 and no data can be received or
+ * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0
+ */
+ if (*ifidx)
+ (*ifidx)++;
if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
BDC_PROTO_VER) {
@@ -338,7 +320,7 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
}
if (h->flags & BDC_FLAG_SUM_GOOD) {
- brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n",
+ brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n",
brcmf_ifname(drvr, *ifidx), h->flags);
pkt_set_sum_good(pktbuf, true);
}
@@ -348,6 +330,8 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx,
skb_pull(pktbuf, BDC_HEADER_LEN);
skb_pull(pktbuf, h->data_offset << 2);
+ if (pktbuf->len == 0)
+ return -ENODATA;
return 0;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
index f8b52e5b941a..4544342a0428 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
@@ -14,8 +14,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index f2ab01cd7966..bc013cbe06f6 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -18,21 +18,26 @@
#define _BRCMF_DBG_H_
/* message levels */
-#define BRCMF_TRACE_VAL 0x0002
-#define BRCMF_INFO_VAL 0x0004
-#define BRCMF_DATA_VAL 0x0008
-#define BRCMF_CTL_VAL 0x0010
-#define BRCMF_TIMER_VAL 0x0020
-#define BRCMF_HDRS_VAL 0x0040
-#define BRCMF_BYTES_VAL 0x0080
-#define BRCMF_INTR_VAL 0x0100
-#define BRCMF_GLOM_VAL 0x0200
-#define BRCMF_EVENT_VAL 0x0400
-#define BRCMF_BTA_VAL 0x0800
-#define BRCMF_FIL_VAL 0x1000
-#define BRCMF_USB_VAL 0x2000
-#define BRCMF_SCAN_VAL 0x4000
-#define BRCMF_CONN_VAL 0x8000
+#define BRCMF_TRACE_VAL 0x00000002
+#define BRCMF_INFO_VAL 0x00000004
+#define BRCMF_DATA_VAL 0x00000008
+#define BRCMF_CTL_VAL 0x00000010
+#define BRCMF_TIMER_VAL 0x00000020
+#define BRCMF_HDRS_VAL 0x00000040
+#define BRCMF_BYTES_VAL 0x00000080
+#define BRCMF_INTR_VAL 0x00000100
+#define BRCMF_GLOM_VAL 0x00000200
+#define BRCMF_EVENT_VAL 0x00000400
+#define BRCMF_BTA_VAL 0x00000800
+#define BRCMF_FIL_VAL 0x00001000
+#define BRCMF_USB_VAL 0x00002000
+#define BRCMF_SCAN_VAL 0x00004000
+#define BRCMF_CONN_VAL 0x00008000
+#define BRCMF_CDC_VAL 0x00010000
+
+/* set default print format */
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* Macro for error messages. net_ratelimit() is used when driver
* debugging is not selected. When debugging the driver error
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index 74a616b4de8e..c06cea88df0d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -14,8 +14,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/module.h>
@@ -28,6 +26,8 @@
#include "dhd_bus.h"
#include "dhd_proto.h"
#include "dhd_dbg.h"
+#include "fwil_types.h"
+#include "p2p.h"
#include "wl_cfg80211.h"
#include "fwil.h"
@@ -42,6 +42,12 @@ MODULE_LICENSE("Dual BSD/GPL");
int brcmf_msg_level;
module_param(brcmf_msg_level, int, 0);
+/* P2P0 enable */
+static int brcmf_p2p_enable;
+#ifdef CONFIG_BRCMDBG
+module_param_named(p2pon, brcmf_p2p_enable, int, 0);
+MODULE_PARM_DESC(p2pon, "enable p2p management functionality");
+#endif
char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
{
@@ -72,9 +78,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
u32 buflen;
s32 err;
- brcmf_dbg(TRACE, "enter\n");
-
ifp = container_of(work, struct brcmf_if, multicast_work);
+
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
ndev = ifp->ndev;
/* Determine initial value of allmulti flag */
@@ -131,9 +138,10 @@ _brcmf_set_mac_address(struct work_struct *work)
struct brcmf_if *ifp;
s32 err;
- brcmf_dbg(TRACE, "enter\n");
-
ifp = container_of(work, struct brcmf_if, setmacaddr_work);
+
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+
err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
ETH_ALEN);
if (err < 0) {
@@ -162,28 +170,31 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
schedule_work(&ifp->multicast_work);
}
-static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
{
int ret;
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
+ struct ethhdr *eh;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
- /* Reject if down */
- if (!drvr->bus_if->drvr_up ||
- (drvr->bus_if->state != BRCMF_BUS_DATA)) {
- brcmf_err("xmit rejected drvup=%d state=%d\n",
- drvr->bus_if->drvr_up,
- drvr->bus_if->state);
+ /* Can the device send data? */
+ if (drvr->bus_if->state != BRCMF_BUS_DATA) {
+ brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
netif_stop_queue(ndev);
- return -ENODEV;
+ dev_kfree_skb(skb);
+ ret = -ENODEV;
+ goto done;
}
- if (!drvr->iflist[ifp->idx]) {
- brcmf_err("bad ifidx %d\n", ifp->idx);
+ if (!drvr->iflist[ifp->bssidx]) {
+ brcmf_err("bad ifidx %d\n", ifp->bssidx);
netif_stop_queue(ndev);
- return -ENODEV;
+ dev_kfree_skb(skb);
+ ret = -ENODEV;
+ goto done;
}
/* Make sure there's enough room for any header */
@@ -191,44 +202,49 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
struct sk_buff *skb2;
brcmf_dbg(INFO, "%s: insufficient headroom\n",
- brcmf_ifname(drvr, ifp->idx));
+ brcmf_ifname(drvr, ifp->bssidx));
drvr->bus_if->tx_realloc++;
skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
dev_kfree_skb(skb);
skb = skb2;
if (skb == NULL) {
brcmf_err("%s: skb_realloc_headroom failed\n",
- brcmf_ifname(drvr, ifp->idx));
+ brcmf_ifname(drvr, ifp->bssidx));
ret = -ENOMEM;
goto done;
}
}
- /* Update multicast statistic */
- if (skb->len >= ETH_ALEN) {
- u8 *pktdata = (u8 *)(skb->data);
- struct ethhdr *eh = (struct ethhdr *)pktdata;
-
- if (is_multicast_ether_addr(eh->h_dest))
- drvr->tx_multicast++;
- if (ntohs(eh->h_proto) == ETH_P_PAE)
- atomic_inc(&drvr->pend_8021x_cnt);
+ /* validate length for ether packet */
+ if (skb->len < sizeof(*eh)) {
+ ret = -EINVAL;
+ dev_kfree_skb(skb);
+ goto done;
}
+ /* handle ethernet header */
+ eh = (struct ethhdr *)(skb->data);
+ if (is_multicast_ether_addr(eh->h_dest))
+ drvr->tx_multicast++;
+ if (ntohs(eh->h_proto) == ETH_P_PAE)
+ atomic_inc(&ifp->pend_8021x_cnt);
+
/* If the protocol uses a data header, apply it */
- brcmf_proto_hdrpush(drvr, ifp->idx, skb);
+ brcmf_proto_hdrpush(drvr, ifp->ifidx, skb);
/* Use bus module to send data frame */
ret = brcmf_bus_txdata(drvr->bus_if, skb);
done:
- if (ret)
- drvr->bus_if->dstats.tx_dropped++;
- else
- drvr->bus_if->dstats.tx_packets++;
+ if (ret) {
+ ifp->stats.tx_dropped++;
+ } else {
+ ifp->stats.tx_packets++;
+ ifp->stats.tx_bytes += skb->len;
+ }
/* Return ok: we always eat the packet */
- return 0;
+ return NETDEV_TX_OK;
}
void brcmf_txflowblock(struct device *dev, bool state)
@@ -250,8 +266,7 @@ void brcmf_txflowblock(struct device *dev, bool state)
}
}
-void brcmf_rx_frame(struct device *dev, u8 ifidx,
- struct sk_buff_head *skb_list)
+void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
{
unsigned char *eth;
uint len;
@@ -259,12 +274,25 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx,
struct brcmf_if *ifp;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
+ u8 ifidx;
+ int ret;
brcmf_dbg(TRACE, "Enter\n");
skb_queue_walk_safe(skb_list, skb, pnext) {
skb_unlink(skb, skb_list);
+ /* process and remove protocol-specific header */
+ ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
+ ifp = drvr->iflist[ifidx];
+
+ if (ret || !ifp || !ifp->ndev) {
+ if ((ret != -ENODATA) && ifp)
+ ifp->stats.rx_errors++;
+ brcmu_pkt_buf_free_skb(skb);
+ continue;
+ }
+
/* Get the protocol, maintain skb around eth_type_trans()
* The main reason for this hack is for the limitation of
* Linux 2.4 where 'eth_type_trans' uses the
@@ -280,21 +308,11 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx,
eth = skb->data;
len = skb->len;
- ifp = drvr->iflist[ifidx];
- if (ifp == NULL)
- ifp = drvr->iflist[0];
-
- if (!ifp || !ifp->ndev ||
- ifp->ndev->reg_state != NETREG_REGISTERED) {
- brcmu_pkt_buf_free_skb(skb);
- continue;
- }
-
skb->dev = ifp->ndev;
skb->protocol = eth_type_trans(skb, skb->dev);
if (skb->pkt_type == PACKET_MULTICAST)
- bus_if->dstats.multicast++;
+ ifp->stats.multicast++;
skb->data = eth;
skb->len = len;
@@ -310,8 +328,13 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx,
ifp->ndev->last_rx = jiffies;
}
- bus_if->dstats.rx_bytes += skb->len;
- bus_if->dstats.rx_packets++; /* Local count */
+ if (!(ifp->ndev->flags & IFF_UP)) {
+ brcmu_pkt_buf_free_skb(skb);
+ continue;
+ }
+
+ ifp->stats.rx_bytes += skb->len;
+ ifp->stats.rx_packets++;
if (in_interrupt())
netif_rx(skb);
@@ -328,41 +351,36 @@ void brcmf_rx_frame(struct device *dev, u8 ifidx,
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
{
- uint ifidx;
+ u8 ifidx;
struct ethhdr *eh;
u16 type;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
+ struct brcmf_if *ifp;
+
+ brcmf_proto_hdrpull(drvr, &ifidx, txp);
- brcmf_proto_hdrpull(dev, &ifidx, txp);
+ ifp = drvr->iflist[ifidx];
+ if (!ifp)
+ return;
eh = (struct ethhdr *)(txp->data);
type = ntohs(eh->h_proto);
if (type == ETH_P_PAE) {
- atomic_dec(&drvr->pend_8021x_cnt);
- if (waitqueue_active(&drvr->pend_8021x_wait))
- wake_up(&drvr->pend_8021x_wait);
+ atomic_dec(&ifp->pend_8021x_cnt);
+ if (waitqueue_active(&ifp->pend_8021x_wait))
+ wake_up(&ifp->pend_8021x_wait);
}
+ if (!success)
+ ifp->stats.tx_errors++;
}
static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_bus *bus_if = ifp->drvr->bus_if;
- brcmf_dbg(TRACE, "Enter\n");
-
- /* Copy dongle stats to net device stats */
- ifp->stats.rx_packets = bus_if->dstats.rx_packets;
- ifp->stats.tx_packets = bus_if->dstats.tx_packets;
- ifp->stats.rx_bytes = bus_if->dstats.rx_bytes;
- ifp->stats.tx_bytes = bus_if->dstats.tx_bytes;
- ifp->stats.rx_errors = bus_if->dstats.rx_errors;
- ifp->stats.tx_errors = bus_if->dstats.tx_errors;
- ifp->stats.rx_dropped = bus_if->dstats.rx_dropped;
- ifp->stats.tx_dropped = bus_if->dstats.tx_dropped;
- ifp->stats.multicast = bus_if->dstats.multicast;
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
return &ifp->stats;
}
@@ -395,9 +413,11 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
- sprintf(info->driver, KBUILD_MODNAME);
- sprintf(info->version, "%lu", drvr->drv_version);
- sprintf(info->bus_info, "%s", dev_name(drvr->bus_if->dev));
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+ snprintf(info->version, sizeof(info->version), "%lu",
+ drvr->drv_version);
+ strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
+ sizeof(info->bus_info));
}
static const struct ethtool_ops brcmf_ethtool_ops = {
@@ -414,7 +434,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
u32 toe_cmpnt, csum_dir;
int ret;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
/* all ethtool calls start with a cmd word */
if (copy_from_user(&cmd, uaddr, sizeof(u32)))
@@ -437,20 +457,14 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
sprintf(info.driver, "dhd");
strcpy(info.version, BRCMF_VERSION_STR);
}
-
- /* otherwise, require dongle to be up */
- else if (!drvr->bus_if->drvr_up) {
- brcmf_err("dongle is not up\n");
- return -ENODEV;
- }
- /* finally, report dongle driver type */
+ /* report dongle driver type */
else
sprintf(info.driver, "wl");
sprintf(info.version, "%lu", drvr->drv_version);
if (copy_to_user(uaddr, &info, sizeof(info)))
return -EFAULT;
- brcmf_dbg(CTL, "given %*s, returning %s\n",
+ brcmf_dbg(TRACE, "given %*s, returning %s\n",
(int)sizeof(drvname), drvname, info.driver);
break;
@@ -517,9 +531,9 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
- brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd);
+ brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd);
- if (!drvr->iflist[ifp->idx])
+ if (!drvr->iflist[ifp->bssidx])
return -1;
if (cmd == SIOCETHTOOL)
@@ -531,17 +545,12 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
static int brcmf_netdev_stop(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_pub *drvr = ifp->drvr;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (drvr->bus_if->drvr_up == 0)
- return 0;
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
brcmf_cfg80211_down(ndev);
/* Set state and stop OS transmissions */
- drvr->bus_if->drvr_up = false;
netif_stop_queue(ndev);
return 0;
@@ -555,7 +564,7 @@ static int brcmf_netdev_open(struct net_device *ndev)
u32 toe_ol;
s32 ret = 0;
- brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
+ brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
/* If bus is not ready, can't continue */
if (bus_if->state != BRCMF_BUS_DATA) {
@@ -563,25 +572,17 @@ static int brcmf_netdev_open(struct net_device *ndev)
return -EAGAIN;
}
- atomic_set(&drvr->pend_8021x_cnt, 0);
-
- memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
+ atomic_set(&ifp->pend_8021x_cnt, 0);
/* Get current TOE mode from dongle */
if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
&& (toe_ol & TOE_TX_CSUM_OL) != 0)
- drvr->iflist[ifp->idx]->ndev->features |=
- NETIF_F_IP_CSUM;
+ ndev->features |= NETIF_F_IP_CSUM;
else
- drvr->iflist[ifp->idx]->ndev->features &=
- ~NETIF_F_IP_CSUM;
-
- /* make sure RF is ready for work */
- brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
+ ndev->features &= ~NETIF_F_IP_CSUM;
/* Allow transmit calls */
netif_start_queue(ndev);
- drvr->bus_if->drvr_up = true;
if (brcmf_cfg80211_up(ndev)) {
brcmf_err("failed to bring up cfg80211\n");
return -1;
@@ -600,29 +601,18 @@ static const struct net_device_ops brcmf_netdev_ops_pri = {
.ndo_set_rx_mode = brcmf_netdev_set_multicast_list
};
-static const struct net_device_ops brcmf_netdev_ops_virt = {
- .ndo_open = brcmf_cfg80211_up,
- .ndo_stop = brcmf_cfg80211_down,
- .ndo_get_stats = brcmf_netdev_get_stats,
- .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
- .ndo_start_xmit = brcmf_netdev_start_xmit,
- .ndo_set_mac_address = brcmf_netdev_set_mac_address,
- .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
-};
-
-int brcmf_net_attach(struct brcmf_if *ifp)
+int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
{
struct brcmf_pub *drvr = ifp->drvr;
struct net_device *ndev;
+ s32 err;
- brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr);
+ brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
+ ifp->mac_addr);
ndev = ifp->ndev;
/* set appropriate operations */
- if (!ifp->idx)
- ndev->netdev_ops = &brcmf_netdev_ops_pri;
- else
- ndev->netdev_ops = &brcmf_netdev_ops_virt;
+ ndev->netdev_ops = &brcmf_netdev_ops_pri;
ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
ndev->ethtool_ops = &brcmf_ethtool_ops;
@@ -633,7 +623,14 @@ int brcmf_net_attach(struct brcmf_if *ifp)
/* set the mac address */
memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
- if (register_netdev(ndev) != 0) {
+ INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
+ INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
+
+ if (rtnl_locked)
+ err = register_netdevice(ndev);
+ else
+ err = register_netdev(ndev);
+ if (err != 0) {
brcmf_err("couldn't register the net device\n");
goto fail;
}
@@ -647,16 +644,78 @@ fail:
return -EBADE;
}
-struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
- char *name, u8 *addr_mask)
+static int brcmf_net_p2p_open(struct net_device *ndev)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ return brcmf_cfg80211_up(ndev);
+}
+
+static int brcmf_net_p2p_stop(struct net_device *ndev)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ return brcmf_cfg80211_down(ndev);
+}
+
+static int brcmf_net_p2p_do_ioctl(struct net_device *ndev,
+ struct ifreq *ifr, int cmd)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+ return 0;
+}
+
+static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ if (skb)
+ dev_kfree_skb_any(skb);
+
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops brcmf_netdev_ops_p2p = {
+ .ndo_open = brcmf_net_p2p_open,
+ .ndo_stop = brcmf_net_p2p_stop,
+ .ndo_do_ioctl = brcmf_net_p2p_do_ioctl,
+ .ndo_start_xmit = brcmf_net_p2p_start_xmit
+};
+
+static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
+{
+ struct net_device *ndev;
+
+ brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx,
+ ifp->mac_addr);
+ ndev = ifp->ndev;
+
+ ndev->netdev_ops = &brcmf_netdev_ops_p2p;
+
+ /* set the mac address */
+ memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
+
+ if (register_netdev(ndev) != 0) {
+ brcmf_err("couldn't register the p2p net device\n");
+ goto fail;
+ }
+
+ brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
+
+ return 0;
+
+fail:
+ return -EBADE;
+}
+
+struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
+ char *name, u8 *mac_addr)
{
struct brcmf_if *ifp;
struct net_device *ndev;
- int i;
- brcmf_dbg(TRACE, "idx %d\n", ifidx);
+ brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx);
- ifp = drvr->iflist[ifidx];
+ ifp = drvr->iflist[bssidx];
/*
* Delete the existing interface before overwriting it
* in case we missed the BRCMF_E_IF_DEL event.
@@ -668,7 +727,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
netif_stop_queue(ifp->ndev);
unregister_netdev(ifp->ndev);
free_netdev(ifp->ndev);
- drvr->iflist[ifidx] = NULL;
+ drvr->iflist[bssidx] = NULL;
} else {
brcmf_err("ignore IF event\n");
return ERR_PTR(-EINVAL);
@@ -685,16 +744,15 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
ifp = netdev_priv(ndev);
ifp->ndev = ndev;
ifp->drvr = drvr;
- drvr->iflist[ifidx] = ifp;
- ifp->idx = ifidx;
+ drvr->iflist[bssidx] = ifp;
+ ifp->ifidx = ifidx;
ifp->bssidx = bssidx;
- INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
- INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
- if (addr_mask != NULL)
- for (i = 0; i < ETH_ALEN; i++)
- ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i];
+ init_waitqueue_head(&ifp->pend_8021x_wait);
+
+ if (mac_addr != NULL)
+ memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
current->pid, ifp->ndev->name, ifp->mac_addr);
@@ -702,19 +760,18 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
return ifp;
}
-void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
+void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
{
struct brcmf_if *ifp;
- brcmf_dbg(TRACE, "idx %d\n", ifidx);
-
- ifp = drvr->iflist[ifidx];
+ ifp = drvr->iflist[bssidx];
if (!ifp) {
- brcmf_err("Null interface\n");
+ brcmf_err("Null interface, idx=%d\n", bssidx);
return;
}
+ brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx);
if (ifp->ndev) {
- if (ifidx == 0) {
+ if (bssidx == 0) {
if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
rtnl_lock();
brcmf_netdev_stop(ifp->ndev);
@@ -724,12 +781,14 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
netif_stop_queue(ifp->ndev);
}
- cancel_work_sync(&ifp->setmacaddr_work);
- cancel_work_sync(&ifp->multicast_work);
+ if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+ cancel_work_sync(&ifp->setmacaddr_work);
+ cancel_work_sync(&ifp->multicast_work);
+ }
unregister_netdev(ifp->ndev);
- drvr->iflist[ifidx] = NULL;
- if (ifidx == 0)
+ drvr->iflist[bssidx] = NULL;
+ if (bssidx == 0)
brcmf_cfg80211_detach(drvr->config);
free_netdev(ifp->ndev);
}
@@ -769,8 +828,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
- init_waitqueue_head(&drvr->pend_8021x_wait);
-
return ret;
fail:
@@ -785,6 +842,7 @@ int brcmf_bus_start(struct device *dev)
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
struct brcmf_if *ifp;
+ struct brcmf_if *p2p_ifp;
brcmf_dbg(TRACE, "\n");
@@ -800,6 +858,13 @@ int brcmf_bus_start(struct device *dev)
if (IS_ERR(ifp))
return PTR_ERR(ifp);
+ if (brcmf_p2p_enable)
+ p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL);
+ else
+ p2p_ifp = NULL;
+ if (IS_ERR(p2p_ifp))
+ p2p_ifp = NULL;
+
/* signal bus ready */
bus_if->state = BRCMF_BUS_DATA;
@@ -818,16 +883,22 @@ int brcmf_bus_start(struct device *dev)
if (ret < 0)
goto fail;
- ret = brcmf_net_attach(ifp);
+ ret = brcmf_net_attach(ifp, false);
fail:
if (ret < 0) {
brcmf_err("failed: %d\n", ret);
if (drvr->config)
brcmf_cfg80211_detach(drvr->config);
- free_netdev(drvr->iflist[0]->ndev);
+ free_netdev(ifp->ndev);
drvr->iflist[0] = NULL;
+ if (p2p_ifp) {
+ free_netdev(p2p_ifp->ndev);
+ drvr->iflist[1] = NULL;
+ }
return ret;
}
+ if ((brcmf_p2p_enable) && (p2p_ifp))
+ brcmf_net_p2p_attach(p2p_ifp);
return 0;
}
@@ -845,9 +916,21 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr)
}
}
+void brcmf_dev_reset(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+
+ if (drvr == NULL)
+ return;
+
+ if (drvr->iflist[0])
+ brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
+}
+
void brcmf_detach(struct device *dev)
{
- int i;
+ s32 i;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
@@ -866,28 +949,26 @@ void brcmf_detach(struct device *dev)
brcmf_bus_detach(drvr);
- if (drvr->prot) {
+ if (drvr->prot)
brcmf_proto_detach(drvr);
- }
brcmf_debugfs_detach(drvr);
bus_if->drvr = NULL;
kfree(drvr);
}
-static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr)
+static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
{
- return atomic_read(&drvr->pend_8021x_cnt);
+ return atomic_read(&ifp->pend_8021x_cnt);
}
int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_pub *drvr = ifp->drvr;
int err;
- err = wait_event_timeout(drvr->pend_8021x_wait,
- !brcmf_get_pend_8021x_cnt(drvr),
+ err = wait_event_timeout(ifp->pend_8021x_wait,
+ !brcmf_get_pend_8021x_cnt(ifp),
msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));
WARN_ON(!err);
@@ -895,6 +976,16 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
return !err;
}
+/*
+ * return chip id and rev of the device encoded in u32.
+ */
+u32 brcmf_get_chip_info(struct brcmf_if *ifp)
+{
+ struct brcmf_bus *bus = ifp->drvr->bus_if;
+
+ return bus->chip << 4 | bus->chiprev;
+}
+
static void brcmf_driver_init(struct work_struct *work)
{
brcmf_debugfs_init();
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index cf857f1edf8c..4469321c0eb3 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -14,8 +14,6 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
@@ -1098,7 +1096,6 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL &&
type != BRCMF_SDIO_FT_SUPER) {
brcmf_err("HW header length too long\n");
- bus->sdiodev->bus_if->dstats.rx_errors++;
bus->sdcnt.rx_toolong++;
brcmf_sdbrcm_rxfail(bus, false, false);
rd->len = 0;
@@ -1169,7 +1166,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
int errcode;
u8 doff, sfdoff;
- int ifidx = 0;
bool usechain = bus->use_rxchain;
struct brcmf_sdio_read rd_new;
@@ -1301,7 +1297,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
if (errcode < 0) {
brcmf_err("glom read of %d bytes failed: %d\n",
dlen, errcode);
- bus->sdiodev->bus_if->dstats.rx_errors++;
sdio_claim_host(bus->sdiodev->func[1]);
if (bus->glomerr++ < 3) {
@@ -1388,13 +1383,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
skb_unlink(pfirst, &bus->glom);
brcmu_pkt_buf_free_skb(pfirst);
continue;
- } else if (brcmf_proto_hdrpull(bus->sdiodev->dev,
- &ifidx, pfirst) != 0) {
- brcmf_err("rx protocol error\n");
- bus->sdiodev->bus_if->dstats.rx_errors++;
- skb_unlink(pfirst, &bus->glom);
- brcmu_pkt_buf_free_skb(pfirst);
- continue;
}
brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
@@ -1407,7 +1395,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
}
/* sent any remaining packets up */
if (bus->glom.qlen)
- brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom);
+ brcmf_rx_frames(bus->sdiodev->dev, &bus->glom);
bus->sdcnt.rxglomframes++;
bus->sdcnt.rxglompkts += bus->glom.qlen;
@@ -1455,10 +1443,9 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
if (bus->rxblen)
buf = vzalloc(bus->rxblen);
- if (!buf) {
- brcmf_err("no memory for control frame\n");
+ if (!buf)
goto done;
- }
+
rbuf = bus->rxbuf;
pad = ((unsigned long)rbuf % BRCMF_SDALIGN);
if (pad)
@@ -1488,7 +1475,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
rdlen, bus->sdiodev->bus_if->maxctl);
- bus->sdiodev->bus_if->dstats.rx_errors++;
brcmf_sdbrcm_rxfail(bus, false, false);
goto done;
}
@@ -1496,7 +1482,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
if ((len - doff) > bus->sdiodev->bus_if->maxctl) {
brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
len, len - doff, bus->sdiodev->bus_if->maxctl);
- bus->sdiodev->bus_if->dstats.rx_errors++;
bus->sdcnt.rx_toolong++;
brcmf_sdbrcm_rxfail(bus, false, false);
goto done;
@@ -1558,10 +1543,10 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
{
struct sk_buff *pkt; /* Packet for event or data frames */
+ struct sk_buff_head pktlist; /* needed for bus interface */
u16 pad; /* Number of pad bytes to read */
uint rxleft = 0; /* Remaining number of frames allowed */
int sdret; /* Return code from calls */
- int ifidx = 0;
uint rxcount = 0; /* Total frames read */
struct brcmf_sdio_read *rd = &bus->cur_read, rd_new;
u8 head_read = 0;
@@ -1644,7 +1629,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
if (!pkt) {
/* Give up on data, request rtx of events */
brcmf_err("brcmu_pkt_buf_get_skb failed\n");
- bus->sdiodev->bus_if->dstats.rx_dropped++;
brcmf_sdbrcm_rxfail(bus, false,
RETRYCHAN(rd->channel));
sdio_release_host(bus->sdiodev->func[1]);
@@ -1662,7 +1646,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
brcmf_err("read %d bytes from channel %d failed: %d\n",
rd->len, rd->channel, sdret);
brcmu_pkt_buf_free_skb(pkt);
- bus->sdiodev->bus_if->dstats.rx_errors++;
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_rxfail(bus, true,
RETRYCHAN(rd->channel));
@@ -1760,15 +1743,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
if (pkt->len == 0) {
brcmu_pkt_buf_free_skb(pkt);
continue;
- } else if (brcmf_proto_hdrpull(bus->sdiodev->dev, &ifidx,
- pkt) != 0) {
- brcmf_err("rx protocol error\n");
- brcmu_pkt_buf_free_skb(pkt);
- bus->sdiodev->bus_if->dstats.rx_errors++;
- continue;
}
- brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt);
+ skb_queue_head_init(&pktlist);
+ skb_queue_tail(&pktlist, pkt);
+ brcmf_rx_frames(bus->sdiodev->dev, &pktlist);
}
rxcount = maxframes - rxleft;
@@ -1954,10 +1933,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
datalen = pkt->len - SDPCM_HDRLEN;
ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
- if (ret)
- bus->sdiodev->bus_if->dstats.tx_errors++;
- else
- bus->sdiodev->bus_if->dstats.tx_bytes += datalen;
/* In poll mode, need to check for other events */
if (!bus->intr && cnt) {
@@ -1976,8 +1951,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
}
/* Deflow-control stack if needed */
- if (bus->sdiodev->bus_if->drvr_up &&
- (bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
+ if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
bus->txoff = false;
brcmf_txflowblock(bus->sdiodev->dev, false);
@@ -2724,9 +2698,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
* address of sdpcm_shared structure
*/
sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
(u8 *)&addr_le, 4);
- sdio_claim_host(bus->sdiodev->func[1]);
+ sdio_release_host(bus->sdiodev->func[1]);
if (rv < 0)
return rv;
@@ -2745,10 +2720,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
}
/* Read hndrte_shared structure */
- sdio_claim_host(bus->sdiodev->func[1]);
rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
sizeof(struct sdpcm_shared_le));
- sdio_release_host(bus->sdiodev->func[1]);
if (rv < 0)
return rv;
@@ -2850,14 +2823,12 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
return 0;
- sdio_claim_host(bus->sdiodev->func[1]);
error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
sizeof(struct brcmf_trap_info));
if (error < 0)
return error;
nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
- sdio_release_host(bus->sdiodev->func[1]);
if (nbytes < 0)
return nbytes;
@@ -3322,9 +3293,6 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
{
int ret;
- if (bus->sdiodev->bus_if->drvr_up)
- return -EISCONN;
-
ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
&bus->sdiodev->func[2]->dev);
if (ret) {
@@ -3955,6 +3923,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
/* Assign bus interface call back */
bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops;
+ bus->sdiodev->bus_if->chip = bus->ci->chip;
+ bus->sdiodev->bus_if->chiprev = bus->ci->chiprev;
/* Attach to the brcmf/OS/network interface */
ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
index ba0b22512f12..e9d6f91a1f2b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -189,24 +189,24 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
return;
}
- ifp = drvr->iflist[ifevent->ifidx];
+ ifp = drvr->iflist[ifevent->bssidx];
if (ifevent->action == BRCMF_E_IF_ADD) {
brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
emsg->addr);
- ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx,
+ ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx,
emsg->ifname, emsg->addr);
if (IS_ERR(ifp))
return;
if (!drvr->fweh.evt_handler[BRCMF_E_IF])
- err = brcmf_net_attach(ifp);
+ err = brcmf_net_attach(ifp, false);
}
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
if (ifevent->action == BRCMF_E_IF_DEL)
- brcmf_del_if(drvr, ifevent->ifidx);
+ brcmf_del_if(drvr, ifevent->bssidx);
}
/**
@@ -250,8 +250,6 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
drvr = container_of(fweh, struct brcmf_pub, fweh);
while ((event = brcmf_fweh_dequeue_event(fweh))) {
- ifp = drvr->iflist[event->ifidx];
-
brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n",
brcmf_fweh_event_name(event->code), event->code,
event->emsg.ifidx, event->emsg.bsscfgidx,
@@ -283,6 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
goto event_free;
}
+ ifp = drvr->iflist[emsg.bsscfgidx];
err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg,
event->data);
if (err) {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
index 36901f76a3b5..8c39b51dcccf 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
@@ -83,6 +83,7 @@ struct brcmf_event;
BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \
BRCMF_ENUM_DEF(TRACE, 52) \
BRCMF_ENUM_DEF(IF, 54) \
+ BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \
BRCMF_ENUM_DEF(RSSI, 56) \
BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \
BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \
@@ -96,8 +97,11 @@ struct brcmf_event;
BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \
BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \
BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \
+ BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \
+ BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \
BRCMF_ENUM_DEF(DCS_REQUEST, 73) \
- BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74)
+ BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
+ BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75)
#define BRCMF_ENUM_DEF(id, val) \
BRCMF_E_##id = (val),
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
index d8d8b6549dc5..8d1def935b8d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
@@ -45,9 +45,10 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
if (data != NULL)
len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
if (set)
- err = brcmf_proto_cdc_set_dcmd(drvr, ifp->idx, cmd, data, len);
+ err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data,
+ len);
else
- err = brcmf_proto_cdc_query_dcmd(drvr, ifp->idx, cmd, data,
+ err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data,
len);
if (err >= 0)
@@ -100,6 +101,7 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data)
__le32 data_le = cpu_to_le32(data);
mutex_lock(&ifp->drvr->proto_block);
+ brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data);
err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
mutex_unlock(&ifp->drvr->proto_block);
@@ -116,6 +118,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
mutex_unlock(&ifp->drvr->proto_block);
*data = le32_to_cpu(data_le);
+ brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data);
return err;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
new file mode 100644
index 000000000000..0f2c83bc95dc
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * 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 FWIL_TYPES_H_
+#define FWIL_TYPES_H_
+
+#include <linux/if_ether.h>
+
+
+#define BRCMF_FIL_ACTION_FRAME_SIZE 1800
+
+
+enum brcmf_fil_p2p_if_types {
+ BRCMF_FIL_P2P_IF_CLIENT,
+ BRCMF_FIL_P2P_IF_GO,
+ BRCMF_FIL_P2P_IF_DYNBCN_GO,
+ BRCMF_FIL_P2P_IF_DEV,
+};
+
+struct brcmf_fil_p2p_if_le {
+ u8 addr[ETH_ALEN];
+ __le16 type;
+ __le16 chspec;
+};
+
+struct brcmf_fil_chan_info_le {
+ __le32 hw_channel;
+ __le32 target_channel;
+ __le32 scan_channel;
+};
+
+struct brcmf_fil_action_frame_le {
+ u8 da[ETH_ALEN];
+ __le16 len;
+ __le32 packet_id;
+ u8 data[BRCMF_FIL_ACTION_FRAME_SIZE];
+};
+
+struct brcmf_fil_af_params_le {
+ __le32 channel;
+ __le32 dwell_time;
+ u8 bssid[ETH_ALEN];
+ u8 pad[2];
+ struct brcmf_fil_action_frame_le action_frame;
+};
+
+struct brcmf_fil_bss_enable_le {
+ __le32 bsscfg_idx;
+ __le32 enable;
+};
+
+#endif /* FWIL_TYPES_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
new file mode 100644
index 000000000000..4166e642068b
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -0,0 +1,2277 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * 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/slab.h>
+#include <linux/netdevice.h>
+#include <net/cfg80211.h>
+
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include <defs.h>
+#include <dhd.h>
+#include <dhd_dbg.h>
+#include "fwil.h"
+#include "fwil_types.h"
+#include "p2p.h"
+#include "wl_cfg80211.h"
+
+/* parameters used for p2p escan */
+#define P2PAPI_SCAN_NPROBES 1
+#define P2PAPI_SCAN_DWELL_TIME_MS 80
+#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
+#define P2PAPI_SCAN_HOME_TIME_MS 60
+#define P2PAPI_SCAN_NPROBS_TIME_MS 30
+#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100
+#define WL_SCAN_CONNECT_DWELL_TIME_MS 200
+#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20
+
+#define BRCMF_P2P_WILDCARD_SSID "DIRECT-"
+#define BRCMF_P2P_WILDCARD_SSID_LEN (sizeof(BRCMF_P2P_WILDCARD_SSID) - 1)
+
+#define SOCIAL_CHAN_1 1
+#define SOCIAL_CHAN_2 6
+#define SOCIAL_CHAN_3 11
+#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \
+ (channel == SOCIAL_CHAN_2) || \
+ (channel == SOCIAL_CHAN_3))
+#define SOCIAL_CHAN_CNT 3
+#define AF_PEER_SEARCH_CNT 2
+
+#define BRCMF_SCB_TIMEOUT_VALUE 20
+
+#define P2P_VER 9 /* P2P version: 9=WiFi P2P v1.0 */
+#define P2P_PUB_AF_CATEGORY 0x04
+#define P2P_PUB_AF_ACTION 0x09
+#define P2P_AF_CATEGORY 0x7f
+#define P2P_OUI "\x50\x6F\x9A" /* P2P OUI */
+#define P2P_OUI_LEN 3 /* P2P OUI length */
+
+/* Action Frame Constants */
+#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action */
+#define DOT11_ACTION_CAT_OFF 0 /* category offset */
+#define DOT11_ACTION_ACT_OFF 1 /* action offset */
+
+#define P2P_AF_DWELL_TIME 200
+#define P2P_AF_MIN_DWELL_TIME 100
+#define P2P_AF_MED_DWELL_TIME 400
+#define P2P_AF_LONG_DWELL_TIME 1000
+#define P2P_AF_TX_MAX_RETRY 1
+#define P2P_AF_MAX_WAIT_TIME 2000
+#define P2P_INVALID_CHANNEL -1
+#define P2P_CHANNEL_SYNC_RETRY 5
+#define P2P_AF_FRM_SCAN_MAX_WAIT 1500
+#define P2P_DEFAULT_SLEEP_TIME_VSDB 200
+
+/* WiFi P2P Public Action Frame OUI Subtypes */
+#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */
+#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */
+#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */
+#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */
+#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */
+#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */
+#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */
+#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */
+#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */
+#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */
+
+/* WiFi P2P Action Frame OUI Subtypes */
+#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */
+#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */
+#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */
+#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */
+
+/* P2P Service Discovery related */
+#define P2PSD_ACTION_CATEGORY 0x04 /* Public action frame */
+#define P2PSD_ACTION_ID_GAS_IREQ 0x0a /* GAS Initial Request AF */
+#define P2PSD_ACTION_ID_GAS_IRESP 0x0b /* GAS Initial Response AF */
+#define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */
+#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */
+
+/**
+ * struct brcmf_p2p_disc_st_le - set discovery state in firmware.
+ *
+ * @state: requested discovery state (see enum brcmf_p2p_disc_state).
+ * @chspec: channel parameter for %WL_P2P_DISC_ST_LISTEN state.
+ * @dwell: dwell time in ms for %WL_P2P_DISC_ST_LISTEN state.
+ */
+struct brcmf_p2p_disc_st_le {
+ u8 state;
+ __le16 chspec;
+ __le16 dwell;
+};
+
+/**
+ * enum brcmf_p2p_disc_state - P2P discovery state values
+ *
+ * @WL_P2P_DISC_ST_SCAN: P2P discovery with wildcard SSID and P2P IE.
+ * @WL_P2P_DISC_ST_LISTEN: P2P discovery off-channel for specified time.
+ * @WL_P2P_DISC_ST_SEARCH: P2P discovery with P2P wildcard SSID and P2P IE.
+ */
+enum brcmf_p2p_disc_state {
+ WL_P2P_DISC_ST_SCAN,
+ WL_P2P_DISC_ST_LISTEN,
+ WL_P2P_DISC_ST_SEARCH
+};
+
+/**
+ * struct brcmf_p2p_scan_le - P2P specific scan request.
+ *
+ * @type: type of scan method requested (values: 'E' or 'S').
+ * @reserved: reserved (ignored).
+ * @eparams: parameters used for type 'E'.
+ * @sparams: parameters used for type 'S'.
+ */
+struct brcmf_p2p_scan_le {
+ u8 type;
+ u8 reserved[3];
+ union {
+ struct brcmf_escan_params_le eparams;
+ struct brcmf_scan_params_le sparams;
+ };
+};
+
+/**
+ * struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame
+ *
+ * @category: P2P_PUB_AF_CATEGORY
+ * @action: P2P_PUB_AF_ACTION
+ * @oui[3]: P2P_OUI
+ * @oui_type: OUI type - P2P_VER
+ * @subtype: OUI subtype - P2P_TYPE_*
+ * @dialog_token: nonzero, identifies req/rsp transaction
+ * @elts[1]: Variable length information elements.
+ */
+struct brcmf_p2p_pub_act_frame {
+ u8 category;
+ u8 action;
+ u8 oui[3];
+ u8 oui_type;
+ u8 subtype;
+ u8 dialog_token;
+ u8 elts[1];
+};
+
+/**
+ * struct brcmf_p2p_action_frame - WiFi P2P Action Frame
+ *
+ * @category: P2P_AF_CATEGORY
+ * @OUI[3]: OUI - P2P_OUI
+ * @type: OUI Type - P2P_VER
+ * @subtype: OUI Subtype - P2P_AF_*
+ * @dialog_token: nonzero, identifies req/resp tranaction
+ * @elts[1]: Variable length information elements.
+ */
+struct brcmf_p2p_action_frame {
+ u8 category;
+ u8 oui[3];
+ u8 type;
+ u8 subtype;
+ u8 dialog_token;
+ u8 elts[1];
+};
+
+/**
+ * struct brcmf_p2psd_gas_pub_act_frame - Wi-Fi GAS Public Action Frame
+ *
+ * @category: 0x04 Public Action Frame
+ * @action: 0x6c Advertisement Protocol
+ * @dialog_token: nonzero, identifies req/rsp transaction
+ * @query_data[1]: Query Data. SD gas ireq SD gas iresp
+ */
+struct brcmf_p2psd_gas_pub_act_frame {
+ u8 category;
+ u8 action;
+ u8 dialog_token;
+ u8 query_data[1];
+};
+
+/**
+ * struct brcmf_config_af_params - Action Frame Parameters for tx.
+ *
+ * @mpc_onoff: To make sure to send successfully action frame, we have to
+ * turn off mpc 0: off, 1: on, (-1): do nothing
+ * @search_channel: 1: search peer's channel to send af
+ * extra_listen: keep the dwell time to get af response frame.
+ */
+struct brcmf_config_af_params {
+ s32 mpc_onoff;
+ bool search_channel;
+ bool extra_listen;
+};
+
+/**
+ * brcmf_p2p_is_pub_action() - true if p2p public type frame.
+ *
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Determine if action frame is p2p public action type
+ */
+static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len)
+{
+ struct brcmf_p2p_pub_act_frame *pact_frm;
+
+ if (frame == NULL)
+ return false;
+
+ pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
+ if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1)
+ return false;
+
+ if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
+ pact_frm->action == P2P_PUB_AF_ACTION &&
+ pact_frm->oui_type == P2P_VER &&
+ memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
+ return true;
+
+ return false;
+}
+
+/**
+ * brcmf_p2p_is_p2p_action() - true if p2p action type frame.
+ *
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Determine if action frame is p2p action type
+ */
+static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len)
+{
+ struct brcmf_p2p_action_frame *act_frm;
+
+ if (frame == NULL)
+ return false;
+
+ act_frm = (struct brcmf_p2p_action_frame *)frame;
+ if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1)
+ return false;
+
+ if (act_frm->category == P2P_AF_CATEGORY &&
+ act_frm->type == P2P_VER &&
+ memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0)
+ return true;
+
+ return false;
+}
+
+/**
+ * brcmf_p2p_is_gas_action() - true if p2p gas action type frame.
+ *
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Determine if action frame is p2p gas action type
+ */
+static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len)
+{
+ struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
+
+ if (frame == NULL)
+ return false;
+
+ sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
+ if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1)
+ return false;
+
+ if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
+ return false;
+
+ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
+ return true;
+
+ return false;
+}
+
+/**
+ * brcmf_p2p_print_actframe() - debug print routine.
+ *
+ * @tx: Received or to be transmitted
+ * @frame: action frame data.
+ * @frame_len: length of action frame data.
+ *
+ * Print information about the p2p action frame
+ */
+
+#ifdef DEBUG
+
+static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
+{
+ struct brcmf_p2p_pub_act_frame *pact_frm;
+ struct brcmf_p2p_action_frame *act_frm;
+ struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
+
+ if (!frame || frame_len <= 2)
+ return;
+
+ if (brcmf_p2p_is_pub_action(frame, frame_len)) {
+ pact_frm = (struct brcmf_p2p_pub_act_frame *)frame;
+ switch (pact_frm->subtype) {
+ case P2P_PAF_GON_REQ:
+ brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Req Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_PAF_GON_RSP:
+ brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Rsp Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_PAF_GON_CONF:
+ brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Confirm Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_PAF_INVITE_REQ:
+ brcmf_dbg(TRACE, "%s P2P Invitation Request Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_PAF_INVITE_RSP:
+ brcmf_dbg(TRACE, "%s P2P Invitation Response Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_PAF_DEVDIS_REQ:
+ brcmf_dbg(TRACE, "%s P2P Device Discoverability Request Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_PAF_DEVDIS_RSP:
+ brcmf_dbg(TRACE, "%s P2P Device Discoverability Response Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_PAF_PROVDIS_REQ:
+ brcmf_dbg(TRACE, "%s P2P Provision Discovery Request Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_PAF_PROVDIS_RSP:
+ brcmf_dbg(TRACE, "%s P2P Provision Discovery Response Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ default:
+ brcmf_dbg(TRACE, "%s Unknown P2P Public Action Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ }
+ } else if (brcmf_p2p_is_p2p_action(frame, frame_len)) {
+ act_frm = (struct brcmf_p2p_action_frame *)frame;
+ switch (act_frm->subtype) {
+ case P2P_AF_NOTICE_OF_ABSENCE:
+ brcmf_dbg(TRACE, "%s P2P Notice of Absence Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_AF_PRESENCE_REQ:
+ brcmf_dbg(TRACE, "%s P2P Presence Request Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_AF_PRESENCE_RSP:
+ brcmf_dbg(TRACE, "%s P2P Presence Response Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2P_AF_GO_DISC_REQ:
+ brcmf_dbg(TRACE, "%s P2P Discoverability Request Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ default:
+ brcmf_dbg(TRACE, "%s Unknown P2P Action Frame\n",
+ (tx) ? "TX" : "RX");
+ }
+
+ } else if (brcmf_p2p_is_gas_action(frame, frame_len)) {
+ sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
+ switch (sd_act_frm->action) {
+ case P2PSD_ACTION_ID_GAS_IREQ:
+ brcmf_dbg(TRACE, "%s P2P GAS Initial Request\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2PSD_ACTION_ID_GAS_IRESP:
+ brcmf_dbg(TRACE, "%s P2P GAS Initial Response\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2PSD_ACTION_ID_GAS_CREQ:
+ brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n",
+ (tx) ? "TX" : "RX");
+ break;
+ case P2PSD_ACTION_ID_GAS_CRESP:
+ brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n",
+ (tx) ? "TX" : "RX");
+ break;
+ default:
+ brcmf_dbg(TRACE, "%s Unknown P2P GAS Frame\n",
+ (tx) ? "TX" : "RX");
+ break;
+ }
+ }
+}
+
+#else
+
+static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
+{
+}
+
+#endif
+
+
+/**
+ * brcmf_p2p_chnr_to_chspec() - convert channel number to chanspec.
+ *
+ * @channel: channel number
+ */
+static u16 brcmf_p2p_chnr_to_chspec(u16 channel)
+{
+ u16 chanspec;
+
+ chanspec = channel & WL_CHANSPEC_CHAN_MASK;
+
+ if (channel <= CH_MAX_2G_CHANNEL)
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_5G;
+
+ chanspec |= WL_CHANSPEC_BW_20;
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+ return chanspec;
+}
+
+
+/**
+ * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation.
+ *
+ * @ifp: ifp to use for iovars (primary).
+ * @p2p_mac: mac address to configure for p2p_da_override
+ */
+static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
+{
+ s32 ret = 0;
+
+ brcmf_fil_iovar_int_set(ifp, "apsta", 1);
+
+ /* In case of COB type, firmware has default mac address
+ * After Initializing firmware, we have to set current mac address to
+ * firmware for P2P device address
+ */
+ ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac,
+ ETH_ALEN);
+ if (ret)
+ brcmf_err("failed to update device address ret %d\n", ret);
+
+ return ret;
+}
+
+/**
+ * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P.
+ *
+ * @p2p: P2P specific data.
+ *
+ * P2P needs mac addresses for P2P device and interface. These are
+ * derived from the primary net device, ie. the permanent ethernet
+ * address of the device.
+ */
+static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p)
+{
+ struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+ struct brcmf_if *p2p_ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
+
+ /* Generate the P2P Device Address. This consists of the device's
+ * primary MAC address with the locally administered bit set.
+ */
+ memcpy(p2p->dev_addr, pri_ifp->mac_addr, ETH_ALEN);
+ p2p->dev_addr[0] |= 0x02;
+ memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+
+ /* Generate the P2P Interface Address. If the discovery and connection
+ * BSSCFGs need to simultaneously co-exist, then this address must be
+ * different from the P2P Device Address, but also locally administered.
+ */
+ memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN);
+ p2p->int_addr[4] ^= 0x80;
+}
+
+/**
+ * brcmf_p2p_scan_is_p2p_request() - is cfg80211 scan request a P2P scan.
+ *
+ * @request: the scan request as received from cfg80211.
+ *
+ * returns true if one of the ssids in the request matches the
+ * P2P wildcard ssid; otherwise returns false.
+ */
+static bool brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request *request)
+{
+ struct cfg80211_ssid *ssids = request->ssids;
+ int i;
+
+ for (i = 0; i < request->n_ssids; i++) {
+ if (ssids[i].ssid_len != BRCMF_P2P_WILDCARD_SSID_LEN)
+ continue;
+
+ brcmf_dbg(INFO, "comparing ssid \"%s\"", ssids[i].ssid);
+ if (!memcmp(BRCMF_P2P_WILDCARD_SSID, ssids[i].ssid,
+ BRCMF_P2P_WILDCARD_SSID_LEN))
+ return true;
+ }
+ return false;
+}
+
+/**
+ * brcmf_p2p_set_discover_state - set discover state in firmware.
+ *
+ * @ifp: low-level interface object.
+ * @state: discover state to set.
+ * @chanspec: channel parameters (for state @WL_P2P_DISC_ST_LISTEN only).
+ * @listen_ms: duration to listen (for state @WL_P2P_DISC_ST_LISTEN only).
+ */
+static s32 brcmf_p2p_set_discover_state(struct brcmf_if *ifp, u8 state,
+ u16 chanspec, u16 listen_ms)
+{
+ struct brcmf_p2p_disc_st_le discover_state;
+ s32 ret = 0;
+ brcmf_dbg(TRACE, "enter\n");
+
+ discover_state.state = state;
+ discover_state.chspec = cpu_to_le16(chanspec);
+ discover_state.dwell = cpu_to_le16(listen_ms);
+ ret = brcmf_fil_bsscfg_data_set(ifp, "p2p_state", &discover_state,
+ sizeof(discover_state));
+ return ret;
+}
+
+/**
+ * brcmf_p2p_deinit_discovery() - disable P2P device discovery.
+ *
+ * @p2p: P2P specific data.
+ *
+ * Resets the discovery state and disables it in firmware.
+ */
+static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
+{
+ struct brcmf_cfg80211_vif *vif;
+
+ brcmf_dbg(TRACE, "enter\n");
+
+ /* Set the discovery state to SCAN */
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ (void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+
+ /* Disable P2P discovery in the firmware */
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+ (void)brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 0);
+
+ return 0;
+}
+
+/**
+ * brcmf_p2p_enable_discovery() - initialize and configure discovery.
+ *
+ * @p2p: P2P specific data.
+ *
+ * Initializes the discovery device and configure the virtual interface.
+ */
+static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p)
+{
+ struct brcmf_cfg80211_vif *vif;
+ s32 ret = 0;
+
+ brcmf_dbg(TRACE, "enter\n");
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (!vif) {
+ brcmf_err("P2P config device not available\n");
+ ret = -EPERM;
+ goto exit;
+ }
+
+ if (test_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status)) {
+ brcmf_dbg(INFO, "P2P config device already configured\n");
+ goto exit;
+ }
+
+ /* Re-initialize P2P Discovery in the firmware */
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+ ret = brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 1);
+ if (ret < 0) {
+ brcmf_err("set p2p_disc error\n");
+ goto exit;
+ }
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ ret = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+ if (ret < 0) {
+ brcmf_err("unable to set WL_P2P_DISC_ST_SCAN\n");
+ goto exit;
+ }
+
+ /*
+ * Set wsec to any non-zero value in the discovery bsscfg
+ * to ensure our P2P probe responses have the privacy bit
+ * set in the 802.11 WPA IE. Some peer devices may not
+ * initiate WPS with us if this bit is not set.
+ */
+ ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED);
+ if (ret < 0) {
+ brcmf_err("wsec error %d\n", ret);
+ goto exit;
+ }
+
+ set_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status);
+exit:
+ return ret;
+}
+
+/**
+ * brcmf_p2p_escan() - initiate a P2P scan.
+ *
+ * @p2p: P2P specific data.
+ * @num_chans: number of channels to scan.
+ * @chanspecs: channel parameters for @num_chans channels.
+ * @search_state: P2P discover state to use.
+ * @action: scan action to pass to firmware.
+ * @bss_type: type of P2P bss.
+ */
+static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,
+ u16 chanspecs[], s32 search_state, u16 action,
+ enum p2p_bss_type bss_type)
+{
+ s32 ret = 0;
+ s32 memsize = offsetof(struct brcmf_p2p_scan_le,
+ eparams.params_le.channel_list);
+ s32 nprobes;
+ s32 active;
+ u32 i;
+ u8 *memblk;
+ struct brcmf_cfg80211_vif *vif;
+ struct brcmf_p2p_scan_le *p2p_params;
+ struct brcmf_scan_params_le *sparams;
+ struct brcmf_ssid ssid;
+
+ memsize += num_chans * sizeof(__le16);
+ memblk = kzalloc(memsize, GFP_KERNEL);
+ if (!memblk)
+ return -ENOMEM;
+
+ vif = p2p->bss_idx[bss_type].vif;
+ if (vif == NULL) {
+ brcmf_err("no vif for bss type %d\n", bss_type);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ switch (search_state) {
+ case WL_P2P_DISC_ST_SEARCH:
+ /*
+ * If we in SEARCH STATE, we don't need to set SSID explictly
+ * because dongle use P2P WILDCARD internally by default
+ */
+ /* use null ssid */
+ ssid.SSID_len = 0;
+ memset(ssid.SSID, 0, sizeof(ssid.SSID));
+ break;
+ case WL_P2P_DISC_ST_SCAN:
+ /*
+ * wpa_supplicant has p2p_find command with type social or
+ * progressive. For progressive, we need to set the ssid to
+ * P2P WILDCARD because we just do broadcast scan unless
+ * setting SSID.
+ */
+ ssid.SSID_len = BRCMF_P2P_WILDCARD_SSID_LEN;
+ memcpy(ssid.SSID, BRCMF_P2P_WILDCARD_SSID, ssid.SSID_len);
+ break;
+ default:
+ brcmf_err(" invalid search state %d\n", search_state);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ brcmf_p2p_set_discover_state(vif->ifp, search_state, 0, 0);
+
+ /*
+ * set p2p scan parameters.
+ */
+ p2p_params = (struct brcmf_p2p_scan_le *)memblk;
+ p2p_params->type = 'E';
+
+ /* determine the scan engine parameters */
+ sparams = &p2p_params->eparams.params_le;
+ sparams->bss_type = DOT11_BSSTYPE_ANY;
+ if (p2p->cfg->active_scan)
+ sparams->scan_type = 0;
+ else
+ sparams->scan_type = 1;
+
+ memset(&sparams->bssid, 0xFF, ETH_ALEN);
+ if (ssid.SSID_len)
+ memcpy(sparams->ssid_le.SSID, ssid.SSID, ssid.SSID_len);
+ sparams->ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
+ sparams->home_time = cpu_to_le32(P2PAPI_SCAN_HOME_TIME_MS);
+
+ /*
+ * SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan
+ * supported by the supplicant.
+ */
+ if (num_chans == SOCIAL_CHAN_CNT || num_chans == (SOCIAL_CHAN_CNT + 1))
+ active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS;
+ else if (num_chans == AF_PEER_SEARCH_CNT)
+ active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS;
+ else if (wl_get_vif_state_all(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED))
+ active = -1;
+ else
+ active = P2PAPI_SCAN_DWELL_TIME_MS;
+
+ /* Override scan params to find a peer for a connection */
+ if (num_chans == 1) {
+ active = WL_SCAN_CONNECT_DWELL_TIME_MS;
+ /* WAR to sync with presence period of VSDB GO.
+ * send probe request more frequently
+ */
+ nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS;
+ } else {
+ nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS;
+ }
+
+ if (nprobes <= 0)
+ nprobes = 1;
+
+ brcmf_dbg(INFO, "nprobes # %d, active_time %d\n", nprobes, active);
+ sparams->active_time = cpu_to_le32(active);
+ sparams->nprobes = cpu_to_le32(nprobes);
+ sparams->passive_time = cpu_to_le32(-1);
+ sparams->channel_num = cpu_to_le32(num_chans &
+ BRCMF_SCAN_PARAMS_COUNT_MASK);
+ for (i = 0; i < num_chans; i++)
+ sparams->channel_list[i] = cpu_to_le16(chanspecs[i]);
+
+ /* set the escan specific parameters */
+ p2p_params->eparams.version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
+ p2p_params->eparams.action = cpu_to_le16(action);
+ p2p_params->eparams.sync_id = cpu_to_le16(0x1234);
+ /* perform p2p scan on primary device */
+ ret = brcmf_fil_bsscfg_data_set(vif->ifp, "p2p_scan", memblk, memsize);
+ if (!ret)
+ set_bit(BRCMF_SCAN_STATUS_BUSY, &p2p->cfg->scan_status);
+exit:
+ kfree(memblk);
+ return ret;
+}
+
+/**
+ * brcmf_p2p_run_escan() - escan callback for peer-to-peer.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @ndev: net device for which scan is requested.
+ * @request: scan request from cfg80211.
+ * @action: scan action.
+ *
+ * Determines the P2P discovery state based to scan request parameters and
+ * validates the channels in the request.
+ */
+static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
+ struct net_device *ndev,
+ struct cfg80211_scan_request *request,
+ u16 action)
+{
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ s32 err = 0;
+ s32 search_state = WL_P2P_DISC_ST_SCAN;
+ struct brcmf_cfg80211_vif *vif;
+ struct net_device *dev = NULL;
+ int i, num_nodfs = 0;
+ u16 *chanspecs;
+
+ brcmf_dbg(TRACE, "enter\n");
+
+ if (!request) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ if (request->n_channels) {
+ chanspecs = kcalloc(request->n_channels, sizeof(*chanspecs),
+ GFP_KERNEL);
+ if (!chanspecs) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
+ if (vif)
+ dev = vif->wdev.netdev;
+ if (request->n_channels == 3 &&
+ request->channels[0]->hw_value == SOCIAL_CHAN_1 &&
+ request->channels[1]->hw_value == SOCIAL_CHAN_2 &&
+ request->channels[2]->hw_value == SOCIAL_CHAN_3) {
+ /* SOCIAL CHANNELS 1, 6, 11 */
+ search_state = WL_P2P_DISC_ST_SEARCH;
+ brcmf_dbg(INFO, "P2P SEARCH PHASE START\n");
+ } else if (dev != NULL && vif->mode == WL_MODE_AP) {
+ /* If you are already a GO, then do SEARCH only */
+ brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n");
+ search_state = WL_P2P_DISC_ST_SEARCH;
+ } else {
+ brcmf_dbg(INFO, "P2P SCAN STATE START\n");
+ }
+
+ /*
+ * no P2P scanning on passive or DFS channels.
+ */
+ for (i = 0; i < request->n_channels; i++) {
+ struct ieee80211_channel *chan = request->channels[i];
+
+ if (chan->flags & (IEEE80211_CHAN_RADAR |
+ IEEE80211_CHAN_PASSIVE_SCAN))
+ continue;
+
+ chanspecs[i] = channel_to_chanspec(chan);
+ brcmf_dbg(INFO, "%d: chan=%d, channel spec=%x\n",
+ num_nodfs, chan->hw_value, chanspecs[i]);
+ num_nodfs++;
+ }
+ err = brcmf_p2p_escan(p2p, num_nodfs, chanspecs, search_state,
+ action, P2PAPI_BSSCFG_DEVICE);
+ }
+exit:
+ if (err)
+ brcmf_err("error (%d)\n", err);
+ return err;
+}
+
+
+/**
+ * brcmf_p2p_find_listen_channel() - find listen channel in ie string.
+ *
+ * @ie: string of information elements.
+ * @ie_len: length of string.
+ *
+ * Scan ie for p2p ie and look for attribute 6 channel. If available determine
+ * channel and return it.
+ */
+static s32 brcmf_p2p_find_listen_channel(const u8 *ie, u32 ie_len)
+{
+ u8 channel_ie[5];
+ s32 listen_channel;
+ s32 err;
+
+ err = cfg80211_get_p2p_attr(ie, ie_len,
+ IEEE80211_P2P_ATTR_LISTEN_CHANNEL,
+ channel_ie, sizeof(channel_ie));
+ if (err < 0)
+ return err;
+
+ /* listen channel subel length format: */
+ /* 3(country) + 1(op. class) + 1(chan num) */
+ listen_channel = (s32)channel_ie[3 + 1];
+
+ if (listen_channel == SOCIAL_CHAN_1 ||
+ listen_channel == SOCIAL_CHAN_2 ||
+ listen_channel == SOCIAL_CHAN_3) {
+ brcmf_dbg(INFO, "Found my Listen Channel %d\n", listen_channel);
+ return listen_channel;
+ }
+
+ return -EPERM;
+}
+
+
+/**
+ * brcmf_p2p_scan_prep() - prepare scan based on request.
+ *
+ * @wiphy: wiphy device.
+ * @request: scan request from cfg80211.
+ * @vif: vif on which scan request is to be executed.
+ *
+ * Prepare the scan appropriately for type of scan requested. Overrides the
+ * escan .run() callback for peer-to-peer scanning.
+ */
+int brcmf_p2p_scan_prep(struct wiphy *wiphy,
+ struct cfg80211_scan_request *request,
+ struct brcmf_cfg80211_vif *vif)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ int err = 0;
+
+ if (brcmf_p2p_scan_is_p2p_request(request)) {
+ /* find my listen channel */
+ err = brcmf_p2p_find_listen_channel(request->ie,
+ request->ie_len);
+ if (err < 0)
+ return err;
+
+ p2p->afx_hdl.my_listen_chan = err;
+
+ clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+ brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
+
+ err = brcmf_p2p_enable_discovery(p2p);
+ if (err)
+ return err;
+
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+
+ /* override .run_escan() callback. */
+ cfg->escan_info.run = brcmf_p2p_run_escan;
+ }
+ err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
+ request->ie, request->ie_len);
+ return err;
+}
+
+
+/**
+ * brcmf_p2p_discover_listen() - set firmware to discover listen state.
+ *
+ * @p2p: p2p device.
+ * @channel: channel nr for discover listen.
+ * @duration: time in ms to stay on channel.
+ *
+ */
+static s32
+brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration)
+{
+ struct brcmf_cfg80211_vif *vif;
+ s32 err = 0;
+ u16 chanspec;
+
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (!vif) {
+ brcmf_err("Discovery is not set, so we have nothing to do\n");
+ err = -EPERM;
+ goto exit;
+ }
+
+ if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status)) {
+ brcmf_err("Previous LISTEN is not completed yet\n");
+ /* WAR: prevent cookie mismatch in wpa_supplicant return OK */
+ goto exit;
+ }
+
+ chanspec = brcmf_p2p_chnr_to_chspec(channel);
+ err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN,
+ chanspec, (u16)duration);
+ if (!err) {
+ set_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status);
+ p2p->remain_on_channel_cookie++;
+ }
+exit:
+ return err;
+}
+
+
+/**
+ * brcmf_p2p_remain_on_channel() - put device on channel and stay there.
+ *
+ * @wiphy: wiphy device.
+ * @channel: channel to stay on.
+ * @duration: time in ms to remain on channel.
+ *
+ */
+int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+ struct ieee80211_channel *channel,
+ unsigned int duration, u64 *cookie)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ s32 err;
+ u16 channel_nr;
+
+ channel_nr = ieee80211_frequency_to_channel(channel->center_freq);
+ brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n", channel_nr,
+ duration);
+
+ err = brcmf_p2p_enable_discovery(p2p);
+ if (err)
+ goto exit;
+ err = brcmf_p2p_discover_listen(p2p, channel_nr, duration);
+ if (err)
+ goto exit;
+
+ memcpy(&p2p->remain_on_channel, channel, sizeof(*channel));
+ *cookie = p2p->remain_on_channel_cookie;
+ cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL);
+
+exit:
+ return err;
+}
+
+
+/**
+ * brcmf_p2p_notify_listen_complete() - p2p listen has completed.
+ *
+ * @ifp: interfac control.
+ * @e: event message. Not used, to make it usable for fweh event dispatcher.
+ * @data: payload of message. Not used.
+ *
+ */
+int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e,
+ void *data)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+
+ brcmf_dbg(TRACE, "Enter\n");
+ if (test_and_clear_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN,
+ &p2p->status)) {
+ if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+ &p2p->status)) {
+ clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+ &p2p->status);
+ brcmf_dbg(INFO, "Listen DONE, wake up wait_next_af\n");
+ complete(&p2p->wait_next_af);
+ }
+
+ cfg80211_remain_on_channel_expired(&ifp->vif->wdev,
+ p2p->remain_on_channel_cookie,
+ &p2p->remain_on_channel,
+ GFP_KERNEL);
+ }
+ return 0;
+}
+
+
+/**
+ * brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state.
+ *
+ * @ifp: interfac control.
+ *
+ */
+void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp)
+{
+ if (!ifp)
+ return;
+ brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
+ brcmf_p2p_notify_listen_complete(ifp, NULL, NULL);
+}
+
+
+/**
+ * brcmf_p2p_act_frm_search() - search function for action frame.
+ *
+ * @p2p: p2p device.
+ * channel: channel on which action frame is to be trasmitted.
+ *
+ * search function to reach at common channel to send action frame. When
+ * channel is 0 then all social channels will be used to send af
+ */
+static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel)
+{
+ s32 err;
+ u32 channel_cnt;
+ u16 *default_chan_list;
+ u32 i;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (channel)
+ channel_cnt = AF_PEER_SEARCH_CNT;
+ else
+ channel_cnt = SOCIAL_CHAN_CNT;
+ default_chan_list = kzalloc(channel_cnt * sizeof(*default_chan_list),
+ GFP_KERNEL);
+ if (default_chan_list == NULL) {
+ brcmf_err("channel list allocation failed\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+ if (channel) {
+ /* insert same channel to the chan_list */
+ for (i = 0; i < channel_cnt; i++)
+ default_chan_list[i] =
+ brcmf_p2p_chnr_to_chspec(channel);
+ } else {
+ default_chan_list[0] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_1);
+ default_chan_list[1] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_2);
+ default_chan_list[2] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_3);
+ }
+ err = brcmf_p2p_escan(p2p, channel_cnt, default_chan_list,
+ WL_P2P_DISC_ST_SEARCH, WL_ESCAN_ACTION_START,
+ P2PAPI_BSSCFG_DEVICE);
+ kfree(default_chan_list);
+exit:
+ return err;
+}
+
+
+/**
+ * brcmf_p2p_afx_handler() - afx worker thread.
+ *
+ * @work:
+ *
+ */
+static void brcmf_p2p_afx_handler(struct work_struct *work)
+{
+ struct afx_hdl *afx_hdl = container_of(work, struct afx_hdl, afx_work);
+ struct brcmf_p2p_info *p2p = container_of(afx_hdl,
+ struct brcmf_p2p_info,
+ afx_hdl);
+ s32 err;
+
+ if (!afx_hdl->is_active)
+ return;
+
+ if (afx_hdl->is_listen && afx_hdl->my_listen_chan)
+ /* 100ms ~ 300ms */
+ err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan,
+ 100 * (1 + (random32() % 3)));
+ else
+ err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan);
+
+ if (err) {
+ brcmf_err("ERROR occurred! value is (%d)\n", err);
+ if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+ &p2p->status))
+ complete(&afx_hdl->act_frm_scan);
+ }
+}
+
+
+/**
+ * brcmf_p2p_af_searching_channel() - search channel.
+ *
+ * @p2p: p2p device info struct.
+ *
+ */
+static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p)
+{
+ struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+ struct brcmf_cfg80211_vif *pri_vif;
+ unsigned long duration;
+ s32 retry;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ pri_vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+
+ INIT_COMPLETION(afx_hdl->act_frm_scan);
+ set_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);
+ afx_hdl->is_active = true;
+ afx_hdl->peer_chan = P2P_INVALID_CHANNEL;
+
+ /* Loop to wait until we find a peer's channel or the
+ * pending action frame tx is cancelled.
+ */
+ retry = 0;
+ duration = msecs_to_jiffies(P2P_AF_FRM_SCAN_MAX_WAIT);
+ while ((retry < P2P_CHANNEL_SYNC_RETRY) &&
+ (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) {
+ afx_hdl->is_listen = false;
+ brcmf_dbg(TRACE, "Scheduling action frame for sending.. (%d)\n",
+ retry);
+ /* search peer on peer's listen channel */
+ schedule_work(&afx_hdl->afx_work);
+ wait_for_completion_timeout(&afx_hdl->act_frm_scan, duration);
+ if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
+ (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+ &p2p->status)))
+ break;
+
+ if (afx_hdl->my_listen_chan) {
+ brcmf_dbg(TRACE, "Scheduling listen peer, channel=%d\n",
+ afx_hdl->my_listen_chan);
+ /* listen on my listen channel */
+ afx_hdl->is_listen = true;
+ schedule_work(&afx_hdl->afx_work);
+ wait_for_completion_timeout(&afx_hdl->act_frm_scan,
+ duration);
+ }
+ if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) ||
+ (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+ &p2p->status)))
+ break;
+ retry++;
+
+ /* if sta is connected or connecting, sleep for a while before
+ * retry af tx or finding a peer
+ */
+ if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &pri_vif->sme_state) ||
+ test_bit(BRCMF_VIF_STATUS_CONNECTING, &pri_vif->sme_state))
+ msleep(P2P_DEFAULT_SLEEP_TIME_VSDB);
+ }
+
+ brcmf_dbg(TRACE, "Completed search/listen peer_chan=%d\n",
+ afx_hdl->peer_chan);
+ afx_hdl->is_active = false;
+
+ clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);
+
+ return afx_hdl->peer_chan;
+}
+
+
+/**
+ * brcmf_p2p_scan_finding_common_channel() - was escan used for finding channel
+ *
+ * @cfg: common configuration struct.
+ * @bi: bss info struct, result from scan.
+ *
+ */
+bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_bss_info_le *bi)
+
+{
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+ u8 *ie;
+ s32 err;
+ u8 p2p_dev_addr[ETH_ALEN];
+
+ if (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status))
+ return false;
+
+ if (bi == NULL) {
+ brcmf_dbg(TRACE, "ACTION FRAME SCAN Done\n");
+ if (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)
+ complete(&afx_hdl->act_frm_scan);
+ return true;
+ }
+
+ ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
+ memset(p2p_dev_addr, 0, sizeof(p2p_dev_addr));
+ err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length),
+ IEEE80211_P2P_ATTR_DEVICE_INFO,
+ p2p_dev_addr, sizeof(p2p_dev_addr));
+ if (err < 0)
+ err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length),
+ IEEE80211_P2P_ATTR_DEVICE_ID,
+ p2p_dev_addr, sizeof(p2p_dev_addr));
+ if ((err >= 0) &&
+ (!memcmp(p2p_dev_addr, afx_hdl->tx_dst_addr, ETH_ALEN))) {
+ afx_hdl->peer_chan = bi->ctl_ch ? bi->ctl_ch :
+ CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+ brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n",
+ afx_hdl->tx_dst_addr, afx_hdl->peer_chan);
+ complete(&afx_hdl->act_frm_scan);
+ }
+ return true;
+}
+
+/**
+ * brcmf_p2p_stop_wait_next_action_frame() - finish scan if af tx complete.
+ *
+ * @cfg: common configuration struct.
+ *
+ */
+static void
+brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct net_device *ndev = cfg->escan_info.ndev;
+
+ if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) &&
+ (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) ||
+ test_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status))) {
+ brcmf_dbg(TRACE, "*** Wake UP ** abort actframe iovar\n");
+ /* if channel is not zero, "actfame" uses off channel scan.
+ * So abort scan for off channel completion.
+ */
+ if (p2p->af_sent_channel)
+ brcmf_notify_escan_complete(cfg, ndev, true, true);
+ } else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+ &p2p->status)) {
+ brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n");
+ /* So abort scan to cancel listen */
+ brcmf_notify_escan_complete(cfg, ndev, true, true);
+ }
+}
+
+
+/**
+ * brcmf_p2p_gon_req_collision() - Check if go negotiaton collission
+ *
+ * @p2p: p2p device info struct.
+ *
+ * return true if recevied action frame is to be dropped.
+ */
+static bool
+brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac)
+{
+ struct brcmf_cfg80211_info *cfg = p2p->cfg;
+ struct brcmf_if *ifp;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (!test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) ||
+ !p2p->gon_req_action)
+ return false;
+
+ brcmf_dbg(TRACE, "GO Negotiation Request COLLISION !!!\n");
+ /* if sa(peer) addr is less than da(my) addr, then this device
+ * process peer's gon request and block to send gon req.
+ * if not (sa addr > da addr),
+ * this device will process gon request and drop gon req of peer.
+ */
+ ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
+ if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) {
+ brcmf_dbg(INFO, "Block transmit gon req !!!\n");
+ p2p->block_gon_req_tx = true;
+ /* if we are finding a common channel for sending af,
+ * do not scan more to block to send current gon req
+ */
+ if (test_and_clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+ &p2p->status))
+ complete(&p2p->afx_hdl.act_frm_scan);
+ if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+ &p2p->status))
+ brcmf_p2p_stop_wait_next_action_frame(cfg);
+ return false;
+ }
+
+ /* drop gon request of peer to process gon request by this device. */
+ brcmf_dbg(INFO, "Drop received gon req !!!\n");
+
+ return true;
+}
+
+
+/**
+ * brcmf_p2p_notify_action_frame_rx() - received action frame.
+ *
+ * @ifp: interfac control.
+ * @e: event message. Not used, to make it usable for fweh event dispatcher.
+ * @data: payload of message, containing action frame data.
+ *
+ */
+int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e,
+ void *data)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+ struct wireless_dev *wdev;
+ u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data);
+ struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
+ u8 *frame = (u8 *)(rxframe + 1);
+ struct brcmf_p2p_pub_act_frame *act_frm;
+ struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
+ u16 chanspec = be16_to_cpu(rxframe->chanspec);
+ struct ieee80211_mgmt *mgmt_frame;
+ s32 freq;
+ u16 mgmt_type;
+ u8 action;
+
+ /* Check if wpa_supplicant has registered for this frame */
+ brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg);
+ mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4;
+ if ((ifp->vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
+ return 0;
+
+ brcmf_p2p_print_actframe(false, frame, mgmt_frame_len);
+
+ action = P2P_PAF_SUBTYPE_INVALID;
+ if (brcmf_p2p_is_pub_action(frame, mgmt_frame_len)) {
+ act_frm = (struct brcmf_p2p_pub_act_frame *)frame;
+ action = act_frm->subtype;
+ if ((action == P2P_PAF_GON_REQ) &&
+ (brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) {
+ if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
+ &p2p->status) &&
+ (memcmp(afx_hdl->tx_dst_addr, e->addr,
+ ETH_ALEN) == 0)) {
+ afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec);
+ brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n",
+ afx_hdl->peer_chan);
+ complete(&afx_hdl->act_frm_scan);
+ }
+ return 0;
+ }
+ /* After complete GO Negotiation, roll back to mpc mode */
+ if ((action == P2P_PAF_GON_CONF) ||
+ (action == P2P_PAF_PROVDIS_RSP))
+ brcmf_set_mpc(ifp->ndev, 1);
+ if (action == P2P_PAF_GON_CONF) {
+ brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
+ clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+ }
+ } else if (brcmf_p2p_is_gas_action(frame, mgmt_frame_len)) {
+ sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame;
+ action = sd_act_frm->action;
+ }
+
+ if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&
+ (p2p->next_af_subtype == action)) {
+ brcmf_dbg(TRACE, "We got a right next frame! (%d)\n", action);
+ clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+ &p2p->status);
+ /* Stop waiting for next AF. */
+ brcmf_p2p_stop_wait_next_action_frame(cfg);
+ }
+
+ mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) +
+ mgmt_frame_len, GFP_KERNEL);
+ if (!mgmt_frame) {
+ brcmf_err("No memory available for action frame\n");
+ return -ENOMEM;
+ }
+ memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN);
+ brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid,
+ ETH_ALEN);
+ memcpy(mgmt_frame->sa, e->addr, ETH_ALEN);
+ mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
+ memcpy(&mgmt_frame->u, frame, mgmt_frame_len);
+ mgmt_frame_len += offsetof(struct ieee80211_mgmt, u);
+
+ freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
+ CHSPEC_IS2G(chanspec) ?
+ IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ);
+ wdev = ifp->ndev->ieee80211_ptr;
+ cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len,
+ GFP_ATOMIC);
+
+ kfree(mgmt_frame);
+ return 0;
+}
+
+
+/**
+ * brcmf_p2p_notify_action_tx_complete() - transmit action frame complete
+ *
+ * @ifp: interfac control.
+ * @e: event message. Not used, to make it usable for fweh event dispatcher.
+ * @data: not used.
+ *
+ */
+int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e,
+ void *data)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+
+ brcmf_dbg(INFO, "Enter: event %s, status=%d\n",
+ e->event_code == BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE ?
+ "ACTION_FRAME_OFF_CHAN_COMPLETE" : "ACTION_FRAME_COMPLETE",
+ e->status);
+
+ if (!test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status))
+ return 0;
+
+ if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) {
+ if (e->status == BRCMF_E_STATUS_SUCCESS)
+ set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
+ &p2p->status);
+ else {
+ set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
+ /* If there is no ack, we don't need to wait for
+ * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event
+ */
+ brcmf_p2p_stop_wait_next_action_frame(cfg);
+ }
+
+ } else {
+ complete(&p2p->send_af_done);
+ }
+ return 0;
+}
+
+
+/**
+ * brcmf_p2p_tx_action_frame() - send action frame over fil.
+ *
+ * @p2p: p2p info struct for vif.
+ * @af_params: action frame data/info.
+ *
+ * Send an action frame immediately without doing channel synchronization.
+ *
+ * This function waits for a completion event before returning.
+ * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
+ * frame is transmitted.
+ */
+static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
+ struct brcmf_fil_af_params_le *af_params)
+{
+ struct brcmf_cfg80211_vif *vif;
+ s32 err = 0;
+ s32 timeout = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ INIT_COMPLETION(p2p->send_af_done);
+ clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);
+ clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
+
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params,
+ sizeof(*af_params));
+ if (err) {
+ brcmf_err(" sending action frame has failed\n");
+ goto exit;
+ }
+
+ p2p->af_sent_channel = le32_to_cpu(af_params->channel);
+ p2p->af_tx_sent_jiffies = jiffies;
+
+ timeout = wait_for_completion_timeout(&p2p->send_af_done,
+ msecs_to_jiffies(P2P_AF_MAX_WAIT_TIME));
+
+ if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) {
+ brcmf_dbg(TRACE, "TX action frame operation is success\n");
+ } else {
+ err = -EIO;
+ brcmf_dbg(TRACE, "TX action frame operation has failed\n");
+ }
+ /* clear status bit for action tx */
+ clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);
+ clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status);
+
+exit:
+ return err;
+}
+
+
+/**
+ * brcmf_p2p_pub_af_tx() - public action frame tx routine.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @af_params: action frame data/info.
+ * @config_af_params: configuration data for action frame.
+ *
+ * routine which transmits ation frame public type.
+ */
+static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_fil_af_params_le *af_params,
+ struct brcmf_config_af_params *config_af_params)
+{
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct brcmf_fil_action_frame_le *action_frame;
+ struct brcmf_p2p_pub_act_frame *act_frm;
+ s32 err = 0;
+ u16 ie_len;
+
+ action_frame = &af_params->action_frame;
+ act_frm = (struct brcmf_p2p_pub_act_frame *)(action_frame->data);
+
+ config_af_params->extra_listen = true;
+
+ switch (act_frm->subtype) {
+ case P2P_PAF_GON_REQ:
+ brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status set\n");
+ set_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+ config_af_params->mpc_onoff = 0;
+ config_af_params->search_channel = true;
+ p2p->next_af_subtype = act_frm->subtype + 1;
+ p2p->gon_req_action = true;
+ /* increase dwell time to wait for RESP frame */
+ af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+ break;
+ case P2P_PAF_GON_RSP:
+ p2p->next_af_subtype = act_frm->subtype + 1;
+ /* increase dwell time to wait for CONF frame */
+ af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+ break;
+ case P2P_PAF_GON_CONF:
+ /* If we reached till GO Neg confirmation reset the filter */
+ brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
+ clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+ /* turn on mpc again if go nego is done */
+ config_af_params->mpc_onoff = 1;
+ /* minimize dwell time */
+ af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+ config_af_params->extra_listen = false;
+ break;
+ case P2P_PAF_INVITE_REQ:
+ config_af_params->search_channel = true;
+ p2p->next_af_subtype = act_frm->subtype + 1;
+ /* increase dwell time */
+ af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+ break;
+ case P2P_PAF_INVITE_RSP:
+ /* minimize dwell time */
+ af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+ config_af_params->extra_listen = false;
+ break;
+ case P2P_PAF_DEVDIS_REQ:
+ config_af_params->search_channel = true;
+ p2p->next_af_subtype = act_frm->subtype + 1;
+ /* maximize dwell time to wait for RESP frame */
+ af_params->dwell_time = cpu_to_le32(P2P_AF_LONG_DWELL_TIME);
+ break;
+ case P2P_PAF_DEVDIS_RSP:
+ /* minimize dwell time */
+ af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+ config_af_params->extra_listen = false;
+ break;
+ case P2P_PAF_PROVDIS_REQ:
+ ie_len = le16_to_cpu(action_frame->len) -
+ offsetof(struct brcmf_p2p_pub_act_frame, elts);
+ if (cfg80211_get_p2p_attr(&act_frm->elts[0], ie_len,
+ IEEE80211_P2P_ATTR_GROUP_ID,
+ NULL, 0) < 0)
+ config_af_params->search_channel = true;
+ config_af_params->mpc_onoff = 0;
+ p2p->next_af_subtype = act_frm->subtype + 1;
+ /* increase dwell time to wait for RESP frame */
+ af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+ break;
+ case P2P_PAF_PROVDIS_RSP:
+ /* wpa_supplicant send go nego req right after prov disc */
+ p2p->next_af_subtype = P2P_PAF_GON_REQ;
+ /* increase dwell time to MED level */
+ af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+ config_af_params->extra_listen = false;
+ break;
+ default:
+ brcmf_err("Unknown p2p pub act frame subtype: %d\n",
+ act_frm->subtype);
+ err = -EINVAL;
+ }
+ return err;
+}
+
+/**
+ * brcmf_p2p_send_action_frame() - send action frame .
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @ndev: net device to transmit on.
+ * @af_params: configuration data for action frame.
+ */
+bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
+ struct net_device *ndev,
+ struct brcmf_fil_af_params_le *af_params)
+{
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct brcmf_fil_action_frame_le *action_frame;
+ struct brcmf_config_af_params config_af_params;
+ struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+ u16 action_frame_len;
+ bool ack = false;
+ u8 category;
+ u8 action;
+ s32 tx_retry;
+ s32 extra_listen_time;
+ uint delta_ms;
+
+ action_frame = &af_params->action_frame;
+ action_frame_len = le16_to_cpu(action_frame->len);
+
+ brcmf_p2p_print_actframe(true, action_frame->data, action_frame_len);
+
+ /* Add the default dwell time. Dwell time to stay off-channel */
+ /* to wait for a response action frame after transmitting an */
+ /* GO Negotiation action frame */
+ af_params->dwell_time = cpu_to_le32(P2P_AF_DWELL_TIME);
+
+ category = action_frame->data[DOT11_ACTION_CAT_OFF];
+ action = action_frame->data[DOT11_ACTION_ACT_OFF];
+
+ /* initialize variables */
+ p2p->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
+ p2p->gon_req_action = false;
+
+ /* config parameters */
+ config_af_params.mpc_onoff = -1;
+ config_af_params.search_channel = false;
+ config_af_params.extra_listen = false;
+
+ if (brcmf_p2p_is_pub_action(action_frame->data, action_frame_len)) {
+ /* p2p public action frame process */
+ if (brcmf_p2p_pub_af_tx(cfg, af_params, &config_af_params)) {
+ /* Just send unknown subtype frame with */
+ /* default parameters. */
+ brcmf_err("P2P Public action frame, unknown subtype.\n");
+ }
+ } else if (brcmf_p2p_is_gas_action(action_frame->data,
+ action_frame_len)) {
+ /* service discovery process */
+ if (action == P2PSD_ACTION_ID_GAS_IREQ ||
+ action == P2PSD_ACTION_ID_GAS_CREQ) {
+ /* configure service discovery query frame */
+ config_af_params.search_channel = true;
+
+ /* save next af suptype to cancel */
+ /* remaining dwell time */
+ p2p->next_af_subtype = action + 1;
+
+ af_params->dwell_time =
+ cpu_to_le32(P2P_AF_MED_DWELL_TIME);
+ } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
+ action == P2PSD_ACTION_ID_GAS_CRESP) {
+ /* configure service discovery response frame */
+ af_params->dwell_time =
+ cpu_to_le32(P2P_AF_MIN_DWELL_TIME);
+ } else {
+ brcmf_err("Unknown action type: %d\n", action);
+ goto exit;
+ }
+ } else if (brcmf_p2p_is_p2p_action(action_frame->data,
+ action_frame_len)) {
+ /* do not configure anything. it will be */
+ /* sent with a default configuration */
+ } else {
+ brcmf_err("Unknown Frame: category 0x%x, action 0x%x\n",
+ category, action);
+ return false;
+ }
+
+ /* if connecting on primary iface, sleep for a while before sending
+ * af tx for VSDB
+ */
+ if (test_bit(BRCMF_VIF_STATUS_CONNECTING,
+ &p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->sme_state))
+ msleep(50);
+
+ /* if scan is ongoing, abort current scan. */
+ if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
+ brcmf_abort_scanning(cfg);
+
+ memcpy(afx_hdl->tx_dst_addr, action_frame->da, ETH_ALEN);
+
+ /* To make sure to send successfully action frame, turn off mpc */
+ if (config_af_params.mpc_onoff == 0)
+ brcmf_set_mpc(ndev, 0);
+
+ /* set status and destination address before sending af */
+ if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
+ /* set status to cancel the remained dwell time in rx process */
+ set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
+ }
+
+ p2p->af_sent_channel = 0;
+ set_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status);
+ /* validate channel and p2p ies */
+ if (config_af_params.search_channel &&
+ IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) &&
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) {
+ afx_hdl = &p2p->afx_hdl;
+ afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel);
+
+ if (brcmf_p2p_af_searching_channel(p2p) ==
+ P2P_INVALID_CHANNEL) {
+ brcmf_err("Couldn't find peer's channel.\n");
+ goto exit;
+ }
+
+ /* Abort scan even for VSDB scenarios. Scan gets aborted in
+ * firmware but after the check of piggyback algorithm. To take
+ * care of current piggback algo, lets abort the scan here
+ * itself.
+ */
+ brcmf_notify_escan_complete(cfg, ndev, true, true);
+
+ /* update channel */
+ af_params->channel = cpu_to_le32(afx_hdl->peer_chan);
+ }
+
+ tx_retry = 0;
+ while (!p2p->block_gon_req_tx &&
+ (ack == false) && (tx_retry < P2P_AF_TX_MAX_RETRY)) {
+ ack = !brcmf_p2p_tx_action_frame(p2p, af_params);
+ tx_retry++;
+ }
+ if (ack == false) {
+ brcmf_err("Failed to send Action Frame(retry %d)\n", tx_retry);
+ clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+ }
+
+exit:
+ clear_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status);
+
+ /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
+ * if we coundn't get the next action response frame and dongle does
+ * not keep the dwell time, go to listen state again to get next action
+ * response frame.
+ */
+ if (ack && config_af_params.extra_listen && !p2p->block_gon_req_tx &&
+ test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) &&
+ p2p->af_sent_channel == afx_hdl->my_listen_chan) {
+ delta_ms = jiffies_to_msecs(jiffies - p2p->af_tx_sent_jiffies);
+ if (le32_to_cpu(af_params->dwell_time) > delta_ms)
+ extra_listen_time = le32_to_cpu(af_params->dwell_time) -
+ delta_ms;
+ else
+ extra_listen_time = 0;
+ if (extra_listen_time > 50) {
+ set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+ &p2p->status);
+ brcmf_dbg(INFO, "Wait more time! actual af time:%d, calculated extra listen:%d\n",
+ le32_to_cpu(af_params->dwell_time),
+ extra_listen_time);
+ extra_listen_time += 100;
+ if (!brcmf_p2p_discover_listen(p2p,
+ p2p->af_sent_channel,
+ extra_listen_time)) {
+ unsigned long duration;
+
+ extra_listen_time += 100;
+ duration = msecs_to_jiffies(extra_listen_time);
+ wait_for_completion_timeout(&p2p->wait_next_af,
+ duration);
+ }
+ clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+ &p2p->status);
+ }
+ }
+
+ if (p2p->block_gon_req_tx) {
+ /* if ack is true, supplicant will wait more time(100ms).
+ * so we will return it as a success to get more time .
+ */
+ p2p->block_gon_req_tx = false;
+ ack = true;
+ }
+
+ clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
+ /* if all done, turn mpc on again */
+ if (config_af_params.mpc_onoff == 1)
+ brcmf_set_mpc(ndev, 1);
+
+ return ack;
+}
+
+/**
+ * brcmf_p2p_notify_rx_mgmt_p2p_probereq() - Event handler for p2p probe req.
+ *
+ * @ifp: interface pointer for which event was received.
+ * @e: even message.
+ * @data: payload of event message (probe request).
+ */
+s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e,
+ void *data)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+ struct wireless_dev *wdev;
+ struct brcmf_cfg80211_vif *vif = ifp->vif;
+ struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
+ u16 chanspec = be16_to_cpu(rxframe->chanspec);
+ u8 *mgmt_frame;
+ u32 mgmt_frame_len;
+ s32 freq;
+ u16 mgmt_type;
+
+ brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
+ e->reason);
+
+ if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) &&
+ (memcmp(afx_hdl->tx_dst_addr, e->addr, ETH_ALEN) == 0)) {
+ afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec);
+ brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n",
+ afx_hdl->peer_chan);
+ complete(&afx_hdl->act_frm_scan);
+ }
+
+ /* Firmware sends us two proberesponses for each idx one. At the */
+ /* moment anything but bsscfgidx 0 is passed up to supplicant */
+ if (e->bsscfgidx == 0)
+ return 0;
+
+ /* Filter any P2P probe reqs arriving during the GO-NEG Phase */
+ if (test_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status)) {
+ brcmf_dbg(INFO, "Filtering P2P probe_req in GO-NEG phase\n");
+ return 0;
+ }
+
+ /* Check if wpa_supplicant has registered for this frame */
+ brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg);
+ mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4;
+ if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0)
+ return 0;
+
+ mgmt_frame = (u8 *)(rxframe + 1);
+ mgmt_frame_len = e->datalen - sizeof(*rxframe);
+ freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
+ CHSPEC_IS2G(chanspec) ?
+ IEEE80211_BAND_2GHZ :
+ IEEE80211_BAND_5GHZ);
+ wdev = ifp->ndev->ieee80211_ptr;
+ cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
+
+ brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
+ mgmt_frame_len, e->datalen, chanspec, freq);
+
+ return 0;
+}
+
+
+/**
+ * brcmf_p2p_attach() - attach for P2P.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ */
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_if *pri_ifp;
+ struct brcmf_if *p2p_ifp;
+ struct brcmf_cfg80211_vif *p2p_vif;
+ struct brcmf_p2p_info *p2p;
+ struct brcmf_pub *drvr;
+ s32 bssidx;
+ s32 err = 0;
+
+ p2p = &cfg->p2p;
+ p2p->cfg = cfg;
+
+ drvr = cfg->pub;
+
+ pri_ifp = drvr->iflist[0];
+ p2p_ifp = drvr->iflist[1];
+
+ p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif;
+
+ if (p2p_ifp) {
+ p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE,
+ false);
+ if (IS_ERR(p2p_vif)) {
+ brcmf_err("could not create discovery vif\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ p2p_vif->ifp = p2p_ifp;
+ p2p_ifp->vif = p2p_vif;
+ p2p_vif->wdev.netdev = p2p_ifp->ndev;
+ p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev;
+ SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy));
+
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
+
+ brcmf_p2p_generate_bss_mac(p2p);
+ brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+
+ /* Initialize P2P Discovery in the firmware */
+ err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
+ if (err < 0) {
+ brcmf_err("set p2p_disc error\n");
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+ /* obtain bsscfg index for P2P discovery */
+ err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
+ if (err < 0) {
+ brcmf_err("retrieving discover bsscfg index failed\n");
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+ /* Verify that firmware uses same bssidx as driver !! */
+ if (p2p_ifp->bssidx != bssidx) {
+ brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
+ bssidx, p2p_ifp->bssidx);
+ brcmf_free_vif(p2p_vif);
+ goto exit;
+ }
+
+ init_completion(&p2p->send_af_done);
+ INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
+ init_completion(&p2p->afx_hdl.act_frm_scan);
+ init_completion(&p2p->wait_next_af);
+ }
+exit:
+ return err;
+}
+
+
+/**
+ * brcmf_p2p_detach() - detach P2P.
+ *
+ * @p2p: P2P specific data.
+ */
+void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
+{
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (vif != NULL) {
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+ brcmf_p2p_deinit_discovery(p2p);
+ /* remove discovery interface */
+ brcmf_free_vif(vif);
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+ }
+ /* just set it all to zero */
+ memset(p2p, 0, sizeof(*p2p));
+}
+
+/**
+ * brcmf_p2p_get_current_chanspec() - Get current operation channel.
+ *
+ * @p2p: P2P specific data.
+ * @chanspec: chanspec to be returned.
+ */
+static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p,
+ u16 *chanspec)
+{
+ struct brcmf_if *ifp;
+ struct brcmf_fil_chan_info_le ci;
+ s32 err;
+
+ ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+
+ *chanspec = 11 & WL_CHANSPEC_CHAN_MASK;
+
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci));
+ if (!err) {
+ *chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK;
+ if (*chanspec < CH_MAX_2G_CHANNEL)
+ *chanspec |= WL_CHANSPEC_BAND_2G;
+ else
+ *chanspec |= WL_CHANSPEC_BAND_5G;
+ }
+ *chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
+}
+
+/**
+ * Change a P2P Role.
+ * Parameters:
+ * @mac: MAC address of the BSS to change a role
+ * Returns 0 if success.
+ */
+int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
+ enum brcmf_fil_p2p_if_types if_type)
+{
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct brcmf_cfg80211_vif *vif;
+ struct brcmf_fil_p2p_if_le if_request;
+ s32 err;
+ u16 chanspec;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
+ if (!vif) {
+ brcmf_err("vif for P2PAPI_BSSCFG_PRIMARY does not exist\n");
+ return -EPERM;
+ }
+ brcmf_notify_escan_complete(cfg, vif->ifp->ndev, true, true);
+ vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
+ if (!vif) {
+ brcmf_err("vif for P2PAPI_BSSCFG_CONNECTION does not exist\n");
+ return -EPERM;
+ }
+ brcmf_set_mpc(vif->ifp->ndev, 0);
+
+ /* In concurrency case, STA may be already associated in a particular */
+ /* channel. so retrieve the current channel of primary interface and */
+ /* then start the virtual interface on that. */
+ brcmf_p2p_get_current_chanspec(p2p, &chanspec);
+
+ if_request.type = cpu_to_le16((u16)if_type);
+ if_request.chspec = cpu_to_le16(chanspec);
+ memcpy(if_request.addr, p2p->int_addr, sizeof(if_request.addr));
+
+ brcmf_cfg80211_arm_vif_event(cfg, vif);
+ err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request,
+ sizeof(if_request));
+ if (err) {
+ brcmf_err("p2p_ifupd FAILED, err=%d\n", err);
+ brcmf_cfg80211_arm_vif_event(cfg, NULL);
+ return err;
+ }
+ err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE,
+ msecs_to_jiffies(1500));
+ brcmf_cfg80211_arm_vif_event(cfg, NULL);
+ if (!err) {
+ brcmf_err("No BRCMF_E_IF_CHANGE event received\n");
+ return -EIO;
+ }
+
+ err = brcmf_fil_cmd_int_set(vif->ifp, BRCMF_C_SET_SCB_TIMEOUT,
+ BRCMF_SCB_TIMEOUT_VALUE);
+
+ return err;
+}
+
+static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p,
+ struct brcmf_if *ifp, u8 ea[ETH_ALEN],
+ enum brcmf_fil_p2p_if_types iftype)
+{
+ struct brcmf_fil_p2p_if_le if_request;
+ int err;
+ u16 chanspec;
+
+ /* we need a default channel */
+ brcmf_p2p_get_current_chanspec(p2p, &chanspec);
+
+ /* fill the firmware request */
+ memcpy(if_request.addr, ea, ETH_ALEN);
+ if_request.type = cpu_to_le16((u16)iftype);
+ if_request.chspec = cpu_to_le16(chanspec);
+
+ err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request,
+ sizeof(if_request));
+ if (err)
+ return err;
+
+ return err;
+}
+
+static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif)
+{
+ struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
+ struct net_device *pri_ndev = cfg_to_ndev(cfg);
+ struct brcmf_if *ifp = netdev_priv(pri_ndev);
+ u8 *addr = vif->wdev.netdev->dev_addr;
+
+ return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN);
+}
+
+static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif)
+{
+ struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
+ struct net_device *pri_ndev = cfg_to_ndev(cfg);
+ struct brcmf_if *ifp = netdev_priv(pri_ndev);
+ u8 *addr = vif->wdev.netdev->dev_addr;
+
+ return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN);
+}
+
+/**
+ * brcmf_p2p_add_vif() - create a new P2P virtual interface.
+ *
+ * @wiphy: wiphy device of new interface.
+ * @name: name of the new interface.
+ * @type: nl80211 interface type.
+ * @flags: TBD
+ * @params: TBD
+ */
+struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct brcmf_cfg80211_vif *vif;
+ enum brcmf_fil_p2p_if_types iftype;
+ enum wl_mode mode;
+ int err;
+
+ if (brcmf_cfg80211_vif_event_armed(cfg))
+ return ERR_PTR(-EBUSY);
+
+ brcmf_dbg(INFO, "adding vif \"%s\" (type=%d)\n", name, type);
+
+ switch (type) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ iftype = BRCMF_FIL_P2P_IF_CLIENT;
+ mode = WL_MODE_BSS;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ iftype = BRCMF_FIL_P2P_IF_GO;
+ mode = WL_MODE_AP;
+ break;
+ default:
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
+ vif = brcmf_alloc_vif(cfg, type, false);
+ if (IS_ERR(vif))
+ return (struct wireless_dev *)vif;
+ brcmf_cfg80211_arm_vif_event(cfg, vif);
+
+ err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp, cfg->p2p.int_addr,
+ iftype);
+ if (err) {
+ brcmf_cfg80211_arm_vif_event(cfg, NULL);
+ goto fail;
+ }
+
+ /* wait for firmware event */
+ err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
+ msecs_to_jiffies(1500));
+ brcmf_cfg80211_arm_vif_event(cfg, NULL);
+ if (!err) {
+ brcmf_err("timeout occurred\n");
+ err = -EIO;
+ goto fail;
+ }
+
+ /* interface created in firmware */
+ ifp = vif->ifp;
+ if (!ifp) {
+ brcmf_err("no if pointer provided\n");
+ err = -ENOENT;
+ goto fail;
+ }
+
+ strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
+ err = brcmf_net_attach(ifp, true);
+ if (err) {
+ brcmf_err("Registering netdevice failed\n");
+ goto fail;
+ }
+ cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;
+ /* Disable firmware roaming for P2P interface */
+ brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
+ if (iftype == BRCMF_FIL_P2P_IF_GO) {
+ /* set station timeout for p2p */
+ brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCB_TIMEOUT,
+ BRCMF_SCB_TIMEOUT_VALUE);
+ }
+ return &ifp->vif->wdev;
+
+fail:
+ brcmf_free_vif(vif);
+ return ERR_PTR(err);
+}
+
+/**
+ * brcmf_p2p_del_vif() - delete a P2P virtual interface.
+ *
+ * @wiphy: wiphy device of interface.
+ * @wdev: wireless device of interface.
+ *
+ * TODO: not yet supported.
+ */
+int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct brcmf_cfg80211_vif *vif;
+ unsigned long jiffie_timeout = msecs_to_jiffies(1500);
+ bool wait_for_disable = false;
+ int err;
+
+ brcmf_dbg(TRACE, "delete P2P vif\n");
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+
+ switch (vif->wdev.iftype) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))
+ wait_for_disable = true;
+ break;
+
+ case NL80211_IFTYPE_P2P_GO:
+ if (!brcmf_p2p_disable_p2p_if(vif))
+ wait_for_disable = true;
+ break;
+
+ case NL80211_IFTYPE_P2P_DEVICE:
+ default:
+ return -ENOTSUPP;
+ break;
+ }
+
+ clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
+ brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
+
+ if (wait_for_disable)
+ wait_for_completion_timeout(&cfg->vif_disabled,
+ msecs_to_jiffies(500));
+
+ brcmf_vif_clear_mgmt_ies(vif);
+
+ brcmf_cfg80211_arm_vif_event(cfg, vif);
+ err = brcmf_p2p_release_p2p_if(vif);
+ if (!err) {
+ /* wait for firmware event */
+ err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
+ jiffie_timeout);
+ if (!err)
+ err = -EIO;
+ else
+ err = 0;
+ }
+ brcmf_cfg80211_arm_vif_event(cfg, NULL);
+ brcmf_free_vif(vif);
+ p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
+
+ return err;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
new file mode 100644
index 000000000000..6821b26224be
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * 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 WL_CFGP2P_H_
+#define WL_CFGP2P_H_
+
+#include <net/cfg80211.h>
+
+struct brcmf_cfg80211_info;
+
+/**
+ * enum p2p_bss_type - different type of BSS configurations.
+ *
+ * @P2PAPI_BSSCFG_PRIMARY: maps to driver's primary bsscfg.
+ * @P2PAPI_BSSCFG_DEVICE: maps to driver's P2P device discovery bsscfg.
+ * @P2PAPI_BSSCFG_CONNECTION: maps to driver's P2P connection bsscfg.
+ * @P2PAPI_BSSCFG_MAX: used for range checking.
+ */
+enum p2p_bss_type {
+ P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */
+ P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */
+ P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */
+ P2PAPI_BSSCFG_MAX
+};
+
+/**
+ * struct p2p_bss - peer-to-peer bss related information.
+ *
+ * @vif: virtual interface of this P2P bss.
+ * @private_data: TBD
+ */
+struct p2p_bss {
+ struct brcmf_cfg80211_vif *vif;
+ void *private_data;
+};
+
+/**
+ * enum brcmf_p2p_status - P2P specific dongle status.
+ *
+ * @BRCMF_P2P_STATUS_IF_ADD: peer-to-peer vif add sent to dongle.
+ * @BRCMF_P2P_STATUS_IF_DEL: NOT-USED?
+ * @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle.
+ * @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle.
+ * @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle.
+ * @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed.
+ * @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked.
+ * @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing.
+ * @BRCMF_P2P_STATUS_DISCOVER_LISTEN: P2P listen, remaining on channel.
+ * @BRCMF_P2P_STATUS_SENDING_ACT_FRAME: In the process of sending action frame.
+ * @BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN: extra listen time for af tx.
+ * @BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME: waiting for action frame response.
+ * @BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL: search channel for AF active.
+ */
+enum brcmf_p2p_status {
+ BRCMF_P2P_STATUS_ENABLED,
+ BRCMF_P2P_STATUS_IF_ADD,
+ BRCMF_P2P_STATUS_IF_DEL,
+ BRCMF_P2P_STATUS_IF_DELETING,
+ BRCMF_P2P_STATUS_IF_CHANGING,
+ BRCMF_P2P_STATUS_IF_CHANGED,
+ BRCMF_P2P_STATUS_ACTION_TX_COMPLETED,
+ BRCMF_P2P_STATUS_ACTION_TX_NOACK,
+ BRCMF_P2P_STATUS_GO_NEG_PHASE,
+ BRCMF_P2P_STATUS_DISCOVER_LISTEN,
+ BRCMF_P2P_STATUS_SENDING_ACT_FRAME,
+ BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
+ BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME,
+ BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL
+};
+
+/**
+ * struct afx_hdl - action frame off channel storage.
+ *
+ * @afx_work: worker thread for searching channel
+ * @act_frm_scan: thread synchronizing struct.
+ * @is_active: channel searching active.
+ * @peer_chan: current channel.
+ * @is_listen: sets mode for afx worker.
+ * @my_listen_chan: this peers listen channel.
+ * @peer_listen_chan: remote peers listen channel.
+ * @tx_dst_addr: mac address where tx af should be sent to.
+ */
+struct afx_hdl {
+ struct work_struct afx_work;
+ struct completion act_frm_scan;
+ bool is_active;
+ s32 peer_chan;
+ bool is_listen;
+ u16 my_listen_chan;
+ u16 peer_listen_chan;
+ u8 tx_dst_addr[ETH_ALEN];
+};
+
+/**
+ * struct brcmf_p2p_info - p2p specific driver information.
+ *
+ * @cfg: driver private data for cfg80211 interface.
+ * @status: status of P2P (see enum brcmf_p2p_status).
+ * @dev_addr: P2P device address.
+ * @int_addr: P2P interface address.
+ * @bss_idx: informate for P2P bss types.
+ * @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state.
+ * @ssid: ssid for P2P GO.
+ * @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state.
+ * @remain_on_channel: contains copy of struct used by cfg80211.
+ * @remain_on_channel_cookie: cookie counter for remain on channel cmd
+ * @next_af_subtype: expected action frame subtype.
+ * @send_af_done: indication that action frame tx is complete.
+ * @afx_hdl: action frame search handler info.
+ * @af_sent_channel: channel action frame is sent.
+ * @af_tx_sent_jiffies: jiffies time when af tx was transmitted.
+ * @wait_next_af: thread synchronizing struct.
+ * @gon_req_action: about to send go negotiation requets frame.
+ * @block_gon_req_tx: drop tx go negotiation requets frame.
+ */
+struct brcmf_p2p_info {
+ struct brcmf_cfg80211_info *cfg;
+ unsigned long status;
+ u8 dev_addr[ETH_ALEN];
+ u8 int_addr[ETH_ALEN];
+ struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX];
+ struct timer_list listen_timer;
+ struct brcmf_ssid ssid;
+ u8 listen_channel;
+ struct ieee80211_channel remain_on_channel;
+ u32 remain_on_channel_cookie;
+ u8 next_af_subtype;
+ struct completion send_af_done;
+ struct afx_hdl afx_hdl;
+ u32 af_sent_channel;
+ unsigned long af_tx_sent_jiffies;
+ struct completion wait_next_af;
+ bool gon_req_action;
+ bool block_gon_req_tx;
+};
+
+s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
+void brcmf_p2p_detach(struct brcmf_p2p_info *p2p);
+struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params);
+int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
+int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
+ enum brcmf_fil_p2p_if_types if_type);
+int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+int brcmf_p2p_scan_prep(struct wiphy *wiphy,
+ struct cfg80211_scan_request *request,
+ struct brcmf_cfg80211_vif *vif);
+int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
+ struct ieee80211_channel *channel,
+ unsigned int duration, u64 *cookie);
+int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e,
+ void *data);
+void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp);
+int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e,
+ void *data);
+int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e,
+ void *data);
+bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
+ struct net_device *ndev,
+ struct brcmf_fil_af_params_le *af_params);
+bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_bss_info_le *bi);
+s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e,
+ void *data);
+#endif /* WL_CFGP2P_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
index b1bb46c49799..14be2d5530ce 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
@@ -15,8 +15,6 @@
*/
/* ***** SDIO interface chip backplane handle functions ***** */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/mmc/card.h>
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 914c56fe6c5f..42289e9ea886 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -354,11 +354,10 @@ brcmf_usbdev_qinit(struct list_head *q, int qsize)
int i;
struct brcmf_usbreq *req, *reqs;
- reqs = kzalloc(sizeof(struct brcmf_usbreq) * qsize, GFP_ATOMIC);
- if (reqs == NULL) {
- brcmf_err("fail to allocate memory!\n");
+ reqs = kcalloc(qsize, sizeof(struct brcmf_usbreq), GFP_ATOMIC);
+ if (reqs == NULL)
return NULL;
- }
+
req = reqs;
for (i = 0; i < qsize; i++) {
@@ -421,10 +420,6 @@ static void brcmf_usb_tx_complete(struct urb *urb)
brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
req->skb);
brcmf_usb_del_fromq(devinfo, req);
- if (urb->status == 0)
- devinfo->bus_pub.bus->dstats.tx_packets++;
- else
- devinfo->bus_pub.bus->dstats.tx_errors++;
brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
@@ -443,30 +438,25 @@ static void brcmf_usb_rx_complete(struct urb *urb)
struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
struct brcmf_usbdev_info *devinfo = req->devinfo;
struct sk_buff *skb;
- int ifidx = 0;
+ struct sk_buff_head skbq;
brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
brcmf_usb_del_fromq(devinfo, req);
skb = req->skb;
req->skb = NULL;
- if (urb->status == 0) {
- devinfo->bus_pub.bus->dstats.rx_packets++;
- } else {
- devinfo->bus_pub.bus->dstats.rx_errors++;
+ /* zero lenght packets indicate usb "failure". Do not refill */
+ if (urb->status != 0 || !urb->actual_length) {
brcmu_pkt_buf_free_skb(skb);
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
return;
}
if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
+ skb_queue_head_init(&skbq);
+ skb_queue_tail(&skbq, skb);
skb_put(skb, urb->actual_length);
- if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
- brcmf_err("rx protocol error\n");
- brcmu_pkt_buf_free_skb(skb);
- devinfo->bus_pub.bus->dstats.rx_errors++;
- } else
- brcmf_rx_packet(devinfo->dev, ifidx, skb);
+ brcmf_rx_frames(devinfo->dev, &skbq);
brcmf_usb_rx_refill(devinfo, req);
} else {
brcmu_pkt_buf_free_skb(skb);
@@ -1259,6 +1249,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
bus->bus_priv.usb = bus_pub;
dev_set_drvdata(dev, bus);
bus->ops = &brcmf_usb_bus_ops;
+ bus->chip = bus_pub->devid;
+ bus->chiprev = bus_pub->chiprev;
/* Attach to the common driver interface */
ret = brcmf_attach(0, dev);
@@ -1520,10 +1512,23 @@ static void brcmf_release_fw(struct list_head *q)
}
}
+static int brcmf_usb_reset_device(struct device *dev, void *notused)
+{
+ /* device past is the usb interface so we
+ * need to use parent here.
+ */
+ brcmf_dev_reset(dev->parent);
+ return 0;
+}
void brcmf_usb_exit(void)
{
+ struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver;
+ int ret;
+
brcmf_dbg(USB, "Enter\n");
+ ret = driver_for_each_device(drv, NULL, NULL,
+ brcmf_usb_reset_device);
usb_deregister(&brcmf_usbdrvr);
brcmf_release_fw(&fw_image_list);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 75464ad4fbd1..cecc3eff72e9 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -16,8 +16,6 @@
/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <net/cfg80211.h>
@@ -28,6 +26,8 @@
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_dbg.h"
+#include "fwil_types.h"
+#include "p2p.h"
#include "wl_cfg80211.h"
#include "fwil.h"
@@ -43,16 +43,13 @@
#define BRCMF_PNO_SCAN_COMPLETE 1
#define BRCMF_PNO_SCAN_INCOMPLETE 0
-#define BRCMF_IFACE_MAX_CNT 2
+#define BRCMF_IFACE_MAX_CNT 3
-#define TLV_LEN_OFF 1 /* length offset */
-#define TLV_HDR_LEN 2 /* header length */
-#define TLV_BODY_OFF 2 /* body offset */
-#define TLV_OUI_LEN 3 /* oui id length */
#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */
#define WPA_OUI_TYPE 1
#define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */
#define WME_OUI_TYPE 2
+#define WPS_OUI_TYPE 4
#define VS_IE_FIXED_HDR_LEN 6
#define WPA_IE_VERSION_LEN 2
@@ -78,13 +75,15 @@
#define VNDR_IE_PKTFLAG_OFFSET 8
#define VNDR_IE_VSIE_OFFSET 12
#define VNDR_IE_HDR_SIZE 12
-#define VNDR_IE_BEACON_FLAG 0x1
-#define VNDR_IE_PRBRSP_FLAG 0x2
-#define MAX_VNDR_IE_NUMBER 5
+#define VNDR_IE_PARSE_LIMIT 5
#define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */
#define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */
+#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
+#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
+#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20
+
#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
@@ -273,13 +272,6 @@ static const u32 __wl_cipher_suites[] = {
WLAN_CIPHER_SUITE_AES_CMAC,
};
-/* tag_ID/length/value_buffer tuple */
-struct brcmf_tlv {
- u8 id;
- u8 len;
- u8 data[1];
-};
-
/* Vendor specific ie. id = 221, oui and type defines exact ie */
struct brcmf_vs_tlv {
u8 id;
@@ -296,7 +288,7 @@ struct parsed_vndr_ie_info {
struct parsed_vndr_ies {
u32 count;
- struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER];
+ struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
};
/* Quarter dBm units to mW
@@ -383,7 +375,7 @@ static u8 brcmf_mw_to_qdbm(u16 mw)
return qdbm;
}
-static u16 channel_to_chanspec(struct ieee80211_channel *ch)
+u16 channel_to_chanspec(struct ieee80211_channel *ch)
{
u16 chanspec;
@@ -395,19 +387,92 @@ static u16 channel_to_chanspec(struct ieee80211_channel *ch)
else
chanspec |= WL_CHANSPEC_BAND_5G;
- if (ch->flags & IEEE80211_CHAN_NO_HT40) {
- chanspec |= WL_CHANSPEC_BW_20;
- chanspec |= WL_CHANSPEC_CTL_SB_NONE;
- } else {
- chanspec |= WL_CHANSPEC_BW_40;
- if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS)
- chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
- else
- chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
- }
+ chanspec |= WL_CHANSPEC_BW_20;
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
return chanspec;
}
+/* Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
+ * matches tag
+ */
+struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
+{
+ struct brcmf_tlv *elt;
+ int totlen;
+
+ elt = (struct brcmf_tlv *)buf;
+ totlen = buflen;
+
+ /* find tagged parameter */
+ while (totlen >= TLV_HDR_LEN) {
+ int len = elt->len;
+
+ /* validate remaining totlen */
+ if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
+ return elt;
+
+ elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
+ totlen -= (len + TLV_HDR_LEN);
+ }
+
+ return NULL;
+}
+
+/* Is any of the tlvs the expected entry? If
+ * not update the tlvs buffer pointer/length.
+ */
+static bool
+brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
+ u8 *oui, u32 oui_len, u8 type)
+{
+ /* If the contents match the OUI and the type */
+ if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
+ !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
+ type == ie[TLV_BODY_OFF + oui_len]) {
+ return true;
+ }
+
+ if (tlvs == NULL)
+ return false;
+ /* point to the next ie */
+ ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
+ /* calculate the length of the rest of the buffer */
+ *tlvs_len -= (int)(ie - *tlvs);
+ /* update the pointer to the start of the buffer */
+ *tlvs = ie;
+
+ return false;
+}
+
+static struct brcmf_vs_tlv *
+brcmf_find_wpaie(u8 *parse, u32 len)
+{
+ struct brcmf_tlv *ie;
+
+ while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
+ if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
+ WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
+ return (struct brcmf_vs_tlv *)ie;
+ }
+ return NULL;
+}
+
+static struct brcmf_vs_tlv *
+brcmf_find_wpsie(u8 *parse, u32 len)
+{
+ struct brcmf_tlv *ie;
+
+ while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
+ if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
+ WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
+ return (struct brcmf_vs_tlv *)ie;
+ }
+ return NULL;
+}
+
+
static void convert_key_from_CPU(struct brcmf_wsec_key *key,
struct brcmf_wsec_key_le *key_le)
{
@@ -440,11 +505,153 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
return err;
}
+static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
+ const char *name,
+ enum nl80211_iftype type,
+ u32 *flags,
+ struct vif_params *params)
+{
+ brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_MESH_POINT:
+ return ERR_PTR(-EOPNOTSUPP);
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_P2P_DEVICE:
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+}
+
+void brcmf_set_mpc(struct net_device *ndev, int mpc)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ s32 err = 0;
+
+ if (check_vif_up(ifp->vif)) {
+ err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
+ if (err) {
+ brcmf_err("fail to set mpc\n");
+ return;
+ }
+ brcmf_dbg(INFO, "MPC : %d\n", mpc);
+ }
+}
+
+s32
+brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
+ struct net_device *ndev,
+ bool aborted, bool fw_abort)
+{
+ struct brcmf_scan_params_le params_le;
+ struct cfg80211_scan_request *scan_request;
+ s32 err = 0;
+
+ brcmf_dbg(SCAN, "Enter\n");
+
+ /* clear scan request, because the FW abort can cause a second call */
+ /* to this functon and might cause a double cfg80211_scan_done */
+ scan_request = cfg->scan_request;
+ cfg->scan_request = NULL;
+
+ if (timer_pending(&cfg->escan_timeout))
+ del_timer_sync(&cfg->escan_timeout);
+
+ if (fw_abort) {
+ /* Do a scan abort to stop the driver's scan engine */
+ brcmf_dbg(SCAN, "ABORT scan in firmware\n");
+ memset(&params_le, 0, sizeof(params_le));
+ memset(params_le.bssid, 0xFF, ETH_ALEN);
+ params_le.bss_type = DOT11_BSSTYPE_ANY;
+ params_le.scan_type = 0;
+ params_le.channel_num = cpu_to_le32(1);
+ params_le.nprobes = cpu_to_le32(1);
+ params_le.active_time = cpu_to_le32(-1);
+ params_le.passive_time = cpu_to_le32(-1);
+ params_le.home_time = cpu_to_le32(-1);
+ /* Scan is aborted by setting channel_list[0] to -1 */
+ params_le.channel_list[0] = cpu_to_le16(-1);
+ /* E-Scan (or anyother type) can be aborted by SCAN */
+ err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
+ &params_le, sizeof(params_le));
+ if (err)
+ brcmf_err("Scan abort failed\n");
+ }
+ /*
+ * e-scan can be initiated by scheduled scan
+ * which takes precedence.
+ */
+ if (cfg->sched_escan) {
+ brcmf_dbg(SCAN, "scheduled scan completed\n");
+ cfg->sched_escan = false;
+ if (!aborted)
+ cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
+ brcmf_set_mpc(ndev, 1);
+ } else if (scan_request) {
+ brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
+ aborted ? "Aborted" : "Done");
+ cfg80211_scan_done(scan_request, aborted);
+ brcmf_set_mpc(ndev, 1);
+ }
+ if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
+ brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
+
+ return err;
+}
+
+static
+int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = wdev->netdev;
+
+ /* vif event pending in firmware */
+ if (brcmf_cfg80211_vif_event_armed(cfg))
+ return -EBUSY;
+
+ if (ndev) {
+ if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
+ cfg->escan_info.ndev == ndev)
+ brcmf_notify_escan_complete(cfg, ndev, true,
+ true);
+
+ brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
+ }
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_MESH_POINT:
+ return -EOPNOTSUPP;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ return brcmf_p2p_del_vif(wiphy, wdev);
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_P2P_DEVICE:
+ default:
+ return -EINVAL;
+ }
+ return -EOPNOTSUPP;
+}
+
static s32
brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_vif *vif = ifp->vif;
s32 infra = 0;
@@ -464,10 +671,23 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
infra = 0;
break;
case NL80211_IFTYPE_STATION:
+ /* Ignore change for p2p IF. Unclear why supplicant does this */
+ if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
+ (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
+ brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
+ /* WAR: It is unexpected to get a change of VIF for P2P
+ * IF, but it happens. The request can not be handled
+ * but returning EPERM causes a crash. Returning 0
+ * without setting ieee80211_ptr->iftype causes trace
+ * (WARN_ON) but it works with wpa_supplicant
+ */
+ return 0;
+ }
vif->mode = WL_MODE_BSS;
infra = 1;
break;
case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
vif->mode = WL_MODE_AP;
ap = 1;
break;
@@ -477,8 +697,14 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
}
if (ap) {
- set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
- brcmf_dbg(INFO, "IF Type = AP\n");
+ if (type == NL80211_IFTYPE_P2P_GO) {
+ brcmf_dbg(INFO, "IF Type = P2P GO\n");
+ err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
+ }
+ if (!err) {
+ set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
+ brcmf_dbg(INFO, "IF Type = AP\n");
+ }
} else {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
if (err) {
@@ -497,21 +723,6 @@ done:
return err;
}
-static void brcmf_set_mpc(struct net_device *ndev, int mpc)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- s32 err = 0;
-
- if (check_vif_up(ifp->vif)) {
- err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
- if (err) {
- brcmf_err("fail to set mpc\n");
- return;
- }
- brcmf_dbg(INFO, "MPC : %d\n", mpc);
- }
-}
-
static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
struct cfg80211_scan_request *request)
{
@@ -592,69 +803,6 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
}
static s32
-brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
- bool aborted, bool fw_abort)
-{
- struct brcmf_scan_params_le params_le;
- struct cfg80211_scan_request *scan_request;
- s32 err = 0;
-
- brcmf_dbg(SCAN, "Enter\n");
-
- /* clear scan request, because the FW abort can cause a second call */
- /* to this functon and might cause a double cfg80211_scan_done */
- scan_request = cfg->scan_request;
- cfg->scan_request = NULL;
-
- if (timer_pending(&cfg->escan_timeout))
- del_timer_sync(&cfg->escan_timeout);
-
- if (fw_abort) {
- /* Do a scan abort to stop the driver's scan engine */
- brcmf_dbg(SCAN, "ABORT scan in firmware\n");
- memset(&params_le, 0, sizeof(params_le));
- memset(params_le.bssid, 0xFF, ETH_ALEN);
- params_le.bss_type = DOT11_BSSTYPE_ANY;
- params_le.scan_type = 0;
- params_le.channel_num = cpu_to_le32(1);
- params_le.nprobes = cpu_to_le32(1);
- params_le.active_time = cpu_to_le32(-1);
- params_le.passive_time = cpu_to_le32(-1);
- params_le.home_time = cpu_to_le32(-1);
- /* Scan is aborted by setting channel_list[0] to -1 */
- params_le.channel_list[0] = cpu_to_le16(-1);
- /* E-Scan (or anyother type) can be aborted by SCAN */
- err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
- &params_le, sizeof(params_le));
- if (err)
- brcmf_err("Scan abort failed\n");
- }
- /*
- * e-scan can be initiated by scheduled scan
- * which takes precedence.
- */
- if (cfg->sched_escan) {
- brcmf_dbg(SCAN, "scheduled scan completed\n");
- cfg->sched_escan = false;
- if (!aborted)
- cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
- brcmf_set_mpc(ndev, 1);
- } else if (scan_request) {
- brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
- aborted ? "Aborted" : "Done");
- cfg80211_scan_done(scan_request, aborted);
- brcmf_set_mpc(ndev, 1);
- }
- if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
- brcmf_err("Scan complete while device not scanning\n");
- return -EPERM;
- }
-
- return err;
-}
-
-static s32
brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
struct cfg80211_scan_request *request, u16 action)
{
@@ -705,11 +853,12 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
s32 err;
u32 passive_scan;
struct brcmf_scan_results *results;
+ struct escan_info *escan = &cfg->escan_info;
brcmf_dbg(SCAN, "Enter\n");
- cfg->escan_info.ndev = ndev;
- cfg->escan_info.wiphy = wiphy;
- cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
+ escan->ndev = ndev;
+ escan->wiphy = wiphy;
+ escan->escan_state = WL_ESCAN_STATE_SCANNING;
passive_scan = cfg->active_scan ? 0 : 1;
err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
passive_scan);
@@ -723,7 +872,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
results->count = 0;
results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
- err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START);
+ err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START);
if (err)
brcmf_set_mpc(ndev, 1);
return err;
@@ -760,6 +909,12 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
return -EAGAIN;
}
+ /* If scan req comes for p2p0, send it over primary I/F */
+ if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) {
+ ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+ ndev = ifp->ndev;
+ }
+
/* Arm scan timeout timer */
mod_timer(&cfg->escan_timeout, jiffies +
WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
@@ -778,6 +933,11 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
cfg->scan_request = request;
set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
if (escan_req) {
+ cfg->escan_info.run = brcmf_run_escan;
+ err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif);
+ if (err)
+ goto scan_out;
+
err = brcmf_do_escan(cfg, wiphy, ndev, request);
if (err)
goto scan_out;
@@ -935,31 +1095,6 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
memset(prof, 0, sizeof(*prof));
}
-static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
- size_t *join_params_size)
-{
- u16 chanspec = 0;
-
- if (ch != 0) {
- if (ch <= CH_MAX_2G_CHANNEL)
- chanspec |= WL_CHANSPEC_BAND_2G;
- else
- chanspec |= WL_CHANSPEC_BAND_5G;
-
- chanspec |= WL_CHANSPEC_BW_20;
- chanspec |= WL_CHANSPEC_CTL_SB_NONE;
-
- *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
- sizeof(u16);
-
- chanspec |= (ch & WL_CHANSPEC_CHAN_MASK);
- join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec);
- join_params->params_le.chanspec_num = cpu_to_le32(1);
-
- brcmf_dbg(CONN, "channel %d, chanspec %#X\n", ch, chanspec);
- }
-}
-
static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
{
s32 err = 0;
@@ -990,6 +1125,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
s32 err = 0;
s32 wsec = 0;
s32 bcnprd;
+ u16 chanspec;
brcmf_dbg(TRACE, "Enter\n");
if (!check_vif_up(ifp->vif))
@@ -1093,8 +1229,11 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
params->chandef.chan->center_freq);
if (params->channel_fixed) {
/* adding chanspec */
- brcmf_ch_to_chanspec(cfg->channel,
- &join_params, &join_params_size);
+ chanspec = channel_to_chanspec(params->chandef.chan);
+ join_params.params_le.chanspec_list[0] =
+ cpu_to_le16(chanspec);
+ join_params.params_le.chanspec_num = cpu_to_le32(1);
+ join_params_size += sizeof(join_params.params_le);
}
/* set channel for starter */
@@ -1157,7 +1296,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev,
else
val = WPA_AUTH_DISABLED;
brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
- err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
if (err) {
brcmf_err("set wpa_auth failed (%d)\n", err);
return err;
@@ -1196,7 +1335,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
break;
}
- err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
if (err) {
brcmf_err("set auth failed (%d)\n", err);
return err;
@@ -1260,7 +1399,12 @@ brcmf_set_set_cipher(struct net_device *ndev,
}
brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
- err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
+ /* In case of privacy, but no security and WPS then simulate */
+ /* setting AES. WPS-2.0 allows no security */
+ if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
+ sme->privacy)
+ pval = AES_ENABLED;
+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval);
if (err) {
brcmf_err("error (%d)\n", err);
return err;
@@ -1282,8 +1426,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
s32 err = 0;
if (sme->crypto.n_akm_suites) {
- err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
- "wpa_auth", &val);
+ err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
+ "wpa_auth", &val);
if (err) {
brcmf_err("could not get wpa_auth (%d)\n", err);
return err;
@@ -1317,8 +1461,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
}
brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
- err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
- "wpa_auth", val);
+ err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
+ "wpa_auth", val);
if (err) {
brcmf_err("could not set wpa_auth (%d)\n", err);
return err;
@@ -1395,9 +1539,28 @@ brcmf_set_sharedkey(struct net_device *ndev,
return err;
}
+static
+enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
+ enum nl80211_auth_type type)
+{
+ u32 ci;
+ if (type == NL80211_AUTHTYPE_AUTOMATIC) {
+ /* shift to ignore chip revision */
+ ci = brcmf_get_chip_info(ifp) >> 4;
+ switch (ci) {
+ case 43236:
+ brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
+ return NL80211_AUTHTYPE_OPEN_SYSTEM;
+ default:
+ break;
+ }
+ }
+ return type;
+}
+
static s32
brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
- struct cfg80211_connect_params *sme)
+ struct cfg80211_connect_params *sme)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
@@ -1405,7 +1568,12 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
struct ieee80211_channel *chan = sme->channel;
struct brcmf_join_params join_params;
size_t join_params_size;
- struct brcmf_ssid ssid;
+ struct brcmf_tlv *rsn_ie;
+ struct brcmf_vs_tlv *wpa_ie;
+ void *ie;
+ u32 ie_len;
+ struct brcmf_ext_join_params_le *ext_join_params;
+ u16 chanspec;
s32 err = 0;
@@ -1418,15 +1586,46 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
return -EOPNOTSUPP;
}
+ if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
+ /* A normal (non P2P) connection request setup. */
+ ie = NULL;
+ ie_len = 0;
+ /* find the WPA_IE */
+ wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
+ if (wpa_ie) {
+ ie = wpa_ie;
+ ie_len = wpa_ie->len + TLV_HDR_LEN;
+ } else {
+ /* find the RSN_IE */
+ rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len,
+ WLAN_EID_RSN);
+ if (rsn_ie) {
+ ie = rsn_ie;
+ ie_len = rsn_ie->len + TLV_HDR_LEN;
+ }
+ }
+ brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
+ }
+
+ err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
+ sme->ie, sme->ie_len);
+ if (err)
+ brcmf_err("Set Assoc REQ IE Failed\n");
+ else
+ brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");
+
set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
if (chan) {
cfg->channel =
ieee80211_frequency_to_channel(chan->center_freq);
- brcmf_dbg(CONN, "channel (%d), center_req (%d)\n",
- cfg->channel, chan->center_freq);
- } else
+ chanspec = channel_to_chanspec(chan);
+ brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
+ cfg->channel, chan->center_freq, chanspec);
+ } else {
cfg->channel = 0;
+ chanspec = 0;
+ }
brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
@@ -1436,6 +1635,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
goto done;
}
+ sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
err = brcmf_set_auth_type(ndev, sme);
if (err) {
brcmf_err("wl_set_auth_type failed (%d)\n", err);
@@ -1460,27 +1660,88 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
goto done;
}
+ profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
+ (u32)sme->ssid_len);
+ memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
+ if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+ profile->ssid.SSID[profile->ssid.SSID_len] = 0;
+ brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
+ profile->ssid.SSID_len);
+ }
+
+ /* Join with specific BSSID and cached SSID
+ * If SSID is zero join based on BSSID only
+ */
+ join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
+ offsetof(struct brcmf_assoc_params_le, chanspec_list);
+ if (cfg->channel)
+ join_params_size += sizeof(u16);
+ ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
+ if (ext_join_params == NULL) {
+ err = -ENOMEM;
+ goto done;
+ }
+ ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
+ memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
+ profile->ssid.SSID_len);
+ /*increase dwell time to receive probe response or detect Beacon
+ * from target AP at a noisy air only during connect command
+ */
+ ext_join_params->scan_le.active_time =
+ cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
+ ext_join_params->scan_le.passive_time =
+ cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
+ /* Set up join scan parameters */
+ ext_join_params->scan_le.scan_type = -1;
+ /* to sync with presence period of VSDB GO.
+ * Send probe request more frequently. Probe request will be stopped
+ * when it gets probe response from target AP/GO.
+ */
+ ext_join_params->scan_le.nprobes =
+ cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
+ BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
+ ext_join_params->scan_le.home_time = cpu_to_le32(-1);
+
+ if (sme->bssid)
+ memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
+ else
+ memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
+
+ if (cfg->channel) {
+ ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
+
+ ext_join_params->assoc_le.chanspec_list[0] =
+ cpu_to_le16(chanspec);
+ }
+
+ err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
+ join_params_size);
+ kfree(ext_join_params);
+ if (!err)
+ /* This is it. join command worked, we are done */
+ goto done;
+
+ /* join command failed, fallback to set ssid */
memset(&join_params, 0, sizeof(join_params));
join_params_size = sizeof(join_params.ssid_le);
- profile->ssid.SSID_len = min_t(u32,
- sizeof(ssid.SSID), (u32)sme->ssid_len);
memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
- memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
- memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
-
- if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
- brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n",
- ssid.SSID, ssid.SSID_len);
+ if (sme->bssid)
+ memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
+ else
+ memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
- brcmf_ch_to_chanspec(cfg->channel,
- &join_params, &join_params_size);
+ if (cfg->channel) {
+ join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
+ join_params.params_le.chanspec_num = cpu_to_le32(1);
+ join_params_size += sizeof(join_params.params_le);
+ }
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
&join_params, join_params_size);
if (err)
- brcmf_err("WLC_SET_SSID failed (%d)\n", err);
+ brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
done:
if (err)
@@ -1939,7 +2200,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
goto done;
}
/* Report the current tx rate */
- err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
if (err) {
brcmf_err("Could not get rate (%d)\n", err);
goto done;
@@ -2011,67 +2272,6 @@ done:
return err;
}
-static s32
-brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
- const u8 *addr,
- const struct cfg80211_bitrate_mask *mask)
-{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcm_rateset_le rateset_le;
- s32 rate;
- s32 val;
- s32 err_bg;
- s32 err_a;
- u32 legacy;
- s32 err = 0;
-
- brcmf_dbg(TRACE, "Enter\n");
- if (!check_vif_up(ifp->vif))
- return -EIO;
-
- /* addr param is always NULL. ignore it */
- /* Get current rateset */
- err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CURR_RATESET,
- &rateset_le, sizeof(rateset_le));
- if (err) {
- brcmf_err("could not get current rateset (%d)\n", err);
- goto done;
- }
-
- legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF);
- if (!legacy)
- legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy &
- 0xFFFF);
-
- val = wl_g_rates[legacy - 1].bitrate * 100000;
-
- if (val < le32_to_cpu(rateset_le.count))
- /* Select rate by rateset index */
- rate = rateset_le.rates[val] & 0x7f;
- else
- /* Specified rate in bps */
- rate = val / 500000;
-
- brcmf_dbg(CONN, "rate %d mbps\n", rate / 2);
-
- /*
- *
- * Set rate override,
- * Since the is a/b/g-blind, both a/bg_rate are enforced.
- */
- err_bg = brcmf_fil_iovar_int_set(ifp, "bg_rate", rate);
- err_a = brcmf_fil_iovar_int_set(ifp, "a_rate", rate);
- if (err_bg && err_a) {
- brcmf_err("could not set fixed rate (%d) (%d)\n", err_bg,
- err_a);
- err = err_bg | err_a;
- }
-
-done:
- brcmf_dbg(TRACE, "Exit\n");
- return err;
-}
-
static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
struct brcmf_bss_info_le *bi)
{
@@ -2123,7 +2323,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
if (!bss)
return -ENOMEM;
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
return err;
}
@@ -2229,7 +2429,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
goto CleanUp;
}
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
CleanUp:
@@ -2245,78 +2445,10 @@ static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
return vif->mode == WL_MODE_IBSS;
}
-/*
- * Traverse a string of 1-byte tag/1-byte length/variable-length value
- * triples, returning a pointer to the substring whose first element
- * matches tag
- */
-static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
-{
- struct brcmf_tlv *elt;
- int totlen;
-
- elt = (struct brcmf_tlv *) buf;
- totlen = buflen;
-
- /* find tagged parameter */
- while (totlen >= TLV_HDR_LEN) {
- int len = elt->len;
-
- /* validate remaining totlen */
- if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
- return elt;
-
- elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN));
- totlen -= (len + TLV_HDR_LEN);
- }
-
- return NULL;
-}
-
-/* Is any of the tlvs the expected entry? If
- * not update the tlvs buffer pointer/length.
- */
-static bool
-brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
- u8 *oui, u32 oui_len, u8 type)
+static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_if *ifp)
{
- /* If the contents match the OUI and the type */
- if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
- !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
- type == ie[TLV_BODY_OFF + oui_len]) {
- return true;
- }
-
- if (tlvs == NULL)
- return false;
- /* point to the next ie */
- ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
- /* calculate the length of the rest of the buffer */
- *tlvs_len -= (int)(ie - *tlvs);
- /* update the pointer to the start of the buffer */
- *tlvs = ie;
-
- return false;
-}
-
-static struct brcmf_vs_tlv *
-brcmf_find_wpaie(u8 *parse, u32 len)
-{
- struct brcmf_tlv *ie;
-
- while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
- if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
- WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
- return (struct brcmf_vs_tlv *)ie;
- }
- return NULL;
-}
-
-static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
-{
- struct net_device *ndev = cfg_to_ndev(cfg);
- struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
- struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
struct brcmf_bss_info_le *bi;
struct brcmf_ssid *ssid;
struct brcmf_tlv *tim;
@@ -2372,7 +2504,7 @@ update_bss_info_out:
return err;
}
-static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
+void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
{
struct escan_info *escan = &cfg->escan_info;
@@ -2391,8 +2523,7 @@ static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
container_of(work, struct brcmf_cfg80211_info,
escan_timeout_work);
- brcmf_notify_escan_complete(cfg,
- cfg->escan_info.ndev, true, true);
+ brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
}
static void brcmf_escan_timeout(unsigned long data)
@@ -2469,11 +2600,6 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
brcmf_err("Invalid escan result (NULL pointer)\n");
goto exit;
}
- if (!cfg->scan_request) {
- brcmf_dbg(SCAN, "result without cfg80211 request\n");
- goto exit;
- }
-
if (le16_to_cpu(escan_result_le->bss_count) != 1) {
brcmf_err("Invalid bss_count %d: ignoring\n",
escan_result_le->bss_count);
@@ -2481,6 +2607,14 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
}
bss_info_le = &escan_result_le->bss_info_le;
+ if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
+ goto exit;
+
+ if (!cfg->scan_request) {
+ brcmf_dbg(SCAN, "result without cfg80211 request\n");
+ goto exit;
+ }
+
bi_length = le32_to_cpu(bss_info_le->length);
if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
WL_ESCAN_RESULTS_FIXED_SIZE)) {
@@ -2519,6 +2653,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
list->count++;
} else {
cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
+ goto exit;
if (cfg->scan_request) {
cfg->bss_list = (struct brcmf_scan_results *)
cfg->escan_info.escan_buf;
@@ -2527,7 +2663,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
brcmf_notify_escan_complete(cfg, ndev, aborted,
false);
} else
- brcmf_err("Unexpected scan result 0x%x\n", status);
+ brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
+ status);
}
exit:
return err;
@@ -3031,9 +3168,8 @@ static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
}
#endif
-static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx)
+static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
{
- struct brcmf_if *ifp = netdev_priv(ndev);
s32 err;
/* set auth */
@@ -3292,7 +3428,7 @@ brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
parsed_info->vndrie.oui[2],
parsed_info->vndrie.oui_type);
- if (vndr_ies->count >= MAX_VNDR_IE_NUMBER)
+ if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
break;
next:
remaining_len -= (ie->len + TLV_HDR_LEN);
@@ -3326,7 +3462,6 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
return ie_len + VNDR_IE_HDR_SIZE;
}
-static
s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
const u8 *vndr_ie_buf, u32 vndr_ie_len)
{
@@ -3358,24 +3493,28 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
if (!iovar_ie_buf)
return -ENOMEM;
curr_ie_buf = iovar_ie_buf;
- if (ifp->vif->mode == WL_MODE_AP) {
- switch (pktflag) {
- case VNDR_IE_PRBRSP_FLAG:
- mgmt_ie_buf = saved_ie->probe_res_ie;
- mgmt_ie_len = &saved_ie->probe_res_ie_len;
- mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
- break;
- case VNDR_IE_BEACON_FLAG:
- mgmt_ie_buf = saved_ie->beacon_ie;
- mgmt_ie_len = &saved_ie->beacon_ie_len;
- mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
- break;
- default:
- err = -EPERM;
- brcmf_err("not suitable type\n");
- goto exit;
- }
- } else {
+ switch (pktflag) {
+ case BRCMF_VNDR_IE_PRBREQ_FLAG:
+ mgmt_ie_buf = saved_ie->probe_req_ie;
+ mgmt_ie_len = &saved_ie->probe_req_ie_len;
+ mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
+ break;
+ case BRCMF_VNDR_IE_PRBRSP_FLAG:
+ mgmt_ie_buf = saved_ie->probe_res_ie;
+ mgmt_ie_len = &saved_ie->probe_res_ie_len;
+ mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
+ break;
+ case BRCMF_VNDR_IE_BEACON_FLAG:
+ mgmt_ie_buf = saved_ie->beacon_ie;
+ mgmt_ie_len = &saved_ie->beacon_ie_len;
+ mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
+ break;
+ case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
+ mgmt_ie_buf = saved_ie->assoc_req_ie;
+ mgmt_ie_len = &saved_ie->assoc_req_ie_len;
+ mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
+ break;
+ default:
err = -EPERM;
brcmf_err("not suitable type\n");
goto exit;
@@ -3484,6 +3623,49 @@ exit:
return err;
}
+s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
+{
+ s32 pktflags[] = {
+ BRCMF_VNDR_IE_PRBREQ_FLAG,
+ BRCMF_VNDR_IE_PRBRSP_FLAG,
+ BRCMF_VNDR_IE_BEACON_FLAG
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pktflags); i++)
+ brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
+
+ memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
+ return 0;
+}
+
+static s32
+brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
+ struct cfg80211_beacon_data *beacon)
+{
+ s32 err;
+
+ /* Set Beacon IEs to FW */
+ err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
+ beacon->tail, beacon->tail_len);
+ if (err) {
+ brcmf_err("Set Beacon IE Failed\n");
+ return err;
+ }
+ brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
+
+ /* Set Probe Response IEs to FW */
+ err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
+ beacon->proberesp_ies,
+ beacon->proberesp_ies_len);
+ if (err)
+ brcmf_err("Set Probe Resp IE Failed\n");
+ else
+ brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
+
+ return err;
+}
+
static s32
brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_ap_settings *settings)
@@ -3496,7 +3678,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
struct brcmf_tlv *rsn_ie;
struct brcmf_vs_tlv *wpa_ie;
struct brcmf_join_params join_params;
- s32 bssidx = 0;
+ enum nl80211_iftype dev_role;
+ struct brcmf_fil_bss_enable_le bss_enable;
brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
cfg80211_get_chandef_type(&settings->chandef),
@@ -3506,10 +3689,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
settings->ssid, settings->ssid_len, settings->auth_type,
settings->inactivity_timeout);
- if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
- brcmf_err("Not in AP creation mode\n");
- return -EPERM;
- }
+ dev_role = ifp->vif->wdev.iftype;
memset(&ssid_le, 0, sizeof(ssid_le));
if (settings->ssid == NULL || settings->ssid_len == 0) {
@@ -3530,21 +3710,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
}
brcmf_set_mpc(ndev, 0);
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
- if (err < 0) {
- brcmf_err("BRCMF_C_DOWN error %d\n", err);
- goto exit;
- }
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
- if (err < 0) {
- brcmf_err("SET INFRA error %d\n", err);
- goto exit;
- }
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
- if (err < 0) {
- brcmf_err("setting AP mode failed %d\n", err);
- goto exit;
- }
/* find the RSN_IE */
rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
@@ -3570,27 +3735,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
}
} else {
brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
- brcmf_configure_opensecurity(ndev, bssidx);
+ brcmf_configure_opensecurity(ifp);
}
- /* Set Beacon IEs to FW */
- err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
- VNDR_IE_BEACON_FLAG,
- settings->beacon.tail,
- settings->beacon.tail_len);
- if (err)
- brcmf_err("Set Beacon IE Failed\n");
- else
- brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
- /* Set Probe Response IEs to FW */
- err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
- VNDR_IE_PRBRSP_FLAG,
- settings->beacon.proberesp_ies,
- settings->beacon.proberesp_ies_len);
- if (err)
- brcmf_err("Set Probe Resp IE Failed\n");
- else
- brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
+ brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
if (settings->beacon_interval) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
@@ -3608,22 +3756,62 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
goto exit;
}
}
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
- if (err < 0) {
- brcmf_err("BRCMF_C_UP error (%d)\n", err);
- goto exit;
+
+ if (dev_role == NL80211_IFTYPE_AP) {
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
+ if (err < 0) {
+ brcmf_err("BRCMF_C_DOWN error %d\n", err);
+ goto exit;
+ }
+ brcmf_fil_iovar_int_set(ifp, "apsta", 0);
}
- memset(&join_params, 0, sizeof(join_params));
- /* join parameters starts with ssid */
- memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
- /* create softap */
- err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
- &join_params, sizeof(join_params));
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
if (err < 0) {
- brcmf_err("SET SSID error (%d)\n", err);
+ brcmf_err("SET INFRA error %d\n", err);
goto exit;
}
+ if (dev_role == NL80211_IFTYPE_AP) {
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
+ if (err < 0) {
+ brcmf_err("setting AP mode failed %d\n", err);
+ goto exit;
+ }
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
+ if (err < 0) {
+ brcmf_err("BRCMF_C_UP error (%d)\n", err);
+ goto exit;
+ }
+
+ memset(&join_params, 0, sizeof(join_params));
+ /* join parameters starts with ssid */
+ memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
+ /* create softap */
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+ &join_params, sizeof(join_params));
+ if (err < 0) {
+ brcmf_err("SET SSID error (%d)\n", err);
+ goto exit;
+ }
+ brcmf_dbg(TRACE, "AP mode configuration complete\n");
+ } else {
+ err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
+ sizeof(ssid_le));
+ if (err < 0) {
+ brcmf_err("setting ssid failed %d\n", err);
+ goto exit;
+ }
+ bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
+ bss_enable.enable = cpu_to_le32(1);
+ err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
+ sizeof(bss_enable));
+ if (err < 0) {
+ brcmf_err("bss_enable config failed %d\n", err);
+ goto exit;
+ }
+
+ brcmf_dbg(TRACE, "GO mode configuration complete\n");
+ }
clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
@@ -3637,10 +3825,11 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err = -EPERM;
+ struct brcmf_fil_bss_enable_le bss_enable;
brcmf_dbg(TRACE, "Enter\n");
- if (ifp->vif->mode == WL_MODE_AP) {
+ if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
/* Due to most likely deauths outstanding we sleep */
/* first to make sure they get processed by fw. */
msleep(400);
@@ -3654,18 +3843,41 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
brcmf_err("BRCMF_C_UP error %d\n", err);
goto exit;
}
- brcmf_set_mpc(ndev, 1);
- clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
- clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+ } else {
+ bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
+ bss_enable.enable = cpu_to_le32(0);
+ err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
+ sizeof(bss_enable));
+ if (err < 0)
+ brcmf_err("bss_enable config failed %d\n", err);
}
+ brcmf_set_mpc(ndev, 1);
+ set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
+ clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
+
exit:
return err;
}
+static s32
+brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_beacon_data *info)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ s32 err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ err = brcmf_config_ap_mgmt_ie(ifp->vif, info);
+
+ return err;
+}
+
static int
brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
u8 *mac)
{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_scb_val_le scbval;
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err;
@@ -3675,6 +3887,8 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(TRACE, "Enter %pM\n", mac);
+ if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
+ ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
if (!check_vif_up(ifp->vif))
return -EIO;
@@ -3689,7 +3903,147 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
return err;
}
+
+static void
+brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u16 frame_type, bool reg)
+{
+ struct brcmf_if *ifp = netdev_priv(wdev->netdev);
+ struct brcmf_cfg80211_vif *vif = ifp->vif;
+ u16 mgmt_type;
+
+ brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
+
+ mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+ if (reg)
+ vif->mgmt_rx_reg |= BIT(mgmt_type);
+ else
+ vif->mgmt_rx_reg &= ~BIT(mgmt_type);
+}
+
+
+static int
+brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
+ struct ieee80211_channel *chan, bool offchan,
+ unsigned int wait, const u8 *buf, size_t len,
+ bool no_cck, bool dont_wait_for_ack, u64 *cookie)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ const struct ieee80211_mgmt *mgmt;
+ struct brcmf_if *ifp;
+ struct brcmf_cfg80211_vif *vif;
+ s32 err = 0;
+ s32 ie_offset;
+ s32 ie_len;
+ struct brcmf_fil_action_frame_le *action_frame;
+ struct brcmf_fil_af_params_le *af_params;
+ bool ack;
+ s32 chan_nr;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ *cookie = 0;
+
+ mgmt = (const struct ieee80211_mgmt *)buf;
+
+ if (!ieee80211_is_mgmt(mgmt->frame_control)) {
+ brcmf_err("Driver only allows MGMT packet type\n");
+ return -EPERM;
+ }
+
+ if (ieee80211_is_probe_resp(mgmt->frame_control)) {
+ /* Right now the only reason to get a probe response */
+ /* is for p2p listen response or for p2p GO from */
+ /* wpa_supplicant. Unfortunately the probe is send */
+ /* on primary ndev, while dongle wants it on the p2p */
+ /* vif. Since this is only reason for a probe */
+ /* response to be sent, the vif is taken from cfg. */
+ /* If ever desired to send proberesp for non p2p */
+ /* response then data should be checked for */
+ /* "DIRECT-". Note in future supplicant will take */
+ /* dedicated p2p wdev to do this and then this 'hack'*/
+ /* is not needed anymore. */
+ ie_offset = DOT11_MGMT_HDR_LEN +
+ DOT11_BCN_PRB_FIXED_LEN;
+ ie_len = len - ie_offset;
+ ifp = netdev_priv(wdev->netdev);
+ vif = ifp->vif;
+ if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
+ vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ err = brcmf_vif_set_mgmt_ie(vif,
+ BRCMF_VNDR_IE_PRBRSP_FLAG,
+ &buf[ie_offset],
+ ie_len);
+ cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
+ GFP_KERNEL);
+ } else if (ieee80211_is_action(mgmt->frame_control)) {
+ af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
+ if (af_params == NULL) {
+ brcmf_err("unable to allocate frame\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+ action_frame = &af_params->action_frame;
+ /* Add the packet Id */
+ action_frame->packet_id = cpu_to_le32(*cookie);
+ /* Add BSSID */
+ memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
+ memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
+ /* Add the length exepted for 802.11 header */
+ action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
+ /* Add the channel */
+ chan_nr = ieee80211_frequency_to_channel(chan->center_freq);
+ af_params->channel = cpu_to_le32(chan_nr);
+
+ memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
+ le16_to_cpu(action_frame->len));
+
+ brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
+ *cookie, le16_to_cpu(action_frame->len),
+ chan->center_freq);
+
+ ack = brcmf_p2p_send_action_frame(cfg, wdev->netdev,
+ af_params);
+
+ cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
+ GFP_KERNEL);
+ kfree(af_params);
+ } else {
+ brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
+ brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
+ }
+
+exit:
+ return err;
+}
+
+
+static int
+brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ u64 cookie)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_cfg80211_vif *vif;
+ int err = 0;
+
+ brcmf_dbg(TRACE, "Enter p2p listen cancel\n");
+
+ vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
+ if (vif == NULL) {
+ brcmf_err("No p2p device available for probe response\n");
+ err = -ENODEV;
+ goto exit;
+ }
+ brcmf_p2p_cancel_remain_on_channel(vif->ifp);
+exit:
+ return err;
+}
+
static struct cfg80211_ops wl_cfg80211_ops = {
+ .add_virtual_intf = brcmf_cfg80211_add_iface,
+ .del_virtual_intf = brcmf_cfg80211_del_iface,
.change_virtual_intf = brcmf_cfg80211_change_iface,
.scan = brcmf_cfg80211_scan,
.set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
@@ -3704,7 +4058,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.set_default_key = brcmf_cfg80211_config_default_key,
.set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
.set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
- .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask,
.connect = brcmf_cfg80211_connect,
.disconnect = brcmf_cfg80211_disconnect,
.suspend = brcmf_cfg80211_suspend,
@@ -3714,28 +4067,43 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.flush_pmksa = brcmf_cfg80211_flush_pmksa,
.start_ap = brcmf_cfg80211_start_ap,
.stop_ap = brcmf_cfg80211_stop_ap,
+ .change_beacon = brcmf_cfg80211_change_beacon,
.del_station = brcmf_cfg80211_del_station,
.sched_scan_start = brcmf_cfg80211_sched_scan_start,
.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
+ .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
+ .mgmt_tx = brcmf_cfg80211_mgmt_tx,
+ .remain_on_channel = brcmf_p2p_remain_on_channel,
+ .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
#ifdef CONFIG_NL80211_TESTMODE
.testmode_cmd = brcmf_cfg80211_testmode
#endif
};
-static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
+static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type)
{
- s32 err = 0;
-
- switch (mode) {
- case WL_MODE_BSS:
- return NL80211_IFTYPE_STATION;
- case WL_MODE_IBSS:
- return NL80211_IFTYPE_ADHOC;
+ switch (type) {
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_MESH_POINT:
+ return -ENOTSUPP;
+ case NL80211_IFTYPE_ADHOC:
+ return WL_MODE_IBSS;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ return WL_MODE_BSS;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ return WL_MODE_AP;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ return WL_MODE_P2P;
+ case NL80211_IFTYPE_UNSPECIFIED:
default:
- return NL80211_IFTYPE_UNSPECIFIED;
+ break;
}
- return err;
+ return -EINVAL;
}
static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
@@ -3747,6 +4115,56 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
}
+static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP)
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO)
+ },
+};
+static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
+ {
+ .max_interfaces = BRCMF_IFACE_MAX_CNT,
+ .num_different_channels = 1, /* no multi-channel for now */
+ .n_limits = ARRAY_SIZE(brcmf_iface_limits),
+ .limits = brcmf_iface_limits
+ }
+};
+
+static const struct ieee80211_txrx_stypes
+brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_STATION] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ }
+};
+
static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
{
struct wiphy *wiphy;
@@ -3759,10 +4177,16 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
}
set_wiphy_dev(wiphy, phydev);
wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+ wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP);
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
+ wiphy->iface_combinations = brcmf_iface_combos;
+ wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
* it as 11a by default.
@@ -3774,10 +4198,11 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->cipher_suites = __wl_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
- wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
- * save mode
- * by default
- */
+ wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
+ WIPHY_FLAG_OFFCHAN_TX |
+ WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ wiphy->mgmt_stypes = brcmf_txrx_stypes;
+ wiphy->max_remain_on_channel_duration = 5000;
brcmf_wiphy_pno_params(wiphy);
err = wiphy_register(wiphy);
if (err < 0) {
@@ -3788,31 +4213,25 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
return wiphy;
}
-static
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
- struct net_device *netdev,
- s32 mode, bool pm_block)
+ enum nl80211_iftype type,
+ bool pm_block)
{
struct brcmf_cfg80211_vif *vif;
if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
return ERR_PTR(-ENOSPC);
+ brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
+ sizeof(*vif));
vif = kzalloc(sizeof(*vif), GFP_KERNEL);
if (!vif)
return ERR_PTR(-ENOMEM);
vif->wdev.wiphy = cfg->wiphy;
- vif->wdev.netdev = netdev;
- vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
+ vif->wdev.iftype = type;
- if (netdev) {
- vif->ifp = netdev_priv(netdev);
- netdev->ieee80211_ptr = &vif->wdev;
- SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
- }
-
- vif->mode = mode;
+ vif->mode = brcmf_nl80211_iftype_to_mode(type);
vif->pm_block = pm_block;
vif->roam_off = -1;
@@ -3823,7 +4242,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
return vif;
}
-static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
{
struct brcmf_cfg80211_info *cfg;
struct wiphy *wiphy;
@@ -3897,9 +4316,9 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
conn_info->resp_ie_len = 0;
}
-static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
+static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_if *ifp)
{
- struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
u32 req_len;
@@ -3975,9 +4394,9 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
brcmf_dbg(TRACE, "Enter\n");
- brcmf_get_assoc_ies(cfg);
+ brcmf_get_assoc_ies(cfg, ifp);
memcpy(profile->bssid, e->addr, ETH_ALEN);
- brcmf_update_bss_info(cfg);
+ brcmf_update_bss_info(cfg, ifp);
buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
if (buf == NULL) {
@@ -4032,9 +4451,11 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
&ifp->vif->sme_state)) {
if (completed) {
- brcmf_get_assoc_ies(cfg);
+ brcmf_get_assoc_ies(cfg, ifp);
memcpy(profile->bssid, e->addr, ETH_ALEN);
- brcmf_update_bss_info(cfg);
+ brcmf_update_bss_info(cfg, ifp);
+ set_bit(BRCMF_VIF_STATUS_CONNECTED,
+ &ifp->vif->sme_state);
}
cfg80211_connect_result(ndev,
(u8 *)profile->bssid,
@@ -4045,9 +4466,6 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
completed ? WLAN_STATUS_SUCCESS :
WLAN_STATUS_AUTH_TIMEOUT,
GFP_KERNEL);
- if (completed)
- set_bit(BRCMF_VIF_STATUS_CONNECTED,
- &ifp->vif->sme_state);
brcmf_dbg(CONN, "Report connect result - connection %s\n",
completed ? "succeeded" : "failed");
}
@@ -4060,38 +4478,38 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
struct net_device *ndev,
const struct brcmf_event_msg *e, void *data)
{
- s32 err = 0;
+ static int generation;
u32 event = e->event_code;
u32 reason = e->reason;
- u32 len = e->datalen;
- static int generation;
-
struct station_info sinfo;
brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
- memset(&sinfo, 0, sizeof(sinfo));
+ if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
+ ndev != cfg_to_ndev(cfg)) {
+ brcmf_dbg(CONN, "AP mode link down\n");
+ complete(&cfg->vif_disabled);
+ return 0;
+ }
- sinfo.filled = 0;
if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
- reason == BRCMF_E_STATUS_SUCCESS) {
+ (reason == BRCMF_E_STATUS_SUCCESS)) {
+ memset(&sinfo, 0, sizeof(sinfo));
sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
if (!data) {
brcmf_err("No IEs present in ASSOC/REASSOC_IND");
return -EINVAL;
}
sinfo.assoc_req_ies = data;
- sinfo.assoc_req_ies_len = len;
+ sinfo.assoc_req_ies_len = e->datalen;
generation++;
sinfo.generation = generation;
- cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC);
+ cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
} else if ((event == BRCMF_E_DISASSOC_IND) ||
(event == BRCMF_E_DEAUTH_IND) ||
(event == BRCMF_E_DEAUTH)) {
- generation++;
- sinfo.generation = generation;
- cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC);
+ cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
}
- return err;
+ return 0;
}
static s32
@@ -4128,6 +4546,8 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
}
brcmf_link_down(ifp->vif);
brcmf_init_prof(ndev_to_prof(ndev));
+ if (ndev != cfg_to_ndev(cfg))
+ complete(&cfg->vif_disabled);
} else if (brcmf_is_nonetwork(cfg, e)) {
if (brcmf_is_ibssmode(ifp->vif))
clear_bit(BRCMF_VIF_STATUS_CONNECTING,
@@ -4176,6 +4596,57 @@ brcmf_notify_mic_status(struct brcmf_if *ifp,
return 0;
}
+static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e, void *data)
+{
+ struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+ struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
+ struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+ struct brcmf_cfg80211_vif *vif;
+
+ brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
+ ifevent->action, ifevent->flags, ifevent->ifidx,
+ ifevent->bssidx);
+
+ mutex_lock(&event->vif_event_lock);
+ event->action = ifevent->action;
+ vif = event->vif;
+
+ switch (ifevent->action) {
+ case BRCMF_E_IF_ADD:
+ /* waiting process may have timed out */
+ if (!cfg->vif_event.vif)
+ return -EBADF;
+
+ ifp->vif = vif;
+ vif->ifp = ifp;
+ vif->wdev.netdev = ifp->ndev;
+ ifp->ndev->ieee80211_ptr = &vif->wdev;
+ SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
+ mutex_unlock(&event->vif_event_lock);
+ wake_up(&event->vif_wq);
+ return 0;
+
+ case BRCMF_E_IF_DEL:
+ ifp->vif = NULL;
+ mutex_unlock(&event->vif_event_lock);
+ /* event may not be upon user request */
+ if (brcmf_cfg80211_vif_event_armed(cfg))
+ wake_up(&event->vif_wq);
+ return 0;
+
+ case BRCMF_E_IF_CHANGE:
+ mutex_unlock(&event->vif_event_lock);
+ wake_up(&event->vif_wq);
+ return 0;
+
+ default:
+ mutex_unlock(&event->vif_event_lock);
+ break;
+ }
+ return -EINVAL;
+}
+
static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
{
conf->frag_threshold = (u32)-1;
@@ -4207,6 +4678,18 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
brcmf_notify_connect_status);
brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
brcmf_notify_sched_scan_results);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
+ brcmf_notify_vif_event);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
+ brcmf_p2p_notify_rx_mgmt_p2p_probereq);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
+ brcmf_p2p_notify_listen_complete);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
+ brcmf_p2p_notify_action_frame_rx);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
+ brcmf_p2p_notify_action_tx_complete);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
+ brcmf_p2p_notify_action_tx_complete);
}
static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
@@ -4262,7 +4745,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
mutex_init(&cfg->usr_sync);
brcmf_init_escan(cfg);
brcmf_init_conf(cfg->conf);
-
+ init_completion(&cfg->vif_disabled);
return err;
}
@@ -4273,6 +4756,12 @@ static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
brcmf_deinit_priv_mem(cfg);
}
+static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
+{
+ init_waitqueue_head(&event->vif_wq);
+ mutex_init(&event->vif_event_lock);
+}
+
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
struct device *busdev)
{
@@ -4296,25 +4785,41 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
cfg = wiphy_priv(wiphy);
cfg->wiphy = wiphy;
cfg->pub = drvr;
+ init_vif_event(&cfg->vif_event);
INIT_LIST_HEAD(&cfg->vif_list);
- vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
+ vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
if (IS_ERR(vif)) {
wiphy_free(wiphy);
return NULL;
}
+ vif->ifp = ifp;
+ vif->wdev.netdev = ndev;
+ ndev->ieee80211_ptr = &vif->wdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
+
err = wl_init_priv(cfg);
if (err) {
brcmf_err("Failed to init iwm_priv (%d)\n", err);
goto cfg80211_attach_out;
}
-
ifp->vif = vif;
+
+ err = brcmf_p2p_attach(cfg);
+ if (err) {
+ brcmf_err("P2P initilisation failed (%d)\n", err);
+ goto cfg80211_p2p_attach_out;
+ }
+
return cfg;
+cfg80211_p2p_attach_out:
+ wl_deinit_priv(cfg);
+
cfg80211_attach_out:
brcmf_free_vif(vif);
+ wiphy_free(wiphy);
return NULL;
}
@@ -4330,9 +4835,8 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
}
static s32
-brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
+brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
{
- struct brcmf_if *ifp = netdev_priv(ndev);
s32 err = 0;
__le32 roamtrigger[2];
__le32 roam_delta[2];
@@ -4383,10 +4887,9 @@ dongle_rom_out:
}
static s32
-brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
+brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
s32 scan_unassoc_time, s32 scan_passive_time)
{
- struct brcmf_if *ifp = netdev_priv(ndev);
s32 err = 0;
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
@@ -4456,6 +4959,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
{
struct net_device *ndev;
struct wireless_dev *wdev;
+ struct brcmf_if *ifp;
s32 power_mode;
s32 err = 0;
@@ -4464,35 +4968,34 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
ndev = cfg_to_ndev(cfg);
wdev = ndev->ieee80211_ptr;
+ ifp = netdev_priv(ndev);
+
+ /* make sure RF is ready for work */
+ brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
- brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
- WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
+ brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
+ WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
- err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
- power_mode);
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
if (err)
goto default_conf_out;
brcmf_dbg(INFO, "power save set to %s\n",
(power_mode ? "enabled" : "disabled"));
- err = brcmf_dongle_roam(ndev, (cfg->roam_on ? 0 : 1),
- WL_BEACON_TIMEOUT);
+ err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
if (err)
goto default_conf_out;
err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
NULL, NULL);
- if (err && err != -EINPROGRESS)
+ if (err)
goto default_conf_out;
err = brcmf_dongle_probecap(cfg);
if (err)
goto default_conf_out;
- /* -EINPROGRESS: Call commit handler */
-
-default_conf_out:
-
cfg->dongle_up = true;
+default_conf_out:
return err;
@@ -4501,8 +5004,6 @@ default_conf_out:
static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
{
set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
- if (ifp->idx)
- return 0;
return brcmf_config_dongle(ifp->drvr->config);
}
@@ -4557,3 +5058,57 @@ s32 brcmf_cfg80211_down(struct net_device *ndev)
return err;
}
+u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
+{
+ struct brcmf_cfg80211_vif *vif;
+ bool result = 0;
+
+ list_for_each_entry(vif, &cfg->vif_list, list) {
+ if (test_bit(state, &vif->sme_state))
+ result++;
+ }
+ return result;
+}
+
+static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
+ u8 action)
+{
+ u8 evt_action;
+
+ mutex_lock(&event->vif_event_lock);
+ evt_action = event->action;
+ mutex_unlock(&event->vif_event_lock);
+ return evt_action == action;
+}
+
+void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_cfg80211_vif *vif)
+{
+ struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+
+ mutex_lock(&event->vif_event_lock);
+ event->vif = vif;
+ event->action = 0;
+ mutex_unlock(&event->vif_event_lock);
+}
+
+bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+ bool armed;
+
+ mutex_lock(&event->vif_event_lock);
+ armed = event->vif != NULL;
+ mutex_unlock(&event->vif_event_lock);
+
+ return armed;
+}
+int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
+ u8 action, ulong timeout)
+{
+ struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
+
+ return wait_event_timeout(event->vif_wq,
+ vif_event_equals(event, action), timeout);
+}
+
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
index e4d9cc7a8e63..8b5d4989906c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
@@ -41,6 +41,38 @@
#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */
#define IE_MAX_LEN 512
+/* IE TLV processing */
+#define TLV_LEN_OFF 1 /* length offset */
+#define TLV_HDR_LEN 2 /* header length */
+#define TLV_BODY_OFF 2 /* body offset */
+#define TLV_OUI_LEN 3 /* oui id length */
+
+/* 802.11 Mgmt Packet flags */
+#define BRCMF_VNDR_IE_BEACON_FLAG 0x1
+#define BRCMF_VNDR_IE_PRBRSP_FLAG 0x2
+#define BRCMF_VNDR_IE_ASSOCRSP_FLAG 0x4
+#define BRCMF_VNDR_IE_AUTHRSP_FLAG 0x8
+#define BRCMF_VNDR_IE_PRBREQ_FLAG 0x10
+#define BRCMF_VNDR_IE_ASSOCREQ_FLAG 0x20
+/* vendor IE in IW advertisement protocol ID field */
+#define BRCMF_VNDR_IE_IWAPID_FLAG 0x40
+/* allow custom IE id */
+#define BRCMF_VNDR_IE_CUSTOM_FLAG 0x100
+
+/* P2P Action Frames flags (spec ordered) */
+#define BRCMF_VNDR_IE_GONREQ_FLAG 0x001000
+#define BRCMF_VNDR_IE_GONRSP_FLAG 0x002000
+#define BRCMF_VNDR_IE_GONCFM_FLAG 0x004000
+#define BRCMF_VNDR_IE_INVREQ_FLAG 0x008000
+#define BRCMF_VNDR_IE_INVRSP_FLAG 0x010000
+#define BRCMF_VNDR_IE_DISREQ_FLAG 0x020000
+#define BRCMF_VNDR_IE_DISRSP_FLAG 0x040000
+#define BRCMF_VNDR_IE_PRDREQ_FLAG 0x080000
+#define BRCMF_VNDR_IE_PRDRSP_FLAG 0x100000
+
+#define BRCMF_VNDR_IE_P2PAF_SHIFT 12
+
+
/**
* enum brcmf_scan_status - dongle scan status
*
@@ -52,11 +84,19 @@ enum brcmf_scan_status {
BRCMF_SCAN_STATUS_ABORT,
};
-/* wi-fi mode */
+/**
+ * enum wl_mode - driver mode of virtual interface.
+ *
+ * @WL_MODE_BSS: connects to BSS.
+ * @WL_MODE_IBSS: operate as ad-hoc.
+ * @WL_MODE_AP: operate as access-point.
+ * @WL_MODE_P2P: provide P2P discovery.
+ */
enum wl_mode {
WL_MODE_BSS,
WL_MODE_IBSS,
- WL_MODE_AP
+ WL_MODE_AP,
+ WL_MODE_P2P
};
/* dongle configuration */
@@ -108,6 +148,7 @@ struct brcmf_cfg80211_profile {
* @BRCMF_VIF_STATUS_READY: ready for operation.
* @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
* @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
+ * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
* @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation.
* @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
*/
@@ -115,6 +156,7 @@ enum brcmf_vif_status {
BRCMF_VIF_STATUS_READY,
BRCMF_VIF_STATUS_CONNECTING,
BRCMF_VIF_STATUS_CONNECTED,
+ BRCMF_VIF_STATUS_DISCONNECTING,
BRCMF_VIF_STATUS_AP_CREATING,
BRCMF_VIF_STATUS_AP_CREATED
};
@@ -122,16 +164,22 @@ enum brcmf_vif_status {
/**
* struct vif_saved_ie - holds saved IEs for a virtual interface.
*
+ * @probe_req_ie: IE info for probe request.
* @probe_res_ie: IE info for probe response.
* @beacon_ie: IE info for beacon frame.
+ * @probe_req_ie_len: IE info length for probe request.
* @probe_res_ie_len: IE info length for probe response.
* @beacon_ie_len: IE info length for beacon frame.
*/
struct vif_saved_ie {
+ u8 probe_req_ie[IE_MAX_LEN];
u8 probe_res_ie[IE_MAX_LEN];
u8 beacon_ie[IE_MAX_LEN];
+ u8 assoc_req_ie[IE_MAX_LEN];
+ u32 probe_req_ie_len;
u32 probe_res_ie_len;
u32 beacon_ie_len;
+ u32 assoc_req_ie_len;
};
/**
@@ -145,6 +193,7 @@ struct vif_saved_ie {
* @sme_state: SME state using enum brcmf_vif_status bits.
* @pm_block: power-management blocked.
* @list: linked list.
+ * @mgmt_rx_reg: registered rx mgmt frame types.
*/
struct brcmf_cfg80211_vif {
struct brcmf_if *ifp;
@@ -156,6 +205,7 @@ struct brcmf_cfg80211_vif {
bool pm_block;
struct vif_saved_ie saved_ie;
struct list_head list;
+ u16 mgmt_rx_reg;
};
/* association inform */
@@ -189,6 +239,9 @@ struct escan_info {
u8 escan_buf[WL_ESCAN_BUF_SIZE];
struct wiphy *wiphy;
struct net_device *ndev;
+ s32 (*run)(struct brcmf_cfg80211_info *cfg,
+ struct net_device *ndev,
+ struct cfg80211_scan_request *request, u16 action);
};
/**
@@ -273,10 +326,27 @@ struct brcmf_pno_scanresults_le {
};
/**
+ * struct brcmf_cfg80211_vif_event - virtual interface event information.
+ *
+ * @vif_wq: waitqueue awaiting interface event from firmware.
+ * @vif_event_lock: protects other members in this structure.
+ * @vif_complete: completion for net attach.
+ * @action: either add, change, or delete.
+ * @vif: virtual interface object related to the event.
+ */
+struct brcmf_cfg80211_vif_event {
+ wait_queue_head_t vif_wq;
+ struct mutex vif_event_lock;
+ u8 action;
+ struct brcmf_cfg80211_vif *vif;
+};
+
+/**
* struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
*
* @wiphy: wiphy object for cfg80211 interface.
* @conf: dongle configuration.
+ * @p2p: peer-to-peer specific information.
* @scan_request: cfg80211 scan request object.
* @usr_sync: mainly for dongle up/down synchronization.
* @bss_list: bss_list holding scanned ap information.
@@ -304,10 +374,12 @@ struct brcmf_pno_scanresults_le {
* @escan_ioctl_buf: dongle command buffer for escan commands.
* @vif_list: linked list of vif instances.
* @vif_cnt: number of vif instances.
+ * @vif_event: vif event signalling.
*/
struct brcmf_cfg80211_info {
struct wiphy *wiphy;
struct brcmf_cfg80211_conf *conf;
+ struct brcmf_p2p_info p2p;
struct cfg80211_scan_request *scan_request;
struct mutex usr_sync;
struct brcmf_scan_results *bss_list;
@@ -335,6 +407,21 @@ struct brcmf_cfg80211_info {
u8 *escan_ioctl_buf;
struct list_head vif_list;
u8 vif_cnt;
+ struct brcmf_cfg80211_vif_event vif_event;
+ struct completion vif_disabled;
+};
+
+/**
+ * struct brcmf_tlv - tag_ID/length/value_buffer tuple.
+ *
+ * @id: tag identifier.
+ * @len: number of bytes in value buffer.
+ * @data: value buffer.
+ */
+struct brcmf_tlv {
+ u8 id;
+ u8 len;
+ u8 data[1];
};
static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg)
@@ -389,4 +476,26 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
s32 brcmf_cfg80211_up(struct net_device *ndev);
s32 brcmf_cfg80211_down(struct net_device *ndev);
+struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
+ enum nl80211_iftype type,
+ bool pm_block);
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
+
+s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
+ const u8 *vndr_ie_buf, u32 vndr_ie_len);
+s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
+struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key);
+u16 channel_to_chanspec(struct ieee80211_channel *ch);
+u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state);
+void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_cfg80211_vif *vif);
+bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
+int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
+ u8 action, ulong timeout);
+s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
+ struct net_device *ndev,
+ bool aborted, bool fw_abort);
+void brcmf_set_mpc(struct net_device *ndev, int mpc);
+void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
+
#endif /* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
index 1de94f30564f..1585cc5bf866 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
@@ -961,7 +961,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
/* if acked then clear bit and free packet */
if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
&& isset(bitmap, bindex)) {
- ini->tx_in_transit--;
ini->txretry[index] = 0;
/*
@@ -990,7 +989,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
if (retry && (ini->txretry[index] < (int)retry_limit)) {
int ret;
ini->txretry[index]++;
- ini->tx_in_transit--;
ret = brcms_c_txfifo(wlc, queue, p);
/*
* We shouldn't be out of space in the DMA
@@ -1000,7 +998,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
WARN_ONCE(ret, "queue %d out of txds\n", queue);
} else {
/* Retry timeout */
- ini->tx_in_transit--;
ieee80211_tx_info_clear_status(tx_info);
tx_info->status.ampdu_ack_len = 0;
tx_info->status.ampdu_len = 1;
@@ -1009,8 +1006,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
skb_pull(p, D11_PHY_HDR_LEN);
skb_pull(p, D11_TXH_LEN);
brcms_dbg_ht(wlc->hw->d11core,
- "BA Timeout, seq %d, in_transit %d\n",
- seq, ini->tx_in_transit);
+ "BA Timeout, seq %d\n",
+ seq);
ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
p);
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
index a90b72202ec5..10ee314c4229 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
@@ -183,8 +183,7 @@ static bool brcms_c_country_valid(const char *ccode)
* chars.
*/
if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A &&
- (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A &&
- ccode[2] == '\0'))
+ (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A))
return false;
/*
@@ -670,7 +669,7 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
const struct ieee80211_reg_rule *rule;
- int band, i, ret;
+ int band, i;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
sband = wiphy->bands[band];
@@ -685,9 +684,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
- ret = freq_reg_info(wiphy, ch->center_freq,
- 0, &rule);
- if (ret)
+ rule = freq_reg_info(wiphy, ch->center_freq);
+ if (IS_ERR(rule))
continue;
if (!(rule->flags & NL80211_RRF_NO_IBSS))
@@ -703,8 +701,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
}
}
-static int brcms_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
+static void brcms_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct brcms_info *wl = hw->priv;
@@ -745,8 +743,6 @@ static int brcms_reg_notifier(struct wiphy *wiphy,
if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
brcms_c_japan_ccode(request->alpha2));
-
- return 0;
}
void brcms_c_regd_init(struct brcms_c_info *wlc)
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 0f71d1d4339d..c6451c61407a 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -36,6 +36,7 @@
#include "debug.h"
#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */
+#define BRCMS_FLUSH_TIMEOUT 500 /* msec */
/* Flags we support */
#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
@@ -362,8 +363,11 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
return -EOPNOTSUPP;
}
+ spin_lock_bh(&wl->lock);
+ memcpy(wl->pub->cur_etheraddr, vif->addr, sizeof(vif->addr));
wl->mute_tx = false;
brcms_c_mute(wl->wlc, false);
+ spin_unlock_bh(&wl->lock);
return 0;
}
@@ -539,9 +543,8 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ARP_FILTER) {
/* Hardware ARP filter address list or state changed */
- brcms_err(core, "%s: arp filtering: enabled %s, count %d"
- " (implement)\n", __func__, info->arp_filter_enabled ?
- "true" : "false", info->arp_addr_cnt);
+ brcms_err(core, "%s: arp filtering: %d addresses"
+ " (implement)\n", __func__, info->arp_addr_cnt);
}
if (changed & BSS_CHANGED_QOS) {
@@ -668,7 +671,9 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
spin_lock_bh(&wl->lock);
brcms_c_ampdu_flush(wl->wlc, sta, tid);
spin_unlock_bh(&wl->lock);
@@ -708,16 +713,29 @@ static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw)
wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked);
}
+static bool brcms_tx_flush_completed(struct brcms_info *wl)
+{
+ bool result;
+
+ spin_lock_bh(&wl->lock);
+ result = brcms_c_tx_flush_completed(wl->wlc);
+ spin_unlock_bh(&wl->lock);
+ return result;
+}
+
static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
{
struct brcms_info *wl = hw->priv;
+ int ret;
no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false");
- /* wait for packet queue and dma fifos to run empty */
- spin_lock_bh(&wl->lock);
- brcms_c_wait_for_tx_completion(wl->wlc, drop);
- spin_unlock_bh(&wl->lock);
+ ret = wait_event_timeout(wl->tx_flush_wq,
+ brcms_tx_flush_completed(wl),
+ msecs_to_jiffies(BRCMS_FLUSH_TIMEOUT));
+
+ brcms_dbg_mac80211(wl->wlc->hw->d11core,
+ "ret=%d\n", jiffies_to_msecs(ret));
}
static const struct ieee80211_ops brcms_ops = {
@@ -772,6 +790,7 @@ void brcms_dpc(unsigned long data)
done:
spin_unlock_bh(&wl->lock);
+ wake_up(&wl->tx_flush_wq);
}
/*
@@ -1020,6 +1039,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
atomic_set(&wl->callbacks, 0);
+ init_waitqueue_head(&wl->tx_flush_wq);
+
/* setup the bottom half handler */
tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl);
@@ -1609,13 +1630,3 @@ bool brcms_rfkill_set_hw_state(struct brcms_info *wl)
spin_lock_bh(&wl->lock);
return blocked;
}
-
-/*
- * precondition: perimeter lock has been acquired
- */
-void brcms_msleep(struct brcms_info *wl, uint ms)
-{
- spin_unlock_bh(&wl->lock);
- msleep(ms);
- spin_lock_bh(&wl->lock);
-}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
index 9358bd5ebd35..947ccacf43e6 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
@@ -68,6 +68,8 @@ struct brcms_info {
spinlock_t lock; /* per-device perimeter lock */
spinlock_t isr_lock; /* per-device ISR synchronization lock */
+ /* tx flush */
+ wait_queue_head_t tx_flush_wq;
/* timer related fields */
atomic_t callbacks; /* # outstanding callback functions */
@@ -100,7 +102,6 @@ extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl,
extern void brcms_free_timer(struct brcms_timer *timer);
extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic);
extern bool brcms_del_timer(struct brcms_timer *timer);
-extern void brcms_msleep(struct brcms_info *wl, uint ms);
extern void brcms_dpc(unsigned long data);
extern void brcms_timer(struct brcms_timer *t);
extern void brcms_fatal_error(struct brcms_info *wl);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 17594de4199e..8ef02dca8f8c 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -101,8 +101,6 @@
#define DOT11_RTS_LEN 16
#define DOT11_CTS_LEN 10
#define DOT11_BA_BITMAP_LEN 128
-#define DOT11_MIN_BEACON_PERIOD 1
-#define DOT11_MAX_BEACON_PERIOD 0xFFFF
#define DOT11_MAXNUMFRAGS 16
#define DOT11_MAX_FRAG_LEN 2346
@@ -1027,7 +1025,6 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
static bool
brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
{
- bool morepending = false;
struct bcma_device *core;
struct tx_status txstatus, *txs;
u32 s1, s2;
@@ -1041,23 +1038,20 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
txs = &txstatus;
core = wlc_hw->d11core;
*fatal = false;
- s1 = bcma_read32(core, D11REGOFFS(frmtxstatus));
- while (!(*fatal)
- && (s1 & TXS_V)) {
- /* !give others some time to run! */
- if (n >= max_tx_num) {
- morepending = true;
- break;
- }
+ while (n < max_tx_num) {
+ s1 = bcma_read32(core, D11REGOFFS(frmtxstatus));
if (s1 == 0xffffffff) {
brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
__func__);
*fatal = true;
return false;
}
- s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2));
+ /* only process when valid */
+ if (!(s1 & TXS_V))
+ break;
+ s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2));
txs->status = s1 & TXS_STATUS_MASK;
txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;
txs->sequence = s2 & TXS_SEQ_MASK;
@@ -1065,15 +1059,12 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
txs->lasttxtime = 0;
*fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs);
-
- s1 = bcma_read32(core, D11REGOFFS(frmtxstatus));
+ if (*fatal == true)
+ return false;
n++;
}
- if (*fatal)
- return false;
-
- return morepending;
+ return n >= max_tx_num;
}
static void brcms_c_tbtt(struct brcms_c_info *wlc)
@@ -2473,6 +2464,7 @@ static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
{
static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+ u8 *ethaddr = wlc_hw->wlc->pub->cur_etheraddr;
if (mute_tx) {
/* suspend tx fifos */
@@ -2482,8 +2474,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);
/* zero the address match register so we do not send ACKs */
- brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
- null_ether_addr);
+ brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, null_ether_addr);
} else {
/* resume tx fifos */
brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);
@@ -2492,8 +2483,7 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);
/* Restore address */
- brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
- wlc_hw->etheraddr);
+ brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, ethaddr);
}
wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0);
@@ -3148,8 +3138,7 @@ void brcms_c_reset(struct brcms_c_info *wlc)
brcms_c_statsupd(wlc);
/* reset our snapshot of macstat counters */
- memset((char *)wlc->core->macstat_snapshot, 0,
- sizeof(struct macstat));
+ memset(wlc->core->macstat_snapshot, 0, sizeof(struct macstat));
brcms_b_reset(wlc->hw);
}
@@ -4062,7 +4051,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
return;
}
- memset((char *)&acp_shm, 0, sizeof(struct shm_acparams));
+ memset(&acp_shm, 0, sizeof(struct shm_acparams));
/* fill in shm ac params struct */
acp_shm.txop = params->txop;
/* convert from units of 32us to us for ucode */
@@ -4778,7 +4767,7 @@ static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
struct brcms_bss_info *bi = wlc->default_bss;
/* init default and target BSS with some sane initial values */
- memset((char *)(bi), 0, sizeof(struct brcms_bss_info));
+ memset(bi, 0, sizeof(*bi));
bi->beacon_period = BEACON_INTERVAL_DEFAULT;
/* fill the default channel as the first valid channel
@@ -5307,7 +5296,7 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode);
/* Clear rateset override */
- memset(&rs, 0, sizeof(struct brcms_c_rateset));
+ memset(&rs, 0, sizeof(rs));
switch (gmode) {
case GMODE_LEGACY_B:
@@ -5530,7 +5519,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
if (rs->count > BRCMS_NUMRATES)
return -ENOBUFS;
- memset(&internal_rs, 0, sizeof(struct brcms_c_rateset));
+ memset(&internal_rs, 0, sizeof(internal_rs));
/* Copy only legacy rateset section */
internal_rs.count = rs->count;
@@ -5556,8 +5545,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
{
- if (period < DOT11_MIN_BEACON_PERIOD ||
- period > DOT11_MAX_BEACON_PERIOD)
+ if (period == 0)
return -EINVAL;
wlc->default_bss->beacon_period = period;
@@ -5634,7 +5622,7 @@ int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,
for (i = 0; i < BRCMS_MAXMODULES; i++) {
if (!strcmp(wlc->modulecb[i].name, name) &&
(wlc->modulecb[i].hdl == hdl)) {
- memset(&wlc->modulecb[i], 0, sizeof(struct modulecb));
+ memset(&wlc->modulecb[i], 0, sizeof(wlc->modulecb[i]));
return 0;
}
}
@@ -6454,10 +6442,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
&& (!is_mcs_rate(rspec[k]))) {
- brcms_err(wlc->hw->d11core,
- "wl%d: %s: IEEE80211_TX_"
- "RC_MCS != is_mcs_rate(rspec)\n",
- wlc->pub->unit, __func__);
+ brcms_warn(wlc->hw->d11core,
+ "wl%d: %s: IEEE80211_TX_RC_MCS != is_mcs_rate(rspec)\n",
+ wlc->pub->unit, __func__);
}
if (is_mcs_rate(rspec[k])) {
@@ -6690,11 +6677,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
(struct ofdm_phy_hdr *) rts_plcp) :
rts_plcp[0]) << 8;
} else {
- memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
- memset((char *)&txh->rts_frame, 0,
- sizeof(struct ieee80211_rts));
- memset((char *)txh->RTSPLCPFallback, 0,
- sizeof(txh->RTSPLCPFallback));
+ memset(txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);
+ memset(&txh->rts_frame, 0, sizeof(struct ieee80211_rts));
+ memset(txh->RTSPLCPFallback, 0, sizeof(txh->RTSPLCPFallback));
txh->RTSDurFallback = 0;
}
@@ -6849,21 +6834,19 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
wlc->fragthresh[queue] =
(u16) newfragthresh;
} else {
- brcms_err(wlc->hw->d11core,
- "wl%d: %s txop invalid "
- "for rate %d\n",
- wlc->pub->unit, fifo_names[queue],
- rspec2rate(rspec[0]));
+ brcms_warn(wlc->hw->d11core,
+ "wl%d: %s txop invalid for rate %d\n",
+ wlc->pub->unit, fifo_names[queue],
+ rspec2rate(rspec[0]));
}
if (dur > wlc->edcf_txop[ac])
- brcms_err(wlc->hw->d11core,
- "wl%d: %s: %s txop "
- "exceeded phylen %d/%d dur %d/%d\n",
- wlc->pub->unit, __func__,
- fifo_names[queue],
- phylen, wlc->fragthresh[queue],
- dur, wlc->edcf_txop[ac]);
+ brcms_warn(wlc->hw->d11core,
+ "wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n",
+ wlc->pub->unit, __func__,
+ fifo_names[queue],
+ phylen, wlc->fragthresh[queue],
+ dur, wlc->edcf_txop[ac]);
}
}
@@ -7338,7 +7321,7 @@ brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
*len = hdr_len + body_len;
/* format PHY and MAC headers */
- memset((char *)buf, 0, hdr_len);
+ memset(buf, 0, hdr_len);
plcp = (struct cck_phy_hdr *) buf;
@@ -7409,9 +7392,13 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
struct brcms_bss_cfg *cfg,
bool suspend)
{
- u16 prb_resp[BCN_TMPL_LEN / 2];
+ u16 *prb_resp;
int len = BCN_TMPL_LEN;
+ prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC);
+ if (!prb_resp)
+ return;
+
/*
* write the probe response to hardware, or save in
* the config structure
@@ -7445,6 +7432,8 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
if (suspend)
brcms_c_enable_mac(wlc);
+
+ kfree(prb_resp);
}
void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
@@ -7518,25 +7507,16 @@ int brcms_c_get_curband(struct brcms_c_info *wlc)
return wlc->band->bandunit;
}
-void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
+bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc)
{
- int timeout = 20;
int i;
/* Kick DMA to send any pending AMPDU */
for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++)
if (wlc->hw->di[i])
- dma_txflush(wlc->hw->di[i]);
-
- /* wait for queue and DMA fifos to run dry */
- while (brcms_txpktpendtot(wlc) > 0) {
- brcms_msleep(wlc->wl, 1);
-
- if (--timeout == 0)
- break;
- }
+ dma_kick_tx(wlc->hw->di[i]);
- WARN_ON_ONCE(timeout == 0);
+ return !brcms_txpktpendtot(wlc);
}
void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
@@ -7633,7 +7613,7 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
uint n = 0;
uint bound_limit = bound ? RXBND : -1;
- bool morepending;
+ bool morepending = false;
skb_queue_head_init(&recv_frames);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
index 4fb2834f4e64..b0f14b7b8616 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
@@ -314,8 +314,6 @@ extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state);
extern void brcms_c_scan_start(struct brcms_c_info *wlc);
extern void brcms_c_scan_stop(struct brcms_c_info *wlc);
extern int brcms_c_get_curband(struct brcms_c_info *wlc);
-extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc,
- bool drop);
extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel);
extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl);
extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
@@ -332,5 +330,6 @@ extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
+extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc);
#endif /* _BRCM_PUB_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/scb.h b/drivers/net/wireless/brcm80211/brcmsmac/scb.h
index 51c79c7239b7..3a3d73699f83 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/scb.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/scb.h
@@ -36,7 +36,6 @@
/* structure to store per-tid state for the ampdu initiator */
struct scb_ampdu_tid_ini {
- u8 tx_in_transit; /* number of pending mpdus in transit in driver */
u8 tid; /* initiator tid for easy lookup */
/* tx retry count; indexed by seq modulo */
u8 txretry[AMPDU_TX_BA_MAX_WSIZE];
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index c6ea995750db..dd9a18f8dbca 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -376,7 +376,7 @@ int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL);
if (entry == NULL)
- return -1;
+ return -ENOMEM;
memcpy(entry->addr, mac, ETH_ALEN);
diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig
index 2715b101aded..91c0cb3c368e 100644
--- a/drivers/net/wireless/ipw2x00/Kconfig
+++ b/drivers/net/wireless/ipw2x00/Kconfig
@@ -137,7 +137,7 @@ config IPW2200_PROMISCUOUS
config IPW2200_QOS
bool "Enable QoS support"
- depends on IPW2200 && EXPERIMENTAL
+ depends on IPW2200
config IPW2200_DEBUG
bool "Enable full debugging output in IPW2200 module."
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index d92b21a8e597..cb066f62879d 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -2181,9 +2181,10 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
mod_delayed_work(system_wq, &priv->rf_kill, round_jiffies_relative(HZ));
}
-static void send_scan_event(void *data)
+static void ipw2100_scan_event(struct work_struct *work)
{
- struct ipw2100_priv *priv = data;
+ struct ipw2100_priv *priv = container_of(work, struct ipw2100_priv,
+ scan_event.work);
union iwreq_data wrqu;
wrqu.data.length = 0;
@@ -2191,18 +2192,6 @@ static void send_scan_event(void *data)
wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
}
-static void ipw2100_scan_event_later(struct work_struct *work)
-{
- send_scan_event(container_of(work, struct ipw2100_priv,
- scan_event_later.work));
-}
-
-static void ipw2100_scan_event_now(struct work_struct *work)
-{
- send_scan_event(container_of(work, struct ipw2100_priv,
- scan_event_now));
-}
-
static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
{
IPW_DEBUG_SCAN("scan complete\n");
@@ -2212,13 +2201,11 @@ static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
/* Only userspace-requested scan completion events go out immediately */
if (!priv->user_requested_scan) {
- if (!delayed_work_pending(&priv->scan_event_later))
- schedule_delayed_work(&priv->scan_event_later,
- round_jiffies_relative(msecs_to_jiffies(4000)));
+ schedule_delayed_work(&priv->scan_event,
+ round_jiffies_relative(msecs_to_jiffies(4000)));
} else {
priv->user_requested_scan = 0;
- cancel_delayed_work(&priv->scan_event_later);
- schedule_work(&priv->scan_event_now);
+ mod_delayed_work(system_wq, &priv->scan_event, 0);
}
}
@@ -4459,8 +4446,7 @@ static void ipw2100_kill_works(struct ipw2100_priv *priv)
cancel_delayed_work_sync(&priv->wx_event_work);
cancel_delayed_work_sync(&priv->hang_check);
cancel_delayed_work_sync(&priv->rf_kill);
- cancel_work_sync(&priv->scan_event_now);
- cancel_delayed_work_sync(&priv->scan_event_later);
+ cancel_delayed_work_sync(&priv->scan_event);
}
static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
@@ -4478,13 +4464,10 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
return err;
}
- priv->tx_buffers =
- kmalloc(TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
- GFP_ATOMIC);
+ priv->tx_buffers = kmalloc_array(TX_PENDED_QUEUE_LENGTH,
+ sizeof(struct ipw2100_tx_packet),
+ GFP_ATOMIC);
if (!priv->tx_buffers) {
- printk(KERN_ERR DRV_NAME
- ": %s: alloc failed form tx buffers.\n",
- priv->net_dev->name);
bd_queue_free(priv, &priv->tx_queue);
return -ENOMEM;
}
@@ -6195,8 +6178,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
- INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now);
- INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later);
+ INIT_DELAYED_WORK(&priv->scan_event, ipw2100_scan_event);
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
ipw2100_irq_tasklet, (unsigned long)priv);
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h
index 5fe17cbab1f3..c6d78790cb0d 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.h
+++ b/drivers/net/wireless/ipw2x00/ipw2100.h
@@ -577,8 +577,7 @@ struct ipw2100_priv {
struct delayed_work wx_event_work;
struct delayed_work hang_check;
struct delayed_work rf_kill;
- struct work_struct scan_event_now;
- struct delayed_work scan_event_later;
+ struct delayed_work scan_event;
int user_requested_scan;
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 844f201b7b70..d96257b79a84 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -4480,18 +4480,11 @@ static void handle_scan_event(struct ipw_priv *priv)
{
/* Only userspace-requested scan completion events go out immediately */
if (!priv->user_requested_scan) {
- if (!delayed_work_pending(&priv->scan_event))
- schedule_delayed_work(&priv->scan_event,
- round_jiffies_relative(msecs_to_jiffies(4000)));
+ schedule_delayed_work(&priv->scan_event,
+ round_jiffies_relative(msecs_to_jiffies(4000)));
} else {
- union iwreq_data wrqu;
-
priv->user_requested_scan = 0;
- cancel_delayed_work(&priv->scan_event);
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
+ mod_delayed_work(system_wq, &priv->scan_event, 0);
}
}
@@ -11327,7 +11320,6 @@ static int ipw_up(struct ipw_priv *priv)
if (!(priv->config & CFG_CUSTOM_MAC))
eeprom_parse_mac(priv, priv->mac_addr);
memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
- memcpy(priv->net_dev->perm_addr, priv->mac_addr, ETH_ALEN);
ipw_set_geo(priv);
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index 3726cd6fcd75..3630a41df50d 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -572,26 +572,11 @@ il3945_tx_skb(struct il_priv *il,
il3945_hw_build_tx_cmd_rate(il, out_cmd, info, hdr, sta_id);
/* Total # bytes to be transmitted */
- len = (u16) skb->len;
- tx_cmd->len = cpu_to_le16(len);
+ tx_cmd->len = cpu_to_le16((u16) skb->len);
- il_update_stats(il, true, fc, len);
tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
- if (!ieee80211_has_morefrags(hdr->frame_control)) {
- txq->need_update = 1;
- } else {
- wait_write_ptr = 1;
- txq->need_update = 0;
- }
-
- D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence));
- D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
- il_print_hex_dump(il, IL_DL_TX, tx_cmd, sizeof(*tx_cmd));
- il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd->hdr,
- ieee80211_hdrlen(fc));
-
/*
* Use the first empty entry in this queue's command buffer array
* to contain the Tx command and MAC header concatenated together
@@ -610,14 +595,8 @@ il3945_tx_skb(struct il_priv *il,
* within command buffer array. */
txcmd_phys =
pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE);
- /* we do not map meta data ... so we can safely access address to
- * provide to unmap command*/
- dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
- dma_unmap_len_set(out_meta, len, len);
-
- /* Add buffer containing Tx command and MAC(!) header to TFD's
- * first entry */
- il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
+ if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys)))
+ goto drop_unlock;
/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
@@ -626,10 +605,34 @@ il3945_tx_skb(struct il_priv *il,
phys_addr =
pci_map_single(il->pci_dev, skb->data + hdr_len, len,
PCI_DMA_TODEVICE);
+ if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr)))
+ goto drop_unlock;
+ }
+
+ /* Add buffer containing Tx command and MAC(!) header to TFD's
+ * first entry */
+ il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
+ dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ dma_unmap_len_set(out_meta, len, len);
+ if (len)
il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0,
U32_PAD(len));
+
+ if (!ieee80211_has_morefrags(hdr->frame_control)) {
+ txq->need_update = 1;
+ } else {
+ wait_write_ptr = 1;
+ txq->need_update = 0;
}
+ il_update_stats(il, true, fc, skb->len);
+
+ D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence));
+ D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
+ il_print_hex_dump(il, IL_DL_TX, tx_cmd, sizeof(*tx_cmd));
+ il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd->hdr,
+ ieee80211_hdrlen(fc));
+
/* Tell device the write idx *just past* this latest filled TFD */
q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd);
il_txq_update_write_ptr(il, txq);
@@ -1001,12 +1004,12 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority)
struct list_head *element;
struct il_rx_buf *rxb;
struct page *page;
+ dma_addr_t page_dma;
unsigned long flags;
gfp_t gfp_mask = priority;
while (1) {
spin_lock_irqsave(&rxq->lock, flags);
-
if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags);
return;
@@ -1035,26 +1038,34 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority)
break;
}
+ /* Get physical address of RB/SKB */
+ page_dma =
+ pci_map_page(il->pci_dev, page, 0,
+ PAGE_SIZE << il->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+
+ if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) {
+ __free_pages(page, il->hw_params.rx_page_order);
+ break;
+ }
+
spin_lock_irqsave(&rxq->lock, flags);
+
if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags);
+ pci_unmap_page(il->pci_dev, page_dma,
+ PAGE_SIZE << il->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
__free_pages(page, il->hw_params.rx_page_order);
return;
}
+
element = rxq->rx_used.next;
rxb = list_entry(element, struct il_rx_buf, list);
list_del(element);
- spin_unlock_irqrestore(&rxq->lock, flags);
rxb->page = page;
- /* Get physical address of RB/SKB */
- rxb->page_dma =
- pci_map_page(il->pci_dev, page, 0,
- PAGE_SIZE << il->hw_params.rx_page_order,
- PCI_DMA_FROMDEVICE);
-
- spin_lock_irqsave(&rxq->lock, flags);
-
+ rxb->page_dma = page_dma;
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
il->alloc_rxb_page++;
@@ -1284,8 +1295,15 @@ il3945_rx_handle(struct il_priv *il)
pci_map_page(il->pci_dev, rxb->page, 0,
PAGE_SIZE << il->hw_params.
rx_page_order, PCI_DMA_FROMDEVICE);
- list_add_tail(&rxb->list, &rxq->rx_free);
- rxq->free_count++;
+ if (unlikely(pci_dma_mapping_error(il->pci_dev,
+ rxb->page_dma))) {
+ __il_free_pages(il, rxb->page);
+ rxb->page = NULL;
+ list_add_tail(&rxb->list, &rxq->rx_used);
+ } else {
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ }
} else
list_add_tail(&rxb->list, &rxq->rx_used);
@@ -3474,6 +3492,7 @@ struct ieee80211_ops il3945_mac_ops = {
.sta_add = il3945_mac_sta_add,
.sta_remove = il_mac_sta_remove,
.tx_last_beacon = il_mac_tx_last_beacon,
+ .flush = il_mac_flush,
};
static int
@@ -3548,7 +3567,8 @@ il3945_setup_mac(struct il_priv *il)
hw->vif_data_size = sizeof(struct il_vif_priv);
/* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT;
+ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
@@ -3557,6 +3577,8 @@ il3945_setup_mac(struct il_priv *il)
WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
+ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
/* we create the 802.11 header and a zero-length SSID element */
hw->wiphy->max_scan_ie_len = IL3945_MAX_PROBE_REQUEST - 24 - 2;
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index c3fbf6717564..7941eb3a0166 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -319,6 +319,7 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority)
struct list_head *element;
struct il_rx_buf *rxb;
struct page *page;
+ dma_addr_t page_dma;
unsigned long flags;
gfp_t gfp_mask = priority;
@@ -356,33 +357,35 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority)
return;
}
+ /* Get physical address of the RB */
+ page_dma =
+ pci_map_page(il->pci_dev, page, 0,
+ PAGE_SIZE << il->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(il->pci_dev, page_dma))) {
+ __free_pages(page, il->hw_params.rx_page_order);
+ break;
+ }
+
spin_lock_irqsave(&rxq->lock, flags);
if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags);
+ pci_unmap_page(il->pci_dev, page_dma,
+ PAGE_SIZE << il->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
__free_pages(page, il->hw_params.rx_page_order);
return;
}
+
element = rxq->rx_used.next;
rxb = list_entry(element, struct il_rx_buf, list);
list_del(element);
- spin_unlock_irqrestore(&rxq->lock, flags);
-
BUG_ON(rxb->page);
- rxb->page = page;
- /* Get physical address of the RB */
- rxb->page_dma =
- pci_map_page(il->pci_dev, page, 0,
- PAGE_SIZE << il->hw_params.rx_page_order,
- PCI_DMA_FROMDEVICE);
- /* dma address must be no more than 36 bits */
- BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
- /* and also 256 byte aligned! */
- BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
-
- spin_lock_irqsave(&rxq->lock, flags);
+ rxb->page = page;
+ rxb->page_dma = page_dma;
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
il->alloc_rxb_page++;
@@ -725,6 +728,16 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
if (rate_n_flags & RATE_MCS_SGI_MSK)
rx_status.flag |= RX_FLAG_SHORT_GI;
+ if (phy_res->phy_flags & RX_RES_PHY_FLAGS_AGG_MSK) {
+ /* We know which subframes of an A-MPDU belong
+ * together since we get a single PHY response
+ * from the firmware for all of them.
+ */
+
+ rx_status.flag |= RX_FLAG_AMPDU_DETAILS;
+ rx_status.ampdu_reference = il->_4965.ampdu_ref;
+ }
+
il4965_pass_packet_to_mac80211(il, header, len, ampdu_status, rxb,
&rx_status);
}
@@ -736,6 +749,7 @@ il4965_hdl_rx_phy(struct il_priv *il, struct il_rx_buf *rxb)
{
struct il_rx_pkt *pkt = rxb_addr(rxb);
il->_4965.last_phy_res_valid = true;
+ il->_4965.ampdu_ref++;
memcpy(&il->_4965.last_phy_res, pkt->u.raw,
sizeof(struct il_rx_phy_res));
}
@@ -1779,8 +1793,7 @@ il4965_tx_skb(struct il_priv *il,
memcpy(tx_cmd->hdr, hdr, hdr_len);
/* Total # bytes to be transmitted */
- len = (u16) skb->len;
- tx_cmd->len = cpu_to_le16(len);
+ tx_cmd->len = cpu_to_le16((u16) skb->len);
if (info->control.hw_key)
il4965_tx_cmd_build_hwcrypto(il, info, tx_cmd, skb, sta_id);
@@ -1790,7 +1803,6 @@ il4965_tx_skb(struct il_priv *il,
il4965_tx_cmd_build_rate(il, tx_cmd, info, sta, fc);
- il_update_stats(il, true, fc, len);
/*
* Use the first empty entry in this queue's command buffer array
* to contain the Tx command and MAC header concatenated together
@@ -1812,18 +1824,8 @@ il4965_tx_skb(struct il_priv *il,
txcmd_phys =
pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen,
PCI_DMA_BIDIRECTIONAL);
- 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 */
- il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
-
- if (!ieee80211_has_morefrags(hdr->frame_control)) {
- txq->need_update = 1;
- } else {
- wait_write_ptr = 1;
- txq->need_update = 0;
- }
+ if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys)))
+ goto drop_unlock;
/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
@@ -1832,8 +1834,24 @@ il4965_tx_skb(struct il_priv *il,
phys_addr =
pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen,
PCI_DMA_TODEVICE);
+ if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr)))
+ goto drop_unlock;
+ }
+
+ /* Add buffer containing Tx command and MAC(!) header to TFD's
+ * first entry */
+ il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
+ dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ dma_unmap_len_set(out_meta, len, firstlen);
+ if (secondlen)
il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen,
0, 0);
+
+ if (!ieee80211_has_morefrags(hdr->frame_control)) {
+ txq->need_update = 1;
+ } else {
+ wait_write_ptr = 1;
+ txq->need_update = 0;
}
scratch_phys =
@@ -1846,6 +1864,8 @@ il4965_tx_skb(struct il_priv *il,
tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
tx_cmd->dram_msb_ptr = il_get_dma_hi_addr(scratch_phys);
+ il_update_stats(il, true, fc, skb->len);
+
D_TX("sequence nr = 0X%x\n", le16_to_cpu(out_cmd->hdr.sequence));
D_TX("tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
il_print_hex_dump(il, IL_DL_TX, (u8 *) tx_cmd, sizeof(*tx_cmd));
@@ -4281,8 +4301,16 @@ il4965_rx_handle(struct il_priv *il)
pci_map_page(il->pci_dev, rxb->page, 0,
PAGE_SIZE << il->hw_params.
rx_page_order, PCI_DMA_FROMDEVICE);
- list_add_tail(&rxb->list, &rxq->rx_free);
- rxq->free_count++;
+
+ if (unlikely(pci_dma_mapping_error(il->pci_dev,
+ rxb->page_dma))) {
+ __il_free_pages(il, rxb->page);
+ rxb->page = NULL;
+ list_add_tail(&rxb->list, &rxq->rx_used);
+ } else {
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ }
} else
list_add_tail(&rxb->list, &rxq->rx_used);
@@ -5711,9 +5739,9 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
/* Tell mac80211 our characteristics */
hw->flags =
IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS;
-
+ IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
if (il->cfg->sku & IL_SKU_N)
hw->flags |=
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
@@ -5968,7 +5996,9 @@ il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
D_HT("start Tx\n");
ret = il4965_tx_agg_start(il, vif, sta, tid, ssn);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
D_HT("stop Tx\n");
ret = il4965_tx_agg_stop(il, vif, sta, tid);
if (test_bit(S_EXIT_PENDING, &il->status))
@@ -6306,6 +6336,7 @@ const struct ieee80211_ops il4965_mac_ops = {
.sta_remove = il_mac_sta_remove,
.channel_switch = il4965_mac_channel_switch,
.tx_last_beacon = il_mac_tx_last_beacon,
+ .flush = il_mac_flush,
};
static int
@@ -6553,6 +6584,7 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
il4965_prepare_card_hw(il);
if (!il->hw_ready) {
IL_WARN("Failed, HW not ready\n");
+ err = -EIO;
goto out_iounmap;
}
@@ -6569,9 +6601,6 @@ il4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto out_free_eeprom;
- if (err)
- goto out_free_eeprom;
-
/* extract MAC Address */
il4965_eeprom_get_mac(il, il->addresses[0].addr);
D_INFO("MAC address: %pM\n", il->addresses[0].addr);
diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c
index f3b8e91aa3dc..e8324b5e5bfe 100644
--- a/drivers/net/wireless/iwlegacy/4965-rs.c
+++ b/drivers/net/wireless/iwlegacy/4965-rs.c
@@ -1183,8 +1183,7 @@ il4965_rs_switch_to_mimo2(struct il_priv *il, struct il_lq_sta *lq_sta,
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1;
- if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) ==
- WLAN_HT_CAP_SM_PS_STATIC)
+ if (sta->smps_mode == IEEE80211_SMPS_STATIC)
return -1;
/* Need both Tx chains/antennas to support MIMO */
diff --git a/drivers/net/wireless/iwlegacy/4965.c b/drivers/net/wireless/iwlegacy/4965.c
index 5db11714e047..91eb2d07fdb8 100644
--- a/drivers/net/wireless/iwlegacy/4965.c
+++ b/drivers/net/wireless/iwlegacy/4965.c
@@ -1748,7 +1748,6 @@ static void
il4965_post_associate(struct il_priv *il)
{
struct ieee80211_vif *vif = il->vif;
- struct ieee80211_conf *conf = NULL;
int ret = 0;
if (!vif || !il->is_open)
@@ -1759,8 +1758,6 @@ il4965_post_associate(struct il_priv *il)
il_scan_cancel_timeout(il, 200);
- conf = &il->hw->conf;
-
il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
il_commit_rxon(il);
diff --git a/drivers/net/wireless/iwlegacy/commands.h b/drivers/net/wireless/iwlegacy/commands.h
index 25dd7d28d022..3b6c99400892 100644
--- a/drivers/net/wireless/iwlegacy/commands.h
+++ b/drivers/net/wireless/iwlegacy/commands.h
@@ -1134,8 +1134,9 @@ struct il_wep_cmd {
#define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1)
#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2)
#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK 0xf0
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK 0x70
#define RX_RES_PHY_FLAGS_ANTENNA_POS 4
+#define RX_RES_PHY_FLAGS_AGG_MSK cpu_to_le16(1 << 7)
#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c
index 90b8970eadf0..e006ea831320 100644
--- a/drivers/net/wireless/iwlegacy/common.c
+++ b/drivers/net/wireless/iwlegacy/common.c
@@ -1830,32 +1830,30 @@ il_set_ht_add_station(struct il_priv *il, u8 idx, struct ieee80211_sta *sta)
{
struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
__le32 sta_flags;
- u8 mimo_ps_mode;
if (!sta || !sta_ht_inf->ht_supported)
goto done;
- mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
D_ASSOC("spatial multiplexing power save mode: %s\n",
- (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? "static" :
- (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? "dynamic" :
+ (sta->smps_mode == IEEE80211_SMPS_STATIC) ? "static" :
+ (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ? "dynamic" :
"disabled");
sta_flags = il->stations[idx].sta.station_flags;
sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
- switch (mimo_ps_mode) {
- case WLAN_HT_CAP_SM_PS_STATIC:
+ switch (sta->smps_mode) {
+ case IEEE80211_SMPS_STATIC:
sta_flags |= STA_FLG_MIMO_DIS_MSK;
break;
- case WLAN_HT_CAP_SM_PS_DYNAMIC:
+ case IEEE80211_SMPS_DYNAMIC:
sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
break;
- case WLAN_HT_CAP_SM_PS_DISABLED:
+ case IEEE80211_SMPS_OFF:
break;
default:
- IL_WARN("Invalid MIMO PS mode %d\n", mimo_ps_mode);
+ IL_WARN("Invalid MIMO PS mode %d\n", sta->smps_mode);
break;
}
@@ -3162,18 +3160,23 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
idx, il->cmd_queue);
}
#endif
- txq->need_update = 1;
-
- if (il->ops->txq_update_byte_cnt_tbl)
- /* Set up entry in queue's byte count circular buffer */
- il->ops->txq_update_byte_cnt_tbl(il, txq, 0);
phys_addr =
pci_map_single(il->pci_dev, &out_cmd->hdr, fix_size,
PCI_DMA_BIDIRECTIONAL);
+ if (unlikely(pci_dma_mapping_error(il->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);
+ txq->need_update = 1;
+
+ if (il->ops->txq_update_byte_cnt_tbl)
+ /* Set up entry in queue's byte count circular buffer */
+ il->ops->txq_update_byte_cnt_tbl(il, txq, 0);
+
il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, fix_size, 1,
U32_PAD(cmd->len));
@@ -3181,6 +3184,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
q->write_ptr = il_queue_inc_wrap(q->write_ptr, q->n_bd);
il_txq_update_write_ptr(il, txq);
+out:
spin_unlock_irqrestore(&il->hcmd_lock, flags);
return idx;
}
@@ -4700,6 +4704,42 @@ out:
}
EXPORT_SYMBOL(il_mac_change_interface);
+void
+il_mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+ struct il_priv *il = hw->priv;
+ unsigned long timeout = jiffies + msecs_to_jiffies(500);
+ int i;
+
+ mutex_lock(&il->mutex);
+ D_MAC80211("enter\n");
+
+ if (il->txq == NULL)
+ goto out;
+
+ for (i = 0; i < il->hw_params.max_txq_num; i++) {
+ struct il_queue *q;
+
+ if (i == il->cmd_queue)
+ continue;
+
+ q = &il->txq[i].q;
+ if (q->read_ptr == q->write_ptr)
+ continue;
+
+ if (time_after(jiffies, timeout)) {
+ IL_ERR("Failed to flush queue %d\n", q->id);
+ break;
+ }
+
+ msleep(20);
+ }
+out:
+ D_MAC80211("leave\n");
+ mutex_unlock(&il->mutex);
+}
+EXPORT_SYMBOL(il_mac_flush);
+
/*
* On every watchdog tick we check (latest) time stamp. If it does not
* change during timeout period and queue is not empty we reset firmware.
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h
index a9a569f432fb..96f2025d936e 100644
--- a/drivers/net/wireless/iwlegacy/common.h
+++ b/drivers/net/wireless/iwlegacy/common.h
@@ -1356,6 +1356,7 @@ struct il_priv {
struct {
struct il_rx_phy_res last_phy_res;
bool last_phy_res_valid;
+ u32 ampdu_ref;
struct completion firmware_loading_complete;
@@ -1723,6 +1724,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum nl80211_iftype newtype, bool newp2p);
+void il_mac_flush(struct ieee80211_hw *hw, bool drop);
int il_alloc_txq_mem(struct il_priv *il);
void il_free_txq_mem(struct il_priv *il);
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 5cf43236421e..ba319cba3f1e 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -43,8 +43,20 @@ config IWLWIFI
module will be called iwlwifi.
config IWLDVM
- tristate "Intel Wireless WiFi"
+ tristate "Intel Wireless WiFi DVM Firmware support"
depends on IWLWIFI
+ help
+ This is the driver supporting the DVM firmware which is
+ currently the only firmware available for existing devices.
+
+config IWLMVM
+ tristate "Intel Wireless WiFi MVM Firmware support"
+ depends on IWLWIFI
+ help
+ This is the driver supporting the MVM firmware which is
+ currently only available for 7000 series devices.
+
+ Say yes if you have such a device.
menu "Debugging Options"
depends on IWLWIFI
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 170ec330d2a9..6c7800044a04 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -5,8 +5,10 @@ iwlwifi-objs += iwl-drv.o
iwlwifi-objs += iwl-debug.o
iwlwifi-objs += iwl-notif-wait.o
iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o
+iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o
iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
iwlwifi-objs += pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o
+iwlwifi-objs += pcie/7000.o
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-test.o
@@ -15,5 +17,6 @@ ccflags-y += -D__CHECK_ENDIAN__ -I$(src)
obj-$(CONFIG_IWLDVM) += dvm/
+obj-$(CONFIG_IWLMVM) += mvm/
CFLAGS_iwl-devtrace.o := -I$(src)
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h
index 33b3ad2e546b..41ec27cb6efe 100644
--- a/drivers/net/wireless/iwlwifi/dvm/agn.h
+++ b/drivers/net/wireless/iwlwifi/dvm/agn.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -338,7 +338,7 @@ int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct iwl_rxon_context *ctx,
- struct ieee80211_sta_ht_cap *ht_cap);
+ struct ieee80211_sta *sta);
static inline int iwl_sta_id(struct ieee80211_sta *sta)
{
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.c b/drivers/net/wireless/iwlwifi/dvm/calib.c
index de54713b680c..6468de8634b0 100644
--- a/drivers/net/wireless/iwlwifi/dvm/calib.c
+++ b/drivers/net/wireless/iwlwifi/dvm/calib.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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/dvm/calib.h b/drivers/net/wireless/iwlwifi/dvm/calib.h
index 2349f393cc42..65e920cab2b7 100644
--- a/drivers/net/wireless/iwlwifi/dvm/calib.h
+++ b/drivers/net/wireless/iwlwifi/dvm/calib.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h
index 71ab76b2b39d..84e2c0fcfef6 100644
--- a/drivers/net/wireless/iwlwifi/dvm/commands.h
+++ b/drivers/net/wireless/iwlwifi/dvm/commands.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -1403,6 +1403,7 @@ enum {
#define AGG_TX_STATUS_MSK 0x00000fff /* bits 0:11 */
#define AGG_TX_TRY_MSK 0x0000f000 /* bits 12:15 */
+#define AGG_TX_TRY_POS 12
#define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
@@ -3695,7 +3696,7 @@ struct iwl_bt_uart_msg {
u8 frame5;
u8 frame6;
u8 frame7;
-} __attribute__((packed));
+} __packed;
struct iwl_bt_coex_profile_notif {
struct iwl_bt_uart_msg last_bt_uart_msg;
@@ -3703,7 +3704,7 @@ struct iwl_bt_coex_profile_notif {
u8 bt_traffic_load; /* 0 .. 3? */
u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
u8 reserved;
-} __attribute__((packed));
+} __packed;
#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS 0
#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK 0x1
@@ -3752,7 +3753,7 @@ enum bt_coex_prio_table_priorities {
struct iwl_bt_coex_prio_table_cmd {
u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
-} __attribute__((packed));
+} __packed;
#define IWL_BT_COEX_ENV_CLOSE 0
#define IWL_BT_COEX_ENV_OPEN 1
@@ -3764,7 +3765,7 @@ struct iwl_bt_coex_prot_env_cmd {
u8 action; /* 0 = closed, 1 = open */
u8 type; /* 0 .. 15 */
u8 reserved[2];
-} __attribute__((packed));
+} __packed;
/*
* REPLY_D3_CONFIG
@@ -3897,6 +3898,24 @@ struct iwlagn_wowlan_kek_kck_material_cmd {
__le64 replay_ctr;
} __packed;
+#define RF_KILL_INDICATOR_FOR_WOWLAN 0x87
+
+/*
+ * REPLY_WOWLAN_GET_STATUS = 0xe5
+ */
+struct iwlagn_wowlan_status {
+ __le64 replay_ctr;
+ __le32 rekey_status;
+ __le32 wakeup_reason;
+ u8 pattern_number;
+ u8 reserved1;
+ __le16 qos_seq_ctr[8];
+ __le16 non_qos_seq_ctr;
+ __le16 reserved2;
+ union iwlagn_all_tsc_rsc tsc_rsc;
+ __le16 reserved3;
+} __packed;
+
/*
* REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
*/
diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
index 5b9533eef54d..20806cae11b7 100644
--- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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
@@ -157,7 +157,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
sram = priv->dbgfs_sram_offset & ~0x3;
/* read the first u32 from sram */
- val = iwl_read_targ_mem(priv->trans, sram);
+ val = iwl_trans_read_mem32(priv->trans, sram);
for (; len; len--) {
/* put the address at the start of every line */
@@ -176,7 +176,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
if (++offset == 4) {
sram += 4;
offset = 0;
- val = iwl_read_targ_mem(priv->trans, sram);
+ val = iwl_trans_read_mem32(priv->trans, sram);
}
/* put in extra spaces and split lines for human readability */
diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h
index 2653a891cc7e..71ea77576d22 100644
--- a/drivers/net/wireless/iwlwifi/dvm/dev.h
+++ b/drivers/net/wireless/iwlwifi/dvm/dev.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c
index 8c72be3f37c1..15cca2ef9294 100644
--- a/drivers/net/wireless/iwlwifi/dvm/devices.c
+++ b/drivers/net/wireless/iwlwifi/dvm/devices.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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/dvm/led.c b/drivers/net/wireless/iwlwifi/dvm/led.c
index bf479f709091..33c7e15d24f5 100644
--- a/drivers/net/wireless/iwlwifi/dvm/led.c
+++ b/drivers/net/wireless/iwlwifi/dvm/led.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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
@@ -69,7 +69,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = {
/* Set led register off */
void iwlagn_led_enable(struct iwl_priv *priv)
{
- iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+ iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON);
}
/*
diff --git a/drivers/net/wireless/iwlwifi/dvm/led.h b/drivers/net/wireless/iwlwifi/dvm/led.h
index b02a853103d3..8749dcfe695f 100644
--- a/drivers/net/wireless/iwlwifi/dvm/led.h
+++ b/drivers/net/wireless/iwlwifi/dvm/led.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c
index 6ff46605ad4f..86ea5f4c3939 100644
--- a/drivers/net/wireless/iwlwifi/dvm/lib.c
+++ b/drivers/net/wireless/iwlwifi/dvm/lib.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 3163e0f38c25..323e4a33fcac 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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.
@@ -145,14 +145,13 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_NEED_DTIM_PERIOD |
+ IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_QUEUE_CONTROL |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_WANT_MONITOR_VIF |
- IEEE80211_HW_SCAN_WHILE_IDLE;
+ IEEE80211_HW_WANT_MONITOR_VIF;
hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
@@ -206,7 +205,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
#ifdef CONFIG_PM_SLEEP
if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
- priv->trans->ops->wowlan_suspend &&
+ priv->trans->ops->d3_suspend &&
+ priv->trans->ops->d3_resume &&
device_can_wakeup(priv->trans->dev)) {
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
WIPHY_WOWLAN_DISCONNECT |
@@ -426,7 +426,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
if (ret)
goto error;
- iwl_trans_wowlan_suspend(priv->trans);
+ iwl_trans_d3_suspend(priv->trans);
goto out;
@@ -441,54 +441,154 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
return ret;
}
+struct iwl_resume_data {
+ struct iwl_priv *priv;
+ struct iwlagn_wowlan_status *cmd;
+ bool valid;
+};
+
+static bool iwl_resume_status_fn(struct iwl_notif_wait_data *notif_wait,
+ struct iwl_rx_packet *pkt, void *data)
+{
+ struct iwl_resume_data *resume_data = data;
+ struct iwl_priv *priv = resume_data->priv;
+ u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+
+ if (len - 4 != sizeof(*resume_data->cmd)) {
+ IWL_ERR(priv, "rx wrong size data\n");
+ return true;
+ }
+ memcpy(resume_data->cmd, pkt->data, sizeof(*resume_data->cmd));
+ resume_data->valid = true;
+
+ return true;
+}
+
static int iwlagn_mac_resume(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
struct ieee80211_vif *vif;
- unsigned long flags;
- u32 base, status = 0xffffffff;
- int ret = -EIO;
+ u32 base;
+ int ret;
+ enum iwl_d3_status d3_status;
+ struct error_table_start {
+ /* cf. struct iwl_error_event_table */
+ u32 valid;
+ u32 error_id;
+ } err_info;
+ struct iwl_notification_wait status_wait;
+ static const u8 status_cmd[] = {
+ REPLY_WOWLAN_GET_STATUS,
+ };
+ struct iwlagn_wowlan_status status_data = {};
+ struct iwl_resume_data resume_data = {
+ .priv = priv,
+ .cmd = &status_data,
+ .valid = false,
+ };
+ struct cfg80211_wowlan_wakeup wakeup = {
+ .pattern_idx = -1,
+ };
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ const struct fw_img *img;
+#endif
IWL_DEBUG_MAC80211(priv, "enter\n");
mutex_lock(&priv->mutex);
- iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
- CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+ /* we'll clear ctx->vif during iwlagn_prepare_restart() */
+ vif = ctx->vif;
+
+ ret = iwl_trans_d3_resume(priv->trans, &d3_status);
+ if (ret)
+ goto out_unlock;
+
+ if (d3_status != IWL_D3_STATUS_ALIVE) {
+ IWL_INFO(priv, "Device was reset during suspend\n");
+ goto out_unlock;
+ }
base = priv->device_pointers.error_event_table;
- if (iwlagn_hw_valid_rtc_data_addr(base)) {
- spin_lock_irqsave(&priv->trans->reg_lock, flags);
- ret = iwl_grab_nic_access_silent(priv->trans);
- if (likely(ret == 0)) {
- iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
- status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
- iwl_release_nic_access(priv->trans);
+ if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+ IWL_WARN(priv, "Invalid error table during resume!\n");
+ goto out_unlock;
+ }
+
+ iwl_trans_read_mem_bytes(priv->trans, base,
+ &err_info, sizeof(err_info));
+
+ if (err_info.valid) {
+ IWL_INFO(priv, "error table is valid (%d, 0x%x)\n",
+ err_info.valid, err_info.error_id);
+ if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
+ wakeup.rfkill_release = true;
+ ieee80211_report_wowlan_wakeup(vif, &wakeup,
+ GFP_KERNEL);
}
- spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
+ goto out_unlock;
+ }
#ifdef CONFIG_IWLWIFI_DEBUGFS
- if (ret == 0) {
- const struct fw_img *img;
-
- img = &(priv->fw->img[IWL_UCODE_WOWLAN]);
- if (!priv->wowlan_sram) {
- priv->wowlan_sram =
- kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
- GFP_KERNEL);
- }
+ img = &priv->fw->img[IWL_UCODE_WOWLAN];
+ if (!priv->wowlan_sram)
+ priv->wowlan_sram =
+ kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
+ GFP_KERNEL);
+
+ if (priv->wowlan_sram)
+ iwl_trans_read_mem(priv->trans, 0x800000,
+ priv->wowlan_sram,
+ img->sec[IWL_UCODE_SECTION_DATA].len / 4);
+#endif
+
+ /*
+ * This is very strange. The GET_STATUS command is sent but the device
+ * doesn't reply properly, it seems it doesn't close the RBD so one is
+ * always left open ... As a result, we need to send another command
+ * and have to reset the driver afterwards. As we need to switch to
+ * runtime firmware again that'll happen.
+ */
- if (priv->wowlan_sram)
- _iwl_read_targ_mem_dwords(
- priv->trans, 0x800000,
- priv->wowlan_sram,
- img->sec[IWL_UCODE_SECTION_DATA].len / 4);
+ iwl_init_notification_wait(&priv->notif_wait, &status_wait, status_cmd,
+ ARRAY_SIZE(status_cmd), iwl_resume_status_fn,
+ &resume_data);
+
+ iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_GET_STATUS, CMD_ASYNC, 0, NULL);
+ iwl_dvm_send_cmd_pdu(priv, REPLY_ECHO, CMD_ASYNC, 0, NULL);
+ /* an RBD is left open in the firmware now! */
+
+ ret = iwl_wait_notification(&priv->notif_wait, &status_wait, HZ/5);
+ if (ret)
+ goto out_unlock;
+
+ if (resume_data.valid && priv->contexts[IWL_RXON_CTX_BSS].vif) {
+ u32 reasons = le32_to_cpu(status_data.wakeup_reason);
+ struct cfg80211_wowlan_wakeup *wakeup_report;
+
+ IWL_INFO(priv, "WoWLAN wakeup reason(s): 0x%.8x\n", reasons);
+
+ if (reasons) {
+ if (reasons & IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET)
+ wakeup.magic_pkt = true;
+ if (reasons & IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH)
+ wakeup.pattern_idx = status_data.pattern_number;
+ if (reasons & (IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
+ IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE))
+ wakeup.disconnect = true;
+ if (reasons & IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL)
+ wakeup.gtk_rekey_failure = true;
+ if (reasons & IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ)
+ wakeup.eap_identity_req = true;
+ if (reasons & IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE)
+ wakeup.four_way_handshake = true;
+ wakeup_report = &wakeup;
+ } else {
+ wakeup_report = NULL;
}
-#endif
- }
- /* we'll clear ctx->vif during iwlagn_prepare_restart() */
- vif = ctx->vif;
+ ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL);
+ }
priv->wowlan = false;
@@ -498,6 +598,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
iwl_connection_init_rx_config(priv, ctx);
iwlagn_set_rxon_chain(priv, ctx);
+ out_unlock:
mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -520,9 +621,6 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw,
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
- IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
- ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
-
if (iwlagn_tx_skb(priv, control->sta, skb))
ieee80211_free_txskb(hw, skb);
}
@@ -679,7 +777,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
IWL_DEBUG_HT(priv, "start Tx\n");
ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
IWL_DEBUG_HT(priv, "stop Tx\n");
ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
if ((ret == 0) && (priv->agg_tids_count > 0)) {
@@ -1154,6 +1254,7 @@ static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
}
static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index faa05932efae..b9e3517652d6 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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.
@@ -353,11 +353,8 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
/* Make sure device is powered up for SRAM reads */
- spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
- if (unlikely(!iwl_grab_nic_access(priv->trans))) {
- spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
+ if (!iwl_trans_grab_nic_access(priv->trans, false, &reg_flags))
return;
- }
/* Set starting address; reads will auto-increment */
iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr);
@@ -388,8 +385,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
}
}
/* Allow device to power down */
- iwl_release_nic_access(priv->trans);
- spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
+ iwl_trans_release_nic_access(priv->trans, &reg_flags);
}
static void iwl_continuous_event_trace(struct iwl_priv *priv)
@@ -408,7 +404,8 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)
base = priv->device_pointers.log_event_table;
if (iwlagn_hw_valid_rtc_data_addr(base)) {
- iwl_read_targ_mem_bytes(priv->trans, base, &read, sizeof(read));
+ iwl_trans_read_mem_bytes(priv->trans, base,
+ &read, sizeof(read));
capacity = read.capacity;
mode = read.mode;
num_wraps = read.wrap_counter;
@@ -1627,7 +1624,7 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
}
/*TODO: Update dbgfs with ISR error stats obtained below */
- iwl_read_targ_mem_bytes(trans, base, &table, sizeof(table));
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
IWL_ERR(trans, "Start IWL Error Log Dump:\n");
@@ -1716,9 +1713,8 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
/* Make sure device is powered up for SRAM reads */
- spin_lock_irqsave(&trans->reg_lock, reg_flags);
- if (unlikely(!iwl_grab_nic_access(trans)))
- goto out_unlock;
+ if (!iwl_trans_grab_nic_access(trans, false, &reg_flags))
+ return pos;
/* Set starting address; reads will auto-increment */
iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr);
@@ -1756,9 +1752,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
}
/* Allow device to power down */
- iwl_release_nic_access(trans);
-out_unlock:
- spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
+ iwl_trans_release_nic_access(trans, &reg_flags);
return pos;
}
@@ -1835,10 +1829,10 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
}
/* event log header */
- capacity = iwl_read_targ_mem(trans, base);
- mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32)));
- num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32)));
- next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32)));
+ capacity = iwl_trans_read_mem32(trans, base);
+ mode = iwl_trans_read_mem32(trans, base + (1 * sizeof(u32)));
+ num_wraps = iwl_trans_read_mem32(trans, base + (2 * sizeof(u32)));
+ next_entry = iwl_trans_read_mem32(trans, base + (3 * sizeof(u32)));
if (capacity > logsize) {
IWL_ERR(priv, "Log capacity %d is bogus, limit to %d "
@@ -1990,13 +1984,13 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode)
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
/* SKU Control */
- iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
- CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP,
- (CSR_HW_REV_STEP(priv->trans->hw_rev) <<
- CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) |
- (CSR_HW_REV_DASH(priv->trans->hw_rev) <<
- CSR_HW_IF_CONFIG_REG_POS_MAC_DASH));
+ iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
+ CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP,
+ (CSR_HW_REV_STEP(priv->trans->hw_rev) <<
+ CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) |
+ (CSR_HW_REV_DASH(priv->trans->hw_rev) <<
+ CSR_HW_IF_CONFIG_REG_POS_MAC_DASH));
/* write radio config values to register */
if (priv->nvm_data->radio_cfg_type <= EEPROM_RF_CONFIG_TYPE_MAX) {
@@ -2008,10 +2002,11 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode)
priv->nvm_data->radio_cfg_dash <<
CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
- iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
- CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
- CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, reg_val);
+ iwl_trans_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
+ CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
+ CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH,
+ reg_val);
IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n",
priv->nvm_data->radio_cfg_type,
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c
index 518cf3715809..bd69018d07a9 100644
--- a/drivers/net/wireless/iwlwifi/dvm/power.c
+++ b/drivers/net/wireless/iwlwifi/dvm/power.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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/dvm/power.h b/drivers/net/wireless/iwlwifi/dvm/power.h
index a2cee7f04848..7b03e1342d47 100644
--- a/drivers/net/wireless/iwlwifi/dvm/power.h
+++ b/drivers/net/wireless/iwlwifi/dvm/power.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c
index f3dd0da60d8a..abe304267261 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rs.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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
@@ -411,8 +411,9 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
* BT traffic, as they would just be disrupted by BT.
*/
if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) {
- IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n",
- priv->bt_traffic_load);
+ IWL_DEBUG_COEX(priv,
+ "BT traffic (%d), no aggregation allowed\n",
+ priv->bt_traffic_load);
return ret;
}
@@ -1288,8 +1289,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1;
- if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
- == WLAN_HT_CAP_SM_PS_STATIC)
+ if (sta->smps_mode == IEEE80211_SMPS_STATIC)
return -1;
/* Need both Tx chains/antennas to support MIMO */
@@ -1304,7 +1304,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_mimo2_rate;
- if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+ if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
tbl->is_ht40 = 1;
else
tbl->is_ht40 = 0;
@@ -1344,8 +1344,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
return -1;
- if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
- == WLAN_HT_CAP_SM_PS_STATIC)
+ if (sta->smps_mode == IEEE80211_SMPS_STATIC)
return -1;
/* Need both Tx chains/antennas to support MIMO */
@@ -1360,7 +1359,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
rate_mask = lq_sta->active_mimo3_rate;
- if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+ if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
tbl->is_ht40 = 1;
else
tbl->is_ht40 = 0;
@@ -1409,7 +1408,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_siso_rate;
- if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+ if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
tbl->is_ht40 = 1;
else
tbl->is_ht40 = 0;
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h
index ad3aea8f626a..5d83cab22d62 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/dvm/rs.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c
index cac4f37cc427..a4eed2055fdb 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rx.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portionhelp of the ieee80211 subsystem header files.
@@ -790,7 +790,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
- ieee80211_rx(priv->hw, skb);
+ ieee80211_rx_ni(priv->hw, skb);
}
static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c
index 9a891e6e60e8..23be948cf162 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rxon.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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
@@ -1545,10 +1545,9 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
bss_conf->bssid);
}
- if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC &&
- priv->beacon_ctx) {
+ if (changes & BSS_CHANGED_BEACON && priv->beacon_ctx == ctx) {
if (iwlagn_update_beacon(priv, vif))
- IWL_ERR(priv, "Error sending IBSS beacon\n");
+ IWL_ERR(priv, "Error updating beacon\n");
}
mutex_unlock(&priv->mutex);
diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c
index 610ed2204e1f..3a4aa5239c45 100644
--- a/drivers/net/wireless/iwlwifi/dvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/dvm/scan.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c
index bdba9543c351..94ef33838bc6 100644
--- a/drivers/net/wireless/iwlwifi/dvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/dvm/sta.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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.
@@ -77,7 +77,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,
IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
sta_id);
- spin_lock(&priv->sta_lock);
+ spin_lock_bh(&priv->sta_lock);
switch (add_sta_resp->status) {
case ADD_STA_SUCCESS_MSK:
@@ -119,7 +119,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,
priv->stations[sta_id].sta.mode ==
STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
addsta->sta.addr);
- spin_unlock(&priv->sta_lock);
+ spin_unlock_bh(&priv->sta_lock);
return ret;
}
@@ -173,7 +173,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct iwl_rxon_context *ctx,
- struct ieee80211_sta_ht_cap *ht_cap)
+ struct ieee80211_sta *sta)
{
if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
return false;
@@ -183,20 +183,11 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
return false;
#endif
- /*
- * Remainder of this function checks ht_cap, but if it's
- * NULL then we can do HT40 (special case for RXON)
- */
- if (!ht_cap)
+ /* special case for RXON */
+ if (!sta)
return true;
- if (!ht_cap->ht_supported)
- return false;
-
- if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
- return false;
-
- return true;
+ return sta->bandwidth >= IEEE80211_STA_RX_BW_40;
}
static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
@@ -205,7 +196,6 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
__le32 *flags, __le32 *mask)
{
struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
- u8 mimo_ps_mode;
*mask = STA_FLG_RTS_MIMO_PROT_MSK |
STA_FLG_MIMO_DIS_MSK |
@@ -217,26 +207,24 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
if (!sta || !sta_ht_inf->ht_supported)
return;
- mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
-
IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n",
sta->addr,
- (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
+ (sta->smps_mode == IEEE80211_SMPS_STATIC) ?
"static" :
- (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
+ (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) ?
"dynamic" : "disabled");
- switch (mimo_ps_mode) {
- case WLAN_HT_CAP_SM_PS_STATIC:
+ switch (sta->smps_mode) {
+ case IEEE80211_SMPS_STATIC:
*flags |= STA_FLG_MIMO_DIS_MSK;
break;
- case WLAN_HT_CAP_SM_PS_DYNAMIC:
+ case IEEE80211_SMPS_DYNAMIC:
*flags |= STA_FLG_RTS_MIMO_PROT_MSK;
break;
- case WLAN_HT_CAP_SM_PS_DISABLED:
+ case IEEE80211_SMPS_OFF:
break;
default:
- IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode);
+ IWL_WARN(priv, "Invalid MIMO PS mode %d\n", sta->smps_mode);
break;
}
@@ -246,7 +234,7 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
*flags |= cpu_to_le32(
(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
- if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+ if (iwl_is_ht40_tx_allowed(priv, ctx, sta))
*flags |= STA_FLG_HT40_EN_MSK;
}
diff --git a/drivers/net/wireless/iwlwifi/dvm/testmode.c b/drivers/net/wireless/iwlwifi/dvm/testmode.c
index 57b918ce3b5f..dc6f965a123a 100644
--- a/drivers/net/wireless/iwlwifi/dvm/testmode.c
+++ b/drivers/net/wireless/iwlwifi/dvm/testmode.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 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) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 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/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c
index eb864433e59d..03f9bc01c0cc 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tt.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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.
@@ -185,10 +185,8 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
priv->thermal_throttle.ct_kill_toggle = true;
}
iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
- spin_lock_irqsave(&priv->trans->reg_lock, flags);
- if (likely(iwl_grab_nic_access(priv->trans)))
- iwl_release_nic_access(priv->trans);
- spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
+ if (iwl_trans_grab_nic_access(priv->trans, false, &flags))
+ iwl_trans_release_nic_access(priv->trans, &flags);
/* Reschedule the ct_kill timer to occur in
* CT_KILL_EXIT_DURATION seconds to ensure we get a
@@ -473,8 +471,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
set_bit(STATUS_CT_KILL, &priv->status);
iwl_perform_ct_kill_task(priv, true);
} else {
- iwl_prepare_ct_kill_task(priv);
tt->state = old_state;
+ iwl_prepare_ct_kill_task(priv);
}
} else if (old_state == IWL_TI_CT_KILL &&
tt->state != IWL_TI_CT_KILL) {
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.h b/drivers/net/wireless/iwlwifi/dvm/tt.h
index 44c7c8f30a2d..9356c4b908ca 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tt.h
+++ b/drivers/net/wireless/iwlwifi/dvm/tt.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index 31534f7c0548..6aec2df3bb27 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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
@@ -231,13 +231,11 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
if (info->flags & IEEE80211_TX_CTL_AMPDU)
tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
- IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
break;
case WLAN_CIPHER_SUITE_TKIP:
tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
- IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
break;
case WLAN_CIPHER_SUITE_WEP104:
@@ -355,8 +353,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
}
}
- IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
-
if (sta)
sta_priv = (void *)sta->drv_priv;
@@ -472,6 +468,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
WARN_ON_ONCE(is_agg &&
priv->queue_to_mac80211[txq_id] != info->hw_queue);
+ IWL_DEBUG_TX(priv, "TX to [%d|%d] Q:%d - seq: 0x%x\n", sta_id, tid,
+ txq_id, seq_number);
+
if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id))
goto drop_unlock_sta;
@@ -541,9 +540,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
spin_lock_bh(&priv->sta_lock);
tid_data = &priv->tid_data[sta_id][tid];
- txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
+ txq_id = tid_data->agg.txq_id;
- switch (priv->tid_data[sta_id][tid].agg.state) {
+ switch (tid_data->agg.state) {
case IWL_EMPTYING_HW_QUEUE_ADDBA:
/*
* This can happen if the peer stops aggregation
@@ -563,9 +562,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
case IWL_AGG_ON:
break;
default:
- IWL_WARN(priv, "Stopping AGG while state not ON "
- "or starting for %d on %d (%d)\n", sta_id, tid,
- priv->tid_data[sta_id][tid].agg.state);
+ IWL_WARN(priv,
+ "Stopping AGG while state not ON or starting for %d on %d (%d)\n",
+ sta_id, tid, tid_data->agg.state);
spin_unlock_bh(&priv->sta_lock);
return 0;
}
@@ -578,12 +577,11 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
"stopping AGG on STA/TID %d/%d but hwq %d not used\n",
sta_id, tid, txq_id);
} else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
- IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
- "next_recl = %d\n",
+ IWL_DEBUG_TX_QUEUES(priv,
+ "Can't proceed: ssn %d, next_recl = %d\n",
tid_data->agg.ssn,
tid_data->next_reclaimed);
- priv->tid_data[sta_id][tid].agg.state =
- IWL_EMPTYING_HW_QUEUE_DELBA;
+ tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_DELBA;
spin_unlock_bh(&priv->sta_lock);
return 0;
}
@@ -591,8 +589,8 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
tid_data->agg.ssn);
turn_off:
- agg_state = priv->tid_data[sta_id][tid].agg.state;
- priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
+ agg_state = tid_data->agg.state;
+ tid_data->agg.state = IWL_AGG_OFF;
spin_unlock_bh(&priv->sta_lock);
@@ -910,6 +908,12 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
}
}
+static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
+{
+ return le32_to_cpup((__le32 *)&tx_resp->status +
+ tx_resp->frame_count) & MAX_SN;
+}
+
static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
struct iwlagn_tx_resp *tx_resp)
{
@@ -944,9 +948,15 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
if (tx_resp->frame_count == 1)
return;
+ IWL_DEBUG_TX_REPLY(priv, "TXQ %d initial_rate 0x%x ssn %d frm_cnt %d\n",
+ agg->txq_id,
+ le32_to_cpu(tx_resp->rate_n_flags),
+ iwlagn_get_scd_ssn(tx_resp), tx_resp->frame_count);
+
/* Construct bit-map of pending frames within Tx window */
for (i = 0; i < tx_resp->frame_count; i++) {
u16 fstatus = le16_to_cpu(frame_status[i].status);
+ u8 retry_cnt = (fstatus & AGG_TX_TRY_MSK) >> AGG_TX_TRY_POS;
if (status & AGG_TX_STATUS_MSK)
iwlagn_count_agg_tx_err_status(priv, fstatus);
@@ -955,11 +965,13 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
AGG_TX_STATE_ABORT_MSK))
continue;
- IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
- "try-count (0x%08x)\n",
- iwl_get_agg_tx_fail_reason(fstatus),
- fstatus & AGG_TX_STATUS_MSK,
- fstatus & AGG_TX_TRY_MSK);
+ if (status & AGG_TX_STATUS_MSK || retry_cnt > 1)
+ IWL_DEBUG_TX_REPLY(priv,
+ "%d: status %s (0x%04x), try-count (0x%01x)\n",
+ i,
+ iwl_get_agg_tx_fail_reason(fstatus),
+ fstatus & AGG_TX_STATUS_MSK,
+ retry_cnt);
}
}
@@ -990,12 +1002,6 @@ const char *iwl_get_agg_tx_fail_reason(u16 status)
}
#endif /* CONFIG_IWLWIFI_DEBUG */
-static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
-{
- return le32_to_cpup((__le32 *)&tx_resp->status +
- tx_resp->frame_count) & MAX_SN;
-}
-
static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
{
status &= TX_STATUS_MSK;
@@ -1125,10 +1131,16 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
IWLAGN_TX_RES_RA_POS;
- spin_lock(&priv->sta_lock);
+ spin_lock_bh(&priv->sta_lock);
- if (is_agg)
+ if (is_agg) {
+ WARN_ON_ONCE(sta_id >= IWLAGN_STATION_COUNT ||
+ tid >= IWL_MAX_TID_COUNT);
+ if (txq_id != priv->tid_data[sta_id][tid].agg.txq_id)
+ IWL_ERR(priv, "txq_id mismatch: %d %d\n", txq_id,
+ priv->tid_data[sta_id][tid].agg.txq_id);
iwl_rx_reply_tx_agg(priv, tx_resp);
+ }
__skb_queue_head_init(&skbs);
@@ -1153,6 +1165,13 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
next_reclaimed = ssn;
}
+ if (tid != IWL_TID_NON_QOS) {
+ priv->tid_data[sta_id][tid].next_reclaimed =
+ next_reclaimed;
+ IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
+ next_reclaimed);
+ }
+
iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs);
iwlagn_check_ratid_empty(priv, sta_id, tid);
@@ -1203,16 +1222,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
if (!is_agg)
iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1);
- /*
- * W/A for FW bug - the seq_ctl isn't updated when the
- * queues are flushed. Fetch it from the packet itself
- */
- if (!is_agg && status == TX_STATUS_FAIL_FIFO_FLUSHED) {
- next_reclaimed = le16_to_cpu(hdr->seq_ctrl);
- next_reclaimed =
- SEQ_TO_SN(next_reclaimed + 0x10);
- }
-
is_offchannel_skb =
(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN);
freed++;
@@ -1225,22 +1234,34 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
next_reclaimed);
}
- WARN_ON(!is_agg && freed != 1);
+ if (!is_agg && freed != 1)
+ IWL_ERR(priv, "Q: %d, freed %d\n", txq_id, freed);
/*
* An offchannel frame can be send only on the AUX queue, where
* there is no aggregation (and reordering) so it only is single
* skb is expected to be processed.
*/
- WARN_ON(is_offchannel_skb && freed != 1);
+ if (is_offchannel_skb && freed != 1)
+ IWL_ERR(priv, "OFFCHANNEL SKB freed %d\n", freed);
+
+ IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x)\n", txq_id,
+ iwl_get_tx_fail_reason(status), status);
+
+ IWL_DEBUG_TX_REPLY(priv,
+ "\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d seq_ctl=0x%x\n",
+ le32_to_cpu(tx_resp->rate_n_flags),
+ tx_resp->failure_frame,
+ SEQ_TO_INDEX(sequence), ssn,
+ le16_to_cpu(tx_resp->seq_ctl));
}
iwl_check_abort_status(priv, tx_resp->frame_count, status);
- spin_unlock(&priv->sta_lock);
+ spin_unlock_bh(&priv->sta_lock);
while (!skb_queue_empty(&skbs)) {
skb = __skb_dequeue(&skbs);
- ieee80211_tx_status(priv->hw, skb);
+ ieee80211_tx_status_ni(priv->hw, skb);
}
if (is_offchannel_skb)
@@ -1287,12 +1308,12 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
tid = ba_resp->tid;
agg = &priv->tid_data[sta_id][tid].agg;
- spin_lock(&priv->sta_lock);
+ spin_lock_bh(&priv->sta_lock);
if (unlikely(!agg->wait_for_ba)) {
if (unlikely(ba_resp->bitmap))
IWL_ERR(priv, "Received BA when not expected\n");
- spin_unlock(&priv->sta_lock);
+ spin_unlock_bh(&priv->sta_lock);
return 0;
}
@@ -1306,7 +1327,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
IWL_DEBUG_TX_QUEUES(priv,
"Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n",
scd_flow, sta_id, tid, agg->txq_id);
- spin_unlock(&priv->sta_lock);
+ spin_unlock_bh(&priv->sta_lock);
return 0;
}
@@ -1375,11 +1396,11 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
}
}
- spin_unlock(&priv->sta_lock);
+ spin_unlock_bh(&priv->sta_lock);
while (!skb_queue_empty(&reclaimed_skbs)) {
skb = __skb_dequeue(&reclaimed_skbs);
- ieee80211_tx_status(priv->hw, skb);
+ ieee80211_tx_status_ni(priv->hw, skb);
}
return 0;
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c
index c6467e5554f5..736fe9bb140e 100644
--- a/drivers/net/wireless/iwlwifi/dvm/ucode.c
+++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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
@@ -286,89 +286,6 @@ static int iwl_alive_notify(struct iwl_priv *priv)
return iwl_send_calib_results(priv);
}
-
-/**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
- * using sample data 100 bytes apart. If these sample points are good,
- * it's a pretty good bet that everything between them is good, too.
- */
-static int iwl_verify_sec_sparse(struct iwl_priv *priv,
- const struct fw_desc *fw_desc)
-{
- __le32 *image = (__le32 *)fw_desc->data;
- u32 len = fw_desc->len;
- u32 val;
- u32 i;
-
- IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
- for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
- /* read data comes through single port, auto-incr addr */
- /* NOTE: Use the debugless read so we don't flood kernel log
- * if IWL_DL_IO is set */
- iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
- i + fw_desc->offset);
- val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image))
- return -EIO;
- }
-
- return 0;
-}
-
-static void iwl_print_mismatch_sec(struct iwl_priv *priv,
- const struct fw_desc *fw_desc)
-{
- __le32 *image = (__le32 *)fw_desc->data;
- u32 len = fw_desc->len;
- u32 val;
- u32 offs;
- int errors = 0;
-
- IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
- iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
- fw_desc->offset);
-
- for (offs = 0;
- offs < len && errors < 20;
- offs += sizeof(u32), image++) {
- /* read data comes through single port, auto-incr addr */
- val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image)) {
- 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++;
- }
- }
-}
-
-/**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
- * and verify its contents
- */
-static int iwl_verify_ucode(struct iwl_priv *priv,
- enum iwl_ucode_type ucode_type)
-{
- const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
-
- if (!img) {
- IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
- return -EINVAL;
- }
-
- if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) {
- IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
- return 0;
- }
-
- IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
-
- iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]);
- return -EIO;
-}
-
struct iwl_alive_data {
bool valid;
u8 subtype;
@@ -426,7 +343,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
alive_cmd, ARRAY_SIZE(alive_cmd),
iwl_alive_fn, &alive_data);
- ret = iwl_trans_start_fw(priv->trans, fw);
+ ret = iwl_trans_start_fw(priv->trans, fw, false);
if (ret) {
priv->cur_ucode = old_type;
iwl_remove_notification(&priv->notif_wait, &alive_wait);
@@ -450,18 +367,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
return -EIO;
}
- /*
- * This step takes a long time (60-80ms!!) and
- * WoWLAN image should be loaded quickly, so
- * skip it for WoWLAN.
- */
if (ucode_type != IWL_UCODE_WOWLAN) {
- ret = iwl_verify_ucode(priv, ucode_type);
- if (ret) {
- priv->cur_ucode = old_type;
- return ret;
- }
-
/* delay a bit to give rfkill time to run */
msleep(5);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
index 7960a52f6ad4..e9975c54c276 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 864219d2136a..743b48343358 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -83,6 +83,7 @@ enum iwl_device_family {
IWL_DEVICE_FAMILY_6030,
IWL_DEVICE_FAMILY_6050,
IWL_DEVICE_FAMILY_6150,
+ IWL_DEVICE_FAMILY_7000,
};
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 34a5287dfc2f..df3463a38704 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -381,8 +381,8 @@
/* LED */
#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF)
-#define CSR_LED_REG_TRUN_ON (0x78)
-#define CSR_LED_REG_TRUN_OFF (0x38)
+#define CSR_LED_REG_TURN_ON (0x60)
+#define CSR_LED_REG_TURN_OFF (0x20)
/* ANA_PLL */
#define CSR50_ANA_PLL_CFG_VAL (0x00880300)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 42b20b0e83bc..8cf5db7fb5c9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
@@ -116,6 +116,7 @@ do { \
#define IWL_DL_HCMD 0x00000004
#define IWL_DL_STATE 0x00000008
/* 0x000000F0 - 0x00000010 */
+#define IWL_DL_TE 0x00000020
#define IWL_DL_EEPROM 0x00000040
#define IWL_DL_RADIO 0x00000080
/* 0x00000F00 - 0x00000100 */
@@ -156,6 +157,7 @@ do { \
#define IWL_DEBUG_LED(p, f, a...) IWL_DEBUG(p, IWL_DL_LED, f, ## a)
#define IWL_DEBUG_WEP(p, f, a...) IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
#define IWL_DEBUG_HC(p, f, a...) IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
+#define IWL_DEBUG_TE(p, f, a...) IWL_DEBUG(p, IWL_DL_TE, f, ## a)
#define IWL_DEBUG_EEPROM(d, f, a...) IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a)
#define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
#define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
index 70191ddbd8f6..8f61c717f619 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2009 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2013 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 dc7e26b2f383..9a0f45ec9e01 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2009 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2013 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-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index d3549f493a17..6f228bb2b844 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -139,8 +139,10 @@ struct iwl_drv {
#endif
};
-#define DVM_OP_MODE 0
-#define MVM_OP_MODE 1
+enum {
+ DVM_OP_MODE = 0,
+ MVM_OP_MODE = 1,
+};
/* Protects the table contents, i.e. the ops pointer & drv list */
static struct mutex iwlwifi_opmode_table_mtx;
@@ -149,8 +151,8 @@ static struct iwlwifi_opmode_table {
const struct iwl_op_mode_ops *ops; /* pointer to op_mode ops */
struct list_head drv; /* list of devices using this op_mode */
} iwlwifi_opmode_table[] = { /* ops set when driver is initialized */
- { .name = "iwldvm", .ops = NULL },
- { .name = "iwlmvm", .ops = NULL },
+ [DVM_OP_MODE] = { .name = "iwldvm", .ops = NULL },
+ [MVM_OP_MODE] = { .name = "iwlmvm", .ops = NULL },
};
/*
@@ -268,7 +270,7 @@ struct fw_sec_parsing {
*/
struct iwl_tlv_calib_data {
__le32 ucode_type;
- __le64 calib;
+ struct iwl_tlv_calib_ctrl calib;
} __packed;
struct iwl_firmware_pieces {
@@ -358,7 +360,11 @@ static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data)
ucode_type);
return -EINVAL;
}
- drv->fw.default_calib[ucode_type] = le64_to_cpu(def_calib->calib);
+ drv->fw.default_calib[ucode_type].flow_trigger =
+ def_calib->calib.flow_trigger;
+ drv->fw.default_calib[ucode_type].event_trigger =
+ def_calib->calib.event_trigger;
+
return 0;
}
@@ -959,7 +965,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
release_firmware(ucode_raw);
mutex_lock(&iwlwifi_opmode_table_mtx);
- op = &iwlwifi_opmode_table[DVM_OP_MODE];
+ if (fw->mvm_fw)
+ op = &iwlwifi_opmode_table[MVM_OP_MODE];
+ else
+ op = &iwlwifi_opmode_table[DVM_OP_MODE];
/* add this device to the list of devices using this op_mode */
list_add_tail(&drv->list, &op->drv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h
index 285de5f68c05..594a5c71b272 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.h
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,7 @@
/* for all modules */
#define DRV_NAME "iwlwifi"
#define IWLWIFI_VERSION "in-tree:"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2012 Intel Corporation"
+#define DRV_COPYRIGHT "Copyright(c) 2003-2013 Intel Corporation"
#define DRV_AUTHOR "<ilw@linux.intel.com>"
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
index 471986690cf0..034f2ff4f43d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -703,9 +703,9 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
return n_channels;
}
-static int iwl_init_sband_channels(struct iwl_nvm_data *data,
- struct ieee80211_supported_band *sband,
- int n_channels, enum ieee80211_band band)
+int iwl_init_sband_channels(struct iwl_nvm_data *data,
+ struct ieee80211_supported_band *sband,
+ int n_channels, enum ieee80211_band band)
{
struct ieee80211_channel *chan = &data->channels[0];
int n = 0, idx = 0;
@@ -728,10 +728,10 @@ static int iwl_init_sband_channels(struct iwl_nvm_data *data,
#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
-static void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
- struct iwl_nvm_data *data,
- struct ieee80211_sta_ht_cap *ht_info,
- enum ieee80211_band band)
+void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
+ struct iwl_nvm_data *data,
+ struct ieee80211_sta_ht_cap *ht_info,
+ enum ieee80211_band band)
{
int max_bit_rate = 0;
u8 rx_chains;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
index 555f0eb61d48..683fe6a8c58f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -126,4 +126,13 @@ static inline void iwl_free_nvm_data(struct iwl_nvm_data *data)
int iwl_nvm_check_version(struct iwl_nvm_data *data,
struct iwl_trans *trans);
+int iwl_init_sband_channels(struct iwl_nvm_data *data,
+ struct ieee80211_supported_band *sband,
+ int n_channels, enum ieee80211_band band);
+
+void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
+ struct iwl_nvm_data *data,
+ struct ieee80211_sta_ht_cap *ht_info,
+ enum ieee80211_band band);
+
#endif /* __iwl_eeprom_parse_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
index 27c7da3c6ed1..ef4806f27cf8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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-eeprom-read.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
index 1337c9d36fee..b2588c5cbf93 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index ec48563d3c6a..f5592fb3b1ed 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -225,6 +225,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008)
#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
+#define FW_RSCSR_CHNL0_RXDCB_RDPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x00c)
+#define FH_RSCSR_CHNL0_RDPTR FW_RSCSR_CHNL0_RXDCB_RDPTR_REG
/**
* Rx Config/Status Registers (RCSR)
@@ -257,6 +259,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND)
#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0)
+#define FH_MEM_RCSR_CHNL0_RBDCB_WPTR (FH_MEM_RCSR_CHNL0 + 0x8)
+#define FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ (FH_MEM_RCSR_CHNL0 + 0x10)
#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */
#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK (0x00001000) /* bits 12 */
@@ -410,6 +414,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
* uCode/driver must write "1" in order to clear this flag
*/
#define FH_TSSR_TX_ERROR_REG (FH_TSSR_LOWER_BOUND + 0x018)
+#define FH_TSSR_TX_MSG_CONFIG_REG (FH_TSSR_LOWER_BOUND + 0x008)
#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16)
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index e71564053e7f..90873eca35f7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index d1a86b66bc51..b545178e46e3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -139,6 +139,19 @@ struct fw_img {
#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8)
#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF)
+/*
+ * Calibration control struct.
+ * Sent as part of the phy configuration command.
+ * @flow_trigger: bitmap for which calibrations to perform according to
+ * flow triggers.
+ * @event_trigger: bitmap for which calibrations to perform according to
+ * event triggers.
+ */
+struct iwl_tlv_calib_ctrl {
+ __le32 flow_trigger;
+ __le32 event_trigger;
+} __packed;
+
/**
* struct iwl_fw - variables associated with the firmware
*
@@ -153,11 +166,12 @@ struct fw_img {
* @inst_evtlog_ptr: event log offset for runtime ucode.
* @inst_evtlog_size: event log size for runtime ucode.
* @inst_errlog_ptr: error log offfset for runtime ucode.
+ * @mvm_fw: indicates this is MVM firmware
*/
struct iwl_fw {
u32 ucode_ver;
- char fw_version[ETHTOOL_BUSINFO_LEN];
+ char fw_version[ETHTOOL_FWVERS_LEN];
/* ucode images */
struct fw_img img[IWL_UCODE_TYPE_MAX];
@@ -168,7 +182,7 @@ struct iwl_fw {
u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
- u64 default_calib[IWL_UCODE_TYPE_MAX];
+ struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX];
u32 phy_config;
bool mvm_fw;
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index cdaff9572059..276410d82de4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
@@ -35,54 +35,6 @@
#define IWL_POLL_INTERVAL 10 /* microseconds */
-static inline void __iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
-{
- iwl_write32(trans, reg, iwl_read32(trans, reg) | mask);
-}
-
-static inline void __iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
-{
- iwl_write32(trans, reg, iwl_read32(trans, reg) & ~mask);
-}
-
-void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&trans->reg_lock, flags);
- __iwl_set_bit(trans, reg, mask);
- spin_unlock_irqrestore(&trans->reg_lock, flags);
-}
-EXPORT_SYMBOL_GPL(iwl_set_bit);
-
-void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&trans->reg_lock, flags);
- __iwl_clear_bit(trans, reg, mask);
- spin_unlock_irqrestore(&trans->reg_lock, flags);
-}
-EXPORT_SYMBOL_GPL(iwl_clear_bit);
-
-void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
-{
- unsigned long flags;
- u32 v;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- WARN_ON_ONCE(value & ~mask);
-#endif
-
- spin_lock_irqsave(&trans->reg_lock, flags);
- v = iwl_read32(trans, reg);
- v &= ~mask;
- v |= value;
- iwl_write32(trans, reg, v);
- spin_unlock_irqrestore(&trans->reg_lock, flags);
-}
-EXPORT_SYMBOL_GPL(iwl_set_bits_mask);
-
int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
u32 bits, u32 mask, int timeout)
{
@@ -99,87 +51,14 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
}
EXPORT_SYMBOL_GPL(iwl_poll_bit);
-int iwl_grab_nic_access_silent(struct iwl_trans *trans)
-{
- int ret;
-
- lockdep_assert_held(&trans->reg_lock);
-
- /* this bit wakes up the NIC */
- __iwl_set_bit(trans, 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(trans, 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(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
- return -EIO;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent);
-
-bool iwl_grab_nic_access(struct iwl_trans *trans)
-{
- int ret = iwl_grab_nic_access_silent(trans);
- if (unlikely(ret)) {
- u32 val = iwl_read32(trans, CSR_GP_CNTRL);
- WARN_ONCE(1, "Timeout waiting for hardware access "
- "(CSR_GP_CNTRL 0x%08x)\n", val);
- return false;
- }
-
- return true;
-}
-EXPORT_SYMBOL_GPL(iwl_grab_nic_access);
-
-void iwl_release_nic_access(struct iwl_trans *trans)
-{
- lockdep_assert_held(&trans->reg_lock);
- __iwl_clear_bit(trans, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- /*
- * Above we read the CSR_GP_CNTRL register, which will flush
- * any previous writes, but we need the write that clears the
- * MAC_ACCESS_REQ bit to be performed before any other writes
- * scheduled on different CPUs (after we drop reg_lock).
- */
- mmiowb();
-}
-EXPORT_SYMBOL_GPL(iwl_release_nic_access);
-
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
{
- u32 value;
+ u32 value = 0x5a5a5a5a;
unsigned long flags;
-
- spin_lock_irqsave(&trans->reg_lock, flags);
- iwl_grab_nic_access(trans);
- value = iwl_read32(trans, reg);
- iwl_release_nic_access(trans);
- spin_unlock_irqrestore(&trans->reg_lock, flags);
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+ value = iwl_read32(trans, reg);
+ iwl_trans_release_nic_access(trans, &flags);
+ }
return value;
}
@@ -189,12 +68,10 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
{
unsigned long flags;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (likely(iwl_grab_nic_access(trans))) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
iwl_write32(trans, reg, value);
- iwl_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_write_direct32);
@@ -230,13 +107,12 @@ static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
{
unsigned long flags;
- u32 val;
+ u32 val = 0x5a5a5a5a;
- spin_lock_irqsave(&trans->reg_lock, flags);
- iwl_grab_nic_access(trans);
- val = __iwl_read_prph(trans, ofs);
- iwl_release_nic_access(trans);
- spin_unlock_irqrestore(&trans->reg_lock, flags);
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+ val = __iwl_read_prph(trans, ofs);
+ iwl_trans_release_nic_access(trans, &flags);
+ }
return val;
}
EXPORT_SYMBOL_GPL(iwl_read_prph);
@@ -245,12 +121,10 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
{
unsigned long flags;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (likely(iwl_grab_nic_access(trans))) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
__iwl_write_prph(trans, ofs, val);
- iwl_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_write_prph);
@@ -258,13 +132,11 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
{
unsigned long flags;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (likely(iwl_grab_nic_access(trans))) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
__iwl_write_prph(trans, ofs,
__iwl_read_prph(trans, ofs) | mask);
- iwl_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
@@ -273,13 +145,11 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
{
unsigned long flags;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (likely(iwl_grab_nic_access(trans))) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
__iwl_write_prph(trans, ofs,
(__iwl_read_prph(trans, ofs) & mask) | bits);
- iwl_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
@@ -288,67 +158,10 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
unsigned long flags;
u32 val;
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (likely(iwl_grab_nic_access(trans))) {
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
val = __iwl_read_prph(trans, ofs);
__iwl_write_prph(trans, ofs, (val & ~mask));
- iwl_release_nic_access(trans);
+ iwl_trans_release_nic_access(trans, &flags);
}
- spin_unlock_irqrestore(&trans->reg_lock, flags);
}
EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
-
-void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
- void *buf, int dwords)
-{
- unsigned long flags;
- int offs;
- u32 *vals = buf;
-
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (likely(iwl_grab_nic_access(trans))) {
- iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
- for (offs = 0; offs < dwords; offs++)
- vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
- iwl_release_nic_access(trans);
- }
- spin_unlock_irqrestore(&trans->reg_lock, flags);
-}
-EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_dwords);
-
-u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
-{
- u32 value;
-
- _iwl_read_targ_mem_dwords(trans, addr, &value, 1);
-
- return value;
-}
-EXPORT_SYMBOL_GPL(iwl_read_targ_mem);
-
-int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
- const void *buf, int dwords)
-{
- unsigned long flags;
- int offs, result = 0;
- const u32 *vals = buf;
-
- spin_lock_irqsave(&trans->reg_lock, flags);
- if (likely(iwl_grab_nic_access(trans))) {
- iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
- for (offs = 0; offs < dwords; offs++)
- iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]);
- iwl_release_nic_access(trans);
- } else
- result = -EBUSY;
- spin_unlock_irqrestore(&trans->reg_lock, flags);
-
- return result;
-}
-EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_dwords);
-
-int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val)
-{
- return _iwl_write_targ_mem_dwords(trans, addr, &val, 1);
-}
-EXPORT_SYMBOL_GPL(iwl_write_targ_mem);
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 48dc753e3742..fd9f5b97fff3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
@@ -51,20 +51,21 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
return val;
}
-void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
-void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
+static inline void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
+{
+ iwl_trans_set_bits_mask(trans, reg, mask, mask);
+}
-void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value);
+static inline void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
+{
+ iwl_trans_set_bits_mask(trans, reg, mask, 0);
+}
int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
u32 bits, u32 mask, int timeout);
int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
int timeout);
-int iwl_grab_nic_access_silent(struct iwl_trans *trans);
-bool iwl_grab_nic_access(struct iwl_trans *trans);
-void iwl_release_nic_access(struct iwl_trans *trans);
-
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg);
void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
@@ -76,19 +77,4 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
u32 bits, u32 mask);
void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask);
-void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
- void *buf, int dwords);
-
-#define iwl_read_targ_mem_bytes(trans, addr, buf, bufsize) \
- do { \
- BUILD_BUG_ON((bufsize) % sizeof(u32)); \
- _iwl_read_targ_mem_dwords(trans, addr, buf, \
- (bufsize) / sizeof(u32));\
- } while (0)
-
-int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
- const void *buf, int dwords);
-
-u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr);
-int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val);
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h
index d9a86d6b2bd7..e5e3a79eae2f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
index c61f2070f15a..c3affbc62cdf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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-notif-wait.h b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
index 821523100cf1..c2ce764463a3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
new file mode 100644
index 000000000000..a70213bdb83c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -0,0 +1,346 @@
+/******************************************************************************
+ *
+ * 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) 2008 - 2013 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) 2005 - 2013 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/types.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "iwl-modparams.h"
+#include "iwl-nvm-parse.h"
+
+/* NVM offsets (in words) definitions */
+enum wkp_nvm_offsets {
+ /* NVM HW-Section offset (in words) definitions */
+ HW_ADDR = 0x15,
+
+/* NVM SW-Section offset (in words) definitions */
+ NVM_SW_SECTION = 0x1C0,
+ NVM_VERSION = 0,
+ RADIO_CFG = 1,
+ SKU = 2,
+ N_HW_ADDRS = 3,
+ NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION,
+
+/* NVM calibration section offset (in words) definitions */
+ NVM_CALIB_SECTION = 0x2B8,
+ XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
+};
+
+/* SKU Capabilities (actual values from NVM definition) */
+enum nvm_sku_bits {
+ NVM_SKU_CAP_BAND_24GHZ = BIT(0),
+ NVM_SKU_CAP_BAND_52GHZ = BIT(1),
+ NVM_SKU_CAP_11N_ENABLE = BIT(2),
+};
+
+/* radio config bits (actual values from NVM definition) */
+#define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */
+#define NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */
+#define NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */
+#define NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */
+#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
+#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
+
+/*
+ * These are the channel numbers in the order that they are stored in the NVM
+ */
+static const u8 iwl_nvm_channels[] = {
+ /* 2.4 GHz */
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ /* 5 GHz */
+ 36, 40, 44 , 48, 52, 56, 60, 64,
+ 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
+ 149, 153, 157, 161, 165
+};
+
+#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
+#define NUM_2GHZ_CHANNELS 14
+#define FIRST_2GHZ_HT_MINUS 5
+#define LAST_2GHZ_HT_PLUS 9
+#define LAST_5GHZ_HT 161
+
+
+/* rate data (static) */
+static struct ieee80211_rate iwl_cfg80211_rates[] = {
+ { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
+ { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+ { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+ { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3,
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+ { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, },
+ { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, },
+ { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, },
+ { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, },
+ { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, },
+ { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, },
+ { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, },
+ { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, },
+};
+#define RATES_24_OFFS 0
+#define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates)
+#define RATES_52_OFFS 4
+#define N_RATES_52 (N_RATES_24 - RATES_52_OFFS)
+
+/**
+ * enum iwl_nvm_channel_flags - channel flags in NVM
+ * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo
+ * @NVM_CHANNEL_IBSS: usable as an IBSS channel
+ * @NVM_CHANNEL_ACTIVE: active scanning allowed
+ * @NVM_CHANNEL_RADAR: radar detection required
+ * @NVM_CHANNEL_DFS: dynamic freq selection candidate
+ * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
+ * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
+ */
+enum iwl_nvm_channel_flags {
+ NVM_CHANNEL_VALID = BIT(0),
+ NVM_CHANNEL_IBSS = BIT(1),
+ NVM_CHANNEL_ACTIVE = BIT(3),
+ NVM_CHANNEL_RADAR = BIT(4),
+ NVM_CHANNEL_DFS = BIT(7),
+ NVM_CHANNEL_WIDE = BIT(8),
+ NVM_CHANNEL_40MHZ = BIT(9),
+};
+
+#define CHECK_AND_PRINT_I(x) \
+ ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "")
+
+static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
+ struct iwl_nvm_data *data,
+ const __le16 * const nvm_ch_flags)
+{
+ int ch_idx;
+ int n_channels = 0;
+ struct ieee80211_channel *channel;
+ u16 ch_flags;
+ bool is_5ghz;
+
+ for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) {
+ ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
+ if (!(ch_flags & NVM_CHANNEL_VALID)) {
+ IWL_DEBUG_EEPROM(dev,
+ "Ch. %d Flags %x [%sGHz] - No traffic\n",
+ iwl_nvm_channels[ch_idx],
+ ch_flags,
+ (ch_idx >= NUM_2GHZ_CHANNELS) ?
+ "5.2" : "2.4");
+ continue;
+ }
+
+ channel = &data->channels[n_channels];
+ n_channels++;
+
+ channel->hw_value = iwl_nvm_channels[ch_idx];
+ channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
+ IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ channel->center_freq =
+ ieee80211_channel_to_frequency(
+ channel->hw_value, channel->band);
+
+ /* TODO: Need to be dependent to the NVM */
+ channel->flags = IEEE80211_CHAN_NO_HT40;
+ if (ch_idx < NUM_2GHZ_CHANNELS &&
+ (ch_flags & NVM_CHANNEL_40MHZ)) {
+ if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS)
+ channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
+ if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS)
+ channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
+ } else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT &&
+ (ch_flags & NVM_CHANNEL_40MHZ)) {
+ if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
+ channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
+ else
+ channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
+ }
+
+ if (!(ch_flags & NVM_CHANNEL_IBSS))
+ channel->flags |= IEEE80211_CHAN_NO_IBSS;
+
+ if (!(ch_flags & NVM_CHANNEL_ACTIVE))
+ channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+ if (ch_flags & NVM_CHANNEL_RADAR)
+ channel->flags |= IEEE80211_CHAN_RADAR;
+
+ /* Initialize regulatory-based run-time data */
+
+ /* TODO: read the real value from the NVM */
+ channel->max_power = 0;
+ is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
+ IWL_DEBUG_EEPROM(dev,
+ "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
+ channel->hw_value,
+ is_5ghz ? "5.2" : "2.4",
+ CHECK_AND_PRINT_I(VALID),
+ CHECK_AND_PRINT_I(IBSS),
+ CHECK_AND_PRINT_I(ACTIVE),
+ CHECK_AND_PRINT_I(RADAR),
+ CHECK_AND_PRINT_I(WIDE),
+ CHECK_AND_PRINT_I(DFS),
+ ch_flags,
+ channel->max_power,
+ ((ch_flags & NVM_CHANNEL_IBSS) &&
+ !(ch_flags & NVM_CHANNEL_RADAR))
+ ? "" : "not ");
+ }
+
+ return n_channels;
+}
+
+static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
+ struct iwl_nvm_data *data, const __le16 *nvm_sw)
+{
+ int n_channels = iwl_init_channel_map(dev, cfg, data,
+ &nvm_sw[NVM_CHANNELS]);
+ int n_used = 0;
+ struct ieee80211_supported_band *sband;
+
+ sband = &data->bands[IEEE80211_BAND_2GHZ];
+ sband->band = IEEE80211_BAND_2GHZ;
+ sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
+ sband->n_bitrates = N_RATES_24;
+ n_used += iwl_init_sband_channels(data, sband, n_channels,
+ IEEE80211_BAND_2GHZ);
+ iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ);
+
+ sband = &data->bands[IEEE80211_BAND_5GHZ];
+ sband->band = IEEE80211_BAND_5GHZ;
+ sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
+ sband->n_bitrates = N_RATES_52;
+ n_used += iwl_init_sband_channels(data, sband, n_channels,
+ IEEE80211_BAND_5GHZ);
+ iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ);
+
+ if (n_channels != n_used)
+ IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
+ n_used, n_channels);
+}
+
+struct iwl_nvm_data *
+iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
+ const __le16 *nvm_hw, const __le16 *nvm_sw,
+ const __le16 *nvm_calib)
+{
+ struct iwl_nvm_data *data;
+ u8 hw_addr[ETH_ALEN];
+ u16 radio_cfg, sku;
+
+ data = kzalloc(sizeof(*data) +
+ sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
+ GFP_KERNEL);
+ if (!data)
+ return NULL;
+
+ data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION);
+
+ radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG);
+ data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
+ data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
+ data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
+ data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
+ data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
+ data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
+
+ sku = le16_to_cpup(nvm_sw + SKU);
+ data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
+ data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
+ data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
+ data->sku_cap_11n_enable = false;
+
+ /* check overrides (some devices have wrong NVM) */
+ if (cfg->valid_tx_ant)
+ data->valid_tx_ant = cfg->valid_tx_ant;
+ if (cfg->valid_rx_ant)
+ data->valid_rx_ant = cfg->valid_rx_ant;
+
+ if (!data->valid_tx_ant || !data->valid_rx_ant) {
+ IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
+ data->valid_tx_ant, data->valid_rx_ant);
+ kfree(data);
+ return NULL;
+ }
+
+ data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS);
+
+ data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
+ data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
+
+ /* The byte order is little endian 16 bit, meaning 214365 */
+ memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN);
+ data->hw_addr[0] = hw_addr[1];
+ data->hw_addr[1] = hw_addr[0];
+ data->hw_addr[2] = hw_addr[3];
+ data->hw_addr[3] = hw_addr[2];
+ data->hw_addr[4] = hw_addr[5];
+ data->hw_addr[5] = hw_addr[4];
+
+ iwl_init_sbands(dev, cfg, data, nvm_sw);
+
+ data->calib_version = 255; /* TODO:
+ this value will prevent some checks from
+ failing, we need to check if this
+ field is still needed, and if it does,
+ where is it in the NVM*/
+
+ return data;
+}
+EXPORT_SYMBOL_GPL(iwl_parse_nvm_data);
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
new file mode 100644
index 000000000000..b2692bd287fa
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ * 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) 2008 - 2013 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) 2005 - 2013 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_nvm_parse_h__
+#define __iwl_nvm_parse_h__
+
+#include "iwl-eeprom-parse.h"
+
+/**
+ * iwl_parse_nvm_data - parse NVM data and return values
+ *
+ * This function parses all NVM values we need and then
+ * returns a (newly allocated) struct containing all the
+ * relevant values for driver use. The struct must be freed
+ * later with iwl_free_nvm_data().
+ */
+struct iwl_nvm_data *
+iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
+ const __le16 *nvm_hw, const __le16 *nvm_sw,
+ const __le16 *nvm_calib);
+
+#endif /* __iwl_nvm_parse_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
index c8d9b9517468..4a680019e117 100644
--- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,6 +63,8 @@
#ifndef __iwl_op_mode_h__
#define __iwl_op_mode_h__
+#include <linux/debugfs.h>
+
struct iwl_op_mode;
struct iwl_trans;
struct sk_buff;
@@ -111,13 +113,13 @@ struct iwl_cfg;
* May sleep
* @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the
* HCMD the this Rx responds to.
- * Must be atomic and called with BH disabled.
+ * This callback may sleep, it is called from a threaded IRQ handler.
* @queue_full: notifies that a HW queue is full.
* Must be atomic and called with BH disabled.
* @queue_not_full: notifies that a HW queue is not full any more.
* Must be atomic and called with BH disabled.
* @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that
- * the radio is killed. Must be atomic.
+ * the radio is killed. May sleep.
* @free_skb: allows the transport layer to free skbs that haven't been
* reclaimed by the op_mode. This can happen when the driver is freed and
* there are Tx packets pending in the transport layer.
@@ -128,8 +130,7 @@ struct iwl_cfg;
* called with BH disabled.
* @nic_config: configure NIC, called before firmware is started.
* May sleep
- * @wimax_active: invoked when WiMax becomes active. Must be atomic and called
- * with BH disabled.
+ * @wimax_active: invoked when WiMax becomes active. May sleep
*/
struct iwl_op_mode_ops {
struct iwl_op_mode *(*start)(struct iwl_trans *trans,
@@ -176,6 +177,7 @@ static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
+ might_sleep();
return op_mode->ops->rx(op_mode, rxb, cmd);
}
@@ -194,6 +196,7 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode,
static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode,
bool state)
{
+ might_sleep();
op_mode->ops->hw_rf_kill(op_mode, state);
}
@@ -221,6 +224,7 @@ static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode)
static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode)
{
+ might_sleep();
op_mode->ops->wimax_active(op_mode);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
new file mode 100644
index 000000000000..14fc8d39fc28
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
@@ -0,0 +1,514 @@
+/******************************************************************************
+ *
+ * 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) 2007 - 2013 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) 2005 - 2013 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/slab.h>
+#include <linux/string.h>
+#include <linux/export.h>
+
+#include "iwl-phy-db.h"
+#include "iwl-debug.h"
+#include "iwl-op-mode.h"
+#include "iwl-trans.h"
+
+#define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */
+#define IWL_NUM_PAPD_CH_GROUPS 4
+#define IWL_NUM_TXP_CH_GROUPS 9
+
+struct iwl_phy_db_entry {
+ u16 size;
+ u8 *data;
+};
+
+/**
+ * struct iwl_phy_db - stores phy configuration and calibration data.
+ *
+ * @cfg: phy configuration.
+ * @calib_nch: non channel specific calibration data.
+ * @calib_ch: channel specific calibration data.
+ * @calib_ch_group_papd: calibration data related to papd channel group.
+ * @calib_ch_group_txp: calibration data related to tx power chanel group.
+ */
+struct iwl_phy_db {
+ struct iwl_phy_db_entry cfg;
+ struct iwl_phy_db_entry calib_nch;
+ struct iwl_phy_db_entry calib_ch;
+ struct iwl_phy_db_entry calib_ch_group_papd[IWL_NUM_PAPD_CH_GROUPS];
+ struct iwl_phy_db_entry calib_ch_group_txp[IWL_NUM_TXP_CH_GROUPS];
+
+ u32 channel_num;
+ u32 channel_size;
+
+ struct iwl_trans *trans;
+};
+
+enum iwl_phy_db_section_type {
+ IWL_PHY_DB_CFG = 1,
+ IWL_PHY_DB_CALIB_NCH,
+ IWL_PHY_DB_CALIB_CH,
+ IWL_PHY_DB_CALIB_CHG_PAPD,
+ IWL_PHY_DB_CALIB_CHG_TXP,
+ IWL_PHY_DB_MAX
+};
+
+#define PHY_DB_CMD 0x6c /* TEMP API - The actual is 0x8c */
+
+/*
+ * phy db - configure operational ucode
+ */
+struct iwl_phy_db_cmd {
+ __le16 type;
+ __le16 length;
+ u8 data[];
+} __packed;
+
+/* for parsing of tx power channel group data that comes from the firmware*/
+struct iwl_phy_db_chg_txp {
+ __le32 space;
+ __le16 max_channel_idx;
+} __packed;
+
+/*
+ * phy db - Receieve phy db chunk after calibrations
+ */
+struct iwl_calib_res_notif_phy_db {
+ __le16 type;
+ __le16 length;
+ u8 data[];
+} __packed;
+
+#define IWL_PHY_DB_STATIC_PIC cpu_to_le32(0x21436587)
+static inline void iwl_phy_db_test_pic(__le32 pic)
+{
+ WARN_ON(IWL_PHY_DB_STATIC_PIC != pic);
+}
+
+struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)
+{
+ struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db),
+ GFP_KERNEL);
+
+ if (!phy_db)
+ return phy_db;
+
+ phy_db->trans = trans;
+
+ /* TODO: add default values of the phy db. */
+ return phy_db;
+}
+EXPORT_SYMBOL(iwl_phy_db_init);
+
+/*
+ * get phy db section: returns a pointer to a phy db section specified by
+ * type and channel group id.
+ */
+static struct iwl_phy_db_entry *
+iwl_phy_db_get_section(struct iwl_phy_db *phy_db,
+ enum iwl_phy_db_section_type type,
+ u16 chg_id)
+{
+ if (!phy_db || type >= IWL_PHY_DB_MAX)
+ return NULL;
+
+ switch (type) {
+ case IWL_PHY_DB_CFG:
+ return &phy_db->cfg;
+ case IWL_PHY_DB_CALIB_NCH:
+ return &phy_db->calib_nch;
+ case IWL_PHY_DB_CALIB_CH:
+ return &phy_db->calib_ch;
+ case IWL_PHY_DB_CALIB_CHG_PAPD:
+ if (chg_id >= IWL_NUM_PAPD_CH_GROUPS)
+ return NULL;
+ return &phy_db->calib_ch_group_papd[chg_id];
+ case IWL_PHY_DB_CALIB_CHG_TXP:
+ if (chg_id >= IWL_NUM_TXP_CH_GROUPS)
+ return NULL;
+ return &phy_db->calib_ch_group_txp[chg_id];
+ default:
+ return NULL;
+ }
+ return NULL;
+}
+
+static void iwl_phy_db_free_section(struct iwl_phy_db *phy_db,
+ enum iwl_phy_db_section_type type,
+ u16 chg_id)
+{
+ struct iwl_phy_db_entry *entry =
+ iwl_phy_db_get_section(phy_db, type, chg_id);
+ if (!entry)
+ return;
+
+ kfree(entry->data);
+ entry->data = NULL;
+ entry->size = 0;
+}
+
+void iwl_phy_db_free(struct iwl_phy_db *phy_db)
+{
+ int i;
+
+ if (!phy_db)
+ return;
+
+ iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0);
+ iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0);
+ iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CH, 0);
+ for (i = 0; i < IWL_NUM_PAPD_CH_GROUPS; i++)
+ iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i);
+ for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++)
+ iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i);
+
+ kfree(phy_db);
+}
+EXPORT_SYMBOL(iwl_phy_db_free);
+
+int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
+ gfp_t alloc_ctx)
+{
+ struct iwl_calib_res_notif_phy_db *phy_db_notif =
+ (struct iwl_calib_res_notif_phy_db *)pkt->data;
+ enum iwl_phy_db_section_type type = le16_to_cpu(phy_db_notif->type);
+ u16 size = le16_to_cpu(phy_db_notif->length);
+ struct iwl_phy_db_entry *entry;
+ u16 chg_id = 0;
+
+ if (!phy_db)
+ return -EINVAL;
+
+ if (type == IWL_PHY_DB_CALIB_CHG_PAPD ||
+ type == IWL_PHY_DB_CALIB_CHG_TXP)
+ chg_id = le16_to_cpup((__le16 *)phy_db_notif->data);
+
+ entry = iwl_phy_db_get_section(phy_db, type, chg_id);
+ if (!entry)
+ return -EINVAL;
+
+ kfree(entry->data);
+ entry->data = kmemdup(phy_db_notif->data, size, alloc_ctx);
+ if (!entry->data) {
+ entry->size = 0;
+ return -ENOMEM;
+ }
+
+ entry->size = size;
+
+ if (type == IWL_PHY_DB_CALIB_CH) {
+ phy_db->channel_num =
+ le32_to_cpup((__le32 *)phy_db_notif->data);
+ phy_db->channel_size =
+ (size - CHANNEL_NUM_SIZE) / phy_db->channel_num;
+ }
+
+ /* Test PIC */
+ if (type != IWL_PHY_DB_CFG)
+ iwl_phy_db_test_pic(*(((__le32 *)phy_db_notif->data) +
+ (size / sizeof(__le32)) - 1));
+
+ IWL_DEBUG_INFO(phy_db->trans,
+ "%s(%d): [PHYDB]SET: Type %d , Size: %d\n",
+ __func__, __LINE__, type, size);
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_phy_db_set_section);
+
+static int is_valid_channel(u16 ch_id)
+{
+ if (ch_id <= 14 ||
+ (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) ||
+ (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) ||
+ (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1))
+ return 1;
+ return 0;
+}
+
+static u8 ch_id_to_ch_index(u16 ch_id)
+{
+ if (WARN_ON(!is_valid_channel(ch_id)))
+ return 0xff;
+
+ if (ch_id <= 14)
+ return ch_id - 1;
+ if (ch_id <= 64)
+ return (ch_id + 20) / 4;
+ if (ch_id <= 140)
+ return (ch_id - 12) / 4;
+ return (ch_id - 13) / 4;
+}
+
+
+static u16 channel_id_to_papd(u16 ch_id)
+{
+ if (WARN_ON(!is_valid_channel(ch_id)))
+ return 0xff;
+
+ if (1 <= ch_id && ch_id <= 14)
+ return 0;
+ if (36 <= ch_id && ch_id <= 64)
+ return 1;
+ if (100 <= ch_id && ch_id <= 140)
+ return 2;
+ return 3;
+}
+
+static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id)
+{
+ struct iwl_phy_db_chg_txp *txp_chg;
+ int i;
+ u8 ch_index = ch_id_to_ch_index(ch_id);
+ if (ch_index == 0xff)
+ return 0xff;
+
+ for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) {
+ txp_chg = (void *)phy_db->calib_ch_group_txp[i].data;
+ if (!txp_chg)
+ return 0xff;
+ /*
+ * Looking for the first channel group that its max channel is
+ * higher then wanted channel.
+ */
+ if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index)
+ return i;
+ }
+ return 0xff;
+}
+static
+int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db,
+ u32 type, u8 **data, u16 *size, u16 ch_id)
+{
+ struct iwl_phy_db_entry *entry;
+ u32 channel_num;
+ u32 channel_size;
+ u16 ch_group_id = 0;
+ u16 index;
+
+ if (!phy_db)
+ return -EINVAL;
+
+ /* find wanted channel group */
+ if (type == IWL_PHY_DB_CALIB_CHG_PAPD)
+ ch_group_id = channel_id_to_papd(ch_id);
+ else if (type == IWL_PHY_DB_CALIB_CHG_TXP)
+ ch_group_id = channel_id_to_txp(phy_db, ch_id);
+
+ entry = iwl_phy_db_get_section(phy_db, type, ch_group_id);
+ if (!entry)
+ return -EINVAL;
+
+ if (type == IWL_PHY_DB_CALIB_CH) {
+ index = ch_id_to_ch_index(ch_id);
+ channel_num = phy_db->channel_num;
+ channel_size = phy_db->channel_size;
+ if (index >= channel_num) {
+ IWL_ERR(phy_db->trans, "Wrong channel number %d\n",
+ ch_id);
+ return -EINVAL;
+ }
+ *data = entry->data + CHANNEL_NUM_SIZE + index * channel_size;
+ *size = channel_size;
+ } else {
+ *data = entry->data;
+ *size = entry->size;
+ }
+
+ /* Test PIC */
+ if (type != IWL_PHY_DB_CFG)
+ iwl_phy_db_test_pic(*(((__le32 *)*data) +
+ (*size / sizeof(__le32)) - 1));
+
+ IWL_DEBUG_INFO(phy_db->trans,
+ "%s(%d): [PHYDB] GET: Type %d , Size: %d\n",
+ __func__, __LINE__, type, *size);
+
+ return 0;
+}
+
+static int iwl_send_phy_db_cmd(struct iwl_phy_db *phy_db, u16 type,
+ u16 length, void *data)
+{
+ struct iwl_phy_db_cmd phy_db_cmd;
+ struct iwl_host_cmd cmd = {
+ .id = PHY_DB_CMD,
+ .flags = CMD_SYNC,
+ };
+
+ IWL_DEBUG_INFO(phy_db->trans,
+ "Sending PHY-DB hcmd of type %d, of length %d\n",
+ type, length);
+
+ /* Set phy db cmd variables */
+ phy_db_cmd.type = cpu_to_le16(type);
+ phy_db_cmd.length = cpu_to_le16(length);
+
+ /* Set hcmd variables */
+ cmd.data[0] = &phy_db_cmd;
+ cmd.len[0] = sizeof(struct iwl_phy_db_cmd);
+ cmd.data[1] = data;
+ cmd.len[1] = length;
+ cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
+
+ return iwl_trans_send_cmd(phy_db->trans, &cmd);
+}
+
+static int iwl_phy_db_send_all_channel_groups(
+ struct iwl_phy_db *phy_db,
+ enum iwl_phy_db_section_type type,
+ u8 max_ch_groups)
+{
+ u16 i;
+ int err;
+ struct iwl_phy_db_entry *entry;
+
+ /* Send all the channel specific groups to operational fw */
+ for (i = 0; i < max_ch_groups; i++) {
+ entry = iwl_phy_db_get_section(phy_db,
+ type,
+ i);
+ if (!entry)
+ return -EINVAL;
+
+ /* Send the requested PHY DB section */
+ err = iwl_send_phy_db_cmd(phy_db,
+ type,
+ entry->size,
+ entry->data);
+ if (err) {
+ IWL_ERR(phy_db->trans,
+ "Can't SEND phy_db section %d (%d), err %d",
+ type, i, err);
+ return err;
+ }
+
+ IWL_DEBUG_INFO(phy_db->trans,
+ "Sent PHY_DB HCMD, type = %d num = %d",
+ type, i);
+ }
+
+ return 0;
+}
+
+int iwl_send_phy_db_data(struct iwl_phy_db *phy_db)
+{
+ u8 *data = NULL;
+ u16 size = 0;
+ int err;
+
+ IWL_DEBUG_INFO(phy_db->trans,
+ "Sending phy db data and configuration to runtime image\n");
+
+ /* Send PHY DB CFG section */
+ err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CFG,
+ &data, &size, 0);
+ if (err) {
+ IWL_ERR(phy_db->trans, "Cannot get Phy DB cfg section\n");
+ return err;
+ }
+
+ err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CFG, size, data);
+ if (err) {
+ IWL_ERR(phy_db->trans,
+ "Cannot send HCMD of Phy DB cfg section\n");
+ return err;
+ }
+
+ err = iwl_phy_db_get_section_data(phy_db, IWL_PHY_DB_CALIB_NCH,
+ &data, &size, 0);
+ if (err) {
+ IWL_ERR(phy_db->trans,
+ "Cannot get Phy DB non specific channel section\n");
+ return err;
+ }
+
+ err = iwl_send_phy_db_cmd(phy_db, IWL_PHY_DB_CALIB_NCH, size, data);
+ if (err) {
+ IWL_ERR(phy_db->trans,
+ "Cannot send HCMD of Phy DB non specific channel section\n");
+ return err;
+ }
+
+ /* Send all the TXP channel specific data */
+ err = iwl_phy_db_send_all_channel_groups(phy_db,
+ IWL_PHY_DB_CALIB_CHG_PAPD,
+ IWL_NUM_PAPD_CH_GROUPS);
+ if (err) {
+ IWL_ERR(phy_db->trans,
+ "Cannot send channel specific PAPD groups");
+ return err;
+ }
+
+ /* Send all the TXP channel specific data */
+ err = iwl_phy_db_send_all_channel_groups(phy_db,
+ IWL_PHY_DB_CALIB_CHG_TXP,
+ IWL_NUM_TXP_CH_GROUPS);
+ if (err) {
+ IWL_ERR(phy_db->trans,
+ "Cannot send channel specific TX power groups");
+ return err;
+ }
+
+ IWL_DEBUG_INFO(phy_db->trans,
+ "Finished sending phy db non channel data\n");
+ return 0;
+}
+EXPORT_SYMBOL(iwl_send_phy_db_data);
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.h b/drivers/net/wireless/iwlwifi/iwl-phy-db.h
new file mode 100644
index 000000000000..d0e43d96ab38
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.h
@@ -0,0 +1,82 @@
+/******************************************************************************
+ *
+ * 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) 2007 - 2013 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) 2005 - 2013 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_PHYDB_H__
+#define __IWL_PHYDB_H__
+
+#include <linux/types.h>
+
+#include "iwl-op-mode.h"
+#include "iwl-trans.h"
+
+struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans);
+
+void iwl_phy_db_free(struct iwl_phy_db *phy_db);
+
+int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
+ gfp_t alloc_ctx);
+
+
+int iwl_send_phy_db_data(struct iwl_phy_db *phy_db);
+
+#endif /* __IWL_PHYDB_H__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index c3a4bb41e533..f76e9cad7757 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,6 +97,9 @@
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
+/* Device system time */
+#define DEVICE_SYSTEM_TIME_REG 0xA0206C
+
/**
* Tx Scheduler
*
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c
index 81e8c7126d72..ce0c67b425ee 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.c
+++ b/drivers/net/wireless/iwlwifi/iwl-test.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 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) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -466,19 +466,18 @@ static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size)
/* Hard-coded periphery absolute address */
if (IWL_ABS_PRPH_START <= addr &&
addr < IWL_ABS_PRPH_START + PRPH_END) {
- spin_lock_irqsave(&trans->reg_lock, flags);
- iwl_grab_nic_access(trans);
+ if (!iwl_trans_grab_nic_access(trans, false, &flags)) {
+ return -EIO;
+ }
iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
addr | (3 << 24));
for (i = 0; i < size; i += 4)
*(u32 *)(tst->mem.addr + i) =
iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
- iwl_release_nic_access(trans);
- spin_unlock_irqrestore(&trans->reg_lock, flags);
+ iwl_trans_release_nic_access(trans, &flags);
} else { /* target memory (SRAM) */
- _iwl_read_targ_mem_dwords(trans, addr,
- tst->mem.addr,
- tst->mem.size / 4);
+ iwl_trans_read_mem(trans, addr, tst->mem.addr,
+ tst->mem.size / 4);
}
tst->mem.nchunks =
@@ -501,28 +500,25 @@ static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr,
if (IWL_ABS_PRPH_START <= addr &&
addr < IWL_ABS_PRPH_START + PRPH_END) {
- /* Periphery writes can be 1-3 bytes long, or DWORDs */
- if (size < 4) {
- memcpy(&val, buf, size);
- spin_lock_irqsave(&trans->reg_lock, flags);
- iwl_grab_nic_access(trans);
- iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
- (addr & 0x0000FFFF) |
- ((size - 1) << 24));
- iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
- iwl_release_nic_access(trans);
- /* needed after consecutive writes w/o read */
- mmiowb();
- spin_unlock_irqrestore(&trans->reg_lock, flags);
- } else {
- if (size % 4)
- return -EINVAL;
- for (i = 0; i < size; i += 4)
- iwl_write_prph(trans, addr+i,
- *(u32 *)(buf+i));
- }
+ /* Periphery writes can be 1-3 bytes long, or DWORDs */
+ if (size < 4) {
+ memcpy(&val, buf, size);
+ if (!iwl_trans_grab_nic_access(trans, false, &flags))
+ return -EIO;
+ iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
+ (addr & 0x0000FFFF) |
+ ((size - 1) << 24));
+ iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
+ iwl_trans_release_nic_access(trans, &flags);
+ } else {
+ if (size % 4)
+ return -EINVAL;
+ for (i = 0; i < size; i += 4)
+ iwl_write_prph(trans, addr+i,
+ *(u32 *)(buf+i));
+ }
} else if (iwl_test_valid_hw_addr(tst, addr)) {
- _iwl_write_targ_mem_dwords(trans, addr, buf, size / 4);
+ iwl_trans_write_mem(trans, addr, buf, size / 4);
} else {
return -EINVAL;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.h b/drivers/net/wireless/iwlwifi/iwl-test.h
index e13ffa8acc02..7fbf4d717caa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.h
+++ b/drivers/net/wireless/iwlwifi/iwl-test.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 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) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 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-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h
index 6ba211b09426..a963f45c6849 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 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) 2010 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010 - 2013 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-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index b76532e238c1..8c7bec6b9a0b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -65,6 +65,7 @@
#include <linux/ieee80211.h>
#include <linux/mm.h> /* for page_address */
+#include <linux/lockdep.h>
#include "iwl-debug.h"
#include "iwl-config.h"
@@ -193,11 +194,11 @@ struct iwl_rx_packet {
* @CMD_ON_DEMAND: This command is sent by the test mode pipe.
*/
enum CMD_MODE {
- CMD_SYNC = 0,
- CMD_ASYNC = BIT(0),
- CMD_WANT_SKB = BIT(1),
- CMD_WANT_HCMD = BIT(2),
- CMD_ON_DEMAND = BIT(3),
+ CMD_SYNC = 0,
+ CMD_ASYNC = BIT(0),
+ CMD_WANT_SKB = BIT(1),
+ CMD_WANT_HCMD = BIT(2),
+ CMD_ON_DEMAND = BIT(3),
};
#define DEF_CMD_PAYLOAD_SIZE 320
@@ -274,6 +275,7 @@ struct iwl_rx_cmd_buffer {
struct page *_page;
int _offset;
bool _page_stolen;
+ u32 _rx_page_order;
unsigned int truesize;
};
@@ -294,6 +296,11 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
return r->_page;
}
+static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r)
+{
+ __free_pages(r->_page, r->_rx_page_order);
+}
+
#define MAX_NO_RECLAIM_CMDS 6
#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
@@ -308,6 +315,16 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
#define IWL_FRAME_LIMIT 64
/**
+ * enum iwl_wowlan_status - WoWLAN image/device status
+ * @IWL_D3_STATUS_ALIVE: firmware is still running after resume
+ * @IWL_D3_STATUS_RESET: device was reset while suspended
+ */
+enum iwl_d3_status {
+ IWL_D3_STATUS_ALIVE,
+ IWL_D3_STATUS_RESET,
+};
+
+/**
* struct iwl_trans_config - transport configuration
*
* @op_mode: pointer to the upper layer.
@@ -321,6 +338,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
* @n_no_reclaim_cmds: # of commands in list
* @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs,
* if unset 4k will be the RX buffer size
+ * @bc_table_dword: set to true if the BC table expects the byte count to be
+ * in DWORD (as opposed to bytes)
* @queue_watchdog_timeout: time (in ms) after which queues
* are considered stuck and will trigger device restart
* @command_names: array of command names, must be 256 entries
@@ -335,6 +354,7 @@ struct iwl_trans_config {
int n_no_reclaim_cmds;
bool rx_buf_size_8k;
+ bool bc_table_dword;
unsigned int queue_watchdog_timeout;
const char **command_names;
};
@@ -360,9 +380,12 @@ struct iwl_trans;
* May sleep
* @stop_device:stops the whole device (embedded CPU put to reset)
* May sleep
- * @wowlan_suspend: put the device into the correct mode for WoWLAN during
+ * @d3_suspend: put the device into the correct mode for WoWLAN during
* suspend. This is optional, if not implemented WoWLAN will not be
* supported. This callback may sleep.
+ * @d3_resume: resume the device after WoWLAN, enabling the opmode to
+ * talk to the WoWLAN image to get its status. This is optional, if not
+ * implemented WoWLAN will not be supported. This callback may sleep.
* @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted.
* If RFkill is asserted in the middle of a SYNC host command, it must
* return -ERFKILL straight away.
@@ -387,20 +410,31 @@ struct iwl_trans;
* @read32: read a u32 register at offset ofs from the BAR
* @read_prph: read a DWORD from a periphery register
* @write_prph: write a DWORD to a periphery register
+ * @read_mem: read device's SRAM in DWORD
+ * @write_mem: write device's SRAM in DWORD. If %buf is %NULL, then the memory
+ * will be zeroed.
* @configure: configure parameters required by the transport layer from
* the op_mode. May be called several times before start_fw, can't be
* called after that.
* @set_pmi: set the power pmi state
+ * @grab_nic_access: wake the NIC to be able to access non-HBUS regs.
+ * Sleeping is not allowed between grab_nic_access and
+ * release_nic_access.
+ * @release_nic_access: let the NIC go to sleep. The "flags" parameter
+ * must be the same one that was sent before to the grab_nic_access.
+ * @set_bits_mask - set SRAM register according to value and mask.
*/
struct iwl_trans_ops {
int (*start_hw)(struct iwl_trans *iwl_trans);
void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);
- int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw);
+ int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
+ bool run_in_rfkill);
void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
void (*stop_device)(struct iwl_trans *trans);
- void (*wowlan_suspend)(struct iwl_trans *trans);
+ void (*d3_suspend)(struct iwl_trans *trans);
+ int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status);
int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
@@ -424,9 +458,19 @@ struct iwl_trans_ops {
u32 (*read32)(struct iwl_trans *trans, u32 ofs);
u32 (*read_prph)(struct iwl_trans *trans, u32 ofs);
void (*write_prph)(struct iwl_trans *trans, u32 ofs, u32 val);
+ int (*read_mem)(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords);
+ int (*write_mem)(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords);
void (*configure)(struct iwl_trans *trans,
const struct iwl_trans_config *trans_cfg);
void (*set_pmi)(struct iwl_trans *trans, bool state);
+ bool (*grab_nic_access)(struct iwl_trans *trans, bool silent,
+ unsigned long *flags);
+ void (*release_nic_access)(struct iwl_trans *trans,
+ unsigned long *flags);
+ void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask,
+ u32 value);
};
/**
@@ -446,7 +490,6 @@ enum iwl_trans_state {
* @ops - pointer to iwl_trans_ops
* @op_mode - pointer to the op_mode
* @cfg - pointer to the configuration
- * @reg_lock - protect hw register access
* @dev - pointer to struct device * that represents the device
* @hw_id: a u32 with the ID of the device / subdevice.
* Set during transport allocation.
@@ -467,7 +510,6 @@ struct iwl_trans {
struct iwl_op_mode *op_mode;
const struct iwl_cfg *cfg;
enum iwl_trans_state state;
- spinlock_t reg_lock;
struct device *dev;
u32 hw_rev;
@@ -485,6 +527,10 @@ struct iwl_trans {
struct dentry *dbgfs_dir;
+#ifdef CONFIG_LOCKDEP
+ struct lockdep_map sync_cmd_lockdep_map;
+#endif
+
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
char trans_specific[0] __aligned(sizeof(void *));
@@ -528,13 +574,14 @@ static inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr)
}
static inline int iwl_trans_start_fw(struct iwl_trans *trans,
- const struct fw_img *fw)
+ const struct fw_img *fw,
+ bool run_in_rfkill)
{
might_sleep();
WARN_ON_ONCE(!trans->rx_mpdu_cmd);
- return trans->ops->start_fw(trans, fw);
+ return trans->ops->start_fw(trans, fw, run_in_rfkill);
}
static inline void iwl_trans_stop_device(struct iwl_trans *trans)
@@ -546,19 +593,36 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)
trans->state = IWL_TRANS_NO_FW;
}
-static inline void iwl_trans_wowlan_suspend(struct iwl_trans *trans)
+static inline void iwl_trans_d3_suspend(struct iwl_trans *trans)
{
might_sleep();
- trans->ops->wowlan_suspend(trans);
+ trans->ops->d3_suspend(trans);
+}
+
+static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
+ enum iwl_d3_status *status)
+{
+ might_sleep();
+ return trans->ops->d3_resume(trans, status);
}
static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
- struct iwl_host_cmd *cmd)
+ struct iwl_host_cmd *cmd)
{
+ int ret;
+
WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
"%s bad state = %d", __func__, trans->state);
- return trans->ops->send_cmd(trans, cmd);
+ if (!(cmd->flags & CMD_ASYNC))
+ lock_map_acquire_read(&trans->sync_cmd_lockdep_map);
+
+ ret = trans->ops->send_cmd(trans, cmd);
+
+ if (!(cmd->flags & CMD_ASYNC))
+ lock_map_release(&trans->sync_cmd_lockdep_map);
+
+ return ret;
}
static inline struct iwl_device_cmd *
@@ -636,7 +700,7 @@ static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
}
static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
- struct dentry *dir)
+ struct dentry *dir)
{
return trans->ops->dbgfs_register(trans, dir);
}
@@ -679,15 +743,77 @@ static inline void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs,
return trans->ops->write_prph(trans, ofs, val);
}
+static inline int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords)
+{
+ return trans->ops->read_mem(trans, addr, buf, dwords);
+}
+
+#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \
+ do { \
+ if (__builtin_constant_p(bufsize)) \
+ BUILD_BUG_ON((bufsize) % sizeof(u32)); \
+ iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\
+ } while (0)
+
+static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr)
+{
+ u32 value;
+
+ if (WARN_ON(iwl_trans_read_mem(trans, addr, &value, 1)))
+ return 0xa5a5a5a5;
+
+ return value;
+}
+
+static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords)
+{
+ return trans->ops->write_mem(trans, addr, buf, dwords);
+}
+
+static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,
+ u32 val)
+{
+ return iwl_trans_write_mem(trans, addr, &val, 1);
+}
+
static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
{
trans->ops->set_pmi(trans, state);
}
+static inline void
+iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
+{
+ trans->ops->set_bits_mask(trans, reg, mask, value);
+}
+
+#define iwl_trans_grab_nic_access(trans, silent, flags) \
+ __cond_lock(nic_access, \
+ likely((trans)->ops->grab_nic_access(trans, silent, flags)))
+
+static inline void __releases(nic_access)
+iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
+{
+ trans->ops->release_nic_access(trans, flags);
+ __release(nic_access);
+}
+
/*****************************************************
* driver (transport) register/unregister functions
******************************************************/
int __must_check iwl_pci_register_driver(void);
void iwl_pci_unregister_driver(void);
+static inline void trans_lockdep_init(struct iwl_trans *trans)
+{
+#ifdef CONFIG_LOCKDEP
+ static struct lock_class_key __key;
+
+ lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map",
+ &__key, 0);
+#endif
+}
+
#endif /* __iwl_trans_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile
new file mode 100644
index 000000000000..807b250ec396
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_IWLMVM) += iwlmvm.o
+iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
+iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o
+iwlmvm-y += scan.o time-event.o rs.o
+iwlmvm-y += power.o
+iwlmvm-y += led.o
+iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
+iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
+
+ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../
diff --git a/drivers/net/wireless/iwlwifi/mvm/binding.c b/drivers/net/wireless/iwlwifi/mvm/binding.c
new file mode 100644
index 000000000000..73d24aacb90a
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/binding.c
@@ -0,0 +1,197 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 <net/mac80211.h>
+#include "fw-api.h"
+#include "mvm.h"
+
+struct iwl_mvm_iface_iterator_data {
+ struct ieee80211_vif *ignore_vif;
+ int idx;
+
+ struct iwl_mvm_phy_ctxt *phyctxt;
+
+ u16 ids[MAX_MACS_IN_BINDING];
+ u16 colors[MAX_MACS_IN_BINDING];
+};
+
+static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action,
+ struct iwl_mvm_iface_iterator_data *data)
+{
+ struct iwl_binding_cmd cmd;
+ struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt;
+ int i, ret;
+ u32 status;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
+ phyctxt->color));
+ cmd.action = cpu_to_le32(action);
+ cmd.phy = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
+ phyctxt->color));
+
+ for (i = 0; i < MAX_MACS_IN_BINDING; i++)
+ cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
+ for (i = 0; i < data->idx; i++)
+ cmd.macs[i] = cpu_to_le32(FW_CMD_ID_AND_COLOR(data->ids[i],
+ data->colors[i]));
+
+ status = 0;
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
+ sizeof(cmd), &cmd, &status);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n",
+ action, ret);
+ return ret;
+ }
+
+ if (status) {
+ IWL_ERR(mvm, "Binding command failed: %u\n", status);
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_iface_iterator_data *data = _data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (vif == data->ignore_vif)
+ return;
+
+ if (mvmvif->phy_ctxt != data->phyctxt)
+ return;
+
+ if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING))
+ return;
+
+ data->ids[data->idx] = mvmvif->id;
+ data->colors[data->idx] = mvmvif->color;
+ data->idx++;
+}
+
+static int iwl_mvm_binding_update(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_mvm_phy_ctxt *phyctxt,
+ bool add)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_iface_iterator_data data = {
+ .ignore_vif = vif,
+ .phyctxt = phyctxt,
+ };
+ u32 action = FW_CTXT_ACTION_MODIFY;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_iface_iterator,
+ &data);
+
+ /*
+ * If there are no other interfaces yet we
+ * need to create a new binding.
+ */
+ if (data.idx == 0) {
+ if (add)
+ action = FW_CTXT_ACTION_ADD;
+ else
+ action = FW_CTXT_ACTION_REMOVE;
+ }
+
+ if (add) {
+ if (WARN_ON_ONCE(data.idx >= MAX_MACS_IN_BINDING))
+ return -EINVAL;
+
+ data.ids[data.idx] = mvmvif->id;
+ data.colors[data.idx] = mvmvif->color;
+ data.idx++;
+ }
+
+ return iwl_mvm_binding_cmd(mvm, action, &data);
+}
+
+int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
+ return -EINVAL;
+
+ return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
+}
+
+int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
+ return -EINVAL;
+
+ return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
new file mode 100644
index 000000000000..c64d864799cd
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -0,0 +1,955 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 <net/cfg80211.h>
+#include <net/ipv6.h>
+#include "iwl-modparams.h"
+#include "fw-api.h"
+#include "mvm.h"
+
+void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_gtk_rekey_data *data)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (iwlwifi_mod_params.sw_crypto)
+ return;
+
+ mutex_lock(&mvm->mutex);
+
+ memcpy(mvmvif->rekey_data.kek, data->kek, NL80211_KEK_LEN);
+ memcpy(mvmvif->rekey_data.kck, data->kck, NL80211_KCK_LEN);
+ mvmvif->rekey_data.replay_ctr =
+ cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
+ mvmvif->rekey_data.valid = true;
+
+ mutex_unlock(&mvm->mutex);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct inet6_dev *idev)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct inet6_ifaddr *ifa;
+ int idx = 0;
+
+ read_lock_bh(&idev->lock);
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
+ mvmvif->target_ipv6_addrs[idx] = ifa->addr;
+ idx++;
+ if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS)
+ break;
+ }
+ read_unlock_bh(&idev->lock);
+
+ mvmvif->num_target_ipv6_addrs = idx;
+}
+#endif
+
+void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, int idx)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ mvmvif->tx_key_idx = idx;
+}
+
+static void iwl_mvm_convert_p1k(u16 *p1k, __le16 *out)
+{
+ int i;
+
+ for (i = 0; i < IWL_P1K_SIZE; i++)
+ out[i] = cpu_to_le16(p1k[i]);
+}
+
+struct wowlan_key_data {
+ struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
+ struct iwl_wowlan_tkip_params_cmd *tkip;
+ bool error, use_rsc_tsc, use_tkip;
+ int gtk_key_idx;
+};
+
+static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ void *_data)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct wowlan_key_data *data = _data;
+ struct aes_sc *aes_sc, *aes_tx_sc = NULL;
+ struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
+ struct iwl_p1k_cache *rx_p1ks;
+ u8 *rx_mic_key;
+ struct ieee80211_key_seq seq;
+ u32 cur_rx_iv32 = 0;
+ u16 p1k[IWL_P1K_SIZE];
+ int ret, i;
+
+ mutex_lock(&mvm->mutex);
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */
+ struct {
+ struct iwl_mvm_wep_key_cmd wep_key_cmd;
+ struct iwl_mvm_wep_key wep_key;
+ } __packed wkc = {
+ .wep_key_cmd.mac_id_n_color =
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+ mvmvif->color)),
+ .wep_key_cmd.num_keys = 1,
+ /* firmware sets STA_KEY_FLG_WEP_13BYTES */
+ .wep_key_cmd.decryption_type = STA_KEY_FLG_WEP,
+ .wep_key.key_index = key->keyidx,
+ .wep_key.key_size = key->keylen,
+ };
+
+ /*
+ * This will fail -- the key functions don't set support
+ * pairwise WEP keys. However, that's better than silently
+ * failing WoWLAN. Or maybe not?
+ */
+ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+ break;
+
+ memcpy(&wkc.wep_key.key[3], key->key, key->keylen);
+ if (key->keyidx == mvmvif->tx_key_idx) {
+ /* TX key must be at offset 0 */
+ wkc.wep_key.key_offset = 0;
+ } else {
+ /* others start at 1 */
+ data->gtk_key_idx++;
+ wkc.wep_key.key_offset = data->gtk_key_idx;
+ }
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC,
+ sizeof(wkc), &wkc);
+ data->error = ret != 0;
+
+ /* don't upload key again */
+ goto out_unlock;
+ }
+ default:
+ data->error = true;
+ goto out_unlock;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ /*
+ * Ignore CMAC keys -- the WoWLAN firmware doesn't support them
+ * but we also shouldn't abort suspend due to that. It does have
+ * support for the IGTK key renewal, but doesn't really use the
+ * IGTK for anything. This means we could spuriously wake up or
+ * be deauthenticated, but that was considered acceptable.
+ */
+ goto out_unlock;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (sta) {
+ tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
+ tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
+
+ rx_p1ks = data->tkip->rx_uni;
+
+ ieee80211_get_key_tx_seq(key, &seq);
+ tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
+ tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+
+ ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
+ iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k);
+
+ memcpy(data->tkip->mic_keys.tx,
+ &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+ IWL_MIC_KEY_SIZE);
+
+ rx_mic_key = data->tkip->mic_keys.rx_unicast;
+ } else {
+ tkip_sc =
+ data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
+ rx_p1ks = data->tkip->rx_multi;
+ rx_mic_key = data->tkip->mic_keys.rx_mcast;
+ }
+
+ /*
+ * For non-QoS this relies on the fact that both the uCode and
+ * mac80211 use TID 0 (as they need to to avoid replay attacks)
+ * for checking the IV in the frames.
+ */
+ for (i = 0; i < IWL_NUM_RSC; i++) {
+ ieee80211_get_key_rx_seq(key, i, &seq);
+ tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
+ tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
+ /* wrapping isn't allowed, AP must rekey */
+ if (seq.tkip.iv32 > cur_rx_iv32)
+ cur_rx_iv32 = seq.tkip.iv32;
+ }
+
+ ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid,
+ cur_rx_iv32, p1k);
+ iwl_mvm_convert_p1k(p1k, rx_p1ks[0].p1k);
+ ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid,
+ cur_rx_iv32 + 1, p1k);
+ iwl_mvm_convert_p1k(p1k, rx_p1ks[1].p1k);
+
+ memcpy(rx_mic_key,
+ &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+ IWL_MIC_KEY_SIZE);
+
+ data->use_tkip = true;
+ data->use_rsc_tsc = true;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (sta) {
+ u8 *pn = seq.ccmp.pn;
+
+ aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
+ aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
+
+ ieee80211_get_key_tx_seq(key, &seq);
+ aes_tx_sc->pn = cpu_to_le64((u64)pn[5] |
+ ((u64)pn[4] << 8) |
+ ((u64)pn[3] << 16) |
+ ((u64)pn[2] << 24) |
+ ((u64)pn[1] << 32) |
+ ((u64)pn[0] << 40));
+ } else {
+ aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
+ }
+
+ /*
+ * For non-QoS this relies on the fact that both the uCode and
+ * mac80211 use TID 0 for checking the IV in the frames.
+ */
+ for (i = 0; i < IWL_NUM_RSC; i++) {
+ u8 *pn = seq.ccmp.pn;
+
+ ieee80211_get_key_rx_seq(key, i, &seq);
+ aes_sc->pn = cpu_to_le64((u64)pn[5] |
+ ((u64)pn[4] << 8) |
+ ((u64)pn[3] << 16) |
+ ((u64)pn[2] << 24) |
+ ((u64)pn[1] << 32) |
+ ((u64)pn[0] << 40));
+ }
+ data->use_rsc_tsc = true;
+ break;
+ }
+
+ /*
+ * The D3 firmware hardcodes the key offset 0 as the key it uses
+ * to transmit packets to the AP, i.e. the PTK.
+ */
+ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
+ key->hw_key_idx = 0;
+ } else {
+ data->gtk_key_idx++;
+ key->hw_key_idx = data->gtk_key_idx;
+ }
+
+ ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);
+ data->error = ret != 0;
+out_unlock:
+ mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
+ struct cfg80211_wowlan *wowlan)
+{
+ struct iwl_wowlan_patterns_cmd *pattern_cmd;
+ struct iwl_host_cmd cmd = {
+ .id = WOWLAN_PATTERNS,
+ .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+ .flags = CMD_SYNC,
+ };
+ int i, err;
+
+ if (!wowlan->n_patterns)
+ return 0;
+
+ cmd.len[0] = sizeof(*pattern_cmd) +
+ wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern);
+
+ pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
+ if (!pattern_cmd)
+ return -ENOMEM;
+
+ pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+
+ for (i = 0; i < wowlan->n_patterns; i++) {
+ int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+
+ memcpy(&pattern_cmd->patterns[i].mask,
+ wowlan->patterns[i].mask, mask_len);
+ memcpy(&pattern_cmd->patterns[i].pattern,
+ wowlan->patterns[i].pattern,
+ wowlan->patterns[i].pattern_len);
+ pattern_cmd->patterns[i].mask_size = mask_len;
+ pattern_cmd->patterns[i].pattern_size =
+ wowlan->patterns[i].pattern_len;
+ }
+
+ cmd.data[0] = pattern_cmd;
+ err = iwl_mvm_send_cmd(mvm, &cmd);
+ kfree(pattern_cmd);
+ return err;
+}
+
+static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_proto_offload_cmd cmd = {};
+#if IS_ENABLED(CONFIG_IPV6)
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int i;
+
+ if (mvmvif->num_target_ipv6_addrs) {
+ cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_NS);
+ memcpy(cmd.ndp_mac_addr, vif->addr, ETH_ALEN);
+ }
+
+ BUILD_BUG_ON(sizeof(cmd.target_ipv6_addr[i]) !=
+ sizeof(mvmvif->target_ipv6_addrs[i]));
+
+ for (i = 0; i < mvmvif->num_target_ipv6_addrs; i++)
+ memcpy(cmd.target_ipv6_addr[i],
+ &mvmvif->target_ipv6_addrs[i],
+ sizeof(cmd.target_ipv6_addr[i]));
+#endif
+
+ if (vif->bss_conf.arp_addr_cnt) {
+ cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_ARP);
+ cmd.host_ipv4_addr = vif->bss_conf.arp_addr_list[0];
+ memcpy(cmd.arp_mac_addr, vif->addr, ETH_ALEN);
+ }
+
+ if (!cmd.enabled)
+ return 0;
+
+ return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC,
+ sizeof(cmd), &cmd);
+}
+
+struct iwl_d3_iter_data {
+ struct iwl_mvm *mvm;
+ struct ieee80211_vif *vif;
+ bool error;
+};
+
+static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_d3_iter_data *data = _data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+ return;
+
+ if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
+ return;
+
+ if (data->vif) {
+ IWL_ERR(data->mvm, "More than one managed interface active!\n");
+ data->error = true;
+ return;
+ }
+
+ data->vif = vif;
+}
+
+static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *ap_sta)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct ieee80211_chanctx_conf *ctx;
+ u8 chains_static, chains_dynamic;
+ struct cfg80211_chan_def chandef;
+ int ret, i;
+ struct iwl_binding_cmd binding_cmd = {};
+ struct iwl_time_quota_cmd quota_cmd = {};
+ u32 status;
+
+ /* add back the PHY */
+ if (WARN_ON(!mvmvif->phy_ctxt))
+ return -EINVAL;
+
+ rcu_read_lock();
+ ctx = rcu_dereference(vif->chanctx_conf);
+ if (WARN_ON(!ctx)) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ chandef = ctx->def;
+ chains_static = ctx->rx_chains_static;
+ chains_dynamic = ctx->rx_chains_dynamic;
+ rcu_read_unlock();
+
+ ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt, &chandef,
+ chains_static, chains_dynamic);
+ if (ret)
+ return ret;
+
+ /* add back the MAC */
+ mvmvif->uploaded = false;
+
+ if (WARN_ON(!vif->bss_conf.assoc))
+ return -EINVAL;
+ /* hack */
+ vif->bss_conf.assoc = false;
+ ret = iwl_mvm_mac_ctxt_add(mvm, vif);
+ vif->bss_conf.assoc = true;
+ if (ret)
+ return ret;
+
+ /* add back binding - XXX refactor? */
+ binding_cmd.id_and_color =
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
+ mvmvif->phy_ctxt->color));
+ binding_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
+ binding_cmd.phy =
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
+ mvmvif->phy_ctxt->color));
+ binding_cmd.macs[0] = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+ mvmvif->color));
+ for (i = 1; i < MAX_MACS_IN_BINDING; i++)
+ binding_cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
+
+ status = 0;
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
+ sizeof(binding_cmd), &binding_cmd,
+ &status);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to add binding: %d\n", ret);
+ return ret;
+ }
+
+ if (status) {
+ IWL_ERR(mvm, "Binding command failed: %u\n", status);
+ return -EIO;
+ }
+
+ ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false);
+ if (ret)
+ return ret;
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta);
+
+ ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
+ if (ret)
+ return ret;
+
+ /* and some quota */
+ quota_cmd.quotas[0].id_and_color =
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
+ mvmvif->phy_ctxt->color));
+ quota_cmd.quotas[0].quota = cpu_to_le32(100);
+ quota_cmd.quotas[0].max_duration = cpu_to_le32(1000);
+
+ for (i = 1; i < MAX_BINDINGS; i++)
+ quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC,
+ sizeof(quota_cmd), &quota_cmd);
+ if (ret)
+ IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
+
+ return 0;
+}
+
+int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_d3_iter_data suspend_iter_data = {
+ .mvm = mvm,
+ };
+ struct ieee80211_vif *vif;
+ struct iwl_mvm_vif *mvmvif;
+ struct ieee80211_sta *ap_sta;
+ struct iwl_mvm_sta *mvm_ap_sta;
+ struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
+ struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
+ struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
+ struct iwl_d3_manager_config d3_cfg_cmd = {};
+ struct wowlan_key_data key_data = {
+ .use_rsc_tsc = false,
+ .tkip = &tkip_cmd,
+ .use_tkip = false,
+ };
+ int ret, i;
+ u16 seq;
+ u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
+
+ if (WARN_ON(!wowlan))
+ return -EINVAL;
+
+ key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
+ if (!key_data.rsc_tsc)
+ return -ENOMEM;
+
+ mutex_lock(&mvm->mutex);
+
+ old_aux_sta_id = mvm->aux_sta.sta_id;
+
+ /* see if there's only a single BSS vif and it's associated */
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_d3_iface_iterator, &suspend_iter_data);
+
+ if (suspend_iter_data.error || !suspend_iter_data.vif) {
+ ret = 1;
+ goto out_noreset;
+ }
+
+ vif = suspend_iter_data.vif;
+ mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ ap_sta = rcu_dereference_protected(
+ mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
+ lockdep_is_held(&mvm->mutex));
+ if (IS_ERR_OR_NULL(ap_sta)) {
+ ret = -EINVAL;
+ goto out_noreset;
+ }
+
+ mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
+
+ /*
+ * The D3 firmware still hardcodes the AP station ID for the
+ * BSS we're associated with as 0. Store the real STA ID here
+ * and assign 0. When we leave this function, we'll restore
+ * the original value for the resume code.
+ */
+ old_ap_sta_id = mvm_ap_sta->sta_id;
+ mvm_ap_sta->sta_id = 0;
+ mvmvif->ap_sta_id = 0;
+
+ /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */
+
+ wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported;
+
+ /*
+ * We know the last used seqno, and the uCode expects to know that
+ * one, it will increment before TX.
+ */
+ seq = mvm_ap_sta->last_seq_ctl & IEEE80211_SCTL_SEQ;
+ wowlan_config_cmd.non_qos_seq = cpu_to_le16(seq);
+
+ /*
+ * For QoS counters, we store the one to use next, so subtract 0x10
+ * since the uCode will add 0x10 *before* using the value while we
+ * increment after using the value (i.e. store the next value to use).
+ */
+ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+ seq = mvm_ap_sta->tid_data[i].seq_number;
+ seq -= 0x10;
+ wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq);
+ }
+
+ if (wowlan->disconnect)
+ wowlan_config_cmd.wakeup_filter |=
+ cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |
+ IWL_WOWLAN_WAKEUP_LINK_CHANGE);
+ if (wowlan->magic_pkt)
+ wowlan_config_cmd.wakeup_filter |=
+ cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET);
+ if (wowlan->gtk_rekey_failure)
+ wowlan_config_cmd.wakeup_filter |=
+ cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
+ if (wowlan->eap_identity_req)
+ wowlan_config_cmd.wakeup_filter |=
+ cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ);
+ if (wowlan->four_way_handshake)
+ wowlan_config_cmd.wakeup_filter |=
+ cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
+ if (wowlan->n_patterns)
+ wowlan_config_cmd.wakeup_filter |=
+ cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
+
+ if (wowlan->rfkill_release)
+ d3_cfg_cmd.wakeup_flags |=
+ cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
+
+ iwl_mvm_cancel_scan(mvm);
+
+ iwl_trans_stop_device(mvm->trans);
+
+ /*
+ * Set the HW restart bit -- this is mostly true as we're
+ * going to load new firmware and reprogram that, though
+ * the reprogramming is going to be manual to avoid adding
+ * all the MACs that aren't support.
+ * We don't have to clear up everything though because the
+ * reprogramming is manual. When we resume, we'll actually
+ * go through a proper restart sequence again to switch
+ * back to the runtime firmware image.
+ */
+ set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+
+ /* We reprogram keys and shouldn't allocate new key indices */
+ memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
+
+ /*
+ * The D3 firmware still hardcodes the AP station ID for the
+ * BSS we're associated with as 0. As a result, we have to move
+ * the auxiliary station to ID 1 so the ID 0 remains free for
+ * the AP station for later.
+ * We set the sta_id to 1 here, and reset it to its previous
+ * value (that we stored above) later.
+ */
+ mvm->aux_sta.sta_id = 1;
+
+ ret = iwl_mvm_load_d3_fw(mvm);
+ if (ret)
+ goto out;
+
+ ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
+ if (ret)
+ goto out;
+
+ if (!iwlwifi_mod_params.sw_crypto) {
+ /*
+ * This needs to be unlocked due to lock ordering
+ * constraints. Since we're in the suspend path
+ * that isn't really a problem though.
+ */
+ mutex_unlock(&mvm->mutex);
+ ieee80211_iter_keys(mvm->hw, vif,
+ iwl_mvm_wowlan_program_keys,
+ &key_data);
+ mutex_lock(&mvm->mutex);
+ if (key_data.error) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (key_data.use_rsc_tsc) {
+ struct iwl_host_cmd rsc_tsc_cmd = {
+ .id = WOWLAN_TSC_RSC_PARAM,
+ .flags = CMD_SYNC,
+ .data[0] = key_data.rsc_tsc,
+ .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+ .len[0] = sizeof(*key_data.rsc_tsc),
+ };
+
+ ret = iwl_mvm_send_cmd(mvm, &rsc_tsc_cmd);
+ if (ret)
+ goto out;
+ }
+
+ if (key_data.use_tkip) {
+ ret = iwl_mvm_send_cmd_pdu(mvm,
+ WOWLAN_TKIP_PARAM,
+ CMD_SYNC, sizeof(tkip_cmd),
+ &tkip_cmd);
+ if (ret)
+ goto out;
+ }
+
+ if (mvmvif->rekey_data.valid) {
+ memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
+ memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck,
+ NL80211_KCK_LEN);
+ kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
+ memcpy(kek_kck_cmd.kek, mvmvif->rekey_data.kek,
+ NL80211_KEK_LEN);
+ kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
+ kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr;
+
+ ret = iwl_mvm_send_cmd_pdu(mvm,
+ WOWLAN_KEK_KCK_MATERIAL,
+ CMD_SYNC,
+ sizeof(kek_kck_cmd),
+ &kek_kck_cmd);
+ if (ret)
+ goto out;
+ }
+ }
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION,
+ CMD_SYNC, sizeof(wowlan_config_cmd),
+ &wowlan_config_cmd);
+ if (ret)
+ goto out;
+
+ ret = iwl_mvm_send_patterns(mvm, wowlan);
+ if (ret)
+ goto out;
+
+ ret = iwl_mvm_send_proto_offload(mvm, vif);
+ if (ret)
+ goto out;
+
+ /* must be last -- this switches firmware state */
+ ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
+ sizeof(d3_cfg_cmd), &d3_cfg_cmd);
+ if (ret)
+ goto out;
+
+ clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+
+ iwl_trans_d3_suspend(mvm->trans);
+ out:
+ mvm->aux_sta.sta_id = old_aux_sta_id;
+ mvm_ap_sta->sta_id = old_ap_sta_id;
+ mvmvif->ap_sta_id = old_ap_sta_id;
+ out_noreset:
+ kfree(key_data.rsc_tsc);
+ if (ret < 0)
+ ieee80211_restart_hw(mvm->hw);
+
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ u32 base = mvm->error_event_table;
+ struct error_table_start {
+ /* cf. struct iwl_error_event_table */
+ u32 valid;
+ u32 error_id;
+ } err_info;
+ struct cfg80211_wowlan_wakeup wakeup = {
+ .pattern_idx = -1,
+ };
+ struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
+ struct iwl_host_cmd cmd = {
+ .id = WOWLAN_GET_STATUSES,
+ .flags = CMD_SYNC | CMD_WANT_SKB,
+ };
+ struct iwl_wowlan_status *status;
+ u32 reasons;
+ int ret, len;
+ bool pkt8023 = false;
+ struct sk_buff *pkt = NULL;
+
+ iwl_trans_read_mem_bytes(mvm->trans, base,
+ &err_info, sizeof(err_info));
+
+ if (err_info.valid) {
+ IWL_INFO(mvm, "error table is valid (%d)\n",
+ err_info.valid);
+ if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) {
+ wakeup.rfkill_release = true;
+ ieee80211_report_wowlan_wakeup(vif, &wakeup,
+ GFP_KERNEL);
+ }
+ return;
+ }
+
+ /* only for tracing for now */
+ ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL);
+ if (ret)
+ IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret);
+
+ ret = iwl_mvm_send_cmd(mvm, &cmd);
+ if (ret) {
+ IWL_ERR(mvm, "failed to query status (%d)\n", ret);
+ return;
+ }
+
+ /* RF-kill already asserted again... */
+ if (!cmd.resp_pkt)
+ return;
+
+ len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+ if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) {
+ IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
+ goto out;
+ }
+
+ status = (void *)cmd.resp_pkt->data;
+
+ if (len - sizeof(struct iwl_cmd_header) !=
+ sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) {
+ IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
+ goto out;
+ }
+
+ reasons = le32_to_cpu(status->wakeup_reasons);
+
+ if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {
+ wakeup_report = NULL;
+ goto report;
+ }
+
+ if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) {
+ wakeup.magic_pkt = true;
+ pkt8023 = true;
+ }
+
+ if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) {
+ wakeup.pattern_idx =
+ le16_to_cpu(status->pattern_number);
+ pkt8023 = true;
+ }
+
+ if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
+ IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))
+ wakeup.disconnect = true;
+
+ if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) {
+ wakeup.gtk_rekey_failure = true;
+ pkt8023 = true;
+ }
+
+ if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) {
+ wakeup.rfkill_release = true;
+ pkt8023 = true;
+ }
+
+ if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) {
+ wakeup.eap_identity_req = true;
+ pkt8023 = true;
+ }
+
+ if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) {
+ wakeup.four_way_handshake = true;
+ pkt8023 = true;
+ }
+
+ if (status->wake_packet_bufsize) {
+ u32 pktsize = le32_to_cpu(status->wake_packet_bufsize);
+ u32 pktlen = le32_to_cpu(status->wake_packet_length);
+
+ if (pkt8023) {
+ pkt = alloc_skb(pktsize, GFP_KERNEL);
+ if (!pkt)
+ goto report;
+ memcpy(skb_put(pkt, pktsize), status->wake_packet,
+ pktsize);
+ if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))
+ goto report;
+ wakeup.packet = pkt->data;
+ wakeup.packet_present_len = pkt->len;
+ wakeup.packet_len = pkt->len - (pktlen - pktsize);
+ wakeup.packet_80211 = false;
+ } else {
+ wakeup.packet = status->wake_packet;
+ wakeup.packet_present_len = pktsize;
+ wakeup.packet_len = pktlen;
+ wakeup.packet_80211 = true;
+ }
+ }
+
+ report:
+ ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL);
+ kfree_skb(pkt);
+
+ out:
+ iwl_free_resp(&cmd);
+}
+
+int iwl_mvm_resume(struct ieee80211_hw *hw)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_d3_iter_data resume_iter_data = {
+ .mvm = mvm,
+ };
+ struct ieee80211_vif *vif = NULL;
+ int ret;
+ enum iwl_d3_status d3_status;
+
+ mutex_lock(&mvm->mutex);
+
+ /* get the BSS vif pointer again */
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_d3_iface_iterator, &resume_iter_data);
+
+ if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif))
+ goto out_unlock;
+
+ vif = resume_iter_data.vif;
+
+ ret = iwl_trans_d3_resume(mvm->trans, &d3_status);
+ if (ret)
+ goto out_unlock;
+
+ if (d3_status != IWL_D3_STATUS_ALIVE) {
+ IWL_INFO(mvm, "Device was reset during suspend\n");
+ goto out_unlock;
+ }
+
+ iwl_mvm_query_wakeup_reasons(mvm, vif);
+
+ out_unlock:
+ mutex_unlock(&mvm->mutex);
+
+ if (vif)
+ ieee80211_resume_disconnect(vif);
+
+ /* return 1 to reconfigure the device */
+ set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+ return 1;
+}
+
+void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ device_set_wakeup_enable(mvm->trans->dev, enabled);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
new file mode 100644
index 000000000000..c1bdb5582126
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -0,0 +1,378 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 "mvm.h"
+#include "sta.h"
+#include "iwl-io.h"
+
+struct iwl_dbgfs_mvm_ctx {
+ struct iwl_mvm *mvm;
+ struct ieee80211_vif *vif;
+};
+
+static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t iwl_dbgfs_tx_flush_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+
+ char buf[16];
+ int buf_size, ret;
+ u32 scd_q_msk;
+
+ if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
+ return -EIO;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ if (sscanf(buf, "%x", &scd_q_msk) != 1)
+ return -EINVAL;
+
+ IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk);
+
+ mutex_lock(&mvm->mutex);
+ ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, true) ? : count;
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_sta_drain_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ struct ieee80211_sta *sta;
+
+ char buf[8];
+ int buf_size, sta_id, drain, ret;
+
+ if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
+ return -EIO;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
+ return -EINVAL;
+
+ mutex_lock(&mvm->mutex);
+
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+ if (IS_ERR_OR_NULL(sta))
+ ret = -ENOENT;
+ else
+ ret = iwl_mvm_drain_sta(mvm, (void *)sta->drv_priv, drain) ? :
+ count;
+
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ const struct fw_img *img;
+ int ofs, len, pos = 0;
+ size_t bufsz, ret;
+ char *buf;
+ u8 *ptr;
+
+ /* default is to dump the entire data segment */
+ if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) {
+ mvm->dbgfs_sram_offset = 0x800000;
+ if (!mvm->ucode_loaded)
+ return -EINVAL;
+ img = &mvm->fw->img[mvm->cur_ucode];
+ mvm->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
+ }
+ len = mvm->dbgfs_sram_len;
+
+ bufsz = len * 4 + 256;
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ptr = kzalloc(len, GFP_KERNEL);
+ if (!ptr) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len);
+ pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
+ mvm->dbgfs_sram_offset);
+
+ iwl_trans_read_mem_bytes(mvm->trans,
+ mvm->dbgfs_sram_offset,
+ ptr, len);
+ for (ofs = 0; ofs < len; ofs += 16) {
+ pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs);
+ hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
+ bufsz - pos, false);
+ pos += strlen(buf + pos);
+ if (bufsz - pos > 0)
+ buf[pos++] = '\n';
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+
+ kfree(buf);
+ kfree(ptr);
+
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_sram_write(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ char buf[64];
+ int buf_size;
+ u32 offset, len;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
+ if ((offset & 0x3) || (len & 0x3))
+ return -EINVAL;
+ mvm->dbgfs_sram_offset = offset;
+ mvm->dbgfs_sram_len = len;
+ } else {
+ mvm->dbgfs_sram_offset = 0;
+ mvm->dbgfs_sram_len = 0;
+ }
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ struct ieee80211_sta *sta;
+ char buf[400];
+ int i, pos = 0, bufsz = sizeof(buf);
+
+ mutex_lock(&mvm->mutex);
+
+ for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
+ pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i);
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
+ lockdep_is_held(&mvm->mutex));
+ if (!sta)
+ pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
+ else if (IS_ERR(sta))
+ pos += scnprintf(buf + pos, bufsz - pos, "%ld\n",
+ PTR_ERR(sta));
+ else
+ pos += scnprintf(buf + pos, bufsz - pos, "%pM\n",
+ sta->addr);
+ }
+
+ mutex_unlock(&mvm->mutex);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_power_down_allow_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ char buf[8] = {};
+ int allow;
+
+ if (!mvm->ucode_loaded)
+ return -EIO;
+
+ if (copy_from_user(buf, user_buf, sizeof(buf)))
+ return -EFAULT;
+
+ if (sscanf(buf, "%d", &allow) != 1)
+ return -EINVAL;
+
+ IWL_DEBUG_POWER(mvm, "%s device power down\n",
+ allow ? "allow" : "prevent");
+
+ /*
+ * TODO: Send REPLY_DEBUG_CMD (0xf0) when FW support it
+ */
+
+ return count;
+}
+
+static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ char buf[8] = {};
+ int allow;
+
+ if (copy_from_user(buf, user_buf, sizeof(buf)))
+ return -EFAULT;
+
+ if (sscanf(buf, "%d", &allow) != 1)
+ return -EINVAL;
+
+ IWL_DEBUG_POWER(mvm, "%s device power down in d3\n",
+ allow ? "allow" : "prevent");
+
+ /*
+ * TODO: When WoWLAN FW alive notification happens, driver will send
+ * REPLY_DEBUG_CMD setting power_down_allow flag according to
+ * mvm->prevent_power_down_d3
+ */
+ mvm->prevent_power_down_d3 = !allow;
+
+ return count;
+}
+
+#define MVM_DEBUGFS_READ_FILE_OPS(name) \
+static const struct file_operations iwl_dbgfs_##name##_ops = { \
+ .read = iwl_dbgfs_##name##_read, \
+ .open = iwl_dbgfs_open_file_generic, \
+ .llseek = generic_file_llseek, \
+}
+
+#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \
+static const struct file_operations iwl_dbgfs_##name##_ops = { \
+ .write = iwl_dbgfs_##name##_write, \
+ .read = iwl_dbgfs_##name##_read, \
+ .open = iwl_dbgfs_open_file_generic, \
+ .llseek = generic_file_llseek, \
+};
+
+#define MVM_DEBUGFS_WRITE_FILE_OPS(name) \
+static const struct file_operations iwl_dbgfs_##name##_ops = { \
+ .write = iwl_dbgfs_##name##_write, \
+ .open = iwl_dbgfs_open_file_generic, \
+ .llseek = generic_file_llseek, \
+};
+
+#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \
+ if (!debugfs_create_file(#name, mode, parent, mvm, \
+ &iwl_dbgfs_##name##_ops)) \
+ goto err; \
+ } while (0)
+
+#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
+ if (!debugfs_create_file(#name, mode, parent, vif, \
+ &iwl_dbgfs_##name##_ops)) \
+ goto err; \
+ } while (0)
+
+/* Device wide debugfs entries */
+MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush);
+MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram);
+MVM_DEBUGFS_READ_FILE_OPS(stations);
+MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
+MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
+
+int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
+{
+ char buf[100];
+
+ mvm->debugfs_dir = dbgfs_dir;
+
+ MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
+
+ /*
+ * Create a symlink with mac80211. It will be removed when mac80211
+ * exists (before the opmode exists which removes the target.)
+ */
+ snprintf(buf, 100, "../../%s/%s",
+ dbgfs_dir->d_parent->d_parent->d_name.name,
+ dbgfs_dir->d_parent->d_name.name);
+ if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
+ goto err;
+
+ return 0;
+err:
+ IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
+ return -ENOMEM;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
new file mode 100644
index 000000000000..cf6f9a02fb74
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
@@ -0,0 +1,282 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 __fw_api_d3_h__
+#define __fw_api_d3_h__
+
+/**
+ * enum iwl_d3_wakeup_flags - D3 manager wakeup flags
+ * @IWL_WAKEUP_D3_CONFIG_FW_ERROR: wake up on firmware sysassert
+ */
+enum iwl_d3_wakeup_flags {
+ IWL_WAKEUP_D3_CONFIG_FW_ERROR = BIT(0),
+}; /* D3_MANAGER_WAKEUP_CONFIG_API_E_VER_3 */
+
+/**
+ * struct iwl_d3_manager_config - D3 manager configuration command
+ * @min_sleep_time: minimum sleep time (in usec)
+ * @wakeup_flags: wakeup flags, see &enum iwl_d3_wakeup_flags
+ *
+ * The structure is used for the D3_CONFIG_CMD command.
+ */
+struct iwl_d3_manager_config {
+ __le32 min_sleep_time;
+ __le32 wakeup_flags;
+} __packed; /* D3_MANAGER_CONFIG_CMD_S_VER_3 */
+
+
+/* TODO: OFFLOADS_QUERY_API_S_VER_1 */
+
+/**
+ * enum iwl_d3_proto_offloads - enabled protocol offloads
+ * @IWL_D3_PROTO_OFFLOAD_ARP: ARP data is enabled
+ * @IWL_D3_PROTO_OFFLOAD_NS: NS (Neighbor Solicitation) is enabled
+ */
+enum iwl_proto_offloads {
+ IWL_D3_PROTO_OFFLOAD_ARP = BIT(0),
+ IWL_D3_PROTO_OFFLOAD_NS = BIT(1),
+};
+
+#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS 2
+
+/**
+ * struct iwl_proto_offload_cmd - ARP/NS offload configuration
+ * @enabled: enable flags
+ * @remote_ipv4_addr: remote address to answer to (or zero if all)
+ * @host_ipv4_addr: our IPv4 address to respond to queries for
+ * @arp_mac_addr: our MAC address for ARP responses
+ * @remote_ipv6_addr: remote address to answer to (or zero if all)
+ * @solicited_node_ipv6_addr: broken -- solicited node address exists
+ * for each target address
+ * @target_ipv6_addr: our target addresses
+ * @ndp_mac_addr: neighbor soliciation response MAC address
+ */
+struct iwl_proto_offload_cmd {
+ __le32 enabled;
+ __be32 remote_ipv4_addr;
+ __be32 host_ipv4_addr;
+ u8 arp_mac_addr[ETH_ALEN];
+ __le16 reserved1;
+
+ u8 remote_ipv6_addr[16];
+ u8 solicited_node_ipv6_addr[16];
+ u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS][16];
+ u8 ndp_mac_addr[ETH_ALEN];
+ __le16 reserved2;
+} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_1 */
+
+
+/*
+ * WOWLAN_PATTERNS
+ */
+#define IWL_WOWLAN_MIN_PATTERN_LEN 16
+#define IWL_WOWLAN_MAX_PATTERN_LEN 128
+
+struct iwl_wowlan_pattern {
+ u8 mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8];
+ u8 pattern[IWL_WOWLAN_MAX_PATTERN_LEN];
+ u8 mask_size;
+ u8 pattern_size;
+ __le16 reserved;
+} __packed; /* WOWLAN_PATTERN_API_S_VER_1 */
+
+#define IWL_WOWLAN_MAX_PATTERNS 20
+
+struct iwl_wowlan_patterns_cmd {
+ __le32 n_patterns;
+ struct iwl_wowlan_pattern patterns[];
+} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_1 */
+
+enum iwl_wowlan_wakeup_filters {
+ IWL_WOWLAN_WAKEUP_MAGIC_PACKET = BIT(0),
+ IWL_WOWLAN_WAKEUP_PATTERN_MATCH = BIT(1),
+ IWL_WOWLAN_WAKEUP_BEACON_MISS = BIT(2),
+ IWL_WOWLAN_WAKEUP_LINK_CHANGE = BIT(3),
+ IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL = BIT(4),
+ IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ = BIT(5),
+ IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE = BIT(6),
+ IWL_WOWLAN_WAKEUP_ENABLE_NET_DETECT = BIT(7),
+ IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT = BIT(8),
+ IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS = BIT(9),
+ IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE = BIT(10),
+ /* BIT(11) reserved */
+ IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET = BIT(12),
+}; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */
+
+struct iwl_wowlan_config_cmd {
+ __le32 wakeup_filter;
+ __le16 non_qos_seq;
+ __le16 qos_seq[8];
+ u8 wowlan_ba_teardown_tids;
+ u8 is_11n_connection;
+} __packed; /* WOWLAN_CONFIG_API_S_VER_2 */
+
+/*
+ * WOWLAN_TSC_RSC_PARAMS
+ */
+#define IWL_NUM_RSC 16
+
+struct tkip_sc {
+ __le16 iv16;
+ __le16 pad;
+ __le32 iv32;
+} __packed; /* TKIP_SC_API_U_VER_1 */
+
+struct iwl_tkip_rsc_tsc {
+ struct tkip_sc unicast_rsc[IWL_NUM_RSC];
+ struct tkip_sc multicast_rsc[IWL_NUM_RSC];
+ struct tkip_sc tsc;
+} __packed; /* TKIP_TSC_RSC_API_S_VER_1 */
+
+struct aes_sc {
+ __le64 pn;
+} __packed; /* TKIP_AES_SC_API_U_VER_1 */
+
+struct iwl_aes_rsc_tsc {
+ struct aes_sc unicast_rsc[IWL_NUM_RSC];
+ struct aes_sc multicast_rsc[IWL_NUM_RSC];
+ struct aes_sc tsc;
+} __packed; /* AES_TSC_RSC_API_S_VER_1 */
+
+union iwl_all_tsc_rsc {
+ struct iwl_tkip_rsc_tsc tkip;
+ struct iwl_aes_rsc_tsc aes;
+}; /* ALL_TSC_RSC_API_S_VER_2 */
+
+struct iwl_wowlan_rsc_tsc_params_cmd {
+ union iwl_all_tsc_rsc all_tsc_rsc;
+} __packed; /* ALL_TSC_RSC_API_S_VER_2 */
+
+#define IWL_MIC_KEY_SIZE 8
+struct iwl_mic_keys {
+ u8 tx[IWL_MIC_KEY_SIZE];
+ u8 rx_unicast[IWL_MIC_KEY_SIZE];
+ u8 rx_mcast[IWL_MIC_KEY_SIZE];
+} __packed; /* MIC_KEYS_API_S_VER_1 */
+
+#define IWL_P1K_SIZE 5
+struct iwl_p1k_cache {
+ __le16 p1k[IWL_P1K_SIZE];
+} __packed;
+
+#define IWL_NUM_RX_P1K_CACHE 2
+
+struct iwl_wowlan_tkip_params_cmd {
+ struct iwl_mic_keys mic_keys;
+ struct iwl_p1k_cache tx;
+ struct iwl_p1k_cache rx_uni[IWL_NUM_RX_P1K_CACHE];
+ struct iwl_p1k_cache rx_multi[IWL_NUM_RX_P1K_CACHE];
+} __packed; /* WOWLAN_TKIP_SETTING_API_S_VER_1 */
+
+#define IWL_KCK_MAX_SIZE 32
+#define IWL_KEK_MAX_SIZE 32
+
+struct iwl_wowlan_kek_kck_material_cmd {
+ u8 kck[IWL_KCK_MAX_SIZE];
+ u8 kek[IWL_KEK_MAX_SIZE];
+ __le16 kck_len;
+ __le16 kek_len;
+ __le64 replay_ctr;
+} __packed; /* KEK_KCK_MATERIAL_API_S_VER_2 */
+
+#define RF_KILL_INDICATOR_FOR_WOWLAN 0x87
+
+enum iwl_wowlan_rekey_status {
+ IWL_WOWLAN_REKEY_POST_REKEY = 0,
+ IWL_WOWLAN_REKEY_WHILE_REKEY = 1,
+}; /* WOWLAN_REKEY_STATUS_API_E_VER_1 */
+
+enum iwl_wowlan_wakeup_reason {
+ IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS = 0,
+ IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET = BIT(0),
+ IWL_WOWLAN_WAKEUP_BY_PATTERN = BIT(1),
+ IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON = BIT(2),
+ IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH = BIT(3),
+ IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE = BIT(4),
+ IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED = BIT(5),
+ IWL_WOWLAN_WAKEUP_BY_UCODE_ERROR = BIT(6),
+ IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST = BIT(7),
+ IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8),
+ IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9),
+ IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10),
+ IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL = BIT(11),
+ IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12),
+}; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */
+
+struct iwl_wowlan_status {
+ __le64 replay_ctr;
+ __le16 pattern_number;
+ __le16 non_qos_seq_ctr;
+ __le16 qos_seq_ctr[8];
+ __le32 wakeup_reasons;
+ __le32 rekey_status;
+ __le32 num_of_gtk_rekeys;
+ __le32 transmitted_ndps;
+ __le32 received_beacons;
+ __le32 wake_packet_length;
+ __le32 wake_packet_bufsize;
+ u8 wake_packet[]; /* can be truncated from _length to _bufsize */
+} __packed; /* WOWLAN_STATUSES_API_S_VER_4 */
+
+/* TODO: NetDetect API */
+
+#endif /* __fw_api_d3_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
new file mode 100644
index 000000000000..ae39b7dfda7b
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
@@ -0,0 +1,369 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 __fw_api_mac_h__
+#define __fw_api_mac_h__
+
+/*
+ * The first MAC indices (starting from 0)
+ * are available to the driver, AUX follows
+ */
+#define MAC_INDEX_AUX 4
+#define MAC_INDEX_MIN_DRIVER 0
+#define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX
+
+#define AC_NUM 4 /* Number of access categories */
+
+/**
+ * enum iwl_mac_protection_flags - MAC context flags
+ * @MAC_PROT_FLG_TGG_PROTECT: 11g protection when transmitting OFDM frames,
+ * this will require CCK RTS/CTS2self.
+ * RTS/CTS will protect full burst time.
+ * @MAC_PROT_FLG_HT_PROT: enable HT protection
+ * @MAC_PROT_FLG_FAT_PROT: protect 40 MHz transmissions
+ * @MAC_PROT_FLG_SELF_CTS_EN: allow CTS2self
+ */
+enum iwl_mac_protection_flags {
+ MAC_PROT_FLG_TGG_PROTECT = BIT(3),
+ MAC_PROT_FLG_HT_PROT = BIT(23),
+ MAC_PROT_FLG_FAT_PROT = BIT(24),
+ MAC_PROT_FLG_SELF_CTS_EN = BIT(30),
+};
+
+#define MAC_FLG_SHORT_SLOT BIT(4)
+#define MAC_FLG_SHORT_PREAMBLE BIT(5)
+
+/**
+ * enum iwl_mac_types - Supported MAC types
+ * @FW_MAC_TYPE_FIRST: lowest supported MAC type
+ * @FW_MAC_TYPE_AUX: Auxiliary MAC (internal)
+ * @FW_MAC_TYPE_LISTENER: monitor MAC type (?)
+ * @FW_MAC_TYPE_PIBSS: Pseudo-IBSS
+ * @FW_MAC_TYPE_IBSS: IBSS
+ * @FW_MAC_TYPE_BSS_STA: BSS (managed) station
+ * @FW_MAC_TYPE_P2P_DEVICE: P2P Device
+ * @FW_MAC_TYPE_P2P_STA: P2P client
+ * @FW_MAC_TYPE_GO: P2P GO
+ * @FW_MAC_TYPE_TEST: ?
+ * @FW_MAC_TYPE_MAX: highest support MAC type
+ */
+enum iwl_mac_types {
+ FW_MAC_TYPE_FIRST = 1,
+ FW_MAC_TYPE_AUX = FW_MAC_TYPE_FIRST,
+ FW_MAC_TYPE_LISTENER,
+ FW_MAC_TYPE_PIBSS,
+ FW_MAC_TYPE_IBSS,
+ FW_MAC_TYPE_BSS_STA,
+ FW_MAC_TYPE_P2P_DEVICE,
+ FW_MAC_TYPE_P2P_STA,
+ FW_MAC_TYPE_GO,
+ FW_MAC_TYPE_TEST,
+ FW_MAC_TYPE_MAX = FW_MAC_TYPE_TEST
+}; /* MAC_CONTEXT_TYPE_API_E_VER_1 */
+
+/**
+ * enum iwl_tsf_id - TSF hw timer ID
+ * @TSF_ID_A: use TSF A
+ * @TSF_ID_B: use TSF B
+ * @TSF_ID_C: use TSF C
+ * @TSF_ID_D: use TSF D
+ * @NUM_TSF_IDS: number of TSF timers available
+ */
+enum iwl_tsf_id {
+ TSF_ID_A = 0,
+ TSF_ID_B = 1,
+ TSF_ID_C = 2,
+ TSF_ID_D = 3,
+ NUM_TSF_IDS = 4,
+}; /* TSF_ID_API_E_VER_1 */
+
+/**
+ * struct iwl_mac_data_ap - configuration data for AP MAC context
+ * @beacon_time: beacon transmit time in system time
+ * @beacon_tsf: beacon transmit time in TSF
+ * @bi: beacon interval in TU
+ * @bi_reciprocal: 2^32 / bi
+ * @dtim_interval: dtim transmit time in TU
+ * @dtim_reciprocal: 2^32 / dtim_interval
+ * @mcast_qid: queue ID for multicast traffic
+ * @beacon_template: beacon template ID
+ */
+struct iwl_mac_data_ap {
+ __le32 beacon_time;
+ __le64 beacon_tsf;
+ __le32 bi;
+ __le32 bi_reciprocal;
+ __le32 dtim_interval;
+ __le32 dtim_reciprocal;
+ __le32 mcast_qid;
+ __le32 beacon_template;
+} __packed; /* AP_MAC_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_mac_data_ibss - configuration data for IBSS MAC context
+ * @beacon_time: beacon transmit time in system time
+ * @beacon_tsf: beacon transmit time in TSF
+ * @bi: beacon interval in TU
+ * @bi_reciprocal: 2^32 / bi
+ */
+struct iwl_mac_data_ibss {
+ __le32 beacon_time;
+ __le64 beacon_tsf;
+ __le32 bi;
+ __le32 bi_reciprocal;
+} __packed; /* IBSS_MAC_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_mac_data_sta - configuration data for station MAC context
+ * @is_assoc: 1 for associated state, 0 otherwise
+ * @dtim_time: DTIM arrival time in system time
+ * @dtim_tsf: DTIM arrival time in TSF
+ * @bi: beacon interval in TU, applicable only when associated
+ * @bi_reciprocal: 2^32 / bi , applicable only when associated
+ * @dtim_interval: DTIM interval in TU, applicable only when associated
+ * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated
+ * @listen_interval: in beacon intervals, applicable only when associated
+ * @assoc_id: unique ID assigned by the AP during association
+ */
+struct iwl_mac_data_sta {
+ __le32 is_assoc;
+ __le32 dtim_time;
+ __le64 dtim_tsf;
+ __le32 bi;
+ __le32 bi_reciprocal;
+ __le32 dtim_interval;
+ __le32 dtim_reciprocal;
+ __le32 listen_interval;
+ __le32 assoc_id;
+ __le32 assoc_beacon_arrive_time;
+} __packed; /* STA_MAC_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_mac_data_go - configuration data for P2P GO MAC context
+ * @ap: iwl_mac_data_ap struct with most config data
+ * @ctwin: client traffic window in TU (period after TBTT when GO is present).
+ * 0 indicates that there is no CT window.
+ * @opp_ps_enabled: indicate that opportunistic PS allowed
+ */
+struct iwl_mac_data_go {
+ struct iwl_mac_data_ap ap;
+ __le32 ctwin;
+ __le32 opp_ps_enabled;
+} __packed; /* GO_MAC_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_mac_data_p2p_sta - configuration data for P2P client MAC context
+ * @sta: iwl_mac_data_sta struct with most config data
+ * @ctwin: client traffic window in TU (period after TBTT when GO is present).
+ * 0 indicates that there is no CT window.
+ */
+struct iwl_mac_data_p2p_sta {
+ struct iwl_mac_data_sta sta;
+ __le32 ctwin;
+} __packed; /* P2P_STA_MAC_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_mac_data_pibss - Pseudo IBSS config data
+ * @stats_interval: interval in TU between statistics notifications to host.
+ */
+struct iwl_mac_data_pibss {
+ __le32 stats_interval;
+} __packed; /* PIBSS_MAC_DATA_API_S_VER_1 */
+
+/*
+ * struct iwl_mac_data_p2p_dev - configuration data for the P2P Device MAC
+ * context.
+ * @is_disc_extended: if set to true, P2P Device discoverability is enabled on
+ * other channels as well. This should be to true only in case that the
+ * device is discoverable and there is an active GO. Note that setting this
+ * field when not needed, will increase the number of interrupts and have
+ * effect on the platform power, as this setting opens the Rx filters on
+ * all macs.
+ */
+struct iwl_mac_data_p2p_dev {
+ __le32 is_disc_extended;
+} __packed; /* _P2P_DEV_MAC_DATA_API_S_VER_1 */
+
+/**
+ * enum iwl_mac_filter_flags - MAC context filter flags
+ * @MAC_FILTER_IN_PROMISC: accept all data frames
+ * @MAC_FILTER_IN_CONTROL_AND_MGMT: pass all mangement and
+ * control frames to the host
+ * @MAC_FILTER_ACCEPT_GRP: accept multicast frames
+ * @MAC_FILTER_DIS_DECRYPT: don't decrypt unicast frames
+ * @MAC_FILTER_DIS_GRP_DECRYPT: don't decrypt multicast frames
+ * @MAC_FILTER_IN_BEACON: transfer foreign BSS's beacons to host
+ * (in station mode when associated)
+ * @MAC_FILTER_OUT_BCAST: filter out all broadcast frames
+ * @MAC_FILTER_IN_CRC32: extract FCS and append it to frames
+ * @MAC_FILTER_IN_PROBE_REQUEST: pass probe requests to host
+ */
+enum iwl_mac_filter_flags {
+ MAC_FILTER_IN_PROMISC = BIT(0),
+ MAC_FILTER_IN_CONTROL_AND_MGMT = BIT(1),
+ MAC_FILTER_ACCEPT_GRP = BIT(2),
+ MAC_FILTER_DIS_DECRYPT = BIT(3),
+ MAC_FILTER_DIS_GRP_DECRYPT = BIT(4),
+ MAC_FILTER_IN_BEACON = BIT(6),
+ MAC_FILTER_OUT_BCAST = BIT(8),
+ MAC_FILTER_IN_CRC32 = BIT(11),
+ MAC_FILTER_IN_PROBE_REQUEST = BIT(12),
+};
+
+/**
+ * enum iwl_mac_qos_flags - QoS flags
+ * @MAC_QOS_FLG_UPDATE_EDCA: ?
+ * @MAC_QOS_FLG_TGN: HT is enabled
+ * @MAC_QOS_FLG_TXOP_TYPE: ?
+ *
+ */
+enum iwl_mac_qos_flags {
+ MAC_QOS_FLG_UPDATE_EDCA = BIT(0),
+ MAC_QOS_FLG_TGN = BIT(1),
+ MAC_QOS_FLG_TXOP_TYPE = BIT(4),
+};
+
+/**
+ * struct iwl_ac_qos - QOS timing params for MAC_CONTEXT_CMD
+ * @cw_min: Contention window, start value in numbers of slots.
+ * Should be a power-of-2, minus 1. Device's default is 0x0f.
+ * @cw_max: Contention window, max value in numbers of slots.
+ * Should be a power-of-2, minus 1. Device's default is 0x3f.
+ * @aifsn: Number of slots in Arbitration Interframe Space (before
+ * performing random backoff timing prior to Tx). Device default 1.
+ * @fifos_mask: FIFOs used by this MAC for this AC
+ * @edca_txop: Length of Tx opportunity, in uSecs. Device default is 0.
+ *
+ * One instance of this config struct for each of 4 EDCA access categories
+ * in struct iwl_qosparam_cmd.
+ *
+ * Device will automatically increase contention window by (2*CW) + 1 for each
+ * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW
+ * value, to cap the CW value.
+ */
+struct iwl_ac_qos {
+ __le16 cw_min;
+ __le16 cw_max;
+ u8 aifsn;
+ u8 fifos_mask;
+ __le16 edca_txop;
+} __packed; /* AC_QOS_API_S_VER_2 */
+
+/**
+ * struct iwl_mac_ctx_cmd - command structure to configure MAC contexts
+ * ( MAC_CONTEXT_CMD = 0x28 )
+ * @id_and_color: ID and color of the MAC
+ * @action: action to perform, one of FW_CTXT_ACTION_*
+ * @mac_type: one of FW_MAC_TYPE_*
+ * @tsd_id: TSF HW timer, one of TSF_ID_*
+ * @node_addr: MAC address
+ * @bssid_addr: BSSID
+ * @cck_rates: basic rates available for CCK
+ * @ofdm_rates: basic rates available for OFDM
+ * @protection_flags: combination of MAC_PROT_FLG_FLAG_*
+ * @cck_short_preamble: 0x20 for enabling short preamble, 0 otherwise
+ * @short_slot: 0x10 for enabling short slots, 0 otherwise
+ * @filter_flags: combination of MAC_FILTER_*
+ * @qos_flags: from MAC_QOS_FLG_*
+ * @ac: one iwl_mac_qos configuration for each AC
+ * @mac_specific: one of struct iwl_mac_data_*, according to mac_type
+ */
+struct iwl_mac_ctx_cmd {
+ /* COMMON_INDEX_HDR_API_S_VER_1 */
+ __le32 id_and_color;
+ __le32 action;
+ /* MAC_CONTEXT_COMMON_DATA_API_S_VER_1 */
+ __le32 mac_type;
+ __le32 tsf_id;
+ u8 node_addr[6];
+ __le16 reserved_for_node_addr;
+ u8 bssid_addr[6];
+ __le16 reserved_for_bssid_addr;
+ __le32 cck_rates;
+ __le32 ofdm_rates;
+ __le32 protection_flags;
+ __le32 cck_short_preamble;
+ __le32 short_slot;
+ __le32 filter_flags;
+ /* MAC_QOS_PARAM_API_S_VER_1 */
+ __le32 qos_flags;
+ struct iwl_ac_qos ac[AC_NUM+1];
+ /* MAC_CONTEXT_COMMON_DATA_API_S */
+ union {
+ struct iwl_mac_data_ap ap;
+ struct iwl_mac_data_go go;
+ struct iwl_mac_data_sta sta;
+ struct iwl_mac_data_p2p_sta p2p_sta;
+ struct iwl_mac_data_p2p_dev p2p_dev;
+ struct iwl_mac_data_pibss pibss;
+ struct iwl_mac_data_ibss ibss;
+ };
+} __packed; /* MAC_CONTEXT_CMD_API_S_VER_1 */
+
+static inline u32 iwl_mvm_reciprocal(u32 v)
+{
+ if (!v)
+ return 0;
+ return 0xFFFFFFFF / v;
+}
+
+#endif /* __fw_api_mac_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
new file mode 100644
index 000000000000..be36b7604b7f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 __fw_api_power_h__
+#define __fw_api_power_h__
+
+/* Power Management Commands, Responses, Notifications */
+
+/**
+ * enum iwl_scan_flags - masks for power table command flags
+ * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management,
+ * '1' Driver enables PM (use rest of parameters)
+ * @POWER_FLAGS_SLEEP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM,
+ * '1' PM could sleep over DTIM till listen Interval.
+ * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
+ * @POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all
+ * access categories are both delivery and trigger enabled.
+ * @POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and
+ * PBW Snoozing enabled
+ * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask
+*/
+enum iwl_power_flags {
+ POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(0),
+ POWER_FLAGS_SLEEP_OVER_DTIM_MSK = BIT(1),
+ POWER_FLAGS_LPRX_ENA_MSK = BIT(2),
+ POWER_FLAGS_SNOOZE_ENA_MSK = BIT(3),
+ POWER_FLAGS_BT_SCO_ENA = BIT(4),
+ POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(5)
+};
+
+/**
+ * struct iwl_powertable_cmd - Power Table Command
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * @id_and_color: MAC contex identifier
+ * @action: Action on context - no action, add new,
+ * modify existent, remove
+ * @flags: Power table command flags from POWER_FLAGS_*
+ * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec.
+ * Minimum allowed:- 3 * DTIM
+ * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to
+ * PSM transition - legacy PM
+ * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to
+ * PSM transition - legacy PM
+ * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to
+ * PSM transition - uAPSD
+ * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to
+ * PSM transition - uAPSD
+ * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled.
+ * Default: 80dbm
+ * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set
+ * @snooze_interval: TBD
+ * @snooze_window: TBD
+ * @snooze_step: TBD
+ * @qndp_tid: TBD
+ * @uapsd_ac_flags: TBD
+ * @uapsd_max_sp: TBD
+ */
+struct iwl_powertable_cmd {
+ /* COMMON_INDEX_HDR_API_S_VER_1 */
+ __le32 id_and_color;
+ __le32 action;
+ __le16 flags;
+ u8 reserved;
+ __le16 keep_alive_seconds;
+ __le32 rx_data_timeout;
+ __le32 tx_data_timeout;
+ __le32 rx_data_timeout_uapsd;
+ __le32 tx_data_timeout_uapsd;
+ u8 lprx_rssi_threshold;
+ u8 num_skip_dtim;
+ __le16 snooze_interval;
+ __le16 snooze_window;
+ u8 snooze_step;
+ u8 qndp_tid;
+ u8 uapsd_ac_flags;
+ u8 uapsd_max_sp;
+} __packed;
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
new file mode 100644
index 000000000000..aa3474d08231
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
@@ -0,0 +1,312 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 __fw_api_rs_h__
+#define __fw_api_rs_h__
+
+#include "fw-api-mac.h"
+
+/*
+ * These serve as indexes into
+ * struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT];
+ */
+enum {
+ IWL_RATE_1M_INDEX = 0,
+ IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
+ IWL_RATE_2M_INDEX,
+ IWL_RATE_5M_INDEX,
+ IWL_RATE_11M_INDEX,
+ IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
+ IWL_RATE_6M_INDEX,
+ IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
+ IWL_RATE_9M_INDEX,
+ IWL_RATE_12M_INDEX,
+ IWL_RATE_18M_INDEX,
+ IWL_RATE_24M_INDEX,
+ IWL_RATE_36M_INDEX,
+ IWL_RATE_48M_INDEX,
+ IWL_RATE_54M_INDEX,
+ IWL_LAST_NON_HT_RATE = IWL_RATE_54M_INDEX,
+ IWL_RATE_60M_INDEX,
+ IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
+ IWL_RATE_COUNT_LEGACY = IWL_LAST_NON_HT_RATE + 1,
+ IWL_RATE_COUNT,
+};
+
+#define IWL_RATE_BIT_MSK(r) BIT(IWL_RATE_##r##M_INDEX)
+
+/* fw API values for legacy bit rates, both OFDM and CCK */
+enum {
+ IWL_RATE_6M_PLCP = 13,
+ IWL_RATE_9M_PLCP = 15,
+ IWL_RATE_12M_PLCP = 5,
+ IWL_RATE_18M_PLCP = 7,
+ IWL_RATE_24M_PLCP = 9,
+ IWL_RATE_36M_PLCP = 11,
+ IWL_RATE_48M_PLCP = 1,
+ IWL_RATE_54M_PLCP = 3,
+ IWL_RATE_1M_PLCP = 10,
+ IWL_RATE_2M_PLCP = 20,
+ IWL_RATE_5M_PLCP = 55,
+ IWL_RATE_11M_PLCP = 110,
+};
+
+/*
+ * rate_n_flags bit fields
+ *
+ * The 32-bit value has different layouts in the low 8 bites depending on the
+ * format. There are three formats, HT, VHT and legacy (11abg, with subformats
+ * for CCK and OFDM).
+ *
+ * High-throughput (HT) rate format
+ * bit 8 is 1, bit 26 is 0, bit 9 is 0 (OFDM)
+ * Very High-throughput (VHT) rate format
+ * bit 8 is 0, bit 26 is 1, bit 9 is 0 (OFDM)
+ * Legacy OFDM rate format for bits 7:0
+ * bit 8 is 0, bit 26 is 0, bit 9 is 0 (OFDM)
+ * Legacy CCK rate format for bits 7:0:
+ * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK)
+ */
+
+/* Bit 8: (1) HT format, (0) legacy or VHT format */
+#define RATE_MCS_HT_POS 8
+#define RATE_MCS_HT_MSK (1 << RATE_MCS_HT_POS)
+
+/* Bit 9: (1) CCK, (0) OFDM. HT (bit 8) must be "0" for this bit to be valid */
+#define RATE_MCS_CCK_POS 9
+#define RATE_MCS_CCK_MSK (1 << RATE_MCS_CCK_POS)
+
+/* Bit 26: (1) VHT format, (0) legacy format in bits 8:0 */
+#define RATE_MCS_VHT_POS 26
+#define RATE_MCS_VHT_MSK (1 << RATE_MCS_VHT_POS)
+
+
+/*
+ * High-throughput (HT) rate format for bits 7:0
+ *
+ * 2-0: MCS rate base
+ * 0) 6 Mbps
+ * 1) 12 Mbps
+ * 2) 18 Mbps
+ * 3) 24 Mbps
+ * 4) 36 Mbps
+ * 5) 48 Mbps
+ * 6) 54 Mbps
+ * 7) 60 Mbps
+ * 4-3: 0) Single stream (SISO)
+ * 1) Dual stream (MIMO)
+ * 2) Triple stream (MIMO)
+ * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data
+ * (bits 7-6 are zero)
+ *
+ * Together the low 5 bits work out to the MCS index because we don't
+ * support MCSes above 15/23, and 0-7 have one stream, 8-15 have two
+ * streams and 16-23 have three streams. We could also support MCS 32
+ * which is the duplicate 20 MHz MCS (bit 5 set, all others zero.)
+ */
+#define RATE_HT_MCS_RATE_CODE_MSK 0x7
+
+/* Bit 10: (1) Use Green Field preamble */
+#define RATE_HT_MCS_GF_POS 10
+#define RATE_HT_MCS_GF_MSK (1 << RATE_HT_MCS_GF_POS)
+
+#define RATE_HT_MCS_INDEX_MSK 0x3f
+
+/*
+ * Very High-throughput (VHT) rate format for bits 7:0
+ *
+ * 3-0: VHT MCS (0-9)
+ * 5-4: number of streams - 1:
+ * 0) Single stream (SISO)
+ * 1) Dual stream (MIMO)
+ * 2) Triple stream (MIMO)
+ */
+
+/* Bit 4-5: (0) SISO, (1) MIMO2 (2) MIMO3 */
+#define RATE_VHT_MCS_RATE_CODE_MSK 0xf
+#define RATE_VHT_MCS_NSS_POS 4
+#define RATE_VHT_MCS_NSS_MSK (3 << RATE_VHT_MCS_NSS_POS)
+
+/*
+ * Legacy OFDM rate format for bits 7:0
+ *
+ * 3-0: 0xD) 6 Mbps
+ * 0xF) 9 Mbps
+ * 0x5) 12 Mbps
+ * 0x7) 18 Mbps
+ * 0x9) 24 Mbps
+ * 0xB) 36 Mbps
+ * 0x1) 48 Mbps
+ * 0x3) 54 Mbps
+ * (bits 7-4 are 0)
+ *
+ * Legacy CCK rate format for bits 7:0:
+ * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK):
+ *
+ * 6-0: 10) 1 Mbps
+ * 20) 2 Mbps
+ * 55) 5.5 Mbps
+ * 110) 11 Mbps
+ * (bit 7 is 0)
+ */
+#define RATE_LEGACY_RATE_MSK 0xff
+
+
+/*
+ * Bit 11-12: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz
+ * 0 and 1 are valid for HT and VHT, 2 and 3 only for VHT
+ */
+#define RATE_MCS_CHAN_WIDTH_POS 11
+#define RATE_MCS_CHAN_WIDTH_MSK (3 << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_20 (0 << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_40 (1 << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_80 (2 << RATE_MCS_CHAN_WIDTH_POS)
+#define RATE_MCS_CHAN_WIDTH_160 (3 << RATE_MCS_CHAN_WIDTH_POS)
+
+/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
+#define RATE_MCS_SGI_POS 13
+#define RATE_MCS_SGI_MSK (1 << RATE_MCS_SGI_POS)
+
+/* Bit 14-16: Antenna selection (1) Ant A, (2) Ant B, (4) Ant C */
+#define RATE_MCS_ANT_POS 14
+#define RATE_MCS_ANT_A_MSK (1 << RATE_MCS_ANT_POS)
+#define RATE_MCS_ANT_B_MSK (2 << RATE_MCS_ANT_POS)
+#define RATE_MCS_ANT_C_MSK (4 << RATE_MCS_ANT_POS)
+#define RATE_MCS_ANT_AB_MSK (RATE_MCS_ANT_A_MSK | \
+ RATE_MCS_ANT_B_MSK)
+#define RATE_MCS_ANT_ABC_MSK (RATE_MCS_ANT_AB_MSK | \
+ RATE_MCS_ANT_C_MSK)
+#define RATE_MCS_ANT_MSK RATE_MCS_ANT_ABC_MSK
+#define RATE_MCS_ANT_NUM 3
+
+/* Bit 17-18: (0) SS, (1) SS*2 */
+#define RATE_MCS_STBC_POS 17
+#define RATE_MCS_STBC_MSK (1 << RATE_MCS_STBC_POS)
+
+/* Bit 19: (0) Beamforming is off, (1) Beamforming is on */
+#define RATE_MCS_BF_POS 19
+#define RATE_MCS_BF_MSK (1 << RATE_MCS_BF_POS)
+
+/* Bit 20: (0) ZLF is off, (1) ZLF is on */
+#define RATE_MCS_ZLF_POS 20
+#define RATE_MCS_ZLF_MSK (1 << RATE_MCS_ZLF_POS)
+
+/* Bit 24-25: (0) 20MHz (no dup), (1) 2x20MHz, (2) 4x20MHz, 3 8x20MHz */
+#define RATE_MCS_DUP_POS 24
+#define RATE_MCS_DUP_MSK (3 << RATE_MCS_DUP_POS)
+
+/* Bit 27: (1) LDPC enabled, (0) LDPC disabled */
+#define RATE_MCS_LDPC_POS 27
+#define RATE_MCS_LDPC_MSK (1 << RATE_MCS_LDPC_POS)
+
+
+/* Link Quality definitions */
+
+/* # entries in rate scale table to support Tx retries */
+#define LQ_MAX_RETRY_NUM 16
+
+/* Link quality command flags, only this one is available */
+#define LQ_FLAG_SET_STA_TLC_RTS_MSK BIT(0)
+
+/**
+ * struct iwl_lq_cmd - link quality command
+ * @sta_id: station to update
+ * @control: not used
+ * @flags: combination of LQ_FLAG_*
+ * @mimo_delim: the first SISO index in rs_table, which separates MIMO
+ * and SISO rates
+ * @single_stream_ant_msk: best antenna for SISO (can be dual in CDD).
+ * Should be ANT_[ABC]
+ * @dual_stream_ant_msk: best antennas for MIMO, combination of ANT_[ABC]
+ * @initial_rate_index: first index from rs_table per AC category
+ * @agg_time_limit: aggregation max time threshold in usec/100, meaning
+ * value of 100 is one usec. Range is 100 to 8000
+ * @agg_disable_start_th: try-count threshold for starting aggregation.
+ * If a frame has higher try-count, it should not be selected for
+ * starting an aggregation sequence.
+ * @agg_frame_cnt_limit: max frame count in an aggregation.
+ * 0: no limit
+ * 1: no aggregation (one frame per aggregation)
+ * 2 - 0x3f: maximal number of frames (up to 3f == 63)
+ * @rs_table: array of rates for each TX try, each is rate_n_flags,
+ * meaning it is a combination of RATE_MCS_* and IWL_RATE_*_PLCP
+ * @bf_params: beam forming params, currently not used
+ */
+struct iwl_lq_cmd {
+ u8 sta_id;
+ u8 reserved1;
+ u16 control;
+ /* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */
+ u8 flags;
+ u8 mimo_delim;
+ u8 single_stream_ant_msk;
+ u8 dual_stream_ant_msk;
+ u8 initial_rate_index[AC_NUM];
+ /* LINK_QUAL_AGG_PARAMS_API_S_VER_1 */
+ __le16 agg_time_limit;
+ u8 agg_disable_start_th;
+ u8 agg_frame_cnt_limit;
+ __le32 reserved2;
+ __le32 rs_table[LQ_MAX_RETRY_NUM];
+ __le32 bf_params;
+}; /* LINK_QUALITY_CMD_API_S_VER_1 */
+#endif /* __fw_api_rs_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
new file mode 100644
index 000000000000..670ac8f95e26
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -0,0 +1,561 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 __fw_api_scan_h__
+#define __fw_api_scan_h__
+
+#include "fw-api.h"
+
+/* Scan Commands, Responses, Notifications */
+
+/* Masks for iwl_scan_channel.type flags */
+#define SCAN_CHANNEL_TYPE_PASSIVE 0
+#define SCAN_CHANNEL_TYPE_ACTIVE BIT(0)
+#define SCAN_CHANNEL_NARROW_BAND BIT(22)
+
+/* Max number of IEs for direct SSID scans in a command */
+#define PROBE_OPTION_MAX 20
+
+/**
+ * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
+ * @channel: band is selected by iwl_scan_cmd "flags" field
+ * @tx_gain: gain for analog radio
+ * @dsp_atten: gain for DSP
+ * @active_dwell: dwell time for active scan in TU, typically 5-50
+ * @passive_dwell: dwell time for passive scan in TU, typically 20-500
+ * @type: type is broken down to these bits:
+ * bit 0: 0 = passive, 1 = active
+ * bits 1-20: SSID direct bit map. If any of these bits is set then
+ * the corresponding SSID IE is transmitted in probe request
+ * (bit i adds IE in position i to the probe request)
+ * bit 22: channel width, 0 = regular, 1 = TGj narrow channel
+ *
+ * @iteration_count:
+ * @iteration_interval:
+ * This struct is used once for each channel in the scan list.
+ * Each channel can independently select:
+ * 1) SSID for directed active scans
+ * 2) Txpower setting (for rate specified within Tx command)
+ * 3) How long to stay on-channel (behavior may be modified by quiet_time,
+ * quiet_plcp_th, good_CRC_th)
+ *
+ * To avoid uCode errors, make sure the following are true (see comments
+ * under struct iwl_scan_cmd about max_out_time and quiet_time):
+ * 1) If using passive_dwell (i.e. passive_dwell != 0):
+ * active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
+ * 2) quiet_time <= active_dwell
+ * 3) If restricting off-channel time (i.e. max_out_time !=0):
+ * passive_dwell < max_out_time
+ * active_dwell < max_out_time
+ */
+struct iwl_scan_channel {
+ __le32 type;
+ __le16 channel;
+ __le16 iteration_count;
+ __le32 iteration_interval;
+ __le16 active_dwell;
+ __le16 passive_dwell;
+} __packed; /* SCAN_CHANNEL_CONTROL_API_S_VER_1 */
+
+/**
+ * struct iwl_ssid_ie - directed scan network information element
+ *
+ * Up to 20 of these may appear in REPLY_SCAN_CMD,
+ * selected by "type" bit field in struct iwl_scan_channel;
+ * each channel may select different ssids from among the 20 entries.
+ * SSID IEs get transmitted in reverse order of entry.
+ */
+struct iwl_ssid_ie {
+ u8 id;
+ u8 len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+} __packed; /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */
+
+/**
+ * iwl_scan_flags - masks for scan command flags
+ *@SCAN_FLAGS_PERIODIC_SCAN:
+ *@SCAN_FLAGS_P2P_PUBLIC_ACTION_FRAME_TX:
+ *@SCAN_FLAGS_DELAYED_SCAN_LOWBAND:
+ *@SCAN_FLAGS_DELAYED_SCAN_HIGHBAND:
+ *@SCAN_FLAGS_FRAGMENTED_SCAN:
+ */
+enum iwl_scan_flags {
+ SCAN_FLAGS_PERIODIC_SCAN = BIT(0),
+ SCAN_FLAGS_P2P_PUBLIC_ACTION_FRAME_TX = BIT(1),
+ SCAN_FLAGS_DELAYED_SCAN_LOWBAND = BIT(2),
+ SCAN_FLAGS_DELAYED_SCAN_HIGHBAND = BIT(3),
+ SCAN_FLAGS_FRAGMENTED_SCAN = BIT(4),
+};
+
+/**
+ * enum iwl_scan_type - Scan types for scan command
+ * @SCAN_TYPE_FORCED:
+ * @SCAN_TYPE_BACKGROUND:
+ * @SCAN_TYPE_OS:
+ * @SCAN_TYPE_ROAMING:
+ * @SCAN_TYPE_ACTION:
+ * @SCAN_TYPE_DISCOVERY:
+ * @SCAN_TYPE_DISCOVERY_FORCED:
+ */
+enum iwl_scan_type {
+ SCAN_TYPE_FORCED = 0,
+ SCAN_TYPE_BACKGROUND = 1,
+ SCAN_TYPE_OS = 2,
+ SCAN_TYPE_ROAMING = 3,
+ SCAN_TYPE_ACTION = 4,
+ SCAN_TYPE_DISCOVERY = 5,
+ SCAN_TYPE_DISCOVERY_FORCED = 6,
+}; /* SCAN_ACTIVITY_TYPE_E_VER_1 */
+
+/* Maximal number of channels to scan */
+#define MAX_NUM_SCAN_CHANNELS 0x24
+
+/**
+ * struct iwl_scan_cmd - scan request command
+ * ( SCAN_REQUEST_CMD = 0x80 )
+ * @len: command length in bytes
+ * @scan_flags: scan flags from SCAN_FLAGS_*
+ * @channel_count: num of channels in channel list (1 - MAX_NUM_SCAN_CHANNELS)
+ * @quiet_time: in msecs, dwell this time for active scan on quiet channels
+ * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than
+ * this number of packets were received (typically 1)
+ * @passive2active: is auto switching from passive to active allowed (0 or 1)
+ * @rxchain_sel_flags: RXON_RX_CHAIN_*
+ * @max_out_time: in usecs, max out of serving channel time
+ * @suspend_time: how long to pause scan when returning to service channel:
+ * bits 0-19: beacon interal in usecs (suspend before executing)
+ * bits 20-23: reserved
+ * bits 24-31: number of beacons (suspend between channels)
+ * @rxon_flags: RXON_FLG_*
+ * @filter_flags: RXON_FILTER_*
+ * @tx_cmd: for active scans (zero for passive), w/o payload,
+ * no RS so specify TX rate
+ * @direct_scan: direct scan SSIDs
+ * @type: one of SCAN_TYPE_*
+ * @repeats: how many time to repeat the scan
+ */
+struct iwl_scan_cmd {
+ __le16 len;
+ u8 scan_flags;
+ u8 channel_count;
+ __le16 quiet_time;
+ __le16 quiet_plcp_th;
+ __le16 passive2active;
+ __le16 rxchain_sel_flags;
+ __le32 max_out_time;
+ __le32 suspend_time;
+ /* RX_ON_FLAGS_API_S_VER_1 */
+ __le32 rxon_flags;
+ __le32 filter_flags;
+ struct iwl_tx_cmd tx_cmd;
+ struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
+ __le32 type;
+ __le32 repeats;
+
+ /*
+ * 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 iwl_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; /* SCAN_REQUEST_FIXED_PART_API_S_VER_5 */
+
+/* Response to scan request contains only status with one of these values */
+#define SCAN_RESPONSE_OK 0x1
+#define SCAN_RESPONSE_ERROR 0x2
+
+/*
+ * SCAN_ABORT_CMD = 0x81
+ * When scan abort is requested, the command has no fields except the common
+ * header. The response contains only a status with one of these values.
+ */
+#define SCAN_ABORT_POSSIBLE 0x1
+#define SCAN_ABORT_IGNORED 0x2 /* no pending scans */
+
+/* TODO: complete documentation */
+#define SCAN_OWNER_STATUS 0x1
+#define MEASURE_OWNER_STATUS 0x2
+
+/**
+ * struct iwl_scan_start_notif - notifies start of scan in the device
+ * ( SCAN_START_NOTIFICATION = 0x82 )
+ * @tsf_low: TSF timer (lower half) in usecs
+ * @tsf_high: TSF timer (higher half) in usecs
+ * @beacon_timer: structured as follows:
+ * bits 0:19 - beacon interval in usecs
+ * bits 20:23 - reserved (0)
+ * bits 24:31 - number of beacons
+ * @channel: which channel is scanned
+ * @band: 0 for 5.2 GHz, 1 for 2.4 GHz
+ * @status: one of *_OWNER_STATUS
+ */
+struct iwl_scan_start_notif {
+ __le32 tsf_low;
+ __le32 tsf_high;
+ __le32 beacon_timer;
+ u8 channel;
+ u8 band;
+ u8 reserved[2];
+ __le32 status;
+} __packed; /* SCAN_START_NTF_API_S_VER_1 */
+
+/* scan results probe_status first bit indicates success */
+#define SCAN_PROBE_STATUS_OK 0
+#define SCAN_PROBE_STATUS_TX_FAILED BIT(0)
+/* error statuses combined with TX_FAILED */
+#define SCAN_PROBE_STATUS_FAIL_TTL BIT(1)
+#define SCAN_PROBE_STATUS_FAIL_BT BIT(2)
+
+/* How many statistics are gathered for each channel */
+#define SCAN_RESULTS_STATISTICS 1
+
+/**
+ * enum iwl_scan_complete_status - status codes for scan complete notifications
+ * @SCAN_COMP_STATUS_OK: scan completed successfully
+ * @SCAN_COMP_STATUS_ABORT: scan was aborted by user
+ * @SCAN_COMP_STATUS_ERR_SLEEP: sending null sleep packet failed
+ * @SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT: timeout before channel is ready
+ * @SCAN_COMP_STATUS_ERR_PROBE: sending probe request failed
+ * @SCAN_COMP_STATUS_ERR_WAKEUP: sending null wakeup packet failed
+ * @SCAN_COMP_STATUS_ERR_ANTENNAS: invalid antennas chosen at scan command
+ * @SCAN_COMP_STATUS_ERR_INTERNAL: internal error caused scan abort
+ * @SCAN_COMP_STATUS_ERR_COEX: medium was lost ot WiMax
+ * @SCAN_COMP_STATUS_P2P_ACTION_OK: P2P public action frame TX was successful
+ * (not an error!)
+ * @SCAN_COMP_STATUS_ITERATION_END: indicates end of one repeatition the driver
+ * asked for
+ * @SCAN_COMP_STATUS_ERR_ALLOC_TE: scan could not allocate time events
+*/
+enum iwl_scan_complete_status {
+ SCAN_COMP_STATUS_OK = 0x1,
+ SCAN_COMP_STATUS_ABORT = 0x2,
+ SCAN_COMP_STATUS_ERR_SLEEP = 0x3,
+ SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT = 0x4,
+ SCAN_COMP_STATUS_ERR_PROBE = 0x5,
+ SCAN_COMP_STATUS_ERR_WAKEUP = 0x6,
+ SCAN_COMP_STATUS_ERR_ANTENNAS = 0x7,
+ SCAN_COMP_STATUS_ERR_INTERNAL = 0x8,
+ SCAN_COMP_STATUS_ERR_COEX = 0x9,
+ SCAN_COMP_STATUS_P2P_ACTION_OK = 0xA,
+ SCAN_COMP_STATUS_ITERATION_END = 0x0B,
+ SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C,
+};
+
+/**
+ * struct iwl_scan_results_notif - scan results for one channel
+ * ( SCAN_RESULTS_NOTIFICATION = 0x83 )
+ * @channel: which channel the results are from
+ * @band: 0 for 5.2 GHz, 1 for 2.4 GHz
+ * @probe_status: SCAN_PROBE_STATUS_*, indicates success of probe request
+ * @num_probe_not_sent: # of request that weren't sent due to not enough time
+ * @duration: duration spent in channel, in usecs
+ * @statistics: statistics gathered for this channel
+ */
+struct iwl_scan_results_notif {
+ u8 channel;
+ u8 band;
+ u8 probe_status;
+ u8 num_probe_not_sent;
+ __le32 duration;
+ __le32 statistics[SCAN_RESULTS_STATISTICS];
+} __packed; /* SCAN_RESULT_NTF_API_S_VER_2 */
+
+/**
+ * struct iwl_scan_complete_notif - notifies end of scanning (all channels)
+ * ( SCAN_COMPLETE_NOTIFICATION = 0x84 )
+ * @scanned_channels: number of channels scanned (and number of valid results)
+ * @status: one of SCAN_COMP_STATUS_*
+ * @bt_status: BT on/off status
+ * @last_channel: last channel that was scanned
+ * @tsf_low: TSF timer (lower half) in usecs
+ * @tsf_high: TSF timer (higher half) in usecs
+ * @results: all scan results, only "scanned_channels" of them are valid
+ */
+struct iwl_scan_complete_notif {
+ u8 scanned_channels;
+ u8 status;
+ u8 bt_status;
+ u8 last_channel;
+ __le32 tsf_low;
+ __le32 tsf_high;
+ struct iwl_scan_results_notif results[MAX_NUM_SCAN_CHANNELS];
+} __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */
+
+/* scan offload */
+#define IWL_MAX_SCAN_CHANNELS 40
+#define IWL_SCAN_MAX_BLACKLIST_LEN 64
+#define IWL_SCAN_MAX_PROFILES 11
+#define SCAN_OFFLOAD_PROBE_REQ_SIZE 512
+
+/* Default watchdog (in MS) for scheduled scan iteration */
+#define IWL_SCHED_SCAN_WATCHDOG cpu_to_le16(15000)
+
+#define IWL_GOOD_CRC_TH_DEFAULT cpu_to_le16(1)
+#define CAN_ABORT_STATUS 1
+
+#define IWL_FULL_SCAN_MULTIPLIER 5
+#define IWL_FAST_SCHED_SCAN_ITERATIONS 3
+
+/**
+ * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6
+ * @scan_flags: see enum iwl_scan_flags
+ * @channel_count: channels in channel list
+ * @quiet_time: dwell time, in milisiconds, on quiet channel
+ * @quiet_plcp_th: quiet channel num of packets threshold
+ * @good_CRC_th: passive to active promotion threshold
+ * @rx_chain: RXON rx chain.
+ * @max_out_time: max uSec to be out of assoceated channel
+ * @suspend_time: pause scan this long when returning to service channel
+ * @flags: RXON flags
+ * @filter_flags: RXONfilter
+ * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz.
+ * @direct_scan: list of SSIDs for directed active scan
+ * @scan_type: see enum iwl_scan_type.
+ * @rep_count: repetition count for each scheduled scan iteration.
+ */
+struct iwl_scan_offload_cmd {
+ __le16 len;
+ u8 scan_flags;
+ u8 channel_count;
+ __le16 quiet_time;
+ __le16 quiet_plcp_th;
+ __le16 good_CRC_th;
+ __le16 rx_chain;
+ __le32 max_out_time;
+ __le32 suspend_time;
+ /* RX_ON_FLAGS_API_S_VER_1 */
+ __le32 flags;
+ __le32 filter_flags;
+ struct iwl_tx_cmd tx_cmd[2];
+ /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */
+ struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
+ __le32 scan_type;
+ __le32 rep_count;
+} __packed;
+
+enum iwl_scan_offload_channel_flags {
+ IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE = BIT(0),
+ IWL_SCAN_OFFLOAD_CHANNEL_NARROW = BIT(22),
+ IWL_SCAN_OFFLOAD_CHANNEL_FULL = BIT(24),
+ IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL = BIT(25),
+};
+
+/**
+ * iwl_scan_channel_cfg - SCAN_CHANNEL_CFG_S
+ * @type: bitmap - see enum iwl_scan_offload_channel_flags.
+ * 0: passive (0) or active (1) scan.
+ * 1-20: directed scan to i'th ssid.
+ * 22: channel width configuation - 1 for narrow.
+ * 24: full scan.
+ * 25: partial scan.
+ * @channel_number: channel number 1-13 etc.
+ * @iter_count: repetition count for the channel.
+ * @iter_interval: interval between two innteration on one channel.
+ * @dwell_time: entry 0 - active scan, entry 1 - passive scan.
+ */
+struct iwl_scan_channel_cfg {
+ __le32 type[IWL_MAX_SCAN_CHANNELS];
+ __le16 channel_number[IWL_MAX_SCAN_CHANNELS];
+ __le16 iter_count[IWL_MAX_SCAN_CHANNELS];
+ __le32 iter_interval[IWL_MAX_SCAN_CHANNELS];
+ u8 dwell_time[IWL_MAX_SCAN_CHANNELS][2];
+} __packed;
+
+/**
+ * iwl_scan_offload_cfg - SCAN_OFFLOAD_CONFIG_API_S
+ * @scan_cmd: scan command fixed part
+ * @channel_cfg: scan channel configuration
+ * @data: probe request frames (one per band)
+ */
+struct iwl_scan_offload_cfg {
+ struct iwl_scan_offload_cmd scan_cmd;
+ struct iwl_scan_channel_cfg channel_cfg;
+ u8 data[0];
+} __packed;
+
+/**
+ * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S
+ * @ssid: MAC address to filter out
+ * @reported_rssi: AP rssi reported to the host
+ */
+struct iwl_scan_offload_blacklist {
+ u8 ssid[ETH_ALEN];
+ u8 reported_rssi;
+ u8 reserved;
+} __packed;
+
+enum iwl_scan_offload_network_type {
+ IWL_NETWORK_TYPE_BSS = 1,
+ IWL_NETWORK_TYPE_IBSS = 2,
+ IWL_NETWORK_TYPE_ANY = 3,
+};
+
+enum iwl_scan_offload_band_selection {
+ IWL_SCAN_OFFLOAD_SELECT_2_4 = 0x4,
+ IWL_SCAN_OFFLOAD_SELECT_5_2 = 0x8,
+ IWL_SCAN_OFFLOAD_SELECT_ANY = 0xc,
+};
+
+/**
+ * iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S
+ * @ssid_index: index to ssid list in fixed part
+ * @unicast_cipher: encryption olgorithm to match - bitmap
+ * @aut_alg: authentication olgorithm to match - bitmap
+ * @network_type: enum iwl_scan_offload_network_type
+ * @band_selection: enum iwl_scan_offload_band_selection
+ */
+struct iwl_scan_offload_profile {
+ u8 ssid_index;
+ u8 unicast_cipher;
+ u8 auth_alg;
+ u8 network_type;
+ u8 band_selection;
+ u8 reserved[3];
+} __packed;
+
+/**
+ * iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1
+ * @blaclist: AP list to filter off from scan results
+ * @profiles: profiles to search for match
+ * @blacklist_len: length of blacklist
+ * @num_profiles: num of profiles in the list
+ */
+struct iwl_scan_offload_profile_cfg {
+ struct iwl_scan_offload_blacklist blacklist[IWL_SCAN_MAX_BLACKLIST_LEN];
+ struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES];
+ u8 blacklist_len;
+ u8 num_profiles;
+ u8 reserved[2];
+} __packed;
+
+/**
+ * iwl_scan_offload_schedule - schedule of scan offload
+ * @delay: delay between iterations, in seconds.
+ * @iterations: num of scan iterations
+ * @full_scan_mul: number of partial scans before each full scan
+ */
+struct iwl_scan_offload_schedule {
+ u16 delay;
+ u8 iterations;
+ u8 full_scan_mul;
+} __packed;
+
+/*
+ * iwl_scan_offload_flags
+ *
+ * IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID: filter mode - upload every beacon or match
+ * ssid list.
+ * IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL: add cached channels to partial scan.
+ * IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN: use energy based scan before partial scan
+ * on A band.
+ */
+enum iwl_scan_offload_flags {
+ IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID = BIT(0),
+ IWL_SCAN_OFFLOAD_FLAG_CACHED_CHANNEL = BIT(2),
+ IWL_SCAN_OFFLOAD_FLAG_ENERGY_SCAN = BIT(3),
+};
+
+/**
+ * iwl_scan_offload_req - scan offload request command
+ * @flags: bitmap - enum iwl_scan_offload_flags.
+ * @watchdog: maximum scan duration in TU.
+ * @delay: delay in seconds before first iteration.
+ * @schedule_line: scan offload schedule, for fast and regular scan.
+ */
+struct iwl_scan_offload_req {
+ __le16 flags;
+ __le16 watchdog;
+ __le16 delay;
+ __le16 reserved;
+ struct iwl_scan_offload_schedule schedule_line[2];
+} __packed;
+
+enum iwl_scan_offload_compleate_status {
+ IWL_SCAN_OFFLOAD_COMPLETED = 1,
+ IWL_SCAN_OFFLOAD_ABORTED = 2,
+};
+
+/**
+ * iwl_scan_offload_complete - SCAN_OFFLOAD_COMPLETE_NTF_API_S_VER_1
+ * @last_schedule_line: last schedule line executed (fast or regular)
+ * @last_schedule_iteration: last scan iteration executed before scan abort
+ * @status: enum iwl_scan_offload_compleate_status
+ */
+struct iwl_scan_offload_complete {
+ u8 last_schedule_line;
+ u8 last_schedule_iteration;
+ u8 status;
+ u8 reserved;
+} __packed;
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
new file mode 100644
index 000000000000..0acb53dda22d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
@@ -0,0 +1,380 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 __fw_api_sta_h__
+#define __fw_api_sta_h__
+
+/**
+ * enum iwl_sta_flags - flags for the ADD_STA host command
+ * @STA_FLG_REDUCED_TX_PWR_CTRL:
+ * @STA_FLG_REDUCED_TX_PWR_DATA:
+ * @STA_FLG_FLG_ANT_MSK: Antenna selection
+ * @STA_FLG_PS: set if STA is in Power Save
+ * @STA_FLG_INVALID: set if STA is invalid
+ * @STA_FLG_DLP_EN: Direct Link Protocol is enabled
+ * @STA_FLG_SET_ALL_KEYS: the current key applies to all key IDs
+ * @STA_FLG_DRAIN_FLOW: drain flow
+ * @STA_FLG_PAN: STA is for PAN interface
+ * @STA_FLG_CLASS_AUTH:
+ * @STA_FLG_CLASS_ASSOC:
+ * @STA_FLG_CLASS_MIMO_PROT:
+ * @STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU
+ * @STA_FLG_AGG_MPDU_DENS_MSK: maximal MPDU density for Tx aggregation
+ * @STA_FLG_FAT_EN_MSK: support for channel width (for Tx). This flag is
+ * initialised by driver and can be updated by fw upon reception of
+ * action frames that can change the channel width. When cleared the fw
+ * will send all the frames in 20MHz even when FAT channel is requested.
+ * @STA_FLG_MIMO_EN_MSK: support for MIMO. This flag is initialised by the
+ * driver and can be updated by fw upon reception of action frames.
+ * @STA_FLG_MFP_EN: Management Frame Protection
+ */
+enum iwl_sta_flags {
+ STA_FLG_REDUCED_TX_PWR_CTRL = BIT(3),
+ STA_FLG_REDUCED_TX_PWR_DATA = BIT(6),
+
+ STA_FLG_FLG_ANT_A = (1 << 4),
+ STA_FLG_FLG_ANT_B = (2 << 4),
+ STA_FLG_FLG_ANT_MSK = (STA_FLG_FLG_ANT_A |
+ STA_FLG_FLG_ANT_B),
+
+ STA_FLG_PS = BIT(8),
+ STA_FLG_INVALID = BIT(9),
+ STA_FLG_DLP_EN = BIT(10),
+ STA_FLG_SET_ALL_KEYS = BIT(11),
+ STA_FLG_DRAIN_FLOW = BIT(12),
+ STA_FLG_PAN = BIT(13),
+ STA_FLG_CLASS_AUTH = BIT(14),
+ STA_FLG_CLASS_ASSOC = BIT(15),
+ STA_FLG_RTS_MIMO_PROT = BIT(17),
+
+ STA_FLG_MAX_AGG_SIZE_SHIFT = 19,
+ STA_FLG_MAX_AGG_SIZE_8K = (0 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+ STA_FLG_MAX_AGG_SIZE_16K = (1 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+ STA_FLG_MAX_AGG_SIZE_32K = (2 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+ STA_FLG_MAX_AGG_SIZE_64K = (3 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+ STA_FLG_MAX_AGG_SIZE_128K = (4 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+ STA_FLG_MAX_AGG_SIZE_256K = (5 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+ STA_FLG_MAX_AGG_SIZE_512K = (6 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+ STA_FLG_MAX_AGG_SIZE_1024K = (7 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+ STA_FLG_MAX_AGG_SIZE_MSK = (7 << STA_FLG_MAX_AGG_SIZE_SHIFT),
+
+ STA_FLG_AGG_MPDU_DENS_SHIFT = 23,
+ STA_FLG_AGG_MPDU_DENS_2US = (4 << STA_FLG_AGG_MPDU_DENS_SHIFT),
+ STA_FLG_AGG_MPDU_DENS_4US = (5 << STA_FLG_AGG_MPDU_DENS_SHIFT),
+ STA_FLG_AGG_MPDU_DENS_8US = (6 << STA_FLG_AGG_MPDU_DENS_SHIFT),
+ STA_FLG_AGG_MPDU_DENS_16US = (7 << STA_FLG_AGG_MPDU_DENS_SHIFT),
+ STA_FLG_AGG_MPDU_DENS_MSK = (7 << STA_FLG_AGG_MPDU_DENS_SHIFT),
+
+ STA_FLG_FAT_EN_20MHZ = (0 << 26),
+ STA_FLG_FAT_EN_40MHZ = (1 << 26),
+ STA_FLG_FAT_EN_80MHZ = (2 << 26),
+ STA_FLG_FAT_EN_160MHZ = (3 << 26),
+ STA_FLG_FAT_EN_MSK = (3 << 26),
+
+ STA_FLG_MIMO_EN_SISO = (0 << 28),
+ STA_FLG_MIMO_EN_MIMO2 = (1 << 28),
+ STA_FLG_MIMO_EN_MIMO3 = (2 << 28),
+ STA_FLG_MIMO_EN_MSK = (3 << 28),
+};
+
+/**
+ * enum iwl_sta_key_flag - key flags for the ADD_STA host command
+ * @STA_KEY_FLG_EN_MSK: mask for encryption algorithm
+ * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from
+ * station info array (1 - n 1X mode)
+ * @STA_KEY_FLG_KEYID_MSK: the index of the key
+ * @STA_KEY_NOT_VALID: key is invalid
+ * @STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key
+ * @STA_KEY_MULTICAST: set for multical key
+ * @STA_KEY_MFP: key is used for Management Frame Protection
+ */
+enum iwl_sta_key_flag {
+ STA_KEY_FLG_NO_ENC = (0 << 0),
+ STA_KEY_FLG_WEP = (1 << 0),
+ STA_KEY_FLG_CCM = (2 << 0),
+ STA_KEY_FLG_TKIP = (3 << 0),
+ STA_KEY_FLG_CMAC = (6 << 0),
+ STA_KEY_FLG_ENC_UNKNOWN = (7 << 0),
+ STA_KEY_FLG_EN_MSK = (7 << 0),
+
+ STA_KEY_FLG_WEP_KEY_MAP = BIT(3),
+ STA_KEY_FLG_KEYID_POS = 8,
+ STA_KEY_FLG_KEYID_MSK = (3 << STA_KEY_FLG_KEYID_POS),
+ STA_KEY_NOT_VALID = BIT(11),
+ STA_KEY_FLG_WEP_13BYTES = BIT(12),
+ STA_KEY_MULTICAST = BIT(14),
+ STA_KEY_MFP = BIT(15),
+};
+
+/**
+ * enum iwl_sta_modify_flag - indicate to the fw what flag are being changed
+ * @STA_MODIFY_KEY: this command modifies %key
+ * @STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx
+ * @STA_MODIFY_TX_RATE: unused
+ * @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid
+ * @STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid
+ * @STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count
+ * @STA_MODIFY_PROT_TH:
+ * @STA_MODIFY_QUEUES: modify the queues used by this station
+ */
+enum iwl_sta_modify_flag {
+ STA_MODIFY_KEY = BIT(0),
+ STA_MODIFY_TID_DISABLE_TX = BIT(1),
+ STA_MODIFY_TX_RATE = BIT(2),
+ STA_MODIFY_ADD_BA_TID = BIT(3),
+ STA_MODIFY_REMOVE_BA_TID = BIT(4),
+ STA_MODIFY_SLEEPING_STA_TX_COUNT = BIT(5),
+ STA_MODIFY_PROT_TH = BIT(6),
+ STA_MODIFY_QUEUES = BIT(7),
+};
+
+#define STA_MODE_MODIFY 1
+
+/**
+ * enum iwl_sta_sleep_flag - type of sleep of the station
+ * @STA_SLEEP_STATE_AWAKE:
+ * @STA_SLEEP_STATE_PS_POLL:
+ * @STA_SLEEP_STATE_UAPSD:
+ */
+enum iwl_sta_sleep_flag {
+ STA_SLEEP_STATE_AWAKE = 0,
+ STA_SLEEP_STATE_PS_POLL = BIT(0),
+ STA_SLEEP_STATE_UAPSD = BIT(1),
+};
+
+/* STA ID and color bits definitions */
+#define STA_ID_SEED (0x0f)
+#define STA_ID_POS (0)
+#define STA_ID_MSK (STA_ID_SEED << STA_ID_POS)
+
+#define STA_COLOR_SEED (0x7)
+#define STA_COLOR_POS (4)
+#define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS)
+
+#define STA_ID_N_COLOR_GET_COLOR(id_n_color) \
+ (((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS)
+#define STA_ID_N_COLOR_GET_ID(id_n_color) \
+ (((id_n_color) & STA_ID_MSK) >> STA_ID_POS)
+
+#define STA_KEY_MAX_NUM (16)
+#define STA_KEY_IDX_INVALID (0xff)
+#define STA_KEY_MAX_DATA_KEY_NUM (4)
+#define IWL_MAX_GLOBAL_KEYS (4)
+#define STA_KEY_LEN_WEP40 (5)
+#define STA_KEY_LEN_WEP104 (13)
+
+/**
+ * struct iwl_mvm_keyinfo - key information
+ * @key_flags: type %iwl_sta_key_flag
+ * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection
+ * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx
+ * @key_offset: key offset in the fw's key table
+ * @key: 16-byte unicast decryption key
+ * @tx_secur_seq_cnt: initial RSC / PN needed for replay check
+ * @hw_tkip_mic_rx_key: byte: MIC Rx Key - used for TKIP only
+ * @hw_tkip_mic_tx_key: byte: MIC Tx Key - used for TKIP only
+ */
+struct iwl_mvm_keyinfo {
+ __le16 key_flags;
+ u8 tkip_rx_tsc_byte2;
+ u8 reserved1;
+ __le16 tkip_rx_ttak[5];
+ u8 key_offset;
+ u8 reserved2;
+ u8 key[16];
+ __le64 tx_secur_seq_cnt;
+ __le64 hw_tkip_mic_rx_key;
+ __le64 hw_tkip_mic_tx_key;
+} __packed;
+
+/**
+ * struct iwl_mvm_add_sta_cmd - Add / modify a station in the fw's station table
+ * ( REPLY_ADD_STA = 0x18 )
+ * @add_modify: 1: modify existing, 0: add new station
+ * @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent
+ * @multicast_tx_key_id: multicast tx key id. Relevant only when multicast key
+ * sent
+ * @mac_id_n_color: the Mac context this station belongs to
+ * @addr[ETH_ALEN]: station's MAC address
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave
+ * alone. 1 - modify, 0 - don't change.
+ * @key: look at %iwl_mvm_keyinfo
+ * @station_flags: look at %iwl_sta_flags
+ * @station_flags_msk: what of %station_flags have changed
+ * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable
+ * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field.
+ * @add_immediate_ba_tid: tid for which to add block-ack support (Rx)
+ * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set
+ * add_immediate_ba_ssn.
+ * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx)
+ * Set %STA_MODIFY_REMOVE_BA_TID to use this field
+ * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with
+ * add_immediate_ba_tid.
+ * @sleep_tx_count: number of packets 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.
+ * @sleep_state_flags: Look at %iwl_sta_sleep_flag.
+ * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP
+ * mac-addr.
+ * @beamform_flags: beam forming controls
+ * @tfd_queue_msk: tfd queues used by this station
+ *
+ * The device contains an internal table of per-station information, with info
+ * on security keys, aggregation parameters, and Tx rates for initial Tx
+ * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD).
+ *
+ * ADD_STA sets up the table entry for one station, either creating a new
+ * entry, or modifying a pre-existing one.
+ */
+struct iwl_mvm_add_sta_cmd {
+ u8 add_modify;
+ u8 unicast_tx_key_id;
+ u8 multicast_tx_key_id;
+ u8 reserved1;
+ __le32 mac_id_n_color;
+ u8 addr[ETH_ALEN];
+ __le16 reserved2;
+ u8 sta_id;
+ u8 modify_mask;
+ __le16 reserved3;
+ struct iwl_mvm_keyinfo key;
+ __le32 station_flags;
+ __le32 station_flags_msk;
+ __le16 tid_disable_tx;
+ __le16 reserved4;
+ u8 add_immediate_ba_tid;
+ u8 remove_immediate_ba_tid;
+ __le16 add_immediate_ba_ssn;
+ __le16 sleep_tx_count;
+ __le16 sleep_state_flags;
+ __le16 assoc_id;
+ __le16 beamform_flags;
+ __le32 tfd_queue_msk;
+} __packed; /* ADD_STA_CMD_API_S_VER_5 */
+
+/**
+ * enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command
+ * @ADD_STA_SUCCESS: operation was executed successfully
+ * @ADD_STA_STATIONS_OVERLOAD: no room left in the fw's station table
+ * @ADD_STA_IMMEDIATE_BA_FAILURE: can't add Rx block ack session
+ * @ADD_STA_MODIFY_NON_EXISTING_STA: driver requested to modify a station that
+ * doesn't exist.
+ */
+enum iwl_mvm_add_sta_rsp_status {
+ ADD_STA_SUCCESS = 0x1,
+ ADD_STA_STATIONS_OVERLOAD = 0x2,
+ ADD_STA_IMMEDIATE_BA_FAILURE = 0x4,
+ ADD_STA_MODIFY_NON_EXISTING_STA = 0x8,
+};
+
+/**
+ * struct iwl_mvm_rm_sta_cmd - Add / modify a station in the fw's station table
+ * ( REMOVE_STA = 0x19 )
+ * @sta_id: the station id of the station to be removed
+ */
+struct iwl_mvm_rm_sta_cmd {
+ u8 sta_id;
+ u8 reserved[3];
+} __packed; /* REMOVE_STA_CMD_API_S_VER_2 */
+
+/**
+ * struct iwl_mvm_mgmt_mcast_key_cmd
+ * ( MGMT_MCAST_KEY = 0x1f )
+ * @ctrl_flags: %iwl_sta_key_flag
+ * @IGTK:
+ * @K1: IGTK master key
+ * @K2: IGTK sub key
+ * @sta_id: station ID that support IGTK
+ * @key_id:
+ * @receive_seq_cnt: initial RSC/PN needed for replay check
+ */
+struct iwl_mvm_mgmt_mcast_key_cmd {
+ __le32 ctrl_flags;
+ u8 IGTK[16];
+ u8 K1[16];
+ u8 K2[16];
+ __le32 key_id;
+ __le32 sta_id;
+ __le64 receive_seq_cnt;
+} __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */
+
+struct iwl_mvm_wep_key {
+ u8 key_index;
+ u8 key_offset;
+ __le16 reserved1;
+ u8 key_size;
+ u8 reserved2[3];
+ u8 key[16];
+} __packed;
+
+struct iwl_mvm_wep_key_cmd {
+ __le32 mac_id_n_color;
+ u8 num_keys;
+ u8 decryption_type;
+ u8 flags;
+ u8 reserved;
+ struct iwl_mvm_wep_key wep_key[0];
+} __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */
+
+
+#endif /* __fw_api_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
new file mode 100644
index 000000000000..2677914bf0a6
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
@@ -0,0 +1,580 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 __fw_api_tx_h__
+#define __fw_api_tx_h__
+
+/**
+ * enum iwl_tx_flags - bitmasks for tx_flags in TX command
+ * @TX_CMD_FLG_PROT_REQUIRE: use RTS or CTS-to-self to protect the frame
+ * @TX_CMD_FLG_ACK: expect ACK from receiving station
+ * @TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command.
+ * Otherwise, use rate_n_flags from the TX command
+ * @TX_CMD_FLG_BA: this frame is a block ack
+ * @TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected
+ * Must set TX_CMD_FLG_ACK with this flag.
+ * @TX_CMD_FLG_TXOP_PROT: protect frame with full TXOP protection
+ * @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence
+ * @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence
+ * @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC)
+ * @TX_CMD_FLG_BT_DIS: disable BT priority for this frame
+ * @TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control.
+ * Should be set for mgmt, non-QOS data, mcast, bcast and in scan command
+ * @TX_CMD_FLG_MORE_FRAG: this frame is non-last MPDU
+ * @TX_CMD_FLG_NEXT_FRAME: this frame includes information of the next frame
+ * @TX_CMD_FLG_TSF: FW should calculate and insert TSF in the frame
+ * Should be set for beacons and probe responses
+ * @TX_CMD_FLG_CALIB: activate PA TX power calibrations
+ * @TX_CMD_FLG_KEEP_SEQ_CTL: if seq_ctl is set, don't increase inner seq count
+ * @TX_CMD_FLG_AGG_START: allow this frame to start aggregation
+ * @TX_CMD_FLG_MH_PAD: driver inserted 2 byte padding after MAC header.
+ * Should be set for 26/30 length MAC headers
+ * @TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW
+ * @TX_CMD_FLG_CCMP_AGG: this frame uses CCMP for aggregation acceleration
+ * @TX_CMD_FLG_TKIP_MIC_DONE: FW already performed TKIP MIC calculation
+ * @TX_CMD_FLG_CTS_ONLY: send CTS only, no data after that
+ * @TX_CMD_FLG_DUR: disable duration overwriting used in PS-Poll Assoc-id
+ * @TX_CMD_FLG_FW_DROP: FW should mark frame to be dropped
+ * @TX_CMD_FLG_EXEC_PAPD: execute PAPD
+ * @TX_CMD_FLG_PAPD_TYPE: 0 for reference power, 1 for nominal power
+ * @TX_CMD_FLG_HCCA_CHUNK: mark start of TSPEC chunk
+ */
+enum iwl_tx_flags {
+ TX_CMD_FLG_PROT_REQUIRE = BIT(0),
+ TX_CMD_FLG_ACK = BIT(3),
+ TX_CMD_FLG_STA_RATE = BIT(4),
+ TX_CMD_FLG_BA = BIT(5),
+ TX_CMD_FLG_BAR = BIT(6),
+ TX_CMD_FLG_TXOP_PROT = BIT(7),
+ TX_CMD_FLG_VHT_NDPA = BIT(8),
+ TX_CMD_FLG_HT_NDPA = BIT(9),
+ TX_CMD_FLG_CSI_FDBK2HOST = BIT(10),
+ TX_CMD_FLG_BT_DIS = BIT(12),
+ TX_CMD_FLG_SEQ_CTL = BIT(13),
+ TX_CMD_FLG_MORE_FRAG = BIT(14),
+ TX_CMD_FLG_NEXT_FRAME = BIT(15),
+ TX_CMD_FLG_TSF = BIT(16),
+ TX_CMD_FLG_CALIB = BIT(17),
+ TX_CMD_FLG_KEEP_SEQ_CTL = BIT(18),
+ TX_CMD_FLG_AGG_START = BIT(19),
+ TX_CMD_FLG_MH_PAD = BIT(20),
+ TX_CMD_FLG_RESP_TO_DRV = BIT(21),
+ TX_CMD_FLG_CCMP_AGG = BIT(22),
+ TX_CMD_FLG_TKIP_MIC_DONE = BIT(23),
+ TX_CMD_FLG_CTS_ONLY = BIT(24),
+ TX_CMD_FLG_DUR = BIT(25),
+ TX_CMD_FLG_FW_DROP = BIT(26),
+ TX_CMD_FLG_EXEC_PAPD = BIT(27),
+ TX_CMD_FLG_PAPD_TYPE = BIT(28),
+ TX_CMD_FLG_HCCA_CHUNK = BIT(31)
+}; /* TX_FLAGS_BITS_API_S_VER_1 */
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP 0x01
+#define TX_CMD_SEC_CCM 0x02
+#define TX_CMD_SEC_TKIP 0x03
+#define TX_CMD_SEC_WEP_KEY_IDX_POS 6
+#define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0
+#define TX_CMD_SEC_KEY128 0x08
+
+/* TODO: how does these values are OK with only 16 bit variable??? */
+/*
+ * TX command next frame info
+ *
+ * bits 0:2 - security control (TX_CMD_SEC_*)
+ * bit 3 - immediate ACK required
+ * bit 4 - rate is taken from STA table
+ * bit 5 - frame belongs to BA stream
+ * bit 6 - immediate BA response expected
+ * bit 7 - unused
+ * bits 8:15 - Station ID
+ * bits 16:31 - rate
+ */
+#define TX_CMD_NEXT_FRAME_ACK_MSK (0x8)
+#define TX_CMD_NEXT_FRAME_STA_RATE_MSK (0x10)
+#define TX_CMD_NEXT_FRAME_BA_MSK (0x20)
+#define TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK (0x40)
+#define TX_CMD_NEXT_FRAME_FLAGS_MSK (0xf8)
+#define TX_CMD_NEXT_FRAME_STA_ID_MSK (0xff00)
+#define TX_CMD_NEXT_FRAME_STA_ID_POS (8)
+#define TX_CMD_NEXT_FRAME_RATE_MSK (0xffff0000)
+#define TX_CMD_NEXT_FRAME_RATE_POS (16)
+
+/*
+ * TX command Frame life time in us - to be written in pm_frame_timeout
+ */
+#define TX_CMD_LIFE_TIME_INFINITE 0xFFFFFFFF
+#define TX_CMD_LIFE_TIME_DEFAULT 2000000 /* 2000 ms*/
+#define TX_CMD_LIFE_TIME_PROBE_RESP 40000 /* 40 ms */
+#define TX_CMD_LIFE_TIME_EXPIRED_FRAME 0
+
+/*
+ * TID for non QoS frames - to be written in tid_tspec
+ */
+#define IWL_TID_NON_QOS IWL_MAX_TID_COUNT
+
+/*
+ * Limits on the retransmissions - to be written in {data,rts}_retry_limit
+ */
+#define IWL_DEFAULT_TX_RETRY 15
+#define IWL_MGMT_DFAULT_RETRY_LIMIT 3
+#define IWL_RTS_DFAULT_RETRY_LIMIT 60
+#define IWL_BAR_DFAULT_RETRY_LIMIT 60
+#define IWL_LOW_RETRY_LIMIT 7
+
+/* TODO: complete documentation for try_cnt and btkill_cnt */
+/**
+ * struct iwl_tx_cmd - TX command struct to FW
+ * ( TX_CMD = 0x1c )
+ * @len: in bytes of the payload, see below for details
+ * @next_frame_len: same as len, but for next frame (0 if not applicable)
+ * Used for fragmentation and bursting, but not in 11n aggregation.
+ * @tx_flags: combination of TX_CMD_FLG_*
+ * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is
+ * cleared. Combination of RATE_MCS_*
+ * @sta_id: index of destination station in FW station table
+ * @sec_ctl: security control, TX_CMD_SEC_*
+ * @initial_rate_index: index into the the rate table for initial TX attempt.
+ * Applied if TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames.
+ * @key: security key
+ * @next_frame_flags: TX_CMD_SEC_* and TX_CMD_NEXT_FRAME_*
+ * @life_time: frame life time (usecs??)
+ * @dram_lsb_ptr: Physical address of scratch area in the command (try_cnt +
+ * btkill_cnd + reserved), first 32 bits. "0" disables usage.
+ * @dram_msb_ptr: upper bits of the scratch physical address
+ * @rts_retry_limit: max attempts for RTS
+ * @data_retry_limit: max attempts to send the data packet
+ * @tid_spec: TID/tspec
+ * @pm_frame_timeout: PM TX frame timeout
+ * @driver_txop: duration od EDCA TXOP, in 32-usec units. Set this if not
+ * specified by HCCA protocol
+ *
+ * The byte count (both len and next_frame_len) includes 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)
+ * It does not include post-MAC padding, i.e.,
+ * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.
+ * Range of len: 14-2342 bytes.
+ *
+ * After the struct fields the MAC header is placed, plus any padding,
+ * and then the actial payload.
+ */
+struct iwl_tx_cmd {
+ __le16 len;
+ __le16 next_frame_len;
+ __le32 tx_flags;
+ /* DRAM_SCRATCH_API_U_VER_1 */
+ u8 try_cnt;
+ u8 btkill_cnt;
+ __le16 reserved;
+ __le32 rate_n_flags;
+ u8 sta_id;
+ u8 sec_ctl;
+ u8 initial_rate_index;
+ u8 reserved2;
+ u8 key[16];
+ __le16 next_frame_flags;
+ __le16 reserved3;
+ __le32 life_time;
+ __le32 dram_lsb_ptr;
+ u8 dram_msb_ptr;
+ u8 rts_retry_limit;
+ u8 data_retry_limit;
+ u8 tid_tspec;
+ __le16 pm_frame_timeout;
+ __le16 driver_txop;
+ u8 payload[0];
+ struct ieee80211_hdr hdr[0];
+} __packed; /* TX_CMD_API_S_VER_3 */
+
+/*
+ * TX response related data
+ */
+
+/*
+ * enum iwl_tx_status - status that is returned by the fw after attempts to Tx
+ * @TX_STATUS_SUCCESS:
+ * @TX_STATUS_DIRECT_DONE:
+ * @TX_STATUS_POSTPONE_DELAY:
+ * @TX_STATUS_POSTPONE_FEW_BYTES:
+ * @TX_STATUS_POSTPONE_BT_PRIO:
+ * @TX_STATUS_POSTPONE_QUIET_PERIOD:
+ * @TX_STATUS_POSTPONE_CALC_TTAK:
+ * @TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY:
+ * @TX_STATUS_FAIL_SHORT_LIMIT:
+ * @TX_STATUS_FAIL_LONG_LIMIT:
+ * @TX_STATUS_FAIL_UNDERRUN:
+ * @TX_STATUS_FAIL_DRAIN_FLOW:
+ * @TX_STATUS_FAIL_RFKILL_FLUSH:
+ * @TX_STATUS_FAIL_LIFE_EXPIRE:
+ * @TX_STATUS_FAIL_DEST_PS:
+ * @TX_STATUS_FAIL_HOST_ABORTED:
+ * @TX_STATUS_FAIL_BT_RETRY:
+ * @TX_STATUS_FAIL_STA_INVALID:
+ * @TX_TATUS_FAIL_FRAG_DROPPED:
+ * @TX_STATUS_FAIL_TID_DISABLE:
+ * @TX_STATUS_FAIL_FIFO_FLUSHED:
+ * @TX_STATUS_FAIL_SMALL_CF_POLL:
+ * @TX_STATUS_FAIL_FW_DROP:
+ * @TX_STATUS_FAIL_STA_COLOR_MISMATCH: mismatch between color of Tx cmd and
+ * STA table
+ * @TX_FRAME_STATUS_INTERNAL_ABORT:
+ * @TX_MODE_MSK:
+ * @TX_MODE_NO_BURST:
+ * @TX_MODE_IN_BURST_SEQ:
+ * @TX_MODE_FIRST_IN_BURST:
+ * @TX_QUEUE_NUM_MSK:
+ *
+ * Valid only if frame_count =1
+ * TODO: complete documentation
+ */
+enum iwl_tx_status {
+ TX_STATUS_MSK = 0x000000ff,
+ TX_STATUS_SUCCESS = 0x01,
+ TX_STATUS_DIRECT_DONE = 0x02,
+ /* postpone TX */
+ TX_STATUS_POSTPONE_DELAY = 0x40,
+ TX_STATUS_POSTPONE_FEW_BYTES = 0x41,
+ TX_STATUS_POSTPONE_BT_PRIO = 0x42,
+ TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43,
+ TX_STATUS_POSTPONE_CALC_TTAK = 0x44,
+ /* abort TX */
+ TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81,
+ TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+ TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+ TX_STATUS_FAIL_UNDERRUN = 0x84,
+ TX_STATUS_FAIL_DRAIN_FLOW = 0x85,
+ TX_STATUS_FAIL_RFKILL_FLUSH = 0x86,
+ TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+ TX_STATUS_FAIL_DEST_PS = 0x88,
+ TX_STATUS_FAIL_HOST_ABORTED = 0x89,
+ TX_STATUS_FAIL_BT_RETRY = 0x8a,
+ TX_STATUS_FAIL_STA_INVALID = 0x8b,
+ TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+ TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+ TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e,
+ TX_STATUS_FAIL_SMALL_CF_POLL = 0x8f,
+ TX_STATUS_FAIL_FW_DROP = 0x90,
+ TX_STATUS_FAIL_STA_COLOR_MISMATCH = 0x91,
+ TX_STATUS_INTERNAL_ABORT = 0x92,
+ TX_MODE_MSK = 0x00000f00,
+ TX_MODE_NO_BURST = 0x00000000,
+ TX_MODE_IN_BURST_SEQ = 0x00000100,
+ TX_MODE_FIRST_IN_BURST = 0x00000200,
+ TX_QUEUE_NUM_MSK = 0x0001f000,
+ TX_NARROW_BW_MSK = 0x00060000,
+ TX_NARROW_BW_1DIV2 = 0x00020000,
+ TX_NARROW_BW_1DIV4 = 0x00040000,
+ TX_NARROW_BW_1DIV8 = 0x00060000,
+};
+
+/*
+ * enum iwl_tx_agg_status - TX aggregation status
+ * @AGG_TX_STATE_STATUS_MSK:
+ * @AGG_TX_STATE_TRANSMITTED:
+ * @AGG_TX_STATE_UNDERRUN:
+ * @AGG_TX_STATE_BT_PRIO:
+ * @AGG_TX_STATE_FEW_BYTES:
+ * @AGG_TX_STATE_ABORT:
+ * @AGG_TX_STATE_LAST_SENT_TTL:
+ * @AGG_TX_STATE_LAST_SENT_TRY_CNT:
+ * @AGG_TX_STATE_LAST_SENT_BT_KILL:
+ * @AGG_TX_STATE_SCD_QUERY:
+ * @AGG_TX_STATE_TEST_BAD_CRC32:
+ * @AGG_TX_STATE_RESPONSE:
+ * @AGG_TX_STATE_DUMP_TX:
+ * @AGG_TX_STATE_DELAY_TX:
+ * @AGG_TX_STATE_TRY_CNT_MSK: 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.
+ *@ AGG_TX_STATE_SEQ_NUM_MSK: Command ID and sequence number of Tx command for
+ * this frame
+ *
+ * TODO: complete documentation
+ */
+enum iwl_tx_agg_status {
+ AGG_TX_STATE_STATUS_MSK = 0x00fff,
+ AGG_TX_STATE_TRANSMITTED = 0x000,
+ AGG_TX_STATE_UNDERRUN = 0x001,
+ AGG_TX_STATE_BT_PRIO = 0x002,
+ AGG_TX_STATE_FEW_BYTES = 0x004,
+ AGG_TX_STATE_ABORT = 0x008,
+ AGG_TX_STATE_LAST_SENT_TTL = 0x010,
+ AGG_TX_STATE_LAST_SENT_TRY_CNT = 0x020,
+ AGG_TX_STATE_LAST_SENT_BT_KILL = 0x040,
+ AGG_TX_STATE_SCD_QUERY = 0x080,
+ AGG_TX_STATE_TEST_BAD_CRC32 = 0x0100,
+ AGG_TX_STATE_RESPONSE = 0x1ff,
+ AGG_TX_STATE_DUMP_TX = 0x200,
+ AGG_TX_STATE_DELAY_TX = 0x400,
+ AGG_TX_STATE_TRY_CNT_POS = 12,
+ AGG_TX_STATE_TRY_CNT_MSK = 0xf << AGG_TX_STATE_TRY_CNT_POS,
+};
+
+#define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL| \
+ AGG_TX_STATE_LAST_SENT_TRY_CNT| \
+ AGG_TX_STATE_LAST_SENT_BT_KILL)
+
+/*
+ * The mask below describes a status where we are absolutely sure that the MPDU
+ * wasn't sent. For BA/Underrun we cannot be that sure. All we know that we've
+ * written the bytes to the TXE, but we know nothing about what the DSP did.
+ */
+#define AGG_TX_STAT_FRAME_NOT_SENT (AGG_TX_STATE_FEW_BYTES | \
+ AGG_TX_STATE_ABORT | \
+ AGG_TX_STATE_SCD_QUERY)
+
+/*
+ * REPLY_TX = 0x1c (response)
+ *
+ * This response may be in one of two slightly different formats, indicated
+ * by the frame_count field:
+ *
+ * 1) No aggregation (frame_count == 1). This reports Tx results for a single
+ * frame. Multiple attempts, at various bit rates, may have been made for
+ * this frame.
+ *
+ * 2) Aggregation (frame_count > 1). This reports Tx results for two or more
+ * frames that used block-acknowledge. All frames were transmitted at
+ * same rate. Rate scaling may have been used if first frame in this new
+ * agg block failed in previous agg block(s).
+ *
+ * Note that, for aggregation, ACK (block-ack) status is not delivered
+ * here; block-ack has not been received by the time the device records
+ * this status.
+ * This status relates to reasons the tx might have been blocked or aborted
+ * within the device, rather than whether it was received successfully by
+ * the destination station.
+ */
+
+/**
+ * struct agg_tx_status - per packet TX aggregation status
+ * @status: enum iwl_tx_agg_status
+ * @sequence: Sequence # for this frame's Tx cmd (not SSN!)
+ */
+struct agg_tx_status {
+ __le16 status;
+ __le16 sequence;
+} __packed;
+
+/*
+ * definitions for initial rate index field
+ * bits [3:0] initial rate index
+ * bits [6:4] rate table color, used for the initial rate
+ * bit-7 invalid rate indication
+ */
+#define TX_RES_INIT_RATE_INDEX_MSK 0x0f
+#define TX_RES_RATE_TABLE_COLOR_MSK 0x70
+#define TX_RES_INV_RATE_INDEX_MSK 0x80
+
+#define IWL_MVM_TX_RES_GET_TID(_ra_tid) ((_ra_tid) & 0x0f)
+#define IWL_MVM_TX_RES_GET_RA(_ra_tid) ((_ra_tid) >> 4)
+
+/**
+ * struct iwl_mvm_tx_resp - notifies that fw is TXing a packet
+ * ( REPLY_TX = 0x1c )
+ * @frame_count: 1 no aggregation, >1 aggregation
+ * @bt_kill_count: num of times blocked by bluetooth (unused for agg)
+ * @failure_rts: num of failures due to unsuccessful RTS
+ * @failure_frame: num failures due to no ACK (unused for agg)
+ * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the
+ * Tx of all the batch. RATE_MCS_*
+ * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK.
+ * for agg: RTS + CTS + aggregation tx time + block-ack time.
+ * in usec.
+ * @pa_status: tx power info
+ * @pa_integ_res_a: tx power info
+ * @pa_integ_res_b: tx power info
+ * @pa_integ_res_c: tx power info
+ * @measurement_req_id: tx power info
+ * @tfd_info: TFD information set by the FH
+ * @seq_ctl: sequence control from the Tx cmd
+ * @byte_cnt: byte count from the Tx cmd
+ * @tlc_info: TLC rate info
+ * @ra_tid: bits [3:0] = ra, bits [7:4] = tid
+ * @frame_ctrl: frame control
+ * @status: 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.
+ *
+ * After the array of statuses comes the SSN of the SCD. Look at
+ * %iwl_mvm_get_scd_ssn for more details.
+ */
+struct iwl_mvm_tx_resp {
+ u8 frame_count;
+ u8 bt_kill_count;
+ u8 failure_rts;
+ u8 failure_frame;
+ __le32 initial_rate;
+ __le16 wireless_media_time;
+
+ u8 pa_status;
+ u8 pa_integ_res_a[3];
+ u8 pa_integ_res_b[3];
+ u8 pa_integ_res_c[3];
+ __le16 measurement_req_id;
+ __le16 reserved;
+
+ __le32 tfd_info;
+ __le16 seq_ctl;
+ __le16 byte_cnt;
+ u8 tlc_info;
+ u8 ra_tid;
+ __le16 frame_ctrl;
+
+ struct agg_tx_status status;
+} __packed; /* TX_RSP_API_S_VER_3 */
+
+/**
+ * struct iwl_mvm_ba_notif - notifies about reception of BA
+ * ( BA_NOTIF = 0xc5 )
+ * @sta_addr_lo32: lower 32 bits of the MAC address
+ * @sta_addr_hi16: upper 16 bits of the MAC address
+ * @sta_id: Index of recipient (BA-sending) station in fw's station table
+ * @tid: tid of the session
+ * @seq_ctl:
+ * @bitmap: the bitmap of the BA notification as seen in the air
+ * @scd_flow: the tx queue this BA relates to
+ * @scd_ssn: the index of the last contiguously sent packet
+ * @txed: number of Txed frames in this batch
+ * @txed_2_done: number of Acked frames in this batch
+ */
+struct iwl_mvm_ba_notif {
+ __le32 sta_addr_lo32;
+ __le16 sta_addr_hi16;
+ __le16 reserved;
+
+ u8 sta_id;
+ u8 tid;
+ __le16 seq_ctl;
+ __le64 bitmap;
+ __le16 scd_flow;
+ __le16 scd_ssn;
+ u8 txed;
+ u8 txed_2_done;
+ __le16 reserved1;
+} __packed;
+
+/*
+ * struct iwl_mac_beacon_cmd - beacon template command
+ * @tx: the tx commands associated with the beacon frame
+ * @template_id: currently equal to the mac context id of the coresponding
+ * mac.
+ * @tim_idx: the offset of the tim IE in the beacon
+ * @tim_size: the length of the tim IE
+ * @frame: the template of the beacon frame
+ */
+struct iwl_mac_beacon_cmd {
+ struct iwl_tx_cmd tx;
+ __le32 template_id;
+ __le32 tim_idx;
+ __le32 tim_size;
+ struct ieee80211_hdr frame[0];
+} __packed;
+
+/**
+ * enum iwl_dump_control - dump (flush) control flags
+ * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty
+ * and the TFD queues are empty.
+ */
+enum iwl_dump_control {
+ DUMP_TX_FIFO_FLUSH = BIT(1),
+};
+
+/**
+ * struct iwl_tx_path_flush_cmd -- queue/FIFO flush command
+ * @queues_ctl: bitmap of queues to flush
+ * @flush_ctl: control flags
+ * @reserved: reserved
+ */
+struct iwl_tx_path_flush_cmd {
+ __le32 queues_ctl;
+ __le16 flush_ctl;
+ __le16 reserved;
+} __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_1 */
+
+/**
+ * iwl_mvm_get_scd_ssn - returns the SSN of the SCD
+ * @tx_resp: the Tx response from the fw (agg or non-agg)
+ *
+ * When the fw sends an AMPDU, it fetches the MPDUs one after the other. Since
+ * it can't know that everything will go well until the end of the AMPDU, it
+ * can't know in advance the number of MPDUs that will be sent in the current
+ * batch. This is why it writes the agg Tx response while it fetches the MPDUs.
+ * Hence, it can't know in advance what the SSN of the SCD will be at the end
+ * of the batch. This is why the SSN of the SCD is written at the end of the
+ * whole struct at a variable offset. This function knows how to cope with the
+ * variable offset and returns the SSN of the SCD.
+ */
+static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm_tx_resp *tx_resp)
+{
+ return le32_to_cpup((__le32 *)&tx_resp->status +
+ tx_resp->frame_count) & 0xfff;
+}
+
+#endif /* __fw_api_tx_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
new file mode 100644
index 000000000000..23eebda848b0
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -0,0 +1,952 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 __fw_api_h__
+#define __fw_api_h__
+
+#include "fw-api-rs.h"
+#include "fw-api-tx.h"
+#include "fw-api-sta.h"
+#include "fw-api-mac.h"
+#include "fw-api-power.h"
+#include "fw-api-d3.h"
+
+/* queue and FIFO numbers by usage */
+enum {
+ IWL_MVM_OFFCHANNEL_QUEUE = 8,
+ IWL_MVM_CMD_QUEUE = 9,
+ IWL_MVM_AUX_QUEUE = 15,
+ IWL_MVM_FIRST_AGG_QUEUE = 16,
+ IWL_MVM_NUM_QUEUES = 20,
+ IWL_MVM_LAST_AGG_QUEUE = IWL_MVM_NUM_QUEUES - 1,
+ IWL_MVM_CMD_FIFO = 7
+};
+
+#define IWL_MVM_STATION_COUNT 16
+
+/* commands */
+enum {
+ MVM_ALIVE = 0x1,
+ REPLY_ERROR = 0x2,
+
+ INIT_COMPLETE_NOTIF = 0x4,
+
+ /* PHY context commands */
+ PHY_CONTEXT_CMD = 0x8,
+ DBG_CFG = 0x9,
+
+ /* station table */
+ ADD_STA = 0x18,
+ REMOVE_STA = 0x19,
+
+ /* TX */
+ TX_CMD = 0x1c,
+ TXPATH_FLUSH = 0x1e,
+ MGMT_MCAST_KEY = 0x1f,
+
+ /* global key */
+ WEP_KEY = 0x20,
+
+ /* MAC and Binding commands */
+ MAC_CONTEXT_CMD = 0x28,
+ TIME_EVENT_CMD = 0x29, /* both CMD and response */
+ TIME_EVENT_NOTIFICATION = 0x2a,
+ BINDING_CONTEXT_CMD = 0x2b,
+ TIME_QUOTA_CMD = 0x2c,
+
+ LQ_CMD = 0x4e,
+
+ /* Calibration */
+ TEMPERATURE_NOTIFICATION = 0x62,
+ CALIBRATION_CFG_CMD = 0x65,
+ CALIBRATION_RES_NOTIFICATION = 0x66,
+ CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
+ RADIO_VERSION_NOTIFICATION = 0x68,
+
+ /* Scan offload */
+ SCAN_OFFLOAD_REQUEST_CMD = 0x51,
+ SCAN_OFFLOAD_ABORT_CMD = 0x52,
+ SCAN_OFFLOAD_COMPLETE = 0x6D,
+ SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
+ SCAN_OFFLOAD_CONFIG_CMD = 0x6f,
+
+ /* Phy */
+ PHY_CONFIGURATION_CMD = 0x6a,
+ CALIB_RES_NOTIF_PHY_DB = 0x6b,
+ /* PHY_DB_CMD = 0x6c, */
+
+ /* Power */
+ POWER_TABLE_CMD = 0x77,
+
+ /* Scanning */
+ SCAN_REQUEST_CMD = 0x80,
+ SCAN_ABORT_CMD = 0x81,
+ SCAN_START_NOTIFICATION = 0x82,
+ SCAN_RESULTS_NOTIFICATION = 0x83,
+ SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+ /* NVM */
+ NVM_ACCESS_CMD = 0x88,
+
+ SET_CALIB_DEFAULT_CMD = 0x8e,
+
+ BEACON_TEMPLATE_CMD = 0x91,
+ TX_ANT_CONFIGURATION_CMD = 0x98,
+ STATISTICS_NOTIFICATION = 0x9d,
+
+ /* RF-KILL commands and notifications */
+ CARD_STATE_CMD = 0xa0,
+ CARD_STATE_NOTIFICATION = 0xa1,
+
+ REPLY_RX_PHY_CMD = 0xc0,
+ REPLY_RX_MPDU_CMD = 0xc1,
+ BA_NOTIF = 0xc5,
+
+ REPLY_DEBUG_CMD = 0xf0,
+ DEBUG_LOG_MSG = 0xf7,
+
+ /* D3 commands/notifications */
+ D3_CONFIG_CMD = 0xd3,
+ PROT_OFFLOAD_CONFIG_CMD = 0xd4,
+ OFFLOADS_QUERY_CMD = 0xd5,
+ REMOTE_WAKE_CONFIG_CMD = 0xd6,
+
+ /* for WoWLAN in particular */
+ WOWLAN_PATTERNS = 0xe0,
+ WOWLAN_CONFIGURATION = 0xe1,
+ WOWLAN_TSC_RSC_PARAM = 0xe2,
+ WOWLAN_TKIP_PARAM = 0xe3,
+ WOWLAN_KEK_KCK_MATERIAL = 0xe4,
+ WOWLAN_GET_STATUSES = 0xe5,
+ WOWLAN_TX_POWER_PER_DB = 0xe6,
+
+ /* and for NetDetect */
+ NET_DETECT_CONFIG_CMD = 0x54,
+ NET_DETECT_PROFILES_QUERY_CMD = 0x56,
+ NET_DETECT_PROFILES_CMD = 0x57,
+ NET_DETECT_HOTSPOTS_CMD = 0x58,
+ NET_DETECT_HOTSPOTS_QUERY_CMD = 0x59,
+
+ REPLY_MAX = 0xff,
+};
+
+/**
+ * struct iwl_cmd_response - generic response struct for most commands
+ * @status: status of the command asked, changes for each one
+ */
+struct iwl_cmd_response {
+ __le32 status;
+};
+
+/*
+ * struct iwl_tx_ant_cfg_cmd
+ * @valid: valid antenna configuration
+ */
+struct iwl_tx_ant_cfg_cmd {
+ __le32 valid;
+} __packed;
+
+/*
+ * Calibration control struct.
+ * Sent as part of the phy configuration command.
+ * @flow_trigger: bitmap for which calibrations to perform according to
+ * flow triggers.
+ * @event_trigger: bitmap for which calibrations to perform according to
+ * event triggers.
+ */
+struct iwl_calib_ctrl {
+ __le32 flow_trigger;
+ __le32 event_trigger;
+} __packed;
+
+/* This enum defines the bitmap of various calibrations to enable in both
+ * init ucode and runtime ucode through CALIBRATION_CFG_CMD.
+ */
+enum iwl_calib_cfg {
+ IWL_CALIB_CFG_XTAL_IDX = BIT(0),
+ IWL_CALIB_CFG_TEMPERATURE_IDX = BIT(1),
+ IWL_CALIB_CFG_VOLTAGE_READ_IDX = BIT(2),
+ IWL_CALIB_CFG_PAPD_IDX = BIT(3),
+ IWL_CALIB_CFG_TX_PWR_IDX = BIT(4),
+ IWL_CALIB_CFG_DC_IDX = BIT(5),
+ IWL_CALIB_CFG_BB_FILTER_IDX = BIT(6),
+ IWL_CALIB_CFG_LO_LEAKAGE_IDX = BIT(7),
+ IWL_CALIB_CFG_TX_IQ_IDX = BIT(8),
+ IWL_CALIB_CFG_TX_IQ_SKEW_IDX = BIT(9),
+ IWL_CALIB_CFG_RX_IQ_IDX = BIT(10),
+ IWL_CALIB_CFG_RX_IQ_SKEW_IDX = BIT(11),
+ IWL_CALIB_CFG_SENSITIVITY_IDX = BIT(12),
+ IWL_CALIB_CFG_CHAIN_NOISE_IDX = BIT(13),
+ IWL_CALIB_CFG_DISCONNECTED_ANT_IDX = BIT(14),
+ IWL_CALIB_CFG_ANT_COUPLING_IDX = BIT(15),
+ IWL_CALIB_CFG_DAC_IDX = BIT(16),
+ IWL_CALIB_CFG_ABS_IDX = BIT(17),
+ IWL_CALIB_CFG_AGC_IDX = BIT(18),
+};
+
+/*
+ * Phy configuration command.
+ */
+struct iwl_phy_cfg_cmd {
+ __le32 phy_cfg;
+ struct iwl_calib_ctrl calib_control;
+} __packed;
+
+#define PHY_CFG_RADIO_TYPE (BIT(0) | BIT(1))
+#define PHY_CFG_RADIO_STEP (BIT(2) | BIT(3))
+#define PHY_CFG_RADIO_DASH (BIT(4) | BIT(5))
+#define PHY_CFG_PRODUCT_NUMBER (BIT(6) | BIT(7))
+#define PHY_CFG_TX_CHAIN_A BIT(8)
+#define PHY_CFG_TX_CHAIN_B BIT(9)
+#define PHY_CFG_TX_CHAIN_C BIT(10)
+#define PHY_CFG_RX_CHAIN_A BIT(12)
+#define PHY_CFG_RX_CHAIN_B BIT(13)
+#define PHY_CFG_RX_CHAIN_C BIT(14)
+
+
+/* Target of the NVM_ACCESS_CMD */
+enum {
+ NVM_ACCESS_TARGET_CACHE = 0,
+ NVM_ACCESS_TARGET_OTP = 1,
+ NVM_ACCESS_TARGET_EEPROM = 2,
+};
+
+/**
+ * struct iwl_nvm_access_cmd_ver1 - Request the device to send the NVM.
+ * @op_code: 0 - read, 1 - write.
+ * @target: NVM_ACCESS_TARGET_*. should be 0 for read.
+ * @cache_refresh: 0 - None, 1- NVM.
+ * @offset: offset in the nvm data.
+ * @length: of the chunk.
+ * @data: empty on read, the NVM chunk on write
+ */
+struct iwl_nvm_access_cmd_ver1 {
+ u8 op_code;
+ u8 target;
+ u8 cache_refresh;
+ u8 reserved;
+ __le16 offset;
+ __le16 length;
+ u8 data[];
+} __packed; /* NVM_ACCESS_CMD_API_S_VER_1 */
+
+/**
+ * struct iwl_nvm_access_resp_ver1 - response to NVM_ACCESS_CMD
+ * @offset: the offset in the nvm data
+ * @length: of the chunk
+ * @data: the nvm chunk on when NVM_ACCESS_CMD was read, nothing on write
+ */
+struct iwl_nvm_access_resp_ver1 {
+ __le16 offset;
+ __le16 length;
+ u8 data[];
+} __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_1 */
+
+/* Section types for NVM_ACCESS_CMD version 2 */
+enum {
+ NVM_SECTION_TYPE_HW = 0,
+ NVM_SECTION_TYPE_SW,
+ NVM_SECTION_TYPE_PAPD,
+ NVM_SECTION_TYPE_BT,
+ NVM_SECTION_TYPE_CALIBRATION,
+ NVM_SECTION_TYPE_PRODUCTION,
+ NVM_SECTION_TYPE_POST_FCS_CALIB,
+ NVM_NUM_OF_SECTIONS,
+};
+
+/**
+ * struct iwl_nvm_access_cmd_ver2 - Request the device to send an NVM section
+ * @op_code: 0 - read, 1 - write
+ * @target: NVM_ACCESS_TARGET_*
+ * @type: NVM_SECTION_TYPE_*
+ * @offset: offset in bytes into the section
+ * @length: in bytes, to read/write
+ * @data: if write operation, the data to write. On read its empty
+ */
+struct iwl_nvm_access_cmd_ver2 {
+ u8 op_code;
+ u8 target;
+ __le16 type;
+ __le16 offset;
+ __le16 length;
+ u8 data[];
+} __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */
+
+/**
+ * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD
+ * @offset: offset in bytes into the section
+ * @length: in bytes, either how much was written or read
+ * @type: NVM_SECTION_TYPE_*
+ * @status: 0 for success, fail otherwise
+ * @data: if read operation, the data returned. Empty on write.
+ */
+struct iwl_nvm_access_resp_ver2 {
+ __le16 offset;
+ __le16 length;
+ __le16 type;
+ __le16 status;
+ u8 data[];
+} __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_2 */
+
+/* MVM_ALIVE 0x1 */
+
+/* alive response is_valid values */
+#define ALIVE_RESP_UCODE_OK BIT(0)
+#define ALIVE_RESP_RFKILL BIT(1)
+
+/* alive response ver_type values */
+enum {
+ FW_TYPE_HW = 0,
+ FW_TYPE_PROT = 1,
+ FW_TYPE_AP = 2,
+ FW_TYPE_WOWLAN = 3,
+ FW_TYPE_TIMING = 4,
+ FW_TYPE_WIPAN = 5
+};
+
+/* alive response ver_subtype values */
+enum {
+ FW_SUBTYPE_FULL_FEATURE = 0,
+ FW_SUBTYPE_BOOTSRAP = 1, /* Not valid */
+ FW_SUBTYPE_REDUCED = 2,
+ FW_SUBTYPE_ALIVE_ONLY = 3,
+ FW_SUBTYPE_WOWLAN = 4,
+ FW_SUBTYPE_AP_SUBTYPE = 5,
+ FW_SUBTYPE_WIPAN = 6,
+ FW_SUBTYPE_INITIALIZE = 9
+};
+
+#define IWL_ALIVE_STATUS_ERR 0xDEAD
+#define IWL_ALIVE_STATUS_OK 0xCAFE
+
+#define IWL_ALIVE_FLG_RFKILL BIT(0)
+
+struct mvm_alive_resp {
+ __le16 status;
+ __le16 flags;
+ u8 ucode_minor;
+ u8 ucode_major;
+ __le16 id;
+ u8 api_minor;
+ u8 api_major;
+ u8 ver_subtype;
+ u8 ver_type;
+ u8 mac;
+ u8 opt;
+ __le16 reserved2;
+ __le32 timestamp;
+ __le32 error_event_table_ptr; /* SRAM address for error log */
+ __le32 log_event_table_ptr; /* SRAM address for event log */
+ __le32 cpu_register_ptr;
+ __le32 dbgm_config_ptr;
+ __le32 alive_counter_ptr;
+ __le32 scd_base_ptr; /* SRAM address for SCD */
+} __packed; /* ALIVE_RES_API_S_VER_1 */
+
+/* Error response/notification */
+enum {
+ FW_ERR_UNKNOWN_CMD = 0x0,
+ FW_ERR_INVALID_CMD_PARAM = 0x1,
+ FW_ERR_SERVICE = 0x2,
+ FW_ERR_ARC_MEMORY = 0x3,
+ FW_ERR_ARC_CODE = 0x4,
+ FW_ERR_WATCH_DOG = 0x5,
+ FW_ERR_WEP_GRP_KEY_INDX = 0x10,
+ FW_ERR_WEP_KEY_SIZE = 0x11,
+ FW_ERR_OBSOLETE_FUNC = 0x12,
+ FW_ERR_UNEXPECTED = 0xFE,
+ FW_ERR_FATAL = 0xFF
+};
+
+/**
+ * struct iwl_error_resp - FW error indication
+ * ( REPLY_ERROR = 0x2 )
+ * @error_type: one of FW_ERR_*
+ * @cmd_id: the command ID for which the error occured
+ * @bad_cmd_seq_num: sequence number of the erroneous command
+ * @error_service: which service created the error, applicable only if
+ * error_type = 2, otherwise 0
+ * @timestamp: TSF in usecs.
+ */
+struct iwl_error_resp {
+ __le32 error_type;
+ u8 cmd_id;
+ u8 reserved1;
+ __le16 bad_cmd_seq_num;
+ __le32 error_service;
+ __le64 timestamp;
+} __packed;
+
+
+/* Common PHY, MAC and Bindings definitions */
+
+#define MAX_MACS_IN_BINDING (3)
+#define MAX_BINDINGS (4)
+#define AUX_BINDING_INDEX (3)
+#define MAX_PHYS (4)
+
+/* Used to extract ID and color from the context dword */
+#define FW_CTXT_ID_POS (0)
+#define FW_CTXT_ID_MSK (0xff << FW_CTXT_ID_POS)
+#define FW_CTXT_COLOR_POS (8)
+#define FW_CTXT_COLOR_MSK (0xff << FW_CTXT_COLOR_POS)
+#define FW_CTXT_INVALID (0xffffffff)
+
+#define FW_CMD_ID_AND_COLOR(_id, _color) ((_id << FW_CTXT_ID_POS) |\
+ (_color << FW_CTXT_COLOR_POS))
+
+/* Possible actions on PHYs, MACs and Bindings */
+enum {
+ FW_CTXT_ACTION_STUB = 0,
+ FW_CTXT_ACTION_ADD,
+ FW_CTXT_ACTION_MODIFY,
+ FW_CTXT_ACTION_REMOVE,
+ FW_CTXT_ACTION_NUM
+}; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */
+
+/* Time Events */
+
+/* Time Event types, according to MAC type */
+enum iwl_time_event_type {
+ /* BSS Station Events */
+ TE_BSS_STA_AGGRESSIVE_ASSOC,
+ TE_BSS_STA_ASSOC,
+ TE_BSS_EAP_DHCP_PROT,
+ TE_BSS_QUIET_PERIOD,
+
+ /* P2P Device Events */
+ TE_P2P_DEVICE_DISCOVERABLE,
+ TE_P2P_DEVICE_LISTEN,
+ TE_P2P_DEVICE_ACTION_SCAN,
+ TE_P2P_DEVICE_FULL_SCAN,
+
+ /* P2P Client Events */
+ TE_P2P_CLIENT_AGGRESSIVE_ASSOC,
+ TE_P2P_CLIENT_ASSOC,
+ TE_P2P_CLIENT_QUIET_PERIOD,
+
+ /* P2P GO Events */
+ TE_P2P_GO_ASSOC_PROT,
+ TE_P2P_GO_REPETITIVE_NOA,
+ TE_P2P_GO_CT_WINDOW,
+
+ /* WiDi Sync Events */
+ TE_WIDI_TX_SYNC,
+
+ TE_MAX
+}; /* MAC_EVENT_TYPE_API_E_VER_1 */
+
+/* Time Event dependencies: none, on another TE, or in a specific time */
+enum {
+ TE_INDEPENDENT = 0,
+ TE_DEP_OTHER = 1,
+ TE_DEP_TSF = 2,
+ TE_EVENT_SOCIOPATHIC = 4,
+}; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */
+
+/* When to send Time Event notifications and to whom (internal = FW) */
+enum {
+ TE_NOTIF_NONE = 0,
+ TE_NOTIF_HOST_START = 0x1,
+ TE_NOTIF_HOST_END = 0x2,
+ TE_NOTIF_INTERNAL_START = 0x4,
+ TE_NOTIF_INTERNAL_END = 0x8
+}; /* MAC_EVENT_ACTION_API_E_VER_1 */
+
+/*
+ * @TE_FRAG_NONE: fragmentation of the time event is NOT allowed.
+ * @TE_FRAG_SINGLE: fragmentation of the time event is allowed, but only
+ * the first fragment is scheduled.
+ * @TE_FRAG_DUAL: fragmentation of the time event is allowed, but only
+ * the first 2 fragments are scheduled.
+ * @TE_FRAG_ENDLESS: fragmentation of the time event is allowed, and any number
+ * of fragments are valid.
+ *
+ * Other than the constant defined above, specifying a fragmentation value 'x'
+ * means that the event can be fragmented but only the first 'x' will be
+ * scheduled.
+ */
+enum {
+ TE_FRAG_NONE = 0,
+ TE_FRAG_SINGLE = 1,
+ TE_FRAG_DUAL = 2,
+ TE_FRAG_ENDLESS = 0xffffffff
+};
+
+/* Repeat the time event endlessly (until removed) */
+#define TE_REPEAT_ENDLESS (0xffffffff)
+/* If a Time Event has bounded repetitions, this is the maximal value */
+#define TE_REPEAT_MAX_MSK (0x0fffffff)
+/* If a Time Event can be fragmented, this is the max number of fragments */
+#define TE_FRAG_MAX_MSK (0x0fffffff)
+
+/**
+ * struct iwl_time_event_cmd - configuring Time Events
+ * ( TIME_EVENT_CMD = 0x29 )
+ * @id_and_color: ID and color of the relevant MAC
+ * @action: action to perform, one of FW_CTXT_ACTION_*
+ * @id: this field has two meanings, depending on the action:
+ * If the action is ADD, then it means the type of event to add.
+ * For all other actions it is the unique event ID assigned when the
+ * event was added by the FW.
+ * @apply_time: When to start the Time Event (in GP2)
+ * @max_delay: maximum delay to event's start (apply time), in TU
+ * @depends_on: the unique ID of the event we depend on (if any)
+ * @interval: interval between repetitions, in TU
+ * @interval_reciprocal: 2^32 / interval
+ * @duration: duration of event in TU
+ * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS
+ * @dep_policy: one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF
+ * @is_present: 0 or 1, are we present or absent during the Time Event
+ * @max_frags: maximal number of fragments the Time Event can be divided to
+ * @notify: notifications using TE_NOTIF_* (whom to notify when)
+ */
+struct iwl_time_event_cmd {
+ /* COMMON_INDEX_HDR_API_S_VER_1 */
+ __le32 id_and_color;
+ __le32 action;
+ __le32 id;
+ /* MAC_TIME_EVENT_DATA_API_S_VER_1 */
+ __le32 apply_time;
+ __le32 max_delay;
+ __le32 dep_policy;
+ __le32 depends_on;
+ __le32 is_present;
+ __le32 max_frags;
+ __le32 interval;
+ __le32 interval_reciprocal;
+ __le32 duration;
+ __le32 repeat;
+ __le32 notify;
+} __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_1 */
+
+/**
+ * struct iwl_time_event_resp - response structure to iwl_time_event_cmd
+ * @status: bit 0 indicates success, all others specify errors
+ * @id: the Time Event type
+ * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE
+ * @id_and_color: ID and color of the relevant MAC
+ */
+struct iwl_time_event_resp {
+ __le32 status;
+ __le32 id;
+ __le32 unique_id;
+ __le32 id_and_color;
+} __packed; /* MAC_TIME_EVENT_RSP_API_S_VER_1 */
+
+/**
+ * struct iwl_time_event_notif - notifications of time event start/stop
+ * ( TIME_EVENT_NOTIFICATION = 0x2a )
+ * @timestamp: action timestamp in GP2
+ * @session_id: session's unique id
+ * @unique_id: unique id of the Time Event itself
+ * @id_and_color: ID and color of the relevant MAC
+ * @action: one of TE_NOTIF_START or TE_NOTIF_END
+ * @status: true if scheduled, false otherwise (not executed)
+ */
+struct iwl_time_event_notif {
+ __le32 timestamp;
+ __le32 session_id;
+ __le32 unique_id;
+ __le32 id_and_color;
+ __le32 action;
+ __le32 status;
+} __packed; /* MAC_TIME_EVENT_NTFY_API_S_VER_1 */
+
+
+/* Bindings and Time Quota */
+
+/**
+ * struct iwl_binding_cmd - configuring bindings
+ * ( BINDING_CONTEXT_CMD = 0x2b )
+ * @id_and_color: ID and color of the relevant Binding
+ * @action: action to perform, one of FW_CTXT_ACTION_*
+ * @macs: array of MAC id and colors which belong to the binding
+ * @phy: PHY id and color which belongs to the binding
+ */
+struct iwl_binding_cmd {
+ /* COMMON_INDEX_HDR_API_S_VER_1 */
+ __le32 id_and_color;
+ __le32 action;
+ /* BINDING_DATA_API_S_VER_1 */
+ __le32 macs[MAX_MACS_IN_BINDING];
+ __le32 phy;
+} __packed; /* BINDING_CMD_API_S_VER_1 */
+
+/* The maximal number of fragments in the FW's schedule session */
+#define IWL_MVM_MAX_QUOTA 128
+
+/**
+ * struct iwl_time_quota_data - configuration of time quota per binding
+ * @id_and_color: ID and color of the relevant Binding
+ * @quota: absolute time quota in TU. The scheduler will try to divide the
+ * remainig quota (after Time Events) according to this quota.
+ * @max_duration: max uninterrupted context duration in TU
+ */
+struct iwl_time_quota_data {
+ __le32 id_and_color;
+ __le32 quota;
+ __le32 max_duration;
+} __packed; /* TIME_QUOTA_DATA_API_S_VER_1 */
+
+/**
+ * struct iwl_time_quota_cmd - configuration of time quota between bindings
+ * ( TIME_QUOTA_CMD = 0x2c )
+ * @quotas: allocations per binding
+ */
+struct iwl_time_quota_cmd {
+ struct iwl_time_quota_data quotas[MAX_BINDINGS];
+} __packed; /* TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */
+
+
+/* PHY context */
+
+/* Supported bands */
+#define PHY_BAND_5 (0)
+#define PHY_BAND_24 (1)
+
+/* Supported channel width, vary if there is VHT support */
+#define PHY_VHT_CHANNEL_MODE20 (0x0)
+#define PHY_VHT_CHANNEL_MODE40 (0x1)
+#define PHY_VHT_CHANNEL_MODE80 (0x2)
+#define PHY_VHT_CHANNEL_MODE160 (0x3)
+
+/*
+ * Control channel position:
+ * For legacy set bit means upper channel, otherwise lower.
+ * For VHT - bit-2 marks if the control is lower/upper relative to center-freq
+ * bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0.
+ * center_freq
+ * |
+ * 40Mhz |_______|_______|
+ * 80Mhz |_______|_______|_______|_______|
+ * 160Mhz |_______|_______|_______|_______|_______|_______|_______|_______|
+ * code 011 010 001 000 | 100 101 110 111
+ */
+#define PHY_VHT_CTRL_POS_1_BELOW (0x0)
+#define PHY_VHT_CTRL_POS_2_BELOW (0x1)
+#define PHY_VHT_CTRL_POS_3_BELOW (0x2)
+#define PHY_VHT_CTRL_POS_4_BELOW (0x3)
+#define PHY_VHT_CTRL_POS_1_ABOVE (0x4)
+#define PHY_VHT_CTRL_POS_2_ABOVE (0x5)
+#define PHY_VHT_CTRL_POS_3_ABOVE (0x6)
+#define PHY_VHT_CTRL_POS_4_ABOVE (0x7)
+
+/*
+ * @band: PHY_BAND_*
+ * @channel: channel number
+ * @width: PHY_[VHT|LEGACY]_CHANNEL_*
+ * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_*
+ */
+struct iwl_fw_channel_info {
+ u8 band;
+ u8 channel;
+ u8 width;
+ u8 ctrl_pos;
+} __packed;
+
+#define PHY_RX_CHAIN_DRIVER_FORCE_POS (0)
+#define PHY_RX_CHAIN_DRIVER_FORCE_MSK \
+ (0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS)
+#define PHY_RX_CHAIN_VALID_POS (1)
+#define PHY_RX_CHAIN_VALID_MSK \
+ (0x7 << PHY_RX_CHAIN_VALID_POS)
+#define PHY_RX_CHAIN_FORCE_SEL_POS (4)
+#define PHY_RX_CHAIN_FORCE_SEL_MSK \
+ (0x7 << PHY_RX_CHAIN_FORCE_SEL_POS)
+#define PHY_RX_CHAIN_FORCE_MIMO_SEL_POS (7)
+#define PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK \
+ (0x7 << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS)
+#define PHY_RX_CHAIN_CNT_POS (10)
+#define PHY_RX_CHAIN_CNT_MSK \
+ (0x3 << PHY_RX_CHAIN_CNT_POS)
+#define PHY_RX_CHAIN_MIMO_CNT_POS (12)
+#define PHY_RX_CHAIN_MIMO_CNT_MSK \
+ (0x3 << PHY_RX_CHAIN_MIMO_CNT_POS)
+#define PHY_RX_CHAIN_MIMO_FORCE_POS (14)
+#define PHY_RX_CHAIN_MIMO_FORCE_MSK \
+ (0x1 << PHY_RX_CHAIN_MIMO_FORCE_POS)
+
+/* TODO: fix the value, make it depend on firmware at runtime? */
+#define NUM_PHY_CTX 3
+
+/* TODO: complete missing documentation */
+/**
+ * struct iwl_phy_context_cmd - config of the PHY context
+ * ( PHY_CONTEXT_CMD = 0x8 )
+ * @id_and_color: ID and color of the relevant Binding
+ * @action: action to perform, one of FW_CTXT_ACTION_*
+ * @apply_time: 0 means immediate apply and context switch.
+ * other value means apply new params after X usecs
+ * @tx_param_color: ???
+ * @channel_info:
+ * @txchain_info: ???
+ * @rxchain_info: ???
+ * @acquisition_data: ???
+ * @dsp_cfg_flags: set to 0
+ */
+struct iwl_phy_context_cmd {
+ /* COMMON_INDEX_HDR_API_S_VER_1 */
+ __le32 id_and_color;
+ __le32 action;
+ /* PHY_CONTEXT_DATA_API_S_VER_1 */
+ __le32 apply_time;
+ __le32 tx_param_color;
+ struct iwl_fw_channel_info ci;
+ __le32 txchain_info;
+ __le32 rxchain_info;
+ __le32 acquisition_data;
+ __le32 dsp_cfg_flags;
+} __packed; /* PHY_CONTEXT_CMD_API_VER_1 */
+
+#define IWL_RX_INFO_PHY_CNT 8
+#define IWL_RX_INFO_AGC_IDX 1
+#define IWL_RX_INFO_RSSI_AB_IDX 2
+#define IWL_RX_INFO_RSSI_C_IDX 3
+#define IWL_OFDM_AGC_DB_MSK 0xfe00
+#define IWL_OFDM_AGC_DB_POS 9
+#define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff
+#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00
+#define IWL_OFDM_RSSI_A_POS 0
+#define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000
+#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000
+#define IWL_OFDM_RSSI_B_POS 16
+#define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff
+#define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00
+#define IWL_OFDM_RSSI_C_POS 0
+
+/**
+ * struct iwl_rx_phy_info - phy info
+ * (REPLY_RX_PHY_CMD = 0xc0)
+ * @non_cfg_phy_cnt: non configurable DSP phy data byte count
+ * @cfg_phy_cnt: configurable DSP phy data byte count
+ * @stat_id: configurable DSP phy data set ID
+ * @reserved1:
+ * @system_timestamp: GP2 at on air rise
+ * @timestamp: TSF at on air rise
+ * @beacon_time_stamp: beacon at on-air rise
+ * @phy_flags: general phy flags: band, modulation, ...
+ * @channel: channel number
+ * @non_cfg_phy_buf: for various implementations of non_cfg_phy
+ * @rate_n_flags: RATE_MCS_*
+ * @byte_count: frame's byte-count
+ * @frame_time: frame's time on the air, based on byte count and frame rate
+ * calculation
+ *
+ * Before each Rx, the device sends this data. It contains PHY information
+ * about the reception of the packet.
+ */
+struct iwl_rx_phy_info {
+ u8 non_cfg_phy_cnt;
+ u8 cfg_phy_cnt;
+ u8 stat_id;
+ u8 reserved1;
+ __le32 system_timestamp;
+ __le64 timestamp;
+ __le32 beacon_time_stamp;
+ __le16 phy_flags;
+ __le16 channel;
+ __le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT];
+ __le32 rate_n_flags;
+ __le32 byte_count;
+ __le16 reserved2;
+ __le16 frame_time;
+} __packed;
+
+struct iwl_rx_mpdu_res_start {
+ __le16 byte_count;
+ __le16 reserved;
+} __packed;
+
+/**
+ * enum iwl_rx_phy_flags - to parse %iwl_rx_phy_info phy_flags
+ * @RX_RES_PHY_FLAGS_BAND_24: true if the packet was received on 2.4 band
+ * @RX_RES_PHY_FLAGS_MOD_CCK:
+ * @RX_RES_PHY_FLAGS_SHORT_PREAMBLE: true if packet's preamble was short
+ * @RX_RES_PHY_FLAGS_NARROW_BAND:
+ * @RX_RES_PHY_FLAGS_ANTENNA: antenna on which the packet was received
+ * @RX_RES_PHY_FLAGS_AGG: set if the packet was part of an A-MPDU
+ * @RX_RES_PHY_FLAGS_OFDM_HT: The frame was an HT frame
+ * @RX_RES_PHY_FLAGS_OFDM_GF: The frame used GF preamble
+ * @RX_RES_PHY_FLAGS_OFDM_VHT: The frame was a VHT frame
+ */
+enum iwl_rx_phy_flags {
+ RX_RES_PHY_FLAGS_BAND_24 = BIT(0),
+ RX_RES_PHY_FLAGS_MOD_CCK = BIT(1),
+ RX_RES_PHY_FLAGS_SHORT_PREAMBLE = BIT(2),
+ RX_RES_PHY_FLAGS_NARROW_BAND = BIT(3),
+ RX_RES_PHY_FLAGS_ANTENNA = (0x7 << 4),
+ RX_RES_PHY_FLAGS_ANTENNA_POS = 4,
+ RX_RES_PHY_FLAGS_AGG = BIT(7),
+ RX_RES_PHY_FLAGS_OFDM_HT = BIT(8),
+ RX_RES_PHY_FLAGS_OFDM_GF = BIT(9),
+ RX_RES_PHY_FLAGS_OFDM_VHT = BIT(10),
+};
+
+/**
+ * enum iwl_mvm_rx_status - written by fw for each Rx packet
+ * @RX_MPDU_RES_STATUS_CRC_OK: CRC is fine
+ * @RX_MPDU_RES_STATUS_OVERRUN_OK: there was no RXE overflow
+ * @RX_MPDU_RES_STATUS_SRC_STA_FOUND:
+ * @RX_MPDU_RES_STATUS_KEY_VALID:
+ * @RX_MPDU_RES_STATUS_KEY_PARAM_OK:
+ * @RX_MPDU_RES_STATUS_ICV_OK: ICV is fine, if not, the packet is destroyed
+ * @RX_MPDU_RES_STATUS_MIC_OK: used for CCM alg only. TKIP MIC is checked
+ * in the driver.
+ * @RX_MPDU_RES_STATUS_TTAK_OK: TTAK is fine
+ * @RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR: valid for alg = CCM_CMAC or
+ * alg = CCM only. Checks replay attack for 11w frames. Relevant only if
+ * %RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME is set.
+ * @RX_MPDU_RES_STATUS_SEC_NO_ENC: this frame is not encrypted
+ * @RX_MPDU_RES_STATUS_SEC_WEP_ENC: this frame is encrypted using WEP
+ * @RX_MPDU_RES_STATUS_SEC_CCM_ENC: this frame is encrypted using CCM
+ * @RX_MPDU_RES_STATUS_SEC_TKIP_ENC: this frame is encrypted using TKIP
+ * @RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC: this frame is encrypted using CCM_CMAC
+ * @RX_MPDU_RES_STATUS_SEC_ENC_ERR: this frame couldn't be decrypted
+ * @RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm
+ * @RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted
+ * @RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP:
+ * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP:
+ * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT:
+ * @RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame
+ * @RX_MPDU_RES_STATUS_HASH_INDEX_MSK:
+ * @RX_MPDU_RES_STATUS_STA_ID_MSK:
+ * @RX_MPDU_RES_STATUS_RRF_KILL:
+ * @RX_MPDU_RES_STATUS_FILTERING_MSK:
+ * @RX_MPDU_RES_STATUS2_FILTERING_MSK:
+ */
+enum iwl_mvm_rx_status {
+ RX_MPDU_RES_STATUS_CRC_OK = BIT(0),
+ RX_MPDU_RES_STATUS_OVERRUN_OK = BIT(1),
+ RX_MPDU_RES_STATUS_SRC_STA_FOUND = BIT(2),
+ RX_MPDU_RES_STATUS_KEY_VALID = BIT(3),
+ RX_MPDU_RES_STATUS_KEY_PARAM_OK = BIT(4),
+ RX_MPDU_RES_STATUS_ICV_OK = BIT(5),
+ RX_MPDU_RES_STATUS_MIC_OK = BIT(6),
+ RX_MPDU_RES_STATUS_TTAK_OK = BIT(7),
+ RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR = BIT(7),
+ RX_MPDU_RES_STATUS_SEC_NO_ENC = (0 << 8),
+ RX_MPDU_RES_STATUS_SEC_WEP_ENC = (1 << 8),
+ RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8),
+ RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8),
+ RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC = (6 << 8),
+ RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8),
+ RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8),
+ RX_MPDU_RES_STATUS_DEC_DONE = BIT(11),
+ RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP = BIT(12),
+ RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP = BIT(13),
+ RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT = BIT(14),
+ RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME = BIT(15),
+ RX_MPDU_RES_STATUS_HASH_INDEX_MSK = (0x3F0000),
+ RX_MPDU_RES_STATUS_STA_ID_MSK = (0x1f000000),
+ RX_MPDU_RES_STATUS_RRF_KILL = BIT(29),
+ RX_MPDU_RES_STATUS_FILTERING_MSK = (0xc00000),
+ RX_MPDU_RES_STATUS2_FILTERING_MSK = (0xc0000000),
+};
+
+/**
+ * struct iwl_radio_version_notif - information on the radio version
+ * ( RADIO_VERSION_NOTIFICATION = 0x68 )
+ * @radio_flavor:
+ * @radio_step:
+ * @radio_dash:
+ */
+struct iwl_radio_version_notif {
+ __le32 radio_flavor;
+ __le32 radio_step;
+ __le32 radio_dash;
+} __packed; /* RADIO_VERSION_NOTOFICATION_S_VER_1 */
+
+enum iwl_card_state_flags {
+ CARD_ENABLED = 0x00,
+ HW_CARD_DISABLED = 0x01,
+ SW_CARD_DISABLED = 0x02,
+ CT_KILL_CARD_DISABLED = 0x04,
+ HALT_CARD_DISABLED = 0x08,
+ CARD_DISABLED_MSK = 0x0f,
+ CARD_IS_RX_ON = 0x10,
+};
+
+/**
+ * struct iwl_radio_version_notif - information on the radio version
+ * ( CARD_STATE_NOTIFICATION = 0xa1 )
+ * @flags: %iwl_card_state_flags
+ */
+struct iwl_card_state_notif {
+ __le32 flags;
+} __packed; /* CARD_STATE_NTFY_API_S_VER_1 */
+
+/**
+ * struct iwl_set_calib_default_cmd - set default value for calibration.
+ * ( SET_CALIB_DEFAULT_CMD = 0x8e )
+ * @calib_index: the calibration to set value for
+ * @length: of data
+ * @data: the value to set for the calibration result
+ */
+struct iwl_set_calib_default_cmd {
+ __le16 calib_index;
+ __le16 length;
+ u8 data[0];
+} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */
+
+#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
new file mode 100644
index 000000000000..d3d959db03a9
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.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) 2012 - 2013 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) 2012 - 2013 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 <net/mac80211.h>
+
+#include "iwl-trans.h"
+#include "iwl-op-mode.h"
+#include "iwl-fw.h"
+#include "iwl-debug.h"
+#include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */
+#include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */
+#include "iwl-eeprom-parse.h"
+
+#include "mvm.h"
+#include "iwl-phy-db.h"
+
+#define MVM_UCODE_ALIVE_TIMEOUT HZ
+#define MVM_UCODE_CALIB_TIMEOUT (2*HZ)
+
+#define UCODE_VALID_OK cpu_to_le32(0x1)
+
+/* Default calibration values for WkP - set to INIT image w/o running */
+static const u8 wkp_calib_values_bb_filter[] = { 0xbf, 0x00, 0x5f, 0x00, 0x2f,
+ 0x00, 0x18, 0x00 };
+static const u8 wkp_calib_values_rx_dc[] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f };
+static const u8 wkp_calib_values_tx_lo[] = { 0x00, 0x00, 0x00, 0x00 };
+static const u8 wkp_calib_values_tx_iq[] = { 0xff, 0x00, 0xff, 0x00, 0x00,
+ 0x00 };
+static const u8 wkp_calib_values_rx_iq[] = { 0xff, 0x00, 0x00, 0x00 };
+static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 };
+static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 };
+static const u8 wkp_calib_values_xtal[] = { 0xd2, 0xd2 };
+
+struct iwl_calib_default_data {
+ u16 size;
+ void *data;
+};
+
+#define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf}
+
+static const struct iwl_calib_default_data wkp_calib_default_data[12] = {
+ [5] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_dc),
+ [6] = CALIB_SIZE_N_DATA(wkp_calib_values_bb_filter),
+ [7] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_lo),
+ [8] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq),
+ [9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew),
+ [10] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq),
+ [11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew),
+};
+
+struct iwl_mvm_alive_data {
+ bool valid;
+ u32 scd_base_addr;
+};
+
+static inline const struct fw_img *
+iwl_get_ucode_image(struct iwl_mvm *mvm, enum iwl_ucode_type ucode_type)
+{
+ if (ucode_type >= IWL_UCODE_TYPE_MAX)
+ return NULL;
+
+ return &mvm->fw->img[ucode_type];
+}
+
+static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant)
+{
+ struct iwl_tx_ant_cfg_cmd tx_ant_cmd = {
+ .valid = cpu_to_le32(valid_tx_ant),
+ };
+
+ IWL_DEBUG_HC(mvm, "select valid tx ant: %u\n", valid_tx_ant);
+ return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, CMD_SYNC,
+ sizeof(tx_ant_cmd), &tx_ant_cmd);
+}
+
+static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
+ struct iwl_rx_packet *pkt, void *data)
+{
+ struct iwl_mvm *mvm =
+ container_of(notif_wait, struct iwl_mvm, notif_wait);
+ struct iwl_mvm_alive_data *alive_data = data;
+ struct mvm_alive_resp *palive;
+
+ palive = (void *)pkt->data;
+
+ mvm->error_event_table = le32_to_cpu(palive->error_event_table_ptr);
+ mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr);
+ alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
+
+ alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK;
+ IWL_DEBUG_FW(mvm, "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n",
+ le16_to_cpu(palive->status), palive->ver_type,
+ palive->ver_subtype);
+
+ return true;
+}
+
+static bool iwl_wait_phy_db_entry(struct iwl_notif_wait_data *notif_wait,
+ struct iwl_rx_packet *pkt, void *data)
+{
+ struct iwl_phy_db *phy_db = data;
+
+ if (pkt->hdr.cmd != CALIB_RES_NOTIF_PHY_DB) {
+ WARN_ON(pkt->hdr.cmd != INIT_COMPLETE_NOTIF);
+ return true;
+ }
+
+ WARN_ON(iwl_phy_db_set_section(phy_db, pkt, GFP_ATOMIC));
+
+ return false;
+}
+
+static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
+ enum iwl_ucode_type ucode_type)
+{
+ struct iwl_notification_wait alive_wait;
+ struct iwl_mvm_alive_data alive_data;
+ const struct fw_img *fw;
+ int ret, i;
+ enum iwl_ucode_type old_type = mvm->cur_ucode;
+ static const u8 alive_cmd[] = { MVM_ALIVE };
+
+ mvm->cur_ucode = ucode_type;
+ fw = iwl_get_ucode_image(mvm, ucode_type);
+
+ mvm->ucode_loaded = false;
+
+ if (!fw)
+ return -EINVAL;
+
+ iwl_init_notification_wait(&mvm->notif_wait, &alive_wait,
+ alive_cmd, ARRAY_SIZE(alive_cmd),
+ iwl_alive_fn, &alive_data);
+
+ ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT);
+ if (ret) {
+ mvm->cur_ucode = old_type;
+ iwl_remove_notification(&mvm->notif_wait, &alive_wait);
+ return ret;
+ }
+
+ /*
+ * Some things may run in the background now, but we
+ * just wait for the ALIVE notification here.
+ */
+ ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait,
+ MVM_UCODE_ALIVE_TIMEOUT);
+ if (ret) {
+ mvm->cur_ucode = old_type;
+ return ret;
+ }
+
+ if (!alive_data.valid) {
+ IWL_ERR(mvm, "Loaded ucode is not valid!\n");
+ mvm->cur_ucode = old_type;
+ return -EIO;
+ }
+
+ iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr);
+
+ /*
+ * Note: all the queues are enabled as part of the interface
+ * initialization, but in firmware restart scenarios they
+ * could be stopped, so wake them up. In firmware restart,
+ * mac80211 will have the queues stopped as well until the
+ * reconfiguration completes. During normal startup, they
+ * will be empty.
+ */
+
+ for (i = 0; i < IWL_MAX_HW_QUEUES; i++) {
+ if (i < IWL_MVM_FIRST_AGG_QUEUE && i != IWL_MVM_CMD_QUEUE)
+ mvm->queue_to_mac80211[i] = i;
+ else
+ mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
+ atomic_set(&mvm->queue_stop_count[i], 0);
+ }
+
+ mvm->transport_queue_stop = 0;
+
+ mvm->ucode_loaded = true;
+
+ return 0;
+}
+#define IWL_HW_REV_ID_RAINBOW 0x2
+#define IWL_PROJ_TYPE_LHP 0x5
+
+static u32 iwl_mvm_build_phy_cfg(struct iwl_mvm *mvm)
+{
+ struct iwl_nvm_data *data = mvm->nvm_data;
+ /* Temp calls to static definitions, will be changed to CSR calls */
+ u8 hw_rev_id = IWL_HW_REV_ID_RAINBOW;
+ u8 project_type = IWL_PROJ_TYPE_LHP;
+
+ return data->radio_cfg_dash | (data->radio_cfg_step << 2) |
+ (hw_rev_id << 4) | ((project_type & 0x7f) << 6) |
+ (data->valid_tx_ant << 16) | (data->valid_rx_ant << 20);
+}
+
+static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
+{
+ struct iwl_phy_cfg_cmd phy_cfg_cmd;
+ enum iwl_ucode_type ucode_type = mvm->cur_ucode;
+
+ /* Set parameters */
+ phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_build_phy_cfg(mvm));
+ phy_cfg_cmd.calib_control.event_trigger =
+ mvm->fw->default_calib[ucode_type].event_trigger;
+ phy_cfg_cmd.calib_control.flow_trigger =
+ mvm->fw->default_calib[ucode_type].flow_trigger;
+
+ IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n",
+ phy_cfg_cmd.phy_cfg);
+
+ return iwl_mvm_send_cmd_pdu(mvm, PHY_CONFIGURATION_CMD, CMD_SYNC,
+ sizeof(phy_cfg_cmd), &phy_cfg_cmd);
+}
+
+/* Starting with the new PHY DB implementation - New calibs are enabled */
+/* Value - 0x405e7 */
+#define IWL_CALIB_DEFAULT_FLOW_INIT (IWL_CALIB_CFG_XTAL_IDX |\
+ IWL_CALIB_CFG_TEMPERATURE_IDX |\
+ IWL_CALIB_CFG_VOLTAGE_READ_IDX |\
+ IWL_CALIB_CFG_DC_IDX |\
+ IWL_CALIB_CFG_BB_FILTER_IDX |\
+ IWL_CALIB_CFG_LO_LEAKAGE_IDX |\
+ IWL_CALIB_CFG_TX_IQ_IDX |\
+ IWL_CALIB_CFG_RX_IQ_IDX |\
+ IWL_CALIB_CFG_AGC_IDX)
+
+#define IWL_CALIB_DEFAULT_EVENT_INIT 0x0
+
+/* Value 0x41567 */
+#define IWL_CALIB_DEFAULT_FLOW_RUN (IWL_CALIB_CFG_XTAL_IDX |\
+ IWL_CALIB_CFG_TEMPERATURE_IDX |\
+ IWL_CALIB_CFG_VOLTAGE_READ_IDX |\
+ IWL_CALIB_CFG_BB_FILTER_IDX |\
+ IWL_CALIB_CFG_DC_IDX |\
+ IWL_CALIB_CFG_TX_IQ_IDX |\
+ IWL_CALIB_CFG_RX_IQ_IDX |\
+ IWL_CALIB_CFG_SENSITIVITY_IDX |\
+ IWL_CALIB_CFG_AGC_IDX)
+
+#define IWL_CALIB_DEFAULT_EVENT_RUN (IWL_CALIB_CFG_XTAL_IDX |\
+ IWL_CALIB_CFG_TEMPERATURE_IDX |\
+ IWL_CALIB_CFG_VOLTAGE_READ_IDX |\
+ IWL_CALIB_CFG_TX_PWR_IDX |\
+ IWL_CALIB_CFG_DC_IDX |\
+ IWL_CALIB_CFG_TX_IQ_IDX |\
+ IWL_CALIB_CFG_SENSITIVITY_IDX)
+
+/*
+ * Sets the calibrations trigger values that will be sent to the FW for runtime
+ * and init calibrations.
+ * The ones given in the FW TLV are not correct.
+ */
+static void iwl_set_default_calib_trigger(struct iwl_mvm *mvm)
+{
+ struct iwl_tlv_calib_ctrl default_calib;
+
+ /*
+ * WkP FW TLV calib bits are wrong, overwrite them.
+ * This defines the dynamic calibrations which are implemented in the
+ * uCode both for init(flow) calculation and event driven calibs.
+ */
+
+ /* Init Image */
+ default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_INIT);
+ default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_INIT);
+
+ if (default_calib.event_trigger !=
+ mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger)
+ IWL_ERR(mvm,
+ "Updating the event calib for INIT image: 0x%x -> 0x%x\n",
+ mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger,
+ default_calib.event_trigger);
+ if (default_calib.flow_trigger !=
+ mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger)
+ IWL_ERR(mvm,
+ "Updating the flow calib for INIT image: 0x%x -> 0x%x\n",
+ mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger,
+ default_calib.flow_trigger);
+
+ memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_INIT],
+ &default_calib, sizeof(struct iwl_tlv_calib_ctrl));
+ IWL_ERR(mvm,
+ "Setting uCode init calibrations event 0x%x, trigger 0x%x\n",
+ default_calib.event_trigger,
+ default_calib.flow_trigger);
+
+ /* Run time image */
+ default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_RUN);
+ default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_RUN);
+
+ if (default_calib.event_trigger !=
+ mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger)
+ IWL_ERR(mvm,
+ "Updating the event calib for RT image: 0x%x -> 0x%x\n",
+ mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger,
+ default_calib.event_trigger);
+ if (default_calib.flow_trigger !=
+ mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger)
+ IWL_ERR(mvm,
+ "Updating the flow calib for RT image: 0x%x -> 0x%x\n",
+ mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger,
+ default_calib.flow_trigger);
+
+ memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_REGULAR],
+ &default_calib, sizeof(struct iwl_tlv_calib_ctrl));
+ IWL_ERR(mvm,
+ "Setting uCode runtime calibs event 0x%x, trigger 0x%x\n",
+ default_calib.event_trigger,
+ default_calib.flow_trigger);
+}
+
+static int iwl_set_default_calibrations(struct iwl_mvm *mvm)
+{
+ u8 cmd_raw[16]; /* holds the variable size commands */
+ struct iwl_set_calib_default_cmd *cmd =
+ (struct iwl_set_calib_default_cmd *)cmd_raw;
+ int ret, i;
+
+ /* Setting default values for calibrations we don't run */
+ for (i = 0; i < ARRAY_SIZE(wkp_calib_default_data); i++) {
+ u16 cmd_len;
+
+ if (wkp_calib_default_data[i].size == 0)
+ continue;
+
+ memset(cmd_raw, 0, sizeof(cmd_raw));
+ cmd_len = wkp_calib_default_data[i].size + sizeof(cmd);
+ cmd->calib_index = cpu_to_le16(i);
+ cmd->length = cpu_to_le16(wkp_calib_default_data[i].size);
+ if (WARN_ONCE(cmd_len > sizeof(cmd_raw),
+ "Need to enlarge cmd_raw to %d\n", cmd_len))
+ break;
+ memcpy(cmd->data, wkp_calib_default_data[i].data,
+ wkp_calib_default_data[i].size);
+ ret = iwl_mvm_send_cmd_pdu(mvm, SET_CALIB_DEFAULT_CMD, 0,
+ sizeof(*cmd) +
+ wkp_calib_default_data[i].size,
+ cmd);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
+{
+ struct iwl_notification_wait calib_wait;
+ static const u8 init_complete[] = {
+ INIT_COMPLETE_NOTIF,
+ CALIB_RES_NOTIF_PHY_DB
+ };
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (mvm->init_ucode_run)
+ return 0;
+
+ iwl_init_notification_wait(&mvm->notif_wait,
+ &calib_wait,
+ init_complete,
+ ARRAY_SIZE(init_complete),
+ iwl_wait_phy_db_entry,
+ mvm->phy_db);
+
+ /* Will also start the device */
+ ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_INIT);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to start INIT ucode: %d\n", ret);
+ goto error;
+ }
+
+ if (read_nvm) {
+ /* Read nvm */
+ ret = iwl_nvm_init(mvm);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to read NVM: %d\n", ret);
+ goto error;
+ }
+ }
+
+ ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);
+ WARN_ON(ret);
+
+ /* Override the calibrations from TLV and the const of fw */
+ iwl_set_default_calib_trigger(mvm);
+
+ /* WkP doesn't have all calibrations, need to set default values */
+ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+ ret = iwl_set_default_calibrations(mvm);
+ if (ret)
+ goto error;
+ }
+
+ /*
+ * Send phy configurations command to init uCode
+ * to start the 16.0 uCode init image internal calibrations.
+ */
+ ret = iwl_send_phy_cfg_cmd(mvm);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n",
+ ret);
+ goto error;
+ }
+
+ /*
+ * Some things may run in the background now, but we
+ * just wait for the calibration complete notification.
+ */
+ ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait,
+ MVM_UCODE_CALIB_TIMEOUT);
+ if (!ret)
+ mvm->init_ucode_run = true;
+ goto out;
+
+error:
+ iwl_remove_notification(&mvm->notif_wait, &calib_wait);
+out:
+ if (!iwlmvm_mod_params.init_dbg) {
+ iwl_trans_stop_device(mvm->trans);
+ } else if (!mvm->nvm_data) {
+ /* we want to debug INIT and we have no NVM - fake */
+ mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) +
+ sizeof(struct ieee80211_channel) +
+ sizeof(struct ieee80211_rate),
+ GFP_KERNEL);
+ if (!mvm->nvm_data)
+ return -ENOMEM;
+ mvm->nvm_data->valid_rx_ant = 1;
+ mvm->nvm_data->valid_tx_ant = 1;
+ mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels;
+ mvm->nvm_data->bands[0].n_channels = 1;
+ mvm->nvm_data->bands[0].n_bitrates = 1;
+ mvm->nvm_data->bands[0].bitrates =
+ (void *)mvm->nvm_data->channels + 1;
+ mvm->nvm_data->bands[0].bitrates->hw_value = 10;
+ }
+
+ return ret;
+}
+
+#define UCODE_CALIB_TIMEOUT (2*HZ)
+
+int iwl_mvm_up(struct iwl_mvm *mvm)
+{
+ int ret, i;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ ret = iwl_trans_start_hw(mvm->trans);
+ if (ret)
+ return ret;
+
+ /* If we were in RFKILL during module loading, load init ucode now */
+ if (!mvm->init_ucode_run) {
+ ret = iwl_run_init_mvm_ucode(mvm, false);
+ if (ret && !iwlmvm_mod_params.init_dbg) {
+ IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
+ goto error;
+ }
+ }
+
+ if (iwlmvm_mod_params.init_dbg)
+ return 0;
+
+ ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret);
+ goto error;
+ }
+
+ ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
+ if (ret)
+ goto error;
+
+ /* Send phy db control command and then phy db calibration*/
+ ret = iwl_send_phy_db_data(mvm->phy_db);
+ if (ret)
+ goto error;
+
+ ret = iwl_send_phy_cfg_cmd(mvm);
+ if (ret)
+ goto error;
+
+ /* init the fw <-> mac80211 STA mapping */
+ for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
+ RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
+
+ /* Add auxiliary station for scanning */
+ ret = iwl_mvm_add_aux_sta(mvm);
+ if (ret)
+ goto error;
+
+ IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
+
+ return 0;
+ error:
+ iwl_trans_stop_device(mvm->trans);
+ return ret;
+}
+
+int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
+{
+ int ret, i;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ ret = iwl_trans_start_hw(mvm->trans);
+ if (ret)
+ return ret;
+
+ ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_WOWLAN);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to start WoWLAN firmware: %d\n", ret);
+ goto error;
+ }
+
+ ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
+ if (ret)
+ goto error;
+
+ /* Send phy db control command and then phy db calibration*/
+ ret = iwl_send_phy_db_data(mvm->phy_db);
+ if (ret)
+ goto error;
+
+ ret = iwl_send_phy_cfg_cmd(mvm);
+ if (ret)
+ goto error;
+
+ /* init the fw <-> mac80211 STA mapping */
+ for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
+ RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
+
+ /* Add auxiliary station for scanning */
+ ret = iwl_mvm_add_aux_sta(mvm);
+ if (ret)
+ goto error;
+
+ return 0;
+ error:
+ iwl_trans_stop_device(mvm->trans);
+ return ret;
+}
+
+int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_card_state_notif *card_state_notif = (void *)pkt->data;
+ u32 flags = le32_to_cpu(card_state_notif->flags);
+
+ IWL_DEBUG_RF_KILL(mvm, "Card state received: HW:%s SW:%s CT:%s\n",
+ (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+ (flags & SW_CARD_DISABLED) ? "Kill" : "On",
+ (flags & CT_KILL_CARD_DISABLED) ?
+ "Reached" : "Not reached");
+
+ return 0;
+}
+
+int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_radio_version_notif *radio_version = (void *)pkt->data;
+
+ /* TODO: what to do with that? */
+ IWL_DEBUG_INFO(mvm,
+ "Radio version: flavor: 0x%08x, step 0x%08x, dash 0x%08x\n",
+ le32_to_cpu(radio_version->radio_flavor),
+ le32_to_cpu(radio_version->radio_step),
+ le32_to_cpu(radio_version->radio_dash));
+ return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/led.c b/drivers/net/wireless/iwlwifi/mvm/led.c
new file mode 100644
index 000000000000..011906e73a05
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/led.c
@@ -0,0 +1,134 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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/leds.h>
+#include "iwl-io.h"
+#include "iwl-csr.h"
+#include "mvm.h"
+
+/* Set led register on */
+static void iwl_mvm_led_enable(struct iwl_mvm *mvm)
+{
+ iwl_write32(mvm->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON);
+}
+
+/* Set led register off */
+static void iwl_mvm_led_disable(struct iwl_mvm *mvm)
+{
+ iwl_write32(mvm->trans, CSR_LED_REG, CSR_LED_REG_TURN_OFF);
+}
+
+static void iwl_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct iwl_mvm *mvm = container_of(led_cdev, struct iwl_mvm, led);
+ if (brightness > 0)
+ iwl_mvm_led_enable(mvm);
+ else
+ iwl_mvm_led_disable(mvm);
+}
+
+int iwl_mvm_leds_init(struct iwl_mvm *mvm)
+{
+ int mode = iwlwifi_mod_params.led_mode;
+ int ret;
+
+ switch (mode) {
+ case IWL_LED_DEFAULT:
+ case IWL_LED_RF_STATE:
+ mode = IWL_LED_RF_STATE;
+ break;
+ case IWL_LED_DISABLE:
+ IWL_INFO(mvm, "Led disabled\n");
+ return 0;
+ default:
+ return -EINVAL;
+ };
+
+ mvm->led.name = kasprintf(GFP_KERNEL, "%s-led",
+ wiphy_name(mvm->hw->wiphy));
+ mvm->led.brightness_set = iwl_led_brightness_set;
+ mvm->led.max_brightness = 1;
+
+ if (mode == IWL_LED_RF_STATE)
+ mvm->led.default_trigger =
+ ieee80211_get_radio_led_name(mvm->hw);
+
+ ret = led_classdev_register(mvm->trans->dev, &mvm->led);
+ if (ret) {
+ kfree(mvm->led.name);
+ IWL_INFO(mvm, "Failed to enable led\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+void iwl_mvm_leds_exit(struct iwl_mvm *mvm)
+{
+ if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE)
+ return;
+
+ led_classdev_unregister(&mvm->led);
+ kfree(mvm->led.name);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
new file mode 100644
index 000000000000..341dbc0237ea
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -0,0 +1,992 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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/etherdevice.h>
+#include <net/mac80211.h>
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "fw-api.h"
+#include "mvm.h"
+
+const u8 iwl_mvm_ac_to_tx_fifo[] = {
+ IWL_MVM_TX_FIFO_BK,
+ IWL_MVM_TX_FIFO_BE,
+ IWL_MVM_TX_FIFO_VI,
+ IWL_MVM_TX_FIFO_VO,
+};
+
+struct iwl_mvm_mac_iface_iterator_data {
+ struct iwl_mvm *mvm;
+ struct ieee80211_vif *vif;
+ unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)];
+ unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)];
+ unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_FIRST_AGG_QUEUE)];
+ enum iwl_tsf_id preferred_tsf;
+ bool found_vif;
+};
+
+static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_mac_iface_iterator_data *data = _data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ u32 ac;
+
+ /* Iterator may already find the interface being added -- skip it */
+ if (vif == data->vif) {
+ data->found_vif = true;
+ return;
+ }
+
+ /* Mark the queues used by the vif */
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
+ __set_bit(vif->hw_queue[ac], data->used_hw_queues);
+
+ if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
+ __set_bit(vif->cab_queue, data->used_hw_queues);
+
+ /*
+ * Mark MAC IDs as used by clearing the available bit, and
+ * (below) mark TSFs as used if their existing use is not
+ * compatible with the new interface type.
+ * No locking or atomic bit operations are needed since the
+ * data is on the stack of the caller function.
+ */
+ __clear_bit(mvmvif->id, data->available_mac_ids);
+
+ /*
+ * The TSF is a hardware/firmware resource, there are 4 and
+ * the driver should assign and free them as needed. However,
+ * there are cases where 2 MACs should share the same TSF ID
+ * for the purpose of clock sync, an optimization to avoid
+ * clock drift causing overlapping TBTTs/DTIMs for a GO and
+ * client in the system.
+ *
+ * The firmware will decide according to the MAC type which
+ * will be the master and slave. Clients that need to sync
+ * with a remote station will be the master, and an AP or GO
+ * will be the slave.
+ *
+ * Depending on the new interface type it can be slaved to
+ * or become the master of an existing interface.
+ */
+ switch (data->vif->type) {
+ case NL80211_IFTYPE_STATION:
+ /*
+ * The new interface is client, so if the existing one
+ * we're iterating is an AP, the TSF should be used to
+ * avoid drift between the new client and existing AP,
+ * the existing AP will get drift updates from the new
+ * client context in this case
+ */
+ if (vif->type == NL80211_IFTYPE_AP) {
+ if (data->preferred_tsf == NUM_TSF_IDS &&
+ test_bit(mvmvif->tsf_id, data->available_tsf_ids))
+ data->preferred_tsf = mvmvif->tsf_id;
+ return;
+ }
+ break;
+ case NL80211_IFTYPE_AP:
+ /*
+ * The new interface is AP/GO, so should get drift
+ * updates from an existing client or use the same
+ * TSF as an existing GO. There's no drift between
+ * TSFs internally but if they used different TSFs
+ * then a new client MAC could update one of them
+ * and cause drift that way.
+ */
+ if (vif->type == NL80211_IFTYPE_STATION ||
+ vif->type == NL80211_IFTYPE_AP) {
+ if (data->preferred_tsf == NUM_TSF_IDS &&
+ test_bit(mvmvif->tsf_id, data->available_tsf_ids))
+ data->preferred_tsf = mvmvif->tsf_id;
+ return;
+ }
+ break;
+ default:
+ /*
+ * For all other interface types there's no need to
+ * take drift into account. Either they're exclusive
+ * like IBSS and monitor, or we don't care much about
+ * their TSF (like P2P Device), but we won't be able
+ * to share the TSF resource.
+ */
+ break;
+ }
+
+ /*
+ * Unless we exited above, we can't share the TSF resource
+ * that the virtual interface we're iterating over is using
+ * with the new one, so clear the available bit and if this
+ * was the preferred one, reset that as well.
+ */
+ __clear_bit(mvmvif->tsf_id, data->available_tsf_ids);
+
+ if (data->preferred_tsf == mvmvif->tsf_id)
+ data->preferred_tsf = NUM_TSF_IDS;
+}
+
+/*
+ * Get the mask of the queus used by the vif
+ */
+u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ u32 qmask, ac;
+
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
+ return BIT(IWL_OFFCHANNEL_QUEUE);
+
+ qmask = (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) ?
+ BIT(vif->cab_queue) : 0;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
+ qmask |= BIT(vif->hw_queue[ac]);
+
+ return qmask;
+}
+
+static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_mac_iface_iterator_data data = {
+ .mvm = mvm,
+ .vif = vif,
+ .available_mac_ids = { (1 << NUM_MAC_INDEX_DRIVER) - 1 },
+ .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 },
+ /* no preference yet */
+ .preferred_tsf = NUM_TSF_IDS,
+ .used_hw_queues = {
+ BIT(IWL_MVM_OFFCHANNEL_QUEUE) |
+ BIT(IWL_MVM_AUX_QUEUE) |
+ BIT(IWL_MVM_CMD_QUEUE)
+ },
+ .found_vif = false,
+ };
+ u32 ac;
+ int ret;
+
+ /*
+ * Allocate a MAC ID and a TSF for this MAC, along with the queues
+ * and other resources.
+ */
+
+ /*
+ * Before the iterator, we start with all MAC IDs and TSFs available.
+ *
+ * During iteration, all MAC IDs are cleared that are in use by other
+ * virtual interfaces, and all TSF IDs are cleared that can't be used
+ * by this new virtual interface because they're used by an interface
+ * that can't share it with the new one.
+ * At the same time, we check if there's a preferred TSF in the case
+ * that we should share it with another interface.
+ */
+
+ /* Currently, MAC ID 0 should be used only for the managed vif */
+ if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+ __clear_bit(0, data.available_mac_ids);
+
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+ iwl_mvm_mac_iface_iterator, &data);
+
+ /*
+ * In the case we're getting here during resume, it's similar to
+ * firmware restart, and with RESUME_ALL the iterator will find
+ * the vif being added already.
+ * We don't want to reassign any IDs in either case since doing
+ * so would probably assign different IDs (as interfaces aren't
+ * necessarily added in the same order), but the old IDs were
+ * preserved anyway, so skip ID assignment for both resume and
+ * recovery.
+ */
+ if (data.found_vif)
+ return 0;
+
+ /* Therefore, in recovery, we can't get here */
+ WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status));
+
+ mvmvif->id = find_first_bit(data.available_mac_ids,
+ NUM_MAC_INDEX_DRIVER);
+ if (mvmvif->id == NUM_MAC_INDEX_DRIVER) {
+ IWL_ERR(mvm, "Failed to init MAC context - no free ID!\n");
+ ret = -EIO;
+ goto exit_fail;
+ }
+
+ if (data.preferred_tsf != NUM_TSF_IDS)
+ mvmvif->tsf_id = data.preferred_tsf;
+ else
+ mvmvif->tsf_id = find_first_bit(data.available_tsf_ids,
+ NUM_TSF_IDS);
+ if (mvmvif->tsf_id == NUM_TSF_IDS) {
+ IWL_ERR(mvm, "Failed to init MAC context - no free TSF!\n");
+ ret = -EIO;
+ goto exit_fail;
+ }
+
+ mvmvif->color = 0;
+
+ INIT_LIST_HEAD(&mvmvif->time_event_data.list);
+ mvmvif->time_event_data.id = TE_MAX;
+
+ /* No need to allocate data queues to P2P Device MAC.*/
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE;
+
+ return 0;
+ }
+
+ /* Find available queues, and allocate them to the ACs */
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ u8 queue = find_first_zero_bit(data.used_hw_queues,
+ IWL_MVM_FIRST_AGG_QUEUE);
+
+ if (queue >= IWL_MVM_FIRST_AGG_QUEUE) {
+ IWL_ERR(mvm, "Failed to allocate queue\n");
+ ret = -EIO;
+ goto exit_fail;
+ }
+
+ __set_bit(queue, data.used_hw_queues);
+ vif->hw_queue[ac] = queue;
+ }
+
+ /* Allocate the CAB queue for softAP and GO interfaces */
+ if (vif->type == NL80211_IFTYPE_AP) {
+ u8 queue = find_first_zero_bit(data.used_hw_queues,
+ IWL_MVM_FIRST_AGG_QUEUE);
+
+ if (queue >= IWL_MVM_FIRST_AGG_QUEUE) {
+ IWL_ERR(mvm, "Failed to allocate cab queue\n");
+ ret = -EIO;
+ goto exit_fail;
+ }
+
+ vif->cab_queue = queue;
+ } else {
+ vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+ }
+
+ mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT;
+ mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
+
+ return 0;
+
+exit_fail:
+ memset(mvmvif, 0, sizeof(struct iwl_mvm_vif));
+ memset(vif->hw_queue, IEEE80211_INVAL_HW_QUEUE, sizeof(vif->hw_queue));
+ vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+ return ret;
+}
+
+int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ u32 ac;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ ret = iwl_mvm_mac_ctxt_allocate_resources(mvm, vif);
+ if (ret)
+ return ret;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_P2P_DEVICE:
+ iwl_trans_ac_txq_enable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE,
+ IWL_MVM_TX_FIFO_VO);
+ break;
+ case NL80211_IFTYPE_AP:
+ iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue,
+ IWL_MVM_TX_FIFO_VO);
+ /* fall through */
+ default:
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ iwl_trans_ac_txq_enable(mvm->trans, vif->hw_queue[ac],
+ iwl_mvm_ac_to_tx_fifo[ac]);
+ break;
+ }
+
+ return 0;
+}
+
+void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ int ac;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_P2P_DEVICE:
+ iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE);
+ break;
+ case NL80211_IFTYPE_AP:
+ iwl_trans_txq_disable(mvm->trans, vif->cab_queue);
+ /* fall through */
+ default:
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac]);
+ }
+}
+
+static void iwl_mvm_ack_rates(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ enum ieee80211_band band,
+ u8 *cck_rates, u8 *ofdm_rates)
+{
+ struct ieee80211_supported_band *sband;
+ unsigned long basic = vif->bss_conf.basic_rates;
+ int lowest_present_ofdm = 100;
+ int lowest_present_cck = 100;
+ u8 cck = 0;
+ u8 ofdm = 0;
+ int i;
+
+ sband = mvm->hw->wiphy->bands[band];
+
+ for_each_set_bit(i, &basic, BITS_PER_LONG) {
+ int hw = sband->bitrates[i].hw_value;
+ if (hw >= IWL_FIRST_OFDM_RATE) {
+ ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE);
+ if (lowest_present_ofdm > hw)
+ lowest_present_ofdm = hw;
+ } else {
+ BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
+
+ cck |= BIT(hw);
+ if (lowest_present_cck > hw)
+ lowest_present_cck = hw;
+ }
+ }
+
+ /*
+ * Now we've got the basic rates as bitmaps in the ofdm and cck
+ * variables. This isn't sufficient though, as there might not
+ * be all the right rates in the bitmap. E.g. if the only basic
+ * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps
+ * and 6 Mbps because the 802.11-2007 standard says in 9.6:
+ *
+ * [...] a STA responding to a received frame shall transmit
+ * its Control Response frame [...] at the highest rate in the
+ * BSSBasicRateSet parameter that is less than or equal to the
+ * rate of the immediately previous frame in the frame exchange
+ * sequence ([...]) and that is of the same modulation class
+ * ([...]) as the received frame. If no rate contained in the
+ * BSSBasicRateSet parameter meets these conditions, then the
+ * control frame sent in response to a received frame shall be
+ * transmitted at the highest mandatory rate of the PHY that is
+ * less than or equal to the rate of the received frame, and
+ * that is of the same modulation class as the received frame.
+ *
+ * As a consequence, we need to add all mandatory rates that are
+ * lower than all of the basic rates to these bitmaps.
+ */
+
+ if (IWL_RATE_24M_INDEX < lowest_present_ofdm)
+ ofdm |= IWL_RATE_BIT_MSK(24) >> IWL_FIRST_OFDM_RATE;
+ if (IWL_RATE_12M_INDEX < lowest_present_ofdm)
+ ofdm |= IWL_RATE_BIT_MSK(12) >> IWL_FIRST_OFDM_RATE;
+ /* 6M already there or needed so always add */
+ ofdm |= IWL_RATE_BIT_MSK(6) >> IWL_FIRST_OFDM_RATE;
+
+ /*
+ * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP.
+ * Note, however:
+ * - if no CCK rates are basic, it must be ERP since there must
+ * be some basic rates at all, so they're OFDM => ERP PHY
+ * (or we're in 5 GHz, and the cck bitmap will never be used)
+ * - if 11M is a basic rate, it must be ERP as well, so add 5.5M
+ * - if 5.5M is basic, 1M and 2M are mandatory
+ * - if 2M is basic, 1M is mandatory
+ * - if 1M is basic, that's the only valid ACK rate.
+ * As a consequence, it's not as complicated as it sounds, just add
+ * any lower rates to the ACK rate bitmap.
+ */
+ if (IWL_RATE_11M_INDEX < lowest_present_cck)
+ cck |= IWL_RATE_BIT_MSK(11) >> IWL_FIRST_CCK_RATE;
+ if (IWL_RATE_5M_INDEX < lowest_present_cck)
+ cck |= IWL_RATE_BIT_MSK(5) >> IWL_FIRST_CCK_RATE;
+ if (IWL_RATE_2M_INDEX < lowest_present_cck)
+ cck |= IWL_RATE_BIT_MSK(2) >> IWL_FIRST_CCK_RATE;
+ /* 1M already there or needed so always add */
+ cck |= IWL_RATE_BIT_MSK(1) >> IWL_FIRST_CCK_RATE;
+
+ *cck_rates = cck;
+ *ofdm_rates = ofdm;
+}
+
+static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_mac_ctx_cmd *cmd,
+ u32 action)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct ieee80211_chanctx_conf *chanctx;
+ u8 cck_ack_rates, ofdm_ack_rates;
+ int i;
+
+ cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+ mvmvif->color));
+ cmd->action = cpu_to_le32(action);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ if (vif->p2p)
+ cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_P2P_STA);
+ else
+ cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_BSS_STA);
+ break;
+ case NL80211_IFTYPE_AP:
+ cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_GO);
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_LISTENER);
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_P2P_DEVICE);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ cmd->mac_type = cpu_to_le32(FW_MAC_TYPE_IBSS);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+
+ cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id);
+
+ memcpy(cmd->node_addr, vif->addr, ETH_ALEN);
+ if (vif->bss_conf.bssid)
+ memcpy(cmd->bssid_addr, vif->bss_conf.bssid, ETH_ALEN);
+ else
+ eth_broadcast_addr(cmd->bssid_addr);
+
+ rcu_read_lock();
+ chanctx = rcu_dereference(vif->chanctx_conf);
+ iwl_mvm_ack_rates(mvm, vif, chanctx ? chanctx->def.chan->band
+ : IEEE80211_BAND_2GHZ,
+ &cck_ack_rates, &ofdm_ack_rates);
+ rcu_read_unlock();
+
+ cmd->cck_rates = cpu_to_le32((u32)cck_ack_rates);
+ cmd->ofdm_rates = cpu_to_le32((u32)ofdm_ack_rates);
+
+ cmd->cck_short_preamble =
+ cpu_to_le32(vif->bss_conf.use_short_preamble ?
+ MAC_FLG_SHORT_PREAMBLE : 0);
+ cmd->short_slot =
+ cpu_to_le32(vif->bss_conf.use_short_slot ?
+ MAC_FLG_SHORT_SLOT : 0);
+
+ for (i = 0; i < AC_NUM; i++) {
+ cmd->ac[i].cw_min = cpu_to_le16(mvmvif->queue_params[i].cw_min);
+ cmd->ac[i].cw_max = cpu_to_le16(mvmvif->queue_params[i].cw_max);
+ cmd->ac[i].aifsn = mvmvif->queue_params[i].aifs;
+ cmd->ac[i].edca_txop =
+ cpu_to_le16(mvmvif->queue_params[i].txop * 32);
+ cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]);
+ }
+
+ if (vif->bss_conf.qos)
+ cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
+
+ if (vif->bss_conf.use_cts_prot)
+ cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT |
+ MAC_PROT_FLG_SELF_CTS_EN);
+
+ /*
+ * I think that we should enable these 2 flags regardless the HT PROT
+ * fields in the HT IE, but I am not sure. Someone knows whom to ask?...
+ */
+ if (vif->bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
+ cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN);
+ cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_HT_PROT |
+ MAC_PROT_FLG_FAT_PROT);
+ }
+
+ cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP);
+}
+
+static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
+ struct iwl_mac_ctx_cmd *cmd)
+{
+ int ret = iwl_mvm_send_cmd_pdu(mvm, MAC_CONTEXT_CMD, CMD_SYNC,
+ sizeof(*cmd), cmd);
+ if (ret)
+ IWL_ERR(mvm, "Failed to send MAC context (action:%d): %d\n",
+ le32_to_cpu(cmd->action), ret);
+ return ret;
+}
+
+/*
+ * Fill the specific data for mac context of type station or p2p client
+ */
+static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_mac_data_sta *ctxt_sta)
+{
+ /* We need the dtim_period to set the MAC as associated */
+ if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) {
+ u32 dtim_offs;
+
+ /*
+ * The DTIM count counts down, so when it is N that means N
+ * more beacon intervals happen until the DTIM TBTT. Therefore
+ * add this to the current time. If that ends up being in the
+ * future, the firmware will handle it.
+ *
+ * Also note that the system_timestamp (which we get here as
+ * "sync_device_ts") and TSF timestamp aren't at exactly the
+ * same offset in the frame -- the TSF is at the first symbol
+ * of the TSF, the system timestamp is at signal acquisition
+ * time. This means there's an offset between them of at most
+ * a few hundred microseconds (24 * 8 bits + PLCP time gives
+ * 384us in the longest case), this is currently not relevant
+ * as the firmware wakes up around 2ms before the TBTT.
+ */
+ dtim_offs = vif->bss_conf.sync_dtim_count *
+ vif->bss_conf.beacon_int;
+ /* convert TU to usecs */
+ dtim_offs *= 1024;
+
+ ctxt_sta->dtim_tsf =
+ cpu_to_le64(vif->bss_conf.sync_tsf + dtim_offs);
+ ctxt_sta->dtim_time =
+ cpu_to_le32(vif->bss_conf.sync_device_ts + dtim_offs);
+
+ IWL_DEBUG_INFO(mvm, "DTIM TBTT is 0x%llx/0x%x, offset %d\n",
+ le64_to_cpu(ctxt_sta->dtim_tsf),
+ le32_to_cpu(ctxt_sta->dtim_time),
+ dtim_offs);
+
+ ctxt_sta->is_assoc = cpu_to_le32(1);
+ } else {
+ ctxt_sta->is_assoc = cpu_to_le32(0);
+ }
+
+ ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int);
+ ctxt_sta->bi_reciprocal =
+ cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int));
+ ctxt_sta->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int *
+ vif->bss_conf.dtim_period);
+ ctxt_sta->dtim_reciprocal =
+ cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int *
+ vif->bss_conf.dtim_period));
+
+ ctxt_sta->listen_interval = cpu_to_le32(mvm->hw->conf.listen_interval);
+ ctxt_sta->assoc_id = cpu_to_le32(vif->bss_conf.aid);
+}
+
+static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 action)
+{
+ struct iwl_mac_ctx_cmd cmd = {};
+
+ WARN_ON(vif->type != NL80211_IFTYPE_STATION || vif->p2p);
+
+ /* Fill the common data for all mac context types */
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+
+ /* Fill the data specific for station mode */
+ iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta);
+
+ return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 action)
+{
+ struct iwl_mac_ctx_cmd cmd = {};
+
+ WARN_ON(vif->type != NL80211_IFTYPE_STATION || !vif->p2p);
+
+ /* Fill the common data for all mac context types */
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+
+ /* Fill the data specific for station mode */
+ iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta);
+
+ cmd.p2p_sta.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow);
+
+ return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 action)
+{
+ struct iwl_mac_ctx_cmd cmd = {};
+
+ WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
+
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ /* No other data to be filled */
+ return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+struct iwl_mvm_go_iterator_data {
+ bool go_active;
+};
+
+static void iwl_mvm_go_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_go_iterator_data *data = _data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (vif->type == NL80211_IFTYPE_AP && vif->p2p && mvmvif->ap_active)
+ data->go_active = true;
+}
+
+static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 action)
+{
+ struct iwl_mac_ctx_cmd cmd = {};
+ struct iwl_mvm_go_iterator_data data = {};
+
+ WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
+
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+
+ cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
+ cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROMISC);
+
+ /*
+ * This flag should be set to true when the P2P Device is
+ * discoverable and there is at least another active P2P GO. Settings
+ * this flag will allow the P2P Device to be discoverable on other
+ * channels in addition to its listen channel.
+ * Note that this flag should not be set in other cases as it opens the
+ * Rx filters on all MAC and increases the number of interrupts.
+ */
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+ iwl_mvm_go_iterator, &data);
+
+ cmd.p2p_dev.is_disc_extended = cpu_to_le32(data.go_active ? 1 : 0);
+ return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
+ struct iwl_mac_beacon_cmd *beacon_cmd,
+ u8 *beacon, u32 frame_size)
+{
+ u32 tim_idx;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
+
+ /* The index is relative to frame start but we start looking at the
+ * variable-length part of the beacon. */
+ tim_idx = mgmt->u.beacon.variable - beacon;
+
+ /* Parse variable-length elements of beacon to find WLAN_EID_TIM */
+ while ((tim_idx < (frame_size - 2)) &&
+ (beacon[tim_idx] != WLAN_EID_TIM))
+ tim_idx += beacon[tim_idx+1] + 2;
+
+ /* If TIM field was found, set variables */
+ if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) {
+ beacon_cmd->tim_idx = cpu_to_le32(tim_idx);
+ beacon_cmd->tim_size = cpu_to_le32((u32)beacon[tim_idx+1]);
+ } else {
+ IWL_WARN(mvm, "Unable to find TIM Element in beacon\n");
+ }
+}
+
+static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct sk_buff *beacon)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_host_cmd cmd = {
+ .id = BEACON_TEMPLATE_CMD,
+ .flags = CMD_ASYNC,
+ };
+ struct iwl_mac_beacon_cmd beacon_cmd = {};
+ struct ieee80211_tx_info *info;
+ u32 beacon_skb_len;
+ u32 rate;
+
+ if (WARN_ON(!beacon))
+ return -EINVAL;
+
+ beacon_skb_len = beacon->len;
+
+ /* TODO: for now the beacon template id is set to be the mac context id.
+ * Might be better to handle it as another resource ... */
+ beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
+
+ /* Set up TX command fields */
+ beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len);
+ beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id;
+ beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
+ beacon_cmd.tx.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
+ TX_CMD_FLG_BT_DIS |
+ TX_CMD_FLG_TSF);
+
+ mvm->mgmt_last_antenna_idx =
+ iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+ mvm->mgmt_last_antenna_idx);
+
+ beacon_cmd.tx.rate_n_flags =
+ cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
+ RATE_MCS_ANT_POS);
+
+ info = IEEE80211_SKB_CB(beacon);
+
+ if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) {
+ rate = IWL_FIRST_OFDM_RATE;
+ } else {
+ rate = IWL_FIRST_CCK_RATE;
+ beacon_cmd.tx.rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK);
+ }
+ beacon_cmd.tx.rate_n_flags |=
+ cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate));
+
+ /* Set up TX beacon command fields */
+ iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd,
+ beacon->data,
+ beacon_skb_len);
+
+ /* Submit command */
+ cmd.len[0] = sizeof(beacon_cmd);
+ cmd.data[0] = &beacon_cmd;
+ cmd.dataflags[0] = 0;
+ cmd.len[1] = beacon_skb_len;
+ cmd.data[1] = beacon->data;
+ cmd.dataflags[1] = IWL_HCMD_DFL_DUP;
+
+ return iwl_mvm_send_cmd(mvm, &cmd);
+}
+
+/* The beacon template for the AP/GO context has changed and needs update */
+int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ struct sk_buff *beacon;
+ int ret;
+
+ WARN_ON(vif->type != NL80211_IFTYPE_AP);
+
+ beacon = ieee80211_beacon_get(mvm->hw, vif);
+ if (!beacon)
+ return -ENOMEM;
+
+ ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon);
+ dev_kfree_skb(beacon);
+ return ret;
+}
+
+/*
+ * Fill the specific data for mac context of type AP of P2P GO
+ */
+static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_mac_data_ap *ctxt_ap)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ u32 curr_dev_time;
+
+ ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int);
+ ctxt_ap->bi_reciprocal =
+ cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int));
+ ctxt_ap->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int *
+ vif->bss_conf.dtim_period);
+ ctxt_ap->dtim_reciprocal =
+ cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int *
+ vif->bss_conf.dtim_period));
+
+ ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue);
+ curr_dev_time = iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
+ ctxt_ap->beacon_time = cpu_to_le32(curr_dev_time);
+
+ ctxt_ap->beacon_tsf = cpu_to_le64(curr_dev_time);
+
+ /* TODO: Assume that the beacon id == mac context id */
+ ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id);
+}
+
+static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 action)
+{
+ struct iwl_mac_ctx_cmd cmd = {};
+
+ WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p);
+
+ /* Fill the common data for all mac context types */
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+
+ /* Fill the data specific for ap mode */
+ iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap);
+
+ return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 action)
+{
+ struct iwl_mac_ctx_cmd cmd = {};
+
+ WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p);
+
+ /* Fill the common data for all mac context types */
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+
+ /* Fill the data specific for GO mode */
+ iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap);
+
+ cmd.go.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow);
+ cmd.go.opp_ps_enabled = cpu_to_le32(!!vif->bss_conf.p2p_oppps);
+
+ return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
+}
+
+static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ u32 action)
+{
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ if (!vif->p2p)
+ return iwl_mvm_mac_ctxt_cmd_station(mvm, vif,
+ action);
+ else
+ return iwl_mvm_mac_ctxt_cmd_p2p_client(mvm, vif,
+ action);
+ break;
+ case NL80211_IFTYPE_AP:
+ if (!vif->p2p)
+ return iwl_mvm_mac_ctxt_cmd_ap(mvm, vif, action);
+ else
+ return iwl_mvm_mac_ctxt_cmd_go(mvm, vif, action);
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ return iwl_mvm_mac_ctxt_cmd_listener(mvm, vif, action);
+ case NL80211_IFTYPE_P2P_DEVICE:
+ return iwl_mvm_mac_ctxt_cmd_p2p_device(mvm, vif, action);
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int ret;
+
+ if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n",
+ vif->addr, ieee80211_vif_type_p2p(vif)))
+ return -EIO;
+
+ ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD);
+ if (ret)
+ return ret;
+
+ mvmvif->uploaded = true;
+ return 0;
+}
+
+int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n",
+ vif->addr, ieee80211_vif_type_p2p(vif)))
+ return -EIO;
+
+ return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY);
+}
+
+int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mac_ctx_cmd cmd;
+ int ret;
+
+ if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n",
+ vif->addr, ieee80211_vif_type_p2p(vif)))
+ return -EIO;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+ mvmvif->color));
+ cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, MAC_CONTEXT_CMD, CMD_SYNC,
+ sizeof(cmd), &cmd);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to remove MAC context: %d\n", ret);
+ return ret;
+ }
+
+ mvmvif->uploaded = false;
+ return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
new file mode 100644
index 000000000000..e8264e11b12d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -0,0 +1,1314 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+
+#include "iwl-op-mode.h"
+#include "iwl-io.h"
+#include "mvm.h"
+#include "sta.h"
+#include "time-event.h"
+#include "iwl-eeprom-parse.h"
+#include "fw-api-scan.h"
+#include "iwl-phy-db.h"
+
+static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
+ },
+};
+
+static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
+ {
+ .num_different_channels = 1,
+ .max_interfaces = 3,
+ .limits = iwl_mvm_limits,
+ .n_limits = ARRAY_SIZE(iwl_mvm_limits),
+ },
+};
+
+int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
+{
+ struct ieee80211_hw *hw = mvm->hw;
+ int num_mac, ret;
+
+ /* Tell mac80211 our characteristics */
+ hw->flags = IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+ IEEE80211_HW_QUEUE_CONTROL |
+ IEEE80211_HW_WANT_MONITOR_VIF |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
+ IEEE80211_HW_AMPDU_AGGREGATION |
+ IEEE80211_HW_TIMING_BEACON_ONLY;
+
+ hw->queues = IWL_FIRST_AMPDU_QUEUE;
+ hw->offchannel_tx_hw_queue = IWL_OFFCHANNEL_QUEUE;
+ hw->rate_control_algorithm = "iwl-mvm-rs";
+
+ /*
+ * Enable 11w if advertised by firmware and software crypto
+ * is not enabled (as the firmware will interpret some mgmt
+ * packets, so enabling it with software crypto isn't safe)
+ */
+ if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP &&
+ !iwlwifi_mod_params.sw_crypto)
+ hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
+ hw->sta_data_size = sizeof(struct iwl_mvm_sta);
+ hw->vif_data_size = sizeof(struct iwl_mvm_vif);
+ hw->chanctx_data_size = sizeof(struct iwl_mvm_phy_ctxt);
+
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
+
+ hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+ WIPHY_FLAG_DISABLE_BEACON_HINTS |
+ WIPHY_FLAG_IBSS_RSN;
+
+ hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
+ hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(iwl_mvm_iface_combinations);
+
+ hw->wiphy->max_remain_on_channel_duration = 500;
+ hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+
+ /* Extract MAC address */
+ memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
+ hw->wiphy->addresses = mvm->addresses;
+ hw->wiphy->n_addresses = 1;
+ num_mac = mvm->nvm_data->n_hw_addrs;
+ if (num_mac > 1) {
+ memcpy(mvm->addresses[1].addr, mvm->addresses[0].addr,
+ ETH_ALEN);
+ mvm->addresses[1].addr[5]++;
+ hw->wiphy->n_addresses++;
+ }
+
+ /* we create the 802.11 header and a max-length SSID element */
+ hw->wiphy->max_scan_ie_len =
+ mvm->fw->ucode_capa.max_probe_length - 24 - 34;
+ hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+
+ if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels)
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
+ if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels)
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
+
+ hw->wiphy->hw_version = mvm->trans->hw_id;
+
+ if (iwlwifi_mod_params.power_save)
+ hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+ else
+ hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+ hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
+ NL80211_FEATURE_P2P_GO_OPPPS;
+
+ mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+
+#ifdef CONFIG_PM_SLEEP
+ if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
+ mvm->trans->ops->d3_suspend &&
+ mvm->trans->ops->d3_resume &&
+ device_can_wakeup(mvm->trans->dev)) {
+ hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+ WIPHY_WOWLAN_DISCONNECT |
+ WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+ WIPHY_WOWLAN_RFKILL_RELEASE;
+ if (!iwlwifi_mod_params.sw_crypto)
+ hw->wiphy->wowlan.flags |=
+ WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+ WIPHY_WOWLAN_GTK_REKEY_FAILURE |
+ WIPHY_WOWLAN_4WAY_HANDSHAKE;
+
+ hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
+ hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
+ hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
+ }
+#endif
+
+ ret = iwl_mvm_leds_init(mvm);
+ if (ret)
+ return ret;
+
+ return ieee80211_register_hw(mvm->hw);
+}
+
+static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ if (test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status)) {
+ IWL_DEBUG_DROP(mvm, "Dropping - RF KILL\n");
+ goto drop;
+ }
+
+ if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_OFFCHANNEL_QUEUE &&
+ !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
+ goto drop;
+
+ if (control->sta) {
+ if (iwl_mvm_tx_skb(mvm, skb, control->sta))
+ goto drop;
+ return;
+ }
+
+ if (iwl_mvm_tx_skb_non_sta(mvm, skb))
+ goto drop;
+ return;
+ drop:
+ ieee80211_free_txskb(hw, skb);
+}
+
+static int iwl_mvm_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_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
+ sta->addr, tid, action);
+
+ if (!(mvm->nvm_data->sku_cap_11n_enable))
+ return -EACCES;
+
+ mutex_lock(&mvm->mutex);
+
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true);
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
+ break;
+ case IEEE80211_AMPDU_TX_START:
+ ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn);
+ break;
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+ ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);
+ break;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ mvmvif->uploaded = false;
+ mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
+
+ /* does this make sense at all? */
+ mvmvif->color++;
+
+ spin_lock_bh(&mvm->time_event_lock);
+ iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data);
+ spin_unlock_bh(&mvm->time_event_lock);
+
+ if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
+ mvmvif->phy_ctxt = NULL;
+}
+
+static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
+{
+ iwl_trans_stop_device(mvm->trans);
+ iwl_trans_stop_hw(mvm->trans, false);
+
+ mvm->scan_status = IWL_MVM_SCAN_NONE;
+
+ /* just in case one was running */
+ ieee80211_remain_on_channel_expired(mvm->hw);
+
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+ iwl_mvm_cleanup_iterator, mvm);
+
+ memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
+ memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
+
+ ieee80211_wake_queues(mvm->hw);
+
+ mvm->vif_count = 0;
+}
+
+static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+
+ /* Clean up some internal and mac80211 state on restart */
+ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ iwl_mvm_restart_cleanup(mvm);
+
+ ret = iwl_mvm_up(mvm);
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+
+ clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+ ret = iwl_mvm_update_quotas(mvm, NULL);
+ if (ret)
+ IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",
+ ret);
+
+ mutex_unlock(&mvm->mutex);
+}
+
+static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ flush_work(&mvm->async_handlers_wk);
+
+ mutex_lock(&mvm->mutex);
+ /* async_handlers_wk is now blocked */
+
+ /*
+ * The work item could be running or queued if the
+ * ROC time event stops just as we get here.
+ */
+ cancel_work_sync(&mvm->roc_done_wk);
+
+ iwl_trans_stop_device(mvm->trans);
+ iwl_trans_stop_hw(mvm->trans, false);
+
+ iwl_mvm_async_handlers_purge(mvm);
+ /* async_handlers_list is empty and will stay empty: HW is stopped */
+
+ /* the fw is stopped, the aux sta is dead: clean up driver state */
+ iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+
+ mutex_unlock(&mvm->mutex);
+
+ /*
+ * The worker might have been waiting for the mutex, let it run and
+ * discover that its list is now empty.
+ */
+ cancel_work_sync(&mvm->async_handlers_wk);
+}
+
+static void iwl_mvm_pm_disable_iterator(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = data;
+ int ret;
+
+ ret = iwl_mvm_power_disable(mvm, vif);
+ if (ret)
+ IWL_ERR(mvm, "failed to disable power management\n");
+}
+
+static void iwl_mvm_power_update_iterator(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = data;
+
+ iwl_mvm_power_update_mode(mvm, vif);
+}
+
+static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int ret;
+
+ /*
+ * Not much to do here. The stack will not allow interface
+ * types or combinations that we didn't advertise, so we
+ * don't really have to check the types.
+ */
+
+ mutex_lock(&mvm->mutex);
+
+ /* Allocate resources for the MAC context, and add it the the fw */
+ ret = iwl_mvm_mac_ctxt_init(mvm, vif);
+ if (ret)
+ goto out_unlock;
+
+ /*
+ * The AP binding flow can be done only after the beacon
+ * template is configured (which happens only in the mac80211
+ * start_ap() flow), and adding the broadcast station can happen
+ * only after the binding.
+ * In addition, since modifying the MAC before adding a bcast
+ * station is not allowed by the FW, delay the adding of MAC context to
+ * the point where we can also add the bcast station.
+ * In short: there's not much we can do at this point, other than
+ * allocating resources :)
+ */
+ if (vif->type == NL80211_IFTYPE_AP) {
+ u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+ ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta,
+ qmask);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to allocate bcast sta\n");
+ goto out_release;
+ }
+
+ goto out_unlock;
+ }
+
+ /*
+ * TODO: remove this temporary code.
+ * Currently MVM FW supports power management only on single MAC.
+ * Iterate and disable PM on all active interfaces.
+ * Note: the method below does not count the new interface being added
+ * at this moment.
+ */
+ mvm->vif_count++;
+ if (mvm->vif_count > 1) {
+ IWL_DEBUG_MAC80211(mvm,
+ "Disable power on existing interfaces\n");
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_pm_disable_iterator, mvm);
+ }
+
+ ret = iwl_mvm_mac_ctxt_add(mvm, vif);
+ if (ret)
+ goto out_release;
+
+ /*
+ * Update power state on the new interface. Admittedly, based on
+ * mac80211 logics this power update will disable power management
+ */
+ iwl_mvm_power_update_mode(mvm, vif);
+
+ /*
+ * P2P_DEVICE interface does not have a channel context assigned to it,
+ * so a dedicated PHY context is allocated to it and the corresponding
+ * MAC context is bound to it at this stage.
+ */
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ struct ieee80211_channel *chan;
+ struct cfg80211_chan_def chandef;
+
+ mvmvif->phy_ctxt = &mvm->phy_ctxt_roc;
+
+ /*
+ * The channel used here isn't relevant as it's
+ * going to be overwritten as part of the ROC flow.
+ * For now use the first channel we have.
+ */
+ chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0];
+ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+ ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt,
+ &chandef, 1, 1);
+ if (ret)
+ goto out_remove_mac;
+
+ ret = iwl_mvm_binding_add_vif(mvm, vif);
+ if (ret)
+ goto out_remove_phy;
+
+ ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
+ if (ret)
+ goto out_unbind;
+
+ /* Save a pointer to p2p device vif, so it can later be used to
+ * update the p2p device MAC when a GO is started/stopped */
+ mvm->p2p_device_vif = vif;
+ }
+
+ goto out_unlock;
+
+ out_unbind:
+ iwl_mvm_binding_remove_vif(mvm, vif);
+ out_remove_phy:
+ iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
+ out_remove_mac:
+ mvmvif->phy_ctxt = NULL;
+ iwl_mvm_mac_ctxt_remove(mvm, vif);
+ out_release:
+ /*
+ * TODO: remove this temporary code.
+ * Currently MVM FW supports power management only on single MAC.
+ * Check if only one additional interface remains after rereasing
+ * current one. Update power mode on the remaining interface.
+ */
+ mvm->vif_count--;
+ IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
+ mvm->vif_count);
+ if (mvm->vif_count == 1) {
+ ieee80211_iterate_active_interfaces(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_power_update_iterator, mvm);
+ }
+ iwl_mvm_mac_ctxt_release(mvm, vif);
+ out_unlock:
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ u32 tfd_msk = 0, ac;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
+ tfd_msk |= BIT(vif->hw_queue[ac]);
+
+ if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
+ tfd_msk |= BIT(vif->cab_queue);
+
+ if (tfd_msk) {
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_flush_tx_path(mvm, tfd_msk, true);
+ mutex_unlock(&mvm->mutex);
+ }
+
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ /*
+ * Flush the ROC worker which will flush the OFFCHANNEL queue.
+ * We assume here that all the packets sent to the OFFCHANNEL
+ * queue are sent in ROC session.
+ */
+ flush_work(&mvm->roc_done_wk);
+ } else {
+ /*
+ * By now, all the AC queues are empty. The AGG queues are
+ * empty too. We already got all the Tx responses for all the
+ * packets in the queues. The drain work can have been
+ * triggered. Flush it. This work item takes the mutex, so kill
+ * it before we take it.
+ */
+ flush_work(&mvm->sta_drained_wk);
+ }
+
+ mutex_lock(&mvm->mutex);
+
+ /*
+ * For AP/GO interface, the tear down of the resources allocated to the
+ * interface should be handled as part of the bss_info_changed flow.
+ */
+ if (vif->type == NL80211_IFTYPE_AP) {
+ iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
+ goto out_release;
+ }
+
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ mvm->p2p_device_vif = NULL;
+ iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+ iwl_mvm_binding_remove_vif(mvm, vif);
+ iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt);
+ mvmvif->phy_ctxt = NULL;
+ }
+
+ /*
+ * TODO: remove this temporary code.
+ * Currently MVM FW supports power management only on single MAC.
+ * Check if only one additional interface remains after removing
+ * current one. Update power mode on the remaining interface.
+ */
+ if (mvm->vif_count)
+ mvm->vif_count--;
+ IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
+ mvm->vif_count);
+ if (mvm->vif_count == 1) {
+ ieee80211_iterate_active_interfaces(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_power_update_iterator, mvm);
+ }
+
+ iwl_mvm_mac_ctxt_remove(mvm, vif);
+
+out_release:
+ iwl_mvm_mac_ctxt_release(mvm, vif);
+ mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed)
+{
+ return 0;
+}
+
+static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ u64 multicast)
+{
+ *total_flags = 0;
+}
+
+static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int ret;
+
+ ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
+ if (ret)
+ IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
+
+ if (changes & BSS_CHANGED_ASSOC) {
+ if (bss_conf->assoc) {
+ /* add quota for this interface */
+ ret = iwl_mvm_update_quotas(mvm, vif);
+ if (ret) {
+ IWL_ERR(mvm, "failed to update quotas\n");
+ return;
+ }
+ } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+ /* remove AP station now that the MAC is unassoc */
+ ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
+ if (ret)
+ IWL_ERR(mvm, "failed to remove AP station\n");
+ mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
+ /* remove quota for this interface */
+ ret = iwl_mvm_update_quotas(mvm, NULL);
+ if (ret)
+ IWL_ERR(mvm, "failed to update quotas\n");
+ }
+ } else if (changes & BSS_CHANGED_DTIM_PERIOD) {
+ /*
+ * We received a beacon _after_ association so
+ * remove the session protection.
+ */
+ iwl_mvm_remove_time_event(mvm, mvmvif,
+ &mvmvif->time_event_data);
+ } else if (changes & BSS_CHANGED_PS) {
+ /*
+ * TODO: remove this temporary code.
+ * Currently MVM FW supports power management only on single
+ * MAC. Avoid power mode update if more than one interface
+ * is active.
+ */
+ IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
+ mvm->vif_count);
+ if (mvm->vif_count == 1) {
+ ret = iwl_mvm_power_update_mode(mvm, vif);
+ if (ret)
+ IWL_ERR(mvm, "failed to update power mode\n");
+ }
+ }
+}
+
+static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+
+ /* Send the beacon template */
+ ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif);
+ if (ret)
+ goto out_unlock;
+
+ /* Add the mac context */
+ ret = iwl_mvm_mac_ctxt_add(mvm, vif);
+ if (ret)
+ goto out_unlock;
+
+ /* Perform the binding */
+ ret = iwl_mvm_binding_add_vif(mvm, vif);
+ if (ret)
+ goto out_remove;
+
+ mvmvif->ap_active = true;
+
+ /* Send the bcast station. At this stage the TBTT and DTIM time events
+ * are added and applied to the scheduler */
+ ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
+ if (ret)
+ goto out_unbind;
+
+ ret = iwl_mvm_update_quotas(mvm, vif);
+ if (ret)
+ goto out_rm_bcast;
+
+ /* Need to update the P2P Device MAC */
+ if (vif->p2p && mvm->p2p_device_vif)
+ iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif);
+
+ mutex_unlock(&mvm->mutex);
+ return 0;
+
+out_rm_bcast:
+ iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+out_unbind:
+ iwl_mvm_binding_remove_vif(mvm, vif);
+out_remove:
+ iwl_mvm_mac_ctxt_remove(mvm, vif);
+out_unlock:
+ mutex_unlock(&mvm->mutex);
+ return ret;
+}
+
+static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ mutex_lock(&mvm->mutex);
+
+ mvmvif->ap_active = false;
+
+ /* Need to update the P2P Device MAC */
+ if (vif->p2p && mvm->p2p_device_vif)
+ iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif);
+
+ iwl_mvm_update_quotas(mvm, NULL);
+ iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+ iwl_mvm_binding_remove_vif(mvm, vif);
+ iwl_mvm_mac_ctxt_remove(mvm, vif);
+
+ mutex_unlock(&mvm->mutex);
+}
+
+static void iwl_mvm_bss_info_changed_ap(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes)
+{
+ /* Need to send a new beacon template to the FW */
+ if (changes & BSS_CHANGED_BEACON) {
+ if (iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
+ IWL_WARN(mvm, "Failed updating beacon data\n");
+ }
+}
+
+static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ mutex_lock(&mvm->mutex);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes);
+ break;
+ case NL80211_IFTYPE_AP:
+ iwl_mvm_bss_info_changed_ap(mvm, vif, bss_conf, changes);
+ break;
+ default:
+ /* shouldn't happen */
+ WARN_ON_ONCE(1);
+ }
+
+ mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_scan_request *req)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS)
+ return -EINVAL;
+
+ mutex_lock(&mvm->mutex);
+
+ if (mvm->scan_status == IWL_MVM_SCAN_NONE)
+ ret = iwl_mvm_scan_request(mvm, vif, req);
+ else
+ ret = -EBUSY;
+
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ mutex_lock(&mvm->mutex);
+
+ iwl_mvm_cancel_scan(mvm);
+
+ mutex_unlock(&mvm->mutex);
+}
+
+static void
+iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u16 tid,
+ int num_frames,
+ enum ieee80211_frame_release_type reason,
+ bool more_data)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ /* TODO: how do we tell the fw to send frames for a specific TID */
+
+ /*
+ * The fw will send EOSP notification when the last frame will be
+ * transmitted.
+ */
+ iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames);
+}
+
+static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+
+ switch (cmd) {
+ case STA_NOTIFY_SLEEP:
+ if (atomic_read(&mvmsta->pending_frames) > 0)
+ ieee80211_sta_block_awake(hw, sta, true);
+ /*
+ * The fw updates the STA to be asleep. Tx packets on the Tx
+ * queues to this station will not be transmitted. The fw will
+ * send a Tx response with TX_STATUS_FAIL_DEST_PS.
+ */
+ break;
+ case STA_NOTIFY_AWAKE:
+ if (WARN_ON(mvmsta->sta_id == IWL_INVALID_STATION))
+ break;
+ iwl_mvm_sta_modify_ps_wake(mvm, sta);
+ break;
+ default:
+ break;
+ }
+}
+
+static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ enum ieee80211_sta_state old_state,
+ enum ieee80211_sta_state new_state)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int ret;
+
+ IWL_DEBUG_MAC80211(mvm, "station %pM state change %d->%d\n",
+ sta->addr, old_state, new_state);
+
+ /* this would be a mac80211 bug ... but don't crash */
+ if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
+ return -EINVAL;
+
+ /* if a STA is being removed, reuse its ID */
+ flush_work(&mvm->sta_drained_wk);
+
+ mutex_lock(&mvm->mutex);
+ if (old_state == IEEE80211_STA_NOTEXIST &&
+ new_state == IEEE80211_STA_NONE) {
+ ret = iwl_mvm_add_sta(mvm, vif, sta);
+ } else if (old_state == IEEE80211_STA_NONE &&
+ new_state == IEEE80211_STA_AUTH) {
+ ret = 0;
+ } else if (old_state == IEEE80211_STA_AUTH &&
+ new_state == IEEE80211_STA_ASSOC) {
+ ret = iwl_mvm_update_sta(mvm, vif, sta);
+ if (ret == 0)
+ iwl_mvm_rs_rate_init(mvm, sta,
+ mvmvif->phy_ctxt->channel->band);
+ } else if (old_state == IEEE80211_STA_ASSOC &&
+ new_state == IEEE80211_STA_AUTHORIZED) {
+ ret = 0;
+ } else if (old_state == IEEE80211_STA_AUTHORIZED &&
+ new_state == IEEE80211_STA_ASSOC) {
+ ret = 0;
+ } else if (old_state == IEEE80211_STA_ASSOC &&
+ new_state == IEEE80211_STA_AUTH) {
+ ret = 0;
+ } else if (old_state == IEEE80211_STA_AUTH &&
+ new_state == IEEE80211_STA_NONE) {
+ ret = 0;
+ } else if (old_state == IEEE80211_STA_NONE &&
+ new_state == IEEE80211_STA_NOTEXIST) {
+ ret = iwl_mvm_rm_sta(mvm, vif, sta);
+ } else {
+ ret = -EIO;
+ }
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ mvm->rts_threshold = value;
+
+ return 0;
+}
+
+static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u16 ac,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ mvmvif->queue_params[ac] = *params;
+
+ /*
+ * No need to update right away, we'll get BSS_CHANGED_QOS
+ * The exception is P2P_DEVICE interface which needs immediate update.
+ */
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+ ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
+ mutex_unlock(&mvm->mutex);
+ return ret;
+ }
+ return 0;
+}
+
+static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ u32 duration = min(IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS,
+ 200 + vif->bss_conf.beacon_int);
+ u32 min_duration = min(IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS,
+ 100 + vif->bss_conf.beacon_int);
+
+ if (WARN_ON_ONCE(vif->bss_conf.assoc))
+ return;
+
+ mutex_lock(&mvm->mutex);
+ /* Try really hard to protect the session and hear a beacon */
+ iwl_mvm_protect_session(mvm, vif, duration, min_duration);
+ mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_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_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ if (iwlwifi_mod_params.sw_crypto) {
+ IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n");
+ return -EOPNOTSUPP;
+ }
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_TKIP:
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ /* fall-through */
+ case WLAN_CIPHER_SUITE_CCMP:
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ WARN_ON_ONCE(!(hw->flags & IEEE80211_HW_MFP_CAPABLE));
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ /*
+ * Support for TX only, at least for now, so accept
+ * the key and do nothing else. Then mac80211 will
+ * pass it for TX but we don't have to use it for RX.
+ */
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ mutex_lock(&mvm->mutex);
+
+ switch (cmd) {
+ case SET_KEY:
+ IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
+ ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false);
+ if (ret) {
+ IWL_WARN(mvm, "set key failed\n");
+ /*
+ * can't add key for RX, but we don't need it
+ * in the device for TX so still return 0
+ */
+ ret = 0;
+ }
+
+ break;
+ case DISABLE_KEY:
+ IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n");
+ ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&mvm->mutex);
+ return ret;
+}
+
+static void iwl_mvm_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_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key);
+}
+
+
+static int iwl_mvm_roc(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_channel *channel,
+ int duration)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct cfg80211_chan_def chandef;
+ int ret;
+
+ if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {
+ IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type);
+ return -EINVAL;
+ }
+
+ IWL_DEBUG_MAC80211(mvm, "enter (%d, %d)\n", channel->hw_value,
+ duration);
+
+ mutex_lock(&mvm->mutex);
+
+ cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
+ ret = iwl_mvm_phy_ctxt_changed(mvm, &mvm->phy_ctxt_roc,
+ &chandef, 1, 1);
+
+ /* Schedule the time events */
+ ret = iwl_mvm_start_p2p_roc(mvm, vif, duration);
+
+ mutex_unlock(&mvm->mutex);
+ IWL_DEBUG_MAC80211(mvm, "leave\n");
+
+ return ret;
+}
+
+static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ IWL_DEBUG_MAC80211(mvm, "enter\n");
+
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_stop_p2p_roc(mvm);
+ mutex_unlock(&mvm->mutex);
+
+ IWL_DEBUG_MAC80211(mvm, "leave\n");
+ return 0;
+}
+
+static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+
+ IWL_DEBUG_MAC80211(mvm, "Add PHY context\n");
+ ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, &ctx->def,
+ ctx->rx_chains_static,
+ ctx->rx_chains_dynamic);
+ mutex_unlock(&mvm->mutex);
+ return ret;
+}
+
+static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
+
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_phy_ctxt_remove(mvm, phy_ctxt);
+ mutex_unlock(&mvm->mutex);
+}
+
+static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx,
+ u32 changed)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
+
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
+ ctx->rx_chains_static,
+ ctx->rx_chains_dynamic);
+ mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_phy_ctxt *phyctx = (void *)ctx->drv_priv;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+
+ mvmvif->phy_ctxt = phyctx;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP:
+ /*
+ * The AP binding flow is handled as part of the start_ap flow
+ * (in bss_info_changed).
+ */
+ ret = 0;
+ goto out_unlock;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MONITOR:
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ ret = iwl_mvm_binding_add_vif(mvm, vif);
+ if (ret)
+ goto out_unlock;
+
+ /*
+ * Setting the quota at this stage is only required for monitor
+ * interfaces. For the other types, the bss_info changed flow
+ * will handle quota settings.
+ */
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ ret = iwl_mvm_update_quotas(mvm, vif);
+ if (ret)
+ goto out_remove_binding;
+ }
+
+ goto out_unlock;
+
+ out_remove_binding:
+ iwl_mvm_binding_remove_vif(mvm, vif);
+ out_unlock:
+ mutex_unlock(&mvm->mutex);
+ if (ret)
+ mvmvif->phy_ctxt = NULL;
+ return ret;
+}
+
+static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ mutex_lock(&mvm->mutex);
+
+ iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data);
+
+ if (vif->type == NL80211_IFTYPE_AP)
+ goto out_unlock;
+
+ iwl_mvm_binding_remove_vif(mvm, vif);
+ switch (vif->type) {
+ case NL80211_IFTYPE_MONITOR:
+ iwl_mvm_update_quotas(mvm, vif);
+ break;
+ default:
+ break;
+ }
+
+out_unlock:
+ mvmvif->phy_ctxt = NULL;
+ mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ bool set)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+
+ if (!mvm_sta || !mvm_sta->vif) {
+ IWL_ERR(mvm, "Station is not associated to a vif\n");
+ return -EINVAL;
+ }
+
+ return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif);
+}
+
+struct ieee80211_ops iwl_mvm_hw_ops = {
+ .tx = iwl_mvm_mac_tx,
+ .ampdu_action = iwl_mvm_mac_ampdu_action,
+ .start = iwl_mvm_mac_start,
+ .restart_complete = iwl_mvm_mac_restart_complete,
+ .stop = iwl_mvm_mac_stop,
+ .add_interface = iwl_mvm_mac_add_interface,
+ .remove_interface = iwl_mvm_mac_remove_interface,
+ .config = iwl_mvm_mac_config,
+ .configure_filter = iwl_mvm_configure_filter,
+ .bss_info_changed = iwl_mvm_bss_info_changed,
+ .hw_scan = iwl_mvm_mac_hw_scan,
+ .cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,
+ .sta_state = iwl_mvm_mac_sta_state,
+ .sta_notify = iwl_mvm_mac_sta_notify,
+ .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
+ .set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
+ .conf_tx = iwl_mvm_mac_conf_tx,
+ .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
+ .set_key = iwl_mvm_mac_set_key,
+ .update_tkip_key = iwl_mvm_mac_update_tkip_key,
+ .remain_on_channel = iwl_mvm_roc,
+ .cancel_remain_on_channel = iwl_mvm_cancel_roc,
+
+ .add_chanctx = iwl_mvm_add_chanctx,
+ .remove_chanctx = iwl_mvm_remove_chanctx,
+ .change_chanctx = iwl_mvm_change_chanctx,
+ .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx,
+ .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx,
+
+ .start_ap = iwl_mvm_start_ap,
+ .stop_ap = iwl_mvm_stop_ap,
+
+ .set_tim = iwl_mvm_set_tim,
+
+#ifdef CONFIG_PM_SLEEP
+ /* look at d3.c */
+ .suspend = iwl_mvm_suspend,
+ .resume = iwl_mvm_resume,
+ .set_wakeup = iwl_mvm_set_wakeup,
+ .set_rekey_data = iwl_mvm_set_rekey_data,
+#if IS_ENABLED(CONFIG_IPV6)
+ .ipv6_addr_change = iwl_mvm_ipv6_addr_change,
+#endif
+ .set_default_unicast_key = iwl_mvm_set_default_unicast_key,
+#endif
+};
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
new file mode 100644
index 000000000000..4e339ccfa800
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -0,0 +1,500 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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_MVM_H__
+#define __IWL_MVM_H__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/leds.h>
+#include <linux/in6.h>
+
+#include "iwl-op-mode.h"
+#include "iwl-trans.h"
+#include "iwl-notif-wait.h"
+#include "iwl-eeprom-parse.h"
+#include "iwl-test.h"
+#include "iwl-trans.h"
+#include "sta.h"
+#include "fw-api.h"
+
+#define IWL_INVALID_MAC80211_QUEUE 0xff
+#define IWL_MVM_MAX_ADDRESSES 2
+#define IWL_RSSI_OFFSET 44
+
+enum iwl_mvm_tx_fifo {
+ IWL_MVM_TX_FIFO_BK = 0,
+ IWL_MVM_TX_FIFO_BE,
+ IWL_MVM_TX_FIFO_VI,
+ IWL_MVM_TX_FIFO_VO,
+};
+
+/* Placeholder */
+#define IWL_OFFCHANNEL_QUEUE 8
+#define IWL_FIRST_AMPDU_QUEUE 11
+
+extern struct ieee80211_ops iwl_mvm_hw_ops;
+/**
+ * struct iwl_mvm_mod_params - module parameters for iwlmvm
+ * @init_dbg: if true, then the NIC won't be stopped if the INIT fw asserted.
+ * We will register to mac80211 to have testmode working. The NIC must not
+ * be up'ed after the INIT fw asserted. This is useful to be able to use
+ * proprietary tools over testmode to debug the INIT fw.
+ * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power
+ * Save)-2(default), LP(Low Power)-3
+ */
+struct iwl_mvm_mod_params {
+ bool init_dbg;
+ int power_scheme;
+};
+extern struct iwl_mvm_mod_params iwlmvm_mod_params;
+
+struct iwl_mvm_phy_ctxt {
+ u16 id;
+ u16 color;
+
+ /*
+ * TODO: This should probably be removed. Currently here only for rate
+ * scaling algorithm
+ */
+ struct ieee80211_channel *channel;
+};
+
+struct iwl_mvm_time_event_data {
+ struct ieee80211_vif *vif;
+ struct list_head list;
+ unsigned long end_jiffies;
+ u32 duration;
+ bool running;
+ u32 uid;
+
+ /*
+ * The access to the 'id' field must be done when the
+ * mvm->time_event_lock is held, as it value is used to indicate
+ * if the te is in the time event list or not (when id == TE_MAX)
+ */
+ u32 id;
+};
+
+ /* Power management */
+
+/**
+ * enum iwl_power_scheme
+ * @IWL_POWER_LEVEL_CAM - Continuously Active Mode
+ * @IWL_POWER_LEVEL_BPS - Balanced Power Save (default)
+ * @IWL_POWER_LEVEL_LP - Low Power
+ */
+enum iwl_power_scheme {
+ IWL_POWER_SCHEME_CAM = 1,
+ IWL_POWER_SCHEME_BPS,
+ IWL_POWER_SCHEME_LP
+};
+
+#define IWL_CONN_MAX_LISTEN_INTERVAL 70
+
+/**
+ * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context
+ * @id: between 0 and 3
+ * @color: to solve races upon MAC addition and removal
+ * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA
+ * @uploaded: indicates the MAC context has been added to the device
+ * @ap_active: indicates that ap context is configured, and that the interface
+ * should get quota etc.
+ * @queue_params: QoS params for this MAC
+ * @bcast_sta: station used for broadcast packets. Used by the following
+ * vifs: P2P_DEVICE, GO and AP.
+ * @beacon_skb: the skb used to hold the AP/GO beacon template
+ */
+struct iwl_mvm_vif {
+ u16 id;
+ u16 color;
+ u8 ap_sta_id;
+
+ bool uploaded;
+ bool ap_active;
+
+ enum iwl_tsf_id tsf_id;
+
+ /*
+ * QoS data from mac80211, need to store this here
+ * as mac80211 has a separate callback but we need
+ * to have the data for the MAC context
+ */
+ struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
+ struct iwl_mvm_time_event_data time_event_data;
+
+ struct iwl_mvm_int_sta bcast_sta;
+
+ /*
+ * Assigned while mac80211 has the interface in a channel context,
+ * or, for P2P Device, while it exists.
+ */
+ struct iwl_mvm_phy_ctxt *phy_ctxt;
+
+#ifdef CONFIG_PM_SLEEP
+ /* WoWLAN GTK rekey data */
+ struct {
+ u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN];
+ __le64 replay_ctr;
+ bool valid;
+ } rekey_data;
+
+ int tx_key_idx;
+
+#if IS_ENABLED(CONFIG_IPV6)
+ /* IPv6 addresses for WoWLAN */
+ struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS];
+ int num_target_ipv6_addrs;
+#endif
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ struct dentry *dbgfs_dir;
+ void *dbgfs_data;
+#endif
+};
+
+static inline struct iwl_mvm_vif *
+iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
+{
+ return (void *)vif->drv_priv;
+}
+
+enum iwl_mvm_status {
+ IWL_MVM_STATUS_HW_RFKILL,
+ IWL_MVM_STATUS_ROC_RUNNING,
+ IWL_MVM_STATUS_IN_HW_RESTART,
+};
+
+enum iwl_scan_status {
+ IWL_MVM_SCAN_NONE,
+ IWL_MVM_SCAN_OS,
+};
+
+/**
+ * struct iwl_nvm_section - describes an NVM section in memory.
+ *
+ * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD,
+ * and saved for later use by the driver. Not all NVM sections are saved
+ * this way, only the needed ones.
+ */
+struct iwl_nvm_section {
+ u16 length;
+ const u8 *data;
+};
+
+struct iwl_mvm {
+ /* for logger access */
+ struct device *dev;
+
+ struct iwl_trans *trans;
+ const struct iwl_fw *fw;
+ const struct iwl_cfg *cfg;
+ struct iwl_phy_db *phy_db;
+ struct ieee80211_hw *hw;
+
+ /* for protecting access to iwl_mvm */
+ struct mutex mutex;
+ struct list_head async_handlers_list;
+ spinlock_t async_handlers_lock;
+ struct work_struct async_handlers_wk;
+
+ struct work_struct roc_done_wk;
+
+ unsigned long status;
+
+ enum iwl_ucode_type cur_ucode;
+ bool ucode_loaded;
+ bool init_ucode_run;
+ u32 error_event_table;
+ u32 log_event_table;
+
+ u32 ampdu_ref;
+
+ struct iwl_notif_wait_data notif_wait;
+
+ unsigned long transport_queue_stop;
+ u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
+ atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
+
+ struct iwl_nvm_data *nvm_data;
+ /* eeprom blob for debugfs/testmode */
+ u8 *eeprom_blob;
+ size_t eeprom_blob_size;
+ /* NVM sections for 7000 family */
+ struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS];
+
+ /* EEPROM MAC addresses */
+ struct mac_address addresses[IWL_MVM_MAX_ADDRESSES];
+
+ /* data related to data path */
+ struct iwl_rx_phy_info last_phy_info;
+ struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
+ struct work_struct sta_drained_wk;
+ unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
+
+ /* configured by mac80211 */
+ u32 rts_threshold;
+
+ /* Scan status, cmd (pre-allocated) and auxiliary station */
+ enum iwl_scan_status scan_status;
+ struct iwl_scan_cmd *scan_cmd;
+
+ /* Internal station */
+ struct iwl_mvm_int_sta aux_sta;
+
+ u8 scan_last_antenna_idx; /* to toggle TX between antennas */
+ u8 mgmt_last_antenna_idx;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ struct dentry *debugfs_dir;
+ u32 dbgfs_sram_offset, dbgfs_sram_len;
+ bool prevent_power_down_d3;
+#endif
+
+ struct iwl_mvm_phy_ctxt phy_ctxt_roc;
+
+ struct list_head time_event_list;
+ spinlock_t time_event_lock;
+
+ /*
+ * A bitmap indicating the index of the key in use. The firmware
+ * can hold 16 keys at most. Reflect this fact.
+ */
+ unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
+ u8 vif_count;
+
+ struct led_classdev led;
+
+ struct ieee80211_vif *p2p_device_vif;
+};
+
+/* Extract MVM priv from op_mode and _hw */
+#define IWL_OP_MODE_GET_MVM(_iwl_op_mode) \
+ ((struct iwl_mvm *)(_iwl_op_mode)->op_mode_specific)
+
+#define IWL_MAC80211_GET_MVM(_hw) \
+ IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv))
+
+extern const u8 iwl_mvm_ac_to_tx_fifo[];
+
+struct iwl_rate_info {
+ u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
+ u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
+ u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
+ u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */
+ u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */
+};
+
+/******************
+ * MVM Methods
+ ******************/
+/* uCode */
+int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm);
+
+/* Utils */
+int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
+ enum ieee80211_band band);
+u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx);
+void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
+u8 first_antenna(u8 mask);
+u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);
+
+/* Tx / Host Commands */
+int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm,
+ struct iwl_host_cmd *cmd);
+int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id,
+ u32 flags, u16 len, const void *data);
+int __must_check iwl_mvm_send_cmd_status(struct iwl_mvm *mvm,
+ struct iwl_host_cmd *cmd,
+ u32 *status);
+int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id,
+ u16 len, const void *data,
+ u32 *status);
+int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
+ struct ieee80211_sta *sta);
+int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb);
+#ifdef CONFIG_IWLWIFI_DEBUG
+const char *iwl_mvm_get_tx_fail_reason(u32 status);
+#else
+static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; }
+#endif
+int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync);
+void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm);
+
+/* Statistics */
+int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+
+/* NVM */
+int iwl_nvm_init(struct iwl_mvm *mvm);
+
+int iwl_mvm_up(struct iwl_mvm *mvm);
+int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm);
+
+int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm);
+
+/*
+ * FW notifications / CMD responses handlers
+ * Convention: iwl_mvm_rx_<NAME OF THE CMD>
+ */
+int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+
+/* MVM PHY */
+int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
+ struct cfg80211_chan_def *chandef,
+ u8 chains_static, u8 chains_dynamic);
+int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
+ struct cfg80211_chan_def *chandef,
+ u8 chains_static, u8 chains_dynamic);
+void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm,
+ struct iwl_mvm_phy_ctxt *ctxt);
+
+/* MAC (virtual interface) programming */
+int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif);
+int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif);
+
+/* Bindings */
+int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+
+/* Quota management */
+int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif);
+
+/* Scanning */
+int iwl_mvm_scan_request(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_scan_request *req);
+int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+void iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
+
+/* MVM debugfs */
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir);
+int iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct dentry *dbgfs_dir);
+void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_powertable_cmd *cmd);
+#else
+static inline int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm,
+ struct dentry *dbgfs_dir)
+{
+ return 0;
+}
+#endif /* CONFIG_IWLWIFI_DEBUGFS */
+
+/* rate scaling */
+int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
+ u8 flags, bool init);
+
+/* power managment */
+int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+
+int iwl_mvm_leds_init(struct iwl_mvm *mvm);
+void iwl_mvm_leds_exit(struct iwl_mvm *mvm);
+
+/* D3 (WoWLAN, NetDetect) */
+int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
+int iwl_mvm_resume(struct ieee80211_hw *hw);
+void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled);
+void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_gtk_rekey_data *data);
+void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct inet6_dev *idev);
+void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, int idx);
+
+#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
new file mode 100644
index 000000000000..20016bcbdeab
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -0,0 +1,311 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 "iwl-trans.h"
+#include "mvm.h"
+#include "iwl-eeprom-parse.h"
+#include "iwl-eeprom-read.h"
+#include "iwl-nvm-parse.h"
+
+/* list of NVM sections we are allowed/need to read */
+static const int nvm_to_read[] = {
+ NVM_SECTION_TYPE_HW,
+ NVM_SECTION_TYPE_SW,
+ NVM_SECTION_TYPE_CALIBRATION,
+ NVM_SECTION_TYPE_PRODUCTION,
+};
+
+/* used to simplify the shared operations on NCM_ACCESS_CMD versions */
+union iwl_nvm_access_cmd {
+ struct iwl_nvm_access_cmd_ver1 ver1;
+ struct iwl_nvm_access_cmd_ver2 ver2;
+};
+union iwl_nvm_access_resp {
+ struct iwl_nvm_access_resp_ver1 ver1;
+ struct iwl_nvm_access_resp_ver2 ver2;
+};
+
+static inline void iwl_nvm_fill_read_ver1(struct iwl_nvm_access_cmd_ver1 *cmd,
+ u16 offset, u16 length)
+{
+ cmd->offset = cpu_to_le16(offset);
+ cmd->length = cpu_to_le16(length);
+ cmd->cache_refresh = 1;
+}
+
+static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd,
+ u16 offset, u16 length, u16 section)
+{
+ cmd->offset = cpu_to_le16(offset);
+ cmd->length = cpu_to_le16(length);
+ cmd->type = cpu_to_le16(section);
+}
+
+static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
+ u16 offset, u16 length, u8 *data)
+{
+ union iwl_nvm_access_cmd nvm_access_cmd;
+ union iwl_nvm_access_resp *nvm_resp;
+ struct iwl_rx_packet *pkt;
+ struct iwl_host_cmd cmd = {
+ .id = NVM_ACCESS_CMD,
+ .flags = CMD_SYNC | CMD_WANT_SKB,
+ .data = { &nvm_access_cmd, },
+ };
+ int ret, bytes_read, offset_read;
+ u8 *resp_data;
+
+ memset(&nvm_access_cmd, 0, sizeof(nvm_access_cmd));
+
+ /* TODO: not sure family should be the decider, maybe FW version? */
+ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+ iwl_nvm_fill_read_ver2(&(nvm_access_cmd.ver2),
+ offset, length, section);
+ cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver2);
+ } else {
+ iwl_nvm_fill_read_ver1(&(nvm_access_cmd.ver1),
+ offset, length);
+ cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver1);
+ }
+
+ ret = iwl_mvm_send_cmd(mvm, &cmd);
+ if (ret)
+ return ret;
+
+ pkt = cmd.resp_pkt;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERR(mvm, "Bad return from NVM_ACCES_COMMAND (0x%08X)\n",
+ pkt->hdr.flags);
+ ret = -EIO;
+ goto exit;
+ }
+
+ /* Extract NVM response */
+ nvm_resp = (void *)pkt->data;
+ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+ ret = le16_to_cpu(nvm_resp->ver2.status);
+ bytes_read = le16_to_cpu(nvm_resp->ver2.length);
+ offset_read = le16_to_cpu(nvm_resp->ver2.offset);
+ resp_data = nvm_resp->ver2.data;
+ } else {
+ ret = le16_to_cpu(nvm_resp->ver1.length) <= 0;
+ bytes_read = le16_to_cpu(nvm_resp->ver1.length);
+ offset_read = le16_to_cpu(nvm_resp->ver1.offset);
+ resp_data = nvm_resp->ver1.data;
+ }
+ if (ret) {
+ IWL_ERR(mvm,
+ "NVM access command failed with status %d (device: %s)\n",
+ ret, mvm->cfg->name);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (offset_read != offset) {
+ IWL_ERR(mvm, "NVM ACCESS response with invalid offset %d\n",
+ offset_read);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* Write data to NVM */
+ memcpy(data + offset, resp_data, bytes_read);
+ ret = bytes_read;
+
+exit:
+ iwl_free_resp(&cmd);
+ return ret;
+}
+
+/*
+ * Reads an NVM section completely.
+ * NICs prior to 7000 family doesn't have a real NVM, but just read
+ * section 0 which is the EEPROM. Because the EEPROM reading is unlimited
+ * by uCode, we need to manually check in this case that we don't
+ * overflow and try to read more than the EEPROM size.
+ * For 7000 family NICs, we supply the maximal size we can read, and
+ * the uCode fills the response with as much data as we can,
+ * without overflowing, so no check is needed.
+ */
+static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
+ u8 *data)
+{
+ u16 length, offset = 0;
+ int ret;
+ bool old_eeprom = mvm->cfg->device_family != IWL_DEVICE_FAMILY_7000;
+
+ length = (iwlwifi_mod_params.amsdu_size_8K ? (8 * 1024) : (4 * 1024))
+ - sizeof(union iwl_nvm_access_cmd)
+ - sizeof(struct iwl_rx_packet);
+ /*
+ * if length is greater than EEPROM size, truncate it because uCode
+ * doesn't check it by itself, and exit the loop when reached.
+ */
+ if (old_eeprom && length > mvm->cfg->base_params->eeprom_size)
+ length = mvm->cfg->base_params->eeprom_size;
+ ret = length;
+
+ /* Read the NVM until exhausted (reading less than requested) */
+ while (ret == length) {
+ ret = iwl_nvm_read_chunk(mvm, section, offset, length, data);
+ if (ret < 0) {
+ IWL_ERR(mvm,
+ "Cannot read NVM from section %d offset %d, length %d\n",
+ section, offset, length);
+ return ret;
+ }
+ offset += ret;
+ if (old_eeprom && offset == mvm->cfg->base_params->eeprom_size)
+ break;
+ }
+
+ IWL_INFO(mvm, "NVM section %d read completed\n", section);
+ return offset;
+}
+
+static struct iwl_nvm_data *
+iwl_parse_nvm_sections(struct iwl_mvm *mvm)
+{
+ struct iwl_nvm_section *sections = mvm->nvm_sections;
+ const __le16 *hw, *sw, *calib;
+
+ /* Checking for required sections */
+ if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
+ !mvm->nvm_sections[NVM_SECTION_TYPE_HW].data) {
+ IWL_ERR(mvm, "Can't parse empty NVM sections\n");
+ return NULL;
+ }
+
+ if (WARN_ON(!mvm->cfg))
+ return NULL;
+
+ hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data;
+ sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
+ calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
+ return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib);
+}
+
+int iwl_nvm_init(struct iwl_mvm *mvm)
+{
+ int ret, i, section;
+ u8 *nvm_buffer, *temp;
+
+ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+ /* TODO: find correct NVM max size for a section */
+ nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
+ GFP_KERNEL);
+ if (!nvm_buffer)
+ return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
+ section = nvm_to_read[i];
+ /* we override the constness for initial read */
+ ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
+ if (ret < 0)
+ break;
+ temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
+ if (!temp) {
+ ret = -ENOMEM;
+ break;
+ }
+ mvm->nvm_sections[section].data = temp;
+ mvm->nvm_sections[section].length = ret;
+ }
+ kfree(nvm_buffer);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* allocate eeprom */
+ mvm->eeprom_blob_size = mvm->cfg->base_params->eeprom_size;
+ IWL_DEBUG_EEPROM(mvm->trans->dev, "NVM size = %zd\n",
+ mvm->eeprom_blob_size);
+ mvm->eeprom_blob = kzalloc(mvm->eeprom_blob_size, GFP_KERNEL);
+ if (!mvm->eeprom_blob)
+ return -ENOMEM;
+
+ ret = iwl_nvm_read_section(mvm, 0, mvm->eeprom_blob);
+ if (ret != mvm->eeprom_blob_size) {
+ IWL_ERR(mvm, "Read partial NVM %d/%zd\n",
+ ret, mvm->eeprom_blob_size);
+ kfree(mvm->eeprom_blob);
+ mvm->eeprom_blob = NULL;
+ return -EINVAL;
+ }
+ }
+
+ ret = 0;
+ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
+ mvm->nvm_data = iwl_parse_nvm_sections(mvm);
+ else
+ mvm->nvm_data =
+ iwl_parse_eeprom_data(mvm->trans->dev,
+ mvm->cfg,
+ mvm->eeprom_blob,
+ mvm->eeprom_blob_size);
+
+ if (!mvm->nvm_data) {
+ kfree(mvm->eeprom_blob);
+ mvm->eeprom_blob = NULL;
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
new file mode 100644
index 000000000000..aa59adf87db3
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -0,0 +1,682 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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/module.h>
+#include <net/mac80211.h>
+
+#include "iwl-notif-wait.h"
+#include "iwl-trans.h"
+#include "iwl-op-mode.h"
+#include "iwl-fw.h"
+#include "iwl-debug.h"
+#include "iwl-drv.h"
+#include "iwl-modparams.h"
+#include "mvm.h"
+#include "iwl-phy-db.h"
+#include "iwl-eeprom-parse.h"
+#include "iwl-csr.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "rs.h"
+#include "fw-api-scan.h"
+#include "time-event.h"
+
+/*
+ * module name, copyright, version, etc.
+ */
+#define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux"
+
+#define DRV_VERSION IWLWIFI_VERSION
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+
+static const struct iwl_op_mode_ops iwl_mvm_ops;
+
+struct iwl_mvm_mod_params iwlmvm_mod_params = {
+ .power_scheme = IWL_POWER_SCHEME_BPS,
+ /* rest of fields are 0 by default */
+};
+
+module_param_named(init_dbg, iwlmvm_mod_params.init_dbg, bool, S_IRUGO);
+MODULE_PARM_DESC(init_dbg,
+ "set to true to debug an ASSERT in INIT fw (default: false");
+module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO);
+MODULE_PARM_DESC(power_scheme,
+ "power management scheme: 1-active, 2-balanced, 3-low power, default: 2");
+
+/*
+ * module init and exit functions
+ */
+static int __init iwl_mvm_init(void)
+{
+ int ret;
+
+ ret = iwl_mvm_rate_control_register();
+ if (ret) {
+ pr_err("Unable to register rate control algorithm: %d\n", ret);
+ return ret;
+ }
+
+ ret = iwl_opmode_register("iwlmvm", &iwl_mvm_ops);
+
+ if (ret) {
+ pr_err("Unable to register MVM op_mode: %d\n", ret);
+ iwl_mvm_rate_control_unregister();
+ }
+
+ return ret;
+}
+module_init(iwl_mvm_init);
+
+static void __exit iwl_mvm_exit(void)
+{
+ iwl_opmode_deregister("iwlmvm");
+ iwl_mvm_rate_control_unregister();
+}
+module_exit(iwl_mvm_exit);
+
+static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
+{
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash;
+ u32 reg_val = 0;
+
+ /*
+ * We can't upload the correct value to the INIT image
+ * as we don't have nvm_data by that time.
+ *
+ * TODO: Figure out what we should do here
+ */
+ if (mvm->nvm_data) {
+ radio_cfg_type = mvm->nvm_data->radio_cfg_type;
+ radio_cfg_step = mvm->nvm_data->radio_cfg_step;
+ radio_cfg_dash = mvm->nvm_data->radio_cfg_dash;
+ } else {
+ radio_cfg_type = 0;
+ radio_cfg_step = 0;
+ radio_cfg_dash = 0;
+ }
+
+ /* SKU control */
+ reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) <<
+ CSR_HW_IF_CONFIG_REG_POS_MAC_STEP;
+ reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) <<
+ CSR_HW_IF_CONFIG_REG_POS_MAC_DASH;
+
+ /* radio configuration */
+ reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE;
+ reg_val |= radio_cfg_step << CSR_HW_IF_CONFIG_REG_POS_PHY_STEP;
+ reg_val |= radio_cfg_dash << CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
+
+ WARN_ON((radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE) &
+ ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE);
+
+ /* silicon bits */
+ reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI;
+ reg_val |= CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
+
+ iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
+ CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP |
+ CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
+ CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
+ CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH |
+ CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+ CSR_HW_IF_CONFIG_REG_BIT_MAC_SI,
+ reg_val);
+
+ IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type,
+ radio_cfg_step, radio_cfg_dash);
+
+ /*
+ * W/A : NIC is stuck in a reset state after Early PCIe power off
+ * (PCIe power is lost before PERST# is asserted), causing ME FW
+ * to lose ownership and not being able to obtain it back.
+ */
+ iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
+ ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+}
+
+struct iwl_rx_handlers {
+ u8 cmd_id;
+ bool async;
+ int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+};
+
+#define RX_HANDLER(_cmd_id, _fn, _async) \
+ { .cmd_id = _cmd_id , .fn = _fn , .async = _async }
+
+/*
+ * Handlers for fw notifications
+ * Convention: RX_HANDLER(CMD_NAME, iwl_mvm_rx_CMD_NAME
+ * This list should be in order of frequency for performance purposes.
+ *
+ * The handler can be SYNC - this means that it will be called in the Rx path
+ * which can't acquire mvm->mutex. If the handler needs to hold mvm->mutex (and
+ * only in this case!), it should be set as ASYNC. In that case, it will be
+ * called from a worker with mvm->mutex held.
+ */
+static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
+ RX_HANDLER(REPLY_RX_MPDU_CMD, iwl_mvm_rx_rx_mpdu, false),
+ RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false),
+ RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false),
+ RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false),
+ RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
+
+ RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
+ RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
+
+ RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
+ RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
+
+ RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false),
+};
+#undef RX_HANDLER
+#define CMD(x) [x] = #x
+
+static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
+ CMD(MVM_ALIVE),
+ CMD(REPLY_ERROR),
+ CMD(INIT_COMPLETE_NOTIF),
+ CMD(PHY_CONTEXT_CMD),
+ CMD(MGMT_MCAST_KEY),
+ CMD(TX_CMD),
+ CMD(TXPATH_FLUSH),
+ CMD(MAC_CONTEXT_CMD),
+ CMD(TIME_EVENT_CMD),
+ CMD(TIME_EVENT_NOTIFICATION),
+ CMD(BINDING_CONTEXT_CMD),
+ CMD(TIME_QUOTA_CMD),
+ CMD(RADIO_VERSION_NOTIFICATION),
+ CMD(SCAN_REQUEST_CMD),
+ CMD(SCAN_ABORT_CMD),
+ CMD(SCAN_START_NOTIFICATION),
+ CMD(SCAN_RESULTS_NOTIFICATION),
+ CMD(SCAN_COMPLETE_NOTIFICATION),
+ CMD(NVM_ACCESS_CMD),
+ CMD(PHY_CONFIGURATION_CMD),
+ CMD(CALIB_RES_NOTIF_PHY_DB),
+ CMD(SET_CALIB_DEFAULT_CMD),
+ CMD(CALIBRATION_COMPLETE_NOTIFICATION),
+ CMD(ADD_STA),
+ CMD(REMOVE_STA),
+ CMD(LQ_CMD),
+ CMD(SCAN_OFFLOAD_CONFIG_CMD),
+ CMD(SCAN_OFFLOAD_REQUEST_CMD),
+ CMD(SCAN_OFFLOAD_ABORT_CMD),
+ CMD(SCAN_OFFLOAD_COMPLETE),
+ CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
+ CMD(POWER_TABLE_CMD),
+ CMD(WEP_KEY),
+ CMD(REPLY_RX_PHY_CMD),
+ CMD(REPLY_RX_MPDU_CMD),
+ CMD(BEACON_TEMPLATE_CMD),
+ CMD(STATISTICS_NOTIFICATION),
+ CMD(TX_ANT_CONFIGURATION_CMD),
+ CMD(D3_CONFIG_CMD),
+ CMD(PROT_OFFLOAD_CONFIG_CMD),
+ CMD(OFFLOADS_QUERY_CMD),
+ CMD(REMOTE_WAKE_CONFIG_CMD),
+ CMD(WOWLAN_PATTERNS),
+ CMD(WOWLAN_CONFIGURATION),
+ CMD(WOWLAN_TSC_RSC_PARAM),
+ CMD(WOWLAN_TKIP_PARAM),
+ CMD(WOWLAN_KEK_KCK_MATERIAL),
+ CMD(WOWLAN_GET_STATUSES),
+ CMD(WOWLAN_TX_POWER_PER_DB),
+ CMD(NET_DETECT_CONFIG_CMD),
+ CMD(NET_DETECT_PROFILES_QUERY_CMD),
+ CMD(NET_DETECT_PROFILES_CMD),
+ CMD(NET_DETECT_HOTSPOTS_CMD),
+ CMD(NET_DETECT_HOTSPOTS_QUERY_CMD),
+};
+#undef CMD
+
+/* this forward declaration can avoid to export the function */
+static void iwl_mvm_async_handlers_wk(struct work_struct *wk);
+
+static struct iwl_op_mode *
+iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
+ const struct iwl_fw *fw, struct dentry *dbgfs_dir)
+{
+ struct ieee80211_hw *hw;
+ struct iwl_op_mode *op_mode;
+ struct iwl_mvm *mvm;
+ struct iwl_trans_config trans_cfg = {};
+ static const u8 no_reclaim_cmds[] = {
+ TX_CMD,
+ };
+ int err, scan_size;
+
+ switch (cfg->device_family) {
+ case IWL_DEVICE_FAMILY_6030:
+ case IWL_DEVICE_FAMILY_6005:
+ case IWL_DEVICE_FAMILY_7000:
+ break;
+ default:
+ IWL_ERR(trans, "Trying to load mvm on an unsupported device\n");
+ return NULL;
+ }
+
+ /********************************
+ * 1. Allocating and configuring HW data
+ ********************************/
+ hw = ieee80211_alloc_hw(sizeof(struct iwl_op_mode) +
+ sizeof(struct iwl_mvm),
+ &iwl_mvm_hw_ops);
+ if (!hw)
+ return NULL;
+
+ op_mode = hw->priv;
+ op_mode->ops = &iwl_mvm_ops;
+ op_mode->trans = trans;
+
+ mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ mvm->dev = trans->dev;
+ mvm->trans = trans;
+ mvm->cfg = cfg;
+ mvm->fw = fw;
+ mvm->hw = hw;
+
+ mutex_init(&mvm->mutex);
+ spin_lock_init(&mvm->async_handlers_lock);
+ INIT_LIST_HEAD(&mvm->time_event_list);
+ INIT_LIST_HEAD(&mvm->async_handlers_list);
+ spin_lock_init(&mvm->time_event_lock);
+
+ INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk);
+ INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
+ INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk);
+
+ SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev);
+
+ /*
+ * Populate the state variables that the transport layer needs
+ * to know about.
+ */
+ trans_cfg.op_mode = op_mode;
+ trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
+ trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
+ trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
+
+ /* TODO: this should really be a TLV */
+ if (cfg->device_family == IWL_DEVICE_FAMILY_7000)
+ trans_cfg.bc_table_dword = true;
+
+ if (!iwlwifi_mod_params.wd_disable)
+ trans_cfg.queue_watchdog_timeout = cfg->base_params->wd_timeout;
+ else
+ trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED;
+
+ trans_cfg.command_names = iwl_mvm_cmd_strings;
+
+ trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
+ trans_cfg.cmd_fifo = IWL_MVM_CMD_FIFO;
+
+ snprintf(mvm->hw->wiphy->fw_version,
+ sizeof(mvm->hw->wiphy->fw_version),
+ "%s", fw->fw_version);
+
+ /* Configure transport layer */
+ iwl_trans_configure(mvm->trans, &trans_cfg);
+
+ trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
+ trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start);
+
+ /* set up notification wait support */
+ iwl_notification_wait_init(&mvm->notif_wait);
+
+ /* Init phy db */
+ mvm->phy_db = iwl_phy_db_init(trans);
+ if (!mvm->phy_db) {
+ IWL_ERR(mvm, "Cannot init phy_db\n");
+ goto out_free;
+ }
+
+ IWL_INFO(mvm, "Detected %s, REV=0x%X\n",
+ mvm->cfg->name, mvm->trans->hw_rev);
+
+ err = iwl_trans_start_hw(mvm->trans);
+ if (err)
+ goto out_free;
+
+ mutex_lock(&mvm->mutex);
+ err = iwl_run_init_mvm_ucode(mvm, true);
+ mutex_unlock(&mvm->mutex);
+ if (err && !iwlmvm_mod_params.init_dbg) {
+ IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
+ goto out_free;
+ }
+
+ /* Stop the hw after the ALIVE and NVM has been read */
+ if (!iwlmvm_mod_params.init_dbg)
+ iwl_trans_stop_hw(mvm->trans, false);
+
+ scan_size = sizeof(struct iwl_scan_cmd) +
+ mvm->fw->ucode_capa.max_probe_length +
+ (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel));
+ mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL);
+ if (!mvm->scan_cmd)
+ goto out_free;
+
+ err = iwl_mvm_mac_setup_register(mvm);
+ if (err)
+ goto out_free;
+
+ err = iwl_mvm_dbgfs_register(mvm, dbgfs_dir);
+ if (err)
+ goto out_unregister;
+
+ return op_mode;
+
+ out_unregister:
+ ieee80211_unregister_hw(mvm->hw);
+ out_free:
+ iwl_phy_db_free(mvm->phy_db);
+ kfree(mvm->scan_cmd);
+ kfree(mvm->eeprom_blob);
+ iwl_trans_stop_hw(trans, true);
+ ieee80211_free_hw(mvm->hw);
+ return NULL;
+}
+
+static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
+{
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ int i;
+
+ iwl_mvm_leds_exit(mvm);
+
+ ieee80211_unregister_hw(mvm->hw);
+
+ kfree(mvm->scan_cmd);
+
+ iwl_trans_stop_hw(mvm->trans, true);
+
+ iwl_phy_db_free(mvm->phy_db);
+ mvm->phy_db = NULL;
+
+ kfree(mvm->eeprom_blob);
+ iwl_free_nvm_data(mvm->nvm_data);
+ for (i = 0; i < NVM_NUM_OF_SECTIONS; i++)
+ kfree(mvm->nvm_sections[i].data);
+
+ ieee80211_free_hw(mvm->hw);
+}
+
+struct iwl_async_handler_entry {
+ struct list_head list;
+ struct iwl_rx_cmd_buffer rxb;
+ int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+};
+
+void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm)
+{
+ struct iwl_async_handler_entry *entry, *tmp;
+
+ spin_lock_bh(&mvm->async_handlers_lock);
+ list_for_each_entry_safe(entry, tmp, &mvm->async_handlers_list, list) {
+ iwl_free_rxb(&entry->rxb);
+ list_del(&entry->list);
+ kfree(entry);
+ }
+ spin_unlock_bh(&mvm->async_handlers_lock);
+}
+
+static void iwl_mvm_async_handlers_wk(struct work_struct *wk)
+{
+ struct iwl_mvm *mvm =
+ container_of(wk, struct iwl_mvm, async_handlers_wk);
+ struct iwl_async_handler_entry *entry, *tmp;
+ struct list_head local_list;
+
+ INIT_LIST_HEAD(&local_list);
+
+ /* Ensure that we are not in stop flow (check iwl_mvm_mac_stop) */
+ mutex_lock(&mvm->mutex);
+
+ /*
+ * Sync with Rx path with a lock. Remove all the entries from this list,
+ * add them to a local one (lock free), and then handle them.
+ */
+ spin_lock_bh(&mvm->async_handlers_lock);
+ list_splice_init(&mvm->async_handlers_list, &local_list);
+ spin_unlock_bh(&mvm->async_handlers_lock);
+
+ list_for_each_entry_safe(entry, tmp, &local_list, list) {
+ if (entry->fn(mvm, &entry->rxb, NULL))
+ IWL_WARN(mvm,
+ "returned value from ASYNC handlers are ignored\n");
+ iwl_free_rxb(&entry->rxb);
+ list_del(&entry->list);
+ kfree(entry);
+ }
+ mutex_unlock(&mvm->mutex);
+}
+
+static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ u8 i;
+
+ /*
+ * Do the notification wait before RX handlers so
+ * even if the RX handler consumes the RXB we have
+ * access to it in the notification wait entry.
+ */
+ iwl_notification_wait_notify(&mvm->notif_wait, pkt);
+
+ for (i = 0; i < ARRAY_SIZE(iwl_mvm_rx_handlers); i++) {
+ const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i];
+ struct iwl_async_handler_entry *entry;
+
+ if (rx_h->cmd_id != pkt->hdr.cmd)
+ continue;
+
+ if (!rx_h->async)
+ return rx_h->fn(mvm, rxb, cmd);
+
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ /* we can't do much... */
+ if (!entry)
+ return 0;
+
+ entry->rxb._page = rxb_steal_page(rxb);
+ entry->rxb._offset = rxb->_offset;
+ entry->rxb._rx_page_order = rxb->_rx_page_order;
+ entry->fn = rx_h->fn;
+ spin_lock(&mvm->async_handlers_lock);
+ list_add_tail(&entry->list, &mvm->async_handlers_list);
+ spin_unlock(&mvm->async_handlers_lock);
+ schedule_work(&mvm->async_handlers_wk);
+ break;
+ }
+
+ return 0;
+}
+
+static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
+{
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ int mq = mvm->queue_to_mac80211[queue];
+
+ if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
+ return;
+
+ if (atomic_inc_return(&mvm->queue_stop_count[mq]) > 1) {
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "queue %d (mac80211 %d) already stopped\n",
+ queue, mq);
+ return;
+ }
+
+ set_bit(mq, &mvm->transport_queue_stop);
+ ieee80211_stop_queue(mvm->hw, mq);
+}
+
+static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
+{
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ int mq = mvm->queue_to_mac80211[queue];
+
+ if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
+ return;
+
+ if (atomic_dec_return(&mvm->queue_stop_count[mq]) > 0) {
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "queue %d (mac80211 %d) already awake\n",
+ queue, mq);
+ return;
+ }
+
+ clear_bit(mq, &mvm->transport_queue_stop);
+
+ ieee80211_wake_queue(mvm->hw, mq);
+}
+
+static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
+{
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+
+ if (state)
+ set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
+ else
+ clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
+
+ wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state);
+}
+
+static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
+{
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ struct ieee80211_tx_info *info;
+
+ info = IEEE80211_SKB_CB(skb);
+ iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
+ ieee80211_free_txskb(mvm->hw, skb);
+}
+
+static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)
+{
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+
+ iwl_mvm_dump_nic_error_log(mvm);
+
+ iwl_abort_notification_waits(&mvm->notif_wait);
+
+ /*
+ * If we're restarting already, don't cycle restarts.
+ * If INIT fw asserted, it will likely fail again.
+ * If WoWLAN fw asserted, don't restart either, mac80211
+ * can't recover this since we're already half suspended.
+ */
+ if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+ IWL_ERR(mvm, "Firmware error during reconfiguration! Abort.\n");
+ } else if (mvm->cur_ucode == IWL_UCODE_REGULAR &&
+ iwlwifi_mod_params.restart_fw) {
+ /*
+ * This is a bit racy, but worst case we tell mac80211 about
+ * a stopped/aborted (sched) scan when that was already done
+ * which is not a problem. It is necessary to abort any scan
+ * here because mac80211 requires having the scan cleared
+ * before restarting.
+ * We'll reset the scan_status to NONE in restart cleanup in
+ * the next start() call from mac80211.
+ */
+ switch (mvm->scan_status) {
+ case IWL_MVM_SCAN_NONE:
+ break;
+ case IWL_MVM_SCAN_OS:
+ ieee80211_scan_completed(mvm->hw, true);
+ break;
+ }
+
+ ieee80211_restart_hw(mvm->hw);
+ }
+}
+
+static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)
+{
+ WARN_ON(1);
+}
+
+static const struct iwl_op_mode_ops iwl_mvm_ops = {
+ .start = iwl_op_mode_mvm_start,
+ .stop = iwl_op_mode_mvm_stop,
+ .rx = iwl_mvm_rx_dispatch,
+ .queue_full = iwl_mvm_stop_sw_queue,
+ .queue_not_full = iwl_mvm_wake_sw_queue,
+ .hw_rf_kill = iwl_mvm_set_hw_rfkill_state,
+ .free_skb = iwl_mvm_free_skb,
+ .nic_error = iwl_mvm_nic_error,
+ .cmd_queue_full = iwl_mvm_cmd_queue_full,
+ .nic_config = iwl_mvm_nic_config,
+};
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
new file mode 100644
index 000000000000..b428448f8ddf
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -0,0 +1,292 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 <net/mac80211.h>
+#include "fw-api.h"
+#include "mvm.h"
+
+/* Maps the driver specific channel width definition to the the fw values */
+static inline u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef)
+{
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ return PHY_VHT_CHANNEL_MODE20;
+ case NL80211_CHAN_WIDTH_40:
+ return PHY_VHT_CHANNEL_MODE40;
+ case NL80211_CHAN_WIDTH_80:
+ return PHY_VHT_CHANNEL_MODE80;
+ case NL80211_CHAN_WIDTH_160:
+ return PHY_VHT_CHANNEL_MODE160;
+ default:
+ WARN(1, "Invalid channel width=%u", chandef->width);
+ return PHY_VHT_CHANNEL_MODE20;
+ }
+}
+
+/*
+ * Maps the driver specific control channel position (relative to the center
+ * freq) definitions to the the fw values
+ */
+static inline u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef)
+{
+ switch (chandef->chan->center_freq - chandef->center_freq1) {
+ case -70:
+ return PHY_VHT_CTRL_POS_4_BELOW;
+ case -50:
+ return PHY_VHT_CTRL_POS_3_BELOW;
+ case -30:
+ return PHY_VHT_CTRL_POS_2_BELOW;
+ case -10:
+ return PHY_VHT_CTRL_POS_1_BELOW;
+ case 10:
+ return PHY_VHT_CTRL_POS_1_ABOVE;
+ case 30:
+ return PHY_VHT_CTRL_POS_2_ABOVE;
+ case 50:
+ return PHY_VHT_CTRL_POS_3_ABOVE;
+ case 70:
+ return PHY_VHT_CTRL_POS_4_ABOVE;
+ default:
+ WARN(1, "Invalid channel definition");
+ case 0:
+ /*
+ * The FW is expected to check the control channel position only
+ * when in HT/VHT and the channel width is not 20MHz. Return
+ * this value as the default one.
+ */
+ return PHY_VHT_CTRL_POS_1_BELOW;
+ }
+}
+
+/*
+ * Construct the generic fields of the PHY context command
+ */
+static void iwl_mvm_phy_ctxt_cmd_hdr(struct iwl_mvm_phy_ctxt *ctxt,
+ struct iwl_phy_context_cmd *cmd,
+ u32 action, u32 apply_time)
+{
+ memset(cmd, 0, sizeof(struct iwl_phy_context_cmd));
+
+ cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(ctxt->id,
+ ctxt->color));
+ cmd->action = cpu_to_le32(action);
+ cmd->apply_time = cpu_to_le32(apply_time);
+}
+
+/*
+ * Add the phy configuration to the PHY context command
+ */
+static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
+ struct iwl_phy_context_cmd *cmd,
+ struct cfg80211_chan_def *chandef,
+ u8 chains_static, u8 chains_dynamic)
+{
+ u8 valid_rx_chains, active_cnt, idle_cnt;
+
+ /* Set the channel info data */
+ cmd->ci.band = (chandef->chan->band == IEEE80211_BAND_2GHZ ?
+ PHY_BAND_24 : PHY_BAND_5);
+
+ cmd->ci.channel = chandef->chan->hw_value;
+ cmd->ci.width = iwl_mvm_get_channel_width(chandef);
+ cmd->ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef);
+
+ /* Set rx the chains */
+
+ /* TODO:
+ * Need to add on chain noise calibration limitations, and
+ * BT coex considerations.
+ */
+ valid_rx_chains = mvm->nvm_data->valid_rx_ant;
+ idle_cnt = chains_static;
+ active_cnt = chains_dynamic;
+
+ cmd->rxchain_info = cpu_to_le32(valid_rx_chains <<
+ PHY_RX_CHAIN_VALID_POS);
+ cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
+ cmd->rxchain_info |= cpu_to_le32(active_cnt <<
+ PHY_RX_CHAIN_MIMO_CNT_POS);
+
+ cmd->txchain_info = cpu_to_le32(mvm->nvm_data->valid_tx_ant);
+}
+
+/*
+ * Send a command to apply the current phy configuration. The command is send
+ * only if something in the configuration changed: in case that this is the
+ * first time that the phy configuration is applied or in case that the phy
+ * configuration changed from the previous apply.
+ */
+static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm,
+ struct iwl_mvm_phy_ctxt *ctxt,
+ struct cfg80211_chan_def *chandef,
+ u8 chains_static, u8 chains_dynamic,
+ u32 action, u32 apply_time)
+{
+ struct iwl_phy_context_cmd cmd;
+ int ret;
+
+ /* Set the command header fields */
+ iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action, apply_time);
+
+ /* Set the command data */
+ iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef,
+ chains_static, chains_dynamic);
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC,
+ sizeof(struct iwl_phy_context_cmd),
+ &cmd);
+ if (ret)
+ IWL_ERR(mvm, "PHY ctxt cmd error. ret=%d\n", ret);
+ return ret;
+}
+
+
+struct phy_ctx_used_data {
+ unsigned long used[BITS_TO_LONGS(NUM_PHY_CTX)];
+};
+
+static void iwl_mvm_phy_ctx_used_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx,
+ void *_data)
+{
+ struct phy_ctx_used_data *data = _data;
+ struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv;
+
+ __set_bit(phy_ctxt->id, data->used);
+}
+
+/*
+ * Send a command to add a PHY context based on the current HW configuration.
+ */
+int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
+ struct cfg80211_chan_def *chandef,
+ u8 chains_static, u8 chains_dynamic)
+{
+ struct phy_ctx_used_data data = {
+ .used = { },
+ };
+
+ /*
+ * If this is a regular PHY context (not the ROC one)
+ * skip the ROC PHY context's ID.
+ */
+ if (ctxt != &mvm->phy_ctxt_roc)
+ __set_bit(mvm->phy_ctxt_roc.id, data.used);
+
+ lockdep_assert_held(&mvm->mutex);
+ ctxt->color++;
+
+ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+ ieee80211_iter_chan_contexts_atomic(
+ mvm->hw, iwl_mvm_phy_ctx_used_iter, &data);
+
+ ctxt->id = find_first_zero_bit(data.used, NUM_PHY_CTX);
+ if (WARN_ONCE(ctxt->id == NUM_PHY_CTX,
+ "Failed to init PHY context - no free ID!\n"))
+ return -EIO;
+ }
+
+ ctxt->channel = chandef->chan;
+ return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef,
+ chains_static, chains_dynamic,
+ FW_CTXT_ACTION_ADD, 0);
+}
+
+/*
+ * Send a command to modify the PHY context based on the current HW
+ * configuration. Note that the function does not check that the configuration
+ * changed.
+ */
+int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
+ struct cfg80211_chan_def *chandef,
+ u8 chains_static, u8 chains_dynamic)
+{
+ lockdep_assert_held(&mvm->mutex);
+
+ ctxt->channel = chandef->chan;
+ return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef,
+ chains_static, chains_dynamic,
+ FW_CTXT_ACTION_MODIFY, 0);
+}
+
+/*
+ * Send a command to the FW to remove the given phy context.
+ * Once the command is sent, regardless of success or failure, the context is
+ * marked as invalid
+ */
+void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt)
+{
+ struct iwl_phy_context_cmd cmd;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, FW_CTXT_ACTION_REMOVE, 0);
+ ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC,
+ sizeof(struct iwl_phy_context_cmd),
+ &cmd);
+ if (ret)
+ IWL_ERR(mvm, "Failed to send PHY remove: ctxt id=%d\n",
+ ctxt->id);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
new file mode 100644
index 000000000000..5a92a4978795
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -0,0 +1,207 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <net/mac80211.h>
+
+#include "iwl-debug.h"
+#include "mvm.h"
+#include "iwl-modparams.h"
+#include "fw-api-power.h"
+
+#define POWER_KEEP_ALIVE_PERIOD_SEC 25
+
+static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_powertable_cmd *cmd)
+{
+ struct ieee80211_hw *hw = mvm->hw;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_channel *chan;
+ int dtimper, dtimper_msec;
+ int keep_alive;
+ bool radar_detect = false;
+
+ cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+ mvmvif->color));
+ cmd->action = cpu_to_le32(FW_CTXT_ACTION_MODIFY);
+
+ if ((!vif->bss_conf.ps) ||
+ (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM))
+ return;
+
+ cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
+
+ dtimper = hw->conf.ps_dtim_period ?: 1;
+
+ /* Check if radar detection is required on current channel */
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(vif->chanctx_conf);
+ WARN_ON(!chanctx_conf);
+ if (chanctx_conf) {
+ chan = chanctx_conf->def.chan;
+ radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
+ }
+ rcu_read_unlock();
+
+ /* Check skip over DTIM conditions */
+ if (!radar_detect && (dtimper <= 10) &&
+ (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) {
+ cmd->flags |= cpu_to_le16(POWER_FLAGS_SLEEP_OVER_DTIM_MSK);
+ cmd->num_skip_dtim = 2;
+ }
+
+ /* Check that keep alive period is at least 3 * DTIM */
+ dtimper_msec = dtimper * vif->bss_conf.beacon_int;
+ keep_alive = max_t(int, 3 * dtimper_msec,
+ MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC);
+ keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
+
+ cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
+
+ if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) {
+ /* TODO: Also for D3 (device sleep / WoWLAN) */
+ cmd->rx_data_timeout = cpu_to_le32(10);
+ cmd->tx_data_timeout = cpu_to_le32(10);
+ } else {
+ cmd->rx_data_timeout = cpu_to_le32(50);
+ cmd->tx_data_timeout = cpu_to_le32(50);
+ }
+}
+
+int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_powertable_cmd cmd = {};
+
+ if (!iwlwifi_mod_params.power_save) {
+ IWL_DEBUG_POWER(mvm, "Power management is not allowed\n");
+ return 0;
+ }
+
+ if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+ return 0;
+
+ iwl_power_build_cmd(mvm, vif, &cmd);
+
+ IWL_DEBUG_POWER(mvm,
+ "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
+ cmd.id_and_color, iwlmvm_mod_params.power_scheme,
+ le16_to_cpu(cmd.flags));
+
+ if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
+ IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n",
+ le16_to_cpu(cmd.keep_alive_seconds));
+ IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n",
+ le32_to_cpu(cmd.rx_data_timeout));
+ IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
+ le32_to_cpu(cmd.tx_data_timeout));
+ IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n",
+ le32_to_cpu(cmd.rx_data_timeout_uapsd));
+ IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
+ le32_to_cpu(cmd.tx_data_timeout_uapsd));
+ IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
+ cmd.lprx_rssi_threshold);
+ IWL_DEBUG_POWER(mvm, "DTIMs to skip = %u\n", cmd.num_skip_dtim);
+ }
+
+ return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
+ sizeof(cmd), &cmd);
+}
+
+int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_powertable_cmd cmd = {};
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (!iwlwifi_mod_params.power_save) {
+ IWL_DEBUG_POWER(mvm, "Power management is not allowed\n");
+ return 0;
+ }
+
+ if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+ return 0;
+
+ cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+ mvmvif->color));
+ cmd.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY);
+
+ IWL_DEBUG_POWER(mvm,
+ "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
+ cmd.id_and_color, iwlmvm_mod_params.power_scheme,
+ le16_to_cpu(cmd.flags));
+
+ return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC,
+ sizeof(cmd), &cmd);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_powertable_cmd *cmd)
+{
+ iwl_power_build_cmd(mvm, vif, cmd);
+}
+#endif /* CONFIG_IWLWIFI_DEBUGFS */
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c
new file mode 100644
index 000000000000..925628468146
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/quota.c
@@ -0,0 +1,197 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 <net/mac80211.h>
+#include "fw-api.h"
+#include "mvm.h"
+
+struct iwl_mvm_quota_iterator_data {
+ int n_interfaces[MAX_BINDINGS];
+ int colors[MAX_BINDINGS];
+ struct ieee80211_vif *new_vif;
+};
+
+static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_quota_iterator_data *data = _data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ u16 id;
+
+ /*
+ * We'll account for the new interface (if any) below,
+ * skip it here in case we're not called from within
+ * the add_interface callback (otherwise it won't show
+ * up in iteration)
+ */
+ if (vif == data->new_vif)
+ return;
+
+ if (!mvmvif->phy_ctxt)
+ return;
+
+ /* currently, PHY ID == binding ID */
+ id = mvmvif->phy_ctxt->id;
+
+ /* need at least one binding per PHY */
+ BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS);
+
+ if (WARN_ON_ONCE(id >= MAX_BINDINGS))
+ return;
+
+ if (data->colors[id] < 0)
+ data->colors[id] = mvmvif->phy_ctxt->color;
+ else
+ WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ if (vif->bss_conf.assoc)
+ data->n_interfaces[id]++;
+ break;
+ case NL80211_IFTYPE_AP:
+ if (mvmvif->ap_active)
+ data->n_interfaces[id]++;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ data->n_interfaces[id]++;
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (vif->bss_conf.ibss_joined)
+ data->n_interfaces[id]++;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+}
+
+int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
+{
+ struct iwl_time_quota_cmd cmd;
+ int i, idx, ret, num_active_bindings, quota, quota_rem;
+ struct iwl_mvm_quota_iterator_data data = {
+ .n_interfaces = {},
+ .colors = { -1, -1, -1, -1 },
+ .new_vif = newvif,
+ };
+
+ /* update all upon completion */
+ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ return 0;
+
+ BUILD_BUG_ON(data.colors[MAX_BINDINGS - 1] != -1);
+
+ lockdep_assert_held(&mvm->mutex);
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_quota_iterator, &data);
+ if (newvif) {
+ data.new_vif = NULL;
+ iwl_mvm_quota_iterator(&data, newvif->addr, newvif);
+ }
+
+ /*
+ * The FW's scheduling session consists of
+ * IWL_MVM_MAX_QUOTA fragments. Divide these fragments
+ * equally between all the bindings that require quota
+ */
+ num_active_bindings = 0;
+ for (i = 0; i < MAX_BINDINGS; i++) {
+ cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
+ if (data.n_interfaces[i] > 0)
+ num_active_bindings++;
+ }
+
+ if (!num_active_bindings)
+ goto send_cmd;
+
+ quota = IWL_MVM_MAX_QUOTA / num_active_bindings;
+ quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings;
+
+ for (idx = 0, i = 0; i < MAX_BINDINGS; i++) {
+ if (data.n_interfaces[i] <= 0)
+ continue;
+
+ cmd.quotas[idx].id_and_color =
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i]));
+ cmd.quotas[idx].quota = cpu_to_le32(quota);
+ cmd.quotas[idx].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA);
+ idx++;
+ }
+
+ /* Give the remainder of the session to the first binding */
+ le32_add_cpu(&cmd.quotas[0].quota, quota_rem);
+
+send_cmd:
+ ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC,
+ sizeof(cmd), &cmd);
+ if (ret)
+ IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
+ return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
new file mode 100644
index 000000000000..56b636d9ab30
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -0,0 +1,3080 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2013 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/init.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <net/mac80211.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#include <linux/workqueue.h>
+#include "rs.h"
+#include "fw-api.h"
+#include "sta.h"
+#include "iwl-op-mode.h"
+#include "mvm.h"
+
+#define RS_NAME "iwl-mvm-rs"
+
+#define NUM_TRY_BEFORE_ANT_TOGGLE 1
+#define IWL_NUMBER_TRY 1
+#define IWL_HT_NUMBER_TRY 3
+
+#define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */
+#define IWL_RATE_MIN_FAILURE_TH 6 /* min failures to calc tpt */
+#define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */
+
+/* max allowed rate miss before sync LQ cmd */
+#define IWL_MISSED_RATE_MAX 15
+/* max time to accum history 2 seconds */
+#define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ)
+
+static u8 rs_ht_to_legacy[] = {
+ IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+ IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+ IWL_RATE_6M_INDEX,
+ IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,
+ IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,
+ IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,
+ IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
+};
+
+static const u8 ant_toggle_lookup[] = {
+ /*ANT_NONE -> */ ANT_NONE,
+ /*ANT_A -> */ ANT_B,
+ /*ANT_B -> */ ANT_C,
+ /*ANT_AB -> */ ANT_BC,
+ /*ANT_C -> */ ANT_A,
+ /*ANT_AC -> */ ANT_AB,
+ /*ANT_BC -> */ ANT_AC,
+ /*ANT_ABC -> */ ANT_ABC,
+};
+
+#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \
+ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
+ IWL_RATE_SISO_##s##M_PLCP, \
+ IWL_RATE_MIMO2_##s##M_PLCP,\
+ IWL_RATE_MIMO3_##s##M_PLCP,\
+ IWL_RATE_##r##M_IEEE, \
+ IWL_RATE_##ip##M_INDEX, \
+ IWL_RATE_##in##M_INDEX, \
+ IWL_RATE_##rp##M_INDEX, \
+ IWL_RATE_##rn##M_INDEX, \
+ IWL_RATE_##pp##M_INDEX, \
+ IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
+ IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */
+ IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */
+ IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */
+ IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */
+ IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */
+ IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */
+ IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */
+ IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */
+ IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */
+ IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */
+ IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */
+ IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+ IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+ /* FIXME:RS: ^^ should be INV (legacy) */
+};
+
+static inline u8 rs_extract_rate(u32 rate_n_flags)
+{
+ /* also works for HT because bits 7:6 are zero there */
+ return (u8)(rate_n_flags & RATE_LEGACY_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 = rs_extract_rate(rate_n_flags);
+
+ if (idx >= IWL_RATE_MIMO3_6M_PLCP)
+ idx = idx - IWL_RATE_MIMO3_6M_PLCP;
+ else if (idx >= IWL_RATE_MIMO2_6M_PLCP)
+ idx = idx - IWL_RATE_MIMO2_6M_PLCP;
+
+ idx += IWL_FIRST_OFDM_RATE;
+ /* skip 9M not supported in ht*/
+ if (idx >= IWL_RATE_9M_INDEX)
+ idx += 1;
+ if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE))
+ return idx;
+
+ /* legacy rate format, search for match in table */
+ } else {
+ for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
+ if (iwl_rates[idx].plcp ==
+ rs_extract_rate(rate_n_flags))
+ return idx;
+ }
+
+ return -1;
+}
+
+static void rs_rate_scale_perform(struct iwl_mvm *mvm,
+ struct sk_buff *skb,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta);
+static void rs_fill_link_cmd(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+ u32 *rate_n_flags, int index);
+#else
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+ u32 *rate_n_flags, int index)
+{}
+#endif
+
+/**
+ * The following tables contain the expected throughput metrics for all rates
+ *
+ * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
+ *
+ * where invalid entries are zeros.
+ *
+ * CCK rates are only valid in legacy table and will only be used in G
+ * (2.4 GHz) band.
+ */
+
+static s32 expected_tpt_legacy[IWL_RATE_COUNT] = {
+ 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0
+};
+
+static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202}, /* Norm */
+ {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210}, /* SGI */
+ {0, 0, 0, 0, 47, 0, 91, 133, 171, 242, 305, 334, 362}, /* AGG */
+ {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */
+ {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */
+ {0, 0, 0, 0, 94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */
+ {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */
+ {0, 0, 0, 0, 81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */
+ {0, 0, 0, 0, 89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */
+ {0, 0, 0, 0, 97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/
+};
+
+static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */
+ {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */
+ {0, 0, 0, 0, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */
+ {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */
+ {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */
+ {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */
+ {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */
+ {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */
+ {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */
+ {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */
+};
+
+/* mbps, mcs */
+static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
+ { "1", "BPSK DSSS"},
+ { "2", "QPSK DSSS"},
+ {"5.5", "BPSK CCK"},
+ { "11", "QPSK CCK"},
+ { "6", "BPSK 1/2"},
+ { "9", "BPSK 1/2"},
+ { "12", "QPSK 1/2"},
+ { "18", "QPSK 3/4"},
+ { "24", "16QAM 1/2"},
+ { "36", "16QAM 3/4"},
+ { "48", "64QAM 2/3"},
+ { "54", "64QAM 3/4"},
+ { "60", "64QAM 5/6"},
+};
+
+#define MCS_INDEX_PER_STREAM (8)
+
+static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
+{
+ window->data = 0;
+ window->success_counter = 0;
+ window->success_ratio = IWL_INVALID_VALUE;
+ window->counter = 0;
+ window->average_tpt = IWL_INVALID_VALUE;
+ window->stamp = 0;
+}
+
+static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
+{
+ return (ant_type & valid_antenna) == ant_type;
+}
+
+/*
+ * removes the old data from the statistics. All data that is older than
+ * TID_MAX_TIME_DIFF, will be deleted.
+ */
+static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time)
+{
+ /* The oldest age we want to keep */
+ u32 oldest_time = curr_time - TID_MAX_TIME_DIFF;
+
+ while (tl->queue_count &&
+ (tl->time_stamp < oldest_time)) {
+ tl->total -= tl->packet_count[tl->head];
+ tl->packet_count[tl->head] = 0;
+ tl->time_stamp += TID_QUEUE_CELL_SPACING;
+ tl->queue_count--;
+ tl->head++;
+ if (tl->head >= TID_QUEUE_MAX_SIZE)
+ tl->head = 0;
+ }
+}
+
+/*
+ * increment traffic load value for tid and also remove
+ * any old values if passed the certain time period
+ */
+static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
+ struct ieee80211_hdr *hdr)
+{
+ u32 curr_time = jiffies_to_msecs(jiffies);
+ u32 time_diff;
+ s32 index;
+ struct iwl_traffic_load *tl = NULL;
+ u8 tid;
+
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & 0xf;
+ } else {
+ return IWL_MAX_TID_COUNT;
+ }
+
+ if (unlikely(tid >= IWL_MAX_TID_COUNT))
+ return IWL_MAX_TID_COUNT;
+
+ tl = &lq_data->load[tid];
+
+ curr_time -= curr_time % TID_ROUND_VALUE;
+
+ /* Happens only for the first packet. Initialize the data */
+ if (!(tl->queue_count)) {
+ tl->total = 1;
+ tl->time_stamp = curr_time;
+ tl->queue_count = 1;
+ tl->head = 0;
+ tl->packet_count[0] = 1;
+ return IWL_MAX_TID_COUNT;
+ }
+
+ time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
+ index = time_diff / TID_QUEUE_CELL_SPACING;
+
+ /* The history is too long: remove data that is older than */
+ /* TID_MAX_TIME_DIFF */
+ if (index >= TID_QUEUE_MAX_SIZE)
+ rs_tl_rm_old_stats(tl, curr_time);
+
+ index = (tl->head + index) % TID_QUEUE_MAX_SIZE;
+ tl->packet_count[index] = tl->packet_count[index] + 1;
+ tl->total = tl->total + 1;
+
+ if ((index + 1) > tl->queue_count)
+ tl->queue_count = index + 1;
+
+ return tid;
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+/**
+ * Program the device to use fixed rate for frame transmit
+ * This is for debugging/testing only
+ * once the device start use fixed rate, we need to reload the module
+ * to being back the normal operation.
+ */
+static void rs_program_fix_rate(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta)
+{
+ 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(mvm, "sta_id %d rate 0x%X\n",
+ lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
+
+ if (lq_sta->dbg_fixed_rate) {
+ rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
+ iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false);
+ }
+}
+#endif
+
+/*
+ get the traffic load value for tid
+*/
+static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
+{
+ u32 curr_time = jiffies_to_msecs(jiffies);
+ u32 time_diff;
+ s32 index;
+ struct iwl_traffic_load *tl = NULL;
+
+ if (tid >= IWL_MAX_TID_COUNT)
+ return 0;
+
+ tl = &(lq_data->load[tid]);
+
+ curr_time -= curr_time % TID_ROUND_VALUE;
+
+ if (!(tl->queue_count))
+ return 0;
+
+ time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
+ index = time_diff / TID_QUEUE_CELL_SPACING;
+
+ /* The history is too long: remove data that is older than */
+ /* TID_MAX_TIME_DIFF */
+ if (index >= TID_QUEUE_MAX_SIZE)
+ rs_tl_rm_old_stats(tl, curr_time);
+
+ return tl->total;
+}
+
+static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_data, u8 tid,
+ struct ieee80211_sta *sta)
+{
+ int ret = -EAGAIN;
+ u32 load;
+
+ load = rs_tl_get_load(lq_data, tid);
+
+ if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) {
+ IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n",
+ sta->addr, tid);
+ ret = ieee80211_start_tx_ba_session(sta, tid, 5000);
+ if (ret == -EAGAIN) {
+ /*
+ * driver and mac80211 is out of sync
+ * this might be cause by reloading firmware
+ * stop the tx ba session here
+ */
+ IWL_ERR(mvm, "Fail start Tx agg on tid: %d\n",
+ tid);
+ ieee80211_stop_tx_ba_session(sta, tid);
+ }
+ } else {
+ IWL_DEBUG_HT(mvm,
+ "Aggregation not enabled for tid %d because load = %u\n",
+ tid, load);
+ }
+ return ret;
+}
+
+static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, u8 tid,
+ struct iwl_lq_sta *lq_data,
+ struct ieee80211_sta *sta)
+{
+ if (tid < IWL_MAX_TID_COUNT)
+ rs_tl_turn_on_agg_for_tid(mvm, lq_data, tid, sta);
+ else
+ IWL_ERR(mvm, "tid exceeds max TID count: %d/%d\n",
+ tid, IWL_MAX_TID_COUNT);
+}
+
+static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
+{
+ return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
+ !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
+ !!(rate_n_flags & RATE_MCS_ANT_C_MSK);
+}
+
+/*
+ * Static function to get the expected throughput from an iwl_scale_tbl_info
+ * that wraps a NULL pointer check
+ */
+static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
+{
+ if (tbl->expected_tpt)
+ return tbl->expected_tpt[rs_index];
+ return 0;
+}
+
+/**
+ * rs_collect_tx_data - Update the success/failure sliding window
+ *
+ * We keep a sliding window of the last 62 packets transmitted
+ * at this rate. window->data contains the bitmask of successful
+ * packets.
+ */
+static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
+ int scale_index, int attempts, int successes)
+{
+ struct iwl_rate_scale_data *window = NULL;
+ static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
+ s32 fail_count, tpt;
+
+ if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
+ return -EINVAL;
+
+ /* Select window for current tx bit rate */
+ window = &(tbl->win[scale_index]);
+
+ /* Get expected throughput */
+ tpt = get_expected_tpt(tbl, scale_index);
+
+ /*
+ * Keep track of only the latest 62 tx frame attempts in this rate's
+ * history window; anything older isn't really relevant any more.
+ * If we have filled up the sliding window, drop the oldest attempt;
+ * if the oldest attempt (highest bit in bitmap) shows "success",
+ * subtract "1" from the success counter (this is the main reason
+ * we keep these bitmaps!).
+ */
+ while (attempts > 0) {
+ if (window->counter >= IWL_RATE_MAX_WINDOW) {
+ /* remove earliest */
+ window->counter = IWL_RATE_MAX_WINDOW - 1;
+
+ if (window->data & mask) {
+ window->data &= ~mask;
+ window->success_counter--;
+ }
+ }
+
+ /* Increment frames-attempted counter */
+ window->counter++;
+
+ /* Shift bitmap by one frame to throw away oldest history */
+ window->data <<= 1;
+
+ /* Mark the most recent #successes attempts as successful */
+ if (successes > 0) {
+ window->success_counter++;
+ window->data |= 0x1;
+ successes--;
+ }
+
+ attempts--;
+ }
+
+ /* Calculate current success ratio, avoid divide-by-0! */
+ if (window->counter > 0)
+ window->success_ratio = 128 * (100 * window->success_counter)
+ / window->counter;
+ else
+ window->success_ratio = IWL_INVALID_VALUE;
+
+ fail_count = window->counter - window->success_counter;
+
+ /* Calculate average throughput, if we have enough history. */
+ if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
+ (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+ window->average_tpt = (window->success_ratio * tpt + 64) / 128;
+ else
+ window->average_tpt = IWL_INVALID_VALUE;
+
+ /* Tag this window as having been updated */
+ window->stamp = jiffies;
+
+ return 0;
+}
+
+/*
+ * Fill uCode API rate_n_flags field, based on "search" or "active" table.
+ */
+/* FIXME:RS:remove this function and put the flags statically in the table */
+static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm,
+ struct iwl_scale_tbl_info *tbl,
+ int index, u8 use_green)
+{
+ u32 rate_n_flags = 0;
+
+ if (is_legacy(tbl->lq_type)) {
+ rate_n_flags = iwl_rates[index].plcp;
+ if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
+ rate_n_flags |= RATE_MCS_CCK_MSK;
+ } else if (is_Ht(tbl->lq_type)) {
+ if (index > IWL_LAST_OFDM_RATE) {
+ IWL_ERR(mvm, "Invalid HT rate index %d\n", index);
+ index = IWL_LAST_OFDM_RATE;
+ }
+ rate_n_flags = RATE_MCS_HT_MSK;
+
+ if (is_siso(tbl->lq_type))
+ rate_n_flags |= iwl_rates[index].plcp_siso;
+ else if (is_mimo2(tbl->lq_type))
+ rate_n_flags |= iwl_rates[index].plcp_mimo2;
+ else
+ rate_n_flags |= iwl_rates[index].plcp_mimo3;
+ } else {
+ IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type);
+ }
+
+ rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
+ RATE_MCS_ANT_ABC_MSK);
+
+ if (is_Ht(tbl->lq_type)) {
+ if (tbl->is_ht40)
+ rate_n_flags |= RATE_MCS_CHAN_WIDTH_40;
+ if (tbl->is_SGI)
+ rate_n_flags |= RATE_MCS_SGI_MSK;
+
+ if (use_green) {
+ rate_n_flags |= RATE_HT_MCS_GF_MSK;
+ if (is_siso(tbl->lq_type) && tbl->is_SGI) {
+ rate_n_flags &= ~RATE_MCS_SGI_MSK;
+ IWL_ERR(mvm, "GF was set with SGI:SISO\n");
+ }
+ }
+ }
+ return rate_n_flags;
+}
+
+/*
+ * Interpret uCode API's rate_n_flags format,
+ * fill "search" or "active" tx mode table.
+ */
+static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
+ enum ieee80211_band band,
+ struct iwl_scale_tbl_info *tbl,
+ int *rate_idx)
+{
+ u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
+ u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
+ u8 mcs;
+
+ memset(tbl, 0, sizeof(struct iwl_scale_tbl_info));
+ *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
+
+ if (*rate_idx == IWL_RATE_INVALID) {
+ *rate_idx = -1;
+ return -EINVAL;
+ }
+ tbl->is_SGI = 0; /* default legacy setup */
+ tbl->is_ht40 = 0;
+ tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
+ tbl->lq_type = LQ_NONE;
+ tbl->max_search = IWL_MAX_SEARCH;
+
+ /* legacy rate format */
+ if (!(rate_n_flags & RATE_MCS_HT_MSK)) {
+ if (num_of_ant == 1) {
+ if (band == IEEE80211_BAND_5GHZ)
+ tbl->lq_type = LQ_A;
+ else
+ tbl->lq_type = LQ_G;
+ }
+ /* HT rate format */
+ } else {
+ if (rate_n_flags & RATE_MCS_SGI_MSK)
+ tbl->is_SGI = 1;
+
+ if (rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */
+ tbl->is_ht40 = 1;
+
+ mcs = rs_extract_rate(rate_n_flags);
+
+ /* SISO */
+ if (mcs <= IWL_RATE_SISO_60M_PLCP) {
+ if (num_of_ant == 1)
+ tbl->lq_type = LQ_SISO; /*else NONE*/
+ /* MIMO2 */
+ } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) {
+ if (num_of_ant == 2)
+ tbl->lq_type = LQ_MIMO2;
+ /* MIMO3 */
+ } else {
+ if (num_of_ant == 3) {
+ tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
+ tbl->lq_type = LQ_MIMO3;
+ }
+ }
+ }
+ return 0;
+}
+
+/* switch to another antenna/antennas and return 1 */
+/* if no other valid antenna found, return 0 */
+static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
+ struct iwl_scale_tbl_info *tbl)
+{
+ u8 new_ant_type;
+
+ if (!tbl->ant_type || tbl->ant_type > ANT_ABC)
+ return 0;
+
+ if (!rs_is_valid_ant(valid_ant, tbl->ant_type))
+ return 0;
+
+ new_ant_type = ant_toggle_lookup[tbl->ant_type];
+
+ while ((new_ant_type != tbl->ant_type) &&
+ !rs_is_valid_ant(valid_ant, new_ant_type))
+ new_ant_type = ant_toggle_lookup[new_ant_type];
+
+ if (new_ant_type == tbl->ant_type)
+ return 0;
+
+ tbl->ant_type = new_ant_type;
+ *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK;
+ *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS;
+ return 1;
+}
+
+/**
+ * Green-field mode is valid if the station supports it and
+ * there are no non-GF stations present in the BSS.
+ */
+static bool rs_use_green(struct ieee80211_sta *sta)
+{
+ struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
+
+ bool use_green = !(sta_priv->vif->bss_conf.ht_operation_mode &
+ IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+
+ return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && use_green;
+}
+
+/**
+ * rs_get_supported_rates - get the available rates
+ *
+ * if management frame or broadcast frame only return
+ * basic available rates.
+ *
+ */
+static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
+ struct ieee80211_hdr *hdr,
+ enum iwl_table_type rate_type)
+{
+ if (is_legacy(rate_type)) {
+ return lq_sta->active_legacy_rate;
+ } else {
+ if (is_siso(rate_type))
+ return lq_sta->active_siso_rate;
+ else if (is_mimo2(rate_type))
+ return lq_sta->active_mimo2_rate;
+ else
+ return lq_sta->active_mimo3_rate;
+ }
+}
+
+static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
+ int rate_type)
+{
+ u8 high = IWL_RATE_INVALID;
+ u8 low = IWL_RATE_INVALID;
+
+ /* 802.11A or ht walks to the next literal adjacent rate in
+ * the rate table */
+ if (is_a_band(rate_type) || !is_legacy(rate_type)) {
+ int i;
+ u32 mask;
+
+ /* Find the previous rate that is in the rate mask */
+ i = index - 1;
+ for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+ if (rate_mask & mask) {
+ low = i;
+ break;
+ }
+ }
+
+ /* Find the next rate that is in the rate mask */
+ i = index + 1;
+ for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
+ if (rate_mask & mask) {
+ high = i;
+ break;
+ }
+ }
+
+ return (high << 8) | low;
+ }
+
+ low = index;
+ while (low != IWL_RATE_INVALID) {
+ low = iwl_rates[low].prev_rs;
+ if (low == IWL_RATE_INVALID)
+ break;
+ if (rate_mask & (1 << low))
+ break;
+ IWL_DEBUG_RATE(mvm, "Skipping masked lower rate: %d\n", low);
+ }
+
+ high = index;
+ while (high != IWL_RATE_INVALID) {
+ high = iwl_rates[high].next_rs;
+ if (high == IWL_RATE_INVALID)
+ break;
+ if (rate_mask & (1 << high))
+ break;
+ IWL_DEBUG_RATE(mvm, "Skipping masked higher rate: %d\n", high);
+ }
+
+ return (high << 8) | low;
+}
+
+static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl,
+ u8 scale_index, u8 ht_possible)
+{
+ s32 low;
+ u16 rate_mask;
+ u16 high_low;
+ u8 switch_to_legacy = 0;
+ u8 is_green = lq_sta->is_green;
+ struct iwl_mvm *mvm = lq_sta->drv;
+
+ /* check if we need to switch from HT to legacy rates.
+ * assumption is that mandatory rates (1Mbps or 6Mbps)
+ * are always supported (spec demand) */
+ if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
+ switch_to_legacy = 1;
+ scale_index = rs_ht_to_legacy[scale_index];
+ if (lq_sta->band == IEEE80211_BAND_5GHZ)
+ tbl->lq_type = LQ_A;
+ else
+ tbl->lq_type = LQ_G;
+
+ if (num_of_ant(tbl->ant_type) > 1)
+ tbl->ant_type =
+ first_antenna(mvm->nvm_data->valid_tx_ant);
+
+ tbl->is_ht40 = 0;
+ tbl->is_SGI = 0;
+ tbl->max_search = IWL_MAX_SEARCH;
+ }
+
+ rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
+
+ /* Mask with station rate restriction */
+ if (is_legacy(tbl->lq_type)) {
+ /* supp_rates has no CCK bits in A mode */
+ if (lq_sta->band == IEEE80211_BAND_5GHZ)
+ rate_mask = (u16)(rate_mask &
+ (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
+ else
+ rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
+ }
+
+ /* If we switched from HT to legacy, check current rate */
+ if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
+ low = scale_index;
+ goto out;
+ }
+
+ high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
+ tbl->lq_type);
+ low = high_low & 0xff;
+
+ if (low == IWL_RATE_INVALID)
+ low = scale_index;
+
+out:
+ return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green);
+}
+
+/*
+ * Simple function to compare two rate scale table types
+ */
+static bool table_type_matches(struct iwl_scale_tbl_info *a,
+ struct iwl_scale_tbl_info *b)
+{
+ return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&
+ (a->is_SGI == b->is_SGI);
+}
+
+/*
+ * mac80211 sends us Tx status
+ */
+static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ struct sk_buff *skb)
+{
+ int legacy_success;
+ int retries;
+ int rs_index, mac_index, i;
+ struct iwl_lq_sta *lq_sta = priv_sta;
+ struct iwl_lq_cmd *table;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_r;
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ enum mac80211_rate_control_flags mac_flags;
+ u32 tx_rate;
+ struct iwl_scale_tbl_info tbl_type;
+ struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
+
+ IWL_DEBUG_RATE_LIMIT(mvm,
+ "get frame ack response, update rate scale window\n");
+
+ /* Treat uninitialized rate scaling data same as non-existing. */
+ if (!lq_sta) {
+ IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n");
+ return;
+ } else if (!lq_sta->drv) {
+ IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n");
+ return;
+ }
+
+ if (!ieee80211_is_data(hdr->frame_control) ||
+ info->flags & IEEE80211_TX_CTL_NO_ACK)
+ return;
+
+ /* This packet was aggregated but doesn't carry status info */
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ !(info->flags & IEEE80211_TX_STAT_AMPDU))
+ return;
+
+ /*
+ * Ignore this Tx frame response if its initial rate doesn't match
+ * that of latest Link Quality command. There may be stragglers
+ * from a previous Link Quality command, but we're no longer interested
+ * in those; they're either from the "active" mode while we're trying
+ * to check "search" mode, or a prior "search" mode after we've moved
+ * to a new "search" mode (which might become the new "active" mode).
+ */
+ table = &lq_sta->lq;
+ tx_rate = le32_to_cpu(table->rs_table[0]);
+ rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, &rs_index);
+ if (info->band == IEEE80211_BAND_5GHZ)
+ rs_index -= IWL_FIRST_OFDM_RATE;
+ mac_flags = info->status.rates[0].flags;
+ mac_index = info->status.rates[0].idx;
+ /* For HT packets, map MCS to PLCP */
+ if (mac_flags & IEEE80211_TX_RC_MCS) {
+ /* Remove # of streams */
+ mac_index &= RATE_HT_MCS_RATE_CODE_MSK;
+ if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE))
+ mac_index++;
+ /*
+ * mac80211 HT index is always zero-indexed; we need to move
+ * HT OFDM rates after CCK rates in 2.4 GHz band
+ */
+ if (info->band == IEEE80211_BAND_2GHZ)
+ mac_index += IWL_FIRST_OFDM_RATE;
+ }
+ /* Here we actually compare this rate to the latest LQ command */
+ if ((mac_index < 0) ||
+ (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
+ (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
+ (tbl_type.ant_type != info->status.antenna) ||
+ (!!(tx_rate & RATE_MCS_HT_MSK) !=
+ !!(mac_flags & IEEE80211_TX_RC_MCS)) ||
+ (!!(tx_rate & RATE_HT_MCS_GF_MSK) !=
+ !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
+ (rs_index != mac_index)) {
+ IWL_DEBUG_RATE(mvm,
+ "initial rate %d does not match %d (0x%x)\n",
+ mac_index, rs_index, tx_rate);
+ /*
+ * Since rates mis-match, the last LQ command may have failed.
+ * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
+ * ... driver.
+ */
+ lq_sta->missed_rate_counter++;
+ if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
+ lq_sta->missed_rate_counter = 0;
+ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false);
+ }
+ /* Regardless, ignore this status info for outdated rate */
+ return;
+ } else
+ /* Rate did match, so reset the missed_rate_counter */
+ lq_sta->missed_rate_counter = 0;
+
+ /* Figure out if rate scale algorithm is in active or search table */
+ if (table_type_matches(&tbl_type,
+ &(lq_sta->lq_info[lq_sta->active_tbl]))) {
+ curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+ } else if (table_type_matches(
+ &tbl_type, &lq_sta->lq_info[1 - lq_sta->active_tbl])) {
+ curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+ other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ } else {
+ IWL_DEBUG_RATE(mvm,
+ "Neither active nor search matches tx rate\n");
+ tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ IWL_DEBUG_RATE(mvm, "active- lq:%x, ant:%x, SGI:%d\n",
+ tmp_tbl->lq_type, tmp_tbl->ant_type,
+ tmp_tbl->is_SGI);
+ tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+ IWL_DEBUG_RATE(mvm, "search- lq:%x, ant:%x, SGI:%d\n",
+ tmp_tbl->lq_type, tmp_tbl->ant_type,
+ tmp_tbl->is_SGI);
+ IWL_DEBUG_RATE(mvm, "actual- lq:%x, ant:%x, SGI:%d\n",
+ tbl_type.lq_type, tbl_type.ant_type,
+ tbl_type.is_SGI);
+ /*
+ * no matching table found, let's by-pass the data collection
+ * and continue to perform rate scale to find the rate table
+ */
+ rs_stay_in_table(lq_sta, true);
+ goto done;
+ }
+
+ /*
+ * Updating the frame history depends on whether packets were
+ * aggregated.
+ *
+ * For aggregation, all packets were transmitted at the same rate, the
+ * first index into rate scale table.
+ */
+ if (info->flags & IEEE80211_TX_STAT_AMPDU) {
+ tx_rate = le32_to_cpu(table->rs_table[0]);
+ rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type,
+ &rs_index);
+ rs_collect_tx_data(curr_tbl, rs_index,
+ info->status.ampdu_len,
+ info->status.ampdu_ack_len);
+
+ /* Update success/fail counts if not searching for new mode */
+ if (lq_sta->stay_in_tbl) {
+ lq_sta->total_success += info->status.ampdu_ack_len;
+ lq_sta->total_failed += (info->status.ampdu_len -
+ info->status.ampdu_ack_len);
+ }
+ } else {
+ /*
+ * For legacy, update frame history with for each Tx retry.
+ */
+ retries = info->status.rates[0].count - 1;
+ /* HW doesn't send more than 15 retries */
+ retries = min(retries, 15);
+
+ /* The last transmission may have been successful */
+ legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+ /* Collect data for each rate used during failed TX attempts */
+ for (i = 0; i <= retries; ++i) {
+ tx_rate = le32_to_cpu(table->rs_table[i]);
+ rs_get_tbl_info_from_mcs(tx_rate, info->band,
+ &tbl_type, &rs_index);
+ /*
+ * Only collect stats if retried rate is in the same RS
+ * table as active/search.
+ */
+ if (table_type_matches(&tbl_type, curr_tbl))
+ tmp_tbl = curr_tbl;
+ else if (table_type_matches(&tbl_type, other_tbl))
+ tmp_tbl = other_tbl;
+ else
+ continue;
+ rs_collect_tx_data(tmp_tbl, rs_index, 1,
+ i < retries ? 0 : legacy_success);
+ }
+
+ /* Update success/fail counts if not searching for new mode */
+ if (lq_sta->stay_in_tbl) {
+ lq_sta->total_success += legacy_success;
+ lq_sta->total_failed += retries + (1 - legacy_success);
+ }
+ }
+ /* The last TX rate is cached in lq_sta; it's set in if/else above */
+ lq_sta->last_rate_n_flags = tx_rate;
+done:
+ /* See if there's a better rate or modulation mode to try. */
+ if (sta && sta->supp_rates[sband->band])
+ rs_rate_scale_perform(mvm, skb, sta, lq_sta);
+}
+
+/*
+ * Begin a period of staying with a selected modulation mode.
+ * Set "stay_in_tbl" flag to prevent any mode switches.
+ * Set frame tx success limits according to legacy vs. high-throughput,
+ * and reset overall (spanning all rates) tx success history statistics.
+ * These control how long we stay using same modulation mode before
+ * searching for a new mode.
+ */
+static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
+ struct iwl_lq_sta *lq_sta)
+{
+ IWL_DEBUG_RATE(mvm, "we are staying in the same table\n");
+ lq_sta->stay_in_tbl = 1; /* only place this gets set */
+ if (is_legacy) {
+ lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
+ lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
+ lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
+ } else {
+ lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
+ lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
+ lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
+ }
+ lq_sta->table_count = 0;
+ lq_sta->total_failed = 0;
+ lq_sta->total_success = 0;
+ lq_sta->flush_timer = jiffies;
+ lq_sta->action_counter = 0;
+}
+
+/*
+ * Find correct throughput table for given mode of modulation
+ */
+static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl)
+{
+ /* Used to choose among HT tables */
+ s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
+
+ /* Check for invalid LQ type */
+ if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) {
+ tbl->expected_tpt = expected_tpt_legacy;
+ return;
+ }
+
+ /* Legacy rates have only one table */
+ if (is_legacy(tbl->lq_type)) {
+ tbl->expected_tpt = expected_tpt_legacy;
+ return;
+ }
+
+ /* Choose among many HT tables depending on number of streams
+ * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation
+ * status */
+ if (is_siso(tbl->lq_type) && !tbl->is_ht40)
+ ht_tbl_pointer = expected_tpt_siso20MHz;
+ else if (is_siso(tbl->lq_type))
+ ht_tbl_pointer = expected_tpt_siso40MHz;
+ else if (is_mimo2(tbl->lq_type) && !tbl->is_ht40)
+ ht_tbl_pointer = expected_tpt_mimo2_20MHz;
+ else if (is_mimo2(tbl->lq_type))
+ ht_tbl_pointer = expected_tpt_mimo2_40MHz;
+ else if (is_mimo3(tbl->lq_type) && !tbl->is_ht40)
+ ht_tbl_pointer = expected_tpt_mimo3_20MHz;
+ else /* if (is_mimo3(tbl->lq_type)) <-- must be true */
+ ht_tbl_pointer = expected_tpt_mimo3_40MHz;
+
+ if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */
+ tbl->expected_tpt = ht_tbl_pointer[0];
+ else if (tbl->is_SGI && !lq_sta->is_agg) /* SGI */
+ tbl->expected_tpt = ht_tbl_pointer[1];
+ else if (!tbl->is_SGI && lq_sta->is_agg) /* AGG */
+ tbl->expected_tpt = ht_tbl_pointer[2];
+ else /* AGG+SGI */
+ tbl->expected_tpt = ht_tbl_pointer[3];
+}
+
+/*
+ * Find starting rate for new "search" high-throughput mode of modulation.
+ * Goal is to find lowest expected rate (under perfect conditions) that is
+ * above the current measured throughput of "active" mode, to give new mode
+ * a fair chance to prove itself without too many challenges.
+ *
+ * This gets called when transitioning to more aggressive modulation
+ * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
+ * (i.e. MIMO to SISO). When moving to MIMO, bit rate will typically need
+ * to decrease to match "active" throughput. When moving from MIMO to SISO,
+ * bit rate will typically need to increase, but not if performance was bad.
+ */
+static s32 rs_get_best_rate(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl, /* "search" */
+ u16 rate_mask, s8 index)
+{
+ /* "active" values */
+ struct iwl_scale_tbl_info *active_tbl =
+ &(lq_sta->lq_info[lq_sta->active_tbl]);
+ s32 active_sr = active_tbl->win[index].success_ratio;
+ s32 active_tpt = active_tbl->expected_tpt[index];
+
+ /* expected "search" throughput */
+ s32 *tpt_tbl = tbl->expected_tpt;
+
+ s32 new_rate, high, low, start_hi;
+ u16 high_low;
+ s8 rate = index;
+
+ new_rate = high = low = start_hi = IWL_RATE_INVALID;
+
+ while (1) {
+ high_low = rs_get_adjacent_rate(mvm, rate, rate_mask,
+ tbl->lq_type);
+
+ low = high_low & 0xff;
+ high = (high_low >> 8) & 0xff;
+
+ /*
+ * Lower the "search" bit rate, to give new "search" mode
+ * approximately the same throughput as "active" if:
+ *
+ * 1) "Active" mode has been working modestly well (but not
+ * great), and expected "search" throughput (under perfect
+ * conditions) at candidate rate is above the actual
+ * measured "active" throughput (but less than expected
+ * "active" throughput under perfect conditions).
+ * OR
+ * 2) "Active" mode has been working perfectly or very well
+ * and expected "search" throughput (under perfect
+ * conditions) at candidate rate is above expected
+ * "active" throughput (under perfect conditions).
+ */
+ if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) &&
+ ((active_sr > IWL_RATE_DECREASE_TH) &&
+ (active_sr <= IWL_RATE_HIGH_TH) &&
+ (tpt_tbl[rate] <= active_tpt))) ||
+ ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
+ (tpt_tbl[rate] > active_tpt))) {
+ /* (2nd or later pass)
+ * If we've already tried to raise the rate, and are
+ * now trying to lower it, use the higher rate. */
+ if (start_hi != IWL_RATE_INVALID) {
+ new_rate = start_hi;
+ break;
+ }
+
+ new_rate = rate;
+
+ /* Loop again with lower rate */
+ if (low != IWL_RATE_INVALID)
+ rate = low;
+
+ /* Lower rate not available, use the original */
+ else
+ break;
+
+ /* Else try to raise the "search" rate to match "active" */
+ } else {
+ /* (2nd or later pass)
+ * If we've already tried to lower the rate, and are
+ * now trying to raise it, use the lower rate. */
+ if (new_rate != IWL_RATE_INVALID)
+ break;
+
+ /* Loop again with higher rate */
+ else if (high != IWL_RATE_INVALID) {
+ start_hi = high;
+ rate = high;
+
+ /* Higher rate not available, use the original */
+ } else {
+ new_rate = rate;
+ break;
+ }
+ }
+ }
+
+ return new_rate;
+}
+
+static bool iwl_is_ht40_tx_allowed(struct ieee80211_sta *sta)
+{
+ return sta->bandwidth >= IEEE80211_STA_RX_BW_40;
+}
+
+/*
+ * Set up search table for MIMO2
+ */
+static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta *sta,
+ struct iwl_scale_tbl_info *tbl, int index)
+{
+ u16 rate_mask;
+ s32 rate;
+ s8 is_green = lq_sta->is_green;
+
+ if (!sta->ht_cap.ht_supported)
+ return -1;
+
+ if (sta->smps_mode == IEEE80211_SMPS_STATIC)
+ return -1;
+
+ /* Need both Tx chains/antennas to support MIMO */
+ if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 2)
+ return -1;
+
+ IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n");
+
+ tbl->lq_type = LQ_MIMO2;
+ tbl->action = 0;
+ tbl->max_search = IWL_MAX_SEARCH;
+ rate_mask = lq_sta->active_mimo2_rate;
+
+ if (iwl_is_ht40_tx_allowed(sta))
+ tbl->is_ht40 = 1;
+ else
+ tbl->is_ht40 = 0;
+
+ rs_set_expected_tpt_table(lq_sta, tbl);
+
+ rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
+
+ IWL_DEBUG_RATE(mvm, "LQ: MIMO2 best rate %d mask %X\n",
+ rate, rate_mask);
+ if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+ IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n",
+ rate, rate_mask);
+ return -1;
+ }
+ tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green);
+
+ IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n",
+ tbl->current_rate, is_green);
+ return 0;
+}
+
+/*
+ * Set up search table for MIMO3
+ */
+static int rs_switch_to_mimo3(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta *sta,
+ struct iwl_scale_tbl_info *tbl, int index)
+{
+ u16 rate_mask;
+ s32 rate;
+ s8 is_green = lq_sta->is_green;
+
+ if (!sta->ht_cap.ht_supported)
+ return -1;
+
+ if (sta->smps_mode == IEEE80211_SMPS_STATIC)
+ return -1;
+
+ /* Need both Tx chains/antennas to support MIMO */
+ if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 3)
+ return -1;
+
+ IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n");
+
+ tbl->lq_type = LQ_MIMO3;
+ tbl->action = 0;
+ tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
+ rate_mask = lq_sta->active_mimo3_rate;
+
+ if (iwl_is_ht40_tx_allowed(sta))
+ tbl->is_ht40 = 1;
+ else
+ tbl->is_ht40 = 0;
+
+ rs_set_expected_tpt_table(lq_sta, tbl);
+
+ rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
+
+ IWL_DEBUG_RATE(mvm, "LQ: MIMO3 best rate %d mask %X\n",
+ rate, rate_mask);
+ if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+ IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n",
+ rate, rate_mask);
+ return -1;
+ }
+ tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green);
+
+ IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n",
+ tbl->current_rate, is_green);
+ return 0;
+}
+
+/*
+ * Set up search table for SISO
+ */
+static int rs_switch_to_siso(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta *sta,
+ struct iwl_scale_tbl_info *tbl, int index)
+{
+ u16 rate_mask;
+ u8 is_green = lq_sta->is_green;
+ s32 rate;
+
+ if (!sta->ht_cap.ht_supported)
+ return -1;
+
+ IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n");
+
+ tbl->lq_type = LQ_SISO;
+ tbl->action = 0;
+ tbl->max_search = IWL_MAX_SEARCH;
+ rate_mask = lq_sta->active_siso_rate;
+
+ if (iwl_is_ht40_tx_allowed(sta))
+ tbl->is_ht40 = 1;
+ else
+ tbl->is_ht40 = 0;
+
+ if (is_green)
+ tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
+
+ rs_set_expected_tpt_table(lq_sta, tbl);
+ rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
+
+ IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n", rate, rate_mask);
+ if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+ IWL_DEBUG_RATE(mvm,
+ "can not switch with index %d rate mask %x\n",
+ rate, rate_mask);
+ return -1;
+ }
+ tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate, is_green);
+ IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index is green %X\n",
+ tbl->current_rate, is_green);
+ return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from legacy
+ */
+static int rs_move_legacy_other(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta *sta,
+ int index)
+{
+ struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action;
+ u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ u8 tx_chains_num = num_of_ant(valid_tx_ant);
+ int ret;
+ u8 update_search_tbl_counter = 0;
+
+ start_action = tbl->action;
+ while (1) {
+ lq_sta->action_counter++;
+ switch (tbl->action) {
+ case IWL_LEGACY_SWITCH_ANTENNA1:
+ case IWL_LEGACY_SWITCH_ANTENNA2:
+ IWL_DEBUG_RATE(mvm, "LQ: Legacy toggle Antenna\n");
+
+ if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 &&
+ tx_chains_num <= 1) ||
+ (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 &&
+ tx_chains_num <= 2))
+ break;
+
+ /* Don't change antenna if success has been great */
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ break;
+
+ /* Set up search table to try other antenna */
+ memcpy(search_tbl, tbl, sz);
+
+ if (rs_toggle_antenna(valid_tx_ant,
+ &search_tbl->current_rate,
+ search_tbl)) {
+ update_search_tbl_counter = 1;
+ rs_set_expected_tpt_table(lq_sta, search_tbl);
+ goto out;
+ }
+ break;
+ case IWL_LEGACY_SWITCH_SISO:
+ IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to SISO\n");
+
+ /* Set up search table to try SISO */
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+ ret = rs_switch_to_siso(mvm, lq_sta, sta,
+ search_tbl, index);
+ if (!ret) {
+ lq_sta->action_counter = 0;
+ goto out;
+ }
+
+ break;
+ case IWL_LEGACY_SWITCH_MIMO2_AB:
+ case IWL_LEGACY_SWITCH_MIMO2_AC:
+ case IWL_LEGACY_SWITCH_MIMO2_BC:
+ IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n");
+
+ /* Set up search table to try MIMO */
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+
+ if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB)
+ search_tbl->ant_type = ANT_AB;
+ else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC)
+ search_tbl->ant_type = ANT_AC;
+ else
+ search_tbl->ant_type = ANT_BC;
+
+ if (!rs_is_valid_ant(valid_tx_ant,
+ search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
+ search_tbl, index);
+ if (!ret) {
+ lq_sta->action_counter = 0;
+ goto out;
+ }
+ break;
+
+ case IWL_LEGACY_SWITCH_MIMO3_ABC:
+ IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO3\n");
+
+ /* Set up search table to try MIMO3 */
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+
+ search_tbl->ant_type = ANT_ABC;
+
+ if (!rs_is_valid_ant(valid_tx_ant,
+ search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_mimo3(mvm, lq_sta, sta,
+ search_tbl, index);
+ if (!ret) {
+ lq_sta->action_counter = 0;
+ goto out;
+ }
+ break;
+ }
+ tbl->action++;
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+ tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+
+ if (tbl->action == start_action)
+ break;
+ }
+ search_tbl->lq_type = LQ_NONE;
+ return 0;
+
+out:
+ lq_sta->search_better_tbl = 1;
+ tbl->action++;
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+ tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+ if (update_search_tbl_counter)
+ search_tbl->action = tbl->action;
+ return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from SISO
+ */
+static int rs_move_siso_to_other(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta *sta, int index)
+{
+ u8 is_green = lq_sta->is_green;
+ struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action;
+ u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ u8 tx_chains_num = num_of_ant(valid_tx_ant);
+ u8 update_search_tbl_counter = 0;
+ int ret;
+
+ start_action = tbl->action;
+ while (1) {
+ lq_sta->action_counter++;
+ switch (tbl->action) {
+ case IWL_SISO_SWITCH_ANTENNA1:
+ case IWL_SISO_SWITCH_ANTENNA2:
+ IWL_DEBUG_RATE(mvm, "LQ: SISO toggle Antenna\n");
+ if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
+ tx_chains_num <= 1) ||
+ (tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
+ tx_chains_num <= 2))
+ break;
+
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ break;
+
+ memcpy(search_tbl, tbl, sz);
+ if (rs_toggle_antenna(valid_tx_ant,
+ &search_tbl->current_rate,
+ search_tbl)) {
+ update_search_tbl_counter = 1;
+ goto out;
+ }
+ break;
+ case IWL_SISO_SWITCH_MIMO2_AB:
+ case IWL_SISO_SWITCH_MIMO2_AC:
+ case IWL_SISO_SWITCH_MIMO2_BC:
+ IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+
+ if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB)
+ search_tbl->ant_type = ANT_AB;
+ else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC)
+ search_tbl->ant_type = ANT_AC;
+ else
+ search_tbl->ant_type = ANT_BC;
+
+ if (!rs_is_valid_ant(valid_tx_ant,
+ search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
+ search_tbl, index);
+ if (!ret)
+ goto out;
+ break;
+ case IWL_SISO_SWITCH_GI:
+ if (!tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_20))
+ break;
+ if (tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_40))
+ break;
+
+ IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n");
+
+ memcpy(search_tbl, tbl, sz);
+ if (is_green) {
+ if (!tbl->is_SGI)
+ break;
+ else
+ IWL_ERR(mvm,
+ "SGI was set in GF+SISO\n");
+ }
+ search_tbl->is_SGI = !tbl->is_SGI;
+ rs_set_expected_tpt_table(lq_sta, search_tbl);
+ if (tbl->is_SGI) {
+ s32 tpt = lq_sta->last_tpt / 100;
+ if (tpt >= search_tbl->expected_tpt[index])
+ break;
+ }
+ search_tbl->current_rate =
+ rate_n_flags_from_tbl(mvm, search_tbl,
+ index, is_green);
+ update_search_tbl_counter = 1;
+ goto out;
+ case IWL_SISO_SWITCH_MIMO3_ABC:
+ IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO3\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+ search_tbl->ant_type = ANT_ABC;
+
+ if (!rs_is_valid_ant(valid_tx_ant,
+ search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_mimo3(mvm, lq_sta, sta,
+ search_tbl, index);
+ if (!ret)
+ goto out;
+ break;
+ }
+ tbl->action++;
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+ tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+
+ if (tbl->action == start_action)
+ break;
+ }
+ search_tbl->lq_type = LQ_NONE;
+ return 0;
+
+ out:
+ lq_sta->search_better_tbl = 1;
+ tbl->action++;
+ if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
+ tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+ if (update_search_tbl_counter)
+ search_tbl->action = tbl->action;
+
+ return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from MIMO2
+ */
+static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta *sta, int index)
+{
+ s8 is_green = lq_sta->is_green;
+ struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action;
+ u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ u8 tx_chains_num = num_of_ant(valid_tx_ant);
+ u8 update_search_tbl_counter = 0;
+ int ret;
+
+ start_action = tbl->action;
+ while (1) {
+ lq_sta->action_counter++;
+ switch (tbl->action) {
+ case IWL_MIMO2_SWITCH_ANTENNA1:
+ case IWL_MIMO2_SWITCH_ANTENNA2:
+ IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle Antennas\n");
+
+ if (tx_chains_num <= 2)
+ break;
+
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ break;
+
+ memcpy(search_tbl, tbl, sz);
+ if (rs_toggle_antenna(valid_tx_ant,
+ &search_tbl->current_rate,
+ search_tbl)) {
+ update_search_tbl_counter = 1;
+ goto out;
+ }
+ break;
+ case IWL_MIMO2_SWITCH_SISO_A:
+ case IWL_MIMO2_SWITCH_SISO_B:
+ case IWL_MIMO2_SWITCH_SISO_C:
+ IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n");
+
+ /* Set up new search table for SISO */
+ memcpy(search_tbl, tbl, sz);
+
+ if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
+ search_tbl->ant_type = ANT_A;
+ else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
+ search_tbl->ant_type = ANT_B;
+ else
+ search_tbl->ant_type = ANT_C;
+
+ if (!rs_is_valid_ant(valid_tx_ant,
+ search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_siso(mvm, lq_sta, sta,
+ search_tbl, index);
+ if (!ret)
+ goto out;
+
+ break;
+
+ case IWL_MIMO2_SWITCH_GI:
+ if (!tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_20))
+ break;
+ if (tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_40))
+ break;
+
+ IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n");
+
+ /* Set up new search table for MIMO2 */
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = !tbl->is_SGI;
+ rs_set_expected_tpt_table(lq_sta, search_tbl);
+ /*
+ * If active table already uses the fastest possible
+ * modulation (dual stream with short guard interval),
+ * and it's working well, there's no need to look
+ * for a better type of modulation!
+ */
+ if (tbl->is_SGI) {
+ s32 tpt = lq_sta->last_tpt / 100;
+ if (tpt >= search_tbl->expected_tpt[index])
+ break;
+ }
+ search_tbl->current_rate =
+ rate_n_flags_from_tbl(mvm, search_tbl,
+ index, is_green);
+ update_search_tbl_counter = 1;
+ goto out;
+
+ case IWL_MIMO2_SWITCH_MIMO3_ABC:
+ IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to MIMO3\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+ search_tbl->ant_type = ANT_ABC;
+
+ if (!rs_is_valid_ant(valid_tx_ant,
+ search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_mimo3(mvm, lq_sta, sta,
+ search_tbl, index);
+ if (!ret)
+ goto out;
+
+ break;
+ }
+ tbl->action++;
+ if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
+ tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
+
+ if (tbl->action == start_action)
+ break;
+ }
+ search_tbl->lq_type = LQ_NONE;
+ return 0;
+ out:
+ lq_sta->search_better_tbl = 1;
+ tbl->action++;
+ if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
+ tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
+ if (update_search_tbl_counter)
+ search_tbl->action = tbl->action;
+
+ return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from MIMO3
+ */
+static int rs_move_mimo3_to_other(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta *sta, int index)
+{
+ s8 is_green = lq_sta->is_green;
+ struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action;
+ u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ u8 tx_chains_num = num_of_ant(valid_tx_ant);
+ int ret;
+ u8 update_search_tbl_counter = 0;
+
+ start_action = tbl->action;
+ while (1) {
+ lq_sta->action_counter++;
+ switch (tbl->action) {
+ case IWL_MIMO3_SWITCH_ANTENNA1:
+ case IWL_MIMO3_SWITCH_ANTENNA2:
+ IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle Antennas\n");
+
+ if (tx_chains_num <= 3)
+ break;
+
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ break;
+
+ memcpy(search_tbl, tbl, sz);
+ if (rs_toggle_antenna(valid_tx_ant,
+ &search_tbl->current_rate,
+ search_tbl))
+ goto out;
+ break;
+ case IWL_MIMO3_SWITCH_SISO_A:
+ case IWL_MIMO3_SWITCH_SISO_B:
+ case IWL_MIMO3_SWITCH_SISO_C:
+ IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to SISO\n");
+
+ /* Set up new search table for SISO */
+ memcpy(search_tbl, tbl, sz);
+
+ if (tbl->action == IWL_MIMO3_SWITCH_SISO_A)
+ search_tbl->ant_type = ANT_A;
+ else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
+ search_tbl->ant_type = ANT_B;
+ else
+ search_tbl->ant_type = ANT_C;
+
+ if (!rs_is_valid_ant(valid_tx_ant,
+ search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_siso(mvm, lq_sta, sta,
+ search_tbl, index);
+ if (!ret)
+ goto out;
+
+ break;
+
+ case IWL_MIMO3_SWITCH_MIMO2_AB:
+ case IWL_MIMO3_SWITCH_MIMO2_AC:
+ case IWL_MIMO3_SWITCH_MIMO2_BC:
+ IWL_DEBUG_RATE(mvm, "LQ: MIMO3 switch to MIMO2\n");
+
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = 0;
+ if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB)
+ search_tbl->ant_type = ANT_AB;
+ else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC)
+ search_tbl->ant_type = ANT_AC;
+ else
+ search_tbl->ant_type = ANT_BC;
+
+ if (!rs_is_valid_ant(valid_tx_ant,
+ search_tbl->ant_type))
+ break;
+
+ ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
+ search_tbl, index);
+ if (!ret)
+ goto out;
+
+ break;
+
+ case IWL_MIMO3_SWITCH_GI:
+ if (!tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_20))
+ break;
+ if (tbl->is_ht40 && !(ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_40))
+ break;
+
+ IWL_DEBUG_RATE(mvm, "LQ: MIMO3 toggle SGI/NGI\n");
+
+ /* Set up new search table for MIMO */
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->is_SGI = !tbl->is_SGI;
+ rs_set_expected_tpt_table(lq_sta, search_tbl);
+ /*
+ * If active table already uses the fastest possible
+ * modulation (dual stream with short guard interval),
+ * and it's working well, there's no need to look
+ * for a better type of modulation!
+ */
+ if (tbl->is_SGI) {
+ s32 tpt = lq_sta->last_tpt / 100;
+ if (tpt >= search_tbl->expected_tpt[index])
+ break;
+ }
+ search_tbl->current_rate =
+ rate_n_flags_from_tbl(mvm, search_tbl,
+ index, is_green);
+ update_search_tbl_counter = 1;
+ goto out;
+ }
+ tbl->action++;
+ if (tbl->action > IWL_MIMO3_SWITCH_GI)
+ tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+
+ if (tbl->action == start_action)
+ break;
+ }
+ search_tbl->lq_type = LQ_NONE;
+ return 0;
+ out:
+ lq_sta->search_better_tbl = 1;
+ tbl->action++;
+ if (tbl->action > IWL_MIMO3_SWITCH_GI)
+ tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+ if (update_search_tbl_counter)
+ search_tbl->action = tbl->action;
+
+ return 0;
+}
+
+/*
+ * Check whether we should continue using same modulation mode, or
+ * begin search for a new mode, based on:
+ * 1) # tx successes or failures while using this mode
+ * 2) # times calling this function
+ * 3) elapsed time in this mode (not used, for now)
+ */
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
+{
+ struct iwl_scale_tbl_info *tbl;
+ int i;
+ int active_tbl;
+ int flush_interval_passed = 0;
+ struct iwl_mvm *mvm;
+
+ mvm = lq_sta->drv;
+ active_tbl = lq_sta->active_tbl;
+
+ tbl = &(lq_sta->lq_info[active_tbl]);
+
+ /* If we've been disallowing search, see if we should now allow it */
+ if (lq_sta->stay_in_tbl) {
+ /* Elapsed time using current modulation mode */
+ if (lq_sta->flush_timer)
+ flush_interval_passed =
+ time_after(jiffies,
+ (unsigned long)(lq_sta->flush_timer +
+ IWL_RATE_SCALE_FLUSH_INTVL));
+
+ /*
+ * Check if we should allow search for new modulation mode.
+ * If many frames have failed or succeeded, or we've used
+ * this same modulation for a long time, allow search, and
+ * reset history stats that keep track of whether we should
+ * allow a new search. Also (below) reset all bitmaps and
+ * stats in active history.
+ */
+ if (force_search ||
+ (lq_sta->total_failed > lq_sta->max_failure_limit) ||
+ (lq_sta->total_success > lq_sta->max_success_limit) ||
+ ((!lq_sta->search_better_tbl) &&
+ (lq_sta->flush_timer) && (flush_interval_passed))) {
+ IWL_DEBUG_RATE(mvm,
+ "LQ: stay is expired %d %d %d\n",
+ lq_sta->total_failed,
+ lq_sta->total_success,
+ flush_interval_passed);
+
+ /* Allow search for new mode */
+ lq_sta->stay_in_tbl = 0; /* only place reset */
+ lq_sta->total_failed = 0;
+ lq_sta->total_success = 0;
+ lq_sta->flush_timer = 0;
+ /*
+ * Else if we've used this modulation mode enough repetitions
+ * (regardless of elapsed time or success/failure), reset
+ * history bitmaps and rate-specific stats for all rates in
+ * active table.
+ */
+ } else {
+ lq_sta->table_count++;
+ if (lq_sta->table_count >=
+ lq_sta->table_count_limit) {
+ lq_sta->table_count = 0;
+
+ IWL_DEBUG_RATE(mvm,
+ "LQ: stay in table clear win\n");
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(
+ &(tbl->win[i]));
+ }
+ }
+
+ /* If transitioning to allow "search", reset all history
+ * bitmaps and stats in active table (this will become the new
+ * "search" table). */
+ if (!lq_sta->stay_in_tbl) {
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&(tbl->win[i]));
+ }
+ }
+}
+
+/*
+ * setup rate table in uCode
+ */
+static void rs_update_rate_tbl(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl,
+ int index, u8 is_green)
+{
+ u32 rate;
+
+ /* Update uCode's rate table. */
+ rate = rate_n_flags_from_tbl(mvm, tbl, index, is_green);
+ rs_fill_link_cmd(mvm, lq_sta, rate);
+ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false);
+}
+
+/*
+ * Do rate scaling and search for new modulation mode.
+ */
+static void rs_rate_scale_perform(struct iwl_mvm *mvm,
+ struct sk_buff *skb,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ int low = IWL_RATE_INVALID;
+ int high = IWL_RATE_INVALID;
+ int index;
+ int i;
+ struct iwl_rate_scale_data *window = NULL;
+ int current_tpt = IWL_INVALID_VALUE;
+ int low_tpt = IWL_INVALID_VALUE;
+ int high_tpt = IWL_INVALID_VALUE;
+ u32 fail_count;
+ s8 scale_action = 0;
+ u16 rate_mask;
+ u8 update_lq = 0;
+ struct iwl_scale_tbl_info *tbl, *tbl1;
+ u16 rate_scale_index_msk = 0;
+ u8 is_green = 0;
+ u8 active_tbl = 0;
+ u8 done_search = 0;
+ u16 high_low;
+ s32 sr;
+ u8 tid = IWL_MAX_TID_COUNT;
+ struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
+ struct iwl_mvm_tid_data *tid_data;
+
+ IWL_DEBUG_RATE(mvm, "rate scale calculate new rate for skb\n");
+
+ /* Send management frames and NO_ACK data using lowest rate. */
+ /* TODO: this could probably be improved.. */
+ if (!ieee80211_is_data(hdr->frame_control) ||
+ info->flags & IEEE80211_TX_CTL_NO_ACK)
+ return;
+
+ lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
+
+ tid = rs_tl_add_packet(lq_sta, hdr);
+ if ((tid != IWL_MAX_TID_COUNT) &&
+ (lq_sta->tx_agg_tid_en & (1 << tid))) {
+ tid_data = &sta_priv->tid_data[tid];
+ if (tid_data->state == IWL_AGG_OFF)
+ lq_sta->is_agg = 0;
+ else
+ lq_sta->is_agg = 1;
+ } else {
+ lq_sta->is_agg = 0;
+ }
+
+ /*
+ * Select rate-scale / modulation-mode table to work with in
+ * the rest of this function: "search" if searching for better
+ * modulation mode, or "active" if doing rate scaling within a mode.
+ */
+ if (!lq_sta->search_better_tbl)
+ active_tbl = lq_sta->active_tbl;
+ else
+ active_tbl = 1 - lq_sta->active_tbl;
+
+ tbl = &(lq_sta->lq_info[active_tbl]);
+ if (is_legacy(tbl->lq_type))
+ lq_sta->is_green = 0;
+ else
+ lq_sta->is_green = rs_use_green(sta);
+ is_green = lq_sta->is_green;
+
+ /* current tx rate */
+ index = lq_sta->last_txrate_idx;
+
+ IWL_DEBUG_RATE(mvm, "Rate scale index %d for type %d\n", index,
+ tbl->lq_type);
+
+ /* rates available for this association, and for modulation mode */
+ rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
+
+ IWL_DEBUG_RATE(mvm, "mask 0x%04X\n", rate_mask);
+
+ /* mask with station rate restriction */
+ if (is_legacy(tbl->lq_type)) {
+ if (lq_sta->band == IEEE80211_BAND_5GHZ)
+ /* supp_rates has no CCK bits in A mode */
+ rate_scale_index_msk = (u16) (rate_mask &
+ (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
+ else
+ rate_scale_index_msk = (u16) (rate_mask &
+ lq_sta->supp_rates);
+
+ } else {
+ rate_scale_index_msk = rate_mask;
+ }
+
+ if (!rate_scale_index_msk)
+ rate_scale_index_msk = rate_mask;
+
+ if (!((1 << index) & rate_scale_index_msk)) {
+ IWL_ERR(mvm, "Current Rate is not valid\n");
+ if (lq_sta->search_better_tbl) {
+ /* revert to active table if search table is not valid*/
+ tbl->lq_type = LQ_NONE;
+ lq_sta->search_better_tbl = 0;
+ tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ /* get "active" rate info */
+ index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+ rs_update_rate_tbl(mvm, lq_sta, tbl, index, is_green);
+ }
+ return;
+ }
+
+ /* Get expected throughput table and history window for current rate */
+ if (!tbl->expected_tpt) {
+ IWL_ERR(mvm, "tbl->expected_tpt is NULL\n");
+ return;
+ }
+
+ /* force user max rate if set by user */
+ if ((lq_sta->max_rate_idx != -1) &&
+ (lq_sta->max_rate_idx < index)) {
+ index = lq_sta->max_rate_idx;
+ update_lq = 1;
+ window = &(tbl->win[index]);
+ goto lq_update;
+ }
+
+ window = &(tbl->win[index]);
+
+ /*
+ * If there is not enough history to calculate actual average
+ * throughput, keep analyzing results of more tx frames, without
+ * changing rate or mode (bypass most of the rest of this function).
+ * Set up new rate table in uCode only if old rate is not supported
+ * in current association (use new rate found above).
+ */
+ fail_count = window->counter - window->success_counter;
+ if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
+ (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
+ IWL_DEBUG_RATE(mvm,
+ "LQ: still below TH. succ=%d total=%d for index %d\n",
+ window->success_counter, window->counter, index);
+
+ /* Can't calculate this yet; not enough history */
+ window->average_tpt = IWL_INVALID_VALUE;
+
+ /* Should we stay with this modulation mode,
+ * or search for a new one? */
+ rs_stay_in_table(lq_sta, false);
+
+ goto out;
+ }
+ /* Else we have enough samples; calculate estimate of
+ * actual average throughput */
+ if (window->average_tpt != ((window->success_ratio *
+ tbl->expected_tpt[index] + 64) / 128)) {
+ IWL_ERR(mvm,
+ "expected_tpt should have been calculated by now\n");
+ window->average_tpt = ((window->success_ratio *
+ tbl->expected_tpt[index] + 64) / 128);
+ }
+
+ /* If we are searching for better modulation mode, check success. */
+ if (lq_sta->search_better_tbl) {
+ /* If good success, continue using the "search" mode;
+ * no need to send new link quality command, since we're
+ * continuing to use the setup that we've been trying. */
+ if (window->average_tpt > lq_sta->last_tpt) {
+ IWL_DEBUG_RATE(mvm,
+ "LQ: SWITCHING TO NEW TABLE suc=%d cur-tpt=%d old-tpt=%d\n",
+ window->success_ratio,
+ window->average_tpt,
+ lq_sta->last_tpt);
+
+ if (!is_legacy(tbl->lq_type))
+ lq_sta->enable_counter = 1;
+
+ /* Swap tables; "search" becomes "active" */
+ lq_sta->active_tbl = active_tbl;
+ current_tpt = window->average_tpt;
+ /* Else poor success; go back to mode in "active" table */
+ } else {
+ IWL_DEBUG_RATE(mvm,
+ "LQ: GOING BACK TO THE OLD TABLE suc=%d cur-tpt=%d old-tpt=%d\n",
+ window->success_ratio,
+ window->average_tpt,
+ lq_sta->last_tpt);
+
+ /* Nullify "search" table */
+ tbl->lq_type = LQ_NONE;
+
+ /* Revert to "active" table */
+ active_tbl = lq_sta->active_tbl;
+ tbl = &(lq_sta->lq_info[active_tbl]);
+
+ /* Revert to "active" rate and throughput info */
+ index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+ current_tpt = lq_sta->last_tpt;
+
+ /* Need to set up a new rate table in uCode */
+ update_lq = 1;
+ }
+
+ /* Either way, we've made a decision; modulation mode
+ * search is done, allow rate adjustment next time. */
+ lq_sta->search_better_tbl = 0;
+ done_search = 1; /* Don't switch modes below! */
+ goto lq_update;
+ }
+
+ /* (Else) not in search of better modulation mode, try for better
+ * starting rate, while staying in this mode. */
+ high_low = rs_get_adjacent_rate(mvm, index, rate_scale_index_msk,
+ tbl->lq_type);
+ low = high_low & 0xff;
+ high = (high_low >> 8) & 0xff;
+
+ /* If user set max rate, dont allow higher than user constrain */
+ if ((lq_sta->max_rate_idx != -1) &&
+ (lq_sta->max_rate_idx < high))
+ high = IWL_RATE_INVALID;
+
+ sr = window->success_ratio;
+
+ /* Collect measured throughputs for current and adjacent rates */
+ current_tpt = window->average_tpt;
+ if (low != IWL_RATE_INVALID)
+ low_tpt = tbl->win[low].average_tpt;
+ if (high != IWL_RATE_INVALID)
+ high_tpt = tbl->win[high].average_tpt;
+
+ scale_action = 0;
+
+ /* Too many failures, decrease rate */
+ if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
+ IWL_DEBUG_RATE(mvm,
+ "decrease rate because of low success_ratio\n");
+ scale_action = -1;
+ /* No throughput measured yet for adjacent rates; try increase. */
+ } else if ((low_tpt == IWL_INVALID_VALUE) &&
+ (high_tpt == IWL_INVALID_VALUE)) {
+ if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
+ scale_action = 1;
+ else if (low != IWL_RATE_INVALID)
+ scale_action = 0;
+ }
+
+ /* Both adjacent throughputs are measured, but neither one has better
+ * throughput; we're using the best rate, don't change it! */
+ else if ((low_tpt != IWL_INVALID_VALUE) &&
+ (high_tpt != IWL_INVALID_VALUE) &&
+ (low_tpt < current_tpt) &&
+ (high_tpt < current_tpt))
+ scale_action = 0;
+
+ /* At least one adjacent rate's throughput is measured,
+ * and may have better performance. */
+ else {
+ /* Higher adjacent rate's throughput is measured */
+ if (high_tpt != IWL_INVALID_VALUE) {
+ /* Higher rate has better throughput */
+ if (high_tpt > current_tpt &&
+ sr >= IWL_RATE_INCREASE_TH) {
+ scale_action = 1;
+ } else {
+ scale_action = 0;
+ }
+
+ /* Lower adjacent rate's throughput is measured */
+ } else if (low_tpt != IWL_INVALID_VALUE) {
+ /* Lower rate has better throughput */
+ if (low_tpt > current_tpt) {
+ IWL_DEBUG_RATE(mvm,
+ "decrease rate because of low tpt\n");
+ scale_action = -1;
+ } else if (sr >= IWL_RATE_INCREASE_TH) {
+ scale_action = 1;
+ }
+ }
+ }
+
+ /* Sanity check; asked for decrease, but success rate or throughput
+ * has been good at old rate. Don't change it. */
+ if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
+ ((sr > IWL_RATE_HIGH_TH) ||
+ (current_tpt > (100 * tbl->expected_tpt[low]))))
+ scale_action = 0;
+
+ switch (scale_action) {
+ case -1:
+ /* Decrease starting rate, update uCode's rate table */
+ if (low != IWL_RATE_INVALID) {
+ update_lq = 1;
+ index = low;
+ }
+
+ break;
+ case 1:
+ /* Increase starting rate, update uCode's rate table */
+ if (high != IWL_RATE_INVALID) {
+ update_lq = 1;
+ index = high;
+ }
+
+ break;
+ case 0:
+ /* No change */
+ default:
+ break;
+ }
+
+ IWL_DEBUG_RATE(mvm,
+ "choose rate scale index %d action %d low %d high %d type %d\n",
+ index, scale_action, low, high, tbl->lq_type);
+
+lq_update:
+ /* Replace uCode's rate table for the destination station. */
+ if (update_lq)
+ rs_update_rate_tbl(mvm, lq_sta, tbl, index, is_green);
+
+ rs_stay_in_table(lq_sta, false);
+
+ /*
+ * Search for new modulation mode if we're:
+ * 1) Not changing rates right now
+ * 2) Not just finishing up a search
+ * 3) Allowing a new search
+ */
+ if (!update_lq && !done_search &&
+ !lq_sta->stay_in_tbl && window->counter) {
+ /* Save current throughput to compare with "search" throughput*/
+ lq_sta->last_tpt = current_tpt;
+
+ /* Select a new "search" modulation mode to try.
+ * If one is found, set up the new "search" table. */
+ if (is_legacy(tbl->lq_type))
+ rs_move_legacy_other(mvm, lq_sta, sta, index);
+ else if (is_siso(tbl->lq_type))
+ rs_move_siso_to_other(mvm, lq_sta, sta, index);
+ else if (is_mimo2(tbl->lq_type))
+ rs_move_mimo2_to_other(mvm, lq_sta, sta, index);
+ else
+ rs_move_mimo3_to_other(mvm, lq_sta, sta, index);
+
+ /* If new "search" mode was selected, set up in uCode table */
+ if (lq_sta->search_better_tbl) {
+ /* Access the "search" table, clear its history. */
+ tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&(tbl->win[i]));
+
+ /* Use new "search" start rate */
+ index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+
+ IWL_DEBUG_RATE(mvm,
+ "Switch current mcs: %X index: %d\n",
+ tbl->current_rate, index);
+ rs_fill_link_cmd(mvm, lq_sta, tbl->current_rate);
+ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_ASYNC, false);
+ } else {
+ done_search = 1;
+ }
+ }
+
+ if (done_search && !lq_sta->stay_in_tbl) {
+ /* If the "active" (non-search) mode was legacy,
+ * and we've tried switching antennas,
+ * but we haven't been able to try HT modes (not available),
+ * stay with best antenna legacy modulation for a while
+ * before next round of mode comparisons. */
+ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ if (is_legacy(tbl1->lq_type) && !sta->ht_cap.ht_supported &&
+ lq_sta->action_counter > tbl1->max_search) {
+ IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n");
+ rs_set_stay_in_table(mvm, 1, lq_sta);
+ }
+
+ /* If we're in an HT mode, and all 3 mode switch actions
+ * have been tried and compared, stay in this best modulation
+ * mode for a while before next round of mode comparisons. */
+ if (lq_sta->enable_counter &&
+ (lq_sta->action_counter >= tbl1->max_search)) {
+ if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
+ (lq_sta->tx_agg_tid_en & (1 << tid)) &&
+ (tid != IWL_MAX_TID_COUNT)) {
+ tid_data = &sta_priv->tid_data[tid];
+ if (tid_data->state == IWL_AGG_OFF) {
+ IWL_DEBUG_RATE(mvm,
+ "try to aggregate tid %d\n",
+ tid);
+ rs_tl_turn_on_agg(mvm, tid,
+ lq_sta, sta);
+ }
+ }
+ rs_set_stay_in_table(mvm, 0, lq_sta);
+ }
+ }
+
+out:
+ tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, index, is_green);
+ lq_sta->last_txrate_idx = index;
+}
+
+/**
+ * rs_initialize_lq - Initialize a station's hardware rate table
+ *
+ * The uCode's station table contains a table of fallback rates
+ * for automatic fallback during transmission.
+ *
+ * NOTE: This sets up a default set of values. These will be replaced later
+ * if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
+ * rc80211_simple.
+ *
+ * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
+ * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
+ * which requires station table entry to exist).
+ */
+static void rs_initialize_lq(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta,
+ enum ieee80211_band band)
+{
+ struct iwl_scale_tbl_info *tbl;
+ int rate_idx;
+ int i;
+ u32 rate;
+ u8 use_green = rs_use_green(sta);
+ u8 active_tbl = 0;
+ u8 valid_tx_ant;
+
+ if (!sta || !lq_sta)
+ return;
+
+ i = lq_sta->last_txrate_idx;
+
+ valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+
+ if (!lq_sta->search_better_tbl)
+ active_tbl = lq_sta->active_tbl;
+ else
+ active_tbl = 1 - lq_sta->active_tbl;
+
+ tbl = &(lq_sta->lq_info[active_tbl]);
+
+ if ((i < 0) || (i >= IWL_RATE_COUNT))
+ i = 0;
+
+ rate = iwl_rates[i].plcp;
+ tbl->ant_type = first_antenna(valid_tx_ant);
+ rate |= tbl->ant_type << RATE_MCS_ANT_POS;
+
+ if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
+ rate |= RATE_MCS_CCK_MSK;
+
+ rs_get_tbl_info_from_mcs(rate, band, tbl, &rate_idx);
+ if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
+ rs_toggle_antenna(valid_tx_ant, &rate, tbl);
+
+ rate = rate_n_flags_from_tbl(mvm, tbl, rate_idx, use_green);
+ tbl->current_rate = rate;
+ rs_set_expected_tpt_table(lq_sta, tbl);
+ rs_fill_link_cmd(NULL, lq_sta, rate);
+ /* TODO restore station should remember the lq cmd */
+ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, CMD_SYNC, true);
+}
+
+static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
+ struct ieee80211_tx_rate_control *txrc)
+{
+ struct sk_buff *skb = txrc->skb;
+ struct ieee80211_supported_band *sband = txrc->sband;
+ struct iwl_op_mode *op_mode __maybe_unused =
+ (struct iwl_op_mode *)mvm_r;
+ struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct iwl_lq_sta *lq_sta = mvm_sta;
+ int rate_idx;
+
+ IWL_DEBUG_RATE_LIMIT(mvm, "rate scale calculate new rate for skb\n");
+
+ /* Get max rate if user set max rate */
+ if (lq_sta) {
+ lq_sta->max_rate_idx = txrc->max_rate_idx;
+ if ((sband->band == IEEE80211_BAND_5GHZ) &&
+ (lq_sta->max_rate_idx != -1))
+ lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
+ if ((lq_sta->max_rate_idx < 0) ||
+ (lq_sta->max_rate_idx >= IWL_RATE_COUNT))
+ lq_sta->max_rate_idx = -1;
+ }
+
+ /* Treat uninitialized rate scaling data same as non-existing. */
+ if (lq_sta && !lq_sta->drv) {
+ IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n");
+ mvm_sta = NULL;
+ }
+
+ /* Send management frames and NO_ACK data using lowest rate. */
+ if (rate_control_send_low(sta, mvm_sta, txrc))
+ return;
+
+ rate_idx = lq_sta->last_txrate_idx;
+
+ if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
+ rate_idx -= IWL_FIRST_OFDM_RATE;
+ /* 6M and 9M shared same MCS index */
+ rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0;
+ if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
+ IWL_RATE_MIMO3_6M_PLCP)
+ rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM);
+ else if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
+ IWL_RATE_MIMO2_6M_PLCP)
+ rate_idx = rate_idx + MCS_INDEX_PER_STREAM;
+ info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
+ if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK)
+ info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
+ if (lq_sta->last_rate_n_flags & RATE_MCS_CHAN_WIDTH_40) /* TODO */
+ info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ if (lq_sta->last_rate_n_flags & RATE_HT_MCS_GF_MSK)
+ info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
+ } else {
+ /* Check for invalid rates */
+ if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) ||
+ ((sband->band == IEEE80211_BAND_5GHZ) &&
+ (rate_idx < IWL_FIRST_OFDM_RATE)))
+ rate_idx = rate_lowest_index(sband, sta);
+ /* On valid 5 GHz rate, adjust index */
+ else if (sband->band == IEEE80211_BAND_5GHZ)
+ rate_idx -= IWL_FIRST_OFDM_RATE;
+ info->control.rates[0].flags = 0;
+ }
+ info->control.rates[0].idx = rate_idx;
+}
+
+static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
+ gfp_t gfp)
+{
+ struct iwl_mvm_sta *sta_priv = (struct iwl_mvm_sta *)sta->drv_priv;
+ struct iwl_op_mode *op_mode __maybe_unused =
+ (struct iwl_op_mode *)mvm_rate;
+ struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
+
+ IWL_DEBUG_RATE(mvm, "create station rate scale window\n");
+
+ return &sta_priv->lq_sta;
+}
+
+/*
+ * Called after adding a new station to initialize rate scaling
+ */
+void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ enum ieee80211_band band)
+{
+ int i, j;
+ struct ieee80211_hw *hw = mvm->hw;
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+ struct iwl_mvm_sta *sta_priv;
+ struct iwl_lq_sta *lq_sta;
+ struct ieee80211_supported_band *sband;
+ unsigned long supp; /* must be unsigned long for for_each_set_bit */
+
+ sta_priv = (struct iwl_mvm_sta *)sta->drv_priv;
+ lq_sta = &sta_priv->lq_sta;
+ sband = hw->wiphy->bands[band];
+
+ lq_sta->lq.sta_id = sta_priv->sta_id;
+
+ for (j = 0; j < LQ_SIZE; j++)
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
+
+ lq_sta->flush_timer = 0;
+ lq_sta->supp_rates = sta->supp_rates[sband->band];
+ for (j = 0; j < LQ_SIZE; j++)
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
+
+ IWL_DEBUG_RATE(mvm,
+ "LQ: *** rate scale station global init for station %d ***\n",
+ sta_priv->sta_id);
+ /* TODO: what is a good starting rate for STA? About middle? Maybe not
+ * the lowest or the highest rate.. Could consider using RSSI from
+ * previous packets? Need to have IEEE 802.1X auth succeed immediately
+ * after assoc.. */
+
+ lq_sta->max_rate_idx = -1;
+ lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
+ lq_sta->is_green = rs_use_green(sta);
+ lq_sta->band = sband->band;
+ /*
+ * active legacy rates as per supported rates bitmap
+ */
+ supp = sta->supp_rates[sband->band];
+ lq_sta->active_legacy_rate = 0;
+ for_each_set_bit(i, &supp, BITS_PER_LONG)
+ lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value);
+
+ /*
+ * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
+ * supp_rates[] does not; shift to convert format, force 9 MBits off.
+ */
+ lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
+ lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
+ lq_sta->active_siso_rate &= ~((u16)0x2);
+ lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
+
+ /* Same here */
+ lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
+ lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
+ lq_sta->active_mimo2_rate &= ~((u16)0x2);
+ lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
+
+ lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1;
+ lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1;
+ lq_sta->active_mimo3_rate &= ~((u16)0x2);
+ lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
+
+ IWL_DEBUG_RATE(mvm,
+ "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n",
+ lq_sta->active_siso_rate,
+ lq_sta->active_mimo2_rate,
+ lq_sta->active_mimo3_rate);
+
+ /* These values will be overridden later */
+ lq_sta->lq.single_stream_ant_msk =
+ first_antenna(mvm->nvm_data->valid_tx_ant);
+ lq_sta->lq.dual_stream_ant_msk =
+ mvm->nvm_data->valid_tx_ant &
+ ~first_antenna(mvm->nvm_data->valid_tx_ant);
+ if (!lq_sta->lq.dual_stream_ant_msk) {
+ lq_sta->lq.dual_stream_ant_msk = ANT_AB;
+ } else if (num_of_ant(mvm->nvm_data->valid_tx_ant) == 2) {
+ lq_sta->lq.dual_stream_ant_msk =
+ mvm->nvm_data->valid_tx_ant;
+ }
+
+ /* as default allow aggregation for all tids */
+ lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
+ lq_sta->drv = mvm;
+
+ /* Set last_txrate_idx to lowest rate */
+ lq_sta->last_txrate_idx = rate_lowest_index(sband, sta);
+ if (sband->band == IEEE80211_BAND_5GHZ)
+ lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+ lq_sta->is_agg = 0;
+#ifdef CONFIG_MAC80211_DEBUGFS
+ lq_sta->dbg_fixed_rate = 0;
+#endif
+
+ rs_initialize_lq(mvm, sta, lq_sta, band);
+}
+
+static void rs_fill_link_cmd(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta, u32 new_rate)
+{
+ struct iwl_scale_tbl_info tbl_type;
+ int index = 0;
+ int rate_idx;
+ int repeat_rate = 0;
+ u8 ant_toggle_cnt = 0;
+ u8 use_ht_possible = 1;
+ u8 valid_tx_ant = 0;
+ struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
+
+ /* Override starting rate (index 0) if needed for debug purposes */
+ rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+ /* Interpret new_rate (rate_n_flags) */
+ rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
+ &tbl_type, &rate_idx);
+
+ /* How many times should we repeat the initial rate? */
+ if (is_legacy(tbl_type.lq_type)) {
+ ant_toggle_cnt = 1;
+ repeat_rate = IWL_NUMBER_TRY;
+ } else {
+ repeat_rate = min(IWL_HT_NUMBER_TRY,
+ LINK_QUAL_AGG_DISABLE_START_DEF - 1);
+ }
+
+ lq_cmd->mimo_delim = is_mimo(tbl_type.lq_type) ? 1 : 0;
+
+ /* Fill 1st table entry (index 0) */
+ lq_cmd->rs_table[index] = cpu_to_le32(new_rate);
+
+ if (num_of_ant(tbl_type.ant_type) == 1)
+ lq_cmd->single_stream_ant_msk = tbl_type.ant_type;
+ else if (num_of_ant(tbl_type.ant_type) == 2)
+ lq_cmd->dual_stream_ant_msk = tbl_type.ant_type;
+ /* otherwise we don't modify the existing value */
+
+ index++;
+ repeat_rate--;
+ if (mvm)
+ valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+
+ /* Fill rest of rate table */
+ while (index < LINK_QUAL_MAX_RETRY_NUM) {
+ /* Repeat initial/next rate.
+ * For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
+ * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
+ while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
+ if (is_legacy(tbl_type.lq_type)) {
+ if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
+ ant_toggle_cnt++;
+ else if (mvm &&
+ rs_toggle_antenna(valid_tx_ant,
+ &new_rate, &tbl_type))
+ ant_toggle_cnt = 1;
+ }
+
+ /* Override next rate if needed for debug purposes */
+ rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+ /* Fill next table entry */
+ lq_cmd->rs_table[index] =
+ cpu_to_le32(new_rate);
+ repeat_rate--;
+ index++;
+ }
+
+ rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
+ &rate_idx);
+
+
+ /* Indicate to uCode which entries might be MIMO.
+ * If initial rate was MIMO, this will finally end up
+ * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
+ if (is_mimo(tbl_type.lq_type))
+ lq_cmd->mimo_delim = index;
+
+ /* Get next rate */
+ new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
+ use_ht_possible);
+
+ /* How many times should we repeat the next rate? */
+ if (is_legacy(tbl_type.lq_type)) {
+ if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
+ ant_toggle_cnt++;
+ else if (mvm &&
+ rs_toggle_antenna(valid_tx_ant,
+ &new_rate, &tbl_type))
+ ant_toggle_cnt = 1;
+
+ repeat_rate = IWL_NUMBER_TRY;
+ } else {
+ repeat_rate = IWL_HT_NUMBER_TRY;
+ }
+
+ /* Don't allow HT rates after next pass.
+ * rs_get_lower_rate() will change type to LQ_A or LQ_G. */
+ use_ht_possible = 0;
+
+ /* Override next rate if needed for debug purposes */
+ rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+ /* Fill next table entry */
+ lq_cmd->rs_table[index] = cpu_to_le32(new_rate);
+
+ index++;
+ repeat_rate--;
+ }
+
+ lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+ lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+
+ lq_cmd->agg_time_limit =
+ cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+}
+
+static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+{
+ return hw->priv;
+}
+/* rate scale requires free function to be implemented */
+static void rs_free(void *mvm_rate)
+{
+ return;
+}
+
+static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta,
+ void *mvm_sta)
+{
+ struct iwl_op_mode *op_mode __maybe_unused = mvm_r;
+ struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
+
+ IWL_DEBUG_RATE(mvm, "enter\n");
+ IWL_DEBUG_RATE(mvm, "leave\n");
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+ u32 *rate_n_flags, int index)
+{
+ struct iwl_mvm *mvm;
+ u8 valid_tx_ant;
+ u8 ant_sel_tx;
+
+ mvm = lq_sta->drv;
+ valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ if (lq_sta->dbg_fixed_rate) {
+ ant_sel_tx =
+ ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
+ >> RATE_MCS_ANT_POS);
+ if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
+ *rate_n_flags = lq_sta->dbg_fixed_rate;
+ IWL_DEBUG_RATE(mvm, "Fixed rate ON\n");
+ } else {
+ lq_sta->dbg_fixed_rate = 0;
+ IWL_ERR(mvm,
+ "Invalid antenna selection 0x%X, Valid is 0x%X\n",
+ ant_sel_tx, valid_tx_ant);
+ IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n");
+ }
+ } else {
+ IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n");
+ }
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct iwl_lq_sta *lq_sta = file->private_data;
+ struct iwl_mvm *mvm;
+ char buf[64];
+ size_t buf_size;
+ u32 parsed_rate;
+
+
+ mvm = lq_sta->drv;
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ if (sscanf(buf, "%x", &parsed_rate) == 1)
+ lq_sta->dbg_fixed_rate = parsed_rate;
+ else
+ lq_sta->dbg_fixed_rate = 0;
+
+ rs_program_fix_rate(mvm, lq_sta);
+
+ return count;
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char *buff;
+ int desc = 0;
+ int i = 0;
+ int index = 0;
+ ssize_t ret;
+
+ struct iwl_lq_sta *lq_sta = file->private_data;
+ struct iwl_mvm *mvm;
+ struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+
+ mvm = lq_sta->drv;
+ buff = kmalloc(1024, GFP_KERNEL);
+ if (!buff)
+ return -ENOMEM;
+
+ desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
+ desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
+ 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);
+ desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
+ (mvm->nvm_data->valid_tx_ant & ANT_A) ? "ANT_A," : "",
+ (mvm->nvm_data->valid_tx_ant & ANT_B) ? "ANT_B," : "",
+ (mvm->nvm_data->valid_tx_ant & ANT_C) ? "ANT_C" : "");
+ desc += sprintf(buff+desc, "lq type %s\n",
+ (is_legacy(tbl->lq_type)) ? "legacy" : "HT");
+ if (is_Ht(tbl->lq_type)) {
+ desc += sprintf(buff+desc, " %s",
+ (is_siso(tbl->lq_type)) ? "SISO" :
+ ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
+ desc += sprintf(buff+desc, " %s",
+ (tbl->is_ht40) ? "40MHz" : "20MHz");
+ desc += sprintf(buff+desc, " %s %s %s\n",
+ (tbl->is_SGI) ? "SGI" : "",
+ (lq_sta->is_green) ? "GF enabled" : "",
+ (lq_sta->is_agg) ? "AGG on" : "");
+ }
+ desc += sprintf(buff+desc, "last tx rate=0x%X\n",
+ lq_sta->last_rate_n_flags);
+ desc += sprintf(buff+desc,
+ "general: flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
+ lq_sta->lq.flags,
+ lq_sta->lq.mimo_delim,
+ lq_sta->lq.single_stream_ant_msk,
+ lq_sta->lq.dual_stream_ant_msk);
+
+ desc += sprintf(buff+desc,
+ "agg: time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
+ le16_to_cpu(lq_sta->lq.agg_time_limit),
+ lq_sta->lq.agg_disable_start_th,
+ lq_sta->lq.agg_frame_cnt_limit);
+
+ desc += sprintf(buff+desc,
+ "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
+ lq_sta->lq.initial_rate_index[0],
+ lq_sta->lq.initial_rate_index[1],
+ lq_sta->lq.initial_rate_index[2],
+ lq_sta->lq.initial_rate_index[3]);
+
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+ index = iwl_hwrate_to_plcp_idx(
+ le32_to_cpu(lq_sta->lq.rs_table[i]));
+ if (is_legacy(tbl->lq_type)) {
+ desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n",
+ i, le32_to_cpu(lq_sta->lq.rs_table[i]),
+ iwl_rate_mcs[index].mbps);
+ } else {
+ desc += sprintf(buff+desc,
+ " rate[%d] 0x%X %smbps (%s)\n",
+ i, le32_to_cpu(lq_sta->lq.rs_table[i]),
+ iwl_rate_mcs[index].mbps,
+ iwl_rate_mcs[index].mcs);
+ }
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+ kfree(buff);
+ return ret;
+}
+
+static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
+ .write = rs_sta_dbgfs_scale_table_write,
+ .read = rs_sta_dbgfs_scale_table_read,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char *buff;
+ int desc = 0;
+ int i, j;
+ ssize_t ret;
+
+ struct iwl_lq_sta *lq_sta = file->private_data;
+
+ buff = kmalloc(1024, GFP_KERNEL);
+ if (!buff)
+ return -ENOMEM;
+
+ for (i = 0; i < LQ_SIZE; i++) {
+ desc += sprintf(buff+desc,
+ "%s type=%d SGI=%d HT40=%d DUP=0 GF=%d\n"
+ "rate=0x%X\n",
+ lq_sta->active_tbl == i ? "*" : "x",
+ lq_sta->lq_info[i].lq_type,
+ lq_sta->lq_info[i].is_SGI,
+ lq_sta->lq_info[i].is_ht40,
+ lq_sta->is_green,
+ lq_sta->lq_info[i].current_rate);
+ for (j = 0; j < IWL_RATE_COUNT; j++) {
+ desc += sprintf(buff+desc,
+ "counter=%d success=%d %%=%d\n",
+ lq_sta->lq_info[i].win[j].counter,
+ lq_sta->lq_info[i].win[j].success_counter,
+ lq_sta->lq_info[i].win[j].success_ratio);
+ }
+ }
+ ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+ kfree(buff);
+ return ret;
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+ .read = rs_sta_dbgfs_stats_table_read,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
+static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct iwl_lq_sta *lq_sta = file->private_data;
+ struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+ char buff[120];
+ int desc = 0;
+
+ if (is_Ht(tbl->lq_type))
+ desc += sprintf(buff+desc,
+ "Bit Rate= %d Mb/s\n",
+ tbl->expected_tpt[lq_sta->last_txrate_idx]);
+ else
+ desc += sprintf(buff+desc,
+ "Bit Rate= %d Mb/s\n",
+ iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
+ .read = rs_sta_dbgfs_rate_scale_data_read,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
+static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
+{
+ struct iwl_lq_sta *lq_sta = mvm_sta;
+ lq_sta->rs_sta_dbgfs_scale_table_file =
+ debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
+ lq_sta, &rs_sta_dbgfs_scale_table_ops);
+ lq_sta->rs_sta_dbgfs_stats_table_file =
+ debugfs_create_file("rate_stats_table", S_IRUSR, dir,
+ lq_sta, &rs_sta_dbgfs_stats_table_ops);
+ lq_sta->rs_sta_dbgfs_rate_scale_data_file =
+ debugfs_create_file("rate_scale_data", S_IRUSR, dir,
+ lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
+ lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
+ debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
+ &lq_sta->tx_agg_tid_en);
+}
+
+static void rs_remove_debugfs(void *mvm, void *mvm_sta)
+{
+ struct iwl_lq_sta *lq_sta = mvm_sta;
+ debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
+ debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
+ debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
+ debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
+}
+#endif
+
+/*
+ * Initialization of rate scaling information is done by driver after
+ * the station is added. Since mac80211 calls this function before a
+ * station is added we ignore it.
+ */
+static void rs_rate_init_stub(void *mvm_r,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *mvm_sta)
+{
+}
+static struct rate_control_ops rs_mvm_ops = {
+ .module = NULL,
+ .name = RS_NAME,
+ .tx_status = rs_tx_status,
+ .get_rate = rs_get_rate,
+ .rate_init = rs_rate_init_stub,
+ .alloc = rs_alloc,
+ .free = rs_free,
+ .alloc_sta = rs_alloc_sta,
+ .free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+ .add_sta_debugfs = rs_add_debugfs,
+ .remove_sta_debugfs = rs_remove_debugfs,
+#endif
+};
+
+int iwl_mvm_rate_control_register(void)
+{
+ return ieee80211_rate_control_register(&rs_mvm_ops);
+}
+
+void iwl_mvm_rate_control_unregister(void)
+{
+ ieee80211_rate_control_unregister(&rs_mvm_ops);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
new file mode 100644
index 000000000000..219c6857cc0f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -0,0 +1,393 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2013 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
+ *
+ *****************************************************************************/
+
+#ifndef __rs_h__
+#define __rs_h__
+
+#include <net/mac80211.h>
+
+#include "iwl-config.h"
+
+#include "fw-api.h"
+#include "iwl-trans.h"
+
+struct iwl_rs_rate_info {
+ u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
+ u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
+ u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
+ u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_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 */
+};
+
+#define IWL_RATE_60M_PLCP 3
+
+enum {
+ IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
+ IWL_RATE_INVALID = IWL_RATE_COUNT,
+};
+
+#define LINK_QUAL_MAX_RETRY_NUM 16
+
+enum {
+ IWL_RATE_6M_INDEX_TABLE = 0,
+ IWL_RATE_9M_INDEX_TABLE,
+ IWL_RATE_12M_INDEX_TABLE,
+ IWL_RATE_18M_INDEX_TABLE,
+ IWL_RATE_24M_INDEX_TABLE,
+ IWL_RATE_36M_INDEX_TABLE,
+ IWL_RATE_48M_INDEX_TABLE,
+ IWL_RATE_54M_INDEX_TABLE,
+ IWL_RATE_1M_INDEX_TABLE,
+ IWL_RATE_2M_INDEX_TABLE,
+ IWL_RATE_5M_INDEX_TABLE,
+ IWL_RATE_11M_INDEX_TABLE,
+ IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX - 1,
+};
+
+/* #define vs. enum to keep from defaulting to 'large integer' */
+#define IWL_RATE_6M_MASK (1 << IWL_RATE_6M_INDEX)
+#define IWL_RATE_9M_MASK (1 << IWL_RATE_9M_INDEX)
+#define IWL_RATE_12M_MASK (1 << IWL_RATE_12M_INDEX)
+#define IWL_RATE_18M_MASK (1 << IWL_RATE_18M_INDEX)
+#define IWL_RATE_24M_MASK (1 << IWL_RATE_24M_INDEX)
+#define IWL_RATE_36M_MASK (1 << IWL_RATE_36M_INDEX)
+#define IWL_RATE_48M_MASK (1 << IWL_RATE_48M_INDEX)
+#define IWL_RATE_54M_MASK (1 << IWL_RATE_54M_INDEX)
+#define IWL_RATE_60M_MASK (1 << IWL_RATE_60M_INDEX)
+#define IWL_RATE_1M_MASK (1 << IWL_RATE_1M_INDEX)
+#define IWL_RATE_2M_MASK (1 << IWL_RATE_2M_INDEX)
+#define IWL_RATE_5M_MASK (1 << IWL_RATE_5M_INDEX)
+#define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX)
+
+
+/* uCode API values for OFDM high-throughput (HT) bit rates */
+enum {
+ IWL_RATE_SISO_6M_PLCP = 0,
+ IWL_RATE_SISO_12M_PLCP = 1,
+ IWL_RATE_SISO_18M_PLCP = 2,
+ IWL_RATE_SISO_24M_PLCP = 3,
+ IWL_RATE_SISO_36M_PLCP = 4,
+ IWL_RATE_SISO_48M_PLCP = 5,
+ IWL_RATE_SISO_54M_PLCP = 6,
+ IWL_RATE_SISO_60M_PLCP = 7,
+ IWL_RATE_MIMO2_6M_PLCP = 0x8,
+ IWL_RATE_MIMO2_12M_PLCP = 0x9,
+ IWL_RATE_MIMO2_18M_PLCP = 0xa,
+ IWL_RATE_MIMO2_24M_PLCP = 0xb,
+ IWL_RATE_MIMO2_36M_PLCP = 0xc,
+ IWL_RATE_MIMO2_48M_PLCP = 0xd,
+ IWL_RATE_MIMO2_54M_PLCP = 0xe,
+ IWL_RATE_MIMO2_60M_PLCP = 0xf,
+ IWL_RATE_MIMO3_6M_PLCP = 0x10,
+ IWL_RATE_MIMO3_12M_PLCP = 0x11,
+ IWL_RATE_MIMO3_18M_PLCP = 0x12,
+ IWL_RATE_MIMO3_24M_PLCP = 0x13,
+ IWL_RATE_MIMO3_36M_PLCP = 0x14,
+ IWL_RATE_MIMO3_48M_PLCP = 0x15,
+ IWL_RATE_MIMO3_54M_PLCP = 0x16,
+ IWL_RATE_MIMO3_60M_PLCP = 0x17,
+ IWL_RATE_SISO_INVM_PLCP,
+ IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+ IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+};
+
+/* MAC header values for bit rates */
+enum {
+ IWL_RATE_6M_IEEE = 12,
+ IWL_RATE_9M_IEEE = 18,
+ IWL_RATE_12M_IEEE = 24,
+ IWL_RATE_18M_IEEE = 36,
+ IWL_RATE_24M_IEEE = 48,
+ IWL_RATE_36M_IEEE = 72,
+ IWL_RATE_48M_IEEE = 96,
+ IWL_RATE_54M_IEEE = 108,
+ IWL_RATE_60M_IEEE = 120,
+ IWL_RATE_1M_IEEE = 2,
+ IWL_RATE_2M_IEEE = 4,
+ IWL_RATE_5M_IEEE = 11,
+ IWL_RATE_11M_IEEE = 22,
+};
+
+#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
+
+#define IWL_INVALID_VALUE -1
+
+#define IWL_MIN_RSSI_VAL -100
+#define IWL_MAX_RSSI_VAL 0
+
+/* These values specify how many Tx frame attempts before
+ * searching for a new modulation mode */
+#define IWL_LEGACY_FAILURE_LIMIT 160
+#define IWL_LEGACY_SUCCESS_LIMIT 480
+#define IWL_LEGACY_TABLE_COUNT 160
+
+#define IWL_NONE_LEGACY_FAILURE_LIMIT 400
+#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500
+#define IWL_NONE_LEGACY_TABLE_COUNT 1500
+
+/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
+#define IWL_RS_GOOD_RATIO 12800 /* 100% */
+#define IWL_RATE_SCALE_SWITCH 10880 /* 85% */
+#define IWL_RATE_HIGH_TH 10880 /* 85% */
+#define IWL_RATE_INCREASE_TH 6400 /* 50% */
+#define IWL_RATE_DECREASE_TH 1920 /* 15% */
+
+/* possible actions when in legacy mode */
+#define IWL_LEGACY_SWITCH_ANTENNA1 0
+#define IWL_LEGACY_SWITCH_ANTENNA2 1
+#define IWL_LEGACY_SWITCH_SISO 2
+#define IWL_LEGACY_SWITCH_MIMO2_AB 3
+#define IWL_LEGACY_SWITCH_MIMO2_AC 4
+#define IWL_LEGACY_SWITCH_MIMO2_BC 5
+#define IWL_LEGACY_SWITCH_MIMO3_ABC 6
+
+/* possible actions when in siso mode */
+#define IWL_SISO_SWITCH_ANTENNA1 0
+#define IWL_SISO_SWITCH_ANTENNA2 1
+#define IWL_SISO_SWITCH_MIMO2_AB 2
+#define IWL_SISO_SWITCH_MIMO2_AC 3
+#define IWL_SISO_SWITCH_MIMO2_BC 4
+#define IWL_SISO_SWITCH_GI 5
+#define IWL_SISO_SWITCH_MIMO3_ABC 6
+
+
+/* possible actions when in mimo mode */
+#define IWL_MIMO2_SWITCH_ANTENNA1 0
+#define IWL_MIMO2_SWITCH_ANTENNA2 1
+#define IWL_MIMO2_SWITCH_SISO_A 2
+#define IWL_MIMO2_SWITCH_SISO_B 3
+#define IWL_MIMO2_SWITCH_SISO_C 4
+#define IWL_MIMO2_SWITCH_GI 5
+#define IWL_MIMO2_SWITCH_MIMO3_ABC 6
+
+
+/* possible actions when in mimo3 mode */
+#define IWL_MIMO3_SWITCH_ANTENNA1 0
+#define IWL_MIMO3_SWITCH_ANTENNA2 1
+#define IWL_MIMO3_SWITCH_SISO_A 2
+#define IWL_MIMO3_SWITCH_SISO_B 3
+#define IWL_MIMO3_SWITCH_SISO_C 4
+#define IWL_MIMO3_SWITCH_MIMO2_AB 5
+#define IWL_MIMO3_SWITCH_MIMO2_AC 6
+#define IWL_MIMO3_SWITCH_MIMO2_BC 7
+#define IWL_MIMO3_SWITCH_GI 8
+
+
+#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI
+#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC
+
+/*FIXME:RS:add possible actions for MIMO3*/
+
+#define IWL_ACTION_LIMIT 3 /* # possible actions */
+
+#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
+#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000)
+#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100)
+
+#define LINK_QUAL_AGG_DISABLE_START_DEF (3)
+#define LINK_QUAL_AGG_DISABLE_START_MAX (255)
+#define LINK_QUAL_AGG_DISABLE_START_MIN (0)
+
+#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0)
+
+#define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */
+
+/* load per tid defines for A-MPDU activation */
+#define IWL_AGG_TPT_THREHOLD 0
+#define IWL_AGG_LOAD_THRESHOLD 10
+#define IWL_AGG_ALL_TID 0xff
+#define TID_QUEUE_CELL_SPACING 50 /*mS */
+#define TID_QUEUE_MAX_SIZE 20
+#define TID_ROUND_VALUE 5 /* mS */
+
+#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
+#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
+
+enum iwl_table_type {
+ LQ_NONE,
+ LQ_G, /* legacy types */
+ LQ_A,
+ LQ_SISO, /* high-throughput types */
+ LQ_MIMO2,
+ LQ_MIMO3,
+ LQ_MAX,
+};
+
+#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
+#define is_siso(tbl) ((tbl) == LQ_SISO)
+#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
+#define is_mimo3(tbl) ((tbl) == LQ_MIMO3)
+#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl))
+#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
+#define is_a_band(tbl) ((tbl) == LQ_A)
+#define is_g_and(tbl) ((tbl) == LQ_G)
+
+#define IWL_MAX_MCS_DISPLAY_SIZE 12
+
+struct iwl_rate_mcs_info {
+ char mbps[IWL_MAX_MCS_DISPLAY_SIZE];
+ char mcs[IWL_MAX_MCS_DISPLAY_SIZE];
+};
+
+/**
+ * struct iwl_rate_scale_data -- tx success history for one rate
+ */
+struct iwl_rate_scale_data {
+ u64 data; /* bitmap of successful frames */
+ s32 success_counter; /* number of frames successful */
+ s32 success_ratio; /* per-cent * 128 */
+ s32 counter; /* number of frames attempted */
+ s32 average_tpt; /* success ratio * expected throughput */
+ unsigned long stamp;
+};
+
+/**
+ * struct iwl_scale_tbl_info -- tx params and success history for all rates
+ *
+ * There are two of these in struct iwl_lq_sta,
+ * one for "active", and one for "search".
+ */
+struct iwl_scale_tbl_info {
+ enum iwl_table_type lq_type;
+ u8 ant_type;
+ u8 is_SGI; /* 1 = short guard interval */
+ u8 is_ht40; /* 1 = 40 MHz channel width */
+ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
+ u8 max_search; /* maximun number of tables we can search */
+ s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
+ u32 current_rate; /* rate_n_flags, uCode API format */
+ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
+};
+
+struct iwl_traffic_load {
+ unsigned long time_stamp; /* age of the oldest statistics */
+ u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
+ * slice */
+ u32 total; /* total num of packets during the
+ * last TID_MAX_TIME_DIFF */
+ u8 queue_count; /* number of queues that has
+ * been used since the last cleanup */
+ u8 head; /* start of the circular buffer */
+};
+
+/**
+ * struct iwl_lq_sta -- driver's rate scaling private structure
+ *
+ * Pointer to this gets passed back and forth between driver and mac80211.
+ */
+struct iwl_lq_sta {
+ u8 active_tbl; /* index of active table, range 0-1 */
+ u8 enable_counter; /* indicates HT mode */
+ u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
+ u8 search_better_tbl; /* 1: currently trying alternate mode */
+ s32 last_tpt;
+
+ /* The following determine when to search for a new mode */
+ u32 table_count_limit;
+ u32 max_failure_limit; /* # failed frames before new search */
+ u32 max_success_limit; /* # successful frames before new search */
+ u32 table_count;
+ u32 total_failed; /* total failed frames, any/all rates */
+ u32 total_success; /* total successful frames, any/all rates */
+ u64 flush_timer; /* time staying in mode before new search */
+
+ u8 action_counter; /* # mode-switch actions tried */
+ u8 is_green;
+ enum ieee80211_band band;
+
+ /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
+ u32 supp_rates;
+ u16 active_legacy_rate;
+ u16 active_siso_rate;
+ u16 active_mimo2_rate;
+ u16 active_mimo3_rate;
+ s8 max_rate_idx; /* Max rate set by user */
+ u8 missed_rate_counter;
+
+ struct iwl_lq_cmd lq;
+ struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
+ struct iwl_traffic_load load[IWL_MAX_TID_COUNT];
+ u8 tx_agg_tid_en;
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *rs_sta_dbgfs_scale_table_file;
+ struct dentry *rs_sta_dbgfs_stats_table_file;
+ struct dentry *rs_sta_dbgfs_rate_scale_data_file;
+ struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
+ u32 dbg_fixed_rate;
+#endif
+ struct iwl_mvm *drv;
+
+ /* used to be in sta_info */
+ int last_txrate_idx;
+ /* last tx rate_n_flags */
+ u32 last_rate_n_flags;
+ /* packets destined for this STA are aggregated */
+ u8 is_agg;
+ /* BT traffic this sta was last updated in */
+ u8 last_bt_traffic;
+};
+
+static inline u8 num_of_ant(u8 mask)
+{
+ return !!((mask) & ANT_A) +
+ !!((mask) & ANT_B) +
+ !!((mask) & ANT_C);
+}
+
+/* Initialize station's rate scaling information after adding station */
+extern void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ enum ieee80211_band band);
+
+/**
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
+ *
+ * Since the rate control algorithm is hardware specific, there is no need
+ * or reason to place it as a stand alone module. The driver can call
+ * iwl_rate_control_register in order to register the rate control callbacks
+ * with the mac80211 subsystem. This should be performed prior to calling
+ * ieee80211_register_hw
+ *
+ */
+extern int iwl_mvm_rate_control_register(void);
+
+/**
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
+ *
+ * This should be called after calling ieee80211_unregister_hw, but before
+ * the driver is unloaded.
+ */
+extern void iwl_mvm_rate_control_unregister(void);
+
+#endif /* __rs__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
new file mode 100644
index 000000000000..3f40ab05bbd8
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -0,0 +1,356 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 "iwl-trans.h"
+
+#include "mvm.h"
+#include "fw-api.h"
+
+/*
+ * iwl_mvm_rx_rx_phy_cmd - REPLY_RX_PHY_CMD handler
+ *
+ * Copies the phy information in mvm->last_phy_info, it will be used when the
+ * actual data will come from the fw in the next packet.
+ */
+int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+ memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info));
+ mvm->ampdu_ref++;
+ return 0;
+}
+
+/*
+ * iwl_mvm_pass_packet_to_mac80211 - builds the packet for mac80211
+ *
+ * Adds the rxb to a new skb and give it to mac80211
+ */
+static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
+ struct ieee80211_hdr *hdr, u16 len,
+ u32 ampdu_status,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct ieee80211_rx_status *stats)
+{
+ struct sk_buff *skb;
+ unsigned int hdrlen, fraglen;
+
+ /* Dont use dev_alloc_skb(), we'll have enough headroom once
+ * ieee80211_hdr pulled.
+ */
+ skb = alloc_skb(128, GFP_ATOMIC);
+ if (!skb) {
+ IWL_ERR(mvm, "alloc_skb failed\n");
+ return;
+ }
+ /* If frame is small enough to fit in skb->head, pull it completely.
+ * If not, only pull ieee80211_hdr so that splice() or TCP coalesce
+ * are more efficient.
+ */
+ hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr);
+
+ memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
+ fraglen = len - hdrlen;
+
+ if (fraglen) {
+ int offset = (void *)hdr + hdrlen -
+ rxb_addr(rxb) + rxb_offset(rxb);
+
+ skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
+ fraglen, rxb->truesize);
+ }
+
+ memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
+
+ ieee80211_rx_ni(mvm->hw, skb);
+}
+
+/*
+ * iwl_mvm_calc_rssi - calculate the rssi in dBm
+ * @phy_info: the phy information for the coming packet
+ */
+static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm,
+ struct iwl_rx_phy_info *phy_info)
+{
+ u32 rssi_a, rssi_b, rssi_c, max_rssi, agc_db;
+ u32 val;
+
+ /* Find max rssi among 3 possible receivers.
+ * These values are measured by the Digital Signal Processor (DSP).
+ * They should stay fairly constant even as the signal strength varies,
+ * if the radio's Automatic Gain Control (AGC) is working right.
+ * AGC value (see below) will provide the "interesting" info.
+ */
+ val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]);
+ rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS;
+ rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS;
+ val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_C_IDX]);
+ rssi_c = (val & IWL_OFDM_RSSI_INBAND_C_MSK) >> IWL_OFDM_RSSI_C_POS;
+
+ val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]);
+ agc_db = (val & IWL_OFDM_AGC_DB_MSK) >> IWL_OFDM_AGC_DB_POS;
+
+ max_rssi = max_t(u32, rssi_a, rssi_b);
+ max_rssi = max_t(u32, max_rssi, rssi_c);
+
+ IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+ rssi_a, rssi_b, rssi_c, max_rssi, agc_db);
+
+ /* dBm = max_rssi dB - agc dB - constant.
+ * Higher AGC (higher radio gain) means lower signal. */
+ return max_rssi - agc_db - IWL_RSSI_OFFSET;
+}
+
+/*
+ * iwl_mvm_set_mac80211_rx_flag - translate fw status to mac80211 format
+ * @mvm: the mvm object
+ * @hdr: 80211 header
+ * @stats: status in mac80211's format
+ * @rx_pkt_status: status coming from fw
+ *
+ * returns non 0 value if the packet should be dropped
+ */
+static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
+ struct ieee80211_hdr *hdr,
+ struct ieee80211_rx_status *stats,
+ u32 rx_pkt_status)
+{
+ if (!ieee80211_has_protected(hdr->frame_control) ||
+ (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
+ RX_MPDU_RES_STATUS_SEC_NO_ENC)
+ return 0;
+
+ /* packet was encrypted with unknown alg */
+ if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
+ RX_MPDU_RES_STATUS_SEC_ENC_ERR)
+ return 0;
+
+ switch (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) {
+ case RX_MPDU_RES_STATUS_SEC_CCM_ENC:
+ /* alg is CCM: check MIC only */
+ if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK))
+ return -1;
+
+ stats->flag |= RX_FLAG_DECRYPTED;
+ IWL_DEBUG_WEP(mvm, "hw decrypted CCMP successfully\n");
+ return 0;
+
+ case RX_MPDU_RES_STATUS_SEC_TKIP_ENC:
+ /* Don't drop the frame and decrypt it in SW */
+ if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK))
+ return 0;
+ /* fall through if TTAK OK */
+
+ case RX_MPDU_RES_STATUS_SEC_WEP_ENC:
+ if (!(rx_pkt_status & RX_MPDU_RES_STATUS_ICV_OK))
+ return -1;
+
+ stats->flag |= RX_FLAG_DECRYPTED;
+ return 0;
+
+ default:
+ IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);
+ }
+
+ return 0;
+}
+
+/*
+ * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler
+ *
+ * Handles the actual data of the Rx packet from the fw
+ */
+int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_rx_status rx_status = {};
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_rx_phy_info *phy_info;
+ struct iwl_rx_mpdu_res_start *rx_res;
+ u32 len;
+ u32 ampdu_status;
+ u32 rate_n_flags;
+ u32 rx_pkt_status;
+
+ phy_info = &mvm->last_phy_info;
+ rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data;
+ hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res));
+ len = le16_to_cpu(rx_res->byte_count);
+ rx_pkt_status = le32_to_cpup((__le32 *)
+ (pkt->data + sizeof(*rx_res) + len));
+
+ memset(&rx_status, 0, sizeof(rx_status));
+
+ /*
+ * drop the packet if it has failed being decrypted by HW
+ */
+ if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, &rx_status, rx_pkt_status)) {
+ IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n",
+ rx_pkt_status);
+ return 0;
+ }
+
+ if ((unlikely(phy_info->cfg_phy_cnt > 20))) {
+ IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n",
+ phy_info->cfg_phy_cnt);
+ return 0;
+ }
+
+ if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) ||
+ !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) {
+ IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status);
+ return 0;
+ }
+
+ /* This will be used in several places later */
+ rate_n_flags = le32_to_cpu(phy_info->rate_n_flags);
+
+ /* rx_status carries information about the packet to mac80211 */
+ rx_status.mactime = le64_to_cpu(phy_info->timestamp);
+ rx_status.device_timestamp = le32_to_cpu(phy_info->system_timestamp);
+ rx_status.band =
+ (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ?
+ IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ rx_status.freq =
+ ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel),
+ rx_status.band);
+ /*
+ * TSF as indicated by the fw is at INA time, but mac80211 expects the
+ * TSF at the beginning of the MPDU.
+ */
+ /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/
+
+ /* Find max signal strength (dBm) among 3 antenna/receiver chains */
+ rx_status.signal = iwl_mvm_calc_rssi(mvm, phy_info);
+
+ IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal,
+ (unsigned long long)rx_status.mactime);
+
+ /*
+ * "antenna number"
+ *
+ * It seems that the antenna field in the phy flags value
+ * is actually a bit field. This is undefined by radiotap,
+ * it wants an actual antenna number but I always get "7"
+ * for most legacy frames I receive indicating that the
+ * same frame was received on all three RX chains.
+ *
+ * I think this field should be removed in favor of a
+ * new 802.11n radiotap field "RX chains" that is defined
+ * as a bitmask.
+ */
+ rx_status.antenna = (le16_to_cpu(phy_info->phy_flags) &
+ RX_RES_PHY_FLAGS_ANTENNA)
+ >> RX_RES_PHY_FLAGS_ANTENNA_POS;
+
+ /* set the preamble flag if appropriate */
+ if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE))
+ rx_status.flag |= RX_FLAG_SHORTPRE;
+
+ if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
+ /*
+ * We know which subframes of an A-MPDU belong
+ * together since we get a single PHY response
+ * from the firmware for all of them
+ */
+ rx_status.flag |= RX_FLAG_AMPDU_DETAILS;
+ rx_status.ampdu_reference = mvm->ampdu_ref;
+ }
+
+ /* Set up the HT phy flags */
+ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
+ case RATE_MCS_CHAN_WIDTH_20:
+ break;
+ case RATE_MCS_CHAN_WIDTH_40:
+ rx_status.flag |= RX_FLAG_40MHZ;
+ break;
+ case RATE_MCS_CHAN_WIDTH_80:
+ rx_status.flag |= RX_FLAG_80MHZ;
+ break;
+ case RATE_MCS_CHAN_WIDTH_160:
+ rx_status.flag |= RX_FLAG_160MHZ;
+ break;
+ }
+ if (rate_n_flags & RATE_MCS_SGI_MSK)
+ rx_status.flag |= RX_FLAG_SHORT_GI;
+ if (rate_n_flags & RATE_HT_MCS_GF_MSK)
+ rx_status.flag |= RX_FLAG_HT_GF;
+ if (rate_n_flags & RATE_MCS_HT_MSK) {
+ rx_status.flag |= RX_FLAG_HT;
+ rx_status.rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
+ } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+ rx_status.vht_nss =
+ ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
+ RATE_VHT_MCS_NSS_POS) + 1;
+ rx_status.rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
+ rx_status.flag |= RX_FLAG_VHT;
+ } else {
+ rx_status.rate_idx =
+ iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
+ rx_status.band);
+ }
+
+ iwl_mvm_pass_packet_to_mac80211(mvm, hdr, len, ampdu_status,
+ rxb, &rx_status);
+ return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
new file mode 100644
index 000000000000..9b21b92aa8d1
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -0,0 +1,442 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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/etherdevice.h>
+#include <net/mac80211.h>
+
+#include "mvm.h"
+#include "iwl-eeprom-parse.h"
+#include "fw-api-scan.h"
+
+#define IWL_PLCP_QUIET_THRESH 1
+#define IWL_ACTIVE_QUIET_TIME 10
+
+static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
+{
+ u16 rx_chain;
+ u8 rx_ant = mvm->nvm_data->valid_rx_ant;
+
+ rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS;
+ rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
+ rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS;
+ rx_chain |= 0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS;
+ return cpu_to_le16(rx_chain);
+}
+
+static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif)
+{
+ if (vif->bss_conf.assoc)
+ return cpu_to_le32(200 * 1024);
+ else
+ return 0;
+}
+
+static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif)
+{
+ if (vif->bss_conf.assoc)
+ return cpu_to_le32(vif->bss_conf.beacon_int);
+ else
+ return 0;
+}
+
+static inline __le32
+iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req)
+{
+ if (req->channels[0]->band == IEEE80211_BAND_2GHZ)
+ return cpu_to_le32(PHY_BAND_24);
+ else
+ return cpu_to_le32(PHY_BAND_5);
+}
+
+static inline __le32
+iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
+ bool no_cck)
+{
+ u32 tx_ant;
+
+ mvm->scan_last_antenna_idx =
+ iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+ mvm->scan_last_antenna_idx);
+ tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS;
+
+ if (band == IEEE80211_BAND_2GHZ && !no_cck)
+ return cpu_to_le32(IWL_RATE_1M_PLCP | RATE_MCS_CCK_MSK |
+ tx_ant);
+ else
+ return cpu_to_le32(IWL_RATE_6M_PLCP | tx_ant);
+}
+
+/*
+ * We insert the SSIDs in an inverted order, because the FW will
+ * invert it back. The most prioritized SSID, which is first in the
+ * request list, is not copied here, but inserted directly to the probe
+ * request.
+ */
+static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
+ struct cfg80211_scan_request *req)
+{
+ int fw_idx, req_idx;
+
+ fw_idx = 0;
+ for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) {
+ cmd->direct_scan[fw_idx].id = WLAN_EID_SSID;
+ cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len;
+ memcpy(cmd->direct_scan[fw_idx].ssid,
+ req->ssids[req_idx].ssid,
+ req->ssids[req_idx].ssid_len);
+ }
+}
+
+/*
+ * If req->n_ssids > 0, it means we should do an active scan.
+ * In case of active scan w/o directed scan, we receive a zero-length SSID
+ * just to notify that this scan is active and not passive.
+ * In order to notify the FW of the number of SSIDs we wish to scan (including
+ * the zero-length one), we need to set the corresponding bits in chan->type,
+ * one for each SSID, and set the active bit (first).
+ */
+static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
+{
+ if (band == IEEE80211_BAND_2GHZ)
+ return 30 + 3 * (n_ssids + 1);
+ return 20 + 2 * (n_ssids + 1);
+}
+
+static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
+{
+ return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10;
+}
+
+static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
+ struct cfg80211_scan_request *req)
+{
+ u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band);
+ u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band,
+ req->n_ssids);
+ struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
+ (cmd->data + le16_to_cpu(cmd->tx_cmd.len));
+ int i;
+ __le32 chan_type_value;
+
+ if (req->n_ssids > 0)
+ chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1);
+ else
+ chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE;
+
+ for (i = 0; i < cmd->channel_count; i++) {
+ chan->channel = cpu_to_le16(req->channels[i]->hw_value);
+ if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ chan->type = SCAN_CHANNEL_TYPE_PASSIVE;
+ else
+ chan->type = chan_type_value;
+ chan->active_dwell = cpu_to_le16(active_dwell);
+ chan->passive_dwell = cpu_to_le16(passive_dwell);
+ chan->iteration_count = cpu_to_le16(1);
+ chan++;
+ }
+}
+
+/*
+ * Fill in probe request with the following parameters:
+ * TA is our vif HW address, which mac80211 ensures we have.
+ * Packet is broadcasted, so this is both SA and DA.
+ * The probe request IE is made out of two: first comes the most prioritized
+ * SSID if a directed scan is requested. Second comes whatever extra
+ * information was given to us as the scan request IE.
+ */
+static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
+ int n_ssids, const u8 *ssid, int ssid_len,
+ const u8 *ie, int ie_len,
+ int left)
+{
+ int len = 0;
+ u8 *pos = NULL;
+
+ /* Make sure there is enough space for the probe request,
+ * two mandatory IEs and the data */
+ left -= 24;
+ if (left < 0)
+ return 0;
+
+ frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+ eth_broadcast_addr(frame->da);
+ memcpy(frame->sa, ta, ETH_ALEN);
+ eth_broadcast_addr(frame->bssid);
+ frame->seq_ctrl = 0;
+
+ len += 24;
+
+ /* for passive scans, no need to fill anything */
+ if (n_ssids == 0)
+ return (u16)len;
+
+ /* points to the payload of the request */
+ pos = &frame->u.probe_req.variable[0];
+
+ /* fill in our SSID IE */
+ left -= ssid_len + 2;
+ if (left < 0)
+ return 0;
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ssid_len;
+ if (ssid && ssid_len) { /* ssid_len may be == 0 even if ssid is valid */
+ memcpy(pos, ssid, ssid_len);
+ pos += ssid_len;
+ }
+
+ len += ssid_len + 2;
+
+ if (WARN_ON(left < ie_len))
+ return len;
+
+ if (ie && ie_len) {
+ memcpy(pos, ie, ie_len);
+ len += ie_len;
+ }
+
+ return (u16)len;
+}
+
+int iwl_mvm_scan_request(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_scan_request *req)
+{
+ struct iwl_host_cmd hcmd = {
+ .id = SCAN_REQUEST_CMD,
+ .len = { 0, },
+ .data = { mvm->scan_cmd, },
+ .flags = CMD_SYNC,
+ .dataflags = { IWL_HCMD_DFL_NOCOPY, },
+ };
+ struct iwl_scan_cmd *cmd = mvm->scan_cmd;
+ int ret;
+ u32 status;
+ int ssid_len = 0;
+ u8 *ssid = NULL;
+
+ lockdep_assert_held(&mvm->mutex);
+ BUG_ON(mvm->scan_cmd == NULL);
+
+ IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n");
+ mvm->scan_status = IWL_MVM_SCAN_OS;
+ memset(cmd, 0, sizeof(struct iwl_scan_cmd) +
+ mvm->fw->ucode_capa.max_probe_length +
+ (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)));
+
+ cmd->channel_count = (u8)req->n_channels;
+ cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
+ cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
+ cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm);
+ cmd->max_out_time = iwl_mvm_scan_max_out_time(vif);
+ cmd->suspend_time = iwl_mvm_scan_suspend_time(vif);
+ cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req);
+ cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
+ MAC_FILTER_IN_BEACON);
+
+ if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
+ cmd->type = cpu_to_le32(SCAN_TYPE_DISCOVERY_FORCED);
+ else
+ cmd->type = cpu_to_le32(SCAN_TYPE_FORCED);
+
+ cmd->repeats = cpu_to_le32(1);
+
+ /*
+ * If the user asked for passive scan, don't change to active scan if
+ * you see any activity on the channel - remain passive.
+ */
+ if (req->n_ssids > 0) {
+ cmd->passive2active = cpu_to_le16(1);
+ ssid = req->ssids[0].ssid;
+ ssid_len = req->ssids[0].ssid_len;
+ } else {
+ cmd->passive2active = 0;
+ }
+
+ iwl_mvm_scan_fill_ssids(cmd, req);
+
+ cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL);
+ cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id;
+ cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
+ cmd->tx_cmd.rate_n_flags =
+ iwl_mvm_scan_rate_n_flags(mvm, req->channels[0]->band,
+ req->no_cck);
+
+ cmd->tx_cmd.len =
+ cpu_to_le16(iwl_mvm_fill_probe_req(
+ (struct ieee80211_mgmt *)cmd->data,
+ vif->addr,
+ req->n_ssids, ssid, ssid_len,
+ req->ie, req->ie_len,
+ mvm->fw->ucode_capa.max_probe_length));
+
+ iwl_mvm_scan_fill_channels(cmd, req);
+
+ cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) +
+ le16_to_cpu(cmd->tx_cmd.len) +
+ (cmd->channel_count * sizeof(struct iwl_scan_channel)));
+ hcmd.len[0] = le16_to_cpu(cmd->len);
+
+ status = SCAN_RESPONSE_OK;
+ ret = iwl_mvm_send_cmd_status(mvm, &hcmd, &status);
+ if (!ret && status == SCAN_RESPONSE_OK) {
+ IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
+ } else {
+ /*
+ * If the scan failed, it usually means that the FW was unable
+ * to allocate the time events. Warn on it, but maybe we
+ * should try to send the command again with different params.
+ */
+ IWL_ERR(mvm, "Scan failed! status 0x%x ret %d\n",
+ status, ret);
+ mvm->scan_status = IWL_MVM_SCAN_NONE;
+ ret = -EIO;
+ }
+ return ret;
+}
+
+int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_cmd_response *resp = (void *)pkt->data;
+
+ IWL_DEBUG_SCAN(mvm, "Scan response received. status 0x%x\n",
+ le32_to_cpu(resp->status));
+ return 0;
+}
+
+int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_scan_complete_notif *notif = (void *)pkt->data;
+
+ IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n",
+ notif->status, notif->scanned_channels);
+
+ mvm->scan_status = IWL_MVM_SCAN_NONE;
+ ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK);
+
+ return 0;
+}
+
+static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
+ struct iwl_rx_packet *pkt, void *data)
+{
+ struct iwl_mvm *mvm =
+ container_of(notif_wait, struct iwl_mvm, notif_wait);
+ struct iwl_scan_complete_notif *notif;
+ u32 *resp;
+
+ switch (pkt->hdr.cmd) {
+ case SCAN_ABORT_CMD:
+ resp = (void *)pkt->data;
+ if (*resp == CAN_ABORT_STATUS) {
+ IWL_DEBUG_SCAN(mvm,
+ "Scan can be aborted, wait until completion\n");
+ return false;
+ }
+
+ IWL_DEBUG_SCAN(mvm, "Scan cannot be aborted, exit now: %d\n",
+ *resp);
+ return true;
+
+ case SCAN_COMPLETE_NOTIFICATION:
+ notif = (void *)pkt->data;
+ IWL_DEBUG_SCAN(mvm, "Scan aborted: status 0x%x\n",
+ notif->status);
+ return true;
+
+ default:
+ WARN_ON(1);
+ return false;
+ };
+}
+
+void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
+{
+ struct iwl_notification_wait wait_scan_abort;
+ static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD,
+ SCAN_COMPLETE_NOTIFICATION };
+ int ret;
+
+ iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
+ scan_abort_notif,
+ ARRAY_SIZE(scan_abort_notif),
+ iwl_mvm_scan_abort_notif, NULL);
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL);
+ if (ret) {
+ IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret);
+ goto out_remove_notif;
+ }
+
+ ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, 1 * HZ);
+ if (ret)
+ IWL_ERR(mvm, "%s - failed on timeout\n", __func__);
+
+ return;
+
+out_remove_notif:
+ iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
new file mode 100644
index 000000000000..861a7f9f8e7f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -0,0 +1,1241 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 <net/mac80211.h>
+
+#include "mvm.h"
+#include "sta.h"
+
+static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm)
+{
+ int sta_id;
+
+ WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status));
+
+ lockdep_assert_held(&mvm->mutex);
+
+ /* Don't take rcu_read_lock() since we are protected by mvm->mutex */
+ for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++)
+ if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex)))
+ return sta_id;
+ return IWL_MVM_STATION_COUNT;
+}
+
+/* send station add/update command to firmware */
+int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ bool update)
+{
+ struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_add_sta_cmd add_sta_cmd;
+ int ret;
+ u32 status;
+ u32 agg_size = 0, mpdu_dens = 0;
+
+ memset(&add_sta_cmd, 0, sizeof(add_sta_cmd));
+
+ add_sta_cmd.sta_id = mvm_sta->sta_id;
+ add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
+ if (!update) {
+ add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk);
+ memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN);
+ }
+ add_sta_cmd.add_modify = update ? 1 : 0;
+
+ /* STA_FLG_FAT_EN_MSK ? */
+ /* STA_FLG_MIMO_EN_MSK ? */
+
+ if (sta->ht_cap.ht_supported) {
+ add_sta_cmd.station_flags_msk |=
+ cpu_to_le32(STA_FLG_MAX_AGG_SIZE_MSK |
+ STA_FLG_AGG_MPDU_DENS_MSK);
+
+ mpdu_dens = sta->ht_cap.ampdu_density;
+ }
+
+ if (sta->vht_cap.vht_supported) {
+ agg_size = sta->vht_cap.cap &
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+ agg_size >>=
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+ } else if (sta->ht_cap.ht_supported) {
+ agg_size = sta->ht_cap.ampdu_factor;
+ }
+
+ add_sta_cmd.station_flags |=
+ cpu_to_le32(agg_size << STA_FLG_MAX_AGG_SIZE_SHIFT);
+ add_sta_cmd.station_flags |=
+ cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT);
+
+ status = ADD_STA_SUCCESS;
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd),
+ &add_sta_cmd, &status);
+ if (ret)
+ return ret;
+
+ switch (status) {
+ case ADD_STA_SUCCESS:
+ IWL_DEBUG_ASSOC(mvm, "ADD_STA PASSED\n");
+ break;
+ default:
+ ret = -EIO;
+ IWL_ERR(mvm, "ADD_STA failed\n");
+ break;
+ }
+
+ return ret;
+}
+
+int iwl_mvm_add_sta(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ int i, ret, sta_id;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ sta_id = iwl_mvm_find_free_sta_id(mvm);
+ else
+ sta_id = mvm_sta->sta_id;
+
+ if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
+ return -ENOSPC;
+
+ spin_lock_init(&mvm_sta->lock);
+
+ mvm_sta->sta_id = sta_id;
+ mvm_sta->mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id,
+ mvmvif->color);
+ mvm_sta->vif = vif;
+ mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+
+ /* HW restart, don't assume the memory has been zeroed */
+ atomic_set(&mvm_sta->pending_frames, 0);
+ mvm_sta->tid_disable_agg = 0;
+ mvm_sta->tfd_queue_msk = 0;
+ for (i = 0; i < IEEE80211_NUM_ACS; i++)
+ if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE)
+ mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]);
+
+ if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
+ mvm_sta->tfd_queue_msk |= BIT(vif->cab_queue);
+
+ /* for HW restart - need to reset the seq_number etc... */
+ memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data));
+
+ ret = iwl_mvm_sta_send_to_fw(mvm, sta, false);
+ if (ret)
+ return ret;
+
+ /* The first station added is the AP, the others are TDLS STAs */
+ if (vif->type == NL80211_IFTYPE_STATION &&
+ mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
+ mvmvif->ap_sta_id = sta_id;
+
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
+
+ return 0;
+}
+
+int iwl_mvm_update_sta(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ return iwl_mvm_sta_send_to_fw(mvm, sta, true);
+}
+
+int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
+ bool drain)
+{
+ struct iwl_mvm_add_sta_cmd cmd = {};
+ int ret;
+ u32 status;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ cmd.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color);
+ cmd.sta_id = mvmsta->sta_id;
+ cmd.add_modify = STA_MODE_MODIFY;
+ cmd.station_flags = drain ? cpu_to_le32(STA_FLG_DRAIN_FLOW) : 0;
+ cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW);
+
+ status = ADD_STA_SUCCESS;
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+ &cmd, &status);
+ if (ret)
+ return ret;
+
+ switch (status) {
+ case ADD_STA_SUCCESS:
+ IWL_DEBUG_INFO(mvm, "Frames for staid %d will drained in fw\n",
+ mvmsta->sta_id);
+ break;
+ default:
+ ret = -EIO;
+ IWL_ERR(mvm, "Couldn't drain frames for staid %d\n",
+ mvmsta->sta_id);
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Remove a station from the FW table. Before sending the command to remove
+ * the station validate that the station is indeed known to the driver (sanity
+ * only).
+ */
+static int iwl_mvm_rm_sta_common(struct iwl_mvm *mvm, u8 sta_id)
+{
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_rm_sta_cmd rm_sta_cmd = {
+ .sta_id = sta_id,
+ };
+ int ret;
+
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+
+ /* Note: internal stations are marked as error values */
+ if (!sta) {
+ IWL_ERR(mvm, "Invalid station id\n");
+ return -EINVAL;
+ }
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, REMOVE_STA, CMD_SYNC,
+ sizeof(rm_sta_cmd), &rm_sta_cmd);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to remove station. Id=%d\n", sta_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+void iwl_mvm_sta_drained_wk(struct work_struct *wk)
+{
+ struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, sta_drained_wk);
+ u8 sta_id;
+
+ /*
+ * The mutex is needed because of the SYNC cmd, but not only: if the
+ * work would run concurrently with iwl_mvm_rm_sta, it would run before
+ * iwl_mvm_rm_sta sets the station as busy, and exit. Then
+ * iwl_mvm_rm_sta would set the station as busy, and nobody will clean
+ * that later.
+ */
+ mutex_lock(&mvm->mutex);
+
+ for_each_set_bit(sta_id, mvm->sta_drained, IWL_MVM_STATION_COUNT) {
+ int ret;
+ struct ieee80211_sta *sta =
+ rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+
+ /* This station is in use */
+ if (!IS_ERR(sta))
+ continue;
+
+ if (PTR_ERR(sta) == -EINVAL) {
+ IWL_ERR(mvm, "Drained sta %d, but it is internal?\n",
+ sta_id);
+ continue;
+ }
+
+ if (!sta) {
+ IWL_ERR(mvm, "Drained sta %d, but it was NULL?\n",
+ sta_id);
+ continue;
+ }
+
+ WARN_ON(PTR_ERR(sta) != -EBUSY);
+ /* This station was removed and we waited until it got drained,
+ * we can now proceed and remove it.
+ */
+ ret = iwl_mvm_rm_sta_common(mvm, sta_id);
+ if (ret) {
+ IWL_ERR(mvm,
+ "Couldn't remove sta %d after it was drained\n",
+ sta_id);
+ continue;
+ }
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL);
+ clear_bit(sta_id, mvm->sta_drained);
+ }
+
+ mutex_unlock(&mvm->mutex);
+}
+
+int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (vif->type == NL80211_IFTYPE_STATION &&
+ mvmvif->ap_sta_id == mvm_sta->sta_id) {
+ /*
+ * Put a non-NULL since the fw station isn't removed.
+ * It will be removed after the MAC will be set as
+ * unassoc.
+ */
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
+ ERR_PTR(-EINVAL));
+
+ /* flush its queues here since we are freeing mvm_sta */
+ ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true);
+
+ /* if we are associated - we can't remove the AP STA now */
+ if (vif->bss_conf.assoc)
+ return ret;
+
+ /* unassoc - go ahead - remove the AP STA now */
+ mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
+ }
+
+ /*
+ * There are frames pending on the AC queues for this station.
+ * We need to wait until all the frames are drained...
+ */
+ if (atomic_read(&mvm_sta->pending_frames)) {
+ ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
+ ERR_PTR(-EBUSY));
+ } else {
+ ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
+ }
+
+ return ret;
+}
+
+int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u8 sta_id)
+{
+ int ret = iwl_mvm_rm_sta_common(mvm, sta_id);
+
+ lockdep_assert_held(&mvm->mutex);
+
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], NULL);
+ return ret;
+}
+
+int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
+ u32 qmask)
+{
+ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+ sta->sta_id = iwl_mvm_find_free_sta_id(mvm);
+ if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT))
+ return -ENOSPC;
+ }
+
+ sta->tfd_queue_msk = qmask;
+
+ /* put a non-NULL value so iterating over the stations won't stop */
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], ERR_PTR(-EINVAL));
+ return 0;
+}
+
+void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta)
+{
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], NULL);
+ memset(sta, 0, sizeof(struct iwl_mvm_int_sta));
+ sta->sta_id = IWL_MVM_STATION_COUNT;
+}
+
+static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
+ struct iwl_mvm_int_sta *sta,
+ const u8 *addr,
+ u16 mac_id, u16 color)
+{
+ struct iwl_mvm_add_sta_cmd cmd;
+ int ret;
+ u32 status;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd));
+ cmd.sta_id = sta->sta_id;
+ cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id,
+ color));
+
+ cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk);
+
+ if (addr)
+ memcpy(cmd.addr, addr, ETH_ALEN);
+
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+ &cmd, &status);
+ if (ret)
+ return ret;
+
+ switch (status) {
+ case ADD_STA_SUCCESS:
+ IWL_DEBUG_INFO(mvm, "Internal station added.\n");
+ return 0;
+ default:
+ ret = -EIO;
+ IWL_ERR(mvm, "Add internal station failed, status=0x%x\n",
+ status);
+ break;
+ }
+ return ret;
+}
+
+int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
+{
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ /* Add the aux station, but without any queues */
+ ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0);
+ if (ret)
+ return ret;
+
+ ret = iwl_mvm_add_int_sta_common(mvm, &mvm->aux_sta, NULL,
+ MAC_INDEX_AUX, 0);
+
+ if (ret)
+ iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+ return ret;
+}
+
+/*
+ * Send the add station command for the vif's broadcast station.
+ * Assumes that the station was already allocated.
+ *
+ * @mvm: the mvm component
+ * @vif: the interface to which the broadcast station is added
+ * @bsta: the broadcast station to add.
+ */
+int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_mvm_int_sta *bsta)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_STATION_COUNT))
+ return -ENOSPC;
+
+ return iwl_mvm_add_int_sta_common(mvm, bsta, baddr,
+ mvmvif->id, mvmvif->color);
+}
+
+/* Send the FW a request to remove the station from it's internal data
+ * structures, but DO NOT remove the entry from the local data structures. */
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
+ struct iwl_mvm_int_sta *bsta)
+{
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
+ if (ret)
+ IWL_WARN(mvm, "Failed sending remove station\n");
+ return ret;
+}
+
+/* Allocate a new station entry for the broadcast station to the given vif,
+ * and send it to the FW.
+ * Note that each P2P mac should have its own broadcast station.
+ *
+ * @mvm: the mvm component
+ * @vif: the interface to which the broadcast station is added
+ * @bsta: the broadcast station to add. */
+int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_mvm_int_sta *bsta)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+ u32 qmask;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+ ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask);
+ if (ret)
+ return ret;
+
+ ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr,
+ mvmvif->id, mvmvif->color);
+
+ if (ret)
+ iwl_mvm_dealloc_int_sta(mvm, bsta);
+ return ret;
+}
+
+/*
+ * Send the FW a request to remove the station from it's internal data
+ * structures, and in addition remove it from the local data structure.
+ */
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
+{
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
+ if (ret)
+ return ret;
+
+ iwl_mvm_dealloc_int_sta(mvm, bsta);
+ return ret;
+}
+
+int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ int tid, u16 ssn, bool start)
+{
+ struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_add_sta_cmd cmd = {};
+ int ret;
+ u32 status;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
+ cmd.sta_id = mvm_sta->sta_id;
+ cmd.add_modify = STA_MODE_MODIFY;
+ cmd.add_immediate_ba_tid = (u8) tid;
+ cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+ cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID :
+ STA_MODIFY_REMOVE_BA_TID;
+
+ status = ADD_STA_SUCCESS;
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+ &cmd, &status);
+ if (ret)
+ return ret;
+
+ switch (status) {
+ case ADD_STA_SUCCESS:
+ IWL_DEBUG_INFO(mvm, "RX BA Session %sed in fw\n",
+ start ? "start" : "stopp");
+ break;
+ case ADD_STA_IMMEDIATE_BA_FAILURE:
+ IWL_WARN(mvm, "RX BA Session refused by fw\n");
+ ret = -ENOSPC;
+ break;
+ default:
+ ret = -EIO;
+ IWL_ERR(mvm, "RX BA Session failed %sing, status 0x%x\n",
+ start ? "start" : "stopp", status);
+ break;
+ }
+
+ return ret;
+}
+
+static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ int tid, u8 queue, bool start)
+{
+ struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_add_sta_cmd cmd = {};
+ int ret;
+ u32 status;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (start) {
+ mvm_sta->tfd_queue_msk |= BIT(queue);
+ mvm_sta->tid_disable_agg &= ~BIT(tid);
+ } else {
+ mvm_sta->tfd_queue_msk &= ~BIT(queue);
+ mvm_sta->tid_disable_agg |= BIT(tid);
+ }
+
+ cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
+ cmd.sta_id = mvm_sta->sta_id;
+ cmd.add_modify = STA_MODE_MODIFY;
+ cmd.modify_mask = STA_MODIFY_QUEUES | STA_MODIFY_TID_DISABLE_TX;
+ cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk);
+ cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg);
+
+ status = ADD_STA_SUCCESS;
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+ &cmd, &status);
+ if (ret)
+ return ret;
+
+ switch (status) {
+ case ADD_STA_SUCCESS:
+ break;
+ default:
+ ret = -EIO;
+ IWL_ERR(mvm, "TX BA Session failed %sing, status 0x%x\n",
+ start ? "start" : "stopp", status);
+ break;
+ }
+
+ return ret;
+}
+
+static const u8 tid_to_ac[] = {
+ IEEE80211_AC_BE,
+ IEEE80211_AC_BK,
+ IEEE80211_AC_BK,
+ IEEE80211_AC_BE,
+ IEEE80211_AC_VI,
+ IEEE80211_AC_VI,
+ IEEE80211_AC_VO,
+ IEEE80211_AC_VO,
+};
+
+int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+ struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+ struct iwl_mvm_tid_data *tid_data;
+ int txq_id;
+
+ if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+ return -EINVAL;
+
+ if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) {
+ IWL_ERR(mvm, "Start AGG when state is not IWL_AGG_OFF %d!\n",
+ mvmsta->tid_data[tid].state);
+ return -ENXIO;
+ }
+
+ lockdep_assert_held(&mvm->mutex);
+
+ for (txq_id = IWL_MVM_FIRST_AGG_QUEUE;
+ txq_id <= IWL_MVM_LAST_AGG_QUEUE; txq_id++)
+ if (mvm->queue_to_mac80211[txq_id] ==
+ IWL_INVALID_MAC80211_QUEUE)
+ break;
+
+ if (txq_id > IWL_MVM_LAST_AGG_QUEUE) {
+ IWL_ERR(mvm, "Failed to allocate agg queue\n");
+ return -EIO;
+ }
+
+ /* the new tx queue is still connected to the same mac80211 queue */
+ mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_ac[tid]];
+
+ spin_lock_bh(&mvmsta->lock);
+ tid_data = &mvmsta->tid_data[tid];
+ tid_data->ssn = SEQ_TO_SN(tid_data->seq_number);
+ tid_data->txq_id = txq_id;
+ *ssn = tid_data->ssn;
+
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Start AGG: sta %d tid %d queue %d - ssn = %d, next_recl = %d\n",
+ mvmsta->sta_id, tid, txq_id, tid_data->ssn,
+ tid_data->next_reclaimed);
+
+ if (tid_data->ssn == tid_data->next_reclaimed) {
+ tid_data->state = IWL_AGG_STARTING;
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ } else {
+ tid_data->state = IWL_EMPTYING_HW_QUEUE_ADDBA;
+ }
+
+ spin_unlock_bh(&mvmsta->lock);
+
+ return 0;
+}
+
+int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid, u8 buf_size)
+{
+ struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+ struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+ int queue, fifo, ret;
+ u16 ssn;
+
+ buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
+
+ spin_lock_bh(&mvmsta->lock);
+ ssn = tid_data->ssn;
+ queue = tid_data->txq_id;
+ tid_data->state = IWL_AGG_ON;
+ tid_data->ssn = 0xffff;
+ spin_unlock_bh(&mvmsta->lock);
+
+ fifo = iwl_mvm_ac_to_tx_fifo[tid_to_ac[tid]];
+
+ ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
+ if (ret)
+ return -EIO;
+
+ iwl_trans_txq_enable(mvm->trans, queue, fifo, mvmsta->sta_id, tid,
+ buf_size, ssn);
+
+ /*
+ * Even though in theory the peer could have different
+ * aggregation reorder buffer sizes for different sessions,
+ * our ucode doesn't allow for that and has a global limit
+ * for each station. Therefore, use the minimum of all the
+ * aggregation sessions and our default value.
+ */
+ mvmsta->max_agg_bufsize =
+ min(mvmsta->max_agg_bufsize, buf_size);
+ mvmsta->lq_sta.lq.agg_frame_cnt_limit = mvmsta->max_agg_bufsize;
+
+ if (mvm->cfg->ht_params->use_rts_for_aggregation) {
+ /*
+ * switch to RTS/CTS if it is the prefer protection
+ * method for HT traffic
+ */
+ mvmsta->lq_sta.lq.flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK;
+ /*
+ * TODO: remove the TLC_RTS flag when we tear down the last
+ * AGG session (agg_tids_count in DVM)
+ */
+ }
+
+ IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
+ sta->addr, tid);
+
+ return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, CMD_ASYNC, false);
+}
+
+int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid)
+{
+ struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+ struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+ u16 txq_id;
+ int err;
+
+ spin_lock_bh(&mvmsta->lock);
+
+ txq_id = tid_data->txq_id;
+
+ IWL_DEBUG_TX_QUEUES(mvm, "Stop AGG: sta %d tid %d q %d state %d\n",
+ mvmsta->sta_id, tid, txq_id, tid_data->state);
+
+ switch (tid_data->state) {
+ case IWL_AGG_ON:
+ tid_data->ssn = SEQ_TO_SN(tid_data->seq_number);
+
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "ssn = %d, next_recl = %d\n",
+ tid_data->ssn, tid_data->next_reclaimed);
+
+ /* There are still packets for this RA / TID in the HW */
+ if (tid_data->ssn != tid_data->next_reclaimed) {
+ tid_data->state = IWL_EMPTYING_HW_QUEUE_DELBA;
+ err = 0;
+ break;
+ }
+
+ tid_data->ssn = 0xffff;
+ iwl_trans_txq_disable(mvm->trans, txq_id);
+ /* fall through */
+ case IWL_AGG_STARTING:
+ case IWL_EMPTYING_HW_QUEUE_ADDBA:
+ /*
+ * The agg session has been stopped before it was set up. This
+ * can happen when the AddBA timer times out for example.
+ */
+
+ /* No barriers since we are under mutex */
+ lockdep_assert_held(&mvm->mutex);
+ mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE;
+
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ tid_data->state = IWL_AGG_OFF;
+ err = 0;
+ break;
+ default:
+ IWL_ERR(mvm,
+ "Stopping AGG while state not ON or starting for %d on %d (%d)\n",
+ mvmsta->sta_id, tid, tid_data->state);
+ IWL_ERR(mvm,
+ "\ttid_data->txq_id = %d\n", tid_data->txq_id);
+ err = -EINVAL;
+ }
+
+ spin_unlock_bh(&mvmsta->lock);
+
+ return err;
+}
+
+static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
+{
+ int i;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ i = find_first_zero_bit(mvm->fw_key_table, STA_KEY_MAX_NUM);
+
+ if (i == STA_KEY_MAX_NUM)
+ return STA_KEY_IDX_INVALID;
+
+ __set_bit(i, mvm->fw_key_table);
+
+ return i;
+}
+
+static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+
+ if (sta) {
+ struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+
+ return mvm_sta->sta_id;
+ }
+
+ /*
+ * The device expects GTKs for station interfaces to be
+ * installed as GTKs for the AP station. If we have no
+ * station ID, then use AP's station ID.
+ */
+ if (vif->type == NL80211_IFTYPE_STATION &&
+ mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT)
+ return mvmvif->ap_sta_id;
+
+ return IWL_INVALID_STATION;
+}
+
+static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
+ struct iwl_mvm_sta *mvm_sta,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k,
+ u32 cmd_flags)
+{
+ __le16 key_flags;
+ struct iwl_mvm_add_sta_cmd cmd = {};
+ int ret, status;
+ u16 keyidx;
+ int i;
+
+ keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
+ STA_KEY_FLG_KEYID_MSK;
+ key_flags = cpu_to_le16(keyidx);
+ key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_KEY_MAP);
+
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_TKIP:
+ key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP);
+ cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;
+ for (i = 0; i < 5; i++)
+ cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]);
+ memcpy(cmd.key.key, keyconf->key, keyconf->keylen);
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key_flags |= cpu_to_le16(STA_KEY_FLG_CCM);
+ memcpy(cmd.key.key, keyconf->key, keyconf->keylen);
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
+
+ cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
+ cmd.key.key_offset = keyconf->hw_key_idx;
+ cmd.key.key_flags = key_flags;
+ cmd.add_modify = STA_MODE_MODIFY;
+ cmd.modify_mask = STA_MODIFY_KEY;
+ cmd.sta_id = sta_id;
+
+ status = ADD_STA_SUCCESS;
+ if (cmd_flags == CMD_SYNC)
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+ &cmd, &status);
+ else
+ ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
+ sizeof(cmd), &cmd);
+
+ switch (status) {
+ case ADD_STA_SUCCESS:
+ IWL_DEBUG_WEP(mvm, "MODIFY_STA: set dynamic key passed\n");
+ break;
+ default:
+ ret = -EIO;
+ IWL_ERR(mvm, "MODIFY_STA: set dynamic key failed\n");
+ break;
+ }
+
+ return ret;
+}
+
+static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id, bool remove_key)
+{
+ struct iwl_mvm_mgmt_mcast_key_cmd igtk_cmd = {};
+
+ /* verify the key details match the required command's expectations */
+ if (WARN_ON((keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC) ||
+ (keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
+ (keyconf->keyidx != 4 && keyconf->keyidx != 5)))
+ return -EINVAL;
+
+ igtk_cmd.key_id = cpu_to_le32(keyconf->keyidx);
+ igtk_cmd.sta_id = cpu_to_le32(sta_id);
+
+ if (remove_key) {
+ igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID);
+ } else {
+ struct ieee80211_key_seq seq;
+ const u8 *pn;
+
+ memcpy(igtk_cmd.IGTK, keyconf->key, keyconf->keylen);
+ ieee80211_aes_cmac_calculate_k1_k2(keyconf,
+ igtk_cmd.K1, igtk_cmd.K2);
+ ieee80211_get_key_rx_seq(keyconf, 0, &seq);
+ pn = seq.aes_cmac.pn;
+ igtk_cmd.receive_seq_cnt = cpu_to_le64(((u64) pn[5] << 0) |
+ ((u64) pn[4] << 8) |
+ ((u64) pn[3] << 16) |
+ ((u64) pn[2] << 24) |
+ ((u64) pn[1] << 32) |
+ ((u64) pn[0] << 40));
+ }
+
+ IWL_DEBUG_INFO(mvm, "%s igtk for sta %u\n",
+ remove_key ? "removing" : "installing",
+ igtk_cmd.sta_id);
+
+ return iwl_mvm_send_cmd_pdu(mvm, MGMT_MCAST_KEY, CMD_SYNC,
+ sizeof(igtk_cmd), &igtk_cmd);
+}
+
+
+static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+
+ if (sta)
+ return sta->addr;
+
+ if (vif->type == NL80211_IFTYPE_STATION &&
+ mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+ u8 sta_id = mvmvif->ap_sta_id;
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+ return sta->addr;
+ }
+
+
+ return NULL;
+}
+
+int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *keyconf,
+ bool have_key_offset)
+{
+ struct iwl_mvm_sta *mvm_sta;
+ int ret;
+ u8 *addr, sta_id;
+ struct ieee80211_key_seq seq;
+ u16 p1k[5];
+
+ lockdep_assert_held(&mvm->mutex);
+
+ /* Get the station id from the mvm local station table */
+ sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_ERR(mvm, "Failed to find station id\n");
+ return -EINVAL;
+ }
+
+ if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false);
+ goto end;
+ }
+
+ /*
+ * It is possible that the 'sta' parameter is NULL, and thus
+ * there is a need to retrieve the sta from the local station table.
+ */
+ if (!sta) {
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+ if (IS_ERR_OR_NULL(sta)) {
+ IWL_ERR(mvm, "Invalid station id\n");
+ return -EINVAL;
+ }
+ }
+
+ mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv;
+ if (WARN_ON_ONCE(mvm_sta->vif != vif))
+ return -EINVAL;
+
+ if (!have_key_offset) {
+ /*
+ * The D3 firmware hardcodes the PTK offset to 0, so we have to
+ * configure it there. As a result, this workaround exists to
+ * let the caller set the key offset (hw_key_idx), see d3.c.
+ */
+ keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm);
+ if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)
+ return -ENOSPC;
+ }
+
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_TKIP:
+ addr = iwl_mvm_get_mac_addr(mvm, vif, sta);
+ /* get phase 1 key from mac80211 */
+ ieee80211_get_key_rx_seq(keyconf, 0, &seq);
+ ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
+ ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id,
+ seq.tkip.iv32, p1k, CMD_SYNC);
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id,
+ 0, NULL, CMD_SYNC);
+ break;
+ default:
+ IWL_ERR(mvm, "Unknown cipher %x\n", keyconf->cipher);
+ ret = -EINVAL;
+ }
+
+ if (ret)
+ __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
+
+end:
+ IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
+ keyconf->cipher, keyconf->keylen, keyconf->keyidx,
+ sta->addr, ret);
+ return ret;
+}
+
+int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *keyconf)
+{
+ struct iwl_mvm_sta *mvm_sta;
+ struct iwl_mvm_add_sta_cmd cmd = {};
+ __le16 key_flags;
+ int ret, status;
+ u8 sta_id;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ /* Get the station id from the mvm local station table */
+ sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+
+ IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
+ keyconf->keyidx, sta_id);
+
+ if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+ return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true);
+
+ ret = __test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
+ if (!ret) {
+ IWL_ERR(mvm, "offset %d not used in fw key table.\n",
+ keyconf->hw_key_idx);
+ return -ENOENT;
+ }
+
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n");
+ return 0;
+ }
+
+ /*
+ * It is possible that the 'sta' parameter is NULL, and thus
+ * there is a need to retrieve the sta from the local station table,
+ * for example when a GTK is removed (where the sta_id will then be
+ * the AP ID, and no station was passed by mac80211.)
+ */
+ if (!sta) {
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+ if (!sta) {
+ IWL_ERR(mvm, "Invalid station id\n");
+ return -EINVAL;
+ }
+ }
+
+ mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv;
+ if (WARN_ON_ONCE(mvm_sta->vif != vif))
+ return -EINVAL;
+
+ key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
+ STA_KEY_FLG_KEYID_MSK);
+ key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP);
+ key_flags |= cpu_to_le16(STA_KEY_NOT_VALID);
+
+ if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
+
+ cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
+ cmd.key.key_flags = key_flags;
+ cmd.key.key_offset = keyconf->hw_key_idx;
+ cmd.sta_id = sta_id;
+
+ cmd.modify_mask = STA_MODIFY_KEY;
+ cmd.add_modify = STA_MODE_MODIFY;
+
+ status = ADD_STA_SUCCESS;
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+ &cmd, &status);
+
+ switch (status) {
+ case ADD_STA_SUCCESS:
+ IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n");
+ break;
+ default:
+ ret = -EIO;
+ IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n");
+ break;
+ }
+
+ return ret;
+}
+
+void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *keyconf,
+ struct ieee80211_sta *sta, u32 iv32,
+ u16 *phase1key)
+{
+ struct iwl_mvm_sta *mvm_sta;
+ u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+
+ if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
+ return;
+
+ rcu_read_lock();
+
+ if (!sta) {
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+ if (WARN_ON(IS_ERR_OR_NULL(sta))) {
+ rcu_read_unlock();
+ return;
+ }
+ }
+
+ mvm_sta = (void *)sta->drv_priv;
+ iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id,
+ iv32, phase1key, CMD_ASYNC);
+ rcu_read_unlock();
+}
+
+void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+ struct iwl_mvm_add_sta_cmd cmd = {
+ .add_modify = STA_MODE_MODIFY,
+ .sta_id = mvmsta->sta_id,
+ .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
+ .sleep_state_flags = cpu_to_le16(STA_SLEEP_STATE_AWAKE),
+ .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
+ };
+ int ret;
+
+ /*
+ * Same modify mask for sleep_tx_count and sleep_state_flags but this
+ * should be fine since if we set the STA as "awake", then
+ * sleep_tx_count is not relevant.
+ */
+ ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
+ if (ret)
+ IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
+}
+
+void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ enum ieee80211_frame_release_type reason,
+ u16 cnt)
+{
+ u16 sleep_state_flags =
+ (reason == IEEE80211_FRAME_RELEASE_UAPSD) ?
+ STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL;
+ struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+ struct iwl_mvm_add_sta_cmd cmd = {
+ .add_modify = STA_MODE_MODIFY,
+ .sta_id = mvmsta->sta_id,
+ .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
+ .sleep_tx_count = cpu_to_le16(cnt),
+ .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
+ /*
+ * Same modify mask for sleep_tx_count and sleep_state_flags so
+ * we must set the sleep_state_flags too.
+ */
+ .sleep_state_flags = cpu_to_le16(sleep_state_flags),
+ };
+ int ret;
+
+ /* TODO: somehow the fw doesn't seem to take PS_POLL into account */
+ ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
+ if (ret)
+ IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
new file mode 100644
index 000000000000..896f88ac8145
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -0,0 +1,374 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 __sta_h__
+#define __sta_h__
+
+#include <linux/spinlock.h>
+#include <net/mac80211.h>
+#include <linux/wait.h>
+
+#include "iwl-trans.h" /* for IWL_MAX_TID_COUNT */
+#include "fw-api.h" /* IWL_MVM_STATION_COUNT */
+#include "rs.h"
+
+struct iwl_mvm;
+
+/**
+ * DOC: station table - introduction
+ *
+ * The station table is a list of data structure that reprensent the stations.
+ * In STA/P2P client mode, the driver will hold one station for the AP/ GO.
+ * In GO/AP mode, the driver will have as many stations as associated clients.
+ * All these stations are reflected in the fw's station table. The driver
+ * keeps the fw's station table up to date with the ADD_STA command. Stations
+ * can be removed by the REMOVE_STA command.
+ *
+ * All the data related to a station is held in the structure %iwl_mvm_sta
+ * which is embed in the mac80211's %ieee80211_sta (in the drv_priv) area.
+ * This data includes the index of the station in the fw, per tid information
+ * (sequence numbers, Block-ack state machine, etc...). The stations are
+ * created and deleted by the %sta_state callback from %ieee80211_ops.
+ *
+ * The driver holds a map: %fw_id_to_mac_id that allows to fetch a
+ * %ieee80211_sta (and the %iwl_mvm_sta embedded into it) based on a fw
+ * station index. That way, the driver is able to get the tid related data in
+ * O(1) in time sensitive paths (Tx / Tx response / BA notification). These
+ * paths are triggered by the fw, and the driver needs to get a pointer to the
+ * %ieee80211 structure. This map helps to get that pointer quickly.
+ */
+
+/**
+ * DOC: station table - locking
+ *
+ * As stated before, the station is created / deleted by mac80211's %sta_state
+ * callback from %ieee80211_ops which can sleep. The next paragraph explains
+ * the locking of a single stations, the next ones relates to the station
+ * table.
+ *
+ * The station holds the sequence number per tid. So this data needs to be
+ * accessed in the Tx path (which is softIRQ). It also holds the Block-Ack
+ * information (the state machine / and the logic that checks if the queues
+ * were drained), so it also needs to be accessible from the Tx response flow.
+ * In short, the station needs to be access from sleepable context as well as
+ * from tasklets, so the station itself needs a spinlock.
+ *
+ * The writers of %fw_id_to_mac_id map are serialized by the global mutex of
+ * the mvm op_mode. This is possible since %sta_state can sleep.
+ * The pointers in this map are RCU protected, hence we won't replace the
+ * station while we have Tx / Tx response / BA notification running.
+ *
+ * If a station is deleted while it still has packets in its A-MPDU queues,
+ * then the reclaim flow will notice that there is no station in the map for
+ * sta_id and it will dump the responses.
+ */
+
+/**
+ * DOC: station table - internal stations
+ *
+ * The FW needs a few internal stations that are not reflected in
+ * mac80211, such as broadcast station in AP / GO mode, or AUX sta for
+ * scanning and P2P device (during the GO negotiation).
+ * For these kind of stations we have %iwl_mvm_int_sta struct which holds the
+ * data relevant for them from both %iwl_mvm_sta and %ieee80211_sta.
+ * Usually the data for these stations is static, so no locking is required,
+ * and no TID data as this is also not needed.
+ * One thing to note, is that these stations have an ID in the fw, but not
+ * in mac80211. In order to "reserve" them a sta_id in %fw_id_to_mac_id
+ * we fill ERR_PTR(EINVAL) in this mapping and all other dereferencing of
+ * pointers from this mapping need to check that the value is not error
+ * or NULL.
+ *
+ * Currently there is only one auxiliary station for scanning, initialized
+ * on init.
+ */
+
+/**
+ * DOC: station table - AP Station in STA mode
+ *
+ * %iwl_mvm_vif includes the index of the AP station in the fw's STA table:
+ * %ap_sta_id. To get the point to the coresponsding %ieee80211_sta,
+ * &fw_id_to_mac_id can be used. Due to the way the fw works, we must not remove
+ * the AP station from the fw before setting the MAC context as unassociated.
+ * Hence, %fw_id_to_mac_id[%ap_sta_id] will be NULLed when the AP station is
+ * removed by mac80211, but the station won't be removed in the fw until the
+ * VIF is set as unassociated. Then, %ap_sta_id will be invalidated.
+ */
+
+/**
+ * DOC: station table - Drain vs. Flush
+ *
+ * Flush means that all the frames in the SCD queue are dumped regardless the
+ * station to which they were sent. We do that when we disassociate and before
+ * we remove the STA of the AP. The flush can be done synchronously against the
+ * fw.
+ * Drain means that the fw will drop all the frames sent to a specific station.
+ * This is useful when a client (if we are IBSS / GO or AP) disassociates. In
+ * that case, we need to drain all the frames for that client from the AC queues
+ * that are shared with the other clients. Only then, we can remove the STA in
+ * the fw. In order to do so, we track the non-AMPDU packets for each station.
+ * If mac80211 removes a STA and if it still has non-AMPDU packets pending in
+ * the queues, we mark this station as %EBUSY in %fw_id_to_mac_id, and drop all
+ * the frames for this STA (%iwl_mvm_rm_sta). When the last frame is dropped
+ * (we know about it with its Tx response), we remove the station in fw and set
+ * it as %NULL in %fw_id_to_mac_id: this is the purpose of
+ * %iwl_mvm_sta_drained_wk.
+ */
+
+/**
+ * DOC: station table - fw restart
+ *
+ * When the fw asserts, or we have any other issue that requires to reset the
+ * driver, we require mac80211 to reconfigure the driver. Since the private
+ * data of the stations is embed in mac80211's %ieee80211_sta, that data will
+ * not be zeroed and needs to be reinitialized manually.
+ * %IWL_MVM_STATUS_IN_HW_RESTART is set during restart and that will hint us
+ * that we must not allocate a new sta_id but reuse the previous one. This
+ * means that the stations being re-added after the reset will have the same
+ * place in the fw as before the reset. We do need to zero the %fw_id_to_mac_id
+ * map, since the stations aren't in the fw any more. Internal stations that
+ * are not added by mac80211 will be re-added in the init flow that is called
+ * after the restart: mac80211 call's %iwl_mvm_mac_start which calls to
+ * %iwl_mvm_up.
+ */
+
+/**
+ * DOC: AP mode - PS
+ *
+ * When a station is asleep, the fw will set it as "asleep". All the
+ * non-aggregation frames to that station will be dropped by the fw
+ * (%TX_STATUS_FAIL_DEST_PS failure code).
+ * AMPDUs are in a separate queue that is stopped by the fw. We just need to
+ * let mac80211 know how many frames we have in these queues so that it can
+ * properly handle trigger frames.
+ * When the a trigger frame is received, mac80211 tells the driver to send
+ * frames from the AMPDU queues or AC queue depending on which queue are
+ * delivery-enabled and what TID has frames to transmit (Note that mac80211 has
+ * all the knowledege since all the non-agg frames are buffered / filtered, and
+ * the driver tells mac80211 about agg frames). The driver needs to tell the fw
+ * to let frames out even if the station is asleep. This is done by
+ * %iwl_mvm_sta_modify_sleep_tx_count.
+ * When we receive a frame from that station with PM bit unset, the
+ * driver needs to let the fw know that this station isn't alseep any more.
+ * This is done by %iwl_mvm_sta_modify_ps_wake.
+ *
+ * TODO - EOSP handling
+ */
+
+/**
+ * enum iwl_mvm_agg_state
+ *
+ * The state machine of the BA agreement establishment / tear down.
+ * These states relate to a specific RA / TID.
+ *
+ * @IWL_AGG_OFF: aggregation is not used
+ * @IWL_AGG_STARTING: aggregation are starting (between start and oper)
+ * @IWL_AGG_ON: aggregation session is up
+ * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the
+ * HW queue to be empty from packets for this RA /TID.
+ * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the
+ * HW queue to be empty from packets for this RA /TID.
+ */
+enum iwl_mvm_agg_state {
+ IWL_AGG_OFF = 0,
+ IWL_AGG_STARTING,
+ IWL_AGG_ON,
+ IWL_EMPTYING_HW_QUEUE_ADDBA,
+ IWL_EMPTYING_HW_QUEUE_DELBA,
+};
+
+/**
+ * struct iwl_mvm_tid_data - holds the states for each RA / TID
+ * @seq_number: the next WiFi sequence number to use
+ * @next_reclaimed: the WiFi sequence number of the next packet to be acked.
+ * This is basically (last acked packet++).
+ * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the
+ * Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA).
+ * @state: state of the BA agreement establishment / tear down.
+ * @txq_id: Tx queue used by the BA session
+ * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or
+ * the first packet to be sent in legacy HW queue in Tx AGG stop flow.
+ * Basically when next_reclaimed reaches ssn, we can tell mac80211 that
+ * we are ready to finish the Tx AGG stop / start flow.
+ * @wait_for_ba: Expect block-ack before next Tx reply
+ */
+struct iwl_mvm_tid_data {
+ u16 seq_number;
+ u16 next_reclaimed;
+ /* The rest is Tx AGG related */
+ u32 rate_n_flags;
+ enum iwl_mvm_agg_state state;
+ u16 txq_id;
+ u16 ssn;
+ bool wait_for_ba;
+};
+
+/**
+ * struct iwl_mvm_sta - representation of a station in the driver
+ * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
+ * @tfd_queue_msk: the tfd queues used by the station
+ * @mac_id_n_color: the MAC context this station is linked to
+ * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
+ * tid.
+ * @max_agg_bufsize: the maximal size of the AGG buffer for this station
+ * @lock: lock to protect the whole struct. Since %tid_data is access from Tx
+ * and from Tx response flow, it needs a spinlock.
+ * @pending_frames: number of frames for this STA on the shared Tx queues.
+ * @tid_data: per tid data. Look at %iwl_mvm_tid_data.
+ *
+ * When mac80211 creates a station it reserves some space (hw->sta_data_size)
+ * in the structure for use by driver. This structure is placed in that
+ * space.
+ *
+ */
+struct iwl_mvm_sta {
+ u32 sta_id;
+ u32 tfd_queue_msk;
+ u32 mac_id_n_color;
+ u16 tid_disable_agg;
+ u8 max_agg_bufsize;
+ spinlock_t lock;
+ atomic_t pending_frames;
+ struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
+ struct iwl_lq_sta lq_sta;
+ struct ieee80211_vif *vif;
+
+#ifdef CONFIG_PM_SLEEP
+ u16 last_seq_ctl;
+#endif
+};
+
+/**
+ * struct iwl_mvm_int_sta - representation of an internal station (auxiliary or
+ * broadcast)
+ * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
+ * @tfd_queue_msk: the tfd queues used by the station
+ */
+struct iwl_mvm_int_sta {
+ u32 sta_id;
+ u32 tfd_queue_msk;
+};
+
+int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ bool update);
+int iwl_mvm_add_sta(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+int iwl_mvm_update_sta(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u8 sta_id);
+int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ bool have_key_offset);
+int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *keyconf);
+
+void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *keyconf,
+ struct ieee80211_sta *sta, u32 iv32,
+ u16 *phase1key);
+
+/* AMPDU */
+int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ int tid, u16 ssn, bool start);
+int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid, u8 buf_size);
+int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid);
+
+int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
+int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
+ u32 qmask);
+void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
+ struct iwl_mvm_int_sta *sta);
+int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_mvm_int_sta *bsta);
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
+ struct iwl_mvm_int_sta *bsta);
+int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_mvm_int_sta *bsta);
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta);
+void iwl_mvm_sta_drained_wk(struct work_struct *wk);
+void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta);
+void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ enum ieee80211_frame_release_type reason,
+ u16 cnt);
+int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
+ bool drain);
+
+#endif /* __sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
new file mode 100644
index 000000000000..e437e02c7149
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -0,0 +1,519 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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/jiffies.h>
+#include <net/mac80211.h>
+
+#include "iwl-notif-wait.h"
+#include "iwl-trans.h"
+#include "fw-api.h"
+#include "time-event.h"
+#include "mvm.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+
+/* A TimeUnit is 1024 microsecond */
+#define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024))
+#define MSEC_TO_TU(_msec) (_msec*1000/1024)
+
+/* For ROC use a TE type which has priority high enough to be scheduled when
+ * there is a concurrent BSS or GO/AP. Currently, use a TE type that has
+ * priority similar to the TE priority used for action scans by the FW.
+ * TODO: This needs to be changed, based on the reason for the ROC, i.e., use
+ * TE_P2P_DEVICE_DISCOVERABLE for remain on channel without mgmt skb, and use
+ * TE_P2P_DEVICE_ACTION_SCAN
+ */
+#define IWL_MVM_ROC_TE_TYPE TE_P2P_DEVICE_ACTION_SCAN
+
+void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
+ struct iwl_mvm_time_event_data *te_data)
+{
+ lockdep_assert_held(&mvm->time_event_lock);
+
+ if (te_data->id == TE_MAX)
+ return;
+
+ list_del(&te_data->list);
+ te_data->running = false;
+ te_data->uid = 0;
+ te_data->id = TE_MAX;
+ te_data->vif = NULL;
+}
+
+void iwl_mvm_roc_done_wk(struct work_struct *wk)
+{
+ struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk);
+
+ synchronize_net();
+
+ /*
+ * Flush the offchannel queue -- this is called when the time
+ * event finishes or is cancelled, so that frames queued for it
+ * won't get stuck on the queue and be transmitted in the next
+ * time event.
+ * We have to send the command asynchronously since this cannot
+ * be under the mutex for locking reasons, but that's not an
+ * issue as it will have to complete before the next command is
+ * executed, and a new time event means a new command.
+ */
+ iwl_mvm_flush_tx_path(mvm, BIT(IWL_OFFCHANNEL_QUEUE), false);
+}
+
+static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
+{
+ /*
+ * First, clear the ROC_RUNNING status bit. This will cause the TX
+ * path to drop offchannel transmissions. That would also be done
+ * by mac80211, but it is racy, in particular in the case that the
+ * time event actually completed in the firmware (which is handled
+ * in iwl_mvm_te_handle_notif).
+ */
+ clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
+
+ /*
+ * Of course, our status bit is just as racy as mac80211, so in
+ * addition, fire off the work struct which will drop all frames
+ * from the hardware queues that made it through the race. First
+ * it will of course synchronize the TX path to make sure that
+ * any *new* TX will be rejected.
+ */
+ schedule_work(&mvm->roc_done_wk);
+}
+
+/*
+ * Handles a FW notification for an event that is known to the driver.
+ *
+ * @mvm: the mvm component
+ * @te_data: the time event data
+ * @notif: the notification data corresponding the time event data.
+ */
+static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
+ struct iwl_mvm_time_event_data *te_data,
+ struct iwl_time_event_notif *notif)
+{
+ lockdep_assert_held(&mvm->time_event_lock);
+
+ IWL_DEBUG_TE(mvm, "Handle time event notif - UID = 0x%x action %d\n",
+ le32_to_cpu(notif->unique_id),
+ le32_to_cpu(notif->action));
+
+ /*
+ * The FW sends the start/end time event notifications even for events
+ * that it fails to schedule. This is indicated in the status field of
+ * the notification. This happens in cases that the scheduler cannot
+ * find a schedule that can handle the event (for example requesting a
+ * P2P Device discoveribility, while there are other higher priority
+ * events in the system).
+ */
+ WARN_ONCE(!le32_to_cpu(notif->status),
+ "Failed to schedule time event\n");
+
+ if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_END) {
+ IWL_DEBUG_TE(mvm,
+ "TE ended - current time %lu, estimated end %lu\n",
+ jiffies, te_data->end_jiffies);
+
+ if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ ieee80211_remain_on_channel_expired(mvm->hw);
+ iwl_mvm_roc_finished(mvm);
+ }
+
+ /*
+ * By now, we should have finished association
+ * and know the dtim period.
+ */
+ if (te_data->vif->type == NL80211_IFTYPE_STATION &&
+ (!te_data->vif->bss_conf.assoc ||
+ !te_data->vif->bss_conf.dtim_period)) {
+ IWL_ERR(mvm,
+ "No assocation and the time event is over already...\n");
+ ieee80211_connection_loss(te_data->vif);
+ }
+
+ iwl_mvm_te_clear_data(mvm, te_data);
+ } else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) {
+ te_data->running = true;
+ te_data->end_jiffies = jiffies +
+ TU_TO_JIFFIES(te_data->duration);
+
+ if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
+ ieee80211_ready_on_channel(mvm->hw);
+ }
+ } else {
+ IWL_WARN(mvm, "Got TE with unknown action\n");
+ }
+}
+
+/*
+ * The Rx handler for time event notifications
+ */
+int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_time_event_notif *notif = (void *)pkt->data;
+ struct iwl_mvm_time_event_data *te_data, *tmp;
+
+ IWL_DEBUG_TE(mvm, "Time event notification - UID = 0x%x action %d\n",
+ le32_to_cpu(notif->unique_id),
+ le32_to_cpu(notif->action));
+
+ spin_lock_bh(&mvm->time_event_lock);
+ list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) {
+ if (le32_to_cpu(notif->unique_id) == te_data->uid)
+ iwl_mvm_te_handle_notif(mvm, te_data, notif);
+ }
+ spin_unlock_bh(&mvm->time_event_lock);
+
+ return 0;
+}
+
+static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
+ struct iwl_rx_packet *pkt, void *data)
+{
+ struct iwl_mvm *mvm =
+ container_of(notif_wait, struct iwl_mvm, notif_wait);
+ struct iwl_mvm_time_event_data *te_data = data;
+ struct iwl_time_event_resp *resp;
+ int resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+
+ if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_CMD))
+ return true;
+
+ if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) {
+ IWL_ERR(mvm, "Invalid TIME_EVENT_CMD response\n");
+ return true;
+ }
+
+ resp = (void *)pkt->data;
+
+ /* we should never get a response to another TIME_EVENT_CMD here */
+ if (WARN_ON_ONCE(le32_to_cpu(resp->id) != te_data->id))
+ return false;
+
+ te_data->uid = le32_to_cpu(resp->unique_id);
+ IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",
+ te_data->uid);
+ return true;
+}
+
+static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_mvm_time_event_data *te_data,
+ struct iwl_time_event_cmd *te_cmd)
+{
+ static const u8 time_event_response[] = { TIME_EVENT_CMD };
+ struct iwl_notification_wait wait_time_event;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ IWL_DEBUG_TE(mvm, "Add new TE, duration %d TU\n",
+ le32_to_cpu(te_cmd->duration));
+
+ spin_lock_bh(&mvm->time_event_lock);
+ if (WARN_ON(te_data->id != TE_MAX)) {
+ spin_unlock_bh(&mvm->time_event_lock);
+ return -EIO;
+ }
+ te_data->vif = vif;
+ te_data->duration = le32_to_cpu(te_cmd->duration);
+ te_data->id = le32_to_cpu(te_cmd->id);
+ list_add_tail(&te_data->list, &mvm->time_event_list);
+ spin_unlock_bh(&mvm->time_event_lock);
+
+ /*
+ * Use a notification wait, which really just processes the
+ * command response and doesn't wait for anything, in order
+ * to be able to process the response and get the UID inside
+ * the RX path. Using CMD_WANT_SKB doesn't work because it
+ * stores the buffer and then wakes up this thread, by which
+ * time another notification (that the time event started)
+ * might already be processed unsuccessfully.
+ */
+ iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
+ time_event_response,
+ ARRAY_SIZE(time_event_response),
+ iwl_mvm_time_event_response, te_data);
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
+ sizeof(*te_cmd), te_cmd);
+ if (ret) {
+ IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret);
+ iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
+ goto out_clear_te;
+ }
+
+ /* No need to wait for anything, so just pass 1 (0 isn't valid) */
+ ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1);
+ /* should never fail */
+ WARN_ON_ONCE(ret);
+
+ if (ret) {
+ out_clear_te:
+ spin_lock_bh(&mvm->time_event_lock);
+ iwl_mvm_te_clear_data(mvm, te_data);
+ spin_unlock_bh(&mvm->time_event_lock);
+ }
+ return ret;
+}
+
+void iwl_mvm_protect_session(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 duration, u32 min_duration)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
+ struct iwl_time_event_cmd time_cmd = {};
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (te_data->running &&
+ time_after(te_data->end_jiffies,
+ jiffies + TU_TO_JIFFIES(min_duration))) {
+ IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n",
+ jiffies_to_msecs(te_data->end_jiffies - jiffies));
+ return;
+ }
+
+ if (te_data->running) {
+ IWL_DEBUG_TE(mvm, "extend 0x%x: only %u ms left\n",
+ te_data->uid,
+ jiffies_to_msecs(te_data->end_jiffies - jiffies));
+ /*
+ * we don't have enough time
+ * cancel the current TE and issue a new one
+ * Of course it would be better to remove the old one only
+ * when the new one is added, but we don't care if we are off
+ * channel for a bit. All we need to do, is not to return
+ * before we actually begin to be on the channel.
+ */
+ iwl_mvm_stop_session_protection(mvm, vif);
+ }
+
+ time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
+ time_cmd.id_and_color =
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
+ time_cmd.id = cpu_to_le32(TE_BSS_STA_AGGRESSIVE_ASSOC);
+
+ time_cmd.apply_time =
+ cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG));
+
+ time_cmd.dep_policy = TE_INDEPENDENT;
+ time_cmd.is_present = cpu_to_le32(1);
+ time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE);
+ time_cmd.max_delay = cpu_to_le32(500);
+ /* TODO: why do we need to interval = bi if it is not periodic? */
+ time_cmd.interval = cpu_to_le32(1);
+ time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1));
+ time_cmd.duration = cpu_to_le32(duration);
+ time_cmd.repeat = cpu_to_le32(1);
+ time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END);
+
+ iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
+}
+
+/*
+ * Explicit request to remove a time event. The removal of a time event needs to
+ * be synchronized with the flow of a time event's end notification, which also
+ * removes the time event from the op mode data structures.
+ */
+void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
+ struct iwl_mvm_vif *mvmvif,
+ struct iwl_mvm_time_event_data *te_data)
+{
+ struct iwl_time_event_cmd time_cmd = {};
+ u32 id, uid;
+ int ret;
+
+ /*
+ * It is possible that by the time we got to this point the time
+ * event was already removed.
+ */
+ spin_lock_bh(&mvm->time_event_lock);
+
+ /* Save time event uid before clearing its data */
+ uid = te_data->uid;
+ id = te_data->id;
+
+ /*
+ * The clear_data function handles time events that were already removed
+ */
+ iwl_mvm_te_clear_data(mvm, te_data);
+ spin_unlock_bh(&mvm->time_event_lock);
+
+ /*
+ * It is possible that by the time we try to remove it, the time event
+ * has already ended and removed. In such a case there is no need to
+ * send a removal command.
+ */
+ if (id == TE_MAX) {
+ IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", uid);
+ return;
+ }
+
+ /* When we remove a TE, the UID is to be set in the id field */
+ time_cmd.id = cpu_to_le32(uid);
+ time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
+ time_cmd.id_and_color =
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
+
+ IWL_DEBUG_TE(mvm, "Removing TE 0x%x\n", le32_to_cpu(time_cmd.id));
+ ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC,
+ sizeof(time_cmd), &time_cmd);
+ if (WARN_ON(ret))
+ return;
+}
+
+void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
+
+ lockdep_assert_held(&mvm->mutex);
+ iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
+}
+
+int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ int duration)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
+ struct iwl_time_event_cmd time_cmd = {};
+
+ lockdep_assert_held(&mvm->mutex);
+ if (te_data->running) {
+ IWL_WARN(mvm, "P2P_DEVICE remain on channel already running\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Flush the done work, just in case it's still pending, so that
+ * the work it does can complete and we can accept new frames.
+ */
+ flush_work(&mvm->roc_done_wk);
+
+ time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
+ time_cmd.id_and_color =
+ cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
+ time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE);
+
+ time_cmd.apply_time = cpu_to_le32(0);
+ time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT);
+ time_cmd.is_present = cpu_to_le32(1);
+
+ time_cmd.interval = cpu_to_le32(1);
+
+ /*
+ * IWL_MVM_ROC_TE_TYPE can have lower priority than other events
+ * that are being scheduled by the driver/fw, and thus it might not be
+ * scheduled. To improve the chances of it being scheduled, allow it to
+ * be fragmented.
+ * In addition, for the same reasons, allow to delay the scheduling of
+ * the time event.
+ */
+ time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20);
+ time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2));
+ time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
+ time_cmd.repeat = cpu_to_le32(1);
+ time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END);
+
+ return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
+}
+
+void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm)
+{
+ struct iwl_mvm_vif *mvmvif;
+ struct iwl_mvm_time_event_data *te_data;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ /*
+ * Iterate over the list of time events and find the time event that is
+ * associated with a P2P_DEVICE interface.
+ * This assumes that a P2P_DEVICE interface can have only a single time
+ * event at any given time and this time event coresponds to a ROC
+ * request
+ */
+ mvmvif = NULL;
+ spin_lock_bh(&mvm->time_event_lock);
+ list_for_each_entry(te_data, &mvm->time_event_list, list) {
+ if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+ break;
+ }
+ }
+ spin_unlock_bh(&mvm->time_event_lock);
+
+ if (!mvmvif) {
+ IWL_WARN(mvm, "P2P_DEVICE no remain on channel event\n");
+ return;
+ }
+
+ iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
+
+ iwl_mvm_roc_finished(mvm);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h
new file mode 100644
index 000000000000..64fb57a5ab43
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h
@@ -0,0 +1,214 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 __time_event_h__
+#define __time_event_h__
+
+#include "fw-api.h"
+
+#include "mvm.h"
+
+/**
+ * DOC: Time Events - what is it?
+ *
+ * Time Events are a fw feature that allows the driver to control the presence
+ * of the device on the channel. Since the fw supports multiple channels
+ * concurrently, the fw may choose to jump to another channel at any time.
+ * In order to make sure that the fw is on a specific channel at a certain time
+ * and for a certain duration, the driver needs to issue a time event.
+ *
+ * The simplest example is for BSS association. The driver issues a time event,
+ * waits for it to start, and only then tells mac80211 that we can start the
+ * association. This way, we make sure that the association will be done
+ * smoothly and won't be interrupted by channel switch decided within the fw.
+ */
+
+ /**
+ * DOC: The flow against the fw
+ *
+ * When the driver needs to make sure we are in a certain channel, at a certain
+ * time and for a certain duration, it sends a Time Event. The flow against the
+ * fw goes like this:
+ * 1) Driver sends a TIME_EVENT_CMD to the fw
+ * 2) Driver gets the response for that command. This response contains the
+ * Unique ID (UID) of the event.
+ * 3) The fw sends notification when the event starts.
+ *
+ * Of course the API provides various options that allow to cover parameters
+ * of the flow.
+ * What is the duration of the event?
+ * What is the start time of the event?
+ * Is there an end-time for the event?
+ * How much can the event be delayed?
+ * Can the event be split?
+ * If yes what is the maximal number of chunks?
+ * etc...
+ */
+
+/**
+ * DOC: Abstraction to the driver
+ *
+ * In order to simplify the use of time events to the rest of the driver,
+ * we abstract the use of time events. This component provides the functions
+ * needed by the driver.
+ */
+
+#define IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS 500
+#define IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS 400
+
+/**
+ * iwl_mvm_protect_session - start / extend the session protection.
+ * @mvm: the mvm component
+ * @vif: the virtual interface for which the session is issued
+ * @duration: the duration of the session in TU.
+ * @min_duration: will start a new session if the current session will end
+ * in less than min_duration.
+ *
+ * This function can be used to start a session protection which means that the
+ * fw will stay on the channel for %duration_ms milliseconds. This function
+ * will block (sleep) until the session starts. This function can also be used
+ * to extend a currently running session.
+ * This function is meant to be used for BSS association for example, where we
+ * want to make sure that the fw stays on the channel during the association.
+ */
+void iwl_mvm_protect_session(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 duration, u32 min_duration);
+
+/**
+ * iwl_mvm_stop_session_protection - cancel the session protection.
+ * @mvm: the mvm component
+ * @vif: the virtual interface for which the session is issued
+ *
+ * This functions cancels the session protection which is an act of good
+ * citizenship. If it is not needed any more it should be cancelled because
+ * the other bindings wait for the medium during that time.
+ * This funtions doesn't sleep.
+ */
+void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif);
+
+/*
+ * iwl_mvm_rx_time_event_notif - handles %TIME_EVENT_NOTIFICATION.
+ */
+int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+
+/**
+ * iwl_mvm_start_p2p_roc - start remain on channel for p2p device functionlity
+ * @mvm: the mvm component
+ * @vif: the virtual interface for which the roc is requested. It is assumed
+ * that the vif type is NL80211_IFTYPE_P2P_DEVICE
+ * @duration: the requested duration in millisecond for the fw to be on the
+ * channel that is bound to the vif.
+ *
+ * This function can be used to issue a remain on channel session,
+ * which means that the fw will stay in the channel for the request %duration
+ * milliseconds. The function is async, meaning that it only issues the ROC
+ * request but does not wait for it to start. Once the FW is ready to serve the
+ * ROC request, it will issue a notification to the driver that it is on the
+ * requested channel. Once the FW completes the ROC request it will issue
+ * another notification to the driver.
+ */
+int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ int duration);
+
+/**
+ * iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity
+ * @mvm: the mvm component
+ *
+ * This function can be used to cancel an ongoing ROC session.
+ * The function is async, it will instruct the FW to stop serving the ROC
+ * session, but will not wait for the actual stopping of the session.
+ */
+void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm);
+
+/**
+ * iwl_mvm_remove_time_event - general function to clean up of time event
+ * @mvm: the mvm component
+ * @vif: the vif to which the time event belongs
+ * @te_data: the time event data that corresponds to that time event
+ *
+ * This function can be used to cancel a time event regardless its type.
+ * It is useful for cleaning up time events running before removing an
+ * interface.
+ */
+void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
+ struct iwl_mvm_vif *mvmvif,
+ struct iwl_mvm_time_event_data *te_data);
+
+/**
+ * iwl_mvm_te_clear_data - remove time event from list
+ * @mvm: the mvm component
+ * @te_data: the time event data to remove
+ *
+ * This function is mostly internal, it is made available here only
+ * for firmware restart purposes.
+ */
+void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
+ struct iwl_mvm_time_event_data *te_data);
+
+void iwl_mvm_roc_done_wk(struct work_struct *wk);
+
+#endif /* __time_event_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
new file mode 100644
index 000000000000..6b67ce3f679c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -0,0 +1,916 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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/ieee80211.h>
+#include <linux/etherdevice.h>
+
+#include "iwl-trans.h"
+#include "iwl-eeprom-parse.h"
+#include "mvm.h"
+#include "sta.h"
+
+/*
+ * Sets most of the Tx cmd's fields
+ */
+static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
+ struct iwl_tx_cmd *tx_cmd,
+ struct ieee80211_tx_info *info, u8 sta_id)
+{
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ __le16 fc = hdr->frame_control;
+ u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags);
+ u32 len = skb->len + FCS_LEN;
+
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+ tx_flags |= TX_CMD_FLG_ACK;
+ else
+ tx_flags &= ~TX_CMD_FLG_ACK;
+
+ if (ieee80211_is_probe_resp(fc))
+ tx_flags |= TX_CMD_FLG_TSF;
+ else if (ieee80211_is_back_req(fc))
+ tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
+
+ /* High prio packet (wrt. BT coex) if it is EAPOL, MCAST or MGMT */
+ if (info->band == IEEE80211_BAND_2GHZ &&
+ (skb->protocol == cpu_to_be16(ETH_P_PAE) ||
+ is_multicast_ether_addr(hdr->addr1) ||
+ ieee80211_is_back_req(fc) ||
+ ieee80211_is_mgmt(fc)))
+ tx_flags |= TX_CMD_FLG_BT_DIS;
+
+ if (ieee80211_has_morefrags(fc))
+ tx_flags |= TX_CMD_FLG_MORE_FRAG;
+
+ if (ieee80211_is_data_qos(fc)) {
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+ tx_cmd->tid_tspec = qc[0] & 0xf;
+ tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
+ } else {
+ tx_cmd->tid_tspec = IWL_TID_NON_QOS;
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ tx_flags |= TX_CMD_FLG_SEQ_CTL;
+ else
+ tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
+ }
+
+ if (ieee80211_is_mgmt(fc)) {
+ if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
+ tx_cmd->pm_frame_timeout = cpu_to_le16(3);
+ else
+ tx_cmd->pm_frame_timeout = cpu_to_le16(2);
+
+ /* The spec allows Action frames in A-MPDU, we don't support
+ * it
+ */
+ WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU);
+ } else {
+ tx_cmd->pm_frame_timeout = 0;
+ }
+
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
+
+ if (ieee80211_is_data(fc) && len > mvm->rts_threshold &&
+ !is_multicast_ether_addr(ieee80211_get_DA(hdr)))
+ tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
+
+ tx_cmd->driver_txop = 0;
+ tx_cmd->tx_flags = cpu_to_le32(tx_flags);
+ /* Total # bytes to be transmitted */
+ tx_cmd->len = cpu_to_le16((u16)skb->len);
+ tx_cmd->next_frame_len = 0;
+ tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
+ tx_cmd->sta_id = sta_id;
+}
+
+/*
+ * Sets the fields in the Tx cmd that are rate related
+ */
+static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
+ struct iwl_tx_cmd *tx_cmd,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ __le16 fc)
+{
+ u32 rate_flags;
+ int rate_idx;
+ u8 rate_plcp;
+
+ /* Set retry limit on RTS packets */
+ tx_cmd->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT;
+
+ /* Set retry limit on DATA packets and Probe Responses*/
+ if (ieee80211_is_probe_resp(fc)) {
+ tx_cmd->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT;
+ tx_cmd->rts_retry_limit =
+ min(tx_cmd->data_retry_limit, tx_cmd->rts_retry_limit);
+ } else if (ieee80211_is_back_req(fc)) {
+ tx_cmd->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT;
+ } else {
+ tx_cmd->data_retry_limit = IWL_DEFAULT_TX_RETRY;
+ }
+
+ /*
+ * for data packets, rate info comes from the table inside he fw. This
+ * table is controlled by LINK_QUALITY commands
+ */
+
+ if (ieee80211_is_data(fc)) {
+ tx_cmd->initial_rate_index = 0;
+ tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
+ return;
+ } else if (ieee80211_is_back_req(fc)) {
+ tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
+ }
+
+ /* HT rate doesn't make sense for a non data frame */
+ WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS,
+ "Got an HT rate for a non data frame 0x%x\n",
+ info->control.rates[0].flags);
+
+ rate_idx = info->control.rates[0].idx;
+ /* if the rate isn't a well known legacy rate, take the lowest one */
+ if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT_LEGACY)
+ rate_idx = rate_lowest_index(
+ &mvm->nvm_data->bands[info->band], sta);
+
+ /* For 5 GHZ band, remap mac80211 rate indices into driver indices */
+ if (info->band == IEEE80211_BAND_5GHZ)
+ rate_idx += IWL_FIRST_OFDM_RATE;
+
+ /* For 2.4 GHZ band, check that there is no need to remap */
+ BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
+
+ /* Get PLCP rate for tx_cmd->rate_n_flags */
+ rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx);
+
+ mvm->mgmt_last_antenna_idx =
+ iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+ mvm->mgmt_last_antenna_idx);
+ rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
+
+ /* Set CCK flag as needed */
+ if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
+ rate_flags |= RATE_MCS_CCK_MSK;
+
+ /* Set the rate in the TX cmd */
+ tx_cmd->rate_n_flags = cpu_to_le32((u32)rate_plcp | rate_flags);
+}
+
+/*
+ * Sets the fields in the Tx cmd that are crypto related
+ */
+static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
+ struct ieee80211_tx_info *info,
+ struct iwl_tx_cmd *tx_cmd,
+ struct sk_buff *skb_frag)
+{
+ struct ieee80211_key_conf *keyconf = info->control.hw_key;
+
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
+ tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
+ memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG);
+ break;
+
+ case WLAN_CIPHER_SUITE_TKIP:
+ tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
+ ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
+ break;
+
+ case WLAN_CIPHER_SUITE_WEP104:
+ tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+ /* fall through */
+ case WLAN_CIPHER_SUITE_WEP40:
+ tx_cmd->sec_ctl |= TX_CMD_SEC_WEP |
+ ((keyconf->keyidx << TX_CMD_SEC_WEP_KEY_IDX_POS) &
+ TX_CMD_SEC_WEP_KEY_IDX_MSK);
+
+ memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
+ break;
+ default:
+ IWL_ERR(mvm, "Unknown encode cipher %x\n", keyconf->cipher);
+ break;
+ }
+}
+
+/*
+ * Allocates and sets the Tx cmd the driver data pointers in the skb
+ */
+static struct iwl_device_cmd *
+iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
+ struct ieee80211_sta *sta, u8 sta_id)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct iwl_device_cmd *dev_cmd;
+ struct iwl_tx_cmd *tx_cmd;
+
+ dev_cmd = iwl_trans_alloc_tx_cmd(mvm->trans);
+
+ if (unlikely(!dev_cmd))
+ return NULL;
+
+ memset(dev_cmd, 0, sizeof(*dev_cmd));
+ tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
+
+ if (info->control.hw_key)
+ iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb);
+
+ iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id);
+
+ iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control);
+
+ memset(&info->status, 0, sizeof(info->status));
+
+ info->driver_data[0] = NULL;
+ info->driver_data[1] = dev_cmd;
+
+ return dev_cmd;
+}
+
+int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct iwl_device_cmd *dev_cmd;
+ struct iwl_tx_cmd *tx_cmd;
+ u8 sta_id;
+
+ if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU))
+ return -1;
+
+ if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
+ (!info->control.vif ||
+ info->hw_queue != info->control.vif->cab_queue)))
+ return -1;
+
+ /*
+ * If the interface on which frame is sent is the P2P_DEVICE
+ * or an AP/GO interface use the broadcast station associated
+ * with it; otherwise use the AUX station.
+ */
+ if (info->control.vif &&
+ (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
+ info->control.vif->type == NL80211_IFTYPE_AP)) {
+ struct iwl_mvm_vif *mvmvif =
+ iwl_mvm_vif_from_mac80211(info->control.vif);
+ sta_id = mvmvif->bcast_sta.sta_id;
+ } else {
+ sta_id = mvm->aux_sta.sta_id;
+ }
+
+ IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue);
+
+ dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id);
+ if (!dev_cmd)
+ return -1;
+
+ /* From now on, we cannot access info->control */
+ tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
+
+ /* Copy MAC header from skb into command buffer */
+ memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control));
+
+ if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) {
+ iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Sets the fields in the Tx cmd that are crypto related
+ */
+int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
+ struct ieee80211_sta *sta)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct iwl_mvm_sta *mvmsta;
+ struct iwl_device_cmd *dev_cmd;
+ struct iwl_tx_cmd *tx_cmd;
+ __le16 fc;
+ u16 seq_number = 0;
+ u8 tid = IWL_MAX_TID_COUNT;
+ u8 txq_id = info->hw_queue;
+ bool is_data_qos = false, is_ampdu = false;
+
+ mvmsta = (void *)sta->drv_priv;
+ fc = hdr->frame_control;
+
+ if (WARN_ON_ONCE(!mvmsta))
+ return -1;
+
+ if (WARN_ON_ONCE(mvmsta->sta_id == IWL_INVALID_STATION))
+ return -1;
+
+ dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id);
+ if (!dev_cmd)
+ goto drop;
+
+ tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
+ /* From now on, we cannot access info->control */
+
+ spin_lock(&mvmsta->lock);
+
+ if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
+ u8 *qc = NULL;
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+ if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+ goto drop_unlock_sta;
+
+ seq_number = mvmsta->tid_data[tid].seq_number;
+ seq_number &= IEEE80211_SCTL_SEQ;
+ hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(seq_number);
+ seq_number += 0x10;
+ is_data_qos = true;
+ is_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU;
+ }
+
+ /* Copy MAC header from skb into command buffer */
+ memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(fc));
+
+ WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM);
+
+ if (is_ampdu) {
+ if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON))
+ goto drop_unlock_sta;
+ txq_id = mvmsta->tid_data[tid].txq_id;
+ }
+
+ IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x\n", mvmsta->sta_id,
+ tid, txq_id, seq_number);
+
+ /* NOTE: aggregation will need changes here (for txq id) */
+ if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id))
+ goto drop_unlock_sta;
+
+ if (is_data_qos && !ieee80211_has_morefrags(fc))
+ mvmsta->tid_data[tid].seq_number = seq_number;
+
+ spin_unlock(&mvmsta->lock);
+
+ if (mvmsta->vif->type == NL80211_IFTYPE_AP &&
+ txq_id < IWL_FIRST_AMPDU_QUEUE)
+ atomic_inc(&mvmsta->pending_frames);
+
+ return 0;
+
+drop_unlock_sta:
+ iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
+ spin_unlock(&mvmsta->lock);
+drop:
+ return -1;
+}
+
+static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta, u8 tid)
+{
+ struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+ struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+ struct ieee80211_vif *vif = mvmsta->vif;
+
+ lockdep_assert_held(&mvmsta->lock);
+
+ if (tid_data->ssn != tid_data->next_reclaimed)
+ return;
+
+ switch (tid_data->state) {
+ case IWL_EMPTYING_HW_QUEUE_ADDBA:
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Can continue addBA flow ssn = next_recl = %d\n",
+ tid_data->next_reclaimed);
+ tid_data->state = IWL_AGG_STARTING;
+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+
+ case IWL_EMPTYING_HW_QUEUE_DELBA:
+ IWL_DEBUG_TX_QUEUES(mvm,
+ "Can continue DELBA flow ssn = next_recl = %d\n",
+ tid_data->next_reclaimed);
+ iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+ tid_data->state = IWL_AGG_OFF;
+ /*
+ * we can't hold the mutex - but since we are after a sequence
+ * point (call to iwl_trans_txq_disable), so we don't even need
+ * a memory barrier.
+ */
+ mvm->queue_to_mac80211[tid_data->txq_id] =
+ IWL_INVALID_MAC80211_QUEUE;
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+
+ default:
+ break;
+ }
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+const char *iwl_mvm_get_tx_fail_reason(u32 status)
+{
+#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
+
+ switch (status & TX_STATUS_MSK) {
+ case TX_STATUS_SUCCESS:
+ return "SUCCESS";
+ TX_STATUS_POSTPONE(DELAY);
+ TX_STATUS_POSTPONE(FEW_BYTES);
+ TX_STATUS_POSTPONE(BT_PRIO);
+ TX_STATUS_POSTPONE(QUIET_PERIOD);
+ TX_STATUS_POSTPONE(CALC_TTAK);
+ TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
+ TX_STATUS_FAIL(SHORT_LIMIT);
+ TX_STATUS_FAIL(LONG_LIMIT);
+ TX_STATUS_FAIL(UNDERRUN);
+ TX_STATUS_FAIL(DRAIN_FLOW);
+ TX_STATUS_FAIL(RFKILL_FLUSH);
+ TX_STATUS_FAIL(LIFE_EXPIRE);
+ TX_STATUS_FAIL(DEST_PS);
+ TX_STATUS_FAIL(HOST_ABORTED);
+ TX_STATUS_FAIL(BT_RETRY);
+ TX_STATUS_FAIL(STA_INVALID);
+ TX_STATUS_FAIL(FRAG_DROPPED);
+ TX_STATUS_FAIL(TID_DISABLE);
+ TX_STATUS_FAIL(FIFO_FLUSHED);
+ TX_STATUS_FAIL(SMALL_CF_POLL);
+ TX_STATUS_FAIL(FW_DROP);
+ TX_STATUS_FAIL(STA_COLOR_MISMATCH);
+ }
+
+ return "UNKNOWN";
+
+#undef TX_STATUS_FAIL
+#undef TX_STATUS_POSTPONE
+}
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+/**
+ * translate ucode response to mac80211 tx status control values
+ */
+static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags,
+ struct ieee80211_tx_info *info)
+{
+ struct ieee80211_tx_rate *r = &info->status.rates[0];
+
+ info->status.antenna =
+ ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
+ if (rate_n_flags & RATE_HT_MCS_GF_MSK)
+ r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
+ case RATE_MCS_CHAN_WIDTH_20:
+ break;
+ case RATE_MCS_CHAN_WIDTH_40:
+ r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ break;
+ case RATE_MCS_CHAN_WIDTH_80:
+ r->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
+ break;
+ case RATE_MCS_CHAN_WIDTH_160:
+ r->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH;
+ break;
+ }
+ if (rate_n_flags & RATE_MCS_SGI_MSK)
+ r->flags |= IEEE80211_TX_RC_SHORT_GI;
+ if (rate_n_flags & RATE_MCS_HT_MSK) {
+ r->flags |= IEEE80211_TX_RC_MCS;
+ r->idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
+ } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+ ieee80211_rate_set_vht(
+ r, rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK,
+ ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
+ RATE_VHT_MCS_NSS_POS) + 1);
+ r->flags |= IEEE80211_TX_RC_VHT_MCS;
+ } else {
+ r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
+ info->band);
+ }
+}
+
+static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
+ struct iwl_rx_packet *pkt)
+{
+ struct ieee80211_sta *sta;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
+ int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid);
+ int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid);
+ u32 status = le16_to_cpu(tx_resp->status.status);
+ u16 ssn = iwl_mvm_get_scd_ssn(tx_resp);
+ struct iwl_mvm_sta *mvmsta;
+ struct sk_buff_head skbs;
+ u8 skb_freed = 0;
+ u16 next_reclaimed, seq_ctl;
+
+ __skb_queue_head_init(&skbs);
+
+ seq_ctl = le16_to_cpu(tx_resp->seq_ctl);
+
+ /* we can free until ssn % q.n_bd not inclusive */
+ iwl_trans_reclaim(mvm->trans, txq_id, ssn, &skbs);
+
+ while (!skb_queue_empty(&skbs)) {
+ struct sk_buff *skb = __skb_dequeue(&skbs);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ skb_freed++;
+
+ iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
+
+ memset(&info->status, 0, sizeof(info->status));
+
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+
+ /* inform mac80211 about what happened with the frame */
+ switch (status & TX_STATUS_MSK) {
+ case TX_STATUS_SUCCESS:
+ case TX_STATUS_DIRECT_DONE:
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ break;
+ case TX_STATUS_FAIL_DEST_PS:
+ info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ break;
+ default:
+ break;
+ }
+
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
+ iwl_mvm_hwrate_to_tx_control(le32_to_cpu(tx_resp->initial_rate),
+ info);
+
+ /* Single frame failure in an AMPDU queue => send BAR */
+ if (txq_id >= IWL_FIRST_AMPDU_QUEUE &&
+ !(info->flags & IEEE80211_TX_STAT_ACK)) {
+ /* there must be only one skb in the skb_list */
+ WARN_ON_ONCE(skb_freed > 1 ||
+ !skb_queue_empty(&skbs));
+ info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+ }
+
+ /* W/A FW bug: seq_ctl is wrong when the queue is flushed */
+ if (status == TX_STATUS_FAIL_FIFO_FLUSHED) {
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ seq_ctl = le16_to_cpu(hdr->seq_ctrl);
+ }
+
+ ieee80211_tx_status_ni(mvm->hw, skb);
+ }
+
+ if (txq_id >= IWL_FIRST_AMPDU_QUEUE) {
+ /* If this is an aggregation queue, we use the ssn since:
+ * ssn = wifi seq_num % 256.
+ * The seq_ctl is the sequence control of the packet to which
+ * this Tx response relates. But if there is a hole in the
+ * bitmap of the BA we received, this Tx response may allow to
+ * reclaim the hole and all the subsequent packets that were
+ * already acked. In that case, seq_ctl != ssn, and the next
+ * packet to be reclaimed will be ssn and not seq_ctl. In that
+ * case, several packets will be reclaimed even if
+ * frame_count = 1.
+ *
+ * The ssn is the index (% 256) of the latest packet that has
+ * treated (acked / dropped) + 1.
+ */
+ next_reclaimed = ssn;
+ } else {
+ /* The next packet to be reclaimed is the one after this one */
+ next_reclaimed = SEQ_TO_SN(seq_ctl + 0x10);
+ }
+
+ IWL_DEBUG_TX_REPLY(mvm,
+ "TXQ %d status %s (0x%08x)\n\t\t\t\tinitial_rate 0x%x "
+ "retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n",
+ txq_id, iwl_mvm_get_tx_fail_reason(status),
+ status, le32_to_cpu(tx_resp->initial_rate),
+ tx_resp->failure_frame, SEQ_TO_INDEX(sequence),
+ ssn, next_reclaimed, seq_ctl);
+
+ rcu_read_lock();
+
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+
+ if (!IS_ERR_OR_NULL(sta)) {
+ mvmsta = (void *)sta->drv_priv;
+
+ if (tid != IWL_TID_NON_QOS) {
+ struct iwl_mvm_tid_data *tid_data =
+ &mvmsta->tid_data[tid];
+
+ spin_lock_bh(&mvmsta->lock);
+ tid_data->next_reclaimed = next_reclaimed;
+ IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n",
+ next_reclaimed);
+ iwl_mvm_check_ratid_empty(mvm, sta, tid);
+ spin_unlock_bh(&mvmsta->lock);
+ }
+
+#ifdef CONFIG_PM_SLEEP
+ mvmsta->last_seq_ctl = seq_ctl;
+#endif
+ } else {
+ sta = NULL;
+ mvmsta = NULL;
+ }
+
+ /*
+ * If the txq is not an AMPDU queue, there is no chance we freed
+ * several skbs. Check that out...
+ * If there are no pending frames for this STA, notify mac80211 that
+ * this station can go to sleep in its STA table.
+ */
+ if (txq_id < IWL_FIRST_AMPDU_QUEUE && mvmsta &&
+ !WARN_ON(skb_freed > 1) &&
+ mvmsta->vif->type == NL80211_IFTYPE_AP &&
+ atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) {
+ ieee80211_sta_block_awake(mvm->hw, sta, false);
+ set_bit(sta_id, mvm->sta_drained);
+ schedule_work(&mvm->sta_drained_wk);
+ }
+
+ rcu_read_unlock();
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define AGG_TX_STATE_(x) case AGG_TX_STATE_ ## x: return #x
+static const char *iwl_get_agg_tx_status(u16 status)
+{
+ switch (status & AGG_TX_STATE_STATUS_MSK) {
+ AGG_TX_STATE_(TRANSMITTED);
+ AGG_TX_STATE_(UNDERRUN);
+ AGG_TX_STATE_(BT_PRIO);
+ AGG_TX_STATE_(FEW_BYTES);
+ AGG_TX_STATE_(ABORT);
+ AGG_TX_STATE_(LAST_SENT_TTL);
+ AGG_TX_STATE_(LAST_SENT_TRY_CNT);
+ AGG_TX_STATE_(LAST_SENT_BT_KILL);
+ AGG_TX_STATE_(SCD_QUERY);
+ AGG_TX_STATE_(TEST_BAD_CRC32);
+ AGG_TX_STATE_(RESPONSE);
+ AGG_TX_STATE_(DUMP_TX);
+ AGG_TX_STATE_(DELAY_TX);
+ }
+
+ return "UNKNOWN";
+}
+
+static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm,
+ struct iwl_rx_packet *pkt)
+{
+ struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
+ struct agg_tx_status *frame_status = &tx_resp->status;
+ int i;
+
+ for (i = 0; i < tx_resp->frame_count; i++) {
+ u16 fstatus = le16_to_cpu(frame_status[i].status);
+
+ IWL_DEBUG_TX_REPLY(mvm,
+ "status %s (0x%04x), try-count (%d) seq (0x%x)\n",
+ iwl_get_agg_tx_status(fstatus),
+ fstatus & AGG_TX_STATE_STATUS_MSK,
+ (fstatus & AGG_TX_STATE_TRY_CNT_MSK) >>
+ AGG_TX_STATE_TRY_CNT_POS,
+ le16_to_cpu(frame_status[i].sequence));
+ }
+}
+#else
+static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm,
+ struct iwl_rx_packet *pkt)
+{}
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
+ struct iwl_rx_packet *pkt)
+{
+ struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
+ int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid);
+ int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid);
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ struct ieee80211_sta *sta;
+
+ if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_FIRST_AMPDU_QUEUE))
+ return;
+
+ if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS))
+ return;
+
+ iwl_mvm_rx_tx_cmd_agg_dbg(mvm, pkt);
+
+ rcu_read_lock();
+
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+
+ if (!WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
+ struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+ mvmsta->tid_data[tid].rate_n_flags =
+ le32_to_cpu(tx_resp->initial_rate);
+ }
+
+ rcu_read_unlock();
+}
+
+int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
+
+ if (tx_resp->frame_count == 1)
+ iwl_mvm_rx_tx_cmd_single(mvm, pkt);
+ else
+ iwl_mvm_rx_tx_cmd_agg(mvm, pkt);
+
+ return 0;
+}
+
+int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data;
+ struct sk_buff_head reclaimed_skbs;
+ struct iwl_mvm_tid_data *tid_data;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvmsta;
+ struct ieee80211_hdr *hdr;
+ struct sk_buff *skb;
+ int sta_id, tid, freed;
+
+ /* "flow" corresponds to Tx queue */
+ u16 scd_flow = le16_to_cpu(ba_notif->scd_flow);
+
+ /* "ssn" is start of block-ack Tx window, corresponds to index
+ * (in Tx queue's circular buffer) of first TFD/frame in window */
+ u16 ba_resp_scd_ssn = le16_to_cpu(ba_notif->scd_ssn);
+
+ sta_id = ba_notif->sta_id;
+ tid = ba_notif->tid;
+
+ rcu_read_lock();
+
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+
+ /* Reclaiming frames for a station that has been deleted ? */
+ if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ mvmsta = (void *)sta->drv_priv;
+ tid_data = &mvmsta->tid_data[tid];
+
+ if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d",
+ tid_data->txq_id, tid, scd_flow)) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ spin_lock_bh(&mvmsta->lock);
+
+ __skb_queue_head_init(&reclaimed_skbs);
+
+ /*
+ * Release all TFDs before the SSN, i.e. all TFDs in front of
+ * block-ack window (we assume that they've been successfully
+ * transmitted ... if not, it's too late anyway).
+ */
+ iwl_trans_reclaim(mvm->trans, scd_flow, ba_resp_scd_ssn,
+ &reclaimed_skbs);
+
+ IWL_DEBUG_TX_REPLY(mvm,
+ "BA_NOTIFICATION Received from %pM, sta_id = %d\n",
+ (u8 *)&ba_notif->sta_addr_lo32,
+ ba_notif->sta_id);
+ IWL_DEBUG_TX_REPLY(mvm,
+ "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
+ ba_notif->tid, le16_to_cpu(ba_notif->seq_ctl),
+ (unsigned long long)le64_to_cpu(ba_notif->bitmap),
+ scd_flow, ba_resp_scd_ssn, ba_notif->txed,
+ ba_notif->txed_2_done);
+
+ tid_data->next_reclaimed = ba_resp_scd_ssn;
+
+ iwl_mvm_check_ratid_empty(mvm, sta, tid);
+
+ freed = 0;
+
+ skb_queue_walk(&reclaimed_skbs, skb) {
+ hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (ieee80211_is_data_qos(hdr->frame_control))
+ freed++;
+ else
+ WARN_ON_ONCE(1);
+
+ info = IEEE80211_SKB_CB(skb);
+ iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
+
+ if (freed == 1) {
+ /* this is the first skb we deliver in this batch */
+ /* put the rate scaling data there */
+ info = IEEE80211_SKB_CB(skb);
+ memset(&info->status, 0, sizeof(info->status));
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ info->flags |= IEEE80211_TX_STAT_AMPDU;
+ info->status.ampdu_ack_len = ba_notif->txed_2_done;
+ info->status.ampdu_len = ba_notif->txed;
+ iwl_mvm_hwrate_to_tx_control(tid_data->rate_n_flags,
+ info);
+ }
+ }
+
+ spin_unlock_bh(&mvmsta->lock);
+
+ rcu_read_unlock();
+
+ while (!skb_queue_empty(&reclaimed_skbs)) {
+ skb = __skb_dequeue(&reclaimed_skbs);
+ ieee80211_tx_status_ni(mvm->hw, skb);
+ }
+
+ return 0;
+}
+
+int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync)
+{
+ int ret;
+ struct iwl_tx_path_flush_cmd flush_cmd = {
+ .queues_ctl = cpu_to_le32(tfd_msk),
+ .flush_ctl = cpu_to_le16(DUMP_TX_FIFO_FLUSH),
+ };
+
+ u32 flags = sync ? CMD_SYNC : CMD_ASYNC;
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags,
+ sizeof(flush_cmd), &flush_cmd);
+ if (ret)
+ IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret);
+ return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
new file mode 100644
index 000000000000..000e842c2edd
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -0,0 +1,472 @@
+/******************************************************************************
+ *
+ * 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) 2012 - 2013 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) 2012 - 2013 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 <net/mac80211.h>
+
+#include "iwl-debug.h"
+#include "iwl-io.h"
+
+#include "mvm.h"
+#include "fw-api-rs.h"
+
+/*
+ * Will return 0 even if the cmd failed when RFKILL is asserted unless
+ * CMD_WANT_SKB is set in cmd->flags.
+ */
+int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd)
+{
+ int ret;
+
+ /*
+ * Synchronous commands from this op-mode must hold
+ * the mutex, this ensures we don't try to send two
+ * (or more) synchronous commands at a time.
+ */
+ if (!(cmd->flags & CMD_ASYNC))
+ lockdep_assert_held(&mvm->mutex);
+
+ ret = iwl_trans_send_cmd(mvm->trans, cmd);
+
+ /*
+ * If the caller wants the SKB, then don't hide any problems, the
+ * caller might access the response buffer which will be NULL if
+ * the command failed.
+ */
+ if (cmd->flags & CMD_WANT_SKB)
+ return ret;
+
+ /* Silently ignore failures if RFKILL is asserted */
+ if (!ret || ret == -ERFKILL)
+ return 0;
+ return ret;
+}
+
+int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id,
+ u32 flags, u16 len, const void *data)
+{
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = { len, },
+ .data = { data, },
+ .flags = flags,
+ };
+
+ return iwl_mvm_send_cmd(mvm, &cmd);
+}
+
+/*
+ * We assume that the caller set the status to the sucess value
+ */
+int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,
+ u32 *status)
+{
+ struct iwl_rx_packet *pkt;
+ struct iwl_cmd_response *resp;
+ int ret, resp_len;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ /*
+ * Only synchronous commands can wait for status,
+ * we use WANT_SKB so the caller can't.
+ */
+ if (WARN_ONCE(cmd->flags & (CMD_ASYNC | CMD_WANT_SKB),
+ "cmd flags %x", cmd->flags))
+ return -EINVAL;
+
+ cmd->flags |= CMD_SYNC | CMD_WANT_SKB;
+
+ ret = iwl_trans_send_cmd(mvm->trans, cmd);
+ if (ret == -ERFKILL) {
+ /*
+ * The command failed because of RFKILL, don't update
+ * the status, leave it as success and return 0.
+ */
+ return 0;
+ } else if (ret) {
+ return ret;
+ }
+
+ pkt = cmd->resp_pkt;
+ /* Can happen if RFKILL is asserted */
+ if (!pkt) {
+ ret = 0;
+ goto out_free_resp;
+ }
+
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+ ret = -EIO;
+ goto out_free_resp;
+ }
+
+ resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+ if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) {
+ ret = -EIO;
+ goto out_free_resp;
+ }
+
+ resp = (void *)pkt->data;
+ *status = le32_to_cpu(resp->status);
+ out_free_resp:
+ iwl_free_resp(cmd);
+ return ret;
+}
+
+/*
+ * We assume that the caller set the status to the sucess value
+ */
+int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, u16 len,
+ const void *data, u32 *status)
+{
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = { len, },
+ .data = { data, },
+ };
+
+ return iwl_mvm_send_cmd_status(mvm, &cmd, status);
+}
+
+#define IWL_DECLARE_RATE_INFO(r) \
+ [IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP
+
+/*
+ * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP
+ */
+static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = {
+ IWL_DECLARE_RATE_INFO(1),
+ IWL_DECLARE_RATE_INFO(2),
+ IWL_DECLARE_RATE_INFO(5),
+ IWL_DECLARE_RATE_INFO(11),
+ IWL_DECLARE_RATE_INFO(6),
+ IWL_DECLARE_RATE_INFO(9),
+ IWL_DECLARE_RATE_INFO(12),
+ IWL_DECLARE_RATE_INFO(18),
+ IWL_DECLARE_RATE_INFO(24),
+ IWL_DECLARE_RATE_INFO(36),
+ IWL_DECLARE_RATE_INFO(48),
+ IWL_DECLARE_RATE_INFO(54),
+};
+
+int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
+ enum ieee80211_band band)
+{
+ int rate = rate_n_flags & RATE_LEGACY_RATE_MSK;
+ int idx;
+ int band_offset = 0;
+
+ /* Legacy rate format, search for match in table */
+ if (band == IEEE80211_BAND_5GHZ)
+ band_offset = IWL_FIRST_OFDM_RATE;
+ for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
+ if (fw_rate_idx_to_plcp[idx] == rate)
+ return idx - band_offset;
+
+ return -1;
+}
+
+u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx)
+{
+ /* Get PLCP rate for tx_cmd->rate_n_flags */
+ return fw_rate_idx_to_plcp[rate_idx];
+}
+
+int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_error_resp *err_resp = (void *)pkt->data;
+
+ IWL_ERR(mvm, "FW Error notification: type 0x%08X cmd_id 0x%02X\n",
+ le32_to_cpu(err_resp->error_type), err_resp->cmd_id);
+ IWL_ERR(mvm, "FW Error notification: seq 0x%04X service 0x%08X\n",
+ le16_to_cpu(err_resp->bad_cmd_seq_num),
+ le32_to_cpu(err_resp->error_service));
+ IWL_ERR(mvm, "FW Error notification: timestamp 0x%16llX\n",
+ le64_to_cpu(err_resp->timestamp));
+ return 0;
+}
+
+/*
+ * Returns the first antenna as ANT_[ABC], as defined in iwl-config.h.
+ * The parameter should also be a combination of ANT_[ABC].
+ */
+u8 first_antenna(u8 mask)
+{
+ BUILD_BUG_ON(ANT_A != BIT(0)); /* using ffs is wrong if not */
+ WARN_ON_ONCE(!mask); /* ffs will return 0 if mask is zeroed */
+ return (u8)(BIT(ffs(mask)));
+}
+
+/*
+ * Toggles between TX antennas to send the probe request on.
+ * Receives the bitmask of valid TX antennas and the *index* used
+ * for the last TX, and returns the next valid *index* to use.
+ * In order to set it in the tx_cmd, must do BIT(idx).
+ */
+u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx)
+{
+ u8 ind = last_idx;
+ int i;
+
+ for (i = 0; i < RATE_MCS_ANT_NUM; i++) {
+ ind = (ind + 1) % RATE_MCS_ANT_NUM;
+ if (valid & BIT(ind))
+ return ind;
+ }
+
+ WARN_ONCE(1, "Failed to toggle between antennas 0x%x", valid);
+ return last_idx;
+}
+
+static struct {
+ char *name;
+ u8 num;
+} advanced_lookup[] = {
+ { "NMI_INTERRUPT_WDG", 0x34 },
+ { "SYSASSERT", 0x35 },
+ { "UCODE_VERSION_MISMATCH", 0x37 },
+ { "BAD_COMMAND", 0x38 },
+ { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
+ { "FATAL_ERROR", 0x3D },
+ { "NMI_TRM_HW_ERR", 0x46 },
+ { "NMI_INTERRUPT_TRM", 0x4C },
+ { "NMI_INTERRUPT_BREAK_POINT", 0x54 },
+ { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
+ { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
+ { "NMI_INTERRUPT_HOST", 0x66 },
+ { "NMI_INTERRUPT_ACTION_PT", 0x7C },
+ { "NMI_INTERRUPT_UNKNOWN", 0x84 },
+ { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
+ { "ADVANCED_SYSASSERT", 0 },
+};
+
+static const char *desc_lookup(u32 num)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(advanced_lookup) - 1; i++)
+ if (advanced_lookup[i].num == num)
+ return advanced_lookup[i].name;
+
+ /* No entry matches 'num', so it is the last: ADVANCED_SYSASSERT */
+ return advanced_lookup[i].name;
+}
+
+/*
+ * 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 data3; /* error-specific data */
+ 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 */
+ 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 */
+} __packed;
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
+{
+ struct iwl_trans *trans = mvm->trans;
+ struct iwl_error_event_table table;
+ u32 base;
+
+ base = mvm->error_event_table;
+ if (mvm->cur_ucode == IWL_UCODE_INIT) {
+ if (!base)
+ base = mvm->fw->init_errlog_ptr;
+ } else {
+ if (!base)
+ base = mvm->fw->inst_errlog_ptr;
+ }
+
+ if (base < 0x800000 || base >= 0x80C000) {
+ IWL_ERR(mvm,
+ "Not valid error log pointer 0x%08X for %s uCode\n",
+ base,
+ (mvm->cur_ucode == IWL_UCODE_INIT)
+ ? "Init" : "RT");
+ return;
+ }
+
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+ if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+ IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+ IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
+ mvm->status, table.valid);
+ }
+
+ trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
+ table.data1, table.data2, table.data3,
+ 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(mvm, "0x%08X | %-28s\n", table.error_id,
+ desc_lookup(table.error_id));
+ IWL_ERR(mvm, "0x%08X | uPc\n", table.pc);
+ IWL_ERR(mvm, "0x%08X | branchlink1\n", table.blink1);
+ IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2);
+ IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1);
+ IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2);
+ IWL_ERR(mvm, "0x%08X | data1\n", table.data1);
+ IWL_ERR(mvm, "0x%08X | data2\n", table.data2);
+ IWL_ERR(mvm, "0x%08X | data3\n", table.data3);
+ IWL_ERR(mvm, "0x%08X | beacon time\n", table.bcon_time);
+ IWL_ERR(mvm, "0x%08X | tsf low\n", table.tsf_low);
+ IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi);
+ IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1);
+ IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2);
+ IWL_ERR(mvm, "0x%08X | time gp3\n", table.gp3);
+ IWL_ERR(mvm, "0x%08X | uCode version\n", table.ucode_ver);
+ IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver);
+ IWL_ERR(mvm, "0x%08X | board version\n", table.brd_ver);
+ IWL_ERR(mvm, "0x%08X | hcmd\n", table.hcmd);
+ IWL_ERR(mvm, "0x%08X | isr0\n", table.isr0);
+ IWL_ERR(mvm, "0x%08X | isr1\n", table.isr1);
+ IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2);
+ IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3);
+ IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4);
+ IWL_ERR(mvm, "0x%08X | isr_pref\n", table.isr_pref);
+ IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event);
+ IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control);
+ IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration);
+ IWL_ERR(mvm, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
+ IWL_ERR(mvm, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
+ IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
+ IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp);
+ IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler);
+}
+
+/**
+ * iwl_mvm_send_lq_cmd() - Send link quality command
+ * @init: This command is sent as part of station initialization right
+ * after station has been added.
+ *
+ * The link quality command is sent as the last step of station creation.
+ * This is the special case in which init is set and we call a callback in
+ * this case to clear the state indicating that station creation is in
+ * progress.
+ */
+int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
+ u8 flags, bool init)
+{
+ struct iwl_host_cmd cmd = {
+ .id = LQ_CMD,
+ .len = { sizeof(struct iwl_lq_cmd), },
+ .flags = flags,
+ .data = { lq, },
+ };
+
+ if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
+ return -EINVAL;
+
+ if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
+ return -EINVAL;
+
+ return iwl_mvm_send_cmd(mvm, &cmd);
+}
diff --git a/drivers/net/wireless/iwlwifi/pcie/1000.c b/drivers/net/wireless/iwlwifi/pcie/1000.c
index f8620ecae6b4..ff3389757281 100644
--- a/drivers/net/wireless/iwlwifi/pcie/1000.c
+++ b/drivers/net/wireless/iwlwifi/pcie/1000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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/pcie/2000.c b/drivers/net/wireless/iwlwifi/pcie/2000.c
index 244019cec3e1..e7de33128b16 100644
--- a/drivers/net/wireless/iwlwifi/pcie/2000.c
+++ b/drivers/net/wireless/iwlwifi/pcie/2000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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/pcie/5000.c b/drivers/net/wireless/iwlwifi/pcie/5000.c
index 83ca40321ff1..5096f7c96ab6 100644
--- a/drivers/net/wireless/iwlwifi/pcie/5000.c
+++ b/drivers/net/wireless/iwlwifi/pcie/5000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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/pcie/6000.c b/drivers/net/wireless/iwlwifi/pcie/6000.c
index d4df976d4709..801ff49796dd 100644
--- a/drivers/net/wireless/iwlwifi/pcie/6000.c
+++ b/drivers/net/wireless/iwlwifi/pcie/6000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2013 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/pcie/7000.c b/drivers/net/wireless/iwlwifi/pcie/7000.c
new file mode 100644
index 000000000000..6e35b2b72332
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/pcie/7000.c
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2013 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/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "cfg.h"
+
+/* Highest firmware API version supported */
+#define IWL7260_UCODE_API_MAX 6
+#define IWL3160_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL7260_UCODE_API_OK 6
+#define IWL3160_UCODE_API_OK 6
+
+/* Lowest firmware API version supported */
+#define IWL7260_UCODE_API_MIN 6
+#define IWL3160_UCODE_API_MIN 6
+
+/* NVM versions */
+#define IWL7260_NVM_VERSION 0x0a1d
+#define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */
+#define IWL3160_NVM_VERSION 0x709
+#define IWL3160_TX_POWER_VERSION 0xffff /* meaningless */
+
+#define IWL7260_FW_PRE "iwlwifi-7260-"
+#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode"
+
+#define IWL3160_FW_PRE "iwlwifi-3160-"
+#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl7000_base_params = {
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .pll_cfg_val = 0,
+ .shadow_ram_support = true,
+ .led_compensation = 57,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .wd_timeout = IWL_LONG_WD_TIMEOUT,
+ .max_event_log_size = 512,
+ .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_ht_params iwl7000_ht_params = {
+ .ht_greenfield_support = true,
+ .use_rts_for_aggregation = true, /* use rts/cts protection */
+ .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+#define IWL_DEVICE_7000 \
+ .ucode_api_max = IWL7260_UCODE_API_MAX, \
+ .ucode_api_ok = IWL7260_UCODE_API_OK, \
+ .ucode_api_min = IWL7260_UCODE_API_MIN, \
+ .device_family = IWL_DEVICE_FAMILY_7000, \
+ .max_inst_size = IWL60_RTC_INST_SIZE, \
+ .max_data_size = IWL60_RTC_DATA_SIZE, \
+ .base_params = &iwl7000_base_params, \
+ /* TODO: .bt_params? */ \
+ .need_temp_offset_calib = true, \
+ .led_mode = IWL_LED_RF_STATE, \
+ .adv_pm = true \
+
+
+const struct iwl_cfg iwl7260_2ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC7260",
+ .fw_name_pre = IWL7260_FW_PRE,
+ IWL_DEVICE_7000,
+ .ht_params = &iwl7000_ht_params,
+ .nvm_ver = IWL7260_NVM_VERSION,
+ .nvm_calib_ver = IWL7260_TX_POWER_VERSION,
+};
+
+const struct iwl_cfg iwl3160_ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC3160",
+ .fw_name_pre = IWL3160_FW_PRE,
+ IWL_DEVICE_7000,
+ .ht_params = &iwl7000_ht_params,
+ .nvm_ver = IWL3160_NVM_VERSION,
+ .nvm_calib_ver = IWL3160_TX_POWER_VERSION,
+};
+
+MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
+MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/cfg.h b/drivers/net/wireless/iwlwifi/pcie/cfg.h
index 82152311d73b..c6f8e83c3551 100644
--- a/drivers/net/wireless/iwlwifi/pcie/cfg.h
+++ b/drivers/net/wireless/iwlwifi/pcie/cfg.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -109,5 +109,7 @@ extern const struct iwl_cfg iwl6035_2agn_cfg;
extern const struct iwl_cfg iwl105_bgn_cfg;
extern const struct iwl_cfg iwl105_bgn_d_cfg;
extern const struct iwl_cfg iwl135_bgn_cfg;
+extern const struct iwl_cfg iwl7260_2ac_cfg;
+extern const struct iwl_cfg iwl3160_ac_cfg;
#endif /* __iwl_pci_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index c2e141af353c..7bc0fb9128dd 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -255,6 +255,12 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
{IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
+/* 7000 Series */
+ {IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x08B1, 0xC070, iwl7260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_ac_cfg)},
+ {IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_ac_cfg)},
+
{0}
};
MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index d91d2e8c62f5..aa2a39a637dd 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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.
@@ -222,8 +222,6 @@ struct iwl_txq {
* @rx_replenish: work that will be called when buffers need to be allocated
* @drv - pointer to iwl_drv
* @trans: pointer to the generic transport area
- * @irq - the irq number for the device
- * @irq_requested: true when the irq has been requested
* @scd_base_addr: scheduler sram base address in SRAM
* @scd_bc_tbls: pointer to the byte count table of the scheduler
* @kw: keep warm address
@@ -234,8 +232,10 @@ struct iwl_txq {
* @status - transport specific status flags
* @cmd_queue - command queue number
* @rx_buf_size_8k: 8 kB RX buffer size
+ * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
* @rx_page_order: page order for receive buffer size
* @wd_timeout: queue watchdog timeout (jiffies)
+ * @reg_lock: protect hw register access
*/
struct iwl_trans_pcie {
struct iwl_rxq rxq;
@@ -249,11 +249,8 @@ struct iwl_trans_pcie {
int ict_index;
u32 inta;
bool use_ict;
- bool irq_requested;
- struct tasklet_struct irq_tasklet;
struct isr_statistics isr_stats;
- unsigned int irq;
spinlock_t irq_lock;
u32 inta_mask;
u32 scd_base_addr;
@@ -279,12 +276,16 @@ struct iwl_trans_pcie {
u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
bool rx_buf_size_8k;
+ bool bc_table_dword;
u32 rx_page_order;
const char **command_names;
/* queue watchdog */
unsigned long wd_timeout;
+
+ /*protect hw register */
+ spinlock_t reg_lock;
};
/**
@@ -328,7 +329,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans);
* RX
******************************************************/
int iwl_pcie_rx_init(struct iwl_trans *trans);
-void iwl_pcie_tasklet(struct iwl_trans *trans);
+irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id);
int iwl_pcie_rx_stop(struct iwl_trans *trans);
void iwl_pcie_rx_free(struct iwl_trans *trans);
@@ -359,6 +360,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
struct iwl_rx_cmd_buffer *rxb, int handler_status);
void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
struct sk_buff_head *skbs);
+void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
+
/*****************************************************
* Error handling
******************************************************/
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index 8389cd38338b..b0ae06d2456f 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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.
@@ -81,10 +81,10 @@
* 'processed' and 'read' driver indexes as well)
* + A received packet is processed and handed to the kernel network stack,
* detached from the iwl->rxq. The driver 'processed' index is updated.
- * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
- * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
- * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
- * were enough free buffers and RX_STALLED is set it is cleared.
+ * + The Host/Firmware iwl->rxq is replenished at irq thread time from the
+ * rx_free list. If there are no allocated buffers in iwl->rxq->rx_free,
+ * the READ INDEX is not incremented and iwl->status(RX_STALLED) is set.
+ * If there were enough free buffers and RX_STALLED is set it is cleared.
*
*
* Driver sequence:
@@ -214,9 +214,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
/*
* If the device isn't enabled - not need to try to add buffers...
* This can happen when we stop the device and still have an interrupt
- * pending. We stop the APM before we sync the interrupts / tasklets
- * because we have to (see comment there). On the other hand, since
- * the APM is stopped, we cannot access the HW (in particular not prph).
+ * pending. We stop the APM before we sync the interrupts because we
+ * have to (see comment there). On the other hand, since the APM is
+ * stopped, we cannot access the HW (in particular not prph).
* So don't try to restock if the APM has been already stopped.
*/
if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status))
@@ -436,7 +436,7 @@ static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
err_rb_stts:
dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
rxq->bd, rxq->bd_dma);
- memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+ rxq->bd_dma = 0;
rxq->bd = NULL;
err_bd:
return -ENOMEM;
@@ -455,6 +455,10 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
/* Stop Rx DMA */
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+ /* reset and flush pointers */
+ iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
+ iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
+ iwl_write_direct32(trans, FH_RSCSR_CHNL0_RDPTR, 0);
/* Reset driver's Rx queue write index */
iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
@@ -491,7 +495,6 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rxq *rxq = &trans_pcie->rxq;
-
int i, err;
unsigned long flags;
@@ -518,6 +521,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
rxq->read = rxq->write = 0;
rxq->write_actual = 0;
rxq->free_count = 0;
+ memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
spin_unlock_irqrestore(&rxq->lock, flags);
iwl_pcie_rx_replenish(trans);
@@ -545,13 +549,15 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
return;
}
+ cancel_work_sync(&trans_pcie->rx_replenish);
+
spin_lock_irqsave(&rxq->lock, flags);
iwl_pcie_rxq_free_rbs(trans);
spin_unlock_irqrestore(&rxq->lock, flags);
dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
rxq->bd, rxq->bd_dma);
- memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+ rxq->bd_dma = 0;
rxq->bd = NULL;
if (rxq->rb_stts)
@@ -560,7 +566,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
rxq->rb_stts, rxq->rb_stts_dma);
else
IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
- memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
+ rxq->rb_stts_dma = 0;
rxq->rb_stts = NULL;
}
@@ -588,6 +594,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
int index, cmd_index, err, len;
struct iwl_rx_cmd_buffer rxcb = {
._offset = offset,
+ ._rx_page_order = trans_pcie->rx_page_order,
._page = rxb->page,
._page_stolen = false,
.truesize = max_len,
@@ -789,11 +796,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
wake_up(&trans_pcie->wait_command_queue);
+ local_bh_disable();
iwl_op_mode_nic_error(trans->op_mode);
+ local_bh_enable();
}
-void iwl_pcie_tasklet(struct iwl_trans *trans)
+irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
{
+ struct iwl_trans *trans = dev_id;
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
u32 inta = 0;
@@ -804,6 +814,8 @@ void iwl_pcie_tasklet(struct iwl_trans *trans)
u32 inta_mask;
#endif
+ lock_map_acquire(&trans->sync_cmd_lockdep_map);
+
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
/* Ack/clear/reset pending uCode interrupts.
@@ -848,7 +860,7 @@ void iwl_pcie_tasklet(struct iwl_trans *trans)
handled |= CSR_INT_BIT_HW_ERR;
- return;
+ goto out;
}
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -998,6 +1010,10 @@ void iwl_pcie_tasklet(struct iwl_trans *trans)
/* Re-enable RF_KILL if it occurred */
else if (handled & CSR_INT_BIT_RF_KILL)
iwl_enable_rfkill_int(trans);
+
+out:
+ lock_map_release(&trans->sync_cmd_lockdep_map);
+ return IRQ_HANDLED;
}
/******************************************************************************
@@ -1120,7 +1136,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
/* Disable (but don't clear!) interrupts here to avoid
* back-to-back ISRs and sporadic interrupts from our NIC.
- * If we have something to service, the tasklet will re-enable ints.
+ * If we have something to service, the irq thread will re-enable ints.
* If we *don't* have something, we'll re-enable before leaving here. */
inta_mask = iwl_read32(trans, CSR_INT_MASK);
iwl_write32(trans, CSR_INT_MASK, 0x00000000);
@@ -1160,9 +1176,9 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
#endif
trans_pcie->inta |= inta;
- /* iwl_pcie_tasklet() will service interrupts and re-enable them */
+ /* the thread will service interrupts and re-enable them */
if (likely(inta))
- tasklet_schedule(&trans_pcie->irq_tasklet);
+ return IRQ_WAKE_THREAD;
else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
!trans_pcie->inta)
iwl_enable_interrupts(trans);
@@ -1270,9 +1286,10 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
trans_pcie->inta |= inta;
/* iwl_pcie_tasklet() will service interrupts and re-enable them */
- if (likely(inta))
- tasklet_schedule(&trans_pcie->irq_tasklet);
- else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+ if (likely(inta)) {
+ spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+ return IRQ_WAKE_THREAD;
+ } else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
!trans_pcie->inta) {
/* Allow interrupt if was disabled by this handler and
* no tasklet was schedules, We should not enable interrupt,
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 35708b959ad6..17bedc50e753 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2013 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 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -75,21 +75,43 @@
#include "iwl-agn-hw.h"
#include "internal.h"
-static void iwl_pcie_set_pwr_vmain(struct iwl_trans *trans)
+static void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans,
+ u32 reg, u32 mask, u32 value)
{
-/*
- * (for documentation purposes)
- * to set power to V_AUX, do:
+ u32 v;
- if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
- iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
- ~APMG_PS_CTRL_MSK_PWR_SRC);
- */
+#ifdef CONFIG_IWLWIFI_DEBUG
+ WARN_ON_ONCE(value & ~mask);
+#endif
- iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
- ~APMG_PS_CTRL_MSK_PWR_SRC);
+ v = iwl_read32(trans, reg);
+ v &= ~mask;
+ v |= value;
+ iwl_write32(trans, reg, v);
+}
+
+static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans,
+ u32 reg, u32 mask)
+{
+ __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0);
+}
+
+static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
+ u32 reg, u32 mask)
+{
+ __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask);
+}
+
+static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
+{
+ if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
+ iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+ else
+ iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
}
/* PCI registers */
@@ -259,7 +281,7 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans)
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
- iwl_pcie_set_pwr_vmain(trans);
+ iwl_pcie_set_pwr(trans, false);
iwl_op_mode_nic_config(trans->op_mode);
@@ -435,7 +457,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
}
static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
- const struct fw_img *fw)
+ const struct fw_img *fw, bool run_in_rfkill)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret;
@@ -454,7 +476,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
/* If platform's RF_KILL switch is NOT set to KILL */
hw_rfkill = iwl_is_rfkill_set(trans);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
- if (hw_rfkill)
+ if (hw_rfkill && !run_in_rfkill)
return -ERFKILL;
iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
@@ -534,12 +556,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
iwl_enable_rfkill_int(trans);
- /* wait to make sure we flush pending tasklet*/
- synchronize_irq(trans_pcie->irq);
- tasklet_kill(&trans_pcie->irq_tasklet);
-
- cancel_work_sync(&trans_pcie->rx_replenish);
-
/* stop and reset the on-board processor */
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
@@ -551,46 +567,87 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
clear_bit(STATUS_RFKILL, &trans_pcie->status);
}
-static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
+static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
{
/* let the ucode operate on its own */
iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
iwl_disable_interrupts(trans);
+ iwl_pcie_disable_ict(trans);
+
iwl_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ iwl_clear_bit(trans, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ /*
+ * reset TX queues -- some of their registers reset during S3
+ * so if we don't reset everything here the D3 image would try
+ * to execute some invalid memory upon resume
+ */
+ iwl_trans_pcie_tx_reset(trans);
+
+ iwl_pcie_set_pwr(trans, true);
}
-static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
+static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
+ enum iwl_d3_status *status)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- int err;
- bool hw_rfkill;
+ u32 val;
+ int ret;
- trans_pcie->inta_mask = CSR_INI_SET_MASK;
+ iwl_pcie_set_pwr(trans, false);
- if (!trans_pcie->irq_requested) {
- tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
- iwl_pcie_tasklet, (unsigned long)trans);
+ val = iwl_read32(trans, CSR_RESET);
+ if (val & CSR_RESET_REG_FLAG_NEVO_RESET) {
+ *status = IWL_D3_STATUS_RESET;
+ return 0;
+ }
- iwl_pcie_alloc_ict(trans);
+ /*
+ * Also enables interrupts - none will happen as the device doesn't
+ * know we're waking it up, only when the opmode actually tells it
+ * after this call.
+ */
+ iwl_pcie_reset_ict(trans);
- err = request_irq(trans_pcie->irq, iwl_pcie_isr_ict,
- IRQF_SHARED, DRV_NAME, trans);
- if (err) {
- IWL_ERR(trans, "Error allocating IRQ %d\n",
- trans_pcie->irq);
- goto error;
- }
+ iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ 25000);
+ if (ret) {
+ IWL_ERR(trans, "Failed to resume the device (mac ready)\n");
+ return ret;
+ }
- trans_pcie->irq_requested = true;
+ iwl_trans_pcie_tx_reset(trans);
+
+ ret = iwl_pcie_rx_init(trans);
+ if (ret) {
+ IWL_ERR(trans, "Failed to resume the device (RX reset)\n");
+ return ret;
}
+ iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+ *status = IWL_D3_STATUS_ALIVE;
+ return 0;
+}
+
+static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
+{
+ bool hw_rfkill;
+ int err;
+
err = iwl_pcie_prepare_card_hw(trans);
if (err) {
IWL_ERR(trans, "Error while preparing HW: %d\n", err);
- goto err_free_irq;
+ return err;
}
iwl_pcie_apm_init(trans);
@@ -601,15 +658,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
hw_rfkill = iwl_is_rfkill_set(trans);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
- return err;
-
-err_free_irq:
- trans_pcie->irq_requested = false;
- free_irq(trans_pcie->irq, trans);
-error:
- iwl_pcie_free_ict(trans);
- tasklet_kill(&trans_pcie->irq_tasklet);
- return err;
+ return 0;
}
static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
@@ -703,19 +752,20 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
trans_pcie->command_names = trans_cfg->command_names;
+ trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
}
void iwl_trans_pcie_free(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ synchronize_irq(trans_pcie->pci_dev->irq);
+
iwl_pcie_tx_free(trans);
iwl_pcie_rx_free(trans);
- if (trans_pcie->irq_requested == true) {
- free_irq(trans_pcie->irq, trans);
- iwl_pcie_free_ict(trans);
- }
+ free_irq(trans_pcie->pci_dev->irq, trans);
+ iwl_pcie_free_ict(trans);
pci_disable_msi(trans_pcie->pci_dev);
iounmap(trans_pcie->hw_base);
@@ -751,13 +801,126 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
hw_rfkill = iwl_is_rfkill_set(trans);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
- if (!hw_rfkill)
- iwl_enable_interrupts(trans);
-
return 0;
}
#endif /* CONFIG_PM_SLEEP */
+static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
+ unsigned long *flags)
+{
+ int ret;
+ struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans);
+ spin_lock_irqsave(&pcie_trans->reg_lock, *flags);
+
+ /* this bit wakes up the NIC */
+ __iwl_trans_pcie_set_bit(trans, 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(trans, 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 (unlikely(ret < 0)) {
+ iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
+ if (!silent) {
+ u32 val = iwl_read32(trans, CSR_GP_CNTRL);
+ WARN_ONCE(1,
+ "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
+ val);
+ spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags);
+ return false;
+ }
+ }
+
+ /*
+ * Fool sparse by faking we release the lock - sparse will
+ * track nic_access anyway.
+ */
+ __release(&pcie_trans->reg_lock);
+ return true;
+}
+
+static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
+ unsigned long *flags)
+{
+ struct iwl_trans_pcie *pcie_trans = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ lockdep_assert_held(&pcie_trans->reg_lock);
+
+ /*
+ * Fool sparse by faking we acquiring the lock - sparse will
+ * track nic_access anyway.
+ */
+ __acquire(&pcie_trans->reg_lock);
+
+ __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ /*
+ * Above we read the CSR_GP_CNTRL register, which will flush
+ * any previous writes, but we need the write that clears the
+ * MAC_ACCESS_REQ bit to be performed before any other writes
+ * scheduled on different CPUs (after we drop reg_lock).
+ */
+ mmiowb();
+ spin_unlock_irqrestore(&pcie_trans->reg_lock, *flags);
+}
+
+static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords)
+{
+ unsigned long flags;
+ int offs, ret = 0;
+ u32 *vals = buf;
+
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+ iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
+ for (offs = 0; offs < dwords; offs++)
+ vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+ iwl_trans_release_nic_access(trans, &flags);
+ } else {
+ ret = -EBUSY;
+ }
+ return ret;
+}
+
+static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
+ void *buf, int dwords)
+{
+ unsigned long flags;
+ int offs, ret = 0;
+ u32 *vals = buf;
+
+ if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+ iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
+ for (offs = 0; offs < dwords; offs++)
+ iwl_write32(trans, HBUS_TARG_MEM_WDAT,
+ vals ? vals[offs] : 0);
+ iwl_trans_release_nic_access(trans, &flags);
+ } else {
+ ret = -EBUSY;
+ }
+ return ret;
+}
+
#define IWL_FLUSH_WAIT_MS 2000
static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
@@ -767,6 +930,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
struct iwl_queue *q;
int cnt;
unsigned long now = jiffies;
+ u32 scd_sram_addr;
+ u8 buf[16];
int ret = 0;
/* waiting for all the tx frames complete might take a while */
@@ -780,14 +945,64 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
msleep(1);
if (q->read_ptr != q->write_ptr) {
- IWL_ERR(trans, "fail to flush all tx fifo queues\n");
+ IWL_ERR(trans,
+ "fail to flush all tx fifo queues Q %d\n", cnt);
ret = -ETIMEDOUT;
break;
}
}
+
+ if (!ret)
+ return 0;
+
+ IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
+ txq->q.read_ptr, txq->q.write_ptr);
+
+ scd_sram_addr = trans_pcie->scd_base_addr +
+ SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
+ iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
+
+ iwl_print_hex_error(trans, buf, sizeof(buf));
+
+ for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++)
+ IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt,
+ iwl_read_direct32(trans, FH_TX_TRB_REG(cnt)));
+
+ for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
+ u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt));
+ u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
+ bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
+ u32 tbl_dw =
+ iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr +
+ SCD_TRANS_TBL_OFFSET_QUEUE(cnt));
+
+ if (cnt & 0x1)
+ tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
+ else
+ tbl_dw = tbl_dw & 0x0000FFFF;
+
+ IWL_ERR(trans,
+ "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
+ cnt, active ? "" : "in", fifo, tbl_dw,
+ iwl_read_prph(trans,
+ SCD_QUEUE_RDPTR(cnt)) & (txq->q.n_bd - 1),
+ iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt)));
+ }
+
return ret;
}
+static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
+ u32 mask, u32 value)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ unsigned long flags;
+
+ spin_lock_irqsave(&trans_pcie->reg_lock, flags);
+ __iwl_trans_pcie_set_bits_mask(trans, reg, mask, value);
+ spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
+}
+
static const char *get_fh_string(int cmd)
{
#define IWL_CMD(x) case x: return #x
@@ -1212,7 +1427,8 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.start_fw = iwl_trans_pcie_start_fw,
.stop_device = iwl_trans_pcie_stop_device,
- .wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
+ .d3_suspend = iwl_trans_pcie_d3_suspend,
+ .d3_resume = iwl_trans_pcie_d3_resume,
.send_cmd = iwl_trans_pcie_send_hcmd,
@@ -1235,8 +1451,13 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.read32 = iwl_trans_pcie_read32,
.read_prph = iwl_trans_pcie_read_prph,
.write_prph = iwl_trans_pcie_write_prph,
+ .read_mem = iwl_trans_pcie_read_mem,
+ .write_mem = iwl_trans_pcie_write_mem,
.configure = iwl_trans_pcie_configure,
.set_pmi = iwl_trans_pcie_set_pmi,
+ .grab_nic_access = iwl_trans_pcie_grab_nic_access,
+ .release_nic_access = iwl_trans_pcie_release_nic_access,
+ .set_bits_mask = iwl_trans_pcie_set_bits_mask,
};
struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
@@ -1258,8 +1479,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
trans->ops = &trans_ops_pcie;
trans->cfg = cfg;
+ trans_lockdep_init(trans);
trans_pcie->trans = trans;
spin_lock_init(&trans_pcie->irq_lock);
+ spin_lock_init(&trans_pcie->reg_lock);
init_waitqueue_head(&trans_pcie->ucode_write_waitq);
/* W/A - seems to solve weird behavior. We need to remove this if we
@@ -1318,7 +1541,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
}
trans->dev = &pdev->dev;
- trans_pcie->irq = pdev->irq;
trans_pcie->pci_dev = pdev;
trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
@@ -1327,7 +1549,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
/* Initialize the wait queue for commands */
init_waitqueue_head(&trans_pcie->wait_command_queue);
- spin_lock_init(&trans->reg_lock);
snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
"iwl_cmd_pool:%s", dev_name(trans->dev));
@@ -1344,8 +1565,24 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
if (!trans->dev_cmd_pool)
goto out_pci_disable_msi;
+ trans_pcie->inta_mask = CSR_INI_SET_MASK;
+
+ if (iwl_pcie_alloc_ict(trans))
+ goto out_free_cmd_pool;
+
+ if (request_threaded_irq(pdev->irq, iwl_pcie_isr_ict,
+ iwl_pcie_irq_handler,
+ IRQF_SHARED, DRV_NAME, trans)) {
+ IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
+ goto out_free_ict;
+ }
+
return trans;
+out_free_ict:
+ iwl_pcie_free_ict(trans);
+out_free_cmd_pool:
+ kmem_cache_destroy(trans->dev_cmd_pool);
out_pci_disable_msi:
pci_disable_msi(pdev);
out_pci_release_regions:
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 6c5b867c353a..8e9e3212fe78 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2013 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.
@@ -160,7 +160,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
txq->q.read_ptr, txq->q.write_ptr);
- iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
+ iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
iwl_print_hex_error(trans, buf, sizeof(buf));
@@ -173,9 +173,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
u32 tbl_dw =
- iwl_read_targ_mem(trans,
- trans_pcie->scd_base_addr +
- SCD_TRANS_TBL_OFFSET_QUEUE(i));
+ iwl_trans_read_mem32(trans,
+ trans_pcie->scd_base_addr +
+ SCD_TRANS_TBL_OFFSET_QUEUE(i));
if (i & 0x1)
tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
@@ -237,7 +237,10 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
break;
}
- bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
+ if (trans_pcie->bc_table_dword)
+ len = DIV_ROUND_UP(len, 4);
+
+ bc_ent = cpu_to_le16(len | (sta_id << 12));
scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
@@ -306,6 +309,9 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
return;
}
+ IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id,
+ txq->q.write_ptr);
+
iwl_write_direct32(trans, HBUS_TARG_WRPTR,
txq->q.write_ptr | (txq_id << 8));
@@ -612,7 +618,7 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
if (txq->q.n_bd) {
dma_free_coherent(dev, sizeof(struct iwl_tfd) *
txq->q.n_bd, txq->tfds, txq->q.dma_addr);
- memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
+ txq->q.dma_addr = 0;
}
kfree(txq->entries);
@@ -638,9 +644,11 @@ static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask)
void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- u32 a;
+ int nq = trans->cfg->base_params->num_of_queues;
int chan;
u32 reg_val;
+ int clear_dwords = (SCD_TRANS_TBL_OFFSET_QUEUE(nq) -
+ SCD_CONTEXT_MEM_LOWER_BOUND) / sizeof(u32);
/* make sure all queue are not stopped/used */
memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
@@ -652,20 +660,10 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
WARN_ON(scd_base_addr != 0 &&
scd_base_addr != trans_pcie->scd_base_addr);
- a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
- /* reset conext data memory */
- for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
- a += 4)
- iwl_write_targ_mem(trans, a, 0);
- /* reset tx status memory */
- for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
- a += 4)
- iwl_write_targ_mem(trans, a, 0);
- for (; a < trans_pcie->scd_base_addr +
- SCD_TRANS_TBL_OFFSET_QUEUE(
- trans->cfg->base_params->num_of_queues);
- a += 4)
- iwl_write_targ_mem(trans, a, 0);
+ /* reset context data, TX status and translation data */
+ iwl_trans_write_mem(trans, trans_pcie->scd_base_addr +
+ SCD_CONTEXT_MEM_LOWER_BOUND,
+ NULL, clear_dwords);
iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
trans_pcie->scd_bc_tbls.dma >> 10);
@@ -697,6 +695,29 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
}
+void iwl_trans_pcie_tx_reset(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ int txq_id;
+
+ for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+ txq_id++) {
+ struct iwl_txq *txq = &trans_pcie->txq[txq_id];
+
+ iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
+ txq->q.dma_addr >> 8);
+ iwl_pcie_txq_unmap(trans, txq_id);
+ txq->q.read_ptr = 0;
+ txq->q.write_ptr = 0;
+ }
+
+ /* Tell NIC where to find the "keep warm" buffer */
+ iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
+ trans_pcie->kw.dma >> 4);
+
+ iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr);
+}
+
/*
* iwl_pcie_tx_stop - Stop all Tx DMA channels
*/
@@ -905,7 +926,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
if (WARN_ON(txq_id == trans_pcie->cmd_queue))
return;
- spin_lock(&txq->lock);
+ spin_lock_bh(&txq->lock);
if (txq->q.read_ptr == tfd_num)
goto out;
@@ -949,7 +970,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
if (iwl_queue_space(&txq->q) > txq->q.low_mark)
iwl_wake_queue(trans, txq);
out:
- spin_unlock(&txq->lock);
+ spin_unlock_bh(&txq->lock);
}
/*
@@ -1002,14 +1023,14 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
tbl_dw_addr = trans_pcie->scd_base_addr +
SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);
- tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr);
+ tbl_dw = iwl_trans_read_mem32(trans, tbl_dw_addr);
if (txq_id & 0x1)
tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
else
tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
- iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw);
+ iwl_trans_write_mem32(trans, tbl_dw_addr, tbl_dw);
return 0;
}
@@ -1068,9 +1089,9 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
/* Set up Tx window size and frame limit for this queue */
- iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+ iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
- iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+ iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
@@ -1101,8 +1122,8 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
iwl_pcie_txq_set_inactive(trans, txq_id);
- _iwl_write_targ_mem_dwords(trans, stts_addr,
- zero_val, ARRAY_SIZE(zero_val));
+ iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
+ ARRAY_SIZE(zero_val));
iwl_pcie_txq_unmap(trans, txq_id);
@@ -1350,7 +1371,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
return;
}
- spin_lock(&txq->lock);
+ spin_lock_bh(&txq->lock);
cmd_index = get_cmd_index(&txq->q, index);
cmd = txq->entries[cmd_index].cmd;
@@ -1384,7 +1405,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
meta->flags = 0;
- spin_unlock(&txq->lock);
+ spin_unlock_bh(&txq->lock);
}
#define HOST_COMPLETE_TIMEOUT (2 * HZ)
@@ -1642,10 +1663,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
- IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
- le16_to_cpu(dev_cmd->hdr.sequence));
- IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
-
/* Set up entry for this TFD in Tx byte-count array */
iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index ec6d5d6b452e..116f4aba08d6 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -657,7 +657,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
capa, intvl, ie, ielen,
LBS_SCAN_RSSI_TO_MBM(rssi),
GFP_KERNEL);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
}
} else
lbs_deb_scan("scan response: missing BSS channel IE\n");
@@ -1444,7 +1444,7 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
done:
if (bss)
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
return ret;
}
@@ -1766,7 +1766,7 @@ static void lbs_join_post(struct lbs_private *priv,
params->beacon_interval,
fake_ie, fake - fake_ie,
0, GFP_KERNEL);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(priv->wdev->wiphy, bss);
memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
priv->wdev->ssid_len = params->ssid_len;
@@ -2011,7 +2011,7 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
if (bss) {
ret = lbs_ibss_join_existing(priv, params, bss);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(wiphy, bss);
} else
ret = lbs_ibss_start_new(priv, params);
@@ -2081,10 +2081,8 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev)
lbs_deb_enter(LBS_DEB_CFG80211);
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
- if (!wdev) {
- dev_err(dev, "cannot allocate wireless device\n");
+ if (!wdev)
return ERR_PTR(-ENOMEM);
- }
wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private));
if (!wdev->wiphy) {
@@ -2132,6 +2130,21 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_CFG80211);
}
+static void lbs_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
+ "callback for domain %c%c\n", request->alpha2[0],
+ request->alpha2[1]);
+
+ memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
+ if (lbs_iface_active(priv))
+ lbs_set_11d_domain_info(priv);
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+}
/*
* This function get's called after lbs_setup_firmware() determined the
@@ -2184,24 +2197,6 @@ int lbs_cfg_register(struct lbs_private *priv)
return ret;
}
-int lbs_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
-{
- struct lbs_private *priv = wiphy_priv(wiphy);
- int ret = 0;
-
- lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
- "callback for domain %c%c\n", request->alpha2[0],
- request->alpha2[1]);
-
- memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
- if (lbs_iface_active(priv))
- ret = lbs_set_11d_domain_info(priv);
-
- lbs_deb_leave(LBS_DEB_CFG80211);
- return ret;
-}
-
void lbs_scan_deinit(struct lbs_private *priv)
{
lbs_deb_enter(LBS_DEB_CFG80211);
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index 558168ce634d..10995f59fe34 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -10,9 +10,6 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev);
int lbs_cfg_register(struct lbs_private *priv);
void lbs_cfg_free(struct lbs_private *priv);
-int lbs_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request);
-
void lbs_send_disconnect_notification(struct lbs_private *priv);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index ff9085502bea..cffdf4fbf161 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -48,6 +48,10 @@ static int channels = 1;
module_param(channels, int, 0444);
MODULE_PARM_DESC(channels, "Number of concurrent channels");
+static bool paged_rx = false;
+module_param(paged_rx, bool, 0644);
+MODULE_PARM_DESC(paged_rx, "Use paged SKBs for RX instead of linear ones");
+
/**
* enum hwsim_regtest - the type of regulatory tests we offer
*
@@ -333,11 +337,11 @@ struct mac80211_hwsim_data {
int scan_chan_idx;
struct ieee80211_channel *channel;
- unsigned long beacon_int; /* in jiffies unit */
+ u64 beacon_int /* beacon interval in us */;
unsigned int rx_filter;
bool started, idle, scanning;
struct mutex mutex;
- struct timer_list beacon_timer;
+ struct tasklet_hrtimer beacon_timer;
enum ps_mode {
PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
} ps;
@@ -357,7 +361,10 @@ struct mac80211_hwsim_data {
int power_level;
/* difference between this hw's clock and the real clock, in usecs */
- u64 tsf_offset;
+ s64 tsf_offset;
+ s64 bcn_delta;
+ /* absolute beacon transmission time. Used to cover up "tx" delay. */
+ u64 abs_bcn_ts;
};
@@ -405,15 +412,19 @@ static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
+static inline u64 mac80211_hwsim_get_tsf_raw(void)
+{
+ return ktime_to_us(ktime_get_real());
+}
+
static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data)
{
- struct timeval tv = ktime_to_timeval(ktime_get_real());
- u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
+ u64 now = mac80211_hwsim_get_tsf_raw();
return cpu_to_le64(now + data->tsf_offset);
}
static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+ struct ieee80211_vif *vif)
{
struct mac80211_hwsim_data *data = hw->priv;
return le64_to_cpu(__mac80211_hwsim_get_tsf(data));
@@ -423,9 +434,13 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u64 tsf)
{
struct mac80211_hwsim_data *data = hw->priv;
- struct timeval tv = ktime_to_timeval(ktime_get_real());
- u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
- data->tsf_offset = tsf - now;
+ u64 now = mac80211_hwsim_get_tsf(hw, vif);
+ u32 bcn_int = data->beacon_int;
+ s64 delta = tsf - now;
+
+ data->tsf_offset += delta;
+ /* adjust after beaconing with new timestamp at old TBTT */
+ data->bcn_delta = do_div(delta, bcn_int);
}
static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
@@ -696,7 +711,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_rx_status rx_status;
- struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
+ u64 now;
memset(&rx_status, 0, sizeof(rx_status));
rx_status.flag |= RX_FLAG_MACTIME_START;
@@ -722,11 +737,23 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
secpath_reset(skb);
nf_reset(skb);
+ /*
+ * Get absolute mactime here so all HWs RX at the "same time", and
+ * absolute TX time for beacon mactime so the timestamp matches.
+ * Giving beacons a different mactime than non-beacons looks messy, but
+ * it helps the Toffset be exact and a ~10us mactime discrepancy
+ * probably doesn't really matter.
+ */
+ if (ieee80211_is_beacon(hdr->frame_control) ||
+ ieee80211_is_probe_resp(hdr->frame_control))
+ now = data->abs_bcn_ts;
+ else
+ now = mac80211_hwsim_get_tsf_raw();
+
/* Copy skb to all enabled radios that are on the current frequency */
spin_lock(&hwsim_radio_lock);
list_for_each_entry(data2, &hwsim_radios, list) {
struct sk_buff *nskb;
- struct ieee80211_mgmt *mgmt;
struct tx_iter_data tx_iter_data = {
.receive = false,
.channel = chan,
@@ -755,24 +782,30 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
* reserve some space for our vendor and the normal
* radiotap header, since we're copying anyway
*/
- nskb = skb_copy_expand(skb, 64, 0, GFP_ATOMIC);
- if (nskb == NULL)
- continue;
+ if (skb->len < PAGE_SIZE && paged_rx) {
+ struct page *page = alloc_page(GFP_ATOMIC);
+
+ if (!page)
+ continue;
+
+ nskb = dev_alloc_skb(128);
+ if (!nskb) {
+ __free_page(page);
+ continue;
+ }
+
+ memcpy(page_address(page), skb->data, skb->len);
+ skb_add_rx_frag(nskb, 0, page, 0, skb->len, skb->len);
+ } else {
+ nskb = skb_copy(skb, GFP_ATOMIC);
+ if (!nskb)
+ continue;
+ }
if (mac80211_hwsim_addr_match(data2, hdr->addr1))
ack = true;
- /* set bcn timestamp relative to receiver mactime */
- rx_status.mactime =
- le64_to_cpu(__mac80211_hwsim_get_tsf(data2));
- mgmt = (struct ieee80211_mgmt *) nskb->data;
- if (ieee80211_is_beacon(mgmt->frame_control) ||
- ieee80211_is_probe_resp(mgmt->frame_control))
- mgmt->u.beacon.timestamp = cpu_to_le64(
- rx_status.mactime +
- (data->tsf_offset - data2->tsf_offset) +
- 24 * 8 * 10 / txrate->bitrate);
-
+ rx_status.mactime = now + data2->tsf_offset;
#if 0
/*
* Don't enable this code by default as the OUI 00:00:00
@@ -896,7 +929,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
{
struct mac80211_hwsim_data *data = hw->priv;
data->started = false;
- del_timer(&data->beacon_timer);
+ tasklet_hrtimer_cancel(&data->beacon_timer);
wiphy_debug(hw->wiphy, "%s\n", __func__);
}
@@ -962,7 +995,11 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
struct ieee80211_vif *vif)
{
- struct ieee80211_hw *hw = arg;
+ struct mac80211_hwsim_data *data = arg;
+ struct ieee80211_hw *hw = data->hw;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_rate *txrate;
+ struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
hwsim_check_magic(vif);
@@ -975,26 +1012,48 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
skb = ieee80211_beacon_get(hw, vif);
if (skb == NULL)
return;
+ info = IEEE80211_SKB_CB(skb);
+ txrate = ieee80211_get_tx_rate(hw, info);
+
+ mgmt = (struct ieee80211_mgmt *) skb->data;
+ /* fake header transmission time */
+ data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw();
+ mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts +
+ data->tsf_offset +
+ 24 * 8 * 10 / txrate->bitrate);
mac80211_hwsim_tx_frame(hw, skb,
rcu_dereference(vif->chanctx_conf)->def.chan);
}
-
-static void mac80211_hwsim_beacon(unsigned long arg)
+static enum hrtimer_restart
+mac80211_hwsim_beacon(struct hrtimer *timer)
{
- struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
- struct mac80211_hwsim_data *data = hw->priv;
+ struct mac80211_hwsim_data *data =
+ container_of(timer, struct mac80211_hwsim_data,
+ beacon_timer.timer);
+ struct ieee80211_hw *hw = data->hw;
+ u64 bcn_int = data->beacon_int;
+ ktime_t next_bcn;
if (!data->started)
- return;
+ goto out;
ieee80211_iterate_active_interfaces_atomic(
hw, IEEE80211_IFACE_ITER_NORMAL,
- mac80211_hwsim_beacon_tx, hw);
+ mac80211_hwsim_beacon_tx, data);
+
+ /* beacon at new TBTT + beacon interval */
+ if (data->bcn_delta) {
+ bcn_int -= data->bcn_delta;
+ data->bcn_delta = 0;
+ }
- data->beacon_timer.expires = jiffies + data->beacon_int;
- add_timer(&data->beacon_timer);
+ next_bcn = ktime_add(hrtimer_get_expires(timer),
+ ns_to_ktime(bcn_int * 1000));
+ tasklet_hrtimer_start(&data->beacon_timer, next_bcn, HRTIMER_MODE_ABS);
+out:
+ return HRTIMER_NORESTART;
}
static const char *hwsim_chantypes[] = {
@@ -1032,9 +1091,16 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
data->power_level = conf->power_level;
if (!data->started || !data->beacon_int)
- del_timer(&data->beacon_timer);
- else
- mod_timer(&data->beacon_timer, jiffies + data->beacon_int);
+ tasklet_hrtimer_cancel(&data->beacon_timer);
+ else if (!hrtimer_is_queued(&data->beacon_timer.timer)) {
+ u64 tsf = mac80211_hwsim_get_tsf(hw, NULL);
+ u32 bcn_int = data->beacon_int;
+ u64 until_tbtt = bcn_int - do_div(tsf, bcn_int);
+
+ tasklet_hrtimer_start(&data->beacon_timer,
+ ns_to_ktime(until_tbtt * 1000),
+ HRTIMER_MODE_REL);
+ }
return 0;
}
@@ -1084,12 +1150,26 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BEACON_INT) {
wiphy_debug(hw->wiphy, " BCNINT: %d\n", info->beacon_int);
- data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000;
- if (WARN_ON(!data->beacon_int))
- data->beacon_int = 1;
- if (data->started)
- mod_timer(&data->beacon_timer,
- jiffies + data->beacon_int);
+ data->beacon_int = info->beacon_int * 1024;
+ }
+
+ if (changed & BSS_CHANGED_BEACON_ENABLED) {
+ wiphy_debug(hw->wiphy, " BCN EN: %d\n", info->enable_beacon);
+ if (data->started &&
+ !hrtimer_is_queued(&data->beacon_timer.timer) &&
+ info->enable_beacon) {
+ u64 tsf, until_tbtt;
+ u32 bcn_int;
+ if (WARN_ON(!data->beacon_int))
+ data->beacon_int = 1000 * 1024;
+ tsf = mac80211_hwsim_get_tsf(hw, vif);
+ bcn_int = data->beacon_int;
+ until_tbtt = bcn_int - do_div(tsf, bcn_int);
+ tasklet_hrtimer_start(&data->beacon_timer,
+ ns_to_ktime(until_tbtt * 1000),
+ HRTIMER_MODE_REL);
+ } else if (!info->enable_beacon)
+ tasklet_hrtimer_cancel(&data->beacon_timer);
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
@@ -1292,7 +1372,9 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_TX_START:
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
@@ -2165,6 +2247,7 @@ static int __init init_mac80211_hwsim(void)
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
hw->sta_data_size = sizeof(struct hwsim_sta_priv);
+ hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv);
memcpy(data->channels_2ghz, hwsim_channels_2ghz,
sizeof(hwsim_channels_2ghz));
@@ -2370,8 +2453,9 @@ static int __init init_mac80211_hwsim(void)
data->debugfs, data,
&hwsim_fops_group);
- setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
- (unsigned long) hw);
+ tasklet_hrtimer_init(&data->beacon_timer,
+ mac80211_hwsim_beacon,
+ CLOCK_REALTIME, HRTIMER_MODE_ABS);
list_add_tail(&data->list, &hwsim_radios);
}
diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c
new file mode 100644
index 000000000000..cf43b3c29250
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11ac.c
@@ -0,0 +1,261 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11ac
+ *
+ * Copyright (C) 2013, 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 "fw.h"
+#include "main.h"
+#include "11ac.h"
+
+/* This function converts the 2-bit MCS map to the highest long GI
+ * VHT data rate.
+ */
+static u16
+mwifiex_convert_mcsmap_to_maxrate(struct mwifiex_private *priv,
+ u8 bands, u16 mcs_map)
+{
+ u8 i, nss, max_mcs;
+ u16 max_rate = 0;
+ u32 usr_vht_cap_info = 0;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ /* tables of the MCS map to the highest data rate (in Mbps)
+ * supported for long GI
+ */
+ u16 max_rate_lgi_80MHZ[8][3] = {
+ {0x124, 0x15F, 0x186}, /* NSS = 1 */
+ {0x249, 0x2BE, 0x30C}, /* NSS = 2 */
+ {0x36D, 0x41D, 0x492}, /* NSS = 3 */
+ {0x492, 0x57C, 0x618}, /* NSS = 4 */
+ {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */
+ {0x6DB, 0x83A, 0x0}, /* NSS = 6 */
+ {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */
+ {0x924, 0xAF8, 0xC30} /* NSS = 8 */
+ };
+ u16 max_rate_lgi_160MHZ[8][3] = {
+ {0x249, 0x2BE, 0x30C}, /* NSS = 1 */
+ {0x492, 0x57C, 0x618}, /* NSS = 2 */
+ {0x6DB, 0x83A, 0x0}, /* NSS = 3 */
+ {0x924, 0xAF8, 0xC30}, /* NSS = 4 */
+ {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */
+ {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
+ {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
+ {0x1248, 0x15F0, 0x1860} /* NSS = 8 */
+ };
+
+ if (bands & BAND_AAC)
+ usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
+ else
+ usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
+
+ /* find the max NSS supported */
+ nss = 0;
+ for (i = 0; i < 8; i++) {
+ max_mcs = (mcs_map >> (2 * i)) & 0x3;
+ if (max_mcs < 3)
+ nss = i;
+ }
+ max_mcs = (mcs_map >> (2 * nss)) & 0x3;
+
+ /* if max_mcs is 3, nss must be 0 (SS = 1). Thus, max mcs is MCS 9 */
+ if (max_mcs >= 3)
+ max_mcs = 2;
+
+ if (GET_VHTCAP_CHWDSET(usr_vht_cap_info)) {
+ /* support 160 MHz */
+ max_rate = max_rate_lgi_160MHZ[nss][max_mcs];
+ if (!max_rate)
+ /* MCS9 is not supported in NSS6 */
+ max_rate = max_rate_lgi_160MHZ[nss][max_mcs - 1];
+ } else {
+ max_rate = max_rate_lgi_80MHZ[nss][max_mcs];
+ if (!max_rate)
+ /* MCS9 is not supported in NSS3 */
+ max_rate = max_rate_lgi_80MHZ[nss][max_mcs - 1];
+ }
+
+ return max_rate;
+}
+
+static void
+mwifiex_fill_vht_cap_info(struct mwifiex_private *priv,
+ struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ if (bands & BAND_A)
+ vht_cap->vht_cap.vht_cap_info =
+ cpu_to_le32(adapter->usr_dot_11ac_dev_cap_a);
+ else
+ vht_cap->vht_cap.vht_cap_info =
+ cpu_to_le32(adapter->usr_dot_11ac_dev_cap_bg);
+}
+
+static void
+mwifiex_fill_vht_cap_tlv(struct mwifiex_private *priv,
+ struct mwifiex_ie_types_vhtcap *vht_cap, u8 bands)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u16 mcs_map_user, mcs_map_resp, mcs_map_result;
+ u16 mcs_user, mcs_resp, nss, tmp;
+
+ /* Fill VHT cap info */
+ mwifiex_fill_vht_cap_info(priv, vht_cap, bands);
+
+ /* rx MCS Set: find the minimum of the user rx mcs and ap rx mcs */
+ mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);
+ mcs_map_resp = le16_to_cpu(vht_cap->vht_cap.supp_mcs.rx_mcs_map);
+ mcs_map_result = 0;
+
+ for (nss = 1; nss <= 8; nss++) {
+ mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
+ mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
+
+ if ((mcs_user == NO_NSS_SUPPORT) ||
+ (mcs_resp == NO_NSS_SUPPORT))
+ SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
+ else
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ min(mcs_user, mcs_resp));
+ }
+
+ vht_cap->vht_cap.supp_mcs.rx_mcs_map = cpu_to_le16(mcs_map_result);
+
+ tmp = mwifiex_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
+ vht_cap->vht_cap.supp_mcs.rx_highest = cpu_to_le16(tmp);
+
+ /* tx MCS Set: find the minimum of the user tx mcs and ap tx mcs */
+ mcs_map_user = GET_DEVTXMCSMAP(adapter->usr_dot_11ac_mcs_support);
+ mcs_map_resp = le16_to_cpu(vht_cap->vht_cap.supp_mcs.tx_mcs_map);
+ mcs_map_result = 0;
+
+ for (nss = 1; nss <= 8; nss++) {
+ mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
+ mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
+ if ((mcs_user == NO_NSS_SUPPORT) ||
+ (mcs_resp == NO_NSS_SUPPORT))
+ SET_VHTNSSMCS(mcs_map_result, nss, NO_NSS_SUPPORT);
+ else
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ min(mcs_user, mcs_resp));
+ }
+
+ vht_cap->vht_cap.supp_mcs.tx_mcs_map = cpu_to_le16(mcs_map_result);
+
+ tmp = mwifiex_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
+ vht_cap->vht_cap.supp_mcs.tx_highest = cpu_to_le16(tmp);
+
+ return;
+}
+
+int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc,
+ u8 **buffer)
+{
+ struct mwifiex_ie_types_vhtcap *vht_cap;
+ struct mwifiex_ie_types_oper_mode_ntf *oper_ntf;
+ struct ieee_types_oper_mode_ntf *ieee_oper_ntf;
+ struct mwifiex_ie_types_vht_oper *vht_op;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u8 supp_chwd_set;
+ u32 usr_vht_cap_info;
+ int ret_len = 0;
+
+ if (bss_desc->bss_band & BAND_A)
+ usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
+ else
+ usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
+
+ /* VHT Capabilities IE */
+ if (bss_desc->bcn_vht_cap) {
+ vht_cap = (struct mwifiex_ie_types_vhtcap *)*buffer;
+ memset(vht_cap, 0, sizeof(*vht_cap));
+ vht_cap->header.type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY);
+ vht_cap->header.len =
+ cpu_to_le16(sizeof(struct ieee80211_vht_cap));
+ memcpy((u8 *)vht_cap + sizeof(struct mwifiex_ie_types_header),
+ (u8 *)bss_desc->bcn_vht_cap +
+ sizeof(struct ieee_types_header),
+ le16_to_cpu(vht_cap->header.len));
+
+ mwifiex_fill_vht_cap_tlv(priv, vht_cap, bss_desc->bss_band);
+ *buffer += sizeof(*vht_cap);
+ ret_len += sizeof(*vht_cap);
+ }
+
+ /* VHT Operation IE */
+ if (bss_desc->bcn_vht_oper) {
+ if (priv->bss_mode == HostCmd_BSS_MODE_IBSS) {
+ vht_op = (struct mwifiex_ie_types_vht_oper *)*buffer;
+ memset(vht_op, 0, sizeof(*vht_op));
+ vht_op->header.type =
+ cpu_to_le16(WLAN_EID_VHT_OPERATION);
+ vht_op->header.len = cpu_to_le16(sizeof(*vht_op) -
+ sizeof(struct mwifiex_ie_types_header));
+ memcpy((u8 *)vht_op +
+ sizeof(struct mwifiex_ie_types_header),
+ (u8 *)bss_desc->bcn_vht_oper +
+ sizeof(struct ieee_types_header),
+ le16_to_cpu(vht_op->header.len));
+
+ /* negotiate the channel width and central freq
+ * and keep the central freq as the peer suggests
+ */
+ supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);
+
+ switch (supp_chwd_set) {
+ case 0:
+ vht_op->chan_width =
+ min_t(u8, IEEE80211_VHT_CHANWIDTH_80MHZ,
+ bss_desc->bcn_vht_oper->chan_width);
+ break;
+ case 1:
+ vht_op->chan_width =
+ min_t(u8, IEEE80211_VHT_CHANWIDTH_160MHZ,
+ bss_desc->bcn_vht_oper->chan_width);
+ break;
+ case 2:
+ vht_op->chan_width =
+ min_t(u8, IEEE80211_VHT_CHANWIDTH_80P80MHZ,
+ bss_desc->bcn_vht_oper->chan_width);
+ break;
+ default:
+ vht_op->chan_width =
+ IEEE80211_VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+
+ *buffer += sizeof(*vht_op);
+ ret_len += sizeof(*vht_op);
+ }
+ }
+
+ /* Operating Mode Notification IE */
+ if (bss_desc->oper_mode) {
+ ieee_oper_ntf = bss_desc->oper_mode;
+ oper_ntf = (void *)*buffer;
+ memset(oper_ntf, 0, sizeof(*oper_ntf));
+ oper_ntf->header.type = cpu_to_le16(WLAN_EID_OPMODE_NOTIF);
+ oper_ntf->header.len = cpu_to_le16(sizeof(u8));
+ oper_ntf->oper_mode = ieee_oper_ntf->oper_mode;
+ *buffer += sizeof(*oper_ntf);
+ ret_len += sizeof(*oper_ntf);
+ }
+
+ return ret_len;
+}
diff --git a/drivers/net/wireless/mwifiex/11ac.h b/drivers/net/wireless/mwifiex/11ac.h
new file mode 100644
index 000000000000..80fd1ba46200
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11ac.h
@@ -0,0 +1,26 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11ac
+ *
+ * Copyright (C) 2013, 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_11AC_H_
+#define _MWIFIEX_11AC_H_
+
+int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc,
+ u8 **buffer);
+#endif /* _MWIFIEX_11AC_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 245a371f1a43..45f19716687e 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -53,7 +53,9 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
sizeof(sband->ht_cap.mcs));
if (priv->bss_mode == NL80211_IFTYPE_STATION ||
- sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+ (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
+ (priv->adapter->sec_chan_offset !=
+ IEEE80211_HT_PARAM_CHA_SEC_NONE)))
/* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
@@ -248,7 +250,8 @@ int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
* - 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,
+int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action,
struct mwifiex_ds_11n_tx_cfg *txcfg)
{
struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
@@ -258,6 +261,10 @@ int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action,
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);
+
+ if (priv->adapter->is_hw_11ac_capable)
+ htcfg->misc_config = cpu_to_le16(txcfg->misc_config);
+
return 0;
}
@@ -398,45 +405,6 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
}
/*
- * 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.
*/
@@ -531,11 +499,8 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid,
if (!mwifiex_get_ba_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__);
+ if (!new_node)
return;
- }
INIT_LIST_HEAD(&new_node->list);
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
index 46006a54a656..375db01442bf 100644
--- a/drivers/net/wireless/mwifiex/11n.h
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -28,14 +28,12 @@ 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_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action,
+int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action,
struct mwifiex_ds_11n_tx_cfg *txcfg);
-
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,
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index 68d52cfc1ebd..af8fe6352eed 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -278,14 +278,16 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
break;
case -1:
- adapter->data_sent = false;
+ if (adapter->iface_type != MWIFIEX_PCIE)
+ 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, 1, ret);
return 0;
case -EINPROGRESS:
- adapter->data_sent = false;
+ if (adapter->iface_type != MWIFIEX_PCIE)
+ adapter->data_sent = false;
break;
case 0:
mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index 4a97acd170f7..5e796f847088 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -272,11 +272,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
}
/* if !tbl 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__);
+ if (!new_node)
return;
- }
INIT_LIST_HEAD(&new_node->list);
new_node->tid = tid;
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
index b2e27723f801..4f614aad9ded 100644
--- a/drivers/net/wireless/mwifiex/Kconfig
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -20,12 +20,12 @@ config MWIFIEX_SDIO
mwifiex_sdio.
config MWIFIEX_PCIE
- tristate "Marvell WiFi-Ex Driver for PCIE 8766"
+ tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897"
depends on MWIFIEX && PCI
select FW_LOADER
---help---
This adds support for wireless adapters based on Marvell
- 8766 chipset with PCIe interface.
+ 8766/8897 chipsets with PCIe interface.
If you choose to build it as a module, it will be called
mwifiex_pcie.
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index dd0410d2d465..97b245cbafd8 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -23,6 +23,7 @@ mwifiex-y += util.o
mwifiex-y += txrx.o
mwifiex-y += wmm.o
mwifiex-y += 11n.o
+mwifiex-y += 11ac.o
mwifiex-y += 11n_aggr.o
mwifiex-y += 11n_rxreorder.o
mwifiex-y += scan.o
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README
index b55badef4660..3d64613ebb29 100644
--- a/drivers/net/wireless/mwifiex/README
+++ b/drivers/net/wireless/mwifiex/README
@@ -121,7 +121,6 @@ info
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>
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index cdb11b3964e2..a44023a7bd57 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -519,8 +519,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
* - Set by user
* - Set bt Country IE
*/
-static int mwifiex_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
+static void mwifiex_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
{
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
@@ -540,8 +540,6 @@ static int mwifiex_reg_notifier(struct wiphy *wiphy,
break;
}
mwifiex_send_domain_info_cmd_fw(wiphy);
-
- return 0;
}
/*
@@ -836,6 +834,66 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
return ret;
}
+static void
+mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo,
+ struct rate_info *rate)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ if (adapter->is_hw_11ac_capable) {
+ /* bit[1-0]: 00=LG 01=HT 10=VHT */
+ if (tx_htinfo & BIT(0)) {
+ /* HT */
+ rate->mcs = priv->tx_rate;
+ rate->flags |= RATE_INFO_FLAGS_MCS;
+ }
+ if (tx_htinfo & BIT(1)) {
+ /* VHT */
+ rate->mcs = priv->tx_rate & 0x0F;
+ rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
+ }
+
+ if (tx_htinfo & (BIT(1) | BIT(0))) {
+ /* HT or VHT */
+ switch (tx_htinfo & (BIT(3) | BIT(2))) {
+ case 0:
+ /* This will be 20MHz */
+ break;
+ case (BIT(2)):
+ rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ break;
+ case (BIT(3)):
+ rate->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+ break;
+ case (BIT(3) | BIT(2)):
+ rate->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
+ break;
+ }
+
+ if (tx_htinfo & BIT(4))
+ rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+ if ((priv->tx_rate >> 4) == 1)
+ rate->nss = 2;
+ else
+ rate->nss = 1;
+ }
+ } else {
+ /*
+ * Bit 0 in tx_htinfo indicates that current Tx rate
+ * is 11n rate. Valid MCS index values for us are 0 to 15.
+ */
+ if ((tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) {
+ rate->mcs = priv->tx_rate;
+ rate->flags |= RATE_INFO_FLAGS_MCS;
+ if (tx_htinfo & BIT(1))
+ rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ if (tx_htinfo & BIT(2))
+ rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
+ }
+ }
+}
+
/*
* This function dumps the station information on a buffer.
*
@@ -875,20 +933,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
HostCmd_ACT_GEN_GET, DTIM_PERIOD_I,
&priv->dtim_period);
- /*
- * Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid
- * MCS index values for us are 0 to 15.
- */
- if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) {
- sinfo->txrate.mcs = priv->tx_rate;
- sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
- /* 40MHz rate */
- if (priv->tx_htinfo & BIT(1))
- sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
- /* SGI enabled */
- if (priv->tx_htinfo & BIT(2))
- sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
- }
+ mwifiex_parse_htinfo(priv, priv->tx_htinfo, &sinfo->txrate);
sinfo->signal_avg = priv->bcn_rssi_avg;
sinfo->rx_bytes = priv->stats.rx_bytes;
@@ -1297,20 +1342,22 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
/* Set appropriate bands */
if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) {
bss_cfg->band_cfg = BAND_CONFIG_BG;
+ config_bands = BAND_B | BAND_G;
- if (cfg80211_get_chandef_type(&params->chandef) ==
- NL80211_CHAN_NO_HT)
- config_bands = BAND_B | BAND_G;
- else
- config_bands = BAND_B | BAND_G | BAND_GN;
+ if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
+ config_bands |= BAND_GN;
+
+ if (params->chandef.width > NL80211_CHAN_WIDTH_40)
+ config_bands |= BAND_GAC;
} else {
bss_cfg->band_cfg = BAND_CONFIG_A;
+ config_bands = BAND_A;
- if (cfg80211_get_chandef_type(&params->chandef) ==
- NL80211_CHAN_NO_HT)
- config_bands = BAND_A;
- else
- config_bands = BAND_AN | BAND_A;
+ if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
+ config_bands |= BAND_AN;
+
+ if (params->chandef.width > NL80211_CHAN_WIDTH_40)
+ config_bands |= BAND_AAC;
}
if (!((config_bands | priv->adapter->fw_bands) &
@@ -1327,6 +1374,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
}
mwifiex_set_ht_params(priv, bss_cfg, params);
+ mwifiex_set_wmm_params(priv, bss_cfg, params);
if (params->inactivity_timeout > 0) {
/* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */
@@ -1431,7 +1479,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
0, ie_buf, ie_len, 0, GFP_KERNEL);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(priv->wdev->wiphy, bss);
memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
return 0;
@@ -1821,10 +1869,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
GFP_KERNEL);
- if (!priv->user_scan_cfg) {
- dev_err(priv->adapter->dev, "failed to alloc scan_req\n");
+ if (!priv->user_scan_cfg)
return -ENOMEM;
- }
priv->scan_request = request;
@@ -1882,6 +1928,79 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
return 0;
}
+static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info,
+ struct mwifiex_private *priv)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u32 vht_cap = 0, cap = adapter->hw_dot_11ac_dev_cap;
+
+ vht_info->vht_supported = true;
+
+ switch (GET_VHTCAP_MAXMPDULEN(cap)) {
+ case 0x00:
+ vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
+ break;
+ case 0x01:
+ vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
+ break;
+ case 0x10:
+ vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
+ break;
+ default:
+ dev_err(adapter->dev, "unsupported MAX MPDU len\n");
+ break;
+ }
+
+ if (ISSUPP_11ACVHTHTCVHT(cap))
+ vht_cap |= IEEE80211_VHT_CAP_HTC_VHT;
+
+ if (ISSUPP_11ACVHTTXOPPS(cap))
+ vht_cap |= IEEE80211_VHT_CAP_VHT_TXOP_PS;
+
+ if (ISSUPP_11ACMURXBEAMFORMEE(cap))
+ vht_cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
+
+ if (ISSUPP_11ACMUTXBEAMFORMEE(cap))
+ vht_cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+ if (ISSUPP_11ACSUBEAMFORMER(cap))
+ vht_cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
+
+ if (ISSUPP_11ACSUBEAMFORMEE(cap))
+ vht_cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+
+ if (ISSUPP_11ACRXSTBC(cap))
+ vht_cap |= IEEE80211_VHT_CAP_RXSTBC_1;
+
+ if (ISSUPP_11ACTXSTBC(cap))
+ vht_cap |= IEEE80211_VHT_CAP_TXSTBC;
+
+ if (ISSUPP_11ACSGI160(cap))
+ vht_cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
+
+ if (ISSUPP_11ACSGI80(cap))
+ vht_cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
+
+ if (ISSUPP_11ACLDPC(cap))
+ vht_cap |= IEEE80211_VHT_CAP_RXLDPC;
+
+ if (ISSUPP_11ACBW8080(cap))
+ vht_cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+
+ if (ISSUPP_11ACBW160(cap))
+ vht_cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+
+ vht_info->cap = vht_cap;
+
+ /* Update MCS support for VHT */
+ vht_info->vht_mcs.rx_mcs_map = cpu_to_le16(
+ adapter->hw_dot_11ac_mcs_support & 0xFFFF);
+ vht_info->vht_mcs.rx_highest = 0;
+ vht_info->vht_mcs.tx_mcs_map = cpu_to_le16(
+ adapter->hw_dot_11ac_mcs_support >> 16);
+ vht_info->vht_mcs.tx_highest = 0;
+}
+
/*
* This function sets up the CFG802.11 specific HT capability fields
* with default values.
@@ -2095,16 +2214,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->netdev = dev;
mwifiex_setup_ht_caps(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv);
+ if (adapter->is_hw_11ac_capable)
+ mwifiex_setup_vht_caps(
+ &wiphy->bands[IEEE80211_BAND_2GHZ]->vht_cap, priv);
if (adapter->config_bands & BAND_A)
mwifiex_setup_ht_caps(
&wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv);
+ if ((adapter->config_bands & BAND_A) && adapter->is_hw_11ac_capable)
+ mwifiex_setup_vht_caps(
+ &wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv);
+
dev_net_set(dev, wiphy_net(wiphy));
dev->ieee80211_ptr = priv->wdev;
dev->ieee80211_ptr->iftype = priv->bss_mode;
memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
- memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(dev, wiphy_dev(wiphy));
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
@@ -2248,6 +2373,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
+ WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index f69300f93f42..988552dece75 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -106,8 +106,8 @@ u8 *mwifiex_11d_code_2_region(u8 code)
* This function maps an index in supported rates table into
* the corresponding data rate.
*/
-u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index,
- u8 ht_info)
+u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
+ u8 index, u8 ht_info)
{
/*
* For every mcs_rate line, the first 8 bytes are for stream 1x1,
@@ -130,10 +130,155 @@ u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index,
{ 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
};
+ /* AC rates */
+ u16 ac_mcs_rate_nss1[8][10] = {
+ /* LG 160M */
+ { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
+ 0x492, 0x57C, 0x618 },
+
+ /* SG 160M */
+ { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
+ 0x514, 0x618, 0x6C6 },
+
+ /* LG 80M */
+ { 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F,
+ 0x249, 0x2BE, 0x30C },
+
+ /* SG 80M */
+ { 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249,
+ 0x28A, 0x30C, 0x363 },
+
+ /* LG 40M */
+ { 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3,
+ 0x10E, 0x144, 0x168 },
+
+ /* SG 40M */
+ { 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E,
+ 0x12C, 0x168, 0x190 },
+
+ /* LG 20M */
+ { 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 },
+
+ /* SG 20M */
+ { 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 },
+ };
+ /* NSS2 note: the value in the table is 2 multiplier of the actual
+ * rate
+ */
+ u16 ac_mcs_rate_nss2[8][10] = {
+ /* LG 160M */
+ { 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A,
+ 0x924, 0xAF8, 0xC30 },
+
+ /* SG 160M */
+ { 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924,
+ 0xA28, 0xC30, 0xD8B },
+
+ /* LG 80M */
+ { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
+ 0x492, 0x57C, 0x618 },
+
+ /* SG 80M */
+ { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
+ 0x514, 0x618, 0x6C6 },
+
+ /* LG 40M */
+ { 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6,
+ 0x21C, 0x288, 0x2D0 },
+
+ /* SG 40M */
+ { 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C,
+ 0x258, 0x2D0, 0x320 },
+
+ /* LG 20M */
+ { 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104,
+ 0x138, 0x00 },
+
+ /* SG 20M */
+ { 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121,
+ 0x15B, 0x00 },
+ };
+ u32 rate = 0;
+ u8 mcs_index = 0;
+ u8 bw = 0;
+ u8 gi = 0;
+
+ if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_VHT) {
+ mcs_index = min(index & 0xF, 9);
+
+ /* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */
+ bw = (ht_info & 0xC) >> 2;
+
+ /* LGI: gi =0, SGI: gi = 1 */
+ gi = (ht_info & 0x10) >> 4;
+
+ if ((index >> 4) == 1) /* NSS = 2 */
+ rate = ac_mcs_rate_nss2[2 * (3 - bw) + gi][mcs_index];
+ else /* NSS = 1 */
+ rate = ac_mcs_rate_nss1[2 * (3 - bw) + gi][mcs_index];
+ } else if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_HT) {
+ /* 20M: bw=0, 40M: bw=1 */
+ bw = (ht_info & 0xC) >> 2;
+
+ /* LGI: gi =0, SGI: gi = 1 */
+ gi = (ht_info & 0x10) >> 4;
+
+ if (index == MWIFIEX_RATE_BITMAP_MCS0) {
+ if (gi == 1)
+ rate = 0x0D; /* MCS 32 SGI rate */
+ else
+ rate = 0x0C; /* MCS 32 LGI rate */
+ } else if (index < 16) {
+ if ((bw == 1) || (bw == 0))
+ rate = mcs_rate[2 * (1 - bw) + gi][index];
+ else
+ rate = mwifiex_data_rates[0];
+ } else {
+ rate = mwifiex_data_rates[0];
+ }
+ } else {
+ /* 11n non-HT rates */
+ if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
+ index = 0;
+ rate = mwifiex_data_rates[index];
+ }
+
+ return rate;
+}
+
+/* This function maps an index in supported rates table into
+ * the corresponding data rate.
+ */
+u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
+ u8 index, u8 ht_info)
+{
+ /* For every mcs_rate line, the first 8 bytes are for stream 1x1,
+ * and all 16 bytes are for stream 2x2.
+ */
+ u16 mcs_rate[4][16] = {
+ /* LGI 40M */
+ { 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e,
+ 0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c },
+
+ /* SGI 40M */
+ { 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c,
+ 0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 },
+
+ /* LGI 20M */
+ { 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82,
+ 0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 },
+
+ /* SGI 20M */
+ { 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
+ 0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
+ };
u32 mcs_num_supp =
(priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
u32 rate;
+ if (priv->adapter->is_hw_11ac_capable)
+ return mwifiex_index_to_acs_data_rate(priv, index, ht_info);
+
if (ht_info & BIT(0)) {
if (index == MWIFIEX_RATE_BITMAP_MCS0) {
if (ht_info & BIT(2))
@@ -269,6 +414,7 @@ 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:
@@ -279,6 +425,7 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
break;
case BAND_G:
case BAND_G | BAND_GN:
+ case BAND_G | BAND_GN | BAND_GAC:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_g\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_g,
@@ -288,7 +435,11 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
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_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC:
+ case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN |
+ BAND_AAC | BAND_GAC:
case BAND_B | BAND_G | BAND_GN:
+ case BAND_B | BAND_G | BAND_GN | BAND_GAC:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_bg\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_bg,
@@ -301,14 +452,18 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
k = mwifiex_copy_rates(rates, k, supported_rates_a,
sizeof(supported_rates_a));
break;
+ case BAND_AN:
case BAND_A | BAND_AN:
+ case BAND_A | BAND_AN | BAND_AAC:
case BAND_A | BAND_G | BAND_AN | BAND_GN:
+ case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC:
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:
+ case BAND_GN | BAND_GAC:
dev_dbg(adapter->dev, "info: infra band=%d "
"supported_rates_n\n", adapter->config_bands);
k = mwifiex_copy_rates(rates, k, supported_rates_n,
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 5f438e6c2155..20a6c5555873 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -24,6 +24,7 @@
#include "main.h"
#include "wmm.h"
#include "11n.h"
+#include "11ac.h"
/*
* This function initializes a command node.
@@ -334,20 +335,15 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
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__);
+ cmd_array = kcalloc(MWIFIEX_NUM_OF_CMD_BUFFER,
+ sizeof(struct cmd_ctrl_node), GFP_KERNEL);
+ if (!cmd_array)
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++) {
@@ -1470,6 +1466,24 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
+ if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) {
+ adapter->is_hw_11ac_capable = true;
+
+ /* Copy 11AC cap */
+ adapter->hw_dot_11ac_dev_cap =
+ le32_to_cpu(hw_spec->dot_11ac_dev_cap);
+ adapter->usr_dot_11ac_dev_cap_bg = adapter->hw_dot_11ac_dev_cap;
+ adapter->usr_dot_11ac_dev_cap_a = adapter->hw_dot_11ac_dev_cap;
+
+ /* Copy 11AC mcs */
+ adapter->hw_dot_11ac_mcs_support =
+ le32_to_cpu(hw_spec->dot_11ac_mcs_support);
+ adapter->usr_dot_11ac_mcs_support =
+ adapter->hw_dot_11ac_mcs_support;
+ } else {
+ adapter->is_hw_11ac_capable = false;
+ }
+
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",
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index 46e34aa65d1c..753b5682d53f 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -58,8 +58,6 @@ static struct mwifiex_debug_data items[] = {
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),
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index e9357d87d327..e8a569aaa2e8 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -26,6 +26,7 @@
#include <linux/wait.h>
#include <linux/timer.h>
#include <linux/ieee80211.h>
+#include <net/mac80211.h>
#define MWIFIEX_MAX_BSS_NUM (3)
@@ -58,6 +59,8 @@
#define MWIFIEX_RTS_MAX_VALUE (2347)
#define MWIFIEX_FRAG_MIN_VALUE (256)
#define MWIFIEX_FRAG_MAX_VALUE (2346)
+#define MWIFIEX_WMM_VERSION 0x01
+#define MWIFIEX_WMM_SUBTYPE 0x01
#define MWIFIEX_RETRY_LIMIT 14
#define MWIFIEX_SDIO_BLOCK_SIZE 256
@@ -126,4 +129,19 @@ enum mwifiex_wmm_ac_e {
WMM_AC_VI,
WMM_AC_VO
} __packed;
+
+struct ieee_types_wmm_ac_parameters {
+ u8 aci_aifsn_bitmap;
+ u8 ecw_bitmap;
+ __le16 tx_op_limit;
+} __packed;
+
+struct mwifiex_types_wmm_info {
+ u8 oui[4];
+ u8 subtype;
+ u8 version;
+ u8 qos_info;
+ u8 reserved;
+ struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS];
+} __packed;
#endif /* !_MWIFIEX_DECL_H_ */
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 4dc8e2e9a889..25acb0682c56 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -49,13 +49,23 @@ struct tx_packet_hdr {
#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 ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN | \
+ BAND_AN | BAND_GAC | BAND_AAC)
-#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11))
+#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11) | \
+ BIT(12) | BIT(13))
#define IS_SUPPORT_MULTI_BANDS(adapter) \
(adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
+
+/* shift bit 12 and bit 13 in fw_cap_info from the firmware to bit 13 and 14
+ * for 11ac so that bit 11 is for GN, bit 12 for AN, bit 13 for GAC, and bit
+ * bit 14 for AAC, in order to be compatible with the band capability
+ * defined in the driver after right shift of 8 bits.
+ */
#define GET_FW_DEFAULT_BANDS(adapter) \
- ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS)
+ (((((adapter->fw_cap_info & 0x3000) << 1) | \
+ (adapter->fw_cap_info & ~0xF000)) >> 8) & \
+ ALL_802_11_BANDS)
#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
@@ -216,6 +226,47 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define LLC_SNAP_LEN 8
+/* HW_SPEC fw_cap_info */
+
+#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & (BIT(13)|BIT(14)))
+
+#define GET_VHTCAP_MAXMPDULEN(vht_cap_info) (vht_cap_info & 0x3)
+#define GET_VHTCAP_CHWDSET(vht_cap_info) ((vht_cap_info >> 2) & 0x3)
+#define GET_VHTNSSMCS(mcs_mapset, nss) ((mcs_mapset >> (2 * (nss - 1))) & 0x3)
+#define SET_VHTNSSMCS(mcs_mapset, nss, value) (mcs_mapset |= (value & 0x3) << \
+ (2 * (nss - 1)))
+#define NO_NSS_SUPPORT 0x3
+
+/* HW_SPEC: HTC-VHT supported */
+#define ISSUPP_11ACVHTHTCVHT(Dot11acDevCap) (Dot11acDevCap & BIT(22))
+/* HW_SPEC: VHT TXOP PS support */
+#define ISSUPP_11ACVHTTXOPPS(Dot11acDevCap) (Dot11acDevCap & BIT(21))
+/* HW_SPEC: MU RX beamformee support */
+#define ISSUPP_11ACMURXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(20))
+/* HW_SPEC: MU TX beamformee support */
+#define ISSUPP_11ACMUTXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(19))
+/* HW_SPEC: SU Beamformee support */
+#define ISSUPP_11ACSUBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(10))
+/* HW_SPEC: SU Beamformer support */
+#define ISSUPP_11ACSUBEAMFORMER(Dot11acDevCap) (Dot11acDevCap & BIT(9))
+/* HW_SPEC: Rx STBC support */
+#define ISSUPP_11ACRXSTBC(Dot11acDevCap) (Dot11acDevCap & BIT(8))
+/* HW_SPEC: Tx STBC support */
+#define ISSUPP_11ACTXSTBC(Dot11acDevCap) (Dot11acDevCap & BIT(7))
+/* HW_SPEC: Short GI support for 160MHz BW */
+#define ISSUPP_11ACSGI160(Dot11acDevCap) (Dot11acDevCap & BIT(6))
+/* HW_SPEC: Short GI support for 80MHz BW */
+#define ISSUPP_11ACSGI80(Dot11acDevCap) (Dot11acDevCap & BIT(5))
+/* HW_SPEC: LDPC coding support */
+#define ISSUPP_11ACLDPC(Dot11acDevCap) (Dot11acDevCap & BIT(4))
+/* HW_SPEC: Channel BW 20/40/80/160/80+80 MHz support */
+#define ISSUPP_11ACBW8080(Dot11acDevCap) (Dot11acDevCap & BIT(3))
+/* HW_SPEC: Channel BW 20/40/80/160 MHz support */
+#define ISSUPP_11ACBW160(Dot11acDevCap) (Dot11acDevCap & BIT(2))
+
+#define GET_DEVTXMCSMAP(dev_mcs_map) (dev_mcs_map >> 16)
+#define GET_DEVRXMCSMAP(dev_mcs_map) (dev_mcs_map & 0xFFFF)
+
#define MOD_CLASS_HR_DSSS 0x03
#define MOD_CLASS_OFDM 0x07
#define MOD_CLASS_HT 0x08
@@ -330,6 +381,9 @@ enum P2P_MODES {
#define HOST_SLEEP_CFG_GPIO_DEF 0xff
#define HOST_SLEEP_CFG_GAP_DEF 0
+#define MWIFIEX_TIMEOUT_FOR_AP_RESP 0xfffc
+#define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT 2
+
#define CMD_F_HOSTCMD (1 << 0)
#define CMD_F_CANCELED (1 << 1)
@@ -452,9 +506,22 @@ struct rxpd {
u8 rx_rate;
s8 snr;
s8 nf;
- /* Ht Info [Bit 0] RxRate format: LG=0, HT=1
+
+ /* For: Non-802.11 AC cards
+ *
+ * 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 */
+ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1
+ *
+ * For: 802.11 AC cards
+ * [Bit 1] [Bit 0] RxRate format: legacy rate = 00 HT = 01 VHT = 10
+ * [Bit 3] [Bit 2] HT/VHT Bandwidth BW20 = 00 BW40 = 01
+ * BW80 = 10 BW160 = 11
+ * [Bit 4] HT/VHT Guard interval LGI = 0 SGI = 1
+ * [Bit 5] STBC support Enabled = 1
+ * [Bit 6] LDPC support Enabled = 1
+ * [Bit 7] Reserved
+ */
u8 ht_info;
u8 reserved;
} __packed;
@@ -677,7 +744,11 @@ struct host_cmd_ds_get_hw_spec {
__le32 dot_11n_dev_cap;
u8 dev_mcs_support;
__le16 mp_end_port; /* SDIO only, reserved for other interfacces */
- __le16 reserved_4;
+ __le16 mgmt_buf_count; /* mgmt IE buffer count */
+ __le32 reserved_5;
+ __le32 reserved_6;
+ __le32 dot_11ac_dev_cap;
+ __le32 dot_11ac_mcs_support;
} __packed;
struct host_cmd_ds_802_11_rssi_info {
@@ -783,6 +854,12 @@ union ieee_types_phy_param_set {
struct ieee_types_ds_param_set ds_param_set;
} __packed;
+struct ieee_types_oper_mode_ntf {
+ u8 element_id;
+ u8 len;
+ u8 oper_mode;
+} __packed;
+
struct host_cmd_ds_802_11_ad_hoc_start {
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 bss_mode;
@@ -843,11 +920,27 @@ struct host_cmd_ds_802_11_get_log {
__le32 wep_icv_err_cnt[4];
};
+/* Enumeration for rate format */
+enum _mwifiex_rate_format {
+ MWIFIEX_RATE_FORMAT_LG = 0,
+ MWIFIEX_RATE_FORMAT_HT,
+ MWIFIEX_RATE_FORMAT_VHT,
+ MWIFIEX_RATE_FORMAT_AUTO = 0xFF,
+};
+
struct host_cmd_ds_tx_rate_query {
u8 tx_rate;
- /* Ht Info [Bit 0] RxRate format: LG=0, HT=1
+ /* Tx Rate Info: For 802.11 AC cards
+ *
+ * [Bit 0-1] tx rate formate: LG = 0, HT = 1, VHT = 2
+ * [Bit 2-3] HT/VHT Bandwidth: BW20 = 0, BW40 = 1, BW80 = 2, BW160 = 3
+ * [Bit 4] HT/VHT Guard Interval: LGI = 0, SGI = 1
+ *
+ * For non-802.11 AC cards
+ * 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 */
+ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1
+ */
u8 ht_info;
} __packed;
@@ -1093,6 +1186,7 @@ struct host_cmd_ds_11n_cfg {
__le16 action;
__le16 ht_tx_cap;
__le16 ht_tx_info;
+ __le16 misc_config; /* Needed for 802.11AC cards only */
} __packed;
struct host_cmd_ds_txbuf_cfg {
@@ -1131,12 +1225,6 @@ struct ieee_types_vendor_header {
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:
@@ -1186,6 +1274,31 @@ struct mwifiex_ie_types_htcap {
struct ieee80211_ht_cap ht_cap;
} __packed;
+struct mwifiex_ie_types_vhtcap {
+ struct mwifiex_ie_types_header header;
+ struct ieee80211_vht_cap vht_cap;
+} __packed;
+
+struct mwifiex_ie_types_oper_mode_ntf {
+ struct mwifiex_ie_types_header header;
+ u8 oper_mode;
+} __packed;
+
+/* VHT Operations IE */
+struct mwifiex_ie_types_vht_oper {
+ struct mwifiex_ie_types_header header;
+ u8 chan_width;
+ u8 chan_center_freq_1;
+ u8 chan_center_freq_2;
+ /* Basic MCS set map, each 2 bits stands for a NSS */
+ u16 basic_mcs_map;
+} __packed;
+
+struct mwifiex_ie_types_wmmcap {
+ struct mwifiex_ie_types_header header;
+ struct mwifiex_types_wmm_info wmm_info;
+} __packed;
+
struct mwifiex_ie_types_htinfo {
struct mwifiex_ie_types_header header;
struct ieee80211_ht_operation ht_oper;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 39f03ce5a5b1..e38aa9b3663d 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -39,11 +39,8 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
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__);
+ if (!bss_prio)
return -ENOMEM;
- }
bss_prio->priv = priv;
INIT_LIST_HEAD(&bss_prio->list);
@@ -317,7 +314,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
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;
@@ -591,6 +587,12 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter)
return -1;
}
}
+
+ if (adapter->if_ops.init_fw_port) {
+ if (adapter->if_ops.init_fw_port(adapter))
+ return -1;
+ }
+
for (i = 0; i < adapter->priv_num; i++) {
if (adapter->priv[i]) {
ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta);
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index 4e31c6013ebe..d85e6eb1f58a 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -20,7 +20,6 @@
#ifndef _MWIFIEX_IOCTL_H_
#define _MWIFIEX_IOCTL_H_
-#include <net/mac80211.h>
#include <net/lib80211.h>
enum {
@@ -61,6 +60,8 @@ enum {
BAND_A = 4,
BAND_GN = 8,
BAND_AN = 16,
+ BAND_GAC = 32,
+ BAND_AAC = 64,
};
#define MWIFIEX_WPA_PASSHPHRASE_LEN 64
@@ -104,9 +105,12 @@ struct mwifiex_uap_bss_param {
struct wpa_param wpa_cfg;
struct wep_key wep_cfg[NUM_WEP_KEYS];
struct ieee80211_ht_cap ht_cap;
+ struct ieee80211_vht_cap vht_cap;
u8 rates[MWIFIEX_SUPPORTED_RATES];
u32 sta_ao_timer;
u32 ps_sta_ao_timer;
+ u8 qos_info;
+ struct mwifiex_types_wmm_info wmm_info;
};
enum {
@@ -177,7 +181,6 @@ struct mwifiex_ds_tx_ba_stream_tbl {
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;
@@ -272,6 +275,7 @@ struct mwifiex_ds_pm_cfg {
struct mwifiex_ds_11n_tx_cfg {
u16 tx_htcap;
u16 tx_htinfo;
+ u16 misc_config; /* Needed for 802.11AC cards only */
};
struct mwifiex_ds_11n_amsdu_aggr_ctrl {
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 88664ae667ba..246aa62a4817 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -24,6 +24,7 @@
#include "main.h"
#include "wmm.h"
#include "11n.h"
+#include "11ac.h"
#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9)))
@@ -157,8 +158,8 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
memset(rate1, 0, rate1_size);
- for (i = 0; rate2[i] && i < rate2_size; i++) {
- for (j = 0; tmp[j] && j < rate1_size; j++) {
+ for (i = 0; i < rate2_size && rate2[i]; i++) {
+ for (j = 0; j < rate1_size && tmp[j]; j++) {
/* Check common rate, excluding the bit for
basic rate */
if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
@@ -398,8 +399,6 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
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 */
@@ -514,6 +513,12 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
priv->adapter->config_bands & BAND_AN))
mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos);
+ if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
+ !bss_desc->disable_11n && !bss_desc->disable_11ac &&
+ (priv->adapter->config_bands & BAND_GAC ||
+ priv->adapter->config_bands & BAND_AAC))
+ mwifiex_cmd_append_11ac_tlv(priv, bss_desc, &pos);
+
/* Append vendor specific IE TLV */
mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos);
@@ -615,23 +620,33 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
struct ieee_types_assoc_rsp *assoc_rsp;
struct mwifiex_bssdescriptor *bss_desc;
u8 enable_data = true;
+ u16 cap_info, status_code;
assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
+ cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap);
+ status_code = le16_to_cpu(assoc_rsp->status_code);
+
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)) {
+ if (status_code) {
priv->adapter->dbg.num_cmd_assoc_failure++;
dev_err(priv->adapter->dev,
"ASSOC_RESP: failed, status code=%d err=%#x a_id=%#x\n",
- le16_to_cpu(assoc_rsp->status_code),
- le16_to_cpu(assoc_rsp->cap_info_bitmap),
- le16_to_cpu(assoc_rsp->a_id));
+ status_code, cap_info, le16_to_cpu(assoc_rsp->a_id));
+
+ if (cap_info == MWIFIEX_TIMEOUT_FOR_AP_RESP) {
+ if (status_code == MWIFIEX_STATUS_CODE_AUTH_TIMEOUT)
+ ret = WLAN_STATUS_AUTH_TIMEOUT;
+ else
+ ret = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ } else {
+ ret = status_code;
+ }
- ret = le16_to_cpu(assoc_rsp->status_code);
goto done;
}
@@ -969,6 +984,16 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
priv->adapter->config_bands);
mwifiex_fill_cap_info(priv, radio_type, ht_cap);
+ if (adapter->sec_chan_offset ==
+ IEEE80211_HT_PARAM_CHA_SEC_NONE) {
+ u16 tmp_ht_cap;
+
+ tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info);
+ tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40;
+ ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap);
+ }
+
pos += sizeof(struct mwifiex_ie_types_htcap);
cmd_append_size += sizeof(struct mwifiex_ie_types_htcap);
@@ -1403,6 +1428,7 @@ mwifiex_band_to_radio_type(u8 band)
case BAND_A:
case BAND_AN:
case BAND_A | BAND_AN:
+ case BAND_A | BAND_AN | BAND_AAC:
return HostCmd_SCAN_RADIO_TYPE_A;
case BAND_B:
case BAND_G:
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 1b3cfc821940..553adfb0aa81 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -295,6 +295,13 @@ struct mwifiex_bssdescriptor {
u16 bss_co_2040_offset;
u8 *bcn_ext_cap;
u16 ext_cap_offset;
+ struct ieee80211_vht_cap *bcn_vht_cap;
+ u16 vht_cap_offset;
+ struct ieee80211_vht_operation *bcn_vht_oper;
+ u16 vht_info_offset;
+ struct ieee_types_oper_mode_ntf *oper_mode;
+ u16 oper_mode_offset;
+ u8 disable_11ac;
struct ieee_types_vendor_specific *bcn_wpa_ie;
u16 wpa_offset;
struct ieee_types_generic *bcn_rsn_ie;
@@ -499,6 +506,7 @@ struct mwifiex_private {
u16 rsn_idx;
struct timer_list scan_delay_timer;
u8 ap_11n_enabled;
+ u8 ap_11ac_enabled;
u32 mgmt_frame_mask;
struct mwifiex_roc_cfg roc_cfg;
};
@@ -599,8 +607,10 @@ struct mwifiex_if_ops {
int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *);
int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);
int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *);
+ int (*init_fw_port) (struct mwifiex_adapter *);
int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
void (*card_reset) (struct mwifiex_adapter *);
+ int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
};
struct mwifiex_adapter {
@@ -629,7 +639,6 @@ struct mwifiex_adapter {
/* 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;
@@ -721,6 +730,15 @@ struct mwifiex_adapter {
u16 max_mgmt_ie_index;
u8 scan_delay_cnt;
u8 empty_tx_q_cnt;
+
+ /* 11AC */
+ u32 is_hw_11ac_capable;
+ u32 hw_dot_11ac_dev_cap;
+ u32 hw_dot_11ac_mcs_support;
+ u32 usr_dot_11ac_dev_cap_bg;
+ u32 usr_dot_11ac_dev_cap_a;
+ u32 usr_dot_11ac_mcs_support;
+
atomic_t is_tx_received;
atomic_t pending_bridged_pkts;
};
@@ -863,8 +881,10 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd);
struct mwifiex_chan_freq_power *mwifiex_get_cfp(struct mwifiex_private *priv,
u8 band, u16 channel, u32 freq);
-u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index,
- u8 ht_info);
+u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
+ u8 index, u8 ht_info);
+u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
+ 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);
@@ -890,6 +910,10 @@ void mwifiex_set_ht_params(struct mwifiex_private *priv,
struct cfg80211_ap_settings *params);
void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void
+mwifiex_set_wmm_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params);
/*
* This function checks if the queuing is RA based or not.
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index b879e1338a54..4b54bcf382f3 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -39,17 +39,20 @@ static struct semaphore add_remove_card_sem;
static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter);
static int mwifiex_pcie_resume(struct pci_dev *pdev);
-/*
- * This function is called after skb allocation to update
- * "skb->cb" with physical address of data pointer.
- */
-static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb)
+static int
+mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
+ int size, int flags)
{
- phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
-
- *buf_pa = (phys_addr_t)virt_to_phys(skb->data);
+ struct pcie_service_card *card = adapter->card;
+ dma_addr_t buf_pa;
- return buf_pa;
+ buf_pa = pci_map_single(card->dev, skb->data, size, flags);
+ if (pci_dma_mapping_error(card->dev, buf_pa)) {
+ dev_err(adapter->dev, "failed to map pci memory!\n");
+ return -1;
+ }
+ memcpy(skb->cb, &buf_pa, sizeof(dma_addr_t));
+ return 0;
}
/*
@@ -59,9 +62,13 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
{
u32 *cookie_addr;
struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+ if (!reg->sleep_cookie)
+ return true;
- if (card->sleep_cookie) {
- cookie_addr = (u32 *)card->sleep_cookie->data;
+ if (card->sleep_cookie_vbase) {
+ cookie_addr = (u32 *)card->sleep_cookie_vbase;
dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n",
*cookie_addr);
if (*cookie_addr == FW_AWAKE_COOKIE)
@@ -91,6 +98,13 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
card->dev = pdev;
+ if (ent->driver_data) {
+ struct mwifiex_pcie_device *data = (void *)ent->driver_data;
+ card->pcie.firmware = data->firmware;
+ card->pcie.reg = data->reg;
+ card->pcie.blksz_fw_dl = data->blksz_fw_dl;
+ }
+
if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
MWIFIEX_PCIE)) {
pr_err("%s failed\n", __func__);
@@ -227,13 +241,16 @@ static int mwifiex_pcie_resume(struct pci_dev *pdev)
return 0;
}
-#define PCIE_VENDOR_ID_MARVELL (0x11ab)
-#define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30)
-
static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
{
PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ .driver_data = (unsigned long) &mwifiex_pcie8766,
+ },
+ {
+ PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ .driver_data = (unsigned long) &mwifiex_pcie8897,
},
{},
};
@@ -286,8 +303,10 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
{
int i = 0;
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- while (mwifiex_pcie_ok_to_access_hw(adapter)) {
+ while (reg->sleep_cookie && mwifiex_pcie_ok_to_access_hw(adapter)) {
i++;
usleep_range(10, 20);
/* 50ms max wait */
@@ -361,14 +380,246 @@ static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
}
/*
- * This function creates buffer descriptor ring for TX
+ * This function initializes TX buffer ring descriptors
*/
-static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
+static int mwifiex_init_txq_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+ struct mwifiex_pcie_buf_desc *desc;
+ struct mwifiex_pfu_buf_desc *desc2;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ card->tx_buf_list[i] = NULL;
+ if (reg->pfu_enabled) {
+ card->txbd_ring[i] = (void *)card->txbd_ring_vbase +
+ (sizeof(*desc2) * i);
+ desc2 = card->txbd_ring[i];
+ memset(desc2, 0, sizeof(*desc2));
+ } else {
+ card->txbd_ring[i] = (void *)card->txbd_ring_vbase +
+ (sizeof(*desc) * i);
+ desc = card->txbd_ring[i];
+ memset(desc, 0, sizeof(*desc));
+ }
+ }
+
+ return 0;
+}
+
+/* This function initializes RX buffer ring descriptors. Each SKB is allocated
+ * here and after mapping PCI memory, its physical address is assigned to
+ * PCIE Rx buffer descriptor's physical address.
+ */
+static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+ struct sk_buff *skb;
+ struct mwifiex_pcie_buf_desc *desc;
+ struct mwifiex_pfu_buf_desc *desc2;
+ dma_addr_t buf_pa;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ /* Allocate skb here so that firmware can DMA data from it */
+ skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
+ if (!skb) {
+ dev_err(adapter->dev,
+ "Unable to allocate skb for RX ring.\n");
+ kfree(card->rxbd_ring_vbase);
+ return -ENOMEM;
+ }
+
+ if (mwifiex_map_pci_memory(adapter, skb,
+ MWIFIEX_RX_DATA_BUF_SIZE,
+ PCI_DMA_FROMDEVICE))
+ return -1;
+
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
+
+ dev_dbg(adapter->dev,
+ "info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
+ skb, skb->len, skb->data, (u32)buf_pa,
+ (u32)((u64)buf_pa >> 32));
+
+ card->rx_buf_list[i] = skb;
+ if (reg->pfu_enabled) {
+ card->rxbd_ring[i] = (void *)card->rxbd_ring_vbase +
+ (sizeof(*desc2) * i);
+ desc2 = card->rxbd_ring[i];
+ desc2->paddr = buf_pa;
+ desc2->len = (u16)skb->len;
+ desc2->frag_len = (u16)skb->len;
+ desc2->flags = reg->ring_flag_eop | reg->ring_flag_sop;
+ desc2->offset = 0;
+ } else {
+ card->rxbd_ring[i] = (void *)(card->rxbd_ring_vbase +
+ (sizeof(*desc) * i));
+ desc = card->rxbd_ring[i];
+ desc->paddr = buf_pa;
+ desc->len = (u16)skb->len;
+ desc->flags = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* This function initializes event buffer ring descriptors. Each SKB is
+ * allocated here and after mapping PCI memory, its physical address is assigned
+ * to PCIE Rx buffer descriptor's physical address
+ */
+static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct mwifiex_evt_buf_desc *desc;
+ struct sk_buff *skb;
+ dma_addr_t buf_pa;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+ /* Allocate skb here so that firmware can DMA data from it */
+ skb = dev_alloc_skb(MAX_EVENT_SIZE);
+ if (!skb) {
+ dev_err(adapter->dev,
+ "Unable to allocate skb for EVENT buf.\n");
+ kfree(card->evtbd_ring_vbase);
+ return -ENOMEM;
+ }
+ skb_put(skb, MAX_EVENT_SIZE);
+
+ if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
+ PCI_DMA_FROMDEVICE))
+ return -1;
+
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
+
+ dev_dbg(adapter->dev,
+ "info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
+ skb, skb->len, skb->data, (u32)buf_pa,
+ (u32)((u64)buf_pa >> 32));
+
+ card->evt_buf_list[i] = skb;
+ card->evtbd_ring[i] = (void *)(card->evtbd_ring_vbase +
+ (sizeof(*desc) * i));
+ desc = card->evtbd_ring[i];
+ desc->paddr = buf_pa;
+ desc->len = (u16)skb->len;
+ desc->flags = 0;
+ }
+
+ return 0;
+}
+
+/* This function cleans up TX buffer rings. If any of the buffer list has valid
+ * SKB address, associated SKB is freed.
+ */
+static void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+ struct sk_buff *skb;
+ struct mwifiex_pcie_buf_desc *desc;
+ struct mwifiex_pfu_buf_desc *desc2;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ if (reg->pfu_enabled) {
+ desc2 = card->txbd_ring[i];
+ if (card->tx_buf_list[i]) {
+ skb = card->tx_buf_list[i];
+ pci_unmap_single(card->dev, desc2->paddr,
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(skb);
+ }
+ memset(desc2, 0, sizeof(*desc2));
+ } else {
+ desc = card->txbd_ring[i];
+ if (card->tx_buf_list[i]) {
+ skb = card->tx_buf_list[i];
+ pci_unmap_single(card->dev, desc->paddr,
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(skb);
+ }
+ memset(desc, 0, sizeof(*desc));
+ }
+ card->tx_buf_list[i] = NULL;
+ }
+
+ return;
+}
+
+/* This function cleans up RX buffer rings. If any of the buffer list has valid
+ * SKB address, associated SKB is freed.
+ */
+static void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+ struct mwifiex_pcie_buf_desc *desc;
+ struct mwifiex_pfu_buf_desc *desc2;
struct sk_buff *skb;
int i;
- phys_addr_t *buf_pa;
+
+ for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
+ if (reg->pfu_enabled) {
+ desc2 = card->rxbd_ring[i];
+ if (card->rx_buf_list[i]) {
+ skb = card->rx_buf_list[i];
+ pci_unmap_single(card->dev, desc2->paddr,
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(skb);
+ }
+ memset(desc2, 0, sizeof(*desc2));
+ } else {
+ desc = card->rxbd_ring[i];
+ if (card->rx_buf_list[i]) {
+ skb = card->rx_buf_list[i];
+ pci_unmap_single(card->dev, desc->paddr,
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(skb);
+ }
+ memset(desc, 0, sizeof(*desc));
+ }
+ card->rx_buf_list[i] = NULL;
+ }
+
+ return;
+}
+
+/* This function cleans up event buffer rings. If any of the buffer list has
+ * valid SKB address, associated SKB is freed.
+ */
+static void mwifiex_cleanup_evt_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ struct mwifiex_evt_buf_desc *desc;
+ struct sk_buff *skb;
+ int i;
+
+ for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
+ desc = card->evtbd_ring[i];
+ if (card->evt_buf_list[i]) {
+ skb = card->evt_buf_list[i];
+ pci_unmap_single(card->dev, desc->paddr, MAX_EVENT_SIZE,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(skb);
+ }
+ card->evt_buf_list[i] = NULL;
+ memset(desc, 0, sizeof(*desc));
+ }
+
+ return;
+}
+
+/* This function creates buffer descriptor ring for TX
+ */
+static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
/*
* driver maintaines the write pointer and firmware maintaines the read
@@ -376,76 +627,56 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
* starts at zero with rollover bit set
*/
card->txbd_wrptr = 0;
- card->txbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+
+ if (reg->pfu_enabled)
+ card->txbd_rdptr = 0;
+ else
+ card->txbd_rdptr |= reg->tx_rollover_ind;
/* allocate shared memory for the BD ring and divide the same in to
several descriptors */
- card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
- MWIFIEX_MAX_TXRX_BD;
+ if (reg->pfu_enabled)
+ card->txbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) *
+ MWIFIEX_MAX_TXRX_BD;
+ else
+ card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+ MWIFIEX_MAX_TXRX_BD;
+
dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n",
card->txbd_ring_size);
- card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL);
+ card->txbd_ring_vbase = pci_alloc_consistent(card->dev,
+ card->txbd_ring_size,
+ &card->txbd_ring_pbase);
if (!card->txbd_ring_vbase) {
- dev_err(adapter->dev, "Unable to alloc buffer for txbd ring\n");
+ dev_err(adapter->dev,
+ "allocate consistent memory (%d bytes) failed!\n",
+ card->txbd_ring_size);
return -ENOMEM;
}
- card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase);
-
dev_dbg(adapter->dev,
"info: txbd_ring - base: %p, pbase: %#x:%x, len: %x\n",
- card->txbd_ring_vbase, (u32)card->txbd_ring_pbase,
+ card->txbd_ring_vbase, (unsigned int)card->txbd_ring_pbase,
(u32)((u64)card->txbd_ring_pbase >> 32), card->txbd_ring_size);
- for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
- card->txbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
- (card->txbd_ring_vbase +
- (sizeof(struct mwifiex_pcie_buf_desc)
- * i));
-
- /* Allocate buffer here so that firmware can DMA data from it */
- skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
- if (!skb) {
- dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n");
- kfree(card->txbd_ring_vbase);
- return -ENOMEM;
- }
- buf_pa = mwifiex_update_sk_buff_pa(skb);
-
- skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
- dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, "
- "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
- skb, skb->data, (u32)*buf_pa,
- (u32)(((u64)*buf_pa >> 32)), skb->len);
-
- card->tx_buf_list[i] = skb;
- card->txbd_ring[i]->paddr = *buf_pa;
- card->txbd_ring[i]->len = (u16)skb->len;
- card->txbd_ring[i]->flags = 0;
- }
-
- return 0;
+ return mwifiex_init_txq_ring(adapter);
}
static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
- int i;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
- if (card->tx_buf_list[i])
- dev_kfree_skb_any(card->tx_buf_list[i]);
- card->tx_buf_list[i] = NULL;
- card->txbd_ring[i]->paddr = 0;
- card->txbd_ring[i]->len = 0;
- card->txbd_ring[i]->flags = 0;
- card->txbd_ring[i] = NULL;
- }
+ mwifiex_cleanup_txq_ring(adapter);
- kfree(card->txbd_ring_vbase);
+ if (card->txbd_ring_vbase)
+ pci_free_consistent(card->dev, card->txbd_ring_size,
+ card->txbd_ring_vbase,
+ card->txbd_ring_pbase);
card->txbd_ring_size = 0;
card->txbd_wrptr = 0;
- card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->txbd_rdptr = 0 | reg->tx_rollover_ind;
card->txbd_ring_vbase = NULL;
+ card->txbd_ring_pbase = 0;
return 0;
}
@@ -456,9 +687,7 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
- struct sk_buff *skb;
- int i;
- phys_addr_t *buf_pa;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
/*
* driver maintaines the read pointer and firmware maintaines the write
@@ -466,19 +695,26 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
* starts at zero with rollover bit set
*/
card->rxbd_wrptr = 0;
- card->rxbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->rxbd_rdptr = reg->rx_rollover_ind;
+
+ if (reg->pfu_enabled)
+ card->rxbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) *
+ MWIFIEX_MAX_TXRX_BD;
+ else
+ card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
+ MWIFIEX_MAX_TXRX_BD;
- card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
- MWIFIEX_MAX_TXRX_BD;
dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n",
card->rxbd_ring_size);
- card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL);
+ card->rxbd_ring_vbase = pci_alloc_consistent(card->dev,
+ card->rxbd_ring_size,
+ &card->rxbd_ring_pbase);
if (!card->rxbd_ring_vbase) {
- dev_err(adapter->dev, "Unable to allocate buffer for "
- "rxbd_ring.\n");
+ dev_err(adapter->dev,
+ "allocate consistent memory (%d bytes) failed!\n",
+ card->rxbd_ring_size);
return -ENOMEM;
}
- card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase);
dev_dbg(adapter->dev,
"info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
@@ -486,35 +722,7 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
(u32)((u64)card->rxbd_ring_pbase >> 32),
card->rxbd_ring_size);
- for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
- card->rxbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
- (card->rxbd_ring_vbase +
- (sizeof(struct mwifiex_pcie_buf_desc)
- * i));
-
- /* Allocate skb here so that firmware can DMA data from it */
- skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
- if (!skb) {
- dev_err(adapter->dev,
- "Unable to allocate skb for RX ring.\n");
- kfree(card->rxbd_ring_vbase);
- return -ENOMEM;
- }
- buf_pa = mwifiex_update_sk_buff_pa(skb);
- skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE);
-
- dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, "
- "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
- skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
- skb->len);
-
- card->rx_buf_list[i] = skb;
- card->rxbd_ring[i]->paddr = *buf_pa;
- card->rxbd_ring[i]->len = (u16)skb->len;
- card->rxbd_ring[i]->flags = 0;
- }
-
- return 0;
+ return mwifiex_init_rxq_ring(adapter);
}
/*
@@ -523,23 +731,19 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
- int i;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
- if (card->rx_buf_list[i])
- dev_kfree_skb_any(card->rx_buf_list[i]);
- card->rx_buf_list[i] = NULL;
- card->rxbd_ring[i]->paddr = 0;
- card->rxbd_ring[i]->len = 0;
- card->rxbd_ring[i]->flags = 0;
- card->rxbd_ring[i] = NULL;
- }
+ mwifiex_cleanup_rxq_ring(adapter);
- kfree(card->rxbd_ring_vbase);
+ if (card->rxbd_ring_vbase)
+ pci_free_consistent(card->dev, card->rxbd_ring_size,
+ card->rxbd_ring_vbase,
+ card->rxbd_ring_pbase);
card->rxbd_ring_size = 0;
card->rxbd_wrptr = 0;
- card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->rxbd_rdptr = 0 | reg->rx_rollover_ind;
card->rxbd_ring_vbase = NULL;
+ card->rxbd_ring_pbase = 0;
return 0;
}
@@ -550,9 +754,7 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
- struct sk_buff *skb;
- int i;
- phys_addr_t *buf_pa;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
/*
* driver maintaines the read pointer and firmware maintaines the write
@@ -560,19 +762,22 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
* starts at zero with rollover bit set
*/
card->evtbd_wrptr = 0;
- card->evtbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->evtbd_rdptr = reg->evt_rollover_ind;
+
+ card->evtbd_ring_size = sizeof(struct mwifiex_evt_buf_desc) *
+ MWIFIEX_MAX_EVT_BD;
- card->evtbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
- MWIFIEX_MAX_EVT_BD;
dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n",
card->evtbd_ring_size);
- card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL);
+ card->evtbd_ring_vbase = pci_alloc_consistent(card->dev,
+ card->evtbd_ring_size,
+ &card->evtbd_ring_pbase);
if (!card->evtbd_ring_vbase) {
dev_err(adapter->dev,
- "Unable to allocate buffer. Terminating download\n");
+ "allocate consistent memory (%d bytes) failed!\n",
+ card->evtbd_ring_size);
return -ENOMEM;
}
- card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase);
dev_dbg(adapter->dev,
"info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n",
@@ -580,35 +785,7 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
(u32)((u64)card->evtbd_ring_pbase >> 32),
card->evtbd_ring_size);
- for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
- card->evtbd_ring[i] = (struct mwifiex_pcie_buf_desc *)
- (card->evtbd_ring_vbase +
- (sizeof(struct mwifiex_pcie_buf_desc)
- * i));
-
- /* Allocate skb here so that firmware can DMA data from it */
- skb = dev_alloc_skb(MAX_EVENT_SIZE);
- if (!skb) {
- dev_err(adapter->dev,
- "Unable to allocate skb for EVENT buf.\n");
- kfree(card->evtbd_ring_vbase);
- return -ENOMEM;
- }
- buf_pa = mwifiex_update_sk_buff_pa(skb);
- skb_put(skb, MAX_EVENT_SIZE);
-
- dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, "
- "buf_base: %p, buf_pbase: %#x:%x, buf_len: %#x\n",
- skb, skb->data, (u32)*buf_pa, (u32)((u64)*buf_pa >> 32),
- skb->len);
-
- card->evt_buf_list[i] = skb;
- card->evtbd_ring[i]->paddr = *buf_pa;
- card->evtbd_ring[i]->len = (u16)skb->len;
- card->evtbd_ring[i]->flags = 0;
- }
-
- return 0;
+ return mwifiex_pcie_init_evt_ring(adapter);
}
/*
@@ -617,23 +794,19 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
- int i;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
- if (card->evt_buf_list[i])
- dev_kfree_skb_any(card->evt_buf_list[i]);
- card->evt_buf_list[i] = NULL;
- card->evtbd_ring[i]->paddr = 0;
- card->evtbd_ring[i]->len = 0;
- card->evtbd_ring[i]->flags = 0;
- card->evtbd_ring[i] = NULL;
- }
+ mwifiex_cleanup_evt_ring(adapter);
- kfree(card->evtbd_ring_vbase);
+ if (card->evtbd_ring_vbase)
+ pci_free_consistent(card->dev, card->evtbd_ring_size,
+ card->evtbd_ring_vbase,
+ card->evtbd_ring_pbase);
card->evtbd_wrptr = 0;
- card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND;
+ card->evtbd_rdptr = 0 | reg->evt_rollover_ind;
card->evtbd_ring_size = 0;
card->evtbd_ring_vbase = NULL;
+ card->evtbd_ring_pbase = 0;
return 0;
}
@@ -653,21 +826,12 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
"Unable to allocate skb for command response data.\n");
return -ENOMEM;
}
- mwifiex_update_sk_buff_pa(skb);
skb_put(skb, MWIFIEX_UPLD_SIZE);
- card->cmdrsp_buf = skb;
+ if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
+ PCI_DMA_FROMDEVICE))
+ return -1;
- skb = NULL;
- /* Allocate memory for sending command to firmware */
- skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
- if (!skb) {
- dev_err(adapter->dev,
- "Unable to allocate skb for command data.\n");
- return -ENOMEM;
- }
- mwifiex_update_sk_buff_pa(skb);
- skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER);
- card->cmd_buf = skb;
+ card->cmdrsp_buf = skb;
return 0;
}
@@ -678,18 +842,26 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card;
+ dma_addr_t buf_pa;
if (!adapter)
return 0;
card = adapter->card;
- if (card && card->cmdrsp_buf)
+ if (card && card->cmdrsp_buf) {
+ MWIFIEX_SKB_PACB(card->cmdrsp_buf, &buf_pa);
+ pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(card->cmdrsp_buf);
+ }
- if (card && card->cmd_buf)
+ if (card && card->cmd_buf) {
+ MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa);
+ pci_unmap_single(card->dev, buf_pa, MWIFIEX_SIZE_OF_CMD_BUFFER,
+ PCI_DMA_TODEVICE);
dev_kfree_skb_any(card->cmd_buf);
-
+ }
return 0;
}
@@ -698,27 +870,19 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
*/
static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
{
- struct sk_buff *skb;
struct pcie_service_card *card = adapter->card;
- /* Allocate memory for sleep cookie */
- skb = dev_alloc_skb(sizeof(u32));
- if (!skb) {
- dev_err(adapter->dev,
- "Unable to allocate skb for sleep cookie!\n");
+ card->sleep_cookie_vbase = pci_alloc_consistent(card->dev, sizeof(u32),
+ &card->sleep_cookie_pbase);
+ if (!card->sleep_cookie_vbase) {
+ dev_err(adapter->dev, "pci_alloc_consistent failed!\n");
return -ENOMEM;
}
- mwifiex_update_sk_buff_pa(skb);
- skb_put(skb, sizeof(u32));
-
/* Init val of Sleep Cookie */
- *(u32 *)skb->data = FW_AWAKE_COOKIE;
+ *(u32 *)card->sleep_cookie_vbase = FW_AWAKE_COOKIE;
dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n",
- *((u32 *)skb->data));
-
- /* Save the sleep cookie */
- card->sleep_cookie = skb;
+ *((u32 *)card->sleep_cookie_vbase));
return 0;
}
@@ -735,86 +899,246 @@ static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter)
card = adapter->card;
- if (card && card->sleep_cookie) {
- dev_kfree_skb_any(card->sleep_cookie);
- card->sleep_cookie = NULL;
+ if (card && card->sleep_cookie_vbase) {
+ pci_free_consistent(card->dev, sizeof(u32),
+ card->sleep_cookie_vbase,
+ card->sleep_cookie_pbase);
+ card->sleep_cookie_vbase = NULL;
}
return 0;
}
+/* This function flushes the TX buffer descriptor ring
+ * This function defined as handler is also called while cleaning TXRX
+ * during disconnect/ bss stop.
+ */
+static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+ u32 rdptr;
+
+ /* Read the TX ring read pointer set by firmware */
+ if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) {
+ dev_err(adapter->dev,
+ "Flush TXBD: failed to read reg->tx_rdptr\n");
+ return -1;
+ }
+
+ if (!mwifiex_pcie_txbd_empty(card, rdptr)) {
+ card->txbd_flush = 1;
+ /* write pointer already set at last send
+ * send dnld-rdy intr again, wait for completion.
+ */
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_DNLD_RDY)) {
+ dev_err(adapter->dev,
+ "failed to assert dnld-rdy interrupt.\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
/*
- * This function sends data buffer to device
+ * This function unmaps and frees downloaded data buffer
*/
-static int
-mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
{
+ struct sk_buff *skb;
+ dma_addr_t buf_pa;
+ u32 wrdoneidx, rdptr, num_tx_buffs, unmap_count = 0;
+ struct mwifiex_pcie_buf_desc *desc;
+ struct mwifiex_pfu_buf_desc *desc2;
struct pcie_service_card *card = adapter->card;
- u32 wrindx, rdptr;
- phys_addr_t *buf_pa;
- __le16 *tmp;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
if (!mwifiex_pcie_ok_to_access_hw(adapter))
mwifiex_pm_wakeup_card(adapter);
/* Read the TX ring read pointer set by firmware */
- if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
+ if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) {
dev_err(adapter->dev,
- "SEND DATA: failed to read REG_TXBD_RDPTR\n");
+ "SEND COMP: failed to read reg->tx_rdptr\n");
return -1;
}
- wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
+ dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
+ card->txbd_rdptr, rdptr);
- dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr,
- card->txbd_wrptr);
- if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) !=
- (rdptr & MWIFIEX_TXBD_MASK)) ||
- ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
- (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
- struct sk_buff *skb_data;
+ num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
+ /* free from previous txbd_rdptr to current txbd_rdptr */
+ while (((card->txbd_rdptr & reg->tx_mask) !=
+ (rdptr & reg->tx_mask)) ||
+ ((card->txbd_rdptr & reg->tx_rollover_ind) !=
+ (rdptr & reg->tx_rollover_ind))) {
+ wrdoneidx = (card->txbd_rdptr & reg->tx_mask) >>
+ reg->tx_start_ptr;
+
+ skb = card->tx_buf_list[wrdoneidx];
+ if (skb) {
+ dev_dbg(adapter->dev,
+ "SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
+ skb, wrdoneidx);
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
+ pci_unmap_single(card->dev, buf_pa, skb->len,
+ PCI_DMA_TODEVICE);
+
+ unmap_count++;
+
+ if (card->txbd_flush)
+ mwifiex_write_data_complete(adapter, skb, 0,
+ -1);
+ else
+ mwifiex_write_data_complete(adapter, skb, 0, 0);
+ }
+
+ card->tx_buf_list[wrdoneidx] = NULL;
+
+ if (reg->pfu_enabled) {
+ desc2 = (void *)card->txbd_ring[wrdoneidx];
+ memset(desc2, 0, sizeof(*desc2));
+ } else {
+ desc = card->txbd_ring[wrdoneidx];
+ memset(desc, 0, sizeof(*desc));
+ }
+ switch (card->dev->device) {
+ case PCIE_DEVICE_ID_MARVELL_88W8766P:
+ card->txbd_rdptr++;
+ break;
+ case PCIE_DEVICE_ID_MARVELL_88W8897:
+ card->txbd_rdptr += reg->ring_tx_start_ptr;
+ break;
+ }
+
+
+ if ((card->txbd_rdptr & reg->tx_mask) == num_tx_buffs)
+ card->txbd_rdptr = ((card->txbd_rdptr &
+ reg->tx_rollover_ind) ^
+ reg->tx_rollover_ind);
+ }
+
+ if (unmap_count)
+ adapter->data_sent = false;
+
+ if (card->txbd_flush) {
+ if (mwifiex_pcie_txbd_empty(card, card->txbd_rdptr))
+ card->txbd_flush = 0;
+ else
+ mwifiex_clean_pcie_ring_buf(adapter);
+ }
+
+ return 0;
+}
+
+/* This function sends data buffer to device. First 4 bytes of payload
+ * are filled with payload length and payload type. Then this payload
+ * is mapped to PCI device memory. Tx ring pointers are advanced accordingly.
+ * Download ready interrupt to FW is deffered if Tx ring is not full and
+ * additional payload can be accomodated.
+ */
+static int
+mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
+ struct mwifiex_tx_param *tx_param)
+{
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+ u32 wrindx, num_tx_buffs, rx_val;
+ int ret;
+ dma_addr_t buf_pa;
+ struct mwifiex_pcie_buf_desc *desc;
+ struct mwifiex_pfu_buf_desc *desc2;
+ __le16 *tmp;
+
+ if (!(skb->data && skb->len)) {
+ dev_err(adapter->dev, "%s(): invalid parameter <%p, %#x>\n",
+ __func__, skb->data, skb->len);
+ return -1;
+ }
+
+ if (!mwifiex_pcie_ok_to_access_hw(adapter))
+ mwifiex_pm_wakeup_card(adapter);
+
+ num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
+ dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
+ card->txbd_rdptr, card->txbd_wrptr);
+ if (mwifiex_pcie_txbd_not_full(card)) {
u8 *payload;
adapter->data_sent = true;
- skb_data = card->tx_buf_list[wrindx];
- memcpy(skb_data->data, skb->data, skb->len);
- payload = skb_data->data;
+ payload = skb->data;
tmp = (__le16 *)&payload[0];
*tmp = cpu_to_le16((u16)skb->len);
tmp = (__le16 *)&payload[2];
*tmp = cpu_to_le16(MWIFIEX_TYPE_DATA);
- skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len);
- skb_trim(skb_data, skb->len);
- buf_pa = MWIFIEX_SKB_PACB(skb_data);
- card->txbd_ring[wrindx]->paddr = *buf_pa;
- card->txbd_ring[wrindx]->len = (u16)skb_data->len;
- card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
- MWIFIEX_BD_FLAG_LAST_DESC;
-
- if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
- MWIFIEX_MAX_TXRX_BD)
- card->txbd_wrptr = ((card->txbd_wrptr &
- MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
- MWIFIEX_BD_FLAG_ROLLOVER_IND);
- /* Write the TX ring write pointer in to REG_TXBD_WRPTR */
- if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR,
- card->txbd_wrptr)) {
- dev_err(adapter->dev,
- "SEND DATA: failed to write REG_TXBD_WRPTR\n");
- return 0;
+ if (mwifiex_map_pci_memory(adapter, skb, skb->len ,
+ PCI_DMA_TODEVICE))
+ return -1;
+
+ wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr;
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
+ card->tx_buf_list[wrindx] = skb;
+
+ if (reg->pfu_enabled) {
+ desc2 = (void *)card->txbd_ring[wrindx];
+ desc2->paddr = buf_pa;
+ desc2->len = (u16)skb->len;
+ desc2->frag_len = (u16)skb->len;
+ desc2->offset = 0;
+ desc2->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
+ MWIFIEX_BD_FLAG_LAST_DESC;
+ } else {
+ desc = card->txbd_ring[wrindx];
+ desc->paddr = buf_pa;
+ desc->len = (u16)skb->len;
+ desc->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
+ MWIFIEX_BD_FLAG_LAST_DESC;
}
- /* Send the TX ready interrupt */
- if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
- CPU_INTR_DNLD_RDY)) {
+ switch (card->dev->device) {
+ case PCIE_DEVICE_ID_MARVELL_88W8766P:
+ card->txbd_wrptr++;
+ break;
+ case PCIE_DEVICE_ID_MARVELL_88W8897:
+ card->txbd_wrptr += reg->ring_tx_start_ptr;
+ break;
+ }
+
+ if ((card->txbd_wrptr & reg->tx_mask) == num_tx_buffs)
+ card->txbd_wrptr = ((card->txbd_wrptr &
+ reg->tx_rollover_ind) ^
+ reg->tx_rollover_ind);
+
+ rx_val = card->rxbd_rdptr & reg->rx_wrap_mask;
+ /* Write the TX ring write pointer in to reg->tx_wrptr */
+ if (mwifiex_write_reg(adapter, reg->tx_wrptr,
+ card->txbd_wrptr | rx_val)) {
dev_err(adapter->dev,
- "SEND DATA: failed to assert door-bell intr\n");
- return -1;
+ "SEND DATA: failed to write reg->tx_wrptr\n");
+ ret = -1;
+ goto done_unmap;
+ }
+ if ((mwifiex_pcie_txbd_not_full(card)) &&
+ tx_param->next_pkt_len) {
+ /* have more packets and TxBD still can hold more */
+ dev_dbg(adapter->dev,
+ "SEND DATA: delay dnld-rdy interrupt.\n");
+ adapter->data_sent = false;
+ } else {
+ /* Send the TX ready interrupt */
+ if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+ CPU_INTR_DNLD_RDY)) {
+ dev_err(adapter->dev,
+ "SEND DATA: failed to assert dnld-rdy interrupt.\n");
+ ret = -1;
+ goto done_unmap;
+ }
}
dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: "
"%#x> and sent packet to firmware successfully\n",
- rdptr, card->txbd_wrptr);
+ card->txbd_rdptr, card->txbd_wrptr);
} else {
dev_dbg(adapter->dev,
"info: TX Ring full, can't send packets to fw\n");
@@ -827,7 +1151,17 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
return -EBUSY;
}
- return 0;
+ return -EINPROGRESS;
+done_unmap:
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
+ pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE);
+ card->tx_buf_list[wrindx] = NULL;
+ if (reg->pfu_enabled)
+ memset(desc2, 0, sizeof(*desc2));
+ else
+ memset(desc, 0, sizeof(*desc));
+
+ return ret;
}
/*
@@ -837,78 +1171,119 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
- u32 wrptr, rd_index;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+ u32 wrptr, rd_index, tx_val;
+ dma_addr_t buf_pa;
int ret = 0;
struct sk_buff *skb_tmp = NULL;
+ struct mwifiex_pcie_buf_desc *desc;
+ struct mwifiex_pfu_buf_desc *desc2;
+
+ if (!mwifiex_pcie_ok_to_access_hw(adapter))
+ mwifiex_pm_wakeup_card(adapter);
/* Read the RX ring Write pointer set by firmware */
- if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+ if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
dev_err(adapter->dev,
- "RECV DATA: failed to read REG_TXBD_RDPTR\n");
+ "RECV DATA: failed to read reg->rx_wrptr\n");
ret = -1;
goto done;
}
+ card->rxbd_wrptr = wrptr;
- while (((wrptr & MWIFIEX_RXBD_MASK) !=
- (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) ||
- ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
- (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+ while (((wrptr & reg->rx_mask) !=
+ (card->rxbd_rdptr & reg->rx_mask)) ||
+ ((wrptr & reg->rx_rollover_ind) ==
+ (card->rxbd_rdptr & reg->rx_rollover_ind))) {
struct sk_buff *skb_data;
u16 rx_len;
+ __le16 pkt_len;
- rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK;
+ rd_index = card->rxbd_rdptr & reg->rx_mask;
skb_data = card->rx_buf_list[rd_index];
+ MWIFIEX_SKB_PACB(skb_data, &buf_pa);
+ pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ card->rx_buf_list[rd_index] = NULL;
+
/* Get data length from interface header -
- first byte is len, second byte is type */
- rx_len = *((u16 *)skb_data->data);
+ * first 2 bytes for len, next 2 bytes is for type
+ */
+ pkt_len = *((__le16 *)skb_data->data);
+ rx_len = le16_to_cpu(pkt_len);
+ skb_put(skb_data, rx_len);
dev_dbg(adapter->dev,
"info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
card->rxbd_rdptr, wrptr, rx_len);
- skb_tmp = dev_alloc_skb(rx_len);
+ skb_pull(skb_data, INTF_HEADER_LEN);
+ mwifiex_handle_rx_packet(adapter, skb_data);
+
+ skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
if (!skb_tmp) {
- dev_dbg(adapter->dev,
- "info: Failed to alloc skb for RX\n");
- ret = -EBUSY;
- goto done;
+ dev_err(adapter->dev,
+ "Unable to allocate skb.\n");
+ return -ENOMEM;
}
- skb_put(skb_tmp, rx_len);
+ if (mwifiex_map_pci_memory(adapter, skb_tmp,
+ MWIFIEX_RX_DATA_BUF_SIZE,
+ PCI_DMA_FROMDEVICE))
+ return -1;
+
+ MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
+
+ dev_dbg(adapter->dev,
+ "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
+ skb_tmp, rd_index);
+ card->rx_buf_list[rd_index] = skb_tmp;
+
+ if (reg->pfu_enabled) {
+ desc2 = (void *)card->rxbd_ring[rd_index];
+ desc2->paddr = buf_pa;
+ desc2->len = skb_tmp->len;
+ desc2->frag_len = skb_tmp->len;
+ desc2->offset = 0;
+ desc2->flags = reg->ring_flag_sop | reg->ring_flag_eop;
+ } else {
+ desc = card->rxbd_ring[rd_index];
+ desc->paddr = buf_pa;
+ desc->len = skb_tmp->len;
+ desc->flags = 0;
+ }
- memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len);
- if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) ==
+ if ((++card->rxbd_rdptr & reg->rx_mask) ==
MWIFIEX_MAX_TXRX_BD) {
card->rxbd_rdptr = ((card->rxbd_rdptr &
- MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
- MWIFIEX_BD_FLAG_ROLLOVER_IND);
+ reg->rx_rollover_ind) ^
+ reg->rx_rollover_ind);
}
dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
card->rxbd_rdptr, wrptr);
- /* Write the RX ring read pointer in to REG_RXBD_RDPTR */
- if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR,
- card->rxbd_rdptr)) {
+ tx_val = card->txbd_wrptr & reg->tx_wrap_mask;
+ /* Write the RX ring read pointer in to reg->rx_rdptr */
+ if (mwifiex_write_reg(adapter, reg->rx_rdptr,
+ card->rxbd_rdptr | tx_val)) {
dev_err(adapter->dev,
- "RECV DATA: failed to write REG_RXBD_RDPTR\n");
+ "RECV DATA: failed to write reg->rx_rdptr\n");
ret = -1;
goto done;
}
/* Read the RX ring Write pointer set by firmware */
- if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
+ if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
dev_err(adapter->dev,
- "RECV DATA: failed to read REG_TXBD_RDPTR\n");
+ "RECV DATA: failed to read reg->rx_wrptr\n");
ret = -1;
goto done;
}
dev_dbg(adapter->dev,
"info: RECV DATA: Rcvd packet from fw successfully\n");
- mwifiex_handle_rx_packet(adapter, skb_tmp);
+ card->rxbd_wrptr = wrptr;
}
done:
- if (ret && skb_tmp)
- dev_kfree_skb_any(skb_tmp);
return ret;
}
@@ -918,40 +1293,54 @@ done:
static int
mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
{
- phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb);
+ dma_addr_t buf_pa;
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- if (!(skb->data && skb->len && *buf_pa)) {
+ if (!(skb->data && skb->len)) {
dev_err(adapter->dev,
- "Invalid parameter in %s <%p, %#x:%x, %x>\n",
- __func__, skb->data, skb->len,
- (u32)*buf_pa, (u32)((u64)*buf_pa >> 32));
+ "Invalid parameter in %s <%p. len %d>\n",
+ __func__, skb->data, skb->len);
return -1;
}
- /* Write the lower 32bits of the physical address to scratch
- * register 0 */
- if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) {
+ if (mwifiex_map_pci_memory(adapter, skb, skb->len , PCI_DMA_TODEVICE))
+ return -1;
+
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
+
+ /* Write the lower 32bits of the physical address to low command
+ * address scratch register
+ */
+ if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, (u32)buf_pa)) {
dev_err(adapter->dev,
"%s: failed to write download command to boot code.\n",
__func__);
+ pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+ PCI_DMA_TODEVICE);
return -1;
}
- /* Write the upper 32bits of the physical address to scratch
- * register 1 */
- if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG,
- (u32)((u64)*buf_pa >> 32))) {
+ /* Write the upper 32bits of the physical address to high command
+ * address scratch register
+ */
+ if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
+ (u32)((u64)buf_pa >> 32))) {
dev_err(adapter->dev,
"%s: failed to write download command to boot code.\n",
__func__);
+ pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+ PCI_DMA_TODEVICE);
return -1;
}
- /* Write the command length to scratch register 2 */
- if (mwifiex_write_reg(adapter, PCIE_SCRATCH_2_REG, skb->len)) {
+ /* Write the command length to cmd_size scratch register */
+ if (mwifiex_write_reg(adapter, reg->cmd_size, skb->len)) {
dev_err(adapter->dev,
- "%s: failed to write command len to scratch reg 2\n",
+ "%s: failed to write command len to cmd_size scratch reg\n",
__func__);
+ pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+ PCI_DMA_TODEVICE);
return -1;
}
@@ -960,22 +1349,43 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
CPU_INTR_DOOR_BELL)) {
dev_err(adapter->dev,
"%s: failed to assert door-bell intr\n", __func__);
+ pci_unmap_single(card->dev, buf_pa,
+ MWIFIEX_UPLD_SIZE, PCI_DMA_TODEVICE);
return -1;
}
return 0;
}
-/*
- * This function downloads commands to the device
+/* This function init rx port in firmware which in turn enables to receive data
+ * from device before transmitting any packet.
+ */
+static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
+{
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+ int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask;
+
+ /* Write the RX ring read pointer in to reg->rx_rdptr */
+ if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr |
+ tx_wrap)) {
+ dev_err(adapter->dev,
+ "RECV DATA: failed to write reg->rx_rdptr\n");
+ return -1;
+ }
+ return 0;
+}
+
+/* This function downloads commands to the device
*/
static int
mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
{
struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
int ret = 0;
- phys_addr_t *cmd_buf_pa;
- phys_addr_t *cmdrsp_buf_pa;
+ dma_addr_t cmd_buf_pa, cmdrsp_buf_pa;
+ u8 *payload = (u8 *)skb->data;
if (!(skb->data && skb->len)) {
dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n",
@@ -990,21 +1400,22 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
return -EBUSY;
}
- /* Make sure a command buffer is available */
- if (!card->cmd_buf) {
- dev_err(adapter->dev, "Command buffer not available\n");
- return -EBUSY;
- }
+ if (!mwifiex_pcie_ok_to_access_hw(adapter))
+ mwifiex_pm_wakeup_card(adapter);
adapter->cmd_sent = true;
- /* Copy the given skb in to DMA accessable shared buffer */
- skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len);
- skb_trim(card->cmd_buf, skb->len);
- memcpy(card->cmd_buf->data, skb->data, skb->len);
+
+ *(__le16 *)&payload[0] = cpu_to_le16((u16)skb->len);
+ *(__le16 *)&payload[2] = cpu_to_le16(MWIFIEX_TYPE_CMD);
+
+ if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE))
+ return -1;
+
+ card->cmd_buf = skb;
/* To send a command, the driver will:
1. Write the 64bit physical address of the data buffer to
- SCRATCH1 + SCRATCH0
+ cmd response address low + cmd response address high
2. Ring the door bell (i.e. set the door bell interrupt)
In response to door bell interrupt, the firmware will perform
@@ -1013,11 +1424,11 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
*/
if (card->cmdrsp_buf) {
- cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf);
+ MWIFIEX_SKB_PACB(card->cmdrsp_buf, &cmdrsp_buf_pa);
/* Write the lower 32bits of the cmdrsp buffer physical
address */
- if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO,
- (u32)*cmdrsp_buf_pa)) {
+ if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo,
+ (u32)cmdrsp_buf_pa)) {
dev_err(adapter->dev,
"Failed to write download cmd to boot code.\n");
ret = -1;
@@ -1025,8 +1436,8 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
}
/* Write the upper 32bits of the cmdrsp buffer physical
address */
- if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI,
- (u32)((u64)*cmdrsp_buf_pa >> 32))) {
+ if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi,
+ (u32)((u64)cmdrsp_buf_pa >> 32))) {
dev_err(adapter->dev,
"Failed to write download cmd to boot code.\n");
ret = -1;
@@ -1034,27 +1445,29 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
}
}
- cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf);
- /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */
- if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, (u32)*cmd_buf_pa)) {
+ MWIFIEX_SKB_PACB(card->cmd_buf, &cmd_buf_pa);
+ /* Write the lower 32bits of the physical address to reg->cmd_addr_lo */
+ if (mwifiex_write_reg(adapter, reg->cmd_addr_lo,
+ (u32)cmd_buf_pa)) {
dev_err(adapter->dev,
"Failed to write download cmd to boot code.\n");
ret = -1;
goto done;
}
- /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */
- if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI,
- (u32)((u64)*cmd_buf_pa >> 32))) {
+ /* Write the upper 32bits of the physical address to reg->cmd_addr_hi */
+ if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
+ (u32)((u64)cmd_buf_pa >> 32))) {
dev_err(adapter->dev,
"Failed to write download cmd to boot code.\n");
ret = -1;
goto done;
}
- /* Write the command length to REG_CMD_SIZE */
- if (mwifiex_write_reg(adapter, REG_CMD_SIZE, card->cmd_buf->len)) {
+ /* Write the command length to reg->cmd_size */
+ if (mwifiex_write_reg(adapter, reg->cmd_size,
+ card->cmd_buf->len)) {
dev_err(adapter->dev,
- "Failed to write cmd len to REG_CMD_SIZE\n");
+ "Failed to write cmd len to reg->cmd_size\n");
ret = -1;
goto done;
}
@@ -1081,18 +1494,30 @@ done:
static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
struct sk_buff *skb = card->cmdrsp_buf;
int count = 0;
+ u16 rx_len;
+ __le16 pkt_len;
+ dma_addr_t buf_pa;
dev_dbg(adapter->dev, "info: Rx CMD Response\n");
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
+ pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+ PCI_DMA_FROMDEVICE);
+
+ pkt_len = *((__le16 *)skb->data);
+ rx_len = le16_to_cpu(pkt_len);
+ skb_trim(skb, rx_len);
+ skb_pull(skb, INTF_HEADER_LEN);
+
if (!adapter->curr_cmd) {
- skb_pull(skb, INTF_HEADER_LEN);
if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
mwifiex_process_sleep_confirm_resp(adapter, skb->data,
skb->len);
- while (mwifiex_pcie_ok_to_access_hw(adapter) &&
- (count++ < 10))
+ while (reg->sleep_cookie && (count++ < 10) &&
+ mwifiex_pcie_ok_to_access_hw(adapter))
usleep_range(50, 60);
} else {
dev_err(adapter->dev,
@@ -1100,9 +1525,12 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
}
memcpy(adapter->upld_buf, skb->data,
min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
- skb_push(skb, INTF_HEADER_LEN);
+ if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
+ PCI_DMA_FROMDEVICE))
+ return -1;
+
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
} else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
- skb_pull(skb, INTF_HEADER_LEN);
adapter->curr_cmd->resp_skb = skb;
adapter->cmd_resp_received = true;
/* Take the pointer and set it to CMD node and will
@@ -1112,14 +1540,14 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
/* Clear the cmd-rsp buffer address in scratch registers. This
will prevent firmware from writing to the same response
buffer again. */
- if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, 0)) {
+ if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, 0)) {
dev_err(adapter->dev,
"cmd_done: failed to clear cmd_rsp_addr_lo\n");
return -1;
}
/* Write the upper 32bits of the cmdrsp buffer physical
address */
- if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, 0)) {
+ if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, 0)) {
dev_err(adapter->dev,
"cmd_done: failed to clear cmd_rsp_addr_hi\n");
return -1;
@@ -1136,10 +1564,23 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
struct sk_buff *skb)
{
struct pcie_service_card *card = adapter->card;
+ dma_addr_t buf_pa;
+ struct sk_buff *skb_tmp;
if (skb) {
card->cmdrsp_buf = skb;
skb_push(card->cmdrsp_buf, INTF_HEADER_LEN);
+ if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
+ PCI_DMA_FROMDEVICE))
+ return -1;
+ }
+
+ skb_tmp = card->cmd_buf;
+ if (skb_tmp) {
+ MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
+ pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+ PCI_DMA_FROMDEVICE);
+ card->cmd_buf = NULL;
}
return 0;
@@ -1151,8 +1592,14 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
u32 wrptr, event;
+ dma_addr_t buf_pa;
+ struct mwifiex_evt_buf_desc *desc;
+
+ if (!mwifiex_pcie_ok_to_access_hw(adapter))
+ mwifiex_pm_wakeup_card(adapter);
if (adapter->event_received) {
dev_dbg(adapter->dev, "info: Event being processed, "
@@ -1166,9 +1613,9 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
}
/* Read the event ring write pointer set by firmware */
- if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+ if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
dev_err(adapter->dev,
- "EventReady: failed to read REG_EVTBD_WRPTR\n");
+ "EventReady: failed to read reg->evt_wrptr\n");
return -1;
}
@@ -1176,20 +1623,23 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
card->evtbd_rdptr, wrptr);
if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr
& MWIFIEX_EVTBD_MASK)) ||
- ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) ==
- (card->evtbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+ ((wrptr & reg->evt_rollover_ind) ==
+ (card->evtbd_rdptr & reg->evt_rollover_ind))) {
struct sk_buff *skb_cmd;
__le16 data_len = 0;
u16 evt_len;
dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr);
skb_cmd = card->evt_buf_list[rdptr];
+ MWIFIEX_SKB_PACB(skb_cmd, &buf_pa);
+ pci_unmap_single(card->dev, buf_pa, MAX_EVENT_SIZE,
+ PCI_DMA_FROMDEVICE);
+
/* Take the pointer and set it to event pointer in adapter
and will return back after event handling callback */
card->evt_buf_list[rdptr] = NULL;
- card->evtbd_ring[rdptr]->paddr = 0;
- card->evtbd_ring[rdptr]->len = 0;
- card->evtbd_ring[rdptr]->flags = 0;
+ desc = card->evtbd_ring[rdptr];
+ memset(desc, 0, sizeof(*desc));
event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN];
adapter->event_cause = event;
@@ -1225,10 +1675,12 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
struct sk_buff *skb)
{
struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
int ret = 0;
u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
u32 wrptr;
- phys_addr_t *buf_pa;
+ dma_addr_t buf_pa;
+ struct mwifiex_evt_buf_desc *desc;
if (!skb)
return 0;
@@ -1240,19 +1692,25 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
}
/* Read the event ring write pointer set by firmware */
- if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
+ if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
dev_err(adapter->dev,
- "event_complete: failed to read REG_EVTBD_WRPTR\n");
+ "event_complete: failed to read reg->evt_wrptr\n");
return -1;
}
if (!card->evt_buf_list[rdptr]) {
skb_push(skb, INTF_HEADER_LEN);
+ if (mwifiex_map_pci_memory(adapter, skb,
+ MAX_EVENT_SIZE,
+ PCI_DMA_FROMDEVICE))
+ return -1;
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
card->evt_buf_list[rdptr] = skb;
- buf_pa = MWIFIEX_SKB_PACB(skb);
- card->evtbd_ring[rdptr]->paddr = *buf_pa;
- card->evtbd_ring[rdptr]->len = (u16)skb->len;
- card->evtbd_ring[rdptr]->flags = 0;
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
+ desc = card->evtbd_ring[rdptr];
+ desc->paddr = buf_pa;
+ desc->len = (u16)skb->len;
+ desc->flags = 0;
skb = NULL;
} else {
dev_dbg(adapter->dev,
@@ -1262,17 +1720,18 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
card->evtbd_rdptr = ((card->evtbd_rdptr &
- MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
- MWIFIEX_BD_FLAG_ROLLOVER_IND);
+ reg->evt_rollover_ind) ^
+ reg->evt_rollover_ind);
}
dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>",
card->evtbd_rdptr, wrptr);
- /* Write the event ring read pointer in to REG_EVTBD_RDPTR */
- if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) {
+ /* Write the event ring read pointer in to reg->evt_rdptr */
+ if (mwifiex_write_reg(adapter, reg->evt_rdptr,
+ card->evtbd_rdptr)) {
dev_err(adapter->dev,
- "event_complete: failed to read REG_EVTBD_RDPTR\n");
+ "event_complete: failed to read reg->evt_rdptr\n");
return -1;
}
@@ -1299,11 +1758,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
struct sk_buff *skb;
u32 txlen, tx_blocks = 0, tries, len;
u32 block_retry_cnt = 0;
-
- if (!adapter) {
- pr_err("adapter structure is not valid\n");
- return -1;
- }
+ dma_addr_t buf_pa;
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
if (!firmware || !firmware_len) {
dev_err(adapter->dev,
@@ -1325,7 +1782,6 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
ret = -ENOMEM;
goto done;
}
- mwifiex_update_sk_buff_pa(skb);
/* Perform firmware data transfer */
do {
@@ -1336,7 +1792,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
break;
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
- ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_2_REG,
+ ret = mwifiex_read_reg(adapter, reg->cmd_size,
&len);
if (ret) {
dev_warn(adapter->dev,
@@ -1382,16 +1838,15 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
dev_dbg(adapter->dev, ".");
- tx_blocks = (txlen +
- MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD - 1) /
- MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD;
+ tx_blocks = (txlen + card->pcie.blksz_fw_dl - 1) /
+ card->pcie.blksz_fw_dl;
/* Copy payload to buffer */
memmove(skb->data, &firmware[offset], txlen);
}
skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
- skb_trim(skb, tx_blocks * MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD);
+ skb_trim(skb, tx_blocks * card->pcie.blksz_fw_dl);
/* Send the boot command to device */
if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
@@ -1400,6 +1855,9 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
ret = -1;
goto done;
}
+
+ MWIFIEX_SKB_PACB(skb, &buf_pa);
+
/* Wait for the command done interrupt */
do {
if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
@@ -1407,11 +1865,17 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
dev_err(adapter->dev, "%s: Failed to read "
"interrupt status during fw dnld.\n",
__func__);
+ pci_unmap_single(card->dev, buf_pa, skb->len,
+ PCI_DMA_TODEVICE);
ret = -1;
goto done;
}
} while ((ireg_intr & CPU_INTR_DOOR_BELL) ==
CPU_INTR_DOOR_BELL);
+
+ pci_unmap_single(card->dev, buf_pa, skb->len,
+ PCI_DMA_TODEVICE);
+
offset += txlen;
} while (true);
@@ -1435,6 +1899,8 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
{
int ret = 0;
u32 firmware_stat, winner_status;
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
u32 tries;
/* Mask spurios interrupts */
@@ -1445,7 +1911,8 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
}
dev_dbg(adapter->dev, "Setting driver ready signature\n");
- if (mwifiex_write_reg(adapter, REG_DRV_READY, FIRMWARE_READY_PCIE)) {
+ if (mwifiex_write_reg(adapter, reg->drv_rdy,
+ FIRMWARE_READY_PCIE)) {
dev_err(adapter->dev,
"Failed to write driver ready signature\n");
return -1;
@@ -1453,7 +1920,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
/* Wait for firmware initialization event */
for (tries = 0; tries < poll_num; tries++) {
- if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+ if (mwifiex_read_reg(adapter, reg->fw_status,
&firmware_stat))
ret = -1;
else
@@ -1470,7 +1937,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
}
if (ret) {
- if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG,
+ if (mwifiex_read_reg(adapter, reg->fw_status,
&winner_status))
ret = -1;
else if (!winner_status) {
@@ -1594,39 +2061,40 @@ exit:
static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
{
int ret;
- u32 pcie_ireg = 0;
+ u32 pcie_ireg;
unsigned long flags;
spin_lock_irqsave(&adapter->int_lock, flags);
/* Clear out unused interrupts */
- adapter->int_status &= HOST_INTR_MASK;
+ pcie_ireg = adapter->int_status;
+ adapter->int_status = 0;
spin_unlock_irqrestore(&adapter->int_lock, flags);
- while (adapter->int_status & HOST_INTR_MASK) {
- if (adapter->int_status & HOST_INTR_DNLD_DONE) {
- adapter->int_status &= ~HOST_INTR_DNLD_DONE;
- if (adapter->data_sent) {
- dev_dbg(adapter->dev, "info: DATA sent intr\n");
- adapter->data_sent = false;
- }
+ while (pcie_ireg & HOST_INTR_MASK) {
+ if (pcie_ireg & HOST_INTR_DNLD_DONE) {
+ pcie_ireg &= ~HOST_INTR_DNLD_DONE;
+ dev_dbg(adapter->dev, "info: TX DNLD Done\n");
+ ret = mwifiex_pcie_send_data_complete(adapter);
+ if (ret)
+ return ret;
}
- if (adapter->int_status & HOST_INTR_UPLD_RDY) {
- adapter->int_status &= ~HOST_INTR_UPLD_RDY;
+ if (pcie_ireg & HOST_INTR_UPLD_RDY) {
+ pcie_ireg &= ~HOST_INTR_UPLD_RDY;
dev_dbg(adapter->dev, "info: Rx DATA\n");
ret = mwifiex_pcie_process_recv_data(adapter);
if (ret)
return ret;
}
- if (adapter->int_status & HOST_INTR_EVENT_RDY) {
- adapter->int_status &= ~HOST_INTR_EVENT_RDY;
+ if (pcie_ireg & HOST_INTR_EVENT_RDY) {
+ pcie_ireg &= ~HOST_INTR_EVENT_RDY;
dev_dbg(adapter->dev, "info: Rx EVENT\n");
ret = mwifiex_pcie_process_event_ready(adapter);
if (ret)
return ret;
}
- if (adapter->int_status & HOST_INTR_CMD_DONE) {
- adapter->int_status &= ~HOST_INTR_CMD_DONE;
+ if (pcie_ireg & HOST_INTR_CMD_DONE) {
+ pcie_ireg &= ~HOST_INTR_CMD_DONE;
if (adapter->cmd_sent) {
dev_dbg(adapter->dev,
"info: CMD sent Interrupt\n");
@@ -1654,8 +2122,6 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
"Write register failed\n");
return -1;
}
- adapter->int_status |= pcie_ireg;
- adapter->int_status &= HOST_INTR_MASK;
}
}
@@ -1687,7 +2153,7 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
}
if (type == MWIFIEX_TYPE_DATA)
- return mwifiex_pcie_send_data(adapter, skb);
+ return mwifiex_pcie_send_data(adapter, skb, tx_param);
else if (type == MWIFIEX_TYPE_CMD)
return mwifiex_pcie_send_cmd(adapter, skb);
@@ -1709,6 +2175,7 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
struct pcie_service_card *card = adapter->card;
int ret;
struct pci_dev *pdev = card->dev;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
pci_set_drvdata(pdev, card);
@@ -1739,6 +2206,7 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
card->pci_mmap = pci_iomap(pdev, 0, 0);
if (!card->pci_mmap) {
dev_err(adapter->dev, "iomap(0) error\n");
+ ret = -EIO;
goto err_iomap0;
}
ret = pci_request_region(pdev, 2, DRV_NAME);
@@ -1749,6 +2217,7 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
card->pci_mmap1 = pci_iomap(pdev, 2, 0);
if (!card->pci_mmap1) {
dev_err(adapter->dev, "iomap(2) error\n");
+ ret = -EIO;
goto err_iomap2;
}
@@ -1769,10 +2238,13 @@ static int mwifiex_pcie_init(struct mwifiex_adapter *adapter)
ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
if (ret)
goto err_alloc_cmdbuf;
- ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
- if (ret)
- goto err_alloc_cookie;
-
+ if (reg->sleep_cookie) {
+ ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
+ if (ret)
+ goto err_alloc_cookie;
+ } else {
+ card->sleep_cookie_vbase = NULL;
+ }
return ret;
err_alloc_cookie:
@@ -1813,17 +2285,11 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
struct pci_dev *pdev = card->dev;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- mwifiex_pcie_delete_sleep_cookie_buf(adapter);
- mwifiex_pcie_delete_cmdrsp_buf(adapter);
- mwifiex_pcie_delete_evtbd_ring(adapter);
- mwifiex_pcie_delete_rxbd_ring(adapter);
- mwifiex_pcie_delete_txbd_ring(adapter);
- card->cmdrsp_buf = NULL;
-
- dev_dbg(adapter->dev, "Clearing driver ready signature\n");
if (user_rmmod) {
- if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000))
+ dev_dbg(adapter->dev, "Clearing driver ready signature\n");
+ if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
dev_err(adapter->dev,
"Failed to write driver not-ready signature\n");
}
@@ -1861,7 +2327,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
}
adapter->dev = &pdev->dev;
- strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME);
+ strcpy(adapter->fw_name, card->pcie.firmware);
return 0;
}
@@ -1875,10 +2341,21 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg;
if (card) {
dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__);
free_irq(card->dev->irq, card->dev);
+
+ reg = card->pcie.reg;
+ if (reg->sleep_cookie)
+ mwifiex_pcie_delete_sleep_cookie_buf(adapter);
+
+ mwifiex_pcie_delete_cmdrsp_buf(adapter);
+ mwifiex_pcie_delete_evtbd_ring(adapter);
+ mwifiex_pcie_delete_rxbd_ring(adapter);
+ mwifiex_pcie_delete_txbd_ring(adapter);
+ card->cmdrsp_buf = NULL;
}
}
@@ -1900,6 +2377,8 @@ static struct mwifiex_if_ops pcie_ops = {
.event_complete = mwifiex_pcie_event_complete,
.update_mp_end_port = NULL,
.cleanup_mpa_buf = NULL,
+ .init_fw_port = mwifiex_pcie_init_fw_port,
+ .clean_pcie_ring = mwifiex_clean_pcie_ring_buf,
};
/*
@@ -1912,7 +2391,7 @@ static int mwifiex_pcie_init_module(void)
{
int ret;
- pr_debug("Marvell 8766 PCIe Driver\n");
+ pr_debug("Marvell PCIe Driver\n");
sema_init(&add_remove_card_sem, 1);
@@ -1955,4 +2434,5 @@ MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION);
MODULE_VERSION(PCIE_VERSION);
MODULE_LICENSE("GPL v2");
-MODULE_FIRMWARE("mrvl/pcie8766_uapsta.bin");
+MODULE_FIRMWARE(PCIE8766_DEFAULT_FW_NAME);
+MODULE_FIRMWARE(PCIE8897_DEFAULT_FW_NAME);
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
index 2f218f9a3fd3..d322ab8604ea 100644
--- a/drivers/net/wireless/mwifiex/pcie.h
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -29,6 +29,11 @@
#include "main.h"
#define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"
+#define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin"
+
+#define PCIE_VENDOR_ID_MARVELL (0x11ab)
+#define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30)
+#define PCIE_DEVICE_ID_MARVELL_88W8897 (0x2b38)
/* Constants for Buffer Descriptor (BD) rings */
#define MWIFIEX_MAX_TXRX_BD 0x20
@@ -57,6 +62,8 @@
#define PCIE_SCRATCH_10_REG 0xCE8
#define PCIE_SCRATCH_11_REG 0xCEC
#define PCIE_SCRATCH_12_REG 0xCF0
+#define PCIE_RD_DATA_PTR_Q0_Q1 0xC08C
+#define PCIE_WR_DATA_PTR_Q0_Q1 0xC05C
#define CPU_INTR_DNLD_RDY BIT(0)
#define CPU_INTR_DOOR_BELL BIT(1)
@@ -75,27 +82,14 @@
#define MWIFIEX_BD_FLAG_ROLLOVER_IND BIT(7)
#define MWIFIEX_BD_FLAG_FIRST_DESC BIT(0)
#define MWIFIEX_BD_FLAG_LAST_DESC BIT(1)
-#define REG_CMD_ADDR_LO PCIE_SCRATCH_0_REG
-#define REG_CMD_ADDR_HI PCIE_SCRATCH_1_REG
-#define REG_CMD_SIZE PCIE_SCRATCH_2_REG
-
-#define REG_CMDRSP_ADDR_LO PCIE_SCRATCH_4_REG
-#define REG_CMDRSP_ADDR_HI PCIE_SCRATCH_5_REG
-
-/* TX buffer description read pointer */
-#define REG_TXBD_RDPTR PCIE_SCRATCH_6_REG
-/* TX buffer description write pointer */
-#define REG_TXBD_WRPTR PCIE_SCRATCH_7_REG
-/* RX buffer description read pointer */
-#define REG_RXBD_RDPTR PCIE_SCRATCH_8_REG
-/* RX buffer description write pointer */
-#define REG_RXBD_WRPTR PCIE_SCRATCH_9_REG
-/* Event buffer description read pointer */
-#define REG_EVTBD_RDPTR PCIE_SCRATCH_10_REG
-/* Event buffer description write pointer */
-#define REG_EVTBD_WRPTR PCIE_SCRATCH_11_REG
-/* Driver ready signature write pointer */
-#define REG_DRV_READY PCIE_SCRATCH_12_REG
+#define MWIFIEX_BD_FLAG_SOP BIT(0)
+#define MWIFIEX_BD_FLAG_EOP BIT(1)
+#define MWIFIEX_BD_FLAG_XS_SOP BIT(2)
+#define MWIFIEX_BD_FLAG_XS_EOP BIT(3)
+#define MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND BIT(7)
+#define MWIFIEX_BD_FLAG_RX_ROLLOVER_IND BIT(10)
+#define MWIFIEX_BD_FLAG_TX_START_PTR BIT(16)
+#define MWIFIEX_BD_FLAG_TX_ROLLOVER_IND BIT(26)
/* Max retry number of command write */
#define MAX_WRITE_IOMEM_RETRY 2
@@ -104,45 +98,223 @@
/* FW awake cookie after FW ready */
#define FW_AWAKE_COOKIE (0xAA55AA55)
+struct mwifiex_pcie_card_reg {
+ u16 cmd_addr_lo;
+ u16 cmd_addr_hi;
+ u16 fw_status;
+ u16 cmd_size;
+ u16 cmdrsp_addr_lo;
+ u16 cmdrsp_addr_hi;
+ u16 tx_rdptr;
+ u16 tx_wrptr;
+ u16 rx_rdptr;
+ u16 rx_wrptr;
+ u16 evt_rdptr;
+ u16 evt_wrptr;
+ u16 drv_rdy;
+ u16 tx_start_ptr;
+ u32 tx_mask;
+ u32 tx_wrap_mask;
+ u32 rx_mask;
+ u32 rx_wrap_mask;
+ u32 tx_rollover_ind;
+ u32 rx_rollover_ind;
+ u32 evt_rollover_ind;
+ u8 ring_flag_sop;
+ u8 ring_flag_eop;
+ u8 ring_flag_xs_sop;
+ u8 ring_flag_xs_eop;
+ u32 ring_tx_start_ptr;
+ u8 pfu_enabled;
+ u8 sleep_cookie;
+};
+
+static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
+ .cmd_addr_lo = PCIE_SCRATCH_0_REG,
+ .cmd_addr_hi = PCIE_SCRATCH_1_REG,
+ .cmd_size = PCIE_SCRATCH_2_REG,
+ .fw_status = PCIE_SCRATCH_3_REG,
+ .cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
+ .cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
+ .tx_rdptr = PCIE_SCRATCH_6_REG,
+ .tx_wrptr = PCIE_SCRATCH_7_REG,
+ .rx_rdptr = PCIE_SCRATCH_8_REG,
+ .rx_wrptr = PCIE_SCRATCH_9_REG,
+ .evt_rdptr = PCIE_SCRATCH_10_REG,
+ .evt_wrptr = PCIE_SCRATCH_11_REG,
+ .drv_rdy = PCIE_SCRATCH_12_REG,
+ .tx_start_ptr = 0,
+ .tx_mask = MWIFIEX_TXBD_MASK,
+ .tx_wrap_mask = 0,
+ .rx_mask = MWIFIEX_RXBD_MASK,
+ .rx_wrap_mask = 0,
+ .tx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
+ .rx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
+ .evt_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
+ .ring_flag_sop = 0,
+ .ring_flag_eop = 0,
+ .ring_flag_xs_sop = 0,
+ .ring_flag_xs_eop = 0,
+ .ring_tx_start_ptr = 0,
+ .pfu_enabled = 0,
+ .sleep_cookie = 1,
+};
+
+static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
+ .cmd_addr_lo = PCIE_SCRATCH_0_REG,
+ .cmd_addr_hi = PCIE_SCRATCH_1_REG,
+ .cmd_size = PCIE_SCRATCH_2_REG,
+ .fw_status = PCIE_SCRATCH_3_REG,
+ .cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
+ .cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
+ .tx_rdptr = PCIE_RD_DATA_PTR_Q0_Q1,
+ .tx_wrptr = PCIE_WR_DATA_PTR_Q0_Q1,
+ .rx_rdptr = PCIE_WR_DATA_PTR_Q0_Q1,
+ .rx_wrptr = PCIE_RD_DATA_PTR_Q0_Q1,
+ .evt_rdptr = PCIE_SCRATCH_10_REG,
+ .evt_wrptr = PCIE_SCRATCH_11_REG,
+ .drv_rdy = PCIE_SCRATCH_12_REG,
+ .tx_start_ptr = 16,
+ .tx_mask = 0x03FF0000,
+ .tx_wrap_mask = 0x07FF0000,
+ .rx_mask = 0x000003FF,
+ .rx_wrap_mask = 0x000007FF,
+ .tx_rollover_ind = MWIFIEX_BD_FLAG_TX_ROLLOVER_IND,
+ .rx_rollover_ind = MWIFIEX_BD_FLAG_RX_ROLLOVER_IND,
+ .evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND,
+ .ring_flag_sop = MWIFIEX_BD_FLAG_SOP,
+ .ring_flag_eop = MWIFIEX_BD_FLAG_EOP,
+ .ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP,
+ .ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP,
+ .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
+ .pfu_enabled = 1,
+ .sleep_cookie = 0,
+};
+
+struct mwifiex_pcie_device {
+ const char *firmware;
+ const struct mwifiex_pcie_card_reg *reg;
+ u16 blksz_fw_dl;
+};
+
+static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
+ .firmware = PCIE8766_DEFAULT_FW_NAME,
+ .reg = &mwifiex_reg_8766,
+ .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
+};
+
+static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
+ .firmware = PCIE8897_DEFAULT_FW_NAME,
+ .reg = &mwifiex_reg_8897,
+ .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
+};
+
+struct mwifiex_evt_buf_desc {
+ u64 paddr;
+ u16 len;
+ u16 flags;
+} __packed;
+
struct mwifiex_pcie_buf_desc {
u64 paddr;
u16 len;
u16 flags;
} __packed;
+struct mwifiex_pfu_buf_desc {
+ u16 flags;
+ u16 offset;
+ u16 frag_len;
+ u16 len;
+ u64 paddr;
+ u32 reserved;
+} __packed;
+
struct pcie_service_card {
struct pci_dev *dev;
struct mwifiex_adapter *adapter;
+ struct mwifiex_pcie_device pcie;
+ u8 txbd_flush;
u32 txbd_wrptr;
u32 txbd_rdptr;
u32 txbd_ring_size;
u8 *txbd_ring_vbase;
- phys_addr_t txbd_ring_pbase;
- struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD];
+ dma_addr_t txbd_ring_pbase;
+ void *txbd_ring[MWIFIEX_MAX_TXRX_BD];
struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD];
u32 rxbd_wrptr;
u32 rxbd_rdptr;
u32 rxbd_ring_size;
u8 *rxbd_ring_vbase;
- phys_addr_t rxbd_ring_pbase;
- struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD];
+ dma_addr_t rxbd_ring_pbase;
+ void *rxbd_ring[MWIFIEX_MAX_TXRX_BD];
struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD];
u32 evtbd_wrptr;
u32 evtbd_rdptr;
u32 evtbd_ring_size;
u8 *evtbd_ring_vbase;
- phys_addr_t evtbd_ring_pbase;
- struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD];
+ dma_addr_t evtbd_ring_pbase;
+ void *evtbd_ring[MWIFIEX_MAX_EVT_BD];
struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD];
struct sk_buff *cmd_buf;
struct sk_buff *cmdrsp_buf;
- struct sk_buff *sleep_cookie;
+ u8 *sleep_cookie_vbase;
+ dma_addr_t sleep_cookie_pbase;
void __iomem *pci_mmap;
void __iomem *pci_mmap1;
};
+static inline int
+mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr)
+{
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+ switch (card->dev->device) {
+ case PCIE_DEVICE_ID_MARVELL_88W8766P:
+ if (((card->txbd_wrptr & reg->tx_mask) ==
+ (rdptr & reg->tx_mask)) &&
+ ((card->txbd_wrptr & reg->tx_rollover_ind) !=
+ (rdptr & reg->tx_rollover_ind)))
+ return 1;
+ break;
+ case PCIE_DEVICE_ID_MARVELL_88W8897:
+ if (((card->txbd_wrptr & reg->tx_mask) ==
+ (rdptr & reg->tx_mask)) &&
+ ((card->txbd_wrptr & reg->tx_rollover_ind) ==
+ (rdptr & reg->tx_rollover_ind)))
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+static inline int
+mwifiex_pcie_txbd_not_full(struct pcie_service_card *card)
+{
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+ switch (card->dev->device) {
+ case PCIE_DEVICE_ID_MARVELL_88W8766P:
+ if (((card->txbd_wrptr & reg->tx_mask) !=
+ (card->txbd_rdptr & reg->tx_mask)) ||
+ ((card->txbd_wrptr & reg->tx_rollover_ind) !=
+ (card->txbd_rdptr & reg->tx_rollover_ind)))
+ return 1;
+ break;
+ case PCIE_DEVICE_ID_MARVELL_88W8897:
+ if (((card->txbd_wrptr & reg->tx_mask) !=
+ (card->txbd_rdptr & reg->tx_mask)) ||
+ ((card->txbd_wrptr & reg->tx_rollover_ind) ==
+ (card->txbd_rdptr & reg->tx_rollover_ind)))
+ return 1;
+ break;
+ }
+
+ return 0;
+}
#endif /* _MWIFIEX_PCIE_H */
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 9189a32b7844..bb60c2754a97 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -1250,6 +1250,23 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
sizeof(struct ieee_types_header) -
bss_entry->beacon_buf);
break;
+ case WLAN_EID_VHT_CAPABILITY:
+ bss_entry->disable_11ac = false;
+ bss_entry->bcn_vht_cap =
+ (void *)(current_ptr +
+ sizeof(struct ieee_types_header));
+ bss_entry->vht_cap_offset =
+ (u16)((u8 *)bss_entry->bcn_vht_cap -
+ bss_entry->beacon_buf);
+ break;
+ case WLAN_EID_VHT_OPERATION:
+ bss_entry->bcn_vht_oper =
+ (void *)(current_ptr +
+ sizeof(struct ieee_types_header));
+ bss_entry->vht_info_offset =
+ (u16)((u8 *)bss_entry->bcn_vht_oper -
+ bss_entry->beacon_buf);
+ break;
case WLAN_EID_BSS_COEX_2040:
bss_entry->bcn_bss_co_2040 = current_ptr +
sizeof(struct ieee_types_header);
@@ -1264,6 +1281,14 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
sizeof(struct ieee_types_header) -
bss_entry->beacon_buf);
break;
+ case WLAN_EID_OPMODE_NOTIF:
+ bss_entry->oper_mode =
+ (void *)(current_ptr +
+ sizeof(struct ieee_types_header));
+ bss_entry->oper_mode_offset =
+ (u16)((u8 *)bss_entry->oper_mode -
+ bss_entry->beacon_buf);
+ break;
default:
break;
}
@@ -1309,7 +1334,6 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
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 filtered_scan;
u8 scan_current_chan_only;
@@ -1332,18 +1356,16 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!scan_cfg_out) {
- dev_err(adapter->dev, "failed to alloc scan_cfg_out\n");
ret = -ENOMEM;
goto done;
}
- buf_size = sizeof(struct mwifiex_chan_scan_param_set) *
- MWIFIEX_USER_SCAN_CHAN_MAX;
- scan_chan_list = kzalloc(buf_size, GFP_KERNEL);
+ scan_chan_list = kcalloc(MWIFIEX_USER_SCAN_CHAN_MAX,
+ sizeof(struct mwifiex_chan_scan_param_set),
+ GFP_KERNEL);
if (!scan_chan_list) {
- dev_err(adapter->dev, "failed to alloc scan_chan_list\n");
kfree(scan_cfg_out);
ret = -ENOMEM;
goto done;
@@ -1461,12 +1483,9 @@ static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
unsigned long flags;
/* Allocate and fill new bss descriptor */
- bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
- GFP_KERNEL);
- if (!bss_desc) {
- dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+ bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), GFP_KERNEL);
+ if (!bss_desc)
return -ENOMEM;
- }
ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
if (ret)
@@ -1485,20 +1504,26 @@ static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
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.ht_cap_offset = 0;
priv->curr_bss_params.bss_descriptor.bcn_ht_oper = 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.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.beacon_buf = NULL;
- priv->curr_bss_params.bss_descriptor.beacon_buf_size =
- 0;
+ priv->curr_bss_params.bss_descriptor.beacon_buf_size = 0;
+ priv->curr_bss_params.bss_descriptor.bcn_vht_cap = NULL;
+ priv->curr_bss_params.bss_descriptor.vht_cap_offset = 0;
+ priv->curr_bss_params.bss_descriptor.bcn_vht_oper = NULL;
+ priv->curr_bss_params.bss_descriptor.vht_info_offset = 0;
+ priv->curr_bss_params.bss_descriptor.oper_mode = NULL;
+ priv->curr_bss_params.bss_descriptor.oper_mode_offset = 0;
+
+ /* Disable 11ac by default. Enable it only where there
+ * exist VHT_CAP IE in AP beacon
+ */
+ priv->curr_bss_params.bss_descriptor.disable_11ac = true;
/* Make a copy of current BSSID descriptor */
memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc,
@@ -1563,7 +1588,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
scan_rsp->number_of_sets);
ret = -1;
- goto done;
+ goto check_next_scan;
}
bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
@@ -1634,7 +1659,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
if (!beacon_size || beacon_size > bytes_left) {
bss_info += bytes_left;
bytes_left = 0;
- return -1;
+ ret = -1;
+ goto check_next_scan;
}
/* Initialize the current working beacon pointer for this BSS
@@ -1690,7 +1716,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
dev_err(priv->adapter->dev,
"%s: bytes left < IE length\n",
__func__);
- goto done;
+ goto check_next_scan;
}
if (element_id == WLAN_EID_DS_PARAMS) {
channel = *(current_ptr + sizeof(struct ieee_types_header));
@@ -1746,13 +1772,14 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
.mac_address, ETH_ALEN))
mwifiex_update_curr_bss_params(priv,
bss);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(priv->wdev->wiphy, bss);
}
} else {
dev_dbg(adapter->dev, "missing BSS channel IE\n");
}
}
+check_next_scan:
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);
@@ -1813,7 +1840,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
}
}
-done:
return ret;
}
@@ -1879,10 +1905,8 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
}
scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
- if (!scan_cfg) {
- dev_err(adapter->dev, "failed to alloc scan_cfg\n");
+ if (!scan_cfg)
return -ENOMEM;
- }
scan_cfg->ssid_list = req_ssid;
scan_cfg->num_ssids = 1;
@@ -1996,11 +2020,8 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
kfree(priv->curr_bcn_buf);
priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size,
GFP_ATOMIC);
- if (!priv->curr_bcn_buf) {
- dev_err(priv->adapter->dev,
- "failed to alloc curr_bcn_buf\n");
+ if (!priv->curr_bcn_buf)
return;
- }
}
memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
@@ -2032,6 +2053,14 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
(curr_bss->beacon_buf +
curr_bss->ht_info_offset);
+ if (curr_bss->bcn_vht_cap)
+ curr_bss->bcn_ht_cap = (void *)(curr_bss->beacon_buf +
+ curr_bss->vht_cap_offset);
+
+ if (curr_bss->bcn_vht_oper)
+ curr_bss->bcn_ht_oper = (void *)(curr_bss->beacon_buf +
+ curr_bss->vht_info_offset);
+
if (curr_bss->bcn_bss_co_2040)
curr_bss->bcn_bss_co_2040 =
(curr_bss->beacon_buf + curr_bss->bss_co_2040_offset);
@@ -2039,6 +2068,10 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
if (curr_bss->bcn_ext_cap)
curr_bss->bcn_ext_cap = curr_bss->beacon_buf +
curr_bss->ext_cap_offset;
+
+ if (curr_bss->oper_mode)
+ curr_bss->oper_mode = (void *)(curr_bss->beacon_buf +
+ curr_bss->oper_mode_offset);
}
/*
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 5a1c1d0e5599..e63f646a260e 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -332,7 +332,7 @@ 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;
+ int ret;
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;
@@ -350,8 +350,7 @@ mwifiex_write_data_sync(struct mwifiex_adapter *adapter,
sdio_claim_host(card->func);
- if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size))
- ret = 0;
+ ret = sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size);
sdio_release_host(card->func);
@@ -365,7 +364,7 @@ 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;
+ int ret;
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;
@@ -376,8 +375,7 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer,
if (claim)
sdio_claim_host(card->func);
- if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size))
- ret = 0;
+ ret = sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size);
if (claim)
sdio_release_host(card->func);
@@ -718,11 +716,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
/* 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 FW. Terminating dnld\n");
+ if (!fwbuf)
return -ENOMEM;
- }
/* Perform firmware data transfer */
do {
@@ -1520,7 +1515,6 @@ static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter,
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;
}
@@ -1529,7 +1523,6 @@ static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter,
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;
}
@@ -1682,10 +1675,8 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
/* 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");
+ if (!card->mp_regs)
return -ENOMEM;
- }
ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
@@ -1752,6 +1743,8 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
static struct mmc_host *reset_host;
static void sdio_card_reset_worker(struct work_struct *work)
{
+ struct mmc_host *target = reset_host;
+
/* The actual reset operation must be run outside of driver thread.
* This is because mmc_remove_host() will cause the device to be
* instantly destroyed, and the driver then needs to end its thread,
@@ -1761,10 +1754,10 @@ static void sdio_card_reset_worker(struct work_struct *work)
*/
pr_err("Resetting card...\n");
- mmc_remove_host(reset_host);
+ mmc_remove_host(target);
/* 20ms delay is based on experiment with sdhci controller */
mdelay(20);
- mmc_add_host(reset_host);
+ mmc_add_host(target);
}
static DECLARE_WORK(card_reset_work, sdio_card_reset_worker);
@@ -1773,9 +1766,6 @@ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter)
{
struct sdio_mmc_card *card = adapter->card;
- if (work_pending(&card_reset_work))
- return;
-
reset_host = card->func->card->host;
schedule_work(&card_reset_work);
}
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 5d87195390f8..c55c5bb93134 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -931,7 +931,6 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
struct host_cmd_ds_pcie_details *host_spec =
&cmd->params.pcie_host_spec;
struct pcie_service_card *card = priv->adapter->card;
- phys_addr_t *buf_pa;
cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS);
cmd->size = cpu_to_le16(sizeof(struct
@@ -953,10 +952,11 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv,
host_spec->evtbd_addr_lo = (u32)(card->evtbd_ring_pbase);
host_spec->evtbd_addr_hi = (u32)(((u64)card->evtbd_ring_pbase)>>32);
host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD;
- if (card->sleep_cookie) {
- buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie);
- host_spec->sleep_cookie_addr_lo = (u32) *buf_pa;
- host_spec->sleep_cookie_addr_hi = (u32) (((u64)*buf_pa) >> 32);
+ if (card->sleep_cookie_vbase) {
+ host_spec->sleep_cookie_addr_lo =
+ (u32)(card->sleep_cookie_pbase);
+ host_spec->sleep_cookie_addr_hi =
+ (u32)(((u64)(card->sleep_cookie_pbase)) >> 32);
dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: 0x%x\n",
host_spec->sleep_cookie_addr_lo);
}
@@ -1230,7 +1230,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
data_buf);
break;
case HostCmd_CMD_11N_CFG:
- ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action, data_buf);
+ ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, data_buf);
break;
case HostCmd_CMD_WMM_GET_STATUS:
dev_dbg(priv->adapter->dev,
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 65c12eb3e5e7..4669f8d9389f 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -24,6 +24,7 @@
#include "main.h"
#include "wmm.h"
#include "11n.h"
+#include "11ac.h"
/*
@@ -935,9 +936,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
/ 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);
+ dev_dbg(adapter->dev, "cmd: curr_tx_buf_size=%d\n",
+ adapter->curr_tx_buf_size);
if (adapter->if_ops.update_mp_end_port)
adapter->if_ops.update_mp_end_port(adapter,
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index f542bb8ccbc8..9f33c92c90f5 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -162,13 +162,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
rcu_read_lock();
ies = rcu_dereference(bss->ies);
- if (WARN_ON(!ies)) {
- /* should never happen */
- rcu_read_unlock();
- return -EINVAL;
- }
beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);
beacon_ie_len = ies->len;
+ bss_desc->timestamp = ies->tsf;
rcu_read_unlock();
if (!beacon_ie) {
@@ -184,7 +180,6 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
bss_desc->cap_info_bitmap = bss->capability;
bss_desc->bss_band = bss_priv->band;
bss_desc->fw_tsf = bss_priv->fw_tsf;
- bss_desc->timestamp = bss->tsf;
if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
@@ -266,11 +261,9 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
/* Allocate and fill new bss descriptor */
bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
- GFP_KERNEL);
- if (!bss_desc) {
- dev_err(priv->adapter->dev, " failed to alloc bss_desc\n");
+ GFP_KERNEL);
+ if (!bss_desc)
return -ENOMEM;
- }
ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
if (ret)
@@ -288,9 +281,10 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
if (mwifiex_band_to_radio_type((u8) bss_desc->bss_band)
== HostCmd_SCAN_RADIO_TYPE_BG)
- config_bands = BAND_B | BAND_G | BAND_GN;
+ config_bands = BAND_B | BAND_G | BAND_GN |
+ BAND_GAC;
else
- config_bands = BAND_A | BAND_AN;
+ config_bands = BAND_A | BAND_AN | BAND_AAC;
if (!((config_bands | adapter->fw_bands) &
~adapter->fw_bands))
@@ -324,7 +318,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
}
if (bss)
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(priv->adapter->wiphy, bss);
} else {
/* Adhoc mode */
/* If the requested SSID matches current SSID, return */
@@ -354,7 +348,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
" list. Joining...\n");
ret = mwifiex_adhoc_join(priv, bss_desc);
if (bss)
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(priv->adapter->wiphy, bss);
} else {
dev_dbg(adapter->dev, "info: Network not found in "
"the list, creating adhoc with ssid = %s\n",
@@ -636,11 +630,8 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
}
}
buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
- if (!buf) {
- dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n",
- __func__);
+ if (!buf)
return -ENOMEM;
- }
txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index 8c80024c30ff..296faec14365 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -117,14 +117,16 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
break;
case -1:
- adapter->data_sent = false;
+ if (adapter->iface_type != MWIFIEX_PCIE)
+ 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, 0, ret);
break;
case -EINPROGRESS:
- adapter->data_sent = false;
+ if (adapter->iface_type != MWIFIEX_PCIE)
+ adapter->data_sent = false;
break;
case 0:
mwifiex_write_data_complete(adapter, skb, 0, ret);
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index 8dd72240f162..6e76a15a8950 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -219,6 +219,7 @@ void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
config->rts_threshold = 0x7FFF;
config->frag_threshold = 0x7FFF;
config->retry_limit = 0x7F;
+ config->qos_info = 0xFF;
}
/* This function parses BSS related parameters from structure
@@ -297,6 +298,38 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
return;
}
+/* This function parses WMM related parameters from cfg80211_ap_settings
+ * structure and updates bss_config structure.
+ */
+void
+mwifiex_set_wmm_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params)
+{
+ const u8 *vendor_ie;
+ struct ieee_types_header *wmm_ie;
+ u8 wmm_oui[] = {0x00, 0x50, 0xf2, 0x02};
+
+ vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+ WLAN_OUI_TYPE_MICROSOFT_WMM,
+ params->beacon.tail,
+ params->beacon.tail_len);
+ if (vendor_ie) {
+ wmm_ie = (struct ieee_types_header *)vendor_ie;
+ memcpy(&bss_cfg->wmm_info, wmm_ie + 1,
+ sizeof(bss_cfg->wmm_info));
+ priv->wmm_enabled = 1;
+ } else {
+ memset(&bss_cfg->wmm_info, 0, sizeof(bss_cfg->wmm_info));
+ memcpy(&bss_cfg->wmm_info.oui, wmm_oui, sizeof(wmm_oui));
+ bss_cfg->wmm_info.subtype = MWIFIEX_WMM_SUBTYPE;
+ bss_cfg->wmm_info.version = MWIFIEX_WMM_VERSION;
+ priv->wmm_enabled = 0;
+ }
+
+ bss_cfg->qos_info = 0x00;
+ return;
+}
/* This function parses BSS related parameters from structure
* and prepares TLVs specific to WEP encryption.
* These TLVs are appended to command buffer.
@@ -354,6 +387,7 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
struct host_cmd_tlv_rates *tlv_rates;
struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer;
struct mwifiex_ie_types_htcap *htcap;
+ struct mwifiex_ie_types_wmmcap *wmm_cap;
struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
int i;
u16 cmd_size = *param_size;
@@ -507,6 +541,16 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
tlv += sizeof(struct mwifiex_ie_types_htcap);
}
+ if (bss_cfg->wmm_info.qos_info != 0xFF) {
+ wmm_cap = (struct mwifiex_ie_types_wmmcap *)tlv;
+ wmm_cap->header.type = cpu_to_le16(WLAN_EID_VENDOR_SPECIFIC);
+ wmm_cap->header.len = cpu_to_le16(sizeof(wmm_cap->wmm_info));
+ memcpy(&wmm_cap->wmm_info, &bss_cfg->wmm_info,
+ sizeof(wmm_cap->wmm_info));
+ cmd_size += sizeof(struct mwifiex_ie_types_wmmcap);
+ tlv += sizeof(struct mwifiex_ie_types_wmmcap);
+ }
+
if (bss_cfg->sta_ao_timer) {
ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER);
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index 63ac9f2d11ae..f90fe21e5bfd 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -672,7 +672,7 @@ static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
*len, &actual_length, timeout);
if (ret) {
dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret);
- ret = -1;
+ return ret;
}
*len = actual_length;
@@ -691,7 +691,7 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf,
*len, &actual_length, timeout);
if (ret) {
dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret);
- ret = -1;
+ return ret;
}
*len = actual_length;
@@ -786,21 +786,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
return 0;
}
-/* This function reads one block of firmware data. */
-static int mwifiex_get_fw_data(struct mwifiex_adapter *adapter,
- u32 offset, u32 len, u8 *buf)
-{
- if (!buf || !len)
- return -1;
-
- if (offset + len > adapter->firmware->size)
- return -1;
-
- memcpy(buf, adapter->firmware->data + offset, len);
-
- return 0;
-}
-
static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
struct mwifiex_fw_image *fw)
{
@@ -836,23 +821,14 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
dlen = 0;
} else {
/* copy the header of the fw_data to get the length */
- if (firmware)
- memcpy(&fwdata->fw_hdr, &firmware[tlen],
- sizeof(struct fw_header));
- else
- mwifiex_get_fw_data(adapter, tlen,
- sizeof(struct fw_header),
- (u8 *)&fwdata->fw_hdr);
+ memcpy(&fwdata->fw_hdr, &firmware[tlen],
+ sizeof(struct fw_header));
dlen = le32_to_cpu(fwdata->fw_hdr.data_len);
dnld_cmd = le32_to_cpu(fwdata->fw_hdr.dnld_cmd);
tlen += sizeof(struct fw_header);
- if (firmware)
- memcpy(fwdata->data, &firmware[tlen], dlen);
- else
- mwifiex_get_fw_data(adapter, tlen, dlen,
- (u8 *)fwdata->data);
+ memcpy(fwdata->data, &firmware[tlen], dlen);
fwdata->seq_num = cpu_to_le32(fw_seqnum);
tlen += dlen;
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index 0982375ba3b1..21553976b550 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -91,7 +91,7 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
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->curr_tx_buf_size = (u32) adapter->curr_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);
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h
index f6d36b9654a0..cb2d0582bd36 100644
--- a/drivers/net/wireless/mwifiex/util.h
+++ b/drivers/net/wireless/mwifiex/util.h
@@ -22,16 +22,16 @@
static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
{
- return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t));
+ return (struct mwifiex_rxinfo *)(skb->cb + sizeof(dma_addr_t));
}
static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
{
- return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t));
+ return (struct mwifiex_txinfo *)(skb->cb + sizeof(dma_addr_t));
}
-static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb)
+static inline void MWIFIEX_SKB_PACB(struct sk_buff *skb, dma_addr_t *buf_pa)
{
- return (phys_addr_t *)skb->cb;
+ memcpy(buf_pa, skb->cb, sizeof(dma_addr_t));
}
#endif /* !_MWIFIEX_UTIL_H_ */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 818f871ae987..32adc878041d 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -109,12 +109,9 @@ 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__);
+ if (!ra_list)
return NULL;
- }
+
INIT_LIST_HEAD(&ra_list->list);
skb_queue_head_init(&ra_list->skb_head);
@@ -568,6 +565,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
mwifiex_wmm_delete_all_ralist(priv);
memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
+ if (priv->adapter->if_ops.clean_pcie_ring)
+ priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
}
@@ -1206,13 +1205,15 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
ra_list_flags);
break;
case -1:
- adapter->data_sent = false;
+ if (adapter->iface_type != MWIFIEX_PCIE)
+ 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, 0, ret);
break;
case -EINPROGRESS:
- adapter->data_sent = false;
+ if (adapter->iface_type != MWIFIEX_PCIE)
+ adapter->data_sent = false;
default:
break;
}
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 83564d36e801..091d9a64080a 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -101,6 +101,18 @@ MODULE_PARM_DESC(ap_mode_default,
#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)
+/* txpriorities are mapped with hw queues.
+ * Each hw queue has a txpriority.
+ */
+#define TOTAL_HW_TX_QUEUES 8
+
+/* Each HW queue can have one AMPDU stream.
+ * But, because one of the hw queue is reserved,
+ * maximum AMPDU queues that can be created are
+ * one short of total tx queues.
+ */
+#define MWL8K_NUM_AMPDU_STREAMS (TOTAL_HW_TX_QUEUES - 1)
+
struct rxd_ops {
int rxd_size;
void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
@@ -160,7 +172,6 @@ struct mwl8k_ampdu_stream {
u8 tid;
u8 state;
u8 idx;
- u8 txq_idx; /* index of this stream in priv->txq */
};
struct mwl8k_priv {
@@ -202,6 +213,8 @@ struct mwl8k_priv {
int fw_mutex_depth;
struct completion *hostcmd_wait;
+ atomic_t watchdog_event_pending;
+
/* lock held over TX and TX reap */
spinlock_t tx_lock;
@@ -272,6 +285,9 @@ struct mwl8k_priv {
char *fw_pref;
char *fw_alt;
struct completion firmware_loading_complete;
+
+ /* bitmap of running BSSes */
+ u32 running_bsses;
};
#define MAX_WEP_KEY_LEN 13
@@ -318,20 +334,20 @@ struct mwl8k_sta {
#define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv))
static const struct ieee80211_channel mwl8k_channels_24[] = {
- { .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, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2412, .hw_value = 1, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2417, .hw_value = 2, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2422, .hw_value = 3, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2427, .hw_value = 4, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2432, .hw_value = 5, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2437, .hw_value = 6, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2442, .hw_value = 7, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2447, .hw_value = 8, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2452, .hw_value = 9, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2457, .hw_value = 10, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2462, .hw_value = 11, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2467, .hw_value = 12, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2472, .hw_value = 13, },
+ { .band = IEEE80211_BAND_2GHZ, .center_freq = 2484, .hw_value = 14, },
};
static const struct ieee80211_rate mwl8k_rates_24[] = {
@@ -352,10 +368,10 @@ static const struct ieee80211_rate mwl8k_rates_24[] = {
};
static const struct ieee80211_channel mwl8k_channels_50[] = {
- { .center_freq = 5180, .hw_value = 36, },
- { .center_freq = 5200, .hw_value = 40, },
- { .center_freq = 5220, .hw_value = 44, },
- { .center_freq = 5240, .hw_value = 48, },
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5180, .hw_value = 36, },
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5200, .hw_value = 40, },
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5220, .hw_value = 44, },
+ { .band = IEEE80211_BAND_5GHZ, .center_freq = 5240, .hw_value = 48, },
};
static const struct ieee80211_rate mwl8k_rates_50[] = {
@@ -1133,7 +1149,6 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
rxq->buf = kcalloc(MWL8K_RX_DESCS, sizeof(*rxq->buf), GFP_KERNEL);
if (rxq->buf == NULL) {
- wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n");
pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma);
return -ENOMEM;
}
@@ -1426,7 +1441,6 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index)
txq->skb = kcalloc(MWL8K_TX_DESCS, sizeof(*txq->skb), GFP_KERNEL);
if (txq->skb == NULL) {
- wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n");
pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma);
return -ENOMEM;
}
@@ -1516,6 +1530,9 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
return -EBUSY;
}
+ if (atomic_read(&priv->watchdog_event_pending))
+ return 0;
+
/*
* The TX queues are stopped at this point, so this test
* doesn't need to take ->tx_lock.
@@ -1537,6 +1554,14 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
spin_unlock_bh(&priv->tx_lock);
timeout = wait_for_completion_timeout(&tx_wait,
msecs_to_jiffies(MWL8K_TX_WAIT_TIMEOUT_MS));
+
+ if (atomic_read(&priv->watchdog_event_pending)) {
+ spin_lock_bh(&priv->tx_lock);
+ priv->tx_wait = NULL;
+ spin_unlock_bh(&priv->tx_lock);
+ return 0;
+ }
+
spin_lock_bh(&priv->tx_lock);
if (timeout) {
@@ -1564,6 +1589,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
rc = -ETIMEDOUT;
}
+ priv->tx_wait = NULL;
spin_unlock_bh(&priv->tx_lock);
return rc;
@@ -1734,14 +1760,13 @@ mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid)
struct mwl8k_priv *priv = hw->priv;
int i;
- for (i = 0; i < priv->num_ampdu_queues; i++) {
+ for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; 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;
@@ -1782,7 +1807,7 @@ 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++) {
+ for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
struct mwl8k_ampdu_stream *stream;
stream = &priv->ampdu[i];
if (stream->state == AMPDU_NO_STREAM)
@@ -1829,6 +1854,13 @@ static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid)
tx_stats->pkts++;
}
+/* The hardware ampdu queues start from 5.
+ * txpriorities for ampdu queues are
+ * 5 6 7 0 1 2 3 4 ie., queue 5 is highest
+ * and queue 3 is lowest (queue 4 is reserved)
+ */
+#define BA_QUEUE 5
+
static void
mwl8k_txq_xmit(struct ieee80211_hw *hw,
int index,
@@ -1928,8 +1960,13 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,
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;
+ WARN_ON(!(qos & MWL8K_QOS_ACK_POLICY_BLOCKACK));
+ txpriority = (BA_QUEUE + stream->idx) %
+ TOTAL_HW_TX_QUEUES;
+ if (stream->idx <= 1)
+ index = stream->idx +
+ MWL8K_TX_WMM_QUEUES;
+
} else if (stream->state == AMPDU_STREAM_NEW) {
/* We get here if the driver sends us packets
* after we've initiated a stream, but before
@@ -1971,6 +2008,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,
}
}
spin_unlock(&priv->stream_lock);
+ } else {
+ qos &= ~MWL8K_QOS_ACK_POLICY_MASK;
+ qos |= MWL8K_QOS_ACK_POLICY_NORMAL;
}
dma = pci_map_single(priv->pdev, skb->data,
@@ -2117,6 +2157,8 @@ static void mwl8k_fw_unlock(struct ieee80211_hw *hw)
}
}
+static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable,
+ u32 bitmap);
/*
* Command processing.
@@ -2135,6 +2177,34 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
int rc;
unsigned long timeout = 0;
u8 buf[32];
+ u32 bitmap = 0;
+
+ wiphy_dbg(hw->wiphy, "Posting %s [%d]\n",
+ mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), cmd->macid);
+
+ /* Before posting firmware commands that could change the hardware
+ * characteristics, make sure that all BSSes are stopped temporary.
+ * Enable these stopped BSSes after completion of the commands
+ */
+
+ rc = mwl8k_fw_lock(hw);
+ if (rc)
+ return rc;
+
+ if (priv->ap_fw && priv->running_bsses) {
+ switch (le16_to_cpu(cmd->code)) {
+ case MWL8K_CMD_SET_RF_CHANNEL:
+ case MWL8K_CMD_RADIO_CONTROL:
+ case MWL8K_CMD_RF_TX_POWER:
+ case MWL8K_CMD_TX_POWER:
+ case MWL8K_CMD_RF_ANTENNA:
+ case MWL8K_CMD_RTS_THRESHOLD:
+ case MWL8K_CMD_MIMO_CONFIG:
+ bitmap = priv->running_bsses;
+ mwl8k_enable_bsses(hw, false, bitmap);
+ break;
+ }
+ }
cmd->result = (__force __le16) 0xffff;
dma_size = le16_to_cpu(cmd->length);
@@ -2143,13 +2213,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
if (pci_dma_mapping_error(priv->pdev, dma_addr))
return -ENOMEM;
- rc = mwl8k_fw_lock(hw);
- if (rc) {
- pci_unmap_single(priv->pdev, dma_addr, dma_size,
- PCI_DMA_BIDIRECTIONAL);
- return rc;
- }
-
priv->hostcmd_wait = &cmd_wait;
iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
iowrite32(MWL8K_H2A_INT_DOORBELL,
@@ -2162,7 +2225,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
priv->hostcmd_wait = NULL;
- mwl8k_fw_unlock(hw);
pci_unmap_single(priv->pdev, dma_addr, dma_size,
PCI_DMA_BIDIRECTIONAL);
@@ -2189,6 +2251,11 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
ms);
}
+ if (bitmap)
+ mwl8k_enable_bsses(hw, true, bitmap);
+
+ mwl8k_fw_unlock(hw);
+
return rc;
}
@@ -2450,7 +2517,7 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
priv->hw_rev = cmd->hw_rev;
mwl8k_set_caps(hw, le32_to_cpu(cmd->caps));
priv->ap_macids_supported = 0x000000ff;
- priv->sta_macids_supported = 0x00000000;
+ priv->sta_macids_supported = 0x00000100;
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"
@@ -3469,7 +3536,10 @@ static int mwl8k_cmd_update_mac_addr(struct ieee80211_hw *hw,
mac_type = MWL8K_MAC_TYPE_PRIMARY_AP;
if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) {
if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported))
- mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT;
+ if (priv->ap_fw)
+ mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT;
+ else
+ mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT;
else
mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT;
} else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) {
@@ -3578,7 +3648,11 @@ static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap)
return rc;
}
-#define INVALID_BA 0xAA
+#define MWL8K_WMM_QUEUE_NUMBER 3
+
+static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
+ u8 idx);
+
static void mwl8k_watchdog_ba_events(struct work_struct *work)
{
int rc;
@@ -3586,24 +3660,41 @@ static void mwl8k_watchdog_ba_events(struct work_struct *work)
struct mwl8k_ampdu_stream *streams;
struct mwl8k_priv *priv =
container_of(work, struct mwl8k_priv, watchdog_ba_handle);
+ struct ieee80211_hw *hw = priv->hw;
+ int i;
+ u32 status = 0;
+
+ mwl8k_fw_lock(hw);
rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap);
if (rc)
- return;
+ goto done;
- if (bitmap == INVALID_BA)
- return;
+ spin_lock(&priv->stream_lock);
/* 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);
+ for (i = 0; i < TOTAL_HW_TX_QUEUES; i++) {
+ if (bitmap & (1 << i)) {
+ stream_index = (i + MWL8K_WMM_QUEUE_NUMBER) %
+ TOTAL_HW_TX_QUEUES;
+ streams = &priv->ampdu[stream_index];
+ if (streams->state == AMPDU_STREAM_ACTIVE) {
+ ieee80211_stop_tx_ba_session(streams->sta,
+ streams->tid);
+ spin_unlock(&priv->stream_lock);
+ mwl8k_destroy_ba(hw, stream_index);
+ spin_lock(&priv->stream_lock);
+ }
+ }
+ }
+ spin_unlock(&priv->stream_lock);
+done:
+ atomic_dec(&priv->watchdog_event_pending);
+ status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+ iowrite32((status | MWL8K_A2H_INT_BA_WATCHDOG),
+ priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+ mwl8k_fw_unlock(hw);
return;
}
@@ -3620,8 +3711,16 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int enable)
{
struct mwl8k_cmd_bss_start *cmd;
+ struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+ struct mwl8k_priv *priv = hw->priv;
int rc;
+ if (enable && (priv->running_bsses & (1 << mwl8k_vif->macid)))
+ return 0;
+
+ if (!enable && !(priv->running_bsses & (1 << mwl8k_vif->macid)))
+ return 0;
+
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
@@ -3633,9 +3732,31 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
kfree(cmd);
+ if (!rc) {
+ if (enable)
+ priv->running_bsses |= (1 << mwl8k_vif->macid);
+ else
+ priv->running_bsses &= ~(1 << mwl8k_vif->macid);
+ }
return rc;
}
+static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable, u32 bitmap)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ struct mwl8k_vif *mwl8k_vif, *tmp_vif;
+ struct ieee80211_vif *vif;
+
+ list_for_each_entry_safe(mwl8k_vif, tmp_vif, &priv->vif_list, list) {
+ vif = mwl8k_vif->vif;
+
+ if (!(bitmap & (1 << mwl8k_vif->macid)))
+ continue;
+
+ if (vif->type == NL80211_IFTYPE_AP)
+ mwl8k_cmd_bss_start(hw, vif, enable);
+ }
+}
/*
* CMD_BASTREAM.
*/
@@ -3763,7 +3884,7 @@ mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream,
}
static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
- struct mwl8k_ampdu_stream *stream)
+ u8 idx)
{
struct mwl8k_cmd_bastream *cmd;
@@ -3775,10 +3896,10 @@ static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
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);
+ cmd->destroy_params.ba_context = cpu_to_le32(idx);
mwl8k_post_cmd(hw, &cmd->header);
- wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx);
+ wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", idx);
kfree(cmd);
}
@@ -3875,7 +3996,30 @@ static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u8 *addr)
{
struct mwl8k_cmd_set_new_stn *cmd;
- int rc;
+ struct mwl8k_priv *priv = hw->priv;
+ int rc, i;
+ u8 idx;
+
+ spin_lock(&priv->stream_lock);
+ /* Destroy any active ampdu streams for this sta */
+ for (i = 0; i < MWL8K_NUM_AMPDU_STREAMS; i++) {
+ struct mwl8k_ampdu_stream *s;
+ s = &priv->ampdu[i];
+ if (s->state != AMPDU_NO_STREAM) {
+ if (memcmp(s->sta->addr, addr, ETH_ALEN) == 0) {
+ if (s->state == AMPDU_STREAM_ACTIVE) {
+ idx = s->idx;
+ spin_unlock(&priv->stream_lock);
+ mwl8k_destroy_ba(hw, idx);
+ spin_lock(&priv->stream_lock);
+ } else if (s->state == AMPDU_STREAM_NEW) {
+ mwl8k_remove_stream(hw, s);
+ }
+ }
+ }
+ }
+
+ spin_unlock(&priv->stream_lock);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (cmd == NULL)
@@ -4119,8 +4263,9 @@ static int mwl8k_set_key(struct ieee80211_hw *hw,
u8 encr_type;
u8 *addr;
struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+ struct mwl8k_priv *priv = hw->priv;
- if (vif->type == NL80211_IFTYPE_STATION)
+ if (vif->type == NL80211_IFTYPE_STATION && !priv->ap_fw)
return -EOPNOTSUPP;
if (sta == NULL)
@@ -4303,6 +4448,10 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
}
if (status & MWL8K_A2H_INT_BA_WATCHDOG) {
+ iowrite32(~MWL8K_A2H_INT_BA_WATCHDOG,
+ priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+
+ atomic_inc(&priv->watchdog_event_pending);
status &= ~MWL8K_A2H_INT_BA_WATCHDOG;
ieee80211_queue_work(hw, &priv->watchdog_ba_handle);
}
@@ -4446,6 +4595,8 @@ static int mwl8k_start(struct ieee80211_hw *hw)
priv->irq = -1;
tasklet_disable(&priv->poll_tx_task);
tasklet_disable(&priv->poll_rx_task);
+ } else {
+ ieee80211_wake_queues(hw);
}
return rc;
@@ -4520,12 +4671,18 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
break;
case NL80211_IFTYPE_STATION:
if (priv->ap_fw && di->fw_image_sta) {
- /* we must load the sta fw to meet this request */
- if (!list_empty(&priv->vif_list))
- return -EBUSY;
- rc = mwl8k_reload_firmware(hw, di->fw_image_sta);
- if (rc)
- return rc;
+ if (!list_empty(&priv->vif_list)) {
+ wiphy_warn(hw->wiphy, "AP interface is running.\n"
+ "Adding STA interface for WDS");
+ } else {
+ /* we must load the sta fw to
+ * meet this request.
+ */
+ rc = mwl8k_reload_firmware(hw,
+ di->fw_image_sta);
+ if (rc)
+ return rc;
+ }
}
macids_supported = priv->sta_macids_supported;
break;
@@ -4549,7 +4706,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
/* Set the mac address. */
mwl8k_cmd_set_mac_addr(hw, vif, vif->addr);
- if (priv->ap_fw)
+ if (vif->type == NL80211_IFTYPE_AP)
mwl8k_cmd_set_new_stn_add_self(hw, vif);
priv->macids_used |= 1 << mwl8k_vif->macid;
@@ -4574,7 +4731,7 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw,
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
- if (priv->ap_fw)
+ if (vif->type == NL80211_IFTYPE_AP)
mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr);
mwl8k_cmd_del_mac_addr(hw, vif, vif->addr);
@@ -4648,9 +4805,11 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
if (rc)
goto out;
- rc = mwl8k_cmd_set_rf_channel(hw, conf);
- if (rc)
- goto out;
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ rc = mwl8k_cmd_set_rf_channel(hw, conf);
+ if (rc)
+ goto out;
+ }
if (conf->power_level > 18)
conf->power_level = 18;
@@ -4663,12 +4822,6 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
goto out;
}
- rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3);
- if (rc)
- wiphy_warn(hw->wiphy, "failed to set # of RX antennas");
- rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7);
- if (rc)
- wiphy_warn(hw->wiphy, "failed to set # of TX antennas");
} else {
rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level);
@@ -4726,7 +4879,8 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
rcu_read_unlock();
}
- if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) {
+ if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc &&
+ !priv->ap_fw) {
rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates);
if (rc)
goto out;
@@ -4734,6 +4888,25 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
rc = mwl8k_cmd_use_fixed_rate_sta(hw);
if (rc)
goto out;
+ } else {
+ if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc &&
+ priv->ap_fw) {
+ int idx;
+ int rate;
+
+ /* Use AP firmware specific rate command.
+ */
+ idx = ffs(vif->bss_conf.basic_rates);
+ if (idx)
+ idx--;
+
+ if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+ rate = mwl8k_rates_24[idx].hw_value;
+ else
+ rate = mwl8k_rates_50[idx].hw_value;
+
+ mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate);
+ }
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
@@ -4743,13 +4916,13 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
goto out;
}
- if (changed & BSS_CHANGED_ERP_SLOT) {
+ if ((changed & BSS_CHANGED_ERP_SLOT) && !priv->ap_fw) {
rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot);
if (rc)
goto out;
}
- if (vif->bss_conf.assoc &&
+ if (vif->bss_conf.assoc && !priv->ap_fw &&
(changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT |
BSS_CHANGED_HT))) {
rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates);
@@ -4829,11 +5002,9 @@ static void
mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u32 changed)
{
- struct mwl8k_priv *priv = hw->priv;
-
- if (!priv->ap_fw)
+ if (vif->type == NL80211_IFTYPE_STATION)
mwl8k_bss_info_changed_sta(hw, vif, info, changed);
- else
+ if (vif->type == NL80211_IFTYPE_AP)
mwl8k_bss_info_changed_ap(hw, vif, info, changed);
}
@@ -5094,7 +5265,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int i, rc = 0;
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_ampdu_stream *stream;
- u8 *addr = sta->addr;
+ u8 *addr = sta->addr, idx;
struct mwl8k_sta *sta_info = MWL8K_STA(sta);
if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
@@ -5172,11 +5343,14 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
if (stream) {
if (stream->state == AMPDU_STREAM_ACTIVE) {
+ idx = stream->idx;
spin_unlock(&priv->stream_lock);
- mwl8k_destroy_ba(hw, stream);
+ mwl8k_destroy_ba(hw, idx);
spin_lock(&priv->stream_lock);
}
mwl8k_remove_stream(hw, stream);
@@ -5192,8 +5366,9 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (!rc)
stream->state = AMPDU_STREAM_ACTIVE;
else {
+ idx = stream->idx;
spin_unlock(&priv->stream_lock);
- mwl8k_destroy_ba(hw, stream);
+ mwl8k_destroy_ba(hw, idx);
spin_lock(&priv->stream_lock);
wiphy_debug(hw->wiphy,
"Failed adding stream for sta %pM tid %d\n",
@@ -5256,7 +5431,7 @@ enum {
MWL8366,
};
-#define MWL8K_8366_AP_FW_API 2
+#define MWL8K_8366_AP_FW_API 3
#define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw"
#define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api)
@@ -5296,6 +5471,8 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
{ PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, },
{ PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, },
{ PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, },
+ { PCI_VDEVICE(MARVELL, 0x2a41), .driver_data = MWL8366, },
+ { PCI_VDEVICE(MARVELL, 0x2a42), .driver_data = MWL8366, },
{ PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, },
{ },
};
@@ -5464,6 +5641,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
if (priv->rxd_ops == NULL) {
wiphy_err(hw->wiphy,
"Driver does not have AP firmware image support for this hardware\n");
+ rc = -ENOENT;
goto err_stop_firmware;
}
} else {
@@ -5473,6 +5651,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
priv->sniffer_enabled = false;
priv->wmm_enabled = false;
priv->pending_tx_pkts = 0;
+ atomic_set(&priv->watchdog_event_pending, 0);
rc = mwl8k_rxq_init(hw, 0);
if (rc)
@@ -5552,6 +5731,15 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
goto err_free_irq;
}
+ /* Configure Antennas */
+ rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3);
+ if (rc)
+ wiphy_warn(hw->wiphy, "failed to set # of RX antennas");
+ rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7);
+ if (rc)
+ wiphy_warn(hw->wiphy, "failed to set # of TX antennas");
+
+
/* Disable interrupts */
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
free_irq(priv->pdev->irq, hw);
@@ -5639,6 +5827,7 @@ fail:
static const struct ieee80211_iface_limit ap_if_limits[] = {
{ .max = 8, .types = BIT(NL80211_IFTYPE_AP) },
+ { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) },
};
static const struct ieee80211_iface_combination ap_if_comb = {
@@ -5731,6 +5920,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
if (priv->ap_macids_supported || priv->device_info->fw_image_ap) {
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
+ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
hw->wiphy->iface_combinations = &ap_if_comb;
hw->wiphy->n_iface_combinations = 1;
}
@@ -5809,6 +5999,7 @@ static int mwl8k_probe(struct pci_dev *pdev,
priv->sram = pci_iomap(pdev, 0, 0x10000);
if (priv->sram == NULL) {
wiphy_err(hw->wiphy, "Cannot map device SRAM\n");
+ rc = -EIO;
goto err_iounmap;
}
@@ -5821,6 +6012,7 @@ static int mwl8k_probe(struct pci_dev *pdev,
priv->regs = pci_iomap(pdev, 2, 0x10000);
if (priv->regs == NULL) {
wiphy_err(hw->wiphy, "Cannot map device registers\n");
+ rc = -EIO;
goto err_iounmap;
}
}
@@ -5851,6 +6043,8 @@ static int mwl8k_probe(struct pci_dev *pdev,
priv->hw_restart_in_progress = false;
+ priv->running_bsses = 0;
+
return rc;
err_stop_firmware:
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 88e3ad2d1db8..38ec8d19ac29 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -853,12 +853,8 @@ void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw)
int err;
desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
- if (!desc) {
- printk(KERN_WARNING
- "%s: Can't allocate space for RX descriptor\n",
- dev->name);
+ if (!desc)
goto update_stats;
- }
rxfid = hermes_read_regn(hw, RXFID);
@@ -1336,10 +1332,9 @@ static void qbuf_scan(struct orinoco_private *priv, void *buf,
unsigned long flags;
sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
- if (!sd) {
- printk(KERN_ERR "%s: failed to alloc memory\n", __func__);
+ if (!sd)
return;
- }
+
sd->buf = buf;
sd->len = len;
sd->type = type;
@@ -1357,10 +1352,9 @@ static void qabort_scan(struct orinoco_private *priv)
unsigned long flags;
sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
- if (!sd) {
- printk(KERN_ERR "%s: failed to alloc memory\n", __func__);
+ if (!sd)
return;
- }
+
sd->len = -1; /* Abort */
spin_lock_irqsave(&priv->scan_lock, flags);
@@ -2290,7 +2284,6 @@ int orinoco_if_add(struct orinoco_private *priv,
netif_carrier_off(dev);
memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
- memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
dev->base_addr = base_addr;
dev->irq = irq;
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 01624dcaf73e..7744f42de1ea 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -804,10 +804,15 @@ static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset)
static int ezusb_firmware_download(struct ezusb_priv *upriv,
struct ez_usb_fw *fw)
{
- u8 fw_buffer[FW_BUF_SIZE];
+ u8 *fw_buffer;
int retval, addr;
int variant_offset;
+ fw_buffer = kmalloc(FW_BUF_SIZE, GFP_KERNEL);
+ if (!fw_buffer) {
+ printk(KERN_ERR PFX "Out of memory for firmware buffer.\n");
+ return -ENOMEM;
+ }
/*
* This byte is 1 and should be replaced with 0. The offset is
* 0x10AD in version 0.0.6. The byte in question should follow
@@ -859,6 +864,7 @@ static int ezusb_firmware_download(struct ezusb_priv *upriv,
printk(KERN_ERR PFX "Firmware download failed, error %d\n",
retval);
exit:
+ kfree(fw_buffer);
return retval;
}
@@ -1681,7 +1687,8 @@ static int ezusb_probe(struct usb_interface *interface,
firmware.code = fw_entry->data;
}
if (firmware.size && firmware.code) {
- ezusb_firmware_download(upriv, &firmware);
+ if (ezusb_firmware_download(upriv, &firmware))
+ goto error;
} else {
err("No firmware to download");
goto error;
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index 96e39edfec77..e8c5714bfd11 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -125,7 +125,7 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
capability, beacon_interval, ie_buf, ie_len,
signal, GFP_KERNEL);
- cfg80211_put_bss(cbss);
+ cfg80211_put_bss(wiphy, cbss);
}
void orinoco_add_extscan_result(struct orinoco_private *priv,
@@ -158,7 +158,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
capability, beacon_interval, ie, ie_len,
signal, GFP_KERNEL);
- cfg80211_put_bss(cbss);
+ cfg80211_put_bss(wiphy, cbss);
}
void orinoco_add_hostscan_results(struct orinoco_private *priv,
diff --git a/drivers/net/wireless/p54/Kconfig b/drivers/net/wireless/p54/Kconfig
index 0ec55b50798e..15ea36b51a66 100644
--- a/drivers/net/wireless/p54/Kconfig
+++ b/drivers/net/wireless/p54/Kconfig
@@ -1,6 +1,6 @@
config P54_COMMON
tristate "Softmac Prism54 support"
- depends on MAC80211 && EXPERIMENTAL
+ depends on MAC80211
select FW_LOADER
select CRC_CCITT
---help---
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 933e5d941937..57e3af8ebb4b 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -559,6 +559,7 @@ static int p54p_probe(struct pci_dev *pdev,
mem_len = pci_resource_len(pdev, 0);
if (mem_len < sizeof(struct p54p_csr)) {
dev_err(&pdev->dev, "Too short PCI resources\n");
+ err = -ENODEV;
goto err_disable_dev;
}
@@ -568,8 +569,10 @@ static int p54p_probe(struct pci_dev *pdev,
goto err_disable_dev;
}
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ||
- pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (!err)
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
dev_err(&pdev->dev, "No suitable DMA available\n");
goto err_free_reg;
}
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 800a16526c8e..b9deef66cf4b 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -84,8 +84,8 @@ static struct usb_device_id p54u_table[] = {
{USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
{USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
{USB_DEVICE(0x0803, 0x4310)}, /* Zoom 4410a */
- {USB_DEVICE(0x083a, 0x4503)}, /* T-Com Sinus 154 data II */
{USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
+ {USB_DEVICE(0x083a, 0x4531)}, /* T-Com Sinus 154 data II */
{USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */
{USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
{USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
@@ -510,11 +510,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
return err;
tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
- if (!buf) {
- dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
- "upload buffer!\n");
+ if (!buf)
return -ENOMEM;
- }
left = block_size = min((size_t)P54U_FW_BLOCK, priv->fw->size);
strcpy(buf, p54u_firmware_upload_3887);
@@ -637,11 +634,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
const u8 *data;
buf = kmalloc(512, GFP_KERNEL);
- if (!buf) {
- dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
- "alloc failed!\n");
+ if (!buf)
return -ENOMEM;
- }
#define P54U_WRITE(type, addr, data) \
do {\
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 4e44b1af119a..1c22b81e6ef3 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -1503,6 +1503,7 @@ static int prism54_get_auth(struct net_device *ndev,
case DOT11_AUTH_BOTH:
case DOT11_AUTH_SK:
param->value = IW_AUTH_ALG_SHARED_KEY;
+ break;
case DOT11_AUTH_NONE:
default:
param->value = 0;
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
index c5404cb59e08..9f19cceab487 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.c
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -123,11 +123,8 @@ islpci_mgmt_rx_fill(struct net_device *ndev)
if (buf->mem == NULL) {
buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC);
- if (!buf->mem) {
- printk(KERN_WARNING
- "Error allocating management frame.\n");
+ if (!buf->mem)
return -ENOMEM;
- }
buf->size = MGMT_FRAME_SIZE;
}
if (buf->pci_addr == 0) {
@@ -356,14 +353,11 @@ islpci_mgt_receive(struct net_device *ndev)
/* Determine frame size, skipping OID_INL_TUNNEL headers. */
size = PIMFOR_HEADER_SIZE + header->length;
- frame = kmalloc(sizeof (struct islpci_mgmtframe) + size,
+ frame = kmalloc(sizeof(struct islpci_mgmtframe) + size,
GFP_ATOMIC);
- if (!frame) {
- printk(KERN_WARNING
- "%s: Out of memory, cannot handle oid 0x%08x\n",
- ndev->name, header->oid);
+ if (!frame)
continue;
- }
+
frame->ndev = ndev;
memcpy(&frame->buf, header, size);
frame->header = (pimfor_header_t *) frame->buf;
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 598ca1cafb95..e7cf37f550d1 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -1107,12 +1107,15 @@ static int ray_get_essid(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
ray_dev_t *local = netdev_priv(dev);
+ UCHAR tmp[IW_ESSID_MAX_SIZE + 1];
/* Get the essid that was set */
memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
+ memcpy(tmp, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
+ tmp[IW_ESSID_MAX_SIZE] = '\0';
/* Push it out ! */
- wrqu->essid.length = strlen(extra);
+ wrqu->essid.length = strlen(tmp);
wrqu->essid.flags = 1; /* active */
return 0;
@@ -1842,6 +1845,8 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
UCHAR tmp;
UCHAR cmd;
UCHAR status;
+ UCHAR memtmp[ESSID_SIZE + 1];
+
if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */
return IRQ_NONE;
@@ -1901,17 +1906,21 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
break;
case CCS_START_NETWORK:
case CCS_JOIN_NETWORK:
+ memcpy(memtmp, local->sparm.b4.a_current_ess_id,
+ ESSID_SIZE);
+ memtmp[ESSID_SIZE] = '\0';
+
if (status == CCS_COMMAND_COMPLETE) {
if (readb
(&pccs->var.start_network.net_initiated) ==
1) {
dev_dbg(&link->dev,
"ray_cs interrupt network \"%s\" started\n",
- local->sparm.b4.a_current_ess_id);
+ memtmp);
} else {
dev_dbg(&link->dev,
"ray_cs interrupt network \"%s\" joined\n",
- local->sparm.b4.a_current_ess_id);
+ memtmp);
}
memcpy_fromio(&local->bss_id,
pccs->var.start_network.bssid,
@@ -1939,12 +1948,12 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
if (status == CCS_START_NETWORK) {
dev_dbg(&link->dev,
"ray_cs interrupt network \"%s\" start failed\n",
- local->sparm.b4.a_current_ess_id);
+ memtmp);
local->timer.function = start_net;
} else {
dev_dbg(&link->dev,
"ray_cs interrupt network \"%s\" join failed\n",
- local->sparm.b4.a_current_ess_id);
+ memtmp);
local->timer.function = join_net;
}
add_timer(&local->timer);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index abe1d039be81..525fd7521dff 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -1621,11 +1621,8 @@ static void set_multicast_list(struct usbnet *usbdev)
} else if (mc_count) {
int i = 0;
- mc_addrs = kmalloc(mc_count * ETH_ALEN, GFP_ATOMIC);
+ mc_addrs = kmalloc_array(mc_count, ETH_ALEN, GFP_ATOMIC);
if (!mc_addrs) {
- netdev_warn(usbdev->net,
- "couldn't alloc %d bytes of memory\n",
- mc_count * ETH_ALEN);
netif_addr_unlock_bh(usbdev->net);
return;
}
@@ -2029,7 +2026,7 @@ static bool rndis_bss_info_update(struct usbnet *usbdev,
bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
timestamp, capability, beacon_interval, ie, ie_len, signal,
GFP_KERNEL);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(priv->wdev.wiphy, bss);
return (bss != NULL);
}
@@ -2718,7 +2715,7 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
timestamp, capability, beacon_period, ie_buf, ie_len,
signal, GFP_KERNEL);
- cfg80211_put_bss(bss);
+ cfg80211_put_bss(priv->wdev.wiphy, bss);
}
/*
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index c7548da6573d..44d6ead43341 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -82,7 +82,6 @@ config RT2800PCI_RT33XX
config RT2800PCI_RT35XX
bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)"
- depends on EXPERIMENTAL
default y
---help---
This adds support for rt35xx wireless chipset family to the
@@ -92,7 +91,6 @@ config RT2800PCI_RT35XX
config RT2800PCI_RT53XX
bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)"
- depends on EXPERIMENTAL
default y
---help---
This adds support for rt53xx wireless chipset family to the
@@ -101,7 +99,6 @@ config RT2800PCI_RT53XX
config RT2800PCI_RT3290
bool "rt2800pci - Include support for rt3290 devices (EXPERIMENTAL)"
- depends on EXPERIMENTAL
default y
---help---
This adds support for rt3290 wireless chipset family to the
@@ -159,7 +156,6 @@ config RT2800USB_RT33XX
config RT2800USB_RT35XX
bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)"
- depends on EXPERIMENTAL
default y
---help---
This adds support for rt35xx wireless chipset family to the
@@ -168,7 +164,6 @@ config RT2800USB_RT35XX
config RT2800USB_RT53XX
bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)"
- depends on EXPERIMENTAL
---help---
This adds support for rt53xx wireless chipset family to the
rt2800usb driver.
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index a2d2bc2c7b3d..221beaaa83f1 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1185,8 +1185,14 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
- rt2x00queue_map_txskb(entry);
-
+ if (rt2x00queue_map_txskb(entry)) {
+ ERROR(rt2x00dev, "Fail to map beacon, aborting\n");
+ goto out;
+ }
+ /*
+ * Enable beaconing again.
+ */
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
/*
* Write the TX descriptor for the beacon.
*/
@@ -1196,7 +1202,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
* Dump beacon to userspace through debugfs.
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
-
+out:
/*
* Enable beaconing again.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 9bea10f53f0a..39edc59e8d03 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1338,7 +1338,10 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
- rt2x00queue_map_txskb(entry);
+ if (rt2x00queue_map_txskb(entry)) {
+ ERROR(rt2x00dev, "Fail to map beacon, aborting\n");
+ goto out;
+ }
/*
* Write the TX descriptor for the beacon.
@@ -1349,7 +1352,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
* Dump beacon to userspace through debugfs.
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
-
+out:
/*
* Enable beaconing again.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 197b4466a5d2..a658b4bc7da2 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -80,7 +80,7 @@ static inline bool rt2800_is_305x_soc(struct rt2x00_dev *rt2x00dev)
rt2x00_rf(rt2x00dev, RF3022))
return true;
- NOTICE(rt2x00dev, "Unknown RF chipset on rt305x\n");
+ WARNING(rt2x00dev, "Unknown RF chipset on rt305x\n");
return false;
}
@@ -1296,8 +1296,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_CONTROL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
!(filter_flags & FIF_PSPOLL));
- rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA,
- !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 0);
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR,
!(filter_flags & FIF_CONTROL));
rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
@@ -3866,6 +3865,400 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
return rfcsr24;
}
+static void rt2800_init_rfcsr_305x_soc(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
+ rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
+ rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
+ rt2800_rfcsr_write(rt2x00dev, 3, 0x75);
+ rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+ rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
+ rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
+ rt2800_rfcsr_write(rt2x00dev, 7, 0x50);
+ rt2800_rfcsr_write(rt2x00dev, 8, 0x39);
+ rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
+ rt2800_rfcsr_write(rt2x00dev, 10, 0x60);
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x75);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x75);
+ rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+ rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
+ rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
+ rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
+ rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
+ rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
+ rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
+ rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 23, 0x31);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
+ rt2800_rfcsr_write(rt2x00dev, 26, 0x25);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x23);
+ rt2800_rfcsr_write(rt2x00dev, 28, 0x13);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0x83);
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
+}
+
+static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+ rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
+ rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
+ rt2800_rfcsr_write(rt2x00dev, 7, 0x60);
+ rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
+ rt2800_rfcsr_write(rt2x00dev, 10, 0x41);
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x7b);
+ rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+ rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
+ rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
+ rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
+ rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
+ rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
+ rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
+ rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
+}
+
+static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
+ rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
+ rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
+ rt2800_rfcsr_write(rt2x00dev, 8, 0xf3);
+ rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
+ rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+ rt2800_rfcsr_write(rt2x00dev, 18, 0x02);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x83);
+ rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 34, 0x05);
+ rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+ rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+ rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
+ rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+ rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0x7b);
+ rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+ rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+ rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+ rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 49, 0x98);
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
+ rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+ rt2800_rfcsr_write(rt2x00dev, 56, 0x02);
+ rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
+ rt2800_rfcsr_write(rt2x00dev, 59, 0x09);
+ rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+ rt2800_rfcsr_write(rt2x00dev, 61, 0xc1);
+}
+
+static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
+ rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
+ rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
+ rt2800_rfcsr_write(rt2x00dev, 3, 0x18);
+ rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 6, 0x33);
+ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 8, 0xf1);
+ rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
+ rt2800_rfcsr_write(rt2x00dev, 10, 0xd2);
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 14, 0x5a);
+ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 16, 0x01);
+ rt2800_rfcsr_write(rt2x00dev, 18, 0x45);
+ rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
+ rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
+ rt2800_rfcsr_write(rt2x00dev, 28, 0x03);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
+ rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
+ rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
+ rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
+ rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
+ rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
+ rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
+ rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
+ rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
+ rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
+ rt2800_rfcsr_write(rt2x00dev, 46, 0xdd);
+ rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
+ rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
+ rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
+ rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
+ rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
+ rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
+ rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
+ rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+}
+
+static void rt2800_init_rfcsr_3390(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
+ rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
+ rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
+ rt2800_rfcsr_write(rt2x00dev, 3, 0x62);
+ rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+ rt2800_rfcsr_write(rt2x00dev, 5, 0x8b);
+ rt2800_rfcsr_write(rt2x00dev, 6, 0x42);
+ rt2800_rfcsr_write(rt2x00dev, 7, 0x34);
+ rt2800_rfcsr_write(rt2x00dev, 8, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
+ rt2800_rfcsr_write(rt2x00dev, 10, 0x61);
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x3b);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0xe0);
+ rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+ rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
+ rt2800_rfcsr_write(rt2x00dev, 16, 0xe0);
+ rt2800_rfcsr_write(rt2x00dev, 17, 0x94);
+ rt2800_rfcsr_write(rt2x00dev, 18, 0x5c);
+ rt2800_rfcsr_write(rt2x00dev, 19, 0x4a);
+ rt2800_rfcsr_write(rt2x00dev, 20, 0xb2);
+ rt2800_rfcsr_write(rt2x00dev, 21, 0xf6);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 23, 0x14);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
+ rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 28, 0x41);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
+}
+
+static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_rfcsr_write(rt2x00dev, 0, 0x70);
+ rt2800_rfcsr_write(rt2x00dev, 1, 0x81);
+ rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
+ rt2800_rfcsr_write(rt2x00dev, 3, 0x02);
+ rt2800_rfcsr_write(rt2x00dev, 4, 0x4c);
+ rt2800_rfcsr_write(rt2x00dev, 5, 0x05);
+ rt2800_rfcsr_write(rt2x00dev, 6, 0x4a);
+ rt2800_rfcsr_write(rt2x00dev, 7, 0xd8);
+ rt2800_rfcsr_write(rt2x00dev, 9, 0xc3);
+ rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
+ rt2800_rfcsr_write(rt2x00dev, 11, 0xb9);
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x70);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x65);
+ rt2800_rfcsr_write(rt2x00dev, 14, 0xa0);
+ rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
+ rt2800_rfcsr_write(rt2x00dev, 16, 0x4c);
+ rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
+ rt2800_rfcsr_write(rt2x00dev, 18, 0xac);
+ rt2800_rfcsr_write(rt2x00dev, 19, 0x93);
+ rt2800_rfcsr_write(rt2x00dev, 20, 0xb3);
+ rt2800_rfcsr_write(rt2x00dev, 21, 0xd0);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 23, 0x3c);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x15);
+ rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x09);
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x10);
+}
+
+static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
+ rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
+ rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+ rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
+ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+ rt2800_rfcsr_write(rt2x00dev, 12, 0xc6);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+ rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
+ rt2800_rfcsr_write(rt2x00dev, 19, 0x00);
+
+ rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+ rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 25, 0xc0);
+ rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+ rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
+ rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+ rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
+ rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+ rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 40, 0x4b);
+ rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+ rt2800_rfcsr_write(rt2x00dev, 42, 0xd2);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0x9a);
+ rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+ rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+ rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 46, 0x7b);
+ rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
+
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+ rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 53, 0x84);
+ rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x44);
+ rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
+ rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
+ rt2800_rfcsr_write(rt2x00dev, 59, 0x63);
+
+ rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
+ rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
+ rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+}
+
+static void rt2800_init_rfcsr_5392(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
+ rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
+ rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
+ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+ rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
+ rt2800_rfcsr_write(rt2x00dev, 19, 0x4d);
+ rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 21, 0x8d);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+ rt2800_rfcsr_write(rt2x00dev, 23, 0x0b);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x44);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+ rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 32, 0x20);
+ rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
+ rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
+ rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+ rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
+ rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+ rt2800_rfcsr_write(rt2x00dev, 40, 0x0f);
+ rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+ rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0x9b);
+ rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+ rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+ rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+ rt2800_rfcsr_write(rt2x00dev, 47, 0x0c);
+ rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
+ rt2800_rfcsr_write(rt2x00dev, 50, 0x94);
+ rt2800_rfcsr_write(rt2x00dev, 51, 0x3a);
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
+ rt2800_rfcsr_write(rt2x00dev, 53, 0x44);
+ rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+ rt2800_rfcsr_write(rt2x00dev, 56, 0xa1);
+ rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
+ rt2800_rfcsr_write(rt2x00dev, 59, 0x07);
+ rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+ rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
+ rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
+ rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
+}
+
static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
{
struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
@@ -3889,6 +4282,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
/*
* Init RF calibration.
*/
+
if (rt2x00_rt(rt2x00dev, RT3290) ||
rt2x00_rt(rt2x00dev, RT5390) ||
rt2x00_rt(rt2x00dev, RT5392)) {
@@ -3907,379 +4301,35 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
}
- if (rt2x00_rt(rt2x00dev, RT3070) ||
- rt2x00_rt(rt2x00dev, RT3071) ||
- rt2x00_rt(rt2x00dev, RT3090)) {
- rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
- rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
- rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
- rt2800_rfcsr_write(rt2x00dev, 7, 0x60);
- rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
- rt2800_rfcsr_write(rt2x00dev, 10, 0x41);
- rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
- rt2800_rfcsr_write(rt2x00dev, 12, 0x7b);
- rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
- rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
- rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
- rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
- rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
- rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
- rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
- rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
- rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
- rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
- rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
- } else if (rt2x00_rt(rt2x00dev, RT3290)) {
- rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
- rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
- rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
- rt2800_rfcsr_write(rt2x00dev, 8, 0xf3);
- rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
- rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
- rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
- rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
- rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
- rt2800_rfcsr_write(rt2x00dev, 18, 0x02);
- rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
- rt2800_rfcsr_write(rt2x00dev, 25, 0x83);
- rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
- rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
- rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
- rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
- rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 34, 0x05);
- rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
- rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
- rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
- rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
- rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
- rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
- rt2800_rfcsr_write(rt2x00dev, 43, 0x7b);
- rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
- rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
- rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
- rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
- rt2800_rfcsr_write(rt2x00dev, 49, 0x98);
- rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
- rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
- rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
- rt2800_rfcsr_write(rt2x00dev, 56, 0x02);
- rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
- rt2800_rfcsr_write(rt2x00dev, 59, 0x09);
- rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
- rt2800_rfcsr_write(rt2x00dev, 61, 0xc1);
- } else if (rt2x00_rt(rt2x00dev, RT3390)) {
- rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
- rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
- rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
- rt2800_rfcsr_write(rt2x00dev, 3, 0x62);
- rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
- rt2800_rfcsr_write(rt2x00dev, 5, 0x8b);
- rt2800_rfcsr_write(rt2x00dev, 6, 0x42);
- rt2800_rfcsr_write(rt2x00dev, 7, 0x34);
- rt2800_rfcsr_write(rt2x00dev, 8, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
- rt2800_rfcsr_write(rt2x00dev, 10, 0x61);
- rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
- rt2800_rfcsr_write(rt2x00dev, 12, 0x3b);
- rt2800_rfcsr_write(rt2x00dev, 13, 0xe0);
- rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
- rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
- rt2800_rfcsr_write(rt2x00dev, 16, 0xe0);
- rt2800_rfcsr_write(rt2x00dev, 17, 0x94);
- rt2800_rfcsr_write(rt2x00dev, 18, 0x5c);
- rt2800_rfcsr_write(rt2x00dev, 19, 0x4a);
- rt2800_rfcsr_write(rt2x00dev, 20, 0xb2);
- rt2800_rfcsr_write(rt2x00dev, 21, 0xf6);
- rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 23, 0x14);
- rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
- rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
- rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
- rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 28, 0x41);
- rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
- rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
- rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
- } else if (rt2x00_rt(rt2x00dev, RT3572)) {
- rt2800_rfcsr_write(rt2x00dev, 0, 0x70);
- rt2800_rfcsr_write(rt2x00dev, 1, 0x81);
- rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
- rt2800_rfcsr_write(rt2x00dev, 3, 0x02);
- rt2800_rfcsr_write(rt2x00dev, 4, 0x4c);
- rt2800_rfcsr_write(rt2x00dev, 5, 0x05);
- rt2800_rfcsr_write(rt2x00dev, 6, 0x4a);
- rt2800_rfcsr_write(rt2x00dev, 7, 0xd8);
- rt2800_rfcsr_write(rt2x00dev, 9, 0xc3);
- rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
- rt2800_rfcsr_write(rt2x00dev, 11, 0xb9);
- rt2800_rfcsr_write(rt2x00dev, 12, 0x70);
- rt2800_rfcsr_write(rt2x00dev, 13, 0x65);
- rt2800_rfcsr_write(rt2x00dev, 14, 0xa0);
- rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
- rt2800_rfcsr_write(rt2x00dev, 16, 0x4c);
- rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
- rt2800_rfcsr_write(rt2x00dev, 18, 0xac);
- rt2800_rfcsr_write(rt2x00dev, 19, 0x93);
- rt2800_rfcsr_write(rt2x00dev, 20, 0xb3);
- rt2800_rfcsr_write(rt2x00dev, 21, 0xd0);
- rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 23, 0x3c);
- rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
- rt2800_rfcsr_write(rt2x00dev, 25, 0x15);
- rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
- rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
- rt2800_rfcsr_write(rt2x00dev, 30, 0x09);
- rt2800_rfcsr_write(rt2x00dev, 31, 0x10);
- } else if (rt2800_is_305x_soc(rt2x00dev)) {
- rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
- rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
- rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
- rt2800_rfcsr_write(rt2x00dev, 3, 0x75);
- rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
- rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
- rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
- rt2800_rfcsr_write(rt2x00dev, 7, 0x50);
- rt2800_rfcsr_write(rt2x00dev, 8, 0x39);
- rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
- rt2800_rfcsr_write(rt2x00dev, 10, 0x60);
- rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
- rt2800_rfcsr_write(rt2x00dev, 12, 0x75);
- rt2800_rfcsr_write(rt2x00dev, 13, 0x75);
- rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
- rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
- rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
- rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
- rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
- rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
- rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
- rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
- rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 23, 0x31);
- rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
- rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
- rt2800_rfcsr_write(rt2x00dev, 26, 0x25);
- rt2800_rfcsr_write(rt2x00dev, 27, 0x23);
- rt2800_rfcsr_write(rt2x00dev, 28, 0x13);
- rt2800_rfcsr_write(rt2x00dev, 29, 0x83);
- rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
+ if (rt2800_is_305x_soc(rt2x00dev)) {
+ rt2800_init_rfcsr_305x_soc(rt2x00dev);
return 0;
- } else if (rt2x00_rt(rt2x00dev, RT3352)) {
- rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
- rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
- rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
- rt2800_rfcsr_write(rt2x00dev, 3, 0x18);
- rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 6, 0x33);
- rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 8, 0xf1);
- rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
- rt2800_rfcsr_write(rt2x00dev, 10, 0xd2);
- rt2800_rfcsr_write(rt2x00dev, 11, 0x42);
- rt2800_rfcsr_write(rt2x00dev, 12, 0x1c);
- rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 14, 0x5a);
- rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 16, 0x01);
- rt2800_rfcsr_write(rt2x00dev, 18, 0x45);
- rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
- rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
- rt2800_rfcsr_write(rt2x00dev, 28, 0x03);
- rt2800_rfcsr_write(rt2x00dev, 29, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
- rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 34, 0x01);
- rt2800_rfcsr_write(rt2x00dev, 35, 0x03);
- rt2800_rfcsr_write(rt2x00dev, 36, 0xbd);
- rt2800_rfcsr_write(rt2x00dev, 37, 0x3c);
- rt2800_rfcsr_write(rt2x00dev, 38, 0x5f);
- rt2800_rfcsr_write(rt2x00dev, 39, 0xc5);
- rt2800_rfcsr_write(rt2x00dev, 40, 0x33);
- rt2800_rfcsr_write(rt2x00dev, 41, 0x5b);
- rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
- rt2800_rfcsr_write(rt2x00dev, 43, 0xdb);
- rt2800_rfcsr_write(rt2x00dev, 44, 0xdb);
- rt2800_rfcsr_write(rt2x00dev, 45, 0xdb);
- rt2800_rfcsr_write(rt2x00dev, 46, 0xdd);
- rt2800_rfcsr_write(rt2x00dev, 47, 0x0d);
- rt2800_rfcsr_write(rt2x00dev, 48, 0x14);
- rt2800_rfcsr_write(rt2x00dev, 49, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 50, 0x2d);
- rt2800_rfcsr_write(rt2x00dev, 51, 0x7f);
- rt2800_rfcsr_write(rt2x00dev, 52, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 53, 0x52);
- rt2800_rfcsr_write(rt2x00dev, 54, 0x1b);
- rt2800_rfcsr_write(rt2x00dev, 55, 0x7f);
- rt2800_rfcsr_write(rt2x00dev, 56, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 57, 0x52);
- rt2800_rfcsr_write(rt2x00dev, 58, 0x1b);
- rt2800_rfcsr_write(rt2x00dev, 59, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 60, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
- } else if (rt2x00_rt(rt2x00dev, RT5390)) {
- rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
- rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
- rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
- if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
- rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
- else
- rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
- rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
- rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
- rt2800_rfcsr_write(rt2x00dev, 12, 0xc6);
- rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
- rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
- rt2800_rfcsr_write(rt2x00dev, 19, 0x00);
-
- rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 21, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
- rt2800_rfcsr_write(rt2x00dev, 23, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
- if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
- rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
- else
- rt2800_rfcsr_write(rt2x00dev, 25, 0xc0);
- rt2800_rfcsr_write(rt2x00dev, 26, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
- rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
-
- rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
- rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
- rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
- rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
- rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
-
- if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
- rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
- else
- rt2800_rfcsr_write(rt2x00dev, 40, 0x4b);
- rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
- rt2800_rfcsr_write(rt2x00dev, 42, 0xd2);
- rt2800_rfcsr_write(rt2x00dev, 43, 0x9a);
- rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
- rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
- if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
- rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
- else
- rt2800_rfcsr_write(rt2x00dev, 46, 0x7b);
- rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
- rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
-
- rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
- if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
- rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
- else
- rt2800_rfcsr_write(rt2x00dev, 53, 0x84);
- rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
- rt2800_rfcsr_write(rt2x00dev, 55, 0x44);
- rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
- rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
- rt2800_rfcsr_write(rt2x00dev, 59, 0x63);
-
- rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
- if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
- rt2800_rfcsr_write(rt2x00dev, 61, 0xd1);
- else
- rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
- rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
- } else if (rt2x00_rt(rt2x00dev, RT5392)) {
- rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
- rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
- rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
- rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
- rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
- rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
- rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
- rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
- rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
- rt2800_rfcsr_write(rt2x00dev, 19, 0x4d);
- rt2800_rfcsr_write(rt2x00dev, 20, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 21, 0x8d);
- rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
- rt2800_rfcsr_write(rt2x00dev, 23, 0x0b);
- rt2800_rfcsr_write(rt2x00dev, 24, 0x44);
- rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
- rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
- rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
- rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
- rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 32, 0x20);
- rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
- rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
- rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
- rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
- rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
- rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
- rt2800_rfcsr_write(rt2x00dev, 40, 0x0f);
- rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
- rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
- rt2800_rfcsr_write(rt2x00dev, 43, 0x9b);
- rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
- rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
- rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
- rt2800_rfcsr_write(rt2x00dev, 47, 0x0c);
- rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
- rt2800_rfcsr_write(rt2x00dev, 49, 0x94);
- rt2800_rfcsr_write(rt2x00dev, 50, 0x94);
- rt2800_rfcsr_write(rt2x00dev, 51, 0x3a);
- rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
- rt2800_rfcsr_write(rt2x00dev, 53, 0x44);
- rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
- rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
- rt2800_rfcsr_write(rt2x00dev, 56, 0xa1);
- rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
- rt2800_rfcsr_write(rt2x00dev, 59, 0x07);
- rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
- rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
- rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
- rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
+ }
+
+ switch (rt2x00dev->chip.rt) {
+ case RT3070:
+ case RT3071:
+ case RT3090:
+ rt2800_init_rfcsr_30xx(rt2x00dev);
+ break;
+ case RT3290:
+ rt2800_init_rfcsr_3290(rt2x00dev);
+ break;
+ case RT3352:
+ rt2800_init_rfcsr_3352(rt2x00dev);
+ break;
+ case RT3390:
+ rt2800_init_rfcsr_3390(rt2x00dev);
+ break;
+ case RT3572:
+ rt2800_init_rfcsr_3572(rt2x00dev);
+ break;
+ case RT5390:
+ rt2800_init_rfcsr_5390(rt2x00dev);
+ break;
+ case RT5392:
+ rt2800_init_rfcsr_5392(rt2x00dev);
+ break;
}
if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
@@ -4620,12 +4670,14 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
mutex_unlock(&rt2x00dev->csr_mutex);
}
-void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
{
unsigned int i;
for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8)
rt2800_efuse_read(rt2x00dev, i);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse);
@@ -4635,11 +4687,14 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
u16 word;
u8 *mac;
u8 default_lna_gain;
+ int retval;
/*
* Read the EEPROM.
*/
- rt2800_read_eeprom(rt2x00dev);
+ retval = rt2800_read_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
/*
* Start validation of the data that has been read.
@@ -5090,8 +5145,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL;
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS;
/*
* Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
@@ -5484,7 +5538,9 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_START:
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index a128ceadcb3e..6ec739466db4 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -43,7 +43,7 @@ struct rt2800_ops {
const unsigned int offset,
const struct rt2x00_field32 field, u32 *reg);
- void (*read_eeprom)(struct rt2x00_dev *rt2x00dev);
+ int (*read_eeprom)(struct rt2x00_dev *rt2x00dev);
bool (*hwcrypt_disabled)(struct rt2x00_dev *rt2x00dev);
int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
@@ -117,11 +117,11 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev,
return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg);
}
-static inline void rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
- rt2800ops->read_eeprom(rt2x00dev);
+ return rt2800ops->read_eeprom(rt2x00dev);
}
static inline bool rt2800_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev)
@@ -207,7 +207,7 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
-void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
+int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 9224d874bf24..48a01aa21f1c 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -90,17 +90,22 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
}
#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
-static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+static int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
{
void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE);
+ if (!base_addr)
+ return -ENOMEM;
+
memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
iounmap(base_addr);
+ return 0;
}
#else
-static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
{
+ return -ENOMEM;
}
#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */
@@ -135,7 +140,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
}
-static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
+static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
{
struct eeprom_93cx6 eeprom;
u32 reg;
@@ -164,6 +169,8 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
EEPROM_SIZE / sizeof(u16));
+
+ return 0;
}
static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
@@ -171,13 +178,14 @@ static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
return rt2800_efuse_detect(rt2x00dev);
}
-static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
{
- rt2800_read_eeprom_efuse(rt2x00dev);
+ return rt2800_read_eeprom_efuse(rt2x00dev);
}
#else
-static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
{
+ return -EOPNOTSUPP;
}
static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
@@ -185,8 +193,9 @@ static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
return 0;
}
-static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+static inline int rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
{
+ return -EOPNOTSUPP;
}
#endif /* CONFIG_PCI */
@@ -970,14 +979,18 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
/*
* Device probe functions.
*/
-static void rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev)
+static int rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev)
{
+ int retval;
+
if (rt2x00_is_soc(rt2x00dev))
- rt2800pci_read_eeprom_soc(rt2x00dev);
+ retval = rt2800pci_read_eeprom_soc(rt2x00dev);
else if (rt2800pci_efuse_detect(rt2x00dev))
- rt2800pci_read_eeprom_efuse(rt2x00dev);
+ retval = rt2800pci_read_eeprom_efuse(rt2x00dev);
else
- rt2800pci_read_eeprom_pci(rt2x00dev);
+ retval = rt2800pci_read_eeprom_pci(rt2x00dev);
+
+ return retval;
}
static const struct ieee80211_ops rt2800pci_mac80211_ops = {
@@ -1139,6 +1152,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
{ PCI_DEVICE(0x1814, 0x3562) },
{ PCI_DEVICE(0x1814, 0x3592) },
{ PCI_DEVICE(0x1814, 0x3593) },
+ { PCI_DEVICE(0x1814, 0x359f) },
#endif
#ifdef CONFIG_RT2800PCI_RT53XX
{ PCI_DEVICE(0x1814, 0x5360) },
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 5c149b58ab46..098613ed93fb 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -540,9 +540,9 @@ rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg)
tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) {
- WARNING(entry->queue->rt2x00dev,
- "TX status report missed for queue %d entry %d\n",
- entry->queue->qid, entry->entry_idx);
+ DEBUG(entry->queue->rt2x00dev,
+ "TX status report missed for queue %d entry %d\n",
+ entry->queue->qid, entry->entry_idx);
return TXDONE_UNKNOWN;
}
@@ -735,13 +735,17 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
/*
* Device probe functions.
*/
-static void rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
+static int rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
{
+ int retval;
+
if (rt2800_efuse_detect(rt2x00dev))
- rt2800_read_eeprom_efuse(rt2x00dev);
+ retval = rt2800_read_eeprom_efuse(rt2x00dev);
else
- rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
- EEPROM_SIZE);
+ retval = rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
+ EEPROM_SIZE);
+
+ return retval;
}
static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -964,6 +968,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x07d1, 0x3c13) },
{ USB_DEVICE(0x07d1, 0x3c15) },
{ USB_DEVICE(0x07d1, 0x3c16) },
+ { USB_DEVICE(0x07d1, 0x3c17) },
{ USB_DEVICE(0x2001, 0x3c1b) },
/* Draytek */
{ USB_DEVICE(0x07fa, 0x7712) },
@@ -1094,9 +1099,11 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x15a9, 0x0006) },
/* Sweex */
{ USB_DEVICE(0x177f, 0x0153) },
+ { USB_DEVICE(0x177f, 0x0164) },
{ USB_DEVICE(0x177f, 0x0302) },
{ USB_DEVICE(0x177f, 0x0313) },
{ USB_DEVICE(0x177f, 0x0323) },
+ { USB_DEVICE(0x177f, 0x0324) },
/* U-Media */
{ USB_DEVICE(0x157e, 0x300e) },
{ USB_DEVICE(0x157e, 0x3013) },
@@ -1111,6 +1118,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
/* Zyxel */
{ USB_DEVICE(0x0586, 0x3416) },
{ USB_DEVICE(0x0586, 0x3418) },
+ { USB_DEVICE(0x0586, 0x341a) },
{ USB_DEVICE(0x0586, 0x341e) },
{ USB_DEVICE(0x0586, 0x343e) },
#ifdef CONFIG_RT2800USB_RT33XX
@@ -1127,6 +1135,9 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x148f, 0x8070) },
/* Sitecom */
{ USB_DEVICE(0x0df6, 0x0050) },
+ /* Sweex */
+ { USB_DEVICE(0x177f, 0x0163) },
+ { USB_DEVICE(0x177f, 0x0165) },
#endif
#ifdef CONFIG_RT2800USB_RT35XX
/* Allwin */
@@ -1162,6 +1173,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
#ifdef CONFIG_RT2800USB_RT53XX
/* Arcadyan */
{ USB_DEVICE(0x043e, 0x7a12) },
+ { USB_DEVICE(0x043e, 0x7a32) },
/* Azurewave */
{ USB_DEVICE(0x13d3, 0x3329) },
{ USB_DEVICE(0x13d3, 0x3365) },
@@ -1173,16 +1185,20 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x2001, 0x3c1e) },
/* LG innotek */
{ USB_DEVICE(0x043e, 0x7a22) },
+ { USB_DEVICE(0x043e, 0x7a42) },
/* Panasonic */
{ USB_DEVICE(0x04da, 0x1801) },
{ USB_DEVICE(0x04da, 0x1800) },
+ { USB_DEVICE(0x04da, 0x23f6) },
/* Philips */
{ USB_DEVICE(0x0471, 0x2104) },
+ { USB_DEVICE(0x0471, 0x2126) },
+ { USB_DEVICE(0x0471, 0x2180) },
+ { USB_DEVICE(0x0471, 0x2181) },
+ { USB_DEVICE(0x0471, 0x2182) },
/* Ralink */
{ USB_DEVICE(0x148f, 0x5370) },
{ USB_DEVICE(0x148f, 0x5372) },
- /* Unknown */
- { USB_DEVICE(0x04da, 0x23f6) },
#endif
#ifdef CONFIG_RT2800USB_UNKNOWN
/*
@@ -1203,10 +1219,15 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x0b05, 0x1760) },
{ USB_DEVICE(0x0b05, 0x1761) },
{ USB_DEVICE(0x0b05, 0x1790) },
+ { USB_DEVICE(0x0b05, 0x17a7) },
/* AzureWave */
{ USB_DEVICE(0x13d3, 0x3262) },
{ USB_DEVICE(0x13d3, 0x3284) },
{ USB_DEVICE(0x13d3, 0x3322) },
+ { USB_DEVICE(0x13d3, 0x3340) },
+ { USB_DEVICE(0x13d3, 0x3399) },
+ { USB_DEVICE(0x13d3, 0x3400) },
+ { USB_DEVICE(0x13d3, 0x3401) },
/* Belkin */
{ USB_DEVICE(0x050d, 0x1003) },
/* Buffalo */
@@ -1219,13 +1240,17 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x18c5, 0x0008) },
/* D-Link */
{ USB_DEVICE(0x07d1, 0x3c0b) },
- { USB_DEVICE(0x07d1, 0x3c17) },
/* Encore */
{ USB_DEVICE(0x203d, 0x14a1) },
+ /* EnGenius */
+ { USB_DEVICE(0x1740, 0x0600) },
+ { USB_DEVICE(0x1740, 0x0602) },
/* Gemtek */
{ USB_DEVICE(0x15a9, 0x0010) },
/* Gigabyte */
{ USB_DEVICE(0x1044, 0x800c) },
+ /* Hercules */
+ { USB_DEVICE(0x06f8, 0xe036) },
/* Huawei */
{ USB_DEVICE(0x148f, 0xf101) },
/* I-O DATA */
@@ -1252,13 +1277,17 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x0df6, 0x004a) },
{ USB_DEVICE(0x0df6, 0x004d) },
{ USB_DEVICE(0x0df6, 0x0053) },
+ { USB_DEVICE(0x0df6, 0x0069) },
+ { USB_DEVICE(0x0df6, 0x006f) },
/* SMC */
{ USB_DEVICE(0x083a, 0xa512) },
{ USB_DEVICE(0x083a, 0xc522) },
{ USB_DEVICE(0x083a, 0xd522) },
{ USB_DEVICE(0x083a, 0xf511) },
- /* Zyxel */
- { USB_DEVICE(0x0586, 0x341a) },
+ /* Sweex */
+ { USB_DEVICE(0x177f, 0x0254) },
+ /* TP-LINK */
+ { USB_DEVICE(0xf201, 0x5370) },
#endif
{ 0, }
};
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 0751b35ef6dc..086abb403a4f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -88,11 +88,9 @@
#define ERROR_PROBE(__msg, __args...) \
DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args)
#define WARNING(__dev, __msg, __args...) \
- DEBUG_PRINTK(__dev, KERN_WARNING, "Warning", __msg, ##__args)
-#define NOTICE(__dev, __msg, __args...) \
- DEBUG_PRINTK(__dev, KERN_NOTICE, "Notice", __msg, ##__args)
+ DEBUG_PRINTK_MSG(__dev, KERN_WARNING, "Warning", __msg, ##__args)
#define INFO(__dev, __msg, __args...) \
- DEBUG_PRINTK(__dev, KERN_INFO, "Info", __msg, ##__args)
+ DEBUG_PRINTK_MSG(__dev, KERN_INFO, "Info", __msg, ##__args)
#define DEBUG(__dev, __msg, __args...) \
DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args)
#define EEPROM(__dev, __msg, __args...) \
@@ -1016,6 +1014,26 @@ struct rt2x00_dev {
* Protect the interrupt mask register.
*/
spinlock_t irqmask_lock;
+
+ /*
+ * List of BlockAckReq TX entries that need driver BlockAck processing.
+ */
+ struct list_head bar_list;
+ spinlock_t bar_list_lock;
+};
+
+struct rt2x00_bar_list_entry {
+ struct list_head list;
+ struct rcu_head head;
+
+ struct queue_entry *entry;
+ int block_acked;
+
+ /* Relevant parts of the IEEE80211 BAR header */
+ __u8 ra[6];
+ __u8 ta[6];
+ __le16 control;
+ __le16 start_seq_num;
};
/*
@@ -1151,8 +1169,10 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
/**
* rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
* @entry: Pointer to &struct queue_entry
+ *
+ * Returns -ENOMEM if mapping fail, 0 otherwise.
*/
-void rt2x00queue_map_txskb(struct queue_entry *entry);
+int rt2x00queue_map_txskb(struct queue_entry *entry);
/**
* rt2x00queue_unmap_skb - Unmap a skb from DMA.
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 44f8b3f3cbed..1031db66474a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -271,6 +271,50 @@ void rt2x00lib_dmadone(struct queue_entry *entry)
}
EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
+static inline int rt2x00lib_txdone_bar_status(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct ieee80211_bar *bar = (void *) entry->skb->data;
+ struct rt2x00_bar_list_entry *bar_entry;
+ int ret;
+
+ if (likely(!ieee80211_is_back_req(bar->frame_control)))
+ return 0;
+
+ /*
+ * Unlike all other frames, the status report for BARs does
+ * not directly come from the hardware as it is incapable of
+ * matching a BA to a previously send BAR. The hardware will
+ * report all BARs as if they weren't acked at all.
+ *
+ * Instead the RX-path will scan for incoming BAs and set the
+ * block_acked flag if it sees one that was likely caused by
+ * a BAR from us.
+ *
+ * Remove remaining BARs here and return their status for
+ * TX done processing.
+ */
+ ret = 0;
+ rcu_read_lock();
+ list_for_each_entry_rcu(bar_entry, &rt2x00dev->bar_list, list) {
+ if (bar_entry->entry != entry)
+ continue;
+
+ spin_lock_bh(&rt2x00dev->bar_list_lock);
+ /* Return whether this BAR was blockacked or not */
+ ret = bar_entry->block_acked;
+ /* Remove the BAR from our checklist */
+ list_del_rcu(&bar_entry->list);
+ spin_unlock_bh(&rt2x00dev->bar_list_lock);
+ kfree_rcu(bar_entry, head);
+
+ break;
+ }
+ rcu_read_unlock();
+
+ return ret;
+}
+
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc)
{
@@ -324,9 +368,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);
/*
- * Determine if the frame has been successfully transmitted.
+ * Determine if the frame has been successfully transmitted and
+ * remove BARs from our check list while checking for their
+ * TX status.
*/
success =
+ rt2x00lib_txdone_bar_status(entry) ||
test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
test_bit(TXDONE_UNKNOWN, &txdesc->flags);
@@ -491,6 +538,50 @@ static void rt2x00lib_sleep(struct work_struct *work)
IEEE80211_CONF_CHANGE_PS);
}
+static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev,
+ struct sk_buff *skb,
+ struct rxdone_entry_desc *rxdesc)
+{
+ struct rt2x00_bar_list_entry *entry;
+ struct ieee80211_bar *ba = (void *)skb->data;
+
+ if (likely(!ieee80211_is_back(ba->frame_control)))
+ return;
+
+ if (rxdesc->size < sizeof(*ba) + FCS_LEN)
+ return;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(entry, &rt2x00dev->bar_list, list) {
+
+ if (ba->start_seq_num != entry->start_seq_num)
+ continue;
+
+#define TID_CHECK(a, b) ( \
+ ((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) == \
+ ((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK))) \
+
+ if (!TID_CHECK(ba->control, entry->control))
+ continue;
+
+#undef TID_CHECK
+
+ if (compare_ether_addr(ba->ra, entry->ta))
+ continue;
+
+ if (compare_ether_addr(ba->ta, entry->ra))
+ continue;
+
+ /* Mark BAR since we received the according BA */
+ spin_lock_bh(&rt2x00dev->bar_list_lock);
+ entry->block_acked = 1;
+ spin_unlock_bh(&rt2x00dev->bar_list_lock);
+ break;
+ }
+ rcu_read_unlock();
+
+}
+
static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct rxdone_entry_desc *rxdesc)
@@ -674,6 +765,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp)
rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc);
/*
+ * Check for incoming BlockAcks to match to the BlockAckReqs
+ * we've send out.
+ */
+ rt2x00lib_rxdone_check_ba(rt2x00dev, entry->skb, &rxdesc);
+
+ /*
* Update extra components
*/
rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
@@ -1139,7 +1236,8 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev)
*/
if_limit = &rt2x00dev->if_limits_ap;
if_limit->max = rt2x00dev->ops->max_ap_intf;
- if_limit->types = BIT(NL80211_IFTYPE_AP);
+ if_limit->types = BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
/*
* Build up AP interface combinations structure.
@@ -1183,6 +1281,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
spin_lock_init(&rt2x00dev->irqmask_lock);
mutex_init(&rt2x00dev->csr_mutex);
+ INIT_LIST_HEAD(&rt2x00dev->bar_list);
+ spin_lock_init(&rt2x00dev->bar_list_lock);
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
@@ -1347,7 +1447,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
#ifdef CONFIG_PM
int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
{
- NOTICE(rt2x00dev, "Going to sleep.\n");
+ DEBUG(rt2x00dev, "Going to sleep.\n");
/*
* Prevent mac80211 from accessing driver while suspended.
@@ -1387,7 +1487,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_suspend);
int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
{
- NOTICE(rt2x00dev, "Waking up.\n");
+ DEBUG(rt2x00dev, "Waking up.\n");
/*
* Restore/enable extra components.
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index ed7a1bb3f245..20c6eccce5aa 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -731,9 +731,9 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
queue->aifs = params->aifs;
queue->txop = params->txop;
- INFO(rt2x00dev,
- "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n",
- queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop);
+ DEBUG(rt2x00dev,
+ "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n",
+ queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop);
return 0;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index e488b944a034..4d91795dc6a2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -87,24 +87,35 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp)
skbdesc->entry = entry;
if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) {
- skbdesc->skb_dma = dma_map_single(rt2x00dev->dev,
- skb->data,
- skb->len,
- DMA_FROM_DEVICE);
+ dma_addr_t skb_dma;
+
+ skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len,
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(rt2x00dev->dev, skb_dma))) {
+ dev_kfree_skb_any(skb);
+ return NULL;
+ }
+
+ skbdesc->skb_dma = skb_dma;
skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
}
return skb;
}
-void rt2x00queue_map_txskb(struct queue_entry *entry)
+int rt2x00queue_map_txskb(struct queue_entry *entry)
{
struct device *dev = entry->queue->rt2x00dev->dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
skbdesc->skb_dma =
dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE);
+
+ if (unlikely(dma_mapping_error(dev, skbdesc->skb_dma)))
+ return -ENOMEM;
+
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
+ return 0;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
@@ -343,10 +354,7 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev,
* when using more then one tx stream (>MCS7).
*/
if (sta && txdesc->u.ht.mcs > 7 &&
- ((sta->ht_cap.cap &
- IEEE80211_HT_CAP_SM_PS) >>
- IEEE80211_HT_CAP_SM_PS_SHIFT) ==
- WLAN_HT_CAP_SM_PS_DYNAMIC)
+ sta->smps_mode == IEEE80211_SMPS_DYNAMIC)
__set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
} else {
txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs);
@@ -545,8 +553,9 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry,
/*
* Map the skb to DMA.
*/
- if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
- rt2x00queue_map_txskb(entry);
+ if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags) &&
+ rt2x00queue_map_txskb(entry))
+ return -ENOMEM;
return 0;
}
@@ -582,6 +591,48 @@ static void rt2x00queue_kick_tx_queue(struct data_queue *queue,
queue->rt2x00dev->ops->lib->kick_queue(queue);
}
+static void rt2x00queue_bar_check(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct ieee80211_bar *bar = (void *) (entry->skb->data +
+ rt2x00dev->ops->extra_tx_headroom);
+ struct rt2x00_bar_list_entry *bar_entry;
+
+ if (likely(!ieee80211_is_back_req(bar->frame_control)))
+ return;
+
+ bar_entry = kmalloc(sizeof(*bar_entry), GFP_ATOMIC);
+
+ /*
+ * If the alloc fails we still send the BAR out but just don't track
+ * it in our bar list. And as a result we will report it to mac80211
+ * back as failed.
+ */
+ if (!bar_entry)
+ return;
+
+ bar_entry->entry = entry;
+ bar_entry->block_acked = 0;
+
+ /*
+ * Copy the relevant parts of the 802.11 BAR into out check list
+ * such that we can use RCU for less-overhead in the RX path since
+ * sending BARs and processing the according BlockAck should be
+ * the exception.
+ */
+ memcpy(bar_entry->ra, bar->ra, sizeof(bar->ra));
+ memcpy(bar_entry->ta, bar->ta, sizeof(bar->ta));
+ bar_entry->control = bar->control;
+ bar_entry->start_seq_num = bar->start_seq_num;
+
+ /*
+ * Insert BAR into our BAR check list.
+ */
+ spin_lock_bh(&rt2x00dev->bar_list_lock);
+ list_add_tail_rcu(&bar_entry->list, &rt2x00dev->bar_list);
+ spin_unlock_bh(&rt2x00dev->bar_list_lock);
+}
+
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
bool local)
{
@@ -680,6 +731,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
goto out;
}
+ /*
+ * Put BlockAckReqs into our check list for driver BA processing.
+ */
+ rt2x00queue_bar_check(entry);
+
set_bit(ENTRY_DATA_PENDING, &entry->flags);
rt2x00queue_index_inc(entry, Q_INDEX);
diff --git a/drivers/net/wireless/rtl818x/Kconfig b/drivers/net/wireless/rtl818x/Kconfig
index 17d80fe556de..30332175bcd8 100644
--- a/drivers/net/wireless/rtl818x/Kconfig
+++ b/drivers/net/wireless/rtl818x/Kconfig
@@ -3,7 +3,7 @@
#
config RTL8180
tristate "Realtek 8180/8185 PCI support"
- depends on MAC80211 && PCI && EXPERIMENTAL
+ depends on MAC80211 && PCI
select EEPROM_93CX6
---help---
This is a driver for RTL8180 and RTL8185 based cards.
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index b80bc4612581..b6aa0c40658f 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -1,8 +1,26 @@
+config RTLWIFI
+ tristate "Realtek wireless card support"
+ depends on MAC80211
+ select FW_LOADER
+ ---help---
+ This is common code for RTL8192CE/RTL8192CU/RTL8192SE/RTL8723AE
+ drivers. This module does nothing by itself - the various front-end
+ drivers need to be enabled to support any desired devices.
+
+ If you choose to build as a module, it'll be called rtlwifi.
+
+config RTLWIFI_DEBUG
+ bool "Debugging output for rtlwifi driver family"
+ depends on RTLWIFI
+ default y
+ ---help---
+ To use the module option that sets the dynamic-debugging level for,
+ the front-end driver, this parameter must be "Y". For memory-limited
+ systems, choose "N". If in doubt, choose "Y".
+
config RTL8192CE
tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter"
- depends on MAC80211 && PCI
- select FW_LOADER
- select RTLWIFI
+ depends on RTLWIFI && PCI
select RTL8192C_COMMON
---help---
This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe
@@ -12,9 +30,7 @@ config RTL8192CE
config RTL8192SE
tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter"
- depends on MAC80211 && PCI
- select FW_LOADER
- select RTLWIFI
+ depends on RTLWIFI && PCI
---help---
This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe
wireless network adapters.
@@ -23,9 +39,7 @@ config RTL8192SE
config RTL8192DE
tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter"
- depends on MAC80211 && PCI
- select FW_LOADER
- select RTLWIFI
+ depends on RTLWIFI && PCI
---help---
This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe
wireless network adapters.
@@ -34,9 +48,7 @@ config RTL8192DE
config RTL8723AE
tristate "Realtek RTL8723AE PCIe Wireless Network Adapter"
- depends on MAC80211 && PCI && EXPERIMENTAL
- select FW_LOADER
- select RTLWIFI
+ depends on RTLWIFI && PCI
---help---
This is the driver for Realtek RTL8723AE 802.11n PCIe
wireless network adapters.
@@ -45,9 +57,7 @@ config RTL8723AE
config RTL8192CU
tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
- depends on MAC80211 && USB
- select FW_LOADER
- select RTLWIFI
+ depends on RTLWIFI && USB
select RTL8192C_COMMON
---help---
This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB
@@ -55,16 +65,6 @@ config RTL8192CU
If you choose to build it as a module, it will be called rtl8192cu
-config RTLWIFI
- tristate
- depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE
- default m
-
-config RTLWIFI_DEBUG
- bool "Additional debugging output"
- depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE
- default y
-
config RTL8192C_COMMON
tristate
depends on RTL8192CE || RTL8192CU
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 4494d130b37c..99c5cea3fe21 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -523,8 +523,8 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw,
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;
+ mac->opmode == NL80211_IFTYPE_ADHOC)
+ bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
if (bw_40 && sgi_40)
tcb_desc->use_shortgi = true;
@@ -634,8 +634,7 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
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))
+ if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
return;
} else if (mac->opmode == NL80211_IFTYPE_STATION) {
if (!mac->bw_40 || !(sta->ht_cap.ht_supported))
@@ -1004,7 +1003,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
is_tx ? "Tx" : "Rx");
if (is_tx) {
- rtl_lps_leave(hw);
+ schedule_work(&rtlpriv->
+ works.lps_leave_work);
ppsc->last_delaylps_stamp_jiffies =
jiffies;
}
@@ -1014,7 +1014,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
}
} else if (ETH_P_ARP == ether_type) {
if (is_tx) {
- rtl_lps_leave(hw);
+ schedule_work(&rtlpriv->works.lps_leave_work);
ppsc->last_delaylps_stamp_jiffies = jiffies;
}
@@ -1024,7 +1024,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
"802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx");
if (is_tx) {
- rtl_lps_leave(hw);
+ schedule_work(&rtlpriv->works.lps_leave_work);
ppsc->last_delaylps_stamp_jiffies = jiffies;
}
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index be33aa14c8af..d3ce9fbef00e 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -879,7 +879,9 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
"IEEE80211_AMPDU_TX_START: TID:%d\n", tid);
return rtl_tx_agg_start(hw, sta, tid, ssn);
break;
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid);
return rtl_tx_agg_stop(hw, sta, tid);
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c
index c1e065f136ba..f9f059dadb73 100644
--- a/drivers/net/wireless/rtlwifi/rc.c
+++ b/drivers/net/wireless/rtlwifi/rc.c
@@ -116,9 +116,8 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
if (txrc->short_preamble)
rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
if (mac->opmode == NL80211_IFTYPE_AP ||
- mac->opmode == NL80211_IFTYPE_ADHOC) {
- if (sta && (sta->ht_cap.cap &
- IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (sta && (sta->bandwidth >= IEEE80211_STA_RX_BW_40))
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
} else {
if (mac->bw_40)
@@ -223,13 +222,6 @@ static void rtl_rate_init(void *ppriv,
{
}
-static void rtl_rate_update(void *ppriv,
- struct ieee80211_supported_band *sband,
- struct ieee80211_sta *sta, void *priv_sta,
- u32 changed)
-{
-}
-
static void *rtl_rate_alloc(struct ieee80211_hw *hw,
struct dentry *debugfsdir)
{
@@ -275,7 +267,6 @@ static struct rate_control_ops rtl_rate_ops = {
.alloc_sta = rtl_rate_alloc_sta,
.free_sta = rtl_rate_free_sta,
.rate_init = rtl_rate_init,
- .rate_update = rtl_rate_update,
.tx_status = rtl_tx_status,
.get_rate = rtl_get_rate,
};
diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c
index c1608cddc529..d7d0d4948b01 100644
--- a/drivers/net/wireless/rtlwifi/regd.c
+++ b/drivers/net/wireless/rtlwifi/regd.c
@@ -158,8 +158,6 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
const struct ieee80211_reg_rule *reg_rule;
struct ieee80211_channel *ch;
unsigned int i;
- u32 bandwidth = 0;
- int r;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
@@ -174,9 +172,8 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
(ch->flags & IEEE80211_CHAN_RADAR))
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
- r = freq_reg_info(wiphy, ch->center_freq,
- bandwidth, &reg_rule);
- if (r)
+ reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ if (IS_ERR(reg_rule))
continue;
/*
@@ -211,8 +208,6 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
const struct ieee80211_reg_rule *reg_rule;
- u32 bandwidth = 0;
- int r;
if (!wiphy->bands[IEEE80211_BAND_2GHZ])
return;
@@ -240,16 +235,16 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/
ch = &sband->channels[11]; /* CH 12 */
- r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
- if (!r) {
+ reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
}
ch = &sband->channels[12]; /* CH 13 */
- r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
- if (!r) {
+ reg_rule = freq_reg_info(wiphy, ch->center_freq);
+ if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
@@ -303,9 +298,9 @@ static void _rtl_reg_apply_world_flags(struct wiphy *wiphy,
return;
}
-static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
- struct regulatory_request *request,
- struct rtl_regulatory *reg)
+static void _rtl_reg_notifier_apply(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ struct rtl_regulatory *reg)
{
/* We always apply this */
_rtl_reg_apply_radar_flags(wiphy);
@@ -319,8 +314,6 @@ static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
_rtl_reg_apply_world_flags(wiphy, request->initiator, reg);
break;
}
-
- return 0;
}
static const struct ieee80211_regdomain *_rtl_regdomain_select(
@@ -353,9 +346,9 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select(
static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
struct wiphy *wiphy,
- int (*reg_notifier) (struct wiphy *wiphy,
- struct regulatory_request *
- request))
+ void (*reg_notifier) (struct wiphy *wiphy,
+ struct regulatory_request *
+ request))
{
const struct ieee80211_regdomain *regd;
@@ -384,7 +377,7 @@ static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode)
}
int rtl_regd_init(struct ieee80211_hw *hw,
- int (*reg_notifier) (struct wiphy *wiphy,
+ void (*reg_notifier) (struct wiphy *wiphy,
struct regulatory_request *request))
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -426,12 +419,12 @@ int rtl_regd_init(struct ieee80211_hw *hw,
return 0;
}
-int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct rtl_priv *rtlpriv = rtl_priv(hw);
RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, "\n");
- return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
+ _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
}
diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h
index 70ef2f418a44..4e1f4f00e6e9 100644
--- a/drivers/net/wireless/rtlwifi/regd.h
+++ b/drivers/net/wireless/rtlwifi/regd.h
@@ -55,7 +55,7 @@ enum country_code_type_t {
};
int rtl_regd_init(struct ieee80211_hw *hw,
- int (*reg_notifier) (struct wiphy *wiphy,
- struct regulatory_request *request));
-int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+ void (*reg_notifier) (struct wiphy *wiphy,
+ struct regulatory_request *request));
+void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index 1cdf5a271c9f..b793a659a465 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -669,7 +669,8 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
u8 thermalvalue, delta, delta_lck, delta_iqk;
long ele_a, ele_d, temp_cck, val_x, value32;
long val_y, ele_c = 0;
- u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0;
+ u8 ofdm_index[2], ofdm_index_old[2], cck_index_old = 0;
+ s8 cck_index = 0;
int i;
bool is2t = IS_92C_SERIAL(rtlhal->version);
s8 txpwr_level[2] = {0, 0};
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index d1f34f6ffbdf..1b65db7fd651 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -1846,9 +1846,9 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
struct rtl_sta_info *sta_entry = NULL;
u32 ratr_bitmap;
u8 ratr_index;
- 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) ?
+ u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
+ u8 curshortgi_40mhz = curtxbw_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;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index c31795e379f7..b9b1a6e0b16e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -488,7 +488,7 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw,
u8 *praddr;
__le16 fc;
u16 type, c_fc;
- bool packet_matchbssid, packet_toself, packet_beacon;
+ bool packet_matchbssid, packet_toself, packet_beacon = false;
tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
@@ -626,8 +626,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
} 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;
+ bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
}
seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
index 32ff959a0251..85b6bdb163c0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
@@ -1084,7 +1084,7 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw,
u8 *praddr;
__le16 fc;
u16 type, cpu_fc;
- bool packet_matchbssid, packet_toself, packet_beacon;
+ bool packet_matchbssid, packet_toself, packet_beacon = false;
tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
hdr = (struct ieee80211_hdr *)tmp_buf;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index b7e6607e6b6d..a73a17bc56dd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -76,7 +76,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
GFP_KERNEL, hw, rtl_fw_cb);
- return 0;
+ return err;
}
static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw)
@@ -285,6 +285,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)},
/* RTL8188CUS-VL */
{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)},
+ {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x819a, rtl92cu_hal_cfg)},
/* 8188 Combo for BC4 */
{RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)},
@@ -363,9 +364,15 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
MODULE_DEVICE_TABLE(usb, rtl8192c_usb_ids);
+static int rtl8192cu_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return rtl_usb_probe(intf, id, &rtl92cu_hal_cfg);
+}
+
static struct usb_driver rtl8192cu_driver = {
.name = "rtl8192cu",
- .probe = rtl_usb_probe,
+ .probe = rtl8192cu_probe,
.disconnect = rtl_usb_disconnect,
.id_table = rtl8192c_usb_ids,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
index fd8df233ff22..5251fb8a111e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
@@ -841,9 +841,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
long ele_a = 0, ele_d, temp_cck, val_x, value32;
long val_y, ele_c = 0;
u8 ofdm_index[2];
- u8 cck_index = 0;
+ s8 cck_index = 0;
u8 ofdm_index_old[2];
- u8 cck_index_old = 0;
+ s8 cck_index_old = 0;
u8 index;
int i;
bool is2t = IS_92D_SINGLEPHY(rtlhal->version);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
index f4051f4f0390..aa5b42521bb4 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
@@ -1970,8 +1970,7 @@ static void rtl92de_update_hal_rate_mask(struct ieee80211_hw *hw,
struct rtl_sta_info *sta_entry = NULL;
u32 ratr_bitmap;
u8 ratr_index;
- u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
- ? 1 : 0;
+ u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_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) ?
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
index a0fbf284420e..941080e03c06 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
@@ -452,7 +452,7 @@ static void _rtl92de_translate_rx_signal_stuff(struct ieee80211_hw *hw,
u8 *praddr;
u16 type, cfc;
__le16 fc;
- bool packet_matchbssid, packet_toself, packet_beacon;
+ bool packet_matchbssid, packet_toself, packet_beacon = false;
tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
hdr = (struct ieee80211_hdr *)tmp_buf;
@@ -574,8 +574,7 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
} 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;
+ bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
}
seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
index 28526a7361f5..084e7773bce2 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
@@ -2085,8 +2085,7 @@ static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *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 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_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) ?
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index 206561d7282f..7b0a2e75b8b8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -480,7 +480,7 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw,
u8 *praddr;
__le16 fc;
u16 type, cfc;
- bool packet_matchbssid, packet_toself, packet_beacon;
+ bool packet_matchbssid, packet_toself, packet_beacon = false;
tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
@@ -621,8 +621,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
} 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;
+ bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
}
seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
index f55b1767ef57..35cb8f83eed4 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
@@ -252,7 +252,7 @@ static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw,
u16 box_reg = 0, box_extreg = 0;
u8 u1tmp;
bool isfw_rd = false;
- bool bwrite_sucess = false;
+ bool bwrite_success = false;
u8 wait_h2c_limmit = 100;
u8 wait_writeh2c_limmit = 100;
u8 boxcontent[4], boxextcontent[2];
@@ -291,7 +291,7 @@ static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw,
}
}
- while (!bwrite_sucess) {
+ while (!bwrite_success) {
wait_writeh2c_limmit--;
if (wait_writeh2c_limmit == 0) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -429,7 +429,7 @@ static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw,
break;
}
- bwrite_sucess = true;
+ bwrite_success = true;
rtlhal->last_hmeboxnum = boxnum + 1;
if (rtlhal->last_hmeboxnum == 4)
@@ -512,7 +512,6 @@ static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *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;
@@ -525,7 +524,6 @@ static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw,
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);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
index 887d521fe690..68c28340f791 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
@@ -1433,7 +1433,6 @@ static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
- u8 bt_retry_cnt;
u8 bt_info_original;
RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
"[BTCoex] Get bt info by fw!!\n");
@@ -1445,7 +1444,6 @@ static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw)
"[BTCoex] c2h for btInfo not rcvd yet!!\n");
}
- bt_retry_cnt = rtlhal->hal_coex_8723.bt_retry_cnt;
bt_info_original = rtlhal->hal_coex_8723.c2h_bt_info_original;
/* when bt inquiry or page scan, we have to set h2c 0x25
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
index 0a8c03863fb2..9a0c71c2e15e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
@@ -703,11 +703,9 @@ static void _rtl8723ae_hw_configure(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
u8 reg_bw_opmode;
- u32 reg_ratr, reg_prsr;
+ u32 reg_prsr;
reg_bw_opmode = BW_OPMODE_20MHZ;
- reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
- RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8);
@@ -1868,8 +1866,7 @@ static void rtl8723ae_update_hal_rate_mask(struct ieee80211_hw *hw,
struct rtl_sta_info *sta_entry = NULL;
u32 ratr_bitmap;
u8 ratr_index;
- u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
- ? 1 : 0;
+ u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_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) ?
@@ -2030,7 +2027,7 @@ bool rtl8723ae_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_phy *rtlphy = &(rtlpriv->phy);
- enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
+ enum rf_pwrstate e_rfpowerstate_toset;
u8 u1tmp;
bool actuallyset = false;
@@ -2049,8 +2046,6 @@ bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
spin_unlock(&rtlpriv->locks.rf_ps_lock);
}
- cur_rfstate = ppsc->rfpwr_state;
-
rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2,
rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2)&~(BIT(1)));
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
index 3d8536bb0d2b..eafbb18dd48e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
@@ -614,17 +614,11 @@ bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i;
- bool rtstatus = true;
u32 *radioa_array_table;
- u32 *radiob_array_table;
- u16 radioa_arraylen, radiob_arraylen;
+ u16 radioa_arraylen;
radioa_arraylen = Rtl8723ERADIOA_1TARRAYLENGTH;
radioa_array_table = RTL8723E_RADIOA_1TARRAY;
- radiob_arraylen = RTL8723E_RADIOB_1TARRAYLENGTH;
- radiob_array_table = RTL8723E_RADIOB_1TARRAY;
-
- rtstatus = true;
switch (rfpath) {
case RF90_PATH_A:
@@ -1531,11 +1525,8 @@ static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
0x522, 0x550, 0x551, 0x040
};
const u32 retrycount = 2;
- u32 bbvalue;
if (t == 0) {
- bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD);
-
phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16);
phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
}
@@ -1712,8 +1703,7 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
long result[4][8];
u8 i, final_candidate;
bool patha_ok, pathb_ok;
- long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
- reg_ecc, reg_tmp = 0;
+ long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_tmp = 0;
bool is12simular, is13simular, is23simular;
bool start_conttx = false, singletone = false;
u32 iqk_bb_reg[10] = {
@@ -1780,21 +1770,15 @@ void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
reg_e94 = result[i][0];
reg_e9c = result[i][1];
reg_ea4 = result[i][2];
- reg_eac = result[i][3];
reg_eb4 = result[i][4];
reg_ebc = result[i][5];
- reg_ec4 = result[i][6];
- reg_ecc = result[i][7];
}
if (final_candidate != 0xff) {
rtlphy->reg_e94 = reg_e94 = result[final_candidate][0];
rtlphy->reg_e9c = reg_e9c = result[final_candidate][1];
reg_ea4 = result[final_candidate][2];
- reg_eac = result[final_candidate][3];
rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4];
rtlphy->reg_ebc = reg_ebc = result[final_candidate][5];
- reg_ec4 = result[final_candidate][6];
- reg_ecc = result[final_candidate][7];
patha_ok = pathb_ok = true;
} else {
rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
index a313be8c21d2..ac081297db50 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
@@ -244,10 +244,9 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr;
u8 *tmp_buf;
u8 *praddr;
- u8 *psaddr;
__le16 fc;
u16 type;
- bool packet_matchbssid, packet_toself, packet_beacon;
+ bool packet_matchbssid, packet_toself, packet_beacon = false;
tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
@@ -255,7 +254,6 @@ static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw,
fc = hdr->frame_control;
type = WLAN_FC_GET_TYPE(fc);
praddr = hdr->addr1;
- psaddr = ieee80211_get_SA(hdr);
packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
(!compare_ether_addr(mac->bssid,
@@ -397,8 +395,7 @@ void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
} 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;
+ bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
}
seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index f2ecdeb3a90d..156b52732f3d 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -42,8 +42,12 @@
static void usbctrl_async_callback(struct urb *urb)
{
- if (urb)
- kfree(urb->context);
+ if (urb) {
+ /* free dr */
+ kfree(urb->setup_packet);
+ /* free databuf */
+ kfree(urb->transfer_buffer);
+ }
}
static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
@@ -55,39 +59,47 @@ static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
u8 reqtype;
struct usb_ctrlrequest *dr;
struct urb *urb;
- struct rtl819x_async_write_data {
- u8 data[REALTEK_USB_VENQT_MAX_BUF_SIZE];
- struct usb_ctrlrequest dr;
- } *buf;
+ const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE;
+ u8 *databuf;
+
+ if (WARN_ON_ONCE(len > databuf_maxlen))
+ len = databuf_maxlen;
pipe = usb_sndctrlpipe(udev, 0); /* write_out */
reqtype = REALTEK_USB_VENQT_WRITE;
- buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
- if (!buf)
+ dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+ if (!dr)
return -ENOMEM;
+ databuf = kmalloc(databuf_maxlen, GFP_ATOMIC);
+ if (!databuf) {
+ kfree(dr);
+ return -ENOMEM;
+ }
+
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- kfree(buf);
+ kfree(databuf);
+ kfree(dr);
return -ENOMEM;
}
- dr = &buf->dr;
-
dr->bRequestType = reqtype;
dr->bRequest = request;
dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(len);
/* data are already in little-endian order */
- memcpy(buf, pdata, len);
+ memcpy(databuf, pdata, len);
usb_fill_control_urb(urb, udev, pipe,
- (unsigned char *)dr, buf, len,
- usbctrl_async_callback, buf);
+ (unsigned char *)dr, databuf, len,
+ usbctrl_async_callback, NULL);
rc = usb_submit_urb(urb, GFP_ATOMIC);
- if (rc < 0)
- kfree(buf);
+ if (rc < 0) {
+ kfree(databuf);
+ kfree(dr);
+ }
usb_free_urb(urb);
return rc;
}
@@ -542,8 +554,8 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb)
WARN_ON(skb_queue_empty(&rx_queue));
while (!skb_queue_empty(&rx_queue)) {
_skb = skb_dequeue(&rx_queue);
- _rtl_usb_rx_process_agg(hw, skb);
- ieee80211_rx_irqsafe(hw, skb);
+ _rtl_usb_rx_process_agg(hw, _skb);
+ ieee80211_rx_irqsafe(hw, _skb);
}
}
@@ -825,8 +837,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,
u32 ep_num;
struct urb *_urb = NULL;
struct sk_buff *_skb = NULL;
- struct sk_buff_head *skb_list;
- struct usb_anchor *urb_list;
WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl);
if (unlikely(IS_USB_STOP(rtlusb))) {
@@ -836,7 +846,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,
return;
}
ep_num = rtlusb->ep_map.ep_mapping[qnum];
- skb_list = &rtlusb->tx_skb_queue[ep_num];
_skb = skb;
_urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num);
if (unlikely(!_urb)) {
@@ -844,7 +853,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,
"Can't allocate urb. Drop skb!\n");
return;
}
- urb_list = &rtlusb->tx_pending[ep_num];
_rtl_submit_tx_urb(hw, _urb);
}
@@ -941,7 +949,8 @@ static struct rtl_intf_ops rtl_usb_ops = {
};
int rtl_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+ const struct usb_device_id *id,
+ struct rtl_hal_cfg *rtl_hal_cfg)
{
int err;
struct ieee80211_hw *hw = NULL;
@@ -976,7 +985,7 @@ int rtl_usb_probe(struct usb_interface *intf,
usb_set_intfdata(intf, hw);
/* init cfg & intf_ops */
rtlpriv->rtlhal.interface = INTF_USB;
- rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_info);
+ rtlpriv->cfg = rtl_hal_cfg;
rtlpriv->intf_ops = &rtl_usb_ops;
rtl_dbgp_flag_init(hw);
/* Init IO handler */
diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h
index 5235136f6dd2..fb986f98d1df 100644
--- a/drivers/net/wireless/rtlwifi/usb.h
+++ b/drivers/net/wireless/rtlwifi/usb.h
@@ -157,7 +157,8 @@ struct rtl_usb_priv {
int rtl_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id);
+ const struct usb_device_id *id,
+ struct rtl_hal_cfg *rtl92cu_hal_cfg);
void rtl_usb_disconnect(struct usb_interface *intf);
int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message);
int rtl_usb_resume(struct usb_interface *pusb_intf);
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 21a5f4f4a135..f13258a8d995 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -1702,7 +1702,7 @@ struct rtl_works {
struct rtl_debug {
u32 dbgp_type[DBGP_TYPE_MAX];
- u32 global_debuglevel;
+ int global_debuglevel;
u64 global_debugcomponents;
/* add for proc debug */
diff --git a/drivers/net/wireless/ti/Kconfig b/drivers/net/wireless/ti/Kconfig
index be800119d0a3..cbe1e7fef61b 100644
--- a/drivers/net/wireless/ti/Kconfig
+++ b/drivers/net/wireless/ti/Kconfig
@@ -12,4 +12,13 @@ source "drivers/net/wireless/ti/wl18xx/Kconfig"
# keep last for automatic dependencies
source "drivers/net/wireless/ti/wlcore/Kconfig"
+
+config WILINK_PLATFORM_DATA
+ bool "TI WiLink platform data"
+ depends on WLCORE_SDIO || WL1251_SDIO
+ default y
+ ---help---
+ Small platform data bit needed to pass data to the sdio modules.
+
+
endif # WL_TI
diff --git a/drivers/net/wireless/ti/Makefile b/drivers/net/wireless/ti/Makefile
index 4d6823983c04..af14231aeede 100644
--- a/drivers/net/wireless/ti/Makefile
+++ b/drivers/net/wireless/ti/Makefile
@@ -1,5 +1,7 @@
obj-$(CONFIG_WLCORE) += wlcore/
obj-$(CONFIG_WL12XX) += wl12xx/
-obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wlcore/
obj-$(CONFIG_WL1251) += wl1251/
obj-$(CONFIG_WL18XX) += wl18xx/
+
+# small builtin driver bit
+obj-$(CONFIG_WILINK_PLATFORM_DATA) += wilink_platform_data.o
diff --git a/drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c b/drivers/net/wireless/ti/wilink_platform_data.c
index 998e95895f9d..998e95895f9d 100644
--- a/drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c
+++ b/drivers/net/wireless/ti/wilink_platform_data.c
diff --git a/drivers/net/wireless/ti/wl1251/Kconfig b/drivers/net/wireless/ti/wl1251/Kconfig
index 1fb65849414f..8fec4ed36ac2 100644
--- a/drivers/net/wireless/ti/wl1251/Kconfig
+++ b/drivers/net/wireless/ti/wl1251/Kconfig
@@ -1,6 +1,6 @@
menuconfig WL1251
tristate "TI wl1251 driver support"
- depends on MAC80211 && EXPERIMENTAL && GENERIC_HARDIRQS
+ depends on MAC80211 && GENERIC_HARDIRQS
select FW_LOADER
select CRC7
---help---
diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c
index 5ec50a476a69..74ae8e1c2e33 100644
--- a/drivers/net/wireless/ti/wl1251/event.c
+++ b/drivers/net/wireless/ti/wl1251/event.c
@@ -29,6 +29,8 @@
static int wl1251_event_scan_complete(struct wl1251 *wl,
struct event_mailbox *mbox)
{
+ int ret = 0;
+
wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
mbox->scheduled_scan_status,
mbox->scheduled_scan_channels);
@@ -37,9 +39,11 @@ static int wl1251_event_scan_complete(struct wl1251 *wl,
ieee80211_scan_completed(wl->hw, false);
wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
wl->scanning = false;
+ if (wl->hw->conf.flags & IEEE80211_CONF_IDLE)
+ ret = wl1251_ps_set_mode(wl, STATION_IDLE);
}
- return 0;
+ return ret;
}
static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index f47e8b0482ad..bbbf68cf50a7 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -623,7 +623,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
}
}
- if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+ if (changed & IEEE80211_CONF_CHANGE_IDLE && !wl->scanning) {
if (conf->flags & IEEE80211_CONF_IDLE) {
ret = wl1251_ps_set_mode(wl, STATION_IDLE);
if (ret < 0)
@@ -895,11 +895,21 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
+ if (hw->conf.flags & IEEE80211_CONF_IDLE) {
+ 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;
+ }
+
skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
req->ie_len);
if (!skb) {
ret = -ENOMEM;
- goto out;
+ goto out_idle;
}
if (req->ie_len)
memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
@@ -908,11 +918,11 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
skb->len);
dev_kfree_skb(skb);
if (ret < 0)
- goto out_sleep;
+ goto out_idle;
ret = wl1251_cmd_trigger_scan_to(wl, 0);
if (ret < 0)
- goto out_sleep;
+ goto out_idle;
wl->scanning = true;
@@ -920,9 +930,13 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
req->n_channels, WL1251_SCAN_NUM_PROBES);
if (ret < 0) {
wl->scanning = false;
- goto out_sleep;
+ goto out_idle;
}
+ goto out_sleep;
+out_idle:
+ if (hw->conf.flags & IEEE80211_CONF_IDLE)
+ ret = wl1251_ps_set_mode(wl, STATION_IDLE);
out_sleep:
wl1251_ps_elp_sleep(wl);
diff --git a/drivers/net/wireless/ti/wl1251/ps.c b/drivers/net/wireless/ti/wl1251/ps.c
index db719f7d2692..b9e27b98bbc9 100644
--- a/drivers/net/wireless/ti/wl1251/ps.c
+++ b/drivers/net/wireless/ti/wl1251/ps.c
@@ -68,8 +68,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
unsigned long timeout, start;
u32 elp_reg;
- if (delayed_work_pending(&wl->elp_work))
- cancel_delayed_work(&wl->elp_work);
+ cancel_delayed_work(&wl->elp_work);
if (!wl->elp)
return 0;
diff --git a/drivers/net/wireless/ti/wl12xx/Makefile b/drivers/net/wireless/ti/wl12xx/Makefile
index da509aa7d009..e6a24056b3c8 100644
--- a/drivers/net/wireless/ti/wl12xx/Makefile
+++ b/drivers/net/wireless/ti/wl12xx/Makefile
@@ -1,3 +1,3 @@
-wl12xx-objs = main.o cmd.o acx.o debugfs.o
+wl12xx-objs = main.o cmd.o acx.o debugfs.o scan.o event.o
obj-$(CONFIG_WL12XX) += wl12xx.o
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.c b/drivers/net/wireless/ti/wl12xx/cmd.c
index 622206241e83..7dc9f965037d 100644
--- a/drivers/net/wireless/ti/wl12xx/cmd.c
+++ b/drivers/net/wireless/ti/wl12xx/cmd.c
@@ -284,3 +284,40 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
kfree(radio_parms);
return ret;
}
+
+int wl12xx_cmd_channel_switch(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct ieee80211_channel_switch *ch_switch)
+{
+ struct wl12xx_cmd_channel_switch *cmd;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "cmd channel switch");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->role_id = wlvif->role_id;
+ cmd->channel = ch_switch->channel->hw_value;
+ cmd->switch_time = ch_switch->count;
+ cmd->stop_tx = ch_switch->block_tx;
+
+ /* FIXME: control from mac80211 in the future */
+ /* Enable TX on the target channel */
+ cmd->post_switch_tx_disable = 0;
+
+ ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send channel switch command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.h b/drivers/net/wireless/ti/wl12xx/cmd.h
index 140a0e8829d5..32cbad54e993 100644
--- a/drivers/net/wireless/ti/wl12xx/cmd.h
+++ b/drivers/net/wireless/ti/wl12xx/cmd.h
@@ -103,10 +103,30 @@ struct wl1271_ext_radio_parms_cmd {
u8 padding[3];
} __packed;
+struct wl12xx_cmd_channel_switch {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+
+ /* The new serving channel */
+ u8 channel;
+ /* Relative time of the serving channel switch in TBTT units */
+ u8 switch_time;
+ /* Stop the role TX, should expect it after radar detection */
+ u8 stop_tx;
+ /* The target channel tx status 1-stopped 0-open*/
+ u8 post_switch_tx_disable;
+
+ u8 padding[3];
+} __packed;
+
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 wl12xx_cmd_channel_switch(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct ieee80211_channel_switch *ch_switch);
#endif /* __WL12XX_CMD_H__ */
diff --git a/drivers/net/wireless/ti/wl12xx/event.c b/drivers/net/wireless/ti/wl12xx/event.c
new file mode 100644
index 000000000000..6ac0ed751da8
--- /dev/null
+++ b/drivers/net/wireless/ti/wl12xx/event.c
@@ -0,0 +1,116 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You 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 "event.h"
+#include "scan.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/debug.h"
+
+int wl12xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
+ bool *timeout)
+{
+ u32 local_event;
+
+ switch (event) {
+ case WLCORE_EVENT_ROLE_STOP_COMPLETE:
+ local_event = ROLE_STOP_COMPLETE_EVENT_ID;
+ break;
+
+ case WLCORE_EVENT_PEER_REMOVE_COMPLETE:
+ local_event = PEER_REMOVE_COMPLETE_EVENT_ID;
+ break;
+
+ default:
+ /* event not implemented */
+ return 0;
+ }
+ return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout);
+}
+
+int wl12xx_process_mailbox_events(struct wl1271 *wl)
+{
+ struct wl12xx_event_mailbox *mbox = wl->mbox;
+ u32 vector;
+
+
+ vector = le32_to_cpu(mbox->events_vector);
+ vector &= ~(le32_to_cpu(mbox->events_mask));
+
+ wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector);
+
+ if (vector & SCAN_COMPLETE_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT, "status: 0x%x",
+ mbox->scheduled_scan_status);
+
+ if (wl->scan_wlvif)
+ wl12xx_scan_completed(wl, wl->scan_wlvif);
+ }
+
+ if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT,
+ "PERIODIC_SCAN_REPORT_EVENT (status 0x%0x)",
+ mbox->scheduled_scan_status);
+
+ wlcore_scan_sched_scan_results(wl);
+ }
+
+ if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID)
+ wlcore_event_sched_scan_completed(wl,
+ mbox->scheduled_scan_status);
+ if (vector & SOFT_GEMINI_SENSE_EVENT_ID)
+ wlcore_event_soft_gemini_sense(wl,
+ mbox->soft_gemini_sense_info);
+
+ if (vector & BSS_LOSE_EVENT_ID)
+ wlcore_event_beacon_loss(wl, 0xff);
+
+ if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID)
+ wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric);
+
+ if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)
+ wlcore_event_ba_rx_constraint(wl,
+ BIT(mbox->role_id),
+ mbox->rx_ba_allowed);
+
+ if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID)
+ wlcore_event_channel_switch(wl, 0xff,
+ mbox->channel_switch_status);
+
+ if (vector & DUMMY_PACKET_EVENT_ID)
+ wlcore_event_dummy_packet(wl);
+
+ /*
+ * "TX retries exceeded" has a different meaning according to mode.
+ * In AP mode the offending station is disconnected.
+ */
+ if (vector & MAX_TX_RETRY_EVENT_ID)
+ wlcore_event_max_tx_failure(wl,
+ le16_to_cpu(mbox->sta_tx_retry_exceeded));
+
+ if (vector & INACTIVE_STA_EVENT_ID)
+ wlcore_event_inactive_sta(wl,
+ le16_to_cpu(mbox->sta_aging_status));
+
+ if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID)
+ wlcore_event_roc_complete(wl);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ti/wl12xx/event.h b/drivers/net/wireless/ti/wl12xx/event.h
new file mode 100644
index 000000000000..a5cc3fcd9eea
--- /dev/null
+++ b/drivers/net/wireless/ti/wl12xx/event.h
@@ -0,0 +1,111 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL12XX_EVENT_H__
+#define __WL12XX_EVENT_H__
+
+#include "../wlcore/wlcore.h"
+
+enum {
+ MEASUREMENT_START_EVENT_ID = BIT(8),
+ MEASUREMENT_COMPLETE_EVENT_ID = BIT(9),
+ SCAN_COMPLETE_EVENT_ID = BIT(10),
+ WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11),
+ AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
+ RESERVED1 = BIT(13),
+ PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
+ ROLE_STOP_COMPLETE_EVENT_ID = BIT(15),
+ RADAR_DETECTED_EVENT_ID = BIT(16),
+ CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
+ BSS_LOSE_EVENT_ID = BIT(18),
+ REGAINED_BSS_EVENT_ID = BIT(19),
+ MAX_TX_RETRY_EVENT_ID = BIT(20),
+ DUMMY_PACKET_EVENT_ID = BIT(21),
+ SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
+ CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23),
+ SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
+ PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
+ INACTIVE_STA_EVENT_ID = BIT(26),
+ PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27),
+ PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28),
+ PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29),
+ BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30),
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31),
+};
+
+struct wl12xx_event_mailbox {
+ __le32 events_vector;
+ __le32 events_mask;
+ __le32 reserved_1;
+ __le32 reserved_2;
+
+ u8 number_of_scan_results;
+ u8 scan_tag;
+ u8 completed_scan_status;
+ u8 reserved_3;
+
+ u8 soft_gemini_sense_info;
+ u8 soft_gemini_protective_info;
+ s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
+ u8 change_auto_mode_timeout;
+ u8 scheduled_scan_status;
+ u8 reserved4;
+ /* tuned channel (roc) */
+ u8 roc_channel;
+
+ __le16 hlid_removed_bitmap;
+
+ /* bitmap of aged stations (by HLID) */
+ __le16 sta_aging_status;
+
+ /* bitmap of stations (by HLID) which exceeded max tx retries */
+ __le16 sta_tx_retry_exceeded;
+
+ /* discovery completed results */
+ u8 discovery_tag;
+ u8 number_of_preq_results;
+ u8 number_of_prsp_results;
+ u8 reserved_5;
+
+ /* rx ba constraint */
+ u8 role_id; /* 0xFF means any role. */
+ u8 rx_ba_allowed;
+ u8 reserved_6[2];
+
+ /* Channel switch results */
+
+ u8 channel_switch_role_id;
+ u8 channel_switch_status;
+ u8 reserved_7[2];
+
+ u8 ps_poll_delivery_failure_role_ids;
+ u8 stopped_role_ids;
+ u8 started_role_ids;
+
+ u8 reserved_8[9];
+} __packed;
+
+int wl12xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
+ bool *timeout);
+int wl12xx_process_mailbox_events(struct wl1271 *wl);
+
+#endif
+
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index e5f5f8f39144..09694e39bb14 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -38,6 +38,8 @@
#include "reg.h"
#include "cmd.h"
#include "acx.h"
+#include "scan.h"
+#include "event.h"
#include "debugfs.h"
static char *fref_param;
@@ -208,6 +210,8 @@ static struct wlcore_conf wl12xx_conf = {
.tmpl_short_retry_limit = 10,
.tmpl_long_retry_limit = 10,
.tx_watchdog_timeout = 5000,
+ .slow_link_thold = 3,
+ .fast_link_thold = 10,
},
.conn = {
.wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
@@ -265,8 +269,10 @@ static struct wlcore_conf wl12xx_conf = {
.scan = {
.min_dwell_time_active = 7500,
.max_dwell_time_active = 30000,
- .min_dwell_time_passive = 100000,
- .max_dwell_time_passive = 100000,
+ .min_dwell_time_active_long = 25000,
+ .max_dwell_time_active_long = 50000,
+ .dwell_time_passive = 100000,
+ .dwell_time_dfs = 150000,
.num_probe_reqs = 2,
.split_scan_timeout = 50000,
},
@@ -368,6 +374,10 @@ static struct wlcore_conf wl12xx_conf = {
.increase_time = 1,
.window_size = 16,
},
+ .recovery = {
+ .bug_on_recovery = 0,
+ .no_recovery = 0,
+ },
};
static struct wl12xx_priv_conf wl12xx_default_priv_conf = {
@@ -601,9 +611,9 @@ static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
{
int ret;
- if (wl->chip.id != CHIP_ID_1283_PG20) {
+ if (wl->chip.id != CHIP_ID_128X_PG20) {
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
- struct wl127x_rx_mem_pool_addr rx_mem_addr;
+ struct wl12xx_priv *priv = wl->priv;
/*
* Choose the block we want to read
@@ -612,13 +622,13 @@ static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
*/
u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK;
- rx_mem_addr.addr = (mem_block << 8) +
+ priv->rx_mem_addr->addr = (mem_block << 8) +
le32_to_cpu(wl_mem_map->packet_memory_pool_start);
- rx_mem_addr.addr_extra = rx_mem_addr.addr + 4;
+ priv->rx_mem_addr->addr_extra = priv->rx_mem_addr->addr + 4;
- ret = wlcore_write(wl, WL1271_SLV_REG_DATA, &rx_mem_addr,
- sizeof(rx_mem_addr), false);
+ ret = wlcore_write(wl, WL1271_SLV_REG_DATA, priv->rx_mem_addr,
+ sizeof(*priv->rx_mem_addr), false);
if (ret < 0)
return ret;
}
@@ -631,13 +641,15 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
int ret = 0;
switch (wl->chip.id) {
- case CHIP_ID_1271_PG10:
+ case CHIP_ID_127X_PG10:
wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
wl->chip.id);
wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
WLCORE_QUIRK_DUAL_PROBE_TMPL |
- WLCORE_QUIRK_TKIP_HEADER_SPACE;
+ WLCORE_QUIRK_TKIP_HEADER_SPACE |
+ WLCORE_QUIRK_START_STA_FAILS |
+ WLCORE_QUIRK_AP_ZERO_SESSION_ID;
wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
wl->mr_fw_name = WL127X_FW_NAME_MULTI;
memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x,
@@ -646,18 +658,22 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
/* read data preparation is only needed by wl127x */
wl->ops->prepare_read = wl127x_prepare_read;
- wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER,
- WL127X_MAJOR_VER, WL127X_SUBTYPE_VER,
- WL127X_MINOR_VER);
+ wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER,
+ WL127X_IFTYPE_SR_VER, WL127X_MAJOR_SR_VER,
+ WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER,
+ WL127X_IFTYPE_MR_VER, WL127X_MAJOR_MR_VER,
+ WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER);
break;
- case CHIP_ID_1271_PG20:
+ case CHIP_ID_127X_PG20:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
wl->chip.id);
wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
WLCORE_QUIRK_DUAL_PROBE_TMPL |
- WLCORE_QUIRK_TKIP_HEADER_SPACE;
+ WLCORE_QUIRK_TKIP_HEADER_SPACE |
+ WLCORE_QUIRK_START_STA_FAILS |
+ WLCORE_QUIRK_AP_ZERO_SESSION_ID;
wl->plt_fw_name = WL127X_PLT_FW_NAME;
wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
wl->mr_fw_name = WL127X_FW_NAME_MULTI;
@@ -667,12 +683,14 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
/* read data preparation is only needed by wl127x */
wl->ops->prepare_read = wl127x_prepare_read;
- wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER,
- WL127X_MAJOR_VER, WL127X_SUBTYPE_VER,
- WL127X_MINOR_VER);
+ wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER,
+ WL127X_IFTYPE_SR_VER, WL127X_MAJOR_SR_VER,
+ WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER,
+ WL127X_IFTYPE_MR_VER, WL127X_MAJOR_MR_VER,
+ WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER);
break;
- case CHIP_ID_1283_PG20:
+ case CHIP_ID_128X_PG20:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
wl->chip.id);
wl->plt_fw_name = WL128X_PLT_FW_NAME;
@@ -682,19 +700,29 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
/* wl128x requires TX blocksize alignment */
wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
WLCORE_QUIRK_DUAL_PROBE_TMPL |
- WLCORE_QUIRK_TKIP_HEADER_SPACE;
-
- wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, WL128X_IFTYPE_VER,
- WL128X_MAJOR_VER, WL128X_SUBTYPE_VER,
- WL128X_MINOR_VER);
+ WLCORE_QUIRK_TKIP_HEADER_SPACE |
+ WLCORE_QUIRK_START_STA_FAILS |
+ WLCORE_QUIRK_AP_ZERO_SESSION_ID;
+
+ wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER,
+ WL128X_IFTYPE_SR_VER, WL128X_MAJOR_SR_VER,
+ WL128X_SUBTYPE_SR_VER, WL128X_MINOR_SR_VER,
+ WL128X_IFTYPE_MR_VER, WL128X_MAJOR_MR_VER,
+ WL128X_SUBTYPE_MR_VER, WL128X_MINOR_MR_VER);
break;
- case CHIP_ID_1283_PG10:
+ case CHIP_ID_128X_PG10:
default:
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
goto out;
}
+ /* common settings */
+ wl->scan_templ_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY;
+ wl->scan_templ_id_5 = CMD_TEMPL_APP_PROBE_REQ_5_LEGACY;
+ wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
+ wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
+ wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ;
out:
return ret;
}
@@ -1067,7 +1095,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
u32 clk;
int selected_clock = -1;
- if (wl->chip.id == CHIP_ID_1283_PG20) {
+ if (wl->chip.id == CHIP_ID_128X_PG20) {
ret = wl128x_boot_clk(wl, &selected_clock);
if (ret < 0)
goto out;
@@ -1098,7 +1126,7 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
- if (wl->chip.id == CHIP_ID_1283_PG20)
+ if (wl->chip.id == CHIP_ID_128X_PG20)
clk |= ((selected_clock & 0x3) << 1) << 4;
else
clk |= (priv->ref_clock << 1) << 4;
@@ -1152,7 +1180,7 @@ static int wl12xx_pre_upload(struct wl1271 *wl)
/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
* to upload_fw) */
- if (wl->chip.id == CHIP_ID_1283_PG20) {
+ if (wl->chip.id == CHIP_ID_128X_PG20) {
ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
if (ret < 0)
goto out;
@@ -1219,6 +1247,23 @@ static int wl12xx_boot(struct wl1271 *wl)
if (ret < 0)
goto out;
+ wl->event_mask = BSS_LOSE_EVENT_ID |
+ REGAINED_BSS_EVENT_ID |
+ SCAN_COMPLETE_EVENT_ID |
+ ROLE_STOP_COMPLETE_EVENT_ID |
+ RSSI_SNR_TRIGGER_0_EVENT_ID |
+ PSPOLL_DELIVERY_FAILURE_EVENT_ID |
+ SOFT_GEMINI_SENSE_EVENT_ID |
+ PERIODIC_SCAN_REPORT_EVENT_ID |
+ PERIODIC_SCAN_COMPLETE_EVENT_ID |
+ DUMMY_PACKET_EVENT_ID |
+ PEER_REMOVE_COMPLETE_EVENT_ID |
+ BA_SESSION_RX_CONSTRAINT_EVENT_ID |
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
+ INACTIVE_STA_EVENT_ID |
+ MAX_TX_RETRY_EVENT_ID |
+ CHANNEL_SWITCH_COMPLETE_EVENT_ID;
+
ret = wlcore_boot_run_firmware(wl);
if (ret < 0)
goto out;
@@ -1261,7 +1306,7 @@ static void
wl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
u32 blks, u32 spare_blks)
{
- if (wl->chip.id == CHIP_ID_1283_PG20) {
+ if (wl->chip.id == CHIP_ID_128X_PG20) {
desc->wl128x_mem.total_mem_blocks = blks;
} else {
desc->wl127x_mem.extra_blocks = spare_blks;
@@ -1275,7 +1320,7 @@ wl12xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
{
u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len);
- if (wl->chip.id == CHIP_ID_1283_PG20) {
+ if (wl->chip.id == CHIP_ID_128X_PG20) {
desc->wl128x_mem.extra_bytes = aligned_len - skb->len;
desc->length = cpu_to_le16(aligned_len >> 2);
@@ -1339,7 +1384,7 @@ static int wl12xx_hw_init(struct wl1271 *wl)
{
int ret;
- if (wl->chip.id == CHIP_ID_1283_PG20) {
+ if (wl->chip.id == CHIP_ID_128X_PG20) {
u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
ret = wl128x_cmd_general_parms(wl);
@@ -1394,22 +1439,6 @@ static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl,
return wlvif->rate_set;
}
-static int wl12xx_identify_fw(struct wl1271 *wl)
-{
- unsigned int *fw_ver = wl->chip.fw_ver;
-
- /* Only new station firmwares support routing fw logs to the host */
- if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
- (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN))
- wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED;
-
- /* This feature is not yet supported for AP mode */
- if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP)
- wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED;
-
- return 0;
-}
-
static void wl12xx_conf_init(struct wl1271 *wl)
{
struct wl12xx_priv *priv = wl->priv;
@@ -1426,7 +1455,7 @@ static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
bool supported = false;
u8 major, minor;
- if (wl->chip.id == CHIP_ID_1283_PG20) {
+ if (wl->chip.id == CHIP_ID_128X_PG20) {
major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
@@ -1482,7 +1511,7 @@ static int wl12xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
u16 die_info;
int ret;
- if (wl->chip.id == CHIP_ID_1283_PG20)
+ if (wl->chip.id == CHIP_ID_128X_PG20)
ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1,
&die_info);
else
@@ -1589,16 +1618,46 @@ static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
return wlcore_set_key(wl, cmd, vif, sta, key_conf);
}
+static int wl12xx_set_peer_cap(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid)
+{
+ return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation,
+ hlid);
+}
+
+static bool wl12xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ u8 thold;
+
+ if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map))
+ thold = wl->conf.tx.fast_link_thold;
+ else
+ thold = wl->conf.tx.slow_link_thold;
+
+ return lnk->allocated_pkts < thold;
+}
+
+static bool wl12xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ /* any link is good for low priority */
+ return true;
+}
+
static int wl12xx_setup(struct wl1271 *wl);
static struct wlcore_ops wl12xx_ops = {
.setup = wl12xx_setup,
.identify_chip = wl12xx_identify_chip,
- .identify_fw = wl12xx_identify_fw,
.boot = wl12xx_boot,
.plt_init = wl12xx_plt_init,
.trigger_cmd = wl12xx_trigger_cmd,
.ack_event = wl12xx_ack_event,
+ .wait_for_event = wl12xx_wait_for_event,
+ .process_mailbox_events = wl12xx_process_mailbox_events,
.calc_tx_blocks = wl12xx_calc_tx_blocks,
.set_tx_desc_blocks = wl12xx_set_tx_desc_blocks,
.set_tx_desc_data_len = wl12xx_set_tx_desc_data_len,
@@ -1615,9 +1674,17 @@ static struct wlcore_ops wl12xx_ops = {
.set_rx_csum = NULL,
.ap_get_mimo_wide_rate_mask = NULL,
.debugfs_init = wl12xx_debugfs_add_files,
+ .scan_start = wl12xx_scan_start,
+ .scan_stop = wl12xx_scan_stop,
+ .sched_scan_start = wl12xx_sched_scan_start,
+ .sched_scan_stop = wl12xx_scan_sched_scan_stop,
.get_spare_blocks = wl12xx_get_spare_blocks,
.set_key = wl12xx_set_key,
+ .channel_switch = wl12xx_cmd_channel_switch,
.pre_pkt_send = NULL,
+ .set_peer_cap = wl12xx_set_peer_cap,
+ .lnk_high_prio = wl12xx_lnk_high_prio,
+ .lnk_low_prio = wl12xx_lnk_low_prio,
};
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
@@ -1636,11 +1703,13 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
static int wl12xx_setup(struct wl1271 *wl)
{
struct wl12xx_priv *priv = wl->priv;
- struct wl12xx_platform_data *pdata = wl->pdev->dev.platform_data;
+ struct wlcore_platdev_data *pdev_data = wl->pdev->dev.platform_data;
+ struct wl12xx_platform_data *pdata = pdev_data->pdata;
wl->rtable = wl12xx_rtable;
wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS;
wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS;
+ wl->num_channels = 1;
wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES;
wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
@@ -1693,6 +1762,10 @@ static int wl12xx_setup(struct wl1271 *wl)
wl1271_error("Invalid tcxo parameter %s", tcxo_param);
}
+ priv->rx_mem_addr = kmalloc(sizeof(*priv->rx_mem_addr), GFP_KERNEL);
+ if (!priv->rx_mem_addr)
+ return -ENOMEM;
+
return 0;
}
@@ -1703,7 +1776,8 @@ static int wl12xx_probe(struct platform_device *pdev)
int ret;
hw = wlcore_alloc_hw(sizeof(struct wl12xx_priv),
- WL12XX_AGGR_BUFFER_SIZE);
+ WL12XX_AGGR_BUFFER_SIZE,
+ sizeof(struct wl12xx_event_mailbox));
if (IS_ERR(hw)) {
wl1271_error("can't allocate hw");
ret = PTR_ERR(hw);
@@ -1725,6 +1799,21 @@ out:
return ret;
}
+static int wl12xx_remove(struct platform_device *pdev)
+{
+ struct wl1271 *wl = platform_get_drvdata(pdev);
+ struct wl12xx_priv *priv;
+
+ if (!wl)
+ goto out;
+ priv = wl->priv;
+
+ kfree(priv->rx_mem_addr);
+
+out:
+ return wlcore_remove(pdev);
+}
+
static const struct platform_device_id wl12xx_id_table[] = {
{ "wl12xx", 0 },
{ } /* Terminating Entry */
@@ -1733,7 +1822,7 @@ MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
static struct platform_driver wl12xx_driver = {
.probe = wl12xx_probe,
- .remove = wlcore_remove,
+ .remove = wl12xx_remove,
.id_table = wl12xx_id_table,
.driver = {
.name = "wl12xx_driver",
diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c
new file mode 100644
index 000000000000..affdb3ec6225
--- /dev/null
+++ b/drivers/net/wireless/ti/wl12xx/scan.c
@@ -0,0 +1,501 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/ieee80211.h>
+#include "scan.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/tx.h"
+
+static int wl1271_get_scan_channels(struct wl1271 *wl,
+ struct cfg80211_scan_request *req,
+ struct basic_scan_channel_params *channels,
+ enum ieee80211_band band, bool passive)
+{
+ struct conf_scan_settings *c = &wl->conf.scan;
+ int i, j;
+ u32 flags;
+
+ for (i = 0, j = 0;
+ i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
+ i++) {
+ flags = req->channels[i]->flags;
+
+ if (!test_bit(i, wl->scan.scanned_ch) &&
+ !(flags & IEEE80211_CHAN_DISABLED) &&
+ (req->channels[i]->band == band) &&
+ /*
+ * In passive scans, we scan all remaining
+ * channels, even if not marked as such.
+ * In active scans, we only scan channels not
+ * marked as passive.
+ */
+ (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
+ wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
+ req->channels[i]->band,
+ req->channels[i]->center_freq);
+ wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
+ req->channels[i]->hw_value,
+ req->channels[i]->flags);
+ wl1271_debug(DEBUG_SCAN,
+ "max_antenna_gain %d, max_power %d",
+ req->channels[i]->max_antenna_gain,
+ req->channels[i]->max_power);
+ wl1271_debug(DEBUG_SCAN, "beacon_found %d",
+ req->channels[i]->beacon_found);
+
+ if (!passive) {
+ channels[j].min_duration =
+ cpu_to_le32(c->min_dwell_time_active);
+ channels[j].max_duration =
+ cpu_to_le32(c->max_dwell_time_active);
+ } else {
+ channels[j].min_duration =
+ cpu_to_le32(c->dwell_time_passive);
+ channels[j].max_duration =
+ cpu_to_le32(c->dwell_time_passive);
+ }
+ channels[j].early_termination = 0;
+ channels[j].tx_power_att = req->channels[i]->max_power;
+ channels[j].channel = req->channels[i]->hw_value;
+
+ memset(&channels[j].bssid_lsb, 0xff, 4);
+ memset(&channels[j].bssid_msb, 0xff, 2);
+
+ /* Mark the channels we already used */
+ set_bit(i, wl->scan.scanned_ch);
+
+ j++;
+ }
+ }
+
+ return j;
+}
+
+#define WL1271_NOTHING_TO_SCAN 1
+
+static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ enum ieee80211_band band,
+ bool passive, u32 basic_rate)
+{
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+ struct wl1271_cmd_scan *cmd;
+ struct wl1271_cmd_trigger_scan_to *trigger;
+ int ret;
+ u16 scan_options = 0;
+
+ /* skip active scans if we don't have SSIDs */
+ if (!passive && wl->scan.req->n_ssids == 0)
+ return WL1271_NOTHING_TO_SCAN;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+ if (!cmd || !trigger) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (wl->conf.scan.split_scan_timeout)
+ scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN;
+
+ if (passive)
+ scan_options |= WL1271_SCAN_OPT_PASSIVE;
+
+ cmd->params.role_id = wlvif->role_id;
+
+ if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cmd->params.scan_options = cpu_to_le16(scan_options);
+
+ cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
+ cmd->channels,
+ band, passive);
+ if (cmd->params.n_ch == 0) {
+ ret = WL1271_NOTHING_TO_SCAN;
+ goto out;
+ }
+
+ cmd->params.tx_rate = cpu_to_le32(basic_rate);
+ cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
+ cmd->params.tid_trigger = CONF_TX_AC_ANY_TID;
+ cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
+
+ if (band == IEEE80211_BAND_2GHZ)
+ cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
+ else
+ cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
+
+ if (wl->scan.ssid_len && wl->scan.ssid) {
+ cmd->params.ssid_len = wl->scan.ssid_len;
+ memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
+ }
+
+ memcpy(cmd->addr, vif->addr, ETH_ALEN);
+
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ cmd->params.role_id, band,
+ wl->scan.ssid, wl->scan.ssid_len,
+ wl->scan.req->ie,
+ wl->scan.req->ie_len, false);
+ if (ret < 0) {
+ wl1271_error("PROBE request template failed");
+ goto out;
+ }
+
+ trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout);
+ ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+ sizeof(*trigger), 0);
+ if (ret < 0) {
+ wl1271_error("trigger scan to failed for hw scan");
+ goto out;
+ }
+
+ wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+ ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("SCAN failed");
+ goto out;
+ }
+
+out:
+ kfree(cmd);
+ kfree(trigger);
+ return ret;
+}
+
+int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ struct wl1271_cmd_header *cmd = NULL;
+ int ret = 0;
+
+ if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE))
+ return -EINVAL;
+
+ wl1271_debug(DEBUG_CMD, "cmd scan stop");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd,
+ sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("cmd stop_scan failed");
+ goto out;
+ }
+out:
+ kfree(cmd);
+ return ret;
+}
+
+void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ int ret = 0;
+ enum ieee80211_band band;
+ u32 rate, mask;
+
+ switch (wl->scan.state) {
+ case WL1271_SCAN_STATE_IDLE:
+ break;
+
+ case WL1271_SCAN_STATE_2GHZ_ACTIVE:
+ band = IEEE80211_BAND_2GHZ;
+ mask = wlvif->bitrate_masks[band];
+ if (wl->scan.req->no_cck) {
+ mask &= ~CONF_TX_CCK_RATES;
+ if (!mask)
+ mask = CONF_TX_RATE_MASK_BASIC_P2P;
+ }
+ rate = wl1271_tx_min_rate_get(wl, mask);
+ ret = wl1271_scan_send(wl, wlvif, band, false, rate);
+ if (ret == WL1271_NOTHING_TO_SCAN) {
+ wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
+ wl1271_scan_stm(wl, wlvif);
+ }
+
+ break;
+
+ case WL1271_SCAN_STATE_2GHZ_PASSIVE:
+ band = IEEE80211_BAND_2GHZ;
+ mask = wlvif->bitrate_masks[band];
+ if (wl->scan.req->no_cck) {
+ mask &= ~CONF_TX_CCK_RATES;
+ if (!mask)
+ mask = CONF_TX_RATE_MASK_BASIC_P2P;
+ }
+ rate = wl1271_tx_min_rate_get(wl, mask);
+ ret = wl1271_scan_send(wl, wlvif, band, true, rate);
+ if (ret == WL1271_NOTHING_TO_SCAN) {
+ if (wl->enable_11a)
+ wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
+ else
+ wl->scan.state = WL1271_SCAN_STATE_DONE;
+ wl1271_scan_stm(wl, wlvif);
+ }
+
+ break;
+
+ case WL1271_SCAN_STATE_5GHZ_ACTIVE:
+ band = IEEE80211_BAND_5GHZ;
+ rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
+ ret = wl1271_scan_send(wl, wlvif, band, false, rate);
+ if (ret == WL1271_NOTHING_TO_SCAN) {
+ wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
+ wl1271_scan_stm(wl, wlvif);
+ }
+
+ break;
+
+ case WL1271_SCAN_STATE_5GHZ_PASSIVE:
+ band = IEEE80211_BAND_5GHZ;
+ rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
+ ret = wl1271_scan_send(wl, wlvif, band, true, rate);
+ if (ret == WL1271_NOTHING_TO_SCAN) {
+ wl->scan.state = WL1271_SCAN_STATE_DONE;
+ wl1271_scan_stm(wl, wlvif);
+ }
+
+ break;
+
+ case WL1271_SCAN_STATE_DONE:
+ wl->scan.failed = false;
+ cancel_delayed_work(&wl->scan_complete_work);
+ ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+ msecs_to_jiffies(0));
+ break;
+
+ default:
+ wl1271_error("invalid scan state");
+ break;
+ }
+
+ if (ret < 0) {
+ cancel_delayed_work(&wl->scan_complete_work);
+ ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+ msecs_to_jiffies(0));
+ }
+}
+
+static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd,
+ struct wlcore_scan_channels *cmd_channels)
+{
+ memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive));
+ memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active));
+ cmd->dfs = cmd_channels->dfs;
+ cmd->n_pactive_ch = cmd_channels->passive_active;
+
+ memcpy(cmd->channels_2, cmd_channels->channels_2,
+ sizeof(cmd->channels_2));
+ memcpy(cmd->channels_5, cmd_channels->channels_5,
+ sizeof(cmd->channels_2));
+ /* channels_4 are not supported, so no need to copy them */
+}
+
+int wl1271_scan_sched_scan_config(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ struct wl1271_cmd_sched_scan_config *cfg = NULL;
+ struct wlcore_scan_channels *cfg_channels = NULL;
+ struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+ int i, ret;
+ bool force_passive = !req->n_ssids;
+
+ wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
+
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ cfg->role_id = wlvif->role_id;
+ 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);
+
+ cfg->ssid_len = 0;
+ ret = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
+ if (ret < 0)
+ goto out;
+
+ cfg->filter_type = ret;
+
+ wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type);
+
+ cfg_channels = kzalloc(sizeof(*cfg_channels), GFP_KERNEL);
+ if (!cfg_channels) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (!wlcore_set_scan_chan_params(wl, cfg_channels, req->channels,
+ req->n_channels, req->n_ssids,
+ SCAN_TYPE_PERIODIC)) {
+ wl1271_error("scan channel list is empty");
+ ret = -EINVAL;
+ goto out;
+ }
+ wl12xx_adjust_channels(cfg, cfg_channels);
+
+ if (!force_passive && cfg->active[0]) {
+ u8 band = IEEE80211_BAND_2GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ wlvif->role_id, band,
+ req->ssids[0].ssid,
+ req->ssids[0].ssid_len,
+ ies->ie[band],
+ ies->len[band], true);
+ if (ret < 0) {
+ wl1271_error("2.4GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ if (!force_passive && cfg->active[1]) {
+ u8 band = IEEE80211_BAND_5GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ wlvif->role_id, band,
+ req->ssids[0].ssid,
+ req->ssids[0].ssid_len,
+ ies->ie[band],
+ ies->len[band], true);
+ 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_channels);
+ kfree(cfg);
+ return ret;
+}
+
+int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ struct wl1271_cmd_sched_scan_start *start;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
+
+ if (wlvif->bss_type != BSS_TYPE_STA_BSS)
+ return -EOPNOTSUPP;
+
+ if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) &&
+ test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
+ return -EBUSY;
+
+ start = kzalloc(sizeof(*start), GFP_KERNEL);
+ if (!start)
+ return -ENOMEM;
+
+ start->role_id = wlvif->role_id;
+ 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;
+}
+
+int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ int ret;
+
+ ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
+ if (ret < 0)
+ return ret;
+
+ return wl1271_scan_sched_scan_start(wl, wlvif);
+}
+
+void wl12xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ 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->role_id = wlvif->role_id;
+ 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;
+ }
+
+out_free:
+ kfree(stop);
+}
+
+int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_scan_request *req)
+{
+ wl1271_scan_stm(wl, wlvif);
+ return 0;
+}
+
+void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ wl1271_scan_stm(wl, wlvif);
+}
diff --git a/drivers/net/wireless/ti/wl12xx/scan.h b/drivers/net/wireless/ti/wl12xx/scan.h
new file mode 100644
index 000000000000..264af7ac2785
--- /dev/null
+++ b/drivers/net/wireless/ti/wl12xx/scan.h
@@ -0,0 +1,140 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL12XX_SCAN_H__
+#define __WL12XX_SCAN_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/scan.h"
+
+#define WL12XX_MAX_CHANNELS_5GHZ 23
+
+struct basic_scan_params {
+ /* Scan option flags (WL1271_SCAN_OPT_*) */
+ __le16 scan_options;
+ u8 role_id;
+ /* Number of scan channels in the list (maximum 30) */
+ u8 n_ch;
+ /* This field indicates the number of probe requests to send
+ per channel for an active scan */
+ u8 n_probe_reqs;
+ u8 tid_trigger;
+ u8 ssid_len;
+ u8 use_ssid_list;
+
+ /* Rate bit field for sending the probes */
+ __le32 tx_rate;
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ /* Band to scan */
+ u8 band;
+
+ u8 scan_tag;
+ u8 padding2[2];
+} __packed;
+
+struct basic_scan_channel_params {
+ /* Duration in TU to wait for frames on a channel for active scan */
+ __le32 min_duration;
+ __le32 max_duration;
+ __le32 bssid_lsb;
+ __le16 bssid_msb;
+ u8 early_termination;
+ u8 tx_power_att;
+ u8 channel;
+ /* FW internal use only! */
+ u8 dfs_candidate;
+ u8 activity_detected;
+ u8 pad;
+} __packed;
+
+struct wl1271_cmd_scan {
+ struct wl1271_cmd_header header;
+
+ struct basic_scan_params params;
+ struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
+
+ /* src mac address */
+ u8 addr[ETH_ALEN];
+ u8 padding[2];
+} __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[IEEE80211_MAX_SSID_LEN];
+
+ u8 n_probe_reqs; /* Number of probes requests per channel */
+
+ u8 passive[SCAN_MAX_BANDS];
+ u8 active[SCAN_MAX_BANDS];
+
+ u8 dfs;
+
+ u8 n_pactive_ch; /* number of pactive (passive until fw detects energy)
+ channels in BG band */
+ u8 role_id;
+ u8 padding[1];
+ struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+ struct conn_scan_ch_params channels_5[WL12XX_MAX_CHANNELS_5GHZ];
+ struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
+} __packed;
+
+struct wl1271_cmd_sched_scan_start {
+ struct wl1271_cmd_header header;
+
+ u8 tag;
+ u8 role_id;
+ u8 padding[2];
+} __packed;
+
+struct wl1271_cmd_sched_scan_stop {
+ struct wl1271_cmd_header header;
+
+ u8 tag;
+ u8 role_id;
+ u8 padding[2];
+} __packed;
+
+int wl12xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_scan_request *req);
+int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies);
+void wl12xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+#endif
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h
index 7182bbf6625d..d4552857480c 100644
--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
@@ -24,19 +24,37 @@
#include "conf.h"
-/* minimum FW required for driver for wl127x */
+/* WiLink 6/7 chip IDs */
+#define CHIP_ID_127X_PG10 (0x04030101)
+#define CHIP_ID_127X_PG20 (0x04030111)
+#define CHIP_ID_128X_PG10 (0x05030101)
+#define CHIP_ID_128X_PG20 (0x05030111)
+
+/* FW chip version for wl127x */
#define WL127X_CHIP_VER 6
-#define WL127X_IFTYPE_VER 3
-#define WL127X_MAJOR_VER 10
-#define WL127X_SUBTYPE_VER 2
-#define WL127X_MINOR_VER 115
+/* minimum single-role FW version for wl127x */
+#define WL127X_IFTYPE_SR_VER 3
+#define WL127X_MAJOR_SR_VER 10
+#define WL127X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE
+#define WL127X_MINOR_SR_VER 115
+/* minimum multi-role FW version for wl127x */
+#define WL127X_IFTYPE_MR_VER 5
+#define WL127X_MAJOR_MR_VER 7
+#define WL127X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE
+#define WL127X_MINOR_MR_VER 115
-/* minimum FW required for driver for wl128x */
+/* FW chip version for wl128x */
#define WL128X_CHIP_VER 7
-#define WL128X_IFTYPE_VER 3
-#define WL128X_MAJOR_VER 10
-#define WL128X_SUBTYPE_VER 2
-#define WL128X_MINOR_VER 115
+/* minimum single-role FW version for wl128x */
+#define WL128X_IFTYPE_SR_VER 3
+#define WL128X_MAJOR_SR_VER 10
+#define WL128X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE
+#define WL128X_MINOR_SR_VER 115
+/* minimum multi-role FW version for wl128x */
+#define WL128X_IFTYPE_MR_VER 5
+#define WL128X_MAJOR_MR_VER 7
+#define WL128X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE
+#define WL128X_MINOR_MR_VER 42
#define WL12XX_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
@@ -55,6 +73,8 @@ struct wl12xx_priv {
int ref_clock;
int tcxo_clock;
+
+ struct wl127x_rx_mem_pool_addr *rx_mem_addr;
};
#endif /* __WL12XX_PRIV_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/Makefile b/drivers/net/wireless/ti/wl18xx/Makefile
index 67c098734c7f..ae2b81735785 100644
--- a/drivers/net/wireless/ti/wl18xx/Makefile
+++ b/drivers/net/wireless/ti/wl18xx/Makefile
@@ -1,3 +1,3 @@
-wl18xx-objs = main.o acx.o tx.o io.o debugfs.o
+wl18xx-objs = main.o acx.o tx.o io.o debugfs.o scan.o cmd.o event.o
obj-$(CONFIG_WL18XX) += wl18xx.o
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
index 72840e23bf59..a169bb5a5dbf 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.c
+++ b/drivers/net/wireless/ti/wl18xx/acx.c
@@ -75,7 +75,7 @@ int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
- ret = wl1271_cmd_configure(wl, ACX_CHECKSUM_CONFIG, acx, sizeof(*acx));
+ ret = wl1271_cmd_configure(wl, ACX_CSUM_CONFIG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("failed to set Tx checksum state: %d", ret);
goto out;
@@ -109,3 +109,88 @@ out:
kfree(acx);
return ret;
}
+
+int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide)
+{
+ struct wlcore_peer_ht_operation_mode *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d",
+ hlid, wide);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->hlid = hlid;
+ acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ;
+
+ ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx,
+ sizeof(*acx));
+
+ if (ret < 0) {
+ wl1271_warning("acx peer ht operation mode failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+
+}
+
+/*
+ * this command is basically the same as wl1271_acx_ht_capabilities,
+ * with the addition of supported rates. they should be unified in
+ * the next fw api change
+ */
+int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid)
+{
+ struct wlcore_acx_peer_cap *acx;
+ int ret = 0;
+ u32 ht_capabilites = 0;
+
+ wl1271_debug(DEBUG_ACX,
+ "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x",
+ ht_cap->ht_supported, ht_cap->cap, rate_set);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (allow_ht_operation && ht_cap->ht_supported) {
+ /* no need to translate capabilities - use the spec values */
+ ht_capabilites = ht_cap->cap;
+
+ /*
+ * this bit is not employed by the spec but only by FW to
+ * indicate peer HT support
+ */
+ ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
+
+ /* get data from A-MPDU parameters field */
+ acx->ampdu_max_length = ht_cap->ampdu_factor;
+ acx->ampdu_min_spacing = ht_cap->ampdu_density;
+ }
+
+ acx->hlid = hlid;
+ acx->ht_capabilites = cpu_to_le32(ht_capabilites);
+ acx->supported_rates = cpu_to_le32(rate_set);
+
+ ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx ht capabilities setting failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
index e2609a6b7341..0e636def1217 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.h
+++ b/drivers/net/wireless/ti/wl18xx/acx.h
@@ -26,7 +26,13 @@
#include "../wlcore/acx.h"
enum {
- ACX_CLEAR_STATISTICS = 0x0047,
+ ACX_NS_IPV6_FILTER = 0x0050,
+ ACX_PEER_HT_OPERATION_MODE_CFG = 0x0051,
+ ACX_CSUM_CONFIG = 0x0052,
+ ACX_SIM_CONFIG = 0x0053,
+ ACX_CLEAR_STATISTICS = 0x0054,
+ ACX_AUTO_RX_STREAMING = 0x0055,
+ ACX_PEER_CAP = 0x0056
};
/* numbers of bits the length field takes (add 1 for the actual number) */
@@ -278,10 +284,57 @@ struct wl18xx_acx_clear_statistics {
struct acx_header header;
};
+enum wlcore_bandwidth {
+ WLCORE_BANDWIDTH_20MHZ,
+ WLCORE_BANDWIDTH_40MHZ,
+};
+
+struct wlcore_peer_ht_operation_mode {
+ struct acx_header header;
+
+ u8 hlid;
+ u8 bandwidth; /* enum wlcore_bandwidth */
+ u8 padding[2];
+};
+
+/*
+ * ACX_PEER_CAP
+ * this struct is very similar to wl1271_acx_ht_capabilities, with the
+ * addition of supported rates
+ */
+struct wlcore_acx_peer_cap {
+ struct acx_header header;
+
+ /* bitmask of capability bits supported by the peer */
+ __le32 ht_capabilites;
+
+ /* rates supported by the remote peer */
+ __le32 supported_rates;
+
+ /* Indicates to which link these capabilities apply. */
+ u8 hlid;
+
+ /*
+ * This the maximum A-MPDU length supported by the AP. The FW may not
+ * exceed this length when sending A-MPDUs
+ */
+ u8 ampdu_max_length;
+
+ /* This is the minimal spacing required when sending A-MPDUs to the AP*/
+ u8 ampdu_min_spacing;
+
+ u8 padding;
+} __packed;
+
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks,
u32 len_field_size);
int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
int wl18xx_acx_clear_statistics(struct wl1271 *wl);
+int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide);
+int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid);
#endif /* __WL18XX_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c
new file mode 100644
index 000000000000..1d1f6cc7a50a
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/cmd.c
@@ -0,0 +1,80 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You 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 "../wlcore/cmd.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/hw_ops.h"
+
+#include "cmd.h"
+
+int wl18xx_cmd_channel_switch(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct ieee80211_channel_switch *ch_switch)
+{
+ struct wl18xx_cmd_channel_switch *cmd;
+ u32 supported_rates;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "cmd channel switch");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->role_id = wlvif->role_id;
+ cmd->channel = ch_switch->channel->hw_value;
+ cmd->switch_time = ch_switch->count;
+ cmd->stop_tx = ch_switch->block_tx;
+
+ switch (ch_switch->channel->band) {
+ case IEEE80211_BAND_2GHZ:
+ cmd->band = WLCORE_BAND_2_4GHZ;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ cmd->band = WLCORE_BAND_5GHZ;
+ break;
+ default:
+ wl1271_error("invalid channel switch band: %d",
+ ch_switch->channel->band);
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES |
+ wlcore_hw_sta_get_ap_rate_mask(wl, wlvif);
+ if (wlvif->p2p)
+ supported_rates &= ~CONF_TX_CCK_RATES;
+ cmd->local_supported_rates = cpu_to_le32(supported_rates);
+ cmd->channel_type = wlvif->channel_type;
+
+ ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send channel switch command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+out:
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h
new file mode 100644
index 000000000000..6687d10899ac
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/cmd.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL18XX_CMD_H__
+#define __WL18XX_CMD_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/acx.h"
+
+struct wl18xx_cmd_channel_switch {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+
+ /* The new serving channel */
+ u8 channel;
+ /* Relative time of the serving channel switch in TBTT units */
+ u8 switch_time;
+ /* Stop the role TX, should expect it after radar detection */
+ u8 stop_tx;
+
+ __le32 local_supported_rates;
+
+ u8 channel_type;
+ u8 band;
+
+ u8 padding[2];
+} __packed;
+
+int wl18xx_cmd_channel_switch(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct ieee80211_channel_switch *ch_switch);
+
+#endif
diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h
index 4d426cc20274..e34302e3b51d 100644
--- a/drivers/net/wireless/ti/wl18xx/conf.h
+++ b/drivers/net/wireless/ti/wl18xx/conf.h
@@ -23,20 +23,21 @@
#define __WL18XX_CONF_H__
#define WL18XX_CONF_MAGIC 0x10e100ca
-#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0003)
+#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0006)
#define WL18XX_CONF_MASK 0x0000ffff
#define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \
sizeof(struct wl18xx_priv_conf))
#define NUM_OF_CHANNELS_11_ABG 150
#define NUM_OF_CHANNELS_11_P 7
-#define WL18XX_NUM_OF_SUB_BANDS 9
#define SRF_TABLE_LEN 16
#define PIN_MUXING_SIZE 2
+#define WL18XX_TRACE_LOSS_GAPS_TX 10
+#define WL18XX_TRACE_LOSS_GAPS_RX 18
struct wl18xx_mac_and_phy_params {
u8 phy_standalone;
- u8 rdl;
+ u8 spare0;
u8 enable_clpc;
u8 enable_tx_low_pwr_on_siso_rdl;
u8 auto_detect;
@@ -69,18 +70,27 @@ struct wl18xx_mac_and_phy_params {
u8 pwr_limit_reference_11_abg;
u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P];
u8 pwr_limit_reference_11p;
- u8 per_sub_band_tx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
- u8 per_sub_band_rx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
+ u8 spare1;
+ u8 per_chan_bo_mode_11_abg[13];
+ u8 per_chan_bo_mode_11_p[4];
u8 primary_clock_setting_time;
u8 clock_valid_on_wake_up;
u8 secondary_clock_setting_time;
u8 board_type;
/* enable point saturation */
u8 psat;
- /* low/medium/high Tx power in dBm */
+ /* low/medium/high Tx power in dBm for STA-HP BG */
s8 low_power_val;
s8 med_power_val;
s8 high_power_val;
+ s8 per_sub_band_tx_trace_loss[WL18XX_TRACE_LOSS_GAPS_TX];
+ s8 per_sub_band_rx_trace_loss[WL18XX_TRACE_LOSS_GAPS_RX];
+ u8 tx_rf_margin;
+ /* low/medium/high Tx power in dBm for other role */
+ s8 low_power_val_2nd;
+ s8 med_power_val_2nd;
+ s8 high_power_val_2nd;
+
u8 padding[1];
} __packed;
diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c
new file mode 100644
index 000000000000..c9199d7804c6
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/event.c
@@ -0,0 +1,111 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You 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 "event.h"
+#include "scan.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/debug.h"
+
+int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
+ bool *timeout)
+{
+ u32 local_event;
+
+ switch (event) {
+ case WLCORE_EVENT_PEER_REMOVE_COMPLETE:
+ local_event = PEER_REMOVE_COMPLETE_EVENT_ID;
+ break;
+
+ case WLCORE_EVENT_DFS_CONFIG_COMPLETE:
+ local_event = DFS_CHANNELS_CONFIG_COMPLETE_EVENT;
+ break;
+
+ default:
+ /* event not implemented */
+ return 0;
+ }
+ return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout);
+}
+
+int wl18xx_process_mailbox_events(struct wl1271 *wl)
+{
+ struct wl18xx_event_mailbox *mbox = wl->mbox;
+ u32 vector;
+
+ vector = le32_to_cpu(mbox->events_vector);
+ wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector);
+
+ if (vector & SCAN_COMPLETE_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT, "scan results: %d",
+ mbox->number_of_scan_results);
+
+ if (wl->scan_wlvif)
+ wl18xx_scan_completed(wl, wl->scan_wlvif);
+ }
+
+ if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT,
+ "PERIODIC_SCAN_REPORT_EVENT (results %d)",
+ mbox->number_of_sched_scan_results);
+
+ wlcore_scan_sched_scan_results(wl);
+ }
+
+ if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID)
+ wlcore_event_sched_scan_completed(wl, 1);
+
+ if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID)
+ wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric);
+
+ if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)
+ wlcore_event_ba_rx_constraint(wl,
+ le16_to_cpu(mbox->rx_ba_role_id_bitmap),
+ le16_to_cpu(mbox->rx_ba_allowed_bitmap));
+
+ if (vector & BSS_LOSS_EVENT_ID)
+ wlcore_event_beacon_loss(wl,
+ le16_to_cpu(mbox->bss_loss_bitmap));
+
+ if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID)
+ wlcore_event_channel_switch(wl,
+ le16_to_cpu(mbox->channel_switch_role_id_bitmap),
+ true);
+
+ if (vector & DUMMY_PACKET_EVENT_ID)
+ wlcore_event_dummy_packet(wl);
+
+ /*
+ * "TX retries exceeded" has a different meaning according to mode.
+ * In AP mode the offending station is disconnected.
+ */
+ if (vector & MAX_TX_FAILURE_EVENT_ID)
+ wlcore_event_max_tx_failure(wl,
+ le32_to_cpu(mbox->tx_retry_exceeded_bitmap));
+
+ if (vector & INACTIVE_STA_EVENT_ID)
+ wlcore_event_inactive_sta(wl,
+ le32_to_cpu(mbox->inactive_sta_bitmap));
+
+ if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID)
+ wlcore_event_roc_complete(wl);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h
new file mode 100644
index 000000000000..398f3d2c0a6c
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/event.h
@@ -0,0 +1,77 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL18XX_EVENT_H__
+#define __WL18XX_EVENT_H__
+
+#include "../wlcore/wlcore.h"
+
+enum {
+ SCAN_COMPLETE_EVENT_ID = BIT(8),
+ RADAR_DETECTED_EVENT_ID = BIT(9),
+ CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(10),
+ BSS_LOSS_EVENT_ID = BIT(11),
+ MAX_TX_FAILURE_EVENT_ID = BIT(12),
+ DUMMY_PACKET_EVENT_ID = BIT(13),
+ INACTIVE_STA_EVENT_ID = BIT(14),
+ PEER_REMOVE_COMPLETE_EVENT_ID = BIT(15),
+ PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(16),
+ BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(17),
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18),
+ DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19),
+ PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20),
+};
+
+struct wl18xx_event_mailbox {
+ __le32 events_vector;
+
+ u8 number_of_scan_results;
+ u8 number_of_sched_scan_results;
+
+ __le16 channel_switch_role_id_bitmap;
+
+ s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
+
+ /* bitmap of removed links */
+ __le32 hlid_removed_bitmap;
+
+ /* rx ba constraint */
+ __le16 rx_ba_role_id_bitmap; /* 0xfff means any role. */
+ __le16 rx_ba_allowed_bitmap;
+
+ /* bitmap of roc completed (by role id) */
+ __le16 roc_completed_bitmap;
+
+ /* bitmap of stations (by role id) with bss loss */
+ __le16 bss_loss_bitmap;
+
+ /* bitmap of stations (by HLID) which exceeded max tx retries */
+ __le32 tx_retry_exceeded_bitmap;
+
+ /* bitmap of inactive stations (by HLID) */
+ __le32 inactive_sta_bitmap;
+} __packed;
+
+int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
+ bool *timeout);
+int wl18xx_process_mailbox_events(struct wl1271 *wl);
+
+#endif
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 8d8c1f8c63b7..da3ef1b10a9c 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -34,10 +34,13 @@
#include "reg.h"
#include "conf.h"
+#include "cmd.h"
#include "acx.h"
#include "tx.h"
#include "wl18xx.h"
#include "io.h"
+#include "scan.h"
+#include "event.h"
#include "debugfs.h"
#define WL18XX_RX_CHECKSUM_MASK 0x40
@@ -334,6 +337,8 @@ static struct wlcore_conf wl18xx_conf = {
.tmpl_short_retry_limit = 10,
.tmpl_long_retry_limit = 10,
.tx_watchdog_timeout = 5000,
+ .slow_link_thold = 3,
+ .fast_link_thold = 30,
},
.conn = {
.wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
@@ -391,8 +396,10 @@ static struct wlcore_conf wl18xx_conf = {
.scan = {
.min_dwell_time_active = 7500,
.max_dwell_time_active = 30000,
- .min_dwell_time_passive = 100000,
- .max_dwell_time_passive = 100000,
+ .min_dwell_time_active_long = 25000,
+ .max_dwell_time_active_long = 50000,
+ .dwell_time_passive = 100000,
+ .dwell_time_dfs = 150000,
.num_probe_reqs = 2,
.split_scan_timeout = 50000,
},
@@ -489,6 +496,10 @@ static struct wlcore_conf wl18xx_conf = {
.increase_time = 1,
.window_size = 16,
},
+ .recovery = {
+ .bug_on_recovery = 0,
+ .no_recovery = 0,
+ },
};
static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
@@ -501,7 +512,6 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
.clock_valid_on_wake_up = 0x00,
.secondary_clock_setting_time = 0x05,
.board_type = BOARD_TYPE_HDK_18XX,
- .rdl = 0x01,
.auto_detect = 0x00,
.dedicated_fem = FEM_NONE,
.low_band_component = COMPONENT_3_WAY_SWITCH,
@@ -517,14 +527,44 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
.enable_clpc = 0x00,
.enable_tx_low_pwr_on_siso_rdl = 0x00,
.rx_profile = 0x00,
- .pwr_limit_reference_11_abg = 0xc8,
+ .pwr_limit_reference_11_abg = 0x64,
+ .per_chan_pwr_limit_arr_11abg = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ .pwr_limit_reference_11p = 0x64,
+ .per_chan_bo_mode_11_abg = { 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00 },
+ .per_chan_bo_mode_11_p = { 0x00, 0x00, 0x00, 0x00 },
+ .per_chan_pwr_limit_arr_11p = { 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff },
.psat = 0,
- .low_power_val = 0x00,
- .med_power_val = 0x0a,
- .high_power_val = 0x1e,
+ .low_power_val = 0x08,
+ .med_power_val = 0x12,
+ .high_power_val = 0x18,
+ .low_power_val_2nd = 0x05,
+ .med_power_val_2nd = 0x0a,
+ .high_power_val_2nd = 0x14,
.external_pa_dc2dc = 0,
- .number_of_assembled_ant2_4 = 1,
+ .number_of_assembled_ant2_4 = 2,
.number_of_assembled_ant5 = 1,
+ .tx_rf_margin = 1,
},
};
@@ -595,7 +635,7 @@ static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
};
/* TODO: maybe move to a new header file? */
-#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw.bin"
+#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-2.bin"
static int wl18xx_identify_chip(struct wl1271 *wl)
{
@@ -608,15 +648,18 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
wl->sr_fw_name = WL18XX_FW_NAME;
/* wl18xx uses the same firmware for PLT */
wl->plt_fw_name = WL18XX_FW_NAME;
- wl->quirks |= WLCORE_QUIRK_NO_ELP |
- WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
+ wl->quirks |= WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN |
- WLCORE_QUIRK_TX_PAD_LAST_FRAME;
-
- wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, WL18XX_IFTYPE_VER,
- WL18XX_MAJOR_VER, WL18XX_SUBTYPE_VER,
- WL18XX_MINOR_VER);
+ WLCORE_QUIRK_TX_PAD_LAST_FRAME |
+ WLCORE_QUIRK_REGDOMAIN_CONF |
+ WLCORE_QUIRK_DUAL_PROBE_TMPL;
+
+ wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER,
+ WL18XX_IFTYPE_VER, WL18XX_MAJOR_VER,
+ WL18XX_SUBTYPE_VER, WL18XX_MINOR_VER,
+ /* there's no separate multi-role FW */
+ 0, 0, 0, 0);
break;
case CHIP_ID_185x_PG10:
wl1271_warning("chip id 0x%x (185x PG10) is deprecated",
@@ -630,6 +673,11 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
goto out;
}
+ wl->scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
+ wl->scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
+ wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
+ wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
+ wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ;
out:
return ret;
}
@@ -843,6 +891,20 @@ static int wl18xx_boot(struct wl1271 *wl)
if (ret < 0)
goto out;
+ wl->event_mask = BSS_LOSS_EVENT_ID |
+ SCAN_COMPLETE_EVENT_ID |
+ RSSI_SNR_TRIGGER_0_EVENT_ID |
+ PERIODIC_SCAN_COMPLETE_EVENT_ID |
+ PERIODIC_SCAN_REPORT_EVENT_ID |
+ DUMMY_PACKET_EVENT_ID |
+ PEER_REMOVE_COMPLETE_EVENT_ID |
+ BA_SESSION_RX_CONSTRAINT_EVENT_ID |
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
+ INACTIVE_STA_EVENT_ID |
+ MAX_TX_FAILURE_EVENT_ID |
+ CHANNEL_SWITCH_COMPLETE_EVENT_ID |
+ DFS_CHANNELS_CONFIG_COMPLETE_EVENT;
+
ret = wlcore_boot_run_firmware(wl);
if (ret < 0)
goto out;
@@ -964,7 +1026,7 @@ static int wl18xx_hw_init(struct wl1271 *wl)
/* (re)init private structures. Relevant on recovery as well. */
priv->last_fw_rls_idx = 0;
- priv->extra_spare_vif_count = 0;
+ priv->extra_spare_key_count = 0;
/* set the default amount of spare blocks in the bitmap */
ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE);
@@ -1022,7 +1084,12 @@ static bool wl18xx_is_mimo_supported(struct wl1271 *wl)
{
struct wl18xx_priv *priv = wl->priv;
- return priv->conf.phy.number_of_assembled_ant2_4 >= 2;
+ /* only support MIMO with multiple antennas, and when SISO
+ * is not forced through config
+ */
+ return (priv->conf.phy.number_of_assembled_ant2_4 >= 2) &&
+ (priv->conf.ht.mode != HT_MODE_WIDE) &&
+ (priv->conf.ht.mode != HT_MODE_SISO20);
}
/*
@@ -1223,8 +1290,8 @@ static int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
{
struct wl18xx_priv *priv = wl->priv;
- /* If we have VIFs requiring extra spare, indulge them */
- if (priv->extra_spare_vif_count)
+ /* If we have keys requiring extra spare, indulge them */
+ if (priv->extra_spare_key_count)
return WL18XX_TX_HW_EXTRA_BLOCK_SPARE;
return WL18XX_TX_HW_BLOCK_SPARE;
@@ -1236,42 +1303,48 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
struct ieee80211_key_conf *key_conf)
{
struct wl18xx_priv *priv = wl->priv;
- bool change_spare = false;
+ bool change_spare = false, special_enc;
int ret;
+ wl1271_debug(DEBUG_CRYPT, "extra spare keys before: %d",
+ priv->extra_spare_key_count);
+
+ special_enc = key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
+ key_conf->cipher == WLAN_CIPHER_SUITE_TKIP;
+
+ ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
+ if (ret < 0)
+ goto out;
+
/*
- * when adding the first or removing the last GEM/TKIP interface,
+ * when adding the first or removing the last GEM/TKIP key,
* we have to adjust the number of spare blocks.
*/
- change_spare = (key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
- key_conf->cipher == WLAN_CIPHER_SUITE_TKIP) &&
- ((priv->extra_spare_vif_count == 0 && cmd == SET_KEY) ||
- (priv->extra_spare_vif_count == 1 && cmd == DISABLE_KEY));
+ if (special_enc) {
+ if (cmd == SET_KEY) {
+ /* first key */
+ change_spare = (priv->extra_spare_key_count == 0);
+ priv->extra_spare_key_count++;
+ } else if (cmd == DISABLE_KEY) {
+ /* last key */
+ change_spare = (priv->extra_spare_key_count == 1);
+ priv->extra_spare_key_count--;
+ }
+ }
- /* no need to change spare - just regular set_key */
- if (!change_spare)
- return wlcore_set_key(wl, cmd, vif, sta, key_conf);
+ wl1271_debug(DEBUG_CRYPT, "extra spare keys after: %d",
+ priv->extra_spare_key_count);
- ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
- if (ret < 0)
+ if (!change_spare)
goto out;
/* key is now set, change the spare blocks */
- if (cmd == SET_KEY) {
+ if (priv->extra_spare_key_count)
ret = wl18xx_set_host_cfg_bitmap(wl,
WL18XX_TX_HW_EXTRA_BLOCK_SPARE);
- if (ret < 0)
- goto out;
-
- priv->extra_spare_vif_count++;
- } else {
+ else
ret = wl18xx_set_host_cfg_bitmap(wl,
WL18XX_TX_HW_BLOCK_SPARE);
- if (ret < 0)
- goto out;
-
- priv->extra_spare_vif_count--;
- }
out:
return ret;
@@ -1296,6 +1369,92 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
return buf_offset;
}
+static void wl18xx_sta_rc_update(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct ieee80211_sta *sta,
+ u32 changed)
+{
+ bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
+
+ if (!(changed & IEEE80211_RC_BW_CHANGED))
+ return;
+
+ mutex_lock(&wl->mutex);
+
+ /* sanity */
+ if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
+ goto out;
+
+ /* ignore the change before association */
+ if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+ goto out;
+
+ /*
+ * If we started out as wide, we can change the operation mode. If we
+ * thought this was a 20mhz AP, we have to reconnect
+ */
+ if (wlvif->sta.role_chan_type == NL80211_CHAN_HT40MINUS ||
+ wlvif->sta.role_chan_type == NL80211_CHAN_HT40PLUS)
+ wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide);
+ else
+ ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif));
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static int wl18xx_set_peer_cap(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid)
+{
+ return wl18xx_acx_set_peer_cap(wl, ht_cap, allow_ht_operation,
+ rate_set, hlid);
+}
+
+static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ u8 thold;
+ struct wl18xx_fw_status_priv *status_priv =
+ (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+ u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+
+ /* suspended links are never high priority */
+ if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
+ return false;
+
+ /* the priority thresholds are taken from FW */
+ if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) &&
+ !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map))
+ thold = status_priv->tx_fast_link_prio_threshold;
+ else
+ thold = status_priv->tx_slow_link_prio_threshold;
+
+ return lnk->allocated_pkts < thold;
+}
+
+static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ u8 thold;
+ struct wl18xx_fw_status_priv *status_priv =
+ (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+ u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
+
+ if (test_bit(hlid, (unsigned long *)&suspend_bitmap))
+ thold = status_priv->tx_suspend_threshold;
+ else if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) &&
+ !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map))
+ thold = status_priv->tx_fast_stop_threshold;
+ else
+ thold = status_priv->tx_slow_stop_threshold;
+
+ return lnk->allocated_pkts < thold;
+}
+
static int wl18xx_setup(struct wl1271 *wl);
static struct wlcore_ops wl18xx_ops = {
@@ -1305,6 +1464,8 @@ static struct wlcore_ops wl18xx_ops = {
.plt_init = wl18xx_plt_init,
.trigger_cmd = wl18xx_trigger_cmd,
.ack_event = wl18xx_ack_event,
+ .wait_for_event = wl18xx_wait_for_event,
+ .process_mailbox_events = wl18xx_process_mailbox_events,
.calc_tx_blocks = wl18xx_calc_tx_blocks,
.set_tx_desc_blocks = wl18xx_set_tx_desc_blocks,
.set_tx_desc_data_len = wl18xx_set_tx_desc_data_len,
@@ -1320,16 +1481,26 @@ static struct wlcore_ops wl18xx_ops = {
.ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask,
.get_mac = wl18xx_get_mac,
.debugfs_init = wl18xx_debugfs_add_files,
+ .scan_start = wl18xx_scan_start,
+ .scan_stop = wl18xx_scan_stop,
+ .sched_scan_start = wl18xx_sched_scan_start,
+ .sched_scan_stop = wl18xx_scan_sched_scan_stop,
.handle_static_data = wl18xx_handle_static_data,
.get_spare_blocks = wl18xx_get_spare_blocks,
.set_key = wl18xx_set_key,
+ .channel_switch = wl18xx_cmd_channel_switch,
.pre_pkt_send = wl18xx_pre_pkt_send,
+ .sta_rc_update = wl18xx_sta_rc_update,
+ .set_peer_cap = wl18xx_set_peer_cap,
+ .lnk_high_prio = wl18xx_lnk_high_prio,
+ .lnk_low_prio = wl18xx_lnk_low_prio,
};
/* HT cap appropriate for wide channels in 2Ghz */
static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = {
.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
- IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40,
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40 |
+ IEEE80211_HT_CAP_GRN_FLD,
.ht_supported = true,
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
@@ -1343,7 +1514,8 @@ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = {
/* HT cap appropriate for wide channels in 5Ghz */
static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = {
.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
- IEEE80211_HT_CAP_SUP_WIDTH_20_40,
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_GRN_FLD,
.ht_supported = true,
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
@@ -1356,7 +1528,8 @@ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = {
/* HT cap appropriate for SISO 20 */
static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
- .cap = IEEE80211_HT_CAP_SGI_20,
+ .cap = IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_GRN_FLD,
.ht_supported = true,
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
@@ -1369,7 +1542,8 @@ static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
/* HT cap appropriate for MIMO rates in 20mhz channel */
static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {
- .cap = IEEE80211_HT_CAP_SGI_20,
+ .cap = IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_GRN_FLD,
.ht_supported = true,
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
@@ -1387,7 +1561,8 @@ static int wl18xx_setup(struct wl1271 *wl)
wl->rtable = wl18xx_rtable;
wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS;
- wl->num_rx_desc = WL18XX_NUM_TX_DESCRIPTORS;
+ wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS;
+ wl->num_channels = 2;
wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
@@ -1506,7 +1681,8 @@ static int wl18xx_probe(struct platform_device *pdev)
int ret;
hw = wlcore_alloc_hw(sizeof(struct wl18xx_priv),
- WL18XX_AGGR_BUFFER_SIZE);
+ WL18XX_AGGR_BUFFER_SIZE,
+ sizeof(struct wl18xx_event_mailbox));
if (IS_ERR(hw)) {
wl1271_error("can't allocate hw");
ret = PTR_ERR(hw);
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c
new file mode 100644
index 000000000000..09d944505ac0
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/scan.c
@@ -0,0 +1,326 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/ieee80211.h>
+#include "scan.h"
+#include "../wlcore/debug.h"
+
+static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
+ struct wlcore_scan_channels *cmd_channels)
+{
+ memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive));
+ memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active));
+ cmd->dfs = cmd_channels->dfs;
+ cmd->passive_active = cmd_channels->passive_active;
+
+ memcpy(cmd->channels_2, cmd_channels->channels_2,
+ sizeof(cmd->channels_2));
+ memcpy(cmd->channels_5, cmd_channels->channels_5,
+ sizeof(cmd->channels_2));
+ /* channels_4 are not supported, so no need to copy them */
+}
+
+static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_scan_request *req)
+{
+ struct wl18xx_cmd_scan_params *cmd;
+ struct wlcore_scan_channels *cmd_channels = NULL;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->role_id = wlvif->role_id;
+
+ if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cmd->scan_type = SCAN_TYPE_SEARCH;
+ cmd->rssi_threshold = -127;
+ cmd->snr_threshold = 0;
+
+ cmd->bss_type = SCAN_BSS_TYPE_ANY;
+
+ cmd->ssid_from_list = 0;
+ cmd->filter = 0;
+ cmd->add_broadcast = 0;
+
+ cmd->urgency = 0;
+ cmd->protect = 0;
+
+ cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs;
+ cmd->terminate_after = 0;
+
+ /* configure channels */
+ WARN_ON(req->n_ssids > 1);
+
+ cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
+ if (!cmd_channels) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
+ req->n_channels, req->n_ssids,
+ SCAN_TYPE_SEARCH);
+ wl18xx_adjust_channels(cmd, cmd_channels);
+
+ /*
+ * all the cycles params (except total cycles) should
+ * remain 0 for normal scan
+ */
+ cmd->total_cycles = 1;
+
+ if (req->no_cck)
+ cmd->rate = WL18XX_SCAN_RATE_6;
+
+ cmd->tag = WL1271_SCAN_DEFAULT_TAG;
+
+ if (req->n_ssids) {
+ cmd->ssid_len = req->ssids[0].ssid_len;
+ memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len);
+ }
+
+ /* TODO: per-band ies? */
+ if (cmd->active[0]) {
+ u8 band = IEEE80211_BAND_2GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ cmd->role_id, band,
+ req->ssids ? req->ssids[0].ssid : NULL,
+ req->ssids ? req->ssids[0].ssid_len : 0,
+ req->ie,
+ req->ie_len,
+ false);
+ if (ret < 0) {
+ wl1271_error("2.4GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ if (cmd->active[1] || cmd->dfs) {
+ u8 band = IEEE80211_BAND_5GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ cmd->role_id, band,
+ req->ssids ? req->ssids[0].ssid : NULL,
+ req->ssids ? req->ssids[0].ssid_len : 0,
+ req->ie,
+ req->ie_len,
+ false);
+ if (ret < 0) {
+ wl1271_error("5GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+ ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("SCAN failed");
+ goto out;
+ }
+
+out:
+ kfree(cmd_channels);
+ kfree(cmd);
+ return ret;
+}
+
+void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ wl->scan.failed = false;
+ cancel_delayed_work(&wl->scan_complete_work);
+ ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+ msecs_to_jiffies(0));
+}
+
+static
+int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ struct wl18xx_cmd_scan_params *cmd;
+ struct wlcore_scan_channels *cmd_channels = NULL;
+ struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+ int ret;
+ int filter_type;
+
+ wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
+
+ filter_type = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
+ if (filter_type < 0)
+ return filter_type;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->role_id = wlvif->role_id;
+
+ if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cmd->scan_type = SCAN_TYPE_PERIODIC;
+ cmd->rssi_threshold = c->rssi_threshold;
+ cmd->snr_threshold = c->snr_threshold;
+
+ /* don't filter on BSS type */
+ cmd->bss_type = SCAN_BSS_TYPE_ANY;
+
+ cmd->ssid_from_list = 1;
+ if (filter_type == SCAN_SSID_FILTER_LIST)
+ cmd->filter = 1;
+ cmd->add_broadcast = 0;
+
+ cmd->urgency = 0;
+ cmd->protect = 0;
+
+ cmd->n_probe_reqs = c->num_probe_reqs;
+ /* don't stop scanning automatically when something is found */
+ cmd->terminate_after = 0;
+
+ cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
+ if (!cmd_channels) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* configure channels */
+ wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
+ req->n_channels, req->n_ssids,
+ SCAN_TYPE_PERIODIC);
+ wl18xx_adjust_channels(cmd, cmd_channels);
+
+ cmd->short_cycles_sec = 0;
+ cmd->long_cycles_sec = cpu_to_le16(req->interval);
+ cmd->short_cycles_count = 0;
+
+ cmd->total_cycles = 0;
+
+ cmd->tag = WL1271_SCAN_DEFAULT_TAG;
+
+ /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */
+ cmd->report_threshold = 1;
+ cmd->terminate_on_report = 0;
+
+ if (cmd->active[0]) {
+ u8 band = IEEE80211_BAND_2GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ cmd->role_id, band,
+ req->ssids ? req->ssids[0].ssid : NULL,
+ req->ssids ? req->ssids[0].ssid_len : 0,
+ ies->ie[band],
+ ies->len[band],
+ true);
+ if (ret < 0) {
+ wl1271_error("2.4GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ if (cmd->active[1] || cmd->dfs) {
+ u8 band = IEEE80211_BAND_5GHZ;
+ ret = wl12xx_cmd_build_probe_req(wl, wlvif,
+ cmd->role_id, band,
+ req->ssids ? req->ssids[0].ssid : NULL,
+ req->ssids ? req->ssids[0].ssid_len : 0,
+ ies->ie[band],
+ ies->len[band],
+ true);
+ if (ret < 0) {
+ wl1271_error("5GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+
+ ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("SCAN failed");
+ goto out;
+ }
+
+out:
+ kfree(cmd_channels);
+ kfree(cmd);
+ return ret;
+}
+
+int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies);
+}
+
+static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 scan_type)
+{
+ struct wl18xx_cmd_scan_stop *stop;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
+
+ stop = kzalloc(sizeof(*stop), GFP_KERNEL);
+ if (!stop) {
+ wl1271_error("failed to alloc memory to send sched scan stop");
+ return -ENOMEM;
+ }
+
+ stop->role_id = wlvif->role_id;
+ stop->scan_type = scan_type;
+
+ ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send sched scan stop command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(stop);
+ return ret;
+}
+
+void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC);
+}
+int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_scan_request *req)
+{
+ return wl18xx_scan_send(wl, wlvif, req);
+}
+
+int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH);
+}
diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h
new file mode 100644
index 000000000000..eadee42689d1
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/scan.h
@@ -0,0 +1,127 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL18XX_SCAN_H__
+#define __WL18XX_SCAN_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/scan.h"
+
+struct tracking_ch_params {
+ struct conn_scan_ch_params channel;
+
+ __le32 bssid_lsb;
+ __le16 bssid_msb;
+
+ u8 padding[2];
+} __packed;
+
+/* probe request rate */
+enum
+{
+ WL18XX_SCAN_RATE_1 = 0,
+ WL18XX_SCAN_RATE_5_5 = 1,
+ WL18XX_SCAN_RATE_6 = 2,
+};
+
+#define WL18XX_MAX_CHANNELS_5GHZ 32
+
+struct wl18xx_cmd_scan_params {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 scan_type;
+
+ s8 rssi_threshold; /* for filtering (in dBm) */
+ s8 snr_threshold; /* for filtering (in dB) */
+
+ u8 bss_type; /* for filtering */
+ u8 ssid_from_list; /* use ssid from configured ssid list */
+ u8 filter; /* forward only results with matching ssids */
+
+ /*
+ * add broadcast ssid in addition to the configured ssids.
+ * the driver should add dummy entry for it (?).
+ */
+ u8 add_broadcast;
+
+ u8 urgency;
+ u8 protect; /* ??? */
+ u8 n_probe_reqs; /* Number of probes requests per channel */
+ u8 terminate_after; /* early terminate scan operation */
+
+ u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */
+ u8 active[SCAN_MAX_BANDS]; /* number of active scan channels */
+ u8 dfs; /* number of dfs channels in 5ghz */
+ u8 passive_active; /* number of passive before active channels 2.4ghz */
+
+ __le16 short_cycles_sec;
+ __le16 long_cycles_sec;
+ u8 short_cycles_count;
+ u8 total_cycles; /* 0 - infinite */
+ u8 padding[2];
+
+ union {
+ struct {
+ struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+ struct conn_scan_ch_params channels_5[WL18XX_MAX_CHANNELS_5GHZ];
+ struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
+ };
+ struct tracking_ch_params channels_tracking[WL1271_SCAN_MAX_CHANNELS];
+ } ;
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */
+ u8 tag;
+ u8 rate;
+
+ /* send SCAN_REPORT_EVENT in periodic scans after each cycle
+ * if number of results >= report_threshold. Must be 0 for
+ * non periodic scans
+ */
+ u8 report_threshold;
+
+ /* Should periodic scan stop after a report event was created.
+ * Must be 0 for non periodic scans.
+ */
+ u8 terminate_on_report;
+
+ u8 padding1[3];
+} __packed;
+
+struct wl18xx_cmd_scan_stop {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 scan_type;
+ u8 padding[2];
+} __packed;
+
+int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_scan_request *req);
+int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies);
+void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+#endif
diff --git a/drivers/net/wireless/ti/wl18xx/tx.c b/drivers/net/wireless/ti/wl18xx/tx.c
index 5b1fb10d9fd7..57c694396647 100644
--- a/drivers/net/wireless/ti/wl18xx/tx.c
+++ b/drivers/net/wireless/ti/wl18xx/tx.c
@@ -28,6 +28,49 @@
#include "wl18xx.h"
#include "tx.h"
+static
+void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif,
+ struct ieee80211_tx_rate *rate)
+{
+ u8 fw_rate = wl->fw_status_2->counters.tx_last_rate;
+
+ if (fw_rate > CONF_HW_RATE_INDEX_MAX) {
+ wl1271_error("last Tx rate invalid: %d", fw_rate);
+ rate->idx = 0;
+ rate->flags = 0;
+ return;
+ }
+
+ if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) {
+ rate->idx = fw_rate;
+ rate->flags = 0;
+ } else {
+ rate->flags = IEEE80211_TX_RC_MCS;
+ rate->idx = fw_rate - CONF_HW_RATE_INDEX_MCS0;
+
+ /* SGI modifier is counted as a separate rate */
+ if (fw_rate >= CONF_HW_RATE_INDEX_MCS7_SGI)
+ (rate->idx)--;
+ if (fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI)
+ (rate->idx)--;
+
+ /* this also covers the 40Mhz SGI case (= MCS15) */
+ if (fw_rate == CONF_HW_RATE_INDEX_MCS7_SGI ||
+ fw_rate == CONF_HW_RATE_INDEX_MCS15_SGI)
+ rate->flags |= IEEE80211_TX_RC_SHORT_GI;
+
+ if (fw_rate > CONF_HW_RATE_INDEX_MCS7_SGI && vif) {
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
+ wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
+ /* adjustment needed for range 0-7 */
+ rate->idx -= 8;
+ rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ }
+ }
+ }
+}
+
static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
{
struct ieee80211_tx_info *info;
@@ -44,7 +87,6 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
/* a zero bit indicates Tx success */
tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX));
-
skb = wl->tx_frames[id];
info = IEEE80211_SKB_CB(skb);
@@ -56,11 +98,13 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
/* update the TX status info */
if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_ACK;
+ /*
+ * first pass info->control.vif while it's valid, and then fill out
+ * the info->status structures
+ */
+ wl18xx_get_last_tx_rate(wl, info->control.vif, &info->status.rates[0]);
- /* no real data about Tx completion */
- info->status.rates[0].idx = -1;
- info->status.rates[0].count = 0;
- info->status.rates[0].flags = 0;
+ info->status.rates[0].count = 1; /* no data about retries */
info->status.ack_signal = -1;
if (!tx_success)
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
index 96a1e438d677..b6739e79efcf 100644
--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -26,10 +26,10 @@
/* minimum FW required for driver */
#define WL18XX_CHIP_VER 8
-#define WL18XX_IFTYPE_VER 2
-#define WL18XX_MAJOR_VER 0
-#define WL18XX_SUBTYPE_VER 0
-#define WL18XX_MINOR_VER 100
+#define WL18XX_IFTYPE_VER 5
+#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
+#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE
+#define WL18XX_MINOR_VER 28
#define WL18XX_CMD_MAX_SIZE 740
@@ -49,8 +49,8 @@ struct wl18xx_priv {
/* Index of last released Tx desc in FW */
u8 last_fw_rls_idx;
- /* number of VIFs requiring extra spare mem-blocks */
- int extra_spare_vif_count;
+ /* number of keys requiring extra spare mem-blocks */
+ int extra_spare_key_count;
};
#define WL18XX_FW_MAX_TX_STATUS_DESC 33
@@ -68,7 +68,43 @@ struct wl18xx_fw_status_priv {
*/
u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC];
- u8 padding[2];
+ /* A bitmap representing the currently suspended links. The suspend
+ * is short lived, for multi-channel Tx requirements.
+ */
+ __le32 link_suspend_bitmap;
+
+ /* packet threshold for an "almost empty" AC,
+ * for Tx schedulng purposes
+ */
+ u8 tx_ac_threshold;
+
+ /* number of packets to queue up for a link in PS */
+ u8 tx_ps_threshold;
+
+ /* number of packet to queue up for a suspended link */
+ u8 tx_suspend_threshold;
+
+ /* Should have less than this number of packets in queue of a slow
+ * link to qualify as high priority link
+ */
+ u8 tx_slow_link_prio_threshold;
+
+ /* Should have less than this number of packets in queue of a fast
+ * link to qualify as high priority link
+ */
+ u8 tx_fast_link_prio_threshold;
+
+ /* Should have less than this number of packets in queue of a slow
+ * link before we stop queuing up packets for it.
+ */
+ u8 tx_slow_stop_threshold;
+
+ /* Should have less than this number of packets in queue of a fast
+ * link before we stop queuing up packets for it.
+ */
+ u8 tx_fast_stop_threshold;
+
+ u8 padding[3];
};
#define WL18XX_PHY_VERSION_MAX_LEN 20
diff --git a/drivers/net/wireless/ti/wlcore/Kconfig b/drivers/net/wireless/ti/wlcore/Kconfig
index d7b907e67170..2b832825c3d4 100644
--- a/drivers/net/wireless/ti/wlcore/Kconfig
+++ b/drivers/net/wireless/ti/wlcore/Kconfig
@@ -33,8 +33,3 @@ config WLCORE_SDIO
If you choose to build a module, it'll be called wlcore_sdio.
Say N if unsure.
-
-config WL12XX_PLATFORM_DATA
- bool
- depends on WLCORE_SDIO != n || WL1251_SDIO != n
- default y
diff --git a/drivers/net/wireless/ti/wlcore/Makefile b/drivers/net/wireless/ti/wlcore/Makefile
index d9fba9e32130..b21398f6c3ec 100644
--- a/drivers/net/wireless/ti/wlcore/Makefile
+++ b/drivers/net/wireless/ti/wlcore/Makefile
@@ -9,7 +9,4 @@ obj-$(CONFIG_WLCORE) += wlcore.o
obj-$(CONFIG_WLCORE_SPI) += wlcore_spi.o
obj-$(CONFIG_WLCORE_SDIO) += wlcore_sdio.o
-# small builtin driver bit
-obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o
-
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index ce108a736bd0..c79654323396 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -1340,6 +1340,8 @@ out:
kfree(acx);
return ret;
}
+EXPORT_SYMBOL_GPL(wl1271_acx_set_ht_capabilities);
+
int wl1271_acx_set_ht_information(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
@@ -1433,13 +1435,22 @@ int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
acx->win_size = wl->conf.ht.rx_ba_win_size;
acx->ssn = ssn;
- ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx,
- sizeof(*acx));
+ ret = wlcore_cmd_configure_failsafe(wl, ACX_BA_SESSION_RX_SETUP, acx,
+ sizeof(*acx),
+ BIT(CMD_STATUS_NO_RX_BA_SESSION));
if (ret < 0) {
wl1271_warning("acx ba receiver session failed: %d", ret);
goto out;
}
+ /* sometimes we can't start the session */
+ if (ret == CMD_STATUS_NO_RX_BA_SESSION) {
+ wl1271_warning("no fw rx ba on tid %d", tid_index);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = 0;
out:
kfree(acx);
return ret;
diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h
index d03215d6b3bd..126536c6a393 100644
--- a/drivers/net/wireless/ti/wlcore/acx.h
+++ b/drivers/net/wireless/ti/wlcore/acx.h
@@ -1025,7 +1025,6 @@ enum {
ACX_CONFIG_HANGOVER = 0x0042,
ACX_FEATURE_CFG = 0x0043,
ACX_PROTECTION_CFG = 0x0044,
- ACX_CHECKSUM_CONFIG = 0x0045,
};
diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c
index 375ea574eafb..77752b03f189 100644
--- a/drivers/net/wireless/ti/wlcore/boot.c
+++ b/drivers/net/wireless/ti/wlcore/boot.c
@@ -84,47 +84,57 @@ out:
static int wlcore_validate_fw_ver(struct wl1271 *wl)
{
unsigned int *fw_ver = wl->chip.fw_ver;
- unsigned int *min_ver = wl->min_fw_ver;
+ unsigned int *min_ver = (wl->fw_type == WL12XX_FW_TYPE_MULTI) ?
+ wl->min_mr_fw_ver : wl->min_sr_fw_ver;
+ char min_fw_str[32] = "";
+ int i;
/* the chip must be exactly equal */
- if (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP])
+ if ((min_ver[FW_VER_CHIP] != WLCORE_FW_VER_IGNORE) &&
+ (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP]))
goto fail;
- /* always check the next digit if all previous ones are equal */
-
- if (min_ver[FW_VER_IF_TYPE] < fw_ver[FW_VER_IF_TYPE])
- goto out;
- else if (min_ver[FW_VER_IF_TYPE] > fw_ver[FW_VER_IF_TYPE])
+ /* the firmware type must be equal */
+ if ((min_ver[FW_VER_IF_TYPE] != WLCORE_FW_VER_IGNORE) &&
+ (min_ver[FW_VER_IF_TYPE] != fw_ver[FW_VER_IF_TYPE]))
goto fail;
- if (min_ver[FW_VER_MAJOR] < fw_ver[FW_VER_MAJOR])
- goto out;
- else if (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR])
+ /* the project number must be equal */
+ if ((min_ver[FW_VER_SUBTYPE] != WLCORE_FW_VER_IGNORE) &&
+ (min_ver[FW_VER_SUBTYPE] != fw_ver[FW_VER_SUBTYPE]))
goto fail;
- if (min_ver[FW_VER_SUBTYPE] < fw_ver[FW_VER_SUBTYPE])
- goto out;
- else if (min_ver[FW_VER_SUBTYPE] > fw_ver[FW_VER_SUBTYPE])
+ /* the API version must be greater or equal */
+ if ((min_ver[FW_VER_MAJOR] != WLCORE_FW_VER_IGNORE) &&
+ (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR]))
goto fail;
- if (min_ver[FW_VER_MINOR] < fw_ver[FW_VER_MINOR])
- goto out;
- else if (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR])
+ /* if the API version is equal... */
+ if (((min_ver[FW_VER_MAJOR] == WLCORE_FW_VER_IGNORE) ||
+ (min_ver[FW_VER_MAJOR] == fw_ver[FW_VER_MAJOR])) &&
+ /* ...the minor must be greater or equal */
+ ((min_ver[FW_VER_MINOR] != WLCORE_FW_VER_IGNORE) &&
+ (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR])))
goto fail;
-out:
return 0;
fail:
- wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is outdated.\n"
- "Please use at least FW %u.%u.%u.%u.%u.\n"
- "You can get more information at:\n"
- "http://wireless.kernel.org/en/users/Drivers/wl12xx",
+ for (i = 0; i < NUM_FW_VER; i++)
+ if (min_ver[i] == WLCORE_FW_VER_IGNORE)
+ snprintf(min_fw_str, sizeof(min_fw_str),
+ "%s*.", min_fw_str);
+ else
+ snprintf(min_fw_str, sizeof(min_fw_str),
+ "%s%u.", min_fw_str, min_ver[i]);
+
+ wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is invalid.\n"
+ "Please use at least FW %s\n"
+ "You can get the latest firmwares at:\n"
+ "git://github.com/TI-OpenLink/firmwares.git",
fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE],
fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE],
- fw_ver[FW_VER_MINOR], min_ver[FW_VER_CHIP],
- min_ver[FW_VER_IF_TYPE], min_ver[FW_VER_MAJOR],
- min_ver[FW_VER_SUBTYPE], min_ver[FW_VER_MINOR]);
+ fw_ver[FW_VER_MINOR], min_fw_str);
return -EINVAL;
}
@@ -491,7 +501,7 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
if (ret < 0)
return ret;
- wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
+ wl->mbox_ptr[1] = wl->mbox_ptr[0] + wl->mbox_size;
wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
wl->mbox_ptr[0], wl->mbox_ptr[1]);
@@ -508,23 +518,6 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
*/
/* unmask required mbox events */
- wl->event_mask = BSS_LOSE_EVENT_ID |
- REGAINED_BSS_EVENT_ID |
- SCAN_COMPLETE_EVENT_ID |
- ROLE_STOP_COMPLETE_EVENT_ID |
- RSSI_SNR_TRIGGER_0_EVENT_ID |
- PSPOLL_DELIVERY_FAILURE_EVENT_ID |
- SOFT_GEMINI_SENSE_EVENT_ID |
- PERIODIC_SCAN_REPORT_EVENT_ID |
- PERIODIC_SCAN_COMPLETE_EVENT_ID |
- DUMMY_PACKET_EVENT_ID |
- PEER_REMOVE_COMPLETE_EVENT_ID |
- BA_SESSION_RX_CONSTRAINT_EVENT_ID |
- REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
- INACTIVE_STA_EVENT_ID |
- MAX_TX_RETRY_EVENT_ID |
- CHANNEL_SWITCH_COMPLETE_EVENT_ID;
-
ret = wl1271_event_unmask(wl);
if (ret < 0) {
wl1271_error("EVENT mask setting failed");
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 27f83f72a93b..6331f9e1cb39 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -48,14 +48,15 @@
* @id: command id
* @buf: buffer containing the command, must work with dma
* @len: length of the buffer
+ * return the cmd status code on success.
*/
-int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
- size_t res_len)
+static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf,
+ size_t len, size_t res_len)
{
struct wl1271_cmd_header *cmd;
unsigned long timeout;
u32 intr;
- int ret = 0;
+ int ret;
u16 status;
u16 poll_count = 0;
@@ -71,7 +72,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false);
if (ret < 0)
- goto fail;
+ return ret;
/*
* TODO: we just need this because one bit is in a different
@@ -79,19 +80,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
*/
ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len);
if (ret < 0)
- goto fail;
+ return ret;
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
if (ret < 0)
- goto fail;
+ return ret;
while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout");
- ret = -ETIMEDOUT;
- goto fail;
+ return -ETIMEDOUT;
}
poll_count++;
@@ -102,7 +102,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
if (ret < 0)
- goto fail;
+ return ret;
}
/* read back the status code of the command */
@@ -111,33 +111,66 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false);
if (ret < 0)
- goto fail;
+ return ret;
status = le16_to_cpu(cmd->status);
- if (status != CMD_STATUS_SUCCESS) {
- wl1271_error("command execute failure %d", status);
- ret = -EIO;
- goto fail;
- }
ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
if (ret < 0)
+ return ret;
+
+ return status;
+}
+
+/*
+ * send command to fw and return cmd status on success
+ * valid_rets contains a bitmap of allowed error codes
+ */
+int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len,
+ size_t res_len, unsigned long valid_rets)
+{
+ int ret = __wlcore_cmd_send(wl, id, buf, len, res_len);
+
+ if (ret < 0)
goto fail;
- return 0;
+ /* success is always a valid status */
+ valid_rets |= BIT(CMD_STATUS_SUCCESS);
+ if (ret >= MAX_COMMAND_STATUS ||
+ !test_bit(ret, &valid_rets)) {
+ wl1271_error("command execute failure %d", ret);
+ ret = -EIO;
+ goto fail;
+ }
+ return ret;
fail:
wl12xx_queue_recovery_work(wl);
return ret;
}
+EXPORT_SYMBOL_GPL(wl1271_cmd_send);
+
+/*
+ * wrapper for wlcore_cmd_send that accept only CMD_STATUS_SUCCESS
+ * return 0 on success.
+ */
+int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
+ size_t res_len)
+{
+ int ret = wlcore_cmd_send_failsafe(wl, id, buf, len, res_len, 0);
+
+ if (ret < 0)
+ return ret;
+ return 0;
+}
/*
* Poll the mailbox event field until any of the bits in the mask is set or a
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
*/
-static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
- u32 mask, bool *timeout)
+int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
+ u32 mask, bool *timeout)
{
u32 *events_vector;
u32 event;
@@ -187,20 +220,7 @@ out:
kfree(events_vector);
return ret;
}
-
-static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
-{
- int ret;
- bool timeout = false;
-
- ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout);
- if (ret != 0 || timeout) {
- wl12xx_queue_recovery_work(wl);
- return ret;
- }
-
- return 0;
-}
+EXPORT_SYMBOL_GPL(wlcore_cmd_wait_for_event_or_timeout);
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
u8 *role_id)
@@ -278,6 +298,16 @@ out:
return ret;
}
+static int wlcore_get_new_session_id(struct wl1271 *wl, u8 hlid)
+{
+ if (wl->session_ids[hlid] >= SESSION_COUNTER_MAX)
+ wl->session_ids[hlid] = 0;
+
+ wl->session_ids[hlid]++;
+
+ return wl->session_ids[hlid];
+}
+
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
{
unsigned long flags;
@@ -285,12 +315,21 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
if (link >= WL12XX_MAX_LINKS)
return -EBUSY;
+ wl->session_ids[link] = wlcore_get_new_session_id(wl, link);
+
/* these bits are used by op_tx */
spin_lock_irqsave(&wl->wl_lock, flags);
__set_bit(link, wl->links_map);
__set_bit(link, wlvif->links_map);
spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ /* take the last "freed packets" value from the current FW status */
+ wl->links[link].prev_freed_pkts =
+ wl->fw_status_2->counters.tx_lnk_free_pkts[link];
+ wl->links[link].wlvif = wlvif;
*hlid = link;
+
+ wl->active_link_count++;
return 0;
}
@@ -307,24 +346,21 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
__clear_bit(*hlid, wlvif->links_map);
spin_unlock_irqrestore(&wl->wl_lock, flags);
+ wl->links[*hlid].allocated_pkts = 0;
+ wl->links[*hlid].prev_freed_pkts = 0;
+ wl->links[*hlid].ba_bitmap = 0;
+ memset(wl->links[*hlid].addr, 0, ETH_ALEN);
+
/*
* At this point op_tx() will not add more packets to the queues. We
* can purge them.
*/
wl1271_tx_reset_link_queues(wl, *hlid);
+ wl->links[*hlid].wlvif = NULL;
*hlid = WL12XX_INVALID_LINK_ID;
-}
-
-static int wl12xx_get_new_session_id(struct wl1271 *wl,
- struct wl12xx_vif *wlvif)
-{
- if (wlvif->session_counter >= SESSION_COUNTER_MAX)
- wlvif->session_counter = 0;
-
- wlvif->session_counter++;
-
- return wlvif->session_counter;
+ wl->active_link_count--;
+ WARN_ON_ONCE(wl->active_link_count < 0);
}
static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
@@ -345,7 +381,9 @@ static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
}
static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
- struct wl12xx_vif *wlvif)
+ struct wl12xx_vif *wlvif,
+ enum ieee80211_band band,
+ int channel)
{
struct wl12xx_cmd_role_start *cmd;
int ret;
@@ -359,9 +397,9 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id);
cmd->role_id = wlvif->dev_role_id;
- if (wlvif->band == IEEE80211_BAND_5GHZ)
+ if (band == IEEE80211_BAND_5GHZ)
cmd->band = WLCORE_BAND_5GHZ;
- cmd->channel = wlvif->channel;
+ cmd->channel = channel;
if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) {
ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid);
@@ -369,7 +407,7 @@ static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
goto out_free;
}
cmd->device.hlid = wlvif->dev_hlid;
- cmd->device.session = wl12xx_get_new_session_id(wl, wlvif);
+ cmd->device.session = wl->session_ids[wlvif->dev_hlid];
wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d",
cmd->role_id, cmd->device.hlid, cmd->device.session);
@@ -420,12 +458,6 @@ static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl,
goto out_free;
}
- ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID);
- if (ret < 0) {
- wl1271_error("cmd role stop dev event completion error");
- goto out_free;
- }
-
wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid);
out_free:
@@ -439,6 +471,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
struct wl12xx_cmd_role_start *cmd;
+ u32 supported_rates;
int ret;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -459,7 +492,14 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
cmd->sta.ssid_len = wlvif->ssid_len;
memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len);
memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN);
- cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
+
+ supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES |
+ wlcore_hw_sta_get_ap_rate_mask(wl, wlvif);
+ if (wlvif->p2p)
+ supported_rates &= ~CONF_TX_CCK_RATES;
+
+ cmd->sta.local_rates = cpu_to_le32(supported_rates);
+
cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
@@ -468,8 +508,14 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
goto out_free;
}
cmd->sta.hlid = wlvif->sta.hlid;
- cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif);
- cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set);
+ cmd->sta.session = wl->session_ids[wlvif->sta.hlid];
+ /*
+ * We don't have the correct remote rates in this stage. The
+ * rates will be reconfigured later, after association, if the
+ * firmware supports ACX_PEER_CAP. Otherwise, there's nothing
+ * we can do, so use all supported_rates here.
+ */
+ cmd->sta.remote_rates = cpu_to_le32(supported_rates);
wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
"basic_rate_set: 0x%x, remote_rates: 0x%x",
@@ -482,6 +528,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
goto err_hlid;
}
+ wlvif->sta.role_chan_type = wlvif->channel_type;
goto out_free;
err_hlid:
@@ -500,7 +547,6 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
struct wl12xx_cmd_role_stop *cmd;
int ret;
- bool timeout = false;
if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID))
return -EINVAL;
@@ -523,17 +569,6 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
goto out_free;
}
- /*
- * Sometimes the firmware doesn't send this event, so we just
- * time out without failing. Queue recovery for other
- * failures.
- */
- ret = wl1271_cmd_wait_for_event_or_timeout(wl,
- ROLE_STOP_COMPLETE_EVENT_ID,
- &timeout);
- if (ret)
- wl12xx_queue_recovery_work(wl);
-
wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid);
out_free:
@@ -579,12 +614,15 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
cmd->ap.global_hlid = wlvif->ap.global_hlid;
cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid;
+ cmd->ap.global_session_id = wl->session_ids[wlvif->ap.global_hlid];
+ cmd->ap.bcast_session_id = wl->session_ids[wlvif->ap.bcast_hlid];
cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set);
cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int);
cmd->ap.dtim_interval = bss_conf->dtim_period;
cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
/* FIXME: Change when adding DFS */
cmd->ap.reset_tsf = 1; /* By default reset AP TSF */
+ cmd->ap.wmm = wlvif->wmm_enabled;
cmd->channel = wlvif->channel;
cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
@@ -599,8 +637,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
}
- supported_rates = CONF_TX_AP_ENABLED_RATES | CONF_TX_MCS_RATES |
+ supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES |
wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
+ if (wlvif->p2p)
+ supported_rates &= ~CONF_TX_CCK_RATES;
wl1271_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x",
supported_rates);
@@ -799,8 +839,11 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
* @id: acx id
* @buf: buffer containing acx, including all headers, must work with dma
* @len: length of buf
+ * @valid_rets: bitmap of valid cmd status codes (i.e. return values).
+ * return the cmd status on success.
*/
-int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
+int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf,
+ size_t len, unsigned long valid_rets)
{
struct acx_header *acx = buf;
int ret;
@@ -812,12 +855,26 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
/* payload length, does not include any headers */
acx->len = cpu_to_le16(len - sizeof(*acx));
- ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0);
+ ret = wlcore_cmd_send_failsafe(wl, CMD_CONFIGURE, acx, len, 0,
+ valid_rets);
if (ret < 0) {
wl1271_warning("CONFIGURE command NOK");
return ret;
}
+ return ret;
+}
+
+/*
+ * wrapper for wlcore_cmd_configure that accepts only success status.
+ * return 0 on success
+ */
+int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
+{
+ int ret = wlcore_cmd_configure_failsafe(wl, id, buf, len, 0);
+
+ if (ret < 0)
+ return ret;
return 0;
}
EXPORT_SYMBOL_GPL(wl1271_cmd_configure);
@@ -1034,8 +1091,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct sk_buff *skb;
int ret;
u32 rate;
- u16 template_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
- u16 template_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
+ u16 template_id_2_4 = wl->scan_templ_id_2_4;
+ u16 template_id_5 = wl->scan_templ_id_5;
skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len,
ie_len);
@@ -1048,10 +1105,10 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
- if (!sched_scan &&
+ if (sched_scan &&
(wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) {
- template_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4;
- template_id_5 = CMD_TEMPL_APP_PROBE_REQ_5;
+ template_id_2_4 = wl->sched_scan_templ_id_2_4;
+ template_id_5 = wl->sched_scan_templ_id_5;
}
rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
@@ -1068,6 +1125,7 @@ out:
dev_kfree_skb(skb);
return ret;
}
+EXPORT_SYMBOL_GPL(wl12xx_cmd_build_probe_req);
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
@@ -1379,7 +1437,8 @@ out:
return ret;
}
-int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid)
+int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 hlid)
{
struct wl12xx_cmd_set_peer_state *cmd;
int ret = 0;
@@ -1395,6 +1454,10 @@ int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid)
cmd->hlid = hlid;
cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
+ /* wmm param is valid only for station role */
+ if (wlvif->bss_type == BSS_TYPE_STA_BSS)
+ cmd->wmm = wlvif->wmm_enabled;
+
ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send set peer state command");
@@ -1429,6 +1492,7 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
cmd->hlid = hlid;
cmd->sp_len = sta->max_sp;
cmd->wmm = sta->wme ? 1 : 0;
+ cmd->session_id = wl->session_ids[hlid];
for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
if (sta->wme && (sta->uapsd_queues & BIT(i)))
@@ -1490,9 +1554,10 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
goto out_free;
}
- ret = wl1271_cmd_wait_for_event_or_timeout(wl,
- PEER_REMOVE_COMPLETE_EVENT_ID,
- &timeout);
+ ret = wl->ops->wait_for_event(wl,
+ WLCORE_EVENT_PEER_REMOVE_COMPLETE,
+ &timeout);
+
/*
* We are ok with a timeout here. The event is sometimes not sent
* due to a firmware bug. In case of another error (like SDIO timeout)
@@ -1508,6 +1573,131 @@ out:
return ret;
}
+static int wlcore_get_reg_conf_ch_idx(enum ieee80211_band band, u16 ch)
+{
+ int idx = -1;
+
+ switch (band) {
+ case IEEE80211_BAND_5GHZ:
+ if (ch >= 8 && ch <= 16)
+ idx = ((ch-8)/4 + 18);
+ else if (ch >= 34 && ch <= 64)
+ idx = ((ch-34)/2 + 3 + 18);
+ else if (ch >= 100 && ch <= 140)
+ idx = ((ch-100)/4 + 15 + 18);
+ else if (ch >= 149 && ch <= 165)
+ idx = ((ch-149)/4 + 26 + 18);
+ else
+ idx = -1;
+ break;
+ case IEEE80211_BAND_2GHZ:
+ if (ch >= 1 && ch <= 14)
+ idx = ch - 1;
+ else
+ idx = -1;
+ break;
+ default:
+ wl1271_error("get reg conf ch idx - unknown band: %d",
+ (int)band);
+ }
+
+ return idx;
+}
+
+void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
+ enum ieee80211_band band)
+{
+ int ch_bit_idx = 0;
+
+ if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF))
+ return;
+
+ ch_bit_idx = wlcore_get_reg_conf_ch_idx(band, channel);
+
+ if (ch_bit_idx > 0 && ch_bit_idx <= WL1271_MAX_CHANNELS)
+ set_bit(ch_bit_idx, (long *)wl->reg_ch_conf_pending);
+}
+
+int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
+{
+ struct wl12xx_cmd_regdomain_dfs_config *cmd = NULL;
+ int ret = 0, i, b, ch_bit_idx;
+ struct ieee80211_channel *channel;
+ u32 tmp_ch_bitmap[2];
+ u16 ch;
+ struct wiphy *wiphy = wl->hw->wiphy;
+ struct ieee80211_supported_band *band;
+ bool timeout = false;
+
+ if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF))
+ return 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd reg domain config");
+
+ memset(tmp_ch_bitmap, 0, sizeof(tmp_ch_bitmap));
+
+ for (b = IEEE80211_BAND_2GHZ; b <= IEEE80211_BAND_5GHZ; b++) {
+ band = wiphy->bands[b];
+ for (i = 0; i < band->n_channels; i++) {
+ channel = &band->channels[i];
+ ch = channel->hw_value;
+
+ if (channel->flags & (IEEE80211_CHAN_DISABLED |
+ IEEE80211_CHAN_RADAR |
+ IEEE80211_CHAN_PASSIVE_SCAN))
+ continue;
+
+ ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch);
+ if (ch_bit_idx < 0)
+ continue;
+
+ set_bit(ch_bit_idx, (long *)tmp_ch_bitmap);
+ }
+ }
+
+ tmp_ch_bitmap[0] |= wl->reg_ch_conf_pending[0];
+ tmp_ch_bitmap[1] |= wl->reg_ch_conf_pending[1];
+
+ if (!memcmp(tmp_ch_bitmap, wl->reg_ch_conf_last, sizeof(tmp_ch_bitmap)))
+ goto out;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->ch_bit_map1 = cpu_to_le32(tmp_ch_bitmap[0]);
+ cmd->ch_bit_map2 = cpu_to_le32(tmp_ch_bitmap[1]);
+
+ wl1271_debug(DEBUG_CMD,
+ "cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x",
+ cmd->ch_bit_map1, cmd->ch_bit_map2);
+
+ ret = wl1271_cmd_send(wl, CMD_DFS_CHANNEL_CONFIG, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send reg domain dfs config");
+ goto out;
+ }
+
+ ret = wl->ops->wait_for_event(wl,
+ WLCORE_EVENT_DFS_CONFIG_COMPLETE,
+ &timeout);
+ if (ret < 0 || timeout) {
+ wl1271_error("reg domain conf %serror",
+ timeout ? "completion " : "");
+ ret = timeout ? -ETIMEDOUT : ret;
+ goto out;
+ }
+
+ memcpy(wl->reg_ch_conf_last, tmp_ch_bitmap, sizeof(tmp_ch_bitmap));
+ memset(wl->reg_ch_conf_pending, 0, sizeof(wl->reg_ch_conf_pending));
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
int wl12xx_cmd_config_fwlog(struct wl1271 *wl)
{
struct wl12xx_cmd_config_fwlog *cmd;
@@ -1593,12 +1783,12 @@ out:
}
static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- u8 role_id)
+ u8 role_id, enum ieee80211_band band, u8 channel)
{
struct wl12xx_cmd_roc *cmd;
int ret = 0;
- wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id);
+ wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", channel, role_id);
if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID))
return -EINVAL;
@@ -1610,8 +1800,8 @@ static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
}
cmd->role_id = role_id;
- cmd->channel = wlvif->channel;
- switch (wlvif->band) {
+ cmd->channel = channel;
+ switch (band) {
case IEEE80211_BAND_2GHZ:
cmd->band = WLCORE_BAND_2_4GHZ;
break;
@@ -1666,30 +1856,18 @@ out:
return ret;
}
-int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id)
+int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id,
+ enum ieee80211_band band, u8 channel)
{
int ret = 0;
- bool is_first_roc;
if (WARN_ON(test_bit(role_id, wl->roc_map)))
return 0;
- is_first_roc = (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >=
- WL12XX_MAX_ROLES);
-
- ret = wl12xx_cmd_roc(wl, wlvif, role_id);
+ ret = wl12xx_cmd_roc(wl, wlvif, role_id, band, channel);
if (ret < 0)
goto out;
- if (is_first_roc) {
- ret = wl1271_cmd_wait_for_event(wl,
- REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
- if (ret < 0) {
- wl1271_error("cmd roc event completion error");
- goto out;
- }
- }
-
__set_bit(role_id, wl->roc_map);
out:
return ret;
@@ -1719,43 +1897,7 @@ out:
return ret;
}
-int wl12xx_cmd_channel_switch(struct wl1271 *wl,
- struct wl12xx_vif *wlvif,
- struct ieee80211_channel_switch *ch_switch)
-{
- struct wl12xx_cmd_channel_switch *cmd;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "cmd channel switch");
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd) {
- ret = -ENOMEM;
- goto out;
- }
-
- cmd->role_id = wlvif->role_id;
- cmd->channel = ch_switch->channel->hw_value;
- cmd->switch_time = ch_switch->count;
- cmd->stop_tx = ch_switch->block_tx;
-
- /* FIXME: control from mac80211 in the future */
- cmd->post_switch_tx_disable = 0; /* Enable TX on the target channel */
-
- ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
- if (ret < 0) {
- wl1271_error("failed to send channel switch command");
- goto out_free;
- }
-
-out_free:
- kfree(cmd);
-
-out:
- return ret;
-}
-
-int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl)
+int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
struct wl12xx_cmd_stop_channel_switch *cmd;
int ret;
@@ -1768,6 +1910,8 @@ int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl)
goto out;
}
+ cmd->role_id = wlvif->role_id;
+
ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to stop channel switch command");
@@ -1782,7 +1926,8 @@ out:
}
/* start dev role and roc on its channel */
-int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ enum ieee80211_band band, int channel)
{
int ret;
@@ -1797,11 +1942,11 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if (ret < 0)
goto out;
- ret = wl12xx_cmd_role_start_dev(wl, wlvif);
+ ret = wl12xx_cmd_role_start_dev(wl, wlvif, band, channel);
if (ret < 0)
goto out_disable;
- ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
+ ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id, band, channel);
if (ret < 0)
goto out_stop;
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h
index 2409f3d71f63..fd34123047cd 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.h
+++ b/drivers/net/wireless/ti/wlcore/cmd.h
@@ -31,6 +31,8 @@ struct acx_header;
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len);
+int wlcore_cmd_send_failsafe(struct wl1271 *wl, u16 id, void *buf, size_t len,
+ size_t res_len, unsigned long valid_rets);
int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type,
u8 *role_id);
int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
@@ -39,11 +41,14 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ enum ieee80211_band band, int channel);
int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
+int wlcore_cmd_configure_failsafe(struct wl1271 *wl, u16 id, void *buf,
+ size_t len, unsigned long valid_rets);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 ps_mode, u16 auto_ps_timeout);
@@ -75,22 +80,30 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16);
-int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid);
-int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id);
+int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 hlid);
+int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id,
+ enum ieee80211_band band, u8 channel);
int wl12xx_croc(struct wl1271 *wl, u8 role_id);
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_sta *sta, u8 hlid);
int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
+void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
+ enum ieee80211_band band);
+int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl);
int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
int wl12xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
-int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
+int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif);
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 *hlid);
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
+int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
+ u32 mask, bool *timeout);
enum wl1271_commands {
CMD_INTERROGATE = 1, /* use this to read information elements */
@@ -149,8 +162,11 @@ enum wl1271_commands {
CMD_WFD_START_DISCOVERY = 45,
CMD_WFD_STOP_DISCOVERY = 46,
CMD_WFD_ATTRIBUTE_CONFIG = 47,
- CMD_NOP = 48,
- CMD_LAST_COMMAND,
+ CMD_GENERIC_CFG = 48,
+ CMD_NOP = 49,
+
+ /* start of 18xx specific commands */
+ CMD_DFS_CHANNEL_CONFIG = 60,
MAX_COMMAND_ID = 0xFFFF,
};
@@ -167,8 +183,8 @@ enum cmd_templ {
CMD_TEMPL_PS_POLL,
CMD_TEMPL_KLV,
CMD_TEMPL_DISCONNECT,
- CMD_TEMPL_APP_PROBE_REQ_2_4,
- CMD_TEMPL_APP_PROBE_REQ_5,
+ CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY,
+ CMD_TEMPL_APP_PROBE_REQ_5_LEGACY,
CMD_TEMPL_BAR, /* for firmware internal use only */
CMD_TEMPL_CTS, /*
* For CTS-to-self (FastCTS) mechanism
@@ -179,6 +195,8 @@ enum cmd_templ {
CMD_TEMPL_DEAUTH_AP,
CMD_TEMPL_TEMPORARY,
CMD_TEMPL_LINK_MEASUREMENT_REPORT,
+ CMD_TEMPL_PROBE_REQ_2_4_PERIODIC,
+ CMD_TEMPL_PROBE_REQ_5_PERIODIC,
CMD_TEMPL_MAX = 0xff
};
@@ -220,7 +238,8 @@ enum {
CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/
CMD_STATUS_TEMPLATE_OOM = 23,
CMD_STATUS_NO_RX_BA_SESSION = 24,
- MAX_COMMAND_STATUS = 0xff
+
+ MAX_COMMAND_STATUS
};
#define CMDMBOX_HEADER_LEN 4
@@ -345,7 +364,15 @@ struct wl12xx_cmd_role_start {
u8 reset_tsf;
- u8 padding_1[4];
+ /*
+ * ap supports wmm (note that there is additional
+ * per-sta wmm configuration)
+ */
+ u8 wmm;
+
+ u8 bcast_session_id;
+ u8 global_session_id;
+ u8 padding_1[1];
} __packed ap;
};
} __packed;
@@ -515,7 +542,14 @@ struct wl12xx_cmd_set_peer_state {
u8 hlid;
u8 state;
- u8 padding[2];
+
+ /*
+ * wmm is relevant for sta role only.
+ * ap role configures the per-sta wmm params in
+ * the add_peer command.
+ */
+ u8 wmm;
+ u8 padding[1];
} __packed;
struct wl12xx_cmd_roc {
@@ -558,7 +592,7 @@ struct wl12xx_cmd_add_peer {
u8 bss_index;
u8 sp_len;
u8 wmm;
- u8 padding1;
+ u8 session_id;
} __packed;
struct wl12xx_cmd_remove_peer {
@@ -597,6 +631,13 @@ enum wl12xx_fwlogger_output {
WL12XX_FWLOG_OUTPUT_HOST,
};
+struct wl12xx_cmd_regdomain_dfs_config {
+ struct wl1271_cmd_header header;
+
+ __le32 ch_bit_map1;
+ __le32 ch_bit_map2;
+} __packed;
+
struct wl12xx_cmd_config_fwlog {
struct wl1271_cmd_header header;
@@ -626,27 +667,13 @@ struct wl12xx_cmd_stop_fwlog {
struct wl1271_cmd_header header;
} __packed;
-struct wl12xx_cmd_channel_switch {
+struct wl12xx_cmd_stop_channel_switch {
struct wl1271_cmd_header header;
u8 role_id;
-
- /* The new serving channel */
- u8 channel;
- /* Relative time of the serving channel switch in TBTT units */
- u8 switch_time;
- /* Stop the role TX, should expect it after radar detection */
- u8 stop_tx;
- /* The target channel tx status 1-stopped 0-open*/
- u8 post_switch_tx_disable;
-
u8 padding[3];
} __packed;
-struct wl12xx_cmd_stop_channel_switch {
- struct wl1271_cmd_header header;
-} __packed;
-
/* Used to check radio status after calibration */
#define MAX_TLV_LENGTH 500
#define TEST_CMD_P2G_CAL 2 /* TX BiP */
diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h
index 9e40760bafe1..2b96ff821341 100644
--- a/drivers/net/wireless/ti/wlcore/conf.h
+++ b/drivers/net/wireless/ti/wlcore/conf.h
@@ -57,20 +57,49 @@ enum {
};
enum {
- CONF_HW_RATE_INDEX_1MBPS = 0,
- CONF_HW_RATE_INDEX_2MBPS = 1,
- CONF_HW_RATE_INDEX_5_5MBPS = 2,
- CONF_HW_RATE_INDEX_6MBPS = 3,
- CONF_HW_RATE_INDEX_9MBPS = 4,
- CONF_HW_RATE_INDEX_11MBPS = 5,
- CONF_HW_RATE_INDEX_12MBPS = 6,
- CONF_HW_RATE_INDEX_18MBPS = 7,
- CONF_HW_RATE_INDEX_22MBPS = 8,
- CONF_HW_RATE_INDEX_24MBPS = 9,
- CONF_HW_RATE_INDEX_36MBPS = 10,
- CONF_HW_RATE_INDEX_48MBPS = 11,
- CONF_HW_RATE_INDEX_54MBPS = 12,
- CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS,
+ CONF_HW_RATE_INDEX_1MBPS = 0,
+ CONF_HW_RATE_INDEX_2MBPS = 1,
+ CONF_HW_RATE_INDEX_5_5MBPS = 2,
+ CONF_HW_RATE_INDEX_11MBPS = 3,
+ CONF_HW_RATE_INDEX_6MBPS = 4,
+ CONF_HW_RATE_INDEX_9MBPS = 5,
+ CONF_HW_RATE_INDEX_12MBPS = 6,
+ CONF_HW_RATE_INDEX_18MBPS = 7,
+ CONF_HW_RATE_INDEX_24MBPS = 8,
+ CONF_HW_RATE_INDEX_36MBPS = 9,
+ CONF_HW_RATE_INDEX_48MBPS = 10,
+ CONF_HW_RATE_INDEX_54MBPS = 11,
+ CONF_HW_RATE_INDEX_MCS0 = 12,
+ CONF_HW_RATE_INDEX_MCS1 = 13,
+ CONF_HW_RATE_INDEX_MCS2 = 14,
+ CONF_HW_RATE_INDEX_MCS3 = 15,
+ CONF_HW_RATE_INDEX_MCS4 = 16,
+ CONF_HW_RATE_INDEX_MCS5 = 17,
+ CONF_HW_RATE_INDEX_MCS6 = 18,
+ CONF_HW_RATE_INDEX_MCS7 = 19,
+ CONF_HW_RATE_INDEX_MCS7_SGI = 20,
+ CONF_HW_RATE_INDEX_MCS0_40MHZ = 21,
+ CONF_HW_RATE_INDEX_MCS1_40MHZ = 22,
+ CONF_HW_RATE_INDEX_MCS2_40MHZ = 23,
+ CONF_HW_RATE_INDEX_MCS3_40MHZ = 24,
+ CONF_HW_RATE_INDEX_MCS4_40MHZ = 25,
+ CONF_HW_RATE_INDEX_MCS5_40MHZ = 26,
+ CONF_HW_RATE_INDEX_MCS6_40MHZ = 27,
+ CONF_HW_RATE_INDEX_MCS7_40MHZ = 28,
+ CONF_HW_RATE_INDEX_MCS7_40MHZ_SGI = 29,
+
+ /* MCS8+ rates overlap with 40Mhz rates */
+ CONF_HW_RATE_INDEX_MCS8 = 21,
+ CONF_HW_RATE_INDEX_MCS9 = 22,
+ CONF_HW_RATE_INDEX_MCS10 = 23,
+ CONF_HW_RATE_INDEX_MCS11 = 24,
+ CONF_HW_RATE_INDEX_MCS12 = 25,
+ CONF_HW_RATE_INDEX_MCS13 = 26,
+ CONF_HW_RATE_INDEX_MCS14 = 27,
+ CONF_HW_RATE_INDEX_MCS15 = 28,
+ CONF_HW_RATE_INDEX_MCS15_SGI = 29,
+
+ CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_MCS7_40MHZ_SGI,
};
#define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff
@@ -415,11 +444,11 @@ struct conf_rx_settings {
#define CONF_TX_RATE_MASK_BASIC_P2P CONF_HW_BIT_RATE_6MBPS
/*
- * Rates supported for data packets when operating as AP. Note the absence
+ * Rates supported for data packets when operating as STA/AP. Note the absence
* of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop
* one. The rate dropped is not mandatory under any operating mode.
*/
-#define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \
+#define CONF_TX_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \
CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \
@@ -677,6 +706,18 @@ struct conf_tx_settings {
/* Time in ms for Tx watchdog timer to expire */
u32 tx_watchdog_timeout;
+
+ /*
+ * when a slow link has this much packets pending, it becomes a low
+ * priority link, scheduling-wise
+ */
+ u8 slow_link_thold;
+
+ /*
+ * when a fast link has this much packets pending, it becomes a low
+ * priority link, scheduling-wise
+ */
+ u8 fast_link_thold;
} __packed;
enum {
@@ -1047,6 +1088,7 @@ struct conf_roam_trigger_settings {
struct conf_scan_settings {
/*
* The minimum time to wait on each channel for active scans
+ * This value will be used whenever there's a connected interface.
*
* Range: u32 tu/1000
*/
@@ -1054,24 +1096,37 @@ struct conf_scan_settings {
/*
* The maximum time to wait on each channel for active scans
+ * This value will be currently used whenever there's a
+ * connected interface. It shouldn't exceed 30000 (~30ms) to avoid
+ * possible interference of voip traffic going on while scanning.
*
* Range: u32 tu/1000
*/
u32 max_dwell_time_active;
- /*
- * The minimum time to wait on each channel for passive scans
+ /* The minimum time to wait on each channel for active scans
+ * when it's possible to have longer scan dwell times.
+ * Currently this is used whenever we're idle on all interfaces.
+ * Longer dwell times improve detection of networks within a
+ * single scan.
*
* Range: u32 tu/1000
*/
- u32 min_dwell_time_passive;
+ u32 min_dwell_time_active_long;
- /*
- * The maximum time to wait on each channel for passive scans
+ /* The maximum time to wait on each channel for active scans
+ * when it's possible to have longer scan dwell times.
+ * See min_dwell_time_active_long
*
* Range: u32 tu/1000
*/
- u32 max_dwell_time_passive;
+ u32 max_dwell_time_active_long;
+
+ /* time to wait on the channel for passive scans (in TU/1000) */
+ u32 dwell_time_passive;
+
+ /* time to wait on the channel for DFS scans (in TU/1000) */
+ u32 dwell_time_dfs;
/*
* Number of probe requests to transmit on each active scan channel
@@ -1276,12 +1331,20 @@ struct conf_hangover_settings {
u8 window_size;
} __packed;
+struct conf_recovery_settings {
+ /* BUG() on fw recovery */
+ u8 bug_on_recovery;
+
+ /* Prevent HW recovery. FW will remain stuck. */
+ u8 no_recovery;
+} __packed;
+
/*
* The conf version consists of 4 bytes. The two MSB are the wlcore
* version, the two LSB are the lower driver's private conf
* version.
*/
-#define WLCORE_CONF_VERSION (0x0002 << 16)
+#define WLCORE_CONF_VERSION (0x0005 << 16)
#define WLCORE_CONF_MASK 0xffff0000
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
sizeof(struct wlcore_conf))
@@ -1309,6 +1372,7 @@ struct wlcore_conf {
struct conf_fwlog fwlog;
struct conf_rate_policy_settings rate;
struct conf_hangover_settings hangover;
+ struct conf_recovery_settings recovery;
} __packed;
struct wlcore_conf_file {
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index c86bb00c2488..e70a7c864865 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -490,7 +490,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_HEX(chip.id);
DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str);
- DRIVER_STATE_PRINT_INT(sched_scanning);
+ DRIVER_STATE_PRINT_INT(recovery_count);
#undef DRIVER_STATE_PRINT_INT
#undef DRIVER_STATE_PRINT_LONG
@@ -560,7 +560,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
wlvif->bss_type == BSS_TYPE_IBSS) {
VIF_STATE_PRINT_INT(sta.hlid);
- VIF_STATE_PRINT_INT(sta.ba_rx_bitmap);
VIF_STATE_PRINT_INT(sta.basic_rate_idx);
VIF_STATE_PRINT_INT(sta.ap_rate_idx);
VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
@@ -577,6 +576,10 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]);
}
VIF_STATE_PRINT_INT(last_tx_hlid);
+ VIF_STATE_PRINT_INT(tx_queue_count[0]);
+ VIF_STATE_PRINT_INT(tx_queue_count[1]);
+ VIF_STATE_PRINT_INT(tx_queue_count[2]);
+ VIF_STATE_PRINT_INT(tx_queue_count[3]);
VIF_STATE_PRINT_LHEX(links_map[0]);
VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len);
VIF_STATE_PRINT_INT(band);
@@ -589,7 +592,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(beacon_int);
VIF_STATE_PRINT_INT(default_key);
VIF_STATE_PRINT_INT(aid);
- VIF_STATE_PRINT_INT(session_counter);
VIF_STATE_PRINT_INT(psm_entry_retry);
VIF_STATE_PRINT_INT(power_level);
VIF_STATE_PRINT_INT(rssi_thold);
@@ -993,7 +995,7 @@ static ssize_t sleep_auth_write(struct file *file,
return -EINVAL;
}
- if (value < 0 || value > WL1271_PSM_MAX) {
+ if (value > WL1271_PSM_MAX) {
wl1271_warning("sleep_auth must be between 0 and %d",
WL1271_PSM_MAX);
return -ERANGE;
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 48907054d493..70f289aa1bc6 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -29,34 +29,39 @@
#include "scan.h"
#include "wl12xx_80211.h"
-static void wl1271_event_rssi_trigger(struct wl1271 *wl,
- struct wl12xx_vif *wlvif,
- struct event_mailbox *mbox)
+void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr)
{
- struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+ struct wl12xx_vif *wlvif;
+ struct ieee80211_vif *vif;
enum nl80211_cqm_rssi_threshold_event event;
- s8 metric = mbox->rssi_snr_trigger_metric[0];
+ s8 metric = metric_arr[0];
wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric);
- if (metric <= wlvif->rssi_thold)
- event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
- else
- event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
-
- if (event != wlvif->last_rssi_event)
- ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
- wlvif->last_rssi_event = event;
+ /* TODO: check actual multi-role support */
+ wl12xx_for_each_wlvif_sta(wl, wlvif) {
+ if (metric <= wlvif->rssi_thold)
+ event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
+ else
+ event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
+
+ vif = wl12xx_wlvif_to_vif(wlvif);
+ if (event != wlvif->last_rssi_event)
+ ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
+ wlvif->last_rssi_event = event;
+ }
}
+EXPORT_SYMBOL_GPL(wlcore_event_rssi_trigger);
static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
- if (!wlvif->sta.ba_rx_bitmap)
+ u8 hlid = wlvif->sta.hlid;
+ if (!wl->links[hlid].ba_bitmap)
return;
- ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap,
+ ieee80211_stop_rx_ba_session(vif, wl->links[hlid].ba_bitmap,
vif->bss_conf.bssid);
} else {
u8 hlid;
@@ -74,8 +79,7 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
}
}
-static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
- u8 enable)
+void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable)
{
struct wl12xx_vif *wlvif;
@@ -87,201 +91,169 @@ static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
wl1271_recalc_rx_streaming(wl, wlvif);
}
}
-
}
+EXPORT_SYMBOL_GPL(wlcore_event_soft_gemini_sense);
-static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
+void wlcore_event_sched_scan_completed(struct wl1271 *wl,
+ u8 status)
{
- wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
- wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
- wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
+ wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT (status 0x%0x)",
+ status);
+
+ if (wl->sched_vif) {
+ ieee80211_sched_scan_stopped(wl->hw);
+ wl->sched_vif = NULL;
+ }
}
+EXPORT_SYMBOL_GPL(wlcore_event_sched_scan_completed);
-static int wl1271_event_process(struct wl1271 *wl)
+void wlcore_event_ba_rx_constraint(struct wl1271 *wl,
+ unsigned long roles_bitmap,
+ unsigned long allowed_bitmap)
{
- struct event_mailbox *mbox = wl->mbox;
- struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif;
- u32 vector;
- bool disconnect_sta = false;
- unsigned long sta_bitmap = 0;
- int ret;
-
- wl1271_event_mbox_dump(mbox);
-
- vector = le32_to_cpu(mbox->events_vector);
- vector &= ~(le32_to_cpu(mbox->events_mask));
- wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
- if (vector & SCAN_COMPLETE_EVENT_ID) {
- wl1271_debug(DEBUG_EVENT, "status: 0x%x",
- mbox->scheduled_scan_status);
-
- wl1271_scan_stm(wl, wl->scan_vif);
- }
+ wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx allowed=0x%lx",
+ __func__, roles_bitmap, allowed_bitmap);
- if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
- wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT "
- "(status 0x%0x)", mbox->scheduled_scan_status);
+ wl12xx_for_each_wlvif(wl, wlvif) {
+ if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
+ !test_bit(wlvif->role_id , &roles_bitmap))
+ continue;
- wl1271_scan_sched_scan_results(wl);
+ wlvif->ba_allowed = !!test_bit(wlvif->role_id,
+ &allowed_bitmap);
+ if (!wlvif->ba_allowed)
+ wl1271_stop_ba_event(wl, wlvif);
}
+}
+EXPORT_SYMBOL_GPL(wlcore_event_ba_rx_constraint);
- 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) {
- ieee80211_sched_scan_stopped(wl->hw);
- wl->sched_scanning = false;
- }
- }
+void wlcore_event_channel_switch(struct wl1271 *wl,
+ unsigned long roles_bitmap,
+ bool success)
+{
+ struct wl12xx_vif *wlvif;
+ struct ieee80211_vif *vif;
- if (vector & SOFT_GEMINI_SENSE_EVENT_ID)
- wl12xx_event_soft_gemini_sense(wl,
- mbox->soft_gemini_sense_info);
+ wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx success=%d",
+ __func__, roles_bitmap, success);
- /*
- * We are HW_MONITOR device. On beacon loss - queue
- * connection loss work. Cancel it on REGAINED event.
- */
- if (vector & BSS_LOSE_EVENT_ID) {
- /* TODO: check for multi-role */
- int delay = wl->conf.conn.synch_fail_thold *
- wl->conf.conn.bss_lose_timeout;
- wl1271_info("Beacon loss detected.");
+ wl12xx_for_each_wlvif_sta(wl, wlvif) {
+ if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
+ !test_bit(wlvif->role_id , &roles_bitmap))
+ continue;
- /*
- * if the work is already queued, it should take place. We
- * don't want to delay the connection loss indication
- * any more.
- */
- ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work,
- msecs_to_jiffies(delay));
+ if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
+ &wlvif->flags))
+ continue;
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
- vif = wl12xx_wlvif_to_vif(wlvif);
+ vif = wl12xx_wlvif_to_vif(wlvif);
- ieee80211_cqm_rssi_notify(
- vif,
- NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
- GFP_KERNEL);
- }
+ ieee80211_chswitch_done(vif, success);
+ cancel_delayed_work(&wlvif->channel_switch_work);
}
+}
+EXPORT_SYMBOL_GPL(wlcore_event_channel_switch);
- if (vector & REGAINED_BSS_EVENT_ID) {
- /* TODO: check for multi-role */
- wl1271_info("Beacon regained.");
- cancel_delayed_work(&wl->connection_loss_work);
-
- /* sanity check - we can't lose and gain the beacon together */
- WARN(vector & BSS_LOSE_EVENT_ID,
- "Concurrent beacon loss and gain from FW");
- }
+void wlcore_event_dummy_packet(struct wl1271 *wl)
+{
+ wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
+ wl1271_tx_dummy_packet(wl);
+}
+EXPORT_SYMBOL_GPL(wlcore_event_dummy_packet);
- if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
- /* TODO: check actual multi-role support */
- wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
- wl1271_event_rssi_trigger(wl, wlvif, mbox);
+static void wlcore_disconnect_sta(struct wl1271 *wl, unsigned long sta_bitmap)
+{
+ u32 num_packets = wl->conf.tx.max_tx_retries;
+ struct wl12xx_vif *wlvif;
+ struct ieee80211_vif *vif;
+ struct ieee80211_sta *sta;
+ const u8 *addr;
+ int h;
+
+ for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
+ bool found = false;
+ /* find the ap vif connected to this sta */
+ wl12xx_for_each_wlvif_ap(wl, wlvif) {
+ if (!test_bit(h, wlvif->ap.sta_hlid_map))
+ continue;
+ found = true;
+ break;
}
- }
+ if (!found)
+ continue;
- if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) {
- u8 role_id = mbox->role_id;
- wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
- "ba_allowed = 0x%x, role_id=%d",
- mbox->rx_ba_allowed, role_id);
+ vif = wl12xx_wlvif_to_vif(wlvif);
+ addr = wl->links[h].addr;
- wl12xx_for_each_wlvif(wl, wlvif) {
- if (role_id != 0xff && role_id != wlvif->role_id)
- continue;
-
- wlvif->ba_allowed = !!mbox->rx_ba_allowed;
- if (!wlvif->ba_allowed)
- wl1271_stop_ba_event(wl, wlvif);
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, addr);
+ if (sta) {
+ wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
+ ieee80211_report_low_ack(sta, num_packets);
}
+ rcu_read_unlock();
}
+}
- if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) {
- wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. "
- "status = 0x%x",
- mbox->channel_switch_status);
- /*
- * That event uses for two cases:
- * 1) channel switch complete with status=0
- * 2) channel switch failed status=1
- */
-
- /* TODO: configure only the relevant vif */
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
- bool success;
-
- if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
- &wlvif->flags))
- continue;
-
- success = mbox->channel_switch_status ? false : true;
- vif = wl12xx_wlvif_to_vif(wlvif);
+void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap)
+{
+ wl1271_debug(DEBUG_EVENT, "MAX_TX_FAILURE_EVENT_ID");
+ wlcore_disconnect_sta(wl, sta_bitmap);
+}
+EXPORT_SYMBOL_GPL(wlcore_event_max_tx_failure);
- ieee80211_chswitch_done(vif, success);
- }
- }
+void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap)
+{
+ wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
+ wlcore_disconnect_sta(wl, sta_bitmap);
+}
+EXPORT_SYMBOL_GPL(wlcore_event_inactive_sta);
- if ((vector & DUMMY_PACKET_EVENT_ID)) {
- wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
- ret = wl1271_tx_dummy_packet(wl);
- if (ret < 0)
- return ret;
- }
+void wlcore_event_roc_complete(struct wl1271 *wl)
+{
+ wl1271_debug(DEBUG_EVENT, "REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID");
+ if (wl->roc_vif)
+ ieee80211_ready_on_channel(wl->hw);
+}
+EXPORT_SYMBOL_GPL(wlcore_event_roc_complete);
+void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
+{
/*
- * "TX retries exceeded" has a different meaning according to mode.
- * In AP mode the offending station is disconnected.
+ * We are HW_MONITOR device. On beacon loss - queue
+ * connection loss work. Cancel it on REGAINED event.
*/
- if (vector & MAX_TX_RETRY_EVENT_ID) {
- wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
- sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
- disconnect_sta = true;
- }
+ struct wl12xx_vif *wlvif;
+ struct ieee80211_vif *vif;
+ int delay = wl->conf.conn.synch_fail_thold *
+ wl->conf.conn.bss_lose_timeout;
- if (vector & INACTIVE_STA_EVENT_ID) {
- wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
- sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
- disconnect_sta = true;
- }
+ wl1271_info("Beacon loss detected. roles:0x%lx", roles_bitmap);
- if (disconnect_sta) {
- u32 num_packets = wl->conf.tx.max_tx_retries;
- struct ieee80211_sta *sta;
- const u8 *addr;
- int h;
-
- for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
- bool found = false;
- /* find the ap vif connected to this sta */
- wl12xx_for_each_wlvif_ap(wl, wlvif) {
- if (!test_bit(h, wlvif->ap.sta_hlid_map))
- continue;
- found = true;
- break;
- }
- if (!found)
- continue;
+ wl12xx_for_each_wlvif_sta(wl, wlvif) {
+ if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
+ !test_bit(wlvif->role_id , &roles_bitmap))
+ continue;
- vif = wl12xx_wlvif_to_vif(wlvif);
- addr = wl->links[h].addr;
+ /*
+ * if the work is already queued, it should take place.
+ * We don't want to delay the connection loss
+ * indication any more.
+ */
+ ieee80211_queue_delayed_work(wl->hw,
+ &wlvif->connection_loss_work,
+ msecs_to_jiffies(delay));
- rcu_read_lock();
- sta = ieee80211_find_sta(vif, addr);
- if (sta) {
- wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
- ieee80211_report_low_ack(sta, num_packets);
- }
- rcu_read_unlock();
- }
+ vif = wl12xx_wlvif_to_vif(wlvif);
+ ieee80211_cqm_rssi_notify(
+ vif,
+ NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
+ GFP_KERNEL);
}
- return 0;
}
+EXPORT_SYMBOL_GPL(wlcore_event_beacon_loss);
int wl1271_event_unmask(struct wl1271 *wl)
{
@@ -305,12 +277,12 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
/* first we read the mbox descriptor */
ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
- sizeof(*wl->mbox), false);
+ wl->mbox_size, false);
if (ret < 0)
return ret;
/* process the descriptor */
- ret = wl1271_event_process(wl);
+ ret = wl->ops->process_mailbox_events(wl);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/ti/wlcore/event.h b/drivers/net/wireless/ti/wlcore/event.h
index 8adf18d6c58f..acc7a59d3828 100644
--- a/drivers/net/wireless/ti/wlcore/event.h
+++ b/drivers/net/wireless/ti/wlcore/event.h
@@ -46,33 +46,17 @@ enum {
RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5),
RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6),
RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7),
- MEASUREMENT_START_EVENT_ID = BIT(8),
- MEASUREMENT_COMPLETE_EVENT_ID = BIT(9),
- SCAN_COMPLETE_EVENT_ID = BIT(10),
- WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11),
- AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
- RESERVED1 = BIT(13),
- PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
- ROLE_STOP_COMPLETE_EVENT_ID = BIT(15),
- RADAR_DETECTED_EVENT_ID = BIT(16),
- CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
- BSS_LOSE_EVENT_ID = BIT(18),
- REGAINED_BSS_EVENT_ID = BIT(19),
- MAX_TX_RETRY_EVENT_ID = BIT(20),
- DUMMY_PACKET_EVENT_ID = BIT(21),
- SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
- CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23),
- SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
- PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
- INACTIVE_STA_EVENT_ID = BIT(26),
- PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27),
- PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28),
- PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29),
- BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30),
- REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31),
+
EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff,
};
+/* events the driver might want to wait for */
+enum wlcore_wait_event {
+ WLCORE_EVENT_ROLE_STOP_COMPLETE,
+ WLCORE_EVENT_PEER_REMOVE_COMPLETE,
+ WLCORE_EVENT_DFS_CONFIG_COMPLETE
+};
+
enum {
EVENT_ENTER_POWER_SAVE_FAIL = 0,
EVENT_ENTER_POWER_SAVE_SUCCESS,
@@ -80,61 +64,24 @@ enum {
#define NUM_OF_RSSI_SNR_TRIGGERS 8
-struct event_mailbox {
- __le32 events_vector;
- __le32 events_mask;
- __le32 reserved_1;
- __le32 reserved_2;
-
- u8 number_of_scan_results;
- u8 scan_tag;
- u8 completed_scan_status;
- u8 reserved_3;
-
- u8 soft_gemini_sense_info;
- u8 soft_gemini_protective_info;
- s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
- u8 change_auto_mode_timeout;
- u8 scheduled_scan_status;
- u8 reserved4;
- /* tuned channel (roc) */
- u8 roc_channel;
-
- __le16 hlid_removed_bitmap;
-
- /* bitmap of aged stations (by HLID) */
- __le16 sta_aging_status;
-
- /* bitmap of stations (by HLID) which exceeded max tx retries */
- __le16 sta_tx_retry_exceeded;
-
- /* discovery completed results */
- u8 discovery_tag;
- u8 number_of_preq_results;
- u8 number_of_prsp_results;
- u8 reserved_5;
-
- /* rx ba constraint */
- u8 role_id; /* 0xFF means any role. */
- u8 rx_ba_allowed;
- u8 reserved_6[2];
-
- /* Channel switch results */
-
- u8 channel_switch_role_id;
- u8 channel_switch_status;
- u8 reserved_7[2];
-
- u8 ps_poll_delivery_failure_role_ids;
- u8 stopped_role_ids;
- u8 started_role_ids;
-
- u8 reserved_8[9];
-} __packed;
-
struct wl1271;
int wl1271_event_unmask(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
+void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable);
+void wlcore_event_sched_scan_completed(struct wl1271 *wl,
+ u8 status);
+void wlcore_event_ba_rx_constraint(struct wl1271 *wl,
+ unsigned long roles_bitmap,
+ unsigned long allowed_bitmap);
+void wlcore_event_channel_switch(struct wl1271 *wl,
+ unsigned long roles_bitmap,
+ bool success);
+void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap);
+void wlcore_event_dummy_packet(struct wl1271 *wl);
+void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap);
+void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap);
+void wlcore_event_roc_complete(struct wl1271 *wl);
+void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr);
#endif
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 2673d783ec1e..7fd260c02a0a 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -201,4 +201,45 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
return buf_offset;
}
+static inline void
+wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct ieee80211_sta *sta, u32 changed)
+{
+ if (wl->ops->sta_rc_update)
+ wl->ops->sta_rc_update(wl, wlvif, sta, changed);
+}
+
+static inline int
+wlcore_hw_set_peer_cap(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid)
+{
+ if (wl->ops->set_peer_cap)
+ return wl->ops->set_peer_cap(wl, ht_cap, allow_ht_operation,
+ rate_set, hlid);
+
+ return 0;
+}
+
+static inline bool
+wlcore_hw_lnk_high_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ if (!wl->ops->lnk_high_prio)
+ BUG_ON(1);
+
+ return wl->ops->lnk_high_prio(wl, hlid, lnk);
+}
+
+static inline bool
+wlcore_hw_lnk_low_prio(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk)
+{
+ if (!wl->ops->lnk_low_prio)
+ BUG_ON(1);
+
+ return wl->ops->lnk_low_prio(wl, hlid, lnk);
+}
+
#endif
diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c
index 32d157f62f31..5c6f11e157d9 100644
--- a/drivers/net/wireless/ti/wlcore/init.c
+++ b/drivers/net/wireless/ti/wlcore/init.c
@@ -41,14 +41,14 @@ int wl1271_init_templates_config(struct wl1271 *wl)
/* send empty templates for fw memory reservation */
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
- CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
+ wl->scan_templ_id_2_4, NULL,
WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
- CMD_TEMPL_CFG_PROBE_REQ_5,
+ wl->scan_templ_id_5,
NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
WL1271_RATE_AUTOMATIC);
if (ret < 0)
@@ -56,14 +56,16 @@ int wl1271_init_templates_config(struct wl1271 *wl)
if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) {
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
- CMD_TEMPL_APP_PROBE_REQ_2_4, NULL,
+ wl->sched_scan_templ_id_2_4,
+ NULL,
WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
- CMD_TEMPL_APP_PROBE_REQ_5, NULL,
+ wl->sched_scan_templ_id_5,
+ NULL,
WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
@@ -463,7 +465,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
supported_rates = CONF_TX_OFDM_RATES;
else
- supported_rates = CONF_TX_AP_ENABLED_RATES;
+ supported_rates = CONF_TX_ENABLED_RATES;
/* unconditionally enable HT rates */
supported_rates |= CONF_TX_MCS_RATES;
@@ -575,9 +577,6 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
/* Configure for power according to debugfs */
if (sta_auth != WL1271_PSM_ILLEGAL)
ret = wl1271_acx_sleep_auth(wl, sta_auth);
- /* Configure for power always on */
- else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
- ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
/* Configure for ELP power saving */
else
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
@@ -679,6 +678,10 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
+ ret = wlcore_cmd_regdomain_config_locked(wl);
+ if (ret < 0)
+ return ret;
+
/* Bluetooth WLAN coexistence */
ret = wl1271_init_pta(wl);
if (ret < 0)
diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h
index f48530fec14f..af7d9f9b3b4d 100644
--- a/drivers/net/wireless/ti/wlcore/io.h
+++ b/drivers/net/wireless/ti/wlcore/io.h
@@ -105,13 +105,13 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
{
int ret;
- ret = wlcore_raw_read(wl, addr, &wl->buffer_32,
- sizeof(wl->buffer_32), false);
+ ret = wlcore_raw_read(wl, addr, wl->buffer_32,
+ sizeof(*wl->buffer_32), false);
if (ret < 0)
return ret;
if (val)
- *val = le32_to_cpu(wl->buffer_32);
+ *val = le32_to_cpu(*wl->buffer_32);
return 0;
}
@@ -119,9 +119,9 @@ static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr,
u32 val)
{
- wl->buffer_32 = cpu_to_le32(val);
- return wlcore_raw_write(wl, addr, &wl->buffer_32,
- sizeof(wl->buffer_32), false);
+ *wl->buffer_32 = cpu_to_le32(val);
+ return wlcore_raw_write(wl, addr, wl->buffer_32,
+ sizeof(*wl->buffer_32), false);
}
static inline int __must_check wlcore_read(struct wl1271 *wl, int addr,
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index ea9d8e011bc9..2c2ff3e1f849 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -56,8 +56,8 @@
#define WL1271_BOOT_RETRIES 3
static char *fwlog_param;
-static bool bug_on_recovery;
-static bool no_recovery;
+static int bug_on_recovery = -1;
+static int no_recovery = -1;
static void __wl1271_op_remove_interface(struct wl1271 *wl,
struct ieee80211_vif *vif,
@@ -79,22 +79,22 @@ static int wl12xx_set_authorized(struct wl1271 *wl,
if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
return 0;
- ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
+ ret = wl12xx_cmd_set_peer_state(wl, wlvif, wlvif->sta.hlid);
if (ret < 0)
return ret;
- wl12xx_croc(wl, wlvif->role_id);
-
wl1271_info("Association completed.");
return 0;
}
-static int wl1271_reg_notify(struct wiphy *wiphy,
- struct regulatory_request *request)
+static void wl1271_reg_notify(struct wiphy *wiphy,
+ struct regulatory_request *request)
{
struct ieee80211_supported_band *band;
struct ieee80211_channel *ch;
int i;
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct wl1271 *wl = hw->priv;
band = wiphy->bands[IEEE80211_BAND_5GHZ];
for (i = 0; i < band->n_channels; i++) {
@@ -108,7 +108,8 @@ static int wl1271_reg_notify(struct wiphy *wiphy,
}
- return 0;
+ if (likely(wl->state == WLCORE_STATE_ON))
+ wlcore_regdomain_config(wl);
}
static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -303,6 +304,7 @@ out:
static void wlcore_adjust_conf(struct wl1271 *wl)
{
/* Adjust settings according to optional module parameters */
+
if (fwlog_param) {
if (!strcmp(fwlog_param, "continuous")) {
wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
@@ -318,16 +320,22 @@ static void wlcore_adjust_conf(struct wl1271 *wl)
wl1271_error("Unknown fwlog parameter %s", fwlog_param);
}
}
+
+ if (bug_on_recovery != -1)
+ wl->conf.recovery.bug_on_recovery = (u8) bug_on_recovery;
+
+ if (no_recovery != -1)
+ wl->conf.recovery.no_recovery = (u8) no_recovery;
}
static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
u8 hlid, u8 tx_pkts)
{
- bool fw_ps, single_sta;
+ bool fw_ps, single_link;
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
- single_sta = (wl->active_sta_count == 1);
+ single_link = (wl->active_link_count == 1);
/*
* Wake up from high level PS if the STA is asleep with too little
@@ -338,10 +346,10 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
/*
* Start high-level PS if the STA is asleep with enough blocks in FW.
- * Make an exception if this is the only connected station. In this
- * case FW-memory congestion is not a problem.
+ * Make an exception if this is the only connected link. In this
+ * case FW-memory congestion is less of a problem.
*/
- else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+ else if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
@@ -349,11 +357,8 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct wl_fw_status_2 *status)
{
- struct wl1271_link *lnk;
u32 cur_fw_ps_map;
- u8 hlid, cnt;
-
- /* TODO: also use link_fast_bitmap here */
+ u8 hlid;
cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
if (wl->ap_fw_ps_map != cur_fw_ps_map) {
@@ -365,17 +370,9 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
wl->ap_fw_ps_map = cur_fw_ps_map;
}
- for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
- lnk = &wl->links[hlid];
- cnt = status->counters.tx_lnk_free_pkts[hlid] -
- lnk->prev_freed_pkts;
-
- lnk->prev_freed_pkts = status->counters.tx_lnk_free_pkts[hlid];
- lnk->allocated_pkts -= cnt;
-
+ for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS)
wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
- lnk->allocated_pkts);
- }
+ wl->links[hlid].allocated_pkts);
}
static int wlcore_fw_status(struct wl1271 *wl,
@@ -389,6 +386,7 @@ static int wlcore_fw_status(struct wl1271 *wl,
int i;
size_t status_len;
int ret;
+ struct wl1271_link *lnk;
status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
sizeof(*status_2) + wl->fw_status_priv_len;
@@ -414,6 +412,17 @@ static int wlcore_fw_status(struct wl1271 *wl,
wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
}
+
+ for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) {
+ lnk = &wl->links[i];
+ /* prevent wrap-around in freed-packets counter */
+ lnk->allocated_pkts -=
+ (status_2->counters.tx_lnk_free_pkts[i] -
+ lnk->prev_freed_pkts) & 0xff;
+
+ lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i];
+ }
+
/* prevent wrap-around in total blocks counter */
if (likely(wl->tx_blocks_freed <=
le32_to_cpu(status_2->total_released_blks)))
@@ -466,6 +475,8 @@ static int wlcore_fw_status(struct wl1271 *wl,
wl->time_offset = (timespec_to_ns(&ts) >> 10) -
(s64)le32_to_cpu(status_2->fw_localtime);
+ wl->fw_fast_lnk_map = le32_to_cpu(status_2->link_fast_bitmap);
+
return 0;
}
@@ -802,11 +813,13 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
/*
* Make sure the chip is awake and the logger isn't active.
- * Do not send a stop fwlog command if the fw is hanged.
+ * Do not send a stop fwlog command if the fw is hanged or if
+ * dbgpins are used (due to some fw bug).
*/
if (wl1271_ps_elp_wakeup(wl))
goto out;
- if (!wl->watchdog_recovery)
+ if (!wl->watchdog_recovery &&
+ wl->conf.fwlog.output != WL12XX_FWLOG_OUTPUT_DBG_PINS)
wl12xx_cmd_stop_fwlog(wl);
/* Read the first memory block address */
@@ -874,7 +887,8 @@ static void wlcore_print_recovery(struct wl1271 *wl)
if (ret < 0)
return;
- wl1271_info("pc: 0x%x, hint_sts: 0x%08x", pc, hint_sts);
+ wl1271_info("pc: 0x%x, hint_sts: 0x%08x count: %d",
+ pc, hint_sts, ++wl->recovery_count);
wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
}
@@ -897,10 +911,10 @@ static void wl1271_recovery_work(struct work_struct *work)
wlcore_print_recovery(wl);
}
- BUG_ON(bug_on_recovery &&
+ BUG_ON(wl->conf.recovery.bug_on_recovery &&
!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
- if (no_recovery) {
+ if (wl->conf.recovery.no_recovery) {
wl1271_info("No recovery (chosen on module load). Fw will remain stuck.");
goto out_unlock;
}
@@ -920,11 +934,6 @@ static void wl1271_recovery_work(struct work_struct *work)
/* Prevent spurious TX during FW restart */
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
- if (wl->sched_scanning) {
- ieee80211_sched_scan_stopped(wl->hw);
- wl->sched_scanning = false;
- }
-
/* reboot the chipset */
while (!list_empty(&wl->wlvif_list)) {
wlvif = list_first_entry(&wl->wlvif_list,
@@ -1141,7 +1150,6 @@ int wl1271_plt_stop(struct wl1271 *wl)
cancel_work_sync(&wl->recovery_work);
cancel_delayed_work_sync(&wl->elp_work);
cancel_delayed_work_sync(&wl->tx_watchdog_work);
- cancel_delayed_work_sync(&wl->connection_loss_work);
mutex_lock(&wl->mutex);
wl1271_power_off(wl);
@@ -1169,9 +1177,13 @@ static void wl1271_op_tx(struct ieee80211_hw *hw,
int q, mapping;
u8 hlid;
- if (vif)
- wlvif = wl12xx_vif_to_data(vif);
+ if (!vif) {
+ wl1271_debug(DEBUG_TX, "DROP skb with no vif");
+ ieee80211_free_txskb(hw, skb);
+ return;
+ }
+ wlvif = wl12xx_vif_to_data(vif);
mapping = skb_get_queue_mapping(skb);
q = wl1271_tx_get_queue(mapping);
@@ -1185,9 +1197,9 @@ static void wl1271_op_tx(struct ieee80211_hw *hw,
* allow these packets through.
*/
if (hlid == WL12XX_INVALID_LINK_ID ||
- (wlvif && !test_bit(hlid, wlvif->links_map)) ||
- (wlcore_is_queue_stopped(wl, q) &&
- !wlcore_is_queue_stopped_by_reason(wl, q,
+ (!test_bit(hlid, wlvif->links_map)) ||
+ (wlcore_is_queue_stopped_locked(wl, wlvif, q) &&
+ !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q,
WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
ieee80211_free_txskb(hw, skb);
@@ -1199,16 +1211,17 @@ static void wl1271_op_tx(struct ieee80211_hw *hw,
skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
wl->tx_queue_count[q]++;
+ wlvif->tx_queue_count[q]++;
/*
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
- if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK &&
- !wlcore_is_queue_stopped_by_reason(wl, q,
+ if (wlvif->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK &&
+ !wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, q,
WLCORE_QUEUE_STOP_REASON_WATERMARK)) {
wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
- wlcore_stop_queue_locked(wl, q,
+ wlcore_stop_queue_locked(wl, wlvif, q,
WLCORE_QUEUE_STOP_REASON_WATERMARK);
}
@@ -1843,11 +1856,10 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
cancel_work_sync(&wl->tx_work);
cancel_delayed_work_sync(&wl->elp_work);
cancel_delayed_work_sync(&wl->tx_watchdog_work);
- cancel_delayed_work_sync(&wl->connection_loss_work);
/* let's notify MAC80211 about the remaining pending TX frames */
- wl12xx_tx_reset(wl);
mutex_lock(&wl->mutex);
+ wl12xx_tx_reset(wl);
wl1271_power_off(wl);
/*
@@ -1870,14 +1882,17 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
wl->time_offset = 0;
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
- wl->sched_scanning = false;
wl->sleep_auth = WL1271_PSM_ILLEGAL;
memset(wl->roles_map, 0, sizeof(wl->roles_map));
memset(wl->links_map, 0, sizeof(wl->links_map));
memset(wl->roc_map, 0, sizeof(wl->roc_map));
+ memset(wl->session_ids, 0, sizeof(wl->session_ids));
wl->active_sta_count = 0;
+ wl->active_link_count = 0;
/* The system link is always allocated */
+ wl->links[WL12XX_SYSTEM_HLID].allocated_pkts = 0;
+ wl->links[WL12XX_SYSTEM_HLID].prev_freed_pkts = 0;
__set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
/*
@@ -1903,6 +1918,12 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
wl->tx_res_if = NULL;
kfree(wl->target_mem_map);
wl->target_mem_map = NULL;
+
+ /*
+ * FW channels must be re-calibrated after recovery,
+ * clear the last Reg-Domain channel configuration.
+ */
+ memset(wl->reg_ch_conf_last, 0, sizeof(wl->reg_ch_conf_last));
}
static void wlcore_op_stop(struct ieee80211_hw *hw)
@@ -1918,6 +1939,71 @@ static void wlcore_op_stop(struct ieee80211_hw *hw)
mutex_unlock(&wl->mutex);
}
+static void wlcore_channel_switch_work(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct wl1271 *wl;
+ struct ieee80211_vif *vif;
+ struct wl12xx_vif *wlvif;
+ int ret;
+
+ dwork = container_of(work, struct delayed_work, work);
+ wlvif = container_of(dwork, struct wl12xx_vif, channel_switch_work);
+ wl = wlvif->wl;
+
+ wl1271_info("channel switch failed (role_id: %d).", wlvif->role_id);
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ /* check the channel switch is still ongoing */
+ if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags))
+ goto out;
+
+ vif = wl12xx_wlvif_to_vif(wlvif);
+ ieee80211_chswitch_done(vif, false);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ wl12xx_cmd_stop_channel_switch(wl, wlvif);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static void wlcore_connection_loss_work(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct wl1271 *wl;
+ struct ieee80211_vif *vif;
+ struct wl12xx_vif *wlvif;
+
+ dwork = container_of(work, struct delayed_work, work);
+ wlvif = container_of(dwork, struct wl12xx_vif, connection_loss_work);
+ wl = wlvif->wl;
+
+ wl1271_info("Connection loss work (role_id: %d).", wlvif->role_id);
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ /* Call mac80211 connection loss */
+ if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+ goto out;
+
+ vif = wl12xx_wlvif_to_vif(wlvif);
+ ieee80211_connection_loss(vif);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
{
u8 policy = find_first_zero_bit(wl->rate_policies_map,
@@ -2037,15 +2123,15 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
wl12xx_allocate_rate_policy(wl,
&wlvif->ap.ucast_rate_idx[i]);
- wlvif->basic_rate_set = CONF_TX_AP_ENABLED_RATES;
+ wlvif->basic_rate_set = CONF_TX_ENABLED_RATES;
/*
* TODO: check if basic_rate shouldn't be
* wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
* instead (the same thing for STA above).
*/
- wlvif->basic_rate = CONF_TX_AP_ENABLED_RATES;
+ wlvif->basic_rate = CONF_TX_ENABLED_RATES;
/* TODO: this seems to be used only for STA, check it */
- wlvif->rate_set = CONF_TX_AP_ENABLED_RATES;
+ wlvif->rate_set = CONF_TX_ENABLED_RATES;
}
wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
@@ -2065,6 +2151,10 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wl1271_rx_streaming_enable_work);
INIT_WORK(&wlvif->rx_streaming_disable_work,
wl1271_rx_streaming_disable_work);
+ INIT_DELAYED_WORK(&wlvif->channel_switch_work,
+ wlcore_channel_switch_work);
+ INIT_DELAYED_WORK(&wlvif->connection_loss_work,
+ wlcore_connection_loss_work);
INIT_LIST_HEAD(&wlvif->list);
setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
@@ -2072,7 +2162,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
return 0;
}
-static bool wl12xx_init_fw(struct wl1271 *wl)
+static int wl12xx_init_fw(struct wl1271 *wl)
{
int retries = WL1271_BOOT_RETRIES;
bool booted = false;
@@ -2138,7 +2228,7 @@ power_off:
wl->state = WLCORE_STATE_ON;
out:
- return booted;
+ return ret;
}
static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
@@ -2198,6 +2288,81 @@ static void wl12xx_force_active_psm(struct wl1271 *wl)
}
}
+struct wlcore_hw_queue_iter_data {
+ unsigned long hw_queue_map[BITS_TO_LONGS(WLCORE_NUM_MAC_ADDRESSES)];
+ /* current vif */
+ struct ieee80211_vif *vif;
+ /* is the current vif among those iterated */
+ bool cur_running;
+};
+
+static void wlcore_hw_queue_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct wlcore_hw_queue_iter_data *iter_data = data;
+
+ if (WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE))
+ return;
+
+ if (iter_data->cur_running || vif == iter_data->vif) {
+ iter_data->cur_running = true;
+ return;
+ }
+
+ __set_bit(vif->hw_queue[0] / NUM_TX_QUEUES, iter_data->hw_queue_map);
+}
+
+static int wlcore_allocate_hw_queue_base(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif)
+{
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+ struct wlcore_hw_queue_iter_data iter_data = {};
+ int i, q_base;
+
+ iter_data.vif = vif;
+
+ /* mark all bits taken by active interfaces */
+ ieee80211_iterate_active_interfaces_atomic(wl->hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ wlcore_hw_queue_iter, &iter_data);
+
+ /* the current vif is already running in mac80211 (resume/recovery) */
+ if (iter_data.cur_running) {
+ wlvif->hw_queue_base = vif->hw_queue[0];
+ wl1271_debug(DEBUG_MAC80211,
+ "using pre-allocated hw queue base %d",
+ wlvif->hw_queue_base);
+
+ /* interface type might have changed type */
+ goto adjust_cab_queue;
+ }
+
+ q_base = find_first_zero_bit(iter_data.hw_queue_map,
+ WLCORE_NUM_MAC_ADDRESSES);
+ if (q_base >= WLCORE_NUM_MAC_ADDRESSES)
+ return -EBUSY;
+
+ wlvif->hw_queue_base = q_base * NUM_TX_QUEUES;
+ wl1271_debug(DEBUG_MAC80211, "allocating hw queue base: %d",
+ wlvif->hw_queue_base);
+
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ wl->queue_stop_reasons[wlvif->hw_queue_base + i] = 0;
+ /* register hw queues in mac80211 */
+ vif->hw_queue[i] = wlvif->hw_queue_base + i;
+ }
+
+adjust_cab_queue:
+ /* the last places are reserved for cab queues per interface */
+ if (wlvif->bss_type == BSS_TYPE_AP_BSS)
+ vif->cab_queue = NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES +
+ wlvif->hw_queue_base / NUM_TX_QUEUES;
+ else
+ vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+
+ return 0;
+}
+
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -2206,7 +2371,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct vif_counter_data vif_count;
int ret = 0;
u8 role_type;
- bool booted = false;
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
@@ -2244,6 +2408,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+ ret = wlcore_allocate_hw_queue_base(wl, wlvif);
+ if (ret < 0)
+ goto out;
+
if (wl12xx_need_fw_change(wl, vif_count, true)) {
wl12xx_force_active_psm(wl);
set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags);
@@ -2263,11 +2431,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
*/
memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
- booted = wl12xx_init_fw(wl);
- if (!booted) {
- ret = -EINVAL;
+ ret = wl12xx_init_fw(wl);
+ if (ret < 0)
goto out;
- }
}
ret = wl12xx_cmd_role_enable(wl, vif->addr,
@@ -2314,7 +2480,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl1271_info("down");
if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
- wl->scan_vif == vif) {
+ wl->scan_wlvif == wlvif) {
/*
* Rearm the tx watchdog just before idling scan. This
* prevents just-finished scans from triggering the watchdog
@@ -2323,11 +2489,21 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl->scan.state = WL1271_SCAN_STATE_IDLE;
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
- wl->scan_vif = NULL;
+ wl->scan_wlvif = NULL;
wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, true);
}
+ if (wl->sched_vif == wlvif) {
+ ieee80211_sched_scan_stopped(wl->hw);
+ wl->sched_vif = NULL;
+ }
+
+ if (wl->roc_vif == vif) {
+ wl->roc_vif = NULL;
+ ieee80211_remain_on_channel_expired(wl->hw);
+ }
+
if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
/* disable active roles */
ret = wl1271_ps_elp_wakeup(wl);
@@ -2396,9 +2572,6 @@ deinit:
/* Configure for power according to debugfs */
if (sta_auth != WL1271_PSM_ILLEGAL)
wl1271_acx_sleep_auth(wl, sta_auth);
- /* Configure for power always on */
- else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
- wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
/* Configure for ELP power saving */
else
wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
@@ -2410,6 +2583,7 @@ unlock:
del_timer_sync(&wlvif->rx_streaming_timer);
cancel_work_sync(&wlvif->rx_streaming_enable_work);
cancel_work_sync(&wlvif->rx_streaming_disable_work);
+ cancel_delayed_work_sync(&wlvif->connection_loss_work);
mutex_lock(&wl->mutex);
}
@@ -2468,8 +2642,7 @@ static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
return ret;
}
-static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- bool set_assoc)
+static int wlcore_join(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
int ret;
bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
@@ -2489,18 +2662,111 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
/* clear encryption type */
wlvif->encryption_type = KEY_NONE;
- if (set_assoc)
- set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
-
if (is_ibss)
ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
- else
+ else {
+ if (wl->quirks & WLCORE_QUIRK_START_STA_FAILS) {
+ /*
+ * TODO: this is an ugly workaround for wl12xx fw
+ * bug - we are not able to tx/rx after the first
+ * start_sta, so make dummy start+stop calls,
+ * and then call start_sta again.
+ * this should be fixed in the fw.
+ */
+ wl12xx_cmd_role_start_sta(wl, wlvif);
+ wl12xx_cmd_role_stop_sta(wl, wlvif);
+ }
+
ret = wl12xx_cmd_role_start_sta(wl, wlvif);
+ }
+
+ return ret;
+}
+
+static int wl1271_ssid_set(struct wl12xx_vif *wlvif, struct sk_buff *skb,
+ int offset)
+{
+ u8 ssid_len;
+ const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
+ skb->len - offset);
+
+ if (!ptr) {
+ wl1271_error("No SSID in IEs!");
+ return -ENOENT;
+ }
+
+ ssid_len = ptr[1];
+ if (ssid_len > IEEE80211_MAX_SSID_LEN) {
+ wl1271_error("SSID is too long!");
+ return -EINVAL;
+ }
+
+ wlvif->ssid_len = ssid_len;
+ memcpy(wlvif->ssid, ptr+2, ssid_len);
+ return 0;
+}
+
+static int wlcore_set_ssid(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+ struct sk_buff *skb;
+ int ieoffset;
+
+ /* we currently only support setting the ssid from the ap probe req */
+ if (wlvif->bss_type != BSS_TYPE_STA_BSS)
+ return -EINVAL;
+
+ skb = ieee80211_ap_probereq_get(wl->hw, vif);
+ if (!skb)
+ return -EINVAL;
+
+ ieoffset = offsetof(struct ieee80211_mgmt,
+ u.probe_req.variable);
+ wl1271_ssid_set(wlvif, skb, ieoffset);
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 sta_rate_set)
+{
+ int ieoffset;
+ int ret;
+
+ wlvif->aid = bss_conf->aid;
+ wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef);
+ wlvif->beacon_int = bss_conf->beacon_int;
+ wlvif->wmm_enabled = bss_conf->qos;
+
+ set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
+
+ /*
+ * with wl1271, we don't need to update the
+ * beacon_int and dtim_period, because the firmware
+ * updates it by itself when the first beacon is
+ * received after a join.
+ */
+ ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
if (ret < 0)
- goto out;
+ return ret;
- if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
- goto out;
+ /*
+ * Get a template for hardware connection maintenance
+ */
+ dev_kfree_skb(wlvif->probereq);
+ wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
+ wlvif,
+ NULL);
+ ieoffset = offsetof(struct ieee80211_mgmt,
+ u.probe_req.variable);
+ wl1271_ssid_set(wlvif, wlvif->probereq, ieoffset);
+
+ /* enable the connection monitoring feature */
+ ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
+ if (ret < 0)
+ return ret;
/*
* The join command disable the keep-alive mode, shut down its process,
@@ -2510,35 +2776,83 @@ static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
*/
ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
if (ret < 0)
- goto out;
+ return ret;
ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
if (ret < 0)
- goto out;
+ return ret;
ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
if (ret < 0)
- goto out;
+ return ret;
ret = wl1271_acx_keep_alive_config(wl, wlvif,
wlvif->sta.klv_template_id,
ACX_KEEP_ALIVE_TPL_VALID);
if (ret < 0)
- goto out;
+ return ret;
+
+ /*
+ * The default fw psm configuration is AUTO, while mac80211 default
+ * setting is off (ACTIVE), so sync the fw with the correct value.
+ */
+ ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE);
+ if (ret < 0)
+ return ret;
+
+ if (sta_rate_set) {
+ wlvif->rate_set =
+ wl1271_tx_enabled_rates_get(wl,
+ sta_rate_set,
+ wlvif->band);
+ ret = wl1271_acx_sta_rate_policies(wl, wlvif);
+ if (ret < 0)
+ return ret;
+ }
-out:
return ret;
}
-static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
int ret;
+ bool sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
+
+ /* make sure we are connected (sta) joined */
+ if (sta &&
+ !test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+ return false;
+
+ /* make sure we are joined (ibss) */
+ if (!sta &&
+ test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags))
+ return false;
+
+ if (sta) {
+ /* use defaults when not associated */
+ wlvif->aid = 0;
+
+ /* free probe-request template */
+ dev_kfree_skb(wlvif->probereq);
+ wlvif->probereq = NULL;
+
+ /* disable connection monitor features */
+ ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
+ if (ret < 0)
+ return ret;
+
+ /* Disable the keep-alive feature */
+ ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
+ if (ret < 0)
+ return ret;
+ }
if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
- wl12xx_cmd_stop_channel_switch(wl);
+ wl12xx_cmd_stop_channel_switch(wl, wlvif);
ieee80211_chswitch_done(vif, false);
+ cancel_delayed_work(&wlvif->channel_switch_work);
}
/* invalidate keep-alive template */
@@ -2546,17 +2860,11 @@ static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wlvif->sta.klv_template_id,
ACX_KEEP_ALIVE_TPL_INVALID);
- /* to stop listening to a channel, we disconnect */
- ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
- if (ret < 0)
- goto out;
-
/* reset TX security counters on a clean disconnect */
wlvif->tx_security_last_seq_lsb = 0;
wlvif->tx_security_seq = 0;
-out:
- return ret;
+ return 0;
}
static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
@@ -2565,147 +2873,10 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wlvif->rate_set = wlvif->basic_rate_set;
}
-static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- bool idle)
-{
- int ret;
- bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
-
- if (idle == cur_idle)
- return 0;
-
- if (idle) {
- /* no need to croc if we weren't busy (e.g. during boot) */
- if (wl12xx_dev_role_started(wlvif)) {
- ret = wl12xx_stop_dev(wl, wlvif);
- if (ret < 0)
- goto out;
- }
- wlvif->rate_set =
- wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
- ret = wl1271_acx_sta_rate_policies(wl, wlvif);
- if (ret < 0)
- goto out;
- clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
- } else {
- /* The current firmware only supports sched_scan in idle */
- if (wl->sched_scanning) {
- wl1271_scan_sched_scan_stop(wl, wlvif);
- ieee80211_sched_scan_stopped(wl->hw);
- }
-
- ret = wl12xx_start_dev(wl, wlvif);
- if (ret < 0)
- goto out;
- set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
- }
-
-out:
- return ret;
-}
-
static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct ieee80211_conf *conf, u32 changed)
{
- bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
- int channel, ret;
-
- channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
-
- /* if the channel changes while joined, join again */
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
- ((wlvif->band != conf->channel->band) ||
- (wlvif->channel != channel) ||
- (wlvif->channel_type != conf->channel_type))) {
- /* send all pending packets */
- ret = wlcore_tx_work_locked(wl);
- if (ret < 0)
- return ret;
-
- wlvif->band = conf->channel->band;
- wlvif->channel = channel;
- wlvif->channel_type = conf->channel_type;
-
- if (is_ap) {
- wl1271_set_band_rate(wl, wlvif);
- ret = wl1271_init_ap_rates(wl, wlvif);
- if (ret < 0)
- wl1271_error("AP rate policy change failed %d",
- ret);
- } else {
- /*
- * FIXME: the mac80211 should really provide a fixed
- * rate to use here. for now, just use the smallest
- * possible rate for the band as a fixed rate for
- * association frames and other control messages.
- */
- if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
- wl1271_set_band_rate(wl, wlvif);
-
- wlvif->basic_rate =
- wl1271_tx_min_rate_get(wl,
- wlvif->basic_rate_set);
- ret = wl1271_acx_sta_rate_policies(wl, wlvif);
- if (ret < 0)
- wl1271_warning("rate policy for channel "
- "failed %d", ret);
-
- /*
- * change the ROC channel. do it only if we are
- * not idle. otherwise, CROC will be called
- * anyway.
- */
- if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED,
- &wlvif->flags) &&
- wl12xx_dev_role_started(wlvif) &&
- !(conf->flags & IEEE80211_CONF_IDLE)) {
- ret = wl12xx_stop_dev(wl, wlvif);
- if (ret < 0)
- return ret;
-
- ret = wl12xx_start_dev(wl, wlvif);
- if (ret < 0)
- return ret;
- }
- }
- }
-
- if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
-
- if ((conf->flags & IEEE80211_CONF_PS) &&
- test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
- !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
-
- int ps_mode;
- char *ps_mode_str;
-
- if (wl->conf.conn.forced_ps) {
- ps_mode = STATION_POWER_SAVE_MODE;
- ps_mode_str = "forced";
- } else {
- ps_mode = STATION_AUTO_PS_MODE;
- ps_mode_str = "auto";
- }
-
- wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
-
- ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
-
- if (ret < 0)
- wl1271_warning("enter %s ps failed %d",
- ps_mode_str, ret);
-
- } else if (!(conf->flags & IEEE80211_CONF_PS) &&
- test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
-
- wl1271_debug(DEBUG_PSM, "auto ps disabled");
-
- ret = wl1271_ps_set_mode(wl, wlvif,
- STATION_ACTIVE_MODE);
- if (ret < 0)
- wl1271_warning("exit auto ps failed %d", ret);
- }
- }
+ int ret;
if (conf->power_level != wlvif->power_level) {
ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
@@ -2723,37 +2894,17 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif;
struct ieee80211_conf *conf = &hw->conf;
- int channel, ret = 0;
-
- channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ int ret = 0;
- wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
+ wl1271_debug(DEBUG_MAC80211, "mac80211 config psm %s power %d %s"
" changed 0x%x",
- channel,
conf->flags & IEEE80211_CONF_PS ? "on" : "off",
conf->power_level,
conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
changed);
- /*
- * mac80211 will go to idle nearly immediately after transmitting some
- * frames, such as the deauth. To make sure those frames reach the air,
- * wait here until the TX queue is fully flushed.
- */
- if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
- ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
- (conf->flags & IEEE80211_CONF_IDLE)))
- wl1271_tx_flush(wl);
-
mutex_lock(&wl->mutex);
- /* we support configuring the channel and band even while off */
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- wl->band = conf->channel->band;
- wl->channel = channel;
- wl->channel_type = conf->channel_type;
- }
-
if (changed & IEEE80211_CONF_CHANGE_POWER)
wl->power_level = conf->power_level;
@@ -3073,10 +3224,7 @@ static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* stop the queues and flush to ensure the next packets are
* in sync with FW spare block accounting
*/
- mutex_lock(&wl->mutex);
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
- mutex_unlock(&wl->mutex);
-
wl1271_tx_flush(wl);
}
@@ -3202,6 +3350,29 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
}
EXPORT_SYMBOL_GPL(wlcore_set_key);
+void wlcore_regdomain_config(struct wl1271 *wl)
+{
+ int ret;
+
+ if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF))
+ return;
+
+ mutex_lock(&wl->mutex);
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wlcore_cmd_regdomain_config_locked(wl);
+ if (ret < 0) {
+ wl12xx_queue_recovery_work(wl);
+ goto out;
+ }
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_scan_request *req)
@@ -3241,7 +3412,7 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
goto out_sleep;
}
- ret = wl1271_scan(hw->priv, vif, ssid, len, req);
+ ret = wlcore_scan(hw->priv, vif, ssid, len, req);
out_sleep:
wl1271_ps_elp_sleep(wl);
out:
@@ -3254,6 +3425,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
@@ -3271,7 +3443,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
goto out;
if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
- ret = wl1271_scan_stop(wl);
+ ret = wl->ops->scan_stop(wl, wlvif);
if (ret < 0)
goto out_sleep;
}
@@ -3284,7 +3456,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
wl->scan.state = WL1271_SCAN_STATE_IDLE;
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
- wl->scan_vif = NULL;
+ wl->scan_wlvif = NULL;
wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, true);
@@ -3318,15 +3490,11 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
+ ret = wl->ops->sched_scan_start(wl, wlvif, req, ies);
if (ret < 0)
goto out_sleep;
- ret = wl1271_scan_sched_scan_start(wl, wlvif);
- if (ret < 0)
- goto out_sleep;
-
- wl->sched_scanning = true;
+ wl->sched_vif = wlvif;
out_sleep:
wl1271_ps_elp_sleep(wl);
@@ -3353,7 +3521,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- wl1271_scan_sched_scan_stop(wl, wlvif);
+ wl->ops->sched_scan_stop(wl, wlvif);
wl1271_ps_elp_sleep(wl);
out:
@@ -3418,30 +3586,6 @@ out:
return ret;
}
-static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
- int offset)
-{
- struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
- u8 ssid_len;
- const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
- skb->len - offset);
-
- if (!ptr) {
- wl1271_error("No SSID in IEs!");
- return -ENOENT;
- }
-
- ssid_len = ptr[1];
- if (ssid_len > IEEE80211_MAX_SSID_LEN) {
- wl1271_error("SSID is too long!");
- return -EINVAL;
- }
-
- wlvif->ssid_len = ssid_len;
- memcpy(wlvif->ssid, ptr+2, ssid_len);
- return 0;
-}
-
static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
{
int len;
@@ -3622,7 +3766,7 @@ static int wlcore_set_beacon_template(struct wl1271 *wl,
wl1271_debug(DEBUG_MASTER, "beacon updated");
- ret = wl1271_ssid_set(vif, beacon, ieoffset);
+ ret = wl1271_ssid_set(wlvif, beacon, ieoffset);
if (ret < 0) {
dev_kfree_skb(beacon);
goto out;
@@ -3639,6 +3783,12 @@ static int wlcore_set_beacon_template(struct wl1271 *wl,
goto out;
}
+ wlvif->wmm_enabled =
+ cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+ WLAN_OUI_TYPE_MICROSOFT_WMM,
+ beacon->data + ieoffset,
+ beacon->len - ieoffset);
+
/*
* In case we already have a probe-resp beacon set explicitly
* by usermode, don't use the beacon data.
@@ -3692,7 +3842,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
int ret = 0;
- if ((changed & BSS_CHANGED_BEACON_INT)) {
+ if (changed & BSS_CHANGED_BEACON_INT) {
wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
bss_conf->beacon_int);
@@ -3705,7 +3855,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
wl1271_ap_set_probe_resp_tmpl(wl, rate, vif);
}
- if ((changed & BSS_CHANGED_BEACON)) {
+ if (changed & BSS_CHANGED_BEACON) {
ret = wlcore_set_beacon_template(wl, vif, is_ap);
if (ret < 0)
goto out;
@@ -3726,7 +3876,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
int ret = 0;
- if ((changed & BSS_CHANGED_BASIC_RATES)) {
+ if (changed & BSS_CHANGED_BASIC_RATES) {
u32 rates = bss_conf->basic_rates;
wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
@@ -3757,7 +3907,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if (ret < 0)
goto out;
- if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
+ if (changed & BSS_CHANGED_BEACON_ENABLED) {
if (bss_conf->enable_beacon) {
if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
ret = wl12xx_cmd_role_start_ap(wl, wlvif);
@@ -3804,6 +3954,79 @@ out:
return;
}
+static int wlcore_set_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 sta_rate_set)
+{
+ u32 rates;
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211,
+ "changed_bssid: %pM, aid: %d, bcn_int: %d, brates: 0x%x sta_rate_set: 0x%x",
+ bss_conf->bssid, bss_conf->aid,
+ bss_conf->beacon_int,
+ bss_conf->basic_rates, sta_rate_set);
+
+ wlvif->beacon_int = bss_conf->beacon_int;
+ rates = bss_conf->basic_rates;
+ wlvif->basic_rate_set =
+ wl1271_tx_enabled_rates_get(wl, rates,
+ wlvif->band);
+ wlvif->basic_rate =
+ wl1271_tx_min_rate_get(wl,
+ wlvif->basic_rate_set);
+
+ if (sta_rate_set)
+ wlvif->rate_set =
+ wl1271_tx_enabled_rates_get(wl,
+ sta_rate_set,
+ wlvif->band);
+
+ /* we only support sched_scan while not connected */
+ if (wl->sched_vif == wlvif)
+ wl->ops->sched_scan_stop(wl, wlvif);
+
+ ret = wl1271_acx_sta_rate_policies(wl, wlvif);
+ if (ret < 0)
+ return ret;
+
+ ret = wl12xx_cmd_build_null_data(wl, wlvif);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1271_build_qos_null_data(wl, wl12xx_wlvif_to_vif(wlvif));
+ if (ret < 0)
+ return ret;
+
+ wlcore_set_ssid(wl, wlvif);
+
+ set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
+
+ return 0;
+}
+
+static int wlcore_clear_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ int ret;
+
+ /* revert back to minimum rates for the current band */
+ wl1271_set_band_rate(wl, wlvif);
+ wlvif->basic_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
+
+ ret = wl1271_acx_sta_rate_policies(wl, wlvif);
+ if (ret < 0)
+ return ret;
+
+ if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
+ test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) {
+ ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
+ if (ret < 0)
+ return ret;
+ }
+
+ clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
+ return 0;
+}
/* STA/IBSS mode changes */
static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
struct ieee80211_vif *vif,
@@ -3811,7 +4034,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
u32 changed)
{
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
- bool do_join = false, set_assoc = false;
+ bool do_join = false;
bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
bool ibss_joined = false;
u32 sta_rate_set = 0;
@@ -3832,9 +4055,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
ibss_joined = true;
} else {
- if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
- &wlvif->flags))
- wl1271_unjoin(wl, wlvif);
+ wlcore_unset_assoc(wl, wlvif);
+ wl12xx_cmd_role_stop_sta(wl, wlvif);
}
}
@@ -3852,13 +4074,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
do_join = true;
}
- if (changed & BSS_CHANGED_IDLE && !is_ibss) {
- ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
- if (ret < 0)
- wl1271_warning("idle mode change failed %d", ret);
- }
-
- if ((changed & BSS_CHANGED_CQM)) {
+ if (changed & BSS_CHANGED_CQM) {
bool enable = false;
if (bss_conf->cqm_rssi_thold)
enable = true;
@@ -3870,150 +4086,39 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
}
- if (changed & BSS_CHANGED_BSSID)
- if (!is_zero_ether_addr(bss_conf->bssid)) {
- ret = wl12xx_cmd_build_null_data(wl, wlvif);
- if (ret < 0)
- goto out;
-
- ret = wl1271_build_qos_null_data(wl, vif);
- if (ret < 0)
- goto out;
- }
-
- if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
+ if (changed & (BSS_CHANGED_BSSID | BSS_CHANGED_HT |
+ BSS_CHANGED_ASSOC)) {
rcu_read_lock();
sta = ieee80211_find_sta(vif, bss_conf->bssid);
- if (!sta)
- goto sta_not_found;
-
- /* save the supp_rates of the ap */
- sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
- if (sta->ht_cap.ht_supported)
- sta_rate_set |=
- (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
- (sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
- sta_ht_cap = sta->ht_cap;
- sta_exists = true;
-
-sta_not_found:
+ if (sta) {
+ u8 *rx_mask = sta->ht_cap.mcs.rx_mask;
+
+ /* save the supp_rates of the ap */
+ sta_rate_set = sta->supp_rates[wlvif->band];
+ if (sta->ht_cap.ht_supported)
+ sta_rate_set |=
+ (rx_mask[0] << HW_HT_RATES_OFFSET) |
+ (rx_mask[1] << HW_MIMO_RATES_OFFSET);
+ sta_ht_cap = sta->ht_cap;
+ sta_exists = true;
+ }
+
rcu_read_unlock();
}
- if ((changed & BSS_CHANGED_ASSOC)) {
- if (bss_conf->assoc) {
- u32 rates;
- int ieoffset;
- wlvif->aid = bss_conf->aid;
- wlvif->channel_type =
- cfg80211_get_chandef_type(&bss_conf->chandef);
- wlvif->beacon_int = bss_conf->beacon_int;
- do_join = true;
- set_assoc = true;
-
- /*
- * use basic rates from AP, and determine lowest rate
- * to use with control frames.
- */
- rates = bss_conf->basic_rates;
- wlvif->basic_rate_set =
- wl1271_tx_enabled_rates_get(wl, rates,
- wlvif->band);
- wlvif->basic_rate =
- wl1271_tx_min_rate_get(wl,
- wlvif->basic_rate_set);
- if (sta_rate_set)
- wlvif->rate_set =
- wl1271_tx_enabled_rates_get(wl,
- sta_rate_set,
- wlvif->band);
- ret = wl1271_acx_sta_rate_policies(wl, wlvif);
- if (ret < 0)
- goto out;
-
- /*
- * with wl1271, we don't need to update the
- * beacon_int and dtim_period, because the firmware
- * updates it by itself when the first beacon is
- * received after a join.
- */
- ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
+ if (changed & BSS_CHANGED_BSSID) {
+ if (!is_zero_ether_addr(bss_conf->bssid)) {
+ ret = wlcore_set_bssid(wl, wlvif, bss_conf,
+ sta_rate_set);
if (ret < 0)
goto out;
- /*
- * Get a template for hardware connection maintenance
- */
- dev_kfree_skb(wlvif->probereq);
- wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
- wlvif,
- NULL);
- ieoffset = offsetof(struct ieee80211_mgmt,
- u.probe_req.variable);
- wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
-
- /* enable the connection monitoring feature */
- ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
- if (ret < 0)
- goto out;
+ /* Need to update the BSSID (for filtering etc) */
+ do_join = true;
} else {
- /* use defaults when not associated */
- bool was_assoc =
- !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
- &wlvif->flags);
- bool was_ifup =
- !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
- &wlvif->flags);
- wlvif->aid = 0;
-
- /* free probe-request template */
- dev_kfree_skb(wlvif->probereq);
- wlvif->probereq = NULL;
-
- /* revert back to minimum rates for the current band */
- wl1271_set_band_rate(wl, wlvif);
- wlvif->basic_rate =
- wl1271_tx_min_rate_get(wl,
- wlvif->basic_rate_set);
- ret = wl1271_acx_sta_rate_policies(wl, wlvif);
- if (ret < 0)
- goto out;
-
- /* disable connection monitor features */
- ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
-
- /* Disable the keep-alive feature */
- ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
+ ret = wlcore_clear_bssid(wl, wlvif);
if (ret < 0)
goto out;
-
- /* restore the bssid filter and go to dummy bssid */
- if (was_assoc) {
- /*
- * we might have to disable roc, if there was
- * no IF_OPER_UP notification.
- */
- if (!was_ifup) {
- ret = wl12xx_croc(wl, wlvif->role_id);
- if (ret < 0)
- goto out;
- }
- /*
- * (we also need to disable roc in case of
- * roaming on the same channel. until we will
- * have a better flow...)
- */
- if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
- ret = wl12xx_croc(wl,
- wlvif->dev_role_id);
- if (ret < 0)
- goto out;
- }
-
- wl1271_unjoin(wl, wlvif);
- if (!bss_conf->idle)
- wl12xx_start_dev(wl, wlvif);
- }
}
}
@@ -4043,71 +4148,87 @@ sta_not_found:
goto out;
if (do_join) {
- ret = wl1271_join(wl, wlvif, set_assoc);
+ ret = wlcore_join(wl, wlvif);
if (ret < 0) {
wl1271_warning("cmd join failed %d", ret);
goto out;
}
+ }
- /* ROC until connected (after EAPOL exchange) */
- if (!is_ibss) {
- ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
+ if (changed & BSS_CHANGED_ASSOC) {
+ if (bss_conf->assoc) {
+ ret = wlcore_set_assoc(wl, wlvif, bss_conf,
+ sta_rate_set);
if (ret < 0)
goto out;
if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags))
wl12xx_set_authorized(wl, wlvif);
+ } else {
+ wlcore_unset_assoc(wl, wlvif);
}
- /*
- * stop device role if started (we might already be in
- * STA/IBSS role).
- */
- if (wl12xx_dev_role_started(wlvif)) {
- ret = wl12xx_stop_dev(wl, wlvif);
+ }
+
+ if (changed & BSS_CHANGED_PS) {
+ if ((bss_conf->ps) &&
+ test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
+ !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
+ int ps_mode;
+ char *ps_mode_str;
+
+ if (wl->conf.conn.forced_ps) {
+ ps_mode = STATION_POWER_SAVE_MODE;
+ ps_mode_str = "forced";
+ } else {
+ ps_mode = STATION_AUTO_PS_MODE;
+ ps_mode_str = "auto";
+ }
+
+ wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
+
+ ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
if (ret < 0)
- goto out;
+ wl1271_warning("enter %s ps failed %d",
+ ps_mode_str, ret);
+ } else if (!bss_conf->ps &&
+ test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
+ wl1271_debug(DEBUG_PSM, "auto ps disabled");
+
+ ret = wl1271_ps_set_mode(wl, wlvif,
+ STATION_ACTIVE_MODE);
+ if (ret < 0)
+ wl1271_warning("exit auto ps failed %d", ret);
}
}
/* Handle new association with HT. Do this after join. */
- if (sta_exists) {
- if ((changed & BSS_CHANGED_HT) &&
- (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
- ret = wl1271_acx_set_ht_capabilities(wl,
- &sta_ht_cap,
- true,
- wlvif->sta.hlid);
- if (ret < 0) {
- wl1271_warning("Set ht cap true failed %d",
- ret);
- goto out;
- }
+ if (sta_exists &&
+ (changed & BSS_CHANGED_HT)) {
+ bool enabled =
+ bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
+
+ ret = wlcore_hw_set_peer_cap(wl,
+ &sta_ht_cap,
+ enabled,
+ wlvif->rate_set,
+ wlvif->sta.hlid);
+ if (ret < 0) {
+ wl1271_warning("Set ht cap failed %d", ret);
+ goto out;
+
}
- /* handle new association without HT and disassociation */
- else if (changed & BSS_CHANGED_ASSOC) {
- ret = wl1271_acx_set_ht_capabilities(wl,
- &sta_ht_cap,
- false,
- wlvif->sta.hlid);
+
+ if (enabled) {
+ ret = wl1271_acx_set_ht_information(wl, wlvif,
+ bss_conf->ht_operation_mode);
if (ret < 0) {
- wl1271_warning("Set ht cap false failed %d",
+ wl1271_warning("Set ht information failed %d",
ret);
goto out;
}
}
}
- /* Handle HT information change. Done after join. */
- if ((changed & BSS_CHANGED_HT) &&
- (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
- ret = wl1271_acx_set_ht_information(wl, wlvif,
- bss_conf->ht_operation_mode);
- if (ret < 0) {
- wl1271_warning("Set ht information failed %d", ret);
- goto out;
- }
- }
-
/* Handle arp filtering. Done after join. */
if ((changed & BSS_CHANGED_ARP_FILTER) ||
(!is_ibss && (changed & BSS_CHANGED_QOS))) {
@@ -4115,8 +4236,7 @@ sta_not_found:
wlvif->sta.qos = bss_conf->qos;
WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
- if (bss_conf->arp_addr_cnt == 1 &&
- bss_conf->arp_filter_enabled) {
+ if (bss_conf->arp_addr_cnt == 1 && bss_conf->assoc) {
wlvif->ip_addr = addr;
/*
* The template should have been configured only upon
@@ -4157,15 +4277,15 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
int ret;
- wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
- (int)changed);
+ wl1271_debug(DEBUG_MAC80211, "mac80211 bss info role %d changed 0x%x",
+ wlvif->role_id, (int)changed);
/*
* make sure to cancel pending disconnections if our association
* state changed
*/
if (!is_ap && (changed & BSS_CHANGED_ASSOC))
- cancel_delayed_work_sync(&wl->connection_loss_work);
+ cancel_delayed_work_sync(&wlvif->connection_loss_work);
if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) &&
!bss_conf->enable_beacon)
@@ -4194,6 +4314,76 @@ out:
mutex_unlock(&wl->mutex);
}
+static int wlcore_op_add_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ wl1271_debug(DEBUG_MAC80211, "mac80211 add chanctx %d (type %d)",
+ ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
+ cfg80211_get_chandef_type(&ctx->def));
+ return 0;
+}
+
+static void wlcore_op_remove_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ wl1271_debug(DEBUG_MAC80211, "mac80211 remove chanctx %d (type %d)",
+ ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
+ cfg80211_get_chandef_type(&ctx->def));
+}
+
+static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *ctx,
+ u32 changed)
+{
+ wl1271_debug(DEBUG_MAC80211,
+ "mac80211 change chanctx %d (type %d) changed 0x%x",
+ ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
+ cfg80211_get_chandef_type(&ctx->def), changed);
+}
+
+static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct wl1271 *wl = hw->priv;
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ int channel = ieee80211_frequency_to_channel(
+ ctx->def.chan->center_freq);
+
+ wl1271_debug(DEBUG_MAC80211,
+ "mac80211 assign chanctx (role %d) %d (type %d)",
+ wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def));
+
+ mutex_lock(&wl->mutex);
+
+ wlvif->band = ctx->def.chan->band;
+ wlvif->channel = channel;
+ wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def);
+
+ /* update default rates according to the band */
+ wl1271_set_band_rate(wl, wlvif);
+
+ mutex_unlock(&wl->mutex);
+
+ return 0;
+}
+
+static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct wl1271 *wl = hw->priv;
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+
+ wl1271_debug(DEBUG_MAC80211,
+ "mac80211 unassign chanctx (role %d) %d (type %d)",
+ wlvif->role_id,
+ ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
+ cfg80211_get_chandef_type(&ctx->def));
+
+ wl1271_tx_flush(wl);
+}
+
static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
@@ -4321,8 +4511,6 @@ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
return;
clear_bit(hlid, wlvif->ap.sta_hlid_map);
- memset(wl->links[hlid].addr, 0, ETH_ALEN);
- wl->links[hlid].ba_bitmap = 0;
__clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
wl12xx_free_link(wl, wlvif, &hlid);
@@ -4382,6 +4570,45 @@ static int wl12xx_sta_remove(struct wl1271 *wl,
return ret;
}
+static void wlcore_roc_if_possible(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif)
+{
+ if (find_first_bit(wl->roc_map,
+ WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)
+ return;
+
+ if (WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID))
+ return;
+
+ wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel);
+}
+
+static void wlcore_update_inconn_sta(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct wl1271_station *wl_sta,
+ bool in_connection)
+{
+ if (in_connection) {
+ if (WARN_ON(wl_sta->in_connection))
+ return;
+ wl_sta->in_connection = true;
+ if (!wlvif->inconn_count++)
+ wlcore_roc_if_possible(wl, wlvif);
+ } else {
+ if (!wl_sta->in_connection)
+ return;
+
+ wl_sta->in_connection = false;
+ wlvif->inconn_count--;
+ if (WARN_ON(wlvif->inconn_count < 0))
+ return;
+
+ if (!wlvif->inconn_count)
+ if (test_bit(wlvif->role_id, wl->roc_map))
+ wl12xx_croc(wl, wlvif->role_id);
+ }
+}
+
static int wl12xx_update_sta_state(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_sta *sta,
@@ -4400,8 +4627,13 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
/* Add station (AP mode) */
if (is_ap &&
old_state == IEEE80211_STA_NOTEXIST &&
- new_state == IEEE80211_STA_NONE)
- return wl12xx_sta_add(wl, wlvif, sta);
+ new_state == IEEE80211_STA_NONE) {
+ ret = wl12xx_sta_add(wl, wlvif, sta);
+ if (ret)
+ return ret;
+
+ wlcore_update_inconn_sta(wl, wlvif, wl_sta, true);
+ }
/* Remove station (AP mode) */
if (is_ap &&
@@ -4409,35 +4641,59 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
new_state == IEEE80211_STA_NOTEXIST) {
/* must not fail */
wl12xx_sta_remove(wl, wlvif, sta);
- return 0;
+
+ wlcore_update_inconn_sta(wl, wlvif, wl_sta, false);
}
/* Authorize station (AP mode) */
if (is_ap &&
new_state == IEEE80211_STA_AUTHORIZED) {
- ret = wl12xx_cmd_set_peer_state(wl, hlid);
+ ret = wl12xx_cmd_set_peer_state(wl, wlvif, hlid);
if (ret < 0)
return ret;
ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
hlid);
- return ret;
+ if (ret)
+ return ret;
+
+ wlcore_update_inconn_sta(wl, wlvif, wl_sta, false);
}
/* Authorize station */
if (is_sta &&
new_state == IEEE80211_STA_AUTHORIZED) {
set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
- return wl12xx_set_authorized(wl, wlvif);
+ ret = wl12xx_set_authorized(wl, wlvif);
+ if (ret)
+ return ret;
}
if (is_sta &&
old_state == IEEE80211_STA_AUTHORIZED &&
new_state == IEEE80211_STA_ASSOC) {
clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags);
- return 0;
+ clear_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags);
}
+ /* clear ROCs on failure or authorization */
+ if (is_sta &&
+ (new_state == IEEE80211_STA_AUTHORIZED ||
+ new_state == IEEE80211_STA_NOTEXIST)) {
+ if (test_bit(wlvif->role_id, wl->roc_map))
+ wl12xx_croc(wl, wlvif->role_id);
+ }
+
+ if (is_sta &&
+ old_state == IEEE80211_STA_NOTEXIST &&
+ new_state == IEEE80211_STA_NONE) {
+ if (find_first_bit(wl->roc_map,
+ WL12XX_MAX_ROLES) >= WL12XX_MAX_ROLES) {
+ WARN_ON(wlvif->role_id == WL12XX_INVALID_ROLE_ID);
+ wl12xx_roc(wl, wlvif, wlvif->role_id,
+ wlvif->band, wlvif->channel);
+ }
+ }
return 0;
}
@@ -4502,18 +4758,18 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
hlid = wlvif->sta.hlid;
- ba_bitmap = &wlvif->sta.ba_rx_bitmap;
} else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
struct wl1271_station *wl_sta;
wl_sta = (struct wl1271_station *)sta->drv_priv;
hlid = wl_sta->hlid;
- ba_bitmap = &wl->links[hlid].ba_bitmap;
} else {
ret = -EINVAL;
goto out;
}
+ ba_bitmap = &wl->links[hlid].ba_bitmap;
+
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
@@ -4575,7 +4831,9 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
* Falling break here on purpose for all TX APDU commands.
*/
case IEEE80211_AMPDU_TX_START:
- case IEEE80211_AMPDU_TX_STOP:
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
case IEEE80211_AMPDU_TX_OPERATIONAL:
ret = -EINVAL;
break;
@@ -4665,12 +4923,23 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
/* TODO: change mac80211 to pass vif as param */
wl12xx_for_each_wlvif_sta(wl, wlvif) {
- ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
+ unsigned long delay_usec;
+
+ ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
+ if (ret)
+ goto out_sleep;
- if (!ret)
- set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
+ set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
+
+ /* indicate failure 5 seconds after channel switch time */
+ delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) *
+ ch_switch->count;
+ ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work,
+ usecs_to_jiffies(delay_usec) +
+ msecs_to_jiffies(5000));
}
+out_sleep:
wl1271_ps_elp_sleep(wl);
out:
@@ -4684,6 +4953,144 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop)
wl1271_tx_flush(wl);
}
+static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_channel *chan,
+ int duration)
+{
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ struct wl1271 *wl = hw->priv;
+ int channel, ret = 0;
+
+ channel = ieee80211_frequency_to_channel(chan->center_freq);
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 roc %d (%d)",
+ channel, wlvif->role_id);
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ /* return EBUSY if we can't ROC right now */
+ if (WARN_ON(wl->roc_vif ||
+ find_first_bit(wl->roc_map,
+ WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl12xx_start_dev(wl, wlvif, chan->band, channel);
+ if (ret < 0)
+ goto out_sleep;
+
+ wl->roc_vif = vif;
+ ieee80211_queue_delayed_work(hw, &wl->roc_complete_work,
+ msecs_to_jiffies(duration));
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+ return ret;
+}
+
+static int __wlcore_roc_completed(struct wl1271 *wl)
+{
+ struct wl12xx_vif *wlvif;
+ int ret;
+
+ /* already completed */
+ if (unlikely(!wl->roc_vif))
+ return 0;
+
+ wlvif = wl12xx_vif_to_data(wl->roc_vif);
+
+ if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
+ return -EBUSY;
+
+ ret = wl12xx_stop_dev(wl, wlvif);
+ if (ret < 0)
+ return ret;
+
+ wl->roc_vif = NULL;
+
+ return 0;
+}
+
+static int wlcore_roc_completed(struct wl1271 *wl)
+{
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211, "roc complete");
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = __wlcore_roc_completed(wl);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static void wlcore_roc_complete_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, roc_complete_work);
+
+ ret = wlcore_roc_completed(wl);
+ if (!ret)
+ ieee80211_remain_on_channel_expired(wl->hw);
+}
+
+static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw)
+{
+ struct wl1271 *wl = hw->priv;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 croc");
+
+ /* TODO: per-vif */
+ wl1271_tx_flush(wl);
+
+ /*
+ * we can't just flush_work here, because it might deadlock
+ * (as we might get called from the same workqueue)
+ */
+ cancel_delayed_work_sync(&wl->roc_complete_work);
+ wlcore_roc_completed(wl);
+
+ return 0;
+}
+
+static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ u32 changed)
+{
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ struct wl1271 *wl = hw->priv;
+
+ wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
+}
+
static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
@@ -4747,20 +5154,20 @@ static struct ieee80211_rate wl1271_rates[] = {
/* can't be const, mac80211 writes to this */
static struct ieee80211_channel wl1271_channels[] = {
- { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
- { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
- { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
- { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
- { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
- { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
- { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
- { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
- { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
- { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
- { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
- { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
- { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
- { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
+ { .hw_value = 1, .center_freq = 2412, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 2, .center_freq = 2417, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 3, .center_freq = 2422, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 4, .center_freq = 2427, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 5, .center_freq = 2432, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 6, .center_freq = 2437, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 7, .center_freq = 2442, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 8, .center_freq = 2447, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 9, .center_freq = 2452, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 10, .center_freq = 2457, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 11, .center_freq = 2462, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 12, .center_freq = 2467, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 13, .center_freq = 2472, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 14, .center_freq = 2484, .max_power = WLCORE_MAX_TXPWR },
};
/* can't be const, mac80211 writes to this */
@@ -4801,40 +5208,40 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = {
/* 5 GHz band channels for WL1273 */
static struct ieee80211_channel wl1271_channels_5ghz[] = {
- { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
- { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
- { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
- { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
- { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
- { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
- { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
- { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
- { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
- { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
- { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
- { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
- { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
- { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
- { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
- { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
- { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
- { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
- { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
- { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
- { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
- { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
- { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
- { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
- { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
- { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
- { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
- { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
- { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
- { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
- { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
- { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
- { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
- { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
+ { .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 36, .center_freq = 5180, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 38, .center_freq = 5190, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 40, .center_freq = 5200, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 42, .center_freq = 5210, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 44, .center_freq = 5220, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 46, .center_freq = 5230, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 48, .center_freq = 5240, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 52, .center_freq = 5260, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 56, .center_freq = 5280, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 60, .center_freq = 5300, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 64, .center_freq = 5320, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 100, .center_freq = 5500, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 104, .center_freq = 5520, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 108, .center_freq = 5540, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 112, .center_freq = 5560, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 116, .center_freq = 5580, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 120, .center_freq = 5600, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 124, .center_freq = 5620, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 128, .center_freq = 5640, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 132, .center_freq = 5660, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 136, .center_freq = 5680, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 140, .center_freq = 5700, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 149, .center_freq = 5745, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 153, .center_freq = 5765, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 157, .center_freq = 5785, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 161, .center_freq = 5805, .max_power = WLCORE_MAX_TXPWR },
+ { .hw_value = 165, .center_freq = 5825, .max_power = WLCORE_MAX_TXPWR },
};
static struct ieee80211_supported_band wl1271_band_5ghz = {
@@ -4875,6 +5282,14 @@ static const struct ieee80211_ops wl1271_ops = {
.set_bitrate_mask = wl12xx_set_bitrate_mask,
.channel_switch = wl12xx_op_channel_switch,
.flush = wlcore_op_flush,
+ .remain_on_channel = wlcore_op_remain_on_channel,
+ .cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel,
+ .add_chanctx = wlcore_op_add_chanctx,
+ .remove_chanctx = wlcore_op_remove_chanctx,
+ .change_chanctx = wlcore_op_change_chanctx,
+ .assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
+ .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
+ .sta_rc_update = wlcore_op_sta_rc_update,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@@ -5044,34 +5459,6 @@ static struct bin_attribute fwlog_attr = {
.read = wl1271_sysfs_read_fwlog,
};
-static void wl1271_connection_loss_work(struct work_struct *work)
-{
- struct delayed_work *dwork;
- struct wl1271 *wl;
- struct ieee80211_vif *vif;
- struct wl12xx_vif *wlvif;
-
- dwork = container_of(work, struct delayed_work, work);
- wl = container_of(dwork, struct wl1271, connection_loss_work);
-
- wl1271_info("Connection loss work.");
-
- mutex_lock(&wl->mutex);
-
- if (unlikely(wl->state != WLCORE_STATE_ON))
- goto out;
-
- /* Call mac80211 connection loss */
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
- if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
- goto out;
- vif = wl12xx_wlvif_to_vif(wlvif);
- ieee80211_connection_loss(vif);
- }
-out:
- mutex_unlock(&wl->mutex);
-}
-
static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic)
{
int i;
@@ -5117,7 +5504,7 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
ret = wl12xx_set_power_on(wl);
if (ret < 0)
- goto out;
+ return ret;
ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id);
if (ret < 0)
@@ -5207,10 +5594,9 @@ static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
},
};
-static const struct ieee80211_iface_combination
+static struct ieee80211_iface_combination
wlcore_iface_combinations[] = {
{
- .num_different_channels = 1,
.max_interfaces = 3,
.limits = wlcore_iface_limits,
.n_limits = ARRAY_SIZE(wlcore_iface_limits),
@@ -5219,6 +5605,7 @@ wlcore_iface_combinations[] = {
static int wl1271_init_ieee80211(struct wl1271 *wl)
{
+ int i;
static const u32 cipher_suites[] = {
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
@@ -5249,7 +5636,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_AP_LINK_PS |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
- IEEE80211_HW_SCAN_WHILE_IDLE;
+ IEEE80211_HW_QUEUE_CONTROL;
wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -5271,6 +5658,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
sizeof(struct ieee80211_header);
+ wl->hw->wiphy->max_remain_on_channel_duration = 5000;
+
wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
@@ -5279,6 +5668,22 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
ARRAY_SIZE(wl1271_channels_5ghz) >
WL1271_MAX_CHANNELS);
/*
+ * clear channel flags from the previous usage
+ * and restore max_power & max_antenna_gain values.
+ */
+ for (i = 0; i < ARRAY_SIZE(wl1271_channels); i++) {
+ wl1271_band_2ghz.channels[i].flags = 0;
+ wl1271_band_2ghz.channels[i].max_power = WLCORE_MAX_TXPWR;
+ wl1271_band_2ghz.channels[i].max_antenna_gain = 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wl1271_channels_5ghz); i++) {
+ wl1271_band_5ghz.channels[i].flags = 0;
+ wl1271_band_5ghz.channels[i].max_power = WLCORE_MAX_TXPWR;
+ wl1271_band_5ghz.channels[i].max_antenna_gain = 0;
+ }
+
+ /*
* We keep local copies of the band structs because we need to
* modify them on a per-device basis.
*/
@@ -5298,7 +5703,14 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&wl->bands[IEEE80211_BAND_5GHZ];
- wl->hw->queues = 4;
+ /*
+ * allow 4 queues per mac address we support +
+ * 1 cab queue per mac + one global offchannel Tx queue
+ */
+ wl->hw->queues = (NUM_TX_QUEUES + 1) * WLCORE_NUM_MAC_ADDRESSES + 1;
+
+ /* the last queue is the offchannel queue */
+ wl->hw->offchannel_tx_hw_queue = wl->hw->queues - 1;
wl->hw->max_rates = 1;
wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
@@ -5311,6 +5723,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
/* allowed interface combinations */
+ wlcore_iface_combinations[0].num_different_channels = wl->num_channels;
wl->hw->wiphy->iface_combinations = wlcore_iface_combinations;
wl->hw->wiphy->n_iface_combinations =
ARRAY_SIZE(wlcore_iface_combinations);
@@ -5327,7 +5740,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
#define WL1271_DEFAULT_CHANNEL 0
-struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size)
+struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
+ u32 mbox_size)
{
struct ieee80211_hw *hw;
struct wl1271 *wl;
@@ -5369,9 +5783,8 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size)
INIT_WORK(&wl->tx_work, wl1271_tx_work);
INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
+ INIT_DELAYED_WORK(&wl->roc_complete_work, wlcore_roc_complete_work);
INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work);
- INIT_DELAYED_WORK(&wl->connection_loss_work,
- wl1271_connection_loss_work);
wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
if (!wl->freezable_wq) {
@@ -5387,14 +5800,15 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size)
wl->flags = 0;
wl->sg_enabled = true;
wl->sleep_auth = WL1271_PSM_ILLEGAL;
+ wl->recovery_count = 0;
wl->hw_pg_ver = -1;
wl->ap_ps_map = 0;
wl->ap_fw_ps_map = 0;
wl->quirks = 0;
wl->platform_quirks = 0;
- wl->sched_scanning = false;
wl->system_hlid = WL12XX_SYSTEM_HLID;
wl->active_sta_count = 0;
+ wl->active_link_count = 0;
wl->fwlog_size = 0;
init_waitqueue_head(&wl->fwlog_waitq);
@@ -5434,14 +5848,24 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size)
goto err_dummy_packet;
}
- wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_KERNEL | GFP_DMA);
+ wl->mbox_size = mbox_size;
+ wl->mbox = kmalloc(wl->mbox_size, GFP_KERNEL | GFP_DMA);
if (!wl->mbox) {
ret = -ENOMEM;
goto err_fwlog;
}
+ wl->buffer_32 = kmalloc(sizeof(*wl->buffer_32), GFP_KERNEL);
+ if (!wl->buffer_32) {
+ ret = -ENOMEM;
+ goto err_mbox;
+ }
+
return hw;
+err_mbox:
+ kfree(wl->mbox);
+
err_fwlog:
free_page((unsigned long)wl->fwlog);
@@ -5480,6 +5904,8 @@ int wlcore_free_hw(struct wl1271 *wl)
device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
device_remove_file(wl->dev, &dev_attr_bt_coex_state);
+ kfree(wl->buffer_32);
+ kfree(wl->mbox);
free_page((unsigned long)wl->fwlog);
dev_kfree_skb(wl->dummy_packet);
free_pages((unsigned long)wl->aggr_buf, get_order(wl->aggr_buf_size));
@@ -5536,7 +5962,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
{
struct wl1271 *wl = context;
struct platform_device *pdev = wl->pdev;
- struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
+ struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data;
+ struct wl12xx_platform_data *pdata = pdev_data->pdata;
unsigned long irqflags;
int ret;
@@ -5565,8 +5992,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
wl->irq = platform_get_irq(pdev, 0);
wl->platform_quirks = pdata->platform_quirks;
- wl->set_power = pdata->set_power;
- wl->if_ops = pdata->ops;
+ wl->if_ops = pdev_data->if_ops;
if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
irqflags = IRQF_TRIGGER_RISING;
@@ -5712,10 +6138,10 @@ module_param_named(fwlog, fwlog_param, charp, 0);
MODULE_PARM_DESC(fwlog,
"FW logger options: continuous, ondemand, dbgpins or disable");
-module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
+module_param(bug_on_recovery, int, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
-module_param(no_recovery, bool, S_IRUSR | S_IWUSR);
+module_param(no_recovery, int, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck.");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c
index 4d1414a673fb..9b7b6e2e4fbc 100644
--- a/drivers/net/wireless/ti/wlcore/ps.c
+++ b/drivers/net/wireless/ti/wlcore/ps.c
@@ -151,9 +151,6 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
wl12xx_queue_recovery_work(wl);
ret = -ETIMEDOUT;
goto err;
- } else if (ret < 0) {
- wl1271_error("ELP wakeup completion error.");
- goto err;
}
}
@@ -242,11 +239,12 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
struct ieee80211_tx_info *info;
unsigned long flags;
int filtered[NUM_TX_QUEUES];
+ struct wl1271_link *lnk = &wl->links[hlid];
/* filter all frames currently in the low level queues for this hlid */
for (i = 0; i < NUM_TX_QUEUES; i++) {
filtered[i] = 0;
- while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
+ while ((skb = skb_dequeue(&lnk->tx_queue[i]))) {
filtered[i]++;
if (WARN_ON(wl12xx_is_dummy_packet(wl, skb)))
@@ -260,8 +258,11 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
}
spin_lock_irqsave(&wl->wl_lock, flags);
- for (i = 0; i < NUM_TX_QUEUES; i++)
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
wl->tx_queue_count[i] -= filtered[i];
+ if (lnk->wlvif)
+ lnk->wlvif->tx_queue_count[i] -= filtered[i];
+ }
spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_handle_tx_low_watermark(wl);
diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c
index 9ee0ec6fd1db..6791a1a6afba 100644
--- a/drivers/net/wireless/ti/wlcore/rx.c
+++ b/drivers/net/wireless/ti/wlcore/rx.c
@@ -92,11 +92,16 @@ static void wl1271_rx_status(struct wl1271 *wl,
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
RX_FLAG_DECRYPTED;
- if (unlikely(desc_err_code == 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");
+ wl1271_warning("Michael MIC error. Desc: 0x%x",
+ desc_err_code);
}
}
+
+ if (beacon)
+ wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel,
+ status->band);
}
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
@@ -108,7 +113,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
u8 *buf;
u8 beacon = 0;
u8 is_data = 0;
- u8 reserved = 0;
+ u8 reserved = 0, offset_to_data = 0;
u16 seq_num;
u32 pkt_data_len;
@@ -128,6 +133,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
if (rx_align == WLCORE_RX_BUF_UNALIGNED)
reserved = RX_BUF_ALIGN;
+ else if (rx_align == WLCORE_RX_BUF_PADDED)
+ offset_to_data = RX_BUF_ALIGN;
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) data;
@@ -139,19 +146,15 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
return 0;
}
- 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);
+ if (desc->status & WL1271_RX_DESC_DECRYPT_FAIL) {
+ hdr = (void *)(data + sizeof(*desc) + offset_to_data);
+ wl1271_warning("corrupted packet in RX: status: 0x%x len: %d",
+ desc->status & WL1271_RX_DESC_STATUS_MASK,
+ pkt_data_len);
+ wl1271_dump((DEBUG_RX|DEBUG_CMD), "PKT: ", data + sizeof(*desc),
+ min(pkt_data_len,
+ ieee80211_hdrlen(hdr->frame_control)));
return -EINVAL;
}
diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h
index 71eba1899915..3363f60fb7da 100644
--- a/drivers/net/wireless/ti/wlcore/rx.h
+++ b/drivers/net/wireless/ti/wlcore/rx.h
@@ -84,12 +84,11 @@
* Bits 3-5 - process_id tag (AP mode FW)
* Bits 6-7 - reserved
*/
-#define WL1271_RX_DESC_STATUS_MASK 0x03
+#define WL1271_RX_DESC_STATUS_MASK 0x07
#define WL1271_RX_DESC_SUCCESS 0x00
#define WL1271_RX_DESC_DECRYPT_FAIL 0x01
#define WL1271_RX_DESC_MIC_FAIL 0x02
-#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03
#define RX_MEM_BLOCK_MASK 0xFF
#define RX_BUF_SIZE_MASK 0xFFF00
diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c
index d00501493dfe..f407101e525b 100644
--- a/drivers/net/wireless/ti/wlcore/scan.c
+++ b/drivers/net/wireless/ti/wlcore/scan.c
@@ -35,7 +35,6 @@ void wl1271_scan_complete_work(struct work_struct *work)
{
struct delayed_work *dwork;
struct wl1271 *wl;
- struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif;
int ret;
@@ -52,8 +51,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
goto out;
- vif = wl->scan_vif;
- wlvif = wl12xx_vif_to_data(vif);
+ wlvif = wl->scan_wlvif;
/*
* Rearm the tx watchdog just before idling scan. This
@@ -64,7 +62,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
wl->scan.state = WL1271_SCAN_STATE_IDLE;
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan.req = NULL;
- wl->scan_vif = NULL;
+ wl->scan_wlvif = NULL;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
@@ -82,6 +80,8 @@ void wl1271_scan_complete_work(struct work_struct *work)
wl12xx_queue_recovery_work(wl);
}
+ wlcore_cmd_regdomain_config_locked(wl);
+
ieee80211_scan_completed(wl->hw, false);
out:
@@ -89,371 +89,99 @@ out:
}
-
-static int wl1271_get_scan_channels(struct wl1271 *wl,
- struct cfg80211_scan_request *req,
- struct basic_scan_channel_params *channels,
- enum ieee80211_band band, bool passive)
-{
- struct conf_scan_settings *c = &wl->conf.scan;
- int i, j;
- u32 flags;
-
- for (i = 0, j = 0;
- i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
- i++) {
- flags = req->channels[i]->flags;
-
- if (!test_bit(i, wl->scan.scanned_ch) &&
- !(flags & IEEE80211_CHAN_DISABLED) &&
- (req->channels[i]->band == band) &&
- /*
- * In passive scans, we scan all remaining
- * channels, even if not marked as such.
- * In active scans, we only scan channels not
- * marked as passive.
- */
- (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
- wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
- req->channels[i]->band,
- req->channels[i]->center_freq);
- wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
- req->channels[i]->hw_value,
- req->channels[i]->flags);
- wl1271_debug(DEBUG_SCAN,
- "max_antenna_gain %d, max_power %d",
- req->channels[i]->max_antenna_gain,
- req->channels[i]->max_power);
- wl1271_debug(DEBUG_SCAN, "beacon_found %d",
- req->channels[i]->beacon_found);
-
- if (!passive) {
- channels[j].min_duration =
- cpu_to_le32(c->min_dwell_time_active);
- channels[j].max_duration =
- cpu_to_le32(c->max_dwell_time_active);
- } else {
- channels[j].min_duration =
- cpu_to_le32(c->min_dwell_time_passive);
- channels[j].max_duration =
- cpu_to_le32(c->max_dwell_time_passive);
- }
- channels[j].early_termination = 0;
- channels[j].tx_power_att = req->channels[i]->max_power;
- channels[j].channel = req->channels[i]->hw_value;
-
- memset(&channels[j].bssid_lsb, 0xff, 4);
- memset(&channels[j].bssid_msb, 0xff, 2);
-
- /* Mark the channels we already used */
- set_bit(i, wl->scan.scanned_ch);
-
- j++;
- }
- }
-
- return j;
-}
-
-#define WL1271_NOTHING_TO_SCAN 1
-
-static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif,
- enum ieee80211_band band,
- bool passive, u32 basic_rate)
+static void wlcore_started_vifs_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
{
- struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
- struct wl1271_cmd_scan *cmd;
- struct wl1271_cmd_trigger_scan_to *trigger;
- int ret;
- u16 scan_options = 0;
-
- /* skip active scans if we don't have SSIDs */
- if (!passive && wl->scan.req->n_ssids == 0)
- return WL1271_NOTHING_TO_SCAN;
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
- if (!cmd || !trigger) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (wl->conf.scan.split_scan_timeout)
- scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN;
-
- if (passive)
- scan_options |= WL1271_SCAN_OPT_PASSIVE;
-
- cmd->params.role_id = wlvif->role_id;
-
- if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) {
- ret = -EINVAL;
- goto out;
- }
-
- cmd->params.scan_options = cpu_to_le16(scan_options);
-
- cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
- cmd->channels,
- band, passive);
- if (cmd->params.n_ch == 0) {
- ret = WL1271_NOTHING_TO_SCAN;
- goto out;
- }
-
- cmd->params.tx_rate = cpu_to_le32(basic_rate);
- cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
- cmd->params.tid_trigger = CONF_TX_AC_ANY_TID;
- cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
-
- if (band == IEEE80211_BAND_2GHZ)
- cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
- else
- cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
-
- if (wl->scan.ssid_len && wl->scan.ssid) {
- cmd->params.ssid_len = wl->scan.ssid_len;
- memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
- }
-
- memcpy(cmd->addr, vif->addr, ETH_ALEN);
-
- ret = wl12xx_cmd_build_probe_req(wl, wlvif,
- cmd->params.role_id, band,
- wl->scan.ssid, wl->scan.ssid_len,
- wl->scan.req->ie,
- wl->scan.req->ie_len, false);
- if (ret < 0) {
- wl1271_error("PROBE request template failed");
- goto out;
- }
-
- trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout);
- ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
- sizeof(*trigger), 0);
- if (ret < 0) {
- wl1271_error("trigger scan to failed for hw scan");
- goto out;
- }
-
- wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
+ int *count = (int *)data;
- ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
- if (ret < 0) {
- wl1271_error("SCAN failed");
- goto out;
- }
-
-out:
- kfree(cmd);
- kfree(trigger);
- return ret;
+ if (!vif->bss_conf.idle)
+ (*count)++;
}
-void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif)
+static int wlcore_count_started_vifs(struct wl1271 *wl)
{
- struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
- int ret = 0;
- enum ieee80211_band band;
- u32 rate, mask;
-
- switch (wl->scan.state) {
- case WL1271_SCAN_STATE_IDLE:
- break;
-
- case WL1271_SCAN_STATE_2GHZ_ACTIVE:
- band = IEEE80211_BAND_2GHZ;
- mask = wlvif->bitrate_masks[band];
- if (wl->scan.req->no_cck) {
- mask &= ~CONF_TX_CCK_RATES;
- if (!mask)
- mask = CONF_TX_RATE_MASK_BASIC_P2P;
- }
- rate = wl1271_tx_min_rate_get(wl, mask);
- ret = wl1271_scan_send(wl, vif, band, false, rate);
- if (ret == WL1271_NOTHING_TO_SCAN) {
- wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
- wl1271_scan_stm(wl, vif);
- }
-
- break;
-
- case WL1271_SCAN_STATE_2GHZ_PASSIVE:
- band = IEEE80211_BAND_2GHZ;
- mask = wlvif->bitrate_masks[band];
- if (wl->scan.req->no_cck) {
- mask &= ~CONF_TX_CCK_RATES;
- if (!mask)
- mask = CONF_TX_RATE_MASK_BASIC_P2P;
- }
- rate = wl1271_tx_min_rate_get(wl, mask);
- ret = wl1271_scan_send(wl, vif, band, true, rate);
- if (ret == WL1271_NOTHING_TO_SCAN) {
- if (wl->enable_11a)
- wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
- else
- wl->scan.state = WL1271_SCAN_STATE_DONE;
- wl1271_scan_stm(wl, vif);
- }
-
- break;
+ int count = 0;
- case WL1271_SCAN_STATE_5GHZ_ACTIVE:
- band = IEEE80211_BAND_5GHZ;
- rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
- ret = wl1271_scan_send(wl, vif, band, false, rate);
- if (ret == WL1271_NOTHING_TO_SCAN) {
- wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
- wl1271_scan_stm(wl, vif);
- }
-
- break;
-
- case WL1271_SCAN_STATE_5GHZ_PASSIVE:
- band = IEEE80211_BAND_5GHZ;
- rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]);
- ret = wl1271_scan_send(wl, vif, band, true, rate);
- if (ret == WL1271_NOTHING_TO_SCAN) {
- wl->scan.state = WL1271_SCAN_STATE_DONE;
- wl1271_scan_stm(wl, vif);
- }
-
- break;
-
- case WL1271_SCAN_STATE_DONE:
- wl->scan.failed = false;
- cancel_delayed_work(&wl->scan_complete_work);
- ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
- msecs_to_jiffies(0));
- break;
-
- default:
- wl1271_error("invalid scan state");
- break;
- }
-
- if (ret < 0) {
- cancel_delayed_work(&wl->scan_complete_work);
- ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
- msecs_to_jiffies(0));
- }
-}
-
-int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
- 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;
-
- wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
-
- if (ssid_len && ssid) {
- wl->scan.ssid_len = ssid_len;
- memcpy(wl->scan.ssid, ssid, ssid_len);
- } else {
- wl->scan.ssid_len = 0;
- }
-
- wl->scan_vif = vif;
- wl->scan.req = req;
- memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
-
- /* we assume failure so that timeout scenarios are handled correctly */
- wl->scan.failed = true;
- ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
- msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
-
- wl1271_scan_stm(wl, vif);
-
- return 0;
-}
-
-int wl1271_scan_stop(struct wl1271 *wl)
-{
- struct wl1271_cmd_header *cmd = NULL;
- int ret = 0;
-
- if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE))
- return -EINVAL;
-
- wl1271_debug(DEBUG_CMD, "cmd scan stop");
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd,
- sizeof(*cmd), 0);
- if (ret < 0) {
- wl1271_error("cmd stop_scan failed");
- goto out;
- }
-out:
- kfree(cmd);
- return ret;
+ ieee80211_iterate_active_interfaces_atomic(wl->hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ wlcore_started_vifs_iter, &count);
+ return count;
}
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, int max_channels,
- u8 *n_pactive_ch)
+wlcore_scan_get_channels(struct wl1271 *wl,
+ struct ieee80211_channel *req_channels[],
+ u32 n_channels,
+ u32 n_ssids,
+ struct conn_scan_ch_params *channels,
+ u32 band, bool radar, bool passive,
+ int start, int max_channels,
+ u8 *n_pactive_ch,
+ int scan_type)
{
- struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
int i, j;
u32 flags;
- bool force_passive = !req->n_ssids;
- u32 min_dwell_time_active, max_dwell_time_active, delta_per_probe;
+ bool force_passive = !n_ssids;
+ u32 min_dwell_time_active, max_dwell_time_active;
u32 dwell_time_passive, dwell_time_dfs;
- if (band == IEEE80211_BAND_5GHZ)
- delta_per_probe = c->dwell_time_delta_per_probe_5;
- else
- delta_per_probe = c->dwell_time_delta_per_probe;
+ /* configure dwell times according to scan type */
+ if (scan_type == SCAN_TYPE_SEARCH) {
+ struct conf_scan_settings *c = &wl->conf.scan;
+ bool active_vif_exists = !!wlcore_count_started_vifs(wl);
+
+ min_dwell_time_active = active_vif_exists ?
+ c->min_dwell_time_active :
+ c->min_dwell_time_active_long;
+ max_dwell_time_active = active_vif_exists ?
+ c->max_dwell_time_active :
+ c->max_dwell_time_active_long;
+ dwell_time_passive = c->dwell_time_passive;
+ dwell_time_dfs = c->dwell_time_dfs;
+ } else {
+ struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+ u32 delta_per_probe;
- min_dwell_time_active = c->base_dwell_time +
- req->n_ssids * c->num_probe_reqs * delta_per_probe;
+ if (band == IEEE80211_BAND_5GHZ)
+ delta_per_probe = c->dwell_time_delta_per_probe_5;
+ else
+ delta_per_probe = c->dwell_time_delta_per_probe;
- max_dwell_time_active = min_dwell_time_active + c->max_dwell_time_delta;
+ min_dwell_time_active = c->base_dwell_time +
+ n_ssids * c->num_probe_reqs * delta_per_probe;
+ max_dwell_time_active = min_dwell_time_active +
+ c->max_dwell_time_delta;
+ dwell_time_passive = c->dwell_time_passive;
+ dwell_time_dfs = c->dwell_time_dfs;
+ }
min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000);
max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000);
- dwell_time_passive = DIV_ROUND_UP(c->dwell_time_passive, 1000);
- dwell_time_dfs = DIV_ROUND_UP(c->dwell_time_dfs, 1000);
+ dwell_time_passive = DIV_ROUND_UP(dwell_time_passive, 1000);
+ dwell_time_dfs = DIV_ROUND_UP(dwell_time_dfs, 1000);
for (i = 0, j = start;
- i < req->n_channels && j < max_channels;
+ i < n_channels && j < max_channels;
i++) {
- flags = req->channels[i]->flags;
+ flags = req_channels[i]->flags;
if (force_passive)
flags |= IEEE80211_CHAN_PASSIVE_SCAN;
- if ((req->channels[i]->band == band) &&
+ if ((req_channels[i]->band == band) &&
!(flags & IEEE80211_CHAN_DISABLED) &&
(!!(flags & IEEE80211_CHAN_RADAR) == radar) &&
/* if radar is set, we ignore the passive flag */
(radar ||
!!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
- req->channels[i]->band,
- req->channels[i]->center_freq);
+ 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);
+ req_channels[i]->hw_value,
+ req_channels[i]->flags);
wl1271_debug(DEBUG_SCAN, "max_power %d",
- req->channels[i]->max_power);
+ req_channels[i]->max_power);
wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d",
min_dwell_time_active,
max_dwell_time_active);
@@ -473,10 +201,11 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
channels[j].max_duration =
cpu_to_le16(max_dwell_time_active);
- channels[j].tx_power_att = req->channels[i]->max_power;
- channels[j].channel = req->channels[i]->hw_value;
+ channels[j].tx_power_att = req_channels[i]->max_power;
+ channels[j].channel = req_channels[i]->hw_value;
- if ((band == IEEE80211_BAND_2GHZ) &&
+ if (n_pactive_ch &&
+ (band == IEEE80211_BAND_2GHZ) &&
(channels[j].channel >= 12) &&
(channels[j].channel <= 14) &&
(flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
@@ -500,51 +229,80 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
return j - start;
}
-static bool
-wl1271_scan_sched_scan_channels(struct wl1271 *wl,
- struct cfg80211_sched_scan_request *req,
- struct wl1271_cmd_sched_scan_config *cfg)
+bool
+wlcore_set_scan_chan_params(struct wl1271 *wl,
+ struct wlcore_scan_channels *cfg,
+ struct ieee80211_channel *channels[],
+ u32 n_channels,
+ u32 n_ssids,
+ int scan_type)
{
u8 n_pactive_ch = 0;
cfg->passive[0] =
- wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
- IEEE80211_BAND_2GHZ,
- false, true, 0,
- MAX_CHANNELS_2GHZ,
- &n_pactive_ch);
+ wlcore_scan_get_channels(wl,
+ channels,
+ n_channels,
+ n_ssids,
+ cfg->channels_2,
+ IEEE80211_BAND_2GHZ,
+ false, true, 0,
+ MAX_CHANNELS_2GHZ,
+ &n_pactive_ch,
+ scan_type);
cfg->active[0] =
- wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
- IEEE80211_BAND_2GHZ,
- false, false,
- cfg->passive[0],
- MAX_CHANNELS_2GHZ,
- &n_pactive_ch);
+ wlcore_scan_get_channels(wl,
+ channels,
+ n_channels,
+ n_ssids,
+ cfg->channels_2,
+ IEEE80211_BAND_2GHZ,
+ false, false,
+ cfg->passive[0],
+ MAX_CHANNELS_2GHZ,
+ &n_pactive_ch,
+ scan_type);
cfg->passive[1] =
- wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
- IEEE80211_BAND_5GHZ,
- false, true, 0,
- MAX_CHANNELS_5GHZ,
- &n_pactive_ch);
+ wlcore_scan_get_channels(wl,
+ channels,
+ n_channels,
+ n_ssids,
+ cfg->channels_5,
+ IEEE80211_BAND_5GHZ,
+ false, true, 0,
+ wl->max_channels_5,
+ &n_pactive_ch,
+ scan_type);
cfg->dfs =
- wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
- IEEE80211_BAND_5GHZ,
- true, true,
- cfg->passive[1],
- MAX_CHANNELS_5GHZ,
- &n_pactive_ch);
+ wlcore_scan_get_channels(wl,
+ channels,
+ n_channels,
+ n_ssids,
+ cfg->channels_5,
+ IEEE80211_BAND_5GHZ,
+ true, true,
+ cfg->passive[1],
+ wl->max_channels_5,
+ &n_pactive_ch,
+ scan_type);
cfg->active[1] =
- wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
- IEEE80211_BAND_5GHZ,
- false, false,
- cfg->passive[1] + cfg->dfs,
- MAX_CHANNELS_5GHZ,
- &n_pactive_ch);
+ wlcore_scan_get_channels(wl,
+ channels,
+ n_channels,
+ n_ssids,
+ cfg->channels_5,
+ IEEE80211_BAND_5GHZ,
+ false, false,
+ cfg->passive[1] + cfg->dfs,
+ wl->max_channels_5,
+ &n_pactive_ch,
+ scan_type);
+
/* 802.11j channels are not supported yet */
cfg->passive[2] = 0;
cfg->active[2] = 0;
- cfg->n_pactive_ch = n_pactive_ch;
+ cfg->passive_active = n_pactive_ch;
wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d",
cfg->active[0], cfg->passive[0]);
@@ -556,10 +314,48 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
cfg->passive[1] || cfg->active[1] || cfg->dfs ||
cfg->passive[2] || cfg->active[2];
}
+EXPORT_SYMBOL_GPL(wlcore_set_scan_chan_params);
+
+int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
+ const u8 *ssid, size_t ssid_len,
+ struct cfg80211_scan_request *req)
+{
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+
+ /*
+ * 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;
+
+ wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
+
+ if (ssid_len && ssid) {
+ wl->scan.ssid_len = ssid_len;
+ memcpy(wl->scan.ssid, ssid, ssid_len);
+ } else {
+ wl->scan.ssid_len = 0;
+ }
+
+ wl->scan_wlvif = wlvif;
+ wl->scan.req = req;
+ memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
+
+ /* we assume failure so that timeout scenarios are handled correctly */
+ wl->scan.failed = true;
+ ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
+ msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
+ wl->ops->scan_start(wl, wlvif, req);
+
+ return 0;
+}
/* Returns the scan type to be used or a negative value on error */
-static int
-wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
+int
+wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct cfg80211_sched_scan_request *req)
{
@@ -662,160 +458,12 @@ out:
return ret;
return type;
}
+EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_ssid_list);
-int wl1271_scan_sched_scan_config(struct wl1271 *wl,
- struct wl12xx_vif *wlvif,
- 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, ret;
- bool force_passive = !req->n_ssids;
-
- wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
-
- cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
- if (!cfg)
- return -ENOMEM;
-
- cfg->role_id = wlvif->role_id;
- 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);
-
- cfg->ssid_len = 0;
- ret = wl12xx_scan_sched_scan_ssid_list(wl, wlvif, req);
- if (ret < 0)
- goto out;
-
- cfg->filter_type = ret;
-
- wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type);
-
- if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) {
- wl1271_error("scan channel list is empty");
- ret = -EINVAL;
- goto out;
- }
-
- if (!force_passive && cfg->active[0]) {
- u8 band = IEEE80211_BAND_2GHZ;
- ret = wl12xx_cmd_build_probe_req(wl, wlvif,
- wlvif->role_id, band,
- req->ssids[0].ssid,
- req->ssids[0].ssid_len,
- ies->ie[band],
- ies->len[band], true);
- if (ret < 0) {
- wl1271_error("2.4GHz PROBE request template failed");
- goto out;
- }
- }
-
- if (!force_passive && cfg->active[1]) {
- u8 band = IEEE80211_BAND_5GHZ;
- ret = wl12xx_cmd_build_probe_req(wl, wlvif,
- wlvif->role_id, band,
- req->ssids[0].ssid,
- req->ssids[0].ssid_len,
- ies->ie[band],
- ies->len[band], true);
- 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 wl12xx_vif *wlvif)
-{
- struct wl1271_cmd_sched_scan_start *start;
- int ret = 0;
-
- wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
-
- if (wlvif->bss_type != BSS_TYPE_STA_BSS)
- return -EOPNOTSUPP;
-
- if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) &&
- test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
- return -EBUSY;
-
- start = kzalloc(sizeof(*start), GFP_KERNEL);
- if (!start)
- return -ENOMEM;
-
- start->role_id = wlvif->role_id;
- 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)
+void wlcore_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 wl12xx_vif *wlvif)
-{
- 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->role_id = wlvif->role_id;
- 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;
- }
-
-out_free:
- kfree(stop);
-}
+EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_results);
diff --git a/drivers/net/wireless/ti/wlcore/scan.h b/drivers/net/wireless/ti/wlcore/scan.h
index 29f3c8d6b046..a6ab24b5c0f9 100644
--- a/drivers/net/wireless/ti/wlcore/scan.h
+++ b/drivers/net/wireless/ti/wlcore/scan.h
@@ -26,22 +26,20 @@
#include "wlcore.h"
-int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
+int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
const u8 *ssid, size_t ssid_len,
struct cfg80211_scan_request *req);
-int wl1271_scan_stop(struct wl1271 *wl);
int wl1271_scan_build_probe_req(struct wl1271 *wl,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, u8 band);
-void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif);
+void wl1271_scan_stm(struct wl1271 *wl, struct wl12xx_vif *wlvif);
void wl1271_scan_complete_work(struct work_struct *work);
int wl1271_scan_sched_scan_config(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct cfg80211_sched_scan_request *req,
struct ieee80211_sched_scan_ies *ies);
int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl1271_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl1271_scan_sched_scan_results(struct wl1271 *wl);
+void wlcore_scan_sched_scan_results(struct wl1271 *wl);
#define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1
@@ -66,56 +64,6 @@ enum {
WL1271_SCAN_STATE_DONE
};
-struct basic_scan_params {
- /* Scan option flags (WL1271_SCAN_OPT_*) */
- __le16 scan_options;
- u8 role_id;
- /* Number of scan channels in the list (maximum 30) */
- u8 n_ch;
- /* This field indicates the number of probe requests to send
- per channel for an active scan */
- u8 n_probe_reqs;
- u8 tid_trigger;
- u8 ssid_len;
- u8 use_ssid_list;
-
- /* Rate bit field for sending the probes */
- __le32 tx_rate;
-
- u8 ssid[IEEE80211_MAX_SSID_LEN];
- /* Band to scan */
- u8 band;
-
- u8 scan_tag;
- u8 padding2[2];
-} __packed;
-
-struct basic_scan_channel_params {
- /* Duration in TU to wait for frames on a channel for active scan */
- __le32 min_duration;
- __le32 max_duration;
- __le32 bssid_lsb;
- __le16 bssid_msb;
- u8 early_termination;
- u8 tx_power_att;
- u8 channel;
- /* FW internal use only! */
- u8 dfs_candidate;
- u8 activity_detected;
- u8 pad;
-} __packed;
-
-struct wl1271_cmd_scan {
- struct wl1271_cmd_header header;
-
- struct basic_scan_params params;
- struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
-
- /* src mac address */
- u8 addr[ETH_ALEN];
- u8 padding[2];
-} __packed;
-
struct wl1271_cmd_trigger_scan_to {
struct wl1271_cmd_header header;
@@ -123,9 +71,17 @@ struct wl1271_cmd_trigger_scan_to {
} __packed;
#define MAX_CHANNELS_2GHZ 14
-#define MAX_CHANNELS_5GHZ 23
#define MAX_CHANNELS_4GHZ 4
+/*
+ * This max value here is used only for the struct definition of
+ * wlcore_scan_channels. This struct is used by both 12xx
+ * and 18xx (which have different max 5ghz channels value).
+ * In order to make sure this is large enough, just use the
+ * max possible 5ghz channels.
+ */
+#define MAX_CHANNELS_5GHZ 42
+
#define SCAN_MAX_CYCLE_INTERVALS 16
#define SCAN_MAX_BANDS 3
@@ -160,43 +116,6 @@ struct conn_scan_ch_params {
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[IEEE80211_MAX_SSID_LEN];
-
- u8 n_probe_reqs; /* Number of probes requests per channel */
-
- u8 passive[SCAN_MAX_BANDS];
- u8 active[SCAN_MAX_BANDS];
-
- u8 dfs;
-
- u8 n_pactive_ch; /* number of pactive (passive until fw detects energy)
- channels in BG band */
- u8 role_id;
- u8 padding[1];
-
- struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
- struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
- struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
-} __packed;
-
-
#define SCHED_SCAN_MAX_SSIDS 16
enum {
@@ -220,21 +139,34 @@ struct wl1271_cmd_sched_scan_ssid_list {
u8 padding[2];
} __packed;
-struct wl1271_cmd_sched_scan_start {
- struct wl1271_cmd_header header;
+struct wlcore_scan_channels {
+ u8 passive[SCAN_MAX_BANDS]; /* number of passive scan channels */
+ u8 active[SCAN_MAX_BANDS]; /* number of active scan channels */
+ u8 dfs; /* number of dfs channels in 5ghz */
+ u8 passive_active; /* number of passive before active channels 2.4ghz */
- u8 tag;
- u8 role_id;
- u8 padding[2];
-} __packed;
-
-struct wl1271_cmd_sched_scan_stop {
- struct wl1271_cmd_header header;
+ struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
+ struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
+ struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
+};
- u8 tag;
- u8 role_id;
- u8 padding[2];
-} __packed;
+enum {
+ SCAN_TYPE_SEARCH = 0,
+ SCAN_TYPE_PERIODIC = 1,
+ SCAN_TYPE_TRACKING = 2,
+};
+bool
+wlcore_set_scan_chan_params(struct wl1271 *wl,
+ struct wlcore_scan_channels *cfg,
+ struct ieee80211_channel *channels[],
+ u32 n_channels,
+ u32 n_ssids,
+ int scan_type);
+
+int
+wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req);
#endif /* __WL1271_SCAN_H__ */
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c
index 646f703ae739..29ef2492951f 100644
--- a/drivers/net/wireless/ti/wlcore/sdio.c
+++ b/drivers/net/wireless/ti/wlcore/sdio.c
@@ -217,7 +217,7 @@ static struct wl1271_if_operations sdio_ops = {
static int wl1271_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
- struct wl12xx_platform_data *wlan_data;
+ struct wlcore_platdev_data *pdev_data;
struct wl12xx_sdio_glue *glue;
struct resource res[1];
mmc_pm_flag_t mmcflags;
@@ -228,10 +228,16 @@ static int wl1271_probe(struct sdio_func *func,
if (func->num != 0x02)
return -ENODEV;
+ pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL);
+ if (!pdev_data)
+ goto out;
+
+ pdev_data->if_ops = &sdio_ops;
+
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&func->dev, "can't allocate glue\n");
- goto out;
+ goto out_free_pdev_data;
}
glue->dev = &func->dev;
@@ -242,9 +248,9 @@ static int wl1271_probe(struct sdio_func *func,
/* 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);
+ pdev_data->pdata = wl12xx_get_platform_data();
+ if (IS_ERR(pdev_data->pdata)) {
+ ret = PTR_ERR(pdev_data->pdata);
dev_err(glue->dev, "missing wlan platform data: %d\n", ret);
goto out_free_glue;
}
@@ -254,9 +260,7 @@ static int wl1271_probe(struct sdio_func *func,
dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);
if (mmcflags & MMC_PM_KEEP_POWER)
- wlan_data->pwr_in_suspend = true;
-
- wlan_data->ops = &sdio_ops;
+ pdev_data->pdata->pwr_in_suspend = true;
sdio_set_drvdata(func, glue);
@@ -274,7 +278,7 @@ static int wl1271_probe(struct sdio_func *func,
else
chip_family = "wl12xx";
- glue->core = platform_device_alloc(chip_family, -1);
+ glue->core = platform_device_alloc(chip_family, PLATFORM_DEVID_AUTO);
if (!glue->core) {
dev_err(glue->dev, "can't allocate platform_device");
ret = -ENOMEM;
@@ -285,7 +289,7 @@ static int wl1271_probe(struct sdio_func *func,
memset(res, 0x00, sizeof(res));
- res[0].start = wlan_data->irq;
+ res[0].start = pdev_data->pdata->irq;
res[0].flags = IORESOURCE_IRQ;
res[0].name = "irq";
@@ -295,8 +299,8 @@ static int wl1271_probe(struct sdio_func *func,
goto out_dev_put;
}
- ret = platform_device_add_data(glue->core, wlan_data,
- sizeof(*wlan_data));
+ ret = platform_device_add_data(glue->core, pdev_data,
+ sizeof(*pdev_data));
if (ret) {
dev_err(glue->dev, "can't add platform data\n");
goto out_dev_put;
@@ -315,6 +319,9 @@ out_dev_put:
out_free_glue:
kfree(glue);
+out_free_pdev_data:
+ kfree(pdev_data);
+
out:
return ret;
}
@@ -326,8 +333,7 @@ static void wl1271_remove(struct sdio_func *func)
/* Undo decrement done above in wl1271_probe */
pm_runtime_get_noresume(&func->dev);
- platform_device_del(glue->core);
- platform_device_put(glue->core);
+ platform_device_unregister(glue->core);
kfree(glue);
}
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index f06f4770ce02..e26447832683 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -270,7 +270,7 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
void *buf, size_t len, bool fixed)
{
struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
- struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
+ struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)];
struct spi_message m;
u32 commands[WSPI_MAX_NUM_OF_CHUNKS];
u32 *cmd;
@@ -327,22 +327,27 @@ static struct wl1271_if_operations spi_ops = {
static int wl1271_probe(struct spi_device *spi)
{
struct wl12xx_spi_glue *glue;
- struct wl12xx_platform_data *pdata;
+ struct wlcore_platdev_data *pdev_data;
struct resource res[1];
int ret = -ENOMEM;
- pdata = spi->dev.platform_data;
- if (!pdata) {
+ pdev_data = kzalloc(sizeof(*pdev_data), GFP_KERNEL);
+ if (!pdev_data)
+ goto out;
+
+ pdev_data->pdata = spi->dev.platform_data;
+ if (!pdev_data->pdata) {
dev_err(&spi->dev, "no platform data\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free_pdev_data;
}
- pdata->ops = &spi_ops;
+ pdev_data->if_ops = &spi_ops;
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&spi->dev, "can't allocate glue\n");
- goto out;
+ goto out_free_pdev_data;
}
glue->dev = &spi->dev;
@@ -359,7 +364,7 @@ static int wl1271_probe(struct spi_device *spi)
goto out_free_glue;
}
- glue->core = platform_device_alloc("wl12xx", -1);
+ glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO);
if (!glue->core) {
dev_err(glue->dev, "can't allocate platform_device\n");
ret = -ENOMEM;
@@ -380,7 +385,8 @@ static int wl1271_probe(struct spi_device *spi)
goto out_dev_put;
}
- ret = platform_device_add_data(glue->core, pdata, sizeof(*pdata));
+ ret = platform_device_add_data(glue->core, pdev_data,
+ sizeof(*pdev_data));
if (ret) {
dev_err(glue->dev, "can't add platform data\n");
goto out_dev_put;
@@ -399,6 +405,10 @@ out_dev_put:
out_free_glue:
kfree(glue);
+
+out_free_pdev_data:
+ kfree(pdev_data);
+
out:
return ret;
}
@@ -407,8 +417,7 @@ static int wl1271_remove(struct spi_device *spi)
{
struct wl12xx_spi_glue *glue = spi_get_drvdata(spi);
- platform_device_del(glue->core);
- platform_device_put(glue->core);
+ platform_device_unregister(glue->core);
kfree(glue);
return 0;
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index a90d3cd09408..ece392c54d9c 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -104,7 +104,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
u8 hlid)
{
- bool fw_ps, single_sta;
+ bool fw_ps, single_link;
u8 tx_pkts;
if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
@@ -112,15 +112,15 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
tx_pkts = wl->links[hlid].allocated_pkts;
- single_sta = (wl->active_sta_count == 1);
+ single_link = (wl->active_link_count == 1);
/*
* if in FW PS and there is enough data in FW we can put the link
* into high-level PS and clean out its TX queues.
- * Make an exception if this is the only connected station. In this
- * case FW-memory congestion is not a problem.
+ * Make an exception if this is the only connected link. In this
+ * case FW-memory congestion is less of a problem.
*/
- if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+ if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
@@ -155,21 +155,18 @@ static u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
struct sk_buff *skb, struct ieee80211_sta *sta)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-
- if (!wlvif || wl12xx_is_dummy_packet(wl, skb))
- return wl->system_hlid;
+ struct ieee80211_tx_info *control;
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta);
- if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
- test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) &&
- !ieee80211_is_auth(hdr->frame_control) &&
- !ieee80211_is_assoc_req(hdr->frame_control))
- return wlvif->sta.hlid;
- else
+ control = IEEE80211_SKB_CB(skb);
+ if (control->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
+ wl1271_debug(DEBUG_TX, "tx offchannel");
return wlvif->dev_hlid;
+ }
+
+ return wlvif->sta.hlid;
}
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
@@ -224,9 +221,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
wl->tx_allocated_pkts[ac]++;
- if (!wl12xx_is_dummy_packet(wl, skb) && wlvif &&
- wlvif->bss_type == BSS_TYPE_AP_BSS &&
- test_bit(hlid, wlvif->ap.sta_hlid_map))
+ if (test_bit(hlid, wl->links_map))
wl->links[hlid].allocated_pkts++;
ret = 0;
@@ -293,9 +288,14 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
} else if (wlvif) {
+ u8 session_id = wl->session_ids[hlid];
+
+ if ((wl->quirks & WLCORE_QUIRK_AP_ZERO_SESSION_ID) &&
+ (wlvif->bss_type == BSS_TYPE_AP_BSS))
+ session_id = 0;
+
/* configure the tx attributes */
- tx_attr = wlvif->session_counter <<
- TX_HW_ATTR_OFST_SESSION_COUNTER;
+ tx_attr = session_id << TX_HW_ATTR_OFST_SESSION_COUNTER;
}
desc->hlid = hlid;
@@ -452,20 +452,22 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
{
int i;
+ struct wl12xx_vif *wlvif;
- for (i = 0; i < NUM_TX_QUEUES; i++) {
- if (wlcore_is_queue_stopped_by_reason(wl, i,
- WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
- wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) {
- /* firmware buffer has space, restart queues */
- wlcore_wake_queue(wl, i,
- WLCORE_QUEUE_STOP_REASON_WATERMARK);
+ wl12xx_for_each_wlvif(wl, wlvif) {
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ if (wlcore_is_queue_stopped_by_reason(wl, wlvif, i,
+ WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
+ wlvif->tx_queue_count[i] <=
+ WL1271_TX_QUEUE_LOW_WATERMARK)
+ /* firmware buffer has space, restart queues */
+ wlcore_wake_queue(wl, wlvif, i,
+ WLCORE_QUEUE_STOP_REASON_WATERMARK);
}
}
}
-static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
- struct sk_buff_head *queues)
+static int wlcore_select_ac(struct wl1271 *wl)
{
int i, q = -1, ac;
u32 min_pkts = 0xffffffff;
@@ -479,45 +481,60 @@ static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
*/
for (i = 0; i < NUM_TX_QUEUES; i++) {
ac = wl1271_tx_get_queue(i);
- if (!skb_queue_empty(&queues[ac]) &&
- (wl->tx_allocated_pkts[ac] < min_pkts)) {
+ if (wl->tx_queue_count[ac] &&
+ wl->tx_allocated_pkts[ac] < min_pkts) {
q = ac;
min_pkts = wl->tx_allocated_pkts[q];
}
}
- if (q == -1)
- return NULL;
-
- return &queues[q];
+ return q;
}
-static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl,
- struct wl1271_link *lnk)
+static struct sk_buff *wlcore_lnk_dequeue(struct wl1271 *wl,
+ struct wl1271_link *lnk, u8 q)
{
struct sk_buff *skb;
unsigned long flags;
- struct sk_buff_head *queue;
- queue = wl1271_select_queue(wl, lnk->tx_queue);
- if (!queue)
- return NULL;
-
- skb = skb_dequeue(queue);
+ skb = skb_dequeue(&lnk->tx_queue[q]);
if (skb) {
- int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
spin_lock_irqsave(&wl->wl_lock, flags);
WARN_ON_ONCE(wl->tx_queue_count[q] <= 0);
wl->tx_queue_count[q]--;
+ if (lnk->wlvif) {
+ WARN_ON_ONCE(lnk->wlvif->tx_queue_count[q] <= 0);
+ lnk->wlvif->tx_queue_count[q]--;
+ }
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
return skb;
}
-static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl,
- struct wl12xx_vif *wlvif,
- u8 *hlid)
+static struct sk_buff *wlcore_lnk_dequeue_high_prio(struct wl1271 *wl,
+ u8 hlid, u8 ac,
+ u8 *low_prio_hlid)
+{
+ struct wl1271_link *lnk = &wl->links[hlid];
+
+ if (!wlcore_hw_lnk_high_prio(wl, hlid, lnk)) {
+ if (*low_prio_hlid == WL12XX_INVALID_LINK_ID &&
+ !skb_queue_empty(&lnk->tx_queue[ac]) &&
+ wlcore_hw_lnk_low_prio(wl, hlid, lnk))
+ /* we found the first non-empty low priority queue */
+ *low_prio_hlid = hlid;
+
+ return NULL;
+ }
+
+ return wlcore_lnk_dequeue(wl, lnk, ac);
+}
+
+static struct sk_buff *wlcore_vif_dequeue_high_prio(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ u8 ac, u8 *hlid,
+ u8 *low_prio_hlid)
{
struct sk_buff *skb = NULL;
int i, h, start_hlid;
@@ -533,7 +550,8 @@ static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl,
if (!test_bit(h, wlvif->links_map))
continue;
- skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]);
+ skb = wlcore_lnk_dequeue_high_prio(wl, h, ac,
+ low_prio_hlid);
if (!skb)
continue;
@@ -553,42 +571,74 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid)
unsigned long flags;
struct wl12xx_vif *wlvif = wl->last_wlvif;
struct sk_buff *skb = NULL;
+ int ac;
+ u8 low_prio_hlid = WL12XX_INVALID_LINK_ID;
+
+ ac = wlcore_select_ac(wl);
+ if (ac < 0)
+ goto out;
/* continue from last wlvif (round robin) */
if (wlvif) {
wl12xx_for_each_wlvif_continue(wl, wlvif) {
- skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid);
- if (skb) {
- wl->last_wlvif = wlvif;
- break;
- }
+ if (!wlvif->tx_queue_count[ac])
+ continue;
+
+ skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid,
+ &low_prio_hlid);
+ if (!skb)
+ continue;
+
+ wl->last_wlvif = wlvif;
+ break;
}
}
/* dequeue from the system HLID before the restarting wlvif list */
if (!skb) {
- skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]);
- *hlid = wl->system_hlid;
+ skb = wlcore_lnk_dequeue_high_prio(wl, wl->system_hlid,
+ ac, &low_prio_hlid);
+ if (skb) {
+ *hlid = wl->system_hlid;
+ wl->last_wlvif = NULL;
+ }
}
- /* do a new pass over the wlvif list */
+ /* Do a new pass over the wlvif list. But no need to continue
+ * after last_wlvif. The previous pass should have found it. */
if (!skb) {
wl12xx_for_each_wlvif(wl, wlvif) {
- skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid);
+ if (!wlvif->tx_queue_count[ac])
+ goto next;
+
+ skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid,
+ &low_prio_hlid);
if (skb) {
wl->last_wlvif = wlvif;
break;
}
- /*
- * No need to continue after last_wlvif. The previous
- * pass should have found it.
- */
+next:
if (wlvif == wl->last_wlvif)
break;
}
}
+ /* no high priority skbs found - but maybe a low priority one? */
+ if (!skb && low_prio_hlid != WL12XX_INVALID_LINK_ID) {
+ struct wl1271_link *lnk = &wl->links[low_prio_hlid];
+ skb = wlcore_lnk_dequeue(wl, lnk, ac);
+
+ WARN_ON(!skb); /* we checked this before */
+ *hlid = low_prio_hlid;
+
+ /* ensure proper round robin in the vif/link levels */
+ wl->last_wlvif = lnk->wlvif;
+ if (lnk->wlvif)
+ lnk->wlvif->last_tx_hlid = low_prio_hlid;
+
+ }
+
if (!skb &&
test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
int q;
@@ -602,6 +652,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid)
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
+out:
return skb;
}
@@ -623,6 +674,8 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif,
spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count[q]++;
+ if (wlvif)
+ wlvif->tx_queue_count[q]++;
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
@@ -699,7 +752,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl)
bool has_data = false;
wlvif = NULL;
- if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif)
+ if (!wl12xx_is_dummy_packet(wl, skb))
wlvif = wl12xx_vif_to_data(info->control.vif);
else
hlid = wl->system_hlid;
@@ -972,10 +1025,11 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
unsigned long flags;
struct ieee80211_tx_info *info;
int total[NUM_TX_QUEUES];
+ struct wl1271_link *lnk = &wl->links[hlid];
for (i = 0; i < NUM_TX_QUEUES; i++) {
total[i] = 0;
- while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
+ while ((skb = skb_dequeue(&lnk->tx_queue[i]))) {
wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb);
if (!wl12xx_is_dummy_packet(wl, skb)) {
@@ -990,8 +1044,11 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
}
spin_lock_irqsave(&wl->wl_lock, flags);
- for (i = 0; i < NUM_TX_QUEUES; i++)
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
wl->tx_queue_count[i] -= total[i];
+ if (lnk->wlvif)
+ lnk->wlvif->tx_queue_count[i] -= total[i];
+ }
spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_handle_tx_low_watermark(wl);
@@ -1004,16 +1061,18 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
/* TX failure */
for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) {
- if (wlvif->bss_type == BSS_TYPE_AP_BSS)
+ if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
+ /* this calls wl12xx_free_link */
wl1271_free_sta(wl, wlvif, i);
- else
- wlvif->sta.ba_rx_bitmap = 0;
-
- wl->links[i].allocated_pkts = 0;
- wl->links[i].prev_freed_pkts = 0;
+ } else {
+ u8 hlid = i;
+ wl12xx_free_link(wl, wlvif, &hlid);
+ }
}
wlvif->last_tx_hlid = 0;
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ wlvif->tx_queue_count[i] = 0;
}
/* caller must hold wl->mutex and TX must be stopped */
void wl12xx_tx_reset(struct wl1271 *wl)
@@ -1023,7 +1082,7 @@ void wl12xx_tx_reset(struct wl1271 *wl)
struct ieee80211_tx_info *info;
/* only reset the queues if something bad happened */
- if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) {
+ if (wl1271_tx_total_queue_count(wl) != 0) {
for (i = 0; i < WL12XX_MAX_LINKS; i++)
wl1271_tx_reset_link_queues(wl, i);
@@ -1135,45 +1194,48 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
return BIT(__ffs(rate_set));
}
+EXPORT_SYMBOL_GPL(wl1271_tx_min_rate_get);
-void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
- enum wlcore_queue_stop_reason reason)
+void wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 queue, enum wlcore_queue_stop_reason reason)
{
- bool stopped = !!wl->queue_stop_reasons[queue];
+ int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
+ bool stopped = !!wl->queue_stop_reasons[hwq];
/* queue should not be stopped for this reason */
- WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[queue]));
+ WARN_ON_ONCE(test_and_set_bit(reason, &wl->queue_stop_reasons[hwq]));
if (stopped)
return;
- ieee80211_stop_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
+ ieee80211_stop_queue(wl->hw, hwq);
}
-void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
+void wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason)
{
unsigned long flags;
spin_lock_irqsave(&wl->wl_lock, flags);
- wlcore_stop_queue_locked(wl, queue, reason);
+ wlcore_stop_queue_locked(wl, wlvif, queue, reason);
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
-void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
+void wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason)
{
unsigned long flags;
+ int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
spin_lock_irqsave(&wl->wl_lock, flags);
/* queue should not be clear for this reason */
- WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[queue]));
+ WARN_ON_ONCE(!test_and_clear_bit(reason, &wl->queue_stop_reasons[hwq]));
- if (wl->queue_stop_reasons[queue])
+ if (wl->queue_stop_reasons[hwq])
goto out;
- ieee80211_wake_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
+ ieee80211_wake_queue(wl->hw, hwq);
out:
spin_unlock_irqrestore(&wl->wl_lock, flags);
@@ -1183,48 +1245,74 @@ void wlcore_stop_queues(struct wl1271 *wl,
enum wlcore_queue_stop_reason reason)
{
int i;
+ unsigned long flags;
- for (i = 0; i < NUM_TX_QUEUES; i++)
- wlcore_stop_queue(wl, i, reason);
+ spin_lock_irqsave(&wl->wl_lock, flags);
+
+ /* mark all possible queues as stopped */
+ for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++)
+ WARN_ON_ONCE(test_and_set_bit(reason,
+ &wl->queue_stop_reasons[i]));
+
+ /* use the global version to make sure all vifs in mac80211 we don't
+ * know are stopped.
+ */
+ ieee80211_stop_queues(wl->hw);
+
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
}
-EXPORT_SYMBOL_GPL(wlcore_stop_queues);
void wlcore_wake_queues(struct wl1271 *wl,
enum wlcore_queue_stop_reason reason)
{
int i;
+ unsigned long flags;
- for (i = 0; i < NUM_TX_QUEUES; i++)
- wlcore_wake_queue(wl, i, reason);
+ spin_lock_irqsave(&wl->wl_lock, flags);
+
+ /* mark all possible queues as awake */
+ for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++)
+ WARN_ON_ONCE(!test_and_clear_bit(reason,
+ &wl->queue_stop_reasons[i]));
+
+ /* use the global version to make sure all vifs in mac80211 we don't
+ * know are woken up.
+ */
+ ieee80211_wake_queues(wl->hw);
+
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
}
-EXPORT_SYMBOL_GPL(wlcore_wake_queues);
-void wlcore_reset_stopped_queues(struct wl1271 *wl)
+bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif, u8 queue,
+ enum wlcore_queue_stop_reason reason)
{
- int i;
unsigned long flags;
+ bool stopped;
spin_lock_irqsave(&wl->wl_lock, flags);
-
- for (i = 0; i < NUM_TX_QUEUES; i++) {
- if (!wl->queue_stop_reasons[i])
- continue;
-
- wl->queue_stop_reasons[i] = 0;
- ieee80211_wake_queue(wl->hw,
- wl1271_tx_get_mac80211_queue(i));
- }
-
+ stopped = wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, queue,
+ reason);
spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ return stopped;
}
-bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
- enum wlcore_queue_stop_reason reason)
+bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif, u8 queue,
+ enum wlcore_queue_stop_reason reason)
{
- return test_bit(reason, &wl->queue_stop_reasons[queue]);
+ int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
+
+ WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
+ return test_bit(reason, &wl->queue_stop_reasons[hwq]);
}
-bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue)
+bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 queue)
{
- return !!wl->queue_stop_reasons[queue];
+ int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
+
+ WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
+ return !!wl->queue_stop_reasons[hwq];
}
diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h
index 349520d8b724..55aa4acf9105 100644
--- a/drivers/net/wireless/ti/wlcore/tx.h
+++ b/drivers/net/wireless/ti/wlcore/tx.h
@@ -207,19 +207,22 @@ static inline int wl1271_tx_get_queue(int queue)
}
}
-static inline int wl1271_tx_get_mac80211_queue(int queue)
+static inline
+int wlcore_tx_get_mac80211_queue(struct wl12xx_vif *wlvif, int queue)
{
+ int mac_queue = wlvif->hw_queue_base;
+
switch (queue) {
case CONF_TX_AC_VO:
- return 0;
+ return mac_queue + 0;
case CONF_TX_AC_VI:
- return 1;
+ return mac_queue + 1;
case CONF_TX_AC_BE:
- return 2;
+ return mac_queue + 2;
case CONF_TX_AC_BK:
- return 3;
+ return mac_queue + 3;
default:
- return 2;
+ return mac_queue + 2;
}
}
@@ -252,20 +255,26 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length);
void wl1271_free_tx_id(struct wl1271 *wl, int id);
-void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
- enum wlcore_queue_stop_reason reason);
-void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
+void wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 queue, enum wlcore_queue_stop_reason reason);
+void wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason);
-void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
+void wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason);
void wlcore_stop_queues(struct wl1271 *wl,
enum wlcore_queue_stop_reason reason);
void wlcore_wake_queues(struct wl1271 *wl,
enum wlcore_queue_stop_reason reason);
-void wlcore_reset_stopped_queues(struct wl1271 *wl);
-bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
+bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif, u8 queue,
enum wlcore_queue_stop_reason reason);
-bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue);
+bool
+wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ u8 queue,
+ enum wlcore_queue_stop_reason reason);
+bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 queue);
/* from main.c */
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index c3884937c007..af9fecaefc30 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -37,6 +37,9 @@
*/
#define WLCORE_NUM_MAC_ADDRESSES 3
+/* wl12xx/wl18xx maximum transmission power (in dBm) */
+#define WLCORE_MAX_TXPWR 25
+
/* forward declaration */
struct wl1271_tx_hw_descr;
enum wl_rx_buf_align;
@@ -51,6 +54,9 @@ struct wlcore_ops {
int (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
void *buf, size_t len);
int (*ack_event)(struct wl1271 *wl);
+ int (*wait_for_event)(struct wl1271 *wl, enum wlcore_wait_event event,
+ bool *timeout);
+ int (*process_mailbox_events)(struct wl1271 *wl);
u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks);
void (*set_tx_desc_blocks)(struct wl1271 *wl,
struct wl1271_tx_hw_descr *desc,
@@ -82,12 +88,32 @@ struct wlcore_ops {
int (*debugfs_init)(struct wl1271 *wl, struct dentry *rootdir);
int (*handle_static_data)(struct wl1271 *wl,
struct wl1271_static_data *static_data);
+ int (*scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_scan_request *req);
+ int (*scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+ int (*sched_scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies);
+ void (*sched_scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem);
int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key_conf);
+ int (*channel_switch)(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct ieee80211_channel_switch *ch_switch);
u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
+ void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ struct ieee80211_sta *sta, u32 changed);
+ int (*set_peer_cap)(struct wl1271 *wl,
+ struct ieee80211_sta_ht_cap *ht_cap,
+ bool allow_ht_operation,
+ u32 rate_set, u8 hlid);
+ bool (*lnk_high_prio)(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk);
+ bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid,
+ struct wl1271_link *lnk);
};
enum wlcore_partitions {
@@ -157,7 +183,6 @@ struct wl1271 {
struct wl1271_if_operations *if_ops;
- void (*set_power)(bool enable);
int irq;
spinlock_t wl_lock;
@@ -202,6 +227,8 @@ struct wl1271 {
unsigned long klv_templates_map[
BITS_TO_LONGS(WLCORE_MAX_KLV_TEMPLATES)];
+ u8 session_ids[WL12XX_MAX_LINKS];
+
struct list_head wlvif_list;
u8 sta_count;
@@ -227,7 +254,8 @@ struct wl1271 {
/* Frames scheduled for transmission, not handled yet */
int tx_queue_count[NUM_TX_QUEUES];
- unsigned long queue_stop_reasons[NUM_TX_QUEUES];
+ unsigned long queue_stop_reasons[
+ NUM_TX_QUEUES * WLCORE_NUM_MAC_ADDRESSES];
/* Frames received, not handled yet by mac80211 */
struct sk_buff_head deferred_rx_queue;
@@ -269,24 +297,30 @@ struct wl1271 {
struct work_struct recovery_work;
bool watchdog_recovery;
+ /* Reg domain last configuration */
+ u32 reg_ch_conf_last[2];
+ /* Reg domain pending configuration */
+ u32 reg_ch_conf_pending[2];
+
/* Pointer that holds DMA-friendly block for the mailbox */
- struct event_mailbox *mbox;
+ void *mbox;
/* The mbox event mask */
u32 event_mask;
/* Mailbox pointers */
+ u32 mbox_size;
u32 mbox_ptr[2];
/* Are we currently scanning */
- struct ieee80211_vif *scan_vif;
+ struct wl12xx_vif *scan_wlvif;
struct wl1271_scan scan;
struct delayed_work scan_complete_work;
- /* Connection loss work */
- struct delayed_work connection_loss_work;
+ struct ieee80211_vif *roc_vif;
+ struct delayed_work roc_complete_work;
- bool sched_scanning;
+ struct wl12xx_vif *sched_vif;
/* The current band */
enum ieee80211_band band;
@@ -299,7 +333,7 @@ struct wl1271 {
struct wl1271_stats stats;
- __le32 buffer_32;
+ __le32 *buffer_32;
u32 buffer_cmd;
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
@@ -314,6 +348,8 @@ struct wl1271 {
bool enable_11a;
+ int recovery_count;
+
/* Most recently reported noise in dBm */
s8 noise;
@@ -333,6 +369,12 @@ struct wl1271 {
*/
struct wl1271_link links[WL12XX_MAX_LINKS];
+ /* number of currently active links */
+ int active_link_count;
+
+ /* Fast/slow links bitmap according to FW */
+ u32 fw_fast_lnk_map;
+
/* AP-mode - a bitmap of links currently in PS mode according to FW */
u32 ap_fw_ps_map;
@@ -367,6 +409,12 @@ struct wl1271 {
const char *sr_fw_name;
const char *mr_fw_name;
+ u8 scan_templ_id_2_4;
+ u8 scan_templ_id_5;
+ u8 sched_scan_templ_id_2_4;
+ u8 sched_scan_templ_id_5;
+ u8 max_channels_5;
+
/* per-chip-family private structure */
void *priv;
@@ -408,20 +456,28 @@ struct wl1271 {
/* the number of allocated MAC addresses in this chip */
int num_mac_addr;
- /* the minimum FW version required for the driver to work */
- unsigned int min_fw_ver[NUM_FW_VER];
+ /* minimum FW version required for the driver to work in single-role */
+ unsigned int min_sr_fw_ver[NUM_FW_VER];
+
+ /* minimum FW version required for the driver to work in multi-role */
+ unsigned int min_mr_fw_ver[NUM_FW_VER];
struct completion nvs_loading_complete;
+
+ /* number of concurrent channels the HW supports */
+ u32 num_channels;
};
int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
int wlcore_remove(struct platform_device *pdev);
-struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size);
+struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
+ u32 mbox_size);
int wlcore_free_hw(struct wl1271 *wl);
int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key_conf);
+void wlcore_regdomain_config(struct wl1271 *wl);
static inline void
wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
@@ -430,16 +486,27 @@ wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap));
}
+/* Tell wlcore not to care about this element when checking the version */
+#define WLCORE_FW_VER_IGNORE -1
+
static inline void
wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip,
- unsigned int iftype, unsigned int major,
- unsigned int subtype, unsigned int minor)
+ unsigned int iftype_sr, unsigned int major_sr,
+ unsigned int subtype_sr, unsigned int minor_sr,
+ unsigned int iftype_mr, unsigned int major_mr,
+ unsigned int subtype_mr, unsigned int minor_mr)
{
- wl->min_fw_ver[FW_VER_CHIP] = chip;
- wl->min_fw_ver[FW_VER_IF_TYPE] = iftype;
- wl->min_fw_ver[FW_VER_MAJOR] = major;
- wl->min_fw_ver[FW_VER_SUBTYPE] = subtype;
- wl->min_fw_ver[FW_VER_MINOR] = minor;
+ wl->min_sr_fw_ver[FW_VER_CHIP] = chip;
+ wl->min_sr_fw_ver[FW_VER_IF_TYPE] = iftype_sr;
+ wl->min_sr_fw_ver[FW_VER_MAJOR] = major_sr;
+ wl->min_sr_fw_ver[FW_VER_SUBTYPE] = subtype_sr;
+ wl->min_sr_fw_ver[FW_VER_MINOR] = minor_sr;
+
+ wl->min_mr_fw_ver[FW_VER_CHIP] = chip;
+ wl->min_mr_fw_ver[FW_VER_IF_TYPE] = iftype_mr;
+ wl->min_mr_fw_ver[FW_VER_MAJOR] = major_mr;
+ wl->min_mr_fw_ver[FW_VER_SUBTYPE] = subtype_mr;
+ wl->min_mr_fw_ver[FW_VER_MINOR] = minor_mr;
}
/* Firmware image load chunk size */
@@ -450,6 +517,9 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip,
/* Each RX/TX transaction requires an end-of-transaction transfer */
#define WLCORE_QUIRK_END_OF_TRANSACTION BIT(0)
+/* the first start_role(sta) sometimes doesn't work on wl12xx */
+#define WLCORE_QUIRK_START_STA_FAILS BIT(1)
+
/* wl127x and SPI don't support SDIO block size alignment */
#define WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN BIT(2)
@@ -462,9 +532,6 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip,
/* Older firmwares use an old NVS format */
#define WLCORE_QUIRK_LEGACY_NVS BIT(5)
-/* Some firmwares may not support ELP */
-#define WLCORE_QUIRK_NO_ELP BIT(6)
-
/* pad only the last frame in the aggregate buffer */
#define WLCORE_QUIRK_TX_PAD_LAST_FRAME BIT(7)
@@ -477,11 +544,11 @@ wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip,
/* separate probe response templates for one-shot and sched scans */
#define WLCORE_QUIRK_DUAL_PROBE_TMPL BIT(10)
-/* TODO: move to the lower drivers when all usages are abstracted */
-#define CHIP_ID_1271_PG10 (0x4030101)
-#define CHIP_ID_1271_PG20 (0x4030111)
-#define CHIP_ID_1283_PG10 (0x05030101)
-#define CHIP_ID_1283_PG20 (0x05030111)
+/* Firmware requires reg domain configuration for active calibration */
+#define WLCORE_QUIRK_REGDOMAIN_CONF BIT(11)
+
+/* The FW only support a zero session id for AP */
+#define WLCORE_QUIRK_AP_ZERO_SESSION_ID BIT(12)
/* TODO: move all these common registers and values elsewhere */
#define HW_ACCESS_ELP_CTRL_REG 0x1FFFC
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index 6678d4b18611..508f5b0f8a70 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -109,22 +109,11 @@ enum {
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
-
-#define FW_VER_MINOR_FWLOG_STA_MIN 70
-
struct wl1271_chip {
u32 id;
- char fw_ver_str[ETHTOOL_BUSINFO_LEN];
+ char fw_ver_str[ETHTOOL_FWVERS_LEN];
unsigned int fw_ver[NUM_FW_VER];
- char phy_fw_ver_str[ETHTOOL_BUSINFO_LEN];
+ char phy_fw_ver_str[ETHTOOL_FWVERS_LEN];
};
#define NUM_TX_QUEUES 4
@@ -141,7 +130,10 @@ struct wl_fw_packet_counters {
/* Cumulative counter of released Voice memory blocks */
u8 tx_voice_released_blks;
- u8 padding[3];
+ /* Tx rate of the last transmitted packet */
+ u8 tx_last_rate;
+
+ u8 padding[2];
} __packed;
/* FW status registers */
@@ -214,6 +206,11 @@ struct wl1271_if_operations {
void (*set_block_size) (struct device *child, unsigned int blksz);
};
+struct wlcore_platdev_data {
+ struct wl12xx_platform_data *pdata;
+ struct wl1271_if_operations *if_ops;
+};
+
#define MAX_NUM_KEYS 14
#define MAX_KEY_SIZE 32
@@ -260,6 +257,8 @@ enum wl12xx_vif_flags {
WLVIF_FLAG_IN_USE,
};
+struct wl12xx_vif;
+
struct wl1271_link {
/* AP-mode - TX queue per AC in link */
struct sk_buff_head tx_queue[NUM_TX_QUEUES];
@@ -272,6 +271,9 @@ struct wl1271_link {
/* bitmap of TIDs where RX BA sessions are active for this link */
u8 ba_bitmap;
+
+ /* The wlvif this link belongs to. Might be null for global links */
+ struct wl12xx_vif *wlvif;
};
#define WL1271_MAX_RX_FILTERS 5
@@ -315,6 +317,7 @@ struct wl12xx_rx_filter {
struct wl1271_station {
u8 hlid;
+ bool in_connection;
};
struct wl12xx_vif {
@@ -332,7 +335,6 @@ struct wl12xx_vif {
union {
struct {
u8 hlid;
- u8 ba_rx_bitmap;
u8 basic_rate_idx;
u8 ap_rate_idx;
@@ -341,6 +343,8 @@ struct wl12xx_vif {
u8 klv_template_id;
bool qos;
+ /* channel type we started the STA role with */
+ enum nl80211_channel_type role_chan_type;
} sta;
struct {
u8 global_hlid;
@@ -362,6 +366,9 @@ struct wl12xx_vif {
/* the hlid of the last transmitted skb */
int last_tx_hlid;
+ /* counters of packets per AC, across all links in the vif */
+ int tx_queue_count[NUM_TX_QUEUES];
+
unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
@@ -396,9 +403,6 @@ struct wl12xx_vif {
/* Our association ID */
u16 aid;
- /* Session counter for the chipset */
- int session_counter;
-
/* retry counter for PSM entries */
u8 psm_entry_retry;
@@ -416,11 +420,28 @@ struct wl12xx_vif {
bool ba_support;
bool ba_allowed;
+ bool wmm_enabled;
+
/* Rx Streaming */
struct work_struct rx_streaming_enable_work;
struct work_struct rx_streaming_disable_work;
struct timer_list rx_streaming_timer;
+ struct delayed_work channel_switch_work;
+ struct delayed_work connection_loss_work;
+
+ /* number of in connection stations */
+ int inconn_count;
+
+ /*
+ * This vif's queues are mapped to mac80211 HW queues as:
+ * VO - hw_queue_base
+ * VI - hw_queue_base + 1
+ * BE - hw_queue_base + 2
+ * BK - hw_queue_base + 3
+ */
+ int hw_queue_base;
+
/*
* This struct must be last!
* data that has to be saved acrossed reconfigs (e.g. recovery)
@@ -443,6 +464,7 @@ struct wl12xx_vif {
static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif)
{
+ WARN_ON(!vif);
return (struct wl12xx_vif *)vif->drv_priv;
}
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig
index 5f809695f71a..96c8e1de0879 100644
--- a/drivers/net/wireless/zd1211rw/Kconfig
+++ b/drivers/net/wireless/zd1211rw/Kconfig
@@ -1,6 +1,6 @@
config ZD1211RW
tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
- depends on USB && MAC80211 && EXPERIMENTAL
+ depends on USB && MAC80211
select FW_LOADER
---help---
This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index ef2b171e3514..7ef0b4a181e1 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -155,7 +155,6 @@ static int upload_code(struct usb_device *udev,
*/
p = kmalloc(MAX_TRANSFER_SIZE, GFP_KERNEL);
if (!p) {
- dev_err(&udev->dev, "out of memory\n");
r = -ENOMEM;
goto error;
}
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index 94b79c3338c4..9d7f1723dd8f 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -151,6 +151,9 @@ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb);
/* Notify xenvif that ring now has space to send an skb to the frontend */
void xenvif_notify_tx_completion(struct xenvif *vif);
+/* Prevent the device from generating any further traffic. */
+void xenvif_carrier_off(struct xenvif *vif);
+
/* Returns number of ring slots required to send an skb to the frontend */
unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb);
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index b7d41f8c338a..d98414168485 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -132,6 +132,7 @@ static void xenvif_up(struct xenvif *vif)
static void xenvif_down(struct xenvif *vif)
{
disable_irq(vif->irq);
+ del_timer_sync(&vif->credit_timeout);
xen_netbk_deschedule_xenvif(vif);
xen_netbk_remove_xenvif(vif);
}
@@ -238,6 +239,8 @@ static const struct net_device_ops xenvif_netdev_ops = {
.ndo_stop = xenvif_close,
.ndo_change_mtu = xenvif_change_mtu,
.ndo_fix_features = xenvif_fix_features,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
};
struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
@@ -343,23 +346,26 @@ err:
return err;
}
-void xenvif_disconnect(struct xenvif *vif)
+void xenvif_carrier_off(struct xenvif *vif)
{
struct net_device *dev = vif->dev;
- if (netif_carrier_ok(dev)) {
- rtnl_lock();
- netif_carrier_off(dev); /* discard queued packets */
- if (netif_running(dev))
- xenvif_down(vif);
- rtnl_unlock();
- xenvif_put(vif);
- }
+
+ rtnl_lock();
+ netif_carrier_off(dev); /* discard queued packets */
+ if (netif_running(dev))
+ xenvif_down(vif);
+ rtnl_unlock();
+ xenvif_put(vif);
+}
+
+void xenvif_disconnect(struct xenvif *vif)
+{
+ if (netif_carrier_ok(vif->dev))
+ xenvif_carrier_off(vif);
atomic_dec(&vif->refcnt);
wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0);
- del_timer_sync(&vif->credit_timeout);
-
if (vif->irq)
unbind_from_irqhandler(vif->irq, vif);
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index f2d6b78d901d..cd49ba949636 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -147,7 +147,8 @@ void xen_netbk_remove_xenvif(struct xenvif *vif)
atomic_dec(&netbk->netfront_count);
}
-static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
+static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx,
+ u8 status);
static void make_tx_response(struct xenvif *vif,
struct xen_netif_tx_request *txp,
s8 st);
@@ -879,7 +880,7 @@ static void netbk_tx_err(struct xenvif *vif,
do {
make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- if (cons >= end)
+ if (cons == end)
break;
txp = RING_GET_REQUEST(&vif->tx, cons++);
} while (1);
@@ -888,6 +889,13 @@ static void netbk_tx_err(struct xenvif *vif,
xenvif_put(vif);
}
+static void netbk_fatal_tx_err(struct xenvif *vif)
+{
+ netdev_err(vif->dev, "fatal error; disabling device\n");
+ xenvif_carrier_off(vif);
+ xenvif_put(vif);
+}
+
static int netbk_count_requests(struct xenvif *vif,
struct xen_netif_tx_request *first,
struct xen_netif_tx_request *txp,
@@ -901,29 +909,33 @@ static int netbk_count_requests(struct xenvif *vif,
do {
if (frags >= work_to_do) {
- netdev_dbg(vif->dev, "Need more frags\n");
- return -frags;
+ netdev_err(vif->dev, "Need more frags\n");
+ netbk_fatal_tx_err(vif);
+ return -ENODATA;
}
if (unlikely(frags >= MAX_SKB_FRAGS)) {
- netdev_dbg(vif->dev, "Too many frags\n");
- return -frags;
+ netdev_err(vif->dev, "Too many frags\n");
+ netbk_fatal_tx_err(vif);
+ return -E2BIG;
}
memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags),
sizeof(*txp));
if (txp->size > first->size) {
- netdev_dbg(vif->dev, "Frags galore\n");
- return -frags;
+ netdev_err(vif->dev, "Frag is bigger than frame.\n");
+ netbk_fatal_tx_err(vif);
+ return -EIO;
}
first->size -= txp->size;
frags++;
if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
- netdev_dbg(vif->dev, "txp->offset: %x, size: %u\n",
+ netdev_err(vif->dev, "txp->offset: %x, size: %u\n",
txp->offset, txp->size);
- return -frags;
+ netbk_fatal_tx_err(vif);
+ return -EINVAL;
}
} while ((txp++)->flags & XEN_NETTXF_more_data);
return frags;
@@ -966,7 +978,7 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
pending_idx = netbk->pending_ring[index];
page = xen_netbk_alloc_page(netbk, skb, pending_idx);
if (!page)
- return NULL;
+ goto err;
gop->source.u.ref = txp->gref;
gop->source.domid = vif->domid;
@@ -988,6 +1000,17 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
}
return gop;
+err:
+ /* Unwind, freeing all pages and sending error responses. */
+ while (i-- > start) {
+ xen_netbk_idx_release(netbk, frag_get_pending_idx(&frags[i]),
+ XEN_NETIF_RSP_ERROR);
+ }
+ /* The head too, if necessary. */
+ if (start)
+ xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR);
+
+ return NULL;
}
static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
@@ -996,30 +1019,20 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
{
struct gnttab_copy *gop = *gopp;
u16 pending_idx = *((u16 *)skb->data);
- struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
- struct xenvif *vif = pending_tx_info[pending_idx].vif;
- struct xen_netif_tx_request *txp;
struct skb_shared_info *shinfo = skb_shinfo(skb);
int nr_frags = shinfo->nr_frags;
int i, err, start;
/* Check status of header. */
err = gop->status;
- if (unlikely(err)) {
- pending_ring_idx_t index;
- index = pending_index(netbk->pending_prod++);
- txp = &pending_tx_info[pending_idx].req;
- make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- netbk->pending_ring[index] = pending_idx;
- xenvif_put(vif);
- }
+ if (unlikely(err))
+ xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR);
/* Skip first skb fragment if it is on same page as header fragment. */
start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
for (i = start; i < nr_frags; i++) {
int j, newerr;
- pending_ring_idx_t index;
pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
@@ -1028,16 +1041,12 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
if (likely(!newerr)) {
/* Had a previous error? Invalidate this fragment. */
if (unlikely(err))
- xen_netbk_idx_release(netbk, pending_idx);
+ xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
continue;
}
/* Error on this fragment: respond to client with an error. */
- txp = &netbk->pending_tx_info[pending_idx].req;
- make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- index = pending_index(netbk->pending_prod++);
- netbk->pending_ring[index] = pending_idx;
- xenvif_put(vif);
+ xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR);
/* Not the first error? Preceding frags already invalidated. */
if (err)
@@ -1045,10 +1054,10 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
/* First error: invalidate header and preceding fragments. */
pending_idx = *((u16 *)skb->data);
- xen_netbk_idx_release(netbk, pending_idx);
+ xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
for (j = start; j < i; j++) {
pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
- xen_netbk_idx_release(netbk, pending_idx);
+ xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
}
/* Remember the error: invalidate all subsequent fragments. */
@@ -1082,7 +1091,7 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb)
/* Take an extra reference to offset xen_netbk_idx_release */
get_page(netbk->mmap_pages[pending_idx]);
- xen_netbk_idx_release(netbk, pending_idx);
+ xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
}
}
@@ -1095,7 +1104,8 @@ static int xen_netbk_get_extras(struct xenvif *vif,
do {
if (unlikely(work_to_do-- <= 0)) {
- netdev_dbg(vif->dev, "Missing extra info\n");
+ netdev_err(vif->dev, "Missing extra info\n");
+ netbk_fatal_tx_err(vif);
return -EBADR;
}
@@ -1104,8 +1114,9 @@ static int xen_netbk_get_extras(struct xenvif *vif,
if (unlikely(!extra.type ||
extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
vif->tx.req_cons = ++cons;
- netdev_dbg(vif->dev,
+ netdev_err(vif->dev,
"Invalid extra type: %d\n", extra.type);
+ netbk_fatal_tx_err(vif);
return -EINVAL;
}
@@ -1121,13 +1132,15 @@ static int netbk_set_skb_gso(struct xenvif *vif,
struct xen_netif_extra_info *gso)
{
if (!gso->u.gso.size) {
- netdev_dbg(vif->dev, "GSO size must not be zero.\n");
+ netdev_err(vif->dev, "GSO size must not be zero.\n");
+ netbk_fatal_tx_err(vif);
return -EINVAL;
}
/* Currently only TCPv4 S.O. is supported. */
if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
- netdev_dbg(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type);
+ netdev_err(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type);
+ netbk_fatal_tx_err(vif);
return -EINVAL;
}
@@ -1264,9 +1277,25 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
/* Get a netif from the list with work to do. */
vif = poll_net_schedule_list(netbk);
+ /* This can sometimes happen because the test of
+ * list_empty(net_schedule_list) at the top of the
+ * loop is unlocked. Just go back and have another
+ * look.
+ */
if (!vif)
continue;
+ if (vif->tx.sring->req_prod - vif->tx.req_cons >
+ XEN_NETIF_TX_RING_SIZE) {
+ netdev_err(vif->dev,
+ "Impossible number of requests. "
+ "req_prod %d, req_cons %d, size %ld\n",
+ vif->tx.sring->req_prod, vif->tx.req_cons,
+ XEN_NETIF_TX_RING_SIZE);
+ netbk_fatal_tx_err(vif);
+ continue;
+ }
+
RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, work_to_do);
if (!work_to_do) {
xenvif_put(vif);
@@ -1294,17 +1323,14 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
work_to_do = xen_netbk_get_extras(vif, extras,
work_to_do);
idx = vif->tx.req_cons;
- if (unlikely(work_to_do < 0)) {
- netbk_tx_err(vif, &txreq, idx);
+ if (unlikely(work_to_do < 0))
continue;
- }
}
ret = netbk_count_requests(vif, &txreq, txfrags, work_to_do);
- if (unlikely(ret < 0)) {
- netbk_tx_err(vif, &txreq, idx - ret);
+ if (unlikely(ret < 0))
continue;
- }
+
idx += ret;
if (unlikely(txreq.size < ETH_HLEN)) {
@@ -1316,11 +1342,11 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
/* No crossing a page as the payload mustn't fragment. */
if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
- netdev_dbg(vif->dev,
+ netdev_err(vif->dev,
"txreq.offset: %x, size: %u, end: %lu\n",
txreq.offset, txreq.size,
(txreq.offset&~PAGE_MASK) + txreq.size);
- netbk_tx_err(vif, &txreq, idx);
+ netbk_fatal_tx_err(vif);
continue;
}
@@ -1348,8 +1374,8 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
if (netbk_set_skb_gso(vif, skb, gso)) {
+ /* Failure in netbk_set_skb_gso is fatal. */
kfree_skb(skb);
- netbk_tx_err(vif, &txreq, idx);
continue;
}
}
@@ -1448,7 +1474,7 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
txp->size -= data_len;
} else {
/* Schedule a response immediately. */
- xen_netbk_idx_release(netbk, pending_idx);
+ xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
}
if (txp->flags & XEN_NETTXF_csum_blank)
@@ -1500,7 +1526,8 @@ static void xen_netbk_tx_action(struct xen_netbk *netbk)
xen_netbk_tx_submit(netbk);
}
-static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
+static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx,
+ u8 status)
{
struct xenvif *vif;
struct pending_tx_info *pending_tx_info;
@@ -1514,7 +1541,7 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
vif = pending_tx_info->vif;
- make_tx_response(vif, &pending_tx_info->req, XEN_NETIF_RSP_OKAY);
+ make_tx_response(vif, &pending_tx_info->req, status);
index = pending_index(netbk->pending_prod++);
netbk->pending_ring[index] = pending_idx;
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index ec857676c39f..e57034971ccc 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -5,19 +5,6 @@
menu "Near Field Communication (NFC) devices"
depends on NFC
-config PN544_HCI_NFC
- tristate "HCI PN544 NFC driver"
- depends on I2C && NFC_HCI && NFC_SHDLC
- select CRC_CCITT
- default n
- ---help---
- NXP PN544 i2c driver.
- This is a driver based on the SHDLC and HCI NFC kernel layers and
- will thus not work with NXP libnfc library.
-
- To compile this driver as a module, choose m here. The module will
- be called pn544_hci.
-
config NFC_PN533
tristate "NXP PN533 USB driver"
depends on USB
@@ -39,4 +26,7 @@ config NFC_WILINK
Say Y here to compile support for Texas Instrument's NFC WiLink driver
into the kernel or say M to compile it as module.
+source "drivers/nfc/pn544/Kconfig"
+source "drivers/nfc/microread/Kconfig"
+
endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 36c359043f54..a189ada0926a 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -2,7 +2,8 @@
# Makefile for nfc devices
#
-obj-$(CONFIG_PN544_HCI_NFC) += pn544/
+obj-$(CONFIG_NFC_PN544) += pn544/
+obj-$(CONFIG_NFC_MICROREAD) += microread/
obj-$(CONFIG_NFC_PN533) += pn533.o
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
diff --git a/drivers/nfc/microread/Kconfig b/drivers/nfc/microread/Kconfig
new file mode 100644
index 000000000000..572305be6e37
--- /dev/null
+++ b/drivers/nfc/microread/Kconfig
@@ -0,0 +1,35 @@
+config NFC_MICROREAD
+ tristate "Inside Secure microread NFC driver"
+ depends on NFC_HCI
+ select CRC_CCITT
+ default n
+ ---help---
+ This module contains the main code for Inside Secure microread
+ NFC chipsets. It implements the chipset HCI logic and hooks into
+ the NFC kernel APIs. Physical layers will register against it.
+
+ To compile this driver as a module, choose m here. The module will
+ be called microread.
+ Say N if unsure.
+
+config NFC_MICROREAD_I2C
+ tristate "NFC Microread i2c support"
+ depends on NFC_MICROREAD && I2C && NFC_SHDLC
+ ---help---
+ This module adds support for the i2c interface of adapters using
+ Inside microread chipsets. Select this if your platform is using
+ the i2c bus.
+
+ If you choose to build a module, it'll be called microread_i2c.
+ Say N if unsure.
+
+config NFC_MICROREAD_MEI
+ tristate "NFC Microread MEI support"
+ depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC
+ ---help---
+ This module adds support for the mei interface of adapters using
+ Inside microread chipsets. Select this if your microread chipset
+ is handled by Intel's Management Engine Interface on your platform.
+
+ If you choose to build a module, it'll be called microread_mei.
+ Say N if unsure.
diff --git a/drivers/nfc/microread/Makefile b/drivers/nfc/microread/Makefile
new file mode 100644
index 000000000000..755c24cba253
--- /dev/null
+++ b/drivers/nfc/microread/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for Microread HCI based NFC driver
+#
+
+microread_i2c-objs = i2c.o
+microread_mei-objs = mei.o
+
+obj-$(CONFIG_NFC_MICROREAD) += microread.o
+obj-$(CONFIG_NFC_MICROREAD_I2C) += microread_i2c.o
+obj-$(CONFIG_NFC_MICROREAD_MEI) += microread_mei.o
diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c
new file mode 100644
index 000000000000..101089495bf8
--- /dev/null
+++ b/drivers/nfc/microread/i2c.c
@@ -0,0 +1,340 @@
+/*
+ * HCI based Driver for Inside Secure microread NFC Chip - i2c layer
+ *
+ * Copyright (C) 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+
+#include <linux/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "microread.h"
+
+#define MICROREAD_I2C_DRIVER_NAME "microread"
+
+#define MICROREAD_I2C_FRAME_HEADROOM 1
+#define MICROREAD_I2C_FRAME_TAILROOM 1
+
+/* framing in HCI mode */
+#define MICROREAD_I2C_LLC_LEN 1
+#define MICROREAD_I2C_LLC_CRC 1
+#define MICROREAD_I2C_LLC_LEN_CRC (MICROREAD_I2C_LLC_LEN + \
+ MICROREAD_I2C_LLC_CRC)
+#define MICROREAD_I2C_LLC_MIN_SIZE (1 + MICROREAD_I2C_LLC_LEN_CRC)
+#define MICROREAD_I2C_LLC_MAX_PAYLOAD 29
+#define MICROREAD_I2C_LLC_MAX_SIZE (MICROREAD_I2C_LLC_LEN_CRC + 1 + \
+ MICROREAD_I2C_LLC_MAX_PAYLOAD)
+
+struct microread_i2c_phy {
+ struct i2c_client *i2c_dev;
+ struct nfc_hci_dev *hdev;
+
+ int irq;
+
+ int hard_fault; /*
+ * < 0 if hardware error occured (e.g. i2c err)
+ * and prevents normal operation.
+ */
+};
+
+#define I2C_DUMP_SKB(info, skb) \
+do { \
+ pr_debug("%s:\n", info); \
+ print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \
+ 16, 1, (skb)->data, (skb)->len, 0); \
+} while (0)
+
+static void microread_i2c_add_len_crc(struct sk_buff *skb)
+{
+ int i;
+ u8 crc = 0;
+ int len;
+
+ len = skb->len;
+ *skb_push(skb, 1) = len;
+
+ for (i = 0; i < skb->len; i++)
+ crc = crc ^ skb->data[i];
+
+ *skb_put(skb, 1) = crc;
+}
+
+static void microread_i2c_remove_len_crc(struct sk_buff *skb)
+{
+ skb_pull(skb, MICROREAD_I2C_FRAME_HEADROOM);
+ skb_trim(skb, MICROREAD_I2C_FRAME_TAILROOM);
+}
+
+static int check_crc(struct sk_buff *skb)
+{
+ int i;
+ u8 crc = 0;
+
+ for (i = 0; i < skb->len - 1; i++)
+ crc = crc ^ skb->data[i];
+
+ if (crc != skb->data[skb->len-1]) {
+ pr_err(MICROREAD_I2C_DRIVER_NAME
+ ": CRC error 0x%x != 0x%x\n",
+ crc, skb->data[skb->len-1]);
+
+ pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__);
+
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int microread_i2c_enable(void *phy_id)
+{
+ return 0;
+}
+
+static void microread_i2c_disable(void *phy_id)
+{
+ return;
+}
+
+static int microread_i2c_write(void *phy_id, struct sk_buff *skb)
+{
+ int r;
+ struct microread_i2c_phy *phy = phy_id;
+ struct i2c_client *client = phy->i2c_dev;
+
+ if (phy->hard_fault != 0)
+ return phy->hard_fault;
+
+ usleep_range(3000, 6000);
+
+ microread_i2c_add_len_crc(skb);
+
+ I2C_DUMP_SKB("i2c frame written", skb);
+
+ r = i2c_master_send(client, skb->data, skb->len);
+
+ if (r == -EREMOTEIO) { /* Retry, chip was in standby */
+ usleep_range(6000, 10000);
+ r = i2c_master_send(client, skb->data, skb->len);
+ }
+
+ if (r >= 0) {
+ if (r != skb->len)
+ r = -EREMOTEIO;
+ else
+ r = 0;
+ }
+
+ microread_i2c_remove_len_crc(skb);
+
+ return r;
+}
+
+
+static int microread_i2c_read(struct microread_i2c_phy *phy,
+ struct sk_buff **skb)
+{
+ int r;
+ u8 len;
+ u8 tmp[MICROREAD_I2C_LLC_MAX_SIZE - 1];
+ struct i2c_client *client = phy->i2c_dev;
+
+ pr_debug("%s\n", __func__);
+
+ r = i2c_master_recv(client, &len, 1);
+ if (r != 1) {
+ dev_err(&client->dev, "cannot read len byte\n");
+ return -EREMOTEIO;
+ }
+
+ if ((len < MICROREAD_I2C_LLC_MIN_SIZE) ||
+ (len > MICROREAD_I2C_LLC_MAX_SIZE)) {
+ dev_err(&client->dev, "invalid len byte\n");
+ pr_err("invalid len byte\n");
+ r = -EBADMSG;
+ goto flush;
+ }
+
+ *skb = alloc_skb(1 + len, GFP_KERNEL);
+ if (*skb == NULL) {
+ r = -ENOMEM;
+ goto flush;
+ }
+
+ *skb_put(*skb, 1) = len;
+
+ r = i2c_master_recv(client, skb_put(*skb, len), len);
+ if (r != len) {
+ kfree_skb(*skb);
+ return -EREMOTEIO;
+ }
+
+ I2C_DUMP_SKB("cc frame read", *skb);
+
+ r = check_crc(*skb);
+ if (r != 0) {
+ kfree_skb(*skb);
+ r = -EBADMSG;
+ goto flush;
+ }
+
+ skb_pull(*skb, 1);
+ skb_trim(*skb, (*skb)->len - MICROREAD_I2C_FRAME_TAILROOM);
+
+ usleep_range(3000, 6000);
+
+ return 0;
+
+flush:
+ if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0)
+ r = -EREMOTEIO;
+
+ usleep_range(3000, 6000);
+
+ return r;
+}
+
+static irqreturn_t microread_i2c_irq_thread_fn(int irq, void *phy_id)
+{
+ struct microread_i2c_phy *phy = phy_id;
+ struct i2c_client *client;
+ struct sk_buff *skb = NULL;
+ int r;
+
+ if (!phy || irq != phy->i2c_dev->irq) {
+ WARN_ON_ONCE(1);
+ return IRQ_NONE;
+ }
+
+ client = phy->i2c_dev;
+ dev_dbg(&client->dev, "IRQ\n");
+
+ if (phy->hard_fault != 0)
+ return IRQ_HANDLED;
+
+ r = microread_i2c_read(phy, &skb);
+ if (r == -EREMOTEIO) {
+ phy->hard_fault = r;
+
+ nfc_hci_recv_frame(phy->hdev, NULL);
+
+ return IRQ_HANDLED;
+ } else if ((r == -ENOMEM) || (r == -EBADMSG)) {
+ return IRQ_HANDLED;
+ }
+
+ nfc_hci_recv_frame(phy->hdev, skb);
+
+ return IRQ_HANDLED;
+}
+
+static struct nfc_phy_ops i2c_phy_ops = {
+ .write = microread_i2c_write,
+ .enable = microread_i2c_enable,
+ .disable = microread_i2c_disable,
+};
+
+static int microread_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct microread_i2c_phy *phy;
+ struct microread_nfc_platform_data *pdata =
+ dev_get_platdata(&client->dev);
+ int r;
+
+ dev_dbg(&client->dev, "client %p", client);
+
+ if (!pdata) {
+ dev_err(&client->dev, "client %p: missing platform data",
+ client);
+ return -EINVAL;
+ }
+
+ phy = devm_kzalloc(&client->dev, sizeof(struct microread_i2c_phy),
+ GFP_KERNEL);
+ if (!phy) {
+ dev_err(&client->dev, "Can't allocate microread phy");
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, phy);
+ phy->i2c_dev = client;
+
+ r = request_threaded_irq(client->irq, NULL, microread_i2c_irq_thread_fn,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ MICROREAD_I2C_DRIVER_NAME, phy);
+ if (r) {
+ dev_err(&client->dev, "Unable to register IRQ handler");
+ return r;
+ }
+
+ r = microread_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
+ MICROREAD_I2C_FRAME_HEADROOM,
+ MICROREAD_I2C_FRAME_TAILROOM,
+ MICROREAD_I2C_LLC_MAX_PAYLOAD, &phy->hdev);
+ if (r < 0)
+ goto err_irq;
+
+ dev_info(&client->dev, "Probed");
+
+ return 0;
+
+err_irq:
+ free_irq(client->irq, phy);
+
+ return r;
+}
+
+static int microread_i2c_remove(struct i2c_client *client)
+{
+ struct microread_i2c_phy *phy = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ microread_remove(phy->hdev);
+
+ free_irq(client->irq, phy);
+
+ return 0;
+}
+
+static struct i2c_device_id microread_i2c_id[] = {
+ { MICROREAD_I2C_DRIVER_NAME, 0},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, microread_i2c_id);
+
+static struct i2c_driver microread_i2c_driver = {
+ .driver = {
+ .name = MICROREAD_I2C_DRIVER_NAME,
+ },
+ .probe = microread_i2c_probe,
+ .remove = microread_i2c_remove,
+ .id_table = microread_i2c_id,
+};
+
+module_i2c_driver(microread_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c
new file mode 100644
index 000000000000..eef38cfd812e
--- /dev/null
+++ b/drivers/nfc/microread/mei.c
@@ -0,0 +1,246 @@
+/*
+ * HCI based Driver for Inside Secure microread NFC Chip
+ *
+ * Copyright (C) 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/mei_bus.h>
+
+#include <linux/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "microread.h"
+
+#define MICROREAD_DRIVER_NAME "microread"
+
+#define MICROREAD_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \
+ 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
+
+struct mei_nfc_hdr {
+ u8 cmd;
+ u8 status;
+ u16 req_id;
+ u32 reserved;
+ u16 data_size;
+} __attribute__((packed));
+
+#define MEI_NFC_HEADER_SIZE 10
+#define MEI_NFC_MAX_HCI_PAYLOAD 300
+#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
+
+struct microread_mei_phy {
+ struct mei_device *mei_device;
+ struct nfc_hci_dev *hdev;
+
+ int powered;
+
+ int hard_fault; /*
+ * < 0 if hardware error occured (e.g. i2c err)
+ * and prevents normal operation.
+ */
+};
+
+#define MEI_DUMP_SKB_IN(info, skb) \
+do { \
+ pr_debug("%s:\n", info); \
+ print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET, \
+ 16, 1, (skb)->data, (skb)->len, 0); \
+} while (0)
+
+#define MEI_DUMP_SKB_OUT(info, skb) \
+do { \
+ pr_debug("%s:\n", info); \
+ print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET, \
+ 16, 1, (skb)->data, (skb)->len, 0); \
+} while (0)
+
+static int microread_mei_enable(void *phy_id)
+{
+ struct microread_mei_phy *phy = phy_id;
+
+ pr_info(DRIVER_DESC ": %s\n", __func__);
+
+ phy->powered = 1;
+
+ return 0;
+}
+
+static void microread_mei_disable(void *phy_id)
+{
+ struct microread_mei_phy *phy = phy_id;
+
+ pr_info(DRIVER_DESC ": %s\n", __func__);
+
+ phy->powered = 0;
+}
+
+/*
+ * Writing a frame must not return the number of written bytes.
+ * It must return either zero for success, or <0 for error.
+ * In addition, it must not alter the skb
+ */
+static int microread_mei_write(void *phy_id, struct sk_buff *skb)
+{
+ struct microread_mei_phy *phy = phy_id;
+ int r;
+
+ MEI_DUMP_SKB_OUT("mei frame sent", skb);
+
+ r = mei_send(phy->device, skb->data, skb->len);
+ if (r > 0)
+ r = 0;
+
+ return r;
+}
+
+static void microread_event_cb(struct mei_device *device, u32 events,
+ void *context)
+{
+ struct microread_mei_phy *phy = context;
+
+ if (phy->hard_fault != 0)
+ return;
+
+ if (events & BIT(MEI_EVENT_RX)) {
+ struct sk_buff *skb;
+ int reply_size;
+
+ skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
+ if (!skb)
+ return;
+
+ reply_size = mei_recv(device, skb->data, MEI_NFC_MAX_READ);
+ if (reply_size < MEI_NFC_HEADER_SIZE) {
+ kfree(skb);
+ return;
+ }
+
+ skb_put(skb, reply_size);
+ skb_pull(skb, MEI_NFC_HEADER_SIZE);
+
+ MEI_DUMP_SKB_IN("mei frame read", skb);
+
+ nfc_hci_recv_frame(phy->hdev, skb);
+ }
+}
+
+static struct nfc_phy_ops mei_phy_ops = {
+ .write = microread_mei_write,
+ .enable = microread_mei_enable,
+ .disable = microread_mei_disable,
+};
+
+static int microread_mei_probe(struct mei_device *device,
+ const struct mei_id *id)
+{
+ struct microread_mei_phy *phy;
+ int r;
+
+ pr_info("Probing NFC microread\n");
+
+ phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL);
+ if (!phy) {
+ pr_err("Cannot allocate memory for microread mei phy.\n");
+ return -ENOMEM;
+ }
+
+ phy->device = device;
+ mei_set_clientdata(device, phy);
+
+ r = mei_register_event_cb(device, microread_event_cb, phy);
+ if (r) {
+ pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
+ goto err_out;
+ }
+
+ r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
+ MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
+ &phy->hdev);
+ if (r < 0)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ kfree(phy);
+
+ return r;
+}
+
+static int microread_mei_remove(struct mei_device *device)
+{
+ struct microread_mei_phy *phy = mei_get_clientdata(device);
+
+ pr_info("Removing microread\n");
+
+ microread_remove(phy->hdev);
+
+ if (phy->powered)
+ microread_mei_disable(phy);
+
+ kfree(phy);
+
+ return 0;
+}
+
+static struct mei_id microread_mei_tbl[] = {
+ { MICROREAD_DRIVER_NAME, MICROREAD_UUID },
+
+ /* required last entry */
+ { }
+};
+
+MODULE_DEVICE_TABLE(mei, microread_mei_tbl);
+
+static struct mei_driver microread_driver = {
+ .id_table = microread_mei_tbl,
+ .name = MICROREAD_DRIVER_NAME,
+
+ .probe = microread_mei_probe,
+ .remove = microread_mei_remove,
+};
+
+static int microread_mei_init(void)
+{
+ int r;
+
+ pr_debug(DRIVER_DESC ": %s\n", __func__);
+
+ r = mei_driver_register(&microread_driver);
+ if (r) {
+ pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n");
+ return r;
+ }
+
+ return 0;
+}
+
+static void microread_mei_exit(void)
+{
+ mei_driver_unregister(&microread_driver);
+}
+
+module_init(microread_mei_init);
+module_exit(microread_mei_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c
new file mode 100644
index 000000000000..3420d833db17
--- /dev/null
+++ b/drivers/nfc/microread/microread.c
@@ -0,0 +1,728 @@
+/*
+ * HCI based Driver for Inside Secure microread NFC Chip
+ *
+ * Copyright (C) 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/crc-ccitt.h>
+
+#include <linux/nfc.h>
+#include <net/nfc/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "microread.h"
+
+/* Proprietary gates, events, commands and registers */
+/* Admin */
+#define MICROREAD_GATE_ID_ADM NFC_HCI_ADMIN_GATE
+#define MICROREAD_GATE_ID_MGT 0x01
+#define MICROREAD_GATE_ID_OS 0x02
+#define MICROREAD_GATE_ID_TESTRF 0x03
+#define MICROREAD_GATE_ID_LOOPBACK NFC_HCI_LOOPBACK_GATE
+#define MICROREAD_GATE_ID_IDT NFC_HCI_ID_MGMT_GATE
+#define MICROREAD_GATE_ID_LMS NFC_HCI_LINK_MGMT_GATE
+
+/* Reader */
+#define MICROREAD_GATE_ID_MREAD_GEN 0x10
+#define MICROREAD_GATE_ID_MREAD_ISO_B NFC_HCI_RF_READER_B_GATE
+#define MICROREAD_GATE_ID_MREAD_NFC_T1 0x12
+#define MICROREAD_GATE_ID_MREAD_ISO_A NFC_HCI_RF_READER_A_GATE
+#define MICROREAD_GATE_ID_MREAD_NFC_T3 0x14
+#define MICROREAD_GATE_ID_MREAD_ISO_15_3 0x15
+#define MICROREAD_GATE_ID_MREAD_ISO_15_2 0x16
+#define MICROREAD_GATE_ID_MREAD_ISO_B_3 0x17
+#define MICROREAD_GATE_ID_MREAD_BPRIME 0x18
+#define MICROREAD_GATE_ID_MREAD_ISO_A_3 0x19
+
+/* Card */
+#define MICROREAD_GATE_ID_MCARD_GEN 0x20
+#define MICROREAD_GATE_ID_MCARD_ISO_B 0x21
+#define MICROREAD_GATE_ID_MCARD_BPRIME 0x22
+#define MICROREAD_GATE_ID_MCARD_ISO_A 0x23
+#define MICROREAD_GATE_ID_MCARD_NFC_T3 0x24
+#define MICROREAD_GATE_ID_MCARD_ISO_15_3 0x25
+#define MICROREAD_GATE_ID_MCARD_ISO_15_2 0x26
+#define MICROREAD_GATE_ID_MCARD_ISO_B_2 0x27
+#define MICROREAD_GATE_ID_MCARD_ISO_CUSTOM 0x28
+#define MICROREAD_GATE_ID_SECURE_ELEMENT 0x2F
+
+/* P2P */
+#define MICROREAD_GATE_ID_P2P_GEN 0x30
+#define MICROREAD_GATE_ID_P2P_TARGET 0x31
+#define MICROREAD_PAR_P2P_TARGET_MODE 0x01
+#define MICROREAD_PAR_P2P_TARGET_GT 0x04
+#define MICROREAD_GATE_ID_P2P_INITIATOR 0x32
+#define MICROREAD_PAR_P2P_INITIATOR_GI 0x01
+#define MICROREAD_PAR_P2P_INITIATOR_GT 0x03
+
+/* Those pipes are created/opened by default in the chip */
+#define MICROREAD_PIPE_ID_LMS 0x00
+#define MICROREAD_PIPE_ID_ADMIN 0x01
+#define MICROREAD_PIPE_ID_MGT 0x02
+#define MICROREAD_PIPE_ID_OS 0x03
+#define MICROREAD_PIPE_ID_HDS_LOOPBACK 0x04
+#define MICROREAD_PIPE_ID_HDS_IDT 0x05
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B 0x08
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_BPRIME 0x09
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_A 0x0A
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_3 0x0B
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_2 0x0C
+#define MICROREAD_PIPE_ID_HDS_MCARD_NFC_T3 0x0D
+#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B_2 0x0E
+#define MICROREAD_PIPE_ID_HDS_MCARD_CUSTOM 0x0F
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B 0x10
+#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1 0x11
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A 0x12
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_3 0x13
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_2 0x14
+#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3 0x15
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B_3 0x16
+#define MICROREAD_PIPE_ID_HDS_MREAD_BPRIME 0x17
+#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3 0x18
+#define MICROREAD_PIPE_ID_HDS_MREAD_GEN 0x1B
+#define MICROREAD_PIPE_ID_HDS_STACKED_ELEMENT 0x1C
+#define MICROREAD_PIPE_ID_HDS_INSTANCES 0x1D
+#define MICROREAD_PIPE_ID_HDS_TESTRF 0x1E
+#define MICROREAD_PIPE_ID_HDS_P2P_TARGET 0x1F
+#define MICROREAD_PIPE_ID_HDS_P2P_INITIATOR 0x20
+
+/* Events */
+#define MICROREAD_EVT_MREAD_DISCOVERY_OCCURED NFC_HCI_EVT_TARGET_DISCOVERED
+#define MICROREAD_EVT_MREAD_CARD_FOUND 0x3D
+#define MICROREAD_EMCF_A_ATQA 0
+#define MICROREAD_EMCF_A_SAK 2
+#define MICROREAD_EMCF_A_LEN 3
+#define MICROREAD_EMCF_A_UID 4
+#define MICROREAD_EMCF_A3_ATQA 0
+#define MICROREAD_EMCF_A3_SAK 2
+#define MICROREAD_EMCF_A3_LEN 3
+#define MICROREAD_EMCF_A3_UID 4
+#define MICROREAD_EMCF_B_UID 0
+#define MICROREAD_EMCF_T1_ATQA 0
+#define MICROREAD_EMCF_T1_UID 4
+#define MICROREAD_EMCF_T3_UID 0
+#define MICROREAD_EVT_MREAD_DISCOVERY_START NFC_HCI_EVT_READER_REQUESTED
+#define MICROREAD_EVT_MREAD_DISCOVERY_START_SOME 0x3E
+#define MICROREAD_EVT_MREAD_DISCOVERY_STOP NFC_HCI_EVT_END_OPERATION
+#define MICROREAD_EVT_MREAD_SIM_REQUESTS 0x3F
+#define MICROREAD_EVT_MCARD_EXCHANGE NFC_HCI_EVT_TARGET_DISCOVERED
+#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF 0x20
+#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF 0x21
+#define MICROREAD_EVT_MCARD_FIELD_ON 0x11
+#define MICROREAD_EVT_P2P_TARGET_ACTIVATED 0x13
+#define MICROREAD_EVT_P2P_TARGET_DEACTIVATED 0x12
+#define MICROREAD_EVT_MCARD_FIELD_OFF 0x14
+
+/* Commands */
+#define MICROREAD_CMD_MREAD_EXCHANGE 0x10
+#define MICROREAD_CMD_MREAD_SUBSCRIBE 0x3F
+
+/* Hosts IDs */
+#define MICROREAD_ELT_ID_HDS NFC_HCI_TERMINAL_HOST_ID
+#define MICROREAD_ELT_ID_SIM NFC_HCI_UICC_HOST_ID
+#define MICROREAD_ELT_ID_SE1 0x03
+#define MICROREAD_ELT_ID_SE2 0x04
+#define MICROREAD_ELT_ID_SE3 0x05
+
+static struct nfc_hci_gate microread_gates[] = {
+ {MICROREAD_GATE_ID_ADM, MICROREAD_PIPE_ID_ADMIN},
+ {MICROREAD_GATE_ID_LOOPBACK, MICROREAD_PIPE_ID_HDS_LOOPBACK},
+ {MICROREAD_GATE_ID_IDT, MICROREAD_PIPE_ID_HDS_IDT},
+ {MICROREAD_GATE_ID_LMS, MICROREAD_PIPE_ID_LMS},
+ {MICROREAD_GATE_ID_MREAD_ISO_B, MICROREAD_PIPE_ID_HDS_MREAD_ISO_B},
+ {MICROREAD_GATE_ID_MREAD_ISO_A, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A},
+ {MICROREAD_GATE_ID_MREAD_ISO_A_3, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3},
+ {MICROREAD_GATE_ID_MGT, MICROREAD_PIPE_ID_MGT},
+ {MICROREAD_GATE_ID_OS, MICROREAD_PIPE_ID_OS},
+ {MICROREAD_GATE_ID_MREAD_NFC_T1, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1},
+ {MICROREAD_GATE_ID_MREAD_NFC_T3, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3},
+ {MICROREAD_GATE_ID_P2P_TARGET, MICROREAD_PIPE_ID_HDS_P2P_TARGET},
+ {MICROREAD_GATE_ID_P2P_INITIATOR, MICROREAD_PIPE_ID_HDS_P2P_INITIATOR}
+};
+
+/* Largest headroom needed for outgoing custom commands */
+#define MICROREAD_CMDS_HEADROOM 2
+#define MICROREAD_CMD_TAILROOM 2
+
+struct microread_info {
+ struct nfc_phy_ops *phy_ops;
+ void *phy_id;
+
+ struct nfc_hci_dev *hdev;
+
+ int async_cb_type;
+ data_exchange_cb_t async_cb;
+ void *async_cb_context;
+};
+
+static int microread_open(struct nfc_hci_dev *hdev)
+{
+ struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+ return info->phy_ops->enable(info->phy_id);
+}
+
+static void microread_close(struct nfc_hci_dev *hdev)
+{
+ struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+ info->phy_ops->disable(info->phy_id);
+}
+
+static int microread_hci_ready(struct nfc_hci_dev *hdev)
+{
+ int r;
+ u8 param[4];
+
+ param[0] = 0x03;
+ r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
+ MICROREAD_CMD_MREAD_SUBSCRIBE, param, 1, NULL);
+ if (r)
+ return r;
+
+ r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A_3,
+ MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL);
+ if (r)
+ return r;
+
+ param[0] = 0x00;
+ param[1] = 0x03;
+ param[2] = 0x00;
+ r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_B,
+ MICROREAD_CMD_MREAD_SUBSCRIBE, param, 3, NULL);
+ if (r)
+ return r;
+
+ r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T1,
+ MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL);
+ if (r)
+ return r;
+
+ param[0] = 0xFF;
+ param[1] = 0xFF;
+ param[2] = 0x00;
+ param[3] = 0x00;
+ r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T3,
+ MICROREAD_CMD_MREAD_SUBSCRIBE, param, 4, NULL);
+
+ return r;
+}
+
+static int microread_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+ struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+ return info->phy_ops->write(info->phy_id, skb);
+}
+
+static int microread_start_poll(struct nfc_hci_dev *hdev,
+ u32 im_protocols, u32 tm_protocols)
+{
+ int r;
+
+ u8 param[2];
+ u8 mode;
+
+ param[0] = 0x00;
+ param[1] = 0x00;
+
+ if (im_protocols & NFC_PROTO_ISO14443_MASK)
+ param[0] |= (1 << 2);
+
+ if (im_protocols & NFC_PROTO_ISO14443_B_MASK)
+ param[0] |= 1;
+
+ if (im_protocols & NFC_PROTO_MIFARE_MASK)
+ param[1] |= 1;
+
+ if (im_protocols & NFC_PROTO_JEWEL_MASK)
+ param[0] |= (1 << 1);
+
+ if (im_protocols & NFC_PROTO_FELICA_MASK)
+ param[0] |= (1 << 5);
+
+ if (im_protocols & NFC_PROTO_NFC_DEP_MASK)
+ param[1] |= (1 << 1);
+
+ if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
+ hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
+ &hdev->gb_len);
+ if (hdev->gb == NULL || hdev->gb_len == 0) {
+ im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
+ tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
+ }
+ }
+
+ r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
+ MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0);
+ if (r)
+ return r;
+
+ mode = 0xff;
+ r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+ MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
+ if (r)
+ return r;
+
+ if (im_protocols & NFC_PROTO_NFC_DEP_MASK) {
+ r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_INITIATOR,
+ MICROREAD_PAR_P2P_INITIATOR_GI,
+ hdev->gb, hdev->gb_len);
+ if (r)
+ return r;
+ }
+
+ if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
+ r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+ MICROREAD_PAR_P2P_TARGET_GT,
+ hdev->gb, hdev->gb_len);
+ if (r)
+ return r;
+
+ mode = 0x02;
+ r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+ MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
+ if (r)
+ return r;
+ }
+
+ return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
+ MICROREAD_EVT_MREAD_DISCOVERY_START_SOME,
+ param, 2);
+}
+
+static int microread_dep_link_up(struct nfc_hci_dev *hdev,
+ struct nfc_target *target, u8 comm_mode,
+ u8 *gb, size_t gb_len)
+{
+ struct sk_buff *rgb_skb = NULL;
+ int r;
+
+ r = nfc_hci_get_param(hdev, target->hci_reader_gate,
+ MICROREAD_PAR_P2P_INITIATOR_GT, &rgb_skb);
+ if (r < 0)
+ return r;
+
+ if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) {
+ r = -EPROTO;
+ goto exit;
+ }
+
+ r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data,
+ rgb_skb->len);
+ if (r == 0)
+ r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode,
+ NFC_RF_INITIATOR);
+exit:
+ kfree_skb(rgb_skb);
+
+ return r;
+}
+
+static int microread_dep_link_down(struct nfc_hci_dev *hdev)
+{
+ return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_INITIATOR,
+ MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0);
+}
+
+static int microread_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
+ struct nfc_target *target)
+{
+ switch (gate) {
+ case MICROREAD_GATE_ID_P2P_INITIATOR:
+ target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+ break;
+ default:
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+static int microread_complete_target_discovered(struct nfc_hci_dev *hdev,
+ u8 gate,
+ struct nfc_target *target)
+{
+ return 0;
+}
+
+#define MICROREAD_CB_TYPE_READER_ALL 1
+
+static void microread_im_transceive_cb(void *context, struct sk_buff *skb,
+ int err)
+{
+ struct microread_info *info = context;
+
+ switch (info->async_cb_type) {
+ case MICROREAD_CB_TYPE_READER_ALL:
+ if (err == 0) {
+ if (skb->len == 0) {
+ err = -EPROTO;
+ kfree_skb(skb);
+ info->async_cb(info->async_cb_context, NULL,
+ -EPROTO);
+ return;
+ }
+
+ if (skb->data[skb->len - 1] != 0) {
+ err = nfc_hci_result_to_errno(
+ skb->data[skb->len - 1]);
+ kfree_skb(skb);
+ info->async_cb(info->async_cb_context, NULL,
+ err);
+ return;
+ }
+
+ skb_trim(skb, skb->len - 1); /* RF Error ind. */
+ }
+ info->async_cb(info->async_cb_context, skb, err);
+ break;
+ default:
+ if (err == 0)
+ kfree_skb(skb);
+ break;
+ }
+}
+
+/*
+ * Returns:
+ * <= 0: driver handled the data exchange
+ * 1: driver doesn't especially handle, please do standard processing
+ */
+static int microread_im_transceive(struct nfc_hci_dev *hdev,
+ struct nfc_target *target,
+ struct sk_buff *skb, data_exchange_cb_t cb,
+ void *cb_context)
+{
+ struct microread_info *info = nfc_hci_get_clientdata(hdev);
+ u8 control_bits;
+ u16 crc;
+
+ pr_info("data exchange to gate 0x%x\n", target->hci_reader_gate);
+
+ if (target->hci_reader_gate == MICROREAD_GATE_ID_P2P_INITIATOR) {
+ *skb_push(skb, 1) = 0;
+
+ return nfc_hci_send_event(hdev, target->hci_reader_gate,
+ MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF,
+ skb->data, skb->len);
+ }
+
+ switch (target->hci_reader_gate) {
+ case MICROREAD_GATE_ID_MREAD_ISO_A:
+ control_bits = 0xCB;
+ break;
+ case MICROREAD_GATE_ID_MREAD_ISO_A_3:
+ control_bits = 0xCB;
+ break;
+ case MICROREAD_GATE_ID_MREAD_ISO_B:
+ control_bits = 0xCB;
+ break;
+ case MICROREAD_GATE_ID_MREAD_NFC_T1:
+ control_bits = 0x1B;
+
+ crc = crc_ccitt(0xffff, skb->data, skb->len);
+ crc = ~crc;
+ *skb_put(skb, 1) = crc & 0xff;
+ *skb_put(skb, 1) = crc >> 8;
+ break;
+ case MICROREAD_GATE_ID_MREAD_NFC_T3:
+ control_bits = 0xDB;
+ break;
+ default:
+ pr_info("Abort im_transceive to invalid gate 0x%x\n",
+ target->hci_reader_gate);
+ return 1;
+ }
+
+ *skb_push(skb, 1) = control_bits;
+
+ info->async_cb_type = MICROREAD_CB_TYPE_READER_ALL;
+ info->async_cb = cb;
+ info->async_cb_context = cb_context;
+
+ return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
+ MICROREAD_CMD_MREAD_EXCHANGE,
+ skb->data, skb->len,
+ microread_im_transceive_cb, info);
+}
+
+static int microread_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+ int r;
+
+ r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+ MICROREAD_EVT_MCARD_EXCHANGE,
+ skb->data, skb->len);
+
+ kfree_skb(skb);
+
+ return r;
+}
+
+static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate,
+ struct sk_buff *skb)
+{
+ struct nfc_target *targets;
+ int r = 0;
+
+ pr_info("target discovered to gate 0x%x\n", gate);
+
+ targets = kzalloc(sizeof(struct nfc_target), GFP_KERNEL);
+ if (targets == NULL) {
+ r = -ENOMEM;
+ goto exit;
+ }
+
+ targets->hci_reader_gate = gate;
+
+ switch (gate) {
+ case MICROREAD_GATE_ID_MREAD_ISO_A:
+ targets->supported_protocols =
+ nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A_SAK]);
+ targets->sens_res =
+ be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A_ATQA]);
+ targets->sel_res = skb->data[MICROREAD_EMCF_A_SAK];
+ memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A_UID],
+ skb->data[MICROREAD_EMCF_A_LEN]);
+ targets->nfcid1_len = skb->data[MICROREAD_EMCF_A_LEN];
+ break;
+ case MICROREAD_GATE_ID_MREAD_ISO_A_3:
+ targets->supported_protocols =
+ nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A3_SAK]);
+ targets->sens_res =
+ be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A3_ATQA]);
+ targets->sel_res = skb->data[MICROREAD_EMCF_A3_SAK];
+ memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A3_UID],
+ skb->data[MICROREAD_EMCF_A3_LEN]);
+ targets->nfcid1_len = skb->data[MICROREAD_EMCF_A3_LEN];
+ break;
+ case MICROREAD_GATE_ID_MREAD_ISO_B:
+ targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK;
+ memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_B_UID], 4);
+ targets->nfcid1_len = 4;
+ break;
+ case MICROREAD_GATE_ID_MREAD_NFC_T1:
+ targets->supported_protocols = NFC_PROTO_JEWEL_MASK;
+ targets->sens_res =
+ le16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_T1_ATQA]);
+ memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T1_UID], 4);
+ targets->nfcid1_len = 4;
+ break;
+ case MICROREAD_GATE_ID_MREAD_NFC_T3:
+ targets->supported_protocols = NFC_PROTO_FELICA_MASK;
+ memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T3_UID], 8);
+ targets->nfcid1_len = 8;
+ break;
+ default:
+ pr_info("discard target discovered to gate 0x%x\n", gate);
+ goto exit_free;
+ }
+
+ r = nfc_targets_found(hdev->ndev, targets, 1);
+
+exit_free:
+ kfree(targets);
+
+exit:
+ kfree_skb(skb);
+
+ if (r)
+ pr_err("Failed to handle discovered target err=%d", r);
+}
+
+static int microread_event_received(struct nfc_hci_dev *hdev, u8 gate,
+ u8 event, struct sk_buff *skb)
+{
+ int r;
+ u8 mode;
+
+ pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate);
+
+ switch (event) {
+ case MICROREAD_EVT_MREAD_CARD_FOUND:
+ microread_target_discovered(hdev, gate, skb);
+ return 0;
+
+ case MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF:
+ if (skb->len < 1) {
+ kfree_skb(skb);
+ return -EPROTO;
+ }
+
+ if (skb->data[skb->len - 1]) {
+ kfree_skb(skb);
+ return -EIO;
+ }
+
+ skb_trim(skb, skb->len - 1);
+
+ r = nfc_tm_data_received(hdev->ndev, skb);
+ break;
+
+ case MICROREAD_EVT_MCARD_FIELD_ON:
+ case MICROREAD_EVT_MCARD_FIELD_OFF:
+ kfree_skb(skb);
+ return 0;
+
+ case MICROREAD_EVT_P2P_TARGET_ACTIVATED:
+ r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
+ NFC_COMM_PASSIVE, skb->data,
+ skb->len);
+
+ kfree_skb(skb);
+ break;
+
+ case MICROREAD_EVT_MCARD_EXCHANGE:
+ if (skb->len < 1) {
+ kfree_skb(skb);
+ return -EPROTO;
+ }
+
+ if (skb->data[skb->len-1]) {
+ kfree_skb(skb);
+ return -EIO;
+ }
+
+ skb_trim(skb, skb->len - 1);
+
+ r = nfc_tm_data_received(hdev->ndev, skb);
+ break;
+
+ case MICROREAD_EVT_P2P_TARGET_DEACTIVATED:
+ kfree_skb(skb);
+
+ mode = 0xff;
+ r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
+ MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
+ if (r)
+ break;
+
+ r = nfc_hci_send_event(hdev, gate,
+ MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL,
+ 0);
+ break;
+
+ default:
+ return 1;
+ }
+
+ return r;
+}
+
+static struct nfc_hci_ops microread_hci_ops = {
+ .open = microread_open,
+ .close = microread_close,
+ .hci_ready = microread_hci_ready,
+ .xmit = microread_xmit,
+ .start_poll = microread_start_poll,
+ .dep_link_up = microread_dep_link_up,
+ .dep_link_down = microread_dep_link_down,
+ .target_from_gate = microread_target_from_gate,
+ .complete_target_discovered = microread_complete_target_discovered,
+ .im_transceive = microread_im_transceive,
+ .tm_send = microread_tm_send,
+ .check_presence = NULL,
+ .event_received = microread_event_received,
+};
+
+int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
+ int phy_headroom, int phy_tailroom, int phy_payload,
+ struct nfc_hci_dev **hdev)
+{
+ struct microread_info *info;
+ unsigned long quirks = 0;
+ u32 protocols, se;
+ struct nfc_hci_init_data init_data;
+ int r;
+
+ info = kzalloc(sizeof(struct microread_info), GFP_KERNEL);
+ if (!info) {
+ pr_err("Cannot allocate memory for microread_info.\n");
+ r = -ENOMEM;
+ goto err_info_alloc;
+ }
+
+ info->phy_ops = phy_ops;
+ info->phy_id = phy_id;
+
+ init_data.gate_count = ARRAY_SIZE(microread_gates);
+ memcpy(init_data.gates, microread_gates, sizeof(microread_gates));
+
+ strcpy(init_data.session_id, "MICROREA");
+
+ set_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &quirks);
+
+ protocols = NFC_PROTO_JEWEL_MASK |
+ NFC_PROTO_MIFARE_MASK |
+ NFC_PROTO_FELICA_MASK |
+ NFC_PROTO_ISO14443_MASK |
+ NFC_PROTO_ISO14443_B_MASK |
+ NFC_PROTO_NFC_DEP_MASK;
+
+ se = NFC_SE_UICC | NFC_SE_EMBEDDED;
+
+ info->hdev = nfc_hci_allocate_device(&microread_hci_ops, &init_data,
+ quirks, protocols, se, llc_name,
+ phy_headroom +
+ MICROREAD_CMDS_HEADROOM,
+ phy_tailroom +
+ MICROREAD_CMD_TAILROOM,
+ phy_payload);
+ if (!info->hdev) {
+ pr_err("Cannot allocate nfc hdev.\n");
+ r = -ENOMEM;
+ goto err_alloc_hdev;
+ }
+
+ nfc_hci_set_clientdata(info->hdev, info);
+
+ r = nfc_hci_register_device(info->hdev);
+ if (r)
+ goto err_regdev;
+
+ *hdev = info->hdev;
+
+ return 0;
+
+err_regdev:
+ nfc_hci_free_device(info->hdev);
+
+err_alloc_hdev:
+ kfree(info);
+
+err_info_alloc:
+ return r;
+}
+EXPORT_SYMBOL(microread_probe);
+
+void microread_remove(struct nfc_hci_dev *hdev)
+{
+ struct microread_info *info = nfc_hci_get_clientdata(hdev);
+
+ nfc_hci_unregister_device(hdev);
+ nfc_hci_free_device(hdev);
+ kfree(info);
+}
+EXPORT_SYMBOL(microread_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/microread/microread.h b/drivers/nfc/microread/microread.h
new file mode 100644
index 000000000000..64b447a1c5bf
--- /dev/null
+++ b/drivers/nfc/microread/microread.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 - 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LOCAL_MICROREAD_H_
+#define __LOCAL_MICROREAD_H_
+
+#include <net/nfc/hci.h>
+
+#define DRIVER_DESC "NFC driver for microread"
+
+int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
+ int phy_headroom, int phy_tailroom, int phy_payload,
+ struct nfc_hci_dev **hdev);
+
+void microread_remove(struct nfc_hci_dev *hdev);
+
+#endif /* __LOCAL_MICROREAD_H_ */
diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c
index 50b1ee41afc6..3b731acbc408 100644
--- a/drivers/nfc/nfcwilink.c
+++ b/drivers/nfc/nfcwilink.c
@@ -526,7 +526,7 @@ static int nfcwilink_probe(struct platform_device *pdev)
nfc_dev_dbg(&pdev->dev, "probe entry");
- drv = kzalloc(sizeof(struct nfcwilink), GFP_KERNEL);
+ drv = devm_kzalloc(&pdev->dev, sizeof(struct nfcwilink), GFP_KERNEL);
if (!drv) {
rc = -ENOMEM;
goto exit;
@@ -542,12 +542,13 @@ static int nfcwilink_probe(struct platform_device *pdev)
drv->ndev = nci_allocate_device(&nfcwilink_ops,
protocols,
+ NFC_SE_NONE,
NFCWILINK_HDR_LEN,
0);
if (!drv->ndev) {
nfc_dev_err(&pdev->dev, "nci_allocate_device failed");
rc = -ENOMEM;
- goto free_exit;
+ goto exit;
}
nci_set_parent_dev(drv->ndev, &pdev->dev);
@@ -566,9 +567,6 @@ static int nfcwilink_probe(struct platform_device *pdev)
free_dev_exit:
nci_free_device(drv->ndev);
-free_exit:
- kfree(drv);
-
exit:
return rc;
}
@@ -588,8 +586,6 @@ static int nfcwilink_remove(struct platform_device *pdev)
nci_unregister_device(ndev);
nci_free_device(ndev);
- kfree(drv);
-
dev_set_drvdata(&pdev->dev, NULL);
return 0;
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index ada681b01a17..f0f6763d67ae 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -41,11 +41,6 @@
#define SONY_VENDOR_ID 0x054c
#define PASORI_PRODUCT_ID 0x02e1
-#define PN533_QUIRKS_TYPE_A BIT(0)
-#define PN533_QUIRKS_TYPE_F BIT(1)
-#define PN533_QUIRKS_DEP BIT(2)
-#define PN533_QUIRKS_RAW_EXCHANGE BIT(3)
-
#define PN533_DEVICE_STD 0x1
#define PN533_DEVICE_PASORI 0x2
@@ -84,14 +79,18 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_LISTEN_TIME 2
/* frame definitions */
-#define PN533_NORMAL_FRAME_MAX_LEN 262 /* 6 (PREAMBLE, SOF, LEN, LCS, TFI)
- 254 (DATA)
- 2 (DCS, postamble) */
-
-#define PN533_FRAME_TAIL_SIZE 2
-#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
- PN533_FRAME_TAIL_SIZE)
-#define PN533_FRAME_ACK_SIZE (sizeof(struct pn533_frame) + 1)
+#define PN533_FRAME_HEADER_LEN (sizeof(struct pn533_frame) \
+ + 2) /* data[0] TFI, data[1] CC */
+#define PN533_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
+
+/*
+ * Max extended frame payload len, excluding TFI and CC
+ * which are already in PN533_FRAME_HEADER_LEN.
+ */
+#define PN533_FRAME_MAX_PAYLOAD_LEN 263
+
+#define PN533_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2),
+ Postamble (1) */
#define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen])
#define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
@@ -105,8 +104,6 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
/* PN533 Commands */
#define PN533_FRAME_CMD(f) (f->data[1])
-#define PN533_FRAME_CMD_PARAMS_PTR(f) (&f->data[2])
-#define PN533_FRAME_CMD_PARAMS_LEN(f) (f->datalen - 2)
#define PN533_CMD_GET_FIRMWARE_VERSION 0x02
#define PN533_CMD_RF_CONFIGURATION 0x32
@@ -120,6 +117,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_CMD_TG_INIT_AS_TARGET 0x8c
#define PN533_CMD_TG_GET_DATA 0x86
#define PN533_CMD_TG_SET_DATA 0x8e
+#define PN533_CMD_UNDEF 0xff
#define PN533_CMD_RESPONSE(cmd) (cmd + 1)
@@ -128,13 +126,12 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_CMD_MI_MASK 0x40
#define PN533_CMD_RET_SUCCESS 0x00
-/* PN533 status codes */
-#define PN533_STATUS_TARGET_RELEASED 0x29
-
struct pn533;
-typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg,
- u8 *params, int params_len);
+typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, int status);
+
+typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg,
+ struct sk_buff *resp);
/* structs for pn533 commands */
@@ -222,7 +219,7 @@ struct pn533_poll_modulations {
u8 len;
};
-const struct pn533_poll_modulations poll_mod[] = {
+static const struct pn533_poll_modulations poll_mod[] = {
[PN533_POLL_MOD_106KBPS_A] = {
.data = {
.maxtg = 1,
@@ -282,11 +279,6 @@ const struct pn533_poll_modulations poll_mod[] = {
/* PN533_CMD_IN_ATR */
-struct pn533_cmd_activate_param {
- u8 tg;
- u8 next;
-} __packed;
-
struct pn533_cmd_activate_response {
u8 status;
u8 nfcid3t[10];
@@ -299,14 +291,6 @@ struct pn533_cmd_activate_response {
u8 gt[];
} __packed;
-/* PN533_CMD_IN_JUMP_FOR_DEP */
-struct pn533_cmd_jump_dep {
- u8 active;
- u8 baud;
- u8 next;
- u8 data[];
-} __packed;
-
struct pn533_cmd_jump_dep_response {
u8 status;
u8 tg;
@@ -329,32 +313,13 @@ struct pn533_cmd_jump_dep_response {
#define PN533_INIT_TARGET_RESP_ACTIVE 0x1
#define PN533_INIT_TARGET_RESP_DEP 0x4
-struct pn533_cmd_init_target {
- u8 mode;
- u8 mifare[6];
- u8 felica[18];
- u8 nfcid3[10];
- u8 gb_len;
- u8 gb[];
-} __packed;
-
-struct pn533_cmd_init_target_response {
- u8 mode;
- u8 cmd[];
-} __packed;
-
struct pn533 {
struct usb_device *udev;
struct usb_interface *interface;
struct nfc_dev *nfc_dev;
struct urb *out_urb;
- int out_maxlen;
- struct pn533_frame *out_frame;
-
struct urb *in_urb;
- int in_maxlen;
- struct pn533_frame *in_frame;
struct sk_buff_head resp_q;
@@ -365,12 +330,12 @@ struct pn533 {
struct work_struct mi_work;
struct work_struct tg_work;
struct timer_list listen_timer;
- struct pn533_frame *wq_in_frame;
int wq_in_error;
int cancel_listen;
pn533_cmd_complete_t cmd_complete;
void *cmd_complete_arg;
+ void *cmd_complete_mi_arg;
struct mutex cmd_lock;
u8 cmd;
@@ -391,16 +356,17 @@ struct pn533 {
struct list_head cmd_queue;
u8 cmd_pending;
+
+ struct pn533_frame_ops *ops;
};
struct pn533_cmd {
struct list_head queue;
- struct pn533_frame *out_frame;
- struct pn533_frame *in_frame;
- int in_frame_len;
- pn533_cmd_complete_t cmd_complete;
+ u8 cmd_code;
+ struct sk_buff *req;
+ struct sk_buff *resp;
+ int resp_len;
void *arg;
- gfp_t flags;
};
struct pn533_frame {
@@ -411,6 +377,22 @@ struct pn533_frame {
u8 data[];
} __packed;
+struct pn533_frame_ops {
+ void (*tx_frame_init)(void *frame, u8 cmd_code);
+ void (*tx_frame_finish)(void *frame);
+ void (*tx_update_payload_len)(void *frame, int len);
+ int tx_header_len;
+ int tx_tail_len;
+
+ bool (*rx_is_frame_valid)(void *frame);
+ int (*rx_frame_size)(void *frame);
+ int rx_header_len;
+ int rx_tail_len;
+
+ int max_payload_len;
+ u8 (*get_cmd_code)(void *frame);
+};
+
/* The rule: value + checksum = 0 */
static inline u8 pn533_checksum(u8 value)
{
@@ -429,37 +411,21 @@ static u8 pn533_data_checksum(u8 *data, int datalen)
return pn533_checksum(sum);
}
-/**
- * pn533_tx_frame_ack - create a ack frame
- * @frame: The frame to be set as ack
- *
- * Ack is different type of standard frame. As a standard frame, it has
- * preamble and start_frame. However the checksum of this frame must fail,
- * i.e. datalen + datalen_checksum must NOT be zero. When the checksum test
- * fails and datalen = 0 and datalen_checksum = 0xFF, the frame is a ack.
- * After datalen_checksum field, the postamble is placed.
- */
-static void pn533_tx_frame_ack(struct pn533_frame *frame)
+static void pn533_tx_frame_init(void *_frame, u8 cmd_code)
{
- frame->preamble = 0;
- frame->start_frame = cpu_to_be16(PN533_SOF);
- frame->datalen = 0;
- frame->datalen_checksum = 0xFF;
- /* data[0] is used as postamble */
- frame->data[0] = 0;
-}
+ struct pn533_frame *frame = _frame;
-static void pn533_tx_frame_init(struct pn533_frame *frame, u8 cmd)
-{
frame->preamble = 0;
frame->start_frame = cpu_to_be16(PN533_SOF);
PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT;
- PN533_FRAME_CMD(frame) = cmd;
+ PN533_FRAME_CMD(frame) = cmd_code;
frame->datalen = 2;
}
-static void pn533_tx_frame_finish(struct pn533_frame *frame)
+static void pn533_tx_frame_finish(void *_frame)
{
+ struct pn533_frame *frame = _frame;
+
frame->datalen_checksum = pn533_checksum(frame->datalen);
PN533_FRAME_CHECKSUM(frame) =
@@ -468,9 +434,17 @@ static void pn533_tx_frame_finish(struct pn533_frame *frame)
PN533_FRAME_POSTAMBLE(frame) = 0;
}
-static bool pn533_rx_frame_is_valid(struct pn533_frame *frame)
+static void pn533_tx_update_payload_len(void *_frame, int len)
+{
+ struct pn533_frame *frame = _frame;
+
+ frame->datalen += len;
+}
+
+static bool pn533_rx_frame_is_valid(void *_frame)
{
u8 checksum;
+ struct pn533_frame *frame = _frame;
if (frame->start_frame != cpu_to_be16(PN533_SOF))
return false;
@@ -497,28 +471,48 @@ static bool pn533_rx_frame_is_ack(struct pn533_frame *frame)
return true;
}
-static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd)
+static inline int pn533_rx_frame_size(void *frame)
+{
+ struct pn533_frame *f = frame;
+
+ return sizeof(struct pn533_frame) + f->datalen + PN533_FRAME_TAIL_LEN;
+}
+
+static u8 pn533_get_cmd_code(void *frame)
+{
+ struct pn533_frame *f = frame;
+
+ return PN533_FRAME_CMD(f);
+}
+
+static struct pn533_frame_ops pn533_std_frame_ops = {
+ .tx_frame_init = pn533_tx_frame_init,
+ .tx_frame_finish = pn533_tx_frame_finish,
+ .tx_update_payload_len = pn533_tx_update_payload_len,
+ .tx_header_len = PN533_FRAME_HEADER_LEN,
+ .tx_tail_len = PN533_FRAME_TAIL_LEN,
+
+ .rx_is_frame_valid = pn533_rx_frame_is_valid,
+ .rx_frame_size = pn533_rx_frame_size,
+ .rx_header_len = PN533_FRAME_HEADER_LEN,
+ .rx_tail_len = PN533_FRAME_TAIL_LEN,
+
+ .max_payload_len = PN533_FRAME_MAX_PAYLOAD_LEN,
+ .get_cmd_code = pn533_get_cmd_code,
+};
+
+static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame)
{
- return (PN533_FRAME_CMD(frame) == PN533_CMD_RESPONSE(cmd));
+ return (dev->ops->get_cmd_code(frame) == PN533_CMD_RESPONSE(dev->cmd));
}
static void pn533_wq_cmd_complete(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work);
- struct pn533_frame *in_frame;
int rc;
- in_frame = dev->wq_in_frame;
-
- if (dev->wq_in_error)
- rc = dev->cmd_complete(dev, dev->cmd_complete_arg, NULL,
- dev->wq_in_error);
- else
- rc = dev->cmd_complete(dev, dev->cmd_complete_arg,
- PN533_FRAME_CMD_PARAMS_PTR(in_frame),
- PN533_FRAME_CMD_PARAMS_LEN(in_frame));
-
+ rc = dev->cmd_complete(dev, dev->cmd_complete_arg, dev->wq_in_error);
if (rc != -EINPROGRESS)
queue_work(dev->wq, &dev->cmd_work);
}
@@ -526,46 +520,46 @@ static void pn533_wq_cmd_complete(struct work_struct *work)
static void pn533_recv_response(struct urb *urb)
{
struct pn533 *dev = urb->context;
- struct pn533_frame *in_frame;
-
- dev->wq_in_frame = NULL;
+ u8 *in_frame;
switch (urb->status) {
case 0:
- /* success */
- break;
+ break; /* success */
case -ECONNRESET:
case -ENOENT:
- case -ESHUTDOWN:
- nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
- " status: %d", urb->status);
+ nfc_dev_dbg(&dev->interface->dev,
+ "The urb has been canceled (status %d)",
+ urb->status);
dev->wq_in_error = urb->status;
goto sched_wq;
+ case -ESHUTDOWN:
default:
- nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:"
- " %d", urb->status);
+ nfc_dev_err(&dev->interface->dev,
+ "Urb failure (status %d)", urb->status);
dev->wq_in_error = urb->status;
goto sched_wq;
}
in_frame = dev->in_urb->transfer_buffer;
- if (!pn533_rx_frame_is_valid(in_frame)) {
+ nfc_dev_dbg(&dev->interface->dev, "Received a frame.");
+ print_hex_dump(KERN_DEBUG, "PN533 RX: ", DUMP_PREFIX_NONE, 16, 1,
+ in_frame, dev->ops->rx_frame_size(in_frame), false);
+
+ if (!dev->ops->rx_is_frame_valid(in_frame)) {
nfc_dev_err(&dev->interface->dev, "Received an invalid frame");
dev->wq_in_error = -EIO;
goto sched_wq;
}
- if (!pn533_rx_frame_is_cmd_response(in_frame, dev->cmd)) {
- nfc_dev_err(&dev->interface->dev, "The received frame is not "
- "response to the last command");
+ if (!pn533_rx_frame_is_cmd_response(dev, in_frame)) {
+ nfc_dev_err(&dev->interface->dev,
+ "It it not the response to the last command");
dev->wq_in_error = -EIO;
goto sched_wq;
}
- nfc_dev_dbg(&dev->interface->dev, "Received a valid frame");
dev->wq_in_error = 0;
- dev->wq_in_frame = in_frame;
sched_wq:
queue_work(dev->wq, &dev->cmd_complete_work);
@@ -586,18 +580,18 @@ static void pn533_recv_ack(struct urb *urb)
switch (urb->status) {
case 0:
- /* success */
- break;
+ break; /* success */
case -ECONNRESET:
case -ENOENT:
- case -ESHUTDOWN:
- nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
- " status: %d", urb->status);
+ nfc_dev_dbg(&dev->interface->dev,
+ "The urb has been stopped (status %d)",
+ urb->status);
dev->wq_in_error = urb->status;
goto sched_wq;
+ case -ESHUTDOWN:
default:
- nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:"
- " %d", urb->status);
+ nfc_dev_err(&dev->interface->dev,
+ "Urb failure (status %d)", urb->status);
dev->wq_in_error = urb->status;
goto sched_wq;
}
@@ -610,12 +604,10 @@ static void pn533_recv_ack(struct urb *urb)
goto sched_wq;
}
- nfc_dev_dbg(&dev->interface->dev, "Received a valid ack");
-
rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC);
if (rc) {
- nfc_dev_err(&dev->interface->dev, "usb_submit_urb failed with"
- " result %d", rc);
+ nfc_dev_err(&dev->interface->dev,
+ "usb_submit_urb failed with result %d", rc);
dev->wq_in_error = rc;
goto sched_wq;
}
@@ -623,7 +615,6 @@ static void pn533_recv_ack(struct urb *urb)
return;
sched_wq:
- dev->wq_in_frame = NULL;
queue_work(dev->wq, &dev->cmd_complete_work);
}
@@ -636,47 +627,46 @@ static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags)
static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
{
+ u8 ack[PN533_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
+ /* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- pn533_tx_frame_ack(dev->out_frame);
-
- dev->out_urb->transfer_buffer = dev->out_frame;
- dev->out_urb->transfer_buffer_length = PN533_FRAME_ACK_SIZE;
+ dev->out_urb->transfer_buffer = ack;
+ dev->out_urb->transfer_buffer_length = sizeof(ack);
rc = usb_submit_urb(dev->out_urb, flags);
return rc;
}
-static int __pn533_send_cmd_frame_async(struct pn533 *dev,
- struct pn533_frame *out_frame,
- struct pn533_frame *in_frame,
- int in_frame_len,
+static int __pn533_send_frame_async(struct pn533 *dev,
+ struct sk_buff *out,
+ struct sk_buff *in,
+ int in_len,
pn533_cmd_complete_t cmd_complete,
- void *arg, gfp_t flags)
+ void *arg)
{
int rc;
- nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x",
- PN533_FRAME_CMD(out_frame));
-
- dev->cmd = PN533_FRAME_CMD(out_frame);
+ dev->cmd = dev->ops->get_cmd_code(out->data);
dev->cmd_complete = cmd_complete;
dev->cmd_complete_arg = arg;
- dev->out_urb->transfer_buffer = out_frame;
- dev->out_urb->transfer_buffer_length =
- PN533_FRAME_SIZE(out_frame);
+ dev->out_urb->transfer_buffer = out->data;
+ dev->out_urb->transfer_buffer_length = out->len;
- dev->in_urb->transfer_buffer = in_frame;
- dev->in_urb->transfer_buffer_length = in_frame_len;
+ dev->in_urb->transfer_buffer = in->data;
+ dev->in_urb->transfer_buffer_length = in_len;
- rc = usb_submit_urb(dev->out_urb, flags);
+ print_hex_dump(KERN_DEBUG, "PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
+ out->data, out->len, false);
+
+ rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
if (rc)
return rc;
- rc = pn533_submit_urb_for_ack(dev, flags);
+ rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL);
if (rc)
goto error;
@@ -687,146 +677,325 @@ error:
return rc;
}
-static void pn533_wq_cmd(struct work_struct *work)
+static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code,
+ struct sk_buff *skb)
{
- struct pn533 *dev = container_of(work, struct pn533, cmd_work);
- struct pn533_cmd *cmd;
+ /* payload is already there, just update datalen */
+ int payload_len = skb->len;
+ struct pn533_frame_ops *ops = dev->ops;
- mutex_lock(&dev->cmd_lock);
- if (list_empty(&dev->cmd_queue)) {
- dev->cmd_pending = 0;
- mutex_unlock(&dev->cmd_lock);
- return;
- }
+ skb_push(skb, ops->tx_header_len);
+ skb_put(skb, ops->tx_tail_len);
- cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue);
+ ops->tx_frame_init(skb->data, cmd_code);
+ ops->tx_update_payload_len(skb->data, payload_len);
+ ops->tx_frame_finish(skb->data);
+}
- list_del(&cmd->queue);
+struct pn533_send_async_complete_arg {
+ pn533_send_async_complete_t complete_cb;
+ void *complete_cb_context;
+ struct sk_buff *resp;
+ struct sk_buff *req;
+};
- mutex_unlock(&dev->cmd_lock);
+static int pn533_send_async_complete(struct pn533 *dev, void *_arg, int status)
+{
+ struct pn533_send_async_complete_arg *arg = _arg;
- __pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame,
- cmd->in_frame_len, cmd->cmd_complete,
- cmd->arg, cmd->flags);
+ struct sk_buff *req = arg->req;
+ struct sk_buff *resp = arg->resp;
- kfree(cmd);
+ int rc;
+
+ dev_kfree_skb(req);
+
+ if (status < 0) {
+ arg->complete_cb(dev, arg->complete_cb_context,
+ ERR_PTR(status));
+ dev_kfree_skb(resp);
+ kfree(arg);
+ return status;
+ }
+
+ skb_put(resp, dev->ops->rx_frame_size(resp->data));
+ skb_pull(resp, dev->ops->rx_header_len);
+ skb_trim(resp, resp->len - dev->ops->rx_tail_len);
+
+ rc = arg->complete_cb(dev, arg->complete_cb_context, resp);
+
+ kfree(arg);
+ return rc;
}
-static int pn533_send_cmd_frame_async(struct pn533 *dev,
- struct pn533_frame *out_frame,
- struct pn533_frame *in_frame,
- int in_frame_len,
- pn533_cmd_complete_t cmd_complete,
- void *arg, gfp_t flags)
+static int __pn533_send_async(struct pn533 *dev, u8 cmd_code,
+ struct sk_buff *req, struct sk_buff *resp,
+ int resp_len,
+ pn533_send_async_complete_t complete_cb,
+ void *complete_cb_context)
{
struct pn533_cmd *cmd;
+ struct pn533_send_async_complete_arg *arg;
int rc = 0;
- nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+ nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", cmd_code);
+
+ arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+ if (!arg)
+ return -ENOMEM;
+
+ arg->complete_cb = complete_cb;
+ arg->complete_cb_context = complete_cb_context;
+ arg->resp = resp;
+ arg->req = req;
+
+ pn533_build_cmd_frame(dev, cmd_code, req);
mutex_lock(&dev->cmd_lock);
if (!dev->cmd_pending) {
- rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
- in_frame_len, cmd_complete,
- arg, flags);
- if (!rc)
- dev->cmd_pending = 1;
+ rc = __pn533_send_frame_async(dev, req, resp, resp_len,
+ pn533_send_async_complete, arg);
+ if (rc)
+ goto error;
+ dev->cmd_pending = 1;
goto unlock;
}
- nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__);
+ nfc_dev_dbg(&dev->interface->dev, "%s Queueing command 0x%x", __func__,
+ cmd_code);
- cmd = kzalloc(sizeof(struct pn533_cmd), flags);
+ cmd = kzalloc(sizeof(struct pn533_cmd), GFP_KERNEL);
if (!cmd) {
rc = -ENOMEM;
- goto unlock;
+ goto error;
}
INIT_LIST_HEAD(&cmd->queue);
- cmd->out_frame = out_frame;
- cmd->in_frame = in_frame;
- cmd->in_frame_len = in_frame_len;
- cmd->cmd_complete = cmd_complete;
+ cmd->cmd_code = cmd_code;
+ cmd->req = req;
+ cmd->resp = resp;
+ cmd->resp_len = resp_len;
cmd->arg = arg;
- cmd->flags = flags;
list_add_tail(&cmd->queue, &dev->cmd_queue);
+ goto unlock;
+
+error:
+ kfree(arg);
unlock:
mutex_unlock(&dev->cmd_lock);
+ return rc;
+}
+
+static int pn533_send_data_async(struct pn533 *dev, u8 cmd_code,
+ struct sk_buff *req,
+ pn533_send_async_complete_t complete_cb,
+ void *complete_cb_context)
+{
+ struct sk_buff *resp;
+ int rc;
+ int resp_len = dev->ops->rx_header_len +
+ dev->ops->max_payload_len +
+ dev->ops->rx_tail_len;
+
+ resp = nfc_alloc_recv_skb(resp_len, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb,
+ complete_cb_context);
+ if (rc)
+ dev_kfree_skb(resp);
return rc;
}
-struct pn533_sync_cmd_response {
+static int pn533_send_cmd_async(struct pn533 *dev, u8 cmd_code,
+ struct sk_buff *req,
+ pn533_send_async_complete_t complete_cb,
+ void *complete_cb_context)
+{
+ struct sk_buff *resp;
int rc;
- struct completion done;
-};
+ int resp_len = dev->ops->rx_header_len +
+ dev->ops->max_payload_len +
+ dev->ops->rx_tail_len;
+
+ resp = alloc_skb(resp_len, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb,
+ complete_cb_context);
+ if (rc)
+ dev_kfree_skb(resp);
+
+ return rc;
+}
-static int pn533_sync_cmd_complete(struct pn533 *dev, void *_arg,
- u8 *params, int params_len)
+/*
+ * pn533_send_cmd_direct_async
+ *
+ * The function sends a piority cmd directly to the chip omiting the cmd
+ * queue. It's intended to be used by chaining mechanism of received responses
+ * where the host has to request every single chunk of data before scheduling
+ * next cmd from the queue.
+ */
+static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
+ struct sk_buff *req,
+ pn533_send_async_complete_t complete_cb,
+ void *complete_cb_context)
{
- struct pn533_sync_cmd_response *arg = _arg;
+ struct pn533_send_async_complete_arg *arg;
+ struct sk_buff *resp;
+ int rc;
+ int resp_len = dev->ops->rx_header_len +
+ dev->ops->max_payload_len +
+ dev->ops->rx_tail_len;
- nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+ resp = alloc_skb(resp_len, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+ if (!arg) {
+ dev_kfree_skb(resp);
+ return -ENOMEM;
+ }
+
+ arg->complete_cb = complete_cb;
+ arg->complete_cb_context = complete_cb_context;
+ arg->resp = resp;
+ arg->req = req;
+
+ pn533_build_cmd_frame(dev, cmd_code, req);
+
+ rc = __pn533_send_frame_async(dev, req, resp, resp_len,
+ pn533_send_async_complete, arg);
+ if (rc < 0) {
+ dev_kfree_skb(resp);
+ kfree(arg);
+ }
+
+ return rc;
+}
+
+static void pn533_wq_cmd(struct work_struct *work)
+{
+ struct pn533 *dev = container_of(work, struct pn533, cmd_work);
+ struct pn533_cmd *cmd;
+
+ mutex_lock(&dev->cmd_lock);
+
+ if (list_empty(&dev->cmd_queue)) {
+ dev->cmd_pending = 0;
+ mutex_unlock(&dev->cmd_lock);
+ return;
+ }
+
+ cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue);
+
+ list_del(&cmd->queue);
+
+ mutex_unlock(&dev->cmd_lock);
+
+ __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len,
+ pn533_send_async_complete, cmd->arg);
+
+ kfree(cmd);
+}
- arg->rc = 0;
+struct pn533_sync_cmd_response {
+ struct sk_buff *resp;
+ struct completion done;
+};
- if (params_len < 0) /* error */
- arg->rc = params_len;
+static int pn533_send_sync_complete(struct pn533 *dev, void *_arg,
+ struct sk_buff *resp)
+{
+ struct pn533_sync_cmd_response *arg = _arg;
+ arg->resp = resp;
complete(&arg->done);
return 0;
}
-static int pn533_send_cmd_frame_sync(struct pn533 *dev,
- struct pn533_frame *out_frame,
- struct pn533_frame *in_frame,
- int in_frame_len)
+/* pn533_send_cmd_sync
+ *
+ * Please note the req parameter is freed inside the function to
+ * limit a number of return value interpretations by the caller.
+ *
+ * 1. negative in case of error during TX path -> req should be freed
+ *
+ * 2. negative in case of error during RX path -> req should not be freed
+ * as it's been already freed at the begining of RX path by
+ * async_complete_cb.
+ *
+ * 3. valid pointer in case of succesfult RX path
+ *
+ * A caller has to check a return value with IS_ERR macro. If the test pass,
+ * the returned pointer is valid.
+ *
+ * */
+static struct sk_buff *pn533_send_cmd_sync(struct pn533 *dev, u8 cmd_code,
+ struct sk_buff *req)
{
int rc;
struct pn533_sync_cmd_response arg;
- nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
-
init_completion(&arg.done);
- rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, in_frame_len,
- pn533_sync_cmd_complete, &arg, GFP_KERNEL);
- if (rc)
- return rc;
+ rc = pn533_send_cmd_async(dev, cmd_code, req,
+ pn533_send_sync_complete, &arg);
+ if (rc) {
+ dev_kfree_skb(req);
+ return ERR_PTR(rc);
+ }
wait_for_completion(&arg.done);
- return arg.rc;
+ return arg.resp;
}
static void pn533_send_complete(struct urb *urb)
{
struct pn533 *dev = urb->context;
- nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
-
switch (urb->status) {
case 0:
- /* success */
- break;
+ break; /* success */
case -ECONNRESET:
case -ENOENT:
- case -ESHUTDOWN:
- nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with"
- " status: %d", urb->status);
+ nfc_dev_dbg(&dev->interface->dev,
+ "The urb has been stopped (status %d)",
+ urb->status);
break;
+ case -ESHUTDOWN:
default:
- nfc_dev_dbg(&dev->interface->dev, "Nonzero urb status received:"
- " %d", urb->status);
+ nfc_dev_err(&dev->interface->dev,
+ "Urb failure (status %d)", urb->status);
}
}
+static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size)
+{
+ struct sk_buff *skb;
+
+ skb = alloc_skb(dev->ops->tx_header_len +
+ size +
+ dev->ops->tx_tail_len, GFP_KERNEL);
+
+ if (skb)
+ skb_reserve(skb, dev->ops->tx_header_len);
+
+ return skb;
+}
+
struct pn533_target_type_a {
__be16 sens_res;
u8 sel_res;
@@ -867,9 +1036,9 @@ static bool pn533_target_type_a_is_valid(struct pn533_target_type_a *type_a,
platconf = PN533_TYPE_A_SENS_RES_PLATCONF(type_a->sens_res);
if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
- platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
- (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
- platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+ platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+ (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+ platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
return false;
/* Requirements 4.8.2.1, 4.8.2.3, 4.8.2.5 and 4.8.2.7 from NFC Forum */
@@ -884,7 +1053,7 @@ static int pn533_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data,
{
struct pn533_target_type_a *tgt_type_a;
- tgt_type_a = (struct pn533_target_type_a *) tgt_data;
+ tgt_type_a = (struct pn533_target_type_a *)tgt_data;
if (!pn533_target_type_a_is_valid(tgt_type_a, tgt_data_len))
return -EPROTO;
@@ -942,14 +1111,13 @@ static int pn533_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data,
{
struct pn533_target_felica *tgt_felica;
- tgt_felica = (struct pn533_target_felica *) tgt_data;
+ tgt_felica = (struct pn533_target_felica *)tgt_data;
if (!pn533_target_felica_is_valid(tgt_felica, tgt_data_len))
return -EPROTO;
- if (tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1 &&
- tgt_felica->nfcid2[1] ==
- PN533_FELICA_SENSF_NFCID2_DEP_B2)
+ if ((tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1) &&
+ (tgt_felica->nfcid2[1] == PN533_FELICA_SENSF_NFCID2_DEP_B2))
nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
else
nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK;
@@ -979,9 +1147,9 @@ static bool pn533_target_jewel_is_valid(struct pn533_target_jewel *jewel,
platconf = PN533_TYPE_A_SENS_RES_PLATCONF(jewel->sens_res);
if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
- platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
- (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
- platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+ platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+ (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+ platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
return false;
return true;
@@ -992,7 +1160,7 @@ static int pn533_target_found_jewel(struct nfc_target *nfc_tgt, u8 *tgt_data,
{
struct pn533_target_jewel *tgt_jewel;
- tgt_jewel = (struct pn533_target_jewel *) tgt_data;
+ tgt_jewel = (struct pn533_target_jewel *)tgt_data;
if (!pn533_target_jewel_is_valid(tgt_jewel, tgt_data_len))
return -EPROTO;
@@ -1051,7 +1219,7 @@ static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data,
{
struct pn533_target_type_b *tgt_type_b;
- tgt_type_b = (struct pn533_target_type_b *) tgt_data;
+ tgt_type_b = (struct pn533_target_type_b *)tgt_data;
if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len))
return -EPROTO;
@@ -1061,50 +1229,37 @@ static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data,
return 0;
}
-struct pn533_poll_response {
- u8 nbtg;
- u8 tg;
- u8 target_data[];
-} __packed;
-
-static int pn533_target_found(struct pn533 *dev,
- struct pn533_poll_response *resp, int resp_len)
+static int pn533_target_found(struct pn533 *dev, u8 tg, u8 *tgdata,
+ int tgdata_len)
{
- int target_data_len;
struct nfc_target nfc_tgt;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s - modulation=%d", __func__,
- dev->poll_mod_curr);
+ dev->poll_mod_curr);
- if (resp->tg != 1)
+ if (tg != 1)
return -EPROTO;
memset(&nfc_tgt, 0, sizeof(struct nfc_target));
- target_data_len = resp_len - sizeof(struct pn533_poll_response);
-
switch (dev->poll_mod_curr) {
case PN533_POLL_MOD_106KBPS_A:
- rc = pn533_target_found_type_a(&nfc_tgt, resp->target_data,
- target_data_len);
+ rc = pn533_target_found_type_a(&nfc_tgt, tgdata, tgdata_len);
break;
case PN533_POLL_MOD_212KBPS_FELICA:
case PN533_POLL_MOD_424KBPS_FELICA:
- rc = pn533_target_found_felica(&nfc_tgt, resp->target_data,
- target_data_len);
+ rc = pn533_target_found_felica(&nfc_tgt, tgdata, tgdata_len);
break;
case PN533_POLL_MOD_106KBPS_JEWEL:
- rc = pn533_target_found_jewel(&nfc_tgt, resp->target_data,
- target_data_len);
+ rc = pn533_target_found_jewel(&nfc_tgt, tgdata, tgdata_len);
break;
case PN533_POLL_MOD_847KBPS_B:
- rc = pn533_target_found_type_b(&nfc_tgt, resp->target_data,
- target_data_len);
+ rc = pn533_target_found_type_b(&nfc_tgt, tgdata, tgdata_len);
break;
default:
- nfc_dev_err(&dev->interface->dev, "Unknown current poll"
- " modulation");
+ nfc_dev_err(&dev->interface->dev,
+ "Unknown current poll modulation");
return -EPROTO;
}
@@ -1112,13 +1267,14 @@ static int pn533_target_found(struct pn533 *dev,
return rc;
if (!(nfc_tgt.supported_protocols & dev->poll_protocols)) {
- nfc_dev_dbg(&dev->interface->dev, "The target found does not"
- " have the desired protocol");
+ nfc_dev_dbg(&dev->interface->dev,
+ "The Tg found doesn't have the desired protocol");
return -EAGAIN;
}
- nfc_dev_dbg(&dev->interface->dev, "Target found - supported protocols: "
- "0x%x", nfc_tgt.supported_protocols);
+ nfc_dev_dbg(&dev->interface->dev,
+ "Target found - supported protocols: 0x%x",
+ nfc_tgt.supported_protocols);
dev->tgt_available_prots = nfc_tgt.supported_protocols;
@@ -1140,7 +1296,7 @@ static void pn533_poll_reset_mod_list(struct pn533 *dev)
static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index)
{
dev->poll_mod_active[dev->poll_mod_count] =
- (struct pn533_poll_modulations *) &poll_mod[mod_index];
+ (struct pn533_poll_modulations *)&poll_mod[mod_index];
dev->poll_mod_count++;
}
@@ -1149,13 +1305,13 @@ static void pn533_poll_create_mod_list(struct pn533 *dev,
{
pn533_poll_reset_mod_list(dev);
- if (im_protocols & NFC_PROTO_MIFARE_MASK
- || im_protocols & NFC_PROTO_ISO14443_MASK
- || im_protocols & NFC_PROTO_NFC_DEP_MASK)
+ if ((im_protocols & NFC_PROTO_MIFARE_MASK) ||
+ (im_protocols & NFC_PROTO_ISO14443_MASK) ||
+ (im_protocols & NFC_PROTO_NFC_DEP_MASK))
pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A);
- if (im_protocols & NFC_PROTO_FELICA_MASK
- || im_protocols & NFC_PROTO_NFC_DEP_MASK) {
+ if (im_protocols & NFC_PROTO_FELICA_MASK ||
+ im_protocols & NFC_PROTO_NFC_DEP_MASK) {
pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA);
pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA);
}
@@ -1170,16 +1326,20 @@ static void pn533_poll_create_mod_list(struct pn533 *dev,
pn533_poll_add_mod(dev, PN533_LISTEN_MOD);
}
-static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_len)
+static int pn533_start_poll_complete(struct pn533 *dev, struct sk_buff *resp)
{
- struct pn533_poll_response *resp;
- int rc;
+ u8 nbtg, tg, *tgdata;
+ int rc, tgdata_len;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- resp = (struct pn533_poll_response *) params;
- if (resp->nbtg) {
- rc = pn533_target_found(dev, resp, params_len);
+ nbtg = resp->data[0];
+ tg = resp->data[1];
+ tgdata = &resp->data[2];
+ tgdata_len = resp->len - 2; /* nbtg + tg */
+
+ if (nbtg) {
+ rc = pn533_target_found(dev, tg, tgdata, tgdata_len);
/* We must stop the poll after a valid target found */
if (rc == 0) {
@@ -1191,158 +1351,134 @@ static int pn533_start_poll_complete(struct pn533 *dev, u8 *params, int params_l
return -EAGAIN;
}
-static int pn533_init_target_frame(struct pn533_frame *frame,
- u8 *gb, size_t gb_len)
+static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev)
{
- struct pn533_cmd_init_target *cmd;
- size_t cmd_len;
+ struct sk_buff *skb;
+ u8 *felica, *nfcid3, *gb;
+
+ u8 *gbytes = dev->gb;
+ size_t gbytes_len = dev->gb_len;
+
u8 felica_params[18] = {0x1, 0xfe, /* DEP */
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0xff, 0xff}; /* System code */
+
u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */
0x0, 0x0, 0x0,
0x40}; /* SEL_RES for DEP */
- cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1;
- cmd = kzalloc(cmd_len, GFP_KERNEL);
- if (cmd == NULL)
- return -ENOMEM;
+ unsigned int skb_len = 36 + /* mode (1), mifare (6),
+ felica (18), nfcid3 (10), gb_len (1) */
+ gbytes_len +
+ 1; /* len Tk*/
- pn533_tx_frame_init(frame, PN533_CMD_TG_INIT_AS_TARGET);
+ skb = pn533_alloc_skb(dev, skb_len);
+ if (!skb)
+ return NULL;
/* DEP support only */
- cmd->mode |= PN533_INIT_TARGET_DEP;
+ *skb_put(skb, 1) = PN533_INIT_TARGET_DEP;
+
+ /* MIFARE params */
+ memcpy(skb_put(skb, 6), mifare_params, 6);
/* Felica params */
- memcpy(cmd->felica, felica_params, 18);
- get_random_bytes(cmd->felica + 2, 6);
+ felica = skb_put(skb, 18);
+ memcpy(felica, felica_params, 18);
+ get_random_bytes(felica + 2, 6);
/* NFCID3 */
- memset(cmd->nfcid3, 0, 10);
- memcpy(cmd->nfcid3, cmd->felica, 8);
-
- /* MIFARE params */
- memcpy(cmd->mifare, mifare_params, 6);
+ nfcid3 = skb_put(skb, 10);
+ memset(nfcid3, 0, 10);
+ memcpy(nfcid3, felica, 8);
/* General bytes */
- cmd->gb_len = gb_len;
- memcpy(cmd->gb, gb, gb_len);
+ *skb_put(skb, 1) = gbytes_len;
- /* Len Tk */
- cmd->gb[gb_len] = 0;
-
- memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len);
-
- frame->datalen += cmd_len;
-
- pn533_tx_frame_finish(frame);
+ gb = skb_put(skb, gbytes_len);
+ memcpy(gb, gbytes, gbytes_len);
- kfree(cmd);
+ /* Len Tk */
+ *skb_put(skb, 1) = 0;
- return 0;
+ return skb;
}
-#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
+#define PN533_CMD_DATAEXCH_HEAD_LEN 1
#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg,
- u8 *params, int params_len)
+ struct sk_buff *resp)
{
- struct sk_buff *skb_resp = arg;
- struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
+ u8 status;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- if (params_len < 0) {
- nfc_dev_err(&dev->interface->dev,
- "Error %d when starting as a target",
- params_len);
+ if (IS_ERR(resp))
+ return PTR_ERR(resp);
- return params_len;
- }
+ status = resp->data[0];
+ skb_pull(resp, sizeof(status));
- if (params_len > 0 && params[0] != 0) {
+ if (status != 0) {
nfc_tm_deactivated(dev->nfc_dev);
-
dev->tgt_mode = 0;
-
- kfree_skb(skb_resp);
+ dev_kfree_skb(resp);
return 0;
}
- skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
- skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
- skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
-
- return nfc_tm_data_received(dev->nfc_dev, skb_resp);
+ return nfc_tm_data_received(dev->nfc_dev, resp);
}
static void pn533_wq_tg_get_data(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, tg_work);
- struct pn533_frame *in_frame;
- struct sk_buff *skb_resp;
- size_t skb_resp_len;
- nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+ struct sk_buff *skb;
+ int rc;
- skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
- PN533_CMD_DATAEXCH_DATA_MAXLEN +
- PN533_FRAME_TAIL_SIZE;
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
- if (!skb_resp)
+ skb = pn533_alloc_skb(dev, 0);
+ if (!skb)
return;
- in_frame = (struct pn533_frame *)skb_resp->data;
+ rc = pn533_send_data_async(dev, PN533_CMD_TG_GET_DATA, skb,
+ pn533_tm_get_data_complete, NULL);
- pn533_tx_frame_init(dev->out_frame, PN533_CMD_TG_GET_DATA);
- pn533_tx_frame_finish(dev->out_frame);
-
- pn533_send_cmd_frame_async(dev, dev->out_frame, in_frame,
- skb_resp_len,
- pn533_tm_get_data_complete,
- skb_resp, GFP_KERNEL);
+ if (rc < 0)
+ dev_kfree_skb(skb);
return;
}
#define ATR_REQ_GB_OFFSET 17
-static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_len)
+static int pn533_init_target_complete(struct pn533 *dev, struct sk_buff *resp)
{
- struct pn533_cmd_init_target_response *resp;
- u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
+ u8 mode, *cmd, comm_mode = NFC_COMM_PASSIVE, *gb;
size_t gb_len;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- if (params_len < 0) {
- nfc_dev_err(&dev->interface->dev,
- "Error %d when starting as a target",
- params_len);
-
- return params_len;
- }
-
- if (params_len < ATR_REQ_GB_OFFSET + 1)
+ if (resp->len < ATR_REQ_GB_OFFSET + 1)
return -EINVAL;
- resp = (struct pn533_cmd_init_target_response *) params;
+ mode = resp->data[0];
+ cmd = &resp->data[1];
- nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x param len %d\n",
- resp->mode, params_len);
+ nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x len %d\n",
+ mode, resp->len);
- frame = resp->mode & PN533_INIT_TARGET_RESP_FRAME_MASK;
- if (frame == PN533_INIT_TARGET_RESP_ACTIVE)
+ if ((mode & PN533_INIT_TARGET_RESP_FRAME_MASK) ==
+ PN533_INIT_TARGET_RESP_ACTIVE)
comm_mode = NFC_COMM_ACTIVE;
- /* Again, only DEP */
- if ((resp->mode & PN533_INIT_TARGET_RESP_DEP) == 0)
+ if ((mode & PN533_INIT_TARGET_RESP_DEP) == 0) /* Only DEP supported */
return -EOPNOTSUPP;
- gb = resp->cmd + ATR_REQ_GB_OFFSET;
- gb_len = params_len - (ATR_REQ_GB_OFFSET + 1);
+ gb = cmd + ATR_REQ_GB_OFFSET;
+ gb_len = resp->len - (ATR_REQ_GB_OFFSET + 1);
rc = nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
comm_mode, gb, gb_len);
@@ -1353,7 +1489,6 @@ static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_
}
dev->tgt_mode = 1;
-
queue_work(dev->wq, &dev->tg_work);
return 0;
@@ -1361,7 +1496,7 @@ static int pn533_init_target_complete(struct pn533 *dev, u8 *params, int params_
static void pn533_listen_mode_timer(unsigned long data)
{
- struct pn533 *dev = (struct pn533 *) data;
+ struct pn533 *dev = (struct pn533 *)data;
nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout");
@@ -1376,88 +1511,104 @@ static void pn533_listen_mode_timer(unsigned long data)
}
static int pn533_poll_complete(struct pn533 *dev, void *arg,
- u8 *params, int params_len)
+ struct sk_buff *resp)
{
struct pn533_poll_modulations *cur_mod;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- if (params_len == -ENOENT) {
- if (dev->poll_mod_count != 0)
- return 0;
-
- nfc_dev_err(&dev->interface->dev,
- "Polling operation has been stopped");
-
- goto stop_poll;
- }
+ if (IS_ERR(resp)) {
+ rc = PTR_ERR(resp);
- if (params_len < 0) {
- nfc_dev_err(&dev->interface->dev,
- "Error %d when running poll", params_len);
+ nfc_dev_err(&dev->interface->dev, "%s Poll complete error %d",
+ __func__, rc);
- goto stop_poll;
+ if (rc == -ENOENT) {
+ if (dev->poll_mod_count != 0)
+ return rc;
+ else
+ goto stop_poll;
+ } else if (rc < 0) {
+ nfc_dev_err(&dev->interface->dev,
+ "Error %d when running poll", rc);
+ goto stop_poll;
+ }
}
cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
- if (cur_mod->len == 0) {
+ if (cur_mod->len == 0) { /* Target mode */
del_timer(&dev->listen_timer);
-
- return pn533_init_target_complete(dev, params, params_len);
- } else {
- rc = pn533_start_poll_complete(dev, params, params_len);
- if (!rc)
- return rc;
+ rc = pn533_init_target_complete(dev, resp);
+ goto done;
}
- pn533_poll_next_mod(dev);
+ /* Initiator mode */
+ rc = pn533_start_poll_complete(dev, resp);
+ if (!rc)
+ goto done;
+ pn533_poll_next_mod(dev);
queue_work(dev->wq, &dev->poll_work);
- return 0;
+done:
+ dev_kfree_skb(resp);
+ return rc;
stop_poll:
+ nfc_dev_err(&dev->interface->dev, "Polling operation has been stopped");
+
pn533_poll_reset_mod_list(dev);
dev->poll_protocols = 0;
- return 0;
+ return rc;
}
-static void pn533_build_poll_frame(struct pn533 *dev,
- struct pn533_frame *frame,
- struct pn533_poll_modulations *mod)
+static struct sk_buff *pn533_alloc_poll_in_frame(struct pn533 *dev,
+ struct pn533_poll_modulations *mod)
{
- nfc_dev_dbg(&dev->interface->dev, "mod len %d\n", mod->len);
+ struct sk_buff *skb;
- if (mod->len == 0) {
- /* Listen mode */
- pn533_init_target_frame(frame, dev->gb, dev->gb_len);
- } else {
- /* Polling mode */
- pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
+ skb = pn533_alloc_skb(dev, mod->len);
+ if (!skb)
+ return NULL;
- memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
- frame->datalen += mod->len;
+ memcpy(skb_put(skb, mod->len), &mod->data, mod->len);
- pn533_tx_frame_finish(frame);
- }
+ return skb;
}
static int pn533_send_poll_frame(struct pn533 *dev)
{
- struct pn533_poll_modulations *cur_mod;
+ struct pn533_poll_modulations *mod;
+ struct sk_buff *skb;
int rc;
+ u8 cmd_code;
- cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+ mod = dev->poll_mod_active[dev->poll_mod_curr];
- pn533_build_poll_frame(dev, dev->out_frame, cur_mod);
+ nfc_dev_dbg(&dev->interface->dev, "%s mod len %d\n",
+ __func__, mod->len);
- rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
- dev->in_maxlen, pn533_poll_complete,
- NULL, GFP_KERNEL);
- if (rc)
+ if (mod->len == 0) { /* Listen mode */
+ cmd_code = PN533_CMD_TG_INIT_AS_TARGET;
+ skb = pn533_alloc_poll_tg_frame(dev);
+ } else { /* Polling mode */
+ cmd_code = PN533_CMD_IN_LIST_PASSIVE_TARGET;
+ skb = pn533_alloc_poll_in_frame(dev, mod);
+ }
+
+ if (!skb) {
+ nfc_dev_err(&dev->interface->dev, "Failed to allocate skb.");
+ return -ENOMEM;
+ }
+
+ rc = pn533_send_cmd_async(dev, cmd_code, skb, pn533_poll_complete,
+ NULL);
+ if (rc < 0) {
+ dev_kfree_skb(skb);
nfc_dev_err(&dev->interface->dev, "Polling loop error %d", rc);
+ }
return rc;
}
@@ -1533,8 +1684,8 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
del_timer(&dev->listen_timer);
if (!dev->poll_mod_count) {
- nfc_dev_dbg(&dev->interface->dev, "Polling operation was not"
- " running");
+ nfc_dev_dbg(&dev->interface->dev,
+ "Polling operation was not running");
return;
}
@@ -1549,38 +1700,38 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
static int pn533_activate_target_nfcdep(struct pn533 *dev)
{
- struct pn533_cmd_activate_param param;
- struct pn533_cmd_activate_response *resp;
+ struct pn533_cmd_activate_response *rsp;
u16 gt_len;
int rc;
- nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+ struct sk_buff *skb;
+ struct sk_buff *resp;
- pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_ATR);
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- param.tg = 1;
- param.next = 0;
- memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &param,
- sizeof(struct pn533_cmd_activate_param));
- dev->out_frame->datalen += sizeof(struct pn533_cmd_activate_param);
+ skb = pn533_alloc_skb(dev, sizeof(u8) * 2); /*TG + Next*/
+ if (!skb)
+ return -ENOMEM;
- pn533_tx_frame_finish(dev->out_frame);
+ *skb_put(skb, sizeof(u8)) = 1; /* TG */
+ *skb_put(skb, sizeof(u8)) = 0; /* Next */
- rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
- dev->in_maxlen);
- if (rc)
- return rc;
+ resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_ATR, skb);
+ if (IS_ERR(resp))
+ return PTR_ERR(resp);
- resp = (struct pn533_cmd_activate_response *)
- PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame);
- rc = resp->status & PN533_CMD_RET_MASK;
- if (rc != PN533_CMD_RET_SUCCESS)
+ rsp = (struct pn533_cmd_activate_response *)resp->data;
+ rc = rsp->status & PN533_CMD_RET_MASK;
+ if (rc != PN533_CMD_RET_SUCCESS) {
+ dev_kfree_skb(resp);
return -EIO;
+ }
/* ATR_RES general bytes are located at offset 16 */
- gt_len = PN533_FRAME_CMD_PARAMS_LEN(dev->in_frame) - 16;
- rc = nfc_set_remote_general_bytes(dev->nfc_dev, resp->gt, gt_len);
+ gt_len = resp->len - 16;
+ rc = nfc_set_remote_general_bytes(dev->nfc_dev, rsp->gt, gt_len);
+ dev_kfree_skb(resp);
return rc;
}
@@ -1591,38 +1742,38 @@ static int pn533_activate_target(struct nfc_dev *nfc_dev,
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s - protocol=%u", __func__,
- protocol);
+ protocol);
if (dev->poll_mod_count) {
- nfc_dev_err(&dev->interface->dev, "Cannot activate while"
- " polling");
+ nfc_dev_err(&dev->interface->dev,
+ "Cannot activate while polling");
return -EBUSY;
}
if (dev->tgt_active_prot) {
- nfc_dev_err(&dev->interface->dev, "There is already an active"
- " target");
+ nfc_dev_err(&dev->interface->dev,
+ "There is already an active target");
return -EBUSY;
}
if (!dev->tgt_available_prots) {
- nfc_dev_err(&dev->interface->dev, "There is no available target"
- " to activate");
+ nfc_dev_err(&dev->interface->dev,
+ "There is no available target to activate");
return -EINVAL;
}
if (!(dev->tgt_available_prots & (1 << protocol))) {
- nfc_dev_err(&dev->interface->dev, "The target does not support"
- " the requested protocol %u", protocol);
+ nfc_dev_err(&dev->interface->dev,
+ "Target doesn't support requested proto %u",
+ protocol);
return -EINVAL;
}
if (protocol == NFC_PROTO_NFC_DEP) {
rc = pn533_activate_target_nfcdep(dev);
if (rc) {
- nfc_dev_err(&dev->interface->dev, "Error %d when"
- " activating target with"
- " NFC_DEP protocol", rc);
+ nfc_dev_err(&dev->interface->dev,
+ "Activating target with DEP failed %d", rc);
return rc;
}
}
@@ -1637,8 +1788,10 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev,
struct nfc_target *target)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
- u8 tg;
- u8 status;
+
+ struct sk_buff *skb;
+ struct sk_buff *resp;
+
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
@@ -1649,83 +1802,69 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev,
}
dev->tgt_active_prot = 0;
-
skb_queue_purge(&dev->resp_q);
- pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_RELEASE);
-
- tg = 1;
- memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &tg, sizeof(u8));
- dev->out_frame->datalen += sizeof(u8);
+ skb = pn533_alloc_skb(dev, sizeof(u8));
+ if (!skb)
+ return;
- pn533_tx_frame_finish(dev->out_frame);
+ *skb_put(skb, 1) = 1; /* TG*/
- rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
- dev->in_maxlen);
- if (rc) {
- nfc_dev_err(&dev->interface->dev, "Error when sending release"
- " command to the controller");
+ resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_RELEASE, skb);
+ if (IS_ERR(resp))
return;
- }
- status = PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame)[0];
- rc = status & PN533_CMD_RET_MASK;
+ rc = resp->data[0] & PN533_CMD_RET_MASK;
if (rc != PN533_CMD_RET_SUCCESS)
- nfc_dev_err(&dev->interface->dev, "Error 0x%x when releasing"
- " the target", rc);
+ nfc_dev_err(&dev->interface->dev,
+ "Error 0x%x when releasing the target", rc);
+ dev_kfree_skb(resp);
return;
}
static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
- u8 *params, int params_len)
+ struct sk_buff *resp)
{
- struct pn533_cmd_jump_dep_response *resp;
- struct nfc_target nfc_target;
+ struct pn533_cmd_jump_dep_response *rsp;
u8 target_gt_len;
int rc;
- struct pn533_cmd_jump_dep *cmd = (struct pn533_cmd_jump_dep *)arg;
- u8 active = cmd->active;
+ u8 active = *(u8 *)arg;
kfree(arg);
- if (params_len == -ENOENT) {
- nfc_dev_dbg(&dev->interface->dev, "");
- return 0;
- }
-
- if (params_len < 0) {
- nfc_dev_err(&dev->interface->dev,
- "Error %d when bringing DEP link up",
- params_len);
- return 0;
- }
+ if (IS_ERR(resp))
+ return PTR_ERR(resp);
if (dev->tgt_available_prots &&
!(dev->tgt_available_prots & (1 << NFC_PROTO_NFC_DEP))) {
nfc_dev_err(&dev->interface->dev,
- "The target does not support DEP");
- return -EINVAL;
+ "The target does not support DEP");
+ rc = -EINVAL;
+ goto error;
}
- resp = (struct pn533_cmd_jump_dep_response *) params;
- rc = resp->status & PN533_CMD_RET_MASK;
+ rsp = (struct pn533_cmd_jump_dep_response *)resp->data;
+
+ rc = rsp->status & PN533_CMD_RET_MASK;
if (rc != PN533_CMD_RET_SUCCESS) {
nfc_dev_err(&dev->interface->dev,
- "Bringing DEP link up failed %d", rc);
- return 0;
+ "Bringing DEP link up failed %d", rc);
+ goto error;
}
if (!dev->tgt_available_prots) {
+ struct nfc_target nfc_target;
+
nfc_dev_dbg(&dev->interface->dev, "Creating new target");
nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK;
nfc_target.nfcid1_len = 10;
- memcpy(nfc_target.nfcid1, resp->nfcid3t, nfc_target.nfcid1_len);
+ memcpy(nfc_target.nfcid1, rsp->nfcid3t, nfc_target.nfcid1_len);
rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1);
if (rc)
- return 0;
+ goto error;
dev->tgt_available_prots = 0;
}
@@ -1733,15 +1872,17 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
dev->tgt_active_prot = NFC_PROTO_NFC_DEP;
/* ATR_RES general bytes are located at offset 17 */
- target_gt_len = PN533_FRAME_CMD_PARAMS_LEN(dev->in_frame) - 17;
+ target_gt_len = resp->len - 17;
rc = nfc_set_remote_general_bytes(dev->nfc_dev,
- resp->gt, target_gt_len);
+ rsp->gt, target_gt_len);
if (rc == 0)
rc = nfc_dep_link_is_up(dev->nfc_dev,
- dev->nfc_dev->targets[0].idx,
- !active, NFC_RF_INITIATOR);
+ dev->nfc_dev->targets[0].idx,
+ !active, NFC_RF_INITIATOR);
- return 0;
+error:
+ dev_kfree_skb(resp);
+ return rc;
}
static int pn533_mod_to_baud(struct pn533 *dev)
@@ -1760,25 +1901,26 @@ static int pn533_mod_to_baud(struct pn533 *dev)
#define PASSIVE_DATA_LEN 5
static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
- u8 comm_mode, u8* gb, size_t gb_len)
+ u8 comm_mode, u8 *gb, size_t gb_len)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
- struct pn533_cmd_jump_dep *cmd;
- u8 cmd_len, *data_ptr;
+ struct sk_buff *skb;
+ int rc, baud, skb_len;
+ u8 *next, *arg;
+
u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
- int rc, baud;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
if (dev->poll_mod_count) {
nfc_dev_err(&dev->interface->dev,
- "Cannot bring the DEP link up while polling");
+ "Cannot bring the DEP link up while polling");
return -EBUSY;
}
if (dev->tgt_active_prot) {
nfc_dev_err(&dev->interface->dev,
- "There is already an active target");
+ "There is already an active target");
return -EBUSY;
}
@@ -1789,43 +1931,48 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
return baud;
}
- cmd_len = sizeof(struct pn533_cmd_jump_dep) + gb_len;
+ skb_len = 3 + gb_len; /* ActPass + BR + Next */
if (comm_mode == NFC_COMM_PASSIVE)
- cmd_len += PASSIVE_DATA_LEN;
+ skb_len += PASSIVE_DATA_LEN;
- cmd = kzalloc(cmd_len, GFP_KERNEL);
- if (cmd == NULL)
+ skb = pn533_alloc_skb(dev, skb_len);
+ if (!skb)
return -ENOMEM;
- pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_JUMP_FOR_DEP);
+ *skb_put(skb, 1) = !comm_mode; /* ActPass */
+ *skb_put(skb, 1) = baud; /* Baud rate */
- cmd->active = !comm_mode;
- cmd->next = 0;
- cmd->baud = baud;
- data_ptr = cmd->data;
- if (comm_mode == NFC_COMM_PASSIVE && cmd->baud > 0) {
- memcpy(data_ptr, passive_data, PASSIVE_DATA_LEN);
- cmd->next |= 1;
- data_ptr += PASSIVE_DATA_LEN;
+ next = skb_put(skb, 1); /* Next */
+ *next = 0;
+
+ if (comm_mode == NFC_COMM_PASSIVE && baud > 0) {
+ memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data,
+ PASSIVE_DATA_LEN);
+ *next |= 1;
}
if (gb != NULL && gb_len > 0) {
- cmd->next |= 4; /* We have some Gi */
- memcpy(data_ptr, gb, gb_len);
+ memcpy(skb_put(skb, gb_len), gb, gb_len);
+ *next |= 4; /* We have some Gi */
} else {
- cmd->next = 0;
+ *next = 0;
}
- memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), cmd, cmd_len);
- dev->out_frame->datalen += cmd_len;
+ arg = kmalloc(sizeof(*arg), GFP_KERNEL);
+ if (!arg) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
- pn533_tx_frame_finish(dev->out_frame);
+ *arg = !comm_mode;
- rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
- dev->in_maxlen, pn533_in_dep_link_up_complete,
- cmd, GFP_KERNEL);
- if (rc < 0)
- kfree(cmd);
+ rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb,
+ pn533_in_dep_link_up_complete, arg);
+
+ if (rc < 0) {
+ dev_kfree_skb(skb);
+ kfree(arg);
+ }
return rc;
}
@@ -1834,6 +1981,8 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
pn533_poll_reset_mod_list(dev);
if (dev->tgt_mode || dev->tgt_active_prot) {
@@ -1849,68 +1998,7 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
return 0;
}
-static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,
- bool target)
-{
- int payload_len = skb->len;
- struct pn533_frame *out_frame;
- u8 tg;
-
- nfc_dev_dbg(&dev->interface->dev, "%s - Sending %d bytes", __func__,
- payload_len);
-
- if (payload_len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
- /* TODO: Implement support to multi-part data exchange */
- nfc_dev_err(&dev->interface->dev, "Data length greater than the"
- " max allowed: %d",
- PN533_CMD_DATAEXCH_DATA_MAXLEN);
- return -ENOSYS;
- }
-
- if (target == true) {
- switch (dev->device_type) {
- case PN533_DEVICE_PASORI:
- if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
- skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
- out_frame = (struct pn533_frame *) skb->data;
- pn533_tx_frame_init(out_frame,
- PN533_CMD_IN_COMM_THRU);
-
- break;
- }
-
- default:
- skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
- out_frame = (struct pn533_frame *) skb->data;
- pn533_tx_frame_init(out_frame,
- PN533_CMD_IN_DATA_EXCHANGE);
- tg = 1;
- memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame),
- &tg, sizeof(u8));
- out_frame->datalen += sizeof(u8);
-
- break;
- }
-
- } else {
- skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
- out_frame = (struct pn533_frame *) skb->data;
- pn533_tx_frame_init(out_frame, PN533_CMD_TG_SET_DATA);
- }
-
-
- /* The data is already in the out_frame, just update the datalen */
- out_frame->datalen += payload_len;
-
- pn533_tx_frame_finish(out_frame);
- skb_put(skb, PN533_FRAME_TAIL_SIZE);
-
- return 0;
-}
-
struct pn533_data_exchange_arg {
- struct sk_buff *skb_resp;
- struct sk_buff *skb_out;
data_exchange_cb_t cb;
void *cb_context;
};
@@ -1920,7 +2008,7 @@ static struct sk_buff *pn533_build_response(struct pn533 *dev)
struct sk_buff *skb, *tmp, *t;
unsigned int skb_len = 0, tmp_len = 0;
- nfc_dev_dbg(&dev->interface->dev, "%s\n", __func__);
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
if (skb_queue_empty(&dev->resp_q))
return NULL;
@@ -1954,46 +2042,44 @@ out:
}
static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
- u8 *params, int params_len)
+ struct sk_buff *resp)
{
struct pn533_data_exchange_arg *arg = _arg;
- struct sk_buff *skb = NULL, *skb_resp = arg->skb_resp;
- struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
- int err = 0;
- u8 status;
- u8 cmd_ret;
+ struct sk_buff *skb;
+ int rc = 0;
+ u8 status, ret, mi;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- dev_kfree_skb(arg->skb_out);
-
- if (params_len < 0) { /* error */
- err = params_len;
- goto error;
+ if (IS_ERR(resp)) {
+ rc = PTR_ERR(resp);
+ goto _error;
}
- status = params[0];
+ status = resp->data[0];
+ ret = status & PN533_CMD_RET_MASK;
+ mi = status & PN533_CMD_MI_MASK;
+
+ skb_pull(resp, sizeof(status));
- cmd_ret = status & PN533_CMD_RET_MASK;
- if (cmd_ret != PN533_CMD_RET_SUCCESS) {
- nfc_dev_err(&dev->interface->dev, "PN533 reported error %d when"
- " exchanging data", cmd_ret);
- err = -EIO;
+ if (ret != PN533_CMD_RET_SUCCESS) {
+ nfc_dev_err(&dev->interface->dev,
+ "PN533 reported error %d when exchanging data",
+ ret);
+ rc = -EIO;
goto error;
}
- skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
- skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
- skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
- skb_queue_tail(&dev->resp_q, skb_resp);
+ skb_queue_tail(&dev->resp_q, resp);
- if (status & PN533_CMD_MI_MASK) {
+ if (mi) {
+ dev->cmd_complete_mi_arg = arg;
queue_work(dev->wq, &dev->mi_work);
return -EINPROGRESS;
}
skb = pn533_build_response(dev);
- if (skb == NULL)
+ if (!skb)
goto error;
arg->cb(arg->cb_context, skb, 0);
@@ -2001,11 +2087,12 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
return 0;
error:
+ dev_kfree_skb(resp);
+_error:
skb_queue_purge(&dev->resp_q);
- dev_kfree_skb(skb_resp);
- arg->cb(arg->cb_context, NULL, err);
+ arg->cb(arg->cb_context, NULL, rc);
kfree(arg);
- return 0;
+ return rc;
}
static int pn533_transceive(struct nfc_dev *nfc_dev,
@@ -2013,87 +2100,82 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
data_exchange_cb_t cb, void *cb_context)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
- struct pn533_frame *out_frame, *in_frame;
- struct pn533_data_exchange_arg *arg;
- struct sk_buff *skb_resp;
- int skb_resp_len;
+ struct pn533_data_exchange_arg *arg = NULL;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- if (!dev->tgt_active_prot) {
- nfc_dev_err(&dev->interface->dev, "Cannot exchange data if"
- " there is no active target");
- rc = -EINVAL;
+ if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
+ /* TODO: Implement support to multi-part data exchange */
+ nfc_dev_err(&dev->interface->dev,
+ "Data length greater than the max allowed: %d",
+ PN533_CMD_DATAEXCH_DATA_MAXLEN);
+ rc = -ENOSYS;
goto error;
}
- rc = pn533_build_tx_frame(dev, skb, true);
- if (rc)
- goto error;
-
- skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
- PN533_CMD_DATAEXCH_DATA_MAXLEN +
- PN533_FRAME_TAIL_SIZE;
-
- skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
- if (!skb_resp) {
- rc = -ENOMEM;
+ if (!dev->tgt_active_prot) {
+ nfc_dev_err(&dev->interface->dev,
+ "Can't exchange data if there is no active target");
+ rc = -EINVAL;
goto error;
}
- in_frame = (struct pn533_frame *) skb_resp->data;
- out_frame = (struct pn533_frame *) skb->data;
-
- arg = kmalloc(sizeof(struct pn533_data_exchange_arg), GFP_KERNEL);
+ arg = kmalloc(sizeof(*arg), GFP_KERNEL);
if (!arg) {
rc = -ENOMEM;
- goto free_skb_resp;
+ goto error;
}
- arg->skb_resp = skb_resp;
- arg->skb_out = skb;
arg->cb = cb;
arg->cb_context = cb_context;
- rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, skb_resp_len,
- pn533_data_exchange_complete, arg,
- GFP_KERNEL);
- if (rc) {
- nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
- " perform data_exchange", rc);
- goto free_arg;
+ switch (dev->device_type) {
+ case PN533_DEVICE_PASORI:
+ if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
+ rc = pn533_send_data_async(dev, PN533_CMD_IN_COMM_THRU,
+ skb,
+ pn533_data_exchange_complete,
+ arg);
+
+ break;
+ }
+ default:
+ *skb_push(skb, sizeof(u8)) = 1; /*TG*/
+
+ rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE,
+ skb, pn533_data_exchange_complete,
+ arg);
+
+ break;
}
+ if (rc < 0) /* rc from send_async */
+ goto error;
+
return 0;
-free_arg:
- kfree(arg);
-free_skb_resp:
- kfree_skb(skb_resp);
error:
- kfree_skb(skb);
+ kfree(arg);
+ dev_kfree_skb(skb);
return rc;
}
static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
- u8 *params, int params_len)
+ struct sk_buff *resp)
{
- struct sk_buff *skb_out = arg;
+ u8 status;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- dev_kfree_skb(skb_out);
+ if (IS_ERR(resp))
+ return PTR_ERR(resp);
- if (params_len < 0) {
- nfc_dev_err(&dev->interface->dev,
- "Error %d when sending data",
- params_len);
+ status = resp->data[0];
- return params_len;
- }
+ dev_kfree_skb(resp);
- if (params_len > 0 && params[0] != 0) {
+ if (status != 0) {
nfc_tm_deactivated(dev->nfc_dev);
dev->tgt_mode = 0;
@@ -2109,30 +2191,21 @@ static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
- struct pn533_frame *out_frame;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- rc = pn533_build_tx_frame(dev, skb, false);
- if (rc)
- goto error;
-
- out_frame = (struct pn533_frame *) skb->data;
-
- rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame,
- dev->in_maxlen, pn533_tm_send_complete,
- skb, GFP_KERNEL);
- if (rc) {
+ if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
nfc_dev_err(&dev->interface->dev,
- "Error %d when trying to send data", rc);
- goto error;
+ "Data length greater than the max allowed: %d",
+ PN533_CMD_DATAEXCH_DATA_MAXLEN);
+ return -ENOSYS;
}
- return 0;
-
-error:
- kfree_skb(skb);
+ rc = pn533_send_data_async(dev, PN533_CMD_TG_SET_DATA, skb,
+ pn533_tm_send_complete, NULL);
+ if (rc < 0)
+ dev_kfree_skb(skb);
return rc;
}
@@ -2140,107 +2213,123 @@ error:
static void pn533_wq_mi_recv(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, mi_work);
- struct sk_buff *skb_cmd;
- struct pn533_data_exchange_arg *arg = dev->cmd_complete_arg;
- struct pn533_frame *out_frame, *in_frame;
- struct sk_buff *skb_resp;
- int skb_resp_len;
+
+ struct sk_buff *skb;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- /* This is a zero payload size skb */
- skb_cmd = alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN + PN533_FRAME_TAIL_SIZE,
- GFP_KERNEL);
- if (skb_cmd == NULL)
- goto error_cmd;
-
- skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN);
+ skb = pn533_alloc_skb(dev, PN533_CMD_DATAEXCH_HEAD_LEN);
+ if (!skb)
+ goto error;
- rc = pn533_build_tx_frame(dev, skb_cmd, true);
- if (rc)
- goto error_frame;
+ switch (dev->device_type) {
+ case PN533_DEVICE_PASORI:
+ if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
+ rc = pn533_send_cmd_direct_async(dev,
+ PN533_CMD_IN_COMM_THRU,
+ skb,
+ pn533_data_exchange_complete,
+ dev->cmd_complete_mi_arg);
- skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
- PN533_CMD_DATAEXCH_DATA_MAXLEN +
- PN533_FRAME_TAIL_SIZE;
- skb_resp = alloc_skb(skb_resp_len, GFP_KERNEL);
- if (!skb_resp) {
- rc = -ENOMEM;
- goto error_frame;
- }
+ break;
+ }
+ default:
+ *skb_put(skb, sizeof(u8)) = 1; /*TG*/
- in_frame = (struct pn533_frame *) skb_resp->data;
- out_frame = (struct pn533_frame *) skb_cmd->data;
+ rc = pn533_send_cmd_direct_async(dev,
+ PN533_CMD_IN_DATA_EXCHANGE,
+ skb,
+ pn533_data_exchange_complete,
+ dev->cmd_complete_mi_arg);
- arg->skb_resp = skb_resp;
- arg->skb_out = skb_cmd;
+ break;
+ }
- rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
- skb_resp_len,
- pn533_data_exchange_complete,
- dev->cmd_complete_arg, GFP_KERNEL);
- if (!rc)
+ if (rc == 0) /* success */
return;
- nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
- " perform data_exchange", rc);
-
- kfree_skb(skb_resp);
+ nfc_dev_err(&dev->interface->dev,
+ "Error %d when trying to perform data_exchange", rc);
-error_frame:
- kfree_skb(skb_cmd);
+ dev_kfree_skb(skb);
+ kfree(dev->cmd_complete_arg);
-error_cmd:
+error:
pn533_send_ack(dev, GFP_KERNEL);
-
- kfree(arg);
-
queue_work(dev->wq, &dev->cmd_work);
}
static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
u8 cfgdata_len)
{
- int rc;
- u8 *params;
+ struct sk_buff *skb;
+ struct sk_buff *resp;
+
+ int skb_len;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- pn533_tx_frame_init(dev->out_frame, PN533_CMD_RF_CONFIGURATION);
+ skb_len = sizeof(cfgitem) + cfgdata_len; /* cfgitem + cfgdata */
- params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame);
- params[0] = cfgitem;
- memcpy(&params[1], cfgdata, cfgdata_len);
- dev->out_frame->datalen += (1 + cfgdata_len);
+ skb = pn533_alloc_skb(dev, skb_len);
+ if (!skb)
+ return -ENOMEM;
- pn533_tx_frame_finish(dev->out_frame);
+ *skb_put(skb, sizeof(cfgitem)) = cfgitem;
+ memcpy(skb_put(skb, cfgdata_len), cfgdata, cfgdata_len);
- rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
- dev->in_maxlen);
+ resp = pn533_send_cmd_sync(dev, PN533_CMD_RF_CONFIGURATION, skb);
+ if (IS_ERR(resp))
+ return PTR_ERR(resp);
- return rc;
+ dev_kfree_skb(resp);
+ return 0;
+}
+
+static int pn533_get_firmware_version(struct pn533 *dev,
+ struct pn533_fw_version *fv)
+{
+ struct sk_buff *skb;
+ struct sk_buff *resp;
+
+ skb = pn533_alloc_skb(dev, 0);
+ if (!skb)
+ return -ENOMEM;
+
+ resp = pn533_send_cmd_sync(dev, PN533_CMD_GET_FIRMWARE_VERSION, skb);
+ if (IS_ERR(resp))
+ return PTR_ERR(resp);
+
+ fv->ic = resp->data[0];
+ fv->ver = resp->data[1];
+ fv->rev = resp->data[2];
+ fv->support = resp->data[3];
+
+ dev_kfree_skb(resp);
+ return 0;
}
static int pn533_fw_reset(struct pn533 *dev)
{
- int rc;
- u8 *params;
+ struct sk_buff *skb;
+ struct sk_buff *resp;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- pn533_tx_frame_init(dev->out_frame, 0x18);
+ skb = pn533_alloc_skb(dev, sizeof(u8));
+ if (!skb)
+ return -ENOMEM;
- params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame);
- params[0] = 0x1;
- dev->out_frame->datalen += 1;
+ *skb_put(skb, sizeof(u8)) = 0x1;
- pn533_tx_frame_finish(dev->out_frame);
+ resp = pn533_send_cmd_sync(dev, 0x18, skb);
+ if (IS_ERR(resp))
+ return PTR_ERR(resp);
- rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
- dev->in_maxlen);
+ dev_kfree_skb(resp);
- return rc;
+ return 0;
}
static struct nfc_ops pn533_nfc_ops = {
@@ -2337,7 +2426,7 @@ static int pn533_setup(struct pn533 *dev)
static int pn533_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
- struct pn533_fw_version *fw_ver;
+ struct pn533_fw_version fw_ver;
struct pn533 *dev;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
@@ -2359,41 +2448,32 @@ static int pn533_probe(struct usb_interface *interface,
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
- if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
- dev->in_maxlen = le16_to_cpu(endpoint->wMaxPacketSize);
+ if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint))
in_endpoint = endpoint->bEndpointAddress;
- }
- if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint)) {
- dev->out_maxlen =
- le16_to_cpu(endpoint->wMaxPacketSize);
+ if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint))
out_endpoint = endpoint->bEndpointAddress;
- }
}
if (!in_endpoint || !out_endpoint) {
- nfc_dev_err(&interface->dev, "Could not find bulk-in or"
- " bulk-out endpoint");
+ nfc_dev_err(&interface->dev,
+ "Could not find bulk-in or bulk-out endpoint");
rc = -ENODEV;
goto error;
}
- dev->in_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
dev->in_urb = usb_alloc_urb(0, GFP_KERNEL);
- dev->out_frame = kmalloc(PN533_NORMAL_FRAME_MAX_LEN, GFP_KERNEL);
dev->out_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->in_frame || !dev->out_frame ||
- !dev->in_urb || !dev->out_urb)
+ if (!dev->in_urb || !dev->out_urb)
goto error;
usb_fill_bulk_urb(dev->in_urb, dev->udev,
- usb_rcvbulkpipe(dev->udev, in_endpoint),
- NULL, 0, NULL, dev);
+ usb_rcvbulkpipe(dev->udev, in_endpoint),
+ NULL, 0, NULL, dev);
usb_fill_bulk_urb(dev->out_urb, dev->udev,
- usb_sndbulkpipe(dev->udev, out_endpoint),
- NULL, 0,
- pn533_send_complete, dev);
+ usb_sndbulkpipe(dev->udev, out_endpoint),
+ NULL, 0, pn533_send_complete, dev);
INIT_WORK(&dev->cmd_work, pn533_wq_cmd);
INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete);
@@ -2414,18 +2494,7 @@ static int pn533_probe(struct usb_interface *interface,
usb_set_intfdata(interface, dev);
- pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION);
- pn533_tx_frame_finish(dev->out_frame);
-
- rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
- dev->in_maxlen);
- if (rc)
- goto destroy_wq;
-
- fw_ver = (struct pn533_fw_version *)
- PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame);
- nfc_dev_info(&dev->interface->dev, "NXP PN533 firmware ver %d.%d now"
- " attached", fw_ver->ver, fw_ver->rev);
+ dev->ops = &pn533_std_frame_ops;
dev->device_type = id->driver_info;
switch (dev->device_type) {
@@ -2444,9 +2513,21 @@ static int pn533_probe(struct usb_interface *interface,
goto destroy_wq;
}
+ memset(&fw_ver, 0, sizeof(fw_ver));
+ rc = pn533_get_firmware_version(dev, &fw_ver);
+ if (rc < 0)
+ goto destroy_wq;
+
+ nfc_dev_info(&dev->interface->dev,
+ "NXP PN533 firmware ver %d.%d now attached",
+ fw_ver.ver, fw_ver.rev);
+
+
dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols,
+ NFC_SE_NONE,
+ dev->ops->tx_header_len +
PN533_CMD_DATAEXCH_HEAD_LEN,
- PN533_FRAME_TAIL_SIZE);
+ dev->ops->tx_tail_len);
if (!dev->nfc_dev)
goto destroy_wq;
@@ -2472,9 +2553,7 @@ free_nfc_dev:
destroy_wq:
destroy_workqueue(dev->wq);
error:
- kfree(dev->in_frame);
usb_free_urb(dev->in_urb);
- kfree(dev->out_frame);
usb_free_urb(dev->out_urb);
kfree(dev);
return rc;
@@ -2505,9 +2584,7 @@ static void pn533_disconnect(struct usb_interface *interface)
kfree(cmd);
}
- kfree(dev->in_frame);
usb_free_urb(dev->in_urb);
- kfree(dev->out_frame);
usb_free_urb(dev->out_urb);
kfree(dev);
diff --git a/drivers/nfc/pn544/Kconfig b/drivers/nfc/pn544/Kconfig
new file mode 100644
index 000000000000..c277790ac71c
--- /dev/null
+++ b/drivers/nfc/pn544/Kconfig
@@ -0,0 +1,23 @@
+config NFC_PN544
+ tristate "NXP PN544 NFC driver"
+ depends on NFC_HCI
+ select CRC_CCITT
+ default n
+ ---help---
+ NXP PN544 core driver.
+ This is a driver based on the HCI NFC kernel layers and
+ will thus not work with NXP libnfc library.
+
+ To compile this driver as a module, choose m here. The module will
+ be called pn544.
+ Say N if unsure.
+
+config NFC_PN544_I2C
+ tristate "NFC PN544 i2c support"
+ depends on NFC_PN544 && I2C && NFC_SHDLC
+ ---help---
+ This module adds support for the NXP pn544 i2c interface.
+ Select this if your platform is using the i2c bus.
+
+ If you choose to build a module, it'll be called pn544_i2c.
+ Say N if unsure. \ No newline at end of file
diff --git a/drivers/nfc/pn544/Makefile b/drivers/nfc/pn544/Makefile
index 725733881eb3..ac076793687d 100644
--- a/drivers/nfc/pn544/Makefile
+++ b/drivers/nfc/pn544/Makefile
@@ -2,6 +2,7 @@
# Makefile for PN544 HCI based NFC driver
#
-obj-$(CONFIG_PN544_HCI_NFC) += pn544_i2c.o
+pn544_i2c-objs = i2c.o
-pn544_i2c-y := pn544.o i2c.o
+obj-$(CONFIG_NFC_PN544) += pn544.o
+obj-$(CONFIG_NFC_PN544_I2C) += pn544_i2c.o
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
index 2a9c8d93d2e8..8cf64c19f022 100644
--- a/drivers/nfc/pn544/i2c.c
+++ b/drivers/nfc/pn544/i2c.c
@@ -376,12 +376,12 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
return -ENODEV;
}
- phy = kzalloc(sizeof(struct pn544_i2c_phy), GFP_KERNEL);
+ phy = devm_kzalloc(&client->dev, sizeof(struct pn544_i2c_phy),
+ GFP_KERNEL);
if (!phy) {
dev_err(&client->dev,
"Cannot allocate memory for pn544 i2c phy.\n");
- r = -ENOMEM;
- goto err_phy_alloc;
+ return -ENOMEM;
}
phy->i2c_dev = client;
@@ -390,20 +390,18 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
pdata = client->dev.platform_data;
if (pdata == NULL) {
dev_err(&client->dev, "No platform data\n");
- r = -EINVAL;
- goto err_pdata;
+ return -EINVAL;
}
if (pdata->request_resources == NULL) {
dev_err(&client->dev, "request_resources() missing\n");
- r = -EINVAL;
- goto err_pdata;
+ return -EINVAL;
}
r = pdata->request_resources(client);
if (r) {
dev_err(&client->dev, "Cannot get platform resources\n");
- goto err_pdata;
+ return r;
}
phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
@@ -435,10 +433,6 @@ err_rti:
if (pdata->free_resources != NULL)
pdata->free_resources();
-err_pdata:
- kfree(phy);
-
-err_phy_alloc:
return r;
}
@@ -458,8 +452,6 @@ static int pn544_hci_i2c_remove(struct i2c_client *client)
if (pdata->free_resources)
pdata->free_resources();
- kfree(phy);
-
return 0;
}
@@ -472,29 +464,7 @@ static struct i2c_driver pn544_hci_i2c_driver = {
.remove = pn544_hci_i2c_remove,
};
-static int __init pn544_hci_i2c_init(void)
-{
- int r;
-
- pr_debug(DRIVER_DESC ": %s\n", __func__);
-
- r = i2c_add_driver(&pn544_hci_i2c_driver);
- if (r) {
- pr_err(PN544_HCI_I2C_DRIVER_NAME
- ": driver registration failed\n");
- return r;
- }
-
- return 0;
-}
-
-static void __exit pn544_hci_i2c_exit(void)
-{
- i2c_del_driver(&pn544_hci_i2c_driver);
-}
-
-module_init(pn544_hci_i2c_init);
-module_exit(pn544_hci_i2c_exit);
+module_i2c_driver(pn544_hci_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c
index cc666de3b8e5..9c5f16e7baef 100644
--- a/drivers/nfc/pn544/pn544.c
+++ b/drivers/nfc/pn544/pn544.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <linux/nfc.h>
#include <net/nfc/hci.h>
@@ -675,11 +676,17 @@ static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev,
static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
{
+ int r;
+
/* Set default false for multiple information chaining */
*skb_push(skb, 1) = 0;
- return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
- PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
+ r = nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
+ PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
+
+ kfree_skb(skb);
+
+ return r;
}
static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
@@ -714,35 +721,40 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
return 0;
}
-static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate,
- u8 event, struct sk_buff *skb)
+/*
+ * Returns:
+ * <= 0: driver handled the event, skb consumed
+ * 1: driver does not handle the event, please do standard processing
+ */
+static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event,
+ struct sk_buff *skb)
{
struct sk_buff *rgb_skb = NULL;
- int r = 0;
+ int r;
pr_debug("hci event %d", event);
switch (event) {
case PN544_HCI_EVT_ACTIVATED:
- if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
- nfc_hci_target_discovered(hdev, gate);
- else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
+ if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) {
+ r = nfc_hci_target_discovered(hdev, gate);
+ } else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ,
- &rgb_skb);
-
+ &rgb_skb);
if (r < 0)
goto exit;
- nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
- NFC_COMM_PASSIVE, rgb_skb->data,
- rgb_skb->len);
+ r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
+ NFC_COMM_PASSIVE, rgb_skb->data,
+ rgb_skb->len);
kfree_skb(rgb_skb);
+ } else {
+ r = -EINVAL;
}
-
break;
case PN544_HCI_EVT_DEACTIVATED:
- nfc_hci_send_event(hdev, gate,
- NFC_HCI_EVT_END_OPERATION, NULL, 0);
+ r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION,
+ NULL, 0);
break;
case PN544_HCI_EVT_RCV_DATA:
if (skb->len < 2) {
@@ -757,15 +769,15 @@ static void pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate,
}
skb_pull(skb, 2);
- nfc_tm_data_received(hdev->ndev, skb);
-
- return;
+ return nfc_tm_data_received(hdev->ndev, skb);
default:
- break;
+ return 1;
}
exit:
kfree_skb(skb);
+
+ return r;
}
static struct nfc_hci_ops pn544_hci_ops = {
@@ -789,7 +801,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
struct nfc_hci_dev **hdev)
{
struct pn544_hci_info *info;
- u32 protocols;
+ u32 protocols, se;
struct nfc_hci_init_data init_data;
int r;
@@ -822,8 +834,10 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
NFC_PROTO_ISO14443_B_MASK |
NFC_PROTO_NFC_DEP_MASK;
- info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data,
- protocols, llc_name,
+ se = NFC_SE_UICC | NFC_SE_EMBEDDED;
+
+ info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0,
+ protocols, se, llc_name,
phy_headroom + PN544_CMDS_HEADROOM,
phy_tailroom, phy_payload);
if (!info->hdev) {
@@ -851,6 +865,7 @@ err_alloc_hdev:
err_info_alloc:
return r;
}
+EXPORT_SYMBOL(pn544_hci_probe);
void pn544_hci_remove(struct nfc_hci_dev *hdev)
{
@@ -860,3 +875,7 @@ void pn544_hci_remove(struct nfc_hci_dev *hdev)
nfc_hci_free_device(hdev);
kfree(info);
}
+EXPORT_SYMBOL(pn544_hci_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/ntb/Kconfig b/drivers/ntb/Kconfig
new file mode 100644
index 000000000000..37ee6495acc1
--- /dev/null
+++ b/drivers/ntb/Kconfig
@@ -0,0 +1,13 @@
+config NTB
+ tristate "Intel Non-Transparent Bridge support"
+ depends on PCI
+ depends on X86_64
+ help
+ The PCI-E Non-transparent bridge hardware is a point-to-point PCI-E bus
+ connecting 2 systems. When configured, writes to the device's PCI
+ mapped memory will be mirrored to a buffer on the remote system. The
+ ntb Linux driver uses this point-to-point communication as a method to
+ transfer data from one system to the other.
+
+ If unsure, say N.
+
diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile
new file mode 100644
index 000000000000..15cb59fd354e
--- /dev/null
+++ b/drivers/ntb/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_NTB) += ntb.o
+
+ntb-objs := ntb_hw.o ntb_transport.o
diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c
new file mode 100644
index 000000000000..f802e7c92356
--- /dev/null
+++ b/drivers/ntb/ntb_hw.c
@@ -0,0 +1,1141 @@
+/*
+ * 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) 2012 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.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 Intel Corporation. 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 copy
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of 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.
+ *
+ * Intel PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Jon Mason <jon.mason@intel.com>
+ */
+#include <linux/debugfs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include "ntb_hw.h"
+#include "ntb_regs.h"
+
+#define NTB_NAME "Intel(R) PCI-E Non-Transparent Bridge Driver"
+#define NTB_VER "0.25"
+
+MODULE_DESCRIPTION(NTB_NAME);
+MODULE_VERSION(NTB_VER);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+
+enum {
+ NTB_CONN_CLASSIC = 0,
+ NTB_CONN_B2B,
+ NTB_CONN_RP,
+};
+
+enum {
+ NTB_DEV_USD = 0,
+ NTB_DEV_DSD,
+};
+
+enum {
+ SNB_HW = 0,
+ BWD_HW,
+};
+
+/* Translate memory window 0,1 to BAR 2,4 */
+#define MW_TO_BAR(mw) (mw * 2 + 2)
+
+static DEFINE_PCI_DEVICE_TABLE(ntb_pci_tbl) = {
+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)},
+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)},
+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_CLASSIC_JSF)},
+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_RP_JSF)},
+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_RP_SNB)},
+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)},
+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_CLASSIC_SNB)},
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, ntb_pci_tbl);
+
+/**
+ * ntb_register_event_callback() - register event callback
+ * @ndev: pointer to ntb_device instance
+ * @func: callback function to register
+ *
+ * This function registers a callback for any HW driver events such as link
+ * up/down, power management notices and etc.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_register_event_callback(struct ntb_device *ndev,
+ void (*func)(void *handle, enum ntb_hw_event event))
+{
+ if (ndev->event_cb)
+ return -EINVAL;
+
+ ndev->event_cb = func;
+
+ return 0;
+}
+
+/**
+ * ntb_unregister_event_callback() - unregisters the event callback
+ * @ndev: pointer to ntb_device instance
+ *
+ * This function unregisters the existing callback from transport
+ */
+void ntb_unregister_event_callback(struct ntb_device *ndev)
+{
+ ndev->event_cb = NULL;
+}
+
+/**
+ * ntb_register_db_callback() - register a callback for doorbell interrupt
+ * @ndev: pointer to ntb_device instance
+ * @idx: doorbell index to register callback, zero based
+ * @func: callback function to register
+ *
+ * This function registers a callback function for the doorbell interrupt
+ * on the primary side. The function will unmask the doorbell as well to
+ * allow interrupt.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
+ void *data, void (*func)(void *data, int db_num))
+{
+ unsigned long mask;
+
+ if (idx >= ndev->max_cbs || ndev->db_cb[idx].callback) {
+ dev_warn(&ndev->pdev->dev, "Invalid Index.\n");
+ return -EINVAL;
+ }
+
+ ndev->db_cb[idx].callback = func;
+ ndev->db_cb[idx].data = data;
+
+ /* unmask interrupt */
+ mask = readw(ndev->reg_ofs.pdb_mask);
+ clear_bit(idx * ndev->bits_per_vector, &mask);
+ writew(mask, ndev->reg_ofs.pdb_mask);
+
+ return 0;
+}
+
+/**
+ * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt
+ * @ndev: pointer to ntb_device instance
+ * @idx: doorbell index to register callback, zero based
+ *
+ * This function unregisters a callback function for the doorbell interrupt
+ * on the primary side. The function will also mask the said doorbell.
+ */
+void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx)
+{
+ unsigned long mask;
+
+ if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback)
+ return;
+
+ mask = readw(ndev->reg_ofs.pdb_mask);
+ set_bit(idx * ndev->bits_per_vector, &mask);
+ writew(mask, ndev->reg_ofs.pdb_mask);
+
+ ndev->db_cb[idx].callback = NULL;
+}
+
+/**
+ * ntb_find_transport() - find the transport pointer
+ * @transport: pointer to pci device
+ *
+ * Given the pci device pointer, return the transport pointer passed in when
+ * the transport attached when it was inited.
+ *
+ * RETURNS: pointer to transport.
+ */
+void *ntb_find_transport(struct pci_dev *pdev)
+{
+ struct ntb_device *ndev = pci_get_drvdata(pdev);
+ return ndev->ntb_transport;
+}
+
+/**
+ * ntb_register_transport() - Register NTB transport with NTB HW driver
+ * @transport: transport identifier
+ *
+ * This function allows a transport to reserve the hardware driver for
+ * NTB usage.
+ *
+ * RETURNS: pointer to ntb_device, NULL on error.
+ */
+struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void *transport)
+{
+ struct ntb_device *ndev = pci_get_drvdata(pdev);
+
+ if (ndev->ntb_transport)
+ return NULL;
+
+ ndev->ntb_transport = transport;
+ return ndev;
+}
+
+/**
+ * ntb_unregister_transport() - Unregister the transport with the NTB HW driver
+ * @ndev - ntb_device of the transport to be freed
+ *
+ * This function unregisters the transport from the HW driver and performs any
+ * necessary cleanups.
+ */
+void ntb_unregister_transport(struct ntb_device *ndev)
+{
+ int i;
+
+ if (!ndev->ntb_transport)
+ return;
+
+ for (i = 0; i < ndev->max_cbs; i++)
+ ntb_unregister_db_callback(ndev, i);
+
+ ntb_unregister_event_callback(ndev);
+ ndev->ntb_transport = NULL;
+}
+
+/**
+ * ntb_write_local_spad() - write to the secondary scratchpad register
+ * @ndev: pointer to ntb_device instance
+ * @idx: index to the scratchpad register, 0 based
+ * @val: the data value to put into the register
+ *
+ * This function allows writing of a 32bit value to the indexed scratchpad
+ * register. This writes over the data mirrored to the local scratchpad register
+ * by the remote system.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val)
+{
+ if (idx >= ndev->limits.max_spads)
+ return -EINVAL;
+
+ dev_dbg(&ndev->pdev->dev, "Writing %x to local scratch pad index %d\n",
+ val, idx);
+ writel(val, ndev->reg_ofs.spad_read + idx * 4);
+
+ return 0;
+}
+
+/**
+ * ntb_read_local_spad() - read from the primary scratchpad register
+ * @ndev: pointer to ntb_device instance
+ * @idx: index to scratchpad register, 0 based
+ * @val: pointer to 32bit integer for storing the register value
+ *
+ * This function allows reading of the 32bit scratchpad register on
+ * the primary (internal) side. This allows the local system to read data
+ * written and mirrored to the scratchpad register by the remote system.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
+{
+ if (idx >= ndev->limits.max_spads)
+ return -EINVAL;
+
+ *val = readl(ndev->reg_ofs.spad_write + idx * 4);
+ dev_dbg(&ndev->pdev->dev,
+ "Reading %x from local scratch pad index %d\n", *val, idx);
+
+ return 0;
+}
+
+/**
+ * ntb_write_remote_spad() - write to the secondary scratchpad register
+ * @ndev: pointer to ntb_device instance
+ * @idx: index to the scratchpad register, 0 based
+ * @val: the data value to put into the register
+ *
+ * This function allows writing of a 32bit value to the indexed scratchpad
+ * register. The register resides on the secondary (external) side. This allows
+ * the local system to write data to be mirrored to the remote systems
+ * scratchpad register.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val)
+{
+ if (idx >= ndev->limits.max_spads)
+ return -EINVAL;
+
+ dev_dbg(&ndev->pdev->dev, "Writing %x to remote scratch pad index %d\n",
+ val, idx);
+ writel(val, ndev->reg_ofs.spad_write + idx * 4);
+
+ return 0;
+}
+
+/**
+ * ntb_read_remote_spad() - read from the primary scratchpad register
+ * @ndev: pointer to ntb_device instance
+ * @idx: index to scratchpad register, 0 based
+ * @val: pointer to 32bit integer for storing the register value
+ *
+ * This function allows reading of the 32bit scratchpad register on
+ * the primary (internal) side. This alloows the local system to read the data
+ * it wrote to be mirrored on the remote system.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
+{
+ if (idx >= ndev->limits.max_spads)
+ return -EINVAL;
+
+ *val = readl(ndev->reg_ofs.spad_read + idx * 4);
+ dev_dbg(&ndev->pdev->dev,
+ "Reading %x from remote scratch pad index %d\n", *val, idx);
+
+ return 0;
+}
+
+/**
+ * ntb_get_mw_vbase() - get virtual addr for the NTB memory window
+ * @ndev: pointer to ntb_device instance
+ * @mw: memory window number
+ *
+ * This function provides the base virtual address of the memory window
+ * specified.
+ *
+ * RETURNS: pointer to virtual address, or NULL on error.
+ */
+void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw)
+{
+ if (mw > NTB_NUM_MW)
+ return NULL;
+
+ return ndev->mw[mw].vbase;
+}
+
+/**
+ * ntb_get_mw_size() - return size of NTB memory window
+ * @ndev: pointer to ntb_device instance
+ * @mw: memory window number
+ *
+ * This function provides the physical size of the memory window specified
+ *
+ * RETURNS: the size of the memory window or zero on error
+ */
+resource_size_t ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw)
+{
+ if (mw > NTB_NUM_MW)
+ return 0;
+
+ return ndev->mw[mw].bar_sz;
+}
+
+/**
+ * ntb_set_mw_addr - set the memory window address
+ * @ndev: pointer to ntb_device instance
+ * @mw: memory window number
+ * @addr: base address for data
+ *
+ * This function sets the base physical address of the memory window. This
+ * memory address is where data from the remote system will be transfered into
+ * or out of depending on how the transport is configured.
+ */
+void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr)
+{
+ if (mw > NTB_NUM_MW)
+ return;
+
+ dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr,
+ MW_TO_BAR(mw));
+
+ ndev->mw[mw].phys_addr = addr;
+
+ switch (MW_TO_BAR(mw)) {
+ case NTB_BAR_23:
+ writeq(addr, ndev->reg_ofs.sbar2_xlat);
+ break;
+ case NTB_BAR_45:
+ writeq(addr, ndev->reg_ofs.sbar4_xlat);
+ break;
+ }
+}
+
+/**
+ * ntb_ring_sdb() - Set the doorbell on the secondary/external side
+ * @ndev: pointer to ntb_device instance
+ * @db: doorbell to ring
+ *
+ * This function allows triggering of a doorbell on the secondary/external
+ * side that will initiate an interrupt on the remote host
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+void ntb_ring_sdb(struct ntb_device *ndev, unsigned int db)
+{
+ dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db);
+
+ if (ndev->hw_type == BWD_HW)
+ writeq((u64) 1 << db, ndev->reg_ofs.sdb);
+ else
+ writew(((1 << ndev->bits_per_vector) - 1) <<
+ (db * ndev->bits_per_vector), ndev->reg_ofs.sdb);
+}
+
+static void ntb_link_event(struct ntb_device *ndev, int link_state)
+{
+ unsigned int event;
+
+ if (ndev->link_status == link_state)
+ return;
+
+ if (link_state == NTB_LINK_UP) {
+ u16 status;
+
+ dev_info(&ndev->pdev->dev, "Link Up\n");
+ ndev->link_status = NTB_LINK_UP;
+ event = NTB_EVENT_HW_LINK_UP;
+
+ if (ndev->hw_type == BWD_HW)
+ status = readw(ndev->reg_ofs.lnk_stat);
+ else {
+ int rc = pci_read_config_word(ndev->pdev,
+ SNB_LINK_STATUS_OFFSET,
+ &status);
+ if (rc)
+ return;
+ }
+ dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n",
+ (status & NTB_LINK_WIDTH_MASK) >> 4,
+ (status & NTB_LINK_SPEED_MASK));
+ } else {
+ dev_info(&ndev->pdev->dev, "Link Down\n");
+ ndev->link_status = NTB_LINK_DOWN;
+ event = NTB_EVENT_HW_LINK_DOWN;
+ }
+
+ /* notify the upper layer if we have an event change */
+ if (ndev->event_cb)
+ ndev->event_cb(ndev->ntb_transport, event);
+}
+
+static int ntb_link_status(struct ntb_device *ndev)
+{
+ int link_state;
+
+ if (ndev->hw_type == BWD_HW) {
+ u32 ntb_cntl;
+
+ ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
+ if (ntb_cntl & BWD_CNTL_LINK_DOWN)
+ link_state = NTB_LINK_DOWN;
+ else
+ link_state = NTB_LINK_UP;
+ } else {
+ u16 status;
+ int rc;
+
+ rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET,
+ &status);
+ if (rc)
+ return rc;
+
+ if (status & NTB_LINK_STATUS_ACTIVE)
+ link_state = NTB_LINK_UP;
+ else
+ link_state = NTB_LINK_DOWN;
+ }
+
+ ntb_link_event(ndev, link_state);
+
+ return 0;
+}
+
+/* BWD doesn't have link status interrupt, poll on that platform */
+static void bwd_link_poll(struct work_struct *work)
+{
+ struct ntb_device *ndev = container_of(work, struct ntb_device,
+ hb_timer.work);
+ unsigned long ts = jiffies;
+
+ /* If we haven't gotten an interrupt in a while, check the BWD link
+ * status bit
+ */
+ if (ts > ndev->last_ts + NTB_HB_TIMEOUT) {
+ int rc = ntb_link_status(ndev);
+ if (rc)
+ dev_err(&ndev->pdev->dev,
+ "Error determining link status\n");
+ }
+
+ schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
+}
+
+static int ntb_xeon_setup(struct ntb_device *ndev)
+{
+ int rc;
+ u8 val;
+
+ ndev->hw_type = SNB_HW;
+
+ rc = pci_read_config_byte(ndev->pdev, NTB_PPD_OFFSET, &val);
+ if (rc)
+ return rc;
+
+ switch (val & SNB_PPD_CONN_TYPE) {
+ case NTB_CONN_B2B:
+ ndev->conn_type = NTB_CONN_B2B;
+ break;
+ case NTB_CONN_CLASSIC:
+ case NTB_CONN_RP:
+ default:
+ dev_err(&ndev->pdev->dev, "Only B2B supported at this time\n");
+ return -EINVAL;
+ }
+
+ if (val & SNB_PPD_DEV_TYPE)
+ ndev->dev_type = NTB_DEV_DSD;
+ else
+ ndev->dev_type = NTB_DEV_USD;
+
+ ndev->reg_ofs.pdb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
+ ndev->reg_ofs.pdb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET;
+ ndev->reg_ofs.sbar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET;
+ ndev->reg_ofs.sbar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET;
+ ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET;
+ ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_LINK_STATUS_OFFSET;
+ ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET;
+ ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET;
+
+ if (ndev->conn_type == NTB_CONN_B2B) {
+ ndev->reg_ofs.sdb = ndev->reg_base + SNB_B2B_DOORBELL_OFFSET;
+ ndev->reg_ofs.spad_write = ndev->reg_base + SNB_B2B_SPAD_OFFSET;
+ ndev->limits.max_spads = SNB_MAX_SPADS;
+ } else {
+ ndev->reg_ofs.sdb = ndev->reg_base + SNB_SDOORBELL_OFFSET;
+ ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET;
+ ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS;
+ }
+
+ ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
+ ndev->limits.msix_cnt = SNB_MSIX_CNT;
+ ndev->bits_per_vector = SNB_DB_BITS_PER_VEC;
+
+ return 0;
+}
+
+static int ntb_bwd_setup(struct ntb_device *ndev)
+{
+ int rc;
+ u32 val;
+
+ ndev->hw_type = BWD_HW;
+
+ rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &val);
+ if (rc)
+ return rc;
+
+ switch ((val & BWD_PPD_CONN_TYPE) >> 8) {
+ case NTB_CONN_B2B:
+ ndev->conn_type = NTB_CONN_B2B;
+ break;
+ case NTB_CONN_RP:
+ default:
+ dev_err(&ndev->pdev->dev, "Only B2B supported at this time\n");
+ return -EINVAL;
+ }
+
+ if (val & BWD_PPD_DEV_TYPE)
+ ndev->dev_type = NTB_DEV_DSD;
+ else
+ ndev->dev_type = NTB_DEV_USD;
+
+ /* Initiate PCI-E link training */
+ rc = pci_write_config_dword(ndev->pdev, NTB_PPD_OFFSET,
+ val | BWD_PPD_INIT_LINK);
+ if (rc)
+ return rc;
+
+ ndev->reg_ofs.pdb = ndev->reg_base + BWD_PDOORBELL_OFFSET;
+ ndev->reg_ofs.pdb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET;
+ ndev->reg_ofs.sbar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET;
+ ndev->reg_ofs.sbar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET;
+ ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET;
+ ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET;
+ ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET;
+ ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET;
+
+ if (ndev->conn_type == NTB_CONN_B2B) {
+ ndev->reg_ofs.sdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET;
+ ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET;
+ ndev->limits.max_spads = BWD_MAX_SPADS;
+ } else {
+ ndev->reg_ofs.sdb = ndev->reg_base + BWD_PDOORBELL_OFFSET;
+ ndev->reg_ofs.spad_write = ndev->reg_base + BWD_SPAD_OFFSET;
+ ndev->limits.max_spads = BWD_MAX_COMPAT_SPADS;
+ }
+
+ ndev->limits.max_db_bits = BWD_MAX_DB_BITS;
+ ndev->limits.msix_cnt = BWD_MSIX_CNT;
+ ndev->bits_per_vector = BWD_DB_BITS_PER_VEC;
+
+ /* Since bwd doesn't have a link interrupt, setup a poll timer */
+ INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll);
+ schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
+
+ return 0;
+}
+
+static int ntb_device_setup(struct ntb_device *ndev)
+{
+ int rc;
+
+ switch (ndev->pdev->device) {
+ case PCI_DEVICE_ID_INTEL_NTB_2ND_SNB:
+ case PCI_DEVICE_ID_INTEL_NTB_RP_JSF:
+ case PCI_DEVICE_ID_INTEL_NTB_RP_SNB:
+ case PCI_DEVICE_ID_INTEL_NTB_CLASSIC_JSF:
+ case PCI_DEVICE_ID_INTEL_NTB_CLASSIC_SNB:
+ case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
+ case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
+ rc = ntb_xeon_setup(ndev);
+ break;
+ case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD:
+ rc = ntb_bwd_setup(ndev);
+ break;
+ default:
+ rc = -ENODEV;
+ }
+
+ /* Enable Bus Master and Memory Space on the secondary side */
+ writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, ndev->reg_ofs.spci_cmd);
+
+ return rc;
+}
+
+static void ntb_device_free(struct ntb_device *ndev)
+{
+ if (ndev->hw_type == BWD_HW)
+ cancel_delayed_work_sync(&ndev->hb_timer);
+}
+
+static irqreturn_t bwd_callback_msix_irq(int irq, void *data)
+{
+ struct ntb_db_cb *db_cb = data;
+ struct ntb_device *ndev = db_cb->ndev;
+
+ dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
+ db_cb->db_num);
+
+ if (db_cb->callback)
+ db_cb->callback(db_cb->data, db_cb->db_num);
+
+ /* No need to check for the specific HB irq, any interrupt means
+ * we're connected.
+ */
+ ndev->last_ts = jiffies;
+
+ writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.pdb);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t xeon_callback_msix_irq(int irq, void *data)
+{
+ struct ntb_db_cb *db_cb = data;
+ struct ntb_device *ndev = db_cb->ndev;
+
+ dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
+ db_cb->db_num);
+
+ if (db_cb->callback)
+ db_cb->callback(db_cb->data, db_cb->db_num);
+
+ /* On Sandybridge, there are 16 bits in the interrupt register
+ * but only 4 vectors. So, 5 bits are assigned to the first 3
+ * vectors, with the 4th having a single bit for link
+ * interrupts.
+ */
+ writew(((1 << ndev->bits_per_vector) - 1) <<
+ (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.pdb);
+
+ return IRQ_HANDLED;
+}
+
+/* Since we do not have a HW doorbell in BWD, this is only used in JF/JT */
+static irqreturn_t xeon_event_msix_irq(int irq, void *dev)
+{
+ struct ntb_device *ndev = dev;
+ int rc;
+
+ dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for Events\n", irq);
+
+ rc = ntb_link_status(ndev);
+ if (rc)
+ dev_err(&ndev->pdev->dev, "Error determining link status\n");
+
+ /* bit 15 is always the link bit */
+ writew(1 << ndev->limits.max_db_bits, ndev->reg_ofs.pdb);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ntb_interrupt(int irq, void *dev)
+{
+ struct ntb_device *ndev = dev;
+ unsigned int i = 0;
+
+ if (ndev->hw_type == BWD_HW) {
+ u64 pdb = readq(ndev->reg_ofs.pdb);
+
+ dev_dbg(&ndev->pdev->dev, "irq %d - pdb = %Lx\n", irq, pdb);
+
+ while (pdb) {
+ i = __ffs(pdb);
+ pdb &= pdb - 1;
+ bwd_callback_msix_irq(irq, &ndev->db_cb[i]);
+ }
+ } else {
+ u16 pdb = readw(ndev->reg_ofs.pdb);
+
+ dev_dbg(&ndev->pdev->dev, "irq %d - pdb = %x sdb %x\n", irq,
+ pdb, readw(ndev->reg_ofs.sdb));
+
+ if (pdb & SNB_DB_HW_LINK) {
+ xeon_event_msix_irq(irq, dev);
+ pdb &= ~SNB_DB_HW_LINK;
+ }
+
+ while (pdb) {
+ i = __ffs(pdb);
+ pdb &= pdb - 1;
+ xeon_callback_msix_irq(irq, &ndev->db_cb[i]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ntb_setup_msix(struct ntb_device *ndev)
+{
+ struct pci_dev *pdev = ndev->pdev;
+ struct msix_entry *msix;
+ int msix_entries;
+ int rc, i, pos;
+ u16 val;
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+ if (!pos) {
+ rc = -EIO;
+ goto err;
+ }
+
+ rc = pci_read_config_word(pdev, pos + PCI_MSIX_FLAGS, &val);
+ if (rc)
+ goto err;
+
+ msix_entries = msix_table_size(val);
+ if (msix_entries > ndev->limits.msix_cnt) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries,
+ GFP_KERNEL);
+ if (!ndev->msix_entries) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < msix_entries; i++)
+ ndev->msix_entries[i].entry = i;
+
+ rc = pci_enable_msix(pdev, ndev->msix_entries, msix_entries);
+ if (rc < 0)
+ goto err1;
+ if (rc > 0) {
+ /* On SNB, the link interrupt is always tied to 4th vector. If
+ * we can't get all 4, then we can't use MSI-X.
+ */
+ if (ndev->hw_type != BWD_HW) {
+ rc = -EIO;
+ goto err1;
+ }
+
+ dev_warn(&pdev->dev,
+ "Only %d MSI-X vectors. Limiting the number of queues to that number.\n",
+ rc);
+ msix_entries = rc;
+ }
+
+ for (i = 0; i < msix_entries; i++) {
+ msix = &ndev->msix_entries[i];
+ WARN_ON(!msix->vector);
+
+ /* Use the last MSI-X vector for Link status */
+ if (ndev->hw_type == BWD_HW) {
+ rc = request_irq(msix->vector, bwd_callback_msix_irq, 0,
+ "ntb-callback-msix", &ndev->db_cb[i]);
+ if (rc)
+ goto err2;
+ } else {
+ if (i == msix_entries - 1) {
+ rc = request_irq(msix->vector,
+ xeon_event_msix_irq, 0,
+ "ntb-event-msix", ndev);
+ if (rc)
+ goto err2;
+ } else {
+ rc = request_irq(msix->vector,
+ xeon_callback_msix_irq, 0,
+ "ntb-callback-msix",
+ &ndev->db_cb[i]);
+ if (rc)
+ goto err2;
+ }
+ }
+ }
+
+ ndev->num_msix = msix_entries;
+ if (ndev->hw_type == BWD_HW)
+ ndev->max_cbs = msix_entries;
+ else
+ ndev->max_cbs = msix_entries - 1;
+
+ return 0;
+
+err2:
+ while (--i >= 0) {
+ msix = &ndev->msix_entries[i];
+ if (ndev->hw_type != BWD_HW && i == ndev->num_msix - 1)
+ free_irq(msix->vector, ndev);
+ else
+ free_irq(msix->vector, &ndev->db_cb[i]);
+ }
+ pci_disable_msix(pdev);
+err1:
+ kfree(ndev->msix_entries);
+ dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n");
+err:
+ ndev->num_msix = 0;
+ return rc;
+}
+
+static int ntb_setup_msi(struct ntb_device *ndev)
+{
+ struct pci_dev *pdev = ndev->pdev;
+ int rc;
+
+ rc = pci_enable_msi(pdev);
+ if (rc)
+ return rc;
+
+ rc = request_irq(pdev->irq, ntb_interrupt, 0, "ntb-msi", ndev);
+ if (rc) {
+ pci_disable_msi(pdev);
+ dev_err(&pdev->dev, "Error allocating MSI interrupt\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int ntb_setup_intx(struct ntb_device *ndev)
+{
+ struct pci_dev *pdev = ndev->pdev;
+ int rc;
+
+ pci_msi_off(pdev);
+
+ /* Verify intx is enabled */
+ pci_intx(pdev, 1);
+
+ rc = request_irq(pdev->irq, ntb_interrupt, IRQF_SHARED, "ntb-intx",
+ ndev);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static int ntb_setup_interrupts(struct ntb_device *ndev)
+{
+ int rc;
+
+ /* On BWD, disable all interrupts. On SNB, disable all but Link
+ * Interrupt. The rest will be unmasked as callbacks are registered.
+ */
+ if (ndev->hw_type == BWD_HW)
+ writeq(~0, ndev->reg_ofs.pdb_mask);
+ else
+ writew(~(1 << ndev->limits.max_db_bits),
+ ndev->reg_ofs.pdb_mask);
+
+ rc = ntb_setup_msix(ndev);
+ if (!rc)
+ goto done;
+
+ ndev->bits_per_vector = 1;
+ ndev->max_cbs = ndev->limits.max_db_bits;
+
+ rc = ntb_setup_msi(ndev);
+ if (!rc)
+ goto done;
+
+ rc = ntb_setup_intx(ndev);
+ if (rc) {
+ dev_err(&ndev->pdev->dev, "no usable interrupts\n");
+ return rc;
+ }
+
+done:
+ return 0;
+}
+
+static void ntb_free_interrupts(struct ntb_device *ndev)
+{
+ struct pci_dev *pdev = ndev->pdev;
+
+ /* mask interrupts */
+ if (ndev->hw_type == BWD_HW)
+ writeq(~0, ndev->reg_ofs.pdb_mask);
+ else
+ writew(~0, ndev->reg_ofs.pdb_mask);
+
+ if (ndev->num_msix) {
+ struct msix_entry *msix;
+ u32 i;
+
+ for (i = 0; i < ndev->num_msix; i++) {
+ msix = &ndev->msix_entries[i];
+ if (ndev->hw_type != BWD_HW && i == ndev->num_msix - 1)
+ free_irq(msix->vector, ndev);
+ else
+ free_irq(msix->vector, &ndev->db_cb[i]);
+ }
+ pci_disable_msix(pdev);
+ } else {
+ free_irq(pdev->irq, ndev);
+
+ if (pci_dev_msi_enabled(pdev))
+ pci_disable_msi(pdev);
+ }
+}
+
+static int ntb_create_callbacks(struct ntb_device *ndev)
+{
+ int i;
+
+ /* Checken-egg issue. We won't know how many callbacks are necessary
+ * until we see how many MSI-X vectors we get, but these pointers need
+ * to be passed into the MSI-X register fucntion. So, we allocate the
+ * max, knowing that they might not all be used, to work around this.
+ */
+ ndev->db_cb = kcalloc(ndev->limits.max_db_bits,
+ sizeof(struct ntb_db_cb),
+ GFP_KERNEL);
+ if (!ndev->db_cb)
+ return -ENOMEM;
+
+ for (i = 0; i < ndev->limits.max_db_bits; i++) {
+ ndev->db_cb[i].db_num = i;
+ ndev->db_cb[i].ndev = ndev;
+ }
+
+ return 0;
+}
+
+static void ntb_free_callbacks(struct ntb_device *ndev)
+{
+ int i;
+
+ for (i = 0; i < ndev->limits.max_db_bits; i++)
+ ntb_unregister_db_callback(ndev, i);
+
+ kfree(ndev->db_cb);
+}
+
+static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct ntb_device *ndev;
+ int rc, i;
+
+ ndev = kzalloc(sizeof(struct ntb_device), GFP_KERNEL);
+ if (!ndev)
+ return -ENOMEM;
+
+ ndev->pdev = pdev;
+ ndev->link_status = NTB_LINK_DOWN;
+ pci_set_drvdata(pdev, ndev);
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ goto err;
+
+ pci_set_master(ndev->pdev);
+
+ rc = pci_request_selected_regions(pdev, NTB_BAR_MASK, KBUILD_MODNAME);
+ if (rc)
+ goto err1;
+
+ ndev->reg_base = pci_ioremap_bar(pdev, NTB_BAR_MMIO);
+ if (!ndev->reg_base) {
+ dev_warn(&pdev->dev, "Cannot remap BAR 0\n");
+ rc = -EIO;
+ goto err2;
+ }
+
+ for (i = 0; i < NTB_NUM_MW; i++) {
+ ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i));
+ ndev->mw[i].vbase =
+ ioremap_wc(pci_resource_start(pdev, MW_TO_BAR(i)),
+ ndev->mw[i].bar_sz);
+ dev_info(&pdev->dev, "MW %d size %d\n", i,
+ (u32) pci_resource_len(pdev, MW_TO_BAR(i)));
+ if (!ndev->mw[i].vbase) {
+ dev_warn(&pdev->dev, "Cannot remap BAR %d\n",
+ MW_TO_BAR(i));
+ rc = -EIO;
+ goto err3;
+ }
+ }
+
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (rc) {
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc)
+ goto err3;
+
+ dev_warn(&pdev->dev, "Cannot DMA highmem\n");
+ }
+
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc)
+ goto err3;
+
+ dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n");
+ }
+
+ rc = ntb_device_setup(ndev);
+ if (rc)
+ goto err3;
+
+ rc = ntb_create_callbacks(ndev);
+ if (rc)
+ goto err4;
+
+ rc = ntb_setup_interrupts(ndev);
+ if (rc)
+ goto err5;
+
+ /* The scratchpad registers keep the values between rmmod/insmod,
+ * blast them now
+ */
+ for (i = 0; i < ndev->limits.max_spads; i++) {
+ ntb_write_local_spad(ndev, i, 0);
+ ntb_write_remote_spad(ndev, i, 0);
+ }
+
+ rc = ntb_transport_init(pdev);
+ if (rc)
+ goto err6;
+
+ /* Let's bring the NTB link up */
+ writel(NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP,
+ ndev->reg_ofs.lnk_cntl);
+
+ return 0;
+
+err6:
+ ntb_free_interrupts(ndev);
+err5:
+ ntb_free_callbacks(ndev);
+err4:
+ ntb_device_free(ndev);
+err3:
+ for (i--; i >= 0; i--)
+ iounmap(ndev->mw[i].vbase);
+ iounmap(ndev->reg_base);
+err2:
+ pci_release_selected_regions(pdev, NTB_BAR_MASK);
+err1:
+ pci_disable_device(pdev);
+err:
+ kfree(ndev);
+
+ dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME);
+ return rc;
+}
+
+static void ntb_pci_remove(struct pci_dev *pdev)
+{
+ struct ntb_device *ndev = pci_get_drvdata(pdev);
+ int i;
+ u32 ntb_cntl;
+
+ /* Bring NTB link down */
+ ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
+ ntb_cntl |= NTB_LINK_DISABLE;
+ writel(ntb_cntl, ndev->reg_ofs.lnk_cntl);
+
+ ntb_transport_free(ndev->ntb_transport);
+
+ ntb_free_interrupts(ndev);
+ ntb_free_callbacks(ndev);
+ ntb_device_free(ndev);
+
+ for (i = 0; i < NTB_NUM_MW; i++)
+ iounmap(ndev->mw[i].vbase);
+
+ iounmap(ndev->reg_base);
+ pci_release_selected_regions(pdev, NTB_BAR_MASK);
+ pci_disable_device(pdev);
+ kfree(ndev);
+}
+
+static struct pci_driver ntb_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ntb_pci_tbl,
+ .probe = ntb_pci_probe,
+ .remove = ntb_pci_remove,
+};
+module_pci_driver(ntb_pci_driver);
diff --git a/drivers/ntb/ntb_hw.h b/drivers/ntb/ntb_hw.h
new file mode 100644
index 000000000000..3a3038ca83e6
--- /dev/null
+++ b/drivers/ntb/ntb_hw.h
@@ -0,0 +1,181 @@
+/*
+ * 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) 2012 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.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 Intel Corporation. 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 copy
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of 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.
+ *
+ * Intel PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Jon Mason <jon.mason@intel.com>
+ */
+
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725
+#define PCI_DEVICE_ID_INTEL_NTB_CLASSIC_JSF 0x3726
+#define PCI_DEVICE_ID_INTEL_NTB_RP_JSF 0x3727
+#define PCI_DEVICE_ID_INTEL_NTB_RP_SNB 0x3C08
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D
+#define PCI_DEVICE_ID_INTEL_NTB_CLASSIC_SNB 0x3C0E
+#define PCI_DEVICE_ID_INTEL_NTB_2ND_SNB 0x3C0F
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E
+
+#define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1)
+
+#define NTB_BAR_MMIO 0
+#define NTB_BAR_23 2
+#define NTB_BAR_45 4
+#define NTB_BAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
+ (1 << NTB_BAR_45))
+
+#define NTB_LINK_DOWN 0
+#define NTB_LINK_UP 1
+
+#define NTB_HB_TIMEOUT msecs_to_jiffies(1000)
+
+#define NTB_NUM_MW 2
+
+enum ntb_hw_event {
+ NTB_EVENT_SW_EVENT0 = 0,
+ NTB_EVENT_SW_EVENT1,
+ NTB_EVENT_SW_EVENT2,
+ NTB_EVENT_HW_ERROR,
+ NTB_EVENT_HW_LINK_UP,
+ NTB_EVENT_HW_LINK_DOWN,
+};
+
+struct ntb_mw {
+ dma_addr_t phys_addr;
+ void __iomem *vbase;
+ resource_size_t bar_sz;
+};
+
+struct ntb_db_cb {
+ void (*callback) (void *data, int db_num);
+ unsigned int db_num;
+ void *data;
+ struct ntb_device *ndev;
+};
+
+struct ntb_device {
+ struct pci_dev *pdev;
+ struct msix_entry *msix_entries;
+ void __iomem *reg_base;
+ struct ntb_mw mw[NTB_NUM_MW];
+ struct {
+ unsigned int max_spads;
+ unsigned int max_db_bits;
+ unsigned int msix_cnt;
+ } limits;
+ struct {
+ void __iomem *pdb;
+ void __iomem *pdb_mask;
+ void __iomem *sdb;
+ void __iomem *sbar2_xlat;
+ void __iomem *sbar4_xlat;
+ void __iomem *spad_write;
+ void __iomem *spad_read;
+ void __iomem *lnk_cntl;
+ void __iomem *lnk_stat;
+ void __iomem *spci_cmd;
+ } reg_ofs;
+ struct ntb_transport *ntb_transport;
+ void (*event_cb)(void *handle, enum ntb_hw_event event);
+
+ struct ntb_db_cb *db_cb;
+ unsigned char hw_type;
+ unsigned char conn_type;
+ unsigned char dev_type;
+ unsigned char num_msix;
+ unsigned char bits_per_vector;
+ unsigned char max_cbs;
+ unsigned char link_status;
+ struct delayed_work hb_timer;
+ unsigned long last_ts;
+};
+
+/**
+ * ntb_hw_link_status() - return the hardware link status
+ * @ndev: pointer to ntb_device instance
+ *
+ * Returns true if the hardware is connected to the remote system
+ *
+ * RETURNS: true or false based on the hardware link state
+ */
+static inline bool ntb_hw_link_status(struct ntb_device *ndev)
+{
+ return ndev->link_status == NTB_LINK_UP;
+}
+
+/**
+ * ntb_query_pdev() - return the pci_dev pointer
+ * @ndev: pointer to ntb_device instance
+ *
+ * Given the ntb pointer return the pci_dev pointerfor the NTB hardware device
+ *
+ * RETURNS: a pointer to the ntb pci_dev
+ */
+static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev)
+{
+ return ndev->pdev;
+}
+
+struct ntb_device *ntb_register_transport(struct pci_dev *pdev,
+ void *transport);
+void ntb_unregister_transport(struct ntb_device *ndev);
+void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr);
+int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
+ void *data, void (*db_cb_func) (void *data,
+ int db_num));
+void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx);
+int ntb_register_event_callback(struct ntb_device *ndev,
+ void (*event_cb_func) (void *handle,
+ enum ntb_hw_event event));
+void ntb_unregister_event_callback(struct ntb_device *ndev);
+int ntb_get_max_spads(struct ntb_device *ndev);
+int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
+int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
+int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
+int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
+void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw);
+resource_size_t ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw);
+void ntb_ring_sdb(struct ntb_device *ndev, unsigned int idx);
+void *ntb_find_transport(struct pci_dev *pdev);
+
+int ntb_transport_init(struct pci_dev *pdev);
+void ntb_transport_free(void *transport);
diff --git a/drivers/ntb/ntb_regs.h b/drivers/ntb/ntb_regs.h
new file mode 100644
index 000000000000..5bfa8c06c059
--- /dev/null
+++ b/drivers/ntb/ntb_regs.h
@@ -0,0 +1,139 @@
+/*
+ * 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) 2012 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.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 Intel Corporation. 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 copy
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of 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.
+ *
+ * Intel PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Jon Mason <jon.mason@intel.com>
+ */
+
+#define NTB_LINK_ENABLE 0x0000
+#define NTB_LINK_DISABLE 0x0002
+#define NTB_LINK_STATUS_ACTIVE 0x2000
+#define NTB_LINK_SPEED_MASK 0x000f
+#define NTB_LINK_WIDTH_MASK 0x03f0
+
+#define SNB_MSIX_CNT 4
+#define SNB_MAX_SPADS 16
+#define SNB_MAX_COMPAT_SPADS 8
+/* Reserve the uppermost bit for link interrupt */
+#define SNB_MAX_DB_BITS 15
+#define SNB_DB_BITS_PER_VEC 5
+
+#define SNB_DB_HW_LINK 0x8000
+
+#define SNB_PCICMD_OFFSET 0x0504
+#define SNB_DEVCTRL_OFFSET 0x0598
+#define SNB_LINK_STATUS_OFFSET 0x01A2
+
+#define SNB_PBAR2LMT_OFFSET 0x0000
+#define SNB_PBAR4LMT_OFFSET 0x0008
+#define SNB_PBAR2XLAT_OFFSET 0x0010
+#define SNB_PBAR4XLAT_OFFSET 0x0018
+#define SNB_SBAR2LMT_OFFSET 0x0020
+#define SNB_SBAR4LMT_OFFSET 0x0028
+#define SNB_SBAR2XLAT_OFFSET 0x0030
+#define SNB_SBAR4XLAT_OFFSET 0x0038
+#define SNB_SBAR0BASE_OFFSET 0x0040
+#define SNB_SBAR2BASE_OFFSET 0x0048
+#define SNB_SBAR4BASE_OFFSET 0x0050
+#define SNB_NTBCNTL_OFFSET 0x0058
+#define SNB_SBDF_OFFSET 0x005C
+#define SNB_PDOORBELL_OFFSET 0x0060
+#define SNB_PDBMSK_OFFSET 0x0062
+#define SNB_SDOORBELL_OFFSET 0x0064
+#define SNB_SDBMSK_OFFSET 0x0066
+#define SNB_USMEMMISS 0x0070
+#define SNB_SPAD_OFFSET 0x0080
+#define SNB_SPADSEMA4_OFFSET 0x00c0
+#define SNB_WCCNTRL_OFFSET 0x00e0
+#define SNB_B2B_SPAD_OFFSET 0x0100
+#define SNB_B2B_DOORBELL_OFFSET 0x0140
+#define SNB_B2B_XLAT_OFFSET 0x0144
+
+#define BWD_MSIX_CNT 34
+#define BWD_MAX_SPADS 16
+#define BWD_MAX_COMPAT_SPADS 16
+#define BWD_MAX_DB_BITS 34
+#define BWD_DB_BITS_PER_VEC 1
+
+#define BWD_PCICMD_OFFSET 0xb004
+#define BWD_MBAR23_OFFSET 0xb018
+#define BWD_MBAR45_OFFSET 0xb020
+#define BWD_DEVCTRL_OFFSET 0xb048
+#define BWD_LINK_STATUS_OFFSET 0xb052
+
+#define BWD_SBAR2XLAT_OFFSET 0x0008
+#define BWD_SBAR4XLAT_OFFSET 0x0010
+#define BWD_PDOORBELL_OFFSET 0x0020
+#define BWD_PDBMSK_OFFSET 0x0028
+#define BWD_NTBCNTL_OFFSET 0x0060
+#define BWD_EBDF_OFFSET 0x0064
+#define BWD_SPAD_OFFSET 0x0080
+#define BWD_SPADSEMA_OFFSET 0x00c0
+#define BWD_STKYSPAD_OFFSET 0x00c4
+#define BWD_PBAR2XLAT_OFFSET 0x8008
+#define BWD_PBAR4XLAT_OFFSET 0x8010
+#define BWD_B2B_DOORBELL_OFFSET 0x8020
+#define BWD_B2B_SPAD_OFFSET 0x8080
+#define BWD_B2B_SPADSEMA_OFFSET 0x80c0
+#define BWD_B2B_STKYSPAD_OFFSET 0x80c4
+
+#define NTB_CNTL_BAR23_SNOOP (1 << 2)
+#define NTB_CNTL_BAR45_SNOOP (1 << 6)
+#define BWD_CNTL_LINK_DOWN (1 << 16)
+
+#define NTB_PPD_OFFSET 0x00D4
+#define SNB_PPD_CONN_TYPE 0x0003
+#define SNB_PPD_DEV_TYPE 0x0010
+#define BWD_PPD_INIT_LINK 0x0008
+#define BWD_PPD_CONN_TYPE 0x0300
+#define BWD_PPD_DEV_TYPE 0x1000
+
+#define BWD_PBAR2XLAT_USD_ADDR 0x0000004000000000
+#define BWD_PBAR4XLAT_USD_ADDR 0x0000008000000000
+#define BWD_MBAR23_USD_ADDR 0x000000410000000C
+#define BWD_MBAR45_USD_ADDR 0x000000810000000C
+#define BWD_PBAR2XLAT_DSD_ADDR 0x0000004100000000
+#define BWD_PBAR4XLAT_DSD_ADDR 0x0000008100000000
+#define BWD_MBAR23_DSD_ADDR 0x000000400000000C
+#define BWD_MBAR45_DSD_ADDR 0x000000800000000C
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
new file mode 100644
index 000000000000..e0bdfd7f9930
--- /dev/null
+++ b/drivers/ntb/ntb_transport.c
@@ -0,0 +1,1441 @@
+/*
+ * 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) 2012 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.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 Intel Corporation. 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 copy
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of 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.
+ *
+ * Intel PCIe NTB Linux driver
+ *
+ * Contact Information:
+ * Jon Mason <jon.mason@intel.com>
+ */
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/ntb.h>
+#include "ntb_hw.h"
+
+#define NTB_TRANSPORT_VERSION 2
+
+static unsigned int transport_mtu = 0x401E;
+module_param(transport_mtu, uint, 0644);
+MODULE_PARM_DESC(transport_mtu, "Maximum size of NTB transport packets");
+
+static unsigned char max_num_clients = 2;
+module_param(max_num_clients, byte, 0644);
+MODULE_PARM_DESC(max_num_clients, "Maximum number of NTB transport clients");
+
+struct ntb_queue_entry {
+ /* ntb_queue list reference */
+ struct list_head entry;
+ /* pointers to data to be transfered */
+ void *cb_data;
+ void *buf;
+ unsigned int len;
+ unsigned int flags;
+};
+
+struct ntb_rx_info {
+ unsigned int entry;
+};
+
+struct ntb_transport_qp {
+ struct ntb_transport *transport;
+ struct ntb_device *ndev;
+ void *cb_data;
+
+ bool client_ready;
+ bool qp_link;
+ u8 qp_num; /* Only 64 QP's are allowed. 0-63 */
+
+ struct ntb_rx_info __iomem *rx_info;
+ struct ntb_rx_info *remote_rx_info;
+
+ void (*tx_handler) (struct ntb_transport_qp *qp, void *qp_data,
+ void *data, int len);
+ struct list_head tx_free_q;
+ spinlock_t ntb_tx_free_q_lock;
+ void __iomem *tx_mw;
+ unsigned int tx_index;
+ unsigned int tx_max_entry;
+ unsigned int tx_max_frame;
+
+ void (*rx_handler) (struct ntb_transport_qp *qp, void *qp_data,
+ void *data, int len);
+ struct tasklet_struct rx_work;
+ struct list_head rx_pend_q;
+ struct list_head rx_free_q;
+ spinlock_t ntb_rx_pend_q_lock;
+ spinlock_t ntb_rx_free_q_lock;
+ void *rx_buff;
+ unsigned int rx_index;
+ unsigned int rx_max_entry;
+ unsigned int rx_max_frame;
+
+ void (*event_handler) (void *data, int status);
+ struct delayed_work link_work;
+ struct work_struct link_cleanup;
+
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_stats;
+
+ /* Stats */
+ u64 rx_bytes;
+ u64 rx_pkts;
+ u64 rx_ring_empty;
+ u64 rx_err_no_buf;
+ u64 rx_err_oflow;
+ u64 rx_err_ver;
+ u64 tx_bytes;
+ u64 tx_pkts;
+ u64 tx_ring_full;
+};
+
+struct ntb_transport_mw {
+ size_t size;
+ void *virt_addr;
+ dma_addr_t dma_addr;
+};
+
+struct ntb_transport_client_dev {
+ struct list_head entry;
+ struct device dev;
+};
+
+struct ntb_transport {
+ struct list_head entry;
+ struct list_head client_devs;
+
+ struct ntb_device *ndev;
+ struct ntb_transport_mw mw[NTB_NUM_MW];
+ struct ntb_transport_qp *qps;
+ unsigned int max_qps;
+ unsigned long qp_bitmap;
+ bool transport_link;
+ struct delayed_work link_work;
+ struct work_struct link_cleanup;
+ struct dentry *debugfs_dir;
+};
+
+enum {
+ DESC_DONE_FLAG = 1 << 0,
+ LINK_DOWN_FLAG = 1 << 1,
+};
+
+struct ntb_payload_header {
+ unsigned int ver;
+ unsigned int len;
+ unsigned int flags;
+};
+
+enum {
+ VERSION = 0,
+ MW0_SZ,
+ MW1_SZ,
+ NUM_QPS,
+ QP_LINKS,
+ MAX_SPAD,
+};
+
+#define QP_TO_MW(qp) ((qp) % NTB_NUM_MW)
+#define NTB_QP_DEF_NUM_ENTRIES 100
+#define NTB_LINK_DOWN_TIMEOUT 10
+
+static int ntb_match_bus(struct device *dev, struct device_driver *drv)
+{
+ return !strncmp(dev_name(dev), drv->name, strlen(drv->name));
+}
+
+static int ntb_client_probe(struct device *dev)
+{
+ const struct ntb_client *drv = container_of(dev->driver,
+ struct ntb_client, driver);
+ struct pci_dev *pdev = container_of(dev->parent, struct pci_dev, dev);
+ int rc = -EINVAL;
+
+ get_device(dev);
+ if (drv && drv->probe)
+ rc = drv->probe(pdev);
+ if (rc)
+ put_device(dev);
+
+ return rc;
+}
+
+static int ntb_client_remove(struct device *dev)
+{
+ const struct ntb_client *drv = container_of(dev->driver,
+ struct ntb_client, driver);
+ struct pci_dev *pdev = container_of(dev->parent, struct pci_dev, dev);
+
+ if (drv && drv->remove)
+ drv->remove(pdev);
+
+ put_device(dev);
+
+ return 0;
+}
+
+static struct bus_type ntb_bus_type = {
+ .name = "ntb_bus",
+ .match = ntb_match_bus,
+ .probe = ntb_client_probe,
+ .remove = ntb_client_remove,
+};
+
+static LIST_HEAD(ntb_transport_list);
+
+static int ntb_bus_init(struct ntb_transport *nt)
+{
+ if (list_empty(&ntb_transport_list)) {
+ int rc = bus_register(&ntb_bus_type);
+ if (rc)
+ return rc;
+ }
+
+ list_add(&nt->entry, &ntb_transport_list);
+
+ return 0;
+}
+
+static void ntb_bus_remove(struct ntb_transport *nt)
+{
+ struct ntb_transport_client_dev *client_dev, *cd;
+
+ list_for_each_entry_safe(client_dev, cd, &nt->client_devs, entry) {
+ dev_err(client_dev->dev.parent, "%s still attached to bus, removing\n",
+ dev_name(&client_dev->dev));
+ list_del(&client_dev->entry);
+ device_unregister(&client_dev->dev);
+ }
+
+ list_del(&nt->entry);
+
+ if (list_empty(&ntb_transport_list))
+ bus_unregister(&ntb_bus_type);
+}
+
+static void ntb_client_release(struct device *dev)
+{
+ struct ntb_transport_client_dev *client_dev;
+ client_dev = container_of(dev, struct ntb_transport_client_dev, dev);
+
+ kfree(client_dev);
+}
+
+/**
+ * ntb_unregister_client_dev - Unregister NTB client device
+ * @device_name: Name of NTB client device
+ *
+ * Unregister an NTB client device with the NTB transport layer
+ */
+void ntb_unregister_client_dev(char *device_name)
+{
+ struct ntb_transport_client_dev *client, *cd;
+ struct ntb_transport *nt;
+
+ list_for_each_entry(nt, &ntb_transport_list, entry)
+ list_for_each_entry_safe(client, cd, &nt->client_devs, entry)
+ if (!strncmp(dev_name(&client->dev), device_name,
+ strlen(device_name))) {
+ list_del(&client->entry);
+ device_unregister(&client->dev);
+ }
+}
+EXPORT_SYMBOL_GPL(ntb_unregister_client_dev);
+
+/**
+ * ntb_register_client_dev - Register NTB client device
+ * @device_name: Name of NTB client device
+ *
+ * Register an NTB client device with the NTB transport layer
+ */
+int ntb_register_client_dev(char *device_name)
+{
+ struct ntb_transport_client_dev *client_dev;
+ struct ntb_transport *nt;
+ int rc;
+
+ if (list_empty(&ntb_transport_list))
+ return -ENODEV;
+
+ list_for_each_entry(nt, &ntb_transport_list, entry) {
+ struct device *dev;
+
+ client_dev = kzalloc(sizeof(struct ntb_transport_client_dev),
+ GFP_KERNEL);
+ if (!client_dev) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ dev = &client_dev->dev;
+
+ /* setup and register client devices */
+ dev_set_name(dev, "%s", device_name);
+ dev->bus = &ntb_bus_type;
+ dev->release = ntb_client_release;
+ dev->parent = &ntb_query_pdev(nt->ndev)->dev;
+
+ rc = device_register(dev);
+ if (rc) {
+ kfree(client_dev);
+ goto err;
+ }
+
+ list_add_tail(&client_dev->entry, &nt->client_devs);
+ }
+
+ return 0;
+
+err:
+ ntb_unregister_client_dev(device_name);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ntb_register_client_dev);
+
+/**
+ * ntb_register_client - Register NTB client driver
+ * @drv: NTB client driver to be registered
+ *
+ * Register an NTB client driver with the NTB transport layer
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_register_client(struct ntb_client *drv)
+{
+ drv->driver.bus = &ntb_bus_type;
+
+ if (list_empty(&ntb_transport_list))
+ return -ENODEV;
+
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(ntb_register_client);
+
+/**
+ * ntb_unregister_client - Unregister NTB client driver
+ * @drv: NTB client driver to be unregistered
+ *
+ * Unregister an NTB client driver with the NTB transport layer
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+void ntb_unregister_client(struct ntb_client *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(ntb_unregister_client);
+
+static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
+ loff_t *offp)
+{
+ struct ntb_transport_qp *qp;
+ char *buf;
+ ssize_t ret, out_offset, out_count;
+
+ out_count = 600;
+
+ buf = kmalloc(out_count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ qp = filp->private_data;
+ out_offset = 0;
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "NTB QP stats\n");
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "rx_bytes - \t%llu\n", qp->rx_bytes);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "rx_pkts - \t%llu\n", qp->rx_pkts);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "rx_ring_empty - %llu\n", qp->rx_ring_empty);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "rx_err_no_buf - %llu\n", qp->rx_err_no_buf);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "rx_err_oflow - \t%llu\n", qp->rx_err_oflow);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "rx_err_ver - \t%llu\n", qp->rx_err_ver);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "rx_buff - \t%p\n", qp->rx_buff);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "rx_index - \t%u\n", qp->rx_index);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "rx_max_entry - \t%u\n", qp->rx_max_entry);
+
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "tx_bytes - \t%llu\n", qp->tx_bytes);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "tx_pkts - \t%llu\n", qp->tx_pkts);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "tx_ring_full - \t%llu\n", qp->tx_ring_full);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "tx_mw - \t%p\n", qp->tx_mw);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "tx_index - \t%u\n", qp->tx_index);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "tx_max_entry - \t%u\n", qp->tx_max_entry);
+
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "\nQP Link %s\n", (qp->qp_link == NTB_LINK_UP) ?
+ "Up" : "Down");
+ if (out_offset > out_count)
+ out_offset = out_count;
+
+ ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations ntb_qp_debugfs_stats = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = debugfs_read,
+};
+
+static void ntb_list_add(spinlock_t *lock, struct list_head *entry,
+ struct list_head *list)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+ list_add_tail(entry, list);
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static struct ntb_queue_entry *ntb_list_rm(spinlock_t *lock,
+ struct list_head *list)
+{
+ struct ntb_queue_entry *entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+ if (list_empty(list)) {
+ entry = NULL;
+ goto out;
+ }
+ entry = list_first_entry(list, struct ntb_queue_entry, entry);
+ list_del(&entry->entry);
+out:
+ spin_unlock_irqrestore(lock, flags);
+
+ return entry;
+}
+
+static void ntb_transport_setup_qp_mw(struct ntb_transport *nt,
+ unsigned int qp_num)
+{
+ struct ntb_transport_qp *qp = &nt->qps[qp_num];
+ unsigned int rx_size, num_qps_mw;
+ u8 mw_num = QP_TO_MW(qp_num);
+ unsigned int i;
+
+ WARN_ON(nt->mw[mw_num].virt_addr == NULL);
+
+ if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW)
+ num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
+ else
+ num_qps_mw = nt->max_qps / NTB_NUM_MW;
+
+ rx_size = (unsigned int) nt->mw[mw_num].size / num_qps_mw;
+ qp->remote_rx_info = nt->mw[mw_num].virt_addr +
+ (qp_num / NTB_NUM_MW * rx_size);
+ rx_size -= sizeof(struct ntb_rx_info);
+
+ qp->rx_buff = qp->remote_rx_info + sizeof(struct ntb_rx_info);
+ qp->rx_max_frame = min(transport_mtu, rx_size);
+ qp->rx_max_entry = rx_size / qp->rx_max_frame;
+ qp->rx_index = 0;
+
+ qp->remote_rx_info->entry = qp->rx_max_entry;
+
+ /* setup the hdr offsets with 0's */
+ for (i = 0; i < qp->rx_max_entry; i++) {
+ void *offset = qp->rx_buff + qp->rx_max_frame * (i + 1) -
+ sizeof(struct ntb_payload_header);
+ memset(offset, 0, sizeof(struct ntb_payload_header));
+ }
+
+ qp->rx_pkts = 0;
+ qp->tx_pkts = 0;
+}
+
+static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size)
+{
+ struct ntb_transport_mw *mw = &nt->mw[num_mw];
+ struct pci_dev *pdev = ntb_query_pdev(nt->ndev);
+
+ /* Alloc memory for receiving data. Must be 4k aligned */
+ mw->size = ALIGN(size, 4096);
+
+ mw->virt_addr = dma_alloc_coherent(&pdev->dev, mw->size, &mw->dma_addr,
+ GFP_KERNEL);
+ if (!mw->virt_addr) {
+ dev_err(&pdev->dev, "Unable to allocate MW buffer of size %d\n",
+ (int) mw->size);
+ return -ENOMEM;
+ }
+
+ /* Notify HW the memory location of the receive buffer */
+ ntb_set_mw_addr(nt->ndev, num_mw, mw->dma_addr);
+
+ return 0;
+}
+
+static void ntb_qp_link_cleanup(struct work_struct *work)
+{
+ struct ntb_transport_qp *qp = container_of(work,
+ struct ntb_transport_qp,
+ link_cleanup);
+ struct ntb_transport *nt = qp->transport;
+ struct pci_dev *pdev = ntb_query_pdev(nt->ndev);
+
+ if (qp->qp_link == NTB_LINK_DOWN) {
+ cancel_delayed_work_sync(&qp->link_work);
+ return;
+ }
+
+ if (qp->event_handler)
+ qp->event_handler(qp->cb_data, NTB_LINK_DOWN);
+
+ dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num);
+ qp->qp_link = NTB_LINK_DOWN;
+
+ if (nt->transport_link == NTB_LINK_UP)
+ schedule_delayed_work(&qp->link_work,
+ msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
+}
+
+static void ntb_qp_link_down(struct ntb_transport_qp *qp)
+{
+ schedule_work(&qp->link_cleanup);
+}
+
+static void ntb_transport_link_cleanup(struct work_struct *work)
+{
+ struct ntb_transport *nt = container_of(work, struct ntb_transport,
+ link_cleanup);
+ int i;
+
+ if (nt->transport_link == NTB_LINK_DOWN)
+ cancel_delayed_work_sync(&nt->link_work);
+ else
+ nt->transport_link = NTB_LINK_DOWN;
+
+ /* Pass along the info to any clients */
+ for (i = 0; i < nt->max_qps; i++)
+ if (!test_bit(i, &nt->qp_bitmap))
+ ntb_qp_link_down(&nt->qps[i]);
+
+ /* The scratchpad registers keep the values if the remote side
+ * goes down, blast them now to give them a sane value the next
+ * time they are accessed
+ */
+ for (i = 0; i < MAX_SPAD; i++)
+ ntb_write_local_spad(nt->ndev, i, 0);
+}
+
+static void ntb_transport_event_callback(void *data, enum ntb_hw_event event)
+{
+ struct ntb_transport *nt = data;
+
+ switch (event) {
+ case NTB_EVENT_HW_LINK_UP:
+ schedule_delayed_work(&nt->link_work, 0);
+ break;
+ case NTB_EVENT_HW_LINK_DOWN:
+ schedule_work(&nt->link_cleanup);
+ break;
+ default:
+ BUG();
+ }
+}
+
+static void ntb_transport_link_work(struct work_struct *work)
+{
+ struct ntb_transport *nt = container_of(work, struct ntb_transport,
+ link_work.work);
+ struct ntb_device *ndev = nt->ndev;
+ struct pci_dev *pdev = ntb_query_pdev(ndev);
+ u32 val;
+ int rc, i;
+
+ /* send the local info */
+ rc = ntb_write_remote_spad(ndev, VERSION, NTB_TRANSPORT_VERSION);
+ if (rc) {
+ dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
+ 0, VERSION);
+ goto out;
+ }
+
+ rc = ntb_write_remote_spad(ndev, MW0_SZ, ntb_get_mw_size(ndev, 0));
+ if (rc) {
+ dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
+ (u32) ntb_get_mw_size(ndev, 0), MW0_SZ);
+ goto out;
+ }
+
+ rc = ntb_write_remote_spad(ndev, MW1_SZ, ntb_get_mw_size(ndev, 1));
+ if (rc) {
+ dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
+ (u32) ntb_get_mw_size(ndev, 1), MW1_SZ);
+ goto out;
+ }
+
+ rc = ntb_write_remote_spad(ndev, NUM_QPS, nt->max_qps);
+ if (rc) {
+ dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
+ nt->max_qps, NUM_QPS);
+ goto out;
+ }
+
+ rc = ntb_read_local_spad(nt->ndev, QP_LINKS, &val);
+ if (rc) {
+ dev_err(&pdev->dev, "Error reading spad %d\n", QP_LINKS);
+ goto out;
+ }
+
+ rc = ntb_write_remote_spad(ndev, QP_LINKS, val);
+ if (rc) {
+ dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
+ val, QP_LINKS);
+ goto out;
+ }
+
+ /* Query the remote side for its info */
+ rc = ntb_read_remote_spad(ndev, VERSION, &val);
+ if (rc) {
+ dev_err(&pdev->dev, "Error reading remote spad %d\n", VERSION);
+ goto out;
+ }
+
+ if (val != NTB_TRANSPORT_VERSION)
+ goto out;
+ dev_dbg(&pdev->dev, "Remote version = %d\n", val);
+
+ rc = ntb_read_remote_spad(ndev, NUM_QPS, &val);
+ if (rc) {
+ dev_err(&pdev->dev, "Error reading remote spad %d\n", NUM_QPS);
+ goto out;
+ }
+
+ if (val != nt->max_qps)
+ goto out;
+ dev_dbg(&pdev->dev, "Remote max number of qps = %d\n", val);
+
+ rc = ntb_read_remote_spad(ndev, MW0_SZ, &val);
+ if (rc) {
+ dev_err(&pdev->dev, "Error reading remote spad %d\n", MW0_SZ);
+ goto out;
+ }
+
+ if (!val)
+ goto out;
+ dev_dbg(&pdev->dev, "Remote MW0 size = %d\n", val);
+
+ rc = ntb_set_mw(nt, 0, val);
+ if (rc)
+ goto out;
+
+ rc = ntb_read_remote_spad(ndev, MW1_SZ, &val);
+ if (rc) {
+ dev_err(&pdev->dev, "Error reading remote spad %d\n", MW1_SZ);
+ goto out;
+ }
+
+ if (!val)
+ goto out;
+ dev_dbg(&pdev->dev, "Remote MW1 size = %d\n", val);
+
+ rc = ntb_set_mw(nt, 1, val);
+ if (rc)
+ goto out;
+
+ nt->transport_link = NTB_LINK_UP;
+
+ for (i = 0; i < nt->max_qps; i++) {
+ struct ntb_transport_qp *qp = &nt->qps[i];
+
+ ntb_transport_setup_qp_mw(nt, i);
+
+ if (qp->client_ready == NTB_LINK_UP)
+ schedule_delayed_work(&qp->link_work, 0);
+ }
+
+ return;
+
+out:
+ if (ntb_hw_link_status(ndev))
+ schedule_delayed_work(&nt->link_work,
+ msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
+}
+
+static void ntb_qp_link_work(struct work_struct *work)
+{
+ struct ntb_transport_qp *qp = container_of(work,
+ struct ntb_transport_qp,
+ link_work.work);
+ struct pci_dev *pdev = ntb_query_pdev(qp->ndev);
+ struct ntb_transport *nt = qp->transport;
+ int rc, val;
+
+ WARN_ON(nt->transport_link != NTB_LINK_UP);
+
+ rc = ntb_read_local_spad(nt->ndev, QP_LINKS, &val);
+ if (rc) {
+ dev_err(&pdev->dev, "Error reading spad %d\n", QP_LINKS);
+ return;
+ }
+
+ rc = ntb_write_remote_spad(nt->ndev, QP_LINKS, val | 1 << qp->qp_num);
+ if (rc)
+ dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
+ val | 1 << qp->qp_num, QP_LINKS);
+
+ /* query remote spad for qp ready bits */
+ rc = ntb_read_remote_spad(nt->ndev, QP_LINKS, &val);
+ if (rc)
+ dev_err(&pdev->dev, "Error reading remote spad %d\n", QP_LINKS);
+
+ dev_dbg(&pdev->dev, "Remote QP link status = %x\n", val);
+
+ /* See if the remote side is up */
+ if (1 << qp->qp_num & val) {
+ qp->qp_link = NTB_LINK_UP;
+
+ dev_info(&pdev->dev, "qp %d: Link Up\n", qp->qp_num);
+ if (qp->event_handler)
+ qp->event_handler(qp->cb_data, NTB_LINK_UP);
+ } else if (nt->transport_link == NTB_LINK_UP)
+ schedule_delayed_work(&qp->link_work,
+ msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
+}
+
+static void ntb_transport_init_queue(struct ntb_transport *nt,
+ unsigned int qp_num)
+{
+ struct ntb_transport_qp *qp;
+ unsigned int num_qps_mw, tx_size;
+ u8 mw_num = QP_TO_MW(qp_num);
+
+ qp = &nt->qps[qp_num];
+ qp->qp_num = qp_num;
+ qp->transport = nt;
+ qp->ndev = nt->ndev;
+ qp->qp_link = NTB_LINK_DOWN;
+ qp->client_ready = NTB_LINK_DOWN;
+ qp->event_handler = NULL;
+
+ if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW)
+ num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
+ else
+ num_qps_mw = nt->max_qps / NTB_NUM_MW;
+
+ tx_size = (unsigned int) ntb_get_mw_size(qp->ndev, mw_num) / num_qps_mw;
+ qp->rx_info = ntb_get_mw_vbase(nt->ndev, mw_num) +
+ (qp_num / NTB_NUM_MW * tx_size);
+ tx_size -= sizeof(struct ntb_rx_info);
+
+ qp->tx_mw = qp->rx_info + sizeof(struct ntb_rx_info);
+ qp->tx_max_frame = min(transport_mtu, tx_size);
+ qp->tx_max_entry = tx_size / qp->tx_max_frame;
+ qp->tx_index = 0;
+
+ if (nt->debugfs_dir) {
+ char debugfs_name[4];
+
+ snprintf(debugfs_name, 4, "qp%d", qp_num);
+ qp->debugfs_dir = debugfs_create_dir(debugfs_name,
+ nt->debugfs_dir);
+
+ qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR,
+ qp->debugfs_dir, qp,
+ &ntb_qp_debugfs_stats);
+ }
+
+ INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work);
+ INIT_WORK(&qp->link_cleanup, ntb_qp_link_cleanup);
+
+ spin_lock_init(&qp->ntb_rx_pend_q_lock);
+ spin_lock_init(&qp->ntb_rx_free_q_lock);
+ spin_lock_init(&qp->ntb_tx_free_q_lock);
+
+ INIT_LIST_HEAD(&qp->rx_pend_q);
+ INIT_LIST_HEAD(&qp->rx_free_q);
+ INIT_LIST_HEAD(&qp->tx_free_q);
+}
+
+int ntb_transport_init(struct pci_dev *pdev)
+{
+ struct ntb_transport *nt;
+ int rc, i;
+
+ nt = kzalloc(sizeof(struct ntb_transport), GFP_KERNEL);
+ if (!nt)
+ return -ENOMEM;
+
+ if (debugfs_initialized())
+ nt->debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ else
+ nt->debugfs_dir = NULL;
+
+ nt->ndev = ntb_register_transport(pdev, nt);
+ if (!nt->ndev) {
+ rc = -EIO;
+ goto err;
+ }
+
+ nt->max_qps = min(nt->ndev->max_cbs, max_num_clients);
+
+ nt->qps = kcalloc(nt->max_qps, sizeof(struct ntb_transport_qp),
+ GFP_KERNEL);
+ if (!nt->qps) {
+ rc = -ENOMEM;
+ goto err1;
+ }
+
+ nt->qp_bitmap = ((u64) 1 << nt->max_qps) - 1;
+
+ for (i = 0; i < nt->max_qps; i++)
+ ntb_transport_init_queue(nt, i);
+
+ INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work);
+ INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup);
+
+ rc = ntb_register_event_callback(nt->ndev,
+ ntb_transport_event_callback);
+ if (rc)
+ goto err2;
+
+ INIT_LIST_HEAD(&nt->client_devs);
+ rc = ntb_bus_init(nt);
+ if (rc)
+ goto err3;
+
+ if (ntb_hw_link_status(nt->ndev))
+ schedule_delayed_work(&nt->link_work, 0);
+
+ return 0;
+
+err3:
+ ntb_unregister_event_callback(nt->ndev);
+err2:
+ kfree(nt->qps);
+err1:
+ ntb_unregister_transport(nt->ndev);
+err:
+ debugfs_remove_recursive(nt->debugfs_dir);
+ kfree(nt);
+ return rc;
+}
+
+void ntb_transport_free(void *transport)
+{
+ struct ntb_transport *nt = transport;
+ struct pci_dev *pdev;
+ int i;
+
+ nt->transport_link = NTB_LINK_DOWN;
+
+ /* verify that all the qp's are freed */
+ for (i = 0; i < nt->max_qps; i++)
+ if (!test_bit(i, &nt->qp_bitmap))
+ ntb_transport_free_queue(&nt->qps[i]);
+
+ ntb_bus_remove(nt);
+
+ cancel_delayed_work_sync(&nt->link_work);
+
+ debugfs_remove_recursive(nt->debugfs_dir);
+
+ ntb_unregister_event_callback(nt->ndev);
+
+ pdev = ntb_query_pdev(nt->ndev);
+
+ for (i = 0; i < NTB_NUM_MW; i++)
+ if (nt->mw[i].virt_addr)
+ dma_free_coherent(&pdev->dev, nt->mw[i].size,
+ nt->mw[i].virt_addr,
+ nt->mw[i].dma_addr);
+
+ kfree(nt->qps);
+ ntb_unregister_transport(nt->ndev);
+ kfree(nt);
+}
+
+static void ntb_rx_copy_task(struct ntb_transport_qp *qp,
+ struct ntb_queue_entry *entry, void *offset)
+{
+ void *cb_data = entry->cb_data;
+ unsigned int len = entry->len;
+
+ memcpy(entry->buf, offset, entry->len);
+
+ ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q);
+
+ if (qp->rx_handler && qp->client_ready == NTB_LINK_UP)
+ qp->rx_handler(qp, qp->cb_data, cb_data, len);
+}
+
+static int ntb_process_rxc(struct ntb_transport_qp *qp)
+{
+ struct ntb_payload_header *hdr;
+ struct ntb_queue_entry *entry;
+ void *offset;
+
+ offset = qp->rx_buff + qp->rx_max_frame * qp->rx_index;
+ hdr = offset + qp->rx_max_frame - sizeof(struct ntb_payload_header);
+
+ entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
+ if (!entry) {
+ dev_dbg(&ntb_query_pdev(qp->ndev)->dev,
+ "no buffer - HDR ver %u, len %d, flags %x\n",
+ hdr->ver, hdr->len, hdr->flags);
+ qp->rx_err_no_buf++;
+ return -ENOMEM;
+ }
+
+ if (!(hdr->flags & DESC_DONE_FLAG)) {
+ ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry,
+ &qp->rx_pend_q);
+ qp->rx_ring_empty++;
+ return -EAGAIN;
+ }
+
+ if (hdr->ver != (u32) qp->rx_pkts) {
+ dev_dbg(&ntb_query_pdev(qp->ndev)->dev,
+ "qp %d: version mismatch, expected %llu - got %u\n",
+ qp->qp_num, qp->rx_pkts, hdr->ver);
+ ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry,
+ &qp->rx_pend_q);
+ qp->rx_err_ver++;
+ return -EIO;
+ }
+
+ if (hdr->flags & LINK_DOWN_FLAG) {
+ ntb_qp_link_down(qp);
+
+ ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry,
+ &qp->rx_pend_q);
+ goto out;
+ }
+
+ dev_dbg(&ntb_query_pdev(qp->ndev)->dev,
+ "rx offset %u, ver %u - %d payload received, buf size %d\n",
+ qp->rx_index, hdr->ver, hdr->len, entry->len);
+
+ if (hdr->len <= entry->len) {
+ entry->len = hdr->len;
+ ntb_rx_copy_task(qp, entry, offset);
+ } else {
+ ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry,
+ &qp->rx_pend_q);
+
+ qp->rx_err_oflow++;
+ dev_dbg(&ntb_query_pdev(qp->ndev)->dev,
+ "RX overflow! Wanted %d got %d\n",
+ hdr->len, entry->len);
+ }
+
+ qp->rx_bytes += hdr->len;
+ qp->rx_pkts++;
+
+out:
+ /* Ensure that the data is fully copied out before clearing the flag */
+ wmb();
+ hdr->flags = 0;
+ iowrite32(qp->rx_index, &qp->rx_info->entry);
+
+ qp->rx_index++;
+ qp->rx_index %= qp->rx_max_entry;
+
+ return 0;
+}
+
+static void ntb_transport_rx(unsigned long data)
+{
+ struct ntb_transport_qp *qp = (struct ntb_transport_qp *)data;
+ int rc;
+
+ do {
+ rc = ntb_process_rxc(qp);
+ } while (!rc);
+}
+
+static void ntb_transport_rxc_db(void *data, int db_num)
+{
+ struct ntb_transport_qp *qp = data;
+
+ dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n",
+ __func__, db_num);
+
+ tasklet_schedule(&qp->rx_work);
+}
+
+static void ntb_tx_copy_task(struct ntb_transport_qp *qp,
+ struct ntb_queue_entry *entry,
+ void __iomem *offset)
+{
+ struct ntb_payload_header __iomem *hdr;
+
+ memcpy_toio(offset, entry->buf, entry->len);
+
+ hdr = offset + qp->tx_max_frame - sizeof(struct ntb_payload_header);
+ iowrite32(entry->len, &hdr->len);
+ iowrite32((u32) qp->tx_pkts, &hdr->ver);
+
+ /* Ensure that the data is fully copied out before setting the flag */
+ wmb();
+ iowrite32(entry->flags | DESC_DONE_FLAG, &hdr->flags);
+
+ ntb_ring_sdb(qp->ndev, qp->qp_num);
+
+ /* The entry length can only be zero if the packet is intended to be a
+ * "link down" or similar. Since no payload is being sent in these
+ * cases, there is nothing to add to the completion queue.
+ */
+ if (entry->len > 0) {
+ qp->tx_bytes += entry->len;
+
+ if (qp->tx_handler)
+ qp->tx_handler(qp, qp->cb_data, entry->cb_data,
+ entry->len);
+ }
+
+ ntb_list_add(&qp->ntb_tx_free_q_lock, &entry->entry, &qp->tx_free_q);
+}
+
+static int ntb_process_tx(struct ntb_transport_qp *qp,
+ struct ntb_queue_entry *entry)
+{
+ void __iomem *offset;
+
+ offset = qp->tx_mw + qp->tx_max_frame * qp->tx_index;
+
+ dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%lld - offset %p, tx %u, entry len %d flags %x buff %p\n",
+ qp->tx_pkts, offset, qp->tx_index, entry->len, entry->flags,
+ entry->buf);
+ if (qp->tx_index == qp->remote_rx_info->entry) {
+ qp->tx_ring_full++;
+ return -EAGAIN;
+ }
+
+ if (entry->len > qp->tx_max_frame - sizeof(struct ntb_payload_header)) {
+ if (qp->tx_handler)
+ qp->tx_handler(qp->cb_data, qp, NULL, -EIO);
+
+ ntb_list_add(&qp->ntb_tx_free_q_lock, &entry->entry,
+ &qp->tx_free_q);
+ return 0;
+ }
+
+ ntb_tx_copy_task(qp, entry, offset);
+
+ qp->tx_index++;
+ qp->tx_index %= qp->tx_max_entry;
+
+ qp->tx_pkts++;
+
+ return 0;
+}
+
+static void ntb_send_link_down(struct ntb_transport_qp *qp)
+{
+ struct pci_dev *pdev = ntb_query_pdev(qp->ndev);
+ struct ntb_queue_entry *entry;
+ int i, rc;
+
+ if (qp->qp_link == NTB_LINK_DOWN)
+ return;
+
+ qp->qp_link = NTB_LINK_DOWN;
+ dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num);
+
+ for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) {
+ entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
+ if (entry)
+ break;
+ msleep(100);
+ }
+
+ if (!entry)
+ return;
+
+ entry->cb_data = NULL;
+ entry->buf = NULL;
+ entry->len = 0;
+ entry->flags = LINK_DOWN_FLAG;
+
+ rc = ntb_process_tx(qp, entry);
+ if (rc)
+ dev_err(&pdev->dev, "ntb: QP%d unable to send linkdown msg\n",
+ qp->qp_num);
+}
+
+/**
+ * ntb_transport_create_queue - Create a new NTB transport layer queue
+ * @rx_handler: receive callback function
+ * @tx_handler: transmit callback function
+ * @event_handler: event callback function
+ *
+ * Create a new NTB transport layer queue and provide the queue with a callback
+ * routine for both transmit and receive. The receive callback routine will be
+ * used to pass up data when the transport has received it on the queue. The
+ * transmit callback routine will be called when the transport has completed the
+ * transmission of the data on the queue and the data is ready to be freed.
+ *
+ * RETURNS: pointer to newly created ntb_queue, NULL on error.
+ */
+struct ntb_transport_qp *
+ntb_transport_create_queue(void *data, struct pci_dev *pdev,
+ const struct ntb_queue_handlers *handlers)
+{
+ struct ntb_queue_entry *entry;
+ struct ntb_transport_qp *qp;
+ struct ntb_transport *nt;
+ unsigned int free_queue;
+ int rc, i;
+
+ nt = ntb_find_transport(pdev);
+ if (!nt)
+ goto err;
+
+ free_queue = ffs(nt->qp_bitmap);
+ if (!free_queue)
+ goto err;
+
+ /* decrement free_queue to make it zero based */
+ free_queue--;
+
+ clear_bit(free_queue, &nt->qp_bitmap);
+
+ qp = &nt->qps[free_queue];
+ qp->cb_data = data;
+ qp->rx_handler = handlers->rx_handler;
+ qp->tx_handler = handlers->tx_handler;
+ qp->event_handler = handlers->event_handler;
+
+ for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
+ entry = kzalloc(sizeof(struct ntb_queue_entry), GFP_ATOMIC);
+ if (!entry)
+ goto err1;
+
+ ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry,
+ &qp->rx_free_q);
+ }
+
+ for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
+ entry = kzalloc(sizeof(struct ntb_queue_entry), GFP_ATOMIC);
+ if (!entry)
+ goto err2;
+
+ ntb_list_add(&qp->ntb_tx_free_q_lock, &entry->entry,
+ &qp->tx_free_q);
+ }
+
+ tasklet_init(&qp->rx_work, ntb_transport_rx, (unsigned long) qp);
+
+ rc = ntb_register_db_callback(qp->ndev, free_queue, qp,
+ ntb_transport_rxc_db);
+ if (rc)
+ goto err3;
+
+ dev_info(&pdev->dev, "NTB Transport QP %d created\n", qp->qp_num);
+
+ return qp;
+
+err3:
+ tasklet_disable(&qp->rx_work);
+err2:
+ while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
+ kfree(entry);
+err1:
+ while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
+ kfree(entry);
+ set_bit(free_queue, &nt->qp_bitmap);
+err:
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(ntb_transport_create_queue);
+
+/**
+ * ntb_transport_free_queue - Frees NTB transport queue
+ * @qp: NTB queue to be freed
+ *
+ * Frees NTB transport queue
+ */
+void ntb_transport_free_queue(struct ntb_transport_qp *qp)
+{
+ struct pci_dev *pdev = ntb_query_pdev(qp->ndev);
+ struct ntb_queue_entry *entry;
+
+ if (!qp)
+ return;
+
+ cancel_delayed_work_sync(&qp->link_work);
+
+ ntb_unregister_db_callback(qp->ndev, qp->qp_num);
+ tasklet_disable(&qp->rx_work);
+
+ while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
+ kfree(entry);
+
+ while ((entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q))) {
+ dev_warn(&pdev->dev, "Freeing item from a non-empty queue\n");
+ kfree(entry);
+ }
+
+ while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
+ kfree(entry);
+
+ set_bit(qp->qp_num, &qp->transport->qp_bitmap);
+
+ dev_info(&pdev->dev, "NTB Transport QP %d freed\n", qp->qp_num);
+}
+EXPORT_SYMBOL_GPL(ntb_transport_free_queue);
+
+/**
+ * ntb_transport_rx_remove - Dequeues enqueued rx packet
+ * @qp: NTB queue to be freed
+ * @len: pointer to variable to write enqueued buffers length
+ *
+ * Dequeues unused buffers from receive queue. Should only be used during
+ * shutdown of qp.
+ *
+ * RETURNS: NULL error value on error, or void* for success.
+ */
+void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len)
+{
+ struct ntb_queue_entry *entry;
+ void *buf;
+
+ if (!qp || qp->client_ready == NTB_LINK_UP)
+ return NULL;
+
+ entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
+ if (!entry)
+ return NULL;
+
+ buf = entry->cb_data;
+ *len = entry->len;
+
+ ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q);
+
+ return buf;
+}
+EXPORT_SYMBOL_GPL(ntb_transport_rx_remove);
+
+/**
+ * ntb_transport_rx_enqueue - Enqueue a new NTB queue entry
+ * @qp: NTB transport layer queue the entry is to be enqueued on
+ * @cb: per buffer pointer for callback function to use
+ * @data: pointer to data buffer that incoming packets will be copied into
+ * @len: length of the data buffer
+ *
+ * Enqueue a new receive buffer onto the transport queue into which a NTB
+ * payload can be received into.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
+ unsigned int len)
+{
+ struct ntb_queue_entry *entry;
+
+ if (!qp)
+ return -EINVAL;
+
+ entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->cb_data = cb;
+ entry->buf = data;
+ entry->len = len;
+
+ ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, &qp->rx_pend_q);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ntb_transport_rx_enqueue);
+
+/**
+ * ntb_transport_tx_enqueue - Enqueue a new NTB queue entry
+ * @qp: NTB transport layer queue the entry is to be enqueued on
+ * @cb: per buffer pointer for callback function to use
+ * @data: pointer to data buffer that will be sent
+ * @len: length of the data buffer
+ *
+ * Enqueue a new transmit buffer onto the transport queue from which a NTB
+ * payload will be transmitted. This assumes that a lock is behing held to
+ * serialize access to the qp.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
+ unsigned int len)
+{
+ struct ntb_queue_entry *entry;
+ int rc;
+
+ if (!qp || qp->qp_link != NTB_LINK_UP || !len)
+ return -EINVAL;
+
+ entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->cb_data = cb;
+ entry->buf = data;
+ entry->len = len;
+ entry->flags = 0;
+
+ rc = ntb_process_tx(qp, entry);
+ if (rc)
+ ntb_list_add(&qp->ntb_tx_free_q_lock, &entry->entry,
+ &qp->tx_free_q);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ntb_transport_tx_enqueue);
+
+/**
+ * ntb_transport_link_up - Notify NTB transport of client readiness to use queue
+ * @qp: NTB transport layer queue to be enabled
+ *
+ * Notify NTB transport layer of client readiness to use queue
+ */
+void ntb_transport_link_up(struct ntb_transport_qp *qp)
+{
+ if (!qp)
+ return;
+
+ qp->client_ready = NTB_LINK_UP;
+
+ if (qp->transport->transport_link == NTB_LINK_UP)
+ schedule_delayed_work(&qp->link_work, 0);
+}
+EXPORT_SYMBOL_GPL(ntb_transport_link_up);
+
+/**
+ * ntb_transport_link_down - Notify NTB transport to no longer enqueue data
+ * @qp: NTB transport layer queue to be disabled
+ *
+ * Notify NTB transport layer of client's desire to no longer receive data on
+ * transport queue specified. It is the client's responsibility to ensure all
+ * entries on queue are purged or otherwise handled appropraitely.
+ */
+void ntb_transport_link_down(struct ntb_transport_qp *qp)
+{
+ struct pci_dev *pdev = ntb_query_pdev(qp->ndev);
+ int rc, val;
+
+ if (!qp)
+ return;
+
+ qp->client_ready = NTB_LINK_DOWN;
+
+ rc = ntb_read_local_spad(qp->ndev, QP_LINKS, &val);
+ if (rc) {
+ dev_err(&pdev->dev, "Error reading spad %d\n", QP_LINKS);
+ return;
+ }
+
+ rc = ntb_write_remote_spad(qp->ndev, QP_LINKS,
+ val & ~(1 << qp->qp_num));
+ if (rc)
+ dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
+ val & ~(1 << qp->qp_num), QP_LINKS);
+
+ if (qp->qp_link == NTB_LINK_UP)
+ ntb_send_link_down(qp);
+ else
+ cancel_delayed_work_sync(&qp->link_work);
+}
+EXPORT_SYMBOL_GPL(ntb_transport_link_down);
+
+/**
+ * ntb_transport_link_query - Query transport link state
+ * @qp: NTB transport layer queue to be queried
+ *
+ * Query connectivity to the remote system of the NTB transport queue
+ *
+ * RETURNS: true for link up or false for link down
+ */
+bool ntb_transport_link_query(struct ntb_transport_qp *qp)
+{
+ return qp->qp_link == NTB_LINK_UP;
+}
+EXPORT_SYMBOL_GPL(ntb_transport_link_query);
+
+/**
+ * ntb_transport_qp_num - Query the qp number
+ * @qp: NTB transport layer queue to be queried
+ *
+ * Query qp number of the NTB transport queue
+ *
+ * RETURNS: a zero based number specifying the qp number
+ */
+unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp)
+{
+ return qp->qp_num;
+}
+EXPORT_SYMBOL_GPL(ntb_transport_qp_num);
+
+/**
+ * ntb_transport_max_size - Query the max payload size of a qp
+ * @qp: NTB transport layer queue to be queried
+ *
+ * Query the maximum payload size permissible on the given qp
+ *
+ * RETURNS: the max payload size of a qp
+ */
+unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp)
+{
+ return qp->tx_max_frame - sizeof(struct ntb_payload_header);
+}
+EXPORT_SYMBOL_GPL(ntb_transport_max_size);
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 0125524c08c4..04da786c84d2 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -429,7 +429,7 @@ static u64 __of_translate_address(struct device_node *dev,
goto bail;
bus = of_match_bus(parent);
- /* Cound address cells & copy address locally */
+ /* Count address cells & copy address locally */
bus->count_cells(dev, &na, &ns);
if (!OF_CHECK_COUNTS(na, ns)) {
printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 2390ddb22d60..321d3ef05006 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -24,38 +24,21 @@
#include <linux/slab.h>
#include <linux/proc_fs.h>
-/**
- * struct alias_prop - Alias property in 'aliases' node
- * @link: List node to link the structure in aliases_lookup list
- * @alias: Alias property name
- * @np: Pointer to device_node that the alias stands for
- * @id: Index value from end of alias name
- * @stem: Alias string without the index
- *
- * The structure represents one alias property of 'aliases' node as
- * an entry in aliases_lookup list.
- */
-struct alias_prop {
- struct list_head link;
- const char *alias;
- struct device_node *np;
- int id;
- char stem[0];
-};
+#include "of_private.h"
-static LIST_HEAD(aliases_lookup);
+LIST_HEAD(aliases_lookup);
struct device_node *of_allnodes;
EXPORT_SYMBOL(of_allnodes);
struct device_node *of_chosen;
struct device_node *of_aliases;
-static DEFINE_MUTEX(of_aliases_mutex);
+DEFINE_MUTEX(of_aliases_mutex);
/* use when traversing tree through the allnext, child, sibling,
* or parent members of struct device_node.
*/
-DEFINE_RWLOCK(devtree_lock);
+DEFINE_RAW_SPINLOCK(devtree_lock);
int of_n_addr_cells(struct device_node *np)
{
@@ -164,16 +147,14 @@ void of_node_put(struct device_node *node)
EXPORT_SYMBOL(of_node_put);
#endif /* CONFIG_OF_DYNAMIC */
-struct property *of_find_property(const struct device_node *np,
- const char *name,
- int *lenp)
+static struct property *__of_find_property(const struct device_node *np,
+ const char *name, int *lenp)
{
struct property *pp;
if (!np)
return NULL;
- read_lock(&devtree_lock);
for (pp = np->properties; pp; pp = pp->next) {
if (of_prop_cmp(pp->name, name) == 0) {
if (lenp)
@@ -181,7 +162,20 @@ struct property *of_find_property(const struct device_node *np,
break;
}
}
- read_unlock(&devtree_lock);
+
+ return pp;
+}
+
+struct property *of_find_property(const struct device_node *np,
+ const char *name,
+ int *lenp)
+{
+ struct property *pp;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ pp = __of_find_property(np, name, lenp);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return pp;
}
@@ -199,13 +193,13 @@ struct device_node *of_find_all_nodes(struct device_node *prev)
{
struct device_node *np;
- read_lock(&devtree_lock);
+ raw_spin_lock(&devtree_lock);
np = prev ? prev->allnext : of_allnodes;
for (; np != NULL; np = np->allnext)
if (of_node_get(np))
break;
of_node_put(prev);
- read_unlock(&devtree_lock);
+ raw_spin_unlock(&devtree_lock);
return np;
}
EXPORT_SYMBOL(of_find_all_nodes);
@@ -214,8 +208,20 @@ EXPORT_SYMBOL(of_find_all_nodes);
* Find a property with a given name for a given node
* and return the value.
*/
+static const void *__of_get_property(const struct device_node *np,
+ const char *name, int *lenp)
+{
+ struct property *pp = __of_find_property(np, name, lenp);
+
+ return pp ? pp->value : NULL;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
const void *of_get_property(const struct device_node *np, const char *name,
- int *lenp)
+ int *lenp)
{
struct property *pp = of_find_property(np, name, lenp);
@@ -226,13 +232,13 @@ EXPORT_SYMBOL(of_get_property);
/** Checks if the given "compat" string matches one of the strings in
* the device's "compatible" property
*/
-int of_device_is_compatible(const struct device_node *device,
- const char *compat)
+static int __of_device_is_compatible(const struct device_node *device,
+ const char *compat)
{
const char* cp;
int cplen, l;
- cp = of_get_property(device, "compatible", &cplen);
+ cp = __of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
@@ -245,6 +251,21 @@ int of_device_is_compatible(const struct device_node *device,
return 0;
}
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
+{
+ unsigned long flags;
+ int res;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ res = __of_device_is_compatible(device, compat);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ return res;
+}
EXPORT_SYMBOL(of_device_is_compatible);
/**
@@ -269,19 +290,19 @@ int of_machine_is_compatible(const char *compat)
EXPORT_SYMBOL(of_machine_is_compatible);
/**
- * of_device_is_available - check if a device is available for use
+ * __of_device_is_available - check if a device is available for use
*
- * @device: Node to check for availability
+ * @device: Node to check for availability, with locks already held
*
* Returns 1 if the status property is absent or set to "okay" or "ok",
* 0 otherwise
*/
-int of_device_is_available(const struct device_node *device)
+static int __of_device_is_available(const struct device_node *device)
{
const char *status;
int statlen;
- status = of_get_property(device, "status", &statlen);
+ status = __of_get_property(device, "status", &statlen);
if (status == NULL)
return 1;
@@ -292,6 +313,26 @@ int of_device_is_available(const struct device_node *device)
return 0;
}
+
+/**
+ * of_device_is_available - check if a device is available for use
+ *
+ * @device: Node to check for availability
+ *
+ * Returns 1 if the status property is absent or set to "okay" or "ok",
+ * 0 otherwise
+ */
+int of_device_is_available(const struct device_node *device)
+{
+ unsigned long flags;
+ int res;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ res = __of_device_is_available(device);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ return res;
+
+}
EXPORT_SYMBOL(of_device_is_available);
/**
@@ -304,13 +345,14 @@ EXPORT_SYMBOL(of_device_is_available);
struct device_node *of_get_parent(const struct device_node *node)
{
struct device_node *np;
+ unsigned long flags;
if (!node)
return NULL;
- read_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
np = of_node_get(node->parent);
- read_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_get_parent);
@@ -329,14 +371,15 @@ EXPORT_SYMBOL(of_get_parent);
struct device_node *of_get_next_parent(struct device_node *node)
{
struct device_node *parent;
+ unsigned long flags;
if (!node)
return NULL;
- read_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
parent = of_node_get(node->parent);
of_node_put(node);
- read_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return parent;
}
@@ -352,14 +395,15 @@ struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
+ unsigned long flags;
- read_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling)
if (of_node_get(next))
break;
of_node_put(prev);
- read_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return next;
}
EXPORT_SYMBOL(of_get_next_child);
@@ -377,16 +421,16 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
{
struct device_node *next;
- read_lock(&devtree_lock);
+ raw_spin_lock(&devtree_lock);
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling) {
- if (!of_device_is_available(next))
+ if (!__of_device_is_available(next))
continue;
if (of_node_get(next))
break;
}
of_node_put(prev);
- read_unlock(&devtree_lock);
+ raw_spin_unlock(&devtree_lock);
return next;
}
EXPORT_SYMBOL(of_get_next_available_child);
@@ -424,14 +468,15 @@ EXPORT_SYMBOL(of_get_child_by_name);
struct device_node *of_find_node_by_path(const char *path)
{
struct device_node *np = of_allnodes;
+ unsigned long flags;
- read_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
for (; np; np = np->allnext) {
if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
&& of_node_get(np))
break;
}
- read_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_node_by_path);
@@ -451,15 +496,16 @@ struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)
{
struct device_node *np;
+ unsigned long flags;
- read_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes;
for (; np; np = np->allnext)
if (np->name && (of_node_cmp(np->name, name) == 0)
&& of_node_get(np))
break;
of_node_put(from);
- read_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_node_by_name);
@@ -480,15 +526,16 @@ struct device_node *of_find_node_by_type(struct device_node *from,
const char *type)
{
struct device_node *np;
+ unsigned long flags;
- read_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes;
for (; np; np = np->allnext)
if (np->type && (of_node_cmp(np->type, type) == 0)
&& of_node_get(np))
break;
of_node_put(from);
- read_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_node_by_type);
@@ -511,18 +558,20 @@ struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compatible)
{
struct device_node *np;
+ unsigned long flags;
- read_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes;
for (; np; np = np->allnext) {
if (type
&& !(np->type && (of_node_cmp(np->type, type) == 0)))
continue;
- if (of_device_is_compatible(np, compatible) && of_node_get(np))
+ if (__of_device_is_compatible(np, compatible) &&
+ of_node_get(np))
break;
}
of_node_put(from);
- read_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_compatible_node);
@@ -544,8 +593,9 @@ struct device_node *of_find_node_with_property(struct device_node *from,
{
struct device_node *np;
struct property *pp;
+ unsigned long flags;
- read_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes;
for (; np; np = np->allnext) {
for (pp = np->properties; pp; pp = pp->next) {
@@ -557,20 +607,14 @@ struct device_node *of_find_node_with_property(struct device_node *from,
}
out:
of_node_put(from);
- read_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_node_with_property);
-/**
- * of_match_node - Tell if an device_node has a matching of_match structure
- * @matches: array of of device match structures to search in
- * @node: the of device structure to match against
- *
- * Low level utility function used by device matching.
- */
-const struct of_device_id *of_match_node(const struct of_device_id *matches,
- const struct device_node *node)
+static
+const struct of_device_id *__of_match_node(const struct of_device_id *matches,
+ const struct device_node *node)
{
if (!matches)
return NULL;
@@ -584,14 +628,33 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches,
match &= node->type
&& !strcmp(matches->type, node->type);
if (matches->compatible[0])
- match &= of_device_is_compatible(node,
- matches->compatible);
+ match &= __of_device_is_compatible(node,
+ matches->compatible);
if (match)
return matches;
matches++;
}
return NULL;
}
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ * @matches: array of of device match structures to search in
+ * @node: the of device structure to match against
+ *
+ * Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+ const struct device_node *node)
+{
+ const struct of_device_id *match;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ match = __of_match_node(matches, node);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+ return match;
+}
EXPORT_SYMBOL(of_match_node);
/**
@@ -612,21 +675,24 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from,
const struct of_device_id **match)
{
struct device_node *np;
+ const struct of_device_id *m;
+ unsigned long flags;
if (match)
*match = NULL;
- read_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
np = from ? from->allnext : of_allnodes;
for (; np; np = np->allnext) {
- if (of_match_node(matches, np) && of_node_get(np)) {
+ m = __of_match_node(matches, np);
+ if (m && of_node_get(np)) {
if (match)
- *match = matches;
+ *match = m;
break;
}
}
of_node_put(from);
- read_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_matching_node_and_match);
@@ -669,12 +735,12 @@ struct device_node *of_find_node_by_phandle(phandle handle)
{
struct device_node *np;
- read_lock(&devtree_lock);
+ raw_spin_lock(&devtree_lock);
for (np = of_allnodes; np; np = np->allnext)
if (np->phandle == handle)
break;
of_node_get(np);
- read_unlock(&devtree_lock);
+ raw_spin_unlock(&devtree_lock);
return np;
}
EXPORT_SYMBOL(of_find_node_by_phandle);
@@ -1025,12 +1091,13 @@ EXPORT_SYMBOL(of_parse_phandle);
* To get a device_node of the `node2' node you may call this:
* of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
*/
-int of_parse_phandle_with_args(const struct device_node *np, const char *list_name,
- const char *cells_name, int index,
- struct of_phandle_args *out_args)
+static int __of_parse_phandle_with_args(const struct device_node *np,
+ const char *list_name,
+ const char *cells_name, int index,
+ struct of_phandle_args *out_args)
{
const __be32 *list, *list_end;
- int size, cur_index = 0;
+ int rc = 0, size, cur_index = 0;
uint32_t count = 0;
struct device_node *node = NULL;
phandle phandle;
@@ -1043,6 +1110,7 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
/* Loop over the phandles until all the requested entry is found */
while (list < list_end) {
+ rc = -EINVAL;
count = 0;
/*
@@ -1059,13 +1127,13 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
if (!node) {
pr_err("%s: could not find phandle\n",
np->full_name);
- break;
+ goto err;
}
if (of_property_read_u32(node, cells_name, &count)) {
pr_err("%s: could not get %s for %s\n",
np->full_name, cells_name,
node->full_name);
- break;
+ goto err;
}
/*
@@ -1075,7 +1143,7 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
if (list + count > list_end) {
pr_err("%s: arguments longer than property\n",
np->full_name);
- break;
+ goto err;
}
}
@@ -1085,9 +1153,10 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
* index matches, then fill the out_args structure and return,
* or return -ENOENT for an empty entry.
*/
+ rc = -ENOENT;
if (cur_index == index) {
if (!phandle)
- return -ENOENT;
+ goto err;
if (out_args) {
int i;
@@ -1098,6 +1167,10 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
for (i = 0; i < count; i++)
out_args->args[i] = be32_to_cpup(list++);
}
+
+ /* Found it! return success */
+ if (node)
+ of_node_put(node);
return 0;
}
@@ -1107,13 +1180,51 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
cur_index++;
}
- /* Loop exited without finding a valid entry; return an error */
+ /*
+ * Unlock node before returning result; will be one of:
+ * -ENOENT : index is for empty phandle
+ * -EINVAL : parsing error on data
+ * [1..n] : Number of phandle (count mode; when index = -1)
+ */
+ rc = index < 0 ? cur_index : -ENOENT;
+ err:
if (node)
of_node_put(node);
- return -EINVAL;
+ return rc;
+}
+
+int of_parse_phandle_with_args(const struct device_node *np, const char *list_name,
+ const char *cells_name, int index,
+ struct of_phandle_args *out_args)
+{
+ if (index < 0)
+ return -EINVAL;
+ return __of_parse_phandle_with_args(np, list_name, cells_name, index, out_args);
}
EXPORT_SYMBOL(of_parse_phandle_with_args);
+/**
+ * of_count_phandle_with_args() - Find the number of phandles references in a property
+ * @np: pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name: property name that specifies phandles' arguments count
+ *
+ * Returns the number of phandle + argument tuples within a property. It
+ * is a typical pattern to encode a list of phandle and variable
+ * arguments into a single property. The number of arguments is encoded
+ * by a property in the phandle-target node. For example, a gpios
+ * property would contain a list of GPIO specifies consisting of a
+ * phandle and 1 or more arguments. The number of arguments are
+ * determined by the #gpio-cells property in the node pointed to by the
+ * phandle.
+ */
+int of_count_phandle_with_args(const struct device_node *np, const char *list_name,
+ const char *cells_name)
+{
+ return __of_parse_phandle_with_args(np, list_name, cells_name, -1, NULL);
+}
+EXPORT_SYMBOL(of_count_phandle_with_args);
+
#if defined(CONFIG_OF_DYNAMIC)
static int of_property_notify(int action, struct device_node *np,
struct property *prop)
@@ -1146,18 +1257,18 @@ int of_add_property(struct device_node *np, struct property *prop)
return rc;
prop->next = NULL;
- write_lock_irqsave(&devtree_lock, flags);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
next = &np->properties;
while (*next) {
if (strcmp(prop->name, (*next)->name) == 0) {
/* duplicate ! don't insert it */
- write_unlock_irqrestore(&devtree_lock, flags);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return -1;
}
next = &(*next)->next;
}
*next = prop;
- write_unlock_irqrestore(&devtree_lock, flags);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
#ifdef CONFIG_PROC_DEVICETREE
/* try to add to proc as well if it was initialized */
@@ -1187,7 +1298,7 @@ int of_remove_property(struct device_node *np, struct property *prop)
if (rc)
return rc;
- write_lock_irqsave(&devtree_lock, flags);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
next = &np->properties;
while (*next) {
if (*next == prop) {
@@ -1200,7 +1311,7 @@ int of_remove_property(struct device_node *np, struct property *prop)
}
next = &(*next)->next;
}
- write_unlock_irqrestore(&devtree_lock, flags);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (!found)
return -ENODEV;
@@ -1240,7 +1351,7 @@ int of_update_property(struct device_node *np, struct property *newprop)
if (!oldprop)
return of_add_property(np, newprop);
- write_lock_irqsave(&devtree_lock, flags);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
next = &np->properties;
while (*next) {
if (*next == oldprop) {
@@ -1254,7 +1365,7 @@ int of_update_property(struct device_node *np, struct property *newprop)
}
next = &(*next)->next;
}
- write_unlock_irqrestore(&devtree_lock, flags);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (!found)
return -ENODEV;
@@ -1327,12 +1438,12 @@ int of_attach_node(struct device_node *np)
if (rc)
return rc;
- write_lock_irqsave(&devtree_lock, flags);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
np->sibling = np->parent->child;
np->allnext = of_allnodes;
np->parent->child = np;
of_allnodes = np;
- write_unlock_irqrestore(&devtree_lock, flags);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
of_add_proc_dt_entry(np);
return 0;
@@ -1375,17 +1486,17 @@ int of_detach_node(struct device_node *np)
if (rc)
return rc;
- write_lock_irqsave(&devtree_lock, flags);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
if (of_node_check_flag(np, OF_DETACHED)) {
/* someone already detached it */
- write_unlock_irqrestore(&devtree_lock, flags);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return rc;
}
parent = np->parent;
if (!parent) {
- write_unlock_irqrestore(&devtree_lock, flags);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return rc;
}
@@ -1412,7 +1523,7 @@ int of_detach_node(struct device_node *np)
}
of_node_set_flag(np, OF_DETACHED);
- write_unlock_irqrestore(&devtree_lock, flags);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
of_remove_proc_dt_entry(np);
return rc;
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 4c74e4fc5a51..f685e55e0717 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -8,6 +8,7 @@
#include <linux/slab.h>
#include <asm/errno.h>
+#include "of_private.h"
/**
* of_match_device - Tell if a struct device matches an of_device_id list
@@ -131,6 +132,7 @@ ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len)
void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
const char *compat;
+ struct alias_prop *app;
int seen = 0, cplen, sl;
if ((!dev) || (!dev->of_node))
@@ -153,6 +155,17 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
seen++;
}
add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
+
+ seen = 0;
+ mutex_lock(&of_aliases_mutex);
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (dev->of_node == app->np) {
+ add_uevent_var(env, "OF_ALIAS_%d=%s", seen,
+ app->alias);
+ seen++;
+ }
+ }
+ mutex_unlock(&of_aliases_mutex);
}
int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 83ca06f4312b..e3a8b22ef9dd 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -157,7 +157,7 @@ struct phy_device *of_phy_connect(struct net_device *dev,
if (!phy)
return NULL;
- return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy;
+ return phy_connect_direct(dev, phy, hndlr, iface) ? NULL : phy;
}
EXPORT_SYMBOL(of_phy_connect);
@@ -194,7 +194,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
sprintf(bus_id, PHY_ID_FMT, "fixed-0", be32_to_cpu(phy_id[0]));
- phy = phy_connect(dev, bus_id, hndlr, 0, iface);
+ phy = phy_connect(dev, bus_id, hndlr, iface);
return IS_ERR(phy) ? NULL : phy;
}
EXPORT_SYMBOL(of_phy_connect_fixed_link);
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
new file mode 100644
index 000000000000..ff350c8fa7ac
--- /dev/null
+++ b/drivers/of/of_private.h
@@ -0,0 +1,36 @@
+#ifndef _LINUX_OF_PRIVATE_H
+#define _LINUX_OF_PRIVATE_H
+/*
+ * Private symbols used by OF support code
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/**
+ * struct alias_prop - Alias property in 'aliases' node
+ * @link: List node to link the structure in aliases_lookup list
+ * @alias: Alias property name
+ * @np: Pointer to device_node that the alias stands for
+ * @id: Index value from end of alias name
+ * @stem: Alias string without the index
+ *
+ * The structure represents one alias property of 'aliases' node as
+ * an entry in aliases_lookup list.
+ */
+struct alias_prop {
+ struct list_head link;
+ const char *alias;
+ struct device_node *np;
+ int id;
+ char stem[0];
+};
+
+extern struct mutex of_aliases_mutex;
+extern struct list_head aliases_lookup;
+#endif /* _LINUX_OF_PRIVATE_H */
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index b80891b43816..e0a6514ab46c 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -436,6 +436,7 @@ EXPORT_SYMBOL(of_platform_bus_probe);
* of_platform_populate() - Populate platform_devices from device tree data
* @root: parent of the first level to probe or NULL for the root of the tree
* @matches: match table, NULL to use the default
+ * @lookup: auxdata table for matching id and platform_data with device nodes
* @parent: parent to hook devices from, NULL for toplevel
*
* Similar to of_platform_bus_probe(), this function walks the device tree
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
index f24ffd7088d2..0eb5c38b4e07 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/selftest.c
@@ -2,7 +2,7 @@
* Self tests for device tree subsystem
*/
-#define pr_fmt(fmt) "### %s(): " fmt, __func__
+#define pr_fmt(fmt) "### dt-test ### " fmt
#include <linux/clk.h>
#include <linux/err.h>
@@ -16,26 +16,30 @@
static bool selftest_passed = true;
#define selftest(result, fmt, ...) { \
- selftest_passed &= (result); \
- if (!(result)) \
+ if (!(result)) { \
pr_err("FAIL %s:%i " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \
+ selftest_passed = false; \
+ } else { \
+ pr_info("pass %s:%i\n", __FILE__, __LINE__); \
+ } \
}
static void __init of_selftest_parse_phandle_with_args(void)
{
struct device_node *np;
struct of_phandle_args args;
- int rc, i;
- bool passed_all = true;
+ int i, rc;
- pr_info("start\n");
np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
if (!np) {
pr_err("missing testcase data\n");
return;
}
- for (i = 0; i < 7; i++) {
+ rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells");
+ selftest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);
+
+ for (i = 0; i < 8; i++) {
bool passed = true;
rc = of_parse_phandle_with_args(np, "phandle-list",
"#phandle-cells", i, &args);
@@ -79,45 +83,47 @@ static void __init of_selftest_parse_phandle_with_args(void)
passed &= (args.args[0] == (i + 1));
break;
case 7:
- passed &= (rc == -EINVAL);
+ passed &= (rc == -ENOENT);
break;
default:
passed = false;
}
- if (!passed) {
- int j;
- pr_err("index %i - data error on node %s rc=%i regs=[",
- i, args.np->full_name, rc);
- for (j = 0; j < args.args_count; j++)
- printk(" %i", args.args[j]);
- printk(" ]\n");
-
- passed_all = false;
- }
+ selftest(passed, "index %i - data error on node %s rc=%i\n",
+ i, args.np->full_name, rc);
}
/* Check for missing list property */
rc = of_parse_phandle_with_args(np, "phandle-list-missing",
"#phandle-cells", 0, &args);
- passed_all &= (rc == -EINVAL);
+ selftest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
+ rc = of_count_phandle_with_args(np, "phandle-list-missing",
+ "#phandle-cells");
+ selftest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
/* Check for missing cells property */
rc = of_parse_phandle_with_args(np, "phandle-list",
"#phandle-cells-missing", 0, &args);
- passed_all &= (rc == -EINVAL);
+ selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+ rc = of_count_phandle_with_args(np, "phandle-list",
+ "#phandle-cells-missing");
+ selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
/* Check for bad phandle in list */
rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle",
"#phandle-cells", 0, &args);
- passed_all &= (rc == -EINVAL);
+ selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+ rc = of_count_phandle_with_args(np, "phandle-list-bad-phandle",
+ "#phandle-cells");
+ selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
/* Check for incorrectly formed argument list */
rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
"#phandle-cells", 1, &args);
- passed_all &= (rc == -EINVAL);
-
- pr_info("end - %s\n", passed_all ? "PASS" : "FAIL");
+ selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+ rc = of_count_phandle_with_args(np, "phandle-list-bad-args",
+ "#phandle-cells");
+ selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
}
static void __init of_selftest_property_match_string(void)
diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig
index 620264936341..592de566e72f 100644
--- a/drivers/parisc/Kconfig
+++ b/drivers/parisc/Kconfig
@@ -128,6 +128,7 @@ config SUPERIO
config CHASSIS_LCD_LED
bool "Chassis LCD and LED support"
default y
+ select VM_EVENT_COUNTERS
help
Say Y here if you want to enable support for the Heartbeat,
Disk/Network activities LEDs on some PA-RISC machines,
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 8e4e86b78428..9eae9834bcc7 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -580,15 +580,13 @@ dino_fixup_bus(struct pci_bus *bus)
}
- DBG("DEBUG %s assigning %d [0x%lx,0x%lx]\n",
+ DBG("DEBUG %s assigning %d [%pR]\n",
dev_name(&bus->self->dev), i,
- bus->self->resource[i].start,
- bus->self->resource[i].end);
+ &bus->self->resource[i]);
WARN_ON(pci_assign_resource(bus->self, i));
- DBG("DEBUG %s after assign %d [0x%lx,0x%lx]\n",
+ DBG("DEBUG %s after assign %d [%pR]\n",
dev_name(&bus->self->dev), i,
- bus->self->resource[i].start,
- bus->self->resource[i].end);
+ &bus->self->resource[i]);
}
}
@@ -772,8 +770,7 @@ dino_bridge_init(struct dino_device *dino_dev, const char *name)
result = ccio_request_resource(dino_dev->hba.dev, &res[i]);
if (result < 0) {
printk(KERN_ERR "%s: failed to claim PCI Bus address "
- "space %d (0x%lx-0x%lx)!\n", name, i,
- (unsigned long)res[i].start, (unsigned long)res[i].end);
+ "space %d (%pR)!\n", name, i, &res[i]);
return result;
}
}
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index 815db175d427..898208e4f302 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -74,10 +74,8 @@ static int hppb_probe(struct parisc_device *dev)
status = ccio_request_resource(dev, &card->mmio_region);
if(status < 0) {
- printk(KERN_ERR "%s: failed to claim HP-PB "
- "bus space (0x%08llx, 0x%08llx)\n",
- __FILE__, (unsigned long long) card->mmio_region.start,
- (unsigned long long) card->mmio_region.end);
+ printk(KERN_ERR "%s: failed to claim HP-PB bus space (%pR)\n",
+ __FILE__, &card->mmio_region);
}
return 0;
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index 246a92f677e4..0f54ab6260df 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -212,12 +212,10 @@ pdcspath_store(struct pdcspath_entry *entry)
entry, devpath, entry->addr);
/* addr, devpath and count must be word aligned */
- if (pdc_stable_write(entry->addr, devpath, sizeof(*devpath)) != PDC_OK) {
- printk(KERN_ERR "%s: an error occurred when writing to PDC.\n"
+ if (pdc_stable_write(entry->addr, devpath, sizeof(*devpath)) != PDC_OK)
+ WARN(1, KERN_ERR "%s: an error occurred when writing to PDC.\n"
"It is likely that the Stable Storage data has been corrupted.\n"
"Please check it carefully upon next reboot.\n", __func__);
- WARN_ON(1);
- }
/* kobject is already registered */
entry->ready = 2;
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index 5003458980d3..ac6e8e7a02df 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -274,7 +274,7 @@ superio_init(struct pci_dev *pcidev)
else
printk(KERN_ERR PFX "USB regulator not initialized!\n");
- if (request_irq(pdev->irq, superio_interrupt, IRQF_DISABLED,
+ if (request_irq(pdev->irq, superio_interrupt, 0,
SUPERIO, (void *)sio)) {
printk(KERN_ERR PFX "could not get irq\n");
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 0e60438ebe30..24e12d4d1769 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -35,7 +35,7 @@ if PARPORT
config PARPORT_PC
tristate "PC-style hardware"
- depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && \
+ depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && !S390 && \
(!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && !XTENSA
---help---
You should say Y here if you have a PC-style parallel port. All
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index ef6169adb845..1b8bdb7e9bf4 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -63,6 +63,7 @@ enum parport_pc_pci_cards {
timedia_9079b,
timedia_9079c,
wch_ch353_2s1p,
+ sunix_2s1p,
};
/* each element directly indexed from enum list, above */
@@ -148,8 +149,12 @@ static struct parport_pc_pci cards[] = {
/* timedia_9079b */ { 1, { { 2, 3 }, } },
/* timedia_9079c */ { 1, { { 2, 3 }, } },
/* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
+ /* sunix_2s1p */ { 1, { { 3, -1 }, } },
};
+#define PCI_VENDOR_ID_SUNIX 0x1fd4
+#define PCI_DEVICE_ID_SUNIX_1999 0x1999
+
static struct pci_device_id parport_serial_pci_tbl[] = {
/* PCI cards */
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L,
@@ -246,8 +251,18 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
{ 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a },
{ 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b },
{ 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
+
/* WCH CARDS */
{ 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
+
+ /*
+ * More SUNIX variations. At least one of these has part number
+ * '5079A but subdevice 0x102. That board reports 0x0708 as
+ * its PCI Class.
+ */
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
+ 0x0102, 0, 0, sunix_2s1p },
+
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
@@ -470,6 +485,12 @@ static struct pciserial_board pci_parport_serial_boards[] = {
.base_baud = 115200,
.uart_offset = 8,
},
+ [sunix_2s1p] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
};
struct parport_serial_private {
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 3d6d4fd1e3c5..a951c22921d1 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -734,34 +734,24 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
*/
static int acpiphp_bus_add(struct acpiphp_func *func)
{
- acpi_handle phandle;
- struct acpi_device *device, *pdevice;
+ struct acpi_device *device;
int ret_val;
- acpi_get_parent(func->handle, &phandle);
- if (acpi_bus_get_device(phandle, &pdevice)) {
- dbg("no parent device, assuming NULL\n");
- pdevice = NULL;
- }
if (!acpi_bus_get_device(func->handle, &device)) {
dbg("bus exists... trim\n");
/* this shouldn't be in here, so remove
* the bus then re-add it...
*/
- ret_val = acpi_bus_trim(device, 1);
- dbg("acpi_bus_trim return %x\n", ret_val);
+ acpi_bus_trim(device);
}
- ret_val = acpi_bus_add(&device, pdevice, func->handle,
- ACPI_BUS_TYPE_DEVICE);
- if (ret_val) {
- dbg("error adding bus, %x\n",
- -ret_val);
- goto acpiphp_bus_add_out;
- }
- ret_val = acpi_bus_start(device);
+ ret_val = acpi_bus_scan(func->handle);
+ if (!ret_val)
+ ret_val = acpi_bus_get_device(func->handle, &device);
+
+ if (ret_val)
+ dbg("error adding bus, %x\n", -ret_val);
-acpiphp_bus_add_out:
return ret_val;
}
@@ -781,11 +771,8 @@ static int acpiphp_bus_trim(acpi_handle handle)
return retval;
}
- retval = acpi_bus_trim(device, 1);
- if (retval)
- err("cannot remove from acpi list\n");
-
- return retval;
+ acpi_bus_trim(device);
+ return 0;
}
static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
@@ -1130,8 +1117,7 @@ static int acpiphp_configure_bridge (acpi_handle handle)
static void handle_bridge_insertion(acpi_handle handle, u32 type)
{
- struct acpi_device *device, *pdevice;
- acpi_handle phandle;
+ struct acpi_device *device;
if ((type != ACPI_NOTIFY_BUS_CHECK) &&
(type != ACPI_NOTIFY_DEVICE_CHECK)) {
@@ -1139,17 +1125,15 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type)
return;
}
- acpi_get_parent(handle, &phandle);
- if (acpi_bus_get_device(phandle, &pdevice)) {
- dbg("no parent device, assuming NULL\n");
- pdevice = NULL;
- }
- if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) {
+ if (acpi_bus_scan(handle)) {
err("cannot add bridge to acpi list\n");
return;
}
- if (!acpiphp_configure_bridge(handle) &&
- !acpi_bus_start(device))
+ if (acpi_bus_get_device(handle, &device)) {
+ err("ACPI device object missing\n");
+ return;
+ }
+ if (!acpiphp_configure_bridge(handle))
add_bridge(handle);
else
err("cannot configure and start bridge\n");
@@ -1234,6 +1218,8 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
handle = hp_work->handle;
type = hp_work->type;
+ acpi_scan_lock_acquire();
+
if (acpi_bus_get_device(handle, &device)) {
/* This bridge must have just been physically inserted */
handle_bridge_insertion(handle, type);
@@ -1311,6 +1297,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
}
out:
+ acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
}
@@ -1357,6 +1344,8 @@ static void _handle_hotplug_event_func(struct work_struct *work)
func = (struct acpiphp_func *)context;
+ acpi_scan_lock_acquire();
+
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* bus re-enumerate */
@@ -1387,6 +1376,7 @@ static void _handle_hotplug_event_func(struct work_struct *work)
break;
}
+ acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event_func */
}
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c
index dee68e0698e1..7db249a25016 100644
--- a/drivers/pci/hotplug/s390_pci_hpc.c
+++ b/drivers/pci/hotplug/s390_pci_hpc.c
@@ -172,25 +172,6 @@ error:
return -ENOMEM;
}
-static int __init init_pci_slots(void)
-{
- struct zpci_dev *zdev;
- int device = 0;
-
- /*
- * Create a structure for each slot, and register that slot
- * with the pci_hotplug subsystem.
- */
- mutex_lock(&zpci_list_lock);
- list_for_each_entry(zdev, &zpci_list, entry) {
- init_pci_slot(zdev);
- device++;
- }
-
- mutex_unlock(&zpci_list_lock);
- return (device) ? 0 : -ENODEV;
-}
-
static void exit_pci_slot(struct zpci_dev *zdev)
{
struct list_head *tmp, *n;
@@ -205,6 +186,26 @@ static void exit_pci_slot(struct zpci_dev *zdev)
}
}
+static struct pci_hp_callback_ops hp_ops = {
+ .create_slot = init_pci_slot,
+ .remove_slot = exit_pci_slot,
+};
+
+static void __init init_pci_slots(void)
+{
+ struct zpci_dev *zdev;
+
+ /*
+ * Create a structure for each slot, and register that slot
+ * with the pci_hotplug subsystem.
+ */
+ mutex_lock(&zpci_list_lock);
+ list_for_each_entry(zdev, &zpci_list, entry) {
+ init_pci_slot(zdev);
+ }
+ mutex_unlock(&zpci_list_lock);
+}
+
static void __exit exit_pci_slots(void)
{
struct list_head *tmp, *n;
@@ -224,28 +225,19 @@ static void __exit exit_pci_slots(void)
static int __init pci_hotplug_s390_init(void)
{
- /*
- * Do specific initialization stuff for your driver here
- * like initializing your controller hardware (if any) and
- * determining the number of slots you have in the system
- * right now.
- */
-
- if (!pci_probe)
+ if (!s390_pci_probe)
return -EOPNOTSUPP;
- /* register callbacks for slot handling from arch code */
- mutex_lock(&zpci_list_lock);
- hotplug_ops.create_slot = init_pci_slot;
- hotplug_ops.remove_slot = exit_pci_slot;
- mutex_unlock(&zpci_list_lock);
- pr_info("registered hotplug slot callbacks\n");
- return init_pci_slots();
+ zpci_register_hp_ops(&hp_ops);
+ init_pci_slots();
+
+ return 0;
}
static void __exit pci_hotplug_s390_exit(void)
{
exit_pci_slots();
+ zpci_deregister_hp_ops();
}
module_init(pci_hotplug_s390_init);
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index f64ca92253da..574421bc2fa6 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -412,7 +412,6 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
if (SN_ACPI_BASE_SUPPORT() && ssdt) {
unsigned long long adr;
struct acpi_device *pdevice;
- struct acpi_device *device;
acpi_handle phandle;
acpi_handle chandle = NULL;
acpi_handle rethandle;
@@ -426,6 +425,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
pdevice = NULL;
}
+ acpi_scan_lock_acquire();
/*
* Walk the rootbus node's immediate children looking for
* the slot's device node(s). There can be more than
@@ -448,20 +448,18 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
if (ACPI_SUCCESS(ret) &&
(adr>>16) == (slot->device_num + 1)) {
- ret = acpi_bus_add(&device, pdevice, chandle,
- ACPI_BUS_TYPE_DEVICE);
+ ret = acpi_bus_scan(chandle);
if (ACPI_FAILURE(ret)) {
- printk(KERN_ERR "%s: acpi_bus_add "
+ printk(KERN_ERR "%s: acpi_bus_scan "
"failed (0x%x) for slot %d "
"func %d\n", __func__,
ret, (int)(adr>>16),
(int)(adr&0xffff));
/* try to continue on */
- } else {
- acpi_bus_start(device);
}
}
}
+ acpi_scan_lock_release();
}
/* Call the driver for the new device */
@@ -512,6 +510,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
/* Get the rootbus node pointer */
phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+ acpi_scan_lock_acquire();
/*
* Walk the rootbus node's immediate children looking for
* the slot's device node(s). There can be more than
@@ -539,10 +538,10 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
ret = acpi_bus_get_device(chandle,
&device);
if (ACPI_SUCCESS(ret))
- acpi_bus_trim(device, 1);
+ acpi_bus_trim(device);
}
}
-
+ acpi_scan_lock_release();
}
/* Free the SN resources assigned to the Linux device.*/
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 5099636a6e5f..00cc78c7aa04 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -845,6 +845,32 @@ int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
}
EXPORT_SYMBOL(pci_enable_msi_block);
+int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec)
+{
+ int ret, pos, nvec;
+ u16 msgctl;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ if (!pos)
+ return -EINVAL;
+
+ pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+ ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
+
+ if (maxvec)
+ *maxvec = ret;
+
+ do {
+ nvec = ret;
+ ret = pci_enable_msi_block(dev, nvec);
+ } while (ret > 0);
+
+ if (ret < 0)
+ return ret;
+ return nvec;
+}
+EXPORT_SYMBOL(pci_enable_msi_block_auto);
+
void pci_msi_shutdown(struct pci_dev *dev)
{
struct msi_desc *desc;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 1af4008182fd..e407c61559ca 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -283,7 +283,6 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {
.is_manageable = acpi_pci_power_manageable,
.set_state = acpi_pci_set_power_state,
.choose_state = acpi_pci_choose_state,
- .can_wakeup = acpi_pci_can_wakeup,
.sleep_wake = acpi_pci_sleep_wake,
.run_wake = acpi_pci_run_wake,
};
@@ -321,10 +320,65 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle)
return 0;
}
+static void pci_acpi_setup(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ acpi_handle handle = ACPI_HANDLE(dev);
+ struct acpi_device *adev;
+ acpi_status status;
+ acpi_handle dummy;
+
+ /*
+ * Evaluate and parse _PRT, if exists. This code allows parsing of
+ * _PRT objects within the scope of non-bridge devices. Note that
+ * _PRTs within the scope of a PCI bridge assume the bridge's
+ * subordinate bus number.
+ *
+ * TBD: Can _PRTs exist within the scope of non-bridge PCI devices?
+ */
+ status = acpi_get_handle(handle, METHOD_NAME__PRT, &dummy);
+ if (ACPI_SUCCESS(status)) {
+ unsigned char bus;
+
+ bus = pci_dev->subordinate ?
+ pci_dev->subordinate->number : pci_dev->bus->number;
+ acpi_pci_irq_add_prt(handle, pci_domain_nr(pci_dev->bus), bus);
+ }
+
+ if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid)
+ return;
+
+ device_set_wakeup_capable(dev, true);
+ acpi_pci_sleep_wake(pci_dev, false);
+
+ pci_acpi_add_pm_notifier(adev, pci_dev);
+ if (adev->wakeup.flags.run_wake)
+ device_set_run_wake(dev, true);
+}
+
+static void pci_acpi_cleanup(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ acpi_handle handle = ACPI_HANDLE(dev);
+ struct acpi_device *adev;
+
+ if (!acpi_bus_get_device(handle, &adev) && adev->wakeup.flags.valid) {
+ device_set_wakeup_capable(dev, false);
+ device_set_run_wake(dev, false);
+ pci_acpi_remove_pm_notifier(adev);
+ }
+
+ if (pci_dev->subordinate)
+ acpi_pci_irq_del_prt(pci_domain_nr(pci_dev->bus),
+ pci_dev->subordinate->number);
+}
+
static struct acpi_bus_type acpi_pci_bus = {
.bus = &pci_bus_type,
.find_device = acpi_pci_find_device,
.find_bridge = acpi_pci_find_root_bridge,
+ .setup = pci_acpi_setup,
+ .cleanup = pci_acpi_cleanup,
};
static int __init acpi_pci_init(void)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 5cb5820fae40..0c4f641b7be1 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -450,7 +450,7 @@ static struct pci_platform_pm_ops *pci_platform_pm;
int pci_set_platform_pm(struct pci_platform_pm_ops *ops)
{
if (!ops->is_manageable || !ops->set_state || !ops->choose_state
- || !ops->sleep_wake || !ops->can_wakeup)
+ || !ops->sleep_wake)
return -EINVAL;
pci_platform_pm = ops;
return 0;
@@ -473,11 +473,6 @@ static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
}
-static inline bool platform_pci_can_wakeup(struct pci_dev *dev)
-{
- return pci_platform_pm ? pci_platform_pm->can_wakeup(dev) : false;
-}
-
static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
{
return pci_platform_pm ?
@@ -1985,25 +1980,6 @@ void pci_pm_init(struct pci_dev *dev)
}
}
-/**
- * platform_pci_wakeup_init - init platform wakeup if present
- * @dev: PCI device
- *
- * Some devices don't have PCI PM caps but can still generate wakeup
- * events through platform methods (like ACPI events). If @dev supports
- * platform wakeup events, set the device flag to indicate as much. This
- * may be redundant if the device also supports PCI PM caps, but double
- * initialization should be safe in that case.
- */
-void platform_pci_wakeup_init(struct pci_dev *dev)
-{
- if (!platform_pci_can_wakeup(dev))
- return;
-
- device_set_wakeup_capable(&dev->dev, true);
- platform_pci_sleep_wake(dev, false);
-}
-
static void pci_add_saved_cap(struct pci_dev *pci_dev,
struct pci_cap_saved_state *new_cap)
{
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index e8518292826f..adfd172c5b9b 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -43,9 +43,6 @@ int pci_probe_reset_function(struct pci_dev *dev);
* platform; to be used during system-wide transitions from a
* sleeping state to the working state and vice versa
*
- * @can_wakeup: returns 'true' if given device is capable of waking up the
- * system from a sleeping state
- *
* @sleep_wake: enables/disables the system wake up capability of given device
*
* @run_wake: enables/disables the platform to generate run-time wake-up events
@@ -59,7 +56,6 @@ struct pci_platform_pm_ops {
bool (*is_manageable)(struct pci_dev *dev);
int (*set_state)(struct pci_dev *dev, pci_power_t state);
pci_power_t (*choose_state)(struct pci_dev *dev);
- bool (*can_wakeup)(struct pci_dev *dev);
int (*sleep_wake)(struct pci_dev *dev, bool enable);
int (*run_wake)(struct pci_dev *dev, bool enable);
};
@@ -74,7 +70,6 @@ extern void pci_wakeup_bus(struct pci_bus *bus);
extern void pci_config_pm_runtime_get(struct pci_dev *dev);
extern void pci_config_pm_runtime_put(struct pci_dev *dev);
extern void pci_pm_init(struct pci_dev *dev);
-extern void platform_pci_wakeup_init(struct pci_dev *dev);
extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
void pci_free_cap_save_buffers(struct pci_dev *dev);
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c
index 3ea51736f18d..5ab14251839d 100644
--- a/drivers/pci/pcie/aer/aerdrv_errprint.c
+++ b/drivers/pci/pcie/aer/aerdrv_errprint.c
@@ -23,6 +23,9 @@
#include "aerdrv.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/ras.h>
+
#define AER_AGENT_RECEIVER 0
#define AER_AGENT_REQUESTER 1
#define AER_AGENT_COMPLETER 2
@@ -121,12 +124,11 @@ static const char *aer_agent_string[] = {
"Transmitter ID"
};
-static void __aer_print_error(const char *prefix,
+static void __aer_print_error(struct pci_dev *dev,
struct aer_err_info *info)
{
int i, status;
const char *errmsg = NULL;
-
status = (info->status & ~info->mask);
for (i = 0; i < 32; i++) {
@@ -141,26 +143,22 @@ static void __aer_print_error(const char *prefix,
aer_uncorrectable_error_string[i] : NULL;
if (errmsg)
- printk("%s"" [%2d] %-22s%s\n", prefix, i, errmsg,
+ dev_err(&dev->dev, " [%2d] %-22s%s\n", i, errmsg,
info->first_error == i ? " (First)" : "");
else
- printk("%s"" [%2d] Unknown Error Bit%s\n", prefix, i,
- info->first_error == i ? " (First)" : "");
+ dev_err(&dev->dev, " [%2d] Unknown Error Bit%s\n",
+ i, info->first_error == i ? " (First)" : "");
}
}
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
{
int id = ((dev->bus->number << 8) | dev->devfn);
- char prefix[44];
-
- snprintf(prefix, sizeof(prefix), "%s%s %s: ",
- (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR,
- dev_driver_string(&dev->dev), dev_name(&dev->dev));
if (info->status == 0) {
- printk("%s""PCIe Bus Error: severity=%s, type=Unaccessible, "
- "id=%04x(Unregistered Agent ID)\n", prefix,
+ dev_err(&dev->dev,
+ "PCIe Bus Error: severity=%s, type=Unaccessible, "
+ "id=%04x(Unregistered Agent ID)\n",
aer_error_severity_string[info->severity], id);
} else {
int layer, agent;
@@ -168,22 +166,24 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
layer = AER_GET_LAYER_ERROR(info->severity, info->status);
agent = AER_GET_AGENT(info->severity, info->status);
- printk("%s""PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n",
- prefix, aer_error_severity_string[info->severity],
+ dev_err(&dev->dev,
+ "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n",
+ aer_error_severity_string[info->severity],
aer_error_layer[layer], id, aer_agent_string[agent]);
- printk("%s"" device [%04x:%04x] error status/mask=%08x/%08x\n",
- prefix, dev->vendor, dev->device,
+ dev_err(&dev->dev,
+ " device [%04x:%04x] error status/mask=%08x/%08x\n",
+ dev->vendor, dev->device,
info->status, info->mask);
- __aer_print_error(prefix, info);
+ __aer_print_error(dev, info);
if (info->tlp_header_valid) {
unsigned char *tlp = (unsigned char *) &info->tlp;
- printk("%s"" TLP Header:"
+ dev_err(&dev->dev, " TLP Header:"
" %02x%02x%02x%02x %02x%02x%02x%02x"
" %02x%02x%02x%02x %02x%02x%02x%02x\n",
- prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
+ *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
*(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
*(tlp + 11), *(tlp + 10), *(tlp + 9),
*(tlp + 8), *(tlp + 15), *(tlp + 14),
@@ -192,8 +192,11 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
}
if (info->id && info->error_dev_num > 1 && info->id == id)
- printk("%s"" Error of this Agent(%04x) is reported first\n",
- prefix, id);
+ dev_err(&dev->dev,
+ " Error of this Agent(%04x) is reported first\n",
+ id);
+ trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
+ info->severity);
}
void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
@@ -217,7 +220,7 @@ int cper_severity_to_aer(int cper_severity)
}
EXPORT_SYMBOL_GPL(cper_severity_to_aer);
-void cper_print_aer(const char *prefix, int cper_severity,
+void cper_print_aer(const char *prefix, struct pci_dev *dev, int cper_severity,
struct aer_capability_regs *aer)
{
int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0;
@@ -239,25 +242,27 @@ void cper_print_aer(const char *prefix, int cper_severity,
}
layer = AER_GET_LAYER_ERROR(aer_severity, status);
agent = AER_GET_AGENT(aer_severity, status);
- printk("%s""aer_status: 0x%08x, aer_mask: 0x%08x\n",
- prefix, status, mask);
+ dev_err(&dev->dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n",
+ status, mask);
cper_print_bits(prefix, status, status_strs, status_strs_size);
- printk("%s""aer_layer=%s, aer_agent=%s\n", prefix,
+ dev_err(&dev->dev, "aer_layer=%s, aer_agent=%s\n",
aer_error_layer[layer], aer_agent_string[agent]);
if (aer_severity != AER_CORRECTABLE)
- printk("%s""aer_uncor_severity: 0x%08x\n",
- prefix, aer->uncor_severity);
+ dev_err(&dev->dev, "aer_uncor_severity: 0x%08x\n",
+ aer->uncor_severity);
if (tlp_header_valid) {
const unsigned char *tlp;
tlp = (const unsigned char *)&aer->header_log;
- printk("%s""aer_tlp_header:"
+ dev_err(&dev->dev, "aer_tlp_header:"
" %02x%02x%02x%02x %02x%02x%02x%02x"
" %02x%02x%02x%02x %02x%02x%02x%02x\n",
- prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
+ *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
*(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
*(tlp + 11), *(tlp + 10), *(tlp + 9),
*(tlp + 8), *(tlp + 15), *(tlp + 14),
*(tlp + 13), *(tlp + 12));
}
+ trace_aer_event(dev_name(&dev->dev), (status & ~mask),
+ aer_severity);
}
#endif
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6186f03d84f3..2dcd22d9c816 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1280,7 +1280,6 @@ static void pci_init_capabilities(struct pci_dev *dev)
/* Power Management */
pci_pm_init(dev);
- platform_pci_wakeup_init(dev);
/* Vital Product Data */
pci_vpd_pci22_init(dev);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 7c0fd9252e6f..84954a726a94 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -19,6 +19,8 @@ static void pci_free_resources(struct pci_dev *dev)
static void pci_stop_dev(struct pci_dev *dev)
{
+ pci_pme_active(dev, false);
+
if (dev->is_added) {
pci_proc_detach_device(dev);
pci_remove_sysfs_dev_files(dev);
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 8fd255f7ee40..b90f85bf5f81 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -36,8 +36,8 @@ config PCMCIA
If unsure, say Y.
config PCMCIA_LOAD_CIS
- bool "Load CIS updates from userspace (EXPERIMENTAL)"
- depends on PCMCIA && EXPERIMENTAL
+ bool "Load CIS updates from userspace"
+ depends on PCMCIA
select FW_LOADER
default y
help
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 673c14ea11e3..5292db69c426 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -484,7 +484,7 @@ static int socket_early_resume(struct pcmcia_socket *skt)
static int socket_late_resume(struct pcmcia_socket *skt)
{
- int ret;
+ int ret = 0;
mutex_lock(&skt->ops_mutex);
skt->state &= ~SOCKET_SUSPEND;
@@ -511,19 +511,31 @@ static int socket_late_resume(struct pcmcia_socket *skt)
return socket_insert(skt);
}
+ if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
+ ret = skt->callback->early_resume(skt);
+ return ret;
+}
+
+/*
+ * Finalize the resume. In case of a cardbus socket, we have
+ * to rebind the devices as we can't be certain that it has been
+ * replaced, or not.
+ */
+static int socket_complete_resume(struct pcmcia_socket *skt)
+{
+ int ret = 0;
#ifdef CONFIG_CARDBUS
if (skt->state & SOCKET_CARDBUS) {
/* We can't be sure the CardBus card is the same
* as the one previously inserted. Therefore, remove
* and re-add... */
cb_free(skt);
- cb_alloc(skt);
- return 0;
+ ret = cb_alloc(skt);
+ if (ret)
+ cb_free(skt);
}
#endif
- if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
- skt->callback->early_resume(skt);
- return 0;
+ return ret;
}
/*
@@ -533,11 +545,15 @@ static int socket_late_resume(struct pcmcia_socket *skt)
*/
static int socket_resume(struct pcmcia_socket *skt)
{
+ int err;
if (!(skt->state & SOCKET_SUSPEND))
return -EBUSY;
socket_early_resume(skt);
- return socket_late_resume(skt);
+ err = socket_late_resume(skt);
+ if (!err)
+ err = socket_complete_resume(skt);
+ return err;
}
static void socket_remove(struct pcmcia_socket *skt)
@@ -848,6 +864,12 @@ static int __used pcmcia_socket_dev_resume(struct device *dev)
return __pcmcia_pm_op(dev, socket_late_resume);
}
+static void __used pcmcia_socket_dev_complete(struct device *dev)
+{
+ WARN(__pcmcia_pm_op(dev, socket_complete_resume),
+ "failed to complete resume");
+}
+
static const struct dev_pm_ops pcmcia_socket_pm_ops = {
/* dev_resume may be called with IRQs enabled */
SET_SYSTEM_SLEEP_PM_OPS(NULL,
@@ -862,6 +884,7 @@ static const struct dev_pm_ops pcmcia_socket_pm_ops = {
.resume_noirq = pcmcia_socket_dev_resume_noirq,
.thaw_noirq = pcmcia_socket_dev_resume_noirq,
.restore_noirq = pcmcia_socket_dev_resume_noirq,
+ .complete = pcmcia_socket_dev_complete,
};
#define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops)
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index 3578e1ca97a0..519c4d6003a6 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -133,8 +133,6 @@ static int i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *i
goto err_out_free_res;
}
- pci_set_drvdata(dev, &sockets[i].socket);
-
for (i = 0; i<socket_count; i++) {
sockets[i].socket.dev.parent = &dev->dev;
sockets[i].socket.ops = &i82092aa_operations;
@@ -164,14 +162,14 @@ err_out_disable:
static void i82092aa_pci_remove(struct pci_dev *dev)
{
- struct pcmcia_socket *socket = pci_get_drvdata(dev);
+ int i;
enter("i82092aa_pci_remove");
free_irq(dev->irq, i82092aa_interrupt);
- if (socket)
- pcmcia_unregister_socket(socket);
+ for (i = 0; i < socket_count; i++)
+ pcmcia_unregister_socket(&sockets[i].socket);
leave("i82092aa_pci_remove");
}
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 430a9ac56091..065704c605d5 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -369,12 +369,12 @@ static int do_validate_mem(struct pcmcia_socket *s,
}
}
- free_region(res2);
- free_region(res1);
-
dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u",
base, base+size-1, res1, res2, ret, info1, info2);
+ free_region(res2);
+ free_region(res1);
+
if ((ret) || (info1 != info2) || (info1 == 0))
return -EINVAL;
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index 75806be344e5..d98a08612492 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -246,6 +246,7 @@ static int pccard_init(struct pcmcia_socket *sock)
socket = &vrc4171_sockets[slot];
socket->csc_irq = search_nonuse_irq();
socket->io_irq = search_nonuse_irq();
+ spin_lock_init(&socket->lock);
return 0;
}
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index efaecefe3f8c..34f51d2d90d2 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -26,6 +26,29 @@ config DEBUG_PINCTRL
help
Say Y here to add some extra checks and diagnostics to PINCTRL calls.
+config PINCTRL_ABX500
+ bool "ST-Ericsson ABx500 family Mixed Signal Circuit gpio functions"
+ depends on AB8500_CORE
+ select GENERIC_PINCONF
+ help
+ Select this to enable the ABx500 family IC GPIO driver
+
+config PINCTRL_AB8500
+ bool "AB8500 pin controller driver"
+ depends on PINCTRL_ABX500 && ARCH_U8500
+
+config PINCTRL_AB8540
+ bool "AB8540 pin controller driver"
+ depends on PINCTRL_ABX500 && ARCH_U8500
+
+config PINCTRL_AB9540
+ bool "AB9540 pin controller driver"
+ depends on PINCTRL_ABX500 && ARCH_U8500
+
+config PINCTRL_AB8505
+ bool "AB8505 pin controller driver"
+ depends on PINCTRL_ABX500 && ARCH_U8500
+
config PINCTRL_AT91
bool "AT91 pinctrl driver"
depends on OF
@@ -151,6 +174,11 @@ config PINCTRL_SIRF
depends on ARCH_SIRF
select PINMUX
+config PINCTRL_SUNXI
+ bool
+ select PINMUX
+ select GENERIC_PINCONF
+
config PINCTRL_TEGRA
bool
select PINMUX
@@ -164,6 +192,10 @@ config PINCTRL_TEGRA30
bool
select PINCTRL_TEGRA
+config PINCTRL_TEGRA114
+ bool
+ select PINCTRL_TEGRA
+
config PINCTRL_U300
bool "U300 pin controller driver"
depends on ARCH_U300
@@ -184,8 +216,8 @@ config PINCTRL_SAMSUNG
select PINMUX
select PINCONF
-config PINCTRL_EXYNOS4
- bool "Pinctrl driver data for Exynos4 SoC"
+config PINCTRL_EXYNOS
+ bool "Pinctrl driver data for Samsung EXYNOS SoCs"
depends on OF && GPIOLIB
select PINCTRL_SAMSUNG
@@ -195,7 +227,7 @@ config PINCTRL_EXYNOS5440
select PINCONF
source "drivers/pinctrl/mvebu/Kconfig"
-
+source "drivers/pinctrl/sh-pfc/Kconfig"
source "drivers/pinctrl/spear/Kconfig"
config PINCTRL_XWAY
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index fc4606f27dc7..f82cc5baf767 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -9,6 +9,11 @@ ifeq ($(CONFIG_OF),y)
obj-$(CONFIG_PINCTRL) += devicetree.o
endif
obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
+obj-$(CONFIG_PINCTRL_ABX500) += pinctrl-abx500.o
+obj-$(CONFIG_PINCTRL_AB8500) += pinctrl-ab8500.o
+obj-$(CONFIG_PINCTRL_AB8540) += pinctrl-ab8540.o
+obj-$(CONFIG_PINCTRL_AB9540) += pinctrl-ab9540.o
+obj-$(CONFIG_PINCTRL_AB8505) += pinctrl-ab8505.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
@@ -30,16 +35,20 @@ obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o
obj-$(CONFIG_PINCTRL_PXA910) += pinctrl-pxa910.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o
+obj-$(CONFIG_PINCTRL_SUNXI) += pinctrl-sunxi.o
obj-$(CONFIG_PINCTRL_TEGRA) += pinctrl-tegra.o
obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
+obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o
obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o
-obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o
+obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o
obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.o
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
obj-$(CONFIG_PLAT_ORION) += mvebu/
+obj-$(CONFIG_ARCH_SHMOBILE) += sh-pfc/
+obj-$(CONFIG_SUPERH) += sh-pfc/
obj-$(CONFIG_PLAT_SPEAR) += spear/
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 59f5a965bdc4..b0de6e7f1fdb 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -14,6 +14,7 @@
#define pr_fmt(fmt) "pinctrl core: " fmt
#include <linux/kernel.h>
+#include <linux/kref.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/device.h>
@@ -31,17 +32,6 @@
#include "pinmux.h"
#include "pinconf.h"
-/**
- * struct pinctrl_maps - a list item containing part of the mapping table
- * @node: mapping table list node
- * @maps: array of mapping table entries
- * @num_maps: the number of entries in @maps
- */
-struct pinctrl_maps {
- struct list_head node;
- struct pinctrl_map const *maps;
- unsigned num_maps;
-};
static bool pinctrl_dummy_state;
@@ -55,13 +45,8 @@ LIST_HEAD(pinctrldev_list);
static LIST_HEAD(pinctrl_list);
/* List of pinctrl maps (struct pinctrl_maps) */
-static LIST_HEAD(pinctrl_maps);
+LIST_HEAD(pinctrl_maps);
-#define for_each_maps(_maps_node_, _i_, _map_) \
- list_for_each_entry(_maps_node_, &pinctrl_maps, node) \
- for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \
- _i_ < _maps_node_->num_maps; \
- _i_++, _map_ = &_maps_node_->maps[_i_])
/**
* pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support
@@ -83,6 +68,12 @@ const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev)
}
EXPORT_SYMBOL_GPL(pinctrl_dev_get_name);
+const char *pinctrl_dev_get_devname(struct pinctrl_dev *pctldev)
+{
+ return dev_name(pctldev->dev);
+}
+EXPORT_SYMBOL_GPL(pinctrl_dev_get_devname);
+
void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev)
{
return pctldev->driver_data;
@@ -609,13 +600,16 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
if (setting->pctldev == NULL) {
- dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
- map->ctrl_dev_name);
kfree(setting);
+ /* Do not defer probing of hogs (circular loop) */
+ if (!strcmp(map->ctrl_dev_name, map->dev_name))
+ return -ENODEV;
/*
* OK let us guess that the driver is not there yet, and
* let's defer obtaining this pinctrl handle to later...
*/
+ dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
+ map->ctrl_dev_name);
return -EPROBE_DEFER;
}
@@ -694,11 +688,31 @@ static struct pinctrl *create_pinctrl(struct device *dev)
continue;
ret = add_setting(p, map);
- if (ret < 0) {
+ /*
+ * At this point the adding of a setting may:
+ *
+ * - Defer, if the pinctrl device is not yet available
+ * - Fail, if the pinctrl device is not yet available,
+ * AND the setting is a hog. We cannot defer that, since
+ * the hog will kick in immediately after the device
+ * is registered.
+ *
+ * If the error returned was not -EPROBE_DEFER then we
+ * accumulate the errors to see if we end up with
+ * an -EPROBE_DEFER later, as that is the worst case.
+ */
+ if (ret == -EPROBE_DEFER) {
pinctrl_put_locked(p, false);
return ERR_PTR(ret);
}
}
+ if (ret < 0) {
+ /* If some other error than deferral occured, return here */
+ pinctrl_put_locked(p, false);
+ return ERR_PTR(ret);
+ }
+
+ kref_init(&p->users);
/* Add the pinctrl handle to the global list */
list_add_tail(&p->node, &pinctrl_list);
@@ -713,9 +727,17 @@ static struct pinctrl *pinctrl_get_locked(struct device *dev)
if (WARN_ON(!dev))
return ERR_PTR(-EINVAL);
+ /*
+ * See if somebody else (such as the device core) has already
+ * obtained a handle to the pinctrl for this device. In that case,
+ * return another pointer to it.
+ */
p = find_pinctrl(dev);
- if (p != NULL)
- return ERR_PTR(-EBUSY);
+ if (p != NULL) {
+ dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n");
+ kref_get(&p->users);
+ return p;
+ }
return create_pinctrl(dev);
}
@@ -771,13 +793,24 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
}
/**
- * pinctrl_put() - release a previously claimed pinctrl handle
+ * pinctrl_release() - release the pinctrl handle
+ * @kref: the kref in the pinctrl being released
+ */
+static void pinctrl_release(struct kref *kref)
+{
+ struct pinctrl *p = container_of(kref, struct pinctrl, users);
+
+ pinctrl_put_locked(p, true);
+}
+
+/**
+ * pinctrl_put() - decrease use count on a previously claimed pinctrl handle
* @p: the pinctrl handle to release
*/
void pinctrl_put(struct pinctrl *p)
{
mutex_lock(&pinctrl_mutex);
- pinctrl_put_locked(p, true);
+ kref_put(&p->users, pinctrl_release);
mutex_unlock(&pinctrl_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_put);
@@ -1055,6 +1088,30 @@ void pinctrl_unregister_map(struct pinctrl_map const *map)
}
}
+/**
+ * pinctrl_force_sleep() - turn a given controller device into sleep state
+ * @pctldev: pin controller device
+ */
+int pinctrl_force_sleep(struct pinctrl_dev *pctldev)
+{
+ if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_sleep))
+ return pinctrl_select_state(pctldev->p, pctldev->hog_sleep);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_force_sleep);
+
+/**
+ * pinctrl_force_default() - turn a given controller device into default state
+ * @pctldev: pin controller device
+ */
+int pinctrl_force_default(struct pinctrl_dev *pctldev)
+{
+ if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_default))
+ return pinctrl_select_state(pctldev->p, pctldev->hog_default);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_force_default);
+
#ifdef CONFIG_DEBUG_FS
static int pinctrl_pins_show(struct seq_file *s, void *what)
@@ -1500,16 +1557,23 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
pctldev->p = pinctrl_get_locked(pctldev->dev);
if (!IS_ERR(pctldev->p)) {
- struct pinctrl_state *s =
+ pctldev->hog_default =
pinctrl_lookup_state_locked(pctldev->p,
PINCTRL_STATE_DEFAULT);
- if (IS_ERR(s)) {
+ if (IS_ERR(pctldev->hog_default)) {
dev_dbg(dev, "failed to lookup the default state\n");
} else {
- if (pinctrl_select_state_locked(pctldev->p, s))
+ if (pinctrl_select_state_locked(pctldev->p,
+ pctldev->hog_default))
dev_err(dev,
"failed to select default state\n");
}
+
+ pctldev->hog_sleep =
+ pinctrl_lookup_state_locked(pctldev->p,
+ PINCTRL_STATE_SLEEP);
+ if (IS_ERR(pctldev->hog_sleep))
+ dev_dbg(dev, "failed to lookup the sleep state\n");
}
mutex_unlock(&pinctrl_mutex);
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index 12f5694f3d5d..ee72f1f6d862 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -9,6 +9,7 @@
* License terms: GNU General Public License (GPL) version 2
*/
+#include <linux/kref.h>
#include <linux/mutex.h>
#include <linux/radix-tree.h>
#include <linux/pinctrl/pinconf.h>
@@ -30,6 +31,8 @@ struct pinctrl_gpio_range;
* @driver_data: driver data for drivers registering to the pin controller
* subsystem
* @p: result of pinctrl_get() for this device
+ * @hog_default: default state for pins hogged by this device
+ * @hog_sleep: sleep state for pins hogged by this device
* @device_root: debugfs root for this device
*/
struct pinctrl_dev {
@@ -41,6 +44,8 @@ struct pinctrl_dev {
struct module *owner;
void *driver_data;
struct pinctrl *p;
+ struct pinctrl_state *hog_default;
+ struct pinctrl_state *hog_sleep;
#ifdef CONFIG_DEBUG_FS
struct dentry *device_root;
#endif
@@ -54,6 +59,7 @@ struct pinctrl_dev {
* @state: the current state
* @dt_maps: the mapping table chunks dynamically parsed from device tree for
* this device, if any
+ * @users: reference count
*/
struct pinctrl {
struct list_head node;
@@ -61,6 +67,7 @@ struct pinctrl {
struct list_head states;
struct pinctrl_state *state;
struct list_head dt_maps;
+ struct kref users;
};
/**
@@ -148,6 +155,18 @@ struct pin_desc {
#endif
};
+/**
+ * struct pinctrl_maps - a list item containing part of the mapping table
+ * @node: mapping table list node
+ * @maps: array of mapping table entries
+ * @num_maps: the number of entries in @maps
+ */
+struct pinctrl_maps {
+ struct list_head node;
+ struct pinctrl_map const *maps;
+ unsigned num_maps;
+};
+
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
@@ -164,5 +183,15 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
bool dup, bool locked);
void pinctrl_unregister_map(struct pinctrl_map const *map);
+extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev);
+extern int pinctrl_force_default(struct pinctrl_dev *pctldev);
+
extern struct mutex pinctrl_mutex;
extern struct list_head pinctrldev_list;
+extern struct list_head pinctrl_maps;
+
+#define for_each_maps(_maps_node_, _i_, _map_) \
+ list_for_each_entry(_maps_node_, &pinctrl_maps, node) \
+ for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \
+ _i_ < _maps_node_->num_maps; \
+ _i_++, _map_ = &_maps_node_->maps[_i_])
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index fe2d1af7cfa0..fd40a11ad645 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -141,6 +141,11 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
pctldev = find_pinctrl_by_of_node(np_pctldev);
if (pctldev)
break;
+ /* Do not defer probing of hogs (circular loop) */
+ if (np_pctldev == p->dev->of_node) {
+ of_node_put(np_pctldev);
+ return -ENODEV;
+ }
}
of_node_put(np_pctldev);
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 833a36458157..06c304ac6f7d 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -41,11 +41,13 @@ struct pin_config_item conf_items[] = {
PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
- PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_DISABLE, "input schmitt disabled", NULL),
+ PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL),
PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"),
PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"),
+ PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL),
PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"),
+ PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level"),
};
void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index baee2cc46a17..ac8d382a79bb 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -574,6 +574,207 @@ static const struct file_operations pinconf_groups_ops = {
.release = single_release,
};
+/* 32bit read/write ressources */
+#define MAX_NAME_LEN 16
+char dbg_pinname[MAX_NAME_LEN]; /* shared: name of the state of the pin*/
+char dbg_state_name[MAX_NAME_LEN]; /* shared: state of the pin*/
+static u32 dbg_config; /* shared: config to be read/set for the pin & state*/
+
+static int pinconf_dbg_pinname_print(struct seq_file *s, void *d)
+{
+ if (strlen(dbg_pinname))
+ seq_printf(s, "%s\n", dbg_pinname);
+ else
+ seq_printf(s, "No pin name set\n");
+ return 0;
+}
+
+static int pinconf_dbg_pinname_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinconf_dbg_pinname_print, inode->i_private);
+}
+
+static int pinconf_dbg_pinname_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ int err;
+
+ if (count > MAX_NAME_LEN)
+ return -EINVAL;
+
+ err = sscanf(user_buf, "%15s", dbg_pinname);
+
+ if (err != 1)
+ return -EINVAL;
+
+ return count;
+}
+
+static const struct file_operations pinconf_dbg_pinname_fops = {
+ .open = pinconf_dbg_pinname_open,
+ .write = pinconf_dbg_pinname_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int pinconf_dbg_state_print(struct seq_file *s, void *d)
+{
+ if (strlen(dbg_state_name))
+ seq_printf(s, "%s\n", dbg_pinname);
+ else
+ seq_printf(s, "No pin state set\n");
+ return 0;
+}
+
+static int pinconf_dbg_state_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinconf_dbg_state_print, inode->i_private);
+}
+
+static int pinconf_dbg_state_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ int err;
+
+ if (count > MAX_NAME_LEN)
+ return -EINVAL;
+
+ err = sscanf(user_buf, "%15s", dbg_state_name);
+
+ if (err != 1)
+ return -EINVAL;
+
+ return count;
+}
+
+static const struct file_operations pinconf_dbg_pinstate_fops = {
+ .open = pinconf_dbg_state_open,
+ .write = pinconf_dbg_state_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+/**
+ * pinconf_dbg_config_print() - display the pinctrl config from the pinctrl
+ * map, of a pin/state pair based on pinname and state that have been
+ * selected with the debugfs entries pinconf-name and pinconf-state
+ * @s: contains the 32bits config to be written
+ * @d: not used
+ */
+static int pinconf_dbg_config_print(struct seq_file *s, void *d)
+{
+ struct pinctrl_maps *maps_node;
+ struct pinctrl_map const *map;
+ struct pinctrl_dev *pctldev = NULL;
+ struct pinconf_ops *confops = NULL;
+ int i, j;
+ bool found = false;
+
+ mutex_lock(&pinctrl_mutex);
+
+ /* Parse the pinctrl map and look for the elected pin/state */
+ for_each_maps(maps_node, i, map) {
+ if (map->type != PIN_MAP_TYPE_CONFIGS_PIN)
+ continue;
+
+ if (strncmp(map->name, dbg_state_name, MAX_NAME_LEN) > 0)
+ continue;
+
+ for (j = 0; j < map->data.configs.num_configs; j++) {
+ if (0 == strncmp(map->data.configs.group_or_pin,
+ dbg_pinname, MAX_NAME_LEN)) {
+ /* We found the right pin / state, read the
+ * config and store the pctldev */
+ dbg_config = map->data.configs.configs[j];
+ pctldev = get_pinctrl_dev_from_devname
+ (map->ctrl_dev_name);
+ found = true;
+ break;
+ }
+ }
+ }
+
+ mutex_unlock(&pinctrl_mutex);
+
+ if (found) {
+ seq_printf(s, "Config of %s in state %s: 0x%08X\n", dbg_pinname,
+ dbg_state_name, dbg_config);
+
+ if (pctldev)
+ confops = pctldev->desc->confops;
+
+ if (confops && confops->pin_config_config_dbg_show)
+ confops->pin_config_config_dbg_show(pctldev,
+ s, dbg_config);
+ } else {
+ seq_printf(s, "No pin found for defined name/state\n");
+ }
+
+ return 0;
+}
+
+static int pinconf_dbg_config_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinconf_dbg_config_print, inode->i_private);
+}
+
+/**
+ * pinconf_dbg_config_write() - overwrite the pinctrl config in thepinctrl
+ * map, of a pin/state pair based on pinname and state that have been
+ * selected with the debugfs entries pinconf-name and pinconf-state
+ */
+static int pinconf_dbg_config_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ int err;
+ unsigned long config;
+ struct pinctrl_maps *maps_node;
+ struct pinctrl_map const *map;
+ int i, j;
+
+ err = kstrtoul_from_user(user_buf, count, 0, &config);
+
+ if (err)
+ return err;
+
+ dbg_config = config;
+
+ mutex_lock(&pinctrl_mutex);
+
+ /* Parse the pinctrl map and look for the selected pin/state */
+ for_each_maps(maps_node, i, map) {
+ if (map->type != PIN_MAP_TYPE_CONFIGS_PIN)
+ continue;
+
+ if (strncmp(map->name, dbg_state_name, MAX_NAME_LEN) > 0)
+ continue;
+
+ /* we found the right pin / state, so overwrite config */
+ for (j = 0; j < map->data.configs.num_configs; j++) {
+ if (strncmp(map->data.configs.group_or_pin, dbg_pinname,
+ MAX_NAME_LEN) == 0)
+ map->data.configs.configs[j] = dbg_config;
+ }
+ }
+
+ mutex_unlock(&pinctrl_mutex);
+
+ return count;
+}
+
+static const struct file_operations pinconf_dbg_pinconfig_fops = {
+ .open = pinconf_dbg_config_open,
+ .write = pinconf_dbg_config_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
void pinconf_init_device_debugfs(struct dentry *devroot,
struct pinctrl_dev *pctldev)
{
@@ -581,6 +782,12 @@ void pinconf_init_device_debugfs(struct dentry *devroot,
devroot, pctldev, &pinconf_pins_ops);
debugfs_create_file("pinconf-groups", S_IFREG | S_IRUGO,
devroot, pctldev, &pinconf_groups_ops);
+ debugfs_create_file("pinconf-name", (S_IRUGO | S_IWUSR | S_IWGRP),
+ devroot, pctldev, &pinconf_dbg_pinname_fops);
+ debugfs_create_file("pinconf-state", (S_IRUGO | S_IWUSR | S_IWGRP),
+ devroot, pctldev, &pinconf_dbg_pinstate_fops);
+ debugfs_create_file("pinconf-config", (S_IRUGO | S_IWUSR | S_IWGRP),
+ devroot, pctldev, &pinconf_dbg_pinconfig_fops);
}
#endif
diff --git a/drivers/pinctrl/pinctrl-ab8500.c b/drivers/pinctrl/pinctrl-ab8500.c
new file mode 100644
index 000000000000..3b471d87c211
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ab8500.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
+ *
+ * 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/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include "pinctrl-abx500.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define ABX500_GPIO(offset) (offset)
+
+#define AB8500_PIN_T10 ABX500_GPIO(1)
+#define AB8500_PIN_T9 ABX500_GPIO(2)
+#define AB8500_PIN_U9 ABX500_GPIO(3)
+#define AB8500_PIN_W2 ABX500_GPIO(4)
+/* hole */
+#define AB8500_PIN_Y18 ABX500_GPIO(6)
+#define AB8500_PIN_AA20 ABX500_GPIO(7)
+#define AB8500_PIN_W18 ABX500_GPIO(8)
+#define AB8500_PIN_AA19 ABX500_GPIO(9)
+#define AB8500_PIN_U17 ABX500_GPIO(10)
+#define AB8500_PIN_AA18 ABX500_GPIO(11)
+#define AB8500_PIN_U16 ABX500_GPIO(12)
+#define AB8500_PIN_W17 ABX500_GPIO(13)
+#define AB8500_PIN_F14 ABX500_GPIO(14)
+#define AB8500_PIN_B17 ABX500_GPIO(15)
+#define AB8500_PIN_F15 ABX500_GPIO(16)
+#define AB8500_PIN_P5 ABX500_GPIO(17)
+#define AB8500_PIN_R5 ABX500_GPIO(18)
+#define AB8500_PIN_U5 ABX500_GPIO(19)
+#define AB8500_PIN_T5 ABX500_GPIO(20)
+#define AB8500_PIN_H19 ABX500_GPIO(21)
+#define AB8500_PIN_G20 ABX500_GPIO(22)
+#define AB8500_PIN_G19 ABX500_GPIO(23)
+#define AB8500_PIN_T14 ABX500_GPIO(24)
+#define AB8500_PIN_R16 ABX500_GPIO(25)
+#define AB8500_PIN_M16 ABX500_GPIO(26)
+#define AB8500_PIN_J6 ABX500_GPIO(27)
+#define AB8500_PIN_K6 ABX500_GPIO(28)
+#define AB8500_PIN_G6 ABX500_GPIO(29)
+#define AB8500_PIN_H6 ABX500_GPIO(30)
+#define AB8500_PIN_F5 ABX500_GPIO(31)
+#define AB8500_PIN_G5 ABX500_GPIO(32)
+/* hole */
+#define AB8500_PIN_R17 ABX500_GPIO(34)
+#define AB8500_PIN_W15 ABX500_GPIO(35)
+#define AB8500_PIN_A17 ABX500_GPIO(36)
+#define AB8500_PIN_E15 ABX500_GPIO(37)
+#define AB8500_PIN_C17 ABX500_GPIO(38)
+#define AB8500_PIN_E16 ABX500_GPIO(39)
+#define AB8500_PIN_T19 ABX500_GPIO(40)
+#define AB8500_PIN_U19 ABX500_GPIO(41)
+#define AB8500_PIN_U2 ABX500_GPIO(42)
+
+/* indicates the highest GPIO number */
+#define AB8500_GPIO_MAX_NUMBER 42
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc ab8500_pins[] = {
+ PINCTRL_PIN(AB8500_PIN_T10, "GPIO1_T10"),
+ PINCTRL_PIN(AB8500_PIN_T9, "GPIO2_T9"),
+ PINCTRL_PIN(AB8500_PIN_U9, "GPIO3_U9"),
+ PINCTRL_PIN(AB8500_PIN_W2, "GPIO4_W2"),
+ /* hole */
+ PINCTRL_PIN(AB8500_PIN_Y18, "GPIO6_Y18"),
+ PINCTRL_PIN(AB8500_PIN_AA20, "GPIO7_AA20"),
+ PINCTRL_PIN(AB8500_PIN_W18, "GPIO8_W18"),
+ PINCTRL_PIN(AB8500_PIN_AA19, "GPIO9_AA19"),
+ PINCTRL_PIN(AB8500_PIN_U17, "GPIO10_U17"),
+ PINCTRL_PIN(AB8500_PIN_AA18, "GPIO11_AA18"),
+ PINCTRL_PIN(AB8500_PIN_U16, "GPIO12_U16"),
+ PINCTRL_PIN(AB8500_PIN_W17, "GPIO13_W17"),
+ PINCTRL_PIN(AB8500_PIN_F14, "GPIO14_F14"),
+ PINCTRL_PIN(AB8500_PIN_B17, "GPIO15_B17"),
+ PINCTRL_PIN(AB8500_PIN_F15, "GPIO16_F15"),
+ PINCTRL_PIN(AB8500_PIN_P5, "GPIO17_P5"),
+ PINCTRL_PIN(AB8500_PIN_R5, "GPIO18_R5"),
+ PINCTRL_PIN(AB8500_PIN_U5, "GPIO19_U5"),
+ PINCTRL_PIN(AB8500_PIN_T5, "GPIO20_T5"),
+ PINCTRL_PIN(AB8500_PIN_H19, "GPIO21_H19"),
+ PINCTRL_PIN(AB8500_PIN_G20, "GPIO22_G20"),
+ PINCTRL_PIN(AB8500_PIN_G19, "GPIO23_G19"),
+ PINCTRL_PIN(AB8500_PIN_T14, "GPIO24_T14"),
+ PINCTRL_PIN(AB8500_PIN_R16, "GPIO25_R16"),
+ PINCTRL_PIN(AB8500_PIN_M16, "GPIO26_M16"),
+ PINCTRL_PIN(AB8500_PIN_J6, "GPIO27_J6"),
+ PINCTRL_PIN(AB8500_PIN_K6, "GPIO28_K6"),
+ PINCTRL_PIN(AB8500_PIN_G6, "GPIO29_G6"),
+ PINCTRL_PIN(AB8500_PIN_H6, "GPIO30_H6"),
+ PINCTRL_PIN(AB8500_PIN_F5, "GPIO31_F5"),
+ PINCTRL_PIN(AB8500_PIN_G5, "GPIO32_G5"),
+ /* hole */
+ PINCTRL_PIN(AB8500_PIN_R17, "GPIO34_R17"),
+ PINCTRL_PIN(AB8500_PIN_W15, "GPIO35_W15"),
+ PINCTRL_PIN(AB8500_PIN_A17, "GPIO36_A17"),
+ PINCTRL_PIN(AB8500_PIN_E15, "GPIO37_E15"),
+ PINCTRL_PIN(AB8500_PIN_C17, "GPIO38_C17"),
+ PINCTRL_PIN(AB8500_PIN_E16, "GPIO39_E16"),
+ PINCTRL_PIN(AB8500_PIN_T19, "GPIO40_T19"),
+ PINCTRL_PIN(AB8500_PIN_U19, "GPIO41_U19"),
+ PINCTRL_PIN(AB8500_PIN_U2, "GPIO42_U2"),
+};
+
+/*
+ * Maps local GPIO offsets to local pin numbers
+ */
+static const struct abx500_pinrange ab8500_pinranges[] = {
+ ABX500_PINRANGE(1, 4, ABX500_ALT_A),
+ ABX500_PINRANGE(6, 4, ABX500_ALT_A),
+ ABX500_PINRANGE(10, 4, ABX500_DEFAULT),
+ ABX500_PINRANGE(14, 12, ABX500_ALT_A),
+ ABX500_PINRANGE(26, 1, ABX500_DEFAULT),
+ ABX500_PINRANGE(27, 6, ABX500_ALT_A),
+ ABX500_PINRANGE(34, 1, ABX500_ALT_A),
+ ABX500_PINRANGE(35, 1, ABX500_DEFAULT),
+ ABX500_PINRANGE(36, 7, ABX500_ALT_A),
+};
+
+/*
+ * Read the pin group names like this:
+ * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* default column */
+static const unsigned sysclkreq2_d_1_pins[] = { AB8500_PIN_T10 };
+static const unsigned sysclkreq3_d_1_pins[] = { AB8500_PIN_T9 };
+static const unsigned sysclkreq4_d_1_pins[] = { AB8500_PIN_U9 };
+static const unsigned sysclkreq6_d_1_pins[] = { AB8500_PIN_W2 };
+static const unsigned ycbcr0123_d_1_pins[] = { AB8500_PIN_Y18, AB8500_PIN_AA20,
+ AB8500_PIN_W18, AB8500_PIN_AA19};
+static const unsigned gpio10_d_1_pins[] = { AB8500_PIN_U17 };
+static const unsigned gpio11_d_1_pins[] = { AB8500_PIN_AA18 };
+static const unsigned gpio12_d_1_pins[] = { AB8500_PIN_U16 };
+static const unsigned gpio13_d_1_pins[] = { AB8500_PIN_W17 };
+static const unsigned pwmout1_d_1_pins[] = { AB8500_PIN_F14 };
+static const unsigned pwmout2_d_1_pins[] = { AB8500_PIN_B17 };
+static const unsigned pwmout3_d_1_pins[] = { AB8500_PIN_F15 };
+
+/* audio data interface 1*/
+static const unsigned adi1_d_1_pins[] = { AB8500_PIN_P5, AB8500_PIN_R5,
+ AB8500_PIN_U5, AB8500_PIN_T5 };
+/* USBUICC */
+static const unsigned usbuicc_d_1_pins[] = { AB8500_PIN_H19, AB8500_PIN_G20,
+ AB8500_PIN_G19 };
+static const unsigned sysclkreq7_d_1_pins[] = { AB8500_PIN_T14 };
+static const unsigned sysclkreq8_d_1_pins[] = { AB8500_PIN_R16 };
+static const unsigned gpio26_d_1_pins[] = { AB8500_PIN_M16 };
+/* Digital microphone 1 and 2 */
+static const unsigned dmic12_d_1_pins[] = { AB8500_PIN_J6, AB8500_PIN_K6 };
+/* Digital microphone 3 and 4 */
+static const unsigned dmic34_d_1_pins[] = { AB8500_PIN_G6, AB8500_PIN_H6 };
+/* Digital microphone 5 and 6 */
+static const unsigned dmic56_d_1_pins[] = { AB8500_PIN_F5, AB8500_PIN_G5 };
+static const unsigned extcpena_d_1_pins[] = { AB8500_PIN_R17 };
+static const unsigned gpio35_d_1_pins[] = { AB8500_PIN_W15 };
+/* APE SPI */
+static const unsigned apespi_d_1_pins[] = { AB8500_PIN_A17, AB8500_PIN_E15,
+ AB8500_PIN_C17, AB8500_PIN_E16};
+/* modem SDA/SCL */
+static const unsigned modsclsda_d_1_pins[] = { AB8500_PIN_T19, AB8500_PIN_U19 };
+static const unsigned sysclkreq5_d_1_pins[] = { AB8500_PIN_U2 };
+
+/* Altfunction A column */
+static const unsigned gpio1_a_1_pins[] = { AB8500_PIN_T10 };
+static const unsigned gpio2_a_1_pins[] = { AB8500_PIN_T9 };
+static const unsigned gpio3_a_1_pins[] = { AB8500_PIN_U9 };
+static const unsigned gpio4_a_1_pins[] = { AB8500_PIN_W2 };
+static const unsigned gpio6_a_1_pins[] = { AB8500_PIN_Y18 };
+static const unsigned gpio7_a_1_pins[] = { AB8500_PIN_AA20 };
+static const unsigned gpio8_a_1_pins[] = { AB8500_PIN_W18 };
+static const unsigned gpio9_a_1_pins[] = { AB8500_PIN_AA19 };
+/* YCbCr4 YCbCr5 YCbCr6 YCbCr7*/
+static const unsigned ycbcr4567_a_1_pins[] = { AB8500_PIN_U17, AB8500_PIN_AA18,
+ AB8500_PIN_U16, AB8500_PIN_W17};
+static const unsigned gpio14_a_1_pins[] = { AB8500_PIN_F14 };
+static const unsigned gpio15_a_1_pins[] = { AB8500_PIN_B17 };
+static const unsigned gpio16_a_1_pins[] = { AB8500_PIN_F15 };
+static const unsigned gpio17_a_1_pins[] = { AB8500_PIN_P5 };
+static const unsigned gpio18_a_1_pins[] = { AB8500_PIN_R5 };
+static const unsigned gpio19_a_1_pins[] = { AB8500_PIN_U5 };
+static const unsigned gpio20_a_1_pins[] = { AB8500_PIN_T5 };
+static const unsigned gpio21_a_1_pins[] = { AB8500_PIN_H19 };
+static const unsigned gpio22_a_1_pins[] = { AB8500_PIN_G20 };
+static const unsigned gpio23_a_1_pins[] = { AB8500_PIN_G19 };
+static const unsigned gpio24_a_1_pins[] = { AB8500_PIN_T14 };
+static const unsigned gpio25_a_1_pins[] = { AB8500_PIN_R16 };
+static const unsigned gpio27_a_1_pins[] = { AB8500_PIN_J6 };
+static const unsigned gpio28_a_1_pins[] = { AB8500_PIN_K6 };
+static const unsigned gpio29_a_1_pins[] = { AB8500_PIN_G6 };
+static const unsigned gpio30_a_1_pins[] = { AB8500_PIN_H6 };
+static const unsigned gpio31_a_1_pins[] = { AB8500_PIN_F5 };
+static const unsigned gpio32_a_1_pins[] = { AB8500_PIN_G5 };
+static const unsigned gpio34_a_1_pins[] = { AB8500_PIN_R17 };
+static const unsigned gpio36_a_1_pins[] = { AB8500_PIN_A17 };
+static const unsigned gpio37_a_1_pins[] = { AB8500_PIN_E15 };
+static const unsigned gpio38_a_1_pins[] = { AB8500_PIN_C17 };
+static const unsigned gpio39_a_1_pins[] = { AB8500_PIN_E16 };
+static const unsigned gpio40_a_1_pins[] = { AB8500_PIN_T19 };
+static const unsigned gpio41_a_1_pins[] = { AB8500_PIN_U19 };
+static const unsigned gpio42_a_1_pins[] = { AB8500_PIN_U2 };
+
+/* Altfunction B colum */
+static const unsigned hiqclkena_b_1_pins[] = { AB8500_PIN_U17 };
+static const unsigned usbuiccpd_b_1_pins[] = { AB8500_PIN_AA18 };
+static const unsigned i2ctrig1_b_1_pins[] = { AB8500_PIN_U16 };
+static const unsigned i2ctrig2_b_1_pins[] = { AB8500_PIN_W17 };
+
+/* Altfunction C column */
+static const unsigned usbvdat_c_1_pins[] = { AB8500_PIN_W17 };
+
+
+#define AB8500_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \
+ .npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct abx500_pingroup ab8500_groups[] = {
+ /* default column */
+ AB8500_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(sysclkreq6_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(ycbcr0123_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(gpio10_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(gpio11_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(gpio12_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(gpio13_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(pwmout2_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(pwmout3_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(adi1_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(usbuicc_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(sysclkreq7_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(sysclkreq8_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(gpio26_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(dmic12_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(dmic34_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(dmic56_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(extcpena_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(gpio35_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(apespi_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(modsclsda_d_1, ABX500_DEFAULT),
+ AB8500_PIN_GROUP(sysclkreq5_d_1, ABX500_DEFAULT),
+ /* Altfunction A column */
+ AB8500_PIN_GROUP(gpio1_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio2_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio3_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio4_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio6_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio7_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio8_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio9_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(ycbcr4567_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio14_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio15_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio16_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio17_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio18_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio19_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio20_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio21_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio22_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio23_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio24_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio25_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio27_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio28_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio29_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio30_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio31_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio32_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio34_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio36_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio37_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio38_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio39_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio40_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio41_a_1, ABX500_ALT_A),
+ AB8500_PIN_GROUP(gpio42_a_1, ABX500_ALT_A),
+ /* Altfunction B column */
+ AB8500_PIN_GROUP(hiqclkena_b_1, ABX500_ALT_B),
+ AB8500_PIN_GROUP(usbuiccpd_b_1, ABX500_ALT_B),
+ AB8500_PIN_GROUP(i2ctrig1_b_1, ABX500_ALT_B),
+ AB8500_PIN_GROUP(i2ctrig2_b_1, ABX500_ALT_B),
+ /* Altfunction C column */
+ AB8500_PIN_GROUP(usbvdat_c_1, ABX500_ALT_C),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define AB8500_FUNC_GROUPS(a, b...) \
+static const char * const a##_groups[] = { b };
+
+AB8500_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1",
+ "sysclkreq4_d_1", "sysclkreq5_d_1", "sysclkreq6_d_1",
+ "sysclkreq7_d_1", "sysclkreq8_d_1");
+AB8500_FUNC_GROUPS(ycbcr, "ycbcr0123_d_1", "ycbcr4567_a_1");
+AB8500_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1", "gpio4_a_1",
+ "gpio6_a_1", "gpio7_a_1", "gpio8_a_1", "gpio9_a_1",
+ "gpio10_d_1", "gpio11_d_1", "gpio12_d_1", "gpio13_d_1",
+ "gpio14_a_1", "gpio15_a_1", "gpio16_a_1", "gpio17_a_1",
+ "gpio18_a_1", "gpio19_a_1", "gpio20_a_1", "gpio21_a_1",
+ "gpio22_a_1", "gpio23_a_1", "gpio24_a_1", "gpio25_a_1",
+ "gpio26_d_1", "gpio27_a_1", "gpio28_a_1", "gpio29_a_1",
+ "gpio30_a_1", "gpio31_a_1", "gpio32_a_1", "gpio34_a_1",
+ "gpio35_d_1", "gpio36_a_1", "gpio37_a_1", "gpio38_a_1",
+ "gpio39_a_1", "gpio40_a_1", "gpio41_a_1", "gpio42_a_1");
+AB8500_FUNC_GROUPS(pwmout, "pwmout1_d_1", "pwmout2_d_1", "pwmout3_d_1");
+AB8500_FUNC_GROUPS(adi1, "adi1_d_1");
+AB8500_FUNC_GROUPS(usbuicc, "usbuicc_d_1", "usbuiccpd_b_1");
+AB8500_FUNC_GROUPS(dmic, "dmic12_d_1", "dmic34_d_1", "dmic56_d_1");
+AB8500_FUNC_GROUPS(extcpena, "extcpena_d_1");
+AB8500_FUNC_GROUPS(apespi, "apespi_d_1");
+AB8500_FUNC_GROUPS(modsclsda, "modsclsda_d_1");
+AB8500_FUNC_GROUPS(hiqclkena, "hiqclkena_b_1");
+AB8500_FUNC_GROUPS(i2ctrig, "i2ctrig1_b_1", "i2ctrig2_b_1");
+AB8500_FUNC_GROUPS(usbvdat, "usbvdat_c_1");
+
+#define FUNCTION(fname) \
+ { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+static const struct abx500_function ab8500_functions[] = {
+ FUNCTION(sysclkreq),
+ FUNCTION(ycbcr),
+ FUNCTION(gpio),
+ FUNCTION(pwmout),
+ FUNCTION(adi1),
+ FUNCTION(usbuicc),
+ FUNCTION(dmic),
+ FUNCTION(extcpena),
+ FUNCTION(apespi),
+ FUNCTION(modsclsda),
+ FUNCTION(hiqclkena),
+ FUNCTION(i2ctrig),
+ FUNCTION(usbvdat),
+};
+
+/*
+ * this table translates what's is in the AB8500 specification regarding the
+ * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C).
+ * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1,
+ * ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val),
+ *
+ * example :
+ *
+ * ALTERNATE_FUNCTIONS(13, 4, 3, 4, 0, 1 ,2),
+ * means that pin AB8500_PIN_W17 (pin 13) supports 4 mux (default/ALT_A,
+ * ALT_B and ALT_C), so GPIOSEL and ALTERNATFUNC registers are used to
+ * select the mux. ALTA, ALTB and ALTC val indicates values to write in
+ * ALTERNATFUNC register. We need to specifies these values as SOC
+ * designers didn't apply the same logic on how to select mux in the
+ * ABx500 family.
+ *
+ * As this pins supports at least ALT_B mux, default mux is
+ * selected by writing 1 in GPIOSEL bit :
+ *
+ * | GPIOSEL bit=4 | alternatfunc bit2=4 | alternatfunc bit1=3
+ * default | 1 | 0 | 0
+ * alt_A | 0 | 0 | 0
+ * alt_B | 0 | 0 | 1
+ * alt_C | 0 | 1 | 0
+ *
+ * ALTERNATE_FUNCTIONS(8, 7, UNUSED, UNUSED),
+ * means that pin AB8500_PIN_W18 (pin 8) supports 2 mux, so only GPIOSEL
+ * register is used to select the mux. As this pins doesn't support at
+ * least ALT_B mux, default mux is by writing 0 in GPIOSEL bit :
+ *
+ * | GPIOSEL bit=7 | alternatfunc bit2= | alternatfunc bit1=
+ * default | 0 | 0 | 0
+ * alt_A | 1 | 0 | 0
+ */
+
+struct alternate_functions ab8500_alternate_functions[AB8500_GPIO_MAX_NUMBER + 1] = {
+ ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
+ ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(2, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(3, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/
+ ALTERNATE_FUNCTIONS(4, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO4, altA controlled by bit 3*/
+ /* bit 4 reserved */
+ ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5 */
+ ALTERNATE_FUNCTIONS(6, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO6, altA controlled by bit 5*/
+ ALTERNATE_FUNCTIONS(7, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO7, altA controlled by bit 6*/
+ ALTERNATE_FUNCTIONS(8, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO8, altA controlled by bit 7*/
+
+ ALTERNATE_FUNCTIONS(9, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO9, altA controlled by bit 0*/
+ ALTERNATE_FUNCTIONS(10, 1, 0, UNUSED, 0, 1, 0), /* GPIO10, altA and altB controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(11, 2, 1, UNUSED, 0, 1, 0), /* GPIO11, altA and altB controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(12, 3, 2, UNUSED, 0, 1, 0), /* GPIO12, altA and altB controlled by bit 2 */
+ ALTERNATE_FUNCTIONS(13, 4, 3, 4, 0, 1, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
+ ALTERNATE_FUNCTIONS(14, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(15, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO15, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(16, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO16, altA controlled by bit 7 */
+ /*
+ * pins 17 to 20 are special case, only bit 0 is used to select
+ * alternate function for these 4 pins.
+ * bits 1 to 3 are reserved
+ */
+ ALTERNATE_FUNCTIONS(17, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(18, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(19, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(20, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(21, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO21, altA controlled by bit 4 */
+ ALTERNATE_FUNCTIONS(22, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO22, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(23, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO23, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(24, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO24, altA controlled by bit 7 */
+
+ ALTERNATE_FUNCTIONS(25, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO25, altA controlled by bit 0 */
+ /* pin 26 special case, no alternate function, bit 1 reserved */
+ ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* GPIO26 */
+ ALTERNATE_FUNCTIONS(27, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO27, altA controlled by bit 2 */
+ ALTERNATE_FUNCTIONS(28, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO28, altA controlled by bit 3 */
+ ALTERNATE_FUNCTIONS(29, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO29, altA controlled by bit 4 */
+ ALTERNATE_FUNCTIONS(30, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO30, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(31, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO31, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(32, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO32, altA controlled by bit 7 */
+
+ ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33 */
+ ALTERNATE_FUNCTIONS(34, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO34, altA controlled by bit 1 */
+ /* pin 35 special case, no alternate function, bit 2 reserved */
+ ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* GPIO35 */
+ ALTERNATE_FUNCTIONS(36, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO36, altA controlled by bit 3 */
+ ALTERNATE_FUNCTIONS(37, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO37, altA controlled by bit 4 */
+ ALTERNATE_FUNCTIONS(38, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO38, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(39, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO39, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(40, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO40, altA controlled by bit 7 */
+
+ ALTERNATE_FUNCTIONS(41, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO41, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(42, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO42, altA controlled by bit 1 */
+};
+
+/*
+ * Only some GPIOs are interrupt capable, and they are
+ * organized in discontiguous clusters:
+ *
+ * GPIO6 to GPIO13
+ * GPIO24 and GPIO25
+ * GPIO36 to GPIO41
+ */
+struct abx500_gpio_irq_cluster ab8500_gpio_irq_cluster[] = {
+ GPIO_IRQ_CLUSTER(6, 13, AB8500_INT_GPIO6R),
+ GPIO_IRQ_CLUSTER(24, 25, AB8500_INT_GPIO24R),
+ GPIO_IRQ_CLUSTER(36, 41, AB8500_INT_GPIO36R),
+};
+
+static struct abx500_pinctrl_soc_data ab8500_soc = {
+ .gpio_ranges = ab8500_pinranges,
+ .gpio_num_ranges = ARRAY_SIZE(ab8500_pinranges),
+ .pins = ab8500_pins,
+ .npins = ARRAY_SIZE(ab8500_pins),
+ .functions = ab8500_functions,
+ .nfunctions = ARRAY_SIZE(ab8500_functions),
+ .groups = ab8500_groups,
+ .ngroups = ARRAY_SIZE(ab8500_groups),
+ .alternate_functions = ab8500_alternate_functions,
+ .gpio_irq_cluster = ab8500_gpio_irq_cluster,
+ .ngpio_irq_cluster = ARRAY_SIZE(ab8500_gpio_irq_cluster),
+ .irq_gpio_rising_offset = AB8500_INT_GPIO6R,
+ .irq_gpio_falling_offset = AB8500_INT_GPIO6F,
+ .irq_gpio_factor = 1,
+};
+
+void abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc)
+{
+ *soc = &ab8500_soc;
+}
diff --git a/drivers/pinctrl/pinctrl-ab8505.c b/drivers/pinctrl/pinctrl-ab8505.c
new file mode 100644
index 000000000000..3a4238e879e3
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ab8505.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
+ *
+ * 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/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include "pinctrl-abx500.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define ABX500_GPIO(offset) (offset)
+
+#define AB8505_PIN_N4 ABX500_GPIO(1)
+#define AB8505_PIN_R5 ABX500_GPIO(2)
+#define AB8505_PIN_P5 ABX500_GPIO(3)
+/* hole */
+#define AB8505_PIN_B16 ABX500_GPIO(10)
+#define AB8505_PIN_B17 ABX500_GPIO(11)
+/* hole */
+#define AB8505_PIN_D17 ABX500_GPIO(13)
+#define AB8505_PIN_C16 ABX500_GPIO(14)
+/* hole */
+#define AB8505_PIN_P2 ABX500_GPIO(17)
+#define AB8505_PIN_N3 ABX500_GPIO(18)
+#define AB8505_PIN_T1 ABX500_GPIO(19)
+#define AB8505_PIN_P3 ABX500_GPIO(20)
+/* hole */
+#define AB8505_PIN_H14 ABX500_GPIO(34)
+/* hole */
+#define AB8505_PIN_J15 ABX500_GPIO(40)
+#define AB8505_PIN_J14 ABX500_GPIO(41)
+/* hole */
+#define AB8505_PIN_L4 ABX500_GPIO(50)
+/* hole */
+#define AB8505_PIN_D16 ABX500_GPIO(52)
+#define AB8505_PIN_D15 ABX500_GPIO(53)
+
+/* indicates the higher GPIO number */
+#define AB8505_GPIO_MAX_NUMBER 53
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc ab8505_pins[] = {
+ PINCTRL_PIN(AB8505_PIN_N4, "GPIO1_N4"),
+ PINCTRL_PIN(AB8505_PIN_R5, "GPIO2_R5"),
+ PINCTRL_PIN(AB8505_PIN_P5, "GPIO3_P5"),
+/* hole */
+ PINCTRL_PIN(AB8505_PIN_B16, "GPIO10_B16"),
+ PINCTRL_PIN(AB8505_PIN_B17, "GPIO11_B17"),
+/* hole */
+ PINCTRL_PIN(AB8505_PIN_D17, "GPIO13_D17"),
+ PINCTRL_PIN(AB8505_PIN_C16, "GPIO14_C16"),
+/* hole */
+ PINCTRL_PIN(AB8505_PIN_P2, "GPIO17_P2"),
+ PINCTRL_PIN(AB8505_PIN_N3, "GPIO18_N3"),
+ PINCTRL_PIN(AB8505_PIN_T1, "GPIO19_T1"),
+ PINCTRL_PIN(AB8505_PIN_P3, "GPIO20_P3"),
+/* hole */
+ PINCTRL_PIN(AB8505_PIN_H14, "GPIO34_H14"),
+/* hole */
+ PINCTRL_PIN(AB8505_PIN_J15, "GPIO40_J15"),
+ PINCTRL_PIN(AB8505_PIN_J14, "GPIO41_J14"),
+/* hole */
+ PINCTRL_PIN(AB8505_PIN_L4, "GPIO50_L4"),
+/* hole */
+ PINCTRL_PIN(AB8505_PIN_D16, "GPIO52_D16"),
+ PINCTRL_PIN(AB8505_PIN_D15, "GPIO53_D15"),
+};
+
+/*
+ * Maps local GPIO offsets to local pin numbers
+ */
+static const struct abx500_pinrange ab8505_pinranges[] = {
+ ABX500_PINRANGE(1, 3, ABX500_ALT_A),
+ ABX500_PINRANGE(10, 2, ABX500_DEFAULT),
+ ABX500_PINRANGE(13, 1, ABX500_DEFAULT),
+ ABX500_PINRANGE(14, 1, ABX500_ALT_A),
+ ABX500_PINRANGE(17, 4, ABX500_ALT_A),
+ ABX500_PINRANGE(34, 1, ABX500_ALT_A),
+ ABX500_PINRANGE(40, 2, ABX500_ALT_A),
+ ABX500_PINRANGE(50, 1, ABX500_DEFAULT),
+ ABX500_PINRANGE(52, 2, ABX500_ALT_A),
+};
+
+/*
+ * Read the pin group names like this:
+ * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* default column */
+static const unsigned sysclkreq2_d_1_pins[] = { AB8505_PIN_N4 };
+static const unsigned sysclkreq3_d_1_pins[] = { AB8505_PIN_R5 };
+static const unsigned sysclkreq4_d_1_pins[] = { AB8505_PIN_P5 };
+static const unsigned gpio10_d_1_pins[] = { AB8505_PIN_B16 };
+static const unsigned gpio11_d_1_pins[] = { AB8505_PIN_B17 };
+static const unsigned gpio13_d_1_pins[] = { AB8505_PIN_D17 };
+static const unsigned pwmout1_d_1_pins[] = { AB8505_PIN_C16 };
+/* audio data interface 2*/
+static const unsigned adi2_d_1_pins[] = { AB8505_PIN_P2, AB8505_PIN_N3,
+ AB8505_PIN_T1, AB8505_PIN_P3 };
+static const unsigned extcpena_d_1_pins[] = { AB8505_PIN_H14 };
+/* modem SDA/SCL */
+static const unsigned modsclsda_d_1_pins[] = { AB8505_PIN_J15, AB8505_PIN_J14 };
+static const unsigned gpio50_d_1_pins[] = { AB8505_PIN_L4 };
+static const unsigned resethw_d_1_pins[] = { AB8505_PIN_D16 };
+static const unsigned service_d_1_pins[] = { AB8505_PIN_D15 };
+
+/* Altfunction A column */
+static const unsigned gpio1_a_1_pins[] = { AB8505_PIN_N4 };
+static const unsigned gpio2_a_1_pins[] = { AB8505_PIN_R5 };
+static const unsigned gpio3_a_1_pins[] = { AB8505_PIN_P5 };
+static const unsigned hiqclkena_a_1_pins[] = { AB8505_PIN_B16 };
+static const unsigned pdmclk_a_1_pins[] = { AB8505_PIN_B17 };
+static const unsigned uarttxdata_a_1_pins[] = { AB8505_PIN_D17 };
+static const unsigned gpio14_a_1_pins[] = { AB8505_PIN_C16 };
+static const unsigned gpio17_a_1_pins[] = { AB8505_PIN_P2 };
+static const unsigned gpio18_a_1_pins[] = { AB8505_PIN_N3 };
+static const unsigned gpio19_a_1_pins[] = { AB8505_PIN_T1 };
+static const unsigned gpio20_a_1_pins[] = { AB8505_PIN_P3 };
+static const unsigned gpio34_a_1_pins[] = { AB8505_PIN_H14 };
+static const unsigned gpio40_a_1_pins[] = { AB8505_PIN_J15 };
+static const unsigned gpio41_a_1_pins[] = { AB8505_PIN_J14 };
+static const unsigned uartrxdata_a_1_pins[] = { AB8505_PIN_J14 };
+static const unsigned gpio50_a_1_pins[] = { AB8505_PIN_L4 };
+static const unsigned gpio52_a_1_pins[] = { AB8505_PIN_D16 };
+static const unsigned gpio53_a_1_pins[] = { AB8505_PIN_D15 };
+
+/* Altfunction B colum */
+static const unsigned pdmdata_b_1_pins[] = { AB8505_PIN_B16 };
+static const unsigned extvibrapwm1_b_1_pins[] = { AB8505_PIN_D17 };
+static const unsigned extvibrapwm2_b_1_pins[] = { AB8505_PIN_L4 };
+
+/* Altfunction C column */
+static const unsigned usbvdat_c_1_pins[] = { AB8505_PIN_D17 };
+
+#define AB8505_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \
+ .npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct abx500_pingroup ab8505_groups[] = {
+ AB8505_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(gpio10_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(gpio11_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(gpio13_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(adi2_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(extcpena_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(modsclsda_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(gpio50_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(resethw_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(service_d_1, ABX500_DEFAULT),
+ AB8505_PIN_GROUP(gpio1_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio2_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio3_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(hiqclkena_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(pdmclk_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(uarttxdata_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio14_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio17_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio18_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio19_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio20_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio34_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio40_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio41_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(uartrxdata_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio52_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(gpio53_a_1, ABX500_ALT_A),
+ AB8505_PIN_GROUP(pdmdata_b_1, ABX500_ALT_B),
+ AB8505_PIN_GROUP(extvibrapwm1_b_1, ABX500_ALT_B),
+ AB8505_PIN_GROUP(extvibrapwm2_b_1, ABX500_ALT_B),
+ AB8505_PIN_GROUP(usbvdat_c_1, ABX500_ALT_C),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define AB8505_FUNC_GROUPS(a, b...) \
+static const char * const a##_groups[] = { b };
+
+AB8505_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1",
+ "sysclkreq4_d_1");
+AB8505_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1",
+ "gpio10_d_1", "gpio11_d_1", "gpio13_d_1", "gpio14_a_1",
+ "gpio17_a_1", "gpio18_a_1", "gpio19_a_1", "gpio20_a_1",
+ "gpio34_a_1", "gpio40_a_1", "gpio41_a_1", "gpio50_d_1",
+ "gpio52_a_1", "gpio53_a_1");
+AB8505_FUNC_GROUPS(pwmout, "pwmout1_d_1");
+AB8505_FUNC_GROUPS(adi2, "adi2_d_1");
+AB8505_FUNC_GROUPS(extcpena, "extcpena_d_1");
+AB8505_FUNC_GROUPS(modsclsda, "modsclsda_d_1");
+AB8505_FUNC_GROUPS(resethw, "resethw_d_1");
+AB8505_FUNC_GROUPS(service, "service_d_1");
+AB8505_FUNC_GROUPS(hiqclkena, "hiqclkena_a_1");
+AB8505_FUNC_GROUPS(pdm, "pdmclk_a_1", "pdmdata_b_1");
+AB8505_FUNC_GROUPS(uartdata, "uarttxdata_a_1", "uartrxdata_a_1");
+AB8505_FUNC_GROUPS(extvibra, "extvibrapwm1_b_1", "extvibrapwm2_b_1");
+AB8505_FUNC_GROUPS(usbvdat, "usbvdat_c_1");
+
+#define FUNCTION(fname) \
+ { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+static const struct abx500_function ab8505_functions[] = {
+ FUNCTION(sysclkreq),
+ FUNCTION(gpio),
+ FUNCTION(pwmout),
+ FUNCTION(adi2),
+ FUNCTION(extcpena),
+ FUNCTION(modsclsda),
+ FUNCTION(resethw),
+ FUNCTION(service),
+ FUNCTION(hiqclkena),
+ FUNCTION(pdm),
+ FUNCTION(uartdata),
+ FUNCTION(extvibra),
+ FUNCTION(extvibra),
+ FUNCTION(usbvdat),
+};
+
+/*
+ * this table translates what's is in the AB8505 specification regarding the
+ * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C).
+ * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1,
+ * ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val),
+ *
+ * example :
+ *
+ * ALTERNATE_FUNCTIONS(13, 4, 3, 4, 1, 0, 2),
+ * means that pin AB8505_PIN_D18 (pin 13) supports 4 mux (default/ALT_A,
+ * ALT_B and ALT_C), so GPIOSEL and ALTERNATFUNC registers are used to
+ * select the mux. ALTA, ALTB and ALTC val indicates values to write in
+ * ALTERNATFUNC register. We need to specifies these values as SOC
+ * designers didn't apply the same logic on how to select mux in the
+ * ABx500 family.
+ *
+ * As this pins supports at least ALT_B mux, default mux is
+ * selected by writing 1 in GPIOSEL bit :
+ *
+ * | GPIOSEL bit=4 | alternatfunc bit2=4 | alternatfunc bit1=3
+ * default | 1 | 0 | 0
+ * alt_A | 0 | 0 | 1
+ * alt_B | 0 | 0 | 0
+ * alt_C | 0 | 1 | 0
+ *
+ * ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED),
+ * means that pin AB9540_PIN_R4 (pin 1) supports 2 mux, so only GPIOSEL
+ * register is used to select the mux. As this pins doesn't support at
+ * least ALT_B mux, default mux is by writing 0 in GPIOSEL bit :
+ *
+ * | GPIOSEL bit=0 | alternatfunc bit2= | alternatfunc bit1=
+ * default | 0 | 0 | 0
+ * alt_A | 1 | 0 | 0
+ */
+
+struct alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1] = {
+ ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
+ ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(2, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(3, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/
+ ALTERNATE_FUNCTIONS(4, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO4, bit 3 reserved */
+ ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5, bit 4 reserved */
+ ALTERNATE_FUNCTIONS(6, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO6, bit 5 reserved */
+ ALTERNATE_FUNCTIONS(7, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO7, bit 6 reserved */
+ ALTERNATE_FUNCTIONS(8, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO8, bit 7 reserved */
+
+ ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9, bit 0 reserved */
+ ALTERNATE_FUNCTIONS(10, 1, 0, UNUSED, 1, 0, 0), /* GPIO10, altA and altB controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(11, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 2 */
+ ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12, bit3 reseved */
+ ALTERNATE_FUNCTIONS(13, 4, 3, 4, 1, 0, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
+ ALTERNATE_FUNCTIONS(14, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(15, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO15, bit 6 reserved */
+ ALTERNATE_FUNCTIONS(16, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO15, bit 7 reserved */
+ /*
+ * pins 17 to 20 are special case, only bit 0 is used to select
+ * alternate function for these 4 pins.
+ * bits 1 to 3 are reserved
+ */
+ ALTERNATE_FUNCTIONS(17, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(18, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(19, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(20, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(21, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO21, bit 4 reserved */
+ ALTERNATE_FUNCTIONS(22, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO22, bit 5 reserved */
+ ALTERNATE_FUNCTIONS(23, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO23, bit 6 reserved */
+ ALTERNATE_FUNCTIONS(24, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO24, bit 7 reserved */
+
+ ALTERNATE_FUNCTIONS(25, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO25, bit 0 reserved */
+ ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO26, bit 1 reserved */
+ ALTERNATE_FUNCTIONS(27, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO27, bit 2 reserved */
+ ALTERNATE_FUNCTIONS(28, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO28, bit 3 reserved */
+ ALTERNATE_FUNCTIONS(29, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO29, bit 4 reserved */
+ ALTERNATE_FUNCTIONS(30, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO30, bit 5 reserved */
+ ALTERNATE_FUNCTIONS(31, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO31, bit 6 reserved */
+ ALTERNATE_FUNCTIONS(32, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO32, bit 7 reserved */
+
+ ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33, bit 0 reserved */
+ ALTERNATE_FUNCTIONS(34, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO34, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO35, bit 2 reserved */
+ ALTERNATE_FUNCTIONS(36, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO36, bit 2 reserved */
+ ALTERNATE_FUNCTIONS(37, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO37, bit 2 reserved */
+ ALTERNATE_FUNCTIONS(38, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO38, bit 2 reserved */
+ ALTERNATE_FUNCTIONS(39, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO39, bit 2 reserved */
+ ALTERNATE_FUNCTIONS(40, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO40, altA controlled by bit 7*/
+
+ ALTERNATE_FUNCTIONS(41, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO41, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(42, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO42, bit 1 reserved */
+ ALTERNATE_FUNCTIONS(43, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO43, bit 2 reserved */
+ ALTERNATE_FUNCTIONS(44, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO44, bit 3 reserved */
+ ALTERNATE_FUNCTIONS(45, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO45, bit 4 reserved */
+ ALTERNATE_FUNCTIONS(46, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO46, bit 5 reserved */
+ ALTERNATE_FUNCTIONS(47, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO47, bit 6 reserved */
+ ALTERNATE_FUNCTIONS(48, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO48, bit 7 reserved */
+
+ ALTERNATE_FUNCTIONS(49, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO49, bit 0 reserved */
+ ALTERNATE_FUNCTIONS(50, 1, 2, UNUSED, 1, 0, 0), /* GPIO50, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(51, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO49, bit 0 reserved */
+ ALTERNATE_FUNCTIONS(52, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO52, altA controlled by bit 3 */
+ ALTERNATE_FUNCTIONS(53, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO53, altA controlled by bit 4 */
+};
+
+/*
+ * For AB8505 Only some GPIOs are interrupt capable, and they are
+ * organized in discontiguous clusters:
+ *
+ * GPIO10 to GPIO11
+ * GPIO13
+ * GPIO40 and GPIO41
+ * GPIO50
+ * GPIO52 to GPIO53
+ */
+struct abx500_gpio_irq_cluster ab8505_gpio_irq_cluster[] = {
+ GPIO_IRQ_CLUSTER(10, 11, AB8500_INT_GPIO10R),
+ GPIO_IRQ_CLUSTER(13, 13, AB8500_INT_GPIO13R),
+ GPIO_IRQ_CLUSTER(40, 41, AB8500_INT_GPIO40R),
+ GPIO_IRQ_CLUSTER(50, 50, AB9540_INT_GPIO50R),
+ GPIO_IRQ_CLUSTER(52, 53, AB9540_INT_GPIO52R),
+};
+
+static struct abx500_pinctrl_soc_data ab8505_soc = {
+ .gpio_ranges = ab8505_pinranges,
+ .gpio_num_ranges = ARRAY_SIZE(ab8505_pinranges),
+ .pins = ab8505_pins,
+ .npins = ARRAY_SIZE(ab8505_pins),
+ .functions = ab8505_functions,
+ .nfunctions = ARRAY_SIZE(ab8505_functions),
+ .groups = ab8505_groups,
+ .ngroups = ARRAY_SIZE(ab8505_groups),
+ .alternate_functions = ab8505_alternate_functions,
+ .gpio_irq_cluster = ab8505_gpio_irq_cluster,
+ .ngpio_irq_cluster = ARRAY_SIZE(ab8505_gpio_irq_cluster),
+ .irq_gpio_rising_offset = AB8500_INT_GPIO6R,
+ .irq_gpio_falling_offset = AB8500_INT_GPIO6F,
+ .irq_gpio_factor = 1,
+};
+
+void
+abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc)
+{
+ *soc = &ab8505_soc;
+}
diff --git a/drivers/pinctrl/pinctrl-ab8540.c b/drivers/pinctrl/pinctrl-ab8540.c
new file mode 100644
index 000000000000..8ee1e8d95f65
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ab8540.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
+ *
+ * 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/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include "pinctrl-abx500.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define ABX500_GPIO(offset) (offset)
+
+#define AB8540_PIN_J16 ABX500_GPIO(1)
+#define AB8540_PIN_D17 ABX500_GPIO(2)
+#define AB8540_PIN_C12 ABX500_GPIO(3)
+#define AB8540_PIN_G12 ABX500_GPIO(4)
+/* hole */
+#define AB8540_PIN_D16 ABX500_GPIO(14)
+#define AB8540_PIN_F15 ABX500_GPIO(15)
+#define AB8540_PIN_J8 ABX500_GPIO(16)
+#define AB8540_PIN_K16 ABX500_GPIO(17)
+#define AB8540_PIN_G15 ABX500_GPIO(18)
+#define AB8540_PIN_F17 ABX500_GPIO(19)
+#define AB8540_PIN_E17 ABX500_GPIO(20)
+/* hole */
+#define AB8540_PIN_AA16 ABX500_GPIO(27)
+#define AB8540_PIN_W18 ABX500_GPIO(28)
+#define AB8540_PIN_Y15 ABX500_GPIO(29)
+#define AB8540_PIN_W16 ABX500_GPIO(30)
+#define AB8540_PIN_V15 ABX500_GPIO(31)
+#define AB8540_PIN_W17 ABX500_GPIO(32)
+/* hole */
+#define AB8540_PIN_D12 ABX500_GPIO(42)
+#define AB8540_PIN_P4 ABX500_GPIO(43)
+#define AB8540_PIN_AB1 ABX500_GPIO(44)
+#define AB8540_PIN_K7 ABX500_GPIO(45)
+#define AB8540_PIN_L7 ABX500_GPIO(46)
+#define AB8540_PIN_G10 ABX500_GPIO(47)
+#define AB8540_PIN_K12 ABX500_GPIO(48)
+/* hole */
+#define AB8540_PIN_N8 ABX500_GPIO(51)
+#define AB8540_PIN_P12 ABX500_GPIO(52)
+#define AB8540_PIN_K8 ABX500_GPIO(53)
+#define AB8540_PIN_J11 ABX500_GPIO(54)
+#define AB8540_PIN_AC2 ABX500_GPIO(55)
+#define AB8540_PIN_AB2 ABX500_GPIO(56)
+
+/* indicates the highest GPIO number */
+#define AB8540_GPIO_MAX_NUMBER 56
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc ab8540_pins[] = {
+ PINCTRL_PIN(AB8540_PIN_J16, "GPIO1_J16"),
+ PINCTRL_PIN(AB8540_PIN_D17, "GPIO2_D17"),
+ PINCTRL_PIN(AB8540_PIN_C12, "GPIO3_C12"),
+ PINCTRL_PIN(AB8540_PIN_G12, "GPIO4_G12"),
+ /* hole */
+ PINCTRL_PIN(AB8540_PIN_D16, "GPIO14_D16"),
+ PINCTRL_PIN(AB8540_PIN_F15, "GPIO15_F15"),
+ PINCTRL_PIN(AB8540_PIN_J8, "GPIO16_J8"),
+ PINCTRL_PIN(AB8540_PIN_K16, "GPIO17_K16"),
+ PINCTRL_PIN(AB8540_PIN_G15, "GPIO18_G15"),
+ PINCTRL_PIN(AB8540_PIN_F17, "GPIO19_F17"),
+ PINCTRL_PIN(AB8540_PIN_E17, "GPIO20_E17"),
+ /* hole */
+ PINCTRL_PIN(AB8540_PIN_AA16, "GPIO27_AA16"),
+ PINCTRL_PIN(AB8540_PIN_W18, "GPIO28_W18"),
+ PINCTRL_PIN(AB8540_PIN_Y15, "GPIO29_Y15"),
+ PINCTRL_PIN(AB8540_PIN_W16, "GPIO30_W16"),
+ PINCTRL_PIN(AB8540_PIN_V15, "GPIO31_V15"),
+ PINCTRL_PIN(AB8540_PIN_W17, "GPIO32_W17"),
+ /* hole */
+ PINCTRL_PIN(AB8540_PIN_D12, "GPIO42_D12"),
+ PINCTRL_PIN(AB8540_PIN_P4, "GPIO43_P4"),
+ PINCTRL_PIN(AB8540_PIN_AB1, "GPIO44_AB1"),
+ PINCTRL_PIN(AB8540_PIN_K7, "GPIO45_K7"),
+ PINCTRL_PIN(AB8540_PIN_L7, "GPIO46_L7"),
+ PINCTRL_PIN(AB8540_PIN_G10, "GPIO47_G10"),
+ PINCTRL_PIN(AB8540_PIN_K12, "GPIO48_K12"),
+ /* hole */
+ PINCTRL_PIN(AB8540_PIN_N8, "GPIO51_N8"),
+ PINCTRL_PIN(AB8540_PIN_P12, "GPIO52_P12"),
+ PINCTRL_PIN(AB8540_PIN_K8, "GPIO53_K8"),
+ PINCTRL_PIN(AB8540_PIN_J11, "GPIO54_J11"),
+ PINCTRL_PIN(AB8540_PIN_AC2, "GPIO55_AC2"),
+ PINCTRL_PIN(AB8540_PIN_AB2, "GPIO56_AB2"),
+};
+
+/*
+ * Maps local GPIO offsets to local pin numbers
+ */
+static const struct abx500_pinrange ab8540_pinranges[] = {
+ ABX500_PINRANGE(1, 4, ABX500_ALT_A),
+ ABX500_PINRANGE(14, 7, ABX500_ALT_A),
+ ABX500_PINRANGE(27, 6, ABX500_ALT_A),
+ ABX500_PINRANGE(42, 7, ABX500_ALT_A),
+ ABX500_PINRANGE(51, 6, ABX500_ALT_A),
+};
+
+/*
+ * Read the pin group names like this:
+ * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* default column */
+static const unsigned sysclkreq2_d_1_pins[] = { AB8540_PIN_J16 };
+static const unsigned sysclkreq3_d_1_pins[] = { AB8540_PIN_D17 };
+static const unsigned sysclkreq4_d_1_pins[] = { AB8540_PIN_C12 };
+static const unsigned sysclkreq6_d_1_pins[] = { AB8540_PIN_G12 };
+static const unsigned pwmout1_d_1_pins[] = { AB8540_PIN_D16 };
+static const unsigned pwmout2_d_1_pins[] = { AB8540_PIN_F15 };
+static const unsigned pwmout3_d_1_pins[] = { AB8540_PIN_J8 };
+
+/* audio data interface 1*/
+static const unsigned adi1_d_1_pins[] = { AB8540_PIN_K16, AB8540_PIN_G15,
+ AB8540_PIN_F17, AB8540_PIN_E17 };
+/* Digital microphone 1 and 2 */
+static const unsigned dmic12_d_1_pins[] = { AB8540_PIN_AA16, AB8540_PIN_W18 };
+/* Digital microphone 3 and 4 */
+static const unsigned dmic34_d_1_pins[] = { AB8540_PIN_Y15, AB8540_PIN_W16 };
+/* Digital microphone 5 and 6 */
+static const unsigned dmic56_d_1_pins[] = { AB8540_PIN_V15, AB8540_PIN_W17 };
+static const unsigned sysclkreq5_d_1_pins[] = { AB8540_PIN_D12 };
+static const unsigned batremn_d_1_pins[] = { AB8540_PIN_P4 };
+static const unsigned service_d_1_pins[] = { AB8540_PIN_AB1 };
+static const unsigned pwrctrl0_d_1_pins[] = { AB8540_PIN_K7 };
+static const unsigned pwrctrl1_d_1_pins[] = { AB8540_PIN_L7 };
+static const unsigned pwmextvibra1_d_1_pins[] = { AB8540_PIN_G10 };
+static const unsigned pwmextvibra2_d_1_pins[] = { AB8540_PIN_K12 };
+static const unsigned gpio1_vbat_d_1_pins[] = { AB8540_PIN_N8 };
+static const unsigned gpio2_vbat_d_1_pins[] = { AB8540_PIN_P12 };
+static const unsigned gpio3_vbat_d_1_pins[] = { AB8540_PIN_K8 };
+static const unsigned gpio4_vbat_d_1_pins[] = { AB8540_PIN_J11 };
+static const unsigned pdmclkdat_d_1_pins[] = { AB8540_PIN_AC2, AB8540_PIN_AB2 };
+
+/* Altfunction A column */
+static const unsigned gpio1_a_1_pins[] = { AB8540_PIN_J16 };
+static const unsigned gpio2_a_1_pins[] = { AB8540_PIN_D17 };
+static const unsigned gpio3_a_1_pins[] = { AB8540_PIN_C12 };
+static const unsigned gpio4_a_1_pins[] = { AB8540_PIN_G12 };
+static const unsigned gpio14_a_1_pins[] = { AB8540_PIN_D16 };
+static const unsigned gpio15_a_1_pins[] = { AB8540_PIN_F15 };
+static const unsigned gpio16_a_1_pins[] = { AB8540_PIN_J8 };
+static const unsigned gpio17_a_1_pins[] = { AB8540_PIN_K16 };
+static const unsigned gpio18_a_1_pins[] = { AB8540_PIN_G15 };
+static const unsigned gpio19_a_1_pins[] = { AB8540_PIN_F17 };
+static const unsigned gpio20_a_1_pins[] = { AB8540_PIN_E17 };
+static const unsigned gpio27_a_1_pins[] = { AB8540_PIN_AA16 };
+static const unsigned gpio28_a_1_pins[] = { AB8540_PIN_W18 };
+static const unsigned gpio29_a_1_pins[] = { AB8540_PIN_Y15 };
+static const unsigned gpio30_a_1_pins[] = { AB8540_PIN_W16 };
+static const unsigned gpio31_a_1_pins[] = { AB8540_PIN_V15 };
+static const unsigned gpio32_a_1_pins[] = { AB8540_PIN_W17 };
+static const unsigned gpio42_a_1_pins[] = { AB8540_PIN_D12 };
+static const unsigned gpio43_a_1_pins[] = { AB8540_PIN_P4 };
+static const unsigned gpio44_a_1_pins[] = { AB8540_PIN_AB1 };
+static const unsigned gpio45_a_1_pins[] = { AB8540_PIN_K7 };
+static const unsigned gpio46_a_1_pins[] = { AB8540_PIN_L7 };
+static const unsigned gpio47_a_1_pins[] = { AB8540_PIN_G10 };
+static const unsigned gpio48_a_1_pins[] = { AB8540_PIN_K12 };
+static const unsigned gpio51_a_1_pins[] = { AB8540_PIN_N8 };
+static const unsigned gpio52_a_1_pins[] = { AB8540_PIN_P12 };
+static const unsigned gpio53_a_1_pins[] = { AB8540_PIN_K8 };
+static const unsigned gpio54_a_1_pins[] = { AB8540_PIN_J11 };
+static const unsigned gpio55_a_1_pins[] = { AB8540_PIN_AC2 };
+static const unsigned gpio56_a_1_pins[] = { AB8540_PIN_AB2 };
+
+#define AB8540_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \
+ .npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct abx500_pingroup ab8540_groups[] = {
+ /* default column */
+ AB8540_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(sysclkreq6_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(pwmout2_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(pwmout3_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(adi1_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(dmic12_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(dmic34_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(dmic56_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(sysclkreq5_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(batremn_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(service_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(pwrctrl0_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(pwrctrl1_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(pwmextvibra1_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(pwmextvibra2_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(gpio1_vbat_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(gpio2_vbat_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(gpio3_vbat_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(gpio4_vbat_d_1, ABX500_DEFAULT),
+ AB8540_PIN_GROUP(pdmclkdat_d_1, ABX500_DEFAULT),
+ /* Altfunction A column */
+ AB8540_PIN_GROUP(gpio1_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio2_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio3_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio4_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio14_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio15_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio16_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio17_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio18_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio19_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio20_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio27_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio28_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio29_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio30_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio31_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio32_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio42_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio43_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio44_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio45_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio46_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio47_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio48_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio51_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio52_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio53_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio54_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio55_a_1, ABX500_ALT_A),
+ AB8540_PIN_GROUP(gpio56_a_1, ABX500_ALT_A),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define AB8540_FUNC_GROUPS(a, b...) \
+static const char * const a##_groups[] = { b };
+
+AB8540_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1",
+ "sysclkreq4_d_1", "sysclkreq5_d_1", "sysclkreq6_d_1");
+AB8540_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1", "gpio4_a_1",
+ "gpio14_a_1", "gpio15_a_1", "gpio16_a_1", "gpio17_a_1",
+ "gpio18_a_1", "gpio19_a_1", "gpio20_a_1", "gpio27_a_1",
+ "gpio28_a_1", "gpio29_a_1", "gpio30_a_1", "gpio31_a_1",
+ "gpio32_a_1", "gpio42_a_1", "gpio43_a_1", "gpio44_a_1",
+ "gpio45_a_1", "gpio46_a_1", "gpio47_a_1", "gpio48_a_1",
+ "gpio51_a_1", "gpio52_a_1", "gpio53_a_1", "gpio54_a_1",
+ "gpio55_a_1", "gpio56_a_1");
+AB8540_FUNC_GROUPS(pwmout, "pwmout1_d_1", "pwmout2_d_1", "pwmout3_d_1");
+AB8540_FUNC_GROUPS(adi1, "adi1_d_1");
+AB8540_FUNC_GROUPS(dmic, "dmic12_d_1", "dmic34_d_1", "dmic56_d_1");
+AB8540_FUNC_GROUPS(batremn, "batremn_d_1");
+AB8540_FUNC_GROUPS(service, "service_d_1");
+AB8540_FUNC_GROUPS(pwrctrl, "pwrctrl0_d_1", "pwrctrl1_d_1");
+AB8540_FUNC_GROUPS(pwmextvibra, "pwmextvibra1_d_1", "pwmextvibra2_d_1");
+AB8540_FUNC_GROUPS(gpio_vbat, "gpio1_vbat_d_1", "gpio2_vbat_d_1",
+ "gpio3_vbat_d_1", "gpio4_vbat_d_1");
+AB8540_FUNC_GROUPS(pdm, "pdmclkdat_d_1");
+
+#define FUNCTION(fname) \
+ { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+static const struct abx500_function ab8540_functions[] = {
+ FUNCTION(sysclkreq),
+ FUNCTION(gpio),
+ FUNCTION(pwmout),
+ FUNCTION(adi1),
+ FUNCTION(dmic),
+ FUNCTION(batremn),
+ FUNCTION(service),
+ FUNCTION(pwrctrl),
+ FUNCTION(pwmextvibra),
+ FUNCTION(gpio_vbat),
+ FUNCTION(pdm),
+};
+
+/*
+ * this table translates what's is in the AB8540 specification regarding the
+ * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C).
+ * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1,
+ * ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val),
+ * AB8540 only supports DEFAULT and ALTA functions, so ALTERNATFUNC
+ * registers is not used
+ *
+ */
+
+struct alternate_functions ab8540_alternate_functions[AB8540_GPIO_MAX_NUMBER + 1] = {
+ /* GPIOSEL1 - bit 4-7 reserved */
+ ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
+ ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(2, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(3, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/
+ ALTERNATE_FUNCTIONS(4, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO4, altA controlled by bit 3*/
+ ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5 */
+ ALTERNATE_FUNCTIONS(6, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO6 */
+ ALTERNATE_FUNCTIONS(7, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO7 */
+ ALTERNATE_FUNCTIONS(8, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO8 */
+ /* GPIOSEL2 - bit 0-4 reserved */
+ ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9 */
+ ALTERNATE_FUNCTIONS(10, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO10 */
+ ALTERNATE_FUNCTIONS(11, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO11 */
+ ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12 */
+ ALTERNATE_FUNCTIONS(13, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO13 */
+ ALTERNATE_FUNCTIONS(14, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(15, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO15, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(16, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO16, altA controlled by bit 7 */
+ /* GPIOSEL3 - bit 4-7 reserved */
+ ALTERNATE_FUNCTIONS(17, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(18, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(19, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 2 */
+ ALTERNATE_FUNCTIONS(20, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 3 */
+ ALTERNATE_FUNCTIONS(21, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO21 */
+ ALTERNATE_FUNCTIONS(22, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO22 */
+ ALTERNATE_FUNCTIONS(23, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO23 */
+ ALTERNATE_FUNCTIONS(24, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO24 */
+ /* GPIOSEL4 - bit 0-1 reserved */
+ ALTERNATE_FUNCTIONS(25, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO25 */
+ ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO26 */
+ ALTERNATE_FUNCTIONS(27, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO27, altA controlled by bit 2 */
+ ALTERNATE_FUNCTIONS(28, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO28, altA controlled by bit 3 */
+ ALTERNATE_FUNCTIONS(29, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO29, altA controlled by bit 4 */
+ ALTERNATE_FUNCTIONS(30, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO30, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(31, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO31, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(32, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO32, altA controlled by bit 7 */
+ /* GPIOSEL5 - bit 0-7 reserved */
+ ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33 */
+ ALTERNATE_FUNCTIONS(34, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO34 */
+ ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO35 */
+ ALTERNATE_FUNCTIONS(36, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO36 */
+ ALTERNATE_FUNCTIONS(37, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO37 */
+ ALTERNATE_FUNCTIONS(38, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO38 */
+ ALTERNATE_FUNCTIONS(39, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO39 */
+ ALTERNATE_FUNCTIONS(40, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO40 */
+ /* GPIOSEL6 - bit 0 reserved */
+ ALTERNATE_FUNCTIONS(41, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO41 */
+ ALTERNATE_FUNCTIONS(42, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO42, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(43, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO43, altA controlled by bit 2 */
+ ALTERNATE_FUNCTIONS(44, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO44, altA controlled by bit 3 */
+ ALTERNATE_FUNCTIONS(45, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO45, altA controlled by bit 4 */
+ ALTERNATE_FUNCTIONS(46, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO46, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(47, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO47, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(48, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO48, altA controlled by bit 7 */
+ /* GPIOSEL7 - bit 0-1 reserved */
+ ALTERNATE_FUNCTIONS(49, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO49 */
+ ALTERNATE_FUNCTIONS(50, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO50 */
+ ALTERNATE_FUNCTIONS(51, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO51, altA controlled by bit 2 */
+ ALTERNATE_FUNCTIONS(52, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO52, altA controlled by bit 3 */
+ ALTERNATE_FUNCTIONS(53, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO53, altA controlled by bit 4 */
+ ALTERNATE_FUNCTIONS(54, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO54, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(55, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO55, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(56, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO56, altA controlled by bit 7 */
+};
+
+static struct pullud ab8540_pullud = {
+ .first_pin = 51, /* GPIO1_VBAT */
+ .last_pin = 54, /* GPIO4_VBAT */
+};
+
+/*
+ * For AB8540 Only some GPIOs are interrupt capable:
+ * GPIO43 to GPIO44
+ * GPIO51 to GPIO54
+ */
+struct abx500_gpio_irq_cluster ab8540_gpio_irq_cluster[] = {
+ GPIO_IRQ_CLUSTER(43, 43, AB8540_INT_GPIO43F),
+ GPIO_IRQ_CLUSTER(44, 44, AB8540_INT_GPIO44F),
+ GPIO_IRQ_CLUSTER(51, 54, AB9540_INT_GPIO51R),
+};
+
+static struct abx500_pinctrl_soc_data ab8540_soc = {
+ .gpio_ranges = ab8540_pinranges,
+ .gpio_num_ranges = ARRAY_SIZE(ab8540_pinranges),
+ .pins = ab8540_pins,
+ .npins = ARRAY_SIZE(ab8540_pins),
+ .functions = ab8540_functions,
+ .nfunctions = ARRAY_SIZE(ab8540_functions),
+ .groups = ab8540_groups,
+ .ngroups = ARRAY_SIZE(ab8540_groups),
+ .alternate_functions = ab8540_alternate_functions,
+ .pullud = &ab8540_pullud,
+ .gpio_irq_cluster = ab8540_gpio_irq_cluster,
+ .ngpio_irq_cluster = ARRAY_SIZE(ab8540_gpio_irq_cluster),
+ .irq_gpio_rising_offset = AB8540_INT_GPIO43R,
+ .irq_gpio_falling_offset = AB8540_INT_GPIO43F,
+ .irq_gpio_factor = 2,
+};
+
+void
+abx500_pinctrl_ab8540_init(struct abx500_pinctrl_soc_data **soc)
+{
+ *soc = &ab8540_soc;
+}
diff --git a/drivers/pinctrl/pinctrl-ab9540.c b/drivers/pinctrl/pinctrl-ab9540.c
new file mode 100644
index 000000000000..7610bd012b98
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ab9540.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Patrice Chotard <patrice.chotard@stericsson.com> for ST-Ericsson.
+ *
+ * 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/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include "pinctrl-abx500.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define ABX500_GPIO(offset) (offset)
+
+#define AB9540_PIN_R4 ABX500_GPIO(1)
+#define AB9540_PIN_V3 ABX500_GPIO(2)
+#define AB9540_PIN_T4 ABX500_GPIO(3)
+#define AB9540_PIN_T5 ABX500_GPIO(4)
+/* hole */
+#define AB9540_PIN_B18 ABX500_GPIO(10)
+#define AB9540_PIN_C18 ABX500_GPIO(11)
+/* hole */
+#define AB9540_PIN_D18 ABX500_GPIO(13)
+#define AB9540_PIN_B19 ABX500_GPIO(14)
+#define AB9540_PIN_C19 ABX500_GPIO(15)
+#define AB9540_PIN_D19 ABX500_GPIO(16)
+#define AB9540_PIN_R3 ABX500_GPIO(17)
+#define AB9540_PIN_T2 ABX500_GPIO(18)
+#define AB9540_PIN_U2 ABX500_GPIO(19)
+#define AB9540_PIN_V2 ABX500_GPIO(20)
+#define AB9540_PIN_N17 ABX500_GPIO(21)
+#define AB9540_PIN_N16 ABX500_GPIO(22)
+#define AB9540_PIN_M19 ABX500_GPIO(23)
+#define AB9540_PIN_T3 ABX500_GPIO(24)
+#define AB9540_PIN_W2 ABX500_GPIO(25)
+/* hole */
+#define AB9540_PIN_H4 ABX500_GPIO(27)
+#define AB9540_PIN_F1 ABX500_GPIO(28)
+#define AB9540_PIN_F4 ABX500_GPIO(29)
+#define AB9540_PIN_F2 ABX500_GPIO(30)
+#define AB9540_PIN_E4 ABX500_GPIO(31)
+#define AB9540_PIN_F3 ABX500_GPIO(32)
+/* hole */
+#define AB9540_PIN_J13 ABX500_GPIO(34)
+/* hole */
+#define AB9540_PIN_L17 ABX500_GPIO(40)
+#define AB9540_PIN_L16 ABX500_GPIO(41)
+#define AB9540_PIN_W3 ABX500_GPIO(42)
+#define AB9540_PIN_N4 ABX500_GPIO(50)
+#define AB9540_PIN_G12 ABX500_GPIO(51)
+#define AB9540_PIN_E17 ABX500_GPIO(52)
+#define AB9540_PIN_D11 ABX500_GPIO(53)
+#define AB9540_PIN_M18 ABX500_GPIO(54)
+
+/* indicates the highest GPIO number */
+#define AB9540_GPIO_MAX_NUMBER 54
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc ab9540_pins[] = {
+ PINCTRL_PIN(AB9540_PIN_R4, "GPIO1_R4"),
+ PINCTRL_PIN(AB9540_PIN_V3, "GPIO2_V3"),
+ PINCTRL_PIN(AB9540_PIN_T4, "GPIO3_T4"),
+ PINCTRL_PIN(AB9540_PIN_T5, "GPIO4_T5"),
+ /* hole */
+ PINCTRL_PIN(AB9540_PIN_B18, "GPIO10_B18"),
+ PINCTRL_PIN(AB9540_PIN_C18, "GPIO11_C18"),
+ /* hole */
+ PINCTRL_PIN(AB9540_PIN_D18, "GPIO13_D18"),
+ PINCTRL_PIN(AB9540_PIN_B19, "GPIO14_B19"),
+ PINCTRL_PIN(AB9540_PIN_C19, "GPIO15_C19"),
+ PINCTRL_PIN(AB9540_PIN_D19, "GPIO16_D19"),
+ PINCTRL_PIN(AB9540_PIN_R3, "GPIO17_R3"),
+ PINCTRL_PIN(AB9540_PIN_T2, "GPIO18_T2"),
+ PINCTRL_PIN(AB9540_PIN_U2, "GPIO19_U2"),
+ PINCTRL_PIN(AB9540_PIN_V2, "GPIO20_V2"),
+ PINCTRL_PIN(AB9540_PIN_N17, "GPIO21_N17"),
+ PINCTRL_PIN(AB9540_PIN_N16, "GPIO22_N16"),
+ PINCTRL_PIN(AB9540_PIN_M19, "GPIO23_M19"),
+ PINCTRL_PIN(AB9540_PIN_T3, "GPIO24_T3"),
+ PINCTRL_PIN(AB9540_PIN_W2, "GPIO25_W2"),
+ /* hole */
+ PINCTRL_PIN(AB9540_PIN_H4, "GPIO27_H4"),
+ PINCTRL_PIN(AB9540_PIN_F1, "GPIO28_F1"),
+ PINCTRL_PIN(AB9540_PIN_F4, "GPIO29_F4"),
+ PINCTRL_PIN(AB9540_PIN_F2, "GPIO30_F2"),
+ PINCTRL_PIN(AB9540_PIN_E4, "GPIO31_E4"),
+ PINCTRL_PIN(AB9540_PIN_F3, "GPIO32_F3"),
+ /* hole */
+ PINCTRL_PIN(AB9540_PIN_J13, "GPIO34_J13"),
+ /* hole */
+ PINCTRL_PIN(AB9540_PIN_L17, "GPIO40_L17"),
+ PINCTRL_PIN(AB9540_PIN_L16, "GPIO41_L16"),
+ PINCTRL_PIN(AB9540_PIN_W3, "GPIO42_W3"),
+ PINCTRL_PIN(AB9540_PIN_N4, "GPIO50_N4"),
+ PINCTRL_PIN(AB9540_PIN_G12, "GPIO51_G12"),
+ PINCTRL_PIN(AB9540_PIN_E17, "GPIO52_E17"),
+ PINCTRL_PIN(AB9540_PIN_D11, "GPIO53_D11"),
+ PINCTRL_PIN(AB9540_PIN_M18, "GPIO60_M18"),
+};
+
+/*
+ * Maps local GPIO offsets to local pin numbers
+ */
+static const struct abx500_pinrange ab9540_pinranges[] = {
+ ABX500_PINRANGE(1, 4, ABX500_ALT_A),
+ ABX500_PINRANGE(10, 2, ABX500_DEFAULT),
+ ABX500_PINRANGE(13, 1, ABX500_DEFAULT),
+ ABX500_PINRANGE(14, 12, ABX500_ALT_A),
+ ABX500_PINRANGE(27, 6, ABX500_ALT_A),
+ ABX500_PINRANGE(34, 1, ABX500_ALT_A),
+ ABX500_PINRANGE(40, 3, ABX500_ALT_A),
+ ABX500_PINRANGE(50, 1, ABX500_DEFAULT),
+ ABX500_PINRANGE(51, 3, ABX500_ALT_A),
+ ABX500_PINRANGE(54, 1, ABX500_DEFAULT),
+};
+
+/*
+ * Read the pin group names like this:
+ * sysclkreq2_d_1 = first groups of pins for sysclkreq2 on default function
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* default column */
+static const unsigned sysclkreq2_d_1_pins[] = { AB9540_PIN_R4 };
+static const unsigned sysclkreq3_d_1_pins[] = { AB9540_PIN_V3 };
+static const unsigned sysclkreq4_d_1_pins[] = { AB9540_PIN_T4 };
+static const unsigned sysclkreq6_d_1_pins[] = { AB9540_PIN_T5 };
+static const unsigned gpio10_d_1_pins[] = { AB9540_PIN_B18 };
+static const unsigned gpio11_d_1_pins[] = { AB9540_PIN_C18 };
+static const unsigned gpio13_d_1_pins[] = { AB9540_PIN_D18 };
+static const unsigned pwmout1_d_1_pins[] = { AB9540_PIN_B19 };
+static const unsigned pwmout2_d_1_pins[] = { AB9540_PIN_C19 };
+static const unsigned pwmout3_d_1_pins[] = { AB9540_PIN_D19 };
+/* audio data interface 1*/
+static const unsigned adi1_d_1_pins[] = { AB9540_PIN_R3, AB9540_PIN_T2,
+ AB9540_PIN_U2, AB9540_PIN_V2 };
+/* USBUICC */
+static const unsigned usbuicc_d_1_pins[] = { AB9540_PIN_N17, AB9540_PIN_N16,
+ AB9540_PIN_M19 };
+static const unsigned sysclkreq7_d_1_pins[] = { AB9540_PIN_T3 };
+static const unsigned sysclkreq8_d_1_pins[] = { AB9540_PIN_W2 };
+/* Digital microphone 1 and 2 */
+static const unsigned dmic12_d_1_pins[] = { AB9540_PIN_H4, AB9540_PIN_F1 };
+/* Digital microphone 3 and 4 */
+static const unsigned dmic34_d_1_pins[] = { AB9540_PIN_F4, AB9540_PIN_F2 };
+/* Digital microphone 5 and 6 */
+static const unsigned dmic56_d_1_pins[] = { AB9540_PIN_E4, AB9540_PIN_F3 };
+static const unsigned extcpena_d_1_pins[] = { AB9540_PIN_J13 };
+/* modem SDA/SCL */
+static const unsigned modsclsda_d_1_pins[] = { AB9540_PIN_L17, AB9540_PIN_L16 };
+static const unsigned sysclkreq5_d_1_pins[] = { AB9540_PIN_W3 };
+static const unsigned gpio50_d_1_pins[] = { AB9540_PIN_N4 };
+static const unsigned batremn_d_1_pins[] = { AB9540_PIN_G12 };
+static const unsigned resethw_d_1_pins[] = { AB9540_PIN_E17 };
+static const unsigned service_d_1_pins[] = { AB9540_PIN_D11 };
+static const unsigned gpio60_d_1_pins[] = { AB9540_PIN_M18 };
+
+/* Altfunction A column */
+static const unsigned gpio1_a_1_pins[] = { AB9540_PIN_R4 };
+static const unsigned gpio2_a_1_pins[] = { AB9540_PIN_V3 };
+static const unsigned gpio3_a_1_pins[] = { AB9540_PIN_T4 };
+static const unsigned gpio4_a_1_pins[] = { AB9540_PIN_T5 };
+static const unsigned hiqclkena_a_1_pins[] = { AB9540_PIN_B18 };
+static const unsigned pdmclk_a_1_pins[] = { AB9540_PIN_C18 };
+static const unsigned uartdata_a_1_pins[] = { AB9540_PIN_D18, AB9540_PIN_N4 };
+static const unsigned gpio14_a_1_pins[] = { AB9540_PIN_B19 };
+static const unsigned gpio15_a_1_pins[] = { AB9540_PIN_C19 };
+static const unsigned gpio16_a_1_pins[] = { AB9540_PIN_D19 };
+static const unsigned gpio17_a_1_pins[] = { AB9540_PIN_R3 };
+static const unsigned gpio18_a_1_pins[] = { AB9540_PIN_T2 };
+static const unsigned gpio19_a_1_pins[] = { AB9540_PIN_U2 };
+static const unsigned gpio20_a_1_pins[] = { AB9540_PIN_V2 };
+static const unsigned gpio21_a_1_pins[] = { AB9540_PIN_N17 };
+static const unsigned gpio22_a_1_pins[] = { AB9540_PIN_N16 };
+static const unsigned gpio23_a_1_pins[] = { AB9540_PIN_M19 };
+static const unsigned gpio24_a_1_pins[] = { AB9540_PIN_T3 };
+static const unsigned gpio25_a_1_pins[] = { AB9540_PIN_W2 };
+static const unsigned gpio27_a_1_pins[] = { AB9540_PIN_H4 };
+static const unsigned gpio28_a_1_pins[] = { AB9540_PIN_F1 };
+static const unsigned gpio29_a_1_pins[] = { AB9540_PIN_F4 };
+static const unsigned gpio30_a_1_pins[] = { AB9540_PIN_F2 };
+static const unsigned gpio31_a_1_pins[] = { AB9540_PIN_E4 };
+static const unsigned gpio32_a_1_pins[] = { AB9540_PIN_F3 };
+static const unsigned gpio34_a_1_pins[] = { AB9540_PIN_J13 };
+static const unsigned gpio40_a_1_pins[] = { AB9540_PIN_L17 };
+static const unsigned gpio41_a_1_pins[] = { AB9540_PIN_L16 };
+static const unsigned gpio42_a_1_pins[] = { AB9540_PIN_W3 };
+static const unsigned gpio51_a_1_pins[] = { AB9540_PIN_G12 };
+static const unsigned gpio52_a_1_pins[] = { AB9540_PIN_E17 };
+static const unsigned gpio53_a_1_pins[] = { AB9540_PIN_D11 };
+static const unsigned usbuiccpd_a_1_pins[] = { AB9540_PIN_M18 };
+
+/* Altfunction B colum */
+static const unsigned pdmdata_b_1_pins[] = { AB9540_PIN_B18 };
+static const unsigned pwmextvibra1_b_1_pins[] = { AB9540_PIN_D18 };
+static const unsigned pwmextvibra2_b_1_pins[] = { AB9540_PIN_N4 };
+
+/* Altfunction C column */
+static const unsigned usbvdat_c_1_pins[] = { AB9540_PIN_D18 };
+
+#define AB9540_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \
+ .npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct abx500_pingroup ab9540_groups[] = {
+ /* default column */
+ AB9540_PIN_GROUP(sysclkreq2_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(sysclkreq3_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(sysclkreq4_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(sysclkreq6_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(gpio10_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(gpio11_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(gpio13_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(pwmout1_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(pwmout2_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(pwmout3_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(adi1_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(usbuicc_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(sysclkreq7_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(sysclkreq8_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(dmic12_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(dmic34_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(dmic56_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(extcpena_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(modsclsda_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(sysclkreq5_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(gpio50_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(batremn_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(resethw_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(service_d_1, ABX500_DEFAULT),
+ AB9540_PIN_GROUP(gpio60_d_1, ABX500_DEFAULT),
+
+ /* Altfunction A column */
+ AB9540_PIN_GROUP(gpio1_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio2_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio3_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio4_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(hiqclkena_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(pdmclk_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(uartdata_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio14_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio15_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio16_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio17_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio18_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio19_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio20_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio21_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio22_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio23_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio24_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio25_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio27_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio28_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio29_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio30_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio31_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio32_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio34_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio40_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio41_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio42_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio51_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio52_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(gpio53_a_1, ABX500_ALT_A),
+ AB9540_PIN_GROUP(usbuiccpd_a_1, ABX500_ALT_A),
+
+ /* Altfunction B column */
+ AB9540_PIN_GROUP(pdmdata_b_1, ABX500_ALT_B),
+ AB9540_PIN_GROUP(pwmextvibra1_b_1, ABX500_ALT_B),
+ AB9540_PIN_GROUP(pwmextvibra2_b_1, ABX500_ALT_B),
+
+ /* Altfunction C column */
+ AB9540_PIN_GROUP(usbvdat_c_1, ABX500_ALT_C),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define AB9540_FUNC_GROUPS(a, b...) \
+static const char * const a##_groups[] = { b };
+
+AB9540_FUNC_GROUPS(sysclkreq, "sysclkreq2_d_1", "sysclkreq3_d_1",
+ "sysclkreq4_d_1", "sysclkreq5_d_1", "sysclkreq6_d_1",
+ "sysclkreq7_d_1", "sysclkreq8_d_1");
+AB9540_FUNC_GROUPS(gpio, "gpio1_a_1", "gpio2_a_1", "gpio3_a_1", "gpio4_a_1",
+ "gpio10_d_1", "gpio11_d_1", "gpio13_d_1", "gpio14_a_1",
+ "gpio15_a_1", "gpio16_a_1", "gpio17_a_1", "gpio18_a_1",
+ "gpio19_a_1", "gpio20_a_1", "gpio21_a_1", "gpio22_a_1",
+ "gpio23_a_1", "gpio24_a_1", "gpio25_a_1", "gpio27_a_1",
+ "gpio28_a_1", "gpio29_a_1", "gpio30_a_1", "gpio31_a_1",
+ "gpio32_a_1", "gpio34_a_1", "gpio40_a_1", "gpio41_a_1",
+ "gpio42_a_1", "gpio50_d_1", "gpio51_a_1", "gpio52_a_1",
+ "gpio53_a_1", "gpio60_d_1");
+AB9540_FUNC_GROUPS(pwmout, "pwmout1_d_1", "pwmout2_d_1", "pwmout3_d_1");
+AB9540_FUNC_GROUPS(adi1, "adi1_d_1");
+AB9540_FUNC_GROUPS(usbuicc, "usbuicc_d_1", "usbuiccpd_a_1");
+AB9540_FUNC_GROUPS(dmic, "dmic12_d_1", "dmic34_d_1", "dmic56_d_1");
+AB9540_FUNC_GROUPS(extcpena, "extcpena_d_1");
+AB9540_FUNC_GROUPS(modsclsda, "modsclsda_d_1");
+AB9540_FUNC_GROUPS(batremn, "batremn_d_1");
+AB9540_FUNC_GROUPS(resethw, "resethw_d_1");
+AB9540_FUNC_GROUPS(service, "service_d_1");
+AB9540_FUNC_GROUPS(hiqclkena, "hiqclkena_a_1");
+AB9540_FUNC_GROUPS(pdm, "pdmdata_b_1", "pdmclk_a_1");
+AB9540_FUNC_GROUPS(uartdata, "uartdata_a_1");
+AB9540_FUNC_GROUPS(pwmextvibra, "pwmextvibra1_b_1", "pwmextvibra2_b_1");
+AB9540_FUNC_GROUPS(usbvdat, "usbvdat_c_1");
+
+#define FUNCTION(fname) \
+ { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+static const struct abx500_function ab9540_functions[] = {
+ FUNCTION(sysclkreq),
+ FUNCTION(gpio),
+ FUNCTION(pwmout),
+ FUNCTION(adi1),
+ FUNCTION(usbuicc),
+ FUNCTION(dmic),
+ FUNCTION(extcpena),
+ FUNCTION(modsclsda),
+ FUNCTION(batremn),
+ FUNCTION(resethw),
+ FUNCTION(service),
+ FUNCTION(hiqclkena),
+ FUNCTION(pdm),
+ FUNCTION(uartdata),
+ FUNCTION(pwmextvibra),
+ FUNCTION(usbvdat),
+};
+
+/*
+ * this table translates what's is in the AB9540 specification regarding the
+ * balls alternate functions (as for DB, default, ALT_A, ALT_B and ALT_C).
+ * ALTERNATE_FUNCTIONS(GPIO_NUMBER, GPIOSEL bit, ALTERNATFUNC bit1,
+ * ALTERNATEFUNC bit2, ALTA val, ALTB val, ALTC val),
+ *
+ * example :
+ *
+ * ALTERNATE_FUNCTIONS(13, 4, 3, 4, 1, 0, 2),
+ * means that pin AB9540_PIN_D18 (pin 13) supports 4 mux (default/ALT_A,
+ * ALT_B and ALT_C), so GPIOSEL and ALTERNATFUNC registers are used to
+ * select the mux. ALTA, ALTB and ALTC val indicates values to write in
+ * ALTERNATFUNC register. We need to specifies these values as SOC
+ * designers didn't apply the same logic on how to select mux in the
+ * ABx500 family.
+ *
+ * As this pins supports at least ALT_B mux, default mux is
+ * selected by writing 1 in GPIOSEL bit :
+ *
+ * | GPIOSEL bit=4 | alternatfunc bit2=4 | alternatfunc bit1=3
+ * default | 1 | 0 | 0
+ * alt_A | 0 | 0 | 1
+ * alt_B | 0 | 0 | 0
+ * alt_C | 0 | 1 | 0
+ *
+ * ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED),
+ * means that pin AB9540_PIN_R4 (pin 1) supports 2 mux, so only GPIOSEL
+ * register is used to select the mux. As this pins doesn't support at
+ * least ALT_B mux, default mux is by writing 0 in GPIOSEL bit :
+ *
+ * | GPIOSEL bit=0 | alternatfunc bit2= | alternatfunc bit1=
+ * default | 0 | 0 | 0
+ * alt_A | 1 | 0 | 0
+ */
+
+struct alternate_functions ab9540alternate_functions[AB9540_GPIO_MAX_NUMBER + 1] = {
+ /* GPIOSEL1 - bits 4-7 are reserved */
+ ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
+ ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(2, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(3, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO3, altA controlled by bit 2*/
+ ALTERNATE_FUNCTIONS(4, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO4, altA controlled by bit 3*/
+ ALTERNATE_FUNCTIONS(5, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO5 */
+ ALTERNATE_FUNCTIONS(6, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO6 */
+ ALTERNATE_FUNCTIONS(7, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO7 */
+ ALTERNATE_FUNCTIONS(8, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO8 */
+ /* GPIOSEL2 - bits 0 and 3 are reserved */
+ ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9 */
+ ALTERNATE_FUNCTIONS(10, 1, 0, UNUSED, 1, 0, 0), /* GPIO10, altA and altB controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(11, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12 */
+ ALTERNATE_FUNCTIONS(13, 4, 3, 4, 1, 0, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
+ ALTERNATE_FUNCTIONS(14, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(15, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO15, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(16, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO16, altA controlled by bit 7 */
+ /* GPIOSEL3 - bit 1-3 reserved
+ * pins 17 to 20 are special case, only bit 0 is used to select
+ * alternate function for these 4 pins.
+ * bits 1 to 3 are reserved
+ */
+ ALTERNATE_FUNCTIONS(17, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO17, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(18, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO18, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(19, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO19, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(20, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO20, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(21, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO21, altA controlled by bit 4 */
+ ALTERNATE_FUNCTIONS(22, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO22, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(23, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO23, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(24, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO24, altA controlled by bit 7 */
+ /* GPIOSEL4 - bit 1 reserved */
+ ALTERNATE_FUNCTIONS(25, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO25, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(26, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO26 */
+ ALTERNATE_FUNCTIONS(27, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO27, altA controlled by bit 2 */
+ ALTERNATE_FUNCTIONS(28, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO28, altA controlled by bit 3 */
+ ALTERNATE_FUNCTIONS(29, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO29, altA controlled by bit 4 */
+ ALTERNATE_FUNCTIONS(30, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO30, altA controlled by bit 5 */
+ ALTERNATE_FUNCTIONS(31, 6, UNUSED, UNUSED, 0, 0, 0), /* GPIO31, altA controlled by bit 6 */
+ ALTERNATE_FUNCTIONS(32, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO32, altA controlled by bit 7 */
+ /* GPIOSEL5 - bit 0, 2-6 are reserved */
+ ALTERNATE_FUNCTIONS(33, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO33 */
+ ALTERNATE_FUNCTIONS(34, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO34, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(35, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO35 */
+ ALTERNATE_FUNCTIONS(36, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO36 */
+ ALTERNATE_FUNCTIONS(37, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO37 */
+ ALTERNATE_FUNCTIONS(38, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO38 */
+ ALTERNATE_FUNCTIONS(39, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO39 */
+ ALTERNATE_FUNCTIONS(40, 7, UNUSED, UNUSED, 0, 0, 0), /* GPIO40, altA controlled by bit 7 */
+ /* GPIOSEL6 - bit 2-7 are reserved */
+ ALTERNATE_FUNCTIONS(41, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO41, altA controlled by bit 0 */
+ ALTERNATE_FUNCTIONS(42, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO42, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(43, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO43 */
+ ALTERNATE_FUNCTIONS(44, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO44 */
+ ALTERNATE_FUNCTIONS(45, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO45 */
+ ALTERNATE_FUNCTIONS(46, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO46 */
+ ALTERNATE_FUNCTIONS(47, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO47 */
+ ALTERNATE_FUNCTIONS(48, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO48 */
+ /*
+ * GPIOSEL7 - bit 0 and 6-7 are reserved
+ * special case with GPIO60, wich is located at offset 5 of gpiosel7
+ * don't know why it has been called GPIO60 in AB9540 datasheet,
+ * GPIO54 would be logical..., so at SOC point of view we consider
+ * GPIO60 = GPIO54
+ */
+ ALTERNATE_FUNCTIONS(49, 0, UNUSED, UNUSED, 0, 0, 0), /* no GPIO49 */
+ ALTERNATE_FUNCTIONS(50, 1, 2, UNUSED, 1, 0, 0), /* GPIO50, altA and altB controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(51, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO51, altA controlled by bit 2 */
+ ALTERNATE_FUNCTIONS(52, 3, UNUSED, UNUSED, 0, 0, 0), /* GPIO52, altA controlled by bit 3 */
+ ALTERNATE_FUNCTIONS(53, 4, UNUSED, UNUSED, 0, 0, 0), /* GPIO53, altA controlled by bit 4 */
+ ALTERNATE_FUNCTIONS(54, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO54 = GPIO60, altA controlled by bit 5 */
+};
+
+struct abx500_gpio_irq_cluster ab9540_gpio_irq_cluster[] = {
+ GPIO_IRQ_CLUSTER(10, 13, AB8500_INT_GPIO10R),
+ GPIO_IRQ_CLUSTER(24, 25, AB8500_INT_GPIO24R),
+ GPIO_IRQ_CLUSTER(40, 41, AB8500_INT_GPIO40R),
+ GPIO_IRQ_CLUSTER(50, 54, AB9540_INT_GPIO50R),
+};
+
+static struct abx500_pinctrl_soc_data ab9540_soc = {
+ .gpio_ranges = ab9540_pinranges,
+ .gpio_num_ranges = ARRAY_SIZE(ab9540_pinranges),
+ .pins = ab9540_pins,
+ .npins = ARRAY_SIZE(ab9540_pins),
+ .functions = ab9540_functions,
+ .nfunctions = ARRAY_SIZE(ab9540_functions),
+ .groups = ab9540_groups,
+ .ngroups = ARRAY_SIZE(ab9540_groups),
+ .alternate_functions = ab9540alternate_functions,
+ .gpio_irq_cluster = ab9540_gpio_irq_cluster,
+ .ngpio_irq_cluster = ARRAY_SIZE(ab9540_gpio_irq_cluster),
+ .irq_gpio_rising_offset = AB8500_INT_GPIO6R,
+ .irq_gpio_falling_offset = AB8500_INT_GPIO6F,
+ .irq_gpio_factor = 1,
+};
+
+void
+abx500_pinctrl_ab9540_init(struct abx500_pinctrl_soc_data **soc)
+{
+ *soc = &ab9540_soc;
+}
diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c
new file mode 100644
index 000000000000..caecdd373061
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-abx500.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2013
+ *
+ * Author: Patrice Chotard <patrice.chotard@st.com>
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * 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/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+#include "pinctrl-abx500.h"
+
+/*
+ * The AB9540 and AB8540 GPIO support are extended versions
+ * of the AB8500 GPIO support.
+ * The AB9540 supports an additional (7th) register so that
+ * more GPIO may be configured and used.
+ * The AB8540 supports 4 new gpios (GPIOx_VBAT) that have
+ * internal pull-up and pull-down capabilities.
+ */
+
+/*
+ * GPIO registers offset
+ * Bank: 0x10
+ */
+#define AB8500_GPIO_SEL1_REG 0x00
+#define AB8500_GPIO_SEL2_REG 0x01
+#define AB8500_GPIO_SEL3_REG 0x02
+#define AB8500_GPIO_SEL4_REG 0x03
+#define AB8500_GPIO_SEL5_REG 0x04
+#define AB8500_GPIO_SEL6_REG 0x05
+#define AB9540_GPIO_SEL7_REG 0x06
+
+#define AB8500_GPIO_DIR1_REG 0x10
+#define AB8500_GPIO_DIR2_REG 0x11
+#define AB8500_GPIO_DIR3_REG 0x12
+#define AB8500_GPIO_DIR4_REG 0x13
+#define AB8500_GPIO_DIR5_REG 0x14
+#define AB8500_GPIO_DIR6_REG 0x15
+#define AB9540_GPIO_DIR7_REG 0x16
+
+#define AB8500_GPIO_OUT1_REG 0x20
+#define AB8500_GPIO_OUT2_REG 0x21
+#define AB8500_GPIO_OUT3_REG 0x22
+#define AB8500_GPIO_OUT4_REG 0x23
+#define AB8500_GPIO_OUT5_REG 0x24
+#define AB8500_GPIO_OUT6_REG 0x25
+#define AB9540_GPIO_OUT7_REG 0x26
+
+#define AB8500_GPIO_PUD1_REG 0x30
+#define AB8500_GPIO_PUD2_REG 0x31
+#define AB8500_GPIO_PUD3_REG 0x32
+#define AB8500_GPIO_PUD4_REG 0x33
+#define AB8500_GPIO_PUD5_REG 0x34
+#define AB8500_GPIO_PUD6_REG 0x35
+#define AB9540_GPIO_PUD7_REG 0x36
+
+#define AB8500_GPIO_IN1_REG 0x40
+#define AB8500_GPIO_IN2_REG 0x41
+#define AB8500_GPIO_IN3_REG 0x42
+#define AB8500_GPIO_IN4_REG 0x43
+#define AB8500_GPIO_IN5_REG 0x44
+#define AB8500_GPIO_IN6_REG 0x45
+#define AB9540_GPIO_IN7_REG 0x46
+#define AB8540_GPIO_VINSEL_REG 0x47
+#define AB8540_GPIO_PULL_UPDOWN_REG 0x48
+#define AB8500_GPIO_ALTFUN_REG 0x50
+#define AB8540_GPIO_PULL_UPDOWN_MASK 0x03
+#define AB8540_GPIO_VINSEL_MASK 0x03
+#define AB8540_GPIOX_VBAT_START 51
+#define AB8540_GPIOX_VBAT_END 54
+
+struct abx500_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctldev;
+ struct abx500_pinctrl_soc_data *soc;
+ struct gpio_chip chip;
+ struct ab8500 *parent;
+ struct mutex lock;
+ struct abx500_gpio_irq_cluster *irq_cluster;
+ int irq_cluster_size;
+};
+
+/**
+ * to_abx500_pinctrl() - get the pointer to abx500_pinctrl
+ * @chip: Member of the structure abx500_pinctrl
+ */
+static inline struct abx500_pinctrl *to_abx500_pinctrl(struct gpio_chip *chip)
+{
+ return container_of(chip, struct abx500_pinctrl, chip);
+}
+
+static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
+ unsigned offset, bool *bit)
+{
+ struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ u8 pos = offset % 8;
+ u8 val;
+ int ret;
+
+ reg += offset / 8;
+ ret = abx500_get_register_interruptible(pct->dev,
+ AB8500_MISC, reg, &val);
+
+ *bit = !!(val & BIT(pos));
+
+ if (ret < 0)
+ dev_err(pct->dev,
+ "%s read reg =%x, offset=%x failed\n",
+ __func__, reg, offset);
+
+ return ret;
+}
+
+static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
+ unsigned offset, int val)
+{
+ struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ u8 pos = offset % 8;
+ int ret;
+
+ reg += offset / 8;
+ ret = abx500_mask_and_set_register_interruptible(pct->dev,
+ AB8500_MISC, reg, BIT(pos), val << pos);
+ if (ret < 0)
+ dev_err(pct->dev, "%s write failed\n", __func__);
+
+ return ret;
+}
+
+/**
+ * abx500_gpio_get() - Get the particular GPIO value
+ * @chip: Gpio device
+ * @offset: GPIO number to read
+ */
+static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ bool bit;
+ int ret;
+
+ ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG,
+ offset, &bit);
+ if (ret < 0) {
+ dev_err(pct->dev, "%s failed\n", __func__);
+ return ret;
+ }
+
+ return bit;
+}
+
+static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ int ret;
+
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
+ if (ret < 0)
+ dev_err(pct->dev, "%s write failed\n", __func__);
+}
+
+static int abx500_config_pull_updown(struct abx500_pinctrl *pct,
+ int offset, enum abx500_gpio_pull_updown val)
+{
+ u8 pos;
+ int ret;
+ struct pullud *pullud;
+
+ if (!pct->soc->pullud) {
+ dev_err(pct->dev, "%s AB chip doesn't support pull up/down feature",
+ __func__);
+ ret = -EPERM;
+ goto out;
+ }
+
+ pullud = pct->soc->pullud;
+
+ if ((offset < pullud->first_pin)
+ || (offset > pullud->last_pin)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pos = offset << 1;
+
+ ret = abx500_mask_and_set_register_interruptible(pct->dev,
+ AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG,
+ AB8540_GPIO_PULL_UPDOWN_MASK << pos, val << pos);
+
+out:
+ if (ret < 0)
+ dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+
+ return ret;
+}
+
+static int abx500_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset,
+ int val)
+{
+ struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct pullud *pullud = pct->soc->pullud;
+ unsigned gpio;
+ int ret;
+
+ /* set direction as output */
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
+ if (ret < 0)
+ return ret;
+
+ /* disable pull down */
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
+ if (ret < 0)
+ return ret;
+
+ /* if supported, disable both pull down and pull up */
+ gpio = offset + 1;
+ if (pullud && gpio >= pullud->first_pin && gpio <= pullud->last_pin) {
+ ret = abx500_config_pull_updown(pct,
+ gpio,
+ ABX500_GPIO_PULL_NONE);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* set the output as 1 or 0 */
+ return abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
+}
+
+static int abx500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ /* set the register as input */
+ return abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
+}
+
+static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ /* The AB8500 GPIO numbers are off by one */
+ int gpio = offset + 1;
+ int hwirq;
+ int i;
+
+ for (i = 0; i < pct->irq_cluster_size; i++) {
+ struct abx500_gpio_irq_cluster *cluster =
+ &pct->irq_cluster[i];
+
+ if (gpio >= cluster->start && gpio <= cluster->end) {
+ /*
+ * The ABx500 GPIO's associated IRQs are clustered together
+ * throughout the interrupt numbers at irregular intervals.
+ * To solve this quandry, we have placed the read-in values
+ * into the cluster information table.
+ */
+ hwirq = gpio - cluster->start + cluster->to_irq;
+ return irq_create_mapping(pct->parent->domain, hwirq);
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+ unsigned gpio, int alt_setting)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+ struct alternate_functions af = pct->soc->alternate_functions[gpio];
+ int ret;
+ int val;
+ unsigned offset;
+
+ const char *modes[] = {
+ [ABX500_DEFAULT] = "default",
+ [ABX500_ALT_A] = "altA",
+ [ABX500_ALT_B] = "altB",
+ [ABX500_ALT_C] = "altC",
+ };
+
+ /* sanity check */
+ if (((alt_setting == ABX500_ALT_A) && (af.gpiosel_bit == UNUSED)) ||
+ ((alt_setting == ABX500_ALT_B) && (af.alt_bit1 == UNUSED)) ||
+ ((alt_setting == ABX500_ALT_C) && (af.alt_bit2 == UNUSED))) {
+ dev_dbg(pct->dev, "pin %d doesn't support %s mode\n", gpio,
+ modes[alt_setting]);
+ return -EINVAL;
+ }
+
+ /* on ABx5xx, there is no GPIO0, so adjust the offset */
+ offset = gpio - 1;
+
+ switch (alt_setting) {
+ case ABX500_DEFAULT:
+ /*
+ * for ABx5xx family, default mode is always selected by
+ * writing 0 to GPIOSELx register, except for pins which
+ * support at least ALT_B mode, default mode is selected
+ * by writing 1 to GPIOSELx register
+ */
+ val = 0;
+ if (af.alt_bit1 != UNUSED)
+ val++;
+
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+ offset, val);
+ break;
+
+ case ABX500_ALT_A:
+ /*
+ * for ABx5xx family, alt_a mode is always selected by
+ * writing 1 to GPIOSELx register, except for pins which
+ * support at least ALT_B mode, alt_a mode is selected
+ * by writing 0 to GPIOSELx register and 0 in ALTFUNC
+ * register
+ */
+ if (af.alt_bit1 != UNUSED) {
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+ offset, 0);
+ ret = abx500_gpio_set_bits(chip,
+ AB8500_GPIO_ALTFUN_REG,
+ af.alt_bit1,
+ !!(af.alta_val && BIT(0)));
+ if (af.alt_bit2 != UNUSED)
+ ret = abx500_gpio_set_bits(chip,
+ AB8500_GPIO_ALTFUN_REG,
+ af.alt_bit2,
+ !!(af.alta_val && BIT(1)));
+ } else
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+ offset, 1);
+ break;
+
+ case ABX500_ALT_B:
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+ offset, 0);
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+ af.alt_bit1, !!(af.altb_val && BIT(0)));
+ if (af.alt_bit2 != UNUSED)
+ ret = abx500_gpio_set_bits(chip,
+ AB8500_GPIO_ALTFUN_REG,
+ af.alt_bit2,
+ !!(af.altb_val && BIT(1)));
+ break;
+
+ case ABX500_ALT_C:
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+ offset, 0);
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+ af.alt_bit2, !!(af.altc_val && BIT(0)));
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+ af.alt_bit2, !!(af.altc_val && BIT(1)));
+ break;
+
+ default:
+ dev_dbg(pct->dev, "unknow alt_setting %d\n", alt_setting);
+
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+ unsigned gpio)
+{
+ u8 mode;
+ bool bit_mode;
+ bool alt_bit1;
+ bool alt_bit2;
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+ struct alternate_functions af = pct->soc->alternate_functions[gpio];
+ /* on ABx5xx, there is no GPIO0, so adjust the offset */
+ unsigned offset = gpio - 1;
+
+ /*
+ * if gpiosel_bit is set to unused,
+ * it means no GPIO or special case
+ */
+ if (af.gpiosel_bit == UNUSED)
+ return ABX500_DEFAULT;
+
+ /* read GpioSelx register */
+ abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8),
+ af.gpiosel_bit, &bit_mode);
+ mode = bit_mode;
+
+ /* sanity check */
+ if ((af.alt_bit1 < UNUSED) || (af.alt_bit1 > 7) ||
+ (af.alt_bit2 < UNUSED) || (af.alt_bit2 > 7)) {
+ dev_err(pct->dev,
+ "alt_bitX value not in correct range (-1 to 7)\n");
+ return -EINVAL;
+ }
+
+ /* if alt_bit2 is used, alt_bit1 must be used too */
+ if ((af.alt_bit2 != UNUSED) && (af.alt_bit1 == UNUSED)) {
+ dev_err(pct->dev,
+ "if alt_bit2 is used, alt_bit1 can't be unused\n");
+ return -EINVAL;
+ }
+
+ /* check if pin use AlternateFunction register */
+ if ((af.alt_bit1 == UNUSED) && (af.alt_bit1 == UNUSED))
+ return mode;
+ /*
+ * if pin GPIOSEL bit is set and pin supports alternate function,
+ * it means DEFAULT mode
+ */
+ if (mode)
+ return ABX500_DEFAULT;
+
+ /*
+ * pin use the AlternatFunction register
+ * read alt_bit1 value
+ */
+ abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
+ af.alt_bit1, &alt_bit1);
+
+ if (af.alt_bit2 != UNUSED)
+ /* read alt_bit2 value */
+ abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit2,
+ &alt_bit2);
+ else
+ alt_bit2 = 0;
+
+ mode = (alt_bit2 << 1) + alt_bit1;
+ if (mode == af.alta_val)
+ return ABX500_ALT_A;
+ else if (mode == af.altb_val)
+ return ABX500_ALT_B;
+ else
+ return ABX500_ALT_C;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+static void abx500_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev,
+ struct gpio_chip *chip,
+ unsigned offset, unsigned gpio)
+{
+ const char *label = gpiochip_is_requested(chip, offset - 1);
+ u8 gpio_offset = offset - 1;
+ int mode = -1;
+ bool is_out;
+ bool pull;
+
+ const char *modes[] = {
+ [ABX500_DEFAULT] = "default",
+ [ABX500_ALT_A] = "altA",
+ [ABX500_ALT_B] = "altB",
+ [ABX500_ALT_C] = "altC",
+ };
+
+ abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, gpio_offset, &is_out);
+ abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG, gpio_offset, &pull);
+
+ if (pctldev)
+ mode = abx500_get_mode(pctldev, chip, offset);
+
+ seq_printf(s, " gpio-%-3d (%-20.20s) %-3s %-9s %s",
+ gpio, label ?: "(none)",
+ is_out ? "out" : "in ",
+ is_out ?
+ (chip->get
+ ? (chip->get(chip, offset) ? "hi" : "lo")
+ : "? ")
+ : (pull ? "pull up" : "pull down"),
+ (mode < 0) ? "unknown" : modes[mode]);
+}
+
+static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ unsigned i;
+ unsigned gpio = chip->base;
+ struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+ struct pinctrl_dev *pctldev = pct->pctldev;
+
+ for (i = 0; i < chip->ngpio; i++, gpio++) {
+ /* On AB8500, there is no GPIO0, the first is the GPIO 1 */
+ abx500_gpio_dbg_show_one(s, pctldev, chip, i + 1, gpio);
+ seq_printf(s, "\n");
+ }
+}
+
+#else
+static inline void abx500_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev,
+ struct gpio_chip *chip,
+ unsigned offset, unsigned gpio)
+{
+}
+#define abx500_gpio_dbg_show NULL
+#endif
+
+int abx500_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ return pinctrl_request_gpio(gpio);
+}
+
+void abx500_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
+static struct gpio_chip abx500gpio_chip = {
+ .label = "abx500-gpio",
+ .owner = THIS_MODULE,
+ .request = abx500_gpio_request,
+ .free = abx500_gpio_free,
+ .direction_input = abx500_gpio_direction_input,
+ .get = abx500_gpio_get,
+ .direction_output = abx500_gpio_direction_output,
+ .set = abx500_gpio_set,
+ .to_irq = abx500_gpio_to_irq,
+ .dbg_show = abx500_gpio_dbg_show,
+};
+
+static int abx500_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+ return pct->soc->nfunctions;
+}
+
+static const char *abx500_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+ return pct->soc->functions[function].name;
+}
+
+static int abx500_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pct->soc->functions[function].groups;
+ *num_groups = pct->soc->functions[function].ngroups;
+
+ return 0;
+}
+
+static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
+ unsigned group)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+ struct gpio_chip *chip = &pct->chip;
+ const struct abx500_pingroup *g;
+ int i;
+ int ret = 0;
+
+ g = &pct->soc->groups[group];
+ if (g->altsetting < 0)
+ return -EINVAL;
+
+ dev_dbg(pct->dev, "enable group %s, %u pins\n", g->name, g->npins);
+
+ for (i = 0; i < g->npins; i++) {
+ dev_dbg(pct->dev, "setting pin %d to altsetting %d\n",
+ g->pins[i], g->altsetting);
+
+ ret = abx500_set_mode(pctldev, chip, g->pins[i], g->altsetting);
+ }
+
+ return ret;
+}
+
+static void abx500_pmx_disable(struct pinctrl_dev *pctldev,
+ unsigned function, unsigned group)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+ const struct abx500_pingroup *g;
+
+ g = &pct->soc->groups[group];
+ if (g->altsetting < 0)
+ return;
+
+ /* FIXME: poke out the mux, set the pin to some default state? */
+ dev_dbg(pct->dev, "disable group %s, %u pins\n", g->name, g->npins);
+}
+
+int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+ const struct abx500_pinrange *p;
+ int ret;
+ int i;
+
+ /*
+ * Different ranges have different ways to enable GPIO function on a
+ * pin, so refer back to our local range type, where we handily define
+ * what altfunc enables GPIO for a certain pin.
+ */
+ for (i = 0; i < pct->soc->gpio_num_ranges; i++) {
+ p = &pct->soc->gpio_ranges[i];
+ if ((offset >= p->offset) &&
+ (offset < (p->offset + p->npins)))
+ break;
+ }
+
+ if (i == pct->soc->gpio_num_ranges) {
+ dev_err(pct->dev, "%s failed to locate range\n", __func__);
+ return -ENODEV;
+ }
+
+ dev_dbg(pct->dev, "enable GPIO by altfunc %d at gpio %d\n",
+ p->altfunc, offset);
+
+ ret = abx500_set_mode(pct->pctldev, &pct->chip,
+ offset, p->altfunc);
+ if (ret < 0) {
+ dev_err(pct->dev, "%s setting altfunc failed\n", __func__);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void abx500_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+}
+
+static struct pinmux_ops abx500_pinmux_ops = {
+ .get_functions_count = abx500_pmx_get_funcs_cnt,
+ .get_function_name = abx500_pmx_get_func_name,
+ .get_function_groups = abx500_pmx_get_func_groups,
+ .enable = abx500_pmx_enable,
+ .disable = abx500_pmx_disable,
+ .gpio_request_enable = abx500_gpio_request_enable,
+ .gpio_disable_free = abx500_gpio_disable_free,
+};
+
+static int abx500_get_groups_cnt(struct pinctrl_dev *pctldev)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+ return pct->soc->ngroups;
+}
+
+static const char *abx500_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+ return pct->soc->groups[selector].name;
+}
+
+static int abx500_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = pct->soc->groups[selector].pins;
+ *num_pins = pct->soc->groups[selector].npins;
+
+ return 0;
+}
+
+static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned offset)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+ struct gpio_chip *chip = &pct->chip;
+
+ abx500_gpio_dbg_show_one(s, pctldev, chip, offset,
+ chip->base + offset - 1);
+}
+
+static struct pinctrl_ops abx500_pinctrl_ops = {
+ .get_groups_count = abx500_get_groups_cnt,
+ .get_group_name = abx500_get_group_name,
+ .get_group_pins = abx500_get_group_pins,
+ .pin_dbg_show = abx500_pin_dbg_show,
+};
+
+int abx500_pin_config_get(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long *config)
+{
+ return -ENOSYS;
+}
+
+int abx500_pin_config_set(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long config)
+{
+ struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+ struct pullud *pullud = pct->soc->pullud;
+ struct gpio_chip *chip = &pct->chip;
+ unsigned offset;
+ int ret;
+ enum pin_config_param param = pinconf_to_config_param(config);
+ enum pin_config_param argument = pinconf_to_config_argument(config);
+
+ dev_dbg(chip->dev, "pin %d [%#lx]: %s %s\n",
+ pin, config, (param == PIN_CONFIG_OUTPUT) ? "output " : "input",
+ (param == PIN_CONFIG_OUTPUT) ? (argument ? "high" : "low") :
+ (argument ? "pull up" : "pull down"));
+
+ /* on ABx500, there is no GPIO0, so adjust the offset */
+ offset = pin - 1;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ /*
+ * if argument = 1 set the pull down
+ * else clear the pull down
+ */
+ ret = abx500_gpio_direction_input(chip, offset);
+ /*
+ * Some chips only support pull down, while some actually
+ * support both pull up and pull down. Such chips have
+ * a "pullud" range specified for the pins that support
+ * both features. If the pin is not within that range, we
+ * fall back to the old bit set that only support pull down.
+ */
+ if (pullud &&
+ pin >= pullud->first_pin &&
+ pin <= pullud->last_pin)
+ ret = abx500_config_pull_updown(pct,
+ pin,
+ argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
+ else
+ /* Chip only supports pull down */
+ ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
+ offset, argument ? 0 : 1);
+ break;
+
+ case PIN_CONFIG_OUTPUT:
+ ret = abx500_gpio_direction_output(chip, offset, argument);
+
+ break;
+
+ default:
+ dev_err(chip->dev, "illegal configuration requested\n");
+
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct pinconf_ops abx500_pinconf_ops = {
+ .pin_config_get = abx500_pin_config_get,
+ .pin_config_set = abx500_pin_config_set,
+};
+
+static struct pinctrl_desc abx500_pinctrl_desc = {
+ .name = "pinctrl-abx500",
+ .pctlops = &abx500_pinctrl_ops,
+ .pmxops = &abx500_pinmux_ops,
+ .confops = &abx500_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static int abx500_get_gpio_num(struct abx500_pinctrl_soc_data *soc)
+{
+ unsigned int lowest = 0;
+ unsigned int highest = 0;
+ unsigned int npins = 0;
+ int i;
+
+ /*
+ * Compute number of GPIOs from the last SoC gpio range descriptors
+ * These ranges may include "holes" but the GPIO number space shall
+ * still be homogeneous, so we need to detect and account for any
+ * such holes so that these are included in the number of GPIO pins.
+ */
+ for (i = 0; i < soc->gpio_num_ranges; i++) {
+ unsigned gstart;
+ unsigned gend;
+ const struct abx500_pinrange *p;
+
+ p = &soc->gpio_ranges[i];
+ gstart = p->offset;
+ gend = p->offset + p->npins - 1;
+
+ if (i == 0) {
+ /* First iteration, set start values */
+ lowest = gstart;
+ highest = gend;
+ } else {
+ if (gstart < lowest)
+ lowest = gstart;
+ if (gend > highest)
+ highest = gend;
+ }
+ }
+ /* this gives the absolute number of pins */
+ npins = highest - lowest + 1;
+ return npins;
+}
+
+static const struct of_device_id abx500_gpio_match[] = {
+ { .compatible = "stericsson,ab8500-gpio", .data = (void *)PINCTRL_AB8500, },
+ { .compatible = "stericsson,ab8505-gpio", .data = (void *)PINCTRL_AB8505, },
+ { .compatible = "stericsson,ab8540-gpio", .data = (void *)PINCTRL_AB8540, },
+ { .compatible = "stericsson,ab9540-gpio", .data = (void *)PINCTRL_AB9540, },
+};
+
+static int abx500_gpio_probe(struct platform_device *pdev)
+{
+ struct ab8500_platform_data *abx500_pdata =
+ dev_get_platdata(pdev->dev.parent);
+ struct abx500_gpio_platform_data *pdata = NULL;
+ struct device_node *np = pdev->dev.of_node;
+ struct abx500_pinctrl *pct;
+ const struct platform_device_id *platid = platform_get_device_id(pdev);
+ unsigned int id = -1;
+ int ret, err;
+ int i;
+
+ if (abx500_pdata)
+ pdata = abx500_pdata->gpio;
+ if (!pdata) {
+ if (np) {
+ const struct of_device_id *match;
+
+ match = of_match_device(abx500_gpio_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
+ id = (unsigned long)match->data;
+ } else {
+ dev_err(&pdev->dev, "gpio dt and platform data missing\n");
+ return -ENODEV;
+ }
+ }
+
+ if (platid)
+ id = platid->driver_data;
+
+ pct = devm_kzalloc(&pdev->dev, sizeof(struct abx500_pinctrl),
+ GFP_KERNEL);
+ if (pct == NULL) {
+ dev_err(&pdev->dev,
+ "failed to allocate memory for pct\n");
+ return -ENOMEM;
+ }
+
+ pct->dev = &pdev->dev;
+ pct->parent = dev_get_drvdata(pdev->dev.parent);
+ pct->chip = abx500gpio_chip;
+ pct->chip.dev = &pdev->dev;
+ pct->chip.base = pdata->gpio_base;
+ pct->chip.base = (np) ? -1 : pdata->gpio_base;
+
+ /* initialize the lock */
+ mutex_init(&pct->lock);
+
+ /* Poke in other ASIC variants here */
+ switch (id) {
+ case PINCTRL_AB8500:
+ abx500_pinctrl_ab8500_init(&pct->soc);
+ break;
+ case PINCTRL_AB8540:
+ abx500_pinctrl_ab8540_init(&pct->soc);
+ break;
+ case PINCTRL_AB9540:
+ abx500_pinctrl_ab9540_init(&pct->soc);
+ break;
+ case PINCTRL_AB8505:
+ abx500_pinctrl_ab8505_init(&pct->soc);
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n",
+ (int) platid->driver_data);
+ mutex_destroy(&pct->lock);
+ return -EINVAL;
+ }
+
+ if (!pct->soc) {
+ dev_err(&pdev->dev, "Invalid SOC data\n");
+ mutex_destroy(&pct->lock);
+ return -EINVAL;
+ }
+
+ pct->chip.ngpio = abx500_get_gpio_num(pct->soc);
+ pct->irq_cluster = pct->soc->gpio_irq_cluster;
+ pct->irq_cluster_size = pct->soc->ngpio_irq_cluster;
+
+ ret = gpiochip_add(&pct->chip);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
+ mutex_destroy(&pct->lock);
+ return ret;
+ }
+ dev_info(&pdev->dev, "added gpiochip\n");
+
+ abx500_pinctrl_desc.pins = pct->soc->pins;
+ abx500_pinctrl_desc.npins = pct->soc->npins;
+ pct->pctldev = pinctrl_register(&abx500_pinctrl_desc, &pdev->dev, pct);
+ if (!pct->pctldev) {
+ dev_err(&pdev->dev,
+ "could not register abx500 pinctrl driver\n");
+ ret = -EINVAL;
+ goto out_rem_chip;
+ }
+ dev_info(&pdev->dev, "registered pin controller\n");
+
+ /* We will handle a range of GPIO pins */
+ for (i = 0; i < pct->soc->gpio_num_ranges; i++) {
+ const struct abx500_pinrange *p = &pct->soc->gpio_ranges[i];
+
+ ret = gpiochip_add_pin_range(&pct->chip,
+ dev_name(&pdev->dev),
+ p->offset - 1, p->offset, p->npins);
+ if (ret < 0)
+ goto out_rem_chip;
+ }
+
+ platform_set_drvdata(pdev, pct);
+ dev_info(&pdev->dev, "initialized abx500 pinctrl driver\n");
+
+ return 0;
+
+out_rem_chip:
+ err = gpiochip_remove(&pct->chip);
+ if (err)
+ dev_info(&pdev->dev, "failed to remove gpiochip\n");
+
+ mutex_destroy(&pct->lock);
+ return ret;
+}
+
+/**
+ * abx500_gpio_remove() - remove Ab8500-gpio driver
+ * @pdev: Platform device registered
+ */
+static int abx500_gpio_remove(struct platform_device *pdev)
+{
+ struct abx500_pinctrl *pct = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = gpiochip_remove(&pct->chip);
+ if (ret < 0) {
+ dev_err(pct->dev, "unable to remove gpiochip: %d\n",
+ ret);
+ return ret;
+ }
+
+ mutex_destroy(&pct->lock);
+
+ return 0;
+}
+
+static const struct platform_device_id abx500_pinctrl_id[] = {
+ { "pinctrl-ab8500", PINCTRL_AB8500 },
+ { "pinctrl-ab8540", PINCTRL_AB8540 },
+ { "pinctrl-ab9540", PINCTRL_AB9540 },
+ { "pinctrl-ab8505", PINCTRL_AB8505 },
+ { },
+};
+
+static struct platform_driver abx500_gpio_driver = {
+ .driver = {
+ .name = "abx500-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = abx500_gpio_match,
+ },
+ .probe = abx500_gpio_probe,
+ .remove = abx500_gpio_remove,
+ .id_table = abx500_pinctrl_id,
+};
+
+static int __init abx500_gpio_init(void)
+{
+ return platform_driver_register(&abx500_gpio_driver);
+}
+core_initcall(abx500_gpio_init);
+
+MODULE_AUTHOR("Patrice Chotard <patrice.chotard@st.com>");
+MODULE_DESCRIPTION("Driver allows to use AxB5xx unused pins to be used as GPIO");
+MODULE_ALIAS("platform:abx500-gpio");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-abx500.h b/drivers/pinctrl/pinctrl-abx500.h
new file mode 100644
index 000000000000..eeca8f973999
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-abx500.h
@@ -0,0 +1,234 @@
+#ifndef PINCTRL_PINCTRL_ABx5O0_H
+#define PINCTRL_PINCTRL_ABx500_H
+
+/* Package definitions */
+#define PINCTRL_AB8500 0
+#define PINCTRL_AB8540 1
+#define PINCTRL_AB9540 2
+#define PINCTRL_AB8505 3
+
+/* pins alternate function */
+enum abx500_pin_func {
+ ABX500_DEFAULT,
+ ABX500_ALT_A,
+ ABX500_ALT_B,
+ ABX500_ALT_C,
+};
+
+/**
+ * struct abx500_function - ABx500 pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct abx500_function {
+ const char *name;
+ const char * const *groups;
+ unsigned ngroups;
+};
+
+/**
+ * struct abx500_pingroup - describes a ABx500 pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ * @altsetting: the altsetting to apply to all pins in this group to
+ * configure them to be used by a function
+ */
+struct abx500_pingroup {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned npins;
+ int altsetting;
+};
+
+#define ALTERNATE_FUNCTIONS(pin, sel_bit, alt1, alt2, alta, altb, altc) \
+{ \
+ .pin_number = pin, \
+ .gpiosel_bit = sel_bit, \
+ .alt_bit1 = alt1, \
+ .alt_bit2 = alt2, \
+ .alta_val = alta, \
+ .altb_val = altb, \
+ .altc_val = altc, \
+}
+
+#define UNUSED -1
+/**
+ * struct alternate_functions
+ * @pin_number: The pin number
+ * @gpiosel_bit: Control bit in GPIOSEL register,
+ * @alt_bit1: First AlternateFunction bit used to select the
+ * alternate function
+ * @alt_bit2: Second AlternateFunction bit used to select the
+ * alternate function
+ *
+ * these 3 following fields are necessary due to none
+ * coherency on how to select the altA, altB and altC
+ * function between the ABx500 SOC family when using
+ * alternatfunc register.
+ * @alta_val: value to write in alternatfunc to select altA function
+ * @altb_val: value to write in alternatfunc to select altB function
+ * @altc_val: value to write in alternatfunc to select altC function
+ */
+struct alternate_functions {
+ unsigned pin_number;
+ s8 gpiosel_bit;
+ s8 alt_bit1;
+ s8 alt_bit2;
+ u8 alta_val;
+ u8 altb_val;
+ u8 altc_val;
+};
+
+/**
+ * struct pullud - specific pull up/down feature
+ * @first_pin: The pin number of the first pins which support
+ * specific pull up/down
+ * @last_pin: The pin number of the last pins
+ */
+struct pullud {
+ unsigned first_pin;
+ unsigned last_pin;
+};
+
+#define GPIO_IRQ_CLUSTER(a, b, c) \
+{ \
+ .start = a, \
+ .end = b, \
+ .to_irq = c, \
+}
+
+/**
+ * struct abx500_gpio_irq_cluster - indicates GPIOs which are interrupt
+ * capable
+ * @start: The pin number of the first pin interrupt capable
+ * @end: The pin number of the last pin interrupt capable
+ * @to_irq: The ABx500 GPIO's associated IRQs are clustered
+ * together throughout the interrupt numbers at irregular
+ * intervals. To solve this quandary, we will place the
+ * read-in values into the cluster information table
+ */
+
+struct abx500_gpio_irq_cluster {
+ int start;
+ int end;
+ int to_irq;
+};
+
+/**
+ * struct abx500_pinrange - map pin numbers to GPIO offsets
+ * @offset: offset into the GPIO local numberspace, incidentally
+ * identical to the offset into the local pin numberspace
+ * @npins: number of pins to map from both offsets
+ * @altfunc: altfunc setting to be used to enable GPIO on a pin in
+ * this range (may vary)
+ */
+struct abx500_pinrange {
+ unsigned int offset;
+ unsigned int npins;
+ int altfunc;
+};
+
+#define ABX500_PINRANGE(a, b, c) { .offset = a, .npins = b, .altfunc = c }
+
+/**
+ * struct abx500_pinctrl_soc_data - ABx500 pin controller per-SoC configuration
+ * @gpio_ranges: An array of GPIO ranges for this SoC
+ * @gpio_num_ranges: The number of GPIO ranges for this SoC
+ * @pins: An array describing all pins the pin controller affects.
+ * All pins which are also GPIOs must be listed first within the
+ * array, and be numbered identically to the GPIO controller's
+ * numbering.
+ * @npins: The number of entries in @pins.
+ * @functions: The functions supported on this SoC.
+ * @nfunction: The number of entries in @functions.
+ * @groups: An array describing all pin groups the pin SoC supports.
+ * @ngroups: The number of entries in @groups.
+ * @alternate_functions: array describing pins which supports alternate and
+ * how to set it.
+ * @pullud: array describing pins which supports pull up/down
+ * specific registers.
+ * @gpio_irq_cluster: An array of GPIO interrupt capable for this SoC
+ * @ngpio_irq_cluster: The number of GPIO inetrrupt capable for this SoC
+ * @irq_gpio_rising_offset: Interrupt offset used as base to compute specific
+ * setting strategy of the rising interrupt line
+ * @irq_gpio_falling_offset: Interrupt offset used as base to compute specific
+ * setting strategy of the falling interrupt line
+ * @irq_gpio_factor: Factor used to compute specific setting strategy of
+ * the interrupt line
+ */
+
+struct abx500_pinctrl_soc_data {
+ const struct abx500_pinrange *gpio_ranges;
+ unsigned gpio_num_ranges;
+ const struct pinctrl_pin_desc *pins;
+ unsigned npins;
+ const struct abx500_function *functions;
+ unsigned nfunctions;
+ const struct abx500_pingroup *groups;
+ unsigned ngroups;
+ struct alternate_functions *alternate_functions;
+ struct pullud *pullud;
+ struct abx500_gpio_irq_cluster *gpio_irq_cluster;
+ unsigned ngpio_irq_cluster;
+ int irq_gpio_rising_offset;
+ int irq_gpio_falling_offset;
+ int irq_gpio_factor;
+};
+
+#ifdef CONFIG_PINCTRL_AB8500
+
+void abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB8540
+
+void abx500_pinctrl_ab8540_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8540_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB9540
+
+void abx500_pinctrl_ab9540_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab9540_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB8505
+
+void abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#endif /* PINCTRL_PINCTRL_ABx500_H */
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 471c71f7f8b6..75933a6aa828 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -1503,10 +1503,9 @@ static int at91_gpio_probe(struct platform_device *pdev)
goto err;
}
- at91_chip->regbase = devm_request_and_ioremap(&pdev->dev, res);
- if (!at91_chip->regbase) {
- dev_err(&pdev->dev, "failed to map registers, ignoring.\n");
- ret = -EBUSY;
+ at91_chip->regbase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(at91_chip->regbase)) {
+ ret = PTR_ERR(at91_chip->regbase);
goto err;
}
diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c
index d347b9f2eae3..4eb6d2c4e4df 100644
--- a/drivers/pinctrl/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/pinctrl-bcm2835.c
@@ -959,9 +959,9 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
return err;
}
- pc->base = devm_request_and_ioremap(dev, &iomem);
- if (!pc->base)
- return -EADDRNOTAVAIL;
+ pc->base = devm_ioremap_resource(dev, &iomem);
+ if (IS_ERR(pc->base))
+ return PTR_ERR(pc->base);
pc->gpio_chip = bcm2835_gpio_chip;
pc->gpio_chip.dev = dev;
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index fbb37154471c..8b7e7bc2226b 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -715,11 +715,9 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
- gpio->base = devm_request_and_ioremap(&pdev->dev, memres);
- if (!gpio->base) {
- dev_err(gpio->dev, "could not get remap memory\n");
- return -ENOMEM;
- }
+ gpio->base = devm_ioremap_resource(&pdev->dev, memres);
+ if (IS_ERR(gpio->base))
+ return PTR_ERR(gpio->base);
gpio->clk = devm_clk_get(gpio->dev, NULL);
if (IS_ERR(gpio->clk)) {
diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c
index 142729914c34..1376eb7305db 100644
--- a/drivers/pinctrl/pinctrl-exynos5440.c
+++ b/drivers/pinctrl/pinctrl-exynos5440.c
@@ -866,11 +866,9 @@ static int exynos5440_pinctrl_probe(struct platform_device *pdev)
return -ENOENT;
}
- priv->reg_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!priv->reg_base) {
- dev_err(dev, "ioremap failed\n");
- return -ENODEV;
- }
+ priv->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->reg_base))
+ return PTR_ERR(priv->reg_base);
ret = exynos5440_gpiolib_register(pdev, priv);
if (ret)
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
index 8ed20e84cb02..af97a1f90007 100644
--- a/drivers/pinctrl/pinctrl-falcon.c
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -170,7 +170,7 @@ static const unsigned pins_ntr[] = {GPIO4};
static const unsigned pins_ntr8k[] = {GPIO5};
static const unsigned pins_hrst[] = {GPIO6};
static const unsigned pins_mdio[] = {GPIO7, GPIO8};
-static const unsigned pins_bled[] = {GPIO7, GPIO10, GPIO11,
+static const unsigned pins_bled[] = {GPIO9, GPIO10, GPIO11,
GPIO12, GPIO13, GPIO14};
static const unsigned pins_asc0[] = {GPIO32, GPIO33};
static const unsigned pins_spi[] = {GPIO34, GPIO35, GPIO36};
@@ -315,6 +315,37 @@ static int falcon_pinconf_set(struct pinctrl_dev *pctrldev,
static void falcon_pinconf_dbg_show(struct pinctrl_dev *pctrldev,
struct seq_file *s, unsigned offset)
{
+ unsigned long config;
+ struct pin_desc *desc;
+
+ struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+ int port = PORT(offset);
+
+ seq_printf(s, " (port %d) mux %d -- ", port,
+ pad_r32(info->membase[port], LTQ_PADC_MUX(PORT_PIN(offset))));
+
+ config = LTQ_PINCONF_PACK(LTQ_PINCONF_PARAM_PULL, 0);
+ if (!falcon_pinconf_get(pctrldev, offset, &config))
+ seq_printf(s, "pull %d ",
+ (int)LTQ_PINCONF_UNPACK_ARG(config));
+
+ config = LTQ_PINCONF_PACK(LTQ_PINCONF_PARAM_DRIVE_CURRENT, 0);
+ if (!falcon_pinconf_get(pctrldev, offset, &config))
+ seq_printf(s, "drive-current %d ",
+ (int)LTQ_PINCONF_UNPACK_ARG(config));
+
+ config = LTQ_PINCONF_PACK(LTQ_PINCONF_PARAM_SLEW_RATE, 0);
+ if (!falcon_pinconf_get(pctrldev, offset, &config))
+ seq_printf(s, "slew-rate %d ",
+ (int)LTQ_PINCONF_UNPACK_ARG(config));
+
+ desc = pin_desc_get(pctrldev, offset);
+ if (desc) {
+ if (desc->gpio_owner)
+ seq_printf(s, " owner: %s", desc->gpio_owner);
+ } else {
+ seq_printf(s, " not registered");
+ }
}
static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev,
@@ -360,6 +391,8 @@ static const struct ltq_cfg_param falcon_cfg_params[] = {
static struct ltq_pinmux_info falcon_info = {
.desc = &falcon_pctrl_desc,
.apply_mux = falcon_mux_apply,
+ .params = falcon_cfg_params,
+ .num_params = ARRAY_SIZE(falcon_cfg_params),
};
@@ -398,6 +431,9 @@ static int pinctrl_falcon_probe(struct platform_device *pdev)
u32 avail;
int pins;
+ if (!of_device_is_available(np))
+ continue;
+
if (!ppdev) {
dev_err(&pdev->dev, "failed to find pad pdev\n");
continue;
@@ -411,14 +447,11 @@ static int pinctrl_falcon_probe(struct platform_device *pdev)
dev_err(&ppdev->dev, "failed to get clock\n");
return PTR_ERR(falcon_info.clk[*bank]);
}
- falcon_info.membase[*bank] =
- devm_request_and_ioremap(&pdev->dev, &res);
- if (!falcon_info.membase[*bank]) {
- dev_err(&pdev->dev,
- "Failed to remap memory for bank %d\n",
- *bank);
- return -ENOMEM;
- }
+ falcon_info.membase[*bank] = devm_ioremap_resource(&pdev->dev,
+ &res);
+ if (IS_ERR(falcon_info.membase[*bank]))
+ return PTR_ERR(falcon_info.membase[*bank]);
+
avail = pad_r32(falcon_info.membase[*bank],
LTQ_PADC_AVAIL);
pins = fls(avail);
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c
index 43a6f1ffc786..4cebb9c6c5c5 100644
--- a/drivers/pinctrl/pinctrl-imx.c
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -584,9 +584,9 @@ int imx_pinctrl_probe(struct platform_device *pdev,
if (!res)
return -ENOENT;
- ipctl->base = devm_request_and_ioremap(&pdev->dev, res);
- if (!ipctl->base)
- return -EBUSY;
+ ipctl->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ipctl->base))
+ return PTR_ERR(ipctl->base);
imx_pinctrl_desc.name = dev_name(&pdev->dev);
imx_pinctrl_desc.pins = info->pins;
diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c
index 15f501d89026..a70384611351 100644
--- a/drivers/pinctrl/pinctrl-lantiq.c
+++ b/drivers/pinctrl/pinctrl-lantiq.c
@@ -64,11 +64,13 @@ static void ltq_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
seq_printf(s, " %s", dev_name(pctldev->dev));
}
-static int ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+static void ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **map)
{
struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
+ struct property *pins = of_find_property(np, "lantiq,pins", NULL);
+ struct property *groups = of_find_property(np, "lantiq,groups", NULL);
unsigned long configs[3];
unsigned num_configs = 0;
struct property *prop;
@@ -76,8 +78,20 @@ static int ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
const char *function;
int ret, i;
+ if (!pins && !groups) {
+ dev_err(pctldev->dev, "%s defines neither pins nor groups\n",
+ np->name);
+ return;
+ }
+
+ if (pins && groups) {
+ dev_err(pctldev->dev, "%s defines both pins and groups\n",
+ np->name);
+ return;
+ }
+
ret = of_property_read_string(np, "lantiq,function", &function);
- if (!ret) {
+ if (groups && !ret) {
of_property_for_each_string(np, "lantiq,groups", prop, group) {
(*map)->type = PIN_MAP_TYPE_MUX_GROUP;
(*map)->name = function;
@@ -85,11 +99,6 @@ static int ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
(*map)->data.mux.function = function;
(*map)++;
}
- if (of_find_property(np, "lantiq,pins", NULL))
- dev_err(pctldev->dev,
- "%s mixes pins and groups settings\n",
- np->name);
- return 0;
}
for (i = 0; i < info->num_params; i++) {
@@ -103,7 +112,7 @@ static int ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
}
if (!num_configs)
- return -EINVAL;
+ return;
of_property_for_each_string(np, "lantiq,pins", prop, pin) {
(*map)->data.configs.configs = kmemdup(configs,
@@ -115,7 +124,16 @@ static int ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
(*map)->data.configs.num_configs = num_configs;
(*map)++;
}
- return 0;
+ of_property_for_each_string(np, "lantiq,groups", prop, group) {
+ (*map)->data.configs.configs = kmemdup(configs,
+ num_configs * sizeof(unsigned long),
+ GFP_KERNEL);
+ (*map)->type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ (*map)->name = group;
+ (*map)->data.configs.group_or_pin = group;
+ (*map)->data.configs.num_configs = num_configs;
+ (*map)++;
+ }
}
static int ltq_pinctrl_dt_subnode_size(struct device_node *np)
@@ -135,23 +153,19 @@ static int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
{
struct pinctrl_map *tmp;
struct device_node *np;
- int ret;
+ int max_maps = 0;
- *num_maps = 0;
for_each_child_of_node(np_config, np)
- *num_maps += ltq_pinctrl_dt_subnode_size(np);
- *map = kzalloc(*num_maps * sizeof(struct pinctrl_map), GFP_KERNEL);
+ max_maps += ltq_pinctrl_dt_subnode_size(np);
+ *map = kzalloc(max_maps * sizeof(struct pinctrl_map) * 2, GFP_KERNEL);
if (!*map)
return -ENOMEM;
tmp = *map;
- for_each_child_of_node(np_config, np) {
- ret = ltq_pinctrl_dt_subnode_to_map(pctldev, np, &tmp);
- if (ret < 0) {
- ltq_pinctrl_dt_free_map(pctldev, *map, *num_maps);
- return ret;
- }
- }
+ for_each_child_of_node(np_config, np)
+ ltq_pinctrl_dt_subnode_to_map(pctldev, np, &tmp);
+ *num_maps = ((int)(tmp - *map));
+
return 0;
}
@@ -280,7 +294,7 @@ static int ltq_pmx_gpio_request_enable(struct pinctrl_dev *pctrldev,
unsigned pin)
{
struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
- int mfp = match_mfp(info, pin + (range->id * 32));
+ int mfp = match_mfp(info, pin);
int pin_func;
if (mfp < 0) {
diff --git a/drivers/pinctrl/pinctrl-lantiq.h b/drivers/pinctrl/pinctrl-lantiq.h
index 4419d32a0ade..6d07f0238532 100644
--- a/drivers/pinctrl/pinctrl-lantiq.h
+++ b/drivers/pinctrl/pinctrl-lantiq.h
@@ -34,6 +34,7 @@ enum ltq_pinconf_param {
LTQ_PINCONF_PARAM_OPEN_DRAIN,
LTQ_PINCONF_PARAM_DRIVE_CURRENT,
LTQ_PINCONF_PARAM_SLEW_RATE,
+ LTQ_PINCONF_PARAM_OUTPUT,
};
struct ltq_cfg_param {
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index 5767b18ebdff..36d20293de5c 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -25,6 +25,8 @@
#include <linux/irqdomain.h>
#include <linux/slab.h>
#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
@@ -32,8 +34,8 @@
#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/pinctrl-nomadik.h>
#include <asm/mach/irq.h>
-#include <mach/irqs.h>
#include "pinctrl-nomadik.h"
+#include "core.h"
/*
* The GPIO module in the Nomadik family of Systems-on-Chip is an
@@ -216,7 +218,7 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
u32 falling = nmk_chip->fimsc & BIT(offset);
u32 rising = nmk_chip->rimsc & BIT(offset);
int gpio = nmk_chip->chip.base + offset;
- int irq = NOMADIK_GPIO_TO_IRQ(gpio);
+ int irq = irq_find_mapping(nmk_chip->domain, offset);
struct irq_data *d = irq_get_irq_data(irq);
if (!rising && !falling)
@@ -1341,8 +1343,7 @@ static int nmk_gpio_probe(struct platform_device *dev)
if (of_property_read_u32(np, "gpio-bank", &dev->id)) {
dev_err(&dev->dev, "gpio-bank property not found\n");
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
pdata->first_gpio = dev->id * NMK_GPIO_PER_CHIP;
@@ -1350,41 +1351,29 @@ static int nmk_gpio_probe(struct platform_device *dev)
}
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENOENT;
- goto out;
- }
+ if (!res)
+ return -ENOENT;
irq = platform_get_irq(dev, 0);
- if (irq < 0) {
- ret = irq;
- goto out;
- }
+ if (irq < 0)
+ return irq;
secondary_irq = platform_get_irq(dev, 1);
- if (secondary_irq >= 0 && !pdata->get_secondary_status) {
- ret = -EINVAL;
- goto out;
- }
+ if (secondary_irq >= 0 && !pdata->get_secondary_status)
+ return -EINVAL;
- base = devm_request_and_ioremap(&dev->dev, res);
- if (!base) {
- ret = -ENOMEM;
- goto out;
- }
+ base = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
clk = devm_clk_get(&dev->dev, NULL);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- goto out;
- }
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
clk_prepare(clk);
nmk_chip = devm_kzalloc(&dev->dev, sizeof(*nmk_chip), GFP_KERNEL);
- if (!nmk_chip) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!nmk_chip)
+ return -ENOMEM;
/*
* The virt address in nmk_chip->addr is in the nomadik register space,
@@ -1418,7 +1407,7 @@ static int nmk_gpio_probe(struct platform_device *dev)
ret = gpiochip_add(&nmk_chip->chip);
if (ret)
- goto out;
+ return ret;
BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips));
@@ -1427,14 +1416,15 @@ static int nmk_gpio_probe(struct platform_device *dev)
platform_set_drvdata(dev, nmk_chip);
if (!np)
- irq_start = NOMADIK_GPIO_TO_IRQ(pdata->first_gpio);
+ irq_start = pdata->first_irq;
nmk_chip->domain = irq_domain_add_simple(np,
NMK_GPIO_PER_CHIP, irq_start,
&nmk_gpio_irq_simple_ops, nmk_chip);
if (!nmk_chip->domain) {
dev_err(&dev->dev, "failed to create irqdomain\n");
- ret = -ENOSYS;
- goto out;
+ /* Just do this, no matter if it fails */
+ ret = gpiochip_remove(&nmk_chip->chip);
+ return -ENOSYS;
}
nmk_gpio_init_irq(nmk_chip);
@@ -1442,12 +1432,6 @@ static int nmk_gpio_probe(struct platform_device *dev)
dev_info(&dev->dev, "at address %p\n", nmk_chip->addr);
return 0;
-
-out:
- dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret,
- pdata->first_gpio, pdata->first_gpio+31);
-
- return ret;
}
static int nmk_get_groups_cnt(struct pinctrl_dev *pctldev)
@@ -1508,11 +1492,285 @@ static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset);
}
+static void nmk_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ int i;
+
+ for (i = 0; i < num_maps; i++)
+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+ kfree(map[i].data.configs.configs);
+ kfree(map);
+}
+
+static int nmk_dt_reserve_map(struct pinctrl_map **map, unsigned *reserved_maps,
+ unsigned *num_maps, unsigned reserve)
+{
+ unsigned old_num = *reserved_maps;
+ unsigned new_num = *num_maps + reserve;
+ struct pinctrl_map *new_map;
+
+ if (old_num >= new_num)
+ return 0;
+
+ new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
+ if (!new_map)
+ return -ENOMEM;
+
+ memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
+
+ *map = new_map;
+ *reserved_maps = new_num;
+
+ return 0;
+}
+
+static int nmk_dt_add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
+ unsigned *num_maps, const char *group,
+ const char *function)
+{
+ if (*num_maps == *reserved_maps)
+ return -ENOSPC;
+
+ (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)[*num_maps].data.mux.group = group;
+ (*map)[*num_maps].data.mux.function = function;
+ (*num_maps)++;
+
+ return 0;
+}
+
+static int nmk_dt_add_map_configs(struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps, const char *group,
+ unsigned long *configs, unsigned num_configs)
+{
+ unsigned long *dup_configs;
+
+ if (*num_maps == *reserved_maps)
+ return -ENOSPC;
+
+ dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
+ GFP_KERNEL);
+ if (!dup_configs)
+ return -ENOMEM;
+
+ (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_PIN;
+
+ (*map)[*num_maps].data.configs.group_or_pin = group;
+ (*map)[*num_maps].data.configs.configs = dup_configs;
+ (*map)[*num_maps].data.configs.num_configs = num_configs;
+ (*num_maps)++;
+
+ return 0;
+}
+
+#define NMK_CONFIG_PIN(x,y) { .property = x, .config = y, }
+#define NMK_CONFIG_PIN_ARRAY(x,y) { .property = x, .choice = y, \
+ .size = ARRAY_SIZE(y), }
+
+static const unsigned long nmk_pin_input_modes[] = {
+ PIN_INPUT_NOPULL,
+ PIN_INPUT_PULLUP,
+ PIN_INPUT_PULLDOWN,
+};
+
+static const unsigned long nmk_pin_output_modes[] = {
+ PIN_OUTPUT_LOW,
+ PIN_OUTPUT_HIGH,
+ PIN_DIR_OUTPUT,
+};
+
+static const unsigned long nmk_pin_sleep_modes[] = {
+ PIN_SLEEPMODE_DISABLED,
+ PIN_SLEEPMODE_ENABLED,
+};
+
+static const unsigned long nmk_pin_sleep_input_modes[] = {
+ PIN_SLPM_INPUT_NOPULL,
+ PIN_SLPM_INPUT_PULLUP,
+ PIN_SLPM_INPUT_PULLDOWN,
+ PIN_SLPM_DIR_INPUT,
+};
+
+static const unsigned long nmk_pin_sleep_output_modes[] = {
+ PIN_SLPM_OUTPUT_LOW,
+ PIN_SLPM_OUTPUT_HIGH,
+ PIN_SLPM_DIR_OUTPUT,
+};
+
+static const unsigned long nmk_pin_sleep_wakeup_modes[] = {
+ PIN_SLPM_WAKEUP_DISABLE,
+ PIN_SLPM_WAKEUP_ENABLE,
+};
+
+static const unsigned long nmk_pin_gpio_modes[] = {
+ PIN_GPIOMODE_DISABLED,
+ PIN_GPIOMODE_ENABLED,
+};
+
+static const unsigned long nmk_pin_sleep_pdis_modes[] = {
+ PIN_SLPM_PDIS_DISABLED,
+ PIN_SLPM_PDIS_ENABLED,
+};
+
+struct nmk_cfg_param {
+ const char *property;
+ unsigned long config;
+ const unsigned long *choice;
+ int size;
+};
+
+static const struct nmk_cfg_param nmk_cfg_params[] = {
+ NMK_CONFIG_PIN_ARRAY("ste,input", nmk_pin_input_modes),
+ NMK_CONFIG_PIN_ARRAY("ste,output", nmk_pin_output_modes),
+ NMK_CONFIG_PIN_ARRAY("ste,sleep", nmk_pin_sleep_modes),
+ NMK_CONFIG_PIN_ARRAY("ste,sleep-input", nmk_pin_sleep_input_modes),
+ NMK_CONFIG_PIN_ARRAY("ste,sleep-output", nmk_pin_sleep_output_modes),
+ NMK_CONFIG_PIN_ARRAY("ste,sleep-wakeup", nmk_pin_sleep_wakeup_modes),
+ NMK_CONFIG_PIN_ARRAY("ste,gpio", nmk_pin_gpio_modes),
+ NMK_CONFIG_PIN_ARRAY("ste,sleep-pull-disable", nmk_pin_sleep_pdis_modes),
+};
+
+static int nmk_dt_pin_config(int index, int val, unsigned long *config)
+{
+ int ret = 0;
+
+ if (nmk_cfg_params[index].choice == NULL)
+ *config = nmk_cfg_params[index].config;
+ else {
+ /* test if out of range */
+ if (val < nmk_cfg_params[index].size) {
+ *config = nmk_cfg_params[index].config |
+ nmk_cfg_params[index].choice[val];
+ }
+ }
+ return ret;
+}
+
+static const char *nmk_find_pin_name(struct pinctrl_dev *pctldev, const char *pin_name)
+{
+ int i, pin_number;
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ if (sscanf((char *)pin_name, "GPIO%d", &pin_number) == 1)
+ for (i = 0; i < npct->soc->npins; i++)
+ if (npct->soc->pins[i].number == pin_number)
+ return npct->soc->pins[i].name;
+ return NULL;
+}
+
+static bool nmk_pinctrl_dt_get_config(struct device_node *np,
+ unsigned long *configs)
+{
+ bool has_config = 0;
+ unsigned long cfg = 0;
+ int i, val, ret;
+
+ for (i = 0; i < ARRAY_SIZE(nmk_cfg_params); i++) {
+ ret = of_property_read_u32(np,
+ nmk_cfg_params[i].property, &val);
+ if (ret != -EINVAL) {
+ if (nmk_dt_pin_config(i, val, &cfg) == 0) {
+ *configs |= cfg;
+ has_config = 1;
+ }
+ }
+ }
+
+ return has_config;
+}
+
+int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps)
+{
+ int ret;
+ const char *function = NULL;
+ unsigned long configs = 0;
+ bool has_config = 0;
+ unsigned reserve = 0;
+ struct property *prop;
+ const char *group, *gpio_name;
+ struct device_node *np_config;
+
+ ret = of_property_read_string(np, "ste,function", &function);
+ if (ret >= 0)
+ reserve = 1;
+
+ has_config = nmk_pinctrl_dt_get_config(np, &configs);
+
+ np_config = of_parse_phandle(np, "ste,config", 0);
+ if (np_config)
+ has_config |= nmk_pinctrl_dt_get_config(np_config, &configs);
+
+ ret = of_property_count_strings(np, "ste,pins");
+ if (ret < 0)
+ goto exit;
+
+ if (has_config)
+ reserve++;
+
+ reserve *= ret;
+
+ ret = nmk_dt_reserve_map(map, reserved_maps, num_maps, reserve);
+ if (ret < 0)
+ goto exit;
+
+ of_property_for_each_string(np, "ste,pins", prop, group) {
+ if (function) {
+ ret = nmk_dt_add_map_mux(map, reserved_maps, num_maps,
+ group, function);
+ if (ret < 0)
+ goto exit;
+ }
+ if (has_config) {
+ gpio_name = nmk_find_pin_name(pctldev, group);
+
+ ret = nmk_dt_add_map_configs(map, reserved_maps, num_maps,
+ gpio_name, &configs, 1);
+ if (ret < 0)
+ goto exit;
+ }
+
+ }
+exit:
+ return ret;
+}
+
+int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ unsigned reserved_maps;
+ struct device_node *np;
+ int ret;
+
+ reserved_maps = 0;
+ *map = NULL;
+ *num_maps = 0;
+
+ for_each_child_of_node(np_config, np) {
+ ret = nmk_pinctrl_dt_subnode_to_map(pctldev, np, map,
+ &reserved_maps, num_maps);
+ if (ret < 0) {
+ nmk_pinctrl_dt_free_map(pctldev, *map, *num_maps);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static struct pinctrl_ops nmk_pinctrl_ops = {
.get_groups_count = nmk_get_groups_cnt,
.get_group_name = nmk_get_group_name,
.get_group_pins = nmk_get_group_pins,
.pin_dbg_show = nmk_pin_dbg_show,
+ .dt_node_to_map = nmk_pinctrl_dt_node_to_map,
+ .dt_free_map = nmk_pinctrl_dt_free_map,
};
static int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
@@ -1846,16 +2104,43 @@ static struct pinctrl_desc nmk_pinctrl_desc = {
static const struct of_device_id nmk_pinctrl_match[] = {
{
- .compatible = "stericsson,nmk_pinctrl",
+ .compatible = "stericsson,nmk-pinctrl-stn8815",
+ .data = (void *)PINCTRL_NMK_STN8815,
+ },
+ {
+ .compatible = "stericsson,nmk-pinctrl",
.data = (void *)PINCTRL_NMK_DB8500,
},
{},
};
+static int nmk_pinctrl_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct nmk_pinctrl *npct;
+
+ npct = platform_get_drvdata(pdev);
+ if (!npct)
+ return -EINVAL;
+
+ return pinctrl_force_sleep(npct->pctl);
+}
+
+static int nmk_pinctrl_resume(struct platform_device *pdev)
+{
+ struct nmk_pinctrl *npct;
+
+ npct = platform_get_drvdata(pdev);
+ if (!npct)
+ return -EINVAL;
+
+ return pinctrl_force_default(npct->pctl);
+}
+
static int nmk_pinctrl_probe(struct platform_device *pdev)
{
const struct platform_device_id *platid = platform_get_device_id(pdev);
struct device_node *np = pdev->dev.of_node;
+ struct device_node *prcm_np;
struct nmk_pinctrl *npct;
struct resource *res;
unsigned int version = 0;
@@ -1884,21 +2169,26 @@ static int nmk_pinctrl_probe(struct platform_device *pdev)
if (version == PINCTRL_NMK_DB8540)
nmk_pinctrl_db8540_init(&npct->soc);
+ if (np) {
+ prcm_np = of_parse_phandle(np, "prcm", 0);
+ if (prcm_np)
+ npct->prcm_base = of_iomap(prcm_np, 0);
+ }
+
+ /* Allow platform passed information to over-write DT. */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res) {
+ if (res)
npct->prcm_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
- if (!npct->prcm_base) {
- dev_err(&pdev->dev,
- "failed to ioremap PRCM registers\n");
- return -ENOMEM;
+ if (!npct->prcm_base) {
+ if (version == PINCTRL_NMK_STN8815) {
+ dev_info(&pdev->dev,
+ "No PRCM base, "
+ "assuming no ALT-Cx control is available\n");
+ } else {
+ dev_err(&pdev->dev, "missing PRCM base address\n");
+ return -EINVAL;
}
- } else if (version == PINCTRL_NMK_STN8815) {
- dev_info(&pdev->dev,
- "No PRCM base, assume no ALT-Cx control is available\n");
- } else {
- dev_err(&pdev->dev, "missing PRCM base address\n");
- return -EINVAL;
}
/*
@@ -1963,6 +2253,10 @@ static struct platform_driver nmk_pinctrl_driver = {
},
.probe = nmk_pinctrl_probe,
.id_table = nmk_pinctrl_id,
+#ifdef CONFIG_PM
+ .suspend = nmk_pinctrl_suspend,
+ .resume = nmk_pinctrl_resume,
+#endif
};
static int __init nmk_gpio_init(void)
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c
index 51f8a388b917..1f49bb02a6af 100644
--- a/drivers/pinctrl/pinctrl-pxa3xx.c
+++ b/drivers/pinctrl/pinctrl-pxa3xx.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -187,9 +188,9 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev,
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
- info->virt_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!info->virt_base)
- return -ENOMEM;
+ info->virt_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(info->virt_base))
+ return PTR_ERR(info->virt_base);
info->pctrl = pinctrl_register(desc, &pdev->dev, info);
if (!info->pctrl) {
dev_err(&pdev->dev, "failed to register PXA pinmux driver\n");
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index fd7b24cd8908..f206df175656 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -716,7 +716,6 @@ static int samsung_pinctrl_register(struct platform_device *pdev,
}
ctrldesc->pins = pindesc;
ctrldesc->npins = drvdata->ctrl->nr_pins;
- ctrldesc->npins = drvdata->ctrl->nr_pins;
/* dynamically populate the pin number and pin name for pindesc */
for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
@@ -917,11 +916,9 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
return -ENOENT;
}
- drvdata->virt_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!drvdata->virt_base) {
- dev_err(dev, "ioremap failed\n");
- return -ENODEV;
- }
+ drvdata->virt_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(drvdata->virt_base))
+ return PTR_ERR(drvdata->virt_base);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res)
@@ -947,9 +944,9 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
}
static const struct of_device_id samsung_pinctrl_dt_match[] = {
- { .compatible = "samsung,pinctrl-exynos4210",
+ { .compatible = "samsung,exynos4210-pinctrl",
.data = (void *)exynos4210_pin_ctrl },
- { .compatible = "samsung,pinctrl-exynos4x12",
+ { .compatible = "samsung,exynos4x12-pinctrl",
.data = (void *)exynos4x12_pin_ctrl },
{},
};
diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c
index 498b2ba905de..d02498b30c6e 100644
--- a/drivers/pinctrl/pinctrl-sirf.c
+++ b/drivers/pinctrl/pinctrl-sirf.c
@@ -1246,6 +1246,22 @@ static void __iomem *sirfsoc_rsc_of_iomap(void)
return of_iomap(np, 0);
}
+static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
+{
+ if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE)
+ return -EINVAL;
+
+ if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc)
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpiospec->args[1];
+
+ return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE;
+}
+
static int sirfsoc_pinmux_probe(struct platform_device *pdev)
{
int ret;
@@ -1736,6 +1752,8 @@ static int sirfsoc_gpio_probe(struct device_node *np)
bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE;
bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL);
bank->chip.gc.of_node = np;
+ bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate;
+ bank->chip.gc.of_gpio_n_cells = 2;
bank->chip.regs = regs;
bank->id = i;
bank->is_marco = is_marco;
diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
new file mode 100644
index 000000000000..80b11e3415bc
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-sunxi.c
@@ -0,0 +1,1505 @@
+/*
+ * Allwinner A1X SoCs pinctrl driver.
+ *
+ * Copyright (C) 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.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/io.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun4i_a10_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* RTS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* CTS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* DTR */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* DSR */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* DCD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* RING */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB21,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB22,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart0")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB23,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart0")), /* RX */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC20,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC21,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC22,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC23,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC24,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart0")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart0")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH8,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH12,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH13,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH14,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH15,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH16,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH17,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH23,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH24,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH25,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH26,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PH27,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI8,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI12,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI13,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI14,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI15,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI16,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI17,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI18,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI19,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI20,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PI21,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+};
+
+static const struct sunxi_desc_pin sun5i_a13_pins[] = {
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* RX */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "uart1")), /* RX */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+};
+
+static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
+ .pins = sun4i_a10_pins,
+ .npins = ARRAY_SIZE(sun4i_a10_pins),
+};
+
+static const struct sunxi_pinctrl_desc sun5i_a13_pinctrl_data = {
+ .pins = sun5i_a13_pins,
+ .npins = ARRAY_SIZE(sun5i_a13_pins),
+};
+
+static struct sunxi_pinctrl_group *
+sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
+{
+ int i;
+
+ for (i = 0; i < pctl->ngroups; i++) {
+ struct sunxi_pinctrl_group *grp = pctl->groups + i;
+
+ if (!strcmp(grp->name, group))
+ return grp;
+ }
+
+ return NULL;
+}
+
+static struct sunxi_pinctrl_function *
+sunxi_pinctrl_find_function_by_name(struct sunxi_pinctrl *pctl,
+ const char *name)
+{
+ struct sunxi_pinctrl_function *func = pctl->functions;
+ int i;
+
+ for (i = 0; i < pctl->nfunctions; i++) {
+ if (!func[i].name)
+ break;
+
+ if (!strcmp(func[i].name, name))
+ return func + i;
+ }
+
+ return NULL;
+}
+
+static struct sunxi_desc_function *
+sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
+ const char *pin_name,
+ const char *func_name)
+{
+ int i;
+
+ for (i = 0; i < pctl->desc->npins; i++) {
+ const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+
+ if (!strcmp(pin->pin.name, pin_name)) {
+ struct sunxi_desc_function *func = pin->functions;
+
+ while (func->name) {
+ if (!strcmp(func->name, func_name))
+ return func;
+
+ func++;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->ngroups;
+}
+
+static const char *sunxi_pctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->groups[group].name;
+}
+
+static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned group,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = (unsigned *)&pctl->groups[group].pin;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *node,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ unsigned long *pinconfig;
+ struct property *prop;
+ const char *function;
+ const char *group;
+ int ret, nmaps, i = 0;
+ u32 val;
+
+ *map = NULL;
+ *num_maps = 0;
+
+ ret = of_property_read_string(node, "allwinner,function", &function);
+ if (ret) {
+ dev_err(pctl->dev,
+ "missing allwinner,function property in node %s\n",
+ node->name);
+ return -EINVAL;
+ }
+
+ nmaps = of_property_count_strings(node, "allwinner,pins") * 2;
+ if (nmaps < 0) {
+ dev_err(pctl->dev,
+ "missing allwinner,pins property in node %s\n",
+ node->name);
+ return -EINVAL;
+ }
+
+ *map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+
+ of_property_for_each_string(node, "allwinner,pins", prop, group) {
+ struct sunxi_pinctrl_group *grp =
+ sunxi_pinctrl_find_group_by_name(pctl, group);
+ int j = 0, configlen = 0;
+
+ if (!grp) {
+ dev_err(pctl->dev, "unknown pin %s", group);
+ continue;
+ }
+
+ if (!sunxi_pinctrl_desc_find_function_by_name(pctl,
+ grp->name,
+ function)) {
+ dev_err(pctl->dev, "unsupported function %s on pin %s",
+ function, group);
+ continue;
+ }
+
+ (*map)[i].type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)[i].data.mux.group = group;
+ (*map)[i].data.mux.function = function;
+
+ i++;
+
+ (*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ (*map)[i].data.configs.group_or_pin = group;
+
+ if (of_find_property(node, "allwinner,drive", NULL))
+ configlen++;
+ if (of_find_property(node, "allwinner,pull", NULL))
+ configlen++;
+
+ pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL);
+
+ if (!of_property_read_u32(node, "allwinner,drive", &val)) {
+ u16 strength = (val + 1) * 10;
+ pinconfig[j++] =
+ pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
+ strength);
+ }
+
+ if (!of_property_read_u32(node, "allwinner,pull", &val)) {
+ enum pin_config_param pull = PIN_CONFIG_END;
+ if (val == 1)
+ pull = PIN_CONFIG_BIAS_PULL_UP;
+ else if (val == 2)
+ pull = PIN_CONFIG_BIAS_PULL_DOWN;
+ pinconfig[j++] = pinconf_to_config_packed(pull, 0);
+ }
+
+ (*map)[i].data.configs.configs = pinconfig;
+ (*map)[i].data.configs.num_configs = configlen;
+
+ i++;
+ }
+
+ *num_maps = nmaps;
+
+ return 0;
+}
+
+static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map,
+ unsigned num_maps)
+{
+ int i;
+
+ for (i = 0; i < num_maps; i++) {
+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+ kfree(map[i].data.configs.configs);
+ }
+
+ kfree(map);
+}
+
+static struct pinctrl_ops sunxi_pctrl_ops = {
+ .dt_node_to_map = sunxi_pctrl_dt_node_to_map,
+ .dt_free_map = sunxi_pctrl_dt_free_map,
+ .get_groups_count = sunxi_pctrl_get_groups_count,
+ .get_group_name = sunxi_pctrl_get_group_name,
+ .get_group_pins = sunxi_pctrl_get_group_pins,
+};
+
+static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev,
+ unsigned group,
+ unsigned long *config)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *config = pctl->groups[group].config;
+
+ return 0;
+}
+
+static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned group,
+ unsigned long config)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct sunxi_pinctrl_group *g = &pctl->groups[group];
+ u32 val, mask;
+ u16 strength;
+ u8 dlevel;
+
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ strength = pinconf_to_config_argument(config);
+ if (strength > 40)
+ return -EINVAL;
+ /*
+ * We convert from mA to what the register expects:
+ * 0: 10mA
+ * 1: 20mA
+ * 2: 30mA
+ * 3: 40mA
+ */
+ dlevel = strength / 10 - 1;
+ val = readl(pctl->membase + sunxi_dlevel_reg(g->pin));
+ mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin);
+ writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin),
+ pctl->membase + sunxi_dlevel_reg(g->pin));
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ val = readl(pctl->membase + sunxi_pull_reg(g->pin));
+ mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
+ writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin),
+ pctl->membase + sunxi_pull_reg(g->pin));
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ val = readl(pctl->membase + sunxi_pull_reg(g->pin));
+ mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
+ writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin),
+ pctl->membase + sunxi_pull_reg(g->pin));
+ break;
+ default:
+ break;
+ }
+
+ /* cache the config value */
+ g->config = config;
+
+ return 0;
+}
+
+static struct pinconf_ops sunxi_pconf_ops = {
+ .pin_config_group_get = sunxi_pconf_group_get,
+ .pin_config_group_set = sunxi_pconf_group_set,
+};
+
+static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->nfunctions;
+}
+
+static const char *sunxi_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->functions[function].name;
+}
+
+static int sunxi_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pctl->functions[function].groups;
+ *num_groups = pctl->functions[function].ngroups;
+
+ return 0;
+}
+
+static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ u8 config)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ u32 val = readl(pctl->membase + sunxi_mux_reg(pin));
+ u32 mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
+ writel((val & ~mask) | config << sunxi_mux_offset(pin),
+ pctl->membase + sunxi_mux_reg(pin));
+}
+
+static int sunxi_pmx_enable(struct pinctrl_dev *pctldev,
+ unsigned function,
+ unsigned group)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct sunxi_pinctrl_group *g = pctl->groups + group;
+ struct sunxi_pinctrl_function *func = pctl->functions + function;
+ struct sunxi_desc_function *desc =
+ sunxi_pinctrl_desc_find_function_by_name(pctl,
+ g->name,
+ func->name);
+
+ if (!desc)
+ return -EINVAL;
+
+ sunxi_pmx_set(pctldev, g->pin, desc->muxval);
+
+ return 0;
+}
+
+static int
+sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset,
+ bool input)
+{
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct sunxi_desc_function *desc;
+ char pin_name[SUNXI_PIN_NAME_MAX_LEN];
+ const char *func;
+ u8 bank, pin;
+ int ret;
+
+ bank = (offset) / PINS_PER_BANK;
+ pin = (offset) % PINS_PER_BANK;
+
+ ret = sprintf(pin_name, "P%c%d", 'A' + bank, pin);
+ if (!ret)
+ goto error;
+
+ if (input)
+ func = "gpio_in";
+ else
+ func = "gpio_out";
+
+ desc = sunxi_pinctrl_desc_find_function_by_name(pctl,
+ pin_name,
+ func);
+ if (!desc) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ sunxi_pmx_set(pctldev, offset, desc->muxval);
+
+ ret = 0;
+
+error:
+ return ret;
+}
+
+static struct pinmux_ops sunxi_pmx_ops = {
+ .get_functions_count = sunxi_pmx_get_funcs_cnt,
+ .get_function_name = sunxi_pmx_get_func_name,
+ .get_function_groups = sunxi_pmx_get_func_groups,
+ .enable = sunxi_pmx_enable,
+ .gpio_set_direction = sunxi_pmx_gpio_set_direction,
+};
+
+static struct pinctrl_desc sunxi_pctrl_desc = {
+ .confops = &sunxi_pconf_ops,
+ .pctlops = &sunxi_pctrl_ops,
+ .pmxops = &sunxi_pmx_ops,
+};
+
+static int sunxi_pinctrl_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void sunxi_pinctrl_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+}
+
+static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ return pinctrl_gpio_direction_input(chip->base + offset);
+}
+
+static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+
+ u32 reg = sunxi_data_reg(offset);
+ u8 index = sunxi_data_offset(offset);
+ u32 val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+
+ return val;
+}
+
+static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ return pinctrl_gpio_direction_output(chip->base + offset);
+}
+
+static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+ u32 reg = sunxi_data_reg(offset);
+ u8 index = sunxi_data_offset(offset);
+
+ writel((value & DATA_PINS_MASK) << index, pctl->membase + reg);
+}
+
+static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
+{
+ int pin, base;
+
+ base = PINS_PER_BANK * gpiospec->args[0];
+ pin = base + gpiospec->args[1];
+
+ if (pin > (gc->base + gc->ngpio))
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpiospec->args[2];
+
+ return pin;
+}
+
+static struct gpio_chip sunxi_pinctrl_gpio_chip = {
+ .owner = THIS_MODULE,
+ .request = sunxi_pinctrl_gpio_request,
+ .free = sunxi_pinctrl_gpio_free,
+ .direction_input = sunxi_pinctrl_gpio_direction_input,
+ .direction_output = sunxi_pinctrl_gpio_direction_output,
+ .get = sunxi_pinctrl_gpio_get,
+ .set = sunxi_pinctrl_gpio_set,
+ .of_xlate = sunxi_pinctrl_gpio_of_xlate,
+ .of_gpio_n_cells = 3,
+ .can_sleep = 0,
+};
+
+static struct of_device_id sunxi_pinctrl_match[] = {
+ { .compatible = "allwinner,sun4i-a10-pinctrl", .data = (void *)&sun4i_a10_pinctrl_data },
+ { .compatible = "allwinner,sun5i-a13-pinctrl", .data = (void *)&sun5i_a13_pinctrl_data },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sunxi_pinctrl_match);
+
+static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl,
+ const char *name)
+{
+ struct sunxi_pinctrl_function *func = pctl->functions;
+
+ while (func->name) {
+ /* function already there */
+ if (strcmp(func->name, name) == 0) {
+ func->ngroups++;
+ return -EEXIST;
+ }
+ func++;
+ }
+
+ func->name = name;
+ func->ngroups = 1;
+
+ pctl->nfunctions++;
+
+ return 0;
+}
+
+static int sunxi_pinctrl_build_state(struct platform_device *pdev)
+{
+ struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
+ int i;
+
+ pctl->ngroups = pctl->desc->npins;
+
+ /* Allocate groups */
+ pctl->groups = devm_kzalloc(&pdev->dev,
+ pctl->ngroups * sizeof(*pctl->groups),
+ GFP_KERNEL);
+ if (!pctl->groups)
+ return -ENOMEM;
+
+ for (i = 0; i < pctl->desc->npins; i++) {
+ const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+ struct sunxi_pinctrl_group *group = pctl->groups + i;
+
+ group->name = pin->pin.name;
+ group->pin = pin->pin.number;
+ }
+
+ /*
+ * We suppose that we won't have any more functions than pins,
+ * we'll reallocate that later anyway
+ */
+ pctl->functions = devm_kzalloc(&pdev->dev,
+ pctl->desc->npins * sizeof(*pctl->functions),
+ GFP_KERNEL);
+ if (!pctl->functions)
+ return -ENOMEM;
+
+ /* Count functions and their associated groups */
+ for (i = 0; i < pctl->desc->npins; i++) {
+ const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+ struct sunxi_desc_function *func = pin->functions;
+
+ while (func->name) {
+ sunxi_pinctrl_add_function(pctl, func->name);
+ func++;
+ }
+ }
+
+ pctl->functions = krealloc(pctl->functions,
+ pctl->nfunctions * sizeof(*pctl->functions),
+ GFP_KERNEL);
+
+ for (i = 0; i < pctl->desc->npins; i++) {
+ const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+ struct sunxi_desc_function *func = pin->functions;
+
+ while (func->name) {
+ struct sunxi_pinctrl_function *func_item;
+ const char **func_grp;
+
+ func_item = sunxi_pinctrl_find_function_by_name(pctl,
+ func->name);
+ if (!func_item)
+ return -EINVAL;
+
+ if (!func_item->groups) {
+ func_item->groups =
+ devm_kzalloc(&pdev->dev,
+ func_item->ngroups * sizeof(*func_item->groups),
+ GFP_KERNEL);
+ if (!func_item->groups)
+ return -ENOMEM;
+ }
+
+ func_grp = func_item->groups;
+ while (*func_grp)
+ func_grp++;
+
+ *func_grp = pin->pin.name;
+ func++;
+ }
+ }
+
+ return 0;
+}
+
+static int sunxi_pinctrl_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ const struct of_device_id *device;
+ struct pinctrl_pin_desc *pins;
+ struct sunxi_pinctrl *pctl;
+ int i, ret, last_pin;
+
+ pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+ if (!pctl)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, pctl);
+
+ pctl->membase = of_iomap(node, 0);
+ if (!pctl->membase)
+ return -ENOMEM;
+
+ device = of_match_device(sunxi_pinctrl_match, &pdev->dev);
+ if (!device)
+ return -ENODEV;
+
+ pctl->desc = (struct sunxi_pinctrl_desc *)device->data;
+
+ ret = sunxi_pinctrl_build_state(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
+ return ret;
+ }
+
+ pins = devm_kzalloc(&pdev->dev,
+ pctl->desc->npins * sizeof(*pins),
+ GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ for (i = 0; i < pctl->desc->npins; i++)
+ pins[i] = pctl->desc->pins[i].pin;
+
+ sunxi_pctrl_desc.name = dev_name(&pdev->dev);
+ sunxi_pctrl_desc.owner = THIS_MODULE;
+ sunxi_pctrl_desc.pins = pins;
+ sunxi_pctrl_desc.npins = pctl->desc->npins;
+ pctl->dev = &pdev->dev;
+ pctl->pctl_dev = pinctrl_register(&sunxi_pctrl_desc,
+ &pdev->dev, pctl);
+ if (!pctl->pctl_dev) {
+ dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
+ return -EINVAL;
+ }
+
+ pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
+ if (!pctl->chip) {
+ ret = -ENOMEM;
+ goto pinctrl_error;
+ }
+
+ last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number;
+ pctl->chip = &sunxi_pinctrl_gpio_chip;
+ pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK);
+ pctl->chip->label = dev_name(&pdev->dev);
+ pctl->chip->dev = &pdev->dev;
+ pctl->chip->base = 0;
+
+ ret = gpiochip_add(pctl->chip);
+ if (ret)
+ goto pinctrl_error;
+
+ for (i = 0; i < pctl->desc->npins; i++) {
+ const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+
+ ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
+ pin->pin.number,
+ pin->pin.number, 1);
+ if (ret)
+ goto gpiochip_error;
+ }
+
+ dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
+
+ return 0;
+
+gpiochip_error:
+ ret = gpiochip_remove(pctl->chip);
+pinctrl_error:
+ pinctrl_unregister(pctl->pctl_dev);
+ return ret;
+}
+
+static struct platform_driver sunxi_pinctrl_driver = {
+ .probe = sunxi_pinctrl_probe,
+ .driver = {
+ .name = "sunxi-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = sunxi_pinctrl_match,
+ },
+};
+module_platform_driver(sunxi_pinctrl_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("Allwinner A1X pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h
new file mode 100644
index 000000000000..e921621059ce
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-sunxi.h
@@ -0,0 +1,478 @@
+/*
+ * Allwinner A1X SoCs pinctrl driver.
+ *
+ * Copyright (C) 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.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.
+ */
+
+#ifndef __PINCTRL_SUNXI_H
+#define __PINCTRL_SUNXI_H
+
+#include <linux/kernel.h>
+
+#define PA_BASE 0
+#define PB_BASE 32
+#define PC_BASE 64
+#define PD_BASE 96
+#define PE_BASE 128
+#define PF_BASE 160
+#define PG_BASE 192
+#define PH_BASE 224
+#define PI_BASE 256
+
+#define SUNXI_PINCTRL_PIN_PA0 PINCTRL_PIN(PA_BASE + 0, "PA0")
+#define SUNXI_PINCTRL_PIN_PA1 PINCTRL_PIN(PA_BASE + 1, "PA1")
+#define SUNXI_PINCTRL_PIN_PA2 PINCTRL_PIN(PA_BASE + 2, "PA2")
+#define SUNXI_PINCTRL_PIN_PA3 PINCTRL_PIN(PA_BASE + 3, "PA3")
+#define SUNXI_PINCTRL_PIN_PA4 PINCTRL_PIN(PA_BASE + 4, "PA4")
+#define SUNXI_PINCTRL_PIN_PA5 PINCTRL_PIN(PA_BASE + 5, "PA5")
+#define SUNXI_PINCTRL_PIN_PA6 PINCTRL_PIN(PA_BASE + 6, "PA6")
+#define SUNXI_PINCTRL_PIN_PA7 PINCTRL_PIN(PA_BASE + 7, "PA7")
+#define SUNXI_PINCTRL_PIN_PA8 PINCTRL_PIN(PA_BASE + 8, "PA8")
+#define SUNXI_PINCTRL_PIN_PA9 PINCTRL_PIN(PA_BASE + 9, "PA9")
+#define SUNXI_PINCTRL_PIN_PA10 PINCTRL_PIN(PA_BASE + 10, "PA10")
+#define SUNXI_PINCTRL_PIN_PA11 PINCTRL_PIN(PA_BASE + 11, "PA11")
+#define SUNXI_PINCTRL_PIN_PA12 PINCTRL_PIN(PA_BASE + 12, "PA12")
+#define SUNXI_PINCTRL_PIN_PA13 PINCTRL_PIN(PA_BASE + 13, "PA13")
+#define SUNXI_PINCTRL_PIN_PA14 PINCTRL_PIN(PA_BASE + 14, "PA14")
+#define SUNXI_PINCTRL_PIN_PA15 PINCTRL_PIN(PA_BASE + 15, "PA15")
+#define SUNXI_PINCTRL_PIN_PA16 PINCTRL_PIN(PA_BASE + 16, "PA16")
+#define SUNXI_PINCTRL_PIN_PA17 PINCTRL_PIN(PA_BASE + 17, "PA17")
+#define SUNXI_PINCTRL_PIN_PA18 PINCTRL_PIN(PA_BASE + 18, "PA18")
+#define SUNXI_PINCTRL_PIN_PA19 PINCTRL_PIN(PA_BASE + 19, "PA19")
+#define SUNXI_PINCTRL_PIN_PA20 PINCTRL_PIN(PA_BASE + 20, "PA20")
+#define SUNXI_PINCTRL_PIN_PA21 PINCTRL_PIN(PA_BASE + 21, "PA21")
+#define SUNXI_PINCTRL_PIN_PA22 PINCTRL_PIN(PA_BASE + 22, "PA22")
+#define SUNXI_PINCTRL_PIN_PA23 PINCTRL_PIN(PA_BASE + 23, "PA23")
+#define SUNXI_PINCTRL_PIN_PA24 PINCTRL_PIN(PA_BASE + 24, "PA24")
+#define SUNXI_PINCTRL_PIN_PA25 PINCTRL_PIN(PA_BASE + 25, "PA25")
+#define SUNXI_PINCTRL_PIN_PA26 PINCTRL_PIN(PA_BASE + 26, "PA26")
+#define SUNXI_PINCTRL_PIN_PA27 PINCTRL_PIN(PA_BASE + 27, "PA27")
+#define SUNXI_PINCTRL_PIN_PA28 PINCTRL_PIN(PA_BASE + 28, "PA28")
+#define SUNXI_PINCTRL_PIN_PA29 PINCTRL_PIN(PA_BASE + 29, "PA29")
+#define SUNXI_PINCTRL_PIN_PA30 PINCTRL_PIN(PA_BASE + 30, "PA30")
+#define SUNXI_PINCTRL_PIN_PA31 PINCTRL_PIN(PA_BASE + 31, "PA31")
+
+#define SUNXI_PINCTRL_PIN_PB0 PINCTRL_PIN(PB_BASE + 0, "PB0")
+#define SUNXI_PINCTRL_PIN_PB1 PINCTRL_PIN(PB_BASE + 1, "PB1")
+#define SUNXI_PINCTRL_PIN_PB2 PINCTRL_PIN(PB_BASE + 2, "PB2")
+#define SUNXI_PINCTRL_PIN_PB3 PINCTRL_PIN(PB_BASE + 3, "PB3")
+#define SUNXI_PINCTRL_PIN_PB4 PINCTRL_PIN(PB_BASE + 4, "PB4")
+#define SUNXI_PINCTRL_PIN_PB5 PINCTRL_PIN(PB_BASE + 5, "PB5")
+#define SUNXI_PINCTRL_PIN_PB6 PINCTRL_PIN(PB_BASE + 6, "PB6")
+#define SUNXI_PINCTRL_PIN_PB7 PINCTRL_PIN(PB_BASE + 7, "PB7")
+#define SUNXI_PINCTRL_PIN_PB8 PINCTRL_PIN(PB_BASE + 8, "PB8")
+#define SUNXI_PINCTRL_PIN_PB9 PINCTRL_PIN(PB_BASE + 9, "PB9")
+#define SUNXI_PINCTRL_PIN_PB10 PINCTRL_PIN(PB_BASE + 10, "PB10")
+#define SUNXI_PINCTRL_PIN_PB11 PINCTRL_PIN(PB_BASE + 11, "PB11")
+#define SUNXI_PINCTRL_PIN_PB12 PINCTRL_PIN(PB_BASE + 12, "PB12")
+#define SUNXI_PINCTRL_PIN_PB13 PINCTRL_PIN(PB_BASE + 13, "PB13")
+#define SUNXI_PINCTRL_PIN_PB14 PINCTRL_PIN(PB_BASE + 14, "PB14")
+#define SUNXI_PINCTRL_PIN_PB15 PINCTRL_PIN(PB_BASE + 15, "PB15")
+#define SUNXI_PINCTRL_PIN_PB16 PINCTRL_PIN(PB_BASE + 16, "PB16")
+#define SUNXI_PINCTRL_PIN_PB17 PINCTRL_PIN(PB_BASE + 17, "PB17")
+#define SUNXI_PINCTRL_PIN_PB18 PINCTRL_PIN(PB_BASE + 18, "PB18")
+#define SUNXI_PINCTRL_PIN_PB19 PINCTRL_PIN(PB_BASE + 19, "PB19")
+#define SUNXI_PINCTRL_PIN_PB20 PINCTRL_PIN(PB_BASE + 20, "PB20")
+#define SUNXI_PINCTRL_PIN_PB21 PINCTRL_PIN(PB_BASE + 21, "PB21")
+#define SUNXI_PINCTRL_PIN_PB22 PINCTRL_PIN(PB_BASE + 22, "PB22")
+#define SUNXI_PINCTRL_PIN_PB23 PINCTRL_PIN(PB_BASE + 23, "PB23")
+#define SUNXI_PINCTRL_PIN_PB24 PINCTRL_PIN(PB_BASE + 24, "PB24")
+#define SUNXI_PINCTRL_PIN_PB25 PINCTRL_PIN(PB_BASE + 25, "PB25")
+#define SUNXI_PINCTRL_PIN_PB26 PINCTRL_PIN(PB_BASE + 26, "PB26")
+#define SUNXI_PINCTRL_PIN_PB27 PINCTRL_PIN(PB_BASE + 27, "PB27")
+#define SUNXI_PINCTRL_PIN_PB28 PINCTRL_PIN(PB_BASE + 28, "PB28")
+#define SUNXI_PINCTRL_PIN_PB29 PINCTRL_PIN(PB_BASE + 29, "PB29")
+#define SUNXI_PINCTRL_PIN_PB30 PINCTRL_PIN(PB_BASE + 30, "PB30")
+#define SUNXI_PINCTRL_PIN_PB31 PINCTRL_PIN(PB_BASE + 31, "PB31")
+
+#define SUNXI_PINCTRL_PIN_PC0 PINCTRL_PIN(PC_BASE + 0, "PC0")
+#define SUNXI_PINCTRL_PIN_PC1 PINCTRL_PIN(PC_BASE + 1, "PC1")
+#define SUNXI_PINCTRL_PIN_PC2 PINCTRL_PIN(PC_BASE + 2, "PC2")
+#define SUNXI_PINCTRL_PIN_PC3 PINCTRL_PIN(PC_BASE + 3, "PC3")
+#define SUNXI_PINCTRL_PIN_PC4 PINCTRL_PIN(PC_BASE + 4, "PC4")
+#define SUNXI_PINCTRL_PIN_PC5 PINCTRL_PIN(PC_BASE + 5, "PC5")
+#define SUNXI_PINCTRL_PIN_PC6 PINCTRL_PIN(PC_BASE + 6, "PC6")
+#define SUNXI_PINCTRL_PIN_PC7 PINCTRL_PIN(PC_BASE + 7, "PC7")
+#define SUNXI_PINCTRL_PIN_PC8 PINCTRL_PIN(PC_BASE + 8, "PC8")
+#define SUNXI_PINCTRL_PIN_PC9 PINCTRL_PIN(PC_BASE + 9, "PC9")
+#define SUNXI_PINCTRL_PIN_PC10 PINCTRL_PIN(PC_BASE + 10, "PC10")
+#define SUNXI_PINCTRL_PIN_PC11 PINCTRL_PIN(PC_BASE + 11, "PC11")
+#define SUNXI_PINCTRL_PIN_PC12 PINCTRL_PIN(PC_BASE + 12, "PC12")
+#define SUNXI_PINCTRL_PIN_PC13 PINCTRL_PIN(PC_BASE + 13, "PC13")
+#define SUNXI_PINCTRL_PIN_PC14 PINCTRL_PIN(PC_BASE + 14, "PC14")
+#define SUNXI_PINCTRL_PIN_PC15 PINCTRL_PIN(PC_BASE + 15, "PC15")
+#define SUNXI_PINCTRL_PIN_PC16 PINCTRL_PIN(PC_BASE + 16, "PC16")
+#define SUNXI_PINCTRL_PIN_PC17 PINCTRL_PIN(PC_BASE + 17, "PC17")
+#define SUNXI_PINCTRL_PIN_PC18 PINCTRL_PIN(PC_BASE + 18, "PC18")
+#define SUNXI_PINCTRL_PIN_PC19 PINCTRL_PIN(PC_BASE + 19, "PC19")
+#define SUNXI_PINCTRL_PIN_PC20 PINCTRL_PIN(PC_BASE + 20, "PC20")
+#define SUNXI_PINCTRL_PIN_PC21 PINCTRL_PIN(PC_BASE + 21, "PC21")
+#define SUNXI_PINCTRL_PIN_PC22 PINCTRL_PIN(PC_BASE + 22, "PC22")
+#define SUNXI_PINCTRL_PIN_PC23 PINCTRL_PIN(PC_BASE + 23, "PC23")
+#define SUNXI_PINCTRL_PIN_PC24 PINCTRL_PIN(PC_BASE + 24, "PC24")
+#define SUNXI_PINCTRL_PIN_PC25 PINCTRL_PIN(PC_BASE + 25, "PC25")
+#define SUNXI_PINCTRL_PIN_PC26 PINCTRL_PIN(PC_BASE + 26, "PC26")
+#define SUNXI_PINCTRL_PIN_PC27 PINCTRL_PIN(PC_BASE + 27, "PC27")
+#define SUNXI_PINCTRL_PIN_PC28 PINCTRL_PIN(PC_BASE + 28, "PC28")
+#define SUNXI_PINCTRL_PIN_PC29 PINCTRL_PIN(PC_BASE + 29, "PC29")
+#define SUNXI_PINCTRL_PIN_PC30 PINCTRL_PIN(PC_BASE + 30, "PC30")
+#define SUNXI_PINCTRL_PIN_PC31 PINCTRL_PIN(PC_BASE + 31, "PC31")
+
+#define SUNXI_PINCTRL_PIN_PD0 PINCTRL_PIN(PD_BASE + 0, "PD0")
+#define SUNXI_PINCTRL_PIN_PD1 PINCTRL_PIN(PD_BASE + 1, "PD1")
+#define SUNXI_PINCTRL_PIN_PD2 PINCTRL_PIN(PD_BASE + 2, "PD2")
+#define SUNXI_PINCTRL_PIN_PD3 PINCTRL_PIN(PD_BASE + 3, "PD3")
+#define SUNXI_PINCTRL_PIN_PD4 PINCTRL_PIN(PD_BASE + 4, "PD4")
+#define SUNXI_PINCTRL_PIN_PD5 PINCTRL_PIN(PD_BASE + 5, "PD5")
+#define SUNXI_PINCTRL_PIN_PD6 PINCTRL_PIN(PD_BASE + 6, "PD6")
+#define SUNXI_PINCTRL_PIN_PD7 PINCTRL_PIN(PD_BASE + 7, "PD7")
+#define SUNXI_PINCTRL_PIN_PD8 PINCTRL_PIN(PD_BASE + 8, "PD8")
+#define SUNXI_PINCTRL_PIN_PD9 PINCTRL_PIN(PD_BASE + 9, "PD9")
+#define SUNXI_PINCTRL_PIN_PD10 PINCTRL_PIN(PD_BASE + 10, "PD10")
+#define SUNXI_PINCTRL_PIN_PD11 PINCTRL_PIN(PD_BASE + 11, "PD11")
+#define SUNXI_PINCTRL_PIN_PD12 PINCTRL_PIN(PD_BASE + 12, "PD12")
+#define SUNXI_PINCTRL_PIN_PD13 PINCTRL_PIN(PD_BASE + 13, "PD13")
+#define SUNXI_PINCTRL_PIN_PD14 PINCTRL_PIN(PD_BASE + 14, "PD14")
+#define SUNXI_PINCTRL_PIN_PD15 PINCTRL_PIN(PD_BASE + 15, "PD15")
+#define SUNXI_PINCTRL_PIN_PD16 PINCTRL_PIN(PD_BASE + 16, "PD16")
+#define SUNXI_PINCTRL_PIN_PD17 PINCTRL_PIN(PD_BASE + 17, "PD17")
+#define SUNXI_PINCTRL_PIN_PD18 PINCTRL_PIN(PD_BASE + 18, "PD18")
+#define SUNXI_PINCTRL_PIN_PD19 PINCTRL_PIN(PD_BASE + 19, "PD19")
+#define SUNXI_PINCTRL_PIN_PD20 PINCTRL_PIN(PD_BASE + 20, "PD20")
+#define SUNXI_PINCTRL_PIN_PD21 PINCTRL_PIN(PD_BASE + 21, "PD21")
+#define SUNXI_PINCTRL_PIN_PD22 PINCTRL_PIN(PD_BASE + 22, "PD22")
+#define SUNXI_PINCTRL_PIN_PD23 PINCTRL_PIN(PD_BASE + 23, "PD23")
+#define SUNXI_PINCTRL_PIN_PD24 PINCTRL_PIN(PD_BASE + 24, "PD24")
+#define SUNXI_PINCTRL_PIN_PD25 PINCTRL_PIN(PD_BASE + 25, "PD25")
+#define SUNXI_PINCTRL_PIN_PD26 PINCTRL_PIN(PD_BASE + 26, "PD26")
+#define SUNXI_PINCTRL_PIN_PD27 PINCTRL_PIN(PD_BASE + 27, "PD27")
+#define SUNXI_PINCTRL_PIN_PD28 PINCTRL_PIN(PD_BASE + 28, "PD28")
+#define SUNXI_PINCTRL_PIN_PD29 PINCTRL_PIN(PD_BASE + 29, "PD29")
+#define SUNXI_PINCTRL_PIN_PD30 PINCTRL_PIN(PD_BASE + 30, "PD30")
+#define SUNXI_PINCTRL_PIN_PD31 PINCTRL_PIN(PD_BASE + 31, "PD31")
+
+#define SUNXI_PINCTRL_PIN_PE0 PINCTRL_PIN(PE_BASE + 0, "PE0")
+#define SUNXI_PINCTRL_PIN_PE1 PINCTRL_PIN(PE_BASE + 1, "PE1")
+#define SUNXI_PINCTRL_PIN_PE2 PINCTRL_PIN(PE_BASE + 2, "PE2")
+#define SUNXI_PINCTRL_PIN_PE3 PINCTRL_PIN(PE_BASE + 3, "PE3")
+#define SUNXI_PINCTRL_PIN_PE4 PINCTRL_PIN(PE_BASE + 4, "PE4")
+#define SUNXI_PINCTRL_PIN_PE5 PINCTRL_PIN(PE_BASE + 5, "PE5")
+#define SUNXI_PINCTRL_PIN_PE6 PINCTRL_PIN(PE_BASE + 6, "PE6")
+#define SUNXI_PINCTRL_PIN_PE7 PINCTRL_PIN(PE_BASE + 7, "PE7")
+#define SUNXI_PINCTRL_PIN_PE8 PINCTRL_PIN(PE_BASE + 8, "PE8")
+#define SUNXI_PINCTRL_PIN_PE9 PINCTRL_PIN(PE_BASE + 9, "PE9")
+#define SUNXI_PINCTRL_PIN_PE10 PINCTRL_PIN(PE_BASE + 10, "PE10")
+#define SUNXI_PINCTRL_PIN_PE11 PINCTRL_PIN(PE_BASE + 11, "PE11")
+#define SUNXI_PINCTRL_PIN_PE12 PINCTRL_PIN(PE_BASE + 12, "PE12")
+#define SUNXI_PINCTRL_PIN_PE13 PINCTRL_PIN(PE_BASE + 13, "PE13")
+#define SUNXI_PINCTRL_PIN_PE14 PINCTRL_PIN(PE_BASE + 14, "PE14")
+#define SUNXI_PINCTRL_PIN_PE15 PINCTRL_PIN(PE_BASE + 15, "PE15")
+#define SUNXI_PINCTRL_PIN_PE16 PINCTRL_PIN(PE_BASE + 16, "PE16")
+#define SUNXI_PINCTRL_PIN_PE17 PINCTRL_PIN(PE_BASE + 17, "PE17")
+#define SUNXI_PINCTRL_PIN_PE18 PINCTRL_PIN(PE_BASE + 18, "PE18")
+#define SUNXI_PINCTRL_PIN_PE19 PINCTRL_PIN(PE_BASE + 19, "PE19")
+#define SUNXI_PINCTRL_PIN_PE20 PINCTRL_PIN(PE_BASE + 20, "PE20")
+#define SUNXI_PINCTRL_PIN_PE21 PINCTRL_PIN(PE_BASE + 21, "PE21")
+#define SUNXI_PINCTRL_PIN_PE22 PINCTRL_PIN(PE_BASE + 22, "PE22")
+#define SUNXI_PINCTRL_PIN_PE23 PINCTRL_PIN(PE_BASE + 23, "PE23")
+#define SUNXI_PINCTRL_PIN_PE24 PINCTRL_PIN(PE_BASE + 24, "PE24")
+#define SUNXI_PINCTRL_PIN_PE25 PINCTRL_PIN(PE_BASE + 25, "PE25")
+#define SUNXI_PINCTRL_PIN_PE26 PINCTRL_PIN(PE_BASE + 26, "PE26")
+#define SUNXI_PINCTRL_PIN_PE27 PINCTRL_PIN(PE_BASE + 27, "PE27")
+#define SUNXI_PINCTRL_PIN_PE28 PINCTRL_PIN(PE_BASE + 28, "PE28")
+#define SUNXI_PINCTRL_PIN_PE29 PINCTRL_PIN(PE_BASE + 29, "PE29")
+#define SUNXI_PINCTRL_PIN_PE30 PINCTRL_PIN(PE_BASE + 30, "PE30")
+#define SUNXI_PINCTRL_PIN_PE31 PINCTRL_PIN(PE_BASE + 31, "PE31")
+
+#define SUNXI_PINCTRL_PIN_PF0 PINCTRL_PIN(PF_BASE + 0, "PF0")
+#define SUNXI_PINCTRL_PIN_PF1 PINCTRL_PIN(PF_BASE + 1, "PF1")
+#define SUNXI_PINCTRL_PIN_PF2 PINCTRL_PIN(PF_BASE + 2, "PF2")
+#define SUNXI_PINCTRL_PIN_PF3 PINCTRL_PIN(PF_BASE + 3, "PF3")
+#define SUNXI_PINCTRL_PIN_PF4 PINCTRL_PIN(PF_BASE + 4, "PF4")
+#define SUNXI_PINCTRL_PIN_PF5 PINCTRL_PIN(PF_BASE + 5, "PF5")
+#define SUNXI_PINCTRL_PIN_PF6 PINCTRL_PIN(PF_BASE + 6, "PF6")
+#define SUNXI_PINCTRL_PIN_PF7 PINCTRL_PIN(PF_BASE + 7, "PF7")
+#define SUNXI_PINCTRL_PIN_PF8 PINCTRL_PIN(PF_BASE + 8, "PF8")
+#define SUNXI_PINCTRL_PIN_PF9 PINCTRL_PIN(PF_BASE + 9, "PF9")
+#define SUNXI_PINCTRL_PIN_PF10 PINCTRL_PIN(PF_BASE + 10, "PF10")
+#define SUNXI_PINCTRL_PIN_PF11 PINCTRL_PIN(PF_BASE + 11, "PF11")
+#define SUNXI_PINCTRL_PIN_PF12 PINCTRL_PIN(PF_BASE + 12, "PF12")
+#define SUNXI_PINCTRL_PIN_PF13 PINCTRL_PIN(PF_BASE + 13, "PF13")
+#define SUNXI_PINCTRL_PIN_PF14 PINCTRL_PIN(PF_BASE + 14, "PF14")
+#define SUNXI_PINCTRL_PIN_PF15 PINCTRL_PIN(PF_BASE + 15, "PF15")
+#define SUNXI_PINCTRL_PIN_PF16 PINCTRL_PIN(PF_BASE + 16, "PF16")
+#define SUNXI_PINCTRL_PIN_PF17 PINCTRL_PIN(PF_BASE + 17, "PF17")
+#define SUNXI_PINCTRL_PIN_PF18 PINCTRL_PIN(PF_BASE + 18, "PF18")
+#define SUNXI_PINCTRL_PIN_PF19 PINCTRL_PIN(PF_BASE + 19, "PF19")
+#define SUNXI_PINCTRL_PIN_PF20 PINCTRL_PIN(PF_BASE + 20, "PF20")
+#define SUNXI_PINCTRL_PIN_PF21 PINCTRL_PIN(PF_BASE + 21, "PF21")
+#define SUNXI_PINCTRL_PIN_PF22 PINCTRL_PIN(PF_BASE + 22, "PF22")
+#define SUNXI_PINCTRL_PIN_PF23 PINCTRL_PIN(PF_BASE + 23, "PF23")
+#define SUNXI_PINCTRL_PIN_PF24 PINCTRL_PIN(PF_BASE + 24, "PF24")
+#define SUNXI_PINCTRL_PIN_PF25 PINCTRL_PIN(PF_BASE + 25, "PF25")
+#define SUNXI_PINCTRL_PIN_PF26 PINCTRL_PIN(PF_BASE + 26, "PF26")
+#define SUNXI_PINCTRL_PIN_PF27 PINCTRL_PIN(PF_BASE + 27, "PF27")
+#define SUNXI_PINCTRL_PIN_PF28 PINCTRL_PIN(PF_BASE + 28, "PF28")
+#define SUNXI_PINCTRL_PIN_PF29 PINCTRL_PIN(PF_BASE + 29, "PF29")
+#define SUNXI_PINCTRL_PIN_PF30 PINCTRL_PIN(PF_BASE + 30, "PF30")
+#define SUNXI_PINCTRL_PIN_PF31 PINCTRL_PIN(PF_BASE + 31, "PF31")
+
+#define SUNXI_PINCTRL_PIN_PG0 PINCTRL_PIN(PG_BASE + 0, "PG0")
+#define SUNXI_PINCTRL_PIN_PG1 PINCTRL_PIN(PG_BASE + 1, "PG1")
+#define SUNXI_PINCTRL_PIN_PG2 PINCTRL_PIN(PG_BASE + 2, "PG2")
+#define SUNXI_PINCTRL_PIN_PG3 PINCTRL_PIN(PG_BASE + 3, "PG3")
+#define SUNXI_PINCTRL_PIN_PG4 PINCTRL_PIN(PG_BASE + 4, "PG4")
+#define SUNXI_PINCTRL_PIN_PG5 PINCTRL_PIN(PG_BASE + 5, "PG5")
+#define SUNXI_PINCTRL_PIN_PG6 PINCTRL_PIN(PG_BASE + 6, "PG6")
+#define SUNXI_PINCTRL_PIN_PG7 PINCTRL_PIN(PG_BASE + 7, "PG7")
+#define SUNXI_PINCTRL_PIN_PG8 PINCTRL_PIN(PG_BASE + 8, "PG8")
+#define SUNXI_PINCTRL_PIN_PG9 PINCTRL_PIN(PG_BASE + 9, "PG9")
+#define SUNXI_PINCTRL_PIN_PG10 PINCTRL_PIN(PG_BASE + 10, "PG10")
+#define SUNXI_PINCTRL_PIN_PG11 PINCTRL_PIN(PG_BASE + 11, "PG11")
+#define SUNXI_PINCTRL_PIN_PG12 PINCTRL_PIN(PG_BASE + 12, "PG12")
+#define SUNXI_PINCTRL_PIN_PG13 PINCTRL_PIN(PG_BASE + 13, "PG13")
+#define SUNXI_PINCTRL_PIN_PG14 PINCTRL_PIN(PG_BASE + 14, "PG14")
+#define SUNXI_PINCTRL_PIN_PG15 PINCTRL_PIN(PG_BASE + 15, "PG15")
+#define SUNXI_PINCTRL_PIN_PG16 PINCTRL_PIN(PG_BASE + 16, "PG16")
+#define SUNXI_PINCTRL_PIN_PG17 PINCTRL_PIN(PG_BASE + 17, "PG17")
+#define SUNXI_PINCTRL_PIN_PG18 PINCTRL_PIN(PG_BASE + 18, "PG18")
+#define SUNXI_PINCTRL_PIN_PG19 PINCTRL_PIN(PG_BASE + 19, "PG19")
+#define SUNXI_PINCTRL_PIN_PG20 PINCTRL_PIN(PG_BASE + 20, "PG20")
+#define SUNXI_PINCTRL_PIN_PG21 PINCTRL_PIN(PG_BASE + 21, "PG21")
+#define SUNXI_PINCTRL_PIN_PG22 PINCTRL_PIN(PG_BASE + 22, "PG22")
+#define SUNXI_PINCTRL_PIN_PG23 PINCTRL_PIN(PG_BASE + 23, "PG23")
+#define SUNXI_PINCTRL_PIN_PG24 PINCTRL_PIN(PG_BASE + 24, "PG24")
+#define SUNXI_PINCTRL_PIN_PG25 PINCTRL_PIN(PG_BASE + 25, "PG25")
+#define SUNXI_PINCTRL_PIN_PG26 PINCTRL_PIN(PG_BASE + 26, "PG26")
+#define SUNXI_PINCTRL_PIN_PG27 PINCTRL_PIN(PG_BASE + 27, "PG27")
+#define SUNXI_PINCTRL_PIN_PG28 PINCTRL_PIN(PG_BASE + 28, "PG28")
+#define SUNXI_PINCTRL_PIN_PG29 PINCTRL_PIN(PG_BASE + 29, "PG29")
+#define SUNXI_PINCTRL_PIN_PG30 PINCTRL_PIN(PG_BASE + 30, "PG30")
+#define SUNXI_PINCTRL_PIN_PG31 PINCTRL_PIN(PG_BASE + 31, "PG31")
+
+#define SUNXI_PINCTRL_PIN_PH0 PINCTRL_PIN(PH_BASE + 0, "PH0")
+#define SUNXI_PINCTRL_PIN_PH1 PINCTRL_PIN(PH_BASE + 1, "PH1")
+#define SUNXI_PINCTRL_PIN_PH2 PINCTRL_PIN(PH_BASE + 2, "PH2")
+#define SUNXI_PINCTRL_PIN_PH3 PINCTRL_PIN(PH_BASE + 3, "PH3")
+#define SUNXI_PINCTRL_PIN_PH4 PINCTRL_PIN(PH_BASE + 4, "PH4")
+#define SUNXI_PINCTRL_PIN_PH5 PINCTRL_PIN(PH_BASE + 5, "PH5")
+#define SUNXI_PINCTRL_PIN_PH6 PINCTRL_PIN(PH_BASE + 6, "PH6")
+#define SUNXI_PINCTRL_PIN_PH7 PINCTRL_PIN(PH_BASE + 7, "PH7")
+#define SUNXI_PINCTRL_PIN_PH8 PINCTRL_PIN(PH_BASE + 8, "PH8")
+#define SUNXI_PINCTRL_PIN_PH9 PINCTRL_PIN(PH_BASE + 9, "PH9")
+#define SUNXI_PINCTRL_PIN_PH10 PINCTRL_PIN(PH_BASE + 10, "PH10")
+#define SUNXI_PINCTRL_PIN_PH11 PINCTRL_PIN(PH_BASE + 11, "PH11")
+#define SUNXI_PINCTRL_PIN_PH12 PINCTRL_PIN(PH_BASE + 12, "PH12")
+#define SUNXI_PINCTRL_PIN_PH13 PINCTRL_PIN(PH_BASE + 13, "PH13")
+#define SUNXI_PINCTRL_PIN_PH14 PINCTRL_PIN(PH_BASE + 14, "PH14")
+#define SUNXI_PINCTRL_PIN_PH15 PINCTRL_PIN(PH_BASE + 15, "PH15")
+#define SUNXI_PINCTRL_PIN_PH16 PINCTRL_PIN(PH_BASE + 16, "PH16")
+#define SUNXI_PINCTRL_PIN_PH17 PINCTRL_PIN(PH_BASE + 17, "PH17")
+#define SUNXI_PINCTRL_PIN_PH18 PINCTRL_PIN(PH_BASE + 18, "PH18")
+#define SUNXI_PINCTRL_PIN_PH19 PINCTRL_PIN(PH_BASE + 19, "PH19")
+#define SUNXI_PINCTRL_PIN_PH20 PINCTRL_PIN(PH_BASE + 20, "PH20")
+#define SUNXI_PINCTRL_PIN_PH21 PINCTRL_PIN(PH_BASE + 21, "PH21")
+#define SUNXI_PINCTRL_PIN_PH22 PINCTRL_PIN(PH_BASE + 22, "PH22")
+#define SUNXI_PINCTRL_PIN_PH23 PINCTRL_PIN(PH_BASE + 23, "PH23")
+#define SUNXI_PINCTRL_PIN_PH24 PINCTRL_PIN(PH_BASE + 24, "PH24")
+#define SUNXI_PINCTRL_PIN_PH25 PINCTRL_PIN(PH_BASE + 25, "PH25")
+#define SUNXI_PINCTRL_PIN_PH26 PINCTRL_PIN(PH_BASE + 26, "PH26")
+#define SUNXI_PINCTRL_PIN_PH27 PINCTRL_PIN(PH_BASE + 27, "PH27")
+#define SUNXI_PINCTRL_PIN_PH28 PINCTRL_PIN(PH_BASE + 28, "PH28")
+#define SUNXI_PINCTRL_PIN_PH29 PINCTRL_PIN(PH_BASE + 29, "PH29")
+#define SUNXI_PINCTRL_PIN_PH30 PINCTRL_PIN(PH_BASE + 30, "PH30")
+#define SUNXI_PINCTRL_PIN_PH31 PINCTRL_PIN(PH_BASE + 31, "PH31")
+
+#define SUNXI_PINCTRL_PIN_PI0 PINCTRL_PIN(PI_BASE + 0, "PI0")
+#define SUNXI_PINCTRL_PIN_PI1 PINCTRL_PIN(PI_BASE + 1, "PI1")
+#define SUNXI_PINCTRL_PIN_PI2 PINCTRL_PIN(PI_BASE + 2, "PI2")
+#define SUNXI_PINCTRL_PIN_PI3 PINCTRL_PIN(PI_BASE + 3, "PI3")
+#define SUNXI_PINCTRL_PIN_PI4 PINCTRL_PIN(PI_BASE + 4, "PI4")
+#define SUNXI_PINCTRL_PIN_PI5 PINCTRL_PIN(PI_BASE + 5, "PI5")
+#define SUNXI_PINCTRL_PIN_PI6 PINCTRL_PIN(PI_BASE + 6, "PI6")
+#define SUNXI_PINCTRL_PIN_PI7 PINCTRL_PIN(PI_BASE + 7, "PI7")
+#define SUNXI_PINCTRL_PIN_PI8 PINCTRL_PIN(PI_BASE + 8, "PI8")
+#define SUNXI_PINCTRL_PIN_PI9 PINCTRL_PIN(PI_BASE + 9, "PI9")
+#define SUNXI_PINCTRL_PIN_PI10 PINCTRL_PIN(PI_BASE + 10, "PI10")
+#define SUNXI_PINCTRL_PIN_PI11 PINCTRL_PIN(PI_BASE + 11, "PI11")
+#define SUNXI_PINCTRL_PIN_PI12 PINCTRL_PIN(PI_BASE + 12, "PI12")
+#define SUNXI_PINCTRL_PIN_PI13 PINCTRL_PIN(PI_BASE + 13, "PI13")
+#define SUNXI_PINCTRL_PIN_PI14 PINCTRL_PIN(PI_BASE + 14, "PI14")
+#define SUNXI_PINCTRL_PIN_PI15 PINCTRL_PIN(PI_BASE + 15, "PI15")
+#define SUNXI_PINCTRL_PIN_PI16 PINCTRL_PIN(PI_BASE + 16, "PI16")
+#define SUNXI_PINCTRL_PIN_PI17 PINCTRL_PIN(PI_BASE + 17, "PI17")
+#define SUNXI_PINCTRL_PIN_PI18 PINCTRL_PIN(PI_BASE + 18, "PI18")
+#define SUNXI_PINCTRL_PIN_PI19 PINCTRL_PIN(PI_BASE + 19, "PI19")
+#define SUNXI_PINCTRL_PIN_PI20 PINCTRL_PIN(PI_BASE + 20, "PI20")
+#define SUNXI_PINCTRL_PIN_PI21 PINCTRL_PIN(PI_BASE + 21, "PI21")
+#define SUNXI_PINCTRL_PIN_PI22 PINCTRL_PIN(PI_BASE + 22, "PI22")
+#define SUNXI_PINCTRL_PIN_PI23 PINCTRL_PIN(PI_BASE + 23, "PI23")
+#define SUNXI_PINCTRL_PIN_PI24 PINCTRL_PIN(PI_BASE + 24, "PI24")
+#define SUNXI_PINCTRL_PIN_PI25 PINCTRL_PIN(PI_BASE + 25, "PI25")
+#define SUNXI_PINCTRL_PIN_PI26 PINCTRL_PIN(PI_BASE + 26, "PI26")
+#define SUNXI_PINCTRL_PIN_PI27 PINCTRL_PIN(PI_BASE + 27, "PI27")
+#define SUNXI_PINCTRL_PIN_PI28 PINCTRL_PIN(PI_BASE + 28, "PI28")
+#define SUNXI_PINCTRL_PIN_PI29 PINCTRL_PIN(PI_BASE + 29, "PI29")
+#define SUNXI_PINCTRL_PIN_PI30 PINCTRL_PIN(PI_BASE + 30, "PI30")
+#define SUNXI_PINCTRL_PIN_PI31 PINCTRL_PIN(PI_BASE + 31, "PI31")
+
+#define SUNXI_PIN_NAME_MAX_LEN 5
+
+#define BANK_MEM_SIZE 0x24
+#define MUX_REGS_OFFSET 0x0
+#define DATA_REGS_OFFSET 0x10
+#define DLEVEL_REGS_OFFSET 0x14
+#define PULL_REGS_OFFSET 0x1c
+
+#define PINS_PER_BANK 32
+#define MUX_PINS_PER_REG 8
+#define MUX_PINS_BITS 4
+#define MUX_PINS_MASK 0x0f
+#define DATA_PINS_PER_REG 32
+#define DATA_PINS_BITS 1
+#define DATA_PINS_MASK 0x01
+#define DLEVEL_PINS_PER_REG 16
+#define DLEVEL_PINS_BITS 2
+#define DLEVEL_PINS_MASK 0x03
+#define PULL_PINS_PER_REG 16
+#define PULL_PINS_BITS 2
+#define PULL_PINS_MASK 0x03
+
+struct sunxi_desc_function {
+ const char *name;
+ u8 muxval;
+};
+
+struct sunxi_desc_pin {
+ struct pinctrl_pin_desc pin;
+ struct sunxi_desc_function *functions;
+};
+
+struct sunxi_pinctrl_desc {
+ const struct sunxi_desc_pin *pins;
+ int npins;
+ struct pinctrl_gpio_range *ranges;
+ int nranges;
+};
+
+struct sunxi_pinctrl_function {
+ const char *name;
+ const char **groups;
+ unsigned ngroups;
+};
+
+struct sunxi_pinctrl_group {
+ const char *name;
+ unsigned long config;
+ unsigned pin;
+};
+
+struct sunxi_pinctrl {
+ void __iomem *membase;
+ struct gpio_chip *chip;
+ struct sunxi_pinctrl_desc *desc;
+ struct device *dev;
+ struct sunxi_pinctrl_function *functions;
+ unsigned nfunctions;
+ struct sunxi_pinctrl_group *groups;
+ unsigned ngroups;
+ struct pinctrl_dev *pctl_dev;
+};
+
+#define SUNXI_PIN(_pin, ...) \
+ { \
+ .pin = _pin, \
+ .functions = (struct sunxi_desc_function[]){ \
+ __VA_ARGS__, { } }, \
+ }
+
+#define SUNXI_FUNCTION(_val, _name) \
+ { \
+ .name = _name, \
+ .muxval = _val, \
+ }
+
+/*
+ * The sunXi PIO registers are organized as is:
+ * 0x00 - 0x0c Muxing values.
+ * 8 pins per register, each pin having a 4bits value
+ * 0x10 Pin values
+ * 32 bits per register, each pin corresponding to one bit
+ * 0x14 - 0x18 Drive level
+ * 16 pins per register, each pin having a 2bits value
+ * 0x1c - 0x20 Pull-Up values
+ * 16 pins per register, each pin having a 2bits value
+ *
+ * This is for the first bank. Each bank will have the same layout,
+ * with an offset being a multiple of 0x24.
+ *
+ * The following functions calculate from the pin number the register
+ * and the bit offset that we should access.
+ */
+static inline u32 sunxi_mux_reg(u16 pin)
+{
+ u8 bank = pin / PINS_PER_BANK;
+ u32 offset = bank * BANK_MEM_SIZE;
+ offset += MUX_REGS_OFFSET;
+ offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04;
+ return round_down(offset, 4);
+}
+
+static inline u32 sunxi_mux_offset(u16 pin)
+{
+ u32 pin_num = pin % MUX_PINS_PER_REG;
+ return pin_num * MUX_PINS_BITS;
+}
+
+static inline u32 sunxi_data_reg(u16 pin)
+{
+ u8 bank = pin / PINS_PER_BANK;
+ u32 offset = bank * BANK_MEM_SIZE;
+ offset += DATA_REGS_OFFSET;
+ offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04;
+ return round_down(offset, 4);
+}
+
+static inline u32 sunxi_data_offset(u16 pin)
+{
+ u32 pin_num = pin % DATA_PINS_PER_REG;
+ return pin_num * DATA_PINS_BITS;
+}
+
+static inline u32 sunxi_dlevel_reg(u16 pin)
+{
+ u8 bank = pin / PINS_PER_BANK;
+ u32 offset = bank * BANK_MEM_SIZE;
+ offset += DLEVEL_REGS_OFFSET;
+ offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04;
+ return round_down(offset, 4);
+}
+
+static inline u32 sunxi_dlevel_offset(u16 pin)
+{
+ u32 pin_num = pin % DLEVEL_PINS_PER_REG;
+ return pin_num * DLEVEL_PINS_BITS;
+}
+
+static inline u32 sunxi_pull_reg(u16 pin)
+{
+ u8 bank = pin / PINS_PER_BANK;
+ u32 offset = bank * BANK_MEM_SIZE;
+ offset += PULL_REGS_OFFSET;
+ offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04;
+ return round_down(offset, 4);
+}
+
+static inline u32 sunxi_pull_offset(u16 pin)
+{
+ u32 pin_num = pin % PULL_PINS_PER_REG;
+ return pin_num * PULL_PINS_BITS;
+}
+
+#endif /* __PINCTRL_SUNXI_H */
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index ae1e4bb3259d..f195d77a3572 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -201,6 +201,7 @@ static const struct cfg_param {
{"nvidia,open-drain", TEGRA_PINCONF_PARAM_OPEN_DRAIN},
{"nvidia,lock", TEGRA_PINCONF_PARAM_LOCK},
{"nvidia,io-reset", TEGRA_PINCONF_PARAM_IORESET},
+ {"nvidia,rcv-sel", TEGRA_PINCONF_PARAM_RCV_SEL},
{"nvidia,high-speed-mode", TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE},
{"nvidia,schmitt", TEGRA_PINCONF_PARAM_SCHMITT},
{"nvidia,low-power-mode", TEGRA_PINCONF_PARAM_LOW_POWER_MODE},
@@ -208,6 +209,7 @@ static const struct cfg_param {
{"nvidia,pull-up-strength", TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH},
{"nvidia,slew-rate-falling", TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING},
{"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
+ {"nvidia,drive-type", TEGRA_PINCONF_PARAM_DRIVE_TYPE},
};
static int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
@@ -450,6 +452,12 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx,
*bit = g->ioreset_bit;
*width = 1;
break;
+ case TEGRA_PINCONF_PARAM_RCV_SEL:
+ *bank = g->rcv_sel_bank;
+ *reg = g->rcv_sel_reg;
+ *bit = g->rcv_sel_bit;
+ *width = 1;
+ break;
case TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE:
*bank = g->drv_bank;
*reg = g->drv_reg;
@@ -492,6 +500,12 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx,
*bit = g->slwr_bit;
*width = g->slwr_width;
break;
+ case TEGRA_PINCONF_PARAM_DRIVE_TYPE:
+ *bank = g->drvtype_bank;
+ *reg = g->drvtype_reg;
+ *bit = g->drvtype_bit;
+ *width = 2;
+ break;
default:
dev_err(pmx->dev, "Invalid config param %04x\n", param);
return -ENOTSUPP;
diff --git a/drivers/pinctrl/pinctrl-tegra.h b/drivers/pinctrl/pinctrl-tegra.h
index 62e380965c68..817f7061dc4c 100644
--- a/drivers/pinctrl/pinctrl-tegra.h
+++ b/drivers/pinctrl/pinctrl-tegra.h
@@ -30,6 +30,8 @@ enum tegra_pinconf_param {
/* argument: Boolean */
TEGRA_PINCONF_PARAM_IORESET,
/* argument: Boolean */
+ TEGRA_PINCONF_PARAM_RCV_SEL,
+ /* argument: Boolean */
TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE,
/* argument: Boolean */
TEGRA_PINCONF_PARAM_SCHMITT,
@@ -43,6 +45,8 @@ enum tegra_pinconf_param {
TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING,
/* argument: Integer, range is HW-dependant */
TEGRA_PINCONF_PARAM_SLEW_RATE_RISING,
+ /* argument: Integer, range is HW-dependant */
+ TEGRA_PINCONF_PARAM_DRIVE_TYPE,
};
enum tegra_pinconf_pull {
@@ -95,6 +99,9 @@ struct tegra_function {
* @ioreset_reg: IO reset register offset. -1 if unsupported.
* @ioreset_bank: IO reset register bank. 0 if unsupported.
* @ioreset_bit: IO reset register bit. 0 if unsupported.
+ * @rcv_sel_reg: Receiver select offset. -1 if unsupported.
+ * @rcv_sel_bank: Receiver select bank. 0 if unsupported.
+ * @rcv_sel_bit: Receiver select bit. 0 if unsupported.
* @drv_reg: Drive fields register offset. -1 if unsupported.
* This register contains the hsm, schmitt, lpmd, drvdn,
* drvup, slwr, and slwf parameters.
@@ -110,6 +117,9 @@ struct tegra_function {
* @slwr_width: Slew Rising field width. 0 if unsupported.
* @slwf_bit: Slew Falling register bit. 0 if unsupported.
* @slwf_width: Slew Falling field width. 0 if unsupported.
+ * @drvtype_reg: Drive type fields register offset. -1 if unsupported.
+ * @drvtype_bank: Drive type fields register bank. 0 if unsupported.
+ * @drvtype_bit: Drive type register bit. 0 if unsupported.
*
* A representation of a group of pins (possibly just one pin) in the Tegra
* pin controller. Each group allows some parameter or parameters to be
@@ -131,15 +141,19 @@ struct tegra_pingroup {
s16 odrain_reg;
s16 lock_reg;
s16 ioreset_reg;
+ s16 rcv_sel_reg;
s16 drv_reg;
+ s16 drvtype_reg;
u32 mux_bank:2;
u32 pupd_bank:2;
u32 tri_bank:2;
u32 einput_bank:2;
u32 odrain_bank:2;
u32 ioreset_bank:2;
+ u32 rcv_sel_bank:2;
u32 lock_bank:2;
u32 drv_bank:2;
+ u32 drvtype_bank:2;
u32 mux_bit:5;
u32 pupd_bit:5;
u32 tri_bit:5;
@@ -147,6 +161,7 @@ struct tegra_pingroup {
u32 odrain_bit:5;
u32 lock_bit:5;
u32 ioreset_bit:5;
+ u32 rcv_sel_bit:5;
u32 hsm_bit:5;
u32 schmitt_bit:5;
u32 lpmd_bit:5;
@@ -154,6 +169,7 @@ struct tegra_pingroup {
u32 drvup_bit:5;
u32 slwr_bit:5;
u32 slwf_bit:5;
+ u32 drvtype_bit:5;
u32 drvdn_width:6;
u32 drvup_width:6;
u32 slwr_width:6;
diff --git a/drivers/pinctrl/pinctrl-tegra114.c b/drivers/pinctrl/pinctrl-tegra114.c
new file mode 100644
index 000000000000..622c4854977e
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-tegra114.c
@@ -0,0 +1,2769 @@
+/*
+ * Pinctrl data and driver for the NVIDIA Tegra114 pinmux
+ *
+ * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Arthur: Pritesh Raithatha <praithatha@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-tegra.h"
+
+/*
+ * Most pins affected by the pinmux can also be GPIOs. Define these first.
+ * These must match how the GPIO driver names/numbers its pins.
+ */
+#define _GPIO(offset) (offset)
+
+#define TEGRA_PIN_CLK_32K_OUT_PA0 _GPIO(0)
+#define TEGRA_PIN_UART3_CTS_N_PA1 _GPIO(1)
+#define TEGRA_PIN_DAP2_FS_PA2 _GPIO(2)
+#define TEGRA_PIN_DAP2_SCLK_PA3 _GPIO(3)
+#define TEGRA_PIN_DAP2_DIN_PA4 _GPIO(4)
+#define TEGRA_PIN_DAP2_DOUT_PA5 _GPIO(5)
+#define TEGRA_PIN_SDMMC3_CLK_PA6 _GPIO(6)
+#define TEGRA_PIN_SDMMC3_CMD_PA7 _GPIO(7)
+#define TEGRA_PIN_GMI_A17_PB0 _GPIO(8)
+#define TEGRA_PIN_GMI_A18_PB1 _GPIO(9)
+#define TEGRA_PIN_SDMMC3_DAT3_PB4 _GPIO(12)
+#define TEGRA_PIN_SDMMC3_DAT2_PB5 _GPIO(13)
+#define TEGRA_PIN_SDMMC3_DAT1_PB6 _GPIO(14)
+#define TEGRA_PIN_SDMMC3_DAT0_PB7 _GPIO(15)
+#define TEGRA_PIN_UART3_RTS_N_PC0 _GPIO(16)
+#define TEGRA_PIN_UART2_TXD_PC2 _GPIO(18)
+#define TEGRA_PIN_UART2_RXD_PC3 _GPIO(19)
+#define TEGRA_PIN_GEN1_I2C_SCL_PC4 _GPIO(20)
+#define TEGRA_PIN_GEN1_I2C_SDA_PC5 _GPIO(21)
+#define TEGRA_PIN_GMI_WP_N_PC7 _GPIO(23)
+#define TEGRA_PIN_GMI_AD0_PG0 _GPIO(48)
+#define TEGRA_PIN_GMI_AD1_PG1 _GPIO(49)
+#define TEGRA_PIN_GMI_AD2_PG2 _GPIO(50)
+#define TEGRA_PIN_GMI_AD3_PG3 _GPIO(51)
+#define TEGRA_PIN_GMI_AD4_PG4 _GPIO(52)
+#define TEGRA_PIN_GMI_AD5_PG5 _GPIO(53)
+#define TEGRA_PIN_GMI_AD6_PG6 _GPIO(54)
+#define TEGRA_PIN_GMI_AD7_PG7 _GPIO(55)
+#define TEGRA_PIN_GMI_AD8_PH0 _GPIO(56)
+#define TEGRA_PIN_GMI_AD9_PH1 _GPIO(57)
+#define TEGRA_PIN_GMI_AD10_PH2 _GPIO(58)
+#define TEGRA_PIN_GMI_AD11_PH3 _GPIO(59)
+#define TEGRA_PIN_GMI_AD12_PH4 _GPIO(60)
+#define TEGRA_PIN_GMI_AD13_PH5 _GPIO(61)
+#define TEGRA_PIN_GMI_AD14_PH6 _GPIO(62)
+#define TEGRA_PIN_GMI_AD15_PH7 _GPIO(63)
+#define TEGRA_PIN_GMI_WR_N_PI0 _GPIO(64)
+#define TEGRA_PIN_GMI_OE_N_PI1 _GPIO(65)
+#define TEGRA_PIN_GMI_CS6_N_PI3 _GPIO(67)
+#define TEGRA_PIN_GMI_RST_N_PI4 _GPIO(68)
+#define TEGRA_PIN_GMI_IORDY_PI5 _GPIO(69)
+#define TEGRA_PIN_GMI_CS7_N_PI6 _GPIO(70)
+#define TEGRA_PIN_GMI_WAIT_PI7 _GPIO(71)
+#define TEGRA_PIN_GMI_CS0_N_PJ0 _GPIO(72)
+#define TEGRA_PIN_GMI_CS1_N_PJ2 _GPIO(74)
+#define TEGRA_PIN_GMI_DQS_P_PJ3 _GPIO(75)
+#define TEGRA_PIN_UART2_CTS_N_PJ5 _GPIO(77)
+#define TEGRA_PIN_UART2_RTS_N_PJ6 _GPIO(78)
+#define TEGRA_PIN_GMI_A16_PJ7 _GPIO(79)
+#define TEGRA_PIN_GMI_ADV_N_PK0 _GPIO(80)
+#define TEGRA_PIN_GMI_CLK_PK1 _GPIO(81)
+#define TEGRA_PIN_GMI_CS4_N_PK2 _GPIO(82)
+#define TEGRA_PIN_GMI_CS2_N_PK3 _GPIO(83)
+#define TEGRA_PIN_GMI_CS3_N_PK4 _GPIO(84)
+#define TEGRA_PIN_SPDIF_OUT_PK5 _GPIO(85)
+#define TEGRA_PIN_SPDIF_IN_PK6 _GPIO(86)
+#define TEGRA_PIN_GMI_A19_PK7 _GPIO(87)
+#define TEGRA_PIN_DAP1_FS_PN0 _GPIO(104)
+#define TEGRA_PIN_DAP1_DIN_PN1 _GPIO(105)
+#define TEGRA_PIN_DAP1_DOUT_PN2 _GPIO(106)
+#define TEGRA_PIN_DAP1_SCLK_PN3 _GPIO(107)
+#define TEGRA_PIN_USB_VBUS_EN0_PN4 _GPIO(108)
+#define TEGRA_PIN_USB_VBUS_EN1_PN5 _GPIO(109)
+#define TEGRA_PIN_HDMI_INT_PN7 _GPIO(111)
+#define TEGRA_PIN_ULPI_DATA7_PO0 _GPIO(112)
+#define TEGRA_PIN_ULPI_DATA0_PO1 _GPIO(113)
+#define TEGRA_PIN_ULPI_DATA1_PO2 _GPIO(114)
+#define TEGRA_PIN_ULPI_DATA2_PO3 _GPIO(115)
+#define TEGRA_PIN_ULPI_DATA3_PO4 _GPIO(116)
+#define TEGRA_PIN_ULPI_DATA4_PO5 _GPIO(117)
+#define TEGRA_PIN_ULPI_DATA5_PO6 _GPIO(118)
+#define TEGRA_PIN_ULPI_DATA6_PO7 _GPIO(119)
+#define TEGRA_PIN_DAP3_FS_PP0 _GPIO(120)
+#define TEGRA_PIN_DAP3_DIN_PP1 _GPIO(121)
+#define TEGRA_PIN_DAP3_DOUT_PP2 _GPIO(122)
+#define TEGRA_PIN_DAP3_SCLK_PP3 _GPIO(123)
+#define TEGRA_PIN_DAP4_FS_PP4 _GPIO(124)
+#define TEGRA_PIN_DAP4_DIN_PP5 _GPIO(125)
+#define TEGRA_PIN_DAP4_DOUT_PP6 _GPIO(126)
+#define TEGRA_PIN_DAP4_SCLK_PP7 _GPIO(127)
+#define TEGRA_PIN_KB_COL0_PQ0 _GPIO(128)
+#define TEGRA_PIN_KB_COL1_PQ1 _GPIO(129)
+#define TEGRA_PIN_KB_COL2_PQ2 _GPIO(130)
+#define TEGRA_PIN_KB_COL3_PQ3 _GPIO(131)
+#define TEGRA_PIN_KB_COL4_PQ4 _GPIO(132)
+#define TEGRA_PIN_KB_COL5_PQ5 _GPIO(133)
+#define TEGRA_PIN_KB_COL6_PQ6 _GPIO(134)
+#define TEGRA_PIN_KB_COL7_PQ7 _GPIO(135)
+#define TEGRA_PIN_KB_ROW0_PR0 _GPIO(136)
+#define TEGRA_PIN_KB_ROW1_PR1 _GPIO(137)
+#define TEGRA_PIN_KB_ROW2_PR2 _GPIO(138)
+#define TEGRA_PIN_KB_ROW3_PR3 _GPIO(139)
+#define TEGRA_PIN_KB_ROW4_PR4 _GPIO(140)
+#define TEGRA_PIN_KB_ROW5_PR5 _GPIO(141)
+#define TEGRA_PIN_KB_ROW6_PR6 _GPIO(142)
+#define TEGRA_PIN_KB_ROW7_PR7 _GPIO(143)
+#define TEGRA_PIN_KB_ROW8_PS0 _GPIO(144)
+#define TEGRA_PIN_KB_ROW9_PS1 _GPIO(145)
+#define TEGRA_PIN_KB_ROW10_PS2 _GPIO(146)
+#define TEGRA_PIN_GEN2_I2C_SCL_PT5 _GPIO(157)
+#define TEGRA_PIN_GEN2_I2C_SDA_PT6 _GPIO(158)
+#define TEGRA_PIN_SDMMC4_CMD_PT7 _GPIO(159)
+#define TEGRA_PIN_PU0 _GPIO(160)
+#define TEGRA_PIN_PU1 _GPIO(161)
+#define TEGRA_PIN_PU2 _GPIO(162)
+#define TEGRA_PIN_PU3 _GPIO(163)
+#define TEGRA_PIN_PU4 _GPIO(164)
+#define TEGRA_PIN_PU5 _GPIO(165)
+#define TEGRA_PIN_PU6 _GPIO(166)
+#define TEGRA_PIN_PV0 _GPIO(168)
+#define TEGRA_PIN_PV1 _GPIO(169)
+#define TEGRA_PIN_SDMMC3_CD_N_PV2 _GPIO(170)
+#define TEGRA_PIN_SDMMC1_WP_N_PV3 _GPIO(171)
+#define TEGRA_PIN_DDC_SCL_PV4 _GPIO(172)
+#define TEGRA_PIN_DDC_SDA_PV5 _GPIO(173)
+#define TEGRA_PIN_GPIO_W2_AUD_PW2 _GPIO(178)
+#define TEGRA_PIN_GPIO_W3_AUD_PW3 _GPIO(179)
+#define TEGRA_PIN_CLK1_OUT_PW4 _GPIO(180)
+#define TEGRA_PIN_CLK2_OUT_PW5 _GPIO(181)
+#define TEGRA_PIN_UART3_TXD_PW6 _GPIO(182)
+#define TEGRA_PIN_UART3_RXD_PW7 _GPIO(183)
+#define TEGRA_PIN_DVFS_PWM_PX0 _GPIO(184)
+#define TEGRA_PIN_GPIO_X1_AUD_PX1 _GPIO(185)
+#define TEGRA_PIN_DVFS_CLK_PX2 _GPIO(186)
+#define TEGRA_PIN_GPIO_X3_AUD_PX3 _GPIO(187)
+#define TEGRA_PIN_GPIO_X4_AUD_PX4 _GPIO(188)
+#define TEGRA_PIN_GPIO_X5_AUD_PX5 _GPIO(189)
+#define TEGRA_PIN_GPIO_X6_AUD_PX6 _GPIO(190)
+#define TEGRA_PIN_GPIO_X7_AUD_PX7 _GPIO(191)
+#define TEGRA_PIN_ULPI_CLK_PY0 _GPIO(192)
+#define TEGRA_PIN_ULPI_DIR_PY1 _GPIO(193)
+#define TEGRA_PIN_ULPI_NXT_PY2 _GPIO(194)
+#define TEGRA_PIN_ULPI_STP_PY3 _GPIO(195)
+#define TEGRA_PIN_SDMMC1_DAT3_PY4 _GPIO(196)
+#define TEGRA_PIN_SDMMC1_DAT2_PY5 _GPIO(197)
+#define TEGRA_PIN_SDMMC1_DAT1_PY6 _GPIO(198)
+#define TEGRA_PIN_SDMMC1_DAT0_PY7 _GPIO(199)
+#define TEGRA_PIN_SDMMC1_CLK_PZ0 _GPIO(200)
+#define TEGRA_PIN_SDMMC1_CMD_PZ1 _GPIO(201)
+#define TEGRA_PIN_SYS_CLK_REQ_PZ5 _GPIO(205)
+#define TEGRA_PIN_PWR_I2C_SCL_PZ6 _GPIO(206)
+#define TEGRA_PIN_PWR_I2C_SDA_PZ7 _GPIO(207)
+#define TEGRA_PIN_SDMMC4_DAT0_PAA0 _GPIO(208)
+#define TEGRA_PIN_SDMMC4_DAT1_PAA1 _GPIO(209)
+#define TEGRA_PIN_SDMMC4_DAT2_PAA2 _GPIO(210)
+#define TEGRA_PIN_SDMMC4_DAT3_PAA3 _GPIO(211)
+#define TEGRA_PIN_SDMMC4_DAT4_PAA4 _GPIO(212)
+#define TEGRA_PIN_SDMMC4_DAT5_PAA5 _GPIO(213)
+#define TEGRA_PIN_SDMMC4_DAT6_PAA6 _GPIO(214)
+#define TEGRA_PIN_SDMMC4_DAT7_PAA7 _GPIO(215)
+#define TEGRA_PIN_PBB0 _GPIO(216)
+#define TEGRA_PIN_CAM_I2C_SCL_PBB1 _GPIO(217)
+#define TEGRA_PIN_CAM_I2C_SDA_PBB2 _GPIO(218)
+#define TEGRA_PIN_PBB3 _GPIO(219)
+#define TEGRA_PIN_PBB4 _GPIO(220)
+#define TEGRA_PIN_PBB5 _GPIO(221)
+#define TEGRA_PIN_PBB6 _GPIO(222)
+#define TEGRA_PIN_PBB7 _GPIO(223)
+#define TEGRA_PIN_CAM_MCLK_PCC0 _GPIO(224)
+#define TEGRA_PIN_PCC1 _GPIO(225)
+#define TEGRA_PIN_PCC2 _GPIO(226)
+#define TEGRA_PIN_SDMMC4_CLK_PCC4 _GPIO(228)
+#define TEGRA_PIN_CLK2_REQ_PCC5 _GPIO(229)
+#define TEGRA_PIN_CLK3_OUT_PEE0 _GPIO(240)
+#define TEGRA_PIN_CLK3_REQ_PEE1 _GPIO(241)
+#define TEGRA_PIN_CLK1_REQ_PEE2 _GPIO(242)
+#define TEGRA_PIN_HDMI_CEC_PEE3 _GPIO(243)
+#define TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4 _GPIO(244)
+#define TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 _GPIO(245)
+
+/* All non-GPIO pins follow */
+#define NUM_GPIOS (TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5 + 1)
+#define _PIN(offset) (NUM_GPIOS + (offset))
+
+/* Non-GPIO pins */
+#define TEGRA_PIN_CORE_PWR_REQ _PIN(0)
+#define TEGRA_PIN_CPU_PWR_REQ _PIN(1)
+#define TEGRA_PIN_PWR_INT_N _PIN(2)
+#define TEGRA_PIN_RESET_OUT_N _PIN(3)
+#define TEGRA_PIN_OWR _PIN(4)
+
+static const struct pinctrl_pin_desc tegra114_pins[] = {
+ PINCTRL_PIN(TEGRA_PIN_CLK_32K_OUT_PA0, "CLK_32K_OUT PA0"),
+ PINCTRL_PIN(TEGRA_PIN_UART3_CTS_N_PA1, "UART3_CTS_N PA1"),
+ PINCTRL_PIN(TEGRA_PIN_DAP2_FS_PA2, "DAP2_FS PA2"),
+ PINCTRL_PIN(TEGRA_PIN_DAP2_SCLK_PA3, "DAP2_SCLK PA3"),
+ PINCTRL_PIN(TEGRA_PIN_DAP2_DIN_PA4, "DAP2_DIN PA4"),
+ PINCTRL_PIN(TEGRA_PIN_DAP2_DOUT_PA5, "DAP2_DOUT PA5"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_PA6, "SDMMC3_CLK PA6"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC3_CMD_PA7, "SDMMC3_CMD PA7"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_A17_PB0, "GMI_A17 PB0"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_A18_PB1, "GMI_A18 PB1"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT3_PB4, "SDMMC3_DAT3 PB4"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT2_PB5, "SDMMC3_DAT2 PB5"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT1_PB6, "SDMMC3_DAT1 PB6"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC3_DAT0_PB7, "SDMMC3_DAT0 PB7"),
+ PINCTRL_PIN(TEGRA_PIN_UART3_RTS_N_PC0, "UART3_RTS_N PC0"),
+ PINCTRL_PIN(TEGRA_PIN_UART2_TXD_PC2, "UART2_TXD PC2"),
+ PINCTRL_PIN(TEGRA_PIN_UART2_RXD_PC3, "UART2_RXD PC3"),
+ PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SCL_PC4, "GEN1_I2C_SCL PC4"),
+ PINCTRL_PIN(TEGRA_PIN_GEN1_I2C_SDA_PC5, "GEN1_I2C_SDA PC5"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_WP_N_PC7, "GMI_WP_N PC7"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD0_PG0, "GMI_AD0 PG0"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD1_PG1, "GMI_AD1 PG1"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD2_PG2, "GMI_AD2 PG2"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD3_PG3, "GMI_AD3 PG3"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD4_PG4, "GMI_AD4 PG4"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD5_PG5, "GMI_AD5 PG5"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD6_PG6, "GMI_AD6 PG6"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD7_PG7, "GMI_AD7 PG7"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD8_PH0, "GMI_AD8 PH0"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD9_PH1, "GMI_AD9 PH1"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD10_PH2, "GMI_AD10 PH2"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD11_PH3, "GMI_AD11 PH3"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD12_PH4, "GMI_AD12 PH4"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD13_PH5, "GMI_AD13 PH5"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD14_PH6, "GMI_AD14 PH6"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_AD15_PH7, "GMI_AD15 PH7"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_WR_N_PI0, "GMI_WR_N PI0"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_OE_N_PI1, "GMI_OE_N PI1"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CS6_N_PI3, "GMI_CS6_N PI3"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_RST_N_PI4, "GMI_RST_N PI4"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_IORDY_PI5, "GMI_IORDY PI5"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CS7_N_PI6, "GMI_CS7_N PI6"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_WAIT_PI7, "GMI_WAIT PI7"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CS0_N_PJ0, "GMI_CS0_N PJ0"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CS1_N_PJ2, "GMI_CS1_N PJ2"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_DQS_P_PJ3, "GMI_DQS_P PJ3"),
+ PINCTRL_PIN(TEGRA_PIN_UART2_CTS_N_PJ5, "UART2_CTS_N PJ5"),
+ PINCTRL_PIN(TEGRA_PIN_UART2_RTS_N_PJ6, "UART2_RTS_N PJ6"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_A16_PJ7, "GMI_A16 PJ7"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_ADV_N_PK0, "GMI_ADV_N PK0"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CLK_PK1, "GMI_CLK PK1"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CS4_N_PK2, "GMI_CS4_N PK2"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CS2_N_PK3, "GMI_CS2_N PK3"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_CS3_N_PK4, "GMI_CS3_N PK4"),
+ PINCTRL_PIN(TEGRA_PIN_SPDIF_OUT_PK5, "SPDIF_OUT PK5"),
+ PINCTRL_PIN(TEGRA_PIN_SPDIF_IN_PK6, "SPDIF_IN PK6"),
+ PINCTRL_PIN(TEGRA_PIN_GMI_A19_PK7, "GMI_A19 PK7"),
+ PINCTRL_PIN(TEGRA_PIN_DAP1_FS_PN0, "DAP1_FS PN0"),
+ PINCTRL_PIN(TEGRA_PIN_DAP1_DIN_PN1, "DAP1_DIN PN1"),
+ PINCTRL_PIN(TEGRA_PIN_DAP1_DOUT_PN2, "DAP1_DOUT PN2"),
+ PINCTRL_PIN(TEGRA_PIN_DAP1_SCLK_PN3, "DAP1_SCLK PN3"),
+ PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN0_PN4, "USB_VBUS_EN0 PN4"),
+ PINCTRL_PIN(TEGRA_PIN_USB_VBUS_EN1_PN5, "USB_VBUS_EN1 PN5"),
+ PINCTRL_PIN(TEGRA_PIN_HDMI_INT_PN7, "HDMI_INT PN7"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_DATA7_PO0, "ULPI_DATA7 PO0"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_DATA0_PO1, "ULPI_DATA0 PO1"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_DATA1_PO2, "ULPI_DATA1 PO2"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_DATA2_PO3, "ULPI_DATA2 PO3"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_DATA3_PO4, "ULPI_DATA3 PO4"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_DATA4_PO5, "ULPI_DATA4 PO5"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_DATA5_PO6, "ULPI_DATA5 PO6"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_DATA6_PO7, "ULPI_DATA6 PO7"),
+ PINCTRL_PIN(TEGRA_PIN_DAP3_FS_PP0, "DAP3_FS PP0"),
+ PINCTRL_PIN(TEGRA_PIN_DAP3_DIN_PP1, "DAP3_DIN PP1"),
+ PINCTRL_PIN(TEGRA_PIN_DAP3_DOUT_PP2, "DAP3_DOUT PP2"),
+ PINCTRL_PIN(TEGRA_PIN_DAP3_SCLK_PP3, "DAP3_SCLK PP3"),
+ PINCTRL_PIN(TEGRA_PIN_DAP4_FS_PP4, "DAP4_FS PP4"),
+ PINCTRL_PIN(TEGRA_PIN_DAP4_DIN_PP5, "DAP4_DIN PP5"),
+ PINCTRL_PIN(TEGRA_PIN_DAP4_DOUT_PP6, "DAP4_DOUT PP6"),
+ PINCTRL_PIN(TEGRA_PIN_DAP4_SCLK_PP7, "DAP4_SCLK PP7"),
+ PINCTRL_PIN(TEGRA_PIN_KB_COL0_PQ0, "KB_COL0 PQ0"),
+ PINCTRL_PIN(TEGRA_PIN_KB_COL1_PQ1, "KB_COL1 PQ1"),
+ PINCTRL_PIN(TEGRA_PIN_KB_COL2_PQ2, "KB_COL2 PQ2"),
+ PINCTRL_PIN(TEGRA_PIN_KB_COL3_PQ3, "KB_COL3 PQ3"),
+ PINCTRL_PIN(TEGRA_PIN_KB_COL4_PQ4, "KB_COL4 PQ4"),
+ PINCTRL_PIN(TEGRA_PIN_KB_COL5_PQ5, "KB_COL5 PQ5"),
+ PINCTRL_PIN(TEGRA_PIN_KB_COL6_PQ6, "KB_COL6 PQ6"),
+ PINCTRL_PIN(TEGRA_PIN_KB_COL7_PQ7, "KB_COL7 PQ7"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW0_PR0, "KB_ROW0 PR0"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW1_PR1, "KB_ROW1 PR1"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW2_PR2, "KB_ROW2 PR2"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW3_PR3, "KB_ROW3 PR3"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW4_PR4, "KB_ROW4 PR4"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW5_PR5, "KB_ROW5 PR5"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW6_PR6, "KB_ROW6 PR6"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW7_PR7, "KB_ROW7 PR7"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW8_PS0, "KB_ROW8 PS0"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW9_PS1, "KB_ROW9 PS1"),
+ PINCTRL_PIN(TEGRA_PIN_KB_ROW10_PS2, "KB_ROW10 PS2"),
+ PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SCL_PT5, "GEN2_I2C_SCL PT5"),
+ PINCTRL_PIN(TEGRA_PIN_GEN2_I2C_SDA_PT6, "GEN2_I2C_SDA PT6"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC4_CMD_PT7, "SDMMC4_CMD PT7"),
+ PINCTRL_PIN(TEGRA_PIN_PU0, "PU0"),
+ PINCTRL_PIN(TEGRA_PIN_PU1, "PU1"),
+ PINCTRL_PIN(TEGRA_PIN_PU2, "PU2"),
+ PINCTRL_PIN(TEGRA_PIN_PU3, "PU3"),
+ PINCTRL_PIN(TEGRA_PIN_PU4, "PU4"),
+ PINCTRL_PIN(TEGRA_PIN_PU5, "PU5"),
+ PINCTRL_PIN(TEGRA_PIN_PU6, "PU6"),
+ PINCTRL_PIN(TEGRA_PIN_PV0, "PV0"),
+ PINCTRL_PIN(TEGRA_PIN_PV1, "PV1"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC3_CD_N_PV2, "SDMMC3_CD_N PV2"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC1_WP_N_PV3, "SDMMC1_WP_N PV3"),
+ PINCTRL_PIN(TEGRA_PIN_DDC_SCL_PV4, "DDC_SCL PV4"),
+ PINCTRL_PIN(TEGRA_PIN_DDC_SDA_PV5, "DDC_SDA PV5"),
+ PINCTRL_PIN(TEGRA_PIN_GPIO_W2_AUD_PW2, "GPIO_W2_AUD PW2"),
+ PINCTRL_PIN(TEGRA_PIN_GPIO_W3_AUD_PW3, "GPIO_W3_AUD PW3"),
+ PINCTRL_PIN(TEGRA_PIN_CLK1_OUT_PW4, "CLK1_OUT PW4"),
+ PINCTRL_PIN(TEGRA_PIN_CLK2_OUT_PW5, "CLK2_OUT PW5"),
+ PINCTRL_PIN(TEGRA_PIN_UART3_TXD_PW6, "UART3_TXD PW6"),
+ PINCTRL_PIN(TEGRA_PIN_UART3_RXD_PW7, "UART3_RXD PW7"),
+ PINCTRL_PIN(TEGRA_PIN_DVFS_PWM_PX0, "DVFS_PWM PX0"),
+ PINCTRL_PIN(TEGRA_PIN_GPIO_X1_AUD_PX1, "GPIO_X1_AUD PX1"),
+ PINCTRL_PIN(TEGRA_PIN_DVFS_CLK_PX2, "DVFS_CLK PX2"),
+ PINCTRL_PIN(TEGRA_PIN_GPIO_X3_AUD_PX3, "GPIO_X3_AUD PX3"),
+ PINCTRL_PIN(TEGRA_PIN_GPIO_X4_AUD_PX4, "GPIO_X4_AUD PX4"),
+ PINCTRL_PIN(TEGRA_PIN_GPIO_X5_AUD_PX5, "GPIO_X5_AUD PX5"),
+ PINCTRL_PIN(TEGRA_PIN_GPIO_X6_AUD_PX6, "GPIO_X6_AUD PX6"),
+ PINCTRL_PIN(TEGRA_PIN_GPIO_X7_AUD_PX7, "GPIO_X7_AUD PX7"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_CLK_PY0, "ULPI_CLK PY0"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_DIR_PY1, "ULPI_DIR PY1"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_NXT_PY2, "ULPI_NXT PY2"),
+ PINCTRL_PIN(TEGRA_PIN_ULPI_STP_PY3, "ULPI_STP PY3"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT3_PY4, "SDMMC1_DAT3 PY4"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT2_PY5, "SDMMC1_DAT2 PY5"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT1_PY6, "SDMMC1_DAT1 PY6"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC1_DAT0_PY7, "SDMMC1_DAT0 PY7"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC1_CLK_PZ0, "SDMMC1_CLK PZ0"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC1_CMD_PZ1, "SDMMC1_CMD PZ1"),
+ PINCTRL_PIN(TEGRA_PIN_SYS_CLK_REQ_PZ5, "SYS_CLK_REQ PZ5"),
+ PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SCL_PZ6, "PWR_I2C_SCL PZ6"),
+ PINCTRL_PIN(TEGRA_PIN_PWR_I2C_SDA_PZ7, "PWR_I2C_SDA PZ7"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT0_PAA0, "SDMMC4_DAT0 PAA0"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT1_PAA1, "SDMMC4_DAT1 PAA1"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT2_PAA2, "SDMMC4_DAT2 PAA2"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT3_PAA3, "SDMMC4_DAT3 PAA3"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT4_PAA4, "SDMMC4_DAT4 PAA4"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT5_PAA5, "SDMMC4_DAT5 PAA5"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT6_PAA6, "SDMMC4_DAT6 PAA6"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC4_DAT7_PAA7, "SDMMC4_DAT7 PAA7"),
+ PINCTRL_PIN(TEGRA_PIN_PBB0, "PBB0"),
+ PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SCL_PBB1, "CAM_I2C_SCL PBB1"),
+ PINCTRL_PIN(TEGRA_PIN_CAM_I2C_SDA_PBB2, "CAM_I2C_SDA PBB2"),
+ PINCTRL_PIN(TEGRA_PIN_PBB3, "PBB3"),
+ PINCTRL_PIN(TEGRA_PIN_PBB4, "PBB4"),
+ PINCTRL_PIN(TEGRA_PIN_PBB5, "PBB5"),
+ PINCTRL_PIN(TEGRA_PIN_PBB6, "PBB6"),
+ PINCTRL_PIN(TEGRA_PIN_PBB7, "PBB7"),
+ PINCTRL_PIN(TEGRA_PIN_CAM_MCLK_PCC0, "CAM_MCLK PCC0"),
+ PINCTRL_PIN(TEGRA_PIN_PCC1, "PCC1"),
+ PINCTRL_PIN(TEGRA_PIN_PCC2, "PCC2"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC4_CLK_PCC4, "SDMMC4_CLK PCC4"),
+ PINCTRL_PIN(TEGRA_PIN_CLK2_REQ_PCC5, "CLK2_REQ PCC5"),
+ PINCTRL_PIN(TEGRA_PIN_CLK3_OUT_PEE0, "CLK3_OUT PEE0"),
+ PINCTRL_PIN(TEGRA_PIN_CLK3_REQ_PEE1, "CLK3_REQ PEE1"),
+ PINCTRL_PIN(TEGRA_PIN_CLK1_REQ_PEE2, "CLK1_REQ PEE2"),
+ PINCTRL_PIN(TEGRA_PIN_HDMI_CEC_PEE3, "HDMI_CEC PEE3"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4, "SDMMC3_CLK_LB_OUT PEE4"),
+ PINCTRL_PIN(TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5, "SDMMC3_CLK_LB_IN PEE5"),
+ PINCTRL_PIN(TEGRA_PIN_CORE_PWR_REQ, "CORE_PWR_REQ"),
+ PINCTRL_PIN(TEGRA_PIN_CPU_PWR_REQ, "CPU_PWR_REQ"),
+ PINCTRL_PIN(TEGRA_PIN_OWR, "OWR"),
+ PINCTRL_PIN(TEGRA_PIN_PWR_INT_N, "PWR_INT_N"),
+ PINCTRL_PIN(TEGRA_PIN_RESET_OUT_N, "RESET_OUT_N"),
+};
+
+static const unsigned clk_32k_out_pa0_pins[] = {
+ TEGRA_PIN_CLK_32K_OUT_PA0,
+};
+
+static const unsigned uart3_cts_n_pa1_pins[] = {
+ TEGRA_PIN_UART3_CTS_N_PA1,
+};
+
+static const unsigned dap2_fs_pa2_pins[] = {
+ TEGRA_PIN_DAP2_FS_PA2,
+};
+
+static const unsigned dap2_sclk_pa3_pins[] = {
+ TEGRA_PIN_DAP2_SCLK_PA3,
+};
+
+static const unsigned dap2_din_pa4_pins[] = {
+ TEGRA_PIN_DAP2_DIN_PA4,
+};
+
+static const unsigned dap2_dout_pa5_pins[] = {
+ TEGRA_PIN_DAP2_DOUT_PA5,
+};
+
+static const unsigned sdmmc3_clk_pa6_pins[] = {
+ TEGRA_PIN_SDMMC3_CLK_PA6,
+};
+
+static const unsigned sdmmc3_cmd_pa7_pins[] = {
+ TEGRA_PIN_SDMMC3_CMD_PA7,
+};
+
+static const unsigned gmi_a17_pb0_pins[] = {
+ TEGRA_PIN_GMI_A17_PB0,
+};
+
+static const unsigned gmi_a18_pb1_pins[] = {
+ TEGRA_PIN_GMI_A18_PB1,
+};
+
+static const unsigned sdmmc3_dat3_pb4_pins[] = {
+ TEGRA_PIN_SDMMC3_DAT3_PB4,
+};
+
+static const unsigned sdmmc3_dat2_pb5_pins[] = {
+ TEGRA_PIN_SDMMC3_DAT2_PB5,
+};
+
+static const unsigned sdmmc3_dat1_pb6_pins[] = {
+ TEGRA_PIN_SDMMC3_DAT1_PB6,
+};
+
+static const unsigned sdmmc3_dat0_pb7_pins[] = {
+ TEGRA_PIN_SDMMC3_DAT0_PB7,
+};
+
+static const unsigned uart3_rts_n_pc0_pins[] = {
+ TEGRA_PIN_UART3_RTS_N_PC0,
+};
+
+static const unsigned uart2_txd_pc2_pins[] = {
+ TEGRA_PIN_UART2_TXD_PC2,
+};
+
+static const unsigned uart2_rxd_pc3_pins[] = {
+ TEGRA_PIN_UART2_RXD_PC3,
+};
+
+static const unsigned gen1_i2c_scl_pc4_pins[] = {
+ TEGRA_PIN_GEN1_I2C_SCL_PC4,
+};
+
+static const unsigned gen1_i2c_sda_pc5_pins[] = {
+ TEGRA_PIN_GEN1_I2C_SDA_PC5,
+};
+
+static const unsigned gmi_wp_n_pc7_pins[] = {
+ TEGRA_PIN_GMI_WP_N_PC7,
+};
+
+static const unsigned gmi_ad0_pg0_pins[] = {
+ TEGRA_PIN_GMI_AD0_PG0,
+};
+
+static const unsigned gmi_ad1_pg1_pins[] = {
+ TEGRA_PIN_GMI_AD1_PG1,
+};
+
+static const unsigned gmi_ad2_pg2_pins[] = {
+ TEGRA_PIN_GMI_AD2_PG2,
+};
+
+static const unsigned gmi_ad3_pg3_pins[] = {
+ TEGRA_PIN_GMI_AD3_PG3,
+};
+
+static const unsigned gmi_ad4_pg4_pins[] = {
+ TEGRA_PIN_GMI_AD4_PG4,
+};
+
+static const unsigned gmi_ad5_pg5_pins[] = {
+ TEGRA_PIN_GMI_AD5_PG5,
+};
+
+static const unsigned gmi_ad6_pg6_pins[] = {
+ TEGRA_PIN_GMI_AD6_PG6,
+};
+
+static const unsigned gmi_ad7_pg7_pins[] = {
+ TEGRA_PIN_GMI_AD7_PG7,
+};
+
+static const unsigned gmi_ad8_ph0_pins[] = {
+ TEGRA_PIN_GMI_AD8_PH0,
+};
+
+static const unsigned gmi_ad9_ph1_pins[] = {
+ TEGRA_PIN_GMI_AD9_PH1,
+};
+
+static const unsigned gmi_ad10_ph2_pins[] = {
+ TEGRA_PIN_GMI_AD10_PH2,
+};
+
+static const unsigned gmi_ad11_ph3_pins[] = {
+ TEGRA_PIN_GMI_AD11_PH3,
+};
+
+static const unsigned gmi_ad12_ph4_pins[] = {
+ TEGRA_PIN_GMI_AD12_PH4,
+};
+
+static const unsigned gmi_ad13_ph5_pins[] = {
+ TEGRA_PIN_GMI_AD13_PH5,
+};
+
+static const unsigned gmi_ad14_ph6_pins[] = {
+ TEGRA_PIN_GMI_AD14_PH6,
+};
+
+static const unsigned gmi_ad15_ph7_pins[] = {
+ TEGRA_PIN_GMI_AD15_PH7,
+};
+
+static const unsigned gmi_wr_n_pi0_pins[] = {
+ TEGRA_PIN_GMI_WR_N_PI0,
+};
+
+static const unsigned gmi_oe_n_pi1_pins[] = {
+ TEGRA_PIN_GMI_OE_N_PI1,
+};
+
+static const unsigned gmi_cs6_n_pi3_pins[] = {
+ TEGRA_PIN_GMI_CS6_N_PI3,
+};
+
+static const unsigned gmi_rst_n_pi4_pins[] = {
+ TEGRA_PIN_GMI_RST_N_PI4,
+};
+
+static const unsigned gmi_iordy_pi5_pins[] = {
+ TEGRA_PIN_GMI_IORDY_PI5,
+};
+
+static const unsigned gmi_cs7_n_pi6_pins[] = {
+ TEGRA_PIN_GMI_CS7_N_PI6,
+};
+
+static const unsigned gmi_wait_pi7_pins[] = {
+ TEGRA_PIN_GMI_WAIT_PI7,
+};
+
+static const unsigned gmi_cs0_n_pj0_pins[] = {
+ TEGRA_PIN_GMI_CS0_N_PJ0,
+};
+
+static const unsigned gmi_cs1_n_pj2_pins[] = {
+ TEGRA_PIN_GMI_CS1_N_PJ2,
+};
+
+static const unsigned gmi_dqs_p_pj3_pins[] = {
+ TEGRA_PIN_GMI_DQS_P_PJ3,
+};
+
+static const unsigned uart2_cts_n_pj5_pins[] = {
+ TEGRA_PIN_UART2_CTS_N_PJ5,
+};
+
+static const unsigned uart2_rts_n_pj6_pins[] = {
+ TEGRA_PIN_UART2_RTS_N_PJ6,
+};
+
+static const unsigned gmi_a16_pj7_pins[] = {
+ TEGRA_PIN_GMI_A16_PJ7,
+};
+
+static const unsigned gmi_adv_n_pk0_pins[] = {
+ TEGRA_PIN_GMI_ADV_N_PK0,
+};
+
+static const unsigned gmi_clk_pk1_pins[] = {
+ TEGRA_PIN_GMI_CLK_PK1,
+};
+
+static const unsigned gmi_cs4_n_pk2_pins[] = {
+ TEGRA_PIN_GMI_CS4_N_PK2,
+};
+
+static const unsigned gmi_cs2_n_pk3_pins[] = {
+ TEGRA_PIN_GMI_CS2_N_PK3,
+};
+
+static const unsigned gmi_cs3_n_pk4_pins[] = {
+ TEGRA_PIN_GMI_CS3_N_PK4,
+};
+
+static const unsigned spdif_out_pk5_pins[] = {
+ TEGRA_PIN_SPDIF_OUT_PK5,
+};
+
+static const unsigned spdif_in_pk6_pins[] = {
+ TEGRA_PIN_SPDIF_IN_PK6,
+};
+
+static const unsigned gmi_a19_pk7_pins[] = {
+ TEGRA_PIN_GMI_A19_PK7,
+};
+
+static const unsigned dap1_fs_pn0_pins[] = {
+ TEGRA_PIN_DAP1_FS_PN0,
+};
+
+static const unsigned dap1_din_pn1_pins[] = {
+ TEGRA_PIN_DAP1_DIN_PN1,
+};
+
+static const unsigned dap1_dout_pn2_pins[] = {
+ TEGRA_PIN_DAP1_DOUT_PN2,
+};
+
+static const unsigned dap1_sclk_pn3_pins[] = {
+ TEGRA_PIN_DAP1_SCLK_PN3,
+};
+
+static const unsigned usb_vbus_en0_pn4_pins[] = {
+ TEGRA_PIN_USB_VBUS_EN0_PN4,
+};
+
+static const unsigned usb_vbus_en1_pn5_pins[] = {
+ TEGRA_PIN_USB_VBUS_EN1_PN5,
+};
+
+static const unsigned hdmi_int_pn7_pins[] = {
+ TEGRA_PIN_HDMI_INT_PN7,
+};
+
+static const unsigned ulpi_data7_po0_pins[] = {
+ TEGRA_PIN_ULPI_DATA7_PO0,
+};
+
+static const unsigned ulpi_data0_po1_pins[] = {
+ TEGRA_PIN_ULPI_DATA0_PO1,
+};
+
+static const unsigned ulpi_data1_po2_pins[] = {
+ TEGRA_PIN_ULPI_DATA1_PO2,
+};
+
+static const unsigned ulpi_data2_po3_pins[] = {
+ TEGRA_PIN_ULPI_DATA2_PO3,
+};
+
+static const unsigned ulpi_data3_po4_pins[] = {
+ TEGRA_PIN_ULPI_DATA3_PO4,
+};
+
+static const unsigned ulpi_data4_po5_pins[] = {
+ TEGRA_PIN_ULPI_DATA4_PO5,
+};
+
+static const unsigned ulpi_data5_po6_pins[] = {
+ TEGRA_PIN_ULPI_DATA5_PO6,
+};
+
+static const unsigned ulpi_data6_po7_pins[] = {
+ TEGRA_PIN_ULPI_DATA6_PO7,
+};
+
+static const unsigned dap3_fs_pp0_pins[] = {
+ TEGRA_PIN_DAP3_FS_PP0,
+};
+
+static const unsigned dap3_din_pp1_pins[] = {
+ TEGRA_PIN_DAP3_DIN_PP1,
+};
+
+static const unsigned dap3_dout_pp2_pins[] = {
+ TEGRA_PIN_DAP3_DOUT_PP2,
+};
+
+static const unsigned dap3_sclk_pp3_pins[] = {
+ TEGRA_PIN_DAP3_SCLK_PP3,
+};
+
+static const unsigned dap4_fs_pp4_pins[] = {
+ TEGRA_PIN_DAP4_FS_PP4,
+};
+
+static const unsigned dap4_din_pp5_pins[] = {
+ TEGRA_PIN_DAP4_DIN_PP5,
+};
+
+static const unsigned dap4_dout_pp6_pins[] = {
+ TEGRA_PIN_DAP4_DOUT_PP6,
+};
+
+static const unsigned dap4_sclk_pp7_pins[] = {
+ TEGRA_PIN_DAP4_SCLK_PP7,
+};
+
+static const unsigned kb_col0_pq0_pins[] = {
+ TEGRA_PIN_KB_COL0_PQ0,
+};
+
+static const unsigned kb_col1_pq1_pins[] = {
+ TEGRA_PIN_KB_COL1_PQ1,
+};
+
+static const unsigned kb_col2_pq2_pins[] = {
+ TEGRA_PIN_KB_COL2_PQ2,
+};
+
+static const unsigned kb_col3_pq3_pins[] = {
+ TEGRA_PIN_KB_COL3_PQ3,
+};
+
+static const unsigned kb_col4_pq4_pins[] = {
+ TEGRA_PIN_KB_COL4_PQ4,
+};
+
+static const unsigned kb_col5_pq5_pins[] = {
+ TEGRA_PIN_KB_COL5_PQ5,
+};
+
+static const unsigned kb_col6_pq6_pins[] = {
+ TEGRA_PIN_KB_COL6_PQ6,
+};
+
+static const unsigned kb_col7_pq7_pins[] = {
+ TEGRA_PIN_KB_COL7_PQ7,
+};
+
+static const unsigned kb_row0_pr0_pins[] = {
+ TEGRA_PIN_KB_ROW0_PR0,
+};
+
+static const unsigned kb_row1_pr1_pins[] = {
+ TEGRA_PIN_KB_ROW1_PR1,
+};
+
+static const unsigned kb_row2_pr2_pins[] = {
+ TEGRA_PIN_KB_ROW2_PR2,
+};
+
+static const unsigned kb_row3_pr3_pins[] = {
+ TEGRA_PIN_KB_ROW3_PR3,
+};
+
+static const unsigned kb_row4_pr4_pins[] = {
+ TEGRA_PIN_KB_ROW4_PR4,
+};
+
+static const unsigned kb_row5_pr5_pins[] = {
+ TEGRA_PIN_KB_ROW5_PR5,
+};
+
+static const unsigned kb_row6_pr6_pins[] = {
+ TEGRA_PIN_KB_ROW6_PR6,
+};
+
+static const unsigned kb_row7_pr7_pins[] = {
+ TEGRA_PIN_KB_ROW7_PR7,
+};
+
+static const unsigned kb_row8_ps0_pins[] = {
+ TEGRA_PIN_KB_ROW8_PS0,
+};
+
+static const unsigned kb_row9_ps1_pins[] = {
+ TEGRA_PIN_KB_ROW9_PS1,
+};
+
+static const unsigned kb_row10_ps2_pins[] = {
+ TEGRA_PIN_KB_ROW10_PS2,
+};
+
+static const unsigned gen2_i2c_scl_pt5_pins[] = {
+ TEGRA_PIN_GEN2_I2C_SCL_PT5,
+};
+
+static const unsigned gen2_i2c_sda_pt6_pins[] = {
+ TEGRA_PIN_GEN2_I2C_SDA_PT6,
+};
+
+static const unsigned sdmmc4_cmd_pt7_pins[] = {
+ TEGRA_PIN_SDMMC4_CMD_PT7,
+};
+
+static const unsigned pu0_pins[] = {
+ TEGRA_PIN_PU0,
+};
+
+static const unsigned pu1_pins[] = {
+ TEGRA_PIN_PU1,
+};
+
+static const unsigned pu2_pins[] = {
+ TEGRA_PIN_PU2,
+};
+
+static const unsigned pu3_pins[] = {
+ TEGRA_PIN_PU3,
+};
+
+static const unsigned pu4_pins[] = {
+ TEGRA_PIN_PU4,
+};
+
+static const unsigned pu5_pins[] = {
+ TEGRA_PIN_PU5,
+};
+
+static const unsigned pu6_pins[] = {
+ TEGRA_PIN_PU6,
+};
+
+static const unsigned pv0_pins[] = {
+ TEGRA_PIN_PV0,
+};
+
+static const unsigned pv1_pins[] = {
+ TEGRA_PIN_PV1,
+};
+
+static const unsigned sdmmc3_cd_n_pv2_pins[] = {
+ TEGRA_PIN_SDMMC3_CD_N_PV2,
+};
+
+static const unsigned sdmmc1_wp_n_pv3_pins[] = {
+ TEGRA_PIN_SDMMC1_WP_N_PV3,
+};
+
+static const unsigned ddc_scl_pv4_pins[] = {
+ TEGRA_PIN_DDC_SCL_PV4,
+};
+
+static const unsigned ddc_sda_pv5_pins[] = {
+ TEGRA_PIN_DDC_SDA_PV5,
+};
+
+static const unsigned gpio_w2_aud_pw2_pins[] = {
+ TEGRA_PIN_GPIO_W2_AUD_PW2,
+};
+
+static const unsigned gpio_w3_aud_pw3_pins[] = {
+ TEGRA_PIN_GPIO_W3_AUD_PW3,
+};
+
+static const unsigned clk1_out_pw4_pins[] = {
+ TEGRA_PIN_CLK1_OUT_PW4,
+};
+
+static const unsigned clk2_out_pw5_pins[] = {
+ TEGRA_PIN_CLK2_OUT_PW5,
+};
+
+static const unsigned uart3_txd_pw6_pins[] = {
+ TEGRA_PIN_UART3_TXD_PW6,
+};
+
+static const unsigned uart3_rxd_pw7_pins[] = {
+ TEGRA_PIN_UART3_RXD_PW7,
+};
+
+static const unsigned dvfs_pwm_px0_pins[] = {
+ TEGRA_PIN_DVFS_PWM_PX0,
+};
+
+static const unsigned gpio_x1_aud_px1_pins[] = {
+ TEGRA_PIN_GPIO_X1_AUD_PX1,
+};
+
+static const unsigned dvfs_clk_px2_pins[] = {
+ TEGRA_PIN_DVFS_CLK_PX2,
+};
+
+static const unsigned gpio_x3_aud_px3_pins[] = {
+ TEGRA_PIN_GPIO_X3_AUD_PX3,
+};
+
+static const unsigned gpio_x4_aud_px4_pins[] = {
+ TEGRA_PIN_GPIO_X4_AUD_PX4,
+};
+
+static const unsigned gpio_x5_aud_px5_pins[] = {
+ TEGRA_PIN_GPIO_X5_AUD_PX5,
+};
+
+static const unsigned gpio_x6_aud_px6_pins[] = {
+ TEGRA_PIN_GPIO_X6_AUD_PX6,
+};
+
+static const unsigned gpio_x7_aud_px7_pins[] = {
+ TEGRA_PIN_GPIO_X7_AUD_PX7,
+};
+
+static const unsigned ulpi_clk_py0_pins[] = {
+ TEGRA_PIN_ULPI_CLK_PY0,
+};
+
+static const unsigned ulpi_dir_py1_pins[] = {
+ TEGRA_PIN_ULPI_DIR_PY1,
+};
+
+static const unsigned ulpi_nxt_py2_pins[] = {
+ TEGRA_PIN_ULPI_NXT_PY2,
+};
+
+static const unsigned ulpi_stp_py3_pins[] = {
+ TEGRA_PIN_ULPI_STP_PY3,
+};
+
+static const unsigned sdmmc1_dat3_py4_pins[] = {
+ TEGRA_PIN_SDMMC1_DAT3_PY4,
+};
+
+static const unsigned sdmmc1_dat2_py5_pins[] = {
+ TEGRA_PIN_SDMMC1_DAT2_PY5,
+};
+
+static const unsigned sdmmc1_dat1_py6_pins[] = {
+ TEGRA_PIN_SDMMC1_DAT1_PY6,
+};
+
+static const unsigned sdmmc1_dat0_py7_pins[] = {
+ TEGRA_PIN_SDMMC1_DAT0_PY7,
+};
+
+static const unsigned sdmmc1_clk_pz0_pins[] = {
+ TEGRA_PIN_SDMMC1_CLK_PZ0,
+};
+
+static const unsigned sdmmc1_cmd_pz1_pins[] = {
+ TEGRA_PIN_SDMMC1_CMD_PZ1,
+};
+
+static const unsigned sys_clk_req_pz5_pins[] = {
+ TEGRA_PIN_SYS_CLK_REQ_PZ5,
+};
+
+static const unsigned pwr_i2c_scl_pz6_pins[] = {
+ TEGRA_PIN_PWR_I2C_SCL_PZ6,
+};
+
+static const unsigned pwr_i2c_sda_pz7_pins[] = {
+ TEGRA_PIN_PWR_I2C_SDA_PZ7,
+};
+
+static const unsigned sdmmc4_dat0_paa0_pins[] = {
+ TEGRA_PIN_SDMMC4_DAT0_PAA0,
+};
+
+static const unsigned sdmmc4_dat1_paa1_pins[] = {
+ TEGRA_PIN_SDMMC4_DAT1_PAA1,
+};
+
+static const unsigned sdmmc4_dat2_paa2_pins[] = {
+ TEGRA_PIN_SDMMC4_DAT2_PAA2,
+};
+
+static const unsigned sdmmc4_dat3_paa3_pins[] = {
+ TEGRA_PIN_SDMMC4_DAT3_PAA3,
+};
+
+static const unsigned sdmmc4_dat4_paa4_pins[] = {
+ TEGRA_PIN_SDMMC4_DAT4_PAA4,
+};
+
+static const unsigned sdmmc4_dat5_paa5_pins[] = {
+ TEGRA_PIN_SDMMC4_DAT5_PAA5,
+};
+
+static const unsigned sdmmc4_dat6_paa6_pins[] = {
+ TEGRA_PIN_SDMMC4_DAT6_PAA6,
+};
+
+static const unsigned sdmmc4_dat7_paa7_pins[] = {
+ TEGRA_PIN_SDMMC4_DAT7_PAA7,
+};
+
+static const unsigned pbb0_pins[] = {
+ TEGRA_PIN_PBB0,
+};
+
+static const unsigned cam_i2c_scl_pbb1_pins[] = {
+ TEGRA_PIN_CAM_I2C_SCL_PBB1,
+};
+
+static const unsigned cam_i2c_sda_pbb2_pins[] = {
+ TEGRA_PIN_CAM_I2C_SDA_PBB2,
+};
+
+static const unsigned pbb3_pins[] = {
+ TEGRA_PIN_PBB3,
+};
+
+static const unsigned pbb4_pins[] = {
+ TEGRA_PIN_PBB4,
+};
+
+static const unsigned pbb5_pins[] = {
+ TEGRA_PIN_PBB5,
+};
+
+static const unsigned pbb6_pins[] = {
+ TEGRA_PIN_PBB6,
+};
+
+static const unsigned pbb7_pins[] = {
+ TEGRA_PIN_PBB7,
+};
+
+static const unsigned cam_mclk_pcc0_pins[] = {
+ TEGRA_PIN_CAM_MCLK_PCC0,
+};
+
+static const unsigned pcc1_pins[] = {
+ TEGRA_PIN_PCC1,
+};
+
+static const unsigned pcc2_pins[] = {
+ TEGRA_PIN_PCC2,
+};
+
+static const unsigned sdmmc4_clk_pcc4_pins[] = {
+ TEGRA_PIN_SDMMC4_CLK_PCC4,
+};
+
+static const unsigned clk2_req_pcc5_pins[] = {
+ TEGRA_PIN_CLK2_REQ_PCC5,
+};
+
+static const unsigned clk3_out_pee0_pins[] = {
+ TEGRA_PIN_CLK3_OUT_PEE0,
+};
+
+static const unsigned clk3_req_pee1_pins[] = {
+ TEGRA_PIN_CLK3_REQ_PEE1,
+};
+
+static const unsigned clk1_req_pee2_pins[] = {
+ TEGRA_PIN_CLK1_REQ_PEE2,
+};
+
+static const unsigned hdmi_cec_pee3_pins[] = {
+ TEGRA_PIN_HDMI_CEC_PEE3,
+};
+
+static const unsigned sdmmc3_clk_lb_out_pee4_pins[] = {
+ TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4,
+};
+
+static const unsigned sdmmc3_clk_lb_in_pee5_pins[] = {
+ TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5,
+};
+
+static const unsigned core_pwr_req_pins[] = {
+ TEGRA_PIN_CORE_PWR_REQ,
+};
+
+static const unsigned cpu_pwr_req_pins[] = {
+ TEGRA_PIN_CPU_PWR_REQ,
+};
+
+static const unsigned owr_pins[] = {
+ TEGRA_PIN_OWR,
+};
+
+static const unsigned pwr_int_n_pins[] = {
+ TEGRA_PIN_PWR_INT_N,
+};
+
+static const unsigned reset_out_n_pins[] = {
+ TEGRA_PIN_RESET_OUT_N,
+};
+
+static const unsigned drive_ao1_pins[] = {
+ TEGRA_PIN_KB_ROW0_PR0,
+ TEGRA_PIN_KB_ROW1_PR1,
+ TEGRA_PIN_KB_ROW2_PR2,
+ TEGRA_PIN_KB_ROW3_PR3,
+ TEGRA_PIN_KB_ROW4_PR4,
+ TEGRA_PIN_KB_ROW5_PR5,
+ TEGRA_PIN_KB_ROW6_PR6,
+ TEGRA_PIN_KB_ROW7_PR7,
+ TEGRA_PIN_PWR_I2C_SCL_PZ6,
+ TEGRA_PIN_PWR_I2C_SDA_PZ7,
+};
+
+static const unsigned drive_ao2_pins[] = {
+ TEGRA_PIN_CLK_32K_OUT_PA0,
+ TEGRA_PIN_KB_COL0_PQ0,
+ TEGRA_PIN_KB_COL1_PQ1,
+ TEGRA_PIN_KB_COL2_PQ2,
+ TEGRA_PIN_KB_COL3_PQ3,
+ TEGRA_PIN_KB_COL4_PQ4,
+ TEGRA_PIN_KB_COL5_PQ5,
+ TEGRA_PIN_KB_COL6_PQ6,
+ TEGRA_PIN_KB_COL7_PQ7,
+ TEGRA_PIN_KB_ROW8_PS0,
+ TEGRA_PIN_KB_ROW9_PS1,
+ TEGRA_PIN_KB_ROW10_PS2,
+ TEGRA_PIN_SYS_CLK_REQ_PZ5,
+ TEGRA_PIN_CORE_PWR_REQ,
+ TEGRA_PIN_CPU_PWR_REQ,
+ TEGRA_PIN_RESET_OUT_N,
+};
+
+static const unsigned drive_at1_pins[] = {
+ TEGRA_PIN_GMI_AD8_PH0,
+ TEGRA_PIN_GMI_AD9_PH1,
+ TEGRA_PIN_GMI_AD10_PH2,
+ TEGRA_PIN_GMI_AD11_PH3,
+ TEGRA_PIN_GMI_AD12_PH4,
+ TEGRA_PIN_GMI_AD13_PH5,
+ TEGRA_PIN_GMI_AD14_PH6,
+ TEGRA_PIN_GMI_AD15_PH7,
+
+ TEGRA_PIN_GMI_IORDY_PI5,
+ TEGRA_PIN_GMI_CS7_N_PI6,
+};
+
+static const unsigned drive_at2_pins[] = {
+ TEGRA_PIN_GMI_AD0_PG0,
+ TEGRA_PIN_GMI_AD1_PG1,
+ TEGRA_PIN_GMI_AD2_PG2,
+ TEGRA_PIN_GMI_AD3_PG3,
+ TEGRA_PIN_GMI_AD4_PG4,
+ TEGRA_PIN_GMI_AD5_PG5,
+ TEGRA_PIN_GMI_AD6_PG6,
+ TEGRA_PIN_GMI_AD7_PG7,
+
+ TEGRA_PIN_GMI_WR_N_PI0,
+ TEGRA_PIN_GMI_OE_N_PI1,
+ TEGRA_PIN_GMI_CS6_N_PI3,
+ TEGRA_PIN_GMI_RST_N_PI4,
+ TEGRA_PIN_GMI_WAIT_PI7,
+
+ TEGRA_PIN_GMI_DQS_P_PJ3,
+
+ TEGRA_PIN_GMI_ADV_N_PK0,
+ TEGRA_PIN_GMI_CLK_PK1,
+ TEGRA_PIN_GMI_CS4_N_PK2,
+ TEGRA_PIN_GMI_CS2_N_PK3,
+ TEGRA_PIN_GMI_CS3_N_PK4,
+};
+
+static const unsigned drive_at3_pins[] = {
+ TEGRA_PIN_GMI_WP_N_PC7,
+ TEGRA_PIN_GMI_CS0_N_PJ0,
+};
+
+static const unsigned drive_at4_pins[] = {
+ TEGRA_PIN_GMI_A17_PB0,
+ TEGRA_PIN_GMI_A18_PB1,
+ TEGRA_PIN_GMI_CS1_N_PJ2,
+ TEGRA_PIN_GMI_A16_PJ7,
+ TEGRA_PIN_GMI_A19_PK7,
+};
+
+static const unsigned drive_at5_pins[] = {
+ TEGRA_PIN_GEN2_I2C_SCL_PT5,
+ TEGRA_PIN_GEN2_I2C_SDA_PT6,
+};
+
+static const unsigned drive_cdev1_pins[] = {
+ TEGRA_PIN_CLK1_OUT_PW4,
+ TEGRA_PIN_CLK1_REQ_PEE2,
+};
+
+static const unsigned drive_cdev2_pins[] = {
+ TEGRA_PIN_CLK2_OUT_PW5,
+ TEGRA_PIN_CLK2_REQ_PCC5,
+ TEGRA_PIN_SDMMC1_WP_N_PV3,
+};
+
+static const unsigned drive_dap1_pins[] = {
+ TEGRA_PIN_DAP1_FS_PN0,
+ TEGRA_PIN_DAP1_DIN_PN1,
+ TEGRA_PIN_DAP1_DOUT_PN2,
+ TEGRA_PIN_DAP1_SCLK_PN3,
+};
+
+static const unsigned drive_dap2_pins[] = {
+ TEGRA_PIN_DAP2_FS_PA2,
+ TEGRA_PIN_DAP2_SCLK_PA3,
+ TEGRA_PIN_DAP2_DIN_PA4,
+ TEGRA_PIN_DAP2_DOUT_PA5,
+};
+
+static const unsigned drive_dap3_pins[] = {
+ TEGRA_PIN_DAP3_FS_PP0,
+ TEGRA_PIN_DAP3_DIN_PP1,
+ TEGRA_PIN_DAP3_DOUT_PP2,
+ TEGRA_PIN_DAP3_SCLK_PP3,
+};
+
+static const unsigned drive_dap4_pins[] = {
+ TEGRA_PIN_DAP4_FS_PP4,
+ TEGRA_PIN_DAP4_DIN_PP5,
+ TEGRA_PIN_DAP4_DOUT_PP6,
+ TEGRA_PIN_DAP4_SCLK_PP7,
+};
+
+static const unsigned drive_dbg_pins[] = {
+ TEGRA_PIN_GEN1_I2C_SCL_PC4,
+ TEGRA_PIN_GEN1_I2C_SDA_PC5,
+ TEGRA_PIN_PU0,
+ TEGRA_PIN_PU1,
+ TEGRA_PIN_PU2,
+ TEGRA_PIN_PU3,
+ TEGRA_PIN_PU4,
+ TEGRA_PIN_PU5,
+ TEGRA_PIN_PU6,
+};
+
+static const unsigned drive_sdio3_pins[] = {
+ TEGRA_PIN_SDMMC3_CLK_PA6,
+ TEGRA_PIN_SDMMC3_CMD_PA7,
+ TEGRA_PIN_SDMMC3_DAT3_PB4,
+ TEGRA_PIN_SDMMC3_DAT2_PB5,
+ TEGRA_PIN_SDMMC3_DAT1_PB6,
+ TEGRA_PIN_SDMMC3_DAT0_PB7,
+ TEGRA_PIN_SDMMC3_CLK_LB_OUT_PEE4,
+ TEGRA_PIN_SDMMC3_CLK_LB_IN_PEE5,
+};
+
+static const unsigned drive_spi_pins[] = {
+ TEGRA_PIN_DVFS_PWM_PX0,
+ TEGRA_PIN_GPIO_X1_AUD_PX1,
+ TEGRA_PIN_DVFS_CLK_PX2,
+ TEGRA_PIN_GPIO_X3_AUD_PX3,
+ TEGRA_PIN_GPIO_X4_AUD_PX4,
+ TEGRA_PIN_GPIO_X5_AUD_PX5,
+ TEGRA_PIN_GPIO_X6_AUD_PX6,
+ TEGRA_PIN_GPIO_X7_AUD_PX7,
+ TEGRA_PIN_GPIO_W2_AUD_PW2,
+ TEGRA_PIN_GPIO_W3_AUD_PW3,
+};
+
+static const unsigned drive_uaa_pins[] = {
+ TEGRA_PIN_ULPI_DATA0_PO1,
+ TEGRA_PIN_ULPI_DATA1_PO2,
+ TEGRA_PIN_ULPI_DATA2_PO3,
+ TEGRA_PIN_ULPI_DATA3_PO4,
+};
+
+static const unsigned drive_uab_pins[] = {
+ TEGRA_PIN_ULPI_DATA7_PO0,
+ TEGRA_PIN_ULPI_DATA4_PO5,
+ TEGRA_PIN_ULPI_DATA5_PO6,
+ TEGRA_PIN_ULPI_DATA6_PO7,
+ TEGRA_PIN_PV0,
+ TEGRA_PIN_PV1,
+};
+
+static const unsigned drive_uart2_pins[] = {
+ TEGRA_PIN_UART2_TXD_PC2,
+ TEGRA_PIN_UART2_RXD_PC3,
+ TEGRA_PIN_UART2_CTS_N_PJ5,
+ TEGRA_PIN_UART2_RTS_N_PJ6,
+};
+
+static const unsigned drive_uart3_pins[] = {
+ TEGRA_PIN_UART3_CTS_N_PA1,
+ TEGRA_PIN_UART3_RTS_N_PC0,
+ TEGRA_PIN_UART3_TXD_PW6,
+ TEGRA_PIN_UART3_RXD_PW7,
+};
+
+static const unsigned drive_sdio1_pins[] = {
+ TEGRA_PIN_SDMMC1_DAT3_PY4,
+ TEGRA_PIN_SDMMC1_DAT2_PY5,
+ TEGRA_PIN_SDMMC1_DAT1_PY6,
+ TEGRA_PIN_SDMMC1_DAT0_PY7,
+ TEGRA_PIN_SDMMC1_CLK_PZ0,
+ TEGRA_PIN_SDMMC1_CMD_PZ1,
+};
+
+static const unsigned drive_ddc_pins[] = {
+ TEGRA_PIN_DDC_SCL_PV4,
+ TEGRA_PIN_DDC_SDA_PV5,
+};
+
+static const unsigned drive_gma_pins[] = {
+ TEGRA_PIN_SDMMC4_CLK_PCC4,
+ TEGRA_PIN_SDMMC4_CMD_PT7,
+ TEGRA_PIN_SDMMC4_DAT0_PAA0,
+ TEGRA_PIN_SDMMC4_DAT1_PAA1,
+ TEGRA_PIN_SDMMC4_DAT2_PAA2,
+ TEGRA_PIN_SDMMC4_DAT3_PAA3,
+ TEGRA_PIN_SDMMC4_DAT4_PAA4,
+ TEGRA_PIN_SDMMC4_DAT5_PAA5,
+ TEGRA_PIN_SDMMC4_DAT6_PAA6,
+ TEGRA_PIN_SDMMC4_DAT7_PAA7,
+};
+
+static const unsigned drive_gme_pins[] = {
+ TEGRA_PIN_PBB0,
+ TEGRA_PIN_CAM_I2C_SCL_PBB1,
+ TEGRA_PIN_CAM_I2C_SDA_PBB2,
+ TEGRA_PIN_PBB3,
+ TEGRA_PIN_PCC2,
+};
+
+static const unsigned drive_gmf_pins[] = {
+ TEGRA_PIN_PBB4,
+ TEGRA_PIN_PBB5,
+ TEGRA_PIN_PBB6,
+ TEGRA_PIN_PBB7,
+};
+
+static const unsigned drive_gmg_pins[] = {
+ TEGRA_PIN_CAM_MCLK_PCC0,
+};
+
+static const unsigned drive_gmh_pins[] = {
+ TEGRA_PIN_PCC1,
+};
+
+static const unsigned drive_owr_pins[] = {
+ TEGRA_PIN_SDMMC3_CD_N_PV2,
+};
+
+static const unsigned drive_uda_pins[] = {
+ TEGRA_PIN_ULPI_CLK_PY0,
+ TEGRA_PIN_ULPI_DIR_PY1,
+ TEGRA_PIN_ULPI_NXT_PY2,
+ TEGRA_PIN_ULPI_STP_PY3,
+};
+
+static const unsigned drive_dev3_pins[] = {
+ TEGRA_PIN_CLK3_OUT_PEE0,
+ TEGRA_PIN_CLK3_REQ_PEE1,
+};
+
+enum tegra_mux {
+ TEGRA_MUX_BLINK,
+ TEGRA_MUX_CEC,
+ TEGRA_MUX_CLDVFS,
+ TEGRA_MUX_CLK12,
+ TEGRA_MUX_CPU,
+ TEGRA_MUX_DAP,
+ TEGRA_MUX_DAP1,
+ TEGRA_MUX_DAP2,
+ TEGRA_MUX_DEV3,
+ TEGRA_MUX_DISPLAYA,
+ TEGRA_MUX_DISPLAYA_ALT,
+ TEGRA_MUX_DISPLAYB,
+ TEGRA_MUX_DTV,
+ TEGRA_MUX_EMC_DLL,
+ TEGRA_MUX_EXTPERIPH1,
+ TEGRA_MUX_EXTPERIPH2,
+ TEGRA_MUX_EXTPERIPH3,
+ TEGRA_MUX_GMI,
+ TEGRA_MUX_GMI_ALT,
+ TEGRA_MUX_HDA,
+ TEGRA_MUX_HSI,
+ TEGRA_MUX_I2C1,
+ TEGRA_MUX_I2C2,
+ TEGRA_MUX_I2C3,
+ TEGRA_MUX_I2C4,
+ TEGRA_MUX_I2CPWR,
+ TEGRA_MUX_I2S0,
+ TEGRA_MUX_I2S1,
+ TEGRA_MUX_I2S2,
+ TEGRA_MUX_I2S3,
+ TEGRA_MUX_I2S4,
+ TEGRA_MUX_IRDA,
+ TEGRA_MUX_KBC,
+ TEGRA_MUX_NAND,
+ TEGRA_MUX_NAND_ALT,
+ TEGRA_MUX_OWR,
+ TEGRA_MUX_PMI,
+ TEGRA_MUX_PWM0,
+ TEGRA_MUX_PWM1,
+ TEGRA_MUX_PWM2,
+ TEGRA_MUX_PWM3,
+ TEGRA_MUX_PWRON,
+ TEGRA_MUX_RESET_OUT_N,
+ TEGRA_MUX_RSVD1,
+ TEGRA_MUX_RSVD2,
+ TEGRA_MUX_RSVD3,
+ TEGRA_MUX_RSVD4,
+ TEGRA_MUX_SDMMC1,
+ TEGRA_MUX_SDMMC2,
+ TEGRA_MUX_SDMMC3,
+ TEGRA_MUX_SDMMC4,
+ TEGRA_MUX_SOC,
+ TEGRA_MUX_SPDIF,
+ TEGRA_MUX_SPI1,
+ TEGRA_MUX_SPI2,
+ TEGRA_MUX_SPI3,
+ TEGRA_MUX_SPI4,
+ TEGRA_MUX_SPI5,
+ TEGRA_MUX_SPI6,
+ TEGRA_MUX_SYSCLK,
+ TEGRA_MUX_TRACE,
+ TEGRA_MUX_UARTA,
+ TEGRA_MUX_UARTB,
+ TEGRA_MUX_UARTC,
+ TEGRA_MUX_UARTD,
+ TEGRA_MUX_ULPI,
+ TEGRA_MUX_USB,
+ TEGRA_MUX_VGP1,
+ TEGRA_MUX_VGP2,
+ TEGRA_MUX_VGP3,
+ TEGRA_MUX_VGP4,
+ TEGRA_MUX_VGP5,
+ TEGRA_MUX_VGP6,
+ TEGRA_MUX_VI,
+ TEGRA_MUX_VI_ALT1,
+ TEGRA_MUX_VI_ALT3,
+};
+
+static const char * const blink_groups[] = {
+ "clk_32k_out_pa0",
+};
+
+static const char * const cec_groups[] = {
+ "hdmi_cec_pee3",
+};
+
+static const char * const cldvfs_groups[] = {
+ "gmi_ad9_ph1",
+ "gmi_ad10_ph2",
+ "kb_row7_pr7",
+ "kb_row8_ps0",
+ "dvfs_pwm_px0",
+ "dvfs_clk_px2",
+};
+
+static const char * const clk12_groups[] = {
+ "sdmmc1_wp_n_pv3",
+ "sdmmc1_clk_pz0",
+};
+
+static const char * const cpu_groups[] = {
+ "cpu_pwr_req",
+};
+
+static const char * const dap_groups[] = {
+ "clk1_req_pee2",
+ "clk2_req_pcc5",
+};
+
+static const char * const dap1_groups[] = {
+ "clk1_req_pee2",
+};
+
+static const char * const dap2_groups[] = {
+ "clk1_out_pw4",
+ "gpio_x4_aud_px4",
+};
+
+static const char * const dev3_groups[] = {
+ "clk3_req_pee1",
+};
+
+static const char * const displaya_groups[] = {
+ "dap3_fs_pp0",
+ "dap3_din_pp1",
+ "dap3_dout_pp2",
+ "dap3_sclk_pp3",
+ "uart3_rts_n_pc0",
+ "pu3",
+ "pu4",
+ "pu5",
+ "pbb3",
+ "pbb4",
+ "pbb5",
+ "pbb6",
+ "kb_row3_pr3",
+ "kb_row4_pr4",
+ "kb_row5_pr5",
+ "kb_row6_pr6",
+ "kb_col3_pq3",
+ "sdmmc3_dat2_pb5",
+};
+
+static const char * const displaya_alt_groups[] = {
+ "kb_row6_pr6",
+};
+
+static const char * const displayb_groups[] = {
+ "dap3_fs_pp0",
+ "dap3_din_pp1",
+ "dap3_dout_pp2",
+ "dap3_sclk_pp3",
+ "pu3",
+ "pu4",
+ "pu5",
+ "pu6",
+ "pbb3",
+ "pbb4",
+ "pbb5",
+ "pbb6",
+ "kb_row3_pr3",
+ "kb_row4_pr4",
+ "kb_row5_pr5",
+ "kb_row6_pr6",
+ "sdmmc3_dat3_pb4",
+};
+
+static const char * const dtv_groups[] = {
+ "uart3_cts_n_pa1",
+ "uart3_rts_n_pc0",
+ "dap4_fs_pp4",
+ "dap4_dout_pp6",
+ "gmi_wait_pi7",
+ "gmi_ad8_ph0",
+ "gmi_ad14_ph6",
+ "gmi_ad15_ph7",
+};
+
+static const char * const emc_dll_groups[] = {
+ "kb_col0_pq0",
+ "kb_col1_pq1",
+};
+
+static const char * const extperiph1_groups[] = {
+ "clk1_out_pw4",
+};
+
+static const char * const extperiph2_groups[] = {
+ "clk2_out_pw5",
+};
+
+static const char * const extperiph3_groups[] = {
+ "clk3_out_pee0",
+};
+
+static const char * const gmi_groups[] = {
+ "gmi_wp_n_pc7",
+
+ "gmi_ad0_pg0",
+ "gmi_ad1_pg1",
+ "gmi_ad2_pg2",
+ "gmi_ad3_pg3",
+ "gmi_ad4_pg4",
+ "gmi_ad5_pg5",
+ "gmi_ad6_pg6",
+ "gmi_ad7_pg7",
+ "gmi_ad8_ph0",
+ "gmi_ad9_ph1",
+ "gmi_ad10_ph2",
+ "gmi_ad11_ph3",
+ "gmi_ad12_ph4",
+ "gmi_ad13_ph5",
+ "gmi_ad14_ph6",
+ "gmi_ad15_ph7",
+ "gmi_wr_n_pi0",
+ "gmi_oe_n_pi1",
+ "gmi_cs6_n_pi3",
+ "gmi_rst_n_pi4",
+ "gmi_iordy_pi5",
+ "gmi_cs7_n_pi6",
+ "gmi_wait_pi7",
+ "gmi_cs0_n_pj0",
+ "gmi_cs1_n_pj2",
+ "gmi_dqs_p_pj3",
+ "gmi_adv_n_pk0",
+ "gmi_clk_pk1",
+ "gmi_cs4_n_pk2",
+ "gmi_cs2_n_pk3",
+ "gmi_cs3_n_pk4",
+ "gmi_a16_pj7",
+ "gmi_a17_pb0",
+ "gmi_a18_pb1",
+ "gmi_a19_pk7",
+ "gen2_i2c_scl_pt5",
+ "gen2_i2c_sda_pt6",
+ "sdmmc4_dat0_paa0",
+ "sdmmc4_dat1_paa1",
+ "sdmmc4_dat2_paa2",
+ "sdmmc4_dat3_paa3",
+ "sdmmc4_dat4_paa4",
+ "sdmmc4_dat5_paa5",
+ "sdmmc4_dat6_paa6",
+ "sdmmc4_dat7_paa7",
+ "sdmmc4_clk_pcc4",
+ "sdmmc4_cmd_pt7",
+ "dap1_fs_pn0",
+ "dap1_din_pn1",
+ "dap1_dout_pn2",
+ "dap1_sclk_pn3",
+};
+
+static const char * const gmi_alt_groups[] = {
+ "gmi_wp_n_pc7",
+ "gmi_cs3_n_pk4",
+ "gmi_a16_pj7",
+};
+
+static const char * const hda_groups[] = {
+ "dap1_fs_pn0",
+ "dap1_din_pn1",
+ "dap1_dout_pn2",
+ "dap1_sclk_pn3",
+ "dap2_fs_pa2",
+ "dap2_sclk_pa3",
+ "dap2_din_pa4",
+ "dap2_dout_pa5",
+};
+
+static const char * const hsi_groups[] = {
+ "ulpi_data0_po1",
+ "ulpi_data1_po2",
+ "ulpi_data2_po3",
+ "ulpi_data3_po4",
+ "ulpi_data4_po5",
+ "ulpi_data5_po6",
+ "ulpi_data6_po7",
+ "ulpi_data7_po0",
+};
+
+static const char * const i2c1_groups[] = {
+ "gen1_i2c_scl_pc4",
+ "gen1_i2c_sda_pc5",
+ "gpio_w2_aud_pw2",
+ "gpio_w3_aud_pw3",
+};
+
+static const char * const i2c2_groups[] = {
+ "gen2_i2c_scl_pt5",
+ "gen2_i2c_sda_pt6",
+};
+
+static const char * const i2c3_groups[] = {
+ "cam_i2c_scl_pbb1",
+ "cam_i2c_sda_pbb2",
+};
+
+static const char * const i2c4_groups[] = {
+ "ddc_scl_pv4",
+ "ddc_sda_pv5",
+};
+
+static const char * const i2cpwr_groups[] = {
+ "pwr_i2c_scl_pz6",
+ "pwr_i2c_sda_pz7",
+};
+
+static const char * const i2s0_groups[] = {
+ "dap1_fs_pn0",
+ "dap1_din_pn1",
+ "dap1_dout_pn2",
+ "dap1_sclk_pn3",
+};
+
+static const char * const i2s1_groups[] = {
+ "dap2_fs_pa2",
+ "dap2_sclk_pa3",
+ "dap2_din_pa4",
+ "dap2_dout_pa5",
+};
+
+static const char * const i2s2_groups[] = {
+ "dap3_fs_pp0",
+ "dap3_din_pp1",
+ "dap3_dout_pp2",
+ "dap3_sclk_pp3",
+};
+
+static const char * const i2s3_groups[] = {
+ "dap4_fs_pp4",
+ "dap4_din_pp5",
+ "dap4_dout_pp6",
+ "dap4_sclk_pp7",
+};
+
+static const char * const i2s4_groups[] = {
+ "pcc1",
+ "pbb0",
+ "pbb7",
+ "pcc2",
+};
+
+static const char * const irda_groups[] = {
+ "uart2_rxd_pc3",
+ "uart2_txd_pc2",
+};
+
+static const char * const kbc_groups[] = {
+ "kb_row0_pr0",
+ "kb_row1_pr1",
+ "kb_row2_pr2",
+ "kb_row3_pr3",
+ "kb_row4_pr4",
+ "kb_row5_pr5",
+ "kb_row6_pr6",
+ "kb_row7_pr7",
+ "kb_row8_ps0",
+ "kb_row9_ps1",
+ "kb_row10_ps2",
+ "kb_col0_pq0",
+ "kb_col1_pq1",
+ "kb_col2_pq2",
+ "kb_col3_pq3",
+ "kb_col4_pq4",
+ "kb_col5_pq5",
+ "kb_col6_pq6",
+ "kb_col7_pq7",
+};
+
+static const char * const nand_groups[] = {
+ "gmi_wp_n_pc7",
+ "gmi_wait_pi7",
+ "gmi_adv_n_pk0",
+ "gmi_clk_pk1",
+ "gmi_cs0_n_pj0",
+ "gmi_cs1_n_pj2",
+ "gmi_cs2_n_pk3",
+ "gmi_cs3_n_pk4",
+ "gmi_cs4_n_pk2",
+ "gmi_cs6_n_pi3",
+ "gmi_cs7_n_pi6",
+ "gmi_ad0_pg0",
+ "gmi_ad1_pg1",
+ "gmi_ad2_pg2",
+ "gmi_ad3_pg3",
+ "gmi_ad4_pg4",
+ "gmi_ad5_pg5",
+ "gmi_ad6_pg6",
+ "gmi_ad7_pg7",
+ "gmi_ad8_ph0",
+ "gmi_ad9_ph1",
+ "gmi_ad10_ph2",
+ "gmi_ad11_ph3",
+ "gmi_ad12_ph4",
+ "gmi_ad13_ph5",
+ "gmi_ad14_ph6",
+ "gmi_ad15_ph7",
+ "gmi_wr_n_pi0",
+ "gmi_oe_n_pi1",
+ "gmi_dqs_p_pj3",
+ "gmi_rst_n_pi4",
+};
+
+static const char * const nand_alt_groups[] = {
+ "gmi_cs6_n_pi3",
+ "gmi_cs7_n_pi6",
+ "gmi_rst_n_pi4",
+};
+
+static const char * const owr_groups[] = {
+ "pu0",
+ "kb_col4_pq4",
+ "owr",
+ "sdmmc3_cd_n_pv2",
+};
+
+static const char * const pmi_groups[] = {
+ "pwr_int_n",
+};
+
+static const char * const pwm0_groups[] = {
+ "sdmmc1_dat2_py5",
+ "uart3_rts_n_pc0",
+ "pu3",
+ "gmi_ad8_ph0",
+ "sdmmc3_dat3_pb4",
+};
+
+static const char * const pwm1_groups[] = {
+ "sdmmc1_dat1_py6",
+ "pu4",
+ "gmi_ad9_ph1",
+ "sdmmc3_dat2_pb5",
+};
+
+static const char * const pwm2_groups[] = {
+ "pu5",
+ "gmi_ad10_ph2",
+ "kb_col3_pq3",
+ "sdmmc3_dat1_pb6",
+};
+
+static const char * const pwm3_groups[] = {
+ "pu6",
+ "gmi_ad11_ph3",
+ "sdmmc3_cmd_pa7",
+};
+
+static const char * const pwron_groups[] = {
+ "core_pwr_req",
+};
+
+static const char * const reset_out_n_groups[] = {
+ "reset_out_n",
+};
+
+static const char * const rsvd1_groups[] = {
+ "pv1",
+ "hdmi_int_pn7",
+ "pu1",
+ "pu2",
+ "gmi_wp_n_pc7",
+ "gmi_adv_n_pk0",
+ "gmi_cs0_n_pj0",
+ "gmi_cs1_n_pj2",
+ "gmi_ad0_pg0",
+ "gmi_ad1_pg1",
+ "gmi_ad2_pg2",
+ "gmi_ad3_pg3",
+ "gmi_ad4_pg4",
+ "gmi_ad5_pg5",
+ "gmi_ad6_pg6",
+ "gmi_ad7_pg7",
+ "gmi_wr_n_pi0",
+ "gmi_oe_n_pi1",
+ "gpio_x4_aud_px4",
+ "gpio_x5_aud_px5",
+ "gpio_x7_aud_px7",
+
+ "reset_out_n",
+};
+
+static const char * const rsvd2_groups[] = {
+ "pv0",
+ "pv1",
+ "sdmmc1_dat0_py7",
+ "clk2_out_pw5",
+ "clk2_req_pcc5",
+ "hdmi_int_pn7",
+ "ddc_scl_pv4",
+ "ddc_sda_pv5",
+ "uart3_txd_pw6",
+ "uart3_rxd_pw7",
+ "gen1_i2c_scl_pc4",
+ "gen1_i2c_sda_pc5",
+ "dap4_fs_pp4",
+ "dap4_din_pp5",
+ "dap4_dout_pp6",
+ "dap4_sclk_pp7",
+ "clk3_out_pee0",
+ "clk3_req_pee1",
+ "gmi_iordy_pi5",
+ "gmi_a17_pb0",
+ "gmi_a18_pb1",
+ "gen2_i2c_scl_pt5",
+ "gen2_i2c_sda_pt6",
+ "sdmmc4_clk_pcc4",
+ "sdmmc4_cmd_pt7",
+ "sdmmc4_dat7_paa7",
+ "pcc1",
+ "pbb7",
+ "pcc2",
+ "pwr_i2c_scl_pz6",
+ "pwr_i2c_sda_pz7",
+ "kb_row0_pr0",
+ "kb_row1_pr1",
+ "kb_row2_pr2",
+ "kb_row7_pr7",
+ "kb_row8_ps0",
+ "kb_row9_ps1",
+ "kb_row10_ps2",
+ "kb_col1_pq1",
+ "kb_col2_pq2",
+ "kb_col5_pq5",
+ "kb_col6_pq6",
+ "kb_col7_pq7",
+ "sys_clk_req_pz5",
+ "core_pwr_req",
+ "cpu_pwr_req",
+ "pwr_int_n",
+ "owr",
+ "spdif_out_pk5",
+ "gpio_x1_aud_px1",
+ "sdmmc3_clk_pa6",
+ "sdmmc3_dat0_pb7",
+ "gpio_w2_aud_pw2",
+ "usb_vbus_en0_pn4",
+ "usb_vbus_en1_pn5",
+ "sdmmc3_clk_lb_out_pee4",
+ "sdmmc3_clk_lb_in_pee5",
+ "reset_out_n",
+};
+
+static const char * const rsvd3_groups[] = {
+ "pv0",
+ "pv1",
+ "sdmmc1_clk_pz0",
+ "clk2_out_pw5",
+ "clk2_req_pcc5",
+ "hdmi_int_pn7",
+ "ddc_scl_pv4",
+ "ddc_sda_pv5",
+ "uart2_rts_n_pj6",
+ "uart2_cts_n_pj5",
+ "uart3_txd_pw6",
+ "uart3_rxd_pw7",
+ "pu0",
+ "pu1",
+ "pu2",
+ "gen1_i2c_scl_pc4",
+ "gen1_i2c_sda_pc5",
+ "dap4_din_pp5",
+ "dap4_sclk_pp7",
+ "clk3_out_pee0",
+ "clk3_req_pee1",
+ "pcc1",
+ "cam_i2c_scl_pbb1",
+ "cam_i2c_sda_pbb2",
+ "pbb7",
+ "pcc2",
+ "pwr_i2c_scl_pz6",
+ "pwr_i2c_sda_pz7",
+ "kb_row0_pr0",
+ "kb_row1_pr1",
+ "kb_row2_pr2",
+ "kb_row3_pr3",
+ "kb_row9_ps1",
+ "kb_row10_ps2",
+ "clk_32k_out_pa0",
+ "sys_clk_req_pz5",
+ "core_pwr_req",
+ "cpu_pwr_req",
+ "pwr_int_n",
+ "owr",
+ "clk1_req_pee2",
+ "clk1_out_pw4",
+ "spdif_out_pk5",
+ "spdif_in_pk6",
+ "dap2_fs_pa2",
+ "dap2_sclk_pa3",
+ "dap2_din_pa4",
+ "dap2_dout_pa5",
+ "dvfs_pwm_px0",
+ "gpio_x1_aud_px1",
+ "gpio_x3_aud_px3",
+ "dvfs_clk_px2",
+ "sdmmc3_clk_pa6",
+ "sdmmc3_dat0_pb7",
+ "hdmi_cec_pee3",
+ "sdmmc3_cd_n_pv2",
+ "usb_vbus_en0_pn4",
+ "usb_vbus_en1_pn5",
+ "sdmmc3_clk_lb_out_pee4",
+ "sdmmc3_clk_lb_in_pee5",
+ "reset_out_n",
+};
+
+static const char * const rsvd4_groups[] = {
+ "pv0",
+ "pv1",
+ "sdmmc1_clk_pz0",
+ "clk2_out_pw5",
+ "clk2_req_pcc5",
+ "hdmi_int_pn7",
+ "ddc_scl_pv4",
+ "ddc_sda_pv5",
+ "pu0",
+ "pu1",
+ "pu2",
+ "gen1_i2c_scl_pc4",
+ "gen1_i2c_sda_pc5",
+ "dap4_fs_pp4",
+ "dap4_din_pp5",
+ "dap4_dout_pp6",
+ "dap4_sclk_pp7",
+ "clk3_out_pee0",
+ "clk3_req_pee1",
+ "gmi_ad0_pg0",
+ "gmi_ad1_pg1",
+ "gmi_ad2_pg2",
+ "gmi_ad3_pg3",
+ "gmi_ad4_pg4",
+ "gmi_ad12_ph4",
+ "gmi_ad13_ph5",
+ "gmi_rst_n_pi4",
+ "gen2_i2c_scl_pt5",
+ "gen2_i2c_sda_pt6",
+ "sdmmc4_clk_pcc4",
+ "sdmmc4_cmd_pt7",
+ "sdmmc4_dat0_paa0",
+ "sdmmc4_dat1_paa1",
+ "sdmmc4_dat2_paa2",
+ "sdmmc4_dat3_paa3",
+ "sdmmc4_dat4_paa4",
+ "sdmmc4_dat5_paa5",
+ "sdmmc4_dat6_paa6",
+ "sdmmc4_dat7_paa7",
+ "cam_mclk_pcc0",
+ "pcc1",
+ "cam_i2c_scl_pbb1",
+ "cam_i2c_sda_pbb2",
+ "pbb3",
+ "pbb4",
+ "pbb5",
+ "pbb6",
+ "pbb7",
+ "pcc2",
+ "pwr_i2c_scl_pz6",
+ "pwr_i2c_sda_pz7",
+ "kb_row0_pr0",
+ "kb_row1_pr1",
+ "kb_row2_pr2",
+ "kb_col2_pq2",
+ "kb_col5_pq5",
+ "kb_col6_pq6",
+ "kb_col7_pq7",
+ "clk_32k_out_pa0",
+ "sys_clk_req_pz5",
+ "core_pwr_req",
+ "cpu_pwr_req",
+ "pwr_int_n",
+ "owr",
+ "dap1_fs_pn0",
+ "dap1_din_pn1",
+ "dap1_dout_pn2",
+ "dap1_sclk_pn3",
+ "clk1_req_pee2",
+ "clk1_out_pw4",
+ "spdif_in_pk6",
+ "spdif_out_pk5",
+ "dap2_fs_pa2",
+ "dap2_sclk_pa3",
+ "dap2_din_pa4",
+ "dap2_dout_pa5",
+ "dvfs_pwm_px0",
+ "gpio_x1_aud_px1",
+ "gpio_x3_aud_px3",
+ "dvfs_clk_px2",
+ "gpio_x5_aud_px5",
+ "gpio_x6_aud_px6",
+ "gpio_x7_aud_px7",
+ "sdmmc3_cd_n_pv2",
+ "usb_vbus_en0_pn4",
+ "usb_vbus_en1_pn5",
+ "sdmmc3_clk_lb_in_pee5",
+ "sdmmc3_clk_lb_out_pee4",
+};
+
+static const char * const sdmmc1_groups[] = {
+
+ "sdmmc1_clk_pz0",
+ "sdmmc1_cmd_pz1",
+ "sdmmc1_dat3_py4",
+ "sdmmc1_dat2_py5",
+ "sdmmc1_dat1_py6",
+ "sdmmc1_dat0_py7",
+ "uart3_cts_n_pa1",
+ "kb_col5_pq5",
+ "sdmmc1_wp_n_pv3",
+};
+
+static const char * const sdmmc2_groups[] = {
+ "gmi_iordy_pi5",
+ "gmi_clk_pk1",
+ "gmi_cs2_n_pk3",
+ "gmi_cs3_n_pk4",
+ "gmi_cs7_n_pi6",
+ "gmi_ad12_ph4",
+ "gmi_ad13_ph5",
+ "gmi_ad14_ph6",
+ "gmi_ad15_ph7",
+ "gmi_dqs_p_pj3",
+};
+
+static const char * const sdmmc3_groups[] = {
+ "kb_col4_pq4",
+ "sdmmc3_clk_pa6",
+ "sdmmc3_cmd_pa7",
+ "sdmmc3_dat0_pb7",
+ "sdmmc3_dat1_pb6",
+ "sdmmc3_dat2_pb5",
+ "sdmmc3_dat3_pb4",
+ "hdmi_cec_pee3",
+ "sdmmc3_cd_n_pv2",
+ "sdmmc3_clk_lb_in_pee5",
+ "sdmmc3_clk_lb_out_pee4",
+};
+
+static const char * const sdmmc4_groups[] = {
+ "sdmmc4_clk_pcc4",
+ "sdmmc4_cmd_pt7",
+ "sdmmc4_dat0_paa0",
+ "sdmmc4_dat1_paa1",
+ "sdmmc4_dat2_paa2",
+ "sdmmc4_dat3_paa3",
+ "sdmmc4_dat4_paa4",
+ "sdmmc4_dat5_paa5",
+ "sdmmc4_dat6_paa6",
+ "sdmmc4_dat7_paa7",
+};
+
+static const char * const soc_groups[] = {
+ "gmi_cs1_n_pj2",
+ "gmi_oe_n_pi1",
+ "clk_32k_out_pa0",
+ "hdmi_cec_pee3",
+};
+
+static const char * const spdif_groups[] = {
+ "sdmmc1_cmd_pz1",
+ "sdmmc1_dat3_py4",
+ "uart2_rxd_pc3",
+ "uart2_txd_pc2",
+ "spdif_in_pk6",
+ "spdif_out_pk5",
+};
+
+static const char * const spi1_groups[] = {
+ "ulpi_clk_py0",
+ "ulpi_dir_py1",
+ "ulpi_nxt_py2",
+ "ulpi_stp_py3",
+ "gpio_x3_aud_px3",
+ "gpio_x4_aud_px4",
+ "gpio_x5_aud_px5",
+ "gpio_x6_aud_px6",
+ "gpio_x7_aud_px7",
+ "gpio_w3_aud_pw3",
+};
+
+static const char * const spi2_groups[] = {
+ "ulpi_data4_po5",
+ "ulpi_data5_po6",
+ "ulpi_data6_po7",
+ "ulpi_data7_po0",
+ "kb_row4_pr4",
+ "kb_row5_pr5",
+ "kb_col0_pq0",
+ "kb_col1_pq1",
+ "kb_col2_pq2",
+ "kb_col6_pq6",
+ "kb_col7_pq7",
+ "gpio_x4_aud_px4",
+ "gpio_x5_aud_px5",
+ "gpio_x6_aud_px6",
+ "gpio_x7_aud_px7",
+ "gpio_w2_aud_pw2",
+ "gpio_w3_aud_pw3",
+};
+
+static const char * const spi3_groups[] = {
+ "ulpi_data0_po1",
+ "ulpi_data1_po2",
+ "ulpi_data2_po3",
+ "ulpi_data3_po4",
+ "sdmmc4_dat0_paa0",
+ "sdmmc4_dat1_paa1",
+ "sdmmc4_dat2_paa2",
+ "sdmmc4_dat3_paa3",
+ "sdmmc4_dat4_paa4",
+ "sdmmc4_dat5_paa5",
+ "sdmmc4_dat6_paa6",
+ "sdmmc3_clk_pa6",
+ "sdmmc3_cmd_pa7",
+ "sdmmc3_dat0_pb7",
+ "sdmmc3_dat1_pb6",
+ "sdmmc3_dat2_pb5",
+ "sdmmc3_dat3_pb4",
+};
+
+static const char * const spi4_groups[] = {
+ "sdmmc1_cmd_pz1",
+ "sdmmc1_dat3_py4",
+ "sdmmc1_dat2_py5",
+ "sdmmc1_dat1_py6",
+ "sdmmc1_dat0_py7",
+ "uart2_rxd_pc3",
+ "uart2_txd_pc2",
+ "uart2_rts_n_pj6",
+ "uart2_cts_n_pj5",
+ "uart3_txd_pw6",
+ "uart3_rxd_pw7",
+ "uart3_cts_n_pa1",
+ "gmi_wait_pi7",
+ "gmi_cs6_n_pi3",
+ "gmi_ad5_pg5",
+ "gmi_ad6_pg6",
+ "gmi_ad7_pg7",
+ "gmi_a19_pk7",
+ "gmi_wr_n_pi0",
+ "sdmmc1_wp_n_pv3",
+};
+
+static const char * const spi5_groups[] = {
+ "ulpi_clk_py0",
+ "ulpi_dir_py1",
+ "ulpi_nxt_py2",
+ "ulpi_stp_py3",
+ "dap3_fs_pp0",
+ "dap3_din_pp1",
+ "dap3_dout_pp2",
+ "dap3_sclk_pp3",
+};
+
+static const char * const spi6_groups[] = {
+ "dvfs_pwm_px0",
+ "gpio_x1_aud_px1",
+ "gpio_x3_aud_px3",
+ "dvfs_clk_px2",
+ "gpio_x6_aud_px6",
+ "gpio_w2_aud_pw2",
+ "gpio_w3_aud_pw3",
+};
+
+static const char * const sysclk_groups[] = {
+ "sys_clk_req_pz5",
+};
+
+static const char * const trace_groups[] = {
+ "gmi_iordy_pi5",
+ "gmi_adv_n_pk0",
+ "gmi_clk_pk1",
+ "gmi_cs2_n_pk3",
+ "gmi_cs4_n_pk2",
+ "gmi_a16_pj7",
+ "gmi_a17_pb0",
+ "gmi_a18_pb1",
+ "gmi_a19_pk7",
+ "gmi_dqs_p_pj3",
+};
+
+static const char * const uarta_groups[] = {
+ "ulpi_data0_po1",
+ "ulpi_data1_po2",
+ "ulpi_data2_po3",
+ "ulpi_data3_po4",
+ "ulpi_data4_po5",
+ "ulpi_data5_po6",
+ "ulpi_data6_po7",
+ "ulpi_data7_po0",
+ "sdmmc1_cmd_pz1",
+ "sdmmc1_dat3_py4",
+ "sdmmc1_dat2_py5",
+ "sdmmc1_dat1_py6",
+ "sdmmc1_dat0_py7",
+ "uart2_rxd_pc3",
+ "uart2_txd_pc2",
+ "uart2_rts_n_pj6",
+ "uart2_cts_n_pj5",
+ "pu0",
+ "pu1",
+ "pu2",
+ "pu3",
+ "pu4",
+ "pu5",
+ "pu6",
+ "kb_row7_pr7",
+ "kb_row8_ps0",
+ "kb_row9_ps1",
+ "kb_row10_ps2",
+ "kb_col3_pq3",
+ "kb_col4_pq4",
+ "sdmmc3_cmd_pa7",
+ "sdmmc3_dat1_pb6",
+ "sdmmc1_wp_n_pv3",
+};
+
+static const char * const uartb_groups[] = {
+ "uart2_rts_n_pj6",
+ "uart2_cts_n_pj5",
+};
+
+static const char * const uartc_groups[] = {
+ "uart3_txd_pw6",
+ "uart3_rxd_pw7",
+ "uart3_cts_n_pa1",
+ "uart3_rts_n_pc0",
+};
+
+static const char * const uartd_groups[] = {
+ "ulpi_clk_py0",
+ "ulpi_dir_py1",
+ "ulpi_nxt_py2",
+ "ulpi_stp_py3",
+ "gmi_a16_pj7",
+ "gmi_a17_pb0",
+ "gmi_a18_pb1",
+ "gmi_a19_pk7",
+};
+
+static const char * const ulpi_groups[] = {
+ "ulpi_data0_po1",
+ "ulpi_data1_po2",
+ "ulpi_data2_po3",
+ "ulpi_data3_po4",
+ "ulpi_data4_po5",
+ "ulpi_data5_po6",
+ "ulpi_data6_po7",
+ "ulpi_data7_po0",
+ "ulpi_clk_py0",
+ "ulpi_dir_py1",
+ "ulpi_nxt_py2",
+ "ulpi_stp_py3",
+};
+
+static const char * const usb_groups[] = {
+ "pv0",
+ "pu6",
+ "gmi_cs0_n_pj0",
+ "gmi_cs4_n_pk2",
+ "gmi_ad11_ph3",
+ "kb_col0_pq0",
+ "spdif_in_pk6",
+ "usb_vbus_en0_pn4",
+ "usb_vbus_en1_pn5",
+};
+
+static const char * const vgp1_groups[] = {
+ "cam_i2c_scl_pbb1",
+};
+
+static const char * const vgp2_groups[] = {
+ "cam_i2c_sda_pbb2",
+};
+
+static const char * const vgp3_groups[] = {
+ "pbb3",
+};
+
+static const char * const vgp4_groups[] = {
+ "pbb4",
+};
+
+static const char * const vgp5_groups[] = {
+ "pbb5",
+};
+
+static const char * const vgp6_groups[] = {
+ "pbb6",
+};
+
+static const char * const vi_groups[] = {
+ "cam_mclk_pcc0",
+ "pbb0",
+};
+
+static const char * const vi_alt1_groups[] = {
+ "cam_mclk_pcc0",
+ "pbb0",
+};
+
+static const char * const vi_alt3_groups[] = {
+ "cam_mclk_pcc0",
+ "pbb0",
+};
+
+#define FUNCTION(fname) \
+ { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+static const struct tegra_function tegra114_functions[] = {
+ FUNCTION(blink),
+ FUNCTION(cec),
+ FUNCTION(cldvfs),
+ FUNCTION(clk12),
+ FUNCTION(cpu),
+ FUNCTION(dap),
+ FUNCTION(dap1),
+ FUNCTION(dap2),
+ FUNCTION(dev3),
+ FUNCTION(displaya),
+ FUNCTION(displaya_alt),
+ FUNCTION(displayb),
+ FUNCTION(dtv),
+ FUNCTION(emc_dll),
+ FUNCTION(extperiph1),
+ FUNCTION(extperiph2),
+ FUNCTION(extperiph3),
+ FUNCTION(gmi),
+ FUNCTION(gmi_alt),
+ FUNCTION(hda),
+ FUNCTION(hsi),
+ FUNCTION(i2c1),
+ FUNCTION(i2c2),
+ FUNCTION(i2c3),
+ FUNCTION(i2c4),
+ FUNCTION(i2cpwr),
+ FUNCTION(i2s0),
+ FUNCTION(i2s1),
+ FUNCTION(i2s2),
+ FUNCTION(i2s3),
+ FUNCTION(i2s4),
+ FUNCTION(irda),
+ FUNCTION(kbc),
+ FUNCTION(nand),
+ FUNCTION(nand_alt),
+ FUNCTION(owr),
+ FUNCTION(pmi),
+ FUNCTION(pwm0),
+ FUNCTION(pwm1),
+ FUNCTION(pwm2),
+ FUNCTION(pwm3),
+ FUNCTION(pwron),
+ FUNCTION(reset_out_n),
+ FUNCTION(rsvd1),
+ FUNCTION(rsvd2),
+ FUNCTION(rsvd3),
+ FUNCTION(rsvd4),
+ FUNCTION(sdmmc1),
+ FUNCTION(sdmmc2),
+ FUNCTION(sdmmc3),
+ FUNCTION(sdmmc4),
+ FUNCTION(soc),
+ FUNCTION(spdif),
+ FUNCTION(spi1),
+ FUNCTION(spi2),
+ FUNCTION(spi3),
+ FUNCTION(spi4),
+ FUNCTION(spi5),
+ FUNCTION(spi6),
+ FUNCTION(sysclk),
+ FUNCTION(trace),
+ FUNCTION(uarta),
+ FUNCTION(uartb),
+ FUNCTION(uartc),
+ FUNCTION(uartd),
+ FUNCTION(ulpi),
+ FUNCTION(usb),
+ FUNCTION(vgp1),
+ FUNCTION(vgp2),
+ FUNCTION(vgp3),
+ FUNCTION(vgp4),
+ FUNCTION(vgp5),
+ FUNCTION(vgp6),
+ FUNCTION(vi),
+ FUNCTION(vi_alt1),
+ FUNCTION(vi_alt3),
+};
+
+#define DRV_PINGROUP_REG_START 0x868 /* bank 0 */
+#define PINGROUP_REG_START 0x3000 /* bank 1 */
+
+#define PINGROUP_REG_Y(r) ((r) - PINGROUP_REG_START)
+#define PINGROUP_REG_N(r) -1
+
+#define PINGROUP(pg_name, f0, f1, f2, f3, f_safe, r, od, ior, rcv_sel) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = ARRAY_SIZE(pg_name##_pins), \
+ .funcs = { \
+ TEGRA_MUX_##f0, \
+ TEGRA_MUX_##f1, \
+ TEGRA_MUX_##f2, \
+ TEGRA_MUX_##f3, \
+ }, \
+ .func_safe = TEGRA_MUX_##f_safe, \
+ .mux_reg = PINGROUP_REG_Y(r), \
+ .mux_bank = 1, \
+ .mux_bit = 0, \
+ .pupd_reg = PINGROUP_REG_Y(r), \
+ .pupd_bank = 1, \
+ .pupd_bit = 2, \
+ .tri_reg = PINGROUP_REG_Y(r), \
+ .tri_bank = 1, \
+ .tri_bit = 4, \
+ .einput_reg = PINGROUP_REG_Y(r), \
+ .einput_bank = 1, \
+ .einput_bit = 5, \
+ .odrain_reg = PINGROUP_REG_##od(r), \
+ .odrain_bank = 1, \
+ .odrain_bit = 6, \
+ .lock_reg = PINGROUP_REG_Y(r), \
+ .lock_bank = 1, \
+ .lock_bit = 7, \
+ .ioreset_reg = PINGROUP_REG_##ior(r), \
+ .ioreset_bank = 1, \
+ .ioreset_bit = 8, \
+ .rcv_sel_reg = PINGROUP_REG_##rcv_sel(r), \
+ .rcv_sel_bank = 1, \
+ .rcv_sel_bit = 9, \
+ .drv_reg = -1, \
+ .drvtype_reg = -1, \
+ }
+
+#define DRV_PINGROUP_DVRTYPE_Y(r) ((r) - DRV_PINGROUP_REG_START)
+#define DRV_PINGROUP_DVRTYPE_N(r) -1
+
+#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \
+ drvdn_b, drvdn_w, drvup_b, drvup_w, \
+ slwr_b, slwr_w, slwf_b, slwf_w, \
+ drvtype) \
+ { \
+ .name = "drive_" #pg_name, \
+ .pins = drive_##pg_name##_pins, \
+ .npins = ARRAY_SIZE(drive_##pg_name##_pins), \
+ .mux_reg = -1, \
+ .pupd_reg = -1, \
+ .tri_reg = -1, \
+ .einput_reg = -1, \
+ .odrain_reg = -1, \
+ .lock_reg = -1, \
+ .ioreset_reg = -1, \
+ .rcv_sel_reg = -1, \
+ .drv_reg = DRV_PINGROUP_DVRTYPE_Y(r), \
+ .drv_bank = 0, \
+ .hsm_bit = hsm_b, \
+ .schmitt_bit = schmitt_b, \
+ .lpmd_bit = lpmd_b, \
+ .drvdn_bit = drvdn_b, \
+ .drvdn_width = drvdn_w, \
+ .drvup_bit = drvup_b, \
+ .drvup_width = drvup_w, \
+ .slwr_bit = slwr_b, \
+ .slwr_width = slwr_w, \
+ .slwf_bit = slwf_b, \
+ .slwf_width = slwf_w, \
+ .drvtype_reg = DRV_PINGROUP_DVRTYPE_##drvtype(r), \
+ .drvtype_bank = 0, \
+ .drvtype_bit = 6, \
+ }
+
+static const struct tegra_pingroup tegra114_groups[] = {
+ /* pg_name, f0, f1, f2, f3, safe, r, od, ior, rcv_sel */
+ /* FIXME: Fill in correct data in safe column */
+ PINGROUP(ulpi_data0_po1, SPI3, HSI, UARTA, ULPI, ULPI, 0x3000, N, N, N),
+ PINGROUP(ulpi_data1_po2, SPI3, HSI, UARTA, ULPI, ULPI, 0x3004, N, N, N),
+ PINGROUP(ulpi_data2_po3, SPI3, HSI, UARTA, ULPI, ULPI, 0x3008, N, N, N),
+ PINGROUP(ulpi_data3_po4, SPI3, HSI, UARTA, ULPI, ULPI, 0x300c, N, N, N),
+ PINGROUP(ulpi_data4_po5, SPI2, HSI, UARTA, ULPI, ULPI, 0x3010, N, N, N),
+ PINGROUP(ulpi_data5_po6, SPI2, HSI, UARTA, ULPI, ULPI, 0x3014, N, N, N),
+ PINGROUP(ulpi_data6_po7, SPI2, HSI, UARTA, ULPI, ULPI, 0x3018, N, N, N),
+ PINGROUP(ulpi_data7_po0, SPI2, HSI, UARTA, ULPI, ULPI, 0x301c, N, N, N),
+ PINGROUP(ulpi_clk_py0, SPI1, SPI5, UARTD, ULPI, ULPI, 0x3020, N, N, N),
+ PINGROUP(ulpi_dir_py1, SPI1, SPI5, UARTD, ULPI, ULPI, 0x3024, N, N, N),
+ PINGROUP(ulpi_nxt_py2, SPI1, SPI5, UARTD, ULPI, ULPI, 0x3028, N, N, N),
+ PINGROUP(ulpi_stp_py3, SPI1, SPI5, UARTD, ULPI, ULPI, 0x302c, N, N, N),
+ PINGROUP(dap3_fs_pp0, I2S2, SPI5, DISPLAYA, DISPLAYB, I2S2, 0x3030, N, N, N),
+ PINGROUP(dap3_din_pp1, I2S2, SPI5, DISPLAYA, DISPLAYB, I2S2, 0x3034, N, N, N),
+ PINGROUP(dap3_dout_pp2, I2S2, SPI5, DISPLAYA, DISPLAYB, I2S2, 0x3038, N, N, N),
+ PINGROUP(dap3_sclk_pp3, I2S2, SPI5, DISPLAYA, DISPLAYB, I2S2, 0x303c, N, N, N),
+ PINGROUP(pv0, USB, RSVD2, RSVD3, RSVD4, RSVD4, 0x3040, N, N, N),
+ PINGROUP(pv1, RSVD1, RSVD2, RSVD3, RSVD4, RSVD4, 0x3044, N, N, N),
+ PINGROUP(sdmmc1_clk_pz0, SDMMC1, CLK12, RSVD3, RSVD4, RSVD4, 0x3048, N, N, N),
+ PINGROUP(sdmmc1_cmd_pz1, SDMMC1, SPDIF, SPI4, UARTA, SDMMC1, 0x304c, N, N, N),
+ PINGROUP(sdmmc1_dat3_py4, SDMMC1, SPDIF, SPI4, UARTA, SDMMC1, 0x3050, N, N, N),
+ PINGROUP(sdmmc1_dat2_py5, SDMMC1, PWM0, SPI4, UARTA, SDMMC1, 0x3054, N, N, N),
+ PINGROUP(sdmmc1_dat1_py6, SDMMC1, PWM1, SPI4, UARTA, SDMMC1, 0x3058, N, N, N),
+ PINGROUP(sdmmc1_dat0_py7, SDMMC1, RSVD2, SPI4, UARTA, RSVD2, 0x305c, N, N, N),
+ PINGROUP(clk2_out_pw5, EXTPERIPH2, RSVD2, RSVD3, RSVD4, RSVD4, 0x3068, N, N, N),
+ PINGROUP(clk2_req_pcc5, DAP, RSVD2, RSVD3, RSVD4, RSVD4, 0x306c, N, N, N),
+ PINGROUP(hdmi_int_pn7, RSVD1, RSVD2, RSVD3, RSVD4, RSVD4, 0x3110, N, N, Y),
+ PINGROUP(ddc_scl_pv4, I2C4, RSVD2, RSVD3, RSVD4, RSVD4, 0x3114, N, N, Y),
+ PINGROUP(ddc_sda_pv5, I2C4, RSVD2, RSVD3, RSVD4, RSVD4, 0x3118, N, N, Y),
+ PINGROUP(uart2_rxd_pc3, IRDA, SPDIF, UARTA, SPI4, IRDA, 0x3164, N, N, N),
+ PINGROUP(uart2_txd_pc2, IRDA, SPDIF, UARTA, SPI4, IRDA, 0x3168, N, N, N),
+ PINGROUP(uart2_rts_n_pj6, UARTA, UARTB, RSVD3, SPI4, RSVD3, 0x316c, N, N, N),
+ PINGROUP(uart2_cts_n_pj5, UARTA, UARTB, RSVD3, SPI4, RSVD3, 0x3170, N, N, N),
+ PINGROUP(uart3_txd_pw6, UARTC, RSVD2, RSVD3, SPI4, RSVD3, 0x3174, N, N, N),
+ PINGROUP(uart3_rxd_pw7, UARTC, RSVD2, RSVD3, SPI4, RSVD3, 0x3178, N, N, N),
+ PINGROUP(uart3_cts_n_pa1, UARTC, SDMMC1, DTV, SPI4, UARTC, 0x317c, N, N, N),
+ PINGROUP(uart3_rts_n_pc0, UARTC, PWM0, DTV, DISPLAYA, UARTC, 0x3180, N, N, N),
+ PINGROUP(pu0, OWR, UARTA, RSVD3, RSVD4, RSVD4, 0x3184, N, N, N),
+ PINGROUP(pu1, RSVD1, UARTA, RSVD3, RSVD4, RSVD4, 0x3188, N, N, N),
+ PINGROUP(pu2, RSVD1, UARTA, RSVD3, RSVD4, RSVD4, 0x318c, N, N, N),
+ PINGROUP(pu3, PWM0, UARTA, DISPLAYA, DISPLAYB, PWM0, 0x3190, N, N, N),
+ PINGROUP(pu4, PWM1, UARTA, DISPLAYA, DISPLAYB, PWM1, 0x3194, N, N, N),
+ PINGROUP(pu5, PWM2, UARTA, DISPLAYA, DISPLAYB, PWM2, 0x3198, N, N, N),
+ PINGROUP(pu6, PWM3, UARTA, USB, DISPLAYB, PWM3, 0x319c, N, N, N),
+ PINGROUP(gen1_i2c_sda_pc5, I2C1, RSVD2, RSVD3, RSVD4, RSVD4, 0x31a0, Y, N, N),
+ PINGROUP(gen1_i2c_scl_pc4, I2C1, RSVD2, RSVD3, RSVD4, RSVD4, 0x31a4, Y, N, N),
+ PINGROUP(dap4_fs_pp4, I2S3, RSVD2, DTV, RSVD4, RSVD4, 0x31a8, N, N, N),
+ PINGROUP(dap4_din_pp5, I2S3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31ac, N, N, N),
+ PINGROUP(dap4_dout_pp6, I2S3, RSVD2, DTV, RSVD4, RSVD4, 0x31b0, N, N, N),
+ PINGROUP(dap4_sclk_pp7, I2S3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31b4, N, N, N),
+ PINGROUP(clk3_out_pee0, EXTPERIPH3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31b8, N, N, N),
+ PINGROUP(clk3_req_pee1, DEV3, RSVD2, RSVD3, RSVD4, RSVD4, 0x31bc, N, N, N),
+ PINGROUP(gmi_wp_n_pc7, RSVD1, NAND, GMI, GMI_ALT, RSVD1, 0x31c0, N, N, N),
+ PINGROUP(gmi_iordy_pi5, SDMMC2, RSVD2, GMI, TRACE, RSVD2, 0x31c4, N, N, N),
+ PINGROUP(gmi_wait_pi7, SPI4, NAND, GMI, DTV, NAND, 0x31c8, N, N, N),
+ PINGROUP(gmi_adv_n_pk0, RSVD1, NAND, GMI, TRACE, RSVD1, 0x31cc, N, N, N),
+ PINGROUP(gmi_clk_pk1, SDMMC2, NAND, GMI, TRACE, GMI, 0x31d0, N, N, N),
+ PINGROUP(gmi_cs0_n_pj0, RSVD1, NAND, GMI, USB, RSVD1, 0x31d4, N, N, N),
+ PINGROUP(gmi_cs1_n_pj2, RSVD1, NAND, GMI, SOC, RSVD1, 0x31d8, N, N, N),
+ PINGROUP(gmi_cs2_n_pk3, SDMMC2, NAND, GMI, TRACE, GMI, 0x31dc, N, N, N),
+ PINGROUP(gmi_cs3_n_pk4, SDMMC2, NAND, GMI, GMI_ALT, GMI, 0x31e0, N, N, N),
+ PINGROUP(gmi_cs4_n_pk2, USB, NAND, GMI, TRACE, GMI, 0x31e4, N, N, N),
+ PINGROUP(gmi_cs6_n_pi3, NAND, NAND_ALT, GMI, SPI4, NAND, 0x31e8, N, N, N),
+ PINGROUP(gmi_cs7_n_pi6, NAND, NAND_ALT, GMI, SDMMC2, NAND, 0x31ec, N, N, N),
+ PINGROUP(gmi_ad0_pg0, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31f0, N, N, N),
+ PINGROUP(gmi_ad1_pg1, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31f4, N, N, N),
+ PINGROUP(gmi_ad2_pg2, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31f8, N, N, N),
+ PINGROUP(gmi_ad3_pg3, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x31fc, N, N, N),
+ PINGROUP(gmi_ad4_pg4, RSVD1, NAND, GMI, RSVD4, RSVD4, 0x3200, N, N, N),
+ PINGROUP(gmi_ad5_pg5, RSVD1, NAND, GMI, SPI4, RSVD1, 0x3204, N, N, N),
+ PINGROUP(gmi_ad6_pg6, RSVD1, NAND, GMI, SPI4, RSVD1, 0x3208, N, N, N),
+ PINGROUP(gmi_ad7_pg7, RSVD1, NAND, GMI, SPI4, RSVD1, 0x320c, N, N, N),
+ PINGROUP(gmi_ad8_ph0, PWM0, NAND, GMI, DTV, GMI, 0x3210, N, N, N),
+ PINGROUP(gmi_ad9_ph1, PWM1, NAND, GMI, CLDVFS, GMI, 0x3214, N, N, N),
+ PINGROUP(gmi_ad10_ph2, PWM2, NAND, GMI, CLDVFS, GMI, 0x3218, N, N, N),
+ PINGROUP(gmi_ad11_ph3, PWM3, NAND, GMI, USB, GMI, 0x321c, N, N, N),
+ PINGROUP(gmi_ad12_ph4, SDMMC2, NAND, GMI, RSVD4, RSVD4, 0x3220, N, N, N),
+ PINGROUP(gmi_ad13_ph5, SDMMC2, NAND, GMI, RSVD4, RSVD4, 0x3224, N, N, N),
+ PINGROUP(gmi_ad14_ph6, SDMMC2, NAND, GMI, DTV, GMI, 0x3228, N, N, N),
+ PINGROUP(gmi_ad15_ph7, SDMMC2, NAND, GMI, DTV, GMI, 0x322c, N, N, N),
+ PINGROUP(gmi_a16_pj7, UARTD, TRACE, GMI, GMI_ALT, GMI, 0x3230, N, N, N),
+ PINGROUP(gmi_a17_pb0, UARTD, RSVD2, GMI, TRACE, RSVD2, 0x3234, N, N, N),
+ PINGROUP(gmi_a18_pb1, UARTD, RSVD2, GMI, TRACE, RSVD2, 0x3238, N, N, N),
+ PINGROUP(gmi_a19_pk7, UARTD, SPI4, GMI, TRACE, GMI, 0x323c, N, N, N),
+ PINGROUP(gmi_wr_n_pi0, RSVD1, NAND, GMI, SPI4, RSVD1, 0x3240, N, N, N),
+ PINGROUP(gmi_oe_n_pi1, RSVD1, NAND, GMI, SOC, RSVD1, 0x3244, N, N, N),
+ PINGROUP(gmi_dqs_p_pj3, SDMMC2, NAND, GMI, TRACE, NAND, 0x3248, N, N, N),
+ PINGROUP(gmi_rst_n_pi4, NAND, NAND_ALT, GMI, RSVD4, RSVD4, 0x324c, N, N, N),
+ PINGROUP(gen2_i2c_scl_pt5, I2C2, RSVD2, GMI, RSVD4, RSVD4, 0x3250, Y, N, N),
+ PINGROUP(gen2_i2c_sda_pt6, I2C2, RSVD2, GMI, RSVD4, RSVD4, 0x3254, Y, N, N),
+ PINGROUP(sdmmc4_clk_pcc4, SDMMC4, RSVD2, GMI, RSVD4, RSVD4, 0x3258, N, Y, N),
+ PINGROUP(sdmmc4_cmd_pt7, SDMMC4, RSVD2, GMI, RSVD4, RSVD4, 0x325c, N, Y, N),
+ PINGROUP(sdmmc4_dat0_paa0, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3260, N, Y, N),
+ PINGROUP(sdmmc4_dat1_paa1, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3264, N, Y, N),
+ PINGROUP(sdmmc4_dat2_paa2, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3268, N, Y, N),
+ PINGROUP(sdmmc4_dat3_paa3, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x326c, N, Y, N),
+ PINGROUP(sdmmc4_dat4_paa4, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3270, N, Y, N),
+ PINGROUP(sdmmc4_dat5_paa5, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3274, N, Y, N),
+ PINGROUP(sdmmc4_dat6_paa6, SDMMC4, SPI3, GMI, RSVD4, RSVD4, 0x3278, N, Y, N),
+ PINGROUP(sdmmc4_dat7_paa7, SDMMC4, RSVD2, GMI, RSVD4, RSVD4, 0x327c, N, Y, N),
+ PINGROUP(cam_mclk_pcc0, VI, VI_ALT1, VI_ALT3, RSVD4, RSVD4, 0x3284, N, N, N),
+ PINGROUP(pcc1, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x3288, N, N, N),
+ PINGROUP(pbb0, I2S4, VI, VI_ALT1, VI_ALT3, I2S4, 0x328c, N, N, N),
+ PINGROUP(cam_i2c_scl_pbb1, VGP1, I2C3, RSVD3, RSVD4, RSVD4, 0x3290, Y, N, N),
+ PINGROUP(cam_i2c_sda_pbb2, VGP2, I2C3, RSVD3, RSVD4, RSVD4, 0x3294, Y, N, N),
+ PINGROUP(pbb3, VGP3, DISPLAYA, DISPLAYB, RSVD4, RSVD4, 0x3298, N, N, N),
+ PINGROUP(pbb4, VGP4, DISPLAYA, DISPLAYB, RSVD4, RSVD4, 0x329c, N, N, N),
+ PINGROUP(pbb5, VGP5, DISPLAYA, DISPLAYB, RSVD4, RSVD4, 0x32a0, N, N, N),
+ PINGROUP(pbb6, VGP6, DISPLAYA, DISPLAYB, RSVD4, RSVD4, 0x32a4, N, N, N),
+ PINGROUP(pbb7, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x32a8, N, N, N),
+ PINGROUP(pcc2, I2S4, RSVD2, RSVD3, RSVD4, RSVD4, 0x32ac, N, N, N),
+ PINGROUP(pwr_i2c_scl_pz6, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b4, Y, N, N),
+ PINGROUP(pwr_i2c_sda_pz7, I2CPWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x32b8, Y, N, N),
+ PINGROUP(kb_row0_pr0, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32bc, N, N, N),
+ PINGROUP(kb_row1_pr1, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32c0, N, N, N),
+ PINGROUP(kb_row2_pr2, KBC, RSVD2, RSVD3, RSVD4, RSVD4, 0x32c4, N, N, N),
+ PINGROUP(kb_row3_pr3, KBC, DISPLAYA, RSVD3, DISPLAYB, RSVD3, 0x32c8, N, N, N),
+ PINGROUP(kb_row4_pr4, KBC, DISPLAYA, SPI2, DISPLAYB, KBC, 0x32cc, N, N, N),
+ PINGROUP(kb_row5_pr5, KBC, DISPLAYA, SPI2, DISPLAYB, KBC, 0x32d0, N, N, N),
+ PINGROUP(kb_row6_pr6, KBC, DISPLAYA, DISPLAYA_ALT, DISPLAYB, KBC, 0x32d4, N, N, N),
+ PINGROUP(kb_row7_pr7, KBC, RSVD2, CLDVFS, UARTA, RSVD2, 0x32d8, N, N, N),
+ PINGROUP(kb_row8_ps0, KBC, RSVD2, CLDVFS, UARTA, RSVD2, 0x32dc, N, N, N),
+ PINGROUP(kb_row9_ps1, KBC, RSVD2, RSVD3, UARTA, RSVD3, 0x32e0, N, N, N),
+ PINGROUP(kb_row10_ps2, KBC, RSVD2, RSVD3, UARTA, RSVD3, 0x32e4, N, N, N),
+ PINGROUP(kb_col0_pq0, KBC, USB, SPI2, EMC_DLL, KBC, 0x32fc, N, N, N),
+ PINGROUP(kb_col1_pq1, KBC, RSVD2, SPI2, EMC_DLL, RSVD2, 0x3300, N, N, N),
+ PINGROUP(kb_col2_pq2, KBC, RSVD2, SPI2, RSVD4, RSVD2, 0x3304, N, N, N),
+ PINGROUP(kb_col3_pq3, KBC, DISPLAYA, PWM2, UARTA, KBC, 0x3308, N, N, N),
+ PINGROUP(kb_col4_pq4, KBC, OWR, SDMMC3, UARTA, KBC, 0x330c, N, N, N),
+ PINGROUP(kb_col5_pq5, KBC, RSVD2, SDMMC1, RSVD4, RSVD4, 0x3310, N, N, N),
+ PINGROUP(kb_col6_pq6, KBC, RSVD2, SPI2, RSVD4, RSVD4, 0x3314, N, N, N),
+ PINGROUP(kb_col7_pq7, KBC, RSVD2, SPI2, RSVD4, RSVD4, 0x3318, N, N, N),
+ PINGROUP(clk_32k_out_pa0, BLINK, SOC, RSVD3, RSVD4, RSVD4, 0x331c, N, N, N),
+ PINGROUP(sys_clk_req_pz5, SYSCLK, RSVD2, RSVD3, RSVD4, RSVD4, 0x3320, N, N, N),
+ PINGROUP(core_pwr_req, PWRON, RSVD2, RSVD3, RSVD4, RSVD4, 0x3324, N, N, N),
+ PINGROUP(cpu_pwr_req, CPU, RSVD2, RSVD3, RSVD4, RSVD4, 0x3328, N, N, N),
+ PINGROUP(pwr_int_n, PMI, RSVD2, RSVD3, RSVD4, RSVD4, 0x332c, N, N, N),
+ PINGROUP(owr, OWR, RSVD2, RSVD3, RSVD4, RSVD4, 0x3334, N, N, Y),
+ PINGROUP(dap1_fs_pn0, I2S0, HDA, GMI, RSVD4, RSVD4, 0x3338, N, N, N),
+ PINGROUP(dap1_din_pn1, I2S0, HDA, GMI, RSVD4, RSVD4, 0x333c, N, N, N),
+ PINGROUP(dap1_dout_pn2, I2S0, HDA, GMI, RSVD4, RSVD4, 0x3340, N, N, N),
+ PINGROUP(dap1_sclk_pn3, I2S0, HDA, GMI, RSVD4, RSVD4, 0x3344, N, N, N),
+ PINGROUP(clk1_req_pee2, DAP, DAP1, RSVD3, RSVD4, RSVD4, 0x3348, N, N, N),
+ PINGROUP(clk1_out_pw4, EXTPERIPH1, DAP2, RSVD3, RSVD4, RSVD4, 0x334c, N, N, N),
+ PINGROUP(spdif_in_pk6, SPDIF, USB, RSVD3, RSVD4, RSVD4, 0x3350, N, N, N),
+ PINGROUP(spdif_out_pk5, SPDIF, RSVD2, RSVD3, RSVD4, RSVD4, 0x3354, N, N, N),
+ PINGROUP(dap2_fs_pa2, I2S1, HDA, RSVD3, RSVD4, RSVD4, 0x3358, N, N, N),
+ PINGROUP(dap2_din_pa4, I2S1, HDA, RSVD3, RSVD4, RSVD4, 0x335c, N, N, N),
+ PINGROUP(dap2_dout_pa5, I2S1, HDA, RSVD3, RSVD4, RSVD4, 0x3360, N, N, N),
+ PINGROUP(dap2_sclk_pa3, I2S1, HDA, RSVD3, RSVD4, RSVD4, 0x3364, N, N, N),
+ PINGROUP(dvfs_pwm_px0, SPI6, CLDVFS, RSVD3, RSVD4, RSVD4, 0x3368, N, N, N),
+ PINGROUP(gpio_x1_aud_px1, SPI6, RSVD2, RSVD3, RSVD4, RSVD4, 0x336c, N, N, N),
+ PINGROUP(gpio_x3_aud_px3, SPI6, SPI1, RSVD3, RSVD4, RSVD4, 0x3370, N, N, N),
+ PINGROUP(dvfs_clk_px2, SPI6, CLDVFS, RSVD3, RSVD4, RSVD4, 0x3374, N, N, N),
+ PINGROUP(gpio_x4_aud_px4, RSVD1, SPI1, SPI2, DAP2, RSVD1, 0x3378, N, N, N),
+ PINGROUP(gpio_x5_aud_px5, RSVD1, SPI1, SPI2, RSVD4, RSVD1, 0x337c, N, N, N),
+ PINGROUP(gpio_x6_aud_px6, SPI6, SPI1, SPI2, RSVD4, RSVD4, 0x3380, N, N, N),
+ PINGROUP(gpio_x7_aud_px7, RSVD1, SPI1, SPI2, RSVD4, RSVD4, 0x3384, N, N, N),
+ PINGROUP(sdmmc3_clk_pa6, SDMMC3, RSVD2, RSVD3, SPI3, RSVD3, 0x3390, N, N, N),
+ PINGROUP(sdmmc3_cmd_pa7, SDMMC3, PWM3, UARTA, SPI3, SDMMC3, 0x3394, N, N, N),
+ PINGROUP(sdmmc3_dat0_pb7, SDMMC3, RSVD2, RSVD3, SPI3, RSVD3, 0x3398, N, N, N),
+ PINGROUP(sdmmc3_dat1_pb6, SDMMC3, PWM2, UARTA, SPI3, SDMMC3, 0x339c, N, N, N),
+ PINGROUP(sdmmc3_dat2_pb5, SDMMC3, PWM1, DISPLAYA, SPI3, SDMMC3, 0x33a0, N, N, N),
+ PINGROUP(sdmmc3_dat3_pb4, SDMMC3, PWM0, DISPLAYB, SPI3, SDMMC3, 0x33a4, N, N, N),
+ PINGROUP(hdmi_cec_pee3, CEC, SDMMC3, RSVD3, SOC, RSVD3, 0x33e0, Y, N, N),
+ PINGROUP(sdmmc1_wp_n_pv3, SDMMC1, CLK12, SPI4, UARTA, SDMMC1, 0x33e4, N, N, N),
+ PINGROUP(sdmmc3_cd_n_pv2, SDMMC3, OWR, RSVD3, RSVD4, RSVD4, 0x33e8, N, N, N),
+ PINGROUP(gpio_w2_aud_pw2, SPI6, RSVD2, SPI2, I2C1, RSVD2, 0x33ec, N, N, N),
+ PINGROUP(gpio_w3_aud_pw3, SPI6, SPI1, SPI2, I2C1, SPI6, 0x33f0, N, N, N),
+ PINGROUP(usb_vbus_en0_pn4, USB, RSVD2, RSVD3, RSVD4, RSVD4, 0x33f4, Y, N, N),
+ PINGROUP(usb_vbus_en1_pn5, USB, RSVD2, RSVD3, RSVD4, RSVD4, 0x33f8, Y, N, N),
+ PINGROUP(sdmmc3_clk_lb_in_pee5, SDMMC3, RSVD2, RSVD3, RSVD4, RSVD4, 0x33fc, N, N, N),
+ PINGROUP(sdmmc3_clk_lb_out_pee4, SDMMC3, RSVD2, RSVD3, RSVD4, RSVD4, 0x3400, N, N, N),
+ PINGROUP(reset_out_n, RSVD1, RSVD2, RSVD3, RESET_OUT_N, RSVD3, 0x3408, N, N, N),
+
+ /* pg_name, r, hsm_b, schmitt_b, lpmd_b, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w, drvtype */
+ DRV_PINGROUP(ao1, 0x868, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ao2, 0x86c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(at1, 0x870, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at2, 0x874, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at3, 0x878, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at4, 0x87c, 2, 3, 4, 12, 7, 20, 7, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(at5, 0x880, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(cdev1, 0x884, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(cdev2, 0x888, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap1, 0x890, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap2, 0x894, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap3, 0x898, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dap4, 0x89c, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(dbg, 0x8a0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(sdio3, 0x8b0, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N),
+ DRV_PINGROUP(spi, 0x8b4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uaa, 0x8b8, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uab, 0x8bc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uart2, 0x8c0, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uart3, 0x8c4, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(sdio1, 0x8ec, 2, 3, -1, 12, 7, 20, 7, 28, 2, 30, 2, N),
+ DRV_PINGROUP(ddc, 0x8fc, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gma, 0x900, 2, 3, 4, 14, 5, 20, 5, 28, 2, 30, 2, Y),
+ DRV_PINGROUP(gme, 0x910, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gmf, 0x914, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gmg, 0x918, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(gmh, 0x91c, 2, 3, 4, 14, 5, 19, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(owr, 0x920, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+ DRV_PINGROUP(uda, 0x924, 2, 3, 4, 12, 5, 20, 5, 28, 2, 30, 2, N),
+};
+
+static const struct tegra_pinctrl_soc_data tegra114_pinctrl = {
+ .ngpios = NUM_GPIOS,
+ .pins = tegra114_pins,
+ .npins = ARRAY_SIZE(tegra114_pins),
+ .functions = tegra114_functions,
+ .nfunctions = ARRAY_SIZE(tegra114_functions),
+ .groups = tegra114_groups,
+ .ngroups = ARRAY_SIZE(tegra114_groups),
+};
+
+static int tegra114_pinctrl_probe(struct platform_device *pdev)
+{
+ return tegra_pinctrl_probe(pdev, &tegra114_pinctrl);
+}
+
+static struct of_device_id tegra114_pinctrl_of_match[] = {
+ { .compatible = "nvidia,tegra114-pinmux", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra114_pinctrl_of_match);
+
+static struct platform_driver tegra114_pinctrl_driver = {
+ .driver = {
+ .name = "tegra114-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = tegra114_pinctrl_of_match,
+ },
+ .probe = tegra114_pinctrl_probe,
+ .remove = tegra_pinctrl_remove,
+};
+module_platform_driver(tegra114_pinctrl_driver);
+
+MODULE_ALIAS("platform:tegra114-pinctrl");
+MODULE_AUTHOR("Pritesh Raithatha <praithatha@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra114 pincontrol driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c
index e848189038f0..fcfb7d012c5b 100644
--- a/drivers/pinctrl/pinctrl-tegra20.c
+++ b/drivers/pinctrl/pinctrl-tegra20.c
@@ -2624,7 +2624,9 @@ static const struct tegra_function tegra20_functions[] = {
.odrain_reg = -1, \
.lock_reg = -1, \
.ioreset_reg = -1, \
+ .rcv_sel_reg = -1, \
.drv_reg = -1, \
+ .drvtype_reg = -1, \
}
/* Pin groups with only pull up and pull down control */
@@ -2642,7 +2644,9 @@ static const struct tegra_function tegra20_functions[] = {
.odrain_reg = -1, \
.lock_reg = -1, \
.ioreset_reg = -1, \
+ .rcv_sel_reg = -1, \
.drv_reg = -1, \
+ .drvtype_reg = -1, \
}
/* Pin groups for drive strength registers (configurable version) */
@@ -2660,6 +2664,7 @@ static const struct tegra_function tegra20_functions[] = {
.odrain_reg = -1, \
.lock_reg = -1, \
.ioreset_reg = -1, \
+ .rcv_sel_reg = -1, \
.drv_reg = ((r) - PINGROUP_REG_A), \
.drv_bank = 3, \
.hsm_bit = hsm_b, \
@@ -2673,6 +2678,7 @@ static const struct tegra_function tegra20_functions[] = {
.slwr_width = slwr_w, \
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
+ .drvtype_reg = -1, \
}
/* Pin groups for drive strength registers (simple version) */
diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c
index 9ad87ea735d4..2300deba25bd 100644
--- a/drivers/pinctrl/pinctrl-tegra30.c
+++ b/drivers/pinctrl/pinctrl-tegra30.c
@@ -3384,7 +3384,9 @@ static const struct tegra_function tegra30_functions[] = {
.ioreset_reg = PINGROUP_REG_##ior(r), \
.ioreset_bank = 1, \
.ioreset_bit = 8, \
+ .rcv_sel_reg = -1, \
.drv_reg = -1, \
+ .drvtype_reg = -1, \
}
#define DRV_PINGROUP(pg_name, r, hsm_b, schmitt_b, lpmd_b, \
@@ -3401,6 +3403,7 @@ static const struct tegra_function tegra30_functions[] = {
.odrain_reg = -1, \
.lock_reg = -1, \
.ioreset_reg = -1, \
+ .rcv_sel_reg = -1, \
.drv_reg = ((r) - DRV_PINGROUP_REG_A), \
.drv_bank = 0, \
.hsm_bit = hsm_b, \
@@ -3414,6 +3417,7 @@ static const struct tegra_function tegra30_functions[] = {
.slwr_width = slwr_w, \
.slwf_bit = slwf_b, \
.slwf_width = slwf_w, \
+ .drvtype_reg = -1, \
}
static const struct tegra_pingroup tegra30_groups[] = {
diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
index 718ec5762683..2b5772550836 100644
--- a/drivers/pinctrl/pinctrl-u300.c
+++ b/drivers/pinctrl/pinctrl-u300.c
@@ -1078,9 +1078,9 @@ static int u300_pmx_probe(struct platform_device *pdev)
if (!res)
return -ENOENT;
- upmx->virtbase = devm_request_and_ioremap(&pdev->dev, res);
- if (!upmx->virtbase)
- return -ENOMEM;
+ upmx->virtbase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(upmx->virtbase))
+ return PTR_ERR(upmx->virtbase);
upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx);
if (!upmx->pctl) {
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index 5f0eb04c2336..068224efa6fa 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -9,6 +9,7 @@
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
*/
+#include <linux/err.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of_platform.h>
@@ -441,17 +442,17 @@ static int xway_pinconf_get(struct pinctrl_dev *pctldev,
if (port == PORT3)
reg = GPIO3_OD;
else
- reg = GPIO_OD(port);
+ reg = GPIO_OD(pin);
*config = LTQ_PINCONF_PACK(param,
- !!gpio_getbit(info->membase[0], reg, PORT_PIN(port)));
+ !gpio_getbit(info->membase[0], reg, PORT_PIN(pin)));
break;
case LTQ_PINCONF_PARAM_PULL:
if (port == PORT3)
reg = GPIO3_PUDEN;
else
- reg = GPIO_PUDEN(port);
- if (!gpio_getbit(info->membase[0], reg, PORT_PIN(port))) {
+ reg = GPIO_PUDEN(pin);
+ if (!gpio_getbit(info->membase[0], reg, PORT_PIN(pin))) {
*config = LTQ_PINCONF_PACK(param, 0);
break;
}
@@ -459,13 +460,18 @@ static int xway_pinconf_get(struct pinctrl_dev *pctldev,
if (port == PORT3)
reg = GPIO3_PUDSEL;
else
- reg = GPIO_PUDSEL(port);
- if (!gpio_getbit(info->membase[0], reg, PORT_PIN(port)))
+ reg = GPIO_PUDSEL(pin);
+ if (!gpio_getbit(info->membase[0], reg, PORT_PIN(pin)))
*config = LTQ_PINCONF_PACK(param, 2);
else
*config = LTQ_PINCONF_PACK(param, 1);
break;
+ case LTQ_PINCONF_PARAM_OUTPUT:
+ reg = GPIO_DIR(pin);
+ *config = LTQ_PINCONF_PACK(param,
+ gpio_getbit(info->membase[0], reg, PORT_PIN(pin)));
+ break;
default:
dev_err(pctldev->dev, "Invalid config param %04x\n", param);
return -ENOTSUPP;
@@ -488,33 +494,44 @@ static int xway_pinconf_set(struct pinctrl_dev *pctldev,
if (port == PORT3)
reg = GPIO3_OD;
else
- reg = GPIO_OD(port);
- gpio_setbit(info->membase[0], reg, PORT_PIN(port));
+ reg = GPIO_OD(pin);
+ if (arg == 0)
+ gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
+ else
+ gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
break;
case LTQ_PINCONF_PARAM_PULL:
if (port == PORT3)
reg = GPIO3_PUDEN;
else
- reg = GPIO_PUDEN(port);
+ reg = GPIO_PUDEN(pin);
if (arg == 0) {
- gpio_clearbit(info->membase[0], reg, PORT_PIN(port));
+ gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
break;
}
- gpio_setbit(info->membase[0], reg, PORT_PIN(port));
+ gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
if (port == PORT3)
reg = GPIO3_PUDSEL;
else
- reg = GPIO_PUDSEL(port);
+ reg = GPIO_PUDSEL(pin);
if (arg == 1)
- gpio_clearbit(info->membase[0], reg, PORT_PIN(port));
+ gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
else if (arg == 2)
- gpio_setbit(info->membase[0], reg, PORT_PIN(port));
+ gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
else
dev_err(pctldev->dev, "Invalid pull value %d\n", arg);
break;
+ case LTQ_PINCONF_PARAM_OUTPUT:
+ reg = GPIO_DIR(pin);
+ if (arg == 0)
+ gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
+ else
+ gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
+ break;
+
default:
dev_err(pctldev->dev, "Invalid config param %04x\n", param);
return -ENOTSUPP;
@@ -522,9 +539,24 @@ static int xway_pinconf_set(struct pinctrl_dev *pctldev,
return 0;
}
+int xway_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned selector,
+ unsigned long config)
+{
+ struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
+ int i, ret = 0;
+
+ for (i = 0; i < info->grps[selector].npins && !ret; i++)
+ ret = xway_pinconf_set(pctldev,
+ info->grps[selector].pins[i], config);
+
+ return ret;
+}
+
static struct pinconf_ops xway_pinconf_ops = {
.pin_config_get = xway_pinconf_get,
.pin_config_set = xway_pinconf_set,
+ .pin_config_group_set = xway_pinconf_group_set,
};
static struct pinctrl_desc xway_pctrl_desc = {
@@ -558,6 +590,7 @@ static inline int xway_mux_apply(struct pinctrl_dev *pctrldev,
static const struct ltq_cfg_param xway_cfg_params[] = {
{"lantiq,pull", LTQ_PINCONF_PARAM_PULL},
{"lantiq,open-drain", LTQ_PINCONF_PARAM_OPEN_DRAIN},
+ {"lantiq,output", LTQ_PINCONF_PARAM_OUTPUT},
};
static struct ltq_pinmux_info xway_info = {
@@ -687,11 +720,9 @@ static int pinmux_xway_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Failed to get resource\n");
return -ENOENT;
}
- xway_info.membase[0] = devm_request_and_ioremap(&pdev->dev, res);
- if (!xway_info.membase[0]) {
- dev_err(&pdev->dev, "Failed to remap resource\n");
- return -ENOMEM;
- }
+ xway_info.membase[0] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(xway_info.membase[0]))
+ return PTR_ERR(xway_info.membase[0]);
match = of_match_device(xway_match, &pdev->dev);
if (match)
diff --git a/drivers/pinctrl/sh-pfc/Kconfig b/drivers/pinctrl/sh-pfc/Kconfig
new file mode 100644
index 000000000000..c3340f54d2ad
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/Kconfig
@@ -0,0 +1,116 @@
+#
+# Renesas SH and SH Mobile PINCTRL drivers
+#
+
+if ARCH_SHMOBILE || SUPERH
+
+config PINCTRL_SH_PFC
+ # XXX move off the gpio dependency
+ depends on GENERIC_GPIO
+ select GPIO_SH_PFC if ARCH_REQUIRE_GPIOLIB
+ select PINMUX
+ select PINCONF
+ def_bool y
+ help
+ This enables pin control drivers for SH and SH Mobile platforms
+
+config GPIO_SH_PFC
+ bool "SuperH PFC GPIO support"
+ depends on PINCTRL_SH_PFC && GPIOLIB
+ help
+ This enables support for GPIOs within the SoC's pin function
+ controller.
+
+config PINCTRL_PFC_R8A7740
+ def_bool y
+ depends on ARCH_R8A7740
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A7779
+ def_bool y
+ depends on ARCH_R8A7779
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7203
+ def_bool y
+ depends on CPU_SUBTYPE_SH7203
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7264
+ def_bool y
+ depends on CPU_SUBTYPE_SH7264
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7269
+ def_bool y
+ depends on CPU_SUBTYPE_SH7269
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7372
+ def_bool y
+ depends on ARCH_SH7372
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH73A0
+ def_bool y
+ depends on ARCH_SH73A0
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7720
+ def_bool y
+ depends on CPU_SUBTYPE_SH7720
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7722
+ def_bool y
+ depends on CPU_SUBTYPE_SH7722
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7723
+ def_bool y
+ depends on CPU_SUBTYPE_SH7723
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7724
+ def_bool y
+ depends on CPU_SUBTYPE_SH7724
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7734
+ def_bool y
+ depends on CPU_SUBTYPE_SH7734
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7757
+ def_bool y
+ depends on CPU_SUBTYPE_SH7757
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7785
+ def_bool y
+ depends on CPU_SUBTYPE_SH7785
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SH7786
+ def_bool y
+ depends on CPU_SUBTYPE_SH7786
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_SHX3
+ def_bool y
+ depends on CPU_SUBTYPE_SHX3
+ depends on GENERIC_GPIO
+ select PINCTRL_SH_PFC
+
+endif
diff --git a/drivers/pinctrl/sh-pfc/Makefile b/drivers/pinctrl/sh-pfc/Makefile
new file mode 100644
index 000000000000..e8b9562c47e1
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/Makefile
@@ -0,0 +1,21 @@
+sh-pfc-objs = core.o pinctrl.o
+ifeq ($(CONFIG_GPIO_SH_PFC),y)
+sh-pfc-objs += gpio.o
+endif
+obj-$(CONFIG_PINCTRL_SH_PFC) += sh-pfc.o
+obj-$(CONFIG_PINCTRL_PFC_R8A7740) += pfc-r8a7740.o
+obj-$(CONFIG_PINCTRL_PFC_R8A7779) += pfc-r8a7779.o
+obj-$(CONFIG_PINCTRL_PFC_SH7203) += pfc-sh7203.o
+obj-$(CONFIG_PINCTRL_PFC_SH7264) += pfc-sh7264.o
+obj-$(CONFIG_PINCTRL_PFC_SH7269) += pfc-sh7269.o
+obj-$(CONFIG_PINCTRL_PFC_SH7372) += pfc-sh7372.o
+obj-$(CONFIG_PINCTRL_PFC_SH73A0) += pfc-sh73a0.o
+obj-$(CONFIG_PINCTRL_PFC_SH7720) += pfc-sh7720.o
+obj-$(CONFIG_PINCTRL_PFC_SH7722) += pfc-sh7722.o
+obj-$(CONFIG_PINCTRL_PFC_SH7723) += pfc-sh7723.o
+obj-$(CONFIG_PINCTRL_PFC_SH7724) += pfc-sh7724.o
+obj-$(CONFIG_PINCTRL_PFC_SH7734) += pfc-sh7734.o
+obj-$(CONFIG_PINCTRL_PFC_SH7757) += pfc-sh7757.o
+obj-$(CONFIG_PINCTRL_PFC_SH7785) += pfc-sh7785.o
+obj-$(CONFIG_PINCTRL_PFC_SH7786) += pfc-sh7786.o
+obj-$(CONFIG_PINCTRL_PFC_SHX3) += pfc-shx3.o
diff --git a/drivers/sh/pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index 68169373c98b..970ddff2b0b6 100644
--- a/drivers/sh/pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -8,78 +8,61 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-#define pr_fmt(fmt) "sh_pfc " KBUILD_MODNAME ": " fmt
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sh_pfc.h>
-#include <linux/module.h>
+#define DRV_NAME "sh-pfc"
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
#include <linux/err.h>
+#include <linux/errno.h>
#include <linux/io.h>
-#include <linux/bitops.h>
-#include <linux/slab.h>
#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pinctrl/machine.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
-static struct sh_pfc *sh_pfc __read_mostly;
-
-static inline bool sh_pfc_initialized(void)
-{
- return !!sh_pfc;
-}
-
-static void pfc_iounmap(struct sh_pfc *pfc)
-{
- int k;
-
- for (k = 0; k < pfc->num_resources; k++)
- if (pfc->window[k].virt)
- iounmap(pfc->window[k].virt);
-
- kfree(pfc->window);
- pfc->window = NULL;
-}
+#include "core.h"
-static int pfc_ioremap(struct sh_pfc *pfc)
+static int sh_pfc_ioremap(struct sh_pfc *pfc, struct platform_device *pdev)
{
struct resource *res;
int k;
- if (!pfc->num_resources)
+ if (pdev->num_resources == 0) {
+ pfc->num_windows = 0;
return 0;
+ }
- pfc->window = kzalloc(pfc->num_resources * sizeof(*pfc->window),
- GFP_NOWAIT);
+ pfc->window = devm_kzalloc(pfc->dev, pdev->num_resources *
+ sizeof(*pfc->window), GFP_NOWAIT);
if (!pfc->window)
- goto err1;
+ return -ENOMEM;
- for (k = 0; k < pfc->num_resources; k++) {
- res = pfc->resource + k;
+ pfc->num_windows = pdev->num_resources;
+
+ for (k = 0, res = pdev->resource; k < pdev->num_resources; k++, res++) {
WARN_ON(resource_type(res) != IORESOURCE_MEM);
pfc->window[k].phys = res->start;
pfc->window[k].size = resource_size(res);
- pfc->window[k].virt = ioremap_nocache(res->start,
- resource_size(res));
+ pfc->window[k].virt = devm_ioremap_nocache(pfc->dev, res->start,
+ resource_size(res));
if (!pfc->window[k].virt)
- goto err2;
+ return -ENOMEM;
}
return 0;
-
-err2:
- pfc_iounmap(pfc);
-err1:
- return -1;
}
-static void __iomem *pfc_phys_to_virt(struct sh_pfc *pfc,
- unsigned long address)
+static void __iomem *sh_pfc_phys_to_virt(struct sh_pfc *pfc,
+ unsigned long address)
{
- struct pfc_window *window;
+ struct sh_pfc_window *window;
int k;
/* scan through physical windows and convert address */
- for (k = 0; k < pfc->num_resources; k++) {
+ for (k = 0; k < pfc->num_windows; k++) {
window = pfc->window + k;
if (address < window->phys)
@@ -95,7 +78,7 @@ static void __iomem *pfc_phys_to_virt(struct sh_pfc *pfc,
return (void __iomem *)address;
}
-static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
+static int sh_pfc_enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
{
if (enum_id < r->begin)
return 0;
@@ -106,8 +89,8 @@ static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
return 1;
}
-static unsigned long gpio_read_raw_reg(void __iomem *mapped_reg,
- unsigned long reg_width)
+static unsigned long sh_pfc_read_raw_reg(void __iomem *mapped_reg,
+ unsigned long reg_width)
{
switch (reg_width) {
case 8:
@@ -122,9 +105,8 @@ static unsigned long gpio_read_raw_reg(void __iomem *mapped_reg,
return 0;
}
-static void gpio_write_raw_reg(void __iomem *mapped_reg,
- unsigned long reg_width,
- unsigned long data)
+static void sh_pfc_write_raw_reg(void __iomem *mapped_reg,
+ unsigned long reg_width, unsigned long data)
{
switch (reg_width) {
case 8:
@@ -150,9 +132,8 @@ int sh_pfc_read_bit(struct pinmux_data_reg *dr, unsigned long in_pos)
pr_debug("read_bit: addr = %lx, pos = %ld, "
"r_width = %ld\n", dr->reg, pos, dr->reg_width);
- return (gpio_read_raw_reg(dr->mapped_reg, dr->reg_width) >> pos) & 1;
+ return (sh_pfc_read_raw_reg(dr->mapped_reg, dr->reg_width) >> pos) & 1;
}
-EXPORT_SYMBOL_GPL(sh_pfc_read_bit);
void sh_pfc_write_bit(struct pinmux_data_reg *dr, unsigned long in_pos,
unsigned long value)
@@ -170,20 +151,19 @@ void sh_pfc_write_bit(struct pinmux_data_reg *dr, unsigned long in_pos,
else
clear_bit(pos, &dr->reg_shadow);
- gpio_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow);
+ sh_pfc_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow);
}
-EXPORT_SYMBOL_GPL(sh_pfc_write_bit);
-
-static void config_reg_helper(struct sh_pfc *pfc,
- struct pinmux_cfg_reg *crp,
- unsigned long in_pos,
- void __iomem **mapped_regp,
- unsigned long *maskp,
- unsigned long *posp)
+
+static void sh_pfc_config_reg_helper(struct sh_pfc *pfc,
+ struct pinmux_cfg_reg *crp,
+ unsigned long in_pos,
+ void __iomem **mapped_regp,
+ unsigned long *maskp,
+ unsigned long *posp)
{
int k;
- *mapped_regp = pfc_phys_to_virt(pfc, crp->reg);
+ *mapped_regp = sh_pfc_phys_to_virt(pfc, crp->reg);
if (crp->field_width) {
*maskp = (1 << crp->field_width) - 1;
@@ -196,30 +176,30 @@ static void config_reg_helper(struct sh_pfc *pfc,
}
}
-static int read_config_reg(struct sh_pfc *pfc,
- struct pinmux_cfg_reg *crp,
- unsigned long field)
+static int sh_pfc_read_config_reg(struct sh_pfc *pfc,
+ struct pinmux_cfg_reg *crp,
+ unsigned long field)
{
void __iomem *mapped_reg;
unsigned long mask, pos;
- config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
+ sh_pfc_config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
pr_debug("read_reg: addr = %lx, field = %ld, "
"r_width = %ld, f_width = %ld\n",
crp->reg, field, crp->reg_width, crp->field_width);
- return (gpio_read_raw_reg(mapped_reg, crp->reg_width) >> pos) & mask;
+ return (sh_pfc_read_raw_reg(mapped_reg, crp->reg_width) >> pos) & mask;
}
-static void write_config_reg(struct sh_pfc *pfc,
- struct pinmux_cfg_reg *crp,
- unsigned long field, unsigned long value)
+static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
+ struct pinmux_cfg_reg *crp,
+ unsigned long field, unsigned long value)
{
void __iomem *mapped_reg;
unsigned long mask, pos, data;
- config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
+ sh_pfc_config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
pr_debug("write_reg addr = %lx, value = %ld, field = %ld, "
"r_width = %ld, f_width = %ld\n",
@@ -228,34 +208,35 @@ static void write_config_reg(struct sh_pfc *pfc,
mask = ~(mask << pos);
value = value << pos;
- data = gpio_read_raw_reg(mapped_reg, crp->reg_width);
+ data = sh_pfc_read_raw_reg(mapped_reg, crp->reg_width);
data &= mask;
data |= value;
- if (pfc->unlock_reg)
- gpio_write_raw_reg(pfc_phys_to_virt(pfc, pfc->unlock_reg),
- 32, ~data);
+ if (pfc->info->unlock_reg)
+ sh_pfc_write_raw_reg(
+ sh_pfc_phys_to_virt(pfc, pfc->info->unlock_reg), 32,
+ ~data);
- gpio_write_raw_reg(mapped_reg, crp->reg_width, data);
+ sh_pfc_write_raw_reg(mapped_reg, crp->reg_width, data);
}
-static int setup_data_reg(struct sh_pfc *pfc, unsigned gpio)
+static int sh_pfc_setup_data_reg(struct sh_pfc *pfc, unsigned gpio)
{
- struct pinmux_gpio *gpiop = &pfc->gpios[gpio];
+ struct pinmux_gpio *gpiop = &pfc->info->gpios[gpio];
struct pinmux_data_reg *data_reg;
int k, n;
- if (!enum_in_range(gpiop->enum_id, &pfc->data))
+ if (!sh_pfc_enum_in_range(gpiop->enum_id, &pfc->info->data))
return -1;
k = 0;
while (1) {
- data_reg = pfc->data_regs + k;
+ data_reg = pfc->info->data_regs + k;
if (!data_reg->reg_width)
break;
- data_reg->mapped_reg = pfc_phys_to_virt(pfc, data_reg->reg);
+ data_reg->mapped_reg = sh_pfc_phys_to_virt(pfc, data_reg->reg);
for (n = 0; n < data_reg->reg_width; n++) {
if (data_reg->enum_ids[n] == gpiop->enum_id) {
@@ -274,23 +255,23 @@ static int setup_data_reg(struct sh_pfc *pfc, unsigned gpio)
return -1;
}
-static void setup_data_regs(struct sh_pfc *pfc)
+static void sh_pfc_setup_data_regs(struct sh_pfc *pfc)
{
struct pinmux_data_reg *drp;
int k;
- for (k = pfc->first_gpio; k <= pfc->last_gpio; k++)
- setup_data_reg(pfc, k);
+ for (k = pfc->info->first_gpio; k <= pfc->info->last_gpio; k++)
+ sh_pfc_setup_data_reg(pfc, k);
k = 0;
while (1) {
- drp = pfc->data_regs + k;
+ drp = pfc->info->data_regs + k;
if (!drp->reg_width)
break;
- drp->reg_shadow = gpio_read_raw_reg(drp->mapped_reg,
- drp->reg_width);
+ drp->reg_shadow = sh_pfc_read_raw_reg(drp->mapped_reg,
+ drp->reg_width);
k++;
}
}
@@ -298,24 +279,22 @@ static void setup_data_regs(struct sh_pfc *pfc)
int sh_pfc_get_data_reg(struct sh_pfc *pfc, unsigned gpio,
struct pinmux_data_reg **drp, int *bitp)
{
- struct pinmux_gpio *gpiop = &pfc->gpios[gpio];
+ struct pinmux_gpio *gpiop = &pfc->info->gpios[gpio];
int k, n;
- if (!enum_in_range(gpiop->enum_id, &pfc->data))
+ if (!sh_pfc_enum_in_range(gpiop->enum_id, &pfc->info->data))
return -1;
k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT;
n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT;
- *drp = pfc->data_regs + k;
+ *drp = pfc->info->data_regs + k;
*bitp = n;
return 0;
}
-EXPORT_SYMBOL_GPL(sh_pfc_get_data_reg);
-static int get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id,
- struct pinmux_cfg_reg **crp,
- int *fieldp, int *valuep,
- unsigned long **cntp)
+static int sh_pfc_get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id,
+ struct pinmux_cfg_reg **crp, int *fieldp,
+ int *valuep, unsigned long **cntp)
{
struct pinmux_cfg_reg *config_reg;
unsigned long r_width, f_width, curr_width, ncomb;
@@ -323,7 +302,7 @@ static int get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id,
k = 0;
while (1) {
- config_reg = pfc->cfg_regs + k;
+ config_reg = pfc->info->cfg_regs + k;
r_width = config_reg->reg_width;
f_width = config_reg->field_width;
@@ -361,12 +340,12 @@ static int get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id,
int sh_pfc_gpio_to_enum(struct sh_pfc *pfc, unsigned gpio, int pos,
pinmux_enum_t *enum_idp)
{
- pinmux_enum_t enum_id = pfc->gpios[gpio].enum_id;
- pinmux_enum_t *data = pfc->gpio_data;
+ pinmux_enum_t enum_id = pfc->info->gpios[gpio].enum_id;
+ pinmux_enum_t *data = pfc->info->gpio_data;
int k;
- if (!enum_in_range(enum_id, &pfc->data)) {
- if (!enum_in_range(enum_id, &pfc->mark)) {
+ if (!sh_pfc_enum_in_range(enum_id, &pfc->info->data)) {
+ if (!sh_pfc_enum_in_range(enum_id, &pfc->info->mark)) {
pr_err("non data/mark enum_id for gpio %d\n", gpio);
return -1;
}
@@ -377,7 +356,7 @@ int sh_pfc_gpio_to_enum(struct sh_pfc *pfc, unsigned gpio, int pos,
return pos + 1;
}
- for (k = 0; k < pfc->gpio_data_size; k++) {
+ for (k = 0; k < pfc->info->gpio_data_size; k++) {
if (data[k] == enum_id) {
*enum_idp = data[k + 1];
return k + 1;
@@ -387,7 +366,6 @@ int sh_pfc_gpio_to_enum(struct sh_pfc *pfc, unsigned gpio, int pos,
pr_err("cannot locate data/mark enum_id for gpio %d\n", gpio);
return -1;
}
-EXPORT_SYMBOL_GPL(sh_pfc_gpio_to_enum);
int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
int cfg_mode)
@@ -405,19 +383,19 @@ int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
break;
case PINMUX_TYPE_OUTPUT:
- range = &pfc->output;
+ range = &pfc->info->output;
break;
case PINMUX_TYPE_INPUT:
- range = &pfc->input;
+ range = &pfc->info->input;
break;
case PINMUX_TYPE_INPUT_PULLUP:
- range = &pfc->input_pu;
+ range = &pfc->info->input_pu;
break;
case PINMUX_TYPE_INPUT_PULLDOWN:
- range = &pfc->input_pd;
+ range = &pfc->info->input_pd;
break;
default:
@@ -437,7 +415,7 @@ int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
break;
/* first check if this is a function enum */
- in_range = enum_in_range(enum_id, &pfc->function);
+ in_range = sh_pfc_enum_in_range(enum_id, &pfc->info->function);
if (!in_range) {
/* not a function enum */
if (range) {
@@ -449,7 +427,7 @@ int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
* for this case we only allow function enums
* and the enums that match the other range.
*/
- in_range = enum_in_range(enum_id, range);
+ in_range = sh_pfc_enum_in_range(enum_id, range);
/*
* special case pass through for fixed
@@ -474,19 +452,19 @@ int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
if (!in_range)
continue;
- if (get_config_reg(pfc, enum_id, &cr,
- &field, &value, &cntp) != 0)
+ if (sh_pfc_get_config_reg(pfc, enum_id, &cr,
+ &field, &value, &cntp) != 0)
goto out_err;
switch (cfg_mode) {
case GPIO_CFG_DRYRUN:
if (!*cntp ||
- (read_config_reg(pfc, cr, field) != value))
+ (sh_pfc_read_config_reg(pfc, cr, field) != value))
continue;
break;
case GPIO_CFG_REQ:
- write_config_reg(pfc, cr, field, value);
+ sh_pfc_write_config_reg(pfc, cr, field, value);
*cntp = *cntp + 1;
break;
@@ -500,11 +478,11 @@ int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
out_err:
return -1;
}
-EXPORT_SYMBOL_GPL(sh_pfc_config_gpio);
-int register_sh_pfc(struct sh_pfc *pfc)
+static int sh_pfc_probe(struct platform_device *pdev)
{
- int (*initroutine)(struct sh_pfc *) = NULL;
+ struct sh_pfc_soc_info *info;
+ struct sh_pfc *pfc;
int ret;
/*
@@ -512,61 +490,146 @@ int register_sh_pfc(struct sh_pfc *pfc)
*/
BUILD_BUG_ON(PINMUX_FLAG_TYPE > ((1 << PINMUX_FLAG_DBIT_SHIFT) - 1));
- if (sh_pfc)
- return -EBUSY;
+ info = pdev->id_entry->driver_data
+ ? (void *)pdev->id_entry->driver_data : pdev->dev.platform_data;
+ if (info == NULL)
+ return -ENODEV;
+
+ pfc = devm_kzalloc(&pdev->dev, sizeof(*pfc), GFP_KERNEL);
+ if (pfc == NULL)
+ return -ENOMEM;
+
+ pfc->info = info;
+ pfc->dev = &pdev->dev;
- ret = pfc_ioremap(pfc);
+ ret = sh_pfc_ioremap(pfc, pdev);
if (unlikely(ret < 0))
return ret;
spin_lock_init(&pfc->lock);
pinctrl_provide_dummies();
- setup_data_regs(pfc);
-
- sh_pfc = pfc;
+ sh_pfc_setup_data_regs(pfc);
/*
* Initialize pinctrl bindings first
*/
- initroutine = symbol_request(sh_pfc_register_pinctrl);
- if (initroutine) {
- ret = (*initroutine)(pfc);
- symbol_put_addr(initroutine);
-
- if (unlikely(ret != 0))
- goto err;
- } else {
- pr_err("failed to initialize pinctrl bindings\n");
- goto err;
- }
+ ret = sh_pfc_register_pinctrl(pfc);
+ if (unlikely(ret != 0))
+ return ret;
+#ifdef CONFIG_GPIO_SH_PFC
/*
* Then the GPIO chip
*/
- initroutine = symbol_request(sh_pfc_register_gpiochip);
- if (initroutine) {
- ret = (*initroutine)(pfc);
- symbol_put_addr(initroutine);
-
+ ret = sh_pfc_register_gpiochip(pfc);
+ if (unlikely(ret != 0)) {
/*
* If the GPIO chip fails to come up we still leave the
* PFC state as it is, given that there are already
* extant users of it that have succeeded by this point.
*/
- if (unlikely(ret != 0)) {
- pr_notice("failed to init GPIO chip, ignoring...\n");
- ret = 0;
- }
+ pr_notice("failed to init GPIO chip, ignoring...\n");
}
+#endif
+
+ platform_set_drvdata(pdev, pfc);
- pr_info("%s support registered\n", pfc->name);
+ pr_info("%s support registered\n", info->name);
return 0;
+}
-err:
- pfc_iounmap(pfc);
- sh_pfc = NULL;
+static int sh_pfc_remove(struct platform_device *pdev)
+{
+ struct sh_pfc *pfc = platform_get_drvdata(pdev);
+
+#ifdef CONFIG_GPIO_SH_PFC
+ sh_pfc_unregister_gpiochip(pfc);
+#endif
+ sh_pfc_unregister_pinctrl(pfc);
+
+ platform_set_drvdata(pdev, NULL);
- return ret;
+ return 0;
}
+
+static const struct platform_device_id sh_pfc_id_table[] = {
+#ifdef CONFIG_PINCTRL_PFC_R8A7740
+ { "pfc-r8a7740", (kernel_ulong_t)&r8a7740_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A7779
+ { "pfc-r8a7779", (kernel_ulong_t)&r8a7779_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7203
+ { "pfc-sh7203", (kernel_ulong_t)&sh7203_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7264
+ { "pfc-sh7264", (kernel_ulong_t)&sh7264_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7269
+ { "pfc-sh7269", (kernel_ulong_t)&sh7269_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7372
+ { "pfc-sh7372", (kernel_ulong_t)&sh7372_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH73A0
+ { "pfc-sh73a0", (kernel_ulong_t)&sh73a0_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7720
+ { "pfc-sh7720", (kernel_ulong_t)&sh7720_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7722
+ { "pfc-sh7722", (kernel_ulong_t)&sh7722_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7723
+ { "pfc-sh7723", (kernel_ulong_t)&sh7723_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7724
+ { "pfc-sh7724", (kernel_ulong_t)&sh7724_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7734
+ { "pfc-sh7734", (kernel_ulong_t)&sh7734_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7757
+ { "pfc-sh7757", (kernel_ulong_t)&sh7757_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7785
+ { "pfc-sh7785", (kernel_ulong_t)&sh7785_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7786
+ { "pfc-sh7786", (kernel_ulong_t)&sh7786_pinmux_info },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SHX3
+ { "pfc-shx3", (kernel_ulong_t)&shx3_pinmux_info },
+#endif
+ { "sh-pfc", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, sh_pfc_id_table);
+
+static struct platform_driver sh_pfc_driver = {
+ .probe = sh_pfc_probe,
+ .remove = sh_pfc_remove,
+ .id_table = sh_pfc_id_table,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sh_pfc_init(void)
+{
+ return platform_driver_register(&sh_pfc_driver);
+}
+postcore_initcall(sh_pfc_init);
+
+static void __exit sh_pfc_exit(void)
+{
+ platform_driver_unregister(&sh_pfc_driver);
+}
+module_exit(sh_pfc_exit);
+
+MODULE_AUTHOR("Magnus Damm, Paul Mundt, Laurent Pinchart");
+MODULE_DESCRIPTION("Pin Control and GPIO driver for SuperH pin function controller");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h
new file mode 100644
index 000000000000..ba7c33c33599
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/core.h
@@ -0,0 +1,72 @@
+/*
+ * SuperH Pin Function Controller support.
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * 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 __SH_PFC_CORE_H__
+#define __SH_PFC_CORE_H__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#include "sh_pfc.h"
+
+struct sh_pfc_window {
+ phys_addr_t phys;
+ void __iomem *virt;
+ unsigned long size;
+};
+
+struct sh_pfc_chip;
+struct sh_pfc_pinctrl;
+
+struct sh_pfc {
+ struct device *dev;
+ struct sh_pfc_soc_info *info;
+ spinlock_t lock;
+
+ unsigned int num_windows;
+ struct sh_pfc_window *window;
+
+ struct sh_pfc_chip *gpio;
+ struct sh_pfc_pinctrl *pinctrl;
+};
+
+int sh_pfc_register_gpiochip(struct sh_pfc *pfc);
+int sh_pfc_unregister_gpiochip(struct sh_pfc *pfc);
+
+int sh_pfc_register_pinctrl(struct sh_pfc *pfc);
+int sh_pfc_unregister_pinctrl(struct sh_pfc *pfc);
+
+int sh_pfc_read_bit(struct pinmux_data_reg *dr, unsigned long in_pos);
+void sh_pfc_write_bit(struct pinmux_data_reg *dr, unsigned long in_pos,
+ unsigned long value);
+int sh_pfc_get_data_reg(struct sh_pfc *pfc, unsigned gpio,
+ struct pinmux_data_reg **drp, int *bitp);
+int sh_pfc_gpio_to_enum(struct sh_pfc *pfc, unsigned gpio, int pos,
+ pinmux_enum_t *enum_idp);
+int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
+ int cfg_mode);
+
+extern struct sh_pfc_soc_info r8a7740_pinmux_info;
+extern struct sh_pfc_soc_info r8a7779_pinmux_info;
+extern struct sh_pfc_soc_info sh7203_pinmux_info;
+extern struct sh_pfc_soc_info sh7264_pinmux_info;
+extern struct sh_pfc_soc_info sh7269_pinmux_info;
+extern struct sh_pfc_soc_info sh7372_pinmux_info;
+extern struct sh_pfc_soc_info sh73a0_pinmux_info;
+extern struct sh_pfc_soc_info sh7720_pinmux_info;
+extern struct sh_pfc_soc_info sh7722_pinmux_info;
+extern struct sh_pfc_soc_info sh7723_pinmux_info;
+extern struct sh_pfc_soc_info sh7724_pinmux_info;
+extern struct sh_pfc_soc_info sh7734_pinmux_info;
+extern struct sh_pfc_soc_info sh7757_pinmux_info;
+extern struct sh_pfc_soc_info sh7785_pinmux_info;
+extern struct sh_pfc_soc_info sh7786_pinmux_info;
+extern struct sh_pfc_soc_info shx3_pinmux_info;
+
+#endif /* __SH_PFC_CORE_H__ */
diff --git a/drivers/sh/pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c
index 6a24f07c2013..a535075c8b69 100644
--- a/drivers/sh/pfc/gpio.c
+++ b/drivers/pinctrl/sh-pfc/gpio.c
@@ -8,16 +8,18 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-#define pr_fmt(fmt) "sh_pfc " KBUILD_MODNAME ": " fmt
-#include <linux/init.h>
+#define pr_fmt(fmt) KBUILD_MODNAME " gpio: " fmt
+
+#include <linux/device.h>
#include <linux/gpio.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
+#include <linux/init.h>
#include <linux/module.h>
-#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
-#include <linux/sh_pfc.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "core.h"
struct sh_pfc_chip {
struct sh_pfc *pfc;
@@ -49,7 +51,7 @@ static void sh_gpio_set_value(struct sh_pfc *pfc, unsigned gpio, int value)
struct pinmux_data_reg *dr = NULL;
int bit = 0;
- if (!pfc || sh_pfc_get_data_reg(pfc, gpio, &dr, &bit) != 0)
+ if (sh_pfc_get_data_reg(pfc, gpio, &dr, &bit) != 0)
BUG();
else
sh_pfc_write_bit(dr, bit, value);
@@ -60,7 +62,7 @@ static int sh_gpio_get_value(struct sh_pfc *pfc, unsigned gpio)
struct pinmux_data_reg *dr = NULL;
int bit = 0;
- if (!pfc || sh_pfc_get_data_reg(pfc, gpio, &dr, &bit) != 0)
+ if (sh_pfc_get_data_reg(pfc, gpio, &dr, &bit) != 0)
return -EINVAL;
return sh_pfc_read_bit(dr, bit);
@@ -103,11 +105,11 @@ static int sh_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
if (pos <= 0 || !enum_id)
break;
- for (i = 0; i < pfc->gpio_irq_size; i++) {
- enum_ids = pfc->gpio_irq[i].enum_ids;
+ for (i = 0; i < pfc->info->gpio_irq_size; i++) {
+ enum_ids = pfc->info->gpio_irq[i].enum_ids;
for (k = 0; enum_ids[k]; k++) {
if (enum_ids[k] == enum_id)
- return pfc->gpio_irq[i].irq;
+ return pfc->info->gpio_irq[i].irq;
}
}
}
@@ -128,12 +130,12 @@ static void sh_pfc_gpio_setup(struct sh_pfc_chip *chip)
gc->set = sh_gpio_set;
gc->to_irq = sh_gpio_to_irq;
- WARN_ON(pfc->first_gpio != 0); /* needs testing */
+ WARN_ON(pfc->info->first_gpio != 0); /* needs testing */
- gc->label = pfc->name;
+ gc->label = pfc->info->name;
gc->owner = THIS_MODULE;
- gc->base = pfc->first_gpio;
- gc->ngpio = (pfc->last_gpio - pfc->first_gpio) + 1;
+ gc->base = pfc->info->first_gpio;
+ gc->ngpio = (pfc->info->last_gpio - pfc->info->first_gpio) + 1;
}
int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
@@ -141,7 +143,7 @@ int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
struct sh_pfc_chip *chip;
int ret;
- chip = kzalloc(sizeof(struct sh_pfc_chip), GFP_KERNEL);
+ chip = devm_kzalloc(pfc->dev, sizeof(*chip), GFP_KERNEL);
if (unlikely(!chip))
return -ENOMEM;
@@ -151,90 +153,26 @@ int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
ret = gpiochip_add(&chip->gpio_chip);
if (unlikely(ret < 0))
- kfree(chip);
-
- pr_info("%s handling gpio %d -> %d\n",
- pfc->name, pfc->first_gpio, pfc->last_gpio);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(sh_pfc_register_gpiochip);
-
-static int sh_pfc_gpio_match(struct gpio_chip *gc, void *data)
-{
- return !!strstr(gc->label, data);
-}
-
-static int sh_pfc_gpio_probe(struct platform_device *pdev)
-{
- struct sh_pfc_chip *chip;
- struct gpio_chip *gc;
-
- gc = gpiochip_find("_pfc", sh_pfc_gpio_match);
- if (unlikely(!gc)) {
- pr_err("Cant find gpio chip\n");
- return -ENODEV;
- }
+ return ret;
- chip = gpio_to_pfc_chip(gc);
- platform_set_drvdata(pdev, chip);
+ pfc->gpio = chip;
- pr_info("attaching to GPIO chip %s\n", chip->pfc->name);
+ pr_info("%s handling gpio %d -> %d\n",
+ pfc->info->name, pfc->info->first_gpio,
+ pfc->info->last_gpio);
return 0;
}
-static int sh_pfc_gpio_remove(struct platform_device *pdev)
+int sh_pfc_unregister_gpiochip(struct sh_pfc *pfc)
{
- struct sh_pfc_chip *chip = platform_get_drvdata(pdev);
+ struct sh_pfc_chip *chip = pfc->gpio;
int ret;
ret = gpiochip_remove(&chip->gpio_chip);
if (unlikely(ret < 0))
return ret;
- kfree(chip);
+ pfc->gpio = NULL;
return 0;
}
-
-static struct platform_driver sh_pfc_gpio_driver = {
- .probe = sh_pfc_gpio_probe,
- .remove = sh_pfc_gpio_remove,
- .driver = {
- .name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_device sh_pfc_gpio_device = {
- .name = KBUILD_MODNAME,
- .id = -1,
-};
-
-static int __init sh_pfc_gpio_init(void)
-{
- int rc;
-
- rc = platform_driver_register(&sh_pfc_gpio_driver);
- if (likely(!rc)) {
- rc = platform_device_register(&sh_pfc_gpio_device);
- if (unlikely(rc))
- platform_driver_unregister(&sh_pfc_gpio_driver);
- }
-
- return rc;
-}
-
-static void __exit sh_pfc_gpio_exit(void)
-{
- platform_device_unregister(&sh_pfc_gpio_device);
- platform_driver_unregister(&sh_pfc_gpio_driver);
-}
-
-module_init(sh_pfc_gpio_init);
-module_exit(sh_pfc_gpio_exit);
-
-MODULE_AUTHOR("Magnus Damm, Paul Mundt");
-MODULE_DESCRIPTION("GPIO driver for SuperH pin function controller");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:pfc-gpio");
diff --git a/arch/arm/mach-shmobile/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
index 134d1b9a8821..214788c4a606 100644
--- a/arch/arm/mach-shmobile/pfc-r8a7740.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
@@ -18,12 +18,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sh_pfc.h>
#include <mach/r8a7740.h>
#include <mach/irqs.h>
+#include "sh_pfc.h"
+
#define CPU_ALL_PORT(fn, pfx, sfx) \
PORT_10(fn, pfx, sfx), PORT_90(fn, pfx, sfx), \
PORT_10(fn, pfx##10, sfx), PORT_90(fn, pfx##1, sfx), \
@@ -2579,7 +2579,7 @@ static struct pinmux_irq pinmux_irqs[] = {
PINMUX_IRQ(evt2irq(0x33E0), PORT41_FN0, PORT167_FN0), /* IRQ31A */
};
-static struct pinmux_info r8a7740_pinmux_info = {
+struct sh_pfc_soc_info r8a7740_pinmux_info = {
.name = "r8a7740_pfc",
.reserved_id = PINMUX_RESERVED,
.data = { PINMUX_DATA_BEGIN,
@@ -2610,8 +2610,3 @@ static struct pinmux_info r8a7740_pinmux_info = {
.gpio_irq = pinmux_irqs,
.gpio_irq_size = ARRAY_SIZE(pinmux_irqs),
};
-
-void r8a7740_pinmux_init(void)
-{
- register_pinmux(&r8a7740_pinmux_info);
-}
diff --git a/arch/arm/mach-shmobile/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
index 9513234d322b..13feaa0c0eb7 100644
--- a/arch/arm/mach-shmobile/pfc-r8a7779.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
@@ -17,12 +17,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <linux/init.h>
+
#include <linux/kernel.h>
-#include <linux/sh_pfc.h>
-#include <linux/ioport.h>
#include <mach/r8a7779.h>
+#include "sh_pfc.h"
+
#define CPU_32_PORT(fn, pfx, sfx) \
PORT_10(fn, pfx, sfx), PORT_10(fn, pfx##1, sfx), \
PORT_10(fn, pfx##2, sfx), PORT_1(fn, pfx##30, sfx), \
@@ -2600,25 +2600,9 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
{ },
};
-static struct resource r8a7779_pfc_resources[] = {
- [0] = {
- .start = 0xfffc0000,
- .end = 0xfffc023b,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = 0xffc40000,
- .end = 0xffc46fff,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct pinmux_info r8a7779_pinmux_info = {
+struct sh_pfc_soc_info r8a7779_pinmux_info = {
.name = "r8a7779_pfc",
- .resource = r8a7779_pfc_resources,
- .num_resources = ARRAY_SIZE(r8a7779_pfc_resources),
-
.unlock_reg = 0xfffc0000, /* PMMR */
.reserved_id = PINMUX_RESERVED,
@@ -2638,8 +2622,3 @@ static struct pinmux_info r8a7779_pinmux_info = {
.gpio_data = pinmux_data,
.gpio_data_size = ARRAY_SIZE(pinmux_data),
};
-
-void r8a7779_pinmux_init(void)
-{
- register_pinmux(&r8a7779_pinmux_info);
-}
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7203.c b/drivers/pinctrl/sh-pfc/pfc-sh7203.c
new file mode 100644
index 000000000000..01b425dfd162
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7203.c
@@ -0,0 +1,1592 @@
+/*
+ * SH7203 Pinmux
+ *
+ * Copyright (C) 2008 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/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7203.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ PB12_DATA,
+ PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
+ PC14_DATA, PC13_DATA, PC12_DATA,
+ PC11_DATA, PC10_DATA, PC9_DATA, PC8_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+ PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+ PE15_DATA, PE14_DATA, PE13_DATA, PE12_DATA,
+ PE11_DATA, PE10_DATA, PE9_DATA, PE8_DATA,
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ PF30_DATA, PF29_DATA, PF28_DATA,
+ PF27_DATA, PF26_DATA, PF25_DATA, PF24_DATA,
+ PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
+ PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA,
+ PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
+ PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ FORCE_IN,
+ PA7_IN, PA6_IN, PA5_IN, PA4_IN,
+ PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+ PB11_IN, PB10_IN, PB9_IN, PB8_IN,
+ PC14_IN, PC13_IN, PC12_IN,
+ PC11_IN, PC10_IN, PC9_IN, PC8_IN,
+ PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+ PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+ PD15_IN, PD14_IN, PD13_IN, PD12_IN,
+ PD11_IN, PD10_IN, PD9_IN, PD8_IN,
+ PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+ PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+ PE15_IN, PE14_IN, PE13_IN, PE12_IN,
+ PE11_IN, PE10_IN, PE9_IN, PE8_IN,
+ PE7_IN, PE6_IN, PE5_IN, PE4_IN,
+ PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+ PF30_IN, PF29_IN, PF28_IN,
+ PF27_IN, PF26_IN, PF25_IN, PF24_IN,
+ PF23_IN, PF22_IN, PF21_IN, PF20_IN,
+ PF19_IN, PF18_IN, PF17_IN, PF16_IN,
+ PF15_IN, PF14_IN, PF13_IN, PF12_IN,
+ PF11_IN, PF10_IN, PF9_IN, PF8_IN,
+ PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+ PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ FORCE_OUT,
+ PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
+ PC14_OUT, PC13_OUT, PC12_OUT,
+ PC11_OUT, PC10_OUT, PC9_OUT, PC8_OUT,
+ PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+ PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+ PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
+ PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
+ PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+ PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+ PE15_OUT, PE14_OUT, PE13_OUT, PE12_OUT,
+ PE11_OUT, PE10_OUT, PE9_OUT, PE8_OUT,
+ PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
+ PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+ PF30_OUT, PF29_OUT, PF28_OUT,
+ PF27_OUT, PF26_OUT, PF25_OUT, PF24_OUT,
+ PF23_OUT, PF22_OUT, PF21_OUT, PF20_OUT,
+ PF19_OUT, PF18_OUT, PF17_OUT, PF16_OUT,
+ PF15_OUT, PF14_OUT, PF13_OUT, PF12_OUT,
+ PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
+ PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+ PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PB11_IOR_IN, PB11_IOR_OUT,
+ PB10_IOR_IN, PB10_IOR_OUT,
+ PB9_IOR_IN, PB9_IOR_OUT,
+ PB8_IOR_IN, PB8_IOR_OUT,
+ PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
+ PB11MD_0, PB11MD_1,
+ PB10MD_0, PB10MD_1,
+ PB9MD_00, PB9MD_01, PB9MD_10,
+ PB8MD_00, PB8MD_01, PB8MD_10,
+ PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
+ PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
+ PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
+ PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
+ PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11,
+ PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11,
+ PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11,
+ PB0MD_00, PB0MD_01, PB0MD_10, PB0MD_11,
+
+ PB12IRQ_00, PB12IRQ_01, PB12IRQ_10,
+
+ PC14MD_0, PC14MD_1,
+ PC13MD_0, PC13MD_1,
+ PC12MD_0, PC12MD_1,
+ PC11MD_00, PC11MD_01, PC11MD_10,
+ PC10MD_00, PC10MD_01, PC10MD_10,
+ PC9MD_0, PC9MD_1,
+ PC8MD_0, PC8MD_1,
+ PC7MD_0, PC7MD_1,
+ PC6MD_0, PC6MD_1,
+ PC5MD_0, PC5MD_1,
+ PC4MD_0, PC4MD_1,
+ PC3MD_0, PC3MD_1,
+ PC2MD_0, PC2MD_1,
+ PC1MD_0, PC1MD_1,
+ PC0MD_00, PC0MD_01, PC0MD_10,
+
+ PD15MD_000, PD15MD_001, PD15MD_010, PD15MD_100, PD15MD_101,
+ PD14MD_000, PD14MD_001, PD14MD_010, PD14MD_101,
+ PD13MD_000, PD13MD_001, PD13MD_010, PD13MD_100, PD13MD_101,
+ PD12MD_000, PD12MD_001, PD12MD_010, PD12MD_100, PD12MD_101,
+ PD11MD_000, PD11MD_001, PD11MD_010, PD11MD_100, PD11MD_101,
+ PD10MD_000, PD10MD_001, PD10MD_010, PD10MD_100, PD10MD_101,
+ PD9MD_000, PD9MD_001, PD9MD_010, PD9MD_100, PD9MD_101,
+ PD8MD_000, PD8MD_001, PD8MD_010, PD8MD_100, PD8MD_101,
+ PD7MD_000, PD7MD_001, PD7MD_010, PD7MD_011, PD7MD_100, PD7MD_101,
+ PD6MD_000, PD6MD_001, PD6MD_010, PD6MD_011, PD6MD_100, PD6MD_101,
+ PD5MD_000, PD5MD_001, PD5MD_010, PD5MD_011, PD5MD_100, PD5MD_101,
+ PD4MD_000, PD4MD_001, PD4MD_010, PD4MD_011, PD4MD_100, PD4MD_101,
+ PD3MD_000, PD3MD_001, PD3MD_010, PD3MD_011, PD3MD_100, PD3MD_101,
+ PD2MD_000, PD2MD_001, PD2MD_010, PD2MD_011, PD2MD_100, PD2MD_101,
+ PD1MD_000, PD1MD_001, PD1MD_010, PD1MD_011, PD1MD_100, PD1MD_101,
+ PD0MD_000, PD0MD_001, PD0MD_010, PD0MD_011, PD0MD_100, PD0MD_101,
+
+ PE15MD_00, PE15MD_01, PE15MD_11,
+ PE14MD_00, PE14MD_01, PE14MD_11,
+ PE13MD_00, PE13MD_11,
+ PE12MD_00, PE12MD_11,
+ PE11MD_000, PE11MD_001, PE11MD_010, PE11MD_100,
+ PE10MD_000, PE10MD_001, PE10MD_010, PE10MD_100,
+ PE9MD_00, PE9MD_01, PE9MD_10, PE9MD_11,
+ PE8MD_00, PE8MD_01, PE8MD_10, PE8MD_11,
+ PE7MD_000, PE7MD_001, PE7MD_010, PE7MD_011, PE7MD_100,
+ PE6MD_000, PE6MD_001, PE6MD_010, PE6MD_011, PE6MD_100,
+ PE5MD_000, PE5MD_001, PE5MD_010, PE5MD_011, PE5MD_100,
+ PE4MD_000, PE4MD_001, PE4MD_010, PE4MD_011, PE4MD_100,
+ PE3MD_00, PE3MD_01, PE3MD_11,
+ PE2MD_00, PE2MD_01, PE2MD_11,
+ PE1MD_00, PE1MD_01, PE1MD_10, PE1MD_11,
+ PE0MD_000, PE0MD_001, PE0MD_011, PE0MD_100,
+
+ PF30MD_0, PF30MD_1,
+ PF29MD_0, PF29MD_1,
+ PF28MD_0, PF28MD_1,
+ PF27MD_0, PF27MD_1,
+ PF26MD_0, PF26MD_1,
+ PF25MD_0, PF25MD_1,
+ PF24MD_0, PF24MD_1,
+ PF23MD_00, PF23MD_01, PF23MD_10,
+ PF22MD_00, PF22MD_01, PF22MD_10,
+ PF21MD_00, PF21MD_01, PF21MD_10,
+ PF20MD_00, PF20MD_01, PF20MD_10,
+ PF19MD_00, PF19MD_01, PF19MD_10,
+ PF18MD_00, PF18MD_01, PF18MD_10,
+ PF17MD_00, PF17MD_01, PF17MD_10,
+ PF16MD_00, PF16MD_01, PF16MD_10,
+ PF15MD_00, PF15MD_01, PF15MD_10,
+ PF14MD_00, PF14MD_01, PF14MD_10,
+ PF13MD_00, PF13MD_01, PF13MD_10,
+ PF12MD_00, PF12MD_01, PF12MD_10,
+ PF11MD_00, PF11MD_01, PF11MD_10,
+ PF10MD_00, PF10MD_01, PF10MD_10,
+ PF9MD_00, PF9MD_01, PF9MD_10,
+ PF8MD_00, PF8MD_01, PF8MD_10,
+ PF7MD_00, PF7MD_01, PF7MD_10, PF7MD_11,
+ PF6MD_00, PF6MD_01, PF6MD_10, PF6MD_11,
+ PF5MD_00, PF5MD_01, PF5MD_10, PF5MD_11,
+ PF4MD_00, PF4MD_01, PF4MD_10, PF4MD_11,
+ PF3MD_00, PF3MD_01, PF3MD_10, PF3MD_11,
+ PF2MD_00, PF2MD_01, PF2MD_10, PF2MD_11,
+ PF1MD_00, PF1MD_01, PF1MD_10, PF1MD_11,
+ PF0MD_00, PF0MD_01, PF0MD_10, PF0MD_11,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ PINT7_PB_MARK, PINT6_PB_MARK, PINT5_PB_MARK, PINT4_PB_MARK,
+ PINT3_PB_MARK, PINT2_PB_MARK, PINT1_PB_MARK, PINT0_PB_MARK,
+ PINT7_PD_MARK, PINT6_PD_MARK, PINT5_PD_MARK, PINT4_PD_MARK,
+ PINT3_PD_MARK, PINT2_PD_MARK, PINT1_PD_MARK, PINT0_PD_MARK,
+ IRQ7_PB_MARK, IRQ6_PB_MARK, IRQ5_PB_MARK, IRQ4_PB_MARK,
+ IRQ3_PB_MARK, IRQ2_PB_MARK, IRQ1_PB_MARK, IRQ0_PB_MARK,
+ IRQ7_PD_MARK, IRQ6_PD_MARK, IRQ5_PD_MARK, IRQ4_PD_MARK,
+ IRQ3_PD_MARK, IRQ2_PD_MARK, IRQ1_PD_MARK, IRQ0_PD_MARK,
+ IRQ7_PE_MARK, IRQ6_PE_MARK, IRQ5_PE_MARK, IRQ4_PE_MARK,
+ IRQ3_PE_MARK, IRQ2_PE_MARK, IRQ1_PE_MARK, IRQ0_PE_MARK,
+ WDTOVF_MARK, IRQOUT_MARK, REFOUT_MARK, IRQOUT_REFOUT_MARK,
+ UBCTRG_MARK,
+ CTX1_MARK, CRX1_MARK, CTX0_MARK, CTX0_CTX1_MARK,
+ CRX0_MARK, CRX0_CRX1_MARK,
+ SDA3_MARK, SCL3_MARK,
+ SDA2_MARK, SCL2_MARK,
+ SDA1_MARK, SCL1_MARK,
+ SDA0_MARK, SCL0_MARK,
+ TEND0_PD_MARK, TEND0_PE_MARK, DACK0_PD_MARK, DACK0_PE_MARK,
+ DREQ0_PD_MARK, DREQ0_PE_MARK, TEND1_PD_MARK, TEND1_PE_MARK,
+ DACK1_PD_MARK, DACK1_PE_MARK, DREQ1_PD_MARK, DREQ1_PE_MARK,
+ DACK2_MARK, DREQ2_MARK, DACK3_MARK, DREQ3_MARK,
+ ADTRG_PD_MARK, ADTRG_PE_MARK,
+ D31_MARK, D30_MARK, D29_MARK, D28_MARK,
+ D27_MARK, D26_MARK, D25_MARK, D24_MARK,
+ D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+ D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+ A25_MARK, A24_MARK, A23_MARK, A22_MARK,
+ A21_MARK, CS4_MARK, MRES_MARK, BS_MARK,
+ IOIS16_MARK, CS1_MARK, CS6_CE1B_MARK, CE2B_MARK,
+ CS5_CE1A_MARK, CE2A_MARK, FRAME_MARK, WAIT_MARK,
+ RDWR_MARK, CKE_MARK, CASU_MARK, BREQ_MARK,
+ RASU_MARK, BACK_MARK, CASL_MARK, RASL_MARK,
+ WE3_DQMUU_AH_ICIO_WR_MARK, WE2_DQMUL_ICIORD_MARK,
+ WE1_DQMLU_WE_MARK, WE0_DQMLL_MARK,
+ CS3_MARK, CS2_MARK, A1_MARK, A0_MARK, CS7_MARK,
+ TIOC4D_MARK, TIOC4C_MARK, TIOC4B_MARK, TIOC4A_MARK,
+ TIOC3D_MARK, TIOC3C_MARK, TIOC3B_MARK, TIOC3A_MARK,
+ TIOC2B_MARK, TIOC1B_MARK, TIOC2A_MARK, TIOC1A_MARK,
+ TIOC0D_MARK, TIOC0C_MARK, TIOC0B_MARK, TIOC0A_MARK,
+ TCLKD_PD_MARK, TCLKC_PD_MARK, TCLKB_PD_MARK, TCLKA_PD_MARK,
+ TCLKD_PF_MARK, TCLKC_PF_MARK, TCLKB_PF_MARK, TCLKA_PF_MARK,
+ SCS0_PD_MARK, SSO0_PD_MARK, SSI0_PD_MARK, SSCK0_PD_MARK,
+ SCS0_PF_MARK, SSO0_PF_MARK, SSI0_PF_MARK, SSCK0_PF_MARK,
+ SCS1_PD_MARK, SSO1_PD_MARK, SSI1_PD_MARK, SSCK1_PD_MARK,
+ SCS1_PF_MARK, SSO1_PF_MARK, SSI1_PF_MARK, SSCK1_PF_MARK,
+ TXD0_MARK, RXD0_MARK, SCK0_MARK,
+ TXD1_MARK, RXD1_MARK, SCK1_MARK,
+ TXD2_MARK, RXD2_MARK, SCK2_MARK,
+ RTS3_MARK, CTS3_MARK, TXD3_MARK,
+ RXD3_MARK, SCK3_MARK,
+ AUDIO_CLK_MARK,
+ SSIDATA3_MARK, SSIWS3_MARK, SSISCK3_MARK,
+ SSIDATA2_MARK, SSIWS2_MARK, SSISCK2_MARK,
+ SSIDATA1_MARK, SSIWS1_MARK, SSISCK1_MARK,
+ SSIDATA0_MARK, SSIWS0_MARK, SSISCK0_MARK,
+ FCE_MARK, FRB_MARK,
+ NAF7_MARK, NAF6_MARK, NAF5_MARK, NAF4_MARK,
+ NAF3_MARK, NAF2_MARK, NAF1_MARK, NAF0_MARK,
+ FSC_MARK, FOE_MARK, FCDE_MARK, FWE_MARK,
+ LCD_VEPWC_MARK, LCD_VCPWC_MARK, LCD_CLK_MARK, LCD_FLM_MARK,
+ LCD_M_DISP_MARK, LCD_CL2_MARK, LCD_CL1_MARK, LCD_DON_MARK,
+ LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
+ LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
+ LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
+ LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+ /* PA */
+ PINMUX_DATA(PA7_DATA, PA7_IN),
+ PINMUX_DATA(PA6_DATA, PA6_IN),
+ PINMUX_DATA(PA5_DATA, PA5_IN),
+ PINMUX_DATA(PA4_DATA, PA4_IN),
+ PINMUX_DATA(PA3_DATA, PA3_IN),
+ PINMUX_DATA(PA2_DATA, PA2_IN),
+ PINMUX_DATA(PA1_DATA, PA1_IN),
+ PINMUX_DATA(PA0_DATA, PA0_IN),
+
+ /* PB */
+ PINMUX_DATA(PB12_DATA, PB12MD_00, FORCE_OUT),
+ PINMUX_DATA(WDTOVF_MARK, PB12MD_01),
+ PINMUX_DATA(IRQOUT_MARK, PB12MD_10, PB12IRQ_00),
+ PINMUX_DATA(REFOUT_MARK, PB12MD_10, PB12IRQ_01),
+ PINMUX_DATA(IRQOUT_REFOUT_MARK, PB12MD_10, PB12IRQ_10),
+ PINMUX_DATA(UBCTRG_MARK, PB12MD_11),
+
+ PINMUX_DATA(PB11_DATA, PB11MD_0, PB11_IN, PB11_OUT),
+ PINMUX_DATA(CTX1_MARK, PB11MD_1),
+
+ PINMUX_DATA(PB10_DATA, PB10MD_0, PB10_IN, PB10_OUT),
+ PINMUX_DATA(CRX1_MARK, PB10MD_1),
+
+ PINMUX_DATA(PB9_DATA, PB9MD_00, PB9_IN, PB9_OUT),
+ PINMUX_DATA(CTX0_MARK, PB9MD_01),
+ PINMUX_DATA(CTX0_CTX1_MARK, PB9MD_10),
+
+ PINMUX_DATA(PB8_DATA, PB8MD_00, PB8_IN, PB8_OUT),
+ PINMUX_DATA(CRX0_MARK, PB8MD_01),
+ PINMUX_DATA(CRX0_CRX1_MARK, PB8MD_10),
+
+ PINMUX_DATA(PB7_DATA, PB7MD_00, FORCE_IN),
+ PINMUX_DATA(SDA3_MARK, PB7MD_01),
+ PINMUX_DATA(PINT7_PB_MARK, PB7MD_10),
+ PINMUX_DATA(IRQ7_PB_MARK, PB7MD_11),
+
+ PINMUX_DATA(PB6_DATA, PB6MD_00, FORCE_IN),
+ PINMUX_DATA(SCL3_MARK, PB6MD_01),
+ PINMUX_DATA(PINT6_PB_MARK, PB6MD_10),
+ PINMUX_DATA(IRQ6_PB_MARK, PB6MD_11),
+
+ PINMUX_DATA(PB5_DATA, PB5MD_00, FORCE_IN),
+ PINMUX_DATA(SDA2_MARK, PB6MD_01),
+ PINMUX_DATA(PINT5_PB_MARK, PB6MD_10),
+ PINMUX_DATA(IRQ5_PB_MARK, PB6MD_11),
+
+ PINMUX_DATA(PB4_DATA, PB4MD_00, FORCE_IN),
+ PINMUX_DATA(SCL2_MARK, PB4MD_01),
+ PINMUX_DATA(PINT4_PB_MARK, PB4MD_10),
+ PINMUX_DATA(IRQ4_PB_MARK, PB4MD_11),
+
+ PINMUX_DATA(PB3_DATA, PB3MD_00, FORCE_IN),
+ PINMUX_DATA(SDA1_MARK, PB3MD_01),
+ PINMUX_DATA(PINT3_PB_MARK, PB3MD_10),
+ PINMUX_DATA(IRQ3_PB_MARK, PB3MD_11),
+
+ PINMUX_DATA(PB2_DATA, PB2MD_00, FORCE_IN),
+ PINMUX_DATA(SCL1_MARK, PB2MD_01),
+ PINMUX_DATA(PINT2_PB_MARK, PB2MD_10),
+ PINMUX_DATA(IRQ2_PB_MARK, PB2MD_11),
+
+ PINMUX_DATA(PB1_DATA, PB1MD_00, FORCE_IN),
+ PINMUX_DATA(SDA0_MARK, PB1MD_01),
+ PINMUX_DATA(PINT1_PB_MARK, PB1MD_10),
+ PINMUX_DATA(IRQ1_PB_MARK, PB1MD_11),
+
+ PINMUX_DATA(PB0_DATA, PB0MD_00, FORCE_IN),
+ PINMUX_DATA(SCL0_MARK, PB0MD_01),
+ PINMUX_DATA(PINT0_PB_MARK, PB0MD_10),
+ PINMUX_DATA(IRQ0_PB_MARK, PB0MD_11),
+
+ /* PC */
+ PINMUX_DATA(PC14_DATA, PC14MD_0, PC14_IN, PC14_OUT),
+ PINMUX_DATA(WAIT_MARK, PC14MD_1),
+
+ PINMUX_DATA(PC13_DATA, PC13MD_0, PC13_IN, PC13_OUT),
+ PINMUX_DATA(RDWR_MARK, PC13MD_1),
+
+ PINMUX_DATA(PC12_DATA, PC12MD_0, PC12_IN, PC12_OUT),
+ PINMUX_DATA(CKE_MARK, PC12MD_1),
+
+ PINMUX_DATA(PC11_DATA, PC11MD_00, PC11_IN, PC11_OUT),
+ PINMUX_DATA(CASU_MARK, PC11MD_01),
+ PINMUX_DATA(BREQ_MARK, PC11MD_10),
+
+ PINMUX_DATA(PC10_DATA, PC10MD_00, PC10_IN, PC10_OUT),
+ PINMUX_DATA(RASU_MARK, PC10MD_01),
+ PINMUX_DATA(BACK_MARK, PC10MD_10),
+
+ PINMUX_DATA(PC9_DATA, PC9MD_0, PC9_IN, PC9_OUT),
+ PINMUX_DATA(CASL_MARK, PC9MD_1),
+
+ PINMUX_DATA(PC8_DATA, PC8MD_0, PC8_IN, PC8_OUT),
+ PINMUX_DATA(RASL_MARK, PC8MD_1),
+
+ PINMUX_DATA(PC7_DATA, PC7MD_0, PC7_IN, PC7_OUT),
+ PINMUX_DATA(WE3_DQMUU_AH_ICIO_WR_MARK, PC7MD_1),
+
+ PINMUX_DATA(PC6_DATA, PC6MD_0, PC6_IN, PC6_OUT),
+ PINMUX_DATA(WE2_DQMUL_ICIORD_MARK, PC6MD_1),
+
+ PINMUX_DATA(PC5_DATA, PC5MD_0, PC5_IN, PC5_OUT),
+ PINMUX_DATA(WE1_DQMLU_WE_MARK, PC5MD_1),
+
+ PINMUX_DATA(PC4_DATA, PC4MD_0, PC4_IN, PC4_OUT),
+ PINMUX_DATA(WE0_DQMLL_MARK, PC4MD_1),
+
+ PINMUX_DATA(PC3_DATA, PC3MD_0, PC3_IN, PC3_OUT),
+ PINMUX_DATA(CS3_MARK, PC3MD_1),
+
+ PINMUX_DATA(PC2_DATA, PC2MD_0, PC2_IN, PC2_OUT),
+ PINMUX_DATA(CS2_MARK, PC2MD_1),
+
+ PINMUX_DATA(PC1_DATA, PC1MD_0, PC1_IN, PC1_OUT),
+ PINMUX_DATA(A1_MARK, PC1MD_1),
+
+ PINMUX_DATA(PC0_DATA, PC0MD_00, PC0_IN, PC0_OUT),
+ PINMUX_DATA(A0_MARK, PC0MD_01),
+ PINMUX_DATA(CS7_MARK, PC0MD_10),
+
+ /* PD */
+ PINMUX_DATA(PD15_DATA, PD15MD_000, PD15_IN, PD15_OUT),
+ PINMUX_DATA(D31_MARK, PD15MD_001),
+ PINMUX_DATA(PINT7_PD_MARK, PD15MD_010),
+ PINMUX_DATA(ADTRG_PD_MARK, PD15MD_100),
+ PINMUX_DATA(TIOC4D_MARK, PD15MD_101),
+
+ PINMUX_DATA(PD14_DATA, PD14MD_000, PD14_IN, PD14_OUT),
+ PINMUX_DATA(D30_MARK, PD14MD_001),
+ PINMUX_DATA(PINT6_PD_MARK, PD14MD_010),
+ PINMUX_DATA(TIOC4C_MARK, PD14MD_101),
+
+ PINMUX_DATA(PD13_DATA, PD13MD_000, PD13_IN, PD13_OUT),
+ PINMUX_DATA(D29_MARK, PD13MD_001),
+ PINMUX_DATA(PINT5_PD_MARK, PD13MD_010),
+ PINMUX_DATA(TEND1_PD_MARK, PD13MD_100),
+ PINMUX_DATA(TIOC4B_MARK, PD13MD_101),
+
+ PINMUX_DATA(PD12_DATA, PD12MD_000, PD12_IN, PD12_OUT),
+ PINMUX_DATA(D28_MARK, PD12MD_001),
+ PINMUX_DATA(PINT4_PD_MARK, PD12MD_010),
+ PINMUX_DATA(DACK1_PD_MARK, PD12MD_100),
+ PINMUX_DATA(TIOC4A_MARK, PD12MD_101),
+
+ PINMUX_DATA(PD11_DATA, PD11MD_000, PD11_IN, PD11_OUT),
+ PINMUX_DATA(D27_MARK, PD11MD_001),
+ PINMUX_DATA(PINT3_PD_MARK, PD11MD_010),
+ PINMUX_DATA(DREQ1_PD_MARK, PD11MD_100),
+ PINMUX_DATA(TIOC3D_MARK, PD11MD_101),
+
+ PINMUX_DATA(PD10_DATA, PD10MD_000, PD10_IN, PD10_OUT),
+ PINMUX_DATA(D26_MARK, PD10MD_001),
+ PINMUX_DATA(PINT2_PD_MARK, PD10MD_010),
+ PINMUX_DATA(TEND0_PD_MARK, PD10MD_100),
+ PINMUX_DATA(TIOC3C_MARK, PD10MD_101),
+
+ PINMUX_DATA(PD9_DATA, PD9MD_000, PD9_IN, PD9_OUT),
+ PINMUX_DATA(D25_MARK, PD9MD_001),
+ PINMUX_DATA(PINT1_PD_MARK, PD9MD_010),
+ PINMUX_DATA(DACK0_PD_MARK, PD9MD_100),
+ PINMUX_DATA(TIOC3B_MARK, PD9MD_101),
+
+ PINMUX_DATA(PD8_DATA, PD8MD_000, PD8_IN, PD8_OUT),
+ PINMUX_DATA(D24_MARK, PD8MD_001),
+ PINMUX_DATA(PINT0_PD_MARK, PD8MD_010),
+ PINMUX_DATA(DREQ0_PD_MARK, PD8MD_100),
+ PINMUX_DATA(TIOC3A_MARK, PD8MD_101),
+
+ PINMUX_DATA(PD7_DATA, PD7MD_000, PD7_IN, PD7_OUT),
+ PINMUX_DATA(D23_MARK, PD7MD_001),
+ PINMUX_DATA(IRQ7_PD_MARK, PD7MD_010),
+ PINMUX_DATA(SCS1_PD_MARK, PD7MD_011),
+ PINMUX_DATA(TCLKD_PD_MARK, PD7MD_100),
+ PINMUX_DATA(TIOC2B_MARK, PD7MD_101),
+
+ PINMUX_DATA(PD6_DATA, PD6MD_000, PD6_IN, PD6_OUT),
+ PINMUX_DATA(D22_MARK, PD6MD_001),
+ PINMUX_DATA(IRQ6_PD_MARK, PD6MD_010),
+ PINMUX_DATA(SSO1_PD_MARK, PD6MD_011),
+ PINMUX_DATA(TCLKC_PD_MARK, PD6MD_100),
+ PINMUX_DATA(TIOC2A_MARK, PD6MD_101),
+
+ PINMUX_DATA(PD5_DATA, PD5MD_000, PD5_IN, PD5_OUT),
+ PINMUX_DATA(D21_MARK, PD5MD_001),
+ PINMUX_DATA(IRQ5_PD_MARK, PD5MD_010),
+ PINMUX_DATA(SSI1_PD_MARK, PD5MD_011),
+ PINMUX_DATA(TCLKB_PD_MARK, PD5MD_100),
+ PINMUX_DATA(TIOC1B_MARK, PD5MD_101),
+
+ PINMUX_DATA(PD4_DATA, PD4MD_000, PD4_IN, PD4_OUT),
+ PINMUX_DATA(D20_MARK, PD4MD_001),
+ PINMUX_DATA(IRQ4_PD_MARK, PD4MD_010),
+ PINMUX_DATA(SSCK1_PD_MARK, PD4MD_011),
+ PINMUX_DATA(TCLKA_PD_MARK, PD4MD_100),
+ PINMUX_DATA(TIOC1A_MARK, PD4MD_101),
+
+ PINMUX_DATA(PD3_DATA, PD3MD_000, PD3_IN, PD3_OUT),
+ PINMUX_DATA(D19_MARK, PD3MD_001),
+ PINMUX_DATA(IRQ3_PD_MARK, PD3MD_010),
+ PINMUX_DATA(SCS0_PD_MARK, PD3MD_011),
+ PINMUX_DATA(DACK3_MARK, PD3MD_100),
+ PINMUX_DATA(TIOC0D_MARK, PD3MD_101),
+
+ PINMUX_DATA(PD2_DATA, PD2MD_000, PD2_IN, PD2_OUT),
+ PINMUX_DATA(D18_MARK, PD2MD_001),
+ PINMUX_DATA(IRQ2_PD_MARK, PD2MD_010),
+ PINMUX_DATA(SSO0_PD_MARK, PD2MD_011),
+ PINMUX_DATA(DREQ3_MARK, PD2MD_100),
+ PINMUX_DATA(TIOC0C_MARK, PD2MD_101),
+
+ PINMUX_DATA(PD1_DATA, PD1MD_000, PD1_IN, PD1_OUT),
+ PINMUX_DATA(D17_MARK, PD1MD_001),
+ PINMUX_DATA(IRQ1_PD_MARK, PD1MD_010),
+ PINMUX_DATA(SSI0_PD_MARK, PD1MD_011),
+ PINMUX_DATA(DACK2_MARK, PD1MD_100),
+ PINMUX_DATA(TIOC0B_MARK, PD1MD_101),
+
+ PINMUX_DATA(PD0_DATA, PD0MD_000, PD0_IN, PD0_OUT),
+ PINMUX_DATA(D16_MARK, PD0MD_001),
+ PINMUX_DATA(IRQ0_PD_MARK, PD0MD_010),
+ PINMUX_DATA(SSCK0_PD_MARK, PD0MD_011),
+ PINMUX_DATA(DREQ2_MARK, PD0MD_100),
+ PINMUX_DATA(TIOC0A_MARK, PD0MD_101),
+
+ /* PE */
+ PINMUX_DATA(PE15_DATA, PE15MD_00, PE15_IN, PE15_OUT),
+ PINMUX_DATA(IOIS16_MARK, PE15MD_01),
+ PINMUX_DATA(RTS3_MARK, PE15MD_11),
+
+ PINMUX_DATA(PE14_DATA, PE14MD_00, PE14_IN, PE14_OUT),
+ PINMUX_DATA(CS1_MARK, PE14MD_01),
+ PINMUX_DATA(CTS3_MARK, PE14MD_11),
+
+ PINMUX_DATA(PE13_DATA, PE13MD_00, PE13_IN, PE13_OUT),
+ PINMUX_DATA(TXD3_MARK, PE13MD_11),
+
+ PINMUX_DATA(PE12_DATA, PE12MD_00, PE12_IN, PE12_OUT),
+ PINMUX_DATA(RXD3_MARK, PE12MD_11),
+
+ PINMUX_DATA(PE11_DATA, PE11MD_000, PE11_IN, PE11_OUT),
+ PINMUX_DATA(CS6_CE1B_MARK, PE11MD_001),
+ PINMUX_DATA(IRQ7_PE_MARK, PE11MD_010),
+ PINMUX_DATA(TEND1_PE_MARK, PE11MD_100),
+
+ PINMUX_DATA(PE10_DATA, PE10MD_000, PE10_IN, PE10_OUT),
+ PINMUX_DATA(CE2B_MARK, PE10MD_001),
+ PINMUX_DATA(IRQ6_PE_MARK, PE10MD_010),
+ PINMUX_DATA(TEND0_PE_MARK, PE10MD_100),
+
+ PINMUX_DATA(PE9_DATA, PE9MD_00, PE9_IN, PE9_OUT),
+ PINMUX_DATA(CS5_CE1A_MARK, PE9MD_01),
+ PINMUX_DATA(IRQ5_PE_MARK, PE9MD_10),
+ PINMUX_DATA(SCK3_MARK, PE9MD_11),
+
+ PINMUX_DATA(PE8_DATA, PE8MD_00, PE8_IN, PE8_OUT),
+ PINMUX_DATA(CE2A_MARK, PE8MD_01),
+ PINMUX_DATA(IRQ4_PE_MARK, PE8MD_10),
+ PINMUX_DATA(SCK2_MARK, PE8MD_11),
+
+ PINMUX_DATA(PE7_DATA, PE7MD_000, PE7_IN, PE7_OUT),
+ PINMUX_DATA(FRAME_MARK, PE7MD_001),
+ PINMUX_DATA(IRQ3_PE_MARK, PE7MD_010),
+ PINMUX_DATA(TXD2_MARK, PE7MD_011),
+ PINMUX_DATA(DACK1_PE_MARK, PE7MD_100),
+
+ PINMUX_DATA(PE6_DATA, PE6MD_000, PE6_IN, PE6_OUT),
+ PINMUX_DATA(A25_MARK, PE6MD_001),
+ PINMUX_DATA(IRQ2_PE_MARK, PE6MD_010),
+ PINMUX_DATA(RXD2_MARK, PE6MD_011),
+ PINMUX_DATA(DREQ1_PE_MARK, PE6MD_100),
+
+ PINMUX_DATA(PE5_DATA, PE5MD_000, PE5_IN, PE5_OUT),
+ PINMUX_DATA(A24_MARK, PE5MD_001),
+ PINMUX_DATA(IRQ1_PE_MARK, PE5MD_010),
+ PINMUX_DATA(TXD1_MARK, PE5MD_011),
+ PINMUX_DATA(DACK0_PE_MARK, PE5MD_100),
+
+ PINMUX_DATA(PE4_DATA, PE4MD_000, PE4_IN, PE4_OUT),
+ PINMUX_DATA(A23_MARK, PE4MD_001),
+ PINMUX_DATA(IRQ0_PE_MARK, PE4MD_010),
+ PINMUX_DATA(RXD1_MARK, PE4MD_011),
+ PINMUX_DATA(DREQ0_PE_MARK, PE4MD_100),
+
+ PINMUX_DATA(PE3_DATA, PE3MD_00, PE3_IN, PE3_OUT),
+ PINMUX_DATA(A22_MARK, PE3MD_01),
+ PINMUX_DATA(SCK1_MARK, PE3MD_11),
+
+ PINMUX_DATA(PE2_DATA, PE2MD_00, PE2_IN, PE2_OUT),
+ PINMUX_DATA(A21_MARK, PE2MD_01),
+ PINMUX_DATA(SCK0_MARK, PE2MD_11),
+
+ PINMUX_DATA(PE1_DATA, PE1MD_00, PE1_IN, PE1_OUT),
+ PINMUX_DATA(CS4_MARK, PE1MD_01),
+ PINMUX_DATA(MRES_MARK, PE1MD_10),
+ PINMUX_DATA(TXD0_MARK, PE1MD_11),
+
+ PINMUX_DATA(PE0_DATA, PE0MD_000, PE0_IN, PE0_OUT),
+ PINMUX_DATA(BS_MARK, PE0MD_001),
+ PINMUX_DATA(RXD0_MARK, PE0MD_011),
+ PINMUX_DATA(ADTRG_PE_MARK, PE0MD_100),
+
+ /* PF */
+ PINMUX_DATA(PF30_DATA, PF30MD_0, PF30_IN, PF30_OUT),
+ PINMUX_DATA(AUDIO_CLK_MARK, PF30MD_1),
+
+ PINMUX_DATA(PF29_DATA, PF29MD_0, PF29_IN, PF29_OUT),
+ PINMUX_DATA(SSIDATA3_MARK, PF29MD_1),
+
+ PINMUX_DATA(PF28_DATA, PF28MD_0, PF28_IN, PF28_OUT),
+ PINMUX_DATA(SSIWS3_MARK, PF28MD_1),
+
+ PINMUX_DATA(PF27_DATA, PF27MD_0, PF27_IN, PF27_OUT),
+ PINMUX_DATA(SSISCK3_MARK, PF27MD_1),
+
+ PINMUX_DATA(PF26_DATA, PF26MD_0, PF26_IN, PF26_OUT),
+ PINMUX_DATA(SSIDATA2_MARK, PF26MD_1),
+
+ PINMUX_DATA(PF25_DATA, PF25MD_0, PF25_IN, PF25_OUT),
+ PINMUX_DATA(SSIWS2_MARK, PF25MD_1),
+
+ PINMUX_DATA(PF24_DATA, PF24MD_0, PF24_IN, PF24_OUT),
+ PINMUX_DATA(SSISCK2_MARK, PF24MD_1),
+
+ PINMUX_DATA(PF23_DATA, PF23MD_00, PF23_IN, PF23_OUT),
+ PINMUX_DATA(SSIDATA1_MARK, PF23MD_01),
+ PINMUX_DATA(LCD_VEPWC_MARK, PF23MD_10),
+
+ PINMUX_DATA(PF22_DATA, PF22MD_00, PF22_IN, PF22_OUT),
+ PINMUX_DATA(SSIWS1_MARK, PF22MD_01),
+ PINMUX_DATA(LCD_VCPWC_MARK, PF22MD_10),
+
+ PINMUX_DATA(PF21_DATA, PF21MD_00, PF21_IN, PF21_OUT),
+ PINMUX_DATA(SSISCK1_MARK, PF21MD_01),
+ PINMUX_DATA(LCD_CLK_MARK, PF21MD_10),
+
+ PINMUX_DATA(PF20_DATA, PF20MD_00, PF20_IN, PF20_OUT),
+ PINMUX_DATA(SSIDATA0_MARK, PF20MD_01),
+ PINMUX_DATA(LCD_FLM_MARK, PF20MD_10),
+
+ PINMUX_DATA(PF19_DATA, PF19MD_00, PF19_IN, PF19_OUT),
+ PINMUX_DATA(SSIWS0_MARK, PF19MD_01),
+ PINMUX_DATA(LCD_M_DISP_MARK, PF19MD_10),
+
+ PINMUX_DATA(PF18_DATA, PF18MD_00, PF18_IN, PF18_OUT),
+ PINMUX_DATA(SSISCK0_MARK, PF18MD_01),
+ PINMUX_DATA(LCD_CL2_MARK, PF18MD_10),
+
+ PINMUX_DATA(PF17_DATA, PF17MD_00, PF17_IN, PF17_OUT),
+ PINMUX_DATA(FCE_MARK, PF17MD_01),
+ PINMUX_DATA(LCD_CL1_MARK, PF17MD_10),
+
+ PINMUX_DATA(PF16_DATA, PF16MD_00, PF16_IN, PF16_OUT),
+ PINMUX_DATA(FRB_MARK, PF16MD_01),
+ PINMUX_DATA(LCD_DON_MARK, PF16MD_10),
+
+ PINMUX_DATA(PF15_DATA, PF15MD_00, PF15_IN, PF15_OUT),
+ PINMUX_DATA(NAF7_MARK, PF15MD_01),
+ PINMUX_DATA(LCD_DATA15_MARK, PF15MD_10),
+
+ PINMUX_DATA(PF14_DATA, PF14MD_00, PF14_IN, PF14_OUT),
+ PINMUX_DATA(NAF6_MARK, PF14MD_01),
+ PINMUX_DATA(LCD_DATA14_MARK, PF14MD_10),
+
+ PINMUX_DATA(PF13_DATA, PF13MD_00, PF13_IN, PF13_OUT),
+ PINMUX_DATA(NAF5_MARK, PF13MD_01),
+ PINMUX_DATA(LCD_DATA13_MARK, PF13MD_10),
+
+ PINMUX_DATA(PF12_DATA, PF12MD_00, PF12_IN, PF12_OUT),
+ PINMUX_DATA(NAF4_MARK, PF12MD_01),
+ PINMUX_DATA(LCD_DATA12_MARK, PF12MD_10),
+
+ PINMUX_DATA(PF11_DATA, PF11MD_00, PF11_IN, PF11_OUT),
+ PINMUX_DATA(NAF3_MARK, PF11MD_01),
+ PINMUX_DATA(LCD_DATA11_MARK, PF11MD_10),
+
+ PINMUX_DATA(PF10_DATA, PF10MD_00, PF10_IN, PF10_OUT),
+ PINMUX_DATA(NAF2_MARK, PF10MD_01),
+ PINMUX_DATA(LCD_DATA10_MARK, PF10MD_10),
+
+ PINMUX_DATA(PF9_DATA, PF9MD_00, PF9_IN, PF9_OUT),
+ PINMUX_DATA(NAF1_MARK, PF9MD_01),
+ PINMUX_DATA(LCD_DATA9_MARK, PF9MD_10),
+
+ PINMUX_DATA(PF8_DATA, PF8MD_00, PF8_IN, PF8_OUT),
+ PINMUX_DATA(NAF0_MARK, PF8MD_01),
+ PINMUX_DATA(LCD_DATA8_MARK, PF8MD_10),
+
+ PINMUX_DATA(PF7_DATA, PF7MD_00, PF7_IN, PF7_OUT),
+ PINMUX_DATA(FSC_MARK, PF7MD_01),
+ PINMUX_DATA(LCD_DATA7_MARK, PF7MD_10),
+ PINMUX_DATA(SCS1_PF_MARK, PF7MD_11),
+
+ PINMUX_DATA(PF6_DATA, PF6MD_00, PF6_IN, PF6_OUT),
+ PINMUX_DATA(FOE_MARK, PF6MD_01),
+ PINMUX_DATA(LCD_DATA6_MARK, PF6MD_10),
+ PINMUX_DATA(SSO1_PF_MARK, PF6MD_11),
+
+ PINMUX_DATA(PF5_DATA, PF5MD_00, PF5_IN, PF5_OUT),
+ PINMUX_DATA(FCDE_MARK, PF5MD_01),
+ PINMUX_DATA(LCD_DATA5_MARK, PF5MD_10),
+ PINMUX_DATA(SSI1_PF_MARK, PF5MD_11),
+
+ PINMUX_DATA(PF4_DATA, PF4MD_00, PF4_IN, PF4_OUT),
+ PINMUX_DATA(FWE_MARK, PF4MD_01),
+ PINMUX_DATA(LCD_DATA4_MARK, PF4MD_10),
+ PINMUX_DATA(SSCK1_PF_MARK, PF4MD_11),
+
+ PINMUX_DATA(PF3_DATA, PF3MD_00, PF3_IN, PF3_OUT),
+ PINMUX_DATA(TCLKD_PF_MARK, PF3MD_01),
+ PINMUX_DATA(LCD_DATA3_MARK, PF3MD_10),
+ PINMUX_DATA(SCS0_PF_MARK, PF3MD_11),
+
+ PINMUX_DATA(PF2_DATA, PF2MD_00, PF2_IN, PF2_OUT),
+ PINMUX_DATA(TCLKC_PF_MARK, PF2MD_01),
+ PINMUX_DATA(LCD_DATA2_MARK, PF2MD_10),
+ PINMUX_DATA(SSO0_PF_MARK, PF2MD_11),
+
+ PINMUX_DATA(PF1_DATA, PF1MD_00, PF1_IN, PF1_OUT),
+ PINMUX_DATA(TCLKB_PF_MARK, PF1MD_01),
+ PINMUX_DATA(LCD_DATA1_MARK, PF1MD_10),
+ PINMUX_DATA(SSI0_PF_MARK, PF1MD_11),
+
+ PINMUX_DATA(PF0_DATA, PF0MD_00, PF0_IN, PF0_OUT),
+ PINMUX_DATA(TCLKA_PF_MARK, PF0MD_01),
+ PINMUX_DATA(LCD_DATA0_MARK, PF0MD_10),
+ PINMUX_DATA(SSCK0_PF_MARK, PF0MD_11),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+
+ /* PA */
+ PINMUX_GPIO(GPIO_PA7, PA7_DATA),
+ PINMUX_GPIO(GPIO_PA6, PA6_DATA),
+ PINMUX_GPIO(GPIO_PA5, PA5_DATA),
+ PINMUX_GPIO(GPIO_PA4, PA4_DATA),
+ PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+ PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+ PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+ PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+ /* PB */
+ PINMUX_GPIO(GPIO_PB12, PB12_DATA),
+ PINMUX_GPIO(GPIO_PB11, PB11_DATA),
+ PINMUX_GPIO(GPIO_PB10, PB10_DATA),
+ PINMUX_GPIO(GPIO_PB9, PB9_DATA),
+ PINMUX_GPIO(GPIO_PB8, PB8_DATA),
+ PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+ PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+ PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+ PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+ PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+ PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+ PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+ PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+
+ /* PC */
+ PINMUX_GPIO(GPIO_PC14, PC14_DATA),
+ PINMUX_GPIO(GPIO_PC13, PC13_DATA),
+ PINMUX_GPIO(GPIO_PC12, PC12_DATA),
+ PINMUX_GPIO(GPIO_PC11, PC11_DATA),
+ PINMUX_GPIO(GPIO_PC10, PC10_DATA),
+ PINMUX_GPIO(GPIO_PC9, PC9_DATA),
+ PINMUX_GPIO(GPIO_PC8, PC8_DATA),
+ PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+ PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+ PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+ PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+ PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+ PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+ PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+ PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+ /* PD */
+ PINMUX_GPIO(GPIO_PD15, PD15_DATA),
+ PINMUX_GPIO(GPIO_PD14, PD14_DATA),
+ PINMUX_GPIO(GPIO_PD13, PD13_DATA),
+ PINMUX_GPIO(GPIO_PD12, PD12_DATA),
+ PINMUX_GPIO(GPIO_PD11, PD11_DATA),
+ PINMUX_GPIO(GPIO_PD10, PD10_DATA),
+ PINMUX_GPIO(GPIO_PD9, PD9_DATA),
+ PINMUX_GPIO(GPIO_PD8, PD8_DATA),
+ PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+ PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+ PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+ PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+ PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+ PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+ PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+ PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+ /* PE */
+ PINMUX_GPIO(GPIO_PE15, PE15_DATA),
+ PINMUX_GPIO(GPIO_PE14, PE14_DATA),
+ PINMUX_GPIO(GPIO_PE13, PE13_DATA),
+ PINMUX_GPIO(GPIO_PE12, PE12_DATA),
+ PINMUX_GPIO(GPIO_PE11, PE11_DATA),
+ PINMUX_GPIO(GPIO_PE10, PE10_DATA),
+ PINMUX_GPIO(GPIO_PE9, PE9_DATA),
+ PINMUX_GPIO(GPIO_PE8, PE8_DATA),
+ PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+ PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+ PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+ PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+ PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+ PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+ PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+ PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+ /* PF */
+ PINMUX_GPIO(GPIO_PF30, PF30_DATA),
+ PINMUX_GPIO(GPIO_PF29, PF29_DATA),
+ PINMUX_GPIO(GPIO_PF28, PF28_DATA),
+ PINMUX_GPIO(GPIO_PF27, PF27_DATA),
+ PINMUX_GPIO(GPIO_PF26, PF26_DATA),
+ PINMUX_GPIO(GPIO_PF25, PF25_DATA),
+ PINMUX_GPIO(GPIO_PF24, PF24_DATA),
+ PINMUX_GPIO(GPIO_PF23, PF23_DATA),
+ PINMUX_GPIO(GPIO_PF22, PF22_DATA),
+ PINMUX_GPIO(GPIO_PF21, PF21_DATA),
+ PINMUX_GPIO(GPIO_PF20, PF20_DATA),
+ PINMUX_GPIO(GPIO_PF19, PF19_DATA),
+ PINMUX_GPIO(GPIO_PF18, PF18_DATA),
+ PINMUX_GPIO(GPIO_PF17, PF17_DATA),
+ PINMUX_GPIO(GPIO_PF16, PF16_DATA),
+ PINMUX_GPIO(GPIO_PF15, PF15_DATA),
+ PINMUX_GPIO(GPIO_PF14, PF14_DATA),
+ PINMUX_GPIO(GPIO_PF13, PF13_DATA),
+ PINMUX_GPIO(GPIO_PF12, PF12_DATA),
+ PINMUX_GPIO(GPIO_PF11, PF11_DATA),
+ PINMUX_GPIO(GPIO_PF10, PF10_DATA),
+ PINMUX_GPIO(GPIO_PF9, PF9_DATA),
+ PINMUX_GPIO(GPIO_PF8, PF8_DATA),
+ PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+ PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+ PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+ PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+ PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+ PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+ PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+ PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+ /* INTC */
+ PINMUX_GPIO(GPIO_FN_PINT7_PB, PINT7_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT6_PB, PINT6_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT5_PB, PINT5_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT4_PB, PINT4_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT3_PB, PINT3_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT2_PB, PINT2_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT1_PB, PINT1_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT0_PB, PINT0_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT7_PD, PINT7_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT6_PD, PINT6_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT5_PD, PINT5_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT4_PD, PINT4_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT3_PD, PINT3_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT2_PD, PINT2_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT1_PD, PINT1_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT0_PD, PINT0_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ7_PB, IRQ7_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6_PB, IRQ6_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5_PB, IRQ5_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4_PB, IRQ4_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PB, IRQ3_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PB, IRQ2_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PB, IRQ1_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PB, IRQ0_PB_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ7_PD, IRQ7_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6_PD, IRQ6_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5_PD, IRQ5_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4_PD, IRQ4_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PD, IRQ3_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PD, IRQ2_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PD, IRQ1_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PD, IRQ0_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ7_PE, IRQ7_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6_PE, IRQ6_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5_PE, IRQ5_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4_PE, IRQ4_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PE, IRQ3_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PE, IRQ2_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PE, IRQ1_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PE, IRQ0_PE_MARK),
+
+ PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQOUT, IRQOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_REFOUT, REFOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQOUT_REFOUT, IRQOUT_REFOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_UBCTRG, UBCTRG_MARK),
+
+ /* CAN */
+ PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
+ PINMUX_GPIO(GPIO_FN_CTX0_CTX1, CTX0_CTX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0_CRX1_MARK),
+
+ /* IIC3 */
+ PINMUX_GPIO(GPIO_FN_SDA3, SDA3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL3, SCL3_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
+
+ /* DMAC */
+ PINMUX_GPIO(GPIO_FN_TEND0_PD, TEND0_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND0_PE, TEND0_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0_PD, DACK0_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0_PE, DACK0_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0_PD, DREQ0_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0_PE, DREQ0_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND1_PD, TEND1_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND1_PE, TEND1_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1_PD, DACK1_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1_PE, DACK1_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1_PD, DREQ1_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1_PE, DREQ1_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK2, DACK2_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ2, DREQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK3, DACK3_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ3, DREQ3_MARK),
+
+ /* ADC */
+ PINMUX_GPIO(GPIO_FN_ADTRG_PD, ADTRG_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_ADTRG_PE, ADTRG_PE_MARK),
+
+ /* BSC */
+ PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
+ PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
+ PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
+ PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
+ PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
+ PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
+ PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
+ PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
+ PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
+ PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
+ PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
+ PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
+ PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
+ PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
+ PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
+ PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+ PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+ PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+ PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_MRES, MRES_MARK),
+ PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+ PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6_CE1B, CS6_CE1B_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5_CE1A, CS5_CE1A_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_FRAME, FRAME_MARK),
+ PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+ PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
+ PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
+ PINMUX_GPIO(GPIO_FN_CASU, CASU_MARK),
+ PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_RASU, RASU_MARK),
+ PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+ PINMUX_GPIO(GPIO_FN_CASL, CASL_MARK),
+ PINMUX_GPIO(GPIO_FN_RASL, RASL_MARK),
+ PINMUX_GPIO(GPIO_FN_WE3_DQMUU_AH_ICIO_WR, WE3_DQMUU_AH_ICIO_WR_MARK),
+ PINMUX_GPIO(GPIO_FN_WE2_DQMUL_ICIORD, WE2_DQMUL_ICIORD_MARK),
+ PINMUX_GPIO(GPIO_FN_WE1_DQMLU_WE, WE1_DQMLU_WE_MARK),
+ PINMUX_GPIO(GPIO_FN_WE0_DQMLL, WE0_DQMLL_MARK),
+ PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
+ PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
+ PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+ PINMUX_GPIO(GPIO_FN_CS7, CS7_MARK),
+
+ /* TMU */
+ PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKD_PD, TCLKD_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKC_PD, TCLKC_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKB_PD, TCLKB_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKA_PD, TCLKA_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKD_PF, TCLKD_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKC_PF, TCLKC_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKB_PF, TCLKB_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKA_PF, TCLKA_PF_MARK),
+
+ /* SSU */
+ PINMUX_GPIO(GPIO_FN_SCS0_PD, SCS0_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_SSO0_PD, SSO0_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI0_PD, SSI0_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_SSCK0_PD, SSCK0_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCS0_PF, SCS0_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_SSO0_PF, SSO0_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI0_PF, SSI0_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_SSCK0_PF, SSCK0_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_SCS1_PD, SCS1_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_SSO1_PD, SSO1_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI1_PD, SSI1_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_SSCK1_PD, SSCK1_PD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCS1_PF, SCS1_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_SSO1_PF, SSO1_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI1_PF, SSI1_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_SSCK1_PF, SSCK1_PF_MARK),
+
+ /* SCIF */
+ PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+
+ /* SSI */
+ PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA0, SSIDATA0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
+
+ /* FLCTL */
+ PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+ PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF7, NAF7_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF6, NAF6_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF5, NAF5_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF4, NAF4_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF3, NAF3_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF2, NAF2_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF1, NAF1_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF0, NAF0_MARK),
+ PINMUX_GPIO(GPIO_FN_FSC, FSC_MARK),
+ PINMUX_GPIO(GPIO_FN_FOE, FOE_MARK),
+ PINMUX_GPIO(GPIO_FN_FCDE, FCDE_MARK),
+ PINMUX_GPIO(GPIO_FN_FWE, FWE_MARK),
+
+ /* LCDC */
+ PINMUX_GPIO(GPIO_FN_LCD_VEPWC, LCD_VEPWC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_VCPWC, LCD_VCPWC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_FLM, LCD_FLM_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_CL2, LCD_CL2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_CL1, LCD_CL1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DON, LCD_DON_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PBIORL", 0xfffe3886, 16, 1) {
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PB11_IN, PB11_OUT,
+ PB10_IN, PB10_OUT,
+ PB9_IN, PB9_OUT,
+ PB8_IN, PB8_OUT,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCRL4", 0xfffe3890, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCRL3", 0xfffe3892, 16, 4) {
+ PB11MD_0, PB11MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB10MD_0, PB10MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB9MD_00, PB9MD_01, PB9MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB8MD_00, PB8MD_01, PB8MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCRL2", 0xfffe3894, 16, 4) {
+ PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCRL1", 0xfffe3896, 16, 4) {
+ PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB0MD_00, PB0MD_01, PB0MD_10, PB0MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("IFCR", 0xfffe38a2, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB12IRQ_00, PB12IRQ_01, PB12IRQ_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCIORL", 0xfffe3906, 16, 1) {
+ 0, 0,
+ PC14_IN, PC14_OUT,
+ PC13_IN, PC13_OUT,
+ PC12_IN, PC12_OUT,
+ PC11_IN, PC11_OUT,
+ PC10_IN, PC10_OUT,
+ PC9_IN, PC9_OUT,
+ PC8_IN, PC8_OUT,
+ PC7_IN, PC7_OUT,
+ PC6_IN, PC6_OUT,
+ PC5_IN, PC5_OUT,
+ PC4_IN, PC4_OUT,
+ PC3_IN, PC3_OUT,
+ PC2_IN, PC2_OUT,
+ PC1_IN, PC1_OUT,
+ PC0_IN, PC0_OUT }
+ },
+ { PINMUX_CFG_REG("PCCRL4", 0xfffe3910, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC14MD_0, PC14MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC13MD_0, PC13MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC12MD_0, PC12MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCRL3", 0xfffe3912, 16, 4) {
+ PC11MD_00, PC11MD_01, PC11MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC10MD_00, PC10MD_01, PC10MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC9MD_0, PC9MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC8MD_0, PC8MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCRL2", 0xfffe3914, 16, 4) {
+ PC7MD_0, PC7MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC6MD_0, PC6MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC5MD_0, PC5MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC4MD_0, PC4MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCRL1", 0xfffe3916, 16, 4) {
+ PC3MD_0, PC3MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC2MD_0, PC2MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC1MD_0, PC1MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC0MD_00, PC0MD_01, PC0MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDIORL", 0xfffe3986, 16, 1) {
+ PD15_IN, PD15_OUT,
+ PD14_IN, PD14_OUT,
+ PD13_IN, PD13_OUT,
+ PD12_IN, PD12_OUT,
+ PD11_IN, PD11_OUT,
+ PD10_IN, PD10_OUT,
+ PD9_IN, PD9_OUT,
+ PD8_IN, PD8_OUT,
+ PD7_IN, PD7_OUT,
+ PD6_IN, PD6_OUT,
+ PD5_IN, PD5_OUT,
+ PD4_IN, PD4_OUT,
+ PD3_IN, PD3_OUT,
+ PD2_IN, PD2_OUT,
+ PD1_IN, PD1_OUT,
+ PD0_IN, PD0_OUT }
+ },
+ { PINMUX_CFG_REG("PDCRL4", 0xfffe3990, 16, 4) {
+ PD15MD_000, PD15MD_001, PD15MD_010, 0,
+ PD15MD_100, PD15MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD14MD_000, PD14MD_001, PD14MD_010, 0,
+ 0, PD14MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD13MD_000, PD13MD_001, PD13MD_010, 0,
+ PD13MD_100, PD13MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD12MD_000, PD12MD_001, PD12MD_010, 0,
+ PD12MD_100, PD12MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCRL3", 0xfffe3992, 16, 4) {
+ PD11MD_000, PD11MD_001, PD11MD_010, 0,
+ PD11MD_100, PD11MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD10MD_000, PD10MD_001, PD10MD_010, 0,
+ PD10MD_100, PD10MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD9MD_000, PD9MD_001, PD9MD_010, 0,
+ PD9MD_100, PD9MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD8MD_000, PD8MD_001, PD8MD_010, 0,
+ PD8MD_100, PD8MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCRL2", 0xfffe3994, 16, 4) {
+ PD7MD_000, PD7MD_001, PD7MD_010, PD7MD_011,
+ PD7MD_100, PD7MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD6MD_000, PD6MD_001, PD6MD_010, PD6MD_011,
+ PD6MD_100, PD6MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD5MD_000, PD5MD_001, PD5MD_010, PD5MD_011,
+ PD5MD_100, PD5MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD4MD_000, PD4MD_001, PD4MD_010, PD4MD_011,
+ PD4MD_100, PD4MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCRL1", 0xfffe3996, 16, 4) {
+ PD3MD_000, PD3MD_001, PD3MD_010, PD3MD_011,
+ PD3MD_100, PD3MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD2MD_000, PD2MD_001, PD2MD_010, PD2MD_011,
+ PD2MD_100, PD2MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD1MD_000, PD1MD_001, PD1MD_010, PD1MD_011,
+ PD1MD_100, PD1MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD0MD_000, PD0MD_001, PD0MD_010, PD0MD_011,
+ PD0MD_100, PD0MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PEIORL", 0xfffe3a06, 16, 1) {
+ PE15_IN, PE15_OUT,
+ PE14_IN, PE14_OUT,
+ PE13_IN, PE13_OUT,
+ PE12_IN, PE12_OUT,
+ PE11_IN, PE11_OUT,
+ PE10_IN, PE10_OUT,
+ PE9_IN, PE9_OUT,
+ PE8_IN, PE8_OUT,
+ PE7_IN, PE7_OUT,
+ PE6_IN, PE6_OUT,
+ PE5_IN, PE5_OUT,
+ PE4_IN, PE4_OUT,
+ PE3_IN, PE3_OUT,
+ PE2_IN, PE2_OUT,
+ PE1_IN, PE1_OUT,
+ PE0_IN, PE0_OUT }
+ },
+ { PINMUX_CFG_REG("PECRL4", 0xfffe3a10, 16, 4) {
+ PE15MD_00, PE15MD_01, 0, PE15MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE14MD_00, PE14MD_01, 0, PE14MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE13MD_00, 0, 0, PE13MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE12MD_00, 0, 0, PE12MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PECRL3", 0xfffe3a12, 16, 4) {
+ PE11MD_000, PE11MD_001, PE11MD_010, 0,
+ PE11MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE10MD_000, PE10MD_001, PE10MD_010, 0,
+ PE10MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE9MD_00, PE9MD_01, PE9MD_10, PE9MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE8MD_00, PE8MD_01, PE8MD_10, PE8MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PECRL2", 0xfffe3a14, 16, 4) {
+ PE7MD_000, PE7MD_001, PE7MD_010, PE7MD_011,
+ PE7MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE6MD_000, PE6MD_001, PE6MD_010, PE6MD_011,
+ PE6MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE5MD_000, PE5MD_001, PE5MD_010, PE5MD_011,
+ PE5MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE4MD_000, PE4MD_001, PE4MD_010, PE4MD_011,
+ PE4MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PECRL1", 0xfffe3a16, 16, 4) {
+ PE3MD_00, PE3MD_01, 0, PE3MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE2MD_00, PE2MD_01, 0, PE2MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE1MD_00, PE1MD_01, PE1MD_10, PE1MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE0MD_000, PE0MD_001, 0, PE0MD_011,
+ PE0MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFIORH", 0xfffe3a84, 16, 1) {
+ 0, 0,
+ PF30_IN, PF30_OUT,
+ PF29_IN, PF29_OUT,
+ PF28_IN, PF28_OUT,
+ PF27_IN, PF27_OUT,
+ PF26_IN, PF26_OUT,
+ PF25_IN, PF25_OUT,
+ PF24_IN, PF24_OUT,
+ PF23_IN, PF23_OUT,
+ PF22_IN, PF22_OUT,
+ PF21_IN, PF21_OUT,
+ PF20_IN, PF20_OUT,
+ PF19_IN, PF19_OUT,
+ PF18_IN, PF18_OUT,
+ PF17_IN, PF17_OUT,
+ PF16_IN, PF16_OUT }
+ },
+ { PINMUX_CFG_REG("PFIORL", 0xfffe3a86, 16, 1) {
+ PF15_IN, PF15_OUT,
+ PF14_IN, PF14_OUT,
+ PF13_IN, PF13_OUT,
+ PF12_IN, PF12_OUT,
+ PF11_IN, PF11_OUT,
+ PF10_IN, PF10_OUT,
+ PF9_IN, PF9_OUT,
+ PF8_IN, PF8_OUT,
+ PF7_IN, PF7_OUT,
+ PF6_IN, PF6_OUT,
+ PF5_IN, PF5_OUT,
+ PF4_IN, PF4_OUT,
+ PF3_IN, PF3_OUT,
+ PF2_IN, PF2_OUT,
+ PF1_IN, PF1_OUT,
+ PF0_IN, PF0_OUT }
+ },
+ { PINMUX_CFG_REG("PFCRH4", 0xfffe3a88, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF30MD_0, PF30MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF29MD_0, PF29MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF28MD_0, PF28MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCRH3", 0xfffe3a8a, 16, 4) {
+ PF27MD_0, PF27MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF26MD_0, PF26MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF25MD_0, PF25MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF24MD_0, PF24MD_1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCRH2", 0xfffe3a8c, 16, 4) {
+ PF23MD_00, PF23MD_01, PF23MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF22MD_00, PF22MD_01, PF22MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF21MD_00, PF21MD_01, PF21MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF20MD_00, PF20MD_01, PF20MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCRH1", 0xfffe3a8e, 16, 4) {
+ PF19MD_00, PF19MD_01, PF19MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF18MD_00, PF18MD_01, PF18MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF17MD_00, PF17MD_01, PF17MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF16MD_00, PF16MD_01, PF16MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCRL4", 0xfffe3a90, 16, 4) {
+ PF15MD_00, PF15MD_01, PF15MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF14MD_00, PF14MD_01, PF14MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF13MD_00, PF13MD_01, PF13MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF12MD_00, PF12MD_01, PF12MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCRL3", 0xfffe3a92, 16, 4) {
+ PF11MD_00, PF11MD_01, PF11MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF10MD_00, PF10MD_01, PF10MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF9MD_00, PF9MD_01, PF9MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF8MD_00, PF8MD_01, PF8MD_10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCRL2", 0xfffe3a94, 16, 4) {
+ PF7MD_00, PF7MD_01, PF7MD_10, PF7MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF6MD_00, PF6MD_01, PF6MD_10, PF6MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF5MD_00, PF5MD_01, PF5MD_10, PF5MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF4MD_00, PF4MD_01, PF4MD_10, PF4MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCRL1", 0xfffe3a96, 16, 4) {
+ PF3MD_00, PF3MD_01, PF3MD_10, PF3MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF2MD_00, PF2MD_01, PF2MD_10, PF2MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF1MD_00, PF1MD_01, PF1MD_10, PF1MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF0MD_00, PF0MD_01, PF0MD_10, PF0MD_11,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADRL", 0xfffe3802, 16) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA }
+ },
+ { PINMUX_DATA_REG("PBDRL", 0xfffe3882, 16) {
+ 0, 0, 0, PB12_DATA,
+ PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA }
+ },
+ { PINMUX_DATA_REG("PCDRL", 0xfffe3902, 16) {
+ 0, PC14_DATA, PC13_DATA, PC12_DATA,
+ PC11_DATA, PC10_DATA, PC9_DATA, PC8_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+ },
+ { PINMUX_DATA_REG("PDDRL", 0xfffe3982, 16) {
+ PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+ PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+ },
+ { PINMUX_DATA_REG("PEDRL", 0xfffe3a02, 16) {
+ PE15_DATA, PE14_DATA, PE13_DATA, PE12_DATA,
+ PE11_DATA, PE10_DATA, PE9_DATA, PE8_DATA,
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
+ },
+ { PINMUX_DATA_REG("PFDRH", 0xfffe3a80, 16) {
+ 0, PF30_DATA, PF29_DATA, PF28_DATA,
+ PF27_DATA, PF26_DATA, PF25_DATA, PF24_DATA,
+ PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
+ PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA }
+ },
+ { PINMUX_DATA_REG("PFDRL", 0xfffe3a82, 16) {
+ PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
+ PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+ },
+ { },
+};
+
+struct sh_pfc_soc_info sh7203_pinmux_info = {
+ .name = "sh7203_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PA7,
+ .last_gpio = GPIO_FN_LCD_DATA0,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7264.c b/drivers/pinctrl/sh-pfc/pfc-sh7264.c
new file mode 100644
index 000000000000..2ba5639dcf34
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7264.c
@@ -0,0 +1,2131 @@
+/*
+ * SH7264 Pinmux
+ *
+ * Copyright (C) 2012 Renesas Electronics Europe Ltd
+ *
+ * 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/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7264.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ /* Port A */
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ /* Port B */
+ PB22_DATA, PB21_DATA, PB20_DATA,
+ PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA,
+ PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+ PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA,
+ /* Port C */
+ PC10_DATA, PC9_DATA, PC8_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ /* Port D */
+ PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+ PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+ /* Port E */
+ PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ /* Port F */
+ PF12_DATA,
+ PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+ /* Port G */
+ PG24_DATA,
+ PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+ PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA,
+ PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+ PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+ /* Port H */
+ /* NOTE - Port H does not have a Data Register, but PH Data is
+ connected to PH Port Register */
+ PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+ /* Port I - not on device */
+ /* Port J */
+ PJ12_DATA,
+ PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
+ /* Port K */
+ PK12_DATA,
+ PK11_DATA, PK10_DATA, PK9_DATA, PK8_DATA,
+ PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
+ PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ FORCE_IN,
+ /* Port A */
+ PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+ /* Port B */
+ PB22_IN, PB21_IN, PB20_IN,
+ PB19_IN, PB18_IN, PB17_IN, PB16_IN,
+ PB15_IN, PB14_IN, PB13_IN, PB12_IN,
+ PB11_IN, PB10_IN, PB9_IN, PB8_IN,
+ PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+ PB3_IN, PB2_IN, PB1_IN,
+ /* Port C */
+ PC10_IN, PC9_IN, PC8_IN,
+ PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+ PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+ /* Port D */
+ PD15_IN, PD14_IN, PD13_IN, PD12_IN,
+ PD11_IN, PD10_IN, PD9_IN, PD8_IN,
+ PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+ PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+ /* Port E */
+ PE5_IN, PE4_IN,
+ PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+ /* Port F */
+ PF12_IN,
+ PF11_IN, PF10_IN, PF9_IN, PF8_IN,
+ PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+ PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+ /* Port G */
+ PG24_IN,
+ PG23_IN, PG22_IN, PG21_IN, PG20_IN,
+ PG19_IN, PG18_IN, PG17_IN, PG16_IN,
+ PG15_IN, PG14_IN, PG13_IN, PG12_IN,
+ PG11_IN, PG10_IN, PG9_IN, PG8_IN,
+ PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+ PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+ /* Port H - Port H does not have a Data Register */
+ /* Port I - not on device */
+ /* Port J */
+ PJ12_IN,
+ PJ11_IN, PJ10_IN, PJ9_IN, PJ8_IN,
+ PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+ PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
+ /* Port K */
+ PK12_IN,
+ PK11_IN, PK10_IN, PK9_IN, PK8_IN,
+ PK7_IN, PK6_IN, PK5_IN, PK4_IN,
+ PK3_IN, PK2_IN, PK1_IN, PK0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ FORCE_OUT,
+ /* Port A */
+ PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+ /* Port B */
+ PB22_OUT, PB21_OUT, PB20_OUT,
+ PB19_OUT, PB18_OUT, PB17_OUT, PB16_OUT,
+ PB15_OUT, PB14_OUT, PB13_OUT, PB12_OUT,
+ PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
+ PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+ PB3_OUT, PB2_OUT, PB1_OUT,
+ /* Port C */
+ PC10_OUT, PC9_OUT, PC8_OUT,
+ PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+ PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+ /* Port D */
+ PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
+ PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
+ PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+ PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+ /* Port E */
+ PE5_OUT, PE4_OUT,
+ PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+ /* Port F */
+ PF12_OUT,
+ PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
+ PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+ PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+ /* Port G */
+ PG24_OUT,
+ PG23_OUT, PG22_OUT, PG21_OUT, PG20_OUT,
+ PG19_OUT, PG18_OUT, PG17_OUT, PG16_OUT,
+ PG15_OUT, PG14_OUT, PG13_OUT, PG12_OUT,
+ PG11_OUT, PG10_OUT, PG9_OUT, PG8_OUT,
+ PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+ PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+ /* Port H - Port H does not have a Data Register */
+ /* Port I - not on device */
+ /* Port J */
+ PJ12_OUT,
+ PJ11_OUT, PJ10_OUT, PJ9_OUT, PJ8_OUT,
+ PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+ PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
+ /* Port K */
+ PK12_OUT,
+ PK11_OUT, PK10_OUT, PK9_OUT, PK8_OUT,
+ PK7_OUT, PK6_OUT, PK5_OUT, PK4_OUT,
+ PK3_OUT, PK2_OUT, PK1_OUT, PK0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ /* Port A */
+ PA3_IOR_IN, PA3_IOR_OUT,
+ PA2_IOR_IN, PA2_IOR_OUT,
+ PA1_IOR_IN, PA1_IOR_OUT,
+ PA0_IOR_IN, PA0_IOR_OUT,
+
+ /* Port B */
+ PB11_IOR_IN, PB11_IOR_OUT,
+ PB10_IOR_IN, PB10_IOR_OUT,
+ PB9_IOR_IN, PB9_IOR_OUT,
+ PB8_IOR_IN, PB8_IOR_OUT,
+
+ PB22MD_00, PB22MD_01, PB22MD_10,
+ PB21MD_0, PB21MD_1,
+ PB20MD_0, PB20MD_1,
+ PB19MD_00, PB19MD_01, PB19MD_10, PB19MD_11,
+ PB18MD_00, PB18MD_01, PB18MD_10, PB18MD_11,
+ PB17MD_00, PB17MD_01, PB17MD_10, PB17MD_11,
+ PB16MD_00, PB16MD_01, PB16MD_10, PB16MD_11,
+ PB15MD_00, PB15MD_01, PB15MD_10, PB15MD_11,
+ PB14MD_00, PB14MD_01, PB14MD_10, PB14MD_11,
+ PB13MD_00, PB13MD_01, PB13MD_10, PB13MD_11,
+ PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
+ PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11,
+ PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11,
+ PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11,
+ PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11,
+ PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
+ PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
+ PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
+ PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
+ PB3MD_0, PB3MD_1,
+ PB2MD_0, PB2MD_1,
+ PB1MD_0, PB1MD_1,
+
+ /* Port C */
+ PC14_IOR_IN, PC14_IOR_OUT,
+ PC13_IOR_IN, PC13_IOR_OUT,
+ PC12_IOR_IN, PC12_IOR_OUT,
+ PC11_IOR_IN, PC11_IOR_OUT,
+ PC10_IOR_IN, PC10_IOR_OUT,
+ PC9_IOR_IN, PC9_IOR_OUT,
+ PC8_IOR_IN, PC8_IOR_OUT,
+ PC7_IOR_IN, PC7_IOR_OUT,
+ PC6_IOR_IN, PC6_IOR_OUT,
+ PC5_IOR_IN, PC5_IOR_OUT,
+ PC4_IOR_IN, PC4_IOR_OUT,
+ PC3_IOR_IN, PC3_IOR_OUT,
+ PC2_IOR_IN, PC2_IOR_OUT,
+ PC1_IOR_IN, PC1_IOR_OUT,
+ PC0_IOR_IN, PC0_IOR_OUT,
+
+ PC10MD_0, PC10MD_1,
+ PC9MD_0, PC9MD_1,
+ PC8MD_00, PC8MD_01, PC8MD_10, PC8MD_11,
+ PC7MD_00, PC7MD_01, PC7MD_10, PC7MD_11,
+ PC6MD_00, PC6MD_01, PC6MD_10, PC6MD_11,
+ PC5MD_00, PC5MD_01, PC5MD_10, PC5MD_11,
+ PC4MD_0, PC4MD_1,
+ PC3MD_0, PC3MD_1,
+ PC2MD_0, PC2MD_1,
+ PC1MD_0, PC1MD_1,
+ PC0MD_0, PC0MD_1,
+
+ /* Port D */
+ PD15_IOR_IN, PD15_IOR_OUT,
+ PD14_IOR_IN, PD14_IOR_OUT,
+ PD13_IOR_IN, PD13_IOR_OUT,
+ PD12_IOR_IN, PD12_IOR_OUT,
+ PD11_IOR_IN, PD11_IOR_OUT,
+ PD10_IOR_IN, PD10_IOR_OUT,
+ PD9_IOR_IN, PD9_IOR_OUT,
+ PD8_IOR_IN, PD8_IOR_OUT,
+ PD7_IOR_IN, PD7_IOR_OUT,
+ PD6_IOR_IN, PD6_IOR_OUT,
+ PD5_IOR_IN, PD5_IOR_OUT,
+ PD4_IOR_IN, PD4_IOR_OUT,
+ PD3_IOR_IN, PD3_IOR_OUT,
+ PD2_IOR_IN, PD2_IOR_OUT,
+ PD1_IOR_IN, PD1_IOR_OUT,
+ PD0_IOR_IN, PD0_IOR_OUT,
+
+ PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11,
+ PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11,
+ PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11,
+ PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11,
+ PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11,
+ PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11,
+ PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11,
+ PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11,
+ PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11,
+ PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11,
+ PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11,
+ PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11,
+ PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11,
+ PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11,
+ PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11,
+ PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11,
+
+ /* Port E */
+ PE5_IOR_IN, PE5_IOR_OUT,
+ PE4_IOR_IN, PE4_IOR_OUT,
+ PE3_IOR_IN, PE3_IOR_OUT,
+ PE2_IOR_IN, PE2_IOR_OUT,
+ PE1_IOR_IN, PE1_IOR_OUT,
+ PE0_IOR_IN, PE0_IOR_OUT,
+
+ PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11,
+ PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11,
+ PE3MD_00, PE3MD_01, PE3MD_10, PE3MD_11,
+ PE2MD_00, PE2MD_01, PE2MD_10, PE2MD_11,
+ PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+ PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+ PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11,
+
+ /* Port F */
+ PF12_IOR_IN, PF12_IOR_OUT,
+ PF11_IOR_IN, PF11_IOR_OUT,
+ PF10_IOR_IN, PF10_IOR_OUT,
+ PF9_IOR_IN, PF9_IOR_OUT,
+ PF8_IOR_IN, PF8_IOR_OUT,
+ PF7_IOR_IN, PF7_IOR_OUT,
+ PF6_IOR_IN, PF6_IOR_OUT,
+ PF5_IOR_IN, PF5_IOR_OUT,
+ PF4_IOR_IN, PF4_IOR_OUT,
+ PF3_IOR_IN, PF3_IOR_OUT,
+ PF2_IOR_IN, PF2_IOR_OUT,
+ PF1_IOR_IN, PF1_IOR_OUT,
+ PF0_IOR_IN, PF0_IOR_OUT,
+
+ PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+ PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+ PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+ PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+ PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+ PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+ PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+ PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+ PF8MD_00, PF8MD_01, PF8MD_10, PF8MD_11,
+ PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+ PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+ PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+ PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+ PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+ PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+ PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+ PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+ PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+ PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+ PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+ PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+ PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+ PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+ PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+ PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+
+ /* Port G */
+ PG24_IOR_IN, PG24_IOR_OUT,
+ PG23_IOR_IN, PG23_IOR_OUT,
+ PG22_IOR_IN, PG22_IOR_OUT,
+ PG21_IOR_IN, PG21_IOR_OUT,
+ PG20_IOR_IN, PG20_IOR_OUT,
+ PG19_IOR_IN, PG19_IOR_OUT,
+ PG18_IOR_IN, PG18_IOR_OUT,
+ PG17_IOR_IN, PG17_IOR_OUT,
+ PG16_IOR_IN, PG16_IOR_OUT,
+ PG15_IOR_IN, PG15_IOR_OUT,
+ PG14_IOR_IN, PG14_IOR_OUT,
+ PG13_IOR_IN, PG13_IOR_OUT,
+ PG12_IOR_IN, PG12_IOR_OUT,
+ PG11_IOR_IN, PG11_IOR_OUT,
+ PG10_IOR_IN, PG10_IOR_OUT,
+ PG9_IOR_IN, PG9_IOR_OUT,
+ PG8_IOR_IN, PG8_IOR_OUT,
+ PG7_IOR_IN, PG7_IOR_OUT,
+ PG6_IOR_IN, PG6_IOR_OUT,
+ PG5_IOR_IN, PG5_IOR_OUT,
+ PG4_IOR_IN, PG4_IOR_OUT,
+ PG3_IOR_IN, PG3_IOR_OUT,
+ PG2_IOR_IN, PG2_IOR_OUT,
+ PG1_IOR_IN, PG1_IOR_OUT,
+ PG0_IOR_IN, PG0_IOR_OUT,
+
+ PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11,
+ PG23MD_00, PG23MD_01, PG23MD_10, PG23MD_11,
+ PG22MD_00, PG22MD_01, PG22MD_10, PG22MD_11,
+ PG21MD_00, PG21MD_01, PG21MD_10, PG21MD_11,
+ PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+ PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+ PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+ PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+ PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+ PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+ PG17MD_000, PG17MD_001, PG17MD_010, PG17MD_011,
+ PG17MD_100, PG17MD_101, PG17MD_110, PG17MD_111,
+ PG16MD_000, PG16MD_001, PG16MD_010, PG16MD_011,
+ PG16MD_100, PG16MD_101, PG16MD_110, PG16MD_111,
+ PG15MD_000, PG15MD_001, PG15MD_010, PG15MD_011,
+ PG15MD_100, PG15MD_101, PG15MD_110, PG15MD_111,
+ PG14MD_000, PG14MD_001, PG14MD_010, PG14MD_011,
+ PG14MD_100, PG14MD_101, PG14MD_110, PG14MD_111,
+ PG13MD_000, PG13MD_001, PG13MD_010, PG13MD_011,
+ PG13MD_100, PG13MD_101, PG13MD_110, PG13MD_111,
+ PG12MD_000, PG12MD_001, PG12MD_010, PG12MD_011,
+ PG12MD_100, PG12MD_101, PG12MD_110, PG12MD_111,
+ PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+ PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+ PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+ PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+ PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+ PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+ PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+ PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+ PG7MD_00, PG7MD_01, PG7MD_10, PG7MD_11,
+ PG6MD_00, PG6MD_01, PG6MD_10, PG6MD_11,
+ PG5MD_00, PG5MD_01, PG5MD_10, PG5MD_11,
+ PG4MD_00, PG4MD_01, PG4MD_10, PG4MD_11,
+ PG3MD_00, PG3MD_01, PG3MD_10, PG3MD_11,
+ PG2MD_00, PG2MD_01, PG2MD_10, PG2MD_11,
+ PG1MD_00, PG1MD_01, PG1MD_10, PG1MD_11,
+ PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+ PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+
+ /* Port H */
+ PH7MD_0, PH7MD_1,
+ PH6MD_0, PH6MD_1,
+ PH5MD_0, PH5MD_1,
+ PH4MD_0, PH4MD_1,
+ PH3MD_0, PH3MD_1,
+ PH2MD_0, PH2MD_1,
+ PH1MD_0, PH1MD_1,
+ PH0MD_0, PH0MD_1,
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PJ11_IOR_IN, PJ11_IOR_OUT,
+ PJ10_IOR_IN, PJ10_IOR_OUT,
+ PJ9_IOR_IN, PJ9_IOR_OUT,
+ PJ8_IOR_IN, PJ8_IOR_OUT,
+ PJ7_IOR_IN, PJ7_IOR_OUT,
+ PJ6_IOR_IN, PJ6_IOR_OUT,
+ PJ5_IOR_IN, PJ5_IOR_OUT,
+ PJ4_IOR_IN, PJ4_IOR_OUT,
+ PJ3_IOR_IN, PJ3_IOR_OUT,
+ PJ2_IOR_IN, PJ2_IOR_OUT,
+ PJ1_IOR_IN, PJ1_IOR_OUT,
+ PJ0_IOR_IN, PJ0_IOR_OUT,
+
+ PJ11MD_00, PJ11MD_01, PJ11MD_10, PJ11MD_11,
+ PJ10MD_00, PJ10MD_01, PJ10MD_10, PJ10MD_11,
+ PJ9MD_00, PJ9MD_01, PJ9MD_10, PJ9MD_11,
+ PJ8MD_00, PJ8MD_01, PJ8MD_10, PJ8MD_11,
+ PJ7MD_00, PJ7MD_01, PJ7MD_10, PJ7MD_11,
+ PJ6MD_00, PJ6MD_01, PJ6MD_10, PJ6MD_11,
+ PJ5MD_00, PJ5MD_01, PJ5MD_10, PJ5MD_11,
+ PJ4MD_00, PJ4MD_01, PJ4MD_10, PJ4MD_11,
+ PJ3MD_00, PJ3MD_01, PJ3MD_10, PJ3MD_11,
+ PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+ PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+ PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+ PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+ PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+ PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+
+ /* Port K */
+ PK11_IOR_IN, PK11_IOR_OUT,
+ PK10_IOR_IN, PK10_IOR_OUT,
+ PK9_IOR_IN, PK9_IOR_OUT,
+ PK8_IOR_IN, PK8_IOR_OUT,
+ PK7_IOR_IN, PK7_IOR_OUT,
+ PK6_IOR_IN, PK6_IOR_OUT,
+ PK5_IOR_IN, PK5_IOR_OUT,
+ PK4_IOR_IN, PK4_IOR_OUT,
+ PK3_IOR_IN, PK3_IOR_OUT,
+ PK2_IOR_IN, PK2_IOR_OUT,
+ PK1_IOR_IN, PK1_IOR_OUT,
+ PK0_IOR_IN, PK0_IOR_OUT,
+
+ PK11MD_00, PK11MD_01, PK11MD_10, PK11MD_11,
+ PK10MD_00, PK10MD_01, PK10MD_10, PK10MD_11,
+ PK9MD_00, PK9MD_01, PK9MD_10, PK9MD_11,
+ PK8MD_00, PK8MD_01, PK8MD_10, PK8MD_11,
+ PK7MD_00, PK7MD_01, PK7MD_10, PK7MD_11,
+ PK6MD_00, PK6MD_01, PK6MD_10, PK6MD_11,
+ PK5MD_00, PK5MD_01, PK5MD_10, PK5MD_11,
+ PK4MD_00, PK4MD_01, PK4MD_10, PK4MD_11,
+ PK3MD_00, PK3MD_01, PK3MD_10, PK3MD_11,
+ PK2MD_00, PK2MD_01, PK2MD_10, PK2MD_11,
+ PK1MD_00, PK1MD_01, PK1MD_10, PK1MD_11,
+ PK0MD_00, PK0MD_01, PK0MD_10, PK0MD_11,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ /* Port A */
+
+ /* Port B */
+
+ /* Port C */
+
+ /* Port D */
+
+ /* Port E */
+
+ /* Port F */
+
+ /* Port G */
+
+ /* Port H */
+ PHAN7_MARK, PHAN6_MARK, PHAN5_MARK, PHAN4_MARK,
+ PHAN3_MARK, PHAN2_MARK, PHAN1_MARK, PHAN0_MARK,
+
+ /* Port I - not on device */
+
+ /* Port J */
+
+ /* Port K */
+
+ IRQ7_PC_MARK, IRQ6_PC_MARK, IRQ5_PC_MARK, IRQ4_PC_MARK,
+ IRQ3_PG_MARK, IRQ2_PG_MARK, IRQ1_PJ_MARK, IRQ0_PJ_MARK,
+ IRQ3_PE_MARK, IRQ2_PE_MARK, IRQ1_PE_MARK, IRQ0_PE_MARK,
+
+ PINT7_PG_MARK, PINT6_PG_MARK, PINT5_PG_MARK, PINT4_PG_MARK,
+ PINT3_PG_MARK, PINT2_PG_MARK, PINT1_PG_MARK, PINT0_PG_MARK,
+
+ SD_CD_MARK, SD_D0_MARK, SD_D1_MARK, SD_D2_MARK, SD_D3_MARK,
+ SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK,
+ CRX0_MARK, CRX1_MARK,
+ CTX0_MARK, CTX1_MARK,
+
+ PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
+ PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
+ PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
+ PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
+ IERXD_MARK, IETXD_MARK,
+ CRX0_CRX1_MARK,
+ WDTOVF_MARK,
+
+ CRX0X1_MARK,
+
+ /* DMAC */
+ TEND0_MARK, DACK0_MARK, DREQ0_MARK,
+ TEND1_MARK, DACK1_MARK, DREQ1_MARK,
+
+ /* ADC */
+ ADTRG_MARK,
+
+ /* BSC */
+ A25_MARK, A24_MARK,
+ A23_MARK, A22_MARK, A21_MARK, A20_MARK,
+ A19_MARK, A18_MARK, A17_MARK, A16_MARK,
+ A15_MARK, A14_MARK, A13_MARK, A12_MARK,
+ A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+ A7_MARK, A6_MARK, A5_MARK, A4_MARK,
+ A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+ D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+ D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+ D7_MARK, D6_MARK, D5_MARK, D4_MARK,
+ D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+ BS_MARK,
+ CS4_MARK, CS3_MARK, CS2_MARK, CS1_MARK, CS0_MARK,
+ CS6CE1B_MARK, CS5CE1A_MARK,
+ CE2A_MARK, CE2B_MARK,
+ RD_MARK, RDWR_MARK,
+ ICIOWRAH_MARK,
+ ICIORD_MARK,
+ WE1DQMUWE_MARK,
+ WE0DQML_MARK,
+ RAS_MARK, CAS_MARK, CKE_MARK,
+ WAIT_MARK, BREQ_MARK, BACK_MARK, IOIS16_MARK,
+
+ /* TMU */
+ TIOC0A_MARK, TIOC0B_MARK, TIOC0C_MARK, TIOC0D_MARK,
+ TIOC1A_MARK, TIOC1B_MARK,
+ TIOC2A_MARK, TIOC2B_MARK,
+ TIOC3A_MARK, TIOC3B_MARK, TIOC3C_MARK, TIOC3D_MARK,
+ TIOC4A_MARK, TIOC4B_MARK, TIOC4C_MARK, TIOC4D_MARK,
+ TCLKA_MARK, TCLKB_MARK, TCLKC_MARK, TCLKD_MARK,
+
+ /* SCIF */
+ SCK0_MARK, SCK1_MARK, SCK2_MARK, SCK3_MARK,
+ RXD0_MARK, RXD1_MARK, RXD2_MARK, RXD3_MARK,
+ TXD0_MARK, TXD1_MARK, TXD2_MARK, TXD3_MARK,
+ RXD4_MARK, RXD5_MARK, RXD6_MARK, RXD7_MARK,
+ TXD4_MARK, TXD5_MARK, TXD6_MARK, TXD7_MARK,
+ RTS1_MARK, RTS3_MARK,
+ CTS1_MARK, CTS3_MARK,
+
+ /* RSPI */
+ RSPCK0_MARK, RSPCK1_MARK,
+ MOSI0_MARK, MOSI1_MARK,
+ MISO0_PF12_MARK, MISO1_MARK, MISO1_PG19_MARK,
+ SSL00_MARK, SSL10_MARK,
+
+ /* IIC3 */
+ SCL0_MARK, SCL1_MARK, SCL2_MARK,
+ SDA0_MARK, SDA1_MARK, SDA2_MARK,
+
+ /* SSI */
+ SSISCK0_MARK,
+ SSIWS0_MARK,
+ SSITXD0_MARK,
+ SSIRXD0_MARK,
+ SSIWS1_MARK, SSIWS2_MARK, SSIWS3_MARK,
+ SSISCK1_MARK, SSISCK2_MARK, SSISCK3_MARK,
+ SSIDATA1_MARK, SSIDATA2_MARK, SSIDATA3_MARK,
+ AUDIO_CLK_MARK,
+
+ /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+ SIOFTXD_MARK, SIOFRXD_MARK, SIOFSYNC_MARK, SIOFSCK_MARK,
+
+ /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+ SPDIF_IN_MARK, SPDIF_OUT_MARK,
+
+ /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+ FCE_MARK,
+ FRB_MARK,
+
+ /* VDC3 */
+ DV_CLK_MARK,
+ DV_VSYNC_MARK, DV_HSYNC_MARK,
+ DV_DATA7_MARK, DV_DATA6_MARK, DV_DATA5_MARK, DV_DATA4_MARK,
+ DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
+ LCD_CLK_MARK, LCD_EXTCLK_MARK,
+ LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
+ LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
+ LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
+ LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
+ LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
+ LCD_M_DISP_MARK,
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+ /* Port A */
+ PINMUX_DATA(PA3_DATA, PA3_IN),
+ PINMUX_DATA(PA2_DATA, PA2_IN),
+ PINMUX_DATA(PA1_DATA, PA1_IN),
+ PINMUX_DATA(PA0_DATA, PA0_IN),
+
+ /* Port B */
+ PINMUX_DATA(PB22_DATA, PB22MD_00, PB22_IN, PB22_OUT),
+ PINMUX_DATA(A22_MARK, PB22MD_01),
+ PINMUX_DATA(CS4_MARK, PB22MD_10),
+
+ PINMUX_DATA(PB21_DATA, PB21MD_0, PB21_IN, PB21_OUT),
+ PINMUX_DATA(A21_MARK, PB21MD_1),
+ PINMUX_DATA(A20_MARK, PB20MD_1),
+ PINMUX_DATA(A19_MARK, PB19MD_01),
+ PINMUX_DATA(A18_MARK, PB18MD_01),
+ PINMUX_DATA(A17_MARK, PB17MD_01),
+ PINMUX_DATA(A16_MARK, PB16MD_01),
+ PINMUX_DATA(A15_MARK, PB15MD_01),
+ PINMUX_DATA(A14_MARK, PB14MD_01),
+ PINMUX_DATA(A13_MARK, PB13MD_01),
+ PINMUX_DATA(A12_MARK, PB12MD_01),
+ PINMUX_DATA(A11_MARK, PB11MD_01),
+ PINMUX_DATA(A10_MARK, PB10MD_01),
+ PINMUX_DATA(A9_MARK, PB9MD_01),
+ PINMUX_DATA(A8_MARK, PB8MD_01),
+ PINMUX_DATA(A7_MARK, PB7MD_01),
+ PINMUX_DATA(A6_MARK, PB6MD_01),
+ PINMUX_DATA(A5_MARK, PB5MD_01),
+ PINMUX_DATA(A4_MARK, PB4MD_01),
+ PINMUX_DATA(A3_MARK, PB3MD_1),
+ PINMUX_DATA(A2_MARK, PB2MD_1),
+ PINMUX_DATA(A1_MARK, PB1MD_1),
+
+ /* Port C */
+ PINMUX_DATA(PC10_DATA, PC10MD_0),
+ PINMUX_DATA(TIOC2B_MARK, PC1MD_1),
+ PINMUX_DATA(PC9_DATA, PC9MD_0),
+ PINMUX_DATA(TIOC2A_MARK, PC9MD_1),
+ PINMUX_DATA(PC8_DATA, PC8MD_00),
+ PINMUX_DATA(CS3_MARK, PC8MD_01),
+ PINMUX_DATA(TIOC4D_MARK, PC8MD_10),
+ PINMUX_DATA(IRQ7_PC_MARK, PC8MD_11),
+ PINMUX_DATA(PC7_DATA, PC7MD_00),
+ PINMUX_DATA(CKE_MARK, PC7MD_01),
+ PINMUX_DATA(TIOC4C_MARK, PC7MD_10),
+ PINMUX_DATA(IRQ6_PC_MARK, PC7MD_11),
+ PINMUX_DATA(PC6_DATA, PC6MD_00),
+ PINMUX_DATA(CAS_MARK, PC6MD_01),
+ PINMUX_DATA(TIOC4B_MARK, PC6MD_10),
+ PINMUX_DATA(IRQ5_PC_MARK, PC6MD_11),
+ PINMUX_DATA(PC5_DATA, PC5MD_00),
+ PINMUX_DATA(RAS_MARK, PC5MD_01),
+ PINMUX_DATA(TIOC4A_MARK, PC5MD_10),
+ PINMUX_DATA(IRQ4_PC_MARK, PC5MD_11),
+ PINMUX_DATA(PC4_DATA, PC4MD_0),
+ PINMUX_DATA(WE1DQMUWE_MARK, PC4MD_1),
+ PINMUX_DATA(PC3_DATA, PC3MD_0),
+ PINMUX_DATA(WE0DQML_MARK, PC3MD_1),
+ PINMUX_DATA(PC2_DATA, PC2MD_0),
+ PINMUX_DATA(RDWR_MARK, PC2MD_1),
+ PINMUX_DATA(PC1_DATA, PC1MD_0),
+ PINMUX_DATA(RD_MARK, PC1MD_1),
+ PINMUX_DATA(PC0_DATA, PC0MD_0),
+ PINMUX_DATA(CS0_MARK, PC0MD_1),
+
+ /* Port D */
+ PINMUX_DATA(D15_MARK, PD15MD_01),
+ PINMUX_DATA(D14_MARK, PD14MD_01),
+ PINMUX_DATA(D13_MARK, PD13MD_01),
+ PINMUX_DATA(D12_MARK, PD12MD_01),
+ PINMUX_DATA(D11_MARK, PD11MD_01),
+ PINMUX_DATA(D10_MARK, PD10MD_01),
+ PINMUX_DATA(D9_MARK, PD9MD_01),
+ PINMUX_DATA(D8_MARK, PD8MD_01),
+ PINMUX_DATA(D7_MARK, PD7MD_01),
+ PINMUX_DATA(D6_MARK, PD6MD_01),
+ PINMUX_DATA(D5_MARK, PD5MD_01),
+ PINMUX_DATA(D4_MARK, PD4MD_01),
+ PINMUX_DATA(D3_MARK, PD3MD_01),
+ PINMUX_DATA(D2_MARK, PD2MD_01),
+ PINMUX_DATA(D1_MARK, PD1MD_01),
+ PINMUX_DATA(D0_MARK, PD0MD_01),
+
+ /* Port E */
+ PINMUX_DATA(PE5_DATA, PE5MD_00),
+ PINMUX_DATA(SDA2_MARK, PE5MD_01),
+ PINMUX_DATA(DV_HSYNC_MARK, PE5MD_11),
+
+ PINMUX_DATA(PE4_DATA, PE4MD_00),
+ PINMUX_DATA(SCL2_MARK, PE4MD_01),
+ PINMUX_DATA(DV_VSYNC_MARK, PE4MD_11),
+
+ PINMUX_DATA(PE3_DATA, PE3MD_00),
+ PINMUX_DATA(SDA1_MARK, PE3MD_01),
+ PINMUX_DATA(IRQ3_PE_MARK, PE3MD_11),
+
+ PINMUX_DATA(PE2_DATA, PE2MD_00),
+ PINMUX_DATA(SCL1_MARK, PE2MD_01),
+ PINMUX_DATA(IRQ2_PE_MARK, PE2MD_11),
+
+ PINMUX_DATA(PE1_DATA, PE1MD_000),
+ PINMUX_DATA(SDA0_MARK, PE1MD_001),
+ PINMUX_DATA(IOIS16_MARK, PE1MD_010),
+ PINMUX_DATA(IRQ1_PE_MARK, PE1MD_011),
+ PINMUX_DATA(TCLKA_MARK, PE1MD_100),
+ PINMUX_DATA(ADTRG_MARK, PE1MD_101),
+
+ PINMUX_DATA(PE0_DATA, PE0MD_00),
+ PINMUX_DATA(SCL0_MARK, PE0MD_01),
+ PINMUX_DATA(AUDIO_CLK_MARK, PE0MD_10),
+ PINMUX_DATA(IRQ0_PE_MARK, PE0MD_11),
+
+ /* Port F */
+ PINMUX_DATA(PF12_DATA, PF12MD_000),
+ PINMUX_DATA(BS_MARK, PF12MD_001),
+ PINMUX_DATA(MISO0_PF12_MARK, PF12MD_011),
+ PINMUX_DATA(TIOC3D_MARK, PF12MD_100),
+ PINMUX_DATA(SPDIF_OUT_MARK, PF12MD_101),
+
+ PINMUX_DATA(PF11_DATA, PF11MD_000),
+ PINMUX_DATA(A25_MARK, PF11MD_001),
+ PINMUX_DATA(SSIDATA3_MARK, PF11MD_010),
+ PINMUX_DATA(MOSI0_MARK, PF11MD_011),
+ PINMUX_DATA(TIOC3C_MARK, PF11MD_100),
+ PINMUX_DATA(SPDIF_IN_MARK, PF11MD_101),
+
+ PINMUX_DATA(PF10_DATA, PF10MD_000),
+ PINMUX_DATA(A24_MARK, PF10MD_001),
+ PINMUX_DATA(SSIWS3_MARK, PF10MD_010),
+ PINMUX_DATA(SSL00_MARK, PF10MD_011),
+ PINMUX_DATA(TIOC3B_MARK, PF10MD_100),
+ PINMUX_DATA(FCE_MARK, PF10MD_101),
+
+ PINMUX_DATA(PF9_DATA, PF9MD_000),
+ PINMUX_DATA(A23_MARK, PF9MD_001),
+ PINMUX_DATA(SSISCK3_MARK, PF9MD_010),
+ PINMUX_DATA(RSPCK0_MARK, PF9MD_011),
+ PINMUX_DATA(TIOC3A_MARK, PF9MD_100),
+ PINMUX_DATA(FRB_MARK, PF9MD_101),
+
+ PINMUX_DATA(PF8_DATA, PF8MD_00),
+ PINMUX_DATA(CE2B_MARK, PF8MD_01),
+ PINMUX_DATA(SSIDATA3_MARK, PF8MD_10),
+ PINMUX_DATA(DV_CLK_MARK, PF8MD_11),
+
+ PINMUX_DATA(PF7_DATA, PF7MD_000),
+ PINMUX_DATA(CE2A_MARK, PF7MD_001),
+ PINMUX_DATA(SSIWS3_MARK, PF7MD_010),
+ PINMUX_DATA(DV_DATA7_MARK, PF7MD_011),
+ PINMUX_DATA(TCLKD_MARK, PF7MD_100),
+
+ PINMUX_DATA(PF6_DATA, PF6MD_000),
+ PINMUX_DATA(CS6CE1B_MARK, PF6MD_001),
+ PINMUX_DATA(SSISCK3_MARK, PF6MD_010),
+ PINMUX_DATA(DV_DATA6_MARK, PF6MD_011),
+ PINMUX_DATA(TCLKB_MARK, PF6MD_100),
+
+ PINMUX_DATA(PF5_DATA, PF5MD_000),
+ PINMUX_DATA(CS5CE1A_MARK, PF5MD_001),
+ PINMUX_DATA(SSIDATA2_MARK, PF5MD_010),
+ PINMUX_DATA(DV_DATA5_MARK, PF5MD_011),
+ PINMUX_DATA(TCLKC_MARK, PF5MD_100),
+
+ PINMUX_DATA(PF4_DATA, PF4MD_000),
+ PINMUX_DATA(ICIOWRAH_MARK, PF4MD_001),
+ PINMUX_DATA(SSIWS2_MARK, PF4MD_010),
+ PINMUX_DATA(DV_DATA4_MARK, PF4MD_011),
+ PINMUX_DATA(TXD3_MARK, PF4MD_100),
+
+ PINMUX_DATA(PF3_DATA, PF3MD_000),
+ PINMUX_DATA(ICIORD_MARK, PF3MD_001),
+ PINMUX_DATA(SSISCK2_MARK, PF3MD_010),
+ PINMUX_DATA(DV_DATA3_MARK, PF3MD_011),
+ PINMUX_DATA(RXD3_MARK, PF3MD_100),
+
+ PINMUX_DATA(PF2_DATA, PF2MD_000),
+ PINMUX_DATA(BACK_MARK, PF2MD_001),
+ PINMUX_DATA(SSIDATA1_MARK, PF2MD_010),
+ PINMUX_DATA(DV_DATA2_MARK, PF2MD_011),
+ PINMUX_DATA(TXD2_MARK, PF2MD_100),
+ PINMUX_DATA(DACK0_MARK, PF2MD_101),
+
+ PINMUX_DATA(PF1_DATA, PF1MD_000),
+ PINMUX_DATA(BREQ_MARK, PF1MD_001),
+ PINMUX_DATA(SSIWS1_MARK, PF1MD_010),
+ PINMUX_DATA(DV_DATA1_MARK, PF1MD_011),
+ PINMUX_DATA(RXD2_MARK, PF1MD_100),
+ PINMUX_DATA(DREQ0_MARK, PF1MD_101),
+
+ PINMUX_DATA(PF0_DATA, PF0MD_000),
+ PINMUX_DATA(WAIT_MARK, PF0MD_001),
+ PINMUX_DATA(SSISCK1_MARK, PF0MD_010),
+ PINMUX_DATA(DV_DATA0_MARK, PF0MD_011),
+ PINMUX_DATA(SCK2_MARK, PF0MD_100),
+ PINMUX_DATA(TEND0_MARK, PF0MD_101),
+
+ /* Port G */
+ PINMUX_DATA(PG24_DATA, PG24MD_00),
+ PINMUX_DATA(MOSI0_MARK, PG24MD_01),
+ PINMUX_DATA(TIOC0D_MARK, PG24MD_10),
+
+ PINMUX_DATA(PG23_DATA, PG23MD_00),
+ PINMUX_DATA(MOSI1_MARK, PG23MD_01),
+ PINMUX_DATA(TIOC0C_MARK, PG23MD_10),
+
+ PINMUX_DATA(PG22_DATA, PG22MD_00),
+ PINMUX_DATA(SSL10_MARK, PG22MD_01),
+ PINMUX_DATA(TIOC0B_MARK, PG22MD_10),
+
+ PINMUX_DATA(PG21_DATA, PG21MD_00),
+ PINMUX_DATA(RSPCK1_MARK, PG21MD_01),
+ PINMUX_DATA(TIOC0A_MARK, PG21MD_10),
+
+ PINMUX_DATA(PG20_DATA, PG20MD_000),
+ PINMUX_DATA(LCD_EXTCLK_MARK, PG20MD_001),
+ PINMUX_DATA(MISO1_MARK, PG20MD_011),
+ PINMUX_DATA(TXD7_MARK, PG20MD_100),
+
+ PINMUX_DATA(PG19_DATA, PG19MD_000),
+ PINMUX_DATA(LCD_CLK_MARK, PG19MD_001),
+ PINMUX_DATA(TIOC2B_MARK, PG19MD_010),
+ PINMUX_DATA(MISO1_PG19_MARK, PG19MD_011),
+ PINMUX_DATA(RXD7_MARK, PG19MD_100),
+
+ PINMUX_DATA(PG18_DATA, PG18MD_000),
+ PINMUX_DATA(LCD_DE_MARK, PG18MD_001),
+ PINMUX_DATA(TIOC2A_MARK, PG18MD_010),
+ PINMUX_DATA(SSL10_MARK, PG18MD_011),
+ PINMUX_DATA(TXD6_MARK, PG18MD_100),
+
+ PINMUX_DATA(PG17_DATA, PG17MD_000),
+ PINMUX_DATA(LCD_HSYNC_MARK, PG17MD_001),
+ PINMUX_DATA(TIOC1B_MARK, PG17MD_010),
+ PINMUX_DATA(RSPCK1_MARK, PG17MD_011),
+ PINMUX_DATA(RXD6_MARK, PG17MD_100),
+
+ PINMUX_DATA(PG16_DATA, PG16MD_000),
+ PINMUX_DATA(LCD_VSYNC_MARK, PG16MD_001),
+ PINMUX_DATA(TIOC1A_MARK, PG16MD_010),
+ PINMUX_DATA(TXD3_MARK, PG16MD_011),
+ PINMUX_DATA(CTS1_MARK, PG16MD_100),
+
+ PINMUX_DATA(PG15_DATA, PG15MD_000),
+ PINMUX_DATA(LCD_DATA15_MARK, PG15MD_001),
+ PINMUX_DATA(TIOC0D_MARK, PG15MD_010),
+ PINMUX_DATA(RXD3_MARK, PG15MD_011),
+ PINMUX_DATA(RTS1_MARK, PG15MD_100),
+
+ PINMUX_DATA(PG14_DATA, PG14MD_000),
+ PINMUX_DATA(LCD_DATA14_MARK, PG14MD_001),
+ PINMUX_DATA(TIOC0C_MARK, PG14MD_010),
+ PINMUX_DATA(SCK1_MARK, PG14MD_100),
+
+ PINMUX_DATA(PG13_DATA, PG13MD_000),
+ PINMUX_DATA(LCD_DATA13_MARK, PG13MD_001),
+ PINMUX_DATA(TIOC0B_MARK, PG13MD_010),
+ PINMUX_DATA(TXD1_MARK, PG13MD_100),
+
+ PINMUX_DATA(PG12_DATA, PG12MD_000),
+ PINMUX_DATA(LCD_DATA12_MARK, PG12MD_001),
+ PINMUX_DATA(TIOC0A_MARK, PG12MD_010),
+ PINMUX_DATA(RXD1_MARK, PG12MD_100),
+
+ PINMUX_DATA(PG11_DATA, PG11MD_000),
+ PINMUX_DATA(LCD_DATA11_MARK, PG11MD_001),
+ PINMUX_DATA(SSITXD0_MARK, PG11MD_010),
+ PINMUX_DATA(IRQ3_PG_MARK, PG11MD_011),
+ PINMUX_DATA(TXD5_MARK, PG11MD_100),
+ PINMUX_DATA(SIOFTXD_MARK, PG11MD_101),
+
+ PINMUX_DATA(PG10_DATA, PG10MD_000),
+ PINMUX_DATA(LCD_DATA10_MARK, PG10MD_001),
+ PINMUX_DATA(SSIRXD0_MARK, PG10MD_010),
+ PINMUX_DATA(IRQ2_PG_MARK, PG10MD_011),
+ PINMUX_DATA(RXD5_MARK, PG10MD_100),
+ PINMUX_DATA(SIOFRXD_MARK, PG10MD_101),
+
+ PINMUX_DATA(PG9_DATA, PG9MD_000),
+ PINMUX_DATA(LCD_DATA9_MARK, PG9MD_001),
+ PINMUX_DATA(SSIWS0_MARK, PG9MD_010),
+ PINMUX_DATA(TXD4_MARK, PG9MD_100),
+ PINMUX_DATA(SIOFSYNC_MARK, PG9MD_101),
+
+ PINMUX_DATA(PG8_DATA, PG8MD_000),
+ PINMUX_DATA(LCD_DATA8_MARK, PG8MD_001),
+ PINMUX_DATA(SSISCK0_MARK, PG8MD_010),
+ PINMUX_DATA(RXD4_MARK, PG8MD_100),
+ PINMUX_DATA(SIOFSCK_MARK, PG8MD_101),
+
+ PINMUX_DATA(PG7_DATA, PG7MD_00),
+ PINMUX_DATA(LCD_DATA7_MARK, PG7MD_01),
+ PINMUX_DATA(SD_CD_MARK, PG7MD_10),
+ PINMUX_DATA(PINT7_PG_MARK, PG7MD_11),
+
+ PINMUX_DATA(PG6_DATA, PG7MD_00),
+ PINMUX_DATA(LCD_DATA6_MARK, PG7MD_01),
+ PINMUX_DATA(SD_WP_MARK, PG7MD_10),
+ PINMUX_DATA(PINT6_PG_MARK, PG7MD_11),
+
+ PINMUX_DATA(PG5_DATA, PG5MD_00),
+ PINMUX_DATA(LCD_DATA5_MARK, PG5MD_01),
+ PINMUX_DATA(SD_D1_MARK, PG5MD_10),
+ PINMUX_DATA(PINT5_PG_MARK, PG5MD_11),
+
+ PINMUX_DATA(PG4_DATA, PG4MD_00),
+ PINMUX_DATA(LCD_DATA4_MARK, PG4MD_01),
+ PINMUX_DATA(SD_D0_MARK, PG4MD_10),
+ PINMUX_DATA(PINT4_PG_MARK, PG4MD_11),
+
+ PINMUX_DATA(PG3_DATA, PG3MD_00),
+ PINMUX_DATA(LCD_DATA3_MARK, PG3MD_01),
+ PINMUX_DATA(SD_CLK_MARK, PG3MD_10),
+ PINMUX_DATA(PINT3_PG_MARK, PG3MD_11),
+
+ PINMUX_DATA(PG2_DATA, PG2MD_00),
+ PINMUX_DATA(LCD_DATA2_MARK, PG2MD_01),
+ PINMUX_DATA(SD_CMD_MARK, PG2MD_10),
+ PINMUX_DATA(PINT2_PG_MARK, PG2MD_11),
+
+ PINMUX_DATA(PG1_DATA, PG1MD_00),
+ PINMUX_DATA(LCD_DATA1_MARK, PG1MD_01),
+ PINMUX_DATA(SD_D3_MARK, PG1MD_10),
+ PINMUX_DATA(PINT1_PG_MARK, PG1MD_11),
+
+ PINMUX_DATA(PG0_DATA, PG0MD_000),
+ PINMUX_DATA(LCD_DATA0_MARK, PG0MD_001),
+ PINMUX_DATA(SD_D2_MARK, PG0MD_010),
+ PINMUX_DATA(PINT0_PG_MARK, PG0MD_011),
+ PINMUX_DATA(WDTOVF_MARK, PG0MD_100),
+
+ /* Port H */
+ PINMUX_DATA(PH7_DATA, PH7MD_0),
+ PINMUX_DATA(PHAN7_MARK, PH7MD_1),
+
+ PINMUX_DATA(PH6_DATA, PH6MD_0),
+ PINMUX_DATA(PHAN6_MARK, PH6MD_1),
+
+ PINMUX_DATA(PH5_DATA, PH5MD_0),
+ PINMUX_DATA(PHAN5_MARK, PH5MD_1),
+
+ PINMUX_DATA(PH4_DATA, PH4MD_0),
+ PINMUX_DATA(PHAN4_MARK, PH4MD_1),
+
+ PINMUX_DATA(PH3_DATA, PH3MD_0),
+ PINMUX_DATA(PHAN3_MARK, PH3MD_1),
+
+ PINMUX_DATA(PH2_DATA, PH2MD_0),
+ PINMUX_DATA(PHAN2_MARK, PH2MD_1),
+
+ PINMUX_DATA(PH1_DATA, PH1MD_0),
+ PINMUX_DATA(PHAN1_MARK, PH1MD_1),
+
+ PINMUX_DATA(PH0_DATA, PH0MD_0),
+ PINMUX_DATA(PHAN0_MARK, PH0MD_1),
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PINMUX_DATA(PJ11_DATA, PJ11MD_00),
+ PINMUX_DATA(PWM2H_MARK, PJ11MD_01),
+ PINMUX_DATA(DACK1_MARK, PJ11MD_10),
+
+ PINMUX_DATA(PJ10_DATA, PJ10MD_00),
+ PINMUX_DATA(PWM2G_MARK, PJ10MD_01),
+ PINMUX_DATA(DREQ1_MARK, PJ10MD_10),
+
+ PINMUX_DATA(PJ9_DATA, PJ9MD_00),
+ PINMUX_DATA(PWM2F_MARK, PJ9MD_01),
+ PINMUX_DATA(TEND1_MARK, PJ9MD_10),
+
+ PINMUX_DATA(PJ8_DATA, PJ8MD_00),
+ PINMUX_DATA(PWM2E_MARK, PJ8MD_01),
+ PINMUX_DATA(RTS3_MARK, PJ8MD_10),
+
+ PINMUX_DATA(PJ7_DATA, PJ7MD_00),
+ PINMUX_DATA(TIOC1B_MARK, PJ7MD_01),
+ PINMUX_DATA(CTS3_MARK, PJ7MD_10),
+
+ PINMUX_DATA(PJ6_DATA, PJ6MD_00),
+ PINMUX_DATA(TIOC1A_MARK, PJ6MD_01),
+ PINMUX_DATA(SCK3_MARK, PJ6MD_10),
+
+ PINMUX_DATA(PJ5_DATA, PJ5MD_00),
+ PINMUX_DATA(IERXD_MARK, PJ5MD_01),
+ PINMUX_DATA(TXD3_MARK, PJ5MD_10),
+
+ PINMUX_DATA(PJ4_DATA, PJ4MD_00),
+ PINMUX_DATA(IETXD_MARK, PJ4MD_01),
+ PINMUX_DATA(RXD3_MARK, PJ4MD_10),
+
+ PINMUX_DATA(PJ3_DATA, PJ3MD_00),
+ PINMUX_DATA(CRX1_MARK, PJ3MD_01),
+ PINMUX_DATA(CRX0X1_MARK, PJ3MD_10),
+ PINMUX_DATA(IRQ1_PJ_MARK, PJ3MD_11),
+
+ PINMUX_DATA(PJ2_DATA, PJ2MD_000),
+ PINMUX_DATA(CTX1_MARK, PJ2MD_001),
+ PINMUX_DATA(CRX0_CRX1_MARK, PJ2MD_010),
+ PINMUX_DATA(CS2_MARK, PJ2MD_011),
+ PINMUX_DATA(SCK0_MARK, PJ2MD_100),
+ PINMUX_DATA(LCD_M_DISP_MARK, PJ2MD_101),
+
+ PINMUX_DATA(PJ1_DATA, PJ1MD_000),
+ PINMUX_DATA(CRX0_MARK, PJ1MD_001),
+ PINMUX_DATA(IERXD_MARK, PJ1MD_010),
+ PINMUX_DATA(IRQ0_PJ_MARK, PJ1MD_011),
+ PINMUX_DATA(RXD0_MARK, PJ1MD_100),
+
+ PINMUX_DATA(PJ0_DATA, PJ0MD_000),
+ PINMUX_DATA(CTX0_MARK, PJ0MD_001),
+ PINMUX_DATA(IERXD_MARK, PJ0MD_010),
+ PINMUX_DATA(CS1_MARK, PJ0MD_011),
+ PINMUX_DATA(TXD0_MARK, PJ0MD_100),
+ PINMUX_DATA(A0_MARK, PJ0MD_101),
+
+ /* Port K */
+ PINMUX_DATA(PK11_DATA, PK11MD_00),
+ PINMUX_DATA(PWM2D_MARK, PK11MD_01),
+ PINMUX_DATA(SSITXD0_MARK, PK11MD_10),
+
+ PINMUX_DATA(PK10_DATA, PK10MD_00),
+ PINMUX_DATA(PWM2C_MARK, PK10MD_01),
+ PINMUX_DATA(SSIRXD0_MARK, PK10MD_10),
+
+ PINMUX_DATA(PK9_DATA, PK9MD_00),
+ PINMUX_DATA(PWM2B_MARK, PK9MD_01),
+ PINMUX_DATA(SSIWS0_MARK, PK9MD_10),
+
+ PINMUX_DATA(PK8_DATA, PK8MD_00),
+ PINMUX_DATA(PWM2A_MARK, PK8MD_01),
+ PINMUX_DATA(SSISCK0_MARK, PK8MD_10),
+
+ PINMUX_DATA(PK7_DATA, PK7MD_00),
+ PINMUX_DATA(PWM1H_MARK, PK7MD_01),
+ PINMUX_DATA(SD_CD_MARK, PK7MD_10),
+
+ PINMUX_DATA(PK6_DATA, PK6MD_00),
+ PINMUX_DATA(PWM1G_MARK, PK6MD_01),
+ PINMUX_DATA(SD_WP_MARK, PK6MD_10),
+
+ PINMUX_DATA(PK5_DATA, PK5MD_00),
+ PINMUX_DATA(PWM1F_MARK, PK5MD_01),
+ PINMUX_DATA(SD_D1_MARK, PK5MD_10),
+
+ PINMUX_DATA(PK4_DATA, PK4MD_00),
+ PINMUX_DATA(PWM1E_MARK, PK4MD_01),
+ PINMUX_DATA(SD_D0_MARK, PK4MD_10),
+
+ PINMUX_DATA(PK3_DATA, PK3MD_00),
+ PINMUX_DATA(PWM1D_MARK, PK3MD_01),
+ PINMUX_DATA(SD_CLK_MARK, PK3MD_10),
+
+ PINMUX_DATA(PK2_DATA, PK2MD_00),
+ PINMUX_DATA(PWM1C_MARK, PK2MD_01),
+ PINMUX_DATA(SD_CMD_MARK, PK2MD_10),
+
+ PINMUX_DATA(PK1_DATA, PK1MD_00),
+ PINMUX_DATA(PWM1B_MARK, PK1MD_01),
+ PINMUX_DATA(SD_D3_MARK, PK1MD_10),
+
+ PINMUX_DATA(PK0_DATA, PK0MD_00),
+ PINMUX_DATA(PWM1A_MARK, PK0MD_01),
+ PINMUX_DATA(SD_D2_MARK, PK0MD_10),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+
+ /* Port A */
+ PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+ PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+ PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+ PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+ /* Port B */
+ PINMUX_GPIO(GPIO_PB22, PB22_DATA),
+ PINMUX_GPIO(GPIO_PB21, PB21_DATA),
+ PINMUX_GPIO(GPIO_PB20, PB20_DATA),
+ PINMUX_GPIO(GPIO_PB19, PB19_DATA),
+ PINMUX_GPIO(GPIO_PB18, PB18_DATA),
+ PINMUX_GPIO(GPIO_PB17, PB17_DATA),
+ PINMUX_GPIO(GPIO_PB16, PB16_DATA),
+ PINMUX_GPIO(GPIO_PB15, PB15_DATA),
+ PINMUX_GPIO(GPIO_PB14, PB14_DATA),
+ PINMUX_GPIO(GPIO_PB13, PB13_DATA),
+ PINMUX_GPIO(GPIO_PB12, PB12_DATA),
+ PINMUX_GPIO(GPIO_PB11, PB11_DATA),
+ PINMUX_GPIO(GPIO_PB10, PB10_DATA),
+ PINMUX_GPIO(GPIO_PB9, PB9_DATA),
+ PINMUX_GPIO(GPIO_PB8, PB8_DATA),
+ PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+ PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+ PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+ PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+ PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+ PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+ PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+
+ /* Port C */
+ PINMUX_GPIO(GPIO_PC10, PC10_DATA),
+ PINMUX_GPIO(GPIO_PC9, PC9_DATA),
+ PINMUX_GPIO(GPIO_PC8, PC8_DATA),
+ PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+ PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+ PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+ PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+ PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+ PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+ PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+ PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+ /* Port D */
+ PINMUX_GPIO(GPIO_PD15, PD15_DATA),
+ PINMUX_GPIO(GPIO_PD14, PD14_DATA),
+ PINMUX_GPIO(GPIO_PD13, PD13_DATA),
+ PINMUX_GPIO(GPIO_PD12, PD12_DATA),
+ PINMUX_GPIO(GPIO_PD11, PD11_DATA),
+ PINMUX_GPIO(GPIO_PD10, PD10_DATA),
+ PINMUX_GPIO(GPIO_PD9, PD9_DATA),
+ PINMUX_GPIO(GPIO_PD8, PD8_DATA),
+ PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+ PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+ PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+ PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+ PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+ PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+ PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+ PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+ /* Port E */
+ PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+ PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+ PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+ PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+ PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+ PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+ /* Port F */
+ PINMUX_GPIO(GPIO_PF12, PF12_DATA),
+ PINMUX_GPIO(GPIO_PF11, PF11_DATA),
+ PINMUX_GPIO(GPIO_PF10, PF10_DATA),
+ PINMUX_GPIO(GPIO_PF9, PF9_DATA),
+ PINMUX_GPIO(GPIO_PF8, PF8_DATA),
+ PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+ PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+ PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+ PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+ PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+ PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+ PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+ PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+ /* Port G */
+ PINMUX_GPIO(GPIO_PG24, PG24_DATA),
+ PINMUX_GPIO(GPIO_PG23, PG23_DATA),
+ PINMUX_GPIO(GPIO_PG22, PG22_DATA),
+ PINMUX_GPIO(GPIO_PG21, PG21_DATA),
+ PINMUX_GPIO(GPIO_PG20, PG20_DATA),
+ PINMUX_GPIO(GPIO_PG19, PG19_DATA),
+ PINMUX_GPIO(GPIO_PG18, PG18_DATA),
+ PINMUX_GPIO(GPIO_PG17, PG17_DATA),
+ PINMUX_GPIO(GPIO_PG16, PG16_DATA),
+ PINMUX_GPIO(GPIO_PG15, PG15_DATA),
+ PINMUX_GPIO(GPIO_PG14, PG14_DATA),
+ PINMUX_GPIO(GPIO_PG13, PG13_DATA),
+ PINMUX_GPIO(GPIO_PG12, PG12_DATA),
+ PINMUX_GPIO(GPIO_PG11, PG11_DATA),
+ PINMUX_GPIO(GPIO_PG10, PG10_DATA),
+ PINMUX_GPIO(GPIO_PG9, PG9_DATA),
+ PINMUX_GPIO(GPIO_PG8, PG8_DATA),
+ PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+ PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+ PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+ PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+ PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+ PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+ PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+ PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+ /* Port H - Port H does not have a Data Register */
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
+ PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
+ PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
+ PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
+ PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+ PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+ PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+ PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+ PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+ PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+ PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+ PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+
+ /* Port K */
+ PINMUX_GPIO(GPIO_PK11, PK11_DATA),
+ PINMUX_GPIO(GPIO_PK10, PK10_DATA),
+ PINMUX_GPIO(GPIO_PK9, PK9_DATA),
+ PINMUX_GPIO(GPIO_PK8, PK8_DATA),
+ PINMUX_GPIO(GPIO_PK7, PK7_DATA),
+ PINMUX_GPIO(GPIO_PK6, PK6_DATA),
+ PINMUX_GPIO(GPIO_PK5, PK5_DATA),
+ PINMUX_GPIO(GPIO_PK4, PK4_DATA),
+ PINMUX_GPIO(GPIO_PK3, PK3_DATA),
+ PINMUX_GPIO(GPIO_PK2, PK2_DATA),
+ PINMUX_GPIO(GPIO_PK1, PK1_DATA),
+ PINMUX_GPIO(GPIO_PK0, PK0_DATA),
+
+ /* INTC */
+ PINMUX_GPIO(GPIO_FN_PINT7_PG, PINT7_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT6_PG, PINT6_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT5_PG, PINT5_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT4_PG, PINT4_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT3_PG, PINT3_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT2_PG, PINT2_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT1_PG, PINT1_PG_MARK),
+
+ PINMUX_GPIO(GPIO_FN_IRQ7_PC, IRQ7_PC_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6_PC, IRQ6_PC_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5_PC, IRQ5_PC_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4_PC, IRQ4_PC_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PG, IRQ3_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PG, IRQ2_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PJ, IRQ1_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PJ, IRQ0_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PE, IRQ3_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PE, IRQ2_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PE, IRQ1_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PE, IRQ0_PE_MARK),
+
+ /* WDT */
+ PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
+
+ /* CAN */
+ PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0_CRX1_MARK),
+
+ /* DMAC */
+ PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+
+ /* ADC */
+ PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
+
+ /* BSCh */
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+ PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+ PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+ PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+ PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
+ PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
+ PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
+ PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
+ PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
+ PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
+ PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
+ PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
+ PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
+ PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
+ PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
+ PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
+ PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+ PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
+ PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
+ PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
+ PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
+ PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
+ PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
+ PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
+ PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+ PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+ PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+ PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+ PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+ PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+ PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+ PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+ PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
+ PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
+ PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
+ PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
+ PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
+ PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
+ PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
+ PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
+ PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
+ PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6CE1B, CS6CE1B_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5CE1A, CS5CE1A_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+ PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
+ PINMUX_GPIO(GPIO_FN_ICIOWRAH, ICIOWRAH_MARK),
+ PINMUX_GPIO(GPIO_FN_ICIORD, ICIORD_MARK),
+ PINMUX_GPIO(GPIO_FN_WE1DQMUWE, WE1DQMUWE_MARK),
+ PINMUX_GPIO(GPIO_FN_WE0DQML, WE0DQML_MARK),
+ PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
+ PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
+ PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
+ PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+ PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+
+ /* TMU */
+ PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKD, TCLKD_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKC, TCLKC_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKB, TCLKB_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKA, TCLKA_MARK),
+
+ /* SCIF */
+ PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD5, TXD5_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD5, RXD5_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD6, TXD6_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD6, RXD6_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD7, TXD7_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD7, RXD7_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS1, RTS1_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS1, CTS1_MARK),
+
+ /* RSPI */
+ PINMUX_GPIO(GPIO_FN_RSPCK0, RSPCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_MOSI0, MOSI0_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO0_PF12, MISO0_PF12_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO1, MISO1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSL00, SSL00_MARK),
+ PINMUX_GPIO(GPIO_FN_RSPCK1, RSPCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_MOSI1, MOSI1_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO1_PG19, MISO1_PG19_MARK),
+ PINMUX_GPIO(GPIO_FN_SSL10, SSL10_MARK),
+
+ /* IIC3 */
+ PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
+
+ /* SSI */
+ PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSITXD0, SSITXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIRXD0, SSIRXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
+
+ /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+ PINMUX_GPIO(GPIO_FN_SIOFTXD, SIOFTXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFRXD, SIOFRXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFSYNC, SIOFSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFSCK, SIOFSCK_MARK),
+
+ /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+ PINMUX_GPIO(GPIO_FN_SPDIF_IN, SPDIF_IN_MARK),
+ PINMUX_GPIO(GPIO_FN_SPDIF_OUT, SPDIF_OUT_MARK),
+
+ /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+ PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+ PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+
+ /* VDC3 */
+ PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+
+ PINMUX_GPIO(GPIO_FN_DV_DATA7, DV_DATA7_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA6, DV_DATA6_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA5, DV_DATA5_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA4, DV_DATA4_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA3, DV_DATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA2, DV_DATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA1, DV_DATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA0, DV_DATA0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_EXTCLK, LCD_EXTCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_VSYNC, LCD_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PAIOR0", 0xfffe3812, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PA3_IN, PA3_OUT,
+ PA2_IN, PA2_OUT,
+ PA1_IN, PA1_OUT,
+ PA0_IN, PA0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PBCR5", 0xfffe3824, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PB22MD_00, PB22MD_01, PB22MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PB21MD_0, PB21MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB20MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+
+ },
+ { PINMUX_CFG_REG("PBCR4", 0xfffe3826, 16, 4) {
+ 0, PB19MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB18MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB17MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB16MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR3", 0xfffe3828, 16, 4) {
+ 0, PB15MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB14MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB13MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB12MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR2", 0xfffe382a, 16, 4) {
+ 0, PB11MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB10MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB9MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB8MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR1", 0xfffe382c, 16, 4) {
+ 0, PB7MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB6MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB5MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB4MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR0", 0xfffe382e, 16, 4) {
+ 0, PB3MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB2MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB1MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PBIOR1", 0xfffe3830, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ PB22_IN, PB22_OUT,
+ PB21_IN, PB21_OUT,
+ PB20_IN, PB20_OUT,
+ PB19_IN, PB19_OUT,
+ PB18_IN, PB18_OUT,
+ PB17_IN, PB17_OUT,
+ PB16_IN, PB16_OUT }
+ },
+
+ { PINMUX_CFG_REG("PBIOR0", 0xfffe3832, 16, 1) {
+ PB15_IN, PB15_OUT,
+ PB14_IN, PB14_OUT,
+ PB13_IN, PB13_OUT,
+ PB12_IN, PB12_OUT,
+ PB11_IN, PB11_OUT,
+ PB10_IN, PB10_OUT,
+ PB9_IN, PB9_OUT,
+ PB8_IN, PB8_OUT,
+ PB7_IN, PB7_OUT,
+ PB6_IN, PB6_OUT,
+ PB5_IN, PB5_OUT,
+ PB4_IN, PB4_OUT,
+ PB3_IN, PB3_OUT,
+ PB2_IN, PB2_OUT,
+ PB1_IN, PB1_OUT,
+ 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PCCR2", 0xfffe384a, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC10MD_0, PC10MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC9MD_0, PC9MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC8MD_00, PC8MD_01, PC8MD_10, PC8MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCR1", 0xfffe384c, 16, 4) {
+ PC7MD_00, PC7MD_01, PC7MD_10, PC7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC6MD_00, PC6MD_01, PC6MD_10, PC6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC5MD_00, PC5MD_01, PC5MD_10, PC5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC4MD_0, PC4MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCR0", 0xfffe384e, 16, 4) {
+ PC3MD_0, PC3MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC2MD_0, PC2MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC1MD_0, PC1MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC0MD_0, PC0MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ PC10_IN, PC10_OUT,
+ PC9_IN, PC9_OUT,
+ PC8_IN, PC8_OUT,
+ PC7_IN, PC7_OUT,
+ PC6_IN, PC6_OUT,
+ PC5_IN, PC5_OUT,
+ PC4_IN, PC4_OUT,
+ PC3_IN, PC3_OUT,
+ PC2_IN, PC2_OUT,
+ PC1_IN, PC1_OUT,
+ PC0_IN, PC0_OUT
+ }
+ },
+
+ { PINMUX_CFG_REG("PDCR3", 0xfffe3868, 16, 4) {
+ 0, PD15MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD14MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD13MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD12MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR2", 0xfffe386a, 16, 4) {
+ 0, PD11MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD10MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD9MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD8MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR1", 0xfffe386c, 16, 4) {
+ 0, PD7MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD6MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD5MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD4MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR0", 0xfffe386e, 16, 4) {
+ 0, PD3MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD2MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD1MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD0MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PDIOR0", 0xfffe3872, 16, 1) {
+ PD15_IN, PD15_OUT,
+ PD14_IN, PD14_OUT,
+ PD13_IN, PD13_OUT,
+ PD12_IN, PD12_OUT,
+ PD11_IN, PD11_OUT,
+ PD10_IN, PD10_OUT,
+ PD9_IN, PD9_OUT,
+ PD8_IN, PD8_OUT,
+ PD7_IN, PD7_OUT,
+ PD6_IN, PD6_OUT,
+ PD5_IN, PD5_OUT,
+ PD4_IN, PD4_OUT,
+ PD3_IN, PD3_OUT,
+ PD2_IN, PD2_OUT,
+ PD1_IN, PD1_OUT,
+ PD0_IN, PD0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PECR1", 0xfffe388c, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE5MD_00, PE5MD_01, 0, PE5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE4MD_00, PE4MD_01, 0, PE4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PECR0", 0xfffe388e, 16, 4) {
+ PE3MD_00, PE3MD_01, 0, PE3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE2MD_00, PE2MD_01, 0, PE2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+ PE1MD_100, PE1MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PEIOR0", 0xfffe3892, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PE5_IN, PE5_OUT,
+ PE4_IN, PE4_OUT,
+ PE3_IN, PE3_OUT,
+ PE2_IN, PE2_OUT,
+ PE1_IN, PE1_OUT,
+ PE0_IN, PE0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
+ PF12MD_000, PF12MD_001, 0, PF12MD_011,
+ PF12MD_100, PF12MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PFCR2", 0xfffe38aa, 16, 4) {
+ PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+ PF11MD_100, PF11MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+ PF10MD_100, PF10MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+ PF9MD_100, PF9MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF8MD_00, PF8MD_01, PF8MD_10, PF8MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PFCR1", 0xfffe38ac, 16, 4) {
+ PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+ PF7MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+ PF6MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+ PF5MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+ PF4MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PFCR0", 0xfffe38ae, 16, 4) {
+ PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+ PF3MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+ PF2MD_100, PF2MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+ PF1MD_100, PF1MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ },
+
+ { PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
+ 0, 0, 0, 0, 0, 0,
+ PF12_IN, PF12_OUT,
+ PF11_IN, PF11_OUT,
+ PF10_IN, PF10_OUT,
+ PF9_IN, PF9_OUT,
+ PF8_IN, PF8_OUT,
+ PF7_IN, PF7_OUT,
+ PF6_IN, PF6_OUT,
+ PF5_IN, PF5_OUT,
+ PF4_IN, PF4_OUT,
+ PF3_IN, PF3_OUT,
+ PF2_IN, PF2_OUT,
+ PF1_IN, PF1_OUT,
+ PF0_IN, PF0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PGCR7", 0xfffe38c0, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+ PG0MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR6", 0xfffe38c2, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR5", 0xfffe38c4, 16, 4) {
+ PG23MD_00, PG23MD_01, PG23MD_10, PG23MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG22MD_00, PG22MD_01, PG22MD_10, PG22MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG21MD_00, PG21MD_01, PG21MD_10, PG21MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+ PG20MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR4", 0xfffe38c6, 16, 4) {
+ PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+ PG19MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+ PG18MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG17MD_000, PG17MD_001, PG17MD_010, PG17MD_011,
+ PG17MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG16MD_000, PG16MD_001, PG16MD_010, PG16MD_011,
+ PG16MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR3", 0xfffe38c8, 16, 4) {
+ PG15MD_000, PG15MD_001, PG15MD_010, PG15MD_011,
+ PG15MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG14MD_000, PG14MD_001, PG14MD_010, 0,
+ PG14MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG13MD_000, PG13MD_001, PG13MD_010, 0,
+ PG13MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG12MD_000, PG12MD_001, PG12MD_010, 0,
+ PG12MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR2", 0xfffe38ca, 16, 4) {
+ PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+ PG11MD_100, PG11MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+ PG10MD_100, PG10MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+ PG9MD_100, PG9MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+ PG8MD_100, PG8MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR1", 0xfffe38cc, 16, 4) {
+ PG7MD_00, PG7MD_01, PG7MD_10, PG7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG6MD_00, PG6MD_01, PG6MD_10, PG6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG5MD_00, PG5MD_01, PG5MD_10, PG5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG4MD_00, PG4MD_01, PG4MD_10, PG4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR0", 0xfffe38ce, 16, 4) {
+ PG3MD_00, PG3MD_01, PG3MD_10, PG3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG2MD_00, PG2MD_01, PG2MD_10, PG2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG1MD_00, PG1MD_01, PG1MD_10, PG1MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGIOR1", 0xfffe38d0, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ PG24_IN, PG24_OUT,
+ PG23_IN, PG23_OUT,
+ PG22_IN, PG22_OUT,
+ PG21_IN, PG21_OUT,
+ PG20_IN, PG20_OUT,
+ PG19_IN, PG19_OUT,
+ PG18_IN, PG18_OUT,
+ PG17_IN, PG17_OUT,
+ PG16_IN, PG16_OUT }
+ },
+
+ { PINMUX_CFG_REG("PGIOR0", 0xfffe38d2, 16, 1) {
+ PG15_IN, PG15_OUT,
+ PG14_IN, PG14_OUT,
+ PG13_IN, PG13_OUT,
+ PG12_IN, PG12_OUT,
+ PG11_IN, PG11_OUT,
+ PG10_IN, PG10_OUT,
+ PG9_IN, PG9_OUT,
+ PG8_IN, PG8_OUT,
+ PG7_IN, PG7_OUT,
+ PG6_IN, PG6_OUT,
+ PG5_IN, PG5_OUT,
+ PG4_IN, PG4_OUT,
+ PG3_IN, PG3_OUT,
+ PG2_IN, PG2_OUT,
+ PG1_IN, PG1_OUT,
+ PG0_IN, PG0_OUT
+ }
+ },
+
+ { PINMUX_CFG_REG("PHCR1", 0xfffe38ec, 16, 4) {
+ PH7MD_0, PH7MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH6MD_0, PH6MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH5MD_0, PH5MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH4MD_0, PH4MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PHCR0", 0xfffe38ee, 16, 4) {
+ PH3MD_0, PH3MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH2MD_0, PH2MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH1MD_0, PH1MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH0MD_0, PH0MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PJCR2", 0xfffe390a, 16, 4) {
+ PJ11MD_00, PJ11MD_01, PJ11MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ10MD_00, PJ10MD_01, PJ10MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ9MD_00, PJ9MD_01, PJ9MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ8MD_00, PJ8MD_01, PJ8MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR1", 0xfffe390c, 16, 4) {
+ PJ7MD_00, PJ7MD_01, PJ7MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ6MD_00, PJ6MD_01, PJ6MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ5MD_00, PJ5MD_01, PJ5MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ4MD_00, PJ4MD_01, PJ4MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR0", 0xfffe390e, 16, 4) {
+ PJ3MD_00, PJ3MD_01, PJ3MD_10, PJ3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+ PJ2MD_100, PJ2MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+ PJ1MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+ PJ0MD_100, PJ0MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, }
+ },
+ { PINMUX_CFG_REG("PJIOR0", 0xfffe3912, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ11_IN, PJ11_OUT,
+ PJ10_IN, PJ10_OUT,
+ PJ9_IN, PJ9_OUT,
+ PJ8_IN, PJ8_OUT,
+ PJ7_IN, PJ7_OUT,
+ PJ6_IN, PJ6_OUT,
+ PJ5_IN, PJ5_OUT,
+ PJ4_IN, PJ4_OUT,
+ PJ3_IN, PJ3_OUT,
+ PJ2_IN, PJ2_OUT,
+ PJ1_IN, PJ1_OUT,
+ PJ0_IN, PJ0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PKCR2", 0xfffe392a, 16, 4) {
+ PK11MD_00, PK11MD_01, PK11MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK10MD_00, PK10MD_01, PK10MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK9MD_00, PK9MD_01, PK9MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK8MD_00, PK8MD_01, PK8MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PKCR1", 0xfffe392c, 16, 4) {
+ PK7MD_00, PK7MD_01, PK7MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK6MD_00, PK6MD_01, PK6MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK5MD_00, PK5MD_01, PK5MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK4MD_00, PK4MD_01, PK4MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PKCR0", 0xfffe392e, 16, 4) {
+ PK3MD_00, PK3MD_01, PK3MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK2MD_00, PK2MD_01, PK2MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK1MD_00, PK1MD_01, PK1MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK0MD_00, PK0MD_01, PK0MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PKIOR0", 0xfffe3932, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ11_IN, PJ11_OUT,
+ PJ10_IN, PJ10_OUT,
+ PJ9_IN, PJ9_OUT,
+ PJ8_IN, PJ8_OUT,
+ PJ7_IN, PJ7_OUT,
+ PJ6_IN, PJ6_OUT,
+ PJ5_IN, PJ5_OUT,
+ PJ4_IN, PJ4_OUT,
+ PJ3_IN, PJ3_OUT,
+ PJ2_IN, PJ2_OUT,
+ PJ1_IN, PJ1_OUT,
+ PJ0_IN, PJ0_OUT }
+ },
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR1", 0xfffe3814, 16) {
+ 0, 0, 0, 0, 0, 0, 0, PA3_DATA,
+ 0, 0, 0, 0, 0, 0, 0, PA2_DATA }
+ },
+
+ { PINMUX_DATA_REG("PADR0", 0xfffe3816, 16) {
+ 0, 0, 0, 0, 0, 0, 0, PA1_DATA,
+ 0, 0, 0, 0, 0, 0, 0, PA0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PBDR1", 0xfffe3834, 16) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB22_DATA, PB21_DATA, PB20_DATA,
+ PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA }
+ },
+
+ { PINMUX_DATA_REG("PBDR0", 0xfffe3836, 16) {
+ PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+ PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, 0 }
+ },
+
+ { PINMUX_DATA_REG("PCDR0", 0xfffe3856, 16) {
+ 0, 0, 0, 0,
+ 0, PC10_DATA, PC9_DATA, PC8_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PDDR0", 0xfffe3876, 16) {
+ PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+ PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PEDR0", 0xfffe3896, 16) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PFDR0", 0xfffe38b6, 16) {
+ 0, 0, 0, PF12_DATA,
+ PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PGDR1", 0xfffe38d4, 16) {
+ 0, 0, 0, 0, 0, 0, 0, PG24_DATA,
+ PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+ PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA }
+ },
+
+ { PINMUX_DATA_REG("PGDR0", 0xfffe38d6, 16) {
+ PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+ PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR0", 0xfffe3916, 16) {
+ 0, 0, 0, PJ12_DATA,
+ PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
+ },
+ { PINMUX_DATA_REG("PKDR0", 0xfffe3936, 16) {
+ 0, 0, 0, PK12_DATA,
+ PK11_DATA, PK10_DATA, PK9_DATA, PK8_DATA,
+ PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
+ PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA }
+ },
+ { }
+};
+
+struct sh_pfc_soc_info sh7264_pinmux_info = {
+ .name = "sh7264_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PA3,
+ .last_gpio = GPIO_FN_LCD_M_DISP,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7269.c b/drivers/pinctrl/sh-pfc/pfc-sh7269.c
new file mode 100644
index 000000000000..b1b5d6d4ad76
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7269.c
@@ -0,0 +1,2834 @@
+/*
+ * SH7269 Pinmux
+ *
+ * Copyright (C) 2012 Renesas Electronics Europe Ltd
+ * Copyright (C) 2012 Phil Edworthy
+ *
+ * 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/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7269.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ /* Port A */
+ PA1_DATA, PA0_DATA,
+ /* Port B */
+ PB22_DATA, PB21_DATA, PB20_DATA,
+ PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA,
+ PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+ PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA,
+ /* Port C */
+ PC8_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ /* Port D */
+ PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+ PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+ /* Port E */
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ /* Port F */
+ PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
+ PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA,
+ PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
+ PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+ /* Port G */
+ PG27_DATA, PG26_DATA, PG25_DATA, PG24_DATA,
+ PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+ PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA,
+ PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+ PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+ /* Port H */
+ /* NOTE - Port H does not have a Data Register, but PH Data is
+ connected to PH Port Register */
+ PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+ /* Port I - not on device */
+ /* Port J */
+ PJ31_DATA, PJ30_DATA, PJ29_DATA, PJ28_DATA,
+ PJ27_DATA, PJ26_DATA, PJ25_DATA, PJ24_DATA,
+ PJ23_DATA, PJ22_DATA, PJ21_DATA, PJ20_DATA,
+ PJ19_DATA, PJ18_DATA, PJ17_DATA, PJ16_DATA,
+ PJ15_DATA, PJ14_DATA, PJ13_DATA, PJ12_DATA,
+ PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ FORCE_IN,
+ /* Port A */
+ PA1_IN, PA0_IN,
+ /* Port B */
+ PB22_IN, PB21_IN, PB20_IN,
+ PB19_IN, PB18_IN, PB17_IN, PB16_IN,
+ PB15_IN, PB14_IN, PB13_IN, PB12_IN,
+ PB11_IN, PB10_IN, PB9_IN, PB8_IN,
+ PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+ PB3_IN, PB2_IN, PB1_IN,
+ /* Port C */
+ PC8_IN,
+ PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+ PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+ /* Port D */
+ PD15_IN, PD14_IN, PD13_IN, PD12_IN,
+ PD11_IN, PD10_IN, PD9_IN, PD8_IN,
+ PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+ PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+ /* Port E */
+ PE7_IN, PE6_IN, PE5_IN, PE4_IN,
+ PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+ /* Port F */
+ PF23_IN, PF22_IN, PF21_IN, PF20_IN,
+ PF19_IN, PF18_IN, PF17_IN, PF16_IN,
+ PF15_IN, PF14_IN, PF13_IN, PF12_IN,
+ PF11_IN, PF10_IN, PF9_IN, PF8_IN,
+ PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+ PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+ /* Port G */
+ PG27_IN, PG26_IN, PG25_IN, PG24_IN,
+ PG23_IN, PG22_IN, PG21_IN, PG20_IN,
+ PG19_IN, PG18_IN, PG17_IN, PG16_IN,
+ PG15_IN, PG14_IN, PG13_IN, PG12_IN,
+ PG11_IN, PG10_IN, PG9_IN, PG8_IN,
+ PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+ PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+ /* Port H - Port H does not have a Data Register */
+ /* Port I - not on device */
+ /* Port J */
+ PJ31_IN, PJ30_IN, PJ29_IN, PJ28_IN,
+ PJ27_IN, PJ26_IN, PJ25_IN, PJ24_IN,
+ PJ23_IN, PJ22_IN, PJ21_IN, PJ20_IN,
+ PJ19_IN, PJ18_IN, PJ17_IN, PJ16_IN,
+ PJ15_IN, PJ14_IN, PJ13_IN, PJ12_IN,
+ PJ11_IN, PJ10_IN, PJ9_IN, PJ8_IN,
+ PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+ PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ FORCE_OUT,
+ /* Port A */
+ PA1_OUT, PA0_OUT,
+ /* Port B */
+ PB22_OUT, PB21_OUT, PB20_OUT,
+ PB19_OUT, PB18_OUT, PB17_OUT, PB16_OUT,
+ PB15_OUT, PB14_OUT, PB13_OUT, PB12_OUT,
+ PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
+ PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+ PB3_OUT, PB2_OUT, PB1_OUT,
+ /* Port C */
+ PC8_OUT,
+ PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+ PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+ /* Port D */
+ PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
+ PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
+ PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+ PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+ /* Port E */
+ PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
+ PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+ /* Port F */
+ PF23_OUT, PF22_OUT, PF21_OUT, PF20_OUT,
+ PF19_OUT, PF18_OUT, PF17_OUT, PF16_OUT,
+ PF15_OUT, PF14_OUT, PF13_OUT, PF12_OUT,
+ PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
+ PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+ PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+ /* Port G */
+ PG27_OUT, PG26_OUT, PG25_OUT, PG24_OUT,
+ PG23_OUT, PG22_OUT, PG21_OUT, PG20_OUT,
+ PG19_OUT, PG18_OUT, PG17_OUT, PG16_OUT,
+ PG15_OUT, PG14_OUT, PG13_OUT, PG12_OUT,
+ PG11_OUT, PG10_OUT, PG9_OUT, PG8_OUT,
+ PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+ PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+ /* Port H - Port H does not have a Data Register */
+ /* Port I - not on device */
+ /* Port J */
+ PJ31_OUT, PJ30_OUT, PJ29_OUT, PJ28_OUT,
+ PJ27_OUT, PJ26_OUT, PJ25_OUT, PJ24_OUT,
+ PJ23_OUT, PJ22_OUT, PJ21_OUT, PJ20_OUT,
+ PJ19_OUT, PJ18_OUT, PJ17_OUT, PJ16_OUT,
+ PJ15_OUT, PJ14_OUT, PJ13_OUT, PJ12_OUT,
+ PJ11_OUT, PJ10_OUT, PJ9_OUT, PJ8_OUT,
+ PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+ PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ /* Port A */
+ PA1_IOR_IN, PA1_IOR_OUT,
+ PA0_IOR_IN, PA0_IOR_OUT,
+
+ /* Port B */
+ PB22_IOR_IN, PB22_IOR_OUT,
+ PB21_IOR_IN, PB21_IOR_OUT,
+ PB20_IOR_IN, PB20_IOR_OUT,
+ PB19_IOR_IN, PB19_IOR_OUT,
+ PB18_IOR_IN, PB18_IOR_OUT,
+ PB17_IOR_IN, PB17_IOR_OUT,
+ PB16_IOR_IN, PB16_IOR_OUT,
+
+ PB15_IOR_IN, PB15_IOR_OUT,
+ PB14_IOR_IN, PB14_IOR_OUT,
+ PB13_IOR_IN, PB13_IOR_OUT,
+ PB12_IOR_IN, PB12_IOR_OUT,
+ PB11_IOR_IN, PB11_IOR_OUT,
+ PB10_IOR_IN, PB10_IOR_OUT,
+ PB9_IOR_IN, PB9_IOR_OUT,
+ PB8_IOR_IN, PB8_IOR_OUT,
+
+ PB7_IOR_IN, PB7_IOR_OUT,
+ PB6_IOR_IN, PB6_IOR_OUT,
+ PB5_IOR_IN, PB5_IOR_OUT,
+ PB4_IOR_IN, PB4_IOR_OUT,
+ PB3_IOR_IN, PB3_IOR_OUT,
+ PB2_IOR_IN, PB2_IOR_OUT,
+ PB1_IOR_IN, PB1_IOR_OUT,
+ PB0_IOR_IN, PB0_IOR_OUT,
+
+ PB22MD_000, PB22MD_001, PB22MD_010, PB22MD_011,
+ PB22MD_100, PB22MD_101, PB22MD_110, PB22MD_111,
+ PB21MD_00, PB21MD_01, PB21MD_10, PB21MD_11,
+ PB20MD_000, PB20MD_001, PB20MD_010, PB20MD_011,
+ PB20MD_100, PB20MD_101, PB20MD_110, PB20MD_111,
+ PB19MD_000, PB19MD_001, PB19MD_010, PB19MD_011,
+ PB19MD_100, PB19MD_101, PB19MD_110, PB19MD_111,
+ PB18MD_000, PB18MD_001, PB18MD_010, PB18MD_011,
+ PB18MD_100, PB18MD_101, PB18MD_110, PB18MD_111,
+ PB17MD_000, PB17MD_001, PB17MD_010, PB17MD_011,
+ PB17MD_100, PB17MD_101, PB17MD_110, PB17MD_111,
+ PB16MD_000, PB16MD_001, PB16MD_010, PB16MD_011,
+ PB16MD_100, PB16MD_101, PB16MD_110, PB16MD_111,
+ PB15MD_000, PB15MD_001, PB15MD_010, PB15MD_011,
+ PB15MD_100, PB15MD_101, PB15MD_110, PB15MD_111,
+ PB14MD_000, PB14MD_001, PB14MD_010, PB14MD_011,
+ PB14MD_100, PB14MD_101, PB14MD_110, PB14MD_111,
+ PB13MD_000, PB13MD_001, PB13MD_010, PB13MD_011,
+ PB13MD_100, PB13MD_101, PB13MD_110, PB13MD_111,
+ PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
+
+ PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11,
+ PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11,
+ PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11,
+ PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11,
+
+ PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
+ PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
+ PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
+ PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
+
+ PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11,
+ PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11,
+ PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11,
+
+ /* Port C */
+ PC8_IOR_IN, PC8_IOR_OUT,
+ PC7_IOR_IN, PC7_IOR_OUT,
+ PC6_IOR_IN, PC6_IOR_OUT,
+ PC5_IOR_IN, PC5_IOR_OUT,
+ PC4_IOR_IN, PC4_IOR_OUT,
+ PC3_IOR_IN, PC3_IOR_OUT,
+ PC2_IOR_IN, PC2_IOR_OUT,
+ PC1_IOR_IN, PC1_IOR_OUT,
+ PC0_IOR_IN, PC0_IOR_OUT,
+
+ PC8MD_000, PC8MD_001, PC8MD_010, PC8MD_011,
+ PC8MD_100, PC8MD_101, PC8MD_110, PC8MD_111,
+ PC7MD_000, PC7MD_001, PC7MD_010, PC7MD_011,
+ PC7MD_100, PC7MD_101, PC7MD_110, PC7MD_111,
+ PC6MD_000, PC6MD_001, PC6MD_010, PC6MD_011,
+ PC6MD_100, PC6MD_101, PC6MD_110, PC6MD_111,
+ PC5MD_000, PC5MD_001, PC5MD_010, PC5MD_011,
+ PC5MD_100, PC5MD_101, PC5MD_110, PC5MD_111,
+ PC4MD_00, PC4MD_01, PC4MD_10, PC4MD_11,
+
+ PC3MD_00, PC3MD_01, PC3MD_10, PC3MD_11,
+ PC2MD_00, PC2MD_01, PC2MD_10, PC2MD_11,
+ PC1MD_0, PC1MD_1,
+ PC0MD_0, PC0MD_1,
+
+ /* Port D */
+ PD15_IOR_IN, PD15_IOR_OUT,
+ PD14_IOR_IN, PD14_IOR_OUT,
+ PD13_IOR_IN, PD13_IOR_OUT,
+ PD12_IOR_IN, PD12_IOR_OUT,
+ PD11_IOR_IN, PD11_IOR_OUT,
+ PD10_IOR_IN, PD10_IOR_OUT,
+ PD9_IOR_IN, PD9_IOR_OUT,
+ PD8_IOR_IN, PD8_IOR_OUT,
+ PD7_IOR_IN, PD7_IOR_OUT,
+ PD6_IOR_IN, PD6_IOR_OUT,
+ PD5_IOR_IN, PD5_IOR_OUT,
+ PD4_IOR_IN, PD4_IOR_OUT,
+ PD3_IOR_IN, PD3_IOR_OUT,
+ PD2_IOR_IN, PD2_IOR_OUT,
+ PD1_IOR_IN, PD1_IOR_OUT,
+ PD0_IOR_IN, PD0_IOR_OUT,
+
+ PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11,
+ PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11,
+ PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11,
+ PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11,
+
+ PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11,
+ PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11,
+ PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11,
+ PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11,
+
+ PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11,
+ PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11,
+ PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11,
+ PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11,
+
+ PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11,
+ PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11,
+ PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11,
+ PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11,
+
+ /* Port E */
+ PE7_IOR_IN, PE7_IOR_OUT,
+ PE6_IOR_IN, PE6_IOR_OUT,
+ PE5_IOR_IN, PE5_IOR_OUT,
+ PE4_IOR_IN, PE4_IOR_OUT,
+ PE3_IOR_IN, PE3_IOR_OUT,
+ PE2_IOR_IN, PE2_IOR_OUT,
+ PE1_IOR_IN, PE1_IOR_OUT,
+ PE0_IOR_IN, PE0_IOR_OUT,
+
+ PE7MD_00, PE7MD_01, PE7MD_10, PE7MD_11,
+ PE6MD_00, PE6MD_01, PE6MD_10, PE6MD_11,
+ PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11,
+ PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11,
+
+ PE3MD_000, PE3MD_001, PE3MD_010, PE3MD_011,
+ PE3MD_100, PE3MD_101, PE3MD_110, PE3MD_111,
+ PE2MD_000, PE2MD_001, PE2MD_010, PE2MD_011,
+ PE2MD_100, PE2MD_101, PE2MD_110, PE2MD_111,
+ PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+ PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+ PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11,
+
+ /* Port F */
+ PF23_IOR_IN, PF23_IOR_OUT,
+ PF22_IOR_IN, PF22_IOR_OUT,
+ PF21_IOR_IN, PF21_IOR_OUT,
+ PF20_IOR_IN, PF20_IOR_OUT,
+ PF19_IOR_IN, PF19_IOR_OUT,
+ PF18_IOR_IN, PF18_IOR_OUT,
+ PF17_IOR_IN, PF17_IOR_OUT,
+ PF16_IOR_IN, PF16_IOR_OUT,
+ PF15_IOR_IN, PF15_IOR_OUT,
+ PF14_IOR_IN, PF14_IOR_OUT,
+ PF13_IOR_IN, PF13_IOR_OUT,
+ PF12_IOR_IN, PF12_IOR_OUT,
+ PF11_IOR_IN, PF11_IOR_OUT,
+ PF10_IOR_IN, PF10_IOR_OUT,
+ PF9_IOR_IN, PF9_IOR_OUT,
+ PF8_IOR_IN, PF8_IOR_OUT,
+ PF7_IOR_IN, PF7_IOR_OUT,
+ PF6_IOR_IN, PF6_IOR_OUT,
+ PF5_IOR_IN, PF5_IOR_OUT,
+ PF4_IOR_IN, PF4_IOR_OUT,
+ PF3_IOR_IN, PF3_IOR_OUT,
+ PF2_IOR_IN, PF2_IOR_OUT,
+ PF1_IOR_IN, PF1_IOR_OUT,
+ PF0_IOR_IN, PF0_IOR_OUT,
+
+ PF23MD_000, PF23MD_001, PF23MD_010, PF23MD_011,
+ PF23MD_100, PF23MD_101, PF23MD_110, PF23MD_111,
+ PF22MD_000, PF22MD_001, PF22MD_010, PF22MD_011,
+ PF22MD_100, PF22MD_101, PF22MD_110, PF22MD_111,
+ PF21MD_000, PF21MD_001, PF21MD_010, PF21MD_011,
+ PF21MD_100, PF21MD_101, PF21MD_110, PF21MD_111,
+ PF20MD_000, PF20MD_001, PF20MD_010, PF20MD_011,
+ PF20MD_100, PF20MD_101, PF20MD_110, PF20MD_111,
+
+ PF19MD_000, PF19MD_001, PF19MD_010, PF19MD_011,
+ PF19MD_100, PF19MD_101, PF19MD_110, PF19MD_111,
+ PF18MD_000, PF18MD_001, PF18MD_010, PF18MD_011,
+ PF18MD_100, PF18MD_101, PF18MD_110, PF18MD_111,
+ PF17MD_000, PF17MD_001, PF17MD_010, PF17MD_011,
+ PF17MD_100, PF17MD_101, PF17MD_110, PF17MD_111,
+ PF16MD_000, PF16MD_001, PF16MD_010, PF16MD_011,
+ PF16MD_100, PF16MD_101, PF16MD_110, PF16MD_111,
+
+ PF15MD_000, PF15MD_001, PF15MD_010, PF15MD_011,
+ PF15MD_100, PF15MD_101, PF15MD_110, PF15MD_111,
+ PF14MD_000, PF14MD_001, PF14MD_010, PF14MD_011,
+ PF14MD_100, PF14MD_101, PF14MD_110, PF14MD_111,
+ PF13MD_000, PF13MD_001, PF13MD_010, PF13MD_011,
+ PF13MD_100, PF13MD_101, PF13MD_110, PF13MD_111,
+ PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+ PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+
+ PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+ PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+ PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+ PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+ PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+ PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+ PF8MD_000, PF8MD_001, PF8MD_010, PF8MD_011,
+ PF8MD_100, PF8MD_101, PF8MD_110, PF8MD_111,
+
+ PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+ PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+ PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+ PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+ PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+ PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+ PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+ PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+
+ PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+ PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+ PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+ PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+ PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+ PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+ PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+ PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+
+ /* Port G */
+ PG27_IOR_IN, PG27_IOR_OUT,
+ PG26_IOR_IN, PG26_IOR_OUT,
+ PG25_IOR_IN, PG25_IOR_OUT,
+ PG24_IOR_IN, PG24_IOR_OUT,
+ PG23_IOR_IN, PG23_IOR_OUT,
+ PG22_IOR_IN, PG22_IOR_OUT,
+ PG21_IOR_IN, PG21_IOR_OUT,
+ PG20_IOR_IN, PG20_IOR_OUT,
+ PG19_IOR_IN, PG19_IOR_OUT,
+ PG18_IOR_IN, PG18_IOR_OUT,
+ PG17_IOR_IN, PG17_IOR_OUT,
+ PG16_IOR_IN, PG16_IOR_OUT,
+ PG15_IOR_IN, PG15_IOR_OUT,
+ PG14_IOR_IN, PG14_IOR_OUT,
+ PG13_IOR_IN, PG13_IOR_OUT,
+ PG12_IOR_IN, PG12_IOR_OUT,
+ PG11_IOR_IN, PG11_IOR_OUT,
+ PG10_IOR_IN, PG10_IOR_OUT,
+ PG9_IOR_IN, PG9_IOR_OUT,
+ PG8_IOR_IN, PG8_IOR_OUT,
+ PG7_IOR_IN, PG7_IOR_OUT,
+ PG6_IOR_IN, PG6_IOR_OUT,
+ PG5_IOR_IN, PG5_IOR_OUT,
+ PG4_IOR_IN, PG4_IOR_OUT,
+ PG3_IOR_IN, PG3_IOR_OUT,
+ PG2_IOR_IN, PG2_IOR_OUT,
+ PG1_IOR_IN, PG1_IOR_OUT,
+ PG0_IOR_IN, PG0_IOR_OUT,
+
+ PG27MD_00, PG27MD_01, PG27MD_10, PG27MD_11,
+ PG26MD_00, PG26MD_01, PG26MD_10, PG26MD_11,
+ PG25MD_00, PG25MD_01, PG25MD_10, PG25MD_11,
+ PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11,
+
+ PG23MD_000, PG23MD_001, PG23MD_010, PG23MD_011,
+ PG23MD_100, PG23MD_101, PG23MD_110, PG23MD_111,
+ PG22MD_000, PG22MD_001, PG22MD_010, PG22MD_011,
+ PG22MD_100, PG22MD_101, PG22MD_110, PG22MD_111,
+ PG21MD_000, PG21MD_001, PG21MD_010, PG21MD_011,
+ PG21MD_100, PG21MD_101, PG21MD_110, PG21MD_111,
+ PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+ PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+
+ PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+ PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+ PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+ PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+ PG17MD_00, PG17MD_01, PG17MD_10, PG17MD_11,
+ PG16MD_00, PG16MD_01, PG16MD_10, PG16MD_11,
+
+ PG15MD_00, PG15MD_01, PG15MD_10, PG15MD_11,
+ PG14MD_00, PG14MD_01, PG14MD_10, PG14MD_11,
+ PG13MD_00, PG13MD_01, PG13MD_10, PG13MD_11,
+ PG12MD_00, PG12MD_01, PG12MD_10, PG12MD_11,
+
+ PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+ PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+ PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+ PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+ PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+ PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+ PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+ PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+
+ PG7MD_000, PG7MD_001, PG7MD_010, PG7MD_011,
+ PG7MD_100, PG7MD_101, PG7MD_110, PG7MD_111,
+ PG6MD_000, PG6MD_001, PG6MD_010, PG6MD_011,
+ PG6MD_100, PG6MD_101, PG6MD_110, PG6MD_111,
+ PG5MD_000, PG5MD_001, PG5MD_010, PG5MD_011,
+ PG5MD_100, PG5MD_101, PG5MD_110, PG5MD_111,
+ PG4MD_000, PG4MD_001, PG4MD_010, PG4MD_011,
+ PG4MD_100, PG4MD_101, PG4MD_110, PG4MD_111,
+
+ PG3MD_000, PG3MD_001, PG3MD_010, PG3MD_011,
+ PG3MD_100, PG3MD_101, PG3MD_110, PG3MD_111,
+ PG2MD_000, PG2MD_001, PG2MD_010, PG2MD_011,
+ PG2MD_100, PG2MD_101, PG2MD_110, PG2MD_111,
+ PG1MD_000, PG1MD_001, PG1MD_010, PG1MD_011,
+ PG1MD_100, PG1MD_101, PG1MD_110, PG1MD_111,
+ PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+ PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+
+ /* Port H */
+ PH7MD_00, PH7MD_01, PH7MD_10, PH7MD_11,
+ PH6MD_00, PH6MD_01, PH6MD_10, PH6MD_11,
+ PH5MD_00, PH5MD_01, PH5MD_10, PH5MD_11,
+ PH4MD_00, PH4MD_01, PH4MD_10, PH4MD_11,
+
+ PH3MD_00, PH3MD_01, PH3MD_10, PH3MD_11,
+ PH2MD_00, PH2MD_01, PH2MD_10, PH2MD_11,
+ PH1MD_00, PH1MD_01, PH1MD_10, PH1MD_11,
+ PH0MD_00, PH0MD_01, PH0MD_10, PH0MD_11,
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PJ31_IOR_IN, PJ31_IOR_OUT,
+ PJ30_IOR_IN, PJ30_IOR_OUT,
+ PJ29_IOR_IN, PJ29_IOR_OUT,
+ PJ28_IOR_IN, PJ28_IOR_OUT,
+ PJ27_IOR_IN, PJ27_IOR_OUT,
+ PJ26_IOR_IN, PJ26_IOR_OUT,
+ PJ25_IOR_IN, PJ25_IOR_OUT,
+ PJ24_IOR_IN, PJ24_IOR_OUT,
+ PJ23_IOR_IN, PJ23_IOR_OUT,
+ PJ22_IOR_IN, PJ22_IOR_OUT,
+ PJ21_IOR_IN, PJ21_IOR_OUT,
+ PJ20_IOR_IN, PJ20_IOR_OUT,
+ PJ19_IOR_IN, PJ19_IOR_OUT,
+ PJ18_IOR_IN, PJ18_IOR_OUT,
+ PJ17_IOR_IN, PJ17_IOR_OUT,
+ PJ16_IOR_IN, PJ16_IOR_OUT,
+ PJ15_IOR_IN, PJ15_IOR_OUT,
+ PJ14_IOR_IN, PJ14_IOR_OUT,
+ PJ13_IOR_IN, PJ13_IOR_OUT,
+ PJ12_IOR_IN, PJ12_IOR_OUT,
+ PJ11_IOR_IN, PJ11_IOR_OUT,
+ PJ10_IOR_IN, PJ10_IOR_OUT,
+ PJ9_IOR_IN, PJ9_IOR_OUT,
+ PJ8_IOR_IN, PJ8_IOR_OUT,
+ PJ7_IOR_IN, PJ7_IOR_OUT,
+ PJ6_IOR_IN, PJ6_IOR_OUT,
+ PJ5_IOR_IN, PJ5_IOR_OUT,
+ PJ4_IOR_IN, PJ4_IOR_OUT,
+ PJ3_IOR_IN, PJ3_IOR_OUT,
+ PJ2_IOR_IN, PJ2_IOR_OUT,
+ PJ1_IOR_IN, PJ1_IOR_OUT,
+ PJ0_IOR_IN, PJ0_IOR_OUT,
+
+ PJ31MD_0, PJ31MD_1,
+ PJ30MD_000, PJ30MD_001, PJ30MD_010, PJ30MD_011,
+ PJ30MD_100, PJ30MD_101, PJ30MD_110, PJ30MD_111,
+ PJ29MD_000, PJ29MD_001, PJ29MD_010, PJ29MD_011,
+ PJ29MD_100, PJ29MD_101, PJ29MD_110, PJ29MD_111,
+ PJ28MD_000, PJ28MD_001, PJ28MD_010, PJ28MD_011,
+ PJ28MD_100, PJ28MD_101, PJ28MD_110, PJ28MD_111,
+
+ PJ27MD_000, PJ27MD_001, PJ27MD_010, PJ27MD_011,
+ PJ27MD_100, PJ27MD_101, PJ27MD_110, PJ27MD_111,
+ PJ26MD_000, PJ26MD_001, PJ26MD_010, PJ26MD_011,
+ PJ26MD_100, PJ26MD_101, PJ26MD_110, PJ26MD_111,
+ PJ25MD_000, PJ25MD_001, PJ25MD_010, PJ25MD_011,
+ PJ25MD_100, PJ25MD_101, PJ25MD_110, PJ25MD_111,
+ PJ24MD_000, PJ24MD_001, PJ24MD_010, PJ24MD_011,
+ PJ24MD_100, PJ24MD_101, PJ24MD_110, PJ24MD_111,
+
+ PJ23MD_000, PJ23MD_001, PJ23MD_010, PJ23MD_011,
+ PJ23MD_100, PJ23MD_101, PJ23MD_110, PJ23MD_111,
+ PJ22MD_000, PJ22MD_001, PJ22MD_010, PJ22MD_011,
+ PJ22MD_100, PJ22MD_101, PJ22MD_110, PJ22MD_111,
+ PJ21MD_000, PJ21MD_001, PJ21MD_010, PJ21MD_011,
+ PJ21MD_100, PJ21MD_101, PJ21MD_110, PJ21MD_111,
+ PJ20MD_000, PJ20MD_001, PJ20MD_010, PJ20MD_011,
+ PJ20MD_100, PJ20MD_101, PJ20MD_110, PJ20MD_111,
+
+ PJ19MD_000, PJ19MD_001, PJ19MD_010, PJ19MD_011,
+ PJ19MD_100, PJ19MD_101, PJ19MD_110, PJ19MD_111,
+ PJ18MD_000, PJ18MD_001, PJ18MD_010, PJ18MD_011,
+ PJ18MD_100, PJ18MD_101, PJ18MD_110, PJ18MD_111,
+ PJ17MD_000, PJ17MD_001, PJ17MD_010, PJ17MD_011,
+ PJ17MD_100, PJ17MD_101, PJ17MD_110, PJ17MD_111,
+ PJ16MD_000, PJ16MD_001, PJ16MD_010, PJ16MD_011,
+ PJ16MD_100, PJ16MD_101, PJ16MD_110, PJ16MD_111,
+
+ PJ15MD_000, PJ15MD_001, PJ15MD_010, PJ15MD_011,
+ PJ15MD_100, PJ15MD_101, PJ15MD_110, PJ15MD_111,
+ PJ14MD_000, PJ14MD_001, PJ14MD_010, PJ14MD_011,
+ PJ14MD_100, PJ14MD_101, PJ14MD_110, PJ14MD_111,
+ PJ13MD_000, PJ13MD_001, PJ13MD_010, PJ13MD_011,
+ PJ13MD_100, PJ13MD_101, PJ13MD_110, PJ13MD_111,
+ PJ12MD_000, PJ12MD_001, PJ12MD_010, PJ12MD_011,
+ PJ12MD_100, PJ12MD_101, PJ12MD_110, PJ12MD_111,
+
+ PJ11MD_000, PJ11MD_001, PJ11MD_010, PJ11MD_011,
+ PJ11MD_100, PJ11MD_101, PJ11MD_110, PJ11MD_111,
+ PJ10MD_000, PJ10MD_001, PJ10MD_010, PJ10MD_011,
+ PJ10MD_100, PJ10MD_101, PJ10MD_110, PJ10MD_111,
+ PJ9MD_000, PJ9MD_001, PJ9MD_010, PJ9MD_011,
+ PJ9MD_100, PJ9MD_101, PJ9MD_110, PJ9MD_111,
+ PJ8MD_000, PJ8MD_001, PJ8MD_010, PJ8MD_011,
+ PJ8MD_100, PJ8MD_101, PJ8MD_110, PJ8MD_111,
+
+ PJ7MD_000, PJ7MD_001, PJ7MD_010, PJ7MD_011,
+ PJ7MD_100, PJ7MD_101, PJ7MD_110, PJ7MD_111,
+ PJ6MD_000, PJ6MD_001, PJ6MD_010, PJ6MD_011,
+ PJ6MD_100, PJ6MD_101, PJ6MD_110, PJ6MD_111,
+ PJ5MD_000, PJ5MD_001, PJ5MD_010, PJ5MD_011,
+ PJ5MD_100, PJ5MD_101, PJ5MD_110, PJ5MD_111,
+ PJ4MD_000, PJ4MD_001, PJ4MD_010, PJ4MD_011,
+ PJ4MD_100, PJ4MD_101, PJ4MD_110, PJ4MD_111,
+
+ PJ3MD_000, PJ3MD_001, PJ3MD_010, PJ3MD_011,
+ PJ3MD_100, PJ3MD_101, PJ3MD_110, PJ3MD_111,
+ PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+ PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+ PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+ PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+ PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+ PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ /* Port H */
+ PHAN7_MARK, PHAN6_MARK, PHAN5_MARK, PHAN4_MARK,
+ PHAN3_MARK, PHAN2_MARK, PHAN1_MARK, PHAN0_MARK,
+
+ /* IRQs */
+ IRQ7_PG_MARK, IRQ6_PG_MARK, IRQ5_PG_MARK, IRQ4_PG_MARK,
+ IRQ3_PG_MARK, IRQ2_PG_MARK, IRQ1_PG_MARK, IRQ0_PG_MARK,
+ IRQ7_PF_MARK, IRQ6_PF_MARK, IRQ5_PF_MARK, IRQ4_PF_MARK,
+ IRQ3_PJ_MARK, IRQ2_PJ_MARK, IRQ1_PJ_MARK, IRQ0_PJ_MARK,
+ IRQ1_PC_MARK, IRQ0_PC_MARK,
+
+ PINT7_PG_MARK, PINT6_PG_MARK, PINT5_PG_MARK, PINT4_PG_MARK,
+ PINT3_PG_MARK, PINT2_PG_MARK, PINT1_PG_MARK, PINT0_PG_MARK,
+ PINT7_PH_MARK, PINT6_PH_MARK, PINT5_PH_MARK, PINT4_PH_MARK,
+ PINT3_PH_MARK, PINT2_PH_MARK, PINT1_PH_MARK, PINT0_PH_MARK,
+ PINT7_PJ_MARK, PINT6_PJ_MARK, PINT5_PJ_MARK, PINT4_PJ_MARK,
+ PINT3_PJ_MARK, PINT2_PJ_MARK, PINT1_PJ_MARK, PINT0_PJ_MARK,
+
+ /* SD */
+ SD_D0_MARK, SD_D1_MARK, SD_D2_MARK, SD_D3_MARK,
+ SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK, SD_CD_MARK,
+
+ /* MMC */
+ MMC_D0_MARK, MMC_D1_MARK, MMC_D2_MARK, MMC_D3_MARK,
+ MMC_D4_MARK, MMC_D5_MARK, MMC_D6_MARK, MMC_D7_MARK,
+ MMC_CLK_MARK, MMC_CMD_MARK, MMC_CD_MARK,
+
+ /* PWM */
+ PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
+ PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
+ PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
+ PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
+
+ /* IEBus */
+ IERXD_MARK, IETXD_MARK,
+
+ /* WDT */
+ WDTOVF_MARK,
+
+ /* DMAC */
+ TEND0_MARK, DACK0_MARK, DREQ0_MARK,
+ TEND1_MARK, DACK1_MARK, DREQ1_MARK,
+
+ /* ADC */
+ ADTRG_MARK,
+
+ /* BSC */
+ A25_MARK, A24_MARK,
+ A23_MARK, A22_MARK, A21_MARK, A20_MARK,
+ A19_MARK, A18_MARK, A17_MARK, A16_MARK,
+ A15_MARK, A14_MARK, A13_MARK, A12_MARK,
+ A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+ A7_MARK, A6_MARK, A5_MARK, A4_MARK,
+ A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+ D31_MARK, D30_MARK, D29_MARK, D28_MARK,
+ D27_MARK, D26_MARK, D25_MARK, D24_MARK,
+ D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+ D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+ D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+ D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+ D7_MARK, D6_MARK, D5_MARK, D4_MARK,
+ D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+ BS_MARK,
+ CS4_MARK, CS3_MARK, CS2_MARK, CS1_MARK, CS0_MARK,
+ CS5CE1A_MARK,
+ CE2A_MARK, CE2B_MARK,
+ RD_MARK, RDWR_MARK,
+ WE3ICIOWRAHDQMUU_MARK,
+ WE2ICIORDDQMUL_MARK,
+ WE1DQMUWE_MARK,
+ WE0DQML_MARK,
+ RAS_MARK, CAS_MARK, CKE_MARK,
+ WAIT_MARK, BREQ_MARK, BACK_MARK, IOIS16_MARK,
+
+ /* TMU */
+ TIOC0A_MARK, TIOC0B_MARK, TIOC0C_MARK, TIOC0D_MARK,
+ TIOC1A_MARK, TIOC1B_MARK,
+ TIOC2A_MARK, TIOC2B_MARK,
+ TIOC3A_MARK, TIOC3B_MARK, TIOC3C_MARK, TIOC3D_MARK,
+ TIOC4A_MARK, TIOC4B_MARK, TIOC4C_MARK, TIOC4D_MARK,
+ TCLKA_MARK, TCLKB_MARK, TCLKC_MARK, TCLKD_MARK,
+
+ /* SCIF */
+ SCK0_MARK, RXD0_MARK, TXD0_MARK,
+ SCK1_MARK, RXD1_MARK, TXD1_MARK, RTS1_MARK, CTS1_MARK,
+ SCK2_MARK, RXD2_MARK, TXD2_MARK,
+ SCK3_MARK, RXD3_MARK, TXD3_MARK,
+ SCK4_MARK, RXD4_MARK, TXD4_MARK,
+ SCK5_MARK, RXD5_MARK, TXD5_MARK, RTS5_MARK, CTS5_MARK,
+ SCK6_MARK, RXD6_MARK, TXD6_MARK,
+ SCK7_MARK, RXD7_MARK, TXD7_MARK, RTS7_MARK, CTS7_MARK,
+
+ /* RSPI */
+ MISO0_PB20_MARK, MOSI0_PB19_MARK, SSL00_PB18_MARK, RSPCK0_PB17_MARK,
+ MISO0_PJ19_MARK, MOSI0_PJ18_MARK, SSL00_PJ17_MARK, RSPCK0_PJ16_MARK,
+ MISO1_MARK, MOSI1_MARK, SSL10_MARK, RSPCK1_MARK,
+
+ /* IIC3 */
+ SCL0_MARK, SDA0_MARK,
+ SCL1_MARK, SDA1_MARK,
+ SCL2_MARK, SDA2_MARK,
+ SCL3_MARK, SDA3_MARK,
+
+ /* SSI */
+ SSISCK0_MARK, SSIWS0_MARK, SSITXD0_MARK, SSIRXD0_MARK,
+ SSISCK1_MARK, SSIWS1_MARK, SSIDATA1_MARK,
+ SSISCK2_MARK, SSIWS2_MARK, SSIDATA2_MARK,
+ SSISCK3_MARK, SSIWS3_MARK, SSIDATA3_MARK,
+ SSISCK4_MARK, SSIWS4_MARK, SSIDATA4_MARK,
+ SSISCK5_MARK, SSIWS5_MARK, SSIDATA5_MARK,
+ AUDIO_CLK_MARK,
+ AUDIO_XOUT_MARK,
+
+ /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+ SIOFTXD_MARK, SIOFRXD_MARK, SIOFSYNC_MARK, SIOFSCK_MARK,
+
+ /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+ SPDIF_IN_MARK, SPDIF_OUT_MARK,
+ SPDIF_IN_PJ24_MARK, SPDIF_OUT_PJ25_MARK,
+
+ /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+ FCE_MARK,
+ FRB_MARK,
+
+ /* CAN */
+ CRX0_MARK, CTX0_MARK,
+ CRX1_MARK, CTX1_MARK,
+ CRX2_MARK, CTX2_MARK,
+ CRX0_CRX1_MARK,
+ CRX0_CRX1_CRX2_MARK,
+ CTX0CTX1CTX2_MARK,
+ CRX1_PJ22_MARK, CTX1_PJ23_MARK,
+ CRX2_PJ20_MARK, CTX2_PJ21_MARK,
+ CRX0CRX1_PJ22_MARK,
+ CRX0CRX1CRX2_PJ20_MARK,
+
+ /* VDC */
+ DV_CLK_MARK,
+ DV_VSYNC_MARK, DV_HSYNC_MARK,
+ DV_DATA23_MARK, DV_DATA22_MARK, DV_DATA21_MARK, DV_DATA20_MARK,
+ DV_DATA19_MARK, DV_DATA18_MARK, DV_DATA17_MARK, DV_DATA16_MARK,
+ DV_DATA15_MARK, DV_DATA14_MARK, DV_DATA13_MARK, DV_DATA12_MARK,
+ DV_DATA11_MARK, DV_DATA10_MARK, DV_DATA9_MARK, DV_DATA8_MARK,
+ DV_DATA7_MARK, DV_DATA6_MARK, DV_DATA5_MARK, DV_DATA4_MARK,
+ DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
+ LCD_CLK_MARK, LCD_EXTCLK_MARK,
+ LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
+ LCD_DATA23_PG23_MARK, LCD_DATA22_PG22_MARK, LCD_DATA21_PG21_MARK,
+ LCD_DATA20_PG20_MARK, LCD_DATA19_PG19_MARK, LCD_DATA18_PG18_MARK,
+ LCD_DATA17_PG17_MARK, LCD_DATA16_PG16_MARK, LCD_DATA15_PG15_MARK,
+ LCD_DATA14_PG14_MARK, LCD_DATA13_PG13_MARK, LCD_DATA12_PG12_MARK,
+ LCD_DATA11_PG11_MARK, LCD_DATA10_PG10_MARK, LCD_DATA9_PG9_MARK,
+ LCD_DATA8_PG8_MARK, LCD_DATA7_PG7_MARK, LCD_DATA6_PG6_MARK,
+ LCD_DATA5_PG5_MARK, LCD_DATA4_PG4_MARK, LCD_DATA3_PG3_MARK,
+ LCD_DATA2_PG2_MARK, LCD_DATA1_PG1_MARK, LCD_DATA0_PG0_MARK,
+ LCD_DATA23_PJ23_MARK, LCD_DATA22_PJ22_MARK, LCD_DATA21_PJ21_MARK,
+ LCD_DATA20_PJ20_MARK, LCD_DATA19_PJ19_MARK, LCD_DATA18_PJ18_MARK,
+ LCD_DATA17_PJ17_MARK, LCD_DATA16_PJ16_MARK, LCD_DATA15_PJ15_MARK,
+ LCD_DATA14_PJ14_MARK, LCD_DATA13_PJ13_MARK, LCD_DATA12_PJ12_MARK,
+ LCD_DATA11_PJ11_MARK, LCD_DATA10_PJ10_MARK, LCD_DATA9_PJ9_MARK,
+ LCD_DATA8_PJ8_MARK, LCD_DATA7_PJ7_MARK, LCD_DATA6_PJ6_MARK,
+ LCD_DATA5_PJ5_MARK, LCD_DATA4_PJ4_MARK, LCD_DATA3_PJ3_MARK,
+ LCD_DATA2_PJ2_MARK, LCD_DATA1_PJ1_MARK, LCD_DATA0_PJ0_MARK,
+ LCD_TCON6_MARK, LCD_TCON5_MARK, LCD_TCON4_MARK,
+ LCD_TCON3_MARK, LCD_TCON2_MARK, LCD_TCON1_MARK, LCD_TCON0_MARK,
+ LCD_M_DISP_MARK,
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+ /* Port A */
+ PINMUX_DATA(PA1_DATA, PA1_IN),
+ PINMUX_DATA(PA0_DATA, PA0_IN),
+
+ /* Port B */
+ PINMUX_DATA(PB22_DATA, PB22MD_000, PB22_IN, PB22_OUT),
+ PINMUX_DATA(A22_MARK, PB22MD_001),
+ PINMUX_DATA(CTX2_MARK, PB22MD_010),
+ PINMUX_DATA(IETXD_MARK, PB22MD_011),
+ PINMUX_DATA(CS4_MARK, PB22MD_100),
+
+ PINMUX_DATA(PB21_DATA, PB21MD_00, PB21_IN, PB21_OUT),
+ PINMUX_DATA(A21_MARK, PB21MD_01),
+ PINMUX_DATA(CRX2_MARK, PB21MD_10),
+ PINMUX_DATA(IERXD_MARK, PB21MD_11),
+
+ PINMUX_DATA(A20_MARK, PB20MD_001),
+ PINMUX_DATA(A19_MARK, PB19MD_001),
+ PINMUX_DATA(A18_MARK, PB18MD_001),
+ PINMUX_DATA(A17_MARK, PB17MD_001),
+ PINMUX_DATA(A16_MARK, PB16MD_001),
+ PINMUX_DATA(A15_MARK, PB15MD_001),
+ PINMUX_DATA(A14_MARK, PB14MD_001),
+ PINMUX_DATA(A13_MARK, PB13MD_001),
+ PINMUX_DATA(A12_MARK, PB12MD_01),
+ PINMUX_DATA(A11_MARK, PB11MD_01),
+ PINMUX_DATA(A10_MARK, PB10MD_01),
+ PINMUX_DATA(A9_MARK, PB9MD_01),
+ PINMUX_DATA(A8_MARK, PB8MD_01),
+ PINMUX_DATA(A7_MARK, PB7MD_01),
+ PINMUX_DATA(A6_MARK, PB6MD_01),
+ PINMUX_DATA(A5_MARK, PB5MD_01),
+ PINMUX_DATA(A4_MARK, PB4MD_01),
+ PINMUX_DATA(A3_MARK, PB3MD_01),
+ PINMUX_DATA(A2_MARK, PB2MD_01),
+ PINMUX_DATA(A1_MARK, PB1MD_01),
+
+ /* Port C */
+ PINMUX_DATA(PC8_DATA, PC8MD_000),
+ PINMUX_DATA(CS3_MARK, PC8MD_001),
+ PINMUX_DATA(TXD7_MARK, PC8MD_010),
+ PINMUX_DATA(CTX1_MARK, PC8MD_011),
+
+ PINMUX_DATA(PC7_DATA, PC7MD_000),
+ PINMUX_DATA(CKE_MARK, PC7MD_001),
+ PINMUX_DATA(RXD7_MARK, PC7MD_010),
+ PINMUX_DATA(CRX1_MARK, PC7MD_011),
+ PINMUX_DATA(CRX0_CRX1_MARK, PC7MD_100),
+ PINMUX_DATA(IRQ1_PC_MARK, PC7MD_101),
+
+ PINMUX_DATA(PC6_DATA, PC6MD_000),
+ PINMUX_DATA(CAS_MARK, PC6MD_001),
+ PINMUX_DATA(SCK7_MARK, PC6MD_010),
+ PINMUX_DATA(CTX0_MARK, PC6MD_011),
+
+ PINMUX_DATA(PC5_DATA, PC5MD_000),
+ PINMUX_DATA(RAS_MARK, PC5MD_001),
+ PINMUX_DATA(CRX0_MARK, PC5MD_011),
+ PINMUX_DATA(CTX0CTX1CTX2_MARK, PC5MD_100),
+ PINMUX_DATA(IRQ0_PC_MARK, PC5MD_101),
+
+ PINMUX_DATA(PC4_DATA, PC4MD_00),
+ PINMUX_DATA(WE1DQMUWE_MARK, PC4MD_01),
+ PINMUX_DATA(TXD6_MARK, PC4MD_10),
+
+ PINMUX_DATA(PC3_DATA, PC3MD_00),
+ PINMUX_DATA(WE0DQML_MARK, PC3MD_01),
+ PINMUX_DATA(RXD6_MARK, PC3MD_10),
+
+ PINMUX_DATA(PC2_DATA, PC2MD_00),
+ PINMUX_DATA(RDWR_MARK, PC2MD_01),
+ PINMUX_DATA(SCK5_MARK, PC2MD_10),
+
+ PINMUX_DATA(PC1_DATA, PC1MD_0),
+ PINMUX_DATA(RD_MARK, PC1MD_1),
+
+ PINMUX_DATA(PC0_DATA, PC0MD_0),
+ PINMUX_DATA(CS0_MARK, PC0MD_1),
+
+ /* Port D */
+ PINMUX_DATA(D15_MARK, PD15MD_01),
+ PINMUX_DATA(D14_MARK, PD14MD_01),
+
+ PINMUX_DATA(PD13_DATA, PD13MD_00),
+ PINMUX_DATA(D13_MARK, PD13MD_01),
+ PINMUX_DATA(PWM2F_MARK, PD13MD_10),
+
+ PINMUX_DATA(PD12_DATA, PD12MD_00),
+ PINMUX_DATA(D12_MARK, PD12MD_01),
+ PINMUX_DATA(PWM2E_MARK, PD12MD_10),
+
+ PINMUX_DATA(D11_MARK, PD11MD_01),
+ PINMUX_DATA(D10_MARK, PD10MD_01),
+ PINMUX_DATA(D9_MARK, PD9MD_01),
+ PINMUX_DATA(D8_MARK, PD8MD_01),
+ PINMUX_DATA(D7_MARK, PD7MD_01),
+ PINMUX_DATA(D6_MARK, PD6MD_01),
+ PINMUX_DATA(D5_MARK, PD5MD_01),
+ PINMUX_DATA(D4_MARK, PD4MD_01),
+ PINMUX_DATA(D3_MARK, PD3MD_01),
+ PINMUX_DATA(D2_MARK, PD2MD_01),
+ PINMUX_DATA(D1_MARK, PD1MD_01),
+ PINMUX_DATA(D0_MARK, PD0MD_01),
+
+ /* Port E */
+ PINMUX_DATA(PE7_DATA, PE7MD_00),
+ PINMUX_DATA(SDA3_MARK, PE7MD_01),
+ PINMUX_DATA(RXD7_MARK, PE7MD_10),
+
+ PINMUX_DATA(PE6_DATA, PE6MD_00),
+ PINMUX_DATA(SCL3_MARK, PE6MD_01),
+ PINMUX_DATA(RXD6_MARK, PE6MD_10),
+
+ PINMUX_DATA(PE5_DATA, PE5MD_00),
+ PINMUX_DATA(SDA2_MARK, PE5MD_01),
+ PINMUX_DATA(RXD5_MARK, PE5MD_10),
+ PINMUX_DATA(DV_HSYNC_MARK, PE5MD_11),
+
+ PINMUX_DATA(PE4_DATA, PE4MD_00),
+ PINMUX_DATA(SCL2_MARK, PE4MD_01),
+ PINMUX_DATA(DV_VSYNC_MARK, PE4MD_11),
+
+ PINMUX_DATA(PE3_DATA, PE3MD_000),
+ PINMUX_DATA(SDA1_MARK, PE3MD_001),
+ PINMUX_DATA(TCLKD_MARK, PE3MD_010),
+ PINMUX_DATA(ADTRG_MARK, PE3MD_011),
+ PINMUX_DATA(DV_HSYNC_MARK, PE3MD_100),
+
+ PINMUX_DATA(PE2_DATA, PE2MD_000),
+ PINMUX_DATA(SCL1_MARK, PE2MD_001),
+ PINMUX_DATA(TCLKD_MARK, PE2MD_010),
+ PINMUX_DATA(IOIS16_MARK, PE2MD_011),
+ PINMUX_DATA(DV_VSYNC_MARK, PE2MD_100),
+
+ PINMUX_DATA(PE1_DATA, PE1MD_000),
+ PINMUX_DATA(SDA0_MARK, PE1MD_001),
+ PINMUX_DATA(TCLKB_MARK, PE1MD_010),
+ PINMUX_DATA(AUDIO_CLK_MARK, PE1MD_010),
+ PINMUX_DATA(DV_CLK_MARK, PE1MD_100),
+
+ PINMUX_DATA(PE0_DATA, PE0MD_00),
+ PINMUX_DATA(SCL0_MARK, PE0MD_01),
+ PINMUX_DATA(TCLKA_MARK, PE0MD_10),
+ PINMUX_DATA(LCD_EXTCLK_MARK, PE0MD_11),
+
+ /* Port F */
+ PINMUX_DATA(PF23_DATA, PF23MD_000),
+ PINMUX_DATA(SD_D2_MARK, PF23MD_001),
+ PINMUX_DATA(TXD3_MARK, PF23MD_100),
+ PINMUX_DATA(MMC_D2_MARK, PF23MD_101),
+
+ PINMUX_DATA(PF22_DATA, PF22MD_000),
+ PINMUX_DATA(SD_D3_MARK, PF22MD_001),
+ PINMUX_DATA(RXD3_MARK, PF22MD_100),
+ PINMUX_DATA(MMC_D3_MARK, PF22MD_101),
+
+ PINMUX_DATA(PF21_DATA, PF21MD_000),
+ PINMUX_DATA(SD_CMD_MARK, PF21MD_001),
+ PINMUX_DATA(SCK3_MARK, PF21MD_100),
+ PINMUX_DATA(MMC_CMD_MARK, PF21MD_101),
+
+ PINMUX_DATA(PF20_DATA, PF20MD_000),
+ PINMUX_DATA(SD_CLK_MARK, PF20MD_001),
+ PINMUX_DATA(SSIDATA3_MARK, PF20MD_010),
+ PINMUX_DATA(MMC_CLK_MARK, PF20MD_101),
+
+ PINMUX_DATA(PF19_DATA, PF19MD_000),
+ PINMUX_DATA(SD_D0_MARK, PF19MD_001),
+ PINMUX_DATA(SSIWS3_MARK, PF19MD_010),
+ PINMUX_DATA(IRQ7_PF_MARK, PF19MD_100),
+ PINMUX_DATA(MMC_D0_MARK, PF19MD_101),
+
+ PINMUX_DATA(PF18_DATA, PF18MD_000),
+ PINMUX_DATA(SD_D1_MARK, PF18MD_001),
+ PINMUX_DATA(SSISCK3_MARK, PF18MD_010),
+ PINMUX_DATA(IRQ6_PF_MARK, PF18MD_100),
+ PINMUX_DATA(MMC_D1_MARK, PF18MD_101),
+
+ PINMUX_DATA(PF17_DATA, PF17MD_000),
+ PINMUX_DATA(SD_WP_MARK, PF17MD_001),
+ PINMUX_DATA(FRB_MARK, PF17MD_011),
+ PINMUX_DATA(IRQ5_PF_MARK, PF17MD_100),
+
+ PINMUX_DATA(PF16_DATA, PF16MD_000),
+ PINMUX_DATA(SD_CD_MARK, PF16MD_001),
+ PINMUX_DATA(FCE_MARK, PF16MD_011),
+ PINMUX_DATA(IRQ4_PF_MARK, PF16MD_100),
+ PINMUX_DATA(MMC_CD_MARK, PF16MD_101),
+
+ PINMUX_DATA(PF15_DATA, PF15MD_000),
+ PINMUX_DATA(A0_MARK, PF15MD_001),
+ PINMUX_DATA(SSIDATA2_MARK, PF15MD_010),
+ PINMUX_DATA(WDTOVF_MARK, PF15MD_011),
+ PINMUX_DATA(TXD2_MARK, PF15MD_100),
+
+ PINMUX_DATA(PF14_DATA, PF14MD_000),
+ PINMUX_DATA(A25_MARK, PF14MD_001),
+ PINMUX_DATA(SSIWS2_MARK, PF14MD_010),
+ PINMUX_DATA(RXD2_MARK, PF14MD_100),
+
+ PINMUX_DATA(PF13_DATA, PF13MD_000),
+ PINMUX_DATA(A24_MARK, PF13MD_001),
+ PINMUX_DATA(SSISCK2_MARK, PF13MD_010),
+ PINMUX_DATA(SCK2_MARK, PF13MD_100),
+
+ PINMUX_DATA(PF12_DATA, PF12MD_000),
+ PINMUX_DATA(SSIDATA1_MARK, PF12MD_010),
+ PINMUX_DATA(DV_DATA12_MARK, PF12MD_011),
+ PINMUX_DATA(TXD1_MARK, PF12MD_100),
+ PINMUX_DATA(MMC_D7_MARK, PF12MD_101),
+
+ PINMUX_DATA(PF11_DATA, PF11MD_000),
+ PINMUX_DATA(SSIWS1_MARK, PF11MD_010),
+ PINMUX_DATA(DV_DATA2_MARK, PF11MD_011),
+ PINMUX_DATA(RXD1_MARK, PF11MD_100),
+ PINMUX_DATA(MMC_D6_MARK, PF11MD_101),
+
+ PINMUX_DATA(PF10_DATA, PF10MD_000),
+ PINMUX_DATA(CS1_MARK, PF10MD_001),
+ PINMUX_DATA(SSISCK1_MARK, PF10MD_010),
+ PINMUX_DATA(DV_DATA1_MARK, PF10MD_011),
+ PINMUX_DATA(SCK1_MARK, PF10MD_100),
+ PINMUX_DATA(MMC_D5_MARK, PF10MD_101),
+
+ PINMUX_DATA(PF9_DATA, PF9MD_000),
+ PINMUX_DATA(BS_MARK, PF9MD_001),
+ PINMUX_DATA(DV_DATA0_MARK, PF9MD_011),
+ PINMUX_DATA(SCK0_MARK, PF9MD_100),
+ PINMUX_DATA(MMC_D4_MARK, PF9MD_101),
+ PINMUX_DATA(RTS1_MARK, PF9MD_110),
+
+ PINMUX_DATA(PF8_DATA, PF8MD_000),
+ PINMUX_DATA(A23_MARK, PF8MD_001),
+ PINMUX_DATA(TXD0_MARK, PF8MD_100),
+
+ PINMUX_DATA(PF7_DATA, PF7MD_000),
+ PINMUX_DATA(SSIRXD0_MARK, PF7MD_010),
+ PINMUX_DATA(RXD0_MARK, PF7MD_100),
+ PINMUX_DATA(CTS1_MARK, PF7MD_110),
+
+ PINMUX_DATA(PF6_DATA, PF6MD_000),
+ PINMUX_DATA(CE2A_MARK, PF6MD_001),
+ PINMUX_DATA(SSITXD0_MARK, PF6MD_010),
+
+ PINMUX_DATA(PF5_DATA, PF5MD_000),
+ PINMUX_DATA(SSIWS0_MARK, PF5MD_010),
+
+ PINMUX_DATA(PF4_DATA, PF4MD_000),
+ PINMUX_DATA(CS5CE1A_MARK, PF4MD_001),
+ PINMUX_DATA(SSISCK0_MARK, PF4MD_010),
+
+ PINMUX_DATA(PF3_DATA, PF3MD_000),
+ PINMUX_DATA(CS2_MARK, PF3MD_001),
+ PINMUX_DATA(MISO1_MARK, PF3MD_011),
+ PINMUX_DATA(TIOC4D_MARK, PF3MD_100),
+
+ PINMUX_DATA(PF2_DATA, PF2MD_000),
+ PINMUX_DATA(WAIT_MARK, PF2MD_001),
+ PINMUX_DATA(MOSI1_MARK, PF2MD_011),
+ PINMUX_DATA(TIOC4C_MARK, PF2MD_100),
+ PINMUX_DATA(TEND0_MARK, PF2MD_101),
+
+ PINMUX_DATA(PF1_DATA, PF1MD_000),
+ PINMUX_DATA(BACK_MARK, PF1MD_001),
+ PINMUX_DATA(SSL10_MARK, PF1MD_011),
+ PINMUX_DATA(TIOC4B_MARK, PF1MD_100),
+ PINMUX_DATA(DACK0_MARK, PF1MD_101),
+
+ PINMUX_DATA(PF0_DATA, PF0MD_000),
+ PINMUX_DATA(BREQ_MARK, PF0MD_001),
+ PINMUX_DATA(RSPCK1_MARK, PF0MD_011),
+ PINMUX_DATA(TIOC4A_MARK, PF0MD_100),
+ PINMUX_DATA(DREQ0_MARK, PF0MD_101),
+
+ /* Port G */
+ PINMUX_DATA(PG27_DATA, PG27MD_00),
+ PINMUX_DATA(LCD_TCON2_MARK, PG27MD_10),
+ PINMUX_DATA(LCD_EXTCLK_MARK, PG27MD_11),
+ PINMUX_DATA(LCD_DE_MARK, PG27MD_11),
+
+ PINMUX_DATA(PG26_DATA, PG26MD_00),
+ PINMUX_DATA(LCD_TCON1_MARK, PG26MD_10),
+ PINMUX_DATA(LCD_HSYNC_MARK, PG26MD_10),
+
+ PINMUX_DATA(PG25_DATA, PG25MD_00),
+ PINMUX_DATA(LCD_TCON0_MARK, PG25MD_10),
+ PINMUX_DATA(LCD_VSYNC_MARK, PG25MD_10),
+
+ PINMUX_DATA(PG24_DATA, PG24MD_00),
+ PINMUX_DATA(LCD_CLK_MARK, PG24MD_10),
+
+ PINMUX_DATA(PG23_DATA, PG23MD_000),
+ PINMUX_DATA(LCD_DATA23_PG23_MARK, PG23MD_010),
+ PINMUX_DATA(LCD_TCON6_MARK, PG23MD_011),
+ PINMUX_DATA(TXD5_MARK, PG23MD_100),
+
+ PINMUX_DATA(PG22_DATA, PG22MD_000),
+ PINMUX_DATA(LCD_DATA22_PG22_MARK, PG22MD_010),
+ PINMUX_DATA(LCD_TCON5_MARK, PG22MD_011),
+ PINMUX_DATA(RXD5_MARK, PG22MD_100),
+
+ PINMUX_DATA(PG21_DATA, PG21MD_000),
+ PINMUX_DATA(DV_DATA7_MARK, PG21MD_001),
+ PINMUX_DATA(LCD_DATA21_PG21_MARK, PG21MD_010),
+ PINMUX_DATA(LCD_TCON4_MARK, PG21MD_011),
+ PINMUX_DATA(TXD4_MARK, PG21MD_100),
+
+ PINMUX_DATA(PG20_DATA, PG20MD_000),
+ PINMUX_DATA(DV_DATA6_MARK, PG20MD_001),
+ PINMUX_DATA(LCD_DATA20_PG20_MARK, PG21MD_010),
+ PINMUX_DATA(LCD_TCON3_MARK, PG20MD_011),
+ PINMUX_DATA(RXD4_MARK, PG20MD_100),
+
+ PINMUX_DATA(PG19_DATA, PG19MD_000),
+ PINMUX_DATA(DV_DATA5_MARK, PG19MD_001),
+ PINMUX_DATA(LCD_DATA19_PG19_MARK, PG19MD_010),
+ PINMUX_DATA(SPDIF_OUT_MARK, PG19MD_011),
+ PINMUX_DATA(SCK5_MARK, PG19MD_100),
+
+ PINMUX_DATA(PG18_DATA, PG18MD_000),
+ PINMUX_DATA(DV_DATA4_MARK, PG18MD_001),
+ PINMUX_DATA(LCD_DATA18_PG18_MARK, PG18MD_010),
+ PINMUX_DATA(SPDIF_IN_MARK, PG18MD_011),
+ PINMUX_DATA(SCK4_MARK, PG18MD_100),
+
+// TODO hardware manual has PG17 3 bits wide in reg picture and 2 bits in description
+// we're going with 2 bits
+ PINMUX_DATA(PG17_DATA, PG17MD_00),
+ PINMUX_DATA(WE3ICIOWRAHDQMUU_MARK, PG17MD_01),
+ PINMUX_DATA(LCD_DATA17_PG17_MARK, PG17MD_10),
+
+// TODO hardware manual has PG16 3 bits wide in reg picture and 2 bits in description
+// we're going with 2 bits
+ PINMUX_DATA(PG16_DATA, PG16MD_00),
+ PINMUX_DATA(WE2ICIORDDQMUL_MARK, PG16MD_01),
+ PINMUX_DATA(LCD_DATA16_PG16_MARK, PG16MD_10),
+
+ PINMUX_DATA(PG15_DATA, PG15MD_00),
+ PINMUX_DATA(D31_MARK, PG15MD_01),
+ PINMUX_DATA(LCD_DATA15_PG15_MARK, PG15MD_10),
+ PINMUX_DATA(PINT7_PG_MARK, PG15MD_11),
+
+ PINMUX_DATA(PG14_DATA, PG14MD_00),
+ PINMUX_DATA(D30_MARK, PG14MD_01),
+ PINMUX_DATA(LCD_DATA14_PG14_MARK, PG14MD_10),
+ PINMUX_DATA(PINT6_PG_MARK, PG14MD_11),
+
+ PINMUX_DATA(PG13_DATA, PG13MD_00),
+ PINMUX_DATA(D29_MARK, PG13MD_01),
+ PINMUX_DATA(LCD_DATA13_PG13_MARK, PG13MD_10),
+ PINMUX_DATA(PINT5_PG_MARK, PG13MD_11),
+
+ PINMUX_DATA(PG12_DATA, PG12MD_00),
+ PINMUX_DATA(D28_MARK, PG12MD_01),
+ PINMUX_DATA(LCD_DATA12_PG12_MARK, PG12MD_10),
+ PINMUX_DATA(PINT4_PG_MARK, PG12MD_11),
+
+ PINMUX_DATA(PG11_DATA, PG11MD_000),
+ PINMUX_DATA(D27_MARK, PG11MD_001),
+ PINMUX_DATA(LCD_DATA11_PG11_MARK, PG11MD_010),
+ PINMUX_DATA(PINT3_PG_MARK, PG11MD_011),
+ PINMUX_DATA(TIOC3D_MARK, PG11MD_100),
+
+ PINMUX_DATA(PG10_DATA, PG10MD_000),
+ PINMUX_DATA(D26_MARK, PG10MD_001),
+ PINMUX_DATA(LCD_DATA10_PG10_MARK, PG10MD_010),
+ PINMUX_DATA(PINT2_PG_MARK, PG10MD_011),
+ PINMUX_DATA(TIOC3C_MARK, PG10MD_100),
+
+ PINMUX_DATA(PG9_DATA, PG9MD_000),
+ PINMUX_DATA(D25_MARK, PG9MD_001),
+ PINMUX_DATA(LCD_DATA9_PG9_MARK, PG9MD_010),
+ PINMUX_DATA(PINT1_PG_MARK, PG9MD_011),
+ PINMUX_DATA(TIOC3B_MARK, PG9MD_100),
+
+ PINMUX_DATA(PG8_DATA, PG8MD_000),
+ PINMUX_DATA(D24_MARK, PG8MD_001),
+ PINMUX_DATA(LCD_DATA8_PG8_MARK, PG8MD_010),
+ PINMUX_DATA(PINT0_PG_MARK, PG8MD_011),
+ PINMUX_DATA(TIOC3A_MARK, PG8MD_100),
+
+ PINMUX_DATA(PG7_DATA, PG7MD_000),
+ PINMUX_DATA(D23_MARK, PG7MD_001),
+ PINMUX_DATA(LCD_DATA7_PG7_MARK, PG7MD_010),
+ PINMUX_DATA(IRQ7_PG_MARK, PG7MD_011),
+ PINMUX_DATA(TIOC2B_MARK, PG7MD_100),
+
+ PINMUX_DATA(PG6_DATA, PG6MD_000),
+ PINMUX_DATA(D22_MARK, PG6MD_001),
+ PINMUX_DATA(LCD_DATA6_PG6_MARK, PG6MD_010),
+ PINMUX_DATA(IRQ6_PG_MARK, PG6MD_011),
+ PINMUX_DATA(TIOC2A_MARK, PG6MD_100),
+
+ PINMUX_DATA(PG5_DATA, PG5MD_000),
+ PINMUX_DATA(D21_MARK, PG5MD_001),
+ PINMUX_DATA(LCD_DATA5_PG5_MARK, PG5MD_010),
+ PINMUX_DATA(IRQ5_PG_MARK, PG5MD_011),
+ PINMUX_DATA(TIOC1B_MARK, PG5MD_100),
+
+ PINMUX_DATA(PG4_DATA, PG4MD_000),
+ PINMUX_DATA(D20_MARK, PG4MD_001),
+ PINMUX_DATA(LCD_DATA4_PG4_MARK, PG4MD_010),
+ PINMUX_DATA(IRQ4_PG_MARK, PG4MD_011),
+ PINMUX_DATA(TIOC1A_MARK, PG4MD_100),
+
+ PINMUX_DATA(PG3_DATA, PG3MD_000),
+ PINMUX_DATA(D19_MARK, PG3MD_001),
+ PINMUX_DATA(LCD_DATA3_PG3_MARK, PG3MD_010),
+ PINMUX_DATA(IRQ3_PG_MARK, PG3MD_011),
+ PINMUX_DATA(TIOC0D_MARK, PG3MD_100),
+
+ PINMUX_DATA(PG2_DATA, PG2MD_000),
+ PINMUX_DATA(D18_MARK, PG2MD_001),
+ PINMUX_DATA(LCD_DATA2_PG2_MARK, PG2MD_010),
+ PINMUX_DATA(IRQ2_PG_MARK, PG2MD_011),
+ PINMUX_DATA(TIOC0C_MARK, PG2MD_100),
+
+ PINMUX_DATA(PG1_DATA, PG1MD_000),
+ PINMUX_DATA(D17_MARK, PG1MD_001),
+ PINMUX_DATA(LCD_DATA1_PG1_MARK, PG1MD_010),
+ PINMUX_DATA(IRQ1_PG_MARK, PG1MD_011),
+ PINMUX_DATA(TIOC0B_MARK, PG1MD_100),
+
+ PINMUX_DATA(PG0_DATA, PG0MD_000),
+ PINMUX_DATA(D16_MARK, PG0MD_001),
+ PINMUX_DATA(LCD_DATA0_PG0_MARK, PG0MD_010),
+ PINMUX_DATA(IRQ0_PG_MARK, PG0MD_011),
+ PINMUX_DATA(TIOC0A_MARK, PG0MD_100),
+
+ /* Port H */
+ PINMUX_DATA(PH7_DATA, PH7MD_00),
+ PINMUX_DATA(PHAN7_MARK, PH7MD_01),
+ PINMUX_DATA(PINT7_PH_MARK, PH7MD_10),
+
+ PINMUX_DATA(PH6_DATA, PH6MD_00),
+ PINMUX_DATA(PHAN6_MARK, PH6MD_01),
+ PINMUX_DATA(PINT6_PH_MARK, PH6MD_10),
+
+ PINMUX_DATA(PH5_DATA, PH5MD_00),
+ PINMUX_DATA(PHAN5_MARK, PH5MD_01),
+ PINMUX_DATA(PINT5_PH_MARK, PH5MD_10),
+ PINMUX_DATA(LCD_EXTCLK_MARK, PH5MD_11),
+
+ PINMUX_DATA(PH4_DATA, PH4MD_00),
+ PINMUX_DATA(PHAN4_MARK, PH4MD_01),
+ PINMUX_DATA(PINT4_PH_MARK, PH4MD_10),
+
+ PINMUX_DATA(PH3_DATA, PH3MD_00),
+ PINMUX_DATA(PHAN3_MARK, PH3MD_01),
+ PINMUX_DATA(PINT3_PH_MARK, PH3MD_10),
+
+ PINMUX_DATA(PH2_DATA, PH2MD_00),
+ PINMUX_DATA(PHAN2_MARK, PH2MD_01),
+ PINMUX_DATA(PINT2_PH_MARK, PH2MD_10),
+
+ PINMUX_DATA(PH1_DATA, PH1MD_00),
+ PINMUX_DATA(PHAN1_MARK, PH1MD_01),
+ PINMUX_DATA(PINT1_PH_MARK, PH1MD_10),
+
+ PINMUX_DATA(PH0_DATA, PH0MD_00),
+ PINMUX_DATA(PHAN0_MARK, PH0MD_01),
+ PINMUX_DATA(PINT0_PH_MARK, PH0MD_10),
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PINMUX_DATA(PJ31_DATA, PJ31MD_0),
+ PINMUX_DATA(DV_CLK_MARK, PJ31MD_1),
+
+ PINMUX_DATA(PJ30_DATA, PJ30MD_000),
+ PINMUX_DATA(SSIDATA5_MARK, PJ30MD_010),
+ PINMUX_DATA(TIOC2B_MARK, PJ30MD_100),
+ PINMUX_DATA(IETXD_MARK, PJ30MD_101),
+
+ PINMUX_DATA(PJ29_DATA, PJ29MD_000),
+ PINMUX_DATA(SSIWS5_MARK, PJ29MD_010),
+ PINMUX_DATA(TIOC2A_MARK, PJ29MD_100),
+ PINMUX_DATA(IERXD_MARK, PJ29MD_101),
+
+ PINMUX_DATA(PJ28_DATA, PJ28MD_000),
+ PINMUX_DATA(SSISCK5_MARK, PJ28MD_010),
+ PINMUX_DATA(TIOC1B_MARK, PJ28MD_100),
+ PINMUX_DATA(RTS7_MARK, PJ28MD_101),
+
+ PINMUX_DATA(PJ27_DATA, PJ27MD_000),
+ PINMUX_DATA(TIOC1A_MARK, PJ27MD_100),
+ PINMUX_DATA(CTS7_MARK, PJ27MD_101),
+
+ PINMUX_DATA(PJ26_DATA, PJ26MD_000),
+ PINMUX_DATA(SSIDATA4_MARK, PJ26MD_010),
+ PINMUX_DATA(LCD_TCON5_MARK, PJ26MD_011),
+ PINMUX_DATA(TXD7_MARK, PJ26MD_101),
+
+ PINMUX_DATA(PJ25_DATA, PJ25MD_000),
+ PINMUX_DATA(SSIWS4_MARK, PJ25MD_010),
+ PINMUX_DATA(LCD_TCON4_MARK, PJ25MD_011),
+ PINMUX_DATA(SPDIF_OUT_MARK, PJ25MD_100),
+ PINMUX_DATA(RXD7_MARK, PJ25MD_101),
+
+ PINMUX_DATA(PJ24_DATA, PJ24MD_000),
+ PINMUX_DATA(SSISCK4_MARK, PJ24MD_010),
+ PINMUX_DATA(LCD_TCON3_MARK, PJ24MD_011),
+ PINMUX_DATA(SPDIF_IN_MARK, PJ24MD_100),
+ PINMUX_DATA(SCK7_MARK, PJ24MD_101),
+
+ PINMUX_DATA(PJ23_DATA, PJ23MD_000),
+ PINMUX_DATA(DV_DATA23_MARK, PJ23MD_001),
+ PINMUX_DATA(LCD_DATA23_PJ23_MARK, PJ23MD_010),
+ PINMUX_DATA(LCD_TCON6_MARK, PJ23MD_011),
+ PINMUX_DATA(IRQ3_PJ_MARK, PJ23MD_100),
+ PINMUX_DATA(CTX1_MARK, PJ23MD_101),
+
+ PINMUX_DATA(PJ22_DATA, PJ22MD_000),
+ PINMUX_DATA(DV_DATA22_MARK, PJ22MD_001),
+ PINMUX_DATA(LCD_DATA22_PJ22_MARK, PJ22MD_010),
+ PINMUX_DATA(LCD_TCON5_MARK, PJ22MD_011),
+ PINMUX_DATA(IRQ2_PJ_MARK, PJ22MD_100),
+ PINMUX_DATA(CRX1_MARK, PJ22MD_101),
+ PINMUX_DATA(CRX0_CRX1_MARK, PJ22MD_110),
+
+ PINMUX_DATA(PJ21_DATA, PJ21MD_000),
+ PINMUX_DATA(DV_DATA21_MARK, PJ21MD_001),
+ PINMUX_DATA(LCD_DATA21_PJ21_MARK, PJ21MD_010),
+ PINMUX_DATA(LCD_TCON4_MARK, PJ21MD_011),
+ PINMUX_DATA(IRQ1_PJ_MARK, PJ21MD_100),
+ PINMUX_DATA(CTX2_MARK, PJ21MD_101),
+
+ PINMUX_DATA(PJ20_DATA, PJ20MD_000),
+ PINMUX_DATA(DV_DATA20_MARK, PJ20MD_001),
+ PINMUX_DATA(LCD_DATA20_PJ20_MARK, PJ20MD_010),
+ PINMUX_DATA(LCD_TCON3_MARK, PJ20MD_011),
+ PINMUX_DATA(IRQ0_PJ_MARK, PJ20MD_100),
+ PINMUX_DATA(CRX2_MARK, PJ20MD_101),
+ PINMUX_DATA(CRX0CRX1CRX2_PJ20_MARK, PJ20MD_110),
+
+ PINMUX_DATA(PJ19_DATA, PJ19MD_000),
+ PINMUX_DATA(DV_DATA19_MARK, PJ19MD_001),
+ PINMUX_DATA(LCD_DATA19_PJ19_MARK, PJ19MD_010),
+ PINMUX_DATA(MISO0_PJ19_MARK, PJ19MD_011),
+ PINMUX_DATA(TIOC0D_MARK, PJ19MD_100),
+ PINMUX_DATA(SIOFRXD_MARK, PJ19MD_101),
+ PINMUX_DATA(AUDIO_XOUT_MARK, PJ19MD_110),
+
+ PINMUX_DATA(PJ18_DATA, PJ18MD_000),
+ PINMUX_DATA(DV_DATA18_MARK, PJ18MD_001),
+ PINMUX_DATA(LCD_DATA18_PJ18_MARK, PJ18MD_010),
+ PINMUX_DATA(MOSI0_PJ18_MARK, PJ18MD_011),
+ PINMUX_DATA(TIOC0C_MARK, PJ18MD_100),
+ PINMUX_DATA(SIOFTXD_MARK, PJ18MD_101),
+
+ PINMUX_DATA(PJ17_DATA, PJ17MD_000),
+ PINMUX_DATA(DV_DATA17_MARK, PJ17MD_001),
+ PINMUX_DATA(LCD_DATA17_PJ17_MARK, PJ17MD_010),
+ PINMUX_DATA(SSL00_PJ17_MARK, PJ17MD_011),
+ PINMUX_DATA(TIOC0B_MARK, PJ17MD_100),
+ PINMUX_DATA(SIOFSYNC_MARK, PJ17MD_101),
+
+ PINMUX_DATA(PJ16_DATA, PJ16MD_000),
+ PINMUX_DATA(DV_DATA16_MARK, PJ16MD_001),
+ PINMUX_DATA(LCD_DATA16_PJ16_MARK, PJ16MD_010),
+ PINMUX_DATA(RSPCK0_PJ16_MARK, PJ16MD_011),
+ PINMUX_DATA(TIOC0A_MARK, PJ16MD_100),
+ PINMUX_DATA(SIOFSCK_MARK, PJ16MD_101),
+
+ PINMUX_DATA(PJ15_DATA, PJ15MD_000),
+ PINMUX_DATA(DV_DATA15_MARK, PJ15MD_001),
+ PINMUX_DATA(LCD_DATA15_PJ15_MARK, PJ15MD_010),
+ PINMUX_DATA(PINT7_PJ_MARK, PJ15MD_011),
+ PINMUX_DATA(PWM2H_MARK, PJ15MD_100),
+ PINMUX_DATA(TXD7_MARK, PJ15MD_101),
+
+ PINMUX_DATA(PJ14_DATA, PJ14MD_000),
+ PINMUX_DATA(DV_DATA14_MARK, PJ14MD_001),
+ PINMUX_DATA(LCD_DATA14_PJ14_MARK, PJ14MD_010),
+ PINMUX_DATA(PINT6_PJ_MARK, PJ14MD_011),
+ PINMUX_DATA(PWM2G_MARK, PJ14MD_100),
+ PINMUX_DATA(TXD6_MARK, PJ14MD_101),
+
+ PINMUX_DATA(PJ13_DATA, PJ13MD_000),
+ PINMUX_DATA(DV_DATA13_MARK, PJ13MD_001),
+ PINMUX_DATA(LCD_DATA13_PJ13_MARK, PJ13MD_010),
+ PINMUX_DATA(PINT5_PJ_MARK, PJ13MD_011),
+ PINMUX_DATA(PWM2F_MARK, PJ13MD_100),
+ PINMUX_DATA(TXD5_MARK, PJ13MD_101),
+
+ PINMUX_DATA(PJ12_DATA, PJ12MD_000),
+ PINMUX_DATA(DV_DATA12_MARK, PJ12MD_001),
+ PINMUX_DATA(LCD_DATA12_PJ12_MARK, PJ12MD_010),
+ PINMUX_DATA(PINT4_PJ_MARK, PJ12MD_011),
+ PINMUX_DATA(PWM2E_MARK, PJ12MD_100),
+ PINMUX_DATA(SCK7_MARK, PJ12MD_101),
+
+ PINMUX_DATA(PJ11_DATA, PJ11MD_000),
+ PINMUX_DATA(DV_DATA11_MARK, PJ11MD_001),
+ PINMUX_DATA(LCD_DATA11_PJ11_MARK, PJ11MD_010),
+ PINMUX_DATA(PINT3_PJ_MARK, PJ11MD_011),
+ PINMUX_DATA(PWM2D_MARK, PJ11MD_100),
+ PINMUX_DATA(SCK6_MARK, PJ11MD_101),
+
+ PINMUX_DATA(PJ10_DATA, PJ10MD_000),
+ PINMUX_DATA(DV_DATA10_MARK, PJ10MD_001),
+ PINMUX_DATA(LCD_DATA10_PJ10_MARK, PJ10MD_010),
+ PINMUX_DATA(PINT2_PJ_MARK, PJ10MD_011),
+ PINMUX_DATA(PWM2C_MARK, PJ10MD_100),
+ PINMUX_DATA(SCK5_MARK, PJ10MD_101),
+
+ PINMUX_DATA(PJ9_DATA, PJ9MD_000),
+ PINMUX_DATA(DV_DATA9_MARK, PJ9MD_001),
+ PINMUX_DATA(LCD_DATA9_PJ9_MARK, PJ9MD_010),
+ PINMUX_DATA(PINT1_PJ_MARK, PJ9MD_011),
+ PINMUX_DATA(PWM2B_MARK, PJ9MD_100),
+ PINMUX_DATA(RTS5_MARK, PJ9MD_101),
+
+ PINMUX_DATA(PJ8_DATA, PJ8MD_000),
+ PINMUX_DATA(DV_DATA8_MARK, PJ8MD_001),
+ PINMUX_DATA(LCD_DATA8_PJ8_MARK, PJ8MD_010),
+ PINMUX_DATA(PINT0_PJ_MARK, PJ8MD_011),
+ PINMUX_DATA(PWM2A_MARK, PJ8MD_100),
+ PINMUX_DATA(CTS5_MARK, PJ8MD_101),
+
+ PINMUX_DATA(PJ7_DATA, PJ7MD_000),
+ PINMUX_DATA(DV_DATA7_MARK, PJ7MD_001),
+ PINMUX_DATA(LCD_DATA7_PJ7_MARK, PJ7MD_010),
+ PINMUX_DATA(SD_D2_MARK, PJ7MD_011),
+ PINMUX_DATA(PWM1H_MARK, PJ7MD_100),
+
+ PINMUX_DATA(PJ6_DATA, PJ6MD_000),
+ PINMUX_DATA(DV_DATA6_MARK, PJ6MD_001),
+ PINMUX_DATA(LCD_DATA6_PJ6_MARK, PJ6MD_010),
+ PINMUX_DATA(SD_D3_MARK, PJ6MD_011),
+ PINMUX_DATA(PWM1G_MARK, PJ6MD_100),
+
+ PINMUX_DATA(PJ5_DATA, PJ5MD_000),
+ PINMUX_DATA(DV_DATA5_MARK, PJ5MD_001),
+ PINMUX_DATA(LCD_DATA5_PJ5_MARK, PJ5MD_010),
+ PINMUX_DATA(SD_CMD_MARK, PJ5MD_011),
+ PINMUX_DATA(PWM1F_MARK, PJ5MD_100),
+
+ PINMUX_DATA(PJ4_DATA, PJ4MD_000),
+ PINMUX_DATA(DV_DATA4_MARK, PJ4MD_001),
+ PINMUX_DATA(LCD_DATA4_PJ4_MARK, PJ4MD_010),
+ PINMUX_DATA(SD_CLK_MARK, PJ4MD_011),
+ PINMUX_DATA(PWM1E_MARK, PJ4MD_100),
+
+ PINMUX_DATA(PJ3_DATA, PJ3MD_000),
+ PINMUX_DATA(DV_DATA3_MARK, PJ3MD_001),
+ PINMUX_DATA(LCD_DATA3_PJ3_MARK, PJ3MD_010),
+ PINMUX_DATA(SD_D0_MARK, PJ3MD_011),
+ PINMUX_DATA(PWM1D_MARK, PJ3MD_100),
+
+ PINMUX_DATA(PJ2_DATA, PJ2MD_000),
+ PINMUX_DATA(DV_DATA2_MARK, PJ2MD_001),
+ PINMUX_DATA(LCD_DATA2_PJ2_MARK, PJ2MD_010),
+ PINMUX_DATA(SD_D1_MARK, PJ2MD_011),
+ PINMUX_DATA(PWM1C_MARK, PJ2MD_100),
+
+ PINMUX_DATA(PJ1_DATA, PJ1MD_000),
+ PINMUX_DATA(DV_DATA1_MARK, PJ1MD_001),
+ PINMUX_DATA(LCD_DATA1_PJ1_MARK, PJ1MD_010),
+ PINMUX_DATA(SD_WP_MARK, PJ1MD_011),
+ PINMUX_DATA(PWM1B_MARK, PJ1MD_100),
+
+ PINMUX_DATA(PJ0_DATA, PJ0MD_000),
+ PINMUX_DATA(DV_DATA0_MARK, PJ0MD_001),
+ PINMUX_DATA(LCD_DATA0_PJ0_MARK, PJ0MD_010),
+ PINMUX_DATA(SD_CD_MARK, PJ0MD_011),
+ PINMUX_DATA(PWM1A_MARK, PJ0MD_100),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ /* Port A */
+ PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+ PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+ /* Port B */
+ PINMUX_GPIO(GPIO_PB22, PB22_DATA),
+ PINMUX_GPIO(GPIO_PB21, PB21_DATA),
+ PINMUX_GPIO(GPIO_PB20, PB20_DATA),
+ PINMUX_GPIO(GPIO_PB19, PB19_DATA),
+ PINMUX_GPIO(GPIO_PB18, PB18_DATA),
+ PINMUX_GPIO(GPIO_PB17, PB17_DATA),
+ PINMUX_GPIO(GPIO_PB16, PB16_DATA),
+ PINMUX_GPIO(GPIO_PB15, PB15_DATA),
+ PINMUX_GPIO(GPIO_PB14, PB14_DATA),
+ PINMUX_GPIO(GPIO_PB13, PB13_DATA),
+ PINMUX_GPIO(GPIO_PB12, PB12_DATA),
+ PINMUX_GPIO(GPIO_PB11, PB11_DATA),
+ PINMUX_GPIO(GPIO_PB10, PB10_DATA),
+ PINMUX_GPIO(GPIO_PB9, PB9_DATA),
+ PINMUX_GPIO(GPIO_PB8, PB8_DATA),
+ PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+ PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+ PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+ PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+ PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+ PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+ PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+
+ /* Port C */
+ PINMUX_GPIO(GPIO_PC8, PC8_DATA),
+ PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+ PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+ PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+ PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+ PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+ PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+ PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+ PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+ /* Port D */
+ PINMUX_GPIO(GPIO_PD15, PD15_DATA),
+ PINMUX_GPIO(GPIO_PD14, PD14_DATA),
+ PINMUX_GPIO(GPIO_PD13, PD13_DATA),
+ PINMUX_GPIO(GPIO_PD12, PD12_DATA),
+ PINMUX_GPIO(GPIO_PD11, PD11_DATA),
+ PINMUX_GPIO(GPIO_PD10, PD10_DATA),
+ PINMUX_GPIO(GPIO_PD9, PD9_DATA),
+ PINMUX_GPIO(GPIO_PD8, PD8_DATA),
+ PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+ PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+ PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+ PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+ PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+ PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+ PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+ PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+ /* Port E */
+ PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+ PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+ PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+ PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+ PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+ PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+ PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+ PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+ /* Port F */
+ PINMUX_GPIO(GPIO_PF23, PF23_DATA),
+ PINMUX_GPIO(GPIO_PF22, PF22_DATA),
+ PINMUX_GPIO(GPIO_PF21, PF21_DATA),
+ PINMUX_GPIO(GPIO_PF20, PF20_DATA),
+ PINMUX_GPIO(GPIO_PF19, PF19_DATA),
+ PINMUX_GPIO(GPIO_PF18, PF18_DATA),
+ PINMUX_GPIO(GPIO_PF17, PF17_DATA),
+ PINMUX_GPIO(GPIO_PF16, PF16_DATA),
+ PINMUX_GPIO(GPIO_PF15, PF15_DATA),
+ PINMUX_GPIO(GPIO_PF14, PF14_DATA),
+ PINMUX_GPIO(GPIO_PF13, PF13_DATA),
+ PINMUX_GPIO(GPIO_PF12, PF12_DATA),
+ PINMUX_GPIO(GPIO_PF11, PF11_DATA),
+ PINMUX_GPIO(GPIO_PF10, PF10_DATA),
+ PINMUX_GPIO(GPIO_PF9, PF9_DATA),
+ PINMUX_GPIO(GPIO_PF8, PF8_DATA),
+ PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+ PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+ PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+ PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+ PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+ PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+ PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+ PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+ /* Port G */
+ PINMUX_GPIO(GPIO_PG27, PG27_DATA),
+ PINMUX_GPIO(GPIO_PG26, PG26_DATA),
+ PINMUX_GPIO(GPIO_PG25, PG25_DATA),
+ PINMUX_GPIO(GPIO_PG24, PG24_DATA),
+ PINMUX_GPIO(GPIO_PG23, PG23_DATA),
+ PINMUX_GPIO(GPIO_PG22, PG22_DATA),
+ PINMUX_GPIO(GPIO_PG21, PG21_DATA),
+ PINMUX_GPIO(GPIO_PG20, PG20_DATA),
+ PINMUX_GPIO(GPIO_PG19, PG19_DATA),
+ PINMUX_GPIO(GPIO_PG18, PG18_DATA),
+ PINMUX_GPIO(GPIO_PG17, PG17_DATA),
+ PINMUX_GPIO(GPIO_PG16, PG16_DATA),
+ PINMUX_GPIO(GPIO_PG15, PG15_DATA),
+ PINMUX_GPIO(GPIO_PG14, PG14_DATA),
+ PINMUX_GPIO(GPIO_PG13, PG13_DATA),
+ PINMUX_GPIO(GPIO_PG12, PG12_DATA),
+ PINMUX_GPIO(GPIO_PG11, PG11_DATA),
+ PINMUX_GPIO(GPIO_PG10, PG10_DATA),
+ PINMUX_GPIO(GPIO_PG9, PG9_DATA),
+ PINMUX_GPIO(GPIO_PG8, PG8_DATA),
+ PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+ PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+ PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+ PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+ PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+ PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+ PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+ PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+ /* Port H - Port H does not have a Data Register */
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PINMUX_GPIO(GPIO_PJ31, PJ31_DATA),
+ PINMUX_GPIO(GPIO_PJ30, PJ30_DATA),
+ PINMUX_GPIO(GPIO_PJ29, PJ29_DATA),
+ PINMUX_GPIO(GPIO_PJ28, PJ28_DATA),
+ PINMUX_GPIO(GPIO_PJ27, PJ27_DATA),
+ PINMUX_GPIO(GPIO_PJ26, PJ26_DATA),
+ PINMUX_GPIO(GPIO_PJ25, PJ25_DATA),
+ PINMUX_GPIO(GPIO_PJ24, PJ24_DATA),
+ PINMUX_GPIO(GPIO_PJ23, PJ23_DATA),
+ PINMUX_GPIO(GPIO_PJ22, PJ22_DATA),
+ PINMUX_GPIO(GPIO_PJ21, PJ21_DATA),
+ PINMUX_GPIO(GPIO_PJ20, PJ20_DATA),
+ PINMUX_GPIO(GPIO_PJ19, PJ19_DATA),
+ PINMUX_GPIO(GPIO_PJ18, PJ18_DATA),
+ PINMUX_GPIO(GPIO_PJ17, PJ17_DATA),
+ PINMUX_GPIO(GPIO_PJ16, PJ16_DATA),
+ PINMUX_GPIO(GPIO_PJ15, PJ15_DATA),
+ PINMUX_GPIO(GPIO_PJ14, PJ14_DATA),
+ PINMUX_GPIO(GPIO_PJ13, PJ13_DATA),
+ PINMUX_GPIO(GPIO_PJ12, PJ12_DATA),
+ PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
+ PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
+ PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
+ PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
+ PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+ PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+ PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+ PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+ PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+ PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+ PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+ PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+
+ /* INTC */
+ PINMUX_GPIO(GPIO_FN_IRQ7_PG, IRQ7_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6_PG, IRQ6_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5_PG, IRQ5_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4_PG, IRQ4_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PG, IRQ3_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PG, IRQ2_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PG, IRQ1_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PG, IRQ0_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ7_PF, IRQ7_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6_PF, IRQ6_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5_PF, IRQ5_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4_PF, IRQ4_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PJ, IRQ3_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PJ, IRQ2_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PJ, IRQ1_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PJ, IRQ0_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PC, IRQ1_PC_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PC, IRQ0_PC_MARK),
+
+ PINMUX_GPIO(GPIO_FN_PINT7_PG, PINT7_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT6_PG, PINT6_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT5_PG, PINT5_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT4_PG, PINT4_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT3_PG, PINT3_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT2_PG, PINT2_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT1_PG, PINT1_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT0_PG, PINT0_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT7_PH, PINT7_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT6_PH, PINT6_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT5_PH, PINT5_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT4_PH, PINT4_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT3_PH, PINT3_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT2_PH, PINT2_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT1_PH, PINT1_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT0_PH, PINT0_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT7_PJ, PINT7_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT6_PJ, PINT6_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT5_PJ, PINT5_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT4_PJ, PINT4_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT3_PJ, PINT3_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT2_PJ, PINT2_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT1_PJ, PINT1_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT0_PJ, PINT0_PJ_MARK),
+
+ /* WDT */
+ PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
+
+ /* CAN */
+ PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0_CRX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0_CRX1_CRX2, CRX0_CRX1_CRX2_MARK),
+
+ /* DMAC */
+ PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+
+ /* ADC */
+ PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
+
+ /* BSCh */
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+ PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+ PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+ PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+ PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
+ PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
+ PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
+ PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
+ PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
+ PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
+ PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
+ PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
+ PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
+ PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
+ PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
+ PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
+ PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+ PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
+ PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
+ PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
+ PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
+ PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
+ PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
+ PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
+ PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+ PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+ PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+ PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+ PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+ PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+ PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+ PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+ PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
+ PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
+ PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
+ PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
+ PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
+ PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
+ PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
+ PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
+ PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
+ PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5CE1A, CS5CE1A_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+ PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
+ PINMUX_GPIO(GPIO_FN_WE3ICIOWRAHDQMUU, WE3ICIOWRAHDQMUU_MARK),
+ PINMUX_GPIO(GPIO_FN_WE2ICIORDDQMUL, WE2ICIORDDQMUL_MARK),
+ PINMUX_GPIO(GPIO_FN_WE1DQMUWE, WE1DQMUWE_MARK),
+ PINMUX_GPIO(GPIO_FN_WE0DQML, WE0DQML_MARK),
+ PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
+ PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
+ PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
+ PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+ PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+
+ /* TMU */
+ PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKD, TCLKD_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKC, TCLKC_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKB, TCLKB_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKA, TCLKA_MARK),
+
+ /* SCIF */
+ PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS1, RTS1_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS1, CTS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK5, SCK5_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD5, TXD5_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD5, RXD5_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS5, RTS5_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS5, CTS5_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK6, SCK6_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD6, TXD6_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD6, RXD6_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK7, SCK7_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD7, TXD7_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD7, RXD7_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS7, RTS7_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS7, CTS7_MARK),
+
+ /* RSPI */
+ PINMUX_GPIO(GPIO_FN_RSPCK0_PJ16, RSPCK0_PJ16_MARK),
+ PINMUX_GPIO(GPIO_FN_SSL00_PJ17, SSL00_PJ17_MARK),
+ PINMUX_GPIO(GPIO_FN_MOSI0_PJ18, MOSI0_PJ18_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO0_PJ19, MISO0_PJ19_MARK),
+ PINMUX_GPIO(GPIO_FN_RSPCK0_PB17, RSPCK0_PB17_MARK),
+ PINMUX_GPIO(GPIO_FN_SSL00_PB18, SSL00_PB18_MARK),
+ PINMUX_GPIO(GPIO_FN_MOSI0_PB19, MOSI0_PB19_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO0_PB20, MISO0_PB20_MARK),
+ PINMUX_GPIO(GPIO_FN_RSPCK1, RSPCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_MOSI1, MOSI1_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO1, MISO1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSL10, SSL10_MARK),
+
+ /* IIC3 */
+ PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
+
+ /* SSI */
+ PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSITXD0, SSITXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIRXD0, SSIRXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDIO_XOUT, AUDIO_XOUT_MARK),
+
+ /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+ PINMUX_GPIO(GPIO_FN_SIOFTXD, SIOFTXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFRXD, SIOFRXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFSYNC, SIOFSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFSCK, SIOFSCK_MARK),
+
+ /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+ PINMUX_GPIO(GPIO_FN_SPDIF_IN, SPDIF_IN_MARK),
+ PINMUX_GPIO(GPIO_FN_SPDIF_OUT, SPDIF_OUT_MARK),
+
+ /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+ PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+ PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+
+ /* VDC3 */
+ PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+
+ PINMUX_GPIO(GPIO_FN_DV_DATA23, DV_DATA23_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA22, DV_DATA22_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA21, DV_DATA21_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA20, DV_DATA20_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA19, DV_DATA19_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA18, DV_DATA18_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA17, DV_DATA17_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA16, DV_DATA16_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA15, DV_DATA15_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA14, DV_DATA14_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA13, DV_DATA13_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA12, DV_DATA12_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA11, DV_DATA11_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA10, DV_DATA10_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA9, DV_DATA9_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA8, DV_DATA8_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA7, DV_DATA7_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA6, DV_DATA6_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA5, DV_DATA5_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA4, DV_DATA4_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA3, DV_DATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA2, DV_DATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA1, DV_DATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA0, DV_DATA0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_EXTCLK, LCD_EXTCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_VSYNC, LCD_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_DATA23_PG23, LCD_DATA23_PG23_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA22_PG22, LCD_DATA22_PG22_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA21_PG21, LCD_DATA21_PG21_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA20_PG20, LCD_DATA20_PG20_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA19_PG19, LCD_DATA19_PG19_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA18_PG18, LCD_DATA18_PG18_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA17_PG17, LCD_DATA17_PG17_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA16_PG16, LCD_DATA16_PG16_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA15_PG15, LCD_DATA15_PG15_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA14_PG14, LCD_DATA14_PG14_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA13_PG13, LCD_DATA13_PG13_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA12_PG12, LCD_DATA12_PG12_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA11_PG11, LCD_DATA11_PG11_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA10_PG10, LCD_DATA10_PG10_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA9_PG9, LCD_DATA9_PG9_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA8_PG8, LCD_DATA8_PG8_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA7_PG7, LCD_DATA7_PG7_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA6_PG6, LCD_DATA6_PG6_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA5_PG5, LCD_DATA5_PG5_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA4_PG4, LCD_DATA4_PG4_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA3_PG3, LCD_DATA3_PG3_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA2_PG2, LCD_DATA2_PG2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA1_PG1, LCD_DATA1_PG1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA0_PG0, LCD_DATA0_PG0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_DATA23_PJ23, LCD_DATA23_PJ23_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA22_PJ22, LCD_DATA22_PJ22_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA21_PJ21, LCD_DATA21_PJ21_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA20_PJ20, LCD_DATA20_PJ20_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA19_PJ19, LCD_DATA19_PJ19_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA18_PJ18, LCD_DATA18_PJ18_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA17_PJ17, LCD_DATA17_PJ17_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA16_PJ16, LCD_DATA16_PJ16_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA15_PJ15, LCD_DATA15_PJ15_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA14_PJ14, LCD_DATA14_PJ14_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA13_PJ13, LCD_DATA13_PJ13_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA12_PJ12, LCD_DATA12_PJ12_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA11_PJ11, LCD_DATA11_PJ11_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA10_PJ10, LCD_DATA10_PJ10_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA9_PJ9, LCD_DATA9_PJ9_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA8_PJ8, LCD_DATA8_PJ8_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA7_PJ7, LCD_DATA7_PJ7_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA6_PJ6, LCD_DATA6_PJ6_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA5_PJ5, LCD_DATA5_PJ5_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA4_PJ4, LCD_DATA4_PJ4_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA3_PJ3, LCD_DATA3_PJ3_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA2_PJ2, LCD_DATA2_PJ2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA1_PJ1, LCD_DATA1_PJ1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA0_PJ0, LCD_DATA0_PJ0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ /* "name" addr register_size Field_Width */
+
+ /* where Field_Width is 1 for single mode registers or 4 for upto 16
+ mode registers and modes are described in assending order [0..16] */
+
+ { PINMUX_CFG_REG("PAIOR0", 0xfffe3812, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, PA1_IN, PA1_OUT,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, PA0_IN, PA0_OUT }
+ },
+ { PINMUX_CFG_REG("PBCR5", 0xfffe3824, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB22MD_000, PB22MD_001, PB22MD_010, PB22MD_011,
+ PB22MD_100, PB22MD_101, PB22MD_110, PB22MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB21MD_00, PB21MD_01, PB21MD_10, PB21MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB20MD_000, PB20MD_001, PB20MD_010, PB20MD_011,
+ PB20MD_100, PB20MD_101, PB20MD_110, PB20MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR4", 0xfffe3826, 16, 4) {
+ PB19MD_000, PB19MD_001, PB19MD_010, PB19MD_011,
+ PB19MD_100, PB19MD_101, PB19MD_110, PB19MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB18MD_000, PB18MD_001, PB18MD_010, PB18MD_011,
+ PB18MD_100, PB18MD_101, PB18MD_110, PB18MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB17MD_000, PB17MD_001, PB17MD_010, PB17MD_011,
+ PB17MD_100, PB17MD_101, PB17MD_110, PB17MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB16MD_000, PB16MD_001, PB16MD_010, PB16MD_011,
+ PB16MD_100, PB16MD_101, PB16MD_110, PB16MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR3", 0xfffe3828, 16, 4) {
+ PB15MD_000, PB15MD_001, PB15MD_010, PB15MD_011,
+ PB15MD_100, PB15MD_101, PB15MD_110, PB15MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB14MD_000, PB14MD_001, PB14MD_010, PB14MD_011,
+ PB14MD_100, PB14MD_101, PB14MD_110, PB14MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB13MD_000, PB13MD_001, PB13MD_010, PB13MD_011,
+ PB13MD_100, PB13MD_101, PB13MD_110, PB13MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR2", 0xfffe382a, 16, 4) {
+ PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR1", 0xfffe382c, 16, 4) {
+ PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR0", 0xfffe382e, 16, 4) {
+ PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PBIOR1", 0xfffe3830, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ PB22_IN, PB22_OUT,
+ PB21_IN, PB21_OUT,
+ PB20_IN, PB20_OUT,
+ PB19_IN, PB19_OUT,
+ PB18_IN, PB18_OUT,
+ PB17_IN, PB17_OUT,
+ PB16_IN, PB16_OUT }
+ },
+ { PINMUX_CFG_REG("PBIOR0", 0xfffe3832, 16, 1) {
+ PB15_IN, PB15_OUT,
+ PB14_IN, PB14_OUT,
+ PB13_IN, PB13_OUT,
+ PB12_IN, PB12_OUT,
+ PB11_IN, PB11_OUT,
+ PB10_IN, PB10_OUT,
+ PB9_IN, PB9_OUT,
+ PB8_IN, PB8_OUT,
+ PB7_IN, PB7_OUT,
+ PB6_IN, PB6_OUT,
+ PB5_IN, PB5_OUT,
+ PB4_IN, PB4_OUT,
+ PB3_IN, PB3_OUT,
+ PB2_IN, PB2_OUT,
+ PB1_IN, PB1_OUT,
+ 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PCCR2", 0xfffe384a, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC8MD_000, PC8MD_001, PC8MD_010, PC8MD_011,
+ PC8MD_100, PC8MD_101, PC8MD_110, PC8MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCR1", 0xfffe384c, 16, 4) {
+ PC7MD_000, PC7MD_001, PC7MD_010, PC7MD_011,
+ PC7MD_100, PC7MD_101, PC7MD_110, PC7MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC6MD_000, PC6MD_001, PC6MD_010, PC6MD_011,
+ PC6MD_100, PC6MD_101, PC6MD_110, PC6MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC5MD_000, PC5MD_001, PC5MD_010, PC5MD_011,
+ PC5MD_100, PC5MD_101, PC5MD_110, PC5MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC4MD_00, PC4MD_01, PC4MD_10, PC4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCR0", 0xfffe384e, 16, 4) {
+ PC3MD_00, PC3MD_01, PC3MD_10, PC3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC2MD_00, PC2MD_01, PC2MD_10, PC2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC1MD_0, PC1MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC0MD_0, PC0MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ PC8_IN, PC8_OUT,
+ PC7_IN, PC7_OUT,
+ PC6_IN, PC6_OUT,
+ PC5_IN, PC5_OUT,
+ PC4_IN, PC4_OUT,
+ PC3_IN, PC3_OUT,
+ PC2_IN, PC2_OUT,
+ PC1_IN, PC1_OUT,
+ PC0_IN, PC0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PDCR3", 0xfffe3868, 16, 4) {
+ PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR2", 0xfffe386a, 16, 4) {
+ PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR1", 0xfffe386c, 16, 4) {
+ PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR0", 0xfffe386e, 16, 4) {
+ PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PDIOR0", 0xfffe3872, 16, 1) {
+ PD15_IN, PD15_OUT,
+ PD14_IN, PD14_OUT,
+ PD13_IN, PD13_OUT,
+ PD12_IN, PD12_OUT,
+ PD11_IN, PD11_OUT,
+ PD10_IN, PD10_OUT,
+ PD9_IN, PD9_OUT,
+ PD8_IN, PD8_OUT,
+ PD7_IN, PD7_OUT,
+ PD6_IN, PD6_OUT,
+ PD5_IN, PD5_OUT,
+ PD4_IN, PD4_OUT,
+ PD3_IN, PD3_OUT,
+ PD2_IN, PD2_OUT,
+ PD1_IN, PD1_OUT,
+ PD0_IN, PD0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PECR1", 0xfffe388c, 16, 4) {
+ PE7MD_00, PE7MD_01, PE7MD_10, PE7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE6MD_00, PE6MD_01, PE6MD_10, PE6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PECR0", 0xfffe388e, 16, 4) {
+ PE3MD_000, PE3MD_001, PE3MD_010, PE3MD_011,
+ PE3MD_100, PE3MD_101, PE3MD_110, PE3MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE2MD_000, PE2MD_001, PE2MD_010, PE2MD_011,
+ PE2MD_100, PE2MD_101, PE2MD_110, PE2MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+ PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PEIOR0", 0xfffe3892, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE7_IN, PE7_OUT,
+ PE6_IN, PE6_OUT,
+ PE5_IN, PE5_OUT,
+ PE4_IN, PE4_OUT,
+ PE3_IN, PE3_OUT,
+ PE2_IN, PE2_OUT,
+ PE1_IN, PE1_OUT,
+ PE0_IN, PE0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PFCR6", 0xfffe38a2, 16, 4) {
+ PF23MD_000, PF23MD_001, PF23MD_010, PF23MD_011,
+ PF23MD_100, PF23MD_101, PF23MD_110, PF23MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF22MD_000, PF22MD_001, PF22MD_010, PF22MD_011,
+ PF22MD_100, PF22MD_101, PF22MD_110, PF22MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF21MD_000, PF21MD_001, PF21MD_010, PF21MD_011,
+ PF21MD_100, PF21MD_101, PF21MD_110, PF21MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF20MD_000, PF20MD_001, PF20MD_010, PF20MD_011,
+ PF20MD_100, PF20MD_101, PF20MD_110, PF20MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR5", 0xfffe38a4, 16, 4) {
+ PF19MD_000, PF19MD_001, PF19MD_010, PF19MD_011,
+ PF19MD_100, PF19MD_101, PF19MD_110, PF19MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF18MD_000, PF18MD_001, PF18MD_010, PF18MD_011,
+ PF18MD_100, PF18MD_101, PF18MD_110, PF18MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF17MD_000, PF17MD_001, PF17MD_010, PF17MD_011,
+ PF17MD_100, PF17MD_101, PF17MD_110, PF17MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF16MD_000, PF16MD_001, PF16MD_010, PF16MD_011,
+ PF16MD_100, PF16MD_101, PF16MD_110, PF16MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR4", 0xfffe38a6, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF15MD_000, PF15MD_001, PF15MD_010, PF15MD_011,
+ PF15MD_100, PF15MD_101, PF15MD_110, PF15MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF14MD_000, PF14MD_001, PF14MD_010, PF14MD_011,
+ PF14MD_100, PF14MD_101, PF14MD_110, PF14MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF13MD_000, PF13MD_001, PF13MD_010, PF13MD_011,
+ PF13MD_100, PF13MD_101, PF13MD_110, PF13MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+ PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR2", 0xfffe38aa, 16, 4) {
+ PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+ PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+ PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+ PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF8MD_000, PF8MD_001, PF8MD_010, PF8MD_011,
+ PF8MD_100, PF8MD_101, PF8MD_110, PF8MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR1", 0xfffe38ac, 16, 4) {
+ PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+ PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+ PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+ PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+ PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR0", 0xfffe38ae, 16, 4) {
+ PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+ PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+ PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+ PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+ PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PFIOR1", 0xfffe38b0, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF23_IN, PF23_OUT,
+ PF22_IN, PF22_OUT,
+ PF21_IN, PF21_OUT,
+ PF20_IN, PF20_OUT,
+ PF19_IN, PF19_OUT,
+ PF18_IN, PF18_OUT,
+ PF17_IN, PF17_OUT,
+ PF16_IN, PF16_OUT }
+ },
+ { PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
+ PF15_IN, PF15_OUT,
+ PF14_IN, PF14_OUT,
+ PF13_IN, PF13_OUT,
+ PF12_IN, PF12_OUT,
+ PF11_IN, PF11_OUT,
+ PF10_IN, PF10_OUT,
+ PF9_IN, PF9_OUT,
+ PF8_IN, PF8_OUT,
+ PF7_IN, PF7_OUT,
+ PF6_IN, PF6_OUT,
+ PF5_IN, PF5_OUT,
+ PF4_IN, PF4_OUT,
+ PF3_IN, PF3_OUT,
+ PF2_IN, PF2_OUT,
+ PF1_IN, PF1_OUT,
+ PF0_IN, PF0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PGCR6", 0xfffe38c2, 16, 4) {
+ PG27MD_00, PG27MD_01, PG27MD_10, PG27MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG26MD_00, PG26MD_01, PG26MD_10, PG26MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG25MD_00, PG25MD_01, PG25MD_10, PG25MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR5", 0xfffe38c4, 16, 4) {
+ PG23MD_000, PG23MD_001, PG23MD_010, PG23MD_011,
+ PG23MD_100, PG23MD_101, PG23MD_110, PG23MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG22MD_000, PG22MD_001, PG22MD_010, PG22MD_011,
+ PG22MD_100, PG22MD_101, PG22MD_110, PG22MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG21MD_000, PG21MD_001, PG21MD_010, PG21MD_011,
+ PG21MD_100, PG21MD_101, PG21MD_110, PG21MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+ PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR4", 0xfffe38c6, 16, 4) {
+ PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+ PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+ PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG17MD_00, PG17MD_01, PG17MD_10, PG17MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG16MD_00, PG16MD_01, PG16MD_10, PG16MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR3", 0xfffe38c8, 16, 4) {
+ PG15MD_00, PG15MD_01, PG15MD_10, PG15MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG14MD_00, PG14MD_01, PG14MD_10, PG14MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG13MD_00, PG13MD_01, PG13MD_10, PG13MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG12MD_00, PG12MD_01, PG12MD_10, PG12MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR2", 0xfffe38ca, 16, 4) {
+ PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+ PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+ PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+ PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+ PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR1", 0xfffe38cc, 16, 4) {
+ PG7MD_000, PG7MD_001, PG7MD_010, PG7MD_011,
+ PG7MD_100, PG7MD_101, PG7MD_110, PG7MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG6MD_000, PG6MD_001, PG6MD_010, PG6MD_011,
+ PG6MD_100, PG6MD_101, PG6MD_110, PG6MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG5MD_000, PG5MD_001, PG5MD_010, PG5MD_011,
+ PG5MD_100, PG5MD_101, PG5MD_110, PG5MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG4MD_000, PG4MD_001, PG4MD_010, PG4MD_011,
+ PG4MD_100, PG4MD_101, PG4MD_110, PG4MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR0", 0xfffe38ce, 16, 4) {
+ PG3MD_000, PG3MD_001, PG3MD_010, PG3MD_011,
+ PG3MD_100, PG3MD_101, PG3MD_110, PG3MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG2MD_000, PG2MD_001, PG2MD_010, PG2MD_011,
+ PG2MD_100, PG2MD_101, PG2MD_110, PG2MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG1MD_000, PG1MD_001, PG1MD_010, PG1MD_011,
+ PG1MD_100, PG1MD_101, PG1MD_110, PG1MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+ PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGIOR1", 0xfffe38d0, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG27_IN, PG27_OUT,
+ PG26_IN, PG26_OUT,
+ PG25_IN, PG25_OUT,
+ PG24_IN, PG24_OUT,
+ PG23_IN, PG23_OUT,
+ PG22_IN, PG22_OUT,
+ PG21_IN, PG21_OUT,
+ PG20_IN, PG20_OUT,
+ PG19_IN, PG19_OUT,
+ PG18_IN, PG18_OUT,
+ PG17_IN, PG17_OUT,
+ PG16_IN, PG16_OUT }
+ },
+ { PINMUX_CFG_REG("PGIOR0", 0xfffe38d2, 16, 1) {
+ PG15_IN, PG15_OUT,
+ PG14_IN, PG14_OUT,
+ PG13_IN, PG13_OUT,
+ PG12_IN, PG12_OUT,
+ PG11_IN, PG11_OUT,
+ PG10_IN, PG10_OUT,
+ PG9_IN, PG9_OUT,
+ PG8_IN, PG8_OUT,
+ PG7_IN, PG7_OUT,
+ PG6_IN, PG6_OUT,
+ PG5_IN, PG5_OUT,
+ PG4_IN, PG4_OUT,
+ PG3_IN, PG3_OUT,
+ PG2_IN, PG2_OUT,
+ PG1_IN, PG1_OUT,
+ PG0_IN, PG0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PHCR1", 0xfffe38ec, 16, 4) {
+ PH7MD_00, PH7MD_01, PH7MD_10, PH7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH6MD_00, PH6MD_01, PH6MD_10, PH6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH5MD_00, PH5MD_01, PH5MD_10, PH5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH4MD_00, PH4MD_01, PH4MD_10, PH4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PHCR0", 0xfffe38ee, 16, 4) {
+ PH3MD_00, PH3MD_01, PH3MD_10, PH3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH2MD_00, PH2MD_01, PH2MD_10, PH2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH1MD_00, PH1MD_01, PH1MD_10, PH1MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH0MD_00, PH0MD_01, PH0MD_10, PH0MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PJCR7", 0xfffe3900, 16, 4) {
+ PJ31MD_0, PJ31MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ30MD_000, PJ30MD_001, PJ30MD_010, PJ30MD_011,
+ PJ30MD_100, PJ30MD_101, PJ30MD_110, PJ30MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ29MD_000, PJ29MD_001, PJ29MD_010, PJ29MD_011,
+ PJ29MD_100, PJ29MD_101, PJ29MD_110, PJ29MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ28MD_000, PJ28MD_001, PJ28MD_010, PJ28MD_011,
+ PJ28MD_100, PJ28MD_101, PJ28MD_110, PJ28MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR6", 0xfffe3902, 16, 4) {
+ PJ27MD_000, PJ27MD_001, PJ27MD_010, PJ27MD_011,
+ PJ27MD_100, PJ27MD_101, PJ27MD_110, PJ27MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ26MD_000, PJ26MD_001, PJ26MD_010, PJ26MD_011,
+ PJ26MD_100, PJ26MD_101, PJ26MD_110, PJ26MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ25MD_000, PJ25MD_001, PJ25MD_010, PJ25MD_011,
+ PJ25MD_100, PJ25MD_101, PJ25MD_110, PJ25MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ24MD_000, PJ24MD_001, PJ24MD_010, PJ24MD_011,
+ PJ24MD_100, PJ24MD_101, PJ24MD_110, PJ24MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR5", 0xfffe3904, 16, 4) {
+ PJ23MD_000, PJ23MD_001, PJ23MD_010, PJ23MD_011,
+ PJ23MD_100, PJ23MD_101, PJ23MD_110, PJ23MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ22MD_000, PJ22MD_001, PJ22MD_010, PJ22MD_011,
+ PJ22MD_100, PJ22MD_101, PJ22MD_110, PJ22MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ21MD_000, PJ21MD_001, PJ21MD_010, PJ21MD_011,
+ PJ21MD_100, PJ21MD_101, PJ21MD_110, PJ21MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ20MD_000, PJ20MD_001, PJ20MD_010, PJ20MD_011,
+ PJ20MD_100, PJ20MD_101, PJ20MD_110, PJ20MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR4", 0xfffe3906, 16, 4) {
+ PJ19MD_000, PJ19MD_001, PJ19MD_010, PJ19MD_011,
+ PJ19MD_100, PJ19MD_101, PJ19MD_110, PJ19MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ18MD_000, PJ18MD_001, PJ18MD_010, PJ18MD_011,
+ PJ18MD_100, PJ18MD_101, PJ18MD_110, PJ18MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ17MD_000, PJ17MD_001, PJ17MD_010, PJ17MD_011,
+ PJ17MD_100, PJ17MD_101, PJ17MD_110, PJ17MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ16MD_000, PJ16MD_001, PJ16MD_010, PJ16MD_011,
+ PJ16MD_100, PJ16MD_101, PJ16MD_110, PJ16MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR3", 0xfffe3908, 16, 4) {
+ PJ15MD_000, PJ15MD_001, PJ15MD_010, PJ15MD_011,
+ PJ15MD_100, PJ15MD_101, PJ15MD_110, PJ15MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ14MD_000, PJ14MD_001, PJ14MD_010, PJ14MD_011,
+ PJ14MD_100, PJ14MD_101, PJ14MD_110, PJ14MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ13MD_000, PJ13MD_001, PJ13MD_010, PJ13MD_011,
+ PJ13MD_100, PJ13MD_101, PJ13MD_110, PJ13MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ12MD_000, PJ12MD_001, PJ12MD_010, PJ12MD_011,
+ PJ12MD_100, PJ12MD_101, PJ12MD_110, PJ12MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR2", 0xfffe390a, 16, 4) {
+ PJ11MD_000, PJ11MD_001, PJ11MD_010, PJ11MD_011,
+ PJ11MD_100, PJ11MD_101, PJ11MD_110, PJ11MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ10MD_000, PJ10MD_001, PJ10MD_010, PJ10MD_011,
+ PJ10MD_100, PJ10MD_101, PJ10MD_110, PJ10MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ9MD_000, PJ9MD_001, PJ9MD_010, PJ9MD_011,
+ PJ9MD_100, PJ9MD_101, PJ9MD_110, PJ9MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ8MD_000, PJ8MD_001, PJ8MD_010, PJ8MD_011,
+ PJ8MD_100, PJ8MD_101, PJ8MD_110, PJ8MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR1", 0xfffe390c, 16, 4) {
+ PJ7MD_000, PJ7MD_001, PJ7MD_010, PJ7MD_011,
+ PJ7MD_100, PJ7MD_101, PJ7MD_110, PJ7MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ6MD_000, PJ6MD_001, PJ6MD_010, PJ6MD_011,
+ PJ6MD_100, PJ6MD_101, PJ6MD_110, PJ6MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ5MD_000, PJ5MD_001, PJ5MD_010, PJ5MD_011,
+ PJ5MD_100, PJ5MD_101, PJ5MD_110, PJ5MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ4MD_000, PJ4MD_001, PJ4MD_010, PJ4MD_011,
+ PJ4MD_100, PJ4MD_101, PJ4MD_110, PJ4MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR0", 0xfffe390e, 16, 4) {
+ PJ3MD_000, PJ3MD_001, PJ3MD_010, PJ3MD_011,
+ PJ3MD_100, PJ3MD_101, PJ3MD_110, PJ3MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+ PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+ PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+ PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PJIOR1", 0xfffe3910, 16, 1) {
+ PJ31_IN, PJ31_OUT,
+ PJ30_IN, PJ30_OUT,
+ PJ29_IN, PJ29_OUT,
+ PJ28_IN, PJ28_OUT,
+ PJ27_IN, PJ27_OUT,
+ PJ26_IN, PJ26_OUT,
+ PJ25_IN, PJ25_OUT,
+ PJ24_IN, PJ24_OUT,
+ PJ23_IN, PJ23_OUT,
+ PJ22_IN, PJ22_OUT,
+ PJ21_IN, PJ21_OUT,
+ PJ20_IN, PJ20_OUT,
+ PJ19_IN, PJ19_OUT,
+ PJ18_IN, PJ18_OUT,
+ PJ17_IN, PJ17_OUT,
+ PJ16_IN, PJ16_OUT }
+ },
+ { PINMUX_CFG_REG("PJIOR0", 0xfffe3912, 16, 1) {
+ PJ15_IN, PJ15_OUT,
+ PJ14_IN, PJ14_OUT,
+ PJ13_IN, PJ13_OUT,
+ PJ12_IN, PJ12_OUT,
+ PJ11_IN, PJ11_OUT,
+ PJ10_IN, PJ10_OUT,
+ PJ9_IN, PJ9_OUT,
+ PJ8_IN, PJ8_OUT,
+ PJ7_IN, PJ7_OUT,
+ PJ6_IN, PJ6_OUT,
+ PJ5_IN, PJ5_OUT,
+ PJ4_IN, PJ4_OUT,
+ PJ3_IN, PJ3_OUT,
+ PJ2_IN, PJ2_OUT,
+ PJ1_IN, PJ1_OUT,
+ PJ0_IN, PJ0_OUT }
+ },
+
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR0", 0xfffe3816, 16) {
+ 0, 0, 0, 0, 0, 0, 0, PA1_DATA,
+ 0, 0, 0, 0, 0, 0, 0, PA0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PBDR1", 0xfffe3834, 16) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB22_DATA, PB21_DATA, PB20_DATA,
+ PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA }
+ },
+ { PINMUX_DATA_REG("PBDR0", 0xfffe3836, 16) {
+ PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+ PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, 0 }
+ },
+
+ { PINMUX_DATA_REG("PCDR0", 0xfffe3856, 16) {
+ 0, 0, 0, 0,
+ 0, 0, 0, PC8_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PDDR0", 0xfffe3876, 16) {
+ PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+ PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PEDR0", 0xfffe3896, 16) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PFDR1", 0xfffe38b4, 16) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
+ PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA }
+ },
+ { PINMUX_DATA_REG("PFDR0", 0xfffe38b6, 16) {
+ PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
+ PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PGDR1", 0xfffe38d4, 16) {
+ 0, 0, 0, 0,
+ PG27_DATA, PG26_DATA, PG25_DATA, PG24_DATA,
+ PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+ PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA }
+ },
+ { PINMUX_DATA_REG("PGDR0", 0xfffe38d6, 16) {
+ PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+ PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PJDR1", 0xfffe3914, 16) {
+ PJ31_DATA, PJ30_DATA, PJ29_DATA, PJ28_DATA,
+ PJ27_DATA, PJ26_DATA, PJ25_DATA, PJ24_DATA,
+ PJ23_DATA, PJ22_DATA, PJ21_DATA, PJ20_DATA,
+ PJ19_DATA, PJ18_DATA, PJ17_DATA, PJ16_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR0", 0xfffe3916, 16) {
+ PJ15_DATA, PJ14_DATA, PJ13_DATA, PJ12_DATA,
+ PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
+ },
+
+ { }
+};
+
+struct sh_pfc_soc_info sh7269_pinmux_info = {
+ .name = "sh7269_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PA1,
+ .last_gpio = GPIO_FN_LCD_M_DISP,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/arch/arm/mach-shmobile/pfc-sh7372.c b/drivers/pinctrl/sh-pfc/pfc-sh7372.c
index 7a1525fd6ada..d44e7f02069b 100644
--- a/arch/arm/mach-shmobile/pfc-sh7372.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7372.c
@@ -20,12 +20,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sh_pfc.h>
#include <mach/irqs.h>
#include <mach/sh7372.h>
+#include "sh_pfc.h"
+
#define CPU_ALL_PORT(fn, pfx, sfx) \
PORT_10(fn, pfx, sfx), PORT_90(fn, pfx, sfx), \
PORT_10(fn, pfx##10, sfx), PORT_10(fn, pfx##11, sfx), \
@@ -1632,7 +1632,7 @@ static struct pinmux_irq pinmux_irqs[] = {
PINMUX_IRQ(EXT_IRQ16H(31), PORT138_FN0, PORT184_FN0),
};
-static struct pinmux_info sh7372_pinmux_info = {
+struct sh_pfc_soc_info sh7372_pinmux_info = {
.name = "sh7372_pfc",
.reserved_id = PINMUX_RESERVED,
.data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
@@ -1656,8 +1656,3 @@ static struct pinmux_info sh7372_pinmux_info = {
.gpio_irq = pinmux_irqs,
.gpio_irq_size = ARRAY_SIZE(pinmux_irqs),
};
-
-void sh7372_pinmux_init(void)
-{
- register_pinmux(&sh7372_pinmux_info);
-}
diff --git a/arch/arm/mach-shmobile/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
index b442f9d8c716..709008e94124 100644
--- a/arch/arm/mach-shmobile/pfc-sh73a0.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
@@ -18,12 +18,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sh_pfc.h>
#include <mach/sh73a0.h>
#include <mach/irqs.h>
+#include "sh_pfc.h"
+
#define CPU_ALL_PORT(fn, pfx, sfx) \
PORT_10(fn, pfx, sfx), PORT_10(fn, pfx##1, sfx), \
PORT_10(fn, pfx##2, sfx), PORT_10(fn, pfx##3, sfx), \
@@ -2772,7 +2772,7 @@ static struct pinmux_irq pinmux_irqs[] = {
PINMUX_IRQ(EXT_IRQ16L(9), PORT308_FN0),
};
-static struct pinmux_info sh73a0_pinmux_info = {
+struct sh_pfc_soc_info sh73a0_pinmux_info = {
.name = "sh73a0_pfc",
.reserved_id = PINMUX_RESERVED,
.data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
@@ -2796,8 +2796,3 @@ static struct pinmux_info sh73a0_pinmux_info = {
.gpio_irq = pinmux_irqs,
.gpio_irq_size = ARRAY_SIZE(pinmux_irqs),
};
-
-void sh73a0_pinmux_init(void)
-{
- register_pinmux(&sh73a0_pinmux_info);
-}
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7720.c b/drivers/pinctrl/sh-pfc/pfc-sh7720.c
new file mode 100644
index 000000000000..10872ed688a6
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7720.c
@@ -0,0 +1,1236 @@
+/*
+ * SH7720 Pinmux
+ *
+ * Copyright (C) 2008 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/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7720.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+ PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
+ PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+ PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
+ PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
+ PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA,
+ PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+ PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
+ PTE6_DATA, PTE5_DATA, PTE4_DATA,
+ PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA,
+ PTF6_DATA, PTF5_DATA, PTF4_DATA,
+ PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
+ PTG6_DATA, PTG5_DATA, PTG4_DATA,
+ PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
+ PTH6_DATA, PTH5_DATA, PTH4_DATA,
+ PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
+ PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+ PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
+ PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
+ PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA, PTL3_DATA,
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
+ PTP4_DATA, PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA,
+ PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
+ PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
+ PTS4_DATA, PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
+ PTT4_DATA, PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
+ PTU4_DATA, PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
+ PTV4_DATA, PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
+ PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
+ PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
+ PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
+ PTC7_IN, PTC6_IN, PTC5_IN, PTC4_IN,
+ PTC3_IN, PTC2_IN, PTC1_IN, PTC0_IN,
+ PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN,
+ PTD3_IN, PTD2_IN, PTD1_IN, PTD0_IN,
+ PTE6_IN, PTE5_IN, PTE4_IN,
+ PTE3_IN, PTE2_IN, PTE1_IN, PTE0_IN,
+ PTF6_IN, PTF5_IN, PTF4_IN,
+ PTF3_IN, PTF2_IN, PTF1_IN, PTF0_IN,
+ PTG6_IN, PTG5_IN, PTG4_IN,
+ PTG3_IN, PTG2_IN, PTG1_IN, PTG0_IN,
+ PTH6_IN, PTH5_IN, PTH4_IN,
+ PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
+ PTJ6_IN, PTJ5_IN, PTJ4_IN,
+ PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
+ PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
+ PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN, PTL3_IN,
+ PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
+ PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
+ PTP4_IN, PTP3_IN, PTP2_IN, PTP1_IN, PTP0_IN,
+ PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
+ PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
+ PTS4_IN, PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
+ PTT4_IN, PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
+ PTU4_IN, PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
+ PTV4_IN, PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_INPUT_PULLUP_BEGIN,
+ PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
+ PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
+ PTB7_IN_PU, PTB6_IN_PU, PTB5_IN_PU, PTB4_IN_PU,
+ PTB3_IN_PU, PTB2_IN_PU, PTB1_IN_PU, PTB0_IN_PU,
+ PTC7_IN_PU, PTC6_IN_PU, PTC5_IN_PU, PTC4_IN_PU,
+ PTC3_IN_PU, PTC2_IN_PU, PTC1_IN_PU, PTC0_IN_PU,
+ PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
+ PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
+ PTE4_IN_PU, PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
+ PTF0_IN_PU,
+ PTG6_IN_PU, PTG5_IN_PU, PTG4_IN_PU,
+ PTG3_IN_PU, PTG2_IN_PU, PTG1_IN_PU, PTG0_IN_PU,
+ PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
+ PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
+ PTJ6_IN_PU, PTJ5_IN_PU, PTJ4_IN_PU,
+ PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
+ PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
+ PTL7_IN_PU, PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU, PTL3_IN_PU,
+ PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
+ PTM3_IN_PU, PTM2_IN_PU, PTM1_IN_PU, PTM0_IN_PU,
+ PTP4_IN_PU, PTP3_IN_PU, PTP2_IN_PU, PTP1_IN_PU, PTP0_IN_PU,
+ PTR7_IN_PU, PTR6_IN_PU, PTR5_IN_PU, PTR4_IN_PU,
+ PTR3_IN_PU, PTR2_IN_PU, PTR1_IN_PU, PTR0_IN_PU,
+ PTS4_IN_PU, PTS3_IN_PU, PTS2_IN_PU, PTS1_IN_PU, PTS0_IN_PU,
+ PTT4_IN_PU, PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
+ PTU4_IN_PU, PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
+ PTV4_IN_PU, PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
+ PINMUX_INPUT_PULLUP_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
+ PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
+ PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
+ PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
+ PTC7_OUT, PTC6_OUT, PTC5_OUT, PTC4_OUT,
+ PTC3_OUT, PTC2_OUT, PTC1_OUT, PTC0_OUT,
+ PTD7_OUT, PTD6_OUT, PTD5_OUT, PTD4_OUT,
+ PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
+ PTE4_OUT, PTE3_OUT, PTE2_OUT, PTE1_OUT, PTE0_OUT,
+ PTF0_OUT,
+ PTG6_OUT, PTG5_OUT, PTG4_OUT,
+ PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
+ PTH6_OUT, PTH5_OUT, PTH4_OUT,
+ PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
+ PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
+ PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
+ PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
+ PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT, PTL3_OUT,
+ PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
+ PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
+ PTP4_OUT, PTP3_OUT, PTP2_OUT, PTP1_OUT, PTP0_OUT,
+ PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
+ PTR3_OUT, PTR2_OUT, PTR1_OUT, PTR0_OUT,
+ PTS4_OUT, PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
+ PTT4_OUT, PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
+ PTU4_OUT, PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
+ PTV4_OUT, PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PTA7_FN, PTA6_FN, PTA5_FN, PTA4_FN,
+ PTA3_FN, PTA2_FN, PTA1_FN, PTA0_FN,
+ PTB7_FN, PTB6_FN, PTB5_FN, PTB4_FN,
+ PTB3_FN, PTB2_FN, PTB1_FN, PTB0_FN,
+ PTC7_FN, PTC6_FN, PTC5_FN, PTC4_FN,
+ PTC3_FN, PTC2_FN, PTC1_FN, PTC0_FN,
+ PTD7_FN, PTD6_FN, PTD5_FN, PTD4_FN,
+ PTD3_FN, PTD2_FN, PTD1_FN, PTD0_FN,
+ PTE6_FN, PTE5_FN, PTE4_FN,
+ PTE3_FN, PTE2_FN, PTE1_FN, PTE0_FN,
+ PTF6_FN, PTF5_FN, PTF4_FN,
+ PTF3_FN, PTF2_FN, PTF1_FN, PTF0_FN,
+ PTG6_FN, PTG5_FN, PTG4_FN,
+ PTG3_FN, PTG2_FN, PTG1_FN, PTG0_FN,
+ PTH6_FN, PTH5_FN, PTH4_FN,
+ PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
+ PTJ6_FN, PTJ5_FN, PTJ4_FN,
+ PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
+ PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
+ PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN, PTL3_FN,
+ PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
+ PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
+ PTP4_FN, PTP3_FN, PTP2_FN, PTP1_FN, PTP0_FN,
+ PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
+ PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
+ PTS4_FN, PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
+ PTT4_FN, PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
+ PTU4_FN, PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
+ PTV4_FN, PTV3_FN, PTV2_FN, PTV1_FN, PTV0_FN,
+
+ PSELA_1_0_00, PSELA_1_0_01, PSELA_1_0_10,
+ PSELA_3_2_00, PSELA_3_2_01, PSELA_3_2_10, PSELA_3_2_11,
+ PSELA_5_4_00, PSELA_5_4_01, PSELA_5_4_10, PSELA_5_4_11,
+ PSELA_7_6_00, PSELA_7_6_01, PSELA_7_6_10,
+ PSELA_9_8_00, PSELA_9_8_01, PSELA_9_8_10,
+ PSELA_11_10_00, PSELA_11_10_01, PSELA_11_10_10,
+ PSELA_13_12_00, PSELA_13_12_10,
+ PSELA_15_14_00, PSELA_15_14_10,
+ PSELB_9_8_00, PSELB_9_8_11,
+ PSELB_11_10_00, PSELB_11_10_01, PSELB_11_10_10, PSELB_11_10_11,
+ PSELB_13_12_00, PSELB_13_12_01, PSELB_13_12_10, PSELB_13_12_11,
+ PSELB_15_14_00, PSELB_15_14_11,
+ PSELC_9_8_00, PSELC_9_8_10,
+ PSELC_11_10_00, PSELC_11_10_10,
+ PSELC_13_12_00, PSELC_13_12_01, PSELC_13_12_10,
+ PSELC_15_14_00, PSELC_15_14_01, PSELC_15_14_10,
+ PSELD_1_0_00, PSELD_1_0_10,
+ PSELD_11_10_00, PSELD_11_10_01,
+ PSELD_15_14_00, PSELD_15_14_01, PSELD_15_14_10,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ D31_MARK, D30_MARK, D29_MARK, D28_MARK,
+ D27_MARK, D26_MARK, D25_MARK, D24_MARK,
+ D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+ D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+ IOIS16_MARK, RAS_MARK, CAS_MARK, CKE_MARK,
+ CS5B_CE1A_MARK, CS6B_CE1B_MARK,
+ A25_MARK, A24_MARK, A23_MARK, A22_MARK,
+ A21_MARK, A20_MARK, A19_MARK, A0_MARK,
+ REFOUT_MARK, IRQOUT_MARK,
+ LCD_DATA15_MARK, LCD_DATA14_MARK,
+ LCD_DATA13_MARK, LCD_DATA12_MARK,
+ LCD_DATA11_MARK, LCD_DATA10_MARK,
+ LCD_DATA9_MARK, LCD_DATA8_MARK,
+ LCD_DATA7_MARK, LCD_DATA6_MARK,
+ LCD_DATA5_MARK, LCD_DATA4_MARK,
+ LCD_DATA3_MARK, LCD_DATA2_MARK,
+ LCD_DATA1_MARK, LCD_DATA0_MARK,
+ LCD_M_DISP_MARK,
+ LCD_CL1_MARK, LCD_CL2_MARK,
+ LCD_DON_MARK, LCD_FLM_MARK,
+ LCD_VEPWC_MARK, LCD_VCPWC_MARK,
+ AFE_RXIN_MARK, AFE_RDET_MARK,
+ AFE_FS_MARK, AFE_TXOUT_MARK,
+ AFE_SCLK_MARK, AFE_RLYCNT_MARK,
+ AFE_HC1_MARK,
+ IIC_SCL_MARK, IIC_SDA_MARK,
+ DA1_MARK, DA0_MARK,
+ AN3_MARK, AN2_MARK, AN1_MARK, AN0_MARK, ADTRG_MARK,
+ USB1D_RCV_MARK, USB1D_TXSE0_MARK,
+ USB1D_TXDPLS_MARK, USB1D_DMNS_MARK,
+ USB1D_DPLS_MARK, USB1D_SPEED_MARK,
+ USB1D_TXENL_MARK,
+ USB2_PWR_EN_MARK, USB1_PWR_EN_USBF_UPLUP_MARK, USB1D_SUSPEND_MARK,
+ IRQ5_MARK, IRQ4_MARK,
+ IRQ3_IRL3_MARK, IRQ2_IRL2_MARK,
+ IRQ1_IRL1_MARK, IRQ0_IRL0_MARK,
+ PCC_REG_MARK, PCC_DRV_MARK,
+ PCC_BVD2_MARK, PCC_BVD1_MARK,
+ PCC_CD2_MARK, PCC_CD1_MARK,
+ PCC_RESET_MARK, PCC_RDY_MARK,
+ PCC_VS2_MARK, PCC_VS1_MARK,
+ AUDATA3_MARK, AUDATA2_MARK, AUDATA1_MARK, AUDATA0_MARK,
+ AUDCK_MARK, AUDSYNC_MARK, ASEBRKAK_MARK, TRST_MARK,
+ TMS_MARK, TDO_MARK, TDI_MARK, TCK_MARK,
+ DACK1_MARK, DREQ1_MARK, DACK0_MARK, DREQ0_MARK,
+ TEND1_MARK, TEND0_MARK,
+ SIOF0_SYNC_MARK, SIOF0_MCLK_MARK,
+ SIOF0_TXD_MARK, SIOF0_RXD_MARK,
+ SIOF0_SCK_MARK,
+ SIOF1_SYNC_MARK, SIOF1_MCLK_MARK,
+ SIOF1_TXD_MARK, SIOF1_RXD_MARK,
+ SIOF1_SCK_MARK,
+ SCIF0_TXD_MARK, SCIF0_RXD_MARK,
+ SCIF0_RTS_MARK, SCIF0_CTS_MARK, SCIF0_SCK_MARK,
+ SCIF1_TXD_MARK, SCIF1_RXD_MARK,
+ SCIF1_RTS_MARK, SCIF1_CTS_MARK, SCIF1_SCK_MARK,
+ TPU_TO1_MARK, TPU_TO0_MARK,
+ TPU_TI3B_MARK, TPU_TI3A_MARK,
+ TPU_TI2B_MARK, TPU_TI2A_MARK,
+ TPU_TO3_MARK, TPU_TO2_MARK,
+ SIM_D_MARK, SIM_CLK_MARK, SIM_RST_MARK,
+ MMC_DAT_MARK, MMC_CMD_MARK,
+ MMC_CLK_MARK, MMC_VDDON_MARK,
+ MMC_ODMOD_MARK,
+ STATUS0_MARK, STATUS1_MARK,
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+ /* PTA GPIO */
+ PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT, PTA7_IN_PU),
+ PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT, PTA6_IN_PU),
+ PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT, PTA5_IN_PU),
+ PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT, PTA4_IN_PU),
+ PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT, PTA3_IN_PU),
+ PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT, PTA2_IN_PU),
+ PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT, PTA1_IN_PU),
+ PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT, PTA0_IN_PU),
+
+ /* PTB GPIO */
+ PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT, PTB7_IN_PU),
+ PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT, PTB6_IN_PU),
+ PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT, PTB5_IN_PU),
+ PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT, PTB4_IN_PU),
+ PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT, PTB3_IN_PU),
+ PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT, PTB2_IN_PU),
+ PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT, PTB1_IN_PU),
+ PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT, PTB0_IN_PU),
+
+ /* PTC GPIO */
+ PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT, PTC7_IN_PU),
+ PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT, PTC6_IN_PU),
+ PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT, PTC5_IN_PU),
+ PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT, PTC4_IN_PU),
+ PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT, PTC3_IN_PU),
+ PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT, PTC2_IN_PU),
+ PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT, PTC1_IN_PU),
+ PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT, PTC0_IN_PU),
+
+ /* PTD GPIO */
+ PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT, PTD7_IN_PU),
+ PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT, PTD6_IN_PU),
+ PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT, PTD5_IN_PU),
+ PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT, PTD4_IN_PU),
+ PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT, PTD3_IN_PU),
+ PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT, PTD2_IN_PU),
+ PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT, PTD1_IN_PU),
+ PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT, PTD0_IN_PU),
+
+ /* PTE GPIO */
+ PINMUX_DATA(PTE6_DATA, PTE6_IN),
+ PINMUX_DATA(PTE5_DATA, PTE5_IN),
+ PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT, PTE4_IN_PU),
+ PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT, PTE3_IN_PU),
+ PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT, PTE2_IN_PU),
+ PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT, PTE1_IN_PU),
+ PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT, PTE0_IN_PU),
+
+ /* PTF GPIO */
+ PINMUX_DATA(PTF6_DATA, PTF6_IN),
+ PINMUX_DATA(PTF5_DATA, PTF5_IN),
+ PINMUX_DATA(PTF4_DATA, PTF4_IN),
+ PINMUX_DATA(PTF3_DATA, PTF3_IN),
+ PINMUX_DATA(PTF2_DATA, PTF2_IN),
+ PINMUX_DATA(PTF1_DATA, PTF1_IN),
+ PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT, PTF0_IN_PU),
+
+ /* PTG GPIO */
+ PINMUX_DATA(PTG6_DATA, PTG6_IN, PTG6_OUT, PTG6_IN_PU),
+ PINMUX_DATA(PTG5_DATA, PTG5_IN, PTG5_OUT, PTG5_IN_PU),
+ PINMUX_DATA(PTG4_DATA, PTG4_IN, PTG4_OUT, PTG4_IN_PU),
+ PINMUX_DATA(PTG3_DATA, PTG3_IN, PTG3_OUT, PTG3_IN_PU),
+ PINMUX_DATA(PTG2_DATA, PTG2_IN, PTG2_OUT, PTG2_IN_PU),
+ PINMUX_DATA(PTG1_DATA, PTG1_IN, PTG1_OUT, PTG1_IN_PU),
+ PINMUX_DATA(PTG0_DATA, PTG0_IN, PTG0_OUT, PTG0_IN_PU),
+
+ /* PTH GPIO */
+ PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT, PTH6_IN_PU),
+ PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT, PTH5_IN_PU),
+ PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT, PTH4_IN_PU),
+ PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT, PTH3_IN_PU),
+ PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT, PTH2_IN_PU),
+ PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT, PTH1_IN_PU),
+ PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT, PTH0_IN_PU),
+
+ /* PTJ GPIO */
+ PINMUX_DATA(PTJ6_DATA, PTJ6_IN, PTJ6_OUT, PTJ6_IN_PU),
+ PINMUX_DATA(PTJ5_DATA, PTJ5_IN, PTJ5_OUT, PTJ5_IN_PU),
+ PINMUX_DATA(PTJ4_DATA, PTJ4_IN, PTJ4_OUT, PTJ4_IN_PU),
+ PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT, PTJ3_IN_PU),
+ PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT, PTJ2_IN_PU),
+ PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT, PTJ1_IN_PU),
+ PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT, PTJ0_IN_PU),
+
+ /* PTK GPIO */
+ PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT, PTK3_IN_PU),
+ PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT, PTK2_IN_PU),
+ PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT, PTK1_IN_PU),
+ PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT, PTK0_IN_PU),
+
+ /* PTL GPIO */
+ PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT, PTL7_IN_PU),
+ PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT, PTL6_IN_PU),
+ PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT, PTL5_IN_PU),
+ PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT, PTL4_IN_PU),
+ PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT, PTL3_IN_PU),
+
+ /* PTM GPIO */
+ PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT, PTM7_IN_PU),
+ PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT, PTM6_IN_PU),
+ PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT, PTM5_IN_PU),
+ PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT, PTM4_IN_PU),
+ PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT, PTM3_IN_PU),
+ PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT, PTM2_IN_PU),
+ PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT, PTM1_IN_PU),
+ PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT, PTM0_IN_PU),
+
+ /* PTP GPIO */
+ PINMUX_DATA(PTP4_DATA, PTP4_IN, PTP4_OUT, PTP4_IN_PU),
+ PINMUX_DATA(PTP3_DATA, PTP3_IN, PTP3_OUT, PTP3_IN_PU),
+ PINMUX_DATA(PTP2_DATA, PTP2_IN, PTP2_OUT, PTP2_IN_PU),
+ PINMUX_DATA(PTP1_DATA, PTP1_IN, PTP1_OUT, PTP1_IN_PU),
+ PINMUX_DATA(PTP0_DATA, PTP0_IN, PTP0_OUT, PTP0_IN_PU),
+
+ /* PTR GPIO */
+ PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT, PTR7_IN_PU),
+ PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT, PTR6_IN_PU),
+ PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT, PTR5_IN_PU),
+ PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT, PTR4_IN_PU),
+ PINMUX_DATA(PTR3_DATA, PTR3_IN, PTR3_OUT, PTR3_IN_PU),
+ PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_OUT, PTR2_IN_PU),
+ PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT, PTR1_IN_PU),
+ PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT, PTR0_IN_PU),
+
+ /* PTS GPIO */
+ PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT, PTS4_IN_PU),
+ PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT, PTS3_IN_PU),
+ PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT, PTS2_IN_PU),
+ PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT, PTS1_IN_PU),
+ PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT, PTS0_IN_PU),
+
+ /* PTT GPIO */
+ PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT, PTT4_IN_PU),
+ PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT, PTT3_IN_PU),
+ PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT, PTT2_IN_PU),
+ PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT, PTT1_IN_PU),
+ PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT, PTT0_IN_PU),
+
+ /* PTU GPIO */
+ PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT, PTU4_IN_PU),
+ PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT, PTU3_IN_PU),
+ PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT, PTU2_IN_PU),
+ PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT, PTU1_IN_PU),
+ PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT, PTU0_IN_PU),
+
+ /* PTV GPIO */
+ PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT, PTV4_IN_PU),
+ PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT, PTV3_IN_PU),
+ PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT, PTV2_IN_PU),
+ PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT, PTV1_IN_PU),
+ PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT, PTV0_IN_PU),
+
+ /* PTA FN */
+ PINMUX_DATA(D23_MARK, PTA7_FN),
+ PINMUX_DATA(D22_MARK, PTA6_FN),
+ PINMUX_DATA(D21_MARK, PTA5_FN),
+ PINMUX_DATA(D20_MARK, PTA4_FN),
+ PINMUX_DATA(D19_MARK, PTA3_FN),
+ PINMUX_DATA(D18_MARK, PTA2_FN),
+ PINMUX_DATA(D17_MARK, PTA1_FN),
+ PINMUX_DATA(D16_MARK, PTA0_FN),
+
+ /* PTB FN */
+ PINMUX_DATA(D31_MARK, PTB7_FN),
+ PINMUX_DATA(D30_MARK, PTB6_FN),
+ PINMUX_DATA(D29_MARK, PTB5_FN),
+ PINMUX_DATA(D28_MARK, PTB4_FN),
+ PINMUX_DATA(D27_MARK, PTB3_FN),
+ PINMUX_DATA(D26_MARK, PTB2_FN),
+ PINMUX_DATA(D25_MARK, PTB1_FN),
+ PINMUX_DATA(D24_MARK, PTB0_FN),
+
+ /* PTC FN */
+ PINMUX_DATA(LCD_DATA7_MARK, PTC7_FN),
+ PINMUX_DATA(LCD_DATA6_MARK, PTC6_FN),
+ PINMUX_DATA(LCD_DATA5_MARK, PTC5_FN),
+ PINMUX_DATA(LCD_DATA4_MARK, PTC4_FN),
+ PINMUX_DATA(LCD_DATA3_MARK, PTC3_FN),
+ PINMUX_DATA(LCD_DATA2_MARK, PTC2_FN),
+ PINMUX_DATA(LCD_DATA1_MARK, PTC1_FN),
+ PINMUX_DATA(LCD_DATA0_MARK, PTC0_FN),
+
+ /* PTD FN */
+ PINMUX_DATA(LCD_DATA15_MARK, PTD7_FN),
+ PINMUX_DATA(LCD_DATA14_MARK, PTD6_FN),
+ PINMUX_DATA(LCD_DATA13_MARK, PTD5_FN),
+ PINMUX_DATA(LCD_DATA12_MARK, PTD4_FN),
+ PINMUX_DATA(LCD_DATA11_MARK, PTD3_FN),
+ PINMUX_DATA(LCD_DATA10_MARK, PTD2_FN),
+ PINMUX_DATA(LCD_DATA9_MARK, PTD1_FN),
+ PINMUX_DATA(LCD_DATA8_MARK, PTD0_FN),
+
+ /* PTE FN */
+ PINMUX_DATA(IIC_SCL_MARK, PSELB_9_8_00, PTE6_FN),
+ PINMUX_DATA(AFE_RXIN_MARK, PSELB_9_8_11, PTE6_FN),
+ PINMUX_DATA(IIC_SDA_MARK, PSELB_9_8_00, PTE5_FN),
+ PINMUX_DATA(AFE_RDET_MARK, PSELB_9_8_11, PTE5_FN),
+ PINMUX_DATA(LCD_M_DISP_MARK, PTE4_FN),
+ PINMUX_DATA(LCD_CL1_MARK, PTE3_FN),
+ PINMUX_DATA(LCD_CL2_MARK, PTE2_FN),
+ PINMUX_DATA(LCD_DON_MARK, PTE1_FN),
+ PINMUX_DATA(LCD_FLM_MARK, PTE0_FN),
+
+ /* PTF FN */
+ PINMUX_DATA(DA1_MARK, PTF6_FN),
+ PINMUX_DATA(DA0_MARK, PTF5_FN),
+ PINMUX_DATA(AN3_MARK, PTF4_FN),
+ PINMUX_DATA(AN2_MARK, PTF3_FN),
+ PINMUX_DATA(AN1_MARK, PTF2_FN),
+ PINMUX_DATA(AN0_MARK, PTF1_FN),
+ PINMUX_DATA(ADTRG_MARK, PTF0_FN),
+
+ /* PTG FN */
+ PINMUX_DATA(USB1D_RCV_MARK, PSELA_3_2_00, PTG6_FN),
+ PINMUX_DATA(AFE_FS_MARK, PSELA_3_2_01, PTG6_FN),
+ PINMUX_DATA(PCC_REG_MARK, PSELA_3_2_10, PTG6_FN),
+ PINMUX_DATA(IRQ5_MARK, PSELA_3_2_11, PTG6_FN),
+ PINMUX_DATA(USB1D_TXSE0_MARK, PSELA_5_4_00, PTG5_FN),
+ PINMUX_DATA(AFE_TXOUT_MARK, PSELA_5_4_01, PTG5_FN),
+ PINMUX_DATA(PCC_DRV_MARK, PSELA_5_4_10, PTG5_FN),
+ PINMUX_DATA(IRQ4_MARK, PSELA_5_4_11, PTG5_FN),
+ PINMUX_DATA(USB1D_TXDPLS_MARK, PSELA_7_6_00, PTG4_FN),
+ PINMUX_DATA(AFE_SCLK_MARK, PSELA_7_6_01, PTG4_FN),
+ PINMUX_DATA(IOIS16_MARK, PSELA_7_6_10, PTG4_FN),
+ PINMUX_DATA(USB1D_DMNS_MARK, PSELA_9_8_00, PTG3_FN),
+ PINMUX_DATA(AFE_RLYCNT_MARK, PSELA_9_8_01, PTG3_FN),
+ PINMUX_DATA(PCC_BVD2_MARK, PSELA_9_8_10, PTG3_FN),
+ PINMUX_DATA(USB1D_DPLS_MARK, PSELA_11_10_00, PTG2_FN),
+ PINMUX_DATA(AFE_HC1_MARK, PSELA_11_10_01, PTG2_FN),
+ PINMUX_DATA(PCC_BVD1_MARK, PSELA_11_10_10, PTG2_FN),
+ PINMUX_DATA(USB1D_SPEED_MARK, PSELA_13_12_00, PTG1_FN),
+ PINMUX_DATA(PCC_CD2_MARK, PSELA_13_12_10, PTG1_FN),
+ PINMUX_DATA(USB1D_TXENL_MARK, PSELA_15_14_00, PTG0_FN),
+ PINMUX_DATA(PCC_CD1_MARK, PSELA_15_14_10, PTG0_FN),
+
+ /* PTH FN */
+ PINMUX_DATA(RAS_MARK, PTH6_FN),
+ PINMUX_DATA(CAS_MARK, PTH5_FN),
+ PINMUX_DATA(CKE_MARK, PTH4_FN),
+ PINMUX_DATA(STATUS1_MARK, PTH3_FN),
+ PINMUX_DATA(STATUS0_MARK, PTH2_FN),
+ PINMUX_DATA(USB2_PWR_EN_MARK, PTH1_FN),
+ PINMUX_DATA(USB1_PWR_EN_USBF_UPLUP_MARK, PTH0_FN),
+
+ /* PTJ FN */
+ PINMUX_DATA(AUDCK_MARK, PTJ6_FN),
+ PINMUX_DATA(ASEBRKAK_MARK, PTJ5_FN),
+ PINMUX_DATA(AUDATA3_MARK, PTJ4_FN),
+ PINMUX_DATA(AUDATA2_MARK, PTJ3_FN),
+ PINMUX_DATA(AUDATA1_MARK, PTJ2_FN),
+ PINMUX_DATA(AUDATA0_MARK, PTJ1_FN),
+ PINMUX_DATA(AUDSYNC_MARK, PTJ0_FN),
+
+ /* PTK FN */
+ PINMUX_DATA(PCC_RESET_MARK, PTK3_FN),
+ PINMUX_DATA(PCC_RDY_MARK, PTK2_FN),
+ PINMUX_DATA(PCC_VS2_MARK, PTK1_FN),
+ PINMUX_DATA(PCC_VS1_MARK, PTK0_FN),
+
+ /* PTL FN */
+ PINMUX_DATA(TRST_MARK, PTL7_FN),
+ PINMUX_DATA(TMS_MARK, PTL6_FN),
+ PINMUX_DATA(TDO_MARK, PTL5_FN),
+ PINMUX_DATA(TDI_MARK, PTL4_FN),
+ PINMUX_DATA(TCK_MARK, PTL3_FN),
+
+ /* PTM FN */
+ PINMUX_DATA(DREQ1_MARK, PTM7_FN),
+ PINMUX_DATA(DREQ0_MARK, PTM6_FN),
+ PINMUX_DATA(DACK1_MARK, PTM5_FN),
+ PINMUX_DATA(DACK0_MARK, PTM4_FN),
+ PINMUX_DATA(TEND1_MARK, PTM3_FN),
+ PINMUX_DATA(TEND0_MARK, PTM2_FN),
+ PINMUX_DATA(CS5B_CE1A_MARK, PTM1_FN),
+ PINMUX_DATA(CS6B_CE1B_MARK, PTM0_FN),
+
+ /* PTP FN */
+ PINMUX_DATA(USB1D_SUSPEND_MARK, PSELA_1_0_00, PTP4_FN),
+ PINMUX_DATA(REFOUT_MARK, PSELA_1_0_01, PTP4_FN),
+ PINMUX_DATA(IRQOUT_MARK, PSELA_1_0_10, PTP4_FN),
+ PINMUX_DATA(IRQ3_IRL3_MARK, PTP3_FN),
+ PINMUX_DATA(IRQ2_IRL2_MARK, PTP2_FN),
+ PINMUX_DATA(IRQ1_IRL1_MARK, PTP1_FN),
+ PINMUX_DATA(IRQ0_IRL0_MARK, PTP0_FN),
+
+ /* PTR FN */
+ PINMUX_DATA(A25_MARK, PTR7_FN),
+ PINMUX_DATA(A24_MARK, PTR6_FN),
+ PINMUX_DATA(A23_MARK, PTR5_FN),
+ PINMUX_DATA(A22_MARK, PTR4_FN),
+ PINMUX_DATA(A21_MARK, PTR3_FN),
+ PINMUX_DATA(A20_MARK, PTR2_FN),
+ PINMUX_DATA(A19_MARK, PTR1_FN),
+ PINMUX_DATA(A0_MARK, PTR0_FN),
+
+ /* PTS FN */
+ PINMUX_DATA(SIOF0_SYNC_MARK, PTS4_FN),
+ PINMUX_DATA(SIOF0_MCLK_MARK, PTS3_FN),
+ PINMUX_DATA(SIOF0_TXD_MARK, PTS2_FN),
+ PINMUX_DATA(SIOF0_RXD_MARK, PTS1_FN),
+ PINMUX_DATA(SIOF0_SCK_MARK, PTS0_FN),
+
+ /* PTT FN */
+ PINMUX_DATA(SCIF0_CTS_MARK, PSELB_15_14_00, PTT4_FN),
+ PINMUX_DATA(TPU_TO1_MARK, PSELB_15_14_11, PTT4_FN),
+ PINMUX_DATA(SCIF0_RTS_MARK, PSELB_15_14_00, PTT3_FN),
+ PINMUX_DATA(TPU_TO0_MARK, PSELB_15_14_11, PTT3_FN),
+ PINMUX_DATA(SCIF0_TXD_MARK, PTT2_FN),
+ PINMUX_DATA(SCIF0_RXD_MARK, PTT1_FN),
+ PINMUX_DATA(SCIF0_SCK_MARK, PTT0_FN),
+
+ /* PTU FN */
+ PINMUX_DATA(SIOF1_SYNC_MARK, PTU4_FN),
+ PINMUX_DATA(SIOF1_MCLK_MARK, PSELD_11_10_00, PTU3_FN),
+ PINMUX_DATA(TPU_TI3B_MARK, PSELD_11_10_01, PTU3_FN),
+ PINMUX_DATA(SIOF1_TXD_MARK, PSELD_15_14_00, PTU2_FN),
+ PINMUX_DATA(TPU_TI3A_MARK, PSELD_15_14_01, PTU2_FN),
+ PINMUX_DATA(MMC_DAT_MARK, PSELD_15_14_10, PTU2_FN),
+ PINMUX_DATA(SIOF1_RXD_MARK, PSELC_13_12_00, PTU1_FN),
+ PINMUX_DATA(TPU_TI2B_MARK, PSELC_13_12_01, PTU1_FN),
+ PINMUX_DATA(MMC_CMD_MARK, PSELC_13_12_10, PTU1_FN),
+ PINMUX_DATA(SIOF1_SCK_MARK, PSELC_15_14_00, PTU0_FN),
+ PINMUX_DATA(TPU_TI2A_MARK, PSELC_15_14_01, PTU0_FN),
+ PINMUX_DATA(MMC_CLK_MARK, PSELC_15_14_10, PTU0_FN),
+
+ /* PTV FN */
+ PINMUX_DATA(SCIF1_CTS_MARK, PSELB_11_10_00, PTV4_FN),
+ PINMUX_DATA(TPU_TO3_MARK, PSELB_11_10_01, PTV4_FN),
+ PINMUX_DATA(MMC_VDDON_MARK, PSELB_11_10_10, PTV4_FN),
+ PINMUX_DATA(LCD_VEPWC_MARK, PSELB_11_10_11, PTV4_FN),
+ PINMUX_DATA(SCIF1_RTS_MARK, PSELB_13_12_00, PTV3_FN),
+ PINMUX_DATA(TPU_TO2_MARK, PSELB_13_12_01, PTV3_FN),
+ PINMUX_DATA(MMC_ODMOD_MARK, PSELB_13_12_10, PTV3_FN),
+ PINMUX_DATA(LCD_VCPWC_MARK, PSELB_13_12_11, PTV3_FN),
+ PINMUX_DATA(SCIF1_TXD_MARK, PSELC_9_8_00, PTV2_FN),
+ PINMUX_DATA(SIM_D_MARK, PSELC_9_8_10, PTV2_FN),
+ PINMUX_DATA(SCIF1_RXD_MARK, PSELC_11_10_00, PTV1_FN),
+ PINMUX_DATA(SIM_RST_MARK, PSELC_11_10_10, PTV1_FN),
+ PINMUX_DATA(SCIF1_SCK_MARK, PSELD_1_0_00, PTV0_FN),
+ PINMUX_DATA(SIM_CLK_MARK, PSELD_1_0_10, PTV0_FN),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ /* PTA */
+ PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
+ PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
+ PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
+ PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
+ PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
+ PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
+ PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
+ PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+
+ /* PTB */
+ PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
+ PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
+ PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
+ PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
+ PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
+ PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
+ PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
+ PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+
+ /* PTC */
+ PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
+ PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
+ PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
+ PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
+ PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
+ PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
+ PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
+ PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+
+ /* PTD */
+ PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
+ PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
+ PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
+ PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
+ PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
+ PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
+ PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
+ PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+
+ /* PTE */
+ PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
+ PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
+ PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
+ PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
+ PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
+ PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
+ PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+
+ /* PTF */
+ PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
+ PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
+ PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
+ PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
+ PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
+ PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
+ PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+
+ /* PTG */
+ PINMUX_GPIO(GPIO_PTG6, PTG6_DATA),
+ PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
+ PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
+ PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
+ PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
+ PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
+ PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+
+ /* PTH */
+ PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
+ PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
+ PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
+ PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
+ PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
+ PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
+ PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+
+ /* PTJ */
+ PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
+ PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
+ PINMUX_GPIO(GPIO_PTJ4, PTJ4_DATA),
+ PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
+ PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
+ PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
+ PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+
+ /* PTK */
+ PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
+ PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
+ PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
+ PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+
+ /* PTL */
+ PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
+ PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
+ PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
+ PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
+ PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
+
+ /* PTM */
+ PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
+ PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
+ PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
+ PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
+ PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
+ PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
+ PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
+ PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+
+ /* PTP */
+ PINMUX_GPIO(GPIO_PTP4, PTP4_DATA),
+ PINMUX_GPIO(GPIO_PTP3, PTP3_DATA),
+ PINMUX_GPIO(GPIO_PTP2, PTP2_DATA),
+ PINMUX_GPIO(GPIO_PTP1, PTP1_DATA),
+ PINMUX_GPIO(GPIO_PTP0, PTP0_DATA),
+
+ /* PTR */
+ PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
+ PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
+ PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
+ PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
+ PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
+ PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
+ PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
+ PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+
+ /* PTS */
+ PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
+ PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
+ PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
+ PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
+ PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+
+ /* PTT */
+ PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
+ PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
+ PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
+ PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
+ PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+
+ /* PTU */
+ PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
+ PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
+ PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
+ PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
+ PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+
+ /* PTV */
+ PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
+ PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
+ PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
+ PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
+ PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+
+ /* BSC */
+ PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
+ PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
+ PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
+ PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
+ PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
+ PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
+ PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
+ PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
+ PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
+ PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
+ PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
+ PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
+ PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
+ PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
+ PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
+ PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+ PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
+ PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
+ PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5B_CE1A, CS5B_CE1A_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6B_CE1B, CS6B_CE1B_MARK),
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+ PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+ PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+ PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+ PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
+ PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
+ PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+ PINMUX_GPIO(GPIO_FN_REFOUT, REFOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQOUT, IRQOUT_MARK),
+
+ /* LCDC */
+ PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_CL1, LCD_CL1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_CL2, LCD_CL2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DON, LCD_DON_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_FLM, LCD_FLM_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_VEPWC, LCD_VEPWC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_VCPWC, LCD_VCPWC_MARK),
+
+ /* AFEIF */
+ PINMUX_GPIO(GPIO_FN_AFE_RXIN, AFE_RXIN_MARK),
+ PINMUX_GPIO(GPIO_FN_AFE_RDET, AFE_RDET_MARK),
+ PINMUX_GPIO(GPIO_FN_AFE_FS, AFE_FS_MARK),
+ PINMUX_GPIO(GPIO_FN_AFE_TXOUT, AFE_TXOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_AFE_SCLK, AFE_SCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_AFE_RLYCNT, AFE_RLYCNT_MARK),
+ PINMUX_GPIO(GPIO_FN_AFE_HC1, AFE_HC1_MARK),
+
+ /* IIC */
+ PINMUX_GPIO(GPIO_FN_IIC_SCL, IIC_SCL_MARK),
+ PINMUX_GPIO(GPIO_FN_IIC_SDA, IIC_SDA_MARK),
+
+ /* DAC */
+ PINMUX_GPIO(GPIO_FN_DA1, DA1_MARK),
+ PINMUX_GPIO(GPIO_FN_DA0, DA0_MARK),
+
+ /* ADC */
+ PINMUX_GPIO(GPIO_FN_AN3, AN3_MARK),
+ PINMUX_GPIO(GPIO_FN_AN2, AN2_MARK),
+ PINMUX_GPIO(GPIO_FN_AN1, AN1_MARK),
+ PINMUX_GPIO(GPIO_FN_AN0, AN0_MARK),
+ PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
+
+ /* USB */
+ PINMUX_GPIO(GPIO_FN_USB1D_RCV, USB1D_RCV_MARK),
+ PINMUX_GPIO(GPIO_FN_USB1D_TXSE0, USB1D_TXSE0_MARK),
+ PINMUX_GPIO(GPIO_FN_USB1D_TXDPLS, USB1D_TXDPLS_MARK),
+ PINMUX_GPIO(GPIO_FN_USB1D_DMNS, USB1D_DMNS_MARK),
+ PINMUX_GPIO(GPIO_FN_USB1D_DPLS, USB1D_DPLS_MARK),
+ PINMUX_GPIO(GPIO_FN_USB1D_SPEED, USB1D_SPEED_MARK),
+ PINMUX_GPIO(GPIO_FN_USB1D_TXENL, USB1D_TXENL_MARK),
+
+ PINMUX_GPIO(GPIO_FN_USB2_PWR_EN, USB2_PWR_EN_MARK),
+ PINMUX_GPIO(GPIO_FN_USB1_PWR_EN_USBF_UPLUP,
+ USB1_PWR_EN_USBF_UPLUP_MARK),
+ PINMUX_GPIO(GPIO_FN_USB1D_SUSPEND, USB1D_SUSPEND_MARK),
+
+ /* INTC */
+ PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4, IRQ4_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_IRL3, IRQ3_IRL3_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_IRL2, IRQ2_IRL2_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_IRL1, IRQ1_IRL1_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_IRL0, IRQ0_IRL0_MARK),
+
+ /* PCC */
+ PINMUX_GPIO(GPIO_FN_PCC_REG, PCC_REG_MARK),
+ PINMUX_GPIO(GPIO_FN_PCC_DRV, PCC_DRV_MARK),
+ PINMUX_GPIO(GPIO_FN_PCC_BVD2, PCC_BVD2_MARK),
+ PINMUX_GPIO(GPIO_FN_PCC_BVD1, PCC_BVD1_MARK),
+ PINMUX_GPIO(GPIO_FN_PCC_CD2, PCC_CD2_MARK),
+ PINMUX_GPIO(GPIO_FN_PCC_CD1, PCC_CD1_MARK),
+ PINMUX_GPIO(GPIO_FN_PCC_RESET, PCC_RESET_MARK),
+ PINMUX_GPIO(GPIO_FN_PCC_RDY, PCC_RDY_MARK),
+ PINMUX_GPIO(GPIO_FN_PCC_VS2, PCC_VS2_MARK),
+ PINMUX_GPIO(GPIO_FN_PCC_VS1, PCC_VS1_MARK),
+
+ /* HUDI */
+ PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_ASEBRKAK, ASEBRKAK_MARK),
+ PINMUX_GPIO(GPIO_FN_TRST, TRST_MARK),
+ PINMUX_GPIO(GPIO_FN_TMS, TMS_MARK),
+ PINMUX_GPIO(GPIO_FN_TDO, TDO_MARK),
+ PINMUX_GPIO(GPIO_FN_TDI, TDI_MARK),
+ PINMUX_GPIO(GPIO_FN_TCK, TCK_MARK),
+
+ /* DMAC */
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
+
+ /* SIOF0 */
+ PINMUX_GPIO(GPIO_FN_SIOF0_SYNC, SIOF0_SYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF0_MCLK, SIOF0_MCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF0_TXD, SIOF0_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF0_RXD, SIOF0_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF0_SCK, SIOF0_SCK_MARK),
+
+ /* SIOF1 */
+ PINMUX_GPIO(GPIO_FN_SIOF1_SYNC, SIOF1_SYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF1_MCLK, SIOF1_MCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF1_TXD, SIOF1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF1_RXD, SIOF1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF1_SCK, SIOF1_SCK_MARK),
+
+ /* SCIF0 */
+ PINMUX_GPIO(GPIO_FN_SCIF0_TXD, SCIF0_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_RXD, SCIF0_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_RTS, SCIF0_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_CTS, SCIF0_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_SCK, SCIF0_SCK_MARK),
+
+ /* SCIF1 */
+ PINMUX_GPIO(GPIO_FN_SCIF1_TXD, SCIF1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_RXD, SCIF1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_RTS, SCIF1_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_CTS, SCIF1_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_SCK, SCIF1_SCK_MARK),
+
+ /* TPU */
+ PINMUX_GPIO(GPIO_FN_TPU_TO1, TPU_TO1_MARK),
+ PINMUX_GPIO(GPIO_FN_TPU_TO0, TPU_TO0_MARK),
+ PINMUX_GPIO(GPIO_FN_TPU_TI3B, TPU_TI3B_MARK),
+ PINMUX_GPIO(GPIO_FN_TPU_TI3A, TPU_TI3A_MARK),
+ PINMUX_GPIO(GPIO_FN_TPU_TI2B, TPU_TI2B_MARK),
+ PINMUX_GPIO(GPIO_FN_TPU_TI2A, TPU_TI2A_MARK),
+ PINMUX_GPIO(GPIO_FN_TPU_TO3, TPU_TO3_MARK),
+ PINMUX_GPIO(GPIO_FN_TPU_TO2, TPU_TO2_MARK),
+
+ /* SIM */
+ PINMUX_GPIO(GPIO_FN_SIM_D, SIM_D_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_CLK, SIM_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_RST, SIM_RST_MARK),
+
+ /* MMC */
+ PINMUX_GPIO(GPIO_FN_MMC_DAT, MMC_DAT_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_CMD, MMC_CMD_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_CLK, MMC_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_VDDON, MMC_VDDON_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_ODMOD, MMC_ODMOD_MARK),
+
+ /* SYSC */
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
+ PTA7_FN, PTA7_OUT, PTA7_IN_PU, PTA7_IN,
+ PTA6_FN, PTA6_OUT, PTA6_IN_PU, PTA6_IN,
+ PTA5_FN, PTA5_OUT, PTA5_IN_PU, PTA5_IN,
+ PTA4_FN, PTA4_OUT, PTA4_IN_PU, PTA4_IN,
+ PTA3_FN, PTA3_OUT, PTA3_IN_PU, PTA3_IN,
+ PTA2_FN, PTA2_OUT, PTA2_IN_PU, PTA2_IN,
+ PTA1_FN, PTA1_OUT, PTA1_IN_PU, PTA1_IN,
+ PTA0_FN, PTA0_OUT, PTA0_IN_PU, PTA0_IN }
+ },
+ { PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
+ PTB7_FN, PTB7_OUT, PTB7_IN_PU, PTB7_IN,
+ PTB6_FN, PTB6_OUT, PTB6_IN_PU, PTB6_IN,
+ PTB5_FN, PTB5_OUT, PTB5_IN_PU, PTB5_IN,
+ PTB4_FN, PTB4_OUT, PTB4_IN_PU, PTB4_IN,
+ PTB3_FN, PTB3_OUT, PTB3_IN_PU, PTB3_IN,
+ PTB2_FN, PTB2_OUT, PTB2_IN_PU, PTB2_IN,
+ PTB1_FN, PTB1_OUT, PTB1_IN_PU, PTB1_IN,
+ PTB0_FN, PTB0_OUT, PTB0_IN_PU, PTB0_IN }
+ },
+ { PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
+ PTC7_FN, PTC7_OUT, PTC7_IN_PU, PTC7_IN,
+ PTC6_FN, PTC6_OUT, PTC6_IN_PU, PTC6_IN,
+ PTC5_FN, PTC5_OUT, PTC5_IN_PU, PTC5_IN,
+ PTC4_FN, PTC4_OUT, PTC4_IN_PU, PTC4_IN,
+ PTC3_FN, PTC3_OUT, PTC3_IN_PU, PTC3_IN,
+ PTC2_FN, PTC2_OUT, PTC2_IN_PU, PTC2_IN,
+ PTC1_FN, PTC1_OUT, PTC1_IN_PU, PTC1_IN,
+ PTC0_FN, PTC0_OUT, PTC0_IN_PU, PTC0_IN }
+ },
+ { PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
+ PTD7_FN, PTD7_OUT, PTD7_IN_PU, PTD7_IN,
+ PTD6_FN, PTD6_OUT, PTD6_IN_PU, PTD6_IN,
+ PTD5_FN, PTD5_OUT, PTD5_IN_PU, PTD5_IN,
+ PTD4_FN, PTD4_OUT, PTD4_IN_PU, PTD4_IN,
+ PTD3_FN, PTD3_OUT, PTD3_IN_PU, PTD3_IN,
+ PTD2_FN, PTD2_OUT, PTD2_IN_PU, PTD2_IN,
+ PTD1_FN, PTD1_OUT, PTD1_IN_PU, PTD1_IN,
+ PTD0_FN, PTD0_OUT, PTD0_IN_PU, PTD0_IN }
+ },
+ { PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
+ 0, 0, 0, 0,
+ PTE6_FN, 0, 0, PTE6_IN,
+ PTE5_FN, 0, 0, PTE5_IN,
+ PTE4_FN, PTE4_OUT, PTE4_IN_PU, PTE4_IN,
+ PTE3_FN, PTE3_OUT, PTE3_IN_PU, PTE3_IN,
+ PTE2_FN, PTE2_OUT, PTE2_IN_PU, PTE2_IN,
+ PTE1_FN, PTE1_OUT, PTE1_IN_PU, PTE1_IN,
+ PTE0_FN, PTE0_OUT, PTE0_IN_PU, PTE0_IN }
+ },
+ { PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
+ 0, 0, 0, 0,
+ PTF6_FN, 0, 0, PTF6_IN,
+ PTF5_FN, 0, 0, PTF5_IN,
+ PTF4_FN, 0, 0, PTF4_IN,
+ PTF3_FN, 0, 0, PTF3_IN,
+ PTF2_FN, 0, 0, PTF2_IN,
+ PTF1_FN, 0, 0, PTF1_IN,
+ PTF0_FN, 0, 0, PTF0_IN }
+ },
+ { PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
+ 0, 0, 0, 0,
+ PTG6_FN, PTG6_OUT, PTG6_IN_PU, PTG6_IN,
+ PTG5_FN, PTG5_OUT, PTG5_IN_PU, PTG5_IN,
+ PTG4_FN, PTG4_OUT, PTG4_IN_PU, PTG4_IN,
+ PTG3_FN, PTG3_OUT, PTG3_IN_PU, PTG3_IN,
+ PTG2_FN, PTG2_OUT, PTG2_IN_PU, PTG2_IN,
+ PTG1_FN, PTG1_OUT, PTG1_IN_PU, PTG1_IN,
+ PTG0_FN, PTG0_OUT, PTG0_IN_PU, PTG0_IN }
+ },
+ { PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
+ 0, 0, 0, 0,
+ PTH6_FN, PTH6_OUT, PTH6_IN_PU, PTH6_IN,
+ PTH5_FN, PTH5_OUT, PTH5_IN_PU, PTH5_IN,
+ PTH4_FN, PTH4_OUT, PTH4_IN_PU, PTH4_IN,
+ PTH3_FN, PTH3_OUT, PTH3_IN_PU, PTH3_IN,
+ PTH2_FN, PTH2_OUT, PTH2_IN_PU, PTH2_IN,
+ PTH1_FN, PTH1_OUT, PTH1_IN_PU, PTH1_IN,
+ PTH0_FN, PTH0_OUT, PTH0_IN_PU, PTH0_IN }
+ },
+ { PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
+ 0, 0, 0, 0,
+ PTJ6_FN, PTJ6_OUT, PTJ6_IN_PU, PTJ6_IN,
+ PTJ5_FN, PTJ5_OUT, PTJ5_IN_PU, PTJ5_IN,
+ PTJ4_FN, PTJ4_OUT, PTJ4_IN_PU, PTJ4_IN,
+ PTJ3_FN, PTJ3_OUT, PTJ3_IN_PU, PTJ3_IN,
+ PTJ2_FN, PTJ2_OUT, PTJ2_IN_PU, PTJ2_IN,
+ PTJ1_FN, PTJ1_OUT, PTJ1_IN_PU, PTJ1_IN,
+ PTJ0_FN, PTJ0_OUT, PTJ0_IN_PU, PTJ0_IN }
+ },
+ { PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTK3_FN, PTK3_OUT, PTK3_IN_PU, PTK3_IN,
+ PTK2_FN, PTK2_OUT, PTK2_IN_PU, PTK2_IN,
+ PTK1_FN, PTK1_OUT, PTK1_IN_PU, PTK1_IN,
+ PTK0_FN, PTK0_OUT, PTK0_IN_PU, PTK0_IN }
+ },
+ { PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
+ PTL7_FN, PTL7_OUT, PTL7_IN_PU, PTL7_IN,
+ PTL6_FN, PTL6_OUT, PTL6_IN_PU, PTL6_IN,
+ PTL5_FN, PTL5_OUT, PTL5_IN_PU, PTL5_IN,
+ PTL4_FN, PTL4_OUT, PTL4_IN_PU, PTL4_IN,
+ PTL3_FN, PTL3_OUT, PTL3_IN_PU, PTL3_IN,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
+ PTM7_FN, PTM7_OUT, PTM7_IN_PU, PTM7_IN,
+ PTM6_FN, PTM6_OUT, PTM6_IN_PU, PTM6_IN,
+ PTM5_FN, PTM5_OUT, PTM5_IN_PU, PTM5_IN,
+ PTM4_FN, PTM4_OUT, PTM4_IN_PU, PTM4_IN,
+ PTM3_FN, PTM3_OUT, PTM3_IN_PU, PTM3_IN,
+ PTM2_FN, PTM2_OUT, PTM2_IN_PU, PTM2_IN,
+ PTM1_FN, PTM1_OUT, PTM1_IN_PU, PTM1_IN,
+ PTM0_FN, PTM0_OUT, PTM0_IN_PU, PTM0_IN }
+ },
+ { PINMUX_CFG_REG("PPCR", 0xa4050118, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTP4_FN, PTP4_OUT, PTP4_IN_PU, PTP4_IN,
+ PTP3_FN, PTP3_OUT, PTP3_IN_PU, PTP3_IN,
+ PTP2_FN, PTP2_OUT, PTP2_IN_PU, PTP2_IN,
+ PTP1_FN, PTP1_OUT, PTP1_IN_PU, PTP1_IN,
+ PTP0_FN, PTP0_OUT, PTP0_IN_PU, PTP0_IN }
+ },
+ { PINMUX_CFG_REG("PRCR", 0xa405011a, 16, 2) {
+ PTR7_FN, PTR7_OUT, PTR7_IN_PU, PTR7_IN,
+ PTR6_FN, PTR6_OUT, PTR6_IN_PU, PTR6_IN,
+ PTR5_FN, PTR5_OUT, PTR5_IN_PU, PTR5_IN,
+ PTR4_FN, PTR4_OUT, PTR4_IN_PU, PTR4_IN,
+ PTR3_FN, PTR3_OUT, PTR3_IN_PU, PTR3_IN,
+ PTR2_FN, PTR2_OUT, PTR2_IN_PU, PTR2_IN,
+ PTR1_FN, PTR1_OUT, PTR1_IN_PU, PTR1_IN,
+ PTR0_FN, PTR0_OUT, PTR0_IN_PU, PTR0_IN }
+ },
+ { PINMUX_CFG_REG("PSCR", 0xa405011c, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTS4_FN, PTS4_OUT, PTS4_IN_PU, PTS4_IN,
+ PTS3_FN, PTS3_OUT, PTS3_IN_PU, PTS3_IN,
+ PTS2_FN, PTS2_OUT, PTS2_IN_PU, PTS2_IN,
+ PTS1_FN, PTS1_OUT, PTS1_IN_PU, PTS1_IN,
+ PTS0_FN, PTS0_OUT, PTS0_IN_PU, PTS0_IN }
+ },
+ { PINMUX_CFG_REG("PTCR", 0xa405011e, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTT4_FN, PTT4_OUT, PTT4_IN_PU, PTT4_IN,
+ PTT3_FN, PTT3_OUT, PTT3_IN_PU, PTT3_IN,
+ PTT2_FN, PTT2_OUT, PTT2_IN_PU, PTT2_IN,
+ PTT1_FN, PTT1_OUT, PTT1_IN_PU, PTT1_IN,
+ PTT0_FN, PTT0_OUT, PTT0_IN_PU, PTT0_IN }
+ },
+ { PINMUX_CFG_REG("PUCR", 0xa4050120, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTU4_FN, PTU4_OUT, PTU4_IN_PU, PTU4_IN,
+ PTU3_FN, PTU3_OUT, PTU3_IN_PU, PTU3_IN,
+ PTU2_FN, PTU2_OUT, PTU2_IN_PU, PTU2_IN,
+ PTU1_FN, PTU1_OUT, PTU1_IN_PU, PTU1_IN,
+ PTU0_FN, PTU0_OUT, PTU0_IN_PU, PTU0_IN }
+ },
+ { PINMUX_CFG_REG("PVCR", 0xa4050122, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTV4_FN, PTV4_OUT, PTV4_IN_PU, PTV4_IN,
+ PTV3_FN, PTV3_OUT, PTV3_IN_PU, PTV3_IN,
+ PTV2_FN, PTV2_OUT, PTV2_IN_PU, PTV2_IN,
+ PTV1_FN, PTV1_OUT, PTV1_IN_PU, PTV1_IN,
+ PTV0_FN, PTV0_OUT, PTV0_IN_PU, PTV0_IN }
+ },
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR", 0xa4050140, 8) {
+ PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+ PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
+ },
+ { PINMUX_DATA_REG("PBDR", 0xa4050142, 8) {
+ PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+ PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
+ },
+ { PINMUX_DATA_REG("PCDR", 0xa4050144, 8) {
+ PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
+ PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA }
+ },
+ { PINMUX_DATA_REG("PDDR", 0xa4050126, 8) {
+ PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+ PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
+ },
+ { PINMUX_DATA_REG("PEDR", 0xa4050148, 8) {
+ 0, PTE6_DATA, PTE5_DATA, PTE4_DATA,
+ PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA }
+ },
+ { PINMUX_DATA_REG("PFDR", 0xa405014a, 8) {
+ 0, PTF6_DATA, PTF5_DATA, PTF4_DATA,
+ PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
+ },
+ { PINMUX_DATA_REG("PGDR", 0xa405014c, 8) {
+ 0, PTG6_DATA, PTG5_DATA, PTG4_DATA,
+ PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
+ },
+ { PINMUX_DATA_REG("PHDR", 0xa405014e, 8) {
+ 0, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+ PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR", 0xa4050150, 8) {
+ 0, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+ PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
+ },
+ { PINMUX_DATA_REG("PKDR", 0xa4050152, 8) {
+ 0, 0, 0, 0,
+ PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
+ },
+ { PINMUX_DATA_REG("PLDR", 0xa4050154, 8) {
+ PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL3_DATA, 0, 0, 0 }
+ },
+ { PINMUX_DATA_REG("PMDR", 0xa4050156, 8) {
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
+ },
+ { PINMUX_DATA_REG("PPDR", 0xa4050158, 8) {
+ 0, 0, 0, PTP4_DATA,
+ PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA }
+ },
+ { PINMUX_DATA_REG("PRDR", 0xa405015a, 8) {
+ PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
+ PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
+ },
+ { PINMUX_DATA_REG("PSDR", 0xa405015c, 8) {
+ 0, 0, 0, PTS4_DATA,
+ PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
+ },
+ { PINMUX_DATA_REG("PTDR", 0xa405015e, 8) {
+ 0, 0, 0, PTT4_DATA,
+ PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
+ },
+ { PINMUX_DATA_REG("PUDR", 0xa4050160, 8) {
+ 0, 0, 0, PTU4_DATA,
+ PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
+ },
+ { PINMUX_DATA_REG("PVDR", 0xa4050162, 8) {
+ 0, 0, 0, PTV4_DATA,
+ PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
+ },
+ { },
+};
+
+struct sh_pfc_soc_info sh7720_pinmux_info = {
+ .name = "sh7720_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PTA7,
+ .last_gpio = GPIO_FN_STATUS1,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7722.c b/drivers/pinctrl/sh-pfc/pfc-sh7722.c
new file mode 100644
index 000000000000..2de0929315e6
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7722.c
@@ -0,0 +1,1779 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7722.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+ PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
+ PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+ PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
+ PTC7_DATA, PTC5_DATA, PTC4_DATA, PTC3_DATA, PTC2_DATA, PTC0_DATA,
+ PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+ PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
+ PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA, PTE1_DATA, PTE0_DATA,
+ PTF6_DATA, PTF5_DATA, PTF4_DATA,
+ PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
+ PTG4_DATA, PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
+ PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+ PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
+ PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, PTJ1_DATA, PTJ0_DATA,
+ PTK6_DATA, PTK5_DATA, PTK4_DATA,
+ PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
+ PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
+ PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
+ PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+ PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
+ PTR4_DATA, PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
+ PTS4_DATA, PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
+ PTT4_DATA, PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
+ PTU4_DATA, PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
+ PTV4_DATA, PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
+ PTW6_DATA, PTW5_DATA, PTW4_DATA,
+ PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA,
+ PTX6_DATA, PTX5_DATA, PTX4_DATA,
+ PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA,
+ PTY6_DATA, PTY5_DATA, PTY4_DATA,
+ PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA,
+ PTZ5_DATA, PTZ4_DATA, PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
+ PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
+ PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
+ PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
+ PTC7_IN, PTC5_IN, PTC4_IN, PTC3_IN, PTC2_IN, PTC0_IN,
+ PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN, PTD3_IN, PTD2_IN, PTD1_IN,
+ PTE7_IN, PTE6_IN, PTE5_IN, PTE4_IN, PTE1_IN, PTE0_IN,
+ PTF6_IN, PTF5_IN, PTF4_IN, PTF3_IN, PTF2_IN, PTF1_IN,
+ PTH6_IN, PTH5_IN, PTH1_IN, PTH0_IN,
+ PTJ1_IN, PTJ0_IN,
+ PTK6_IN, PTK5_IN, PTK4_IN, PTK3_IN, PTK2_IN, PTK0_IN,
+ PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
+ PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
+ PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
+ PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
+ PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
+ PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
+ PTQ5_IN, PTQ4_IN, PTQ3_IN, PTQ2_IN, PTQ0_IN,
+ PTR2_IN,
+ PTS4_IN, PTS2_IN, PTS1_IN,
+ PTT4_IN, PTT3_IN, PTT2_IN, PTT1_IN,
+ PTU4_IN, PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
+ PTV4_IN, PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
+ PTW6_IN, PTW4_IN, PTW3_IN, PTW2_IN, PTW1_IN, PTW0_IN,
+ PTX6_IN, PTX5_IN, PTX4_IN, PTX3_IN, PTX2_IN, PTX1_IN, PTX0_IN,
+ PTY5_IN, PTY4_IN, PTY3_IN, PTY2_IN, PTY0_IN,
+ PTZ5_IN, PTZ4_IN, PTZ3_IN, PTZ2_IN, PTZ1_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_INPUT_PULLDOWN_BEGIN,
+ PTA7_IN_PD, PTA6_IN_PD, PTA5_IN_PD, PTA4_IN_PD,
+ PTA3_IN_PD, PTA2_IN_PD, PTA1_IN_PD, PTA0_IN_PD,
+ PTE7_IN_PD, PTE6_IN_PD, PTE5_IN_PD, PTE4_IN_PD, PTE1_IN_PD, PTE0_IN_PD,
+ PTF6_IN_PD, PTF5_IN_PD, PTF4_IN_PD, PTF3_IN_PD, PTF2_IN_PD, PTF1_IN_PD,
+ PTH6_IN_PD, PTH5_IN_PD, PTH1_IN_PD, PTH0_IN_PD,
+ PTK6_IN_PD, PTK5_IN_PD, PTK4_IN_PD, PTK3_IN_PD, PTK2_IN_PD, PTK0_IN_PD,
+ PTL7_IN_PD, PTL6_IN_PD, PTL5_IN_PD, PTL4_IN_PD,
+ PTL3_IN_PD, PTL2_IN_PD, PTL1_IN_PD, PTL0_IN_PD,
+ PTM7_IN_PD, PTM6_IN_PD, PTM5_IN_PD, PTM4_IN_PD,
+ PTM3_IN_PD, PTM2_IN_PD, PTM1_IN_PD, PTM0_IN_PD,
+ PTQ5_IN_PD, PTQ4_IN_PD, PTQ3_IN_PD, PTQ2_IN_PD,
+ PTS4_IN_PD, PTS2_IN_PD, PTS1_IN_PD,
+ PTT4_IN_PD, PTT3_IN_PD, PTT2_IN_PD, PTT1_IN_PD,
+ PTU4_IN_PD, PTU3_IN_PD, PTU2_IN_PD, PTU1_IN_PD, PTU0_IN_PD,
+ PTV4_IN_PD, PTV3_IN_PD, PTV2_IN_PD, PTV1_IN_PD, PTV0_IN_PD,
+ PTW6_IN_PD, PTW4_IN_PD, PTW3_IN_PD, PTW2_IN_PD, PTW1_IN_PD, PTW0_IN_PD,
+ PTX6_IN_PD, PTX5_IN_PD, PTX4_IN_PD,
+ PTX3_IN_PD, PTX2_IN_PD, PTX1_IN_PD, PTX0_IN_PD,
+ PINMUX_INPUT_PULLDOWN_END,
+
+ PINMUX_INPUT_PULLUP_BEGIN,
+ PTC7_IN_PU, PTC5_IN_PU,
+ PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
+ PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU,
+ PTJ1_IN_PU, PTJ0_IN_PU,
+ PTQ0_IN_PU,
+ PTR2_IN_PU,
+ PTX6_IN_PU,
+ PTY5_IN_PU, PTY4_IN_PU, PTY3_IN_PU, PTY2_IN_PU, PTY0_IN_PU,
+ PTZ5_IN_PU, PTZ4_IN_PU, PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU,
+ PINMUX_INPUT_PULLUP_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ PTA7_OUT, PTA5_OUT,
+ PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
+ PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
+ PTC4_OUT, PTC3_OUT, PTC2_OUT, PTC0_OUT,
+ PTD6_OUT, PTD5_OUT, PTD4_OUT,
+ PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
+ PTE7_OUT, PTE6_OUT, PTE5_OUT, PTE4_OUT, PTE1_OUT, PTE0_OUT,
+ PTF6_OUT, PTF5_OUT, PTF4_OUT, PTF3_OUT, PTF2_OUT, PTF0_OUT,
+ PTG4_OUT, PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
+ PTH7_OUT, PTH6_OUT, PTH5_OUT, PTH4_OUT,
+ PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
+ PTJ7_OUT, PTJ6_OUT, PTJ5_OUT, PTJ1_OUT, PTJ0_OUT,
+ PTK6_OUT, PTK5_OUT, PTK4_OUT, PTK3_OUT, PTK1_OUT, PTK0_OUT,
+ PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
+ PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
+ PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
+ PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
+ PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
+ PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT, PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
+ PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
+ PTR4_OUT, PTR3_OUT, PTR1_OUT, PTR0_OUT,
+ PTS3_OUT, PTS2_OUT, PTS0_OUT,
+ PTT4_OUT, PTT3_OUT, PTT2_OUT, PTT0_OUT,
+ PTU4_OUT, PTU3_OUT, PTU2_OUT, PTU0_OUT,
+ PTV4_OUT, PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
+ PTW5_OUT, PTW4_OUT, PTW3_OUT, PTW2_OUT, PTW1_OUT, PTW0_OUT,
+ PTX6_OUT, PTX5_OUT, PTX4_OUT, PTX3_OUT, PTX2_OUT, PTX1_OUT, PTX0_OUT,
+ PTY5_OUT, PTY4_OUT, PTY3_OUT, PTY2_OUT, PTY1_OUT, PTY0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_MARK_BEGIN,
+ SCIF0_TXD_MARK, SCIF0_RXD_MARK,
+ SCIF0_RTS_MARK, SCIF0_CTS_MARK, SCIF0_SCK_MARK,
+ SCIF1_TXD_MARK, SCIF1_RXD_MARK,
+ SCIF1_RTS_MARK, SCIF1_CTS_MARK, SCIF1_SCK_MARK,
+ SCIF2_TXD_MARK, SCIF2_RXD_MARK,
+ SCIF2_RTS_MARK, SCIF2_CTS_MARK, SCIF2_SCK_MARK,
+ SIOTXD_MARK, SIORXD_MARK,
+ SIOD_MARK, SIOSTRB0_MARK, SIOSTRB1_MARK,
+ SIOSCK_MARK, SIOMCK_MARK,
+ VIO_D15_MARK, VIO_D14_MARK, VIO_D13_MARK, VIO_D12_MARK,
+ VIO_D11_MARK, VIO_D10_MARK, VIO_D9_MARK, VIO_D8_MARK,
+ VIO_D7_MARK, VIO_D6_MARK, VIO_D5_MARK, VIO_D4_MARK,
+ VIO_D3_MARK, VIO_D2_MARK, VIO_D1_MARK, VIO_D0_MARK,
+ VIO_CLK_MARK, VIO_VD_MARK, VIO_HD_MARK, VIO_FLD_MARK,
+ VIO_CKO_MARK, VIO_STEX_MARK, VIO_STEM_MARK, VIO_VD2_MARK,
+ VIO_HD2_MARK, VIO_CLK2_MARK,
+ LCDD23_MARK, LCDD22_MARK, LCDD21_MARK, LCDD20_MARK,
+ LCDD19_MARK, LCDD18_MARK, LCDD17_MARK, LCDD16_MARK,
+ LCDD15_MARK, LCDD14_MARK, LCDD13_MARK, LCDD12_MARK,
+ LCDD11_MARK, LCDD10_MARK, LCDD9_MARK, LCDD8_MARK,
+ LCDD7_MARK, LCDD6_MARK, LCDD5_MARK, LCDD4_MARK,
+ LCDD3_MARK, LCDD2_MARK, LCDD1_MARK, LCDD0_MARK,
+ LCDLCLK_MARK, LCDDON_MARK, LCDVCPWC_MARK, LCDVEPWC_MARK,
+ LCDVSYN_MARK, LCDDCK_MARK, LCDHSYN_MARK, LCDDISP_MARK,
+ LCDRS_MARK, LCDCS_MARK, LCDWR_MARK, LCDRD_MARK,
+ LCDDON2_MARK, LCDVCPWC2_MARK, LCDVEPWC2_MARK, LCDVSYN2_MARK,
+ LCDCS2_MARK,
+ IOIS16_MARK, A25_MARK, A24_MARK, A23_MARK, A22_MARK,
+ BS_MARK, CS6B_CE1B_MARK, WAIT_MARK, CS6A_CE2B_MARK,
+ HPD63_MARK, HPD62_MARK, HPD61_MARK, HPD60_MARK,
+ HPD59_MARK, HPD58_MARK, HPD57_MARK, HPD56_MARK,
+ HPD55_MARK, HPD54_MARK, HPD53_MARK, HPD52_MARK,
+ HPD51_MARK, HPD50_MARK, HPD49_MARK, HPD48_MARK,
+ HPDQM7_MARK, HPDQM6_MARK, HPDQM5_MARK, HPDQM4_MARK,
+ IRQ0_MARK, IRQ1_MARK, IRQ2_MARK, IRQ3_MARK,
+ IRQ4_MARK, IRQ5_MARK, IRQ6_MARK, IRQ7_MARK,
+ SDHICD_MARK, SDHIWP_MARK, SDHID3_MARK, SDHID2_MARK,
+ SDHID1_MARK, SDHID0_MARK, SDHICMD_MARK, SDHICLK_MARK,
+ SIUAOLR_MARK, SIUAOBT_MARK, SIUAISLD_MARK, SIUAILR_MARK,
+ SIUAIBT_MARK, SIUAOSLD_MARK, SIUMCKA_MARK, SIUFCKA_MARK,
+ SIUBOLR_MARK, SIUBOBT_MARK, SIUBISLD_MARK, SIUBILR_MARK,
+ SIUBIBT_MARK, SIUBOSLD_MARK, SIUMCKB_MARK, SIUFCKB_MARK,
+ AUDSYNC_MARK, AUDATA3_MARK, AUDATA2_MARK, AUDATA1_MARK, AUDATA0_MARK,
+ DACK_MARK, DREQ0_MARK,
+ DV_CLKI_MARK, DV_CLK_MARK, DV_HSYNC_MARK, DV_VSYNC_MARK,
+ DV_D15_MARK, DV_D14_MARK, DV_D13_MARK, DV_D12_MARK,
+ DV_D11_MARK, DV_D10_MARK, DV_D9_MARK, DV_D8_MARK,
+ DV_D7_MARK, DV_D6_MARK, DV_D5_MARK, DV_D4_MARK,
+ DV_D3_MARK, DV_D2_MARK, DV_D1_MARK, DV_D0_MARK,
+ STATUS0_MARK, PDSTATUS_MARK,
+ SIOF0_MCK_MARK, SIOF0_SCK_MARK,
+ SIOF0_SYNC_MARK, SIOF0_SS1_MARK, SIOF0_SS2_MARK,
+ SIOF0_TXD_MARK, SIOF0_RXD_MARK,
+ SIOF1_MCK_MARK, SIOF1_SCK_MARK,
+ SIOF1_SYNC_MARK, SIOF1_SS1_MARK, SIOF1_SS2_MARK,
+ SIOF1_TXD_MARK, SIOF1_RXD_MARK,
+ SIM_D_MARK, SIM_CLK_MARK, SIM_RST_MARK,
+ TS_SDAT_MARK, TS_SCK_MARK, TS_SDEN_MARK, TS_SPSYNC_MARK,
+ IRDA_IN_MARK, IRDA_OUT_MARK,
+ TPUTO_MARK,
+ FCE_MARK, NAF7_MARK, NAF6_MARK, NAF5_MARK, NAF4_MARK,
+ NAF3_MARK, NAF2_MARK, NAF1_MARK, NAF0_MARK, FCDE_MARK,
+ FOE_MARK, FSC_MARK, FWE_MARK, FRB_MARK,
+ KEYIN0_MARK, KEYIN1_MARK, KEYIN2_MARK, KEYIN3_MARK, KEYIN4_MARK,
+ KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK,
+ KEYOUT4_IN6_MARK, KEYOUT5_IN5_MARK,
+ PINMUX_MARK_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ VIO_D7_SCIF1_SCK, VIO_D6_SCIF1_RXD, VIO_D5_SCIF1_TXD, VIO_D4,
+ VIO_D3, VIO_D2, VIO_D1, VIO_D0_LCDLCLK,
+ HPD55, HPD54, HPD53, HPD52, HPD51, HPD50, HPD49, HPD48,
+ IOIS16, HPDQM7, HPDQM6, HPDQM5, HPDQM4,
+ SDHICD, SDHIWP, SDHID3, IRQ2_SDHID2, SDHID1, SDHID0, SDHICMD, SDHICLK,
+ A25, A24, A23, A22, IRQ5, IRQ4_BS,
+ PTF6, SIOSCK_SIUBOBT, SIOSTRB1_SIUBOLR,
+ SIOSTRB0_SIUBIBT, SIOD_SIUBILR, SIORXD_SIUBISLD, SIOTXD_SIUBOSLD,
+ AUDSYNC, AUDATA3, AUDATA2, AUDATA1, AUDATA0,
+ LCDVCPWC_LCDVCPWC2, LCDVSYN2_DACK, LCDVSYN, LCDDISP_LCDRS,
+ LCDHSYN_LCDCS, LCDDON_LCDDON2, LCDD17_DV_HSYNC, LCDD16_DV_VSYNC,
+ STATUS0, PDSTATUS, IRQ1, IRQ0,
+ SIUAILR_SIOF1_SS2, SIUAIBT_SIOF1_SS1, SIUAOLR_SIOF1_SYNC,
+ SIUAOBT_SIOF1_SCK, SIUAISLD_SIOF1_RXD, SIUAOSLD_SIOF1_TXD, PTK0,
+ LCDD15_DV_D15, LCDD14_DV_D14, LCDD13_DV_D13, LCDD12_DV_D12,
+ LCDD11_DV_D11, LCDD10_DV_D10, LCDD9_DV_D9, LCDD8_DV_D8,
+ LCDD7_DV_D7, LCDD6_DV_D6, LCDD5_DV_D5, LCDD4_DV_D4,
+ LCDD3_DV_D3, LCDD2_DV_D2, LCDD1_DV_D1, LCDD0_DV_D0,
+ HPD63, HPD62, HPD61, HPD60, HPD59, HPD58, HPD57, HPD56,
+ SIOF0_SS2_SIM_RST, SIOF0_SS1_TS_SPSYNC, SIOF0_SYNC_TS_SDEN,
+ SIOF0_SCK_TS_SCK, PTQ2, PTQ1, PTQ0,
+ LCDRD, CS6B_CE1B_LCDCS2, WAIT, LCDDCK_LCDWR, LCDVEPWC_LCDVEPWC2,
+ SCIF0_CTS_SIUAISPD, SCIF0_RTS_SIUAOSPD,
+ SCIF0_SCK_TPUTO, SCIF0_RXD, SCIF0_TXD,
+ FOE_VIO_VD2, FWE, FSC, DREQ0, FCDE,
+ NAF2_VIO_D10, NAF1_VIO_D9, NAF0_VIO_D8,
+ FRB_VIO_CLK2, FCE_VIO_HD2,
+ NAF7_VIO_D15, NAF6_VIO_D14, NAF5_VIO_D13, NAF4_VIO_D12, NAF3_VIO_D11,
+ VIO_FLD_SCIF2_CTS, VIO_CKO_SCIF2_RTS, VIO_STEX_SCIF2_SCK,
+ VIO_STEM_SCIF2_TXD, VIO_HD_SCIF2_RXD,
+ VIO_VD_SCIF1_CTS, VIO_CLK_SCIF1_RTS,
+ CS6A_CE2B, LCDD23, LCDD22, LCDD21, LCDD20,
+ LCDD19_DV_CLKI, LCDD18_DV_CLK,
+ KEYOUT5_IN5, KEYOUT4_IN6, KEYOUT3, KEYOUT2, KEYOUT1, KEYOUT0,
+ KEYIN4_IRQ7, KEYIN3, KEYIN2, KEYIN1, KEYIN0_IRQ6,
+
+ PSA15_KEYIN0, PSA15_IRQ6, PSA14_KEYIN4, PSA14_IRQ7,
+ PSA9_IRQ4, PSA9_BS, PSA4_IRQ2, PSA4_SDHID2,
+ PSB15_SIOTXD, PSB15_SIUBOSLD, PSB14_SIORXD, PSB14_SIUBISLD,
+ PSB13_SIOD, PSB13_SIUBILR, PSB12_SIOSTRB0, PSB12_SIUBIBT,
+ PSB11_SIOSTRB1, PSB11_SIUBOLR, PSB10_SIOSCK, PSB10_SIUBOBT,
+ PSB9_SIOMCK, PSB9_SIUMCKB, PSB8_SIOF0_MCK, PSB8_IRQ3,
+ PSB7_SIOF0_TXD, PSB7_IRDA_OUT, PSB6_SIOF0_RXD, PSB6_IRDA_IN,
+ PSB5_SIOF0_SCK, PSB5_TS_SCK, PSB4_SIOF0_SYNC, PSB4_TS_SDEN,
+ PSB3_SIOF0_SS1, PSB3_TS_SPSYNC, PSB2_SIOF0_SS2, PSB2_SIM_RST,
+ PSB1_SIUMCKA, PSB1_SIOF1_MCK, PSB0_SIUAOSLD, PSB0_SIOF1_TXD,
+ PSC15_SIUAISLD, PSC15_SIOF1_RXD, PSC14_SIUAOBT, PSC14_SIOF1_SCK,
+ PSC13_SIUAOLR, PSC13_SIOF1_SYNC, PSC12_SIUAIBT, PSC12_SIOF1_SS1,
+ PSC11_SIUAILR, PSC11_SIOF1_SS2, PSC0_NAF, PSC0_VIO,
+ PSD13_VIO, PSD13_SCIF2, PSD12_VIO, PSD12_SCIF1,
+ PSD11_VIO, PSD11_SCIF1, PSD10_VIO_D0, PSD10_LCDLCLK,
+ PSD9_SIOMCK_SIUMCKB, PSD9_SIUFCKB, PSD8_SCIF0_SCK, PSD8_TPUTO,
+ PSD7_SCIF0_RTS, PSD7_SIUAOSPD, PSD6_SCIF0_CTS, PSD6_SIUAISPD,
+ PSD5_CS6B_CE1B, PSD5_LCDCS2,
+ PSD3_LCDVEPWC_LCDVCPWC, PSD3_LCDVEPWC2_LCDVCPWC2,
+ PSD2_LCDDON, PSD2_LCDDON2, PSD0_LCDD19_LCDD0, PSD0_DV,
+ PSE15_SIOF0_MCK_IRQ3, PSE15_SIM_D,
+ PSE14_SIOF0_TXD_IRDA_OUT, PSE14_SIM_CLK,
+ PSE13_SIOF0_RXD_IRDA_IN, PSE13_TS_SDAT, PSE12_LCDVSYN2, PSE12_DACK,
+ PSE11_SIUMCKA_SIOF1_MCK, PSE11_SIUFCKA,
+ PSE3_FLCTL, PSE3_VIO, PSE2_NAF2, PSE2_VIO_D10,
+ PSE1_NAF1, PSE1_VIO_D9, PSE0_NAF0, PSE0_VIO_D8,
+
+ HIZA14_KEYSC, HIZA14_HIZ,
+ HIZA10_NAF, HIZA10_HIZ,
+ HIZA9_VIO, HIZA9_HIZ,
+ HIZA8_LCDC, HIZA8_HIZ,
+ HIZA7_LCDC, HIZA7_HIZ,
+ HIZA6_LCDC, HIZA6_HIZ,
+ HIZB4_SIUA, HIZB4_HIZ,
+ HIZB1_VIO, HIZB1_HIZ,
+ HIZB0_VIO, HIZB0_HIZ,
+ HIZC15_IRQ7, HIZC15_HIZ,
+ HIZC14_IRQ6, HIZC14_HIZ,
+ HIZC13_IRQ5, HIZC13_HIZ,
+ HIZC12_IRQ4, HIZC12_HIZ,
+ HIZC11_IRQ3, HIZC11_HIZ,
+ HIZC10_IRQ2, HIZC10_HIZ,
+ HIZC9_IRQ1, HIZC9_HIZ,
+ HIZC8_IRQ0, HIZC8_HIZ,
+ MSELB9_VIO, MSELB9_VIO2,
+ MSELB8_RGB, MSELB8_SYS,
+ PINMUX_FUNCTION_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+ /* PTA */
+ PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_IN_PD, PTA7_OUT),
+ PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_IN_PD),
+ PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_IN_PD, PTA5_OUT),
+ PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_IN_PD),
+ PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_IN_PD),
+ PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_IN_PD),
+ PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_IN_PD),
+ PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_IN_PD),
+
+ /* PTB */
+ PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT),
+ PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT),
+ PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT),
+ PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT),
+ PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT),
+ PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT),
+ PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT),
+ PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT),
+
+ /* PTC */
+ PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_IN_PU),
+ PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_IN_PU),
+ PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT),
+ PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT),
+ PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT),
+ PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT),
+
+ /* PTD */
+ PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_IN_PU),
+ PINMUX_DATA(PTD6_DATA, PTD6_OUT, PTD6_IN, PTD6_IN_PU),
+ PINMUX_DATA(PTD5_DATA, PTD5_OUT, PTD5_IN, PTD5_IN_PU),
+ PINMUX_DATA(PTD4_DATA, PTD4_OUT, PTD4_IN, PTD4_IN_PU),
+ PINMUX_DATA(PTD3_DATA, PTD3_OUT, PTD3_IN, PTD3_IN_PU),
+ PINMUX_DATA(PTD2_DATA, PTD2_OUT, PTD2_IN, PTD2_IN_PU),
+ PINMUX_DATA(PTD1_DATA, PTD1_OUT, PTD1_IN, PTD1_IN_PU),
+ PINMUX_DATA(PTD0_DATA, PTD0_OUT),
+
+ /* PTE */
+ PINMUX_DATA(PTE7_DATA, PTE7_OUT, PTE7_IN, PTE7_IN_PD),
+ PINMUX_DATA(PTE6_DATA, PTE6_OUT, PTE6_IN, PTE6_IN_PD),
+ PINMUX_DATA(PTE5_DATA, PTE5_OUT, PTE5_IN, PTE5_IN_PD),
+ PINMUX_DATA(PTE4_DATA, PTE4_OUT, PTE4_IN, PTE4_IN_PD),
+ PINMUX_DATA(PTE1_DATA, PTE1_OUT, PTE1_IN, PTE1_IN_PD),
+ PINMUX_DATA(PTE0_DATA, PTE0_OUT, PTE0_IN, PTE0_IN_PD),
+
+ /* PTF */
+ PINMUX_DATA(PTF6_DATA, PTF6_OUT, PTF6_IN, PTF6_IN_PD),
+ PINMUX_DATA(PTF5_DATA, PTF5_OUT, PTF5_IN, PTF5_IN_PD),
+ PINMUX_DATA(PTF4_DATA, PTF4_OUT, PTF4_IN, PTF4_IN_PD),
+ PINMUX_DATA(PTF3_DATA, PTF3_OUT, PTF3_IN, PTF3_IN_PD),
+ PINMUX_DATA(PTF2_DATA, PTF2_OUT, PTF2_IN, PTF2_IN_PD),
+ PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_IN_PD),
+ PINMUX_DATA(PTF0_DATA, PTF0_OUT),
+
+ /* PTG */
+ PINMUX_DATA(PTG4_DATA, PTG4_OUT),
+ PINMUX_DATA(PTG3_DATA, PTG3_OUT),
+ PINMUX_DATA(PTG2_DATA, PTG2_OUT),
+ PINMUX_DATA(PTG1_DATA, PTG1_OUT),
+ PINMUX_DATA(PTG0_DATA, PTG0_OUT),
+
+ /* PTH */
+ PINMUX_DATA(PTH7_DATA, PTH7_OUT),
+ PINMUX_DATA(PTH6_DATA, PTH6_OUT, PTH6_IN, PTH6_IN_PD),
+ PINMUX_DATA(PTH5_DATA, PTH5_OUT, PTH5_IN, PTH5_IN_PD),
+ PINMUX_DATA(PTH4_DATA, PTH4_OUT),
+ PINMUX_DATA(PTH3_DATA, PTH3_OUT),
+ PINMUX_DATA(PTH2_DATA, PTH2_OUT),
+ PINMUX_DATA(PTH1_DATA, PTH1_OUT, PTH1_IN, PTH1_IN_PD),
+ PINMUX_DATA(PTH0_DATA, PTH0_OUT, PTH0_IN, PTH0_IN_PD),
+
+ /* PTJ */
+ PINMUX_DATA(PTJ7_DATA, PTJ7_OUT),
+ PINMUX_DATA(PTJ6_DATA, PTJ6_OUT),
+ PINMUX_DATA(PTJ5_DATA, PTJ5_OUT),
+ PINMUX_DATA(PTJ1_DATA, PTJ1_OUT, PTJ1_IN, PTJ1_IN_PU),
+ PINMUX_DATA(PTJ0_DATA, PTJ0_OUT, PTJ0_IN, PTJ0_IN_PU),
+
+ /* PTK */
+ PINMUX_DATA(PTK6_DATA, PTK6_OUT, PTK6_IN, PTK6_IN_PD),
+ PINMUX_DATA(PTK5_DATA, PTK5_OUT, PTK5_IN, PTK5_IN_PD),
+ PINMUX_DATA(PTK4_DATA, PTK4_OUT, PTK4_IN, PTK4_IN_PD),
+ PINMUX_DATA(PTK3_DATA, PTK3_OUT, PTK3_IN, PTK3_IN_PD),
+ PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_IN_PD),
+ PINMUX_DATA(PTK1_DATA, PTK1_OUT),
+ PINMUX_DATA(PTK0_DATA, PTK0_OUT, PTK0_IN, PTK0_IN_PD),
+
+ /* PTL */
+ PINMUX_DATA(PTL7_DATA, PTL7_OUT, PTL7_IN, PTL7_IN_PD),
+ PINMUX_DATA(PTL6_DATA, PTL6_OUT, PTL6_IN, PTL6_IN_PD),
+ PINMUX_DATA(PTL5_DATA, PTL5_OUT, PTL5_IN, PTL5_IN_PD),
+ PINMUX_DATA(PTL4_DATA, PTL4_OUT, PTL4_IN, PTL4_IN_PD),
+ PINMUX_DATA(PTL3_DATA, PTL3_OUT, PTL3_IN, PTL3_IN_PD),
+ PINMUX_DATA(PTL2_DATA, PTL2_OUT, PTL2_IN, PTL2_IN_PD),
+ PINMUX_DATA(PTL1_DATA, PTL1_OUT, PTL1_IN, PTL1_IN_PD),
+ PINMUX_DATA(PTL0_DATA, PTL0_OUT, PTL0_IN, PTL0_IN_PD),
+
+ /* PTM */
+ PINMUX_DATA(PTM7_DATA, PTM7_OUT, PTM7_IN, PTM7_IN_PD),
+ PINMUX_DATA(PTM6_DATA, PTM6_OUT, PTM6_IN, PTM6_IN_PD),
+ PINMUX_DATA(PTM5_DATA, PTM5_OUT, PTM5_IN, PTM5_IN_PD),
+ PINMUX_DATA(PTM4_DATA, PTM4_OUT, PTM4_IN, PTM4_IN_PD),
+ PINMUX_DATA(PTM3_DATA, PTM3_OUT, PTM3_IN, PTM3_IN_PD),
+ PINMUX_DATA(PTM2_DATA, PTM2_OUT, PTM2_IN, PTM2_IN_PD),
+ PINMUX_DATA(PTM1_DATA, PTM1_OUT, PTM1_IN, PTM1_IN_PD),
+ PINMUX_DATA(PTM0_DATA, PTM0_OUT, PTM0_IN, PTM0_IN_PD),
+
+ /* PTN */
+ PINMUX_DATA(PTN7_DATA, PTN7_OUT, PTN7_IN),
+ PINMUX_DATA(PTN6_DATA, PTN6_OUT, PTN6_IN),
+ PINMUX_DATA(PTN5_DATA, PTN5_OUT, PTN5_IN),
+ PINMUX_DATA(PTN4_DATA, PTN4_OUT, PTN4_IN),
+ PINMUX_DATA(PTN3_DATA, PTN3_OUT, PTN3_IN),
+ PINMUX_DATA(PTN2_DATA, PTN2_OUT, PTN2_IN),
+ PINMUX_DATA(PTN1_DATA, PTN1_OUT, PTN1_IN),
+ PINMUX_DATA(PTN0_DATA, PTN0_OUT, PTN0_IN),
+
+ /* PTQ */
+ PINMUX_DATA(PTQ6_DATA, PTQ6_OUT),
+ PINMUX_DATA(PTQ5_DATA, PTQ5_OUT, PTQ5_IN, PTQ5_IN_PD),
+ PINMUX_DATA(PTQ4_DATA, PTQ4_OUT, PTQ4_IN, PTQ4_IN_PD),
+ PINMUX_DATA(PTQ3_DATA, PTQ3_OUT, PTQ3_IN, PTQ3_IN_PD),
+ PINMUX_DATA(PTQ2_DATA, PTQ2_IN, PTQ2_IN_PD),
+ PINMUX_DATA(PTQ1_DATA, PTQ1_OUT),
+ PINMUX_DATA(PTQ0_DATA, PTQ0_OUT, PTQ0_IN, PTQ0_IN_PU),
+
+ /* PTR */
+ PINMUX_DATA(PTR4_DATA, PTR4_OUT),
+ PINMUX_DATA(PTR3_DATA, PTR3_OUT),
+ PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_IN_PU),
+ PINMUX_DATA(PTR1_DATA, PTR1_OUT),
+ PINMUX_DATA(PTR0_DATA, PTR0_OUT),
+
+ /* PTS */
+ PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_IN_PD),
+ PINMUX_DATA(PTS3_DATA, PTS3_OUT),
+ PINMUX_DATA(PTS2_DATA, PTS2_OUT, PTS2_IN, PTS2_IN_PD),
+ PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_IN_PD),
+ PINMUX_DATA(PTS0_DATA, PTS0_OUT),
+
+ /* PTT */
+ PINMUX_DATA(PTT4_DATA, PTT4_OUT, PTT4_IN, PTT4_IN_PD),
+ PINMUX_DATA(PTT3_DATA, PTT3_OUT, PTT3_IN, PTT3_IN_PD),
+ PINMUX_DATA(PTT2_DATA, PTT2_OUT, PTT2_IN, PTT2_IN_PD),
+ PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_IN_PD),
+ PINMUX_DATA(PTT0_DATA, PTT0_OUT),
+
+ /* PTU */
+ PINMUX_DATA(PTU4_DATA, PTU4_OUT, PTU4_IN, PTU4_IN_PD),
+ PINMUX_DATA(PTU3_DATA, PTU3_OUT, PTU3_IN, PTU3_IN_PD),
+ PINMUX_DATA(PTU2_DATA, PTU2_OUT, PTU2_IN, PTU2_IN_PD),
+ PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_IN_PD),
+ PINMUX_DATA(PTU0_DATA, PTU0_OUT, PTU0_IN, PTU0_IN_PD),
+
+ /* PTV */
+ PINMUX_DATA(PTV4_DATA, PTV4_OUT, PTV4_IN, PTV4_IN_PD),
+ PINMUX_DATA(PTV3_DATA, PTV3_OUT, PTV3_IN, PTV3_IN_PD),
+ PINMUX_DATA(PTV2_DATA, PTV2_OUT, PTV2_IN, PTV2_IN_PD),
+ PINMUX_DATA(PTV1_DATA, PTV1_OUT, PTV1_IN, PTV1_IN_PD),
+ PINMUX_DATA(PTV0_DATA, PTV0_OUT, PTV0_IN, PTV0_IN_PD),
+
+ /* PTW */
+ PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_IN_PD),
+ PINMUX_DATA(PTW5_DATA, PTW5_OUT),
+ PINMUX_DATA(PTW4_DATA, PTW4_OUT, PTW4_IN, PTW4_IN_PD),
+ PINMUX_DATA(PTW3_DATA, PTW3_OUT, PTW3_IN, PTW3_IN_PD),
+ PINMUX_DATA(PTW2_DATA, PTW2_OUT, PTW2_IN, PTW2_IN_PD),
+ PINMUX_DATA(PTW1_DATA, PTW1_OUT, PTW1_IN, PTW1_IN_PD),
+ PINMUX_DATA(PTW0_DATA, PTW0_OUT, PTW0_IN, PTW0_IN_PD),
+
+ /* PTX */
+ PINMUX_DATA(PTX6_DATA, PTX6_OUT, PTX6_IN, PTX6_IN_PD),
+ PINMUX_DATA(PTX5_DATA, PTX5_OUT, PTX5_IN, PTX5_IN_PD),
+ PINMUX_DATA(PTX4_DATA, PTX4_OUT, PTX4_IN, PTX4_IN_PD),
+ PINMUX_DATA(PTX3_DATA, PTX3_OUT, PTX3_IN, PTX3_IN_PD),
+ PINMUX_DATA(PTX2_DATA, PTX2_OUT, PTX2_IN, PTX2_IN_PD),
+ PINMUX_DATA(PTX1_DATA, PTX1_OUT, PTX1_IN, PTX1_IN_PD),
+ PINMUX_DATA(PTX0_DATA, PTX0_OUT, PTX0_IN, PTX0_IN_PD),
+
+ /* PTY */
+ PINMUX_DATA(PTY5_DATA, PTY5_OUT, PTY5_IN, PTY5_IN_PU),
+ PINMUX_DATA(PTY4_DATA, PTY4_OUT, PTY4_IN, PTY4_IN_PU),
+ PINMUX_DATA(PTY3_DATA, PTY3_OUT, PTY3_IN, PTY3_IN_PU),
+ PINMUX_DATA(PTY2_DATA, PTY2_OUT, PTY2_IN, PTY2_IN_PU),
+ PINMUX_DATA(PTY1_DATA, PTY1_OUT),
+ PINMUX_DATA(PTY0_DATA, PTY0_OUT, PTY0_IN, PTY0_IN_PU),
+
+ /* PTZ */
+ PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_IN_PU),
+ PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_IN_PU),
+ PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_IN_PU),
+ PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_IN_PU),
+ PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_IN_PU),
+
+ /* SCIF0 */
+ PINMUX_DATA(SCIF0_TXD_MARK, SCIF0_TXD),
+ PINMUX_DATA(SCIF0_RXD_MARK, SCIF0_RXD),
+ PINMUX_DATA(SCIF0_RTS_MARK, PSD7_SCIF0_RTS, SCIF0_RTS_SIUAOSPD),
+ PINMUX_DATA(SCIF0_CTS_MARK, PSD6_SCIF0_CTS, SCIF0_CTS_SIUAISPD),
+ PINMUX_DATA(SCIF0_SCK_MARK, PSD8_SCIF0_SCK, SCIF0_SCK_TPUTO),
+
+ /* SCIF1 */
+ PINMUX_DATA(SCIF1_TXD_MARK, PSD11_SCIF1, VIO_D5_SCIF1_TXD),
+ PINMUX_DATA(SCIF1_RXD_MARK, PSD11_SCIF1, VIO_D6_SCIF1_RXD),
+ PINMUX_DATA(SCIF1_RTS_MARK, PSD12_SCIF1, VIO_CLK_SCIF1_RTS),
+ PINMUX_DATA(SCIF1_CTS_MARK, PSD12_SCIF1, VIO_VD_SCIF1_CTS),
+ PINMUX_DATA(SCIF1_SCK_MARK, PSD11_SCIF1, VIO_D7_SCIF1_SCK),
+
+ /* SCIF2 */
+ PINMUX_DATA(SCIF2_TXD_MARK, PSD13_SCIF2, VIO_STEM_SCIF2_TXD),
+ PINMUX_DATA(SCIF2_RXD_MARK, PSD13_SCIF2, VIO_HD_SCIF2_RXD),
+ PINMUX_DATA(SCIF2_RTS_MARK, PSD13_SCIF2, VIO_CKO_SCIF2_RTS),
+ PINMUX_DATA(SCIF2_CTS_MARK, PSD13_SCIF2, VIO_FLD_SCIF2_CTS),
+ PINMUX_DATA(SCIF2_SCK_MARK, PSD13_SCIF2, VIO_STEX_SCIF2_SCK),
+
+ /* SIO */
+ PINMUX_DATA(SIOTXD_MARK, PSB15_SIOTXD, SIOTXD_SIUBOSLD),
+ PINMUX_DATA(SIORXD_MARK, PSB14_SIORXD, SIORXD_SIUBISLD),
+ PINMUX_DATA(SIOD_MARK, PSB13_SIOD, SIOD_SIUBILR),
+ PINMUX_DATA(SIOSTRB0_MARK, PSB12_SIOSTRB0, SIOSTRB0_SIUBIBT),
+ PINMUX_DATA(SIOSTRB1_MARK, PSB11_SIOSTRB1, SIOSTRB1_SIUBOLR),
+ PINMUX_DATA(SIOSCK_MARK, PSB10_SIOSCK, SIOSCK_SIUBOBT),
+ PINMUX_DATA(SIOMCK_MARK, PSD9_SIOMCK_SIUMCKB, PSB9_SIOMCK, PTF6),
+
+ /* CEU */
+ PINMUX_DATA(VIO_D15_MARK, PSC0_VIO, HIZA10_NAF, NAF7_VIO_D15),
+ PINMUX_DATA(VIO_D14_MARK, PSC0_VIO, HIZA10_NAF, NAF6_VIO_D14),
+ PINMUX_DATA(VIO_D13_MARK, PSC0_VIO, HIZA10_NAF, NAF5_VIO_D13),
+ PINMUX_DATA(VIO_D12_MARK, PSC0_VIO, HIZA10_NAF, NAF4_VIO_D12),
+ PINMUX_DATA(VIO_D11_MARK, PSC0_VIO, HIZA10_NAF, NAF3_VIO_D11),
+ PINMUX_DATA(VIO_D10_MARK, PSE2_VIO_D10, HIZB0_VIO, NAF2_VIO_D10),
+ PINMUX_DATA(VIO_D9_MARK, PSE1_VIO_D9, HIZB0_VIO, NAF1_VIO_D9),
+ PINMUX_DATA(VIO_D8_MARK, PSE0_VIO_D8, HIZB0_VIO, NAF0_VIO_D8),
+ PINMUX_DATA(VIO_D7_MARK, PSD11_VIO, VIO_D7_SCIF1_SCK),
+ PINMUX_DATA(VIO_D6_MARK, PSD11_VIO, VIO_D6_SCIF1_RXD),
+ PINMUX_DATA(VIO_D5_MARK, PSD11_VIO, VIO_D5_SCIF1_TXD),
+ PINMUX_DATA(VIO_D4_MARK, VIO_D4),
+ PINMUX_DATA(VIO_D3_MARK, VIO_D3),
+ PINMUX_DATA(VIO_D2_MARK, VIO_D2),
+ PINMUX_DATA(VIO_D1_MARK, VIO_D1),
+ PINMUX_DATA(VIO_D0_MARK, PSD10_VIO_D0, VIO_D0_LCDLCLK),
+ PINMUX_DATA(VIO_CLK_MARK, PSD12_VIO, MSELB9_VIO, VIO_CLK_SCIF1_RTS),
+ PINMUX_DATA(VIO_VD_MARK, PSD12_VIO, MSELB9_VIO, VIO_VD_SCIF1_CTS),
+ PINMUX_DATA(VIO_HD_MARK, PSD13_VIO, MSELB9_VIO, VIO_HD_SCIF2_RXD),
+ PINMUX_DATA(VIO_FLD_MARK, PSD13_VIO, HIZA9_VIO, VIO_FLD_SCIF2_CTS),
+ PINMUX_DATA(VIO_CKO_MARK, PSD13_VIO, HIZA9_VIO, VIO_CKO_SCIF2_RTS),
+ PINMUX_DATA(VIO_STEX_MARK, PSD13_VIO, HIZA9_VIO, VIO_STEX_SCIF2_SCK),
+ PINMUX_DATA(VIO_STEM_MARK, PSD13_VIO, HIZA9_VIO, VIO_STEM_SCIF2_TXD),
+ PINMUX_DATA(VIO_VD2_MARK, PSE3_VIO, MSELB9_VIO2,
+ HIZB0_VIO, FOE_VIO_VD2),
+ PINMUX_DATA(VIO_HD2_MARK, PSE3_VIO, MSELB9_VIO2,
+ HIZB1_VIO, FCE_VIO_HD2),
+ PINMUX_DATA(VIO_CLK2_MARK, PSE3_VIO, MSELB9_VIO2,
+ HIZB1_VIO, FRB_VIO_CLK2),
+
+ /* LCDC */
+ PINMUX_DATA(LCDD23_MARK, HIZA8_LCDC, LCDD23),
+ PINMUX_DATA(LCDD22_MARK, HIZA8_LCDC, LCDD22),
+ PINMUX_DATA(LCDD21_MARK, HIZA8_LCDC, LCDD21),
+ PINMUX_DATA(LCDD20_MARK, HIZA8_LCDC, LCDD20),
+ PINMUX_DATA(LCDD19_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD19_DV_CLKI),
+ PINMUX_DATA(LCDD18_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD18_DV_CLK),
+ PINMUX_DATA(LCDD17_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC,
+ LCDD17_DV_HSYNC),
+ PINMUX_DATA(LCDD16_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC,
+ LCDD16_DV_VSYNC),
+ PINMUX_DATA(LCDD15_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD15_DV_D15),
+ PINMUX_DATA(LCDD14_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD14_DV_D14),
+ PINMUX_DATA(LCDD13_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD13_DV_D13),
+ PINMUX_DATA(LCDD12_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD12_DV_D12),
+ PINMUX_DATA(LCDD11_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD11_DV_D11),
+ PINMUX_DATA(LCDD10_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD10_DV_D10),
+ PINMUX_DATA(LCDD9_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD9_DV_D9),
+ PINMUX_DATA(LCDD8_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD8_DV_D8),
+ PINMUX_DATA(LCDD7_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD7_DV_D7),
+ PINMUX_DATA(LCDD6_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD6_DV_D6),
+ PINMUX_DATA(LCDD5_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD5_DV_D5),
+ PINMUX_DATA(LCDD4_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD4_DV_D4),
+ PINMUX_DATA(LCDD3_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD3_DV_D3),
+ PINMUX_DATA(LCDD2_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD2_DV_D2),
+ PINMUX_DATA(LCDD1_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD1_DV_D1),
+ PINMUX_DATA(LCDD0_MARK, PSD0_LCDD19_LCDD0, HIZA8_LCDC, LCDD0_DV_D0),
+ PINMUX_DATA(LCDLCLK_MARK, PSD10_LCDLCLK, VIO_D0_LCDLCLK),
+ /* Main LCD */
+ PINMUX_DATA(LCDDON_MARK, PSD2_LCDDON, HIZA7_LCDC, LCDDON_LCDDON2),
+ PINMUX_DATA(LCDVCPWC_MARK, PSD3_LCDVEPWC_LCDVCPWC,
+ HIZA6_LCDC, LCDVCPWC_LCDVCPWC2),
+ PINMUX_DATA(LCDVEPWC_MARK, PSD3_LCDVEPWC_LCDVCPWC,
+ HIZA6_LCDC, LCDVEPWC_LCDVEPWC2),
+ PINMUX_DATA(LCDVSYN_MARK, HIZA7_LCDC, LCDVSYN),
+ /* Main LCD - RGB Mode */
+ PINMUX_DATA(LCDDCK_MARK, MSELB8_RGB, HIZA8_LCDC, LCDDCK_LCDWR),
+ PINMUX_DATA(LCDHSYN_MARK, MSELB8_RGB, HIZA7_LCDC, LCDHSYN_LCDCS),
+ PINMUX_DATA(LCDDISP_MARK, MSELB8_RGB, HIZA7_LCDC, LCDDISP_LCDRS),
+ /* Main LCD - SYS Mode */
+ PINMUX_DATA(LCDRS_MARK, MSELB8_SYS, HIZA7_LCDC, LCDDISP_LCDRS),
+ PINMUX_DATA(LCDCS_MARK, MSELB8_SYS, HIZA7_LCDC, LCDHSYN_LCDCS),
+ PINMUX_DATA(LCDWR_MARK, MSELB8_SYS, HIZA8_LCDC, LCDDCK_LCDWR),
+ PINMUX_DATA(LCDRD_MARK, HIZA7_LCDC, LCDRD),
+ /* Sub LCD - SYS Mode */
+ PINMUX_DATA(LCDDON2_MARK, PSD2_LCDDON2, HIZA7_LCDC, LCDDON_LCDDON2),
+ PINMUX_DATA(LCDVCPWC2_MARK, PSD3_LCDVEPWC2_LCDVCPWC2,
+ HIZA6_LCDC, LCDVCPWC_LCDVCPWC2),
+ PINMUX_DATA(LCDVEPWC2_MARK, PSD3_LCDVEPWC2_LCDVCPWC2,
+ HIZA6_LCDC, LCDVEPWC_LCDVEPWC2),
+ PINMUX_DATA(LCDVSYN2_MARK, PSE12_LCDVSYN2, HIZA8_LCDC, LCDVSYN2_DACK),
+ PINMUX_DATA(LCDCS2_MARK, PSD5_LCDCS2, CS6B_CE1B_LCDCS2),
+
+ /* BSC */
+ PINMUX_DATA(IOIS16_MARK, IOIS16),
+ PINMUX_DATA(A25_MARK, A25),
+ PINMUX_DATA(A24_MARK, A24),
+ PINMUX_DATA(A23_MARK, A23),
+ PINMUX_DATA(A22_MARK, A22),
+ PINMUX_DATA(BS_MARK, PSA9_BS, IRQ4_BS),
+ PINMUX_DATA(CS6B_CE1B_MARK, PSD5_CS6B_CE1B, CS6B_CE1B_LCDCS2),
+ PINMUX_DATA(WAIT_MARK, WAIT),
+ PINMUX_DATA(CS6A_CE2B_MARK, CS6A_CE2B),
+
+ /* SBSC */
+ PINMUX_DATA(HPD63_MARK, HPD63),
+ PINMUX_DATA(HPD62_MARK, HPD62),
+ PINMUX_DATA(HPD61_MARK, HPD61),
+ PINMUX_DATA(HPD60_MARK, HPD60),
+ PINMUX_DATA(HPD59_MARK, HPD59),
+ PINMUX_DATA(HPD58_MARK, HPD58),
+ PINMUX_DATA(HPD57_MARK, HPD57),
+ PINMUX_DATA(HPD56_MARK, HPD56),
+ PINMUX_DATA(HPD55_MARK, HPD55),
+ PINMUX_DATA(HPD54_MARK, HPD54),
+ PINMUX_DATA(HPD53_MARK, HPD53),
+ PINMUX_DATA(HPD52_MARK, HPD52),
+ PINMUX_DATA(HPD51_MARK, HPD51),
+ PINMUX_DATA(HPD50_MARK, HPD50),
+ PINMUX_DATA(HPD49_MARK, HPD49),
+ PINMUX_DATA(HPD48_MARK, HPD48),
+ PINMUX_DATA(HPDQM7_MARK, HPDQM7),
+ PINMUX_DATA(HPDQM6_MARK, HPDQM6),
+ PINMUX_DATA(HPDQM5_MARK, HPDQM5),
+ PINMUX_DATA(HPDQM4_MARK, HPDQM4),
+
+ /* IRQ */
+ PINMUX_DATA(IRQ0_MARK, HIZC8_IRQ0, IRQ0),
+ PINMUX_DATA(IRQ1_MARK, HIZC9_IRQ1, IRQ1),
+ PINMUX_DATA(IRQ2_MARK, PSA4_IRQ2, HIZC10_IRQ2, IRQ2_SDHID2),
+ PINMUX_DATA(IRQ3_MARK, PSE15_SIOF0_MCK_IRQ3, PSB8_IRQ3,
+ HIZC11_IRQ3, PTQ0),
+ PINMUX_DATA(IRQ4_MARK, PSA9_IRQ4, HIZC12_IRQ4, IRQ4_BS),
+ PINMUX_DATA(IRQ5_MARK, HIZC13_IRQ5, IRQ5),
+ PINMUX_DATA(IRQ6_MARK, PSA15_IRQ6, HIZC14_IRQ6, KEYIN0_IRQ6),
+ PINMUX_DATA(IRQ7_MARK, PSA14_IRQ7, HIZC15_IRQ7, KEYIN4_IRQ7),
+
+ /* SDHI */
+ PINMUX_DATA(SDHICD_MARK, SDHICD),
+ PINMUX_DATA(SDHIWP_MARK, SDHIWP),
+ PINMUX_DATA(SDHID3_MARK, SDHID3),
+ PINMUX_DATA(SDHID2_MARK, PSA4_SDHID2, IRQ2_SDHID2),
+ PINMUX_DATA(SDHID1_MARK, SDHID1),
+ PINMUX_DATA(SDHID0_MARK, SDHID0),
+ PINMUX_DATA(SDHICMD_MARK, SDHICMD),
+ PINMUX_DATA(SDHICLK_MARK, SDHICLK),
+
+ /* SIU - Port A */
+ PINMUX_DATA(SIUAOLR_MARK, PSC13_SIUAOLR, HIZB4_SIUA, SIUAOLR_SIOF1_SYNC),
+ PINMUX_DATA(SIUAOBT_MARK, PSC14_SIUAOBT, HIZB4_SIUA, SIUAOBT_SIOF1_SCK),
+ PINMUX_DATA(SIUAISLD_MARK, PSC15_SIUAISLD, HIZB4_SIUA, SIUAISLD_SIOF1_RXD),
+ PINMUX_DATA(SIUAILR_MARK, PSC11_SIUAILR, HIZB4_SIUA, SIUAILR_SIOF1_SS2),
+ PINMUX_DATA(SIUAIBT_MARK, PSC12_SIUAIBT, HIZB4_SIUA, SIUAIBT_SIOF1_SS1),
+ PINMUX_DATA(SIUAOSLD_MARK, PSB0_SIUAOSLD, HIZB4_SIUA, SIUAOSLD_SIOF1_TXD),
+ PINMUX_DATA(SIUMCKA_MARK, PSE11_SIUMCKA_SIOF1_MCK, HIZB4_SIUA, PSB1_SIUMCKA, PTK0),
+ PINMUX_DATA(SIUFCKA_MARK, PSE11_SIUFCKA, HIZB4_SIUA, PTK0),
+
+ /* SIU - Port B */
+ PINMUX_DATA(SIUBOLR_MARK, PSB11_SIUBOLR, SIOSTRB1_SIUBOLR),
+ PINMUX_DATA(SIUBOBT_MARK, PSB10_SIUBOBT, SIOSCK_SIUBOBT),
+ PINMUX_DATA(SIUBISLD_MARK, PSB14_SIUBISLD, SIORXD_SIUBISLD),
+ PINMUX_DATA(SIUBILR_MARK, PSB13_SIUBILR, SIOD_SIUBILR),
+ PINMUX_DATA(SIUBIBT_MARK, PSB12_SIUBIBT, SIOSTRB0_SIUBIBT),
+ PINMUX_DATA(SIUBOSLD_MARK, PSB15_SIUBOSLD, SIOTXD_SIUBOSLD),
+ PINMUX_DATA(SIUMCKB_MARK, PSD9_SIOMCK_SIUMCKB, PSB9_SIUMCKB, PTF6),
+ PINMUX_DATA(SIUFCKB_MARK, PSD9_SIUFCKB, PTF6),
+
+ /* AUD */
+ PINMUX_DATA(AUDSYNC_MARK, AUDSYNC),
+ PINMUX_DATA(AUDATA3_MARK, AUDATA3),
+ PINMUX_DATA(AUDATA2_MARK, AUDATA2),
+ PINMUX_DATA(AUDATA1_MARK, AUDATA1),
+ PINMUX_DATA(AUDATA0_MARK, AUDATA0),
+
+ /* DMAC */
+ PINMUX_DATA(DACK_MARK, PSE12_DACK, LCDVSYN2_DACK),
+ PINMUX_DATA(DREQ0_MARK, DREQ0),
+
+ /* VOU */
+ PINMUX_DATA(DV_CLKI_MARK, PSD0_DV, LCDD19_DV_CLKI),
+ PINMUX_DATA(DV_CLK_MARK, PSD0_DV, LCDD18_DV_CLK),
+ PINMUX_DATA(DV_HSYNC_MARK, PSD0_DV, LCDD17_DV_HSYNC),
+ PINMUX_DATA(DV_VSYNC_MARK, PSD0_DV, LCDD16_DV_VSYNC),
+ PINMUX_DATA(DV_D15_MARK, PSD0_DV, LCDD15_DV_D15),
+ PINMUX_DATA(DV_D14_MARK, PSD0_DV, LCDD14_DV_D14),
+ PINMUX_DATA(DV_D13_MARK, PSD0_DV, LCDD13_DV_D13),
+ PINMUX_DATA(DV_D12_MARK, PSD0_DV, LCDD12_DV_D12),
+ PINMUX_DATA(DV_D11_MARK, PSD0_DV, LCDD11_DV_D11),
+ PINMUX_DATA(DV_D10_MARK, PSD0_DV, LCDD10_DV_D10),
+ PINMUX_DATA(DV_D9_MARK, PSD0_DV, LCDD9_DV_D9),
+ PINMUX_DATA(DV_D8_MARK, PSD0_DV, LCDD8_DV_D8),
+ PINMUX_DATA(DV_D7_MARK, PSD0_DV, LCDD7_DV_D7),
+ PINMUX_DATA(DV_D6_MARK, PSD0_DV, LCDD6_DV_D6),
+ PINMUX_DATA(DV_D5_MARK, PSD0_DV, LCDD5_DV_D5),
+ PINMUX_DATA(DV_D4_MARK, PSD0_DV, LCDD4_DV_D4),
+ PINMUX_DATA(DV_D3_MARK, PSD0_DV, LCDD3_DV_D3),
+ PINMUX_DATA(DV_D2_MARK, PSD0_DV, LCDD2_DV_D2),
+ PINMUX_DATA(DV_D1_MARK, PSD0_DV, LCDD1_DV_D1),
+ PINMUX_DATA(DV_D0_MARK, PSD0_DV, LCDD0_DV_D0),
+
+ /* CPG */
+ PINMUX_DATA(STATUS0_MARK, STATUS0),
+ PINMUX_DATA(PDSTATUS_MARK, PDSTATUS),
+
+ /* SIOF0 */
+ PINMUX_DATA(SIOF0_MCK_MARK, PSE15_SIOF0_MCK_IRQ3, PSB8_SIOF0_MCK, PTQ0),
+ PINMUX_DATA(SIOF0_SCK_MARK, PSB5_SIOF0_SCK, SIOF0_SCK_TS_SCK),
+ PINMUX_DATA(SIOF0_SYNC_MARK, PSB4_SIOF0_SYNC, SIOF0_SYNC_TS_SDEN),
+ PINMUX_DATA(SIOF0_SS1_MARK, PSB3_SIOF0_SS1, SIOF0_SS1_TS_SPSYNC),
+ PINMUX_DATA(SIOF0_SS2_MARK, PSB2_SIOF0_SS2, SIOF0_SS2_SIM_RST),
+ PINMUX_DATA(SIOF0_TXD_MARK, PSE14_SIOF0_TXD_IRDA_OUT,
+ PSB7_SIOF0_TXD, PTQ1),
+ PINMUX_DATA(SIOF0_RXD_MARK, PSE13_SIOF0_RXD_IRDA_IN,
+ PSB6_SIOF0_RXD, PTQ2),
+
+ /* SIOF1 */
+ PINMUX_DATA(SIOF1_MCK_MARK, PSE11_SIUMCKA_SIOF1_MCK,
+ PSB1_SIOF1_MCK, PTK0),
+ PINMUX_DATA(SIOF1_SCK_MARK, PSC14_SIOF1_SCK, SIUAOBT_SIOF1_SCK),
+ PINMUX_DATA(SIOF1_SYNC_MARK, PSC13_SIOF1_SYNC, SIUAOLR_SIOF1_SYNC),
+ PINMUX_DATA(SIOF1_SS1_MARK, PSC12_SIOF1_SS1, SIUAIBT_SIOF1_SS1),
+ PINMUX_DATA(SIOF1_SS2_MARK, PSC11_SIOF1_SS2, SIUAILR_SIOF1_SS2),
+ PINMUX_DATA(SIOF1_TXD_MARK, PSB0_SIOF1_TXD, SIUAOSLD_SIOF1_TXD),
+ PINMUX_DATA(SIOF1_RXD_MARK, PSC15_SIOF1_RXD, SIUAISLD_SIOF1_RXD),
+
+ /* SIM */
+ PINMUX_DATA(SIM_D_MARK, PSE15_SIM_D, PTQ0),
+ PINMUX_DATA(SIM_CLK_MARK, PSE14_SIM_CLK, PTQ1),
+ PINMUX_DATA(SIM_RST_MARK, PSB2_SIM_RST, SIOF0_SS2_SIM_RST),
+
+ /* TSIF */
+ PINMUX_DATA(TS_SDAT_MARK, PSE13_TS_SDAT, PTQ2),
+ PINMUX_DATA(TS_SCK_MARK, PSB5_TS_SCK, SIOF0_SCK_TS_SCK),
+ PINMUX_DATA(TS_SDEN_MARK, PSB4_TS_SDEN, SIOF0_SYNC_TS_SDEN),
+ PINMUX_DATA(TS_SPSYNC_MARK, PSB3_TS_SPSYNC, SIOF0_SS1_TS_SPSYNC),
+
+ /* IRDA */
+ PINMUX_DATA(IRDA_IN_MARK, PSE13_SIOF0_RXD_IRDA_IN, PSB6_IRDA_IN, PTQ2),
+ PINMUX_DATA(IRDA_OUT_MARK, PSE14_SIOF0_TXD_IRDA_OUT,
+ PSB7_IRDA_OUT, PTQ1),
+
+ /* TPU */
+ PINMUX_DATA(TPUTO_MARK, PSD8_TPUTO, SCIF0_SCK_TPUTO),
+
+ /* FLCTL */
+ PINMUX_DATA(FCE_MARK, PSE3_FLCTL, FCE_VIO_HD2),
+ PINMUX_DATA(NAF7_MARK, PSC0_NAF, HIZA10_NAF, NAF7_VIO_D15),
+ PINMUX_DATA(NAF6_MARK, PSC0_NAF, HIZA10_NAF, NAF6_VIO_D14),
+ PINMUX_DATA(NAF5_MARK, PSC0_NAF, HIZA10_NAF, NAF5_VIO_D13),
+ PINMUX_DATA(NAF4_MARK, PSC0_NAF, HIZA10_NAF, NAF4_VIO_D12),
+ PINMUX_DATA(NAF3_MARK, PSC0_NAF, HIZA10_NAF, NAF3_VIO_D11),
+ PINMUX_DATA(NAF2_MARK, PSE2_NAF2, HIZB0_VIO, NAF2_VIO_D10),
+ PINMUX_DATA(NAF1_MARK, PSE1_NAF1, HIZB0_VIO, NAF1_VIO_D9),
+ PINMUX_DATA(NAF0_MARK, PSE0_NAF0, HIZB0_VIO, NAF0_VIO_D8),
+ PINMUX_DATA(FCDE_MARK, FCDE),
+ PINMUX_DATA(FOE_MARK, PSE3_FLCTL, HIZB0_VIO, FOE_VIO_VD2),
+ PINMUX_DATA(FSC_MARK, FSC),
+ PINMUX_DATA(FWE_MARK, FWE),
+ PINMUX_DATA(FRB_MARK, PSE3_FLCTL, FRB_VIO_CLK2),
+
+ /* KEYSC */
+ PINMUX_DATA(KEYIN0_MARK, PSA15_KEYIN0, HIZC14_IRQ6, KEYIN0_IRQ6),
+ PINMUX_DATA(KEYIN1_MARK, HIZA14_KEYSC, KEYIN1),
+ PINMUX_DATA(KEYIN2_MARK, HIZA14_KEYSC, KEYIN2),
+ PINMUX_DATA(KEYIN3_MARK, HIZA14_KEYSC, KEYIN3),
+ PINMUX_DATA(KEYIN4_MARK, PSA14_KEYIN4, HIZC15_IRQ7, KEYIN4_IRQ7),
+ PINMUX_DATA(KEYOUT0_MARK, HIZA14_KEYSC, KEYOUT0),
+ PINMUX_DATA(KEYOUT1_MARK, HIZA14_KEYSC, KEYOUT1),
+ PINMUX_DATA(KEYOUT2_MARK, HIZA14_KEYSC, KEYOUT2),
+ PINMUX_DATA(KEYOUT3_MARK, HIZA14_KEYSC, KEYOUT3),
+ PINMUX_DATA(KEYOUT4_IN6_MARK, HIZA14_KEYSC, KEYOUT4_IN6),
+ PINMUX_DATA(KEYOUT5_IN5_MARK, HIZA14_KEYSC, KEYOUT5_IN5),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ /* PTA */
+ PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
+ PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
+ PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
+ PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
+ PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
+ PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
+ PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
+ PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+
+ /* PTB */
+ PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
+ PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
+ PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
+ PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
+ PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
+ PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
+ PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
+ PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+
+ /* PTC */
+ PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
+ PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
+ PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
+ PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
+ PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
+ PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+
+ /* PTD */
+ PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
+ PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
+ PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
+ PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
+ PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
+ PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
+ PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
+ PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+
+ /* PTE */
+ PINMUX_GPIO(GPIO_PTE7, PTE7_DATA),
+ PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
+ PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
+ PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
+ PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
+ PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+
+ /* PTF */
+ PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
+ PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
+ PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
+ PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
+ PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
+ PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
+ PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+
+ /* PTG */
+ PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
+ PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
+ PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
+ PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
+ PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+
+ /* PTH */
+ PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
+ PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
+ PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
+ PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
+ PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
+ PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
+ PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
+ PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+
+ /* PTJ */
+ PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
+ PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
+ PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
+ PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
+ PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+
+ /* PTK */
+ PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
+ PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
+ PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
+ PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
+ PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
+ PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
+ PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+
+ /* PTL */
+ PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
+ PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
+ PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
+ PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
+ PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
+ PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
+ PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
+ PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
+
+ /* PTM */
+ PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
+ PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
+ PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
+ PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
+ PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
+ PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
+ PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
+ PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+
+ /* PTN */
+ PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
+ PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
+ PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
+ PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
+ PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
+ PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
+ PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
+ PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
+
+ /* PTQ */
+ PINMUX_GPIO(GPIO_PTQ6, PTQ6_DATA),
+ PINMUX_GPIO(GPIO_PTQ5, PTQ5_DATA),
+ PINMUX_GPIO(GPIO_PTQ4, PTQ4_DATA),
+ PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
+ PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
+ PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
+ PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
+
+ /* PTR */
+ PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
+ PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
+ PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
+ PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
+ PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+
+ /* PTS */
+ PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
+ PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
+ PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
+ PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
+ PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+
+ /* PTT */
+ PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
+ PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
+ PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
+ PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
+ PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+
+ /* PTU */
+ PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
+ PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
+ PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
+ PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
+ PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+
+ /* PTV */
+ PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
+ PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
+ PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
+ PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
+ PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+
+ /* PTW */
+ PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
+ PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
+ PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
+ PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
+ PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
+ PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
+ PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
+
+ /* PTX */
+ PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
+ PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
+ PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
+ PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
+ PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
+ PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
+ PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
+
+ /* PTY */
+ PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
+ PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
+ PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
+ PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
+ PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
+ PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
+
+ /* PTZ */
+ PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
+ PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
+ PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
+ PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
+ PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
+
+ /* SCIF0 */
+ PINMUX_GPIO(GPIO_FN_SCIF0_TXD, SCIF0_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_RXD, SCIF0_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_RTS, SCIF0_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_CTS, SCIF0_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_SCK, SCIF0_SCK_MARK),
+
+ /* SCIF1 */
+ PINMUX_GPIO(GPIO_FN_SCIF1_TXD, SCIF1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_RXD, SCIF1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_RTS, SCIF1_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_CTS, SCIF1_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_SCK, SCIF1_SCK_MARK),
+
+ /* SCIF2 */
+ PINMUX_GPIO(GPIO_FN_SCIF2_TXD, SCIF2_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_RXD, SCIF2_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_RTS, SCIF2_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_CTS, SCIF2_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_SCK, SCIF2_SCK_MARK),
+
+ /* SIO */
+ PINMUX_GPIO(GPIO_FN_SIOTXD, SIOTXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIORXD, SIORXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOD, SIOD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOSTRB0, SIOSTRB0_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOSTRB1, SIOSTRB1_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOSCK, SIOSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOMCK, SIOMCK_MARK),
+
+ /* CEU */
+ PINMUX_GPIO(GPIO_FN_VIO_D15, VIO_D15_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D14, VIO_D14_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D13, VIO_D13_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D12, VIO_D12_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D11, VIO_D11_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D10, VIO_D10_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D9, VIO_D9_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D8, VIO_D8_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D7, VIO_D7_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D6, VIO_D6_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D5, VIO_D5_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D4, VIO_D4_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D3, VIO_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D2, VIO_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D1, VIO_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D0, VIO_D0_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_CLK, VIO_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_VD, VIO_VD_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_HD, VIO_HD_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_FLD, VIO_FLD_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_CKO, VIO_CKO_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_STEX, VIO_STEX_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_STEM, VIO_STEM_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_VD2, VIO_VD2_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_HD2, VIO_HD2_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_CLK2, VIO_CLK2_MARK),
+
+ /* LCDC */
+ PINMUX_GPIO(GPIO_FN_LCDD23, LCDD23_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD22, LCDD22_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD21, LCDD21_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD20, LCDD20_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD19, LCDD19_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD18, LCDD18_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD17, LCDD17_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD16, LCDD16_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD15, LCDD15_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD14, LCDD14_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD13, LCDD13_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD12, LCDD12_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD11, LCDD11_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD10, LCDD10_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD9, LCDD9_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD8, LCDD8_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD7, LCDD7_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD6, LCDD6_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD5, LCDD5_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD4, LCDD4_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD3, LCDD3_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD2, LCDD2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD1, LCDD1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD0, LCDD0_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDLCLK, LCDLCLK_MARK),
+ /* Main LCD */
+ PINMUX_GPIO(GPIO_FN_LCDDON, LCDDON_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVCPWC, LCDVCPWC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVEPWC, LCDVEPWC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVSYN, LCDVSYN_MARK),
+ /* Main LCD - RGB Mode */
+ PINMUX_GPIO(GPIO_FN_LCDDCK, LCDDCK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDHSYN, LCDHSYN_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDDISP, LCDDISP_MARK),
+ /* Main LCD - SYS Mode */
+ PINMUX_GPIO(GPIO_FN_LCDRS, LCDRS_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDCS, LCDCS_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDWR, LCDWR_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDRD, LCDRD_MARK),
+ /* Sub LCD - SYS Mode */
+ PINMUX_GPIO(GPIO_FN_LCDDON2, LCDDON2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVCPWC2, LCDVCPWC2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVEPWC2, LCDVEPWC2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVSYN2, LCDVSYN2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDCS2, LCDCS2_MARK),
+
+ /* BSC */
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+ PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+ PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+ PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6B_CE1B, CS6B_CE1B_MARK),
+ PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6A_CE2B, CS6A_CE2B_MARK),
+
+ /* SBSC */
+ PINMUX_GPIO(GPIO_FN_HPD63, HPD63_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD62, HPD62_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD61, HPD61_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD60, HPD60_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD59, HPD59_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD58, HPD58_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD57, HPD57_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD56, HPD56_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD55, HPD55_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD54, HPD54_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD53, HPD53_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD52, HPD52_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD51, HPD51_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD50, HPD50_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD49, HPD49_MARK),
+ PINMUX_GPIO(GPIO_FN_HPD48, HPD48_MARK),
+ PINMUX_GPIO(GPIO_FN_HPDQM7, HPDQM7_MARK),
+ PINMUX_GPIO(GPIO_FN_HPDQM6, HPDQM6_MARK),
+ PINMUX_GPIO(GPIO_FN_HPDQM5, HPDQM5_MARK),
+ PINMUX_GPIO(GPIO_FN_HPDQM4, HPDQM4_MARK),
+
+ /* IRQ */
+ PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3, IRQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4, IRQ4_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6, IRQ6_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ7, IRQ7_MARK),
+
+ /* SDHI */
+ PINMUX_GPIO(GPIO_FN_SDHICD, SDHICD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHIWP, SDHIWP_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHID3, SDHID3_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHID2, SDHID2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHID1, SDHID1_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHID0, SDHID0_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHICMD, SDHICMD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHICLK, SDHICLK_MARK),
+
+ /* SIU - Port A */
+ PINMUX_GPIO(GPIO_FN_SIUAOLR, SIUAOLR_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAOBT, SIUAOBT_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAISLD, SIUAISLD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAILR, SIUAILR_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAIBT, SIUAIBT_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAOSLD, SIUAOSLD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUMCKA, SIUMCKA_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUFCKA, SIUFCKA_MARK),
+
+ /* SIU - Port B */
+ PINMUX_GPIO(GPIO_FN_SIUBOLR, SIUBOLR_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBOBT, SIUBOBT_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBISLD, SIUBISLD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBILR, SIUBILR_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBIBT, SIUBIBT_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBOSLD, SIUBOSLD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUMCKB, SIUMCKB_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUFCKB, SIUFCKB_MARK),
+
+ /* AUD */
+ PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
+
+ /* DMAC */
+ PINMUX_GPIO(GPIO_FN_DACK, DACK_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+
+ /* VOU */
+ PINMUX_GPIO(GPIO_FN_DV_CLKI, DV_CLKI_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D15, DV_D15_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D14, DV_D14_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D13, DV_D13_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D12, DV_D12_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D11, DV_D11_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D10, DV_D10_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D9, DV_D9_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D8, DV_D8_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D7, DV_D7_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D6, DV_D6_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D5, DV_D5_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D4, DV_D4_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D3, DV_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D2, DV_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D1, DV_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D0, DV_D0_MARK),
+
+ /* CPG */
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
+ PINMUX_GPIO(GPIO_FN_PDSTATUS, PDSTATUS_MARK),
+
+ /* SIOF0 */
+ PINMUX_GPIO(GPIO_FN_SIOF0_MCK, SIOF0_MCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF0_SCK, SIOF0_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF0_SYNC, SIOF0_SYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF0_SS1, SIOF0_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF0_SS2, SIOF0_SS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF0_TXD, SIOF0_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF0_RXD, SIOF0_RXD_MARK),
+
+ /* SIOF1 */
+ PINMUX_GPIO(GPIO_FN_SIOF1_MCK, SIOF1_MCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF1_SCK, SIOF1_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF1_SYNC, SIOF1_SYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF1_SS1, SIOF1_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF1_SS2, SIOF1_SS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF1_TXD, SIOF1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF1_RXD, SIOF1_RXD_MARK),
+
+ /* SIM */
+ PINMUX_GPIO(GPIO_FN_SIM_D, SIM_D_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_CLK, SIM_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_RST, SIM_RST_MARK),
+
+ /* TSIF */
+ PINMUX_GPIO(GPIO_FN_TS_SDAT, TS_SDAT_MARK),
+ PINMUX_GPIO(GPIO_FN_TS_SCK, TS_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_TS_SDEN, TS_SDEN_MARK),
+ PINMUX_GPIO(GPIO_FN_TS_SPSYNC, TS_SPSYNC_MARK),
+
+ /* IRDA */
+ PINMUX_GPIO(GPIO_FN_IRDA_IN, IRDA_IN_MARK),
+ PINMUX_GPIO(GPIO_FN_IRDA_OUT, IRDA_OUT_MARK),
+
+ /* TPU */
+ PINMUX_GPIO(GPIO_FN_TPUTO, TPUTO_MARK),
+
+ /* FLCTL */
+ PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF7, NAF7_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF6, NAF6_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF5, NAF5_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF4, NAF4_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF3, NAF3_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF2, NAF2_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF1, NAF1_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF0, NAF0_MARK),
+ PINMUX_GPIO(GPIO_FN_FCDE, FCDE_MARK),
+ PINMUX_GPIO(GPIO_FN_FOE, FOE_MARK),
+ PINMUX_GPIO(GPIO_FN_FSC, FSC_MARK),
+ PINMUX_GPIO(GPIO_FN_FWE, FWE_MARK),
+ PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+
+ /* KEYSC */
+ PINMUX_GPIO(GPIO_FN_KEYIN0, KEYIN0_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN1, KEYIN1_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN2, KEYIN2_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN3, KEYIN3_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN4, KEYIN4_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT0, KEYOUT0_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT1, KEYOUT1_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT2, KEYOUT2_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT3, KEYOUT3_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT4_IN6, KEYOUT4_IN6_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT5_IN5, KEYOUT5_IN5_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
+ VIO_D7_SCIF1_SCK, PTA7_OUT, PTA7_IN_PD, PTA7_IN,
+ VIO_D6_SCIF1_RXD, 0, PTA6_IN_PD, PTA6_IN,
+ VIO_D5_SCIF1_TXD, PTA5_OUT, PTA5_IN_PD, PTA5_IN,
+ VIO_D4, 0, PTA4_IN_PD, PTA4_IN,
+ VIO_D3, 0, PTA3_IN_PD, PTA3_IN,
+ VIO_D2, 0, PTA2_IN_PD, PTA2_IN,
+ VIO_D1, 0, PTA1_IN_PD, PTA1_IN,
+ VIO_D0_LCDLCLK, 0, PTA0_IN_PD, PTA0_IN }
+ },
+ { PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
+ HPD55, PTB7_OUT, 0, PTB7_IN,
+ HPD54, PTB6_OUT, 0, PTB6_IN,
+ HPD53, PTB5_OUT, 0, PTB5_IN,
+ HPD52, PTB4_OUT, 0, PTB4_IN,
+ HPD51, PTB3_OUT, 0, PTB3_IN,
+ HPD50, PTB2_OUT, 0, PTB2_IN,
+ HPD49, PTB1_OUT, 0, PTB1_IN,
+ HPD48, PTB0_OUT, 0, PTB0_IN }
+ },
+ { PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
+ 0, 0, PTC7_IN_PU, PTC7_IN,
+ 0, 0, 0, 0,
+ IOIS16, 0, PTC5_IN_PU, PTC5_IN,
+ HPDQM7, PTC4_OUT, 0, PTC4_IN,
+ HPDQM6, PTC3_OUT, 0, PTC3_IN,
+ HPDQM5, PTC2_OUT, 0, PTC2_IN,
+ 0, 0, 0, 0,
+ HPDQM4, PTC0_OUT, 0, PTC0_IN }
+ },
+ { PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
+ SDHICD, 0, PTD7_IN_PU, PTD7_IN,
+ SDHIWP, PTD6_OUT, PTD6_IN_PU, PTD6_IN,
+ SDHID3, PTD5_OUT, PTD5_IN_PU, PTD5_IN,
+ IRQ2_SDHID2, PTD4_OUT, PTD4_IN_PU, PTD4_IN,
+ SDHID1, PTD3_OUT, PTD3_IN_PU, PTD3_IN,
+ SDHID0, PTD2_OUT, PTD2_IN_PU, PTD2_IN,
+ SDHICMD, PTD1_OUT, PTD1_IN_PU, PTD1_IN,
+ SDHICLK, PTD0_OUT, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
+ A25, PTE7_OUT, PTE7_IN_PD, PTE7_IN,
+ A24, PTE6_OUT, PTE6_IN_PD, PTE6_IN,
+ A23, PTE5_OUT, PTE5_IN_PD, PTE5_IN,
+ A22, PTE4_OUT, PTE4_IN_PD, PTE4_IN,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ IRQ5, PTE1_OUT, PTE1_IN_PD, PTE1_IN,
+ IRQ4_BS, PTE0_OUT, PTE0_IN_PD, PTE0_IN }
+ },
+ { PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
+ 0, 0, 0, 0,
+ PTF6, PTF6_OUT, PTF6_IN_PD, PTF6_IN,
+ SIOSCK_SIUBOBT, PTF5_OUT, PTF5_IN_PD, PTF5_IN,
+ SIOSTRB1_SIUBOLR, PTF4_OUT, PTF4_IN_PD, PTF4_IN,
+ SIOSTRB0_SIUBIBT, PTF3_OUT, PTF3_IN_PD, PTF3_IN,
+ SIOD_SIUBILR, PTF2_OUT, PTF2_IN_PD, PTF2_IN,
+ SIORXD_SIUBISLD, 0, PTF1_IN_PD, PTF1_IN,
+ SIOTXD_SIUBOSLD, PTF0_OUT, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ AUDSYNC, PTG4_OUT, 0, 0,
+ AUDATA3, PTG3_OUT, 0, 0,
+ AUDATA2, PTG2_OUT, 0, 0,
+ AUDATA1, PTG1_OUT, 0, 0,
+ AUDATA0, PTG0_OUT, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
+ LCDVCPWC_LCDVCPWC2, PTH7_OUT, 0, 0,
+ LCDVSYN2_DACK, PTH6_OUT, PTH6_IN_PD, PTH6_IN,
+ LCDVSYN, PTH5_OUT, PTH5_IN_PD, PTH5_IN,
+ LCDDISP_LCDRS, PTH4_OUT, 0, 0,
+ LCDHSYN_LCDCS, PTH3_OUT, 0, 0,
+ LCDDON_LCDDON2, PTH2_OUT, 0, 0,
+ LCDD17_DV_HSYNC, PTH1_OUT, PTH1_IN_PD, PTH1_IN,
+ LCDD16_DV_VSYNC, PTH0_OUT, PTH0_IN_PD, PTH0_IN }
+ },
+ { PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
+ STATUS0, PTJ7_OUT, 0, 0,
+ 0, PTJ6_OUT, 0, 0,
+ PDSTATUS, PTJ5_OUT, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ IRQ1, PTJ1_OUT, PTJ1_IN_PU, PTJ1_IN,
+ IRQ0, PTJ0_OUT, PTJ0_IN_PU, PTJ0_IN }
+ },
+ { PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
+ 0, 0, 0, 0,
+ SIUAILR_SIOF1_SS2, PTK6_OUT, PTK6_IN_PD, PTK6_IN,
+ SIUAIBT_SIOF1_SS1, PTK5_OUT, PTK5_IN_PD, PTK5_IN,
+ SIUAOLR_SIOF1_SYNC, PTK4_OUT, PTK4_IN_PD, PTK4_IN,
+ SIUAOBT_SIOF1_SCK, PTK3_OUT, PTK3_IN_PD, PTK3_IN,
+ SIUAISLD_SIOF1_RXD, 0, PTK2_IN_PD, PTK2_IN,
+ SIUAOSLD_SIOF1_TXD, PTK1_OUT, 0, 0,
+ PTK0, PTK0_OUT, PTK0_IN_PD, PTK0_IN }
+ },
+ { PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
+ LCDD15_DV_D15, PTL7_OUT, PTL7_IN_PD, PTL7_IN,
+ LCDD14_DV_D14, PTL6_OUT, PTL6_IN_PD, PTL6_IN,
+ LCDD13_DV_D13, PTL5_OUT, PTL5_IN_PD, PTL5_IN,
+ LCDD12_DV_D12, PTL4_OUT, PTL4_IN_PD, PTL4_IN,
+ LCDD11_DV_D11, PTL3_OUT, PTL3_IN_PD, PTL3_IN,
+ LCDD10_DV_D10, PTL2_OUT, PTL2_IN_PD, PTL2_IN,
+ LCDD9_DV_D9, PTL1_OUT, PTL1_IN_PD, PTL1_IN,
+ LCDD8_DV_D8, PTL0_OUT, PTL0_IN_PD, PTL0_IN }
+ },
+ { PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
+ LCDD7_DV_D7, PTM7_OUT, PTM7_IN_PD, PTM7_IN,
+ LCDD6_DV_D6, PTM6_OUT, PTM6_IN_PD, PTM6_IN,
+ LCDD5_DV_D5, PTM5_OUT, PTM5_IN_PD, PTM5_IN,
+ LCDD4_DV_D4, PTM4_OUT, PTM4_IN_PD, PTM4_IN,
+ LCDD3_DV_D3, PTM3_OUT, PTM3_IN_PD, PTM3_IN,
+ LCDD2_DV_D2, PTM2_OUT, PTM2_IN_PD, PTM2_IN,
+ LCDD1_DV_D1, PTM1_OUT, PTM1_IN_PD, PTM1_IN,
+ LCDD0_DV_D0, PTM0_OUT, PTM0_IN_PD, PTM0_IN }
+ },
+ { PINMUX_CFG_REG("PNCR", 0xa4050118, 16, 2) {
+ HPD63, PTN7_OUT, 0, PTN7_IN,
+ HPD62, PTN6_OUT, 0, PTN6_IN,
+ HPD61, PTN5_OUT, 0, PTN5_IN,
+ HPD60, PTN4_OUT, 0, PTN4_IN,
+ HPD59, PTN3_OUT, 0, PTN3_IN,
+ HPD58, PTN2_OUT, 0, PTN2_IN,
+ HPD57, PTN1_OUT, 0, PTN1_IN,
+ HPD56, PTN0_OUT, 0, PTN0_IN }
+ },
+ { PINMUX_CFG_REG("PQCR", 0xa405011a, 16, 2) {
+ 0, 0, 0, 0,
+ SIOF0_SS2_SIM_RST, PTQ6_OUT, 0, 0,
+ SIOF0_SS1_TS_SPSYNC, PTQ5_OUT, PTQ5_IN_PD, PTQ5_IN,
+ SIOF0_SYNC_TS_SDEN, PTQ4_OUT, PTQ4_IN_PD, PTQ4_IN,
+ SIOF0_SCK_TS_SCK, PTQ3_OUT, PTQ3_IN_PD, PTQ3_IN,
+ PTQ2, 0, PTQ2_IN_PD, PTQ2_IN,
+ PTQ1, PTQ1_OUT, 0, 0,
+ PTQ0, PTQ0_OUT, PTQ0_IN_PU, PTQ0_IN }
+ },
+ { PINMUX_CFG_REG("PRCR", 0xa405011c, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ LCDRD, PTR4_OUT, 0, 0,
+ CS6B_CE1B_LCDCS2, PTR3_OUT, 0, 0,
+ WAIT, 0, PTR2_IN_PU, PTR2_IN,
+ LCDDCK_LCDWR, PTR1_OUT, 0, 0,
+ LCDVEPWC_LCDVEPWC2, PTR0_OUT, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PSCR", 0xa405011e, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ SCIF0_CTS_SIUAISPD, 0, PTS4_IN_PD, PTS4_IN,
+ SCIF0_RTS_SIUAOSPD, PTS3_OUT, 0, 0,
+ SCIF0_SCK_TPUTO, PTS2_OUT, PTS2_IN_PD, PTS2_IN,
+ SCIF0_RXD, 0, PTS1_IN_PD, PTS1_IN,
+ SCIF0_TXD, PTS0_OUT, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PTCR", 0xa4050140, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ FOE_VIO_VD2, PTT4_OUT, PTT4_IN_PD, PTT4_IN,
+ FWE, PTT3_OUT, PTT3_IN_PD, PTT3_IN,
+ FSC, PTT2_OUT, PTT2_IN_PD, PTT2_IN,
+ DREQ0, 0, PTT1_IN_PD, PTT1_IN,
+ FCDE, PTT0_OUT, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PUCR", 0xa4050142, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ NAF2_VIO_D10, PTU4_OUT, PTU4_IN_PD, PTU4_IN,
+ NAF1_VIO_D9, PTU3_OUT, PTU3_IN_PD, PTU3_IN,
+ NAF0_VIO_D8, PTU2_OUT, PTU2_IN_PD, PTU2_IN,
+ FRB_VIO_CLK2, 0, PTU1_IN_PD, PTU1_IN,
+ FCE_VIO_HD2, PTU0_OUT, PTU0_IN_PD, PTU0_IN }
+ },
+ { PINMUX_CFG_REG("PVCR", 0xa4050144, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ NAF7_VIO_D15, PTV4_OUT, PTV4_IN_PD, PTV4_IN,
+ NAF6_VIO_D14, PTV3_OUT, PTV3_IN_PD, PTV3_IN,
+ NAF5_VIO_D13, PTV2_OUT, PTV2_IN_PD, PTV2_IN,
+ NAF4_VIO_D12, PTV1_OUT, PTV1_IN_PD, PTV1_IN,
+ NAF3_VIO_D11, PTV0_OUT, PTV0_IN_PD, PTV0_IN }
+ },
+ { PINMUX_CFG_REG("PWCR", 0xa4050146, 16, 2) {
+ 0, 0, 0, 0,
+ VIO_FLD_SCIF2_CTS, 0, PTW6_IN_PD, PTW6_IN,
+ VIO_CKO_SCIF2_RTS, PTW5_OUT, 0, 0,
+ VIO_STEX_SCIF2_SCK, PTW4_OUT, PTW4_IN_PD, PTW4_IN,
+ VIO_STEM_SCIF2_TXD, PTW3_OUT, PTW3_IN_PD, PTW3_IN,
+ VIO_HD_SCIF2_RXD, PTW2_OUT, PTW2_IN_PD, PTW2_IN,
+ VIO_VD_SCIF1_CTS, PTW1_OUT, PTW1_IN_PD, PTW1_IN,
+ VIO_CLK_SCIF1_RTS, PTW0_OUT, PTW0_IN_PD, PTW0_IN }
+ },
+ { PINMUX_CFG_REG("PXCR", 0xa4050148, 16, 2) {
+ 0, 0, 0, 0,
+ CS6A_CE2B, PTX6_OUT, PTX6_IN_PU, PTX6_IN,
+ LCDD23, PTX5_OUT, PTX5_IN_PD, PTX5_IN,
+ LCDD22, PTX4_OUT, PTX4_IN_PD, PTX4_IN,
+ LCDD21, PTX3_OUT, PTX3_IN_PD, PTX3_IN,
+ LCDD20, PTX2_OUT, PTX2_IN_PD, PTX2_IN,
+ LCDD19_DV_CLKI, PTX1_OUT, PTX1_IN_PD, PTX1_IN,
+ LCDD18_DV_CLK, PTX0_OUT, PTX0_IN_PD, PTX0_IN }
+ },
+ { PINMUX_CFG_REG("PYCR", 0xa405014a, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ KEYOUT5_IN5, PTY5_OUT, PTY5_IN_PU, PTY5_IN,
+ KEYOUT4_IN6, PTY4_OUT, PTY4_IN_PU, PTY4_IN,
+ KEYOUT3, PTY3_OUT, PTY3_IN_PU, PTY3_IN,
+ KEYOUT2, PTY2_OUT, PTY2_IN_PU, PTY2_IN,
+ KEYOUT1, PTY1_OUT, 0, 0,
+ KEYOUT0, PTY0_OUT, PTY0_IN_PU, PTY0_IN }
+ },
+ { PINMUX_CFG_REG("PZCR", 0xa405014c, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ KEYIN4_IRQ7, 0, PTZ5_IN_PU, PTZ5_IN,
+ KEYIN3, 0, PTZ4_IN_PU, PTZ4_IN,
+ KEYIN2, 0, PTZ3_IN_PU, PTZ3_IN,
+ KEYIN1, 0, PTZ2_IN_PU, PTZ2_IN,
+ KEYIN0_IRQ6, 0, PTZ1_IN_PU, PTZ1_IN,
+ 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PSELA", 0xa405014e, 16, 1) {
+ PSA15_KEYIN0, PSA15_IRQ6,
+ PSA14_KEYIN4, PSA14_IRQ7,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PSA9_IRQ4, PSA9_BS,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PSA4_IRQ2, PSA4_SDHID2,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0 }
+ },
+ { PINMUX_CFG_REG("PSELB", 0xa4050150, 16, 1) {
+ PSB15_SIOTXD, PSB15_SIUBOSLD,
+ PSB14_SIORXD, PSB14_SIUBISLD,
+ PSB13_SIOD, PSB13_SIUBILR,
+ PSB12_SIOSTRB0, PSB12_SIUBIBT,
+ PSB11_SIOSTRB1, PSB11_SIUBOLR,
+ PSB10_SIOSCK, PSB10_SIUBOBT,
+ PSB9_SIOMCK, PSB9_SIUMCKB,
+ PSB8_SIOF0_MCK, PSB8_IRQ3,
+ PSB7_SIOF0_TXD, PSB7_IRDA_OUT,
+ PSB6_SIOF0_RXD, PSB6_IRDA_IN,
+ PSB5_SIOF0_SCK, PSB5_TS_SCK,
+ PSB4_SIOF0_SYNC, PSB4_TS_SDEN,
+ PSB3_SIOF0_SS1, PSB3_TS_SPSYNC,
+ PSB2_SIOF0_SS2, PSB2_SIM_RST,
+ PSB1_SIUMCKA, PSB1_SIOF1_MCK,
+ PSB0_SIUAOSLD, PSB0_SIOF1_TXD }
+ },
+ { PINMUX_CFG_REG("PSELC", 0xa4050152, 16, 1) {
+ PSC15_SIUAISLD, PSC15_SIOF1_RXD,
+ PSC14_SIUAOBT, PSC14_SIOF1_SCK,
+ PSC13_SIUAOLR, PSC13_SIOF1_SYNC,
+ PSC12_SIUAIBT, PSC12_SIOF1_SS1,
+ PSC11_SIUAILR, PSC11_SIOF1_SS2,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PSC0_NAF, PSC0_VIO }
+ },
+ { PINMUX_CFG_REG("PSELD", 0xa4050154, 16, 1) {
+ 0, 0,
+ 0, 0,
+ PSD13_VIO, PSD13_SCIF2,
+ PSD12_VIO, PSD12_SCIF1,
+ PSD11_VIO, PSD11_SCIF1,
+ PSD10_VIO_D0, PSD10_LCDLCLK,
+ PSD9_SIOMCK_SIUMCKB, PSD9_SIUFCKB,
+ PSD8_SCIF0_SCK, PSD8_TPUTO,
+ PSD7_SCIF0_RTS, PSD7_SIUAOSPD,
+ PSD6_SCIF0_CTS, PSD6_SIUAISPD,
+ PSD5_CS6B_CE1B, PSD5_LCDCS2,
+ 0, 0,
+ PSD3_LCDVEPWC_LCDVCPWC, PSD3_LCDVEPWC2_LCDVCPWC2,
+ PSD2_LCDDON, PSD2_LCDDON2,
+ 0, 0,
+ PSD0_LCDD19_LCDD0, PSD0_DV }
+ },
+ { PINMUX_CFG_REG("PSELE", 0xa4050156, 16, 1) {
+ PSE15_SIOF0_MCK_IRQ3, PSE15_SIM_D,
+ PSE14_SIOF0_TXD_IRDA_OUT, PSE14_SIM_CLK,
+ PSE13_SIOF0_RXD_IRDA_IN, PSE13_TS_SDAT,
+ PSE12_LCDVSYN2, PSE12_DACK,
+ PSE11_SIUMCKA_SIOF1_MCK, PSE11_SIUFCKA,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PSE3_FLCTL, PSE3_VIO,
+ PSE2_NAF2, PSE2_VIO_D10,
+ PSE1_NAF1, PSE1_VIO_D9,
+ PSE0_NAF0, PSE0_VIO_D8 }
+ },
+ { PINMUX_CFG_REG("HIZCRA", 0xa4050158, 16, 1) {
+ 0, 0,
+ HIZA14_KEYSC, HIZA14_HIZ,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ HIZA10_NAF, HIZA10_HIZ,
+ HIZA9_VIO, HIZA9_HIZ,
+ HIZA8_LCDC, HIZA8_HIZ,
+ HIZA7_LCDC, HIZA7_HIZ,
+ HIZA6_LCDC, HIZA6_HIZ,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0 }
+ },
+ { PINMUX_CFG_REG("HIZCRB", 0xa405015a, 16, 1) {
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ HIZB4_SIUA, HIZB4_HIZ,
+ 0, 0,
+ 0, 0,
+ HIZB1_VIO, HIZB1_HIZ,
+ HIZB0_VIO, HIZB0_HIZ }
+ },
+ { PINMUX_CFG_REG("HIZCRC", 0xa405015c, 16, 1) {
+ HIZC15_IRQ7, HIZC15_HIZ,
+ HIZC14_IRQ6, HIZC14_HIZ,
+ HIZC13_IRQ5, HIZC13_HIZ,
+ HIZC12_IRQ4, HIZC12_HIZ,
+ HIZC11_IRQ3, HIZC11_HIZ,
+ HIZC10_IRQ2, HIZC10_HIZ,
+ HIZC9_IRQ1, HIZC9_HIZ,
+ HIZC8_IRQ0, HIZC8_HIZ,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0 }
+ },
+ { PINMUX_CFG_REG("MSELCRB", 0xa4050182, 16, 1) {
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ MSELB9_VIO, MSELB9_VIO2,
+ MSELB8_RGB, MSELB8_SYS,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0 }
+ },
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR", 0xa4050120, 8) {
+ PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+ PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
+ },
+ { PINMUX_DATA_REG("PBDR", 0xa4050122, 8) {
+ PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+ PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
+ },
+ { PINMUX_DATA_REG("PCDR", 0xa4050124, 8) {
+ PTC7_DATA, 0, PTC5_DATA, PTC4_DATA,
+ PTC3_DATA, PTC2_DATA, 0, PTC0_DATA }
+ },
+ { PINMUX_DATA_REG("PDDR", 0xa4050126, 8) {
+ PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+ PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
+ },
+ { PINMUX_DATA_REG("PEDR", 0xa4050128, 8) {
+ PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
+ 0, 0, PTE1_DATA, PTE0_DATA }
+ },
+ { PINMUX_DATA_REG("PFDR", 0xa405012a, 8) {
+ 0, PTF6_DATA, PTF5_DATA, PTF4_DATA,
+ PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
+ },
+ { PINMUX_DATA_REG("PGDR", 0xa405012c, 8) {
+ 0, 0, 0, PTG4_DATA,
+ PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
+ },
+ { PINMUX_DATA_REG("PHDR", 0xa405012e, 8) {
+ PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+ PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR", 0xa4050130, 8) {
+ PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, 0,
+ 0, 0, PTJ1_DATA, PTJ0_DATA }
+ },
+ { PINMUX_DATA_REG("PKDR", 0xa4050132, 8) {
+ 0, PTK6_DATA, PTK5_DATA, PTK4_DATA,
+ PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
+ },
+ { PINMUX_DATA_REG("PLDR", 0xa4050134, 8) {
+ PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
+ },
+ { PINMUX_DATA_REG("PMDR", 0xa4050136, 8) {
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
+ },
+ { PINMUX_DATA_REG("PNDR", 0xa4050138, 8) {
+ PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
+ },
+ { PINMUX_DATA_REG("PQDR", 0xa405013a, 8) {
+ 0, PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+ PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA }
+ },
+ { PINMUX_DATA_REG("PRDR", 0xa405013c, 8) {
+ 0, 0, 0, PTR4_DATA,
+ PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
+ },
+ { PINMUX_DATA_REG("PSDR", 0xa405013e, 8) {
+ 0, 0, 0, PTS4_DATA,
+ PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
+ },
+ { PINMUX_DATA_REG("PTDR", 0xa4050160, 8) {
+ 0, 0, 0, PTT4_DATA,
+ PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
+ },
+ { PINMUX_DATA_REG("PUDR", 0xa4050162, 8) {
+ 0, 0, 0, PTU4_DATA,
+ PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
+ },
+ { PINMUX_DATA_REG("PVDR", 0xa4050164, 8) {
+ 0, 0, 0, PTV4_DATA,
+ PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
+ },
+ { PINMUX_DATA_REG("PWDR", 0xa4050166, 8) {
+ 0, PTW6_DATA, PTW5_DATA, PTW4_DATA,
+ PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA }
+ },
+ { PINMUX_DATA_REG("PXDR", 0xa4050168, 8) {
+ 0, PTX6_DATA, PTX5_DATA, PTX4_DATA,
+ PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA }
+ },
+ { PINMUX_DATA_REG("PYDR", 0xa405016a, 8) {
+ 0, PTY6_DATA, PTY5_DATA, PTY4_DATA,
+ PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA }
+ },
+ { PINMUX_DATA_REG("PZDR", 0xa405016c, 8) {
+ 0, 0, PTZ5_DATA, PTZ4_DATA,
+ PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA }
+ },
+ { },
+};
+
+struct sh_pfc_soc_info sh7722_pinmux_info = {
+ .name = "sh7722_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .input_pd = { PINMUX_INPUT_PULLDOWN_BEGIN, PINMUX_INPUT_PULLDOWN_END },
+ .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PTA7,
+ .last_gpio = GPIO_FN_KEYOUT5_IN5,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7723.c b/drivers/pinctrl/sh-pfc/pfc-sh7723.c
new file mode 100644
index 000000000000..609673d3d70e
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7723.c
@@ -0,0 +1,1903 @@
+/*
+ * SH7723 Pinmux
+ *
+ * Copyright (C) 2008 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/init.h>
+#include <linux/kernel.h>
+#include <cpu/sh7723.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+ PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
+ PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+ PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
+ PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
+ PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA,
+ PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+ PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
+ PTE5_DATA, PTE4_DATA, PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA,
+ PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
+ PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
+ PTG5_DATA, PTG4_DATA, PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
+ PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+ PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
+ PTJ7_DATA, PTJ5_DATA, PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
+ PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
+ PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
+ PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
+ PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
+ PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
+ PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
+ PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
+ PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
+ PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
+ PTT5_DATA, PTT4_DATA, PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
+ PTU5_DATA, PTU4_DATA, PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
+ PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
+ PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
+ PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
+ PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA,
+ PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
+ PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA,
+ PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
+ PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA,
+ PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
+ PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
+ PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
+ PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
+ PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
+ PTC7_IN, PTC6_IN, PTC5_IN, PTC4_IN,
+ PTC3_IN, PTC2_IN, PTC1_IN, PTC0_IN,
+ PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN,
+ PTD3_IN, PTD2_IN, PTD1_IN, PTD0_IN,
+ PTE5_IN, PTE4_IN, PTE3_IN, PTE2_IN, PTE1_IN, PTE0_IN,
+ PTF7_IN, PTF6_IN, PTF5_IN, PTF4_IN,
+ PTF3_IN, PTF2_IN, PTF1_IN, PTF0_IN,
+ PTH7_IN, PTH6_IN, PTH5_IN, PTH4_IN,
+ PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
+ PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
+ PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
+ PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
+ PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
+ PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
+ PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
+ PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
+ PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
+ PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
+ PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
+ PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
+ PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
+ PTS7_IN, PTS6_IN, PTS5_IN, PTS4_IN,
+ PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
+ PTT5_IN, PTT4_IN, PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
+ PTU5_IN, PTU4_IN, PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
+ PTV7_IN, PTV6_IN, PTV5_IN, PTV4_IN,
+ PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
+ PTW7_IN, PTW6_IN, PTW5_IN, PTW4_IN,
+ PTW3_IN, PTW2_IN, PTW1_IN, PTW0_IN,
+ PTX7_IN, PTX6_IN, PTX5_IN, PTX4_IN,
+ PTX3_IN, PTX2_IN, PTX1_IN, PTX0_IN,
+ PTY7_IN, PTY6_IN, PTY5_IN, PTY4_IN,
+ PTY3_IN, PTY2_IN, PTY1_IN, PTY0_IN,
+ PTZ7_IN, PTZ6_IN, PTZ5_IN, PTZ4_IN,
+ PTZ3_IN, PTZ2_IN, PTZ1_IN, PTZ0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_INPUT_PULLUP_BEGIN,
+ PTA4_IN_PU, PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
+ PTB2_IN_PU, PTB1_IN_PU,
+ PTR2_IN_PU,
+ PINMUX_INPUT_PULLUP_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
+ PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
+ PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
+ PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
+ PTC7_OUT, PTC6_OUT, PTC5_OUT, PTC4_OUT,
+ PTC3_OUT, PTC2_OUT, PTC1_OUT, PTC0_OUT,
+ PTD7_OUT, PTD6_OUT, PTD5_OUT, PTD4_OUT,
+ PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
+ PTE5_OUT, PTE4_OUT, PTE3_OUT, PTE2_OUT, PTE1_OUT, PTE0_OUT,
+ PTF7_OUT, PTF6_OUT, PTF5_OUT, PTF4_OUT,
+ PTF3_OUT, PTF2_OUT, PTF1_OUT, PTF0_OUT,
+ PTG5_OUT, PTG4_OUT, PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
+ PTH7_OUT, PTH6_OUT, PTH5_OUT, PTH4_OUT,
+ PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
+ PTJ7_OUT, PTJ5_OUT, PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
+ PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
+ PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
+ PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
+ PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
+ PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
+ PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
+ PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
+ PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
+ PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
+ PTR1_OUT, PTR0_OUT,
+ PTS7_OUT, PTS6_OUT, PTS5_OUT, PTS4_OUT,
+ PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
+ PTT5_OUT, PTT4_OUT, PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
+ PTU5_OUT, PTU4_OUT, PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
+ PTV7_OUT, PTV6_OUT, PTV5_OUT, PTV4_OUT,
+ PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
+ PTW7_OUT, PTW6_OUT, PTW5_OUT, PTW4_OUT,
+ PTW3_OUT, PTW2_OUT, PTW1_OUT, PTW0_OUT,
+ PTX7_OUT, PTX6_OUT, PTX5_OUT, PTX4_OUT,
+ PTX3_OUT, PTX2_OUT, PTX1_OUT, PTX0_OUT,
+ PTY7_OUT, PTY6_OUT, PTY5_OUT, PTY4_OUT,
+ PTY3_OUT, PTY2_OUT, PTY1_OUT, PTY0_OUT,
+ PTZ7_OUT, PTZ6_OUT, PTZ5_OUT, PTZ4_OUT,
+ PTZ3_OUT, PTZ2_OUT, PTZ1_OUT, PTZ0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PTA7_FN, PTA6_FN, PTA5_FN, PTA4_FN,
+ PTA3_FN, PTA2_FN, PTA1_FN, PTA0_FN,
+ PTB7_FN, PTB6_FN, PTB5_FN, PTB4_FN,
+ PTB3_FN, PTB2_FN, PTB1_FN, PTB0_FN,
+ PTC7_FN, PTC6_FN, PTC5_FN, PTC4_FN,
+ PTC3_FN, PTC2_FN, PTC1_FN, PTC0_FN,
+ PTD7_FN, PTD6_FN, PTD5_FN, PTD4_FN,
+ PTD3_FN, PTD2_FN, PTD1_FN, PTD0_FN,
+ PTE5_FN, PTE4_FN, PTE3_FN, PTE2_FN, PTE1_FN, PTE0_FN,
+ PTF7_FN, PTF6_FN, PTF5_FN, PTF4_FN,
+ PTF3_FN, PTF2_FN, PTF1_FN, PTF0_FN,
+ PTG5_FN, PTG4_FN, PTG3_FN, PTG2_FN, PTG1_FN, PTG0_FN,
+ PTH7_FN, PTH6_FN, PTH5_FN, PTH4_FN,
+ PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
+ PTJ7_FN, PTJ5_FN, PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
+ PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
+ PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
+ PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN,
+ PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
+ PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
+ PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
+ PTN7_FN, PTN6_FN, PTN5_FN, PTN4_FN,
+ PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
+ PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
+ PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
+ PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
+ PTS7_FN, PTS6_FN, PTS5_FN, PTS4_FN,
+ PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
+ PTT5_FN, PTT4_FN, PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
+ PTU5_FN, PTU4_FN, PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
+ PTV7_FN, PTV6_FN, PTV5_FN, PTV4_FN,
+ PTV3_FN, PTV2_FN, PTV1_FN, PTV0_FN,
+ PTW7_FN, PTW6_FN, PTW5_FN, PTW4_FN,
+ PTW3_FN, PTW2_FN, PTW1_FN, PTW0_FN,
+ PTX7_FN, PTX6_FN, PTX5_FN, PTX4_FN,
+ PTX3_FN, PTX2_FN, PTX1_FN, PTX0_FN,
+ PTY7_FN, PTY6_FN, PTY5_FN, PTY4_FN,
+ PTY3_FN, PTY2_FN, PTY1_FN, PTY0_FN,
+ PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
+ PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
+
+
+ PSA15_PSA14_FN1, PSA15_PSA14_FN2,
+ PSA13_PSA12_FN1, PSA13_PSA12_FN2,
+ PSA11_PSA10_FN1, PSA11_PSA10_FN2,
+ PSA5_PSA4_FN1, PSA5_PSA4_FN2, PSA5_PSA4_FN3,
+ PSA3_PSA2_FN1, PSA3_PSA2_FN2,
+ PSB15_PSB14_FN1, PSB15_PSB14_FN2,
+ PSB13_PSB12_LCDC_RGB, PSB13_PSB12_LCDC_SYS,
+ PSB9_PSB8_FN1, PSB9_PSB8_FN2, PSB9_PSB8_FN3,
+ PSB7_PSB6_FN1, PSB7_PSB6_FN2,
+ PSB5_PSB4_FN1, PSB5_PSB4_FN2,
+ PSB3_PSB2_FN1, PSB3_PSB2_FN2,
+ PSC15_PSC14_FN1, PSC15_PSC14_FN2,
+ PSC13_PSC12_FN1, PSC13_PSC12_FN2,
+ PSC11_PSC10_FN1, PSC11_PSC10_FN2, PSC11_PSC10_FN3,
+ PSC9_PSC8_FN1, PSC9_PSC8_FN2,
+ PSC7_PSC6_FN1, PSC7_PSC6_FN2, PSC7_PSC6_FN3,
+ PSD15_PSD14_FN1, PSD15_PSD14_FN2,
+ PSD13_PSD12_FN1, PSD13_PSD12_FN2,
+ PSD11_PSD10_FN1, PSD11_PSD10_FN2, PSD11_PSD10_FN3,
+ PSD9_PSD8_FN1, PSD9_PSD8_FN2,
+ PSD7_PSD6_FN1, PSD7_PSD6_FN2,
+ PSD5_PSD4_FN1, PSD5_PSD4_FN2,
+ PSD3_PSD2_FN1, PSD3_PSD2_FN2,
+ PSD1_PSD0_FN1, PSD1_PSD0_FN2,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ SCIF0_PTT_TXD_MARK, SCIF0_PTT_RXD_MARK,
+ SCIF0_PTT_SCK_MARK, SCIF0_PTU_TXD_MARK,
+ SCIF0_PTU_RXD_MARK, SCIF0_PTU_SCK_MARK,
+
+ SCIF1_PTS_TXD_MARK, SCIF1_PTS_RXD_MARK,
+ SCIF1_PTS_SCK_MARK, SCIF1_PTV_TXD_MARK,
+ SCIF1_PTV_RXD_MARK, SCIF1_PTV_SCK_MARK,
+
+ SCIF2_PTT_TXD_MARK, SCIF2_PTT_RXD_MARK,
+ SCIF2_PTT_SCK_MARK, SCIF2_PTU_TXD_MARK,
+ SCIF2_PTU_RXD_MARK, SCIF2_PTU_SCK_MARK,
+
+ SCIF3_PTS_TXD_MARK, SCIF3_PTS_RXD_MARK,
+ SCIF3_PTS_SCK_MARK, SCIF3_PTS_RTS_MARK,
+ SCIF3_PTS_CTS_MARK, SCIF3_PTV_TXD_MARK,
+ SCIF3_PTV_RXD_MARK, SCIF3_PTV_SCK_MARK,
+ SCIF3_PTV_RTS_MARK, SCIF3_PTV_CTS_MARK,
+
+ SCIF4_PTE_TXD_MARK, SCIF4_PTE_RXD_MARK,
+ SCIF4_PTE_SCK_MARK, SCIF4_PTN_TXD_MARK,
+ SCIF4_PTN_RXD_MARK, SCIF4_PTN_SCK_MARK,
+
+ SCIF5_PTE_TXD_MARK, SCIF5_PTE_RXD_MARK,
+ SCIF5_PTE_SCK_MARK, SCIF5_PTN_TXD_MARK,
+ SCIF5_PTN_RXD_MARK, SCIF5_PTN_SCK_MARK,
+
+ VIO_D15_MARK, VIO_D14_MARK, VIO_D13_MARK, VIO_D12_MARK,
+ VIO_D11_MARK, VIO_D10_MARK, VIO_D9_MARK, VIO_D8_MARK,
+ VIO_D7_MARK, VIO_D6_MARK, VIO_D5_MARK, VIO_D4_MARK,
+ VIO_D3_MARK, VIO_D2_MARK, VIO_D1_MARK, VIO_D0_MARK,
+ VIO_FLD_MARK, VIO_CKO_MARK,
+ VIO_VD1_MARK, VIO_HD1_MARK, VIO_CLK1_MARK,
+ VIO_HD2_MARK, VIO_VD2_MARK, VIO_CLK2_MARK,
+
+ LCDD23_MARK, LCDD22_MARK, LCDD21_MARK, LCDD20_MARK,
+ LCDD19_MARK, LCDD18_MARK, LCDD17_MARK, LCDD16_MARK,
+ LCDD15_MARK, LCDD14_MARK, LCDD13_MARK, LCDD12_MARK,
+ LCDD11_MARK, LCDD10_MARK, LCDD9_MARK, LCDD8_MARK,
+ LCDD7_MARK, LCDD6_MARK, LCDD5_MARK, LCDD4_MARK,
+ LCDD3_MARK, LCDD2_MARK, LCDD1_MARK, LCDD0_MARK,
+ LCDDON_MARK, LCDVCPWC_MARK, LCDVEPWC_MARK,
+ LCDVSYN_MARK, LCDDCK_MARK, LCDHSYN_MARK, LCDDISP_MARK,
+ LCDRS_MARK, LCDCS_MARK, LCDWR_MARK, LCDRD_MARK,
+ LCDLCLK_PTR_MARK, LCDLCLK_PTW_MARK,
+
+ IRQ0_MARK, IRQ1_MARK, IRQ2_MARK, IRQ3_MARK,
+ IRQ4_MARK, IRQ5_MARK, IRQ6_MARK, IRQ7_MARK,
+
+ AUDATA3_MARK, AUDATA2_MARK, AUDATA1_MARK, AUDATA0_MARK,
+ AUDCK_MARK, AUDSYNC_MARK,
+
+ SDHI0CD_PTD_MARK, SDHI0WP_PTD_MARK,
+ SDHI0D3_PTD_MARK, SDHI0D2_PTD_MARK,
+ SDHI0D1_PTD_MARK, SDHI0D0_PTD_MARK,
+ SDHI0CMD_PTD_MARK, SDHI0CLK_PTD_MARK,
+
+ SDHI0CD_PTS_MARK, SDHI0WP_PTS_MARK,
+ SDHI0D3_PTS_MARK, SDHI0D2_PTS_MARK,
+ SDHI0D1_PTS_MARK, SDHI0D0_PTS_MARK,
+ SDHI0CMD_PTS_MARK, SDHI0CLK_PTS_MARK,
+
+ SDHI1CD_MARK, SDHI1WP_MARK, SDHI1D3_MARK, SDHI1D2_MARK,
+ SDHI1D1_MARK, SDHI1D0_MARK, SDHI1CMD_MARK, SDHI1CLK_MARK,
+
+ SIUAFCK_MARK, SIUAILR_MARK, SIUAIBT_MARK, SIUAISLD_MARK,
+ SIUAOLR_MARK, SIUAOBT_MARK, SIUAOSLD_MARK, SIUAMCK_MARK,
+ SIUAISPD_MARK, SIUAOSPD_MARK,
+
+ SIUBFCK_MARK, SIUBILR_MARK, SIUBIBT_MARK, SIUBISLD_MARK,
+ SIUBOLR_MARK, SIUBOBT_MARK, SIUBOSLD_MARK, SIUBMCK_MARK,
+
+ IRDA_IN_MARK, IRDA_OUT_MARK,
+
+ DV_CLKI_MARK, DV_CLK_MARK, DV_HSYNC_MARK, DV_VSYNC_MARK,
+ DV_D15_MARK, DV_D14_MARK, DV_D13_MARK, DV_D12_MARK,
+ DV_D11_MARK, DV_D10_MARK, DV_D9_MARK, DV_D8_MARK,
+ DV_D7_MARK, DV_D6_MARK, DV_D5_MARK, DV_D4_MARK,
+ DV_D3_MARK, DV_D2_MARK, DV_D1_MARK, DV_D0_MARK,
+
+ KEYIN0_MARK, KEYIN1_MARK, KEYIN2_MARK, KEYIN3_MARK, KEYIN4_MARK,
+ KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK,
+ KEYOUT4_IN6_MARK, KEYOUT5_IN5_MARK,
+
+ MSIOF0_PTF_TXD_MARK, MSIOF0_PTF_RXD_MARK, MSIOF0_PTF_MCK_MARK,
+ MSIOF0_PTF_TSYNC_MARK, MSIOF0_PTF_TSCK_MARK, MSIOF0_PTF_RSYNC_MARK,
+ MSIOF0_PTF_RSCK_MARK, MSIOF0_PTF_SS1_MARK, MSIOF0_PTF_SS2_MARK,
+
+ MSIOF0_PTT_TXD_MARK, MSIOF0_PTT_RXD_MARK, MSIOF0_PTX_MCK_MARK,
+ MSIOF0_PTT_TSYNC_MARK, MSIOF0_PTT_TSCK_MARK, MSIOF0_PTT_RSYNC_MARK,
+ MSIOF0_PTT_RSCK_MARK, MSIOF0_PTT_SS1_MARK, MSIOF0_PTT_SS2_MARK,
+
+ MSIOF1_TXD_MARK, MSIOF1_RXD_MARK, MSIOF1_MCK_MARK,
+ MSIOF1_TSYNC_MARK, MSIOF1_TSCK_MARK, MSIOF1_RSYNC_MARK,
+ MSIOF1_RSCK_MARK, MSIOF1_SS1_MARK, MSIOF1_SS2_MARK,
+
+ TS0_SDAT_MARK, TS0_SCK_MARK, TS0_SDEN_MARK, TS0_SPSYNC_MARK,
+
+ FCE_MARK, NAF7_MARK, NAF6_MARK, NAF5_MARK, NAF4_MARK,
+ NAF3_MARK, NAF2_MARK, NAF1_MARK, NAF0_MARK, FCDE_MARK,
+ FOE_MARK, FSC_MARK, FWE_MARK, FRB_MARK,
+
+ DACK1_MARK, DREQ1_MARK, DACK0_MARK, DREQ0_MARK,
+
+ AN3_MARK, AN2_MARK, AN1_MARK, AN0_MARK, ADTRG_MARK,
+
+ STATUS0_MARK, PDSTATUS_MARK,
+
+ TPUTO3_MARK, TPUTO2_MARK, TPUTO1_MARK, TPUTO0_MARK,
+
+ D31_MARK, D30_MARK, D29_MARK, D28_MARK,
+ D27_MARK, D26_MARK, D25_MARK, D24_MARK,
+ D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+ D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+ IOIS16_MARK, WAIT_MARK, BS_MARK,
+ A25_MARK, A24_MARK, A23_MARK, A22_MARK,
+ CS6B_CE1B_MARK, CS6A_CE2B_MARK,
+ CS5B_CE1A_MARK, CS5A_CE2A_MARK,
+ WE3_ICIOWR_MARK, WE2_ICIORD_MARK,
+
+ IDED15_MARK, IDED14_MARK, IDED13_MARK, IDED12_MARK,
+ IDED11_MARK, IDED10_MARK, IDED9_MARK, IDED8_MARK,
+ IDED7_MARK, IDED6_MARK, IDED5_MARK, IDED4_MARK,
+ IDED3_MARK, IDED2_MARK, IDED1_MARK, IDED0_MARK,
+ DIRECTION_MARK, EXBUF_ENB_MARK, IDERST_MARK, IODACK_MARK,
+ IODREQ_MARK, IDEIORDY_MARK, IDEINT_MARK, IDEIOWR_MARK,
+ IDEIORD_MARK, IDECS1_MARK, IDECS0_MARK, IDEA2_MARK,
+ IDEA1_MARK, IDEA0_MARK,
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+ /* PTA GPIO */
+ PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT),
+ PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT),
+ PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT),
+ PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT, PTA4_IN_PU),
+ PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT, PTA3_IN_PU),
+ PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT, PTA2_IN_PU),
+ PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT, PTA1_IN_PU),
+ PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT, PTA0_IN_PU),
+
+ /* PTB GPIO */
+ PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT),
+ PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT),
+ PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT),
+ PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT),
+ PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT),
+ PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT, PTB2_IN_PU),
+ PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT, PTB1_IN_PU),
+ PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT),
+
+ /* PTC GPIO */
+ PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT),
+ PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT),
+ PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT),
+ PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT),
+ PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT),
+ PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT),
+ PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT),
+ PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT),
+
+ /* PTD GPIO */
+ PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT),
+ PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT),
+ PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT),
+ PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT),
+ PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT),
+ PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT),
+ PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT),
+ PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT),
+
+ /* PTE GPIO */
+ PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT),
+ PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT),
+ PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT),
+ PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT),
+ PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT),
+ PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT),
+
+ /* PTF GPIO */
+ PINMUX_DATA(PTF7_DATA, PTF7_IN, PTF7_OUT),
+ PINMUX_DATA(PTF6_DATA, PTF6_IN, PTF6_OUT),
+ PINMUX_DATA(PTF5_DATA, PTF5_IN, PTF5_OUT),
+ PINMUX_DATA(PTF4_DATA, PTF4_IN, PTF4_OUT),
+ PINMUX_DATA(PTF3_DATA, PTF3_IN, PTF3_OUT),
+ PINMUX_DATA(PTF2_DATA, PTF2_IN, PTF2_OUT),
+ PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_OUT),
+ PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT),
+
+ /* PTG GPIO */
+ PINMUX_DATA(PTG5_DATA, PTG5_OUT),
+ PINMUX_DATA(PTG4_DATA, PTG4_OUT),
+ PINMUX_DATA(PTG3_DATA, PTG3_OUT),
+ PINMUX_DATA(PTG2_DATA, PTG2_OUT),
+ PINMUX_DATA(PTG1_DATA, PTG1_OUT),
+ PINMUX_DATA(PTG0_DATA, PTG0_OUT),
+
+ /* PTH GPIO */
+ PINMUX_DATA(PTH7_DATA, PTH7_IN, PTH7_OUT),
+ PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT),
+ PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT),
+ PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT),
+ PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT),
+ PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT),
+ PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT),
+ PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT),
+
+ /* PTJ GPIO */
+ PINMUX_DATA(PTJ7_DATA, PTJ7_OUT),
+ PINMUX_DATA(PTJ5_DATA, PTJ5_OUT),
+ PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT),
+ PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT),
+ PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT),
+ PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT),
+
+ /* PTK GPIO */
+ PINMUX_DATA(PTK7_DATA, PTK7_IN, PTK7_OUT),
+ PINMUX_DATA(PTK6_DATA, PTK6_IN, PTK6_OUT),
+ PINMUX_DATA(PTK5_DATA, PTK5_IN, PTK5_OUT),
+ PINMUX_DATA(PTK4_DATA, PTK4_IN, PTK4_OUT),
+ PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT),
+ PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT),
+ PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT),
+ PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT),
+
+ /* PTL GPIO */
+ PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT),
+ PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT),
+ PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT),
+ PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT),
+ PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT),
+ PINMUX_DATA(PTL2_DATA, PTL2_IN, PTL2_OUT),
+ PINMUX_DATA(PTL1_DATA, PTL1_IN, PTL1_OUT),
+ PINMUX_DATA(PTL0_DATA, PTL0_IN, PTL0_OUT),
+
+ /* PTM GPIO */
+ PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT),
+ PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT),
+ PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT),
+ PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT),
+ PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT),
+ PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT),
+ PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT),
+ PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT),
+
+ /* PTN GPIO */
+ PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT),
+ PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT),
+ PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT),
+ PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT),
+ PINMUX_DATA(PTN3_DATA, PTN3_IN, PTN3_OUT),
+ PINMUX_DATA(PTN2_DATA, PTN2_IN, PTN2_OUT),
+ PINMUX_DATA(PTN1_DATA, PTN1_IN, PTN1_OUT),
+ PINMUX_DATA(PTN0_DATA, PTN0_IN, PTN0_OUT),
+
+ /* PTQ GPIO */
+ PINMUX_DATA(PTQ3_DATA, PTQ3_IN),
+ PINMUX_DATA(PTQ2_DATA, PTQ2_IN),
+ PINMUX_DATA(PTQ1_DATA, PTQ1_IN),
+ PINMUX_DATA(PTQ0_DATA, PTQ0_IN),
+
+ /* PTR GPIO */
+ PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT),
+ PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT),
+ PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT),
+ PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT),
+ PINMUX_DATA(PTR3_DATA, PTR3_IN),
+ PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_IN_PU),
+ PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT),
+ PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT),
+
+ /* PTS GPIO */
+ PINMUX_DATA(PTS7_DATA, PTS7_IN, PTS7_OUT),
+ PINMUX_DATA(PTS6_DATA, PTS6_IN, PTS6_OUT),
+ PINMUX_DATA(PTS5_DATA, PTS5_IN, PTS5_OUT),
+ PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT),
+ PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT),
+ PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT),
+ PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT),
+ PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT),
+
+ /* PTT GPIO */
+ PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT),
+ PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT),
+ PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT),
+ PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT),
+ PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT),
+ PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT),
+
+ /* PTU GPIO */
+ PINMUX_DATA(PTU5_DATA, PTU5_IN, PTU5_OUT),
+ PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT),
+ PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT),
+ PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT),
+ PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT),
+ PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT),
+
+ /* PTV GPIO */
+ PINMUX_DATA(PTV7_DATA, PTV7_IN, PTV7_OUT),
+ PINMUX_DATA(PTV6_DATA, PTV6_IN, PTV6_OUT),
+ PINMUX_DATA(PTV5_DATA, PTV5_IN, PTV5_OUT),
+ PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT),
+ PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT),
+ PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT),
+ PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT),
+ PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT),
+
+ /* PTW GPIO */
+ PINMUX_DATA(PTW7_DATA, PTW7_IN, PTW7_OUT),
+ PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_OUT),
+ PINMUX_DATA(PTW5_DATA, PTW5_IN, PTW5_OUT),
+ PINMUX_DATA(PTW4_DATA, PTW4_IN, PTW4_OUT),
+ PINMUX_DATA(PTW3_DATA, PTW3_IN, PTW3_OUT),
+ PINMUX_DATA(PTW2_DATA, PTW2_IN, PTW2_OUT),
+ PINMUX_DATA(PTW1_DATA, PTW1_IN, PTW1_OUT),
+ PINMUX_DATA(PTW0_DATA, PTW0_IN, PTW0_OUT),
+
+ /* PTX GPIO */
+ PINMUX_DATA(PTX7_DATA, PTX7_IN, PTX7_OUT),
+ PINMUX_DATA(PTX6_DATA, PTX6_IN, PTX6_OUT),
+ PINMUX_DATA(PTX5_DATA, PTX5_IN, PTX5_OUT),
+ PINMUX_DATA(PTX4_DATA, PTX4_IN, PTX4_OUT),
+ PINMUX_DATA(PTX3_DATA, PTX3_IN, PTX3_OUT),
+ PINMUX_DATA(PTX2_DATA, PTX2_IN, PTX2_OUT),
+ PINMUX_DATA(PTX1_DATA, PTX1_IN, PTX1_OUT),
+ PINMUX_DATA(PTX0_DATA, PTX0_IN, PTX0_OUT),
+
+ /* PTY GPIO */
+ PINMUX_DATA(PTY7_DATA, PTY7_IN, PTY7_OUT),
+ PINMUX_DATA(PTY6_DATA, PTY6_IN, PTY6_OUT),
+ PINMUX_DATA(PTY5_DATA, PTY5_IN, PTY5_OUT),
+ PINMUX_DATA(PTY4_DATA, PTY4_IN, PTY4_OUT),
+ PINMUX_DATA(PTY3_DATA, PTY3_IN, PTY3_OUT),
+ PINMUX_DATA(PTY2_DATA, PTY2_IN, PTY2_OUT),
+ PINMUX_DATA(PTY1_DATA, PTY1_IN, PTY1_OUT),
+ PINMUX_DATA(PTY0_DATA, PTY0_IN, PTY0_OUT),
+
+ /* PTZ GPIO */
+ PINMUX_DATA(PTZ7_DATA, PTZ7_IN, PTZ7_OUT),
+ PINMUX_DATA(PTZ6_DATA, PTZ6_IN, PTZ6_OUT),
+ PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_OUT),
+ PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_OUT),
+ PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_OUT),
+ PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_OUT),
+ PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_OUT),
+ PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT),
+
+ /* PTA FN */
+ PINMUX_DATA(D23_MARK, PSA15_PSA14_FN1, PTA7_FN),
+ PINMUX_DATA(KEYOUT2_MARK, PSA15_PSA14_FN2, PTA7_FN),
+ PINMUX_DATA(D22_MARK, PSA15_PSA14_FN1, PTA6_FN),
+ PINMUX_DATA(KEYOUT1_MARK, PSA15_PSA14_FN2, PTA6_FN),
+ PINMUX_DATA(D21_MARK, PSA15_PSA14_FN1, PTA5_FN),
+ PINMUX_DATA(KEYOUT0_MARK, PSA15_PSA14_FN2, PTA5_FN),
+ PINMUX_DATA(D20_MARK, PSA15_PSA14_FN1, PTA4_FN),
+ PINMUX_DATA(KEYIN4_MARK, PSA15_PSA14_FN2, PTA4_FN),
+ PINMUX_DATA(D19_MARK, PSA15_PSA14_FN1, PTA3_FN),
+ PINMUX_DATA(KEYIN3_MARK, PSA15_PSA14_FN2, PTA3_FN),
+ PINMUX_DATA(D18_MARK, PSA15_PSA14_FN1, PTA2_FN),
+ PINMUX_DATA(KEYIN2_MARK, PSA15_PSA14_FN2, PTA2_FN),
+ PINMUX_DATA(D17_MARK, PSA15_PSA14_FN1, PTA1_FN),
+ PINMUX_DATA(KEYIN1_MARK, PSA15_PSA14_FN2, PTA1_FN),
+ PINMUX_DATA(D16_MARK, PSA15_PSA14_FN1, PTA0_FN),
+ PINMUX_DATA(KEYIN0_MARK, PSA15_PSA14_FN2, PTA0_FN),
+
+ /* PTB FN */
+ PINMUX_DATA(D31_MARK, PTB7_FN),
+ PINMUX_DATA(D30_MARK, PTB6_FN),
+ PINMUX_DATA(D29_MARK, PTB5_FN),
+ PINMUX_DATA(D28_MARK, PTB4_FN),
+ PINMUX_DATA(D27_MARK, PTB3_FN),
+ PINMUX_DATA(D26_MARK, PSA15_PSA14_FN1, PTB2_FN),
+ PINMUX_DATA(KEYOUT5_IN5_MARK, PSA15_PSA14_FN2, PTB2_FN),
+ PINMUX_DATA(D25_MARK, PSA15_PSA14_FN1, PTB1_FN),
+ PINMUX_DATA(KEYOUT4_IN6_MARK, PSA15_PSA14_FN2, PTB1_FN),
+ PINMUX_DATA(D24_MARK, PSA15_PSA14_FN1, PTB0_FN),
+ PINMUX_DATA(KEYOUT3_MARK, PSA15_PSA14_FN2, PTB0_FN),
+
+ /* PTC FN */
+ PINMUX_DATA(IDED15_MARK, PSA11_PSA10_FN1, PTC7_FN),
+ PINMUX_DATA(SDHI1CD_MARK, PSA11_PSA10_FN2, PTC7_FN),
+ PINMUX_DATA(IDED14_MARK, PSA11_PSA10_FN1, PTC6_FN),
+ PINMUX_DATA(SDHI1WP_MARK, PSA11_PSA10_FN2, PTC6_FN),
+ PINMUX_DATA(IDED13_MARK, PSA11_PSA10_FN1, PTC5_FN),
+ PINMUX_DATA(SDHI1D3_MARK, PSA11_PSA10_FN2, PTC5_FN),
+ PINMUX_DATA(IDED12_MARK, PSA11_PSA10_FN1, PTC4_FN),
+ PINMUX_DATA(SDHI1D2_MARK, PSA11_PSA10_FN2, PTC4_FN),
+ PINMUX_DATA(IDED11_MARK, PSA11_PSA10_FN1, PTC3_FN),
+ PINMUX_DATA(SDHI1D1_MARK, PSA11_PSA10_FN2, PTC3_FN),
+ PINMUX_DATA(IDED10_MARK, PSA11_PSA10_FN1, PTC2_FN),
+ PINMUX_DATA(SDHI1D0_MARK, PSA11_PSA10_FN2, PTC2_FN),
+ PINMUX_DATA(IDED9_MARK, PSA11_PSA10_FN1, PTC1_FN),
+ PINMUX_DATA(SDHI1CMD_MARK, PSA11_PSA10_FN2, PTC1_FN),
+ PINMUX_DATA(IDED8_MARK, PSA11_PSA10_FN1, PTC0_FN),
+ PINMUX_DATA(SDHI1CLK_MARK, PSA11_PSA10_FN2, PTC0_FN),
+
+ /* PTD FN */
+ PINMUX_DATA(IDED7_MARK, PSA11_PSA10_FN1, PTD7_FN),
+ PINMUX_DATA(SDHI0CD_PTD_MARK, PSA11_PSA10_FN2, PTD7_FN),
+ PINMUX_DATA(IDED6_MARK, PSA11_PSA10_FN1, PTD6_FN),
+ PINMUX_DATA(SDHI0WP_PTD_MARK, PSA11_PSA10_FN2, PTD6_FN),
+ PINMUX_DATA(IDED5_MARK, PSA11_PSA10_FN1, PTD5_FN),
+ PINMUX_DATA(SDHI0D3_PTD_MARK, PSA11_PSA10_FN2, PTD5_FN),
+ PINMUX_DATA(IDED4_MARK, PSA11_PSA10_FN1, PTD4_FN),
+ PINMUX_DATA(SDHI0D2_PTD_MARK, PSA11_PSA10_FN2, PTD4_FN),
+ PINMUX_DATA(IDED3_MARK, PSA11_PSA10_FN1, PTD3_FN),
+ PINMUX_DATA(SDHI0D1_PTD_MARK, PSA11_PSA10_FN2, PTD3_FN),
+ PINMUX_DATA(IDED2_MARK, PSA11_PSA10_FN1, PTD2_FN),
+ PINMUX_DATA(SDHI0D0_PTD_MARK, PSA11_PSA10_FN2, PTD2_FN),
+ PINMUX_DATA(IDED1_MARK, PSA11_PSA10_FN1, PTD1_FN),
+ PINMUX_DATA(SDHI0CMD_PTD_MARK, PSA11_PSA10_FN2, PTD1_FN),
+ PINMUX_DATA(IDED0_MARK, PSA11_PSA10_FN1, PTD0_FN),
+ PINMUX_DATA(SDHI0CLK_PTD_MARK, PSA11_PSA10_FN2, PTD0_FN),
+
+ /* PTE FN */
+ PINMUX_DATA(DIRECTION_MARK, PSA11_PSA10_FN1, PTE5_FN),
+ PINMUX_DATA(SCIF5_PTE_SCK_MARK, PSA11_PSA10_FN2, PTE5_FN),
+ PINMUX_DATA(EXBUF_ENB_MARK, PSA11_PSA10_FN1, PTE4_FN),
+ PINMUX_DATA(SCIF5_PTE_RXD_MARK, PSA11_PSA10_FN2, PTE4_FN),
+ PINMUX_DATA(IDERST_MARK, PSA11_PSA10_FN1, PTE3_FN),
+ PINMUX_DATA(SCIF5_PTE_TXD_MARK, PSA11_PSA10_FN2, PTE3_FN),
+ PINMUX_DATA(IODACK_MARK, PSA11_PSA10_FN1, PTE2_FN),
+ PINMUX_DATA(SCIF4_PTE_SCK_MARK, PSA11_PSA10_FN2, PTE2_FN),
+ PINMUX_DATA(IODREQ_MARK, PSA11_PSA10_FN1, PTE1_FN),
+ PINMUX_DATA(SCIF4_PTE_RXD_MARK, PSA11_PSA10_FN2, PTE1_FN),
+ PINMUX_DATA(IDEIORDY_MARK, PSA11_PSA10_FN1, PTE0_FN),
+ PINMUX_DATA(SCIF4_PTE_TXD_MARK, PSA11_PSA10_FN2, PTE0_FN),
+
+ /* PTF FN */
+ PINMUX_DATA(IDEINT_MARK, PTF7_FN),
+ PINMUX_DATA(IDEIOWR_MARK, PSA5_PSA4_FN1, PTF6_FN),
+ PINMUX_DATA(MSIOF0_PTF_SS2_MARK, PSA5_PSA4_FN2, PTF6_FN),
+ PINMUX_DATA(MSIOF0_PTF_RSYNC_MARK, PSA5_PSA4_FN3, PTF6_FN),
+ PINMUX_DATA(IDEIORD_MARK, PSA5_PSA4_FN1, PTF5_FN),
+ PINMUX_DATA(MSIOF0_PTF_SS1_MARK, PSA5_PSA4_FN2, PTF5_FN),
+ PINMUX_DATA(MSIOF0_PTF_RSCK_MARK, PSA5_PSA4_FN3, PTF5_FN),
+ PINMUX_DATA(IDECS1_MARK, PSA11_PSA10_FN1, PTF4_FN),
+ PINMUX_DATA(MSIOF0_PTF_TSYNC_MARK, PSA11_PSA10_FN2, PTF4_FN),
+ PINMUX_DATA(IDECS0_MARK, PSA11_PSA10_FN1, PTF3_FN),
+ PINMUX_DATA(MSIOF0_PTF_TSCK_MARK, PSA11_PSA10_FN2, PTF3_FN),
+ PINMUX_DATA(IDEA2_MARK, PSA11_PSA10_FN1, PTF2_FN),
+ PINMUX_DATA(MSIOF0_PTF_RXD_MARK, PSA11_PSA10_FN2, PTF2_FN),
+ PINMUX_DATA(IDEA1_MARK, PSA11_PSA10_FN1, PTF1_FN),
+ PINMUX_DATA(MSIOF0_PTF_TXD_MARK, PSA11_PSA10_FN2, PTF1_FN),
+ PINMUX_DATA(IDEA0_MARK, PSA11_PSA10_FN1, PTF0_FN),
+ PINMUX_DATA(MSIOF0_PTF_MCK_MARK, PSA11_PSA10_FN2, PTF0_FN),
+
+ /* PTG FN */
+ PINMUX_DATA(AUDCK_MARK, PTG5_FN),
+ PINMUX_DATA(AUDSYNC_MARK, PTG4_FN),
+ PINMUX_DATA(AUDATA3_MARK, PSA3_PSA2_FN1, PTG3_FN),
+ PINMUX_DATA(TPUTO3_MARK, PSA3_PSA2_FN2, PTG3_FN),
+ PINMUX_DATA(AUDATA2_MARK, PSA3_PSA2_FN1, PTG2_FN),
+ PINMUX_DATA(TPUTO2_MARK, PSA3_PSA2_FN2, PTG2_FN),
+ PINMUX_DATA(AUDATA1_MARK, PSA3_PSA2_FN1, PTG1_FN),
+ PINMUX_DATA(TPUTO1_MARK, PSA3_PSA2_FN2, PTG1_FN),
+ PINMUX_DATA(AUDATA0_MARK, PSA3_PSA2_FN1, PTG0_FN),
+ PINMUX_DATA(TPUTO0_MARK, PSA3_PSA2_FN2, PTG0_FN),
+
+ /* PTG FN */
+ PINMUX_DATA(LCDVCPWC_MARK, PTH7_FN),
+ PINMUX_DATA(LCDRD_MARK, PSB15_PSB14_FN1, PTH6_FN),
+ PINMUX_DATA(DV_CLKI_MARK, PSB15_PSB14_FN2, PTH6_FN),
+ PINMUX_DATA(LCDVSYN_MARK, PSB15_PSB14_FN1, PTH5_FN),
+ PINMUX_DATA(DV_CLK_MARK, PSB15_PSB14_FN2, PTH5_FN),
+ PINMUX_DATA(LCDDISP_MARK, PSB13_PSB12_LCDC_RGB, PTH4_FN),
+ PINMUX_DATA(LCDRS_MARK, PSB13_PSB12_LCDC_SYS, PTH4_FN),
+ PINMUX_DATA(LCDHSYN_MARK, PSB13_PSB12_LCDC_RGB, PTH3_FN),
+ PINMUX_DATA(LCDCS_MARK, PSB13_PSB12_LCDC_SYS, PTH3_FN),
+ PINMUX_DATA(LCDDON_MARK, PTH2_FN),
+ PINMUX_DATA(LCDDCK_MARK, PSB13_PSB12_LCDC_RGB, PTH1_FN),
+ PINMUX_DATA(LCDWR_MARK, PSB13_PSB12_LCDC_SYS, PTH1_FN),
+ PINMUX_DATA(LCDVEPWC_MARK, PTH0_FN),
+
+ /* PTJ FN */
+ PINMUX_DATA(STATUS0_MARK, PTJ7_FN),
+ PINMUX_DATA(PDSTATUS_MARK, PTJ5_FN),
+ PINMUX_DATA(A25_MARK, PTJ3_FN),
+ PINMUX_DATA(A24_MARK, PTJ2_FN),
+ PINMUX_DATA(A23_MARK, PTJ1_FN),
+ PINMUX_DATA(A22_MARK, PTJ0_FN),
+
+ /* PTK FN */
+ PINMUX_DATA(SIUAFCK_MARK, PTK7_FN),
+ PINMUX_DATA(SIUAILR_MARK, PSB9_PSB8_FN1, PTK6_FN),
+ PINMUX_DATA(MSIOF1_SS2_MARK, PSB9_PSB8_FN2, PTK6_FN),
+ PINMUX_DATA(MSIOF1_RSYNC_MARK, PSB9_PSB8_FN3, PTK6_FN),
+ PINMUX_DATA(SIUAIBT_MARK, PSB9_PSB8_FN1, PTK5_FN),
+ PINMUX_DATA(MSIOF1_SS1_MARK, PSB9_PSB8_FN2, PTK5_FN),
+ PINMUX_DATA(MSIOF1_RSCK_MARK, PSB9_PSB8_FN3, PTK5_FN),
+ PINMUX_DATA(SIUAISLD_MARK, PSB7_PSB6_FN1, PTK4_FN),
+ PINMUX_DATA(MSIOF1_RXD_MARK, PSB7_PSB6_FN2, PTK4_FN),
+ PINMUX_DATA(SIUAOLR_MARK, PSB7_PSB6_FN1, PTK3_FN),
+ PINMUX_DATA(MSIOF1_TSYNC_MARK, PSB7_PSB6_FN2, PTK3_FN),
+ PINMUX_DATA(SIUAOBT_MARK, PSB7_PSB6_FN1, PTK2_FN),
+ PINMUX_DATA(MSIOF1_TSCK_MARK, PSB7_PSB6_FN2, PTK2_FN),
+ PINMUX_DATA(SIUAOSLD_MARK, PSB7_PSB6_FN1, PTK1_FN),
+ PINMUX_DATA(MSIOF1_RXD_MARK, PSB7_PSB6_FN2, PTK1_FN),
+ PINMUX_DATA(SIUAMCK_MARK, PSB7_PSB6_FN1, PTK0_FN),
+ PINMUX_DATA(MSIOF1_MCK_MARK, PSB7_PSB6_FN2, PTK0_FN),
+
+ /* PTL FN */
+ PINMUX_DATA(LCDD15_MARK, PSB5_PSB4_FN1, PTL7_FN),
+ PINMUX_DATA(DV_D15_MARK, PSB5_PSB4_FN2, PTL7_FN),
+ PINMUX_DATA(LCDD14_MARK, PSB5_PSB4_FN1, PTL6_FN),
+ PINMUX_DATA(DV_D14_MARK, PSB5_PSB4_FN2, PTL6_FN),
+ PINMUX_DATA(LCDD13_MARK, PSB5_PSB4_FN1, PTL5_FN),
+ PINMUX_DATA(DV_D13_MARK, PSB5_PSB4_FN2, PTL5_FN),
+ PINMUX_DATA(LCDD12_MARK, PSB5_PSB4_FN1, PTL4_FN),
+ PINMUX_DATA(DV_D12_MARK, PSB5_PSB4_FN2, PTL4_FN),
+ PINMUX_DATA(LCDD11_MARK, PSB5_PSB4_FN1, PTL3_FN),
+ PINMUX_DATA(DV_D11_MARK, PSB5_PSB4_FN2, PTL3_FN),
+ PINMUX_DATA(LCDD10_MARK, PSB5_PSB4_FN1, PTL2_FN),
+ PINMUX_DATA(DV_D10_MARK, PSB5_PSB4_FN2, PTL2_FN),
+ PINMUX_DATA(LCDD9_MARK, PSB5_PSB4_FN1, PTL1_FN),
+ PINMUX_DATA(DV_D9_MARK, PSB5_PSB4_FN2, PTL1_FN),
+ PINMUX_DATA(LCDD8_MARK, PSB5_PSB4_FN1, PTL0_FN),
+ PINMUX_DATA(DV_D8_MARK, PSB5_PSB4_FN2, PTL0_FN),
+
+ /* PTM FN */
+ PINMUX_DATA(LCDD7_MARK, PSB5_PSB4_FN1, PTM7_FN),
+ PINMUX_DATA(DV_D7_MARK, PSB5_PSB4_FN2, PTM7_FN),
+ PINMUX_DATA(LCDD6_MARK, PSB5_PSB4_FN1, PTM6_FN),
+ PINMUX_DATA(DV_D6_MARK, PSB5_PSB4_FN2, PTM6_FN),
+ PINMUX_DATA(LCDD5_MARK, PSB5_PSB4_FN1, PTM5_FN),
+ PINMUX_DATA(DV_D5_MARK, PSB5_PSB4_FN2, PTM5_FN),
+ PINMUX_DATA(LCDD4_MARK, PSB5_PSB4_FN1, PTM4_FN),
+ PINMUX_DATA(DV_D4_MARK, PSB5_PSB4_FN2, PTM4_FN),
+ PINMUX_DATA(LCDD3_MARK, PSB5_PSB4_FN1, PTM3_FN),
+ PINMUX_DATA(DV_D3_MARK, PSB5_PSB4_FN2, PTM3_FN),
+ PINMUX_DATA(LCDD2_MARK, PSB5_PSB4_FN1, PTM2_FN),
+ PINMUX_DATA(DV_D2_MARK, PSB5_PSB4_FN2, PTM2_FN),
+ PINMUX_DATA(LCDD1_MARK, PSB5_PSB4_FN1, PTM1_FN),
+ PINMUX_DATA(DV_D1_MARK, PSB5_PSB4_FN2, PTM1_FN),
+ PINMUX_DATA(LCDD0_MARK, PSB5_PSB4_FN1, PTM0_FN),
+ PINMUX_DATA(DV_D0_MARK, PSB5_PSB4_FN2, PTM0_FN),
+
+ /* PTN FN */
+ PINMUX_DATA(LCDD23_MARK, PSB3_PSB2_FN1, PTN7_FN),
+ PINMUX_DATA(SCIF5_PTN_SCK_MARK, PSB3_PSB2_FN2, PTN7_FN),
+ PINMUX_DATA(LCDD22_MARK, PSB3_PSB2_FN1, PTN6_FN),
+ PINMUX_DATA(SCIF5_PTN_RXD_MARK, PSB3_PSB2_FN2, PTN6_FN),
+ PINMUX_DATA(LCDD21_MARK, PSB3_PSB2_FN1, PTN5_FN),
+ PINMUX_DATA(SCIF5_PTN_TXD_MARK, PSB3_PSB2_FN2, PTN5_FN),
+ PINMUX_DATA(LCDD20_MARK, PSB3_PSB2_FN1, PTN4_FN),
+ PINMUX_DATA(SCIF4_PTN_SCK_MARK, PSB3_PSB2_FN2, PTN4_FN),
+ PINMUX_DATA(LCDD19_MARK, PSB3_PSB2_FN1, PTN3_FN),
+ PINMUX_DATA(SCIF4_PTN_RXD_MARK, PSB3_PSB2_FN2, PTN3_FN),
+ PINMUX_DATA(LCDD18_MARK, PSB3_PSB2_FN1, PTN2_FN),
+ PINMUX_DATA(SCIF4_PTN_TXD_MARK, PSB3_PSB2_FN2, PTN2_FN),
+ PINMUX_DATA(LCDD17_MARK, PSB5_PSB4_FN1, PTN1_FN),
+ PINMUX_DATA(DV_VSYNC_MARK, PSB5_PSB4_FN2, PTN1_FN),
+ PINMUX_DATA(LCDD16_MARK, PSB5_PSB4_FN1, PTN0_FN),
+ PINMUX_DATA(DV_HSYNC_MARK, PSB5_PSB4_FN2, PTN0_FN),
+
+ /* PTQ FN */
+ PINMUX_DATA(AN3_MARK, PTQ3_FN),
+ PINMUX_DATA(AN2_MARK, PTQ2_FN),
+ PINMUX_DATA(AN1_MARK, PTQ1_FN),
+ PINMUX_DATA(AN0_MARK, PTQ0_FN),
+
+ /* PTR FN */
+ PINMUX_DATA(CS6B_CE1B_MARK, PTR7_FN),
+ PINMUX_DATA(CS6A_CE2B_MARK, PTR6_FN),
+ PINMUX_DATA(CS5B_CE1A_MARK, PTR5_FN),
+ PINMUX_DATA(CS5A_CE2A_MARK, PTR4_FN),
+ PINMUX_DATA(IOIS16_MARK, PSA13_PSA12_FN1, PTR3_FN),
+ PINMUX_DATA(LCDLCLK_PTR_MARK, PSA13_PSA12_FN2, PTR3_FN),
+ PINMUX_DATA(WAIT_MARK, PTR2_FN),
+ PINMUX_DATA(WE3_ICIOWR_MARK, PTR1_FN),
+ PINMUX_DATA(WE2_ICIORD_MARK, PTR0_FN),
+
+ /* PTS FN */
+ PINMUX_DATA(SCIF1_PTS_SCK_MARK, PSC15_PSC14_FN1, PTS7_FN),
+ PINMUX_DATA(SDHI0CD_PTS_MARK, PSC15_PSC14_FN2, PTS7_FN),
+ PINMUX_DATA(SCIF1_PTS_RXD_MARK, PSC15_PSC14_FN1, PTS6_FN),
+ PINMUX_DATA(SDHI0WP_PTS_MARK, PSC15_PSC14_FN2, PTS6_FN),
+ PINMUX_DATA(SCIF1_PTS_TXD_MARK, PSC15_PSC14_FN1, PTS5_FN),
+ PINMUX_DATA(SDHI0D3_PTS_MARK, PSC15_PSC14_FN2, PTS5_FN),
+ PINMUX_DATA(SCIF3_PTS_CTS_MARK, PSC15_PSC14_FN1, PTS4_FN),
+ PINMUX_DATA(SDHI0D2_PTS_MARK, PSC15_PSC14_FN2, PTS4_FN),
+ PINMUX_DATA(SCIF3_PTS_RTS_MARK, PSC15_PSC14_FN1, PTS3_FN),
+ PINMUX_DATA(SDHI0D1_PTS_MARK, PSC15_PSC14_FN2, PTS3_FN),
+ PINMUX_DATA(SCIF3_PTS_SCK_MARK, PSC15_PSC14_FN1, PTS2_FN),
+ PINMUX_DATA(SDHI0D0_PTS_MARK, PSC15_PSC14_FN2, PTS2_FN),
+ PINMUX_DATA(SCIF3_PTS_RXD_MARK, PSC15_PSC14_FN1, PTS1_FN),
+ PINMUX_DATA(SDHI0CMD_PTS_MARK, PSC15_PSC14_FN2, PTS1_FN),
+ PINMUX_DATA(SCIF3_PTS_TXD_MARK, PSC15_PSC14_FN1, PTS0_FN),
+ PINMUX_DATA(SDHI0CLK_PTS_MARK, PSC15_PSC14_FN2, PTS0_FN),
+
+ /* PTT FN */
+ PINMUX_DATA(SCIF0_PTT_SCK_MARK, PSC13_PSC12_FN1, PTT5_FN),
+ PINMUX_DATA(MSIOF0_PTT_TSCK_MARK, PSC13_PSC12_FN2, PTT5_FN),
+ PINMUX_DATA(SCIF0_PTT_RXD_MARK, PSC13_PSC12_FN1, PTT4_FN),
+ PINMUX_DATA(MSIOF0_PTT_RXD_MARK, PSC13_PSC12_FN2, PTT4_FN),
+ PINMUX_DATA(SCIF0_PTT_TXD_MARK, PSC13_PSC12_FN1, PTT3_FN),
+ PINMUX_DATA(MSIOF0_PTT_TXD_MARK, PSC13_PSC12_FN2, PTT3_FN),
+ PINMUX_DATA(SCIF2_PTT_SCK_MARK, PSC11_PSC10_FN1, PTT2_FN),
+ PINMUX_DATA(MSIOF0_PTT_TSYNC_MARK, PSC11_PSC10_FN2, PTT2_FN),
+ PINMUX_DATA(SCIF2_PTT_RXD_MARK, PSC11_PSC10_FN1, PTT1_FN),
+ PINMUX_DATA(MSIOF0_PTT_SS1_MARK, PSC11_PSC10_FN2, PTT1_FN),
+ PINMUX_DATA(MSIOF0_PTT_RSCK_MARK, PSC11_PSC10_FN3, PTT1_FN),
+ PINMUX_DATA(SCIF2_PTT_TXD_MARK, PSC11_PSC10_FN1, PTT0_FN),
+ PINMUX_DATA(MSIOF0_PTT_SS2_MARK, PSC11_PSC10_FN2, PTT0_FN),
+ PINMUX_DATA(MSIOF0_PTT_RSYNC_MARK, PSC11_PSC10_FN3, PTT0_FN),
+
+ /* PTU FN */
+ PINMUX_DATA(FCDE_MARK, PSC9_PSC8_FN1, PTU5_FN),
+ PINMUX_DATA(SCIF0_PTU_SCK_MARK, PSC9_PSC8_FN2, PTU5_FN),
+ PINMUX_DATA(FSC_MARK, PSC9_PSC8_FN1, PTU4_FN),
+ PINMUX_DATA(SCIF0_PTU_RXD_MARK, PSC9_PSC8_FN2, PTU4_FN),
+ PINMUX_DATA(FWE_MARK, PSC9_PSC8_FN1, PTU3_FN),
+ PINMUX_DATA(SCIF0_PTU_TXD_MARK, PSC9_PSC8_FN2, PTU3_FN),
+ PINMUX_DATA(FOE_MARK, PSC7_PSC6_FN1, PTU2_FN),
+ PINMUX_DATA(SCIF2_PTU_SCK_MARK, PSC7_PSC6_FN2, PTU2_FN),
+ PINMUX_DATA(VIO_VD2_MARK, PSC7_PSC6_FN3, PTU2_FN),
+ PINMUX_DATA(FRB_MARK, PSC7_PSC6_FN1, PTU1_FN),
+ PINMUX_DATA(SCIF2_PTU_RXD_MARK, PSC7_PSC6_FN2, PTU1_FN),
+ PINMUX_DATA(VIO_CLK2_MARK, PSC7_PSC6_FN3, PTU1_FN),
+ PINMUX_DATA(FCE_MARK, PSC7_PSC6_FN1, PTU0_FN),
+ PINMUX_DATA(SCIF2_PTU_TXD_MARK, PSC7_PSC6_FN2, PTU0_FN),
+ PINMUX_DATA(VIO_HD2_MARK, PSC7_PSC6_FN3, PTU0_FN),
+
+ /* PTV FN */
+ PINMUX_DATA(NAF7_MARK, PSC7_PSC6_FN1, PTV7_FN),
+ PINMUX_DATA(SCIF1_PTV_SCK_MARK, PSC7_PSC6_FN2, PTV7_FN),
+ PINMUX_DATA(VIO_D15_MARK, PSC7_PSC6_FN3, PTV7_FN),
+ PINMUX_DATA(NAF6_MARK, PSC7_PSC6_FN1, PTV6_FN),
+ PINMUX_DATA(SCIF1_PTV_RXD_MARK, PSC7_PSC6_FN2, PTV6_FN),
+ PINMUX_DATA(VIO_D14_MARK, PSC7_PSC6_FN3, PTV6_FN),
+ PINMUX_DATA(NAF5_MARK, PSC7_PSC6_FN1, PTV5_FN),
+ PINMUX_DATA(SCIF1_PTV_TXD_MARK, PSC7_PSC6_FN2, PTV5_FN),
+ PINMUX_DATA(VIO_D13_MARK, PSC7_PSC6_FN3, PTV5_FN),
+ PINMUX_DATA(NAF4_MARK, PSC7_PSC6_FN1, PTV4_FN),
+ PINMUX_DATA(SCIF3_PTV_CTS_MARK, PSC7_PSC6_FN2, PTV4_FN),
+ PINMUX_DATA(VIO_D12_MARK, PSC7_PSC6_FN3, PTV4_FN),
+ PINMUX_DATA(NAF3_MARK, PSC7_PSC6_FN1, PTV3_FN),
+ PINMUX_DATA(SCIF3_PTV_RTS_MARK, PSC7_PSC6_FN2, PTV3_FN),
+ PINMUX_DATA(VIO_D11_MARK, PSC7_PSC6_FN3, PTV3_FN),
+ PINMUX_DATA(NAF2_MARK, PSC7_PSC6_FN1, PTV2_FN),
+ PINMUX_DATA(SCIF3_PTV_SCK_MARK, PSC7_PSC6_FN2, PTV2_FN),
+ PINMUX_DATA(VIO_D10_MARK, PSC7_PSC6_FN3, PTV2_FN),
+ PINMUX_DATA(NAF1_MARK, PSC7_PSC6_FN1, PTV1_FN),
+ PINMUX_DATA(SCIF3_PTV_RXD_MARK, PSC7_PSC6_FN2, PTV1_FN),
+ PINMUX_DATA(VIO_D9_MARK, PSC7_PSC6_FN3, PTV1_FN),
+ PINMUX_DATA(NAF0_MARK, PSC7_PSC6_FN1, PTV0_FN),
+ PINMUX_DATA(SCIF3_PTV_TXD_MARK, PSC7_PSC6_FN2, PTV0_FN),
+ PINMUX_DATA(VIO_D8_MARK, PSC7_PSC6_FN3, PTV0_FN),
+
+ /* PTW FN */
+ PINMUX_DATA(IRQ7_MARK, PTW7_FN),
+ PINMUX_DATA(IRQ6_MARK, PTW6_FN),
+ PINMUX_DATA(IRQ5_MARK, PTW5_FN),
+ PINMUX_DATA(IRQ4_MARK, PSD15_PSD14_FN1, PTW4_FN),
+ PINMUX_DATA(LCDLCLK_PTW_MARK, PSD15_PSD14_FN2, PTW4_FN),
+ PINMUX_DATA(IRQ3_MARK, PSD13_PSD12_FN1, PTW3_FN),
+ PINMUX_DATA(ADTRG_MARK, PSD13_PSD12_FN2, PTW3_FN),
+ PINMUX_DATA(IRQ2_MARK, PSD11_PSD10_FN1, PTW2_FN),
+ PINMUX_DATA(BS_MARK, PSD11_PSD10_FN2, PTW2_FN),
+ PINMUX_DATA(VIO_CKO_MARK, PSD11_PSD10_FN3, PTW2_FN),
+ PINMUX_DATA(IRQ1_MARK, PSD9_PSD8_FN1, PTW1_FN),
+ PINMUX_DATA(SIUAISPD_MARK, PSD9_PSD8_FN2, PTW1_FN),
+ PINMUX_DATA(IRQ0_MARK, PSD7_PSD6_FN1, PTW0_FN),
+ PINMUX_DATA(SIUAOSPD_MARK, PSD7_PSD6_FN2, PTW0_FN),
+
+ /* PTX FN */
+ PINMUX_DATA(DACK1_MARK, PTX7_FN),
+ PINMUX_DATA(DREQ1_MARK, PSD3_PSD2_FN1, PTX6_FN),
+ PINMUX_DATA(MSIOF0_PTX_MCK_MARK, PSD3_PSD2_FN2, PTX6_FN),
+ PINMUX_DATA(DACK1_MARK, PTX5_FN),
+ PINMUX_DATA(IRDA_OUT_MARK, PSD5_PSD4_FN2, PTX5_FN),
+ PINMUX_DATA(DREQ1_MARK, PTX4_FN),
+ PINMUX_DATA(IRDA_IN_MARK, PSD5_PSD4_FN2, PTX4_FN),
+ PINMUX_DATA(TS0_SDAT_MARK, PTX3_FN),
+ PINMUX_DATA(TS0_SCK_MARK, PTX2_FN),
+ PINMUX_DATA(TS0_SDEN_MARK, PTX1_FN),
+ PINMUX_DATA(TS0_SPSYNC_MARK, PTX0_FN),
+
+ /* PTY FN */
+ PINMUX_DATA(VIO_D7_MARK, PTY7_FN),
+ PINMUX_DATA(VIO_D6_MARK, PTY6_FN),
+ PINMUX_DATA(VIO_D5_MARK, PTY5_FN),
+ PINMUX_DATA(VIO_D4_MARK, PTY4_FN),
+ PINMUX_DATA(VIO_D3_MARK, PTY3_FN),
+ PINMUX_DATA(VIO_D2_MARK, PTY2_FN),
+ PINMUX_DATA(VIO_D1_MARK, PTY1_FN),
+ PINMUX_DATA(VIO_D0_MARK, PTY0_FN),
+
+ /* PTZ FN */
+ PINMUX_DATA(SIUBOBT_MARK, PTZ7_FN),
+ PINMUX_DATA(SIUBOLR_MARK, PTZ6_FN),
+ PINMUX_DATA(SIUBOSLD_MARK, PTZ5_FN),
+ PINMUX_DATA(SIUBMCK_MARK, PTZ4_FN),
+ PINMUX_DATA(VIO_FLD_MARK, PSD1_PSD0_FN1, PTZ3_FN),
+ PINMUX_DATA(SIUBFCK_MARK, PSD1_PSD0_FN2, PTZ3_FN),
+ PINMUX_DATA(VIO_HD1_MARK, PSD1_PSD0_FN1, PTZ2_FN),
+ PINMUX_DATA(SIUBILR_MARK, PSD1_PSD0_FN2, PTZ2_FN),
+ PINMUX_DATA(VIO_VD1_MARK, PSD1_PSD0_FN1, PTZ1_FN),
+ PINMUX_DATA(SIUBIBT_MARK, PSD1_PSD0_FN2, PTZ1_FN),
+ PINMUX_DATA(VIO_CLK1_MARK, PSD1_PSD0_FN1, PTZ0_FN),
+ PINMUX_DATA(SIUBISLD_MARK, PSD1_PSD0_FN2, PTZ0_FN),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ /* PTA */
+ PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
+ PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
+ PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
+ PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
+ PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
+ PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
+ PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
+ PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+
+ /* PTB */
+ PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
+ PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
+ PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
+ PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
+ PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
+ PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
+ PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
+ PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+
+ /* PTC */
+ PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
+ PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
+ PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
+ PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
+ PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
+ PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
+ PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
+ PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+
+ /* PTD */
+ PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
+ PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
+ PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
+ PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
+ PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
+ PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
+ PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
+ PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+
+ /* PTE */
+ PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
+ PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
+ PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
+ PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
+ PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
+ PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+
+ /* PTF */
+ PINMUX_GPIO(GPIO_PTF7, PTF7_DATA),
+ PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
+ PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
+ PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
+ PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
+ PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
+ PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
+ PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+
+ /* PTG */
+ PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
+ PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
+ PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
+ PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
+ PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
+ PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+
+ /* PTH */
+ PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
+ PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
+ PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
+ PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
+ PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
+ PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
+ PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
+ PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+
+ /* PTJ */
+ PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
+ PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
+ PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
+ PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
+ PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
+ PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+
+ /* PTK */
+ PINMUX_GPIO(GPIO_PTK7, PTK7_DATA),
+ PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
+ PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
+ PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
+ PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
+ PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
+ PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
+ PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+
+ /* PTL */
+ PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
+ PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
+ PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
+ PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
+ PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
+ PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
+ PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
+ PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
+
+ /* PTM */
+ PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
+ PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
+ PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
+ PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
+ PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
+ PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
+ PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
+ PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+
+ /* PTN */
+ PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
+ PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
+ PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
+ PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
+ PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
+ PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
+ PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
+ PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
+
+ /* PTQ */
+ PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
+ PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
+ PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
+ PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
+
+ /* PTR */
+ PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
+ PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
+ PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
+ PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
+ PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
+ PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
+ PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
+ PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+
+ /* PTS */
+ PINMUX_GPIO(GPIO_PTS7, PTS7_DATA),
+ PINMUX_GPIO(GPIO_PTS6, PTS6_DATA),
+ PINMUX_GPIO(GPIO_PTS5, PTS5_DATA),
+ PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
+ PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
+ PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
+ PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
+ PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+
+ /* PTT */
+ PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
+ PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
+ PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
+ PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
+ PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
+ PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+
+ /* PTU */
+ PINMUX_GPIO(GPIO_PTU5, PTU5_DATA),
+ PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
+ PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
+ PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
+ PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
+ PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+
+ /* PTV */
+ PINMUX_GPIO(GPIO_PTV7, PTV7_DATA),
+ PINMUX_GPIO(GPIO_PTV6, PTV6_DATA),
+ PINMUX_GPIO(GPIO_PTV5, PTV5_DATA),
+ PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
+ PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
+ PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
+ PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
+ PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+
+ /* PTW */
+ PINMUX_GPIO(GPIO_PTW7, PTW7_DATA),
+ PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
+ PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
+ PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
+ PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
+ PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
+ PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
+ PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
+
+ /* PTX */
+ PINMUX_GPIO(GPIO_PTX7, PTX7_DATA),
+ PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
+ PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
+ PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
+ PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
+ PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
+ PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
+ PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
+
+ /* PTY */
+ PINMUX_GPIO(GPIO_PTY7, PTY7_DATA),
+ PINMUX_GPIO(GPIO_PTY6, PTY6_DATA),
+ PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
+ PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
+ PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
+ PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
+ PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
+ PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
+
+ /* PTZ */
+ PINMUX_GPIO(GPIO_PTZ7, PTZ7_DATA),
+ PINMUX_GPIO(GPIO_PTZ6, PTZ6_DATA),
+ PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
+ PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
+ PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
+ PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
+ PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
+ PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
+
+ /* SCIF0 */
+ PINMUX_GPIO(GPIO_FN_SCIF0_PTT_TXD, SCIF0_PTT_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_PTT_RXD, SCIF0_PTT_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_PTT_SCK, SCIF0_PTT_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_PTU_TXD, SCIF0_PTU_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_PTU_RXD, SCIF0_PTU_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_PTU_SCK, SCIF0_PTU_SCK_MARK),
+
+ /* SCIF1 */
+ PINMUX_GPIO(GPIO_FN_SCIF1_PTS_TXD, SCIF1_PTS_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_PTS_RXD, SCIF1_PTS_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_PTS_SCK, SCIF1_PTS_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_PTV_TXD, SCIF1_PTV_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_PTV_RXD, SCIF1_PTV_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_PTV_SCK, SCIF1_PTV_SCK_MARK),
+
+ /* SCIF2 */
+ PINMUX_GPIO(GPIO_FN_SCIF2_PTT_TXD, SCIF2_PTT_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_PTT_RXD, SCIF2_PTT_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_PTT_SCK, SCIF2_PTT_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_PTU_TXD, SCIF2_PTU_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_PTU_RXD, SCIF2_PTU_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_PTU_SCK, SCIF2_PTU_SCK_MARK),
+
+ /* SCIF3 */
+ PINMUX_GPIO(GPIO_FN_SCIF3_PTS_TXD, SCIF3_PTS_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_PTS_RXD, SCIF3_PTS_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_PTS_SCK, SCIF3_PTS_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_PTS_RTS, SCIF3_PTS_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_PTS_CTS, SCIF3_PTS_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_PTV_TXD, SCIF3_PTV_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_PTV_RXD, SCIF3_PTV_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_PTV_SCK, SCIF3_PTV_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_PTV_RTS, SCIF3_PTV_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_PTV_CTS, SCIF3_PTV_CTS_MARK),
+
+ /* SCIF4 */
+ PINMUX_GPIO(GPIO_FN_SCIF4_PTE_TXD, SCIF4_PTE_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_PTE_RXD, SCIF4_PTE_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_PTE_SCK, SCIF4_PTE_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_PTN_TXD, SCIF4_PTN_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_PTN_RXD, SCIF4_PTN_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_PTN_SCK, SCIF4_PTN_SCK_MARK),
+
+ /* SCIF5 */
+ PINMUX_GPIO(GPIO_FN_SCIF5_PTE_TXD, SCIF5_PTE_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_PTE_RXD, SCIF5_PTE_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_PTE_SCK, SCIF5_PTE_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_PTN_TXD, SCIF5_PTN_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_PTN_RXD, SCIF5_PTN_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_PTN_SCK, SCIF5_PTN_SCK_MARK),
+
+ /* CEU */
+ PINMUX_GPIO(GPIO_FN_VIO_D15, VIO_D15_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D14, VIO_D14_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D13, VIO_D13_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D12, VIO_D12_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D11, VIO_D11_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D10, VIO_D10_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D9, VIO_D9_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D8, VIO_D8_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D7, VIO_D7_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D6, VIO_D6_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D5, VIO_D5_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D4, VIO_D4_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D3, VIO_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D2, VIO_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D1, VIO_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_D0, VIO_D0_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_CLK1, VIO_CLK1_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_VD1, VIO_VD1_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_HD1, VIO_HD1_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_FLD, VIO_FLD_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_CKO, VIO_CKO_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_VD2, VIO_VD2_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_HD2, VIO_HD2_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO_CLK2, VIO_CLK2_MARK),
+
+ /* LCDC */
+ PINMUX_GPIO(GPIO_FN_LCDD23, LCDD23_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD22, LCDD22_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD21, LCDD21_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD20, LCDD20_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD19, LCDD19_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD18, LCDD18_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD17, LCDD17_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD16, LCDD16_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD15, LCDD15_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD14, LCDD14_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD13, LCDD13_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD12, LCDD12_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD11, LCDD11_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD10, LCDD10_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD9, LCDD9_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD8, LCDD8_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD7, LCDD7_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD6, LCDD6_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD5, LCDD5_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD4, LCDD4_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD3, LCDD3_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD2, LCDD2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD1, LCDD1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD0, LCDD0_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDLCLK_PTR, LCDLCLK_PTR_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDLCLK_PTW, LCDLCLK_PTW_MARK),
+ /* Main LCD */
+ PINMUX_GPIO(GPIO_FN_LCDDON, LCDDON_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVCPWC, LCDVCPWC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVEPWC, LCDVEPWC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVSYN, LCDVSYN_MARK),
+ /* Main LCD - RGB Mode */
+ PINMUX_GPIO(GPIO_FN_LCDDCK, LCDDCK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDHSYN, LCDHSYN_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDDISP, LCDDISP_MARK),
+ /* Main LCD - SYS Mode */
+ PINMUX_GPIO(GPIO_FN_LCDRS, LCDRS_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDCS, LCDCS_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDWR, LCDWR_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDRD, LCDRD_MARK),
+
+ /* IRQ */
+ PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3, IRQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4, IRQ4_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6, IRQ6_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ7, IRQ7_MARK),
+
+ /* AUD */
+ PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
+
+ /* SDHI0 (PTD) */
+ PINMUX_GPIO(GPIO_FN_SDHI0CD_PTD, SDHI0CD_PTD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0WP_PTD, SDHI0WP_PTD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D3_PTD, SDHI0D3_PTD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D2_PTD, SDHI0D2_PTD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D1_PTD, SDHI0D1_PTD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D0_PTD, SDHI0D0_PTD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0CMD_PTD, SDHI0CMD_PTD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0CLK_PTD, SDHI0CLK_PTD_MARK),
+
+ /* SDHI0 (PTS) */
+ PINMUX_GPIO(GPIO_FN_SDHI0CD_PTS, SDHI0CD_PTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0WP_PTS, SDHI0WP_PTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D3_PTS, SDHI0D3_PTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D2_PTS, SDHI0D2_PTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D1_PTS, SDHI0D1_PTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D0_PTS, SDHI0D0_PTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0CMD_PTS, SDHI0CMD_PTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0CLK_PTS, SDHI0CLK_PTS_MARK),
+
+ /* SDHI1 */
+ PINMUX_GPIO(GPIO_FN_SDHI1CD, SDHI1CD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1WP, SDHI1WP_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1D3, SDHI1D3_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1D2, SDHI1D2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1D1, SDHI1D1_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1D0, SDHI1D0_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1CMD, SDHI1CMD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1CLK, SDHI1CLK_MARK),
+
+ /* SIUA */
+ PINMUX_GPIO(GPIO_FN_SIUAFCK, SIUAFCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAILR, SIUAILR_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAIBT, SIUAIBT_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAISLD, SIUAISLD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAOLR, SIUAOLR_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAOBT, SIUAOBT_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAOSLD, SIUAOSLD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAMCK, SIUAMCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAISPD, SIUAISPD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUAOSPD, SIUAOSPD_MARK),
+
+ /* SIUB */
+ PINMUX_GPIO(GPIO_FN_SIUBFCK, SIUBFCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBILR, SIUBILR_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBIBT, SIUBIBT_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBISLD, SIUBISLD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBOLR, SIUBOLR_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBOBT, SIUBOBT_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBOSLD, SIUBOSLD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIUBMCK, SIUBMCK_MARK),
+
+ /* IRDA */
+ PINMUX_GPIO(GPIO_FN_IRDA_IN, IRDA_IN_MARK),
+ PINMUX_GPIO(GPIO_FN_IRDA_OUT, IRDA_OUT_MARK),
+
+ /* VOU */
+ PINMUX_GPIO(GPIO_FN_DV_CLKI, DV_CLKI_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D15, DV_D15_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D14, DV_D14_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D13, DV_D13_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D12, DV_D12_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D11, DV_D11_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D10, DV_D10_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D9, DV_D9_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D8, DV_D8_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D7, DV_D7_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D6, DV_D6_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D5, DV_D5_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D4, DV_D4_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D3, DV_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D2, DV_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D1, DV_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D0, DV_D0_MARK),
+
+ /* KEYSC */
+ PINMUX_GPIO(GPIO_FN_KEYIN0, KEYIN0_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN1, KEYIN1_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN2, KEYIN2_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN3, KEYIN3_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN4, KEYIN4_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT0, KEYOUT0_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT1, KEYOUT1_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT2, KEYOUT2_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT3, KEYOUT3_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT4_IN6, KEYOUT4_IN6_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT5_IN5, KEYOUT5_IN5_MARK),
+
+ /* MSIOF0 (PTF) */
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_TXD, MSIOF0_PTF_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_RXD, MSIOF0_PTF_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_MCK, MSIOF0_PTF_MCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_TSYNC, MSIOF0_PTF_TSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_TSCK, MSIOF0_PTF_TSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_RSYNC, MSIOF0_PTF_RSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_RSCK, MSIOF0_PTF_RSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_SS1, MSIOF0_PTF_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTF_SS2, MSIOF0_PTF_SS2_MARK),
+
+ /* MSIOF0 (PTT+PTX) */
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_TXD, MSIOF0_PTT_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_RXD, MSIOF0_PTT_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTX_MCK, MSIOF0_PTX_MCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_TSYNC, MSIOF0_PTT_TSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_TSCK, MSIOF0_PTT_TSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_RSYNC, MSIOF0_PTT_RSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_RSCK, MSIOF0_PTT_RSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_SS1, MSIOF0_PTT_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_PTT_SS2, MSIOF0_PTT_SS2_MARK),
+
+ /* MSIOF1 */
+ PINMUX_GPIO(GPIO_FN_MSIOF1_TXD, MSIOF1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_RXD, MSIOF1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_MCK, MSIOF1_MCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_TSYNC, MSIOF1_TSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_TSCK, MSIOF1_TSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_RSYNC, MSIOF1_RSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_RSCK, MSIOF1_RSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_SS1, MSIOF1_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_SS2, MSIOF1_SS2_MARK),
+
+ /* TSIF */
+ PINMUX_GPIO(GPIO_FN_TS0_SDAT, TS0_SDAT_MARK),
+ PINMUX_GPIO(GPIO_FN_TS0_SCK, TS0_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_TS0_SDEN, TS0_SDEN_MARK),
+ PINMUX_GPIO(GPIO_FN_TS0_SPSYNC, TS0_SPSYNC_MARK),
+
+ /* FLCTL */
+ PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF7, NAF7_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF6, NAF6_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF5, NAF5_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF4, NAF4_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF3, NAF3_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF2, NAF2_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF1, NAF1_MARK),
+ PINMUX_GPIO(GPIO_FN_NAF0, NAF0_MARK),
+ PINMUX_GPIO(GPIO_FN_FCDE, FCDE_MARK),
+ PINMUX_GPIO(GPIO_FN_FOE, FOE_MARK),
+ PINMUX_GPIO(GPIO_FN_FSC, FSC_MARK),
+ PINMUX_GPIO(GPIO_FN_FWE, FWE_MARK),
+ PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+
+ /* DMAC */
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+
+ /* ADC */
+ PINMUX_GPIO(GPIO_FN_AN3, AN3_MARK),
+ PINMUX_GPIO(GPIO_FN_AN2, AN2_MARK),
+ PINMUX_GPIO(GPIO_FN_AN1, AN1_MARK),
+ PINMUX_GPIO(GPIO_FN_AN0, AN0_MARK),
+ PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
+
+ /* CPG */
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
+ PINMUX_GPIO(GPIO_FN_PDSTATUS, PDSTATUS_MARK),
+
+ /* TPU */
+ PINMUX_GPIO(GPIO_FN_TPUTO0, TPUTO0_MARK),
+ PINMUX_GPIO(GPIO_FN_TPUTO1, TPUTO1_MARK),
+ PINMUX_GPIO(GPIO_FN_TPUTO2, TPUTO2_MARK),
+ PINMUX_GPIO(GPIO_FN_TPUTO3, TPUTO3_MARK),
+
+ /* BSC */
+ PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
+ PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
+ PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
+ PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
+ PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
+ PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
+ PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
+ PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
+ PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
+ PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
+ PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
+ PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
+ PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
+ PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
+ PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
+ PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+ PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+ PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+ PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+ PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6B_CE1B, CS6B_CE1B_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6A_CE2B, CS6A_CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5B_CE1A, CS5B_CE1A_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5A_CE2A, CS5A_CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_WE3_ICIOWR, WE3_ICIOWR_MARK),
+ PINMUX_GPIO(GPIO_FN_WE2_ICIORD, WE2_ICIORD_MARK),
+
+ /* ATAPI */
+ PINMUX_GPIO(GPIO_FN_IDED15, IDED15_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED14, IDED14_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED13, IDED13_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED12, IDED12_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED11, IDED11_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED10, IDED10_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED9, IDED9_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED8, IDED8_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED7, IDED7_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED6, IDED6_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED5, IDED5_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED4, IDED4_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED3, IDED3_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED2, IDED2_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED1, IDED1_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED0, IDED0_MARK),
+ PINMUX_GPIO(GPIO_FN_DIRECTION, DIRECTION_MARK),
+ PINMUX_GPIO(GPIO_FN_EXBUF_ENB, EXBUF_ENB_MARK),
+ PINMUX_GPIO(GPIO_FN_IDERST, IDERST_MARK),
+ PINMUX_GPIO(GPIO_FN_IODACK, IODACK_MARK),
+ PINMUX_GPIO(GPIO_FN_IODREQ, IODREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEIORDY, IDEIORDY_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEINT, IDEINT_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEIOWR, IDEIOWR_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEIORD, IDEIORD_MARK),
+ PINMUX_GPIO(GPIO_FN_IDECS1, IDECS1_MARK),
+ PINMUX_GPIO(GPIO_FN_IDECS0, IDECS0_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEA2, IDEA2_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEA1, IDEA1_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEA0, IDEA0_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
+ PTA7_FN, PTA7_OUT, 0, PTA7_IN,
+ PTA6_FN, PTA6_OUT, 0, PTA6_IN,
+ PTA5_FN, PTA5_OUT, 0, PTA5_IN,
+ PTA4_FN, PTA4_OUT, PTA4_IN_PU, PTA4_IN,
+ PTA3_FN, PTA3_OUT, PTA3_IN_PU, PTA3_IN,
+ PTA2_FN, PTA2_OUT, PTA2_IN_PU, PTA2_IN,
+ PTA1_FN, PTA1_OUT, PTA1_IN_PU, PTA1_IN,
+ PTA0_FN, PTA0_OUT, PTA0_IN_PU, PTA0_IN }
+ },
+ { PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
+ PTB7_FN, PTB7_OUT, 0, PTB7_IN,
+ PTB6_FN, PTB6_OUT, 0, PTB6_IN,
+ PTB5_FN, PTB5_OUT, 0, PTB5_IN,
+ PTB4_FN, PTB4_OUT, 0, PTB4_IN,
+ PTB3_FN, PTB3_OUT, 0, PTB3_IN,
+ PTB2_FN, PTB2_OUT, PTB2_IN_PU, PTB2_IN,
+ PTB1_FN, PTB1_OUT, PTB1_IN_PU, PTB1_IN,
+ PTB0_FN, PTB0_OUT, 0, PTB0_IN }
+ },
+ { PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
+ PTC7_FN, PTC7_OUT, 0, PTC7_IN,
+ PTC6_FN, PTC6_OUT, 0, PTC6_IN,
+ PTC5_FN, PTC5_OUT, 0, PTC5_IN,
+ PTC4_FN, PTC4_OUT, 0, PTC4_IN,
+ PTC3_FN, PTC3_OUT, 0, PTC3_IN,
+ PTC2_FN, PTC2_OUT, 0, PTC2_IN,
+ PTC1_FN, PTC1_OUT, 0, PTC1_IN,
+ PTC0_FN, PTC0_OUT, 0, PTC0_IN }
+ },
+ { PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
+ PTD7_FN, PTD7_OUT, 0, PTD7_IN,
+ PTD6_FN, PTD6_OUT, 0, PTD6_IN,
+ PTD5_FN, PTD5_OUT, 0, PTD5_IN,
+ PTD4_FN, PTD4_OUT, 0, PTD4_IN,
+ PTD3_FN, PTD3_OUT, 0, PTD3_IN,
+ PTD2_FN, PTD2_OUT, 0, PTD2_IN,
+ PTD1_FN, PTD1_OUT, 0, PTD1_IN,
+ PTD0_FN, PTD0_OUT, 0, PTD0_IN }
+ },
+ { PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTE5_FN, PTE5_OUT, 0, PTE5_IN,
+ PTE4_FN, PTE4_OUT, 0, PTE4_IN,
+ PTE3_FN, PTE3_OUT, 0, PTE3_IN,
+ PTE2_FN, PTE2_OUT, 0, PTE2_IN,
+ PTE1_FN, PTE1_OUT, 0, PTE1_IN,
+ PTE0_FN, PTE0_OUT, 0, PTE0_IN }
+ },
+ { PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
+ PTF7_FN, PTF7_OUT, 0, PTF7_IN,
+ PTF6_FN, PTF6_OUT, 0, PTF6_IN,
+ PTF5_FN, PTF5_OUT, 0, PTF5_IN,
+ PTF4_FN, PTF4_OUT, 0, PTF4_IN,
+ PTF3_FN, PTF3_OUT, 0, PTF3_IN,
+ PTF2_FN, PTF2_OUT, 0, PTF2_IN,
+ PTF1_FN, PTF1_OUT, 0, PTF1_IN,
+ PTF0_FN, PTF0_OUT, 0, PTF0_IN }
+ },
+ { PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTG5_FN, PTG5_OUT, 0, 0,
+ PTG4_FN, PTG4_OUT, 0, 0,
+ PTG3_FN, PTG3_OUT, 0, 0,
+ PTG2_FN, PTG2_OUT, 0, 0,
+ PTG1_FN, PTG1_OUT, 0, 0,
+ PTG0_FN, PTG0_OUT, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
+ PTH7_FN, PTH7_OUT, 0, PTH7_IN,
+ PTH6_FN, PTH6_OUT, 0, PTH6_IN,
+ PTH5_FN, PTH5_OUT, 0, PTH5_IN,
+ PTH4_FN, PTH4_OUT, 0, PTH4_IN,
+ PTH3_FN, PTH3_OUT, 0, PTH3_IN,
+ PTH2_FN, PTH2_OUT, 0, PTH2_IN,
+ PTH1_FN, PTH1_OUT, 0, PTH1_IN,
+ PTH0_FN, PTH0_OUT, 0, PTH0_IN }
+ },
+ { PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
+ PTJ7_FN, PTJ7_OUT, 0, 0,
+ 0, 0, 0, 0,
+ PTJ5_FN, PTJ5_OUT, 0, 0,
+ 0, 0, 0, 0,
+ PTJ3_FN, PTJ3_OUT, 0, PTJ3_IN,
+ PTJ2_FN, PTJ2_OUT, 0, PTJ2_IN,
+ PTJ1_FN, PTJ1_OUT, 0, PTJ1_IN,
+ PTJ0_FN, PTJ0_OUT, 0, PTJ0_IN }
+ },
+ { PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
+ PTK7_FN, PTK7_OUT, 0, PTK7_IN,
+ PTK6_FN, PTK6_OUT, 0, PTK6_IN,
+ PTK5_FN, PTK5_OUT, 0, PTK5_IN,
+ PTK4_FN, PTK4_OUT, 0, PTK4_IN,
+ PTK3_FN, PTK3_OUT, 0, PTK3_IN,
+ PTK2_FN, PTK2_OUT, 0, PTK2_IN,
+ PTK1_FN, PTK1_OUT, 0, PTK1_IN,
+ PTK0_FN, PTK0_OUT, 0, PTK0_IN }
+ },
+ { PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
+ PTL7_FN, PTL7_OUT, 0, PTL7_IN,
+ PTL6_FN, PTL6_OUT, 0, PTL6_IN,
+ PTL5_FN, PTL5_OUT, 0, PTL5_IN,
+ PTL4_FN, PTL4_OUT, 0, PTL4_IN,
+ PTL3_FN, PTL3_OUT, 0, PTL3_IN,
+ PTL2_FN, PTL2_OUT, 0, PTL2_IN,
+ PTL1_FN, PTL1_OUT, 0, PTL1_IN,
+ PTL0_FN, PTL0_OUT, 0, PTL0_IN }
+ },
+ { PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
+ PTM7_FN, PTM7_OUT, 0, PTM7_IN,
+ PTM6_FN, PTM6_OUT, 0, PTM6_IN,
+ PTM5_FN, PTM5_OUT, 0, PTM5_IN,
+ PTM4_FN, PTM4_OUT, 0, PTM4_IN,
+ PTM3_FN, PTM3_OUT, 0, PTM3_IN,
+ PTM2_FN, PTM2_OUT, 0, PTM2_IN,
+ PTM1_FN, PTM1_OUT, 0, PTM1_IN,
+ PTM0_FN, PTM0_OUT, 0, PTM0_IN }
+ },
+ { PINMUX_CFG_REG("PNCR", 0xa4050118, 16, 2) {
+ PTN7_FN, PTN7_OUT, 0, PTN7_IN,
+ PTN6_FN, PTN6_OUT, 0, PTN6_IN,
+ PTN5_FN, PTN5_OUT, 0, PTN5_IN,
+ PTN4_FN, PTN4_OUT, 0, PTN4_IN,
+ PTN3_FN, PTN3_OUT, 0, PTN3_IN,
+ PTN2_FN, PTN2_OUT, 0, PTN2_IN,
+ PTN1_FN, PTN1_OUT, 0, PTN1_IN,
+ PTN0_FN, PTN0_OUT, 0, PTN0_IN }
+ },
+ { PINMUX_CFG_REG("PQCR", 0xa405011a, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTQ3_FN, 0, 0, PTQ3_IN,
+ PTQ2_FN, 0, 0, PTQ2_IN,
+ PTQ1_FN, 0, 0, PTQ1_IN,
+ PTQ0_FN, 0, 0, PTQ0_IN }
+ },
+ { PINMUX_CFG_REG("PRCR", 0xa405011c, 16, 2) {
+ PTR7_FN, PTR7_OUT, 0, PTR7_IN,
+ PTR6_FN, PTR6_OUT, 0, PTR6_IN,
+ PTR5_FN, PTR5_OUT, 0, PTR5_IN,
+ PTR4_FN, PTR4_OUT, 0, PTR4_IN,
+ PTR3_FN, 0, 0, PTR3_IN,
+ PTR2_FN, 0, PTR2_IN_PU, PTR2_IN,
+ PTR1_FN, PTR1_OUT, 0, PTR1_IN,
+ PTR0_FN, PTR0_OUT, 0, PTR0_IN }
+ },
+ { PINMUX_CFG_REG("PSCR", 0xa405011e, 16, 2) {
+ PTS7_FN, PTS7_OUT, 0, PTS7_IN,
+ PTS6_FN, PTS6_OUT, 0, PTS6_IN,
+ PTS5_FN, PTS5_OUT, 0, PTS5_IN,
+ PTS4_FN, PTS4_OUT, 0, PTS4_IN,
+ PTS3_FN, PTS3_OUT, 0, PTS3_IN,
+ PTS2_FN, PTS2_OUT, 0, PTS2_IN,
+ PTS1_FN, PTS1_OUT, 0, PTS1_IN,
+ PTS0_FN, PTS0_OUT, 0, PTS0_IN }
+ },
+ { PINMUX_CFG_REG("PTCR", 0xa4050140, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTT5_FN, PTT5_OUT, 0, PTT5_IN,
+ PTT4_FN, PTT4_OUT, 0, PTT4_IN,
+ PTT3_FN, PTT3_OUT, 0, PTT3_IN,
+ PTT2_FN, PTT2_OUT, 0, PTT2_IN,
+ PTT1_FN, PTT1_OUT, 0, PTT1_IN,
+ PTT0_FN, PTT0_OUT, 0, PTT0_IN }
+ },
+ { PINMUX_CFG_REG("PUCR", 0xa4050142, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTU5_FN, PTU5_OUT, 0, PTU5_IN,
+ PTU4_FN, PTU4_OUT, 0, PTU4_IN,
+ PTU3_FN, PTU3_OUT, 0, PTU3_IN,
+ PTU2_FN, PTU2_OUT, 0, PTU2_IN,
+ PTU1_FN, PTU1_OUT, 0, PTU1_IN,
+ PTU0_FN, PTU0_OUT, 0, PTU0_IN }
+ },
+ { PINMUX_CFG_REG("PVCR", 0xa4050144, 16, 2) {
+ PTV7_FN, PTV7_OUT, 0, PTV7_IN,
+ PTV6_FN, PTV6_OUT, 0, PTV6_IN,
+ PTV5_FN, PTV5_OUT, 0, PTV5_IN,
+ PTV4_FN, PTV4_OUT, 0, PTV4_IN,
+ PTV3_FN, PTV3_OUT, 0, PTV3_IN,
+ PTV2_FN, PTV2_OUT, 0, PTV2_IN,
+ PTV1_FN, PTV1_OUT, 0, PTV1_IN,
+ PTV0_FN, PTV0_OUT, 0, PTV0_IN }
+ },
+ { PINMUX_CFG_REG("PWCR", 0xa4050146, 16, 2) {
+ PTW7_FN, PTW7_OUT, 0, PTW7_IN,
+ PTW6_FN, PTW6_OUT, 0, PTW6_IN,
+ PTW5_FN, PTW5_OUT, 0, PTW5_IN,
+ PTW4_FN, PTW4_OUT, 0, PTW4_IN,
+ PTW3_FN, PTW3_OUT, 0, PTW3_IN,
+ PTW2_FN, PTW2_OUT, 0, PTW2_IN,
+ PTW1_FN, PTW1_OUT, 0, PTW1_IN,
+ PTW0_FN, PTW0_OUT, 0, PTW0_IN }
+ },
+ { PINMUX_CFG_REG("PXCR", 0xa4050148, 16, 2) {
+ PTX7_FN, PTX7_OUT, 0, PTX7_IN,
+ PTX6_FN, PTX6_OUT, 0, PTX6_IN,
+ PTX5_FN, PTX5_OUT, 0, PTX5_IN,
+ PTX4_FN, PTX4_OUT, 0, PTX4_IN,
+ PTX3_FN, PTX3_OUT, 0, PTX3_IN,
+ PTX2_FN, PTX2_OUT, 0, PTX2_IN,
+ PTX1_FN, PTX1_OUT, 0, PTX1_IN,
+ PTX0_FN, PTX0_OUT, 0, PTX0_IN }
+ },
+ { PINMUX_CFG_REG("PYCR", 0xa405014a, 16, 2) {
+ PTY7_FN, PTY7_OUT, 0, PTY7_IN,
+ PTY6_FN, PTY6_OUT, 0, PTY6_IN,
+ PTY5_FN, PTY5_OUT, 0, PTY5_IN,
+ PTY4_FN, PTY4_OUT, 0, PTY4_IN,
+ PTY3_FN, PTY3_OUT, 0, PTY3_IN,
+ PTY2_FN, PTY2_OUT, 0, PTY2_IN,
+ PTY1_FN, PTY1_OUT, 0, PTY1_IN,
+ PTY0_FN, PTY0_OUT, 0, PTY0_IN }
+ },
+ { PINMUX_CFG_REG("PZCR", 0xa405014c, 16, 2) {
+ PTZ7_FN, PTZ7_OUT, 0, PTZ7_IN,
+ PTZ6_FN, PTZ6_OUT, 0, PTZ6_IN,
+ PTZ5_FN, PTZ5_OUT, 0, PTZ5_IN,
+ PTZ4_FN, PTZ4_OUT, 0, PTZ4_IN,
+ PTZ3_FN, PTZ3_OUT, 0, PTZ3_IN,
+ PTZ2_FN, PTZ2_OUT, 0, PTZ2_IN,
+ PTZ1_FN, PTZ1_OUT, 0, PTZ1_IN,
+ PTZ0_FN, PTZ0_OUT, 0, PTZ0_IN }
+ },
+ { PINMUX_CFG_REG("PSELA", 0xa405014e, 16, 2) {
+ PSA15_PSA14_FN1, PSA15_PSA14_FN2, 0, 0,
+ PSA13_PSA12_FN1, PSA13_PSA12_FN2, 0, 0,
+ PSA11_PSA10_FN1, PSA11_PSA10_FN2, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PSA5_PSA4_FN1, PSA5_PSA4_FN2, PSA5_PSA4_FN3, 0,
+ PSA3_PSA2_FN1, PSA3_PSA2_FN2, 0, 0,
+ 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PSELB", 0xa4050150, 16, 2) {
+ PSB15_PSB14_FN1, PSB15_PSB14_FN2, 0, 0,
+ PSB13_PSB12_LCDC_RGB, PSB13_PSB12_LCDC_SYS, 0, 0,
+ 0, 0, 0, 0,
+ PSB9_PSB8_FN1, PSB9_PSB8_FN2, PSB9_PSB8_FN3, 0,
+ PSB7_PSB6_FN1, PSB7_PSB6_FN2, 0, 0,
+ PSB5_PSB4_FN1, PSB5_PSB4_FN2, 0, 0,
+ PSB3_PSB2_FN1, PSB3_PSB2_FN2, 0, 0,
+ 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PSELC", 0xa4050152, 16, 2) {
+ PSC15_PSC14_FN1, PSC15_PSC14_FN2, 0, 0,
+ PSC13_PSC12_FN1, PSC13_PSC12_FN2, 0, 0,
+ PSC11_PSC10_FN1, PSC11_PSC10_FN2, PSC11_PSC10_FN3, 0,
+ PSC9_PSC8_FN1, PSC9_PSC8_FN2, 0, 0,
+ PSC7_PSC6_FN1, PSC7_PSC6_FN2, PSC7_PSC6_FN3, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PSELD", 0xa4050154, 16, 2) {
+ PSD15_PSD14_FN1, PSD15_PSD14_FN2, 0, 0,
+ PSD13_PSD12_FN1, PSD13_PSD12_FN2, 0, 0,
+ PSD11_PSD10_FN1, PSD11_PSD10_FN2, PSD11_PSD10_FN3, 0,
+ PSD9_PSD8_FN1, PSD9_PSD8_FN2, 0, 0,
+ PSD7_PSD6_FN1, PSD7_PSD6_FN2, 0, 0,
+ PSD5_PSD4_FN1, PSD5_PSD4_FN2, 0, 0,
+ PSD3_PSD2_FN1, PSD3_PSD2_FN2, 0, 0,
+ PSD1_PSD0_FN1, PSD1_PSD0_FN2, 0, 0 }
+ },
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR", 0xa4050120, 8) {
+ PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+ PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
+ },
+ { PINMUX_DATA_REG("PBDR", 0xa4050122, 8) {
+ PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+ PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
+ },
+ { PINMUX_DATA_REG("PCDR", 0xa4050124, 8) {
+ PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
+ PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA }
+ },
+ { PINMUX_DATA_REG("PDDR", 0xa4050126, 8) {
+ PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+ PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
+ },
+ { PINMUX_DATA_REG("PEDR", 0xa4050128, 8) {
+ 0, 0, PTE5_DATA, PTE4_DATA,
+ PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA }
+ },
+ { PINMUX_DATA_REG("PFDR", 0xa405012a, 8) {
+ PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
+ PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
+ },
+ { PINMUX_DATA_REG("PGDR", 0xa405012c, 8) {
+ 0, 0, PTG5_DATA, PTG4_DATA,
+ PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
+ },
+ { PINMUX_DATA_REG("PHDR", 0xa405012e, 8) {
+ PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+ PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR", 0xa4050130, 8) {
+ PTJ7_DATA, 0, PTJ5_DATA, 0,
+ PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
+ },
+ { PINMUX_DATA_REG("PKDR", 0xa4050132, 8) {
+ PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
+ PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
+ },
+ { PINMUX_DATA_REG("PLDR", 0xa4050134, 8) {
+ PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
+ },
+ { PINMUX_DATA_REG("PMDR", 0xa4050136, 8) {
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
+ },
+ { PINMUX_DATA_REG("PNDR", 0xa4050138, 8) {
+ PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
+ },
+ { PINMUX_DATA_REG("PQDR", 0xa405013a, 8) {
+ 0, 0, 0, 0,
+ PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA }
+ },
+ { PINMUX_DATA_REG("PRDR", 0xa405013c, 8) {
+ PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
+ PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
+ },
+ { PINMUX_DATA_REG("PSDR", 0xa405013e, 8) {
+ PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
+ PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
+ },
+ { PINMUX_DATA_REG("PTDR", 0xa4050160, 8) {
+ 0, 0, PTT5_DATA, PTT4_DATA,
+ PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
+ },
+ { PINMUX_DATA_REG("PUDR", 0xa4050162, 8) {
+ 0, 0, PTU5_DATA, PTU4_DATA,
+ PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
+ },
+ { PINMUX_DATA_REG("PVDR", 0xa4050164, 8) {
+ PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
+ PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
+ },
+ { PINMUX_DATA_REG("PWDR", 0xa4050166, 8) {
+ PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
+ PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA }
+ },
+ { PINMUX_DATA_REG("PXDR", 0xa4050168, 8) {
+ PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
+ PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA }
+ },
+ { PINMUX_DATA_REG("PYDR", 0xa405016a, 8) {
+ PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
+ PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA }
+ },
+ { PINMUX_DATA_REG("PZDR", 0xa405016c, 8) {
+ PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
+ PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA }
+ },
+ { },
+};
+
+struct sh_pfc_soc_info sh7723_pinmux_info = {
+ .name = "sh7723_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PTA7,
+ .last_gpio = GPIO_FN_IDEA0,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7724.c b/drivers/pinctrl/sh-pfc/pfc-sh7724.c
new file mode 100644
index 000000000000..233fbf750b39
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7724.c
@@ -0,0 +1,2225 @@
+/*
+ * SH7724 Pinmux
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ *
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on SH7723 Pinmux
+ * Copyright (C) 2008 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/init.h>
+#include <linux/kernel.h>
+#include <cpu/sh7724.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+ PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
+ PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+ PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
+ PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
+ PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA,
+ PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+ PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
+ PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
+ PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA,
+ PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
+ PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
+ PTG5_DATA, PTG4_DATA,
+ PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
+ PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+ PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
+ PTJ7_DATA, PTJ6_DATA, PTJ5_DATA,
+ PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
+ PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
+ PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
+ PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
+ PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
+ PTQ7_DATA, PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+ PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
+ PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
+ PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
+ PTS6_DATA, PTS5_DATA, PTS4_DATA,
+ PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
+ PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
+ PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
+ PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
+ PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
+ PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
+ PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
+ PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
+ PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA,
+ PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
+ PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA,
+ PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
+ PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA,
+ PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
+ PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
+ PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
+ PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
+ PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
+ PTC7_IN, PTC6_IN, PTC5_IN, PTC4_IN,
+ PTC3_IN, PTC2_IN, PTC1_IN, PTC0_IN,
+ PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN,
+ PTD3_IN, PTD2_IN, PTD1_IN, PTD0_IN,
+ PTE7_IN, PTE6_IN, PTE5_IN, PTE4_IN,
+ PTE3_IN, PTE2_IN, PTE1_IN, PTE0_IN,
+ PTF7_IN, PTF6_IN, PTF5_IN, PTF4_IN,
+ PTF3_IN, PTF2_IN, PTF1_IN, PTF0_IN,
+ PTH7_IN, PTH6_IN, PTH5_IN, PTH4_IN,
+ PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
+ PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
+ PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
+ PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
+ PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
+ PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
+ PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
+ PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
+ PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
+ PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
+ PTQ7_IN, PTQ6_IN, PTQ5_IN, PTQ4_IN,
+ PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
+ PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
+ PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
+ PTS6_IN, PTS5_IN, PTS4_IN,
+ PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
+ PTT7_IN, PTT6_IN, PTT5_IN, PTT4_IN,
+ PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
+ PTU7_IN, PTU6_IN, PTU5_IN, PTU4_IN,
+ PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
+ PTV7_IN, PTV6_IN, PTV5_IN, PTV4_IN,
+ PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
+ PTW7_IN, PTW6_IN, PTW5_IN, PTW4_IN,
+ PTW3_IN, PTW2_IN, PTW1_IN, PTW0_IN,
+ PTX7_IN, PTX6_IN, PTX5_IN, PTX4_IN,
+ PTX3_IN, PTX2_IN, PTX1_IN, PTX0_IN,
+ PTY7_IN, PTY6_IN, PTY5_IN, PTY4_IN,
+ PTY3_IN, PTY2_IN, PTY1_IN, PTY0_IN,
+ PTZ7_IN, PTZ6_IN, PTZ5_IN, PTZ4_IN,
+ PTZ3_IN, PTZ2_IN, PTZ1_IN, PTZ0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_INPUT_PULLUP_BEGIN,
+ PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
+ PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
+ PTB7_IN_PU, PTB6_IN_PU, PTB5_IN_PU, PTB4_IN_PU,
+ PTB3_IN_PU, PTB2_IN_PU, PTB1_IN_PU, PTB0_IN_PU,
+ PTC7_IN_PU, PTC6_IN_PU, PTC5_IN_PU, PTC4_IN_PU,
+ PTC3_IN_PU, PTC2_IN_PU, PTC1_IN_PU, PTC0_IN_PU,
+ PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
+ PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
+ PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
+ PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
+ PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
+ PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
+ PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
+ PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
+ PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
+ PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
+ PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
+ PTL7_IN_PU, PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
+ PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
+ PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
+ PTM3_IN_PU, PTM2_IN_PU, PTM1_IN_PU, PTM0_IN_PU,
+ PTN7_IN_PU, PTN6_IN_PU, PTN5_IN_PU, PTN4_IN_PU,
+ PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
+ PTQ7_IN_PU, PTQ6_IN_PU, PTQ5_IN_PU, PTQ4_IN_PU,
+ PTQ3_IN_PU, PTQ2_IN_PU, PTQ1_IN_PU, PTQ0_IN_PU,
+ PTR7_IN_PU, PTR6_IN_PU, PTR5_IN_PU, PTR4_IN_PU,
+ PTR3_IN_PU, PTR2_IN_PU, PTR1_IN_PU, PTR0_IN_PU,
+ PTS6_IN_PU, PTS5_IN_PU, PTS4_IN_PU,
+ PTS3_IN_PU, PTS2_IN_PU, PTS1_IN_PU, PTS0_IN_PU,
+ PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
+ PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
+ PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
+ PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
+ PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
+ PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
+ PTW7_IN_PU, PTW6_IN_PU, PTW5_IN_PU, PTW4_IN_PU,
+ PTW3_IN_PU, PTW2_IN_PU, PTW1_IN_PU, PTW0_IN_PU,
+ PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
+ PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
+ PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
+ PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
+ PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
+ PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
+ PINMUX_INPUT_PULLUP_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
+ PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
+ PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
+ PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
+ PTC7_OUT, PTC6_OUT, PTC5_OUT, PTC4_OUT,
+ PTC3_OUT, PTC2_OUT, PTC1_OUT, PTC0_OUT,
+ PTD7_OUT, PTD6_OUT, PTD5_OUT, PTD4_OUT,
+ PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
+ PTE7_OUT, PTE6_OUT, PTE5_OUT, PTE4_OUT,
+ PTE3_OUT, PTE2_OUT, PTE1_OUT, PTE0_OUT,
+ PTF7_OUT, PTF6_OUT, PTF5_OUT, PTF4_OUT,
+ PTF3_OUT, PTF2_OUT, PTF1_OUT, PTF0_OUT,
+ PTG5_OUT, PTG4_OUT,
+ PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
+ PTH7_OUT, PTH6_OUT, PTH5_OUT, PTH4_OUT,
+ PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
+ PTJ7_OUT, PTJ6_OUT, PTJ5_OUT,
+ PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
+ PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
+ PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
+ PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
+ PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
+ PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
+ PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
+ PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
+ PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
+ PTQ7_OUT, PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
+ PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
+ PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
+ PTR1_OUT, PTR0_OUT,
+ PTS6_OUT, PTS5_OUT, PTS4_OUT,
+ PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
+ PTT7_OUT, PTT6_OUT, PTT5_OUT, PTT4_OUT,
+ PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
+ PTU7_OUT, PTU6_OUT, PTU5_OUT, PTU4_OUT,
+ PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
+ PTV7_OUT, PTV6_OUT, PTV5_OUT, PTV4_OUT,
+ PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
+ PTW7_OUT, PTW6_OUT, PTW5_OUT, PTW4_OUT,
+ PTW3_OUT, PTW2_OUT, PTW1_OUT, PTW0_OUT,
+ PTX7_OUT, PTX6_OUT, PTX5_OUT, PTX4_OUT,
+ PTX3_OUT, PTX2_OUT, PTX1_OUT, PTX0_OUT,
+ PTY7_OUT, PTY6_OUT, PTY5_OUT, PTY4_OUT,
+ PTY3_OUT, PTY2_OUT, PTY1_OUT, PTY0_OUT,
+ PTZ7_OUT, PTZ6_OUT, PTZ5_OUT, PTZ4_OUT,
+ PTZ3_OUT, PTZ2_OUT, PTZ1_OUT, PTZ0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PTA7_FN, PTA6_FN, PTA5_FN, PTA4_FN,
+ PTA3_FN, PTA2_FN, PTA1_FN, PTA0_FN,
+ PTB7_FN, PTB6_FN, PTB5_FN, PTB4_FN,
+ PTB3_FN, PTB2_FN, PTB1_FN, PTB0_FN,
+ PTC7_FN, PTC6_FN, PTC5_FN, PTC4_FN,
+ PTC3_FN, PTC2_FN, PTC1_FN, PTC0_FN,
+ PTD7_FN, PTD6_FN, PTD5_FN, PTD4_FN,
+ PTD3_FN, PTD2_FN, PTD1_FN, PTD0_FN,
+ PTE7_FN, PTE6_FN, PTE5_FN, PTE4_FN,
+ PTE3_FN, PTE2_FN, PTE1_FN, PTE0_FN,
+ PTF7_FN, PTF6_FN, PTF5_FN, PTF4_FN,
+ PTF3_FN, PTF2_FN, PTF1_FN, PTF0_FN,
+ PTG5_FN, PTG4_FN,
+ PTG3_FN, PTG2_FN, PTG1_FN, PTG0_FN,
+ PTH7_FN, PTH6_FN, PTH5_FN, PTH4_FN,
+ PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
+ PTJ7_FN, PTJ6_FN, PTJ5_FN,
+ PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
+ PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
+ PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
+ PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN,
+ PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
+ PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
+ PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
+ PTN7_FN, PTN6_FN, PTN5_FN, PTN4_FN,
+ PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
+ PTQ7_FN, PTQ6_FN, PTQ5_FN, PTQ4_FN,
+ PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
+ PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
+ PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
+ PTS6_FN, PTS5_FN, PTS4_FN,
+ PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
+ PTT7_FN, PTT6_FN, PTT5_FN, PTT4_FN,
+ PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
+ PTU7_FN, PTU6_FN, PTU5_FN, PTU4_FN,
+ PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
+ PTV7_FN, PTV6_FN, PTV5_FN, PTV4_FN,
+ PTV3_FN, PTV2_FN, PTV1_FN, PTV0_FN,
+ PTW7_FN, PTW6_FN, PTW5_FN, PTW4_FN,
+ PTW3_FN, PTW2_FN, PTW1_FN, PTW0_FN,
+ PTX7_FN, PTX6_FN, PTX5_FN, PTX4_FN,
+ PTX3_FN, PTX2_FN, PTX1_FN, PTX0_FN,
+ PTY7_FN, PTY6_FN, PTY5_FN, PTY4_FN,
+ PTY3_FN, PTY2_FN, PTY1_FN, PTY0_FN,
+ PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
+ PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
+
+
+ PSA15_0, PSA15_1,
+ PSA14_0, PSA14_1,
+ PSA13_0, PSA13_1,
+ PSA12_0, PSA12_1,
+ PSA10_0, PSA10_1,
+ PSA9_0, PSA9_1,
+ PSA8_0, PSA8_1,
+ PSA7_0, PSA7_1,
+ PSA6_0, PSA6_1,
+ PSA5_0, PSA5_1,
+ PSA3_0, PSA3_1,
+ PSA2_0, PSA2_1,
+ PSA1_0, PSA1_1,
+ PSA0_0, PSA0_1,
+
+ PSB14_0, PSB14_1,
+ PSB13_0, PSB13_1,
+ PSB12_0, PSB12_1,
+ PSB11_0, PSB11_1,
+ PSB10_0, PSB10_1,
+ PSB9_0, PSB9_1,
+ PSB8_0, PSB8_1,
+ PSB7_0, PSB7_1,
+ PSB6_0, PSB6_1,
+ PSB5_0, PSB5_1,
+ PSB4_0, PSB4_1,
+ PSB3_0, PSB3_1,
+ PSB2_0, PSB2_1,
+ PSB1_0, PSB1_1,
+ PSB0_0, PSB0_1,
+
+ PSC15_0, PSC15_1,
+ PSC14_0, PSC14_1,
+ PSC13_0, PSC13_1,
+ PSC12_0, PSC12_1,
+ PSC11_0, PSC11_1,
+ PSC10_0, PSC10_1,
+ PSC9_0, PSC9_1,
+ PSC8_0, PSC8_1,
+ PSC7_0, PSC7_1,
+ PSC6_0, PSC6_1,
+ PSC5_0, PSC5_1,
+ PSC4_0, PSC4_1,
+ PSC2_0, PSC2_1,
+ PSC1_0, PSC1_1,
+ PSC0_0, PSC0_1,
+
+ PSD15_0, PSD15_1,
+ PSD14_0, PSD14_1,
+ PSD13_0, PSD13_1,
+ PSD12_0, PSD12_1,
+ PSD11_0, PSD11_1,
+ PSD10_0, PSD10_1,
+ PSD9_0, PSD9_1,
+ PSD8_0, PSD8_1,
+ PSD7_0, PSD7_1,
+ PSD6_0, PSD6_1,
+ PSD5_0, PSD5_1,
+ PSD4_0, PSD4_1,
+ PSD3_0, PSD3_1,
+ PSD2_0, PSD2_1,
+ PSD1_0, PSD1_1,
+ PSD0_0, PSD0_1,
+
+ PSE15_0, PSE15_1,
+ PSE14_0, PSE14_1,
+ PSE13_0, PSE13_1,
+ PSE12_0, PSE12_1,
+ PSE11_0, PSE11_1,
+ PSE10_0, PSE10_1,
+ PSE9_0, PSE9_1,
+ PSE8_0, PSE8_1,
+ PSE7_0, PSE7_1,
+ PSE6_0, PSE6_1,
+ PSE5_0, PSE5_1,
+ PSE4_0, PSE4_1,
+ PSE3_0, PSE3_1,
+ PSE2_0, PSE2_1,
+ PSE1_0, PSE1_1,
+ PSE0_0, PSE0_1,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ /*PTA*/
+ D23_MARK, KEYOUT2_MARK, IDED15_MARK,
+ D22_MARK, KEYOUT1_MARK, IDED14_MARK,
+ D21_MARK, KEYOUT0_MARK, IDED13_MARK,
+ D20_MARK, KEYIN4_MARK, IDED12_MARK,
+ D19_MARK, KEYIN3_MARK, IDED11_MARK,
+ D18_MARK, KEYIN2_MARK, IDED10_MARK,
+ D17_MARK, KEYIN1_MARK, IDED9_MARK,
+ D16_MARK, KEYIN0_MARK, IDED8_MARK,
+
+ /*PTB*/
+ D31_MARK, TPUTO1_MARK, IDEA1_MARK,
+ D30_MARK, TPUTO0_MARK, IDEA0_MARK,
+ D29_MARK, IODREQ_MARK,
+ D28_MARK, IDECS0_MARK,
+ D27_MARK, IDECS1_MARK,
+ D26_MARK, KEYOUT5_IN5_MARK, IDEIORD_MARK,
+ D25_MARK, KEYOUT4_IN6_MARK, IDEIOWR_MARK,
+ D24_MARK, KEYOUT3_MARK, IDEINT_MARK,
+
+ /*PTC*/
+ LCDD7_MARK,
+ LCDD6_MARK,
+ LCDD5_MARK,
+ LCDD4_MARK,
+ LCDD3_MARK,
+ LCDD2_MARK,
+ LCDD1_MARK,
+ LCDD0_MARK,
+
+ /*PTD*/
+ LCDD15_MARK,
+ LCDD14_MARK,
+ LCDD13_MARK,
+ LCDD12_MARK,
+ LCDD11_MARK,
+ LCDD10_MARK,
+ LCDD9_MARK,
+ LCDD8_MARK,
+
+ /*PTE*/
+ FSIMCKB_MARK,
+ FSIMCKA_MARK,
+ LCDD21_MARK, SCIF2_L_TXD_MARK,
+ LCDD20_MARK, SCIF4_SCK_MARK,
+ LCDD19_MARK, SCIF4_RXD_MARK,
+ LCDD18_MARK, SCIF4_TXD_MARK,
+ LCDD17_MARK,
+ LCDD16_MARK,
+
+ /*PTF*/
+ LCDVSYN_MARK,
+ LCDDISP_MARK, LCDRS_MARK,
+ LCDHSYN_MARK, LCDCS_MARK,
+ LCDDON_MARK,
+ LCDDCK_MARK, LCDWR_MARK,
+ LCDVEPWC_MARK, SCIF0_TXD_MARK,
+ LCDD23_MARK, SCIF2_L_SCK_MARK,
+ LCDD22_MARK, SCIF2_L_RXD_MARK,
+
+ /*PTG*/
+ AUDCK_MARK,
+ AUDSYNC_MARK,
+ AUDATA3_MARK,
+ AUDATA2_MARK,
+ AUDATA1_MARK,
+ AUDATA0_MARK,
+
+ /*PTH*/
+ VIO0_VD_MARK,
+ VIO0_CLK_MARK,
+ VIO0_D7_MARK,
+ VIO0_D6_MARK,
+ VIO0_D5_MARK,
+ VIO0_D4_MARK,
+ VIO0_D3_MARK,
+ VIO0_D2_MARK,
+
+ /*PTJ*/
+ PDSTATUS_MARK,
+ STATUS2_MARK,
+ STATUS0_MARK,
+ A25_MARK, BS_MARK,
+ A24_MARK,
+ A23_MARK,
+ A22_MARK,
+
+ /*PTK*/
+ VIO1_D5_MARK, VIO0_D13_MARK, IDED5_MARK,
+ VIO1_D4_MARK, VIO0_D12_MARK, IDED4_MARK,
+ VIO1_D3_MARK, VIO0_D11_MARK, IDED3_MARK,
+ VIO1_D2_MARK, VIO0_D10_MARK, IDED2_MARK,
+ VIO1_D1_MARK, VIO0_D9_MARK, IDED1_MARK,
+ VIO1_D0_MARK, VIO0_D8_MARK, IDED0_MARK,
+ VIO0_FLD_MARK,
+ VIO0_HD_MARK,
+
+ /*PTL*/
+ DV_D5_MARK, SCIF3_V_SCK_MARK, RMII_RXD0_MARK,
+ DV_D4_MARK, SCIF3_V_RXD_MARK, RMII_RXD1_MARK,
+ DV_D3_MARK, SCIF3_V_TXD_MARK, RMII_REF_CLK_MARK,
+ DV_D2_MARK, SCIF1_SCK_MARK, RMII_TX_EN_MARK,
+ DV_D1_MARK, SCIF1_RXD_MARK, RMII_TXD0_MARK,
+ DV_D0_MARK, SCIF1_TXD_MARK, RMII_TXD1_MARK,
+ DV_D15_MARK,
+ DV_D14_MARK, MSIOF0_MCK_MARK,
+
+ /*PTM*/
+ DV_D13_MARK, MSIOF0_TSCK_MARK,
+ DV_D12_MARK, MSIOF0_RXD_MARK,
+ DV_D11_MARK, MSIOF0_TXD_MARK,
+ DV_D10_MARK, MSIOF0_TSYNC_MARK,
+ DV_D9_MARK, MSIOF0_SS1_MARK, MSIOF0_RSCK_MARK,
+ DV_D8_MARK, MSIOF0_SS2_MARK, MSIOF0_RSYNC_MARK,
+ LCDVCPWC_MARK, SCIF0_RXD_MARK,
+ LCDRD_MARK, SCIF0_SCK_MARK,
+
+ /*PTN*/
+ VIO0_D1_MARK,
+ VIO0_D0_MARK,
+ DV_CLKI_MARK,
+ DV_CLK_MARK, SCIF2_V_SCK_MARK,
+ DV_VSYNC_MARK, SCIF2_V_RXD_MARK,
+ DV_HSYNC_MARK, SCIF2_V_TXD_MARK,
+ DV_D7_MARK, SCIF3_V_CTS_MARK, RMII_RX_ER_MARK,
+ DV_D6_MARK, SCIF3_V_RTS_MARK, RMII_CRS_DV_MARK,
+
+ /*PTQ*/
+ D7_MARK,
+ D6_MARK,
+ D5_MARK,
+ D4_MARK,
+ D3_MARK,
+ D2_MARK,
+ D1_MARK,
+ D0_MARK,
+
+ /*PTR*/
+ CS6B_CE1B_MARK,
+ CS6A_CE2B_MARK,
+ CS5B_CE1A_MARK,
+ CS5A_CE2A_MARK,
+ IOIS16_MARK, LCDLCLK_MARK,
+ WAIT_MARK,
+ WE3_ICIOWR_MARK, TPUTO3_MARK, TPUTI3_MARK,
+ WE2_ICIORD_MARK, TPUTO2_MARK, IDEA2_MARK,
+
+ /*PTS*/
+ VIO_CKO_MARK,
+ VIO1_FLD_MARK, TPUTI2_MARK, IDEIORDY_MARK,
+ VIO1_HD_MARK, SCIF5_SCK_MARK,
+ VIO1_VD_MARK, SCIF5_RXD_MARK,
+ VIO1_CLK_MARK, SCIF5_TXD_MARK,
+ VIO1_D7_MARK, VIO0_D15_MARK, IDED7_MARK,
+ VIO1_D6_MARK, VIO0_D14_MARK, IDED6_MARK,
+
+ /*PTT*/
+ D15_MARK,
+ D14_MARK,
+ D13_MARK,
+ D12_MARK,
+ D11_MARK,
+ D10_MARK,
+ D9_MARK,
+ D8_MARK,
+
+ /*PTU*/
+ DMAC_DACK0_MARK,
+ DMAC_DREQ0_MARK,
+ FSIOASD_MARK,
+ FSIIABCK_MARK,
+ FSIIALRCK_MARK,
+ FSIOABCK_MARK,
+ FSIOALRCK_MARK,
+ CLKAUDIOAO_MARK,
+
+ /*PTV*/
+ FSIIBSD_MARK, MSIOF1_SS2_MARK, MSIOF1_RSYNC_MARK,
+ FSIOBSD_MARK, MSIOF1_SS1_MARK, MSIOF1_RSCK_MARK,
+ FSIIBBCK_MARK, MSIOF1_RXD_MARK,
+ FSIIBLRCK_MARK, MSIOF1_TSYNC_MARK,
+ FSIOBBCK_MARK, MSIOF1_TSCK_MARK,
+ FSIOBLRCK_MARK, MSIOF1_TXD_MARK,
+ CLKAUDIOBO_MARK, MSIOF1_MCK_MARK,
+ FSIIASD_MARK,
+
+ /*PTW*/
+ MMC_D7_MARK, SDHI1CD_MARK, IODACK_MARK,
+ MMC_D6_MARK, SDHI1WP_MARK, IDERST_MARK,
+ MMC_D5_MARK, SDHI1D3_MARK, EXBUF_ENB_MARK,
+ MMC_D4_MARK, SDHI1D2_MARK, DIRECTION_MARK,
+ MMC_D3_MARK, SDHI1D1_MARK,
+ MMC_D2_MARK, SDHI1D0_MARK,
+ MMC_D1_MARK, SDHI1CMD_MARK,
+ MMC_D0_MARK, SDHI1CLK_MARK,
+
+ /*PTX*/
+ DMAC_DACK1_MARK, IRDA_OUT_MARK,
+ DMAC_DREQ1_MARK, IRDA_IN_MARK,
+ TSIF_TS0_SDAT_MARK, LNKSTA_MARK,
+ TSIF_TS0_SCK_MARK, MDIO_MARK,
+ TSIF_TS0_SDEN_MARK, MDC_MARK,
+ TSIF_TS0_SPSYNC_MARK,
+ MMC_CLK_MARK,
+ MMC_CMD_MARK,
+
+ /*PTY*/
+ SDHI0CD_MARK,
+ SDHI0WP_MARK,
+ SDHI0D3_MARK,
+ SDHI0D2_MARK,
+ SDHI0D1_MARK,
+ SDHI0D0_MARK,
+ SDHI0CMD_MARK,
+ SDHI0CLK_MARK,
+
+ /*PTZ*/
+ INTC_IRQ7_MARK, SCIF3_I_CTS_MARK,
+ INTC_IRQ6_MARK, SCIF3_I_RTS_MARK,
+ INTC_IRQ5_MARK, SCIF3_I_SCK_MARK,
+ INTC_IRQ4_MARK, SCIF3_I_RXD_MARK,
+ INTC_IRQ3_MARK, SCIF3_I_TXD_MARK,
+ INTC_IRQ2_MARK,
+ INTC_IRQ1_MARK,
+ INTC_IRQ0_MARK,
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+ /* PTA GPIO */
+ PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT, PTA7_IN_PU),
+ PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT, PTA6_IN_PU),
+ PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT, PTA5_IN_PU),
+ PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT, PTA4_IN_PU),
+ PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT, PTA3_IN_PU),
+ PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT, PTA2_IN_PU),
+ PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT, PTA1_IN_PU),
+ PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT, PTA0_IN_PU),
+
+ /* PTB GPIO */
+ PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT, PTB7_IN_PU),
+ PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT, PTB6_IN_PU),
+ PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT, PTB5_IN_PU),
+ PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT, PTB4_IN_PU),
+ PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT, PTB3_IN_PU),
+ PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT, PTB2_IN_PU),
+ PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT, PTB1_IN_PU),
+ PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT, PTB0_IN_PU),
+
+ /* PTC GPIO */
+ PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT, PTC7_IN_PU),
+ PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT, PTC6_IN_PU),
+ PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT, PTC5_IN_PU),
+ PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT, PTC4_IN_PU),
+ PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT, PTC3_IN_PU),
+ PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT, PTC2_IN_PU),
+ PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT, PTC1_IN_PU),
+ PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT, PTC0_IN_PU),
+
+ /* PTD GPIO */
+ PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT, PTD7_IN_PU),
+ PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT, PTD6_IN_PU),
+ PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT, PTD5_IN_PU),
+ PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT, PTD4_IN_PU),
+ PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT, PTD3_IN_PU),
+ PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT, PTD2_IN_PU),
+ PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT, PTD1_IN_PU),
+ PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT, PTD0_IN_PU),
+
+ /* PTE GPIO */
+ PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT, PTE7_IN_PU),
+ PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT, PTE6_IN_PU),
+ PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT, PTE5_IN_PU),
+ PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT, PTE4_IN_PU),
+ PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT, PTE3_IN_PU),
+ PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT, PTE2_IN_PU),
+ PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT, PTE1_IN_PU),
+ PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT, PTE0_IN_PU),
+
+ /* PTF GPIO */
+ PINMUX_DATA(PTF7_DATA, PTF7_IN, PTF7_OUT, PTF7_IN_PU),
+ PINMUX_DATA(PTF6_DATA, PTF6_IN, PTF6_OUT, PTF6_IN_PU),
+ PINMUX_DATA(PTF5_DATA, PTF5_IN, PTF5_OUT, PTF5_IN_PU),
+ PINMUX_DATA(PTF4_DATA, PTF4_IN, PTF4_OUT, PTF4_IN_PU),
+ PINMUX_DATA(PTF3_DATA, PTF3_IN, PTF3_OUT, PTF3_IN_PU),
+ PINMUX_DATA(PTF2_DATA, PTF2_IN, PTF2_OUT, PTF2_IN_PU),
+ PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_OUT, PTF1_IN_PU),
+ PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT, PTF0_IN_PU),
+
+ /* PTG GPIO */
+ PINMUX_DATA(PTG5_DATA, PTG5_OUT),
+ PINMUX_DATA(PTG4_DATA, PTG4_OUT),
+ PINMUX_DATA(PTG3_DATA, PTG3_OUT),
+ PINMUX_DATA(PTG2_DATA, PTG2_OUT),
+ PINMUX_DATA(PTG1_DATA, PTG1_OUT),
+ PINMUX_DATA(PTG0_DATA, PTG0_OUT),
+
+ /* PTH GPIO */
+ PINMUX_DATA(PTH7_DATA, PTH7_IN, PTH7_OUT, PTH7_IN_PU),
+ PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT, PTH6_IN_PU),
+ PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT, PTH5_IN_PU),
+ PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT, PTH4_IN_PU),
+ PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT, PTH3_IN_PU),
+ PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT, PTH2_IN_PU),
+ PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT, PTH1_IN_PU),
+ PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT, PTH0_IN_PU),
+
+ /* PTJ GPIO */
+ PINMUX_DATA(PTJ7_DATA, PTJ7_OUT),
+ PINMUX_DATA(PTJ6_DATA, PTJ6_OUT),
+ PINMUX_DATA(PTJ5_DATA, PTJ5_OUT),
+ PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT, PTJ3_IN_PU),
+ PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT, PTJ2_IN_PU),
+ PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT, PTJ1_IN_PU),
+ PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT, PTJ0_IN_PU),
+
+ /* PTK GPIO */
+ PINMUX_DATA(PTK7_DATA, PTK7_IN, PTK7_OUT, PTK7_IN_PU),
+ PINMUX_DATA(PTK6_DATA, PTK6_IN, PTK6_OUT, PTK6_IN_PU),
+ PINMUX_DATA(PTK5_DATA, PTK5_IN, PTK5_OUT, PTK5_IN_PU),
+ PINMUX_DATA(PTK4_DATA, PTK4_IN, PTK4_OUT, PTK4_IN_PU),
+ PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT, PTK3_IN_PU),
+ PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT, PTK2_IN_PU),
+ PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT, PTK1_IN_PU),
+ PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT, PTK0_IN_PU),
+
+ /* PTL GPIO */
+ PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT, PTL7_IN_PU),
+ PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT, PTL6_IN_PU),
+ PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT, PTL5_IN_PU),
+ PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT, PTL4_IN_PU),
+ PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT, PTL3_IN_PU),
+ PINMUX_DATA(PTL2_DATA, PTL2_IN, PTL2_OUT, PTL2_IN_PU),
+ PINMUX_DATA(PTL1_DATA, PTL1_IN, PTL1_OUT, PTL1_IN_PU),
+ PINMUX_DATA(PTL0_DATA, PTL0_IN, PTL0_OUT, PTL0_IN_PU),
+
+ /* PTM GPIO */
+ PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT, PTM7_IN_PU),
+ PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT, PTM6_IN_PU),
+ PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT, PTM5_IN_PU),
+ PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT, PTM4_IN_PU),
+ PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT, PTM3_IN_PU),
+ PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT, PTM2_IN_PU),
+ PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT, PTM1_IN_PU),
+ PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT, PTM0_IN_PU),
+
+ /* PTN GPIO */
+ PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT, PTN7_IN_PU),
+ PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT, PTN6_IN_PU),
+ PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT, PTN5_IN_PU),
+ PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT, PTN4_IN_PU),
+ PINMUX_DATA(PTN3_DATA, PTN3_IN, PTN3_OUT, PTN3_IN_PU),
+ PINMUX_DATA(PTN2_DATA, PTN2_IN, PTN2_OUT, PTN2_IN_PU),
+ PINMUX_DATA(PTN1_DATA, PTN1_IN, PTN1_OUT, PTN1_IN_PU),
+ PINMUX_DATA(PTN0_DATA, PTN0_IN, PTN0_OUT, PTN0_IN_PU),
+
+ /* PTQ GPIO */
+ PINMUX_DATA(PTQ7_DATA, PTQ7_IN, PTQ7_OUT, PTQ7_IN_PU),
+ PINMUX_DATA(PTQ6_DATA, PTQ6_IN, PTQ6_OUT, PTQ6_IN_PU),
+ PINMUX_DATA(PTQ5_DATA, PTQ5_IN, PTQ5_OUT, PTQ5_IN_PU),
+ PINMUX_DATA(PTQ4_DATA, PTQ4_IN, PTQ4_OUT, PTQ4_IN_PU),
+ PINMUX_DATA(PTQ3_DATA, PTQ3_IN, PTQ3_OUT, PTQ3_IN_PU),
+ PINMUX_DATA(PTQ2_DATA, PTQ2_IN, PTQ2_OUT, PTQ2_IN_PU),
+ PINMUX_DATA(PTQ1_DATA, PTQ1_IN, PTQ1_OUT, PTQ1_IN_PU),
+ PINMUX_DATA(PTQ0_DATA, PTQ0_IN, PTQ0_OUT, PTQ0_IN_PU),
+
+ /* PTR GPIO */
+ PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT, PTR7_IN_PU),
+ PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT, PTR6_IN_PU),
+ PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT, PTR5_IN_PU),
+ PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT, PTR4_IN_PU),
+ PINMUX_DATA(PTR3_DATA, PTR3_IN, PTR3_IN_PU),
+ PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_IN_PU),
+ PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT, PTR1_IN_PU),
+ PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT, PTR0_IN_PU),
+
+ /* PTS GPIO */
+ PINMUX_DATA(PTS6_DATA, PTS6_IN, PTS6_OUT, PTS6_IN_PU),
+ PINMUX_DATA(PTS5_DATA, PTS5_IN, PTS5_OUT, PTS5_IN_PU),
+ PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT, PTS4_IN_PU),
+ PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT, PTS3_IN_PU),
+ PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT, PTS2_IN_PU),
+ PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT, PTS1_IN_PU),
+ PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT, PTS0_IN_PU),
+
+ /* PTT GPIO */
+ PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT, PTT7_IN_PU),
+ PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT, PTT6_IN_PU),
+ PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT, PTT5_IN_PU),
+ PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT, PTT4_IN_PU),
+ PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT, PTT3_IN_PU),
+ PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT, PTT2_IN_PU),
+ PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT, PTT1_IN_PU),
+ PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT, PTT0_IN_PU),
+
+ /* PTU GPIO */
+ PINMUX_DATA(PTU7_DATA, PTU7_IN, PTU7_OUT, PTU7_IN_PU),
+ PINMUX_DATA(PTU6_DATA, PTU6_IN, PTU6_OUT, PTU6_IN_PU),
+ PINMUX_DATA(PTU5_DATA, PTU5_IN, PTU5_OUT, PTU5_IN_PU),
+ PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT, PTU4_IN_PU),
+ PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT, PTU3_IN_PU),
+ PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT, PTU2_IN_PU),
+ PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT, PTU1_IN_PU),
+ PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT, PTU0_IN_PU),
+
+ /* PTV GPIO */
+ PINMUX_DATA(PTV7_DATA, PTV7_IN, PTV7_OUT, PTV7_IN_PU),
+ PINMUX_DATA(PTV6_DATA, PTV6_IN, PTV6_OUT, PTV6_IN_PU),
+ PINMUX_DATA(PTV5_DATA, PTV5_IN, PTV5_OUT, PTV5_IN_PU),
+ PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT, PTV4_IN_PU),
+ PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT, PTV3_IN_PU),
+ PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT, PTV2_IN_PU),
+ PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT, PTV1_IN_PU),
+ PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT, PTV0_IN_PU),
+
+ /* PTW GPIO */
+ PINMUX_DATA(PTW7_DATA, PTW7_IN, PTW7_OUT, PTW7_IN_PU),
+ PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_OUT, PTW6_IN_PU),
+ PINMUX_DATA(PTW5_DATA, PTW5_IN, PTW5_OUT, PTW5_IN_PU),
+ PINMUX_DATA(PTW4_DATA, PTW4_IN, PTW4_OUT, PTW4_IN_PU),
+ PINMUX_DATA(PTW3_DATA, PTW3_IN, PTW3_OUT, PTW3_IN_PU),
+ PINMUX_DATA(PTW2_DATA, PTW2_IN, PTW2_OUT, PTW2_IN_PU),
+ PINMUX_DATA(PTW1_DATA, PTW1_IN, PTW1_OUT, PTW1_IN_PU),
+ PINMUX_DATA(PTW0_DATA, PTW0_IN, PTW0_OUT, PTW0_IN_PU),
+
+ /* PTX GPIO */
+ PINMUX_DATA(PTX7_DATA, PTX7_IN, PTX7_OUT, PTX7_IN_PU),
+ PINMUX_DATA(PTX6_DATA, PTX6_IN, PTX6_OUT, PTX6_IN_PU),
+ PINMUX_DATA(PTX5_DATA, PTX5_IN, PTX5_OUT, PTX5_IN_PU),
+ PINMUX_DATA(PTX4_DATA, PTX4_IN, PTX4_OUT, PTX4_IN_PU),
+ PINMUX_DATA(PTX3_DATA, PTX3_IN, PTX3_OUT, PTX3_IN_PU),
+ PINMUX_DATA(PTX2_DATA, PTX2_IN, PTX2_OUT, PTX2_IN_PU),
+ PINMUX_DATA(PTX1_DATA, PTX1_IN, PTX1_OUT, PTX1_IN_PU),
+ PINMUX_DATA(PTX0_DATA, PTX0_IN, PTX0_OUT, PTX0_IN_PU),
+
+ /* PTY GPIO */
+ PINMUX_DATA(PTY7_DATA, PTY7_IN, PTY7_OUT, PTY7_IN_PU),
+ PINMUX_DATA(PTY6_DATA, PTY6_IN, PTY6_OUT, PTY6_IN_PU),
+ PINMUX_DATA(PTY5_DATA, PTY5_IN, PTY5_OUT, PTY5_IN_PU),
+ PINMUX_DATA(PTY4_DATA, PTY4_IN, PTY4_OUT, PTY4_IN_PU),
+ PINMUX_DATA(PTY3_DATA, PTY3_IN, PTY3_OUT, PTY3_IN_PU),
+ PINMUX_DATA(PTY2_DATA, PTY2_IN, PTY2_OUT, PTY2_IN_PU),
+ PINMUX_DATA(PTY1_DATA, PTY1_IN, PTY1_OUT, PTY1_IN_PU),
+ PINMUX_DATA(PTY0_DATA, PTY0_IN, PTY0_OUT, PTY0_IN_PU),
+
+ /* PTZ GPIO */
+ PINMUX_DATA(PTZ7_DATA, PTZ7_IN, PTZ7_OUT, PTZ7_IN_PU),
+ PINMUX_DATA(PTZ6_DATA, PTZ6_IN, PTZ6_OUT, PTZ6_IN_PU),
+ PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_OUT, PTZ5_IN_PU),
+ PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_OUT, PTZ4_IN_PU),
+ PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_OUT, PTZ3_IN_PU),
+ PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_OUT, PTZ2_IN_PU),
+ PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_OUT, PTZ1_IN_PU),
+ PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT, PTZ0_IN_PU),
+
+ /* PTA FN */
+ PINMUX_DATA(D23_MARK, PSA15_0, PSA14_0, PTA7_FN),
+ PINMUX_DATA(D22_MARK, PSA15_0, PSA14_0, PTA6_FN),
+ PINMUX_DATA(D21_MARK, PSA15_0, PSA14_0, PTA5_FN),
+ PINMUX_DATA(D20_MARK, PSA15_0, PSA14_0, PTA4_FN),
+ PINMUX_DATA(D19_MARK, PSA15_0, PSA14_0, PTA3_FN),
+ PINMUX_DATA(D18_MARK, PSA15_0, PSA14_0, PTA2_FN),
+ PINMUX_DATA(D17_MARK, PSA15_0, PSA14_0, PTA1_FN),
+ PINMUX_DATA(D16_MARK, PSA15_0, PSA14_0, PTA0_FN),
+
+ PINMUX_DATA(KEYOUT2_MARK, PSA15_0, PSA14_1, PTA7_FN),
+ PINMUX_DATA(KEYOUT1_MARK, PSA15_0, PSA14_1, PTA6_FN),
+ PINMUX_DATA(KEYOUT0_MARK, PSA15_0, PSA14_1, PTA5_FN),
+ PINMUX_DATA(KEYIN4_MARK, PSA15_0, PSA14_1, PTA4_FN),
+ PINMUX_DATA(KEYIN3_MARK, PSA15_0, PSA14_1, PTA3_FN),
+ PINMUX_DATA(KEYIN2_MARK, PSA15_0, PSA14_1, PTA2_FN),
+ PINMUX_DATA(KEYIN1_MARK, PSA15_0, PSA14_1, PTA1_FN),
+ PINMUX_DATA(KEYIN0_MARK, PSA15_0, PSA14_1, PTA0_FN),
+
+ PINMUX_DATA(IDED15_MARK, PSA15_1, PSA14_0, PTA7_FN),
+ PINMUX_DATA(IDED14_MARK, PSA15_1, PSA14_0, PTA6_FN),
+ PINMUX_DATA(IDED13_MARK, PSA15_1, PSA14_0, PTA5_FN),
+ PINMUX_DATA(IDED12_MARK, PSA15_1, PSA14_0, PTA4_FN),
+ PINMUX_DATA(IDED11_MARK, PSA15_1, PSA14_0, PTA3_FN),
+ PINMUX_DATA(IDED10_MARK, PSA15_1, PSA14_0, PTA2_FN),
+ PINMUX_DATA(IDED9_MARK, PSA15_1, PSA14_0, PTA1_FN),
+ PINMUX_DATA(IDED8_MARK, PSA15_1, PSA14_0, PTA0_FN),
+
+ /* PTB FN */
+ PINMUX_DATA(D31_MARK, PSE15_0, PSE14_0, PTB7_FN),
+ PINMUX_DATA(D30_MARK, PSE15_0, PSE14_0, PTB6_FN),
+ PINMUX_DATA(D29_MARK, PSE11_0, PTB5_FN),
+ PINMUX_DATA(D28_MARK, PSE11_0, PTB4_FN),
+ PINMUX_DATA(D27_MARK, PSE11_0, PTB3_FN),
+ PINMUX_DATA(D26_MARK, PSA15_0, PSA14_0, PTB2_FN),
+ PINMUX_DATA(D25_MARK, PSA15_0, PSA14_0, PTB1_FN),
+ PINMUX_DATA(D24_MARK, PSA15_0, PSA14_0, PTB0_FN),
+
+ PINMUX_DATA(IDEA1_MARK, PSE15_1, PSE14_0, PTB7_FN),
+ PINMUX_DATA(IDEA0_MARK, PSE15_1, PSE14_0, PTB6_FN),
+ PINMUX_DATA(IODREQ_MARK, PSE11_1, PTB5_FN),
+ PINMUX_DATA(IDECS0_MARK, PSE11_1, PTB4_FN),
+ PINMUX_DATA(IDECS1_MARK, PSE11_1, PTB3_FN),
+ PINMUX_DATA(IDEIORD_MARK, PSA15_1, PSA14_0, PTB2_FN),
+ PINMUX_DATA(IDEIOWR_MARK, PSA15_1, PSA14_0, PTB1_FN),
+ PINMUX_DATA(IDEINT_MARK, PSA15_1, PSA14_0, PTB0_FN),
+
+ PINMUX_DATA(TPUTO1_MARK, PSE15_0, PSE14_1, PTB7_FN),
+ PINMUX_DATA(TPUTO0_MARK, PSE15_0, PSE14_1, PTB6_FN),
+
+ PINMUX_DATA(KEYOUT5_IN5_MARK, PSA15_0, PSA14_1, PTB2_FN),
+ PINMUX_DATA(KEYOUT4_IN6_MARK, PSA15_0, PSA14_1, PTB1_FN),
+ PINMUX_DATA(KEYOUT3_MARK, PSA15_0, PSA14_1, PTB0_FN),
+
+ /* PTC FN */
+ PINMUX_DATA(LCDD7_MARK, PSD5_0, PTC7_FN),
+ PINMUX_DATA(LCDD6_MARK, PSD5_0, PTC6_FN),
+ PINMUX_DATA(LCDD5_MARK, PSD5_0, PTC5_FN),
+ PINMUX_DATA(LCDD4_MARK, PSD5_0, PTC4_FN),
+ PINMUX_DATA(LCDD3_MARK, PSD5_0, PTC3_FN),
+ PINMUX_DATA(LCDD2_MARK, PSD5_0, PTC2_FN),
+ PINMUX_DATA(LCDD1_MARK, PSD5_0, PTC1_FN),
+ PINMUX_DATA(LCDD0_MARK, PSD5_0, PTC0_FN),
+
+ /* PTD FN */
+ PINMUX_DATA(LCDD15_MARK, PSD5_0, PTD7_FN),
+ PINMUX_DATA(LCDD14_MARK, PSD5_0, PTD6_FN),
+ PINMUX_DATA(LCDD13_MARK, PSD5_0, PTD5_FN),
+ PINMUX_DATA(LCDD12_MARK, PSD5_0, PTD4_FN),
+ PINMUX_DATA(LCDD11_MARK, PSD5_0, PTD3_FN),
+ PINMUX_DATA(LCDD10_MARK, PSD5_0, PTD2_FN),
+ PINMUX_DATA(LCDD9_MARK, PSD5_0, PTD1_FN),
+ PINMUX_DATA(LCDD8_MARK, PSD5_0, PTD0_FN),
+
+ /* PTE FN */
+ PINMUX_DATA(FSIMCKB_MARK, PTE7_FN),
+ PINMUX_DATA(FSIMCKA_MARK, PTE6_FN),
+
+ PINMUX_DATA(LCDD21_MARK, PSC5_0, PSC4_0, PTE5_FN),
+ PINMUX_DATA(LCDD20_MARK, PSD3_0, PSD2_0, PTE4_FN),
+ PINMUX_DATA(LCDD19_MARK, PSA3_0, PSA2_0, PTE3_FN),
+ PINMUX_DATA(LCDD18_MARK, PSA3_0, PSA2_0, PTE2_FN),
+ PINMUX_DATA(LCDD17_MARK, PSD5_0, PTE1_FN),
+ PINMUX_DATA(LCDD16_MARK, PSD5_0, PTE0_FN),
+
+ PINMUX_DATA(SCIF2_L_TXD_MARK, PSC5_0, PSC4_1, PTE5_FN),
+ PINMUX_DATA(SCIF4_SCK_MARK, PSD3_0, PSD2_1, PTE4_FN),
+ PINMUX_DATA(SCIF4_RXD_MARK, PSA3_0, PSA2_1, PTE3_FN),
+ PINMUX_DATA(SCIF4_TXD_MARK, PSA3_0, PSA2_1, PTE2_FN),
+
+ /* PTF FN */
+ PINMUX_DATA(LCDVSYN_MARK, PSD8_0, PTF7_FN),
+ PINMUX_DATA(LCDDISP_MARK, PSD10_0, PSD9_0, PTF6_FN),
+ PINMUX_DATA(LCDHSYN_MARK, PSD10_0, PSD9_0, PTF5_FN),
+ PINMUX_DATA(LCDDON_MARK, PSD8_0, PTF4_FN),
+ PINMUX_DATA(LCDDCK_MARK, PSD10_0, PSD9_0, PTF3_FN),
+ PINMUX_DATA(LCDVEPWC_MARK, PSA6_0, PTF2_FN),
+ PINMUX_DATA(LCDD23_MARK, PSC7_0, PSC6_0, PTF1_FN),
+ PINMUX_DATA(LCDD22_MARK, PSC5_0, PSC4_0, PTF0_FN),
+
+ PINMUX_DATA(LCDRS_MARK, PSD10_0, PSD9_1, PTF6_FN),
+ PINMUX_DATA(LCDCS_MARK, PSD10_0, PSD9_1, PTF5_FN),
+ PINMUX_DATA(LCDWR_MARK, PSD10_0, PSD9_1, PTF3_FN),
+
+ PINMUX_DATA(SCIF0_TXD_MARK, PSA6_1, PTF2_FN),
+ PINMUX_DATA(SCIF2_L_SCK_MARK, PSC7_0, PSC6_1, PTF1_FN),
+ PINMUX_DATA(SCIF2_L_RXD_MARK, PSC5_0, PSC4_1, PTF0_FN),
+
+ /* PTG FN */
+ PINMUX_DATA(AUDCK_MARK, PTG5_FN),
+ PINMUX_DATA(AUDSYNC_MARK, PTG4_FN),
+ PINMUX_DATA(AUDATA3_MARK, PTG3_FN),
+ PINMUX_DATA(AUDATA2_MARK, PTG2_FN),
+ PINMUX_DATA(AUDATA1_MARK, PTG1_FN),
+ PINMUX_DATA(AUDATA0_MARK, PTG0_FN),
+
+ /* PTH FN */
+ PINMUX_DATA(VIO0_VD_MARK, PTH7_FN),
+ PINMUX_DATA(VIO0_CLK_MARK, PTH6_FN),
+ PINMUX_DATA(VIO0_D7_MARK, PTH5_FN),
+ PINMUX_DATA(VIO0_D6_MARK, PTH4_FN),
+ PINMUX_DATA(VIO0_D5_MARK, PTH3_FN),
+ PINMUX_DATA(VIO0_D4_MARK, PTH2_FN),
+ PINMUX_DATA(VIO0_D3_MARK, PTH1_FN),
+ PINMUX_DATA(VIO0_D2_MARK, PTH0_FN),
+
+ /* PTJ FN */
+ PINMUX_DATA(PDSTATUS_MARK, PTJ7_FN),
+ PINMUX_DATA(STATUS2_MARK, PTJ6_FN),
+ PINMUX_DATA(STATUS0_MARK, PTJ5_FN),
+ PINMUX_DATA(A25_MARK, PSA8_0, PTJ3_FN),
+ PINMUX_DATA(BS_MARK, PSA8_1, PTJ3_FN),
+ PINMUX_DATA(A24_MARK, PTJ2_FN),
+ PINMUX_DATA(A23_MARK, PTJ1_FN),
+ PINMUX_DATA(A22_MARK, PTJ0_FN),
+
+ /* PTK FN */
+ PINMUX_DATA(VIO1_D5_MARK, PSB7_0, PSB6_0, PTK7_FN),
+ PINMUX_DATA(VIO1_D4_MARK, PSB7_0, PSB6_0, PTK6_FN),
+ PINMUX_DATA(VIO1_D3_MARK, PSB7_0, PSB6_0, PTK5_FN),
+ PINMUX_DATA(VIO1_D2_MARK, PSB7_0, PSB6_0, PTK4_FN),
+ PINMUX_DATA(VIO1_D1_MARK, PSB7_0, PSB6_0, PTK3_FN),
+ PINMUX_DATA(VIO1_D0_MARK, PSB7_0, PSB6_0, PTK2_FN),
+
+ PINMUX_DATA(VIO0_D13_MARK, PSB7_0, PSB6_1, PTK7_FN),
+ PINMUX_DATA(VIO0_D12_MARK, PSB7_0, PSB6_1, PTK6_FN),
+ PINMUX_DATA(VIO0_D11_MARK, PSB7_0, PSB6_1, PTK5_FN),
+ PINMUX_DATA(VIO0_D10_MARK, PSB7_0, PSB6_1, PTK4_FN),
+ PINMUX_DATA(VIO0_D9_MARK, PSB7_0, PSB6_1, PTK3_FN),
+ PINMUX_DATA(VIO0_D8_MARK, PSB7_0, PSB6_1, PTK2_FN),
+
+ PINMUX_DATA(IDED5_MARK, PSB7_1, PSB6_0, PTK7_FN),
+ PINMUX_DATA(IDED4_MARK, PSB7_1, PSB6_0, PTK6_FN),
+ PINMUX_DATA(IDED3_MARK, PSB7_1, PSB6_0, PTK5_FN),
+ PINMUX_DATA(IDED2_MARK, PSB7_1, PSB6_0, PTK4_FN),
+ PINMUX_DATA(IDED1_MARK, PSB7_1, PSB6_0, PTK3_FN),
+ PINMUX_DATA(IDED0_MARK, PSB7_1, PSB6_0, PTK2_FN),
+
+ PINMUX_DATA(VIO0_FLD_MARK, PTK1_FN),
+ PINMUX_DATA(VIO0_HD_MARK, PTK0_FN),
+
+ /* PTL FN */
+ PINMUX_DATA(DV_D5_MARK, PSB9_0, PSB8_0, PTL7_FN),
+ PINMUX_DATA(DV_D4_MARK, PSB9_0, PSB8_0, PTL6_FN),
+ PINMUX_DATA(DV_D3_MARK, PSE7_0, PSE6_0, PTL5_FN),
+ PINMUX_DATA(DV_D2_MARK, PSC9_0, PSC8_0, PTL4_FN),
+ PINMUX_DATA(DV_D1_MARK, PSC9_0, PSC8_0, PTL3_FN),
+ PINMUX_DATA(DV_D0_MARK, PSC9_0, PSC8_0, PTL2_FN),
+ PINMUX_DATA(DV_D15_MARK, PSD4_0, PTL1_FN),
+ PINMUX_DATA(DV_D14_MARK, PSE5_0, PSE4_0, PTL0_FN),
+
+ PINMUX_DATA(SCIF3_V_SCK_MARK, PSB9_0, PSB8_1, PTL7_FN),
+ PINMUX_DATA(SCIF3_V_RXD_MARK, PSB9_0, PSB8_1, PTL6_FN),
+ PINMUX_DATA(SCIF3_V_TXD_MARK, PSE7_0, PSE6_1, PTL5_FN),
+ PINMUX_DATA(SCIF1_SCK_MARK, PSC9_0, PSC8_1, PTL4_FN),
+ PINMUX_DATA(SCIF1_RXD_MARK, PSC9_0, PSC8_1, PTL3_FN),
+ PINMUX_DATA(SCIF1_TXD_MARK, PSC9_0, PSC8_1, PTL2_FN),
+
+ PINMUX_DATA(RMII_RXD0_MARK, PSB9_1, PSB8_0, PTL7_FN),
+ PINMUX_DATA(RMII_RXD1_MARK, PSB9_1, PSB8_0, PTL6_FN),
+ PINMUX_DATA(RMII_REF_CLK_MARK, PSE7_1, PSE6_0, PTL5_FN),
+ PINMUX_DATA(RMII_TX_EN_MARK, PSC9_1, PSC8_0, PTL4_FN),
+ PINMUX_DATA(RMII_TXD0_MARK, PSC9_1, PSC8_0, PTL3_FN),
+ PINMUX_DATA(RMII_TXD1_MARK, PSC9_1, PSC8_0, PTL2_FN),
+
+ PINMUX_DATA(MSIOF0_MCK_MARK, PSE5_0, PSE4_1, PTL0_FN),
+
+ /* PTM FN */
+ PINMUX_DATA(DV_D13_MARK, PSC13_0, PSC12_0, PTM7_FN),
+ PINMUX_DATA(DV_D12_MARK, PSC13_0, PSC12_0, PTM6_FN),
+ PINMUX_DATA(DV_D11_MARK, PSC13_0, PSC12_0, PTM5_FN),
+ PINMUX_DATA(DV_D10_MARK, PSC13_0, PSC12_0, PTM4_FN),
+ PINMUX_DATA(DV_D9_MARK, PSC11_0, PSC10_0, PTM3_FN),
+ PINMUX_DATA(DV_D8_MARK, PSC11_0, PSC10_0, PTM2_FN),
+
+ PINMUX_DATA(MSIOF0_TSCK_MARK, PSC13_0, PSC12_1, PTM7_FN),
+ PINMUX_DATA(MSIOF0_RXD_MARK, PSC13_0, PSC12_1, PTM6_FN),
+ PINMUX_DATA(MSIOF0_TXD_MARK, PSC13_0, PSC12_1, PTM5_FN),
+ PINMUX_DATA(MSIOF0_TSYNC_MARK, PSC13_0, PSC12_1, PTM4_FN),
+ PINMUX_DATA(MSIOF0_SS1_MARK, PSC11_0, PSC10_1, PTM3_FN),
+ PINMUX_DATA(MSIOF0_RSCK_MARK, PSC11_1, PSC10_0, PTM3_FN),
+ PINMUX_DATA(MSIOF0_SS2_MARK, PSC11_0, PSC10_1, PTM2_FN),
+ PINMUX_DATA(MSIOF0_RSYNC_MARK, PSC11_1, PSC10_0, PTM2_FN),
+
+ PINMUX_DATA(LCDVCPWC_MARK, PSA6_0, PTM1_FN),
+ PINMUX_DATA(LCDRD_MARK, PSA7_0, PTM0_FN),
+
+ PINMUX_DATA(SCIF0_RXD_MARK, PSA6_1, PTM1_FN),
+ PINMUX_DATA(SCIF0_SCK_MARK, PSA7_1, PTM0_FN),
+
+ /* PTN FN */
+ PINMUX_DATA(VIO0_D1_MARK, PTN7_FN),
+ PINMUX_DATA(VIO0_D0_MARK, PTN6_FN),
+
+ PINMUX_DATA(DV_CLKI_MARK, PSD11_0, PTN5_FN),
+ PINMUX_DATA(DV_CLK_MARK, PSD13_0, PSD12_0, PTN4_FN),
+ PINMUX_DATA(DV_VSYNC_MARK, PSD15_0, PSD14_0, PTN3_FN),
+ PINMUX_DATA(DV_HSYNC_MARK, PSB5_0, PSB4_0, PTN2_FN),
+ PINMUX_DATA(DV_D7_MARK, PSB3_0, PSB2_0, PTN1_FN),
+ PINMUX_DATA(DV_D6_MARK, PSB1_0, PSB0_0, PTN0_FN),
+
+ PINMUX_DATA(SCIF2_V_SCK_MARK, PSD13_0, PSD12_1, PTN4_FN),
+ PINMUX_DATA(SCIF2_V_RXD_MARK, PSD15_0, PSD14_1, PTN3_FN),
+ PINMUX_DATA(SCIF2_V_TXD_MARK, PSB5_0, PSB4_1, PTN2_FN),
+ PINMUX_DATA(SCIF3_V_CTS_MARK, PSB3_0, PSB2_1, PTN1_FN),
+ PINMUX_DATA(SCIF3_V_RTS_MARK, PSB1_0, PSB0_1, PTN0_FN),
+
+ PINMUX_DATA(RMII_RX_ER_MARK, PSB3_1, PSB2_0, PTN1_FN),
+ PINMUX_DATA(RMII_CRS_DV_MARK, PSB1_1, PSB0_0, PTN0_FN),
+
+ /* PTQ FN */
+ PINMUX_DATA(D7_MARK, PTQ7_FN),
+ PINMUX_DATA(D6_MARK, PTQ6_FN),
+ PINMUX_DATA(D5_MARK, PTQ5_FN),
+ PINMUX_DATA(D4_MARK, PTQ4_FN),
+ PINMUX_DATA(D3_MARK, PTQ3_FN),
+ PINMUX_DATA(D2_MARK, PTQ2_FN),
+ PINMUX_DATA(D1_MARK, PTQ1_FN),
+ PINMUX_DATA(D0_MARK, PTQ0_FN),
+
+ /* PTR FN */
+ PINMUX_DATA(CS6B_CE1B_MARK, PTR7_FN),
+ PINMUX_DATA(CS6A_CE2B_MARK, PTR6_FN),
+ PINMUX_DATA(CS5B_CE1A_MARK, PTR5_FN),
+ PINMUX_DATA(CS5A_CE2A_MARK, PTR4_FN),
+ PINMUX_DATA(IOIS16_MARK, PSA5_0, PTR3_FN),
+ PINMUX_DATA(WAIT_MARK, PTR2_FN),
+ PINMUX_DATA(WE3_ICIOWR_MARK, PSA1_0, PSA0_0, PTR1_FN),
+ PINMUX_DATA(WE2_ICIORD_MARK, PSD1_0, PSD0_0, PTR0_FN),
+
+ PINMUX_DATA(LCDLCLK_MARK, PSA5_1, PTR3_FN),
+
+ PINMUX_DATA(IDEA2_MARK, PSD1_1, PSD0_0, PTR0_FN),
+
+ PINMUX_DATA(TPUTO3_MARK, PSA1_0, PSA0_1, PTR1_FN),
+ PINMUX_DATA(TPUTI3_MARK, PSA1_1, PSA0_0, PTR1_FN),
+ PINMUX_DATA(TPUTO2_MARK, PSD1_0, PSD0_1, PTR0_FN),
+
+ /* PTS FN */
+ PINMUX_DATA(VIO_CKO_MARK, PTS6_FN),
+
+ PINMUX_DATA(TPUTI2_MARK, PSE9_0, PSE8_1, PTS5_FN),
+
+ PINMUX_DATA(IDEIORDY_MARK, PSE9_1, PSE8_0, PTS5_FN),
+
+ PINMUX_DATA(VIO1_FLD_MARK, PSE9_0, PSE8_0, PTS5_FN),
+ PINMUX_DATA(VIO1_HD_MARK, PSA10_0, PTS4_FN),
+ PINMUX_DATA(VIO1_VD_MARK, PSA9_0, PTS3_FN),
+ PINMUX_DATA(VIO1_CLK_MARK, PSA9_0, PTS2_FN),
+ PINMUX_DATA(VIO1_D7_MARK, PSB7_0, PSB6_0, PTS1_FN),
+ PINMUX_DATA(VIO1_D6_MARK, PSB7_0, PSB6_0, PTS0_FN),
+
+ PINMUX_DATA(SCIF5_SCK_MARK, PSA10_1, PTS4_FN),
+ PINMUX_DATA(SCIF5_RXD_MARK, PSA9_1, PTS3_FN),
+ PINMUX_DATA(SCIF5_TXD_MARK, PSA9_1, PTS2_FN),
+
+ PINMUX_DATA(VIO0_D15_MARK, PSB7_0, PSB6_1, PTS1_FN),
+ PINMUX_DATA(VIO0_D14_MARK, PSB7_0, PSB6_1, PTS0_FN),
+
+ PINMUX_DATA(IDED7_MARK, PSB7_1, PSB6_0, PTS1_FN),
+ PINMUX_DATA(IDED6_MARK, PSB7_1, PSB6_0, PTS0_FN),
+
+ /* PTT FN */
+ PINMUX_DATA(D15_MARK, PTT7_FN),
+ PINMUX_DATA(D14_MARK, PTT6_FN),
+ PINMUX_DATA(D13_MARK, PTT5_FN),
+ PINMUX_DATA(D12_MARK, PTT4_FN),
+ PINMUX_DATA(D11_MARK, PTT3_FN),
+ PINMUX_DATA(D10_MARK, PTT2_FN),
+ PINMUX_DATA(D9_MARK, PTT1_FN),
+ PINMUX_DATA(D8_MARK, PTT0_FN),
+
+ /* PTU FN */
+ PINMUX_DATA(DMAC_DACK0_MARK, PTU7_FN),
+ PINMUX_DATA(DMAC_DREQ0_MARK, PTU6_FN),
+
+ PINMUX_DATA(FSIOASD_MARK, PSE1_0, PTU5_FN),
+ PINMUX_DATA(FSIIABCK_MARK, PSE1_0, PTU4_FN),
+ PINMUX_DATA(FSIIALRCK_MARK, PSE1_0, PTU3_FN),
+ PINMUX_DATA(FSIOABCK_MARK, PSE1_0, PTU2_FN),
+ PINMUX_DATA(FSIOALRCK_MARK, PSE1_0, PTU1_FN),
+ PINMUX_DATA(CLKAUDIOAO_MARK, PSE0_0, PTU0_FN),
+
+ /* PTV FN */
+ PINMUX_DATA(FSIIBSD_MARK, PSD7_0, PSD6_0, PTV7_FN),
+ PINMUX_DATA(FSIOBSD_MARK, PSD7_0, PSD6_0, PTV6_FN),
+ PINMUX_DATA(FSIIBBCK_MARK, PSC15_0, PSC14_0, PTV5_FN),
+ PINMUX_DATA(FSIIBLRCK_MARK, PSC15_0, PSC14_0, PTV4_FN),
+ PINMUX_DATA(FSIOBBCK_MARK, PSC15_0, PSC14_0, PTV3_FN),
+ PINMUX_DATA(FSIOBLRCK_MARK, PSC15_0, PSC14_0, PTV2_FN),
+ PINMUX_DATA(CLKAUDIOBO_MARK, PSE3_0, PSE2_0, PTV1_FN),
+ PINMUX_DATA(FSIIASD_MARK, PSE10_0, PTV0_FN),
+
+ PINMUX_DATA(MSIOF1_SS2_MARK, PSD7_0, PSD6_1, PTV7_FN),
+ PINMUX_DATA(MSIOF1_RSYNC_MARK, PSD7_1, PSD6_0, PTV7_FN),
+ PINMUX_DATA(MSIOF1_SS1_MARK, PSD7_0, PSD6_1, PTV6_FN),
+ PINMUX_DATA(MSIOF1_RSCK_MARK, PSD7_1, PSD6_0, PTV6_FN),
+ PINMUX_DATA(MSIOF1_RXD_MARK, PSC15_0, PSC14_1, PTV5_FN),
+ PINMUX_DATA(MSIOF1_TSYNC_MARK, PSC15_0, PSC14_1, PTV4_FN),
+ PINMUX_DATA(MSIOF1_TSCK_MARK, PSC15_0, PSC14_1, PTV3_FN),
+ PINMUX_DATA(MSIOF1_TXD_MARK, PSC15_0, PSC14_1, PTV2_FN),
+ PINMUX_DATA(MSIOF1_MCK_MARK, PSE3_0, PSE2_1, PTV1_FN),
+
+ /* PTW FN */
+ PINMUX_DATA(MMC_D7_MARK, PSE13_0, PSE12_0, PTW7_FN),
+ PINMUX_DATA(MMC_D6_MARK, PSE13_0, PSE12_0, PTW6_FN),
+ PINMUX_DATA(MMC_D5_MARK, PSE13_0, PSE12_0, PTW5_FN),
+ PINMUX_DATA(MMC_D4_MARK, PSE13_0, PSE12_0, PTW4_FN),
+ PINMUX_DATA(MMC_D3_MARK, PSA13_0, PTW3_FN),
+ PINMUX_DATA(MMC_D2_MARK, PSA13_0, PTW2_FN),
+ PINMUX_DATA(MMC_D1_MARK, PSA13_0, PTW1_FN),
+ PINMUX_DATA(MMC_D0_MARK, PSA13_0, PTW0_FN),
+
+ PINMUX_DATA(SDHI1CD_MARK, PSE13_0, PSE12_1, PTW7_FN),
+ PINMUX_DATA(SDHI1WP_MARK, PSE13_0, PSE12_1, PTW6_FN),
+ PINMUX_DATA(SDHI1D3_MARK, PSE13_0, PSE12_1, PTW5_FN),
+ PINMUX_DATA(SDHI1D2_MARK, PSE13_0, PSE12_1, PTW4_FN),
+ PINMUX_DATA(SDHI1D1_MARK, PSA13_1, PTW3_FN),
+ PINMUX_DATA(SDHI1D0_MARK, PSA13_1, PTW2_FN),
+ PINMUX_DATA(SDHI1CMD_MARK, PSA13_1, PTW1_FN),
+ PINMUX_DATA(SDHI1CLK_MARK, PSA13_1, PTW0_FN),
+
+ PINMUX_DATA(IODACK_MARK, PSE13_1, PSE12_0, PTW7_FN),
+ PINMUX_DATA(IDERST_MARK, PSE13_1, PSE12_0, PTW6_FN),
+ PINMUX_DATA(EXBUF_ENB_MARK, PSE13_1, PSE12_0, PTW5_FN),
+ PINMUX_DATA(DIRECTION_MARK, PSE13_1, PSE12_0, PTW4_FN),
+
+ /* PTX FN */
+ PINMUX_DATA(DMAC_DACK1_MARK, PSA12_0, PTX7_FN),
+ PINMUX_DATA(DMAC_DREQ1_MARK, PSA12_0, PTX6_FN),
+
+ PINMUX_DATA(IRDA_OUT_MARK, PSA12_1, PTX7_FN),
+ PINMUX_DATA(IRDA_IN_MARK, PSA12_1, PTX6_FN),
+
+ PINMUX_DATA(TSIF_TS0_SDAT_MARK, PSC0_0, PTX5_FN),
+ PINMUX_DATA(TSIF_TS0_SCK_MARK, PSC1_0, PTX4_FN),
+ PINMUX_DATA(TSIF_TS0_SDEN_MARK, PSC2_0, PTX3_FN),
+ PINMUX_DATA(TSIF_TS0_SPSYNC_MARK, PTX2_FN),
+
+ PINMUX_DATA(LNKSTA_MARK, PSC0_1, PTX5_FN),
+ PINMUX_DATA(MDIO_MARK, PSC1_1, PTX4_FN),
+ PINMUX_DATA(MDC_MARK, PSC2_1, PTX3_FN),
+
+ PINMUX_DATA(MMC_CLK_MARK, PTX1_FN),
+ PINMUX_DATA(MMC_CMD_MARK, PTX0_FN),
+
+ /* PTY FN */
+ PINMUX_DATA(SDHI0CD_MARK, PTY7_FN),
+ PINMUX_DATA(SDHI0WP_MARK, PTY6_FN),
+ PINMUX_DATA(SDHI0D3_MARK, PTY5_FN),
+ PINMUX_DATA(SDHI0D2_MARK, PTY4_FN),
+ PINMUX_DATA(SDHI0D1_MARK, PTY3_FN),
+ PINMUX_DATA(SDHI0D0_MARK, PTY2_FN),
+ PINMUX_DATA(SDHI0CMD_MARK, PTY1_FN),
+ PINMUX_DATA(SDHI0CLK_MARK, PTY0_FN),
+
+ /* PTZ FN */
+ PINMUX_DATA(INTC_IRQ7_MARK, PSB10_0, PTZ7_FN),
+ PINMUX_DATA(INTC_IRQ6_MARK, PSB11_0, PTZ6_FN),
+ PINMUX_DATA(INTC_IRQ5_MARK, PSB12_0, PTZ5_FN),
+ PINMUX_DATA(INTC_IRQ4_MARK, PSB13_0, PTZ4_FN),
+ PINMUX_DATA(INTC_IRQ3_MARK, PSB14_0, PTZ3_FN),
+ PINMUX_DATA(INTC_IRQ2_MARK, PTZ2_FN),
+ PINMUX_DATA(INTC_IRQ1_MARK, PTZ1_FN),
+ PINMUX_DATA(INTC_IRQ0_MARK, PTZ0_FN),
+
+ PINMUX_DATA(SCIF3_I_CTS_MARK, PSB10_1, PTZ7_FN),
+ PINMUX_DATA(SCIF3_I_RTS_MARK, PSB11_1, PTZ6_FN),
+ PINMUX_DATA(SCIF3_I_SCK_MARK, PSB12_1, PTZ5_FN),
+ PINMUX_DATA(SCIF3_I_RXD_MARK, PSB13_1, PTZ4_FN),
+ PINMUX_DATA(SCIF3_I_TXD_MARK, PSB14_1, PTZ3_FN),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ /* PTA */
+ PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
+ PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
+ PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
+ PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
+ PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
+ PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
+ PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
+ PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+
+ /* PTB */
+ PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
+ PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
+ PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
+ PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
+ PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
+ PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
+ PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
+ PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+
+ /* PTC */
+ PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
+ PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
+ PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
+ PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
+ PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
+ PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
+ PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
+ PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+
+ /* PTD */
+ PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
+ PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
+ PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
+ PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
+ PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
+ PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
+ PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
+ PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+
+ /* PTE */
+ PINMUX_GPIO(GPIO_PTE7, PTE7_DATA),
+ PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
+ PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
+ PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
+ PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
+ PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
+ PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
+ PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+
+ /* PTF */
+ PINMUX_GPIO(GPIO_PTF7, PTF7_DATA),
+ PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
+ PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
+ PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
+ PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
+ PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
+ PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
+ PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+
+ /* PTG */
+ PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
+ PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
+ PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
+ PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
+ PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
+ PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+
+ /* PTH */
+ PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
+ PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
+ PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
+ PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
+ PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
+ PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
+ PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
+ PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+
+ /* PTJ */
+ PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
+ PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
+ PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
+ PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
+ PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
+ PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
+ PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+
+ /* PTK */
+ PINMUX_GPIO(GPIO_PTK7, PTK7_DATA),
+ PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
+ PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
+ PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
+ PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
+ PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
+ PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
+ PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+
+ /* PTL */
+ PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
+ PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
+ PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
+ PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
+ PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
+ PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
+ PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
+ PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
+
+ /* PTM */
+ PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
+ PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
+ PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
+ PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
+ PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
+ PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
+ PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
+ PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+
+ /* PTN */
+ PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
+ PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
+ PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
+ PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
+ PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
+ PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
+ PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
+ PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
+
+ /* PTQ */
+ PINMUX_GPIO(GPIO_PTQ7, PTQ7_DATA),
+ PINMUX_GPIO(GPIO_PTQ6, PTQ6_DATA),
+ PINMUX_GPIO(GPIO_PTQ5, PTQ5_DATA),
+ PINMUX_GPIO(GPIO_PTQ4, PTQ4_DATA),
+ PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
+ PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
+ PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
+ PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
+
+ /* PTR */
+ PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
+ PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
+ PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
+ PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
+ PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
+ PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
+ PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
+ PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+
+ /* PTS */
+ PINMUX_GPIO(GPIO_PTS6, PTS6_DATA),
+ PINMUX_GPIO(GPIO_PTS5, PTS5_DATA),
+ PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
+ PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
+ PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
+ PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
+ PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+
+ /* PTT */
+ PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
+ PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
+ PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
+ PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
+ PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
+ PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
+ PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
+ PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+
+ /* PTU */
+ PINMUX_GPIO(GPIO_PTU7, PTU7_DATA),
+ PINMUX_GPIO(GPIO_PTU6, PTU6_DATA),
+ PINMUX_GPIO(GPIO_PTU5, PTU5_DATA),
+ PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
+ PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
+ PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
+ PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
+ PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+
+ /* PTV */
+ PINMUX_GPIO(GPIO_PTV7, PTV7_DATA),
+ PINMUX_GPIO(GPIO_PTV6, PTV6_DATA),
+ PINMUX_GPIO(GPIO_PTV5, PTV5_DATA),
+ PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
+ PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
+ PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
+ PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
+ PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+
+ /* PTW */
+ PINMUX_GPIO(GPIO_PTW7, PTW7_DATA),
+ PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
+ PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
+ PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
+ PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
+ PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
+ PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
+ PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
+
+ /* PTX */
+ PINMUX_GPIO(GPIO_PTX7, PTX7_DATA),
+ PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
+ PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
+ PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
+ PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
+ PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
+ PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
+ PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
+
+ /* PTY */
+ PINMUX_GPIO(GPIO_PTY7, PTY7_DATA),
+ PINMUX_GPIO(GPIO_PTY6, PTY6_DATA),
+ PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
+ PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
+ PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
+ PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
+ PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
+ PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
+
+ /* PTZ */
+ PINMUX_GPIO(GPIO_PTZ7, PTZ7_DATA),
+ PINMUX_GPIO(GPIO_PTZ6, PTZ6_DATA),
+ PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
+ PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
+ PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
+ PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
+ PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
+ PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
+
+ /* BSC */
+ PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
+ PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
+ PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
+ PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
+ PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
+ PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
+ PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
+ PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
+ PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
+ PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
+ PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
+ PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
+ PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
+ PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
+ PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
+ PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
+ PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+ PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+ PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+ PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+ PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+ PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+ PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+ PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+ PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
+ PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
+ PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
+ PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
+ PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
+ PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
+ PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
+ PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+ PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+ PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6B_CE1B, CS6B_CE1B_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6A_CE2B, CS6A_CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5B_CE1A, CS5B_CE1A_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5A_CE2A, CS5A_CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_WE3_ICIOWR, WE3_ICIOWR_MARK),
+ PINMUX_GPIO(GPIO_FN_WE2_ICIORD, WE2_ICIORD_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+ PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+ PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+
+ /* KEYSC */
+ PINMUX_GPIO(GPIO_FN_KEYOUT5_IN5, KEYOUT5_IN5_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT4_IN6, KEYOUT4_IN6_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN4, KEYIN4_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN3, KEYIN3_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN2, KEYIN2_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN1, KEYIN1_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYIN0, KEYIN0_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT3, KEYOUT3_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT2, KEYOUT2_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT1, KEYOUT1_MARK),
+ PINMUX_GPIO(GPIO_FN_KEYOUT0, KEYOUT0_MARK),
+
+ /* ATAPI */
+ PINMUX_GPIO(GPIO_FN_IDED15, IDED15_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED14, IDED14_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED13, IDED13_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED12, IDED12_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED11, IDED11_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED10, IDED10_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED9, IDED9_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED8, IDED8_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED7, IDED7_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED6, IDED6_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED5, IDED5_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED4, IDED4_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED3, IDED3_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED2, IDED2_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED1, IDED1_MARK),
+ PINMUX_GPIO(GPIO_FN_IDED0, IDED0_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEA2, IDEA2_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEA1, IDEA1_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEA0, IDEA0_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEIOWR, IDEIOWR_MARK),
+ PINMUX_GPIO(GPIO_FN_IODREQ, IODREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_IDECS0, IDECS0_MARK),
+ PINMUX_GPIO(GPIO_FN_IDECS1, IDECS1_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEIORD, IDEIORD_MARK),
+ PINMUX_GPIO(GPIO_FN_DIRECTION, DIRECTION_MARK),
+ PINMUX_GPIO(GPIO_FN_EXBUF_ENB, EXBUF_ENB_MARK),
+ PINMUX_GPIO(GPIO_FN_IDERST, IDERST_MARK),
+ PINMUX_GPIO(GPIO_FN_IODACK, IODACK_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEINT, IDEINT_MARK),
+ PINMUX_GPIO(GPIO_FN_IDEIORDY, IDEIORDY_MARK),
+
+ /* TPU */
+ PINMUX_GPIO(GPIO_FN_TPUTO3, TPUTO3_MARK),
+ PINMUX_GPIO(GPIO_FN_TPUTO2, TPUTO2_MARK),
+ PINMUX_GPIO(GPIO_FN_TPUTO1, TPUTO1_MARK),
+ PINMUX_GPIO(GPIO_FN_TPUTO0, TPUTO0_MARK),
+ PINMUX_GPIO(GPIO_FN_TPUTI3, TPUTI3_MARK),
+ PINMUX_GPIO(GPIO_FN_TPUTI2, TPUTI2_MARK),
+
+ /* LCDC */
+ PINMUX_GPIO(GPIO_FN_LCDD23, LCDD23_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD22, LCDD22_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD21, LCDD21_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD20, LCDD20_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD19, LCDD19_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD18, LCDD18_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD17, LCDD17_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD16, LCDD16_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD15, LCDD15_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD14, LCDD14_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD13, LCDD13_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD12, LCDD12_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD11, LCDD11_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD10, LCDD10_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD9, LCDD9_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD8, LCDD8_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD7, LCDD7_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD6, LCDD6_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD5, LCDD5_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD4, LCDD4_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD3, LCDD3_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD2, LCDD2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD1, LCDD1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDD0, LCDD0_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVSYN, LCDVSYN_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDDISP, LCDDISP_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDRS, LCDRS_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDHSYN, LCDHSYN_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDCS, LCDCS_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDDON, LCDDON_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDDCK, LCDDCK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDWR, LCDWR_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVEPWC, LCDVEPWC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDVCPWC, LCDVCPWC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDRD, LCDRD_MARK),
+ PINMUX_GPIO(GPIO_FN_LCDLCLK, LCDLCLK_MARK),
+
+ /* SCIF0 */
+ PINMUX_GPIO(GPIO_FN_SCIF0_TXD, SCIF0_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_RXD, SCIF0_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_SCK, SCIF0_SCK_MARK),
+
+ /* SCIF1 */
+ PINMUX_GPIO(GPIO_FN_SCIF1_SCK, SCIF1_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_RXD, SCIF1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_TXD, SCIF1_TXD_MARK),
+
+ /* SCIF2 */
+ PINMUX_GPIO(GPIO_FN_SCIF2_L_TXD, SCIF2_L_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_L_SCK, SCIF2_L_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_L_RXD, SCIF2_L_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_V_TXD, SCIF2_V_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_V_SCK, SCIF2_V_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_V_RXD, SCIF2_V_RXD_MARK),
+
+ /* SCIF3 */
+ PINMUX_GPIO(GPIO_FN_SCIF3_V_SCK, SCIF3_V_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_V_RXD, SCIF3_V_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_V_TXD, SCIF3_V_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_V_CTS, SCIF3_V_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_V_RTS, SCIF3_V_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_I_SCK, SCIF3_I_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_I_RXD, SCIF3_I_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_I_TXD, SCIF3_I_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_I_CTS, SCIF3_I_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_I_RTS, SCIF3_I_RTS_MARK),
+
+ /* SCIF4 */
+ PINMUX_GPIO(GPIO_FN_SCIF4_SCK, SCIF4_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_RXD, SCIF4_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_TXD, SCIF4_TXD_MARK),
+
+ /* SCIF5 */
+ PINMUX_GPIO(GPIO_FN_SCIF5_SCK, SCIF5_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_RXD, SCIF5_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_TXD, SCIF5_TXD_MARK),
+
+ /* FSI */
+ PINMUX_GPIO(GPIO_FN_FSIMCKB, FSIMCKB_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIMCKA, FSIMCKA_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIOASD, FSIOASD_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIIABCK, FSIIABCK_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIIALRCK, FSIIALRCK_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIOABCK, FSIOABCK_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIOALRCK, FSIOALRCK_MARK),
+ PINMUX_GPIO(GPIO_FN_CLKAUDIOAO, CLKAUDIOAO_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIIBSD, FSIIBSD_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIOBSD, FSIOBSD_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIIBBCK, FSIIBBCK_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIIBLRCK, FSIIBLRCK_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIOBBCK, FSIOBBCK_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIOBLRCK, FSIOBLRCK_MARK),
+ PINMUX_GPIO(GPIO_FN_CLKAUDIOBO, CLKAUDIOBO_MARK),
+ PINMUX_GPIO(GPIO_FN_FSIIASD, FSIIASD_MARK),
+
+ /* AUD */
+ PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
+
+ /* VIO */
+ PINMUX_GPIO(GPIO_FN_VIO_CKO, VIO_CKO_MARK),
+
+ /* VIO0 */
+ PINMUX_GPIO(GPIO_FN_VIO0_D15, VIO0_D15_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D14, VIO0_D14_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D13, VIO0_D13_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D12, VIO0_D12_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D11, VIO0_D11_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D10, VIO0_D10_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D9, VIO0_D9_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D8, VIO0_D8_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D7, VIO0_D7_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D6, VIO0_D6_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D5, VIO0_D5_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D4, VIO0_D4_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D3, VIO0_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D2, VIO0_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D1, VIO0_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_D0, VIO0_D0_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_VD, VIO0_VD_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_CLK, VIO0_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_FLD, VIO0_FLD_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO0_HD, VIO0_HD_MARK),
+
+ /* VIO1 */
+ PINMUX_GPIO(GPIO_FN_VIO1_D7, VIO1_D7_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_D6, VIO1_D6_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_D5, VIO1_D5_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_D4, VIO1_D4_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_D3, VIO1_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_D2, VIO1_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_D1, VIO1_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_D0, VIO1_D0_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_FLD, VIO1_FLD_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_HD, VIO1_HD_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_VD, VIO1_VD_MARK),
+ PINMUX_GPIO(GPIO_FN_VIO1_CLK, VIO1_CLK_MARK),
+
+ /* Eth */
+ PINMUX_GPIO(GPIO_FN_RMII_RXD0, RMII_RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII_RXD1, RMII_RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII_TXD0, RMII_TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII_TXD1, RMII_TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII_REF_CLK, RMII_REF_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII_TX_EN, RMII_TX_EN_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII_RX_ER, RMII_RX_ER_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII_CRS_DV, RMII_CRS_DV_MARK),
+ PINMUX_GPIO(GPIO_FN_LNKSTA, LNKSTA_MARK),
+ PINMUX_GPIO(GPIO_FN_MDIO, MDIO_MARK),
+ PINMUX_GPIO(GPIO_FN_MDC, MDC_MARK),
+
+ /* System */
+ PINMUX_GPIO(GPIO_FN_PDSTATUS, PDSTATUS_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS2, STATUS2_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
+
+ /* VOU */
+ PINMUX_GPIO(GPIO_FN_DV_D15, DV_D15_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D14, DV_D14_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D13, DV_D13_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D12, DV_D12_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D11, DV_D11_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D10, DV_D10_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D9, DV_D9_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D8, DV_D8_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D7, DV_D7_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D6, DV_D6_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D5, DV_D5_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D4, DV_D4_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D3, DV_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D2, DV_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D1, DV_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_D0, DV_D0_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_CLKI, DV_CLKI_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+
+ /* MSIOF0 */
+ PINMUX_GPIO(GPIO_FN_MSIOF0_RXD, MSIOF0_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_TXD, MSIOF0_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_MCK, MSIOF0_MCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_TSCK, MSIOF0_TSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_SS1, MSIOF0_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_SS2, MSIOF0_SS2_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_TSYNC, MSIOF0_TSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_RSCK, MSIOF0_RSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF0_RSYNC, MSIOF0_RSYNC_MARK),
+
+ /* MSIOF1 */
+ PINMUX_GPIO(GPIO_FN_MSIOF1_RXD, MSIOF1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_TXD, MSIOF1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_MCK, MSIOF1_MCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_TSCK, MSIOF1_TSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_SS1, MSIOF1_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_SS2, MSIOF1_SS2_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_TSYNC, MSIOF1_TSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_RSCK, MSIOF1_RSCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MSIOF1_RSYNC, MSIOF1_RSYNC_MARK),
+
+ /* DMAC */
+ PINMUX_GPIO(GPIO_FN_DMAC_DACK0, DMAC_DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DMAC_DREQ0, DMAC_DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_DMAC_DACK1, DMAC_DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DMAC_DREQ1, DMAC_DREQ1_MARK),
+
+ /* SDHI0 */
+ PINMUX_GPIO(GPIO_FN_SDHI0CD, SDHI0CD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0WP, SDHI0WP_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0CMD, SDHI0CMD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0CLK, SDHI0CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D3, SDHI0D3_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D2, SDHI0D2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D1, SDHI0D1_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI0D0, SDHI0D0_MARK),
+
+ /* SDHI1 */
+ PINMUX_GPIO(GPIO_FN_SDHI1CD, SDHI1CD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1WP, SDHI1WP_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1CMD, SDHI1CMD_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1CLK, SDHI1CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1D3, SDHI1D3_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1D2, SDHI1D2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1D1, SDHI1D1_MARK),
+ PINMUX_GPIO(GPIO_FN_SDHI1D0, SDHI1D0_MARK),
+
+ /* MMC */
+ PINMUX_GPIO(GPIO_FN_MMC_D7, MMC_D7_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_D6, MMC_D6_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_D5, MMC_D5_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_D4, MMC_D4_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_D3, MMC_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_D2, MMC_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_D1, MMC_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_D0, MMC_D0_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_CLK, MMC_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_MMC_CMD, MMC_CMD_MARK),
+
+ /* IrDA */
+ PINMUX_GPIO(GPIO_FN_IRDA_OUT, IRDA_OUT_MARK),
+ PINMUX_GPIO(GPIO_FN_IRDA_IN, IRDA_IN_MARK),
+
+ /* TSIF */
+ PINMUX_GPIO(GPIO_FN_TSIF_TS0_SDAT, TSIF_TS0_SDAT_MARK),
+ PINMUX_GPIO(GPIO_FN_TSIF_TS0_SCK, TSIF_TS0_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_TSIF_TS0_SDEN, TSIF_TS0_SDEN_MARK),
+ PINMUX_GPIO(GPIO_FN_TSIF_TS0_SPSYNC, TSIF_TS0_SPSYNC_MARK),
+
+ /* IRQ */
+ PINMUX_GPIO(GPIO_FN_INTC_IRQ7, INTC_IRQ7_MARK),
+ PINMUX_GPIO(GPIO_FN_INTC_IRQ6, INTC_IRQ6_MARK),
+ PINMUX_GPIO(GPIO_FN_INTC_IRQ5, INTC_IRQ5_MARK),
+ PINMUX_GPIO(GPIO_FN_INTC_IRQ4, INTC_IRQ4_MARK),
+ PINMUX_GPIO(GPIO_FN_INTC_IRQ3, INTC_IRQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_INTC_IRQ2, INTC_IRQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_INTC_IRQ1, INTC_IRQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_INTC_IRQ0, INTC_IRQ0_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
+ PTA7_FN, PTA7_OUT, PTA7_IN_PU, PTA7_IN,
+ PTA6_FN, PTA6_OUT, PTA6_IN_PU, PTA6_IN,
+ PTA5_FN, PTA5_OUT, PTA5_IN_PU, PTA5_IN,
+ PTA4_FN, PTA4_OUT, PTA4_IN_PU, PTA4_IN,
+ PTA3_FN, PTA3_OUT, PTA3_IN_PU, PTA3_IN,
+ PTA2_FN, PTA2_OUT, PTA2_IN_PU, PTA2_IN,
+ PTA1_FN, PTA1_OUT, PTA1_IN_PU, PTA1_IN,
+ PTA0_FN, PTA0_OUT, PTA0_IN_PU, PTA0_IN }
+ },
+ { PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
+ PTB7_FN, PTB7_OUT, PTB7_IN_PU, PTB7_IN,
+ PTB6_FN, PTB6_OUT, PTB6_IN_PU, PTB6_IN,
+ PTB5_FN, PTB5_OUT, PTB5_IN_PU, PTB5_IN,
+ PTB4_FN, PTB4_OUT, PTB4_IN_PU, PTB4_IN,
+ PTB3_FN, PTB3_OUT, PTB3_IN_PU, PTB3_IN,
+ PTB2_FN, PTB2_OUT, PTB2_IN_PU, PTB2_IN,
+ PTB1_FN, PTB1_OUT, PTB1_IN_PU, PTB1_IN,
+ PTB0_FN, PTB0_OUT, PTB0_IN_PU, PTB0_IN }
+ },
+ { PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
+ PTC7_FN, PTC7_OUT, PTC7_IN_PU, PTC7_IN,
+ PTC6_FN, PTC6_OUT, PTC6_IN_PU, PTC6_IN,
+ PTC5_FN, PTC5_OUT, PTC5_IN_PU, PTC5_IN,
+ PTC4_FN, PTC4_OUT, PTC4_IN_PU, PTC4_IN,
+ PTC3_FN, PTC3_OUT, PTC3_IN_PU, PTC3_IN,
+ PTC2_FN, PTC2_OUT, PTC2_IN_PU, PTC2_IN,
+ PTC1_FN, PTC1_OUT, PTC1_IN_PU, PTC1_IN,
+ PTC0_FN, PTC0_OUT, PTC0_IN_PU, PTC0_IN }
+ },
+ { PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
+ PTD7_FN, PTD7_OUT, PTD7_IN_PU, PTD7_IN,
+ PTD6_FN, PTD6_OUT, PTD6_IN_PU, PTD6_IN,
+ PTD5_FN, PTD5_OUT, PTD5_IN_PU, PTD5_IN,
+ PTD4_FN, PTD4_OUT, PTD4_IN_PU, PTD4_IN,
+ PTD3_FN, PTD3_OUT, PTD3_IN_PU, PTD3_IN,
+ PTD2_FN, PTD2_OUT, PTD2_IN_PU, PTD2_IN,
+ PTD1_FN, PTD1_OUT, PTD1_IN_PU, PTD1_IN,
+ PTD0_FN, PTD0_OUT, PTD0_IN_PU, PTD0_IN }
+ },
+ { PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
+ PTE7_FN, PTE7_OUT, PTE7_IN_PU, PTE7_IN,
+ PTE6_FN, PTE6_OUT, PTE6_IN_PU, PTE6_IN,
+ PTE5_FN, PTE5_OUT, PTE5_IN_PU, PTE5_IN,
+ PTE4_FN, PTE4_OUT, PTE4_IN_PU, PTE4_IN,
+ PTE3_FN, PTE3_OUT, PTE3_IN_PU, PTE3_IN,
+ PTE2_FN, PTE2_OUT, PTE2_IN_PU, PTE2_IN,
+ PTE1_FN, PTE1_OUT, PTE1_IN_PU, PTE1_IN,
+ PTE0_FN, PTE0_OUT, PTE0_IN_PU, PTE0_IN }
+ },
+ { PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
+ PTF7_FN, PTF7_OUT, PTF7_IN_PU, PTF7_IN,
+ PTF6_FN, PTF6_OUT, PTF6_IN_PU, PTF6_IN,
+ PTF5_FN, PTF5_OUT, PTF5_IN_PU, PTF5_IN,
+ PTF4_FN, PTF4_OUT, PTF4_IN_PU, PTF4_IN,
+ PTF3_FN, PTF3_OUT, PTF3_IN_PU, PTF3_IN,
+ PTF2_FN, PTF2_OUT, PTF2_IN_PU, PTF2_IN,
+ PTF1_FN, PTF1_OUT, PTF1_IN_PU, PTF1_IN,
+ PTF0_FN, PTF0_OUT, PTF0_IN_PU, PTF0_IN }
+ },
+ { PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PTG5_FN, PTG5_OUT, 0, 0,
+ PTG4_FN, PTG4_OUT, 0, 0,
+ PTG3_FN, PTG3_OUT, 0, 0,
+ PTG2_FN, PTG2_OUT, 0, 0,
+ PTG1_FN, PTG1_OUT, 0, 0,
+ PTG0_FN, PTG0_OUT, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
+ PTH7_FN, PTH7_OUT, PTH7_IN_PU, PTH7_IN,
+ PTH6_FN, PTH6_OUT, PTH6_IN_PU, PTH6_IN,
+ PTH5_FN, PTH5_OUT, PTH5_IN_PU, PTH5_IN,
+ PTH4_FN, PTH4_OUT, PTH4_IN_PU, PTH4_IN,
+ PTH3_FN, PTH3_OUT, PTH3_IN_PU, PTH3_IN,
+ PTH2_FN, PTH2_OUT, PTH2_IN_PU, PTH2_IN,
+ PTH1_FN, PTH1_OUT, PTH1_IN_PU, PTH1_IN,
+ PTH0_FN, PTH0_OUT, PTH0_IN_PU, PTH0_IN }
+ },
+ { PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
+ PTJ7_FN, PTJ7_OUT, 0, 0,
+ PTJ6_FN, PTJ6_OUT, 0, 0,
+ PTJ5_FN, PTJ5_OUT, 0, 0,
+ 0, 0, 0, 0,
+ PTJ3_FN, PTJ3_OUT, PTJ3_IN_PU, PTJ3_IN,
+ PTJ2_FN, PTJ2_OUT, PTJ2_IN_PU, PTJ2_IN,
+ PTJ1_FN, PTJ1_OUT, PTJ1_IN_PU, PTJ1_IN,
+ PTJ0_FN, PTJ0_OUT, PTJ0_IN_PU, PTJ0_IN }
+ },
+ { PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
+ PTK7_FN, PTK7_OUT, PTK7_IN_PU, PTK7_IN,
+ PTK6_FN, PTK6_OUT, PTK6_IN_PU, PTK6_IN,
+ PTK5_FN, PTK5_OUT, PTK5_IN_PU, PTK5_IN,
+ PTK4_FN, PTK4_OUT, PTK4_IN_PU, PTK4_IN,
+ PTK3_FN, PTK3_OUT, PTK3_IN_PU, PTK3_IN,
+ PTK2_FN, PTK2_OUT, PTK2_IN_PU, PTK2_IN,
+ PTK1_FN, PTK1_OUT, PTK1_IN_PU, PTK1_IN,
+ PTK0_FN, PTK0_OUT, PTK0_IN_PU, PTK0_IN }
+ },
+ { PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
+ PTL7_FN, PTL7_OUT, PTL7_IN_PU, PTL7_IN,
+ PTL6_FN, PTL6_OUT, PTL6_IN_PU, PTL6_IN,
+ PTL5_FN, PTL5_OUT, PTL5_IN_PU, PTL5_IN,
+ PTL4_FN, PTL4_OUT, PTL4_IN_PU, PTL4_IN,
+ PTL3_FN, PTL3_OUT, PTL3_IN_PU, PTL3_IN,
+ PTL2_FN, PTL2_OUT, PTL2_IN_PU, PTL2_IN,
+ PTL1_FN, PTL1_OUT, PTL1_IN_PU, PTL1_IN,
+ PTL0_FN, PTL0_OUT, PTL0_IN_PU, PTL0_IN }
+ },
+ { PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
+ PTM7_FN, PTM7_OUT, PTM7_IN_PU, PTM7_IN,
+ PTM6_FN, PTM6_OUT, PTM6_IN_PU, PTM6_IN,
+ PTM5_FN, PTM5_OUT, PTM5_IN_PU, PTM5_IN,
+ PTM4_FN, PTM4_OUT, PTM4_IN_PU, PTM4_IN,
+ PTM3_FN, PTM3_OUT, PTM3_IN_PU, PTM3_IN,
+ PTM2_FN, PTM2_OUT, PTM2_IN_PU, PTM2_IN,
+ PTM1_FN, PTM1_OUT, PTM1_IN_PU, PTM1_IN,
+ PTM0_FN, PTM0_OUT, PTM0_IN_PU, PTM0_IN }
+ },
+ { PINMUX_CFG_REG("PNCR", 0xa4050118, 16, 2) {
+ PTN7_FN, PTN7_OUT, PTN7_IN_PU, PTN7_IN,
+ PTN6_FN, PTN6_OUT, PTN6_IN_PU, PTN6_IN,
+ PTN5_FN, PTN5_OUT, PTN5_IN_PU, PTN5_IN,
+ PTN4_FN, PTN4_OUT, PTN4_IN_PU, PTN4_IN,
+ PTN3_FN, PTN3_OUT, PTN3_IN_PU, PTN3_IN,
+ PTN2_FN, PTN2_OUT, PTN2_IN_PU, PTN2_IN,
+ PTN1_FN, PTN1_OUT, PTN1_IN_PU, PTN1_IN,
+ PTN0_FN, PTN0_OUT, PTN0_IN_PU, PTN0_IN }
+ },
+ { PINMUX_CFG_REG("PQCR", 0xa405011a, 16, 2) {
+ PTQ7_FN, PTQ7_OUT, PTQ7_IN_PU, PTQ7_IN,
+ PTQ6_FN, PTQ6_OUT, PTQ6_IN_PU, PTQ6_IN,
+ PTQ5_FN, PTQ5_OUT, PTQ5_IN_PU, PTQ5_IN,
+ PTQ4_FN, PTQ4_OUT, PTQ4_IN_PU, PTQ4_IN,
+ PTQ3_FN, PTQ3_OUT, PTQ3_IN_PU, PTQ3_IN,
+ PTQ2_FN, PTQ2_OUT, PTQ2_IN_PU, PTQ2_IN,
+ PTQ1_FN, PTQ1_OUT, PTQ1_IN_PU, PTQ1_IN,
+ PTQ0_FN, PTQ0_OUT, PTQ0_IN_PU, PTQ0_IN }
+ },
+ { PINMUX_CFG_REG("PRCR", 0xa405011c, 16, 2) {
+ PTR7_FN, PTR7_OUT, PTR7_IN_PU, PTR7_IN,
+ PTR6_FN, PTR6_OUT, PTR6_IN_PU, PTR6_IN,
+ PTR5_FN, PTR5_OUT, PTR5_IN_PU, PTR5_IN,
+ PTR4_FN, PTR4_OUT, PTR4_IN_PU, PTR4_IN,
+ PTR3_FN, 0, PTR3_IN_PU, PTR3_IN,
+ PTR2_FN, 0, PTR2_IN_PU, PTR2_IN,
+ PTR1_FN, PTR1_OUT, PTR1_IN_PU, PTR1_IN,
+ PTR0_FN, PTR0_OUT, PTR0_IN_PU, PTR0_IN }
+ },
+ { PINMUX_CFG_REG("PSCR", 0xa405011e, 16, 2) {
+ 0, 0, 0, 0,
+ PTS6_FN, PTS6_OUT, PTS6_IN_PU, PTS6_IN,
+ PTS5_FN, PTS5_OUT, PTS5_IN_PU, PTS5_IN,
+ PTS4_FN, PTS4_OUT, PTS4_IN_PU, PTS4_IN,
+ PTS3_FN, PTS3_OUT, PTS3_IN_PU, PTS3_IN,
+ PTS2_FN, PTS2_OUT, PTS2_IN_PU, PTS2_IN,
+ PTS1_FN, PTS1_OUT, PTS1_IN_PU, PTS1_IN,
+ PTS0_FN, PTS0_OUT, PTS0_IN_PU, PTS0_IN }
+ },
+ { PINMUX_CFG_REG("PTCR", 0xa4050140, 16, 2) {
+ PTT7_FN, PTT7_OUT, PTT7_IN_PU, PTT7_IN,
+ PTT6_FN, PTT6_OUT, PTT6_IN_PU, PTT6_IN,
+ PTT5_FN, PTT5_OUT, PTT5_IN_PU, PTT5_IN,
+ PTT4_FN, PTT4_OUT, PTT4_IN_PU, PTT4_IN,
+ PTT3_FN, PTT3_OUT, PTT3_IN_PU, PTT3_IN,
+ PTT2_FN, PTT2_OUT, PTT2_IN_PU, PTT2_IN,
+ PTT1_FN, PTT1_OUT, PTT1_IN_PU, PTT1_IN,
+ PTT0_FN, PTT0_OUT, PTT0_IN_PU, PTT0_IN }
+ },
+ { PINMUX_CFG_REG("PUCR", 0xa4050142, 16, 2) {
+ PTU7_FN, PTU7_OUT, PTU7_IN_PU, PTU7_IN,
+ PTU6_FN, PTU6_OUT, PTU6_IN_PU, PTU6_IN,
+ PTU5_FN, PTU5_OUT, PTU5_IN_PU, PTU5_IN,
+ PTU4_FN, PTU4_OUT, PTU4_IN_PU, PTU4_IN,
+ PTU3_FN, PTU3_OUT, PTU3_IN_PU, PTU3_IN,
+ PTU2_FN, PTU2_OUT, PTU2_IN_PU, PTU2_IN,
+ PTU1_FN, PTU1_OUT, PTU1_IN_PU, PTU1_IN,
+ PTU0_FN, PTU0_OUT, PTU0_IN_PU, PTU0_IN }
+ },
+ { PINMUX_CFG_REG("PVCR", 0xa4050144, 16, 2) {
+ PTV7_FN, PTV7_OUT, PTV7_IN_PU, PTV7_IN,
+ PTV6_FN, PTV6_OUT, PTV6_IN_PU, PTV6_IN,
+ PTV5_FN, PTV5_OUT, PTV5_IN_PU, PTV5_IN,
+ PTV4_FN, PTV4_OUT, PTV4_IN_PU, PTV4_IN,
+ PTV3_FN, PTV3_OUT, PTV3_IN_PU, PTV3_IN,
+ PTV2_FN, PTV2_OUT, PTV2_IN_PU, PTV2_IN,
+ PTV1_FN, PTV1_OUT, PTV1_IN_PU, PTV1_IN,
+ PTV0_FN, PTV0_OUT, PTV0_IN_PU, PTV0_IN }
+ },
+ { PINMUX_CFG_REG("PWCR", 0xa4050146, 16, 2) {
+ PTW7_FN, PTW7_OUT, PTW7_IN_PU, PTW7_IN,
+ PTW6_FN, PTW6_OUT, PTW6_IN_PU, PTW6_IN,
+ PTW5_FN, PTW5_OUT, PTW5_IN_PU, PTW5_IN,
+ PTW4_FN, PTW4_OUT, PTW4_IN_PU, PTW4_IN,
+ PTW3_FN, PTW3_OUT, PTW3_IN_PU, PTW3_IN,
+ PTW2_FN, PTW2_OUT, PTW2_IN_PU, PTW2_IN,
+ PTW1_FN, PTW1_OUT, PTW1_IN_PU, PTW1_IN,
+ PTW0_FN, PTW0_OUT, PTW0_IN_PU, PTW0_IN }
+ },
+ { PINMUX_CFG_REG("PXCR", 0xa4050148, 16, 2) {
+ PTX7_FN, PTX7_OUT, PTX7_IN_PU, PTX7_IN,
+ PTX6_FN, PTX6_OUT, PTX6_IN_PU, PTX6_IN,
+ PTX5_FN, PTX5_OUT, PTX5_IN_PU, PTX5_IN,
+ PTX4_FN, PTX4_OUT, PTX4_IN_PU, PTX4_IN,
+ PTX3_FN, PTX3_OUT, PTX3_IN_PU, PTX3_IN,
+ PTX2_FN, PTX2_OUT, PTX2_IN_PU, PTX2_IN,
+ PTX1_FN, PTX1_OUT, PTX1_IN_PU, PTX1_IN,
+ PTX0_FN, PTX0_OUT, PTX0_IN_PU, PTX0_IN }
+ },
+ { PINMUX_CFG_REG("PYCR", 0xa405014a, 16, 2) {
+ PTY7_FN, PTY7_OUT, PTY7_IN_PU, PTY7_IN,
+ PTY6_FN, PTY6_OUT, PTY6_IN_PU, PTY6_IN,
+ PTY5_FN, PTY5_OUT, PTY5_IN_PU, PTY5_IN,
+ PTY4_FN, PTY4_OUT, PTY4_IN_PU, PTY4_IN,
+ PTY3_FN, PTY3_OUT, PTY3_IN_PU, PTY3_IN,
+ PTY2_FN, PTY2_OUT, PTY2_IN_PU, PTY2_IN,
+ PTY1_FN, PTY1_OUT, PTY1_IN_PU, PTY1_IN,
+ PTY0_FN, PTY0_OUT, PTY0_IN_PU, PTY0_IN }
+ },
+ { PINMUX_CFG_REG("PZCR", 0xa405014c, 16, 2) {
+ PTZ7_FN, PTZ7_OUT, PTZ7_IN_PU, PTZ7_IN,
+ PTZ6_FN, PTZ6_OUT, PTZ6_IN_PU, PTZ6_IN,
+ PTZ5_FN, PTZ5_OUT, PTZ5_IN_PU, PTZ5_IN,
+ PTZ4_FN, PTZ4_OUT, PTZ4_IN_PU, PTZ4_IN,
+ PTZ3_FN, PTZ3_OUT, PTZ3_IN_PU, PTZ3_IN,
+ PTZ2_FN, PTZ2_OUT, PTZ2_IN_PU, PTZ2_IN,
+ PTZ1_FN, PTZ1_OUT, PTZ1_IN_PU, PTZ1_IN,
+ PTZ0_FN, PTZ0_OUT, PTZ0_IN_PU, PTZ0_IN }
+ },
+ { PINMUX_CFG_REG("PSELA", 0xa405014e, 16, 1) {
+ PSA15_0, PSA15_1,
+ PSA14_0, PSA14_1,
+ PSA13_0, PSA13_1,
+ PSA12_0, PSA12_1,
+ 0, 0,
+ PSA10_0, PSA10_1,
+ PSA9_0, PSA9_1,
+ PSA8_0, PSA8_1,
+ PSA7_0, PSA7_1,
+ PSA6_0, PSA6_1,
+ PSA5_0, PSA5_1,
+ 0, 0,
+ PSA3_0, PSA3_1,
+ PSA2_0, PSA2_1,
+ PSA1_0, PSA1_1,
+ PSA0_0, PSA0_1}
+ },
+ { PINMUX_CFG_REG("PSELB", 0xa4050150, 16, 1) {
+ 0, 0,
+ PSB14_0, PSB14_1,
+ PSB13_0, PSB13_1,
+ PSB12_0, PSB12_1,
+ PSB11_0, PSB11_1,
+ PSB10_0, PSB10_1,
+ PSB9_0, PSB9_1,
+ PSB8_0, PSB8_1,
+ PSB7_0, PSB7_1,
+ PSB6_0, PSB6_1,
+ PSB5_0, PSB5_1,
+ PSB4_0, PSB4_1,
+ PSB3_0, PSB3_1,
+ PSB2_0, PSB2_1,
+ PSB1_0, PSB1_1,
+ PSB0_0, PSB0_1}
+ },
+ { PINMUX_CFG_REG("PSELC", 0xa4050152, 16, 1) {
+ PSC15_0, PSC15_1,
+ PSC14_0, PSC14_1,
+ PSC13_0, PSC13_1,
+ PSC12_0, PSC12_1,
+ PSC11_0, PSC11_1,
+ PSC10_0, PSC10_1,
+ PSC9_0, PSC9_1,
+ PSC8_0, PSC8_1,
+ PSC7_0, PSC7_1,
+ PSC6_0, PSC6_1,
+ PSC5_0, PSC5_1,
+ PSC4_0, PSC4_1,
+ 0, 0,
+ PSC2_0, PSC2_1,
+ PSC1_0, PSC1_1,
+ PSC0_0, PSC0_1}
+ },
+ { PINMUX_CFG_REG("PSELD", 0xa4050154, 16, 1) {
+ PSD15_0, PSD15_1,
+ PSD14_0, PSD14_1,
+ PSD13_0, PSD13_1,
+ PSD12_0, PSD12_1,
+ PSD11_0, PSD11_1,
+ PSD10_0, PSD10_1,
+ PSD9_0, PSD9_1,
+ PSD8_0, PSD8_1,
+ PSD7_0, PSD7_1,
+ PSD6_0, PSD6_1,
+ PSD5_0, PSD5_1,
+ PSD4_0, PSD4_1,
+ PSD3_0, PSD3_1,
+ PSD2_0, PSD2_1,
+ PSD1_0, PSD1_1,
+ PSD0_0, PSD0_1}
+ },
+ { PINMUX_CFG_REG("PSELE", 0xa4050156, 16, 1) {
+ PSE15_0, PSE15_1,
+ PSE14_0, PSE14_1,
+ PSE13_0, PSE13_1,
+ PSE12_0, PSE12_1,
+ PSE11_0, PSE11_1,
+ PSE10_0, PSE10_1,
+ PSE9_0, PSE9_1,
+ PSE8_0, PSE8_1,
+ PSE7_0, PSE7_1,
+ PSE6_0, PSE6_1,
+ PSE5_0, PSE5_1,
+ PSE4_0, PSE4_1,
+ PSE3_0, PSE3_1,
+ PSE2_0, PSE2_1,
+ PSE1_0, PSE1_1,
+ PSE0_0, PSE0_1}
+ },
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR", 0xa4050120, 8) {
+ PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+ PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
+ },
+ { PINMUX_DATA_REG("PBDR", 0xa4050122, 8) {
+ PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+ PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
+ },
+ { PINMUX_DATA_REG("PCDR", 0xa4050124, 8) {
+ PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
+ PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA }
+ },
+ { PINMUX_DATA_REG("PDDR", 0xa4050126, 8) {
+ PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+ PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
+ },
+ { PINMUX_DATA_REG("PEDR", 0xa4050128, 8) {
+ PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
+ PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA }
+ },
+ { PINMUX_DATA_REG("PFDR", 0xa405012a, 8) {
+ PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
+ PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
+ },
+ { PINMUX_DATA_REG("PGDR", 0xa405012c, 8) {
+ 0, 0, PTG5_DATA, PTG4_DATA,
+ PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
+ },
+ { PINMUX_DATA_REG("PHDR", 0xa405012e, 8) {
+ PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+ PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR", 0xa4050130, 8) {
+ PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, 0,
+ PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
+ },
+ { PINMUX_DATA_REG("PKDR", 0xa4050132, 8) {
+ PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
+ PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
+ },
+ { PINMUX_DATA_REG("PLDR", 0xa4050134, 8) {
+ PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
+ },
+ { PINMUX_DATA_REG("PMDR", 0xa4050136, 8) {
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
+ },
+ { PINMUX_DATA_REG("PNDR", 0xa4050138, 8) {
+ PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
+ },
+ { PINMUX_DATA_REG("PQDR", 0xa405013a, 8) {
+ PTQ7_DATA, PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+ PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA }
+ },
+ { PINMUX_DATA_REG("PRDR", 0xa405013c, 8) {
+ PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
+ PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
+ },
+ { PINMUX_DATA_REG("PSDR", 0xa405013e, 8) {
+ 0, PTS6_DATA, PTS5_DATA, PTS4_DATA,
+ PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
+ },
+ { PINMUX_DATA_REG("PTDR", 0xa4050160, 8) {
+ PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
+ PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
+ },
+ { PINMUX_DATA_REG("PUDR", 0xa4050162, 8) {
+ PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
+ PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
+ },
+ { PINMUX_DATA_REG("PVDR", 0xa4050164, 8) {
+ PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
+ PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
+ },
+ { PINMUX_DATA_REG("PWDR", 0xa4050166, 8) {
+ PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
+ PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA }
+ },
+ { PINMUX_DATA_REG("PXDR", 0xa4050168, 8) {
+ PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
+ PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA }
+ },
+ { PINMUX_DATA_REG("PYDR", 0xa405016a, 8) {
+ PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
+ PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA }
+ },
+ { PINMUX_DATA_REG("PZDR", 0xa405016c, 8) {
+ PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
+ PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA }
+ },
+ { },
+};
+
+struct sh_pfc_soc_info sh7724_pinmux_info = {
+ .name = "sh7724_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PTA7,
+ .last_gpio = GPIO_FN_INTC_IRQ0,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
new file mode 100644
index 000000000000..23d76d262c32
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
@@ -0,0 +1,2475 @@
+/*
+ * SH7734 processor support - PFC hardware block
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <cpu/sh7734.h>
+
+#include "sh_pfc.h"
+
+#define CPU_32_PORT(fn, pfx, sfx) \
+ PORT_10(fn, pfx, sfx), PORT_10(fn, pfx##1, sfx), \
+ PORT_10(fn, pfx##2, sfx), PORT_1(fn, pfx##30, sfx), \
+ PORT_1(fn, pfx##31, sfx)
+
+#define CPU_32_PORT5(fn, pfx, sfx) \
+ PORT_1(fn, pfx##0, sfx), PORT_1(fn, pfx##1, sfx), \
+ PORT_1(fn, pfx##2, sfx), PORT_1(fn, pfx##3, sfx), \
+ PORT_1(fn, pfx##4, sfx), PORT_1(fn, pfx##5, sfx), \
+ PORT_1(fn, pfx##6, sfx), PORT_1(fn, pfx##7, sfx), \
+ PORT_1(fn, pfx##8, sfx), PORT_1(fn, pfx##9, sfx), \
+ PORT_1(fn, pfx##10, sfx), PORT_1(fn, pfx##11, sfx)
+
+/* GPSR0 - GPSR5 */
+#define CPU_ALL_PORT(fn, pfx, sfx) \
+ CPU_32_PORT(fn, pfx##_0_, sfx), \
+ CPU_32_PORT(fn, pfx##_1_, sfx), \
+ CPU_32_PORT(fn, pfx##_2_, sfx), \
+ CPU_32_PORT(fn, pfx##_3_, sfx), \
+ CPU_32_PORT(fn, pfx##_4_, sfx), \
+ CPU_32_PORT5(fn, pfx##_5_, sfx)
+
+#define _GP_GPIO(pfx, sfx) PINMUX_GPIO(GPIO_GP##pfx, GP##pfx##_DATA)
+#define _GP_DATA(pfx, sfx) PINMUX_DATA(GP##pfx##_DATA, GP##pfx##_FN, \
+ GP##pfx##_IN, GP##pfx##_OUT)
+
+#define _GP_INOUTSEL(pfx, sfx) GP##pfx##_IN, GP##pfx##_OUT
+#define _GP_INDT(pfx, sfx) GP##pfx##_DATA
+
+#define GP_ALL(str) CPU_ALL_PORT(_PORT_ALL, GP, str)
+#define PINMUX_GPIO_GP_ALL() CPU_ALL_PORT(_GP_GPIO, , unused)
+#define PINMUX_DATA_GP_ALL() CPU_ALL_PORT(_GP_DATA, , unused)
+
+#define PORT_10_REV(fn, pfx, sfx) \
+ PORT_1(fn, pfx##9, sfx), PORT_1(fn, pfx##8, sfx), \
+ PORT_1(fn, pfx##7, sfx), PORT_1(fn, pfx##6, sfx), \
+ PORT_1(fn, pfx##5, sfx), PORT_1(fn, pfx##4, sfx), \
+ PORT_1(fn, pfx##3, sfx), PORT_1(fn, pfx##2, sfx), \
+ PORT_1(fn, pfx##1, sfx), PORT_1(fn, pfx##0, sfx)
+
+#define CPU_32_PORT_REV(fn, pfx, sfx) \
+ PORT_1(fn, pfx##31, sfx), PORT_1(fn, pfx##30, sfx), \
+ PORT_10_REV(fn, pfx##2, sfx), PORT_10_REV(fn, pfx##1, sfx), \
+ PORT_10_REV(fn, pfx, sfx)
+
+#define GP_INOUTSEL(bank) CPU_32_PORT_REV(_GP_INOUTSEL, _##bank##_, unused)
+#define GP_INDT(bank) CPU_32_PORT_REV(_GP_INDT, _##bank##_, unused)
+
+#define PINMUX_IPSR_DATA(ipsr, fn) PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##fn)
+#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) PINMUX_DATA(fn##_MARK, FN_##ms, \
+ FN_##ipsr, FN_##fn)
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ GP_ALL(DATA), /* GP_0_0_DATA -> GP_5_11_DATA */
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ GP_ALL(IN), /* GP_0_0_IN -> GP_5_11_IN */
+ PINMUX_INPUT_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ GP_ALL(OUT), /* GP_0_0_OUT -> GP_5_11_OUT */
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ GP_ALL(FN), /* GP_0_0_FN -> GP_5_11_FN */
+
+ /* GPSR0 */
+ FN_IP1_9_8, FN_IP1_11_10, FN_IP1_13_12, FN_IP1_15_14,
+ FN_IP0_7_6, FN_IP0_9_8, FN_IP0_11_10, FN_IP0_13_12,
+ FN_IP0_15_14, FN_IP0_17_16, FN_IP0_19_18, FN_IP0_21_20,
+ FN_IP0_23_22, FN_IP0_25_24, FN_IP0_27_26, FN_IP0_29_28,
+ FN_IP0_31_30, FN_IP1_1_0, FN_IP1_3_2, FN_IP1_5_4,
+ FN_IP1_7_6, FN_IP11_28, FN_IP0_1_0, FN_IP0_3_2,
+ FN_IP0_5_4, FN_IP1_17_16, FN_IP1_19_18, FN_IP1_22_20,
+ FN_IP1_25_23, FN_IP1_28_26, FN_IP1_31_29, FN_IP2_2_0,
+
+ /* GPSR1 */
+ FN_IP3_20, FN_IP3_29_27, FN_IP11_20_19, FN_IP11_22_21,
+ FN_IP2_16_14, FN_IP2_19_17, FN_IP2_22_20, FN_IP2_24_23,
+ FN_IP2_27_25, FN_IP2_30_28, FN_IP3_1_0, FN_CLKOUT,
+ FN_BS, FN_CS0, FN_IP3_2, FN_EX_CS0,
+ FN_IP3_5_3, FN_IP3_8_6, FN_IP3_11_9, FN_IP3_14_12,
+ FN_IP3_17_15, FN_RD, FN_IP3_19_18, FN_WE0,
+ FN_WE1, FN_IP2_4_3, FN_IP3_23_21, FN_IP3_26_24,
+ FN_IP2_7_5, FN_IP2_10_8, FN_IP2_13_11, FN_IP11_25_23,
+
+ /* GPSR2 */
+ FN_IP11_6_4, FN_IP11_9_7, FN_IP11_11_10, FN_IP4_2_0,
+ FN_IP8_29_28, FN_IP11_27_26, FN_IP8_22_20, FN_IP8_25_23,
+ FN_IP11_12, FN_IP8_27_26, FN_IP4_5_3, FN_IP4_8_6,
+ FN_IP4_11_9, FN_IP4_14_12, FN_IP4_17_15, FN_IP4_19_18,
+ FN_IP4_21_20, FN_IP4_23_22, FN_IP4_25_24, FN_IP4_27_26,
+ FN_IP4_29_28, FN_IP4_31_30, FN_IP5_2_0, FN_IP5_5_3,
+ FN_IP5_8_6, FN_IP5_11_9, FN_IP5_14_12, FN_IP5_17_15,
+ FN_IP5_20_18, FN_IP5_22_21, FN_IP5_24_23, FN_IP5_26_25,
+
+ /* GPSR3 */
+ FN_IP6_2_0, FN_IP6_5_3, FN_IP6_7_6, FN_IP6_9_8,
+ FN_IP6_11_10, FN_IP6_13_12, FN_IP6_15_14, FN_IP6_17_16,
+ FN_IP6_20_18, FN_IP6_23_21, FN_IP7_2_0, FN_IP7_5_3,
+ FN_IP7_8_6, FN_IP7_11_9, FN_IP7_14_12, FN_IP7_17_15,
+ FN_IP7_20_18, FN_IP7_23_21, FN_IP7_26_24, FN_IP7_28_27,
+ FN_IP7_30_29, FN_IP8_1_0, FN_IP8_3_2, FN_IP8_5_4,
+ FN_IP8_7_6, FN_IP8_9_8, FN_IP8_11_10, FN_IP8_13_12,
+ FN_IP8_15_14, FN_IP8_17_16, FN_IP8_19_18, FN_IP9_1_0,
+
+ /* GPSR4 */
+ FN_IP9_19_18, FN_IP9_21_20, FN_IP9_23_22, FN_IP9_25_24,
+ FN_IP9_11_10, FN_IP9_13_12, FN_IP9_15_14, FN_IP9_17_16,
+ FN_IP9_3_2, FN_IP9_5_4, FN_IP9_7_6, FN_IP9_9_8,
+ FN_IP9_27_26, FN_IP9_29_28, FN_IP10_2_0, FN_IP10_5_3,
+ FN_IP10_8_6, FN_IP10_11_9, FN_IP10_14_12, FN_IP10_15,
+ FN_IP10_18_16, FN_IP10_21_19, FN_IP11_0, FN_IP11_1,
+ FN_SCL0, FN_IP11_2, FN_PENC0, FN_IP11_15_13, /* Need check*/
+ FN_USB_OVC0, FN_IP11_18_16,
+ FN_IP10_22, FN_IP10_24_23,
+
+ /* GPSR5 */
+ FN_IP10_25, FN_IP11_3, FN_IRQ2_B, FN_IRQ3_B,
+ FN_IP10_27_26, /* 10 */
+ FN_IP10_29_28, /* 11 */
+
+ /* IPSR0 */
+ FN_A15, FN_ST0_VCO_CLKIN, FN_LCD_DATA15_A, FN_TIOC3D_C,
+ FN_A14, FN_LCD_DATA14_A, FN_TIOC3C_C,
+ FN_A13, FN_LCD_DATA13_A, FN_TIOC3B_C,
+ FN_A12, FN_LCD_DATA12_A, FN_TIOC3A_C,
+ FN_A11, FN_ST0_D7, FN_LCD_DATA11_A, FN_TIOC2B_C,
+ FN_A10, FN_ST0_D6, FN_LCD_DATA10_A, FN_TIOC2A_C,
+ FN_A9, FN_ST0_D5, FN_LCD_DATA9_A, FN_TIOC1B_C,
+ FN_A8, FN_ST0_D4, FN_LCD_DATA8_A, FN_TIOC1A_C,
+ FN_A7, FN_ST0_D3, FN_LCD_DATA7_A, FN_TIOC0D_C,
+ FN_A6, FN_ST0_D2, FN_LCD_DATA6_A, FN_TIOC0C_C,
+ FN_A5, FN_ST0_D1, FN_LCD_DATA5_A, FN_TIOC0B_C,
+ FN_A4, FN_ST0_D0, FN_LCD_DATA4_A, FN_TIOC0A_C,
+ FN_A3, FN_ST0_VLD, FN_LCD_DATA3_A, FN_TCLKD_C,
+ FN_A2, FN_ST0_SYC, FN_LCD_DATA2_A, FN_TCLKC_C,
+ FN_A1, FN_ST0_REQ, FN_LCD_DATA1_A, FN_TCLKB_C,
+ FN_A0, FN_ST0_CLKIN, FN_LCD_DATA0_A, FN_TCLKA_C,
+
+ /* IPSR1 */
+ FN_D3, FN_SD0_DAT3_A, FN_MMC_D3_A, FN_ST1_D6, FN_FD3_A,
+ FN_D2, FN_SD0_DAT2_A, FN_MMC_D2_A, FN_ST1_D5, FN_FD2_A,
+ FN_D1, FN_SD0_DAT1_A, FN_MMC_D1_A, FN_ST1_D4, FN_FD1_A,
+ FN_D0, FN_SD0_DAT0_A, FN_MMC_D0_A, FN_ST1_D3, FN_FD0_A,
+ FN_A25, FN_TX2_D, FN_ST1_D2,
+ FN_A24, FN_RX2_D, FN_ST1_D1,
+ FN_A23, FN_ST1_D0, FN_LCD_M_DISP_A,
+ FN_A22, FN_ST1_VLD, FN_LCD_VEPWC_A,
+ FN_A21, FN_ST1_SYC, FN_LCD_VCPWC_A,
+ FN_A20, FN_ST1_REQ, FN_LCD_FLM_A,
+ FN_A19, FN_ST1_CLKIN, FN_LCD_CLK_A, FN_TIOC4D_C,
+ FN_A18, FN_ST1_PWM, FN_LCD_CL2_A, FN_TIOC4C_C,
+ FN_A17, FN_ST1_VCO_CLKIN, FN_LCD_CL1_A, FN_TIOC4B_C,
+ FN_A16, FN_ST0_PWM, FN_LCD_DON_A, FN_TIOC4A_C,
+
+ /* IPSR2 */
+ FN_D14, FN_TX2_B, FN_FSE_A, FN_ET0_TX_CLK_B,
+ FN_D13, FN_RX2_B, FN_FRB_A, FN_ET0_ETXD6_B,
+ FN_D12, FN_FWE_A, FN_ET0_ETXD5_B,
+ FN_D11, FN_RSPI_MISO_A, FN_QMI_QIO1_A, FN_FRE_A,
+ FN_ET0_ETXD3_B,
+ FN_D10, FN_RSPI_MOSI_A, FN_QMO_QIO0_A, FN_FALE_A,
+ FN_ET0_ETXD2_B,
+ FN_D9, FN_SD0_CMD_A, FN_MMC_CMD_A, FN_QIO3_A, FN_FCLE_A,
+ FN_ET0_ETXD1_B,
+ FN_D8, FN_SD0_CLK_A, FN_MMC_CLK_A, FN_QIO2_A, FN_FCE_A,
+ FN_ET0_GTX_CLK_B,
+ FN_D7, FN_RSPI_SSL_A, FN_MMC_D7_A, FN_QSSL_A, FN_FD7_A,
+ FN_D6, FN_RSPI_RSPCK_A, FN_MMC_D6_A, FN_QSPCLK_A, FN_FD6_A,
+ FN_D5, FN_SD0_WP_A, FN_MMC_D5_A, FN_FD5_A,
+ FN_D4, FN_SD0_CD_A, FN_MMC_D4_A, FN_ST1_D7, FN_FD4_A,
+
+ /* IPSR3 */
+ FN_DRACK0, FN_SD1_DAT2_A, FN_ATAG, FN_TCLK1_A, FN_ET0_ETXD7,
+ FN_EX_WAIT2, FN_SD1_DAT1_A, FN_DACK2, FN_CAN1_RX_C,
+ FN_ET0_MAGIC_C, FN_ET0_ETXD6_A,
+ FN_EX_WAIT1, FN_SD1_DAT0_A, FN_DREQ2, FN_CAN1_TX_C,
+ FN_ET0_LINK_C, FN_ET0_ETXD5_A,
+ FN_EX_WAIT0, FN_TCLK1_B,
+ FN_RD_WR, FN_TCLK0, FN_CAN_CLK_B, FN_ET0_ETXD4,
+ FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B, FN_ET0_ETXD3_A,
+ FN_EX_CS4, FN_SD1_WP_A, FN_ATAWR, FN_QMI_QIO1_B, FN_ET0_ETXD2_A,
+ FN_EX_CS3, FN_SD1_CD_A, FN_ATARD, FN_QMO_QIO0_B, FN_ET0_ETXD1_A,
+ FN_EX_CS2, FN_TX3_B, FN_ATACS1, FN_QSPCLK_B, FN_ET0_GTX_CLK_A,
+ FN_EX_CS1, FN_RX3_B, FN_ATACS0, FN_QIO2_B, FN_ET0_ETXD0,
+ FN_CS1_A26, FN_QIO3_B,
+ FN_D15, FN_SCK2_B,
+
+ /* IPSR4 */
+ FN_SCK2_A, FN_VI0_G3,
+ FN_RTS1_B, FN_VI0_G2,
+ FN_CTS1_B, FN_VI0_DATA7_VI0_G1,
+ FN_TX1_B, FN_VI0_DATA6_VI0_G0, FN_ET0_PHY_INT_A,
+ FN_RX1_B, FN_VI0_DATA5_VI0_B5, FN_ET0_MAGIC_A,
+ FN_SCK1_B, FN_VI0_DATA4_VI0_B4, FN_ET0_LINK_A,
+ FN_RTS0_B, FN_VI0_DATA3_VI0_B3, FN_ET0_MDIO_A,
+ FN_CTS0_B, FN_VI0_DATA2_VI0_B2, FN_RMII0_MDIO_A, FN_ET0_MDC,
+ FN_HTX0_A, FN_TX1_A, FN_VI0_DATA1_VI0_B1, FN_RMII0_MDC_A, FN_ET0_COL,
+ FN_HRX0_A, FN_RX1_A, FN_VI0_DATA0_VI0_B0, FN_RMII0_CRS_DV_A, FN_ET0_CRS,
+ FN_HSCK0_A, FN_SCK1_A, FN_VI0_VSYNC, FN_RMII0_RX_ER_A, FN_ET0_RX_ER,
+ FN_HRTS0_A, FN_RTS1_A, FN_VI0_HSYNC, FN_RMII0_TXD_EN_A, FN_ET0_RX_DV,
+ FN_HCTS0_A, FN_CTS1_A, FN_VI0_FIELD, FN_RMII0_RXD1_A, FN_ET0_ERXD7,
+
+ /* IPSR5 */
+ FN_SD2_CLK_A, FN_RX2_A, FN_VI0_G4, FN_ET0_RX_CLK_B,
+ FN_SD2_CMD_A, FN_TX2_A, FN_VI0_G5, FN_ET0_ERXD2_B,
+ FN_SD2_DAT0_A, FN_RX3_A, FN_VI0_R0, FN_ET0_ERXD3_B,
+ FN_SD2_DAT1_A, FN_TX3_A, FN_VI0_R1, FN_ET0_MDIO_B,
+ FN_SD2_DAT2_A, FN_RX4_A, FN_VI0_R2, FN_ET0_LINK_B,
+ FN_SD2_DAT3_A, FN_TX4_A, FN_VI0_R3, FN_ET0_MAGIC_B,
+ FN_SD2_CD_A, FN_RX5_A, FN_VI0_R4, FN_ET0_PHY_INT_B,
+ FN_SD2_WP_A, FN_TX5_A, FN_VI0_R5,
+ FN_REF125CK, FN_ADTRG, FN_RX5_C,
+ FN_REF50CK, FN_CTS1_E, FN_HCTS0_D,
+
+ /* IPSR6 */
+ FN_DU0_DR0, FN_SCIF_CLK_B, FN_HRX0_D, FN_IETX_A, FN_TCLKA_A, FN_HIFD00,
+ FN_DU0_DR1, FN_SCK0_B, FN_HTX0_D, FN_IERX_A, FN_TCLKB_A, FN_HIFD01,
+ FN_DU0_DR2, FN_RX0_B, FN_TCLKC_A, FN_HIFD02,
+ FN_DU0_DR3, FN_TX0_B, FN_TCLKD_A, FN_HIFD03,
+ FN_DU0_DR4, FN_CTS0_C, FN_TIOC0A_A, FN_HIFD04,
+ FN_DU0_DR5, FN_RTS0_C, FN_TIOC0B_A, FN_HIFD05,
+ FN_DU0_DR6, FN_SCK1_C, FN_TIOC0C_A, FN_HIFD06,
+ FN_DU0_DR7, FN_RX1_C, FN_TIOC0D_A, FN_HIFD07,
+ FN_DU0_DG0, FN_TX1_C, FN_HSCK0_D, FN_IECLK_A, FN_TIOC1A_A, FN_HIFD08,
+ FN_DU0_DG1, FN_CTS1_C, FN_HRTS0_D, FN_TIOC1B_A, FN_HIFD09,
+
+ /* IPSR7 */
+ FN_DU0_DG2, FN_RTS1_C, FN_RMII0_MDC_B, FN_TIOC2A_A, FN_HIFD10,
+ FN_DU0_DG3, FN_SCK2_C, FN_RMII0_MDIO_B, FN_TIOC2B_A, FN_HIFD11,
+ FN_DU0_DG4, FN_RX2_C, FN_RMII0_CRS_DV_B, FN_TIOC3A_A, FN_HIFD12,
+ FN_DU0_DG5, FN_TX2_C, FN_RMII0_RX_ER_B, FN_TIOC3B_A, FN_HIFD13,
+ FN_DU0_DG6, FN_RX3_C, FN_RMII0_RXD0_B, FN_TIOC3C_A, FN_HIFD14,
+ FN_DU0_DG7, FN_TX3_C, FN_RMII0_RXD1_B, FN_TIOC3D_A, FN_HIFD15,
+ FN_DU0_DB0, FN_RX4_C, FN_RMII0_TXD_EN_B, FN_TIOC4A_A, FN_HIFCS,
+ FN_DU0_DB1, FN_TX4_C, FN_RMII0_TXD0_B, FN_TIOC4B_A, FN_HIFRS,
+ FN_DU0_DB2, FN_RX5_B, FN_RMII0_TXD1_B, FN_TIOC4C_A, FN_HIFWR,
+ FN_DU0_DB3, FN_TX5_B, FN_TIOC4D_A, FN_HIFRD,
+ FN_DU0_DB4, FN_HIFINT,
+
+ /* IPSR8 */
+ FN_DU0_DB5, FN_HIFDREQ,
+ FN_DU0_DB6, FN_HIFRDY,
+ FN_DU0_DB7, FN_SSI_SCK0_B, FN_HIFEBL_B,
+ FN_DU0_DOTCLKIN, FN_HSPI_CS0_C, FN_SSI_WS0_B,
+ FN_DU0_DOTCLKOUT, FN_HSPI_CLK0_C, FN_SSI_SDATA0_B,
+ FN_DU0_EXHSYNC_DU0_HSYNC, FN_HSPI_TX0_C, FN_SSI_SCK1_B,
+ FN_DU0_EXVSYNC_DU0_VSYNC, FN_HSPI_RX0_C, FN_SSI_WS1_B,
+ FN_DU0_EXODDF_DU0_ODDF, FN_CAN0_RX_B, FN_HSCK0_B, FN_SSI_SDATA1_B,
+ FN_DU0_DISP, FN_CAN0_TX_B, FN_HRX0_B, FN_AUDIO_CLKA_B,
+ FN_DU0_CDE, FN_HTX0_B, FN_AUDIO_CLKB_B, FN_LCD_VCPWC_B,
+ FN_IRQ0_A, FN_HSPI_TX_B, FN_RX3_E, FN_ET0_ERXD0,
+ FN_IRQ1_A, FN_HSPI_RX_B, FN_TX3_E, FN_ET0_ERXD1,
+ FN_IRQ2_A, FN_CTS0_A, FN_HCTS0_B, FN_ET0_ERXD2_A,
+ FN_IRQ3_A, FN_RTS0_A, FN_HRTS0_B, FN_ET0_ERXD3_A,
+
+ /* IPSR9 */
+ FN_VI1_CLK_A, FN_FD0_B, FN_LCD_DATA0_B,
+ FN_VI1_0_A, FN_FD1_B, FN_LCD_DATA1_B,
+ FN_VI1_1_A, FN_FD2_B, FN_LCD_DATA2_B,
+ FN_VI1_2_A, FN_FD3_B, FN_LCD_DATA3_B,
+ FN_VI1_3_A, FN_FD4_B, FN_LCD_DATA4_B,
+ FN_VI1_4_A, FN_FD5_B, FN_LCD_DATA5_B,
+ FN_VI1_5_A, FN_FD6_B, FN_LCD_DATA6_B,
+ FN_VI1_6_A, FN_FD7_B, FN_LCD_DATA7_B,
+ FN_VI1_7_A, FN_FCE_B, FN_LCD_DATA8_B,
+ FN_SSI_SCK0_A, FN_TIOC1A_B, FN_LCD_DATA9_B,
+ FN_SSI_WS0_A, FN_TIOC1B_B, FN_LCD_DATA10_B,
+ FN_SSI_SDATA0_A, FN_VI1_0_B, FN_TIOC2A_B, FN_LCD_DATA11_B,
+ FN_SSI_SCK1_A, FN_VI1_1_B, FN_TIOC2B_B, FN_LCD_DATA12_B,
+ FN_SSI_WS1_A, FN_VI1_2_B, FN_LCD_DATA13_B,
+ FN_SSI_SDATA1_A, FN_VI1_3_B, FN_LCD_DATA14_B,
+
+ /* IPSR10 */
+ FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B, FN_LCD_DATA15_B,
+ FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B, FN_LCD_DON_B,
+ FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B, FN_LCD_CL1_B,
+ FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B, FN_LCD_CL2_B,
+ FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B, FN_LCD_FLM_B,
+ FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
+ FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B, FN_LCD_VEPWC_B,
+ FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B, FN_LCD_M_DISP_B,
+ FN_CAN_CLK_A, FN_RX4_D,
+ FN_CAN0_TX_A, FN_TX4_D, FN_MLB_CLK,
+ FN_CAN1_RX_A, FN_IRQ1_B,
+ FN_CAN0_RX_A, FN_IRQ0_B, FN_MLB_SIG,
+ FN_CAN1_TX_A, FN_TX5_C, FN_MLB_DAT,
+
+ /* IPSR11 */
+ FN_SCL1, FN_SCIF_CLK_C,
+ FN_SDA1, FN_RX1_E,
+ FN_SDA0, FN_HIFEBL_A,
+ FN_SDSELF, FN_RTS1_E,
+ FN_SCIF_CLK_A, FN_HSPI_CLK_A, FN_VI0_CLK, FN_RMII0_TXD0_A, FN_ET0_ERXD4,
+ FN_SCK0_A, FN_HSPI_CS_A, FN_VI0_CLKENB, FN_RMII0_TXD1_A, FN_ET0_ERXD5,
+ FN_RX0_A, FN_HSPI_RX_A, FN_RMII0_RXD0_A, FN_ET0_ERXD6,
+ FN_TX0_A, FN_HSPI_TX_A,
+ FN_PENC1, FN_TX3_D, FN_CAN1_TX_B, FN_TX5_D, FN_IETX_B,
+ FN_USB_OVC1, FN_RX3_D, FN_CAN1_RX_B, FN_RX5_D, FN_IERX_B,
+ FN_DREQ0, FN_SD1_CLK_A, FN_ET0_TX_EN,
+ FN_DACK0, FN_SD1_DAT3_A, FN_ET0_TX_ER,
+ FN_DREQ1, FN_HSPI_CLK_B, FN_RX4_B, FN_ET0_PHY_INT_C, FN_ET0_TX_CLK_A,
+ FN_DACK1, FN_HSPI_CS_B, FN_TX4_B, FN_ET0_RX_CLK_A,
+ FN_PRESETOUT, FN_ST_CLKOUT,
+
+ /* MOD_SEL1 */
+ FN_SEL_IEBUS_0, FN_SEL_IEBUS_1,
+ FN_SEL_RQSPI_0, FN_SEL_RQSPI_1,
+ FN_SEL_VIN1_0, FN_SEL_VIN1_1,
+ FN_SEL_HIF_0, FN_SEL_HIF_1,
+ FN_SEL_RSPI_0, FN_SEL_RSPI_1,
+ FN_SEL_LCDC_0, FN_SEL_LCDC_1,
+ FN_SEL_ET0_CTL_0, FN_SEL_ET0_CTL_1, FN_SEL_ET0_CTL_2,
+ FN_SEL_ET0_0, FN_SEL_ET0_1,
+ FN_SEL_RMII_0, FN_SEL_RMII_1,
+ FN_SEL_TMU_0, FN_SEL_TMU_1,
+ FN_SEL_HSPI_0, FN_SEL_HSPI_1, FN_SEL_HSPI_2,
+ FN_SEL_HSCIF_0, FN_SEL_HSCIF_1, FN_SEL_HSCIF_2, FN_SEL_HSCIF_3,
+ FN_SEL_RCAN_CLK_0, FN_SEL_RCAN_CLK_1,
+ FN_SEL_RCAN1_0, FN_SEL_RCAN1_1, FN_SEL_RCAN1_2,
+ FN_SEL_RCAN0_0, FN_SEL_RCAN0_1,
+ FN_SEL_SDHI2_0, FN_SEL_SDHI2_1,
+ FN_SEL_SDHI1_0, FN_SEL_SDHI1_1,
+ FN_SEL_SDHI0_0, FN_SEL_SDHI0_1,
+ FN_SEL_SSI1_0, FN_SEL_SSI1_1,
+ FN_SEL_SSI0_0, FN_SEL_SSI0_1,
+ FN_SEL_AUDIO_CLKB_0, FN_SEL_AUDIO_CLKB_1,
+ FN_SEL_AUDIO_CLKA_0, FN_SEL_AUDIO_CLKA_1,
+ FN_SEL_FLCTL_0, FN_SEL_FLCTL_1,
+ FN_SEL_MMC_0, FN_SEL_MMC_1,
+ FN_SEL_INTC_0, FN_SEL_INTC_1,
+
+ /* MOD_SEL2 */
+ FN_SEL_MTU2_CLK_0, FN_SEL_MTU2_CLK_1,
+ FN_SEL_MTU2_CH4_0, FN_SEL_MTU2_CH4_1,
+ FN_SEL_MTU2_CH3_0, FN_SEL_MTU2_CH3_1,
+ FN_SEL_MTU2_CH2_0, FN_SEL_MTU2_CH2_1, FN_SEL_MTU2_CH2_2,
+ FN_SEL_MTU2_CH1_0, FN_SEL_MTU2_CH1_1, FN_SEL_MTU2_CH1_2,
+ FN_SEL_MTU2_CH0_0, FN_SEL_MTU2_CH0_1,
+ FN_SEL_SCIF5_0, FN_SEL_SCIF5_1,
+ FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+ FN_SEL_SCIF4_0, FN_SEL_SCIF4_1,
+ FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+ FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2,
+ FN_SEL_SCIF3_3, FN_SEL_SCIF3_4,
+ FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2,
+ FN_SEL_SCIF2_3,
+ FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2,
+ FN_SEL_SCIF1_3, FN_SEL_SCIF1_4,
+ FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2,
+ FN_SEL_SCIF_CLK_0, FN_SEL_SCIF_CLK_1, FN_SEL_SCIF_CLK_2,
+
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+
+ CLKOUT_MARK, BS_MARK, CS0_MARK, EX_CS0_MARK, RD_MARK,
+ WE0_MARK, WE1_MARK,
+
+ SCL0_MARK, PENC0_MARK, USB_OVC0_MARK,
+
+ IRQ2_B_MARK, IRQ3_B_MARK,
+
+ /* IPSR0 */
+ A15_MARK, ST0_VCO_CLKIN_MARK, LCD_DATA15_A_MARK, TIOC3D_C_MARK,
+ A14_MARK, LCD_DATA14_A_MARK, TIOC3C_C_MARK,
+ A13_MARK, LCD_DATA13_A_MARK, TIOC3B_C_MARK,
+ A12_MARK, LCD_DATA12_A_MARK, TIOC3A_C_MARK,
+ A11_MARK, ST0_D7_MARK, LCD_DATA11_A_MARK, TIOC2B_C_MARK,
+ A10_MARK, ST0_D6_MARK, LCD_DATA10_A_MARK, TIOC2A_C_MARK,
+ A9_MARK, ST0_D5_MARK, LCD_DATA9_A_MARK, TIOC1B_C_MARK,
+ A8_MARK, ST0_D4_MARK, LCD_DATA8_A_MARK, TIOC1A_C_MARK,
+ A7_MARK, ST0_D3_MARK, LCD_DATA7_A_MARK, TIOC0D_C_MARK,
+ A6_MARK, ST0_D2_MARK, LCD_DATA6_A_MARK, TIOC0C_C_MARK,
+ A5_MARK, ST0_D1_MARK, LCD_DATA5_A_MARK, TIOC0B_C_MARK,
+ A4_MARK, ST0_D0_MARK, LCD_DATA4_A_MARK, TIOC0A_C_MARK,
+ A3_MARK, ST0_VLD_MARK, LCD_DATA3_A_MARK, TCLKD_C_MARK,
+ A2_MARK, ST0_SYC_MARK, LCD_DATA2_A_MARK, TCLKC_C_MARK,
+ A1_MARK, ST0_REQ_MARK, LCD_DATA1_A_MARK, TCLKB_C_MARK,
+ A0_MARK, ST0_CLKIN_MARK, LCD_DATA0_A_MARK, TCLKA_C_MARK,
+
+ /* IPSR1 */
+ D3_MARK, SD0_DAT3_A_MARK, MMC_D3_A_MARK, ST1_D6_MARK, FD3_A_MARK,
+ D2_MARK, SD0_DAT2_A_MARK, MMC_D2_A_MARK, ST1_D5_MARK, FD2_A_MARK,
+ D1_MARK, SD0_DAT1_A_MARK, MMC_D1_A_MARK, ST1_D4_MARK, FD1_A_MARK,
+ D0_MARK, SD0_DAT0_A_MARK, MMC_D0_A_MARK, ST1_D3_MARK, FD0_A_MARK,
+ A25_MARK, TX2_D_MARK, ST1_D2_MARK,
+ A24_MARK, RX2_D_MARK, ST1_D1_MARK,
+ A23_MARK, ST1_D0_MARK, LCD_M_DISP_A_MARK,
+ A22_MARK, ST1_VLD_MARK, LCD_VEPWC_A_MARK,
+ A21_MARK, ST1_SYC_MARK, LCD_VCPWC_A_MARK,
+ A20_MARK, ST1_REQ_MARK, LCD_FLM_A_MARK,
+ A19_MARK, ST1_CLKIN_MARK, LCD_CLK_A_MARK, TIOC4D_C_MARK,
+ A18_MARK, ST1_PWM_MARK, LCD_CL2_A_MARK, TIOC4C_C_MARK,
+ A17_MARK, ST1_VCO_CLKIN_MARK, LCD_CL1_A_MARK, TIOC4B_C_MARK,
+ A16_MARK, ST0_PWM_MARK, LCD_DON_A_MARK, TIOC4A_C_MARK,
+
+ /* IPSR2 */
+ D14_MARK, TX2_B_MARK, FSE_A_MARK, ET0_TX_CLK_B_MARK,
+ D13_MARK, RX2_B_MARK, FRB_A_MARK, ET0_ETXD6_B_MARK,
+ D12_MARK, FWE_A_MARK, ET0_ETXD5_B_MARK,
+ D11_MARK, RSPI_MISO_A_MARK, QMI_QIO1_A_MARK, FRE_A_MARK,
+ ET0_ETXD3_B_MARK,
+ D10_MARK, RSPI_MOSI_A_MARK, QMO_QIO0_A_MARK, FALE_A_MARK,
+ ET0_ETXD2_B_MARK,
+ D9_MARK, SD0_CMD_A_MARK, MMC_CMD_A_MARK, QIO3_A_MARK,
+ FCLE_A_MARK, ET0_ETXD1_B_MARK,
+ D8_MARK, SD0_CLK_A_MARK, MMC_CLK_A_MARK, QIO2_A_MARK,
+ FCE_A_MARK, ET0_GTX_CLK_B_MARK,
+ D7_MARK, RSPI_SSL_A_MARK, MMC_D7_A_MARK, QSSL_A_MARK,
+ FD7_A_MARK,
+ D6_MARK, RSPI_RSPCK_A_MARK, MMC_D6_A_MARK, QSPCLK_A_MARK,
+ FD6_A_MARK,
+ D5_MARK, SD0_WP_A_MARK, MMC_D5_A_MARK, FD5_A_MARK,
+ D4_MARK, SD0_CD_A_MARK, MMC_D4_A_MARK, ST1_D7_MARK,
+ FD4_A_MARK,
+
+ /* IPSR3 */
+ DRACK0_MARK, SD1_DAT2_A_MARK, ATAG_MARK, TCLK1_A_MARK, ET0_ETXD7_MARK,
+ EX_WAIT2_MARK, SD1_DAT1_A_MARK, DACK2_MARK, CAN1_RX_C_MARK,
+ ET0_MAGIC_C_MARK, ET0_ETXD6_A_MARK,
+ EX_WAIT1_MARK, SD1_DAT0_A_MARK, DREQ2_MARK, CAN1_TX_C_MARK,
+ ET0_LINK_C_MARK, ET0_ETXD5_A_MARK,
+ EX_WAIT0_MARK, TCLK1_B_MARK,
+ RD_WR_MARK, TCLK0_MARK, CAN_CLK_B_MARK, ET0_ETXD4_MARK,
+ EX_CS5_MARK, SD1_CMD_A_MARK, ATADIR_MARK, QSSL_B_MARK,
+ ET0_ETXD3_A_MARK,
+ EX_CS4_MARK, SD1_WP_A_MARK, ATAWR_MARK, QMI_QIO1_B_MARK,
+ ET0_ETXD2_A_MARK,
+ EX_CS3_MARK, SD1_CD_A_MARK, ATARD_MARK, QMO_QIO0_B_MARK,
+ ET0_ETXD1_A_MARK,
+ EX_CS2_MARK, TX3_B_MARK, ATACS1_MARK, QSPCLK_B_MARK,
+ ET0_GTX_CLK_A_MARK,
+ EX_CS1_MARK, RX3_B_MARK, ATACS0_MARK, QIO2_B_MARK,
+ ET0_ETXD0_MARK,
+ CS1_A26_MARK, QIO3_B_MARK,
+ D15_MARK, SCK2_B_MARK,
+
+ /* IPSR4 */
+ SCK2_A_MARK, VI0_G3_MARK,
+ RTS1_B_MARK, VI0_G2_MARK,
+ CTS1_B_MARK, VI0_DATA7_VI0_G1_MARK,
+ TX1_B_MARK, VI0_DATA6_VI0_G0_MARK, ET0_PHY_INT_A_MARK,
+ RX1_B_MARK, VI0_DATA5_VI0_B5_MARK, ET0_MAGIC_A_MARK,
+ SCK1_B_MARK, VI0_DATA4_VI0_B4_MARK, ET0_LINK_A_MARK,
+ RTS0_B_MARK, VI0_DATA3_VI0_B3_MARK, ET0_MDIO_A_MARK,
+ CTS0_B_MARK, VI0_DATA2_VI0_B2_MARK, RMII0_MDIO_A_MARK,
+ ET0_MDC_MARK,
+ HTX0_A_MARK, TX1_A_MARK, VI0_DATA1_VI0_B1_MARK,
+ RMII0_MDC_A_MARK, ET0_COL_MARK,
+ HRX0_A_MARK, RX1_A_MARK, VI0_DATA0_VI0_B0_MARK,
+ RMII0_CRS_DV_A_MARK, ET0_CRS_MARK,
+ HSCK0_A_MARK, SCK1_A_MARK, VI0_VSYNC_MARK,
+ RMII0_RX_ER_A_MARK, ET0_RX_ER_MARK,
+ HRTS0_A_MARK, RTS1_A_MARK, VI0_HSYNC_MARK,
+ RMII0_TXD_EN_A_MARK, ET0_RX_DV_MARK,
+ HCTS0_A_MARK, CTS1_A_MARK, VI0_FIELD_MARK,
+ RMII0_RXD1_A_MARK, ET0_ERXD7_MARK,
+
+ /* IPSR5 */
+ SD2_CLK_A_MARK, RX2_A_MARK, VI0_G4_MARK, ET0_RX_CLK_B_MARK,
+ SD2_CMD_A_MARK, TX2_A_MARK, VI0_G5_MARK, ET0_ERXD2_B_MARK,
+ SD2_DAT0_A_MARK, RX3_A_MARK, VI0_R0_MARK, ET0_ERXD3_B_MARK,
+ SD2_DAT1_A_MARK, TX3_A_MARK, VI0_R1_MARK, ET0_MDIO_B_MARK,
+ SD2_DAT2_A_MARK, RX4_A_MARK, VI0_R2_MARK, ET0_LINK_B_MARK,
+ SD2_DAT3_A_MARK, TX4_A_MARK, VI0_R3_MARK, ET0_MAGIC_B_MARK,
+ SD2_CD_A_MARK, RX5_A_MARK, VI0_R4_MARK, ET0_PHY_INT_B_MARK,
+ SD2_WP_A_MARK, TX5_A_MARK, VI0_R5_MARK,
+ REF125CK_MARK, ADTRG_MARK, RX5_C_MARK,
+ REF50CK_MARK, CTS1_E_MARK, HCTS0_D_MARK,
+
+ /* IPSR6 */
+ DU0_DR0_MARK, SCIF_CLK_B_MARK, HRX0_D_MARK, IETX_A_MARK,
+ TCLKA_A_MARK, HIFD00_MARK,
+ DU0_DR1_MARK, SCK0_B_MARK, HTX0_D_MARK, IERX_A_MARK,
+ TCLKB_A_MARK, HIFD01_MARK,
+ DU0_DR2_MARK, RX0_B_MARK, TCLKC_A_MARK, HIFD02_MARK,
+ DU0_DR3_MARK, TX0_B_MARK, TCLKD_A_MARK, HIFD03_MARK,
+ DU0_DR4_MARK, CTS0_C_MARK, TIOC0A_A_MARK, HIFD04_MARK,
+ DU0_DR5_MARK, RTS0_C_MARK, TIOC0B_A_MARK, HIFD05_MARK,
+ DU0_DR6_MARK, SCK1_C_MARK, TIOC0C_A_MARK, HIFD06_MARK,
+ DU0_DR7_MARK, RX1_C_MARK, TIOC0D_A_MARK, HIFD07_MARK,
+ DU0_DG0_MARK, TX1_C_MARK, HSCK0_D_MARK, IECLK_A_MARK,
+ TIOC1A_A_MARK, HIFD08_MARK,
+ DU0_DG1_MARK, CTS1_C_MARK, HRTS0_D_MARK, TIOC1B_A_MARK,
+ HIFD09_MARK,
+
+ /* IPSR7 */
+ DU0_DG2_MARK, RTS1_C_MARK, RMII0_MDC_B_MARK, TIOC2A_A_MARK,
+ HIFD10_MARK,
+ DU0_DG3_MARK, SCK2_C_MARK, RMII0_MDIO_B_MARK, TIOC2B_A_MARK,
+ HIFD11_MARK,
+ DU0_DG4_MARK, RX2_C_MARK, RMII0_CRS_DV_B_MARK, TIOC3A_A_MARK,
+ HIFD12_MARK,
+ DU0_DG5_MARK, TX2_C_MARK, RMII0_RX_ER_B_MARK, TIOC3B_A_MARK,
+ HIFD13_MARK,
+ DU0_DG6_MARK, RX3_C_MARK, RMII0_RXD0_B_MARK, TIOC3C_A_MARK,
+ HIFD14_MARK,
+ DU0_DG7_MARK, TX3_C_MARK, RMII0_RXD1_B_MARK, TIOC3D_A_MARK,
+ HIFD15_MARK,
+ DU0_DB0_MARK, RX4_C_MARK, RMII0_TXD_EN_B_MARK, TIOC4A_A_MARK,
+ HIFCS_MARK,
+ DU0_DB1_MARK, TX4_C_MARK, RMII0_TXD0_B_MARK, TIOC4B_A_MARK,
+ HIFRS_MARK,
+ DU0_DB2_MARK, RX5_B_MARK, RMII0_TXD1_B_MARK, TIOC4C_A_MARK,
+ HIFWR_MARK,
+ DU0_DB3_MARK, TX5_B_MARK, TIOC4D_A_MARK, HIFRD_MARK,
+ DU0_DB4_MARK, HIFINT_MARK,
+
+ /* IPSR8 */
+ DU0_DB5_MARK, HIFDREQ_MARK,
+ DU0_DB6_MARK, HIFRDY_MARK,
+ DU0_DB7_MARK, SSI_SCK0_B_MARK, HIFEBL_B_MARK,
+ DU0_DOTCLKIN_MARK, HSPI_CS0_C_MARK, SSI_WS0_B_MARK,
+ DU0_DOTCLKOUT_MARK, HSPI_CLK0_C_MARK, SSI_SDATA0_B_MARK,
+ DU0_EXHSYNC_DU0_HSYNC_MARK, HSPI_TX0_C_MARK, SSI_SCK1_B_MARK,
+ DU0_EXVSYNC_DU0_VSYNC_MARK, HSPI_RX0_C_MARK, SSI_WS1_B_MARK,
+ DU0_EXODDF_DU0_ODDF_MARK, CAN0_RX_B_MARK, HSCK0_B_MARK,
+ SSI_SDATA1_B_MARK,
+ DU0_DISP_MARK, CAN0_TX_B_MARK, HRX0_B_MARK, AUDIO_CLKA_B_MARK,
+ DU0_CDE_MARK, HTX0_B_MARK, AUDIO_CLKB_B_MARK, LCD_VCPWC_B_MARK,
+ IRQ0_A_MARK, HSPI_TX_B_MARK, RX3_E_MARK, ET0_ERXD0_MARK,
+ IRQ1_A_MARK, HSPI_RX_B_MARK, TX3_E_MARK, ET0_ERXD1_MARK,
+ IRQ2_A_MARK, CTS0_A_MARK, HCTS0_B_MARK, ET0_ERXD2_A_MARK,
+ IRQ3_A_MARK, RTS0_A_MARK, HRTS0_B_MARK, ET0_ERXD3_A_MARK,
+
+ /* IPSR9 */
+ VI1_CLK_A_MARK, FD0_B_MARK, LCD_DATA0_B_MARK,
+ VI1_0_A_MARK, FD1_B_MARK, LCD_DATA1_B_MARK,
+ VI1_1_A_MARK, FD2_B_MARK, LCD_DATA2_B_MARK,
+ VI1_2_A_MARK, FD3_B_MARK, LCD_DATA3_B_MARK,
+ VI1_3_A_MARK, FD4_B_MARK, LCD_DATA4_B_MARK,
+ VI1_4_A_MARK, FD5_B_MARK, LCD_DATA5_B_MARK,
+ VI1_5_A_MARK, FD6_B_MARK, LCD_DATA6_B_MARK,
+ VI1_6_A_MARK, FD7_B_MARK, LCD_DATA7_B_MARK,
+ VI1_7_A_MARK, FCE_B_MARK, LCD_DATA8_B_MARK,
+ SSI_SCK0_A_MARK, TIOC1A_B_MARK, LCD_DATA9_B_MARK,
+ SSI_WS0_A_MARK, TIOC1B_B_MARK, LCD_DATA10_B_MARK,
+ SSI_SDATA0_A_MARK, VI1_0_B_MARK, TIOC2A_B_MARK, LCD_DATA11_B_MARK,
+ SSI_SCK1_A_MARK, VI1_1_B_MARK, TIOC2B_B_MARK, LCD_DATA12_B_MARK,
+ SSI_WS1_A_MARK, VI1_2_B_MARK, LCD_DATA13_B_MARK,
+ SSI_SDATA1_A_MARK, VI1_3_B_MARK, LCD_DATA14_B_MARK,
+
+ /* IPSR10 */
+ SSI_SCK23_MARK, VI1_4_B_MARK, RX1_D_MARK, FCLE_B_MARK,
+ LCD_DATA15_B_MARK,
+ SSI_WS23_MARK, VI1_5_B_MARK, TX1_D_MARK, HSCK0_C_MARK,
+ FALE_B_MARK, LCD_DON_B_MARK,
+ SSI_SDATA2_MARK, VI1_6_B_MARK, HRX0_C_MARK, FRE_B_MARK,
+ LCD_CL1_B_MARK,
+ SSI_SDATA3_MARK, VI1_7_B_MARK, HTX0_C_MARK, FWE_B_MARK,
+ LCD_CL2_B_MARK,
+ AUDIO_CLKA_A_MARK, VI1_CLK_B_MARK, SCK1_D_MARK, IECLK_B_MARK,
+ LCD_FLM_B_MARK,
+ AUDIO_CLKB_A_MARK, LCD_CLK_B_MARK,
+ AUDIO_CLKC_MARK, SCK1_E_MARK, HCTS0_C_MARK, FRB_B_MARK,
+ LCD_VEPWC_B_MARK,
+ AUDIO_CLKOUT_MARK, TX1_E_MARK, HRTS0_C_MARK, FSE_B_MARK,
+ LCD_M_DISP_B_MARK,
+ CAN_CLK_A_MARK, RX4_D_MARK,
+ CAN0_TX_A_MARK, TX4_D_MARK, MLB_CLK_MARK,
+ CAN1_RX_A_MARK, IRQ1_B_MARK,
+ CAN0_RX_A_MARK, IRQ0_B_MARK, MLB_SIG_MARK,
+ CAN1_TX_A_MARK, TX5_C_MARK, MLB_DAT_MARK,
+
+ /* IPSR11 */
+ SCL1_MARK, SCIF_CLK_C_MARK,
+ SDA1_MARK, RX1_E_MARK,
+ SDA0_MARK, HIFEBL_A_MARK,
+ SDSELF_MARK, RTS1_E_MARK,
+ SCIF_CLK_A_MARK, HSPI_CLK_A_MARK, VI0_CLK_MARK, RMII0_TXD0_A_MARK,
+ ET0_ERXD4_MARK,
+ SCK0_A_MARK, HSPI_CS_A_MARK, VI0_CLKENB_MARK, RMII0_TXD1_A_MARK,
+ ET0_ERXD5_MARK,
+ RX0_A_MARK, HSPI_RX_A_MARK, RMII0_RXD0_A_MARK, ET0_ERXD6_MARK,
+ TX0_A_MARK, HSPI_TX_A_MARK,
+ PENC1_MARK, TX3_D_MARK, CAN1_TX_B_MARK, TX5_D_MARK,
+ IETX_B_MARK,
+ USB_OVC1_MARK, RX3_D_MARK, CAN1_RX_B_MARK, RX5_D_MARK,
+ IERX_B_MARK,
+ DREQ0_MARK, SD1_CLK_A_MARK, ET0_TX_EN_MARK,
+ DACK0_MARK, SD1_DAT3_A_MARK, ET0_TX_ER_MARK,
+ DREQ1_MARK, HSPI_CLK_B_MARK, RX4_B_MARK, ET0_PHY_INT_C_MARK,
+ ET0_TX_CLK_A_MARK,
+ DACK1_MARK, HSPI_CS_B_MARK, TX4_B_MARK, ET0_RX_CLK_A_MARK,
+ PRESETOUT_MARK, ST_CLKOUT_MARK,
+
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+ PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
+
+ PINMUX_DATA(CLKOUT_MARK, FN_CLKOUT),
+ PINMUX_DATA(BS_MARK, FN_BS), PINMUX_DATA(CS0_MARK, FN_CS0),
+ PINMUX_DATA(EX_CS0_MARK, FN_EX_CS0),
+ PINMUX_DATA(RD_MARK, FN_RD), PINMUX_DATA(WE0_MARK, FN_WE0),
+ PINMUX_DATA(WE1_MARK, FN_WE1),
+ PINMUX_DATA(SCL0_MARK, FN_SCL0), PINMUX_DATA(PENC0_MARK, FN_PENC0),
+ PINMUX_DATA(USB_OVC0_MARK, FN_USB_OVC0),
+ PINMUX_DATA(IRQ2_B_MARK, FN_IRQ2_B),
+ PINMUX_DATA(IRQ3_B_MARK, FN_IRQ3_B),
+
+ /* IPSR0 */
+ PINMUX_IPSR_DATA(IP0_1_0, A0),
+ PINMUX_IPSR_DATA(IP0_1_0, ST0_CLKIN),
+ PINMUX_IPSR_MODSEL_DATA(IP0_1_0, LCD_DATA0_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_1_0, TCLKA_C, SEL_MTU2_CLK_1),
+
+ PINMUX_IPSR_DATA(IP0_3_2, A1),
+ PINMUX_IPSR_DATA(IP0_3_2, ST0_REQ),
+ PINMUX_IPSR_MODSEL_DATA(IP0_3_2, LCD_DATA1_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_3_2, TCLKB_C, SEL_MTU2_CLK_1),
+
+ PINMUX_IPSR_DATA(IP0_5_4, A2),
+ PINMUX_IPSR_DATA(IP0_5_4, ST0_SYC),
+ PINMUX_IPSR_MODSEL_DATA(IP0_5_4, LCD_DATA2_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_5_4, TCLKC_C, SEL_MTU2_CLK_1),
+
+ PINMUX_IPSR_DATA(IP0_7_6, A3),
+ PINMUX_IPSR_DATA(IP0_7_6, ST0_VLD),
+ PINMUX_IPSR_MODSEL_DATA(IP0_7_6, LCD_DATA3_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_7_6, TCLKD_C, SEL_MTU2_CLK_1),
+
+ PINMUX_IPSR_DATA(IP0_9_8, A4),
+ PINMUX_IPSR_DATA(IP0_9_8, ST0_D0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_9_8, LCD_DATA4_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_9_8, TIOC0A_C, SEL_MTU2_CH0_1),
+
+ PINMUX_IPSR_DATA(IP0_11_10, A5),
+ PINMUX_IPSR_DATA(IP0_11_10, ST0_D1),
+ PINMUX_IPSR_MODSEL_DATA(IP0_11_10, LCD_DATA5_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_11_10, TIOC0B_C, SEL_MTU2_CH0_1),
+
+ PINMUX_IPSR_DATA(IP0_13_12, A6),
+ PINMUX_IPSR_DATA(IP0_13_12, ST0_D2),
+ PINMUX_IPSR_MODSEL_DATA(IP0_13_12, LCD_DATA6_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_13_12, TIOC0C_C, SEL_MTU2_CH0_1),
+
+ PINMUX_IPSR_DATA(IP0_15_14, A7),
+ PINMUX_IPSR_DATA(IP0_15_14, ST0_D3),
+ PINMUX_IPSR_MODSEL_DATA(IP0_15_14, LCD_DATA7_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_15_14, TIOC0D_C, SEL_MTU2_CH0_1),
+
+ PINMUX_IPSR_DATA(IP0_17_16, A8),
+ PINMUX_IPSR_DATA(IP0_17_16, ST0_D4),
+ PINMUX_IPSR_MODSEL_DATA(IP0_17_16, LCD_DATA8_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_17_16, TIOC1A_C, SEL_MTU2_CH1_2),
+
+ PINMUX_IPSR_DATA(IP0_19_18, A9),
+ PINMUX_IPSR_DATA(IP0_19_18, ST0_D5),
+ PINMUX_IPSR_MODSEL_DATA(IP0_19_18, LCD_DATA9_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_19_18, TIOC1B_C, SEL_MTU2_CH1_2),
+
+ PINMUX_IPSR_DATA(IP0_21_20, A10),
+ PINMUX_IPSR_DATA(IP0_21_20, ST0_D6),
+ PINMUX_IPSR_MODSEL_DATA(IP0_21_20, LCD_DATA10_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_21_20, TIOC2A_C, SEL_MTU2_CH2_2),
+
+ PINMUX_IPSR_DATA(IP0_23_22, A11),
+ PINMUX_IPSR_DATA(IP0_23_22, ST0_D7),
+ PINMUX_IPSR_MODSEL_DATA(IP0_23_22, LCD_DATA11_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_23_22, TIOC2B_C, SEL_MTU2_CH2_2),
+
+ PINMUX_IPSR_DATA(IP0_25_24, A12),
+ PINMUX_IPSR_MODSEL_DATA(IP0_25_24, LCD_DATA12_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_25_24, TIOC3A_C, SEL_MTU2_CH3_1),
+
+ PINMUX_IPSR_DATA(IP0_27_26, A13),
+ PINMUX_IPSR_MODSEL_DATA(IP0_27_26, LCD_DATA13_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_27_26, TIOC3B_C, SEL_MTU2_CH3_1),
+
+ PINMUX_IPSR_DATA(IP0_29_28, A14),
+ PINMUX_IPSR_MODSEL_DATA(IP0_29_28, LCD_DATA14_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_29_28, TIOC3C_C, SEL_MTU2_CH3_1),
+
+ PINMUX_IPSR_DATA(IP0_31_30, A15),
+ PINMUX_IPSR_DATA(IP0_31_30, ST0_VCO_CLKIN),
+ PINMUX_IPSR_MODSEL_DATA(IP0_31_30, LCD_DATA15_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_31_30, TIOC3D_C, SEL_MTU2_CH3_1),
+
+
+ /* IPSR1 */
+ PINMUX_IPSR_DATA(IP1_1_0, A16),
+ PINMUX_IPSR_DATA(IP1_1_0, ST0_PWM),
+ PINMUX_IPSR_MODSEL_DATA(IP1_1_0, LCD_DON_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_1_0, TIOC4A_C, SEL_MTU2_CH4_1),
+
+ PINMUX_IPSR_DATA(IP1_3_2, A17),
+ PINMUX_IPSR_DATA(IP1_3_2, ST1_VCO_CLKIN),
+ PINMUX_IPSR_MODSEL_DATA(IP1_3_2, LCD_CL1_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_3_2, TIOC4B_C, SEL_MTU2_CH4_1),
+
+ PINMUX_IPSR_DATA(IP1_5_4, A18),
+ PINMUX_IPSR_DATA(IP1_5_4, ST1_PWM),
+ PINMUX_IPSR_MODSEL_DATA(IP1_5_4, LCD_CL2_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_5_4, TIOC4C_C, SEL_MTU2_CH4_1),
+
+ PINMUX_IPSR_DATA(IP1_7_6, A19),
+ PINMUX_IPSR_DATA(IP1_7_6, ST1_CLKIN),
+ PINMUX_IPSR_MODSEL_DATA(IP1_7_6, LCD_CLK_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_7_6, TIOC4D_C, SEL_MTU2_CH4_1),
+
+ PINMUX_IPSR_DATA(IP1_9_8, A20),
+ PINMUX_IPSR_DATA(IP1_9_8, ST1_REQ),
+ PINMUX_IPSR_MODSEL_DATA(IP1_9_8, LCD_FLM_A, SEL_LCDC_0),
+
+ PINMUX_IPSR_DATA(IP1_11_10, A21),
+ PINMUX_IPSR_DATA(IP1_11_10, ST1_SYC),
+ PINMUX_IPSR_MODSEL_DATA(IP1_11_10, LCD_VCPWC_A, SEL_LCDC_0),
+
+ PINMUX_IPSR_DATA(IP1_13_12, A22),
+ PINMUX_IPSR_DATA(IP1_13_12, ST1_VLD),
+ PINMUX_IPSR_MODSEL_DATA(IP1_13_12, LCD_VEPWC_A, SEL_LCDC_0),
+
+ PINMUX_IPSR_DATA(IP1_15_14, A23),
+ PINMUX_IPSR_DATA(IP1_15_14, ST1_D0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_15_14, LCD_M_DISP_A, SEL_LCDC_0),
+
+ PINMUX_IPSR_DATA(IP1_17_16, A24),
+ PINMUX_IPSR_MODSEL_DATA(IP1_17_16, RX2_D, SEL_SCIF2_3),
+ PINMUX_IPSR_DATA(IP1_17_16, ST1_D1),
+
+ PINMUX_IPSR_DATA(IP1_19_18, A25),
+ PINMUX_IPSR_MODSEL_DATA(IP1_17_16, RX2_D, SEL_SCIF2_3),
+ PINMUX_IPSR_DATA(IP1_17_16, ST1_D2),
+
+ PINMUX_IPSR_DATA(IP1_22_20, D0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_22_20, SD0_DAT0_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_22_20, MMC_D0_A, SEL_MMC_0),
+ PINMUX_IPSR_DATA(IP1_22_20, ST1_D3),
+ PINMUX_IPSR_MODSEL_DATA(IP1_22_20, FD0_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP1_25_23, D1),
+ PINMUX_IPSR_MODSEL_DATA(IP1_25_23, SD0_DAT0_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_25_23, MMC_D1_A, SEL_MMC_0),
+ PINMUX_IPSR_DATA(IP1_25_23, ST1_D4),
+ PINMUX_IPSR_MODSEL_DATA(IP1_25_23, FD1_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP1_28_26, D2),
+ PINMUX_IPSR_MODSEL_DATA(IP1_28_26, SD0_DAT0_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_28_26, MMC_D2_A, SEL_MMC_0),
+ PINMUX_IPSR_DATA(IP1_28_26, ST1_D5),
+ PINMUX_IPSR_MODSEL_DATA(IP1_28_26, FD2_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP1_31_29, D3),
+ PINMUX_IPSR_MODSEL_DATA(IP1_31_29, SD0_DAT0_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_31_29, MMC_D3_A, SEL_MMC_0),
+ PINMUX_IPSR_DATA(IP1_31_29, ST1_D6),
+ PINMUX_IPSR_MODSEL_DATA(IP1_31_29, FD3_A, SEL_FLCTL_0),
+
+ /* IPSR2 */
+ PINMUX_IPSR_DATA(IP2_2_0, D4),
+ PINMUX_IPSR_MODSEL_DATA(IP2_2_0, SD0_CD_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_2_0, MMC_D4_A, SEL_MMC_0),
+ PINMUX_IPSR_DATA(IP2_2_0, ST1_D7),
+ PINMUX_IPSR_MODSEL_DATA(IP2_2_0, FD4_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP2_4_3, D5),
+ PINMUX_IPSR_MODSEL_DATA(IP2_4_3, SD0_WP_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_4_3, MMC_D5_A, SEL_MMC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_4_3, FD5_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP2_7_5, D6),
+ PINMUX_IPSR_MODSEL_DATA(IP2_7_5, RSPI_RSPCK_A, SEL_RSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_7_5, MMC_D6_A, SEL_MMC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_7_5, QSPCLK_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_7_5, FD6_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP2_10_8, D7),
+ PINMUX_IPSR_MODSEL_DATA(IP2_10_8, RSPI_SSL_A, SEL_RSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_10_8, MMC_D7_A, SEL_MMC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_10_8, QSSL_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_10_8, FD7_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP2_13_11, D8),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_11, SD0_CLK_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_11, MMC_CLK_A, SEL_MMC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_11, QIO2_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_11, FCE_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_11, ET0_GTX_CLK_B, SEL_ET0_1),
+
+ PINMUX_IPSR_DATA(IP2_16_14, D9),
+ PINMUX_IPSR_MODSEL_DATA(IP2_16_14, SD0_CMD_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_16_14, MMC_CMD_A, SEL_MMC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_16_14, QIO3_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_16_14, FCLE_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_16_14, ET0_ETXD1_B, SEL_ET0_1),
+
+ PINMUX_IPSR_DATA(IP2_19_17, D10),
+ PINMUX_IPSR_MODSEL_DATA(IP2_19_17, RSPI_MOSI_A, SEL_RSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_19_17, QMO_QIO0_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_19_17, FALE_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_19_17, ET0_ETXD2_B, SEL_ET0_1),
+
+ PINMUX_IPSR_DATA(IP2_22_20, D11),
+ PINMUX_IPSR_MODSEL_DATA(IP2_22_20, RSPI_MISO_A, SEL_RSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_22_20, QMI_QIO1_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_22_20, FRE_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP2_24_23, D12),
+ PINMUX_IPSR_MODSEL_DATA(IP2_24_23, FWE_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_24_23, ET0_ETXD5_B, SEL_ET0_1),
+
+ PINMUX_IPSR_DATA(IP2_27_25, D13),
+ PINMUX_IPSR_MODSEL_DATA(IP2_27_25, RX2_B, SEL_SCIF2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP2_27_25, FRB_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_27_25, ET0_ETXD6_B, SEL_ET0_1),
+
+ PINMUX_IPSR_DATA(IP2_30_28, D14),
+ PINMUX_IPSR_MODSEL_DATA(IP2_30_28, TX2_B, SEL_SCIF2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP2_30_28, FSE_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_30_28, ET0_TX_CLK_B, SEL_ET0_1),
+
+ /* IPSR3 */
+ PINMUX_IPSR_DATA(IP3_1_0, D15),
+ PINMUX_IPSR_MODSEL_DATA(IP3_1_0, SCK2_B, SEL_SCIF2_1),
+
+ PINMUX_IPSR_DATA(IP3_2, CS1_A26),
+ PINMUX_IPSR_MODSEL_DATA(IP3_2, QIO3_B, SEL_RQSPI_1),
+
+ PINMUX_IPSR_DATA(IP3_5_3, EX_CS1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_5_3, RX3_B, SEL_SCIF2_1),
+ PINMUX_IPSR_DATA(IP3_5_3, ATACS0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_5_3, QIO2_B, SEL_RQSPI_1),
+ PINMUX_IPSR_DATA(IP3_5_3, ET0_ETXD0),
+
+ PINMUX_IPSR_DATA(IP3_8_6, EX_CS2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_8_6, TX3_B, SEL_SCIF3_1),
+ PINMUX_IPSR_DATA(IP3_8_6, ATACS1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_8_6, QSPCLK_B, SEL_RQSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_8_6, ET0_GTX_CLK_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_11_9, EX_CS3),
+ PINMUX_IPSR_MODSEL_DATA(IP3_11_9, SD1_CD_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_11_9, ATARD),
+ PINMUX_IPSR_MODSEL_DATA(IP3_11_9, QMO_QIO0_B, SEL_RQSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_11_9, ET0_ETXD1_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_14_12, EX_CS4),
+ PINMUX_IPSR_MODSEL_DATA(IP3_14_12, SD1_WP_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_14_12, ATAWR),
+ PINMUX_IPSR_MODSEL_DATA(IP3_14_12, QMI_QIO1_B, SEL_RQSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_14_12, ET0_ETXD2_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_17_15, EX_CS5),
+ PINMUX_IPSR_MODSEL_DATA(IP3_17_15, SD1_CMD_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_17_15, ATADIR),
+ PINMUX_IPSR_MODSEL_DATA(IP3_17_15, QSSL_B, SEL_RQSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_17_15, ET0_ETXD3_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_19_18, RD_WR),
+ PINMUX_IPSR_DATA(IP3_19_18, TCLK0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_19_18, CAN_CLK_B, SEL_RCAN_CLK_1),
+ PINMUX_IPSR_DATA(IP3_19_18, ET0_ETXD4),
+
+ PINMUX_IPSR_DATA(IP3_20, EX_WAIT0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_20, TCLK1_B, SEL_TMU_1),
+
+ PINMUX_IPSR_DATA(IP3_23_21, EX_WAIT1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, SD1_DAT0_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_23_21, DREQ2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, CAN1_TX_C, SEL_RCAN1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, ET0_LINK_C, SEL_ET0_CTL_2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, ET0_ETXD5_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_26_24, EX_WAIT2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, SD1_DAT1_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_26_24, DACK2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, CAN1_RX_C, SEL_RCAN1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, ET0_MAGIC_C, SEL_ET0_CTL_2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, ET0_ETXD6_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_29_27, DRACK0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_29_27, SD1_DAT2_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_29_27, ATAG),
+ PINMUX_IPSR_MODSEL_DATA(IP3_29_27, TCLK1_A, SEL_TMU_0),
+ PINMUX_IPSR_DATA(IP3_29_27, ET0_ETXD7),
+
+ /* IPSR4 */
+ PINMUX_IPSR_MODSEL_DATA(IP4_2_0, HCTS0_A, SEL_HSCIF_0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_2_0, CTS1_A, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP4_2_0, VI0_FIELD),
+ PINMUX_IPSR_MODSEL_DATA(IP4_2_0, RMII0_RXD1_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_2_0, ET0_ERXD7),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_5_3, HRTS0_A, SEL_HSCIF_0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_5_3, RTS1_A, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP4_5_3, VI0_HSYNC),
+ PINMUX_IPSR_MODSEL_DATA(IP4_5_3, RMII0_TXD_EN_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_5_3, ET0_RX_DV),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_8_6, HSCK0_A, SEL_HSCIF_0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_8_6, SCK1_A, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP4_8_6, VI0_VSYNC),
+ PINMUX_IPSR_MODSEL_DATA(IP4_8_6, RMII0_RX_ER_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_8_6, ET0_RX_ER),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_11_9, HRX0_A, SEL_HSCIF_0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_11_9, RX1_A, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP4_11_9, VI0_DATA0_VI0_B0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_11_9, RMII0_CRS_DV_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_11_9, ET0_CRS),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_14_12, HTX0_A, SEL_HSCIF_0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_14_12, TX1_A, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP4_14_12, VI0_DATA1_VI0_B1),
+ PINMUX_IPSR_MODSEL_DATA(IP4_14_12, RMII0_MDC_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_14_12, ET0_COL),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_17_15, CTS0_B, SEL_SCIF0_1),
+ PINMUX_IPSR_DATA(IP4_17_15, VI0_DATA2_VI0_B2),
+ PINMUX_IPSR_MODSEL_DATA(IP4_17_15, RMII0_MDIO_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_17_15, ET0_MDC),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_19_18, RTS0_B, SEL_SCIF0_1),
+ PINMUX_IPSR_DATA(IP4_19_18, VI0_DATA3_VI0_B3),
+ PINMUX_IPSR_MODSEL_DATA(IP4_19_18, ET0_MDIO_A, SEL_ET0_0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_21_20, SCK1_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP4_21_20, VI0_DATA4_VI0_B4),
+ PINMUX_IPSR_MODSEL_DATA(IP4_21_20, ET0_LINK_A, SEL_ET0_CTL_0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_23_22, RX1_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP4_23_22, VI0_DATA5_VI0_B5),
+ PINMUX_IPSR_MODSEL_DATA(IP4_23_22, ET0_MAGIC_A, SEL_ET0_CTL_0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_25_24, TX1_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP4_25_24, VI0_DATA6_VI0_G0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_25_24, ET0_PHY_INT_A, SEL_ET0_CTL_0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_27_26, CTS1_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP4_27_26, VI0_DATA7_VI0_G1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_29_28, RTS1_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP4_29_28, VI0_G2),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_31_30, SCK2_A, SEL_SCIF2_0),
+ PINMUX_IPSR_DATA(IP4_31_30, VI0_G3),
+
+ /* IPSR5 */
+ PINMUX_IPSR_MODSEL_DATA(IP5_2_0, SD2_CLK_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_2_0, RX2_A, SEL_SCIF2_0),
+ PINMUX_IPSR_DATA(IP5_2_0, VI0_G4),
+ PINMUX_IPSR_MODSEL_DATA(IP5_2_0, ET0_RX_CLK_B, SEL_ET0_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_5_3, SD2_CMD_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_5_3, TX2_A, SEL_SCIF2_0),
+ PINMUX_IPSR_DATA(IP5_5_3, VI0_G5),
+ PINMUX_IPSR_MODSEL_DATA(IP5_5_3, ET0_ERXD2_B, SEL_ET0_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_8_6, SD2_DAT0_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_8_6, RX3_A, SEL_SCIF3_0),
+ PINMUX_IPSR_DATA(IP4_8_6, VI0_R0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_8_6, ET0_ERXD2_B, SEL_ET0_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_11_9, SD2_DAT1_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_11_9, TX3_A, SEL_SCIF3_0),
+ PINMUX_IPSR_DATA(IP5_11_9, VI0_R1),
+ PINMUX_IPSR_MODSEL_DATA(IP5_11_9, ET0_MDIO_B, SEL_ET0_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_14_12, SD2_DAT2_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_14_12, RX4_A, SEL_SCIF4_0),
+ PINMUX_IPSR_DATA(IP5_14_12, VI0_R2),
+ PINMUX_IPSR_MODSEL_DATA(IP5_14_12, ET0_LINK_B, SEL_ET0_CTL_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_17_15, SD2_DAT3_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_17_15, TX4_A, SEL_SCIF4_0),
+ PINMUX_IPSR_DATA(IP5_17_15, VI0_R3),
+ PINMUX_IPSR_MODSEL_DATA(IP5_17_15, ET0_MAGIC_B, SEL_ET0_CTL_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_20_18, SD2_CD_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_20_18, RX5_A, SEL_SCIF5_0),
+ PINMUX_IPSR_DATA(IP5_20_18, VI0_R4),
+ PINMUX_IPSR_MODSEL_DATA(IP5_20_18, ET0_PHY_INT_B, SEL_ET0_CTL_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_22_21, SD2_WP_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_22_21, TX5_A, SEL_SCIF5_0),
+ PINMUX_IPSR_DATA(IP5_22_21, VI0_R5),
+
+ PINMUX_IPSR_DATA(IP5_24_23, REF125CK),
+ PINMUX_IPSR_DATA(IP5_24_23, ADTRG),
+ PINMUX_IPSR_MODSEL_DATA(IP5_24_23, RX5_C, SEL_SCIF5_2),
+ PINMUX_IPSR_DATA(IP5_26_25, REF50CK),
+ PINMUX_IPSR_MODSEL_DATA(IP5_26_25, CTS1_E, SEL_SCIF1_3),
+ PINMUX_IPSR_MODSEL_DATA(IP5_26_25, HCTS0_D, SEL_HSCIF_3),
+
+ /* IPSR6 */
+ PINMUX_IPSR_DATA(IP6_2_0, DU0_DR0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_2_0, SCIF_CLK_B, SEL_SCIF_CLK_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_2_0, HRX0_D, SEL_HSCIF_3),
+ PINMUX_IPSR_MODSEL_DATA(IP6_2_0, IETX_A, SEL_IEBUS_0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_2_0, TCLKA_A, SEL_MTU2_CLK_0),
+ PINMUX_IPSR_DATA(IP6_2_0, HIFD00),
+
+ PINMUX_IPSR_DATA(IP6_5_3, DU0_DR1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_5_3, SCK0_B, SEL_SCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_5_3, HTX0_D, SEL_HSCIF_3),
+ PINMUX_IPSR_MODSEL_DATA(IP6_5_3, IERX_A, SEL_IEBUS_0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_5_3, TCLKB_A, SEL_MTU2_CLK_0),
+ PINMUX_IPSR_DATA(IP6_5_3, HIFD01),
+
+ PINMUX_IPSR_DATA(IP6_7_6, DU0_DR2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_7_6, RX0_B, SEL_SCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_7_6, TCLKC_A, SEL_MTU2_CLK_0),
+ PINMUX_IPSR_DATA(IP6_7_6, HIFD02),
+
+ PINMUX_IPSR_DATA(IP6_9_8, DU0_DR3),
+ PINMUX_IPSR_MODSEL_DATA(IP6_9_8, TX0_B, SEL_SCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_9_8, TCLKD_A, SEL_MTU2_CLK_0),
+ PINMUX_IPSR_DATA(IP6_9_8, HIFD03),
+
+ PINMUX_IPSR_DATA(IP6_11_10, DU0_DR4),
+ PINMUX_IPSR_MODSEL_DATA(IP6_11_10, CTS0_C, SEL_SCIF0_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_11_10, TIOC0A_A, SEL_MTU2_CH0_0),
+ PINMUX_IPSR_DATA(IP6_11_10, HIFD04),
+
+ PINMUX_IPSR_DATA(IP6_13_12, DU0_DR5),
+ PINMUX_IPSR_MODSEL_DATA(IP6_13_12, RTS0_C, SEL_SCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_13_12, TIOC0B_A, SEL_MTU2_CH0_0),
+ PINMUX_IPSR_DATA(IP6_13_12, HIFD05),
+
+ PINMUX_IPSR_DATA(IP6_15_14, DU0_DR6),
+ PINMUX_IPSR_MODSEL_DATA(IP6_15_14, SCK1_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_15_14, TIOC0C_A, SEL_MTU2_CH0_0),
+ PINMUX_IPSR_DATA(IP6_15_14, HIFD06),
+
+ PINMUX_IPSR_DATA(IP6_17_16, DU0_DR7),
+ PINMUX_IPSR_MODSEL_DATA(IP6_17_16, RX1_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_17_16, TIOC0D_A, SEL_MTU2_CH0_0),
+ PINMUX_IPSR_DATA(IP6_17_16, HIFD07),
+
+ PINMUX_IPSR_DATA(IP6_20_18, DU0_DG0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_20_18, TX1_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_20_18, HSCK0_D, SEL_HSCIF_3),
+ PINMUX_IPSR_MODSEL_DATA(IP6_20_18, IECLK_A, SEL_IEBUS_0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_20_18, TIOC1A_A, SEL_MTU2_CH1_0),
+ PINMUX_IPSR_DATA(IP6_20_18, HIFD08),
+
+ PINMUX_IPSR_DATA(IP6_23_21, DU0_DG1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_23_21, CTS1_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_23_21, HRTS0_D, SEL_HSCIF_3),
+ PINMUX_IPSR_MODSEL_DATA(IP6_23_21, TIOC1B_A, SEL_MTU2_CH1_0),
+ PINMUX_IPSR_DATA(IP6_23_21, HIFD09),
+
+ /* IPSR7 */
+ PINMUX_IPSR_DATA(IP7_2_0, DU0_DG2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, RTS1_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, RMII0_MDC_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, TIOC2A_A, SEL_MTU2_CH2_0),
+ PINMUX_IPSR_DATA(IP7_2_0, HIFD10),
+
+ PINMUX_IPSR_DATA(IP7_5_3, DU0_DG3),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, SCK2_C, SEL_SCIF2_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, RMII0_MDIO_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, TIOC2B_A, SEL_MTU2_CH2_0),
+ PINMUX_IPSR_DATA(IP7_5_3, HIFD11),
+
+ PINMUX_IPSR_DATA(IP7_8_6, DU0_DG4),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RX2_C, SEL_SCIF2_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RMII0_CRS_DV_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, TIOC3A_A, SEL_MTU2_CH3_0),
+ PINMUX_IPSR_DATA(IP7_8_6, HIFD12),
+
+ PINMUX_IPSR_DATA(IP7_11_9, DU0_DG5),
+ PINMUX_IPSR_MODSEL_DATA(IP7_11_9, TX2_C, SEL_SCIF2_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_11_9, RMII0_RX_ER_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_11_9, TIOC3B_A, SEL_MTU2_CH3_0),
+ PINMUX_IPSR_DATA(IP7_11_9, HIFD13),
+
+ PINMUX_IPSR_DATA(IP7_14_12, DU0_DG6),
+ PINMUX_IPSR_MODSEL_DATA(IP7_14_12, RX3_C, SEL_SCIF3_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_14_12, RMII0_RXD0_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_14_12, TIOC3C_A, SEL_MTU2_CH3_0),
+ PINMUX_IPSR_DATA(IP7_14_12, HIFD14),
+
+ PINMUX_IPSR_DATA(IP7_17_15, DU0_DG7),
+ PINMUX_IPSR_MODSEL_DATA(IP7_17_15, TX3_C, SEL_SCIF3_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_17_15, RMII0_RXD1_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_17_15, TIOC3D_A, SEL_MTU2_CH3_0),
+ PINMUX_IPSR_DATA(IP7_17_15, HIFD15),
+
+ PINMUX_IPSR_DATA(IP7_20_18, DU0_DB0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_20_18, RX4_C, SEL_SCIF4_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_20_18, RMII0_TXD_EN_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_20_18, TIOC4A_A, SEL_MTU2_CH4_0),
+ PINMUX_IPSR_DATA(IP7_20_18, HIFCS),
+
+ PINMUX_IPSR_DATA(IP7_23_21, DU0_DB1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TX4_C, SEL_SCIF4_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_23_21, RMII0_TXD0_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TIOC4B_A, SEL_MTU2_CH4_0),
+ PINMUX_IPSR_DATA(IP7_23_21, HIFWR),
+
+ PINMUX_IPSR_DATA(IP7_26_24, DU0_DB2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RX5_B, SEL_SCIF5_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RMII0_TXD1_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_26_24, TIOC4C_A, SEL_MTU2_CH4_0),
+
+ PINMUX_IPSR_DATA(IP7_28_27, DU0_DB3),
+ PINMUX_IPSR_MODSEL_DATA(IP7_28_27, TX5_B, SEL_SCIF5_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_28_27, TIOC4D_A, SEL_MTU2_CH4_0),
+ PINMUX_IPSR_DATA(IP7_28_27, HIFRD),
+
+ PINMUX_IPSR_DATA(IP7_30_29, DU0_DB4),
+ PINMUX_IPSR_DATA(IP7_30_29, HIFINT),
+
+ /* IPSR8 */
+ PINMUX_IPSR_DATA(IP8_1_0, DU0_DB5),
+ PINMUX_IPSR_DATA(IP8_1_0, HIFDREQ),
+
+ PINMUX_IPSR_DATA(IP8_3_2, DU0_DB6),
+ PINMUX_IPSR_DATA(IP8_3_2, HIFRDY),
+
+ PINMUX_IPSR_DATA(IP8_5_4, DU0_DB7),
+ PINMUX_IPSR_MODSEL_DATA(IP8_5_4, SSI_SCK0_B, SEL_SSI0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_5_4, HIFEBL_B, SEL_HIF_1),
+
+ PINMUX_IPSR_DATA(IP8_7_6, DU0_DOTCLKIN),
+ PINMUX_IPSR_MODSEL_DATA(IP8_7_6, HSPI_CS0_C, SEL_HSPI_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_7_6, SSI_WS0_B, SEL_SSI0_1),
+
+ PINMUX_IPSR_DATA(IP8_9_8, DU0_DOTCLKOUT),
+ PINMUX_IPSR_MODSEL_DATA(IP8_9_8, HSPI_CLK0_C, SEL_HSPI_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_9_8, SSI_SDATA0_B, SEL_SSI0_1),
+
+ PINMUX_IPSR_DATA(IP8_11_10, DU0_EXHSYNC_DU0_HSYNC),
+ PINMUX_IPSR_MODSEL_DATA(IP8_11_10, HSPI_TX0_C, SEL_HSPI_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_11_10, SSI_SCK1_B, SEL_SSI1_1),
+
+ PINMUX_IPSR_DATA(IP8_13_12, DU0_EXVSYNC_DU0_VSYNC),
+ PINMUX_IPSR_MODSEL_DATA(IP8_13_12, HSPI_RX0_C, SEL_HSPI_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_13_12, SSI_WS1_B, SEL_SSI1_1),
+
+ PINMUX_IPSR_DATA(IP8_15_14, DU0_EXODDF_DU0_ODDF),
+ PINMUX_IPSR_MODSEL_DATA(IP8_15_14, CAN0_RX_B, SEL_RCAN0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_15_14, HSCK0_B, SEL_HSCIF_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_15_14, SSI_SDATA1_B, SEL_SSI1_1),
+
+ PINMUX_IPSR_DATA(IP8_17_16, DU0_DISP),
+ PINMUX_IPSR_MODSEL_DATA(IP8_17_16, CAN0_TX_B, SEL_RCAN0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_17_16, HRX0_B, SEL_HSCIF_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_17_16, AUDIO_CLKA_B, SEL_AUDIO_CLKA_1),
+
+ PINMUX_IPSR_DATA(IP8_19_18, DU0_CDE),
+ PINMUX_IPSR_MODSEL_DATA(IP8_19_18, HTX0_B, SEL_HSCIF_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_19_18, AUDIO_CLKB_B, SEL_AUDIO_CLKB_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_19_18, LCD_VCPWC_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP8_22_20, IRQ0_A, SEL_INTC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_22_20, HSPI_TX_B, SEL_HSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_22_20, RX3_E, SEL_SCIF3_4),
+ PINMUX_IPSR_DATA(IP8_22_20, ET0_ERXD0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP8_25_23, IRQ1_A, SEL_INTC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_25_23, HSPI_RX_B, SEL_HSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_25_23, TX3_E, SEL_SCIF3_4),
+ PINMUX_IPSR_DATA(IP8_25_23, ET0_ERXD1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP8_27_26, IRQ2_A, SEL_INTC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_27_26, CTS0_A, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_27_26, HCTS0_B, SEL_HSCIF_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_27_26, ET0_ERXD2_A, SEL_ET0_0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP8_29_28, IRQ3_A, SEL_INTC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_29_28, RTS0_A, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_29_28, HRTS0_B, SEL_HSCIF_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_29_28, ET0_ERXD3_A, SEL_ET0_0),
+
+ /* IPSR9 */
+ PINMUX_IPSR_MODSEL_DATA(IP9_1_0, VI1_CLK_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_1_0, FD0_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_1_0, LCD_DATA0_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_3_2, VI1_0_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_3_2, FD1_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_3_2, LCD_DATA1_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_5_4, VI1_1_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_5_4, FD2_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_5_4, LCD_DATA2_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_7_6, VI1_2_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_7_6, FD3_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_7_6, LCD_DATA3_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_9_8, VI1_3_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_9_8, FD4_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_9_8, LCD_DATA4_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_10, VI1_4_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_10, FD5_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_10, LCD_DATA5_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_13_12, VI1_5_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_13_12, FD6_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_13_12, LCD_DATA6_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_15_14, VI1_6_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_15_14, FD7_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_15_14, LCD_DATA7_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_17_16, VI1_7_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_17_16, FCE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_17_16, LCD_DATA8_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_19_18, SSI_SCK0_A, SEL_SSI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_19_18, TIOC1A_B, SEL_MTU2_CH1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_19_18, LCD_DATA9_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_21_20, SSI_WS0_A, SEL_SSI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_21_20, TIOC1B_B, SEL_MTU2_CH1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_21_20, LCD_DATA10_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_23_22, SSI_SDATA0_A, SEL_SSI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_23_22, VI1_0_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_23_22, TIOC2A_B, SEL_MTU2_CH2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_23_22, LCD_DATA11_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_25_24, SSI_SCK1_A, SEL_SSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_25_24, VI1_1_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_25_24, TIOC2B_B, SEL_MTU2_CH2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_25_24, LCD_DATA12_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_27_26, SSI_WS1_A, SEL_SSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_27_26, VI1_2_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_27_26, LCD_DATA13_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_29_28, SSI_SDATA1_A, SEL_SSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_29_28, VI1_3_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_29_28, LCD_DATA14_B, SEL_LCDC_1),
+
+ /* IPSE10 */
+ PINMUX_IPSR_DATA(IP10_2_0, SSI_SCK23),
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, VI1_4_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, RX1_D, SEL_SCIF1_3),
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, FCLE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, LCD_DATA15_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_DATA(IP10_5_3, SSI_WS23),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, VI1_5_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, TX1_D, SEL_SCIF1_3),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, HSCK0_C, SEL_HSCIF_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, FALE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, LCD_DON_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_DATA(IP10_8_6, SSI_SDATA2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, VI1_6_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, HRX0_C, SEL_HSCIF_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, FRE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, LCD_CL1_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_DATA(IP10_11_9, SSI_SDATA3),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, VI1_7_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, HTX0_C, SEL_HSCIF_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, FWE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, LCD_CL2_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, AUDIO_CLKA_A, SEL_AUDIO_CLKA_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, VI1_CLK_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, SCK1_D, SEL_SCIF1_3),
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, IECLK_B, SEL_IEBUS_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, LCD_FLM_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_15, AUDIO_CLKB_A, SEL_AUDIO_CLKB_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_15, LCD_CLK_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_DATA(IP10_18_16, AUDIO_CLKC),
+ PINMUX_IPSR_MODSEL_DATA(IP10_18_16, SCK1_E, SEL_SCIF1_4),
+ PINMUX_IPSR_MODSEL_DATA(IP10_18_16, HCTS0_C, SEL_HSCIF_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_18_16, FRB_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_18_16, LCD_VEPWC_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_DATA(IP10_21_19, AUDIO_CLKOUT),
+ PINMUX_IPSR_MODSEL_DATA(IP10_21_19, TX1_E, SEL_SCIF1_4),
+ PINMUX_IPSR_MODSEL_DATA(IP10_21_19, HRTS0_C, SEL_HSCIF_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_21_19, FSE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_21_19, LCD_M_DISP_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_22, CAN_CLK_A, SEL_RCAN_CLK_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_22, RX4_D, SEL_SCIF4_3),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_24_23, CAN0_TX_A, SEL_RCAN0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_24_23, TX4_D, SEL_SCIF4_3),
+ PINMUX_IPSR_DATA(IP10_24_23, MLB_CLK),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_25, CAN1_RX_A, SEL_RCAN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_25, IRQ1_B, SEL_INTC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_27_26, CAN0_RX_A, SEL_RCAN0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_27_26, IRQ0_B, SEL_INTC_1),
+ PINMUX_IPSR_DATA(IP10_27_26, MLB_SIG),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_29_28, CAN1_TX_A, SEL_RCAN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_29_28, TX5_C, SEL_SCIF1_2),
+ PINMUX_IPSR_DATA(IP10_29_28, MLB_DAT),
+
+ /* IPSR11 */
+ PINMUX_IPSR_DATA(IP11_0, SCL1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_0, SCIF_CLK_C, SEL_SCIF_CLK_2),
+
+ PINMUX_IPSR_DATA(IP11_1, SDA1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_0, RX1_E, SEL_SCIF1_4),
+
+ PINMUX_IPSR_DATA(IP11_2, SDA0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_2, HIFEBL_A, SEL_HIF_0),
+
+ PINMUX_IPSR_DATA(IP11_3, SDSELF),
+ PINMUX_IPSR_MODSEL_DATA(IP11_3, RTS1_E, SEL_SCIF1_3),
+
+ PINMUX_IPSR_MODSEL_DATA(IP11_6_4, SCIF_CLK_A, SEL_SCIF_CLK_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_6_4, HSPI_CLK_A, SEL_HSPI_0),
+ PINMUX_IPSR_DATA(IP11_6_4, VI0_CLK),
+ PINMUX_IPSR_MODSEL_DATA(IP11_6_4, RMII0_TXD0_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP11_6_4, ET0_ERXD4),
+
+ PINMUX_IPSR_MODSEL_DATA(IP11_9_7, SCK0_A, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_9_7, HSPI_CS_A, SEL_HSPI_0),
+ PINMUX_IPSR_DATA(IP11_9_7, VI0_CLKENB),
+ PINMUX_IPSR_MODSEL_DATA(IP11_9_7, RMII0_TXD1_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP11_9_7, ET0_ERXD5),
+
+ PINMUX_IPSR_MODSEL_DATA(IP11_11_10, RX0_A, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_11_10, HSPI_RX_A, SEL_HSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_11_10, RMII0_RXD0_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP11_11_10, ET0_ERXD6),
+
+ PINMUX_IPSR_MODSEL_DATA(IP11_12, TX0_A, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_12, HSPI_TX_A, SEL_HSPI_0),
+
+ PINMUX_IPSR_DATA(IP11_15_13, PENC1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_13, TX3_D, SEL_SCIF3_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_13, CAN1_TX_B, SEL_RCAN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_13, TX5_D, SEL_SCIF5_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_13, IETX_B, SEL_IEBUS_1),
+
+ PINMUX_IPSR_DATA(IP11_18_16, USB_OVC1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_18_16, RX3_D, SEL_SCIF3_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_18_16, CAN1_RX_B, SEL_RCAN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_18_16, RX5_D, SEL_SCIF5_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_18_16, IERX_B, SEL_IEBUS_1),
+
+ PINMUX_IPSR_DATA(IP11_20_19, DREQ0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_20_19, SD1_CLK_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP11_20_19, ET0_TX_EN),
+
+ PINMUX_IPSR_DATA(IP11_22_21, DACK0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_22_21, SD1_DAT3_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP11_22_21, ET0_TX_ER),
+
+ PINMUX_IPSR_DATA(IP11_25_23, DREQ1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_25_23, HSPI_CLK_B, SEL_HSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_25_23, RX4_B, SEL_SCIF4_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_25_23, ET0_PHY_INT_C, SEL_ET0_CTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_25_23, ET0_TX_CLK_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP11_27_26, DACK1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_27_26, HSPI_CS_B, SEL_HSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_27_26, TX4_B, SEL_SCIF3_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_27_26, ET0_RX_CLK_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP11_28, PRESETOUT),
+ PINMUX_IPSR_DATA(IP11_28, ST_CLKOUT),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ PINMUX_GPIO_GP_ALL(),
+
+ GPIO_FN(CLKOUT), GPIO_FN(BS), GPIO_FN(CS0), GPIO_FN(EX_CS0),
+ GPIO_FN(RD), GPIO_FN(WE0), GPIO_FN(WE1),
+ GPIO_FN(SCL0), GPIO_FN(PENC0), GPIO_FN(USB_OVC0),
+ GPIO_FN(IRQ2_B), GPIO_FN(IRQ3_B),
+
+ /* IPSR0 */
+ GPIO_FN(A0), GPIO_FN(ST0_CLKIN), GPIO_FN(LCD_DATA0_A),
+ GPIO_FN(TCLKA_C),
+ GPIO_FN(A1), GPIO_FN(ST0_REQ), GPIO_FN(LCD_DATA1_A),
+ GPIO_FN(TCLKB_C),
+ GPIO_FN(A2), GPIO_FN(ST0_SYC), GPIO_FN(LCD_DATA2_A),
+ GPIO_FN(TCLKC_C),
+ GPIO_FN(A3), GPIO_FN(ST0_VLD), GPIO_FN(LCD_DATA3_A),
+ GPIO_FN(TCLKD_C),
+ GPIO_FN(A4), GPIO_FN(ST0_D0), GPIO_FN(LCD_DATA4_A),
+ GPIO_FN(TIOC0A_C),
+ GPIO_FN(A5), GPIO_FN(ST0_D1), GPIO_FN(LCD_DATA5_A),
+ GPIO_FN(TIOC0B_C),
+ GPIO_FN(A6), GPIO_FN(ST0_D2), GPIO_FN(LCD_DATA6_A),
+ GPIO_FN(TIOC0C_C),
+ GPIO_FN(A7), GPIO_FN(ST0_D3), GPIO_FN(LCD_DATA7_A),
+ GPIO_FN(TIOC0D_C),
+ GPIO_FN(A8), GPIO_FN(ST0_D4), GPIO_FN(LCD_DATA8_A),
+ GPIO_FN(TIOC1A_C),
+ GPIO_FN(A9), GPIO_FN(ST0_D5), GPIO_FN(LCD_DATA9_A),
+ GPIO_FN(TIOC1B_C),
+ GPIO_FN(A10), GPIO_FN(ST0_D6), GPIO_FN(LCD_DATA10_A),
+ GPIO_FN(TIOC2A_C),
+ GPIO_FN(A11), GPIO_FN(ST0_D7), GPIO_FN(LCD_DATA11_A),
+ GPIO_FN(TIOC2B_C),
+ GPIO_FN(A12), GPIO_FN(LCD_DATA12_A), GPIO_FN(TIOC3A_C),
+ GPIO_FN(A13), GPIO_FN(LCD_DATA13_A), GPIO_FN(TIOC3B_C),
+ GPIO_FN(A14), GPIO_FN(LCD_DATA14_A), GPIO_FN(TIOC3C_C),
+ GPIO_FN(A15), GPIO_FN(ST0_VCO_CLKIN), GPIO_FN(LCD_DATA15_A),
+ GPIO_FN(TIOC3D_C),
+
+ /* IPSR1 */
+ GPIO_FN(A16), GPIO_FN(ST0_PWM), GPIO_FN(LCD_DON_A),
+ GPIO_FN(TIOC4A_C),
+ GPIO_FN(A17), GPIO_FN(ST1_VCO_CLKIN), GPIO_FN(LCD_CL1_A),
+ GPIO_FN(TIOC4B_C),
+ GPIO_FN(A18), GPIO_FN(ST1_PWM), GPIO_FN(LCD_CL2_A),
+ GPIO_FN(TIOC4C_C),
+ GPIO_FN(A19), GPIO_FN(ST1_CLKIN), GPIO_FN(LCD_CLK_A),
+ GPIO_FN(TIOC4D_C),
+ GPIO_FN(A20), GPIO_FN(ST1_REQ), GPIO_FN(LCD_FLM_A),
+ GPIO_FN(A21), GPIO_FN(ST1_SYC), GPIO_FN(LCD_VCPWC_A),
+ GPIO_FN(A22), GPIO_FN(ST1_VLD), GPIO_FN(LCD_VEPWC_A),
+ GPIO_FN(A23), GPIO_FN(ST1_D0), GPIO_FN(LCD_M_DISP_A),
+ GPIO_FN(A24), GPIO_FN(RX2_D), GPIO_FN(ST1_D1),
+ GPIO_FN(A25), GPIO_FN(TX2_D), GPIO_FN(ST1_D2),
+ GPIO_FN(D0), GPIO_FN(SD0_DAT0_A), GPIO_FN(MMC_D0_A),
+ GPIO_FN(ST1_D3), GPIO_FN(FD0_A),
+ GPIO_FN(D1), GPIO_FN(SD0_DAT1_A), GPIO_FN(MMC_D1_A),
+ GPIO_FN(ST1_D4), GPIO_FN(FD1_A),
+ GPIO_FN(D2), GPIO_FN(SD0_DAT2_A), GPIO_FN(MMC_D2_A),
+ GPIO_FN(ST1_D5), GPIO_FN(FD2_A),
+ GPIO_FN(D3), GPIO_FN(SD0_DAT3_A), GPIO_FN(MMC_D3_A),
+ GPIO_FN(ST1_D6), GPIO_FN(FD3_A),
+
+ /* IPSR2 */
+ GPIO_FN(D4), GPIO_FN(SD0_CD_A), GPIO_FN(MMC_D4_A), GPIO_FN(ST1_D7),
+ GPIO_FN(FD4_A),
+ GPIO_FN(D5), GPIO_FN(SD0_WP_A), GPIO_FN(MMC_D5_A), GPIO_FN(FD5_A),
+ GPIO_FN(D6), GPIO_FN(RSPI_RSPCK_A), GPIO_FN(MMC_D6_A),
+ GPIO_FN(QSPCLK_A),
+ GPIO_FN(FD6_A),
+ GPIO_FN(D7), GPIO_FN(RSPI_SSL_A), GPIO_FN(MMC_D7_A), GPIO_FN(QSSL_A),
+ GPIO_FN(FD7_A),
+ GPIO_FN(D8), GPIO_FN(SD0_CLK_A), GPIO_FN(MMC_CLK_A), GPIO_FN(QIO2_A),
+ GPIO_FN(FCE_A), GPIO_FN(ET0_GTX_CLK_B),
+ GPIO_FN(D9), GPIO_FN(SD0_CMD_A), GPIO_FN(MMC_CMD_A), GPIO_FN(QIO3_A),
+ GPIO_FN(FCLE_A), GPIO_FN(ET0_ETXD1_B),
+ GPIO_FN(D10), GPIO_FN(RSPI_MOSI_A), GPIO_FN(QMO_QIO0_A),
+ GPIO_FN(FALE_A), GPIO_FN(ET0_ETXD2_B),
+ GPIO_FN(D11), GPIO_FN(RSPI_MISO_A), GPIO_FN(QMI_QIO1_A), GPIO_FN(FRE_A),
+ GPIO_FN(ET0_ETXD3_B),
+ GPIO_FN(D12), GPIO_FN(FWE_A), GPIO_FN(ET0_ETXD5_B),
+ GPIO_FN(D13), GPIO_FN(RX2_B), GPIO_FN(FRB_A), GPIO_FN(ET0_ETXD6_B),
+ GPIO_FN(D14), GPIO_FN(TX2_B), GPIO_FN(FSE_A), GPIO_FN(ET0_TX_CLK_B),
+
+ /* IPSR3 */
+ GPIO_FN(D15), GPIO_FN(SCK2_B),
+ GPIO_FN(CS1_A26), GPIO_FN(QIO3_B),
+ GPIO_FN(EX_CS1), GPIO_FN(RX3_B), GPIO_FN(ATACS0), GPIO_FN(QIO2_B),
+ GPIO_FN(ET0_ETXD0),
+ GPIO_FN(EX_CS2), GPIO_FN(TX3_B), GPIO_FN(ATACS1), GPIO_FN(QSPCLK_B),
+ GPIO_FN(ET0_GTX_CLK_A),
+ GPIO_FN(EX_CS3), GPIO_FN(SD1_CD_A), GPIO_FN(ATARD), GPIO_FN(QMO_QIO0_B),
+ GPIO_FN(ET0_ETXD1_A),
+ GPIO_FN(EX_CS4), GPIO_FN(SD1_WP_A), GPIO_FN(ATAWR), GPIO_FN(QMI_QIO1_B),
+ GPIO_FN(ET0_ETXD2_A),
+ GPIO_FN(EX_CS5), GPIO_FN(SD1_CMD_A), GPIO_FN(ATADIR), GPIO_FN(QSSL_B),
+ GPIO_FN(ET0_ETXD3_A),
+ GPIO_FN(RD_WR), GPIO_FN(TCLK1_B),
+ GPIO_FN(EX_WAIT0), GPIO_FN(TCLK1_B),
+ GPIO_FN(EX_WAIT1), GPIO_FN(SD1_DAT0_A), GPIO_FN(DREQ2),
+ GPIO_FN(CAN1_TX_C), GPIO_FN(ET0_LINK_C), GPIO_FN(ET0_ETXD5_A),
+ GPIO_FN(EX_WAIT2), GPIO_FN(SD1_DAT1_A), GPIO_FN(DACK2),
+ GPIO_FN(CAN1_RX_C), GPIO_FN(ET0_MAGIC_C), GPIO_FN(ET0_ETXD6_A),
+ GPIO_FN(DRACK0), GPIO_FN(SD1_DAT2_A), GPIO_FN(ATAG), GPIO_FN(TCLK1_A),
+ GPIO_FN(ET0_ETXD7),
+
+ /* IPSR4 */
+ GPIO_FN(HCTS0_A), GPIO_FN(CTS1_A), GPIO_FN(VI0_FIELD),
+ GPIO_FN(RMII0_RXD1_A), GPIO_FN(ET0_ERXD7),
+ GPIO_FN(HRTS0_A), GPIO_FN(RTS1_A), GPIO_FN(VI0_HSYNC),
+ GPIO_FN(RMII0_TXD_EN_A), GPIO_FN(ET0_RX_DV),
+ GPIO_FN(HSCK0_A), GPIO_FN(SCK1_A), GPIO_FN(VI0_VSYNC),
+ GPIO_FN(RMII0_RX_ER_A), GPIO_FN(ET0_RX_ER),
+ GPIO_FN(HRX0_A), GPIO_FN(RX1_A), GPIO_FN(VI0_DATA0_VI0_B0),
+ GPIO_FN(RMII0_CRS_DV_A), GPIO_FN(ET0_CRS),
+ GPIO_FN(HTX0_A), GPIO_FN(TX1_A), GPIO_FN(VI0_DATA1_VI0_B1),
+ GPIO_FN(RMII0_MDC_A), GPIO_FN(ET0_COL),
+ GPIO_FN(CTS0_B), GPIO_FN(VI0_DATA2_VI0_B2), GPIO_FN(RMII0_MDIO_A),
+ GPIO_FN(ET0_MDC),
+ GPIO_FN(RTS0_B), GPIO_FN(VI0_DATA3_VI0_B3), GPIO_FN(ET0_MDIO_A),
+ GPIO_FN(SCK1_B), GPIO_FN(VI0_DATA4_VI0_B4), GPIO_FN(ET0_LINK_A),
+ GPIO_FN(RX1_B), GPIO_FN(VI0_DATA5_VI0_B5), GPIO_FN(ET0_MAGIC_A),
+ GPIO_FN(TX1_B), GPIO_FN(VI0_DATA6_VI0_G0), GPIO_FN(ET0_PHY_INT_A),
+ GPIO_FN(CTS1_B), GPIO_FN(VI0_DATA7_VI0_G1),
+ GPIO_FN(RTS1_B), GPIO_FN(VI0_G2),
+ GPIO_FN(SCK2_A), GPIO_FN(VI0_G3),
+
+ /* IPSR5 */
+ GPIO_FN(REF50CK), GPIO_FN(CTS1_E), GPIO_FN(HCTS0_D),
+ GPIO_FN(REF125CK), GPIO_FN(ADTRG), GPIO_FN(RX5_C),
+ GPIO_FN(SD2_WP_A), GPIO_FN(TX5_A), GPIO_FN(VI0_R5),
+ GPIO_FN(SD2_CD_A), GPIO_FN(RX5_A), GPIO_FN(VI0_R4),
+ GPIO_FN(ET0_PHY_INT_B),
+ GPIO_FN(SD2_DAT3_A), GPIO_FN(TX4_A), GPIO_FN(VI0_R3),
+ GPIO_FN(ET0_MAGIC_B),
+ GPIO_FN(SD2_DAT2_A), GPIO_FN(RX4_A), GPIO_FN(VI0_R2),
+ GPIO_FN(ET0_LINK_B),
+ GPIO_FN(SD2_DAT1_A), GPIO_FN(TX3_A), GPIO_FN(VI0_R1),
+ GPIO_FN(ET0_MDIO_B),
+ GPIO_FN(SD2_DAT0_A), GPIO_FN(RX3_A), GPIO_FN(VI0_R0),
+ GPIO_FN(ET0_ERXD3_B),
+ GPIO_FN(SD2_CMD_A), GPIO_FN(TX2_A), GPIO_FN(VI0_G5),
+ GPIO_FN(ET0_ERXD2_B),
+ GPIO_FN(SD2_CLK_A), GPIO_FN(RX2_A), GPIO_FN(VI0_G4),
+ GPIO_FN(ET0_RX_CLK_B),
+
+ /* IPSR6 */
+ GPIO_FN(DU0_DG1), GPIO_FN(CTS1_C), GPIO_FN(HRTS0_D),
+ GPIO_FN(TIOC1B_A), GPIO_FN(HIFD09),
+ GPIO_FN(DU0_DG0), GPIO_FN(TX1_C), GPIO_FN(HSCK0_D),
+ GPIO_FN(IECLK_A), GPIO_FN(TIOC1A_A), GPIO_FN(HIFD08),
+ GPIO_FN(DU0_DR7), GPIO_FN(RX1_C), GPIO_FN(TIOC0D_A),
+ GPIO_FN(HIFD07),
+ GPIO_FN(DU0_DR6), GPIO_FN(SCK1_C), GPIO_FN(TIOC0C_A),
+ GPIO_FN(HIFD06),
+ GPIO_FN(DU0_DR5), GPIO_FN(RTS0_C), GPIO_FN(TIOC0B_A),
+ GPIO_FN(HIFD05),
+ GPIO_FN(DU0_DR4), GPIO_FN(CTS0_C), GPIO_FN(TIOC0A_A),
+ GPIO_FN(HIFD04),
+ GPIO_FN(DU0_DR3), GPIO_FN(TX0_B), GPIO_FN(TCLKD_A), GPIO_FN(HIFD03),
+ GPIO_FN(DU0_DR2), GPIO_FN(RX0_B), GPIO_FN(TCLKC_A), GPIO_FN(HIFD02),
+ GPIO_FN(DU0_DR1), GPIO_FN(SCK0_B), GPIO_FN(HTX0_D),
+ GPIO_FN(IERX_A), GPIO_FN(TCLKB_A), GPIO_FN(HIFD01),
+ GPIO_FN(DU0_DR0), GPIO_FN(SCIF_CLK_B), GPIO_FN(HRX0_D),
+ GPIO_FN(IETX_A), GPIO_FN(TCLKA_A), GPIO_FN(HIFD00),
+
+ /* IPSR7 */
+ GPIO_FN(DU0_DB4), GPIO_FN(HIFINT),
+ GPIO_FN(DU0_DB3), GPIO_FN(TX5_B), GPIO_FN(TIOC4D_A), GPIO_FN(HIFRD),
+ GPIO_FN(DU0_DB2), GPIO_FN(RX5_B), GPIO_FN(RMII0_TXD1_B),
+ GPIO_FN(TIOC4C_A), GPIO_FN(HIFWR),
+ GPIO_FN(DU0_DB1), GPIO_FN(TX4_C), GPIO_FN(RMII0_TXD0_B),
+ GPIO_FN(TIOC4B_A), GPIO_FN(HIFRS),
+ GPIO_FN(DU0_DB0), GPIO_FN(RX4_C), GPIO_FN(RMII0_TXD_EN_B),
+ GPIO_FN(TIOC4A_A), GPIO_FN(HIFCS),
+ GPIO_FN(DU0_DG7), GPIO_FN(TX3_C), GPIO_FN(RMII0_RXD1_B),
+ GPIO_FN(TIOC3D_A), GPIO_FN(HIFD15),
+ GPIO_FN(DU0_DG6), GPIO_FN(RX3_C), GPIO_FN(RMII0_RXD0_B),
+ GPIO_FN(TIOC3C_A), GPIO_FN(HIFD14),
+ GPIO_FN(DU0_DG5), GPIO_FN(TX2_C), GPIO_FN(RMII0_RX_ER_B),
+ GPIO_FN(TIOC3B_A), GPIO_FN(HIFD13),
+ GPIO_FN(DU0_DG4), GPIO_FN(RX2_C), GPIO_FN(RMII0_CRS_DV_B),
+ GPIO_FN(TIOC3A_A), GPIO_FN(HIFD12),
+ GPIO_FN(DU0_DG3), GPIO_FN(SCK2_C), GPIO_FN(RMII0_MDIO_B),
+ GPIO_FN(TIOC2B_A), GPIO_FN(HIFD11),
+ GPIO_FN(DU0_DG2), GPIO_FN(RTS1_C), GPIO_FN(RMII0_MDC_B),
+ GPIO_FN(TIOC2A_A), GPIO_FN(HIFD10),
+
+ /* IPSR8 */
+ GPIO_FN(IRQ3_A), GPIO_FN(RTS0_A), GPIO_FN(HRTS0_B),
+ GPIO_FN(ET0_ERXD3_A),
+ GPIO_FN(IRQ2_A), GPIO_FN(CTS0_A), GPIO_FN(HCTS0_B),
+ GPIO_FN(ET0_ERXD2_A),
+ GPIO_FN(IRQ1_A), GPIO_FN(HSPI_RX_B), GPIO_FN(TX3_E),
+ GPIO_FN(ET0_ERXD1),
+ GPIO_FN(IRQ0_A), GPIO_FN(HSPI_TX_B), GPIO_FN(RX3_E),
+ GPIO_FN(ET0_ERXD0),
+ GPIO_FN(DU0_CDE), GPIO_FN(HTX0_B), GPIO_FN(AUDIO_CLKB_B),
+ GPIO_FN(LCD_VCPWC_B),
+ GPIO_FN(DU0_DISP), GPIO_FN(CAN0_TX_B), GPIO_FN(HRX0_B),
+ GPIO_FN(AUDIO_CLKA_B),
+ GPIO_FN(DU0_EXODDF_DU0_ODDF), GPIO_FN(CAN0_RX_B), GPIO_FN(HSCK0_B),
+ GPIO_FN(SSI_SDATA1_B),
+ GPIO_FN(DU0_EXVSYNC_DU0_VSYNC), GPIO_FN(HSPI_RX0_C),
+ GPIO_FN(SSI_WS1_B),
+ GPIO_FN(DU0_EXHSYNC_DU0_HSYNC), GPIO_FN(HSPI_TX0_C),
+ GPIO_FN(SSI_SCK1_B),
+ GPIO_FN(DU0_DOTCLKOUT), GPIO_FN(HSPI_CLK0_C),
+ GPIO_FN(SSI_SDATA0_B),
+ GPIO_FN(DU0_DOTCLKIN), GPIO_FN(HSPI_CS0_C),
+ GPIO_FN(SSI_WS0_B),
+ GPIO_FN(DU0_DB7), GPIO_FN(SSI_SCK0_B), GPIO_FN(HIFEBL_B),
+ GPIO_FN(DU0_DB6), GPIO_FN(HIFRDY),
+ GPIO_FN(DU0_DB5), GPIO_FN(HIFDREQ),
+
+ /* IPSR9 */
+ GPIO_FN(SSI_SDATA1_A), GPIO_FN(VI1_3_B), GPIO_FN(LCD_DATA14_B),
+ GPIO_FN(SSI_WS1_A), GPIO_FN(VI1_2_B), GPIO_FN(LCD_DATA13_B),
+ GPIO_FN(SSI_SCK1_A), GPIO_FN(VI1_1_B), GPIO_FN(TIOC2B_B),
+ GPIO_FN(LCD_DATA12_B),
+ GPIO_FN(SSI_SDATA0_A), GPIO_FN(VI1_0_B), GPIO_FN(TIOC2A_B),
+ GPIO_FN(LCD_DATA11_B),
+ GPIO_FN(SSI_WS0_A), GPIO_FN(TIOC1B_B), GPIO_FN(LCD_DATA10_B),
+ GPIO_FN(SSI_SCK0_A), GPIO_FN(TIOC1A_B), GPIO_FN(LCD_DATA9_B),
+ GPIO_FN(VI1_7_A), GPIO_FN(FCE_B), GPIO_FN(LCD_DATA8_B),
+ GPIO_FN(VI1_6_A), GPIO_FN(FD7_B), GPIO_FN(LCD_DATA7_B),
+ GPIO_FN(VI1_5_A), GPIO_FN(FD6_B), GPIO_FN(LCD_DATA6_B),
+ GPIO_FN(VI1_4_A), GPIO_FN(FD5_B), GPIO_FN(LCD_DATA5_B),
+ GPIO_FN(VI1_3_A), GPIO_FN(FD4_B), GPIO_FN(LCD_DATA4_B),
+ GPIO_FN(VI1_2_A), GPIO_FN(FD3_B), GPIO_FN(LCD_DATA3_B),
+ GPIO_FN(VI1_1_A), GPIO_FN(FD2_B), GPIO_FN(LCD_DATA2_B),
+ GPIO_FN(VI1_0_A), GPIO_FN(FD1_B), GPIO_FN(LCD_DATA1_B),
+ GPIO_FN(VI1_CLK_A), GPIO_FN(FD0_B), GPIO_FN(LCD_DATA0_B),
+
+ /* IPSR10 */
+ GPIO_FN(CAN1_TX_A), GPIO_FN(TX5_C), GPIO_FN(MLB_DAT),
+ GPIO_FN(CAN0_RX_A), GPIO_FN(IRQ0_B), GPIO_FN(MLB_SIG),
+ GPIO_FN(CAN1_RX_A), GPIO_FN(IRQ1_B),
+ GPIO_FN(CAN0_TX_A), GPIO_FN(TX4_D), GPIO_FN(MLB_CLK),
+ GPIO_FN(CAN_CLK_A), GPIO_FN(RX4_D),
+ GPIO_FN(AUDIO_CLKOUT), GPIO_FN(TX1_E), GPIO_FN(HRTS0_C),
+ GPIO_FN(FSE_B), GPIO_FN(LCD_M_DISP_B),
+ GPIO_FN(AUDIO_CLKC), GPIO_FN(SCK1_E), GPIO_FN(HCTS0_C),
+ GPIO_FN(FRB_B), GPIO_FN(LCD_VEPWC_B),
+ GPIO_FN(AUDIO_CLKB_A), GPIO_FN(LCD_CLK_B),
+ GPIO_FN(AUDIO_CLKA_A), GPIO_FN(VI1_CLK_B), GPIO_FN(SCK1_D),
+ GPIO_FN(IECLK_B), GPIO_FN(LCD_FLM_B),
+ GPIO_FN(SSI_SDATA3), GPIO_FN(VI1_7_B), GPIO_FN(HTX0_C),
+ GPIO_FN(FWE_B), GPIO_FN(LCD_CL2_B),
+ GPIO_FN(SSI_SDATA2), GPIO_FN(VI1_6_B), GPIO_FN(HRX0_C),
+ GPIO_FN(FRE_B), GPIO_FN(LCD_CL1_B),
+ GPIO_FN(SSI_WS23), GPIO_FN(VI1_5_B), GPIO_FN(TX1_D),
+ GPIO_FN(HSCK0_C), GPIO_FN(FALE_B), GPIO_FN(LCD_DON_B),
+ GPIO_FN(SSI_SCK23), GPIO_FN(VI1_4_B), GPIO_FN(RX1_D),
+ GPIO_FN(FCLE_B), GPIO_FN(LCD_DATA15_B),
+
+ /* IPSR11 */
+ GPIO_FN(PRESETOUT), GPIO_FN(ST_CLKOUT),
+ GPIO_FN(DACK1), GPIO_FN(HSPI_CS_B), GPIO_FN(TX4_B),
+ GPIO_FN(ET0_RX_CLK_A),
+ GPIO_FN(DREQ1), GPIO_FN(HSPI_CLK_B), GPIO_FN(RX4_B),
+ GPIO_FN(ET0_PHY_INT_C), GPIO_FN(ET0_TX_CLK_A),
+ GPIO_FN(DACK0), GPIO_FN(SD1_DAT3_A), GPIO_FN(ET0_TX_ER),
+ GPIO_FN(DREQ0), GPIO_FN(SD1_CLK_A), GPIO_FN(ET0_TX_EN),
+ GPIO_FN(USB_OVC1), GPIO_FN(RX3_D), GPIO_FN(CAN1_RX_B),
+ GPIO_FN(RX5_D), GPIO_FN(IERX_B),
+ GPIO_FN(PENC1), GPIO_FN(TX3_D), GPIO_FN(CAN1_TX_B),
+ GPIO_FN(TX5_D), GPIO_FN(IETX_B),
+ GPIO_FN(TX0_A), GPIO_FN(HSPI_TX_A),
+ GPIO_FN(RX0_A), GPIO_FN(HSPI_RX_A), GPIO_FN(RMII0_RXD0_A),
+ GPIO_FN(ET0_ERXD6),
+ GPIO_FN(SCK0_A), GPIO_FN(HSPI_CS_A), GPIO_FN(VI0_CLKENB),
+ GPIO_FN(RMII0_TXD1_A), GPIO_FN(ET0_ERXD5),
+ GPIO_FN(SCIF_CLK_A), GPIO_FN(HSPI_CLK_A), GPIO_FN(VI0_CLK),
+ GPIO_FN(RMII0_TXD0_A), GPIO_FN(ET0_ERXD4),
+ GPIO_FN(SDSELF), GPIO_FN(RTS1_E),
+ GPIO_FN(SDA0), GPIO_FN(HIFEBL_A),
+ GPIO_FN(SDA1), GPIO_FN(RX1_E),
+ GPIO_FN(SCL1), GPIO_FN(SCIF_CLK_C),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("GPSR0", 0xFFFC0004, 32, 1) {
+ GP_0_31_FN, FN_IP2_2_0,
+ GP_0_30_FN, FN_IP1_31_29,
+ GP_0_29_FN, FN_IP1_28_26,
+ GP_0_28_FN, FN_IP1_25_23,
+ GP_0_27_FN, FN_IP1_22_20,
+ GP_0_26_FN, FN_IP1_19_18,
+ GP_0_25_FN, FN_IP1_17_16,
+ GP_0_24_FN, FN_IP0_5_4,
+ GP_0_23_FN, FN_IP0_3_2,
+ GP_0_22_FN, FN_IP0_1_0,
+ GP_0_21_FN, FN_IP11_28,
+ GP_0_20_FN, FN_IP1_7_6,
+ GP_0_19_FN, FN_IP1_5_4,
+ GP_0_18_FN, FN_IP1_3_2,
+ GP_0_17_FN, FN_IP1_1_0,
+ GP_0_16_FN, FN_IP0_31_30,
+ GP_0_15_FN, FN_IP0_29_28,
+ GP_0_14_FN, FN_IP0_27_26,
+ GP_0_13_FN, FN_IP0_25_24,
+ GP_0_12_FN, FN_IP0_23_22,
+ GP_0_11_FN, FN_IP0_21_20,
+ GP_0_10_FN, FN_IP0_19_18,
+ GP_0_9_FN, FN_IP0_17_16,
+ GP_0_8_FN, FN_IP0_15_14,
+ GP_0_7_FN, FN_IP0_13_12,
+ GP_0_6_FN, FN_IP0_11_10,
+ GP_0_5_FN, FN_IP0_9_8,
+ GP_0_4_FN, FN_IP0_7_6,
+ GP_0_3_FN, FN_IP1_15_14,
+ GP_0_2_FN, FN_IP1_13_12,
+ GP_0_1_FN, FN_IP1_11_10,
+ GP_0_0_FN, FN_IP1_9_8 }
+ },
+ { PINMUX_CFG_REG("GPSR1", 0xFFFC0008, 32, 1) {
+ GP_1_31_FN, FN_IP11_25_23,
+ GP_1_30_FN, FN_IP2_13_11,
+ GP_1_29_FN, FN_IP2_10_8,
+ GP_1_28_FN, FN_IP2_7_5,
+ GP_1_27_FN, FN_IP3_26_24,
+ GP_1_26_FN, FN_IP3_23_21,
+ GP_1_25_FN, FN_IP2_4_3,
+ GP_1_24_FN, FN_WE1,
+ GP_1_23_FN, FN_WE0,
+ GP_1_22_FN, FN_IP3_19_18,
+ GP_1_21_FN, FN_RD,
+ GP_1_20_FN, FN_IP3_17_15,
+ GP_1_19_FN, FN_IP3_14_12,
+ GP_1_18_FN, FN_IP3_11_9,
+ GP_1_17_FN, FN_IP3_8_6,
+ GP_1_16_FN, FN_IP3_5_3,
+ GP_1_15_FN, FN_EX_CS0,
+ GP_1_14_FN, FN_IP3_2,
+ GP_1_13_FN, FN_CS0,
+ GP_1_12_FN, FN_BS,
+ GP_1_11_FN, FN_CLKOUT,
+ GP_1_10_FN, FN_IP3_1_0,
+ GP_1_9_FN, FN_IP2_30_28,
+ GP_1_8_FN, FN_IP2_27_25,
+ GP_1_7_FN, FN_IP2_24_23,
+ GP_1_6_FN, FN_IP2_22_20,
+ GP_1_5_FN, FN_IP2_19_17,
+ GP_1_4_FN, FN_IP2_16_14,
+ GP_1_3_FN, FN_IP11_22_21,
+ GP_1_2_FN, FN_IP11_20_19,
+ GP_1_1_FN, FN_IP3_29_27,
+ GP_1_0_FN, FN_IP3_20 }
+ },
+ { PINMUX_CFG_REG("GPSR2", 0xFFFC000C, 32, 1) {
+ GP_2_31_FN, FN_IP4_31_30,
+ GP_2_30_FN, FN_IP5_2_0,
+ GP_2_29_FN, FN_IP5_5_3,
+ GP_2_28_FN, FN_IP5_8_6,
+ GP_2_27_FN, FN_IP5_11_9,
+ GP_2_26_FN, FN_IP5_14_12,
+ GP_2_25_FN, FN_IP5_17_15,
+ GP_2_24_FN, FN_IP5_20_18,
+ GP_2_23_FN, FN_IP5_22_21,
+ GP_2_22_FN, FN_IP5_24_23,
+ GP_2_21_FN, FN_IP5_26_25,
+ GP_2_20_FN, FN_IP4_29_28,
+ GP_2_19_FN, FN_IP4_27_26,
+ GP_2_18_FN, FN_IP4_25_24,
+ GP_2_17_FN, FN_IP4_23_22,
+ GP_2_16_FN, FN_IP4_21_20,
+ GP_2_15_FN, FN_IP4_19_18,
+ GP_2_14_FN, FN_IP4_17_15,
+ GP_2_13_FN, FN_IP4_14_12,
+ GP_2_12_FN, FN_IP4_11_9,
+ GP_2_11_FN, FN_IP4_8_6,
+ GP_2_10_FN, FN_IP4_5_3,
+ GP_2_9_FN, FN_IP8_27_26,
+ GP_2_8_FN, FN_IP11_12,
+ GP_2_7_FN, FN_IP8_25_23,
+ GP_2_6_FN, FN_IP8_22_20,
+ GP_2_5_FN, FN_IP11_27_26,
+ GP_2_4_FN, FN_IP8_29_28,
+ GP_2_3_FN, FN_IP4_2_0,
+ GP_2_2_FN, FN_IP11_11_10,
+ GP_2_1_FN, FN_IP11_9_7,
+ GP_2_0_FN, FN_IP11_6_4 }
+ },
+ { PINMUX_CFG_REG("GPSR3", 0xFFFC0010, 32, 1) {
+ GP_3_31_FN, FN_IP9_1_0,
+ GP_3_30_FN, FN_IP8_19_18,
+ GP_3_29_FN, FN_IP8_17_16,
+ GP_3_28_FN, FN_IP8_15_14,
+ GP_3_27_FN, FN_IP8_13_12,
+ GP_3_26_FN, FN_IP8_11_10,
+ GP_3_25_FN, FN_IP8_9_8,
+ GP_3_24_FN, FN_IP8_7_6,
+ GP_3_23_FN, FN_IP8_5_4,
+ GP_3_22_FN, FN_IP8_3_2,
+ GP_3_21_FN, FN_IP8_1_0,
+ GP_3_20_FN, FN_IP7_30_29,
+ GP_3_19_FN, FN_IP7_28_27,
+ GP_3_18_FN, FN_IP7_26_24,
+ GP_3_17_FN, FN_IP7_23_21,
+ GP_3_16_FN, FN_IP7_20_18,
+ GP_3_15_FN, FN_IP7_17_15,
+ GP_3_14_FN, FN_IP7_14_12,
+ GP_3_13_FN, FN_IP7_11_9,
+ GP_3_12_FN, FN_IP7_8_6,
+ GP_3_11_FN, FN_IP7_5_3,
+ GP_3_10_FN, FN_IP7_2_0,
+ GP_3_9_FN, FN_IP6_23_21,
+ GP_3_8_FN, FN_IP6_20_18,
+ GP_3_7_FN, FN_IP6_17_16,
+ GP_3_6_FN, FN_IP6_15_14,
+ GP_3_5_FN, FN_IP6_13_12,
+ GP_3_4_FN, FN_IP6_11_10,
+ GP_3_3_FN, FN_IP6_9_8,
+ GP_3_2_FN, FN_IP6_7_6,
+ GP_3_1_FN, FN_IP6_5_3,
+ GP_3_0_FN, FN_IP6_2_0 }
+ },
+
+ { PINMUX_CFG_REG("GPSR4", 0xFFFC0014, 32, 1) {
+ GP_4_31_FN, FN_IP10_24_23,
+ GP_4_30_FN, FN_IP10_22,
+ GP_4_29_FN, FN_IP11_18_16,
+ GP_4_28_FN, FN_USB_OVC0,
+ GP_4_27_FN, FN_IP11_15_13,
+ GP_4_26_FN, FN_PENC0,
+ GP_4_25_FN, FN_IP11_2,
+ GP_4_24_FN, FN_SCL0,
+ GP_4_23_FN, FN_IP11_1,
+ GP_4_22_FN, FN_IP11_0,
+ GP_4_21_FN, FN_IP10_21_19,
+ GP_4_20_FN, FN_IP10_18_16,
+ GP_4_19_FN, FN_IP10_15,
+ GP_4_18_FN, FN_IP10_14_12,
+ GP_4_17_FN, FN_IP10_11_9,
+ GP_4_16_FN, FN_IP10_8_6,
+ GP_4_15_FN, FN_IP10_5_3,
+ GP_4_14_FN, FN_IP10_2_0,
+ GP_4_13_FN, FN_IP9_29_28,
+ GP_4_12_FN, FN_IP9_27_26,
+ GP_4_11_FN, FN_IP9_9_8,
+ GP_4_10_FN, FN_IP9_7_6,
+ GP_4_9_FN, FN_IP9_5_4,
+ GP_4_8_FN, FN_IP9_3_2,
+ GP_4_7_FN, FN_IP9_17_16,
+ GP_4_6_FN, FN_IP9_15_14,
+ GP_4_5_FN, FN_IP9_13_12,
+ GP_4_4_FN, FN_IP9_11_10,
+ GP_4_3_FN, FN_IP9_25_24,
+ GP_4_2_FN, FN_IP9_23_22,
+ GP_4_1_FN, FN_IP9_21_20,
+ GP_4_0_FN, FN_IP9_19_18 }
+ },
+ { PINMUX_CFG_REG("GPSR5", 0xFFFC0018, 32, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 31 - 28 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 27 - 24 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 23 - 20 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 19 - 16 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 15 - 12 */
+ GP_5_11_FN, FN_IP10_29_28,
+ GP_5_10_FN, FN_IP10_27_26,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 9 - 6 */
+ 0, 0, 0, 0, /* 5, 4 */
+ GP_5_3_FN, FN_IRQ3_B,
+ GP_5_2_FN, FN_IRQ2_B,
+ GP_5_1_FN, FN_IP11_3,
+ GP_5_0_FN, FN_IP10_25 }
+ },
+
+ { PINMUX_CFG_REG_VAR("IPSR0", 0xFFFC001C, 32,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2) {
+ /* IP0_31_30 [2] */
+ FN_A15, FN_ST0_VCO_CLKIN, FN_LCD_DATA15_A,
+ FN_TIOC3D_C,
+ /* IP0_29_28 [2] */
+ FN_A14, FN_LCD_DATA14_A, FN_TIOC3C_C, 0,
+ /* IP0_27_26 [2] */
+ FN_A13, FN_LCD_DATA13_A, FN_TIOC3B_C, 0,
+ /* IP0_25_24 [2] */
+ FN_A12, FN_LCD_DATA12_A, FN_TIOC3A_C, 0,
+ /* IP0_23_22 [2] */
+ FN_A11, FN_ST0_D7, FN_LCD_DATA11_A, FN_TIOC2B_C,
+ /* IP0_21_20 [2] */
+ FN_A10, FN_ST0_D6, FN_LCD_DATA10_A, FN_TIOC2A_C,
+ /* IP0_19_18 [2] */
+ FN_A9, FN_ST0_D5, FN_LCD_DATA9_A, FN_TIOC1B_C,
+ /* IP0_17_16 [2] */
+ FN_A8, FN_ST0_D4, FN_LCD_DATA8_A, FN_TIOC1A_C,
+ /* IP0_15_14 [2] */
+ FN_A7, FN_ST0_D3, FN_LCD_DATA7_A, FN_TIOC0D_C,
+ /* IP0_13_12 [2] */
+ FN_A6, FN_ST0_D2, FN_LCD_DATA6_A, FN_TIOC0C_C,
+ /* IP0_11_10 [2] */
+ FN_A5, FN_ST0_D1, FN_LCD_DATA5_A, FN_TIOC0B_C,
+ /* IP0_9_8 [2] */
+ FN_A4, FN_ST0_D0, FN_LCD_DATA4_A, FN_TIOC0A_C,
+ /* IP0_7_6 [2] */
+ FN_A3, FN_ST0_VLD, FN_LCD_DATA3_A, FN_TCLKD_C,
+ /* IP0_5_4 [2] */
+ FN_A2, FN_ST0_SYC, FN_LCD_DATA2_A, FN_TCLKC_C,
+ /* IP0_3_2 [2] */
+ FN_A1, FN_ST0_REQ, FN_LCD_DATA1_A, FN_TCLKB_C,
+ /* IP0_1_0 [2] */
+ FN_A0, FN_ST0_CLKIN, FN_LCD_DATA0_A, FN_TCLKA_C }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR1", 0xFFFC0020, 32,
+ 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
+ /* IP1_31_29 [3] */
+ FN_D3, FN_SD0_DAT3_A, FN_MMC_D3_A, FN_ST1_D6,
+ FN_FD3_A, 0, 0, 0,
+ /* IP1_28_26 [3] */
+ FN_D2, FN_SD0_DAT2_A, FN_MMC_D2_A, FN_ST1_D5,
+ FN_FD2_A, 0, 0, 0,
+ /* IP1_25_23 [3] */
+ FN_D1, FN_SD0_DAT1_A, FN_MMC_D1_A, FN_ST1_D4,
+ FN_FD1_A, 0, 0, 0,
+ /* IP1_22_20 [3] */
+ FN_D0, FN_SD0_DAT0_A, FN_MMC_D0_A, FN_ST1_D3,
+ FN_FD0_A, 0, 0, 0,
+ /* IP1_19_18 [2] */
+ FN_A25, FN_TX2_D, FN_ST1_D2, 0,
+ /* IP1_17_16 [2] */
+ FN_A24, FN_RX2_D, FN_ST1_D1, 0,
+ /* IP1_15_14 [2] */
+ FN_A23, FN_ST1_D0, FN_LCD_M_DISP_A, 0,
+ /* IP1_13_12 [2] */
+ FN_A22, FN_ST1_VLD, FN_LCD_VEPWC_A, 0,
+ /* IP1_11_10 [2] */
+ FN_A21, FN_ST1_SYC, FN_LCD_VCPWC_A, 0,
+ /* IP1_9_8 [2] */
+ FN_A20, FN_ST1_REQ, FN_LCD_FLM_A, 0,
+ /* IP1_7_6 [2] */
+ FN_A19, FN_ST1_CLKIN, FN_LCD_CLK_A, FN_TIOC4D_C,
+ /* IP1_5_4 [2] */
+ FN_A18, FN_ST1_PWM, FN_LCD_CL2_A, FN_TIOC4C_C,
+ /* IP1_3_2 [2] */
+ FN_A17, FN_ST1_VCO_CLKIN, FN_LCD_CL1_A, FN_TIOC4B_C,
+ /* IP1_1_0 [2] */
+ FN_A16, FN_ST0_PWM, FN_LCD_DON_A, FN_TIOC4A_C }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR2", 0xFFFC0024, 32,
+ 1, 3, 3, 2, 3, 3, 3, 3, 3, 3, 2, 3) {
+ /* IP2_31 [1] */
+ 0, 0,
+ /* IP2_30_28 [3] */
+ FN_D14, FN_TX2_B, 0, FN_FSE_A,
+ FN_ET0_TX_CLK_B, 0, 0, 0,
+ /* IP2_27_25 [3] */
+ FN_D13, FN_RX2_B, 0, FN_FRB_A,
+ FN_ET0_ETXD6_B, 0, 0, 0,
+ /* IP2_24_23 [2] */
+ FN_D12, 0, FN_FWE_A, FN_ET0_ETXD5_B,
+ /* IP2_22_20 [3] */
+ FN_D11, FN_RSPI_MISO_A, 0, FN_QMI_QIO1_A,
+ FN_FRE_A, FN_ET0_ETXD3_B, 0, 0,
+ /* IP2_19_17 [3] */
+ FN_D10, FN_RSPI_MOSI_A, 0, FN_QMO_QIO0_A,
+ FN_FALE_A, FN_ET0_ETXD2_B, 0, 0,
+ /* IP2_16_14 [3] */
+ FN_D9, FN_SD0_CMD_A, FN_MMC_CMD_A, FN_QIO3_A,
+ FN_FCLE_A, FN_ET0_ETXD1_B, 0, 0,
+ /* IP2_13_11 [3] */
+ FN_D8, FN_SD0_CLK_A, FN_MMC_CLK_A, FN_QIO2_A,
+ FN_FCE_A, FN_ET0_GTX_CLK_B, 0, 0,
+ /* IP2_10_8 [3] */
+ FN_D7, FN_RSPI_SSL_A, FN_MMC_D7_A, FN_QSSL_A,
+ FN_FD7_A, 0, 0, 0,
+ /* IP2_7_5 [3] */
+ FN_D6, FN_RSPI_RSPCK_A, FN_MMC_D6_A, FN_QSPCLK_A,
+ FN_FD6_A, 0, 0, 0,
+ /* IP2_4_3 [2] */
+ FN_D5, FN_SD0_WP_A, FN_MMC_D5_A, FN_FD5_A,
+ /* IP2_2_0 [3] */
+ FN_D4, FN_SD0_CD_A, FN_MMC_D4_A, FN_ST1_D7,
+ FN_FD4_A, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR3", 0xFFFC0028, 32,
+ 2, 3, 3, 3, 1, 2, 3, 3, 3, 3, 3, 1, 2) {
+ /* IP3_31_30 [2] */
+ 0, 0, 0, 0,
+ /* IP3_29_27 [3] */
+ FN_DRACK0, FN_SD1_DAT2_A, FN_ATAG, FN_TCLK1_A,
+ FN_ET0_ETXD7, 0, 0, 0,
+ /* IP3_26_24 [3] */
+ FN_EX_WAIT2, FN_SD1_DAT1_A, FN_DACK2, FN_CAN1_RX_C,
+ FN_ET0_MAGIC_C, FN_ET0_ETXD6_A, 0, 0,
+ /* IP3_23_21 [3] */
+ FN_EX_WAIT1, FN_SD1_DAT0_A, FN_DREQ2, FN_CAN1_TX_C,
+ FN_ET0_LINK_C, FN_ET0_ETXD5_A, 0, 0,
+ /* IP3_20 [1] */
+ FN_EX_WAIT0, FN_TCLK1_B,
+ /* IP3_19_18 [2] */
+ FN_RD_WR, FN_TCLK1_B, 0, 0,
+ /* IP3_17_15 [3] */
+ FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B,
+ FN_ET0_ETXD3_A, 0, 0, 0,
+ /* IP3_14_12 [3] */
+ FN_EX_CS4, FN_SD1_WP_A, FN_ATAWR, FN_QMI_QIO1_B,
+ FN_ET0_ETXD2_A, 0, 0, 0,
+ /* IP3_11_9 [3] */
+ FN_EX_CS3, FN_SD1_CD_A, FN_ATARD, FN_QMO_QIO0_B,
+ FN_ET0_ETXD1_A, 0, 0, 0,
+ /* IP3_8_6 [3] */
+ FN_EX_CS2, FN_TX3_B, FN_ATACS1, FN_QSPCLK_B,
+ FN_ET0_GTX_CLK_A, 0, 0, 0,
+ /* IP3_5_3 [3] */
+ FN_EX_CS1, FN_RX3_B, FN_ATACS0, FN_QIO2_B,
+ FN_ET0_ETXD0, 0, 0, 0,
+ /* IP3_2 [1] */
+ FN_CS1_A26, FN_QIO3_B,
+ /* IP3_1_0 [2] */
+ FN_D15, FN_SCK2_B, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR4", 0xFFFC002C, 32,
+ 2, 2, 2, 2, 2, 2 , 2, 3, 3, 3, 3, 3, 3) {
+ /* IP4_31_30 [2] */
+ 0, FN_SCK2_A, FN_VI0_G3, 0,
+ /* IP4_29_28 [2] */
+ 0, FN_RTS1_B, FN_VI0_G2, 0,
+ /* IP4_27_26 [2] */
+ 0, FN_CTS1_B, FN_VI0_DATA7_VI0_G1, 0,
+ /* IP4_25_24 [2] */
+ 0, FN_TX1_B, FN_VI0_DATA6_VI0_G0, FN_ET0_PHY_INT_A,
+ /* IP4_23_22 [2] */
+ 0, FN_RX1_B, FN_VI0_DATA5_VI0_B5, FN_ET0_MAGIC_A,
+ /* IP4_21_20 [2] */
+ 0, FN_SCK1_B, FN_VI0_DATA4_VI0_B4, FN_ET0_LINK_A,
+ /* IP4_19_18 [2] */
+ 0, FN_RTS0_B, FN_VI0_DATA3_VI0_B3, FN_ET0_MDIO_A,
+ /* IP4_17_15 [3] */
+ 0, FN_CTS0_B, FN_VI0_DATA2_VI0_B2, FN_RMII0_MDIO_A,
+ FN_ET0_MDC, 0, 0, 0,
+ /* IP4_14_12 [3] */
+ FN_HTX0_A, FN_TX1_A, FN_VI0_DATA1_VI0_B1, FN_RMII0_MDC_A,
+ FN_ET0_COL, 0, 0, 0,
+ /* IP4_11_9 [3] */
+ FN_HRX0_A, FN_RX1_A, FN_VI0_DATA0_VI0_B0, FN_RMII0_CRS_DV_A,
+ FN_ET0_CRS, 0, 0, 0,
+ /* IP4_8_6 [3] */
+ FN_HSCK0_A, FN_SCK1_A, FN_VI0_VSYNC, FN_RMII0_RX_ER_A,
+ FN_ET0_RX_ER, 0, 0, 0,
+ /* IP4_5_3 [3] */
+ FN_HRTS0_A, FN_RTS1_A, FN_VI0_HSYNC, FN_RMII0_TXD_EN_A,
+ FN_ET0_RX_DV, 0, 0, 0,
+ /* IP4_2_0 [3] */
+ FN_HCTS0_A, FN_CTS1_A, FN_VI0_FIELD, FN_RMII0_RXD1_A,
+ FN_ET0_ERXD7, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR5", 0xFFFC0030, 32,
+ 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3) {
+ /* IP5_31 [1] */
+ 0, 0,
+ /* IP5_30 [1] */
+ 0, 0,
+ /* IP5_29 [1] */
+ 0, 0,
+ /* IP5_28 [1] */
+ 0, 0,
+ /* IP5_27 [1] */
+ 0, 0,
+ /* IP5_26_25 [2] */
+ FN_REF50CK, FN_CTS1_E, FN_HCTS0_D, 0,
+ /* IP5_24_23 [2] */
+ FN_REF125CK, FN_ADTRG, FN_RX5_C, 0,
+ /* IP5_22_21 [2] */
+ FN_SD2_WP_A, FN_TX5_A, FN_VI0_R5, 0,
+ /* IP5_20_18 [3] */
+ FN_SD2_CD_A, FN_RX5_A, FN_VI0_R4, 0,
+ 0, 0, 0, FN_ET0_PHY_INT_B,
+ /* IP5_17_15 [3] */
+ FN_SD2_DAT3_A, FN_TX4_A, FN_VI0_R3, 0,
+ 0, 0, 0, FN_ET0_MAGIC_B,
+ /* IP5_14_12 [3] */
+ FN_SD2_DAT2_A, FN_RX4_A, FN_VI0_R2, 0,
+ 0, 0, 0, FN_ET0_LINK_B,
+ /* IP5_11_9 [3] */
+ FN_SD2_DAT1_A, FN_TX3_A, FN_VI0_R1, 0,
+ 0, 0, 0, FN_ET0_MDIO_B,
+ /* IP5_8_6 [3] */
+ FN_SD2_DAT0_A, FN_RX3_A, FN_VI0_R0, 0,
+ 0, 0, 0, FN_ET0_ERXD3_B,
+ /* IP5_5_3 [3] */
+ FN_SD2_CMD_A, FN_TX2_A, FN_VI0_G5, 0,
+ 0, 0, 0, FN_ET0_ERXD2_B,
+ /* IP5_2_0 [3] */
+ FN_SD2_CLK_A, FN_RX2_A, FN_VI0_G4, 0,
+ FN_ET0_RX_CLK_B, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR6", 0xFFFC0034, 32,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 3, 2, 2, 2, 2, 2, 2, 3, 3) {
+ /* IP5_31 [1] */
+ 0, 0,
+ /* IP6_30 [1] */
+ 0, 0,
+ /* IP6_29 [1] */
+ 0, 0,
+ /* IP6_28 [1] */
+ 0, 0,
+ /* IP6_27 [1] */
+ 0, 0,
+ /* IP6_26 [1] */
+ 0, 0,
+ /* IP6_25 [1] */
+ 0, 0,
+ /* IP6_24 [1] */
+ 0, 0,
+ /* IP6_23_21 [3] */
+ FN_DU0_DG1, FN_CTS1_C, FN_HRTS0_D, FN_TIOC1B_A,
+ FN_HIFD09, 0, 0, 0,
+ /* IP6_20_18 [3] */
+ FN_DU0_DG0, FN_TX1_C, FN_HSCK0_D, FN_IECLK_A,
+ FN_TIOC1A_A, FN_HIFD08, 0, 0,
+ /* IP6_17_16 [2] */
+ FN_DU0_DR7, FN_RX1_C, FN_TIOC0D_A, FN_HIFD07,
+ /* IP6_15_14 [2] */
+ FN_DU0_DR6, FN_SCK1_C, FN_TIOC0C_A, FN_HIFD06,
+ /* IP6_13_12 [2] */
+ FN_DU0_DR5, FN_RTS0_C, FN_TIOC0B_A, FN_HIFD05,
+ /* IP6_11_10 [2] */
+ FN_DU0_DR4, FN_CTS0_C, FN_TIOC0A_A, FN_HIFD04,
+ /* IP6_9_8 [2] */
+ FN_DU0_DR3, FN_TX0_B, FN_TCLKD_A, FN_HIFD03,
+ /* IP6_7_6 [2] */
+ FN_DU0_DR2, FN_RX0_B, FN_TCLKC_A, FN_HIFD02,
+ /* IP6_5_3 [3] */
+ FN_DU0_DR1, FN_SCK0_B, FN_HTX0_D, FN_IERX_A,
+ FN_TCLKB_A, FN_HIFD01, 0, 0,
+ /* IP6_2_0 [3] */
+ FN_DU0_DR0, FN_SCIF_CLK_B, FN_HRX0_D, FN_IETX_A,
+ FN_TCLKA_A, FN_HIFD00, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR7", 0xFFFC0038, 32,
+ 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) {
+ /* IP7_31 [1] */
+ 0, 0,
+ /* IP7_30_29 [2] */
+ FN_DU0_DB4, 0, FN_HIFINT, 0,
+ /* IP7_28_27 [2] */
+ FN_DU0_DB3, FN_TX5_B, FN_TIOC4D_A, FN_HIFRD,
+ /* IP7_26_24 [3] */
+ FN_DU0_DB2, FN_RX5_B, FN_RMII0_TXD1_B, FN_TIOC4C_A,
+ FN_HIFWR, 0, 0, 0,
+ /* IP7_23_21 [3] */
+ FN_DU0_DB1, FN_TX4_C, FN_RMII0_TXD0_B, FN_TIOC4B_A,
+ FN_HIFRS, 0, 0, 0,
+ /* IP7_20_18 [3] */
+ FN_DU0_DB0, FN_RX4_C, FN_RMII0_TXD_EN_B, FN_TIOC4A_A,
+ FN_HIFCS, 0, 0, 0,
+ /* IP7_17_15 [3] */
+ FN_DU0_DG7, FN_TX3_C, FN_RMII0_RXD1_B, FN_TIOC3D_A,
+ FN_HIFD15, 0, 0, 0,
+ /* IP7_14_12 [3] */
+ FN_DU0_DG6, FN_RX3_C, FN_RMII0_RXD0_B, FN_TIOC3C_A,
+ FN_HIFD14, 0, 0, 0,
+ /* IP7_11_9 [3] */
+ FN_DU0_DG5, FN_TX2_C, FN_RMII0_RX_ER_B, FN_TIOC3B_A,
+ FN_HIFD13, 0, 0, 0,
+ /* IP7_8_6 [3] */
+ FN_DU0_DG4, FN_RX2_C, FN_RMII0_CRS_DV_B, FN_TIOC3A_A,
+ FN_HIFD12, 0, 0, 0,
+ /* IP7_5_3 [3] */
+ FN_DU0_DG3, FN_SCK2_C, FN_RMII0_MDIO_B, FN_TIOC2B_A,
+ FN_HIFD11, 0, 0, 0,
+ /* IP7_2_0 [3] */
+ FN_DU0_DG2, FN_RTS1_C, FN_RMII0_MDC_B, FN_TIOC2A_A,
+ FN_HIFD10, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR8", 0xFFFC003C, 32,
+ 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
+ /* IP9_31_30 [2] */
+ 0, 0, 0, 0,
+ /* IP8_29_28 [2] */
+ FN_IRQ3_A, FN_RTS0_A, FN_HRTS0_B, FN_ET0_ERXD3_A,
+ /* IP8_27_26 [2] */
+ FN_IRQ2_A, FN_CTS0_A, FN_HCTS0_B, FN_ET0_ERXD2_A,
+ /* IP8_25_23 [3] */
+ FN_IRQ1_A, 0, FN_HSPI_RX_B, FN_TX3_E,
+ FN_ET0_ERXD1, 0, 0, 0,
+ /* IP8_22_20 [3] */
+ FN_IRQ0_A, 0, FN_HSPI_TX_B, FN_RX3_E,
+ FN_ET0_ERXD0, 0, 0, 0,
+ /* IP8_19_18 [2] */
+ FN_DU0_CDE, FN_HTX0_B, FN_AUDIO_CLKB_B, FN_LCD_VCPWC_B,
+ /* IP8_17_16 [2] */
+ FN_DU0_DISP, FN_CAN0_TX_B, FN_HRX0_B, FN_AUDIO_CLKA_B,
+ /* IP8_15_14 [2] */
+ FN_DU0_EXODDF_DU0_ODDF, FN_CAN0_RX_B, FN_HSCK0_B,
+ FN_SSI_SDATA1_B,
+ /* IP8_13_12 [2] */
+ FN_DU0_EXVSYNC_DU0_VSYNC, 0, FN_HSPI_RX0_C, FN_SSI_WS1_B,
+ /* IP8_11_10 [2] */
+ FN_DU0_EXHSYNC_DU0_HSYNC, 0, FN_HSPI_TX0_C, FN_SSI_SCK1_B,
+ /* IP8_9_8 [2] */
+ FN_DU0_DOTCLKOUT, 0, FN_HSPI_CLK0_C, FN_SSI_SDATA0_B,
+ /* IP8_7_6 [2] */
+ FN_DU0_DOTCLKIN, 0, FN_HSPI_CS0_C, FN_SSI_WS0_B,
+ /* IP8_5_4 [2] */
+ FN_DU0_DB7, 0, FN_SSI_SCK0_B, FN_HIFEBL_B,
+ /* IP8_3_2 [2] */
+ FN_DU0_DB6, 0, FN_HIFRDY, 0,
+ /* IP8_1_0 [2] */
+ FN_DU0_DB5, 0, FN_HIFDREQ, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR9", 0xFFFC0040, 32,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2) {
+ /* IP9_31_30 [2] */
+ 0, 0, 0, 0,
+ /* IP9_29_28 [2] */
+ FN_SSI_SDATA1_A, FN_VI1_3_B, FN_LCD_DATA14_B, 0,
+ /* IP9_27_26 [2] */
+ FN_SSI_WS1_A, FN_VI1_2_B, FN_LCD_DATA13_B, 0,
+ /* IP9_25_24 [2] */
+ FN_SSI_SCK1_A, FN_VI1_1_B, FN_TIOC2B_B, FN_LCD_DATA12_B,
+ /* IP9_23_22 [2] */
+ FN_SSI_SDATA0_A, FN_VI1_0_B, FN_TIOC2A_B, FN_LCD_DATA11_B,
+ /* IP9_21_20 [2] */
+ FN_SSI_WS0_A, FN_TIOC1B_B, FN_LCD_DATA10_B, 0,
+ /* IP9_19_18 [2] */
+ FN_SSI_SCK0_A, FN_TIOC1A_B, FN_LCD_DATA9_B, 0,
+ /* IP9_17_16 [2] */
+ FN_VI1_7_A, FN_FCE_B, FN_LCD_DATA8_B, 0,
+ /* IP9_15_14 [2] */
+ FN_VI1_6_A, 0, FN_FD7_B, FN_LCD_DATA7_B,
+ /* IP9_13_12 [2] */
+ FN_VI1_5_A, 0, FN_FD6_B, FN_LCD_DATA6_B,
+ /* IP9_11_10 [2] */
+ FN_VI1_4_A, 0, FN_FD5_B, FN_LCD_DATA5_B,
+ /* IP9_9_8 [2] */
+ FN_VI1_3_A, 0, FN_FD4_B, FN_LCD_DATA4_B,
+ /* IP9_7_6 [2] */
+ FN_VI1_2_A, 0, FN_FD3_B, FN_LCD_DATA3_B,
+ /* IP9_5_4 [2] */
+ FN_VI1_1_A, 0, FN_FD2_B, FN_LCD_DATA2_B,
+ /* IP9_3_2 [2] */
+ FN_VI1_0_A, 0, FN_FD1_B, FN_LCD_DATA1_B,
+ /* IP9_1_0 [2] */
+ FN_VI1_CLK_A, 0, FN_FD0_B, FN_LCD_DATA0_B }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR10", 0xFFFC0044, 32,
+ 2, 2, 2, 1, 2, 1, 3,
+ 3, 1, 3, 3, 3, 3, 3) {
+ /* IP9_31_30 [2] */
+ 0, 0, 0, 0,
+ /* IP10_29_28 [2] */
+ FN_CAN1_TX_A, FN_TX5_C, FN_MLB_DAT, 0,
+ /* IP10_27_26 [2] */
+ FN_CAN0_RX_A, FN_IRQ0_B, FN_MLB_SIG, 0,
+ /* IP10_25 [1] */
+ FN_CAN1_RX_A, FN_IRQ1_B,
+ /* IP10_24_23 [2] */
+ FN_CAN0_TX_A, FN_TX4_D, FN_MLB_CLK, 0,
+ /* IP10_22 [1] */
+ FN_CAN_CLK_A, FN_RX4_D,
+ /* IP10_21_19 [3] */
+ FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B,
+ FN_LCD_M_DISP_B, 0, 0, 0,
+ /* IP10_18_16 [3] */
+ FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B,
+ FN_LCD_VEPWC_B, 0, 0, 0,
+ /* IP10_15 [1] */
+ FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
+ /* IP10_14_12 [3] */
+ FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B,
+ FN_LCD_FLM_B, 0, 0, 0,
+ /* IP10_11_9 [3] */
+ FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B,
+ FN_LCD_CL2_B, 0, 0, 0,
+ /* IP10_8_6 [3] */
+ FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B,
+ FN_LCD_CL1_B, 0, 0, 0,
+ /* IP10_5_3 [3] */
+ FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B,
+ FN_LCD_DON_B, 0, 0, 0,
+ /* IP10_2_0 [3] */
+ FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B,
+ FN_LCD_DATA15_B, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR11", 0xFFFC0048, 32,
+ 3, 1, 2, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) {
+ /* IP11_31_29 [3] */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* IP11_28 [1] */
+ FN_PRESETOUT, FN_ST_CLKOUT,
+ /* IP11_27_26 [2] */
+ FN_DACK1, FN_HSPI_CS_B, FN_TX4_B, FN_ET0_RX_CLK_A,
+ /* IP11_25_23 [3] */
+ FN_DREQ1, FN_HSPI_CLK_B, FN_RX4_B, FN_ET0_PHY_INT_C,
+ FN_ET0_TX_CLK_A, 0, 0, 0,
+ /* IP11_22_21 [2] */
+ FN_DACK0, FN_SD1_DAT3_A, FN_ET0_TX_ER, 0,
+ /* IP11_20_19 [2] */
+ FN_DREQ0, FN_SD1_CLK_A, FN_ET0_TX_EN, 0,
+ /* IP11_18_16 [3] */
+ FN_USB_OVC1, FN_RX3_D, FN_CAN1_RX_B, FN_RX5_D,
+ FN_IERX_B, 0, 0, 0,
+ /* IP11_15_13 [3] */
+ FN_PENC1, FN_TX3_D, FN_CAN1_TX_B, FN_TX5_D,
+ FN_IETX_B, 0, 0, 0,
+ /* IP11_12 [1] */
+ FN_TX0_A, FN_HSPI_TX_A,
+ /* IP11_11_10 [2] */
+ FN_RX0_A, FN_HSPI_RX_A, FN_RMII0_RXD0_A, FN_ET0_ERXD6,
+ /* IP11_9_7 [3] */
+ FN_SCK0_A, FN_HSPI_CS_A, FN_VI0_CLKENB, FN_RMII0_TXD1_A,
+ FN_ET0_ERXD5, 0, 0, 0,
+ /* IP11_6_4 [3] */
+ FN_SCIF_CLK_A, FN_HSPI_CLK_A, FN_VI0_CLK, FN_RMII0_TXD0_A,
+ FN_ET0_ERXD4, 0, 0, 0,
+ /* IP11_3 [1] */
+ FN_SDSELF, FN_RTS1_E,
+ /* IP11_2 [1] */
+ FN_SDA0, FN_HIFEBL_A,
+ /* IP11_1 [1] */
+ FN_SDA1, FN_RX1_E,
+ /* IP11_0 [1] */
+ FN_SCL1, FN_SCIF_CLK_C }
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL1", 0xFFFC004C, 32,
+ 3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2,
+ 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) {
+ /* SEL1_31_29 [3] */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* SEL1_28 [1] */
+ FN_SEL_IEBUS_0, FN_SEL_IEBUS_1,
+ /* SEL1_27 [1] */
+ FN_SEL_RQSPI_0, FN_SEL_RQSPI_1,
+ /* SEL1_26 [1] */
+ FN_SEL_VIN1_0, FN_SEL_VIN1_1,
+ /* SEL1_25 [1] */
+ FN_SEL_HIF_0, FN_SEL_HIF_1,
+ /* SEL1_24 [1] */
+ FN_SEL_RSPI_0, FN_SEL_RSPI_1,
+ /* SEL1_23 [1] */
+ FN_SEL_LCDC_0, FN_SEL_LCDC_1,
+ /* SEL1_22_21 [2] */
+ FN_SEL_ET0_CTL_0, FN_SEL_ET0_CTL_1, FN_SEL_ET0_CTL_2, 0,
+ /* SEL1_20 [1] */
+ FN_SEL_ET0_0, FN_SEL_ET0_1,
+ /* SEL1_19 [1] */
+ FN_SEL_RMII_0, FN_SEL_RMII_1,
+ /* SEL1_18 [1] */
+ FN_SEL_TMU_0, FN_SEL_TMU_1,
+ /* SEL1_17_16 [2] */
+ FN_SEL_HSPI_0, FN_SEL_HSPI_1, FN_SEL_HSPI_2, 0,
+ /* SEL1_15_14 [2] */
+ FN_SEL_HSCIF_0, FN_SEL_HSCIF_1, FN_SEL_HSCIF_2, FN_SEL_HSCIF_3,
+ /* SEL1_13 [1] */
+ FN_SEL_RCAN_CLK_0, FN_SEL_RCAN_CLK_1,
+ /* SEL1_12_11 [2] */
+ FN_SEL_RCAN1_0, FN_SEL_RCAN1_1, FN_SEL_RCAN1_2, 0,
+ /* SEL1_10 [1] */
+ FN_SEL_RCAN0_0, FN_SEL_RCAN0_1,
+ /* SEL1_9 [1] */
+ FN_SEL_SDHI2_0, FN_SEL_SDHI2_1,
+ /* SEL1_8 [1] */
+ FN_SEL_SDHI1_0, FN_SEL_SDHI1_1,
+ /* SEL1_7 [1] */
+ FN_SEL_SDHI0_0, FN_SEL_SDHI0_1,
+ /* SEL1_6 [1] */
+ FN_SEL_SSI1_0, FN_SEL_SSI1_1,
+ /* SEL1_5 [1] */
+ FN_SEL_SSI0_0, FN_SEL_SSI0_1,
+ /* SEL1_4 [1] */
+ FN_SEL_AUDIO_CLKB_0, FN_SEL_AUDIO_CLKB_1,
+ /* SEL1_3 [1] */
+ FN_SEL_AUDIO_CLKA_0, FN_SEL_AUDIO_CLKA_1,
+ /* SEL1_2 [1] */
+ FN_SEL_FLCTL_0, FN_SEL_FLCTL_1,
+ /* SEL1_1 [1] */
+ FN_SEL_MMC_0, FN_SEL_MMC_1,
+ /* SEL1_0 [1] */
+ FN_SEL_INTC_0, FN_SEL_INTC_1 }
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL2", 0xFFFC0050, 32,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 1, 2, 2, 3, 2, 3, 2, 2) {
+ /* SEL2_31 [1] */
+ 0, 0,
+ /* SEL2_30 [1] */
+ 0, 0,
+ /* SEL2_29 [1] */
+ 0, 0,
+ /* SEL2_28 [1] */
+ 0, 0,
+ /* SEL2_27 [1] */
+ 0, 0,
+ /* SEL2_26 [1] */
+ 0, 0,
+ /* SEL2_25 [1] */
+ 0, 0,
+ /* SEL2_24 [1] */
+ 0, 0,
+ /* SEL2_23 [1] */
+ FN_SEL_MTU2_CLK_0, FN_SEL_MTU2_CLK_1,
+ /* SEL2_22 [1] */
+ FN_SEL_MTU2_CH4_0, FN_SEL_MTU2_CH4_1,
+ /* SEL2_21 [1] */
+ FN_SEL_MTU2_CH3_0, FN_SEL_MTU2_CH3_1,
+ /* SEL2_20_19 [2] */
+ FN_SEL_MTU2_CH2_0, FN_SEL_MTU2_CH2_1, FN_SEL_MTU2_CH2_2, 0,
+ /* SEL2_18_17 [2] */
+ FN_SEL_MTU2_CH1_0, FN_SEL_MTU2_CH1_1, FN_SEL_MTU2_CH1_2, 0,
+ /* SEL2_16 [1] */
+ FN_SEL_MTU2_CH0_0, FN_SEL_MTU2_CH0_1,
+ /* SEL2_15_14 [2] */
+ FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+ /* SEL2_13_12 [2] */
+ FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+ /* SEL2_11_9 [3] */
+ FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2, FN_SEL_SCIF3_3,
+ FN_SEL_SCIF3_4, 0, 0, 0,
+ /* SEL2_8_7 [2] */
+ FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2, FN_SEL_SCIF2_3,
+ /* SEL2_6_4 [3] */
+ FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, FN_SEL_SCIF1_3,
+ FN_SEL_SCIF1_4, 0, 0, 0,
+ /* SEL2_3_2 [2] */
+ FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, 0,
+ /* SEL2_1_0 [2] */
+ FN_SEL_SCIF_CLK_0, FN_SEL_SCIF_CLK_1, FN_SEL_SCIF_CLK_2, 0 }
+ },
+ /* GPIO 0 - 5*/
+ { PINMUX_CFG_REG("INOUTSEL0", 0xFFC40004, 32, 1) { GP_INOUTSEL(0) } },
+ { PINMUX_CFG_REG("INOUTSEL1", 0xFFC41004, 32, 1) { GP_INOUTSEL(1) } },
+ { PINMUX_CFG_REG("INOUTSEL2", 0xFFC42004, 32, 1) { GP_INOUTSEL(2) } },
+ { PINMUX_CFG_REG("INOUTSEL3", 0xFFC43004, 32, 1) { GP_INOUTSEL(3) } },
+ { PINMUX_CFG_REG("INOUTSEL4", 0xFFC44004, 32, 1) { GP_INOUTSEL(4) } },
+ { PINMUX_CFG_REG("INOUTSEL5", 0xffc45004, 32, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 31 - 24 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 23 - 16 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 15 - 12 */
+ GP_5_11_IN, GP_5_11_OUT,
+ GP_5_10_IN, GP_5_10_OUT,
+ GP_5_9_IN, GP_5_9_OUT,
+ GP_5_8_IN, GP_5_8_OUT,
+ GP_5_7_IN, GP_5_7_OUT,
+ GP_5_6_IN, GP_5_6_OUT,
+ GP_5_5_IN, GP_5_5_OUT,
+ GP_5_4_IN, GP_5_4_OUT,
+ GP_5_3_IN, GP_5_3_OUT,
+ GP_5_2_IN, GP_5_2_OUT,
+ GP_5_1_IN, GP_5_1_OUT,
+ GP_5_0_IN, GP_5_0_OUT }
+ },
+ { },
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ /* GPIO 0 - 5*/
+ { PINMUX_DATA_REG("INDT0", 0xFFC4000C, 32) { GP_INDT(0) } },
+ { PINMUX_DATA_REG("INDT1", 0xFFC4100C, 32) { GP_INDT(1) } },
+ { PINMUX_DATA_REG("INDT2", 0xFFC4200C, 32) { GP_INDT(2) } },
+ { PINMUX_DATA_REG("INDT3", 0xFFC4300C, 32) { GP_INDT(3) } },
+ { PINMUX_DATA_REG("INDT4", 0xFFC4400C, 32) { GP_INDT(4) } },
+ { PINMUX_DATA_REG("INDT5", 0xFFC4500C, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ GP_5_11_DATA, GP_5_10_DATA, GP_5_9_DATA, GP_5_8_DATA,
+ GP_5_7_DATA, GP_5_6_DATA, GP_5_5_DATA, GP_5_4_DATA,
+ GP_5_3_DATA, GP_5_2_DATA, GP_5_1_DATA, GP_5_0_DATA }
+ },
+ { },
+};
+
+struct sh_pfc_soc_info sh7734_pinmux_info = {
+ .name = "sh7734_pfc",
+
+ .unlock_reg = 0xFFFC0000,
+
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_GP_0_0,
+ .last_gpio = GPIO_FN_ST_CLKOUT,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7757.c b/drivers/pinctrl/sh-pfc/pfc-sh7757.c
new file mode 100644
index 000000000000..5ed74cd0ba99
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7757.c
@@ -0,0 +1,2282 @@
+/*
+ * SH7757 (B0 step) Pinmux
+ *
+ * Copyright (C) 2009-2010 Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * Based on SH7723 Pinmux
+ * Copyright (C) 2008 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/init.h>
+#include <linux/kernel.h>
+#include <cpu/sh7757.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+ PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA,
+ PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+ PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA,
+ PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
+ PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA,
+ PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+ PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA,
+ PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
+ PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA,
+ PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
+ PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA,
+ PTG7_DATA, PTG6_DATA, PTG5_DATA, PTG4_DATA,
+ PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA,
+ PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+ PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
+ PTI7_DATA, PTI6_DATA, PTI5_DATA, PTI4_DATA,
+ PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA,
+ PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+ PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
+ PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
+ PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
+ PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
+ PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
+ PTO7_DATA, PTO6_DATA, PTO5_DATA, PTO4_DATA,
+ PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA,
+ PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
+ PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA,
+ PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+ PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
+ PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
+ PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
+ PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
+ PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
+ PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
+ PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
+ PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
+ PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
+ PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
+ PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA,
+ PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
+ PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA,
+ PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
+ PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA,
+ PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
+ PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA,
+ PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
+ PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ PTA7_IN, PTA6_IN, PTA5_IN, PTA4_IN,
+ PTA3_IN, PTA2_IN, PTA1_IN, PTA0_IN,
+ PTB7_IN, PTB6_IN, PTB5_IN, PTB4_IN,
+ PTB3_IN, PTB2_IN, PTB1_IN, PTB0_IN,
+ PTC7_IN, PTC6_IN, PTC5_IN, PTC4_IN,
+ PTC3_IN, PTC2_IN, PTC1_IN, PTC0_IN,
+ PTD7_IN, PTD6_IN, PTD5_IN, PTD4_IN,
+ PTD3_IN, PTD2_IN, PTD1_IN, PTD0_IN,
+ PTE7_IN, PTE6_IN, PTE5_IN, PTE4_IN,
+ PTE3_IN, PTE2_IN, PTE1_IN, PTE0_IN,
+ PTF7_IN, PTF6_IN, PTF5_IN, PTF4_IN,
+ PTF3_IN, PTF2_IN, PTF1_IN, PTF0_IN,
+ PTG7_IN, PTG6_IN, PTG5_IN, PTG4_IN,
+ PTG3_IN, PTG2_IN, PTG1_IN, PTG0_IN,
+ PTH7_IN, PTH6_IN, PTH5_IN, PTH4_IN,
+ PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
+ PTI7_IN, PTI6_IN, PTI5_IN, PTI4_IN,
+ PTI3_IN, PTI2_IN, PTI1_IN, PTI0_IN,
+ PTJ6_IN, PTJ5_IN, PTJ4_IN,
+ PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
+ PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
+ PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
+ PTL6_IN, PTL5_IN, PTL4_IN,
+ PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
+ PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
+ PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
+ PTN6_IN, PTN5_IN, PTN4_IN,
+ PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
+ PTO7_IN, PTO6_IN, PTO5_IN, PTO4_IN,
+ PTO3_IN, PTO2_IN, PTO1_IN, PTO0_IN,
+ PTP7_IN, PTP6_IN, PTP5_IN, PTP4_IN,
+ PTP3_IN, PTP2_IN, PTP1_IN, PTP0_IN,
+ PTQ6_IN, PTQ5_IN, PTQ4_IN,
+ PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
+ PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
+ PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
+ PTS7_IN, PTS6_IN, PTS5_IN, PTS4_IN,
+ PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
+ PTT7_IN, PTT6_IN, PTT5_IN, PTT4_IN,
+ PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
+ PTU7_IN, PTU6_IN, PTU5_IN, PTU4_IN,
+ PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
+ PTV7_IN, PTV6_IN, PTV5_IN, PTV4_IN,
+ PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
+ PTW7_IN, PTW6_IN, PTW5_IN, PTW4_IN,
+ PTW3_IN, PTW2_IN, PTW1_IN, PTW0_IN,
+ PTX7_IN, PTX6_IN, PTX5_IN, PTX4_IN,
+ PTX3_IN, PTX2_IN, PTX1_IN, PTX0_IN,
+ PTY7_IN, PTY6_IN, PTY5_IN, PTY4_IN,
+ PTY3_IN, PTY2_IN, PTY1_IN, PTY0_IN,
+ PTZ7_IN, PTZ6_IN, PTZ5_IN, PTZ4_IN,
+ PTZ3_IN, PTZ2_IN, PTZ1_IN, PTZ0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_INPUT_PULLUP_BEGIN,
+ PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
+ PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
+ PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
+ PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
+ PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
+ PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
+ PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
+ PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
+ PTG7_IN_PU, PTG6_IN_PU, PTG4_IN_PU,
+ PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
+ PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
+ PTI7_IN_PU, PTI6_IN_PU, PTI4_IN_PU,
+ PTI3_IN_PU, PTI2_IN_PU, PTI1_IN_PU, PTI0_IN_PU,
+ PTJ6_IN_PU, PTJ5_IN_PU, PTJ4_IN_PU,
+ PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
+ PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
+ PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
+ PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
+ PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
+ PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
+ PTN4_IN_PU,
+ PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
+ PTO7_IN_PU, PTO6_IN_PU, PTO5_IN_PU, PTO4_IN_PU,
+ PTO3_IN_PU, PTO2_IN_PU, PTO1_IN_PU, PTO0_IN_PU,
+ PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
+ PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
+ PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
+ PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
+ PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
+ PTV3_IN_PU, PTV2_IN_PU,
+ PTW1_IN_PU, PTW0_IN_PU,
+ PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
+ PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
+ PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
+ PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
+ PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
+ PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
+ PINMUX_INPUT_PULLUP_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
+ PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
+ PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
+ PTB3_OUT, PTB2_OUT, PTB1_OUT, PTB0_OUT,
+ PTC7_OUT, PTC6_OUT, PTC5_OUT, PTC4_OUT,
+ PTC3_OUT, PTC2_OUT, PTC1_OUT, PTC0_OUT,
+ PTD7_OUT, PTD6_OUT, PTD5_OUT, PTD4_OUT,
+ PTD3_OUT, PTD2_OUT, PTD1_OUT, PTD0_OUT,
+ PTE7_OUT, PTE6_OUT, PTE5_OUT, PTE4_OUT,
+ PTE3_OUT, PTE2_OUT, PTE1_OUT, PTE0_OUT,
+ PTF7_OUT, PTF6_OUT, PTF5_OUT, PTF4_OUT,
+ PTF3_OUT, PTF2_OUT, PTF1_OUT, PTF0_OUT,
+ PTG7_OUT, PTG6_OUT, PTG5_OUT, PTG4_OUT,
+ PTG3_OUT, PTG2_OUT, PTG1_OUT, PTG0_OUT,
+ PTH7_OUT, PTH6_OUT, PTH5_OUT, PTH4_OUT,
+ PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
+ PTI7_OUT, PTI6_OUT, PTI5_OUT, PTI4_OUT,
+ PTI3_OUT, PTI2_OUT, PTI1_OUT, PTI0_OUT,
+ PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
+ PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
+ PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
+ PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
+ PTL6_OUT, PTL5_OUT, PTL4_OUT,
+ PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
+ PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
+ PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
+ PTN6_OUT, PTN5_OUT, PTN4_OUT,
+ PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
+ PTO7_OUT, PTO6_OUT, PTO5_OUT, PTO4_OUT,
+ PTO3_OUT, PTO2_OUT, PTO1_OUT, PTO0_OUT,
+ PTP7_OUT, PTP6_OUT, PTP5_OUT, PTP4_OUT,
+ PTP3_OUT, PTP2_OUT, PTP1_OUT, PTP0_OUT,
+ PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
+ PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
+ PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
+ PTR3_OUT, PTR2_OUT, PTR1_OUT, PTR0_OUT,
+ PTS7_OUT, PTS6_OUT, PTS5_OUT, PTS4_OUT,
+ PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
+ PTT7_OUT, PTT6_OUT, PTT5_OUT, PTT4_OUT,
+ PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
+ PTU7_OUT, PTU6_OUT, PTU5_OUT, PTU4_OUT,
+ PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
+ PTV7_OUT, PTV6_OUT, PTV5_OUT, PTV4_OUT,
+ PTV3_OUT, PTV2_OUT, PTV1_OUT, PTV0_OUT,
+ PTW7_OUT, PTW6_OUT, PTW5_OUT, PTW4_OUT,
+ PTW3_OUT, PTW2_OUT, PTW1_OUT, PTW0_OUT,
+ PTX7_OUT, PTX6_OUT, PTX5_OUT, PTX4_OUT,
+ PTX3_OUT, PTX2_OUT, PTX1_OUT, PTX0_OUT,
+ PTY7_OUT, PTY6_OUT, PTY5_OUT, PTY4_OUT,
+ PTY3_OUT, PTY2_OUT, PTY1_OUT, PTY0_OUT,
+ PTZ7_OUT, PTZ6_OUT, PTZ5_OUT, PTZ4_OUT,
+ PTZ3_OUT, PTZ2_OUT, PTZ1_OUT, PTZ0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PTA7_FN, PTA6_FN, PTA5_FN, PTA4_FN,
+ PTA3_FN, PTA2_FN, PTA1_FN, PTA0_FN,
+ PTB7_FN, PTB6_FN, PTB5_FN, PTB4_FN,
+ PTB3_FN, PTB2_FN, PTB1_FN, PTB0_FN,
+ PTC7_FN, PTC6_FN, PTC5_FN, PTC4_FN,
+ PTC3_FN, PTC2_FN, PTC1_FN, PTC0_FN,
+ PTD7_FN, PTD6_FN, PTD5_FN, PTD4_FN,
+ PTD3_FN, PTD2_FN, PTD1_FN, PTD0_FN,
+ PTE7_FN, PTE6_FN, PTE5_FN, PTE4_FN,
+ PTE3_FN, PTE2_FN, PTE1_FN, PTE0_FN,
+ PTF7_FN, PTF6_FN, PTF5_FN, PTF4_FN,
+ PTF3_FN, PTF2_FN, PTF1_FN, PTF0_FN,
+ PTG7_FN, PTG6_FN, PTG5_FN, PTG4_FN,
+ PTG3_FN, PTG2_FN, PTG1_FN, PTG0_FN,
+ PTH7_FN, PTH6_FN, PTH5_FN, PTH4_FN,
+ PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
+ PTI7_FN, PTI6_FN, PTI5_FN, PTI4_FN,
+ PTI3_FN, PTI2_FN, PTI1_FN, PTI0_FN,
+ PTJ6_FN, PTJ5_FN, PTJ4_FN,
+ PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
+ PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
+ PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
+ PTL6_FN, PTL5_FN, PTL4_FN,
+ PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
+ PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
+ PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
+ PTN6_FN, PTN5_FN, PTN4_FN,
+ PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
+ PTO7_FN, PTO6_FN, PTO5_FN, PTO4_FN,
+ PTO3_FN, PTO2_FN, PTO1_FN, PTO0_FN,
+ PTP7_FN, PTP6_FN, PTP5_FN, PTP4_FN,
+ PTP3_FN, PTP2_FN, PTP1_FN, PTP0_FN,
+ PTQ6_FN, PTQ5_FN, PTQ4_FN,
+ PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
+ PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
+ PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
+ PTS7_FN, PTS6_FN, PTS5_FN, PTS4_FN,
+ PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
+ PTT7_FN, PTT6_FN, PTT5_FN, PTT4_FN,
+ PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
+ PTU7_FN, PTU6_FN, PTU5_FN, PTU4_FN,
+ PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
+ PTV7_FN, PTV6_FN, PTV5_FN, PTV4_FN,
+ PTV3_FN, PTV2_FN, PTV1_FN, PTV0_FN,
+ PTW7_FN, PTW6_FN, PTW5_FN, PTW4_FN,
+ PTW3_FN, PTW2_FN, PTW1_FN, PTW0_FN,
+ PTX7_FN, PTX6_FN, PTX5_FN, PTX4_FN,
+ PTX3_FN, PTX2_FN, PTX1_FN, PTX0_FN,
+ PTY7_FN, PTY6_FN, PTY5_FN, PTY4_FN,
+ PTY3_FN, PTY2_FN, PTY1_FN, PTY0_FN,
+ PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
+ PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
+
+ PS0_15_FN1, PS0_15_FN2,
+ PS0_14_FN1, PS0_14_FN2,
+ PS0_13_FN1, PS0_13_FN2,
+ PS0_12_FN1, PS0_12_FN2,
+ PS0_11_FN1, PS0_11_FN2,
+ PS0_10_FN1, PS0_10_FN2,
+ PS0_9_FN1, PS0_9_FN2,
+ PS0_8_FN1, PS0_8_FN2,
+ PS0_7_FN1, PS0_7_FN2,
+ PS0_6_FN1, PS0_6_FN2,
+ PS0_5_FN1, PS0_5_FN2,
+ PS0_4_FN1, PS0_4_FN2,
+ PS0_3_FN1, PS0_3_FN2,
+ PS0_2_FN1, PS0_2_FN2,
+
+ PS1_10_FN1, PS1_10_FN2,
+ PS1_9_FN1, PS1_9_FN2,
+ PS1_8_FN1, PS1_8_FN2,
+ PS1_2_FN1, PS1_2_FN2,
+
+ PS2_13_FN1, PS2_13_FN2,
+ PS2_12_FN1, PS2_12_FN2,
+ PS2_7_FN1, PS2_7_FN2,
+ PS2_6_FN1, PS2_6_FN2,
+ PS2_5_FN1, PS2_5_FN2,
+ PS2_4_FN1, PS2_4_FN2,
+ PS2_2_FN1, PS2_2_FN2,
+
+ PS3_15_FN1, PS3_15_FN2,
+ PS3_14_FN1, PS3_14_FN2,
+ PS3_13_FN1, PS3_13_FN2,
+ PS3_12_FN1, PS3_12_FN2,
+ PS3_11_FN1, PS3_11_FN2,
+ PS3_10_FN1, PS3_10_FN2,
+ PS3_9_FN1, PS3_9_FN2,
+ PS3_8_FN1, PS3_8_FN2,
+ PS3_7_FN1, PS3_7_FN2,
+ PS3_2_FN1, PS3_2_FN2,
+ PS3_1_FN1, PS3_1_FN2,
+
+ PS4_14_FN1, PS4_14_FN2,
+ PS4_13_FN1, PS4_13_FN2,
+ PS4_12_FN1, PS4_12_FN2,
+ PS4_10_FN1, PS4_10_FN2,
+ PS4_9_FN1, PS4_9_FN2,
+ PS4_8_FN1, PS4_8_FN2,
+ PS4_4_FN1, PS4_4_FN2,
+ PS4_3_FN1, PS4_3_FN2,
+ PS4_2_FN1, PS4_2_FN2,
+ PS4_1_FN1, PS4_1_FN2,
+ PS4_0_FN1, PS4_0_FN2,
+
+ PS5_11_FN1, PS5_11_FN2,
+ PS5_10_FN1, PS5_10_FN2,
+ PS5_9_FN1, PS5_9_FN2,
+ PS5_8_FN1, PS5_8_FN2,
+ PS5_7_FN1, PS5_7_FN2,
+ PS5_6_FN1, PS5_6_FN2,
+ PS5_5_FN1, PS5_5_FN2,
+ PS5_4_FN1, PS5_4_FN2,
+ PS5_3_FN1, PS5_3_FN2,
+ PS5_2_FN1, PS5_2_FN2,
+
+ PS6_15_FN1, PS6_15_FN2,
+ PS6_14_FN1, PS6_14_FN2,
+ PS6_13_FN1, PS6_13_FN2,
+ PS6_12_FN1, PS6_12_FN2,
+ PS6_11_FN1, PS6_11_FN2,
+ PS6_10_FN1, PS6_10_FN2,
+ PS6_9_FN1, PS6_9_FN2,
+ PS6_8_FN1, PS6_8_FN2,
+ PS6_7_FN1, PS6_7_FN2,
+ PS6_6_FN1, PS6_6_FN2,
+ PS6_5_FN1, PS6_5_FN2,
+ PS6_4_FN1, PS6_4_FN2,
+ PS6_3_FN1, PS6_3_FN2,
+ PS6_2_FN1, PS6_2_FN2,
+ PS6_1_FN1, PS6_1_FN2,
+ PS6_0_FN1, PS6_0_FN2,
+
+ PS7_15_FN1, PS7_15_FN2,
+ PS7_14_FN1, PS7_14_FN2,
+ PS7_13_FN1, PS7_13_FN2,
+ PS7_12_FN1, PS7_12_FN2,
+ PS7_11_FN1, PS7_11_FN2,
+ PS7_10_FN1, PS7_10_FN2,
+ PS7_9_FN1, PS7_9_FN2,
+ PS7_8_FN1, PS7_8_FN2,
+ PS7_7_FN1, PS7_7_FN2,
+ PS7_6_FN1, PS7_6_FN2,
+ PS7_5_FN1, PS7_5_FN2,
+ PS7_4_FN1, PS7_4_FN2,
+
+ PS8_15_FN1, PS8_15_FN2,
+ PS8_14_FN1, PS8_14_FN2,
+ PS8_13_FN1, PS8_13_FN2,
+ PS8_12_FN1, PS8_12_FN2,
+ PS8_11_FN1, PS8_11_FN2,
+ PS8_10_FN1, PS8_10_FN2,
+ PS8_9_FN1, PS8_9_FN2,
+ PS8_8_FN1, PS8_8_FN2,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ /* PTA (mobule: LBSC, RGMII) */
+ BS_MARK, RDWR_MARK, WE1_MARK, RDY_MARK,
+ ET0_MDC_MARK, ET0_MDIO_MARK, ET1_MDC_MARK, ET1_MDIO_MARK,
+
+ /* PTB (mobule: INTC, ONFI, TMU) */
+ IRQ15_MARK, IRQ14_MARK, IRQ13_MARK, IRQ12_MARK,
+ IRQ11_MARK, IRQ10_MARK, IRQ9_MARK, IRQ8_MARK,
+ ON_NRE_MARK, ON_NWE_MARK, ON_NWP_MARK, ON_NCE0_MARK,
+ ON_R_B0_MARK, ON_ALE_MARK, ON_CLE_MARK, TCLK_MARK,
+
+ /* PTC (mobule: IRQ, PWMU) */
+ IRQ7_MARK, IRQ6_MARK, IRQ5_MARK, IRQ4_MARK,
+ IRQ3_MARK, IRQ2_MARK, IRQ1_MARK, IRQ0_MARK,
+ PWMU0_MARK, PWMU1_MARK, PWMU2_MARK, PWMU3_MARK,
+ PWMU4_MARK, PWMU5_MARK,
+
+ /* PTD (mobule: SPI0, DMAC) */
+ SP0_MOSI_MARK, SP0_MISO_MARK, SP0_SCK_MARK, SP0_SCK_FB_MARK,
+ SP0_SS0_MARK, SP0_SS1_MARK, SP0_SS2_MARK, SP0_SS3_MARK,
+ DREQ0_MARK, DACK0_MARK, TEND0_MARK,
+
+ /* PTE (mobule: RMII) */
+ RMII0_CRS_DV_MARK, RMII0_TXD1_MARK,
+ RMII0_TXD0_MARK, RMII0_TXEN_MARK,
+ RMII0_REFCLK_MARK, RMII0_RXD1_MARK,
+ RMII0_RXD0_MARK, RMII0_RX_ER_MARK,
+
+ /* PTF (mobule: RMII, SerMux) */
+ RMII1_CRS_DV_MARK, RMII1_TXD1_MARK,
+ RMII1_TXD0_MARK, RMII1_TXEN_MARK,
+ RMII1_REFCLK_MARK, RMII1_RXD1_MARK,
+ RMII1_RXD0_MARK, RMII1_RX_ER_MARK,
+ RAC_RI_MARK,
+
+ /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+ BOOTFMS_MARK, BOOTWP_MARK, A25_MARK, A24_MARK,
+ SERIRQ_MARK, WDTOVF_MARK, LPCPD_MARK, LDRQ_MARK,
+ MMCCLK_MARK, MMCCMD_MARK,
+
+ /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
+ SP1_MOSI_MARK, SP1_MISO_MARK, SP1_SCK_MARK, SP1_SCK_FB_MARK,
+ SP1_SS0_MARK, SP1_SS1_MARK, WP_MARK, FMS0_MARK,
+ TEND1_MARK, DREQ1_MARK, DACK1_MARK, ADTRG1_MARK,
+ ADTRG0_MARK,
+
+ /* PTI (mobule: LBSC, SDHI) */
+ D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+ D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+ SD_WP_MARK, SD_CD_MARK, SD_CLK_MARK, SD_CMD_MARK,
+ SD_D3_MARK, SD_D2_MARK, SD_D1_MARK, SD_D0_MARK,
+
+ /* PTJ (mobule: SCIF234) */
+ RTS3_MARK, CTS3_MARK, TXD3_MARK, RXD3_MARK,
+ RTS4_MARK, RXD4_MARK, TXD4_MARK,
+
+ /* PTK (mobule: SERMUX, LBSC, SCIF) */
+ COM2_TXD_MARK, COM2_RXD_MARK, COM2_RTS_MARK, COM2_CTS_MARK,
+ COM2_DTR_MARK, COM2_DSR_MARK, COM2_DCD_MARK, CLKOUT_MARK,
+ SCK2_MARK, SCK4_MARK, SCK3_MARK,
+
+ /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
+ RAC_RXD_MARK, RAC_RTS_MARK, RAC_CTS_MARK, RAC_DTR_MARK,
+ RAC_DSR_MARK, RAC_DCD_MARK, RAC_TXD_MARK, RXD2_MARK,
+ CS5_MARK, CS6_MARK, AUDSYNC_MARK, AUDCK_MARK,
+ TXD2_MARK,
+
+ /* PTM (mobule: LBSC, IIC) */
+ CS4_MARK, RD_MARK, WE0_MARK, CS0_MARK,
+ SDA6_MARK, SCL6_MARK, SDA7_MARK, SCL7_MARK,
+
+ /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+ VBUS_EN_MARK, VBUS_OC_MARK, JMCTCK_MARK, JMCTMS_MARK,
+ JMCTDO_MARK, JMCTDI_MARK, JMCTRST_MARK,
+ SGPIO1_CLK_MARK, SGPIO1_LOAD_MARK, SGPIO1_DI_MARK,
+ SGPIO1_DO_MARK, SUB_CLKIN_MARK,
+
+ /* PTO (mobule: SGPIO, SerMux) */
+ SGPIO0_CLK_MARK, SGPIO0_LOAD_MARK, SGPIO0_DI_MARK,
+ SGPIO0_DO_MARK, SGPIO2_CLK_MARK, SGPIO2_LOAD_MARK,
+ SGPIO2_DI_MARK, SGPIO2_DO_MARK,
+ COM1_TXD_MARK, COM1_RXD_MARK, COM1_RTS_MARK, COM1_CTS_MARK,
+
+ /* PTQ (mobule: LPC) */
+ LAD3_MARK, LAD2_MARK, LAD1_MARK, LAD0_MARK,
+ LFRAME_MARK, LRESET_MARK, LCLK_MARK,
+
+ /* PTR (mobule: GRA, IIC) */
+ DDC3_MARK, DDC2_MARK, SDA2_MARK, SCL2_MARK,
+ SDA1_MARK, SCL1_MARK, SDA0_MARK, SCL0_MARK,
+ SDA8_MARK, SCL8_MARK,
+
+ /* PTS (mobule: GRA, IIC) */
+ DDC1_MARK, DDC0_MARK, SDA5_MARK, SCL5_MARK,
+ SDA4_MARK, SCL4_MARK, SDA3_MARK, SCL3_MARK,
+ SDA9_MARK, SCL9_MARK,
+
+ /* PTT (mobule: PWMX, AUD) */
+ PWMX7_MARK, PWMX6_MARK, PWMX5_MARK, PWMX4_MARK,
+ PWMX3_MARK, PWMX2_MARK, PWMX1_MARK, PWMX0_MARK,
+ AUDATA3_MARK, AUDATA2_MARK, AUDATA1_MARK, AUDATA0_MARK,
+ STATUS1_MARK, STATUS0_MARK,
+
+ /* PTU (mobule: LPC, APM) */
+ LGPIO7_MARK, LGPIO6_MARK, LGPIO5_MARK, LGPIO4_MARK,
+ LGPIO3_MARK, LGPIO2_MARK, LGPIO1_MARK, LGPIO0_MARK,
+ APMONCTL_O_MARK, APMPWBTOUT_O_MARK, APMSCI_O_MARK,
+ APMVDDON_MARK, APMSLPBTN_MARK, APMPWRBTN_MARK, APMS5N_MARK,
+ APMS3N_MARK,
+
+ /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
+ A23_MARK, A22_MARK, A21_MARK, A20_MARK,
+ A19_MARK, A18_MARK, A17_MARK, A16_MARK,
+ COM2_RI_MARK, R_SPI_MOSI_MARK, R_SPI_MISO_MARK,
+ R_SPI_RSPCK_MARK, R_SPI_SSL0_MARK, R_SPI_SSL1_MARK,
+ EVENT7_MARK, EVENT6_MARK, VBIOS_DI_MARK, VBIOS_DO_MARK,
+ VBIOS_CLK_MARK, VBIOS_CS_MARK,
+
+ /* PTW (mobule: LBSC, EVC, SCIF) */
+ A15_MARK, A14_MARK, A13_MARK, A12_MARK,
+ A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+ EVENT5_MARK, EVENT4_MARK, EVENT3_MARK, EVENT2_MARK,
+ EVENT1_MARK, EVENT0_MARK, CTS4_MARK, CTS2_MARK,
+
+ /* PTX (mobule: LBSC, SCIF, SIM) */
+ A7_MARK, A6_MARK, A5_MARK, A4_MARK,
+ A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+ RTS2_MARK, SIM_D_MARK, SIM_CLK_MARK, SIM_RST_MARK,
+
+ /* PTY (mobule: LBSC) */
+ D7_MARK, D6_MARK, D5_MARK, D4_MARK,
+ D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+
+ /* PTZ (mobule: eMMC, ONFI) */
+ MMCDAT7_MARK, MMCDAT6_MARK, MMCDAT5_MARK, MMCDAT4_MARK,
+ MMCDAT3_MARK, MMCDAT2_MARK, MMCDAT1_MARK, MMCDAT0_MARK,
+ ON_DQ7_MARK, ON_DQ6_MARK, ON_DQ5_MARK, ON_DQ4_MARK,
+ ON_DQ3_MARK, ON_DQ2_MARK, ON_DQ1_MARK, ON_DQ0_MARK,
+
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+ /* PTA GPIO */
+ PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT),
+ PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT),
+ PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT),
+ PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT),
+ PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT),
+ PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT),
+ PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT),
+ PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT),
+
+ /* PTB GPIO */
+ PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT),
+ PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT),
+ PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT),
+ PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT),
+ PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT),
+ PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT),
+ PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT),
+ PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT),
+
+ /* PTC GPIO */
+ PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT),
+ PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT),
+ PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT),
+ PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT),
+ PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT),
+ PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT),
+ PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT),
+ PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT),
+
+ /* PTD GPIO */
+ PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT),
+ PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT),
+ PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT),
+ PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT),
+ PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT),
+ PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT),
+ PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT),
+ PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT),
+
+ /* PTE GPIO */
+ PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT),
+ PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT),
+ PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT),
+ PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT),
+ PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT),
+ PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT),
+ PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT),
+ PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT),
+
+ /* PTF GPIO */
+ PINMUX_DATA(PTF7_DATA, PTF7_IN, PTF7_OUT),
+ PINMUX_DATA(PTF6_DATA, PTF6_IN, PTF6_OUT),
+ PINMUX_DATA(PTF5_DATA, PTF5_IN, PTF5_OUT),
+ PINMUX_DATA(PTF4_DATA, PTF4_IN, PTF4_OUT),
+ PINMUX_DATA(PTF3_DATA, PTF3_IN, PTF3_OUT),
+ PINMUX_DATA(PTF2_DATA, PTF2_IN, PTF2_OUT),
+ PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_OUT),
+ PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT),
+
+ /* PTG GPIO */
+ PINMUX_DATA(PTG7_DATA, PTG7_IN, PTG7_OUT),
+ PINMUX_DATA(PTG6_DATA, PTG6_IN, PTG6_OUT),
+ PINMUX_DATA(PTG5_DATA, PTG5_IN, PTG5_OUT),
+ PINMUX_DATA(PTG4_DATA, PTG4_IN, PTG4_OUT),
+ PINMUX_DATA(PTG3_DATA, PTG3_IN, PTG3_OUT),
+ PINMUX_DATA(PTG2_DATA, PTG2_IN, PTG2_OUT),
+ PINMUX_DATA(PTG1_DATA, PTG1_IN, PTG1_OUT),
+ PINMUX_DATA(PTG0_DATA, PTG0_IN, PTG0_OUT),
+
+ /* PTH GPIO */
+ PINMUX_DATA(PTH7_DATA, PTH7_IN, PTH7_OUT),
+ PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT),
+ PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT),
+ PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT),
+ PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT),
+ PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT),
+ PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT),
+ PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT),
+
+ /* PTI GPIO */
+ PINMUX_DATA(PTI7_DATA, PTI7_IN, PTI7_OUT),
+ PINMUX_DATA(PTI6_DATA, PTI6_IN, PTI6_OUT),
+ PINMUX_DATA(PTI5_DATA, PTI5_IN, PTI5_OUT),
+ PINMUX_DATA(PTI4_DATA, PTI4_IN, PTI4_OUT),
+ PINMUX_DATA(PTI3_DATA, PTI3_IN, PTI3_OUT),
+ PINMUX_DATA(PTI2_DATA, PTI2_IN, PTI2_OUT),
+ PINMUX_DATA(PTI1_DATA, PTI1_IN, PTI1_OUT),
+ PINMUX_DATA(PTI0_DATA, PTI0_IN, PTI0_OUT),
+
+ /* PTJ GPIO */
+ PINMUX_DATA(PTJ6_DATA, PTJ6_IN, PTJ6_OUT),
+ PINMUX_DATA(PTJ5_DATA, PTJ5_IN, PTJ5_OUT),
+ PINMUX_DATA(PTJ4_DATA, PTJ4_IN, PTJ4_OUT),
+ PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT),
+ PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT),
+ PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT),
+ PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT),
+
+ /* PTK GPIO */
+ PINMUX_DATA(PTK7_DATA, PTK7_IN, PTK7_OUT),
+ PINMUX_DATA(PTK6_DATA, PTK6_IN, PTK6_OUT),
+ PINMUX_DATA(PTK5_DATA, PTK5_IN, PTK5_OUT),
+ PINMUX_DATA(PTK4_DATA, PTK4_IN, PTK4_OUT),
+ PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT),
+ PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT),
+ PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT),
+ PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT),
+
+ /* PTL GPIO */
+ PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT),
+ PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT),
+ PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT),
+ PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT),
+ PINMUX_DATA(PTL2_DATA, PTL2_IN, PTL2_OUT),
+ PINMUX_DATA(PTL1_DATA, PTL1_IN, PTL1_OUT),
+ PINMUX_DATA(PTL0_DATA, PTL0_IN, PTL0_OUT),
+
+ /* PTM GPIO */
+ PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT),
+ PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT),
+ PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT),
+ PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT),
+ PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT),
+ PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT),
+ PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT),
+
+ /* PTN GPIO */
+ PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT),
+ PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT),
+ PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT),
+ PINMUX_DATA(PTN3_DATA, PTN3_IN, PTN3_OUT),
+ PINMUX_DATA(PTN2_DATA, PTN2_IN, PTN2_OUT),
+ PINMUX_DATA(PTN1_DATA, PTN1_IN, PTN1_OUT),
+ PINMUX_DATA(PTN0_DATA, PTN0_IN, PTN0_OUT),
+
+ /* PTO GPIO */
+ PINMUX_DATA(PTO7_DATA, PTO7_IN, PTO7_OUT),
+ PINMUX_DATA(PTO6_DATA, PTO6_IN, PTO6_OUT),
+ PINMUX_DATA(PTO5_DATA, PTO5_IN, PTO5_OUT),
+ PINMUX_DATA(PTO4_DATA, PTO4_IN, PTO4_OUT),
+ PINMUX_DATA(PTO3_DATA, PTO3_IN, PTO3_OUT),
+ PINMUX_DATA(PTO2_DATA, PTO2_IN, PTO2_OUT),
+ PINMUX_DATA(PTO1_DATA, PTO1_IN, PTO1_OUT),
+ PINMUX_DATA(PTO0_DATA, PTO0_IN, PTO0_OUT),
+
+ /* PTQ GPIO */
+ PINMUX_DATA(PTQ6_DATA, PTQ6_IN, PTQ6_OUT),
+ PINMUX_DATA(PTQ5_DATA, PTQ5_IN, PTQ5_OUT),
+ PINMUX_DATA(PTQ4_DATA, PTQ4_IN, PTQ4_OUT),
+ PINMUX_DATA(PTQ3_DATA, PTQ3_IN, PTQ3_OUT),
+ PINMUX_DATA(PTQ2_DATA, PTQ2_IN, PTQ2_OUT),
+ PINMUX_DATA(PTQ1_DATA, PTQ1_IN, PTQ1_OUT),
+ PINMUX_DATA(PTQ0_DATA, PTQ0_IN, PTQ0_OUT),
+
+ /* PTR GPIO */
+ PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT),
+ PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT),
+ PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT),
+ PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT),
+ PINMUX_DATA(PTR3_DATA, PTR3_IN, PTR3_OUT),
+ PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_OUT),
+ PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT),
+ PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT),
+
+ /* PTS GPIO */
+ PINMUX_DATA(PTS7_DATA, PTS7_IN, PTS7_OUT),
+ PINMUX_DATA(PTS6_DATA, PTS6_IN, PTS6_OUT),
+ PINMUX_DATA(PTS5_DATA, PTS5_IN, PTS5_OUT),
+ PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT),
+ PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT),
+ PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT),
+ PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT),
+ PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT),
+
+ /* PTT GPIO */
+ PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT),
+ PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT),
+ PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT),
+ PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT),
+ PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT),
+ PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT),
+ PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT),
+ PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT),
+
+ /* PTU GPIO */
+ PINMUX_DATA(PTU7_DATA, PTU7_IN, PTU7_OUT),
+ PINMUX_DATA(PTU6_DATA, PTU6_IN, PTU6_OUT),
+ PINMUX_DATA(PTU5_DATA, PTU5_IN, PTU5_OUT),
+ PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT),
+ PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT),
+ PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT),
+ PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT),
+ PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT),
+
+ /* PTV GPIO */
+ PINMUX_DATA(PTV7_DATA, PTV7_IN, PTV7_OUT),
+ PINMUX_DATA(PTV6_DATA, PTV6_IN, PTV6_OUT),
+ PINMUX_DATA(PTV5_DATA, PTV5_IN, PTV5_OUT),
+ PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT),
+ PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT),
+ PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT),
+ PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT),
+ PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT),
+
+ /* PTW GPIO */
+ PINMUX_DATA(PTW7_DATA, PTW7_IN, PTW7_OUT),
+ PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_OUT),
+ PINMUX_DATA(PTW5_DATA, PTW5_IN, PTW5_OUT),
+ PINMUX_DATA(PTW4_DATA, PTW4_IN, PTW4_OUT),
+ PINMUX_DATA(PTW3_DATA, PTW3_IN, PTW3_OUT),
+ PINMUX_DATA(PTW2_DATA, PTW2_IN, PTW2_OUT),
+ PINMUX_DATA(PTW1_DATA, PTW1_IN, PTW1_OUT),
+ PINMUX_DATA(PTW0_DATA, PTW0_IN, PTW0_OUT),
+
+ /* PTX GPIO */
+ PINMUX_DATA(PTX7_DATA, PTX7_IN, PTX7_OUT),
+ PINMUX_DATA(PTX6_DATA, PTX6_IN, PTX6_OUT),
+ PINMUX_DATA(PTX5_DATA, PTX5_IN, PTX5_OUT),
+ PINMUX_DATA(PTX4_DATA, PTX4_IN, PTX4_OUT),
+ PINMUX_DATA(PTX3_DATA, PTX3_IN, PTX3_OUT),
+ PINMUX_DATA(PTX2_DATA, PTX2_IN, PTX2_OUT),
+ PINMUX_DATA(PTX1_DATA, PTX1_IN, PTX1_OUT),
+ PINMUX_DATA(PTX0_DATA, PTX0_IN, PTX0_OUT),
+
+ /* PTY GPIO */
+ PINMUX_DATA(PTY7_DATA, PTY7_IN, PTY7_OUT),
+ PINMUX_DATA(PTY6_DATA, PTY6_IN, PTY6_OUT),
+ PINMUX_DATA(PTY5_DATA, PTY5_IN, PTY5_OUT),
+ PINMUX_DATA(PTY4_DATA, PTY4_IN, PTY4_OUT),
+ PINMUX_DATA(PTY3_DATA, PTY3_IN, PTY3_OUT),
+ PINMUX_DATA(PTY2_DATA, PTY2_IN, PTY2_OUT),
+ PINMUX_DATA(PTY1_DATA, PTY1_IN, PTY1_OUT),
+ PINMUX_DATA(PTY0_DATA, PTY0_IN, PTY0_OUT),
+
+ /* PTZ GPIO */
+ PINMUX_DATA(PTZ7_DATA, PTZ7_IN, PTZ7_OUT),
+ PINMUX_DATA(PTZ6_DATA, PTZ6_IN, PTZ6_OUT),
+ PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_OUT),
+ PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_OUT),
+ PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_OUT),
+ PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_OUT),
+ PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_OUT),
+ PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT),
+
+ /* PTA FN */
+ PINMUX_DATA(BS_MARK, PTA7_FN),
+ PINMUX_DATA(RDWR_MARK, PTA6_FN),
+ PINMUX_DATA(WE1_MARK, PTA5_FN),
+ PINMUX_DATA(RDY_MARK, PTA4_FN),
+ PINMUX_DATA(ET0_MDC_MARK, PTA3_FN),
+ PINMUX_DATA(ET0_MDIO_MARK, PTA2_FN),
+ PINMUX_DATA(ET1_MDC_MARK, PTA1_FN),
+ PINMUX_DATA(ET1_MDIO_MARK, PTA0_FN),
+
+ /* PTB FN */
+ PINMUX_DATA(IRQ15_MARK, PS0_15_FN1, PTB7_FN),
+ PINMUX_DATA(ON_NRE_MARK, PS0_15_FN2, PTB7_FN),
+ PINMUX_DATA(IRQ14_MARK, PS0_14_FN1, PTB6_FN),
+ PINMUX_DATA(ON_NWE_MARK, PS0_14_FN2, PTB6_FN),
+ PINMUX_DATA(IRQ13_MARK, PS0_13_FN1, PTB5_FN),
+ PINMUX_DATA(ON_NWP_MARK, PS0_13_FN2, PTB5_FN),
+ PINMUX_DATA(IRQ12_MARK, PS0_12_FN1, PTB4_FN),
+ PINMUX_DATA(ON_NCE0_MARK, PS0_12_FN2, PTB4_FN),
+ PINMUX_DATA(IRQ11_MARK, PS0_11_FN1, PTB3_FN),
+ PINMUX_DATA(ON_R_B0_MARK, PS0_11_FN2, PTB3_FN),
+ PINMUX_DATA(IRQ10_MARK, PS0_10_FN1, PTB2_FN),
+ PINMUX_DATA(ON_ALE_MARK, PS0_10_FN2, PTB2_FN),
+ PINMUX_DATA(IRQ9_MARK, PS0_9_FN1, PTB1_FN),
+ PINMUX_DATA(ON_CLE_MARK, PS0_9_FN2, PTB1_FN),
+ PINMUX_DATA(IRQ8_MARK, PS0_8_FN1, PTB0_FN),
+ PINMUX_DATA(TCLK_MARK, PS0_8_FN2, PTB0_FN),
+
+ /* PTC FN */
+ PINMUX_DATA(IRQ7_MARK, PS0_7_FN1, PTC7_FN),
+ PINMUX_DATA(PWMU0_MARK, PS0_7_FN2, PTC7_FN),
+ PINMUX_DATA(IRQ6_MARK, PS0_6_FN1, PTC6_FN),
+ PINMUX_DATA(PWMU1_MARK, PS0_6_FN2, PTC6_FN),
+ PINMUX_DATA(IRQ5_MARK, PS0_5_FN1, PTC5_FN),
+ PINMUX_DATA(PWMU2_MARK, PS0_5_FN2, PTC5_FN),
+ PINMUX_DATA(IRQ4_MARK, PS0_4_FN1, PTC5_FN),
+ PINMUX_DATA(PWMU3_MARK, PS0_4_FN2, PTC4_FN),
+ PINMUX_DATA(IRQ3_MARK, PS0_3_FN1, PTC3_FN),
+ PINMUX_DATA(PWMU4_MARK, PS0_3_FN2, PTC3_FN),
+ PINMUX_DATA(IRQ2_MARK, PS0_2_FN1, PTC2_FN),
+ PINMUX_DATA(PWMU5_MARK, PS0_2_FN2, PTC2_FN),
+ PINMUX_DATA(IRQ1_MARK, PTC1_FN),
+ PINMUX_DATA(IRQ0_MARK, PTC0_FN),
+
+ /* PTD FN */
+ PINMUX_DATA(SP0_MOSI_MARK, PTD7_FN),
+ PINMUX_DATA(SP0_MISO_MARK, PTD6_FN),
+ PINMUX_DATA(SP0_SCK_MARK, PTD5_FN),
+ PINMUX_DATA(SP0_SCK_FB_MARK, PTD4_FN),
+ PINMUX_DATA(SP0_SS0_MARK, PTD3_FN),
+ PINMUX_DATA(SP0_SS1_MARK, PS1_10_FN1, PTD2_FN),
+ PINMUX_DATA(DREQ0_MARK, PS1_10_FN2, PTD2_FN),
+ PINMUX_DATA(SP0_SS2_MARK, PS1_9_FN1, PTD1_FN),
+ PINMUX_DATA(DACK0_MARK, PS1_9_FN2, PTD1_FN),
+ PINMUX_DATA(SP0_SS3_MARK, PS1_8_FN1, PTD0_FN),
+ PINMUX_DATA(TEND0_MARK, PS1_8_FN2, PTD0_FN),
+
+ /* PTE FN */
+ PINMUX_DATA(RMII0_CRS_DV_MARK, PTE7_FN),
+ PINMUX_DATA(RMII0_TXD1_MARK, PTE6_FN),
+ PINMUX_DATA(RMII0_TXD0_MARK, PTE5_FN),
+ PINMUX_DATA(RMII0_TXEN_MARK, PTE4_FN),
+ PINMUX_DATA(RMII0_REFCLK_MARK, PTE3_FN),
+ PINMUX_DATA(RMII0_RXD1_MARK, PTE2_FN),
+ PINMUX_DATA(RMII0_RXD0_MARK, PTE1_FN),
+ PINMUX_DATA(RMII0_RX_ER_MARK, PTE0_FN),
+
+ /* PTF FN */
+ PINMUX_DATA(RMII1_CRS_DV_MARK, PTF7_FN),
+ PINMUX_DATA(RMII1_TXD1_MARK, PTF6_FN),
+ PINMUX_DATA(RMII1_TXD0_MARK, PTF5_FN),
+ PINMUX_DATA(RMII1_TXEN_MARK, PTF4_FN),
+ PINMUX_DATA(RMII1_REFCLK_MARK, PTF3_FN),
+ PINMUX_DATA(RMII1_RXD1_MARK, PS1_2_FN1, PTF2_FN),
+ PINMUX_DATA(RAC_RI_MARK, PS1_2_FN2, PTF2_FN),
+ PINMUX_DATA(RMII1_RXD0_MARK, PTF1_FN),
+ PINMUX_DATA(RMII1_RX_ER_MARK, PTF0_FN),
+
+ /* PTG FN */
+ PINMUX_DATA(BOOTFMS_MARK, PTG7_FN),
+ PINMUX_DATA(BOOTWP_MARK, PTG6_FN),
+ PINMUX_DATA(A25_MARK, PS2_13_FN1, PTG5_FN),
+ PINMUX_DATA(MMCCLK_MARK, PS2_13_FN2, PTG5_FN),
+ PINMUX_DATA(A24_MARK, PS2_12_FN1, PTG4_FN),
+ PINMUX_DATA(MMCCMD_MARK, PS2_12_FN2, PTG4_FN),
+ PINMUX_DATA(SERIRQ_MARK, PTG3_FN),
+ PINMUX_DATA(WDTOVF_MARK, PTG2_FN),
+ PINMUX_DATA(LPCPD_MARK, PTG1_FN),
+ PINMUX_DATA(LDRQ_MARK, PTG0_FN),
+
+ /* PTH FN */
+ PINMUX_DATA(SP1_MOSI_MARK, PS2_7_FN1, PTH7_FN),
+ PINMUX_DATA(TEND1_MARK, PS2_7_FN2, PTH7_FN),
+ PINMUX_DATA(SP1_MISO_MARK, PS2_6_FN1, PTH6_FN),
+ PINMUX_DATA(DREQ1_MARK, PS2_6_FN2, PTH6_FN),
+ PINMUX_DATA(SP1_SCK_MARK, PS2_5_FN1, PTH5_FN),
+ PINMUX_DATA(DACK1_MARK, PS2_5_FN2, PTH5_FN),
+ PINMUX_DATA(SP1_SCK_FB_MARK, PS2_4_FN1, PTH4_FN),
+ PINMUX_DATA(ADTRG1_MARK, PS2_4_FN2, PTH4_FN),
+ PINMUX_DATA(SP1_SS0_MARK, PTH3_FN),
+ PINMUX_DATA(SP1_SS1_MARK, PS2_2_FN1, PTH2_FN),
+ PINMUX_DATA(ADTRG0_MARK, PS2_2_FN2, PTH2_FN),
+ PINMUX_DATA(WP_MARK, PTH1_FN),
+ PINMUX_DATA(FMS0_MARK, PTH0_FN),
+
+ /* PTI FN */
+ PINMUX_DATA(D15_MARK, PS3_15_FN1, PTI7_FN),
+ PINMUX_DATA(SD_WP_MARK, PS3_15_FN2, PTI7_FN),
+ PINMUX_DATA(D14_MARK, PS3_14_FN1, PTI6_FN),
+ PINMUX_DATA(SD_CD_MARK, PS3_14_FN2, PTI6_FN),
+ PINMUX_DATA(D13_MARK, PS3_13_FN1, PTI5_FN),
+ PINMUX_DATA(SD_CLK_MARK, PS3_13_FN2, PTI5_FN),
+ PINMUX_DATA(D12_MARK, PS3_12_FN1, PTI4_FN),
+ PINMUX_DATA(SD_CMD_MARK, PS3_12_FN2, PTI4_FN),
+ PINMUX_DATA(D11_MARK, PS3_11_FN1, PTI3_FN),
+ PINMUX_DATA(SD_D3_MARK, PS3_11_FN2, PTI3_FN),
+ PINMUX_DATA(D10_MARK, PS3_10_FN1, PTI2_FN),
+ PINMUX_DATA(SD_D2_MARK, PS3_10_FN2, PTI2_FN),
+ PINMUX_DATA(D9_MARK, PS3_9_FN1, PTI1_FN),
+ PINMUX_DATA(SD_D1_MARK, PS3_9_FN2, PTI1_FN),
+ PINMUX_DATA(D8_MARK, PS3_8_FN1, PTI0_FN),
+ PINMUX_DATA(SD_D0_MARK, PS3_8_FN2, PTI0_FN),
+
+ /* PTJ FN */
+ PINMUX_DATA(RTS3_MARK, PTJ6_FN),
+ PINMUX_DATA(CTS3_MARK, PTJ5_FN),
+ PINMUX_DATA(TXD3_MARK, PTJ4_FN),
+ PINMUX_DATA(RXD3_MARK, PTJ3_FN),
+ PINMUX_DATA(RTS4_MARK, PTJ2_FN),
+ PINMUX_DATA(RXD4_MARK, PTJ1_FN),
+ PINMUX_DATA(TXD4_MARK, PTJ0_FN),
+
+ /* PTK FN */
+ PINMUX_DATA(COM2_TXD_MARK, PS3_7_FN1, PTK7_FN),
+ PINMUX_DATA(SCK2_MARK, PS3_7_FN2, PTK7_FN),
+ PINMUX_DATA(COM2_RXD_MARK, PTK6_FN),
+ PINMUX_DATA(COM2_RTS_MARK, PTK5_FN),
+ PINMUX_DATA(COM2_CTS_MARK, PTK4_FN),
+ PINMUX_DATA(COM2_DTR_MARK, PTK3_FN),
+ PINMUX_DATA(COM2_DSR_MARK, PS3_2_FN1, PTK2_FN),
+ PINMUX_DATA(SCK4_MARK, PS3_2_FN2, PTK2_FN),
+ PINMUX_DATA(COM2_DCD_MARK, PS3_1_FN1, PTK1_FN),
+ PINMUX_DATA(SCK3_MARK, PS3_1_FN2, PTK1_FN),
+ PINMUX_DATA(CLKOUT_MARK, PTK0_FN),
+
+ /* PTL FN */
+ PINMUX_DATA(RAC_RXD_MARK, PS4_14_FN1, PTL6_FN),
+ PINMUX_DATA(RXD2_MARK, PS4_14_FN2, PTL6_FN),
+ PINMUX_DATA(RAC_RTS_MARK, PS4_13_FN1, PTL5_FN),
+ PINMUX_DATA(CS5_MARK, PS4_13_FN2, PTL5_FN),
+ PINMUX_DATA(RAC_CTS_MARK, PS4_12_FN1, PTL4_FN),
+ PINMUX_DATA(CS6_MARK, PS4_12_FN2, PTL4_FN),
+ PINMUX_DATA(RAC_DTR_MARK, PTL3_FN),
+ PINMUX_DATA(RAC_DSR_MARK, PS4_10_FN1, PTL2_FN),
+ PINMUX_DATA(AUDSYNC_MARK, PS4_10_FN2, PTL2_FN),
+ PINMUX_DATA(RAC_DCD_MARK, PS4_9_FN1, PTL1_FN),
+ PINMUX_DATA(AUDCK_MARK, PS4_9_FN2, PTL1_FN),
+ PINMUX_DATA(RAC_TXD_MARK, PS4_8_FN1, PTL0_FN),
+ PINMUX_DATA(TXD2_MARK, PS4_8_FN1, PTL0_FN),
+
+ /* PTM FN */
+ PINMUX_DATA(CS4_MARK, PTM7_FN),
+ PINMUX_DATA(RD_MARK, PTM6_FN),
+ PINMUX_DATA(WE0_MARK, PTM7_FN),
+ PINMUX_DATA(CS0_MARK, PTM4_FN),
+ PINMUX_DATA(SDA6_MARK, PTM3_FN),
+ PINMUX_DATA(SCL6_MARK, PTM2_FN),
+ PINMUX_DATA(SDA7_MARK, PTM1_FN),
+ PINMUX_DATA(SCL7_MARK, PTM0_FN),
+
+ /* PTN FN */
+ PINMUX_DATA(VBUS_EN_MARK, PTN6_FN),
+ PINMUX_DATA(VBUS_OC_MARK, PTN5_FN),
+ PINMUX_DATA(JMCTCK_MARK, PS4_4_FN1, PTN4_FN),
+ PINMUX_DATA(SGPIO1_CLK_MARK, PS4_4_FN2, PTN4_FN),
+ PINMUX_DATA(JMCTMS_MARK, PS4_3_FN1, PTN5_FN),
+ PINMUX_DATA(SGPIO1_LOAD_MARK, PS4_3_FN2, PTN5_FN),
+ PINMUX_DATA(JMCTDO_MARK, PS4_2_FN1, PTN2_FN),
+ PINMUX_DATA(SGPIO1_DO_MARK, PS4_2_FN2, PTN2_FN),
+ PINMUX_DATA(JMCTDI_MARK, PS4_1_FN1, PTN1_FN),
+ PINMUX_DATA(SGPIO1_DI_MARK, PS4_1_FN2, PTN1_FN),
+ PINMUX_DATA(JMCTRST_MARK, PS4_0_FN1, PTN0_FN),
+ PINMUX_DATA(SUB_CLKIN_MARK, PS4_0_FN2, PTN0_FN),
+
+ /* PTO FN */
+ PINMUX_DATA(SGPIO0_CLK_MARK, PTO7_FN),
+ PINMUX_DATA(SGPIO0_LOAD_MARK, PTO6_FN),
+ PINMUX_DATA(SGPIO0_DI_MARK, PTO5_FN),
+ PINMUX_DATA(SGPIO0_DO_MARK, PTO4_FN),
+ PINMUX_DATA(SGPIO2_CLK_MARK, PS5_11_FN1, PTO3_FN),
+ PINMUX_DATA(COM1_TXD_MARK, PS5_11_FN2, PTO3_FN),
+ PINMUX_DATA(SGPIO2_LOAD_MARK, PS5_10_FN1, PTO2_FN),
+ PINMUX_DATA(COM1_RXD_MARK, PS5_10_FN2, PTO2_FN),
+ PINMUX_DATA(SGPIO2_DI_MARK, PS5_9_FN1, PTO1_FN),
+ PINMUX_DATA(COM1_RTS_MARK, PS5_9_FN2, PTO1_FN),
+ PINMUX_DATA(SGPIO2_DO_MARK, PS5_8_FN1, PTO0_FN),
+ PINMUX_DATA(COM1_CTS_MARK, PS5_8_FN2, PTO0_FN),
+
+ /* PTP FN */
+
+ /* PTQ FN */
+ PINMUX_DATA(LAD3_MARK, PTQ6_FN),
+ PINMUX_DATA(LAD2_MARK, PTQ5_FN),
+ PINMUX_DATA(LAD1_MARK, PTQ4_FN),
+ PINMUX_DATA(LAD0_MARK, PTQ3_FN),
+ PINMUX_DATA(LFRAME_MARK, PTQ2_FN),
+ PINMUX_DATA(LRESET_MARK, PTQ1_FN),
+ PINMUX_DATA(LCLK_MARK, PTQ0_FN),
+
+ /* PTR FN */
+ PINMUX_DATA(SDA8_MARK, PTR7_FN), /* DDC3? */
+ PINMUX_DATA(SCL8_MARK, PTR6_FN), /* DDC2? */
+ PINMUX_DATA(SDA2_MARK, PTR5_FN),
+ PINMUX_DATA(SCL2_MARK, PTR4_FN),
+ PINMUX_DATA(SDA1_MARK, PTR3_FN),
+ PINMUX_DATA(SCL1_MARK, PTR2_FN),
+ PINMUX_DATA(SDA0_MARK, PTR1_FN),
+ PINMUX_DATA(SCL0_MARK, PTR0_FN),
+
+ /* PTS FN */
+ PINMUX_DATA(SDA9_MARK, PTS7_FN), /* DDC1? */
+ PINMUX_DATA(SCL9_MARK, PTS6_FN), /* DDC0? */
+ PINMUX_DATA(SDA5_MARK, PTS5_FN),
+ PINMUX_DATA(SCL5_MARK, PTS4_FN),
+ PINMUX_DATA(SDA4_MARK, PTS3_FN),
+ PINMUX_DATA(SCL4_MARK, PTS2_FN),
+ PINMUX_DATA(SDA3_MARK, PTS1_FN),
+ PINMUX_DATA(SCL3_MARK, PTS0_FN),
+
+ /* PTT FN */
+ PINMUX_DATA(PWMX7_MARK, PS5_7_FN1, PTT7_FN),
+ PINMUX_DATA(AUDATA3_MARK, PS5_7_FN2, PTT7_FN),
+ PINMUX_DATA(PWMX6_MARK, PS5_6_FN1, PTT6_FN),
+ PINMUX_DATA(AUDATA2_MARK, PS5_6_FN2, PTT6_FN),
+ PINMUX_DATA(PWMX5_MARK, PS5_5_FN1, PTT5_FN),
+ PINMUX_DATA(AUDATA1_MARK, PS5_5_FN2, PTT5_FN),
+ PINMUX_DATA(PWMX4_MARK, PS5_4_FN1, PTT4_FN),
+ PINMUX_DATA(AUDATA0_MARK, PS5_4_FN2, PTT4_FN),
+ PINMUX_DATA(PWMX3_MARK, PS5_3_FN1, PTT3_FN),
+ PINMUX_DATA(STATUS1_MARK, PS5_3_FN2, PTT3_FN),
+ PINMUX_DATA(PWMX2_MARK, PS5_2_FN1, PTT2_FN),
+ PINMUX_DATA(STATUS0_MARK, PS5_2_FN2, PTT2_FN),
+ PINMUX_DATA(PWMX1_MARK, PTT1_FN),
+ PINMUX_DATA(PWMX0_MARK, PTT0_FN),
+
+ /* PTU FN */
+ PINMUX_DATA(LGPIO7_MARK, PS6_15_FN1, PTU7_FN),
+ PINMUX_DATA(APMONCTL_O_MARK, PS6_15_FN2, PTU7_FN),
+ PINMUX_DATA(LGPIO6_MARK, PS6_14_FN1, PTU6_FN),
+ PINMUX_DATA(APMPWBTOUT_O_MARK, PS6_14_FN2, PTU6_FN),
+ PINMUX_DATA(LGPIO5_MARK, PS6_13_FN1, PTU5_FN),
+ PINMUX_DATA(APMSCI_O_MARK, PS6_13_FN2, PTU5_FN),
+ PINMUX_DATA(LGPIO4_MARK, PS6_12_FN1, PTU4_FN),
+ PINMUX_DATA(APMVDDON_MARK, PS6_12_FN2, PTU4_FN),
+ PINMUX_DATA(LGPIO3_MARK, PS6_11_FN1, PTU3_FN),
+ PINMUX_DATA(APMSLPBTN_MARK, PS6_11_FN2, PTU3_FN),
+ PINMUX_DATA(LGPIO2_MARK, PS6_10_FN1, PTU2_FN),
+ PINMUX_DATA(APMPWRBTN_MARK, PS6_10_FN2, PTU2_FN),
+ PINMUX_DATA(LGPIO1_MARK, PS6_9_FN1, PTU1_FN),
+ PINMUX_DATA(APMS5N_MARK, PS6_9_FN2, PTU1_FN),
+ PINMUX_DATA(LGPIO0_MARK, PS6_8_FN1, PTU0_FN),
+ PINMUX_DATA(APMS3N_MARK, PS6_8_FN2, PTU0_FN),
+
+ /* PTV FN */
+ PINMUX_DATA(A23_MARK, PS6_7_FN1, PTV7_FN),
+ PINMUX_DATA(COM2_RI_MARK, PS6_7_FN2, PTV7_FN),
+ PINMUX_DATA(A22_MARK, PS6_6_FN1, PTV6_FN),
+ PINMUX_DATA(R_SPI_MOSI_MARK, PS6_6_FN2, PTV6_FN),
+ PINMUX_DATA(A21_MARK, PS6_5_FN1, PTV5_FN),
+ PINMUX_DATA(R_SPI_MISO_MARK, PS6_5_FN2, PTV5_FN),
+ PINMUX_DATA(A20_MARK, PS6_4_FN1, PTV4_FN),
+ PINMUX_DATA(R_SPI_RSPCK_MARK, PS6_4_FN2, PTV4_FN),
+ PINMUX_DATA(A19_MARK, PS6_3_FN1, PTV3_FN),
+ PINMUX_DATA(R_SPI_SSL0_MARK, PS6_3_FN2, PTV3_FN),
+ PINMUX_DATA(A18_MARK, PS6_2_FN1, PTV2_FN),
+ PINMUX_DATA(R_SPI_SSL1_MARK, PS6_2_FN2, PTV2_FN),
+ PINMUX_DATA(A17_MARK, PS6_1_FN1, PTV1_FN),
+ PINMUX_DATA(EVENT7_MARK, PS6_1_FN2, PTV1_FN),
+ PINMUX_DATA(A16_MARK, PS6_0_FN1, PTV0_FN),
+ PINMUX_DATA(EVENT6_MARK, PS6_0_FN1, PTV0_FN),
+
+ /* PTW FN */
+ PINMUX_DATA(A15_MARK, PS7_15_FN1, PTW7_FN),
+ PINMUX_DATA(EVENT5_MARK, PS7_15_FN2, PTW7_FN),
+ PINMUX_DATA(A14_MARK, PS7_14_FN1, PTW6_FN),
+ PINMUX_DATA(EVENT4_MARK, PS7_14_FN2, PTW6_FN),
+ PINMUX_DATA(A13_MARK, PS7_13_FN1, PTW5_FN),
+ PINMUX_DATA(EVENT3_MARK, PS7_13_FN2, PTW5_FN),
+ PINMUX_DATA(A12_MARK, PS7_12_FN1, PTW4_FN),
+ PINMUX_DATA(EVENT2_MARK, PS7_12_FN2, PTW4_FN),
+ PINMUX_DATA(A11_MARK, PS7_11_FN1, PTW3_FN),
+ PINMUX_DATA(EVENT1_MARK, PS7_11_FN2, PTW3_FN),
+ PINMUX_DATA(A10_MARK, PS7_10_FN1, PTW2_FN),
+ PINMUX_DATA(EVENT0_MARK, PS7_10_FN2, PTW2_FN),
+ PINMUX_DATA(A9_MARK, PS7_9_FN1, PTW1_FN),
+ PINMUX_DATA(CTS4_MARK, PS7_9_FN2, PTW1_FN),
+ PINMUX_DATA(A8_MARK, PS7_8_FN1, PTW0_FN),
+ PINMUX_DATA(CTS2_MARK, PS7_8_FN2, PTW0_FN),
+
+ /* PTX FN */
+ PINMUX_DATA(A7_MARK, PS7_7_FN1, PTX7_FN),
+ PINMUX_DATA(RTS2_MARK, PS7_7_FN2, PTX7_FN),
+ PINMUX_DATA(A6_MARK, PS7_6_FN1, PTX6_FN),
+ PINMUX_DATA(SIM_D_MARK, PS7_6_FN2, PTX6_FN),
+ PINMUX_DATA(A5_MARK, PS7_5_FN1, PTX5_FN),
+ PINMUX_DATA(SIM_CLK_MARK, PS7_5_FN2, PTX5_FN),
+ PINMUX_DATA(A4_MARK, PS7_4_FN1, PTX4_FN),
+ PINMUX_DATA(SIM_RST_MARK, PS7_4_FN2, PTX4_FN),
+ PINMUX_DATA(A3_MARK, PTX3_FN),
+ PINMUX_DATA(A2_MARK, PTX2_FN),
+ PINMUX_DATA(A1_MARK, PTX1_FN),
+ PINMUX_DATA(A0_MARK, PTX0_FN),
+
+ /* PTY FN */
+ PINMUX_DATA(D7_MARK, PTY7_FN),
+ PINMUX_DATA(D6_MARK, PTY6_FN),
+ PINMUX_DATA(D5_MARK, PTY5_FN),
+ PINMUX_DATA(D4_MARK, PTY4_FN),
+ PINMUX_DATA(D3_MARK, PTY3_FN),
+ PINMUX_DATA(D2_MARK, PTY2_FN),
+ PINMUX_DATA(D1_MARK, PTY1_FN),
+ PINMUX_DATA(D0_MARK, PTY0_FN),
+
+ /* PTZ FN */
+ PINMUX_DATA(MMCDAT7_MARK, PS8_15_FN1, PTZ7_FN),
+ PINMUX_DATA(ON_DQ7_MARK, PS8_15_FN2, PTZ7_FN),
+ PINMUX_DATA(MMCDAT6_MARK, PS8_14_FN1, PTZ6_FN),
+ PINMUX_DATA(ON_DQ6_MARK, PS8_14_FN2, PTZ6_FN),
+ PINMUX_DATA(MMCDAT5_MARK, PS8_13_FN1, PTZ5_FN),
+ PINMUX_DATA(ON_DQ5_MARK, PS8_13_FN2, PTZ5_FN),
+ PINMUX_DATA(MMCDAT4_MARK, PS8_12_FN1, PTZ4_FN),
+ PINMUX_DATA(ON_DQ4_MARK, PS8_12_FN2, PTZ4_FN),
+ PINMUX_DATA(MMCDAT3_MARK, PS8_11_FN1, PTZ3_FN),
+ PINMUX_DATA(ON_DQ3_MARK, PS8_11_FN2, PTZ3_FN),
+ PINMUX_DATA(MMCDAT2_MARK, PS8_10_FN1, PTZ2_FN),
+ PINMUX_DATA(ON_DQ2_MARK, PS8_10_FN2, PTZ2_FN),
+ PINMUX_DATA(MMCDAT1_MARK, PS8_9_FN1, PTZ1_FN),
+ PINMUX_DATA(ON_DQ1_MARK, PS8_9_FN2, PTZ1_FN),
+ PINMUX_DATA(MMCDAT0_MARK, PS8_8_FN1, PTZ0_FN),
+ PINMUX_DATA(ON_DQ0_MARK, PS8_8_FN2, PTZ0_FN),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ /* PTA */
+ PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
+ PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
+ PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
+ PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
+ PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
+ PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
+ PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
+ PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+
+ /* PTB */
+ PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
+ PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
+ PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
+ PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
+ PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
+ PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
+ PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
+ PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+
+ /* PTC */
+ PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
+ PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
+ PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
+ PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
+ PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
+ PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
+ PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
+ PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+
+ /* PTD */
+ PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
+ PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
+ PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
+ PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
+ PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
+ PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
+ PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
+ PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+
+ /* PTE */
+ PINMUX_GPIO(GPIO_PTE7, PTE7_DATA),
+ PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
+ PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
+ PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
+ PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
+ PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
+ PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
+ PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+
+ /* PTF */
+ PINMUX_GPIO(GPIO_PTF7, PTF7_DATA),
+ PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
+ PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
+ PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
+ PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
+ PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
+ PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
+ PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+
+ /* PTG */
+ PINMUX_GPIO(GPIO_PTG7, PTG7_DATA),
+ PINMUX_GPIO(GPIO_PTG6, PTG6_DATA),
+ PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
+ PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
+ PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
+ PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
+ PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
+ PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+
+ /* PTH */
+ PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
+ PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
+ PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
+ PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
+ PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
+ PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
+ PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
+ PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+
+ /* PTI */
+ PINMUX_GPIO(GPIO_PTI7, PTI7_DATA),
+ PINMUX_GPIO(GPIO_PTI6, PTI6_DATA),
+ PINMUX_GPIO(GPIO_PTI5, PTI5_DATA),
+ PINMUX_GPIO(GPIO_PTI4, PTI4_DATA),
+ PINMUX_GPIO(GPIO_PTI3, PTI3_DATA),
+ PINMUX_GPIO(GPIO_PTI2, PTI2_DATA),
+ PINMUX_GPIO(GPIO_PTI1, PTI1_DATA),
+ PINMUX_GPIO(GPIO_PTI0, PTI0_DATA),
+
+ /* PTJ */
+ PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
+ PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
+ PINMUX_GPIO(GPIO_PTJ4, PTJ4_DATA),
+ PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
+ PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
+ PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
+ PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+
+ /* PTK */
+ PINMUX_GPIO(GPIO_PTK7, PTK7_DATA),
+ PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
+ PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
+ PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
+ PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
+ PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
+ PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
+ PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+
+ /* PTL */
+ PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
+ PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
+ PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
+ PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
+ PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
+ PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
+ PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
+
+ /* PTM */
+ PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
+ PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
+ PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
+ PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
+ PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
+ PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
+ PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
+ PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+
+ /* PTN */
+ PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
+ PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
+ PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
+ PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
+ PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
+ PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
+ PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
+
+ /* PTO */
+ PINMUX_GPIO(GPIO_PTO7, PTO7_DATA),
+ PINMUX_GPIO(GPIO_PTO6, PTO6_DATA),
+ PINMUX_GPIO(GPIO_PTO5, PTO5_DATA),
+ PINMUX_GPIO(GPIO_PTO4, PTO4_DATA),
+ PINMUX_GPIO(GPIO_PTO3, PTO3_DATA),
+ PINMUX_GPIO(GPIO_PTO2, PTO2_DATA),
+ PINMUX_GPIO(GPIO_PTO1, PTO1_DATA),
+ PINMUX_GPIO(GPIO_PTO0, PTO0_DATA),
+
+ /* PTP */
+ PINMUX_GPIO(GPIO_PTP7, PTP7_DATA),
+ PINMUX_GPIO(GPIO_PTP6, PTP6_DATA),
+ PINMUX_GPIO(GPIO_PTP5, PTP5_DATA),
+ PINMUX_GPIO(GPIO_PTP4, PTP4_DATA),
+ PINMUX_GPIO(GPIO_PTP3, PTP3_DATA),
+ PINMUX_GPIO(GPIO_PTP2, PTP2_DATA),
+ PINMUX_GPIO(GPIO_PTP1, PTP1_DATA),
+ PINMUX_GPIO(GPIO_PTP0, PTP0_DATA),
+
+ /* PTQ */
+ PINMUX_GPIO(GPIO_PTQ6, PTQ6_DATA),
+ PINMUX_GPIO(GPIO_PTQ5, PTQ5_DATA),
+ PINMUX_GPIO(GPIO_PTQ4, PTQ4_DATA),
+ PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
+ PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
+ PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
+ PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
+
+ /* PTR */
+ PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
+ PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
+ PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
+ PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
+ PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
+ PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
+ PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
+ PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+
+ /* PTS */
+ PINMUX_GPIO(GPIO_PTS7, PTS7_DATA),
+ PINMUX_GPIO(GPIO_PTS6, PTS6_DATA),
+ PINMUX_GPIO(GPIO_PTS5, PTS5_DATA),
+ PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
+ PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
+ PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
+ PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
+ PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+
+ /* PTT */
+ PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
+ PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
+ PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
+ PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
+ PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
+ PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
+ PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
+ PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+
+ /* PTU */
+ PINMUX_GPIO(GPIO_PTU7, PTU7_DATA),
+ PINMUX_GPIO(GPIO_PTU6, PTU6_DATA),
+ PINMUX_GPIO(GPIO_PTU5, PTU5_DATA),
+ PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
+ PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
+ PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
+ PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
+ PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+
+ /* PTV */
+ PINMUX_GPIO(GPIO_PTV7, PTV7_DATA),
+ PINMUX_GPIO(GPIO_PTV6, PTV6_DATA),
+ PINMUX_GPIO(GPIO_PTV5, PTV5_DATA),
+ PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
+ PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
+ PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
+ PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
+ PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+
+ /* PTW */
+ PINMUX_GPIO(GPIO_PTW7, PTW7_DATA),
+ PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
+ PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
+ PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
+ PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
+ PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
+ PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
+ PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
+
+ /* PTX */
+ PINMUX_GPIO(GPIO_PTX7, PTX7_DATA),
+ PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
+ PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
+ PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
+ PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
+ PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
+ PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
+ PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
+
+ /* PTY */
+ PINMUX_GPIO(GPIO_PTY7, PTY7_DATA),
+ PINMUX_GPIO(GPIO_PTY6, PTY6_DATA),
+ PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
+ PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
+ PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
+ PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
+ PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
+ PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
+
+ /* PTZ */
+ PINMUX_GPIO(GPIO_PTZ7, PTZ7_DATA),
+ PINMUX_GPIO(GPIO_PTZ6, PTZ6_DATA),
+ PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
+ PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
+ PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
+ PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
+ PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
+ PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
+
+ /* PTA (mobule: LBSC, RGMII) */
+ PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+ PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
+ PINMUX_GPIO(GPIO_FN_WE1, WE1_MARK),
+ PINMUX_GPIO(GPIO_FN_RDY, RDY_MARK),
+ PINMUX_GPIO(GPIO_FN_ET0_MDC, ET0_MDC_MARK),
+ PINMUX_GPIO(GPIO_FN_ET0_MDIO, ET0_MDIO_MARK),
+ PINMUX_GPIO(GPIO_FN_ET1_MDC, ET1_MDC_MARK),
+ PINMUX_GPIO(GPIO_FN_ET1_MDIO, ET1_MDIO_MARK),
+
+ /* PTB (mobule: INTC, ONFI, TMU) */
+ PINMUX_GPIO(GPIO_FN_IRQ15, IRQ15_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ14, IRQ14_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ13, IRQ13_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ12, IRQ12_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ11, IRQ11_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ10, IRQ10_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ9, IRQ9_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ8, IRQ8_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NRE, ON_NRE_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NWE, ON_NWE_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NWP, ON_NWP_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_NCE0, ON_NCE0_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_R_B0, ON_R_B0_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_ALE, ON_ALE_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_CLE, ON_CLE_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
+
+ /* PTC (mobule: IRQ, PWMU) */
+ PINMUX_GPIO(GPIO_FN_IRQ7, IRQ7_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6, IRQ6_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4, IRQ4_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3, IRQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU0, PWMU0_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU1, PWMU1_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU2, PWMU2_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU3, PWMU3_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU4, PWMU4_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMU5, PWMU5_MARK),
+
+ /* PTD (mobule: SPI0, DMAC) */
+ PINMUX_GPIO(GPIO_FN_SP0_MOSI, SP0_MOSI_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_MISO, SP0_MISO_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SCK, SP0_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SCK_FB, SP0_SCK_FB_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS0, SP0_SS0_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS1, SP0_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS2, SP0_SS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SP0_SS3, SP0_SS3_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
+
+ /* PTE (mobule: RMII) */
+ PINMUX_GPIO(GPIO_FN_RMII0_CRS_DV, RMII0_CRS_DV_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_TXD1, RMII0_TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_TXD0, RMII0_TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_TXEN, RMII0_TXEN_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_REFCLK, RMII0_REFCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_RXD1, RMII0_RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_RXD0, RMII0_RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII0_RX_ER, RMII0_RX_ER_MARK),
+
+ /* PTF (mobule: RMII, SerMux) */
+ PINMUX_GPIO(GPIO_FN_RMII1_CRS_DV, RMII1_CRS_DV_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_TXD1, RMII1_TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_TXD0, RMII1_TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_TXEN, RMII1_TXEN_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_REFCLK, RMII1_REFCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_RXD1, RMII1_RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_RXD0, RMII1_RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RMII1_RX_ER, RMII1_RX_ER_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_RI, RAC_RI_MARK),
+
+ /* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+ PINMUX_GPIO(GPIO_FN_BOOTFMS, BOOTFMS_MARK),
+ PINMUX_GPIO(GPIO_FN_BOOTWP, BOOTWP_MARK),
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+ PINMUX_GPIO(GPIO_FN_SERIRQ, SERIRQ_MARK),
+ PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
+ PINMUX_GPIO(GPIO_FN_LPCPD, LPCPD_MARK),
+ PINMUX_GPIO(GPIO_FN_LDRQ, LDRQ_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCCLK, MMCCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCCMD, MMCCMD_MARK),
+
+ /* PTH (mobule: SPI1, LPC, DMAC, ADC) */
+ PINMUX_GPIO(GPIO_FN_SP1_MOSI, SP1_MOSI_MARK),
+ PINMUX_GPIO(GPIO_FN_SP1_MISO, SP1_MISO_MARK),
+ PINMUX_GPIO(GPIO_FN_SP1_SCK, SP1_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SP1_SCK_FB, SP1_SCK_FB_MARK),
+ PINMUX_GPIO(GPIO_FN_SP1_SS0, SP1_SS0_MARK),
+ PINMUX_GPIO(GPIO_FN_SP1_SS1, SP1_SS1_MARK),
+ PINMUX_GPIO(GPIO_FN_WP, WP_MARK),
+ PINMUX_GPIO(GPIO_FN_FMS0, FMS0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_ADTRG1, ADTRG1_MARK),
+ PINMUX_GPIO(GPIO_FN_ADTRG0, ADTRG0_MARK),
+
+ /* PTI (mobule: LBSC, SDHI) */
+ PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+ PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+ PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+ PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+ PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+ PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+ PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+ PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_WP, SD_WP_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_CD, SD_CD_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_CLK, SD_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_CMD, SD_CMD_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D3, SD_D3_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D2, SD_D2_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D1, SD_D1_MARK),
+ PINMUX_GPIO(GPIO_FN_SD_D0, SD_D0_MARK),
+
+ /* PTJ (mobule: SCIF234, SERMUX) */
+ PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS4, RTS4_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+
+ /* PTK (mobule: SERMUX, LBSC, SCIF) */
+ PINMUX_GPIO(GPIO_FN_COM2_TXD, COM2_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_COM2_RXD, COM2_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_COM2_RTS, COM2_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_COM2_CTS, COM2_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_COM2_DTR, COM2_DTR_MARK),
+ PINMUX_GPIO(GPIO_FN_COM2_DSR, COM2_DSR_MARK),
+ PINMUX_GPIO(GPIO_FN_COM2_DCD, COM2_DCD_MARK),
+ PINMUX_GPIO(GPIO_FN_CLKOUT, CLKOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+
+ /* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
+ PINMUX_GPIO(GPIO_FN_RAC_RXD, RAC_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_RTS, RAC_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_CTS, RAC_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_DTR, RAC_DTR_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_DSR, RAC_DSR_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_DCD, RAC_DCD_MARK),
+ PINMUX_GPIO(GPIO_FN_RAC_TXD, RAC_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+
+ /* PTM (mobule: LBSC, IIC) */
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+ PINMUX_GPIO(GPIO_FN_WE0, WE0_MARK),
+ PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA6, SDA6_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL6, SCL6_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA7, SDA7_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL7, SCL7_MARK),
+
+ /* PTN (mobule: USB, JMC, SGPIO, WDT) */
+ PINMUX_GPIO(GPIO_FN_VBUS_EN, VBUS_EN_MARK),
+ PINMUX_GPIO(GPIO_FN_VBUS_OC, VBUS_OC_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTCK, JMCTCK_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTMS, JMCTMS_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTDO, JMCTDO_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTDI, JMCTDI_MARK),
+ PINMUX_GPIO(GPIO_FN_JMCTRST, JMCTRST_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_CLK, SGPIO1_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_LOAD, SGPIO1_LOAD_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_DI, SGPIO1_DI_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO1_DO, SGPIO1_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_SUB_CLKIN, SUB_CLKIN_MARK),
+
+ /* PTO (mobule: SGPIO, SerMux) */
+ PINMUX_GPIO(GPIO_FN_SGPIO0_CLK, SGPIO0_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO0_LOAD, SGPIO0_LOAD_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO0_DI, SGPIO0_DI_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO0_DO, SGPIO0_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_CLK, SGPIO2_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_LOAD, SGPIO2_LOAD_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_DI, SGPIO2_DI_MARK),
+ PINMUX_GPIO(GPIO_FN_SGPIO2_DO, SGPIO2_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_TXD, COM1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_RXD, COM1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_RTS, COM1_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_COM1_CTS, COM1_CTS_MARK),
+
+ /* PTP (mobule: EVC, ADC) */
+
+ /* PTQ (mobule: LPC) */
+ PINMUX_GPIO(GPIO_FN_LAD3, LAD3_MARK),
+ PINMUX_GPIO(GPIO_FN_LAD2, LAD2_MARK),
+ PINMUX_GPIO(GPIO_FN_LAD1, LAD1_MARK),
+ PINMUX_GPIO(GPIO_FN_LAD0, LAD0_MARK),
+ PINMUX_GPIO(GPIO_FN_LFRAME, LFRAME_MARK),
+ PINMUX_GPIO(GPIO_FN_LRESET, LRESET_MARK),
+ PINMUX_GPIO(GPIO_FN_LCLK, LCLK_MARK),
+
+ /* PTR (mobule: GRA, IIC) */
+ PINMUX_GPIO(GPIO_FN_DDC3, DDC3_MARK),
+ PINMUX_GPIO(GPIO_FN_DDC2, DDC2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA8, SDA8_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL8, SCL8_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
+
+ /* PTS (mobule: GRA, IIC) */
+ PINMUX_GPIO(GPIO_FN_DDC1, DDC1_MARK),
+ PINMUX_GPIO(GPIO_FN_DDC0, DDC0_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA9, SDA9_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL9, SCL9_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA5, SDA5_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL5, SCL5_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA4, SDA4_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL4, SCL4_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA3, SDA3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL3, SCL3_MARK),
+
+ /* PTT (mobule: PWMX, AUD) */
+ PINMUX_GPIO(GPIO_FN_PWMX7, PWMX7_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX6, PWMX6_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX5, PWMX5_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX4, PWMX4_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX3, PWMX3_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX2, PWMX2_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX1, PWMX1_MARK),
+ PINMUX_GPIO(GPIO_FN_PWMX0, PWMX0_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
+
+ /* PTU (mobule: LPC, APM) */
+ PINMUX_GPIO(GPIO_FN_LGPIO7, LGPIO7_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO6, LGPIO6_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO5, LGPIO5_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO4, LGPIO4_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO3, LGPIO3_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO2, LGPIO2_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO1, LGPIO1_MARK),
+ PINMUX_GPIO(GPIO_FN_LGPIO0, LGPIO0_MARK),
+ PINMUX_GPIO(GPIO_FN_APMONCTL_O, APMONCTL_O_MARK),
+ PINMUX_GPIO(GPIO_FN_APMPWBTOUT_O, APMPWBTOUT_O_MARK),
+ PINMUX_GPIO(GPIO_FN_APMSCI_O, APMSCI_O_MARK),
+ PINMUX_GPIO(GPIO_FN_APMVDDON, APMVDDON_MARK),
+ PINMUX_GPIO(GPIO_FN_APMSLPBTN, APMSLPBTN_MARK),
+ PINMUX_GPIO(GPIO_FN_APMPWRBTN, APMPWRBTN_MARK),
+ PINMUX_GPIO(GPIO_FN_APMS5N, APMS5N_MARK),
+ PINMUX_GPIO(GPIO_FN_APMS3N, APMS3N_MARK),
+
+ /* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
+ PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+ PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+ PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+ PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
+ PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
+ PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
+ PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
+ PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
+ PINMUX_GPIO(GPIO_FN_COM2_RI, COM2_RI_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_MOSI, R_SPI_MOSI_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_MISO, R_SPI_MISO_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_RSPCK, R_SPI_RSPCK_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_SSL0, R_SPI_SSL0_MARK),
+ PINMUX_GPIO(GPIO_FN_R_SPI_SSL1, R_SPI_SSL1_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT7, EVENT7_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT6, EVENT6_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_DI, VBIOS_DI_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_DO, VBIOS_DO_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_CLK, VBIOS_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_VBIOS_CS, VBIOS_CS_MARK),
+
+ /* PTW (mobule: LBSC, EVC, SCIF) */
+ PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
+ PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
+ PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
+ PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
+ PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
+ PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
+ PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
+ PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
+ PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT5, EVENT5_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT4, EVENT4_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT3, EVENT3_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT2, EVENT2_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT1, EVENT1_MARK),
+ PINMUX_GPIO(GPIO_FN_EVENT0, EVENT0_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS4, CTS4_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS2, CTS2_MARK),
+
+ /* PTX (mobule: LBSC) */
+ PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
+ PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
+ PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
+ PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
+ PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
+ PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
+ PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
+ PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS2, RTS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_D, SIM_D_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_CLK, SIM_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIM_RST, SIM_RST_MARK),
+
+ /* PTY (mobule: LBSC) */
+ PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
+ PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
+ PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
+ PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
+ PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
+ PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
+ PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
+ PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+ /* PTZ (mobule: eMMC, ONFI) */
+ PINMUX_GPIO(GPIO_FN_MMCDAT7, MMCDAT7_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT6, MMCDAT6_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT5, MMCDAT5_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT4, MMCDAT4_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT3, MMCDAT3_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT2, MMCDAT2_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT1, MMCDAT1_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT0, MMCDAT0_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ7, ON_DQ7_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ6, ON_DQ6_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ5, ON_DQ5_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ4, ON_DQ4_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ3, ON_DQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ2, ON_DQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ1, ON_DQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_ON_DQ0, ON_DQ0_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PACR", 0xffec0000, 16, 2) {
+ PTA7_FN, PTA7_OUT, PTA7_IN, PTA7_IN_PU,
+ PTA6_FN, PTA6_OUT, PTA6_IN, PTA6_IN_PU,
+ PTA5_FN, PTA5_OUT, PTA5_IN, PTA5_IN_PU,
+ PTA4_FN, PTA4_OUT, PTA4_IN, PTA4_IN_PU,
+ PTA3_FN, PTA3_OUT, PTA3_IN, PTA3_IN_PU,
+ PTA2_FN, PTA2_OUT, PTA2_IN, PTA2_IN_PU,
+ PTA1_FN, PTA1_OUT, PTA1_IN, PTA1_IN_PU,
+ PTA0_FN, PTA0_OUT, PTA0_IN, PTA0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PBCR", 0xffec0002, 16, 2) {
+ PTB7_FN, PTB7_OUT, PTB7_IN, 0,
+ PTB6_FN, PTB6_OUT, PTB6_IN, 0,
+ PTB5_FN, PTB5_OUT, PTB5_IN, 0,
+ PTB4_FN, PTB4_OUT, PTB4_IN, 0,
+ PTB3_FN, PTB3_OUT, PTB3_IN, 0,
+ PTB2_FN, PTB2_OUT, PTB2_IN, 0,
+ PTB1_FN, PTB1_OUT, PTB1_IN, 0,
+ PTB0_FN, PTB0_OUT, PTB0_IN, 0 }
+ },
+ { PINMUX_CFG_REG("PCCR", 0xffec0004, 16, 2) {
+ PTC7_FN, PTC7_OUT, PTC7_IN, 0,
+ PTC6_FN, PTC6_OUT, PTC6_IN, 0,
+ PTC5_FN, PTC5_OUT, PTC5_IN, 0,
+ PTC4_FN, PTC4_OUT, PTC4_IN, 0,
+ PTC3_FN, PTC3_OUT, PTC3_IN, 0,
+ PTC2_FN, PTC2_OUT, PTC2_IN, 0,
+ PTC1_FN, PTC1_OUT, PTC1_IN, 0,
+ PTC0_FN, PTC0_OUT, PTC0_IN, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR", 0xffec0006, 16, 2) {
+ PTD7_FN, PTD7_OUT, PTD7_IN, PTD7_IN_PU,
+ PTD6_FN, PTD6_OUT, PTD6_IN, PTD6_IN_PU,
+ PTD5_FN, PTD5_OUT, PTD5_IN, PTD5_IN_PU,
+ PTD4_FN, PTD4_OUT, PTD4_IN, PTD4_IN_PU,
+ PTD3_FN, PTD3_OUT, PTD3_IN, PTD3_IN_PU,
+ PTD2_FN, PTD2_OUT, PTD2_IN, PTD2_IN_PU,
+ PTD1_FN, PTD1_OUT, PTD1_IN, PTD1_IN_PU,
+ PTD0_FN, PTD0_OUT, PTD0_IN, PTD0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PECR", 0xffec0008, 16, 2) {
+ PTE7_FN, PTE7_OUT, PTE7_IN, PTE7_IN_PU,
+ PTE6_FN, PTE6_OUT, PTE6_IN, PTE6_IN_PU,
+ PTE5_FN, PTE5_OUT, PTE5_IN, PTE5_IN_PU,
+ PTE4_FN, PTE4_OUT, PTE4_IN, PTE4_IN_PU,
+ PTE3_FN, PTE3_OUT, PTE3_IN, PTE3_IN_PU,
+ PTE2_FN, PTE2_OUT, PTE2_IN, PTE2_IN_PU,
+ PTE1_FN, PTE1_OUT, PTE1_IN, PTE1_IN_PU,
+ PTE0_FN, PTE0_OUT, PTE0_IN, PTE0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PFCR", 0xffec000a, 16, 2) {
+ PTF7_FN, PTF7_OUT, PTF7_IN, PTF7_IN_PU,
+ PTF6_FN, PTF6_OUT, PTF6_IN, PTF6_IN_PU,
+ PTF5_FN, PTF5_OUT, PTF5_IN, PTF5_IN_PU,
+ PTF4_FN, PTF4_OUT, PTF4_IN, PTF4_IN_PU,
+ PTF3_FN, PTF3_OUT, PTF3_IN, PTF3_IN_PU,
+ PTF2_FN, PTF2_OUT, PTF2_IN, PTF2_IN_PU,
+ PTF1_FN, PTF1_OUT, PTF1_IN, PTF1_IN_PU,
+ PTF0_FN, PTF0_OUT, PTF0_IN, PTF0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PGCR", 0xffec000c, 16, 2) {
+ PTG7_FN, PTG7_OUT, PTG7_IN, PTG7_IN_PU ,
+ PTG6_FN, PTG6_OUT, PTG6_IN, PTG6_IN_PU ,
+ PTG5_FN, PTG5_OUT, PTG5_IN, 0,
+ PTG4_FN, PTG4_OUT, PTG4_IN, PTG4_IN_PU ,
+ PTG3_FN, PTG3_OUT, PTG3_IN, 0,
+ PTG2_FN, PTG2_OUT, PTG2_IN, 0,
+ PTG1_FN, PTG1_OUT, PTG1_IN, 0,
+ PTG0_FN, PTG0_OUT, PTG0_IN, 0 }
+ },
+ { PINMUX_CFG_REG("PHCR", 0xffec000e, 16, 2) {
+ PTH7_FN, PTH7_OUT, PTH7_IN, PTH7_IN_PU,
+ PTH6_FN, PTH6_OUT, PTH6_IN, PTH6_IN_PU,
+ PTH5_FN, PTH5_OUT, PTH5_IN, PTH5_IN_PU,
+ PTH4_FN, PTH4_OUT, PTH4_IN, PTH4_IN_PU,
+ PTH3_FN, PTH3_OUT, PTH3_IN, PTH3_IN_PU,
+ PTH2_FN, PTH2_OUT, PTH2_IN, PTH2_IN_PU,
+ PTH1_FN, PTH1_OUT, PTH1_IN, PTH1_IN_PU,
+ PTH0_FN, PTH0_OUT, PTH0_IN, PTH0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PICR", 0xffec0010, 16, 2) {
+ PTI7_FN, PTI7_OUT, PTI7_IN, PTI7_IN_PU,
+ PTI6_FN, PTI6_OUT, PTI6_IN, PTI6_IN_PU,
+ PTI5_FN, PTI5_OUT, PTI5_IN, 0,
+ PTI4_FN, PTI4_OUT, PTI4_IN, PTI4_IN_PU,
+ PTI3_FN, PTI3_OUT, PTI3_IN, PTI3_IN_PU,
+ PTI2_FN, PTI2_OUT, PTI2_IN, PTI2_IN_PU,
+ PTI1_FN, PTI1_OUT, PTI1_IN, PTI1_IN_PU,
+ PTI0_FN, PTI0_OUT, PTI0_IN, PTI0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PJCR", 0xffec0012, 16, 2) {
+ 0, 0, 0, 0, /* reserved: always set 1 */
+ PTJ6_FN, PTJ6_OUT, PTJ6_IN, PTJ6_IN_PU,
+ PTJ5_FN, PTJ5_OUT, PTJ5_IN, PTJ5_IN_PU,
+ PTJ4_FN, PTJ4_OUT, PTJ4_IN, PTJ4_IN_PU,
+ PTJ3_FN, PTJ3_OUT, PTJ3_IN, PTJ3_IN_PU,
+ PTJ2_FN, PTJ2_OUT, PTJ2_IN, PTJ2_IN_PU,
+ PTJ1_FN, PTJ1_OUT, PTJ1_IN, PTJ1_IN_PU,
+ PTJ0_FN, PTJ0_OUT, PTJ0_IN, PTJ0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PKCR", 0xffec0014, 16, 2) {
+ PTK7_FN, PTK7_OUT, PTK7_IN, PTK7_IN_PU,
+ PTK6_FN, PTK6_OUT, PTK6_IN, PTK6_IN_PU,
+ PTK5_FN, PTK5_OUT, PTK5_IN, PTK5_IN_PU,
+ PTK4_FN, PTK4_OUT, PTK4_IN, PTK4_IN_PU,
+ PTK3_FN, PTK3_OUT, PTK3_IN, PTK3_IN_PU,
+ PTK2_FN, PTK2_OUT, PTK2_IN, PTK2_IN_PU,
+ PTK1_FN, PTK1_OUT, PTK1_IN, PTK1_IN_PU,
+ PTK0_FN, PTK0_OUT, PTK0_IN, PTK0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PLCR", 0xffec0016, 16, 2) {
+ 0, 0, 0, 0, /* reserved: always set 1 */
+ PTL6_FN, PTL6_OUT, PTL6_IN, PTL6_IN_PU,
+ PTL5_FN, PTL5_OUT, PTL5_IN, PTL5_IN_PU,
+ PTL4_FN, PTL4_OUT, PTL4_IN, PTL4_IN_PU,
+ PTL3_FN, PTL3_OUT, PTL3_IN, PTL3_IN_PU,
+ PTL2_FN, PTL2_OUT, PTL2_IN, PTL2_IN_PU,
+ PTL1_FN, PTL1_OUT, PTL1_IN, PTL1_IN_PU,
+ PTL0_FN, PTL0_OUT, PTL0_IN, PTL0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PMCR", 0xffec0018, 16, 2) {
+ PTM7_FN, PTM7_OUT, PTM7_IN, PTM7_IN_PU,
+ PTM6_FN, PTM6_OUT, PTM6_IN, PTM6_IN_PU,
+ PTM5_FN, PTM5_OUT, PTM5_IN, PTM5_IN_PU,
+ PTM4_FN, PTM4_OUT, PTM4_IN, PTM4_IN_PU,
+ PTM3_FN, PTM3_OUT, PTM3_IN, 0,
+ PTM2_FN, PTM2_OUT, PTM2_IN, 0,
+ PTM1_FN, PTM1_OUT, PTM1_IN, 0,
+ PTM0_FN, PTM0_OUT, PTM0_IN, 0 }
+ },
+ { PINMUX_CFG_REG("PNCR", 0xffec001a, 16, 2) {
+ 0, 0, 0, 0, /* reserved: always set 1 */
+ PTN6_FN, PTN6_OUT, PTN6_IN, 0,
+ PTN5_FN, PTN5_OUT, PTN5_IN, 0,
+ PTN4_FN, PTN4_OUT, PTN4_IN, PTN4_IN_PU,
+ PTN3_FN, PTN3_OUT, PTN3_IN, PTN3_IN_PU,
+ PTN2_FN, PTN2_OUT, PTN2_IN, PTN2_IN_PU,
+ PTN1_FN, PTN1_OUT, PTN1_IN, PTN1_IN_PU,
+ PTN0_FN, PTN0_OUT, PTN0_IN, PTN0_IN_PU }
+ },
+ { PINMUX_CFG_REG("POCR", 0xffec001c, 16, 2) {
+ PTO7_FN, PTO7_OUT, PTO7_IN, PTO7_IN_PU,
+ PTO6_FN, PTO6_OUT, PTO6_IN, PTO6_IN_PU,
+ PTO5_FN, PTO5_OUT, PTO5_IN, PTO5_IN_PU,
+ PTO4_FN, PTO4_OUT, PTO4_IN, PTO4_IN_PU,
+ PTO3_FN, PTO3_OUT, PTO3_IN, PTO3_IN_PU,
+ PTO2_FN, PTO2_OUT, PTO2_IN, PTO2_IN_PU,
+ PTO1_FN, PTO1_OUT, PTO1_IN, PTO1_IN_PU,
+ PTO0_FN, PTO0_OUT, PTO0_IN, PTO0_IN_PU }
+ },
+#if 0 /* FIXME: Remove it? */
+ { PINMUX_CFG_REG("PPCR", 0xffec001e, 16, 2) {
+ 0, 0, 0, 0, /* reserved: always set 1 */
+ PTP6_FN, PTP6_OUT, PTP6_IN, 0,
+ PTP5_FN, PTP5_OUT, PTP5_IN, 0,
+ PTP4_FN, PTP4_OUT, PTP4_IN, 0,
+ PTP3_FN, PTP3_OUT, PTP3_IN, 0,
+ PTP2_FN, PTP2_OUT, PTP2_IN, 0,
+ PTP1_FN, PTP1_OUT, PTP1_IN, 0,
+ PTP0_FN, PTP0_OUT, PTP0_IN, 0 }
+ },
+#endif
+ { PINMUX_CFG_REG("PQCR", 0xffec0020, 16, 2) {
+ 0, 0, 0, 0, /* reserved: always set 1 */
+ PTQ6_FN, PTQ6_OUT, PTQ6_IN, 0,
+ PTQ5_FN, PTQ5_OUT, PTQ5_IN, 0,
+ PTQ4_FN, PTQ4_OUT, PTQ4_IN, 0,
+ PTQ3_FN, PTQ3_OUT, PTQ3_IN, 0,
+ PTQ2_FN, PTQ2_OUT, PTQ2_IN, 0,
+ PTQ1_FN, PTQ1_OUT, PTQ1_IN, 0,
+ PTQ0_FN, PTQ0_OUT, PTQ0_IN, 0 }
+ },
+ { PINMUX_CFG_REG("PRCR", 0xffec0022, 16, 2) {
+ PTR7_FN, PTR7_OUT, PTR7_IN, 0,
+ PTR6_FN, PTR6_OUT, PTR6_IN, 0,
+ PTR5_FN, PTR5_OUT, PTR5_IN, 0,
+ PTR4_FN, PTR4_OUT, PTR4_IN, 0,
+ PTR3_FN, PTR3_OUT, PTR3_IN, 0,
+ PTR2_FN, PTR2_OUT, PTR2_IN, 0,
+ PTR1_FN, PTR1_OUT, PTR1_IN, 0,
+ PTR0_FN, PTR0_OUT, PTR0_IN, 0 }
+ },
+ { PINMUX_CFG_REG("PSCR", 0xffec0024, 16, 2) {
+ PTS7_FN, PTS7_OUT, PTS7_IN, 0,
+ PTS6_FN, PTS6_OUT, PTS6_IN, 0,
+ PTS5_FN, PTS5_OUT, PTS5_IN, 0,
+ PTS4_FN, PTS4_OUT, PTS4_IN, 0,
+ PTS3_FN, PTS3_OUT, PTS3_IN, 0,
+ PTS2_FN, PTS2_OUT, PTS2_IN, 0,
+ PTS1_FN, PTS1_OUT, PTS1_IN, 0,
+ PTS0_FN, PTS0_OUT, PTS0_IN, 0 }
+ },
+ { PINMUX_CFG_REG("PTCR", 0xffec0026, 16, 2) {
+ PTT7_FN, PTT7_OUT, PTT7_IN, PTO7_IN_PU,
+ PTT6_FN, PTT6_OUT, PTT6_IN, PTO6_IN_PU,
+ PTT5_FN, PTT5_OUT, PTT5_IN, PTO5_IN_PU,
+ PTT4_FN, PTT4_OUT, PTT4_IN, PTO4_IN_PU,
+ PTT3_FN, PTT3_OUT, PTT3_IN, PTO3_IN_PU,
+ PTT2_FN, PTT2_OUT, PTT2_IN, PTO2_IN_PU,
+ PTT1_FN, PTT1_OUT, PTT1_IN, PTO1_IN_PU,
+ PTT0_FN, PTT0_OUT, PTT0_IN, PTO0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PUCR", 0xffec0028, 16, 2) {
+ PTU7_FN, PTU7_OUT, PTU7_IN, PTU7_IN_PU,
+ PTU6_FN, PTU6_OUT, PTU6_IN, PTU6_IN_PU,
+ PTU5_FN, PTU5_OUT, PTU5_IN, PTU5_IN_PU,
+ PTU4_FN, PTU4_OUT, PTU4_IN, PTU4_IN_PU,
+ PTU3_FN, PTU3_OUT, PTU3_IN, PTU3_IN_PU,
+ PTU2_FN, PTU2_OUT, PTU2_IN, PTU2_IN_PU,
+ PTU1_FN, PTU1_OUT, PTU1_IN, PTU1_IN_PU,
+ PTU0_FN, PTU0_OUT, PTU0_IN, PTU0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PVCR", 0xffec002a, 16, 2) {
+ PTV7_FN, PTV7_OUT, PTV7_IN, PTV7_IN_PU,
+ PTV6_FN, PTV6_OUT, PTV6_IN, PTV6_IN_PU,
+ PTV5_FN, PTV5_OUT, PTV5_IN, PTV5_IN_PU,
+ PTV4_FN, PTV4_OUT, PTV4_IN, PTV4_IN_PU,
+ PTV3_FN, PTV3_OUT, PTV3_IN, PTV3_IN_PU,
+ PTV2_FN, PTV2_OUT, PTV2_IN, PTV2_IN_PU,
+ PTV1_FN, PTV1_OUT, PTV1_IN, 0,
+ PTV0_FN, PTV0_OUT, PTV0_IN, 0 }
+ },
+ { PINMUX_CFG_REG("PWCR", 0xffec002c, 16, 2) {
+ PTW7_FN, PTW7_OUT, PTW7_IN, 0,
+ PTW6_FN, PTW6_OUT, PTW6_IN, 0,
+ PTW5_FN, PTW5_OUT, PTW5_IN, 0,
+ PTW4_FN, PTW4_OUT, PTW4_IN, 0,
+ PTW3_FN, PTW3_OUT, PTW3_IN, 0,
+ PTW2_FN, PTW2_OUT, PTW2_IN, 0,
+ PTW1_FN, PTW1_OUT, PTW1_IN, PTW1_IN_PU,
+ PTW0_FN, PTW0_OUT, PTW0_IN, PTW0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PXCR", 0xffec002e, 16, 2) {
+ PTX7_FN, PTX7_OUT, PTX7_IN, PTX7_IN_PU,
+ PTX6_FN, PTX6_OUT, PTX6_IN, PTX6_IN_PU,
+ PTX5_FN, PTX5_OUT, PTX5_IN, PTX5_IN_PU,
+ PTX4_FN, PTX4_OUT, PTX4_IN, PTX4_IN_PU,
+ PTX3_FN, PTX3_OUT, PTX3_IN, PTX3_IN_PU,
+ PTX2_FN, PTX2_OUT, PTX2_IN, PTX2_IN_PU,
+ PTX1_FN, PTX1_OUT, PTX1_IN, PTX1_IN_PU,
+ PTX0_FN, PTX0_OUT, PTX0_IN, PTX0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PYCR", 0xffec0030, 16, 2) {
+ PTY7_FN, PTY7_OUT, PTY7_IN, PTY7_IN_PU,
+ PTY6_FN, PTY6_OUT, PTY6_IN, PTY6_IN_PU,
+ PTY5_FN, PTY5_OUT, PTY5_IN, PTY5_IN_PU,
+ PTY4_FN, PTY4_OUT, PTY4_IN, PTY4_IN_PU,
+ PTY3_FN, PTY3_OUT, PTY3_IN, PTY3_IN_PU,
+ PTY2_FN, PTY2_OUT, PTY2_IN, PTY2_IN_PU,
+ PTY1_FN, PTY1_OUT, PTY1_IN, PTY1_IN_PU,
+ PTY0_FN, PTY0_OUT, PTY0_IN, PTY0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PZCR", 0xffec0032, 16, 2) {
+ PTZ7_FN, PTZ7_OUT, PTZ7_IN, 0,
+ PTZ6_FN, PTZ6_OUT, PTZ6_IN, 0,
+ PTZ5_FN, PTZ5_OUT, PTZ5_IN, 0,
+ PTZ4_FN, PTZ4_OUT, PTZ4_IN, 0,
+ PTZ3_FN, PTZ3_OUT, PTZ3_IN, 0,
+ PTZ2_FN, PTZ2_OUT, PTZ2_IN, 0,
+ PTZ1_FN, PTZ1_OUT, PTZ1_IN, 0,
+ PTZ0_FN, PTZ0_OUT, PTZ0_IN, 0 }
+ },
+
+ { PINMUX_CFG_REG("PSEL0", 0xffec0070, 16, 1) {
+ PS0_15_FN1, PS0_15_FN2,
+ PS0_14_FN1, PS0_14_FN2,
+ PS0_13_FN1, PS0_13_FN2,
+ PS0_12_FN1, PS0_12_FN2,
+ PS0_11_FN1, PS0_11_FN2,
+ PS0_10_FN1, PS0_10_FN2,
+ PS0_9_FN1, PS0_9_FN2,
+ PS0_8_FN1, PS0_8_FN2,
+ PS0_7_FN1, PS0_7_FN2,
+ PS0_6_FN1, PS0_6_FN2,
+ PS0_5_FN1, PS0_5_FN2,
+ PS0_4_FN1, PS0_4_FN2,
+ PS0_3_FN1, PS0_3_FN2,
+ PS0_2_FN1, PS0_2_FN2,
+ 0, 0,
+ 0, 0, }
+ },
+ { PINMUX_CFG_REG("PSEL1", 0xffec0072, 16, 1) {
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PS1_10_FN1, PS1_10_FN2,
+ PS1_9_FN1, PS1_9_FN2,
+ PS1_8_FN1, PS1_8_FN2,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PS1_2_FN1, PS1_2_FN2,
+ 0, 0,
+ 0, 0, }
+ },
+ { PINMUX_CFG_REG("PSEL2", 0xffec0074, 16, 1) {
+ 0, 0,
+ 0, 0,
+ PS2_13_FN1, PS2_13_FN2,
+ PS2_12_FN1, PS2_12_FN2,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PS2_7_FN1, PS2_7_FN2,
+ PS2_6_FN1, PS2_6_FN2,
+ PS2_5_FN1, PS2_5_FN2,
+ PS2_4_FN1, PS2_4_FN2,
+ 0, 0,
+ PS2_2_FN1, PS2_2_FN2,
+ 0, 0,
+ 0, 0, }
+ },
+ { PINMUX_CFG_REG("PSEL3", 0xffec0076, 16, 1) {
+ PS3_15_FN1, PS3_15_FN2,
+ PS3_14_FN1, PS3_14_FN2,
+ PS3_13_FN1, PS3_13_FN2,
+ PS3_12_FN1, PS3_12_FN2,
+ PS3_11_FN1, PS3_11_FN2,
+ PS3_10_FN1, PS3_10_FN2,
+ PS3_9_FN1, PS3_9_FN2,
+ PS3_8_FN1, PS3_8_FN2,
+ PS3_7_FN1, PS3_7_FN2,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PS3_2_FN1, PS3_2_FN2,
+ PS3_1_FN1, PS3_1_FN2,
+ 0, 0, }
+ },
+
+ { PINMUX_CFG_REG("PSEL4", 0xffec0078, 16, 1) {
+ 0, 0,
+ PS4_14_FN1, PS4_14_FN2,
+ PS4_13_FN1, PS4_13_FN2,
+ PS4_12_FN1, PS4_12_FN2,
+ 0, 0,
+ PS4_10_FN1, PS4_10_FN2,
+ PS4_9_FN1, PS4_9_FN2,
+ PS4_8_FN1, PS4_8_FN2,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PS4_4_FN1, PS4_4_FN2,
+ PS4_3_FN1, PS4_3_FN2,
+ PS4_2_FN1, PS4_2_FN2,
+ PS4_1_FN1, PS4_1_FN2,
+ PS4_0_FN1, PS4_0_FN2, }
+ },
+ { PINMUX_CFG_REG("PSEL5", 0xffec007a, 16, 1) {
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ PS5_11_FN1, PS5_11_FN2,
+ PS5_10_FN1, PS5_10_FN2,
+ PS5_9_FN1, PS5_9_FN2,
+ PS5_8_FN1, PS5_8_FN2,
+ PS5_7_FN1, PS5_7_FN2,
+ PS5_6_FN1, PS5_6_FN2,
+ PS5_5_FN1, PS5_5_FN2,
+ PS5_4_FN1, PS5_4_FN2,
+ PS5_3_FN1, PS5_3_FN2,
+ PS5_2_FN1, PS5_2_FN2,
+ 0, 0,
+ 0, 0, }
+ },
+ { PINMUX_CFG_REG("PSEL6", 0xffec007c, 16, 1) {
+ PS6_15_FN1, PS6_15_FN2,
+ PS6_14_FN1, PS6_14_FN2,
+ PS6_13_FN1, PS6_13_FN2,
+ PS6_12_FN1, PS6_12_FN2,
+ PS6_11_FN1, PS6_11_FN2,
+ PS6_10_FN1, PS6_10_FN2,
+ PS6_9_FN1, PS6_9_FN2,
+ PS6_8_FN1, PS6_8_FN2,
+ PS6_7_FN1, PS6_7_FN2,
+ PS6_6_FN1, PS6_6_FN2,
+ PS6_5_FN1, PS6_5_FN2,
+ PS6_4_FN1, PS6_4_FN2,
+ PS6_3_FN1, PS6_3_FN2,
+ PS6_2_FN1, PS6_2_FN2,
+ PS6_1_FN1, PS6_1_FN2,
+ PS6_0_FN1, PS6_0_FN2, }
+ },
+ { PINMUX_CFG_REG("PSEL7", 0xffec0082, 16, 1) {
+ PS7_15_FN1, PS7_15_FN2,
+ PS7_14_FN1, PS7_14_FN2,
+ PS7_13_FN1, PS7_13_FN2,
+ PS7_12_FN1, PS7_12_FN2,
+ PS7_11_FN1, PS7_11_FN2,
+ PS7_10_FN1, PS7_10_FN2,
+ PS7_9_FN1, PS7_9_FN2,
+ PS7_8_FN1, PS7_8_FN2,
+ PS7_7_FN1, PS7_7_FN2,
+ PS7_6_FN1, PS7_6_FN2,
+ PS7_5_FN1, PS7_5_FN2,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0, }
+ },
+ { PINMUX_CFG_REG("PSEL8", 0xffec0084, 16, 1) {
+ PS8_15_FN1, PS8_15_FN2,
+ PS8_14_FN1, PS8_14_FN2,
+ PS8_13_FN1, PS8_13_FN2,
+ PS8_12_FN1, PS8_12_FN2,
+ PS8_11_FN1, PS8_11_FN2,
+ PS8_10_FN1, PS8_10_FN2,
+ PS8_9_FN1, PS8_9_FN2,
+ PS8_8_FN1, PS8_8_FN2,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0, }
+ },
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR", 0xffec0034, 8) {
+ PTA7_DATA, PTA6_DATA, PTA5_DATA, PTA4_DATA,
+ PTA3_DATA, PTA2_DATA, PTA1_DATA, PTA0_DATA }
+ },
+ { PINMUX_DATA_REG("PBDR", 0xffec0036, 8) {
+ PTB7_DATA, PTB6_DATA, PTB5_DATA, PTB4_DATA,
+ PTB3_DATA, PTB2_DATA, PTB1_DATA, PTB0_DATA }
+ },
+ { PINMUX_DATA_REG("PCDR", 0xffec0038, 8) {
+ PTC7_DATA, PTC6_DATA, PTC5_DATA, PTC4_DATA,
+ PTC3_DATA, PTC2_DATA, PTC1_DATA, PTC0_DATA }
+ },
+ { PINMUX_DATA_REG("PDDR", 0xffec003a, 8) {
+ PTD7_DATA, PTD6_DATA, PTD5_DATA, PTD4_DATA,
+ PTD3_DATA, PTD2_DATA, PTD1_DATA, PTD0_DATA }
+ },
+ { PINMUX_DATA_REG("PEDR", 0xffec003c, 8) {
+ PTE7_DATA, PTE6_DATA, PTE5_DATA, PTE4_DATA,
+ PTE3_DATA, PTE2_DATA, PTE1_DATA, PTE0_DATA }
+ },
+ { PINMUX_DATA_REG("PFDR", 0xffec003e, 8) {
+ PTF7_DATA, PTF6_DATA, PTF5_DATA, PTF4_DATA,
+ PTF3_DATA, PTF2_DATA, PTF1_DATA, PTF0_DATA }
+ },
+ { PINMUX_DATA_REG("PGDR", 0xffec0040, 8) {
+ PTG7_DATA, PTG6_DATA, PTG5_DATA, PTG4_DATA,
+ PTG3_DATA, PTG2_DATA, PTG1_DATA, PTG0_DATA }
+ },
+ { PINMUX_DATA_REG("PHDR", 0xffec0042, 8) {
+ PTH7_DATA, PTH6_DATA, PTH5_DATA, PTH4_DATA,
+ PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA }
+ },
+ { PINMUX_DATA_REG("PIDR", 0xffec0044, 8) {
+ PTI7_DATA, PTI6_DATA, PTI5_DATA, PTI4_DATA,
+ PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR", 0xffec0046, 8) {
+ 0, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+ PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
+ },
+ { PINMUX_DATA_REG("PKDR", 0xffec0048, 8) {
+ PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
+ PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
+ },
+ { PINMUX_DATA_REG("PLDR", 0xffec004a, 8) {
+ 0, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+ PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
+ },
+ { PINMUX_DATA_REG("PMDR", 0xffec004c, 8) {
+ PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+ PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
+ },
+ { PINMUX_DATA_REG("PNDR", 0xffec004e, 8) {
+ 0, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+ PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
+ },
+ { PINMUX_DATA_REG("PODR", 0xffec0050, 8) {
+ PTO7_DATA, PTO6_DATA, PTO5_DATA, PTO4_DATA,
+ PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA }
+ },
+ { PINMUX_DATA_REG("PPDR", 0xffec0052, 8) {
+ PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
+ PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA }
+ },
+ { PINMUX_DATA_REG("PQDR", 0xffec0054, 8) {
+ 0, PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+ PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA }
+ },
+ { PINMUX_DATA_REG("PRDR", 0xffec0056, 8) {
+ PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
+ PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA }
+ },
+ { PINMUX_DATA_REG("PSDR", 0xffec0058, 8) {
+ PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
+ PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
+ },
+ { PINMUX_DATA_REG("PTDR", 0xffec005a, 8) {
+ PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
+ PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
+ },
+ { PINMUX_DATA_REG("PUDR", 0xffec005c, 8) {
+ PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
+ PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA }
+ },
+ { PINMUX_DATA_REG("PVDR", 0xffec005e, 8) {
+ PTV7_DATA, PTV6_DATA, PTV5_DATA, PTV4_DATA,
+ PTV3_DATA, PTV2_DATA, PTV1_DATA, PTV0_DATA }
+ },
+ { PINMUX_DATA_REG("PWDR", 0xffec0060, 8) {
+ PTW7_DATA, PTW6_DATA, PTW5_DATA, PTW4_DATA,
+ PTW3_DATA, PTW2_DATA, PTW1_DATA, PTW0_DATA }
+ },
+ { PINMUX_DATA_REG("PXDR", 0xffec0062, 8) {
+ PTX7_DATA, PTX6_DATA, PTX5_DATA, PTX4_DATA,
+ PTX3_DATA, PTX2_DATA, PTX1_DATA, PTX0_DATA }
+ },
+ { PINMUX_DATA_REG("PYDR", 0xffec0064, 8) {
+ PTY7_DATA, PTY6_DATA, PTY5_DATA, PTY4_DATA,
+ PTY3_DATA, PTY2_DATA, PTY1_DATA, PTY0_DATA }
+ },
+ { PINMUX_DATA_REG("PZDR", 0xffec0066, 8) {
+ PTZ7_DATA, PTZ6_DATA, PTZ5_DATA, PTZ4_DATA,
+ PTZ3_DATA, PTZ2_DATA, PTZ1_DATA, PTZ0_DATA }
+ },
+ { },
+};
+
+struct sh_pfc_soc_info sh7757_pinmux_info = {
+ .name = "sh7757_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PTA0,
+ .last_gpio = GPIO_FN_ON_DQ0,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7785.c b/drivers/pinctrl/sh-pfc/pfc-sh7785.c
new file mode 100644
index 000000000000..3b1825d925bb
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7785.c
@@ -0,0 +1,1304 @@
+/*
+ * SH7785 Pinmux
+ *
+ * Copyright (C) 2008 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/init.h>
+#include <linux/kernel.h>
+#include <cpu/sh7785.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+ PE5_DATA, PE4_DATA, PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+ PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
+ PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
+ PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA,
+ PL7_DATA, PL6_DATA, PL5_DATA, PL4_DATA,
+ PL3_DATA, PL2_DATA, PL1_DATA, PL0_DATA,
+ PM1_DATA, PM0_DATA,
+ PN7_DATA, PN6_DATA, PN5_DATA, PN4_DATA,
+ PN3_DATA, PN2_DATA, PN1_DATA, PN0_DATA,
+ PP5_DATA, PP4_DATA, PP3_DATA, PP2_DATA, PP1_DATA, PP0_DATA,
+ PQ4_DATA, PQ3_DATA, PQ2_DATA, PQ1_DATA, PQ0_DATA,
+ PR3_DATA, PR2_DATA, PR1_DATA, PR0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ PA7_IN, PA6_IN, PA5_IN, PA4_IN,
+ PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+ PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+ PB3_IN, PB2_IN, PB1_IN, PB0_IN,
+ PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+ PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+ PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+ PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+ PE5_IN, PE4_IN, PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+ PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+ PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+ PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+ PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+ PH7_IN, PH6_IN, PH5_IN, PH4_IN,
+ PH3_IN, PH2_IN, PH1_IN, PH0_IN,
+ PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+ PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
+ PK7_IN, PK6_IN, PK5_IN, PK4_IN,
+ PK3_IN, PK2_IN, PK1_IN, PK0_IN,
+ PL7_IN, PL6_IN, PL5_IN, PL4_IN,
+ PL3_IN, PL2_IN, PL1_IN, PL0_IN,
+ PM1_IN, PM0_IN,
+ PN7_IN, PN6_IN, PN5_IN, PN4_IN,
+ PN3_IN, PN2_IN, PN1_IN, PN0_IN,
+ PP5_IN, PP4_IN, PP3_IN, PP2_IN, PP1_IN, PP0_IN,
+ PQ4_IN, PQ3_IN, PQ2_IN, PQ1_IN, PQ0_IN,
+ PR3_IN, PR2_IN, PR1_IN, PR0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_INPUT_PULLUP_BEGIN,
+ PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
+ PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
+ PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
+ PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
+ PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
+ PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
+ PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
+ PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
+ PE5_IN_PU, PE4_IN_PU, PE3_IN_PU, PE2_IN_PU, PE1_IN_PU, PE0_IN_PU,
+ PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
+ PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
+ PG7_IN_PU, PG6_IN_PU, PG5_IN_PU, PG4_IN_PU,
+ PG3_IN_PU, PG2_IN_PU, PG1_IN_PU, PG0_IN_PU,
+ PH7_IN_PU, PH6_IN_PU, PH5_IN_PU, PH4_IN_PU,
+ PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
+ PJ7_IN_PU, PJ6_IN_PU, PJ5_IN_PU, PJ4_IN_PU,
+ PJ3_IN_PU, PJ2_IN_PU, PJ1_IN_PU, PJ0_IN_PU,
+ PK7_IN_PU, PK6_IN_PU, PK5_IN_PU, PK4_IN_PU,
+ PK3_IN_PU, PK2_IN_PU, PK1_IN_PU, PK0_IN_PU,
+ PL7_IN_PU, PL6_IN_PU, PL5_IN_PU, PL4_IN_PU,
+ PL3_IN_PU, PL2_IN_PU, PL1_IN_PU, PL0_IN_PU,
+ PM1_IN_PU, PM0_IN_PU,
+ PN7_IN_PU, PN6_IN_PU, PN5_IN_PU, PN4_IN_PU,
+ PN3_IN_PU, PN2_IN_PU, PN1_IN_PU, PN0_IN_PU,
+ PP5_IN_PU, PP4_IN_PU, PP3_IN_PU, PP2_IN_PU, PP1_IN_PU, PP0_IN_PU,
+ PQ4_IN_PU, PQ3_IN_PU, PQ2_IN_PU, PQ1_IN_PU, PQ0_IN_PU,
+ PR3_IN_PU, PR2_IN_PU, PR1_IN_PU, PR0_IN_PU,
+ PINMUX_INPUT_PULLUP_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
+ PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+ PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+ PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
+ PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+ PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+ PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+ PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+ PE5_OUT, PE4_OUT, PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+ PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+ PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+ PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+ PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+ PH7_OUT, PH6_OUT, PH5_OUT, PH4_OUT,
+ PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
+ PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+ PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
+ PK7_OUT, PK6_OUT, PK5_OUT, PK4_OUT,
+ PK3_OUT, PK2_OUT, PK1_OUT, PK0_OUT,
+ PL7_OUT, PL6_OUT, PL5_OUT, PL4_OUT,
+ PL3_OUT, PL2_OUT, PL1_OUT, PL0_OUT,
+ PM1_OUT, PM0_OUT,
+ PN7_OUT, PN6_OUT, PN5_OUT, PN4_OUT,
+ PN3_OUT, PN2_OUT, PN1_OUT, PN0_OUT,
+ PP5_OUT, PP4_OUT, PP3_OUT, PP2_OUT, PP1_OUT, PP0_OUT,
+ PQ4_OUT, PQ3_OUT, PQ2_OUT, PQ1_OUT, PQ0_OUT,
+ PR3_OUT, PR2_OUT, PR1_OUT, PR0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PA7_FN, PA6_FN, PA5_FN, PA4_FN,
+ PA3_FN, PA2_FN, PA1_FN, PA0_FN,
+ PB7_FN, PB6_FN, PB5_FN, PB4_FN,
+ PB3_FN, PB2_FN, PB1_FN, PB0_FN,
+ PC7_FN, PC6_FN, PC5_FN, PC4_FN,
+ PC3_FN, PC2_FN, PC1_FN, PC0_FN,
+ PD7_FN, PD6_FN, PD5_FN, PD4_FN,
+ PD3_FN, PD2_FN, PD1_FN, PD0_FN,
+ PE5_FN, PE4_FN, PE3_FN, PE2_FN, PE1_FN, PE0_FN,
+ PF7_FN, PF6_FN, PF5_FN, PF4_FN,
+ PF3_FN, PF2_FN, PF1_FN, PF0_FN,
+ PG7_FN, PG6_FN, PG5_FN, PG4_FN,
+ PG3_FN, PG2_FN, PG1_FN, PG0_FN,
+ PH7_FN, PH6_FN, PH5_FN, PH4_FN,
+ PH3_FN, PH2_FN, PH1_FN, PH0_FN,
+ PJ7_FN, PJ6_FN, PJ5_FN, PJ4_FN,
+ PJ3_FN, PJ2_FN, PJ1_FN, PJ0_FN,
+ PK7_FN, PK6_FN, PK5_FN, PK4_FN,
+ PK3_FN, PK2_FN, PK1_FN, PK0_FN,
+ PL7_FN, PL6_FN, PL5_FN, PL4_FN,
+ PL3_FN, PL2_FN, PL1_FN, PL0_FN,
+ PM1_FN, PM0_FN,
+ PN7_FN, PN6_FN, PN5_FN, PN4_FN,
+ PN3_FN, PN2_FN, PN1_FN, PN0_FN,
+ PP5_FN, PP4_FN, PP3_FN, PP2_FN, PP1_FN, PP0_FN,
+ PQ4_FN, PQ3_FN, PQ2_FN, PQ1_FN, PQ0_FN,
+ PR3_FN, PR2_FN, PR1_FN, PR0_FN,
+ P1MSEL15_0, P1MSEL15_1,
+ P1MSEL14_0, P1MSEL14_1,
+ P1MSEL13_0, P1MSEL13_1,
+ P1MSEL12_0, P1MSEL12_1,
+ P1MSEL11_0, P1MSEL11_1,
+ P1MSEL10_0, P1MSEL10_1,
+ P1MSEL9_0, P1MSEL9_1,
+ P1MSEL8_0, P1MSEL8_1,
+ P1MSEL7_0, P1MSEL7_1,
+ P1MSEL6_0, P1MSEL6_1,
+ P1MSEL5_0,
+ P1MSEL4_0, P1MSEL4_1,
+ P1MSEL3_0, P1MSEL3_1,
+ P1MSEL2_0, P1MSEL2_1,
+ P1MSEL1_0, P1MSEL1_1,
+ P1MSEL0_0, P1MSEL0_1,
+ P2MSEL2_0, P2MSEL2_1,
+ P2MSEL1_0, P2MSEL1_1,
+ P2MSEL0_0, P2MSEL0_1,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ D63_AD31_MARK,
+ D62_AD30_MARK,
+ D61_AD29_MARK,
+ D60_AD28_MARK,
+ D59_AD27_MARK,
+ D58_AD26_MARK,
+ D57_AD25_MARK,
+ D56_AD24_MARK,
+ D55_AD23_MARK,
+ D54_AD22_MARK,
+ D53_AD21_MARK,
+ D52_AD20_MARK,
+ D51_AD19_MARK,
+ D50_AD18_MARK,
+ D49_AD17_DB5_MARK,
+ D48_AD16_DB4_MARK,
+ D47_AD15_DB3_MARK,
+ D46_AD14_DB2_MARK,
+ D45_AD13_DB1_MARK,
+ D44_AD12_DB0_MARK,
+ D43_AD11_DG5_MARK,
+ D42_AD10_DG4_MARK,
+ D41_AD9_DG3_MARK,
+ D40_AD8_DG2_MARK,
+ D39_AD7_DG1_MARK,
+ D38_AD6_DG0_MARK,
+ D37_AD5_DR5_MARK,
+ D36_AD4_DR4_MARK,
+ D35_AD3_DR3_MARK,
+ D34_AD2_DR2_MARK,
+ D33_AD1_DR1_MARK,
+ D32_AD0_DR0_MARK,
+ REQ1_MARK,
+ REQ2_MARK,
+ REQ3_MARK,
+ GNT1_MARK,
+ GNT2_MARK,
+ GNT3_MARK,
+ MMCCLK_MARK,
+ D31_MARK,
+ D30_MARK,
+ D29_MARK,
+ D28_MARK,
+ D27_MARK,
+ D26_MARK,
+ D25_MARK,
+ D24_MARK,
+ D23_MARK,
+ D22_MARK,
+ D21_MARK,
+ D20_MARK,
+ D19_MARK,
+ D18_MARK,
+ D17_MARK,
+ D16_MARK,
+ SCIF1_SCK_MARK,
+ SCIF1_RXD_MARK,
+ SCIF1_TXD_MARK,
+ SCIF0_CTS_MARK,
+ INTD_MARK,
+ FCE_MARK,
+ SCIF0_RTS_MARK,
+ HSPI_CS_MARK,
+ FSE_MARK,
+ SCIF0_SCK_MARK,
+ HSPI_CLK_MARK,
+ FRE_MARK,
+ SCIF0_RXD_MARK,
+ HSPI_RX_MARK,
+ FRB_MARK,
+ SCIF0_TXD_MARK,
+ HSPI_TX_MARK,
+ FWE_MARK,
+ SCIF5_TXD_MARK,
+ HAC1_SYNC_MARK,
+ SSI1_WS_MARK,
+ SIOF_TXD_PJ_MARK,
+ HAC0_SDOUT_MARK,
+ SSI0_SDATA_MARK,
+ SIOF_RXD_PJ_MARK,
+ HAC0_SDIN_MARK,
+ SSI0_SCK_MARK,
+ SIOF_SYNC_PJ_MARK,
+ HAC0_SYNC_MARK,
+ SSI0_WS_MARK,
+ SIOF_MCLK_PJ_MARK,
+ HAC_RES_MARK,
+ SIOF_SCK_PJ_MARK,
+ HAC0_BITCLK_MARK,
+ SSI0_CLK_MARK,
+ HAC1_BITCLK_MARK,
+ SSI1_CLK_MARK,
+ TCLK_MARK,
+ IOIS16_MARK,
+ STATUS0_MARK,
+ DRAK0_PK3_MARK,
+ STATUS1_MARK,
+ DRAK1_PK2_MARK,
+ DACK2_MARK,
+ SCIF2_TXD_MARK,
+ MMCCMD_MARK,
+ SIOF_TXD_PK_MARK,
+ DACK3_MARK,
+ SCIF2_SCK_MARK,
+ MMCDAT_MARK,
+ SIOF_SCK_PK_MARK,
+ DREQ0_MARK,
+ DREQ1_MARK,
+ DRAK0_PK1_MARK,
+ DRAK1_PK0_MARK,
+ DREQ2_MARK,
+ INTB_MARK,
+ DREQ3_MARK,
+ INTC_MARK,
+ DRAK2_MARK,
+ CE2A_MARK,
+ IRL4_MARK,
+ FD4_MARK,
+ IRL5_MARK,
+ FD5_MARK,
+ IRL6_MARK,
+ FD6_MARK,
+ IRL7_MARK,
+ FD7_MARK,
+ DRAK3_MARK,
+ CE2B_MARK,
+ BREQ_BSACK_MARK,
+ BACK_BSREQ_MARK,
+ SCIF5_RXD_MARK,
+ HAC1_SDIN_MARK,
+ SSI1_SCK_MARK,
+ SCIF5_SCK_MARK,
+ HAC1_SDOUT_MARK,
+ SSI1_SDATA_MARK,
+ SCIF3_TXD_MARK,
+ FCLE_MARK,
+ SCIF3_RXD_MARK,
+ FALE_MARK,
+ SCIF3_SCK_MARK,
+ FD0_MARK,
+ SCIF4_TXD_MARK,
+ FD1_MARK,
+ SCIF4_RXD_MARK,
+ FD2_MARK,
+ SCIF4_SCK_MARK,
+ FD3_MARK,
+ DEVSEL_DCLKOUT_MARK,
+ STOP_CDE_MARK,
+ LOCK_ODDF_MARK,
+ TRDY_DISPL_MARK,
+ IRDY_HSYNC_MARK,
+ PCIFRAME_VSYNC_MARK,
+ INTA_MARK,
+ GNT0_GNTIN_MARK,
+ REQ0_REQOUT_MARK,
+ PERR_MARK,
+ SERR_MARK,
+ WE7_CBE3_MARK,
+ WE6_CBE2_MARK,
+ WE5_CBE1_MARK,
+ WE4_CBE0_MARK,
+ SCIF2_RXD_MARK,
+ SIOF_RXD_MARK,
+ MRESETOUT_MARK,
+ IRQOUT_MARK,
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+ /* PA GPIO */
+ PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
+ PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
+ PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
+ PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
+ PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
+ PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
+ PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
+ PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+
+ /* PB GPIO */
+ PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
+ PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
+ PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
+ PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
+ PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
+ PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
+ PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
+ PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+
+ /* PC GPIO */
+ PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
+ PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
+ PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
+ PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
+ PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
+ PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
+ PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
+ PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+
+ /* PD GPIO */
+ PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
+ PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
+ PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
+ PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
+ PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
+ PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
+ PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
+ PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+
+ /* PE GPIO */
+ PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT, PE5_IN_PU),
+ PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT, PE4_IN_PU),
+ PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT, PE3_IN_PU),
+ PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT, PE2_IN_PU),
+ PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT, PE1_IN_PU),
+ PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT, PE0_IN_PU),
+
+ /* PF GPIO */
+ PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
+ PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
+ PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
+ PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
+ PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
+ PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
+ PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
+ PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+
+ /* PG GPIO */
+ PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
+ PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
+ PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
+ PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT, PG4_IN_PU),
+ PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT, PG3_IN_PU),
+ PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT, PG2_IN_PU),
+ PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT, PG1_IN_PU),
+ PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT, PG0_IN_PU),
+
+ /* PH GPIO */
+ PINMUX_DATA(PH7_DATA, PH7_IN, PH7_OUT, PH7_IN_PU),
+ PINMUX_DATA(PH6_DATA, PH6_IN, PH6_OUT, PH6_IN_PU),
+ PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
+ PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
+ PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
+ PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
+ PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
+ PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+
+ /* PJ GPIO */
+ PINMUX_DATA(PJ7_DATA, PJ7_IN, PJ7_OUT, PJ7_IN_PU),
+ PINMUX_DATA(PJ6_DATA, PJ6_IN, PJ6_OUT, PJ6_IN_PU),
+ PINMUX_DATA(PJ5_DATA, PJ5_IN, PJ5_OUT, PJ5_IN_PU),
+ PINMUX_DATA(PJ4_DATA, PJ4_IN, PJ4_OUT, PJ4_IN_PU),
+ PINMUX_DATA(PJ3_DATA, PJ3_IN, PJ3_OUT, PJ3_IN_PU),
+ PINMUX_DATA(PJ2_DATA, PJ2_IN, PJ2_OUT, PJ2_IN_PU),
+ PINMUX_DATA(PJ1_DATA, PJ1_IN, PJ1_OUT, PJ1_IN_PU),
+ PINMUX_DATA(PJ0_DATA, PJ0_IN, PJ0_OUT, PJ0_IN_PU),
+
+ /* PK GPIO */
+ PINMUX_DATA(PK7_DATA, PK7_IN, PK7_OUT, PK7_IN_PU),
+ PINMUX_DATA(PK6_DATA, PK6_IN, PK6_OUT, PK6_IN_PU),
+ PINMUX_DATA(PK5_DATA, PK5_IN, PK5_OUT, PK5_IN_PU),
+ PINMUX_DATA(PK4_DATA, PK4_IN, PK4_OUT, PK4_IN_PU),
+ PINMUX_DATA(PK3_DATA, PK3_IN, PK3_OUT, PK3_IN_PU),
+ PINMUX_DATA(PK2_DATA, PK2_IN, PK2_OUT, PK2_IN_PU),
+ PINMUX_DATA(PK1_DATA, PK1_IN, PK1_OUT, PK1_IN_PU),
+ PINMUX_DATA(PK0_DATA, PK0_IN, PK0_OUT, PK0_IN_PU),
+
+ /* PL GPIO */
+ PINMUX_DATA(PL7_DATA, PL7_IN, PL7_OUT, PL7_IN_PU),
+ PINMUX_DATA(PL6_DATA, PL6_IN, PL6_OUT, PL6_IN_PU),
+ PINMUX_DATA(PL5_DATA, PL5_IN, PL5_OUT, PL5_IN_PU),
+ PINMUX_DATA(PL4_DATA, PL4_IN, PL4_OUT, PL4_IN_PU),
+ PINMUX_DATA(PL3_DATA, PL3_IN, PL3_OUT, PL3_IN_PU),
+ PINMUX_DATA(PL2_DATA, PL2_IN, PL2_OUT, PL2_IN_PU),
+ PINMUX_DATA(PL1_DATA, PL1_IN, PL1_OUT, PL1_IN_PU),
+ PINMUX_DATA(PL0_DATA, PL0_IN, PL0_OUT, PL0_IN_PU),
+
+ /* PM GPIO */
+ PINMUX_DATA(PM1_DATA, PM1_IN, PM1_OUT, PM1_IN_PU),
+ PINMUX_DATA(PM0_DATA, PM0_IN, PM0_OUT, PM0_IN_PU),
+
+ /* PN GPIO */
+ PINMUX_DATA(PN7_DATA, PN7_IN, PN7_OUT, PN7_IN_PU),
+ PINMUX_DATA(PN6_DATA, PN6_IN, PN6_OUT, PN6_IN_PU),
+ PINMUX_DATA(PN5_DATA, PN5_IN, PN5_OUT, PN5_IN_PU),
+ PINMUX_DATA(PN4_DATA, PN4_IN, PN4_OUT, PN4_IN_PU),
+ PINMUX_DATA(PN3_DATA, PN3_IN, PN3_OUT, PN3_IN_PU),
+ PINMUX_DATA(PN2_DATA, PN2_IN, PN2_OUT, PN2_IN_PU),
+ PINMUX_DATA(PN1_DATA, PN1_IN, PN1_OUT, PN1_IN_PU),
+ PINMUX_DATA(PN0_DATA, PN0_IN, PN0_OUT, PN0_IN_PU),
+
+ /* PP GPIO */
+ PINMUX_DATA(PP5_DATA, PP5_IN, PP5_OUT, PP5_IN_PU),
+ PINMUX_DATA(PP4_DATA, PP4_IN, PP4_OUT, PP4_IN_PU),
+ PINMUX_DATA(PP3_DATA, PP3_IN, PP3_OUT, PP3_IN_PU),
+ PINMUX_DATA(PP2_DATA, PP2_IN, PP2_OUT, PP2_IN_PU),
+ PINMUX_DATA(PP1_DATA, PP1_IN, PP1_OUT, PP1_IN_PU),
+ PINMUX_DATA(PP0_DATA, PP0_IN, PP0_OUT, PP0_IN_PU),
+
+ /* PQ GPIO */
+ PINMUX_DATA(PQ4_DATA, PQ4_IN, PQ4_OUT, PQ4_IN_PU),
+ PINMUX_DATA(PQ3_DATA, PQ3_IN, PQ3_OUT, PQ3_IN_PU),
+ PINMUX_DATA(PQ2_DATA, PQ2_IN, PQ2_OUT, PQ2_IN_PU),
+ PINMUX_DATA(PQ1_DATA, PQ1_IN, PQ1_OUT, PQ1_IN_PU),
+ PINMUX_DATA(PQ0_DATA, PQ0_IN, PQ0_OUT, PQ0_IN_PU),
+
+ /* PR GPIO */
+ PINMUX_DATA(PR3_DATA, PR3_IN, PR3_OUT, PR3_IN_PU),
+ PINMUX_DATA(PR2_DATA, PR2_IN, PR2_OUT, PR2_IN_PU),
+ PINMUX_DATA(PR1_DATA, PR1_IN, PR1_OUT, PR1_IN_PU),
+ PINMUX_DATA(PR0_DATA, PR0_IN, PR0_OUT, PR0_IN_PU),
+
+ /* PA FN */
+ PINMUX_DATA(D63_AD31_MARK, PA7_FN),
+ PINMUX_DATA(D62_AD30_MARK, PA6_FN),
+ PINMUX_DATA(D61_AD29_MARK, PA5_FN),
+ PINMUX_DATA(D60_AD28_MARK, PA4_FN),
+ PINMUX_DATA(D59_AD27_MARK, PA3_FN),
+ PINMUX_DATA(D58_AD26_MARK, PA2_FN),
+ PINMUX_DATA(D57_AD25_MARK, PA1_FN),
+ PINMUX_DATA(D56_AD24_MARK, PA0_FN),
+
+ /* PB FN */
+ PINMUX_DATA(D55_AD23_MARK, PB7_FN),
+ PINMUX_DATA(D54_AD22_MARK, PB6_FN),
+ PINMUX_DATA(D53_AD21_MARK, PB5_FN),
+ PINMUX_DATA(D52_AD20_MARK, PB4_FN),
+ PINMUX_DATA(D51_AD19_MARK, PB3_FN),
+ PINMUX_DATA(D50_AD18_MARK, PB2_FN),
+ PINMUX_DATA(D49_AD17_DB5_MARK, PB1_FN),
+ PINMUX_DATA(D48_AD16_DB4_MARK, PB0_FN),
+
+ /* PC FN */
+ PINMUX_DATA(D47_AD15_DB3_MARK, PC7_FN),
+ PINMUX_DATA(D46_AD14_DB2_MARK, PC6_FN),
+ PINMUX_DATA(D45_AD13_DB1_MARK, PC5_FN),
+ PINMUX_DATA(D44_AD12_DB0_MARK, PC4_FN),
+ PINMUX_DATA(D43_AD11_DG5_MARK, PC3_FN),
+ PINMUX_DATA(D42_AD10_DG4_MARK, PC2_FN),
+ PINMUX_DATA(D41_AD9_DG3_MARK, PC1_FN),
+ PINMUX_DATA(D40_AD8_DG2_MARK, PC0_FN),
+
+ /* PD FN */
+ PINMUX_DATA(D39_AD7_DG1_MARK, PD7_FN),
+ PINMUX_DATA(D38_AD6_DG0_MARK, PD6_FN),
+ PINMUX_DATA(D37_AD5_DR5_MARK, PD5_FN),
+ PINMUX_DATA(D36_AD4_DR4_MARK, PD4_FN),
+ PINMUX_DATA(D35_AD3_DR3_MARK, PD3_FN),
+ PINMUX_DATA(D34_AD2_DR2_MARK, PD2_FN),
+ PINMUX_DATA(D33_AD1_DR1_MARK, PD1_FN),
+ PINMUX_DATA(D32_AD0_DR0_MARK, PD0_FN),
+
+ /* PE FN */
+ PINMUX_DATA(REQ1_MARK, PE5_FN),
+ PINMUX_DATA(REQ2_MARK, PE4_FN),
+ PINMUX_DATA(REQ3_MARK, P2MSEL0_0, PE3_FN),
+ PINMUX_DATA(GNT1_MARK, PE2_FN),
+ PINMUX_DATA(GNT2_MARK, PE1_FN),
+ PINMUX_DATA(GNT3_MARK, P2MSEL0_0, PE0_FN),
+ PINMUX_DATA(MMCCLK_MARK, P2MSEL0_1, PE0_FN),
+
+ /* PF FN */
+ PINMUX_DATA(D31_MARK, PF7_FN),
+ PINMUX_DATA(D30_MARK, PF6_FN),
+ PINMUX_DATA(D29_MARK, PF5_FN),
+ PINMUX_DATA(D28_MARK, PF4_FN),
+ PINMUX_DATA(D27_MARK, PF3_FN),
+ PINMUX_DATA(D26_MARK, PF2_FN),
+ PINMUX_DATA(D25_MARK, PF1_FN),
+ PINMUX_DATA(D24_MARK, PF0_FN),
+
+ /* PF FN */
+ PINMUX_DATA(D23_MARK, PG7_FN),
+ PINMUX_DATA(D22_MARK, PG6_FN),
+ PINMUX_DATA(D21_MARK, PG5_FN),
+ PINMUX_DATA(D20_MARK, PG4_FN),
+ PINMUX_DATA(D19_MARK, PG3_FN),
+ PINMUX_DATA(D18_MARK, PG2_FN),
+ PINMUX_DATA(D17_MARK, PG1_FN),
+ PINMUX_DATA(D16_MARK, PG0_FN),
+
+ /* PH FN */
+ PINMUX_DATA(SCIF1_SCK_MARK, PH7_FN),
+ PINMUX_DATA(SCIF1_RXD_MARK, PH6_FN),
+ PINMUX_DATA(SCIF1_TXD_MARK, PH5_FN),
+ PINMUX_DATA(SCIF0_CTS_MARK, PH4_FN),
+ PINMUX_DATA(INTD_MARK, P1MSEL7_1, PH4_FN),
+ PINMUX_DATA(FCE_MARK, P1MSEL8_1, P1MSEL7_0, PH4_FN),
+ PINMUX_DATA(SCIF0_RTS_MARK, P1MSEL8_0, P1MSEL7_0, PH3_FN),
+ PINMUX_DATA(HSPI_CS_MARK, P1MSEL8_0, P1MSEL7_1, PH3_FN),
+ PINMUX_DATA(FSE_MARK, P1MSEL8_1, P1MSEL7_0, PH3_FN),
+ PINMUX_DATA(SCIF0_SCK_MARK, P1MSEL8_0, P1MSEL7_0, PH2_FN),
+ PINMUX_DATA(HSPI_CLK_MARK, P1MSEL8_0, P1MSEL7_1, PH2_FN),
+ PINMUX_DATA(FRE_MARK, P1MSEL8_1, P1MSEL7_0, PH2_FN),
+ PINMUX_DATA(SCIF0_RXD_MARK, P1MSEL8_0, P1MSEL7_0, PH1_FN),
+ PINMUX_DATA(HSPI_RX_MARK, P1MSEL8_0, P1MSEL7_1, PH1_FN),
+ PINMUX_DATA(FRB_MARK, P1MSEL8_1, P1MSEL7_0, PH1_FN),
+ PINMUX_DATA(SCIF0_TXD_MARK, P1MSEL8_0, P1MSEL7_0, PH0_FN),
+ PINMUX_DATA(HSPI_TX_MARK, P1MSEL8_0, P1MSEL7_1, PH0_FN),
+ PINMUX_DATA(FWE_MARK, P1MSEL8_1, P1MSEL7_0, PH0_FN),
+
+ /* PJ FN */
+ PINMUX_DATA(SCIF5_TXD_MARK, P1MSEL2_0, P1MSEL1_0, PJ7_FN),
+ PINMUX_DATA(HAC1_SYNC_MARK, P1MSEL2_0, P1MSEL1_1, PJ7_FN),
+ PINMUX_DATA(SSI1_WS_MARK, P1MSEL2_1, P1MSEL1_0, PJ7_FN),
+ PINMUX_DATA(SIOF_TXD_PJ_MARK, P2MSEL1_0, P1MSEL4_0, P1MSEL3_0, PJ6_FN),
+ PINMUX_DATA(HAC0_SDOUT_MARK, P1MSEL4_0, P1MSEL3_1, PJ6_FN),
+ PINMUX_DATA(SSI0_SDATA_MARK, P1MSEL4_1, P1MSEL3_0, PJ6_FN),
+ PINMUX_DATA(SIOF_RXD_PJ_MARK, P2MSEL1_0, P1MSEL4_0, P1MSEL3_0, PJ5_FN),
+ PINMUX_DATA(HAC0_SDIN_MARK, P1MSEL4_0, P1MSEL3_1, PJ5_FN),
+ PINMUX_DATA(SSI0_SCK_MARK, P1MSEL4_1, P1MSEL3_0, PJ5_FN),
+ PINMUX_DATA(SIOF_SYNC_PJ_MARK, P2MSEL1_0, P1MSEL4_0, P1MSEL3_0, PJ4_FN),
+ PINMUX_DATA(HAC0_SYNC_MARK, P1MSEL4_0, P1MSEL3_1, PJ4_FN),
+ PINMUX_DATA(SSI0_WS_MARK, P1MSEL4_1, P1MSEL3_0, PJ4_FN),
+ PINMUX_DATA(SIOF_MCLK_PJ_MARK, P2MSEL1_0, P1MSEL4_0, P1MSEL3_0, PJ3_FN),
+ PINMUX_DATA(HAC_RES_MARK, P1MSEL4_0, P1MSEL3_1, PJ3_FN),
+ PINMUX_DATA(SIOF_SCK_PJ_MARK, P2MSEL1_0, P1MSEL4_0, P1MSEL3_0, PJ2_FN),
+ PINMUX_DATA(HAC0_BITCLK_MARK, P1MSEL4_0, P1MSEL3_1, PJ2_FN),
+ PINMUX_DATA(SSI0_CLK_MARK, P1MSEL4_1, P1MSEL3_0, PJ2_FN),
+ PINMUX_DATA(HAC1_BITCLK_MARK, P1MSEL2_0, PJ1_FN),
+ PINMUX_DATA(SSI1_CLK_MARK, P1MSEL2_1, P1MSEL1_0, PJ1_FN),
+ PINMUX_DATA(TCLK_MARK, P1MSEL9_0, PJ0_FN),
+ PINMUX_DATA(IOIS16_MARK, P1MSEL9_1, PJ0_FN),
+
+ /* PK FN */
+ PINMUX_DATA(STATUS0_MARK, P1MSEL15_0, PK7_FN),
+ PINMUX_DATA(DRAK0_PK3_MARK, P1MSEL15_1, PK7_FN),
+ PINMUX_DATA(STATUS1_MARK, P1MSEL15_0, PK6_FN),
+ PINMUX_DATA(DRAK1_PK2_MARK, P1MSEL15_1, PK6_FN),
+ PINMUX_DATA(DACK2_MARK, P1MSEL12_0, P1MSEL11_0, PK5_FN),
+ PINMUX_DATA(SCIF2_TXD_MARK, P1MSEL12_1, P1MSEL11_0, PK5_FN),
+ PINMUX_DATA(MMCCMD_MARK, P1MSEL12_1, P1MSEL11_1, PK5_FN),
+ PINMUX_DATA(SIOF_TXD_PK_MARK, P2MSEL1_1,
+ P1MSEL12_0, P1MSEL11_1, PK5_FN),
+ PINMUX_DATA(DACK3_MARK, P1MSEL12_0, P1MSEL11_0, PK4_FN),
+ PINMUX_DATA(SCIF2_SCK_MARK, P1MSEL12_1, P1MSEL11_0, PK4_FN),
+ PINMUX_DATA(MMCDAT_MARK, P1MSEL12_1, P1MSEL11_1, PK4_FN),
+ PINMUX_DATA(SIOF_SCK_PK_MARK, P2MSEL1_1,
+ P1MSEL12_0, P1MSEL11_1, PK4_FN),
+ PINMUX_DATA(DREQ0_MARK, PK3_FN),
+ PINMUX_DATA(DREQ1_MARK, PK2_FN),
+ PINMUX_DATA(DRAK0_PK1_MARK, PK1_FN),
+ PINMUX_DATA(DRAK1_PK0_MARK, PK0_FN),
+
+ /* PL FN */
+ PINMUX_DATA(DREQ2_MARK, P1MSEL13_0, PL7_FN),
+ PINMUX_DATA(INTB_MARK, P1MSEL13_1, PL7_FN),
+ PINMUX_DATA(DREQ3_MARK, P1MSEL13_0, PL6_FN),
+ PINMUX_DATA(INTC_MARK, P1MSEL13_1, PL6_FN),
+ PINMUX_DATA(DRAK2_MARK, P1MSEL10_0, PL5_FN),
+ PINMUX_DATA(CE2A_MARK, P1MSEL10_1, PL5_FN),
+ PINMUX_DATA(IRL4_MARK, P1MSEL14_0, PL4_FN),
+ PINMUX_DATA(FD4_MARK, P1MSEL14_1, PL4_FN),
+ PINMUX_DATA(IRL5_MARK, P1MSEL14_0, PL3_FN),
+ PINMUX_DATA(FD5_MARK, P1MSEL14_1, PL3_FN),
+ PINMUX_DATA(IRL6_MARK, P1MSEL14_0, PL2_FN),
+ PINMUX_DATA(FD6_MARK, P1MSEL14_1, PL2_FN),
+ PINMUX_DATA(IRL7_MARK, P1MSEL14_0, PL1_FN),
+ PINMUX_DATA(FD7_MARK, P1MSEL14_1, PL1_FN),
+ PINMUX_DATA(DRAK3_MARK, P1MSEL10_0, PL0_FN),
+ PINMUX_DATA(CE2B_MARK, P1MSEL10_1, PL0_FN),
+
+ /* PM FN */
+ PINMUX_DATA(BREQ_BSACK_MARK, PM1_FN),
+ PINMUX_DATA(BACK_BSREQ_MARK, PM0_FN),
+
+ /* PN FN */
+ PINMUX_DATA(SCIF5_RXD_MARK, P1MSEL2_0, P1MSEL1_0, PN7_FN),
+ PINMUX_DATA(HAC1_SDIN_MARK, P1MSEL2_0, P1MSEL1_1, PN7_FN),
+ PINMUX_DATA(SSI1_SCK_MARK, P1MSEL2_1, P1MSEL1_0, PN7_FN),
+ PINMUX_DATA(SCIF5_SCK_MARK, P1MSEL2_0, P1MSEL1_0, PN6_FN),
+ PINMUX_DATA(HAC1_SDOUT_MARK, P1MSEL2_0, P1MSEL1_1, PN6_FN),
+ PINMUX_DATA(SSI1_SDATA_MARK, P1MSEL2_1, P1MSEL1_0, PN6_FN),
+ PINMUX_DATA(SCIF3_TXD_MARK, P1MSEL0_0, PN5_FN),
+ PINMUX_DATA(FCLE_MARK, P1MSEL0_1, PN5_FN),
+ PINMUX_DATA(SCIF3_RXD_MARK, P1MSEL0_0, PN4_FN),
+ PINMUX_DATA(FALE_MARK, P1MSEL0_1, PN4_FN),
+ PINMUX_DATA(SCIF3_SCK_MARK, P1MSEL0_0, PN3_FN),
+ PINMUX_DATA(FD0_MARK, P1MSEL0_1, PN3_FN),
+ PINMUX_DATA(SCIF4_TXD_MARK, P1MSEL0_0, PN2_FN),
+ PINMUX_DATA(FD1_MARK, P1MSEL0_1, PN2_FN),
+ PINMUX_DATA(SCIF4_RXD_MARK, P1MSEL0_0, PN1_FN),
+ PINMUX_DATA(FD2_MARK, P1MSEL0_1, PN1_FN),
+ PINMUX_DATA(SCIF4_SCK_MARK, P1MSEL0_0, PN0_FN),
+ PINMUX_DATA(FD3_MARK, P1MSEL0_1, PN0_FN),
+
+ /* PP FN */
+ PINMUX_DATA(DEVSEL_DCLKOUT_MARK, PP5_FN),
+ PINMUX_DATA(STOP_CDE_MARK, PP4_FN),
+ PINMUX_DATA(LOCK_ODDF_MARK, PP3_FN),
+ PINMUX_DATA(TRDY_DISPL_MARK, PP2_FN),
+ PINMUX_DATA(IRDY_HSYNC_MARK, PP1_FN),
+ PINMUX_DATA(PCIFRAME_VSYNC_MARK, PP0_FN),
+
+ /* PQ FN */
+ PINMUX_DATA(INTA_MARK, PQ4_FN),
+ PINMUX_DATA(GNT0_GNTIN_MARK, PQ3_FN),
+ PINMUX_DATA(REQ0_REQOUT_MARK, PQ2_FN),
+ PINMUX_DATA(PERR_MARK, PQ1_FN),
+ PINMUX_DATA(SERR_MARK, PQ0_FN),
+
+ /* PR FN */
+ PINMUX_DATA(WE7_CBE3_MARK, PR3_FN),
+ PINMUX_DATA(WE6_CBE2_MARK, PR2_FN),
+ PINMUX_DATA(WE5_CBE1_MARK, PR1_FN),
+ PINMUX_DATA(WE4_CBE0_MARK, PR0_FN),
+
+ /* MISC FN */
+ PINMUX_DATA(SCIF2_RXD_MARK, P1MSEL6_0, P1MSEL5_0),
+ PINMUX_DATA(SIOF_RXD_MARK, P2MSEL1_1, P1MSEL6_1, P1MSEL5_0),
+ PINMUX_DATA(MRESETOUT_MARK, P2MSEL2_0),
+ PINMUX_DATA(IRQOUT_MARK, P2MSEL2_1),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ /* PA */
+ PINMUX_GPIO(GPIO_PA7, PA7_DATA),
+ PINMUX_GPIO(GPIO_PA6, PA6_DATA),
+ PINMUX_GPIO(GPIO_PA5, PA5_DATA),
+ PINMUX_GPIO(GPIO_PA4, PA4_DATA),
+ PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+ PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+ PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+ PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+ /* PB */
+ PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+ PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+ PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+ PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+ PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+ PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+ PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+ PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+
+ /* PC */
+ PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+ PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+ PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+ PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+ PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+ PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+ PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+ PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+ /* PD */
+ PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+ PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+ PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+ PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+ PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+ PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+ PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+ PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+ /* PE */
+ PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+ PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+ PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+ PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+ PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+ PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+ /* PF */
+ PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+ PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+ PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+ PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+ PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+ PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+ PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+ PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+ /* PG */
+ PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+ PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+ PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+ PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+ PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+ PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+ PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+ PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+ /* PH */
+ PINMUX_GPIO(GPIO_PH7, PH7_DATA),
+ PINMUX_GPIO(GPIO_PH6, PH6_DATA),
+ PINMUX_GPIO(GPIO_PH5, PH5_DATA),
+ PINMUX_GPIO(GPIO_PH4, PH4_DATA),
+ PINMUX_GPIO(GPIO_PH3, PH3_DATA),
+ PINMUX_GPIO(GPIO_PH2, PH2_DATA),
+ PINMUX_GPIO(GPIO_PH1, PH1_DATA),
+ PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+
+ /* PJ */
+ PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+ PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+ PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+ PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+ PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+ PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+ PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+ PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+
+ /* PK */
+ PINMUX_GPIO(GPIO_PK7, PK7_DATA),
+ PINMUX_GPIO(GPIO_PK6, PK6_DATA),
+ PINMUX_GPIO(GPIO_PK5, PK5_DATA),
+ PINMUX_GPIO(GPIO_PK4, PK4_DATA),
+ PINMUX_GPIO(GPIO_PK3, PK3_DATA),
+ PINMUX_GPIO(GPIO_PK2, PK2_DATA),
+ PINMUX_GPIO(GPIO_PK1, PK1_DATA),
+ PINMUX_GPIO(GPIO_PK0, PK0_DATA),
+
+ /* PL */
+ PINMUX_GPIO(GPIO_PL7, PL7_DATA),
+ PINMUX_GPIO(GPIO_PL6, PL6_DATA),
+ PINMUX_GPIO(GPIO_PL5, PL5_DATA),
+ PINMUX_GPIO(GPIO_PL4, PL4_DATA),
+ PINMUX_GPIO(GPIO_PL3, PL3_DATA),
+ PINMUX_GPIO(GPIO_PL2, PL2_DATA),
+ PINMUX_GPIO(GPIO_PL1, PL1_DATA),
+ PINMUX_GPIO(GPIO_PL0, PL0_DATA),
+
+ /* PM */
+ PINMUX_GPIO(GPIO_PM1, PM1_DATA),
+ PINMUX_GPIO(GPIO_PM0, PM0_DATA),
+
+ /* PN */
+ PINMUX_GPIO(GPIO_PN7, PN7_DATA),
+ PINMUX_GPIO(GPIO_PN6, PN6_DATA),
+ PINMUX_GPIO(GPIO_PN5, PN5_DATA),
+ PINMUX_GPIO(GPIO_PN4, PN4_DATA),
+ PINMUX_GPIO(GPIO_PN3, PN3_DATA),
+ PINMUX_GPIO(GPIO_PN2, PN2_DATA),
+ PINMUX_GPIO(GPIO_PN1, PN1_DATA),
+ PINMUX_GPIO(GPIO_PN0, PN0_DATA),
+
+ /* PP */
+ PINMUX_GPIO(GPIO_PP5, PP5_DATA),
+ PINMUX_GPIO(GPIO_PP4, PP4_DATA),
+ PINMUX_GPIO(GPIO_PP3, PP3_DATA),
+ PINMUX_GPIO(GPIO_PP2, PP2_DATA),
+ PINMUX_GPIO(GPIO_PP1, PP1_DATA),
+ PINMUX_GPIO(GPIO_PP0, PP0_DATA),
+
+ /* PQ */
+ PINMUX_GPIO(GPIO_PQ4, PQ4_DATA),
+ PINMUX_GPIO(GPIO_PQ3, PQ3_DATA),
+ PINMUX_GPIO(GPIO_PQ2, PQ2_DATA),
+ PINMUX_GPIO(GPIO_PQ1, PQ1_DATA),
+ PINMUX_GPIO(GPIO_PQ0, PQ0_DATA),
+
+ /* PR */
+ PINMUX_GPIO(GPIO_PR3, PR3_DATA),
+ PINMUX_GPIO(GPIO_PR2, PR2_DATA),
+ PINMUX_GPIO(GPIO_PR1, PR1_DATA),
+ PINMUX_GPIO(GPIO_PR0, PR0_DATA),
+
+ /* FN */
+ PINMUX_GPIO(GPIO_FN_D63_AD31, D63_AD31_MARK),
+ PINMUX_GPIO(GPIO_FN_D62_AD30, D62_AD30_MARK),
+ PINMUX_GPIO(GPIO_FN_D61_AD29, D61_AD29_MARK),
+ PINMUX_GPIO(GPIO_FN_D60_AD28, D60_AD28_MARK),
+ PINMUX_GPIO(GPIO_FN_D59_AD27, D59_AD27_MARK),
+ PINMUX_GPIO(GPIO_FN_D58_AD26, D58_AD26_MARK),
+ PINMUX_GPIO(GPIO_FN_D57_AD25, D57_AD25_MARK),
+ PINMUX_GPIO(GPIO_FN_D56_AD24, D56_AD24_MARK),
+ PINMUX_GPIO(GPIO_FN_D55_AD23, D55_AD23_MARK),
+ PINMUX_GPIO(GPIO_FN_D54_AD22, D54_AD22_MARK),
+ PINMUX_GPIO(GPIO_FN_D53_AD21, D53_AD21_MARK),
+ PINMUX_GPIO(GPIO_FN_D52_AD20, D52_AD20_MARK),
+ PINMUX_GPIO(GPIO_FN_D51_AD19, D51_AD19_MARK),
+ PINMUX_GPIO(GPIO_FN_D50_AD18, D50_AD18_MARK),
+ PINMUX_GPIO(GPIO_FN_D49_AD17_DB5, D49_AD17_DB5_MARK),
+ PINMUX_GPIO(GPIO_FN_D48_AD16_DB4, D48_AD16_DB4_MARK),
+ PINMUX_GPIO(GPIO_FN_D47_AD15_DB3, D47_AD15_DB3_MARK),
+ PINMUX_GPIO(GPIO_FN_D46_AD14_DB2, D46_AD14_DB2_MARK),
+ PINMUX_GPIO(GPIO_FN_D45_AD13_DB1, D45_AD13_DB1_MARK),
+ PINMUX_GPIO(GPIO_FN_D44_AD12_DB0, D44_AD12_DB0_MARK),
+ PINMUX_GPIO(GPIO_FN_D43_AD11_DG5, D43_AD11_DG5_MARK),
+ PINMUX_GPIO(GPIO_FN_D42_AD10_DG4, D42_AD10_DG4_MARK),
+ PINMUX_GPIO(GPIO_FN_D41_AD9_DG3, D41_AD9_DG3_MARK),
+ PINMUX_GPIO(GPIO_FN_D40_AD8_DG2, D40_AD8_DG2_MARK),
+ PINMUX_GPIO(GPIO_FN_D39_AD7_DG1, D39_AD7_DG1_MARK),
+ PINMUX_GPIO(GPIO_FN_D38_AD6_DG0, D38_AD6_DG0_MARK),
+ PINMUX_GPIO(GPIO_FN_D37_AD5_DR5, D37_AD5_DR5_MARK),
+ PINMUX_GPIO(GPIO_FN_D36_AD4_DR4, D36_AD4_DR4_MARK),
+ PINMUX_GPIO(GPIO_FN_D35_AD3_DR3, D35_AD3_DR3_MARK),
+ PINMUX_GPIO(GPIO_FN_D34_AD2_DR2, D34_AD2_DR2_MARK),
+ PINMUX_GPIO(GPIO_FN_D33_AD1_DR1, D33_AD1_DR1_MARK),
+ PINMUX_GPIO(GPIO_FN_D32_AD0_DR0, D32_AD0_DR0_MARK),
+ PINMUX_GPIO(GPIO_FN_REQ1, REQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_REQ2, REQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_REQ3, REQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_GNT1, GNT1_MARK),
+ PINMUX_GPIO(GPIO_FN_GNT2, GNT2_MARK),
+ PINMUX_GPIO(GPIO_FN_GNT3, GNT3_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCCLK, MMCCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
+ PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
+ PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
+ PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
+ PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
+ PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
+ PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
+ PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
+ PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
+ PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
+ PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
+ PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
+ PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
+ PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
+ PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
+ PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_SCK, SCIF1_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_RXD, SCIF1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_TXD, SCIF1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_CTS, SCIF0_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_INTD, INTD_MARK),
+ PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_RTS, SCIF0_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_HSPI_CS, HSPI_CS_MARK),
+ PINMUX_GPIO(GPIO_FN_FSE, FSE_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_SCK, SCIF0_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_HSPI_CLK, HSPI_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_FRE, FRE_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_RXD, SCIF0_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_HSPI_RX, HSPI_RX_MARK),
+ PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_TXD, SCIF0_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_HSPI_TX, HSPI_TX_MARK),
+ PINMUX_GPIO(GPIO_FN_FWE, FWE_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_TXD, SCIF5_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC1_SYNC, HAC1_SYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI1_WS, SSI1_WS_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF_TXD_PJ, SIOF_TXD_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC0_SDOUT, HAC0_SDOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI0_SDATA, SSI0_SDATA_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF_RXD_PJ, SIOF_RXD_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC0_SDIN, HAC0_SDIN_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI0_SCK, SSI0_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF_SYNC_PJ, SIOF_SYNC_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC0_SYNC, HAC0_SYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI0_WS, SSI0_WS_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF_MCLK_PJ, SIOF_MCLK_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC_RES, HAC_RES_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF_SCK_PJ, SIOF_SCK_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC0_BITCLK, HAC0_BITCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI0_CLK, SSI0_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC1_BITCLK, HAC1_BITCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI1_CLK, SSI1_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK0_PK3, DRAK0_PK3_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK1_PK2, DRAK1_PK2_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK2, DACK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_TXD, SCIF2_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCCMD, MMCCMD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF_TXD_PK, SIOF_TXD_PK_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK3, DACK3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_SCK, SCIF2_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_MMCDAT, MMCDAT_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF_SCK_PK, SIOF_SCK_PK_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK0_PK1, DRAK0_PK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK1_PK0, DRAK1_PK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ2, DREQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_INTB, INTB_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ3, DREQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_INTC, INTC_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK2, DRAK2_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL4, IRL4_MARK),
+ PINMUX_GPIO(GPIO_FN_FD4, FD4_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL5, IRL5_MARK),
+ PINMUX_GPIO(GPIO_FN_FD5, FD5_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL6, IRL6_MARK),
+ PINMUX_GPIO(GPIO_FN_FD6, FD6_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL7, IRL7_MARK),
+ PINMUX_GPIO(GPIO_FN_FD7, FD7_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK3, DRAK3_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_BREQ_BSACK, BREQ_BSACK_MARK),
+ PINMUX_GPIO(GPIO_FN_BACK_BSREQ, BACK_BSREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_RXD, SCIF5_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC1_SDIN, HAC1_SDIN_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI1_SCK, SSI1_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_SCK, SCIF5_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC1_SDOUT, HAC1_SDOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI1_SDATA, SSI1_SDATA_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_TXD, SCIF3_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_FCLE, FCLE_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_RXD, SCIF3_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_FALE, FALE_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_SCK, SCIF3_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_FD0, FD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_TXD, SCIF4_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_FD1, FD1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_RXD, SCIF4_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_FD2, FD2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_SCK, SCIF4_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_FD3, FD3_MARK),
+ PINMUX_GPIO(GPIO_FN_DEVSEL_DCLKOUT, DEVSEL_DCLKOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_STOP_CDE, STOP_CDE_MARK),
+ PINMUX_GPIO(GPIO_FN_LOCK_ODDF, LOCK_ODDF_MARK),
+ PINMUX_GPIO(GPIO_FN_TRDY_DISPL, TRDY_DISPL_MARK),
+ PINMUX_GPIO(GPIO_FN_IRDY_HSYNC, IRDY_HSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_PCIFRAME_VSYNC, PCIFRAME_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_INTA, INTA_MARK),
+ PINMUX_GPIO(GPIO_FN_GNT0_GNTIN, GNT0_GNTIN_MARK),
+ PINMUX_GPIO(GPIO_FN_REQ0_REQOUT, REQ0_REQOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_PERR, PERR_MARK),
+ PINMUX_GPIO(GPIO_FN_SERR, SERR_MARK),
+ PINMUX_GPIO(GPIO_FN_WE7_CBE3, WE7_CBE3_MARK),
+ PINMUX_GPIO(GPIO_FN_WE6_CBE2, WE6_CBE2_MARK),
+ PINMUX_GPIO(GPIO_FN_WE5_CBE1, WE5_CBE1_MARK),
+ PINMUX_GPIO(GPIO_FN_WE4_CBE0, WE4_CBE0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF2_RXD, SCIF2_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOF_RXD, SIOF_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_MRESETOUT, MRESETOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQOUT, IRQOUT_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PACR", 0xffe70000, 16, 2) {
+ PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
+ PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
+ PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
+ PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
+ PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
+ PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
+ PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
+ PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PBCR", 0xffe70002, 16, 2) {
+ PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
+ PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
+ PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
+ PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
+ PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
+ PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
+ PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
+ PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PCCR", 0xffe70004, 16, 2) {
+ PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
+ PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
+ PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
+ PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
+ PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
+ PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
+ PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
+ PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PDCR", 0xffe70006, 16, 2) {
+ PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
+ PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
+ PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
+ PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
+ PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
+ PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
+ PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
+ PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PECR", 0xffe70008, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PE5_FN, PE5_OUT, PE5_IN, PE5_IN_PU,
+ PE4_FN, PE4_OUT, PE4_IN, PE4_IN_PU,
+ PE3_FN, PE3_OUT, PE3_IN, PE3_IN_PU,
+ PE2_FN, PE2_OUT, PE2_IN, PE2_IN_PU,
+ PE1_FN, PE1_OUT, PE1_IN, PE1_IN_PU,
+ PE0_FN, PE0_OUT, PE0_IN, PE0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PFCR", 0xffe7000a, 16, 2) {
+ PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
+ PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
+ PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
+ PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
+ PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
+ PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
+ PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
+ PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PGCR", 0xffe7000c, 16, 2) {
+ PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
+ PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
+ PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
+ PG4_FN, PG4_OUT, PG4_IN, PG4_IN_PU,
+ PG3_FN, PG3_OUT, PG3_IN, PG3_IN_PU,
+ PG2_FN, PG2_OUT, PG2_IN, PG2_IN_PU,
+ PG1_FN, PG1_OUT, PG1_IN, PG1_IN_PU,
+ PG0_FN, PG0_OUT, PG0_IN, PG0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PHCR", 0xffe7000e, 16, 2) {
+ PH7_FN, PH7_OUT, PH7_IN, PH7_IN_PU,
+ PH6_FN, PH6_OUT, PH6_IN, PH6_IN_PU,
+ PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
+ PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
+ PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
+ PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
+ PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
+ PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PJCR", 0xffe70010, 16, 2) {
+ PJ7_FN, PJ7_OUT, PJ7_IN, PJ7_IN_PU,
+ PJ6_FN, PJ6_OUT, PJ6_IN, PJ6_IN_PU,
+ PJ5_FN, PJ5_OUT, PJ5_IN, PJ5_IN_PU,
+ PJ4_FN, PJ4_OUT, PJ4_IN, PJ4_IN_PU,
+ PJ3_FN, PJ3_OUT, PJ3_IN, PJ3_IN_PU,
+ PJ2_FN, PJ2_OUT, PJ2_IN, PJ2_IN_PU,
+ PJ1_FN, PJ1_OUT, PJ1_IN, PJ1_IN_PU,
+ PJ0_FN, PJ0_OUT, PJ0_IN, PJ0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PKCR", 0xffe70012, 16, 2) {
+ PK7_FN, PK7_OUT, PK7_IN, PK7_IN_PU,
+ PK6_FN, PK6_OUT, PK6_IN, PK6_IN_PU,
+ PK5_FN, PK5_OUT, PK5_IN, PK5_IN_PU,
+ PK4_FN, PK4_OUT, PK4_IN, PK4_IN_PU,
+ PK3_FN, PK3_OUT, PK3_IN, PK3_IN_PU,
+ PK2_FN, PK2_OUT, PK2_IN, PK2_IN_PU,
+ PK1_FN, PK1_OUT, PK1_IN, PK1_IN_PU,
+ PK0_FN, PK0_OUT, PK0_IN, PK0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PLCR", 0xffe70014, 16, 2) {
+ PL7_FN, PL7_OUT, PL7_IN, PL7_IN_PU,
+ PL6_FN, PL6_OUT, PL6_IN, PL6_IN_PU,
+ PL5_FN, PL5_OUT, PL5_IN, PL5_IN_PU,
+ PL4_FN, PL4_OUT, PL4_IN, PL4_IN_PU,
+ PL3_FN, PL3_OUT, PL3_IN, PL3_IN_PU,
+ PL2_FN, PL2_OUT, PL2_IN, PL2_IN_PU,
+ PL1_FN, PL1_OUT, PL1_IN, PL1_IN_PU,
+ PL0_FN, PL0_OUT, PL0_IN, PL0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PMCR", 0xffe70016, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PM1_FN, PM1_OUT, PM1_IN, PM1_IN_PU,
+ PM0_FN, PM0_OUT, PM0_IN, PM0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PNCR", 0xffe70018, 16, 2) {
+ PN7_FN, PN7_OUT, PN7_IN, PN7_IN_PU,
+ PN6_FN, PN6_OUT, PN6_IN, PN6_IN_PU,
+ PN5_FN, PN5_OUT, PN5_IN, PN5_IN_PU,
+ PN4_FN, PN4_OUT, PN4_IN, PN4_IN_PU,
+ PN3_FN, PN3_OUT, PN3_IN, PN3_IN_PU,
+ PN2_FN, PN2_OUT, PN2_IN, PN2_IN_PU,
+ PN1_FN, PN1_OUT, PN1_IN, PN1_IN_PU,
+ PN0_FN, PN0_OUT, PN0_IN, PN0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PPCR", 0xffe7001a, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PP5_FN, PP5_OUT, PP5_IN, PP5_IN_PU,
+ PP4_FN, PP4_OUT, PP4_IN, PP4_IN_PU,
+ PP3_FN, PP3_OUT, PP3_IN, PP3_IN_PU,
+ PP2_FN, PP2_OUT, PP2_IN, PP2_IN_PU,
+ PP1_FN, PP1_OUT, PP1_IN, PP1_IN_PU,
+ PP0_FN, PP0_OUT, PP0_IN, PP0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PQCR", 0xffe7001c, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PQ4_FN, PQ4_OUT, PQ4_IN, PQ4_IN_PU,
+ PQ3_FN, PQ3_OUT, PQ3_IN, PQ3_IN_PU,
+ PQ2_FN, PQ2_OUT, PQ2_IN, PQ2_IN_PU,
+ PQ1_FN, PQ1_OUT, PQ1_IN, PQ1_IN_PU,
+ PQ0_FN, PQ0_OUT, PQ0_IN, PQ0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PRCR", 0xffe7001e, 16, 2) {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PR3_FN, PR3_OUT, PR3_IN, PR3_IN_PU,
+ PR2_FN, PR2_OUT, PR2_IN, PR2_IN_PU,
+ PR1_FN, PR1_OUT, PR1_IN, PR1_IN_PU,
+ PR0_FN, PR0_OUT, PR0_IN, PR0_IN_PU }
+ },
+ { PINMUX_CFG_REG("P1MSELR", 0xffe70080, 16, 1) {
+ P1MSEL15_0, P1MSEL15_1,
+ P1MSEL14_0, P1MSEL14_1,
+ P1MSEL13_0, P1MSEL13_1,
+ P1MSEL12_0, P1MSEL12_1,
+ P1MSEL11_0, P1MSEL11_1,
+ P1MSEL10_0, P1MSEL10_1,
+ P1MSEL9_0, P1MSEL9_1,
+ P1MSEL8_0, P1MSEL8_1,
+ P1MSEL7_0, P1MSEL7_1,
+ P1MSEL6_0, P1MSEL6_1,
+ P1MSEL5_0, 0,
+ P1MSEL4_0, P1MSEL4_1,
+ P1MSEL3_0, P1MSEL3_1,
+ P1MSEL2_0, P1MSEL2_1,
+ P1MSEL1_0, P1MSEL1_1,
+ P1MSEL0_0, P1MSEL0_1 }
+ },
+ { PINMUX_CFG_REG("P2MSELR", 0xffe70082, 16, 1) {
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ P2MSEL2_0, P2MSEL2_1,
+ P2MSEL1_0, P2MSEL1_1,
+ P2MSEL0_0, P2MSEL0_1 }
+ },
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR", 0xffe70020, 8) {
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA }
+ },
+ { PINMUX_DATA_REG("PBDR", 0xffe70022, 8) {
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA }
+ },
+ { PINMUX_DATA_REG("PCDR", 0xffe70024, 8) {
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+ },
+ { PINMUX_DATA_REG("PDDR", 0xffe70026, 8) {
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+ },
+ { PINMUX_DATA_REG("PEDR", 0xffe70028, 8) {
+ 0, 0, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
+ },
+ { PINMUX_DATA_REG("PFDR", 0xffe7002a, 8) {
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+ },
+ { PINMUX_DATA_REG("PGDR", 0xffe7002c, 8) {
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
+ },
+ { PINMUX_DATA_REG("PHDR", 0xffe7002e, 8) {
+ PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR", 0xffe70030, 8) {
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
+ },
+ { PINMUX_DATA_REG("PKDR", 0xffe70032, 8) {
+ PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
+ PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA }
+ },
+ { PINMUX_DATA_REG("PLDR", 0xffe70034, 8) {
+ PL7_DATA, PL6_DATA, PL5_DATA, PL4_DATA,
+ PL3_DATA, PL2_DATA, PL1_DATA, PL0_DATA }
+ },
+ { PINMUX_DATA_REG("PMDR", 0xffe70036, 8) {
+ 0, 0, 0, 0,
+ 0, 0, PM1_DATA, PM0_DATA }
+ },
+ { PINMUX_DATA_REG("PNDR", 0xffe70038, 8) {
+ PN7_DATA, PN6_DATA, PN5_DATA, PN4_DATA,
+ PN3_DATA, PN2_DATA, PN1_DATA, PN0_DATA }
+ },
+ { PINMUX_DATA_REG("PPDR", 0xffe7003a, 8) {
+ 0, 0, PP5_DATA, PP4_DATA,
+ PP3_DATA, PP2_DATA, PP1_DATA, PP0_DATA }
+ },
+ { PINMUX_DATA_REG("PQDR", 0xffe7003c, 8) {
+ 0, 0, 0, PQ4_DATA,
+ PQ3_DATA, PQ2_DATA, PQ1_DATA, PQ0_DATA }
+ },
+ { PINMUX_DATA_REG("PRDR", 0xffe7003e, 8) {
+ 0, 0, 0, 0,
+ PR3_DATA, PR2_DATA, PR1_DATA, PR0_DATA }
+ },
+ { },
+};
+
+struct sh_pfc_soc_info sh7785_pinmux_info = {
+ .name = "sh7785_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PA7,
+ .last_gpio = GPIO_FN_IRQOUT,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7786.c b/drivers/pinctrl/sh-pfc/pfc-sh7786.c
new file mode 100644
index 000000000000..1e18b58f9e5f
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7786.c
@@ -0,0 +1,837 @@
+/*
+ * SH7786 Pinmux
+ *
+ * Copyright (C) 2008, 2009 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on SH7785 pinmux
+ *
+ * Copyright (C) 2008 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/init.h>
+#include <linux/kernel.h>
+#include <cpu/sh7786.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+ PE7_DATA, PE6_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA,
+ PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ PA7_IN, PA6_IN, PA5_IN, PA4_IN,
+ PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+ PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+ PB3_IN, PB2_IN, PB1_IN, PB0_IN,
+ PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+ PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+ PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+ PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+ PE7_IN, PE6_IN,
+ PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+ PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+ PG7_IN, PG6_IN, PG5_IN,
+ PH7_IN, PH6_IN, PH5_IN, PH4_IN,
+ PH3_IN, PH2_IN, PH1_IN, PH0_IN,
+ PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+ PJ3_IN, PJ2_IN, PJ1_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_INPUT_PULLUP_BEGIN,
+ PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
+ PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
+ PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
+ PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
+ PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
+ PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
+ PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
+ PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
+ PE7_IN_PU, PE6_IN_PU,
+ PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
+ PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
+ PG7_IN_PU, PG6_IN_PU, PG5_IN_PU,
+ PH7_IN_PU, PH6_IN_PU, PH5_IN_PU, PH4_IN_PU,
+ PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
+ PJ7_IN_PU, PJ6_IN_PU, PJ5_IN_PU, PJ4_IN_PU,
+ PJ3_IN_PU, PJ2_IN_PU, PJ1_IN_PU,
+ PINMUX_INPUT_PULLUP_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
+ PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+ PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+ PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
+ PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+ PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+ PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+ PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+ PE7_OUT, PE6_OUT,
+ PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+ PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+ PG7_OUT, PG6_OUT, PG5_OUT,
+ PH7_OUT, PH6_OUT, PH5_OUT, PH4_OUT,
+ PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
+ PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+ PJ3_OUT, PJ2_OUT, PJ1_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PA7_FN, PA6_FN, PA5_FN, PA4_FN,
+ PA3_FN, PA2_FN, PA1_FN, PA0_FN,
+ PB7_FN, PB6_FN, PB5_FN, PB4_FN,
+ PB3_FN, PB2_FN, PB1_FN, PB0_FN,
+ PC7_FN, PC6_FN, PC5_FN, PC4_FN,
+ PC3_FN, PC2_FN, PC1_FN, PC0_FN,
+ PD7_FN, PD6_FN, PD5_FN, PD4_FN,
+ PD3_FN, PD2_FN, PD1_FN, PD0_FN,
+ PE7_FN, PE6_FN,
+ PF7_FN, PF6_FN, PF5_FN, PF4_FN,
+ PF3_FN, PF2_FN, PF1_FN, PF0_FN,
+ PG7_FN, PG6_FN, PG5_FN,
+ PH7_FN, PH6_FN, PH5_FN, PH4_FN,
+ PH3_FN, PH2_FN, PH1_FN, PH0_FN,
+ PJ7_FN, PJ6_FN, PJ5_FN, PJ4_FN,
+ PJ3_FN, PJ2_FN, PJ1_FN,
+ P1MSEL14_0, P1MSEL14_1,
+ P1MSEL13_0, P1MSEL13_1,
+ P1MSEL12_0, P1MSEL12_1,
+ P1MSEL11_0, P1MSEL11_1,
+ P1MSEL10_0, P1MSEL10_1,
+ P1MSEL9_0, P1MSEL9_1,
+ P1MSEL8_0, P1MSEL8_1,
+ P1MSEL7_0, P1MSEL7_1,
+ P1MSEL6_0, P1MSEL6_1,
+ P1MSEL5_0, P1MSEL5_1,
+ P1MSEL4_0, P1MSEL4_1,
+ P1MSEL3_0, P1MSEL3_1,
+ P1MSEL2_0, P1MSEL2_1,
+ P1MSEL1_0, P1MSEL1_1,
+ P1MSEL0_0, P1MSEL0_1,
+
+ P2MSEL15_0, P2MSEL15_1,
+ P2MSEL14_0, P2MSEL14_1,
+ P2MSEL13_0, P2MSEL13_1,
+ P2MSEL12_0, P2MSEL12_1,
+ P2MSEL11_0, P2MSEL11_1,
+ P2MSEL10_0, P2MSEL10_1,
+ P2MSEL9_0, P2MSEL9_1,
+ P2MSEL8_0, P2MSEL8_1,
+ P2MSEL7_0, P2MSEL7_1,
+ P2MSEL6_0, P2MSEL6_1,
+ P2MSEL5_0, P2MSEL5_1,
+ P2MSEL4_0, P2MSEL4_1,
+ P2MSEL3_0, P2MSEL3_1,
+ P2MSEL2_0, P2MSEL2_1,
+ P2MSEL1_0, P2MSEL1_1,
+ P2MSEL0_0, P2MSEL0_1,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ DCLKIN_MARK, DCLKOUT_MARK, ODDF_MARK,
+ VSYNC_MARK, HSYNC_MARK, CDE_MARK, DISP_MARK,
+ DR0_MARK, DR1_MARK, DR2_MARK, DR3_MARK, DR4_MARK, DR5_MARK,
+ DG0_MARK, DG1_MARK, DG2_MARK, DG3_MARK, DG4_MARK, DG5_MARK,
+ DB0_MARK, DB1_MARK, DB2_MARK, DB3_MARK, DB4_MARK, DB5_MARK,
+ ETH_MAGIC_MARK, ETH_LINK_MARK, ETH_TX_ER_MARK, ETH_TX_EN_MARK,
+ ETH_MDIO_MARK, ETH_RX_CLK_MARK, ETH_MDC_MARK, ETH_COL_MARK,
+ ETH_TX_CLK_MARK, ETH_CRS_MARK, ETH_RX_DV_MARK, ETH_RX_ER_MARK,
+ ETH_TXD3_MARK, ETH_TXD2_MARK, ETH_TXD1_MARK, ETH_TXD0_MARK,
+ ETH_RXD3_MARK, ETH_RXD2_MARK, ETH_RXD1_MARK, ETH_RXD0_MARK,
+ HSPI_CLK_MARK, HSPI_CS_MARK, HSPI_RX_MARK, HSPI_TX_MARK,
+ SCIF0_CTS_MARK, SCIF0_RTS_MARK,
+ SCIF0_SCK_MARK, SCIF0_RXD_MARK, SCIF0_TXD_MARK,
+ SCIF1_SCK_MARK, SCIF1_RXD_MARK, SCIF1_TXD_MARK,
+ SCIF3_SCK_MARK, SCIF3_RXD_MARK, SCIF3_TXD_MARK,
+ SCIF4_SCK_MARK, SCIF4_RXD_MARK, SCIF4_TXD_MARK,
+ SCIF5_SCK_MARK, SCIF5_RXD_MARK, SCIF5_TXD_MARK,
+ BREQ_MARK, IOIS16_MARK, CE2B_MARK, CE2A_MARK, BACK_MARK,
+ FALE_MARK, FRB_MARK, FSTATUS_MARK,
+ FSE_MARK, FCLE_MARK,
+ DACK0_MARK, DACK1_MARK, DACK2_MARK, DACK3_MARK,
+ DREQ0_MARK, DREQ1_MARK, DREQ2_MARK, DREQ3_MARK,
+ DRAK0_MARK, DRAK1_MARK, DRAK2_MARK, DRAK3_MARK,
+ USB_OVC1_MARK, USB_OVC0_MARK,
+ USB_PENC1_MARK, USB_PENC0_MARK,
+ HAC_RES_MARK,
+ HAC1_SDOUT_MARK, HAC1_SDIN_MARK, HAC1_SYNC_MARK, HAC1_BITCLK_MARK,
+ HAC0_SDOUT_MARK, HAC0_SDIN_MARK, HAC0_SYNC_MARK, HAC0_BITCLK_MARK,
+ SSI0_SDATA_MARK, SSI0_SCK_MARK, SSI0_WS_MARK, SSI0_CLK_MARK,
+ SSI1_SDATA_MARK, SSI1_SCK_MARK, SSI1_WS_MARK, SSI1_CLK_MARK,
+ SSI2_SDATA_MARK, SSI2_SCK_MARK, SSI2_WS_MARK,
+ SSI3_SDATA_MARK, SSI3_SCK_MARK, SSI3_WS_MARK,
+ SDIF1CMD_MARK, SDIF1CD_MARK, SDIF1WP_MARK, SDIF1CLK_MARK,
+ SDIF1D3_MARK, SDIF1D2_MARK, SDIF1D1_MARK, SDIF1D0_MARK,
+ SDIF0CMD_MARK, SDIF0CD_MARK, SDIF0WP_MARK, SDIF0CLK_MARK,
+ SDIF0D3_MARK, SDIF0D2_MARK, SDIF0D1_MARK, SDIF0D0_MARK,
+ TCLK_MARK,
+ IRL7_MARK, IRL6_MARK, IRL5_MARK, IRL4_MARK,
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+ /* PA GPIO */
+ PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
+ PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
+ PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
+ PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
+ PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
+ PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
+ PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
+ PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+
+ /* PB GPIO */
+ PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
+ PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
+ PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
+ PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
+ PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
+ PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
+ PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
+ PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+
+ /* PC GPIO */
+ PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
+ PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
+ PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
+ PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
+ PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
+ PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
+ PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
+ PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+
+ /* PD GPIO */
+ PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
+ PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
+ PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
+ PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
+ PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
+ PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
+ PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
+ PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+
+ /* PE GPIO */
+ PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
+ PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
+
+ /* PF GPIO */
+ PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
+ PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
+ PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
+ PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
+ PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
+ PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
+ PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
+ PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+
+ /* PG GPIO */
+ PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
+ PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
+ PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
+
+ /* PH GPIO */
+ PINMUX_DATA(PH7_DATA, PH7_IN, PH7_OUT, PH7_IN_PU),
+ PINMUX_DATA(PH6_DATA, PH6_IN, PH6_OUT, PH6_IN_PU),
+ PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
+ PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
+ PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
+ PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
+ PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
+ PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+
+ /* PJ GPIO */
+ PINMUX_DATA(PJ7_DATA, PJ7_IN, PJ7_OUT, PJ7_IN_PU),
+ PINMUX_DATA(PJ6_DATA, PJ6_IN, PJ6_OUT, PJ6_IN_PU),
+ PINMUX_DATA(PJ5_DATA, PJ5_IN, PJ5_OUT, PJ5_IN_PU),
+ PINMUX_DATA(PJ4_DATA, PJ4_IN, PJ4_OUT, PJ4_IN_PU),
+ PINMUX_DATA(PJ3_DATA, PJ3_IN, PJ3_OUT, PJ3_IN_PU),
+ PINMUX_DATA(PJ2_DATA, PJ2_IN, PJ2_OUT, PJ2_IN_PU),
+ PINMUX_DATA(PJ1_DATA, PJ1_IN, PJ1_OUT, PJ1_IN_PU),
+
+ /* PA FN */
+ PINMUX_DATA(CDE_MARK, P1MSEL2_0, PA7_FN),
+ PINMUX_DATA(DISP_MARK, P1MSEL2_0, PA6_FN),
+ PINMUX_DATA(DR5_MARK, P1MSEL2_0, PA5_FN),
+ PINMUX_DATA(DR4_MARK, P1MSEL2_0, PA4_FN),
+ PINMUX_DATA(DR3_MARK, P1MSEL2_0, PA3_FN),
+ PINMUX_DATA(DR2_MARK, P1MSEL2_0, PA2_FN),
+ PINMUX_DATA(DR1_MARK, P1MSEL2_0, PA1_FN),
+ PINMUX_DATA(DR0_MARK, P1MSEL2_0, PA0_FN),
+ PINMUX_DATA(ETH_MAGIC_MARK, P1MSEL2_1, PA7_FN),
+ PINMUX_DATA(ETH_LINK_MARK, P1MSEL2_1, PA6_FN),
+ PINMUX_DATA(ETH_TX_ER_MARK, P1MSEL2_1, PA5_FN),
+ PINMUX_DATA(ETH_TX_EN_MARK, P1MSEL2_1, PA4_FN),
+ PINMUX_DATA(ETH_TXD3_MARK, P1MSEL2_1, PA3_FN),
+ PINMUX_DATA(ETH_TXD2_MARK, P1MSEL2_1, PA2_FN),
+ PINMUX_DATA(ETH_TXD1_MARK, P1MSEL2_1, PA1_FN),
+ PINMUX_DATA(ETH_TXD0_MARK, P1MSEL2_1, PA0_FN),
+
+ /* PB FN */
+ PINMUX_DATA(VSYNC_MARK, P1MSEL3_0, PB7_FN),
+ PINMUX_DATA(ODDF_MARK, P1MSEL3_0, PB6_FN),
+ PINMUX_DATA(DG5_MARK, P1MSEL2_0, PB5_FN),
+ PINMUX_DATA(DG4_MARK, P1MSEL2_0, PB4_FN),
+ PINMUX_DATA(DG3_MARK, P1MSEL2_0, PB3_FN),
+ PINMUX_DATA(DG2_MARK, P1MSEL2_0, PB2_FN),
+ PINMUX_DATA(DG1_MARK, P1MSEL2_0, PB1_FN),
+ PINMUX_DATA(DG0_MARK, P1MSEL2_0, PB0_FN),
+ PINMUX_DATA(HSPI_CLK_MARK, P1MSEL3_1, PB7_FN),
+ PINMUX_DATA(HSPI_CS_MARK, P1MSEL3_1, PB6_FN),
+ PINMUX_DATA(ETH_MDIO_MARK, P1MSEL2_1, PB5_FN),
+ PINMUX_DATA(ETH_RX_CLK_MARK, P1MSEL2_1, PB4_FN),
+ PINMUX_DATA(ETH_MDC_MARK, P1MSEL2_1, PB3_FN),
+ PINMUX_DATA(ETH_COL_MARK, P1MSEL2_1, PB2_FN),
+ PINMUX_DATA(ETH_TX_CLK_MARK, P1MSEL2_1, PB1_FN),
+ PINMUX_DATA(ETH_CRS_MARK, P1MSEL2_1, PB0_FN),
+
+ /* PC FN */
+ PINMUX_DATA(DCLKIN_MARK, P1MSEL3_0, PC7_FN),
+ PINMUX_DATA(HSYNC_MARK, P1MSEL3_0, PC6_FN),
+ PINMUX_DATA(DB5_MARK, P1MSEL2_0, PC5_FN),
+ PINMUX_DATA(DB4_MARK, P1MSEL2_0, PC4_FN),
+ PINMUX_DATA(DB3_MARK, P1MSEL2_0, PC3_FN),
+ PINMUX_DATA(DB2_MARK, P1MSEL2_0, PC2_FN),
+ PINMUX_DATA(DB1_MARK, P1MSEL2_0, PC1_FN),
+ PINMUX_DATA(DB0_MARK, P1MSEL2_0, PC0_FN),
+
+ PINMUX_DATA(HSPI_RX_MARK, P1MSEL3_1, PC7_FN),
+ PINMUX_DATA(HSPI_TX_MARK, P1MSEL3_1, PC6_FN),
+ PINMUX_DATA(ETH_RXD3_MARK, P1MSEL2_1, PC5_FN),
+ PINMUX_DATA(ETH_RXD2_MARK, P1MSEL2_1, PC4_FN),
+ PINMUX_DATA(ETH_RXD1_MARK, P1MSEL2_1, PC3_FN),
+ PINMUX_DATA(ETH_RXD0_MARK, P1MSEL2_1, PC2_FN),
+ PINMUX_DATA(ETH_RX_DV_MARK, P1MSEL2_1, PC1_FN),
+ PINMUX_DATA(ETH_RX_ER_MARK, P1MSEL2_1, PC0_FN),
+
+ /* PD FN */
+ PINMUX_DATA(DCLKOUT_MARK, PD7_FN),
+ PINMUX_DATA(SCIF1_SCK_MARK, PD6_FN),
+ PINMUX_DATA(SCIF1_RXD_MARK, PD5_FN),
+ PINMUX_DATA(SCIF1_TXD_MARK, PD4_FN),
+ PINMUX_DATA(DACK1_MARK, P1MSEL13_1, P1MSEL12_0, PD3_FN),
+ PINMUX_DATA(BACK_MARK, P1MSEL13_0, P1MSEL12_1, PD3_FN),
+ PINMUX_DATA(FALE_MARK, P1MSEL13_0, P1MSEL12_0, PD3_FN),
+ PINMUX_DATA(DACK0_MARK, P1MSEL14_1, PD2_FN),
+ PINMUX_DATA(FCLE_MARK, P1MSEL14_0, PD2_FN),
+ PINMUX_DATA(DREQ1_MARK, P1MSEL10_0, P1MSEL9_1, PD1_FN),
+ PINMUX_DATA(BREQ_MARK, P1MSEL10_1, P1MSEL9_0, PD1_FN),
+ PINMUX_DATA(USB_OVC1_MARK, P1MSEL10_0, P1MSEL9_0, PD1_FN),
+ PINMUX_DATA(DREQ0_MARK, P1MSEL11_1, PD0_FN),
+ PINMUX_DATA(USB_OVC0_MARK, P1MSEL11_0, PD0_FN),
+
+ /* PE FN */
+ PINMUX_DATA(USB_PENC1_MARK, PE7_FN),
+ PINMUX_DATA(USB_PENC0_MARK, PE6_FN),
+
+ /* PF FN */
+ PINMUX_DATA(HAC1_SDOUT_MARK, P2MSEL15_0, P2MSEL14_0, PF7_FN),
+ PINMUX_DATA(HAC1_SDIN_MARK, P2MSEL15_0, P2MSEL14_0, PF6_FN),
+ PINMUX_DATA(HAC1_SYNC_MARK, P2MSEL15_0, P2MSEL14_0, PF5_FN),
+ PINMUX_DATA(HAC1_BITCLK_MARK, P2MSEL15_0, P2MSEL14_0, PF4_FN),
+ PINMUX_DATA(HAC0_SDOUT_MARK, P2MSEL13_0, P2MSEL12_0, PF3_FN),
+ PINMUX_DATA(HAC0_SDIN_MARK, P2MSEL13_0, P2MSEL12_0, PF2_FN),
+ PINMUX_DATA(HAC0_SYNC_MARK, P2MSEL13_0, P2MSEL12_0, PF1_FN),
+ PINMUX_DATA(HAC0_BITCLK_MARK, P2MSEL13_0, P2MSEL12_0, PF0_FN),
+ PINMUX_DATA(SSI1_SDATA_MARK, P2MSEL15_0, P2MSEL14_1, PF7_FN),
+ PINMUX_DATA(SSI1_SCK_MARK, P2MSEL15_0, P2MSEL14_1, PF6_FN),
+ PINMUX_DATA(SSI1_WS_MARK, P2MSEL15_0, P2MSEL14_1, PF5_FN),
+ PINMUX_DATA(SSI1_CLK_MARK, P2MSEL15_0, P2MSEL14_1, PF4_FN),
+ PINMUX_DATA(SSI0_SDATA_MARK, P2MSEL13_0, P2MSEL12_1, PF3_FN),
+ PINMUX_DATA(SSI0_SCK_MARK, P2MSEL13_0, P2MSEL12_1, PF2_FN),
+ PINMUX_DATA(SSI0_WS_MARK, P2MSEL13_0, P2MSEL12_1, PF1_FN),
+ PINMUX_DATA(SSI0_CLK_MARK, P2MSEL13_0, P2MSEL12_1, PF0_FN),
+ PINMUX_DATA(SDIF1CMD_MARK, P2MSEL15_1, P2MSEL14_0, PF7_FN),
+ PINMUX_DATA(SDIF1CD_MARK, P2MSEL15_1, P2MSEL14_0, PF6_FN),
+ PINMUX_DATA(SDIF1WP_MARK, P2MSEL15_1, P2MSEL14_0, PF5_FN),
+ PINMUX_DATA(SDIF1CLK_MARK, P2MSEL15_1, P2MSEL14_0, PF4_FN),
+ PINMUX_DATA(SDIF1D3_MARK, P2MSEL13_1, P2MSEL12_0, PF3_FN),
+ PINMUX_DATA(SDIF1D2_MARK, P2MSEL13_1, P2MSEL12_0, PF2_FN),
+ PINMUX_DATA(SDIF1D1_MARK, P2MSEL13_1, P2MSEL12_0, PF1_FN),
+ PINMUX_DATA(SDIF1D0_MARK, P2MSEL13_1, P2MSEL12_0, PF0_FN),
+
+ /* PG FN */
+ PINMUX_DATA(SCIF3_SCK_MARK, P1MSEL8_0, PG7_FN),
+ PINMUX_DATA(SSI2_SDATA_MARK, P1MSEL8_1, PG7_FN),
+ PINMUX_DATA(SCIF3_RXD_MARK, P1MSEL7_0, P1MSEL6_0, PG6_FN),
+ PINMUX_DATA(SSI2_SCK_MARK, P1MSEL7_1, P1MSEL6_0, PG6_FN),
+ PINMUX_DATA(TCLK_MARK, P1MSEL7_0, P1MSEL6_1, PG6_FN),
+ PINMUX_DATA(SCIF3_TXD_MARK, P1MSEL5_0, P1MSEL4_0, PG5_FN),
+ PINMUX_DATA(SSI2_WS_MARK, P1MSEL5_1, P1MSEL4_0, PG5_FN),
+ PINMUX_DATA(HAC_RES_MARK, P1MSEL5_0, P1MSEL4_1, PG5_FN),
+
+ /* PH FN */
+ PINMUX_DATA(DACK3_MARK, P2MSEL4_0, PH7_FN),
+ PINMUX_DATA(SDIF0CMD_MARK, P2MSEL4_1, PH7_FN),
+ PINMUX_DATA(DACK2_MARK, P2MSEL4_0, PH6_FN),
+ PINMUX_DATA(SDIF0CD_MARK, P2MSEL4_1, PH6_FN),
+ PINMUX_DATA(DREQ3_MARK, P2MSEL4_0, PH5_FN),
+ PINMUX_DATA(SDIF0WP_MARK, P2MSEL4_1, PH5_FN),
+ PINMUX_DATA(DREQ2_MARK, P2MSEL3_0, P2MSEL2_1, PH4_FN),
+ PINMUX_DATA(SDIF0CLK_MARK, P2MSEL3_1, P2MSEL2_0, PH4_FN),
+ PINMUX_DATA(SCIF0_CTS_MARK, P2MSEL3_0, P2MSEL2_0, PH4_FN),
+ PINMUX_DATA(SDIF0D3_MARK, P2MSEL1_1, P2MSEL0_0, PH3_FN),
+ PINMUX_DATA(SCIF0_RTS_MARK, P2MSEL1_0, P2MSEL0_0, PH3_FN),
+ PINMUX_DATA(IRL7_MARK, P2MSEL1_0, P2MSEL0_1, PH3_FN),
+ PINMUX_DATA(SDIF0D2_MARK, P2MSEL1_1, P2MSEL0_0, PH2_FN),
+ PINMUX_DATA(SCIF0_SCK_MARK, P2MSEL1_0, P2MSEL0_0, PH2_FN),
+ PINMUX_DATA(IRL6_MARK, P2MSEL1_0, P2MSEL0_1, PH2_FN),
+ PINMUX_DATA(SDIF0D1_MARK, P2MSEL1_1, P2MSEL0_0, PH1_FN),
+ PINMUX_DATA(SCIF0_RXD_MARK, P2MSEL1_0, P2MSEL0_0, PH1_FN),
+ PINMUX_DATA(IRL5_MARK, P2MSEL1_0, P2MSEL0_1, PH1_FN),
+ PINMUX_DATA(SDIF0D0_MARK, P2MSEL1_1, P2MSEL0_0, PH0_FN),
+ PINMUX_DATA(SCIF0_TXD_MARK, P2MSEL1_0, P2MSEL0_0, PH0_FN),
+ PINMUX_DATA(IRL4_MARK, P2MSEL1_0, P2MSEL0_1, PH0_FN),
+
+ /* PJ FN */
+ PINMUX_DATA(SCIF5_SCK_MARK, P2MSEL11_1, PJ7_FN),
+ PINMUX_DATA(FRB_MARK, P2MSEL11_0, PJ7_FN),
+ PINMUX_DATA(SCIF5_RXD_MARK, P2MSEL10_0, PJ6_FN),
+ PINMUX_DATA(IOIS16_MARK, P2MSEL10_1, PJ6_FN),
+ PINMUX_DATA(SCIF5_TXD_MARK, P2MSEL10_0, PJ5_FN),
+ PINMUX_DATA(CE2B_MARK, P2MSEL10_1, PJ5_FN),
+ PINMUX_DATA(DRAK3_MARK, P2MSEL7_0, PJ4_FN),
+ PINMUX_DATA(CE2A_MARK, P2MSEL7_1, PJ4_FN),
+ PINMUX_DATA(SCIF4_SCK_MARK, P2MSEL9_0, P2MSEL8_0, PJ3_FN),
+ PINMUX_DATA(DRAK2_MARK, P2MSEL9_0, P2MSEL8_1, PJ3_FN),
+ PINMUX_DATA(SSI3_WS_MARK, P2MSEL9_1, P2MSEL8_0, PJ3_FN),
+ PINMUX_DATA(SCIF4_RXD_MARK, P2MSEL6_1, P2MSEL5_0, PJ2_FN),
+ PINMUX_DATA(DRAK1_MARK, P2MSEL6_0, P2MSEL5_1, PJ2_FN),
+ PINMUX_DATA(FSTATUS_MARK, P2MSEL6_0, P2MSEL5_0, PJ2_FN),
+ PINMUX_DATA(SSI3_SDATA_MARK, P2MSEL6_1, P2MSEL5_1, PJ2_FN),
+ PINMUX_DATA(SCIF4_TXD_MARK, P2MSEL6_1, P2MSEL5_0, PJ1_FN),
+ PINMUX_DATA(DRAK0_MARK, P2MSEL6_0, P2MSEL5_1, PJ1_FN),
+ PINMUX_DATA(FSE_MARK, P2MSEL6_0, P2MSEL5_0, PJ1_FN),
+ PINMUX_DATA(SSI3_SCK_MARK, P2MSEL6_1, P2MSEL5_1, PJ1_FN),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ /* PA */
+ PINMUX_GPIO(GPIO_PA7, PA7_DATA),
+ PINMUX_GPIO(GPIO_PA6, PA6_DATA),
+ PINMUX_GPIO(GPIO_PA5, PA5_DATA),
+ PINMUX_GPIO(GPIO_PA4, PA4_DATA),
+ PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+ PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+ PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+ PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+ /* PB */
+ PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+ PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+ PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+ PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+ PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+ PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+ PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+ PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+
+ /* PC */
+ PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+ PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+ PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+ PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+ PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+ PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+ PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+ PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+ /* PD */
+ PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+ PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+ PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+ PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+ PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+ PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+ PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+ PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+ /* PE */
+ PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+ PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+
+ /* PF */
+ PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+ PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+ PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+ PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+ PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+ PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+ PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+ PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+ /* PG */
+ PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+ PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+ PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+
+ /* PH */
+ PINMUX_GPIO(GPIO_PH7, PH7_DATA),
+ PINMUX_GPIO(GPIO_PH6, PH6_DATA),
+ PINMUX_GPIO(GPIO_PH5, PH5_DATA),
+ PINMUX_GPIO(GPIO_PH4, PH4_DATA),
+ PINMUX_GPIO(GPIO_PH3, PH3_DATA),
+ PINMUX_GPIO(GPIO_PH2, PH2_DATA),
+ PINMUX_GPIO(GPIO_PH1, PH1_DATA),
+ PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+
+ /* PJ */
+ PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+ PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+ PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+ PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+ PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+ PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+ PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+
+ /* FN */
+ PINMUX_GPIO(GPIO_FN_CDE, CDE_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_MAGIC, ETH_MAGIC_MARK),
+ PINMUX_GPIO(GPIO_FN_DISP, DISP_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_LINK, ETH_LINK_MARK),
+ PINMUX_GPIO(GPIO_FN_DR5, DR5_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_TX_ER, ETH_TX_ER_MARK),
+ PINMUX_GPIO(GPIO_FN_DR4, DR4_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_TX_EN, ETH_TX_EN_MARK),
+ PINMUX_GPIO(GPIO_FN_DR3, DR3_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_TXD3, ETH_TXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_DR2, DR2_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_TXD2, ETH_TXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_DR1, DR1_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_TXD1, ETH_TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_DR0, DR0_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_TXD0, ETH_TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_VSYNC, VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_HSPI_CLK, HSPI_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_ODDF, ODDF_MARK),
+ PINMUX_GPIO(GPIO_FN_HSPI_CS, HSPI_CS_MARK),
+ PINMUX_GPIO(GPIO_FN_DG5, DG5_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_MDIO, ETH_MDIO_MARK),
+ PINMUX_GPIO(GPIO_FN_DG4, DG4_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_RX_CLK, ETH_RX_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_DG3, DG3_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_MDC, ETH_MDC_MARK),
+ PINMUX_GPIO(GPIO_FN_DG2, DG2_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_COL, ETH_COL_MARK),
+ PINMUX_GPIO(GPIO_FN_DG1, DG1_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_TX_CLK, ETH_TX_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_DG0, DG0_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_CRS, ETH_CRS_MARK),
+ PINMUX_GPIO(GPIO_FN_DCLKIN, DCLKIN_MARK),
+ PINMUX_GPIO(GPIO_FN_HSPI_RX, HSPI_RX_MARK),
+ PINMUX_GPIO(GPIO_FN_HSYNC, HSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_HSPI_TX, HSPI_TX_MARK),
+ PINMUX_GPIO(GPIO_FN_DB5, DB5_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_RXD3, ETH_RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_DB4, DB4_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_RXD2, ETH_RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_DB3, DB3_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_RXD1, ETH_RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_DB2, DB2_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_RXD0, ETH_RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_DB1, DB1_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_RX_DV, ETH_RX_DV_MARK),
+ PINMUX_GPIO(GPIO_FN_DB0, DB0_MARK),
+ PINMUX_GPIO(GPIO_FN_ETH_RX_ER, ETH_RX_ER_MARK),
+ PINMUX_GPIO(GPIO_FN_DCLKOUT, DCLKOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_SCK, SCIF1_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_RXD, SCIF1_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF1_TXD, SCIF1_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+ PINMUX_GPIO(GPIO_FN_FALE, FALE_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_FCLE, FCLE_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_USB_OVC1, USB_OVC1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_USB_OVC0, USB_OVC0_MARK),
+ PINMUX_GPIO(GPIO_FN_USB_PENC1, USB_PENC1_MARK),
+ PINMUX_GPIO(GPIO_FN_USB_PENC0, USB_PENC0_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC1_SDOUT, HAC1_SDOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI1_SDATA, SSI1_SDATA_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF1CMD, SDIF1CMD_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC1_SDIN, HAC1_SDIN_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI1_SCK, SSI1_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF1CD, SDIF1CD_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC1_SYNC, HAC1_SYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI1_WS, SSI1_WS_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF1WP, SDIF1WP_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC1_BITCLK, HAC1_BITCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI1_CLK, SSI1_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF1CLK, SDIF1CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC0_SDOUT, HAC0_SDOUT_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI0_SDATA, SSI0_SDATA_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF1D3, SDIF1D3_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC0_SDIN, HAC0_SDIN_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI0_SCK, SSI0_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF1D2, SDIF1D2_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC0_SYNC, HAC0_SYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI0_WS, SSI0_WS_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF1D1, SDIF1D1_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC0_BITCLK, HAC0_BITCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI0_CLK, SSI0_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF1D0, SDIF1D0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_SCK, SCIF3_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI2_SDATA, SSI2_SDATA_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_RXD, SCIF3_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI2_SCK, SSI2_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF3_TXD, SCIF3_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_HAC_RES, HAC_RES_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI2_WS, SSI2_WS_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK3, DACK3_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF0CMD, SDIF0CMD_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK2, DACK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF0CD, SDIF0CD_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ3, DREQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF0WP, SDIF0WP_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_CTS, SCIF0_CTS_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ2, DREQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF0CLK, SDIF0CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_RTS, SCIF0_RTS_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL7, IRL7_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF0D3, SDIF0D3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_SCK, SCIF0_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL6, IRL6_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF0D2, SDIF0D2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_RXD, SCIF0_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL5, IRL5_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF0D1, SDIF0D1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF0_TXD, SCIF0_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL4, IRL4_MARK),
+ PINMUX_GPIO(GPIO_FN_SDIF0D0, SDIF0D0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_SCK, SCIF5_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_RXD, SCIF5_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF5_TXD, SCIF5_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK3, DRAK3_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_SCK, SCIF4_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK2, DRAK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI3_WS, SSI3_WS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_RXD, SCIF4_RXD_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK1, DRAK1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI3_SDATA, SSI3_SDATA_MARK),
+ PINMUX_GPIO(GPIO_FN_FSTATUS, FSTATUS_MARK),
+ PINMUX_GPIO(GPIO_FN_SCIF4_TXD, SCIF4_TXD_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK0, DRAK0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSI3_SCK, SSI3_SCK_MARK),
+ PINMUX_GPIO(GPIO_FN_FSE, FSE_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PACR", 0xffcc0000, 16, 2) {
+ PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
+ PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
+ PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
+ PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
+ PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
+ PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
+ PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
+ PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PBCR", 0xffcc0002, 16, 2) {
+ PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
+ PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
+ PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
+ PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
+ PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
+ PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
+ PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
+ PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PCCR", 0xffcc0004, 16, 2) {
+ PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
+ PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
+ PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
+ PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
+ PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
+ PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
+ PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
+ PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PDCR", 0xffcc0006, 16, 2) {
+ PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
+ PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
+ PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
+ PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
+ PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
+ PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
+ PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
+ PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PECR", 0xffcc0008, 16, 2) {
+ PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
+ PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, }
+ },
+ { PINMUX_CFG_REG("PFCR", 0xffcc000a, 16, 2) {
+ PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
+ PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
+ PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
+ PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
+ PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
+ PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
+ PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
+ PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PGCR", 0xffcc000c, 16, 2) {
+ PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
+ PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
+ PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, }
+ },
+ { PINMUX_CFG_REG("PHCR", 0xffcc000e, 16, 2) {
+ PH7_FN, PH7_OUT, PH7_IN, PH7_IN_PU,
+ PH6_FN, PH6_OUT, PH6_IN, PH6_IN_PU,
+ PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
+ PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
+ PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
+ PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
+ PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
+ PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU }
+ },
+ { PINMUX_CFG_REG("PJCR", 0xffcc0010, 16, 2) {
+ PJ7_FN, PJ7_OUT, PJ7_IN, PJ7_IN_PU,
+ PJ6_FN, PJ6_OUT, PJ6_IN, PJ6_IN_PU,
+ PJ5_FN, PJ5_OUT, PJ5_IN, PJ5_IN_PU,
+ PJ4_FN, PJ4_OUT, PJ4_IN, PJ4_IN_PU,
+ PJ3_FN, PJ3_OUT, PJ3_IN, PJ3_IN_PU,
+ PJ2_FN, PJ2_OUT, PJ2_IN, PJ2_IN_PU,
+ PJ1_FN, PJ1_OUT, PJ1_IN, PJ1_IN_PU,
+ 0, 0, 0, 0, }
+ },
+ { PINMUX_CFG_REG("P1MSELR", 0xffcc0080, 16, 1) {
+ 0, 0,
+ P1MSEL14_0, P1MSEL14_1,
+ P1MSEL13_0, P1MSEL13_1,
+ P1MSEL12_0, P1MSEL12_1,
+ P1MSEL11_0, P1MSEL11_1,
+ P1MSEL10_0, P1MSEL10_1,
+ P1MSEL9_0, P1MSEL9_1,
+ P1MSEL8_0, P1MSEL8_1,
+ P1MSEL7_0, P1MSEL7_1,
+ P1MSEL6_0, P1MSEL6_1,
+ P1MSEL5_0, P1MSEL5_1,
+ P1MSEL4_0, P1MSEL4_1,
+ P1MSEL3_0, P1MSEL3_1,
+ P1MSEL2_0, P1MSEL2_1,
+ P1MSEL1_0, P1MSEL1_1,
+ P1MSEL0_0, P1MSEL0_1 }
+ },
+ { PINMUX_CFG_REG("P2MSELR", 0xffcc0082, 16, 1) {
+ P2MSEL15_0, P2MSEL15_1,
+ P2MSEL14_0, P2MSEL14_1,
+ P2MSEL13_0, P2MSEL13_1,
+ P2MSEL12_0, P2MSEL12_1,
+ P2MSEL11_0, P2MSEL11_1,
+ P2MSEL10_0, P2MSEL10_1,
+ P2MSEL9_0, P2MSEL9_1,
+ P2MSEL8_0, P2MSEL8_1,
+ P2MSEL7_0, P2MSEL7_1,
+ P2MSEL6_0, P2MSEL6_1,
+ P2MSEL5_0, P2MSEL5_1,
+ P2MSEL4_0, P2MSEL4_1,
+ P2MSEL3_0, P2MSEL3_1,
+ P2MSEL2_0, P2MSEL2_1,
+ P2MSEL1_0, P2MSEL1_1,
+ P2MSEL0_0, P2MSEL0_1 }
+ },
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR", 0xffcc0020, 8) {
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA }
+ },
+ { PINMUX_DATA_REG("PBDR", 0xffcc0022, 8) {
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA }
+ },
+ { PINMUX_DATA_REG("PCDR", 0xffcc0024, 8) {
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+ },
+ { PINMUX_DATA_REG("PDDR", 0xffcc0026, 8) {
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+ },
+ { PINMUX_DATA_REG("PEDR", 0xffcc0028, 8) {
+ PE7_DATA, PE6_DATA,
+ 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_DATA_REG("PFDR", 0xffcc002a, 8) {
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+ },
+ { PINMUX_DATA_REG("PGDR", 0xffcc002c, 8) {
+ PG7_DATA, PG6_DATA, PG5_DATA, 0,
+ 0, 0, 0, 0 }
+ },
+ { PINMUX_DATA_REG("PHDR", 0xffcc002e, 8) {
+ PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR", 0xffcc0030, 8) {
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, 0 }
+ },
+ { },
+};
+
+struct sh_pfc_soc_info sh7786_pinmux_info = {
+ .name = "sh7786_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PA7,
+ .last_gpio = GPIO_FN_IRL4,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-shx3.c b/drivers/pinctrl/sh-pfc/pfc-shx3.c
new file mode 100644
index 000000000000..ccf6918b03c6
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-shx3.c
@@ -0,0 +1,582 @@
+/*
+ * SH-X3 prototype CPU pinmux
+ *
+ * Copyright (C) 2010 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <cpu/shx3.h>
+
+#include "sh_pfc.h"
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+
+ PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ PA7_IN, PA6_IN, PA5_IN, PA4_IN,
+ PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+ PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+ PB3_IN, PB2_IN, PB1_IN, PB0_IN,
+ PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+ PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+ PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+ PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+ PE7_IN, PE6_IN, PE5_IN, PE4_IN,
+ PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+ PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+ PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+ PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+ PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+
+ PH5_IN, PH4_IN,
+ PH3_IN, PH2_IN, PH1_IN, PH0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_INPUT_PULLUP_BEGIN,
+ PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
+ PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
+ PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
+ PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
+ PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
+ PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
+ PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
+ PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
+ PE7_IN_PU, PE6_IN_PU, PE5_IN_PU, PE4_IN_PU,
+ PE3_IN_PU, PE2_IN_PU, PE1_IN_PU, PE0_IN_PU,
+ PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
+ PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
+ PG7_IN_PU, PG6_IN_PU, PG5_IN_PU, PG4_IN_PU,
+ PG3_IN_PU, PG2_IN_PU, PG1_IN_PU, PG0_IN_PU,
+
+ PH5_IN_PU, PH4_IN_PU,
+ PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
+ PINMUX_INPUT_PULLUP_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
+ PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+ PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+ PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
+ PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+ PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+ PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+ PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+ PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
+ PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+ PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+ PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+ PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+ PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+
+ PH5_OUT, PH4_OUT,
+ PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PA7_FN, PA6_FN, PA5_FN, PA4_FN,
+ PA3_FN, PA2_FN, PA1_FN, PA0_FN,
+ PB7_FN, PB6_FN, PB5_FN, PB4_FN,
+ PB3_FN, PB2_FN, PB1_FN, PB0_FN,
+ PC7_FN, PC6_FN, PC5_FN, PC4_FN,
+ PC3_FN, PC2_FN, PC1_FN, PC0_FN,
+ PD7_FN, PD6_FN, PD5_FN, PD4_FN,
+ PD3_FN, PD2_FN, PD1_FN, PD0_FN,
+ PE7_FN, PE6_FN, PE5_FN, PE4_FN,
+ PE3_FN, PE2_FN, PE1_FN, PE0_FN,
+ PF7_FN, PF6_FN, PF5_FN, PF4_FN,
+ PF3_FN, PF2_FN, PF1_FN, PF0_FN,
+ PG7_FN, PG6_FN, PG5_FN, PG4_FN,
+ PG3_FN, PG2_FN, PG1_FN, PG0_FN,
+
+ PH5_FN, PH4_FN,
+ PH3_FN, PH2_FN, PH1_FN, PH0_FN,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+
+ D31_MARK, D30_MARK, D29_MARK, D28_MARK, D27_MARK, D26_MARK,
+ D25_MARK, D24_MARK, D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+ D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+
+ BACK_MARK, BREQ_MARK,
+ WE3_MARK, WE2_MARK,
+ CS6_MARK, CS5_MARK, CS4_MARK,
+ CLKOUTENB_MARK,
+
+ DACK3_MARK, DACK2_MARK, DACK1_MARK, DACK0_MARK,
+ DREQ3_MARK, DREQ2_MARK, DREQ1_MARK, DREQ0_MARK,
+
+ IRQ3_MARK, IRQ2_MARK, IRQ1_MARK, IRQ0_MARK,
+
+ DRAK3_MARK, DRAK2_MARK, DRAK1_MARK, DRAK0_MARK,
+
+ SCK3_MARK, SCK2_MARK, SCK1_MARK, SCK0_MARK,
+ IRL3_MARK, IRL2_MARK, IRL1_MARK, IRL0_MARK,
+ TXD3_MARK, TXD2_MARK, TXD1_MARK, TXD0_MARK,
+ RXD3_MARK, RXD2_MARK, RXD1_MARK, RXD0_MARK,
+
+ CE2B_MARK, CE2A_MARK, IOIS16_MARK,
+ STATUS1_MARK, STATUS0_MARK,
+
+ IRQOUT_MARK,
+
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t shx3_pinmux_data[] = {
+
+ /* PA GPIO */
+ PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
+ PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
+ PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
+ PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
+ PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
+ PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
+ PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
+ PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+
+ /* PB GPIO */
+ PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
+ PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
+ PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
+ PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
+ PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
+ PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
+ PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
+ PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+
+ /* PC GPIO */
+ PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
+ PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
+ PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
+ PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
+ PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
+ PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
+ PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
+ PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+
+ /* PD GPIO */
+ PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
+ PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
+ PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
+ PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
+ PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
+ PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
+ PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
+ PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+
+ /* PE GPIO */
+ PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
+ PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
+ PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT, PE5_IN_PU),
+ PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT, PE4_IN_PU),
+ PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT, PE3_IN_PU),
+ PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT, PE2_IN_PU),
+ PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT, PE1_IN_PU),
+ PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT, PE0_IN_PU),
+
+ /* PF GPIO */
+ PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
+ PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
+ PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
+ PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
+ PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
+ PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
+ PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
+ PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+
+ /* PG GPIO */
+ PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
+ PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
+ PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
+ PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT, PG4_IN_PU),
+ PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT, PG3_IN_PU),
+ PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT, PG2_IN_PU),
+ PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT, PG1_IN_PU),
+ PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT, PG0_IN_PU),
+
+ /* PH GPIO */
+ PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
+ PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
+ PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
+ PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
+ PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
+ PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+
+ /* PA FN */
+ PINMUX_DATA(D31_MARK, PA7_FN),
+ PINMUX_DATA(D30_MARK, PA6_FN),
+ PINMUX_DATA(D29_MARK, PA5_FN),
+ PINMUX_DATA(D28_MARK, PA4_FN),
+ PINMUX_DATA(D27_MARK, PA3_FN),
+ PINMUX_DATA(D26_MARK, PA2_FN),
+ PINMUX_DATA(D25_MARK, PA1_FN),
+ PINMUX_DATA(D24_MARK, PA0_FN),
+
+ /* PB FN */
+ PINMUX_DATA(D23_MARK, PB7_FN),
+ PINMUX_DATA(D22_MARK, PB6_FN),
+ PINMUX_DATA(D21_MARK, PB5_FN),
+ PINMUX_DATA(D20_MARK, PB4_FN),
+ PINMUX_DATA(D19_MARK, PB3_FN),
+ PINMUX_DATA(D18_MARK, PB2_FN),
+ PINMUX_DATA(D17_MARK, PB1_FN),
+ PINMUX_DATA(D16_MARK, PB0_FN),
+
+ /* PC FN */
+ PINMUX_DATA(BACK_MARK, PC7_FN),
+ PINMUX_DATA(BREQ_MARK, PC6_FN),
+ PINMUX_DATA(WE3_MARK, PC5_FN),
+ PINMUX_DATA(WE2_MARK, PC4_FN),
+ PINMUX_DATA(CS6_MARK, PC3_FN),
+ PINMUX_DATA(CS5_MARK, PC2_FN),
+ PINMUX_DATA(CS4_MARK, PC1_FN),
+ PINMUX_DATA(CLKOUTENB_MARK, PC0_FN),
+
+ /* PD FN */
+ PINMUX_DATA(DACK3_MARK, PD7_FN),
+ PINMUX_DATA(DACK2_MARK, PD6_FN),
+ PINMUX_DATA(DACK1_MARK, PD5_FN),
+ PINMUX_DATA(DACK0_MARK, PD4_FN),
+ PINMUX_DATA(DREQ3_MARK, PD3_FN),
+ PINMUX_DATA(DREQ2_MARK, PD2_FN),
+ PINMUX_DATA(DREQ1_MARK, PD1_FN),
+ PINMUX_DATA(DREQ0_MARK, PD0_FN),
+
+ /* PE FN */
+ PINMUX_DATA(IRQ3_MARK, PE7_FN),
+ PINMUX_DATA(IRQ2_MARK, PE6_FN),
+ PINMUX_DATA(IRQ1_MARK, PE5_FN),
+ PINMUX_DATA(IRQ0_MARK, PE4_FN),
+ PINMUX_DATA(DRAK3_MARK, PE3_FN),
+ PINMUX_DATA(DRAK2_MARK, PE2_FN),
+ PINMUX_DATA(DRAK1_MARK, PE1_FN),
+ PINMUX_DATA(DRAK0_MARK, PE0_FN),
+
+ /* PF FN */
+ PINMUX_DATA(SCK3_MARK, PF7_FN),
+ PINMUX_DATA(SCK2_MARK, PF6_FN),
+ PINMUX_DATA(SCK1_MARK, PF5_FN),
+ PINMUX_DATA(SCK0_MARK, PF4_FN),
+ PINMUX_DATA(IRL3_MARK, PF3_FN),
+ PINMUX_DATA(IRL2_MARK, PF2_FN),
+ PINMUX_DATA(IRL1_MARK, PF1_FN),
+ PINMUX_DATA(IRL0_MARK, PF0_FN),
+
+ /* PG FN */
+ PINMUX_DATA(TXD3_MARK, PG7_FN),
+ PINMUX_DATA(TXD2_MARK, PG6_FN),
+ PINMUX_DATA(TXD1_MARK, PG5_FN),
+ PINMUX_DATA(TXD0_MARK, PG4_FN),
+ PINMUX_DATA(RXD3_MARK, PG3_FN),
+ PINMUX_DATA(RXD2_MARK, PG2_FN),
+ PINMUX_DATA(RXD1_MARK, PG1_FN),
+ PINMUX_DATA(RXD0_MARK, PG0_FN),
+
+ /* PH FN */
+ PINMUX_DATA(CE2B_MARK, PH5_FN),
+ PINMUX_DATA(CE2A_MARK, PH4_FN),
+ PINMUX_DATA(IOIS16_MARK, PH3_FN),
+ PINMUX_DATA(STATUS1_MARK, PH2_FN),
+ PINMUX_DATA(STATUS0_MARK, PH1_FN),
+ PINMUX_DATA(IRQOUT_MARK, PH0_FN),
+};
+
+static struct pinmux_gpio shx3_pinmux_gpios[] = {
+ /* PA */
+ PINMUX_GPIO(GPIO_PA7, PA7_DATA),
+ PINMUX_GPIO(GPIO_PA6, PA6_DATA),
+ PINMUX_GPIO(GPIO_PA5, PA5_DATA),
+ PINMUX_GPIO(GPIO_PA4, PA4_DATA),
+ PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+ PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+ PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+ PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+ /* PB */
+ PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+ PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+ PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+ PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+ PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+ PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+ PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+ PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+
+ /* PC */
+ PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+ PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+ PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+ PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+ PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+ PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+ PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+ PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+ /* PD */
+ PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+ PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+ PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+ PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+ PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+ PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+ PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+ PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+ /* PE */
+ PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+ PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+ PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+ PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+ PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+ PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+ PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+ PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+ /* PF */
+ PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+ PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+ PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+ PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+ PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+ PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+ PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+ PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+ /* PG */
+ PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+ PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+ PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+ PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+ PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+ PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+ PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+ PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+ /* PH */
+ PINMUX_GPIO(GPIO_PH5, PH5_DATA),
+ PINMUX_GPIO(GPIO_PH4, PH4_DATA),
+ PINMUX_GPIO(GPIO_PH3, PH3_DATA),
+ PINMUX_GPIO(GPIO_PH2, PH2_DATA),
+ PINMUX_GPIO(GPIO_PH1, PH1_DATA),
+ PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+
+ /* FN */
+ PINMUX_GPIO(GPIO_FN_D31, D31_MARK),
+ PINMUX_GPIO(GPIO_FN_D30, D30_MARK),
+ PINMUX_GPIO(GPIO_FN_D29, D29_MARK),
+ PINMUX_GPIO(GPIO_FN_D28, D28_MARK),
+ PINMUX_GPIO(GPIO_FN_D27, D27_MARK),
+ PINMUX_GPIO(GPIO_FN_D26, D26_MARK),
+ PINMUX_GPIO(GPIO_FN_D25, D25_MARK),
+ PINMUX_GPIO(GPIO_FN_D24, D24_MARK),
+ PINMUX_GPIO(GPIO_FN_D23, D23_MARK),
+ PINMUX_GPIO(GPIO_FN_D22, D22_MARK),
+ PINMUX_GPIO(GPIO_FN_D21, D21_MARK),
+ PINMUX_GPIO(GPIO_FN_D20, D20_MARK),
+ PINMUX_GPIO(GPIO_FN_D19, D19_MARK),
+ PINMUX_GPIO(GPIO_FN_D18, D18_MARK),
+ PINMUX_GPIO(GPIO_FN_D17, D17_MARK),
+ PINMUX_GPIO(GPIO_FN_D16, D16_MARK),
+ PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+ PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_WE3, WE3_MARK),
+ PINMUX_GPIO(GPIO_FN_WE2, WE2_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_CLKOUTENB, CLKOUTENB_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK3, DACK3_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK2, DACK2_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ3, DREQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ2, DREQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3, IRQ3_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK3, DRAK3_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK2, DRAK2_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK1, DRAK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DRAK0, DRAK0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL3, IRL3_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL2, IRL2_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL1, IRL1_MARK),
+ PINMUX_GPIO(GPIO_FN_IRL0, IRL0_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
+ PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQOUT, IRQOUT_MARK),
+};
+
+static struct pinmux_cfg_reg shx3_pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PABCR", 0xffc70000, 32, 2) {
+ PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
+ PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
+ PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
+ PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
+ PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
+ PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
+ PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
+ PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU,
+ PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
+ PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
+ PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
+ PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
+ PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
+ PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
+ PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
+ PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU, },
+ },
+ { PINMUX_CFG_REG("PCDCR", 0xffc70004, 32, 2) {
+ PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
+ PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
+ PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
+ PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
+ PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
+ PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
+ PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
+ PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU,
+ PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
+ PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
+ PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
+ PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
+ PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
+ PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
+ PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
+ PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU, },
+ },
+ { PINMUX_CFG_REG("PEFCR", 0xffc70008, 32, 2) {
+ PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
+ PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
+ PE5_FN, PE5_OUT, PE5_IN, PE5_IN_PU,
+ PE4_FN, PE4_OUT, PE4_IN, PE4_IN_PU,
+ PE3_FN, PE3_OUT, PE3_IN, PE3_IN_PU,
+ PE2_FN, PE2_OUT, PE2_IN, PE2_IN_PU,
+ PE1_FN, PE1_OUT, PE1_IN, PE1_IN_PU,
+ PE0_FN, PE0_OUT, PE0_IN, PE0_IN_PU,
+ PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
+ PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
+ PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
+ PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
+ PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
+ PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
+ PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
+ PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU, },
+ },
+ { PINMUX_CFG_REG("PGHCR", 0xffc7000c, 32, 2) {
+ PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
+ PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
+ PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
+ PG4_FN, PG4_OUT, PG4_IN, PG4_IN_PU,
+ PG3_FN, PG3_OUT, PG3_IN, PG3_IN_PU,
+ PG2_FN, PG2_OUT, PG2_IN, PG2_IN_PU,
+ PG1_FN, PG1_OUT, PG1_IN, PG1_IN_PU,
+ PG0_FN, PG0_OUT, PG0_IN, PG0_IN_PU,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
+ PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
+ PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
+ PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
+ PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
+ PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU, },
+ },
+ { },
+};
+
+static struct pinmux_data_reg shx3_pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PABDR", 0xffc70010, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA, },
+ },
+ { PINMUX_DATA_REG("PCDDR", 0xffc70014, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA, },
+ },
+ { PINMUX_DATA_REG("PEFDR", 0xffc70018, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA, },
+ },
+ { PINMUX_DATA_REG("PGHDR", 0xffc7001c, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA, },
+ },
+ { },
+};
+
+struct sh_pfc_soc_info shx3_pinmux_info = {
+ .name = "shx3_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .input_pu = { PINMUX_INPUT_PULLUP_BEGIN,
+ PINMUX_INPUT_PULLUP_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+ .first_gpio = GPIO_PA7,
+ .last_gpio = GPIO_FN_STATUS0,
+ .gpios = shx3_pinmux_gpios,
+ .gpio_data = shx3_pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(shx3_pinmux_data),
+ .cfg_regs = shx3_pinmux_config_regs,
+ .data_regs = shx3_pinmux_data_regs,
+};
diff --git a/drivers/sh/pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c
index 4109b769eac0..11e0e1374d65 100644
--- a/drivers/sh/pfc/pinctrl.c
+++ b/drivers/pinctrl/sh-pfc/pinctrl.c
@@ -7,22 +7,23 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-#define DRV_NAME "pinctrl-sh_pfc"
-#define pr_fmt(fmt) DRV_NAME " " KBUILD_MODNAME ": " fmt
+#define DRV_NAME "sh-pfc"
+#define pr_fmt(fmt) KBUILD_MODNAME " pinctrl: " fmt
+#include <linux/device.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/sh_pfc.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
-#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinconf.h>
-#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "core.h"
struct sh_pfc_pinctrl {
struct pinctrl_dev *pctl;
@@ -37,8 +38,6 @@ struct sh_pfc_pinctrl {
spinlock_t lock;
};
-static struct sh_pfc_pinctrl *sh_pfc_pmx;
-
static int sh_pfc_get_groups_count(struct pinctrl_dev *pctldev)
{
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
@@ -116,7 +115,7 @@ static void sh_pfc_noop_disable(struct pinctrl_dev *pctldev, unsigned func,
{
}
-static inline int sh_pfc_config_function(struct sh_pfc *pfc, unsigned offset)
+static int sh_pfc_config_function(struct sh_pfc *pfc, unsigned offset)
{
if (sh_pfc_config_gpio(pfc, offset,
PINMUX_TYPE_FUNCTION,
@@ -140,7 +139,7 @@ static int sh_pfc_reconfig_pin(struct sh_pfc *pfc, unsigned offset,
spin_lock_irqsave(&pfc->lock, flags);
- pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE;
+ pinmux_type = pfc->info->gpios[offset].flags & PINMUX_FLAG_TYPE;
/*
* See if the present config needs to first be de-configured.
@@ -172,8 +171,8 @@ static int sh_pfc_reconfig_pin(struct sh_pfc *pfc, unsigned offset,
GPIO_CFG_REQ) != 0)
goto err;
- pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
- pfc->gpios[offset].flags |= new_type;
+ pfc->info->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+ pfc->info->gpios[offset].flags |= new_type;
ret = 0;
@@ -195,7 +194,7 @@ static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev,
spin_lock_irqsave(&pfc->lock, flags);
- pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE;
+ pinmux_type = pfc->info->gpios[offset].flags & PINMUX_FLAG_TYPE;
switch (pinmux_type) {
case PINMUX_TYPE_FUNCTION:
@@ -236,7 +235,7 @@ static void sh_pfc_gpio_disable_free(struct pinctrl_dev *pctldev,
spin_lock_irqsave(&pfc->lock, flags);
- pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE;
+ pinmux_type = pfc->info->gpios[offset].flags & PINMUX_FLAG_TYPE;
sh_pfc_config_gpio(pfc, offset, pinmux_type, GPIO_CFG_FREE);
@@ -270,7 +269,7 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
struct sh_pfc *pfc = pmx->pfc;
- *config = pfc->gpios[pin].flags & PINMUX_FLAG_TYPE;
+ *config = pfc->info->gpios[pin].flags & PINMUX_FLAG_TYPE;
return 0;
}
@@ -328,10 +327,8 @@ static struct pinctrl_desc sh_pfc_pinctrl_desc = {
.confops = &sh_pfc_pinconf_ops,
};
-static inline void sh_pfc_map_one_gpio(struct sh_pfc *pfc,
- struct sh_pfc_pinctrl *pmx,
- struct pinmux_gpio *gpio,
- unsigned offset)
+static void sh_pfc_map_one_gpio(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx,
+ struct pinmux_gpio *gpio, unsigned offset)
{
struct pinmux_data_reg *dummy;
unsigned long flags;
@@ -356,10 +353,10 @@ static int sh_pfc_map_gpios(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
unsigned long flags;
int i;
- pmx->nr_pads = pfc->last_gpio - pfc->first_gpio + 1;
+ pmx->nr_pads = pfc->info->last_gpio - pfc->info->first_gpio + 1;
- pmx->pads = kmalloc(sizeof(struct pinctrl_pin_desc) * pmx->nr_pads,
- GFP_KERNEL);
+ pmx->pads = devm_kzalloc(pfc->dev, sizeof(*pmx->pads) * pmx->nr_pads,
+ GFP_KERNEL);
if (unlikely(!pmx->pads)) {
pmx->nr_pads = 0;
return -ENOMEM;
@@ -375,9 +372,9 @@ static int sh_pfc_map_gpios(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
*/
for (i = 0; i < pmx->nr_pads; i++) {
struct pinctrl_pin_desc *pin = pmx->pads + i;
- struct pinmux_gpio *gpio = pfc->gpios + i;
+ struct pinmux_gpio *gpio = pfc->info->gpios + i;
- pin->number = pfc->first_gpio + i;
+ pin->number = pfc->info->first_gpio + i;
pin->name = gpio->name;
/* XXX */
@@ -400,15 +397,15 @@ static int sh_pfc_map_functions(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
unsigned long flags;
int i, fn;
- pmx->functions = kzalloc(pmx->nr_functions * sizeof(void *),
- GFP_KERNEL);
+ pmx->functions = devm_kzalloc(pfc->dev, pmx->nr_functions *
+ sizeof(*pmx->functions), GFP_KERNEL);
if (unlikely(!pmx->functions))
return -ENOMEM;
spin_lock_irqsave(&pmx->lock, flags);
for (i = fn = 0; i < pmx->nr_pads; i++) {
- struct pinmux_gpio *gpio = pfc->gpios + i;
+ struct pinmux_gpio *gpio = pfc->info->gpios + i;
if ((gpio->flags & PINMUX_FLAG_TYPE) == PINMUX_TYPE_FUNCTION)
pmx->functions[fn++] = gpio;
@@ -419,109 +416,48 @@ static int sh_pfc_map_functions(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
return 0;
}
-static int sh_pfc_pinctrl_probe(struct platform_device *pdev)
+int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
{
- struct sh_pfc *pfc;
+ struct sh_pfc_pinctrl *pmx;
int ret;
- if (unlikely(!sh_pfc_pmx))
- return -ENODEV;
+ pmx = devm_kzalloc(pfc->dev, sizeof(*pmx), GFP_KERNEL);
+ if (unlikely(!pmx))
+ return -ENOMEM;
+
+ spin_lock_init(&pmx->lock);
- pfc = sh_pfc_pmx->pfc;
+ pmx->pfc = pfc;
+ pfc->pinctrl = pmx;
- ret = sh_pfc_map_gpios(pfc, sh_pfc_pmx);
+ ret = sh_pfc_map_gpios(pfc, pmx);
if (unlikely(ret != 0))
return ret;
- ret = sh_pfc_map_functions(pfc, sh_pfc_pmx);
+ ret = sh_pfc_map_functions(pfc, pmx);
if (unlikely(ret != 0))
- goto free_pads;
-
- sh_pfc_pmx->pctl = pinctrl_register(&sh_pfc_pinctrl_desc, &pdev->dev,
- sh_pfc_pmx);
- if (IS_ERR(sh_pfc_pmx->pctl)) {
- ret = PTR_ERR(sh_pfc_pmx->pctl);
- goto free_functions;
- }
+ return ret;
- sh_pfc_gpio_range.npins = pfc->last_gpio - pfc->first_gpio + 1;
- sh_pfc_gpio_range.base = pfc->first_gpio;
- sh_pfc_gpio_range.pin_base = pfc->first_gpio;
+ pmx->pctl = pinctrl_register(&sh_pfc_pinctrl_desc, pfc->dev, pmx);
+ if (IS_ERR(pmx->pctl))
+ return PTR_ERR(pmx->pctl);
- pinctrl_add_gpio_range(sh_pfc_pmx->pctl, &sh_pfc_gpio_range);
+ sh_pfc_gpio_range.npins = pfc->info->last_gpio
+ - pfc->info->first_gpio + 1;
+ sh_pfc_gpio_range.base = pfc->info->first_gpio;
+ sh_pfc_gpio_range.pin_base = pfc->info->first_gpio;
- platform_set_drvdata(pdev, sh_pfc_pmx);
+ pinctrl_add_gpio_range(pmx->pctl, &sh_pfc_gpio_range);
return 0;
-
-free_functions:
- kfree(sh_pfc_pmx->functions);
-free_pads:
- kfree(sh_pfc_pmx->pads);
- kfree(sh_pfc_pmx);
-
- return ret;
}
-static int sh_pfc_pinctrl_remove(struct platform_device *pdev)
+int sh_pfc_unregister_pinctrl(struct sh_pfc *pfc)
{
- struct sh_pfc_pinctrl *pmx = platform_get_drvdata(pdev);
+ struct sh_pfc_pinctrl *pmx = pfc->pinctrl;
pinctrl_unregister(pmx->pctl);
- platform_set_drvdata(pdev, NULL);
-
- kfree(sh_pfc_pmx->functions);
- kfree(sh_pfc_pmx->pads);
- kfree(sh_pfc_pmx);
-
+ pfc->pinctrl = NULL;
return 0;
}
-
-static struct platform_driver sh_pfc_pinctrl_driver = {
- .probe = sh_pfc_pinctrl_probe,
- .remove = sh_pfc_pinctrl_remove,
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_device sh_pfc_pinctrl_device = {
- .name = DRV_NAME,
- .id = -1,
-};
-
-static int sh_pfc_pinctrl_init(void)
-{
- int rc;
-
- rc = platform_driver_register(&sh_pfc_pinctrl_driver);
- if (likely(!rc)) {
- rc = platform_device_register(&sh_pfc_pinctrl_device);
- if (unlikely(rc))
- platform_driver_unregister(&sh_pfc_pinctrl_driver);
- }
-
- return rc;
-}
-
-int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
-{
- sh_pfc_pmx = kzalloc(sizeof(struct sh_pfc_pinctrl), GFP_KERNEL);
- if (unlikely(!sh_pfc_pmx))
- return -ENOMEM;
-
- spin_lock_init(&sh_pfc_pmx->lock);
-
- sh_pfc_pmx->pfc = pfc;
-
- return sh_pfc_pinctrl_init();
-}
-EXPORT_SYMBOL_GPL(sh_pfc_register_pinctrl);
-
-static void __exit sh_pfc_pinctrl_exit(void)
-{
- platform_driver_unregister(&sh_pfc_pinctrl_driver);
-}
-module_exit(sh_pfc_pinctrl_exit);
diff --git a/include/linux/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h
index c19a0925829a..13049c4c8d30 100644
--- a/include/linux/sh_pfc.h
+++ b/drivers/pinctrl/sh-pfc/sh_pfc.h
@@ -88,13 +88,7 @@ struct pinmux_range {
pinmux_enum_t force;
};
-struct pfc_window {
- phys_addr_t phys;
- void __iomem *virt;
- unsigned long size;
-};
-
-struct sh_pfc {
+struct sh_pfc_soc_info {
char *name;
pinmux_enum_t reserved_id;
struct pinmux_range data;
@@ -117,44 +111,9 @@ struct sh_pfc {
struct pinmux_irq *gpio_irq;
unsigned int gpio_irq_size;
- spinlock_t lock;
-
- struct resource *resource;
- unsigned int num_resources;
- struct pfc_window *window;
-
unsigned long unlock_reg;
};
-/* XXX compat for now */
-#define pinmux_info sh_pfc
-
-/* drivers/sh/pfc/gpio.c */
-int sh_pfc_register_gpiochip(struct sh_pfc *pfc);
-
-/* drivers/sh/pfc/pinctrl.c */
-int sh_pfc_register_pinctrl(struct sh_pfc *pfc);
-
-/* drivers/sh/pfc/core.c */
-int register_sh_pfc(struct sh_pfc *pfc);
-
-int sh_pfc_read_bit(struct pinmux_data_reg *dr, unsigned long in_pos);
-void sh_pfc_write_bit(struct pinmux_data_reg *dr, unsigned long in_pos,
- unsigned long value);
-int sh_pfc_get_data_reg(struct sh_pfc *pfc, unsigned gpio,
- struct pinmux_data_reg **drp, int *bitp);
-int sh_pfc_gpio_to_enum(struct sh_pfc *pfc, unsigned gpio, int pos,
- pinmux_enum_t *enum_idp);
-int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
- int cfg_mode);
-
-/* xxx */
-static inline int register_pinmux(struct pinmux_info *pip)
-{
- struct sh_pfc *pfc = pip;
- return register_sh_pfc(pfc);
-}
-
enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
/* helper macro for port */
diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c
index 3cf4ecd9302c..295b349a05cf 100644
--- a/drivers/pinctrl/spear/pinctrl-plgpio.c
+++ b/drivers/pinctrl/spear/pinctrl-plgpio.c
@@ -540,11 +540,9 @@ static int plgpio_probe(struct platform_device *pdev)
return -ENOMEM;
}
- plgpio->base = devm_request_and_ioremap(&pdev->dev, res);
- if (!plgpio->base) {
- dev_err(&pdev->dev, "request and ioremap fail\n");
- return -ENOMEM;
- }
+ plgpio->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(plgpio->base))
+ return PTR_ERR(plgpio->base);
ret = plgpio_probe_dt(pdev, plgpio);
if (ret) {
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 8390dca2b4e1..69616aeaa966 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -1,3 +1,7 @@
if X86
source "drivers/platform/x86/Kconfig"
endif
+if GOLDFISH
+source "drivers/platform/goldfish/Kconfig"
+endif
+
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index b17c16ce54ad..8a44a4cd6d1e 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_X86) += x86/
obj-$(CONFIG_OLPC) += olpc/
+obj-$(CONFIG_GOLDFISH) += goldfish/
diff --git a/drivers/platform/goldfish/Kconfig b/drivers/platform/goldfish/Kconfig
new file mode 100644
index 000000000000..635ef25cc722
--- /dev/null
+++ b/drivers/platform/goldfish/Kconfig
@@ -0,0 +1,5 @@
+config GOLDFISH_PIPE
+ tristate "Goldfish virtual device for QEMU pipes"
+ ---help---
+ This is a virtual device to drive the QEMU pipe interface used by
+ the Goldfish Android Virtual Device.
diff --git a/drivers/platform/goldfish/Makefile b/drivers/platform/goldfish/Makefile
new file mode 100644
index 000000000000..a0022395eee9
--- /dev/null
+++ b/drivers/platform/goldfish/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for Goldfish platform specific drivers
+#
+obj-$(CONFIG_GOLDFISH) += pdev_bus.o
+obj-$(CONFIG_GOLDFISH_PIPE) += goldfish_pipe.o
diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
new file mode 100644
index 000000000000..4f5aa831f549
--- /dev/null
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2012 Intel, Inc.
+ * Copyright (C) 2013 Intel, Inc.
+ *
+ * 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.
+ *
+ */
+
+/* This source file contains the implementation of a special device driver
+ * that intends to provide a *very* fast communication channel between the
+ * guest system and the QEMU emulator.
+ *
+ * Usage from the guest is simply the following (error handling simplified):
+ *
+ * int fd = open("/dev/qemu_pipe",O_RDWR);
+ * .... write() or read() through the pipe.
+ *
+ * This driver doesn't deal with the exact protocol used during the session.
+ * It is intended to be as simple as something like:
+ *
+ * // do this _just_ after opening the fd to connect to a specific
+ * // emulator service.
+ * const char* msg = "<pipename>";
+ * if (write(fd, msg, strlen(msg)+1) < 0) {
+ * ... could not connect to <pipename> service
+ * close(fd);
+ * }
+ *
+ * // after this, simply read() and write() to communicate with the
+ * // service. Exact protocol details left as an exercise to the reader.
+ *
+ * This driver is very fast because it doesn't copy any data through
+ * intermediate buffers, since the emulator is capable of translating
+ * guest user addresses into host ones.
+ *
+ * Note that we must however ensure that each user page involved in the
+ * exchange is properly mapped during a transfer.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+/*
+ * IMPORTANT: The following constants must match the ones used and defined
+ * in external/qemu/hw/goldfish_pipe.c in the Android source tree.
+ */
+
+/* pipe device registers */
+#define PIPE_REG_COMMAND 0x00 /* write: value = command */
+#define PIPE_REG_STATUS 0x04 /* read */
+#define PIPE_REG_CHANNEL 0x08 /* read/write: channel id */
+#define PIPE_REG_SIZE 0x0c /* read/write: buffer size */
+#define PIPE_REG_ADDRESS 0x10 /* write: physical address */
+#define PIPE_REG_WAKES 0x14 /* read: wake flags */
+#define PIPE_REG_PARAMS_ADDR_LOW 0x18 /* read/write: batch data address */
+#define PIPE_REG_PARAMS_ADDR_HIGH 0x1c /* read/write: batch data address */
+#define PIPE_REG_ACCESS_PARAMS 0x20 /* write: batch access */
+
+/* list of commands for PIPE_REG_COMMAND */
+#define CMD_OPEN 1 /* open new channel */
+#define CMD_CLOSE 2 /* close channel (from guest) */
+#define CMD_POLL 3 /* poll read/write status */
+
+/* List of bitflags returned in status of CMD_POLL command */
+#define PIPE_POLL_IN (1 << 0)
+#define PIPE_POLL_OUT (1 << 1)
+#define PIPE_POLL_HUP (1 << 2)
+
+/* The following commands are related to write operations */
+#define CMD_WRITE_BUFFER 4 /* send a user buffer to the emulator */
+#define CMD_WAKE_ON_WRITE 5 /* tell the emulator to wake us when writing
+ is possible */
+
+/* The following commands are related to read operations, they must be
+ * listed in the same order than the corresponding write ones, since we
+ * will use (CMD_READ_BUFFER - CMD_WRITE_BUFFER) as a special offset
+ * in goldfish_pipe_read_write() below.
+ */
+#define CMD_READ_BUFFER 6 /* receive a user buffer from the emulator */
+#define CMD_WAKE_ON_READ 7 /* tell the emulator to wake us when reading
+ * is possible */
+
+/* Possible status values used to signal errors - see goldfish_pipe_error_convert */
+#define PIPE_ERROR_INVAL -1
+#define PIPE_ERROR_AGAIN -2
+#define PIPE_ERROR_NOMEM -3
+#define PIPE_ERROR_IO -4
+
+/* Bit-flags used to signal events from the emulator */
+#define PIPE_WAKE_CLOSED (1 << 0) /* emulator closed pipe */
+#define PIPE_WAKE_READ (1 << 1) /* pipe can now be read from */
+#define PIPE_WAKE_WRITE (1 << 2) /* pipe can now be written to */
+
+struct access_params {
+ u32 channel;
+ u32 size;
+ u32 address;
+ u32 cmd;
+ u32 result;
+ /* reserved for future extension */
+ u32 flags;
+};
+
+/* The global driver data. Holds a reference to the i/o page used to
+ * communicate with the emulator, and a wake queue for blocked tasks
+ * waiting to be awoken.
+ */
+struct goldfish_pipe_dev {
+ spinlock_t lock;
+ unsigned char __iomem *base;
+ struct access_params *aps;
+ int irq;
+};
+
+static struct goldfish_pipe_dev pipe_dev[1];
+
+/* This data type models a given pipe instance */
+struct goldfish_pipe {
+ struct goldfish_pipe_dev *dev;
+ struct mutex lock;
+ unsigned long flags;
+ wait_queue_head_t wake_queue;
+};
+
+
+/* Bit flags for the 'flags' field */
+enum {
+ BIT_CLOSED_ON_HOST = 0, /* pipe closed by host */
+ BIT_WAKE_ON_WRITE = 1, /* want to be woken on writes */
+ BIT_WAKE_ON_READ = 2, /* want to be woken on reads */
+};
+
+
+static u32 goldfish_cmd_status(struct goldfish_pipe *pipe, u32 cmd)
+{
+ unsigned long flags;
+ u32 status;
+ struct goldfish_pipe_dev *dev = pipe->dev;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ writel((u32)pipe, dev->base + PIPE_REG_CHANNEL);
+ writel(cmd, dev->base + PIPE_REG_COMMAND);
+ status = readl(dev->base + PIPE_REG_STATUS);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return status;
+}
+
+static void goldfish_cmd(struct goldfish_pipe *pipe, u32 cmd)
+{
+ unsigned long flags;
+ struct goldfish_pipe_dev *dev = pipe->dev;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ writel((u32)pipe, dev->base + PIPE_REG_CHANNEL);
+ writel(cmd, dev->base + PIPE_REG_COMMAND);
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/* This function converts an error code returned by the emulator through
+ * the PIPE_REG_STATUS i/o register into a valid negative errno value.
+ */
+static int goldfish_pipe_error_convert(int status)
+{
+ switch (status) {
+ case PIPE_ERROR_AGAIN:
+ return -EAGAIN;
+ case PIPE_ERROR_NOMEM:
+ return -ENOMEM;
+ case PIPE_ERROR_IO:
+ return -EIO;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * Notice: QEMU will return 0 for un-known register access, indicating
+ * param_acess is supported or not
+ */
+static int valid_batchbuffer_addr(struct goldfish_pipe_dev *dev,
+ struct access_params *aps)
+{
+ u32 aph, apl;
+ u64 paddr;
+ aph = readl(dev->base + PIPE_REG_PARAMS_ADDR_HIGH);
+ apl = readl(dev->base + PIPE_REG_PARAMS_ADDR_LOW);
+
+ paddr = ((u64)aph << 32) | apl;
+ if (paddr != (__pa(aps)))
+ return 0;
+ return 1;
+}
+
+/* 0 on success */
+static int setup_access_params_addr(struct platform_device *pdev,
+ struct goldfish_pipe_dev *dev)
+{
+ u64 paddr;
+ struct access_params *aps;
+
+ aps = devm_kzalloc(&pdev->dev, sizeof(struct access_params), GFP_KERNEL);
+ if (!aps)
+ return -1;
+
+ /* FIXME */
+ paddr = __pa(aps);
+ writel((u32)(paddr >> 32), dev->base + PIPE_REG_PARAMS_ADDR_HIGH);
+ writel((u32)paddr, dev->base + PIPE_REG_PARAMS_ADDR_LOW);
+
+ if (valid_batchbuffer_addr(dev, aps)) {
+ dev->aps = aps;
+ return 0;
+ } else
+ return -1;
+}
+
+/* A value that will not be set by qemu emulator */
+#define INITIAL_BATCH_RESULT (0xdeadbeaf)
+static int access_with_param(struct goldfish_pipe_dev *dev, const int cmd,
+ unsigned long address, unsigned long avail,
+ struct goldfish_pipe *pipe, int *status)
+{
+ struct access_params *aps = dev->aps;
+
+ if (aps == NULL)
+ return -1;
+
+ aps->result = INITIAL_BATCH_RESULT;
+ aps->channel = (unsigned long)pipe;
+ aps->size = avail;
+ aps->address = address;
+ aps->cmd = cmd;
+ writel(cmd, dev->base + PIPE_REG_ACCESS_PARAMS);
+ /*
+ * If the aps->result has not changed, that means
+ * that the batch command failed
+ */
+ if (aps->result == INITIAL_BATCH_RESULT)
+ return -1;
+ *status = aps->result;
+ return 0;
+}
+
+/* This function is used for both reading from and writing to a given
+ * pipe.
+ */
+static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
+ size_t bufflen, int is_write)
+{
+ unsigned long irq_flags;
+ struct goldfish_pipe *pipe = filp->private_data;
+ struct goldfish_pipe_dev *dev = pipe->dev;
+ const int cmd_offset = is_write ? 0
+ : (CMD_READ_BUFFER - CMD_WRITE_BUFFER);
+ unsigned long address, address_end;
+ int ret = 0;
+
+ /* If the emulator already closed the pipe, no need to go further */
+ if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags))
+ return -EIO;
+
+ /* Null reads or writes succeeds */
+ if (unlikely(bufflen) == 0)
+ return 0;
+
+ /* Check the buffer range for access */
+ if (!access_ok(is_write ? VERIFY_WRITE : VERIFY_READ,
+ buffer, bufflen))
+ return -EFAULT;
+
+ /* Serialize access to the pipe */
+ if (mutex_lock_interruptible(&pipe->lock))
+ return -ERESTARTSYS;
+
+ address = (unsigned long)(void *)buffer;
+ address_end = address + bufflen;
+
+ while (address < address_end) {
+ unsigned long page_end = (address & PAGE_MASK) + PAGE_SIZE;
+ unsigned long next = page_end < address_end ? page_end
+ : address_end;
+ unsigned long avail = next - address;
+ int status, wakeBit;
+
+ /* Ensure that the corresponding page is properly mapped */
+ /* FIXME: this isn't safe or sufficient - use get_user_pages */
+ if (is_write) {
+ char c;
+ /* Ensure that the page is mapped and readable */
+ if (__get_user(c, (char __user *)address)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ } else {
+ /* Ensure that the page is mapped and writable */
+ if (__put_user(0, (char __user *)address)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ }
+
+ /* Now, try to transfer the bytes in the current page */
+ spin_lock_irqsave(&dev->lock, irq_flags);
+ if (access_with_param(dev, CMD_WRITE_BUFFER + cmd_offset,
+ address, avail, pipe, &status)) {
+ writel((u32)pipe, dev->base + PIPE_REG_CHANNEL);
+ writel(avail, dev->base + PIPE_REG_SIZE);
+ writel(address, dev->base + PIPE_REG_ADDRESS);
+ writel(CMD_WRITE_BUFFER + cmd_offset,
+ dev->base + PIPE_REG_COMMAND);
+ status = readl(dev->base + PIPE_REG_STATUS);
+ }
+ spin_unlock_irqrestore(&dev->lock, irq_flags);
+
+ if (status > 0) { /* Correct transfer */
+ ret += status;
+ address += status;
+ continue;
+ }
+
+ if (status == 0) /* EOF */
+ break;
+
+ /* An error occured. If we already transfered stuff, just
+ * return with its count. We expect the next call to return
+ * an error code */
+ if (ret > 0)
+ break;
+
+ /* If the error is not PIPE_ERROR_AGAIN, or if we are not in
+ * non-blocking mode, just return the error code.
+ */
+ if (status != PIPE_ERROR_AGAIN ||
+ (filp->f_flags & O_NONBLOCK) != 0) {
+ ret = goldfish_pipe_error_convert(status);
+ break;
+ }
+
+ /* We will have to wait until more data/space is available.
+ * First, mark the pipe as waiting for a specific wake signal.
+ */
+ wakeBit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ;
+ set_bit(wakeBit, &pipe->flags);
+
+ /* Tell the emulator we're going to wait for a wake event */
+ goldfish_cmd(pipe, CMD_WAKE_ON_WRITE + cmd_offset);
+
+ /* Unlock the pipe, then wait for the wake signal */
+ mutex_unlock(&pipe->lock);
+
+ while (test_bit(wakeBit, &pipe->flags)) {
+ if (wait_event_interruptible(
+ pipe->wake_queue,
+ !test_bit(wakeBit, &pipe->flags)))
+ return -ERESTARTSYS;
+
+ if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags))
+ return -EIO;
+ }
+
+ /* Try to re-acquire the lock */
+ if (mutex_lock_interruptible(&pipe->lock))
+ return -ERESTARTSYS;
+
+ /* Try the transfer again */
+ continue;
+ }
+ mutex_unlock(&pipe->lock);
+ return ret;
+}
+
+static ssize_t goldfish_pipe_read(struct file *filp, char __user *buffer,
+ size_t bufflen, loff_t *ppos)
+{
+ return goldfish_pipe_read_write(filp, buffer, bufflen, 0);
+}
+
+static ssize_t goldfish_pipe_write(struct file *filp,
+ const char __user *buffer, size_t bufflen,
+ loff_t *ppos)
+{
+ return goldfish_pipe_read_write(filp, (char __user *)buffer,
+ bufflen, 1);
+}
+
+
+static unsigned int goldfish_pipe_poll(struct file *filp, poll_table *wait)
+{
+ struct goldfish_pipe *pipe = filp->private_data;
+ unsigned int mask = 0;
+ int status;
+
+ mutex_lock(&pipe->lock);
+
+ poll_wait(filp, &pipe->wake_queue, wait);
+
+ status = goldfish_cmd_status(pipe, CMD_POLL);
+
+ mutex_unlock(&pipe->lock);
+
+ if (status & PIPE_POLL_IN)
+ mask |= POLLIN | POLLRDNORM;
+
+ if (status & PIPE_POLL_OUT)
+ mask |= POLLOUT | POLLWRNORM;
+
+ if (status & PIPE_POLL_HUP)
+ mask |= POLLHUP;
+
+ if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags))
+ mask |= POLLERR;
+
+ return mask;
+}
+
+static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
+{
+ struct goldfish_pipe_dev *dev = dev_id;
+ unsigned long irq_flags;
+ int count = 0;
+
+ /* We're going to read from the emulator a list of (channel,flags)
+ * pairs corresponding to the wake events that occured on each
+ * blocked pipe (i.e. channel).
+ */
+ spin_lock_irqsave(&dev->lock, irq_flags);
+ for (;;) {
+ /* First read the channel, 0 means the end of the list */
+ struct goldfish_pipe *pipe;
+ unsigned long wakes;
+ unsigned long channel = readl(dev->base + PIPE_REG_CHANNEL);
+
+ if (channel == 0)
+ break;
+
+ /* Convert channel to struct pipe pointer + read wake flags */
+ wakes = readl(dev->base + PIPE_REG_WAKES);
+ pipe = (struct goldfish_pipe *)(ptrdiff_t)channel;
+
+ /* Did the emulator just closed a pipe? */
+ if (wakes & PIPE_WAKE_CLOSED) {
+ set_bit(BIT_CLOSED_ON_HOST, &pipe->flags);
+ wakes |= PIPE_WAKE_READ | PIPE_WAKE_WRITE;
+ }
+ if (wakes & PIPE_WAKE_READ)
+ clear_bit(BIT_WAKE_ON_READ, &pipe->flags);
+ if (wakes & PIPE_WAKE_WRITE)
+ clear_bit(BIT_WAKE_ON_WRITE, &pipe->flags);
+
+ wake_up_interruptible(&pipe->wake_queue);
+ count++;
+ }
+ spin_unlock_irqrestore(&dev->lock, irq_flags);
+
+ return (count == 0) ? IRQ_NONE : IRQ_HANDLED;
+}
+
+/**
+ * goldfish_pipe_open - open a channel to the AVD
+ * @inode: inode of device
+ * @file: file struct of opener
+ *
+ * Create a new pipe link between the emulator and the use application.
+ * Each new request produces a new pipe.
+ *
+ * Note: we use the pipe ID as a mux. All goldfish emulations are 32bit
+ * right now so this is fine. A move to 64bit will need this addressing
+ */
+static int goldfish_pipe_open(struct inode *inode, struct file *file)
+{
+ struct goldfish_pipe *pipe;
+ struct goldfish_pipe_dev *dev = pipe_dev;
+ int32_t status;
+
+ /* Allocate new pipe kernel object */
+ pipe = kzalloc(sizeof(*pipe), GFP_KERNEL);
+ if (pipe == NULL)
+ return -ENOMEM;
+
+ pipe->dev = dev;
+ mutex_init(&pipe->lock);
+ init_waitqueue_head(&pipe->wake_queue);
+
+ /*
+ * Now, tell the emulator we're opening a new pipe. We use the
+ * pipe object's address as the channel identifier for simplicity.
+ */
+
+ status = goldfish_cmd_status(pipe, CMD_OPEN);
+ if (status < 0) {
+ kfree(pipe);
+ return status;
+ }
+
+ /* All is done, save the pipe into the file's private data field */
+ file->private_data = pipe;
+ return 0;
+}
+
+static int goldfish_pipe_release(struct inode *inode, struct file *filp)
+{
+ struct goldfish_pipe *pipe = filp->private_data;
+
+ /* The guest is closing the channel, so tell the emulator right now */
+ goldfish_cmd(pipe, CMD_CLOSE);
+ kfree(pipe);
+ filp->private_data = NULL;
+ return 0;
+}
+
+static const struct file_operations goldfish_pipe_fops = {
+ .owner = THIS_MODULE,
+ .read = goldfish_pipe_read,
+ .write = goldfish_pipe_write,
+ .poll = goldfish_pipe_poll,
+ .open = goldfish_pipe_open,
+ .release = goldfish_pipe_release,
+};
+
+static struct miscdevice goldfish_pipe_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "goldfish_pipe",
+ .fops = &goldfish_pipe_fops,
+};
+
+static int goldfish_pipe_probe(struct platform_device *pdev)
+{
+ int err;
+ struct resource *r;
+ struct goldfish_pipe_dev *dev = pipe_dev;
+
+ /* not thread safe, but this should not happen */
+ WARN_ON(dev->base != NULL);
+
+ spin_lock_init(&dev->lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL || resource_size(r) < PAGE_SIZE) {
+ dev_err(&pdev->dev, "can't allocate i/o page\n");
+ return -EINVAL;
+ }
+ dev->base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
+ if (dev->base == NULL) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ return -EINVAL;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (r == NULL) {
+ err = -EINVAL;
+ goto error;
+ }
+ dev->irq = r->start;
+
+ err = devm_request_irq(&pdev->dev, dev->irq, goldfish_pipe_interrupt,
+ IRQF_SHARED, "goldfish_pipe", dev);
+ if (err) {
+ dev_err(&pdev->dev, "unable to allocate IRQ\n");
+ goto error;
+ }
+
+ err = misc_register(&goldfish_pipe_device);
+ if (err) {
+ dev_err(&pdev->dev, "unable to register device\n");
+ goto error;
+ }
+ setup_access_params_addr(pdev, dev);
+ return 0;
+
+error:
+ dev->base = NULL;
+ return err;
+}
+
+static int goldfish_pipe_remove(struct platform_device *pdev)
+{
+ struct goldfish_pipe_dev *dev = pipe_dev;
+ misc_deregister(&goldfish_pipe_device);
+ dev->base = NULL;
+ return 0;
+}
+
+static struct platform_driver goldfish_pipe = {
+ .probe = goldfish_pipe_probe,
+ .remove = goldfish_pipe_remove,
+ .driver = {
+ .name = "goldfish_pipe"
+ }
+};
+
+module_platform_driver(goldfish_pipe);
+MODULE_AUTHOR("David Turner <digit@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/goldfish/pdev_bus.c b/drivers/platform/goldfish/pdev_bus.c
new file mode 100644
index 000000000000..92cc4cfafde5
--- /dev/null
+++ b/drivers/platform/goldfish/pdev_bus.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2011 Intel, Inc.
+ * Copyright (C) 2013 Intel, Inc.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#define PDEV_BUS_OP_DONE (0x00)
+#define PDEV_BUS_OP_REMOVE_DEV (0x04)
+#define PDEV_BUS_OP_ADD_DEV (0x08)
+
+#define PDEV_BUS_OP_INIT (0x00)
+
+#define PDEV_BUS_OP (0x00)
+#define PDEV_BUS_GET_NAME (0x04)
+#define PDEV_BUS_NAME_LEN (0x08)
+#define PDEV_BUS_ID (0x0c)
+#define PDEV_BUS_IO_BASE (0x10)
+#define PDEV_BUS_IO_SIZE (0x14)
+#define PDEV_BUS_IRQ (0x18)
+#define PDEV_BUS_IRQ_COUNT (0x1c)
+
+struct pdev_bus_dev {
+ struct list_head list;
+ struct platform_device pdev;
+ struct resource resources[0];
+};
+
+static void goldfish_pdev_worker(struct work_struct *work);
+
+static void __iomem *pdev_bus_base;
+static unsigned long pdev_bus_addr;
+static unsigned long pdev_bus_len;
+static u32 pdev_bus_irq;
+static LIST_HEAD(pdev_bus_new_devices);
+static LIST_HEAD(pdev_bus_registered_devices);
+static LIST_HEAD(pdev_bus_removed_devices);
+static DECLARE_WORK(pdev_bus_worker, goldfish_pdev_worker);
+
+
+static void goldfish_pdev_worker(struct work_struct *work)
+{
+ int ret;
+ struct pdev_bus_dev *pos, *n;
+
+ list_for_each_entry_safe(pos, n, &pdev_bus_removed_devices, list) {
+ list_del(&pos->list);
+ platform_device_unregister(&pos->pdev);
+ kfree(pos);
+ }
+ list_for_each_entry_safe(pos, n, &pdev_bus_new_devices, list) {
+ list_del(&pos->list);
+ ret = platform_device_register(&pos->pdev);
+ if (ret)
+ pr_err("goldfish_pdev_worker failed to register device, %s\n",
+ pos->pdev.name);
+ list_add_tail(&pos->list, &pdev_bus_registered_devices);
+ }
+}
+
+static void goldfish_pdev_remove(void)
+{
+ struct pdev_bus_dev *pos, *n;
+ u32 base;
+
+ base = readl(pdev_bus_base + PDEV_BUS_IO_BASE);
+
+ list_for_each_entry_safe(pos, n, &pdev_bus_new_devices, list) {
+ if (pos->resources[0].start == base) {
+ list_del(&pos->list);
+ kfree(pos);
+ return;
+ }
+ }
+ list_for_each_entry_safe(pos, n, &pdev_bus_registered_devices, list) {
+ if (pos->resources[0].start == base) {
+ list_del(&pos->list);
+ list_add_tail(&pos->list, &pdev_bus_removed_devices);
+ schedule_work(&pdev_bus_worker);
+ return;
+ }
+ };
+ pr_err("goldfish_pdev_remove could not find device at %x\n", base);
+}
+
+static int goldfish_new_pdev(void)
+{
+ struct pdev_bus_dev *dev;
+ u32 name_len;
+ u32 irq = -1, irq_count;
+ int resource_count = 2;
+ u32 base;
+ char *name;
+
+ base = readl(pdev_bus_base + PDEV_BUS_IO_BASE);
+
+ irq_count = readl(pdev_bus_base + PDEV_BUS_IRQ_COUNT);
+ name_len = readl(pdev_bus_base + PDEV_BUS_NAME_LEN);
+ if (irq_count)
+ resource_count++;
+
+ dev = kzalloc(sizeof(*dev) +
+ sizeof(struct resource) * resource_count +
+ name_len + 1 + sizeof(*dev->pdev.dev.dma_mask), GFP_ATOMIC);
+ if (dev == NULL)
+ return -ENOMEM;
+
+ dev->pdev.num_resources = resource_count;
+ dev->pdev.resource = (struct resource *)(dev + 1);
+ dev->pdev.name = name = (char *)(dev->pdev.resource + resource_count);
+ dev->pdev.dev.coherent_dma_mask = ~0;
+ dev->pdev.dev.dma_mask = (void *)(dev->pdev.name + name_len + 1);
+ *dev->pdev.dev.dma_mask = ~0;
+
+ writel((unsigned long)name, pdev_bus_base + PDEV_BUS_GET_NAME);
+ name[name_len] = '\0';
+ dev->pdev.id = readl(pdev_bus_base + PDEV_BUS_ID);
+ dev->pdev.resource[0].start = base;
+ dev->pdev.resource[0].end = base +
+ readl(pdev_bus_base + PDEV_BUS_IO_SIZE) - 1;
+ dev->pdev.resource[0].flags = IORESOURCE_MEM;
+ if (irq_count) {
+ irq = readl(pdev_bus_base + PDEV_BUS_IRQ);
+ dev->pdev.resource[1].start = irq;
+ dev->pdev.resource[1].end = irq + irq_count - 1;
+ dev->pdev.resource[1].flags = IORESOURCE_IRQ;
+ }
+
+ pr_debug("goldfish_new_pdev %s at %x irq %d\n", name, base, irq);
+ list_add_tail(&dev->list, &pdev_bus_new_devices);
+ schedule_work(&pdev_bus_worker);
+
+ return 0;
+}
+
+static irqreturn_t goldfish_pdev_bus_interrupt(int irq, void *dev_id)
+{
+ irqreturn_t ret = IRQ_NONE;
+ while (1) {
+ u32 op = readl(pdev_bus_base + PDEV_BUS_OP);
+ switch (op) {
+ case PDEV_BUS_OP_DONE:
+ return IRQ_NONE;
+
+ case PDEV_BUS_OP_REMOVE_DEV:
+ goldfish_pdev_remove();
+ break;
+
+ case PDEV_BUS_OP_ADD_DEV:
+ goldfish_new_pdev();
+ break;
+ }
+ ret = IRQ_HANDLED;
+ }
+ return ret;
+}
+
+static int goldfish_pdev_bus_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *r;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL)
+ return -EINVAL;
+
+ pdev_bus_addr = r->start;
+ pdev_bus_len = resource_size(r);
+
+ if (request_mem_region(pdev_bus_addr, pdev_bus_len, "goldfish")) {
+ dev_err(&pdev->dev, "unable to reserve Goldfish MMIO.\n");
+ return -EBUSY;
+ }
+
+ pdev_bus_base = ioremap(pdev_bus_addr, pdev_bus_len);
+ if (pdev_bus_base == NULL) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev, "unable to map Goldfish MMIO.\n");
+ goto free_resources;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (r == NULL) {
+ ret = -ENOENT;
+ goto free_map;
+ }
+
+ pdev_bus_irq = r->start;
+
+ ret = request_irq(pdev_bus_irq, goldfish_pdev_bus_interrupt,
+ IRQF_SHARED, "goldfish_pdev_bus", pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to request Goldfish IRQ\n");
+ goto free_map;
+ }
+
+ writel(PDEV_BUS_OP_INIT, pdev_bus_base + PDEV_BUS_OP);
+ return 0;
+
+free_map:
+ iounmap(pdev_bus_base);
+free_resources:
+ release_mem_region(pdev_bus_addr, pdev_bus_len);
+ return ret;
+}
+
+static int goldfish_pdev_bus_remove(struct platform_device *pdev)
+{
+ iounmap(pdev_bus_base);
+ free_irq(pdev_bus_irq, pdev);
+ release_mem_region(pdev_bus_addr, pdev_bus_len);
+ return 0;
+}
+
+static struct platform_driver goldfish_pdev_bus_driver = {
+ .probe = goldfish_pdev_bus_probe,
+ .remove = goldfish_pdev_bus_remove,
+ .driver = {
+ .name = "goldfish_pdev_bus"
+ }
+};
+
+module_platform_driver(goldfish_pdev_bus_driver);
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index c86bae828c28..7ab0b2fba503 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -80,10 +80,9 @@ config ASUS_LAPTOP
If you have an ACPI-compatible ASUS laptop, say Y or M here.
config DELL_LAPTOP
- tristate "Dell Laptop Extras (EXPERIMENTAL)"
+ tristate "Dell Laptop Extras"
depends on X86
depends on DCDBAS
- depends on EXPERIMENTAL
depends on BACKLIGHT_CLASS_DEVICE
depends on RFKILL || RFKILL = n
depends on SERIO_I8042
@@ -171,9 +170,8 @@ config AMILO_RFKILL
laptops.
config TC1100_WMI
- tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)"
+ tristate "HP Compaq TC1100 Tablet WMI Extras"
depends on !X86_64
- depends on EXPERIMENTAL
depends on ACPI
depends on ACPI_WMI
---help---
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index fcde4e528819..d9f9a0dbc6f3 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -1910,7 +1910,7 @@ fail_platform:
return result;
}
-static int asus_acpi_remove(struct acpi_device *device, int type)
+static int asus_acpi_remove(struct acpi_device *device)
{
struct asus_laptop *asus = acpi_driver_data(device);
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index c87ff16873f9..36e5e6c13db4 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -432,7 +432,7 @@ failed_sensitivity:
return error;
}
-static int cmpc_accel_remove_v4(struct acpi_device *acpi, int type)
+static int cmpc_accel_remove_v4(struct acpi_device *acpi)
{
struct input_dev *inputdev;
struct cmpc_accel *accel;
@@ -668,7 +668,7 @@ failed_file:
return error;
}
-static int cmpc_accel_remove(struct acpi_device *acpi, int type)
+static int cmpc_accel_remove(struct acpi_device *acpi)
{
struct input_dev *inputdev;
struct cmpc_accel *accel;
@@ -753,7 +753,7 @@ static int cmpc_tablet_add(struct acpi_device *acpi)
cmpc_tablet_idev_init);
}
-static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
+static int cmpc_tablet_remove(struct acpi_device *acpi)
{
return cmpc_remove_acpi_notify_device(acpi);
}
@@ -1000,7 +1000,7 @@ out_bd:
return retval;
}
-static int cmpc_ipml_remove(struct acpi_device *acpi, int type)
+static int cmpc_ipml_remove(struct acpi_device *acpi)
{
struct ipml200_dev *ipml;
@@ -1079,7 +1079,7 @@ static int cmpc_keys_add(struct acpi_device *acpi)
cmpc_keys_idev_init);
}
-static int cmpc_keys_remove(struct acpi_device *acpi, int type)
+static int cmpc_keys_remove(struct acpi_device *acpi)
{
return cmpc_remove_acpi_notify_device(acpi);
}
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 528e9495458d..5d26e70bed6c 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1007,7 +1007,7 @@ static int eeepc_get_fan_pwm(void)
static void eeepc_set_fan_pwm(int value)
{
- value = SENSORS_LIMIT(value, 0, 255);
+ value = clamp_val(value, 0, 255);
value = value * 100 / 255;
ec_write(EEEPC_EC_FAN_PWM, value);
}
@@ -1501,7 +1501,7 @@ fail_platform:
return result;
}
-static int eeepc_acpi_remove(struct acpi_device *device, int type)
+static int eeepc_acpi_remove(struct acpi_device *device)
{
struct eeepc_laptop *eeepc = acpi_driver_data(device);
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index c4c1a5444b38..1c9386e7c58c 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -733,7 +733,7 @@ err_stop:
return result;
}
-static int acpi_fujitsu_remove(struct acpi_device *device, int type)
+static int acpi_fujitsu_remove(struct acpi_device *device)
{
struct fujitsu_t *fujitsu = acpi_driver_data(device);
struct input_dev *input = fujitsu->input;
@@ -938,7 +938,7 @@ err_stop:
return result;
}
-static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
+static int acpi_fujitsu_hotkey_remove(struct acpi_device *device)
{
struct fujitsu_hotkey_t *fujitsu_hotkey = acpi_driver_data(device);
struct input_dev *input = fujitsu_hotkey->input;
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c
index 174ca01c4aa7..570926c10014 100644
--- a/drivers/platform/x86/fujitsu-tablet.c
+++ b/drivers/platform/x86/fujitsu-tablet.c
@@ -431,7 +431,7 @@ static int acpi_fujitsu_add(struct acpi_device *adev)
return 0;
}
-static int acpi_fujitsu_remove(struct acpi_device *adev, int type)
+static int acpi_fujitsu_remove(struct acpi_device *adev)
{
free_irq(fujitsu.irq, fujitsu_interrupt);
release_region(fujitsu.io_base, fujitsu.io_length);
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
index 18d74f29dcb2..e64a7a870d42 100644
--- a/drivers/platform/x86/hp_accel.c
+++ b/drivers/platform/x86/hp_accel.c
@@ -337,7 +337,7 @@ static int lis3lv02d_add(struct acpi_device *device)
return ret;
}
-static int lis3lv02d_remove(struct acpi_device *device, int type)
+static int lis3lv02d_remove(struct acpi_device *device)
{
if (!device)
return -EINVAL;
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 64bfb30a52e9..17f00b8dc5cb 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -834,7 +834,7 @@ platform_failed:
return ret;
}
-static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
+static int ideapad_acpi_remove(struct acpi_device *adevice)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
int i;
diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c
index 3271ac85115e..d6cfc1558c2f 100644
--- a/drivers/platform/x86/intel_menlow.c
+++ b/drivers/platform/x86/intel_menlow.c
@@ -200,7 +200,7 @@ static int intel_menlow_memory_add(struct acpi_device *device)
}
-static int intel_menlow_memory_remove(struct acpi_device *device, int type)
+static int intel_menlow_memory_remove(struct acpi_device *device)
{
struct thermal_cooling_device *cdev = acpi_driver_data(device);
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 8e8caa767d6a..4add9a31bf60 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -176,7 +176,7 @@ enum SINF_BITS { SINF_NUM_BATTERIES = 0,
/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
static int acpi_pcc_hotkey_add(struct acpi_device *device);
-static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type);
+static int acpi_pcc_hotkey_remove(struct acpi_device *device);
static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id pcc_device_ids[] = {
@@ -663,7 +663,7 @@ static int __init acpi_pcc_init(void)
return 0;
}
-static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
+static int acpi_pcc_hotkey_remove(struct acpi_device *device)
{
struct pcc_acpi *pcc = acpi_driver_data(device);
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index b8ad71f7863f..ceb41eff4230 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -2740,7 +2740,7 @@ outwalk:
return result;
}
-static int sony_nc_remove(struct acpi_device *device, int type)
+static int sony_nc_remove(struct acpi_device *device)
{
struct sony_nc_value *item;
@@ -4111,7 +4111,7 @@ found:
* ACPI driver
*
*****************/
-static int sony_pic_remove(struct acpi_device *device, int type)
+static int sony_pic_remove(struct acpi_device *device)
{
struct sony_pic_ioport *io, *tmp_io;
struct sony_pic_irq *irq, *tmp_irq;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index f946ca7cb762..ebcb461bb2b0 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -4877,8 +4877,7 @@ static int __init light_init(struct ibm_init_struct *iibm)
static void light_exit(void)
{
led_classdev_unregister(&tpacpi_led_thinklight.led_classdev);
- if (work_pending(&tpacpi_led_thinklight.work))
- flush_workqueue(tpacpi_wq);
+ flush_workqueue(tpacpi_wq);
}
static int light_read(struct seq_file *m)
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index d727bfee89a6..4ab618c63b45 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -157,7 +157,7 @@ add_err:
return -ENODEV;
}
-static int acpi_topstar_remove(struct acpi_device *device, int type)
+static int acpi_topstar_remove(struct acpi_device *device)
{
struct topstar_hkey *tps_hkey = acpi_driver_data(device);
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index c2727895794c..904476b2fa8f 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -1118,7 +1118,7 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
return 0;
}
-static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
+static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
{
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
@@ -1250,7 +1250,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
return 0;
error:
- toshiba_acpi_remove(acpi_dev, 0);
+ toshiba_acpi_remove(acpi_dev);
return ret;
}
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c
index e95be0b74859..74dd01ae343b 100644
--- a/drivers/platform/x86/toshiba_bluetooth.c
+++ b/drivers/platform/x86/toshiba_bluetooth.c
@@ -32,7 +32,7 @@ MODULE_LICENSE("GPL");
static int toshiba_bt_rfkill_add(struct acpi_device *device);
-static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type);
+static int toshiba_bt_rfkill_remove(struct acpi_device *device);
static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id bt_device_ids[] = {
@@ -122,7 +122,7 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device)
return result;
}
-static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type)
+static int toshiba_bt_rfkill_remove(struct acpi_device *device)
{
/* clean up */
return 0;
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 42a4dcc25f92..e4ac38aca580 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -92,7 +92,7 @@ module_param(debug_dump_wdg, bool, 0444);
MODULE_PARM_DESC(debug_dump_wdg,
"Dump available WMI interfaces [0/1]");
-static int acpi_wmi_remove(struct acpi_device *device, int type);
+static int acpi_wmi_remove(struct acpi_device *device);
static int acpi_wmi_add(struct acpi_device *device);
static void acpi_wmi_notify(struct acpi_device *device, u32 event);
@@ -917,7 +917,7 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event)
}
}
-static int acpi_wmi_remove(struct acpi_device *device, int type)
+static int acpi_wmi_remove(struct acpi_device *device)
{
acpi_remove_address_space_handler(device->handle,
ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c
index 16d340c3b852..4b1377bd5944 100644
--- a/drivers/platform/x86/xo15-ebook.c
+++ b/drivers/platform/x86/xo15-ebook.c
@@ -150,7 +150,7 @@ static int ebook_switch_add(struct acpi_device *device)
return error;
}
-static int ebook_switch_remove(struct acpi_device *device, int type)
+static int ebook_switch_remove(struct acpi_device *device)
{
struct ebook_switch *button = acpi_driver_data(device);
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 72e822e17d47..8813fc03aa09 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -90,7 +90,7 @@ static int pnpacpi_set_resources(struct pnp_dev *dev)
pnp_dbg(&dev->dev, "set resources\n");
handle = DEVICE_ACPI_HANDLE(&dev->dev);
- if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ if (!handle || acpi_bus_get_device(handle, &acpi_dev)) {
dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
return -ENODEV;
}
@@ -123,7 +123,7 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
dev_dbg(&dev->dev, "disable resources\n");
handle = DEVICE_ACPI_HANDLE(&dev->dev);
- if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ if (!handle || acpi_bus_get_device(handle, &acpi_dev)) {
dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
return 0;
}
@@ -145,7 +145,7 @@ static bool pnpacpi_can_wakeup(struct pnp_dev *dev)
acpi_handle handle;
handle = DEVICE_ACPI_HANDLE(&dev->dev);
- if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ if (!handle || acpi_bus_get_device(handle, &acpi_dev)) {
dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
return false;
}
@@ -160,7 +160,7 @@ static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
int error = 0;
handle = DEVICE_ACPI_HANDLE(&dev->dev);
- if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ if (!handle || acpi_bus_get_device(handle, &acpi_dev)) {
dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
return 0;
}
@@ -197,7 +197,7 @@ static int pnpacpi_resume(struct pnp_dev *dev)
acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
int error = 0;
- if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ if (!handle || acpi_bus_get_device(handle, &acpi_dev)) {
dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
return -ENODEV;
}
diff --git a/drivers/pnp/pnpbios/Kconfig b/drivers/pnp/pnpbios/Kconfig
index b986d9fa3b9a..50c3dd065e03 100644
--- a/drivers/pnp/pnpbios/Kconfig
+++ b/drivers/pnp/pnpbios/Kconfig
@@ -2,8 +2,8 @@
# Plug and Play BIOS configuration
#
config PNPBIOS
- bool "Plug and Play BIOS support (EXPERIMENTAL)"
- depends on ISA && X86 && EXPERIMENTAL
+ bool "Plug and Play BIOS support"
+ depends on ISA && X86
default n
---help---
Linux uses the PNPBIOS as defined in "Plug and Play BIOS
diff --git a/drivers/power/88pm860x_battery.c b/drivers/power/88pm860x_battery.c
index 8bc80b05c63c..d338c1c4e8c8 100644
--- a/drivers/power/88pm860x_battery.c
+++ b/drivers/power/88pm860x_battery.c
@@ -915,15 +915,13 @@ static int pm860x_battery_probe(struct platform_device *pdev)
info->irq_cc = platform_get_irq(pdev, 0);
if (info->irq_cc <= 0) {
dev_err(&pdev->dev, "No IRQ resource!\n");
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
info->irq_batt = platform_get_irq(pdev, 1);
if (info->irq_batt <= 0) {
dev_err(&pdev->dev, "No IRQ resource!\n");
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
info->chip = chip;
@@ -957,7 +955,7 @@ static int pm860x_battery_probe(struct platform_device *pdev)
ret = power_supply_register(&pdev->dev, &info->battery);
if (ret)
- goto out;
+ return ret;
info->battery.dev->parent = &pdev->dev;
ret = request_threaded_irq(info->irq_cc, NULL,
@@ -984,8 +982,6 @@ out_coulomb:
free_irq(info->irq_cc, info);
out_reg:
power_supply_unregister(&info->battery);
-out:
- kfree(info);
return ret;
}
@@ -993,10 +989,9 @@ static int pm860x_battery_remove(struct platform_device *pdev)
{
struct pm860x_battery_info *info = platform_get_drvdata(pdev);
- power_supply_unregister(&info->battery);
free_irq(info->irq_batt, info);
free_irq(info->irq_cc, info);
- kfree(info);
+ power_supply_unregister(&info->battery);
platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 9f45e2f77d53..9e00c389e777 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -346,6 +346,20 @@ config AB8500_BM
help
Say Y to include support for AB8500 battery management.
+config BATTERY_GOLDFISH
+ tristate "Goldfish battery driver"
+ depends on GENERIC_HARDIRQS
+ help
+ Say Y to enable support for the battery and AC power in the
+ Goldfish emulator.
+
+config CHARGER_PM2301
+ bool "PM2301 Battery Charger Driver"
+ depends on AB8500_BM
+ help
+ Say Y to include support for PM2301 charger driver.
+ Depends on AB8500 battery management core.
+
source "drivers/power/reset/Kconfig"
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 22c8913382c0..3f66436af45c 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o
obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o
+obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
@@ -38,7 +39,7 @@ 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_BATTERY_RX51) += rx51_battery.o
-obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
+obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
+obj-$(CONFIG_CHARGER_PM2301) += pm2301_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c
index f034ae43e045..7a96c0650fbb 100644
--- a/drivers/power/ab8500_bmdata.c
+++ b/drivers/power/ab8500_bmdata.c
@@ -182,206 +182,206 @@ static struct batres_vs_temp temp_to_batres_tbl_9100[] = {
};
static struct abx500_battery_type bat_type_thermistor[] = {
-[BATTERY_UNKNOWN] = {
- /* First element always represent the UNKNOWN battery */
- .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
- .resis_high = 0,
- .resis_low = 0,
- .battery_resistance = 300,
- .charge_full_design = 612,
- .nominal_voltage = 3700,
- .termination_vol = 4050,
- .termination_curr = 200,
- .recharge_vol = 3990,
- .normal_cur_lvl = 400,
- .normal_vol_lvl = 4100,
- .maint_a_cur_lvl = 400,
- .maint_a_vol_lvl = 4050,
- .maint_a_chg_timer_h = 60,
- .maint_b_cur_lvl = 400,
- .maint_b_vol_lvl = 4000,
- .maint_b_chg_timer_h = 200,
- .low_high_cur_lvl = 300,
- .low_high_vol_lvl = 4000,
- .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
- .r_to_t_tbl = temp_tbl,
- .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
- .v_to_cap_tbl = cap_tbl,
- .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
- .batres_tbl = temp_to_batres_tbl_thermistor,
-},
-{
- .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
- .resis_high = 53407,
- .resis_low = 12500,
- .battery_resistance = 300,
- .charge_full_design = 900,
- .nominal_voltage = 3600,
- .termination_vol = 4150,
- .termination_curr = 80,
- .recharge_vol = 4130,
- .normal_cur_lvl = 700,
- .normal_vol_lvl = 4200,
- .maint_a_cur_lvl = 600,
- .maint_a_vol_lvl = 4150,
- .maint_a_chg_timer_h = 60,
- .maint_b_cur_lvl = 600,
- .maint_b_vol_lvl = 4100,
- .maint_b_chg_timer_h = 200,
- .low_high_cur_lvl = 300,
- .low_high_vol_lvl = 4000,
- .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
- .r_to_t_tbl = temp_tbl_A_thermistor,
- .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
- .v_to_cap_tbl = cap_tbl_A_thermistor,
- .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
- .batres_tbl = temp_to_batres_tbl_thermistor,
+ [BATTERY_UNKNOWN] = {
+ /* First element always represent the UNKNOWN battery */
+ .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
+ .resis_high = 0,
+ .resis_low = 0,
+ .battery_resistance = 300,
+ .charge_full_design = 612,
+ .nominal_voltage = 3700,
+ .termination_vol = 4050,
+ .termination_curr = 200,
+ .recharge_cap = 95,
+ .normal_cur_lvl = 400,
+ .normal_vol_lvl = 4100,
+ .maint_a_cur_lvl = 400,
+ .maint_a_vol_lvl = 4050,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 400,
+ .maint_b_vol_lvl = 4000,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+ .r_to_t_tbl = temp_tbl,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+ .v_to_cap_tbl = cap_tbl,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+ },
+ {
+ .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+ .resis_high = 53407,
+ .resis_low = 12500,
+ .battery_resistance = 300,
+ .charge_full_design = 900,
+ .nominal_voltage = 3600,
+ .termination_vol = 4150,
+ .termination_curr = 80,
+ .recharge_cap = 95,
+ .normal_cur_lvl = 700,
+ .normal_vol_lvl = 4200,
+ .maint_a_cur_lvl = 600,
+ .maint_a_vol_lvl = 4150,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 600,
+ .maint_b_vol_lvl = 4100,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
+ .r_to_t_tbl = temp_tbl_A_thermistor,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
+ .v_to_cap_tbl = cap_tbl_A_thermistor,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
-},
-{
- .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
- .resis_high = 200000,
- .resis_low = 82869,
- .battery_resistance = 300,
- .charge_full_design = 900,
- .nominal_voltage = 3600,
- .termination_vol = 4150,
- .termination_curr = 80,
- .recharge_vol = 4130,
- .normal_cur_lvl = 700,
- .normal_vol_lvl = 4200,
- .maint_a_cur_lvl = 600,
- .maint_a_vol_lvl = 4150,
- .maint_a_chg_timer_h = 60,
- .maint_b_cur_lvl = 600,
- .maint_b_vol_lvl = 4100,
- .maint_b_chg_timer_h = 200,
- .low_high_cur_lvl = 300,
- .low_high_vol_lvl = 4000,
- .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
- .r_to_t_tbl = temp_tbl_B_thermistor,
- .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
- .v_to_cap_tbl = cap_tbl_B_thermistor,
- .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
- .batres_tbl = temp_to_batres_tbl_thermistor,
-},
+ },
+ {
+ .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+ .resis_high = 200000,
+ .resis_low = 82869,
+ .battery_resistance = 300,
+ .charge_full_design = 900,
+ .nominal_voltage = 3600,
+ .termination_vol = 4150,
+ .termination_curr = 80,
+ .recharge_cap = 95,
+ .normal_cur_lvl = 700,
+ .normal_vol_lvl = 4200,
+ .maint_a_cur_lvl = 600,
+ .maint_a_vol_lvl = 4150,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 600,
+ .maint_b_vol_lvl = 4100,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
+ .r_to_t_tbl = temp_tbl_B_thermistor,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
+ .v_to_cap_tbl = cap_tbl_B_thermistor,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+ },
};
static struct abx500_battery_type bat_type_ext_thermistor[] = {
-[BATTERY_UNKNOWN] = {
- /* First element always represent the UNKNOWN battery */
- .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
- .resis_high = 0,
- .resis_low = 0,
- .battery_resistance = 300,
- .charge_full_design = 612,
- .nominal_voltage = 3700,
- .termination_vol = 4050,
- .termination_curr = 200,
- .recharge_vol = 3990,
- .normal_cur_lvl = 400,
- .normal_vol_lvl = 4100,
- .maint_a_cur_lvl = 400,
- .maint_a_vol_lvl = 4050,
- .maint_a_chg_timer_h = 60,
- .maint_b_cur_lvl = 400,
- .maint_b_vol_lvl = 4000,
- .maint_b_chg_timer_h = 200,
- .low_high_cur_lvl = 300,
- .low_high_vol_lvl = 4000,
- .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
- .r_to_t_tbl = temp_tbl,
- .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
- .v_to_cap_tbl = cap_tbl,
- .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
- .batres_tbl = temp_to_batres_tbl_thermistor,
-},
+ [BATTERY_UNKNOWN] = {
+ /* First element always represent the UNKNOWN battery */
+ .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
+ .resis_high = 0,
+ .resis_low = 0,
+ .battery_resistance = 300,
+ .charge_full_design = 612,
+ .nominal_voltage = 3700,
+ .termination_vol = 4050,
+ .termination_curr = 200,
+ .recharge_cap = 95,
+ .normal_cur_lvl = 400,
+ .normal_vol_lvl = 4100,
+ .maint_a_cur_lvl = 400,
+ .maint_a_vol_lvl = 4050,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 400,
+ .maint_b_vol_lvl = 4000,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+ .r_to_t_tbl = temp_tbl,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+ .v_to_cap_tbl = cap_tbl,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+ },
/*
* These are the batteries that doesn't have an internal NTC resistor to measure
* its temperature. The temperature in this case is measure with a NTC placed
* near the battery but on the PCB.
*/
-{
- .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
- .resis_high = 76000,
- .resis_low = 53000,
- .battery_resistance = 300,
- .charge_full_design = 900,
- .nominal_voltage = 3700,
- .termination_vol = 4150,
- .termination_curr = 100,
- .recharge_vol = 4130,
- .normal_cur_lvl = 700,
- .normal_vol_lvl = 4200,
- .maint_a_cur_lvl = 600,
- .maint_a_vol_lvl = 4150,
- .maint_a_chg_timer_h = 60,
- .maint_b_cur_lvl = 600,
- .maint_b_vol_lvl = 4100,
- .maint_b_chg_timer_h = 200,
- .low_high_cur_lvl = 300,
- .low_high_vol_lvl = 4000,
- .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
- .r_to_t_tbl = temp_tbl,
- .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
- .v_to_cap_tbl = cap_tbl,
- .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
- .batres_tbl = temp_to_batres_tbl_thermistor,
-},
-{
- .name = POWER_SUPPLY_TECHNOLOGY_LION,
- .resis_high = 30000,
- .resis_low = 10000,
- .battery_resistance = 300,
- .charge_full_design = 950,
- .nominal_voltage = 3700,
- .termination_vol = 4150,
- .termination_curr = 100,
- .recharge_vol = 4130,
- .normal_cur_lvl = 700,
- .normal_vol_lvl = 4200,
- .maint_a_cur_lvl = 600,
- .maint_a_vol_lvl = 4150,
- .maint_a_chg_timer_h = 60,
- .maint_b_cur_lvl = 600,
- .maint_b_vol_lvl = 4100,
- .maint_b_chg_timer_h = 200,
- .low_high_cur_lvl = 300,
- .low_high_vol_lvl = 4000,
- .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
- .r_to_t_tbl = temp_tbl,
- .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
- .v_to_cap_tbl = cap_tbl,
- .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
- .batres_tbl = temp_to_batres_tbl_thermistor,
-},
-{
- .name = POWER_SUPPLY_TECHNOLOGY_LION,
- .resis_high = 95000,
- .resis_low = 76001,
- .battery_resistance = 300,
- .charge_full_design = 950,
- .nominal_voltage = 3700,
- .termination_vol = 4150,
- .termination_curr = 100,
- .recharge_vol = 4130,
- .normal_cur_lvl = 700,
- .normal_vol_lvl = 4200,
- .maint_a_cur_lvl = 600,
- .maint_a_vol_lvl = 4150,
- .maint_a_chg_timer_h = 60,
- .maint_b_cur_lvl = 600,
- .maint_b_vol_lvl = 4100,
- .maint_b_chg_timer_h = 200,
- .low_high_cur_lvl = 300,
- .low_high_vol_lvl = 4000,
- .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
- .r_to_t_tbl = temp_tbl,
- .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
- .v_to_cap_tbl = cap_tbl,
- .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
- .batres_tbl = temp_to_batres_tbl_thermistor,
-},
+ {
+ .name = POWER_SUPPLY_TECHNOLOGY_LIPO,
+ .resis_high = 76000,
+ .resis_low = 53000,
+ .battery_resistance = 300,
+ .charge_full_design = 900,
+ .nominal_voltage = 3700,
+ .termination_vol = 4150,
+ .termination_curr = 100,
+ .recharge_cap = 95,
+ .normal_cur_lvl = 700,
+ .normal_vol_lvl = 4200,
+ .maint_a_cur_lvl = 600,
+ .maint_a_vol_lvl = 4150,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 600,
+ .maint_b_vol_lvl = 4100,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+ .r_to_t_tbl = temp_tbl,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+ .v_to_cap_tbl = cap_tbl,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+ },
+ {
+ .name = POWER_SUPPLY_TECHNOLOGY_LION,
+ .resis_high = 30000,
+ .resis_low = 10000,
+ .battery_resistance = 300,
+ .charge_full_design = 950,
+ .nominal_voltage = 3700,
+ .termination_vol = 4150,
+ .termination_curr = 100,
+ .recharge_cap = 95,
+ .normal_cur_lvl = 700,
+ .normal_vol_lvl = 4200,
+ .maint_a_cur_lvl = 600,
+ .maint_a_vol_lvl = 4150,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 600,
+ .maint_b_vol_lvl = 4100,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+ .r_to_t_tbl = temp_tbl,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+ .v_to_cap_tbl = cap_tbl,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+ },
+ {
+ .name = POWER_SUPPLY_TECHNOLOGY_LION,
+ .resis_high = 95000,
+ .resis_low = 76001,
+ .battery_resistance = 300,
+ .charge_full_design = 950,
+ .nominal_voltage = 3700,
+ .termination_vol = 4150,
+ .termination_curr = 100,
+ .recharge_cap = 95,
+ .normal_cur_lvl = 700,
+ .normal_vol_lvl = 4200,
+ .maint_a_cur_lvl = 600,
+ .maint_a_vol_lvl = 4150,
+ .maint_a_chg_timer_h = 60,
+ .maint_b_cur_lvl = 600,
+ .maint_b_vol_lvl = 4100,
+ .maint_b_chg_timer_h = 200,
+ .low_high_cur_lvl = 300,
+ .low_high_vol_lvl = 4000,
+ .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl),
+ .r_to_t_tbl = temp_tbl,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
+ .v_to_cap_tbl = cap_tbl,
+ .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
+ .batres_tbl = temp_to_batres_tbl_thermistor,
+ },
};
static const struct abx500_bm_capacity_levels cap_levels = {
@@ -405,8 +405,8 @@ static const struct abx500_fg_parameters fg = {
.lowbat_threshold = 3100,
.battok_falling_th_sel0 = 2860,
.battok_raising_th_sel1 = 2860,
+ .maint_thres = 95,
.user_cap_limit = 15,
- .maint_thres = 97,
};
static const struct abx500_maxim_parameters maxi_params = {
@@ -424,96 +424,84 @@ static const struct abx500_bm_charger_parameters chg = {
};
struct abx500_bm_data ab8500_bm_data = {
- .temp_under = 3,
- .temp_low = 8,
- .temp_high = 43,
- .temp_over = 48,
- .main_safety_tmr_h = 4,
- .temp_interval_chg = 20,
- .temp_interval_nochg = 120,
- .usb_safety_tmr_h = 4,
- .bkup_bat_v = BUP_VCH_SEL_2P6V,
- .bkup_bat_i = BUP_ICH_SEL_150UA,
- .no_maintenance = false,
- .adc_therm = ABx500_ADC_THERM_BATCTRL,
- .chg_unknown_bat = false,
- .enable_overshoot = false,
- .fg_res = 100,
- .cap_levels = &cap_levels,
- .bat_type = bat_type_thermistor,
- .n_btypes = 3,
- .batt_id = 0,
- .interval_charging = 5,
- .interval_not_charging = 120,
- .temp_hysteresis = 3,
- .gnd_lift_resistance = 34,
- .maxi = &maxi_params,
- .chg_params = &chg,
- .fg_params = &fg,
+ .temp_under = 3,
+ .temp_low = 8,
+ .temp_high = 43,
+ .temp_over = 48,
+ .main_safety_tmr_h = 4,
+ .temp_interval_chg = 20,
+ .temp_interval_nochg = 120,
+ .usb_safety_tmr_h = 4,
+ .bkup_bat_v = BUP_VCH_SEL_2P6V,
+ .bkup_bat_i = BUP_ICH_SEL_150UA,
+ .no_maintenance = false,
+ .capacity_scaling = false,
+ .adc_therm = ABx500_ADC_THERM_BATCTRL,
+ .chg_unknown_bat = false,
+ .enable_overshoot = false,
+ .fg_res = 100,
+ .cap_levels = &cap_levels,
+ .bat_type = bat_type_thermistor,
+ .n_btypes = 3,
+ .batt_id = 0,
+ .interval_charging = 5,
+ .interval_not_charging = 120,
+ .temp_hysteresis = 3,
+ .gnd_lift_resistance = 34,
+ .maxi = &maxi_params,
+ .chg_params = &chg,
+ .fg_params = &fg,
};
-int bmdevs_of_probe(struct device *dev, struct device_node *np,
- struct abx500_bm_data **battery)
+int ab8500_bm_of_probe(struct device *dev,
+ struct device_node *np,
+ struct abx500_bm_data *bm)
{
- struct abx500_battery_type *btype;
- struct device_node *np_bat_supply;
- struct abx500_bm_data *bat;
+ struct batres_vs_temp *tmp_batres_tbl;
+ struct device_node *battery_node;
const char *btech;
- char bat_tech[8];
- int i, thermistor;
-
- *battery = &ab8500_bm_data;
+ int i;
/* get phandle to 'battery-info' node */
- np_bat_supply = of_parse_phandle(np, "battery", 0);
- if (!np_bat_supply) {
- dev_err(dev, "missing property battery\n");
+ battery_node = of_parse_phandle(np, "battery", 0);
+ if (!battery_node) {
+ dev_err(dev, "battery node or reference missing\n");
return -EINVAL;
}
- if (of_property_read_bool(np_bat_supply,
- "thermistor-on-batctrl"))
- thermistor = NTC_INTERNAL;
- else
- thermistor = NTC_EXTERNAL;
- bat = *battery;
- if (thermistor == NTC_EXTERNAL) {
- bat->n_btypes = 4;
- bat->bat_type = bat_type_ext_thermistor;
- bat->adc_therm = ABx500_ADC_THERM_BATTEMP;
- }
- btech = of_get_property(np_bat_supply,
- "stericsson,battery-type", NULL);
+ btech = of_get_property(battery_node, "stericsson,battery-type", NULL);
if (!btech) {
dev_warn(dev, "missing property battery-name/type\n");
- strcpy(bat_tech, "UNKNOWN");
- } else {
- strcpy(bat_tech, btech);
+ return -EINVAL;
}
- if (strncmp(bat_tech, "LION", 4) == 0) {
- bat->no_maintenance = true;
- bat->chg_unknown_bat = true;
- bat->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600;
- bat->bat_type[BATTERY_UNKNOWN].termination_vol = 4150;
- bat->bat_type[BATTERY_UNKNOWN].recharge_vol = 4130;
- bat->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520;
- bat->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200;
+ if (strncmp(btech, "LION", 4) == 0) {
+ bm->no_maintenance = true;
+ bm->chg_unknown_bat = true;
+ bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600;
+ bm->bat_type[BATTERY_UNKNOWN].termination_vol = 4150;
+ bm->bat_type[BATTERY_UNKNOWN].recharge_cap = 95;
+ bm->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520;
+ bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200;
}
- /* select the battery resolution table */
- for (i = 0; i < bat->n_btypes; ++i) {
- btype = (bat->bat_type + i);
- if (thermistor == NTC_EXTERNAL) {
- btype->batres_tbl =
- temp_to_batres_tbl_ext_thermistor;
- } else if (strncmp(bat_tech, "LION", 4) == 0) {
- btype->batres_tbl =
- temp_to_batres_tbl_9100;
- } else {
- btype->batres_tbl =
- temp_to_batres_tbl_thermistor;
- }
+
+ if (of_property_read_bool(battery_node, "thermistor-on-batctrl")) {
+ if (strncmp(btech, "LION", 4) == 0)
+ tmp_batres_tbl = temp_to_batres_tbl_9100;
+ else
+ tmp_batres_tbl = temp_to_batres_tbl_thermistor;
+ } else {
+ bm->n_btypes = 4;
+ bm->bat_type = bat_type_ext_thermistor;
+ bm->adc_therm = ABx500_ADC_THERM_BATTEMP;
+ tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor;
}
- of_node_put(np_bat_supply);
+
+ /* select the battery resolution table */
+ for (i = 0; i < bm->n_btypes; ++i)
+ bm->bat_type[i].batres_tbl = tmp_batres_tbl;
+
+ of_node_put(battery_node);
+
return 0;
}
diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 20e2a7d3ef43..07689064996e 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -39,6 +39,9 @@
#define BTEMP_BATCTRL_CURR_SRC_7UA 7
#define BTEMP_BATCTRL_CURR_SRC_20UA 20
+#define BTEMP_BATCTRL_CURR_SRC_16UA 16
+#define BTEMP_BATCTRL_CURR_SRC_18UA 18
+
#define to_ab8500_btemp_device_info(x) container_of((x), \
struct ab8500_btemp, btemp_psy);
@@ -78,12 +81,13 @@ struct ab8500_btemp_ranges {
* @parent: Pointer to the struct ab8500
* @gpadc: Pointer to the struct gpadc
* @fg: Pointer to the struct fg
- * @bat: Pointer to the abx500_bm platform data
+ * @bm: Platform specific battery management information
* @btemp_psy: Structure for BTEMP specific battery properties
* @events: Structure for information about events triggered
* @btemp_ranges: Battery temperature range structure
* @btemp_wq: Work queue for measuring the temperature periodically
* @btemp_periodic_work: Work for measuring the temperature periodically
+ * @initialized: True if battery id read.
*/
struct ab8500_btemp {
struct device *dev;
@@ -94,12 +98,13 @@ struct ab8500_btemp {
struct ab8500 *parent;
struct ab8500_gpadc *gpadc;
struct ab8500_fg *fg;
- struct abx500_bm_data *bat;
+ struct abx500_bm_data *bm;
struct power_supply btemp_psy;
struct ab8500_btemp_events events;
struct ab8500_btemp_ranges btemp_ranges;
struct workqueue_struct *btemp_wq;
struct delayed_work btemp_periodic_work;
+ bool initialized;
};
/* BTEMP power supply properties */
@@ -147,13 +152,13 @@ static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di,
return (450000 * (v_batctrl)) / (1800 - v_batctrl);
}
- if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL) {
+ if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL) {
/*
* If the battery has internal NTC, we use the current
* source to calculate the resistance, 7uA or 20uA
*/
rbs = (v_batctrl * 1000
- - di->bat->gnd_lift_resistance * inst_curr)
+ - di->bm->gnd_lift_resistance * inst_curr)
/ di->curr_source;
} else {
/*
@@ -209,11 +214,19 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
return 0;
/* Only do this for batteries with internal NTC */
- if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) {
- if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA)
- curr = BAT_CTRL_7U_ENA;
- else
- curr = BAT_CTRL_20U_ENA;
+ if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) {
+
+ if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+ if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_16UA)
+ curr = BAT_CTRL_16U_ENA;
+ else
+ curr = BAT_CTRL_18U_ENA;
+ } else {
+ if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA)
+ curr = BAT_CTRL_7U_ENA;
+ else
+ curr = BAT_CTRL_20U_ENA;
+ }
dev_dbg(di->dev, "Set BATCTRL %duA\n", di->curr_source);
@@ -241,14 +254,25 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
__func__);
goto disable_curr_source;
}
- } else if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) {
+ } else if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) {
dev_dbg(di->dev, "Disable BATCTRL curr source\n");
- /* Write 0 to the curr bits */
- ret = abx500_mask_and_set_register_interruptible(di->dev,
- AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
- BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
- ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+ if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+ /* Write 0 to the curr bits */
+ ret = abx500_mask_and_set_register_interruptible(
+ di->dev,
+ AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+ BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA,
+ ~(BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA));
+ } else {
+ /* Write 0 to the curr bits */
+ ret = abx500_mask_and_set_register_interruptible(
+ di->dev,
+ AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+ BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
+ ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+ }
+
if (ret) {
dev_err(di->dev, "%s failed disabling current source\n",
__func__);
@@ -290,11 +314,20 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
* if we got an error above
*/
disable_curr_source:
- /* Write 0 to the curr bits */
- ret = abx500_mask_and_set_register_interruptible(di->dev,
+ if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+ /* Write 0 to the curr bits */
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+ BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA,
+ ~(BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA));
+ } else {
+ /* Write 0 to the curr bits */
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+ }
+
if (ret) {
dev_err(di->dev, "%s failed disabling current source\n",
__func__);
@@ -372,13 +405,10 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di)
return ret;
}
- /*
- * Since there is no interrupt when current measurement is done,
- * loop for over 250ms (250ms is one sample conversion time
- * with 32.768 Khz RTC clock). Note that a stop time must be set
- * since the ab8500_btemp_read_batctrl_voltage call can block and
- * take an unknown amount of time to complete.
- */
+ do {
+ msleep(20);
+ } while (!ab8500_fg_inst_curr_started(di->fg));
+
i = 0;
do {
@@ -457,9 +487,9 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
int rbat, rntc, vntc;
u8 id;
- id = di->bat->batt_id;
+ id = di->bm->batt_id;
- if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL &&
+ if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL &&
id != BATTERY_UNKNOWN) {
rbat = ab8500_btemp_get_batctrl_res(di);
@@ -474,8 +504,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
}
temp = ab8500_btemp_res_to_temp(di,
- di->bat->bat_type[id].r_to_t_tbl,
- di->bat->bat_type[id].n_temp_tbl_elements, rbat);
+ di->bm->bat_type[id].r_to_t_tbl,
+ di->bm->bat_type[id].n_temp_tbl_elements, rbat);
} else {
vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL);
if (vntc < 0) {
@@ -491,8 +521,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
rntc = 230000 * vntc / (VTVOUT_V - vntc);
temp = ab8500_btemp_res_to_temp(di,
- di->bat->bat_type[id].r_to_t_tbl,
- di->bat->bat_type[id].n_temp_tbl_elements, rntc);
+ di->bm->bat_type[id].r_to_t_tbl,
+ di->bm->bat_type[id].n_temp_tbl_elements, rntc);
prev = temp;
}
dev_dbg(di->dev, "Battery temperature is %d\n", temp);
@@ -511,9 +541,12 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
{
int res;
u8 i;
+ if (is_ab9540(di->parent) || is_ab8505(di->parent))
+ di->curr_source = BTEMP_BATCTRL_CURR_SRC_16UA;
+ else
+ di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA;
- di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA;
- di->bat->batt_id = BATTERY_UNKNOWN;
+ di->bm->batt_id = BATTERY_UNKNOWN;
res = ab8500_btemp_get_batctrl_res(di);
if (res < 0) {
@@ -522,23 +555,23 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
}
/* BATTERY_UNKNOWN is defined on position 0, skip it! */
- for (i = BATTERY_UNKNOWN + 1; i < di->bat->n_btypes; i++) {
- if ((res <= di->bat->bat_type[i].resis_high) &&
- (res >= di->bat->bat_type[i].resis_low)) {
+ for (i = BATTERY_UNKNOWN + 1; i < di->bm->n_btypes; i++) {
+ if ((res <= di->bm->bat_type[i].resis_high) &&
+ (res >= di->bm->bat_type[i].resis_low)) {
dev_dbg(di->dev, "Battery detected on %s"
" low %d < res %d < high: %d"
" index: %d\n",
- di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL ?
+ di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL ?
"BATCTRL" : "BATTEMP",
- di->bat->bat_type[i].resis_low, res,
- di->bat->bat_type[i].resis_high, i);
+ di->bm->bat_type[i].resis_low, res,
+ di->bm->bat_type[i].resis_high, i);
- di->bat->batt_id = i;
+ di->bm->batt_id = i;
break;
}
}
- if (di->bat->batt_id == BATTERY_UNKNOWN) {
+ if (di->bm->batt_id == BATTERY_UNKNOWN) {
dev_warn(di->dev, "Battery identified as unknown"
", resistance %d Ohm\n", res);
return -ENXIO;
@@ -548,13 +581,18 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
* We only have to change current source if the
* detected type is Type 1, else we use the 7uA source
*/
- if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL &&
- di->bat->batt_id == 1) {
- dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n");
- di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA;
+ if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL &&
+ di->bm->batt_id == 1) {
+ if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+ dev_dbg(di->dev, "Set BATCTRL current source to 16uA\n");
+ di->curr_source = BTEMP_BATCTRL_CURR_SRC_16UA;
+ } else {
+ dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n");
+ di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA;
+ }
}
- return di->bat->batt_id;
+ return di->bm->batt_id;
}
/**
@@ -569,6 +607,13 @@ static void ab8500_btemp_periodic_work(struct work_struct *work)
struct ab8500_btemp *di = container_of(work,
struct ab8500_btemp, btemp_periodic_work.work);
+ if (!di->initialized) {
+ di->initialized = true;
+ /* Identify the battery */
+ if (ab8500_btemp_id(di) < 0)
+ dev_warn(di->dev, "failed to identify the battery\n");
+ }
+
di->bat_temp = ab8500_btemp_measure_temp(di);
if (di->bat_temp != di->prev_bat_temp) {
@@ -577,9 +622,9 @@ static void ab8500_btemp_periodic_work(struct work_struct *work)
}
if (di->events.ac_conn || di->events.usb_conn)
- interval = di->bat->temp_interval_chg;
+ interval = di->bm->temp_interval_chg;
else
- interval = di->bat->temp_interval_nochg;
+ interval = di->bm->temp_interval_nochg;
/* Schedule a new measurement */
queue_delayed_work(di->btemp_wq,
@@ -616,9 +661,9 @@ static irqreturn_t ab8500_btemp_templow_handler(int irq, void *_di)
{
struct ab8500_btemp *di = _di;
- if (is_ab8500_2p0_or_earlier(di->parent)) {
+ if (is_ab8500_3p3_or_earlier(di->parent)) {
dev_dbg(di->dev, "Ignore false btemp low irq"
- " for ABB cut 1.0, 1.1 and 2.0\n");
+ " for ABB cut 1.0, 1.1, 2.0 and 3.3\n");
} else {
dev_crit(di->dev, "Battery temperature lower than -10deg c\n");
@@ -732,30 +777,30 @@ static int ab8500_btemp_get_temp(struct ab8500_btemp *di)
int temp = 0;
/*
- * The BTEMP events are not reliabe on AB8500 cut2.0
+ * The BTEMP events are not reliabe on AB8500 cut3.3
* and prior versions
*/
- if (is_ab8500_2p0_or_earlier(di->parent)) {
+ if (is_ab8500_3p3_or_earlier(di->parent)) {
temp = di->bat_temp * 10;
} else {
if (di->events.btemp_low) {
if (temp > di->btemp_ranges.btemp_low_limit)
- temp = di->btemp_ranges.btemp_low_limit;
+ temp = di->btemp_ranges.btemp_low_limit * 10;
else
temp = di->bat_temp * 10;
} else if (di->events.btemp_high) {
if (temp < di->btemp_ranges.btemp_high_limit)
- temp = di->btemp_ranges.btemp_high_limit;
+ temp = di->btemp_ranges.btemp_high_limit * 10;
else
temp = di->bat_temp * 10;
} else if (di->events.btemp_lowmed) {
if (temp > di->btemp_ranges.btemp_med_limit)
- temp = di->btemp_ranges.btemp_med_limit;
+ temp = di->btemp_ranges.btemp_med_limit * 10;
else
temp = di->bat_temp * 10;
} else if (di->events.btemp_medhigh) {
if (temp < di->btemp_ranges.btemp_med_limit)
- temp = di->btemp_ranges.btemp_med_limit;
+ temp = di->btemp_ranges.btemp_med_limit * 10;
else
temp = di->bat_temp * 10;
} else
@@ -806,7 +851,7 @@ static int ab8500_btemp_get_property(struct power_supply *psy,
val->intval = 1;
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
- val->intval = di->bat->bat_type[di->bat->batt_id].name;
+ val->intval = di->bm->bat_type[di->bm->batt_id].name;
break;
case POWER_SUPPLY_PROP_TEMP:
val->intval = ab8500_btemp_get_temp(di);
@@ -967,6 +1012,7 @@ static char *supply_interface[] = {
static int ab8500_btemp_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ struct abx500_bm_data *plat = pdev->dev.platform_data;
struct ab8500_btemp *di;
int irq, i, ret = 0;
u8 val;
@@ -976,21 +1022,19 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s no mem for ab8500_btemp\n", __func__);
return -ENOMEM;
}
- di->bat = pdev->mfd_cell->platform_data;
- if (!di->bat) {
- if (np) {
- ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
- if (ret) {
- dev_err(&pdev->dev,
- "failed to get battery information\n");
- return ret;
- }
- } else {
- dev_err(&pdev->dev, "missing dt node for ab8500_btemp\n");
- return -EINVAL;
+
+ if (!plat) {
+ dev_err(&pdev->dev, "no battery management data supplied\n");
+ return -EINVAL;
+ }
+ di->bm = plat;
+
+ if (np) {
+ ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get battery information\n");
+ return ret;
}
- } else {
- dev_info(&pdev->dev, "falling back to legacy platform data\n");
}
/* get parent data */
@@ -998,6 +1042,8 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
di->parent = dev_get_drvdata(pdev->dev.parent);
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ di->initialized = false;
+
/* BTEMP supply */
di->btemp_psy.name = "ab8500_btemp";
di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY;
@@ -1022,10 +1068,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
INIT_DEFERRABLE_WORK(&di->btemp_periodic_work,
ab8500_btemp_periodic_work);
- /* Identify the battery */
- if (ab8500_btemp_id(di) < 0)
- dev_warn(di->dev, "failed to identify the battery\n");
-
/* Set BTEMP thermal limits. Low and Med are fixed */
di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT;
di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT;
@@ -1123,7 +1165,7 @@ static void __exit ab8500_btemp_exit(void)
platform_driver_unregister(&ab8500_btemp_driver);
}
-subsys_initcall_sync(ab8500_btemp_init);
+device_initcall(ab8500_btemp_init);
module_exit(ab8500_btemp_exit);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 3be9c0ee3fc5..24b30b7ea5ca 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -31,6 +31,7 @@
#include <linux/mfd/abx500/ab8500-gpadc.h>
#include <linux/mfd/abx500/ux500_chargalg.h>
#include <linux/usb/otg.h>
+#include <linux/mutex.h>
/* Charger constants */
#define NO_PW_CONN 0
@@ -54,6 +55,7 @@
#define MAIN_CH_INPUT_CURR_SHIFT 4
#define VBUS_IN_CURR_LIM_SHIFT 4
+#define AUTO_VBUS_IN_CURR_LIM_SHIFT 4
#define LED_INDICATOR_PWM_ENA 0x01
#define LED_INDICATOR_PWM_DIS 0x00
@@ -68,6 +70,11 @@
#define MAIN_CH_NOK 0x01
#define VBUS_DET 0x80
+#define MAIN_CH_STATUS2_MAINCHGDROP 0x80
+#define MAIN_CH_STATUS2_MAINCHARGERDETDBNC 0x40
+#define USB_CH_VBUSDROP 0x40
+#define USB_CH_VBUSDETDBNC 0x01
+
/* UsbLineStatus register bit masks */
#define AB8500_USB_LINK_STATUS 0x78
#define AB8500_STD_HOST_SUSP 0x18
@@ -79,6 +86,17 @@
/* Lowest charger voltage is 3.39V -> 0x4E */
#define LOW_VOLT_REG 0x4E
+/* Step up/down delay in us */
+#define STEP_UDELAY 1000
+
+#define CHARGER_STATUS_POLL 10 /* in ms */
+
+#define CHG_WD_INTERVAL (60 * HZ)
+
+#define AB8500_SW_CONTROL_FALLBACK 0x03
+/* Wait for enumeration before charing in us */
+#define WAIT_ACA_RID_ENUMERATION (5 * 1000)
+
/* UsbLineStatus register - usb types */
enum ab8500_charger_link_status {
USB_STAT_NOT_CONFIGURED,
@@ -97,6 +115,13 @@ enum ab8500_charger_link_status {
USB_STAT_HM_IDGND,
USB_STAT_RESERVED,
USB_STAT_NOT_VALID_LINK,
+ USB_STAT_PHY_EN,
+ USB_STAT_SUP_NO_IDGND_VBUS,
+ USB_STAT_SUP_IDGND_VBUS,
+ USB_STAT_CHARGER_LINE_1,
+ USB_STAT_CARKIT_1,
+ USB_STAT_CARKIT_2,
+ USB_STAT_ACA_DOCK_CHARGER,
};
enum ab8500_usb_state {
@@ -149,6 +174,7 @@ struct ab8500_charger_info {
int charger_voltage;
int cv_active;
bool wd_expired;
+ int charger_current;
};
struct ab8500_charger_event_flags {
@@ -159,12 +185,14 @@ struct ab8500_charger_event_flags {
bool usbchargernotok;
bool chgwdexp;
bool vbus_collapse;
+ bool vbus_drop_end;
};
struct ab8500_charger_usb_state {
- bool usb_changed;
int usb_current;
+ int usb_current_tmp;
enum ab8500_usb_state state;
+ enum ab8500_usb_state state_tmp;
spinlock_t usb_lock;
};
@@ -182,11 +210,17 @@ struct ab8500_charger_usb_state {
* charger is enabled
* @vbat Battery voltage
* @old_vbat Previously measured battery voltage
+ * @usb_device_is_unrecognised USB device is unrecognised by the hardware
* @autopower Indicate if we should have automatic pwron after pwrloss
* @autopower_cfg platform specific power config support for "pwron after pwrloss"
+ * @invalid_charger_detect_state State when forcing AB to use invalid charger
+ * @is_usb_host: Indicate if last detected USB type is host
+ * @is_aca_rid: Incicate if accessory is ACA type
+ * @current_stepping_sessions:
+ * Counter for current stepping sessions
* @parent: Pointer to the struct ab8500
* @gpadc: Pointer to the struct gpadc
- * @bat: Pointer to the abx500_bm platform data
+ * @bm: Platform specific battery management information
* @flags: Structure for information about events triggered
* @usb_state: Structure for usb stack information
* @ac_chg: AC charger power supply
@@ -195,19 +229,28 @@ struct ab8500_charger_usb_state {
* @usb: Structure that holds the USB charger properties
* @regu: Pointer to the struct regulator
* @charger_wq: Work queue for the IRQs and checking HW state
+ * @usb_ipt_crnt_lock: Lock to protect VBUS input current setting from mutuals
+ * @pm_lock: Lock to prevent system to suspend
* @check_vbat_work Work for checking vbat threshold to adjust vbus current
* @check_hw_failure_work: Work for checking HW state
* @check_usbchgnotok_work: Work for checking USB charger not ok status
* @kick_wd_work: Work for kicking the charger watchdog in case
* of ABB rev 1.* due to the watchog logic bug
+ * @ac_charger_attached_work: Work for checking if AC charger is still
+ * connected
+ * @usb_charger_attached_work: Work for checking if USB charger is still
+ * connected
* @ac_work: Work for checking AC charger connection
* @detect_usb_type_work: Work for detecting the USB type connected
* @usb_link_status_work: Work for checking the new USB link status
* @usb_state_changed_work: Work for checking USB state
+ * @attach_work: Work for detecting USB type
+ * @vbus_drop_end_work: Work for detecting VBUS drop end
* @check_main_thermal_prot_work:
* Work for checking Main thermal status
* @check_usb_thermal_prot_work:
* Work for checking USB thermal status
+ * @charger_attached_mutex: For controlling the wakelock
*/
struct ab8500_charger {
struct device *dev;
@@ -219,11 +262,16 @@ struct ab8500_charger {
bool vddadc_en_usb;
int vbat;
int old_vbat;
+ bool usb_device_is_unrecognised;
bool autopower;
bool autopower_cfg;
+ int invalid_charger_detect_state;
+ bool is_usb_host;
+ int is_aca_rid;
+ atomic_t current_stepping_sessions;
struct ab8500 *parent;
struct ab8500_gpadc *gpadc;
- struct abx500_bm_data *bat;
+ struct abx500_bm_data *bm;
struct ab8500_charger_event_flags flags;
struct ab8500_charger_usb_state usb_state;
struct ux500_charger ac_chg;
@@ -232,18 +280,24 @@ struct ab8500_charger {
struct ab8500_charger_info usb;
struct regulator *regu;
struct workqueue_struct *charger_wq;
+ struct mutex usb_ipt_crnt_lock;
struct delayed_work check_vbat_work;
struct delayed_work check_hw_failure_work;
struct delayed_work check_usbchgnotok_work;
struct delayed_work kick_wd_work;
+ struct delayed_work usb_state_changed_work;
+ struct delayed_work attach_work;
+ struct delayed_work ac_charger_attached_work;
+ struct delayed_work usb_charger_attached_work;
+ struct delayed_work vbus_drop_end_work;
struct work_struct ac_work;
struct work_struct detect_usb_type_work;
struct work_struct usb_link_status_work;
- struct work_struct usb_state_changed_work;
struct work_struct check_main_thermal_prot_work;
struct work_struct check_usb_thermal_prot_work;
struct usb_phy *usb_phy;
struct notifier_block nb;
+ struct mutex charger_attached_mutex;
};
/* AC properties */
@@ -267,50 +321,65 @@ static enum power_supply_property ab8500_charger_usb_props[] = {
POWER_SUPPLY_PROP_CURRENT_NOW,
};
-/**
- * ab8500_power_loss_handling - set how we handle powerloss.
- * @di: pointer to the ab8500_charger structure
- *
- * Magic nummbers are from STE HW department.
+/*
+ * Function for enabling and disabling sw fallback mode
+ * should always be disabled when no charger is connected.
*/
-static void ab8500_power_loss_handling(struct ab8500_charger *di)
+static void ab8500_enable_disable_sw_fallback(struct ab8500_charger *di,
+ bool fallback)
{
+ u8 val;
u8 reg;
+ u8 bank;
+ u8 bit;
int ret;
- dev_dbg(di->dev, "Autopower : %d\n", di->autopower);
+ dev_dbg(di->dev, "SW Fallback: %d\n", fallback);
- /* read the autopower register */
- ret = abx500_get_register_interruptible(di->dev, 0x15, 0x00, &reg);
- if (ret) {
- dev_err(di->dev, "%d write failed\n", __LINE__);
- return;
+ if (is_ab8500(di->parent)) {
+ bank = 0x15;
+ reg = 0x0;
+ bit = 3;
+ } else {
+ bank = AB8500_SYS_CTRL1_BLOCK;
+ reg = AB8500_SW_CONTROL_FALLBACK;
+ bit = 0;
}
- /* enable the OPT emulation registers */
- ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x2);
- if (ret) {
- dev_err(di->dev, "%d write failed\n", __LINE__);
+ /* read the register containing fallback bit */
+ ret = abx500_get_register_interruptible(di->dev, bank, reg, &val);
+ if (ret < 0) {
+ dev_err(di->dev, "%d read failed\n", __LINE__);
return;
}
- if (di->autopower)
- reg |= 0x8;
+ if (is_ab8500(di->parent)) {
+ /* enable the OPT emulation registers */
+ ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x2);
+ if (ret) {
+ dev_err(di->dev, "%d write failed\n", __LINE__);
+ goto disable_otp;
+ }
+ }
+
+ if (fallback)
+ val |= (1 << bit);
else
- reg &= ~0x8;
+ val &= ~(1 << bit);
- /* write back the changed value to autopower reg */
- ret = abx500_set_register_interruptible(di->dev, 0x15, 0x00, reg);
+ /* write back the changed fallback bit value to register */
+ ret = abx500_set_register_interruptible(di->dev, bank, reg, val);
if (ret) {
dev_err(di->dev, "%d write failed\n", __LINE__);
- return;
}
- /* disable the set OTP registers again */
- ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x0);
- if (ret) {
- dev_err(di->dev, "%d write failed\n", __LINE__);
- return;
+disable_otp:
+ if (is_ab8500(di->parent)) {
+ /* disable the set OTP registers again */
+ ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x0);
+ if (ret) {
+ dev_err(di->dev, "%d write failed\n", __LINE__);
+ }
}
}
@@ -329,12 +398,12 @@ static void ab8500_power_supply_changed(struct ab8500_charger *di,
!di->ac.charger_connected &&
di->autopower) {
di->autopower = false;
- ab8500_power_loss_handling(di);
+ ab8500_enable_disable_sw_fallback(di, false);
} else if (!di->autopower &&
(di->ac.charger_connected ||
di->usb.charger_connected)) {
di->autopower = true;
- ab8500_power_loss_handling(di);
+ ab8500_enable_disable_sw_fallback(di, true);
}
}
power_supply_changed(psy);
@@ -347,6 +416,19 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di,
dev_dbg(di->dev, "USB connected:%i\n", connected);
di->usb.charger_connected = connected;
sysfs_notify(&di->usb_chg.psy.dev->kobj, NULL, "present");
+
+ if (connected) {
+ mutex_lock(&di->charger_attached_mutex);
+ mutex_unlock(&di->charger_attached_mutex);
+
+ queue_delayed_work(di->charger_wq,
+ &di->usb_charger_attached_work,
+ HZ);
+ } else {
+ cancel_delayed_work_sync(&di->usb_charger_attached_work);
+ mutex_lock(&di->charger_attached_mutex);
+ mutex_unlock(&di->charger_attached_mutex);
+ }
}
}
@@ -500,6 +582,7 @@ static int ab8500_charger_usb_cv(struct ab8500_charger *di)
/**
* ab8500_charger_detect_chargers() - Detect the connected chargers
* @di: pointer to the ab8500_charger structure
+ * @probe: if probe, don't delay and wait for HW
*
* Returns the type of charger connected.
* For USB it will not mean we can actually charge from it
@@ -513,7 +596,7 @@ static int ab8500_charger_usb_cv(struct ab8500_charger *di)
* USB_PW_CONN if the USB power supply is connected
* AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
*/
-static int ab8500_charger_detect_chargers(struct ab8500_charger *di)
+static int ab8500_charger_detect_chargers(struct ab8500_charger *di, bool probe)
{
int result = NO_PW_CONN;
int ret;
@@ -531,13 +614,25 @@ static int ab8500_charger_detect_chargers(struct ab8500_charger *di)
result = AC_PW_CONN;
/* Check for USB charger */
+
+ if (!probe) {
+ /*
+ * AB8500 says VBUS_DET_DBNC1 & VBUS_DET_DBNC100
+ * when disconnecting ACA even though no
+ * charger was connected. Try waiting a little
+ * longer than the 100 ms of VBUS_DET_DBNC100...
+ */
+ msleep(110);
+ }
ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
AB8500_CH_USBCH_STAT1_REG, &val);
if (ret < 0) {
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
}
-
+ dev_dbg(di->dev,
+ "%s AB8500_CH_USBCH_STAT1_REG %x\n", __func__,
+ val);
if ((val & VBUS_DET_DBNC1) && (val & VBUS_DET_DBNC100))
result |= USB_PW_CONN;
@@ -554,31 +649,53 @@ static int ab8500_charger_detect_chargers(struct ab8500_charger *di)
* Returns error code in case of failure else 0 on success
*/
static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
- enum ab8500_charger_link_status link_status)
+ enum ab8500_charger_link_status link_status)
{
int ret = 0;
+ di->usb_device_is_unrecognised = false;
+
+ /*
+ * Platform only supports USB 2.0.
+ * This means that charging current from USB source
+ * is maximum 500 mA. Every occurence of USB_STAT_*_HOST_*
+ * should set USB_CH_IP_CUR_LVL_0P5.
+ */
+
switch (link_status) {
case USB_STAT_STD_HOST_NC:
case USB_STAT_STD_HOST_C_NS:
case USB_STAT_STD_HOST_C_S:
dev_dbg(di->dev, "USB Type - Standard host is "
"detected through USB driver\n");
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P09;
+ di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+ di->is_usb_host = true;
+ di->is_aca_rid = 0;
break;
case USB_STAT_HOST_CHG_HS_CHIRP:
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+ di->is_usb_host = true;
+ di->is_aca_rid = 0;
break;
case USB_STAT_HOST_CHG_HS:
+ di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+ di->is_usb_host = true;
+ di->is_aca_rid = 0;
+ break;
case USB_STAT_ACA_RID_C_HS:
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P9;
+ di->is_usb_host = false;
+ di->is_aca_rid = 0;
break;
case USB_STAT_ACA_RID_A:
/*
* Dedicated charger level minus maximum current accessory
- * can consume (300mA). Closest level is 1100mA
+ * can consume (900mA). Closest level is 500mA
*/
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P1;
+ dev_dbg(di->dev, "USB_STAT_ACA_RID_A detected\n");
+ di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+ di->is_usb_host = false;
+ di->is_aca_rid = 1;
break;
case USB_STAT_ACA_RID_B:
/*
@@ -586,34 +703,68 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
* 100mA for potential accessory). Closest level is 1300mA
*/
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P3;
+ dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
+ di->max_usb_in_curr);
+ di->is_usb_host = false;
+ di->is_aca_rid = 1;
break;
- case USB_STAT_DEDICATED_CHG:
case USB_STAT_HOST_CHG_NM:
+ di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+ di->is_usb_host = true;
+ di->is_aca_rid = 0;
+ break;
+ case USB_STAT_DEDICATED_CHG:
+ di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
+ di->is_usb_host = false;
+ di->is_aca_rid = 0;
+ break;
case USB_STAT_ACA_RID_C_HS_CHIRP:
case USB_STAT_ACA_RID_C_NM:
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
+ di->is_usb_host = false;
+ di->is_aca_rid = 1;
break;
- case USB_STAT_RESERVED:
- /*
- * This state is used to indicate that VBUS has dropped below
- * the detection level 4 times in a row. This is due to the
- * charger output current is set to high making the charger
- * voltage collapse. This have to be propagated through to
- * chargalg. This is done using the property
- * POWER_SUPPLY_PROP_CURRENT_AVG = 1
- */
- di->flags.vbus_collapse = true;
- dev_dbg(di->dev, "USB Type - USB_STAT_RESERVED "
- "VBUS has collapsed\n");
- ret = -1;
- break;
- case USB_STAT_HM_IDGND:
case USB_STAT_NOT_CONFIGURED:
- case USB_STAT_NOT_VALID_LINK:
+ if (di->vbus_detected) {
+ di->usb_device_is_unrecognised = true;
+ dev_dbg(di->dev, "USB Type - Legacy charger.\n");
+ di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
+ break;
+ }
+ case USB_STAT_HM_IDGND:
dev_err(di->dev, "USB Type - Charging not allowed\n");
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
ret = -ENXIO;
break;
+ case USB_STAT_RESERVED:
+ if (is_ab8500(di->parent)) {
+ di->flags.vbus_collapse = true;
+ dev_err(di->dev, "USB Type - USB_STAT_RESERVED "
+ "VBUS has collapsed\n");
+ ret = -ENXIO;
+ break;
+ }
+ if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+ dev_dbg(di->dev, "USB Type - Charging not allowed\n");
+ di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
+ dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d",
+ link_status, di->max_usb_in_curr);
+ ret = -ENXIO;
+ break;
+ }
+ break;
+ case USB_STAT_CARKIT_1:
+ case USB_STAT_CARKIT_2:
+ case USB_STAT_ACA_DOCK_CHARGER:
+ case USB_STAT_CHARGER_LINE_1:
+ di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+ dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
+ di->max_usb_in_curr);
+ case USB_STAT_NOT_VALID_LINK:
+ dev_err(di->dev, "USB Type invalid - try charging anyway\n");
+ di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+ break;
+
default:
dev_err(di->dev, "USB Type - Unknown\n");
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
@@ -645,8 +796,14 @@ static int ab8500_charger_read_usb_type(struct ab8500_charger *di)
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
}
- ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
- AB8500_USB_LINE_STAT_REG, &val);
+ if (is_ab8500(di->parent)) {
+ ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+ AB8500_USB_LINE_STAT_REG, &val);
+ } else {
+ if (is_ab9540(di->parent) || is_ab8505(di->parent))
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
+ }
if (ret < 0) {
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
@@ -682,16 +839,25 @@ static int ab8500_charger_detect_usb_type(struct ab8500_charger *di)
ret = abx500_get_register_interruptible(di->dev,
AB8500_INTERRUPT, AB8500_IT_SOURCE21_REG,
&val);
+ dev_dbg(di->dev, "%s AB8500_IT_SOURCE21_REG %x\n",
+ __func__, val);
if (ret < 0) {
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
}
- ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
- AB8500_USB_LINE_STAT_REG, &val);
+
+ if (is_ab8500(di->parent))
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_USB, AB8500_USB_LINE_STAT_REG, &val);
+ else
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
if (ret < 0) {
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
}
+ dev_dbg(di->dev, "%s AB8500_USB_LINE_STAT_REG %x\n", __func__,
+ val);
/*
* Until the IT source register is read the UsbLineStatus
* register is not updated, hence doing the same
@@ -936,6 +1102,144 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di)
}
/**
+ * ab8500_charger_set_current() - set charger current
+ * @di: pointer to the ab8500_charger structure
+ * @ich: charger current, in mA
+ * @reg: select what charger register to set
+ *
+ * Set charger current.
+ * There is no state machine in the AB to step up/down the charger
+ * current to avoid dips and spikes on MAIN, VBUS and VBAT when
+ * charging is started. Instead we need to implement
+ * this charger current step-up/down here.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_set_current(struct ab8500_charger *di,
+ int ich, int reg)
+{
+ int ret = 0;
+ int auto_curr_index, curr_index, prev_curr_index, shift_value, i;
+ u8 reg_value;
+ u32 step_udelay;
+ bool no_stepping = false;
+
+ atomic_inc(&di->current_stepping_sessions);
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+ reg, &reg_value);
+ if (ret < 0) {
+ dev_err(di->dev, "%s read failed\n", __func__);
+ goto exit_set_current;
+ }
+
+ switch (reg) {
+ case AB8500_MCH_IPT_CURLVL_REG:
+ shift_value = MAIN_CH_INPUT_CURR_SHIFT;
+ prev_curr_index = (reg_value >> shift_value);
+ curr_index = ab8500_current_to_regval(ich);
+ step_udelay = STEP_UDELAY;
+ if (!di->ac.charger_connected)
+ no_stepping = true;
+ break;
+ case AB8500_USBCH_IPT_CRNTLVL_REG:
+ shift_value = VBUS_IN_CURR_LIM_SHIFT;
+ prev_curr_index = (reg_value >> shift_value);
+ curr_index = ab8500_vbus_in_curr_to_regval(ich);
+ step_udelay = STEP_UDELAY * 100;
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_USBCH_STAT2_REG, &reg_value);
+ if (ret < 0) {
+ dev_err(di->dev, "%s read failed\n", __func__);
+ goto exit_set_current;
+ }
+ auto_curr_index =
+ reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT;
+
+ dev_dbg(di->dev, "%s Auto VBUS curr is %d mA\n",
+ __func__,
+ ab8500_charger_vbus_in_curr_map[auto_curr_index]);
+
+ prev_curr_index = min(prev_curr_index, auto_curr_index);
+
+ if (!di->usb.charger_connected)
+ no_stepping = true;
+ break;
+ case AB8500_CH_OPT_CRNTLVL_REG:
+ shift_value = 0;
+ prev_curr_index = (reg_value >> shift_value);
+ curr_index = ab8500_current_to_regval(ich);
+ step_udelay = STEP_UDELAY;
+ if (curr_index && (curr_index - prev_curr_index) > 1)
+ step_udelay *= 100;
+
+ if (!di->usb.charger_connected && !di->ac.charger_connected)
+ no_stepping = true;
+
+ break;
+ default:
+ dev_err(di->dev, "%s current register not valid\n", __func__);
+ ret = -ENXIO;
+ goto exit_set_current;
+ }
+
+ if (curr_index < 0) {
+ dev_err(di->dev, "requested current limit out-of-range\n");
+ ret = -ENXIO;
+ goto exit_set_current;
+ }
+
+ /* only update current if it's been changed */
+ if (prev_curr_index == curr_index) {
+ dev_dbg(di->dev, "%s current not changed for reg: 0x%02x\n",
+ __func__, reg);
+ ret = 0;
+ goto exit_set_current;
+ }
+
+ dev_dbg(di->dev, "%s set charger current: %d mA for reg: 0x%02x\n",
+ __func__, ich, reg);
+
+ if (no_stepping) {
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ reg, (u8)curr_index << shift_value);
+ if (ret)
+ dev_err(di->dev, "%s write failed\n", __func__);
+ } else if (prev_curr_index > curr_index) {
+ for (i = prev_curr_index - 1; i >= curr_index; i--) {
+ dev_dbg(di->dev, "curr change_1 to: %x for 0x%02x\n",
+ (u8) i << shift_value, reg);
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER, reg, (u8)i << shift_value);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ goto exit_set_current;
+ }
+ if (i != curr_index)
+ usleep_range(step_udelay, step_udelay * 2);
+ }
+ } else {
+ for (i = prev_curr_index + 1; i <= curr_index; i++) {
+ dev_dbg(di->dev, "curr change_2 to: %x for 0x%02x\n",
+ (u8)i << shift_value, reg);
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER, reg, (u8)i << shift_value);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ goto exit_set_current;
+ }
+ if (i != curr_index)
+ usleep_range(step_udelay, step_udelay * 2);
+ }
+ }
+
+exit_set_current:
+ atomic_dec(&di->current_stepping_sessions);
+
+ return ret;
+}
+
+/**
* ab8500_charger_set_vbus_in_curr() - set VBUS input current limit
* @di: pointer to the ab8500_charger structure
* @ich_in: charger input current limit
@@ -946,12 +1250,11 @@ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di)
static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di,
int ich_in)
{
- int ret;
- int input_curr_index;
int min_value;
+ int ret;
/* We should always use to lowest current limit */
- min_value = min(di->bat->chg_params->usb_curr_max, ich_in);
+ min_value = min(di->bm->chg_params->usb_curr_max, ich_in);
switch (min_value) {
case 100:
@@ -966,22 +1269,47 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di,
break;
}
- input_curr_index = ab8500_vbus_in_curr_to_regval(min_value);
- if (input_curr_index < 0) {
- dev_err(di->dev, "VBUS input current limit too high\n");
- return -ENXIO;
- }
+ dev_info(di->dev, "VBUS input current limit set to %d mA\n", min_value);
- ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
- AB8500_USBCH_IPT_CRNTLVL_REG,
- input_curr_index << VBUS_IN_CURR_LIM_SHIFT);
- if (ret)
- dev_err(di->dev, "%s write failed\n", __func__);
+ mutex_lock(&di->usb_ipt_crnt_lock);
+ ret = ab8500_charger_set_current(di, min_value,
+ AB8500_USBCH_IPT_CRNTLVL_REG);
+ mutex_unlock(&di->usb_ipt_crnt_lock);
return ret;
}
/**
+ * ab8500_charger_set_main_in_curr() - set main charger input current
+ * @di: pointer to the ab8500_charger structure
+ * @ich_in: input charger current, in mA
+ *
+ * Set main charger input current.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_set_main_in_curr(struct ab8500_charger *di,
+ int ich_in)
+{
+ return ab8500_charger_set_current(di, ich_in,
+ AB8500_MCH_IPT_CURLVL_REG);
+}
+
+/**
+ * ab8500_charger_set_output_curr() - set charger output current
+ * @di: pointer to the ab8500_charger structure
+ * @ich_out: output charger current, in mA
+ *
+ * Set charger output current.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_set_output_curr(struct ab8500_charger *di,
+ int ich_out)
+{
+ return ab8500_charger_set_current(di, ich_out,
+ AB8500_CH_OPT_CRNTLVL_REG);
+}
+
+/**
* ab8500_charger_led_en() - turn on/off chargign led
* @di: pointer to the ab8500_charger structure
* @on: flag to turn on/off the chargign led
@@ -1074,7 +1402,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
volt_index = ab8500_voltage_to_regval(vset);
curr_index = ab8500_current_to_regval(iset);
input_curr_index = ab8500_current_to_regval(
- di->bat->chg_params->ac_curr_max);
+ di->bm->chg_params->ac_curr_max);
if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) {
dev_err(di->dev,
"Charger voltage or current too high, "
@@ -1090,23 +1418,24 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
return ret;
}
/* MainChInputCurr: current that can be drawn from the charger*/
- ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
- AB8500_MCH_IPT_CURLVL_REG,
- input_curr_index << MAIN_CH_INPUT_CURR_SHIFT);
+ ret = ab8500_charger_set_main_in_curr(di,
+ di->bm->chg_params->ac_curr_max);
if (ret) {
- dev_err(di->dev, "%s write failed\n", __func__);
+ dev_err(di->dev, "%s Failed to set MainChInputCurr\n",
+ __func__);
return ret;
}
/* ChOutputCurentLevel: protected output current */
- ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
- AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index);
+ ret = ab8500_charger_set_output_curr(di, iset);
if (ret) {
- dev_err(di->dev, "%s write failed\n", __func__);
+ dev_err(di->dev, "%s "
+ "Failed to set ChOutputCurentLevel\n",
+ __func__);
return ret;
}
/* Check if VBAT overshoot control should be enabled */
- if (!di->bat->enable_overshoot)
+ if (!di->bm->enable_overshoot)
overshoot = MAIN_CH_NO_OVERSHOOT_ENA_N;
/* Enable Main Charger */
@@ -1158,12 +1487,11 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
return ret;
}
- ret = abx500_set_register_interruptible(di->dev,
- AB8500_CHARGER,
- AB8500_CH_OPT_CRNTLVL_REG, CH_OP_CUR_LVL_0P1);
+ ret = ab8500_charger_set_output_curr(di, 0);
if (ret) {
- dev_err(di->dev,
- "%s write failed\n", __func__);
+ dev_err(di->dev, "%s "
+ "Failed to set ChOutputCurentLevel\n",
+ __func__);
return ret;
}
} else {
@@ -1259,24 +1587,13 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
dev_err(di->dev, "%s write failed\n", __func__);
return ret;
}
- /* USBChInputCurr: current that can be drawn from the usb */
- ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
- if (ret) {
- dev_err(di->dev, "setting USBChInputCurr failed\n");
- return ret;
- }
- /* ChOutputCurentLevel: protected output current */
- ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
- AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index);
- if (ret) {
- dev_err(di->dev, "%s write failed\n", __func__);
- return ret;
- }
/* Check if VBAT overshoot control should be enabled */
- if (!di->bat->enable_overshoot)
+ if (!di->bm->enable_overshoot)
overshoot = USB_CHG_NO_OVERSHOOT_ENA_N;
/* Enable USB Charger */
+ dev_dbg(di->dev,
+ "Enabling USB with write to AB8500_USBCH_CTRL1_REG\n");
ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
AB8500_USBCH_CTRL1_REG, USB_CH_ENA | overshoot);
if (ret) {
@@ -1289,11 +1606,29 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
if (ret < 0)
dev_err(di->dev, "failed to enable LED\n");
+ di->usb.charger_online = 1;
+
+ /* USBChInputCurr: current that can be drawn from the usb */
+ ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+ if (ret) {
+ dev_err(di->dev, "setting USBChInputCurr failed\n");
+ return ret;
+ }
+
+ /* ChOutputCurentLevel: protected output current */
+ ret = ab8500_charger_set_output_curr(di, ich_out);
+ if (ret) {
+ dev_err(di->dev, "%s "
+ "Failed to set ChOutputCurentLevel\n",
+ __func__);
+ return ret;
+ }
+
queue_delayed_work(di->charger_wq, &di->check_vbat_work, HZ);
- di->usb.charger_online = 1;
} else {
/* Disable USB charging */
+ dev_dbg(di->dev, "%s Disabled USB charging\n", __func__);
ret = abx500_set_register_interruptible(di->dev,
AB8500_CHARGER,
AB8500_USBCH_CTRL1_REG, 0);
@@ -1306,7 +1641,21 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
ret = ab8500_charger_led_en(di, false);
if (ret < 0)
dev_err(di->dev, "failed to disable LED\n");
+ /* USBChInputCurr: current that can be drawn from the usb */
+ ret = ab8500_charger_set_vbus_in_curr(di, 0);
+ if (ret) {
+ dev_err(di->dev, "setting USBChInputCurr failed\n");
+ return ret;
+ }
+ /* ChOutputCurentLevel: protected output current */
+ ret = ab8500_charger_set_output_curr(di, 0);
+ if (ret) {
+ dev_err(di->dev, "%s "
+ "Failed to reset ChOutputCurentLevel\n",
+ __func__);
+ return ret;
+ }
di->usb.charger_online = 0;
di->usb.wd_expired = false;
@@ -1366,7 +1715,6 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger,
int ich_out)
{
int ret;
- int curr_index;
struct ab8500_charger *di;
if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
@@ -1376,18 +1724,11 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger,
else
return -ENXIO;
- curr_index = ab8500_current_to_regval(ich_out);
- if (curr_index < 0) {
- dev_err(di->dev,
- "Charger current too high, "
- "charging not started\n");
- return -ENXIO;
- }
-
- ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
- AB8500_CH_OPT_CRNTLVL_REG, (u8) curr_index);
+ ret = ab8500_charger_set_output_curr(di, ich_out);
if (ret) {
- dev_err(di->dev, "%s write failed\n", __func__);
+ dev_err(di->dev, "%s "
+ "Failed to set ChOutputCurentLevel\n",
+ __func__);
return ret;
}
@@ -1597,7 +1938,7 @@ static void ab8500_charger_ac_work(struct work_struct *work)
* synchronously, we have the check if the main charger is
* connected by reading the status register
*/
- ret = ab8500_charger_detect_chargers(di);
+ ret = ab8500_charger_detect_chargers(di, false);
if (ret < 0)
return;
@@ -1612,6 +1953,84 @@ static void ab8500_charger_ac_work(struct work_struct *work)
sysfs_notify(&di->ac_chg.psy.dev->kobj, NULL, "present");
}
+static void ab8500_charger_usb_attached_work(struct work_struct *work)
+{
+ struct ab8500_charger *di = container_of(work,
+ struct ab8500_charger,
+ usb_charger_attached_work.work);
+ int usbch = (USB_CH_VBUSDROP | USB_CH_VBUSDETDBNC);
+ int ret, i;
+ u8 statval;
+
+ for (i = 0; i < 10; i++) {
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_CHARGER,
+ AB8500_CH_USBCH_STAT1_REG,
+ &statval);
+ if (ret < 0) {
+ dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
+ goto reschedule;
+ }
+ if ((statval & usbch) != usbch)
+ goto reschedule;
+
+ msleep(CHARGER_STATUS_POLL);
+ }
+
+ ab8500_charger_usb_en(&di->usb_chg, 0, 0, 0);
+
+ mutex_lock(&di->charger_attached_mutex);
+ mutex_unlock(&di->charger_attached_mutex);
+
+ return;
+
+reschedule:
+ queue_delayed_work(di->charger_wq,
+ &di->usb_charger_attached_work,
+ HZ);
+}
+
+static void ab8500_charger_ac_attached_work(struct work_struct *work)
+{
+
+ struct ab8500_charger *di = container_of(work,
+ struct ab8500_charger,
+ ac_charger_attached_work.work);
+ int mainch = (MAIN_CH_STATUS2_MAINCHGDROP |
+ MAIN_CH_STATUS2_MAINCHARGERDETDBNC);
+ int ret, i;
+ u8 statval;
+
+ for (i = 0; i < 10; i++) {
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_CHARGER,
+ AB8500_CH_STATUS2_REG,
+ &statval);
+ if (ret < 0) {
+ dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
+ goto reschedule;
+ }
+
+ if ((statval & mainch) != mainch)
+ goto reschedule;
+
+ msleep(CHARGER_STATUS_POLL);
+ }
+
+ ab8500_charger_ac_en(&di->ac_chg, 0, 0, 0);
+ queue_work(di->charger_wq, &di->ac_work);
+
+ mutex_lock(&di->charger_attached_mutex);
+ mutex_unlock(&di->charger_attached_mutex);
+
+ return;
+
+reschedule:
+ queue_delayed_work(di->charger_wq,
+ &di->ac_charger_attached_work,
+ HZ);
+}
+
/**
* ab8500_charger_detect_usb_type_work() - work to detect USB type
* @work: Pointer to the work_struct structure
@@ -1630,16 +2049,18 @@ static void ab8500_charger_detect_usb_type_work(struct work_struct *work)
* synchronously, we have the check if is
* connected by reading the status register
*/
- ret = ab8500_charger_detect_chargers(di);
+ ret = ab8500_charger_detect_chargers(di, false);
if (ret < 0)
return;
if (!(ret & USB_PW_CONN)) {
- di->vbus_detected = 0;
+ dev_dbg(di->dev, "%s di->vbus_detected = false\n", __func__);
+ di->vbus_detected = false;
ab8500_charger_set_usb_connected(di, false);
ab8500_power_supply_changed(di, &di->usb_chg.psy);
} else {
- di->vbus_detected = 1;
+ dev_dbg(di->dev, "%s di->vbus_detected = true\n", __func__);
+ di->vbus_detected = true;
if (is_ab8500_1p1_or_earlier(di->parent)) {
ret = ab8500_charger_detect_usb_type(di);
@@ -1649,7 +2070,8 @@ static void ab8500_charger_detect_usb_type_work(struct work_struct *work)
&di->usb_chg.psy);
}
} else {
- /* For ABB cut2.0 and onwards we have an IRQ,
+ /*
+ * For ABB cut2.0 and onwards we have an IRQ,
* USB_LINK_STATUS that will be triggered when the USB
* link status changes. The exception is USB connected
* during startup. Then we don't get a
@@ -1670,6 +2092,29 @@ static void ab8500_charger_detect_usb_type_work(struct work_struct *work)
}
/**
+ * ab8500_charger_usb_link_attach_work() - work to detect USB type
+ * @work: pointer to the work_struct structure
+ *
+ * Detect the type of USB plugged
+ */
+static void ab8500_charger_usb_link_attach_work(struct work_struct *work)
+{
+ struct ab8500_charger *di =
+ container_of(work, struct ab8500_charger, attach_work.work);
+ int ret;
+
+ /* Update maximum input current if USB enumeration is not detected */
+ if (!di->usb.charger_online) {
+ ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+ if (ret)
+ return;
+ }
+
+ ab8500_charger_set_usb_connected(di, true);
+ ab8500_power_supply_changed(di, &di->usb_chg.psy);
+}
+
+/**
* ab8500_charger_usb_link_status_work() - work to detect USB type
* @work: pointer to the work_struct structure
*
@@ -1677,7 +2122,9 @@ static void ab8500_charger_detect_usb_type_work(struct work_struct *work)
*/
static void ab8500_charger_usb_link_status_work(struct work_struct *work)
{
+ int detected_chargers;
int ret;
+ u8 val;
struct ab8500_charger *di = container_of(work,
struct ab8500_charger, usb_link_status_work);
@@ -1687,31 +2134,95 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work)
* synchronously, we have the check if is
* connected by reading the status register
*/
- ret = ab8500_charger_detect_chargers(di);
- if (ret < 0)
+ detected_chargers = ab8500_charger_detect_chargers(di, false);
+ if (detected_chargers < 0)
return;
- if (!(ret & USB_PW_CONN)) {
- di->vbus_detected = 0;
+ /*
+ * Some chargers that breaks the USB spec is
+ * identified as invalid by AB8500 and it refuse
+ * to start the charging process. but by jumping
+ * thru a few hoops it can be forced to start.
+ */
+ ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+ AB8500_USB_LINE_STAT_REG, &val);
+ if (ret >= 0)
+ dev_dbg(di->dev, "UsbLineStatus register = 0x%02x\n", val);
+ else
+ dev_dbg(di->dev, "Error reading USB link status\n");
+
+ if (detected_chargers & USB_PW_CONN) {
+ if (((val & AB8500_USB_LINK_STATUS) >> 3) == USB_STAT_NOT_VALID_LINK &&
+ di->invalid_charger_detect_state == 0) {
+ dev_dbg(di->dev, "Invalid charger detected, state= 0\n");
+ /*Enable charger*/
+ abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_USBCH_CTRL1_REG, 0x01, 0x01);
+ /*Enable charger detection*/
+ abx500_mask_and_set_register_interruptible(di->dev, AB8500_USB,
+ AB8500_MCH_IPT_CURLVL_REG, 0x01, 0x01);
+ di->invalid_charger_detect_state = 1;
+ /*exit and wait for new link status interrupt.*/
+ return;
+
+ }
+ if (di->invalid_charger_detect_state == 1) {
+ dev_dbg(di->dev, "Invalid charger detected, state= 1\n");
+ /*Stop charger detection*/
+ abx500_mask_and_set_register_interruptible(di->dev, AB8500_USB,
+ AB8500_MCH_IPT_CURLVL_REG, 0x01, 0x00);
+ /*Check link status*/
+ ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+ AB8500_USB_LINE_STAT_REG, &val);
+ dev_dbg(di->dev, "USB link status= 0x%02x\n",
+ (val & AB8500_USB_LINK_STATUS) >> 3);
+ di->invalid_charger_detect_state = 2;
+ }
+ } else {
+ di->invalid_charger_detect_state = 0;
+ }
+
+ if (!(detected_chargers & USB_PW_CONN)) {
+ di->vbus_detected = false;
ab8500_charger_set_usb_connected(di, false);
ab8500_power_supply_changed(di, &di->usb_chg.psy);
- } else {
- di->vbus_detected = 1;
- ret = ab8500_charger_read_usb_type(di);
- if (!ret) {
- /* Update maximum input current */
- ret = ab8500_charger_set_vbus_in_curr(di,
- di->max_usb_in_curr);
- if (ret)
- return;
+ return;
+ }
- ab8500_charger_set_usb_connected(di, true);
- ab8500_power_supply_changed(di, &di->usb_chg.psy);
- } else if (ret == -ENXIO) {
+ dev_dbg(di->dev,"%s di->vbus_detected = true\n",__func__);
+ di->vbus_detected = true;
+ ret = ab8500_charger_read_usb_type(di);
+ if (ret) {
+ if (ret == -ENXIO) {
/* No valid charger type detected */
ab8500_charger_set_usb_connected(di, false);
ab8500_power_supply_changed(di, &di->usb_chg.psy);
}
+ return;
+ }
+
+ if (di->usb_device_is_unrecognised) {
+ dev_dbg(di->dev,
+ "Potential Legacy Charger device. "
+ "Delay work for %d msec for USB enum "
+ "to finish",
+ WAIT_ACA_RID_ENUMERATION);
+ queue_delayed_work(di->charger_wq,
+ &di->attach_work,
+ msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION));
+ } else if (di->is_aca_rid == 1) {
+ /* Only wait once */
+ di->is_aca_rid++;
+ dev_dbg(di->dev,
+ "%s Wait %d msec for USB enum to finish",
+ __func__, WAIT_ACA_RID_ENUMERATION);
+ queue_delayed_work(di->charger_wq,
+ &di->attach_work,
+ msecs_to_jiffies(WAIT_ACA_RID_ENUMERATION));
+ } else {
+ queue_delayed_work(di->charger_wq,
+ &di->attach_work,
+ 0);
}
}
@@ -1721,24 +2232,20 @@ static void ab8500_charger_usb_state_changed_work(struct work_struct *work)
unsigned long flags;
struct ab8500_charger *di = container_of(work,
- struct ab8500_charger, usb_state_changed_work);
+ struct ab8500_charger, usb_state_changed_work.work);
- if (!di->vbus_detected)
+ if (!di->vbus_detected) {
+ dev_dbg(di->dev,
+ "%s !di->vbus_detected\n",
+ __func__);
return;
+ }
spin_lock_irqsave(&di->usb_state.usb_lock, flags);
- di->usb_state.usb_changed = false;
+ di->usb_state.state = di->usb_state.state_tmp;
+ di->usb_state.usb_current = di->usb_state.usb_current_tmp;
spin_unlock_irqrestore(&di->usb_state.usb_lock, flags);
- /*
- * wait for some time until you get updates from the usb stack
- * and negotiations are completed
- */
- msleep(250);
-
- if (di->usb_state.usb_changed)
- return;
-
dev_dbg(di->dev, "%s USB state: 0x%02x mA: %d\n",
__func__, di->usb_state.state, di->usb_state.usb_current);
@@ -1892,6 +2399,10 @@ static irqreturn_t ab8500_charger_mainchunplugdet_handler(int irq, void *_di)
dev_dbg(di->dev, "Main charger unplugged\n");
queue_work(di->charger_wq, &di->ac_work);
+ cancel_delayed_work_sync(&di->ac_charger_attached_work);
+ mutex_lock(&di->charger_attached_mutex);
+ mutex_unlock(&di->charger_attached_mutex);
+
return IRQ_HANDLED;
}
@@ -1909,6 +2420,11 @@ static irqreturn_t ab8500_charger_mainchplugdet_handler(int irq, void *_di)
dev_dbg(di->dev, "Main charger plugged\n");
queue_work(di->charger_wq, &di->ac_work);
+ mutex_lock(&di->charger_attached_mutex);
+ mutex_unlock(&di->charger_attached_mutex);
+ queue_delayed_work(di->charger_wq,
+ &di->ac_charger_attached_work,
+ HZ);
return IRQ_HANDLED;
}
@@ -1971,6 +2487,21 @@ static irqreturn_t ab8500_charger_mainchthprotf_handler(int irq, void *_di)
return IRQ_HANDLED;
}
+static void ab8500_charger_vbus_drop_end_work(struct work_struct *work)
+{
+ struct ab8500_charger *di = container_of(work,
+ struct ab8500_charger, vbus_drop_end_work.work);
+
+ di->flags.vbus_drop_end = false;
+
+ /* Reset the drop counter */
+ abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CHARGER_CTRL, 0x01);
+
+ if (di->usb.charger_connected)
+ ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+}
+
/**
* ab8500_charger_vbusdetf_handler() - VBUS falling detected
* @irq: interrupt number
@@ -1982,6 +2513,7 @@ static irqreturn_t ab8500_charger_vbusdetf_handler(int irq, void *_di)
{
struct ab8500_charger *di = _di;
+ di->vbus_detected = false;
dev_dbg(di->dev, "VBUS falling detected\n");
queue_work(di->charger_wq, &di->detect_usb_type_work);
@@ -2001,6 +2533,7 @@ static irqreturn_t ab8500_charger_vbusdetr_handler(int irq, void *_di)
di->vbus_detected = true;
dev_dbg(di->dev, "VBUS rising detected\n");
+
queue_work(di->charger_wq, &di->detect_usb_type_work);
return IRQ_HANDLED;
@@ -2109,6 +2642,25 @@ static irqreturn_t ab8500_charger_chwdexp_handler(int irq, void *_di)
}
/**
+ * ab8500_charger_vbuschdropend_handler() - VBUS drop removed
+ * @irq: interrupt number
+ * @_di: pointer to the ab8500_charger structure
+ *
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_charger_vbuschdropend_handler(int irq, void *_di)
+{
+ struct ab8500_charger *di = _di;
+
+ dev_dbg(di->dev, "VBUS charger drop ended\n");
+ di->flags.vbus_drop_end = true;
+ queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work,
+ round_jiffies(30 * HZ));
+
+ return IRQ_HANDLED;
+}
+
+/**
* ab8500_charger_vbusovv_handler() - VBUS overvoltage detected
* @irq: interrupt number
* @_di: pointer to the ab8500_charger structure
@@ -2148,6 +2700,7 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy,
union power_supply_propval *val)
{
struct ab8500_charger *di;
+ int ret;
di = to_ab8500_charger_ac_device_info(psy_to_ux500_charger(psy));
@@ -2169,7 +2722,10 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy,
val->intval = di->ac.charger_connected;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- di->ac.charger_voltage = ab8500_charger_get_ac_voltage(di);
+ ret = ab8500_charger_get_ac_voltage(di);
+ if (ret >= 0)
+ di->ac.charger_voltage = ret;
+ /* On error, use previous value */
val->intval = di->ac.charger_voltage * 1000;
break;
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
@@ -2181,7 +2737,10 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy,
val->intval = di->ac.cv_active;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
- val->intval = ab8500_charger_get_ac_current(di) * 1000;
+ ret = ab8500_charger_get_ac_current(di);
+ if (ret >= 0)
+ di->ac.charger_current = ret;
+ val->intval = di->ac.charger_current * 1000;
break;
default:
return -EINVAL;
@@ -2208,6 +2767,7 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy,
union power_supply_propval *val)
{
struct ab8500_charger *di;
+ int ret;
di = to_ab8500_charger_usb_device_info(psy_to_ux500_charger(psy));
@@ -2231,7 +2791,9 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy,
val->intval = di->usb.charger_connected;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- di->usb.charger_voltage = ab8500_charger_get_vbus_voltage(di);
+ ret = ab8500_charger_get_vbus_voltage(di);
+ if (ret >= 0)
+ di->usb.charger_voltage = ret;
val->intval = di->usb.charger_voltage * 1000;
break;
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
@@ -2243,7 +2805,10 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy,
val->intval = di->usb.cv_active;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
- val->intval = ab8500_charger_get_usb_current(di) * 1000;
+ ret = ab8500_charger_get_usb_current(di);
+ if (ret >= 0)
+ di->usb.charger_current = ret;
+ val->intval = di->usb.charger_current * 1000;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
/*
@@ -2293,13 +2858,23 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
}
}
- /* VBUS OVV set to 6.3V and enable automatic current limitiation */
- ret = abx500_set_register_interruptible(di->dev,
- AB8500_CHARGER,
- AB8500_USBCH_CTRL2_REG,
- VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA);
+ if (is_ab9540_2p0(di->parent) || is_ab8505_2p0(di->parent))
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_CHARGER,
+ AB8500_USBCH_CTRL2_REG,
+ VBUS_AUTO_IN_CURR_LIM_ENA,
+ VBUS_AUTO_IN_CURR_LIM_ENA);
+ else
+ /*
+ * VBUS OVV set to 6.3V and enable automatic current limitation
+ */
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER,
+ AB8500_USBCH_CTRL2_REG,
+ VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA);
if (ret) {
- dev_err(di->dev, "failed to set VBUS OVV\n");
+ dev_err(di->dev,
+ "failed to set automatic current limitation\n");
goto out;
}
@@ -2355,12 +2930,26 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
goto out;
}
+ /* Set charger watchdog timeout */
+ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_WD_TIMER_REG, WD_TIMER);
+ if (ret) {
+ dev_err(di->dev, "failed to set charger watchdog timeout\n");
+ goto out;
+ }
+
+ ret = ab8500_charger_led_en(di, false);
+ if (ret < 0) {
+ dev_err(di->dev, "failed to disable LED\n");
+ goto out;
+ }
+
/* Backup battery voltage and current */
ret = abx500_set_register_interruptible(di->dev,
AB8500_RTC,
AB8500_RTC_BACKUP_CHG_REG,
- di->bat->bkup_bat_v |
- di->bat->bkup_bat_i);
+ di->bm->bkup_bat_v |
+ di->bm->bkup_bat_i);
if (ret) {
dev_err(di->dev, "failed to setup backup battery charging\n");
goto out;
@@ -2394,6 +2983,7 @@ static struct ab8500_charger_interrupts ab8500_charger_irq[] = {
{"USB_CHARGER_NOT_OKR", ab8500_charger_usbchargernotokr_handler},
{"VBUS_OVV", ab8500_charger_vbusovv_handler},
{"CH_WD_EXP", ab8500_charger_chwdexp_handler},
+ {"VBUS_CH_DROP_END", ab8500_charger_vbuschdropend_handler},
};
static int ab8500_charger_usb_notifier_call(struct notifier_block *nb,
@@ -2404,6 +2994,9 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb,
enum ab8500_usb_state bm_usb_state;
unsigned mA = *((unsigned *)power);
+ if (!di)
+ return NOTIFY_DONE;
+
if (event != USB_EVENT_VBUS) {
dev_dbg(di->dev, "not a standard host, returning\n");
return NOTIFY_DONE;
@@ -2427,13 +3020,15 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb,
__func__, bm_usb_state, mA);
spin_lock(&di->usb_state.usb_lock);
- di->usb_state.usb_changed = true;
+ di->usb_state.state_tmp = bm_usb_state;
+ di->usb_state.usb_current_tmp = mA;
spin_unlock(&di->usb_state.usb_lock);
- di->usb_state.state = bm_usb_state;
- di->usb_state.usb_current = mA;
-
- queue_work(di->charger_wq, &di->usb_state_changed_work);
+ /*
+ * wait for some time until you get updates from the usb stack
+ * and negotiations are completed
+ */
+ queue_delayed_work(di->charger_wq, &di->usb_state_changed_work, HZ/2);
return NOTIFY_OK;
}
@@ -2473,6 +3068,9 @@ static int ab8500_charger_resume(struct platform_device *pdev)
&di->check_hw_failure_work, 0);
}
+ if (di->flags.vbus_drop_end)
+ queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work, 0);
+
return 0;
}
@@ -2485,6 +3083,23 @@ static int ab8500_charger_suspend(struct platform_device *pdev,
if (delayed_work_pending(&di->check_hw_failure_work))
cancel_delayed_work(&di->check_hw_failure_work);
+ if (delayed_work_pending(&di->vbus_drop_end_work))
+ cancel_delayed_work(&di->vbus_drop_end_work);
+
+ flush_delayed_work(&di->attach_work);
+ flush_delayed_work(&di->usb_charger_attached_work);
+ flush_delayed_work(&di->ac_charger_attached_work);
+ flush_delayed_work(&di->check_usbchgnotok_work);
+ flush_delayed_work(&di->check_vbat_work);
+ flush_delayed_work(&di->kick_wd_work);
+
+ flush_work(&di->usb_link_status_work);
+ flush_work(&di->ac_work);
+ flush_work(&di->detect_usb_type_work);
+
+ if (atomic_read(&di->current_stepping_sessions))
+ return -EAGAIN;
+
return 0;
}
#else
@@ -2509,9 +3124,6 @@ static int ab8500_charger_remove(struct platform_device *pdev)
free_irq(irq, di);
}
- /* disable the regulator */
- regulator_put(di->regu);
-
/* Backup battery voltage and current disable */
ret = abx500_mask_and_set_register_interruptible(di->dev,
AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0);
@@ -2525,8 +3137,12 @@ static int ab8500_charger_remove(struct platform_device *pdev)
destroy_workqueue(di->charger_wq);
flush_scheduled_work();
- power_supply_unregister(&di->usb_chg.psy);
- power_supply_unregister(&di->ac_chg.psy);
+ if(di->usb_chg.enabled)
+ power_supply_unregister(&di->usb_chg.psy);
+#if !defined(CONFIG_CHARGER_PM2301)
+ if(di->ac_chg.enabled)
+ power_supply_unregister(&di->ac_chg.psy);
+#endif
platform_set_drvdata(pdev, NULL);
return 0;
@@ -2541,32 +3157,31 @@ static char *supply_interface[] = {
static int ab8500_charger_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ struct abx500_bm_data *plat = pdev->dev.platform_data;
struct ab8500_charger *di;
- int irq, i, charger_status, ret = 0;
+ int irq, i, charger_status, ret = 0, ch_stat;
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
if (!di) {
dev_err(&pdev->dev, "%s no mem for ab8500_charger\n", __func__);
return -ENOMEM;
}
- di->bat = pdev->mfd_cell->platform_data;
- if (!di->bat) {
- if (np) {
- ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
- if (ret) {
- dev_err(&pdev->dev,
- "failed to get battery information\n");
- return ret;
- }
- di->autopower_cfg = of_property_read_bool(np, "autopower_cfg");
- } else {
- dev_err(&pdev->dev, "missing dt node for ab8500_charger\n");
- return -EINVAL;
+
+ if (!plat) {
+ dev_err(&pdev->dev, "no battery management data supplied\n");
+ return -EINVAL;
+ }
+ di->bm = plat;
+
+ if (np) {
+ ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get battery information\n");
+ return ret;
}
- } else {
- dev_info(&pdev->dev, "falling back to legacy platform data\n");
+ di->autopower_cfg = of_property_read_bool(np, "autopower_cfg");
+ } else
di->autopower_cfg = false;
- }
/* get parent data */
di->dev = &pdev->dev;
@@ -2575,8 +3190,10 @@ static int ab8500_charger_probe(struct platform_device *pdev)
/* initialize lock */
spin_lock_init(&di->usb_state.usb_lock);
+ mutex_init(&di->usb_ipt_crnt_lock);
di->autopower = false;
+ di->invalid_charger_detect_state = 0;
/* AC supply */
/* power_supply base class */
@@ -2595,6 +3212,9 @@ static int ab8500_charger_probe(struct platform_device *pdev)
ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
di->ac_chg.max_out_curr = ab8500_charger_current_map[
ARRAY_SIZE(ab8500_charger_current_map) - 1];
+ di->ac_chg.wdt_refresh = CHG_WD_INTERVAL;
+ di->ac_chg.enabled = di->bm->ac_enabled;
+ di->ac_chg.external = false;
/* USB supply */
/* power_supply base class */
@@ -2613,7 +3233,9 @@ static int ab8500_charger_probe(struct platform_device *pdev)
ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
di->usb_chg.max_out_curr = ab8500_charger_current_map[
ARRAY_SIZE(ab8500_charger_current_map) - 1];
-
+ di->usb_chg.wdt_refresh = CHG_WD_INTERVAL;
+ di->usb_chg.enabled = di->bm->usb_enabled;
+ di->usb_chg.external = false;
/* Create a work queue for the charger */
di->charger_wq =
@@ -2623,12 +3245,19 @@ static int ab8500_charger_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ mutex_init(&di->charger_attached_mutex);
+
/* Init work for HW failure check */
INIT_DEFERRABLE_WORK(&di->check_hw_failure_work,
ab8500_charger_check_hw_failure_work);
INIT_DEFERRABLE_WORK(&di->check_usbchgnotok_work,
ab8500_charger_check_usbchargernotok_work);
+ INIT_DELAYED_WORK(&di->ac_charger_attached_work,
+ ab8500_charger_ac_attached_work);
+ INIT_DELAYED_WORK(&di->usb_charger_attached_work,
+ ab8500_charger_usb_attached_work);
+
/*
* For ABB revision 1.0 and 1.1 there is a bug in the watchdog
* logic. That means we have to continously kick the charger
@@ -2644,6 +3273,15 @@ static int ab8500_charger_probe(struct platform_device *pdev)
INIT_DEFERRABLE_WORK(&di->check_vbat_work,
ab8500_charger_check_vbat_work);
+ INIT_DELAYED_WORK(&di->attach_work,
+ ab8500_charger_usb_link_attach_work);
+
+ INIT_DELAYED_WORK(&di->usb_state_changed_work,
+ ab8500_charger_usb_state_changed_work);
+
+ INIT_DELAYED_WORK(&di->vbus_drop_end_work,
+ ab8500_charger_vbus_drop_end_work);
+
/* Init work for charger detection */
INIT_WORK(&di->usb_link_status_work,
ab8500_charger_usb_link_status_work);
@@ -2651,9 +3289,6 @@ static int ab8500_charger_probe(struct platform_device *pdev)
INIT_WORK(&di->detect_usb_type_work,
ab8500_charger_detect_usb_type_work);
- INIT_WORK(&di->usb_state_changed_work,
- ab8500_charger_usb_state_changed_work);
-
/* Init work for checking HW status */
INIT_WORK(&di->check_main_thermal_prot_work,
ab8500_charger_check_main_thermal_prot_work);
@@ -2665,7 +3300,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
* is a charger connected to avoid erroneous BTEMP_HIGH/LOW
* interrupts during charging
*/
- di->regu = regulator_get(di->dev, "vddadc");
+ di->regu = devm_regulator_get(di->dev, "vddadc");
if (IS_ERR(di->regu)) {
ret = PTR_ERR(di->regu);
dev_err(di->dev, "failed to get vddadc regulator\n");
@@ -2677,21 +3312,25 @@ static int ab8500_charger_probe(struct platform_device *pdev)
ret = ab8500_charger_init_hw_registers(di);
if (ret) {
dev_err(di->dev, "failed to initialize ABB registers\n");
- goto free_regulator;
+ goto free_charger_wq;
}
/* Register AC charger class */
- ret = power_supply_register(di->dev, &di->ac_chg.psy);
- if (ret) {
- dev_err(di->dev, "failed to register AC charger\n");
- goto free_regulator;
+ if(di->ac_chg.enabled) {
+ ret = power_supply_register(di->dev, &di->ac_chg.psy);
+ if (ret) {
+ dev_err(di->dev, "failed to register AC charger\n");
+ goto free_charger_wq;
+ }
}
/* Register USB charger class */
- ret = power_supply_register(di->dev, &di->usb_chg.psy);
- if (ret) {
- dev_err(di->dev, "failed to register USB charger\n");
- goto free_ac;
+ if(di->usb_chg.enabled) {
+ ret = power_supply_register(di->dev, &di->usb_chg.psy);
+ if (ret) {
+ dev_err(di->dev, "failed to register USB charger\n");
+ goto free_ac;
+ }
}
di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
@@ -2708,7 +3347,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
}
/* Identify the connected charger types during startup */
- charger_status = ab8500_charger_detect_chargers(di);
+ charger_status = ab8500_charger_detect_chargers(di, true);
if (charger_status & AC_PW_CONN) {
di->ac.charger_connected = 1;
di->ac_conn = true;
@@ -2717,7 +3356,6 @@ static int ab8500_charger_probe(struct platform_device *pdev)
}
if (charger_status & USB_PW_CONN) {
- dev_dbg(di->dev, "VBUS Detect during startup\n");
di->vbus_detected = true;
di->vbus_detected_start = true;
queue_work(di->charger_wq,
@@ -2742,6 +3380,23 @@ static int ab8500_charger_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, di);
+ mutex_lock(&di->charger_attached_mutex);
+
+ ch_stat = ab8500_charger_detect_chargers(di, false);
+
+ if ((ch_stat & AC_PW_CONN) == AC_PW_CONN) {
+ queue_delayed_work(di->charger_wq,
+ &di->ac_charger_attached_work,
+ HZ);
+ }
+ if ((ch_stat & USB_PW_CONN) == USB_PW_CONN) {
+ queue_delayed_work(di->charger_wq,
+ &di->usb_charger_attached_work,
+ HZ);
+ }
+
+ mutex_unlock(&di->charger_attached_mutex);
+
return ret;
free_irq:
@@ -2755,11 +3410,11 @@ free_irq:
put_usb_phy:
usb_put_phy(di->usb_phy);
free_usb:
- power_supply_unregister(&di->usb_chg.psy);
+ if(di->usb_chg.enabled)
+ power_supply_unregister(&di->usb_chg.psy);
free_ac:
- power_supply_unregister(&di->ac_chg.psy);
-free_regulator:
- regulator_put(di->regu);
+ if(di->ac_chg.enabled)
+ power_supply_unregister(&di->ac_chg.psy);
free_charger_wq:
destroy_workqueue(di->charger_wq);
return ret;
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index b3bf178c3462..25dae4c4b0ef 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -32,6 +32,7 @@
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-bm.h>
#include <linux/mfd/abx500/ab8500-gpadc.h>
+#include <linux/kernel.h>
#define MILLI_TO_MICRO 1000
#define FG_LSB_IN_MA 1627
@@ -42,7 +43,7 @@
#define NBR_AVG_SAMPLES 20
-#define LOW_BAT_CHECK_INTERVAL (2 * HZ)
+#define LOW_BAT_CHECK_INTERVAL (HZ / 16) /* 62.5 ms */
#define VALID_CAPACITY_SEC (45 * 60) /* 45 minutes */
#define BATT_OK_MIN 2360 /* mV */
@@ -113,6 +114,13 @@ struct ab8500_fg_avg_cap {
int sum;
};
+struct ab8500_fg_cap_scaling {
+ bool enable;
+ int cap_to_scale[2];
+ int disable_cap_level;
+ int scaled_cap;
+};
+
struct ab8500_fg_battery_capacity {
int max_mah_design;
int max_mah;
@@ -123,6 +131,7 @@ struct ab8500_fg_battery_capacity {
int prev_percent;
int prev_level;
int user_mah;
+ struct ab8500_fg_cap_scaling cap_scale;
};
struct ab8500_fg_flags {
@@ -160,6 +169,8 @@ struct inst_curr_result_list {
* @recovery_cnt: Counter for recovery mode
* @high_curr_cnt: Counter for high current mode
* @init_cnt: Counter for init mode
+ * @low_bat_cnt Counter for number of consecutive low battery measures
+ * @nbr_cceoc_irq_cnt Counter for number of CCEOC irqs received since enabled
* @recovery_needed: Indicate if recovery is needed
* @high_curr_mode: Indicate if we're in high current mode
* @init_capacity: Indicate if initial capacity measuring should be done
@@ -167,13 +178,14 @@ struct inst_curr_result_list {
* @calib_state State during offset calibration
* @discharge_state: Current discharge state
* @charge_state: Current charge state
+ * @ab8500_fg_started Completion struct used for the instant current start
* @ab8500_fg_complete Completion struct used for the instant current reading
* @flags: Structure for information about events triggered
* @bat_cap: Structure for battery capacity specific parameters
* @avg_cap: Average capacity filter
* @parent: Pointer to the struct ab8500
* @gpadc: Pointer to the struct gpadc
- * @bat: Pointer to the abx500_bm platform data
+ * @bm: Platform specific battery management information
* @fg_psy: Structure that holds the FG specific battery properties
* @fg_wq: Work queue for running the FG algorithm
* @fg_periodic_work: Work to run the FG algorithm periodically
@@ -199,6 +211,8 @@ struct ab8500_fg {
int recovery_cnt;
int high_curr_cnt;
int init_cnt;
+ int low_bat_cnt;
+ int nbr_cceoc_irq_cnt;
bool recovery_needed;
bool high_curr_mode;
bool init_capacity;
@@ -206,13 +220,14 @@ struct ab8500_fg {
enum ab8500_fg_calibration_state calib_state;
enum ab8500_fg_discharge_state discharge_state;
enum ab8500_fg_charge_state charge_state;
+ struct completion ab8500_fg_started;
struct completion ab8500_fg_complete;
struct ab8500_fg_flags flags;
struct ab8500_fg_battery_capacity bat_cap;
struct ab8500_fg_avg_cap avg_cap;
struct ab8500 *parent;
struct ab8500_gpadc *gpadc;
- struct abx500_bm_data *bat;
+ struct abx500_bm_data *bm;
struct power_supply fg_psy;
struct workqueue_struct *fg_wq;
struct delayed_work fg_periodic_work;
@@ -355,7 +370,7 @@ static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr)
/*
* We want to know if we're in low current mode
*/
- if (curr > -di->bat->fg_params->high_curr_threshold)
+ if (curr > -di->bm->fg_params->high_curr_threshold)
return true;
else
return false;
@@ -484,8 +499,9 @@ static int ab8500_fg_coulomb_counter(struct ab8500_fg *di, bool enable)
di->flags.fg_enabled = true;
} else {
/* Clear any pending read requests */
- ret = abx500_set_register_interruptible(di->dev,
- AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, 0);
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG,
+ (RESET_ACCU | READ_REQ), 0);
if (ret)
goto cc_err;
@@ -523,13 +539,14 @@ cc_err:
* Note: This is part "one" and has to be called before
* ab8500_fg_inst_curr_finalize()
*/
- int ab8500_fg_inst_curr_start(struct ab8500_fg *di)
+int ab8500_fg_inst_curr_start(struct ab8500_fg *di)
{
u8 reg_val;
int ret;
mutex_lock(&di->cc_lock);
+ di->nbr_cceoc_irq_cnt = 0;
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
AB8500_RTC_CC_CONF_REG, &reg_val);
if (ret < 0)
@@ -557,6 +574,7 @@ cc_err:
}
/* Return and WFI */
+ INIT_COMPLETION(di->ab8500_fg_started);
INIT_COMPLETION(di->ab8500_fg_complete);
enable_irq(di->irq);
@@ -568,6 +586,17 @@ fail:
}
/**
+ * ab8500_fg_inst_curr_started() - check if fg conversion has started
+ * @di: pointer to the ab8500_fg structure
+ *
+ * Returns 1 if conversion started, 0 if still waiting
+ */
+int ab8500_fg_inst_curr_started(struct ab8500_fg *di)
+{
+ return completion_done(&di->ab8500_fg_started);
+}
+
+/**
* ab8500_fg_inst_curr_done() - check if fg conversion is done
* @di: pointer to the ab8500_fg structure
*
@@ -595,13 +624,15 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res)
int timeout;
if (!completion_done(&di->ab8500_fg_complete)) {
- timeout = wait_for_completion_timeout(&di->ab8500_fg_complete,
+ timeout = wait_for_completion_timeout(
+ &di->ab8500_fg_complete,
INS_CURR_TIMEOUT);
dev_dbg(di->dev, "Finalize time: %d ms\n",
((INS_CURR_TIMEOUT - timeout) * 1000) / HZ);
if (!timeout) {
ret = -ETIME;
disable_irq(di->irq);
+ di->nbr_cceoc_irq_cnt = 0;
dev_err(di->dev, "completion timed out [%d]\n",
__LINE__);
goto fail;
@@ -609,6 +640,7 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res)
}
disable_irq(di->irq);
+ di->nbr_cceoc_irq_cnt = 0;
ret = abx500_mask_and_set_register_interruptible(di->dev,
AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG,
@@ -647,7 +679,7 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res)
* 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
*/
val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) /
- (1000 * di->bat->fg_res);
+ (1000 * di->bm->fg_res);
if (di->turn_off_fg) {
dev_dbg(di->dev, "%s Disable FG\n", __func__);
@@ -683,6 +715,7 @@ fail:
int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di)
{
int ret;
+ int timeout;
int res = 0;
ret = ab8500_fg_inst_curr_start(di);
@@ -691,13 +724,33 @@ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di)
return 0;
}
+ /* Wait for CC to actually start */
+ if (!completion_done(&di->ab8500_fg_started)) {
+ timeout = wait_for_completion_timeout(
+ &di->ab8500_fg_started,
+ INS_CURR_TIMEOUT);
+ dev_dbg(di->dev, "Start time: %d ms\n",
+ ((INS_CURR_TIMEOUT - timeout) * 1000) / HZ);
+ if (!timeout) {
+ ret = -ETIME;
+ dev_err(di->dev, "completion timed out [%d]\n",
+ __LINE__);
+ goto fail;
+ }
+ }
+
ret = ab8500_fg_inst_curr_finalize(di, &res);
if (ret) {
dev_err(di->dev, "Failed to finalize fg_inst\n");
return 0;
}
+ dev_dbg(di->dev, "%s instant current: %d", __func__, res);
return res;
+fail:
+ disable_irq(di->irq);
+ mutex_unlock(&di->cc_lock);
+ return ret;
}
/**
@@ -750,19 +803,16 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work)
* 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
*/
di->accu_charge = (val * QLSB_NANO_AMP_HOURS_X10) /
- (100 * di->bat->fg_res);
+ (100 * di->bm->fg_res);
/*
* Convert to unit value in mA
- * Full scale input voltage is
- * 66.660mV => LSB = 66.660mV/(4096*res) = 1.627mA
- * Given a 250ms conversion cycle time the LSB corresponds
- * to 112.9 nAh. Convert to current by dividing by the conversion
+ * by dividing by the conversion
* time in hours (= samples / (3600 * 4)h)
- * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
+ * and multiply with 1000
*/
di->avg_curr = (val * QLSB_NANO_AMP_HOURS_X10 * 36) /
- (1000 * di->bat->fg_res * (di->fg_samples / 4));
+ (1000 * di->bm->fg_res * (di->fg_samples / 4));
di->flags.conv_done = true;
@@ -770,6 +820,8 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work)
queue_work(di->fg_wq, &di->fg_work);
+ dev_dbg(di->dev, "fg_res: %d, fg_samples: %d, gasg: %d, accu_charge: %d \n",
+ di->bm->fg_res, di->fg_samples, val, di->accu_charge);
return;
exit:
dev_err(di->dev,
@@ -814,8 +866,8 @@ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage)
struct abx500_v_to_cap *tbl;
int cap = 0;
- tbl = di->bat->bat_type[di->bat->batt_id].v_to_cap_tbl,
- tbl_size = di->bat->bat_type[di->bat->batt_id].n_v_cap_tbl_elements;
+ tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl,
+ tbl_size = di->bm->bat_type[di->bm->batt_id].n_v_cap_tbl_elements;
for (i = 0; i < tbl_size; ++i) {
if (voltage > tbl[i].voltage)
@@ -866,8 +918,8 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di)
struct batres_vs_temp *tbl;
int resist = 0;
- tbl = di->bat->bat_type[di->bat->batt_id].batres_tbl;
- tbl_size = di->bat->bat_type[di->bat->batt_id].n_batres_tbl_elements;
+ tbl = di->bm->bat_type[di->bm->batt_id].batres_tbl;
+ tbl_size = di->bm->bat_type[di->bm->batt_id].n_batres_tbl_elements;
for (i = 0; i < tbl_size; ++i) {
if (di->bat_temp / 10 > tbl[i].temp)
@@ -888,11 +940,11 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di)
dev_dbg(di->dev, "%s Temp: %d battery internal resistance: %d"
" fg resistance %d, total: %d (mOhm)\n",
- __func__, di->bat_temp, resist, di->bat->fg_res / 10,
- (di->bat->fg_res / 10) + resist);
+ __func__, di->bat_temp, resist, di->bm->fg_res / 10,
+ (di->bm->fg_res / 10) + resist);
/* fg_res variable is in 0.1mOhm */
- resist += di->bat->fg_res / 10;
+ resist += di->bm->fg_res / 10;
return resist;
}
@@ -915,7 +967,7 @@ static int ab8500_fg_load_comp_volt_to_capacity(struct ab8500_fg *di)
do {
vbat += ab8500_fg_bat_voltage(di);
i++;
- msleep(5);
+ usleep_range(5000, 6000);
} while (!ab8500_fg_inst_curr_done(di));
ab8500_fg_inst_curr_finalize(di, &di->inst_curr);
@@ -1108,16 +1160,16 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di)
{
int ret, percent;
- percent = di->bat_cap.permille / 10;
+ percent = DIV_ROUND_CLOSEST(di->bat_cap.permille, 10);
- if (percent <= di->bat->cap_levels->critical ||
+ if (percent <= di->bm->cap_levels->critical ||
di->flags.low_bat)
ret = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
- else if (percent <= di->bat->cap_levels->low)
+ else if (percent <= di->bm->cap_levels->low)
ret = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
- else if (percent <= di->bat->cap_levels->normal)
+ else if (percent <= di->bm->cap_levels->normal)
ret = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
- else if (percent <= di->bat->cap_levels->high)
+ else if (percent <= di->bm->cap_levels->high)
ret = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
else
ret = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
@@ -1126,6 +1178,99 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di)
}
/**
+ * ab8500_fg_calculate_scaled_capacity() - Capacity scaling
+ * @di: pointer to the ab8500_fg structure
+ *
+ * Calculates the capacity to be shown to upper layers. Scales the capacity
+ * to have 100% as a reference from the actual capacity upon removal of charger
+ * when charging is in maintenance mode.
+ */
+static int ab8500_fg_calculate_scaled_capacity(struct ab8500_fg *di)
+{
+ struct ab8500_fg_cap_scaling *cs = &di->bat_cap.cap_scale;
+ int capacity = di->bat_cap.prev_percent;
+
+ if (!cs->enable)
+ return capacity;
+
+ /*
+ * As long as we are in fully charge mode scale the capacity
+ * to show 100%.
+ */
+ if (di->flags.fully_charged) {
+ cs->cap_to_scale[0] = 100;
+ cs->cap_to_scale[1] =
+ max(capacity, di->bm->fg_params->maint_thres);
+ dev_dbg(di->dev, "Scale cap with %d/%d\n",
+ cs->cap_to_scale[0], cs->cap_to_scale[1]);
+ }
+
+ /* Calculates the scaled capacity. */
+ if ((cs->cap_to_scale[0] != cs->cap_to_scale[1])
+ && (cs->cap_to_scale[1] > 0))
+ capacity = min(100,
+ DIV_ROUND_CLOSEST(di->bat_cap.prev_percent *
+ cs->cap_to_scale[0],
+ cs->cap_to_scale[1]));
+
+ if (di->flags.charging) {
+ if (capacity < cs->disable_cap_level) {
+ cs->disable_cap_level = capacity;
+ dev_dbg(di->dev, "Cap to stop scale lowered %d%%\n",
+ cs->disable_cap_level);
+ } else if (!di->flags.fully_charged) {
+ if (di->bat_cap.prev_percent >=
+ cs->disable_cap_level) {
+ dev_dbg(di->dev, "Disabling scaled capacity\n");
+ cs->enable = false;
+ capacity = di->bat_cap.prev_percent;
+ } else {
+ dev_dbg(di->dev,
+ "Waiting in cap to level %d%%\n",
+ cs->disable_cap_level);
+ capacity = cs->disable_cap_level;
+ }
+ }
+ }
+
+ return capacity;
+}
+
+/**
+ * ab8500_fg_update_cap_scalers() - Capacity scaling
+ * @di: pointer to the ab8500_fg structure
+ *
+ * To be called when state change from charge<->discharge to update
+ * the capacity scalers.
+ */
+static void ab8500_fg_update_cap_scalers(struct ab8500_fg *di)
+{
+ struct ab8500_fg_cap_scaling *cs = &di->bat_cap.cap_scale;
+
+ if (!cs->enable)
+ return;
+ if (di->flags.charging) {
+ di->bat_cap.cap_scale.disable_cap_level =
+ di->bat_cap.cap_scale.scaled_cap;
+ dev_dbg(di->dev, "Cap to stop scale at charge %d%%\n",
+ di->bat_cap.cap_scale.disable_cap_level);
+ } else {
+ if (cs->scaled_cap != 100) {
+ cs->cap_to_scale[0] = cs->scaled_cap;
+ cs->cap_to_scale[1] = di->bat_cap.prev_percent;
+ } else {
+ cs->cap_to_scale[0] = 100;
+ cs->cap_to_scale[1] =
+ max(di->bat_cap.prev_percent,
+ di->bm->fg_params->maint_thres);
+ }
+
+ dev_dbg(di->dev, "Cap to scale at discharge %d/%d\n",
+ cs->cap_to_scale[0], cs->cap_to_scale[1]);
+ }
+}
+
+/**
* ab8500_fg_check_capacity_limits() - Check if capacity has changed
* @di: pointer to the ab8500_fg structure
* @init: capacity is allowed to go up in init mode
@@ -1136,6 +1281,7 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di)
static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init)
{
bool changed = false;
+ int percent = DIV_ROUND_CLOSEST(di->bat_cap.permille, 10);
di->bat_cap.level = ab8500_fg_capacity_level(di);
@@ -1167,33 +1313,41 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init)
dev_dbg(di->dev, "Battery low, set capacity to 0\n");
di->bat_cap.prev_percent = 0;
di->bat_cap.permille = 0;
+ percent = 0;
di->bat_cap.prev_mah = 0;
di->bat_cap.mah = 0;
changed = true;
} else if (di->flags.fully_charged) {
/*
* We report 100% if algorithm reported fully charged
- * unless capacity drops too much
+ * and show 100% during maintenance charging (scaling).
*/
if (di->flags.force_full) {
- di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+ di->bat_cap.prev_percent = percent;
di->bat_cap.prev_mah = di->bat_cap.mah;
- } else if (!di->flags.force_full &&
- di->bat_cap.prev_percent !=
- (di->bat_cap.permille) / 10 &&
- (di->bat_cap.permille / 10) <
- di->bat->fg_params->maint_thres) {
+
+ changed = true;
+
+ if (!di->bat_cap.cap_scale.enable &&
+ di->bm->capacity_scaling) {
+ di->bat_cap.cap_scale.enable = true;
+ di->bat_cap.cap_scale.cap_to_scale[0] = 100;
+ di->bat_cap.cap_scale.cap_to_scale[1] =
+ di->bat_cap.prev_percent;
+ di->bat_cap.cap_scale.disable_cap_level = 100;
+ }
+ } else if (di->bat_cap.prev_percent != percent) {
dev_dbg(di->dev,
"battery reported full "
"but capacity dropping: %d\n",
- di->bat_cap.permille / 10);
- di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+ percent);
+ di->bat_cap.prev_percent = percent;
di->bat_cap.prev_mah = di->bat_cap.mah;
changed = true;
}
- } else if (di->bat_cap.prev_percent != di->bat_cap.permille / 10) {
- if (di->bat_cap.permille / 10 == 0) {
+ } else if (di->bat_cap.prev_percent != percent) {
+ if (percent == 0) {
/*
* We will not report 0% unless we've got
* the LOW_BAT IRQ, no matter what the FG
@@ -1203,11 +1357,11 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init)
di->bat_cap.permille = 1;
di->bat_cap.prev_mah = 1;
di->bat_cap.mah = 1;
+ percent = 1;
changed = true;
} else if (!(!di->flags.charging &&
- (di->bat_cap.permille / 10) >
- di->bat_cap.prev_percent) || init) {
+ percent > di->bat_cap.prev_percent) || init) {
/*
* We do not allow reported capacity to go up
* unless we're charging or if we're in init
@@ -1215,9 +1369,9 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init)
dev_dbg(di->dev,
"capacity changed from %d to %d (%d)\n",
di->bat_cap.prev_percent,
- di->bat_cap.permille / 10,
+ percent,
di->bat_cap.permille);
- di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+ di->bat_cap.prev_percent = percent;
di->bat_cap.prev_mah = di->bat_cap.mah;
changed = true;
@@ -1225,12 +1379,20 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init)
dev_dbg(di->dev, "capacity not allowed to go up since "
"no charger is connected: %d to %d (%d)\n",
di->bat_cap.prev_percent,
- di->bat_cap.permille / 10,
+ percent,
di->bat_cap.permille);
}
}
if (changed) {
+ if (di->bm->capacity_scaling) {
+ di->bat_cap.cap_scale.scaled_cap =
+ ab8500_fg_calculate_scaled_capacity(di);
+
+ dev_info(di->dev, "capacity=%d (%d)\n",
+ di->bat_cap.prev_percent,
+ di->bat_cap.cap_scale.scaled_cap);
+ }
power_supply_changed(&di->fg_psy);
if (di->flags.fully_charged && di->flags.force_full) {
dev_dbg(di->dev, "Battery full, notifying.\n");
@@ -1284,7 +1446,7 @@ static void ab8500_fg_algorithm_charging(struct ab8500_fg *di)
switch (di->charge_state) {
case AB8500_FG_CHARGE_INIT:
di->fg_samples = SEC_TO_SAMPLE(
- di->bat->fg_params->accu_charging);
+ di->bm->fg_params->accu_charging);
ab8500_fg_coulomb_counter(di, true);
ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_READOUT);
@@ -1296,7 +1458,7 @@ static void ab8500_fg_algorithm_charging(struct ab8500_fg *di)
* Read the FG and calculate the new capacity
*/
mutex_lock(&di->cc_lock);
- if (!di->flags.conv_done) {
+ if (!di->flags.conv_done && !di->flags.force_full) {
/* Wasn't the CC IRQ that got us here */
mutex_unlock(&di->cc_lock);
dev_dbg(di->dev, "%s CC conv not done\n",
@@ -1346,8 +1508,8 @@ static bool check_sysfs_capacity(struct ab8500_fg *di)
cap_permille = ab8500_fg_convert_mah_to_permille(di,
di->bat_cap.user_mah);
- lower = di->bat_cap.permille - di->bat->fg_params->user_cap_limit * 10;
- upper = di->bat_cap.permille + di->bat->fg_params->user_cap_limit * 10;
+ lower = di->bat_cap.permille - di->bm->fg_params->user_cap_limit * 10;
+ upper = di->bat_cap.permille + di->bm->fg_params->user_cap_limit * 10;
if (lower < 0)
lower = 0;
@@ -1387,7 +1549,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
case AB8500_FG_DISCHARGE_INIT:
/* We use the FG IRQ to work on */
di->init_cnt = 0;
- di->fg_samples = SEC_TO_SAMPLE(di->bat->fg_params->init_timer);
+ di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer);
ab8500_fg_coulomb_counter(di, true);
ab8500_fg_discharge_state_to(di,
AB8500_FG_DISCHARGE_INITMEASURING);
@@ -1400,18 +1562,17 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
* samples to get an initial capacity.
* Then go to READOUT
*/
- sleep_time = di->bat->fg_params->init_timer;
+ sleep_time = di->bm->fg_params->init_timer;
/* Discard the first [x] seconds */
- if (di->init_cnt >
- di->bat->fg_params->init_discard_time) {
+ if (di->init_cnt > di->bm->fg_params->init_discard_time) {
ab8500_fg_calc_cap_discharge_voltage(di, true);
ab8500_fg_check_capacity_limits(di, true);
}
di->init_cnt += sleep_time;
- if (di->init_cnt > di->bat->fg_params->init_total_time)
+ if (di->init_cnt > di->bm->fg_params->init_total_time)
ab8500_fg_discharge_state_to(di,
AB8500_FG_DISCHARGE_READOUT_INIT);
@@ -1426,7 +1587,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
/* Intentional fallthrough */
case AB8500_FG_DISCHARGE_RECOVERY:
- sleep_time = di->bat->fg_params->recovery_sleep_timer;
+ sleep_time = di->bm->fg_params->recovery_sleep_timer;
/*
* We should check the power consumption
@@ -1438,9 +1599,9 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
if (ab8500_fg_is_low_curr(di, di->inst_curr)) {
if (di->recovery_cnt >
- di->bat->fg_params->recovery_total_time) {
+ di->bm->fg_params->recovery_total_time) {
di->fg_samples = SEC_TO_SAMPLE(
- di->bat->fg_params->accu_high_curr);
+ di->bm->fg_params->accu_high_curr);
ab8500_fg_coulomb_counter(di, true);
ab8500_fg_discharge_state_to(di,
AB8500_FG_DISCHARGE_READOUT);
@@ -1453,7 +1614,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
di->recovery_cnt += sleep_time;
} else {
di->fg_samples = SEC_TO_SAMPLE(
- di->bat->fg_params->accu_high_curr);
+ di->bm->fg_params->accu_high_curr);
ab8500_fg_coulomb_counter(di, true);
ab8500_fg_discharge_state_to(di,
AB8500_FG_DISCHARGE_READOUT);
@@ -1462,7 +1623,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
case AB8500_FG_DISCHARGE_READOUT_INIT:
di->fg_samples = SEC_TO_SAMPLE(
- di->bat->fg_params->accu_high_curr);
+ di->bm->fg_params->accu_high_curr);
ab8500_fg_coulomb_counter(di, true);
ab8500_fg_discharge_state_to(di,
AB8500_FG_DISCHARGE_READOUT);
@@ -1480,7 +1641,7 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
if (di->recovery_needed) {
ab8500_fg_discharge_state_to(di,
- AB8500_FG_DISCHARGE_RECOVERY);
+ AB8500_FG_DISCHARGE_INIT_RECOVERY);
queue_delayed_work(di->fg_wq,
&di->fg_periodic_work, 0);
@@ -1509,9 +1670,9 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
}
di->high_curr_cnt +=
- di->bat->fg_params->accu_high_curr;
+ di->bm->fg_params->accu_high_curr;
if (di->high_curr_cnt >
- di->bat->fg_params->high_curr_time)
+ di->bm->fg_params->high_curr_time)
di->recovery_needed = true;
ab8500_fg_calc_cap_discharge_fg(di);
@@ -1523,12 +1684,10 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
case AB8500_FG_DISCHARGE_WAKEUP:
ab8500_fg_coulomb_counter(di, true);
- di->inst_curr = ab8500_fg_inst_curr_blocking(di);
-
ab8500_fg_calc_cap_discharge_voltage(di, true);
di->fg_samples = SEC_TO_SAMPLE(
- di->bat->fg_params->accu_high_curr);
+ di->bm->fg_params->accu_high_curr);
ab8500_fg_coulomb_counter(di, true);
ab8500_fg_discharge_state_to(di,
AB8500_FG_DISCHARGE_READOUT);
@@ -1641,8 +1800,6 @@ static void ab8500_fg_periodic_work(struct work_struct *work)
fg_periodic_work.work);
if (di->init_capacity) {
- /* A dummy read that will return 0 */
- di->inst_curr = ab8500_fg_inst_curr_blocking(di);
/* Get an initial capacity calculation */
ab8500_fg_calc_cap_discharge_voltage(di, true);
ab8500_fg_check_capacity_limits(di, true);
@@ -1684,24 +1841,26 @@ static void ab8500_fg_check_hw_failure_work(struct work_struct *work)
* If we have had a battery over-voltage situation,
* check ovv-bit to see if it should be reset.
*/
- if (di->flags.bat_ovv) {
- ret = abx500_get_register_interruptible(di->dev,
- AB8500_CHARGER, AB8500_CH_STAT_REG,
- &reg_value);
- if (ret < 0) {
- dev_err(di->dev, "%s ab8500 read failed\n", __func__);
- return;
- }
- if ((reg_value & BATT_OVV) != BATT_OVV) {
- dev_dbg(di->dev, "Battery recovered from OVV\n");
- di->flags.bat_ovv = false;
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CH_STAT_REG,
+ &reg_value);
+ if (ret < 0) {
+ dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+ return;
+ }
+ if ((reg_value & BATT_OVV) == BATT_OVV) {
+ if (!di->flags.bat_ovv) {
+ dev_dbg(di->dev, "Battery OVV\n");
+ di->flags.bat_ovv = true;
power_supply_changed(&di->fg_psy);
- return;
}
-
/* Not yet recovered from ovv, reschedule this test */
queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work,
- round_jiffies(HZ));
+ HZ);
+ } else {
+ dev_dbg(di->dev, "Battery recovered from OVV\n");
+ di->flags.bat_ovv = false;
+ power_supply_changed(&di->fg_psy);
}
}
@@ -1721,26 +1880,30 @@ static void ab8500_fg_low_bat_work(struct work_struct *work)
vbat = ab8500_fg_bat_voltage(di);
/* Check if LOW_BAT still fulfilled */
- if (vbat < di->bat->fg_params->lowbat_threshold) {
- di->flags.low_bat = true;
- dev_warn(di->dev, "Battery voltage still LOW\n");
-
- /*
- * We need to re-schedule this check to be able to detect
- * if the voltage increases again during charging
- */
- queue_delayed_work(di->fg_wq, &di->fg_low_bat_work,
- round_jiffies(LOW_BAT_CHECK_INTERVAL));
+ if (vbat < di->bm->fg_params->lowbat_threshold) {
+ /* Is it time to shut down? */
+ if (di->low_bat_cnt < 1) {
+ di->flags.low_bat = true;
+ dev_warn(di->dev, "Shut down pending...\n");
+ } else {
+ /*
+ * Else we need to re-schedule this check to be able to detect
+ * if the voltage increases again during charging or
+ * due to decreasing load.
+ */
+ di->low_bat_cnt--;
+ dev_warn(di->dev, "Battery voltage still LOW\n");
+ queue_delayed_work(di->fg_wq, &di->fg_low_bat_work,
+ round_jiffies(LOW_BAT_CHECK_INTERVAL));
+ }
} else {
- di->flags.low_bat = false;
+ di->flags.low_bat_delay = false;
+ di->low_bat_cnt = 10;
dev_warn(di->dev, "Battery voltage OK again\n");
}
/* This is needed to dispatch LOW_BAT */
ab8500_fg_check_capacity_limits(di, false);
-
- /* Set this flag to check if LOW_BAT IRQ still occurs */
- di->flags.low_bat_delay = false;
}
/**
@@ -1779,8 +1942,8 @@ static int ab8500_fg_battok_init_hw_register(struct ab8500_fg *di)
int ret;
int new_val;
- sel0 = di->bat->fg_params->battok_falling_th_sel0;
- sel1 = di->bat->fg_params->battok_raising_th_sel1;
+ sel0 = di->bm->fg_params->battok_falling_th_sel0;
+ sel1 = di->bm->fg_params->battok_raising_th_sel1;
cbp_sel0 = ab8500_fg_battok_calc(di, sel0);
cbp_sel1 = ab8500_fg_battok_calc(di, sel1);
@@ -1828,7 +1991,13 @@ static void ab8500_fg_instant_work(struct work_struct *work)
static irqreturn_t ab8500_fg_cc_data_end_handler(int irq, void *_di)
{
struct ab8500_fg *di = _di;
- complete(&di->ab8500_fg_complete);
+ if (!di->nbr_cceoc_irq_cnt) {
+ di->nbr_cceoc_irq_cnt++;
+ complete(&di->ab8500_fg_started);
+ } else {
+ di->nbr_cceoc_irq_cnt = 0;
+ complete(&di->ab8500_fg_complete);
+ }
return IRQ_HANDLED;
}
@@ -1875,8 +2044,6 @@ static irqreturn_t ab8500_fg_batt_ovv_handler(int irq, void *_di)
struct ab8500_fg *di = _di;
dev_dbg(di->dev, "Battery OVV\n");
- di->flags.bat_ovv = true;
- power_supply_changed(&di->fg_psy);
/* Schedule a new HW failure check */
queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work, 0);
@@ -1895,6 +2062,7 @@ static irqreturn_t ab8500_fg_lowbatf_handler(int irq, void *_di)
{
struct ab8500_fg *di = _di;
+ /* Initiate handling in ab8500_fg_low_bat_work() if not already initiated. */
if (!di->flags.low_bat_delay) {
dev_warn(di->dev, "Battery voltage is below LOW threshold\n");
di->flags.low_bat_delay = true;
@@ -1963,7 +2131,7 @@ static int ab8500_fg_get_property(struct power_supply *psy,
di->bat_cap.max_mah);
break;
case POWER_SUPPLY_PROP_ENERGY_NOW:
- if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+ if (di->flags.batt_unknown && !di->bm->chg_unknown_bat &&
di->flags.batt_id_received)
val->intval = ab8500_fg_convert_mah_to_uwh(di,
di->bat_cap.max_mah);
@@ -1978,21 +2146,23 @@ static int ab8500_fg_get_property(struct power_supply *psy,
val->intval = di->bat_cap.max_mah;
break;
case POWER_SUPPLY_PROP_CHARGE_NOW:
- if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+ if (di->flags.batt_unknown && !di->bm->chg_unknown_bat &&
di->flags.batt_id_received)
val->intval = di->bat_cap.max_mah;
else
val->intval = di->bat_cap.prev_mah;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+ if (di->bm->capacity_scaling)
+ val->intval = di->bat_cap.cap_scale.scaled_cap;
+ else if (di->flags.batt_unknown && !di->bm->chg_unknown_bat &&
di->flags.batt_id_received)
val->intval = 100;
else
val->intval = di->bat_cap.prev_percent;
break;
case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
- if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+ if (di->flags.batt_unknown && !di->bm->chg_unknown_bat &&
di->flags.batt_id_received)
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
else
@@ -2049,6 +2219,8 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
break;
di->flags.charging = false;
di->flags.fully_charged = false;
+ if (di->bm->capacity_scaling)
+ ab8500_fg_update_cap_scalers(di);
queue_work(di->fg_wq, &di->fg_work);
break;
case POWER_SUPPLY_STATUS_FULL:
@@ -2061,10 +2233,13 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
queue_work(di->fg_wq, &di->fg_work);
break;
case POWER_SUPPLY_STATUS_CHARGING:
- if (di->flags.charging)
+ if (di->flags.charging &&
+ !di->flags.fully_charged)
break;
di->flags.charging = true;
di->flags.fully_charged = false;
+ if (di->bm->capacity_scaling)
+ ab8500_fg_update_cap_scalers(di);
queue_work(di->fg_wq, &di->fg_work);
break;
};
@@ -2075,10 +2250,11 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
case POWER_SUPPLY_PROP_TECHNOLOGY:
switch (ext->type) {
case POWER_SUPPLY_TYPE_BATTERY:
- if (!di->flags.batt_id_received) {
+ if (!di->flags.batt_id_received &&
+ di->bm->batt_id != BATTERY_UNKNOWN) {
const struct abx500_battery_type *b;
- b = &(di->bat->bat_type[di->bat->batt_id]);
+ b = &(di->bm->bat_type[di->bm->batt_id]);
di->flags.batt_id_received = true;
@@ -2104,8 +2280,8 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
case POWER_SUPPLY_PROP_TEMP:
switch (ext->type) {
case POWER_SUPPLY_TYPE_BATTERY:
- if (di->flags.batt_id_received)
- di->bat_temp = ret.intval;
+ if (di->flags.batt_id_received)
+ di->bat_temp = ret.intval;
break;
default:
break;
@@ -2155,7 +2331,7 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg *di)
AB8500_SYS_CTRL2_BLOCK,
AB8500_LOW_BAT_REG,
ab8500_volt_to_regval(
- di->bat->fg_params->lowbat_threshold) << 1 |
+ di->bm->fg_params->lowbat_threshold) << 1 |
LOW_BAT_ENABLE);
if (ret) {
dev_err(di->dev, "%s write failed\n", __func__);
@@ -2395,6 +2571,11 @@ static int ab8500_fg_suspend(struct platform_device *pdev,
struct ab8500_fg *di = platform_get_drvdata(pdev);
flush_delayed_work(&di->fg_periodic_work);
+ flush_work(&di->fg_work);
+ flush_work(&di->fg_acc_cur_work);
+ flush_delayed_work(&di->fg_reinit_work);
+ flush_delayed_work(&di->fg_low_bat_work);
+ flush_delayed_work(&di->fg_check_hw_failure_work);
/*
* If the FG is enabled we will disable it before going to suspend
@@ -2448,6 +2629,7 @@ static char *supply_interface[] = {
static int ab8500_fg_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ struct abx500_bm_data *plat = pdev->dev.platform_data;
struct ab8500_fg *di;
int i, irq;
int ret = 0;
@@ -2457,21 +2639,19 @@ static int ab8500_fg_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s no mem for ab8500_fg\n", __func__);
return -ENOMEM;
}
- di->bat = pdev->mfd_cell->platform_data;
- if (!di->bat) {
- if (np) {
- ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
- if (ret) {
- dev_err(&pdev->dev,
- "failed to get battery information\n");
- return ret;
- }
- } else {
- dev_err(&pdev->dev, "missing dt node for ab8500_fg\n");
- return -EINVAL;
+
+ if (!plat) {
+ dev_err(&pdev->dev, "no battery management data supplied\n");
+ return -EINVAL;
+ }
+ di->bm = plat;
+
+ if (np) {
+ ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get battery information\n");
+ return ret;
}
- } else {
- dev_info(&pdev->dev, "falling back to legacy platform data\n");
}
mutex_init(&di->cc_lock);
@@ -2491,11 +2671,11 @@ static int ab8500_fg_probe(struct platform_device *pdev)
di->fg_psy.external_power_changed = ab8500_fg_external_power_changed;
di->bat_cap.max_mah_design = MILLI_TO_MICRO *
- di->bat->bat_type[di->bat->batt_id].charge_full_design;
+ di->bm->bat_type[di->bm->batt_id].charge_full_design;
di->bat_cap.max_mah = di->bat_cap.max_mah_design;
- di->vbat_nom = di->bat->bat_type[di->bat->batt_id].nominal_voltage;
+ di->vbat_nom = di->bm->bat_type[di->bm->batt_id].nominal_voltage;
di->init_capacity = true;
@@ -2531,6 +2711,12 @@ static int ab8500_fg_probe(struct platform_device *pdev)
INIT_DEFERRABLE_WORK(&di->fg_check_hw_failure_work,
ab8500_fg_check_hw_failure_work);
+ /* Reset battery low voltage flag */
+ di->flags.low_bat = false;
+
+ /* Initialize low battery counter */
+ di->low_bat_cnt = 10;
+
/* Initialize OVV, and other registers */
ret = ab8500_fg_init_hw_registers(di);
if (ret) {
@@ -2549,10 +2735,14 @@ static int ab8500_fg_probe(struct platform_device *pdev)
goto free_inst_curr_wq;
}
- di->fg_samples = SEC_TO_SAMPLE(di->bat->fg_params->init_timer);
+ di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer);
ab8500_fg_coulomb_counter(di, true);
- /* Initialize completion used to notify completion of inst current */
+ /*
+ * Initialize completion used to notify completion and start
+ * of inst current
+ */
+ init_completion(&di->ab8500_fg_started);
init_completion(&di->ab8500_fg_complete);
/* Register interrupts */
@@ -2572,6 +2762,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
}
di->irq = platform_get_irq_byname(pdev, "CCEOC");
disable_irq(di->irq);
+ di->nbr_cceoc_irq_cnt = 0;
platform_set_drvdata(pdev, di);
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 297089146064..f043c0851a76 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -33,9 +33,6 @@
/* End-of-charge criteria counter */
#define EOC_COND_CNT 10
-/* Recharge criteria counter */
-#define RCH_COND_CNT 3
-
#define to_abx500_chargalg_device_info(x) container_of((x), \
struct abx500_chargalg, chargalg_psy);
@@ -196,7 +193,6 @@ enum maxim_ret {
* @dev: pointer to the structure device
* @charge_status: battery operating status
* @eoc_cnt: counter used to determine end-of_charge
- * @rch_cnt: counter used to determine start of recharge
* @maintenance_chg: indicate if maintenance charge is active
* @t_hyst_norm temperature hysteresis when the temperature has been
* over or under normal limits
@@ -207,7 +203,7 @@ enum maxim_ret {
* @chg_info: information about connected charger types
* @batt_data: data of the battery
* @susp_status: current charger suspension status
- * @bat: pointer to the abx500_bm platform data
+ * @bm: Platform specific battery management information
* @chargalg_psy: structure that holds the battery properties exposed by
* the charging algorithm
* @events: structure for information about events triggered
@@ -223,7 +219,6 @@ struct abx500_chargalg {
struct device *dev;
int charge_status;
int eoc_cnt;
- int rch_cnt;
bool maintenance_chg;
int t_hyst_norm;
int t_hyst_lowhigh;
@@ -232,7 +227,7 @@ struct abx500_chargalg {
struct abx500_chargalg_charger_info chg_info;
struct abx500_chargalg_battery_data batt_data;
struct abx500_chargalg_suspension_status susp_status;
- struct abx500_bm_data *bat;
+ struct abx500_bm_data *bm;
struct power_supply chargalg_psy;
struct ux500_charger *ac_chg;
struct ux500_charger *usb_chg;
@@ -367,13 +362,13 @@ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
case AC_CHG:
timer_expiration =
round_jiffies(jiffies +
- (di->bat->main_safety_tmr_h * 3600 * HZ));
+ (di->bm->main_safety_tmr_h * 3600 * HZ));
break;
case USB_CHG:
timer_expiration =
round_jiffies(jiffies +
- (di->bat->usb_safety_tmr_h * 3600 * HZ));
+ (di->bm->usb_safety_tmr_h * 3600 * HZ));
break;
default:
@@ -450,8 +445,18 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di)
{
/* Check if charger exists and kick watchdog if charging */
if (di->ac_chg && di->ac_chg->ops.kick_wd &&
- di->chg_info.online_chg & AC_CHG)
+ di->chg_info.online_chg & AC_CHG) {
+ /*
+ * If AB charger watchdog expired, pm2xxx charging
+ * gets disabled. To be safe, kick both AB charger watchdog
+ * and pm2xxx watchdog.
+ */
+ if (di->ac_chg->external &&
+ di->usb_chg && di->usb_chg->ops.kick_wd)
+ di->usb_chg->ops.kick_wd(di->usb_chg);
+
return di->ac_chg->ops.kick_wd(di->ac_chg);
+ }
else if (di->usb_chg && di->usb_chg->ops.kick_wd &&
di->chg_info.online_chg & USB_CHG)
return di->usb_chg->ops.kick_wd(di->usb_chg);
@@ -608,6 +613,8 @@ static void abx500_chargalg_hold_charging(struct abx500_chargalg *di)
static void abx500_chargalg_start_charging(struct abx500_chargalg *di,
int vset, int iset)
{
+ bool start_chargalg_wd = true;
+
switch (di->chg_info.charger_type) {
case AC_CHG:
dev_dbg(di->dev,
@@ -625,8 +632,12 @@ static void abx500_chargalg_start_charging(struct abx500_chargalg *di,
default:
dev_err(di->dev, "Unknown charger to charge from\n");
+ start_chargalg_wd = false;
break;
}
+
+ if (start_chargalg_wd && !delayed_work_pending(&di->chargalg_wd_work))
+ queue_delayed_work(di->chargalg_wq, &di->chargalg_wd_work, 0);
}
/**
@@ -638,32 +649,32 @@ static void abx500_chargalg_start_charging(struct abx500_chargalg *di,
*/
static void abx500_chargalg_check_temp(struct abx500_chargalg *di)
{
- if (di->batt_data.temp > (di->bat->temp_low + di->t_hyst_norm) &&
- di->batt_data.temp < (di->bat->temp_high - di->t_hyst_norm)) {
+ if (di->batt_data.temp > (di->bm->temp_low + di->t_hyst_norm) &&
+ di->batt_data.temp < (di->bm->temp_high - di->t_hyst_norm)) {
/* Temp OK! */
di->events.btemp_underover = false;
di->events.btemp_lowhigh = false;
di->t_hyst_norm = 0;
di->t_hyst_lowhigh = 0;
} else {
- if (((di->batt_data.temp >= di->bat->temp_high) &&
+ if (((di->batt_data.temp >= di->bm->temp_high) &&
(di->batt_data.temp <
- (di->bat->temp_over - di->t_hyst_lowhigh))) ||
+ (di->bm->temp_over - di->t_hyst_lowhigh))) ||
((di->batt_data.temp >
- (di->bat->temp_under + di->t_hyst_lowhigh)) &&
- (di->batt_data.temp <= di->bat->temp_low))) {
+ (di->bm->temp_under + di->t_hyst_lowhigh)) &&
+ (di->batt_data.temp <= di->bm->temp_low))) {
/* TEMP minor!!!!! */
di->events.btemp_underover = false;
di->events.btemp_lowhigh = true;
- di->t_hyst_norm = di->bat->temp_hysteresis;
+ di->t_hyst_norm = di->bm->temp_hysteresis;
di->t_hyst_lowhigh = 0;
- } else if (di->batt_data.temp <= di->bat->temp_under ||
- di->batt_data.temp >= di->bat->temp_over) {
+ } else if (di->batt_data.temp <= di->bm->temp_under ||
+ di->batt_data.temp >= di->bm->temp_over) {
/* TEMP major!!!!! */
di->events.btemp_underover = true;
di->events.btemp_lowhigh = false;
di->t_hyst_norm = 0;
- di->t_hyst_lowhigh = di->bat->temp_hysteresis;
+ di->t_hyst_lowhigh = di->bm->temp_hysteresis;
} else {
/* Within hysteresis */
dev_dbg(di->dev, "Within hysteresis limit temp: %d "
@@ -682,12 +693,12 @@ static void abx500_chargalg_check_temp(struct abx500_chargalg *di)
*/
static void abx500_chargalg_check_charger_voltage(struct abx500_chargalg *di)
{
- if (di->chg_info.usb_volt > di->bat->chg_params->usb_volt_max)
+ if (di->chg_info.usb_volt > di->bm->chg_params->usb_volt_max)
di->chg_info.usb_chg_ok = false;
else
di->chg_info.usb_chg_ok = true;
- if (di->chg_info.ac_volt > di->bat->chg_params->ac_volt_max)
+ if (di->chg_info.ac_volt > di->bm->chg_params->ac_volt_max)
di->chg_info.ac_chg_ok = false;
else
di->chg_info.ac_chg_ok = true;
@@ -707,10 +718,10 @@ static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di)
if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
di->charge_state == STATE_NORMAL &&
!di->maintenance_chg && (di->batt_data.volt >=
- di->bat->bat_type[di->bat->batt_id].termination_vol ||
+ di->bm->bat_type[di->bm->batt_id].termination_vol ||
di->events.usb_cv_active || di->events.ac_cv_active) &&
di->batt_data.avg_curr <
- di->bat->bat_type[di->bat->batt_id].termination_curr &&
+ di->bm->bat_type[di->bm->batt_id].termination_curr &&
di->batt_data.avg_curr > 0) {
if (++di->eoc_cnt >= EOC_COND_CNT) {
di->eoc_cnt = 0;
@@ -733,12 +744,12 @@ static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di)
static void init_maxim_chg_curr(struct abx500_chargalg *di)
{
di->ccm.original_iset =
- di->bat->bat_type[di->bat->batt_id].normal_cur_lvl;
+ di->bm->bat_type[di->bm->batt_id].normal_cur_lvl;
di->ccm.current_iset =
- di->bat->bat_type[di->bat->batt_id].normal_cur_lvl;
- di->ccm.test_delta_i = di->bat->maxi->charger_curr_step;
- di->ccm.max_current = di->bat->maxi->chg_curr;
- di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+ di->bm->bat_type[di->bm->batt_id].normal_cur_lvl;
+ di->ccm.test_delta_i = di->bm->maxi->charger_curr_step;
+ di->ccm.max_current = di->bm->maxi->chg_curr;
+ di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
di->ccm.level = 0;
}
@@ -755,7 +766,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di)
{
int delta_i;
- if (!di->bat->maxi->ena_maxi)
+ if (!di->bm->maxi->ena_maxi)
return MAXIM_RET_NOACTION;
delta_i = di->ccm.original_iset - di->batt_data.inst_curr;
@@ -766,7 +777,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di)
if (di->ccm.wait_cnt == 0) {
dev_dbg(di->dev, "lowering current\n");
di->ccm.wait_cnt++;
- di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+ di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
di->ccm.max_current =
di->ccm.current_iset - di->ccm.test_delta_i;
di->ccm.current_iset = di->ccm.max_current;
@@ -791,7 +802,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di)
if (di->ccm.current_iset == di->ccm.original_iset)
return MAXIM_RET_NOACTION;
- di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+ di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
di->ccm.current_iset = di->ccm.original_iset;
di->ccm.level = 0;
@@ -803,7 +814,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di)
di->ccm.max_current) {
if (di->ccm.condition_cnt-- == 0) {
/* Increse the iset with cco.test_delta_i */
- di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+ di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
di->ccm.current_iset += di->ccm.test_delta_i;
di->ccm.level++;
dev_dbg(di->dev, " Maximization needed, increase"
@@ -818,7 +829,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di)
return MAXIM_RET_NOACTION;
}
} else {
- di->ccm.condition_cnt = di->bat->maxi->wait_cycles;
+ di->ccm.condition_cnt = di->bm->maxi->wait_cycles;
return MAXIM_RET_NOACTION;
}
}
@@ -838,7 +849,7 @@ static void handle_maxim_chg_curr(struct abx500_chargalg *di)
break;
case MAXIM_RET_IBAT_TOO_HIGH:
result = abx500_chargalg_update_chg_curr(di,
- di->bat->bat_type[di->bat->batt_id].normal_cur_lvl);
+ di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
if (result)
dev_err(di->dev, "failed to set chg curr\n");
break;
@@ -858,6 +869,7 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data)
union power_supply_propval ret;
int i, j;
bool psy_found = false;
+ bool capacity_updated = false;
psy = (struct power_supply *)data;
ext = dev_get_drvdata(dev);
@@ -870,6 +882,16 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data)
if (!psy_found)
return 0;
+ /*
+ * If external is not registering 'POWER_SUPPLY_PROP_CAPACITY' to its
+ * property because of handling that sysfs entry on its own, this is
+ * the place to get the battery capacity.
+ */
+ if (!ext->get_property(ext, POWER_SUPPLY_PROP_CAPACITY, &ret)) {
+ di->batt_data.percent = ret.intval;
+ capacity_updated = true;
+ }
+
/* Go through all properties for the psy */
for (j = 0; j < ext->num_properties; j++) {
enum power_supply_property prop;
@@ -1154,7 +1176,8 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data)
}
break;
case POWER_SUPPLY_PROP_CAPACITY:
- di->batt_data.percent = ret.intval;
+ if (!capacity_updated)
+ di->batt_data.percent = ret.intval;
break;
default:
break;
@@ -1210,7 +1233,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
* this way
*/
if (!charger_status ||
- (di->events.batt_unknown && !di->bat->chg_unknown_bat)) {
+ (di->events.batt_unknown && !di->bm->chg_unknown_bat)) {
if (di->charge_state != STATE_HANDHELD) {
di->events.safety_timer_expired = false;
abx500_chargalg_state_to(di, STATE_HANDHELD_INIT);
@@ -1394,8 +1417,8 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
case STATE_NORMAL_INIT:
abx500_chargalg_start_charging(di,
- di->bat->bat_type[di->bat->batt_id].normal_vol_lvl,
- di->bat->bat_type[di->bat->batt_id].normal_cur_lvl);
+ di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
+ di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
abx500_chargalg_state_to(di, STATE_NORMAL);
abx500_chargalg_start_safety_timer(di);
abx500_chargalg_stop_maintenance_timer(di);
@@ -1411,7 +1434,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
handle_maxim_chg_curr(di);
if (di->charge_status == POWER_SUPPLY_STATUS_FULL &&
di->maintenance_chg) {
- if (di->bat->no_maintenance)
+ if (di->bm->no_maintenance)
abx500_chargalg_state_to(di,
STATE_WAIT_FOR_RECHARGE_INIT);
else
@@ -1424,28 +1447,25 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
case STATE_WAIT_FOR_RECHARGE_INIT:
abx500_chargalg_hold_charging(di);
abx500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE);
- di->rch_cnt = RCH_COND_CNT;
/* Intentional fallthrough */
case STATE_WAIT_FOR_RECHARGE:
- if (di->batt_data.volt <=
- di->bat->bat_type[di->bat->batt_id].recharge_vol) {
- if (di->rch_cnt-- == 0)
- abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
- } else
- di->rch_cnt = RCH_COND_CNT;
+ if (di->batt_data.percent <=
+ di->bm->bat_type[di->bm->batt_id].
+ recharge_cap)
+ abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
break;
case STATE_MAINTENANCE_A_INIT:
abx500_chargalg_stop_safety_timer(di);
abx500_chargalg_start_maintenance_timer(di,
- di->bat->bat_type[
- di->bat->batt_id].maint_a_chg_timer_h);
+ di->bm->bat_type[
+ di->bm->batt_id].maint_a_chg_timer_h);
abx500_chargalg_start_charging(di,
- di->bat->bat_type[
- di->bat->batt_id].maint_a_vol_lvl,
- di->bat->bat_type[
- di->bat->batt_id].maint_a_cur_lvl);
+ di->bm->bat_type[
+ di->bm->batt_id].maint_a_vol_lvl,
+ di->bm->bat_type[
+ di->bm->batt_id].maint_a_cur_lvl);
abx500_chargalg_state_to(di, STATE_MAINTENANCE_A);
power_supply_changed(&di->chargalg_psy);
/* Intentional fallthrough*/
@@ -1459,13 +1479,13 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
case STATE_MAINTENANCE_B_INIT:
abx500_chargalg_start_maintenance_timer(di,
- di->bat->bat_type[
- di->bat->batt_id].maint_b_chg_timer_h);
+ di->bm->bat_type[
+ di->bm->batt_id].maint_b_chg_timer_h);
abx500_chargalg_start_charging(di,
- di->bat->bat_type[
- di->bat->batt_id].maint_b_vol_lvl,
- di->bat->bat_type[
- di->bat->batt_id].maint_b_cur_lvl);
+ di->bm->bat_type[
+ di->bm->batt_id].maint_b_vol_lvl,
+ di->bm->bat_type[
+ di->bm->batt_id].maint_b_cur_lvl);
abx500_chargalg_state_to(di, STATE_MAINTENANCE_B);
power_supply_changed(&di->chargalg_psy);
/* Intentional fallthrough*/
@@ -1479,10 +1499,10 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
case STATE_TEMP_LOWHIGH_INIT:
abx500_chargalg_start_charging(di,
- di->bat->bat_type[
- di->bat->batt_id].low_high_vol_lvl,
- di->bat->bat_type[
- di->bat->batt_id].low_high_cur_lvl);
+ di->bm->bat_type[
+ di->bm->batt_id].low_high_vol_lvl,
+ di->bm->bat_type[
+ di->bm->batt_id].low_high_cur_lvl);
abx500_chargalg_stop_maintenance_timer(di);
di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
abx500_chargalg_state_to(di, STATE_TEMP_LOWHIGH);
@@ -1543,11 +1563,11 @@ static void abx500_chargalg_periodic_work(struct work_struct *work)
if (di->chg_info.conn_chg)
queue_delayed_work(di->chargalg_wq,
&di->chargalg_periodic_work,
- di->bat->interval_charging * HZ);
+ di->bm->interval_charging * HZ);
else
queue_delayed_work(di->chargalg_wq,
&di->chargalg_periodic_work,
- di->bat->interval_not_charging * HZ);
+ di->bm->interval_not_charging * HZ);
}
/**
@@ -1614,10 +1634,13 @@ static int abx500_chargalg_get_property(struct power_supply *psy,
if (di->events.batt_ovv) {
val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
} else if (di->events.btemp_underover) {
- if (di->batt_data.temp <= di->bat->temp_under)
+ if (di->batt_data.temp <= di->bm->temp_under)
val->intval = POWER_SUPPLY_HEALTH_COLD;
else
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ } else if (di->charge_state == STATE_SAFETY_TIMER_EXPIRED ||
+ di->charge_state == STATE_SAFETY_TIMER_EXPIRED_INIT) {
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
} else {
val->intval = POWER_SUPPLY_HEALTH_GOOD;
}
@@ -1631,6 +1654,25 @@ static int abx500_chargalg_get_property(struct power_supply *psy,
/* Exposure to the sysfs interface */
/**
+ * abx500_chargalg_sysfs_show() - sysfs show operations
+ * @kobj: pointer to the struct kobject
+ * @attr: pointer to the struct attribute
+ * @buf: buffer that holds the parameter to send to userspace
+ *
+ * Returns a buffer to be displayed in user space
+ */
+static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct abx500_chargalg *di = container_of(kobj,
+ struct abx500_chargalg, chargalg_kobject);
+
+ return sprintf(buf, "%d\n",
+ di->susp_status.ac_suspended &&
+ di->susp_status.usb_suspended);
+}
+
+/**
* abx500_chargalg_sysfs_charger() - sysfs store operations
* @kobj: pointer to the struct kobject
* @attr: pointer to the struct attribute
@@ -1698,7 +1740,7 @@ static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj,
static struct attribute abx500_chargalg_en_charger = \
{
.name = "chargalg",
- .mode = S_IWUGO,
+ .mode = S_IRUGO | S_IWUSR,
};
static struct attribute *abx500_chargalg_chg[] = {
@@ -1707,6 +1749,7 @@ static struct attribute *abx500_chargalg_chg[] = {
};
static const struct sysfs_ops abx500_chargalg_sysfs_ops = {
+ .show = abx500_chargalg_sysfs_show,
.store = abx500_chargalg_sysfs_charger,
};
@@ -1806,6 +1849,7 @@ static char *supply_interface[] = {
static int abx500_chargalg_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ struct abx500_bm_data *plat = pdev->dev.platform_data;
struct abx500_chargalg *di;
int ret = 0;
@@ -1814,21 +1858,19 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__);
return -ENOMEM;
}
- di->bat = pdev->mfd_cell->platform_data;
- if (!di->bat) {
- if (np) {
- ret = bmdevs_of_probe(&pdev->dev, np, &di->bat);
- if (ret) {
- dev_err(&pdev->dev,
- "failed to get battery information\n");
- return ret;
- }
- } else {
- dev_err(&pdev->dev, "missing dt node for ab8500_chargalg\n");
- return -EINVAL;
+
+ if (!plat) {
+ dev_err(&pdev->dev, "no battery management data supplied\n");
+ return -EINVAL;
+ }
+ di->bm = plat;
+
+ if (np) {
+ ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get battery information\n");
+ return ret;
}
- } else {
- dev_info(&pdev->dev, "falling back to legacy platform data\n");
}
/* get device struct */
diff --git a/drivers/power/bq2415x_charger.c b/drivers/power/bq2415x_charger.c
index ee842b37f462..ca91396fc48e 100644
--- a/drivers/power/bq2415x_charger.c
+++ b/drivers/power/bq2415x_charger.c
@@ -28,7 +28,6 @@
* http://www.ti.com/product/bq24155
*/
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/param.h>
@@ -734,12 +733,10 @@ static int bq2415x_set_mode(struct bq2415x_device *bq, enum bq2415x_mode mode)
int charger = 0;
int boost = 0;
- if (mode == BQ2415X_MODE_HOST_CHARGER ||
- mode == BQ2415X_MODE_DEDICATED_CHARGER)
- charger = 1;
-
if (mode == BQ2415X_MODE_BOOST)
boost = 1;
+ else if (mode != BQ2415X_MODE_OFF)
+ charger = 1;
if (!charger)
ret = bq2415x_exec_command(bq, BQ2415X_CHARGER_DISABLE);
@@ -751,6 +748,10 @@ static int bq2415x_set_mode(struct bq2415x_device *bq, enum bq2415x_mode mode)
return ret;
switch (mode) {
+ case BQ2415X_MODE_OFF:
+ dev_dbg(bq->dev, "changing mode to: Offline\n");
+ ret = bq2415x_set_current_limit(bq, 100);
+ break;
case BQ2415X_MODE_NONE:
dev_dbg(bq->dev, "changing mode to: N/A\n");
ret = bq2415x_set_current_limit(bq, 100);
@@ -843,7 +844,7 @@ static void bq2415x_timer_error(struct bq2415x_device *bq, const char *msg)
dev_err(bq->dev, "%s\n", msg);
if (bq->automode > 0)
bq->automode = 0;
- bq2415x_set_mode(bq, BQ2415X_MODE_NONE);
+ bq2415x_set_mode(bq, BQ2415X_MODE_OFF);
bq2415x_set_autotimer(bq, 0);
}
@@ -1136,6 +1137,10 @@ static ssize_t bq2415x_sysfs_set_mode(struct device *dev,
return -ENOSYS;
bq->automode = 1;
mode = bq->reported_mode;
+ } else if (strncmp(buf, "off", 3) == 0) {
+ if (bq->automode > 0)
+ bq->automode = 0;
+ mode = BQ2415X_MODE_OFF;
} else if (strncmp(buf, "none", 4) == 0) {
if (bq->automode > 0)
bq->automode = 0;
@@ -1183,6 +1188,9 @@ static ssize_t bq2415x_sysfs_show_mode(struct device *dev,
ret += sprintf(buf+ret, "auto (");
switch (bq->mode) {
+ case BQ2415X_MODE_OFF:
+ ret += sprintf(buf+ret, "off");
+ break;
case BQ2415X_MODE_NONE:
ret += sprintf(buf+ret, "none");
break;
@@ -1217,6 +1225,8 @@ static ssize_t bq2415x_sysfs_show_reported_mode(struct device *dev,
return -EINVAL;
switch (bq->reported_mode) {
+ case BQ2415X_MODE_OFF:
+ return sprintf(buf, "off\n");
case BQ2415X_MODE_NONE:
return sprintf(buf, "none\n");
case BQ2415X_MODE_HOST_CHARGER:
@@ -1523,7 +1533,7 @@ static int bq2415x_probe(struct i2c_client *client,
goto error_1;
}
- bq = kzalloc(sizeof(*bq), GFP_KERNEL);
+ bq = devm_kzalloc(&client->dev, sizeof(*bq), GFP_KERNEL);
if (!bq) {
dev_err(&client->dev, "failed to allocate device data\n");
ret = -ENOMEM;
@@ -1536,8 +1546,8 @@ static int bq2415x_probe(struct i2c_client *client,
bq->dev = &client->dev;
bq->chip = id->driver_data;
bq->name = name;
- bq->mode = BQ2415X_MODE_NONE;
- bq->reported_mode = BQ2415X_MODE_NONE;
+ bq->mode = BQ2415X_MODE_OFF;
+ bq->reported_mode = BQ2415X_MODE_OFF;
bq->autotimer = 0;
bq->automode = 0;
@@ -1549,19 +1559,19 @@ static int bq2415x_probe(struct i2c_client *client,
ret = bq2415x_power_supply_init(bq);
if (ret) {
dev_err(bq->dev, "failed to register power supply: %d\n", ret);
- goto error_3;
+ goto error_2;
}
ret = bq2415x_sysfs_init(bq);
if (ret) {
dev_err(bq->dev, "failed to create sysfs entries: %d\n", ret);
- goto error_4;
+ goto error_3;
}
ret = bq2415x_set_defaults(bq);
if (ret) {
dev_err(bq->dev, "failed to set default values: %d\n", ret);
- goto error_5;
+ goto error_4;
}
if (bq->init_data.set_mode_hook) {
@@ -1585,12 +1595,10 @@ static int bq2415x_probe(struct i2c_client *client,
dev_info(bq->dev, "driver registered\n");
return 0;
-error_5:
- bq2415x_sysfs_exit(bq);
error_4:
- bq2415x_power_supply_exit(bq);
+ bq2415x_sysfs_exit(bq);
error_3:
- kfree(bq);
+ bq2415x_power_supply_exit(bq);
error_2:
kfree(name);
error_1:
@@ -1622,7 +1630,6 @@ static int bq2415x_remove(struct i2c_client *client)
dev_info(bq->dev, "driver unregistered\n");
kfree(bq->name);
- kfree(bq);
return 0;
}
@@ -1652,18 +1659,7 @@ static struct i2c_driver bq2415x_driver = {
.remove = bq2415x_remove,
.id_table = bq2415x_i2c_id_table,
};
-
-static int __init bq2415x_init(void)
-{
- return i2c_add_driver(&bq2415x_driver);
-}
-module_init(bq2415x_init);
-
-static void __exit bq2415x_exit(void)
-{
- i2c_del_driver(&bq2415x_driver);
-}
-module_exit(bq2415x_exit);
+module_i2c_driver(bq2415x_driver);
MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
MODULE_DESCRIPTION("bq2415x charger driver");
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 36b34efdafc9..8ccf5d7d0add 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -299,7 +299,7 @@ static int bq27x00_battery_read_energy(struct bq27x00_device_info *di)
}
/*
- * Return the battery temperature in tenths of degree Celsius
+ * Return the battery temperature in tenths of degree Kelvin
* Or < 0 if something fails.
*/
static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di)
@@ -312,10 +312,8 @@ static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di)
return temp;
}
- if (bq27xxx_is_chip_version_higher(di))
- temp -= 2731;
- else
- temp = ((temp * 5) - 5463) / 2;
+ if (!bq27xxx_is_chip_version_higher(di))
+ temp = 5 * temp / 2;
return temp;
}
@@ -448,7 +446,6 @@ static void bq27x00_update(struct bq27x00_device_info *di)
cache.temperature = bq27x00_battery_read_temperature(di);
if (!is_bq27425)
cache.cycle_count = bq27x00_battery_read_cyct(di);
- cache.cycle_count = bq27x00_battery_read_cyct(di);
cache.power_avg =
bq27x00_battery_read_pwr_avg(di, BQ27x00_POWER_AVG);
@@ -642,6 +639,8 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_TEMP:
ret = bq27x00_simple_value(di->cache.temperature, val);
+ if (ret == 0)
+ val->intval -= 2731;
break;
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
ret = bq27x00_simple_value(di->cache.time_to_empty, val);
@@ -696,7 +695,6 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
int ret;
di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
- di->chip = BQ27425;
if (di->chip == BQ27425) {
di->bat.properties = bq27425_battery_props;
di->bat.num_properties = ARRAY_SIZE(bq27425_battery_props);
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 6ba047f5ac2c..8acc3f8d303c 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -669,15 +669,21 @@ static void _setup_polling(struct work_struct *work)
WARN(cm_wq == NULL, "charger-manager: workqueue not initialized"
". try it later. %s\n", __func__);
+ /*
+ * Use mod_delayed_work() iff the next polling interval should
+ * occur before the currently scheduled one. If @cm_monitor_work
+ * isn't active, the end result is the same, so no need to worry
+ * about stale @next_polling.
+ */
_next_polling = jiffies + polling_jiffy;
- if (!delayed_work_pending(&cm_monitor_work) ||
- (delayed_work_pending(&cm_monitor_work) &&
- time_after(next_polling, _next_polling))) {
- next_polling = jiffies + polling_jiffy;
+ if (time_before(_next_polling, next_polling)) {
mod_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy);
+ next_polling = _next_polling;
+ } else {
+ if (queue_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy))
+ next_polling = _next_polling;
}
-
out:
mutex_unlock(&cm_list_mtx);
}
@@ -751,8 +757,7 @@ static void misc_event_handler(struct charger_manager *cm,
if (cm_suspended)
device_set_wakeup_capable(cm->dev, true);
- if (!delayed_work_pending(&cm_monitor_work) &&
- is_polling_required(cm) && cm->desc->polling_interval_ms)
+ if (is_polling_required(cm) && cm->desc->polling_interval_ms)
schedule_work(&setup_polling);
uevent_notify(cm, default_event_names[type]);
}
@@ -1170,8 +1175,7 @@ static int charger_extcon_notifier(struct notifier_block *self,
* when charger cable is attached.
*/
if (cable->attached && is_polling_required(cable->cm)) {
- if (work_pending(&setup_polling))
- cancel_work_sync(&setup_polling);
+ cancel_work_sync(&setup_polling);
schedule_work(&setup_polling);
}
@@ -1215,6 +1219,55 @@ static int charger_extcon_init(struct charger_manager *cm,
return ret;
}
+/**
+ * charger_manager_register_extcon - Register extcon device to recevie state
+ * of charger cable.
+ * @cm: the Charger Manager representing the battery.
+ *
+ * This function support EXTCON(External Connector) subsystem to detect the
+ * state of charger cables for enabling or disabling charger(regulator) and
+ * select the charger cable for charging among a number of external cable
+ * according to policy of H/W board.
+ */
+static int charger_manager_register_extcon(struct charger_manager *cm)
+{
+ struct charger_desc *desc = cm->desc;
+ struct charger_regulator *charger;
+ int ret = 0;
+ int i;
+ int j;
+
+ for (i = 0; i < desc->num_charger_regulators; i++) {
+ charger = &desc->charger_regulators[i];
+
+ charger->consumer = regulator_get(cm->dev,
+ charger->regulator_name);
+ if (charger->consumer == NULL) {
+ dev_err(cm->dev, "Cannot find charger(%s)n",
+ charger->regulator_name);
+ ret = -EINVAL;
+ goto err;
+ }
+ charger->cm = cm;
+
+ for (j = 0; j < charger->num_cables; j++) {
+ struct charger_cable *cable = &charger->cables[j];
+
+ ret = charger_extcon_init(cm, cable);
+ if (ret < 0) {
+ dev_err(cm->dev, "Cannot initialize charger(%s)n",
+ charger->regulator_name);
+ goto err;
+ }
+ cable->charger = charger;
+ cable->cm = cm;
+ }
+ }
+
+err:
+ return ret;
+}
+
/* help function of sysfs node to control charger(regulator) */
static ssize_t charger_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1274,7 +1327,7 @@ static ssize_t charger_externally_control_store(struct device *dev,
for (i = 0; i < desc->num_charger_regulators; i++) {
if (&desc->charger_regulators[i] != charger &&
- !desc->charger_regulators[i].externally_control) {
+ !desc->charger_regulators[i].externally_control) {
/*
* At least, one charger is controlled by
* charger-manager
@@ -1303,13 +1356,107 @@ static ssize_t charger_externally_control_store(struct device *dev,
return count;
}
+/**
+ * charger_manager_register_sysfs - Register sysfs entry for each charger
+ * @cm: the Charger Manager representing the battery.
+ *
+ * This function add sysfs entry for charger(regulator) to control charger from
+ * user-space. If some development board use one more chargers for charging
+ * but only need one charger on specific case which is dependent on user
+ * scenario or hardware restrictions, the user enter 1 or 0(zero) to '/sys/
+ * class/power_supply/battery/charger.[index]/externally_control'. For example,
+ * if user enter 1 to 'sys/class/power_supply/battery/charger.[index]/
+ * externally_control, this charger isn't controlled from charger-manager and
+ * always stay off state of regulator.
+ */
+static int charger_manager_register_sysfs(struct charger_manager *cm)
+{
+ struct charger_desc *desc = cm->desc;
+ struct charger_regulator *charger;
+ int chargers_externally_control = 1;
+ char buf[11];
+ char *str;
+ int ret = 0;
+ int i;
+
+ /* Create sysfs entry to control charger(regulator) */
+ for (i = 0; i < desc->num_charger_regulators; i++) {
+ charger = &desc->charger_regulators[i];
+
+ snprintf(buf, 10, "charger.%d", i);
+ str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL);
+ if (!str) {
+ dev_err(cm->dev, "Cannot allocate memory: %s\n",
+ charger->regulator_name);
+ ret = -ENOMEM;
+ goto err;
+ }
+ strcpy(str, buf);
+
+ charger->attrs[0] = &charger->attr_name.attr;
+ charger->attrs[1] = &charger->attr_state.attr;
+ charger->attrs[2] = &charger->attr_externally_control.attr;
+ charger->attrs[3] = NULL;
+ charger->attr_g.name = str;
+ charger->attr_g.attrs = charger->attrs;
+
+ sysfs_attr_init(&charger->attr_name.attr);
+ charger->attr_name.attr.name = "name";
+ charger->attr_name.attr.mode = 0444;
+ charger->attr_name.show = charger_name_show;
+
+ sysfs_attr_init(&charger->attr_state.attr);
+ charger->attr_state.attr.name = "state";
+ charger->attr_state.attr.mode = 0444;
+ charger->attr_state.show = charger_state_show;
+
+ sysfs_attr_init(&charger->attr_externally_control.attr);
+ charger->attr_externally_control.attr.name
+ = "externally_control";
+ charger->attr_externally_control.attr.mode = 0644;
+ charger->attr_externally_control.show
+ = charger_externally_control_show;
+ charger->attr_externally_control.store
+ = charger_externally_control_store;
+
+ if (!desc->charger_regulators[i].externally_control ||
+ !chargers_externally_control)
+ chargers_externally_control = 0;
+
+ dev_info(cm->dev, "'%s' regulator's externally_control"
+ "is %d\n", charger->regulator_name,
+ charger->externally_control);
+
+ ret = sysfs_create_group(&cm->charger_psy.dev->kobj,
+ &charger->attr_g);
+ if (ret < 0) {
+ dev_err(cm->dev, "Cannot create sysfs entry"
+ "of %s regulator\n",
+ charger->regulator_name);
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ if (chargers_externally_control) {
+ dev_err(cm->dev, "Cannot register regulator because "
+ "charger-manager must need at least "
+ "one charger for charging battery\n");
+
+ ret = -EINVAL;
+ goto err;
+ }
+
+err:
+ return ret;
+}
+
static int charger_manager_probe(struct platform_device *pdev)
{
struct charger_desc *desc = dev_get_platdata(&pdev->dev);
struct charger_manager *cm;
int ret = 0, i = 0;
int j = 0;
- int chargers_externally_control = 1;
union power_supply_propval val;
if (g_desc && !rtc_dev && g_desc->rtc_name) {
@@ -1440,11 +1587,10 @@ static int charger_manager_probe(struct platform_device *pdev)
memcpy(&cm->charger_psy, &psy_default, sizeof(psy_default));
- if (!desc->psy_name) {
+ if (!desc->psy_name)
strncpy(cm->psy_name_buf, psy_default.name, PSY_NAME_MAX);
- } else {
+ else
strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX);
- }
cm->charger_psy.name = cm->psy_name_buf;
/* Allocate for psy properties because they may vary */
@@ -1496,105 +1642,19 @@ static int charger_manager_probe(struct platform_device *pdev)
goto err_register;
}
- for (i = 0 ; i < desc->num_charger_regulators ; i++) {
- struct charger_regulator *charger
- = &desc->charger_regulators[i];
- char buf[11];
- char *str;
-
- charger->consumer = regulator_get(&pdev->dev,
- charger->regulator_name);
- if (charger->consumer == NULL) {
- dev_err(&pdev->dev, "Cannot find charger(%s)n",
- charger->regulator_name);
- ret = -EINVAL;
- goto err_chg_get;
- }
- charger->cm = cm;
-
- for (j = 0 ; j < charger->num_cables ; j++) {
- struct charger_cable *cable = &charger->cables[j];
-
- ret = charger_extcon_init(cm, cable);
- if (ret < 0) {
- dev_err(&pdev->dev, "Cannot find charger(%s)n",
- charger->regulator_name);
- goto err_extcon;
- }
- cable->charger = charger;
- cable->cm = cm;
- }
-
- /* Create sysfs entry to control charger(regulator) */
- snprintf(buf, 10, "charger.%d", i);
- str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL);
- if (!str) {
- for (i--; i >= 0; i--) {
- charger = &desc->charger_regulators[i];
- kfree(charger->attr_g.name);
- }
- ret = -ENOMEM;
-
- goto err_extcon;
- }
- strcpy(str, buf);
-
- charger->attrs[0] = &charger->attr_name.attr;
- charger->attrs[1] = &charger->attr_state.attr;
- charger->attrs[2] = &charger->attr_externally_control.attr;
- charger->attrs[3] = NULL;
- charger->attr_g.name = str;
- charger->attr_g.attrs = charger->attrs;
-
- sysfs_attr_init(&charger->attr_name.attr);
- charger->attr_name.attr.name = "name";
- charger->attr_name.attr.mode = 0444;
- charger->attr_name.show = charger_name_show;
-
- sysfs_attr_init(&charger->attr_state.attr);
- charger->attr_state.attr.name = "state";
- charger->attr_state.attr.mode = 0444;
- charger->attr_state.show = charger_state_show;
-
- sysfs_attr_init(&charger->attr_externally_control.attr);
- charger->attr_externally_control.attr.name
- = "externally_control";
- charger->attr_externally_control.attr.mode = 0644;
- charger->attr_externally_control.show
- = charger_externally_control_show;
- charger->attr_externally_control.store
- = charger_externally_control_store;
-
- if (!desc->charger_regulators[i].externally_control ||
- !chargers_externally_control) {
- chargers_externally_control = 0;
- }
- dev_info(&pdev->dev, "'%s' regulator's externally_control"
- "is %d\n", charger->regulator_name,
- charger->externally_control);
-
- ret = sysfs_create_group(&cm->charger_psy.dev->kobj,
- &charger->attr_g);
- if (ret < 0) {
- dev_info(&pdev->dev, "Cannot create sysfs entry"
- "of %s regulator\n",
- charger->regulator_name);
- }
- }
-
- if (chargers_externally_control) {
- dev_err(&pdev->dev, "Cannot register regulator because "
- "charger-manager must need at least "
- "one charger for charging battery\n");
-
- ret = -EINVAL;
- goto err_chg_enable;
+ /* Register extcon device for charger cable */
+ ret = charger_manager_register_extcon(cm);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Cannot initialize extcon device\n");
+ goto err_reg_extcon;
}
- ret = try_charger_enable(cm, true);
- if (ret) {
- dev_err(&pdev->dev, "Cannot enable charger regulators\n");
- goto err_chg_enable;
+ /* Register sysfs entry for charger(regulator) */
+ ret = charger_manager_register_sysfs(cm);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Cannot initialize sysfs entry of regulator\n");
+ goto err_reg_sysfs;
}
/* Add to the list */
@@ -1613,27 +1673,28 @@ static int charger_manager_probe(struct platform_device *pdev)
return 0;
-err_chg_enable:
+err_reg_sysfs:
for (i = 0; i < desc->num_charger_regulators; i++) {
struct charger_regulator *charger;
charger = &desc->charger_regulators[i];
sysfs_remove_group(&cm->charger_psy.dev->kobj,
&charger->attr_g);
+
kfree(charger->attr_g.name);
}
-err_extcon:
- for (i = 0 ; i < desc->num_charger_regulators ; i++) {
- struct charger_regulator *charger
- = &desc->charger_regulators[i];
- for (j = 0 ; j < charger->num_cables ; j++) {
+err_reg_extcon:
+ for (i = 0; i < desc->num_charger_regulators; i++) {
+ struct charger_regulator *charger;
+
+ charger = &desc->charger_regulators[i];
+ for (j = 0; j < charger->num_cables; j++) {
struct charger_cable *cable = &charger->cables[j];
extcon_unregister_interest(&cable->extcon_dev);
}
- }
-err_chg_get:
- for (i = 0 ; i < desc->num_charger_regulators ; i++)
+
regulator_put(desc->charger_regulators[i].consumer);
+ }
power_supply_unregister(&cm->charger_psy);
err_register:
@@ -1661,10 +1722,8 @@ static int charger_manager_remove(struct platform_device *pdev)
list_del(&cm->entry);
mutex_unlock(&cm_list_mtx);
- if (work_pending(&setup_polling))
- cancel_work_sync(&setup_polling);
- if (delayed_work_pending(&cm_monitor_work))
- cancel_delayed_work_sync(&cm_monitor_work);
+ cancel_work_sync(&setup_polling);
+ cancel_delayed_work_sync(&cm_monitor_work);
for (i = 0 ; i < desc->num_charger_regulators ; i++) {
struct charger_regulator *charger
@@ -1733,8 +1792,7 @@ static int cm_suspend_prepare(struct device *dev)
cm_suspended = true;
}
- if (delayed_work_pending(&cm->fullbatt_vchk_work))
- cancel_delayed_work(&cm->fullbatt_vchk_work);
+ cancel_delayed_work(&cm->fullbatt_vchk_work);
cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm);
cm->status_save_batt = is_batt_present(cm);
diff --git a/drivers/power/da9030_battery.c b/drivers/power/da9030_battery.c
index 94762e67e22b..e8c5a391a498 100644
--- a/drivers/power/da9030_battery.c
+++ b/drivers/power/da9030_battery.c
@@ -22,6 +22,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/notifier.h>
#define DA9030_FAULT_LOG 0x0a
#define DA9030_FAULT_LOG_OVER_TEMP (1 << 7)
diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c
index 3c5c2e459d73..08193feb3b08 100644
--- a/drivers/power/da9052-battery.c
+++ b/drivers/power/da9052-battery.c
@@ -337,7 +337,7 @@ static unsigned char da9052_determine_vc_tbl_index(unsigned char adc_temp)
if (adc_temp > vc_tbl_ref[DA9052_VC_TBL_REF_SZ - 1])
return DA9052_VC_TBL_REF_SZ - 1;
- for (i = 0; i < DA9052_VC_TBL_REF_SZ; i++) {
+ for (i = 0; i < DA9052_VC_TBL_REF_SZ - 1; i++) {
if ((adc_temp > vc_tbl_ref[i]) &&
(adc_temp <= DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1])))
return i;
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c
index 2fa9b6bf1f3f..e7301b3ed623 100644
--- a/drivers/power/ds2782_battery.c
+++ b/drivers/power/ds2782_battery.c
@@ -7,6 +7,8 @@
*
* DS2786 added by Yulia Vilensky <vilensky@compulab.co.il>
*
+ * UEvent sending added by Evgeny Romanov <romanov@neurosoft.ru>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -19,6 +21,7 @@
#include <linux/errno.h>
#include <linux/swab.h>
#include <linux/i2c.h>
+#include <linux/delay.h>
#include <linux/idr.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
@@ -40,6 +43,8 @@
#define DS2786_CURRENT_UNITS 25
+#define DS278x_DELAY 1000
+
struct ds278x_info;
struct ds278x_battery_ops {
@@ -54,8 +59,11 @@ struct ds278x_info {
struct i2c_client *client;
struct power_supply battery;
struct ds278x_battery_ops *ops;
+ struct delayed_work bat_work;
int id;
int rsns;
+ int capacity;
+ int status; /* State Of Charge */
};
static DEFINE_IDR(battery_id);
@@ -220,6 +228,8 @@ static int ds278x_get_status(struct ds278x_info *info, int *status)
if (err)
return err;
+ info->capacity = capacity;
+
if (capacity == 100)
*status = POWER_SUPPLY_STATUS_FULL;
else if (current_uA == 0)
@@ -267,6 +277,27 @@ static int ds278x_battery_get_property(struct power_supply *psy,
return ret;
}
+static void ds278x_bat_update(struct ds278x_info *info)
+{
+ int old_status = info->status;
+ int old_capacity = info->capacity;
+
+ ds278x_get_status(info, &info->status);
+
+ if ((old_status != info->status) || (old_capacity != info->capacity))
+ power_supply_changed(&info->battery);
+}
+
+static void ds278x_bat_work(struct work_struct *work)
+{
+ struct ds278x_info *info;
+
+ info = container_of(work, struct ds278x_info, bat_work.work);
+ ds278x_bat_update(info);
+
+ schedule_delayed_work(&info->bat_work, DS278x_DELAY);
+}
+
static enum power_supply_property ds278x_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CAPACITY,
@@ -295,10 +326,39 @@ static int ds278x_battery_remove(struct i2c_client *client)
idr_remove(&battery_id, info->id);
mutex_unlock(&battery_lock);
+ cancel_delayed_work(&info->bat_work);
+
kfree(info);
return 0;
}
+#ifdef CONFIG_PM
+
+static int ds278x_suspend(struct i2c_client *client,
+ pm_message_t state)
+{
+ struct ds278x_info *info = i2c_get_clientdata(client);
+
+ cancel_delayed_work(&info->bat_work);
+ return 0;
+}
+
+static int ds278x_resume(struct i2c_client *client)
+{
+ struct ds278x_info *info = i2c_get_clientdata(client);
+
+ schedule_delayed_work(&info->bat_work, DS278x_DELAY);
+ return 0;
+}
+
+#else
+
+#define ds278x_suspend NULL
+#define ds278x_resume NULL
+
+#endif /* CONFIG_PM */
+
+
enum ds278x_num_id {
DS2782 = 0,
DS2786,
@@ -368,10 +428,17 @@ static int ds278x_battery_probe(struct i2c_client *client,
info->ops = &ds278x_ops[id->driver_data];
ds278x_power_supply_init(&info->battery);
+ info->capacity = 100;
+ info->status = POWER_SUPPLY_STATUS_FULL;
+
+ INIT_DELAYED_WORK(&info->bat_work, ds278x_bat_work);
+
ret = power_supply_register(&client->dev, &info->battery);
if (ret) {
dev_err(&client->dev, "failed to register battery\n");
goto fail_register;
+ } else {
+ schedule_delayed_work(&info->bat_work, DS278x_DELAY);
}
return 0;
@@ -401,6 +468,8 @@ static struct i2c_driver ds278x_battery_driver = {
},
.probe = ds278x_battery_probe,
.remove = ds278x_battery_remove,
+ .suspend = ds278x_suspend,
+ .resume = ds278x_resume,
.id_table = ds278x_id,
};
module_i2c_driver(ds278x_battery_driver);
diff --git a/drivers/power/generic-adc-battery.c b/drivers/power/generic-adc-battery.c
index 32ce17e235c0..8cb5d7f67ace 100644
--- a/drivers/power/generic-adc-battery.c
+++ b/drivers/power/generic-adc-battery.c
@@ -263,9 +263,6 @@ static int gab_probe(struct platform_device *pdev)
psy->external_power_changed = gab_ext_power_changed;
adc_bat->pdata = pdata;
- /* calculate the total number of channels */
- chan = ARRAY_SIZE(gab_chan_name);
-
/*
* copying the static properties and allocating extra memory for holding
* the extra configurable properties received from platform data.
@@ -287,10 +284,11 @@ static int gab_probe(struct platform_device *pdev)
* based on the channel supported by consumer device.
*/
for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
- adc_bat->channel[chan] = iio_channel_get(dev_name(&pdev->dev),
- gab_chan_name[chan]);
+ adc_bat->channel[chan] = iio_channel_get(&pdev->dev,
+ gab_chan_name[chan]);
if (IS_ERR(adc_bat->channel[chan])) {
ret = PTR_ERR(adc_bat->channel[chan]);
+ adc_bat->channel[chan] = NULL;
} else {
/* copying properties for supported channels only */
memcpy(properties + sizeof(*(psy->properties)) * index,
@@ -344,8 +342,10 @@ err_gpio:
gpio_req_fail:
power_supply_unregister(psy);
err_reg_fail:
- for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++)
- iio_channel_release(adc_bat->channel[chan]);
+ for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
+ if (adc_bat->channel[chan])
+ iio_channel_release(adc_bat->channel[chan]);
+ }
second_mem_fail:
kfree(psy->properties);
first_mem_fail:
@@ -365,8 +365,10 @@ static int gab_remove(struct platform_device *pdev)
gpio_free(pdata->gpio_charge_finished);
}
- for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++)
- iio_channel_release(adc_bat->channel[chan]);
+ for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) {
+ if (adc_bat->channel[chan])
+ iio_channel_release(adc_bat->channel[chan]);
+ }
kfree(adc_bat->psy.properties);
cancel_delayed_work(&adc_bat->bat_work);
diff --git a/drivers/power/goldfish_battery.c b/drivers/power/goldfish_battery.c
new file mode 100644
index 000000000000..c10f460f986f
--- /dev/null
+++ b/drivers/power/goldfish_battery.c
@@ -0,0 +1,236 @@
+/*
+ * Power supply driver for the goldfish emulator
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2012 Intel, Inc.
+ * Copyright (C) 2013 Intel, Inc.
+ * Author: Mike Lockwood <lockwood@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/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+struct goldfish_battery_data {
+ void __iomem *reg_base;
+ int irq;
+ spinlock_t lock;
+
+ struct power_supply battery;
+ struct power_supply ac;
+};
+
+#define GOLDFISH_BATTERY_READ(data, addr) \
+ (readl(data->reg_base + addr))
+#define GOLDFISH_BATTERY_WRITE(data, addr, x) \
+ (writel(x, data->reg_base + addr))
+
+/*
+ * Temporary variable used between goldfish_battery_probe() and
+ * goldfish_battery_open().
+ */
+static struct goldfish_battery_data *battery_data;
+
+enum {
+ /* status register */
+ BATTERY_INT_STATUS = 0x00,
+ /* set this to enable IRQ */
+ BATTERY_INT_ENABLE = 0x04,
+
+ BATTERY_AC_ONLINE = 0x08,
+ BATTERY_STATUS = 0x0C,
+ BATTERY_HEALTH = 0x10,
+ BATTERY_PRESENT = 0x14,
+ BATTERY_CAPACITY = 0x18,
+
+ BATTERY_STATUS_CHANGED = 1U << 0,
+ AC_STATUS_CHANGED = 1U << 1,
+ BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
+};
+
+
+static int goldfish_ac_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct goldfish_battery_data *data = container_of(psy,
+ struct goldfish_battery_data, ac);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_AC_ONLINE);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int goldfish_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct goldfish_battery_data *data = container_of(psy,
+ struct goldfish_battery_data, battery);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_STATUS);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_HEALTH);
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_PRESENT);
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static enum power_supply_property goldfish_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static enum power_supply_property goldfish_ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static irqreturn_t goldfish_battery_interrupt(int irq, void *dev_id)
+{
+ unsigned long irq_flags;
+ struct goldfish_battery_data *data = dev_id;
+ uint32_t status;
+
+ spin_lock_irqsave(&data->lock, irq_flags);
+
+ /* read status flags, which will clear the interrupt */
+ status = GOLDFISH_BATTERY_READ(data, BATTERY_INT_STATUS);
+ status &= BATTERY_INT_MASK;
+
+ if (status & BATTERY_STATUS_CHANGED)
+ power_supply_changed(&data->battery);
+ if (status & AC_STATUS_CHANGED)
+ power_supply_changed(&data->ac);
+
+ spin_unlock_irqrestore(&data->lock, irq_flags);
+ return status ? IRQ_HANDLED : IRQ_NONE;
+}
+
+
+static int goldfish_battery_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *r;
+ struct goldfish_battery_data *data;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&data->lock);
+
+ data->battery.properties = goldfish_battery_props;
+ data->battery.num_properties = ARRAY_SIZE(goldfish_battery_props);
+ data->battery.get_property = goldfish_battery_get_property;
+ data->battery.name = "battery";
+ data->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+
+ data->ac.properties = goldfish_ac_props;
+ data->ac.num_properties = ARRAY_SIZE(goldfish_ac_props);
+ data->ac.get_property = goldfish_ac_get_property;
+ data->ac.name = "ac";
+ data->ac.type = POWER_SUPPLY_TYPE_MAINS;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ dev_err(&pdev->dev, "platform_get_resource failed\n");
+ return -ENODEV;
+ }
+
+ data->reg_base = devm_ioremap(&pdev->dev, r->start, r->end - r->start + 1);
+ if (data->reg_base == NULL) {
+ dev_err(&pdev->dev, "unable to remap MMIO\n");
+ return -ENOMEM;
+ }
+
+ data->irq = platform_get_irq(pdev, 0);
+ if (data->irq < 0) {
+ dev_err(&pdev->dev, "platform_get_irq failed\n");
+ return -ENODEV;
+ }
+
+ ret = devm_request_irq(&pdev->dev, data->irq, goldfish_battery_interrupt,
+ IRQF_SHARED, pdev->name, data);
+ if (ret)
+ return ret;
+
+ ret = power_supply_register(&pdev->dev, &data->ac);
+ if (ret)
+ return ret;
+
+ ret = power_supply_register(&pdev->dev, &data->battery);
+ if (ret) {
+ power_supply_unregister(&data->ac);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, data);
+ battery_data = data;
+
+ GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);
+ return 0;
+}
+
+static int goldfish_battery_remove(struct platform_device *pdev)
+{
+ struct goldfish_battery_data *data = platform_get_drvdata(pdev);
+
+ power_supply_unregister(&data->battery);
+ power_supply_unregister(&data->ac);
+ battery_data = NULL;
+ return 0;
+}
+
+static struct platform_driver goldfish_battery_device = {
+ .probe = goldfish_battery_probe,
+ .remove = goldfish_battery_remove,
+ .driver = {
+ .name = "goldfish-battery"
+ }
+};
+module_platform_driver(goldfish_battery_device);
+
+MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c
index bf914893c6fd..c675553d4647 100644
--- a/drivers/power/jz4740-battery.c
+++ b/drivers/power/jz4740-battery.c
@@ -22,6 +22,7 @@
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/mfd/core.h>
#include <linux/power_supply.h>
@@ -266,9 +267,9 @@ static int jz_battery_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- jz_battery->base = devm_request_and_ioremap(&pdev->dev, mem);
- if (!jz_battery->base)
- return -EBUSY;
+ jz_battery->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(jz_battery->base))
+ return PTR_ERR(jz_battery->base);
battery = &jz_battery->battery;
battery->name = pdata->info.name;
diff --git a/drivers/power/lp8727_charger.c b/drivers/power/lp8727_charger.c
index 4ee71a90e248..5ef41b819172 100644
--- a/drivers/power/lp8727_charger.c
+++ b/drivers/power/lp8727_charger.c
@@ -367,28 +367,28 @@ static int lp8727_battery_get_property(struct power_supply *psy,
return -EINVAL;
if (pdata->get_batt_present)
- val->intval = pchg->pdata->get_batt_present();
+ val->intval = pdata->get_batt_present();
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
if (!pdata)
return -EINVAL;
if (pdata->get_batt_level)
- val->intval = pchg->pdata->get_batt_level();
+ val->intval = pdata->get_batt_level();
break;
case POWER_SUPPLY_PROP_CAPACITY:
if (!pdata)
return -EINVAL;
if (pdata->get_batt_capacity)
- val->intval = pchg->pdata->get_batt_capacity();
+ val->intval = pdata->get_batt_capacity();
break;
case POWER_SUPPLY_PROP_TEMP:
if (!pdata)
return -EINVAL;
if (pdata->get_batt_temp)
- val->intval = pchg->pdata->get_batt_temp();
+ val->intval = pdata->get_batt_temp();
break;
default:
break;
diff --git a/drivers/power/lp8788-charger.c b/drivers/power/lp8788-charger.c
index 22b6407c9ca9..6d1f452810b8 100644
--- a/drivers/power/lp8788-charger.c
+++ b/drivers/power/lp8788-charger.c
@@ -367,7 +367,8 @@ static inline bool lp8788_is_valid_charger_register(u8 addr)
return addr >= LP8788_CHG_START && addr <= LP8788_CHG_END;
}
-static int lp8788_update_charger_params(struct lp8788_charger *pchg)
+static int lp8788_update_charger_params(struct platform_device *pdev,
+ struct lp8788_charger *pchg)
{
struct lp8788 *lp = pchg->lp;
struct lp8788_charger_platform_data *pdata = pchg->pdata;
@@ -376,7 +377,7 @@ static int lp8788_update_charger_params(struct lp8788_charger *pchg)
int ret;
if (!pdata || !pdata->chg_params) {
- dev_info(lp->dev, "skip updating charger parameters\n");
+ dev_info(&pdev->dev, "skip updating charger parameters\n");
return 0;
}
@@ -537,7 +538,6 @@ err_free_irq:
static int lp8788_irq_register(struct platform_device *pdev,
struct lp8788_charger *pchg)
{
- struct lp8788 *lp = pchg->lp;
const char *name[] = {
LP8788_CHG_IRQ, LP8788_PRSW_IRQ, LP8788_BATT_IRQ
};
@@ -550,13 +550,13 @@ static int lp8788_irq_register(struct platform_device *pdev,
for (i = 0; i < ARRAY_SIZE(name); i++) {
ret = lp8788_set_irqs(pdev, pchg, name[i]);
if (ret) {
- dev_warn(lp->dev, "irq setup failed: %s\n", name[i]);
+ dev_warn(&pdev->dev, "irq setup failed: %s\n", name[i]);
return ret;
}
}
if (pchg->num_irqs > LP8788_MAX_CHG_IRQS) {
- dev_err(lp->dev, "invalid total number of irqs: %d\n",
+ dev_err(&pdev->dev, "invalid total number of irqs: %d\n",
pchg->num_irqs);
return -EINVAL;
}
@@ -580,7 +580,7 @@ static void lp8788_irq_unregister(struct platform_device *pdev,
}
}
-static void lp8788_setup_adc_channel(const char *consumer_name,
+static void lp8788_setup_adc_channel(struct device *dev,
struct lp8788_charger *pchg)
{
struct lp8788_charger_platform_data *pdata = pchg->pdata;
@@ -590,11 +590,11 @@ static void lp8788_setup_adc_channel(const char *consumer_name,
return;
/* ADC channel for battery voltage */
- chan = iio_channel_get(consumer_name, pdata->adc_vbatt);
+ chan = iio_channel_get(dev, pdata->adc_vbatt);
pchg->chan[LP8788_VBATT] = IS_ERR(chan) ? NULL : chan;
/* ADC channel for battery temperature */
- chan = iio_channel_get(consumer_name, pdata->adc_batt_temp);
+ chan = iio_channel_get(dev, pdata->adc_batt_temp);
pchg->chan[LP8788_BATT_TEMP] = IS_ERR(chan) ? NULL : chan;
}
@@ -690,9 +690,10 @@ static int lp8788_charger_probe(struct platform_device *pdev)
{
struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
struct lp8788_charger *pchg;
+ struct device *dev = &pdev->dev;
int ret;
- pchg = devm_kzalloc(lp->dev, sizeof(struct lp8788_charger), GFP_KERNEL);
+ pchg = devm_kzalloc(dev, sizeof(struct lp8788_charger), GFP_KERNEL);
if (!pchg)
return -ENOMEM;
@@ -700,11 +701,11 @@ static int lp8788_charger_probe(struct platform_device *pdev)
pchg->pdata = lp->pdata ? lp->pdata->chg_pdata : NULL;
platform_set_drvdata(pdev, pchg);
- ret = lp8788_update_charger_params(pchg);
+ ret = lp8788_update_charger_params(pdev, pchg);
if (ret)
return ret;
- lp8788_setup_adc_channel(pdev->name, pchg);
+ lp8788_setup_adc_channel(&pdev->dev, pchg);
ret = lp8788_psy_register(pdev, pchg);
if (ret)
@@ -718,7 +719,7 @@ static int lp8788_charger_probe(struct platform_device *pdev)
ret = lp8788_irq_register(pdev, pchg);
if (ret)
- dev_warn(lp->dev, "failed to register charger irq: %d\n", ret);
+ dev_warn(dev, "failed to register charger irq: %d\n", ret);
return 0;
}
diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c
index 22cfe9cc4727..74a0bd9bc162 100644
--- a/drivers/power/max17040_battery.c
+++ b/drivers/power/max17040_battery.c
@@ -207,7 +207,7 @@ static int max17040_probe(struct i2c_client *client,
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
return -EIO;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -225,7 +225,6 @@ static int max17040_probe(struct i2c_client *client,
ret = power_supply_register(&client->dev, &chip->battery);
if (ret) {
dev_err(&client->dev, "failed: power supply register\n");
- kfree(chip);
return ret;
}
@@ -244,7 +243,6 @@ static int max17040_remove(struct i2c_client *client)
power_supply_unregister(&chip->battery);
cancel_delayed_work(&chip->work);
- kfree(chip);
return 0;
}
diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c
new file mode 100644
index 000000000000..ed48d75bb786
--- /dev/null
+++ b/drivers/power/pm2301_charger.c
@@ -0,0 +1,1088 @@
+/*
+ * Copyright 2012 ST Ericsson.
+ *
+ * Power supply driver for ST Ericsson pm2xxx_charger charger
+ *
+ * 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/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/completion.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
+#include <linux/mfd/abx500/ux500_chargalg.h>
+#include <linux/pm2301_charger.h>
+#include <linux/gpio.h>
+
+#include "pm2301_charger.h"
+
+#define to_pm2xxx_charger_ac_device_info(x) container_of((x), \
+ struct pm2xxx_charger, ac_chg)
+
+static int pm2xxx_interrupt_registers[] = {
+ PM2XXX_REG_INT1,
+ PM2XXX_REG_INT2,
+ PM2XXX_REG_INT3,
+ PM2XXX_REG_INT4,
+ PM2XXX_REG_INT5,
+ PM2XXX_REG_INT6,
+};
+
+static enum power_supply_property pm2xxx_charger_ac_props[] = {
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+};
+
+static int pm2xxx_charger_voltage_map[] = {
+ 3500,
+ 3525,
+ 3550,
+ 3575,
+ 3600,
+ 3625,
+ 3650,
+ 3675,
+ 3700,
+ 3725,
+ 3750,
+ 3775,
+ 3800,
+ 3825,
+ 3850,
+ 3875,
+ 3900,
+ 3925,
+ 3950,
+ 3975,
+ 4000,
+ 4025,
+ 4050,
+ 4075,
+ 4100,
+ 4125,
+ 4150,
+ 4175,
+ 4200,
+ 4225,
+ 4250,
+ 4275,
+ 4300,
+};
+
+static int pm2xxx_charger_current_map[] = {
+ 200,
+ 200,
+ 400,
+ 600,
+ 800,
+ 1000,
+ 1200,
+ 1400,
+ 1600,
+ 1800,
+ 2000,
+ 2200,
+ 2400,
+ 2600,
+ 2800,
+ 3000,
+};
+
+static const struct i2c_device_id pm2xxx_ident[] = {
+ { "pm2301", 0 },
+ { }
+};
+
+static void set_lpn_pin(struct pm2xxx_charger *pm2)
+{
+ if (pm2->ac.charger_connected)
+ return;
+ gpio_set_value(pm2->lpn_pin, 1);
+
+ return;
+}
+
+static void clear_lpn_pin(struct pm2xxx_charger *pm2)
+{
+ if (pm2->ac.charger_connected)
+ return;
+ gpio_set_value(pm2->lpn_pin, 0);
+
+ return;
+}
+
+static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
+{
+ int ret;
+ /*
+ * When AC adaptor is unplugged, the host
+ * must put LPN high to be able to
+ * communicate by I2C with PM2301
+ * and receive I2C "acknowledge" from PM2301.
+ */
+ mutex_lock(&pm2->lock);
+ set_lpn_pin(pm2);
+
+ ret = i2c_smbus_read_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
+ 1, val);
+ if (ret < 0)
+ dev_err(pm2->dev, "Error reading register at 0x%x\n", reg);
+ else
+ ret = 0;
+ clear_lpn_pin(pm2);
+ mutex_unlock(&pm2->lock);
+
+ return ret;
+}
+
+static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val)
+{
+ int ret;
+ /*
+ * When AC adaptor is unplugged, the host
+ * must put LPN high to be able to
+ * communicate by I2C with PM2301
+ * and receive I2C "acknowledge" from PM2301.
+ */
+ mutex_lock(&pm2->lock);
+ set_lpn_pin(pm2);
+
+ ret = i2c_smbus_write_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
+ 1, &val);
+ if (ret < 0)
+ dev_err(pm2->dev, "Error writing register at 0x%x\n", reg);
+ else
+ ret = 0;
+ clear_lpn_pin(pm2);
+ mutex_unlock(&pm2->lock);
+
+ return ret;
+}
+
+static int pm2xxx_charging_enable_mngt(struct pm2xxx_charger *pm2)
+{
+ int ret;
+
+ /* Enable charging */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
+ (PM2XXX_CH_AUTO_RESUME_EN | PM2XXX_CHARGER_ENA));
+
+ return ret;
+}
+
+static int pm2xxx_charging_disable_mngt(struct pm2xxx_charger *pm2)
+{
+ int ret;
+
+ /* Disable charging */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
+ (PM2XXX_CH_AUTO_RESUME_DIS | PM2XXX_CHARGER_DIS));
+
+ return ret;
+}
+
+static int pm2xxx_charger_batt_therm_mngt(struct pm2xxx_charger *pm2, int val)
+{
+ queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
+
+ return 0;
+}
+
+
+int pm2xxx_charger_die_therm_mngt(struct pm2xxx_charger *pm2, int val)
+{
+ queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
+
+ return 0;
+}
+
+static int pm2xxx_charger_ovv_mngt(struct pm2xxx_charger *pm2, int val)
+{
+ int ret = 0;
+
+ pm2->failure_input_ovv++;
+ if (pm2->failure_input_ovv < 4) {
+ ret = pm2xxx_charging_enable_mngt(pm2);
+ goto out;
+ } else {
+ pm2->failure_input_ovv = 0;
+ dev_err(pm2->dev, "Overvoltage detected\n");
+ pm2->flags.ovv = true;
+ power_supply_changed(&pm2->ac_chg.psy);
+ }
+
+out:
+ return ret;
+}
+
+static int pm2xxx_charger_wd_exp_mngt(struct pm2xxx_charger *pm2, int val)
+{
+ dev_dbg(pm2->dev , "20 minutes watchdog occured\n");
+
+ pm2->ac.wd_expired = true;
+ power_supply_changed(&pm2->ac_chg.psy);
+
+ return 0;
+}
+
+static int pm2xxx_charger_vbat_lsig_mngt(struct pm2xxx_charger *pm2, int val)
+{
+ switch (val) {
+ case PM2XXX_INT1_ITVBATLOWR:
+ dev_dbg(pm2->dev, "VBAT grows above VBAT_LOW level\n");
+ break;
+
+ case PM2XXX_INT1_ITVBATLOWF:
+ dev_dbg(pm2->dev, "VBAT drops below VBAT_LOW level\n");
+ break;
+
+ default:
+ dev_err(pm2->dev, "Unknown VBAT level\n");
+ }
+
+ return 0;
+}
+
+static int pm2xxx_charger_bat_disc_mngt(struct pm2xxx_charger *pm2, int val)
+{
+ dev_dbg(pm2->dev, "battery disconnected\n");
+
+ return 0;
+}
+
+static int pm2xxx_charger_detection(struct pm2xxx_charger *pm2, u8 *val)
+{
+ int ret;
+
+ ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT2, val);
+
+ if (ret < 0) {
+ dev_err(pm2->dev, "Charger detection failed\n");
+ goto out;
+ }
+
+ *val &= (PM2XXX_INT2_S_ITVPWR1PLUG | PM2XXX_INT2_S_ITVPWR2PLUG);
+
+out:
+ return ret;
+}
+
+static int pm2xxx_charger_itv_pwr_plug_mngt(struct pm2xxx_charger *pm2, int val)
+{
+
+ int ret;
+ u8 read_val;
+
+ /*
+ * Since we can't be sure that the events are received
+ * synchronously, we have the check if the main charger is
+ * connected by reading the interrupt source register.
+ */
+ ret = pm2xxx_charger_detection(pm2, &read_val);
+
+ if ((ret == 0) && read_val) {
+ pm2->ac.charger_connected = 1;
+ pm2->ac_conn = true;
+ queue_work(pm2->charger_wq, &pm2->ac_work);
+ }
+
+
+ return ret;
+}
+
+static int pm2xxx_charger_itv_pwr_unplug_mngt(struct pm2xxx_charger *pm2,
+ int val)
+{
+ pm2->ac.charger_connected = 0;
+ queue_work(pm2->charger_wq, &pm2->ac_work);
+
+ return 0;
+}
+
+static int pm2_int_reg0(void *pm2_data, int val)
+{
+ struct pm2xxx_charger *pm2 = pm2_data;
+ int ret = 0;
+
+ if (val & (PM2XXX_INT1_ITVBATLOWR | PM2XXX_INT1_ITVBATLOWF)) {
+ ret = pm2xxx_charger_vbat_lsig_mngt(pm2, val &
+ (PM2XXX_INT1_ITVBATLOWR | PM2XXX_INT1_ITVBATLOWF));
+ }
+
+ if (val & PM2XXX_INT1_ITVBATDISCONNECT) {
+ ret = pm2xxx_charger_bat_disc_mngt(pm2,
+ PM2XXX_INT1_ITVBATDISCONNECT);
+ }
+
+ return ret;
+}
+
+static int pm2_int_reg1(void *pm2_data, int val)
+{
+ struct pm2xxx_charger *pm2 = pm2_data;
+ int ret = 0;
+
+ if (val & (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG)) {
+ dev_dbg(pm2->dev , "Main charger plugged\n");
+ ret = pm2xxx_charger_itv_pwr_plug_mngt(pm2, val &
+ (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG));
+ }
+
+ if (val &
+ (PM2XXX_INT2_ITVPWR1UNPLUG | PM2XXX_INT2_ITVPWR2UNPLUG)) {
+ dev_dbg(pm2->dev , "Main charger unplugged\n");
+ ret = pm2xxx_charger_itv_pwr_unplug_mngt(pm2, val &
+ (PM2XXX_INT2_ITVPWR1UNPLUG |
+ PM2XXX_INT2_ITVPWR2UNPLUG));
+ }
+
+ return ret;
+}
+
+static int pm2_int_reg2(void *pm2_data, int val)
+{
+ struct pm2xxx_charger *pm2 = pm2_data;
+ int ret = 0;
+
+ if (val & PM2XXX_INT3_ITAUTOTIMEOUTWD)
+ ret = pm2xxx_charger_wd_exp_mngt(pm2, val);
+
+ if (val & (PM2XXX_INT3_ITCHPRECHARGEWD |
+ PM2XXX_INT3_ITCHCCWD | PM2XXX_INT3_ITCHCVWD)) {
+ dev_dbg(pm2->dev,
+ "Watchdog occured for precharge, CC and CV charge\n");
+ }
+
+ return ret;
+}
+
+static int pm2_int_reg3(void *pm2_data, int val)
+{
+ struct pm2xxx_charger *pm2 = pm2_data;
+ int ret = 0;
+
+ if (val & (PM2XXX_INT4_ITCHARGINGON)) {
+ dev_dbg(pm2->dev ,
+ "chargind operation has started\n");
+ }
+
+ if (val & (PM2XXX_INT4_ITVRESUME)) {
+ dev_dbg(pm2->dev,
+ "battery discharged down to VResume threshold\n");
+ }
+
+ if (val & (PM2XXX_INT4_ITBATTFULL)) {
+ dev_dbg(pm2->dev , "battery fully detected\n");
+ }
+
+ if (val & (PM2XXX_INT4_ITCVPHASE)) {
+ dev_dbg(pm2->dev, "CV phase enter with 0.5C charging\n");
+ }
+
+ if (val & (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV)) {
+ pm2->failure_case = VPWR_OVV;
+ ret = pm2xxx_charger_ovv_mngt(pm2, val &
+ (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV));
+ dev_dbg(pm2->dev, "VPWR/VSYSTEM overvoltage detected\n");
+ }
+
+ if (val & (PM2XXX_INT4_S_ITBATTEMPCOLD |
+ PM2XXX_INT4_S_ITBATTEMPHOT)) {
+ ret = pm2xxx_charger_batt_therm_mngt(pm2, val &
+ (PM2XXX_INT4_S_ITBATTEMPCOLD |
+ PM2XXX_INT4_S_ITBATTEMPHOT));
+ dev_dbg(pm2->dev, "BTEMP is too Low/High\n");
+ }
+
+ return ret;
+}
+
+static int pm2_int_reg4(void *pm2_data, int val)
+{
+ struct pm2xxx_charger *pm2 = pm2_data;
+ int ret = 0;
+
+ if (val & PM2XXX_INT5_ITVSYSTEMOVV) {
+ pm2->failure_case = VSYSTEM_OVV;
+ ret = pm2xxx_charger_ovv_mngt(pm2, val &
+ PM2XXX_INT5_ITVSYSTEMOVV);
+ dev_dbg(pm2->dev, "VSYSTEM overvoltage detected\n");
+ }
+
+ if (val & (PM2XXX_INT5_ITTHERMALWARNINGFALL |
+ PM2XXX_INT5_ITTHERMALWARNINGRISE |
+ PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
+ PM2XXX_INT5_ITTHERMALSHUTDOWNRISE)) {
+ dev_dbg(pm2->dev, "BTEMP die temperature is too Low/High\n");
+ ret = pm2xxx_charger_die_therm_mngt(pm2, val &
+ (PM2XXX_INT5_ITTHERMALWARNINGFALL |
+ PM2XXX_INT5_ITTHERMALWARNINGRISE |
+ PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
+ PM2XXX_INT5_ITTHERMALSHUTDOWNRISE));
+ }
+
+ return ret;
+}
+
+static int pm2_int_reg5(void *pm2_data, int val)
+{
+ struct pm2xxx_charger *pm2 = pm2_data;
+ int ret = 0;
+
+
+ if (val & (PM2XXX_INT6_ITVPWR2DROP | PM2XXX_INT6_ITVPWR1DROP)) {
+ dev_dbg(pm2->dev, "VMPWR drop to VBAT level\n");
+ }
+
+ if (val & (PM2XXX_INT6_ITVPWR2VALIDRISE |
+ PM2XXX_INT6_ITVPWR1VALIDRISE |
+ PM2XXX_INT6_ITVPWR2VALIDFALL |
+ PM2XXX_INT6_ITVPWR1VALIDFALL)) {
+ dev_dbg(pm2->dev, "Falling/Rising edge on WPWR1/2\n");
+ }
+
+ return ret;
+}
+
+static irqreturn_t pm2xxx_irq_int(int irq, void *data)
+{
+ struct pm2xxx_charger *pm2 = data;
+ struct pm2xxx_interrupts *interrupt = pm2->pm2_int;
+ int i;
+
+ for (i = 0; i < PM2XXX_NUM_INT_REG; i++) {
+ pm2xxx_reg_read(pm2,
+ pm2xxx_interrupt_registers[i],
+ &(interrupt->reg[i]));
+
+ if (interrupt->reg[i] > 0)
+ interrupt->handler[i](pm2, interrupt->reg[i]);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int pm2xxx_charger_get_ac_cv(struct pm2xxx_charger *pm2)
+{
+ int ret = 0;
+ u8 val;
+
+ if (pm2->ac.charger_connected && pm2->ac.charger_online) {
+
+ ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &val);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
+ goto out;
+ }
+
+ if (val & PM2XXX_INT4_S_ITCVPHASE)
+ ret = PM2XXX_CONST_VOLT;
+ else
+ ret = PM2XXX_CONST_CURR;
+ }
+out:
+ return ret;
+}
+
+static int pm2xxx_current_to_regval(int curr)
+{
+ int i;
+
+ if (curr < pm2xxx_charger_current_map[0])
+ return 0;
+
+ for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_current_map); i++) {
+ if (curr < pm2xxx_charger_current_map[i])
+ return (i - 1);
+ }
+
+ i = ARRAY_SIZE(pm2xxx_charger_current_map) - 1;
+ if (curr == pm2xxx_charger_current_map[i])
+ return i;
+ else
+ return -EINVAL;
+}
+
+static int pm2xxx_voltage_to_regval(int curr)
+{
+ int i;
+
+ if (curr < pm2xxx_charger_voltage_map[0])
+ return 0;
+
+ for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_voltage_map); i++) {
+ if (curr < pm2xxx_charger_voltage_map[i])
+ return i - 1;
+ }
+
+ i = ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1;
+ if (curr == pm2xxx_charger_voltage_map[i])
+ return i;
+ else
+ return -EINVAL;
+}
+
+static int pm2xxx_charger_update_charger_current(struct ux500_charger *charger,
+ int ich_out)
+{
+ int ret;
+ int curr_index;
+ struct pm2xxx_charger *pm2;
+ u8 val;
+
+ if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
+ pm2 = to_pm2xxx_charger_ac_device_info(charger);
+ else
+ return -ENXIO;
+
+ curr_index = pm2xxx_current_to_regval(ich_out);
+ if (curr_index < 0) {
+ dev_err(pm2->dev,
+ "Charger current too high, charging not started\n");
+ return -ENXIO;
+ }
+
+ ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
+ if (ret >= 0) {
+ val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
+ val |= curr_index;
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
+ if (ret < 0) {
+ dev_err(pm2->dev,
+ "%s write failed\n", __func__);
+ }
+ }
+ else
+ dev_err(pm2->dev, "%s read failed\n", __func__);
+
+ return ret;
+}
+
+static int pm2xxx_charger_ac_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pm2xxx_charger *pm2;
+
+ pm2 = to_pm2xxx_charger_ac_device_info(psy_to_ux500_charger(psy));
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_HEALTH:
+ if (pm2->flags.mainextchnotok)
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ else if (pm2->ac.wd_expired)
+ val->intval = POWER_SUPPLY_HEALTH_DEAD;
+ else if (pm2->flags.main_thermal_prot)
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ else
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = pm2->ac.charger_online;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = pm2->ac.charger_connected;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ pm2->ac.cv_active = pm2xxx_charger_get_ac_cv(pm2);
+ val->intval = pm2->ac.cv_active;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int pm2xxx_charging_init(struct pm2xxx_charger *pm2)
+{
+ int ret = 0;
+
+ /* enable CC and CV watchdog */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG3,
+ (PM2XXX_CH_WD_CV_PHASE_60MIN | PM2XXX_CH_WD_CC_PHASE_60MIN));
+ if( ret < 0)
+ return ret;
+
+ /* enable precharge watchdog */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG4,
+ PM2XXX_CH_WD_PRECH_PHASE_60MIN);
+
+ /* Disable auto timeout */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG5,
+ PM2XXX_CH_WD_AUTO_TIMEOUT_20MIN);
+
+ /*
+ * EOC current level = 100mA
+ * Precharge current level = 100mA
+ * CC current level = 1000mA
+ */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6,
+ (PM2XXX_DIR_CH_CC_CURRENT_1000MA |
+ PM2XXX_CH_PRECH_CURRENT_100MA |
+ PM2XXX_CH_EOC_CURRENT_100MA));
+
+ /*
+ * recharge threshold = 3.8V
+ * Precharge to CC threshold = 2.9V
+ */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG7,
+ (PM2XXX_CH_PRECH_VOL_2_9 | PM2XXX_CH_VRESUME_VOL_3_8));
+
+ /* float voltage charger level = 4.2V */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8,
+ PM2XXX_CH_VOLT_4_2);
+
+ /* Voltage drop between VBAT and VSYS in HW charging = 300mV */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG9,
+ (PM2XXX_CH_150MV_DROP_300MV | PM2XXX_CHARCHING_INFO_DIS |
+ PM2XXX_CH_CC_REDUCED_CURRENT_IDENT |
+ PM2XXX_CH_CC_MODEDROP_DIS));
+
+ /* Input charger level of over voltage = 10V */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR2,
+ PM2XXX_VPWR2_OVV_10);
+ ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR1,
+ PM2XXX_VPWR1_OVV_10);
+
+ /* Input charger drop */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR2,
+ (PM2XXX_VPWR2_HW_OPT_DIS | PM2XXX_VPWR2_VALID_DIS |
+ PM2XXX_VPWR2_DROP_DIS));
+ ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR1,
+ (PM2XXX_VPWR1_HW_OPT_DIS | PM2XXX_VPWR1_VALID_DIS |
+ PM2XXX_VPWR1_DROP_DIS));
+
+ /* Disable battery low monitoring */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_LOW_LEV_COMP_REG,
+ PM2XXX_VBAT_LOW_MONITORING_ENA);
+
+ /* Disable LED */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG,
+ PM2XXX_LED_SELECT_DIS);
+
+ return ret;
+}
+
+static int pm2xxx_charger_ac_en(struct ux500_charger *charger,
+ int enable, int vset, int iset)
+{
+ int ret;
+ int volt_index;
+ int curr_index;
+ u8 val;
+
+ struct pm2xxx_charger *pm2 = to_pm2xxx_charger_ac_device_info(charger);
+
+ if (enable) {
+ if (!pm2->ac.charger_connected) {
+ dev_dbg(pm2->dev, "AC charger not connected\n");
+ return -ENXIO;
+ }
+
+ dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset);
+ if (!pm2->vddadc_en_ac) {
+ regulator_enable(pm2->regu);
+ pm2->vddadc_en_ac = true;
+ }
+
+ ret = pm2xxx_charging_init(pm2);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s charging init failed\n",
+ __func__);
+ goto error_occured;
+ }
+
+ volt_index = pm2xxx_voltage_to_regval(vset);
+ curr_index = pm2xxx_current_to_regval(iset);
+
+ if (volt_index < 0 || curr_index < 0) {
+ dev_err(pm2->dev,
+ "Charger voltage or current too high, "
+ "charging not started\n");
+ return -ENXIO;
+ }
+
+ ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG8, &val);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
+ goto error_occured;
+ }
+ val &= ~PM2XXX_CH_VOLT_MASK;
+ val |= volt_index;
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8, val);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
+ goto error_occured;
+ }
+
+ ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
+ goto error_occured;
+ }
+ val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
+ val |= curr_index;
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
+ goto error_occured;
+ }
+
+ if (!pm2->bat->enable_overshoot) {
+ ret = pm2xxx_reg_read(pm2, PM2XXX_LED_CTRL_REG, &val);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx read failed\n",
+ __func__);
+ goto error_occured;
+ }
+ val |= PM2XXX_ANTI_OVERSHOOT_EN;
+ ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG, val);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx write failed\n",
+ __func__);
+ goto error_occured;
+ }
+ }
+
+ ret = pm2xxx_charging_enable_mngt(pm2);
+ if (ret < 0) {
+ dev_err(pm2->dev, "Failed to enable"
+ "pm2xxx ac charger\n");
+ goto error_occured;
+ }
+
+ pm2->ac.charger_online = 1;
+ } else {
+ pm2->ac.charger_online = 0;
+ pm2->ac.wd_expired = false;
+
+ /* Disable regulator if enabled */
+ if (pm2->vddadc_en_ac) {
+ regulator_disable(pm2->regu);
+ pm2->vddadc_en_ac = false;
+ }
+
+ ret = pm2xxx_charging_disable_mngt(pm2);
+ if (ret < 0) {
+ dev_err(pm2->dev, "failed to disable"
+ "pm2xxx ac charger\n");
+ goto error_occured;
+ }
+
+ dev_dbg(pm2->dev, "PM2301: " "Disabled AC charging\n");
+ }
+ power_supply_changed(&pm2->ac_chg.psy);
+
+error_occured:
+ return ret;
+}
+
+static int pm2xxx_charger_watchdog_kick(struct ux500_charger *charger)
+{
+ int ret;
+ struct pm2xxx_charger *pm2;
+
+ if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
+ pm2 = to_pm2xxx_charger_ac_device_info(charger);
+ else
+ return -ENXIO;
+
+ ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_WD_KICK, WD_TIMER);
+ if (ret)
+ dev_err(pm2->dev, "Failed to kick WD!\n");
+
+ return ret;
+}
+
+static void pm2xxx_charger_ac_work(struct work_struct *work)
+{
+ struct pm2xxx_charger *pm2 = container_of(work,
+ struct pm2xxx_charger, ac_work);
+
+
+ power_supply_changed(&pm2->ac_chg.psy);
+ sysfs_notify(&pm2->ac_chg.psy.dev->kobj, NULL, "present");
+};
+
+static void pm2xxx_charger_check_main_thermal_prot_work(
+ struct work_struct *work)
+{
+};
+
+static struct pm2xxx_interrupts pm2xxx_int = {
+ .handler[0] = pm2_int_reg0,
+ .handler[1] = pm2_int_reg1,
+ .handler[2] = pm2_int_reg2,
+ .handler[3] = pm2_int_reg3,
+ .handler[4] = pm2_int_reg4,
+ .handler[5] = pm2_int_reg5,
+};
+
+static struct pm2xxx_irq pm2xxx_charger_irq[] = {
+ {"PM2XXX_IRQ_INT", pm2xxx_irq_int},
+};
+
+static int pm2xxx_wall_charger_resume(struct i2c_client *i2c_client)
+{
+ return 0;
+}
+
+static int pm2xxx_wall_charger_suspend(struct i2c_client *i2c_client,
+ pm_message_t state)
+{
+ return 0;
+}
+
+static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct pm2xxx_platform_data *pl_data = i2c_client->dev.platform_data;
+ struct pm2xxx_charger *pm2;
+ int ret = 0;
+ u8 val;
+
+ pm2 = kzalloc(sizeof(struct pm2xxx_charger), GFP_KERNEL);
+ if (!pm2) {
+ dev_err(pm2->dev, "pm2xxx_charger allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* get parent data */
+ pm2->dev = &i2c_client->dev;
+ pm2->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+
+ pm2->pm2_int = &pm2xxx_int;
+
+ /* get charger spcific platform data */
+ if (!pl_data->wall_charger) {
+ dev_err(pm2->dev, "no charger platform data supplied\n");
+ ret = -EINVAL;
+ goto free_device_info;
+ }
+
+ pm2->pdata = pl_data->wall_charger;
+
+ /* get battery specific platform data */
+ if (!pl_data->battery) {
+ dev_err(pm2->dev, "no battery platform data supplied\n");
+ ret = -EINVAL;
+ goto free_device_info;
+ }
+
+ pm2->bat = pl_data->battery;
+
+ /*get lpn GPIO from platform data*/
+ if (!pm2->pdata->lpn_gpio) {
+ dev_err(pm2->dev, "no lpn gpio data supplied\n");
+ ret = -EINVAL;
+ goto free_device_info;
+ }
+ pm2->lpn_pin = pm2->pdata->lpn_gpio;
+
+ if (!i2c_check_functionality(i2c_client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ ret = -ENODEV;
+ dev_info(pm2->dev, "pm2301 i2c_check_functionality failed\n");
+ goto free_device_info;
+ }
+
+ pm2->config.pm2xxx_i2c = i2c_client;
+ pm2->config.pm2xxx_id = (struct i2c_device_id *) id;
+ i2c_set_clientdata(i2c_client, pm2);
+
+ /* AC supply */
+ /* power_supply base class */
+ pm2->ac_chg.psy.name = pm2->pdata->label;
+ pm2->ac_chg.psy.type = POWER_SUPPLY_TYPE_MAINS;
+ pm2->ac_chg.psy.properties = pm2xxx_charger_ac_props;
+ pm2->ac_chg.psy.num_properties = ARRAY_SIZE(pm2xxx_charger_ac_props);
+ pm2->ac_chg.psy.get_property = pm2xxx_charger_ac_get_property;
+ pm2->ac_chg.psy.supplied_to = pm2->pdata->supplied_to;
+ pm2->ac_chg.psy.num_supplicants = pm2->pdata->num_supplicants;
+ /* pm2xxx_charger sub-class */
+ pm2->ac_chg.ops.enable = &pm2xxx_charger_ac_en;
+ pm2->ac_chg.ops.kick_wd = &pm2xxx_charger_watchdog_kick;
+ pm2->ac_chg.ops.update_curr = &pm2xxx_charger_update_charger_current;
+ pm2->ac_chg.max_out_volt = pm2xxx_charger_voltage_map[
+ ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1];
+ pm2->ac_chg.max_out_curr = pm2xxx_charger_current_map[
+ ARRAY_SIZE(pm2xxx_charger_current_map) - 1];
+ pm2->ac_chg.wdt_refresh = WD_KICK_INTERVAL;
+ pm2->ac_chg.enabled = true;
+ pm2->ac_chg.external = true;
+
+ /* Create a work queue for the charger */
+ pm2->charger_wq =
+ create_singlethread_workqueue("pm2xxx_charger_wq");
+ if (pm2->charger_wq == NULL) {
+ dev_err(pm2->dev, "failed to create work queue\n");
+ goto free_device_info;
+ }
+
+ /* Init work for charger detection */
+ INIT_WORK(&pm2->ac_work, pm2xxx_charger_ac_work);
+
+ /* Init work for checking HW status */
+ INIT_WORK(&pm2->check_main_thermal_prot_work,
+ pm2xxx_charger_check_main_thermal_prot_work);
+
+ /*
+ * VDD ADC supply needs to be enabled from this driver when there
+ * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
+ * interrupts during charging
+ */
+ pm2->regu = regulator_get(pm2->dev, "vddadc");
+ if (IS_ERR(pm2->regu)) {
+ ret = PTR_ERR(pm2->regu);
+ dev_err(pm2->dev, "failed to get vddadc regulator\n");
+ goto free_charger_wq;
+ }
+
+ /* Register AC charger class */
+ ret = power_supply_register(pm2->dev, &pm2->ac_chg.psy);
+ if (ret) {
+ dev_err(pm2->dev, "failed to register AC charger\n");
+ goto free_regulator;
+ }
+
+ /* Register interrupts */
+ ret = request_threaded_irq(pm2->pdata->irq_number, NULL,
+ pm2xxx_charger_irq[0].isr,
+ pm2->pdata->irq_type,
+ pm2xxx_charger_irq[0].name, pm2);
+
+ if (ret != 0) {
+ dev_err(pm2->dev, "failed to request %s IRQ %d: %d\n",
+ pm2xxx_charger_irq[0].name, pm2->pdata->irq_number, ret);
+ goto unregister_pm2xxx_charger;
+ }
+
+ /*Initialize lock*/
+ mutex_init(&pm2->lock);
+
+ /*
+ * Charger detection mechanism requires pulling up the LPN pin
+ * while i2c communication if Charger is not connected
+ * LPN pin of PM2301 is GPIO60 of AB9540
+ */
+ ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio");
+ if (ret < 0) {
+ dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n");
+ goto unregister_pm2xxx_charger;
+ }
+ ret = gpio_direction_output(pm2->lpn_pin, 0);
+ if (ret < 0) {
+ dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n");
+ goto free_gpio;
+ }
+
+ ret = pm2xxx_charger_detection(pm2, &val);
+
+ if ((ret == 0) && val) {
+ pm2->ac.charger_connected = 1;
+ pm2->ac_conn = true;
+ power_supply_changed(&pm2->ac_chg.psy);
+ sysfs_notify(&pm2->ac_chg.psy.dev->kobj, NULL, "present");
+ }
+
+ return 0;
+
+free_gpio:
+ gpio_free(pm2->lpn_pin);
+unregister_pm2xxx_charger:
+ /* unregister power supply */
+ power_supply_unregister(&pm2->ac_chg.psy);
+free_regulator:
+ /* disable the regulator */
+ regulator_put(pm2->regu);
+free_charger_wq:
+ destroy_workqueue(pm2->charger_wq);
+free_device_info:
+ kfree(pm2);
+ return ret;
+}
+
+static int __devexit pm2xxx_wall_charger_remove(struct i2c_client *i2c_client)
+{
+ struct pm2xxx_charger *pm2 = i2c_get_clientdata(i2c_client);
+
+ /* Disable AC charging */
+ pm2xxx_charger_ac_en(&pm2->ac_chg, false, 0, 0);
+
+ /* Disable interrupts */
+ free_irq(pm2->pdata->irq_number, pm2);
+
+ /* Delete the work queue */
+ destroy_workqueue(pm2->charger_wq);
+
+ flush_scheduled_work();
+
+ /* disable the regulator */
+ regulator_put(pm2->regu);
+
+ power_supply_unregister(&pm2->ac_chg.psy);
+
+ /*Free GPIO60*/
+ gpio_free(pm2->lpn_pin);
+
+ kfree(pm2);
+
+ return 0;
+}
+
+static const struct i2c_device_id pm2xxx_id[] = {
+ { "pm2301", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, pm2xxx_id);
+
+static struct i2c_driver pm2xxx_charger_driver = {
+ .probe = pm2xxx_wall_charger_probe,
+ .remove = __devexit_p(pm2xxx_wall_charger_remove),
+ .suspend = pm2xxx_wall_charger_suspend,
+ .resume = pm2xxx_wall_charger_resume,
+ .driver = {
+ .name = "pm2xxx-wall_charger",
+ .owner = THIS_MODULE,
+ },
+ .id_table = pm2xxx_id,
+};
+
+static int __init pm2xxx_charger_init(void)
+{
+ return i2c_add_driver(&pm2xxx_charger_driver);
+}
+
+static void __exit pm2xxx_charger_exit(void)
+{
+ i2c_del_driver(&pm2xxx_charger_driver);
+}
+
+subsys_initcall_sync(pm2xxx_charger_init);
+module_exit(pm2xxx_charger_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay");
+MODULE_ALIAS("platform:pm2xxx-charger");
+MODULE_DESCRIPTION("PM2xxx charger management driver");
+
diff --git a/drivers/power/pm2301_charger.h b/drivers/power/pm2301_charger.h
new file mode 100644
index 000000000000..e6319cdbc94f
--- /dev/null
+++ b/drivers/power/pm2301_charger.h
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * PM2301 power supply interface
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef PM2301_CHARGER_H
+#define PM2301_CHARGER_H
+
+#define MAIN_WDOG_ENA 0x01
+#define MAIN_WDOG_KICK 0x02
+#define MAIN_WDOG_DIS 0x00
+#define CHARG_WD_KICK 0x01
+#define MAIN_CH_ENA 0x01
+#define MAIN_CH_NO_OVERSHOOT_ENA_N 0x02
+#define MAIN_CH_DET 0x01
+#define MAIN_CH_CV_ON 0x04
+#define OTP_ENABLE_WD 0x01
+
+#define MAIN_CH_INPUT_CURR_SHIFT 4
+
+#define LED_INDICATOR_PWM_ENA 0x01
+#define LED_INDICATOR_PWM_DIS 0x00
+#define LED_IND_CUR_5MA 0x04
+#define LED_INDICATOR_PWM_DUTY_252_256 0xBF
+
+/* HW failure constants */
+#define MAIN_CH_TH_PROT 0x02
+#define MAIN_CH_NOK 0x01
+
+/* Watchdog timeout constant */
+#define WD_TIMER 0x30 /* 4min */
+#define WD_KICK_INTERVAL (30 * HZ)
+
+#define PM2XXX_NUM_INT_REG 0x6
+
+/* Constant voltage/current */
+#define PM2XXX_CONST_CURR 0x0
+#define PM2XXX_CONST_VOLT 0x1
+
+/* Lowest charger voltage is 3.39V -> 0x4E */
+#define LOW_VOLT_REG 0x4E
+
+#define PM2XXX_BATT_CTRL_REG1 0x00
+#define PM2XXX_BATT_CTRL_REG2 0x01
+#define PM2XXX_BATT_CTRL_REG3 0x02
+#define PM2XXX_BATT_CTRL_REG4 0x03
+#define PM2XXX_BATT_CTRL_REG5 0x04
+#define PM2XXX_BATT_CTRL_REG6 0x05
+#define PM2XXX_BATT_CTRL_REG7 0x06
+#define PM2XXX_BATT_CTRL_REG8 0x07
+#define PM2XXX_NTC_CTRL_REG1 0x08
+#define PM2XXX_NTC_CTRL_REG2 0x09
+#define PM2XXX_BATT_CTRL_REG9 0x0A
+#define PM2XXX_BATT_STAT_REG1 0x0B
+#define PM2XXX_INP_VOLT_VPWR2 0x11
+#define PM2XXX_INP_DROP_VPWR2 0x13
+#define PM2XXX_INP_VOLT_VPWR1 0x15
+#define PM2XXX_INP_DROP_VPWR1 0x17
+#define PM2XXX_INP_MODE_VPWR 0x18
+#define PM2XXX_BATT_WD_KICK 0x70
+#define PM2XXX_DEV_VER_STAT 0x0C
+#define PM2XXX_THERM_WARN_CTRL_REG 0x20
+#define PM2XXX_BATT_DISC_REG 0x21
+#define PM2XXX_BATT_LOW_LEV_COMP_REG 0x22
+#define PM2XXX_BATT_LOW_LEV_VAL_REG 0x23
+#define PM2XXX_I2C_PAD_CTRL_REG 0x24
+#define PM2XXX_SW_CTRL_REG 0x26
+#define PM2XXX_LED_CTRL_REG 0x28
+
+#define PM2XXX_REG_INT1 0x40
+#define PM2XXX_MASK_REG_INT1 0x50
+#define PM2XXX_SRCE_REG_INT1 0x60
+#define PM2XXX_REG_INT2 0x41
+#define PM2XXX_MASK_REG_INT2 0x51
+#define PM2XXX_SRCE_REG_INT2 0x61
+#define PM2XXX_REG_INT3 0x42
+#define PM2XXX_MASK_REG_INT3 0x52
+#define PM2XXX_SRCE_REG_INT3 0x62
+#define PM2XXX_REG_INT4 0x43
+#define PM2XXX_MASK_REG_INT4 0x53
+#define PM2XXX_SRCE_REG_INT4 0x63
+#define PM2XXX_REG_INT5 0x44
+#define PM2XXX_MASK_REG_INT5 0x54
+#define PM2XXX_SRCE_REG_INT5 0x64
+#define PM2XXX_REG_INT6 0x45
+#define PM2XXX_MASK_REG_INT6 0x55
+#define PM2XXX_SRCE_REG_INT6 0x65
+
+#define VPWR_OVV 0x0
+#define VSYSTEM_OVV 0x1
+
+/* control Reg 1 */
+#define PM2XXX_CH_RESUME_EN 0x1
+#define PM2XXX_CH_RESUME_DIS 0x0
+
+/* control Reg 2 */
+#define PM2XXX_CH_AUTO_RESUME_EN 0X2
+#define PM2XXX_CH_AUTO_RESUME_DIS 0X0
+#define PM2XXX_CHARGER_ENA 0x4
+#define PM2XXX_CHARGER_DIS 0x0
+
+/* control Reg 3 */
+#define PM2XXX_CH_WD_CC_PHASE_OFF 0x0
+#define PM2XXX_CH_WD_CC_PHASE_5MIN 0x1
+#define PM2XXX_CH_WD_CC_PHASE_10MIN 0x2
+#define PM2XXX_CH_WD_CC_PHASE_30MIN 0x3
+#define PM2XXX_CH_WD_CC_PHASE_60MIN 0x4
+#define PM2XXX_CH_WD_CC_PHASE_120MIN 0x5
+#define PM2XXX_CH_WD_CC_PHASE_240MIN 0x6
+#define PM2XXX_CH_WD_CC_PHASE_360MIN 0x7
+
+#define PM2XXX_CH_WD_CV_PHASE_OFF (0x0<<3)
+#define PM2XXX_CH_WD_CV_PHASE_5MIN (0x1<<3)
+#define PM2XXX_CH_WD_CV_PHASE_10MIN (0x2<<3)
+#define PM2XXX_CH_WD_CV_PHASE_30MIN (0x3<<3)
+#define PM2XXX_CH_WD_CV_PHASE_60MIN (0x4<<3)
+#define PM2XXX_CH_WD_CV_PHASE_120MIN (0x5<<3)
+#define PM2XXX_CH_WD_CV_PHASE_240MIN (0x6<<3)
+#define PM2XXX_CH_WD_CV_PHASE_360MIN (0x7<<3)
+
+/* control Reg 4 */
+#define PM2XXX_CH_WD_PRECH_PHASE_OFF 0x0
+#define PM2XXX_CH_WD_PRECH_PHASE_1MIN 0x1
+#define PM2XXX_CH_WD_PRECH_PHASE_5MIN 0x2
+#define PM2XXX_CH_WD_PRECH_PHASE_10MIN 0x3
+#define PM2XXX_CH_WD_PRECH_PHASE_30MIN 0x4
+#define PM2XXX_CH_WD_PRECH_PHASE_60MIN 0x5
+#define PM2XXX_CH_WD_PRECH_PHASE_120MIN 0x6
+#define PM2XXX_CH_WD_PRECH_PHASE_240MIN 0x7
+
+/* control Reg 5 */
+#define PM2XXX_CH_WD_AUTO_TIMEOUT_NONE 0x0
+#define PM2XXX_CH_WD_AUTO_TIMEOUT_20MIN 0x1
+
+/* control Reg 6 */
+#define PM2XXX_DIR_CH_CC_CURRENT_MASK 0x0F
+#define PM2XXX_DIR_CH_CC_CURRENT_200MA 0x0
+#define PM2XXX_DIR_CH_CC_CURRENT_400MA 0x2
+#define PM2XXX_DIR_CH_CC_CURRENT_600MA 0x3
+#define PM2XXX_DIR_CH_CC_CURRENT_800MA 0x4
+#define PM2XXX_DIR_CH_CC_CURRENT_1000MA 0x5
+#define PM2XXX_DIR_CH_CC_CURRENT_1200MA 0x6
+#define PM2XXX_DIR_CH_CC_CURRENT_1400MA 0x7
+#define PM2XXX_DIR_CH_CC_CURRENT_1600MA 0x8
+#define PM2XXX_DIR_CH_CC_CURRENT_1800MA 0x9
+#define PM2XXX_DIR_CH_CC_CURRENT_2000MA 0xA
+#define PM2XXX_DIR_CH_CC_CURRENT_2200MA 0xB
+#define PM2XXX_DIR_CH_CC_CURRENT_2400MA 0xC
+#define PM2XXX_DIR_CH_CC_CURRENT_2600MA 0xD
+#define PM2XXX_DIR_CH_CC_CURRENT_2800MA 0xE
+#define PM2XXX_DIR_CH_CC_CURRENT_3000MA 0xF
+
+#define PM2XXX_CH_PRECH_CURRENT_MASK 0x30
+#define PM2XXX_CH_PRECH_CURRENT_25MA (0x0<<4)
+#define PM2XXX_CH_PRECH_CURRENT_50MA (0x1<<4)
+#define PM2XXX_CH_PRECH_CURRENT_75MA (0x2<<4)
+#define PM2XXX_CH_PRECH_CURRENT_100MA (0x3<<4)
+
+#define PM2XXX_CH_EOC_CURRENT_MASK 0xC0
+#define PM2XXX_CH_EOC_CURRENT_100MA (0x0<<6)
+#define PM2XXX_CH_EOC_CURRENT_150MA (0x1<<6)
+#define PM2XXX_CH_EOC_CURRENT_300MA (0x2<<6)
+#define PM2XXX_CH_EOC_CURRENT_400MA (0x3<<6)
+
+/* control Reg 7 */
+#define PM2XXX_CH_PRECH_VOL_2_5 0x0
+#define PM2XXX_CH_PRECH_VOL_2_7 0x1
+#define PM2XXX_CH_PRECH_VOL_2_9 0x2
+#define PM2XXX_CH_PRECH_VOL_3_1 0x3
+
+#define PM2XXX_CH_VRESUME_VOL_3_2 (0x0<<2)
+#define PM2XXX_CH_VRESUME_VOL_3_4 (0x1<<2)
+#define PM2XXX_CH_VRESUME_VOL_3_6 (0x2<<2)
+#define PM2XXX_CH_VRESUME_VOL_3_8 (0x3<<2)
+
+/* control Reg 8 */
+#define PM2XXX_CH_VOLT_MASK 0x3F
+#define PM2XXX_CH_VOLT_3_5 0x0
+#define PM2XXX_CH_VOLT_3_5225 0x1
+#define PM2XXX_CH_VOLT_3_6 0x4
+#define PM2XXX_CH_VOLT_3_7 0x8
+#define PM2XXX_CH_VOLT_4_0 0x14
+#define PM2XXX_CH_VOLT_4_175 0x1B
+#define PM2XXX_CH_VOLT_4_2 0x1C
+#define PM2XXX_CH_VOLT_4_275 0x1F
+#define PM2XXX_CH_VOLT_4_3 0x20
+
+/*NTC control register 1*/
+#define PM2XXX_BTEMP_HIGH_TH_45 0x0
+#define PM2XXX_BTEMP_HIGH_TH_50 0x1
+#define PM2XXX_BTEMP_HIGH_TH_55 0x2
+#define PM2XXX_BTEMP_HIGH_TH_60 0x3
+#define PM2XXX_BTEMP_HIGH_TH_65 0x4
+
+#define PM2XXX_BTEMP_LOW_TH_N5 (0x0<<3)
+#define PM2XXX_BTEMP_LOW_TH_0 (0x1<<3)
+#define PM2XXX_BTEMP_LOW_TH_5 (0x2<<3)
+#define PM2XXX_BTEMP_LOW_TH_10 (0x3<<3)
+
+/*NTC control register 2*/
+#define PM2XXX_NTC_BETA_COEFF_3477 0x0
+#define PM2XXX_NTC_BETA_COEFF_3964 0x1
+
+#define PM2XXX_NTC_RES_10K (0x0<<2)
+#define PM2XXX_NTC_RES_47K (0x1<<2)
+#define PM2XXX_NTC_RES_100K (0x2<<2)
+#define PM2XXX_NTC_RES_NO_NTC (0x3<<2)
+
+/* control Reg 9 */
+#define PM2XXX_CH_CC_MODEDROP_EN 1
+#define PM2XXX_CH_CC_MODEDROP_DIS 0
+
+#define PM2XXX_CH_CC_REDUCED_CURRENT_100MA (0x0<<1)
+#define PM2XXX_CH_CC_REDUCED_CURRENT_200MA (0x1<<1)
+#define PM2XXX_CH_CC_REDUCED_CURRENT_400MA (0x2<<1)
+#define PM2XXX_CH_CC_REDUCED_CURRENT_IDENT (0x3<<1)
+
+#define PM2XXX_CHARCHING_INFO_DIS (0<<3)
+#define PM2XXX_CHARCHING_INFO_EN (1<<3)
+
+#define PM2XXX_CH_150MV_DROP_300MV (0<<4)
+#define PM2XXX_CH_150MV_DROP_150MV (1<<4)
+
+
+/* charger status register */
+#define PM2XXX_CHG_STATUS_OFF 0x0
+#define PM2XXX_CHG_STATUS_ON 0x1
+#define PM2XXX_CHG_STATUS_FULL 0x2
+#define PM2XXX_CHG_STATUS_ERR 0x3
+#define PM2XXX_CHG_STATUS_WAIT 0x4
+#define PM2XXX_CHG_STATUS_NOBAT 0x5
+
+/* Input charger voltage VPWR2 */
+#define PM2XXX_VPWR2_OVV_6_0 0x0
+#define PM2XXX_VPWR2_OVV_6_3 0x1
+#define PM2XXX_VPWR2_OVV_10 0x2
+#define PM2XXX_VPWR2_OVV_NONE 0x3
+
+/* Input charger drop VPWR2 */
+#define PM2XXX_VPWR2_HW_OPT_EN (0x1<<4)
+#define PM2XXX_VPWR2_HW_OPT_DIS (0x0<<4)
+
+#define PM2XXX_VPWR2_VALID_EN (0x1<<3)
+#define PM2XXX_VPWR2_VALID_DIS (0x0<<3)
+
+#define PM2XXX_VPWR2_DROP_EN (0x1<<2)
+#define PM2XXX_VPWR2_DROP_DIS (0x0<<2)
+
+/* Input charger voltage VPWR1 */
+#define PM2XXX_VPWR1_OVV_6_0 0x0
+#define PM2XXX_VPWR1_OVV_6_3 0x1
+#define PM2XXX_VPWR1_OVV_10 0x2
+#define PM2XXX_VPWR1_OVV_NONE 0x3
+
+/* Input charger drop VPWR1 */
+#define PM2XXX_VPWR1_HW_OPT_EN (0x1<<4)
+#define PM2XXX_VPWR1_HW_OPT_DIS (0x0<<4)
+
+#define PM2XXX_VPWR1_VALID_EN (0x1<<3)
+#define PM2XXX_VPWR1_VALID_DIS (0x0<<3)
+
+#define PM2XXX_VPWR1_DROP_EN (0x1<<2)
+#define PM2XXX_VPWR1_DROP_DIS (0x0<<2)
+
+/* Battery low level comparator control register */
+#define PM2XXX_VBAT_LOW_MONITORING_DIS 0x0
+#define PM2XXX_VBAT_LOW_MONITORING_ENA 0x1
+
+/* Battery low level value control register */
+#define PM2XXX_VBAT_LOW_LEVEL_2_3 0x0
+#define PM2XXX_VBAT_LOW_LEVEL_2_4 0x1
+#define PM2XXX_VBAT_LOW_LEVEL_2_5 0x2
+#define PM2XXX_VBAT_LOW_LEVEL_2_6 0x3
+#define PM2XXX_VBAT_LOW_LEVEL_2_7 0x4
+#define PM2XXX_VBAT_LOW_LEVEL_2_8 0x5
+#define PM2XXX_VBAT_LOW_LEVEL_2_9 0x6
+#define PM2XXX_VBAT_LOW_LEVEL_3_0 0x7
+#define PM2XXX_VBAT_LOW_LEVEL_3_1 0x8
+#define PM2XXX_VBAT_LOW_LEVEL_3_2 0x9
+#define PM2XXX_VBAT_LOW_LEVEL_3_3 0xA
+#define PM2XXX_VBAT_LOW_LEVEL_3_4 0xB
+#define PM2XXX_VBAT_LOW_LEVEL_3_5 0xC
+#define PM2XXX_VBAT_LOW_LEVEL_3_6 0xD
+#define PM2XXX_VBAT_LOW_LEVEL_3_7 0xE
+#define PM2XXX_VBAT_LOW_LEVEL_3_8 0xF
+#define PM2XXX_VBAT_LOW_LEVEL_3_9 0x10
+#define PM2XXX_VBAT_LOW_LEVEL_4_0 0x11
+#define PM2XXX_VBAT_LOW_LEVEL_4_1 0x12
+#define PM2XXX_VBAT_LOW_LEVEL_4_2 0x13
+
+/* SW CTRL */
+#define PM2XXX_SWCTRL_HW 0x0
+#define PM2XXX_SWCTRL_SW 0x1
+
+
+/* LED Driver Control */
+#define PM2XXX_LED_CURRENT_MASK 0x0C
+#define PM2XXX_LED_CURRENT_2_5MA (0X0<<2)
+#define PM2XXX_LED_CURRENT_1MA (0X1<<2)
+#define PM2XXX_LED_CURRENT_5MA (0X2<<2)
+#define PM2XXX_LED_CURRENT_10MA (0X3<<2)
+
+#define PM2XXX_LED_SELECT_MASK 0x02
+#define PM2XXX_LED_SELECT_EN (0X0<<1)
+#define PM2XXX_LED_SELECT_DIS (0X1<<1)
+
+#define PM2XXX_ANTI_OVERSHOOT_MASK 0x01
+#define PM2XXX_ANTI_OVERSHOOT_DIS 0X0
+#define PM2XXX_ANTI_OVERSHOOT_EN 0X1
+
+enum pm2xxx_reg_int1 {
+ PM2XXX_INT1_ITVBATDISCONNECT = 0x02,
+ PM2XXX_INT1_ITVBATLOWR = 0x04,
+ PM2XXX_INT1_ITVBATLOWF = 0x08,
+};
+
+enum pm2xxx_mask_reg_int1 {
+ PM2XXX_INT1_M_ITVBATDISCONNECT = 0x02,
+ PM2XXX_INT1_M_ITVBATLOWR = 0x04,
+ PM2XXX_INT1_M_ITVBATLOWF = 0x08,
+};
+
+enum pm2xxx_source_reg_int1 {
+ PM2XXX_INT1_S_ITVBATDISCONNECT = 0x02,
+ PM2XXX_INT1_S_ITVBATLOWR = 0x04,
+ PM2XXX_INT1_S_ITVBATLOWF = 0x08,
+};
+
+enum pm2xxx_reg_int2 {
+ PM2XXX_INT2_ITVPWR2PLUG = 0x01,
+ PM2XXX_INT2_ITVPWR2UNPLUG = 0x02,
+ PM2XXX_INT2_ITVPWR1PLUG = 0x04,
+ PM2XXX_INT2_ITVPWR1UNPLUG = 0x08,
+};
+
+enum pm2xxx_mask_reg_int2 {
+ PM2XXX_INT2_M_ITVPWR2PLUG = 0x01,
+ PM2XXX_INT2_M_ITVPWR2UNPLUG = 0x02,
+ PM2XXX_INT2_M_ITVPWR1PLUG = 0x04,
+ PM2XXX_INT2_M_ITVPWR1UNPLUG = 0x08,
+};
+
+enum pm2xxx_source_reg_int2 {
+ PM2XXX_INT2_S_ITVPWR2PLUG = 0x03,
+ PM2XXX_INT2_S_ITVPWR1PLUG = 0x0c,
+};
+
+enum pm2xxx_reg_int3 {
+ PM2XXX_INT3_ITCHPRECHARGEWD = 0x01,
+ PM2XXX_INT3_ITCHCCWD = 0x02,
+ PM2XXX_INT3_ITCHCVWD = 0x04,
+ PM2XXX_INT3_ITAUTOTIMEOUTWD = 0x08,
+};
+
+enum pm2xxx_mask_reg_int3 {
+ PM2XXX_INT3_M_ITCHPRECHARGEWD = 0x01,
+ PM2XXX_INT3_M_ITCHCCWD = 0x02,
+ PM2XXX_INT3_M_ITCHCVWD = 0x04,
+ PM2XXX_INT3_M_ITAUTOTIMEOUTWD = 0x08,
+};
+
+enum pm2xxx_source_reg_int3 {
+ PM2XXX_INT3_S_ITCHPRECHARGEWD = 0x01,
+ PM2XXX_INT3_S_ITCHCCWD = 0x02,
+ PM2XXX_INT3_S_ITCHCVWD = 0x04,
+ PM2XXX_INT3_S_ITAUTOTIMEOUTWD = 0x08,
+};
+
+enum pm2xxx_reg_int4 {
+ PM2XXX_INT4_ITBATTEMPCOLD = 0x01,
+ PM2XXX_INT4_ITBATTEMPHOT = 0x02,
+ PM2XXX_INT4_ITVPWR2OVV = 0x04,
+ PM2XXX_INT4_ITVPWR1OVV = 0x08,
+ PM2XXX_INT4_ITCHARGINGON = 0x10,
+ PM2XXX_INT4_ITVRESUME = 0x20,
+ PM2XXX_INT4_ITBATTFULL = 0x40,
+ PM2XXX_INT4_ITCVPHASE = 0x80,
+};
+
+enum pm2xxx_mask_reg_int4 {
+ PM2XXX_INT4_M_ITBATTEMPCOLD = 0x01,
+ PM2XXX_INT4_M_ITBATTEMPHOT = 0x02,
+ PM2XXX_INT4_M_ITVPWR2OVV = 0x04,
+ PM2XXX_INT4_M_ITVPWR1OVV = 0x08,
+ PM2XXX_INT4_M_ITCHARGINGON = 0x10,
+ PM2XXX_INT4_M_ITVRESUME = 0x20,
+ PM2XXX_INT4_M_ITBATTFULL = 0x40,
+ PM2XXX_INT4_M_ITCVPHASE = 0x80,
+};
+
+enum pm2xxx_source_reg_int4 {
+ PM2XXX_INT4_S_ITBATTEMPCOLD = 0x01,
+ PM2XXX_INT4_S_ITBATTEMPHOT = 0x02,
+ PM2XXX_INT4_S_ITVPWR2OVV = 0x04,
+ PM2XXX_INT4_S_ITVPWR1OVV = 0x08,
+ PM2XXX_INT4_S_ITCHARGINGON = 0x10,
+ PM2XXX_INT4_S_ITVRESUME = 0x20,
+ PM2XXX_INT4_S_ITBATTFULL = 0x40,
+ PM2XXX_INT4_S_ITCVPHASE = 0x80,
+};
+
+enum pm2xxx_reg_int5 {
+ PM2XXX_INT5_ITTHERMALSHUTDOWNRISE = 0x01,
+ PM2XXX_INT5_ITTHERMALSHUTDOWNFALL = 0x02,
+ PM2XXX_INT5_ITTHERMALWARNINGRISE = 0x04,
+ PM2XXX_INT5_ITTHERMALWARNINGFALL = 0x08,
+ PM2XXX_INT5_ITVSYSTEMOVV = 0x10,
+};
+
+enum pm2xxx_mask_reg_int5 {
+ PM2XXX_INT5_M_ITTHERMALSHUTDOWNRISE = 0x01,
+ PM2XXX_INT5_M_ITTHERMALSHUTDOWNFALL = 0x02,
+ PM2XXX_INT5_M_ITTHERMALWARNINGRISE = 0x04,
+ PM2XXX_INT5_M_ITTHERMALWARNINGFALL = 0x08,
+ PM2XXX_INT5_M_ITVSYSTEMOVV = 0x10,
+};
+
+enum pm2xxx_source_reg_int5 {
+ PM2XXX_INT5_S_ITTHERMALSHUTDOWNRISE = 0x01,
+ PM2XXX_INT5_S_ITTHERMALSHUTDOWNFALL = 0x02,
+ PM2XXX_INT5_S_ITTHERMALWARNINGRISE = 0x04,
+ PM2XXX_INT5_S_ITTHERMALWARNINGFALL = 0x08,
+ PM2XXX_INT5_S_ITVSYSTEMOVV = 0x10,
+};
+
+enum pm2xxx_reg_int6 {
+ PM2XXX_INT6_ITVPWR2DROP = 0x01,
+ PM2XXX_INT6_ITVPWR1DROP = 0x02,
+ PM2XXX_INT6_ITVPWR2VALIDRISE = 0x04,
+ PM2XXX_INT6_ITVPWR2VALIDFALL = 0x08,
+ PM2XXX_INT6_ITVPWR1VALIDRISE = 0x10,
+ PM2XXX_INT6_ITVPWR1VALIDFALL = 0x20,
+};
+
+enum pm2xxx_mask_reg_int6 {
+ PM2XXX_INT6_M_ITVPWR2DROP = 0x01,
+ PM2XXX_INT6_M_ITVPWR1DROP = 0x02,
+ PM2XXX_INT6_M_ITVPWR2VALIDRISE = 0x04,
+ PM2XXX_INT6_M_ITVPWR2VALIDFALL = 0x08,
+ PM2XXX_INT6_M_ITVPWR1VALIDRISE = 0x10,
+ PM2XXX_INT6_M_ITVPWR1VALIDFALL = 0x20,
+};
+
+enum pm2xxx_source_reg_int6 {
+ PM2XXX_INT6_S_ITVPWR2DROP = 0x01,
+ PM2XXX_INT6_S_ITVPWR1DROP = 0x02,
+ PM2XXX_INT6_S_ITVPWR2VALIDRISE = 0x04,
+ PM2XXX_INT6_S_ITVPWR2VALIDFALL = 0x08,
+ PM2XXX_INT6_S_ITVPWR1VALIDRISE = 0x10,
+ PM2XXX_INT6_S_ITVPWR1VALIDFALL = 0x20,
+};
+
+struct pm2xxx_charger_info {
+ int charger_connected;
+ int charger_online;
+ int cv_active;
+ bool wd_expired;
+};
+
+struct pm2xxx_charger_event_flags {
+ bool mainextchnotok;
+ bool main_thermal_prot;
+ bool ovv;
+ bool chgwdexp;
+};
+
+struct pm2xxx_interrupts {
+ u8 reg[PM2XXX_NUM_INT_REG];
+ int (*handler[PM2XXX_NUM_INT_REG])(void *, int);
+};
+
+struct pm2xxx_config {
+ struct i2c_client *pm2xxx_i2c;
+ struct i2c_device_id *pm2xxx_id;
+};
+
+struct pm2xxx_irq {
+ char *name;
+ irqreturn_t (*isr)(int irq, void *data);
+};
+
+struct pm2xxx_charger {
+ struct device *dev;
+ u8 chip_id;
+ bool vddadc_en_ac;
+ struct pm2xxx_config config;
+ bool ac_conn;
+ unsigned int gpio_irq;
+ int vbat;
+ int old_vbat;
+ int failure_case;
+ int failure_input_ovv;
+ unsigned int lpn_pin;
+ struct pm2xxx_interrupts *pm2_int;
+ struct ab8500_gpadc *gpadc;
+ struct regulator *regu;
+ struct pm2xxx_bm_data *bat;
+ struct mutex lock;
+ struct ab8500 *parent;
+ struct pm2xxx_charger_info ac;
+ struct pm2xxx_charger_platform_data *pdata;
+ struct workqueue_struct *charger_wq;
+ struct delayed_work check_vbat_work;
+ struct work_struct ac_work;
+ struct work_struct check_main_thermal_prot_work;
+ struct ux500_charger ac_chg;
+ struct pm2xxx_charger_event_flags flags;
+};
+
+#endif /* PM2301_CHARGER_H */
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 8a7cfb3cc166..5deac432e2ae 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -141,7 +141,7 @@ int power_supply_set_battery_charged(struct power_supply *psy)
}
EXPORT_SYMBOL_GPL(power_supply_set_battery_charged);
-static int power_supply_match_device_by_name(struct device *dev, void *data)
+static int power_supply_match_device_by_name(struct device *dev, const void *data)
{
const char *name = data;
struct power_supply *psy = dev_get_drvdata(dev);
@@ -149,7 +149,7 @@ static int power_supply_match_device_by_name(struct device *dev, void *data)
return strcmp(psy->name, name) == 0;
}
-struct power_supply *power_supply_get_by_name(char *name)
+struct power_supply *power_supply_get_by_name(const char *name)
{
struct device *dev = class_find_device(power_supply_class, NULL, name,
power_supply_match_device_by_name);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 40fa3b7cae54..29178f78d73c 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -55,7 +55,8 @@ static ssize_t power_supply_show_property(struct device *dev,
};
static char *health_text[] = {
"Unknown", "Good", "Overheat", "Dead", "Over voltage",
- "Unspecified failure", "Cold",
+ "Unspecified failure", "Cold", "Watchdog timer expire",
+ "Safety timer expire"
};
static char *technology_text[] = {
"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 6461b489fb09..1ae65b822864 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -13,3 +13,20 @@ config POWER_RESET_GPIO
This driver supports turning off your board via a GPIO line.
If your board needs a GPIO high/low to power down, say Y and
create a binding in your devicetree.
+
+config POWER_RESET_QNAP
+ bool "QNAP power-off driver"
+ depends on OF_GPIO && POWER_RESET && PLAT_ORION
+ help
+ This driver supports turning off QNAP NAS devices by sending
+ commands to the microcontroller which controls the main power.
+
+ Say Y if you have a QNAP NAS.
+
+config POWER_RESET_RESTART
+ bool "Restart power-off driver"
+ depends on ARM
+ help
+ Some boards don't actually have the ability to power off.
+ Instead they restart, and u-boot holds the SoC until the
+ user presses a key. u-boot then boots into Linux.
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 751488a4a0c5..0f317f50c56f 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -1 +1,3 @@
obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
+obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
+obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o \ No newline at end of file
diff --git a/drivers/power/reset/qnap-poweroff.c b/drivers/power/reset/qnap-poweroff.c
new file mode 100644
index 000000000000..37f56f7ee926
--- /dev/null
+++ b/drivers/power/reset/qnap-poweroff.c
@@ -0,0 +1,116 @@
+/*
+ * QNAP Turbo NAS Board power off
+ *
+ * Copyright (C) 2012 Andrew Lunn <andrew@lunn.ch>
+ *
+ * Based on the code from:
+ *
+ * Copyright (C) 2009 Martin Michlmayr <tbm@cyrius.com>
+ * Copyright (C) 2008 Byron Bradley <byron.bbradley@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/serial_reg.h>
+#include <linux/kallsyms.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#define UART1_REG(x) (base + ((UART_##x) << 2))
+
+static void __iomem *base;
+static unsigned long tclk;
+
+static void qnap_power_off(void)
+{
+ /* 19200 baud divisor */
+ const unsigned divisor = ((tclk + (8 * 19200)) / (16 * 19200));
+
+ pr_err("%s: triggering power-off...\n", __func__);
+
+ /* hijack UART1 and reset into sane state (19200,8n1) */
+ writel(0x83, UART1_REG(LCR));
+ writel(divisor & 0xff, UART1_REG(DLL));
+ writel((divisor >> 8) & 0xff, UART1_REG(DLM));
+ writel(0x03, UART1_REG(LCR));
+ writel(0x00, UART1_REG(IER));
+ writel(0x00, UART1_REG(FCR));
+ writel(0x00, UART1_REG(MCR));
+
+ /* send the power-off command 'A' to PIC */
+ writel('A', UART1_REG(TX));
+}
+
+static int qnap_power_off_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct clk *clk;
+ char symname[KSYM_NAME_LEN];
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Missing resource");
+ return -EINVAL;
+ }
+
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!base) {
+ dev_err(&pdev->dev, "Unable to map resource");
+ return -EINVAL;
+ }
+
+ /* We need to know tclk in order to calculate the UART divisor */
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Clk missing");
+ return PTR_ERR(clk);
+ }
+
+ tclk = clk_get_rate(clk);
+
+ /* Check that nothing else has already setup a handler */
+ if (pm_power_off) {
+ lookup_symbol_name((ulong)pm_power_off, symname);
+ dev_err(&pdev->dev,
+ "pm_power_off already claimed %p %s",
+ pm_power_off, symname);
+ return -EBUSY;
+ }
+ pm_power_off = qnap_power_off;
+
+ return 0;
+}
+
+static int qnap_power_off_remove(struct platform_device *pdev)
+{
+ pm_power_off = NULL;
+ return 0;
+}
+
+static const struct of_device_id qnap_power_off_of_match_table[] = {
+ { .compatible = "qnap,power-off", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qnap_power_off_of_match_table);
+
+static struct platform_driver qnap_power_off_driver = {
+ .probe = qnap_power_off_probe,
+ .remove = qnap_power_off_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "qnap_power_off",
+ .of_match_table = of_match_ptr(qnap_power_off_of_match_table),
+ },
+};
+module_platform_driver(qnap_power_off_driver);
+
+MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
+MODULE_DESCRIPTION("QNAP Power off driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c
new file mode 100644
index 000000000000..059cd1501e2a
--- /dev/null
+++ b/drivers/power/reset/restart-poweroff.c
@@ -0,0 +1,65 @@
+/*
+ * Power off by restarting and let u-boot keep hold of the machine
+ * until the user presses a button for example.
+ *
+ * Andrew Lunn <andrew@lunn.ch>
+ *
+ * Copyright (C) 2012 Andrew Lunn
+ *
+ * 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/of_platform.h>
+#include <linux/module.h>
+#include <asm/system_misc.h>
+
+static void restart_poweroff_do_poweroff(void)
+{
+ arm_pm_restart('h', NULL);
+}
+
+static int restart_poweroff_probe(struct platform_device *pdev)
+{
+ /* If a pm_power_off function has already been added, leave it alone */
+ if (pm_power_off != NULL) {
+ dev_err(&pdev->dev,
+ "pm_power_off function already registered");
+ return -EBUSY;
+ }
+
+ pm_power_off = &restart_poweroff_do_poweroff;
+ return 0;
+}
+
+static int restart_poweroff_remove(struct platform_device *pdev)
+{
+ if (pm_power_off == &restart_poweroff_do_poweroff)
+ pm_power_off = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id of_restart_poweroff_match[] = {
+ { .compatible = "restart-poweroff", },
+ {},
+};
+
+static struct platform_driver restart_poweroff_driver = {
+ .probe = restart_poweroff_probe,
+ .remove = restart_poweroff_remove,
+ .driver = {
+ .name = "poweroff-restart",
+ .owner = THIS_MODULE,
+ .of_match_table = of_restart_poweroff_match,
+ },
+};
+module_platform_driver(restart_poweroff_driver);
+
+MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch");
+MODULE_DESCRIPTION("restart poweroff driver");
+MODULE_LICENSE("GPLv2");
+MODULE_ALIAS("platform:poweroff-restart");
diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig
index 445197d4a8c4..6efd9b60d8ff 100644
--- a/drivers/pps/clients/Kconfig
+++ b/drivers/pps/clients/Kconfig
@@ -17,7 +17,7 @@ config PPS_CLIENT_KTIMER
config PPS_CLIENT_LDISC
tristate "PPS line discipline"
- depends on PPS
+ depends on PPS && TTY
help
If you say yes here you get support for a PPS source connected
with the CD (Carrier Detect) pin of your serial port.
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
index 79451f2dea6a..73bd3bb4d93b 100644
--- a/drivers/pps/clients/pps-ldisc.c
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -25,18 +25,27 @@
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/pps_kernel.h>
+#include <linux/bug.h>
#define PPS_TTY_MAGIC 0x0001
-static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
- struct pps_event_time *ts)
+static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
{
- struct pps_device *pps = (struct pps_device *)tty->disc_data;
+ struct pps_device *pps;
+ struct pps_event_time ts;
+
+ pps_get_ts(&ts);
- BUG_ON(pps == NULL);
+ pps = pps_lookup_dev(tty);
+ /*
+ * This should never fail, but the ldisc locking is very
+ * convoluted, so don't crash just in case.
+ */
+ if (WARN_ON_ONCE(pps == NULL))
+ return;
/* Now do the PPS event report */
- pps_event(pps, ts, status ? PPS_CAPTUREASSERT :
+ pps_event(pps, &ts, status ? PPS_CAPTUREASSERT :
PPS_CAPTURECLEAR, NULL);
dev_dbg(pps->dev, "PPS %s at %lu\n",
@@ -67,9 +76,9 @@ static int pps_tty_open(struct tty_struct *tty)
pr_err("cannot register PPS source \"%s\"\n", info.path);
return -ENOMEM;
}
- tty->disc_data = pps;
+ pps->lookup_cookie = tty;
- /* Should open N_TTY ldisc too */
+ /* Now open the base class N_TTY ldisc */
ret = alias_n_tty_open(tty);
if (ret < 0) {
pr_err("cannot open tty ldisc \"%s\"\n", info.path);
@@ -81,7 +90,6 @@ static int pps_tty_open(struct tty_struct *tty)
return 0;
err_unregister:
- tty->disc_data = NULL;
pps_unregister_source(pps);
return ret;
}
@@ -90,11 +98,13 @@ static void (*alias_n_tty_close)(struct tty_struct *tty);
static void pps_tty_close(struct tty_struct *tty)
{
- struct pps_device *pps = (struct pps_device *)tty->disc_data;
+ struct pps_device *pps = pps_lookup_dev(tty);
alias_n_tty_close(tty);
- tty->disc_data = NULL;
+ if (WARN_ON(!pps))
+ return;
+
dev_info(pps->dev, "removed\n");
pps_unregister_source(pps);
}
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 2420d5af0583..6437703eb10f 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -247,12 +247,15 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
struct pps_device *pps = container_of(inode->i_cdev,
struct pps_device, cdev);
file->private_data = pps;
-
+ kobject_get(&pps->dev->kobj);
return 0;
}
static int pps_cdev_release(struct inode *inode, struct file *file)
{
+ struct pps_device *pps = container_of(inode->i_cdev,
+ struct pps_device, cdev);
+ kobject_put(&pps->dev->kobj);
return 0;
}
@@ -274,8 +277,10 @@ static void pps_device_destruct(struct device *dev)
{
struct pps_device *pps = dev_get_drvdata(dev);
- /* release id here to protect others from using it while it's
- * still in use */
+ cdev_del(&pps->cdev);
+
+ /* Now we can release the ID for re-use */
+ pr_debug("deallocating pps%d\n", pps->id);
mutex_lock(&pps_idr_lock);
idr_remove(&pps_idr, pps->id);
mutex_unlock(&pps_idr_lock);
@@ -332,6 +337,7 @@ int pps_register_cdev(struct pps_device *pps)
goto del_cdev;
}
+ /* Override the release function with our own */
pps->dev->release = pps_device_destruct;
pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
@@ -352,11 +358,44 @@ free_idr:
void pps_unregister_cdev(struct pps_device *pps)
{
+ pr_debug("unregistering pps%d\n", pps->id);
+ pps->lookup_cookie = NULL;
device_destroy(pps_class, pps->dev->devt);
- cdev_del(&pps->cdev);
}
/*
+ * Look up a pps device by magic cookie.
+ * The cookie is usually a pointer to some enclosing device, but this
+ * code doesn't care; you should never be dereferencing it.
+ *
+ * This is a bit of a kludge that is currently used only by the PPS
+ * serial line discipline. It may need to be tweaked when a second user
+ * is found.
+ *
+ * There is no function interface for setting the lookup_cookie field.
+ * It's initialized to NULL when the pps device is created, and if a
+ * client wants to use it, just fill it in afterward.
+ *
+ * The cookie is automatically set to NULL in pps_unregister_source()
+ * so that it will not be used again, even if the pps device cannot
+ * be removed from the idr due to pending references holding the minor
+ * number in use.
+ */
+struct pps_device *pps_lookup_dev(void const *cookie)
+{
+ struct pps_device *pps;
+ unsigned id;
+
+ rcu_read_lock();
+ idr_for_each_entry(&pps_idr, pps, id)
+ if (cookie == pps->lookup_cookie)
+ break;
+ rcu_read_unlock();
+ return pps;
+}
+EXPORT_SYMBOL(pps_lookup_dev);
+
+/*
* Module stuff
*/
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index 65a86bdeabed..3f5677b7690e 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -274,9 +274,9 @@ static int imx_pwm_probe(struct platform_device *pdev)
return -ENODEV;
}
- imx->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
- if (imx->mmio_base == NULL)
- return -EADDRNOTAVAIL;
+ imx->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(imx->mmio_base))
+ return PTR_ERR(imx->mmio_base);
data = of_id->data;
imx->config = data->config;
diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c
index 14106440294f..b3f0d0dfd748 100644
--- a/drivers/pwm/pwm-lpc32xx.c
+++ b/drivers/pwm/pwm-lpc32xx.c
@@ -110,9 +110,9 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
if (!res)
return -EINVAL;
- lpc32xx->base = devm_request_and_ioremap(&pdev->dev, res);
- if (!lpc32xx->base)
- return -EADDRNOTAVAIL;
+ lpc32xx->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(lpc32xx->base))
+ return PTR_ERR(lpc32xx->base);
lpc32xx->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(lpc32xx->clk))
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
index 7ec345f01831..a53d3094b75a 100644
--- a/drivers/pwm/pwm-mxs.c
+++ b/drivers/pwm/pwm-mxs.c
@@ -139,9 +139,9 @@ static int mxs_pwm_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mxs->base = devm_request_and_ioremap(&pdev->dev, res);
- if (!mxs->base)
- return -EADDRNOTAVAIL;
+ mxs->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mxs->base))
+ return PTR_ERR(mxs->base);
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl))
diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c
index b882f6032fee..db964e6ecf5c 100644
--- a/drivers/pwm/pwm-puv3.c
+++ b/drivers/pwm/pwm-puv3.c
@@ -123,9 +123,9 @@ static int pwm_probe(struct platform_device *pdev)
return -ENODEV;
}
- puv3->base = devm_request_and_ioremap(&pdev->dev, r);
- if (puv3->base == NULL)
- return -EADDRNOTAVAIL;
+ puv3->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(puv3->base))
+ return PTR_ERR(puv3->base);
puv3->chip.dev = &pdev->dev;
puv3->chip.ops = &puv3_pwm_ops;
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index f32fc4e66e0c..20370e61de5a 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -165,9 +165,9 @@ static int pwm_probe(struct platform_device *pdev)
return -ENODEV;
}
- pwm->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
- if (pwm->mmio_base == NULL)
- return -EADDRNOTAVAIL;
+ pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(pwm->mmio_base))
+ return PTR_ERR(pwm->mmio_base);
ret = pwmchip_add(&pwm->chip);
if (ret < 0) {
diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c
index 83b21d9d5cf9..69a2d9eb34db 100644
--- a/drivers/pwm/pwm-spear.c
+++ b/drivers/pwm/pwm-spear.c
@@ -192,9 +192,9 @@ static int spear_pwm_probe(struct platform_device *pdev)
return -ENOMEM;
}
- pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
- if (!pc->mmio_base)
- return -EADDRNOTAVAIL;
+ pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(pc->mmio_base))
+ return PTR_ERR(pc->mmio_base);
pc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pc->clk))
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index 30c0e2b70ce8..71900e8cd3d1 100644
--- a/drivers/pwm/pwm-tegra.c
+++ b/drivers/pwm/pwm-tegra.c
@@ -186,9 +186,9 @@ static int tegra_pwm_probe(struct platform_device *pdev)
return -ENODEV;
}
- pwm->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
- if (!pwm->mmio_base)
- return -EADDRNOTAVAIL;
+ pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(pwm->mmio_base))
+ return PTR_ERR(pwm->mmio_base);
platform_set_drvdata(pdev, pwm);
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 5cf016dd9822..27a67d6b27c1 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -238,9 +238,9 @@ static int ecap_pwm_probe(struct platform_device *pdev)
return -ENODEV;
}
- pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
- if (!pc->mmio_base)
- return -EADDRNOTAVAIL;
+ pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(pc->mmio_base))
+ return PTR_ERR(pc->mmio_base);
ret = pwmchip_add(&pc->chip);
if (ret < 0) {
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 72a6dd40c9ec..5a1399580533 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -453,9 +453,9 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
return -ENODEV;
}
- pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
- if (!pc->mmio_base)
- return -EADDRNOTAVAIL;
+ pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(pc->mmio_base))
+ return PTR_ERR(pc->mmio_base);
/* Acquire tbclk for Time Base EHRPWM submodule */
pc->tbclk = devm_clk_get(&pdev->dev, "tbclk");
diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/pwm/pwm-tipwmss.c
index 3448a1c88590..17cbc59660ec 100644
--- a/drivers/pwm/pwm-tipwmss.c
+++ b/drivers/pwm/pwm-tipwmss.c
@@ -75,9 +75,9 @@ static int pwmss_probe(struct platform_device *pdev)
return -ENODEV;
}
- info->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
- if (!info->mmio_base)
- return -EADDRNOTAVAIL;
+ info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(info->mmio_base))
+ return PTR_ERR(info->mmio_base);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
index b0ba2d403439..f9de9b28e46e 100644
--- a/drivers/pwm/pwm-vt8500.c
+++ b/drivers/pwm/pwm-vt8500.c
@@ -178,9 +178,9 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
return -ENODEV;
}
- chip->base = devm_request_and_ioremap(&pdev->dev, r);
- if (!chip->base)
- return -EADDRNOTAVAIL;
+ chip->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(chip->base))
+ return PTR_ERR(chip->base);
ret = clk_prepare(chip->clk);
if (ret < 0) {
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 2b557119adad..c79ab843333e 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -30,8 +30,6 @@ struct pm8607_regulator_info {
unsigned int *vol_table;
unsigned int *vol_suspend;
- int update_reg;
- int update_bit;
int slope_double;
};
@@ -222,29 +220,6 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
return ret;
}
-static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
-{
- struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- uint8_t val;
- int ret;
-
- val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1));
-
- ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg,
- rdev->desc->vsel_mask, val);
- if (ret)
- return ret;
- switch (info->desc.id) {
- case PM8607_ID_BUCK1:
- case PM8607_ID_BUCK3:
- ret = pm860x_set_bits(info->i2c, info->update_reg,
- 1 << info->update_bit,
- 1 << info->update_bit);
- break;
- }
- return ret;
-}
-
static int pm8606_preg_enable(struct regulator_dev *rdev)
{
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
@@ -276,7 +251,7 @@ static int pm8606_preg_is_enabled(struct regulator_dev *rdev)
static struct regulator_ops pm8607_regulator_ops = {
.list_voltage = pm8607_list_voltage,
- .set_voltage_sel = pm8607_set_voltage_sel,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -313,11 +288,11 @@ static struct regulator_ops pm8606_preg_ops = {
.n_voltages = ARRAY_SIZE(vreg##_table), \
.vsel_reg = PM8607_##vreg, \
.vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \
+ .apply_reg = PM8607_##ureg, \
+ .apply_bit = (ubit), \
.enable_reg = PM8607_##ereg, \
.enable_mask = 1 << (ebit), \
}, \
- .update_reg = PM8607_##ureg, \
- .update_bit = (ubit), \
.slope_double = (0), \
.vol_table = (unsigned int *)&vreg##_table, \
.vol_suspend = (unsigned int *)&vreg##_suspend_table, \
@@ -343,9 +318,9 @@ static struct regulator_ops pm8606_preg_ops = {
}
static struct pm8607_regulator_info pm8607_regulator_info[] = {
- PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0),
- PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1),
- PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2),
+ PM8607_DVC(BUCK1, GO, BIT(0), SUPPLIES_EN11, 0),
+ PM8607_DVC(BUCK2, GO, BIT(1), SUPPLIES_EN11, 1),
+ PM8607_DVC(BUCK3, GO, BIT(2), SUPPLIES_EN11, 2),
PM8607_LDO(1, LDO1, 0, SUPPLIES_EN11, 3),
PM8607_LDO(2, LDO2, 0, SUPPLIES_EN11, 4),
@@ -372,7 +347,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
struct regulator_config *config)
{
struct device_node *nproot, *np;
- nproot = pdev->dev.parent->of_node;
+ nproot = of_node_get(pdev->dev.parent->of_node);
if (!nproot)
return -ENODEV;
nproot = of_find_node_by_name(nproot, "regulators");
@@ -388,6 +363,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
break;
}
}
+ of_node_put(nproot);
return 0;
}
#else
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 551a22b07538..a5d97eaee99e 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -91,6 +91,7 @@ config REGULATOR_AAT2870
config REGULATOR_ARIZONA
tristate "Wolfson Arizona class devices"
depends on MFD_ARIZONA
+ depends on SND_SOC
help
Support for the regulators found on Wolfson Arizona class
devices.
@@ -277,6 +278,15 @@ config REGULATOR_LP872X
help
This driver supports LP8720/LP8725 PMIC
+config REGULATOR_LP8755
+ tristate "TI LP8755 High Performance PMU driver"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver supports LP8755 High Performance PMU driver. This
+ chip contains six step-down DC/DC converters which can support
+ 9 mode multiphase configuration.
+
config REGULATOR_LP8788
bool "TI LP8788 Power Regulators"
depends on MFD_LP8788
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index b802b0c7fb02..6e8250382def 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
+obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 8f39cac661d2..0d4a8ccbb536 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -31,12 +31,18 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
+#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */
+#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */
+
struct anatop_regulator {
const char *name;
u32 control_reg;
struct regmap *anatop;
int vol_bit_shift;
int vol_bit_width;
+ u32 delay_reg;
+ int delay_bit_shift;
+ int delay_bit_width;
int min_bit_val;
int min_voltage;
int max_voltage;
@@ -55,6 +61,32 @@ static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg,
return regulator_set_voltage_sel_regmap(reg, selector);
}
+static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
+ unsigned int old_sel,
+ unsigned int new_sel)
+{
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+ u32 val;
+ int ret = 0;
+
+ /* check whether need to care about LDO ramp up speed */
+ if (anatop_reg->delay_bit_width && new_sel > old_sel) {
+ /*
+ * the delay for LDO ramp up time is
+ * based on the register setting, we need
+ * to calculate how many steps LDO need to
+ * ramp up, and how much delay needed. (us)
+ */
+ regmap_read(anatop_reg->anatop, anatop_reg->delay_reg, &val);
+ val = (val >> anatop_reg->delay_bit_shift) &
+ ((1 << anatop_reg->delay_bit_width) - 1);
+ ret = (new_sel - old_sel) * (LDO_RAMP_UP_UNIT_IN_CYCLES <<
+ val) / LDO_RAMP_UP_FREQ_IN_MHZ + 1;
+ }
+
+ return ret;
+}
+
static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
{
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
@@ -67,6 +99,7 @@ static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
static struct regulator_ops anatop_rops = {
.set_voltage_sel = anatop_regmap_set_voltage_sel,
+ .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
.get_voltage_sel = anatop_regmap_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
@@ -143,6 +176,14 @@ static int anatop_regulator_probe(struct platform_device *pdev)
goto anatop_probe_end;
}
+ /* read LDO ramp up setting, only for core reg */
+ of_property_read_u32(np, "anatop-delay-reg-offset",
+ &sreg->delay_reg);
+ of_property_read_u32(np, "anatop-delay-bit-width",
+ &sreg->delay_bit_width);
+ of_property_read_u32(np, "anatop-delay-bit-shift",
+ &sreg->delay_bit_shift);
+
rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1
+ sreg->min_bit_val;
rdesc->min_uV = sreg->min_voltage;
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index a6d040cbf8ac..e87536bf0bed 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -21,6 +21,8 @@
#include <linux/regulator/machine.h>
#include <linux/gpio.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/soc.h>
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/pdata.h>
@@ -34,6 +36,8 @@ struct arizona_micsupp {
struct regulator_consumer_supply supply;
struct regulator_init_data init_data;
+
+ struct work_struct check_cp_work;
};
static int arizona_micsupp_list_voltage(struct regulator_dev *rdev,
@@ -72,9 +76,73 @@ static int arizona_micsupp_map_voltage(struct regulator_dev *rdev,
return selector;
}
+static void arizona_micsupp_check_cp(struct work_struct *work)
+{
+ struct arizona_micsupp *micsupp =
+ container_of(work, struct arizona_micsupp, check_cp_work);
+ struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm;
+ struct arizona *arizona = micsupp->arizona;
+ struct regmap *regmap = arizona->regmap;
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(regmap, ARIZONA_MIC_CHARGE_PUMP_1, &reg);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to read CP state: %d\n", ret);
+ return;
+ }
+
+ if (dapm) {
+ if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
+ ARIZONA_CPMIC_ENA)
+ snd_soc_dapm_force_enable_pin(dapm, "MICSUPP");
+ else
+ snd_soc_dapm_disable_pin(dapm, "MICSUPP");
+
+ snd_soc_dapm_sync(dapm);
+ }
+}
+
+static int arizona_micsupp_enable(struct regulator_dev *rdev)
+{
+ struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = regulator_enable_regmap(rdev);
+
+ if (ret == 0)
+ schedule_work(&micsupp->check_cp_work);
+
+ return ret;
+}
+
+static int arizona_micsupp_disable(struct regulator_dev *rdev)
+{
+ struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = regulator_disable_regmap(rdev);
+ if (ret == 0)
+ schedule_work(&micsupp->check_cp_work);
+
+ return ret;
+}
+
+static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena)
+{
+ struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = regulator_set_bypass_regmap(rdev, ena);
+ if (ret == 0)
+ schedule_work(&micsupp->check_cp_work);
+
+ return ret;
+}
+
static struct regulator_ops arizona_micsupp_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
+ .enable = arizona_micsupp_enable,
+ .disable = arizona_micsupp_disable,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = arizona_micsupp_list_voltage,
@@ -84,7 +152,7 @@ static struct regulator_ops arizona_micsupp_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_bypass = regulator_get_bypass_regmap,
- .set_bypass = regulator_set_bypass_regmap,
+ .set_bypass = arizona_micsupp_set_bypass,
};
static const struct regulator_desc arizona_micsupp = {
@@ -109,7 +177,8 @@ static const struct regulator_desc arizona_micsupp = {
static const struct regulator_init_data arizona_micsupp_default = {
.constraints = {
.valid_ops_mask = REGULATOR_CHANGE_STATUS |
- REGULATOR_CHANGE_VOLTAGE,
+ REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_BYPASS,
.min_uV = 1700000,
.max_uV = 3300000,
},
@@ -131,6 +200,7 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
}
micsupp->arizona = arizona;
+ INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
/*
* Since the chip usually supplies itself we provide some
diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index 2f1341db38a0..f0ba8c4eefa9 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -303,7 +303,7 @@ static int as3711_regulator_probe(struct platform_device *pdev)
reg_data = pdata ? pdata->init_data[id] : NULL;
/* No need to register if there is no regulator data */
- if (!ri->desc.name)
+ if (!reg_data)
continue;
reg = &regs[id];
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 278584302f2d..da9782bd27d0 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -200,8 +200,8 @@ static int regulator_check_consumers(struct regulator_dev *rdev,
}
if (*min_uV > *max_uV) {
- dev_err(regulator->dev, "Restricting voltage, %u-%uuV\n",
- regulator->min_uV, regulator->max_uV);
+ rdev_err(rdev, "Restricting voltage, %u-%uuV\n",
+ *min_uV, *max_uV);
return -EINVAL;
}
@@ -2080,10 +2080,20 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap);
*/
int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
{
+ int ret;
+
sel <<= ffs(rdev->desc->vsel_mask) - 1;
- return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
rdev->desc->vsel_mask, sel);
+ if (ret)
+ return ret;
+
+ if (rdev->desc->apply_bit)
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+ rdev->desc->apply_bit,
+ rdev->desc->apply_bit);
+ return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
@@ -2229,8 +2239,11 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
best_val = rdev->desc->ops->list_voltage(rdev, ret);
if (min_uV <= best_val && max_uV >= best_val) {
selector = ret;
- ret = rdev->desc->ops->set_voltage_sel(rdev,
- ret);
+ if (old_selector == selector)
+ ret = 0;
+ else
+ ret = rdev->desc->ops->set_voltage_sel(
+ rdev, ret);
} else {
ret = -EINVAL;
}
@@ -2241,7 +2254,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
/* Call set_voltage_time_sel if successfully obtained old_selector */
if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
- rdev->desc->ops->set_voltage_time_sel) {
+ old_selector != selector && rdev->desc->ops->set_voltage_time_sel) {
delay = rdev->desc->ops->set_voltage_time_sel(rdev,
old_selector, selector);
@@ -2294,6 +2307,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
{
struct regulator_dev *rdev = regulator->rdev;
int ret = 0;
+ int old_min_uV, old_max_uV;
mutex_lock(&rdev->mutex);
@@ -2315,18 +2329,29 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
if (ret < 0)
goto out;
+
+ /* restore original values in case of error */
+ old_min_uV = regulator->min_uV;
+ old_max_uV = regulator->max_uV;
regulator->min_uV = min_uV;
regulator->max_uV = max_uV;
ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
if (ret < 0)
- goto out;
+ goto out2;
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
-
+ if (ret < 0)
+ goto out2;
+
out:
mutex_unlock(&rdev->mutex);
return ret;
+out2:
+ regulator->min_uV = old_min_uV;
+ regulator->max_uV = old_max_uV;
+ mutex_unlock(&rdev->mutex);
+ return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_voltage);
@@ -3208,7 +3233,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
if (status < 0)
return status;
}
- if (ops->is_enabled) {
+ if (rdev->ena_gpio || ops->is_enabled) {
status = device_create_file(dev, &dev_attr_state);
if (status < 0)
return status;
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index d0963090442d..96b569abb46c 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -70,7 +70,6 @@ struct da9052_regulator_info {
int step_uV;
int min_uV;
int max_uV;
- unsigned char activate_bit;
};
struct da9052_regulator {
@@ -210,36 +209,6 @@ static int da9052_map_voltage(struct regulator_dev *rdev,
return sel;
}
-static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,
- unsigned int selector)
-{
- struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
- struct da9052_regulator_info *info = regulator->info;
- int id = rdev_get_id(rdev);
- int ret;
-
- ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg,
- rdev->desc->vsel_mask, selector);
- if (ret < 0)
- return ret;
-
- /* Some LDOs and DCDCs are DVC controlled which requires enabling of
- * the activate bit to implment the changes on the output.
- */
- switch (id) {
- case DA9052_ID_BUCK1:
- case DA9052_ID_BUCK2:
- case DA9052_ID_BUCK3:
- case DA9052_ID_LDO2:
- case DA9052_ID_LDO3:
- ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
- info->activate_bit, info->activate_bit);
- break;
- }
-
- return ret;
-}
-
static struct regulator_ops da9052_dcdc_ops = {
.get_current_limit = da9052_dcdc_get_current_limit,
.set_current_limit = da9052_dcdc_set_current_limit,
@@ -247,7 +216,7 @@ static struct regulator_ops da9052_dcdc_ops = {
.list_voltage = da9052_list_voltage,
.map_voltage = da9052_map_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_sel = da9052_regulator_set_voltage_sel,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -257,7 +226,7 @@ static struct regulator_ops da9052_ldo_ops = {
.list_voltage = da9052_list_voltage,
.map_voltage = da9052_map_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_sel = da9052_regulator_set_voltage_sel,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -274,13 +243,14 @@ static struct regulator_ops da9052_ldo_ops = {
.owner = THIS_MODULE,\
.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
.vsel_mask = (1 << (sbits)) - 1,\
+ .apply_reg = DA9052_SUPPLY_REG, \
+ .apply_bit = (abits), \
.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
.enable_mask = 1 << (ebits),\
},\
.min_uV = (min) * 1000,\
.max_uV = (max) * 1000,\
.step_uV = (step) * 1000,\
- .activate_bit = (abits),\
}
#define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \
@@ -294,13 +264,14 @@ static struct regulator_ops da9052_ldo_ops = {
.owner = THIS_MODULE,\
.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
.vsel_mask = (1 << (sbits)) - 1,\
+ .apply_reg = DA9052_SUPPLY_REG, \
+ .apply_bit = (abits), \
.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
.enable_mask = 1 << (ebits),\
},\
.min_uV = (min) * 1000,\
.max_uV = (max) * 1000,\
.step_uV = (step) * 1000,\
- .activate_bit = (abits),\
}
static struct da9052_regulator_info da9052_regulator_info[] = {
@@ -395,9 +366,9 @@ static int da9052_regulator_probe(struct platform_device *pdev)
config.init_data = pdata->regulators[pdev->id];
} else {
#ifdef CONFIG_OF
- struct device_node *nproot = da9052->dev->of_node;
- struct device_node *np;
+ struct device_node *nproot, *np;
+ nproot = of_node_get(da9052->dev->of_node);
if (!nproot)
return -ENODEV;
@@ -414,6 +385,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
break;
}
}
+ of_node_put(nproot);
#endif
}
diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c
index 1a05ac66878f..30221099d09c 100644
--- a/drivers/regulator/da9055-regulator.c
+++ b/drivers/regulator/da9055-regulator.c
@@ -58,7 +58,6 @@ struct da9055_volt_reg {
int reg_b;
int sl_shift;
int v_mask;
- int v_shift;
};
struct da9055_mode_reg {
@@ -388,7 +387,6 @@ static struct regulator_ops da9055_ldo_ops = {
.reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \
.sl_shift = 7,\
.v_mask = (1 << (vbits)) - 1,\
- .v_shift = (vbits),\
},\
}
@@ -417,7 +415,6 @@ static struct regulator_ops da9055_ldo_ops = {
.reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \
.sl_shift = 7,\
.v_mask = (1 << (vbits)) - 1,\
- .v_shift = (vbits),\
},\
.mode = {\
.reg = DA9055_REG_BCORE_MODE,\
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index bae681ccd3ea..9d39eb4aafa3 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -132,7 +132,7 @@ static struct regulator_ops gpio_regulator_voltage_ops = {
.list_voltage = gpio_regulator_list_voltage,
};
-struct gpio_regulator_config *
+static struct gpio_regulator_config *
of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
{
struct gpio_regulator_config *config;
@@ -163,10 +163,7 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0);
/* Fetch GPIOs. */
- for (i = 0; ; i++)
- if (of_get_named_gpio(np, "gpios", i) < 0)
- break;
- config->nr_gpios = i;
+ config->nr_gpios = of_gpio_count(np);
config->gpios = devm_kzalloc(dev,
sizeof(struct gpio) * config->nr_gpios,
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 5f68ff11a298..9cb2c0f34515 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -73,8 +73,6 @@ static const unsigned int buck_voltage_map[] = {
};
#define BUCK_TARGET_VOL_MASK 0x3f
-#define BUCK_TARGET_VOL_MIN_IDX 0x01
-#define BUCK_TARGET_VOL_MAX_IDX 0x19
#define LP3971_BUCK_RAMP_REG(x) (buck_base_addr[x]+2)
@@ -140,7 +138,7 @@ static int lp3971_ldo_disable(struct regulator_dev *dev)
return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0);
}
-static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
+static int lp3971_ldo_get_voltage_sel(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3971_LDO1;
@@ -149,7 +147,7 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
- return dev->desc->volt_table[val];
+ return val;
}
static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
@@ -168,7 +166,7 @@ static struct regulator_ops lp3971_ldo_ops = {
.is_enabled = lp3971_ldo_is_enabled,
.enable = lp3971_ldo_enable,
.disable = lp3971_ldo_disable,
- .get_voltage = lp3971_ldo_get_voltage,
+ .get_voltage_sel = lp3971_ldo_get_voltage_sel,
.set_voltage_sel = lp3971_ldo_set_voltage_sel,
};
@@ -201,24 +199,16 @@ static int lp3971_dcdc_disable(struct regulator_dev *dev)
return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0);
}
-static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
+static int lp3971_dcdc_get_voltage_sel(struct regulator_dev *dev)
{
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3971_DCDC1;
u16 reg;
- int val;
reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck));
reg &= BUCK_TARGET_VOL_MASK;
- if (reg <= BUCK_TARGET_VOL_MAX_IDX)
- val = buck_voltage_map[reg];
- else {
- val = 0;
- dev_warn(&dev->dev, "chip reported incorrect voltage value.\n");
- }
-
- return val;
+ return reg;
}
static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
@@ -249,7 +239,7 @@ static struct regulator_ops lp3971_dcdc_ops = {
.is_enabled = lp3971_dcdc_is_enabled,
.enable = lp3971_dcdc_enable,
.disable = lp3971_dcdc_disable,
- .get_voltage = lp3971_dcdc_get_voltage,
+ .get_voltage_sel = lp3971_dcdc_get_voltage_sel,
.set_voltage_sel = lp3971_dcdc_set_voltage_sel,
};
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index 69c42c318b87..0baabcfb578a 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -165,8 +165,6 @@ static const int buck_base_addr[] = {
#define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
#define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
#define LP3972_BUCK_VOL_MASK 0x1f
-#define LP3972_BUCK_VOL_MIN_IDX(x) ((x) ? 0x01 : 0x00)
-#define LP3972_BUCK_VOL_MAX_IDX(x) ((x) ? 0x19 : 0x1f)
static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count,
u16 *dest)
@@ -257,7 +255,7 @@ static int lp3972_ldo_disable(struct regulator_dev *dev)
mask, 0);
}
-static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
+static int lp3972_ldo_get_voltage_sel(struct regulator_dev *dev)
{
struct lp3972 *lp3972 = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev) - LP3972_LDO1;
@@ -267,7 +265,7 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;
- return dev->desc->volt_table[val];
+ return val;
}
static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
@@ -314,7 +312,7 @@ static struct regulator_ops lp3972_ldo_ops = {
.is_enabled = lp3972_ldo_is_enabled,
.enable = lp3972_ldo_enable,
.disable = lp3972_ldo_disable,
- .get_voltage = lp3972_ldo_get_voltage,
+ .get_voltage_sel = lp3972_ldo_get_voltage_sel,
.set_voltage_sel = lp3972_ldo_set_voltage_sel,
};
@@ -353,24 +351,16 @@ static int lp3972_dcdc_disable(struct regulator_dev *dev)
return val;
}
-static int lp3972_dcdc_get_voltage(struct regulator_dev *dev)
+static int lp3972_dcdc_get_voltage_sel(struct regulator_dev *dev)
{
struct lp3972 *lp3972 = rdev_get_drvdata(dev);
int buck = rdev_get_id(dev) - LP3972_DCDC1;
u16 reg;
- int val;
reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
reg &= LP3972_BUCK_VOL_MASK;
- if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck))
- val = dev->desc->volt_table[reg];
- else {
- val = 0;
- dev_warn(&dev->dev, "chip reported incorrect voltage value."
- " reg = %d\n", reg);
- }
- return val;
+ return reg;
}
static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev,
@@ -402,7 +392,7 @@ static struct regulator_ops lp3972_dcdc_ops = {
.is_enabled = lp3972_dcdc_is_enabled,
.enable = lp3972_dcdc_enable,
.disable = lp3972_dcdc_disable,
- .get_voltage = lp3972_dcdc_get_voltage,
+ .get_voltage_sel = lp3972_dcdc_get_voltage_sel,
.set_voltage_sel = lp3972_dcdc_set_voltage_sel,
};
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index 9289ead715ca..8e3c7ae0047f 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -181,20 +181,6 @@ static inline int lp872x_update_bits(struct lp872x *lp, u8 addr,
return regmap_update_bits(lp->regmap, addr, mask, data);
}
-static int _rdev_to_offset(struct regulator_dev *rdev)
-{
- enum lp872x_regulator_id id = rdev_get_id(rdev);
-
- switch (id) {
- case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
- return id;
- case LP8725_ID_LDO1 ... LP8725_ID_BUCK2:
- return id - LP8725_ID_BASE;
- default:
- return -EINVAL;
- }
-}
-
static int lp872x_get_timestep_usec(struct lp872x *lp)
{
enum lp872x_id chip = lp->chipid;
@@ -234,28 +220,20 @@ static int lp872x_get_timestep_usec(struct lp872x *lp)
static int lp872x_regulator_enable_time(struct regulator_dev *rdev)
{
struct lp872x *lp = rdev_get_drvdata(rdev);
- enum lp872x_regulator_id regulator = rdev_get_id(rdev);
+ enum lp872x_regulator_id rid = rdev_get_id(rdev);
int time_step_us = lp872x_get_timestep_usec(lp);
- int ret, offset;
+ int ret;
u8 addr, val;
if (time_step_us < 0)
return -EINVAL;
- switch (regulator) {
- case LP8720_ID_LDO1 ... LP8720_ID_LDO5:
- case LP8725_ID_LDO1 ... LP8725_ID_LILO2:
- offset = _rdev_to_offset(rdev);
- if (offset < 0)
- return -EINVAL;
-
- addr = LP872X_LDO1_VOUT + offset;
- break;
- case LP8720_ID_BUCK:
- addr = LP8720_BUCK_VOUT1;
+ switch (rid) {
+ case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
+ addr = LP872X_LDO1_VOUT + rid;
break;
- case LP8725_ID_BUCK1:
- addr = LP8725_BUCK1_VOUT1;
+ case LP8725_ID_LDO1 ... LP8725_ID_BUCK1:
+ addr = LP872X_LDO1_VOUT + rid - LP8725_ID_BASE;
break;
case LP8725_ID_BUCK2:
addr = LP8725_BUCK2_VOUT1;
diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c
new file mode 100644
index 000000000000..f0f6ea05065b
--- /dev/null
+++ b/drivers/regulator/lp8755.c
@@ -0,0 +1,566 @@
+/*
+ * LP8755 High Performance Power Management Unit : System Interface Driver
+ * (based on rev. 0.26)
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/platform_data/lp8755.h>
+
+#define LP8755_REG_BUCK0 0x00
+#define LP8755_REG_BUCK1 0x03
+#define LP8755_REG_BUCK2 0x04
+#define LP8755_REG_BUCK3 0x01
+#define LP8755_REG_BUCK4 0x05
+#define LP8755_REG_BUCK5 0x02
+#define LP8755_REG_MAX 0xFF
+
+#define LP8755_BUCK_EN_M BIT(7)
+#define LP8755_BUCK_LINEAR_OUT_MAX 0x76
+#define LP8755_BUCK_VOUT_M 0x7F
+
+struct lp8755_mphase {
+ int nreg;
+ int buck_num[LP8755_BUCK_MAX];
+};
+
+struct lp8755_chip {
+ struct device *dev;
+ struct regmap *regmap;
+ struct lp8755_platform_data *pdata;
+
+ int irq;
+ unsigned int irqmask;
+
+ int mphase;
+ struct regulator_dev *rdev[LP8755_BUCK_MAX];
+};
+
+/**
+ *lp8755_read : read a single register value from lp8755.
+ *@pchip : device to read from
+ *@reg : register to read from
+ *@val : pointer to store read value
+ */
+static int lp8755_read(struct lp8755_chip *pchip, unsigned int reg,
+ unsigned int *val)
+{
+ return regmap_read(pchip->regmap, reg, val);
+}
+
+/**
+ *lp8755_write : write a single register value to lp8755.
+ *@pchip : device to write to
+ *@reg : register to write to
+ *@val : value to be written
+ */
+static int lp8755_write(struct lp8755_chip *pchip, unsigned int reg,
+ unsigned int val)
+{
+ return regmap_write(pchip->regmap, reg, val);
+}
+
+/**
+ *lp8755_update_bits : set the values of bit fields in lp8755 register.
+ *@pchip : device to read from
+ *@reg : register to update
+ *@mask : bitmask to be changed
+ *@val : value for bitmask
+ */
+static int lp8755_update_bits(struct lp8755_chip *pchip, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ return regmap_update_bits(pchip->regmap, reg, mask, val);
+}
+
+static int lp8755_buck_enable_time(struct regulator_dev *rdev)
+{
+ int ret;
+ unsigned int regval;
+ enum lp8755_bucks id = rdev_get_id(rdev);
+ struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+ ret = lp8755_read(pchip, 0x12 + id, &regval);
+ if (ret < 0) {
+ dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+ return ret;
+ }
+ return (regval & 0xff) * 100;
+}
+
+static int lp8755_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ int ret;
+ unsigned int regbval = 0x0;
+ enum lp8755_bucks id = rdev_get_id(rdev);
+ struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ /* forced pwm mode */
+ regbval = (0x01 << id);
+ break;
+ case REGULATOR_MODE_NORMAL:
+ /* enable automatic pwm/pfm mode */
+ ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x00);
+ if (ret < 0)
+ goto err_i2c;
+ break;
+ case REGULATOR_MODE_IDLE:
+ /* enable automatic pwm/pfm/lppfm mode */
+ ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x20);
+ if (ret < 0)
+ goto err_i2c;
+
+ ret = lp8755_update_bits(pchip, 0x10, 0x01, 0x01);
+ if (ret < 0)
+ goto err_i2c;
+ break;
+ default:
+ dev_err(pchip->dev, "Not supported buck mode %s\n", __func__);
+ /* forced pwm mode */
+ regbval = (0x01 << id);
+ }
+
+ ret = lp8755_update_bits(pchip, 0x06, 0x01 << id, regbval);
+ if (ret < 0)
+ goto err_i2c;
+ return ret;
+err_i2c:
+ dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+ return ret;
+}
+
+static unsigned int lp8755_buck_get_mode(struct regulator_dev *rdev)
+{
+ int ret;
+ unsigned int regval;
+ enum lp8755_bucks id = rdev_get_id(rdev);
+ struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+ ret = lp8755_read(pchip, 0x06, &regval);
+ if (ret < 0)
+ goto err_i2c;
+
+ /* mode fast means forced pwm mode */
+ if (regval & (0x01 << id))
+ return REGULATOR_MODE_FAST;
+
+ ret = lp8755_read(pchip, 0x08 + id, &regval);
+ if (ret < 0)
+ goto err_i2c;
+
+ /* mode idle means automatic pwm/pfm/lppfm mode */
+ if (regval & 0x20)
+ return REGULATOR_MODE_IDLE;
+
+ /* mode normal means automatic pwm/pfm mode */
+ return REGULATOR_MODE_NORMAL;
+
+err_i2c:
+ dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+ return 0;
+}
+
+static int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp)
+{
+ int ret;
+ unsigned int regval = 0x00;
+ enum lp8755_bucks id = rdev_get_id(rdev);
+ struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
+
+ /* uV/us */
+ switch (ramp) {
+ case 0 ... 230:
+ regval = 0x07;
+ break;
+ case 231 ... 470:
+ regval = 0x06;
+ break;
+ case 471 ... 940:
+ regval = 0x05;
+ break;
+ case 941 ... 1900:
+ regval = 0x04;
+ break;
+ case 1901 ... 3800:
+ regval = 0x03;
+ break;
+ case 3801 ... 7500:
+ regval = 0x02;
+ break;
+ case 7501 ... 15000:
+ regval = 0x01;
+ break;
+ case 15001 ... 30000:
+ regval = 0x00;
+ break;
+ default:
+ dev_err(pchip->dev,
+ "Not supported ramp value %d %s\n", ramp, __func__);
+ return -EINVAL;
+ }
+
+ ret = lp8755_update_bits(pchip, 0x07 + id, 0x07, regval);
+ if (ret < 0)
+ goto err_i2c;
+ return ret;
+err_i2c:
+ dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+ return ret;
+}
+
+static struct regulator_ops lp8755_buck_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable_time = lp8755_buck_enable_time,
+ .set_mode = lp8755_buck_set_mode,
+ .get_mode = lp8755_buck_get_mode,
+ .set_ramp_delay = lp8755_buck_set_ramp,
+};
+
+#define lp8755_rail(_id) "lp8755_buck"#_id
+#define lp8755_buck_init(_id)\
+{\
+ .constraints = {\
+ .name = lp8755_rail(_id),\
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,\
+ .min_uV = 500000,\
+ .max_uV = 1675000,\
+ },\
+}
+
+static struct regulator_init_data lp8755_reg_default[LP8755_BUCK_MAX] = {
+ [LP8755_BUCK0] = lp8755_buck_init(0),
+ [LP8755_BUCK1] = lp8755_buck_init(1),
+ [LP8755_BUCK2] = lp8755_buck_init(2),
+ [LP8755_BUCK3] = lp8755_buck_init(3),
+ [LP8755_BUCK4] = lp8755_buck_init(4),
+ [LP8755_BUCK5] = lp8755_buck_init(5),
+};
+
+static const struct lp8755_mphase mphase_buck[MPHASE_CONF_MAX] = {
+ { 3, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK5 } },
+ { 6, { LP8755_BUCK0, LP8755_BUCK1, LP8755_BUCK2, LP8755_BUCK3,
+ LP8755_BUCK4, LP8755_BUCK5 } },
+ { 5, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK4,
+ LP8755_BUCK5} },
+ { 4, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK4, LP8755_BUCK5} },
+ { 3, { LP8755_BUCK0, LP8755_BUCK4, LP8755_BUCK5} },
+ { 2, { LP8755_BUCK0, LP8755_BUCK5} },
+ { 1, { LP8755_BUCK0} },
+ { 2, { LP8755_BUCK0, LP8755_BUCK3} },
+ { 4, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK5} },
+};
+
+static int lp8755_init_data(struct lp8755_chip *pchip)
+{
+ unsigned int regval;
+ int ret, icnt, buck_num;
+ struct lp8755_platform_data *pdata = pchip->pdata;
+
+ /* read back muti-phase configuration */
+ ret = lp8755_read(pchip, 0x3D, &regval);
+ if (ret < 0)
+ goto out_i2c_error;
+ pchip->mphase = regval & 0x0F;
+
+ /* set default data based on multi-phase config */
+ for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) {
+ buck_num = mphase_buck[pchip->mphase].buck_num[icnt];
+ pdata->buck_data[buck_num] = &lp8755_reg_default[buck_num];
+ }
+ return ret;
+
+out_i2c_error:
+ dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+ return ret;
+}
+
+#define lp8755_buck_desc(_id)\
+{\
+ .name = lp8755_rail(_id),\
+ .id = LP8755_BUCK##_id,\
+ .ops = &lp8755_buck_ops,\
+ .n_voltages = LP8755_BUCK_LINEAR_OUT_MAX+1,\
+ .uV_step = 10000,\
+ .min_uV = 500000,\
+ .type = REGULATOR_VOLTAGE,\
+ .owner = THIS_MODULE,\
+ .enable_reg = LP8755_REG_BUCK##_id,\
+ .enable_mask = LP8755_BUCK_EN_M,\
+ .vsel_reg = LP8755_REG_BUCK##_id,\
+ .vsel_mask = LP8755_BUCK_VOUT_M,\
+}
+
+static struct regulator_desc lp8755_regulators[] = {
+ lp8755_buck_desc(0),
+ lp8755_buck_desc(1),
+ lp8755_buck_desc(2),
+ lp8755_buck_desc(3),
+ lp8755_buck_desc(4),
+ lp8755_buck_desc(5),
+};
+
+static int lp8755_regulator_init(struct lp8755_chip *pchip)
+{
+ int ret, icnt, buck_num;
+ struct lp8755_platform_data *pdata = pchip->pdata;
+ struct regulator_config rconfig = { };
+
+ rconfig.regmap = pchip->regmap;
+ rconfig.dev = pchip->dev;
+ rconfig.driver_data = pchip;
+
+ for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) {
+ buck_num = mphase_buck[pchip->mphase].buck_num[icnt];
+ rconfig.init_data = pdata->buck_data[buck_num];
+ rconfig.of_node = pchip->dev->of_node;
+ pchip->rdev[buck_num] =
+ regulator_register(&lp8755_regulators[buck_num], &rconfig);
+ if (IS_ERR(pchip->rdev[buck_num])) {
+ ret = PTR_ERR(pchip->rdev[buck_num]);
+ pchip->rdev[buck_num] = NULL;
+ dev_err(pchip->dev, "regulator init failed: buck %d\n",
+ buck_num);
+ goto err_buck;
+ }
+ }
+
+ return 0;
+
+err_buck:
+ for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+ regulator_unregister(pchip->rdev[icnt]);
+ return ret;
+}
+
+static irqreturn_t lp8755_irq_handler(int irq, void *data)
+{
+ int ret, icnt;
+ unsigned int flag0, flag1;
+ struct lp8755_chip *pchip = data;
+
+ /* read flag0 register */
+ ret = lp8755_read(pchip, 0x0D, &flag0);
+ if (ret < 0)
+ goto err_i2c;
+ /* clear flag register to pull up int. pin */
+ ret = lp8755_write(pchip, 0x0D, 0x00);
+ if (ret < 0)
+ goto err_i2c;
+
+ /* sent power fault detection event to specific regulator */
+ for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+ if ((flag0 & (0x4 << icnt))
+ && (pchip->irqmask & (0x04 << icnt))
+ && (pchip->rdev[icnt] != NULL))
+ regulator_notifier_call_chain(pchip->rdev[icnt],
+ LP8755_EVENT_PWR_FAULT,
+ NULL);
+
+ /* read flag1 register */
+ ret = lp8755_read(pchip, 0x0E, &flag1);
+ if (ret < 0)
+ goto err_i2c;
+ /* clear flag register to pull up int. pin */
+ ret = lp8755_write(pchip, 0x0E, 0x00);
+ if (ret < 0)
+ goto err_i2c;
+
+ /* send OCP event to all regualtor devices */
+ if ((flag1 & 0x01) && (pchip->irqmask & 0x01))
+ for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+ if (pchip->rdev[icnt] != NULL)
+ regulator_notifier_call_chain(pchip->rdev[icnt],
+ LP8755_EVENT_OCP,
+ NULL);
+
+ /* send OVP event to all regualtor devices */
+ if ((flag1 & 0x02) && (pchip->irqmask & 0x02))
+ for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+ if (pchip->rdev[icnt] != NULL)
+ regulator_notifier_call_chain(pchip->rdev[icnt],
+ LP8755_EVENT_OVP,
+ NULL);
+ return IRQ_HANDLED;
+
+err_i2c:
+ dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+ return IRQ_NONE;
+}
+
+static int lp8755_int_config(struct lp8755_chip *pchip)
+{
+ int ret;
+ unsigned int regval;
+
+ if (pchip->irq == 0) {
+ dev_warn(pchip->dev, "not use interrupt : %s\n", __func__);
+ return 0;
+ }
+
+ ret = lp8755_read(pchip, 0x0F, &regval);
+ if (ret < 0)
+ goto err_i2c;
+ pchip->irqmask = regval;
+ ret = request_threaded_irq(pchip->irq, NULL, lp8755_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "lp8755-irq", pchip);
+ if (ret)
+ return ret;
+
+ return ret;
+
+err_i2c:
+ dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
+ return ret;
+}
+
+static const struct regmap_config lp8755_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = LP8755_REG_MAX,
+};
+
+static int lp8755_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret, icnt;
+ struct lp8755_chip *pchip;
+ struct lp8755_platform_data *pdata = client->dev.platform_data;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "i2c functionality check fail.\n");
+ return -EOPNOTSUPP;
+ }
+
+ pchip = devm_kzalloc(&client->dev,
+ sizeof(struct lp8755_chip), GFP_KERNEL);
+ if (!pchip)
+ return -ENOMEM;
+
+ pchip->dev = &client->dev;
+ pchip->regmap = devm_regmap_init_i2c(client, &lp8755_regmap);
+ if (IS_ERR(pchip->regmap)) {
+ ret = PTR_ERR(pchip->regmap);
+ dev_err(&client->dev, "fail to allocate regmap %d\n", ret);
+ return ret;
+ }
+ i2c_set_clientdata(client, pchip);
+
+ if (pdata != NULL) {
+ pchip->pdata = pdata;
+ pchip->mphase = pdata->mphase;
+ } else {
+ pchip->pdata = devm_kzalloc(pchip->dev,
+ sizeof(struct lp8755_platform_data),
+ GFP_KERNEL);
+ if (!pchip->pdata)
+ return -ENOMEM;
+ ret = lp8755_init_data(pchip);
+ if (ret < 0) {
+ dev_err(&client->dev, "fail to initialize chip\n");
+ return ret;
+ }
+ }
+
+ ret = lp8755_regulator_init(pchip);
+ if (ret < 0) {
+ dev_err(&client->dev, "fail to initialize regulators\n");
+ goto err_regulator;
+ }
+
+ pchip->irq = client->irq;
+ ret = lp8755_int_config(pchip);
+ if (ret < 0) {
+ dev_err(&client->dev, "fail to irq config\n");
+ goto err_irq;
+ }
+
+ return ret;
+
+err_irq:
+ for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++)
+ regulator_unregister(pchip->rdev[icnt]);
+
+err_regulator:
+ /* output disable */
+ for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+ lp8755_write(pchip, icnt, 0x00);
+
+ return ret;
+}
+
+static int lp8755_remove(struct i2c_client *client)
+{
+ int icnt;
+ struct lp8755_chip *pchip = i2c_get_clientdata(client);
+
+ for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++)
+ regulator_unregister(pchip->rdev[icnt]);
+
+ for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
+ lp8755_write(pchip, icnt, 0x00);
+
+ if (pchip->irq != 0)
+ free_irq(pchip->irq, pchip);
+
+ return 0;
+}
+
+static const struct i2c_device_id lp8755_id[] = {
+ {LP8755_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lp8755_id);
+
+static struct i2c_driver lp8755_i2c_driver = {
+ .driver = {
+ .name = LP8755_NAME,
+ },
+ .probe = lp8755_probe,
+ .remove = lp8755_remove,
+ .id_table = lp8755_id,
+};
+
+static int __init lp8755_init(void)
+{
+ return i2c_add_driver(&lp8755_i2c_driver);
+}
+
+subsys_initcall(lp8755_init);
+
+static void __exit lp8755_exit(void)
+{
+ i2c_del_driver(&lp8755_i2c_driver);
+}
+
+module_exit(lp8755_exit);
+
+MODULE_DESCRIPTION("Texas Instruments lp8755 driver");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c
index aef3f2b0c5ea..97891a7ea7b2 100644
--- a/drivers/regulator/lp8788-buck.c
+++ b/drivers/regulator/lp8788-buck.c
@@ -103,16 +103,6 @@ static const int lp8788_buck_vtbl[] = {
1950000, 2000000,
};
-static const u8 buck1_vout_addr[] = {
- LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
- LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
-};
-
-static const u8 buck2_vout_addr[] = {
- LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1,
- LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3,
-};
-
static void lp8788_buck1_set_dvs(struct lp8788_buck *buck)
{
struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;
@@ -235,7 +225,7 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;
}
- addr = buck1_vout_addr[idx];
+ addr = LP8788_BUCK1_VOUT0 + idx;
break;
case BUCK2:
if (mode == EXTPIN) {
@@ -258,7 +248,7 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;
}
- addr = buck2_vout_addr[idx];
+ addr = LP8788_BUCK2_VOUT0 + idx;
break;
default:
goto err;
@@ -429,7 +419,8 @@ static struct regulator_desc lp8788_buck_desc[] = {
},
};
-static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
+static int lp8788_dvs_gpio_request(struct platform_device *pdev,
+ struct lp8788_buck *buck,
enum lp8788_buck_id id)
{
struct lp8788_platform_data *pdata = buck->lp->pdata;
@@ -440,7 +431,7 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
switch (id) {
case BUCK1:
gpio = pdata->buck1_dvs->gpio;
- ret = devm_gpio_request_one(buck->lp->dev, gpio, DVS_LOW,
+ ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW,
b1_name);
if (ret)
return ret;
@@ -448,9 +439,9 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
buck->dvs = pdata->buck1_dvs;
break;
case BUCK2:
- for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) {
+ for (i = 0; i < LP8788_NUM_BUCK2_DVS; i++) {
gpio = pdata->buck2_dvs->gpio[i];
- ret = devm_gpio_request_one(buck->lp->dev, gpio,
+ ret = devm_gpio_request_one(&pdev->dev, gpio,
DVS_LOW, b2_name[i]);
if (ret)
return ret;
@@ -464,7 +455,8 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
return 0;
}
-static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
+static int lp8788_init_dvs(struct platform_device *pdev,
+ struct lp8788_buck *buck, enum lp8788_buck_id id)
{
struct lp8788_platform_data *pdata = buck->lp->pdata;
u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
@@ -472,7 +464,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };
/* no dvs for buck3, 4 */
- if (id == BUCK3 || id == BUCK4)
+ if (id > BUCK2)
return 0;
/* no dvs platform data, then dvs will be selected by I2C registers */
@@ -483,7 +475,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
(id == BUCK2 && !pdata->buck2_dvs))
goto set_default_dvs_mode;
- if (lp8788_dvs_gpio_request(buck, id))
+ if (lp8788_dvs_gpio_request(pdev, buck, id))
goto set_default_dvs_mode;
return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
@@ -503,17 +495,20 @@ static int lp8788_buck_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
int ret;
- buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
+ if (id >= LP8788_NUM_BUCKS)
+ return -EINVAL;
+
+ buck = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
if (!buck)
return -ENOMEM;
buck->lp = lp;
- ret = lp8788_init_dvs(buck, id);
+ ret = lp8788_init_dvs(pdev, buck, id);
if (ret)
return ret;
- cfg.dev = lp->dev;
+ cfg.dev = pdev->dev.parent;
cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;
cfg.driver_data = buck;
cfg.regmap = lp->regmap;
@@ -521,7 +516,7 @@ static int lp8788_buck_probe(struct platform_device *pdev)
rdev = regulator_register(&lp8788_buck_desc[id], &cfg);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
- dev_err(lp->dev, "BUCK%d regulator register err = %d\n",
+ dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n",
id + 1, ret);
return ret;
}
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c
index 3792741708ce..cd5a14ad9263 100644
--- a/drivers/regulator/lp8788-ldo.c
+++ b/drivers/regulator/lp8788-ldo.c
@@ -88,11 +88,6 @@
#define ENABLE GPIOF_OUT_INIT_HIGH
#define DISABLE GPIOF_OUT_INIT_LOW
-enum lp8788_enable_mode {
- REGISTER,
- EXTPIN,
-};
-
enum lp8788_ldo_id {
DLDO1,
DLDO2,
@@ -189,114 +184,38 @@ static enum lp8788_ldo_id lp8788_aldo_id[] = {
ALDO10,
};
-/* DLDO 7, 9 and 11, ALDO 1 ~ 5 and 7
- : can be enabled either by external pin or by i2c register */
-static enum lp8788_enable_mode
-lp8788_get_ldo_enable_mode(struct lp8788_ldo *ldo, enum lp8788_ldo_id id)
-{
- int ret;
- u8 val, mask;
-
- ret = lp8788_read_byte(ldo->lp, LP8788_EN_SEL, &val);
- if (ret)
- return ret;
-
- switch (id) {
- case DLDO7:
- mask = LP8788_EN_SEL_DLDO7_M;
- break;
- case DLDO9:
- case DLDO11:
- mask = LP8788_EN_SEL_DLDO911_M;
- break;
- case ALDO1:
- mask = LP8788_EN_SEL_ALDO1_M;
- break;
- case ALDO2 ... ALDO4:
- mask = LP8788_EN_SEL_ALDO234_M;
- break;
- case ALDO5:
- mask = LP8788_EN_SEL_ALDO5_M;
- break;
- case ALDO7:
- mask = LP8788_EN_SEL_ALDO7_M;
- break;
- default:
- return REGISTER;
- }
-
- return val & mask ? EXTPIN : REGISTER;
-}
-
-static int lp8788_ldo_ctrl_by_extern_pin(struct lp8788_ldo *ldo, int pinstate)
-{
- struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
-
- if (!pin)
- return -EINVAL;
-
- if (gpio_is_valid(pin->gpio))
- gpio_set_value(pin->gpio, pinstate);
-
- return 0;
-}
-
-static int lp8788_ldo_is_enabled_by_extern_pin(struct lp8788_ldo *ldo)
-{
- struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
-
- if (!pin)
- return -EINVAL;
-
- return gpio_get_value(pin->gpio) ? 1 : 0;
-}
-
static int lp8788_ldo_enable(struct regulator_dev *rdev)
{
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
- enum lp8788_ldo_id id = rdev_get_id(rdev);
- enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
- switch (mode) {
- case EXTPIN:
- return lp8788_ldo_ctrl_by_extern_pin(ldo, ENABLE);
- case REGISTER:
+ if (ldo->en_pin) {
+ gpio_set_value(ldo->en_pin->gpio, ENABLE);
+ return 0;
+ } else {
return regulator_enable_regmap(rdev);
- default:
- return -EINVAL;
}
}
static int lp8788_ldo_disable(struct regulator_dev *rdev)
{
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
- enum lp8788_ldo_id id = rdev_get_id(rdev);
- enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
- switch (mode) {
- case EXTPIN:
- return lp8788_ldo_ctrl_by_extern_pin(ldo, DISABLE);
- case REGISTER:
+ if (ldo->en_pin) {
+ gpio_set_value(ldo->en_pin->gpio, DISABLE);
+ return 0;
+ } else {
return regulator_disable_regmap(rdev);
- default:
- return -EINVAL;
}
}
static int lp8788_ldo_is_enabled(struct regulator_dev *rdev)
{
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
- enum lp8788_ldo_id id = rdev_get_id(rdev);
- enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
- switch (mode) {
- case EXTPIN:
- return lp8788_ldo_is_enabled_by_extern_pin(ldo);
- case REGISTER:
+ if (ldo->en_pin)
+ return gpio_get_value(ldo->en_pin->gpio) ? 1 : 0;
+ else
return regulator_is_enabled_regmap(rdev);
- default:
- return -EINVAL;
- }
}
static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
@@ -616,10 +535,11 @@ static struct regulator_desc lp8788_aldo_desc[] = {
},
};
-static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo,
+static int lp8788_gpio_request_ldo_en(struct platform_device *pdev,
+ struct lp8788_ldo *ldo,
enum lp8788_ext_ldo_en_id id)
{
- struct device *dev = ldo->lp->dev;
+ struct device *dev = &pdev->dev;
struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
int ret, gpio, pinstate;
char *name[] = {
@@ -647,7 +567,8 @@ static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo,
return ret;
}
-static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo,
+static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
+ struct lp8788_ldo *ldo,
enum lp8788_ldo_id id)
{
int ret;
@@ -693,9 +614,11 @@ static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo,
ldo->en_pin = pdata->ldo_pin[enable_id];
- ret = lp8788_gpio_request_ldo_en(ldo, enable_id);
- if (ret)
+ ret = lp8788_gpio_request_ldo_en(pdev, ldo, enable_id);
+ if (ret) {
+ ldo->en_pin = NULL;
goto set_default_ldo_enable_mode;
+ }
return ret;
@@ -712,16 +635,16 @@ static int lp8788_dldo_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
int ret;
- ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
+ ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
if (!ldo)
return -ENOMEM;
ldo->lp = lp;
- ret = lp8788_config_ldo_enable_mode(ldo, lp8788_dldo_id[id]);
+ ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_dldo_id[id]);
if (ret)
return ret;
- cfg.dev = lp->dev;
+ cfg.dev = pdev->dev.parent;
cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL;
cfg.driver_data = ldo;
cfg.regmap = lp->regmap;
@@ -729,7 +652,7 @@ static int lp8788_dldo_probe(struct platform_device *pdev)
rdev = regulator_register(&lp8788_dldo_desc[id], &cfg);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
- dev_err(lp->dev, "DLDO%d regulator register err = %d\n",
+ dev_err(&pdev->dev, "DLDO%d regulator register err = %d\n",
id + 1, ret);
return ret;
}
@@ -768,16 +691,16 @@ static int lp8788_aldo_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
int ret;
- ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
+ ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
if (!ldo)
return -ENOMEM;
ldo->lp = lp;
- ret = lp8788_config_ldo_enable_mode(ldo, lp8788_aldo_id[id]);
+ ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_aldo_id[id]);
if (ret)
return ret;
- cfg.dev = lp->dev;
+ cfg.dev = pdev->dev.parent;
cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL;
cfg.driver_data = ldo;
cfg.regmap = lp->regmap;
@@ -785,7 +708,7 @@ static int lp8788_aldo_probe(struct platform_device *pdev)
rdev = regulator_register(&lp8788_aldo_desc[id], &cfg);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
- dev_err(lp->dev, "ALDO%d regulator register err = %d\n",
+ dev_err(&pdev->dev, "ALDO%d regulator register err = %d\n",
id + 1, ret);
return ret;
}
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
index b85040caaea3..e4586ee8858d 100644
--- a/drivers/regulator/max77686.c
+++ b/drivers/regulator/max77686.c
@@ -75,13 +75,14 @@ static int max77686_buck_set_suspend_disable(struct regulator_dev *rdev)
{
unsigned int val;
struct max77686_data *max77686 = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
- if (rdev->desc->id == MAX77686_BUCK1)
+ if (id == MAX77686_BUCK1)
val = 0x1;
else
val = 0x1 << MAX77686_OPMODE_BUCK234_SHIFT;
- max77686->opmode[rdev->desc->id] = val;
+ max77686->opmode[id] = val;
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask,
val);
@@ -93,9 +94,10 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
{
struct max77686_data *max77686 = rdev_get_drvdata(rdev);
unsigned int val;
+ int id = rdev_get_id(rdev);
/* BUCK[5-9] doesn't support this feature */
- if (rdev->desc->id >= MAX77686_BUCK5)
+ if (id >= MAX77686_BUCK5)
return 0;
switch (mode) {
@@ -111,7 +113,7 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
return -EINVAL;
}
- max77686->opmode[rdev->desc->id] = val;
+ max77686->opmode[id] = val;
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask,
val);
@@ -140,7 +142,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
return -EINVAL;
}
- max77686->opmode[rdev->desc->id] = val;
+ max77686->opmode[rdev_get_id(rdev)] = val;
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask,
val);
@@ -152,7 +154,7 @@ static int max77686_enable(struct regulator_dev *rdev)
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask,
- max77686->opmode[rdev->desc->id]);
+ max77686->opmode[rdev_get_id(rdev)]);
}
static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
@@ -379,9 +381,10 @@ static struct regulator_desc regulators[] = {
};
#ifdef CONFIG_OF
-static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
+static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
struct max77686_platform_data *pdata)
{
+ struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct device_node *pmic_np, *regulators_np;
struct max77686_regulator_data *rdata;
struct of_regulator_match rmatch;
@@ -390,15 +393,15 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
pmic_np = iodev->dev->of_node;
regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators");
if (!regulators_np) {
- dev_err(iodev->dev, "could not find regulators sub-node\n");
+ dev_err(&pdev->dev, "could not find regulators sub-node\n");
return -EINVAL;
}
pdata->num_regulators = ARRAY_SIZE(regulators);
- rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
+ rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
pdata->num_regulators, GFP_KERNEL);
if (!rdata) {
- dev_err(iodev->dev,
+ dev_err(&pdev->dev,
"could not allocate memory for regulator data\n");
return -ENOMEM;
}
@@ -407,7 +410,7 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
rmatch.name = regulators[i].name;
rmatch.init_data = NULL;
rmatch.of_node = NULL;
- of_regulator_match(iodev->dev, regulators_np, &rmatch, 1);
+ of_regulator_match(&pdev->dev, regulators_np, &rmatch, 1);
rdata[i].initdata = rmatch.init_data;
rdata[i].of_node = rmatch.of_node;
}
@@ -417,7 +420,7 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
return 0;
}
#else
-static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
+static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
struct max77686_platform_data *pdata)
{
return 0;
@@ -440,7 +443,7 @@ static int max77686_pmic_probe(struct platform_device *pdev)
}
if (iodev->dev->of_node) {
- ret = max77686_pmic_dt_parse_pdata(iodev, pdata);
+ ret = max77686_pmic_dt_parse_pdata(pdev, pdata);
if (ret)
return ret;
}
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c
index d1a77512d83e..4568c15fa78d 100644
--- a/drivers/regulator/max8907-regulator.c
+++ b/drivers/regulator/max8907-regulator.c
@@ -224,11 +224,11 @@ static struct of_regulator_match max8907_matches[] = {
static int max8907_regulator_parse_dt(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.parent->of_node;
- struct device_node *regulators;
+ struct device_node *np, *regulators;
int ret;
- if (!pdev->dev.parent->of_node)
+ np = of_node_get(pdev->dev.parent->of_node);
+ if (!np)
return 0;
regulators = of_find_node_by_name(np, "regulators");
@@ -237,9 +237,9 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev)
return -EINVAL;
}
- ret = of_regulator_match(pdev->dev.parent, regulators,
- max8907_matches,
+ ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
ARRAY_SIZE(max8907_matches));
+ of_node_put(regulators);
if (ret < 0) {
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
ret);
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index 446a85445553..0d5f64a805a0 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -252,7 +252,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
{
struct device_node *nproot, *np;
int rcount;
- nproot = pdev->dev.parent->of_node;
+ nproot = of_node_get(pdev->dev.parent->of_node);
if (!nproot)
return -ENODEV;
np = of_find_node_by_name(nproot, "regulators");
@@ -263,6 +263,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
rcount = of_regulator_match(&pdev->dev, np,
&max8925_regulator_matches[ridx], 1);
+ of_node_put(np);
if (rcount < 0)
return -ENODEV;
config->init_data = max8925_regulator_matches[ridx].init_data;
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index 02be7fcae32f..0ac7a87519b4 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -54,6 +54,13 @@ struct max8997_data {
u8 saved_states[MAX8997_REG_MAX];
};
+static const unsigned int safeoutvolt[] = {
+ 4850000,
+ 4900000,
+ 4950000,
+ 3300000,
+};
+
static inline void max8997_set_gpio(struct max8997_data *max8997)
{
int set3 = (max8997->buck125_gpioindex) & 0x1;
@@ -130,29 +137,6 @@ static const struct voltage_map_desc *reg_voltage_map[] = {
[MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc,
};
-static int max8997_list_voltage_safeout(struct regulator_dev *rdev,
- unsigned int selector)
-{
- int rid = rdev_get_id(rdev);
-
- if (rid == MAX8997_ESAFEOUT1 || rid == MAX8997_ESAFEOUT2) {
- switch (selector) {
- case 0:
- return 4850000;
- case 1:
- return 4900000;
- case 2:
- return 4950000;
- case 3:
- return 3300000;
- default:
- return -EINVAL;
- }
- }
-
- return -EINVAL;
-}
-
static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev,
unsigned int selector)
{
@@ -522,7 +506,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
return ret;
}
-static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev,
+static int max8997_set_voltage_buck_time_sel(struct regulator_dev *rdev,
unsigned int old_selector,
unsigned int new_selector)
{
@@ -720,49 +704,23 @@ out:
return 0;
}
-static const int safeoutvolt[] = {
- 3300000,
- 4850000,
- 4900000,
- 4950000,
-};
-
/* For SAFEOUT1 and SAFEOUT2 */
-static int max8997_set_voltage_safeout(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+static int max8997_set_voltage_safeout_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
struct max8997_data *max8997 = rdev_get_drvdata(rdev);
struct i2c_client *i2c = max8997->iodev->i2c;
int rid = rdev_get_id(rdev);
int reg, shift = 0, mask, ret;
- int i = 0;
- u8 val;
if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2)
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(safeoutvolt); i++) {
- if (min_uV <= safeoutvolt[i] &&
- max_uV >= safeoutvolt[i])
- break;
- }
-
- if (i >= ARRAY_SIZE(safeoutvolt))
- return -EINVAL;
-
- if (i == 0)
- val = 0x3;
- else
- val = i - 1;
-
ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
if (ret)
return ret;
- ret = max8997_update_reg(i2c, reg, val << shift, mask << shift);
- *selector = val;
-
- return ret;
+ return max8997_update_reg(i2c, reg, selector << shift, mask << shift);
}
static int max8997_reg_disable_suspend(struct regulator_dev *rdev)
@@ -799,7 +757,6 @@ static struct regulator_ops max8997_ldo_ops = {
.disable = max8997_reg_disable,
.get_voltage_sel = max8997_get_voltage_sel,
.set_voltage = max8997_set_voltage_ldobuck,
- .set_voltage_time_sel = max8997_set_voltage_ldobuck_time_sel,
.set_suspend_disable = max8997_reg_disable_suspend,
};
@@ -810,7 +767,7 @@ static struct regulator_ops max8997_buck_ops = {
.disable = max8997_reg_disable,
.get_voltage_sel = max8997_get_voltage_sel,
.set_voltage = max8997_set_voltage_buck,
- .set_voltage_time_sel = max8997_set_voltage_ldobuck_time_sel,
+ .set_voltage_time_sel = max8997_set_voltage_buck_time_sel,
.set_suspend_disable = max8997_reg_disable_suspend,
};
@@ -823,12 +780,12 @@ static struct regulator_ops max8997_fixedvolt_ops = {
};
static struct regulator_ops max8997_safeout_ops = {
- .list_voltage = max8997_list_voltage_safeout,
+ .list_voltage = regulator_list_voltage_table,
.is_enabled = max8997_reg_is_enabled,
.enable = max8997_reg_enable,
.disable = max8997_reg_disable,
.get_voltage_sel = max8997_get_voltage_sel,
- .set_voltage = max8997_set_voltage_safeout,
+ .set_voltage_sel = max8997_set_voltage_safeout_sel,
.set_suspend_disable = max8997_reg_disable_suspend,
};
@@ -934,7 +891,7 @@ static struct regulator_desc regulators[] = {
};
#ifdef CONFIG_OF
-static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev,
+static int max8997_pmic_dt_parse_dvs_gpio(struct platform_device *pdev,
struct max8997_platform_data *pdata,
struct device_node *pmic_np)
{
@@ -944,7 +901,7 @@ static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev,
gpio = of_get_named_gpio(pmic_np,
"max8997,pmic-buck125-dvs-gpios", i);
if (!gpio_is_valid(gpio)) {
- dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
+ dev_err(&pdev->dev, "invalid gpio[%d]: %d\n", i, gpio);
return -EINVAL;
}
pdata->buck125_gpios[i] = gpio;
@@ -952,35 +909,34 @@ static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev,
return 0;
}
-static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
+static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
struct max8997_platform_data *pdata)
{
+ struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct device_node *pmic_np, *regulators_np, *reg_np;
struct max8997_regulator_data *rdata;
unsigned int i, dvs_voltage_nr = 1, ret;
- pmic_np = iodev->dev->of_node;
+ pmic_np = of_node_get(iodev->dev->of_node);
if (!pmic_np) {
- dev_err(iodev->dev, "could not find pmic sub-node\n");
+ dev_err(&pdev->dev, "could not find pmic sub-node\n");
return -ENODEV;
}
regulators_np = of_find_node_by_name(pmic_np, "regulators");
if (!regulators_np) {
- dev_err(iodev->dev, "could not find regulators sub-node\n");
+ dev_err(&pdev->dev, "could not find regulators sub-node\n");
return -EINVAL;
}
/* count the number of regulators to be supported in pmic */
- pdata->num_regulators = 0;
- for_each_child_of_node(regulators_np, reg_np)
- pdata->num_regulators++;
+ pdata->num_regulators = of_get_child_count(regulators_np);
- rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
+ rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
pdata->num_regulators, GFP_KERNEL);
if (!rdata) {
- dev_err(iodev->dev, "could not allocate memory for "
- "regulator data\n");
+ of_node_put(regulators_np);
+ dev_err(&pdev->dev, "could not allocate memory for regulator data\n");
return -ENOMEM;
}
@@ -991,17 +947,18 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
break;
if (i == ARRAY_SIZE(regulators)) {
- dev_warn(iodev->dev, "don't know how to configure "
- "regulator %s\n", reg_np->name);
+ dev_warn(&pdev->dev, "don't know how to configure regulator %s\n",
+ reg_np->name);
continue;
}
rdata->id = i;
- rdata->initdata = of_get_regulator_init_data(
- iodev->dev, reg_np);
+ rdata->initdata = of_get_regulator_init_data(&pdev->dev,
+ reg_np);
rdata->reg_node = reg_np;
rdata++;
}
+ of_node_put(regulators_np);
if (of_get_property(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs", NULL))
pdata->buck1_gpiodvs = true;
@@ -1014,7 +971,7 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
pdata->buck5_gpiodvs) {
- ret = max8997_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
+ ret = max8997_pmic_dt_parse_dvs_gpio(pdev, pdata, pmic_np);
if (ret)
return -EINVAL;
@@ -1025,8 +982,7 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
} else {
if (pdata->buck125_default_idx >= 8) {
pdata->buck125_default_idx = 0;
- dev_info(iodev->dev, "invalid value for "
- "default dvs index, using 0 instead\n");
+ dev_info(&pdev->dev, "invalid value for default dvs index, using 0 instead\n");
}
}
@@ -1040,28 +996,28 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
if (of_property_read_u32_array(pmic_np,
"max8997,pmic-buck1-dvs-voltage",
pdata->buck1_voltage, dvs_voltage_nr)) {
- dev_err(iodev->dev, "buck1 voltages not specified\n");
+ dev_err(&pdev->dev, "buck1 voltages not specified\n");
return -EINVAL;
}
if (of_property_read_u32_array(pmic_np,
"max8997,pmic-buck2-dvs-voltage",
pdata->buck2_voltage, dvs_voltage_nr)) {
- dev_err(iodev->dev, "buck2 voltages not specified\n");
+ dev_err(&pdev->dev, "buck2 voltages not specified\n");
return -EINVAL;
}
if (of_property_read_u32_array(pmic_np,
"max8997,pmic-buck5-dvs-voltage",
pdata->buck5_voltage, dvs_voltage_nr)) {
- dev_err(iodev->dev, "buck5 voltages not specified\n");
+ dev_err(&pdev->dev, "buck5 voltages not specified\n");
return -EINVAL;
}
return 0;
}
#else
-static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
+static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
struct max8997_platform_data *pdata)
{
return 0;
@@ -1085,7 +1041,7 @@ static int max8997_pmic_probe(struct platform_device *pdev)
}
if (iodev->dev->of_node) {
- ret = max8997_pmic_dt_parse_pdata(iodev, pdata);
+ ret = max8997_pmic_dt_parse_pdata(pdev, pdata);
if (ret)
return ret;
}
@@ -1234,13 +1190,15 @@ static int max8997_pmic_probe(struct platform_device *pdev)
int id = pdata->regulators[i].id;
desc = reg_voltage_map[id];
- if (desc)
+ if (desc) {
regulators[id].n_voltages =
(desc->max - desc->min) / desc->step + 1;
- else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2)
- regulators[id].n_voltages = 4;
- else if (id == MAX8997_CHARGER_CV)
+ } else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) {
+ regulators[id].volt_table = safeoutvolt;
+ regulators[id].n_voltages = ARRAY_SIZE(safeoutvolt);
+ } else if (id == MAX8997_CHARGER_CV) {
regulators[id].n_voltages = 16;
+ }
config.dev = max8997->dev;
config.init_data = pdata->regulators[i].initdata;
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 1f0df4046b86..b588f07c7cad 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -65,7 +65,7 @@ static const struct voltage_map_desc ldo9_voltage_map_desc = {
.min = 2800000, .step = 100000, .max = 3100000,
};
static const struct voltage_map_desc ldo10_voltage_map_desc = {
- .min = 95000, .step = 50000, .max = 1300000,
+ .min = 950000, .step = 50000, .max = 1300000,
};
static const struct voltage_map_desc ldo1213_voltage_map_desc = {
.min = 800000, .step = 100000, .max = 3300000,
@@ -311,25 +311,13 @@ static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev,
dev_get_platdata(max8998->iodev->dev);
struct i2c_client *i2c = max8998->iodev->i2c;
int buck = rdev_get_id(rdev);
- int reg, shift = 0, mask, ret;
- int j, previous_sel;
+ int reg, shift = 0, mask, ret, j;
static u8 buck1_last_val;
ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
if (ret)
return ret;
- previous_sel = max8998_get_voltage_sel(rdev);
-
- /* Check if voltage needs to be changed */
- /* if previous_voltage equal new voltage, return */
- if (previous_sel == selector) {
- dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n",
- regulator_list_voltage_linear(rdev, previous_sel),
- regulator_list_voltage_linear(rdev, selector));
- return ret;
- }
-
switch (buck) {
case MAX8998_BUCK1:
dev_dbg(max8998->dev,
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index 0d84b1f33199..9891aec47b57 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -164,6 +164,14 @@ static const unsigned int mc13892_sw1[] = {
1350000, 1375000
};
+/*
+ * Note: this table is used to derive SWxVSEL by index into
+ * the array. Offset the values by the index of 1100000uV
+ * to get the actual register value for that voltage selector
+ * if the HI bit is to be set as well.
+ */
+#define MC13892_SWxHI_SEL_OFFSET 20
+
static const unsigned int mc13892_sw[] = {
600000, 625000, 650000, 675000, 700000, 725000,
750000, 775000, 800000, 825000, 850000, 875000,
@@ -239,7 +247,6 @@ static const unsigned int mc13892_pwgtdrv[] = {
};
static struct regulator_ops mc13892_gpo_regulator_ops;
-/* sw regulators need special care due to the "hi bit" */
static struct regulator_ops mc13892_sw_regulator_ops;
@@ -396,7 +403,7 @@ static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
int ret, id = rdev_get_id(rdev);
- unsigned int val;
+ unsigned int val, selector;
dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
@@ -407,12 +414,28 @@ static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev)
if (ret)
return ret;
- val = (val & mc13892_regulators[id].vsel_mask)
- >> mc13892_regulators[id].vsel_shift;
+ /*
+ * Figure out if the HI bit is set inside the switcher mode register
+ * since this means the selector value we return is at a different
+ * offset into the selector table.
+ *
+ * According to the MC13892 documentation note 59 (Table 47) the SW1
+ * buck switcher does not support output range programming therefore
+ * the HI bit must always remain 0. So do not do anything strange if
+ * our register is MC13892_SWITCHERS0.
+ */
+
+ selector = val & mc13892_regulators[id].vsel_mask;
+
+ if ((mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) &&
+ (val & MC13892_SWITCHERS0_SWxHI)) {
+ selector += MC13892_SWxHI_SEL_OFFSET;
+ }
- dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d val: 0x%08x selector: %d\n",
+ __func__, id, val, selector);
- return val;
+ return selector;
}
static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
@@ -425,18 +448,35 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
volt = rdev->desc->volt_table[selector];
mask = mc13892_regulators[id].vsel_mask;
- reg_value = selector << mc13892_regulators[id].vsel_shift;
-
- if (volt > 1375000) {
- mask |= MC13892_SWITCHERS0_SWxHI;
- reg_value |= MC13892_SWITCHERS0_SWxHI;
- } else if (volt < 1100000) {
- mask |= MC13892_SWITCHERS0_SWxHI;
- reg_value &= ~MC13892_SWITCHERS0_SWxHI;
+ reg_value = selector;
+
+ /*
+ * Don't mess with the HI bit or support HI voltage offsets for SW1.
+ *
+ * Since the get_voltage_sel callback has given a fudged value for
+ * the selector offset, we need to back out that offset if HI is
+ * to be set so we write the correct value to the register.
+ *
+ * The HI bit addition and selector offset handling COULD be more
+ * complicated by shifting and masking off the voltage selector part
+ * of the register then logical OR it back in, but since the selector
+ * is at bits 4:0 there is very little point. This makes the whole
+ * thing more readable and we do far less work.
+ */
+
+ if (mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) {
+ if (volt > 1375000) {
+ reg_value -= MC13892_SWxHI_SEL_OFFSET;
+ reg_value |= MC13892_SWITCHERS0_SWxHI;
+ mask |= MC13892_SWITCHERS0_SWxHI;
+ } else if (volt < 1100000) {
+ reg_value &= ~MC13892_SWITCHERS0_SWxHI;
+ mask |= MC13892_SWITCHERS0_SWxHI;
+ }
}
mc13xxx_lock(priv->mc13xxx);
- ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, mask,
+ ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg, mask,
reg_value);
mc13xxx_unlock(priv->mc13xxx);
@@ -495,15 +535,18 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
struct mc13xxx_regulator_init_data *mc13xxx_data;
struct regulator_config config = { };
int i, ret;
- int num_regulators = 0;
+ int num_regulators = 0, num_parsed;
u32 val;
num_regulators = mc13xxx_get_num_regulators_dt(pdev);
+
if (num_regulators <= 0 && pdata)
num_regulators = pdata->num_regulators;
if (num_regulators <= 0)
return -EINVAL;
+ num_parsed = num_regulators;
+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv) +
num_regulators * sizeof(priv->regulators[0]),
GFP_KERNEL);
@@ -520,7 +563,7 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
if (ret)
goto err_unlock;
- /* enable switch auto mode */
+ /* enable switch auto mode (on 2.0A silicon only) */
if ((val & 0x0000FFFF) == 0x45d0) {
ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
MC13892_SWITCHERS4_SW1MODE_M |
@@ -546,7 +589,39 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
= mc13892_vcam_get_mode;
mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators,
- ARRAY_SIZE(mc13892_regulators));
+ ARRAY_SIZE(mc13892_regulators),
+ &num_parsed);
+
+ /*
+ * Perform a little sanity check on the regulator tree - if we found
+ * a number of regulators from mc13xxx_get_num_regulators_dt and
+ * then parsed a smaller number in mc13xxx_parse_regulators_dt then
+ * there is a regulator defined in the regulators node which has
+ * not matched any usable regulator in the driver. In this case,
+ * there is one missing and what will happen is the first regulator
+ * will get registered again.
+ *
+ * Fix this by basically making our number of registerable regulators
+ * equal to the number of regulators we parsed. We are allocating
+ * too much memory for priv, but this is unavoidable at this point.
+ *
+ * As an example of how this can happen, try making a typo in your
+ * regulators node (vviohi {} instead of viohi {}) so that the name
+ * does not match..
+ *
+ * The check will basically pass for platform data (non-DT) because
+ * mc13xxx_parse_regulators_dt for !CONFIG_OF will not touch num_parsed.
+ *
+ */
+ if (num_parsed != num_regulators) {
+ dev_warn(&pdev->dev,
+ "parsed %d != regulators %d - check your device tree!\n",
+ num_parsed, num_regulators);
+
+ num_regulators = num_parsed;
+ priv->num_regulators = num_regulators;
+ }
+
for (i = 0; i < num_regulators; i++) {
struct regulator_init_data *init_data;
struct regulator_desc *desc;
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index 4ed89c654110..23cf9f9c383b 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -164,29 +164,30 @@ EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops);
#ifdef CONFIG_OF
int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
{
- struct device_node *parent, *child;
- int num = 0;
+ struct device_node *parent;
+ int num;
of_node_get(pdev->dev.parent->of_node);
parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
if (!parent)
return -ENODEV;
- for_each_child_of_node(parent, child)
- num++;
-
+ num = of_get_child_count(parent);
+ of_node_put(parent);
return num;
}
EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt);
struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
struct platform_device *pdev, struct mc13xxx_regulator *regulators,
- int num_regulators)
+ int num_regulators, int *num_parsed)
{
struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
struct mc13xxx_regulator_init_data *data, *p;
struct device_node *parent, *child;
- int i;
+ int i, parsed = 0;
+
+ *num_parsed = 0;
of_node_get(pdev->dev.parent->of_node);
parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
@@ -195,24 +196,32 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
data = devm_kzalloc(&pdev->dev, sizeof(*data) * priv->num_regulators,
GFP_KERNEL);
- if (!data)
+ if (!data) {
+ of_node_put(parent);
return NULL;
+ }
+
p = data;
for_each_child_of_node(parent, child) {
for (i = 0; i < num_regulators; i++) {
if (!of_node_cmp(child->name,
regulators[i].desc.name)) {
+
p->id = i;
p->init_data = of_get_regulator_init_data(
&pdev->dev, child);
p->node = child;
p++;
+
+ parsed++;
break;
}
}
}
+ of_node_put(parent);
+ *num_parsed = parsed;
return data;
}
EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt);
diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h
index 06c8903f182a..007f83387fd6 100644
--- a/drivers/regulator/mc13xxx.h
+++ b/drivers/regulator/mc13xxx.h
@@ -39,7 +39,7 @@ extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev);
extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
struct platform_device *pdev, struct mc13xxx_regulator *regulators,
- int num_regulators);
+ int num_regulators, int *num_parsed);
#else
static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
{
@@ -48,7 +48,7 @@ static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
struct platform_device *pdev, struct mc13xxx_regulator *regulators,
- int num_regulators)
+ int num_regulators, int *num_parsed)
{
return NULL;
}
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 6f684916fd79..66ca769287ab 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -120,6 +120,12 @@ int of_regulator_match(struct device *dev, struct device_node *node,
if (!dev || !node)
return -EINVAL;
+ for (i = 0; i < num_matches; i++) {
+ struct of_regulator_match *match = &matches[i];
+ match->init_data = NULL;
+ match->of_node = NULL;
+ }
+
for_each_child_of_node(node, child) {
name = of_get_property(child,
"regulator-compatible", NULL);
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index c9e912f583bc..cde13bb5a8fb 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -527,6 +527,7 @@ static void palmas_dt_to_pdata(struct device *dev,
u32 prop;
int idx, ret;
+ node = of_node_get(node);
regulators = of_find_node_by_name(node, "regulators");
if (!regulators) {
dev_info(dev, "regulator node not found\n");
@@ -535,6 +536,7 @@ static void palmas_dt_to_pdata(struct device *dev,
ret = of_regulator_match(dev, regulators, palmas_matches,
PALMAS_NUM_REGS);
+ of_node_put(regulators);
if (ret < 0) {
dev_err(dev, "Error parsing regulator init data: %d\n", ret);
return;
@@ -566,11 +568,6 @@ static void palmas_dt_to_pdata(struct device *dev,
pdata->reg_init[idx]->mode_sleep = prop;
ret = of_property_read_u32(palmas_matches[idx].of_node,
- "ti,warm_reset", &prop);
- if (!ret)
- pdata->reg_init[idx]->warm_reset = prop;
-
- ret = of_property_read_u32(palmas_matches[idx].of_node,
"ti,tstep", &prop);
if (!ret)
pdata->reg_init[idx]->tstep = prop;
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index bd062a2ffbe2..cd9ea2ea1826 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -174,9 +174,9 @@ static struct regulator_ops s2mps11_buck_ops = {
.min_uV = S2MPS11_BUCK_MIN2, \
.uV_step = S2MPS11_BUCK_STEP2, \
.n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
- .vsel_reg = S2MPS11_REG_B9CTRL2, \
+ .vsel_reg = S2MPS11_REG_B10CTRL2, \
.vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
- .enable_reg = S2MPS11_REG_B9CTRL1, \
+ .enable_reg = S2MPS11_REG_B10CTRL1, \
.enable_mask = S2MPS11_ENABLE_MASK \
}
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 33b65c9ad5d5..8a831947c351 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -14,6 +14,7 @@
#include <linux/bug.h>
#include <linux/err.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -21,6 +22,9 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/s5m8767.h>
+#include <linux/regulator/of_regulator.h>
+
+#define S5M8767_OPMODE_NORMAL_MODE 0x1
struct s5m8767_info {
struct device *dev;
@@ -255,10 +259,8 @@ static int s5m8767_reg_disable(struct regulator_dev *rdev)
return sec_reg_update(s5m8767->iodev, reg, ~mask, mask);
}
-static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
+static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767)
{
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
- int reg_id = rdev_get_id(rdev);
int reg;
switch (reg_id) {
@@ -296,43 +298,18 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
return -EINVAL;
}
- *_reg = reg;
-
- return 0;
-}
-
-static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
- int reg, mask, ret;
- int reg_id = rdev_get_id(rdev);
- unsigned int val;
-
- ret = s5m8767_get_voltage_register(rdev, &reg);
- if (ret)
- return ret;
-
- mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff;
-
- ret = sec_reg_read(s5m8767->iodev, reg, &val);
- if (ret)
- return ret;
-
- val &= mask;
-
- return val;
+ return reg;
}
-static int s5m8767_convert_voltage_to_sel(
- const struct sec_voltage_desc *desc,
- int min_vol, int max_vol)
+static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc,
+ int min_vol)
{
int selector = 0;
if (desc == NULL)
return -EINVAL;
- if (max_vol < desc->min || min_vol > desc->max)
+ if (min_vol > desc->max)
return -EINVAL;
if (min_vol < desc->min)
@@ -340,7 +317,7 @@ static int s5m8767_convert_voltage_to_sel(
selector = DIV_ROUND_UP(min_vol - desc->min, desc->step);
- if (desc->min + desc->step * selector > max_vol)
+ if (desc->min + desc->step * selector > desc->max)
return -EINVAL;
return selector;
@@ -373,15 +350,13 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
{
struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
int reg_id = rdev_get_id(rdev);
- int reg, mask, ret = 0, old_index, index = 0;
+ int old_index, index = 0;
u8 *buck234_vol = NULL;
switch (reg_id) {
case S5M8767_LDO1 ... S5M8767_LDO28:
- mask = 0x3f;
break;
case S5M8767_BUCK1 ... S5M8767_BUCK6:
- mask = 0xff;
if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs)
buck234_vol = &s5m8767->buck2_vol[0];
else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs)
@@ -392,7 +367,6 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
case S5M8767_BUCK7 ... S5M8767_BUCK8:
return -EINVAL;
case S5M8767_BUCK9:
- mask = 0xff;
break;
default:
return -EINVAL;
@@ -412,11 +386,7 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
else
return s5m8767_set_low(s5m8767);
} else {
- ret = s5m8767_get_voltage_register(rdev, &reg);
- if (ret)
- return ret;
-
- return sec_reg_update(s5m8767->iodev, reg, selector, mask);
+ return regulator_set_voltage_sel_regmap(rdev, selector);
}
}
@@ -441,7 +411,7 @@ static struct regulator_ops s5m8767_ops = {
.is_enabled = s5m8767_reg_is_enabled,
.enable = s5m8767_reg_enable,
.disable = s5m8767_reg_disable,
- .get_voltage_sel = s5m8767_get_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = s5m8767_set_voltage_sel,
.set_voltage_time_sel = s5m8767_set_voltage_time_sel,
};
@@ -508,10 +478,182 @@ static struct regulator_desc regulators[] = {
s5m8767_regulator_desc(BUCK9),
};
+#ifdef CONFIG_OF
+static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
+ struct sec_platform_data *pdata,
+ struct device_node *pmic_np)
+{
+ int i, gpio;
+
+ for (i = 0; i < 3; i++) {
+ gpio = of_get_named_gpio(pmic_np,
+ "s5m8767,pmic-buck-dvs-gpios", i);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
+ return -EINVAL;
+ }
+ pdata->buck_gpios[i] = gpio;
+ }
+ return 0;
+}
+
+static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
+ struct sec_platform_data *pdata,
+ struct device_node *pmic_np)
+{
+ int i, gpio;
+
+ for (i = 0; i < 3; i++) {
+ gpio = of_get_named_gpio(pmic_np,
+ "s5m8767,pmic-buck-ds-gpios", i);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
+ return -EINVAL;
+ }
+ pdata->buck_ds[i] = gpio;
+ }
+ return 0;
+}
+
+static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
+ struct sec_platform_data *pdata)
+{
+ struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ struct device_node *pmic_np, *regulators_np, *reg_np;
+ struct sec_regulator_data *rdata;
+ struct sec_opmode_data *rmode;
+ unsigned int i, dvs_voltage_nr = 1, ret;
+
+ pmic_np = iodev->dev->of_node;
+ if (!pmic_np) {
+ dev_err(iodev->dev, "could not find pmic sub-node\n");
+ return -ENODEV;
+ }
+
+ regulators_np = of_find_node_by_name(pmic_np, "regulators");
+ if (!regulators_np) {
+ dev_err(iodev->dev, "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
+
+ /* count the number of regulators to be supported in pmic */
+ pdata->num_regulators = of_get_child_count(regulators_np);
+
+ rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
+ pdata->num_regulators, GFP_KERNEL);
+ if (!rdata) {
+ dev_err(iodev->dev,
+ "could not allocate memory for regulator data\n");
+ return -ENOMEM;
+ }
+
+ rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) *
+ pdata->num_regulators, GFP_KERNEL);
+ if (!rdata) {
+ dev_err(iodev->dev,
+ "could not allocate memory for regulator mode\n");
+ return -ENOMEM;
+ }
+
+ pdata->regulators = rdata;
+ pdata->opmode = rmode;
+ for_each_child_of_node(regulators_np, reg_np) {
+ for (i = 0; i < ARRAY_SIZE(regulators); i++)
+ if (!of_node_cmp(reg_np->name, regulators[i].name))
+ break;
+
+ if (i == ARRAY_SIZE(regulators)) {
+ dev_warn(iodev->dev,
+ "don't know how to configure regulator %s\n",
+ reg_np->name);
+ continue;
+ }
+
+ rdata->id = i;
+ rdata->initdata = of_get_regulator_init_data(
+ &pdev->dev, reg_np);
+ rdata->reg_node = reg_np;
+ rdata++;
+ rmode->id = i;
+ if (of_property_read_u32(reg_np, "op_mode",
+ &rmode->mode)) {
+ dev_warn(iodev->dev,
+ "no op_mode property property at %s\n",
+ reg_np->full_name);
+
+ rmode->mode = S5M8767_OPMODE_NORMAL_MODE;
+ }
+ rmode++;
+ }
+
+ if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL))
+ pdata->buck2_gpiodvs = true;
+
+ if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL))
+ pdata->buck3_gpiodvs = true;
+
+ if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL))
+ pdata->buck4_gpiodvs = true;
+
+ if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
+ pdata->buck4_gpiodvs) {
+ ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
+ if (ret)
+ return -EINVAL;
+
+ if (of_property_read_u32(pmic_np,
+ "s5m8767,pmic-buck-default-dvs-idx",
+ &pdata->buck_default_idx)) {
+ pdata->buck_default_idx = 0;
+ } else {
+ if (pdata->buck_default_idx >= 8) {
+ pdata->buck_default_idx = 0;
+ dev_info(iodev->dev,
+ "invalid value for default dvs index, use 0\n");
+ }
+ }
+ dvs_voltage_nr = 8;
+ }
+
+ ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np);
+ if (ret)
+ return -EINVAL;
+
+ if (of_property_read_u32_array(pmic_np,
+ "s5m8767,pmic-buck2-dvs-voltage",
+ pdata->buck2_voltage, dvs_voltage_nr)) {
+ dev_err(iodev->dev, "buck2 voltages not specified\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32_array(pmic_np,
+ "s5m8767,pmic-buck3-dvs-voltage",
+ pdata->buck3_voltage, dvs_voltage_nr)) {
+ dev_err(iodev->dev, "buck3 voltages not specified\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32_array(pmic_np,
+ "s5m8767,pmic-buck4-dvs-voltage",
+ pdata->buck4_voltage, dvs_voltage_nr)) {
+ dev_err(iodev->dev, "buck4 voltages not specified\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#else
+static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
+ struct sec_platform_data *pdata)
+{
+ return 0;
+}
+#endif /* CONFIG_OF */
+
static int s5m8767_pmic_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct sec_platform_data *pdata = iodev->pdata;
struct regulator_config config = { };
struct regulator_dev **rdev;
struct s5m8767_info *s5m8767;
@@ -522,6 +664,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (iodev->dev->of_node) {
+ ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata);
+ if (ret)
+ return ret;
+ }
+
if (pdata->buck2_gpiodvs) {
if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
@@ -577,23 +725,17 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
s5m8767->opmode = pdata->opmode;
buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
- pdata->buck2_init,
- pdata->buck2_init +
- buck_voltage_val2.step);
+ pdata->buck2_init);
sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
- pdata->buck3_init,
- pdata->buck3_init +
- buck_voltage_val2.step);
+ pdata->buck3_init);
sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
- pdata->buck4_init,
- pdata->buck4_init +
- buck_voltage_val2.step);
+ pdata->buck4_init);
sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
@@ -602,27 +744,21 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
s5m8767->buck2_vol[i] =
s5m8767_convert_voltage_to_sel(
&buck_voltage_val2,
- pdata->buck2_voltage[i],
- pdata->buck2_voltage[i] +
- buck_voltage_val2.step);
+ pdata->buck2_voltage[i]);
}
if (s5m8767->buck3_gpiodvs) {
s5m8767->buck3_vol[i] =
s5m8767_convert_voltage_to_sel(
&buck_voltage_val2,
- pdata->buck3_voltage[i],
- pdata->buck3_voltage[i] +
- buck_voltage_val2.step);
+ pdata->buck3_voltage[i]);
}
if (s5m8767->buck4_gpiodvs) {
s5m8767->buck4_vol[i] =
s5m8767_convert_voltage_to_sel(
&buck_voltage_val2,
- pdata->buck4_voltage[i],
- pdata->buck4_voltage[i] +
- buck_voltage_val2.step);
+ pdata->buck4_voltage[i]);
}
}
@@ -760,11 +896,19 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
(desc->max - desc->min) / desc->step + 1;
regulators[id].min_uV = desc->min;
regulators[id].uV_step = desc->step;
+ regulators[id].vsel_reg =
+ s5m8767_get_vsel_reg(id, s5m8767);
+ if (id < S5M8767_BUCK1)
+ regulators[id].vsel_mask = 0x3f;
+ else
+ regulators[id].vsel_mask = 0xff;
}
config.dev = s5m8767->dev;
config.init_data = pdata->regulators[i].initdata;
config.driver_data = s5m8767;
+ config.regmap = iodev->regmap;
+ config.of_node = pdata->regulators[i].reg_node;
rdev[i] = regulator_register(&regulators[id], &config);
if (IS_ERR(rdev[i])) {
diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c
index ab21133e6784..6e67be75ea1b 100644
--- a/drivers/regulator/tps51632-regulator.c
+++ b/drivers/regulator/tps51632-regulator.c
@@ -28,10 +28,13 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/regulator/tps51632-regulator.h>
#include <linux/slab.h>
@@ -85,49 +88,8 @@ struct tps51632_chip {
struct regulator_desc desc;
struct regulator_dev *rdev;
struct regmap *regmap;
- bool enable_pwm_dvfs;
};
-static int tps51632_dcdc_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct tps51632_chip *tps = rdev_get_drvdata(rdev);
- unsigned int data;
- int ret;
- unsigned int reg = TPS51632_VOLTAGE_SELECT_REG;
- int vsel;
-
- if (tps->enable_pwm_dvfs)
- reg = TPS51632_VOLTAGE_BASE_REG;
-
- ret = regmap_read(tps->regmap, reg, &data);
- if (ret < 0) {
- dev_err(tps->dev, "reg read failed, err %d\n", ret);
- return ret;
- }
-
- vsel = data & TPS51632_VOUT_MASK;
- return vsel;
-}
-
-static int tps51632_dcdc_set_voltage_sel(struct regulator_dev *rdev,
- unsigned selector)
-{
- struct tps51632_chip *tps = rdev_get_drvdata(rdev);
- int ret;
- unsigned int reg = TPS51632_VOLTAGE_SELECT_REG;
-
- if (tps->enable_pwm_dvfs)
- reg = TPS51632_VOLTAGE_BASE_REG;
-
- if (selector > TPS51632_MAX_VSEL)
- return -EINVAL;
-
- ret = regmap_write(tps->regmap, reg, selector);
- if (ret < 0)
- dev_err(tps->dev, "reg write failed, err %d\n", ret);
- return ret;
-}
-
static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev,
int ramp_delay)
{
@@ -144,8 +106,8 @@ static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev,
}
static struct regulator_ops tps51632_dcdc_ops = {
- .get_voltage_sel = tps51632_dcdc_get_voltage_sel,
- .set_voltage_sel = tps51632_dcdc_set_voltage_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = tps51632_dcdc_set_ramp_delay,
@@ -162,7 +124,6 @@ static int tps51632_init_dcdc(struct tps51632_chip *tps,
goto skip_pwm_config;
control |= TPS51632_DVFS_PWMEN;
- tps->enable_pwm_dvfs = pdata->enable_pwm_dvfs;
vsel = TPS51632_VOLT_VSEL(pdata->base_voltage_uV);
ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG, vsel);
if (ret < 0) {
@@ -205,22 +166,96 @@ skip_pwm_config:
return ret;
}
-static bool rd_wr_reg(struct device *dev, unsigned int reg)
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TPS51632_OFFSET_REG:
+ case TPS51632_FAULT_REG:
+ case TPS51632_IMON_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool is_read_reg(struct device *dev, unsigned int reg)
{
- if ((reg >= 0x8) && (reg <= 0x10))
+ switch (reg) {
+ case 0x08 ... 0x0F:
return false;
- return true;
+ default:
+ return true;
+ }
+}
+
+static bool is_write_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TPS51632_VOLTAGE_SELECT_REG:
+ case TPS51632_VOLTAGE_BASE_REG:
+ case TPS51632_VMAX_REG:
+ case TPS51632_DVFS_CONTROL_REG:
+ case TPS51632_POWER_STATE_REG:
+ case TPS51632_SLEW_REGS:
+ return true;
+ default:
+ return false;
+ }
}
static const struct regmap_config tps51632_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .writeable_reg = rd_wr_reg,
- .readable_reg = rd_wr_reg,
+ .writeable_reg = is_write_reg,
+ .readable_reg = is_read_reg,
+ .volatile_reg = is_volatile_reg,
.max_register = TPS51632_MAX_REG - 1,
.cache_type = REGCACHE_RBTREE,
};
+#if defined(CONFIG_OF)
+static const struct of_device_id tps51632_of_match[] = {
+ { .compatible = "ti,tps51632",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, tps51632_of_match);
+
+static struct tps51632_regulator_platform_data *
+ of_get_tps51632_platform_data(struct device *dev)
+{
+ struct tps51632_regulator_platform_data *pdata;
+ struct device_node *np = dev->of_node;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "Memory alloc failed for platform data\n");
+ return NULL;
+ }
+
+ pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
+ if (!pdata->reg_init_data) {
+ dev_err(dev, "Not able to get OF regulator init data\n");
+ return NULL;
+ }
+
+ pdata->enable_pwm_dvfs =
+ of_property_read_bool(np, "ti,enable-pwm-dvfs");
+ pdata->dvfs_step_20mV = of_property_read_bool(np, "ti,dvfs-step-20mV");
+
+ pdata->base_voltage_uV = pdata->reg_init_data->constraints.min_uV ? :
+ TPS51632_MIN_VOLATGE;
+ pdata->max_voltage_uV = pdata->reg_init_data->constraints.max_uV ? :
+ TPS51632_MAX_VOLATGE;
+ return pdata;
+}
+#else
+static struct tps51632_regulator_platform_data *
+ of_get_tps51632_platform_data(struct device *dev)
+{
+ return NULL;
+}
+#endif
+
static int tps51632_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -230,7 +265,19 @@ static int tps51632_probe(struct i2c_client *client,
int ret;
struct regulator_config config = { };
+ if (client->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_device(of_match_ptr(tps51632_of_match),
+ &client->dev);
+ if (!match) {
+ dev_err(&client->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+ }
+
pdata = client->dev.platform_data;
+ if (!pdata && client->dev.of_node)
+ pdata = of_get_tps51632_platform_data(&client->dev);
if (!pdata) {
dev_err(&client->dev, "No Platform data\n");
return -EINVAL;
@@ -269,6 +316,12 @@ static int tps51632_probe(struct i2c_client *client,
tps->desc.type = REGULATOR_VOLTAGE;
tps->desc.owner = THIS_MODULE;
+ if (pdata->enable_pwm_dvfs)
+ tps->desc.vsel_reg = TPS51632_VOLTAGE_BASE_REG;
+ else
+ tps->desc.vsel_reg = TPS51632_VOLTAGE_SELECT_REG;
+ tps->desc.vsel_mask = TPS51632_VOUT_MASK;
+
tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config);
if (IS_ERR(tps->regmap)) {
ret = PTR_ERR(tps->regmap);
@@ -319,6 +372,7 @@ static struct i2c_driver tps51632_i2c_driver = {
.driver = {
.name = "tps51632",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tps51632_of_match),
},
.probe = tps51632_probe,
.remove = tps51632_remove,
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index 0233cfb56560..54aa2da7283b 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -23,8 +23,10 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/tps6507x.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <linux/mfd/tps6507x.h>
+#include <linux/regulator/of_regulator.h>
/* DCDC's */
#define TPS6507X_DCDC_1 0
@@ -356,6 +358,80 @@ static struct regulator_ops tps6507x_pmic_ops = {
.list_voltage = regulator_list_voltage_table,
};
+#ifdef CONFIG_OF
+static struct of_regulator_match tps6507x_matches[] = {
+ { .name = "VDCDC1"},
+ { .name = "VDCDC2"},
+ { .name = "VDCDC3"},
+ { .name = "LDO1"},
+ { .name = "LDO2"},
+};
+
+static struct tps6507x_board *tps6507x_parse_dt_reg_data(
+ struct platform_device *pdev,
+ struct of_regulator_match **tps6507x_reg_matches)
+{
+ struct tps6507x_board *tps_board;
+ struct device_node *np = pdev->dev.parent->of_node;
+ struct device_node *regulators;
+ struct of_regulator_match *matches;
+ static struct regulator_init_data *reg_data;
+ int idx = 0, count, ret;
+
+ tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board),
+ GFP_KERNEL);
+ if (!tps_board) {
+ dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
+ return NULL;
+ }
+
+ regulators = of_find_node_by_name(np, "regulators");
+ if (!regulators) {
+ dev_err(&pdev->dev, "regulator node not found\n");
+ return NULL;
+ }
+
+ count = ARRAY_SIZE(tps6507x_matches);
+ matches = tps6507x_matches;
+
+ ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+ ret);
+ return NULL;
+ }
+
+ *tps6507x_reg_matches = matches;
+
+ reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data)
+ * TPS6507X_NUM_REGULATOR), GFP_KERNEL);
+ if (!reg_data) {
+ dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n");
+ return NULL;
+ }
+
+ tps_board->tps6507x_pmic_init_data = reg_data;
+
+ for (idx = 0; idx < count; idx++) {
+ if (!matches[idx].init_data || !matches[idx].of_node)
+ continue;
+
+ memcpy(&reg_data[idx], matches[idx].init_data,
+ sizeof(struct regulator_init_data));
+
+ }
+
+ return tps_board;
+}
+#else
+static inline struct tps6507x_board *tps6507x_parse_dt_reg_data(
+ struct platform_device *pdev,
+ struct of_regulator_match **tps6507x_reg_matches)
+{
+ *tps6507x_reg_matches = NULL;
+ return NULL;
+}
+#endif
static int tps6507x_pmic_probe(struct platform_device *pdev)
{
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
@@ -365,8 +441,10 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
struct tps6507x_pmic *tps;
struct tps6507x_board *tps_board;
+ struct of_regulator_match *tps6507x_reg_matches = NULL;
int i;
int error;
+ unsigned int prop;
/**
* tps_board points to pmic related constants
@@ -374,6 +452,9 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
*/
tps_board = dev_get_platdata(tps6507x_dev->dev);
+ if (!tps_board && tps6507x_dev->dev->of_node)
+ tps_board = tps6507x_parse_dt_reg_data(pdev,
+ &tps6507x_reg_matches);
if (!tps_board)
return -EINVAL;
@@ -415,6 +496,17 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
config.init_data = init_data;
config.driver_data = tps;
+ if (tps6507x_reg_matches) {
+ error = of_property_read_u32(
+ tps6507x_reg_matches[i].of_node,
+ "ti,defdcdc_default", &prop);
+
+ if (!error)
+ tps->info[i]->defdcdc_default = prop;
+
+ config.of_node = tps6507x_reg_matches[i].of_node;
+ }
+
rdev = regulator_register(&tps->desc[i], &config);
if (IS_ERR(rdev)) {
dev_err(tps6507x_dev->dev,
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index 41c391789c97..c8e70451df38 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -19,11 +19,13 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/mfd/tps65090.h>
struct tps65090_regulator {
@@ -67,8 +69,8 @@ static struct regulator_desc tps65090_regulator_desc[] = {
tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_reg_contol_ops),
tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_reg_contol_ops),
tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_reg_contol_ops),
- tps65090_REG_DESC(LDO1, "vsys_l1", 0, tps65090_ldo_ops),
- tps65090_REG_DESC(LDO2, "vsys_l2", 0, tps65090_ldo_ops),
+ tps65090_REG_DESC(LDO1, "vsys-l1", 0, tps65090_ldo_ops),
+ tps65090_REG_DESC(LDO2, "vsys-l2", 0, tps65090_ldo_ops),
};
static inline bool is_dcdc(int id)
@@ -138,6 +140,92 @@ static void tps65090_configure_regulator_config(
}
}
+#ifdef CONFIG_OF
+static struct of_regulator_match tps65090_matches[] = {
+ { .name = "dcdc1", },
+ { .name = "dcdc2", },
+ { .name = "dcdc3", },
+ { .name = "fet1", },
+ { .name = "fet2", },
+ { .name = "fet3", },
+ { .name = "fet4", },
+ { .name = "fet5", },
+ { .name = "fet6", },
+ { .name = "fet7", },
+ { .name = "ldo1", },
+ { .name = "ldo2", },
+};
+
+static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
+ struct platform_device *pdev,
+ struct of_regulator_match **tps65090_reg_matches)
+{
+ struct tps65090_platform_data *tps65090_pdata;
+ struct device_node *np = pdev->dev.parent->of_node;
+ struct device_node *regulators;
+ int idx = 0, ret;
+ struct tps65090_regulator_plat_data *reg_pdata;
+
+ tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata),
+ GFP_KERNEL);
+ if (!tps65090_pdata) {
+ dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX *
+ sizeof(*reg_pdata), GFP_KERNEL);
+ if (!reg_pdata) {
+ dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ regulators = of_find_node_by_name(np, "regulators");
+ if (!regulators) {
+ dev_err(&pdev->dev, "regulator node not found\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches,
+ ARRAY_SIZE(tps65090_matches));
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Error parsing regulator init data: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ *tps65090_reg_matches = tps65090_matches;
+ for (idx = 0; idx < ARRAY_SIZE(tps65090_matches); idx++) {
+ struct regulator_init_data *ri_data;
+ struct tps65090_regulator_plat_data *rpdata;
+
+ rpdata = &reg_pdata[idx];
+ ri_data = tps65090_matches[idx].init_data;
+ if (!ri_data || !tps65090_matches[idx].of_node)
+ continue;
+
+ rpdata->reg_init_data = ri_data;
+ rpdata->enable_ext_control = of_property_read_bool(
+ tps65090_matches[idx].of_node,
+ "ti,enable-ext-control");
+ if (rpdata->enable_ext_control)
+ rpdata->gpio = of_get_named_gpio(np,
+ "dcdc-ext-control-gpios", 0);
+
+ tps65090_pdata->reg_pdata[idx] = rpdata;
+ }
+ return tps65090_pdata;
+}
+#else
+static inline struct tps65090_platform_data *tps65090_parse_dt_reg_data(
+ struct platform_device *pdev,
+ struct of_regulator_match **tps65090_reg_matches)
+{
+ *tps65090_reg_matches = NULL;
+ return NULL;
+}
+#endif
+
static int tps65090_regulator_probe(struct platform_device *pdev)
{
struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent);
@@ -147,15 +235,19 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
struct tps65090_regulator_plat_data *tps_pdata;
struct tps65090_regulator *pmic;
struct tps65090_platform_data *tps65090_pdata;
+ struct of_regulator_match *tps65090_reg_matches = NULL;
int num;
int ret;
dev_dbg(&pdev->dev, "Probing regulator\n");
tps65090_pdata = dev_get_platdata(pdev->dev.parent);
- if (!tps65090_pdata) {
+ if (!tps65090_pdata && tps65090_mfd->dev->of_node)
+ tps65090_pdata = tps65090_parse_dt_reg_data(pdev,
+ &tps65090_reg_matches);
+ if (IS_ERR_OR_NULL(tps65090_pdata)) {
dev_err(&pdev->dev, "Platform data missing\n");
- return -EINVAL;
+ return tps65090_pdata ? PTR_ERR(tps65090_pdata) : -EINVAL;
}
pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
@@ -192,13 +284,17 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
}
}
- config.dev = &pdev->dev;
+ config.dev = pdev->dev.parent;
config.driver_data = ri;
config.regmap = tps65090_mfd->rmap;
if (tps_pdata)
config.init_data = tps_pdata->reg_init_data;
else
config.init_data = NULL;
+ if (tps65090_reg_matches)
+ config.of_node = tps65090_reg_matches[num].of_node;
+ else
+ config.of_node = NULL;
rdev = regulator_register(ri->desc, &config);
if (IS_ERR(rdev)) {
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index 73dce7664126..df395187c063 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -305,8 +305,8 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
if (!regs)
return NULL;
- count = of_regulator_match(pdev->dev.parent, regs,
- reg_matches, TPS65217_NUM_REGULATOR);
+ count = of_regulator_match(&pdev->dev, regs, reg_matches,
+ TPS65217_NUM_REGULATOR);
of_node_put(regs);
if ((count < 0) || (count > TPS65217_NUM_REGULATOR))
return NULL;
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index f86da672c758..e68382d0e1ea 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -61,10 +61,6 @@ struct tps6586x_regulator {
int enable_bit[2];
int enable_reg[2];
-
- /* for DVM regulators */
- int go_reg;
- int go_bit;
};
static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
@@ -72,37 +68,10 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
return rdev_get_dev(rdev)->parent;
}
-static int tps6586x_set_voltage_sel(struct regulator_dev *rdev,
- unsigned selector)
-{
- struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
- struct device *parent = to_tps6586x_dev(rdev);
- int ret, val, rid = rdev_get_id(rdev);
- uint8_t mask;
-
- val = selector << (ffs(rdev->desc->vsel_mask) - 1);
- mask = rdev->desc->vsel_mask;
-
- ret = tps6586x_update(parent, rdev->desc->vsel_reg, val, mask);
- if (ret)
- return ret;
-
- /* Update go bit for DVM regulators */
- switch (rid) {
- case TPS6586X_ID_LDO_2:
- case TPS6586X_ID_LDO_4:
- case TPS6586X_ID_SM_0:
- case TPS6586X_ID_SM_1:
- ret = tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit);
- break;
- }
- return ret;
-}
-
static struct regulator_ops tps6586x_regulator_ops = {
.list_voltage = regulator_list_voltage_table,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_sel = tps6586x_set_voltage_sel,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
@@ -142,7 +111,7 @@ static const unsigned int tps6586x_dvm_voltages[] = {
};
#define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1) \
+ ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
.desc = { \
.supply_name = _pin_name, \
.name = "REG-" #_id, \
@@ -156,29 +125,26 @@ static const unsigned int tps6586x_dvm_voltages[] = {
.enable_mask = 1 << (ebit0), \
.vsel_reg = TPS6586X_##vreg, \
.vsel_mask = ((1 << (nbits)) - 1) << (shift), \
+ .apply_reg = (goreg), \
+ .apply_bit = (gobit), \
}, \
.enable_reg[0] = TPS6586X_SUPPLY##ereg0, \
.enable_bit[0] = (ebit0), \
.enable_reg[1] = TPS6586X_SUPPLY##ereg1, \
.enable_bit[1] = (ebit1),
-#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
- .go_reg = TPS6586X_##goreg, \
- .go_bit = (gobit),
-
#define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1) \
{ \
TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1) \
+ ereg0, ebit0, ereg1, ebit1, 0, 0) \
}
#define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
{ \
TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1) \
- TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
+ ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
}
#define TPS6586X_SYS_REGULATOR() \
@@ -207,13 +173,13 @@ static struct tps6586x_regulator tps6586x_regulator[] = {
TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3,
- ENB, 3, VCC2, 6),
+ ENB, 3, TPS6586X_VCC2, BIT(6)),
TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3,
- END, 3, VCC1, 6),
+ END, 3, TPS6586X_VCC1, BIT(6)),
TPS6586X_DVM(SM_0, "vin-sm0", dvm, SM0V1, 0, 5, ENA, 1,
- ENB, 1, VCC1, 2),
+ ENB, 1, TPS6586X_VCC1, BIT(2)),
TPS6586X_DVM(SM_1, "vin-sm1", dvm, SM1V1, 0, 5, ENA, 0,
- ENB, 0, VCC1, 0),
+ ENB, 0, TPS6586X_VCC1, BIT(0)),
};
/*
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 59c3770fa77d..6ba6931ac855 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -964,8 +964,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
{
struct tps65910_board *pmic_plat_data;
struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
- struct device_node *np = pdev->dev.parent->of_node;
- struct device_node *regulators;
+ struct device_node *np, *regulators;
struct of_regulator_match *matches;
unsigned int prop;
int idx = 0, ret, count;
@@ -978,6 +977,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
return NULL;
}
+ np = of_node_get(pdev->dev.parent->of_node);
regulators = of_find_node_by_name(np, "regulators");
if (!regulators) {
dev_err(&pdev->dev, "regulator node not found\n");
@@ -994,11 +994,13 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
matches = tps65911_matches;
break;
default:
+ of_node_put(regulators);
dev_err(&pdev->dev, "Invalid tps chip version\n");
return NULL;
}
- ret = of_regulator_match(pdev->dev.parent, regulators, matches, count);
+ ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+ of_node_put(regulators);
if (ret < 0) {
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
ret);
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 96ce101b9067..cc1f7bf53fd0 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -1,21 +1,19 @@
-menu "Remoteproc drivers (EXPERIMENTAL)"
+menu "Remoteproc drivers"
# REMOTEPROC gets selected by whoever wants it
config REMOTEPROC
tristate
- depends on EXPERIMENTAL
depends on HAS_DMA
select FW_CONFIG
select VIRTIO
config OMAP_REMOTEPROC
tristate "OMAP remoteproc support"
- depends on EXPERIMENTAL
depends on HAS_DMA
depends on ARCH_OMAP4
depends on OMAP_IOMMU
+ depends on OMAP_MBOX_FWK
select REMOTEPROC
- select OMAP_MBOX_FWK
select RPMSG
help
Say y here to support OMAP's remote processors (dual M3
@@ -32,7 +30,6 @@ config OMAP_REMOTEPROC
config STE_MODEM_RPROC
tristate "STE-Modem remoteproc support"
- depends on EXPERIMENTAL
depends on HAS_DMA
select REMOTEPROC
default n
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index 2bd911f12571..f6e0ea6ffda5 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -1,9 +1,8 @@
-menu "Rpmsg drivers (EXPERIMENTAL)"
+menu "Rpmsg drivers"
# RPMSG always gets selected by whoever wants it
config RPMSG
tristate
select VIRTIO
- depends on EXPERIMENTAL
endmenu
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index f1e323924f12..d85446021ddb 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -839,7 +839,7 @@ static void rpmsg_recv_done(struct virtqueue *rvq)
/* farewell, ept, we don't need you anymore */
kref_put(&ept->refcount, __ept_release);
} else
- dev_warn(dev, "msg received with no recepient\n");
+ dev_warn(dev, "msg received with no recipient\n");
/* publish the real size of the buffer */
sg_init_one(&sg, msg, RPMSG_BUF_SIZE);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 923a9da9c829..79fbe3832dfc 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -20,14 +20,24 @@ if RTC_CLASS
config RTC_HCTOSYS
bool "Set system time from RTC on startup and resume"
default y
+ depends on !ALWAYS_USE_PERSISTENT_CLOCK
help
If you say yes here, the system time (wall clock) will be set using
the value read from a specified RTC device. This is useful to avoid
unnecessary fsck runs at boot time, and to network better.
+config RTC_SYSTOHC
+ bool "Set the RTC time based on NTP synchronization"
+ default y
+ depends on !ALWAYS_USE_PERSISTENT_CLOCK
+ help
+ If you say yes here, the system time (wall clock) will be stored
+ in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11
+ minutes if userspace reports synchronized NTP status.
+
config RTC_HCTOSYS_DEVICE
string "RTC used to set the system time"
- depends on RTC_HCTOSYS = y
+ depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y
default "rtc0"
help
The RTC device that will be used to (re)initialize the system
@@ -194,6 +204,12 @@ config RTC_DRV_DS3232
This driver can also be built as a module. If so, the module
will be called rtc-ds3232.
+config RTC_DRV_LP8788
+ tristate "TI LP8788 RTC driver"
+ depends on MFD_LP8788
+ help
+ Say Y to enable support for the LP8788 RTC/ALARM driver.
+
config RTC_DRV_MAX6900
tristate "Maxim MAX6900"
help
@@ -233,6 +249,26 @@ config RTC_DRV_MAX8998
This driver can also be built as a module. If so, the module
will be called rtc-max8998.
+config RTC_DRV_MAX8997
+ tristate "Maxim MAX8997"
+ depends on MFD_MAX8997
+ help
+ If you say yes here you will get support for the
+ RTC of Maxim MAX8997 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max8997.
+
+config RTC_DRV_MAX77686
+ tristate "Maxim MAX77686"
+ depends on MFD_MAX77686
+ help
+ If you say yes here you will get support for the
+ RTC of Maxim MAX77686 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max77686.
+
config RTC_DRV_RS5C372
tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
help
@@ -269,6 +305,16 @@ config RTC_DRV_X1205
This driver can also be built as a module. If so, the module
will be called rtc-x1205.
+config RTC_DRV_PALMAS
+ tristate "TI Palmas RTC driver"
+ depends on MFD_PALMAS
+ help
+ If you say yes here you get support for the RTC of TI PALMA series PMIC
+ chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-palma.
+
config RTC_DRV_PCF8523
tristate "NXP PCF8523"
help
@@ -370,6 +416,14 @@ config RTC_DRV_TPS65910
This driver can also be built as a module. If so, the module
will be called rtc-tps65910.
+config RTC_DRV_TPS80031
+ tristate "TI TPS80031/TPS80032 RTC driver"
+ depends on MFD_TPS80031
+ help
+ TI Power Managment IC TPS80031 supports RTC functionality
+ along with alarm. This driver supports the RTC driver for
+ the TPS80031 RTC module.
+
config RTC_DRV_RC5T583
tristate "RICOH 5T583 RTC driver"
depends on MFD_RC5T583
@@ -527,6 +581,14 @@ config RTC_DRV_PCF2123
This driver can also be built as a module. If so, the module
will be called rtc-pcf2123.
+config RTC_DRV_RX4581
+ tristate "Epson RX-4581"
+ help
+ If you say yes here you will get support for the Epson RX-4581.
+
+ This driver can also be built as a module. If so the module
+ will be called rtc-rx4581.
+
endif # SPI_MASTER
comment "Platform RTC drivers"
@@ -1023,7 +1085,7 @@ config RTC_DRV_TX4939
config RTC_DRV_MV
tristate "Marvell SoC RTC"
- depends on ARCH_KIRKWOOD || ARCH_DOVE
+ depends on ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU
help
If you say yes here you will get support for the in-chip RTC
that can be found in some of Marvell's SoC devices, such as
@@ -1173,4 +1235,20 @@ config RTC_DRV_SNVS
This driver can also be built as a module, if so, the module
will be called "rtc-snvs".
+comment "HID Sensor RTC drivers"
+
+config RTC_DRV_HID_SENSOR_TIME
+ tristate "HID Sensor Time"
+ depends on USB_HID
+ select IIO
+ select HID_SENSOR_HUB
+ select HID_SENSOR_IIO_COMMON
+ help
+ Say yes here to build support for the HID Sensors of type Time.
+ This drivers makes such sensors available as RTCs.
+
+ If this driver is compiled as a module, it will be named
+ rtc-hid-sensor-time.
+
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 4418ef3f9ecc..c33f86f1a69b 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -6,6 +6,7 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG
obj-$(CONFIG_RTC_LIB) += rtc-lib.o
obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
+obj-$(CONFIG_RTC_SYSTOHC) += systohc.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
rtc-core-y := class.o interface.o
@@ -52,10 +53,12 @@ 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
+obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
+obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
@@ -69,13 +72,16 @@ obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
+obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
+obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
@@ -95,6 +101,7 @@ 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_RX4581) += rtc-rx4581.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
@@ -113,6 +120,7 @@ obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o
obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
+obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.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
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 5143629dedbd..9b742d3ffb94 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -11,6 +11,8 @@
* published by the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/kdev_t.h>
@@ -50,6 +52,10 @@ 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 delta, delta_delta;
+
+ if (has_persistent_clock())
+ return 0;
+
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
@@ -88,6 +94,9 @@ static int rtc_resume(struct device *dev)
struct timespec new_system, new_rtc;
struct timespec sleep_time;
+ if (has_persistent_clock())
+ return 0;
+
rtc_hctosys_ret = -ENODEV;
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
@@ -254,7 +263,7 @@ static int __init rtc_init(void)
{
rtc_class = class_create(THIS_MODULE, "rtc");
if (IS_ERR(rtc_class)) {
- printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
+ pr_err("couldn't create class\n");
return PTR_ERR(rtc_class);
}
rtc_class->suspend = rtc_suspend;
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 9592b936b71b..42bd57da239d 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -587,16 +587,16 @@ void rtc_update_irq(struct rtc_device *rtc,
}
EXPORT_SYMBOL_GPL(rtc_update_irq);
-static int __rtc_match(struct device *dev, void *data)
+static int __rtc_match(struct device *dev, const void *data)
{
- char *name = (char *)data;
+ const char *name = data;
if (strcmp(dev_name(dev), name) == 0)
return 1;
return 0;
}
-struct rtc_device *rtc_class_open(char *name)
+struct rtc_device *rtc_class_open(const char *name)
{
struct device *dev;
struct rtc_device *rtc = NULL;
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index b6469e2cae89..434ebc3a99dc 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -86,7 +86,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
tm->tm_year = tm->tm_year - 1900;
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+ dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -100,7 +100,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
{
unsigned long cr;
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+ dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -145,7 +145,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
? 1 : 0;
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+ dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -183,7 +183,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
}
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+ dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
tm.tm_min, tm.tm_sec);
@@ -192,7 +192,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
- pr_debug("%s(): cmd=%08x\n", __func__, enabled);
+ dev_dbg(dev, "%s(): cmd=%08x\n", __func__, enabled);
if (enabled) {
at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
@@ -240,7 +240,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
rtc_update_irq(rtc, 1, events);
- pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__,
+ dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__,
events >> 8, events & 0x000000FF);
return IRQ_HANDLED;
@@ -296,8 +296,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
IRQF_SHARED,
"at91_rtc", pdev);
if (ret) {
- printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n",
- irq);
+ dev_err(&pdev->dev, "IRQ %d already in use.\n", irq);
return ret;
}
@@ -315,7 +314,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, rtc);
- printk(KERN_INFO "AT91 Real Time Clock driver.\n");
+ dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n");
return 0;
}
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 16630aa87f45..af97c94e8a3a 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -706,7 +706,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
rtc_cmos_int_handler = hpet_rtc_interrupt;
err = hpet_register_irq_handler(cmos_interrupt);
if (err != 0) {
- printk(KERN_WARNING "hpet_register_irq_handler "
+ dev_warn(dev, "hpet_register_irq_handler "
" failed in rtc_init().");
goto cleanup1;
}
@@ -731,8 +731,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
goto cleanup2;
}
- pr_info("%s: %s%s, %zd bytes nvram%s\n",
- dev_name(&cmos_rtc.rtc->dev),
+ dev_info(dev, "%s%s, %zd bytes nvram%s\n",
!is_valid_irq(rtc_irq) ? "no alarms" :
cmos_rtc.mon_alrm ? "alarms up to one year" :
cmos_rtc.day_alrm ? "alarms up to one month" :
@@ -820,8 +819,7 @@ static int cmos_suspend(struct device *dev)
enable_irq_wake(cmos->irq);
}
- pr_debug("%s: suspend%s, ctrl %02x\n",
- dev_name(&cmos_rtc.rtc->dev),
+ dev_dbg(dev, "suspend%s, ctrl %02x\n",
(tmp & RTC_AIE) ? ", alarm may wake" : "",
tmp);
@@ -876,9 +874,7 @@ static int cmos_resume(struct device *dev)
spin_unlock_irq(&rtc_lock);
}
- pr_debug("%s: resume, ctrl %02x\n",
- dev_name(&cmos_rtc.rtc->dev),
- tmp);
+ dev_dbg(dev, "resume, ctrl %02x\n", tmp);
return 0;
}
@@ -1098,7 +1094,6 @@ static __init void cmos_of_init(struct platform_device *pdev)
}
#else
static inline void cmos_of_init(struct platform_device *pdev) {}
-#define of_cmos_match NULL
#endif
/*----------------------------------------------------------------*/
@@ -1140,7 +1135,7 @@ static struct platform_driver cmos_platform_driver = {
#ifdef CONFIG_PM
.pm = &cmos_pm_ops,
#endif
- .of_match_table = of_cmos_match,
+ .of_match_table = of_match_ptr(of_cmos_match),
}
};
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c
index c8115b83e5ab..2d28ec1aa1cd 100644
--- a/drivers/rtc/rtc-coh901331.c
+++ b/drivers/rtc/rtc-coh901331.c
@@ -157,7 +157,6 @@ static int __exit coh901331_remove(struct platform_device *pdev)
if (rtap) {
rtc_device_unregister(rtap->rtc);
clk_unprepare(rtap->clk);
- clk_put(rtap->clk);
platform_set_drvdata(pdev, NULL);
}
@@ -196,7 +195,7 @@ static int __init coh901331_probe(struct platform_device *pdev)
"RTC COH 901 331 Alarm", rtap))
return -EIO;
- rtap->clk = clk_get(&pdev->dev, NULL);
+ rtap->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(rtap->clk)) {
ret = PTR_ERR(rtap->clk);
dev_err(&pdev->dev, "could not get clock\n");
@@ -207,7 +206,7 @@ static int __init coh901331_probe(struct platform_device *pdev)
ret = clk_prepare_enable(rtap->clk);
if (ret) {
dev_err(&pdev->dev, "could not enable clock\n");
- goto out_no_clk_prepenable;
+ return ret;
}
clk_disable(rtap->clk);
@@ -224,8 +223,6 @@ static int __init coh901331_probe(struct platform_device *pdev)
out_no_rtc:
platform_set_drvdata(pdev, NULL);
clk_unprepare(rtap->clk);
- out_no_clk_prepenable:
- clk_put(rtap->clk);
return ret;
}
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c
index 60b826e520e2..0dde688ca09b 100644
--- a/drivers/rtc/rtc-da9052.c
+++ b/drivers/rtc/rtc-da9052.c
@@ -240,9 +240,10 @@ static int da9052_rtc_probe(struct platform_device *pdev)
rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
platform_set_drvdata(pdev, rtc);
rtc->irq = platform_get_irq_byname(pdev, "ALM");
- ret = request_threaded_irq(rtc->irq, NULL, da9052_rtc_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "ALM", rtc);
+ ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+ da9052_rtc_irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "ALM", rtc);
if (ret != 0) {
rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
return ret;
@@ -250,16 +251,10 @@ static int da9052_rtc_probe(struct platform_device *pdev)
rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
&da9052_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc->rtc)) {
- ret = PTR_ERR(rtc->rtc);
- goto err_free_irq;
- }
+ if (IS_ERR(rtc->rtc))
+ return PTR_ERR(rtc->rtc);
return 0;
-
-err_free_irq:
- free_irq(rtc->irq, rtc);
- return ret;
}
static int da9052_rtc_remove(struct platform_device *pdev)
@@ -267,7 +262,6 @@ static int da9052_rtc_remove(struct platform_device *pdev)
struct da9052_rtc *rtc = pdev->dev.platform_data;
rtc_device_unregister(rtc->rtc);
- free_irq(rtc->irq, rtc);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c
index 5f7982f7c1b5..56b73089bb29 100644
--- a/drivers/rtc/rtc-davinci.c
+++ b/drivers/rtc/rtc-davinci.c
@@ -506,19 +506,19 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
davinci_rtc->pbase = res->start;
davinci_rtc->base_size = resource_size(res);
- mem = request_mem_region(davinci_rtc->pbase, davinci_rtc->base_size,
- pdev->name);
+ mem = devm_request_mem_region(dev, davinci_rtc->pbase,
+ davinci_rtc->base_size, pdev->name);
if (!mem) {
dev_err(dev, "RTC registers at %08x are not free\n",
davinci_rtc->pbase);
return -EBUSY;
}
- davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size);
+ davinci_rtc->base = devm_ioremap(dev, davinci_rtc->pbase,
+ davinci_rtc->base_size);
if (!davinci_rtc->base) {
dev_err(dev, "unable to ioremap MEM resource\n");
- ret = -ENOMEM;
- goto fail2;
+ return -ENOMEM;
}
platform_set_drvdata(pdev, davinci_rtc);
@@ -529,7 +529,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
ret = PTR_ERR(davinci_rtc->rtc);
dev_err(dev, "unable to register RTC device, err %d\n",
ret);
- goto fail3;
+ goto fail1;
}
rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG);
@@ -539,11 +539,11 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL);
rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL);
- ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt,
+ ret = devm_request_irq(dev, davinci_rtc->irq, davinci_rtc_interrupt,
0, "davinci_rtc", davinci_rtc);
if (ret < 0) {
dev_err(dev, "unable to register davinci RTC interrupt\n");
- goto fail4;
+ goto fail2;
}
/* Enable interrupts */
@@ -557,13 +557,10 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
return 0;
-fail4:
+fail2:
rtc_device_unregister(davinci_rtc->rtc);
-fail3:
+fail1:
platform_set_drvdata(pdev, NULL);
- iounmap(davinci_rtc->base);
-fail2:
- release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
return ret;
}
@@ -575,13 +572,8 @@ static int davinci_rtc_remove(struct platform_device *pdev)
rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
- free_irq(davinci_rtc->irq, davinci_rtc);
-
rtc_device_unregister(davinci_rtc->rtc);
- iounmap(davinci_rtc->base);
- release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
-
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 9a86b4bd8699..d04939369251 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -11,6 +11,8 @@
* published by the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/sched.h>
@@ -462,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc)
return;
if (rtc->id >= RTC_DEV_MAX) {
- pr_debug("%s: too many RTC devices\n", rtc->name);
+ dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name);
return;
}
@@ -480,10 +482,10 @@ void rtc_dev_prepare(struct rtc_device *rtc)
void rtc_dev_add_device(struct rtc_device *rtc)
{
if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
- printk(KERN_WARNING "%s: failed to add char device %d:%d\n",
+ dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n",
rtc->name, MAJOR(rtc_devt), rtc->id);
else
- pr_debug("%s: dev (%d:%d)\n", rtc->name,
+ dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name,
MAJOR(rtc_devt), rtc->id);
}
@@ -499,8 +501,7 @@ void __init rtc_dev_init(void)
err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
if (err < 0)
- printk(KERN_ERR "%s: failed to allocate char dev region\n",
- __FILE__);
+ pr_err("failed to allocate char dev region\n");
}
void __exit rtc_dev_exit(void)
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index d578773f5ce2..b05a6dc96405 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -635,9 +635,7 @@ static int ds1305_probe(struct spi_device *spi)
goto fail0;
}
- dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n",
- "read", ds1305->ctrl[0],
- ds1305->ctrl[1], ds1305->ctrl[2]);
+ dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "read", ds1305->ctrl);
/* Sanity check register values ... partially compensating for the
* fact that SPI has no device handshake. A pullup on MISO would
@@ -723,9 +721,7 @@ static int ds1305_probe(struct spi_device *spi)
goto fail0;
}
- dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n",
- "write", ds1305->ctrl[0],
- ds1305->ctrl[1], ds1305->ctrl[2]);
+ dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "write", ds1305->ctrl);
}
/* see if non-Linux software set up AM/PM mode */
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index e0d0ba4de03f..970a236b147a 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -322,12 +322,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
return -EIO;
}
- dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
- "read",
- ds1307->regs[0], ds1307->regs[1],
- ds1307->regs[2], ds1307->regs[3],
- ds1307->regs[4], ds1307->regs[5],
- ds1307->regs[6]);
+ dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs);
t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f);
t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f);
@@ -398,9 +393,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
break;
}
- dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
- "write", buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6]);
+ dev_dbg(dev, "%s: %7ph\n", "write", buf);
result = ds1307->write_block_data(ds1307->client,
ds1307->offset, 7, buf);
diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c
index 5ea9df7c8c31..b04fc4272fb3 100644
--- a/drivers/rtc/rtc-ds2404.c
+++ b/drivers/rtc/rtc-ds2404.c
@@ -70,7 +70,7 @@ static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev,
for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) {
err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name);
if (err) {
- printk(KERN_ERR "error mapping gpio %s: %d\n",
+ dev_err(&pdev->dev, "error mapping gpio %s: %d\n",
ds2404_gpio[i].name, err);
goto err_request;
}
@@ -177,7 +177,7 @@ static void ds2404_write_memory(struct device *dev, u16 offset,
for (i = 0; i < length; i++) {
if (out[i] != ds2404_read_byte(dev)) {
- printk(KERN_ERR "read invalid data\n");
+ dev_err(dev, "read invalid data\n");
return;
}
}
@@ -283,19 +283,7 @@ static struct platform_driver rtc_device_driver = {
.owner = THIS_MODULE,
},
};
-
-static __init int ds2404_init(void)
-{
- return platform_driver_register(&rtc_device_driver);
-}
-
-static __exit void ds2404_exit(void)
-{
- platform_driver_unregister(&rtc_device_driver);
-}
-
-module_init(ds2404_init);
-module_exit(ds2404_exit);
+module_platform_driver(rtc_device_driver);
MODULE_DESCRIPTION("DS2404 RTC");
MODULE_AUTHOR("Sven Schnelle");
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index c9f890b088da..1a0c37c9152b 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -13,6 +13,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
@@ -47,7 +49,7 @@ compute_wday(efi_time_t *eft)
int ndays = 0;
if (eft->year < 1998) {
- printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+ pr_err("EFI year < 1998, invalid date\n");
return -1;
}
@@ -70,7 +72,7 @@ convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
eft->day = wtime->tm_mday;
eft->hour = wtime->tm_hour;
eft->minute = wtime->tm_min;
- eft->second = wtime->tm_sec;
+ eft->second = wtime->tm_sec;
eft->nanosecond = 0;
eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
@@ -142,7 +144,7 @@ static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
*/
status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
- printk(KERN_WARNING "write status is %d\n", (int)status);
+ dev_warn(dev, "write status is %d\n", (int)status);
return status == EFI_SUCCESS ? 0 : -EINVAL;
}
@@ -157,7 +159,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm)
if (status != EFI_SUCCESS) {
/* should never happen */
- printk(KERN_ERR "efitime: can't read time\n");
+ dev_err(dev, "can't read time\n");
return -EINVAL;
}
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index 04e93c6597f8..bff3cdc5140e 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -116,17 +116,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t)
fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
- dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
- "%02x %02x %02x %02x %02x %02x %02x\n",
- "read",
- fm3130->regs[0], fm3130->regs[1],
- fm3130->regs[2], fm3130->regs[3],
- fm3130->regs[4], fm3130->regs[5],
- fm3130->regs[6], fm3130->regs[7],
- fm3130->regs[8], fm3130->regs[9],
- fm3130->regs[0xa], fm3130->regs[0xb],
- fm3130->regs[0xc], fm3130->regs[0xd],
- fm3130->regs[0xe]);
+ dev_dbg(dev, "%s: %15ph\n", "read", fm3130->regs);
t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
@@ -175,12 +165,7 @@ static int fm3130_set_time(struct device *dev, struct rtc_time *t)
tmp = t->tm_year - 100;
buf[FM3130_RTC_YEARS] = bin2bcd(tmp);
- dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x"
- "%02x %02x %02x %02x %02x %02x %02x %02x\n",
- "write", buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6], buf[7],
- buf[8], buf[9], buf[0xa], buf[0xb],
- buf[0xc], buf[0xd], buf[0xe]);
+ dev_dbg(dev, "%s: %15ph\n", "write", buf);
fm3130_rtc_mode(dev, FM3130_MODE_WRITE);
@@ -517,18 +502,8 @@ bad_alarm:
bad_clock:
if (!fm3130->data_valid || !fm3130->alarm_valid)
- dev_dbg(&client->dev,
- "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
- "%02x %02x %02x %02x %02x %02x %02x\n",
- "bogus registers",
- fm3130->regs[0], fm3130->regs[1],
- fm3130->regs[2], fm3130->regs[3],
- fm3130->regs[4], fm3130->regs[5],
- fm3130->regs[6], fm3130->regs[7],
- fm3130->regs[8], fm3130->regs[9],
- fm3130->regs[0xa], fm3130->regs[0xb],
- fm3130->regs[0xc], fm3130->regs[0xd],
- fm3130->regs[0xe]);
+ dev_dbg(&client->dev, "%s: %15ph\n", "bogus registers",
+ fm3130->regs);
/* We won't bail out here because we just got invalid data.
Time setting from u-boot doesn't work anyway */
diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c
new file mode 100644
index 000000000000..31c5728ef629
--- /dev/null
+++ b/drivers/rtc/rtc-hid-sensor-time.c
@@ -0,0 +1,292 @@
+/*
+ * HID Sensor Time Driver
+ * Copyright (c) 2012, Alexander Holler.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/rtc.h>
+
+/* Format: HID-SENSOR-usage_id_in_hex */
+/* Usage ID from spec for Time: 0x2000A0 */
+#define DRIVER_NAME "HID-SENSOR-2000a0" /* must be lowercase */
+
+enum hid_time_channel {
+ CHANNEL_SCAN_INDEX_YEAR,
+ CHANNEL_SCAN_INDEX_MONTH,
+ CHANNEL_SCAN_INDEX_DAY,
+ CHANNEL_SCAN_INDEX_HOUR,
+ CHANNEL_SCAN_INDEX_MINUTE,
+ CHANNEL_SCAN_INDEX_SECOND,
+ TIME_RTC_CHANNEL_MAX,
+};
+
+struct hid_time_state {
+ struct hid_sensor_hub_callbacks callbacks;
+ struct hid_sensor_common common_attributes;
+ struct hid_sensor_hub_attribute_info info[TIME_RTC_CHANNEL_MAX];
+ struct rtc_time last_time;
+ spinlock_t lock_last_time;
+ struct completion comp_last_time;
+ struct rtc_time time_buf;
+ struct rtc_device *rtc;
+};
+
+static const u32 hid_time_addresses[TIME_RTC_CHANNEL_MAX] = {
+ HID_USAGE_SENSOR_TIME_YEAR,
+ HID_USAGE_SENSOR_TIME_MONTH,
+ HID_USAGE_SENSOR_TIME_DAY,
+ HID_USAGE_SENSOR_TIME_HOUR,
+ HID_USAGE_SENSOR_TIME_MINUTE,
+ HID_USAGE_SENSOR_TIME_SECOND,
+};
+
+/* Channel names for verbose error messages */
+static const char * const hid_time_channel_names[TIME_RTC_CHANNEL_MAX] = {
+ "year", "month", "day", "hour", "minute", "second",
+};
+
+/* Callback handler to send event after all samples are received and captured */
+static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id, void *priv)
+{
+ unsigned long flags;
+ struct hid_time_state *time_state = platform_get_drvdata(priv);
+
+ spin_lock_irqsave(&time_state->lock_last_time, flags);
+ time_state->last_time = time_state->time_buf;
+ spin_unlock_irqrestore(&time_state->lock_last_time, flags);
+ complete(&time_state->comp_last_time);
+ return 0;
+}
+
+static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id, size_t raw_len,
+ char *raw_data, void *priv)
+{
+ struct hid_time_state *time_state = platform_get_drvdata(priv);
+ struct rtc_time *time_buf = &time_state->time_buf;
+
+ switch (usage_id) {
+ case HID_USAGE_SENSOR_TIME_YEAR:
+ time_buf->tm_year = *(u8 *)raw_data;
+ if (time_buf->tm_year < 70)
+ /* assume we are in 1970...2069 */
+ time_buf->tm_year += 100;
+ break;
+ case HID_USAGE_SENSOR_TIME_MONTH:
+ /* sensor sending the month as 1-12, we need 0-11 */
+ time_buf->tm_mon = *(u8 *)raw_data-1;
+ break;
+ case HID_USAGE_SENSOR_TIME_DAY:
+ time_buf->tm_mday = *(u8 *)raw_data;
+ break;
+ case HID_USAGE_SENSOR_TIME_HOUR:
+ time_buf->tm_hour = *(u8 *)raw_data;
+ break;
+ case HID_USAGE_SENSOR_TIME_MINUTE:
+ time_buf->tm_min = *(u8 *)raw_data;
+ break;
+ case HID_USAGE_SENSOR_TIME_SECOND:
+ time_buf->tm_sec = *(u8 *)raw_data;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* small helper, haven't found any other way */
+static const char *hid_time_attrib_name(u32 attrib_id)
+{
+ static const char unknown[] = "unknown";
+ unsigned i;
+
+ for (i = 0; i < TIME_RTC_CHANNEL_MAX; ++i) {
+ if (hid_time_addresses[i] == attrib_id)
+ return hid_time_channel_names[i];
+ }
+ return unknown; /* should never happen */
+}
+
+static int hid_time_parse_report(struct platform_device *pdev,
+ struct hid_sensor_hub_device *hsdev,
+ unsigned usage_id,
+ struct hid_time_state *time_state)
+{
+ int report_id, i;
+
+ for (i = 0; i < TIME_RTC_CHANNEL_MAX; ++i)
+ if (sensor_hub_input_get_attribute_info(hsdev,
+ HID_INPUT_REPORT, usage_id,
+ hid_time_addresses[i],
+ &time_state->info[i]) < 0)
+ return -EINVAL;
+ /* Check the (needed) attributes for sanity */
+ report_id = time_state->info[0].report_id;
+ if (report_id < 0) {
+ dev_err(&pdev->dev, "bad report ID!\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < TIME_RTC_CHANNEL_MAX; ++i) {
+ if (time_state->info[i].report_id != report_id) {
+ dev_err(&pdev->dev,
+ "not all needed attributes inside the same report!\n");
+ return -EINVAL;
+ }
+ if (time_state->info[i].size != 1) {
+ dev_err(&pdev->dev,
+ "attribute '%s' not 8 bits wide!\n",
+ hid_time_attrib_name(
+ time_state->info[i].attrib_id));
+ return -EINVAL;
+ }
+ if (time_state->info[i].units !=
+ HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED &&
+ /* allow attribute seconds with unit seconds */
+ !(time_state->info[i].attrib_id ==
+ HID_USAGE_SENSOR_TIME_SECOND &&
+ time_state->info[i].units ==
+ HID_USAGE_SENSOR_UNITS_SECOND)) {
+ dev_err(&pdev->dev,
+ "attribute '%s' hasn't a unit of type 'none'!\n",
+ hid_time_attrib_name(
+ time_state->info[i].attrib_id));
+ return -EINVAL;
+ }
+ if (time_state->info[i].unit_expo) {
+ dev_err(&pdev->dev,
+ "attribute '%s' hasn't a unit exponent of 1!\n",
+ hid_time_attrib_name(
+ time_state->info[i].attrib_id));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long flags;
+ struct hid_time_state *time_state =
+ platform_get_drvdata(to_platform_device(dev));
+ int ret;
+
+ INIT_COMPLETION(time_state->comp_last_time);
+ /* get a report with all values through requesting one value */
+ sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev,
+ HID_USAGE_SENSOR_TIME, hid_time_addresses[0],
+ time_state->info[0].report_id);
+ /* wait for all values (event) */
+ ret = wait_for_completion_killable_timeout(
+ &time_state->comp_last_time, HZ*6);
+ if (ret > 0) {
+ /* no error */
+ spin_lock_irqsave(&time_state->lock_last_time, flags);
+ *tm = time_state->last_time;
+ spin_unlock_irqrestore(&time_state->lock_last_time, flags);
+ return 0;
+ }
+ if (!ret)
+ return -EIO; /* timeouted */
+ return ret; /* killed (-ERESTARTSYS) */
+}
+
+static const struct rtc_class_ops hid_time_rtc_ops = {
+ .read_time = hid_rtc_read_time,
+};
+
+static int hid_time_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+ struct hid_time_state *time_state = devm_kzalloc(&pdev->dev,
+ sizeof(struct hid_time_state), GFP_KERNEL);
+
+ if (time_state == NULL)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, time_state);
+
+ spin_lock_init(&time_state->lock_last_time);
+ init_completion(&time_state->comp_last_time);
+ time_state->common_attributes.hsdev = hsdev;
+ time_state->common_attributes.pdev = pdev;
+
+ ret = hid_sensor_parse_common_attributes(hsdev,
+ HID_USAGE_SENSOR_TIME,
+ &time_state->common_attributes);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to setup common attributes!\n");
+ return ret;
+ }
+
+ ret = hid_time_parse_report(pdev, hsdev, HID_USAGE_SENSOR_TIME,
+ time_state);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to setup attributes!\n");
+ return ret;
+ }
+
+ time_state->callbacks.send_event = hid_time_proc_event;
+ time_state->callbacks.capture_sample = hid_time_capture_sample;
+ time_state->callbacks.pdev = pdev;
+ ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_TIME,
+ &time_state->callbacks);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "register callback failed!\n");
+ return ret;
+ }
+
+ time_state->rtc = rtc_device_register("hid-sensor-time",
+ &pdev->dev, &hid_time_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(time_state->rtc)) {
+ dev_err(&pdev->dev, "rtc device register failed!\n");
+ return PTR_ERR(time_state->rtc);
+ }
+
+ return ret;
+}
+
+static int hid_time_remove(struct platform_device *pdev)
+{
+ struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
+ struct hid_time_state *time_state = platform_get_drvdata(pdev);
+
+ rtc_device_unregister(time_state->rtc);
+ sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME);
+
+ return 0;
+}
+
+static struct platform_driver hid_time_platform_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = hid_time_probe,
+ .remove = hid_time_remove,
+};
+module_platform_driver(hid_time_platform_driver);
+
+MODULE_DESCRIPTION("HID Sensor Time");
+MODULE_AUTHOR("Alexander Holler <holler@ahsoftware.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 75d307ab37f4..82aad695979e 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -406,7 +406,7 @@ static int dryice_rtc_probe(struct platform_device *pdev)